pax_global_header00006660000000000000000000000064124413171360014514gustar00rootroot0000000000000052 comment=6e42c8330f8304e6cf9f8c1c85506bbc95732ca3 percona-galera-3-3.8-3390/000077500000000000000000000000001244131713600150025ustar00rootroot00000000000000percona-galera-3-3.8-3390/.bzrignore000066400000000000000000000013521244131713600170050ustar00rootroot00000000000000#*# *$ *,v *.BAK *.a *.bak *.elc *.exe *.la *.lo *.o *.obj *.orig *.py[oc] *.so *.os *.tmp *.log *.passed *~ .#* .*.sw[nop] .*.tmp ./.python-eggs .DS_Store .arch-ids .arch-inventory .bzr.log .del-* .git .hg .jamdeps.libs .make.state .sconsign* .svn .sw[nop] .tmp* BitKeeper CVS CVS.adm RCS SCCS TAGS _darcs aclocal.m4 autom4te* config.h config.h.in config.log config.status config.sub docs/build/* stamp-h stamp-h.in stamp-h1 scons* .sconf* {arch} galera_check gu_tests gu_tests++ check_gcomm gcs_test gcs_tests cluster.conf nodes.conf tests/conf/*.cnf tests/run tests/out tests/bin/* gcache/src/test gcache/tests/gcache_tests Makefile Makefile.in .deps .libs garb/garbd gcs/src/.garb docs/build/ gcomm/test/ssl_test galerautils/src/gu_fnv_bench percona-galera-3-3.8-3390/.gitignore000066400000000000000000000013431244131713600167730ustar00rootroot00000000000000*.a *.o *.os *.so *.log *.diff GPATH GRTAGS GTAGS GSYMS .sconf_temp .sconsign.dblite core rb_test galera.cache gvwstate.dat galera/tests/galera_check galera/tests/galera_check.passed galerautils/tests/gu_tests galerautils/tests/gu_tests++ galerautils/tests/gu_tests++.passed galerautils/tests/gu_tests.passed garb/garbd gcache.page.* gcache/src/test gcache/tests/gcache_tests gcache/tests/gcache_tests.passed gcomm/test/check_gcomm gcomm/test/gcomm_check.passed gcomm/test/ssl_test gcs/src/gcs_test gcs/src/unit_tests/gcs_tests gcs/src/unit_tests/gcs_tests.passed scripts/mysql/mysql-[5-9].[5-9].[0-9]* tests/bin tests/out tests/run tests/conf/cluster.conf tests/conf/nodes.conf tests/conf/common_my.cnf tests/conf/my[0-9]*.cnf docs/build percona-galera-3-3.8-3390/AUTHORS000066400000000000000000000000421244131713600160460ustar00rootroot00000000000000Codership Oy percona-galera-3-3.8-3390/COPYING000066400000000000000000000031441244131713600160370ustar00rootroot00000000000000Galera replication - implementation of write set replication (wsrep) interface. Copyright (C) 2007-2014 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License. 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 will find the GNU General Public License version 2 in the file LICENSE or at http://www.gnu.org/licenses/gpl-2.0.html In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL project's "OpenSSL" library (or with modified versions of it that use the same license as the "OpenSSL" library), and distribute the linked executables. You must obey the GNU General Public License in all respects for all of the code used other than "OpenSSL". If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. docs/ Documentation is dual licensed with the Creative Commons Attribution ShareAlike and GNU Free Documentation Licenses. See docs/COPYING for details. Following modules have their own authors and licenses: asio/ see asio/COPYING for details chromium/ see chromium/AUTHORS and chromium/LICENSE for details www.evanjones.ca/ see www.evanjones.ca/AUTHORS and www.evanjones.ca/LICENSE for details percona-galera-3-3.8-3390/DEB-VERSION000066400000000000000000000002551244131713600164440ustar00rootroot00000000000000GALERA_VERSION=3.8-3390 HTTP_LOCATION=http://www.percona.com/redir/downloads/Percona-XtraDB-Cluster-56/LATEST/source/tarball/percona-xtradb-cluster-galera-3-3.8-3390.tar.gz percona-galera-3-3.8-3390/GALERA-REVISION000066400000000000000000000000101244131713600171030ustar00rootroot00000000000000f6147dd percona-galera-3-3.8-3390/LICENSE000066400000000000000000000432541244131713600160170ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. percona-galera-3-3.8-3390/README000066400000000000000000000037661244131713600156760ustar00rootroot00000000000000Codership Oy http://www.codership.com This is Galera replication - Codership's implementation of the write set replication (wsrep) interface (https://launchpad.net/wsrep/). The software and other files in this directory unless otherwise noted are distributed under GPLv2, see COPYING for details. BUILDING - general Build Requirements: * Scons build system http://www.scons.org/ * Check unit test library http://check.sourceforge.net/ * Boost devel package http://www.boost.org/ * OpenSSL devel package To compile, in Galera root directory do either: $ scons (default optimized build) or $ ./scripts/build.sh (see ./scripts/build.sh --help for information on options) To build MySQL/Galera demo distribution, branch lp:codership-mysql into some directory (hereafter ) and run build script from this directory (hereafter ): $ cd $ bzr branch lp:codership-mysql $ cd $ MYSQL_SRC=/codership-mysql ./scripts/mysql/build.sh -b -s -o -t After successful build, demo package can be found under scripts/mysql. BUILDING on CentOS/RHEL 5 CentOS/RHEL by default uses a very old version of GCC and a likewise ancient version of BOOST that lacks important features. In order to build Galera on CentOS/RHEL one needs to: 1) Install gcc44 and gcc44-c++ packages and set CC and CXX variables accordingly: # yum install gcc44 gcc44-c++ # export CC=gcc44 # export CXX=g++44 2) Remove standard boost and boost-devel packages (if present) 3) Install boost141-devel package: # yum install boost141-devel 4) Make link from /usr/include/boost to /usr/include/boost141: # cd /usr/include # ln -sf boost141/boost boost 5) Install scons check-devel openssl-devel # yum install scons check-devel openssl-devel Then proceeed as described above. For more information, see: * Codership mailing list: http://groups.google.com/group/codership-team * https://launchpad.net/galera/ * Codership home page: http://www.codership.com percona-galera-3-3.8-3390/SConscript000066400000000000000000000012501244131713600170120ustar00rootroot00000000000000SConscript(['galerautils/SConscript', 'gcache/SConscript', 'gcomm/SConscript', 'gcs/SConscript', 'galera/SConscript', 'garb/SConscript']) Import('env', 'sysname', 'static_ssl', 'with_ssl') libmmgalera_objs = env['LIBGALERA_OBJS'] libmmgalera_objs.extend(env['LIBMMGALERA_OBJS']) if static_ssl == 1: env.Append(LIBS=File('%s/libssl.a' %(with_ssl))) env.Append(LIBS=File('%s/libcrypto.a' %(with_ssl))) env.Append(LIBS=File('%s/libz.a' %(with_ssl))) if sysname == 'darwin': env.SharedLibrary('galera_smm', libmmgalera_objs, SHLIBSUFFIX='.so') else: env.SharedLibrary('galera_smm', libmmgalera_objs) percona-galera-3-3.8-3390/SConstruct000066400000000000000000000362311244131713600170410ustar00rootroot00000000000000################################################################### # # Copyright (C) 2010-2014 Codership Oy # # SCons build script to build galera libraries # # Script structure: # - Help message # - Default parameters # - Read commandline options # - Set up and configure default build environment # - Set up and configure check unit test build environment # - Run root SConscript with variant_dir # #################################################################### import os import platform import string sysname = os.uname()[0].lower() machine = platform.machine() bits = platform.architecture()[0] print 'Host: ' + sysname + ' ' + machine + ' ' + bits x86 = 0 if bits == '32bit': x86 = 32 elif bits == '64bit': x86 = 64 # # Print Help # Help(''' Build targets: build tests check install all Default target: all Commandline Options: static_ssl=[0|1] Build with static SSL with_ssl=path Prefix for SSL debug=n debug build with optimization level n build_dir=dir build directory, default: '.' boost=[0|1] disable or enable boost libraries boost_pool=[0|1] use or not use boost pool allocator revno=XXXX source code revision number bpostatic=path a path to static libboost_program_options.a extra_sysroot=path a path to extra development environment (Fink, Homebrew, MacPorts, MinGW) ''') # bpostatic option added on Percona request # # Default params # build_target = 'all' # Optimization level opt_flags = ' -g -O3 -DNDEBUG' # Architecture (defaults to build host type) compile_arch = '' link_arch = '' with_ssl = '' # Build directory build_dir = '' # # Read commandline options # build_dir = ARGUMENTS.get('build_dir', '') with_ssl = ARGUMENTS.get('with_ssl', '/usr/lib64') # Debug/dbug flags debug = ARGUMENTS.get('debug', -1) dbug = ARGUMENTS.get('dbug', False) debug_lvl = int(debug) if debug_lvl >= 0 and debug_lvl < 3: opt_flags = ' -g -O%d -fno-inline' % debug_lvl dbug = True elif debug_lvl == 3: opt_flags = ' -g -O3' if dbug: opt_flags = opt_flags + ' -DGU_DBUG_ON' if x86 == 32: compile_arch = ' -m32 -march=i686' link_arch = compile_arch if sysname == 'linux': link_arch = link_arch + ' -Wl,-melf_i386' elif x86 == 64 and sysname != 'sunos': compile_arch = ' -m64' link_arch = compile_arch if sysname == 'linux': link_arch = link_arch + ' -Wl,-melf_x86_64' elif machine == 'ppc64': compile_arch = ' -mtune=native' link_arch = '' elif sysname == 'sunos': compile_arch = ' -mtune=native' link_arch = '' else: compile_arch = '' link_arch = '' boost = int(ARGUMENTS.get('boost', 1)) boost_pool = int(ARGUMENTS.get('boost_pool', 0)) static_ssl = int(ARGUMENTS.get('static_ssl', 0)) ssl = int(ARGUMENTS.get('ssl', 1)) tests = int(ARGUMENTS.get('tests', 1)) strict_build_flags = int(ARGUMENTS.get('strict_build_flags', 1)) GALERA_VER = ARGUMENTS.get('version', '3.8') GALERA_REV = ARGUMENTS.get('revno', 'XXXX') # export to any module that might have use of those Export('GALERA_VER', 'GALERA_REV') print 'Signature: version: ' + GALERA_VER + ', revision: ' + GALERA_REV LIBBOOST_PROGRAM_OPTIONS_A = ARGUMENTS.get('bpostatic', '') LIBBOOST_SYSTEM_A = string.replace(LIBBOOST_PROGRAM_OPTIONS_A, 'boost_program_options', 'boost_system') # # Set up and export default build environment # env = Environment(ENV = {'PATH' : os.environ['PATH'], 'HOME' : os.environ['HOME']}) # Set up environment for ccache and distcc #env['ENV']['HOME'] = os.environ['HOME'] #env['ENV']['DISTCC_HOSTS'] = os.environ['DISTCC_HOSTS'] #env['ENV']['CCACHE_PREFIX'] = os.environ['CCACHE_PREFIX'] if 'CCACHE_DIR' in os.environ: env['ENV']['CCACHE_DIR'] = os.environ['CCACHE_DIR'] if 'CCACHE_CPP2' in os.environ: env['ENV']['CCACHE_CPP2'] = os.environ['CCACHE_CPP2'] # Set CC and CXX compilers cc = os.getenv('CC', 'default') if cc != 'default': env.Replace(CC = cc) cxx = os.getenv('CXX', 'default') if cxx != 'default': env.Replace(CXX = cxx) link = os.getenv('LINK', 'default') if link != 'default': env.Replace(LINK = link) # Initialize CPPFLAGS and LIBPATH from environment to get user preferences env.Replace(CPPFLAGS = os.getenv('CPPFLAGS', '')) env.Replace(LIBPATH = [os.getenv('LIBPATH', '')]) # Set -pthread flag explicitly to make sure that pthreads are # enabled on all platforms. env.Append(CPPFLAGS = ' -pthread') # Freebsd ports are installed under /usr/local if sysname == 'freebsd' or sysname == 'sunos': env.Append(LIBPATH = ['/usr/local/lib']) env.Append(CPPFLAGS = ' -I/usr/local/include ') if sysname == 'sunos': env.Replace(SHLINKFLAGS = '-shared ') # Add paths is extra_sysroot argument was specified extra_sysroot = ARGUMENTS.get('extra_sysroot', '') if sysname == 'darwin' and extra_sysroot == '': # common developer environments and paths if os.system('which -s port') == 0 and os.path.isfile('/opt/local/bin/port'): extra_sysroot = '/opt/local' elif os.system('which -s brew') == 0 and os.path.isfile('/usr/local/bin/brew'): extra_sysroot = '/usr/local' elif os.system('which -s fink') == 0 and os.path.isfile('/sw/bin/fink'): extra_sysroot = '/sw' if extra_sysroot != '': env.Append(LIBPATH = [extra_sysroot + '/lib']) env.Append(CPPFLAGS = ' -I' + extra_sysroot + '/include') # print env.Dump() # # Set up build and link paths # # Include paths env.Append(CPPPATH = Split('''# #/asio #/common #/galerautils/src #/gcomm/src #/gcomm/src/gcomm #/gcache/src #/gcs/src #/wsdb/src #/galera/src ''')) # Library paths #env.Append(LIBPATH = Split('''#/galerautils/src # #/gcomm/src # #/gcs/src # #/wsdb/src # #/galera/src # ''')) # Preprocessor flags if sysname != 'sunos' and sysname != 'darwin' and sysname != 'freebsd': env.Append(CPPFLAGS = ' -D_XOPEN_SOURCE=600') if sysname == 'sunos': env.Append(CPPFLAGS = ' -D__EXTENSIONS__') env.Append(CPPFLAGS = ' -DHAVE_COMMON_H') # Common C/CXX flags # These should be kept minimal as they are appended after C/CXX specific flags env.Replace(CCFLAGS = opt_flags + compile_arch + ' -Wall -Wextra -Wno-unused-parameter') # C-specific flags env.Replace(CFLAGS = ' -std=c99 -fno-strict-aliasing -pipe') # CXX-specific flags # Note: not all 3rd-party libs like '-Wold-style-cast -Weffc++' # adding those after checks env.Replace(CXXFLAGS = ' -Wno-long-long -Wno-deprecated -ansi') if sysname != 'sunos': env.Append(CXXFLAGS = ' -pipe') # Linker flags # TODO: enable '-Wl,--warn-common -Wl,--fatal-warnings' after warnings from # static linking have beed addressed # env.Append(LINKFLAGS = link_arch) # # Check required headers and libraries (autoconf functionality) # conf = Configure(env) # System headers and libraries if not conf.CheckLib('pthread'): print 'Error: pthread library not found' Exit(1) # libatomic may be needed on some 32bit platforms (and 32bit userland PPC64) # for 8 byte atomics but not generally required if 0 == x86: conf.CheckLib('atomic') if sysname != 'darwin': if not conf.CheckLib('rt'): print 'Error: rt library not found' Exit(1) if sysname == 'freebsd': if not conf.CheckLib('execinfo'): print 'Error: execinfo library not found' Exit(1) if sysname == 'sunos': if not conf.CheckLib('socket'): print 'Error: socket library not found' Exit(1) if not conf.CheckLib('crypto'): print 'Error: crypto library not found' Exit(1) if not conf.CheckLib('nsl'): print 'Error: nsl library not found' Exit(1) if conf.CheckHeader('sys/epoll.h'): conf.env.Append(CPPFLAGS = ' -DGALERA_USE_GU_NETWORK') if conf.CheckHeader('byteswap.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_BYTESWAP_H') if conf.CheckHeader('endian.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_ENDIAN_H') elif conf.CheckHeader('sys/endian.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_SYS_ENDIAN_H') elif conf.CheckHeader('sys/byteorder.h'): conf.env.Append(CPPFLAGS = ' -DHAVE_SYS_BYTEORDER_H') elif sysname != 'darwin': print 'can\'t find byte order information' Exit(1) # Additional C headers and libraries # boost headers if not conf.CheckCXXHeader('boost/shared_ptr.hpp'): print 'boost/shared_ptr.hpp not found or not usable' Exit(1) conf.env.Append(CPPFLAGS = ' -DHAVE_BOOST_SHARED_PTR_HPP') if conf.CheckCXXHeader('unordered_map'): conf.env.Append(CPPFLAGS = ' -DHAVE_UNORDERED_MAP') elif conf.CheckCXXHeader('tr1/unordered_map'): conf.env.Append(CPPFLAGS = ' -DHAVE_TR1_UNORDERED_MAP') else: if conf.CheckCXXHeader('boost/unordered_map.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_BOOST_UNORDERED_MAP_HPP') else: print 'no unordered map header available' Exit(1) # pool allocator if boost == 1: # Default suffix for boost multi-threaded libraries if sysname == 'darwin': boost_library_suffix = '-mt' else: boost_library_suffix = '' if sysname == 'darwin' and extra_sysroot != '': boost_library_path = extra_sysroot + '/lib' else: boost_library_path = '' # Use nanosecond time precision conf.env.Append(CPPFLAGS = ' -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG=1') # Common procedure to find boost static library boost_libpaths = [ boost_library_path, '/usr/local/lib', '/usr/local/lib64', '/usr/lib', '/usr/lib64' ] def check_boost_library(libBaseName, header, configuredLibPath, autoadd = 1): libName = libBaseName + boost_library_suffix if configuredLibPath != '' and not os.path.isfile(configuredLibPath): print "Error: file '%s' does not exist" % configuredLibPath Exit(1) if configuredLibPath == '': for libpath in boost_libpaths: libname = libpath + '/lib%s.a' % libName if os.path.isfile(libname): configuredLibPath = libname break if configuredLibPath != '': if not conf.CheckCXXHeader(header): print "Error: header '%s' does not exist" % header Exit (1) if autoadd: conf.env.Append(LIBS=File(configuredLibPath)) else: return File(configuredLibPath) else: if not conf.CheckLibWithHeader(libs=[libName], header=header, language='CXX', autoadd=autoadd): print 'Error: library %s does not exist' % libName Exit (1) return [libName] # Required boost headers/libraries # if boost_pool == 1: if conf.CheckCXXHeader('boost/pool/pool_alloc.hpp'): print 'Using boost pool alloc' conf.env.Append(CPPFLAGS = ' -DGALERA_USE_BOOST_POOL_ALLOC=1') # due to a bug in boost >= 1.50 we need to link with boost_system # - should be a noop with no boost_pool. if sysname == 'darwin': if conf.CheckLib('boost_system' + boost_library_suffix): conf.env.Append(LIBS=['boost_system' + boost_library_suffix]) check_boost_library('boost_system', 'boost/system/error_code.hpp', LIBBOOST_SYSTEM_A) else: print 'Error: boost/pool/pool_alloc.hpp not found or not usable' Exit(1) libboost_program_options = check_boost_library('boost_program_options', 'boost/program_options.hpp', LIBBOOST_PROGRAM_OPTIONS_A, autoadd = 0) else: print 'Not using boost' # asio if conf.CheckCXXHeader('asio.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_ASIO_HPP') else: print 'asio headers not found or not usable' Exit(1) # asio/ssl if ssl == 1: if conf.CheckCXXHeader('asio/ssl.hpp'): conf.env.Append(CPPFLAGS = ' -DHAVE_ASIO_SSL_HPP') else: print 'ssl support required but asio/ssl.hpp not found or not usable' print 'compile with ssl=0 or check that openssl devel headers are usable' Exit(1) if static_ssl == 0: if conf.CheckLib('ssl'): conf.CheckLib('crypto') else: print 'ssl support required but openssl library not found' print 'compile with ssl=0 or check that openssl library is usable' Exit(1) else: conf.env.Append(LIBPATH = [with_ssl]) if conf.CheckLib('libssl.a', autoadd=0) or \ conf.CheckLib('libcrypto.a', autoadd=0) or \ conf.CheckLib('libz.a', autoadd=0): pass else: print 'ssl support required but openssl library (static) not found' print 'compile with ssl=0 or check that' print 'openssl static librares - libssl.a, libcrypto.a, libz.a are available' Exit(1) # these will be used only with our softaware if strict_build_flags == 1: conf.env.Append(CPPFLAGS = ' -Werror') conf.env.Append(CCFLAGS = ' -pedantic') conf.env.Append(CXXFLAGS = ' -Weffc++ -Wold-style-cast') env = conf.Finish() Export('x86', 'env', 'sysname', 'libboost_program_options', 'static_ssl', 'with_ssl') # # Actions to build .dSYM directories, containing debugging information for Darwin # if sysname == 'darwin' and int(debug) >= 0 and int(debug) < 3: env['LINKCOM'] = [env['LINKCOM'], 'dsymutil $TARGET'] env['SHLINKCOM'] = [env['SHLINKCOM'], 'dsymutil $TARGET'] # # Set up and export environment for check unit tests # # Clone base from default environment check_env = env.Clone() conf = Configure(check_env) # Check header and library if not conf.CheckHeader('check.h'): print 'Error: check header file not found or not usable' Exit(1) if not conf.CheckLib('check'): print 'Error: check library not found or not usable' Exit(1) if not conf.CheckLib('m'): print 'Error: math library not found or not usable' Exit(1) if sysname != 'darwin': if not conf.CheckLib('rt'): print 'Error: realtime library not found or not usable' Exit(1) conf.Finish() # # this follows recipes from http://www.scons.org/wiki/UnitTests # def builder_unit_test(target, source, env): app = str(source[0].abspath) if os.spawnl(os.P_WAIT, app, app)==0: open(str(target[0]),'w').write("PASSED\n") else: return 1 def builder_unit_test_dummy(target, source, env): return 0 # Create a builder for tests if tests == 1: bld = Builder(action = builder_unit_test) else: bld = Builder(action = builder_unit_test_dummy) check_env.Append(BUILDERS = {'Test' : bld}) Export('check_env') # # Run root SConscript with variant_dir # SConscript('SConscript', variant_dir=build_dir) percona-galera-3-3.8-3390/asio/000077500000000000000000000000001244131713600157355ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/LICENSE_1_0.txt000066400000000000000000000024721244131713600202240ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. percona-galera-3-3.8-3390/asio/asio.hpp000066400000000000000000000067351244131713600174140ustar00rootroot00000000000000// // asio.hpp // ~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_HPP #define ASIO_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/basic_datagram_socket.hpp" #include "asio/basic_deadline_timer.hpp" #include "asio/basic_io_object.hpp" #include "asio/basic_raw_socket.hpp" #include "asio/basic_serial_port.hpp" #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_socket_streambuf.hpp" #include "asio/basic_stream_socket.hpp" #include "asio/basic_streambuf.hpp" #include "asio/buffer.hpp" #include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffered_read_stream.hpp" #include "asio/buffered_stream_fwd.hpp" #include "asio/buffered_stream.hpp" #include "asio/buffered_write_stream_fwd.hpp" #include "asio/buffered_write_stream.hpp" #include "asio/buffers_iterator.hpp" #include "asio/completion_condition.hpp" #include "asio/datagram_socket_service.hpp" #include "asio/deadline_timer_service.hpp" #include "asio/deadline_timer.hpp" #include "asio/error.hpp" #include "asio/error_code.hpp" #include "asio/handler_alloc_hook.hpp" #include "asio/handler_invoke_hook.hpp" #include "asio/io_service.hpp" #include "asio/ip/address.hpp" #include "asio/ip/address_v4.hpp" #include "asio/ip/address_v6.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_entry.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/host_name.hpp" #include "asio/ip/icmp.hpp" #include "asio/ip/multicast.hpp" #include "asio/ip/resolver_query_base.hpp" #include "asio/ip/resolver_service.hpp" #include "asio/ip/tcp.hpp" #include "asio/ip/udp.hpp" #include "asio/ip/unicast.hpp" #include "asio/ip/v6_only.hpp" #include "asio/is_read_buffered.hpp" #include "asio/is_write_buffered.hpp" #include "asio/local/basic_endpoint.hpp" #include "asio/local/connect_pair.hpp" #include "asio/local/datagram_protocol.hpp" #include "asio/local/stream_protocol.hpp" #include "asio/placeholders.hpp" #include "asio/posix/basic_descriptor.hpp" #include "asio/posix/basic_stream_descriptor.hpp" #include "asio/posix/descriptor_base.hpp" #include "asio/posix/stream_descriptor.hpp" #include "asio/posix/stream_descriptor_service.hpp" #include "asio/raw_socket_service.hpp" #include "asio/read.hpp" #include "asio/read_at.hpp" #include "asio/read_until.hpp" #include "asio/serial_port.hpp" #include "asio/serial_port_base.hpp" #include "asio/serial_port_service.hpp" #include "asio/socket_acceptor_service.hpp" #include "asio/socket_base.hpp" #include "asio/strand.hpp" #include "asio/stream_socket_service.hpp" #include "asio/streambuf.hpp" #include "asio/system_error.hpp" #include "asio/thread.hpp" #include "asio/time_traits.hpp" #include "asio/version.hpp" #include "asio/windows/basic_handle.hpp" #include "asio/windows/basic_random_access_handle.hpp" #include "asio/windows/basic_stream_handle.hpp" #include "asio/windows/overlapped_ptr.hpp" #include "asio/windows/random_access_handle.hpp" #include "asio/windows/random_access_handle_service.hpp" #include "asio/windows/stream_handle.hpp" #include "asio/windows/stream_handle_service.hpp" #include "asio/write.hpp" #include "asio/write_at.hpp" #endif // ASIO_HPP percona-galera-3-3.8-3390/asio/asio/000077500000000000000000000000001244131713600166705ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/basic_datagram_socket.hpp000066400000000000000000000752471244131713600237110ustar00rootroot00000000000000// // basic_datagram_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_DATAGRAM_SOCKET_HPP #define ASIO_BASIC_DATAGRAM_SOCKET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_socket.hpp" #include "asio/datagram_socket_service.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides datagram-oriented socket functionality. /** * The basic_datagram_socket class template provides asynchronous and blocking * datagram-oriented socket functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template > class basic_datagram_socket : public basic_socket { public: /// The native representation of a socket. typedef typename DatagramSocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// Construct a basic_datagram_socket without opening it. /** * This constructor creates a datagram socket without opening it. The open() * function must be called before data can be sent or received on the socket. * * @param io_service The io_service object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. */ explicit basic_datagram_socket(asio::io_service& io_service) : basic_socket(io_service) { } /// Construct and open a basic_datagram_socket. /** * This constructor creates and opens a datagram socket. * * @param io_service The io_service object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const protocol_type& protocol) : basic_socket(io_service, protocol) { } /// Construct a basic_datagram_socket, opening it and binding it to the given /// local endpoint. /** * This constructor creates a datagram socket and automatically opens it bound * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * * @param io_service The io_service object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param endpoint An endpoint on the local machine to which the datagram * socket will be bound. * * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const endpoint_type& endpoint) : basic_socket(io_service, endpoint) { } /// Construct a basic_datagram_socket on an existing native socket. /** * This constructor creates a datagram socket object to hold an existing * native socket. * * @param io_service The io_service object that the datagram socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param protocol An object specifying protocol parameters to be used. * * @param native_socket The new underlying socket implementation. * * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) : basic_socket( io_service, protocol, native_socket) { } /// Send some data on a connected socket. /** * This function is used to send data on the datagram socket. The function * call will block until the data has been sent successfully or an error * occurs. * * @param buffers One ore more data buffers to be sent on the socket. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code socket.send(asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.send(this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Send some data on a connected socket. /** * This function is used to send data on the datagram socket. The function * call will block until the data has been sent successfully or an error * occurs. * * @param buffers One ore more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.send( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Send some data on a connected socket. /** * This function is used to send data on the datagram socket. The function * call will block until the data has been sent successfully or an error * occurs. * * @param buffers One or more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.send(this->implementation, buffers, flags, ec); } /// Start an asynchronous send on a connected socket. /** * This function is used to send data on the datagram socket. The function * call will block until the data has been sent successfully or an error * occurs. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram * socket. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } /// Start an asynchronous send on a connected socket. /** * This function is used to send data on the datagram socket. The function * call will block until the data has been sent successfully or an error * occurs. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected datagram * socket. */ template void async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { this->service.async_send(this->implementation, buffers, flags, handler); } /// Send a datagram to the specified endpoint. /** * This function is used to send a datagram to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.send_to(asio::buffer(data, size), destination); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination) { asio::error_code ec; std::size_t s = this->service.send_to( this->implementation, buffers, destination, 0, ec); asio::detail::throw_error(ec); return s; } /// Send a datagram to the specified endpoint. /** * This function is used to send a datagram to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @param flags Flags specifying how the send call is to be made. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.send_to( this->implementation, buffers, destination, flags, ec); asio::detail::throw_error(ec); return s; } /// Send a datagram to the specified endpoint. /** * This function is used to send a datagram to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @param flags Flags specifying how the send call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { return this->service.send_to(this->implementation, buffers, destination, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send a datagram to the specified * remote endpoint. The function call always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_send_to( * asio::buffer(data, size), destination, handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, 0, handler); } /// Start an asynchronous send. /** * This function is used to asynchronously send a datagram to the specified * remote endpoint. The function call always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, flags, handler); } /// Receive some data on a connected socket. /** * This function is used to receive data on the datagram socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected datagram * socket. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.receive(asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.receive( this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on a connected socket. /** * This function is used to receive data on the datagram socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected datagram * socket. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.receive( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on a connected socket. /** * This function is used to receive data on the datagram socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected datagram * socket. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.receive(this->implementation, buffers, flags, ec); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the datagram * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * datagram socket. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.async_receive(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the datagram * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param flags Flags specifying how the receive call is to be made. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * datagram socket. */ template void async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, flags, handler); } /// Receive a datagram with the endpoint of the sender. /** * This function is used to receive a datagram. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * asio::ip::udp::endpoint sender_endpoint; * socket.receive_from( * asio::buffer(data, size), sender_endpoint); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint) { asio::error_code ec; std::size_t s = this->service.receive_from( this->implementation, buffers, sender_endpoint, 0, ec); asio::detail::throw_error(ec); return s; } /// Receive a datagram with the endpoint of the sender. /** * This function is used to receive a datagram. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. * * @param flags Flags specifying how the receive call is to be made. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.receive_from( this->implementation, buffers, sender_endpoint, flags, ec); asio::detail::throw_error(ec); return s; } /// Receive a datagram with the endpoint of the sender. /** * This function is used to receive a datagram. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. * * @param flags Flags specifying how the receive call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { return this->service.receive_from(this->implementation, buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive a datagram. The function * call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the * handler is called. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.async_receive_from( * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, 0, handler); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive a datagram. The function * call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the datagram. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the * handler is called. * * @param flags Flags specifying how the receive call is to be made. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, flags, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_DATAGRAM_SOCKET_HPP percona-galera-3-3.8-3390/asio/asio/basic_deadline_timer.hpp000066400000000000000000000350221244131713600235110ustar00rootroot00000000000000// // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_DEADLINE_TIMER_HPP #define ASIO_BASIC_DEADLINE_TIMER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_io_object.hpp" #include "asio/deadline_timer_service.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides waitable timer functionality. /** * The basic_deadline_timer class template provides the ability to perform a * blocking or asynchronous wait for a timer to expire. * * A deadline timer is always in one of two states: "expired" or "not expired". * If the wait() or async_wait() function is called on an expired timer, the * wait operation will complete immediately. * * Most applications will use the asio::deadline_timer typedef. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Examples * Performing a blocking wait: * @code * // Construct a timer without setting an expiry time. * asio::deadline_timer timer(io_service); * * // Set an expiry time relative to now. * timer.expires_from_now(boost::posix_time::seconds(5)); * * // Wait for the timer to expire. * timer.wait(); * @endcode * * @par * Performing an asynchronous wait: * @code * void handler(const asio::error_code& error) * { * if (!error) * { * // Timer expired. * } * } * * ... * * // Construct a timer with an absolute expiry time. * asio::deadline_timer timer(io_service, * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); * * // Start an asynchronous wait. * timer.async_wait(handler); * @endcode * * @par Changing an active deadline_timer's expiry time * * Changing the expiry time of a timer while there are pending asynchronous * waits causes those wait operations to be cancelled. To ensure that the action * associated with the timer is performed only once, use something like this: * used: * * @code * void on_some_event() * { * if (my_timer.expires_from_now(seconds(5)) > 0) * { * // We managed to cancel the timer. Start new asynchronous wait. * my_timer.async_wait(on_timeout); * } * else * { * // Too late, timer has already expired! * } * } * * void on_timeout(const asio::error_code& e) * { * if (e != asio::error::operation_aborted) * { * // Timer was not cancelled, take necessary action. * } * } * @endcode * * @li The asio::basic_deadline_timer::expires_from_now() function * cancels any pending asynchronous waits, and returns the number of * asynchronous waits that were cancelled. If it returns 0 then you were too * late and the wait handler has already been executed, or will soon be * executed. If it returns 1 then the wait handler was successfully cancelled. * * @li If a wait handler is cancelled, the asio::error_code passed to * it contains the value asio::error::operation_aborted. */ template , typename TimerService = deadline_timer_service > class basic_deadline_timer : public basic_io_object { public: /// The time traits type. typedef TimeTraits traits_type; /// The time type. typedef typename traits_type::time_type time_type; /// The duration type. typedef typename traits_type::duration_type duration_type; /// Constructor. /** * This constructor creates a timer without setting an expiry time. The * expires_at() or expires_from_now() functions must be called to set an * expiry time before the timer can be waited on. * * @param io_service The io_service object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. */ explicit basic_deadline_timer(asio::io_service& io_service) : basic_io_object(io_service) { } /// Constructor to set a particular expiry time as an absolute time. /** * This constructor creates a timer and sets the expiry time. * * @param io_service The io_service object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, expressed * as an absolute time. */ basic_deadline_timer(asio::io_service& io_service, const time_type& expiry_time) : basic_io_object(io_service) { asio::error_code ec; this->service.expires_at(this->implementation, expiry_time, ec); asio::detail::throw_error(ec); } /// Constructor to set a particular expiry time relative to now. /** * This constructor creates a timer and sets the expiry time. * * @param io_service The io_service object that the timer will use to dispatch * handlers for any asynchronous operations performed on the timer. * * @param expiry_time The expiry time to be used for the timer, relative to * now. */ basic_deadline_timer(asio::io_service& io_service, const duration_type& expiry_time) : basic_io_object(io_service) { asio::error_code ec; this->service.expires_from_now(this->implementation, expiry_time, ec); asio::detail::throw_error(ec); } /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait * operations against the timer. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * Cancelling the timer does not change the expiry time. * * @return The number of asynchronous operations that were cancelled. * * @throws asio::system_error Thrown on failure. * * @note If the timer has already expired when cancel() is called, then the * handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t cancel() { asio::error_code ec; std::size_t s = this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); return s; } /// Cancel any asynchronous operations that are waiting on the timer. /** * This function forces the completion of any pending asynchronous wait * operations against the timer. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * Cancelling the timer does not change the expiry time. * * @param ec Set to indicate what error occurred, if any. * * @return The number of asynchronous operations that were cancelled. * * @note If the timer has already expired when cancel() is called, then the * handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } /// Get the timer's expiry time as an absolute time. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ time_type expires_at() const { return this->service.expires_at(this->implementation); } /// Set the timer's expiry time as an absolute time. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * @param expiry_time The expiry time to be used for the timer. * * @return The number of asynchronous operations that were cancelled. * * @throws asio::system_error Thrown on failure. * * @note If the timer has already expired when expires_at() is called, then * the handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t expires_at(const time_type& expiry_time) { asio::error_code ec; std::size_t s = this->service.expires_at( this->implementation, expiry_time, ec); asio::detail::throw_error(ec); return s; } /// Set the timer's expiry time as an absolute time. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * @param expiry_time The expiry time to be used for the timer. * * @param ec Set to indicate what error occurred, if any. * * @return The number of asynchronous operations that were cancelled. * * @note If the timer has already expired when expires_at() is called, then * the handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t expires_at(const time_type& expiry_time, asio::error_code& ec) { return this->service.expires_at(this->implementation, expiry_time, ec); } /// Get the timer's expiry time relative to now. /** * This function may be used to obtain the timer's current expiry time. * Whether the timer has expired or not does not affect this value. */ duration_type expires_from_now() const { return this->service.expires_from_now(this->implementation); } /// Set the timer's expiry time relative to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * @param expiry_time The expiry time to be used for the timer. * * @return The number of asynchronous operations that were cancelled. * * @throws asio::system_error Thrown on failure. * * @note If the timer has already expired when expires_from_now() is called, * then the handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t expires_from_now(const duration_type& expiry_time) { asio::error_code ec; std::size_t s = this->service.expires_from_now( this->implementation, expiry_time, ec); asio::detail::throw_error(ec); return s; } /// Set the timer's expiry time relative to now. /** * This function sets the expiry time. Any pending asynchronous wait * operations will be cancelled. The handler for each cancelled operation will * be invoked with the asio::error::operation_aborted error code. * * @param expiry_time The expiry time to be used for the timer. * * @param ec Set to indicate what error occurred, if any. * * @return The number of asynchronous operations that were cancelled. * * @note If the timer has already expired when expires_from_now() is called, * then the handlers for asynchronous wait operations will: * * @li have already been invoked; or * * @li have been queued for invocation in the near future. * * These handlers can no longer be cancelled, and therefore are passed an * error code that indicates the successful completion of the wait operation. */ std::size_t expires_from_now(const duration_type& expiry_time, asio::error_code& ec) { return this->service.expires_from_now( this->implementation, expiry_time, ec); } /// Perform a blocking wait on the timer. /** * This function is used to wait for the timer to expire. This function * blocks and does not return until the timer has expired. * * @throws asio::system_error Thrown on failure. */ void wait() { asio::error_code ec; this->service.wait(this->implementation, ec); asio::detail::throw_error(ec); } /// Perform a blocking wait on the timer. /** * This function is used to wait for the timer to expire. This function * blocks and does not return until the timer has expired. * * @param ec Set to indicate what error occurred, if any. */ void wait(asio::error_code& ec) { this->service.wait(this->implementation, ec); } /// Start an asynchronous wait on the timer. /** * This function may be used to initiate an asynchronous wait against the * timer. It always returns immediately. * * For each call to async_wait(), the supplied handler will be called exactly * once. The handler will be called when: * * @li The timer has expired. * * @li The timer was cancelled, in which case the handler is passed the error * code asio::error::operation_aborted. * * @param handler The handler to be called when the timer expires. Copies * will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_wait(WaitHandler handler) { this->service.async_wait(this->implementation, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_DEADLINE_TIMER_HPP percona-galera-3-3.8-3390/asio/asio/basic_io_object.hpp000066400000000000000000000052311244131713600225000ustar00rootroot00000000000000// // basic_io_object.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_IO_OBJECT_HPP #define ASIO_BASIC_IO_OBJECT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Base class for all I/O objects. template class basic_io_object : private noncopyable { public: /// The type of the service that will be used to provide I/O operations. typedef IoObjectService service_type; /// The underlying implementation type of I/O object. typedef typename service_type::implementation_type implementation_type; /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. /** * This function may be used to obtain the io_service object that the I/O * object uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that the I/O object will use * to dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& io_service() { return service.get_io_service(); } /// Get the io_service associated with the object. /** * This function may be used to obtain the io_service object that the I/O * object uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that the I/O object will use * to dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& get_io_service() { return service.get_io_service(); } protected: /// Construct a basic_io_object. /** * Performs: * @code service.construct(implementation); @endcode */ explicit basic_io_object(asio::io_service& io_service) : service(asio::use_service(io_service)) { service.construct(implementation); } /// Protected destructor to prevent deletion through this type. /** * Performs: * @code service.destroy(implementation); @endcode */ ~basic_io_object() { service.destroy(implementation); } /// The service associated with the I/O object. service_type& service; /// The underlying implementation of the I/O object. implementation_type implementation; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_IO_OBJECT_HPP percona-galera-3-3.8-3390/asio/asio/basic_raw_socket.hpp000066400000000000000000000745071244131713600227200ustar00rootroot00000000000000// // basic_raw_socket.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_RAW_SOCKET_HPP #define ASIO_BASIC_RAW_SOCKET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_socket.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/raw_socket_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides raw-oriented socket functionality. /** * The basic_raw_socket class template provides asynchronous and blocking * raw-oriented socket functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template > class basic_raw_socket : public basic_socket { public: /// The native representation of a socket. typedef typename RawSocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// Construct a basic_raw_socket without opening it. /** * This constructor creates a raw socket without opening it. The open() * function must be called before data can be sent or received on the socket. * * @param io_service The io_service object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. */ explicit basic_raw_socket(asio::io_service& io_service) : basic_socket(io_service) { } /// Construct and open a basic_raw_socket. /** * This constructor creates and opens a raw socket. * * @param io_service The io_service object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ basic_raw_socket(asio::io_service& io_service, const protocol_type& protocol) : basic_socket(io_service, protocol) { } /// Construct a basic_raw_socket, opening it and binding it to the given /// local endpoint. /** * This constructor creates a raw socket and automatically opens it bound * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * * @param io_service The io_service object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param endpoint An endpoint on the local machine to which the raw * socket will be bound. * * @throws asio::system_error Thrown on failure. */ basic_raw_socket(asio::io_service& io_service, const endpoint_type& endpoint) : basic_socket(io_service, endpoint) { } /// Construct a basic_raw_socket on an existing native socket. /** * This constructor creates a raw socket object to hold an existing * native socket. * * @param io_service The io_service object that the raw socket will use * to dispatch handlers for any asynchronous operations performed on the * socket. * * @param protocol An object specifying protocol parameters to be used. * * @param native_socket The new underlying socket implementation. * * @throws asio::system_error Thrown on failure. */ basic_raw_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) : basic_socket( io_service, protocol, native_socket) { } /// Send some data on a connected socket. /** * This function is used to send data on the raw socket. The function call * will block until the data has been sent successfully or an error occurs. * * @param buffers One ore more data buffers to be sent on the socket. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected raw socket. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code socket.send(asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.send(this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Send some data on a connected socket. /** * This function is used to send data on the raw socket. The function call * will block until the data has been sent successfully or an error occurs. * * @param buffers One ore more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected raw socket. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.send( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Send some data on a connected socket. /** * This function is used to send data on the raw socket. The function call * will block until the data has been sent successfully or an error occurs. * * @param buffers One or more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected raw socket. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.send(this->implementation, buffers, flags, ec); } /// Start an asynchronous send on a connected socket. /** * This function is used to send data on the raw socket. The function call * will block until the data has been sent successfully or an error occurs. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw * socket. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } /// Start an asynchronous send on a connected socket. /** * This function is used to send data on the raw socket. The function call * will block until the data has been sent successfully or an error occurs. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_send operation can only be used with a connected socket. * Use the async_send_to function to send data on an unconnected raw * socket. */ template void async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { this->service.async_send(this->implementation, buffers, flags, handler); } /// Send raw data to the specified endpoint. /** * This function is used to send raw data to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.send_to(asio::buffer(data, size), destination); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination) { asio::error_code ec; std::size_t s = this->service.send_to( this->implementation, buffers, destination, 0, ec); asio::detail::throw_error(ec); return s; } /// Send raw data to the specified endpoint. /** * This function is used to send raw data to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @param flags Flags specifying how the send call is to be made. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.send_to( this->implementation, buffers, destination, flags, ec); asio::detail::throw_error(ec); return s; } /// Send raw data to the specified endpoint. /** * This function is used to send raw data to the specified remote endpoint. * The function call will block until the data has been sent successfully or * an error occurs. * * @param buffers One or more data buffers to be sent to the remote endpoint. * * @param destination The remote endpoint to which the data will be sent. * * @param flags Flags specifying how the send call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. */ template std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { return this->service.send_to(this->implementation, buffers, destination, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send raw data to the specified * remote endpoint. The function call always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_send_to( * asio::buffer(data, size), destination, handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, 0, handler); } /// Start an asynchronous send. /** * This function is used to asynchronously send raw data to the specified * remote endpoint. The function call always returns immediately. * * @param buffers One or more data buffers to be sent to the remote endpoint. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param destination The remote endpoint to which the data will be sent. * Copies will be made of the endpoint as required. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, flags, handler); } /// Receive some data on a connected socket. /** * This function is used to receive data on the raw socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected raw * socket. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.receive(asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.receive( this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on a connected socket. /** * This function is used to receive data on the raw socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected raw * socket. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.receive( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on a connected socket. /** * This function is used to receive data on the raw socket. The function * call will block until data has been received successfully or an error * occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected raw * socket. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.receive(this->implementation, buffers, flags, ec); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the raw * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * raw socket. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.async_receive(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } /// Start an asynchronous receive on a connected socket. /** * This function is used to asynchronously receive data from the raw * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param flags Flags specifying how the receive call is to be made. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The async_receive operation can only be used with a connected socket. * Use the async_receive_from function to receive data on an unconnected * raw socket. */ template void async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, flags, handler); } /// Receive raw data with the endpoint of the sender. /** * This function is used to receive raw data. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * asio::ip::udp::endpoint sender_endpoint; * socket.receive_from( * asio::buffer(data, size), sender_endpoint); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint) { asio::error_code ec; std::size_t s = this->service.receive_from( this->implementation, buffers, sender_endpoint, 0, ec); asio::detail::throw_error(ec); return s; } /// Receive raw data with the endpoint of the sender. /** * This function is used to receive raw data. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. * * @param flags Flags specifying how the receive call is to be made. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.receive_from( this->implementation, buffers, sender_endpoint, flags, ec); asio::detail::throw_error(ec); return s; } /// Receive raw data with the endpoint of the sender. /** * This function is used to receive raw data. The function call will block * until data has been received successfully or an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. * * @param flags Flags specifying how the receive call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. */ template std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { return this->service.receive_from(this->implementation, buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive raw data. The function * call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the * handler is called. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.async_receive_from( * asio::buffer(data, size), 0, sender_endpoint, handler); @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, 0, handler); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive raw data. The function * call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param sender_endpoint An endpoint object that receives the endpoint of * the remote sender of the data. Ownership of the sender_endpoint object * is retained by the caller, which must guarantee that it is valid until the * handler is called. * * @param flags Flags specifying how the receive call is to be made. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, flags, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_RAW_SOCKET_HPP percona-galera-3-3.8-3390/asio/asio/basic_serial_port.hpp000066400000000000000000000516621244131713600230770ustar00rootroot00000000000000// // basic_serial_port.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_BASIC_SERIAL_PORT_HPP #define ASIO_BASIC_SERIAL_PORT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/basic_io_object.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/serial_port_base.hpp" #include "asio/serial_port_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides serial port functionality. /** * The basic_serial_port class template provides functionality that is common * to all serial ports. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_serial_port : public basic_io_object, public serial_port_base { public: /// The native representation of a serial port. typedef typename SerialPortService::native_type native_type; /// A basic_serial_port is always the lowest layer. typedef basic_serial_port lowest_layer_type; /// Construct a basic_serial_port without opening it. /** * This constructor creates a serial port without opening it. * * @param io_service The io_service object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. */ explicit basic_serial_port(asio::io_service& io_service) : basic_io_object(io_service) { } /// Construct and open a basic_serial_port. /** * This constructor creates and opens a serial port for the specified device * name. * * @param io_service The io_service object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param device The platform-specific device name for this serial * port. */ explicit basic_serial_port(asio::io_service& io_service, const char* device) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, device, ec); asio::detail::throw_error(ec); } /// Construct and open a basic_serial_port. /** * This constructor creates and opens a serial port for the specified device * name. * * @param io_service The io_service object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param device The platform-specific device name for this serial * port. */ explicit basic_serial_port(asio::io_service& io_service, const std::string& device) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, device, ec); asio::detail::throw_error(ec); } /// Construct a basic_serial_port on an existing native serial port. /** * This constructor creates a serial port object to hold an existing native * serial port. * * @param io_service The io_service object that the serial port will use to * dispatch handlers for any asynchronous operations performed on the port. * * @param native_serial_port A native serial port. * * @throws asio::system_error Thrown on failure. */ basic_serial_port(asio::io_service& io_service, const native_type& native_serial_port) : basic_io_object(io_service) { asio::error_code ec; this->service.assign(this->implementation, native_serial_port, ec); asio::detail::throw_error(ec); } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * layers. Since a basic_serial_port cannot contain any further layers, it * simply returns a reference to itself. * * @return A reference to the lowest layer in the stack of layers. Ownership * is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return *this; } /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of * layers. Since a basic_serial_port cannot contain any further layers, it * simply returns a reference to itself. * * @return A const reference to the lowest layer in the stack of layers. * Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return *this; } /// Open the serial port using the specified device name. /** * This function opens the serial port for the specified device name. * * @param device The platform-specific device name. * * @throws asio::system_error Thrown on failure. */ void open(const std::string& device) { asio::error_code ec; this->service.open(this->implementation, device, ec); asio::detail::throw_error(ec); } /// Open the serial port using the specified device name. /** * This function opens the serial port using the given platform-specific * device name. * * @param device The platform-specific device name. * * @param ec Set the indicate what error occurred, if any. */ asio::error_code open(const std::string& device, asio::error_code& ec) { return this->service.open(this->implementation, device, ec); } /// Assign an existing native serial port to the serial port. /* * This function opens the serial port to hold an existing native serial port. * * @param native_serial_port A native serial port. * * @throws asio::system_error Thrown on failure. */ void assign(const native_type& native_serial_port) { asio::error_code ec; this->service.assign(this->implementation, native_serial_port, ec); asio::detail::throw_error(ec); } /// Assign an existing native serial port to the serial port. /* * This function opens the serial port to hold an existing native serial port. * * @param native_serial_port A native serial port. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code assign(const native_type& native_serial_port, asio::error_code& ec) { return this->service.assign(this->implementation, native_serial_port, ec); } /// Determine whether the serial port is open. bool is_open() const { return this->service.is_open(this->implementation); } /// Close the serial port. /** * This function is used to close the serial port. Any asynchronous read or * write operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void close() { asio::error_code ec; this->service.close(this->implementation, ec); asio::detail::throw_error(ec); } /// Close the serial port. /** * This function is used to close the serial port. Any asynchronous read or * write operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code close(asio::error_code& ec) { return this->service.close(this->implementation, ec); } /// Get the native serial port representation. /** * This function may be used to obtain the underlying representation of the * serial port. This is intended to allow access to native serial port * functionality that is not otherwise provided. */ native_type native() { return this->service.native(this->implementation); } /// Cancel all asynchronous operations associated with the serial port. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void cancel() { asio::error_code ec; this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the serial port. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } /// Send a break sequence to the serial port. /** * This function causes a break sequence of platform-specific duration to be * sent out the serial port. * * @throws asio::system_error Thrown on failure. */ void send_break() { asio::error_code ec; this->service.send_break(this->implementation, ec); asio::detail::throw_error(ec); } /// Send a break sequence to the serial port. /** * This function causes a break sequence of platform-specific duration to be * sent out the serial port. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code send_break(asio::error_code& ec) { return this->service.send_break(this->implementation, ec); } /// Set an option on the serial port. /** * This function is used to set an option on the serial port. * * @param option The option value to be set on the serial port. * * @throws asio::system_error Thrown on failure. * * @sa SettableSerialPortOption @n * asio::serial_port_base::baud_rate @n * asio::serial_port_base::flow_control @n * asio::serial_port_base::parity @n * asio::serial_port_base::stop_bits @n * asio::serial_port_base::character_size */ template void set_option(const SettableSerialPortOption& option) { asio::error_code ec; this->service.set_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Set an option on the serial port. /** * This function is used to set an option on the serial port. * * @param option The option value to be set on the serial port. * * @param ec Set to indicate what error occurred, if any. * * @sa SettableSerialPortOption @n * asio::serial_port_base::baud_rate @n * asio::serial_port_base::flow_control @n * asio::serial_port_base::parity @n * asio::serial_port_base::stop_bits @n * asio::serial_port_base::character_size */ template asio::error_code set_option(const SettableSerialPortOption& option, asio::error_code& ec) { return this->service.set_option(this->implementation, option, ec); } /// Get an option from the serial port. /** * This function is used to get the current value of an option on the serial * port. * * @param option The option value to be obtained from the serial port. * * @throws asio::system_error Thrown on failure. * * @sa GettableSerialPortOption @n * asio::serial_port_base::baud_rate @n * asio::serial_port_base::flow_control @n * asio::serial_port_base::parity @n * asio::serial_port_base::stop_bits @n * asio::serial_port_base::character_size */ template void get_option(GettableSerialPortOption& option) { asio::error_code ec; this->service.get_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Get an option from the serial port. /** * This function is used to get the current value of an option on the serial * port. * * @param option The option value to be obtained from the serial port. * * @param ec Set to indicate what error occured, if any. * * @sa GettableSerialPortOption @n * asio::serial_port_base::baud_rate @n * asio::serial_port_base::flow_control @n * asio::serial_port_base::parity @n * asio::serial_port_base::stop_bits @n * asio::serial_port_base::character_size */ template asio::error_code get_option(GettableSerialPortOption& option, asio::error_code& ec) { return this->service.get_option(this->implementation, option, ec); } /// Write some data to the serial port. /** * This function is used to write data to the serial port. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the serial port. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * serial_port.write_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.write_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the serial port. /** * This function is used to write data to the serial port. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the serial port. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return this->service.write_some(this->implementation, buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the serial port. * The function call always returns immediately. * * @param buffers One or more data buffers to be written to the serial port. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * serial_port.async_write_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_write_some(this->implementation, buffers, handler); } /// Read some data from the serial port. /** * This function is used to read data from the serial port. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * serial_port.read_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.read_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the serial port. /** * This function is used to read data from the serial port. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return this->service.read_some(this->implementation, buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the serial port. * The function call always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the * requested amount of data is read before the asynchronous operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * serial_port.async_read_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_read_some(this->implementation, buffers, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_BASIC_SERIAL_PORT_HPP percona-galera-3-3.8-3390/asio/asio/basic_socket.hpp000066400000000000000000001005431244131713600220350ustar00rootroot00000000000000// // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_SOCKET_HPP #define ASIO_BASIC_SOCKET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/socket_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides socket functionality. /** * The basic_socket class template provides functionality that is common to both * stream-oriented and datagram-oriented sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_socket : public basic_io_object, public socket_base { public: /// The native representation of a socket. typedef typename SocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// A basic_socket is always the lowest layer. typedef basic_socket lowest_layer_type; /// Construct a basic_socket without opening it. /** * This constructor creates a socket without opening it. * * @param io_service The io_service object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. */ explicit basic_socket(asio::io_service& io_service) : basic_io_object(io_service) { } /// Construct and open a basic_socket. /** * This constructor creates and opens a socket. * * @param io_service The io_service object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const protocol_type& protocol) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, protocol, ec); asio::detail::throw_error(ec); } /// Construct a basic_socket, opening it and binding it to the given local /// endpoint. /** * This constructor creates a socket and automatically opens it bound to the * specified endpoint on the local machine. The protocol used is the protocol * associated with the given endpoint. * * @param io_service The io_service object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the socket will * be bound. * * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const endpoint_type& endpoint) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, endpoint.protocol(), ec); asio::detail::throw_error(ec); this->service.bind(this->implementation, endpoint, ec); asio::detail::throw_error(ec); } /// Construct a basic_socket on an existing native socket. /** * This constructor creates a socket object to hold an existing native socket. * * @param io_service The io_service object that the socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @param native_socket A native socket. * * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) : basic_io_object(io_service) { asio::error_code ec; this->service.assign(this->implementation, protocol, native_socket, ec); asio::detail::throw_error(ec); } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * layers. Since a basic_socket cannot contain any further layers, it simply * returns a reference to itself. * * @return A reference to the lowest layer in the stack of layers. Ownership * is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return *this; } /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of * layers. Since a basic_socket cannot contain any further layers, it simply * returns a reference to itself. * * @return A const reference to the lowest layer in the stack of layers. * Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return *this; } /// Open the socket using the specified protocol. /** * This function opens the socket so that it will use the specified protocol. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); * @endcode */ void open(const protocol_type& protocol = protocol_type()) { asio::error_code ec; this->service.open(this->implementation, protocol, ec); asio::detail::throw_error(ec); } /// Open the socket using the specified protocol. /** * This function opens the socket so that it will use the specified protocol. * * @param protocol An object specifying which protocol is to be used. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * asio::error_code ec; * socket.open(asio::ip::tcp::v4(), ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code open(const protocol_type& protocol, asio::error_code& ec) { return this->service.open(this->implementation, protocol, ec); } /// Assign an existing native socket to the socket. /* * This function opens the socket to hold an existing native socket. * * @param protocol An object specifying which protocol is to be used. * * @param native_socket A native socket. * * @throws asio::system_error Thrown on failure. */ void assign(const protocol_type& protocol, const native_type& native_socket) { asio::error_code ec; this->service.assign(this->implementation, protocol, native_socket, ec); asio::detail::throw_error(ec); } /// Assign an existing native socket to the socket. /* * This function opens the socket to hold an existing native socket. * * @param protocol An object specifying which protocol is to be used. * * @param native_socket A native socket. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code assign(const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { return this->service.assign(this->implementation, protocol, native_socket, ec); } /// Determine whether the socket is open. bool is_open() const { return this->service.is_open(this->implementation); } /// Close the socket. /** * This function is used to close the socket. Any asynchronous send, receive * or connect operations will be cancelled immediately, and will complete * with the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. * * @note For portable behaviour with respect to graceful closure of a * connected socket, call shutdown() before closing the socket. */ void close() { asio::error_code ec; this->service.close(this->implementation, ec); asio::detail::throw_error(ec); } /// Close the socket. /** * This function is used to close the socket. Any asynchronous send, receive * or connect operations will be cancelled immediately, and will complete * with the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::error_code ec; * socket.close(ec); * if (ec) * { * // An error occurred. * } * @endcode * * @note For portable behaviour with respect to graceful closure of a * connected socket, call shutdown() before closing the socket. */ asio::error_code close(asio::error_code& ec) { return this->service.close(this->implementation, ec); } /// Get the native socket representation. /** * This function may be used to obtain the underlying representation of the * socket. This is intended to allow access to native socket functionality * that is not otherwise provided. */ native_type native() { return this->service.native(this->implementation); } /// Cancel all asynchronous operations associated with the socket. /** * This function causes all outstanding asynchronous connect, send and receive * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. * * @note Calls to cancel() will always fail with * asio::error::operation_not_supported when run on Windows XP, Windows * Server 2003, and earlier versions of Windows, unless * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has * two issues that should be considered before enabling its use: * * @li It will only cancel asynchronous operations that were initiated in the * current thread. * * @li It can appear to complete without error, but the request to cancel the * unfinished operations may be silently ignored by the operating system. * Whether it works or not seems to depend on the drivers that are installed. * * For portable cancellation, consider using one of the following * alternatives: * * @li Disable asio's I/O completion port backend by defining * ASIO_DISABLE_IOCP. * * @li Use the close() function to simultaneously cancel the outstanding * operations and close the socket. * * When running on Windows Vista, Windows Server 2008, and later, the * CancelIoEx function is always used. This function does not have the * problems described above. */ #if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ && !defined(ASIO_ENABLE_CANCELIO) __declspec(deprecated("By default, this function always fails with " "operation_not_supported when used on Windows XP, Windows Server 2003, " "or earlier. Consult documentation for details.")) #endif void cancel() { asio::error_code ec; this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the socket. /** * This function causes all outstanding asynchronous connect, send and receive * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. * * @note Calls to cancel() will always fail with * asio::error::operation_not_supported when run on Windows XP, Windows * Server 2003, and earlier versions of Windows, unless * ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has * two issues that should be considered before enabling its use: * * @li It will only cancel asynchronous operations that were initiated in the * current thread. * * @li It can appear to complete without error, but the request to cancel the * unfinished operations may be silently ignored by the operating system. * Whether it works or not seems to depend on the drivers that are installed. * * For portable cancellation, consider using one of the following * alternatives: * * @li Disable asio's I/O completion port backend by defining * ASIO_DISABLE_IOCP. * * @li Use the close() function to simultaneously cancel the outstanding * operations and close the socket. * * When running on Windows Vista, Windows Server 2008, and later, the * CancelIoEx function is always used. This function does not have the * problems described above. */ #if defined(BOOST_MSVC) && (BOOST_MSVC >= 1400) \ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ && !defined(ASIO_ENABLE_CANCELIO) __declspec(deprecated("By default, this function always fails with " "operation_not_supported when used on Windows XP, Windows Server 2003, " "or earlier. Consult documentation for details.")) #endif asio::error_code cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } /// Determine whether the socket is at the out-of-band data mark. /** * This function is used to check whether the socket input is currently * positioned at the out-of-band data mark. * * @return A bool indicating whether the socket is at the out-of-band data * mark. * * @throws asio::system_error Thrown on failure. */ bool at_mark() const { asio::error_code ec; bool b = this->service.at_mark(this->implementation, ec); asio::detail::throw_error(ec); return b; } /// Determine whether the socket is at the out-of-band data mark. /** * This function is used to check whether the socket input is currently * positioned at the out-of-band data mark. * * @param ec Set to indicate what error occurred, if any. * * @return A bool indicating whether the socket is at the out-of-band data * mark. */ bool at_mark(asio::error_code& ec) const { return this->service.at_mark(this->implementation, ec); } /// Determine the number of bytes available for reading. /** * This function is used to determine the number of bytes that may be read * without blocking. * * @return The number of bytes that may be read without blocking, or 0 if an * error occurs. * * @throws asio::system_error Thrown on failure. */ std::size_t available() const { asio::error_code ec; std::size_t s = this->service.available(this->implementation, ec); asio::detail::throw_error(ec); return s; } /// Determine the number of bytes available for reading. /** * This function is used to determine the number of bytes that may be read * without blocking. * * @param ec Set to indicate what error occurred, if any. * * @return The number of bytes that may be read without blocking, or 0 if an * error occurs. */ std::size_t available(asio::error_code& ec) const { return this->service.available(this->implementation, ec); } /// Bind the socket to the given local endpoint. /** * This function binds the socket to the specified endpoint on the local * machine. * * @param endpoint An endpoint on the local machine to which the socket will * be bound. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); * socket.bind(asio::ip::tcp::endpoint( * asio::ip::tcp::v4(), 12345)); * @endcode */ void bind(const endpoint_type& endpoint) { asio::error_code ec; this->service.bind(this->implementation, endpoint, ec); asio::detail::throw_error(ec); } /// Bind the socket to the given local endpoint. /** * This function binds the socket to the specified endpoint on the local * machine. * * @param endpoint An endpoint on the local machine to which the socket will * be bound. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); * asio::error_code ec; * socket.bind(asio::ip::tcp::endpoint( * asio::ip::tcp::v4(), 12345), ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code bind(const endpoint_type& endpoint, asio::error_code& ec) { return this->service.bind(this->implementation, endpoint, ec); } /// Connect the socket to the specified endpoint. /** * This function is used to connect a socket to the specified remote endpoint. * The function call will block until the connection is successfully made or * an error occurs. * * The socket is automatically opened if it is not already open. If the * connect fails, and the socket was automatically opened, the socket is * not returned to the closed state. * * @param peer_endpoint The remote endpoint to which the socket will be * connected. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.connect(endpoint); * @endcode */ void connect(const endpoint_type& peer_endpoint) { asio::error_code ec; if (!is_open()) { this->service.open(this->implementation, peer_endpoint.protocol(), ec); asio::detail::throw_error(ec); } this->service.connect(this->implementation, peer_endpoint, ec); asio::detail::throw_error(ec); } /// Connect the socket to the specified endpoint. /** * This function is used to connect a socket to the specified remote endpoint. * The function call will block until the connection is successfully made or * an error occurs. * * The socket is automatically opened if it is not already open. If the * connect fails, and the socket was automatically opened, the socket is * not returned to the closed state. * * @param peer_endpoint The remote endpoint to which the socket will be * connected. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * asio::error_code ec; * socket.connect(endpoint, ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code connect(const endpoint_type& peer_endpoint, asio::error_code& ec) { if (!is_open()) { if (this->service.open(this->implementation, peer_endpoint.protocol(), ec)) { return ec; } } return this->service.connect(this->implementation, peer_endpoint, ec); } /// Start an asynchronous connect. /** * This function is used to asynchronously connect a socket to the specified * remote endpoint. The function call always returns immediately. * * The socket is automatically opened if it is not already open. If the * connect fails, and the socket was automatically opened, the socket is * not returned to the closed state. * * @param peer_endpoint The remote endpoint to which the socket will be * connected. Copies will be made of the endpoint object as required. * * @param handler The handler to be called when the connection operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error // Result of operation * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * @code * void connect_handler(const asio::error_code& error) * { * if (!error) * { * // Connect succeeded. * } * } * * ... * * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); * socket.async_connect(endpoint, connect_handler); * @endcode */ template void async_connect(const endpoint_type& peer_endpoint, ConnectHandler handler) { if (!is_open()) { asio::error_code ec; if (this->service.open(this->implementation, peer_endpoint.protocol(), ec)) { this->get_io_service().post( asio::detail::bind_handler(handler, ec)); return; } } this->service.async_connect(this->implementation, peer_endpoint, handler); } /// Set an option on the socket. /** * This function is used to set an option on the socket. * * @param option The new option value to be set on the socket. * * @throws asio::system_error Thrown on failure. * * @sa SettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n * asio::socket_base::linger @n * asio::socket_base::receive_buffer_size @n * asio::socket_base::receive_low_watermark @n * asio::socket_base::reuse_address @n * asio::socket_base::send_buffer_size @n * asio::socket_base::send_low_watermark @n * asio::ip::multicast::join_group @n * asio::ip::multicast::leave_group @n * asio::ip::multicast::enable_loopback @n * asio::ip::multicast::outbound_interface @n * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::no_delay option(true); * socket.set_option(option); * @endcode */ template void set_option(const SettableSocketOption& option) { asio::error_code ec; this->service.set_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Set an option on the socket. /** * This function is used to set an option on the socket. * * @param option The new option value to be set on the socket. * * @param ec Set to indicate what error occurred, if any. * * @sa SettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n * asio::socket_base::linger @n * asio::socket_base::receive_buffer_size @n * asio::socket_base::receive_low_watermark @n * asio::socket_base::reuse_address @n * asio::socket_base::send_buffer_size @n * asio::socket_base::send_low_watermark @n * asio::ip::multicast::join_group @n * asio::ip::multicast::leave_group @n * asio::ip::multicast::enable_loopback @n * asio::ip::multicast::outbound_interface @n * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::no_delay option(true); * asio::error_code ec; * socket.set_option(option, ec); * if (ec) * { * // An error occurred. * } * @endcode */ template asio::error_code set_option(const SettableSocketOption& option, asio::error_code& ec) { return this->service.set_option(this->implementation, option, ec); } /// Get an option from the socket. /** * This function is used to get the current value of an option on the socket. * * @param option The option value to be obtained from the socket. * * @throws asio::system_error Thrown on failure. * * @sa GettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n * asio::socket_base::linger @n * asio::socket_base::receive_buffer_size @n * asio::socket_base::receive_low_watermark @n * asio::socket_base::reuse_address @n * asio::socket_base::send_buffer_size @n * asio::socket_base::send_low_watermark @n * asio::ip::multicast::join_group @n * asio::ip::multicast::leave_group @n * asio::ip::multicast::enable_loopback @n * asio::ip::multicast::outbound_interface @n * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::keep_alive option; * socket.get_option(option); * bool is_set = option.get(); * @endcode */ template void get_option(GettableSocketOption& option) const { asio::error_code ec; this->service.get_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Get an option from the socket. /** * This function is used to get the current value of an option on the socket. * * @param option The option value to be obtained from the socket. * * @param ec Set to indicate what error occurred, if any. * * @sa GettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n * asio::socket_base::linger @n * asio::socket_base::receive_buffer_size @n * asio::socket_base::receive_low_watermark @n * asio::socket_base::reuse_address @n * asio::socket_base::send_buffer_size @n * asio::socket_base::send_low_watermark @n * asio::ip::multicast::join_group @n * asio::ip::multicast::leave_group @n * asio::ip::multicast::enable_loopback @n * asio::ip::multicast::outbound_interface @n * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::keep_alive option; * asio::error_code ec; * socket.get_option(option, ec); * if (ec) * { * // An error occurred. * } * bool is_set = option.get(); * @endcode */ template asio::error_code get_option(GettableSocketOption& option, asio::error_code& ec) const { return this->service.get_option(this->implementation, option, ec); } /// Perform an IO control command on the socket. /** * This function is used to execute an IO control command on the socket. * * @param command The IO control command to be performed on the socket. * * @throws asio::system_error Thrown on failure. * * @sa IoControlCommand @n * asio::socket_base::bytes_readable @n * asio::socket_base::non_blocking_io * * @par Example * Getting the number of bytes ready to read: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::bytes_readable command; * socket.io_control(command); * std::size_t bytes_readable = command.get(); * @endcode */ template void io_control(IoControlCommand& command) { asio::error_code ec; this->service.io_control(this->implementation, command, ec); asio::detail::throw_error(ec); } /// Perform an IO control command on the socket. /** * This function is used to execute an IO control command on the socket. * * @param command The IO control command to be performed on the socket. * * @param ec Set to indicate what error occurred, if any. * * @sa IoControlCommand @n * asio::socket_base::bytes_readable @n * asio::socket_base::non_blocking_io * * @par Example * Getting the number of bytes ready to read: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::bytes_readable command; * asio::error_code ec; * socket.io_control(command, ec); * if (ec) * { * // An error occurred. * } * std::size_t bytes_readable = command.get(); * @endcode */ template asio::error_code io_control(IoControlCommand& command, asio::error_code& ec) { return this->service.io_control(this->implementation, command, ec); } /// Get the local endpoint of the socket. /** * This function is used to obtain the locally bound endpoint of the socket. * * @returns An object that represents the local endpoint of the socket. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); * @endcode */ endpoint_type local_endpoint() const { asio::error_code ec; endpoint_type ep = this->service.local_endpoint(this->implementation, ec); asio::detail::throw_error(ec); return ep; } /// Get the local endpoint of the socket. /** * This function is used to obtain the locally bound endpoint of the socket. * * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the local endpoint of the socket. * Returns a default-constructed endpoint object if an error occurred. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); * if (ec) * { * // An error occurred. * } * @endcode */ endpoint_type local_endpoint(asio::error_code& ec) const { return this->service.local_endpoint(this->implementation, ec); } /// Get the remote endpoint of the socket. /** * This function is used to obtain the remote endpoint of the socket. * * @returns An object that represents the remote endpoint of the socket. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); * @endcode */ endpoint_type remote_endpoint() const { asio::error_code ec; endpoint_type ep = this->service.remote_endpoint(this->implementation, ec); asio::detail::throw_error(ec); return ep; } /// Get the remote endpoint of the socket. /** * This function is used to obtain the remote endpoint of the socket. * * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the remote endpoint of the socket. * Returns a default-constructed endpoint object if an error occurred. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); * if (ec) * { * // An error occurred. * } * @endcode */ endpoint_type remote_endpoint(asio::error_code& ec) const { return this->service.remote_endpoint(this->implementation, ec); } /// Disable sends or receives on the socket. /** * This function is used to disable send operations, receive operations, or * both. * * @param what Determines what types of operation will no longer be allowed. * * @throws asio::system_error Thrown on failure. * * @par Example * Shutting down the send side of the socket: * @code * asio::ip::tcp::socket socket(io_service); * ... * socket.shutdown(asio::ip::tcp::socket::shutdown_send); * @endcode */ void shutdown(shutdown_type what) { asio::error_code ec; this->service.shutdown(this->implementation, what, ec); asio::detail::throw_error(ec); } /// Disable sends or receives on the socket. /** * This function is used to disable send operations, receive operations, or * both. * * @param what Determines what types of operation will no longer be allowed. * * @param ec Set to indicate what error occurred, if any. * * @par Example * Shutting down the send side of the socket: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::error_code ec; * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code shutdown(shutdown_type what, asio::error_code& ec) { return this->service.shutdown(this->implementation, what, ec); } protected: /// Protected destructor to prevent deletion through this type. ~basic_socket() { } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_SOCKET_HPP percona-galera-3-3.8-3390/asio/asio/basic_socket_acceptor.hpp000066400000000000000000000621561244131713600237240ustar00rootroot00000000000000// // basic_socket_acceptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_SOCKET_ACCEPTOR_HPP #define ASIO_BASIC_SOCKET_ACCEPTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" #include "asio/basic_socket.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/socket_acceptor_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides the ability to accept new connections. /** * The basic_socket_acceptor class template is used for accepting new socket * connections. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Example * Opening a socket acceptor with the SO_REUSEADDR option enabled: * @code * asio::ip::tcp::acceptor acceptor(io_service); * asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port); * acceptor.open(endpoint.protocol()); * acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true)); * acceptor.bind(endpoint); * acceptor.listen(); * @endcode */ template > class basic_socket_acceptor : public basic_io_object, public socket_base { public: /// The native representation of an acceptor. typedef typename SocketAcceptorService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// Construct an acceptor without opening it. /** * This constructor creates an acceptor without opening it to listen for new * connections. The open() function must be called before the acceptor can * accept new socket connections. * * @param io_service The io_service object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. */ explicit basic_socket_acceptor(asio::io_service& io_service) : basic_io_object(io_service) { } /// Construct an open acceptor. /** * This constructor creates an acceptor and automatically opens it. * * @param io_service The io_service object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ basic_socket_acceptor(asio::io_service& io_service, const protocol_type& protocol) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, protocol, ec); asio::detail::throw_error(ec); } /// Construct an acceptor opened on the given endpoint. /** * This constructor creates an acceptor and automatically opens it to listen * for new connections on the specified endpoint. * * @param io_service The io_service object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * * @param endpoint An endpoint on the local machine on which the acceptor * will listen for new connections. * * @param reuse_addr Whether the constructor should set the socket option * socket_base::reuse_address. * * @throws asio::system_error Thrown on failure. * * @note This constructor is equivalent to the following code: * @code * basic_socket_acceptor acceptor(io_service); * acceptor.open(endpoint.protocol()); * if (reuse_addr) * acceptor.set_option(socket_base::reuse_address(true)); * acceptor.bind(endpoint); * acceptor.listen(listen_backlog); * @endcode */ basic_socket_acceptor(asio::io_service& io_service, const endpoint_type& endpoint, bool reuse_addr = true) : basic_io_object(io_service) { asio::error_code ec; this->service.open(this->implementation, endpoint.protocol(), ec); asio::detail::throw_error(ec); if (reuse_addr) { this->service.set_option(this->implementation, socket_base::reuse_address(true), ec); asio::detail::throw_error(ec); } this->service.bind(this->implementation, endpoint, ec); asio::detail::throw_error(ec); this->service.listen(this->implementation, socket_base::max_connections, ec); asio::detail::throw_error(ec); } /// Construct a basic_socket_acceptor on an existing native acceptor. /** * This constructor creates an acceptor object to hold an existing native * acceptor. * * @param io_service The io_service object that the acceptor will use to * dispatch handlers for any asynchronous operations performed on the * acceptor. * * @param protocol An object specifying protocol parameters to be used. * * @param native_acceptor A native acceptor. * * @throws asio::system_error Thrown on failure. */ basic_socket_acceptor(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_acceptor) : basic_io_object(io_service) { asio::error_code ec; this->service.assign(this->implementation, protocol, native_acceptor, ec); asio::detail::throw_error(ec); } /// Open the acceptor using the specified protocol. /** * This function opens the socket acceptor so that it will use the specified * protocol. * * @param protocol An object specifying which protocol is to be used. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); * @endcode */ void open(const protocol_type& protocol = protocol_type()) { asio::error_code ec; this->service.open(this->implementation, protocol, ec); asio::detail::throw_error(ec); } /// Open the acceptor using the specified protocol. /** * This function opens the socket acceptor so that it will use the specified * protocol. * * @param protocol An object specifying which protocol is to be used. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * asio::error_code ec; * acceptor.open(asio::ip::tcp::v4(), ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code open(const protocol_type& protocol, asio::error_code& ec) { return this->service.open(this->implementation, protocol, ec); } /// Assigns an existing native acceptor to the acceptor. /* * This function opens the acceptor to hold an existing native acceptor. * * @param protocol An object specifying which protocol is to be used. * * @param native_acceptor A native acceptor. * * @throws asio::system_error Thrown on failure. */ void assign(const protocol_type& protocol, const native_type& native_acceptor) { asio::error_code ec; this->service.assign(this->implementation, protocol, native_acceptor, ec); asio::detail::throw_error(ec); } /// Assigns an existing native acceptor to the acceptor. /* * This function opens the acceptor to hold an existing native acceptor. * * @param protocol An object specifying which protocol is to be used. * * @param native_acceptor A native acceptor. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code assign(const protocol_type& protocol, const native_type& native_acceptor, asio::error_code& ec) { return this->service.assign(this->implementation, protocol, native_acceptor, ec); } /// Determine whether the acceptor is open. bool is_open() const { return this->service.is_open(this->implementation); } /// Bind the acceptor to the given local endpoint. /** * This function binds the socket acceptor to the specified endpoint on the * local machine. * * @param endpoint An endpoint on the local machine to which the socket * acceptor will be bound. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); * acceptor.bind(asio::ip::tcp::endpoint(12345)); * @endcode */ void bind(const endpoint_type& endpoint) { asio::error_code ec; this->service.bind(this->implementation, endpoint, ec); asio::detail::throw_error(ec); } /// Bind the acceptor to the given local endpoint. /** * This function binds the socket acceptor to the specified endpoint on the * local machine. * * @param endpoint An endpoint on the local machine to which the socket * acceptor will be bound. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); * asio::error_code ec; * acceptor.bind(asio::ip::tcp::endpoint(12345), ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code bind(const endpoint_type& endpoint, asio::error_code& ec) { return this->service.bind(this->implementation, endpoint, ec); } /// Place the acceptor into the state where it will listen for new /// connections. /** * This function puts the socket acceptor into the state where it may accept * new connections. * * @param backlog The maximum length of the queue of pending connections. * * @throws asio::system_error Thrown on failure. */ void listen(int backlog = socket_base::max_connections) { asio::error_code ec; this->service.listen(this->implementation, backlog, ec); asio::detail::throw_error(ec); } /// Place the acceptor into the state where it will listen for new /// connections. /** * This function puts the socket acceptor into the state where it may accept * new connections. * * @param backlog The maximum length of the queue of pending connections. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::error_code ec; * acceptor.listen(asio::socket_base::max_connections, ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code listen(int backlog, asio::error_code& ec) { return this->service.listen(this->implementation, backlog, ec); } /// Close the acceptor. /** * This function is used to close the acceptor. Any asynchronous accept * operations will be cancelled immediately. * * A subsequent call to open() is required before the acceptor can again be * used to again perform socket accept operations. * * @throws asio::system_error Thrown on failure. */ void close() { asio::error_code ec; this->service.close(this->implementation, ec); asio::detail::throw_error(ec); } /// Close the acceptor. /** * This function is used to close the acceptor. Any asynchronous accept * operations will be cancelled immediately. * * A subsequent call to open() is required before the acceptor can again be * used to again perform socket accept operations. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::error_code ec; * acceptor.close(ec); * if (ec) * { * // An error occurred. * } * @endcode */ asio::error_code close(asio::error_code& ec) { return this->service.close(this->implementation, ec); } /// Get the native acceptor representation. /** * This function may be used to obtain the underlying representation of the * acceptor. This is intended to allow access to native acceptor functionality * that is not otherwise provided. */ native_type native() { return this->service.native(this->implementation); } /// Cancel all asynchronous operations associated with the acceptor. /** * This function causes all outstanding asynchronous connect, send and receive * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void cancel() { asio::error_code ec; this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the acceptor. /** * This function causes all outstanding asynchronous connect, send and receive * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } /// Set an option on the acceptor. /** * This function is used to set an option on the acceptor. * * @param option The new option value to be set on the acceptor. * * @throws asio::system_error Thrown on failure. * * @sa SettableSocketOption @n * asio::socket_base::reuse_address * asio::socket_base::enable_connection_aborted * * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option(true); * acceptor.set_option(option); * @endcode */ template void set_option(const SettableSocketOption& option) { asio::error_code ec; this->service.set_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Set an option on the acceptor. /** * This function is used to set an option on the acceptor. * * @param option The new option value to be set on the acceptor. * * @param ec Set to indicate what error occurred, if any. * * @sa SettableSocketOption @n * asio::socket_base::reuse_address * asio::socket_base::enable_connection_aborted * * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option(true); * asio::error_code ec; * acceptor.set_option(option, ec); * if (ec) * { * // An error occurred. * } * @endcode */ template asio::error_code set_option(const SettableSocketOption& option, asio::error_code& ec) { return this->service.set_option(this->implementation, option, ec); } /// Get an option from the acceptor. /** * This function is used to get the current value of an option on the * acceptor. * * @param option The option value to be obtained from the acceptor. * * @throws asio::system_error Thrown on failure. * * @sa GettableSocketOption @n * asio::socket_base::reuse_address * * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option; * acceptor.get_option(option); * bool is_set = option.get(); * @endcode */ template void get_option(GettableSocketOption& option) { asio::error_code ec; this->service.get_option(this->implementation, option, ec); asio::detail::throw_error(ec); } /// Get an option from the acceptor. /** * This function is used to get the current value of an option on the * acceptor. * * @param option The option value to be obtained from the acceptor. * * @param ec Set to indicate what error occurred, if any. * * @sa GettableSocketOption @n * asio::socket_base::reuse_address * * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option; * asio::error_code ec; * acceptor.get_option(option, ec); * if (ec) * { * // An error occurred. * } * bool is_set = option.get(); * @endcode */ template asio::error_code get_option(GettableSocketOption& option, asio::error_code& ec) { return this->service.get_option(this->implementation, option, ec); } /// Get the local endpoint of the acceptor. /** * This function is used to obtain the locally bound endpoint of the acceptor. * * @returns An object that represents the local endpoint of the acceptor. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); * @endcode */ endpoint_type local_endpoint() const { asio::error_code ec; endpoint_type ep = this->service.local_endpoint(this->implementation, ec); asio::detail::throw_error(ec); return ep; } /// Get the local endpoint of the acceptor. /** * This function is used to obtain the locally bound endpoint of the acceptor. * * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the local endpoint of the acceptor. * Returns a default-constructed endpoint object if an error occurred and the * error handler did not throw an exception. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::error_code ec; * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); * if (ec) * { * // An error occurred. * } * @endcode */ endpoint_type local_endpoint(asio::error_code& ec) const { return this->service.local_endpoint(this->implementation, ec); } /// Accept a new connection. /** * This function is used to accept a new connection from a peer into the * given socket. The function call will block until a new connection has been * accepted successfully or an error occurs. * * @param peer The socket into which the new connection will be accepted. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * acceptor.accept(socket); * @endcode */ template void accept(basic_socket& peer) { asio::error_code ec; this->service.accept(this->implementation, peer, 0, ec); asio::detail::throw_error(ec); } /// Accept a new connection. /** * This function is used to accept a new connection from a peer into the * given socket. The function call will block until a new connection has been * accepted successfully or an error occurs. * * @param peer The socket into which the new connection will be accepted. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::soocket socket(io_service); * asio::error_code ec; * acceptor.accept(socket, ec); * if (ec) * { * // An error occurred. * } * @endcode */ template asio::error_code accept( basic_socket& peer, asio::error_code& ec) { return this->service.accept(this->implementation, peer, 0, ec); } /// Start an asynchronous accept. /** * This function is used to asynchronously accept a new connection into a * socket. The function call always returns immediately. * * @param peer The socket into which the new connection will be accepted. * Ownership of the peer object is retained by the caller, which must * guarantee that it is valid until the handler is called. * * @param handler The handler to be called when the accept operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * @code * void accept_handler(const asio::error_code& error) * { * if (!error) * { * // Accept succeeded. * } * } * * ... * * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * acceptor.async_accept(socket, accept_handler); * @endcode */ template void async_accept(basic_socket& peer, AcceptHandler handler) { this->service.async_accept(this->implementation, peer, 0, handler); } /// Accept a new connection and obtain the endpoint of the peer /** * This function is used to accept a new connection from a peer into the * given socket, and additionally provide the endpoint of the remote peer. * The function call will block until a new connection has been accepted * successfully or an error occurs. * * @param peer The socket into which the new connection will be accepted. * * @param peer_endpoint An endpoint object which will receive the endpoint of * the remote peer. * * @throws asio::system_error Thrown on failure. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint; * acceptor.accept(socket, endpoint); * @endcode */ template void accept(basic_socket& peer, endpoint_type& peer_endpoint) { asio::error_code ec; this->service.accept(this->implementation, peer, &peer_endpoint, ec); asio::detail::throw_error(ec); } /// Accept a new connection and obtain the endpoint of the peer /** * This function is used to accept a new connection from a peer into the * given socket, and additionally provide the endpoint of the remote peer. * The function call will block until a new connection has been accepted * successfully or an error occurs. * * @param peer The socket into which the new connection will be accepted. * * @param peer_endpoint An endpoint object which will receive the endpoint of * the remote peer. * * @param ec Set to indicate what error occurred, if any. * * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint; * asio::error_code ec; * acceptor.accept(socket, endpoint, ec); * if (ec) * { * // An error occurred. * } * @endcode */ template asio::error_code accept( basic_socket& peer, endpoint_type& peer_endpoint, asio::error_code& ec) { return this->service.accept(this->implementation, peer, &peer_endpoint, ec); } /// Start an asynchronous accept. /** * This function is used to asynchronously accept a new connection into a * socket, and additionally obtain the endpoint of the remote peer. The * function call always returns immediately. * * @param peer The socket into which the new connection will be accepted. * Ownership of the peer object is retained by the caller, which must * guarantee that it is valid until the handler is called. * * @param peer_endpoint An endpoint object into which the endpoint of the * remote peer will be written. Ownership of the peer_endpoint object is * retained by the caller, which must guarantee that it is valid until the * handler is called. * * @param handler The handler to be called when the accept operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_accept(basic_socket& peer, endpoint_type& peer_endpoint, AcceptHandler handler) { this->service.async_accept(this->implementation, peer, &peer_endpoint, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_SOCKET_ACCEPTOR_HPP percona-galera-3-3.8-3390/asio/asio/basic_socket_iostream.hpp000066400000000000000000000113641244131713600237420ustar00rootroot00000000000000// // basic_socket_iostream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_SOCKET_IOSTREAM_HPP #define ASIO_BASIC_SOCKET_IOSTREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include #include #include #include #include #include "asio/basic_socket_streambuf.hpp" #include "asio/stream_socket_service.hpp" #if !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY) #define ASIO_SOCKET_IOSTREAM_MAX_ARITY 5 #endif // !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY) // A macro that should expand to: // template // explicit basic_socket_iostream(T1 x1, ..., Tn xn) // : basic_iostream(&this->boost::base_from_member< // basic_socket_streambuf >::member) // { // if (rdbuf()->connect(x1, ..., xn) == 0) // this->setstate(std::ios_base::failbit); // } // This macro should only persist within this file. #define ASIO_PRIVATE_CTR_DEF(z, n, data) \ template \ explicit basic_socket_iostream(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ : std::basic_iostream(&this->boost::base_from_member< \ basic_socket_streambuf >::member) \ { \ tie(this); \ if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ this->setstate(std::ios_base::failbit); \ } \ /**/ // A macro that should expand to: // template // void connect(T1 x1, ..., Tn xn) // { // if (rdbuf()->connect(x1, ..., xn) == 0) // this->setstate(std::ios_base::failbit); // } // This macro should only persist within this file. #define ASIO_PRIVATE_CONNECT_DEF(z, n, data) \ template \ void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ { \ if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ this->setstate(std::ios_base::failbit); \ } \ /**/ #include "asio/detail/push_options.hpp" namespace asio { /// Iostream interface for a socket. template > class basic_socket_iostream : public boost::base_from_member< basic_socket_streambuf >, public std::basic_iostream { public: /// Construct a basic_socket_iostream without establishing a connection. basic_socket_iostream() : std::basic_iostream(&this->boost::base_from_member< basic_socket_streambuf >::member) { tie(this); } #if defined(GENERATING_DOCUMENTATION) /// Establish a connection to an endpoint corresponding to a resolver query. /** * This constructor automatically establishes a connection based on the * supplied resolver query parameters. The arguments are used to construct * a resolver query object. */ template explicit basic_socket_iostream(T1 t1, ..., TN tn); #else BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY), ASIO_PRIVATE_CTR_DEF, _ ) #endif #if defined(GENERATING_DOCUMENTATION) /// Establish a connection to an endpoint corresponding to a resolver query. /** * This function automatically establishes a connection based on the supplied * resolver query parameters. The arguments are used to construct a resolver * query object. */ template void connect(T1 t1, ..., TN tn); #else BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(ASIO_SOCKET_IOSTREAM_MAX_ARITY), ASIO_PRIVATE_CONNECT_DEF, _ ) #endif /// Close the connection. void close() { if (rdbuf()->close() == 0) this->setstate(std::ios_base::failbit); } /// Return a pointer to the underlying streambuf. basic_socket_streambuf* rdbuf() const { return const_cast*>( &this->boost::base_from_member< basic_socket_streambuf >::member); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_PRIVATE_CTR_DEF #undef ASIO_PRIVATE_CONNECT_DEF #endif // defined(BOOST_NO_IOSTREAM) #endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP percona-galera-3-3.8-3390/asio/asio/basic_socket_streambuf.hpp000066400000000000000000000201031244131713600240760ustar00rootroot00000000000000// // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_SOCKET_STREAMBUF_HPP #define ASIO_BASIC_SOCKET_STREAMBUF_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include #include #include #include #include #include #include #include "asio/basic_socket.hpp" #include "asio/detail/throw_error.hpp" #include "asio/io_service.hpp" #include "asio/stream_socket_service.hpp" #if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY) #define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 #endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY) // A macro that should expand to: // template // basic_socket_streambuf* connect( // T1 x1, ..., Tn xn) // { // init_buffers(); // asio::error_code ec; // this->basic_socket::close(ec); // typedef typename Protocol::resolver resolver_type; // typedef typename resolver_type::query resolver_query; // resolver_query query(x1, ..., xn); // resolve_and_connect(query, ec); // return !ec ? this : 0; // } // This macro should only persist within this file. #define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ template \ basic_socket_streambuf* connect( \ BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ { \ init_buffers(); \ asio::error_code ec; \ this->basic_socket::close(ec); \ typedef typename Protocol::resolver resolver_type; \ typedef typename resolver_type::query resolver_query; \ resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \ resolve_and_connect(query, ec); \ return !ec ? this : 0; \ } \ /**/ #include "asio/detail/push_options.hpp" namespace asio { /// Iostream streambuf for a socket. template > class basic_socket_streambuf : public std::streambuf, private boost::base_from_member, public basic_socket { public: /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf() : basic_socket( boost::base_from_member::member), unbuffered_(false) { init_buffers(); } /// Destructor flushes buffered data. virtual ~basic_socket_streambuf() { if (pptr() != pbase()) overflow(traits_type::eof()); } /// Establish a connection. /** * This function establishes a connection to the specified endpoint. * * @return \c this if a connection was successfully established, a null * pointer otherwise. */ basic_socket_streambuf* connect( const endpoint_type& endpoint) { init_buffers(); asio::error_code ec; this->basic_socket::close(ec); this->basic_socket::connect(endpoint, ec); return !ec ? this : 0; } #if defined(GENERATING_DOCUMENTATION) /// Establish a connection. /** * This function automatically establishes a connection based on the supplied * resolver query parameters. The arguments are used to construct a resolver * query object. * * @return \c this if a connection was successfully established, a null * pointer otherwise. */ template basic_socket_streambuf* connect( T1 t1, ..., TN tn); #else BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY), ASIO_PRIVATE_CONNECT_DEF, _ ) #endif /// Close the connection. /** * @return \c this if a connection was successfully established, a null * pointer otherwise. */ basic_socket_streambuf* close() { asio::error_code ec; sync(); this->basic_socket::close(ec); if (!ec) init_buffers(); return !ec ? this : 0; } protected: int_type underflow() { if (gptr() == egptr()) { asio::error_code ec; std::size_t bytes_transferred = this->service.receive( this->implementation, asio::buffer(asio::buffer(get_buffer_) + putback_max), 0, ec); if (ec) return traits_type::eof(); setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, get_buffer_.begin() + putback_max + bytes_transferred); return traits_type::to_int_type(*gptr()); } else { return traits_type::eof(); } } int_type overflow(int_type c) { if (unbuffered_) { if (traits_type::eq_int_type(c, traits_type::eof())) { // Nothing to do. return traits_type::not_eof(c); } else { // Send the single character immediately. asio::error_code ec; char_type ch = traits_type::to_char_type(c); this->service.send(this->implementation, asio::buffer(&ch, sizeof(char_type)), 0, ec); if (ec) return traits_type::eof(); return c; } } else { // Send all data in the output buffer. asio::const_buffer buffer = asio::buffer(pbase(), pptr() - pbase()); while (asio::buffer_size(buffer) > 0) { asio::error_code ec; std::size_t bytes_transferred = this->service.send( this->implementation, asio::buffer(buffer), 0, ec); if (ec) return traits_type::eof(); buffer = buffer + bytes_transferred; } setp(put_buffer_.begin(), put_buffer_.end()); // If the new character is eof then our work here is done. if (traits_type::eq_int_type(c, traits_type::eof())) return traits_type::not_eof(c); // Add the new character to the output buffer. *pptr() = traits_type::to_char_type(c); pbump(1); return c; } } int sync() { return overflow(traits_type::eof()); } std::streambuf* setbuf(char_type* s, std::streamsize n) { if (pptr() == pbase() && s == 0 && n == 0) { unbuffered_ = true; setp(0, 0); return this; } return 0; } private: void init_buffers() { setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, get_buffer_.begin() + putback_max); if (unbuffered_) setp(0, 0); else setp(put_buffer_.begin(), put_buffer_.end()); } template void resolve_and_connect(const ResolverQuery& query, asio::error_code& ec) { typedef typename Protocol::resolver resolver_type; typedef typename resolver_type::iterator iterator_type; resolver_type resolver( boost::base_from_member::member); iterator_type i = resolver.resolve(query, ec); if (!ec) { iterator_type end; ec = asio::error::host_not_found; while (ec && i != end) { this->basic_socket::close(); this->basic_socket::connect(*i, ec); ++i; } } } enum { putback_max = 8 }; enum { buffer_size = 512 }; boost::array get_buffer_; boost::array put_buffer_; bool unbuffered_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_PRIVATE_CONNECT_DEF #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP percona-galera-3-3.8-3390/asio/asio/basic_stream_socket.hpp000066400000000000000000000673661244131713600234270ustar00rootroot00000000000000// // basic_stream_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_STREAM_SOCKET_HPP #define ASIO_BASIC_STREAM_SOCKET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_socket.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/stream_socket_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides stream-oriented socket functionality. /** * The basic_stream_socket class template provides asynchronous and blocking * stream-oriented socket functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template > class basic_stream_socket : public basic_socket { public: /// The native representation of a socket. typedef typename StreamSocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; /// Construct a basic_stream_socket without opening it. /** * This constructor creates a stream socket without opening it. The socket * needs to be opened and then connected or accepted before data can be sent * or received on it. * * @param io_service The io_service object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. */ explicit basic_stream_socket(asio::io_service& io_service) : basic_socket(io_service) { } /// Construct and open a basic_stream_socket. /** * This constructor creates and opens a stream socket. The socket needs to be * connected or accepted before data can be sent or received on it. * * @param io_service The io_service object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const protocol_type& protocol) : basic_socket(io_service, protocol) { } /// Construct a basic_stream_socket, opening it and binding it to the given /// local endpoint. /** * This constructor creates a stream socket and automatically opens it bound * to the specified endpoint on the local machine. The protocol used is the * protocol associated with the given endpoint. * * @param io_service The io_service object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param endpoint An endpoint on the local machine to which the stream * socket will be bound. * * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const endpoint_type& endpoint) : basic_socket(io_service, endpoint) { } /// Construct a basic_stream_socket on an existing native socket. /** * This constructor creates a stream socket object to hold an existing native * socket. * * @param io_service The io_service object that the stream socket will use to * dispatch handlers for any asynchronous operations performed on the socket. * * @param protocol An object specifying protocol parameters to be used. * * @param native_socket The new underlying socket implementation. * * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) : basic_socket( io_service, protocol, native_socket) { } /// Send some data on the socket. /** * This function is used to send data on the stream socket. The function * call will block until one or more bytes of the data has been sent * successfully, or an until error occurs. * * @param buffers One or more data buffers to be sent on the socket. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.send(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.send( this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Send some data on the socket. /** * This function is used to send data on the stream socket. The function * call will block until one or more bytes of the data has been sent * successfully, or an until error occurs. * * @param buffers One or more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @returns The number of bytes sent. * * @throws asio::system_error Thrown on failure. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.send(asio::buffer(data, size), 0); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.send( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Send some data on the socket. /** * This function is used to send data on the stream socket. The function * call will block until one or more bytes of the data has been sent * successfully, or an until error occurs. * * @param buffers One or more data buffers to be sent on the socket. * * @param flags Flags specifying how the send call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. Returns 0 if an error occurred. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. */ template std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.send(this->implementation, buffers, flags, ec); } /// Start an asynchronous send. /** * This function is used to asynchronously send data on the stream socket. * The function call always returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } /// Start an asynchronous send. /** * This function is used to asynchronously send data on the stream socket. * The function call always returns immediately. * * @param buffers One or more data buffers to be sent on the socket. Although * the buffers object may be copied as necessary, ownership of the underlying * memory blocks is retained by the caller, which must guarantee that they * remain valid until the handler is called. * * @param flags Flags specifying how the send call is to be made. * * @param handler The handler to be called when the send operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), 0, handler); * @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { this->service.async_send(this->implementation, buffers, flags, handler); } /// Receive some data on the socket. /** * This function is used to receive data on the stream socket. The function * call will block until one or more bytes of data has been received * successfully, or until an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.receive(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on the socket. /** * This function is used to receive data on the stream socket. The function * call will block until one or more bytes of data has been received * successfully, or until an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @returns The number of bytes received. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.receive(asio::buffer(data, size), 0); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags) { asio::error_code ec; std::size_t s = this->service.receive( this->implementation, buffers, flags, ec); asio::detail::throw_error(ec); return s; } /// Receive some data on a connected socket. /** * This function is used to receive data on the stream socket. The function * call will block until one or more bytes of data has been received * successfully, or until an error occurs. * * @param buffers One or more buffers into which the data will be received. * * @param flags Flags specifying how the receive call is to be made. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. Returns 0 if an error occurred. * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ template std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return this->service.receive(this->implementation, buffers, flags, ec); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the stream * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure * that the requested amount of data is received before the asynchronous * operation completes. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.async_receive(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } /// Start an asynchronous receive. /** * This function is used to asynchronously receive data from the stream * socket. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be received. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param flags Flags specifying how the receive call is to be made. * * @param handler The handler to be called when the receive operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref async_read function if you need to ensure * that the requested amount of data is received before the asynchronous * operation completes. * * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code * socket.async_receive(asio::buffer(data, size), 0, handler); * @endcode * See the @ref buffer documentation for information on receiving into * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, flags, handler); } /// Write some data to the socket. /** * This function is used to write data to the stream socket. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the socket. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * socket.write_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.send(this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the socket. /** * This function is used to write data to the stream socket. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the socket. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return this->service.send(this->implementation, buffers, 0, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream socket. * The function call always returns immediately. * * @param buffers One or more data buffers to be written to the socket. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * socket.async_write_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } /// Read some data from the socket. /** * This function is used to read data from the stream socket. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * socket.read_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the socket. /** * This function is used to read data from the stream socket. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return this->service.receive(this->implementation, buffers, 0, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream socket. * The function call always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the * requested amount of data is read before the asynchronous operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * socket.async_read_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BASIC_STREAM_SOCKET_HPP percona-galera-3-3.8-3390/asio/asio/basic_streambuf.hpp000066400000000000000000000255761244131713600225510ustar00rootroot00000000000000// // basic_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_STREAMBUF_HPP #define ASIO_BASIC_STREAMBUF_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include #include #include #include #include #include #include #include "asio/basic_streambuf_fwd.hpp" #include "asio/buffer.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Automatically resizable buffer class based on std::streambuf. /** * The @c basic_streambuf class is derived from @c std::streambuf to associate * the streambuf's input and output sequences with one or more character * arrays. These character arrays are internal to the @c basic_streambuf * object, but direct access to the array elements is provided to permit them * to be used efficiently with I/O operations. Characters written to the output * sequence of a @c basic_streambuf object are appended to the input sequence * of the same object. * * The @c basic_streambuf class's public interface is intended to permit the * following implementation strategies: * * @li A single contiguous character array, which is reallocated as necessary * to accommodate changes in the size of the character sequence. This is the * implementation approach currently used in Asio. * * @li A sequence of one or more character arrays, where each array is of the * same size. Additional character array objects are appended to the sequence * to accommodate changes in the size of the character sequence. * * @li A sequence of one or more character arrays of varying sizes. Additional * character array objects are appended to the sequence to accommodate changes * in the size of the character sequence. * * The constructor for basic_streambuf accepts a @c size_t argument specifying * the maximum of the sum of the sizes of the input sequence and output * sequence. During the lifetime of the @c basic_streambuf object, the following * invariant holds: * @code size() <= max_size()@endcode * Any member function that would, if successful, cause the invariant to be * violated shall throw an exception of class @c std::length_error. * * The constructor for @c basic_streambuf takes an Allocator argument. A copy * of this argument is used for any memory allocation performed, by the * constructor and by all member functions, during the lifetime of each @c * basic_streambuf object. * * @par Examples * Writing directly from an streambuf to a socket: * @code * asio::streambuf b; * std::ostream os(&b); * os << "Hello, World!\n"; * * // try sending some data in input sequence * size_t n = sock.send(b.data()); * * b.consume(n); // sent data is removed from input sequence * @endcode * * Reading from a socket directly into a streambuf: * @code * asio::streambuf b; * * // reserve 512 bytes in output sequence * asio::streambuf::mutable_buffers_type bufs = b.prepare(512); * * size_t n = sock.receive(bufs); * * // received data is "committed" from output sequence to input sequence * b.commit(n); * * std::istream is(&b); * std::string s; * is >> s; * @endcode */ #if defined(GENERATING_DOCUMENTATION) template > #else template #endif class basic_streambuf : public std::streambuf, private noncopyable { public: #if defined(GENERATING_DOCUMENTATION) /// The type used to represent the input sequence as a list of buffers. typedef implementation_defined const_buffers_type; /// The type used to represent the output sequence as a list of buffers. typedef implementation_defined mutable_buffers_type; #else typedef asio::const_buffers_1 const_buffers_type; typedef asio::mutable_buffers_1 mutable_buffers_type; #endif /// Construct a basic_streambuf object. /** * Constructs a streambuf with the specified maximum size. The initial size * of the streambuf's input sequence is 0. */ explicit basic_streambuf( std::size_t max_size = (std::numeric_limits::max)(), const Allocator& allocator = Allocator()) : max_size_(max_size), buffer_(allocator) { std::size_t pend = (std::min)(max_size_, buffer_delta); buffer_.resize((std::max)(pend, 1)); setg(&buffer_[0], &buffer_[0], &buffer_[0]); setp(&buffer_[0], &buffer_[0] + pend); } /// Get the size of the input sequence. /** * @returns The size of the input sequence. The value is equal to that * calculated for @c s in the following code: * @code * size_t s = 0; * const_buffers_type bufs = data(); * const_buffers_type::const_iterator i = bufs.begin(); * while (i != bufs.end()) * { * const_buffer buf(*i++); * s += buffer_size(buf); * } * @endcode */ std::size_t size() const { return pptr() - gptr(); } /// Get the maximum size of the basic_streambuf. /** * @returns The allowed maximum of the sum of the sizes of the input sequence * and output sequence. */ std::size_t max_size() const { return max_size_; } /// Get a list of buffers that represents the input sequence. /** * @returns An object of type @c const_buffers_type that satisfies * ConstBufferSequence requirements, representing all character arrays in the * input sequence. * * @note The returned object is invalidated by any @c basic_streambuf member * function that modifies the input sequence or output sequence. */ const_buffers_type data() const { return asio::buffer(asio::const_buffer(gptr(), (pptr() - gptr()) * sizeof(char_type))); } /// Get a list of buffers that represents the output sequence, with the given /// size. /** * Ensures that the output sequence can accommodate @c n characters, * reallocating character array objects as necessary. * * @returns An object of type @c mutable_buffers_type that satisfies * MutableBufferSequence requirements, representing character array objects * at the start of the output sequence such that the sum of the buffer sizes * is @c n. * * @throws std::length_error If size() + n > max_size(). * * @note The returned object is invalidated by any @c basic_streambuf member * function that modifies the input sequence or output sequence. */ mutable_buffers_type prepare(std::size_t n) { reserve(n); return asio::buffer(asio::mutable_buffer( pptr(), n * sizeof(char_type))); } /// Move characters from the output sequence to the input sequence. /** * Appends @c n characters from the start of the output sequence to the input * sequence. The beginning of the output sequence is advanced by @c n * characters. * * Requires a preceding call prepare(x) where x >= n, and * no intervening operations that modify the input or output sequence. * * @throws std::length_error If @c n is greater than the size of the output * sequence. */ void commit(std::size_t n) { if (pptr() + n > epptr()) n = epptr() - pptr(); pbump(static_cast(n)); setg(eback(), gptr(), pptr()); } /// Remove characters from the input sequence. /** * Removes @c n characters from the beginning of the input sequence. * * @throws std::length_error If n > size(). */ void consume(std::size_t n) { if (gptr() + n > pptr()) n = pptr() - gptr(); gbump(static_cast(n)); } protected: enum { buffer_delta = 128 }; /// Override std::streambuf behaviour. /** * Behaves according to the specification of @c std::streambuf::underflow(). */ int_type underflow() { if (gptr() < pptr()) { setg(&buffer_[0], gptr(), pptr()); return traits_type::to_int_type(*gptr()); } else { return traits_type::eof(); } } /// Override std::streambuf behaviour. /** * Behaves according to the specification of @c std::streambuf::overflow(), * with the specialisation that @c std::length_error is thrown if appending * the character to the input sequence would require the condition * size() > max_size() to be true. */ int_type overflow(int_type c) { if (!traits_type::eq_int_type(c, traits_type::eof())) { if (pptr() == epptr()) { std::size_t buffer_size = pptr() - gptr(); if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta) { reserve(max_size_ - buffer_size); } else { reserve(buffer_delta); } } *pptr() = traits_type::to_char_type(c); pbump(1); return c; } return traits_type::not_eof(c); } void reserve(std::size_t n) { // Get current stream positions as offsets. std::size_t gnext = gptr() - &buffer_[0]; std::size_t pnext = pptr() - &buffer_[0]; std::size_t pend = epptr() - &buffer_[0]; // Check if there is already enough space in the put area. if (n <= pend - pnext) { return; } // Shift existing contents of get area to start of buffer. if (gnext > 0) { pnext -= gnext; std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); } // Ensure buffer is large enough to hold at least the specified size. if (n > pend - pnext) { if (n <= max_size_ && pnext <= max_size_ - n) { pend = pnext + n; buffer_.resize((std::max)(pend, 1)); } else { std::length_error ex("asio::streambuf too long"); boost::throw_exception(ex); } } // Update stream positions. setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); setp(&buffer_[0] + pnext, &buffer_[0] + pend); } private: std::size_t max_size_; std::vector buffer_; // Helper function to get the preferred size for reading data. friend std::size_t read_size_helper( basic_streambuf& sb, std::size_t max_size) { return std::min( std::max(512, sb.buffer_.capacity() - sb.size()), std::min(max_size, sb.max_size() - sb.size())); } }; // Helper function to get the preferred size for reading data. Used for any // user-provided specialisations of basic_streambuf. template inline std::size_t read_size_helper( basic_streambuf& sb, std::size_t max_size) { return std::min(512, std::min(max_size, sb.max_size() - sb.size())); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_BASIC_STREAMBUF_HPP percona-galera-3-3.8-3390/asio/asio/basic_streambuf_fwd.hpp000066400000000000000000000013751244131713600234000ustar00rootroot00000000000000// // basic_streambuf_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BASIC_STREAMBUF_FWD_HPP #define ASIO_BASIC_STREAMBUF_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include namespace asio { template > class basic_streambuf; } // namespace asio #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_BASIC_STREAMBUF_FWD_HPP percona-galera-3-3.8-3390/asio/asio/buffer.hpp000066400000000000000000000751611244131713600206640ustar00rootroot00000000000000// // buffer.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFER_HPP #define ASIO_BUFFER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/array_fwd.hpp" #if defined(BOOST_MSVC) # if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) # if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # define ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # endif // defined(_HAS_ITERATOR_DEBUGGING) #endif // defined(BOOST_MSVC) #if defined(__GNUC__) # if defined(_GLIBCXX_DEBUG) # if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # define ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # endif // defined(_GLIBCXX_DEBUG) #endif // defined(__GNUC__) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) # include #endif // ASIO_ENABLE_BUFFER_DEBUGGING #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) # include #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) #include "asio/detail/push_options.hpp" namespace asio { class mutable_buffer; class const_buffer; namespace detail { void* buffer_cast_helper(const mutable_buffer&); const void* buffer_cast_helper(const const_buffer&); std::size_t buffer_size_helper(const mutable_buffer&); std::size_t buffer_size_helper(const const_buffer&); } // namespace detail /// Holds a buffer that can be modified. /** * The mutable_buffer class provides a safe representation of a buffer that can * be modified. It does not own the underlying data, and so is cheap to copy or * assign. */ class mutable_buffer { public: /// Construct an empty buffer. mutable_buffer() : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. mutable_buffer(void* data, std::size_t size) : data_(data), size_(size) { } #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) mutable_buffer(void* data, std::size_t size, boost::function debug_check) : data_(data), size_(size), debug_check_(debug_check) { } const boost::function& get_debug_check() const { return debug_check_; } #endif // ASIO_ENABLE_BUFFER_DEBUGGING private: friend void* asio::detail::buffer_cast_helper( const mutable_buffer& b); friend std::size_t asio::detail::buffer_size_helper( const mutable_buffer& b); void* data_; std::size_t size_; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) boost::function debug_check_; #endif // ASIO_ENABLE_BUFFER_DEBUGGING }; namespace detail { inline void* buffer_cast_helper(const mutable_buffer& b) { #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (b.size_ && b.debug_check_) b.debug_check_(); #endif // ASIO_ENABLE_BUFFER_DEBUGGING return b.data_; } inline std::size_t buffer_size_helper(const mutable_buffer& b) { return b.size_; } } // namespace detail /// Cast a non-modifiable buffer to a specified pointer to POD type. /** * @relates mutable_buffer */ template inline PointerToPodType buffer_cast(const mutable_buffer& b) { return static_cast(detail::buffer_cast_helper(b)); } /// Get the number of bytes in a non-modifiable buffer. /** * @relates mutable_buffer */ inline std::size_t buffer_size(const mutable_buffer& b) { return detail::buffer_size_helper(b); } /// Create a new modifiable buffer that is offset from the start of another. /** * @relates mutable_buffer */ inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) { if (start > buffer_size(b)) return mutable_buffer(); char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; return mutable_buffer(new_data, new_size #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Create a new modifiable buffer that is offset from the start of another. /** * @relates mutable_buffer */ inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b) { if (start > buffer_size(b)) return mutable_buffer(); char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; return mutable_buffer(new_data, new_size #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Adapts a single modifiable buffer so that it meets the requirements of the /// MutableBufferSequence concept. class mutable_buffers_1 : public mutable_buffer { public: /// The type for each element in the list of buffers. typedef mutable_buffer value_type; /// A random-access iterator type that may be used to read elements. typedef const mutable_buffer* const_iterator; /// Construct to represent a given memory range. mutable_buffers_1(void* data, std::size_t size) : mutable_buffer(data, size) { } /// Construct to represent a single modifiable buffer. explicit mutable_buffers_1(const mutable_buffer& b) : mutable_buffer(b) { } /// Get a random-access iterator to the first element. const_iterator begin() const { return this; } /// Get a random-access iterator for one past the last element. const_iterator end() const { return begin() + 1; } }; /// Holds a buffer that cannot be modified. /** * The const_buffer class provides a safe representation of a buffer that cannot * be modified. It does not own the underlying data, and so is cheap to copy or * assign. */ class const_buffer { public: /// Construct an empty buffer. const_buffer() : data_(0), size_(0) { } /// Construct a buffer to represent a given memory range. const_buffer(const void* data, std::size_t size) : data_(data), size_(size) { } /// Construct a non-modifiable buffer from a modifiable one. const_buffer(const mutable_buffer& b) : data_(asio::detail::buffer_cast_helper(b)), size_(asio::detail::buffer_size_helper(b)) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , debug_check_(b.get_debug_check()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING { } #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) const_buffer(const void* data, std::size_t size, boost::function debug_check) : data_(data), size_(size), debug_check_(debug_check) { } const boost::function& get_debug_check() const { return debug_check_; } #endif // ASIO_ENABLE_BUFFER_DEBUGGING private: friend const void* asio::detail::buffer_cast_helper( const const_buffer& b); friend std::size_t asio::detail::buffer_size_helper( const const_buffer& b); const void* data_; std::size_t size_; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) boost::function debug_check_; #endif // ASIO_ENABLE_BUFFER_DEBUGGING }; namespace detail { inline const void* buffer_cast_helper(const const_buffer& b) { #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (b.size_ && b.debug_check_) b.debug_check_(); #endif // ASIO_ENABLE_BUFFER_DEBUGGING return b.data_; } inline std::size_t buffer_size_helper(const const_buffer& b) { return b.size_; } } // namespace detail /// Cast a non-modifiable buffer to a specified pointer to POD type. /** * @relates const_buffer */ template inline PointerToPodType buffer_cast(const const_buffer& b) { return static_cast(detail::buffer_cast_helper(b)); } /// Get the number of bytes in a non-modifiable buffer. /** * @relates const_buffer */ inline std::size_t buffer_size(const const_buffer& b) { return detail::buffer_size_helper(b); } /// Create a new non-modifiable buffer that is offset from the start of another. /** * @relates const_buffer */ inline const_buffer operator+(const const_buffer& b, std::size_t start) { if (start > buffer_size(b)) return const_buffer(); const char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; return const_buffer(new_data, new_size #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Create a new non-modifiable buffer that is offset from the start of another. /** * @relates const_buffer */ inline const_buffer operator+(std::size_t start, const const_buffer& b) { if (start > buffer_size(b)) return const_buffer(); const char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; return const_buffer(new_data, new_size #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Adapts a single non-modifiable buffer so that it meets the requirements of /// the ConstBufferSequence concept. class const_buffers_1 : public const_buffer { public: /// The type for each element in the list of buffers. typedef const_buffer value_type; /// A random-access iterator type that may be used to read elements. typedef const const_buffer* const_iterator; /// Construct to represent a given memory range. const_buffers_1(const void* data, std::size_t size) : const_buffer(data, size) { } /// Construct to represent a single non-modifiable buffer. explicit const_buffers_1(const const_buffer& b) : const_buffer(b) { } /// Get a random-access iterator to the first element. const_iterator begin() const { return this; } /// Get a random-access iterator for one past the last element. const_iterator end() const { return begin() + 1; } }; /// An implementation of both the ConstBufferSequence and MutableBufferSequence /// concepts to represent a null buffer sequence. class null_buffers { public: /// The type for each element in the list of buffers. typedef mutable_buffer value_type; /// A random-access iterator type that may be used to read elements. typedef const mutable_buffer* const_iterator; /// Get a random-access iterator to the first element. const_iterator begin() const { return &buf_; } /// Get a random-access iterator for one past the last element. const_iterator end() const { return &buf_; } private: mutable_buffer buf_; }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) namespace detail { template class buffer_debug_check { public: buffer_debug_check(Iterator iter) : iter_(iter) { } ~buffer_debug_check() { #if BOOST_WORKAROUND(BOOST_MSVC, == 1400) // MSVC 8's string iterator checking may crash in a std::string::iterator // object's destructor when the iterator points to an already-destroyed // std::string object, unless the iterator is cleared first. iter_ = Iterator(); #endif // BOOST_WORKAROUND(BOOST_MSVC, == 1400) } void operator()() { *iter_; } private: Iterator iter_; }; } // namespace detail #endif // ASIO_ENABLE_BUFFER_DEBUGGING /** @defgroup buffer asio::buffer * * @brief The asio::buffer function is used to create a buffer object to * represent raw memory, an array of POD elements, a vector of POD elements, * or a std::string. * * A buffer object represents a contiguous region of memory as a 2-tuple * consisting of a pointer and size in bytes. A tuple of the form {void*, * size_t} specifies a mutable (modifiable) region of memory. Similarly, a * tuple of the form {const void*, size_t} specifies a const * (non-modifiable) region of memory. These two forms correspond to the classes * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the * opposite conversion is not permitted. * * The simplest use case involves reading or writing a single buffer of a * specified size: * * @code sock.send(asio::buffer(data, size)); @endcode * * In the above example, the return value of asio::buffer meets the * requirements of the ConstBufferSequence concept so that it may be directly * passed to the socket's write function. A buffer created for modifiable * memory also meets the requirements of the MutableBufferSequence concept. * * An individual buffer may be created from a builtin array, std::vector or * boost::array of POD elements. This helps prevent buffer overruns by * automatically determining the size of the buffer: * * @code char d1[128]; * size_t bytes_transferred = sock.receive(asio::buffer(d1)); * * std::vector d2(128); * bytes_transferred = sock.receive(asio::buffer(d2)); * * boost::array d3; * bytes_transferred = sock.receive(asio::buffer(d3)); @endcode * * In all three cases above, the buffers created are exactly 128 bytes long. * Note that a vector is @e never automatically resized when creating or using * a buffer. The buffer size is determined using the vector's size() * member function, and not its capacity. * * @par Accessing Buffer Contents * * The contents of a buffer may be accessed using the asio::buffer_size * and asio::buffer_cast functions: * * @code asio::mutable_buffer b1 = ...; * std::size_t s1 = asio::buffer_size(b1); * unsigned char* p1 = asio::buffer_cast(b1); * * asio::const_buffer b2 = ...; * std::size_t s2 = asio::buffer_size(b2); * const void* p2 = asio::buffer_cast(b2); @endcode * * The asio::buffer_cast function permits violations of type safety, so * uses of it in application code should be carefully considered. * * @par Buffer Invalidation * * A buffer object does not have any ownership of the memory it refers to. It * is the responsibility of the application to ensure the memory region remains * valid until it is no longer required for an I/O operation. When the memory * is no longer available, the buffer is said to have been invalidated. * * For the asio::buffer overloads that accept an argument of type * std::vector, the buffer objects returned are invalidated by any vector * operation that also invalidates all references, pointers and iterators * referring to the elements in the sequence (C++ Std, 23.2.4) * * For the asio::buffer overloads that accept an argument of type * std::string, the buffer objects returned are invalidated according to the * rules defined for invalidation of references, pointers and iterators * referring to elements of the sequence (C++ Std, 21.3). * * @par Buffer Arithmetic * * Buffer objects may be manipulated using simple arithmetic in a safe way * which helps prevent buffer overruns. Consider an array initialised as * follows: * * @code boost::array a = { 'a', 'b', 'c', 'd', 'e' }; @endcode * * A buffer object @c b1 created using: * * @code b1 = asio::buffer(a); @endcode * * represents the entire array, { 'a', 'b', 'c', 'd', 'e' }. An * optional second argument to the asio::buffer function may be used to * limit the size, in bytes, of the buffer: * * @code b2 = asio::buffer(a, 3); @endcode * * such that @c b2 represents the data { 'a', 'b', 'c' }. Even if the * size argument exceeds the actual size of the array, the size of the buffer * object created will be limited to the array size. * * An offset may be applied to an existing buffer to create a new one: * * @code b3 = b1 + 2; @endcode * * where @c b3 will set to represent { 'c', 'd', 'e' }. If the offset * exceeds the size of the existing buffer, the newly created buffer will be * empty. * * Both an offset and size may be specified to create a buffer that corresponds * to a specific range of bytes within an existing buffer: * * @code b4 = asio::buffer(b1 + 1, 3); @endcode * * so that @c b4 will refer to the bytes { 'b', 'c', 'd' }. * * @par Buffers and Scatter-Gather I/O * * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple * buffer objects may be assigned into a container that supports the * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: * * @code * char d1[128]; * std::vector d2(128); * boost::array d3; * * boost::array bufs1 = { * asio::buffer(d1), * asio::buffer(d2), * asio::buffer(d3) }; * bytes_transferred = sock.receive(bufs1); * * std::vector bufs2; * bufs2.push_back(asio::buffer(d1)); * bufs2.push_back(asio::buffer(d2)); * bufs2.push_back(asio::buffer(d3)); * bytes_transferred = sock.send(bufs2); @endcode */ /*@{*/ /// Create a new modifiable buffer from an existing buffer. /** * @returns mutable_buffers_1(b). */ inline mutable_buffers_1 buffer(const mutable_buffer& b) { return mutable_buffers_1(b); } /// Create a new modifiable buffer from an existing buffer. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * buffer_cast(b), * min(buffer_size(b), max_size_in_bytes)); @endcode */ inline mutable_buffers_1 buffer(const mutable_buffer& b, std::size_t max_size_in_bytes) { return mutable_buffers_1( mutable_buffer(buffer_cast(b), buffer_size(b) < max_size_in_bytes ? buffer_size(b) : max_size_in_bytes #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new non-modifiable buffer from an existing buffer. /** * @returns const_buffers_1(b). */ inline const_buffers_1 buffer(const const_buffer& b) { return const_buffers_1(b); } /// Create a new non-modifiable buffer from an existing buffer. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * buffer_cast(b), * min(buffer_size(b), max_size_in_bytes)); @endcode */ inline const_buffers_1 buffer(const const_buffer& b, std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(buffer_cast(b), buffer_size(b) < max_size_in_bytes ? buffer_size(b) : max_size_in_bytes #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , b.get_debug_check() #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new modifiable buffer that represents the given memory range. /** * @returns mutable_buffers_1(data, size_in_bytes). */ inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes) { return mutable_buffers_1(mutable_buffer(data, size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given memory range. /** * @returns const_buffers_1(data, size_in_bytes). */ inline const_buffers_1 buffer(const void* data, std::size_t size_in_bytes) { return const_buffers_1(const_buffer(data, size_in_bytes)); } /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * static_cast(data), * N * sizeof(PodType)); @endcode */ template inline mutable_buffers_1 buffer(PodType (&data)[N]) { return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType))); } /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * static_cast(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template inline mutable_buffers_1 buffer(PodType (&data)[N], std::size_t max_size_in_bytes) { return mutable_buffers_1( mutable_buffer(data, N * sizeof(PodType) < max_size_in_bytes ? N * sizeof(PodType) : max_size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * static_cast(data), * N * sizeof(PodType)); @endcode */ template inline const_buffers_1 buffer(const PodType (&data)[N]) { return const_buffers_1(const_buffer(data, N * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * static_cast(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template inline const_buffers_1 buffer(const PodType (&data)[N], std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(data, N * sizeof(PodType) < max_size_in_bytes ? N * sizeof(PodType) : max_size_in_bytes)); } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) // Borland C++ and Sun Studio think the overloads: // // unspecified buffer(boost::array& array ...); // // and // // unspecified buffer(boost::array& array ...); // // are ambiguous. This will be worked around by using a buffer_types traits // class that contains typedefs for the appropriate buffer and container // classes, based on whether PodType is const or non-const. namespace detail { template struct buffer_types_base; template <> struct buffer_types_base { typedef mutable_buffer buffer_type; typedef mutable_buffers_1 container_type; }; template <> struct buffer_types_base { typedef const_buffer buffer_type; typedef const_buffers_1 container_type; }; template struct buffer_types : public buffer_types_base::value> { }; } // namespace detail template inline typename detail::buffer_types::container_type buffer(boost::array& data) { typedef typename asio::detail::buffer_types::buffer_type buffer_type; typedef typename asio::detail::buffer_types::container_type container_type; return container_type( buffer_type(data.c_array(), data.size() * sizeof(PodType))); } template inline typename detail::buffer_types::container_type buffer(boost::array& data, std::size_t max_size_in_bytes) { typedef typename asio::detail::buffer_types::buffer_type buffer_type; typedef typename asio::detail::buffer_types::container_type container_type; return container_type( buffer_type(data.c_array(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes)); } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template inline mutable_buffers_1 buffer(boost::array& data) { return mutable_buffers_1( mutable_buffer(data.c_array(), data.size() * sizeof(PodType))); } /// Create a new modifiable buffer that represents the given POD array. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template inline mutable_buffers_1 buffer(boost::array& data, std::size_t max_size_in_bytes) { return mutable_buffers_1( mutable_buffer(data.c_array(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template inline const_buffers_1 buffer(boost::array& data) { return const_buffers_1( const_buffer(data.data(), data.size() * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template inline const_buffers_1 buffer(boost::array& data, std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes)); } #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.data(), * data.size() * sizeof(PodType)); @endcode */ template inline const_buffers_1 buffer(const boost::array& data) { return const_buffers_1( const_buffer(data.data(), data.size() * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.data(), * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode */ template inline const_buffers_1 buffer(const boost::array& data, std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(data.data(), data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes)); } /// Create a new modifiable buffer that represents the given POD vector. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * data.size() ? &data[0] : 0, * data.size() * sizeof(PodType)); @endcode * * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ template inline mutable_buffers_1 buffer(std::vector& data) { return mutable_buffers_1( mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check< typename std::vector::iterator >(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new modifiable buffer that represents the given POD vector. /** * @returns A mutable_buffers_1 value equivalent to: * @code mutable_buffers_1( * data.size() ? &data[0] : 0, * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode * * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ template inline mutable_buffers_1 buffer(std::vector& data, std::size_t max_size_in_bytes) { return mutable_buffers_1( mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check< typename std::vector::iterator >(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new non-modifiable buffer that represents the given POD vector. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.size() ? &data[0] : 0, * data.size() * sizeof(PodType)); @endcode * * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ template inline const_buffers_1 buffer( const std::vector& data) { return const_buffers_1( const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check< typename std::vector::const_iterator >(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new non-modifiable buffer that represents the given POD vector. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.size() ? &data[0] : 0, * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode * * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ template inline const_buffers_1 buffer( const std::vector& data, std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) < max_size_in_bytes ? data.size() * sizeof(PodType) : max_size_in_bytes #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check< typename std::vector::const_iterator >(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new non-modifiable buffer that represents the given string. /** * @returns const_buffers_1(data.data(), data.size()). * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ inline const_buffers_1 buffer(const std::string& data) { return const_buffers_1(const_buffer(data.data(), data.size() #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /// Create a new non-modifiable buffer that represents the given string. /** * @returns A const_buffers_1 value equivalent to: * @code const_buffers_1( * data.data(), * min(data.size(), max_size_in_bytes)); @endcode * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ inline const_buffers_1 buffer(const std::string& data, std::size_t max_size_in_bytes) { return const_buffers_1( const_buffer(data.data(), data.size() < max_size_in_bytes ? data.size() : max_size_in_bytes #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) , detail::buffer_debug_check(data.begin()) #endif // ASIO_ENABLE_BUFFER_DEBUGGING )); } /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFER_HPP percona-galera-3-3.8-3390/asio/asio/buffered_read_stream.hpp000066400000000000000000000326701244131713600235410ustar00rootroot00000000000000// // buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_READ_STREAM_HPP #define ASIO_BUFFERED_READ_STREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffer.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_resize_guard.hpp" #include "asio/detail/buffered_stream_storage.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Adds buffering to the read-related operations of a stream. /** * The buffered_read_stream class template can be used to add buffering to the * synchronous and asynchronous read operations of a stream. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, Sync_Read_Stream, SyncWriteStream. */ template class buffered_read_stream : private noncopyable { public: /// The type of the next layer. typedef typename boost::remove_reference::type next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; #else BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); #endif /// Construct, passing the specified argument to initialise the next layer. template explicit buffered_read_stream(Arg& a) : next_layer_(a), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template buffered_read_stream(Arg& a, std::size_t buffer_size) : next_layer_(a), storage_(buffer_size) { } /// Get a reference to the next layer. next_layer_type& next_layer() { return next_layer_; } /// Get a reference to the lowest layer. lowest_layer_type& lowest_layer() { return next_layer_.lowest_layer(); } /// Get a const reference to the lowest layer. const lowest_layer_type& lowest_layer() const { return next_layer_.lowest_layer(); } /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() { return next_layer_.get_io_service(); } /// Get the io_service associated with the object. asio::io_service& get_io_service() { return next_layer_.get_io_service(); } /// Close the stream. void close() { next_layer_.close(); } /// Close the stream. asio::error_code close(asio::error_code& ec) { return next_layer_.close(ec); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. template std::size_t write_some(const ConstBufferSequence& buffers) { return next_layer_.write_some(buffers); } /// Write the given data to the stream. Returns the number of bytes written, /// or 0 if an error occurred. template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return next_layer_.write_some(buffers, ec); } /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { next_layer_.async_write_some(buffers, handler); } /// Fill the buffer with some data. Returns the number of bytes placed in the /// buffer as a result of the operation. Throws an exception on failure. std::size_t fill() { detail::buffer_resize_guard resize_guard(storage_); std::size_t previous_size = storage_.size(); storage_.resize(storage_.capacity()); storage_.resize(previous_size + next_layer_.read_some(buffer( storage_.data() + previous_size, storage_.size() - previous_size))); resize_guard.commit(); return storage_.size() - previous_size; } /// Fill the buffer with some data. Returns the number of bytes placed in the /// buffer as a result of the operation, or 0 if an error occurred. std::size_t fill(asio::error_code& ec) { detail::buffer_resize_guard resize_guard(storage_); std::size_t previous_size = storage_.size(); storage_.resize(storage_.capacity()); storage_.resize(previous_size + next_layer_.read_some(buffer( storage_.data() + previous_size, storage_.size() - previous_size), ec)); resize_guard.commit(); return storage_.size() - previous_size; } template class fill_handler { public: fill_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, std::size_t previous_size, ReadHandler handler) : io_service_(io_service), storage_(storage), previous_size_(previous_size), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { storage_.resize(previous_size_ + bytes_transferred); io_service_.dispatch(detail::bind_handler( handler_, ec, bytes_transferred)); } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; std::size_t previous_size_; ReadHandler handler_; }; /// Start an asynchronous fill. template void async_fill(ReadHandler handler) { std::size_t previous_size = storage_.size(); storage_.resize(storage_.capacity()); next_layer_.async_read_some( buffer( storage_.data() + previous_size, storage_.size() - previous_size), fill_handler(get_io_service(), storage_, previous_size, handler)); } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. template std::size_t read_some(const MutableBufferSequence& buffers) { typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::mutable_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) return 0; if (storage_.empty()) fill(); return copy(buffers); } /// Read some data from the stream. Returns the number of bytes read or 0 if /// an error occurred. template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { ec = asio::error_code(); typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::mutable_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) return 0; if (storage_.empty() && !fill(ec)) return 0; return copy(buffers); } template class read_some_handler { public: read_some_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, const MutableBufferSequence& buffers, ReadHandler handler) : io_service_(io_service), storage_(storage), buffers_(buffers), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t) { if (ec || storage_.empty()) { std::size_t length = 0; io_service_.dispatch(detail::bind_handler(handler_, ec, length)); } else { using namespace std; // For memcpy. std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; typename MutableBufferSequence::const_iterator iter = buffers_.begin(); typename MutableBufferSequence::const_iterator end = buffers_.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); std::size_t length = (max_length < bytes_avail) ? max_length : bytes_avail; memcpy(buffer_cast(*iter), storage_.data() + bytes_copied, length); bytes_copied += length; bytes_avail -= length; } storage_.consume(bytes_copied); io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); } } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; MutableBufferSequence buffers_; ReadHandler handler_; }; /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::mutable_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) { get_io_service().post(detail::bind_handler( handler, asio::error_code(), 0)); } else if (storage_.empty()) { async_fill(read_some_handler( get_io_service(), storage_, buffers, handler)); } else { std::size_t length = copy(buffers); get_io_service().post(detail::bind_handler( handler, asio::error_code(), length)); } } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. template std::size_t peek(const MutableBufferSequence& buffers) { if (storage_.empty()) fill(); return peek_copy(buffers); } /// Peek at the incoming data on the stream. Returns the number of bytes read, /// or 0 if an error occurred. template std::size_t peek(const MutableBufferSequence& buffers, asio::error_code& ec) { ec = asio::error_code(); if (storage_.empty() && !fill(ec)) return 0; return peek_copy(buffers); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail() { return storage_.size(); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail(asio::error_code& ec) { ec = asio::error_code(); return storage_.size(); } private: /// Copy data out of the internal buffer to the specified target buffer. /// Returns the number of bytes copied. template std::size_t copy(const MutableBufferSequence& buffers) { using namespace std; // For memcpy. std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); std::size_t length = (max_length < bytes_avail) ? max_length : bytes_avail; memcpy(buffer_cast(*iter), storage_.data() + bytes_copied, length); bytes_copied += length; bytes_avail -= length; } storage_.consume(bytes_copied); return bytes_copied; } /// Copy data from the internal buffer to the specified target buffer, without /// removing the data from the internal buffer. Returns the number of bytes /// copied. template std::size_t peek_copy(const MutableBufferSequence& buffers) { using namespace std; // For memcpy. std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; typename MutableBufferSequence::const_iterator iter = buffers.begin(); typename MutableBufferSequence::const_iterator end = buffers.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); std::size_t length = (max_length < bytes_avail) ? max_length : bytes_avail; memcpy(buffer_cast(*iter), storage_.data() + bytes_copied, length); bytes_copied += length; bytes_avail -= length; } return bytes_copied; } /// The next layer. Stream next_layer_; // The data in the buffer. detail::buffered_stream_storage storage_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFERED_READ_STREAM_HPP percona-galera-3-3.8-3390/asio/asio/buffered_read_stream_fwd.hpp000066400000000000000000000012021244131713600243640ustar00rootroot00000000000000// // buffered_read_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_READ_STREAM_FWD_HPP #define ASIO_BUFFERED_READ_STREAM_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { template class buffered_read_stream; } // namespace asio #endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP percona-galera-3-3.8-3390/asio/asio/buffered_stream.hpp000066400000000000000000000163161244131713600225450ustar00rootroot00000000000000// // buffered_stream.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_STREAM_HPP #define ASIO_BUFFERED_STREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/buffered_read_stream.hpp" #include "asio/buffered_write_stream.hpp" #include "asio/buffered_stream_fwd.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Adds buffering to the read- and write-related operations of a stream. /** * The buffered_stream class template can be used to add buffering to the * synchronous and asynchronous read and write operations of a stream. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class buffered_stream : private noncopyable { public: /// The type of the next layer. typedef typename boost::remove_reference::type next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; /// Construct, passing the specified argument to initialise the next layer. template explicit buffered_stream(Arg& a) : inner_stream_impl_(a), stream_impl_(inner_stream_impl_) { } /// Construct, passing the specified argument to initialise the next layer. template explicit buffered_stream(Arg& a, std::size_t read_buffer_size, std::size_t write_buffer_size) : inner_stream_impl_(a, write_buffer_size), stream_impl_(inner_stream_impl_, read_buffer_size) { } /// Get a reference to the next layer. next_layer_type& next_layer() { return stream_impl_.next_layer().next_layer(); } /// Get a reference to the lowest layer. lowest_layer_type& lowest_layer() { return stream_impl_.lowest_layer(); } /// Get a const reference to the lowest layer. const lowest_layer_type& lowest_layer() const { return stream_impl_.lowest_layer(); } /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() { return stream_impl_.get_io_service(); } /// Get the io_service associated with the object. asio::io_service& get_io_service() { return stream_impl_.get_io_service(); } /// Close the stream. void close() { stream_impl_.close(); } /// Close the stream. asio::error_code close(asio::error_code& ec) { return stream_impl_.close(ec); } /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation. Throws an /// exception on failure. std::size_t flush() { return stream_impl_.next_layer().flush(); } /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation, or 0 if an /// error occurred. std::size_t flush(asio::error_code& ec) { return stream_impl_.next_layer().flush(ec); } /// Start an asynchronous flush. template void async_flush(WriteHandler handler) { return stream_impl_.next_layer().async_flush(handler); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. template std::size_t write_some(const ConstBufferSequence& buffers) { return stream_impl_.write_some(buffers); } /// Write the given data to the stream. Returns the number of bytes written, /// or 0 if an error occurred. template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return stream_impl_.write_some(buffers, ec); } /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { stream_impl_.async_write_some(buffers, handler); } /// Fill the buffer with some data. Returns the number of bytes placed in the /// buffer as a result of the operation. Throws an exception on failure. std::size_t fill() { return stream_impl_.fill(); } /// Fill the buffer with some data. Returns the number of bytes placed in the /// buffer as a result of the operation, or 0 if an error occurred. std::size_t fill(asio::error_code& ec) { return stream_impl_.fill(ec); } /// Start an asynchronous fill. template void async_fill(ReadHandler handler) { stream_impl_.async_fill(handler); } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. template std::size_t read_some(const MutableBufferSequence& buffers) { return stream_impl_.read_some(buffers); } /// Read some data from the stream. Returns the number of bytes read or 0 if /// an error occurred. template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return stream_impl_.read_some(buffers, ec); } /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { stream_impl_.async_read_some(buffers, handler); } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. template std::size_t peek(const MutableBufferSequence& buffers) { return stream_impl_.peek(buffers); } /// Peek at the incoming data on the stream. Returns the number of bytes read, /// or 0 if an error occurred. template std::size_t peek(const MutableBufferSequence& buffers, asio::error_code& ec) { return stream_impl_.peek(buffers, ec); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail() { return stream_impl_.in_avail(); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail(asio::error_code& ec) { return stream_impl_.in_avail(ec); } private: // The buffered write stream. typedef buffered_write_stream write_stream_type; write_stream_type inner_stream_impl_; // The buffered read stream. typedef buffered_read_stream read_stream_type; read_stream_type stream_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFERED_STREAM_HPP percona-galera-3-3.8-3390/asio/asio/buffered_stream_fwd.hpp000066400000000000000000000011441244131713600233760ustar00rootroot00000000000000// // buffered_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_STREAM_FWD_HPP #define ASIO_BUFFERED_STREAM_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { template class buffered_stream; } // namespace asio #endif // ASIO_BUFFERED_STREAM_FWD_HPP percona-galera-3-3.8-3390/asio/asio/buffered_write_stream.hpp000066400000000000000000000277611244131713600237650ustar00rootroot00000000000000// // buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_WRITE_STREAM_HPP #define ASIO_BUFFERED_WRITE_STREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/buffered_write_stream_fwd.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffered_stream_storage.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/write.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Adds buffering to the write-related operations of a stream. /** * The buffered_write_stream class template can be used to add buffering to the * synchronous and asynchronous write operations of a stream. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class buffered_write_stream : private noncopyable { public: /// The type of the next layer. typedef typename boost::remove_reference::type next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; #else BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); #endif /// Construct, passing the specified argument to initialise the next layer. template explicit buffered_write_stream(Arg& a) : next_layer_(a), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template buffered_write_stream(Arg& a, std::size_t buffer_size) : next_layer_(a), storage_(buffer_size) { } /// Get a reference to the next layer. next_layer_type& next_layer() { return next_layer_; } /// Get a reference to the lowest layer. lowest_layer_type& lowest_layer() { return next_layer_.lowest_layer(); } /// Get a const reference to the lowest layer. const lowest_layer_type& lowest_layer() const { return next_layer_.lowest_layer(); } /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() { return next_layer_.get_io_service(); } /// Get the io_service associated with the object. asio::io_service& get_io_service() { return next_layer_.get_io_service(); } /// Close the stream. void close() { next_layer_.close(); } /// Close the stream. asio::error_code close(asio::error_code& ec) { return next_layer_.close(ec); } /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation. Throws an /// exception on failure. std::size_t flush() { std::size_t bytes_written = write(next_layer_, buffer(storage_.data(), storage_.size())); storage_.consume(bytes_written); return bytes_written; } /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation, or 0 if an /// error occurred. std::size_t flush(asio::error_code& ec) { std::size_t bytes_written = write(next_layer_, buffer(storage_.data(), storage_.size()), transfer_all(), ec); storage_.consume(bytes_written); return bytes_written; } template class flush_handler { public: flush_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, WriteHandler handler) : io_service_(io_service), storage_(storage), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_written) { storage_.consume(bytes_written); io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written)); } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; WriteHandler handler_; }; /// Start an asynchronous flush. template void async_flush(WriteHandler handler) { async_write(next_layer_, buffer(storage_.data(), storage_.size()), flush_handler(get_io_service(), storage_, handler)); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. template std::size_t write_some(const ConstBufferSequence& buffers) { typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::const_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) return 0; if (storage_.size() == storage_.capacity()) flush(); return copy(buffers); } /// Write the given data to the stream. Returns the number of bytes written, /// or 0 if an error occurred and the error handler did not throw. template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { ec = asio::error_code(); typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::const_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) return 0; if (storage_.size() == storage_.capacity() && !flush(ec)) return 0; return copy(buffers); } template class write_some_handler { public: write_some_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, const ConstBufferSequence& buffers, WriteHandler handler) : io_service_(io_service), storage_(storage), buffers_(buffers), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t) { if (ec) { std::size_t length = 0; io_service_.dispatch(detail::bind_handler(handler_, ec, length)); } else { using namespace std; // For memcpy. std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; std::size_t bytes_copied = 0; typename ConstBufferSequence::const_iterator iter = buffers_.begin(); typename ConstBufferSequence::const_iterator end = buffers_.end(); for (; iter != end && space_avail > 0; ++iter) { std::size_t bytes_avail = buffer_size(*iter); std::size_t length = (bytes_avail < space_avail) ? bytes_avail : space_avail; storage_.resize(orig_size + bytes_copied + length); memcpy(storage_.data() + orig_size + bytes_copied, buffer_cast(*iter), length); bytes_copied += length; space_avail -= length; } io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); } } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; ConstBufferSequence buffers_; WriteHandler handler_; }; /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); size_t total_buffer_size = 0; for (; iter != end; ++iter) { asio::const_buffer buffer(*iter); total_buffer_size += asio::buffer_size(buffer); } if (total_buffer_size == 0) { get_io_service().post(detail::bind_handler( handler, asio::error_code(), 0)); } else if (storage_.size() == storage_.capacity()) { async_flush(write_some_handler( get_io_service(), storage_, buffers, handler)); } else { std::size_t bytes_copied = copy(buffers); get_io_service().post(detail::bind_handler( handler, asio::error_code(), bytes_copied)); } } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. template std::size_t read_some(const MutableBufferSequence& buffers) { return next_layer_.read_some(buffers); } /// Read some data from the stream. Returns the number of bytes read or 0 if /// an error occurred. template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return next_layer_.read_some(buffers, ec); } /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { next_layer_.async_read_some(buffers, handler); } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. template std::size_t peek(const MutableBufferSequence& buffers) { return next_layer_.peek(buffers); } /// Peek at the incoming data on the stream. Returns the number of bytes read, /// or 0 if an error occurred. template std::size_t peek(const MutableBufferSequence& buffers, asio::error_code& ec) { return next_layer_.peek(buffers, ec); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail() { return next_layer_.in_avail(); } /// Determine the amount of data that may be read without blocking. std::size_t in_avail(asio::error_code& ec) { return next_layer_.in_avail(ec); } private: /// Copy data into the internal buffer from the specified source buffer. /// Returns the number of bytes copied. template std::size_t copy(const ConstBufferSequence& buffers) { using namespace std; // For memcpy. std::size_t orig_size = storage_.size(); std::size_t space_avail = storage_.capacity() - orig_size; std::size_t bytes_copied = 0; typename ConstBufferSequence::const_iterator iter = buffers.begin(); typename ConstBufferSequence::const_iterator end = buffers.end(); for (; iter != end && space_avail > 0; ++iter) { std::size_t bytes_avail = buffer_size(*iter); std::size_t length = (bytes_avail < space_avail) ? bytes_avail : space_avail; storage_.resize(orig_size + bytes_copied + length); memcpy(storage_.data() + orig_size + bytes_copied, buffer_cast(*iter), length); bytes_copied += length; space_avail -= length; } return bytes_copied; } /// The next layer. Stream next_layer_; // The data in the buffer. detail::buffered_stream_storage storage_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFERED_WRITE_STREAM_HPP percona-galera-3-3.8-3390/asio/asio/buffered_write_stream_fwd.hpp000066400000000000000000000012101244131713600246020ustar00rootroot00000000000000// // buffered_write_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERED_WRITE_STREAM_FWD_HPP #define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { template class buffered_write_stream; } // namespace asio #endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP percona-galera-3-3.8-3390/asio/asio/buffers_iterator.hpp000066400000000000000000000264321244131713600227550ustar00rootroot00000000000000// // buffers_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_BUFFERS_ITERATOR_HPP #define ASIO_BUFFERS_ITERATOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include #include #include "asio/buffer.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template struct buffers_iterator_types_helper; template <> struct buffers_iterator_types_helper { typedef const_buffer buffer_type; template struct byte_type { typedef typename boost::add_const::type type; }; }; template <> struct buffers_iterator_types_helper { typedef mutable_buffer buffer_type; template struct byte_type { typedef ByteType type; }; }; template struct buffers_iterator_types { enum { is_mutable = boost::is_convertible< typename BufferSequence::value_type, mutable_buffer>::value }; typedef buffers_iterator_types_helper helper; typedef typename helper::buffer_type buffer_type; typedef typename helper::template byte_type::type byte_type; }; } /// A random access iterator over the bytes in a buffer sequence. template class buffers_iterator : public boost::iterator< std::random_access_iterator_tag, typename detail::buffers_iterator_types< BufferSequence, ByteType>::byte_type> { private: typedef typename detail::buffers_iterator_types< BufferSequence, ByteType>::buffer_type buffer_type; typedef typename detail::buffers_iterator_types< BufferSequence, ByteType>::byte_type byte_type; public: /// Default constructor. Creates an iterator in an undefined state. buffers_iterator() : current_buffer_(), current_buffer_position_(0), begin_(), current_(), end_(), position_(0) { } /// Construct an iterator representing the beginning of the buffers' data. static buffers_iterator begin(const BufferSequence& buffers) #if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) __attribute__ ((noinline)) #endif { buffers_iterator new_iter; new_iter.begin_ = buffers.begin(); new_iter.current_ = buffers.begin(); new_iter.end_ = buffers.end(); while (new_iter.current_ != new_iter.end_) { new_iter.current_buffer_ = *new_iter.current_; if (asio::buffer_size(new_iter.current_buffer_) > 0) break; ++new_iter.current_; } return new_iter; } /// Construct an iterator representing the end of the buffers' data. static buffers_iterator end(const BufferSequence& buffers) #if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) __attribute__ ((noinline)) #endif { buffers_iterator new_iter; new_iter.begin_ = buffers.begin(); new_iter.current_ = buffers.begin(); new_iter.end_ = buffers.end(); while (new_iter.current_ != new_iter.end_) { buffer_type buffer = *new_iter.current_; new_iter.position_ += asio::buffer_size(buffer); ++new_iter.current_; } return new_iter; } /// Dereference an iterator. byte_type& operator*() const { return dereference(); } /// Dereference an iterator. byte_type* operator->() const { return &dereference(); } /// Access an individual element. byte_type& operator[](std::ptrdiff_t difference) const { buffers_iterator tmp(*this); tmp.advance(difference); return *tmp; } /// Increment operator (prefix). buffers_iterator& operator++() { increment(); return *this; } /// Increment operator (postfix). buffers_iterator operator++(int) { buffers_iterator tmp(*this); ++*this; return tmp; } /// Decrement operator (prefix). buffers_iterator& operator--() { decrement(); return *this; } /// Decrement operator (postfix). buffers_iterator operator--(int) { buffers_iterator tmp(*this); --*this; return tmp; } /// Addition operator. buffers_iterator& operator+=(std::ptrdiff_t difference) { advance(difference); return *this; } /// Subtraction operator. buffers_iterator& operator-=(std::ptrdiff_t difference) { advance(-difference); return *this; } /// Addition operator. friend buffers_iterator operator+(const buffers_iterator& iter, std::ptrdiff_t difference) { buffers_iterator tmp(iter); tmp.advance(difference); return tmp; } /// Addition operator. friend buffers_iterator operator+(std::ptrdiff_t difference, const buffers_iterator& iter) { buffers_iterator tmp(iter); tmp.advance(difference); return tmp; } /// Subtraction operator. friend buffers_iterator operator-(const buffers_iterator& iter, std::ptrdiff_t difference) { buffers_iterator tmp(iter); tmp.advance(-difference); return tmp; } /// Subtraction operator. friend std::ptrdiff_t operator-(const buffers_iterator& a, const buffers_iterator& b) { return b.distance_to(a); } /// Test two iterators for equality. friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) { return a.equal(b); } /// Test two iterators for inequality. friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) { return !a.equal(b); } /// Compare two iterators. friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) { return a.distance_to(b) > 0; } /// Compare two iterators. friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) { return !(b < a); } /// Compare two iterators. friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) { return b < a; } /// Compare two iterators. friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) { return !(a < b); } private: // Dereference the iterator. byte_type& dereference() const { return buffer_cast(current_buffer_)[current_buffer_position_]; } // Compare two iterators for equality. bool equal(const buffers_iterator& other) const { return position_ == other.position_; } // Increment the iterator. void increment() { BOOST_ASSERT(current_ != end_ && "iterator out of bounds"); ++position_; // Check if the increment can be satisfied by the current buffer. ++current_buffer_position_; if (current_buffer_position_ != asio::buffer_size(current_buffer_)) return; // Find the next non-empty buffer. ++current_; current_buffer_position_ = 0; while (current_ != end_) { current_buffer_ = *current_; if (asio::buffer_size(current_buffer_) > 0) return; ++current_; } } // Decrement the iterator. void decrement() { BOOST_ASSERT(position_ > 0 && "iterator out of bounds"); --position_; // Check if the decrement can be satisfied by the current buffer. if (current_buffer_position_ != 0) { --current_buffer_position_; return; } // Find the previous non-empty buffer. typename BufferSequence::const_iterator iter = current_; while (iter != begin_) { --iter; buffer_type buffer = *iter; std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > 0) { current_ = iter; current_buffer_ = buffer; current_buffer_position_ = buffer_size - 1; return; } } } // Advance the iterator by the specified distance. void advance(std::ptrdiff_t n) { if (n > 0) { BOOST_ASSERT(current_ != end_ && "iterator out of bounds"); for (;;) { std::ptrdiff_t current_buffer_balance = asio::buffer_size(current_buffer_) - current_buffer_position_; // Check if the advance can be satisfied by the current buffer. if (current_buffer_balance > n) { position_ += n; current_buffer_position_ += n; return; } // Update position. n -= current_buffer_balance; position_ += current_buffer_balance; // Move to next buffer. If it is empty then it will be skipped on the // next iteration of this loop. if (++current_ == end_) { BOOST_ASSERT(n == 0 && "iterator out of bounds"); current_buffer_ = buffer_type(); current_buffer_position_ = 0; return; } current_buffer_ = *current_; current_buffer_position_ = 0; } } else if (n < 0) { std::size_t abs_n = -n; BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds"); for (;;) { // Check if the advance can be satisfied by the current buffer. if (current_buffer_position_ >= abs_n) { position_ -= abs_n; current_buffer_position_ -= abs_n; return; } // Update position. abs_n -= current_buffer_position_; position_ -= current_buffer_position_; // Check if we've reached the beginning of the buffers. if (current_ == begin_) { BOOST_ASSERT(abs_n == 0 && "iterator out of bounds"); current_buffer_position_ = 0; return; } // Find the previous non-empty buffer. typename BufferSequence::const_iterator iter = current_; while (iter != begin_) { --iter; buffer_type buffer = *iter; std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > 0) { current_ = iter; current_buffer_ = buffer; current_buffer_position_ = buffer_size; break; } } } } } // Determine the distance between two iterators. std::ptrdiff_t distance_to(const buffers_iterator& other) const { return other.position_ - position_; } buffer_type current_buffer_; std::size_t current_buffer_position_; typename BufferSequence::const_iterator begin_; typename BufferSequence::const_iterator current_; typename BufferSequence::const_iterator end_; std::size_t position_; }; /// Construct an iterator representing the beginning of the buffers' data. template inline buffers_iterator buffers_begin( const BufferSequence& buffers) { return buffers_iterator::begin(buffers); } /// Construct an iterator representing the end of the buffers' data. template inline buffers_iterator buffers_end( const BufferSequence& buffers) { return buffers_iterator::end(buffers); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_BUFFERS_ITERATOR_HPP percona-galera-3-3.8-3390/asio/asio/completion_condition.hpp000066400000000000000000000075421244131713600236300ustar00rootroot00000000000000// // completion_condition.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_COMPLETION_CONDITION_HPP #define ASIO_COMPLETION_CONDITION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // The default maximum number of bytes to transfer in a single operation. enum { default_max_transfer_size = 65536 }; // Adapt result of old-style completion conditions (which had a bool result // where true indicated that the operation was complete). inline std::size_t adapt_completion_condition_result(bool result) { return result ? 0 : default_max_transfer_size; } // Adapt result of current completion conditions (which have a size_t result // where 0 means the operation is complete, and otherwise the result is the // maximum number of bytes to transfer on the next underlying operation). inline std::size_t adapt_completion_condition_result(std::size_t result) { return result; } class transfer_all_t { public: typedef std::size_t result_type; template std::size_t operator()(const Error& err, std::size_t) { return !!err ? 0 : default_max_transfer_size; } }; class transfer_at_least_t { public: typedef std::size_t result_type; explicit transfer_at_least_t(std::size_t minimum) : minimum_(minimum) { } template std::size_t operator()(const Error& err, std::size_t bytes_transferred) { return (!!err || bytes_transferred >= minimum_) ? 0 : default_max_transfer_size; } private: std::size_t minimum_; }; } // namespace detail /** * @defgroup completion_condition Completion Condition Function Objects * * Function objects used for determining when a read or write operation should * complete. */ /*@{*/ /// Return a completion condition function object that indicates that a read or /// write operation should continue until all of the data has been transferred, /// or until an error occurs. /** * This function is used to create an object, of unspecified type, that meets * CompletionCondition requirements. * * @par Example * Reading until a buffer is full: * @code * boost::array buf; * asio::error_code ec; * std::size_t n = asio::read( * sock, asio::buffer(buf), * asio::transfer_all(), ec); * if (ec) * { * // An error occurred. * } * else * { * // n == 128 * } * @endcode */ #if defined(GENERATING_DOCUMENTATION) unspecified transfer_all(); #else inline detail::transfer_all_t transfer_all() { return detail::transfer_all_t(); } #endif /// Return a completion condition function object that indicates that a read or /// write operation should continue until a minimum number of bytes has been /// transferred, or until an error occurs. /** * This function is used to create an object, of unspecified type, that meets * CompletionCondition requirements. * * @par Example * Reading until a buffer is full or contains at least 64 bytes: * @code * boost::array buf; * asio::error_code ec; * std::size_t n = asio::read( * sock, asio::buffer(buf), * asio::transfer_at_least(64), ec); * if (ec) * { * // An error occurred. * } * else * { * // n >= 64 && n <= 128 * } * @endcode */ #if defined(GENERATING_DOCUMENTATION) unspecified transfer_at_least(std::size_t minimum); #else inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum) { return detail::transfer_at_least_t(minimum); } #endif /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_COMPLETION_CONDITION_HPP percona-galera-3-3.8-3390/asio/asio/datagram_socket_service.hpp000066400000000000000000000224641244131713600242610ustar00rootroot00000000000000// // datagram_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DATAGRAM_SOCKET_SERVICE_HPP #define ASIO_DATAGRAM_SOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" #else # include "asio/detail/reactive_socket_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a datagram socket. template class datagram_socket_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; #else typedef detail::reactive_socket_service service_impl_type; #endif public: /// The type of a datagram socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef typename service_impl_type::native_type native_type; #endif /// Construct a new datagram socket service for the specified io_service. explicit datagram_socket_service(asio::io_service& io_service) : asio::detail::service_base< datagram_socket_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new datagram socket implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a datagram socket implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } // Open a new datagram socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (protocol.type() == SOCK_DGRAM) service_impl_.open(impl, protocol, ec); else ec = asio::error::invalid_argument; return ec; } /// Assign an existing native socket to a datagram socket. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { return service_impl_.assign(impl, protocol, native_socket, ec); } /// Determine whether the socket is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a datagram socket implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native socket implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the socket. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Determine whether the socket is at the out-of-band data mark. bool at_mark(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.at_mark(impl, ec); } /// Determine the number of bytes available for reading. std::size_t available(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.available(impl, ec); } // Bind the datagram socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { return service_impl_.bind(impl, endpoint, ec); } /// Connect the datagram socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { return service_impl_.connect(impl, peer_endpoint, ec); } /// Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, ConnectHandler handler) { service_impl_.async_connect(impl, peer_endpoint, handler); } /// Set a socket option. template asio::error_code set_option(implementation_type& impl, const SettableSocketOption& option, asio::error_code& ec) { return service_impl_.set_option(impl, option, ec); } /// Get a socket option. template asio::error_code get_option(const implementation_type& impl, GettableSocketOption& option, asio::error_code& ec) const { return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. template asio::error_code io_control(implementation_type& impl, IoControlCommand& command, asio::error_code& ec) { return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.local_endpoint(impl, ec); } /// Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.remote_endpoint(impl, ec); } /// Disable sends or receives on the socket. asio::error_code shutdown(implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { return service_impl_.shutdown(impl, what, ec); } /// Send the given data to the peer. template std::size_t send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.send(impl, buffers, flags, ec); } /// Start an asynchronous send. template void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send(impl, buffers, flags, handler); } /// Send a datagram to the specified endpoint. template std::size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.send_to(impl, buffers, destination, flags, ec); } /// Start an asynchronous send. template void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send_to(impl, buffers, destination, flags, handler); } /// Receive some data from the peer. template std::size_t receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive(impl, buffers, flags, ec); } /// Start an asynchronous receive. template void async_receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive(impl, buffers, flags, handler); } /// Receive a datagram with the endpoint of the sender. template std::size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive that will get the endpoint of the sender. template void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/deadline_timer.hpp000066400000000000000000000016751244131713600223570ustar00rootroot00000000000000// // deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DEADLINE_TIMER_HPP #define ASIO_DEADLINE_TIMER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/socket_types.hpp" // Must come before posix_time. #include "asio/basic_deadline_timer.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" namespace asio { /// Typedef for the typical usage of timer. Uses a UTC clock. typedef basic_deadline_timer deadline_timer; } // namespace asio #endif // ASIO_DEADLINE_TIMER_HPP percona-galera-3-3.8-3390/asio/asio/deadline_timer_service.hpp000066400000000000000000000077321244131713600240770ustar00rootroot00000000000000// // deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DEADLINE_TIMER_SERVICE_HPP #define ASIO_DEADLINE_TIMER_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/deadline_timer_service.hpp" #include "asio/io_service.hpp" #include "asio/time_traits.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a timer. template > class deadline_timer_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base< deadline_timer_service > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The time traits type. typedef TimeTraits traits_type; /// The time type. typedef typename traits_type::time_type time_type; /// The duration type. typedef typename traits_type::duration_type duration_type; private: // The type of the platform-specific implementation. typedef detail::deadline_timer_service service_impl_type; public: /// The implementation type of the deadline timer. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// Construct a new timer service for the specified io_service. explicit deadline_timer_service(asio::io_service& io_service) : asio::detail::service_base< deadline_timer_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new timer implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a timer implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Get the expiry time for the timer as an absolute time. time_type expires_at(const implementation_type& impl) const { return service_impl_.expires_at(impl); } /// Set the expiry time for the timer as an absolute time. std::size_t expires_at(implementation_type& impl, const time_type& expiry_time, asio::error_code& ec) { return service_impl_.expires_at(impl, expiry_time, ec); } /// Get the expiry time for the timer relative to now. duration_type expires_from_now(const implementation_type& impl) const { return service_impl_.expires_from_now(impl); } /// Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, const duration_type& expiry_time, asio::error_code& ec) { return service_impl_.expires_from_now(impl, expiry_time, ec); } // Perform a blocking wait on the timer. void wait(implementation_type& impl, asio::error_code& ec) { service_impl_.wait(impl, ec); } // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, WaitHandler handler) { service_impl_.async_wait(impl, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DEADLINE_TIMER_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/000077500000000000000000000000001244131713600201325ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/detail/array_fwd.hpp000066400000000000000000000011231244131713600226160ustar00rootroot00000000000000// // detail/array_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_ARRAY_FWD_HPP #define ASIO_DETAIL_ARRAY_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace boost { template class array; } // namespace boost #endif // ASIO_DETAIL_ARRAY_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/base_from_completion_cond.hpp000066400000000000000000000031531244131713600260360ustar00rootroot00000000000000// // detail/base_from_completion_cond.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP #define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class base_from_completion_cond { protected: explicit base_from_completion_cond(CompletionCondition completion_condition) : completion_condition_(completion_condition) { } std::size_t check_for_completion( const asio::error_code& ec, std::size_t total_transferred) { return detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred)); } private: CompletionCondition completion_condition_; }; template <> class base_from_completion_cond { protected: explicit base_from_completion_cond(transfer_all_t) { } static std::size_t check_for_completion( const asio::error_code& ec, std::size_t total_transferred) { return transfer_all_t()(ec, total_transferred); } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP percona-galera-3-3.8-3390/asio/asio/detail/bind_handler.hpp000066400000000000000000000223771244131713600232670ustar00rootroot00000000000000// // detail/bind_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_BIND_HANDLER_HPP #define ASIO_DETAIL_BIND_HANDLER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class binder1 { public: binder1(const Handler& handler, const Arg1& arg1) : handler_(handler), arg1_(arg1) { } void operator()() { handler_(static_cast(arg1_)); } void operator()() const { handler_(arg1_); } //private: Handler handler_; Arg1 arg1_; }; template inline void* asio_handler_allocate(std::size_t size, binder1* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, binder1* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, binder1* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template inline binder1 bind_handler(const Handler& handler, const Arg1& arg1) { return binder1(handler, arg1); } template class binder2 { public: binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2) : handler_(handler), arg1_(arg1), arg2_(arg2) { } void operator()() { handler_(static_cast(arg1_), static_cast(arg2_)); } void operator()() const { handler_(arg1_, arg2_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; }; template inline void* asio_handler_allocate(std::size_t size, binder2* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, binder2* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, binder2* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template inline binder2 bind_handler(const Handler& handler, const Arg1& arg1, const Arg2& arg2) { return binder2(handler, arg1, arg2); } template class binder3 { public: binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) : handler_(handler), arg1_(arg1), arg2_(arg2), arg3_(arg3) { } void operator()() { handler_(static_cast(arg1_), static_cast(arg2_), static_cast(arg3_)); } void operator()() const { handler_(arg1_, arg2_, arg3_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; }; template inline void* asio_handler_allocate(std::size_t size, binder3* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, binder3* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, binder3* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template inline binder3 bind_handler(const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { return binder3(handler, arg1, arg2, arg3); } template class binder4 { public: binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) : handler_(handler), arg1_(arg1), arg2_(arg2), arg3_(arg3), arg4_(arg4) { } void operator()() { handler_(static_cast(arg1_), static_cast(arg2_), static_cast(arg3_), static_cast(arg4_)); } void operator()() const { handler_(arg1_, arg2_, arg3_, arg4_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; Arg4 arg4_; }; template inline void* asio_handler_allocate(std::size_t size, binder4* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, binder4* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, binder4* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template inline binder4 bind_handler( const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { return binder4(handler, arg1, arg2, arg3, arg4); } template class binder5 { public: binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) : handler_(handler), arg1_(arg1), arg2_(arg2), arg3_(arg3), arg4_(arg4), arg5_(arg5) { } void operator()() { handler_(static_cast(arg1_), static_cast(arg2_), static_cast(arg3_), static_cast(arg4_), static_cast(arg5_)); } void operator()() const { handler_(arg1_, arg2_, arg3_, arg4_, arg5_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; Arg4 arg4_; Arg5 arg5_; }; template inline void* asio_handler_allocate(std::size_t size, binder5* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, binder5* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, binder5* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template inline binder5 bind_handler( const Handler& handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) { return binder5(handler, arg1, arg2, arg3, arg4, arg5); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_BIND_HANDLER_HPP percona-galera-3-3.8-3390/asio/asio/detail/buffer_resize_guard.hpp000066400000000000000000000030561244131713600246630ustar00rootroot00000000000000// // detail/buffer_resize_guard.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP #define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper class to manage buffer resizing in an exception safe way. template class buffer_resize_guard { public: // Constructor. buffer_resize_guard(Buffer& buffer) : buffer_(buffer), old_size_(buffer.size()) { } // Destructor rolls back the buffer resize unless commit was called. ~buffer_resize_guard() { if (old_size_ != std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION()) { buffer_.resize(old_size_); } } // Commit the resize transaction. void commit() { old_size_ = std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION(); } private: // The buffer being managed. Buffer& buffer_; // The size of the buffer at the time the guard was constructed. size_t old_size_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP percona-galera-3-3.8-3390/asio/asio/detail/buffer_sequence_adapter.hpp000066400000000000000000000136641244131713600255160ustar00rootroot00000000000000// // detail/buffer_sequence_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP #define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/buffer.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class buffer_sequence_adapter_base { protected: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF native_buffer_type; static void init_native_buffer(WSABUF& buf, const asio::mutable_buffer& buffer) { buf.buf = asio::buffer_cast(buffer); buf.len = static_cast(asio::buffer_size(buffer)); } static void init_native_buffer(WSABUF& buf, const asio::const_buffer& buffer) { buf.buf = const_cast(asio::buffer_cast(buffer)); buf.len = static_cast(asio::buffer_size(buffer)); } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec native_buffer_type; static void init_iov_base(void*& base, void* addr) { base = addr; } template static void init_iov_base(T& base, void* addr) { base = static_cast(addr); } static void init_native_buffer(iovec& iov, const asio::mutable_buffer& buffer) { init_iov_base(iov.iov_base, asio::buffer_cast(buffer)); iov.iov_len = asio::buffer_size(buffer); } static void init_native_buffer(iovec& iov, const asio::const_buffer& buffer) { init_iov_base(iov.iov_base, const_cast( asio::buffer_cast(buffer))); iov.iov_len = asio::buffer_size(buffer); } #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) }; // Helper class to translate buffers into the native buffer representation. template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: explicit buffer_sequence_adapter(const Buffers& buffers) : count_(0), total_buffer_size_(0) { typename Buffers::const_iterator iter = buffers.begin(); typename Buffers::const_iterator end = buffers.end(); for (; iter != end && count_ < max_buffers; ++iter, ++count_) { Buffer buffer(*iter); init_native_buffer(buffers_[count_], buffer); total_buffer_size_ += asio::buffer_size(buffer); } } native_buffer_type* buffers() { return buffers_; } std::size_t count() const { return count_; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const Buffers& buffers) { typename Buffers::const_iterator iter = buffers.begin(); typename Buffers::const_iterator end = buffers.end(); std::size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) if (asio::buffer_size(Buffer(*iter)) > 0) return false; return true; } static void validate(const Buffers& buffers) { typename Buffers::const_iterator iter = buffers.begin(); typename Buffers::const_iterator end = buffers.end(); for (; iter != end; ++iter) { Buffer buffer(*iter); asio::buffer_cast(buffer); } } static Buffer first(const Buffers& buffers) { typename Buffers::const_iterator iter = buffers.begin(); typename Buffers::const_iterator end = buffers.end(); for (; iter != end; ++iter) { Buffer buffer(*iter); if (asio::buffer_size(buffer) != 0) return buffer; } return Buffer(); } private: // The maximum number of buffers to support in a single operation. enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; }; template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: explicit buffer_sequence_adapter( const asio::mutable_buffers_1& buffers) { init_native_buffer(buffer_, Buffer(buffers)); total_buffer_size_ = asio::buffer_size(buffers); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::mutable_buffers_1& buffers) { return asio::buffer_size(buffers) == 0; } static void validate(const asio::mutable_buffers_1& buffers) { asio::buffer_cast(buffers); } static Buffer first(const asio::mutable_buffers_1& buffers) { return Buffer(buffers); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; template class buffer_sequence_adapter : buffer_sequence_adapter_base { public: explicit buffer_sequence_adapter( const asio::const_buffers_1& buffers) { init_native_buffer(buffer_, Buffer(buffers)); total_buffer_size_ = asio::buffer_size(buffers); } native_buffer_type* buffers() { return &buffer_; } std::size_t count() const { return 1; } bool all_empty() const { return total_buffer_size_ == 0; } static bool all_empty(const asio::const_buffers_1& buffers) { return asio::buffer_size(buffers) == 0; } static void validate(const asio::const_buffers_1& buffers) { asio::buffer_cast(buffers); } static Buffer first(const asio::const_buffers_1& buffers) { return Buffer(buffers); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/buffered_stream_storage.hpp000066400000000000000000000053441244131713600255320ustar00rootroot00000000000000// // detail/buffered_stream_storage.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP #define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class buffered_stream_storage { public: // The type of the bytes stored in the buffer. typedef unsigned char byte_type; // The type used for offsets into the buffer. typedef std::size_t size_type; // Constructor. explicit buffered_stream_storage(std::size_t capacity) : begin_offset_(0), end_offset_(0), buffer_(capacity) { } /// Clear the buffer. void clear() { begin_offset_ = 0; end_offset_ = 0; } // Return a pointer to the beginning of the unread data. byte_type* data() { return &buffer_[0] + begin_offset_; } // Return a pointer to the beginning of the unread data. const byte_type* data() const { return &buffer_[0] + begin_offset_; } // Is there no unread data in the buffer. bool empty() const { return begin_offset_ == end_offset_; } // Return the amount of unread data the is in the buffer. size_type size() const { return end_offset_ - begin_offset_; } // Resize the buffer to the specified length. void resize(size_type length) { assert(length <= capacity()); if (begin_offset_ + length <= capacity()) { end_offset_ = begin_offset_ + length; } else { using namespace std; // For memmove. memmove(&buffer_[0], &buffer_[0] + begin_offset_, size()); end_offset_ = length; begin_offset_ = 0; } } // Return the maximum size for data in the buffer. size_type capacity() const { return buffer_.size(); } // Consume multiple bytes from the beginning of the buffer. void consume(size_type count) { assert(begin_offset_ + count <= end_offset_); begin_offset_ += count; if (empty()) clear(); } private: // The offset to the beginning of the unread data. size_type begin_offset_; // The offset to the end of the unread data. size_type end_offset_; // The data in the buffer. std::vector buffer_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP percona-galera-3-3.8-3390/asio/asio/detail/call_stack.hpp000066400000000000000000000037711244131713600227530ustar00rootroot00000000000000// // detail/call_stack.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_CALL_STACK_HPP #define ASIO_DETAIL_CALL_STACK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/tss_ptr.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper class to determine whether or not the current thread is inside an // invocation of io_service::run() for a specified io_service object. template class call_stack { public: // Context class automatically pushes an owner on to the stack. class context : private noncopyable { public: // Push the owner on to the stack. explicit context(Owner* d) : owner_(d), next_(call_stack::top_) { call_stack::top_ = this; } // Pop the owner from the stack. ~context() { call_stack::top_ = next_; } private: friend class call_stack; // The owner associated with the context. Owner* owner_; // The next element in the stack. context* next_; }; friend class context; // Determine whether the specified owner is on the stack. static bool contains(Owner* d) { context* elem = top_; while (elem) { if (elem->owner_ == d) return true; elem = elem->next_; } return false; } private: // The top of the stack of calls for the current thread. static tss_ptr top_; }; template tss_ptr::context> call_stack::top_; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_CALL_STACK_HPP percona-galera-3-3.8-3390/asio/asio/detail/completion_handler.hpp000066400000000000000000000042001244131713600245050ustar00rootroot00000000000000// // detail/completion_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_COMPLETION_HANDLER_HPP #define ASIO_DETAIL_COMPLETION_HANDLER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class completion_handler : public operation { public: ASIO_DEFINE_HANDLER_PTR(completion_handler); completion_handler(Handler h) : operation(&completion_handler::do_complete), handler_(h) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. completion_handler* h(static_cast(base)); ptr p = { boost::addressof(h->handler_), h, h }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. Handler handler(h->handler_); p.h = boost::addressof(handler); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP percona-galera-3-3.8-3390/asio/asio/detail/config.hpp000066400000000000000000000170561244131713600221210ustar00rootroot00000000000000// // detail/config.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_CONFIG_HPP #define ASIO_DETAIL_CONFIG_HPP #include // Default to a header-only implementation. The user must specifically request // separate compilation by defining either ASIO_SEPARATE_COMPILATION or // ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). #if !defined(ASIO_HEADER_ONLY) # if !defined(ASIO_SEPARATE_COMPILATION) # if !defined(ASIO_DYN_LINK) # define ASIO_HEADER_ONLY # endif // !defined(ASIO_DYN_LINK) # endif // !defined(ASIO_SEPARATE_COMPILATION) #endif // !defined(ASIO_HEADER_ONLY) #if defined(ASIO_HEADER_ONLY) # define ASIO_DECL inline #else // defined(ASIO_HEADER_ONLY) # if defined(BOOST_HAS_DECLSPEC) // We need to import/export our code only if the user has specifically asked // for it by defining ASIO_DYN_LINK. # if defined(ASIO_DYN_LINK) // Export if this is our own source, otherwise import. # if defined(ASIO_SOURCE) # define ASIO_DECL __declspec(dllexport) # else // defined(ASIO_SOURCE) # define ASIO_DECL __declspec(dllimport) # endif // defined(ASIO_SOURCE) # endif // defined(ASIO_DYN_LINK) # endif // defined(BOOST_HAS_DECLSPEC) #endif // defined(ASIO_HEADER_ONLY) // If ASIO_DECL isn't defined yet define it now. #if !defined(ASIO_DECL) # define ASIO_DECL #endif // !defined(ASIO_DECL) // Windows: target OS version. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) || defined(__BORLANDC__) # pragma message( \ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") # else // defined(_MSC_VER) || defined(__BORLANDC__) # warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. # warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. # warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). # endif // defined(_MSC_VER) || defined(__BORLANDC__) # define _WIN32_WINNT 0x0501 # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) # if defined(_WIN32) && !defined(WIN32) # if !defined(_WINSOCK2API_) # define WIN32 // Needed for correct types in winsock2.h # else // !defined(_WINSOCK2API_) # error Please define the macro WIN32 in your compiler options # endif // !defined(_WINSOCK2API_) # endif // defined(_WIN32) && !defined(WIN32) # endif // defined(_MSC_VER) # if defined(__BORLANDC__) # if defined(__WIN32__) && !defined(WIN32) # if !defined(_WINSOCK2API_) # define WIN32 // Needed for correct types in winsock2.h # else // !defined(_WINSOCK2API_) # error Please define the macro WIN32 in your compiler options # endif // !defined(_WINSOCK2API_) # endif // defined(__WIN32__) && !defined(WIN32) # endif // defined(__BORLANDC__) # if defined(__CYGWIN__) # if !defined(__USE_W32_SOCKETS) # error You must add -D__USE_W32_SOCKETS to your compiler options. # endif // !defined(__USE_W32_SOCKETS) # endif // defined(__CYGWIN__) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Windows: minimise header inclusion. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) # if !defined(WIN32_LEAN_AND_MEAN) # define WIN32_LEAN_AND_MEAN # endif // !defined(WIN32_LEAN_AND_MEAN) # endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Windows: suppress definition of "min" and "max" macros. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if !defined(ASIO_NO_NOMINMAX) # if !defined(NOMINMAX) # define NOMINMAX 1 # endif // !defined(NOMINMAX) # endif // !defined(ASIO_NO_NOMINMAX) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Windows: IO Completion Ports. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) # if !defined(UNDER_CE) # if !defined(ASIO_DISABLE_IOCP) # define ASIO_HAS_IOCP 1 # endif // !defined(ASIO_DISABLE_IOCP) # endif // !defined(UNDER_CE) # endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Linux: epoll, eventfd and timerfd. #if defined(__linux__) # include # if !defined(ASIO_DISABLE_EPOLL) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) # define ASIO_HAS_EPOLL 1 # endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) # endif // !defined(ASIO_DISABLE_EVENTFD) # if !defined(ASIO_DISABLE_EVENTFD) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) # define ASIO_HAS_EVENTFD 1 # endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) # endif // !defined(ASIO_DISABLE_EVENTFD) # if defined(ASIO_HAS_EPOLL) # if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) # define ASIO_HAS_TIMERFD 1 # endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) # endif // defined(ASIO_HAS_EPOLL) #endif // defined(__linux__) // Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. #if (defined(__MACH__) && defined(__APPLE__)) \ || defined(__FreeBSD__) \ || defined(__NetBSD__) \ || defined(__OpenBSD__) # if !defined(ASIO_DISABLE_KQUEUE) # define ASIO_HAS_KQUEUE 1 # endif // !defined(ASIO_DISABLE_KQUEUE) #endif // (defined(__MACH__) && defined(__APPLE__)) // || defined(__FreeBSD__) // || defined(__NetBSD__) // || defined(__OpenBSD__) // Solaris: /dev/poll. #if defined(__sun) # if !defined(ASIO_DISABLE_DEV_POLL) # define ASIO_HAS_DEV_POLL 1 # endif // !defined(ASIO_DISABLE_DEV_POLL) #endif // defined(__sun) // Serial ports. #if defined(ASIO_HAS_IOCP) \ || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) # if !defined(__SYMBIAN32__) # if !defined(ASIO_DISABLE_SERIAL_PORT) # define ASIO_HAS_SERIAL_PORT 1 # endif // !defined(ASIO_DISABLE_SERIAL_PORT) # endif // !defined(__SYMBIAN32__) #endif // defined(ASIO_HAS_IOCP) // || !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) // Windows: stream handles. #if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) # if defined(ASIO_HAS_IOCP) # define ASIO_HAS_WINDOWS_STREAM_HANDLE 1 # endif // defined(ASIO_HAS_IOCP) #endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE) // Windows: random access handles. #if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) # if defined(ASIO_HAS_IOCP) # define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 # endif // defined(ASIO_HAS_IOCP) #endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) // Windows: OVERLAPPED wrapper. #if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) # if defined(ASIO_HAS_IOCP) # define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 # endif // defined(ASIO_HAS_IOCP) #endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) // POSIX: stream-oriented file descriptors. #if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) # if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) # define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 # endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) // UNIX domain sockets. #if !defined(ASIO_DISABLE_LOCAL_SOCKETS) # if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) # define ASIO_HAS_LOCAL_SOCKETS 1 # endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS) #endif // ASIO_DETAIL_CONFIG_HPP percona-galera-3-3.8-3390/asio/asio/detail/consuming_buffers.hpp000066400000000000000000000154271244131713600243720ustar00rootroot00000000000000// // detail/consuming_buffers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_CONSUMING_BUFFERS_HPP #define ASIO_DETAIL_CONSUMING_BUFFERS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/buffer.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // A proxy iterator for a sub-range in a list of buffers. template class consuming_buffers_iterator : public boost::iterator { public: // Default constructor creates an end iterator. consuming_buffers_iterator() : at_end_(true) { } // Construct with a buffer for the first entry and an iterator // range for the remaining entries. consuming_buffers_iterator(bool at_end, const Buffer& first, Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, std::size_t max_size) : at_end_(max_size > 0 ? at_end : true), first_(buffer(first, max_size)), begin_remainder_(begin_remainder), end_remainder_(end_remainder), offset_(0), max_size_(max_size) { } // Dereference an iterator. const Buffer& operator*() const { return dereference(); } // Dereference an iterator. const Buffer* operator->() const { return &dereference(); } // Increment operator (prefix). consuming_buffers_iterator& operator++() { increment(); return *this; } // Increment operator (postfix). consuming_buffers_iterator operator++(int) { consuming_buffers_iterator tmp(*this); ++*this; return tmp; } // Test two iterators for equality. friend bool operator==(const consuming_buffers_iterator& a, const consuming_buffers_iterator& b) { return a.equal(b); } // Test two iterators for inequality. friend bool operator!=(const consuming_buffers_iterator& a, const consuming_buffers_iterator& b) { return !a.equal(b); } private: void increment() { if (!at_end_) { if (begin_remainder_ == end_remainder_ || offset_ + buffer_size(first_) >= max_size_) { at_end_ = true; } else { offset_ += buffer_size(first_); first_ = buffer(*begin_remainder_++, max_size_ - offset_); } } } bool equal(const consuming_buffers_iterator& other) const { if (at_end_ && other.at_end_) return true; return !at_end_ && !other.at_end_ && buffer_cast(first_) == buffer_cast(other.first_) && buffer_size(first_) == buffer_size(other.first_) && begin_remainder_ == other.begin_remainder_ && end_remainder_ == other.end_remainder_; } const Buffer& dereference() const { return first_; } bool at_end_; Buffer first_; Buffer_Iterator begin_remainder_; Buffer_Iterator end_remainder_; std::size_t offset_; std::size_t max_size_; }; // A proxy for a sub-range in a list of buffers. template class consuming_buffers { public: // The type for each element in the list of buffers. typedef Buffer value_type; // A forward-only iterator type that may be used to read elements. typedef consuming_buffers_iterator const_iterator; // Construct to represent the entire list of buffers. consuming_buffers(const Buffers& buffers) : buffers_(buffers), at_end_(buffers_.begin() == buffers_.end()), begin_remainder_(buffers_.begin()), max_size_((std::numeric_limits::max)()) { if (!at_end_) { first_ = *buffers_.begin(); ++begin_remainder_; } } // Copy constructor. consuming_buffers(const consuming_buffers& other) : buffers_(other.buffers_), at_end_(other.at_end_), first_(other.first_), begin_remainder_(buffers_.begin()), max_size_(other.max_size_) { typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator second = other.begin_remainder_; std::advance(begin_remainder_, std::distance(first, second)); } // Assignment operator. consuming_buffers& operator=(const consuming_buffers& other) { buffers_ = other.buffers_; at_end_ = other.at_end_; first_ = other.first_; begin_remainder_ = buffers_.begin(); typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator second = other.begin_remainder_; std::advance(begin_remainder_, std::distance(first, second)); max_size_ = other.max_size_; return *this; } // Get a forward-only iterator to the first element. const_iterator begin() const { return const_iterator(at_end_, first_, begin_remainder_, buffers_.end(), max_size_); } // Get a forward-only iterator for one past the last element. const_iterator end() const { return const_iterator(); } // Set the maximum size for a single transfer. void prepare(std::size_t max_size) { max_size_ = max_size; } // Consume the specified number of bytes from the buffers. void consume(std::size_t size) { // Remove buffers from the start until the specified size is reached. while (size > 0 && !at_end_) { if (buffer_size(first_) <= size) { size -= buffer_size(first_); if (begin_remainder_ == buffers_.end()) at_end_ = true; else first_ = *begin_remainder_++; } else { first_ = first_ + size; size = 0; } } // Remove any more empty buffers at the start. while (!at_end_ && buffer_size(first_) == 0) { if (begin_remainder_ == buffers_.end()) at_end_ = true; else first_ = *begin_remainder_++; } } private: Buffers buffers_; bool at_end_; Buffer first_; typename Buffers::const_iterator begin_remainder_; std::size_t max_size_; }; // Specialisation for null_buffers to ensure that the null_buffers type is // always passed through to the underlying read or write operation. template class consuming_buffers : public asio::null_buffers { public: consuming_buffers(const asio::null_buffers&) { // No-op. } void prepare(std::size_t) { // No-op. } void consume(std::size_t) { // No-op. } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP percona-galera-3-3.8-3390/asio/asio/detail/deadline_timer_service.hpp000066400000000000000000000123271244131713600253350ustar00rootroot00000000000000// // detail/deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP #define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue.hpp" #include "asio/detail/timer_scheduler.hpp" #include "asio/detail/wait_handler.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class deadline_timer_service { public: // The time type. typedef typename Time_Traits::time_type time_type; // The duration type. typedef typename Time_Traits::duration_type duration_type; // The implementation type of the timer. This type is dependent on the // underlying implementation of the timer service. struct implementation_type : private asio::detail::noncopyable { time_type expiry; bool might_have_pending_waits; typename timer_queue::per_timer_data timer_data; }; // Constructor. deadline_timer_service(asio::io_service& io_service) : scheduler_(asio::use_service(io_service)) { scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); } // Destructor. ~deadline_timer_service() { scheduler_.remove_timer_queue(timer_queue_); } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { } // Construct a new timer implementation. void construct(implementation_type& impl) { impl.expiry = time_type(); impl.might_have_pending_waits = false; } // Destroy a timer implementation. void destroy(implementation_type& impl) { asio::error_code ec; cancel(impl, ec); } // Cancel any asynchronous wait operations associated with the timer. std::size_t cancel(implementation_type& impl, asio::error_code& ec) { if (!impl.might_have_pending_waits) { ec = asio::error_code(); return 0; } std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); impl.might_have_pending_waits = false; ec = asio::error_code(); return count; } // Get the expiry time for the timer as an absolute time. time_type expires_at(const implementation_type& impl) const { return impl.expiry; } // Set the expiry time for the timer as an absolute time. std::size_t expires_at(implementation_type& impl, const time_type& expiry_time, asio::error_code& ec) { std::size_t count = cancel(impl, ec); impl.expiry = expiry_time; ec = asio::error_code(); return count; } // Get the expiry time for the timer relative to now. duration_type expires_from_now(const implementation_type& impl) const { return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); } // Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, const duration_type& expiry_time, asio::error_code& ec) { return expires_at(impl, Time_Traits::add(Time_Traits::now(), expiry_time), ec); } // Perform a blocking wait on the timer. void wait(implementation_type& impl, asio::error_code& ec) { time_type now = Time_Traits::now(); while (Time_Traits::less_than(now, impl.expiry)) { boost::posix_time::time_duration timeout = Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now)); ::timeval tv; tv.tv_sec = timeout.total_seconds(); tv.tv_usec = timeout.total_microseconds() % 1000000; asio::error_code ec; socket_ops::select(0, 0, 0, 0, &tv, ec); now = Time_Traits::now(); } ec = asio::error_code(); } // Start an asynchronous wait on the timer. template void async_wait(implementation_type& impl, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef wait_handler op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); impl.might_have_pending_waits = true; scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); p.v = p.p = 0; } private: // The queue of timers. timer_queue timer_queue_; // The object that schedules and executes timers. Usually a reactor. timer_scheduler& scheduler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/descriptor_ops.hpp000066400000000000000000000054371244131713600237130ustar00rootroot00000000000000// // detail/descriptor_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DESCRIPTOR_OPS_HPP #define ASIO_DETAIL_DESCRIPTOR_OPS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/error_code.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace descriptor_ops { // Descriptor state bits. enum { // The user wants a non-blocking descriptor. user_set_non_blocking = 1, // The descriptor has been set non-blocking. internal_non_blocking = 2, // Helper "state" used to determine whether the descriptor is non-blocking. non_blocking = user_set_non_blocking | internal_non_blocking }; typedef unsigned char state_type; template inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec) { ec = asio::error_code(errno, asio::error::get_system_category()); return return_value; } ASIO_DECL int open(const char* path, int flags, asio::error_code& ec); ASIO_DECL int close(int d, state_type& state, asio::error_code& ec); ASIO_DECL bool set_internal_non_blocking(int d, state_type& state, asio::error_code& ec); typedef iovec buf; ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec); ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred); ASIO_DECL std::size_t sync_write(int d, state_type state, const buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec); ASIO_DECL bool non_blocking_write(int d, const buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred); ASIO_DECL int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, asio::error_code& ec); ASIO_DECL int fcntl(int d, long cmd, asio::error_code& ec); ASIO_DECL int fcntl(int d, long cmd, long arg, asio::error_code& ec); ASIO_DECL int poll_read(int d, asio::error_code& ec); ASIO_DECL int poll_write(int d, asio::error_code& ec); } // namespace descriptor_ops } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/descriptor_ops.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP percona-galera-3-3.8-3390/asio/asio/detail/descriptor_read_op.hpp000066400000000000000000000065741244131713600245260ustar00rootroot00000000000000// // detail/descriptor_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP #define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/descriptor_ops.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class descriptor_read_op_base : public reactor_op { public: descriptor_read_op_base(int descriptor, const MutableBufferSequence& buffers, func_type complete_func) : reactor_op(&descriptor_read_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { } static bool do_perform(reactor_op* base) { descriptor_read_op_base* o(static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); return descriptor_ops::non_blocking_read(o->descriptor_, bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); } private: int descriptor_; MutableBufferSequence buffers_; }; template class descriptor_read_op : public descriptor_read_op_base { public: ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); descriptor_read_op(int descriptor, const MutableBufferSequence& buffers, Handler handler) : descriptor_read_op_base( descriptor, buffers, &descriptor_read_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. descriptor_read_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/descriptor_write_op.hpp000066400000000000000000000065751244131713600247460ustar00rootroot00000000000000// // detail/descriptor_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP #define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/descriptor_ops.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class descriptor_write_op_base : public reactor_op { public: descriptor_write_op_base(int descriptor, const ConstBufferSequence& buffers, func_type complete_func) : reactor_op(&descriptor_write_op_base::do_perform, complete_func), descriptor_(descriptor), buffers_(buffers) { } static bool do_perform(reactor_op* base) { descriptor_write_op_base* o(static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); return descriptor_ops::non_blocking_write(o->descriptor_, bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_); } private: int descriptor_; ConstBufferSequence buffers_; }; template class descriptor_write_op : public descriptor_write_op_base { public: ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); descriptor_write_op(int descriptor, const ConstBufferSequence& buffers, Handler handler) : descriptor_write_op_base( descriptor, buffers, &descriptor_write_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. descriptor_write_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/dev_poll_reactor.hpp000066400000000000000000000137371244131713600242010ustar00rootroot00000000000000// // detail/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DEV_POLL_REACTOR_HPP #define ASIO_DETAIL_DEV_POLL_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_DEV_POLL) #include #include #include #include "asio/detail/dev_poll_reactor_fwd.hpp" #include "asio/detail/hash_map.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class dev_poll_reactor : public asio::detail::service_base { public: enum { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; // Per-descriptor data. struct per_descriptor_data { }; // Constructor. ASIO_DECL dev_poll_reactor(asio::io_service& io_service); // Destructor. ASIO_DECL ~dev_poll_reactor(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task. ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op) { io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data&, reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. ASIO_DECL void close_descriptor( socket_type descriptor, per_descriptor_data&); // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer); // Run /dev/poll once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. ASIO_DECL void interrupt(); private: // Create the /dev/poll file descriptor. Throws an exception if the descriptor // cannot be created. ASIO_DECL static int do_dev_poll_create(); // Helper function to add a new timer queue. ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the /dev/poll DP_POLL operation. The timeout // value is returned as a number of milliseconds. A return value of -1 // indicates that the poll should block indefinitely. ASIO_DECL int get_timeout(); // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not // acquire the dev_poll_reactor's mutex. ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, const asio::error_code& ec); // Add a pending event entry for the given descriptor. ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to internal data. asio::detail::mutex mutex_; // The /dev/poll file descriptor. int dev_poll_fd_; // Vector of /dev/poll events waiting to be written to the descriptor. std::vector< ::pollfd> pending_event_changes_; // Hash map to associate a descriptor with a pending event change index. hash_map pending_event_change_index_; // The interrupter is used to break a blocking DP_POLL operation. select_interrupter interrupter_; // The queues of read, write and except operations. reactor_op_queue op_queue_[max_ops]; // The timer queues. timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/dev_poll_reactor.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/dev_poll_reactor.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_DEV_POLL) #endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/dev_poll_reactor_fwd.hpp000066400000000000000000000014041244131713600250250ustar00rootroot00000000000000// // detail/dev_poll_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP #define ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_DEV_POLL) namespace asio { namespace detail { class dev_poll_reactor; } // namespace detail } // namespace asio #endif // defined(ASIO_HAS_DEV_POLL) #endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/epoll_reactor.hpp000066400000000000000000000141121244131713600234740ustar00rootroot00000000000000// // detail/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_EPOLL_REACTOR_HPP #define ASIO_DETAIL_EPOLL_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_EPOLL) #include "asio/io_service.hpp" #include "asio/detail/epoll_reactor_fwd.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class epoll_reactor : public asio::detail::service_base { public: enum { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; // Per-descriptor queues. class descriptor_state { friend class epoll_reactor; friend class object_pool_access; mutex mutex_; op_queue op_queue_[max_ops]; bool shutdown_; descriptor_state* next_; descriptor_state* prev_; }; // Per-descriptor data. typedef descriptor_state* per_descriptor_data; // Constructor. ASIO_DECL epoll_reactor(asio::io_service& io_service); // Destructor. ASIO_DECL ~epoll_reactor(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task. ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. ASIO_DECL int register_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data); // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op) { io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. ASIO_DECL void close_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer); // Run epoll once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. ASIO_DECL void interrupt(); private: // The hint to pass to epoll_create to size its data structures. enum { epoll_size = 20000 }; // Create the epoll file descriptor. Throws an exception if the descriptor // cannot be created. ASIO_DECL static int do_epoll_create(); // Helper function to add a new timer queue. ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Called to recalculate and update the timeout. ASIO_DECL void update_timeout(); // Get the timeout value for the epoll_wait call. The timeout value is // returned as a number of milliseconds. A return value of -1 indicates // that epoll_wait should block indefinitely. ASIO_DECL int get_timeout(); #if defined(ASIO_HAS_TIMERFD) // Get the timeout value for the timer descriptor. The return value is the // flag argument to be used when calling timerfd_settime. ASIO_DECL int get_timeout(itimerspec& ts); #endif // defined(ASIO_HAS_TIMERFD) // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to internal data. mutex mutex_; // The epoll file descriptor. int epoll_fd_; // The timer file descriptor. int timer_fd_; // The interrupter is used to break a blocking epoll_wait call. select_interrupter interrupter_; // The timer queues. timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; // Mutex to protect access to the registered descriptors. mutex registered_descriptors_mutex_; // Keep track of all registered descriptors. object_pool registered_descriptors_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/epoll_reactor.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/epoll_reactor.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_EPOLL) #endif // ASIO_DETAIL_EPOLL_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/epoll_reactor_fwd.hpp000066400000000000000000000013541244131713600243400ustar00rootroot00000000000000// // detail/epoll_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP #define ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_EPOLL) namespace asio { namespace detail { class epoll_reactor; } // namespace detail } // namespace asio #endif // defined(ASIO_HAS_EPOLL) #endif // ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/event.hpp000066400000000000000000000021411244131713600217620ustar00rootroot00000000000000// // detail/event.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_EVENT_HPP #define ASIO_DETAIL_EVENT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_event.hpp" #elif defined(BOOST_WINDOWS) # include "asio/detail/win_event.hpp" #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_event.hpp" #else # error Only Windows and POSIX are supported! #endif namespace asio { namespace detail { #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) typedef null_event event; #elif defined(BOOST_WINDOWS) typedef win_event event; #elif defined(BOOST_HAS_PTHREADS) typedef posix_event event; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_EVENT_HPP percona-galera-3-3.8-3390/asio/asio/detail/eventfd_select_interrupter.hpp000066400000000000000000000041241244131713600263010ustar00rootroot00000000000000// // detail/eventfd_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // // 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) // #ifndef ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP #define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_EVENTFD) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class eventfd_select_interrupter { public: // Constructor. ASIO_DECL eventfd_select_interrupter(); // Destructor. ASIO_DECL ~eventfd_select_interrupter(); // Interrupt the select call. ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const { return read_descriptor_; } private: // The read end of a connection used to interrupt the select call. This file // descriptor is passed to select such that when it is time to stop, a single // 64bit value will be written on the other end of the connection and this // descriptor will become readable. int read_descriptor_; // The write end of a connection used to interrupt the select call. A single // 64bit non-zero value may be written to this to wake up the select which is // waiting for the other end to become readable. This descriptor will only // differ from the read descriptor when a pipe is used. int write_descriptor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/eventfd_select_interrupter.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_EVENTFD) #endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/fd_set_adapter.hpp000066400000000000000000000015751244131713600236170ustar00rootroot00000000000000// // detail/fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_FD_SET_ADAPTER_HPP #define ASIO_DETAIL_FD_SET_ADAPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/posix_fd_set_adapter.hpp" #include "asio/detail/win_fd_set_adapter.hpp" namespace asio { namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef win_fd_set_adapter fd_set_adapter; #else typedef posix_fd_set_adapter fd_set_adapter; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/fenced_block.hpp000066400000000000000000000055171244131713600232510ustar00rootroot00000000000000// // detail/fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_FENCED_BLOCK_HPP #define ASIO_DETAIL_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" // #763 - Galera library is multithreaded so make sure that ASIO will have // MT support too. #if !defined(BOOST_HAS_THREADS) #error "BOOST_HAS_THREADS not defined" #endif #if !defined(BOOST_HAS_THREADS) \ || defined(ASIO_DISABLE_THREADS) \ || defined(ASIO_DISABLE_FENCED_BLOCK) # include "asio/detail/null_fenced_block.hpp" #elif defined(__MACH__) && defined(__APPLE__) # include "asio/detail/macos_fenced_block.hpp" #elif defined(__sun) # include "asio/detail/solaris_fenced_block.hpp" #elif defined(__GNUC__) && defined(__arm__) # include "asio/detail/gcc_arm_fenced_block.hpp" #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) # include "asio/detail/gcc_hppa_fenced_block.hpp" #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) # include "asio/detail/gcc_sync_fenced_block.hpp" #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include "asio/detail/gcc_x86_fenced_block.hpp" #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) # include "asio/detail/win_fenced_block.hpp" #else # include "asio/detail/null_fenced_block.hpp" #endif namespace asio { namespace detail { #if !defined(BOOST_HAS_THREADS) \ || defined(ASIO_DISABLE_THREADS) \ || defined(ASIO_DISABLE_FENCED_BLOCK) typedef null_fenced_block fenced_block; #elif defined(__MACH__) && defined(__APPLE__) typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; #elif defined(__GNUC__) && defined(__arm__) typedef gcc_arm_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) typedef gcc_hppa_fenced_block fenced_block; #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) typedef gcc_sync_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) typedef gcc_x86_fenced_block fenced_block; #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) typedef win_fenced_block fenced_block; #else typedef null_fenced_block fenced_block; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/gcc_arm_fenced_block.hpp000066400000000000000000000033121244131713600247130ustar00rootroot00000000000000// // detail/gcc_arm_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP #define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__GNUC__) && defined(__arm__) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class gcc_arm_fenced_block : private noncopyable { public: // Constructor. gcc_arm_fenced_block() { barrier(); } // Destructor. ~gcc_arm_fenced_block() { barrier(); } private: static void barrier() { #if defined(__ARM_ARCH_4__) \ || defined(__ARM_ARCH_4T__) \ || defined(__ARM_ARCH_5__) \ || defined(__ARM_ARCH_5E__) \ || defined(__ARM_ARCH_5T__) \ || defined(__ARM_ARCH_5TE__) \ || defined(__ARM_ARCH_5TEJ__) \ || defined(__ARM_ARCH_6__) \ || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) \ || defined(__ARM_ARCH_6Z__) \ || defined(__ARM_ARCH_6ZK__) \ || defined(__ARM_ARCH_6T2__) int a = 0, b = 0; __asm__ __volatile__ ("swp %0, %1, [%2]" : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); #else // ARMv7 and later. __asm__ __volatile__ ("dmb" : : : "memory"); #endif } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__GNUC__) && defined(__arm__) #endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/gcc_fenced_block.hpp000066400000000000000000000027531244131713600240640ustar00rootroot00000000000000// // gcc_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_GCC_FENCED_BLOCK_HPP #define ASIO_DETAIL_GCC_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) namespace asio { namespace detail { class gcc_fenced_block : private noncopyable { public: // Constructor. gcc_fenced_block() : value_(0) { __sync_lock_test_and_set(&value_, 1); } // Destructor. ~gcc_fenced_block() { __sync_lock_release(&value_); } private: int value_; }; } // namespace detail } // namespace asio #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) // && !defined(__INTEL_COMPILER) && !defined(__ICL) // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_GCC_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/gcc_hppa_fenced_block.hpp000066400000000000000000000023531244131713600250700ustar00rootroot00000000000000// // detail/gcc_hppa_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP #define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class gcc_hppa_fenced_block : private noncopyable { public: // Constructor. gcc_hppa_fenced_block() { barrier(); } // Destructor. ~gcc_hppa_fenced_block() { barrier(); } private: static void barrier() { // This is just a placeholder and almost certainly not sufficient. __asm__ __volatile__ ("" : : : "memory"); } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) #endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/gcc_sync_fenced_block.hpp000066400000000000000000000027301244131713600251130ustar00rootroot00000000000000// // detail/gcc_sync_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP #define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class gcc_sync_fenced_block : private noncopyable { public: // Constructor. gcc_sync_fenced_block() : value_(0) { __sync_lock_test_and_set(&value_, 1); } // Destructor. ~gcc_sync_fenced_block() { __sync_lock_release(&value_); } private: int value_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__GNUC__) // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) // && !defined(__INTEL_COMPILER) && !defined(__ICL) // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) #endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/gcc_x86_fenced_block.hpp000066400000000000000000000023361244131713600245660ustar00rootroot00000000000000// // detail/gcc_x86_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP #define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class gcc_x86_fenced_block : private noncopyable { public: // Constructor. gcc_x86_fenced_block() { barrier(); } // Destructor. ~gcc_x86_fenced_block() { barrier(); } private: static int barrier() { int r = 0; __asm__ __volatile__ ("xchgl %%eax, %0" : "=m" (r) : : "memory", "cc"); return r; } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/handler_alloc_helpers.hpp000066400000000000000000000041461244131713600251610ustar00rootroot00000000000000// // detail/handler_alloc_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP #define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/noncopyable.hpp" #include "asio/handler_alloc_hook.hpp" #include "asio/detail/push_options.hpp" // Calls to asio_handler_allocate and asio_handler_deallocate must be made from // a namespace that does not contain any overloads of these functions. The // asio_handler_alloc_helpers namespace is defined here for that purpose. namespace asio_handler_alloc_helpers { template inline void* allocate(std::size_t s, Handler& h) { #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \ || BOOST_WORKAROUND(__GNUC__, < 3) return ::operator new(s); #else using namespace asio; return asio_handler_allocate(s, boost::addressof(h)); #endif } template inline void deallocate(void* p, std::size_t s, Handler& h) { #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \ || BOOST_WORKAROUND(__GNUC__, < 3) ::operator delete(p); #else using namespace asio; asio_handler_deallocate(p, s, boost::addressof(h)); #endif } } // namespace asio_handler_alloc_helpers #define ASIO_DEFINE_HANDLER_PTR(op) \ struct ptr \ { \ Handler* h; \ void* v; \ op* p; \ ~ptr() \ { \ reset(); \ } \ void reset() \ { \ if (p) \ { \ p->~op(); \ p = 0; \ } \ if (v) \ { \ asio_handler_alloc_helpers::deallocate(v, sizeof(op), *h); \ v = 0; \ } \ } \ } \ /**/ #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP percona-galera-3-3.8-3390/asio/asio/detail/handler_invoke_helpers.hpp000066400000000000000000000026261244131713600253630ustar00rootroot00000000000000// // detail/handler_invoke_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP #define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/handler_invoke_hook.hpp" #include "asio/detail/push_options.hpp" // Calls to asio_handler_invoke must be made from a namespace that does not // contain overloads of this function. The asio_handler_invoke_helpers // namespace is defined here for that purpose. namespace asio_handler_invoke_helpers { template inline void invoke(const Function& function, Context& context) { #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) \ || BOOST_WORKAROUND(__GNUC__, < 3) Function tmp(function); tmp(); #else using namespace asio; asio_handler_invoke(function, boost::addressof(context)); #endif } } // namespace asio_handler_invoke_helpers #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP percona-galera-3-3.8-3390/asio/asio/detail/hash_map.hpp000066400000000000000000000175521244131713600224350ustar00rootroot00000000000000// // detail/hash_map.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_HASH_MAP_HPP #define ASIO_DETAIL_HASH_MAP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/detail/noncopyable.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include "asio/detail/socket_types.hpp" #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { inline std::size_t calculate_hash_value(int i) { return static_cast(i); } inline std::size_t calculate_hash_value(void* p) { return reinterpret_cast(p) + (reinterpret_cast(p) >> 3); } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) inline std::size_t calculate_hash_value(SOCKET s) { return static_cast(s); } #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Note: assumes K and V are POD types. template class hash_map : private noncopyable { public: // The type of a value in the map. typedef std::pair value_type; // The type of a non-const iterator over the hash map. typedef typename std::list::iterator iterator; // The type of a const iterator over the hash map. typedef typename std::list::const_iterator const_iterator; // Constructor. hash_map() : size_(0), buckets_(0), num_buckets_(0) { } // Destructor. ~hash_map() { delete[] buckets_; } // Get an iterator for the beginning of the map. iterator begin() { return values_.begin(); } // Get an iterator for the beginning of the map. const_iterator begin() const { return values_.begin(); } // Get an iterator for the end of the map. iterator end() { return values_.end(); } // Get an iterator for the end of the map. const_iterator end() const { return values_.end(); } // Check whether the map is empty. bool empty() const { return values_.empty(); } // Find an entry in the map. iterator find(const K& k) { if (num_buckets_) { size_t bucket = calculate_hash_value(k) % num_buckets_; iterator it = buckets_[bucket].first; if (it == values_.end()) return values_.end(); iterator end = buckets_[bucket].last; ++end; while (it != end) { if (it->first == k) return it; ++it; } } return values_.end(); } // Find an entry in the map. const_iterator find(const K& k) const { if (num_buckets_) { size_t bucket = calculate_hash_value(k) % num_buckets_; const_iterator it = buckets_[bucket].first; if (it == values_.end()) return it; const_iterator end = buckets_[bucket].last; ++end; while (it != end) { if (it->first == k) return it; ++it; } } return values_.end(); } // Insert a new entry into the map. std::pair insert(const value_type& v) { if (size_ + 1 >= num_buckets_) rehash(hash_size(size_ + 1)); size_t bucket = calculate_hash_value(v.first) % num_buckets_; iterator it = buckets_[bucket].first; if (it == values_.end()) { buckets_[bucket].first = buckets_[bucket].last = values_insert(values_.end(), v); ++size_; return std::pair(buckets_[bucket].last, true); } iterator end = buckets_[bucket].last; ++end; while (it != end) { if (it->first == v.first) return std::pair(it, false); ++it; } buckets_[bucket].last = values_insert(end, v); ++size_; return std::pair(buckets_[bucket].last, true); } // Erase an entry from the map. void erase(iterator it) { assert(it != values_.end()); size_t bucket = calculate_hash_value(it->first) % num_buckets_; bool is_first = (it == buckets_[bucket].first); bool is_last = (it == buckets_[bucket].last); if (is_first && is_last) buckets_[bucket].first = buckets_[bucket].last = values_.end(); else if (is_first) ++buckets_[bucket].first; else if (is_last) --buckets_[bucket].last; values_erase(it); --size_; } // Erase a key from the map. void erase(const K& k) { iterator it = find(k); if (it != values_.end()) erase(it); } // Remove all entries from the map. void clear() { // Clear the values. values_.clear(); size_ = 0; // Initialise all buckets to empty. iterator end = values_.end(); for (size_t i = 0; i < num_buckets_; ++i) buckets_[i].first = buckets_[i].last = end; } private: // Calculate the hash size for the specified number of elements. static std::size_t hash_size(std::size_t num_elems) { static std::size_t sizes[] = { #if defined(ASIO_HASH_MAP_BUCKETS) ASIO_HASH_MAP_BUCKETS #else // ASIO_HASH_MAP_BUCKETS 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843 #endif // ASIO_HASH_MAP_BUCKETS }; const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1; for (std::size_t i = 0; i < nth_size; ++i) if (num_elems < sizes[i]) return sizes[i]; return sizes[nth_size]; } // Re-initialise the hash from the values already contained in the list. void rehash(std::size_t num_buckets) { if (num_buckets == num_buckets_) return; num_buckets_ = num_buckets; iterator end = values_.end(); // Update number of buckets and initialise all buckets to empty. bucket_type* tmp = new bucket_type[num_buckets_]; delete[] buckets_; buckets_ = tmp; for (std::size_t i = 0; i < num_buckets_; ++i) buckets_[i].first = buckets_[i].last = end; // Put all values back into the hash. iterator iter = values_.begin(); while (iter != end) { std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; if (buckets_[bucket].last == end) { buckets_[bucket].first = buckets_[bucket].last = iter++; } else if (++buckets_[bucket].last == iter) { ++iter; } else { values_.splice(buckets_[bucket].last, values_, iter++); --buckets_[bucket].last; } } } // Insert an element into the values list by splicing from the spares list, // if a spare is available, and otherwise by inserting a new element. iterator values_insert(iterator it, const value_type& v) { if (spares_.empty()) { return values_.insert(it, v); } else { spares_.front() = v; values_.splice(it, spares_, spares_.begin()); return --it; } } // Erase an element from the values list by splicing it to the spares list. void values_erase(iterator it) { *it = value_type(); spares_.splice(spares_.begin(), values_, it); } // The number of elements in the hash. std::size_t size_; // The list of all values in the hash map. std::list values_; // The list of spare nodes waiting to be recycled. Assumes that POD types only // are stored in the hash map. std::list spares_; // The type for a bucket in the hash table. struct bucket_type { iterator first; iterator last; }; // The buckets in the hash. bucket_type* buckets_; // The number of buckets in the hash. std::size_t num_buckets_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_HASH_MAP_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/000077500000000000000000000000001244131713600210735ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/detail/impl/descriptor_ops.ipp000066400000000000000000000177221244131713600246550ustar00rootroot00000000000000// // detail/impl/descriptor_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP #define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/descriptor_ops.hpp" #include "asio/error.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace descriptor_ops { int open(const char* path, int flags, asio::error_code& ec) { errno = 0; int result = error_wrapper(::open(path, flags), ec); if (result >= 0) ec = asio::error_code(); return result; } int close(int d, state_type& state, asio::error_code& ec) { int result = 0; if (d != -1) { if (state & internal_non_blocking) { #if defined(__SYMBIAN32__) int flags = ::fcntl(d, F_GETFL, 0); if (flags >= 0) ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); #else // defined(__SYMBIAN32__) ioctl_arg_type arg = 0; ::ioctl(d, FIONBIO, &arg); #endif // defined(__SYMBIAN32__) state &= ~internal_non_blocking; } errno = 0; result = error_wrapper(::close(d), ec); } if (result == 0) ec = asio::error_code(); return result; } bool set_internal_non_blocking(int d, state_type& state, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return false; } errno = 0; #if defined(__SYMBIAN32__) int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); if (result >= 0) { errno = 0; result = error_wrapper(::fcntl(d, F_SETFL, result | O_NONBLOCK), ec); } #else // defined(__SYMBIAN32__) ioctl_arg_type arg = 1; int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); #endif // defined(__SYMBIAN32__) if (result >= 0) { ec = asio::error_code(); state |= internal_non_blocking; return true; } return false; } std::size_t sync_read(int d, state_type state, buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return 0; } // A request to read 0 bytes on a stream is a no-op. if (all_empty) { ec = asio::error_code(); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. errno = 0; int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); // Check if operation succeeded. if (bytes > 0) return bytes; // Check for EOF. if (bytes == 0) { ec = asio::error::eof; return 0; } // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for descriptor to become ready. if (descriptor_ops::poll_read(d, ec) < 0) return 0; } } bool non_blocking_read(int d, buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred) { for (;;) { // Read some data. errno = 0; int bytes = error_wrapper(::readv(d, bufs, static_cast(count)), ec); // Check for end of stream. if (bytes == 0) { ec = asio::error::eof; return true; } // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes > 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } std::size_t sync_write(int d, state_type state, const buf* bufs, std::size_t count, bool all_empty, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return 0; } // A request to write 0 bytes on a stream is a no-op. if (all_empty) { ec = asio::error_code(); return 0; } // Write some data. for (;;) { // Try to complete the operation without blocking. errno = 0; int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); // Check if operation succeeded. if (bytes > 0) return bytes; // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for descriptor to become ready. if (descriptor_ops::poll_write(d, ec) < 0) return 0; } } bool non_blocking_write(int d, const buf* bufs, std::size_t count, asio::error_code& ec, std::size_t& bytes_transferred) { for (;;) { // Write some data. errno = 0; int bytes = error_wrapper(::writev(d, bufs, static_cast(count)), ec); // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes >= 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } int ioctl(int d, state_type& state, long cmd, ioctl_arg_type* arg, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return -1; } errno = 0; int result = error_wrapper(::ioctl(d, cmd, arg), ec); if (result >= 0) { ec = asio::error_code(); // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the descriptor is // already in the correct state. This ensures that the underlying // descriptor is put into the state that has been requested by the user. If // the ioctl syscall was successful then we need to update the flags to // match. if (cmd == static_cast(FIONBIO)) { if (*arg) { state |= user_set_non_blocking; } else { // Clearing the non-blocking mode always overrides any internally-set // non-blocking flag. Any subsequent asynchronous operations will need // to re-enable non-blocking I/O. state &= ~(user_set_non_blocking | internal_non_blocking); } } } return result; } int fcntl(int d, long cmd, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return -1; } errno = 0; int result = error_wrapper(::fcntl(d, cmd), ec); if (result != -1) ec = asio::error_code(); return result; } int fcntl(int d, long cmd, long arg, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return -1; } errno = 0; int result = error_wrapper(::fcntl(d, cmd, arg), ec); if (result != -1) ec = asio::error_code(); return result; } int poll_read(int d, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return -1; } pollfd fds; fds.fd = d; fds.events = POLLIN; fds.revents = 0; errno = 0; int result = error_wrapper(::poll(&fds, 1, -1), ec); if (result >= 0) ec = asio::error_code(); return result; } int poll_write(int d, asio::error_code& ec) { if (d == -1) { ec = asio::error::bad_descriptor; return -1; } pollfd fds; fds.fd = d; fds.events = POLLOUT; fds.revents = 0; errno = 0; int result = error_wrapper(::poll(&fds, 1, -1), ec); if (result >= 0) ec = asio::error_code(); return result; } } // namespace descriptor_ops } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/dev_poll_reactor.hpp000066400000000000000000000037071244131713600251360ustar00rootroot00000000000000// // detail/impl/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP #define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_DEV_POLL) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void dev_poll_reactor::add_timer_queue(timer_queue& queue) { do_add_timer_queue(queue); } template void dev_poll_reactor::remove_timer_queue(timer_queue& queue) { do_remove_timer_queue(queue); } template void dev_poll_reactor::schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { io_service_.post_immediate_completion(op); return; } bool earliest = queue.enqueue_timer(time, timer, op); io_service_.work_started(); if (earliest) interrupter_.interrupt(); } template std::size_t dev_poll_reactor::cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer) { asio::detail::mutex::scoped_lock lock(mutex_); op_queue ops; std::size_t n = queue.cancel_timer(timer, ops); lock.unlock(); io_service_.post_deferred_completions(ops); return n; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_DEV_POLL) #endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/dev_poll_reactor.ipp000066400000000000000000000227431244131713600251400ustar00rootroot00000000000000// // detail/impl/dev_poll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP #define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_DEV_POLL) #include "asio/detail/dev_poll_reactor.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { dev_poll_reactor::dev_poll_reactor(asio::io_service& io_service) : asio::detail::service_base(io_service), io_service_(use_service(io_service)), mutex_(), dev_poll_fd_(do_dev_poll_create()), interrupter_(), shutdown_(false) { // Add the interrupter's descriptor to /dev/poll. ::pollfd ev = { 0, 0, 0 }; ev.fd = interrupter_.read_descriptor(); ev.events = POLLIN | POLLERR; ev.revents = 0; ::write(dev_poll_fd_, &ev, sizeof(ev)); } dev_poll_reactor::~dev_poll_reactor() { shutdown_service(); ::close(dev_poll_fd_); } void dev_poll_reactor::shutdown_service() { asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; lock.unlock(); op_queue ops; for (int i = 0; i < max_ops; ++i) op_queue_[i].get_all_operations(ops); timer_queues_.get_all_timers(ops); } void dev_poll_reactor::init_task() { io_service_.init_task(); } int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) { return 0; } void dev_poll_reactor::start_op(int op_type, socket_type descriptor, dev_poll_reactor::per_descriptor_data&, reactor_op* op, bool allow_speculative) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { post_immediate_completion(op); return; } if (allow_speculative) { if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) { if (!op_queue_[op_type].has_operation(descriptor)) { if (op->perform()) { lock.unlock(); io_service_.post_immediate_completion(op); return; } } } } bool first = op_queue_[op_type].enqueue_operation(descriptor, op); io_service_.work_started(); if (first) { ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLERR | POLLHUP; if (op_type == read_op || op_queue_[read_op].has_operation(descriptor)) ev.events |= POLLIN; if (op_type == write_op || op_queue_[write_op].has_operation(descriptor)) ev.events |= POLLOUT; if (op_type == except_op || op_queue_[except_op].has_operation(descriptor)) ev.events |= POLLPRI; interrupter_.interrupt(); } } void dev_poll_reactor::cancel_ops(socket_type descriptor, dev_poll_reactor::per_descriptor_data&) { asio::detail::mutex::scoped_lock lock(mutex_); cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } void dev_poll_reactor::close_descriptor(socket_type descriptor, dev_poll_reactor::per_descriptor_data&) { asio::detail::mutex::scoped_lock lock(mutex_); // Remove the descriptor from /dev/poll. ::pollfd& ev = add_pending_event_change(descriptor); ev.events = POLLREMOVE; interrupter_.interrupt(); // Cancel any outstanding operations associated with the descriptor. cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } void dev_poll_reactor::run(bool block, op_queue& ops) { asio::detail::mutex::scoped_lock lock(mutex_); // We can return immediately if there's no work to do and the reactor is // not supposed to block. if (!block && op_queue_[read_op].empty() && op_queue_[write_op].empty() && op_queue_[except_op].empty() && timer_queues_.all_empty()) return; // Write the pending event registration changes to the /dev/poll descriptor. std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); if (events_size > 0) { errno = 0; int result = ::write(dev_poll_fd_, &pending_event_changes_[0], events_size); if (result != static_cast(events_size)) { asio::error_code ec = asio::error_code( errno, asio::error::get_system_category()); for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) { int descriptor = pending_event_changes_[i].fd; for (int j = 0; j < max_ops; ++j) op_queue_[j].cancel_operations(descriptor, ops, ec); } } pending_event_changes_.clear(); pending_event_change_index_.clear(); } int timeout = block ? get_timeout() : 0; lock.unlock(); // Block on the /dev/poll descriptor. ::pollfd events[128] = { { 0, 0, 0 } }; ::dvpoll dp = { 0, 0, 0 }; dp.dp_fds = events; dp.dp_nfds = 128; dp.dp_timeout = timeout; int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); lock.lock(); // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { int descriptor = events[i].fd; if (descriptor == interrupter_.read_descriptor()) { interrupter_.reset(); } else { bool more_reads = false; bool more_writes = false; bool more_except = false; // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) more_except = op_queue_[except_op].perform_operations(descriptor, ops); else more_except = op_queue_[except_op].has_operation(descriptor); if (events[i].events & (POLLIN | POLLERR | POLLHUP)) more_reads = op_queue_[read_op].perform_operations(descriptor, ops); else more_reads = op_queue_[read_op].has_operation(descriptor); if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) more_writes = op_queue_[write_op].perform_operations(descriptor, ops); else more_writes = op_queue_[write_op].has_operation(descriptor); if ((events[i].events & (POLLERR | POLLHUP)) != 0 && !more_except && !more_reads && !more_writes) { // If we have an event and no operations associated with the // descriptor then we need to delete the descriptor from /dev/poll. // The poll operation can produce POLLHUP or POLLERR events when there // is no operation pending, so if we do not remove the descriptor we // can end up in a tight polling loop. ::pollfd ev = { 0, 0, 0 }; ev.fd = descriptor; ev.events = POLLREMOVE; ev.revents = 0; ::write(dev_poll_fd_, &ev, sizeof(ev)); } else { ::pollfd ev = { 0, 0, 0 }; ev.fd = descriptor; ev.events = POLLERR | POLLHUP; if (more_reads) ev.events |= POLLIN; if (more_writes) ev.events |= POLLOUT; if (more_except) ev.events |= POLLPRI; ev.revents = 0; int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); if (result != sizeof(ev)) { asio::error_code ec(errno, asio::error::get_system_category()); for (int j = 0; j < max_ops; ++j) op_queue_[j].cancel_operations(descriptor, ops, ec); } } } } timer_queues_.get_ready_timers(ops); } void dev_poll_reactor::interrupt() { interrupter_.interrupt(); } int dev_poll_reactor::do_dev_poll_create() { int fd = ::open("/dev/poll", O_RDWR); if (fd == -1) { asio::error_code ec(errno, asio::error::get_system_category()); asio::detail::throw_error(ec, "/dev/poll"); } return fd; } void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.insert(&queue); } void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.erase(&queue); } int dev_poll_reactor::get_timeout() { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. return timer_queues_.wait_duration_msec(5 * 60 * 1000); } void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, const asio::error_code& ec) { bool need_interrupt = false; op_queue ops; for (int i = 0; i < max_ops; ++i) need_interrupt = op_queue_[i].cancel_operations( descriptor, ops, ec) || need_interrupt; io_service_.post_deferred_completions(ops); if (need_interrupt) interrupter_.interrupt(); } ::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) { hash_map::iterator iter = pending_event_change_index_.find(descriptor); if (iter == pending_event_change_index_.end()) { std::size_t index = pending_event_changes_.size(); pending_event_changes_.reserve(pending_event_changes_.size() + 1); pending_event_change_index_.insert(std::make_pair(descriptor, index)); pending_event_changes_.push_back(::pollfd()); pending_event_changes_[index].fd = descriptor; pending_event_changes_[index].revents = 0; return pending_event_changes_[index]; } else { return pending_event_changes_[iter->second]; } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_DEV_POLL) #endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/epoll_reactor.hpp000066400000000000000000000035371244131713600244460ustar00rootroot00000000000000// // detail/impl/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP #define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if defined(ASIO_HAS_EPOLL) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void epoll_reactor::add_timer_queue(timer_queue& queue) { do_add_timer_queue(queue); } template void epoll_reactor::remove_timer_queue(timer_queue& queue) { do_remove_timer_queue(queue); } template void epoll_reactor::schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op) { mutex::scoped_lock lock(mutex_); if (shutdown_) { io_service_.post_immediate_completion(op); return; } bool earliest = queue.enqueue_timer(time, timer, op); io_service_.work_started(); if (earliest) update_timeout(); } template std::size_t epoll_reactor::cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer) { mutex::scoped_lock lock(mutex_); op_queue ops; std::size_t n = queue.cancel_timer(timer, ops); lock.unlock(); io_service_.post_deferred_completions(ops); return n; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_EPOLL) #endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/epoll_reactor.ipp000066400000000000000000000232771244131713600244520ustar00rootroot00000000000000// // detail/impl/epoll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP #define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_EPOLL) #include #include #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #if defined(ASIO_HAS_TIMERFD) # include #endif // defined(ASIO_HAS_TIMERFD) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { epoll_reactor::epoll_reactor(asio::io_service& io_service) : asio::detail::service_base(io_service), io_service_(use_service(io_service)), mutex_(), epoll_fd_(do_epoll_create()), #if defined(ASIO_HAS_TIMERFD) timer_fd_(timerfd_create(CLOCK_MONOTONIC, 0)), #else // defined(ASIO_HAS_TIMERFD) timer_fd_(-1), #endif // defined(ASIO_HAS_TIMERFD) interrupter_(), shutdown_(false) { // Add the interrupter's descriptor to epoll. epoll_event ev = { 0, { 0 } }; ev.events = EPOLLIN | EPOLLERR | EPOLLET; ev.data.ptr = &interrupter_; epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); interrupter_.interrupt(); // Add the timer descriptor to epoll. if (timer_fd_ != -1) { ev.events = EPOLLIN | EPOLLERR; ev.data.ptr = &timer_fd_; epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); } } epoll_reactor::~epoll_reactor() { close(epoll_fd_); if (timer_fd_ != -1) close(timer_fd_); } void epoll_reactor::shutdown_service() { mutex::scoped_lock lock(mutex_); shutdown_ = true; lock.unlock(); op_queue ops; while (descriptor_state* state = registered_descriptors_.first()) { for (int i = 0; i < max_ops; ++i) ops.push(state->op_queue_[i]); state->shutdown_ = true; registered_descriptors_.free(state); } timer_queues_.get_all_timers(ops); } void epoll_reactor::init_task() { io_service_.init_task(); } int epoll_reactor::register_descriptor(socket_type descriptor, epoll_reactor::per_descriptor_data& descriptor_data) { mutex::scoped_lock lock(registered_descriptors_mutex_); descriptor_data = registered_descriptors_.alloc(); descriptor_data->shutdown_ = false; lock.unlock(); epoll_event ev = { 0, { 0 } }; ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; ev.data.ptr = descriptor_data; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) return errno; return 0; } void epoll_reactor::start_op(int op_type, socket_type descriptor, epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, bool allow_speculative) { if (!descriptor_data) { op->ec_ = asio::error::bad_descriptor; post_immediate_completion(op); return; } mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); if (descriptor_data->shutdown_) { post_immediate_completion(op); return; } if (descriptor_data->op_queue_[op_type].empty()) { if (allow_speculative && (op_type != read_op || descriptor_data->op_queue_[except_op].empty())) { if (op->perform()) { descriptor_lock.unlock(); io_service_.post_immediate_completion(op); return; } } else { epoll_event ev = { 0, { 0 } }; ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLOUT | EPOLLPRI | EPOLLET; ev.data.ptr = descriptor_data; epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); } } descriptor_data->op_queue_[op_type].push(op); io_service_.work_started(); } void epoll_reactor::cancel_ops(socket_type, epoll_reactor::per_descriptor_data& descriptor_data) { if (!descriptor_data) return; mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); op_queue ops; for (int i = 0; i < max_ops; ++i) { while (reactor_op* op = descriptor_data->op_queue_[i].front()) { op->ec_ = asio::error::operation_aborted; descriptor_data->op_queue_[i].pop(); ops.push(op); } } descriptor_lock.unlock(); io_service_.post_deferred_completions(ops); } void epoll_reactor::close_descriptor(socket_type, epoll_reactor::per_descriptor_data& descriptor_data) { if (!descriptor_data) return; mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); if (!descriptor_data->shutdown_) { // Remove the descriptor from the set of known descriptors. The descriptor // will be automatically removed from the epoll set when it is closed. op_queue ops; for (int i = 0; i < max_ops; ++i) { while (reactor_op* op = descriptor_data->op_queue_[i].front()) { op->ec_ = asio::error::operation_aborted; descriptor_data->op_queue_[i].pop(); ops.push(op); } } descriptor_data->shutdown_ = true; descriptor_lock.unlock(); registered_descriptors_.free(descriptor_data); descriptor_data = 0; descriptors_lock.unlock(); io_service_.post_deferred_completions(ops); } } void epoll_reactor::run(bool block, op_queue& ops) { // Calculate a timeout only if timerfd is not used. int timeout; if (timer_fd_ != -1) timeout = block ? -1 : 0; else { mutex::scoped_lock lock(mutex_); timeout = block ? get_timeout() : 0; } // Block on the epoll descriptor. epoll_event events[128]; int num_events = epoll_wait(epoll_fd_, events, 128, timeout); #if defined(ASIO_HAS_TIMERFD) bool check_timers = (timer_fd_ == -1); #else // defined(ASIO_HAS_TIMERFD) bool check_timers = true; #endif // defined(ASIO_HAS_TIMERFD) // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { void* ptr = events[i].data.ptr; if (ptr == &interrupter_) { // No need to reset the interrupter since we're leaving the descriptor // in a ready-to-read state and relying on edge-triggered notifications // to make it so that we only get woken up when the descriptor's epoll // registration is updated. #if defined(ASIO_HAS_TIMERFD) if (timer_fd_ == -1) check_timers = true; #else // defined(ASIO_HAS_TIMERFD) check_timers = true; #endif // defined(ASIO_HAS_TIMERFD) } #if defined(ASIO_HAS_TIMERFD) else if (ptr == &timer_fd_) { check_timers = true; } #endif // defined(ASIO_HAS_TIMERFD) else { descriptor_state* descriptor_data = static_cast(ptr); mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; for (int j = max_ops - 1; j >= 0; --j) { if (events[i].events & (flag[j] | EPOLLERR | EPOLLHUP)) { while (reactor_op* op = descriptor_data->op_queue_[j].front()) { if (op->perform()) { descriptor_data->op_queue_[j].pop(); ops.push(op); } else break; } } } } } if (check_timers) { mutex::scoped_lock common_lock(mutex_); timer_queues_.get_ready_timers(ops); #if defined(ASIO_HAS_TIMERFD) if (timer_fd_ != -1) { itimerspec new_timeout; itimerspec old_timeout; int flags = get_timeout(new_timeout); timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); } #endif // defined(ASIO_HAS_TIMERFD) } } void epoll_reactor::interrupt() { epoll_event ev = { 0, { 0 } }; ev.events = EPOLLIN | EPOLLERR | EPOLLET; ev.data.ptr = &interrupter_; epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); } int epoll_reactor::do_epoll_create() { int fd = epoll_create(epoll_size); if (fd == -1) { asio::error_code ec(errno, asio::error::get_system_category()); asio::detail::throw_error(ec, "epoll"); } return fd; } void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.insert(&queue); } void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.erase(&queue); } void epoll_reactor::update_timeout() { #if defined(ASIO_HAS_TIMERFD) if (timer_fd_ != -1) { itimerspec new_timeout; itimerspec old_timeout; int flags = get_timeout(new_timeout); timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); return; } #endif // defined(ASIO_HAS_TIMERFD) interrupt(); } int epoll_reactor::get_timeout() { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. return timer_queues_.wait_duration_msec(5 * 60 * 1000); } #if defined(ASIO_HAS_TIMERFD) int epoll_reactor::get_timeout(itimerspec& ts) { ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 0; long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); ts.it_value.tv_sec = usec / 1000000; ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; return usec ? 0 : TFD_TIMER_ABSTIME; } #endif // defined(ASIO_HAS_TIMERFD) } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_EPOLL) #endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/eventfd_select_interrupter.ipp000066400000000000000000000065451244131713600272540ustar00rootroot00000000000000// // detail/impl/eventfd_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP #define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_EVENTFD) #include #include #include #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 # include #else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 # include #endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 #include "asio/detail/eventfd_select_interrupter.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { eventfd_select_interrupter::eventfd_select_interrupter() { #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); #else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); #endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 if (read_descriptor_ != -1) { ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); } else { int pipe_fds[2]; if (pipe(pipe_fds) == 0) { read_descriptor_ = pipe_fds[0]; ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); write_descriptor_ = pipe_fds[1]; ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); } else { asio::error_code ec(errno, asio::error::get_system_category()); asio::detail::throw_error(ec, "eventfd_select_interrupter"); } } } eventfd_select_interrupter::~eventfd_select_interrupter() { if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) ::close(write_descriptor_); if (read_descriptor_ != -1) ::close(read_descriptor_); } void eventfd_select_interrupter::interrupt() { uint64_t counter(1UL); int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); (void)result; } bool eventfd_select_interrupter::reset() { if (write_descriptor_ == read_descriptor_) { for (;;) { // Only perform one read. The kernel maintains an atomic counter. uint64_t counter(0); errno = 0; int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); if (bytes_read < 0 && errno == EINTR) continue; bool was_interrupted = (bytes_read > 0); return was_interrupted; } } else { for (;;) { // Clear all data from the pipe. char data[1024]; int bytes_read = ::read(read_descriptor_, data, sizeof(data)); if (bytes_read < 0 && errno == EINTR) continue; bool was_interrupted = (bytes_read > 0); while (bytes_read == sizeof(data)) bytes_read = ::read(read_descriptor_, data, sizeof(data)); return was_interrupted; } } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_EVENTFD) #endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/kqueue_reactor.hpp000066400000000000000000000040131244131713600246200ustar00rootroot00000000000000// // detail/impl/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP #define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_KQUEUE) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void kqueue_reactor::add_timer_queue(timer_queue& queue) { do_add_timer_queue(queue); } // Remove a timer queue from the reactor. template void kqueue_reactor::remove_timer_queue(timer_queue& queue) { do_remove_timer_queue(queue); } template void kqueue_reactor::schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { io_service_.post_immediate_completion(op); return; } bool earliest = queue.enqueue_timer(time, timer, op); io_service_.work_started(); if (earliest) interrupt(); } template std::size_t kqueue_reactor::cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer) { asio::detail::mutex::scoped_lock lock(mutex_); op_queue ops; std::size_t n = queue.cancel_timer(timer, ops); lock.unlock(); io_service_.post_deferred_completions(ops); return n; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_KQUEUE) #endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/kqueue_reactor.ipp000066400000000000000000000242721244131713600246320ustar00rootroot00000000000000// // detail/impl/kqueue_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP #define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_KQUEUE) #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" #if defined(__NetBSD__) # define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ EV_SET(ev, ident, filt, flags, fflags, \ data, reinterpret_cast(udata)) #else # define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ EV_SET(ev, ident, filt, flags, fflags, data, udata) #endif namespace asio { namespace detail { kqueue_reactor::kqueue_reactor(asio::io_service& io_service) : asio::detail::service_base(io_service), io_service_(use_service(io_service)), mutex_(), kqueue_fd_(do_kqueue_create()), interrupter_(), shutdown_(false) { // The interrupter is put into a permanently readable state. Whenever we // want to interrupt the blocked kevent call we register a one-shot read // operation against the descriptor. interrupter_.interrupt(); } kqueue_reactor::~kqueue_reactor() { close(kqueue_fd_); } void kqueue_reactor::shutdown_service() { mutex::scoped_lock lock(mutex_); shutdown_ = true; lock.unlock(); op_queue ops; while (descriptor_state* state = registered_descriptors_.first()) { for (int i = 0; i < max_ops; ++i) ops.push(state->op_queue_[i]); state->shutdown_ = true; registered_descriptors_.free(state); } timer_queues_.get_all_timers(ops); } void kqueue_reactor::init_task() { io_service_.init_task(); } int kqueue_reactor::register_descriptor(socket_type, kqueue_reactor::per_descriptor_data& descriptor_data) { mutex::scoped_lock lock(registered_descriptors_mutex_); descriptor_data = registered_descriptors_.alloc(); descriptor_data->shutdown_ = false; return 0; } void kqueue_reactor::start_op(int op_type, socket_type descriptor, kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, bool allow_speculative) { if (!descriptor_data) { op->ec_ = asio::error::bad_descriptor; post_immediate_completion(op); return; } mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); if (descriptor_data->shutdown_) { post_immediate_completion(op); return; } bool first = descriptor_data->op_queue_[op_type].empty(); if (first) { if (allow_speculative) { if (op_type != read_op || descriptor_data->op_queue_[except_op].empty()) { if (op->perform()) { descriptor_lock.unlock(); io_service_.post_immediate_completion(op); return; } } } } descriptor_data->op_queue_[op_type].push(op); io_service_.work_started(); if (first) { struct kevent event; switch (op_type) { case read_op: ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); break; case write_op: ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); break; case except_op: if (!descriptor_data->op_queue_[read_op].empty()) return; // Already registered for read events. ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); break; } if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { op->ec_ = asio::error_code(errno, asio::error::get_system_category()); descriptor_data->op_queue_[op_type].pop(); io_service_.post_deferred_completion(op); } } } void kqueue_reactor::cancel_ops(socket_type, kqueue_reactor::per_descriptor_data& descriptor_data) { if (!descriptor_data) return; mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); op_queue ops; for (int i = 0; i < max_ops; ++i) { while (reactor_op* op = descriptor_data->op_queue_[i].front()) { op->ec_ = asio::error::operation_aborted; descriptor_data->op_queue_[i].pop(); ops.push(op); } } descriptor_lock.unlock(); io_service_.post_deferred_completions(ops); } void kqueue_reactor::close_descriptor(socket_type, kqueue_reactor::per_descriptor_data& descriptor_data) { if (!descriptor_data) return; mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); if (!descriptor_data->shutdown_) { // Remove the descriptor from the set of known descriptors. The descriptor // will be automatically removed from the kqueue set when it is closed. op_queue ops; for (int i = 0; i < max_ops; ++i) { while (reactor_op* op = descriptor_data->op_queue_[i].front()) { op->ec_ = asio::error::operation_aborted; descriptor_data->op_queue_[i].pop(); ops.push(op); } } descriptor_data->shutdown_ = true; descriptor_lock.unlock(); registered_descriptors_.free(descriptor_data); descriptor_data = 0; descriptors_lock.unlock(); io_service_.post_deferred_completions(ops); } } void kqueue_reactor::run(bool block, op_queue& ops) { mutex::scoped_lock lock(mutex_); // Determine how long to block while waiting for events. timespec timeout_buf = { 0, 0 }; timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; lock.unlock(); // Block on the kqueue descriptor. struct kevent events[128]; int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); // Dispatch the waiting events. for (int i = 0; i < num_events; ++i) { int descriptor = events[i].ident; void* ptr = reinterpret_cast(events[i].udata); if (ptr == &interrupter_) { // No need to reset the interrupter since we're leaving the descriptor // in a ready-to-read state and relying on one-shot notifications. } else { descriptor_state* descriptor_data = static_cast(ptr); mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. #if defined(__NetBSD__) static const unsigned int filter[max_ops] = #else static const int filter[max_ops] = #endif { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; for (int j = max_ops - 1; j >= 0; --j) { if (events[i].filter == filter[j]) { if (j != except_op || events[i].flags & EV_OOBAND) { while (reactor_op* op = descriptor_data->op_queue_[j].front()) { if (events[i].flags & EV_ERROR) { op->ec_ = asio::error_code(events[i].data, asio::error::get_system_category()); descriptor_data->op_queue_[j].pop(); ops.push(op); } if (op->perform()) { descriptor_data->op_queue_[j].pop(); ops.push(op); } else break; } } } } // Renew registration for event notifications. struct kevent event; switch (events[i].filter) { case EVFILT_READ: if (!descriptor_data->op_queue_[read_op].empty()) ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); else if (!descriptor_data->op_queue_[except_op].empty()) ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_READ, EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data); else continue; case EVFILT_WRITE: if (!descriptor_data->op_queue_[write_op].empty()) ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, descriptor_data); else continue; default: break; } if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code error(errno, asio::error::get_system_category()); for (int j = 0; j < max_ops; ++j) { while (reactor_op* op = descriptor_data->op_queue_[j].front()) { op->ec_ = error; descriptor_data->op_queue_[j].pop(); ops.push(op); } } } } } lock.lock(); timer_queues_.get_ready_timers(ops); } void kqueue_reactor::interrupt() { struct kevent event; ASIO_KQUEUE_EV_SET(&event, interrupter_.read_descriptor(), EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &interrupter_); ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); } int kqueue_reactor::do_kqueue_create() { int fd = ::kqueue(); if (fd == -1) { asio::error_code ec(errno, asio::error::get_system_category()); asio::detail::throw_error(ec, "kqueue"); } return fd; } void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.insert(&queue); } void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.erase(&queue); } timespec* kqueue_reactor::get_timeout(timespec& ts) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); ts.tv_sec = usec / 1000000; ts.tv_nsec = (usec % 1000000) * 1000; return &ts; } } // namespace detail } // namespace asio #undef ASIO_KQUEUE_EV_SET #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_KQUEUE) #endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/pipe_select_interrupter.ipp000066400000000000000000000045251244131713600265520ustar00rootroot00000000000000// // detail/impl/pipe_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP #define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) #if !defined(__CYGWIN__) #if !defined(__SYMBIAN32__) #if !defined(ASIO_HAS_EVENTFD) #include #include #include #include #include "asio/detail/pipe_select_interrupter.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { pipe_select_interrupter::pipe_select_interrupter() { int pipe_fds[2]; if (pipe(pipe_fds) == 0) { read_descriptor_ = pipe_fds[0]; ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); write_descriptor_ = pipe_fds[1]; ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); } else { asio::error_code ec(errno, asio::error::get_system_category()); asio::detail::throw_error(ec, "pipe_select_interrupter"); } } pipe_select_interrupter::~pipe_select_interrupter() { if (read_descriptor_ != -1) ::close(read_descriptor_); if (write_descriptor_ != -1) ::close(write_descriptor_); } void pipe_select_interrupter::interrupt() { char byte = 0; int result = ::write(write_descriptor_, &byte, 1); (void)result; } bool pipe_select_interrupter::reset() { for (;;) { char data[1024]; int bytes_read = ::read(read_descriptor_, data, sizeof(data)); if (bytes_read < 0 && errno == EINTR) continue; bool was_interrupted = (bytes_read > 0); while (bytes_read == sizeof(data)) bytes_read = ::read(read_descriptor_, data, sizeof(data)); return was_interrupted; } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HAS_EVENTFD) #endif // !defined(__SYMBIAN32__) #endif // !defined(__CYGWIN__) #endif // !defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/posix_event.ipp000066400000000000000000000022231244131713600241470ustar00rootroot00000000000000// // detail/impl/posix_event.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_POSIX_EVENT_IPP #define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include "asio/detail/posix_event.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { posix_event::posix_event() : signalled_(false) { int error = ::pthread_cond_init(&cond_, 0); asio::error_code ec(error, asio::error::get_system_category()); asio::detail::throw_error(ec, "event"); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/posix_mutex.ipp000066400000000000000000000022311244131713600241670ustar00rootroot00000000000000// // detail/impl/posix_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP #define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include "asio/detail/posix_mutex.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { posix_mutex::posix_mutex() { int error = ::pthread_mutex_init(&mutex_, 0); asio::error_code ec(error, asio::error::get_system_category()); asio::detail::throw_error(ec, "mutex"); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/posix_thread.ipp000066400000000000000000000032061244131713600242770ustar00rootroot00000000000000// // detail/impl/posix_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_POSIX_THREAD_IPP #define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include "asio/detail/posix_thread.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { posix_thread::~posix_thread() { if (!joined_) ::pthread_detach(thread_); } void posix_thread::join() { if (!joined_) { ::pthread_join(thread_, 0); joined_ = true; } } void posix_thread::start_thread(func_base* arg) { int error = ::pthread_create(&thread_, 0, asio_detail_posix_thread_function, arg); if (error != 0) { delete arg; asio::error_code ec(error, asio::error::get_system_category()); asio::detail::throw_error(ec, "thread"); } } void* asio_detail_posix_thread_function(void* arg) { posix_thread::auto_func_base_ptr func = { static_cast(arg) }; func.ptr->run(); return 0; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/posix_tss_ptr.ipp000066400000000000000000000022631244131713600245300ustar00rootroot00000000000000// // detail/impl/posix_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP #define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include "asio/detail/posix_tss_ptr.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { void posix_tss_ptr_create(pthread_key_t& key) { int error = ::pthread_key_create(&key, 0); asio::error_code ec(error, asio::error::get_system_category()); asio::detail::throw_error(ec, "tss"); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/reactive_descriptor_service.ipp000066400000000000000000000065621244131713600273760ustar00rootroot00000000000000// // detail/impl/reactive_descriptor_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP #define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include "asio/error.hpp" #include "asio/detail/reactive_descriptor_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { reactive_descriptor_service::reactive_descriptor_service( asio::io_service& io_service) : reactor_(asio::use_service(io_service)) { reactor_.init_task(); } void reactive_descriptor_service::shutdown_service() { } void reactive_descriptor_service::construct( reactive_descriptor_service::implementation_type& impl) { impl.descriptor_ = -1; impl.state_ = 0; } void reactive_descriptor_service::destroy( reactive_descriptor_service::implementation_type& impl) { if (is_open(impl)) reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); asio::error_code ignored_ec; descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); } asio::error_code reactive_descriptor_service::assign( reactive_descriptor_service::implementation_type& impl, const native_type& native_descriptor, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } if (int err = reactor_.register_descriptor( native_descriptor, impl.reactor_data_)) { ec = asio::error_code(err, asio::error::get_system_category()); return ec; } impl.descriptor_ = native_descriptor; impl.state_ = 0; ec = asio::error_code(); return ec; } asio::error_code reactive_descriptor_service::close( reactive_descriptor_service::implementation_type& impl, asio::error_code& ec) { if (is_open(impl)) reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); if (descriptor_ops::close(impl.descriptor_, impl.state_, ec) == 0) construct(impl); return ec; } asio::error_code reactive_descriptor_service::cancel( reactive_descriptor_service::implementation_type& impl, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); ec = asio::error_code(); return ec; } void reactive_descriptor_service::start_op( reactive_descriptor_service::implementation_type& impl, int op_type, reactor_op* op, bool non_blocking, bool noop) { if (!noop) { if ((impl.state_ & descriptor_ops::non_blocking) || descriptor_ops::set_internal_non_blocking( impl.descriptor_, impl.state_, op->ec_)) { reactor_.start_op(op_type, impl.descriptor_, impl.reactor_data_, op, non_blocking); return; } } reactor_.post_immediate_completion(op); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/reactive_serial_port_service.ipp000066400000000000000000000076401244131713600275410ustar00rootroot00000000000000// // detail/impl/reactive_serial_port_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP #define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/reactive_serial_port_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { reactive_serial_port_service::reactive_serial_port_service( asio::io_service& io_service) : descriptor_service_(io_service) { } void reactive_serial_port_service::shutdown_service() { descriptor_service_.shutdown_service(); } asio::error_code reactive_serial_port_service::open( reactive_serial_port_service::implementation_type& impl, const std::string& device, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } descriptor_ops::state_type state = 0; int fd = descriptor_ops::open(device.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY, ec); if (fd < 0) return ec; int s = descriptor_ops::fcntl(fd, F_GETFL, ec); if (s >= 0) s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); if (s < 0) { asio::error_code ignored_ec; descriptor_ops::close(fd, state, ignored_ec); return ec; } // Set up default serial port options. termios ios; errno = 0; s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); if (s >= 0) { #if defined(_BSD_SOURCE) ::cfmakeraw(&ios); #else ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); ios.c_oflag &= ~OPOST; ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); ios.c_cflag &= ~(CSIZE | PARENB); ios.c_cflag |= CS8; #endif ios.c_iflag |= IGNPAR; ios.c_cflag |= CREAD | CLOCAL; errno = 0; s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); } if (s < 0) { asio::error_code ignored_ec; descriptor_ops::close(fd, state, ignored_ec); return ec; } // We're done. Take ownership of the serial port descriptor. if (descriptor_service_.assign(impl, fd, ec)) { asio::error_code ignored_ec; descriptor_ops::close(fd, state, ignored_ec); } return ec; } asio::error_code reactive_serial_port_service::do_set_option( reactive_serial_port_service::implementation_type& impl, reactive_serial_port_service::store_function_type store, const void* option, asio::error_code& ec) { termios ios; errno = 0; descriptor_ops::error_wrapper(::tcgetattr( descriptor_service_.native(impl), &ios), ec); if (ec) return ec; if (store(option, ios, ec)) return ec; errno = 0; descriptor_ops::error_wrapper(::tcsetattr( descriptor_service_.native(impl), TCSANOW, &ios), ec); return ec; } asio::error_code reactive_serial_port_service::do_get_option( const reactive_serial_port_service::implementation_type& impl, reactive_serial_port_service::load_function_type load, void* option, asio::error_code& ec) const { termios ios; errno = 0; descriptor_ops::error_wrapper(::tcgetattr( descriptor_service_.native(impl), &ios), ec); if (ec) return ec; return load(option, ios, ec); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // defined(ASIO_HAS_SERIAL_PORT) #endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/reactive_socket_service_base.ipp000066400000000000000000000126311244131713600274740ustar00rootroot00000000000000// // detail/reactive_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP #define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) #include "asio/detail/reactive_socket_service_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { reactive_socket_service_base::reactive_socket_service_base( asio::io_service& io_service) : reactor_(use_service(io_service)) { reactor_.init_task(); } void reactive_socket_service_base::shutdown_service() { } void reactive_socket_service_base::construct( reactive_socket_service_base::base_implementation_type& impl) { impl.socket_ = invalid_socket; impl.state_ = 0; } void reactive_socket_service_base::destroy( reactive_socket_service_base::base_implementation_type& impl) { if (impl.socket_ != invalid_socket) { reactor_.close_descriptor(impl.socket_, impl.reactor_data_); asio::error_code ignored_ec; socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); } } asio::error_code reactive_socket_service_base::close( reactive_socket_service_base::base_implementation_type& impl, asio::error_code& ec) { if (is_open(impl)) reactor_.close_descriptor(impl.socket_, impl.reactor_data_); if (socket_ops::close(impl.socket_, impl.state_, true, ec) == 0) construct(impl); return ec; } asio::error_code reactive_socket_service_base::cancel( reactive_socket_service_base::base_implementation_type& impl, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } reactor_.cancel_ops(impl.socket_, impl.reactor_data_); ec = asio::error_code(); return ec; } asio::error_code reactive_socket_service_base::do_open( reactive_socket_service_base::base_implementation_type& impl, int af, int type, int protocol, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } socket_holder sock(socket_ops::socket(af, type, protocol, ec)); if (sock.get() == invalid_socket) return ec; if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) { ec = asio::error_code(err, asio::error::get_system_category()); return ec; } impl.socket_ = sock.release(); switch (type) { case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; default: impl.state_ = 0; break; } ec = asio::error_code(); return ec; } asio::error_code reactive_socket_service_base::do_assign( reactive_socket_service_base::base_implementation_type& impl, int type, const reactive_socket_service_base::native_type& native_socket, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } if (int err = reactor_.register_descriptor( native_socket, impl.reactor_data_)) { ec = asio::error_code(err, asio::error::get_system_category()); return ec; } impl.socket_ = native_socket; switch (type) { case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; default: impl.state_ = 0; break; } ec = asio::error_code(); return ec; } void reactive_socket_service_base::start_op( reactive_socket_service_base::base_implementation_type& impl, int op_type, reactor_op* op, bool non_blocking, bool noop) { if (!noop) { if ((impl.state_ & socket_ops::non_blocking) || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, op->ec_)) { reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op, non_blocking); return; } } reactor_.post_immediate_completion(op); } void reactive_socket_service_base::start_accept_op( reactive_socket_service_base::base_implementation_type& impl, reactor_op* op, bool peer_is_open) { if (!peer_is_open) start_op(impl, reactor::read_op, op, true, false); else { op->ec_ = asio::error::already_open; reactor_.post_immediate_completion(op); } } void reactive_socket_service_base::start_connect_op( reactive_socket_service_base::base_implementation_type& impl, reactor_op* op, const socket_addr_type* addr, size_t addrlen) { if ((impl.state_ & socket_ops::non_blocking) || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, op->ec_)) { if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) { if (op->ec_ == asio::error::in_progress || op->ec_ == asio::error::would_block) { op->ec_ = asio::error_code(); reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_, op, false); return; } } } reactor_.post_immediate_completion(op); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/resolver_service_base.ipp000066400000000000000000000050451244131713600261640ustar00rootroot00000000000000// // detail/impl/resolver_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP #define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/resolver_service_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class resolver_service_base::work_io_service_runner { public: work_io_service_runner(asio::io_service& io_service) : io_service_(io_service) {} void operator()() { io_service_.run(); } private: asio::io_service& io_service_; }; resolver_service_base::resolver_service_base( asio::io_service& io_service) : io_service_impl_(asio::use_service(io_service)), work_io_service_(new asio::io_service), work_io_service_impl_(asio::use_service< io_service_impl>(*work_io_service_)), work_(new asio::io_service::work(*work_io_service_)), work_thread_(0) { } resolver_service_base::~resolver_service_base() { shutdown_service(); } void resolver_service_base::shutdown_service() { work_.reset(); if (work_io_service_) { work_io_service_->stop(); if (work_thread_) { work_thread_->join(); work_thread_.reset(); } work_io_service_.reset(); } } void resolver_service_base::construct( resolver_service_base::implementation_type& impl) { impl.reset(static_cast(0), socket_ops::noop_deleter()); } void resolver_service_base::destroy( resolver_service_base::implementation_type&) { } void resolver_service_base::cancel( resolver_service_base::implementation_type& impl) { impl.reset(static_cast(0), socket_ops::noop_deleter()); } void resolver_service_base::start_resolve_op(operation* op) { start_work_thread(); io_service_impl_.work_started(); work_io_service_impl_.post_immediate_completion(op); } void resolver_service_base::start_work_thread() { asio::detail::mutex::scoped_lock lock(mutex_); if (!work_thread_) { work_thread_.reset(new asio::detail::thread( work_io_service_runner(*work_io_service_))); } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/select_reactor.hpp000066400000000000000000000043131244131713600246030ustar00rootroot00000000000000// // detail/impl/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP #define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) \ || (!defined(ASIO_HAS_DEV_POLL) \ && !defined(ASIO_HAS_EPOLL) \ && !defined(ASIO_HAS_KQUEUE)) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void select_reactor::add_timer_queue(timer_queue& queue) { do_add_timer_queue(queue); } // Remove a timer queue from the reactor. template void select_reactor::remove_timer_queue(timer_queue& queue) { do_remove_timer_queue(queue); } template void select_reactor::schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { io_service_.post_immediate_completion(op); return; } bool earliest = queue.enqueue_timer(time, timer, op); io_service_.work_started(); if (earliest) interrupter_.interrupt(); } template std::size_t select_reactor::cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer) { asio::detail::mutex::scoped_lock lock(mutex_); op_queue ops; std::size_t n = queue.cancel_timer(timer, ops); lock.unlock(); io_service_.post_deferred_completions(ops); return n; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) // || (!defined(ASIO_HAS_DEV_POLL) // && !defined(ASIO_HAS_EPOLL) // && !defined(ASIO_HAS_KQUEUE)) #endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/select_reactor.ipp000066400000000000000000000165721244131713600246160ustar00rootroot00000000000000// // detail/impl/select_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP #define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) \ || (!defined(ASIO_HAS_DEV_POLL) \ && !defined(ASIO_HAS_EPOLL) \ && !defined(ASIO_HAS_KQUEUE)) #include "asio/detail/bind_handler.hpp" #include "asio/detail/fd_set_adapter.hpp" #include "asio/detail/select_reactor.hpp" #include "asio/detail/signal_blocker.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { select_reactor::select_reactor(asio::io_service& io_service) : asio::detail::service_base(io_service), io_service_(use_service(io_service)), mutex_(), interrupter_(), #if defined(ASIO_HAS_IOCP) stop_thread_(false), thread_(0), #endif // defined(ASIO_HAS_IOCP) shutdown_(false) { #if defined(ASIO_HAS_IOCP) asio::detail::signal_blocker sb; thread_ = new asio::detail::thread( bind_handler(&select_reactor::call_run_thread, this)); #endif // defined(ASIO_HAS_IOCP) } select_reactor::~select_reactor() { shutdown_service(); } void select_reactor::shutdown_service() { asio::detail::mutex::scoped_lock lock(mutex_); shutdown_ = true; #if defined(ASIO_HAS_IOCP) stop_thread_ = true; #endif // defined(ASIO_HAS_IOCP) lock.unlock(); #if defined(ASIO_HAS_IOCP) if (thread_) { interrupter_.interrupt(); thread_->join(); delete thread_; thread_ = 0; } #endif // defined(ASIO_HAS_IOCP) op_queue ops; for (int i = 0; i < max_ops; ++i) op_queue_[i].get_all_operations(ops); timer_queues_.get_all_timers(ops); } void select_reactor::init_task() { io_service_.init_task(); } int select_reactor::register_descriptor(socket_type, select_reactor::per_descriptor_data&) { return 0; } void select_reactor::start_op(int op_type, socket_type descriptor, select_reactor::per_descriptor_data&, reactor_op* op, bool) { asio::detail::mutex::scoped_lock lock(mutex_); if (shutdown_) { post_immediate_completion(op); return; } bool first = op_queue_[op_type].enqueue_operation(descriptor, op); io_service_.work_started(); if (first) interrupter_.interrupt(); } void select_reactor::cancel_ops(socket_type descriptor, select_reactor::per_descriptor_data&) { asio::detail::mutex::scoped_lock lock(mutex_); cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } void select_reactor::close_descriptor(socket_type descriptor, select_reactor::per_descriptor_data&) { asio::detail::mutex::scoped_lock lock(mutex_); cancel_ops_unlocked(descriptor, asio::error::operation_aborted); } void select_reactor::run(bool block, op_queue& ops) { asio::detail::mutex::scoped_lock lock(mutex_); #if defined(ASIO_HAS_IOCP) // Check if the thread is supposed to stop. if (stop_thread_) return; #endif // defined(ASIO_HAS_IOCP) // Set up the descriptor sets. fd_set_adapter fds[max_select_ops]; fds[read_op].set(interrupter_.read_descriptor()); socket_type max_fd = 0; bool have_work_to_do = !timer_queues_.all_empty(); for (int i = 0; i < max_select_ops; ++i) { have_work_to_do = have_work_to_do || !op_queue_[i].empty(); op_queue_[i].get_descriptors(fds[i], ops); if (fds[i].max_descriptor() > max_fd) max_fd = fds[i].max_descriptor(); } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Connection operations on Windows use both except and write fd_sets. have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); op_queue_[connect_op].get_descriptors(fds[write_op], ops); if (fds[write_op].max_descriptor() > max_fd) max_fd = fds[write_op].max_descriptor(); op_queue_[connect_op].get_descriptors(fds[except_op], ops); if (fds[except_op].max_descriptor() > max_fd) max_fd = fds[except_op].max_descriptor(); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // We can return immediately if there's no work to do and the reactor is // not supposed to block. if (!block && !have_work_to_do) return; // Determine how long to block while waiting for events. timeval tv_buf = { 0, 0 }; timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; lock.unlock(); // Block on the select call until descriptors become ready. asio::error_code ec; int retval = socket_ops::select(static_cast(max_fd + 1), fds[read_op], fds[write_op], fds[except_op], tv, ec); // Reset the interrupter. if (retval > 0 && fds[read_op].is_set(interrupter_.read_descriptor())) interrupter_.reset(); lock.lock(); // Dispatch all ready operations. if (retval > 0) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Connection operations on Windows use both except and write fd_sets. op_queue_[connect_op].perform_operations_for_descriptors( fds[except_op], ops); op_queue_[connect_op].perform_operations_for_descriptors( fds[write_op], ops); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. for (int i = max_select_ops - 1; i >= 0; --i) op_queue_[i].perform_operations_for_descriptors(fds[i], ops); } timer_queues_.get_ready_timers(ops); } void select_reactor::interrupt() { interrupter_.interrupt(); } #if defined(ASIO_HAS_IOCP) void select_reactor::run_thread() { asio::detail::mutex::scoped_lock lock(mutex_); while (!stop_thread_) { lock.unlock(); op_queue ops; run(true, ops); io_service_.post_deferred_completions(ops); lock.lock(); } } void select_reactor::call_run_thread(select_reactor* reactor) { reactor->run_thread(); } #endif // defined(ASIO_HAS_IOCP) void select_reactor::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.insert(&queue); } void select_reactor::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(mutex_); timer_queues_.erase(&queue); } timeval* select_reactor::get_timeout(timeval& tv) { // By default we will wait no longer than 5 minutes. This will ensure that // any changes to the system clock are detected after no longer than this. long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); tv.tv_sec = usec / 1000000; tv.tv_usec = usec % 1000000; return &tv; } void select_reactor::cancel_ops_unlocked(socket_type descriptor, const asio::error_code& ec) { bool need_interrupt = false; op_queue ops; for (int i = 0; i < max_ops; ++i) need_interrupt = op_queue_[i].cancel_operations( descriptor, ops, ec) || need_interrupt; io_service_.post_deferred_completions(ops); if (need_interrupt) interrupter_.interrupt(); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) // || (!defined(ASIO_HAS_DEV_POLL) // && !defined(ASIO_HAS_EPOLL) // && !defined(ASIO_HAS_KQUEUE)) #endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/service_registry.hpp000066400000000000000000000034101244131713600251720ustar00rootroot00000000000000// // detail/impl/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP #define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template Service& service_registry::use_service() { asio::io_service::service::key key; init_key(key, Service::id); factory_type factory = &service_registry::create; return *static_cast(do_use_service(key, factory)); } template void service_registry::add_service(Service* new_service) { asio::io_service::service::key key; init_key(key, Service::id); return do_add_service(key, new_service); } template bool service_registry::has_service() const { asio::io_service::service::key key; init_key(key, Service::id); return do_has_service(key); } #if !defined(ASIO_NO_TYPEID) template void service_registry::init_key(asio::io_service::service::key& key, const asio::detail::service_id& /*id*/) { key.type_info_ = &typeid(typeid_wrapper); key.id_ = 0; } #endif // !defined(ASIO_NO_TYPEID) template asio::io_service::service* service_registry::create( asio::io_service& owner) { return new Service(owner); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/service_registry.ipp000066400000000000000000000103561244131713600252020ustar00rootroot00000000000000// // detail/impl/service_registry.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP #define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/service_registry.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { service_registry::service_registry(asio::io_service& o) : owner_(o), first_service_(0) { } service_registry::~service_registry() { // Shutdown all services. This must be done in a separate loop before the // services are destroyed since the destructors of user-defined handler // objects may try to access other service objects. asio::io_service::service* service = first_service_; while (service) { service->shutdown_service(); service = service->next_; } // Destroy all services. while (first_service_) { asio::io_service::service* next_service = first_service_->next_; destroy(first_service_); first_service_ = next_service; } } void service_registry::init_key(asio::io_service::service::key& key, const asio::io_service::id& id) { key.type_info_ = 0; key.id_ = &id; } bool service_registry::keys_match( const asio::io_service::service::key& key1, const asio::io_service::service::key& key2) { if (key1.id_ && key2.id_) if (key1.id_ == key2.id_) return true; if (key1.type_info_ && key2.type_info_) if (*key1.type_info_ == *key2.type_info_) return true; return false; } void service_registry::destroy(asio::io_service::service* service) { delete service; } asio::io_service::service* service_registry::do_use_service( const asio::io_service::service::key& key, factory_type factory) { asio::detail::mutex::scoped_lock lock(mutex_); // First see if there is an existing service object with the given key. asio::io_service::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) return service; service = service->next_; } // Create a new service object. The service registry's mutex is not locked // at this time to allow for nested calls into this function from the new // service's constructor. lock.unlock(); auto_service_ptr new_service = { factory(owner_) }; new_service.ptr_->key_ = key; lock.lock(); // Check that nobody else created another service object of the same type // while the lock was released. service = first_service_; while (service) { if (keys_match(service->key_, key)) return service; service = service->next_; } // Service was successfully initialised, pass ownership to registry. new_service.ptr_->next_ = first_service_; first_service_ = new_service.ptr_; new_service.ptr_ = 0; return first_service_; } void service_registry::do_add_service( const asio::io_service::service::key& key, asio::io_service::service* new_service) { if (&owner_ != &new_service->io_service()) boost::throw_exception(invalid_service_owner()); asio::detail::mutex::scoped_lock lock(mutex_); // Check if there is an existing service object with the given key. asio::io_service::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) boost::throw_exception(service_already_exists()); service = service->next_; } // Take ownership of the service object. new_service->key_ = key; new_service->next_ = first_service_; first_service_ = new_service; } bool service_registry::do_has_service( const asio::io_service::service::key& key) const { asio::detail::mutex::scoped_lock lock(mutex_); asio::io_service::service* service = first_service_; while (service) { if (keys_match(service->key_, key)) return true; service = service->next_; } return false; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/socket_ops.ipp000066400000000000000000002305111244131713600237600ustar00rootroot00000000000000// // detail/impl/socket_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_OPS_IPP #define ASIO_DETAIL_SOCKET_OPS_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include #include #include #include "asio/detail/socket_ops.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace socket_ops { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) struct msghdr { int msg_namelen; }; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(__hpux) // HP-UX doesn't declare these functions extern "C", so they are declared again // here to avoid linker errors about undefined symbols. extern "C" char* if_indextoname(unsigned int, char*); extern "C" unsigned int if_nametoindex(const char*); #endif // defined(__hpux) inline void clear_last_error() { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) WSASetLastError(0); #else errno = 0; #endif } template inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = asio::error_code(WSAGetLastError(), asio::error::get_system_category()); #else ec = asio::error_code(errno, asio::error::get_system_category()); #endif return return_value; } template inline socket_type call_accept(SockLenType msghdr::*, socket_type s, socket_addr_type* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); if (addrlen) *addrlen = (std::size_t)tmp_addrlen; return result; } socket_type accept(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return invalid_socket; } clear_last_error(); socket_type new_s = error_wrapper(call_accept( &msghdr::msg_namelen, s, addr, addrlen), ec); if (new_s == invalid_socket) return new_s; #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; int result = error_wrapper(::setsockopt(new_s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); if (result != 0) { ::close(new_s); return invalid_socket; } #endif ec = asio::error_code(); return new_s; } socket_type sync_accept(socket_type s, state_type state, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { // Accept a socket. for (;;) { // Try to complete the operation without blocking. socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); // Check if operation succeeded. if (new_socket != invalid_socket) return new_socket; // Operation failed. if (ec == asio::error::would_block || ec == asio::error::try_again) { if (state & user_set_non_blocking) return invalid_socket; // Fall through to retry operation. } else if (ec == asio::error::connection_aborted) { if (state & enable_connection_aborted) return invalid_socket; // Fall through to retry operation. } #if defined(EPROTO) else if (ec.value() == EPROTO) { if (state & enable_connection_aborted) return invalid_socket; // Fall through to retry operation. } #endif // defined(EPROTO) else return invalid_socket; // Wait for socket to become ready. if (socket_ops::poll_read(s, ec) < 0) return invalid_socket; } } #if defined(ASIO_HAS_IOCP) void complete_iocp_accept(socket_type s, void* output_buffer, DWORD address_length, socket_addr_type* addr, std::size_t* addrlen, socket_type new_socket, asio::error_code& ec) { // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_aborted; if (!ec) { // Get the address of the peer. if (addr && addrlen) { LPSOCKADDR local_addr = 0; int local_addr_length = 0; LPSOCKADDR remote_addr = 0; int remote_addr_length = 0; GetAcceptExSockaddrs(output_buffer, 0, address_length, address_length, &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); if (static_cast(remote_addr_length) > *addrlen) { ec = asio::error::invalid_argument; } else { using namespace std; // For memcpy. memcpy(addr, remote_addr, remote_addr_length); *addrlen = static_cast(remote_addr_length); } } // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname // and getpeername will work on the accepted socket. SOCKET update_ctx_param = s; socket_ops::state_type state = 0; socket_ops::setsockopt(new_socket, state, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, &update_ctx_param, sizeof(SOCKET), ec); } } #else // defined(ASIO_HAS_IOCP) bool non_blocking_accept(socket_type s, state_type state, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec, socket_type& new_socket) { for (;;) { // Accept the waiting connection. new_socket = socket_ops::accept(s, addr, addrlen, ec); // Check if operation succeeded. if (new_socket != invalid_socket) return true; // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Operation failed. if (ec == asio::error::would_block || ec == asio::error::try_again) { if (state & user_set_non_blocking) return true; // Fall through to retry operation. } else if (ec == asio::error::connection_aborted) { if (state & enable_connection_aborted) return true; // Fall through to retry operation. } #if defined(EPROTO) else if (ec.value() == EPROTO) { if (state & enable_connection_aborted) return true; // Fall through to retry operation. } #endif // defined(EPROTO) else return true; return false; } } #endif // defined(ASIO_HAS_IOCP) template inline int call_bind(SockLenType msghdr::*, socket_type s, const socket_addr_type* addr, std::size_t addrlen) { return ::bind(s, addr, (SockLenType)addrlen); } int bind(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); int result = error_wrapper(call_bind( &msghdr::msg_namelen, s, addr, addrlen), ec); if (result == 0) ec = asio::error_code(); return result; } int close(socket_type s, state_type& state, bool destruction, asio::error_code& ec) { int result = 0; if (s != invalid_socket) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if ((state & non_blocking) && (state & user_set_linger)) { ioctl_arg_type arg = 0; ::ioctlsocket(s, FIONBIO, &arg); state &= ~non_blocking; } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (state & non_blocking) { #if defined(__SYMBIAN32__) int flags = ::fcntl(s, F_GETFL, 0); if (flags >= 0) ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); #else // defined(__SYMBIAN32__) ioctl_arg_type arg = 0; ::ioctl(s, FIONBIO, &arg); #endif // defined(__SYMBIAN32__) state &= ~non_blocking; } #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (destruction && (state & user_set_linger)) { ::linger opt; opt.l_onoff = 0; opt.l_linger = 0; asio::error_code ignored_ec; socket_ops::setsockopt(s, state, SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); } clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) result = error_wrapper(::closesocket(s), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) result = error_wrapper(::close(s), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } if (result == 0) ec = asio::error_code(); return result; } bool set_internal_non_blocking(socket_type s, state_type& state, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return false; } clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = 1; int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); #elif defined(__SYMBIAN32__) int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); if (result >= 0) { clear_last_error(); result = error_wrapper(::fcntl(s, F_SETFL, result | O_NONBLOCK), ec); } #else ioctl_arg_type arg = 1; int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); #endif if (result >= 0) { ec = asio::error_code(); state |= internal_non_blocking; return true; } return false; } int shutdown(socket_type s, int what, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); int result = error_wrapper(::shutdown(s, what), ec); if (result == 0) ec = asio::error_code(); return result; } template inline int call_connect(SockLenType msghdr::*, socket_type s, const socket_addr_type* addr, std::size_t addrlen) { return ::connect(s, addr, (SockLenType)addrlen); } int connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); int result = error_wrapper(call_connect( &msghdr::msg_namelen, s, addr, addrlen), ec); if (result == 0) ec = asio::error_code(); return result; } void sync_connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { // Perform the connect operation. socket_ops::connect(s, addr, addrlen, ec); if (ec != asio::error::in_progress && ec != asio::error::would_block) { // The connect operation finished immediately. return; } // Wait for socket to become ready. if (socket_ops::poll_connect(s, ec) < 0) return; // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec) == socket_error_retval) return; // Return the result of the connect operation. ec = asio::error_code(connect_error, asio::error::get_system_category()); } bool non_blocking_connect(socket_type s, asio::error_code& ec) { // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec) == 0) { if (connect_error) { ec = asio::error_code(connect_error, asio::error::get_system_category()); } else ec = asio::error_code(); } return true; } int socketpair(int af, int type, int protocol, socket_type sv[2], asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(af); (void)(type); (void)(protocol); (void)(sv); ec = asio::error::operation_not_supported; return socket_error_retval; #else clear_last_error(); int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); if (result == 0) ec = asio::error_code(); return result; #endif } bool sockatmark(socket_type s, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return false; } #if defined(SIOCATMARK) ioctl_arg_type value = 0; # if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); # else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); # endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (result == 0) ec = asio::error_code(); # if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; # endif // defined(ENOTTY) #else // defined(SIOCATMARK) int value = error_wrapper(::sockatmark(s), ec); if (value != -1) ec = asio::error_code(); #endif // defined(SIOCATMARK) return ec ? false : value != 0; } size_t available(socket_type s, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return 0; } ioctl_arg_type value = 0; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (result == 0) ec = asio::error_code(); #if defined(ENOTTY) if (ec.value() == ENOTTY) ec = asio::error::not_socket; #endif // defined(ENOTTY) return ec ? static_cast(0) : static_cast(value); } int listen(socket_type s, int backlog, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); int result = error_wrapper(::listen(s, backlog), ec); if (result == 0) ec = asio::error_code(); return result; } inline void init_buf_iov_base(void*& base, void* addr) { base = addr; } template inline void init_buf_iov_base(T& base, void* addr) { base = static_cast(addr); } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec buf; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) void init_buf(buf& b, void* data, size_t size) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) b.buf = static_cast(data); b.len = static_cast(size); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) init_buf_iov_base(b.iov_base, data); b.iov_len = size; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } void init_buf(buf& b, const void* data, size_t size) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) b.buf = static_cast(const_cast(data)); b.len = static_cast(size); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) init_buf_iov_base(b.iov_base, const_cast(data)); b.iov_len = size; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) { name = addr; } inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) { name = const_cast(addr); } template inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) { name = reinterpret_cast(addr); } template inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) { name = reinterpret_cast(const_cast(addr)); } int recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = error_wrapper(::WSARecv(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; ec = asio::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = count; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } size_t sync_recv(socket_type s, state_type state, buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return 0; } // A request to read 0 bytes on a stream is a no-op. if (all_empty && (state & stream_oriented)) { ec = asio::error_code(); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. int bytes = socket_ops::recv(s, bufs, count, flags, ec); // Check if operation succeeded. if (bytes > 0) return bytes; // Check for EOF. if ((state & stream_oriented) && bytes == 0) { ec = asio::error::eof; return 0; } // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for socket to become ready. if (socket_ops::poll_read(s, ec) < 0) return 0; } } #if defined(ASIO_HAS_IOCP) void complete_iocp_recv(state_type state, const weak_cancel_token_type& cancel_token, bool all_empty, asio::error_code& ec, size_t bytes_transferred) { // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_NETNAME_DELETED) { if (cancel_token.expired()) ec = asio::error::operation_aborted; else ec = asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; } // Check for connection closed. else if (!ec && bytes_transferred == 0 && (state & stream_oriented) != 0 && !all_empty) { ec = asio::error::eof; } } #else // defined(ASIO_HAS_IOCP) bool non_blocking_recv(socket_type s, buf* bufs, size_t count, int flags, bool is_stream, asio::error_code& ec, size_t& bytes_transferred) { for (;;) { // Read some data. int bytes = socket_ops::recv(s, bufs, count, flags, ec); // Check for end of stream. if (is_stream && bytes == 0) { ec = asio::error::eof; return true; } // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes >= 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } #endif // defined(ASIO_HAS_IOCP) int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); *addrlen = (std::size_t)tmp_addrlen; if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; ec = asio::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = *addrlen; msg.msg_iov = bufs; msg.msg_iovlen = count; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); // Check if operation succeeded. if (bytes >= 0) return bytes; // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for socket to become ready. if (socket_ops::poll_read(s, ec) < 0) return 0; } } #if defined(ASIO_HAS_IOCP) void complete_iocp_recvfrom( const weak_cancel_token_type& cancel_token, asio::error_code& ec) { // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_NETNAME_DELETED) { if (cancel_token.expired()) ec = asio::error::operation_aborted; else ec = asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; } } #else // defined(ASIO_HAS_IOCP) bool non_blocking_recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec, size_t& bytes_transferred) { for (;;) { // Read some data. int bytes = socket_ops::recvfrom(s, bufs, count, flags, addr, addrlen, ec); // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes >= 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } #endif // defined(ASIO_HAS_IOCP) int send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; int result = error_wrapper(::WSASend(s, const_cast(bufs), send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; ec = asio::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) int result = error_wrapper(::sendmsg(s, &msg, flags), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } size_t sync_send(socket_type s, state_type state, const buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return 0; } // A request to write 0 bytes to a stream is a no-op. if (all_empty && (state & stream_oriented)) { ec = asio::error_code(); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. int bytes = socket_ops::send(s, bufs, count, flags, ec); // Check if operation succeeded. if (bytes >= 0) return bytes; // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for socket to become ready. if (socket_ops::poll_write(s, ec) < 0) return 0; } } #if defined(ASIO_HAS_IOCP) void complete_iocp_send( const weak_cancel_token_type& cancel_token, asio::error_code& ec) { // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_NETNAME_DELETED) { if (cancel_token.expired()) ec = asio::error::operation_aborted; else ec = asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; } } #else // defined(ASIO_HAS_IOCP) bool non_blocking_send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec, size_t& bytes_transferred) { for (;;) { // Write some data. int bytes = socket_ops::send(s, bufs, count, flags, ec); // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes >= 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } #endif // defined(ASIO_HAS_IOCP) int sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; int result = error_wrapper(::WSASendTo(s, const_cast(bufs), send_buf_count, &bytes_transferred, flags, addr, static_cast(addrlen), 0, 0), ec); if (ec.value() == ERROR_NETNAME_DELETED) ec = asio::error::connection_reset; else if (ec.value() == ERROR_PORT_UNREACHABLE) ec = asio::error::connection_refused; if (result != 0) return socket_error_retval; ec = asio::error_code(); return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = addrlen; msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) int result = error_wrapper(::sendmsg(s, &msg, flags), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } size_t sync_sendto(socket_type s, state_type state, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return 0; } // Write some data. for (;;) { // Try to complete the operation without blocking. int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); // Check if operation succeeded. if (bytes >= 0) return bytes; // Operation failed. if ((state & user_set_non_blocking) || (ec != asio::error::would_block && ec != asio::error::try_again)) return 0; // Wait for socket to become ready. if (socket_ops::poll_write(s, ec) < 0) return 0; } } #if !defined(ASIO_HAS_IOCP) bool non_blocking_sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec, size_t& bytes_transferred) { for (;;) { // Write some data. int bytes = socket_ops::sendto(s, bufs, count, flags, addr, addrlen, ec); // Retry operation if interrupted by signal. if (ec == asio::error::interrupted) continue; // Check if we need to run the operation again. if (ec == asio::error::would_block || ec == asio::error::try_again) return false; // Operation is complete. if (bytes >= 0) { ec = asio::error_code(); bytes_transferred = bytes; } else bytes_transferred = 0; return true; } } #endif // !defined(ASIO_HAS_IOCP) socket_type socket(int af, int type, int protocol, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED), ec); if (s == invalid_socket) return s; if (af == AF_INET6) { // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to // false. This will only succeed on Windows Vista and later versions of // Windows, where a dual-stack IPv4/v6 implementation is available. DWORD optval = 0; ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&optval), sizeof(optval)); } ec = asio::error_code(); return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) socket_type s = error_wrapper(::socket(af, type, protocol), ec); if (s == invalid_socket) return s; int optval = 1; int result = error_wrapper(::setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); if (result != 0) { ::close(s); return invalid_socket; } return s; #else int s = error_wrapper(::socket(af, type, protocol), ec); if (s >= 0) ec = asio::error_code(); return s; #endif } template inline int call_setsockopt(SockLenType msghdr::*, socket_type s, int level, int optname, const void* optval, std::size_t optlen) { return ::setsockopt(s, level, optname, (const char*)optval, (SockLenType)optlen); } int setsockopt(socket_type s, state_type& state, int level, int optname, const void* optval, std::size_t optlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } if (level == custom_socket_option_level && optname == always_fail_option) { ec = asio::error::invalid_argument; return socket_error_retval; } if (level == custom_socket_option_level && optname == enable_connection_aborted_option) { if (optlen != sizeof(int)) { ec = asio::error::invalid_argument; return socket_error_retval; } if (*static_cast(optval)) state |= enable_connection_aborted; else state &= ~enable_connection_aborted; ec = asio::error_code(); return 0; } if (level == SOL_SOCKET && optname == SO_LINGER) state |= user_set_linger; #if defined(__BORLANDC__) // Mysteriously, using the getsockopt and setsockopt functions directly with // Borland C++ results in incorrect values being set and read. The bug can be // worked around by using function addresses resolved with GetProcAddress. if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) { clear_last_error(); return error_wrapper(sso(s, level, optname, reinterpret_cast(optval), static_cast(optlen)), ec); } } ec = asio::error::fault; return socket_error_retval; #else // defined(__BORLANDC__) clear_last_error(); int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec); if (result == 0) { ec = asio::error_code(); #if defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) // To implement portable behaviour for SO_REUSEADDR with UDP sockets we // need to also set SO_REUSEPORT on BSD-based platforms. if ((state & datagram_oriented) && level == SOL_SOCKET && optname == SO_REUSEADDR) { call_setsockopt(&msghdr::msg_namelen, s, SOL_SOCKET, SO_REUSEPORT, optval, optlen); } #endif } return result; #endif // defined(__BORLANDC__) } template inline int call_getsockopt(SockLenType msghdr::*, socket_type s, int level, int optname, void* optval, std::size_t* optlen) { SockLenType tmp_optlen = (SockLenType)*optlen; int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); *optlen = (std::size_t)tmp_optlen; return result; } int getsockopt(socket_type s, state_type state, int level, int optname, void* optval, size_t* optlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } if (level == custom_socket_option_level && optname == always_fail_option) { ec = asio::error::invalid_argument; return socket_error_retval; } if (level == custom_socket_option_level && optname == enable_connection_aborted_option) { if (*optlen != sizeof(int)) { ec = asio::error::invalid_argument; return socket_error_retval; } *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; ec = asio::error_code(); return 0; } #if defined(__BORLANDC__) // Mysteriously, using the getsockopt and setsockopt functions directly with // Borland C++ results in incorrect values being set and read. The bug can be // worked around by using function addresses resolved with GetProcAddress. if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) { clear_last_error(); int tmp_optlen = static_cast(*optlen); int result = error_wrapper(gso(s, level, optname, reinterpret_cast(optval), &tmp_optlen), ec); *optlen = static_cast(tmp_optlen); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are // only supported on Windows Vista and later. To simplify program logic // we will fake success of getting this option and specify that the // value is non-zero (i.e. true). This corresponds to the behavior of // IPv6 sockets on Windows platforms pre-Vista. *static_cast(optval) = 1; ec = asio::error_code(); } return result; } } ec = asio::error::fault; return socket_error_retval; #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_last_error(); int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only // supported on Windows Vista and later. To simplify program logic we will // fake success of getting this option and specify that the value is // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets // on Windows platforms pre-Vista. *static_cast(optval) = 1; ec = asio::error_code(); } if (result == 0) ec = asio::error_code(); return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_last_error(); int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) { // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel // to set the buffer size to N*2. Linux puts additional stuff into the // buffers so that only about half is actually available to the application. // The retrieved value is divided by 2 here to make it appear as though the // correct value has been set. *static_cast(optval) /= 2; } #endif // defined(__linux__) if (result == 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } template inline int call_getpeername(SockLenType msghdr::*, socket_type s, socket_addr_type* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = (SockLenType)*addrlen; int result = ::getpeername(s, addr, &tmp_addrlen); *addrlen = (std::size_t)tmp_addrlen; return result; } int getpeername(socket_type s, socket_addr_type* addr, std::size_t* addrlen, bool cached, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (cached) { // Check if socket is still connected. DWORD connect_time = 0; size_t connect_time_len = sizeof(connect_time); if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, &connect_time, &connect_time_len, ec) == socket_error_retval) { return socket_error_retval; } if (connect_time == 0xFFFFFFFF) { ec = asio::error::not_connected; return socket_error_retval; } // The cached value is still valid. ec = asio::error_code(); return 0; } #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)cached; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_last_error(); int result = error_wrapper(call_getpeername( &msghdr::msg_namelen, s, addr, addrlen), ec); if (result == 0) ec = asio::error_code(); return result; } template inline int call_getsockname(SockLenType msghdr::*, socket_type s, socket_addr_type* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = (SockLenType)*addrlen; int result = ::getsockname(s, addr, &tmp_addrlen); *addrlen = (std::size_t)tmp_addrlen; return result; } int getsockname(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); int result = error_wrapper(call_getsockname( &msghdr::msg_namelen, s, addr, addrlen), ec); if (result == 0) ec = asio::error_code(); return result; } int ioctl(socket_type s, state_type& state, int cmd, ioctl_arg_type* arg, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) int result = error_wrapper(::ioctl(s, static_cast(cmd), arg), ec); #else int result = error_wrapper(::ioctl(s, cmd, arg), ec); #endif if (result >= 0) { ec = asio::error_code(); // When updating the non-blocking mode we always perform the ioctl syscall, // even if the flags would otherwise indicate that the socket is already in // the correct state. This ensures that the underlying socket is put into // the state that has been requested by the user. If the ioctl syscall was // successful then we need to update the flags to match. if (cmd == static_cast(FIONBIO)) { if (*arg) { state |= user_set_non_blocking; } else { // Clearing the non-blocking mode always overrides any internally-set // non-blocking flag. Any subsequent asynchronous operations will need // to re-enable non-blocking I/O. state &= ~(user_set_non_blocking | internal_non_blocking); } } } return result; } int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (!readfds && !writefds && !exceptfds && timeout) { DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; if (milliseconds == 0) milliseconds = 1; // Force context switch. ::Sleep(milliseconds); ec = asio::error_code(); return 0; } // The select() call allows timeout values measured in microseconds, but the // system clock (as wrapped by boost::posix_time::microsec_clock) typically // has a resolution of 10 milliseconds. This can lead to a spinning select // reactor, meaning increased CPU usage, when waiting for the earliest // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight // spin we'll use a minimum timeout of 1 millisecond. if (timeout && timeout->tv_sec == 0 && timeout->tv_usec > 0 && timeout->tv_usec < 1000) timeout->tv_usec = 1000; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(__hpux) && defined(__SELECT) timespec ts; ts.tv_sec = timeout ? timeout->tv_sec : 0; ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; return error_wrapper(::pselect(nfds, readfds, writefds, exceptfds, timeout ? &ts : 0, 0), ec); #else int result = error_wrapper(::select(nfds, readfds, writefds, exceptfds, timeout), ec); if (result >= 0) ec = asio::error_code(); return result; #endif } int poll_read(socket_type s, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } #if defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) fd_set fds; FD_ZERO(&fds); FD_SET(s, &fds); clear_last_error(); int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); if (result >= 0) ec = asio::error_code(); return result; #else // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) pollfd fds; fds.fd = s; fds.events = POLLIN; fds.revents = 0; clear_last_error(); int result = error_wrapper(::poll(&fds, 1, -1), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) } int poll_write(socket_type s, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } #if defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) fd_set fds; FD_ZERO(&fds); FD_SET(s, &fds); clear_last_error(); int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); if (result >= 0) ec = asio::error_code(); return result; #else // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) pollfd fds; fds.fd = s; fds.events = POLLOUT; fds.revents = 0; clear_last_error(); int result = error_wrapper(::poll(&fds, 1, -1), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) } int poll_connect(socket_type s, asio::error_code& ec) { if (s == invalid_socket) { ec = asio::error::bad_descriptor; return socket_error_retval; } #if defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) fd_set write_fds; FD_ZERO(&write_fds); FD_SET(s, &write_fds); fd_set except_fds; FD_ZERO(&except_fds); FD_SET(s, &except_fds); clear_last_error(); int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); if (result >= 0) ec = asio::error_code(); return result; #else // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) pollfd fds; fds.fd = s; fds.events = POLLOUT; fds.revents = 0; clear_last_error(); int result = error_wrapper(::poll(&fds, 1, -1), ec); if (result >= 0) ec = asio::error_code(); return result; #endif // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) } const char* inet_ntop(int af, const void* src, char* dest, size_t length, unsigned long scope_id, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy. if (af != AF_INET && af != AF_INET6) { ec = asio::error::address_family_not_supported; return 0; } union { socket_addr_type base; sockaddr_storage_type storage; sockaddr_in4_type v4; sockaddr_in6_type v6; } address; DWORD address_length; if (af == AF_INET) { address_length = sizeof(sockaddr_in4_type); address.v4.sin_family = AF_INET; address.v4.sin_port = 0; memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); } else // AF_INET6 { address_length = sizeof(sockaddr_in6_type); address.v6.sin6_family = AF_INET6; address.v6.sin6_port = 0; address.v6.sin6_flowinfo = 0; address.v6.sin6_scope_id = scope_id; memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); } DWORD string_length = static_cast(length); #if defined(BOOST_NO_ANSI_APIS) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); int result = error_wrapper(::WSAAddressToStringW(&address.base, address_length, 0, string_buffer, &string_length), ec); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); #else int result = error_wrapper(::WSAAddressToStringA( &address.base, address_length, 0, dest, &string_length), ec); #endif // Windows may set error code on success. if (result != socket_error_retval) ec = asio::error_code(); // Windows may not set an error code on failure. else if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument; return result == socket_error_retval ? 0 : dest; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); if (result == 0 && !ec) ec = asio::error::invalid_argument; if (result != 0 && af == AF_INET6 && scope_id != 0) { using namespace std; // For strcat and sprintf. char if_name[IF_NAMESIZE + 1] = "%"; const in6_addr_type* ipv6_address = static_cast(src); bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) sprintf(if_name + 1, "%lu", scope_id); strcat(dest, if_name); } return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } int inet_pton(int af, const char* src, void* dest, unsigned long* scope_id, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy and strcmp. if (af != AF_INET && af != AF_INET6) { ec = asio::error::address_family_not_supported; return -1; } union { socket_addr_type base; sockaddr_storage_type storage; sockaddr_in4_type v4; sockaddr_in6_type v6; } address; int address_length = sizeof(sockaddr_storage_type); #if defined(BOOST_NO_ANSI_APIS) int num_wide_chars = strlen(src) + 1; LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); int result = error_wrapper(::WSAStringToAddressW( wide_buffer, af, 0, &address.base, &address_length), ec); #else int result = error_wrapper(::WSAStringToAddressA( const_cast(src), af, 0, &address.base, &address_length), ec); #endif if (af == AF_INET) { if (result != socket_error_retval) { memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); ec = asio::error_code(); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast(dest)->s_addr = INADDR_NONE; ec = asio::error_code(); } } else // AF_INET6 { if (result != socket_error_retval) { memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = address.v6.sin6_scope_id; ec = asio::error_code(); } } // Windows may not set an error code on failure. if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument; if (result != socket_error_retval) ec = asio::error_code(); return result == socket_error_retval ? -1 : 1; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::inet_pton(af, src, dest), ec); if (result <= 0 && !ec) ec = asio::error::invalid_argument; if (result > 0 && af == AF_INET6 && scope_id) { using namespace std; // For strchr and atoi. *scope_id = 0; if (const char* if_name = strchr(src, '%')) { in6_addr_type* ipv6_address = static_cast(dest); bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); if (is_link_local) *scope_id = if_nametoindex(if_name + 1); if (*scope_id == 0) *scope_id = atoi(if_name + 1); } } return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } int gethostname(char* name, int namelen, asio::error_code& ec) { clear_last_error(); int result = error_wrapper(::gethostname(name, namelen), ec); #if defined(BOOST_WINDOWS) if (result == 0) ec = asio::error_code(); #endif return result; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ || defined(__MACH__) && defined(__APPLE__) // The following functions are only needed for emulation of getaddrinfo and // getnameinfo. inline asio::error_code translate_netdb_error(int error) { switch (error) { case 0: return asio::error_code(); case HOST_NOT_FOUND: return asio::error::host_not_found; case TRY_AGAIN: return asio::error::host_not_found_try_again; case NO_RECOVERY: return asio::error::no_recovery; case NO_DATA: return asio::error::no_data; default: BOOST_ASSERT(false); return asio::error::invalid_argument; } } inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* result, char* buffer, int buflength, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); if (!retval) return 0; ec = asio::error_code(); *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) int error = 0; hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, buflength, &error), ec); if (error) ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); int error = 0; hostent* retval = error_wrapper(::getipnodebyaddr( addr, length, af, &error), ec); if (error) ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; return retval; #else hostent* retval = 0; int error = 0; error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, buflength, &retval, &error), ec); if (error) ec = translate_netdb_error(error); return retval; #endif } inline hostent* gethostbyname(const char* name, int af, struct hostent* result, char* buffer, int buflength, int ai_flags, asio::error_code& ec) { clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); (void)(ai_flags); if (af != AF_INET) { ec = asio::error::address_family_not_supported; return 0; } hostent* retval = error_wrapper(::gethostbyname(name), ec); if (!retval) return 0; ec = asio::error_code(); *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) (void)(ai_flags); if (af != AF_INET) { ec = asio::error::address_family_not_supported; return 0; } int error = 0; hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, buflength, &error), ec); if (error) ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); int error = 0; hostent* retval = error_wrapper(::getipnodebyname( name, af, ai_flags, &error), ec); if (error) ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; return retval; #else (void)(ai_flags); if (af != AF_INET) { ec = asio::error::address_family_not_supported; return 0; } hostent* retval = 0; int error = 0; error_wrapper(::gethostbyname_r(name, result, buffer, buflength, &retval, &error), ec); if (error) ec = translate_netdb_error(error); return retval; #endif } inline void freehostent(hostent* h) { #if defined(__MACH__) && defined(__APPLE__) if (h) ::freehostent(h); #else (void)(h); #endif } // Emulation of getaddrinfo based on implementation in: // Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. struct gai_search { const char* host; int family; }; inline int gai_nsearch(const char* host, const addrinfo_type* hints, gai_search (&search)[2]) { int search_count = 0; if (host == 0 || host[0] == '\0') { if (hints->ai_flags & AI_PASSIVE) { // No host and AI_PASSIVE implies wildcard bind. switch (hints->ai_family) { case AF_INET: search[search_count].host = "0.0.0.0"; search[search_count].family = AF_INET; ++search_count; break; case AF_INET6: search[search_count].host = "0::0"; search[search_count].family = AF_INET6; ++search_count; break; case AF_UNSPEC: search[search_count].host = "0::0"; search[search_count].family = AF_INET6; ++search_count; search[search_count].host = "0.0.0.0"; search[search_count].family = AF_INET; ++search_count; break; default: break; } } else { // No host and not AI_PASSIVE means connect to local host. switch (hints->ai_family) { case AF_INET: search[search_count].host = "localhost"; search[search_count].family = AF_INET; ++search_count; break; case AF_INET6: search[search_count].host = "localhost"; search[search_count].family = AF_INET6; ++search_count; break; case AF_UNSPEC: search[search_count].host = "localhost"; search[search_count].family = AF_INET6; ++search_count; search[search_count].host = "localhost"; search[search_count].family = AF_INET; ++search_count; break; default: break; } } } else { // Host is specified. switch (hints->ai_family) { case AF_INET: search[search_count].host = host; search[search_count].family = AF_INET; ++search_count; break; case AF_INET6: search[search_count].host = host; search[search_count].family = AF_INET6; ++search_count; break; case AF_UNSPEC: search[search_count].host = host; search[search_count].family = AF_INET6; ++search_count; search[search_count].host = host; search[search_count].family = AF_INET; ++search_count; break; default: break; } } return search_count; } template inline T* gai_alloc(std::size_t size = sizeof(T)) { using namespace std; T* p = static_cast(::operator new(size, std::nothrow)); if (p) memset(p, 0, size); return p; } inline void gai_free(void* p) { ::operator delete(p); } inline void gai_strcpy(char* target, const char* source, std::size_t max_size) { using namespace std; #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) strcpy_s(target, max_size, source); #else *target = 0; strncat(target, source, max_size); #endif } enum { gai_clone_flag = 1 << 30 }; inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, const void* addr, int family) { using namespace std; addrinfo_type* ai = gai_alloc(); if (ai == 0) return EAI_MEMORY; ai->ai_next = 0; **next = ai; *next = &ai->ai_next; ai->ai_canonname = 0; ai->ai_socktype = hints->ai_socktype; if (ai->ai_socktype == 0) ai->ai_flags |= gai_clone_flag; ai->ai_protocol = hints->ai_protocol; ai->ai_family = family; switch (ai->ai_family) { case AF_INET: { sockaddr_in4_type* sinptr = gai_alloc(); if (sinptr == 0) return EAI_MEMORY; sinptr->sin_family = AF_INET; memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); ai->ai_addr = reinterpret_cast(sinptr); ai->ai_addrlen = sizeof(sockaddr_in4_type); break; } case AF_INET6: { sockaddr_in6_type* sin6ptr = gai_alloc(); if (sin6ptr == 0) return EAI_MEMORY; sin6ptr->sin6_family = AF_INET6; memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); ai->ai_addr = reinterpret_cast(sin6ptr); ai->ai_addrlen = sizeof(sockaddr_in6_type); break; } default: break; } return 0; } inline addrinfo_type* gai_clone(addrinfo_type* ai) { using namespace std; addrinfo_type* new_ai = gai_alloc(); if (new_ai == 0) return new_ai; new_ai->ai_next = ai->ai_next; ai->ai_next = new_ai; new_ai->ai_flags = 0; new_ai->ai_family = ai->ai_family; new_ai->ai_socktype = ai->ai_socktype; new_ai->ai_protocol = ai->ai_protocol; new_ai->ai_canonname = 0; new_ai->ai_addrlen = ai->ai_addrlen; new_ai->ai_addr = gai_alloc(ai->ai_addrlen); memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); return new_ai; } inline int gai_port(addrinfo_type* aihead, int port, int socktype) { int num_found = 0; for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) { if (ai->ai_flags & gai_clone_flag) { if (ai->ai_socktype != 0) { ai = gai_clone(ai); if (ai == 0) return -1; // ai now points to newly cloned entry. } } else if (ai->ai_socktype != socktype) { // Ignore if mismatch on socket type. continue; } ai->ai_socktype = socktype; switch (ai->ai_family) { case AF_INET: { sockaddr_in4_type* sinptr = reinterpret_cast(ai->ai_addr); sinptr->sin_port = port; ++num_found; break; } case AF_INET6: { sockaddr_in6_type* sin6ptr = reinterpret_cast(ai->ai_addr); sin6ptr->sin6_port = port; ++num_found; break; } default: break; } } return num_found; } inline int gai_serv(addrinfo_type* aihead, const addrinfo_type* hints, const char* serv) { using namespace std; int num_found = 0; if ( #if defined(AI_NUMERICSERV) (hints->ai_flags & AI_NUMERICSERV) || #endif isdigit(static_cast(serv[0]))) { int port = htons(atoi(serv)); if (hints->ai_socktype) { // Caller specifies socket type. int rc = gai_port(aihead, port, hints->ai_socktype); if (rc < 0) return EAI_MEMORY; num_found += rc; } else { // Caller does not specify socket type. int rc = gai_port(aihead, port, SOCK_STREAM); if (rc < 0) return EAI_MEMORY; num_found += rc; rc = gai_port(aihead, port, SOCK_DGRAM); if (rc < 0) return EAI_MEMORY; num_found += rc; } } else { // Try service name with TCP first, then UDP. if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) { servent* sptr = getservbyname(serv, "tcp"); if (sptr != 0) { int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); if (rc < 0) return EAI_MEMORY; num_found += rc; } } if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) { servent* sptr = getservbyname(serv, "udp"); if (sptr != 0) { int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); if (rc < 0) return EAI_MEMORY; num_found += rc; } } } if (num_found == 0) { if (hints->ai_socktype == 0) { // All calls to getservbyname() failed. return EAI_NONAME; } else { // Service not supported for socket type. return EAI_SERVICE; } } return 0; } inline int gai_echeck(const char* host, const char* service, int flags, int family, int socktype, int protocol) { (void)(flags); (void)(protocol); // Host or service must be specified. if (host == 0 || host[0] == '\0') if (service == 0 || service[0] == '\0') return EAI_NONAME; // Check combination of family and socket type. switch (family) { case AF_UNSPEC: break; case AF_INET: case AF_INET6: if (service != 0 && service[0] != '\0') if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) return EAI_SOCKTYPE; break; default: return EAI_FAMILY; } return 0; } inline void freeaddrinfo_emulation(addrinfo_type* aihead) { addrinfo_type* ai = aihead; while (ai) { gai_free(ai->ai_addr); gai_free(ai->ai_canonname); addrinfo_type* ainext = ai->ai_next; gai_free(ai); ai = ainext; } } inline int getaddrinfo_emulation(const char* host, const char* service, const addrinfo_type* hintsp, addrinfo_type** result) { // Set up linked list of addrinfo structures. addrinfo_type* aihead = 0; addrinfo_type** ainext = &aihead; char* canon = 0; // Supply default hints if not specified by caller. addrinfo_type hints = addrinfo_type(); hints.ai_family = AF_UNSPEC; if (hintsp) hints = *hintsp; // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED // and AI_ALL flags. #if defined(AI_V4MAPPED) if (hints.ai_family != AF_INET6) hints.ai_flags &= ~AI_V4MAPPED; #endif #if defined(AI_ALL) if (hints.ai_family != AF_INET6) hints.ai_flags &= ~AI_ALL; #endif // Basic error checking. int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, hints.ai_socktype, hints.ai_protocol); if (rc != 0) { freeaddrinfo_emulation(aihead); return rc; } gai_search search[2]; int search_count = gai_nsearch(host, &hints, search); for (gai_search* sptr = search; sptr < search + search_count; ++sptr) { // Check for IPv4 dotted decimal string. in4_addr_type inaddr; asio::error_code ec; if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) { if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) { freeaddrinfo_emulation(aihead); gai_free(canon); return EAI_FAMILY; } if (sptr->family == AF_INET) { rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); if (rc != 0) { freeaddrinfo_emulation(aihead); gai_free(canon); return rc; } } continue; } // Check for IPv6 hex string. in6_addr_type in6addr; if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) { if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) { freeaddrinfo_emulation(aihead); gai_free(canon); return EAI_FAMILY; } if (sptr->family == AF_INET6) { rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); if (rc != 0) { freeaddrinfo_emulation(aihead); gai_free(canon); return rc; } } continue; } // Look up hostname. hostent hent; char hbuf[8192] = ""; hostent* hptr = socket_ops::gethostbyname(sptr->host, sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); if (hptr == 0) { if (search_count == 2) { // Failure is OK if there are multiple searches. continue; } freeaddrinfo_emulation(aihead); gai_free(canon); if (ec == asio::error::host_not_found) return EAI_NONAME; if (ec == asio::error::host_not_found_try_again) return EAI_AGAIN; if (ec == asio::error::no_recovery) return EAI_FAIL; if (ec == asio::error::no_data) return EAI_NONAME; return EAI_NONAME; } // Check for address family mismatch if one was specified. if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) { freeaddrinfo_emulation(aihead); gai_free(canon); socket_ops::freehostent(hptr); return EAI_FAMILY; } // Save canonical name first time. if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] && (hints.ai_flags & AI_CANONNAME) && canon == 0) { std::size_t canon_len = strlen(hptr->h_name) + 1; canon = gai_alloc(canon_len); if (canon == 0) { freeaddrinfo_emulation(aihead); socket_ops::freehostent(hptr); return EAI_MEMORY; } gai_strcpy(canon, hptr->h_name, canon_len); } // Create an addrinfo structure for each returned address. for (char** ap = hptr->h_addr_list; *ap; ++ap) { rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); if (rc != 0) { freeaddrinfo_emulation(aihead); gai_free(canon); socket_ops::freehostent(hptr); return EAI_FAMILY; } } socket_ops::freehostent(hptr); } // Check if we found anything. if (aihead == 0) { gai_free(canon); return EAI_NONAME; } // Return canonical name in first entry. if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) { if (canon) { aihead->ai_canonname = canon; canon = 0; } else { std::size_t canonname_len = strlen(search[0].host) + 1; aihead->ai_canonname = gai_alloc(canonname_len); if (aihead->ai_canonname == 0) { freeaddrinfo_emulation(aihead); return EAI_MEMORY; } gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); } } gai_free(canon); // Process the service name. if (service != 0 && service[0] != '\0') { rc = gai_serv(aihead, &hints, service); if (rc != 0) { freeaddrinfo_emulation(aihead); return rc; } } // Return result to caller. *result = aihead; return 0; } inline asio::error_code getnameinfo_emulation( const socket_addr_type* sa, std::size_t salen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { using namespace std; const char* addr; size_t addr_len; unsigned short port; switch (sa->sa_family) { case AF_INET: if (salen != sizeof(sockaddr_in4_type)) { return ec = asio::error::invalid_argument; } addr = reinterpret_cast( &reinterpret_cast(sa)->sin_addr); addr_len = sizeof(in4_addr_type); port = reinterpret_cast(sa)->sin_port; break; case AF_INET6: if (salen != sizeof(sockaddr_in6_type)) { return ec = asio::error::invalid_argument; } addr = reinterpret_cast( &reinterpret_cast(sa)->sin6_addr); addr_len = sizeof(in6_addr_type); port = reinterpret_cast(sa)->sin6_port; break; default: return ec = asio::error::address_family_not_supported; } if (host && hostlen > 0) { if (flags & NI_NUMERICHOST) { if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) { return ec; } } else { hostent hent; char hbuf[8192] = ""; hostent* hptr = socket_ops::gethostbyaddr(addr, static_cast(addr_len), sa->sa_family, &hent, hbuf, sizeof(hbuf), ec); if (hptr && hptr->h_name && hptr->h_name[0] != '\0') { if (flags & NI_NOFQDN) { char* dot = strchr(hptr->h_name, '.'); if (dot) { *dot = 0; } } gai_strcpy(host, hptr->h_name, hostlen); socket_ops::freehostent(hptr); } else { socket_ops::freehostent(hptr); if (flags & NI_NAMEREQD) { return ec = asio::error::host_not_found; } if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) { return ec; } } } } if (serv && servlen > 0) { if (flags & NI_NUMERICSERV) { if (servlen < 6) { return ec = asio::error::no_buffer_space; } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) sprintf_s(serv, servlen, "%u", ntohs(port)); #else sprintf(serv, "%u", ntohs(port)); #endif } else { #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ && !defined(ASIO_DISABLE_THREADS) static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ::pthread_mutex_lock(&mutex); #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) // && !defined(ASIO_DISABLE_THREADS) servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); if (sptr && sptr->s_name && sptr->s_name[0] != '\0') { gai_strcpy(serv, sptr->s_name, servlen); } else { if (servlen < 6) { return ec = asio::error::no_buffer_space; } #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) sprintf_s(serv, servlen, "%u", ntohs(port)); #else sprintf(serv, "%u", ntohs(port)); #endif } #if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) \ && !defined(ASIO_DISABLE_THREADS) ::pthread_mutex_unlock(&mutex); #endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) // && !defined(ASIO_DISABLE_THREADS) } } ec = asio::error_code(); return ec; } #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // || defined(__MACH__) && defined(__APPLE__) inline asio::error_code translate_addrinfo_error(int error) { switch (error) { case 0: return asio::error_code(); case EAI_AGAIN: return asio::error::host_not_found_try_again; case EAI_BADFLAGS: return asio::error::invalid_argument; case EAI_FAIL: return asio::error::no_recovery; case EAI_FAMILY: return asio::error::address_family_not_supported; case EAI_MEMORY: return asio::error::no_memory; case EAI_NONAME: #if defined(EAI_ADDRFAMILY) case EAI_ADDRFAMILY: #endif #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) case EAI_NODATA: #endif return asio::error::host_not_found; case EAI_SERVICE: return asio::error::service_not_found; case EAI_SOCKTYPE: return asio::error::socket_type_not_supported; default: // Possibly the non-portable EAI_SYSTEM. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return asio::error_code( WSAGetLastError(), asio::error::get_system_category()); #else return asio::error_code( errno, asio::error::get_system_category()); #endif } } asio::error_code getaddrinfo(const char* host, const char* service, const addrinfo_type& hints, addrinfo_type** result, asio::error_code& ec) { host = (host && *host) ? host : 0; service = (service && *service) ? service : 0; clear_last_error(); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. int error = ::getaddrinfo(host, service, &hints, result); return ec = translate_addrinfo_error(error); # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gai_t)(const char*, const char*, const addrinfo_type*, addrinfo_type**); if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) { int error = gai(host, service, &hints, result); return ec = translate_addrinfo_error(error); } } int error = getaddrinfo_emulation(host, service, &hints, result); return ec = translate_addrinfo_error(error); # endif #elif defined(__MACH__) && defined(__APPLE__) int error = getaddrinfo_emulation(host, service, &hints, result); return ec = translate_addrinfo_error(error); #else int error = ::getaddrinfo(host, service, &hints, result); return ec = translate_addrinfo_error(error); #endif } asio::error_code background_getaddrinfo( const weak_cancel_token_type& cancel_token, const char* host, const char* service, const addrinfo_type& hints, addrinfo_type** result, asio::error_code& ec) { if (cancel_token.expired()) ec = asio::error::operation_aborted; else socket_ops::getaddrinfo(host, service, hints, result, ec); return ec; } void freeaddrinfo(addrinfo_type* ai) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. ::freeaddrinfo(ai); # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *fai_t)(addrinfo_type*); if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) { fai(ai); return; } } freeaddrinfo_emulation(ai); # endif #elif defined(__MACH__) && defined(__APPLE__) freeaddrinfo_emulation(ai); #else ::freeaddrinfo(ai); #endif } asio::error_code getnameinfo(const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. clear_last_error(); int error = ::getnameinfo(addr, static_cast(addrlen), host, static_cast(hostlen), serv, static_cast(servlen), flags); return ec = translate_addrinfo_error(error); # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gni_t)(const socket_addr_type*, int, char*, DWORD, char*, DWORD, int); if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) { clear_last_error(); int error = gni(addr, static_cast(addrlen), host, static_cast(hostlen), serv, static_cast(servlen), flags); return ec = translate_addrinfo_error(error); } } clear_last_error(); return getnameinfo_emulation(addr, addrlen, host, hostlen, serv, servlen, flags, ec); # endif #elif defined(__MACH__) && defined(__APPLE__) using namespace std; // For memcpy. sockaddr_storage_type tmp_addr; memcpy(&tmp_addr, addr, addrlen); tmp_addr.ss_len = addrlen; addr = reinterpret_cast(&tmp_addr); clear_last_error(); return getnameinfo_emulation(addr, addrlen, host, hostlen, serv, servlen, flags, ec); #else clear_last_error(); int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); return ec = translate_addrinfo_error(error); #endif } asio::error_code sync_getnameinfo( const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec) { // First try resolving with the service name. If that fails try resolving // but allow the service to be returned as a number. int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; socket_ops::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags, ec); if (ec) { socket_ops::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags | NI_NUMERICSERV, ec); } return ec; } asio::error_code background_getnameinfo( const weak_cancel_token_type& cancel_token, const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec) { if (cancel_token.expired()) { ec = asio::error::operation_aborted; } else { // First try resolving with the service name. If that fails try resolving // but allow the service to be returned as a number. int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; socket_ops::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags, ec); if (ec) { socket_ops::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags | NI_NUMERICSERV, ec); } } return ec; } u_long_type network_to_host_long(u_long_type value) { return ntohl(value); } u_long_type host_to_network_long(u_long_type value) { return htonl(value); } u_short_type network_to_host_short(u_short_type value) { return ntohs(value); } u_short_type host_to_network_short(u_short_type value) { return htons(value); } } // namespace socket_ops } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_OPS_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/socket_select_interrupter.ipp000066400000000000000000000115571244131713600271100ustar00rootroot00000000000000// // detail/impl/socket_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP #define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_select_interrupter.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { socket_select_interrupter::socket_select_interrupter() { asio::error_code ec; socket_holder acceptor(socket_ops::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); if (acceptor.get() == invalid_socket) asio::detail::throw_error(ec, "socket_select_interrupter"); int opt = 1; socket_ops::state_type acceptor_state = 0; socket_ops::setsockopt(acceptor.get(), acceptor_state, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); using namespace std; // For memset. sockaddr_in4_type addr; std::size_t addr_len = sizeof(addr); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = 0; if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, &addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); // Some broken firewalls on Windows will intermittently cause getsockname to // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We // explicitly specify the target address here to work around this problem. addr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (socket_ops::listen(acceptor.get(), SOMAXCONN, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); socket_holder client(socket_ops::socket( AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); if (client.get() == invalid_socket) asio::detail::throw_error(ec, "socket_select_interrupter"); if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, addr_len, ec) == socket_error_retval) asio::detail::throw_error(ec, "socket_select_interrupter"); socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); if (server.get() == invalid_socket) asio::detail::throw_error(ec, "socket_select_interrupter"); ioctl_arg_type non_blocking = 1; socket_ops::state_type client_state = 0; if (socket_ops::ioctl(client.get(), client_state, FIONBIO, &non_blocking, ec)) asio::detail::throw_error(ec, "socket_select_interrupter"); opt = 1; socket_ops::setsockopt(client.get(), client_state, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); non_blocking = 1; socket_ops::state_type server_state = 0; if (socket_ops::ioctl(server.get(), server_state, FIONBIO, &non_blocking, ec)) asio::detail::throw_error(ec, "socket_select_interrupter"); opt = 1; socket_ops::setsockopt(server.get(), server_state, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); read_descriptor_ = server.release(); write_descriptor_ = client.release(); } socket_select_interrupter::~socket_select_interrupter() { asio::error_code ec; socket_ops::state_type state = socket_ops::internal_non_blocking; if (read_descriptor_ != invalid_socket) socket_ops::close(read_descriptor_, state, true, ec); if (write_descriptor_ != invalid_socket) socket_ops::close(write_descriptor_, state, true, ec); } void socket_select_interrupter::interrupt() { char byte = 0; socket_ops::buf b; socket_ops::init_buf(b, &byte, 1); asio::error_code ec; socket_ops::send(write_descriptor_, &b, 1, 0, ec); } bool socket_select_interrupter::reset() { char data[1024]; socket_ops::buf b; socket_ops::init_buf(b, data, sizeof(data)); asio::error_code ec; int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); bool was_interrupted = (bytes_read > 0); while (bytes_read == sizeof(data)) bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); return was_interrupted; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) #endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/strand_service.hpp000066400000000000000000000075611244131713600246300ustar00rootroot00000000000000// // detail/impl/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP #define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/call_stack.hpp" #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { inline strand_service::strand_impl::strand_impl() : operation(&strand_service::do_complete), count_(0) { } struct strand_service::on_dispatch_exit { io_service_impl* io_service_; strand_impl* impl_; ~on_dispatch_exit() { impl_->mutex_.lock(); bool more_handlers = (--impl_->count_ > 0); impl_->mutex_.unlock(); if (more_handlers) io_service_->post_immediate_completion(impl_); } }; inline void strand_service::destroy(strand_service::implementation_type& impl) { impl = 0; } template void strand_service::dispatch(strand_service::implementation_type& impl, Handler handler) { // If we are already in the strand then the handler can run immediately. if (call_stack::contains(impl)) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); return; } // Allocate and construct an operation to wrap the handler. typedef completion_handler op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); // If we are running inside the io_service, and no other handler is queued // or running, then the handler can run immediately. bool can_dispatch = call_stack::contains(&io_service_); impl->mutex_.lock(); bool first = (++impl->count_ == 1); if (can_dispatch && first) { // Immediate invocation is allowed. impl->mutex_.unlock(); // Memory must be releaesed before any upcall is made. p.reset(); // Indicate that this strand is executing on the current thread. call_stack::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. on_dispatch_exit on_exit = { &io_service_, impl }; (void)on_exit; asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); return; } // Immediate invocation is not allowed, so enqueue for later. impl->queue_.push(p.p); impl->mutex_.unlock(); p.v = p.p = 0; // The first handler to be enqueued is responsible for scheduling the // strand. if (first) io_service_.post_immediate_completion(impl); } // Request the io_service to invoke the given handler and return immediately. template void strand_service::post(strand_service::implementation_type& impl, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef completion_handler op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); // Add the handler to the queue. impl->mutex_.lock(); bool first = (++impl->count_ == 1); impl->queue_.push(p.p); impl->mutex_.unlock(); p.v = p.p = 0; // The first handler to be enqueue is responsible for scheduling the strand. if (first) io_service_.post_immediate_completion(impl); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/strand_service.ipp000066400000000000000000000053421244131713600246240ustar00rootroot00000000000000// // detail/impl/strand_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP #define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/call_stack.hpp" #include "asio/detail/strand_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { struct strand_service::on_do_complete_exit { io_service_impl* owner_; strand_impl* impl_; ~on_do_complete_exit() { impl_->mutex_.lock(); bool more_handlers = (--impl_->count_ > 0); impl_->mutex_.unlock(); if (more_handlers) owner_->post_immediate_completion(impl_); } }; strand_service::strand_service(asio::io_service& io_service) : asio::detail::service_base(io_service), io_service_(asio::use_service(io_service)), mutex_(), salt_(0) { } void strand_service::shutdown_service() { op_queue ops; asio::detail::mutex::scoped_lock lock(mutex_); for (std::size_t i = 0; i < num_implementations; ++i) if (strand_impl* impl = implementations_[i].get()) ops.push(impl->queue_); } void strand_service::construct(strand_service::implementation_type& impl) { std::size_t salt = salt_++; std::size_t index = reinterpret_cast(&impl); index += (reinterpret_cast(&impl) >> 3); index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); index = index % num_implementations; asio::detail::mutex::scoped_lock lock(mutex_); if (!implementations_[index]) implementations_[index].reset(new strand_impl); impl = implementations_[index].get(); } void strand_service::do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { if (owner) { strand_impl* impl = static_cast(base); // Get the next handler to be executed. impl->mutex_.lock(); operation* o = impl->queue_.front(); impl->queue_.pop(); impl->mutex_.unlock(); // Indicate that this strand is executing on the current thread. call_stack::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. on_do_complete_exit on_exit = { owner, impl }; (void)on_exit; o->complete(*owner); } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/task_io_service.hpp000066400000000000000000000030751244131713600247620ustar00rootroot00000000000000// // detail/impl/task_io_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP #define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/call_stack.hpp" #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void task_io_service::dispatch(Handler handler) { if (call_stack::contains(this)) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } else post(handler); } template void task_io_service::post(Handler handler) { // Allocate and construct an operation to wrap the handler. typedef completion_handler op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); post_immediate_completion(p.p); p.v = p.p = 0; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/task_io_service.ipp000066400000000000000000000173221244131713600247630ustar00rootroot00000000000000// // detail/impl/task_io_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP #define ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) #include #include "asio/detail/call_stack.hpp" #include "asio/detail/event.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/task_io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { struct task_io_service::task_cleanup { ~task_cleanup() { // Enqueue the completed operations and reinsert the task at the end of // the operation queue. lock_->lock(); task_io_service_->task_interrupted_ = true; task_io_service_->op_queue_.push(*ops_); task_io_service_->op_queue_.push(&task_io_service_->task_operation_); } task_io_service* task_io_service_; mutex::scoped_lock* lock_; op_queue* ops_; }; struct task_io_service::work_finished_on_block_exit { ~work_finished_on_block_exit() { task_io_service_->work_finished(); } task_io_service* task_io_service_; }; struct task_io_service::idle_thread_info { event wakeup_event; idle_thread_info* next; }; task_io_service::task_io_service(asio::io_service& io_service) : asio::detail::service_base(io_service), mutex_(), task_(0), task_interrupted_(true), outstanding_work_(0), stopped_(false), shutdown_(false), first_idle_thread_(0) { } void task_io_service::init(std::size_t /*concurrency_hint*/) { } void task_io_service::shutdown_service() { mutex::scoped_lock lock(mutex_); shutdown_ = true; lock.unlock(); // Destroy handler objects. while (!op_queue_.empty()) { operation* o = op_queue_.front(); op_queue_.pop(); if (o != &task_operation_) o->destroy(); } // Reset to initial state. task_ = 0; } void task_io_service::init_task() { mutex::scoped_lock lock(mutex_); if (!shutdown_ && !task_) { task_ = &use_service(this->get_io_service()); op_queue_.push(&task_operation_); wake_one_thread_and_unlock(lock); } } std::size_t task_io_service::run(asio::error_code& ec) { ec = asio::error_code(); if (outstanding_work_ == 0) { stop(); return 0; } call_stack::context ctx(this); idle_thread_info this_idle_thread; this_idle_thread.next = 0; mutex::scoped_lock lock(mutex_); std::size_t n = 0; for (; do_one(lock, &this_idle_thread); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; } std::size_t task_io_service::run_one(asio::error_code& ec) { ec = asio::error_code(); if (outstanding_work_ == 0) { stop(); return 0; } call_stack::context ctx(this); idle_thread_info this_idle_thread; this_idle_thread.next = 0; mutex::scoped_lock lock(mutex_); return do_one(lock, &this_idle_thread); } std::size_t task_io_service::poll(asio::error_code& ec) { if (outstanding_work_ == 0) { stop(); ec = asio::error_code(); return 0; } call_stack::context ctx(this); mutex::scoped_lock lock(mutex_); std::size_t n = 0; for (; do_one(lock, 0); lock.lock()) if (n != (std::numeric_limits::max)()) ++n; return n; } std::size_t task_io_service::poll_one(asio::error_code& ec) { ec = asio::error_code(); if (outstanding_work_ == 0) { stop(); return 0; } call_stack::context ctx(this); mutex::scoped_lock lock(mutex_); return do_one(lock, 0); } void task_io_service::stop() { mutex::scoped_lock lock(mutex_); stop_all_threads(lock); } void task_io_service::reset() { mutex::scoped_lock lock(mutex_); stopped_ = false; } void task_io_service::post_immediate_completion(task_io_service::operation* op) { work_started(); post_deferred_completion(op); } void task_io_service::post_deferred_completion(task_io_service::operation* op) { mutex::scoped_lock lock(mutex_); op_queue_.push(op); wake_one_thread_and_unlock(lock); } void task_io_service::post_deferred_completions( op_queue& ops) { if (!ops.empty()) { mutex::scoped_lock lock(mutex_); op_queue_.push(ops); wake_one_thread_and_unlock(lock); } } std::size_t task_io_service::do_one(mutex::scoped_lock& lock, task_io_service::idle_thread_info* this_idle_thread) { bool polling = !this_idle_thread; bool task_has_run = false; while (!stopped_) { if (!op_queue_.empty()) { // Prepare to execute first handler from queue. operation* o = op_queue_.front(); op_queue_.pop(); bool more_handlers = (!op_queue_.empty()); if (o == &task_operation_) { task_interrupted_ = more_handlers || polling; // If the task has already run and we're polling then we're done. if (task_has_run && polling) { task_interrupted_ = true; op_queue_.push(&task_operation_); return 0; } task_has_run = true; if (!more_handlers || !wake_one_idle_thread_and_unlock(lock)) lock.unlock(); op_queue completed_ops; task_cleanup c = { this, &lock, &completed_ops }; (void)c; // Run the task. May throw an exception. Only block if the operation // queue is empty and we're not polling, otherwise we want to return // as soon as possible. task_->run(!more_handlers && !polling, completed_ops); } else { if (more_handlers) wake_one_thread_and_unlock(lock); else lock.unlock(); // Ensure the count of outstanding work is decremented on block exit. work_finished_on_block_exit on_exit = { this }; (void)on_exit; // Complete the operation. May throw an exception. o->complete(*this); // deletes the operation object return 1; } } else if (this_idle_thread) { // Nothing to run right now, so just wait for work to do. this_idle_thread->next = first_idle_thread_; first_idle_thread_ = this_idle_thread; this_idle_thread->wakeup_event.clear(lock); this_idle_thread->wakeup_event.wait(lock); } else { return 0; } } return 0; } void task_io_service::stop_all_threads( mutex::scoped_lock& lock) { stopped_ = true; while (first_idle_thread_) { idle_thread_info* idle_thread = first_idle_thread_; first_idle_thread_ = idle_thread->next; idle_thread->next = 0; idle_thread->wakeup_event.signal(lock); } if (!task_interrupted_ && task_) { task_interrupted_ = true; task_->interrupt(); } } bool task_io_service::wake_one_idle_thread_and_unlock( mutex::scoped_lock& lock) { if (first_idle_thread_) { idle_thread_info* idle_thread = first_idle_thread_; first_idle_thread_ = idle_thread->next; idle_thread->next = 0; idle_thread->wakeup_event.signal_and_unlock(lock); return true; } return false; } void task_io_service::wake_one_thread_and_unlock( mutex::scoped_lock& lock) { if (!wake_one_idle_thread_and_unlock(lock)) { if (!task_interrupted_ && task_) { task_interrupted_ = true; task_->interrupt(); } lock.unlock(); } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_TASK_IO_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/throw_error.ipp000066400000000000000000000021171244131713600241620ustar00rootroot00000000000000// // detail/impl/throw_error.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_THROW_ERROR_IPP #define ASIO_DETAIL_IMPL_THROW_ERROR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/throw_error.hpp" #include "asio/system_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { void do_throw_error(const asio::error_code& err) { asio::system_error e(err); boost::throw_exception(e); } void do_throw_error(const asio::error_code& err, const char* location) { asio::system_error e(err, location); boost::throw_exception(e); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/timer_queue.ipp000066400000000000000000000040171244131713600241330ustar00rootroot00000000000000// // detail/impl/timer_queue.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP #define ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HEADER_ONLY) #include "asio/detail/timer_queue.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { timer_queue >::timer_queue() { } timer_queue >::~timer_queue() { } bool timer_queue >::enqueue_timer( const time_type& time, per_timer_data& timer, timer_op* op) { return impl_.enqueue_timer(time, timer, op); } bool timer_queue >::empty() const { return impl_.empty(); } long timer_queue >::wait_duration_msec( long max_duration) const { return impl_.wait_duration_msec(max_duration); } long timer_queue >::wait_duration_usec( long max_duration) const { return impl_.wait_duration_usec(max_duration); } void timer_queue >::get_ready_timers( op_queue& ops) { impl_.get_ready_timers(ops); } void timer_queue >::get_all_timers( op_queue& ops) { impl_.get_all_timers(ops); } std::size_t timer_queue >::cancel_timer( per_timer_data& timer, op_queue& ops) { return impl_.cancel_timer(timer, ops); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/timer_queue_set.ipp000066400000000000000000000042741244131713600250130ustar00rootroot00000000000000// // detail/impl/timer_queue_set.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP #define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { timer_queue_set::timer_queue_set() : first_(0) { } void timer_queue_set::insert(timer_queue_base* q) { q->next_ = first_; first_ = q; } void timer_queue_set::erase(timer_queue_base* q) { if (first_) { if (q == first_) { first_ = q->next_; q->next_ = 0; return; } for (timer_queue_base* p = first_; p->next_; p = p->next_) { if (p->next_ == q) { p->next_ = q->next_; q->next_ = 0; return; } } } } bool timer_queue_set::all_empty() const { for (timer_queue_base* p = first_; p; p = p->next_) if (!p->empty()) return false; return true; } long timer_queue_set::wait_duration_msec(long max_duration) const { long min_duration = max_duration; for (timer_queue_base* p = first_; p; p = p->next_) min_duration = p->wait_duration_msec(min_duration); return min_duration; } long timer_queue_set::wait_duration_usec(long max_duration) const { long min_duration = max_duration; for (timer_queue_base* p = first_; p; p = p->next_) min_duration = p->wait_duration_usec(min_duration); return min_duration; } void timer_queue_set::get_ready_timers(op_queue& ops) { for (timer_queue_base* p = first_; p; p = p->next_) p->get_ready_timers(ops); } void timer_queue_set::get_all_timers(op_queue& ops) { for (timer_queue_base* p = first_; p; p = p->next_) p->get_all_timers(ops); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_event.ipp000066400000000000000000000021711244131713600236040ustar00rootroot00000000000000// // detail/win_event.ipp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_EVENT_IPP #define ASIO_DETAIL_IMPL_WIN_EVENT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include "asio/detail/throw_error.hpp" #include "asio/detail/win_event.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_event::win_event() : event_(::CreateEvent(0, true, false, 0)) { if (!event_) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "event"); } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_iocp_handle_service.ipp000066400000000000000000000265271244131713600264630ustar00rootroot00000000000000// // detail/impl/win_iocp_handle_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP #define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/detail/win_iocp_handle_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_iocp_handle_service::overlapped_wrapper : public OVERLAPPED { public: explicit overlapped_wrapper(asio::error_code& ec) { Internal = 0; InternalHigh = 0; Offset = 0; OffsetHigh = 0; // Create a non-signalled manual-reset event, for GetOverlappedResult. hEvent = ::CreateEvent(0, TRUE, FALSE, 0); if (hEvent) { // As documented in GetQueuedCompletionStatus, setting the low order // bit of this event prevents our synchronous writes from being treated // as completion port events. *reinterpret_cast(&hEvent) |= 1; } else { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } } ~overlapped_wrapper() { if (hEvent) { ::CloseHandle(hEvent); } } }; win_iocp_handle_service::win_iocp_handle_service( asio::io_service& io_service) : iocp_service_(asio::use_service(io_service)), mutex_(), impl_list_(0) { } void win_iocp_handle_service::shutdown_service() { // Close all implementations, causing all operations to complete. asio::detail::mutex::scoped_lock lock(mutex_); implementation_type* impl = impl_list_; while (impl) { close_for_destruction(*impl); impl = impl->next_; } } void win_iocp_handle_service::construct( win_iocp_handle_service::implementation_type& impl) { impl.handle_ = INVALID_HANDLE_VALUE; impl.safe_cancellation_thread_id_ = 0; // Insert implementation into linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); impl.next_ = impl_list_; impl.prev_ = 0; if (impl_list_) impl_list_->prev_ = &impl; impl_list_ = &impl; } void win_iocp_handle_service::destroy( win_iocp_handle_service::implementation_type& impl) { close_for_destruction(impl); // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); if (impl_list_ == &impl) impl_list_ = impl.next_; if (impl.prev_) impl.prev_->next_ = impl.next_; if (impl.next_) impl.next_->prev_= impl.prev_; impl.next_ = 0; impl.prev_ = 0; } asio::error_code win_iocp_handle_service::assign( win_iocp_handle_service::implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } if (iocp_service_.register_handle(native_handle, ec)) return ec; impl.handle_ = native_handle; ec = asio::error_code(); return ec; } asio::error_code win_iocp_handle_service::close( win_iocp_handle_service::implementation_type& impl, asio::error_code& ec) { if (is_open(impl)) { if (!::CloseHandle(impl.handle_)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } impl.handle_ = INVALID_HANDLE_VALUE; impl.safe_cancellation_thread_id_ = 0; } ec = asio::error_code(); return ec; } asio::error_code win_iocp_handle_service::cancel( win_iocp_handle_service::implementation_type& impl, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; } else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; if (!cancel_io_ex(impl.handle_, 0)) { DWORD last_error = ::GetLastError(); if (last_error == ERROR_NOT_FOUND) { // ERROR_NOT_FOUND means that there were no operations to be // cancelled. We swallow this error to match the behaviour on other // platforms. ec = asio::error_code(); } else { ec = asio::error_code(last_error, asio::error::get_system_category()); } } else { ec = asio::error_code(); } } else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. ec = asio::error_code(); } else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) { // Asynchronous operations have been started from the current thread only, // so it is safe to try to cancel them using CancelIo. if (!::CancelIo(impl.handle_)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } else { ec = asio::error_code(); } } else { // Asynchronous operations have been started from more than one thread, // so cancellation is not safe. ec = asio::error::operation_not_supported; } return ec; } size_t win_iocp_handle_service::do_write( win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, const asio::const_buffer& buffer, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return 0; } // A request to write 0 bytes on a handle is a no-op. if (asio::buffer_size(buffer) == 0) { ec = asio::error_code(); return 0; } overlapped_wrapper overlapped(ec); if (ec) { return 0; } // Write the data. overlapped.Offset = offset & 0xFFFFFFFF; overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::WriteFile(impl.handle_, asio::buffer_cast(buffer), static_cast(asio::buffer_size(buffer)), 0, &overlapped); if (!ok) { DWORD last_error = ::GetLastError(); if (last_error != ERROR_IO_PENDING) { ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; } } // Wait for the operation to complete. DWORD bytes_transferred = 0; ok = ::GetOverlappedResult(impl.handle_, &overlapped, &bytes_transferred, TRUE); if (!ok) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; } ec = asio::error_code(); return bytes_transferred; } void win_iocp_handle_service::start_write_op( win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, const asio::const_buffer& buffer, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) { iocp_service_.on_completion(op, asio::error::bad_descriptor); } else if (asio::buffer_size(buffer) == 0) { // A request to write 0 bytes on a handle is a no-op. iocp_service_.on_completion(op); } else { DWORD bytes_transferred = 0; op->Offset = offset & 0xFFFFFFFF; op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::WriteFile(impl.handle_, asio::buffer_cast(buffer), static_cast(asio::buffer_size(buffer)), &bytes_transferred, op); DWORD last_error = ::GetLastError(); if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) { iocp_service_.on_completion(op, last_error, bytes_transferred); } else { iocp_service_.on_pending(op); } } } size_t win_iocp_handle_service::do_read( win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, const asio::mutable_buffer& buffer, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return 0; } // A request to read 0 bytes on a stream handle is a no-op. if (asio::buffer_size(buffer) == 0) { ec = asio::error_code(); return 0; } overlapped_wrapper overlapped(ec); if (ec) { return 0; } // Read some data. overlapped.Offset = offset & 0xFFFFFFFF; overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::ReadFile(impl.handle_, asio::buffer_cast(buffer), static_cast(asio::buffer_size(buffer)), 0, &overlapped); if (!ok) { DWORD last_error = ::GetLastError(); if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) { if (last_error == ERROR_HANDLE_EOF) { ec = asio::error::eof; } else { ec = asio::error_code(last_error, asio::error::get_system_category()); } return 0; } } // Wait for the operation to complete. DWORD bytes_transferred = 0; ok = ::GetOverlappedResult(impl.handle_, &overlapped, &bytes_transferred, TRUE); if (!ok) { DWORD last_error = ::GetLastError(); if (last_error == ERROR_HANDLE_EOF) { ec = asio::error::eof; } else { ec = asio::error_code(last_error, asio::error::get_system_category()); } return 0; } ec = asio::error_code(); return bytes_transferred; } void win_iocp_handle_service::start_read_op( win_iocp_handle_service::implementation_type& impl, boost::uint64_t offset, const asio::mutable_buffer& buffer, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) { iocp_service_.on_completion(op, asio::error::bad_descriptor); } else if (asio::buffer_size(buffer) == 0) { // A request to read 0 bytes on a handle is a no-op. iocp_service_.on_completion(op); } else { DWORD bytes_transferred = 0; op->Offset = offset & 0xFFFFFFFF; op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; BOOL ok = ::ReadFile(impl.handle_, asio::buffer_cast(buffer), static_cast(asio::buffer_size(buffer)), &bytes_transferred, op); DWORD last_error = ::GetLastError(); if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) { iocp_service_.on_completion(op, last_error, bytes_transferred); } else { iocp_service_.on_pending(op); } } } void win_iocp_handle_service::update_cancellation_thread_id( win_iocp_handle_service::implementation_type& impl) { if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); } void win_iocp_handle_service::close_for_destruction(implementation_type& impl) { if (is_open(impl)) { ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; impl.safe_cancellation_thread_id_ = 0; } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_iocp_io_service.hpp000066400000000000000000000060241244131713600256240ustar00rootroot00000000000000// // detail/impl/win_iocp_io_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP #define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/detail/call_stack.hpp" #include "asio/detail/completion_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template void win_iocp_io_service::dispatch(Handler handler) { if (call_stack::contains(this)) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } else post(handler); } template void win_iocp_io_service::post(Handler handler) { // Allocate and construct an operation to wrap the handler. typedef completion_handler op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); post_immediate_completion(p.p); p.v = p.p = 0; } template void win_iocp_io_service::add_timer_queue( timer_queue& queue) { do_add_timer_queue(queue); } template void win_iocp_io_service::remove_timer_queue( timer_queue& queue) { do_remove_timer_queue(queue); } template void win_iocp_io_service::schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op) { // If the service has been shut down we silently discard the timer. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) { post_immediate_completion(op); return; } mutex::scoped_lock lock(dispatch_mutex_); bool earliest = queue.enqueue_timer(time, timer, op); work_started(); if (earliest) update_timeout(); } template std::size_t win_iocp_io_service::cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer) { // If the service has been shut down we silently ignore the cancellation. if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) return 0; mutex::scoped_lock lock(dispatch_mutex_); op_queue ops; std::size_t n = queue.cancel_timer(timer, ops); post_deferred_completions(ops); return n; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_iocp_io_service.ipp000066400000000000000000000322251244131713600256270ustar00rootroot00000000000000// // detail/impl/win_iocp_io_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP #define ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/win_iocp_io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { struct win_iocp_io_service::work_finished_on_block_exit { ~work_finished_on_block_exit() { io_service_->work_finished(); } win_iocp_io_service* io_service_; }; struct win_iocp_io_service::timer_thread_function { void operator()() { while (::InterlockedExchangeAdd(&io_service_->shutdown_, 0) == 0) { if (::WaitForSingleObject(io_service_->waitable_timer_.handle, INFINITE) == WAIT_OBJECT_0) { ::InterlockedExchange(&io_service_->dispatch_required_, 1); ::PostQueuedCompletionStatus(io_service_->iocp_.handle, 0, wake_for_dispatch, 0); } } } win_iocp_io_service* io_service_; }; win_iocp_io_service::win_iocp_io_service(asio::io_service& io_service) : asio::detail::service_base(io_service), iocp_(), outstanding_work_(0), stopped_(0), shutdown_(0), dispatch_required_(0) { } void win_iocp_io_service::init(size_t concurrency_hint) { iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, static_cast((std::min)(concurrency_hint, DWORD(~0)))); if (!iocp_.handle) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "iocp"); } } void win_iocp_io_service::shutdown_service() { ::InterlockedExchange(&shutdown_, 1); if (timer_thread_) { LARGE_INTEGER timeout; timeout.QuadPart = 1; ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); } while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) { op_queue ops; timer_queues_.get_all_timers(ops); ops.push(completed_ops_); if (!ops.empty()) { while (win_iocp_operation* op = ops.front()) { ops.pop(); ::InterlockedDecrement(&outstanding_work_); op->destroy(); } } else { DWORD bytes_transferred = 0; dword_ptr_t completion_key = 0; LPOVERLAPPED overlapped = 0; ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, &completion_key, &overlapped, gqcs_timeout); if (overlapped) { ::InterlockedDecrement(&outstanding_work_); static_cast(overlapped)->destroy(); } } } if (timer_thread_) timer_thread_->join(); } asio::error_code win_iocp_io_service::register_handle( HANDLE handle, asio::error_code& ec) { if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } else { ec = asio::error_code(); } return ec; } size_t win_iocp_io_service::run(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { stop(); ec = asio::error_code(); return 0; } call_stack::context ctx(this); size_t n = 0; while (do_one(true, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } size_t win_iocp_io_service::run_one(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { stop(); ec = asio::error_code(); return 0; } call_stack::context ctx(this); return do_one(true, ec); } size_t win_iocp_io_service::poll(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { stop(); ec = asio::error_code(); return 0; } call_stack::context ctx(this); size_t n = 0; while (do_one(false, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } size_t win_iocp_io_service::poll_one(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) { stop(); ec = asio::error_code(); return 0; } call_stack::context ctx(this); return do_one(false, ec); } void win_iocp_io_service::stop() { if (::InterlockedExchange(&stopped_, 1) == 0) { if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "pqcs"); } } } void win_iocp_io_service::post_deferred_completion(win_iocp_operation* op) { // Flag the operation as ready. op->ready_ = 1; // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, overlapped_contains_result, op)) { // Out of resources. Put on completed queue instead. mutex::scoped_lock lock(dispatch_mutex_); completed_ops_.push(op); ::InterlockedExchange(&dispatch_required_, 1); } } void win_iocp_io_service::post_deferred_completions( op_queue& ops) { while (win_iocp_operation* op = ops.front()) { ops.pop(); // Flag the operation as ready. op->ready_ = 1; // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, overlapped_contains_result, op)) { // Out of resources. Put on completed queue instead. mutex::scoped_lock lock(dispatch_mutex_); completed_ops_.push(op); completed_ops_.push(ops); ::InterlockedExchange(&dispatch_required_, 1); } } } void win_iocp_io_service::on_pending(win_iocp_operation* op) { if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) { // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, overlapped_contains_result, op)) { // Out of resources. Put on completed queue instead. mutex::scoped_lock lock(dispatch_mutex_); completed_ops_.push(op); ::InterlockedExchange(&dispatch_required_, 1); } } } void win_iocp_io_service::on_completion(win_iocp_operation* op, DWORD last_error, DWORD bytes_transferred) { // Flag that the operation is ready for invocation. op->ready_ = 1; // Store results in the OVERLAPPED structure. op->Internal = asio::error::get_system_category(); op->Offset = last_error; op->OffsetHigh = bytes_transferred; // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, overlapped_contains_result, op)) { // Out of resources. Put on completed queue instead. mutex::scoped_lock lock(dispatch_mutex_); completed_ops_.push(op); ::InterlockedExchange(&dispatch_required_, 1); } } void win_iocp_io_service::on_completion(win_iocp_operation* op, const asio::error_code& ec, DWORD bytes_transferred) { // Flag that the operation is ready for invocation. op->ready_ = 1; // Store results in the OVERLAPPED structure. op->Internal = ec.category(); op->Offset = ec.value(); op->OffsetHigh = bytes_transferred; // Enqueue the operation on the I/O completion port. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, overlapped_contains_result, op)) { // Out of resources. Put on completed queue instead. mutex::scoped_lock lock(dispatch_mutex_); completed_ops_.push(op); ::InterlockedExchange(&dispatch_required_, 1); } } size_t win_iocp_io_service::do_one(bool block, asio::error_code& ec) { for (;;) { // Try to acquire responsibility for dispatching timers and completed ops. if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) { mutex::scoped_lock lock(dispatch_mutex_); // Dispatch pending timers and operations. op_queue ops; ops.push(completed_ops_); timer_queues_.get_ready_timers(ops); post_deferred_completions(ops); update_timeout(); } // Get the next operation from the queue. DWORD bytes_transferred = 0; dword_ptr_t completion_key = 0; LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, &completion_key, &overlapped, block ? gqcs_timeout : 0); DWORD last_error = ::GetLastError(); if (overlapped) { win_iocp_operation* op = static_cast(overlapped); asio::error_code result_ec(last_error, asio::error::get_system_category()); // We may have been passed the last_error and bytes_transferred in the // OVERLAPPED structure itself. if (completion_key == overlapped_contains_result) { result_ec = asio::error_code(static_cast(op->Offset), static_cast(op->Internal)); bytes_transferred = op->OffsetHigh; } // Otherwise ensure any result has been saved into the OVERLAPPED // structure. else { op->Internal = result_ec.category(); op->Offset = result_ec.value(); op->OffsetHigh = bytes_transferred; } // Dispatch the operation only if ready. The operation may not be ready // if the initiating function (e.g. a call to WSARecv) has not yet // returned. This is because the initiating function still wants access // to the operation's OVERLAPPED structure. if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) { // Ensure the count of outstanding work is decremented on block exit. work_finished_on_block_exit on_exit = { this }; (void)on_exit; op->complete(*this, result_ec, bytes_transferred); ec = asio::error_code(); return 1; } } else if (!ok) { if (last_error != WAIT_TIMEOUT) { ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; } // If we're not polling we need to keep going until we get a real handler. if (block) continue; ec = asio::error_code(); return 0; } else if (completion_key == wake_for_dispatch) { // We have been woken up to try to acquire responsibility for dispatching // timers and completed operations. } else { // The stopped_ flag is always checked to ensure that any leftover // interrupts from a previous run invocation are ignored. if (::InterlockedExchangeAdd(&stopped_, 0) != 0) { // Wake up next thread that is blocked on GetQueuedCompletionStatus. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; } ec = asio::error_code(); return 0; } } } } void win_iocp_io_service::do_add_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(dispatch_mutex_); timer_queues_.insert(&queue); if (!waitable_timer_.handle) { waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); if (waitable_timer_.handle == 0) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "timer"); } LARGE_INTEGER timeout; timeout.QuadPart = -max_timeout_usec; timeout.QuadPart *= 10; ::SetWaitableTimer(waitable_timer_.handle, &timeout, max_timeout_msec, 0, 0, FALSE); } if (!timer_thread_) { timer_thread_function thread_function = { this }; timer_thread_.reset(new thread(thread_function, 65536)); } } void win_iocp_io_service::do_remove_timer_queue(timer_queue_base& queue) { mutex::scoped_lock lock(dispatch_mutex_); timer_queues_.erase(&queue); } void win_iocp_io_service::update_timeout() { if (timer_thread_) { // There's no point updating the waitable timer if the new timeout period // exceeds the maximum timeout. In that case, we might as well wait for the // existing period of the timer to expire. long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); if (timeout_usec < max_timeout_usec) { LARGE_INTEGER timeout; timeout.QuadPart = -timeout_usec; timeout.QuadPart *= 10; ::SetWaitableTimer(waitable_timer_.handle, &timeout, max_timeout_msec, 0, 0, FALSE); } } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_iocp_serial_port_service.ipp000066400000000000000000000122061244131713600275400ustar00rootroot00000000000000// // detail/impl/win_iocp_serial_port_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP #define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) #include #include "asio/detail/win_iocp_serial_port_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_iocp_serial_port_service::win_iocp_serial_port_service( asio::io_service& io_service) : handle_service_(io_service) { } void win_iocp_serial_port_service::shutdown_service() { } asio::error_code win_iocp_serial_port_service::open( win_iocp_serial_port_service::implementation_type& impl, const std::string& device, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } // For convenience, add a leading \\.\ sequence if not already present. std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; // Open a handle to the serial port. ::HANDLE handle = ::CreateFileA(name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if (handle == INVALID_HANDLE_VALUE) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } // Determine the initial serial port parameters. using namespace std; // For memset. ::DCB dcb; memset(&dcb, 0, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); if (!::GetCommState(handle, &dcb)) { DWORD last_error = ::GetLastError(); ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } // Set some default serial port parameters. This implementation does not // support changing these, so they might as well be in a known state. dcb.fBinary = TRUE; // Win32 only supports binary mode. dcb.fDsrSensitivity = FALSE; dcb.fNull = FALSE; // Do not ignore NULL characters. dcb.fAbortOnError = FALSE; // Ignore serial framing errors. if (!::SetCommState(handle, &dcb)) { DWORD last_error = ::GetLastError(); ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } // Set up timeouts so that the serial port will behave similarly to a // network socket. Reads wait for at least one byte, then return with // whatever they have. Writes return once everything is out the door. ::COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = 1; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!::SetCommTimeouts(handle, &timeouts)) { DWORD last_error = ::GetLastError(); ::CloseHandle(handle); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } // We're done. Take ownership of the serial port handle. if (handle_service_.assign(impl, handle, ec)) ::CloseHandle(handle); return ec; } asio::error_code win_iocp_serial_port_service::do_set_option( win_iocp_serial_port_service::implementation_type& impl, win_iocp_serial_port_service::store_function_type store, const void* option, asio::error_code& ec) { using namespace std; // For memcpy. ::DCB dcb; memset(&dcb, 0, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); if (!::GetCommState(handle_service_.native(impl), &dcb)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } if (store(option, dcb, ec)) return ec; if (!::SetCommState(handle_service_.native(impl), &dcb)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } ec = asio::error_code(); return ec; } asio::error_code win_iocp_serial_port_service::do_get_option( const win_iocp_serial_port_service::implementation_type& impl, win_iocp_serial_port_service::load_function_type load, void* option, asio::error_code& ec) const { using namespace std; // For memset. ::DCB dcb; memset(&dcb, 0, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); if (!::GetCommState(handle_service_.native(impl), &dcb)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return ec; } return load(option, dcb, ec); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_iocp_socket_service_base.ipp000066400000000000000000000423321244131713600275020ustar00rootroot00000000000000// // detail/impl/win_iocp_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP #define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/detail/win_iocp_socket_service_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_iocp_socket_service_base::win_iocp_socket_service_base( asio::io_service& io_service) : io_service_(io_service), iocp_service_(use_service(io_service)), reactor_(0), mutex_(), impl_list_(0) { } void win_iocp_socket_service_base::shutdown_service() { // Close all implementations, causing all operations to complete. asio::detail::mutex::scoped_lock lock(mutex_); base_implementation_type* impl = impl_list_; while (impl) { asio::error_code ignored_ec; close_for_destruction(*impl); impl = impl->next_; } } void win_iocp_socket_service_base::construct( win_iocp_socket_service_base::base_implementation_type& impl) { impl.socket_ = invalid_socket; impl.state_ = 0; impl.cancel_token_.reset(); #if defined(ASIO_ENABLE_CANCELIO) impl.safe_cancellation_thread_id_ = 0; #endif // defined(ASIO_ENABLE_CANCELIO) // Insert implementation into linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); impl.next_ = impl_list_; impl.prev_ = 0; if (impl_list_) impl_list_->prev_ = &impl; impl_list_ = &impl; } void win_iocp_socket_service_base::destroy( win_iocp_socket_service_base::base_implementation_type& impl) { close_for_destruction(impl); // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); if (impl_list_ == &impl) impl_list_ = impl.next_; if (impl.prev_) impl.prev_->next_ = impl.next_; if (impl.next_) impl.next_->prev_= impl.prev_; impl.next_ = 0; impl.prev_ = 0; } asio::error_code win_iocp_socket_service_base::close( win_iocp_socket_service_base::base_implementation_type& impl, asio::error_code& ec) { if (is_open(impl)) { // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); if (r) r->close_descriptor(impl.socket_, impl.reactor_data_); } if (socket_ops::close(impl.socket_, impl.state_, false, ec) == 0) { impl.socket_ = invalid_socket; impl.state_ = 0; impl.cancel_token_.reset(); #if defined(ASIO_ENABLE_CANCELIO) impl.safe_cancellation_thread_id_ = 0; #endif // defined(ASIO_ENABLE_CANCELIO) } return ec; } asio::error_code win_iocp_socket_service_base::cancel( win_iocp_socket_service_base::base_implementation_type& impl, asio::error_code& ec) { if (!is_open(impl)) { ec = asio::error::bad_descriptor; return ec; } else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast(sock); if (!cancel_io_ex(sock_as_handle, 0)) { DWORD last_error = ::GetLastError(); if (last_error == ERROR_NOT_FOUND) { // ERROR_NOT_FOUND means that there were no operations to be // cancelled. We swallow this error to match the behaviour on other // platforms. ec = asio::error_code(); } else { ec = asio::error_code(last_error, asio::error::get_system_category()); } } else { ec = asio::error_code(); } } #if defined(ASIO_ENABLE_CANCELIO) else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. ec = asio::error_code(); } else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) { // Asynchronous operations have been started from the current thread only, // so it is safe to try to cancel them using CancelIo. socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast(sock); if (!::CancelIo(sock_as_handle)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); } else { ec = asio::error_code(); } } else { // Asynchronous operations have been started from more than one thread, // so cancellation is not safe. ec = asio::error::operation_not_supported; } #else // defined(ASIO_ENABLE_CANCELIO) else { // Cancellation is not supported as CancelIo may not be used. ec = asio::error::operation_not_supported; } #endif // defined(ASIO_ENABLE_CANCELIO) // Cancel any operations started via the reactor. if (!ec) { reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); if (r) r->cancel_ops(impl.socket_, impl.reactor_data_); } return ec; } asio::error_code win_iocp_socket_service_base::do_open( win_iocp_socket_service_base::base_implementation_type& impl, int family, int type, int protocol, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } socket_holder sock(socket_ops::socket(family, type, protocol, ec)); if (sock.get() == invalid_socket) return ec; HANDLE sock_as_handle = reinterpret_cast(sock.get()); if (iocp_service_.register_handle(sock_as_handle, ec)) return ec; impl.socket_ = sock.release(); switch (type) { case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; default: impl.state_ = 0; break; } impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); ec = asio::error_code(); return ec; } asio::error_code win_iocp_socket_service_base::do_assign( win_iocp_socket_service_base::base_implementation_type& impl, int type, socket_type native_socket, asio::error_code& ec) { if (is_open(impl)) { ec = asio::error::already_open; return ec; } HANDLE sock_as_handle = reinterpret_cast(native_socket); if (iocp_service_.register_handle(sock_as_handle, ec)) return ec; impl.socket_ = native_socket; switch (type) { case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; default: impl.state_ = 0; break; } impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); ec = asio::error_code(); return ec; } void win_iocp_socket_service_base::start_send_op( win_iocp_socket_service_base::base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (noop) iocp_service_.on_completion(op); else if (!is_open(impl)) iocp_service_.on_completion(op, asio::error::bad_descriptor); else { DWORD bytes_transferred = 0; int result = ::WSASend(impl.socket_, buffers, static_cast(buffer_count), &bytes_transferred, flags, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; if (result != 0 && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error, bytes_transferred); else iocp_service_.on_pending(op); } } void win_iocp_socket_service_base::start_send_to_op( win_iocp_socket_service_base::base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, const socket_addr_type* addr, int addrlen, socket_base::message_flags flags, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) iocp_service_.on_completion(op, asio::error::bad_descriptor); else { DWORD bytes_transferred = 0; int result = ::WSASendTo(impl.socket_, buffers, static_cast(buffer_count), &bytes_transferred, flags, addr, addrlen, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; if (result != 0 && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error, bytes_transferred); else iocp_service_.on_pending(op); } } void win_iocp_socket_service_base::start_receive_op( win_iocp_socket_service_base::base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (noop) iocp_service_.on_completion(op); else if (!is_open(impl)) iocp_service_.on_completion(op, asio::error::bad_descriptor); else { DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(impl.socket_, buffers, static_cast(buffer_count), &bytes_transferred, &recv_flags, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_NETNAME_DELETED) last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; if (result != 0 && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error, bytes_transferred); else iocp_service_.on_pending(op); } } void win_iocp_socket_service_base::start_null_buffers_receive_op( win_iocp_socket_service_base::base_implementation_type& impl, socket_base::message_flags flags, reactor_op* op) { if ((impl.state_ & socket_ops::stream_oriented) != 0) { // For stream sockets on Windows, we may issue a 0-byte overlapped // WSARecv to wait until there is data available on the socket. ::WSABUF buf = { 0, 0 }; start_receive_op(impl, &buf, 1, flags, false, op); } else { start_reactor_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, op); } } void win_iocp_socket_service_base::start_receive_from_op( win_iocp_socket_service_base::base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, socket_base::message_flags flags, int* addrlen, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) iocp_service_.on_completion(op, asio::error::bad_descriptor); else { DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecvFrom(impl.socket_, buffers, static_cast(buffer_count), &bytes_transferred, &recv_flags, addr, addrlen, op, 0); DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; if (result != 0 && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error, bytes_transferred); else iocp_service_.on_pending(op); } } void win_iocp_socket_service_base::start_accept_op( win_iocp_socket_service_base::base_implementation_type& impl, bool peer_is_open, socket_holder& new_socket, int family, int type, int protocol, void* output_buffer, DWORD address_length, operation* op) { update_cancellation_thread_id(impl); iocp_service_.work_started(); if (!is_open(impl)) iocp_service_.on_completion(op, asio::error::bad_descriptor); else if (peer_is_open) iocp_service_.on_completion(op, asio::error::already_open); else { asio::error_code ec; new_socket.reset(socket_ops::socket(family, type, protocol, ec)); if (new_socket.get() == invalid_socket) iocp_service_.on_completion(op, ec); else { DWORD bytes_read = 0; BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, 0, address_length, address_length, &bytes_read, op); DWORD last_error = ::WSAGetLastError(); if (!result && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error); else iocp_service_.on_pending(op); } } } void win_iocp_socket_service_base::restart_accept_op( socket_type s, socket_holder& new_socket, int family, int type, int protocol, void* output_buffer, DWORD address_length, operation* op) { new_socket.reset(); iocp_service_.work_started(); asio::error_code ec; new_socket.reset(socket_ops::socket(family, type, protocol, ec)); if (new_socket.get() == invalid_socket) iocp_service_.on_completion(op, ec); else { DWORD bytes_read = 0; BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, 0, address_length, address_length, &bytes_read, op); DWORD last_error = ::WSAGetLastError(); if (!result && last_error != WSA_IO_PENDING) iocp_service_.on_completion(op, last_error); else iocp_service_.on_pending(op); } } void win_iocp_socket_service_base::start_reactor_op( win_iocp_socket_service_base::base_implementation_type& impl, int op_type, reactor_op* op) { reactor& r = get_reactor(); update_cancellation_thread_id(impl); if (is_open(impl)) { r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false); return; } else op->ec_ = asio::error::bad_descriptor; iocp_service_.post_immediate_completion(op); } void win_iocp_socket_service_base::start_connect_op( win_iocp_socket_service_base::base_implementation_type& impl, reactor_op* op, const socket_addr_type* addr, std::size_t addrlen) { reactor& r = get_reactor(); update_cancellation_thread_id(impl); if ((impl.state_ & socket_ops::non_blocking) != 0 || socket_ops::set_internal_non_blocking( impl.socket_, impl.state_, op->ec_)) { if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) { if (op->ec_ == asio::error::in_progress || op->ec_ == asio::error::would_block) { op->ec_ = asio::error_code(); r.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_, op, false); return; } } } r.post_immediate_completion(op); } void win_iocp_socket_service_base::close_for_destruction( win_iocp_socket_service_base::base_implementation_type& impl) { if (is_open(impl)) { // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be // running there. reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); if (r) r->close_descriptor(impl.socket_, impl.reactor_data_); } asio::error_code ignored_ec; socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); impl.socket_ = invalid_socket; impl.state_ = 0; impl.cancel_token_.reset(); #if defined(ASIO_ENABLE_CANCELIO) impl.safe_cancellation_thread_id_ = 0; #endif // defined(ASIO_ENABLE_CANCELIO) } void win_iocp_socket_service_base::update_cancellation_thread_id( win_iocp_socket_service_base::base_implementation_type& impl) { #if defined(ASIO_ENABLE_CANCELIO) if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); #else // defined(ASIO_ENABLE_CANCELIO) (void)impl; #endif // defined(ASIO_ENABLE_CANCELIO) } reactor& win_iocp_socket_service_base::get_reactor() { reactor* r = static_cast( interlocked_compare_exchange_pointer( reinterpret_cast(&reactor_), 0, 0)); if (!r) { r = &(use_service(io_service_)); interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); } return *r; } void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp) { #if defined(_M_IX86) return reinterpret_cast(InterlockedCompareExchange( reinterpret_cast(dest), reinterpret_cast(exch), reinterpret_cast(cmp))); #else return InterlockedCompareExchangePointer(dest, exch, cmp); #endif } void* win_iocp_socket_service_base::interlocked_exchange_pointer( void** dest, void* val) { #if defined(_M_IX86) return reinterpret_cast(InterlockedExchange( reinterpret_cast(dest), reinterpret_cast(val))); #else return InterlockedExchangePointer(dest, val); #endif } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_mutex.ipp000066400000000000000000000034431244131713600236300ustar00rootroot00000000000000// // detail/impl/win_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_MUTEX_IPP #define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include "asio/detail/throw_error.hpp" #include "asio/detail/win_mutex.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_mutex::win_mutex() { int error = do_init(); asio::error_code ec(error, asio::error::get_system_category()); asio::detail::throw_error(ec, "mutex"); } int win_mutex::do_init() { #if defined(__MINGW32__) // Not sure if MinGW supports structured exception handling, so for now // we'll just call the Windows API and hope. # if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); # else if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) return ::GetLastError(); # endif return 0; #else __try { # if defined(UNDER_CE) ::InitializeCriticalSection(&crit_section_); # else if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) return ::GetLastError(); # endif } __except(GetExceptionCode() == STATUS_NO_MEMORY ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return ERROR_OUTOFMEMORY; } return 0; #endif } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_thread.ipp000066400000000000000000000070741244131713600237410ustar00rootroot00000000000000// // detail/impl/win_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_THREAD_IPP #define ASIO_DETAIL_IMPL_WIN_THREAD_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include #include "asio/detail/throw_error.hpp" #include "asio/detail/win_thread.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { win_thread::~win_thread() { ::CloseHandle(thread_); // The exit_event_ handle is deliberately allowed to leak here since it // is an error for the owner of an internal thread not to join() it. } void win_thread::join() { HANDLE handles[2] = { exit_event_, thread_ }; ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); ::CloseHandle(exit_event_); if (terminate_threads()) { ::TerminateThread(thread_, 0); } else { ::QueueUserAPC(apc_function, thread_, 0); ::WaitForSingleObject(thread_, INFINITE); } } void win_thread::start_thread(func_base* arg, unsigned int stack_size) { ::HANDLE entry_event = 0; arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); if (!entry_event) { DWORD last_error = ::GetLastError(); delete arg; asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "thread.entry_event"); } arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); if (!exit_event_) { DWORD last_error = ::GetLastError(); delete arg; asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "thread.exit_event"); } unsigned int thread_id = 0; thread_ = reinterpret_cast(::_beginthreadex(0, stack_size, win_thread_function, arg, 0, &thread_id)); if (!thread_) { DWORD last_error = ::GetLastError(); delete arg; if (entry_event) ::CloseHandle(entry_event); if (exit_event_) ::CloseHandle(exit_event_); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "thread"); } if (entry_event) { ::WaitForSingleObject(entry_event, INFINITE); ::CloseHandle(entry_event); } } unsigned int __stdcall win_thread_function(void* arg) { std::auto_ptr func( static_cast(arg)); ::SetEvent(func->entry_event_); func->run(); // Signal that the thread has finished its work, but rather than returning go // to sleep to put the thread into a well known state. If the thread is being // joined during global object destruction then it may be killed using // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx // call will be interrupted using QueueUserAPC and the thread will shut down // cleanly. HANDLE exit_event = func->exit_event_; func.reset(); ::SetEvent(exit_event); ::SleepEx(INFINITE, TRUE); return 0; } #if defined(WINVER) && (WINVER < 0x0500) void __stdcall apc_function(ULONG) {} #else void __stdcall apc_function(ULONG_PTR) {} #endif } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/win_tss_ptr.ipp000066400000000000000000000024441244131713600241640ustar00rootroot00000000000000// // detail/impl/win_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP #define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include "asio/detail/throw_error.hpp" #include "asio/detail/win_tss_ptr.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { DWORD win_tss_ptr_create() { #if defined(UNDER_CE) enum { out_of_indexes = 0xFFFFFFFF }; #else enum { out_of_indexes = TLS_OUT_OF_INDEXES }; #endif DWORD tss_key = ::TlsAlloc(); if (tss_key == out_of_indexes) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "tss"); } return tss_key; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP percona-galera-3-3.8-3390/asio/asio/detail/impl/winsock_init.ipp000066400000000000000000000032051244131713600243050ustar00rootroot00000000000000// // detail/impl/winsock_init.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP #define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/socket_types.hpp" #include "asio/detail/winsock_init.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { void winsock_init_base::startup(data& d, unsigned char major, unsigned char minor) { if (::InterlockedIncrement(&d.init_count_) == 1) { WSADATA wsa_data; long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); ::InterlockedExchange(&d.result_, result); } } void winsock_init_base::cleanup(data& d) { if (::InterlockedDecrement(&d.init_count_) == 0) { ::WSACleanup(); } } void winsock_init_base::throw_on_error(data& d) { long result = ::InterlockedExchangeAdd(&d.result_, 0); if (result != 0) { asio::error_code ec(result, asio::error::get_system_category()); asio::detail::throw_error(ec, "winsock"); } } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP percona-galera-3-3.8-3390/asio/asio/detail/io_control.hpp000066400000000000000000000052721244131713600230200ustar00rootroot00000000000000// // detail/io_control.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_IO_CONTROL_HPP #define ASIO_DETAIL_IO_CONTROL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace io_control { // IO control command for non-blocking I/O. class non_blocking_io { public: // Default constructor. non_blocking_io() : value_(0) { } // Construct with a specific command value. non_blocking_io(bool value) : value_(value ? 1 : 0) { } // Get the name of the IO control command. // On Linux/PPC this is a 32-bit unsigned value, // GCC 4.4.6 complains about overflow if using signed int unsigned int name() const { return FIONBIO; } // Set the value of the I/O control command. void set(bool value) { value_ = value ? 1 : 0; } // Get the current value of the I/O control command. bool get() const { return value_ != 0; } // Get the address of the command data. detail::ioctl_arg_type* data() { return &value_; } // Get the address of the command data. const detail::ioctl_arg_type* data() const { return &value_; } private: detail::ioctl_arg_type value_; }; // I/O control command for getting number of bytes available. class bytes_readable { public: // Default constructor. bytes_readable() : value_(0) { } // Construct with a specific command value. bytes_readable(std::size_t value) : value_(static_cast(value)) { } // Get the name of the IO control command. int name() const { return FIONREAD; } // Set the value of the I/O control command. void set(std::size_t value) { value_ = static_cast(value); } // Get the current value of the I/O control command. std::size_t get() const { return static_cast(value_); } // Get the address of the command data. detail::ioctl_arg_type* data() { return &value_; } // Get the address of the command data. const detail::ioctl_arg_type* data() const { return &value_; } private: detail::ioctl_arg_type value_; }; } // namespace io_control } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_IO_CONTROL_HPP percona-galera-3-3.8-3390/asio/asio/detail/kqueue_reactor.hpp000066400000000000000000000133701244131713600236650ustar00rootroot00000000000000// // detail/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // 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) // #ifndef ASIO_DETAIL_KQUEUE_REACTOR_HPP #define ASIO_DETAIL_KQUEUE_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_KQUEUE) #include #include #include #include #include "asio/detail/kqueue_reactor_fwd.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/object_pool.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" // Older versions of Mac OS X may not define EV_OOBAND. #if !defined(EV_OOBAND) # define EV_OOBAND EV_FLAG1 #endif // !defined(EV_OOBAND) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class kqueue_reactor : public asio::detail::service_base { public: enum op_types { read_op = 0, write_op = 1, connect_op = 1, except_op = 2, max_ops = 3 }; // Per-descriptor queues. struct descriptor_state { friend class kqueue_reactor; friend class object_pool_access; mutex mutex_; op_queue op_queue_[max_ops]; bool shutdown_; descriptor_state* next_; descriptor_state* prev_; }; // Per-descriptor data. typedef descriptor_state* per_descriptor_data; // Constructor. ASIO_DECL kqueue_reactor(asio::io_service& io_service); // Destructor. ASIO_DECL ~kqueue_reactor(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task. ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. ASIO_DECL int register_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data); // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op) { io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data& descriptor_data, reactor_op* op, bool allow_speculative); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data& descriptor_data); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. ASIO_DECL void close_descriptor(socket_type descriptor, per_descriptor_data& descriptor_data); // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer); // Run the kqueue loop. ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the kqueue loop. ASIO_DECL void interrupt(); private: // Create the kqueue file descriptor. Throws an exception if the descriptor // cannot be created. ASIO_DECL static int do_kqueue_create(); // Helper function to add a new timer queue. ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the kevent call. ASIO_DECL timespec* get_timeout(timespec& ts); // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to internal data. mutex mutex_; // The kqueue file descriptor. int kqueue_fd_; // The interrupter is used to break a blocking kevent call. select_interrupter interrupter_; // The timer queues. timer_queue_set timer_queues_; // Whether the service has been shut down. bool shutdown_; // Mutex to protect access to the registered descriptors. mutex registered_descriptors_mutex_; // Keep track of all registered descriptors. object_pool registered_descriptors_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/kqueue_reactor.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/kqueue_reactor.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_KQUEUE) #endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/kqueue_reactor_fwd.hpp000066400000000000000000000014611244131713600245230ustar00rootroot00000000000000// // detail/kqueue_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // 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) // #ifndef ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP #define ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_KQUEUE) namespace asio { namespace detail { class kqueue_reactor; } // namespace detail } // namespace asio #endif // defined(ASIO_HAS_KQUEUE) #endif // ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/local_free_on_block_exit.hpp000066400000000000000000000024151244131713600256370ustar00rootroot00000000000000// // detail/local_free_on_block_exit.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP #define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class local_free_on_block_exit : private noncopyable { public: // Constructor blocks all signals for the calling thread. explicit local_free_on_block_exit(void* p) : p_(p) { } // Destructor restores the previous signal mask. ~local_free_on_block_exit() { ::LocalFree(p_); } private: void* p_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP percona-galera-3-3.8-3390/asio/asio/detail/macos_fenced_block.hpp000066400000000000000000000020731244131713600244250ustar00rootroot00000000000000// // detail/macos_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP #define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__MACH__) && defined(__APPLE__) #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class macos_fenced_block : private noncopyable { public: // Constructor. macos_fenced_block() { OSMemoryBarrier(); } // Destructor. ~macos_fenced_block() { OSMemoryBarrier(); } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__MACH__) && defined(__APPLE__) #endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/mutex.hpp000066400000000000000000000021411244131713600220030ustar00rootroot00000000000000// // detail/mutex.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_MUTEX_HPP #define ASIO_DETAIL_MUTEX_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_mutex.hpp" #elif defined(BOOST_WINDOWS) # include "asio/detail/win_mutex.hpp" #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_mutex.hpp" #else # error Only Windows and POSIX are supported! #endif namespace asio { namespace detail { #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) typedef null_mutex mutex; #elif defined(BOOST_WINDOWS) typedef win_mutex mutex; #elif defined(BOOST_HAS_PTHREADS) typedef posix_mutex mutex; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_MUTEX_HPP percona-galera-3-3.8-3390/asio/asio/detail/noncopyable.hpp000066400000000000000000000023771244131713600231650ustar00rootroot00000000000000// // detail/noncopyable.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NONCOPYABLE_HPP #define ASIO_DETAIL_NONCOPYABLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) // Redefine the noncopyable class for Borland C++ since that compiler does not // apply the empty base optimisation unless the base class contains a dummy // char data member. class noncopyable { protected: noncopyable() {} ~noncopyable() {} private: noncopyable(const noncopyable&); const noncopyable& operator=(const noncopyable&); char dummy_; }; #else using boost::noncopyable; #endif } // namespace detail using asio::detail::noncopyable; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_NONCOPYABLE_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_buffers_op.hpp000066400000000000000000000043711244131713600240340ustar00rootroot00000000000000// // null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_BUFFERS_OP_HPP #define ASIO_DETAIL_NULL_BUFFERS_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/reactor_op.hpp" namespace asio { namespace detail { template class null_buffers_op : public reactor_op { public: null_buffers_op(Handler handler) : reactor_op(&null_buffers_op::do_perform, &null_buffers_op::do_complete), handler_(handler) { } static bool do_perform(reactor_op*) { return true; } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. null_buffers_op* o(static_cast(base)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(o->handler_, o); // Make the upcall if required. if (owner) { // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); ptr.reset(); asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_NULL_BUFFERS_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_event.hpp000066400000000000000000000025621244131713600230230ustar00rootroot00000000000000// // detail/null_event.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_EVENT_HPP #define ASIO_DETAIL_NULL_EVENT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class null_event : private noncopyable { public: // Constructor. null_event() { } // Destructor. ~null_event() { } // Signal the event. template void signal(Lock&) { } // Signal the event and unlock the mutex. template void signal_and_unlock(Lock&) { } // Reset the event. template void clear(Lock&) { } // Wait for the event to become signalled. template void wait(Lock&) { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_NULL_EVENT_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_fenced_block.hpp000066400000000000000000000015431244131713600242760ustar00rootroot00000000000000// // detail/null_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_FENCED_BLOCK_HPP #define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class null_fenced_block : private noncopyable { public: // Constructor. null_fenced_block() { } // Destructor. ~null_fenced_block() { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_mutex.hpp000066400000000000000000000023011244131713600230330ustar00rootroot00000000000000// // detail/null_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_MUTEX_HPP #define ASIO_DETAIL_NULL_MUTEX_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class null_mutex : private noncopyable { public: typedef asio::detail::scoped_lock scoped_lock; // Constructor. null_mutex() { } // Destructor. ~null_mutex() { } // Lock the mutex. void lock() { } // Unlock the mutex. void unlock() { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_NULL_MUTEX_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_signal_blocker.hpp000066400000000000000000000027521244131713600246610ustar00rootroot00000000000000// // detail/null_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP #define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) \ || defined(ASIO_DISABLE_THREADS) \ || defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class null_signal_blocker : private noncopyable { public: // Constructor blocks all signals for the calling thread. null_signal_blocker() { } // Destructor restores the previous signal mask. ~null_signal_blocker() { } // Block all signals for the calling thread. void block() { } // Restore the previous signal mask. void unblock() { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_HAS_THREADS) // || defined(ASIO_DISABLE_THREADS) // || defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) #endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_thread.hpp000066400000000000000000000024231244131713600231450ustar00rootroot00000000000000// // detail/null_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_THREAD_HPP #define ASIO_DETAIL_NULL_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class null_thread : private noncopyable { public: // Constructor. template null_thread(Function, unsigned int = 0) { asio::detail::throw_error( asio::error::operation_not_supported, "thread"); } // Destructor. ~null_thread() { } // Wait for the thread to exit. void join() { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_NULL_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/detail/null_tss_ptr.hpp000066400000000000000000000023371244131713600234000ustar00rootroot00000000000000// // detail/null_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_NULL_TSS_PTR_HPP #define ASIO_DETAIL_NULL_TSS_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class null_tss_ptr : private noncopyable { public: // Constructor. null_tss_ptr() : value_(0) { } // Destructor. ~null_tss_ptr() { } // Get the value. operator T*() const { return value_; } // Set the value. void operator=(T* value) { value_ = value; } private: T* value_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_NULL_TSS_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/object_pool.hpp000066400000000000000000000054601244131713600231470ustar00rootroot00000000000000// // detail/object_pool.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_OBJECT_POOL_HPP #define ASIO_DETAIL_OBJECT_POOL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class object_pool; class object_pool_access { public: template static Object* create() { return new Object; } template static void destroy(Object* o) { delete o; } template static Object*& next(Object* o) { return o->next_; } template static Object*& prev(Object* o) { return o->prev_; } }; template class object_pool : private noncopyable { public: // Constructor. object_pool() : live_list_(0), free_list_(0) { } // Destructor destroys all objects. ~object_pool() { destroy_list(live_list_); destroy_list(free_list_); } // Get the object at the start of the live list. Object* first() { return live_list_; } // Allocate a new object. Object* alloc() { Object* o = free_list_; if (o) free_list_ = object_pool_access::next(free_list_); else o = object_pool_access::create(); object_pool_access::next(o) = live_list_; object_pool_access::prev(o) = 0; if (live_list_) object_pool_access::prev(live_list_) = o; live_list_ = o; return o; } // Free an object. Moves it to the free list. No destructors are run. void free(Object* o) { if (live_list_ == o) live_list_ = object_pool_access::next(o); if (object_pool_access::prev(o)) { object_pool_access::next(object_pool_access::prev(o)) = object_pool_access::next(o); } if (object_pool_access::next(o)) { object_pool_access::prev(object_pool_access::next(o)) = object_pool_access::prev(o); } object_pool_access::next(o) = free_list_; object_pool_access::prev(o) = 0; free_list_ = o; } private: // Helper function to destroy all elements in a list. void destroy_list(Object* list) { while (list) { Object* o = list; list = object_pool_access::next(o); object_pool_access::destroy(o); } } // The list of live objects. Object* live_list_; // The free list. Object* free_list_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_OBJECT_POOL_HPP percona-galera-3-3.8-3390/asio/asio/detail/old_win_sdk_compat.hpp000066400000000000000000000171261244131713600245110ustar00rootroot00000000000000// // detail/old_win_sdk_compat.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP #define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Guess whether we are building against on old Platform SDK. #if !defined(IN6ADDR_ANY_INIT) #define ASIO_HAS_OLD_WIN_SDK 1 #endif // !defined(IN6ADDR_ANY_INIT) #if defined(ASIO_HAS_OLD_WIN_SDK) // Emulation of types that are missing from old Platform SDKs. // // N.B. this emulation is also used if building for a Windows 2000 target with // a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support // in that case. #include "asio/detail/push_options.hpp" namespace asio { namespace detail { enum { sockaddr_storage_maxsize = 128, // Maximum size. sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), sockaddr_storage_pad2size = (sockaddr_storage_maxsize - (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) }; struct sockaddr_storage_emulation { short ss_family; char __ss_pad1[sockaddr_storage_pad1size]; __int64 __ss_align; char __ss_pad2[sockaddr_storage_pad2size]; }; struct in6_addr_emulation { union { u_char Byte[16]; u_short Word[8]; } u; }; #if !defined(s6_addr) # define _S6_un u # define _S6_u8 Byte # define s6_addr _S6_un._S6_u8 #endif // !defined(s6_addr) struct sockaddr_in6_emulation { short sin6_family; u_short sin6_port; u_long sin6_flowinfo; in6_addr_emulation sin6_addr; u_long sin6_scope_id; }; struct ipv6_mreq_emulation { in6_addr_emulation ipv6mr_multiaddr; unsigned int ipv6mr_interface; }; #if !defined(IN6ADDR_ANY_INIT) # define IN6ADDR_ANY_INIT { 0 } #endif #if !defined(IN6ADDR_LOOPBACK_INIT) # define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } #endif struct addrinfo_emulation { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char* ai_canonname; sockaddr* ai_addr; addrinfo_emulation* ai_next; }; #if !defined(AI_PASSIVE) # define AI_PASSIVE 0x1 #endif #if !defined(AI_CANONNAME) # define AI_CANONNAME 0x2 #endif #if !defined(AI_NUMERICHOST) # define AI_NUMERICHOST 0x4 #endif #if !defined(EAI_AGAIN) # define EAI_AGAIN WSATRY_AGAIN #endif #if !defined(EAI_BADFLAGS) # define EAI_BADFLAGS WSAEINVAL #endif #if !defined(EAI_FAIL) # define EAI_FAIL WSANO_RECOVERY #endif #if !defined(EAI_FAMILY) # define EAI_FAMILY WSAEAFNOSUPPORT #endif #if !defined(EAI_MEMORY) # define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY #endif #if !defined(EAI_NODATA) # define EAI_NODATA WSANO_DATA #endif #if !defined(EAI_NONAME) # define EAI_NONAME WSAHOST_NOT_FOUND #endif #if !defined(EAI_SERVICE) # define EAI_SERVICE WSATYPE_NOT_FOUND #endif #if !defined(EAI_SOCKTYPE) # define EAI_SOCKTYPE WSAESOCKTNOSUPPORT #endif #if !defined(NI_NOFQDN) # define NI_NOFQDN 0x01 #endif #if !defined(NI_NUMERICHOST) # define NI_NUMERICHOST 0x02 #endif #if !defined(NI_NAMEREQD) # define NI_NAMEREQD 0x04 #endif #if !defined(NI_NUMERICSERV) # define NI_NUMERICSERV 0x08 #endif #if !defined(NI_DGRAM) # define NI_DGRAM 0x10 #endif #if !defined(IPPROTO_IPV6) # define IPPROTO_IPV6 41 #endif #if !defined(IPV6_UNICAST_HOPS) # define IPV6_UNICAST_HOPS 4 #endif #if !defined(IPV6_MULTICAST_IF) # define IPV6_MULTICAST_IF 9 #endif #if !defined(IPV6_MULTICAST_HOPS) # define IPV6_MULTICAST_HOPS 10 #endif #if !defined(IPV6_MULTICAST_LOOP) # define IPV6_MULTICAST_LOOP 11 #endif #if !defined(IPV6_JOIN_GROUP) # define IPV6_JOIN_GROUP 12 #endif #if !defined(IPV6_LEAVE_GROUP) # define IPV6_LEAVE_GROUP 13 #endif inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0) && (a->s6_addr[1] == 0) && (a->s6_addr[2] == 0) && (a->s6_addr[3] == 0) && (a->s6_addr[4] == 0) && (a->s6_addr[5] == 0) && (a->s6_addr[6] == 0) && (a->s6_addr[7] == 0) && (a->s6_addr[8] == 0) && (a->s6_addr[9] == 0) && (a->s6_addr[10] == 0) && (a->s6_addr[11] == 0) && (a->s6_addr[12] == 0) && (a->s6_addr[13] == 0) && (a->s6_addr[14] == 0) && (a->s6_addr[15] == 0)); } inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0) && (a->s6_addr[1] == 0) && (a->s6_addr[2] == 0) && (a->s6_addr[3] == 0) && (a->s6_addr[4] == 0) && (a->s6_addr[5] == 0) && (a->s6_addr[6] == 0) && (a->s6_addr[7] == 0) && (a->s6_addr[8] == 0) && (a->s6_addr[9] == 0) && (a->s6_addr[10] == 0) && (a->s6_addr[11] == 0) && (a->s6_addr[12] == 0) && (a->s6_addr[13] == 0) && (a->s6_addr[14] == 0) && (a->s6_addr[15] == 1)); } inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a) { return (a->s6_addr[0] == 0xff); } inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80)); } inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0)); } inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0) && (a->s6_addr[1] == 0) && (a->s6_addr[2] == 0) && (a->s6_addr[3] == 0) && (a->s6_addr[4] == 0) && (a->s6_addr[5] == 0) && (a->s6_addr[6] == 0) && (a->s6_addr[7] == 0) && (a->s6_addr[8] == 0) && (a->s6_addr[9] == 0) && (a->s6_addr[10] == 0xff) && (a->s6_addr[11] == 0xff)); } inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a) { return ((a->s6_addr[0] == 0) && (a->s6_addr[1] == 0) && (a->s6_addr[2] == 0) && (a->s6_addr[3] == 0) && (a->s6_addr[4] == 0) && (a->s6_addr[5] == 0) && (a->s6_addr[6] == 0) && (a->s6_addr[7] == 0) && (a->s6_addr[8] == 0) && (a->s6_addr[9] == 0) && (a->s6_addr[10] == 0xff) && (a->s6_addr[11] == 0xff) && !((a->s6_addr[12] == 0) && (a->s6_addr[13] == 0) && (a->s6_addr[14] == 0) && ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1)))); } inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1); } inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2); } inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5); } inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8); } inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) { return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_OLD_WIN_SDK) // Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. #if !defined(IPV6_V6ONLY) # define IPV6_V6ONLY 27 #endif // Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. #if !defined(IPPROTO_ICMPV6) # define IPPROTO_ICMPV6 58 #endif #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP percona-galera-3-3.8-3390/asio/asio/detail/op_queue.hpp000066400000000000000000000060121244131713600224640ustar00rootroot00000000000000// // detail/op_queue.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_OP_QUEUE_HPP #define ASIO_DETAIL_OP_QUEUE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class op_queue; class op_queue_access { public: template static Operation* next(Operation* o) { return static_cast(o->next_); } template static void next(Operation1*& o1, Operation2* o2) { o1->next_ = o2; } template static void destroy(Operation* o) { o->destroy(); } template static Operation*& front(op_queue& q) { return q.front_; } template static Operation*& back(op_queue& q) { return q.back_; } }; template class op_queue : private noncopyable { public: // Constructor. op_queue() : front_(0), back_(0) { } // Destructor destroys all operations. ~op_queue() { while (Operation* op = front_) { pop(); op_queue_access::destroy(op); } } // Get the operation at the front of the queue. Operation* front() { return front_; } // Pop an operation from the front of the queue. void pop() { if (front_) { Operation* tmp = front_; front_ = op_queue_access::next(front_); if (front_ == 0) back_ = 0; op_queue_access::next(tmp, static_cast(0)); } } // Push an operation on to the back of the queue. void push(Operation* h) { op_queue_access::next(h, static_cast(0)); if (back_) { op_queue_access::next(back_, h); back_ = h; } else { front_ = back_ = h; } } // Push all operations from another queue on to the back of the queue. The // source queue may contain operations of a derived type. template void push(op_queue& q) { if (Operation* other_front = op_queue_access::front(q)) { if (back_) op_queue_access::next(back_, other_front); else front_ = other_front; back_ = op_queue_access::back(q); op_queue_access::front(q) = 0; op_queue_access::back(q) = 0; } } // Whether the queue is empty. bool empty() const { return front_ == 0; } private: friend class op_queue_access; // The front of the queue. Operation* front_; // The back of the queue. Operation* back_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_OP_QUEUE_HPP percona-galera-3-3.8-3390/asio/asio/detail/operation.hpp000066400000000000000000000015701244131713600226460ustar00rootroot00000000000000// // detail/operation.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_OPERATION_HPP #define ASIO_DETAIL_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_operation.hpp" #else # include "asio/detail/task_io_service_operation.hpp" #endif namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) typedef win_iocp_operation operation; #else typedef task_io_service_operation operation; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_OPERATION_HPP percona-galera-3-3.8-3390/asio/asio/detail/pipe_select_interrupter.hpp000066400000000000000000000041011244131713600255760ustar00rootroot00000000000000// // detail/pipe_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP #define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) #if !defined(__CYGWIN__) #if !defined(__SYMBIAN32__) #if !defined(ASIO_HAS_EVENTFD) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class pipe_select_interrupter { public: // Constructor. ASIO_DECL pipe_select_interrupter(); // Destructor. ASIO_DECL ~pipe_select_interrupter(); // Interrupt the select call. ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. int read_descriptor() const { return read_descriptor_; } private: // The read end of a connection used to interrupt the select call. This file // descriptor is passed to select such that when it is time to stop, a single // byte will be written on the other end of the connection and this // descriptor will become readable. int read_descriptor_; // The write end of a connection used to interrupt the select call. A single // byte may be written to this to wake up the select which is waiting for the // other end to become readable. int write_descriptor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/pipe_select_interrupter.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(ASIO_HAS_EVENTFD) #endif // !defined(__SYMBIAN32__) #endif // !defined(__CYGWIN__) #endif // !defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/pop_options.hpp000066400000000000000000000030501244131713600232120ustar00rootroot00000000000000// // detail/pop_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // // No header guard #if defined(__COMO__) // Comeau C++ #elif defined(__DMC__) // Digital Mars C++ #elif defined(__INTEL_COMPILER) || defined(__ICL) \ || defined(__ICC) || defined(__ECC) // Intel C++ #elif defined(__GNUC__) // GNU C++ # if defined(__MINGW32__) || defined(__CYGWIN__) # pragma pack (pop) # endif # if defined(__OBJC__) # if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) # if defined(ASIO_OBJC_WORKAROUND) # undef Protocol # undef id # undef ASIO_OBJC_WORKAROUND # endif # endif # endif #elif defined(__KCC) // Kai C++ #elif defined(__sgi) // SGI MIPSpro C++ #elif defined(__DECCXX) // Compaq Tru64 Unix cxx #elif defined(__ghs) // Greenhills C++ #elif defined(__BORLANDC__) // Borland C++ # pragma option pop # pragma nopushoptwarn # pragma nopackwarning #elif defined(__MWERKS__) // Metrowerks CodeWarrior #elif defined(__SUNPRO_CC) // Sun Workshop Compiler C++ #elif defined(__HP_aCC) // HP aCC #elif defined(__MRC__) || defined(__SC__) // MPW MrCpp or SCpp #elif defined(__IBMCPP__) // IBM Visual Age #elif defined(_MSC_VER) // Microsoft Visual C++ // // Must remain the last #elif since some other vendors (Metrowerks, for example) // also #define _MSC_VER # pragma warning (pop) # pragma pack (pop) #endif percona-galera-3-3.8-3390/asio/asio/detail/posix_event.hpp000066400000000000000000000041311244131713600232050ustar00rootroot00000000000000// // detail/posix_event.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_EVENT_HPP #define ASIO_DETAIL_POSIX_EVENT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class posix_event : private noncopyable { public: // Constructor. ASIO_DECL posix_event(); // Destructor. ~posix_event() { ::pthread_cond_destroy(&cond_); } // Signal the event. template void signal(Lock& lock) { BOOST_ASSERT(lock.locked()); (void)lock; signalled_ = true; ::pthread_cond_signal(&cond_); // Ignore EINVAL. } // Signal the event and unlock the mutex. template void signal_and_unlock(Lock& lock) { BOOST_ASSERT(lock.locked()); signalled_ = true; lock.unlock(); ::pthread_cond_signal(&cond_); // Ignore EINVAL. } // Reset the event. template void clear(Lock& lock) { BOOST_ASSERT(lock.locked()); (void)lock; signalled_ = false; } // Wait for the event to become signalled. template void wait(Lock& lock) { BOOST_ASSERT(lock.locked()); while (!signalled_) ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. } private: ::pthread_cond_t cond_; bool signalled_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/posix_event.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_POSIX_EVENT_HPP percona-galera-3-3.8-3390/asio/asio/detail/posix_fd_set_adapter.hpp000066400000000000000000000033671244131713600250420ustar00rootroot00000000000000// // detail/posix_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP #define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. class posix_fd_set_adapter { public: posix_fd_set_adapter() : max_descriptor_(invalid_socket) { using namespace std; // Needed for memset on Solaris. FD_ZERO(&fd_set_); } bool set(socket_type descriptor) { if (descriptor < (socket_type)FD_SETSIZE) { if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_) max_descriptor_ = descriptor; FD_SET(descriptor, &fd_set_); return true; } return false; } bool is_set(socket_type descriptor) const { return FD_ISSET(descriptor, &fd_set_) != 0; } operator fd_set*() { return &fd_set_; } socket_type max_descriptor() const { return max_descriptor_; } private: mutable fd_set fd_set_; socket_type max_descriptor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/posix_mutex.hpp000066400000000000000000000031311244131713600232250ustar00rootroot00000000000000// // detail/posix_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_MUTEX_HPP #define ASIO_DETAIL_POSIX_MUTEX_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class posix_event; class posix_mutex : private noncopyable { public: typedef asio::detail::scoped_lock scoped_lock; // Constructor. ASIO_DECL posix_mutex(); // Destructor. ~posix_mutex() { ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. } // Lock the mutex. void lock() { (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. } // Unlock the mutex. void unlock() { (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. } private: friend class posix_event; ::pthread_mutex_t mutex_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/posix_mutex.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_POSIX_MUTEX_HPP percona-galera-3-3.8-3390/asio/asio/detail/posix_signal_blocker.hpp000066400000000000000000000036401244131713600250460ustar00rootroot00000000000000// // detail/posix_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP #define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include #include #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class posix_signal_blocker : private noncopyable { public: // Constructor blocks all signals for the calling thread. posix_signal_blocker() : blocked_(false) { sigset_t new_mask; sigfillset(&new_mask); blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); } // Destructor restores the previous signal mask. ~posix_signal_blocker() { if (blocked_) pthread_sigmask(SIG_SETMASK, &old_mask_, 0); } // Block all signals for the calling thread. void block() { if (!blocked_) { sigset_t new_mask; sigfillset(&new_mask); blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); } } // Restore the previous signal mask. void unblock() { if (blocked_) blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0); } private: // Have signals been blocked. bool blocked_; // The previous signal mask. sigset_t old_mask_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP percona-galera-3-3.8-3390/asio/asio/detail/posix_thread.hpp000066400000000000000000000037021244131713600233360ustar00rootroot00000000000000// // detail/posix_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_THREAD_HPP #define ASIO_DETAIL_POSIX_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { extern "C" { ASIO_DECL void* asio_detail_posix_thread_function(void* arg); } class posix_thread : private noncopyable { public: // Constructor. template posix_thread(Function f) : joined_(false) { start_thread(new func(f)); } // Destructor. ASIO_DECL ~posix_thread(); // Wait for the thread to exit. ASIO_DECL void join(); private: friend void* asio_detail_posix_thread_function(void* arg); class func_base { public: virtual ~func_base() {} virtual void run() = 0; }; struct auto_func_base_ptr { func_base* ptr; ~auto_func_base_ptr() { delete ptr; } }; template class func : public func_base { public: func(Function f) : f_(f) { } virtual void run() { f_(); } private: Function f_; }; ASIO_DECL void start_thread(func_base* arg); ::pthread_t thread_; bool joined_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/posix_thread.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_POSIX_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/detail/posix_tss_ptr.hpp000066400000000000000000000033321244131713600235640ustar00rootroot00000000000000// // detail/posix_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_POSIX_TSS_PTR_HPP #define ASIO_DETAIL_POSIX_TSS_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper function to create thread-specific storage. ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); template class posix_tss_ptr : private noncopyable { public: // Constructor. posix_tss_ptr() { posix_tss_ptr_create(tss_key_); } // Destructor. ~posix_tss_ptr() { ::pthread_key_delete(tss_key_); } // Get the value. operator T*() const { return static_cast(::pthread_getspecific(tss_key_)); } // Set the value. void operator=(T* value) { ::pthread_setspecific(tss_key_, value); } private: // Thread-specific storage to allow unlocked access to determine whether a // thread is a member of the pool. pthread_key_t tss_key_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/posix_tss_ptr.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_HAS_PTHREADS) && !defined(ASIO_DISABLE_THREADS) #endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/push_options.hpp000066400000000000000000000052461244131713600234040ustar00rootroot00000000000000// // detail/push_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // // No header guard #if defined(__COMO__) // Comeau C++ #elif defined(__DMC__) // Digital Mars C++ #elif defined(__INTEL_COMPILER) || defined(__ICL) \ || defined(__ICC) || defined(__ECC) // Intel C++ #elif defined(__GNUC__) // GNU C++ # if defined(__MINGW32__) || defined(__CYGWIN__) # pragma pack (push, 8) # endif # if defined(__OBJC__) # if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) # if !defined(ASIO_DISABLE_OBJC_WORKAROUND) # if !defined(Protocol) && !defined(id) # define Protocol cpp_Protocol # define id cpp_id # define ASIO_OBJC_WORKAROUND # endif # endif # endif # endif #elif defined(__KCC) // Kai C++ #elif defined(__sgi) // SGI MIPSpro C++ #elif defined(__DECCXX) // Compaq Tru64 Unix cxx #elif defined(__ghs) // Greenhills C++ #elif defined(__BORLANDC__) // Borland C++ # pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- # pragma nopushoptwarn # pragma nopackwarning # if !defined(__MT__) # error Multithreaded RTL must be selected. # endif // !defined(__MT__) #elif defined(__MWERKS__) // Metrowerks CodeWarrior #elif defined(__SUNPRO_CC) // Sun Workshop Compiler C++ #elif defined(__HP_aCC) // HP aCC #elif defined(__MRC__) || defined(__SC__) // MPW MrCpp or SCpp #elif defined(__IBMCPP__) // IBM Visual Age #elif defined(_MSC_VER) // Microsoft Visual C++ // // Must remain the last #elif since some other vendors (Metrowerks, for example) // also #define _MSC_VER # pragma warning (disable:4103) # pragma warning (push) # pragma warning (disable:4127) # pragma warning (disable:4244) # pragma warning (disable:4355) # pragma warning (disable:4512) # pragma warning (disable:4675) # if defined(_M_IX86) && defined(_Wp64) // The /Wp64 option is broken. If you want to check 64 bit portability, use a // 64 bit compiler! # pragma warning (disable:4311) # pragma warning (disable:4312) # endif // defined(_M_IX86) && defined(_Wp64) # pragma pack (push, 8) // Note that if the /Og optimisation flag is enabled with MSVC6, the compiler // has a tendency to incorrectly optimise away some calls to member template // functions, even though those functions contain code that should not be // optimised away! Therefore we will always disable this optimisation option // for the MSVC6 compiler. # if (_MSC_VER < 1300) # pragma optimize ("g", off) # endif # if !defined(_MT) # error Multithreaded RTL must be selected. # endif // !defined(_MT) #endif percona-galera-3-3.8-3390/asio/asio/detail/reactive_descriptor_service.hpp000066400000000000000000000200121244131713600264160ustar00rootroot00000000000000// // detail/reactive_descriptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP #define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/buffer.hpp" #include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/descriptor_ops.hpp" #include "asio/detail/descriptor_read_op.hpp" #include "asio/detail/descriptor_write_op.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/reactive_null_buffers_op.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class reactive_descriptor_service { public: // The native type of a descriptor. typedef int native_type; // The implementation type of the descriptor. class implementation_type : private asio::detail::noncopyable { public: // Default constructor. implementation_type() : descriptor_(-1), state_(0) { } private: // Only this service will have access to the internal values. friend class reactive_descriptor_service; // The native descriptor representation. int descriptor_; // The current state of the descriptor. descriptor_ops::state_type state_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; }; // Constructor. ASIO_DECL reactive_descriptor_service( asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new descriptor implementation. ASIO_DECL void construct(implementation_type& impl); // Destroy a descriptor implementation. ASIO_DECL void destroy(implementation_type& impl); // Assign a native descriptor to a descriptor implementation. ASIO_DECL asio::error_code assign(implementation_type& impl, const native_type& native_descriptor, asio::error_code& ec); // Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const { return impl.descriptor_ != -1; } // Destroy a descriptor implementation. ASIO_DECL asio::error_code close(implementation_type& impl, asio::error_code& ec); // Get the native descriptor representation. native_type native(const implementation_type& impl) const { return impl.descriptor_; } // Cancel all operations associated with the descriptor. ASIO_DECL asio::error_code cancel(implementation_type& impl, asio::error_code& ec); // Perform an IO control command on the descriptor. template asio::error_code io_control(implementation_type& impl, IO_Control_Command& command, asio::error_code& ec) { descriptor_ops::ioctl(impl.descriptor_, impl.state_, command.name(), static_cast(command.data()), ec); return ec; } // Write some data to the descriptor. template size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return descriptor_ops::sync_write(impl.descriptor_, impl.state_, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be written without blocking. size_t write_some(implementation_type& impl, const null_buffers&, asio::error_code& ec) { // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, ec); return 0; } // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef descriptor_write_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); start_op(impl, reactor::write_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. template void async_write_some(implementation_type& impl, const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); start_op(impl, reactor::write_op, p.p, false, false); p.v = p.p = 0; } // Read some data from the stream. Returns the number of bytes read. template size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return descriptor_ops::sync_read(impl.descriptor_, impl.state_, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be read without blocking. size_t read_some(implementation_type& impl, const null_buffers&, asio::error_code& ec) { // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, ec); return 0; } // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef descriptor_read_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); start_op(impl, reactor::read_op, p.p, true, buffer_sequence_adapter::all_empty(buffers)); p.v = p.p = 0; } // Wait until data can be read without blocking. template void async_read_some(implementation_type& impl, const null_buffers&, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); start_op(impl, reactor::read_op, p.p, false, false); p.v = p.p = 0; } private: // Start the asynchronous operation. ASIO_DECL void start_op(implementation_type& impl, int op_type, reactor_op* op, bool non_blocking, bool noop); // The selector that performs event demultiplexing for the service. reactor& reactor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/reactive_descriptor_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_null_buffers_op.hpp000066400000000000000000000047161244131713600257210ustar00rootroot00000000000000// // detail/reactive_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP #define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_null_buffers_op : public reactor_op { public: ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); reactive_null_buffers_op(Handler handler) : reactor_op(&reactive_null_buffers_op::do_perform, &reactive_null_buffers_op::do_complete), handler_(handler) { } static bool do_perform(reactor_op*) { return true; } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_null_buffers_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_serial_port_service.hpp000066400000000000000000000157231244131713600266000ustar00rootroot00000000000000// // detail/reactive_serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP #define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/serial_port_base.hpp" #include "asio/detail/descriptor_ops.hpp" #include "asio/detail/reactive_descriptor_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Extend reactive_descriptor_service to provide serial port support. class reactive_serial_port_service { public: // The native type of a serial port. typedef reactive_descriptor_service::native_type native_type; // The implementation type of the serial port. typedef reactive_descriptor_service::implementation_type implementation_type; ASIO_DECL reactive_serial_port_service( asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new serial port implementation. void construct(implementation_type& impl) { descriptor_service_.construct(impl); } // Destroy a serial port implementation. void destroy(implementation_type& impl) { descriptor_service_.destroy(impl); } // Open the serial port using the specified device name. ASIO_DECL asio::error_code open(implementation_type& impl, const std::string& device, asio::error_code& ec); // Assign a native descriptor to a serial port implementation. asio::error_code assign(implementation_type& impl, const native_type& native_descriptor, asio::error_code& ec) { return descriptor_service_.assign(impl, native_descriptor, ec); } // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return descriptor_service_.is_open(impl); } // Destroy a serial port implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return descriptor_service_.close(impl, ec); } // Get the native serial port representation. native_type native(implementation_type& impl) { return descriptor_service_.native(impl); } // Cancel all operations associated with the serial port. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return descriptor_service_.cancel(impl, ec); } // Set an option on the serial port. template asio::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, asio::error_code& ec) { return do_set_option(impl, &reactive_serial_port_service::store_option, &option, ec); } // Get an option from the serial port. template asio::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, asio::error_code& ec) const { return do_get_option(impl, &reactive_serial_port_service::load_option, &option, ec); } // Send a break sequence to the serial port. asio::error_code send_break(implementation_type& impl, asio::error_code& ec) { errno = 0; descriptor_ops::error_wrapper(::tcsendbreak( descriptor_service_.native(impl), 0), ec); return ec; } // Write the given data. Returns the number of bytes sent. template size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return descriptor_service_.write_some(impl, buffers, ec); } // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { descriptor_service_.async_write_some(impl, buffers, handler); } // Read some data. Returns the number of bytes received. template size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return descriptor_service_.read_some(impl, buffers, ec); } // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { descriptor_service_.async_read_some(impl, buffers, handler); } private: // Function pointer type for storing a serial port option. typedef asio::error_code (*store_function_type)( const void*, termios&, asio::error_code&); // Helper function template to store a serial port option. template static asio::error_code store_option(const void* option, termios& storage, asio::error_code& ec) { return static_cast(option)->store( storage, ec); } // Helper function to set a serial port option. ASIO_DECL asio::error_code do_set_option( implementation_type& impl, store_function_type store, const void* option, asio::error_code& ec); // Function pointer type for loading a serial port option. typedef asio::error_code (*load_function_type)( void*, const termios&, asio::error_code&); // Helper function template to load a serial port option. template static asio::error_code load_option(void* option, const termios& storage, asio::error_code& ec) { return static_cast(option)->load(storage, ec); } // Helper function to get a serial port option. ASIO_DECL asio::error_code do_get_option( const implementation_type& impl, load_function_type load, void* option, asio::error_code& ec) const; // The implementation used for initiating asynchronous operations. reactive_descriptor_service descriptor_service_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/reactive_serial_port_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // defined(ASIO_HAS_SERIAL_PORT) #endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_accept_op.hpp000066400000000000000000000102531244131713600260330ustar00rootroot00000000000000// // detail/reactive_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_accept_op_base : public reactor_op { public: reactive_socket_accept_op_base(socket_type socket, socket_ops::state_type state, Socket& peer, const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, func_type complete_func) : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), socket_(socket), state_(state), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint) { } static bool do_perform(reactor_op* base) { reactive_socket_accept_op_base* o( static_cast(base)); std::size_t addrlen = o->peer_endpoint_ ? o->peer_endpoint_->capacity() : 0; socket_type new_socket = invalid_socket; bool result = socket_ops::non_blocking_accept(o->socket_, o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, o->peer_endpoint_ ? &addrlen : 0, o->ec_, new_socket); // On success, assign new connection to peer socket object. if (new_socket >= 0) { socket_holder new_socket_holder(new_socket); if (o->peer_endpoint_) o->peer_endpoint_->resize(addrlen); if (!o->peer_.assign(o->protocol_, new_socket, o->ec_)) new_socket_holder.release(); } return result; } private: socket_type socket_; socket_ops::state_type state_; Socket& peer_; Protocol protocol_; typename Protocol::endpoint* peer_endpoint_; }; template class reactive_socket_accept_op : public reactive_socket_accept_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); reactive_socket_accept_op(socket_type socket, socket_ops::state_type state, Socket& peer, const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, Handler handler) : reactive_socket_accept_op_base(socket, state, peer, protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_accept_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder1 handler(o->handler_, o->ec_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_connect_op.hpp000066400000000000000000000056741244131713600262400ustar00rootroot00000000000000// // detail/reactive_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class reactive_socket_connect_op_base : public reactor_op { public: reactive_socket_connect_op_base(socket_type socket, func_type complete_func) : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), socket_(socket) { } static bool do_perform(reactor_op* base) { reactive_socket_connect_op_base* o( static_cast(base)); return socket_ops::non_blocking_connect(o->socket_, o->ec_); } private: socket_type socket_; }; template class reactive_socket_connect_op : public reactive_socket_connect_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); reactive_socket_connect_op(socket_type socket, Handler handler) : reactive_socket_connect_op_base(socket, &reactive_socket_connect_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_connect_op* o (static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder1 handler(o->handler_, o->ec_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_recv_op.hpp000066400000000000000000000072611244131713600255400ustar00rootroot00000000000000// // detail/reactive_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_recv_op_base : public reactor_op { public: reactive_socket_recv_op_base(socket_type socket, socket_ops::state_type state, const MutableBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), socket_(socket), state_(state), buffers_(buffers), flags_(flags) { } static bool do_perform(reactor_op* base) { reactive_socket_recv_op_base* o( static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); return socket_ops::non_blocking_recv(o->socket_, bufs.buffers(), bufs.count(), o->flags_, (o->state_ & socket_ops::stream_oriented), o->ec_, o->bytes_transferred_); } private: socket_type socket_; socket_ops::state_type state_; MutableBufferSequence buffers_; socket_base::message_flags flags_; }; template class reactive_socket_recv_op : public reactive_socket_recv_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); reactive_socket_recv_op(socket_type socket, socket_ops::state_type state, const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) : reactive_socket_recv_op_base(socket, state, buffers, flags, &reactive_socket_recv_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_recv_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_recvfrom_op.hpp000066400000000000000000000101141244131713600264130ustar00rootroot00000000000000// // detail/reactive_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_recvfrom_op_base : public reactor_op { public: reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), socket_(socket), protocol_type_(protocol_type), buffers_(buffers), sender_endpoint_(endpoint), flags_(flags) { } static bool do_perform(reactor_op* base) { reactive_socket_recvfrom_op_base* o( static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); std::size_t addr_len = o->sender_endpoint_.capacity(); bool result = socket_ops::non_blocking_recvfrom(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->sender_endpoint_.data(), &addr_len, o->ec_, o->bytes_transferred_); if (result && !o->ec_) o->sender_endpoint_.resize(addr_len); return result; } private: socket_type socket_; int protocol_type_; MutableBufferSequence buffers_; Endpoint& sender_endpoint_; socket_base::message_flags flags_; }; template class reactive_socket_recvfrom_op : public reactive_socket_recvfrom_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); reactive_socket_recvfrom_op(socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, Handler handler) : reactive_socket_recvfrom_op_base( socket, protocol_type, buffers, endpoint, flags, &reactive_socket_recvfrom_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_recvfrom_op* o( static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_send_op.hpp000066400000000000000000000067671244131713600255440ustar00rootroot00000000000000// // detail/reactive_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_send_op_base : public reactor_op { public: reactive_socket_send_op_base(socket_type socket, const ConstBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), flags_(flags) { } static bool do_perform(reactor_op* base) { reactive_socket_send_op_base* o( static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); return socket_ops::non_blocking_send(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->ec_, o->bytes_transferred_); } private: socket_type socket_; ConstBufferSequence buffers_; socket_base::message_flags flags_; }; template class reactive_socket_send_op : public reactive_socket_send_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); reactive_socket_send_op(socket_type socket, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) : reactive_socket_send_op_base(socket, buffers, flags, &reactive_socket_send_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_send_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_sendto_op.hpp000066400000000000000000000074061244131713600260760ustar00rootroot00000000000000// // detail/reactive_socket_sendto_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_sendto_op_base : public reactor_op { public: reactive_socket_sendto_op_base(socket_type socket, const ConstBufferSequence& buffers, const Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), socket_(socket), buffers_(buffers), destination_(endpoint), flags_(flags) { } static bool do_perform(reactor_op* base) { reactive_socket_sendto_op_base* o( static_cast(base)); buffer_sequence_adapter bufs(o->buffers_); return socket_ops::non_blocking_sendto(o->socket_, bufs.buffers(), bufs.count(), o->flags_, o->destination_.data(), o->destination_.size(), o->ec_, o->bytes_transferred_); } private: socket_type socket_; ConstBufferSequence buffers_; Endpoint destination_; socket_base::message_flags flags_; }; template class reactive_socket_sendto_op : public reactive_socket_sendto_op_base { public: ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); reactive_socket_sendto_op(socket_type socket, const ConstBufferSequence& buffers, const Endpoint& endpoint, socket_base::message_flags flags, Handler handler) : reactive_socket_sendto_op_base(socket, buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. reactive_socket_sendto_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->bytes_transferred_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_service.hpp000066400000000000000000000311431244131713600255370ustar00rootroot00000000000000// // detail/reactive_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) #include #include "asio/buffer.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/reactive_null_buffers_op.hpp" #include "asio/detail/reactive_socket_accept_op.hpp" #include "asio/detail/reactive_socket_connect_op.hpp" #include "asio/detail/reactive_socket_recvfrom_op.hpp" #include "asio/detail/reactive_socket_sendto_op.hpp" #include "asio/detail/reactive_socket_service_base.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactive_socket_service : public reactive_socket_service_base { public: // The protocol type. typedef Protocol protocol_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; // The native type of a socket. typedef socket_type native_type; // The implementation type of the socket. struct implementation_type : reactive_socket_service_base::base_implementation_type { // Default constructor. implementation_type() : protocol_(endpoint_type().protocol()) { } // The protocol associated with the socket. protocol_type protocol_; }; // Constructor. reactive_socket_service(asio::io_service& io_service) : reactive_socket_service_base(io_service) { } // Open a new socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (!do_open(impl, protocol.family(), protocol.type(), protocol.protocol(), ec)) impl.protocol_ = protocol; return ec; } // Assign a native socket to a socket implementation. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { if (!do_assign(impl, protocol.type(), native_socket, ec)) impl.protocol_ = protocol; return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { return impl.socket_; } // Bind the socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } // Set a socket option. template asio::error_code set_option(implementation_type& impl, const Option& option, asio::error_code& ec) { socket_ops::setsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); return ec; } // Set a socket option. template asio::error_code get_option(const implementation_type& impl, Option& option, asio::error_code& ec) const { std::size_t size = option.size(impl.protocol_); socket_ops::getsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); return ec; } // Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } // Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, false, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_sendto(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, const endpoint_type&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_sendto_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler); start_op(impl, reactor::write_op, p.p, true, false); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); start_op(impl, reactor::write_op, p.p, false, false); p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of // bytes received. template size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); std::size_t addr_len = sender_endpoint.capacity(); std::size_t bytes_recvd = socket_ops::sync_recvfrom( impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); if (!ec) sender_endpoint.resize(addr_len); return bytes_recvd; } // Wait until data can be received without blocking. size_t receive_from(implementation_type& impl, const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); return 0; } // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. template void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_recvfrom_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; int protocol_type = impl.protocol_.type(); p.p = new (p.v) op(impl.socket_, protocol_type, buffers, sender_endpoint, flags, handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, true, false); p.v = p.p = 0; } // Wait until data can be received without blocking. template void async_receive_from(implementation_type& impl, const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, false, false); p.v = p.p = 0; } // Accept a new connection. template asio::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { // We cannot accept a socket that is already open. if (peer.is_open()) { ec = asio::error::already_open; return ec; } std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; socket_holder new_socket(socket_ops::sync_accept(impl.socket_, impl.state_, peer_endpoint ? peer_endpoint->data() : 0, peer_endpoint ? &addr_len : 0, ec)); // On success, assign new connection to peer socket object. if (new_socket.get() != invalid_socket) { if (peer_endpoint) peer_endpoint->resize(addr_len); if (!peer.assign(impl.protocol_, new_socket.get(), ec)) new_socket.release(); } return ec; } // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_accept_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, impl.state_, peer, impl.protocol_, peer_endpoint, handler); start_accept_op(impl, p.p, peer.is_open()); p.v = p.p = 0; } // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); return ec; } // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_connect_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, handler); start_connect_op(impl, p.p, peer_endpoint.data(), peer_endpoint.size()); p.v = p.p = 0; } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactive_socket_service_base.hpp000066400000000000000000000235051244131713600265340ustar00rootroot00000000000000// // detail/reactive_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP #define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) #include #include "asio/buffer.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/reactive_null_buffers_op.hpp" #include "asio/detail/reactive_socket_recv_op.hpp" #include "asio/detail/reactive_socket_send_op.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class reactive_socket_service_base { public: // The native type of a socket. typedef socket_type native_type; // The implementation type of the socket. struct base_implementation_type { // The native socket representation. socket_type socket_; // The current state of the socket. socket_ops::state_type state_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; }; // Constructor. ASIO_DECL reactive_socket_service_base( asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new socket implementation. ASIO_DECL void construct(base_implementation_type& impl); // Destroy a socket implementation. ASIO_DECL void destroy(base_implementation_type& impl); // Determine whether the socket is open. bool is_open(const base_implementation_type& impl) const { return impl.socket_ != invalid_socket; } // Destroy a socket implementation. ASIO_DECL asio::error_code close( base_implementation_type& impl, asio::error_code& ec); // Get the native socket representation. native_type native(base_implementation_type& impl) { return impl.socket_; } // Cancel all operations associated with the socket. ASIO_DECL asio::error_code cancel( base_implementation_type& impl, asio::error_code& ec); // Determine whether the socket is at the out-of-band data mark. bool at_mark(const base_implementation_type& impl, asio::error_code& ec) const { return socket_ops::sockatmark(impl.socket_, ec); } // Determine the number of bytes available for reading. std::size_t available(const base_implementation_type& impl, asio::error_code& ec) const { return socket_ops::available(impl.socket_, ec); } // Place the socket into the state where it will listen for new connections. asio::error_code listen(base_implementation_type& impl, int backlog, asio::error_code& ec) { socket_ops::listen(impl.socket_, backlog, ec); return ec; } // Perform an IO control command on the socket. template asio::error_code io_control(base_implementation_type& impl, IO_Control_Command& command, asio::error_code& ec) { socket_ops::ioctl(impl.socket_, impl.state_, command.name(), static_cast(command.data()), ec); return ec; } /// Disable sends or receives on the socket. asio::error_code shutdown(base_implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { socket_ops::shutdown(impl.socket_, what, ec); return ec; } // Send the given data to the peer. template size_t send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_send(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); } // Wait until data can be sent without blocking. size_t send(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_send_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, buffers, flags, handler); start_op(impl, reactor::write_op, p.p, true, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter::all_empty(buffers))); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); start_op(impl, reactor::write_op, p.p, false, false); p.v = p.p = 0; } // Receive some data from the peer. Returns the number of bytes received. template size_t receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_recv(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); } // Wait until data can be received without blocking. size_t receive(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); return 0; } // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. template void async_receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_recv_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, (flags & socket_base::message_out_of_band) == 0, ((impl.state_ & socket_ops::stream_oriented) && buffer_sequence_adapter::all_empty(buffers))); p.v = p.p = 0; } // Wait until data can be received without blocking. template void async_receive(base_implementation_type& impl, const null_buffers&, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); start_op(impl, (flags & socket_base::message_out_of_band) ? reactor::except_op : reactor::read_op, p.p, false, false); p.v = p.p = 0; } protected: // Open a new socket implementation. ASIO_DECL asio::error_code do_open( base_implementation_type& impl, int af, int type, int protocol, asio::error_code& ec); // Assign a native socket to a socket implementation. ASIO_DECL asio::error_code do_assign( base_implementation_type& impl, int type, const native_type& native_socket, asio::error_code& ec); // Start the asynchronous read or write operation. ASIO_DECL void start_op(base_implementation_type& impl, int op_type, reactor_op* op, bool non_blocking, bool noop); // Start the asynchronous accept operation. ASIO_DECL void start_accept_op(base_implementation_type& impl, reactor_op* op, bool peer_is_open); // Start the asynchronous connect operation. ASIO_DECL void start_connect_op(base_implementation_type& impl, reactor_op* op, const socket_addr_type* addr, size_t addrlen); // The selector that performs event demultiplexing for the service. reactor& reactor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/reactive_socket_service_base.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactor.hpp000066400000000000000000000014601244131713600223030ustar00rootroot00000000000000// // detail/reactor.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTOR_HPP #define ASIO_DETAIL_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/reactor_fwd.hpp" #if defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor.hpp" #elif defined(ASIO_HAS_KQUEUE) # include "asio/detail/kqueue_reactor.hpp" #elif defined(ASIO_HAS_DEV_POLL) # include "asio/detail/dev_poll_reactor.hpp" #else # include "asio/detail/select_reactor.hpp" #endif #endif // ASIO_DETAIL_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactor_fwd.hpp000066400000000000000000000024231244131713600231430ustar00rootroot00000000000000// // detail/reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTOR_FWD_HPP #define ASIO_DETAIL_REACTOR_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/select_reactor_fwd.hpp" #elif defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor_fwd.hpp" #elif defined(ASIO_HAS_KQUEUE) # include "asio/detail/kqueue_reactor_fwd.hpp" #elif defined(ASIO_HAS_DEV_POLL) # include "asio/detail/dev_poll_reactor_fwd.hpp" #else # include "asio/detail/select_reactor_fwd.hpp" #endif namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) typedef select_reactor reactor; #elif defined(ASIO_HAS_EPOLL) typedef epoll_reactor reactor; #elif defined(ASIO_HAS_KQUEUE) typedef kqueue_reactor reactor; #elif defined(ASIO_HAS_DEV_POLL) typedef dev_poll_reactor reactor; #else typedef select_reactor reactor; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_REACTOR_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactor_op.hpp000066400000000000000000000025611244131713600230040ustar00rootroot00000000000000// // detail/reactor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTOR_OP_HPP #define ASIO_DETAIL_REACTOR_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class reactor_op : public operation { public: // The error code to be passed to the completion handler. asio::error_code ec_; // The number of bytes transferred, to be passed to the completion handler. std::size_t bytes_transferred_; // Perform the operation. Returns true if it is finished. bool perform() { return perform_func_(this); } protected: typedef bool (*perform_func_type)(reactor_op*); reactor_op(perform_func_type perform_func, func_type complete_func) : operation(complete_func), bytes_transferred_(0), perform_func_(perform_func) { } private: perform_func_type perform_func_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTOR_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/reactor_op_queue.hpp000066400000000000000000000130771244131713600242140ustar00rootroot00000000000000// // detail/reactor_op_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REACTOR_OP_QUEUE_HPP #define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/hash_map.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class reactor_op_queue : private noncopyable { public: // Constructor. reactor_op_queue() : operations_() { } // Add a new operation to the queue. Returns true if this is the only // operation for the given descriptor, in which case the reactor's event // demultiplexing function call may need to be interrupted and restarted. bool enqueue_operation(Descriptor descriptor, reactor_op* op) { typedef typename operations_map::iterator iterator; typedef typename operations_map::value_type value_type; std::pair entry = operations_.insert(value_type(descriptor, operations())); entry.first->second.op_queue_.push(op); return entry.second; } // Cancel all operations associated with the descriptor. Any operations // pending for the descriptor will be notified that they have been cancelled // next time perform_cancellations is called. Returns true if any operations // were cancelled, in which case the reactor's event demultiplexing function // may need to be interrupted and restarted. bool cancel_operations(Descriptor descriptor, op_queue& ops, const asio::error_code& ec = asio::error::operation_aborted) { typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { while (reactor_op* op = i->second.op_queue_.front()) { op->ec_ = ec; i->second.op_queue_.pop(); ops.push(op); } operations_.erase(i); return true; } return false; } // Whether there are no operations in the queue. bool empty() const { return operations_.empty(); } // Determine whether there are any operations associated with the descriptor. bool has_operation(Descriptor descriptor) const { return operations_.find(descriptor) != operations_.end(); } // Perform the operations corresponding to the descriptor. Returns true if // there are still unfinished operations queued for the descriptor. bool perform_operations(Descriptor descriptor, op_queue& ops) { typename operations_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) { while (reactor_op* op = i->second.op_queue_.front()) { if (op->perform()) { i->second.op_queue_.pop(); ops.push(op); } else { return true; } } operations_.erase(i); } return false; } // Fill a descriptor set with the descriptors corresponding to each active // operation. The op_queue is used only when descriptors fail to be added to // the descriptor set. template void get_descriptors(Descriptor_Set& descriptors, op_queue& ops) { typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { Descriptor descriptor = i->first; ++i; if (!descriptors.set(descriptor)) { asio::error_code ec(error::fd_set_failure); cancel_operations(descriptor, ops, ec); } } } // Perform the operations corresponding to the ready file descriptors // contained in the given descriptor set. template void perform_operations_for_descriptors( const Descriptor_Set& descriptors, op_queue& ops) { typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { typename operations_map::iterator op_iter = i++; if (descriptors.is_set(op_iter->first)) { while (reactor_op* op = op_iter->second.op_queue_.front()) { if (op->perform()) { op_iter->second.op_queue_.pop(); ops.push(op); } else { break; } } if (op_iter->second.op_queue_.empty()) operations_.erase(op_iter); } } } // Get all operations owned by the queue. void get_all_operations(op_queue& ops) { typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { typename operations_map::iterator op_iter = i++; ops.push(op_iter->second.op_queue_); operations_.erase(op_iter); } } private: struct operations { operations() {} operations(const operations&) {} void operator=(const operations&) {} // The operations waiting on the desccriptor. op_queue op_queue_; }; // The type for a map of operations. typedef hash_map operations_map; // The operations that are currently executing asynchronously. operations_map operations_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP percona-galera-3-3.8-3390/asio/asio/detail/regex_fwd.hpp000066400000000000000000000013441244131713600226170ustar00rootroot00000000000000// // detail/regex_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_REGEX_FWD_HPP #define ASIO_DETAIL_REGEX_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include namespace boost { template struct sub_match; template class match_results; } // namespace boost #endif // ASIO_DETAIL_REGEX_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/resolve_endpoint_op.hpp000066400000000000000000000074731244131713600247330ustar00rootroot00000000000000// // detail/resolve_endpoint_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP #define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class resolve_endpoint_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); typedef typename Protocol::endpoint endpoint_type; typedef asio::ip::basic_resolver_iterator iterator_type; resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, const endpoint_type& endpoint, io_service_impl& ios, Handler handler) : operation(&resolve_endpoint_op::do_complete), cancel_token_(cancel_token), endpoint_(endpoint), io_service_impl_(ios), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. resolve_endpoint_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; if (owner && owner != &o->io_service_impl_) { // The operation is being run on the worker io_service. Time to perform // the resolver operation. // Perform the blocking endpoint resolution operation. char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, o->endpoint_.protocol().type(), o->ec_); o->iter_ = iterator_type::create(o->endpoint_, host_name, service_name); // Pass operation back to main io_service for completion. o->io_service_impl_.post_deferred_completion(o); p.v = p.p = 0; } else { // The operation has been returned to the main io_service. The completion // handler is ready to be delivered. // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, o->iter_); p.h = boost::addressof(handler.handler_); p.reset(); if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } } private: socket_ops::weak_cancel_token_type cancel_token_; endpoint_type endpoint_; io_service_impl& io_service_impl_; Handler handler_; asio::error_code ec_; iterator_type iter_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/resolve_op.hpp000066400000000000000000000075561244131713600230350ustar00rootroot00000000000000// // detail/resolve_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_RESOLVE_OP_HPP #define ASIO_DETAIL_RESOLVE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class resolve_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(resolve_op); typedef asio::ip::basic_resolver_query query_type; typedef asio::ip::basic_resolver_iterator iterator_type; resolve_op(socket_ops::weak_cancel_token_type cancel_token, const query_type& query, io_service_impl& ios, Handler handler) : operation(&resolve_op::do_complete), cancel_token_(cancel_token), query_(query), io_service_impl_(ios), handler_(handler), addrinfo_(0) { } ~resolve_op() { if (addrinfo_) socket_ops::freeaddrinfo(addrinfo_); } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. resolve_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; if (owner && owner != &o->io_service_impl_) { // The operation is being run on the worker io_service. Time to perform // the resolver operation. // Perform the blocking host resolution operation. socket_ops::background_getaddrinfo(o->cancel_token_, o->query_.host_name().c_str(), o->query_.service_name().c_str(), o->query_.hints(), &o->addrinfo_, o->ec_); // Pass operation back to main io_service for completion. o->io_service_impl_.post_deferred_completion(o); p.v = p.p = 0; } else { // The operation has been returned to the main io_service. The completion // handler is ready to be delivered. // Make a copy of the handler so that the memory can be deallocated // before the upcall is made. Even if we're not about to make an upcall, // a sub-object of the handler may be the true owner of the memory // associated with the handler. Consequently, a local copy of the handler // is required to ensure that any owning sub-object remains valid until // after we have deallocated the memory here. detail::binder2 handler(o->handler_, o->ec_, iterator_type()); p.h = boost::addressof(handler.handler_); if (o->addrinfo_) { handler.arg2_ = iterator_type::create(o->addrinfo_, o->query_.host_name(), o->query_.service_name()); } p.reset(); if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } } private: socket_ops::weak_cancel_token_type cancel_token_; query_type query_; io_service_impl& io_service_impl_; Handler handler_; asio::error_code ec_; asio::detail::addrinfo_type* addrinfo_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_RESOLVE_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/resolver_service.hpp000066400000000000000000000072741244131713600242360ustar00rootroot00000000000000// // detail/resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_RESOLVER_SERVICE_HPP #define ASIO_DETAIL_RESOLVER_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/resolve_endpoint_op.hpp" #include "asio/detail/resolve_op.hpp" #include "asio/detail/resolver_service_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class resolver_service : public resolver_service_base { public: // The implementation type of the resolver. A cancellation token is used to // indicate to the background thread that the operation has been cancelled. typedef socket_ops::shared_cancel_token_type implementation_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; // The query type. typedef asio::ip::basic_resolver_query query_type; // The iterator type. typedef asio::ip::basic_resolver_iterator iterator_type; // Constructor. resolver_service(asio::io_service& io_service) : resolver_service_base(io_service) { } // Resolve a query to a list of entries. iterator_type resolve(implementation_type&, const query_type& query, asio::error_code& ec) { asio::detail::addrinfo_type* address_info = 0; socket_ops::getaddrinfo(query.host_name().c_str(), query.service_name().c_str(), query.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); return ec ? iterator_type() : iterator_type::create( address_info, query.host_name(), query.service_name()); } // Asynchronously resolve a query to a list of entries. template void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef resolve_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl, query, io_service_impl_, handler); start_resolve_op(p.p); p.v = p.p = 0; } // Resolve an endpoint to a list of entries. iterator_type resolve(implementation_type&, const endpoint_type& endpoint, asio::error_code& ec) { char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, endpoint.protocol().type(), ec); return ec ? iterator_type() : iterator_type::create( endpoint, host_name, service_name); } // Asynchronously resolve an endpoint to a list of entries. template void async_resolve(implementation_type& impl, const endpoint_type& endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef resolve_endpoint_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl, endpoint, io_service_impl_, handler); start_resolve_op(p.p); p.v = p.p = 0; } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/resolver_service_base.hpp000066400000000000000000000065221244131713600252230ustar00rootroot00000000000000// // detail/resolver_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP #define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/thread.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class resolver_service_base { public: // The implementation type of the resolver. A cancellation token is used to // indicate to the background thread that the operation has been cancelled. typedef socket_ops::shared_cancel_token_type implementation_type; // Constructor. ASIO_DECL resolver_service_base(asio::io_service& io_service); // Destructor. ASIO_DECL ~resolver_service_base(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new resolver implementation. ASIO_DECL void construct(implementation_type& impl); // Destroy a resolver implementation. ASIO_DECL void destroy(implementation_type&); // Cancel pending asynchronous operations. ASIO_DECL void cancel(implementation_type& impl); protected: // Helper function to start an asynchronous resolve operation. ASIO_DECL void start_resolve_op(operation* op); // Helper class to perform exception-safe cleanup of addrinfo objects. class auto_addrinfo : private asio::detail::noncopyable { public: explicit auto_addrinfo(asio::detail::addrinfo_type* ai) : ai_(ai) { } ~auto_addrinfo() { if (ai_) socket_ops::freeaddrinfo(ai_); } operator asio::detail::addrinfo_type*() { return ai_; } private: asio::detail::addrinfo_type* ai_; }; // Helper class to run the work io_service in a thread. class work_io_service_runner; // Start the work thread if it's not already running. ASIO_DECL void start_work_thread(); // The io_service implementation used to post completions. io_service_impl& io_service_impl_; private: // Mutex to protect access to internal data. asio::detail::mutex mutex_; // Private io_service used for performing asynchronous host resolution. boost::scoped_ptr work_io_service_; // The work io_service implementation used to post completions. io_service_impl& work_io_service_impl_; // Work for the private io_service to perform. boost::scoped_ptr work_; // Thread used for running the work io_service's run loop. boost::scoped_ptr work_thread_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/resolver_service_base.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP percona-galera-3-3.8-3390/asio/asio/detail/scoped_lock.hpp000066400000000000000000000031441244131713600231320ustar00rootroot00000000000000// // detail/scoped_lock.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SCOPED_LOCK_HPP #define ASIO_DETAIL_SCOPED_LOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/noncopyable.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper class to lock and unlock a mutex automatically. template class scoped_lock : private noncopyable { public: // Constructor acquires the lock. scoped_lock(Mutex& m) : mutex_(m) { mutex_.lock(); locked_ = true; } // Destructor releases the lock. ~scoped_lock() { if (locked_) mutex_.unlock(); } // Explicitly acquire the lock. void lock() { if (!locked_) { mutex_.lock(); locked_ = true; } } // Explicitly release the lock. void unlock() { if (locked_) { mutex_.unlock(); locked_ = false; } } // Test whether the lock is held. bool locked() const { return locked_; } // Get the underlying mutex. Mutex& mutex() { return mutex_; } private: // The underlying mutex. Mutex& mutex_; // Whether the mutex is currently locked or unlocked. bool locked_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SCOPED_LOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/select_interrupter.hpp000066400000000000000000000023211244131713600245630ustar00rootroot00000000000000// // detail/select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SELECT_INTERRUPTER_HPP #define ASIO_DETAIL_SELECT_INTERRUPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include "asio/detail/socket_select_interrupter.hpp" #elif defined(ASIO_HAS_EVENTFD) # include "asio/detail/eventfd_select_interrupter.hpp" #else # include "asio/detail/pipe_select_interrupter.hpp" #endif namespace asio { namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef socket_select_interrupter select_interrupter; #elif defined(ASIO_HAS_EVENTFD) typedef eventfd_select_interrupter select_interrupter; #else typedef pipe_select_interrupter select_interrupter; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/select_reactor.hpp000066400000000000000000000142451244131713600236470ustar00rootroot00000000000000// // detail/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SELECT_REACTOR_HPP #define ASIO_DETAIL_SELECT_REACTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) \ || (!defined(ASIO_HAS_DEV_POLL) \ && !defined(ASIO_HAS_EPOLL) \ && !defined(ASIO_HAS_KQUEUE)) #include #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/select_reactor_fwd.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/io_service.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/thread.hpp" #endif // defined(ASIO_HAS_IOCP) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class select_reactor : public asio::detail::service_base { public: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) enum { read_op = 0, write_op = 1, except_op = 2, max_select_ops = 3, connect_op = 3, max_ops = 4 }; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) enum { read_op = 0, write_op = 1, except_op = 2, max_select_ops = 3, connect_op = 1, max_ops = 3 }; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Per-descriptor data. struct per_descriptor_data { }; // Constructor. ASIO_DECL select_reactor(asio::io_service& io_service); // Destructor. ASIO_DECL ~select_reactor(); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task, but only if the reactor is not in its own thread. ASIO_DECL void init_task(); // Register a socket with the reactor. Returns 0 on success, system error // code on failure. ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); // Post a reactor operation for immediate completion. void post_immediate_completion(reactor_op* op) { io_service_.post_immediate_completion(op); } // Start a new operation. The reactor operation will be performed when the // given descriptor is flagged as ready, or an error has occurred. ASIO_DECL void start_op(int op_type, socket_type descriptor, per_descriptor_data&, reactor_op* op, bool); // Cancel all operations associated with the given descriptor. The // handlers associated with the descriptor will be invoked with the // operation_aborted error. ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); // Cancel any operations that are running against the descriptor and remove // its registration from the reactor. ASIO_DECL void close_descriptor(socket_type descriptor, per_descriptor_data&); // Add a new timer queue to the reactor. template void add_timer_queue(timer_queue& queue); // Remove a timer queue from the reactor. template void remove_timer_queue(timer_queue& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op); // Cancel the timer operations associated with the given token. Returns the // number of operations that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer); // Run select once until interrupted or events are ready to be dispatched. ASIO_DECL void run(bool block, op_queue& ops); // Interrupt the select loop. ASIO_DECL void interrupt(); private: #if defined(ASIO_HAS_IOCP) // Run the select loop in the thread. ASIO_DECL void run_thread(); // Entry point for the select loop thread. ASIO_DECL static void call_run_thread(select_reactor* reactor); #endif // defined(ASIO_HAS_IOCP) // Helper function to add a new timer queue. ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Get the timeout value for the select call. ASIO_DECL timeval* get_timeout(timeval& tv); // Cancel all operations associated with the given descriptor. This function // does not acquire the select_reactor's mutex. ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, const asio::error_code& ec); // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to internal data. asio::detail::mutex mutex_; // The interrupter is used to break a blocking select call. select_interrupter interrupter_; // The queues of read, write and except operations. reactor_op_queue op_queue_[max_ops]; // The timer queues. timer_queue_set timer_queues_; #if defined(ASIO_HAS_IOCP) // Does the reactor loop thread need to stop. bool stop_thread_; // The thread that is running the reactor loop. asio::detail::thread* thread_; #endif // defined(ASIO_HAS_IOCP) // Whether the service has been shut down. bool shutdown_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/select_reactor.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/select_reactor.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_IOCP) // || (!defined(ASIO_HAS_DEV_POLL) // && !defined(ASIO_HAS_EPOLL) // && !defined(ASIO_HAS_KQUEUE)) #endif // ASIO_DETAIL_SELECT_REACTOR_HPP percona-galera-3-3.8-3390/asio/asio/detail/select_reactor_fwd.hpp000066400000000000000000000012171244131713600245020ustar00rootroot00000000000000// // detail/select_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SELECT_REACTOR_FWD_HPP #define ASIO_DETAIL_SELECT_REACTOR_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { namespace detail { class select_reactor; } // namespace detail } // namespace asio #endif // ASIO_DETAIL_SELECT_REACTOR_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/service_base.hpp000066400000000000000000000021631244131713600232770ustar00rootroot00000000000000// // service_base.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SERVICE_BASE_HPP #define ASIO_DETAIL_SERVICE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/io_service.hpp" #include "asio/detail/service_id.hpp" namespace asio { namespace detail { // Special service base class to keep classes header-file only. template class service_base : public asio::io_service::service { public: static asio::detail::service_id id; // Constructor. service_base(asio::io_service& io_service) : asio::io_service::service(io_service) { } }; template asio::detail::service_id service_base::id; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SERVICE_BASE_HPP percona-galera-3-3.8-3390/asio/asio/detail/service_id.hpp000066400000000000000000000015101244131713600227540ustar00rootroot00000000000000// // service_id.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SERVICE_ID_HPP #define ASIO_DETAIL_SERVICE_ID_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/io_service.hpp" namespace asio { namespace detail { // Special derived service id type to keep classes header-file only. template class service_id : public asio::io_service::id { }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SERVICE_ID_HPP percona-galera-3-3.8-3390/asio/asio/detail/service_registry.hpp000066400000000000000000000112601244131713600242330ustar00rootroot00000000000000// // detail/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SERVICE_REGISTRY_HPP #define ASIO_DETAIL_SERVICE_REGISTRY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/io_service.hpp" #if defined(BOOST_NO_TYPEID) # if !defined(ASIO_NO_TYPEID) # define ASIO_NO_TYPEID # endif // !defined(ASIO_NO_TYPEID) #endif // defined(BOOST_NO_TYPEID) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if defined(__GNUC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) # pragma GCC visibility push (default) # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) #endif // defined(__GNUC__) template class typeid_wrapper {}; #if defined(__GNUC__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) # pragma GCC visibility pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) #endif // defined(__GNUC__) class service_registry : private noncopyable { public: // Constructor. ASIO_DECL service_registry(asio::io_service& o); // Destructor. ASIO_DECL ~service_registry(); // Get the service object corresponding to the specified service type. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. template Service& use_service(); // Add a service object. Throws on error, in which case ownership of the // object is retained by the caller. template void add_service(Service* new_service); // Check whether a service object of the specified type already exists. template bool has_service() const; private: // Initialise a service's key based on its id. ASIO_DECL static void init_key( asio::io_service::service::key& key, const asio::io_service::id& id); #if !defined(ASIO_NO_TYPEID) // Initialise a service's key based on its id. template static void init_key(asio::io_service::service::key& key, const asio::detail::service_id& /*id*/); #endif // !defined(ASIO_NO_TYPEID) // Check if a service matches the given id. ASIO_DECL static bool keys_match( const asio::io_service::service::key& key1, const asio::io_service::service::key& key2); // The type of a factory function used for creating a service instance. typedef asio::io_service::service* (*factory_type)(asio::io_service&); // Factory function for creating a service instance. template static asio::io_service::service* create( asio::io_service& owner); // Destroy a service instance. ASIO_DECL static void destroy( asio::io_service::service* service); // Helper class to manage service pointers. struct auto_service_ptr; friend struct auto_service_ptr; struct auto_service_ptr { asio::io_service::service* ptr_; ~auto_service_ptr() { destroy(ptr_); } }; // Get the service object corresponding to the specified service key. Will // create a new service object automatically if no such object already // exists. Ownership of the service object is not transferred to the caller. ASIO_DECL asio::io_service::service* do_use_service( const asio::io_service::service::key& key, factory_type factory); // Add a service object. Returns false on error, in which case ownership of // the object is retained by the caller. ASIO_DECL void do_add_service( const asio::io_service::service::key& key, asio::io_service::service* new_service); // Check whether a service object with the specified key already exists. ASIO_DECL bool do_has_service( const asio::io_service::service::key& key) const; // Mutex to protect access to internal data. mutable asio::detail::mutex mutex_; // The owner of this service registry and the services it contains. asio::io_service& owner_; // The first service in the list of contained services. asio::io_service::service* first_service_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/service_registry.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/service_registry.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP percona-galera-3-3.8-3390/asio/asio/detail/service_registry_fwd.hpp000066400000000000000000000012331244131713600250720ustar00rootroot00000000000000// // detail/service_registry_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP #define ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { namespace detail { class service_registry; } // namespace detail } // namespace asio #endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/shared_ptr.hpp000066400000000000000000000015131244131713600227760ustar00rootroot00000000000000// // detail/shared_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SHARED_PTR_HPP #define ASIO_DETAIL_SHARED_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(_MSC_VER) && (_MSC_VER >= 1600) # include #else # include #endif namespace asio { namespace detail { #if defined(_MSC_VER) && (_MSC_VER >= 1600) using std::shared_ptr; #else using boost::shared_ptr; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_SHARED_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/signal_blocker.hpp000066400000000000000000000023511244131713600236220ustar00rootroot00000000000000// // detail/signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SIGNAL_BLOCKER_HPP #define ASIO_DETAIL_SIGNAL_BLOCKER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \ || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include "asio/detail/null_signal_blocker.hpp" #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_signal_blocker.hpp" #else # error Only Windows and POSIX are supported! #endif namespace asio { namespace detail { #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) \ || defined(BOOST_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) typedef null_signal_blocker signal_blocker; #elif defined(BOOST_HAS_PTHREADS) typedef posix_signal_blocker signal_blocker; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP percona-galera-3-3.8-3390/asio/asio/detail/signal_init.hpp000066400000000000000000000017311244131713600231450ustar00rootroot00000000000000// // detail/signal_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SIGNAL_INIT_HPP #define ASIO_DETAIL_SIGNAL_INIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class signal_init { public: // Constructor. signal_init() { std::signal(Signal, SIG_IGN); } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #endif // ASIO_DETAIL_SIGNAL_INIT_HPP percona-galera-3-3.8-3390/asio/asio/detail/socket_holder.hpp000066400000000000000000000037731244131713600235020ustar00rootroot00000000000000// // detail/socket_holder.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_HOLDER_HPP #define ASIO_DETAIL_SOCKET_HOLDER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Implement the resource acquisition is initialisation idiom for sockets. class socket_holder : private noncopyable { public: // Construct as an uninitialised socket. socket_holder() : socket_(invalid_socket) { } // Construct to take ownership of the specified socket. explicit socket_holder(socket_type s) : socket_(s) { } // Destructor. ~socket_holder() { if (socket_ != invalid_socket) { asio::error_code ec; socket_ops::state_type state = 0; socket_ops::close(socket_, state, true, ec); } } // Get the underlying socket. socket_type get() const { return socket_; } // Reset to an uninitialised socket. void reset() { if (socket_ != invalid_socket) { asio::error_code ec; socket_ops::state_type state = 0; socket_ops::close(socket_, state, true, ec); socket_ = invalid_socket; } } // Reset to take ownership of the specified socket. void reset(socket_type s) { reset(); socket_ = s; } // Release ownership of the socket. socket_type release() { socket_type tmp = socket_; socket_ = invalid_socket; return tmp; } private: // The underlying socket. socket_type socket_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_HOLDER_HPP percona-galera-3-3.8-3390/asio/asio/detail/socket_ops.hpp000066400000000000000000000221511244131713600230150ustar00rootroot00000000000000// // detail/socket_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_OPS_HPP #define ASIO_DETAIL_SOCKET_OPS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/error_code.hpp" #include "asio/detail/shared_ptr.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/weak_ptr.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace socket_ops { // Socket state bits. enum { // The user wants a non-blocking socket. user_set_non_blocking = 1, // The socket has been set non-blocking. internal_non_blocking = 2, // Helper "state" used to determine whether the socket is non-blocking. non_blocking = user_set_non_blocking | internal_non_blocking, // User wants connection_aborted errors, which are disabled by default. enable_connection_aborted = 4, // The user set the linger option. Needs to be checked when closing. user_set_linger = 8, // The socket is stream-oriented. stream_oriented = 16, // The socket is datagram-oriented. datagram_oriented = 32 }; typedef unsigned char state_type; struct noop_deleter { void operator()(void*) {} }; typedef shared_ptr shared_cancel_token_type; typedef weak_ptr weak_cancel_token_type; ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec); ASIO_DECL socket_type sync_accept(socket_type s, state_type state, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_accept(socket_type s, void* output_buffer, DWORD address_length, socket_addr_type* addr, std::size_t* addrlen, socket_type new_socket, asio::error_code& ec); #else // defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_accept(socket_type s, state_type state, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec, socket_type& new_socket); #endif // defined(ASIO_HAS_IOCP) ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL int close(socket_type s, state_type& state, bool destruction, asio::error_code& ec); ASIO_DECL bool set_internal_non_blocking(socket_type s, state_type& state, asio::error_code& ec); ASIO_DECL int shutdown(socket_type s, int what, asio::error_code& ec); ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL bool non_blocking_connect( socket_type s, asio::error_code& ec); ASIO_DECL int socketpair(int af, int type, int protocol, socket_type sv[2], asio::error_code& ec); ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec); ASIO_DECL size_t available(socket_type s, asio::error_code& ec); ASIO_DECL int listen(socket_type s, int backlog, asio::error_code& ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef iovec buf; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) ASIO_DECL void init_buf(buf& b, void* data, size_t size); ASIO_DECL void init_buf(buf& b, const void* data, size_t size); ASIO_DECL int recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec); ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_recv(state_type state, const weak_cancel_token_type& cancel_token, bool all_empty, asio::error_code& ec, size_t bytes_transferred); #else // defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_recv(socket_type s, buf* bufs, size_t count, int flags, bool is_stream, asio::error_code& ec, size_t& bytes_transferred); #endif // defined(ASIO_HAS_IOCP) ASIO_DECL int recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec); ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_recvfrom( const weak_cancel_token_type& cancel_token, asio::error_code& ec); #else // defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_recvfrom(socket_type s, buf* bufs, size_t count, int flags, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec, size_t& bytes_transferred); #endif // defined(ASIO_HAS_IOCP) ASIO_DECL int send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec); ASIO_DECL size_t sync_send(socket_type s, state_type state, const buf* bufs, size_t count, int flags, bool all_empty, asio::error_code& ec); #if defined(ASIO_HAS_IOCP) ASIO_DECL void complete_iocp_send( const weak_cancel_token_type& cancel_token, asio::error_code& ec); #else // defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_send(socket_type s, const buf* bufs, size_t count, int flags, asio::error_code& ec, size_t& bytes_transferred); #endif // defined(ASIO_HAS_IOCP) ASIO_DECL int sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); ASIO_DECL size_t sync_sendto(socket_type s, state_type state, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec); #if !defined(ASIO_HAS_IOCP) ASIO_DECL bool non_blocking_sendto(socket_type s, const buf* bufs, size_t count, int flags, const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec, size_t& bytes_transferred); #endif // !defined(ASIO_HAS_IOCP) ASIO_DECL socket_type socket(int af, int type, int protocol, asio::error_code& ec); ASIO_DECL int setsockopt(socket_type s, state_type& state, int level, int optname, const void* optval, std::size_t optlen, asio::error_code& ec); ASIO_DECL int getsockopt(socket_type s, state_type state, int level, int optname, void* optval, size_t* optlen, asio::error_code& ec); ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, std::size_t* addrlen, bool cached, asio::error_code& ec); ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec); ASIO_DECL int ioctl(socket_type s, state_type& state, int cmd, ioctl_arg_type* arg, asio::error_code& ec); ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, timeval* timeout, asio::error_code& ec); ASIO_DECL int poll_read(socket_type s, asio::error_code& ec); ASIO_DECL int poll_write(socket_type s, asio::error_code& ec); ASIO_DECL int poll_connect(socket_type s, asio::error_code& ec); ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, size_t length, unsigned long scope_id, asio::error_code& ec); ASIO_DECL int inet_pton(int af, const char* src, void* dest, unsigned long* scope_id, asio::error_code& ec); ASIO_DECL int gethostname(char* name, int namelen, asio::error_code& ec); ASIO_DECL asio::error_code getaddrinfo(const char* host, const char* service, const addrinfo_type& hints, addrinfo_type** result, asio::error_code& ec); ASIO_DECL asio::error_code background_getaddrinfo( const weak_cancel_token_type& cancel_token, const char* host, const char* service, const addrinfo_type& hints, addrinfo_type** result, asio::error_code& ec); ASIO_DECL void freeaddrinfo(addrinfo_type* ai); ASIO_DECL asio::error_code getnameinfo( const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec); ASIO_DECL asio::error_code sync_getnameinfo( const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec); ASIO_DECL asio::error_code background_getnameinfo( const weak_cancel_token_type& cancel_token, const socket_addr_type* addr, std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int sock_type, asio::error_code& ec); ASIO_DECL u_long_type network_to_host_long(u_long_type value); ASIO_DECL u_long_type host_to_network_long(u_long_type value); ASIO_DECL u_short_type network_to_host_short(u_short_type value); ASIO_DECL u_short_type host_to_network_short(u_short_type value); } // namespace socket_ops } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/socket_ops.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_SOCKET_OPS_HPP percona-galera-3-3.8-3390/asio/asio/detail/socket_option.hpp000066400000000000000000000141571244131713600235330ustar00rootroot00000000000000// // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_OPTION_HPP #define ASIO_DETAIL_SOCKET_OPTION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { namespace socket_option { // Helper template for implementing boolean-based options. template class boolean { public: // Default constructor. boolean() : value_(0) { } // Construct with a specific option value. explicit boolean(bool v) : value_(v ? 1 : 0) { } // Set the current value of the boolean. boolean& operator=(bool v) { value_ = v ? 1 : 0; return *this; } // Get the current value of the boolean. bool value() const { return !!value_; } // Convert to bool. operator bool() const { return !!value_; } // Test for false. bool operator!() const { return !value_; } // Get the level of the socket option. template int level(const Protocol&) const { return Level; } // Get the name of the socket option. template int name(const Protocol&) const { return Name; } // Get the address of the boolean data. template int* data(const Protocol&) { return &value_; } // Get the address of the boolean data. template const int* data(const Protocol&) const { return &value_; } // Get the size of the boolean data. template std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the boolean data. template void resize(const Protocol&, std::size_t s) { // On some platforms (e.g. Windows Vista), the getsockopt function will // return the size of a boolean socket option as one byte, even though a // four byte integer was passed in. switch (s) { case sizeof(char): value_ = *reinterpret_cast(&value_) ? 1 : 0; break; case sizeof(value_): break; default: { std::length_error ex("boolean socket option resize"); boost::throw_exception(ex); } } } private: int value_; }; // Helper template for implementing integer options. template class integer { public: // Default constructor. integer() : value_(0) { } // Construct with a specific option value. explicit integer(int v) : value_(v) { } // Set the value of the int option. integer& operator=(int v) { value_ = v; return *this; } // Get the current value of the int option. int value() const { return value_; } // Get the level of the socket option. template int level(const Protocol&) const { return Level; } // Get the name of the socket option. template int name(const Protocol&) const { return Name; } // Get the address of the int data. template int* data(const Protocol&) { return &value_; } // Get the address of the int data. template const int* data(const Protocol&) const { return &value_; } // Get the size of the int data. template std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the int data. template void resize(const Protocol&, std::size_t s) { if (s != sizeof(value_)) { std::length_error ex("integer socket option resize"); boost::throw_exception(ex); } } private: int value_; }; // Helper template for implementing linger options. template class linger { public: // Default constructor. linger() { value_.l_onoff = 0; value_.l_linger = 0; } // Construct with specific option values. linger(bool e, int t) { enabled(e); timeout BOOST_PREVENT_MACRO_SUBSTITUTION(t); } // Set the value for whether linger is enabled. void enabled(bool value) { value_.l_onoff = value ? 1 : 0; } // Get the value for whether linger is enabled. bool enabled() const { return value_.l_onoff != 0; } // Set the value for the linger timeout. void timeout BOOST_PREVENT_MACRO_SUBSTITUTION(int value) { #if defined(WIN32) value_.l_linger = static_cast(value); #else value_.l_linger = value; #endif } // Get the value for the linger timeout. int timeout BOOST_PREVENT_MACRO_SUBSTITUTION() const { return static_cast(value_.l_linger); } // Get the level of the socket option. template int level(const Protocol&) const { return Level; } // Get the name of the socket option. template int name(const Protocol&) const { return Name; } // Get the address of the linger data. template ::linger* data(const Protocol&) { return &value_; } // Get the address of the linger data. template const ::linger* data(const Protocol&) const { return &value_; } // Get the size of the linger data. template std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the int data. template void resize(const Protocol&, std::size_t s) { if (s != sizeof(value_)) { std::length_error ex("linger socket option resize"); boost::throw_exception(ex); } } private: ::linger value_; }; } // namespace socket_option } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_OPTION_HPP percona-galera-3-3.8-3390/asio/asio/detail/socket_select_interrupter.hpp000066400000000000000000000041261244131713600261400ustar00rootroot00000000000000// // detail/socket_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP #define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class socket_select_interrupter { public: // Constructor. ASIO_DECL socket_select_interrupter(); // Destructor. ASIO_DECL ~socket_select_interrupter(); // Interrupt the select call. ASIO_DECL void interrupt(); // Reset the select interrupt. Returns true if the call was interrupted. ASIO_DECL bool reset(); // Get the read descriptor to be passed to select. socket_type read_descriptor() const { return read_descriptor_; } private: // The read end of a connection used to interrupt the select call. This file // descriptor is passed to select such that when it is time to stop, a single // byte will be written on the other end of the connection and this // descriptor will become readable. socket_type read_descriptor_; // The write end of a connection used to interrupt the select call. A single // byte may be written to this to wake up the select which is waiting for the // other end to become readable. socket_type write_descriptor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/socket_select_interrupter.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) #endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/socket_types.hpp000066400000000000000000000120461244131713600233620ustar00rootroot00000000000000// // detail/socket_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOCKET_TYPES_HPP #define ASIO_DETAIL_SOCKET_TYPES_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # error WinSock.h has already been included # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # if defined(__BORLANDC__) # include // Needed for __errno # if !defined(_WSPIAPI_H_) # define _WSPIAPI_H_ # define ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) # include # include # include # if defined(ASIO_WSPIAPI_H_DEFINED) # undef _WSPIAPI_H_ # undef ASIO_WSPIAPI_H_DEFINED # endif // defined(ASIO_WSPIAPI_H_DEFINED) # if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) # if defined(UNDER_CE) # pragma comment(lib, "ws2.lib") # elif defined(_MSC_VER) || defined(__BORLANDC__) # pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "mswsock.lib") # endif // defined(_MSC_VER) || defined(__BORLANDC__) # endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS) # include "asio/detail/old_win_sdk_compat.hpp" #else # include # if !defined(__SYMBIAN32__) # include # endif # include # include # include # if defined(__hpux) # include # endif # if !defined(__hpux) || defined(__SELECT) # include # endif # include # include # include # include # if !defined(__SYMBIAN32__) # include # endif # include # include # include # include # if defined(__sun) # include # include # endif #endif #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef SOCKET socket_type; const SOCKET invalid_socket = INVALID_SOCKET; const int socket_error_retval = SOCKET_ERROR; const int max_addr_v4_str_len = 256; const int max_addr_v6_str_len = 256; typedef sockaddr socket_addr_type; typedef in_addr in4_addr_type; typedef ip_mreq in4_mreq_type; typedef sockaddr_in sockaddr_in4_type; # if defined(ASIO_HAS_OLD_WIN_SDK) typedef in6_addr_emulation in6_addr_type; typedef ipv6_mreq_emulation in6_mreq_type; typedef sockaddr_in6_emulation sockaddr_in6_type; typedef sockaddr_storage_emulation sockaddr_storage_type; typedef addrinfo_emulation addrinfo_type; # else typedef in6_addr in6_addr_type; typedef ipv6_mreq in6_mreq_type; typedef sockaddr_in6 sockaddr_in6_type; typedef sockaddr_storage sockaddr_storage_type; typedef addrinfo addrinfo_type; # endif typedef unsigned long ioctl_arg_type; typedef u_long u_long_type; typedef u_short u_short_type; const int shutdown_receive = SD_RECEIVE; const int shutdown_send = SD_SEND; const int shutdown_both = SD_BOTH; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; # if defined (_WIN32_WINNT) const int max_iov_len = 64; # else const int max_iov_len = 16; # endif #else typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; const int max_addr_v4_str_len = INET_ADDRSTRLEN; #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = 256; #endif // defined(INET6_ADDRSTRLEN) typedef sockaddr socket_addr_type; typedef in_addr in4_addr_type; # if defined(__hpux) // HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. struct in4_mreq_type { struct in_addr imr_multiaddr; struct in_addr imr_interface; }; # else typedef ip_mreq in4_mreq_type; # endif typedef sockaddr_in sockaddr_in4_type; typedef in6_addr in6_addr_type; typedef ipv6_mreq in6_mreq_type; typedef sockaddr_in6 sockaddr_in6_type; typedef sockaddr_storage sockaddr_storage_type; typedef sockaddr_un sockaddr_un_type; typedef addrinfo addrinfo_type; typedef int ioctl_arg_type; typedef uint32_t u_long_type; typedef uint16_t u_short_type; const int shutdown_receive = SHUT_RD; const int shutdown_send = SHUT_WR; const int shutdown_both = SHUT_RDWR; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; # if defined(IOV_MAX) const int max_iov_len = IOV_MAX; # else // POSIX platforms are not required to define IOV_MAX. const int max_iov_len = 16; # endif #endif const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; const int always_fail_option = 2; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_TYPES_HPP percona-galera-3-3.8-3390/asio/asio/detail/solaris_fenced_block.hpp000066400000000000000000000020171244131713600247750ustar00rootroot00000000000000// // detail/solaris_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP #define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(__sun) #include #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class solaris_fenced_block : private noncopyable { public: // Constructor. solaris_fenced_block() { membar_consumer(); } // Destructor. ~solaris_fenced_block() { membar_producer(); } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(__sun) #endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/strand_service.hpp000066400000000000000000000065541244131713600236700ustar00rootroot00000000000000// // detail/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_STRAND_SERVICE_HPP #define ASIO_DETAIL_STRAND_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Default service implementation for a strand. class strand_service : public asio::detail::service_base { private: // Helper class to re-post the strand on exit. struct on_do_complete_exit; // Helper class to re-post the strand on exit. struct on_dispatch_exit; public: // The underlying implementation of a strand. class strand_impl : public operation { public: strand_impl(); private: // Only this service will have access to the internal values. friend class strand_service; friend struct on_do_complete_exit; friend struct on_dispatch_exit; // Mutex to protect access to internal data. asio::detail::mutex mutex_; // The count of handlers in the strand, including the upcall (if any). std::size_t count_; // The handlers waiting on the strand. op_queue queue_; }; typedef strand_impl* implementation_type; // Construct a new strand service for the specified io_service. ASIO_DECL explicit strand_service(asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new strand implementation. ASIO_DECL void construct(implementation_type& impl); // Destroy a strand implementation. void destroy(implementation_type& impl); // Request the io_service to invoke the given handler. template void dispatch(implementation_type& impl, Handler handler); // Request the io_service to invoke the given handler and return immediately. template void post(implementation_type& impl, Handler handler); private: ASIO_DECL static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred); // The io_service implementation used to post completions. io_service_impl& io_service_; // Mutex to protect access to the array of implementations. asio::detail::mutex mutex_; // Number of implementations shared between all strand objects. enum { num_implementations = 193 }; // The head of a linked list of all implementations. boost::scoped_ptr implementations_[num_implementations]; // Extra value used when hashing to prevent recycled memory locations from // getting the same strand implementation. std::size_t salt_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/strand_service.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/strand_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_STRAND_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/task_io_service.hpp000066400000000000000000000122041244131713600240130ustar00rootroot00000000000000// // detail/task_io_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TASK_IO_SERVICE_HPP #define ASIO_DETAIL_TASK_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_HAS_IOCP) #include #include "asio/error_code.hpp" #include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/reactor_fwd.hpp" #include "asio/detail/task_io_service_fwd.hpp" #include "asio/detail/task_io_service_operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class task_io_service : public asio::detail::service_base { public: typedef task_io_service_operation operation; // Constructor. ASIO_DECL task_io_service(asio::io_service& io_service); // How many concurrent threads are likely to run the io_service. ASIO_DECL void init(std::size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task, if required. ASIO_DECL void init_task(); // Run the event loop until interrupted or no more work. ASIO_DECL std::size_t run(asio::error_code& ec); // Run until interrupted or one operation is performed. ASIO_DECL std::size_t run_one(asio::error_code& ec); // Poll for operations without blocking. ASIO_DECL std::size_t poll(asio::error_code& ec); // Poll for one operation without blocking. ASIO_DECL std::size_t poll_one(asio::error_code& ec); // Interrupt the event processing loop. ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. ASIO_DECL void reset(); // Notify that some work has started. void work_started() { ++outstanding_work_; } // Notify that some work has finished. void work_finished() { if (--outstanding_work_ == 0) stop(); } // Request invocation of the given handler. template void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. ASIO_DECL void post_immediate_completion(operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. ASIO_DECL void post_deferred_completion(operation* op); // Request invocation of the given operations and return immediately. Assumes // that work_started() was previously called for each operation. ASIO_DECL void post_deferred_completions(op_queue& ops); private: // Structure containing information about an idle thread. struct idle_thread_info; // Run at most one operation. Blocks only if this_idle_thread is non-null. ASIO_DECL std::size_t do_one(mutex::scoped_lock& lock, idle_thread_info* this_idle_thread); // Stop the task and all idle threads. ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); // Wakes a single idle thread and unlocks the mutex. Returns true if an idle // thread was found. If there is no idle thread, returns false and leaves the // mutex locked. ASIO_DECL bool wake_one_idle_thread_and_unlock( mutex::scoped_lock& lock); // Wake a single idle thread, or the task, and always unlock the mutex. ASIO_DECL void wake_one_thread_and_unlock( mutex::scoped_lock& lock); // Helper class to perform task-related operations on block exit. struct task_cleanup; friend struct task_cleanup; // Helper class to call work_finished() on block exit. struct work_finished_on_block_exit; // Mutex to protect access to internal data. mutex mutex_; // The task to be run by this service. reactor* task_; // Operation object to represent the position of the task in the queue. struct task_operation : operation { task_operation() : operation(0) {} } task_operation_; // Whether the task has been interrupted. bool task_interrupted_; // The count of unfinished work. boost::detail::atomic_count outstanding_work_; // The queue of handlers that are ready to be delivered. op_queue op_queue_; // Flag to indicate that the dispatcher has been stopped. bool stopped_; // Flag to indicate that the dispatcher has been shut down. bool shutdown_; // The threads that are currently idle. idle_thread_info* first_idle_thread_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/task_io_service.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/task_io_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // !defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_TASK_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/task_io_service_fwd.hpp000066400000000000000000000012251244131713600246540ustar00rootroot00000000000000// // detail/task_io_service_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP #define ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { namespace detail { class task_io_service; } // namespace detail } // namespace asio #endif // ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/task_io_service_operation.hpp000066400000000000000000000030751244131713600261010ustar00rootroot00000000000000// // detail/task_io_service_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP #define ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/error_code.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/task_io_service_fwd.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. class task_io_service_operation { public: void complete(task_io_service& owner) { func_(&owner, this, asio::error_code(), 0); } void destroy() { func_(0, this, asio::error_code(), 0); } protected: typedef void (*func_type)(task_io_service*, task_io_service_operation*, asio::error_code, std::size_t); task_io_service_operation(func_type func) : next_(0), func_(func) { } // Prevents deletion through this type. ~task_io_service_operation() { } private: friend class op_queue_access; task_io_service_operation* next_; func_type func_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_TASK_IO_SERVICE_OPERATION_HPP percona-galera-3-3.8-3390/asio/asio/detail/thread.hpp000066400000000000000000000024031244131713600221110ustar00rootroot00000000000000// // detail/thread.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_THREAD_HPP #define ASIO_DETAIL_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_thread.hpp" #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) # include "asio/detail/wince_thread.hpp" # else # include "asio/detail/win_thread.hpp" # endif #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_thread.hpp" #else # error Only Windows and POSIX are supported! #endif namespace asio { namespace detail { #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) typedef null_thread thread; #elif defined(BOOST_WINDOWS) # if defined(UNDER_CE) typedef wince_thread thread; # else typedef win_thread thread; # endif #elif defined(BOOST_HAS_PTHREADS) typedef posix_thread thread; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/detail/throw_error.hpp000066400000000000000000000023141244131713600232170ustar00rootroot00000000000000// // detail/throw_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_THROW_ERROR_HPP #define ASIO_DETAIL_THROW_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { ASIO_DECL void do_throw_error(const asio::error_code& err); ASIO_DECL void do_throw_error(const asio::error_code& err, const char* location); inline void throw_error(const asio::error_code& err) { if (err) do_throw_error(err); } inline void throw_error(const asio::error_code& err, const char* location) { if (err) do_throw_error(err, location); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/throw_error.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_THROW_ERROR_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_op.hpp000066400000000000000000000016521244131713600224650ustar00rootroot00000000000000// // detail/timer_op.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_OP_HPP #define ASIO_DETAIL_TIMER_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class timer_op : public operation { public: // The error code to be passed to the completion handler. asio::error_code ec_; protected: timer_op(func_type func) : operation(func) { } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_TIMER_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_queue.hpp000066400000000000000000000245361244131713600232010ustar00rootroot00000000000000// // detail/timer_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_QUEUE_HPP #define ASIO_DETAIL_TIMER_QUEUE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/op_queue.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/error.hpp" #include "asio/time_traits.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class timer_queue : public timer_queue_base { public: // The time type. typedef typename Time_Traits::time_type time_type; // The duration type. typedef typename Time_Traits::duration_type duration_type; // Per-timer data. class per_timer_data { public: per_timer_data() : next_(0), prev_(0) {} private: friend class timer_queue; // The operations waiting on the timer. op_queue op_queue_; // The index of the timer in the heap. std::size_t heap_index_; // Pointers to adjacent timers in a linked list. per_timer_data* next_; per_timer_data* prev_; }; // Constructor. timer_queue() : timers_(), heap_() { } // Add a new timer to the queue. Returns true if this is the timer that is // earliest in the queue, in which case the reactor's event demultiplexing // function call may need to be interrupted and restarted. bool enqueue_timer(const time_type& time, per_timer_data& timer, timer_op* op) { // Enqueue the timer object. if (timer.prev_ == 0 && &timer != timers_) { if (this->is_positive_infinity(time)) { // No heap entry is required for timers that never expire. timer.heap_index_ = (std::numeric_limits::max)(); } else { // Put the new timer at the correct position in the heap. This is done // first since push_back() can throw due to allocation failure. timer.heap_index_ = heap_.size(); heap_entry entry = { time, &timer }; heap_.push_back(entry); up_heap(heap_.size() - 1); } // Insert the new timer into the linked list of active timers. timer.next_ = timers_; timer.prev_ = 0; if (timers_) timers_->prev_ = &timer; timers_ = &timer; } // Enqueue the individual timer operation. timer.op_queue_.push(op); // Interrupt reactor only if newly added timer is first to expire. return timer.heap_index_ == 0 && timer.op_queue_.front() == op; } // Whether there are no timers in the queue. virtual bool empty() const { return timers_ == 0; } // Get the time for the timer that is earliest in the queue. virtual long wait_duration_msec(long max_duration) const { if (heap_.empty()) return max_duration; boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( Time_Traits::subtract(heap_[0].time_, Time_Traits::now())); if (duration > boost::posix_time::milliseconds(max_duration)) duration = boost::posix_time::milliseconds(max_duration); else if (duration <= boost::posix_time::milliseconds(0)) duration = boost::posix_time::milliseconds(0); else if (duration < boost::posix_time::milliseconds(1)) duration = boost::posix_time::milliseconds(1); return duration.total_milliseconds(); } // Get the time for the timer that is earliest in the queue. virtual long wait_duration_usec(long max_duration) const { if (heap_.empty()) return max_duration; boost::posix_time::time_duration duration = Time_Traits::to_posix_duration( Time_Traits::subtract(heap_[0].time_, Time_Traits::now())); if (duration > boost::posix_time::microseconds(max_duration)) duration = boost::posix_time::microseconds(max_duration); else if (duration <= boost::posix_time::microseconds(0)) duration = boost::posix_time::microseconds(0); else if (duration < boost::posix_time::microseconds(1)) duration = boost::posix_time::microseconds(1); return duration.total_microseconds(); } // Dequeue all timers not later than the current time. virtual void get_ready_timers(op_queue& ops) { const time_type now = Time_Traits::now(); while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) { per_timer_data* timer = heap_[0].timer_; ops.push(timer->op_queue_); remove_timer(*timer); } } // Dequeue all timers. virtual void get_all_timers(op_queue& ops) { while (timers_) { per_timer_data* timer = timers_; timers_ = timers_->next_; ops.push(timer->op_queue_); timer->next_ = 0; timer->prev_ = 0; } heap_.clear(); } // Cancel and dequeue the timers with the given token. std::size_t cancel_timer(per_timer_data& timer, op_queue& ops) { std::size_t num_cancelled = 0; if (timer.prev_ != 0 || &timer == timers_) { while (timer_op* op = timer.op_queue_.front()) { op->ec_ = asio::error::operation_aborted; timer.op_queue_.pop(); ops.push(op); ++num_cancelled; } remove_timer(timer); } return num_cancelled; } private: // Move the item at the given index up the heap to its correct position. void up_heap(std::size_t index) { std::size_t parent = (index - 1) / 2; while (index > 0 && Time_Traits::less_than(heap_[index].time_, heap_[parent].time_)) { swap_heap(index, parent); index = parent; parent = (index - 1) / 2; } } // Move the item at the given index down the heap to its correct position. void down_heap(std::size_t index) { std::size_t child = index * 2 + 1; while (child < heap_.size()) { std::size_t min_child = (child + 1 == heap_.size() || Time_Traits::less_than( heap_[child].time_, heap_[child + 1].time_)) ? child : child + 1; if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_)) break; swap_heap(index, min_child); index = min_child; child = index * 2 + 1; } } // Swap two entries in the heap. void swap_heap(std::size_t index1, std::size_t index2) { heap_entry tmp = heap_[index1]; heap_[index1] = heap_[index2]; heap_[index2] = tmp; heap_[index1].timer_->heap_index_ = index1; heap_[index2].timer_->heap_index_ = index2; } // Remove a timer from the heap and list of timers. void remove_timer(per_timer_data& timer) { // Remove the timer from the heap. std::size_t index = timer.heap_index_; if (!heap_.empty() && index < heap_.size()) { if (index == heap_.size() - 1) { heap_.pop_back(); } else { swap_heap(index, heap_.size() - 1); heap_.pop_back(); std::size_t parent = (index - 1) / 2; if (index > 0 && Time_Traits::less_than( heap_[index].time_, heap_[parent].time_)) up_heap(index); else down_heap(index); } } // Remove the timer from the linked list of active timers. if (timers_ == &timer) timers_ = timer.next_; if (timer.prev_) timer.prev_->next_ = timer.next_; if (timer.next_) timer.next_->prev_= timer.prev_; timer.next_ = 0; timer.prev_ = 0; } // Determine if the specified absolute time is positive infinity. template static bool is_positive_infinity(const Time_Type&) { return false; } // Determine if the specified absolute time is positive infinity. static bool is_positive_infinity(const boost::posix_time::ptime& time) { return time == boost::posix_time::pos_infin; } // The head of a linked list of all active timers. per_timer_data* timers_; struct heap_entry { // The time when the timer should fire. time_type time_; // The associated timer with enqueued operations. per_timer_data* timer_; }; // The heap of timers, with the earliest timer at the front. std::vector heap_; }; #if !defined(ASIO_HEADER_ONLY) struct forwarding_posix_time_traits : time_traits {}; // Template specialisation for the commonly used instantation. template <> class timer_queue > : public timer_queue_base { public: // The time type. typedef boost::posix_time::ptime time_type; // The duration type. typedef boost::posix_time::time_duration duration_type; // Per-timer data. typedef timer_queue::per_timer_data per_timer_data; // Constructor. ASIO_DECL timer_queue(); // Destructor. ASIO_DECL virtual ~timer_queue(); // Add a new timer to the queue. Returns true if this is the timer that is // earliest in the queue, in which case the reactor's event demultiplexing // function call may need to be interrupted and restarted. ASIO_DECL bool enqueue_timer(const time_type& time, per_timer_data& timer, timer_op* op); // Whether there are no timers in the queue. ASIO_DECL virtual bool empty() const; // Get the time for the timer that is earliest in the queue. ASIO_DECL virtual long wait_duration_msec(long max_duration) const; // Get the time for the timer that is earliest in the queue. ASIO_DECL virtual long wait_duration_usec(long max_duration) const; // Dequeue all timers not later than the current time. ASIO_DECL virtual void get_ready_timers(op_queue& ops); // Dequeue all timers. ASIO_DECL virtual void get_all_timers(op_queue& ops); // Cancel and dequeue the timers with the given token. ASIO_DECL std::size_t cancel_timer( per_timer_data& timer, op_queue& ops); private: timer_queue impl_; }; #endif // !defined(ASIO_HEADER_ONLY) } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_TIMER_QUEUE_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_queue_base.hpp000066400000000000000000000031111244131713600241550ustar00rootroot00000000000000// // detail/timer_queue_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_QUEUE_BASE_HPP #define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class timer_queue_base : private noncopyable { public: // Constructor. timer_queue_base() : next_(0) {} // Destructor. virtual ~timer_queue_base() {} // Whether there are no timers in the queue. virtual bool empty() const = 0; // Get the time to wait until the next timer. virtual long wait_duration_msec(long max_duration) const = 0; // Get the time to wait until the next timer. virtual long wait_duration_usec(long max_duration) const = 0; // Dequeue all ready timers. virtual void get_ready_timers(op_queue& ops) = 0; // Dequeue all timers. virtual void get_all_timers(op_queue& ops) = 0; private: friend class timer_queue_set; // Next timer queue in the set. timer_queue_base* next_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_queue_fwd.hpp000066400000000000000000000012351244131713600240300ustar00rootroot00000000000000// // detail/timer_queue_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_QUEUE_FWD_HPP #define ASIO_DETAIL_TIMER_QUEUE_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) namespace asio { namespace detail { template class timer_queue; } // namespace detail } // namespace asio #endif // ASIO_DETAIL_TIMER_QUEUE_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_queue_set.hpp000066400000000000000000000031721244131713600240450ustar00rootroot00000000000000// // detail/timer_queue_set.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_QUEUE_SET_HPP #define ASIO_DETAIL_TIMER_QUEUE_SET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class timer_queue_set { public: // Constructor. ASIO_DECL timer_queue_set(); // Add a timer queue to the set. ASIO_DECL void insert(timer_queue_base* q); // Remove a timer queue from the set. ASIO_DECL void erase(timer_queue_base* q); // Determine whether all queues are empty. ASIO_DECL bool all_empty() const; // Get the wait duration in milliseconds. ASIO_DECL long wait_duration_msec(long max_duration) const; // Get the wait duration in microseconds. ASIO_DECL long wait_duration_usec(long max_duration) const; // Dequeue all ready timers. ASIO_DECL void get_ready_timers(op_queue& ops); // Dequeue all timers. ASIO_DECL void get_all_timers(op_queue& ops); private: timer_queue_base* first_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/timer_queue_set.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_scheduler.hpp000066400000000000000000000017171244131713600240270ustar00rootroot00000000000000// // detail/timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_SCHEDULER_HPP #define ASIO_DETAIL_TIMER_SCHEDULER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/timer_scheduler_fwd.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_service.hpp" #elif defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor.hpp" #elif defined(ASIO_HAS_KQUEUE) # include "asio/detail/kqueue_reactor.hpp" #elif defined(ASIO_HAS_DEV_POLL) # include "asio/detail/dev_poll_reactor.hpp" #else # include "asio/detail/select_reactor.hpp" #endif #endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP percona-galera-3-3.8-3390/asio/asio/detail/timer_scheduler_fwd.hpp000066400000000000000000000025551244131713600246700ustar00rootroot00000000000000// // detail/timer_scheduler_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP #define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_service_fwd.hpp" #elif defined(ASIO_HAS_EPOLL) # include "asio/detail/epoll_reactor_fwd.hpp" #elif defined(ASIO_HAS_KQUEUE) # include "asio/detail/kqueue_reactor_fwd.hpp" #elif defined(ASIO_HAS_DEV_POLL) # include "asio/detail/dev_poll_reactor_fwd.hpp" #else # include "asio/detail/select_reactor_fwd.hpp" #endif namespace asio { namespace detail { #if defined(ASIO_HAS_IOCP) typedef win_iocp_io_service timer_scheduler; #elif defined(ASIO_HAS_EPOLL) typedef epoll_reactor timer_scheduler; #elif defined(ASIO_HAS_KQUEUE) typedef kqueue_reactor timer_scheduler; #elif defined(ASIO_HAS_DEV_POLL) typedef dev_poll_reactor timer_scheduler; #else typedef select_reactor timer_scheduler; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/tss_ptr.hpp000066400000000000000000000030251244131713600223410ustar00rootroot00000000000000// // detail/tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_TSS_PTR_HPP #define ASIO_DETAIL_TSS_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) # include "asio/detail/null_tss_ptr.hpp" #elif defined(BOOST_WINDOWS) # include "asio/detail/win_tss_ptr.hpp" #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_tss_ptr.hpp" #else # error Only Windows and POSIX are supported! #endif #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class tss_ptr #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) : public null_tss_ptr #elif defined(BOOST_WINDOWS) : public win_tss_ptr #elif defined(BOOST_HAS_PTHREADS) : public posix_tss_ptr #endif { public: void operator=(T* value) { #if !defined(BOOST_HAS_THREADS) || defined(ASIO_DISABLE_THREADS) null_tss_ptr::operator=(value); #elif defined(BOOST_WINDOWS) win_tss_ptr::operator=(value); #elif defined(BOOST_HAS_PTHREADS) posix_tss_ptr::operator=(value); #endif } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_TSS_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/wait_handler.hpp000066400000000000000000000041761244131713600233140ustar00rootroot00000000000000// // detail/wait_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WAIT_HANDLER_HPP #define ASIO_DETAIL_WAIT_HANDLER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class wait_handler : public timer_op { public: ASIO_DEFINE_HANDLER_PTR(wait_handler); wait_handler(Handler h) : timer_op(&wait_handler::do_complete), handler_(h) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code /*ec*/, std::size_t /*bytes_transferred*/) { // Take ownership of the handler object. wait_handler* h(static_cast(base)); ptr p = { boost::addressof(h->handler_), h, h }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder1 handler(h->handler_, h->ec_); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_WAIT_HANDLER_HPP percona-galera-3-3.8-3390/asio/asio/detail/weak_ptr.hpp000066400000000000000000000015301244131713600224560ustar00rootroot00000000000000// // detail/weak_ptr.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WEAK_PTR_HPP #define ASIO_DETAIL_WEAK_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #if defined(_MSC_VER) && (_MSC_VER >= 1600) # include #else # include #endif namespace asio { namespace detail { #if defined(_MSC_VER) && (_MSC_VER >= 1600) using std::weak_ptr; #else using boost::weak_ptr; #endif } // namespace detail } // namespace asio #endif // ASIO_DETAIL_WEAK_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_event.hpp000066400000000000000000000035571244131713600226530ustar00rootroot00000000000000// // detail/win_event.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_EVENT_HPP #define ASIO_DETAIL_WIN_EVENT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_event : private noncopyable { public: // Constructor. ASIO_DECL win_event(); // Destructor. ~win_event() { ::CloseHandle(event_); } // Signal the event. template void signal(Lock& lock) { BOOST_ASSERT(lock.locked()); (void)lock; ::SetEvent(event_); } // Signal the event and unlock the mutex. template void signal_and_unlock(Lock& lock) { BOOST_ASSERT(lock.locked()); lock.unlock(); ::SetEvent(event_); } // Reset the event. template void clear(Lock& lock) { BOOST_ASSERT(lock.locked()); (void)lock; ::ResetEvent(event_); } // Wait for the event to become signalled. template void wait(Lock& lock) { BOOST_ASSERT(lock.locked()); lock.unlock(); ::WaitForSingleObject(event_, INFINITE); lock.lock(); } private: HANDLE event_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_event.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_WIN_EVENT_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_fd_set_adapter.hpp000066400000000000000000000040241244131713600244640ustar00rootroot00000000000000// // detail/win_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP #define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. class win_fd_set_adapter { public: enum { win_fd_set_size = 1024 }; win_fd_set_adapter() : max_descriptor_(invalid_socket) { fd_set_.fd_count = 0; } bool set(socket_type descriptor) { for (u_int i = 0; i < fd_set_.fd_count; ++i) if (fd_set_.fd_array[i] == descriptor) return true; if (fd_set_.fd_count < win_fd_set_size) { fd_set_.fd_array[fd_set_.fd_count++] = descriptor; return true; } return false; } bool is_set(socket_type descriptor) const { return !!__WSAFDIsSet(descriptor, const_cast(reinterpret_cast(&fd_set_))); } operator fd_set*() { return reinterpret_cast(&fd_set_); } socket_type max_descriptor() const { return max_descriptor_; } private: // This structure is defined to be compatible with the Windows API fd_set // structure, but without being dependent on the value of FD_SETSIZE. struct win_fd_set { u_int fd_count; SOCKET fd_array[win_fd_set_size]; }; win_fd_set fd_set_; socket_type max_descriptor_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_fenced_block.hpp000066400000000000000000000034071244131713600241220ustar00rootroot00000000000000// // detail/win_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_FENCED_BLOCK_HPP #define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_fenced_block : private noncopyable { public: // Constructor. win_fenced_block() { #if defined(__BORLANDC__) LONG barrier = 0; ::InterlockedExchange(&barrier, 1); #elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier)) # if defined(_M_IX86) # pragma warning(push) # pragma warning(disable:4793) LONG barrier; __asm { xchg barrier, eax } # pragma warning(pop) # endif // defined(_M_IX86) #else MemoryBarrier(); #endif } // Destructor. ~win_fenced_block() { #if defined(__BORLANDC__) LONG barrier = 0; ::InterlockedExchange(&barrier, 1); #elif defined(BOOST_MSVC) && ((BOOST_MSVC < 1400) || !defined(MemoryBarrier)) # if defined(_M_IX86) # pragma warning(push) # pragma warning(disable:4793) LONG barrier; __asm { xchg barrier, eax } # pragma warning(pop) # endif // defined(_M_IX86) #else MemoryBarrier(); #endif } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_handle_read_op.hpp000066400000000000000000000061321244131713600254600ustar00rootroot00000000000000// // detail/win_iocp_handle_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP #define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/error.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_handle_read_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); win_iocp_handle_read_op(const MutableBufferSequence& buffers, Handler handler) : operation(&win_iocp_handle_read_op::do_complete), buffers_(buffers), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_handle_read_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { // Check whether buffers are still valid. buffer_sequence_adapter::validate(o->buffers_); } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_HANDLE_EOF) ec = asio::error::eof; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: MutableBufferSequence buffers_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_handle_service.hpp000066400000000000000000000236151244131713600255140ustar00rootroot00000000000000// // detail/win_iocp_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP #define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/win_iocp_handle_read_op.hpp" #include "asio/detail/win_iocp_handle_write_op.hpp" #include "asio/detail/win_iocp_io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_iocp_handle_service { public: // The native type of a stream handle. typedef HANDLE native_type; // The implementation type of the stream handle. class implementation_type { public: // Default constructor. implementation_type() : handle_(INVALID_HANDLE_VALUE), safe_cancellation_thread_id_(0), next_(0), prev_(0) { } private: // Only this service will have access to the internal values. friend class win_iocp_handle_service; // The native stream handle representation. native_type handle_; // The ID of the thread from which it is safe to cancel asynchronous // operations. 0 means no asynchronous operations have been started yet. // ~0 means asynchronous operations have been started from more than one // thread, and cancellation is not supported for the handle. DWORD safe_cancellation_thread_id_; // Pointers to adjacent handle implementations in linked list. implementation_type* next_; implementation_type* prev_; }; ASIO_DECL win_iocp_handle_service(asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new handle implementation. ASIO_DECL void construct(implementation_type& impl); // Destroy a handle implementation. ASIO_DECL void destroy(implementation_type& impl); // Assign a native handle to a handle implementation. ASIO_DECL asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec); // Determine whether the handle is open. bool is_open(const implementation_type& impl) const { return impl.handle_ != INVALID_HANDLE_VALUE; } // Destroy a handle implementation. ASIO_DECL asio::error_code close(implementation_type& impl, asio::error_code& ec); // Get the native handle representation. native_type native(const implementation_type& impl) const { return impl.handle_; } // Cancel all operations associated with the handle. ASIO_DECL asio::error_code cancel(implementation_type& impl, asio::error_code& ec); // Write the given data. Returns the number of bytes written. template size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return write_some_at(impl, 0, buffers, ec); } // Write the given data at the specified offset. Returns the number of bytes // written. template size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, asio::error_code& ec) { asio::const_buffer buffer = buffer_sequence_adapter::first(buffers); return do_write(impl, offset, buffer, ec); } // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { async_write_some_at(impl, 0, buffers, handler); } // Start an asynchronous write at a specified offset. The data being written // must be valid for the lifetime of the asynchronous operation. template void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_write_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(buffers, handler); start_write_op(impl, offset, buffer_sequence_adapter::first(buffers), p.p); p.v = p.p = 0; } // Read some data. Returns the number of bytes received. template size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return read_some_at(impl, 0, buffers, ec); } // Read some data at a specified offset. Returns the number of bytes received. template size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, asio::error_code& ec) { asio::mutable_buffer buffer = buffer_sequence_adapter::first(buffers); return do_read(impl, offset, buffer, ec); } // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { async_read_some_at(impl, 0, buffers, handler); } // Start an asynchronous read at a specified offset. The buffer for the data // being received must be valid for the lifetime of the asynchronous // operation. template void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_handle_read_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(buffers, handler); start_read_op(impl, offset, buffer_sequence_adapter::first(buffers), p.p); p.v = p.p = 0; } private: // Prevent the use of the null_buffers type with this service. size_t write_some(implementation_type& impl, const null_buffers& buffers, asio::error_code& ec); size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, asio::error_code& ec); template void async_write_some(implementation_type& impl, const null_buffers& buffers, Handler handler); template void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); size_t read_some(implementation_type& impl, const null_buffers& buffers, asio::error_code& ec); size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, asio::error_code& ec); template void async_read_some(implementation_type& impl, const null_buffers& buffers, Handler handler); template void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const null_buffers& buffers, Handler handler); // Helper class for waiting for synchronous operations to complete. class overlapped_wrapper; // Helper function to perform a synchronous write operation. ASIO_DECL size_t do_write(implementation_type& impl, boost::uint64_t offset, const asio::const_buffer& buffer, asio::error_code& ec); // Helper function to start a write operation. ASIO_DECL void start_write_op(implementation_type& impl, boost::uint64_t offset, const asio::const_buffer& buffer, operation* op); // Helper function to perform a synchronous write operation. ASIO_DECL size_t do_read(implementation_type& impl, boost::uint64_t offset, const asio::mutable_buffer& buffer, asio::error_code& ec); // Helper function to start a read operation. ASIO_DECL void start_read_op(implementation_type& impl, boost::uint64_t offset, const asio::mutable_buffer& buffer, operation* op); // Update the ID of the thread from which cancellation is safe. ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); // Helper function to close a handle when the associated object is being // destroyed. ASIO_DECL void close_for_destruction(implementation_type& impl); // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // Mutex to protect access to the linked list of implementations. mutex mutex_; // The head of a linked list of all implementations. implementation_type* impl_list_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_iocp_handle_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_handle_write_op.hpp000066400000000000000000000057261244131713600257070ustar00rootroot00000000000000// // detail/win_iocp_handle_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP #define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/error.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_handle_write_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler handler) : operation(&win_iocp_handle_write_op::do_complete), buffers_(buffers), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_handle_write_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { // Check whether buffers are still valid. buffer_sequence_adapter::validate(o->buffers_); } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: ConstBufferSequence buffers_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_io_service.hpp000066400000000000000000000204631244131713600246660ustar00rootroot00000000000000// // detail/win_iocp_io_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP #define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/op_queue.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_op.hpp" #include "asio/detail/timer_queue_base.hpp" #include "asio/detail/timer_queue_fwd.hpp" #include "asio/detail/timer_queue_set.hpp" #include "asio/detail/win_iocp_io_service_fwd.hpp" #include "asio/detail/win_iocp_operation.hpp" #include "asio/detail/thread.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class timer_op; class win_iocp_io_service : public asio::detail::service_base { public: // Constructor. ASIO_DECL win_iocp_io_service(asio::io_service& io_service); ASIO_DECL void init(size_t concurrency_hint); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Initialise the task. Nothing to do here. void init_task() { } // Register a handle with the IO completion port. ASIO_DECL asio::error_code register_handle( HANDLE handle, asio::error_code& ec); // Run the event loop until stopped or no more work. ASIO_DECL size_t run(asio::error_code& ec); // Run until stopped or one operation is performed. ASIO_DECL size_t run_one(asio::error_code& ec); // Poll for operations without blocking. ASIO_DECL size_t poll(asio::error_code& ec); // Poll for one operation without blocking. ASIO_DECL size_t poll_one(asio::error_code& ec); // Stop the event processing loop. ASIO_DECL void stop(); // Reset in preparation for a subsequent run invocation. void reset() { ::InterlockedExchange(&stopped_, 0); } // Notify that some work has started. void work_started() { ::InterlockedIncrement(&outstanding_work_); } // Notify that some work has finished. void work_finished() { if (::InterlockedDecrement(&outstanding_work_) == 0) stop(); } // Request invocation of the given handler. template void dispatch(Handler handler); // Request invocation of the given handler and return immediately. template void post(Handler handler); // Request invocation of the given operation and return immediately. Assumes // that work_started() has not yet been called for the operation. void post_immediate_completion(win_iocp_operation* op) { work_started(); post_deferred_completion(op); } // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operation. ASIO_DECL void post_deferred_completion(win_iocp_operation* op); // Request invocation of the given operation and return immediately. Assumes // that work_started() was previously called for the operations. ASIO_DECL void post_deferred_completions( op_queue& ops); // Called after starting an overlapped I/O operation that did not complete // immediately. The caller must have already called work_started() prior to // starting the operation. ASIO_DECL void on_pending(win_iocp_operation* op); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. ASIO_DECL void on_completion(win_iocp_operation* op, DWORD last_error = 0, DWORD bytes_transferred = 0); // Called after starting an overlapped I/O operation that completed // immediately. The caller must have already called work_started() prior to // starting the operation. ASIO_DECL void on_completion(win_iocp_operation* op, const asio::error_code& ec, DWORD bytes_transferred = 0); // Add a new timer queue to the service. template void add_timer_queue(timer_queue& timer_queue); // Remove a timer queue from the service. template void remove_timer_queue(timer_queue& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template void schedule_timer(timer_queue& queue, const typename Time_Traits::time_type& time, typename timer_queue::per_timer_data& timer, timer_op* op); // Cancel the timer associated with the given token. Returns the number of // handlers that have been posted or dispatched. template std::size_t cancel_timer(timer_queue& queue, typename timer_queue::per_timer_data& timer); private: #if defined(WINVER) && (WINVER < 0x0500) typedef DWORD dword_ptr_t; typedef ULONG ulong_ptr_t; #else // defined(WINVER) && (WINVER < 0x0500) typedef DWORD_PTR dword_ptr_t; typedef ULONG_PTR ulong_ptr_t; #endif // defined(WINVER) && (WINVER < 0x0500) // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). ASIO_DECL size_t do_one(bool block, asio::error_code& ec); // Helper function to add a new timer queue. ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); // Helper function to remove a timer queue. ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); // Called to recalculate and update the timeout. ASIO_DECL void update_timeout(); // Helper class to call work_finished() on block exit. struct work_finished_on_block_exit; // Helper class for managing a HANDLE. struct auto_handle { HANDLE handle; auto_handle() : handle(0) {} ~auto_handle() { if (handle) ::CloseHandle(handle); } }; // The IO completion port used for queueing operations. auto_handle iocp_; // The count of unfinished work. long outstanding_work_; // Flag to indicate whether the event loop has been stopped. long stopped_; // Flag to indicate whether the service has been shut down. long shutdown_; enum { // Timeout to use with GetQueuedCompletionStatus. Some versions of windows // have a "bug" where a call to GetQueuedCompletionStatus can appear stuck // even though there are events waiting on the queue. Using a timeout helps // to work around the issue. gqcs_timeout = 500, // Maximum waitable timer timeout, in milliseconds. max_timeout_msec = 5 * 60 * 1000, // Maximum waitable timer timeout, in microseconds. max_timeout_usec = max_timeout_msec * 1000, // Completion key value used to wake up a thread to dispatch timers or // completed operations. wake_for_dispatch = 1, // Completion key value to indicate that an operation has posted with the // original last_error and bytes_transferred values stored in the fields of // the OVERLAPPED structure. overlapped_contains_result = 2 }; // Function object for processing timeouts in a background thread. struct timer_thread_function; friend struct timer_thread_function; // Background thread used for processing timeouts. boost::scoped_ptr timer_thread_; // A waitable timer object used for waiting for timeouts. auto_handle waitable_timer_; // Non-zero if timers or completed operations need to be dispatched. long dispatch_required_; // Mutex for protecting access to the timer queues and completed operations. mutex dispatch_mutex_; // The timer queues. timer_queue_set timer_queues_; // The operations that are ready to dispatch. op_queue completed_ops_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/detail/impl/win_iocp_io_service.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_iocp_io_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_io_service_fwd.hpp000066400000000000000000000014551244131713600255260ustar00rootroot00000000000000// // detail/win_iocp_io_service_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP #define ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) namespace asio { namespace detail { class win_iocp_io_service; class win_iocp_overlapped_ptr; } // namespace detail } // namespace asio #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_null_buffers_op.hpp000066400000000000000000000063771244131713600257330ustar00rootroot00000000000000// // detail/win_iocp_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP #define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_null_buffers_op : public reactor_op { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, Handler handler) : reactor_op(&win_iocp_null_buffers_op::do_perform, &win_iocp_null_buffers_op::do_complete), cancel_token_(cancel_token), handler_(handler) { } static bool do_perform(reactor_op*) { return true; } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_null_buffers_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // The reactor may have stored a result in the operation object. if (o->ec_) ec = o->ec_; // Map non-portable errors to their portable counterparts. if (ec.value() == ERROR_NETNAME_DELETED) { if (o->cancel_token_.expired()) ec = asio::error::operation_aborted; else ec = asio::error::connection_reset; } else if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; } // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: socket_ops::weak_cancel_token_type cancel_token_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_operation.hpp000066400000000000000000000036301244131713600245340ustar00rootroot00000000000000// // detail/win_iocp_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_OPERATION_HPP #define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/detail/op_queue.hpp" #include "asio/detail/win_iocp_io_service_fwd.hpp" #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Base class for all operations. A function pointer is used instead of virtual // functions to avoid the associated overhead. class win_iocp_operation : public OVERLAPPED { public: void complete(win_iocp_io_service& owner, const asio::error_code& ec = asio::error_code(), std::size_t bytes_transferred = 0) { func_(&owner, this, ec, bytes_transferred); } void destroy() { func_(0, this, asio::error_code(), 0); } protected: typedef void (*func_type)(win_iocp_io_service*, win_iocp_operation*, asio::error_code, std::size_t); win_iocp_operation(func_type func) : next_(0), func_(func) { reset(); } // Prevents deletion through this type. ~win_iocp_operation() { } void reset() { Internal = 0; InternalHigh = 0; Offset = 0; OffsetHigh = 0; hEvent = 0; ready_ = 0; } private: friend class op_queue_access; friend class win_iocp_io_service; win_iocp_operation* next_; func_type func_; long ready_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_overlapped_op.hpp000066400000000000000000000046711244131713600254010ustar00rootroot00000000000000// // detail/win_iocp_overlapped_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP #define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include "asio/error.hpp" #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_overlapped_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); win_iocp_overlapped_op(Handler handler) : operation(&win_iocp_overlapped_op::do_complete), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_overlapped_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_overlapped_ptr.hpp000066400000000000000000000063171244131713600255670ustar00rootroot00000000000000// // detail/win_iocp_overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP #define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/io_service.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/win_iocp_overlapped_op.hpp" #include "asio/detail/win_iocp_io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. class win_iocp_overlapped_ptr : private noncopyable { public: // Construct an empty win_iocp_overlapped_ptr. win_iocp_overlapped_ptr() : ptr_(0), iocp_service_(0) { } // Construct an win_iocp_overlapped_ptr to contain the specified handler. template explicit win_iocp_overlapped_ptr( asio::io_service& io_service, Handler handler) : ptr_(0), iocp_service_(0) { this->reset(io_service, handler); } // Destructor automatically frees the OVERLAPPED object unless released. ~win_iocp_overlapped_ptr() { reset(); } // Reset to empty. void reset() { if (ptr_) { ptr_->destroy(); ptr_ = 0; iocp_service_->work_finished(); iocp_service_ = 0; } } // Reset to contain the specified handler, freeing any current OVERLAPPED // object. template void reset(asio::io_service& io_service, Handler handler) { typedef win_iocp_overlapped_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(handler); io_service.impl_.work_started(); reset(); ptr_ = p.p; p.v = p.p = 0; iocp_service_ = &io_service.impl_; } // Get the contained OVERLAPPED object. OVERLAPPED* get() { return ptr_; } // Get the contained OVERLAPPED object. const OVERLAPPED* get() const { return ptr_; } // Release ownership of the OVERLAPPED object. OVERLAPPED* release() { if (ptr_) iocp_service_->on_pending(ptr_); OVERLAPPED* tmp = ptr_; ptr_ = 0; iocp_service_ = 0; return tmp; } // Post completion notification for overlapped operation. Releases ownership. void complete(const asio::error_code& ec, std::size_t bytes_transferred) { if (ptr_) { iocp_service_->on_completion(ptr_, ec, static_cast(bytes_transferred)); ptr_ = 0; iocp_service_ = 0; } } private: win_iocp_operation* ptr_; win_iocp_io_service* iocp_service_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_serial_port_service.hpp000066400000000000000000000152641244131713600266050ustar00rootroot00000000000000// // detail/win_iocp_serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP #define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/win_iocp_handle_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Extend win_iocp_handle_service to provide serial port support. class win_iocp_serial_port_service { public: // The native type of a serial port. typedef win_iocp_handle_service::native_type native_type; // The implementation type of the serial port. typedef win_iocp_handle_service::implementation_type implementation_type; // Constructor. ASIO_DECL win_iocp_serial_port_service( asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new serial port implementation. void construct(implementation_type& impl) { handle_service_.construct(impl); } // Destroy a serial port implementation. void destroy(implementation_type& impl) { handle_service_.destroy(impl); } // Open the serial port using the specified device name. ASIO_DECL asio::error_code open(implementation_type& impl, const std::string& device, asio::error_code& ec); // Assign a native handle to a serial port implementation. asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { return handle_service_.assign(impl, native_handle, ec); } // Determine whether the serial port is open. bool is_open(const implementation_type& impl) const { return handle_service_.is_open(impl); } // Destroy a serial port implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return handle_service_.close(impl, ec); } // Get the native serial port representation. native_type native(implementation_type& impl) { return handle_service_.native(impl); } // Cancel all operations associated with the handle. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return handle_service_.cancel(impl, ec); } // Set an option on the serial port. template asio::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, asio::error_code& ec) { return do_set_option(impl, &win_iocp_serial_port_service::store_option, &option, ec); } // Get an option from the serial port. template asio::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, asio::error_code& ec) const { return do_get_option(impl, &win_iocp_serial_port_service::load_option, &option, ec); } // Send a break sequence to the serial port. asio::error_code send_break(implementation_type&, asio::error_code& ec) { ec = asio::error::operation_not_supported; return ec; } // Write the given data. Returns the number of bytes sent. template size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return handle_service_.write_some(impl, buffers, ec); } // Start an asynchronous write. The data being written must be valid for the // lifetime of the asynchronous operation. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler handler) { handle_service_.async_write_some(impl, buffers, handler); } // Read some data. Returns the number of bytes received. template size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return handle_service_.read_some(impl, buffers, ec); } // Start an asynchronous read. The buffer for the data being received must be // valid for the lifetime of the asynchronous operation. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler handler) { handle_service_.async_read_some(impl, buffers, handler); } private: // Function pointer type for storing a serial port option. typedef asio::error_code (*store_function_type)( const void*, ::DCB&, asio::error_code&); // Helper function template to store a serial port option. template static asio::error_code store_option(const void* option, ::DCB& storage, asio::error_code& ec) { return static_cast(option)->store( storage, ec); } // Helper function to set a serial port option. ASIO_DECL asio::error_code do_set_option( implementation_type& impl, store_function_type store, const void* option, asio::error_code& ec); // Function pointer type for loading a serial port option. typedef asio::error_code (*load_function_type)( void*, const ::DCB&, asio::error_code&); // Helper function template to load a serial port option. template static asio::error_code load_option(void* option, const ::DCB& storage, asio::error_code& ec) { return static_cast(option)->load(storage, ec); } // Helper function to get a serial port option. ASIO_DECL asio::error_code do_get_option( const implementation_type& impl, load_function_type load, void* option, asio::error_code& ec) const; // The implementation used for initiating asynchronous operations. win_iocp_handle_service handle_service_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_iocp_serial_port_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT) #endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_accept_op.hpp000066400000000000000000000114201244131713600260350ustar00rootroot00000000000000// // detail/win_iocp_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/win_iocp_socket_service_base.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_socket_accept_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, socket_type socket, Socket& peer, const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, bool enable_connection_aborted, Handler handler) : operation(&win_iocp_socket_accept_op::do_complete), socket_service_(socket_service), socket_(socket), peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), handler_(handler) { } socket_holder& new_socket() { return new_socket_; } void* output_buffer() { return output_buffer_; } DWORD address_length() { return sizeof(sockaddr_storage_type) + 16; } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t /*bytes_transferred*/) { // Take ownership of the operation object. win_iocp_socket_accept_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; if (owner) { typename Protocol::endpoint peer_endpoint; std::size_t addr_len = peer_endpoint.capacity(); socket_ops::complete_iocp_accept(o->socket_, o->output_buffer(), o->address_length(), peer_endpoint.data(), &addr_len, o->new_socket_.get(), ec); // Restart the accept operation if we got the connection_aborted error // and the enable_connection_aborted socket option is not set. if (ec == asio::error::connection_aborted && !o->enable_connection_aborted_) { o->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), o->protocol_.type(), o->protocol_.protocol(), o->output_buffer(), o->address_length(), o); p.v = p.p = 0; return; } // If the socket was successfully accepted, transfer ownership of the // socket to the peer object. if (!ec) { o->peer_.assign(o->protocol_, typename Socket::native_type( o->new_socket_.get(), peer_endpoint), ec); if (!ec) o->new_socket_.release(); } // Pass endpoint back to caller. if (o->peer_endpoint_) *o->peer_endpoint_ = peer_endpoint; } // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder1 handler(o->handler_, ec); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: win_iocp_socket_service_base& socket_service_; socket_type socket_; socket_holder new_socket_; Socket& peer_; Protocol protocol_; typename Protocol::endpoint* peer_endpoint_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_recv_op.hpp000066400000000000000000000065501244131713600255450ustar00rootroot00000000000000// // detail/win_iocp_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_socket_recv_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); win_iocp_socket_recv_op(socket_ops::state_type state, socket_ops::weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, Handler handler) : operation(&win_iocp_socket_recv_op::do_complete), state_(state), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_socket_recv_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter::validate(o->buffers_); } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, buffer_sequence_adapter::all_empty(o->buffers_), ec, bytes_transferred); // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: socket_ops::state_type state_; socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_recvfrom_op.hpp000066400000000000000000000070151244131713600264260ustar00rootroot00000000000000// // detail/win_iocp_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_socket_recvfrom_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); win_iocp_socket_recvfrom_op(Endpoint& endpoint, socket_ops::weak_cancel_token_type cancel_token, const MutableBufferSequence& buffers, Handler handler) : operation(&win_iocp_socket_recvfrom_op::do_complete), endpoint_(endpoint), endpoint_size_(static_cast(endpoint.capacity())), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } int& endpoint_size() { return endpoint_size_; } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_socket_recvfrom_op* o( static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter::validate(o->buffers_); } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); // Record the size of the endpoint returned by the operation. o->endpoint_.resize(o->endpoint_size_); // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: Endpoint& endpoint_; int endpoint_size_; socket_ops::weak_cancel_token_type cancel_token_; MutableBufferSequence buffers_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_send_op.hpp000066400000000000000000000061561244131713600255410ustar00rootroot00000000000000// // detail/win_iocp_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_socket_send_op : public operation { public: ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, const ConstBufferSequence& buffers, Handler handler) : operation(&win_iocp_socket_send_op::do_complete), cancel_token_(cancel_token), buffers_(buffers), handler_(handler) { } static void do_complete(io_service_impl* owner, operation* base, asio::error_code ec, std::size_t bytes_transferred) { // Take ownership of the operation object. win_iocp_socket_send_op* o(static_cast(base)); ptr p = { boost::addressof(o->handler_), o, o }; #if defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter::validate(o->buffers_); } #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) socket_ops::complete_iocp_send(o->cancel_token_, ec); // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Even if we're not about to make an upcall, a // sub-object of the handler may be the true owner of the memory associated // with the handler. Consequently, a local copy of the handler is required // to ensure that any owning sub-object remains valid until after we have // deallocated the memory here. detail::binder2 handler(o->handler_, ec, bytes_transferred); p.h = boost::addressof(handler.handler_); p.reset(); // Make the upcall if required. if (owner) { asio::detail::fenced_block b; asio_handler_invoke_helpers::invoke(handler, handler.handler_); } } private: socket_ops::weak_cancel_token_type cancel_token_; ConstBufferSequence buffers_; Handler handler_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_service.hpp000066400000000000000000000350511244131713600255460ustar00rootroot00000000000000// // detail/win_iocp_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/reactive_socket_connect_op.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/win_iocp_io_service.hpp" #include "asio/detail/win_iocp_null_buffers_op.hpp" #include "asio/detail/win_iocp_socket_accept_op.hpp" #include "asio/detail/win_iocp_socket_recvfrom_op.hpp" #include "asio/detail/win_iocp_socket_send_op.hpp" #include "asio/detail/win_iocp_socket_service_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class win_iocp_socket_service : public win_iocp_socket_service_base { public: // The protocol type. typedef Protocol protocol_type; // The endpoint type. typedef typename Protocol::endpoint endpoint_type; // The native type of a socket. class native_type { public: native_type(socket_type s) : socket_(s), have_remote_endpoint_(false) { } native_type(socket_type s, const endpoint_type& ep) : socket_(s), have_remote_endpoint_(true), remote_endpoint_(ep) { } void operator=(socket_type s) { socket_ = s; have_remote_endpoint_ = false; remote_endpoint_ = endpoint_type(); } operator socket_type() const { return socket_; } bool have_remote_endpoint() const { return have_remote_endpoint_; } endpoint_type remote_endpoint() const { return remote_endpoint_; } private: socket_type socket_; bool have_remote_endpoint_; endpoint_type remote_endpoint_; }; // The implementation type of the socket. struct implementation_type : win_iocp_socket_service_base::base_implementation_type { // Default constructor. implementation_type() : protocol_(endpoint_type().protocol()), have_remote_endpoint_(false), remote_endpoint_() { } // The protocol associated with the socket. protocol_type protocol_; // Whether we have a cached remote endpoint. bool have_remote_endpoint_; // A cached remote endpoint. endpoint_type remote_endpoint_; }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) : win_iocp_socket_service_base(io_service) { } // Open a new socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (!do_open(impl, protocol.family(), protocol.type(), protocol.protocol(), ec)) { impl.protocol_ = protocol; impl.have_remote_endpoint_ = false; impl.remote_endpoint_ = endpoint_type(); } return ec; } // Assign a native socket to a socket implementation. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { if (!do_assign(impl, protocol.type(), native_socket, ec)) { impl.protocol_ = protocol; impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); impl.remote_endpoint_ = native_socket.remote_endpoint(); } return ec; } // Get the native socket representation. native_type native(implementation_type& impl) { if (impl.have_remote_endpoint_) return native_type(impl.socket_, impl.remote_endpoint_); return native_type(impl.socket_); } // Bind the socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); return ec; } // Set a socket option. template asio::error_code set_option(implementation_type& impl, const Option& option, asio::error_code& ec) { socket_ops::setsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); return ec; } // Set a socket option. template asio::error_code get_option(const implementation_type& impl, Option& option, asio::error_code& ec) const { std::size_t size = option.size(impl.protocol_); socket_ops::getsockopt(impl.socket_, impl.state_, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); return ec; } // Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { endpoint_type endpoint; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } // Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { endpoint_type endpoint = impl.remote_endpoint_; std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, impl.have_remote_endpoint_, ec)) return endpoint_type(); endpoint.resize(addr_len); return endpoint; } // Send a datagram to the specified endpoint. Returns the number of bytes // sent. template size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_sendto(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, destination.data(), destination.size(), ec); } // Wait until data can be sent without blocking. size_t send_to(implementation_type& impl, const null_buffers&, const endpoint_type&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_send_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_send_to_op(impl, bufs.buffers(), bufs.count(), destination.data(), static_cast(destination.size()), flags, p.p); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send_to(implementation_type& impl, const null_buffers&, const endpoint_type&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); start_reactor_op(impl, reactor::write_op, p.p); p.v = p.p = 0; } // Receive a datagram with the endpoint of the sender. Returns the number of // bytes received. template size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); std::size_t addr_len = sender_endpoint.capacity(); std::size_t bytes_recvd = socket_ops::sync_recvfrom( impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, sender_endpoint.data(), &addr_len, ec); if (!ec) sender_endpoint.resize(addr_len); return bytes_recvd; } // Wait until data can be received without blocking. size_t receive_from(implementation_type& impl, const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); return 0; } // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. template void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endp, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_recvfrom_op< MutableBufferSequence, endpoint_type, Handler> op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_receive_from_op(impl, bufs.buffers(), bufs.count(), sender_endp.data(), flags, &p.p->endpoint_size(), p.p); p.v = p.p = 0; } // Wait until data can be received without blocking. template void async_receive_from(implementation_type& impl, const null_buffers&, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); // Reset endpoint since it can be given no sensible value at this time. sender_endpoint = endpoint_type(); start_null_buffers_receive_op(impl, flags, p.p); p.v = p.p = 0; } // Accept a new connection. template asio::error_code accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { // We cannot accept a socket that is already open. if (peer.is_open()) { ec = asio::error::already_open; return ec; } std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; socket_holder new_socket(socket_ops::sync_accept(impl.socket_, impl.state_, peer_endpoint ? peer_endpoint->data() : 0, peer_endpoint ? &addr_len : 0, ec)); // On success, assign new connection to peer socket object. if (new_socket.get() >= 0) { if (peer_endpoint) peer_endpoint->resize(addr_len); if (!peer.assign(impl.protocol_, new_socket.get(), ec)) new_socket.release(); } return ec; } // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template void async_accept(implementation_type& impl, Socket& peer, endpoint_type* peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_accept_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; bool enable_connection_aborted = (impl.state_ & socket_ops::enable_connection_aborted) != 0; p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, peer_endpoint, enable_connection_aborted, handler); start_accept_op(impl, peer.is_open(), p.p->new_socket(), impl.protocol_.family(), impl.protocol_.type(), impl.protocol_.protocol(), p.p->output_buffer(), p.p->address_length(), p.p); p.v = p.p = 0; } // Connect the socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { socket_ops::sync_connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); return ec; } // Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef reactive_socket_connect_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.socket_, handler); start_connect_op(impl, p.p, peer_endpoint.data(), static_cast(peer_endpoint.size())); p.v = p.p = 0; } }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_iocp_socket_service_base.hpp000066400000000000000000000340301244131713600265340ustar00rootroot00000000000000// // detail/win_iocp_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP #define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_IOCP) #include #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/detail/fenced_block.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/operation.hpp" #include "asio/detail/reactor.hpp" #include "asio/detail/reactor_op.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/win_iocp_io_service.hpp" #include "asio/detail/win_iocp_null_buffers_op.hpp" #include "asio/detail/win_iocp_socket_send_op.hpp" #include "asio/detail/win_iocp_socket_recv_op.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_iocp_socket_service_base { public: // The implementation type of the socket. struct base_implementation_type { // The native socket representation. socket_type socket_; // The current state of the socket. socket_ops::state_type state_; // We use a shared pointer as a cancellation token here to work around the // broken Windows support for cancellation. MSDN says that when you call // closesocket any outstanding WSARecv or WSASend operations will complete // with the error ERROR_OPERATION_ABORTED. In practice they complete with // ERROR_NETNAME_DELETED, which means you can't tell the difference between // a local cancellation and the socket being hard-closed by the peer. socket_ops::shared_cancel_token_type cancel_token_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; #if defined(ASIO_ENABLE_CANCELIO) // The ID of the thread from which it is safe to cancel asynchronous // operations. 0 means no asynchronous operations have been started yet. // ~0 means asynchronous operations have been started from more than one // thread, and cancellation is not supported for the socket. DWORD safe_cancellation_thread_id_; #endif // defined(ASIO_ENABLE_CANCELIO) // Pointers to adjacent socket implementations in linked list. base_implementation_type* next_; base_implementation_type* prev_; }; // Constructor. ASIO_DECL win_iocp_socket_service_base( asio::io_service& io_service); // Destroy all user-defined handler objects owned by the service. ASIO_DECL void shutdown_service(); // Construct a new socket implementation. ASIO_DECL void construct(base_implementation_type& impl); // Destroy a socket implementation. ASIO_DECL void destroy(base_implementation_type& impl); // Determine whether the socket is open. bool is_open(const base_implementation_type& impl) const { return impl.socket_ != invalid_socket; } // Destroy a socket implementation. ASIO_DECL asio::error_code close( base_implementation_type& impl, asio::error_code& ec); // Cancel all operations associated with the socket. ASIO_DECL asio::error_code cancel( base_implementation_type& impl, asio::error_code& ec); // Determine whether the socket is at the out-of-band data mark. bool at_mark(const base_implementation_type& impl, asio::error_code& ec) const { return socket_ops::sockatmark(impl.socket_, ec); } // Determine the number of bytes available for reading. std::size_t available(const base_implementation_type& impl, asio::error_code& ec) const { return socket_ops::available(impl.socket_, ec); } // Place the socket into the state where it will listen for new connections. asio::error_code listen(base_implementation_type& impl, int backlog, asio::error_code& ec) { socket_ops::listen(impl.socket_, backlog, ec); return ec; } // Perform an IO control command on the socket. template asio::error_code io_control(base_implementation_type& impl, IO_Control_Command& command, asio::error_code& ec) { socket_ops::ioctl(impl.socket_, impl.state_, command.name(), static_cast(command.data()), ec); return ec; } /// Disable sends or receives on the socket. asio::error_code shutdown(base_implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { socket_ops::shutdown(impl.socket_, what, ec); return ec; } // Send the given data to the peer. Returns the number of bytes sent. template size_t send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_send(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); } // Wait until data can be sent without blocking. size_t send(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_write(impl.socket_, ec); return 0; } // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_send_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_send_op(impl, bufs.buffers(), bufs.count(), flags, (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), p.p); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template void async_send(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); start_reactor_op(impl, reactor::write_op, p.p); p.v = p.p = 0; } // Receive some data from the peer. Returns the number of bytes received. template size_t receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { buffer_sequence_adapter bufs(buffers); return socket_ops::sync_recv(impl.socket_, impl.state_, bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); } // Wait until data can be received without blocking. size_t receive(base_implementation_type& impl, const null_buffers&, socket_base::message_flags, asio::error_code& ec) { // Wait for socket to become ready. socket_ops::poll_read(impl.socket_, ec); return 0; } // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. template void async_receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_socket_recv_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler); buffer_sequence_adapter bufs(buffers); start_receive_op(impl, bufs.buffers(), bufs.count(), flags, (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), p.p); p.v = p.p = 0; } // Wait until data can be received without blocking. template void async_receive(base_implementation_type& impl, const null_buffers&, socket_base::message_flags flags, Handler handler) { // Allocate and construct an operation to wrap the handler. typedef win_iocp_null_buffers_op op; typename op::ptr p = { boost::addressof(handler), asio_handler_alloc_helpers::allocate( sizeof(op), handler), 0 }; p.p = new (p.v) op(impl.cancel_token_, handler); start_null_buffers_receive_op(impl, flags, p.p); p.v = p.p = 0; } // Helper function to restart an asynchronous accept operation. ASIO_DECL void restart_accept_op(socket_type s, socket_holder& new_socket, int family, int type, int protocol, void* output_buffer, DWORD address_length, operation* op); protected: // Open a new socket implementation. ASIO_DECL asio::error_code do_open( base_implementation_type& impl, int family, int type, int protocol, asio::error_code& ec); // Assign a native socket to a socket implementation. ASIO_DECL asio::error_code do_assign( base_implementation_type& impl, int type, socket_type native_socket, asio::error_code& ec); // Helper function to start an asynchronous send operation. ASIO_DECL void start_send_op(base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op); // Helper function to start an asynchronous send_to operation. ASIO_DECL void start_send_to_op(base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, const socket_addr_type* addr, int addrlen, socket_base::message_flags flags, operation* op); // Helper function to start an asynchronous receive operation. ASIO_DECL void start_receive_op(base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_base::message_flags flags, bool noop, operation* op); // Helper function to start an asynchronous null_buffers receive operation. ASIO_DECL void start_null_buffers_receive_op( base_implementation_type& impl, socket_base::message_flags flags, reactor_op* op); // Helper function to start an asynchronous receive_from operation. ASIO_DECL void start_receive_from_op(base_implementation_type& impl, WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, socket_base::message_flags flags, int* addrlen, operation* op); // Helper function to start an asynchronous accept operation. ASIO_DECL void start_accept_op(base_implementation_type& impl, bool peer_is_open, socket_holder& new_socket, int family, int type, int protocol, void* output_buffer, DWORD address_length, operation* op); // Start an asynchronous read or write operation using the the reactor. ASIO_DECL void start_reactor_op(base_implementation_type& impl, int op_type, reactor_op* op); // Start the asynchronous connect operation using the reactor. ASIO_DECL void start_connect_op(base_implementation_type& impl, reactor_op* op, const socket_addr_type* addr, std::size_t addrlen); // Helper function to close a socket when the associated object is being // destroyed. ASIO_DECL void close_for_destruction(base_implementation_type& impl); // Update the ID of the thread from which cancellation is safe. ASIO_DECL void update_cancellation_thread_id( base_implementation_type& impl); // Helper function to get the reactor. If no reactor has been created yet, a // new one is obtained from the io_service and a pointer to it is cached in // this service. ASIO_DECL reactor& get_reactor(); // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. ASIO_DECL void* interlocked_compare_exchange_pointer( void** dest, void* exch, void* cmp); // Helper function to emulate InterlockedExchangePointer functionality for: // - very old Platform SDKs; and // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); // The io_service used to obtain the reactor, if required. asio::io_service& io_service_; // The IOCP service used for running asynchronous operations and dispatching // handlers. win_iocp_io_service& iocp_service_; // The reactor used for performing connect operations. This object is created // only if needed. reactor* reactor_; // Mutex to protect access to the linked list of implementations. asio::detail::mutex mutex_; // The head of a linked list of all implementations. base_implementation_type* impl_list_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_iocp_socket_service_base.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_IOCP) #endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_mutex.hpp000066400000000000000000000032341244131713600226640ustar00rootroot00000000000000// // detail/win_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_MUTEX_HPP #define ASIO_DETAIL_WIN_MUTEX_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class win_mutex : private noncopyable { public: typedef asio::detail::scoped_lock scoped_lock; // Constructor. ASIO_DECL win_mutex(); // Destructor. ~win_mutex() { ::DeleteCriticalSection(&crit_section_); } // Lock the mutex. void lock() { ::EnterCriticalSection(&crit_section_); } // Unlock the mutex. void unlock() { ::LeaveCriticalSection(&crit_section_); } private: // Initialisation must be performed in a separate function to the constructor // since the compiler does not support the use of structured exceptions and // C++ exceptions in the same function. ASIO_DECL int do_init(); ::CRITICAL_SECTION crit_section_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_mutex.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_WIN_MUTEX_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_signal_blocker.hpp000066400000000000000000000025511244131713600245010ustar00rootroot00000000000000// // win_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP #define ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/noncopyable.hpp" namespace asio { namespace detail { class win_signal_blocker : private noncopyable { public: // Constructor blocks all signals for the calling thread. win_signal_blocker() { // No-op. } // Destructor restores the previous signal mask. ~win_signal_blocker() { // No-op. } // Block all signals for the calling thread. void block() { // No-op. } // Restore the previous signal mask. void unblock() { // No-op. } }; } // namespace detail } // namespace asio #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_thread.hpp000066400000000000000000000054521244131713600227750ustar00rootroot00000000000000// // detail/win_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_THREAD_HPP #define ASIO_DETAIL_WIN_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) ASIO_DECL void __stdcall apc_function(ULONG data); #else ASIO_DECL void __stdcall apc_function(ULONG_PTR data); #endif template class win_thread_base { public: static bool terminate_threads() { return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; } static void set_terminate_threads(bool b) { ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); } private: static long terminate_threads_; }; template long win_thread_base::terminate_threads_ = 0; class win_thread : private noncopyable, public win_thread_base { public: // Constructor. template win_thread(Function f, unsigned int stack_size = 0) : thread_(0), exit_event_(0) { start_thread(new func(f), stack_size); } // Destructor. ASIO_DECL ~win_thread(); // Wait for the thread to exit. ASIO_DECL void join(); private: friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); #if defined(WINVER) && (WINVER < 0x0500) friend ASIO_DECL void __stdcall apc_function(ULONG); #else friend ASIO_DECL void __stdcall apc_function(ULONG_PTR); #endif class func_base { public: virtual ~func_base() {} virtual void run() = 0; ::HANDLE entry_event_; ::HANDLE exit_event_; }; struct auto_func_base_ptr { func_base* ptr; ~auto_func_base_ptr() { delete ptr; } }; template class func : public func_base { public: func(Function f) : f_(f) { } virtual void run() { f_(); } private: Function f_; }; ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); ::HANDLE thread_; ::HANDLE exit_event_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_thread.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #endif // ASIO_DETAIL_WIN_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/detail/win_tss_ptr.hpp000066400000000000000000000031271244131713600232210ustar00rootroot00000000000000// // detail/win_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WIN_TSS_PTR_HPP #define ASIO_DETAIL_WIN_TSS_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { // Helper function to create thread-specific storage. ASIO_DECL DWORD win_tss_ptr_create(); template class win_tss_ptr : private noncopyable { public: // Constructor. win_tss_ptr() : tss_key_(win_tss_ptr_create()) { } // Destructor. ~win_tss_ptr() { ::TlsFree(tss_key_); } // Get the value. operator T*() const { return static_cast(::TlsGetValue(tss_key_)); } // Set the value. void operator=(T* value) { ::TlsSetValue(tss_key_, value); } private: // Thread-specific storage to allow unlocked access to determine whether a // thread is a member of the pool. DWORD tss_key_; }; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/win_tss_ptr.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) #endif // ASIO_DETAIL_WIN_TSS_PTR_HPP percona-galera-3-3.8-3390/asio/asio/detail/wince_thread.hpp000066400000000000000000000044261244131713600233050ustar00rootroot00000000000000// // detail/wince_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WINCE_THREAD_HPP #define ASIO_DETAIL_WINCE_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) && defined(UNDER_CE) #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { DWORD WINAPI wince_thread_function(LPVOID arg); class wince_thread : private noncopyable { public: // Constructor. template wince_thread(Function f) { std::auto_ptr arg(new func(f)); DWORD thread_id = 0; thread_ = ::CreateThread(0, 0, wince_thread_function, arg.get(), 0, &thread_id); if (!thread_) { DWORD last_error = ::GetLastError(); asio::error_code ec(last_error, asio::error::get_system_category()); asio::detail::throw_error(ec, "thread"); } arg.release(); } // Destructor. ~wince_thread() { ::CloseHandle(thread_); } // Wait for the thread to exit. void join() { ::WaitForSingleObject(thread_, INFINITE); } private: friend DWORD WINAPI wince_thread_function(LPVOID arg); class func_base { public: virtual ~func_base() {} virtual void run() = 0; }; template class func : public func_base { public: func(Function f) : f_(f) { } virtual void run() { f_(); } private: Function f_; }; ::HANDLE thread_; }; inline DWORD WINAPI wince_thread_function(LPVOID arg) { std::auto_ptr func( static_cast(arg)); func->run(); return 0; } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) #endif // ASIO_DETAIL_WINCE_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/detail/winsock_init.hpp000066400000000000000000000040701244131713600233440ustar00rootroot00000000000000// // detail/winsock_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WINSOCK_INIT_HPP #define ASIO_DETAIL_WINSOCK_INIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/push_options.hpp" namespace asio { namespace detail { class winsock_init_base { protected: // Structure to track result of initialisation and number of uses. POD is used // to ensure that the values are zero-initialised prior to any code being run. struct data { long init_count_; long result_; }; ASIO_DECL static void startup(data& d, unsigned char major, unsigned char minor); ASIO_DECL static void cleanup(data& d); ASIO_DECL static void throw_on_error(data& d); }; template class winsock_init : private winsock_init_base { public: winsock_init(bool allow_throw = true) { startup(data_, Major, Minor); if (allow_throw) throw_on_error(data_); } winsock_init(const winsock_init&) { startup(data_, Major, Minor); throw_on_error(data_); } ~winsock_init() { cleanup(data_); } private: static data data_; }; template winsock_init_base::data winsock_init::data_; // Static variable to ensure that winsock is initialised before main, and // therefore before any other threads can get started. static const winsock_init<>& winsock_init_instance = winsock_init<>(false); } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/detail/impl/winsock_init.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // ASIO_DETAIL_WINSOCK_INIT_HPP percona-galera-3-3.8-3390/asio/asio/detail/wrapped_handler.hpp000066400000000000000000000125371244131713600240120ustar00rootroot00000000000000// // detail/wrapped_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_DETAIL_WRAPPED_HANDLER_HPP #define ASIO_DETAIL_WRAPPED_HANDLER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template class wrapped_handler { public: typedef void result_type; wrapped_handler(Dispatcher dispatcher, Handler handler) : dispatcher_(dispatcher), handler_(handler) { } void operator()() { dispatcher_.dispatch(handler_); } void operator()() const { dispatcher_.dispatch(handler_); } template void operator()(const Arg1& arg1) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); } template void operator()(const Arg1& arg1) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); } template void operator()(const Arg1& arg1, const Arg2& arg2) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); } template void operator()(const Arg1& arg1, const Arg2& arg2) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) { dispatcher_.dispatch( detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) const { dispatcher_.dispatch( detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) { dispatcher_.dispatch( detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); } template void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) const { dispatcher_.dispatch( detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); } //private: Dispatcher dispatcher_; Handler handler_; }; template class rewrapped_handler { public: explicit rewrapped_handler(const Handler& handler, const Context& context) : handler_(handler), context_(context) { } void operator()() { handler_(); } void operator()() const { handler_(); } //private: Handler handler_; Context context_; }; template inline void* asio_handler_allocate(std::size_t size, wrapped_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, wrapped_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, wrapped_handler* this_handler) { this_handler->dispatcher_.dispatch( rewrapped_handler( function, this_handler->handler_)); } template inline void* asio_handler_allocate(std::size_t size, rewrapped_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->context_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, rewrapped_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->context_); } template inline void asio_handler_invoke(const Function& function, rewrapped_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->context_); } } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP percona-galera-3-3.8-3390/asio/asio/error.hpp000066400000000000000000000155501244131713600205400ustar00rootroot00000000000000// // error.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_ERROR_HPP #define ASIO_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include #else # include # include #endif #if defined(GENERATING_DOCUMENTATION) /// INTERNAL ONLY. # define ASIO_NATIVE_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_SOCKET_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_NETDB_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_GETADDRINFO_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # define ASIO_NATIVE_ERROR(e) e # define ASIO_SOCKET_ERROR(e) WSA ## e # define ASIO_NETDB_ERROR(e) WSA ## e # define ASIO_GETADDRINFO_ERROR(e) WSA ## e # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win #else # define ASIO_NATIVE_ERROR(e) e # define ASIO_SOCKET_ERROR(e) e # define ASIO_NETDB_ERROR(e) e # define ASIO_GETADDRINFO_ERROR(e) e # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif #include "asio/detail/push_options.hpp" namespace asio { namespace error { enum basic_errors { /// Permission denied. access_denied = ASIO_SOCKET_ERROR(EACCES), /// Address family not supported by protocol. address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), /// Address already in use. address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), /// Transport endpoint is already connected. already_connected = ASIO_SOCKET_ERROR(EISCONN), /// Operation already in progress. already_started = ASIO_SOCKET_ERROR(EALREADY), /// Broken pipe. broken_pipe = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE), ASIO_NATIVE_ERROR(EPIPE)), /// A connection has been aborted. connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED), /// Connection refused. connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED), /// Connection reset by peer. connection_reset = ASIO_SOCKET_ERROR(ECONNRESET), /// Bad file descriptor. bad_descriptor = ASIO_SOCKET_ERROR(EBADF), /// Bad address. fault = ASIO_SOCKET_ERROR(EFAULT), /// No route to host. host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH), /// Operation now in progress. in_progress = ASIO_SOCKET_ERROR(EINPROGRESS), /// Interrupted system call. interrupted = ASIO_SOCKET_ERROR(EINTR), /// Invalid argument. invalid_argument = ASIO_SOCKET_ERROR(EINVAL), /// Message too long. message_size = ASIO_SOCKET_ERROR(EMSGSIZE), /// The name was too long. name_too_long = ASIO_SOCKET_ERROR(ENAMETOOLONG), /// Network is down. network_down = ASIO_SOCKET_ERROR(ENETDOWN), /// Network dropped connection on reset. network_reset = ASIO_SOCKET_ERROR(ENETRESET), /// Network is unreachable. network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH), /// Too many open files. no_descriptors = ASIO_SOCKET_ERROR(EMFILE), /// No buffer space available. no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS), /// Cannot allocate memory. no_memory = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), ASIO_NATIVE_ERROR(ENOMEM)), /// Operation not permitted. no_permission = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), ASIO_NATIVE_ERROR(EPERM)), /// Protocol not available. no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT), /// Transport endpoint is not connected. not_connected = ASIO_SOCKET_ERROR(ENOTCONN), /// Socket operation on non-socket. not_socket = ASIO_SOCKET_ERROR(ENOTSOCK), /// Operation cancelled. operation_aborted = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), ASIO_NATIVE_ERROR(ECANCELED)), /// Operation not supported. operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP), /// Cannot send after transport endpoint shutdown. shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN), /// Connection timed out. timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT), /// Resource temporarily unavailable. try_again = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(ERROR_RETRY), ASIO_NATIVE_ERROR(EAGAIN)), /// The socket is marked non-blocking and the requested operation would block. would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK) }; enum netdb_errors { /// Host not found (authoritative). host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND), /// Host not found (non-authoritative). host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN), /// The query is valid but does not have associated address data. no_data = ASIO_NETDB_ERROR(NO_DATA), /// A non-recoverable error occurred. no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY) }; enum addrinfo_errors { /// The service is not supported for the given socket type. service_not_found = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), /// The socket type is not supported. socket_type_not_supported = ASIO_WIN_OR_POSIX( ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)) }; enum misc_errors { /// Already open. already_open = 1, /// End of file or stream. eof, /// Element not found. not_found, /// The descriptor cannot fit into the select system call's fd_set. fd_set_failure }; enum ssl_errors { }; // boostify: error category definitions start here. } // namespace error } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace error { // boostify: error category definitions end here. inline asio::error_code make_error_code(basic_errors e) { return asio::error_code( static_cast(e), get_system_category()); } inline asio::error_code make_error_code(netdb_errors e) { return asio::error_code( static_cast(e), get_netdb_category()); } inline asio::error_code make_error_code(addrinfo_errors e) { return asio::error_code( static_cast(e), get_addrinfo_category()); } inline asio::error_code make_error_code(misc_errors e) { return asio::error_code( static_cast(e), get_misc_category()); } inline asio::error_code make_error_code(ssl_errors e) { return asio::error_code( static_cast(e), get_ssl_category()); } } // namespace error } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_NATIVE_ERROR #undef ASIO_SOCKET_ERROR #undef ASIO_NETDB_ERROR #undef ASIO_GETADDRINFO_ERROR #undef ASIO_WIN_OR_POSIX #if defined(ASIO_HEADER_ONLY) # include "asio/impl/error.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_ERROR_HPP percona-galera-3-3.8-3390/asio/asio/error_code.hpp000066400000000000000000000075731244131713600215400ustar00rootroot00000000000000// // error_code.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_ERROR_CODE_HPP #define ASIO_ERROR_CODE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #if defined(GENERATING_DOCUMENTATION) # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win #else # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif #include "asio/detail/push_options.hpp" namespace asio { namespace error { /// Available error code categories. enum error_category { /// System error codes. system_category = ASIO_WIN_OR_POSIX(0, 0), /// Error codes from NetDB functions. netdb_category = ASIO_WIN_OR_POSIX(system_category, 1), /// Error codes from getaddrinfo. addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2), /// Miscellaneous error codes. misc_category = ASIO_WIN_OR_POSIX(3, 3), /// SSL error codes. ssl_category = ASIO_WIN_OR_POSIX(4, 4) }; // Category getters. inline error_category get_system_category() { return system_category; } inline error_category get_netdb_category() { return netdb_category; } inline error_category get_addrinfo_category() { return addrinfo_category; } inline error_category get_misc_category() { return misc_category; } inline error_category get_ssl_category() { return ssl_category; } } // namespace error /// Bring error category type into the asio namespace. typedef asio::error::error_category error_category; /// Class to represent an error code value. class error_code { public: /// The underlying representation of an error code. typedef int value_type; /// Default constructor. error_code() : value_(0), category_(error::system_category) { } /// Construct with specific error code and category. error_code(value_type v, error_category c) : value_(v), category_(c) { } /// Construct from an error code enum. template error_code(ErrorEnum e) { *this = make_error_code(e); } /// Get the error value. value_type value() const { return value_; } /// Get the error category. error_category category() const { return category_; } /// Get the message associated with the error. ASIO_DECL std::string message() const; struct unspecified_bool_type_t { }; typedef void (*unspecified_bool_type)(unspecified_bool_type_t); static void unspecified_bool_true(unspecified_bool_type_t) {} /// Operator returns non-null if there is a non-success error code. operator unspecified_bool_type() const { if (value_ == 0) return 0; else return &error_code::unspecified_bool_true; } /// Operator to test if the error represents success. bool operator!() const { return value_ == 0; } /// Equality operator to compare two error objects. friend bool operator==(const error_code& e1, const error_code& e2) { return e1.value_ == e2.value_ && e1.category_ == e2.category_; } /// Inequality operator to compare two error objects. friend bool operator!=(const error_code& e1, const error_code& e2) { return e1.value_ != e2.value_ || e1.category_ != e2.category_; } private: // The value associated with the error code. value_type value_; // The category associated with the error code. error_category category_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_WIN_OR_POSIX #if defined(ASIO_HEADER_ONLY) # include "asio/impl/error_code.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_ERROR_CODE_HPP percona-galera-3-3.8-3390/asio/asio/handler_alloc_hook.hpp000066400000000000000000000044131244131713600232120ustar00rootroot00000000000000// // handler_alloc_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_HANDLER_ALLOC_HOOK_HPP #define ASIO_HANDLER_ALLOC_HOOK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/push_options.hpp" namespace asio { /// Default allocation function for handlers. /** * Asynchronous operations may need to allocate temporary objects. Since * asynchronous operations have a handler function object, these temporary * objects can be said to be associated with the handler. * * Implement asio_handler_allocate and asio_handler_deallocate for your own * handlers to provide custom allocation for these temporary objects. * * This default implementation is simply: * @code * return ::operator new(size); * @endcode * * @note All temporary objects associated with a handler will be deallocated * before the upcall to the handler is performed. This allows the same memory to * be reused for a subsequent asynchronous operation initiated by the handler. * * @par Example * @code * class my_handler; * * void* asio_handler_allocate(std::size_t size, my_handler* context) * { * return ::operator new(size); * } * * void asio_handler_deallocate(void* pointer, std::size_t size, * my_handler* context) * { * ::operator delete(pointer); * } * @endcode */ inline void* asio_handler_allocate(std::size_t size, ...) { return ::operator new(size); } /// Default deallocation function for handlers. /** * Implement asio_handler_allocate and asio_handler_deallocate for your own * handlers to provide custom allocation for the associated temporary objects. * * This default implementation is simply: * @code * ::operator delete(pointer); * @endcode * * @sa asio_handler_allocate. */ inline void asio_handler_deallocate(void* pointer, std::size_t size, ...) { (void)(size); ::operator delete(pointer); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_HANDLER_ALLOC_HOOK_HPP percona-galera-3-3.8-3390/asio/asio/handler_invoke_hook.hpp000066400000000000000000000041601244131713600234120ustar00rootroot00000000000000// // handler_invoke_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_HANDLER_INVOKE_HOOK_HPP #define ASIO_HANDLER_INVOKE_HOOK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Default invoke function for handlers. /** * Completion handlers for asynchronous operations are invoked by the * io_service associated with the corresponding object (e.g. a socket or * deadline_timer). Certain guarantees are made on when the handler may be * invoked, in particular that a handler can only be invoked from a thread that * is currently calling @c run() on the corresponding io_service object. * Handlers may subsequently be invoked through other objects (such as * io_service::strand objects) that provide additional guarantees. * * When asynchronous operations are composed from other asynchronous * operations, all intermediate handlers should be invoked using the same * method as the final handler. This is required to ensure that user-defined * objects are not accessed in a way that may violate the guarantees. This * hooking function ensures that the invoked method used for the final handler * is accessible at each intermediate step. * * Implement asio_handler_invoke for your own handlers to specify a custom * invocation strategy. * * This default implementation is simply: * @code * function(); * @endcode * * @par Example * @code * class my_handler; * * template * void asio_handler_invoke(Function function, my_handler* context) * { * context->strand_.dispatch(function); * } * @endcode */ template inline void asio_handler_invoke(Function function, ...) { function(); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_HANDLER_INVOKE_HOOK_HPP percona-galera-3-3.8-3390/asio/asio/impl/000077500000000000000000000000001244131713600176315ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/impl/error.ipp000066400000000000000000000013641244131713600215000ustar00rootroot00000000000000// // impl/error.ipp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_ERROR_IPP #define ASIO_IMPL_ERROR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace error { // boostify: error category function definitions go here. } // namespace error } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_ERROR_IPP percona-galera-3-3.8-3390/asio/asio/impl/error_code.ipp000066400000000000000000000070661244131713600224770ustar00rootroot00000000000000// // impl/error_code.ipp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_ERROR_CODE_IPP #define ASIO_IMPL_ERROR_CODE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/local_free_on_block_exit.hpp" #include "asio/detail/socket_types.hpp" #include "asio/error.hpp" #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { std::string error_code::message() const { if (category_ == error::get_misc_category()) { if (value_ == error::already_open) return "Already open."; if (value_ == error::not_found) return "Not found."; if (value_ == error::fd_set_failure) return "The descriptor does not fit into the select call's fd_set."; if (value_ == error::not_found) return "Element not found."; #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) if (value_ == error::eof) return "End of file."; #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) } if (category_ == error::get_ssl_category()) return "SSL error."; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_type value = value_; if (category_ == error::get_misc_category() && value_ == error::eof) value = ERROR_HANDLE_EOF; else if (category_ != error::get_system_category()) return "asio error"; char* msg = 0; DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); detail::local_free_on_block_exit local_free_obj(msg); if (length && msg[length - 1] == '\n') msg[--length] = '\0'; if (length && msg[length - 1] == '\r') msg[--length] = '\0'; if (length) return msg; else return "asio error"; #else // defined(BOOST_WINDOWS) if (category_ == error::get_netdb_category()) { if (value_ == error::host_not_found) return "Host not found (authoritative)."; if (value_ == error::host_not_found_try_again) return "Host not found (non-authoritative), try again later."; if (value_ == error::no_recovery) return "A non-recoverable error occurred during database lookup."; if (value_ == error::no_data) return "The query is valid, but it does not have associated data."; } if (category_ == error::get_addrinfo_category()) { if (value_ == error::service_not_found) return "Service not found."; if (value_ == error::socket_type_not_supported) return "Socket type not supported."; } if (category_ != error::get_system_category()) return "asio error"; #if !defined(__sun) if (value_ == error::operation_aborted) return "Operation aborted."; #endif // !defined(__sun) #if defined(__sun) || defined(__QNX__) || defined(__SYMBIAN32__) using namespace std; return strerror(value_); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ || defined(_AIX) || defined(__hpux) || defined(__osf__) char buf[256] = ""; strerror_r(value_, buf, sizeof(buf)); return buf; #else char buf[256] = ""; return strerror_r(value_, buf, sizeof(buf)); #endif #endif // defined(BOOST_WINDOWS) } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_ERROR_CODE_IPP percona-galera-3-3.8-3390/asio/asio/impl/io_service.hpp000066400000000000000000000057601244131713600225010ustar00rootroot00000000000000// // impl/io_service.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_IO_SERVICE_HPP #define ASIO_IMPL_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/service_registry.hpp" #include "asio/detail/push_options.hpp" namespace asio { template inline Service& use_service(io_service& ios) { // Check that Service meets the necessary type requirements. (void)static_cast(static_cast(0)); (void)static_cast(&Service::id); return ios.service_registry_->template use_service(); } template inline void add_service(io_service& ios, Service* svc) { // Check that Service meets the necessary type requirements. (void)static_cast(static_cast(0)); (void)static_cast(&Service::id); ios.service_registry_->template add_service(svc); } template inline bool has_service(io_service& ios) { // Check that Service meets the necessary type requirements. (void)static_cast(static_cast(0)); (void)static_cast(&Service::id); return ios.service_registry_->template has_service(); } } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_service.hpp" #else # include "asio/detail/task_io_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { template inline void io_service::dispatch(Handler handler) { impl_.dispatch(handler); } template inline void io_service::post(Handler handler) { impl_.post(handler); } template #if defined(GENERATING_DOCUMENTATION) unspecified #else inline detail::wrapped_handler #endif io_service::wrap(Handler handler) { return detail::wrapped_handler(*this, handler); } inline io_service::work::work(asio::io_service& io_service) : io_service_(io_service) { io_service_.impl_.work_started(); } inline io_service::work::work(const work& other) : io_service_(other.io_service_) { io_service_.impl_.work_started(); } inline io_service::work::~work() { io_service_.impl_.work_finished(); } inline asio::io_service& io_service::work::io_service() { return io_service_; } inline asio::io_service& io_service::work::get_io_service() { return io_service_; } inline asio::io_service& io_service::service::io_service() { return owner_; } inline asio::io_service& io_service::service::get_io_service() { return owner_; } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/impl/io_service.ipp000066400000000000000000000052531244131713600224770ustar00rootroot00000000000000// // impl/io_service.ipp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_IO_SERVICE_IPP #define ASIO_IMPL_IO_SERVICE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/io_service.hpp" #include "asio/detail/service_registry.hpp" #include "asio/detail/throw_error.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_service.hpp" #else # include "asio/detail/task_io_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { io_service::io_service() : service_registry_(new asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init((std::numeric_limits::max)()); } io_service::io_service(std::size_t concurrency_hint) : service_registry_(new asio::detail::service_registry(*this)), impl_(service_registry_->use_service()) { impl_.init(concurrency_hint); } io_service::~io_service() { delete service_registry_; } std::size_t io_service::run() { asio::error_code ec; std::size_t s = impl_.run(ec); asio::detail::throw_error(ec); return s; } std::size_t io_service::run(asio::error_code& ec) { return impl_.run(ec); } std::size_t io_service::run_one() { asio::error_code ec; std::size_t s = impl_.run_one(ec); asio::detail::throw_error(ec); return s; } std::size_t io_service::run_one(asio::error_code& ec) { return impl_.run_one(ec); } std::size_t io_service::poll() { asio::error_code ec; std::size_t s = impl_.poll(ec); asio::detail::throw_error(ec); return s; } std::size_t io_service::poll(asio::error_code& ec) { return impl_.poll(ec); } std::size_t io_service::poll_one() { asio::error_code ec; std::size_t s = impl_.poll_one(ec); asio::detail::throw_error(ec); return s; } std::size_t io_service::poll_one(asio::error_code& ec) { return impl_.poll_one(ec); } void io_service::stop() { impl_.stop(); } void io_service::reset() { impl_.reset(); } io_service::service::service(asio::io_service& owner) : owner_(owner), next_(0) { } io_service::service::~service() { } service_already_exists::service_already_exists() : std::logic_error("Service already exists.") { } invalid_service_owner::invalid_service_owner() : std::logic_error("Invalid service owner.") { } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_IO_SERVICE_IPP percona-galera-3-3.8-3390/asio/asio/impl/read.hpp000066400000000000000000000310431244131713600212560ustar00rootroot00000000000000// // impl/read.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_READ_HPP #define ASIO_IMPL_READ_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { template std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); std::size_t bytes_available = read_size_helper(b, max_size); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); bytes_available = read_size_helper(b, max_size); } return total_transferred; } template inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = read(s, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read(s, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_op : detail::base_from_completion_cond { public: read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { switch (start) { case 1: buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_read_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncReadStream& stream_; asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; ReadHandler handler_; }; template class read_op : detail::base_from_completion_cond { public: read_op(AsyncReadStream& stream, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_read_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncReadStream& stream_; asio::mutable_buffer buffer_; std::size_t total_transferred_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { detail::read_op( s, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, ReadHandler handler) { async_read(s, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_streambuf_op : detail::base_from_completion_cond { public: read_streambuf_op(AsyncReadStream& stream, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), streambuf_(streambuf), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size, bytes_available; switch (start) { case 1: max_size = this->check_for_completion(ec, total_transferred_); bytes_available = read_size_helper(streambuf_, max_size); for (;;) { stream_.async_read_some(streambuf_.prepare(bytes_available), *this); return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); max_size = this->check_for_completion(ec, total_transferred_); bytes_available = read_size_helper(streambuf_, max_size); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_streambuf_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_streambuf_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_streambuf_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { detail::read_streambuf_op( s, b, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, ReadHandler handler) { async_read(s, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_READ_HPP percona-galera-3-3.8-3390/asio/asio/impl/read.ipp000066400000000000000000000315171244131713600212650ustar00rootroot00000000000000// // read.ipp // ~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_IPP #define ASIO_READ_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/error.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" namespace asio { template std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); std::size_t bytes_available = std::min(512, std::min(max_size, b.max_size() - b.size())); while (bytes_available > 0) { std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); bytes_available = std::min(512, std::min(max_size, b.max_size() - b.size())); } return total_transferred; } template inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = read(s, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read(s, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_op : detail::base_from_completion_cond { public: read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { switch (start_) { case true: start_ = false; buffers_.prepare(this->check(ec, total_transferred_)); for (;;) { stream_.async_read_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, total_transferred_); } } //private: AsyncReadStream& stream_; asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; ReadHandler handler_; bool start_; }; template class read_op : detail::base_from_completion_cond { public: read_op(AsyncReadStream& stream, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { std::size_t n = 0; switch (start_) { case true: start_ = false; n = this->check(ec, total_transferred_); for (;;) { stream_.async_read_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, total_transferred_); } } //private: AsyncReadStream& stream_; asio::mutable_buffer buffer_; std::size_t total_transferred_; ReadHandler handler_; bool start_; }; template inline void* asio_handler_allocate(std::size_t size, read_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { detail::read_op( s, buffers, completion_condition, handler)( asio::error_code(), 0); } template inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, ReadHandler handler) { async_read(s, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_streambuf_op : detail::base_from_completion_cond { public: read_streambuf_op(AsyncReadStream& stream, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), streambuf_(streambuf), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { std::size_t max_size, bytes_available; switch (start_) { case true: start_ = false; max_size = this->check(ec, total_transferred_); bytes_available = std::min(512, std::min(max_size, streambuf_.max_size() - streambuf_.size())); for (;;) { stream_.async_read_some(streambuf_.prepare(bytes_available), *this); return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); max_size = this->check(ec, total_transferred_); bytes_available = std::min(512, std::min(max_size, streambuf_.max_size() - streambuf_.size())); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } handler_(ec, total_transferred_); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; ReadHandler handler_; bool start_; }; template inline void* asio_handler_allocate(std::size_t size, read_streambuf_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_streambuf_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_streambuf_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { detail::read_streambuf_op( s, b, completion_condition, handler)( asio::error_code(), 0); } template inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, ReadHandler handler) { async_read(s, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_READ_IPP percona-galera-3-3.8-3390/asio/asio/impl/read_at.hpp000066400000000000000000000337151244131713600217520ustar00rootroot00000000000000// // impl/read_at.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_READ_AT_HPP #define ASIO_IMPL_READ_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); std::size_t bytes_available = read_size_helper(b, max_size); while (bytes_available > 0) { std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); bytes_available = read_size_helper(b, max_size); } return total_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_at_op : detail::base_from_completion_cond { public: read_at_op(AsyncRandomAccessReadDevice& device, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), buffers_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { switch (start) { case 1: buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { device_.async_read_some_at( offset_ + total_transferred_, buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> buffers_; std::size_t total_transferred_; ReadHandler handler_; }; template class read_at_op : detail::base_from_completion_cond { public: read_at_op(AsyncRandomAccessReadDevice& device, boost::uint64_t offset, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { device_.async_read_some_at(offset_ + total_transferred_, asio::buffer(buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; asio::mutable_buffer buffer_; std::size_t total_transferred_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_at_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_at_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_at_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { detail::read_at_op( d, offset, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, ReadHandler handler) { async_read_at(d, offset, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_at_streambuf_op : detail::base_from_completion_cond { public: read_at_streambuf_op(AsyncRandomAccessReadDevice& device, boost::uint64_t offset, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), streambuf_(streambuf), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t max_size, bytes_available; switch (start) { case 1: max_size = this->check_for_completion(ec, total_transferred_); bytes_available = read_size_helper(streambuf_, max_size); for (;;) { device_.async_read_some_at(offset_ + total_transferred_, streambuf_.prepare(bytes_available), *this); return; default: total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); max_size = this->check_for_completion(ec, total_transferred_); bytes_available = read_size_helper(streambuf_, max_size); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessReadDevice& device_; boost::uint64_t offset_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_at_streambuf_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_at_streambuf_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_at_streambuf_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { detail::read_at_streambuf_op( d, offset, b, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, ReadHandler handler) { async_read_at(d, offset, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_READ_AT_HPP percona-galera-3-3.8-3390/asio/asio/impl/read_at.ipp000066400000000000000000000307571244131713600217560ustar00rootroot00000000000000// // read_at.ipp // ~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_AT_IPP #define ASIO_READ_AT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" namespace asio { template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { std::size_t total_transferred = 0; for (;;) { std::size_t bytes_available = std::min(512, b.max_size() - b.size()); std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; if (b.size() == b.max_size() || completion_condition(ec, total_transferred)) return total_transferred; } } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = read_at( d, offset, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_at_handler { public: typedef asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> buffers_type; read_at_handler(AsyncRandomAccessReadDevice& stream, boost::uint64_t offset, const buffers_type& buffers, CompletionCondition completion_condition, ReadHandler handler) : stream_(stream), offset_(offset), buffers_(buffers), total_transferred_(0), completion_condition_(completion_condition), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } else { stream_.async_read_some_at( offset_ + total_transferred_, buffers_, *this); } } //private: AsyncRandomAccessReadDevice& stream_; boost::uint64_t offset_; buffers_type buffers_; std::size_t total_transferred_; CompletionCondition completion_condition_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_at_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_at_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_at_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler) { asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); asio::error_code ec; std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { d.get_io_service().post(detail::bind_handler( handler, ec, total_transferred)); return; } d.async_read_some_at(offset, tmp, detail::read_at_handler( d, offset, tmp, completion_condition, handler)); } template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, ReadHandler handler) { async_read_at(d, offset, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class read_at_streambuf_handler { public: read_at_streambuf_handler(AsyncRandomAccessReadDevice& stream, boost::uint64_t offset, basic_streambuf& streambuf, CompletionCondition completion_condition, ReadHandler handler) : stream_(stream), offset_(offset), streambuf_(streambuf), total_transferred_(0), completion_condition_(completion_condition), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); std::size_t max_size = detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_)); std::size_t bytes_available = std::min(512, std::min(max_size, streambuf_.max_size() - streambuf_.size())); if (bytes_available == 0) { handler_(ec, total_transferred_); } else { stream_.async_read_some_at(offset_ + total_transferred_, streambuf_.prepare(bytes_available), *this); } } //private: AsyncRandomAccessReadDevice& stream_; boost::uint64_t offset_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; CompletionCondition completion_condition_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_at_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_at_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_at_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { asio::error_code ec; std::size_t total_transferred = 0; std::size_t max_size = detail::adapt_completion_condition_result( completion_condition(ec, total_transferred)); std::size_t bytes_available = std::min(512, std::min(max_size, b.max_size() - b.size())); if (bytes_available == 0) { d.get_io_service().post(detail::bind_handler( handler, ec, total_transferred)); return; } d.async_read_some_at(offset, b.prepare(bytes_available), detail::read_at_streambuf_handler( d, offset, b, completion_condition, handler)); } template inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, ReadHandler handler) { async_read_at(d, offset, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_READ_AT_IPP percona-galera-3-3.8-3390/asio/asio/impl/read_until.hpp000066400000000000000000000673361244131713600225070ustar00rootroot00000000000000// // impl/read_until.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_READ_UNTIL_HPP #define ASIO_IMPL_READ_UNTIL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #include #include #include #include #include "asio/buffer.hpp" #include "asio/buffers_iterator.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, delim, ec); asio::detail::throw_error(ec); return bytes_transferred; } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim, asio::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(start, end, delim); if (iter != end) { // Found a match. We're done. ec = asio::error_code(); return iter - begin + 1; } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, delim, ec); asio::detail::throw_error(ec); return bytes_transferred; } namespace detail { // Algorithm that finds a subsequence of equal values in a sequence. Returns // (iterator,true) if a full match was found, in which case the iterator // points to the beginning of the match. Returns (iterator,false) if a // partial match was found at the end of the first sequence, in which case // the iterator points to the beginning of the partial match. Returns // (last1,false) if no full or partial match was found. template std::pair partial_search( Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) { for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) { Iterator1 test_iter1 = iter1; Iterator2 test_iter2 = first2; for (;; ++test_iter1, ++test_iter2) { if (test_iter2 == last2) return std::make_pair(iter1, true); if (test_iter1 == last1) { if (test_iter2 != first2) return std::make_pair(iter1, false); else break; } if (*test_iter1 != *test_iter2) break; } } return std::make_pair(last1, false); } } // namespace detail template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, asio::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. std::pair result = detail::partial_search( start, end, delim.begin(), delim.end()); if (result.first != end) { if (result.second) { // Full match. We're done. ec = asio::error_code(); return result.first - begin + delim.length(); } else { // Partial match. Next search needs to start from beginning of match. search_position = result.first - begin; } } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, expr, ec); asio::detail::throw_error(ec); return bytes_transferred; } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, asio::error_code& ec) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. boost::match_results >::allocator_type> match_results; if (regex_search(start, end, match_results, expr, boost::match_default | boost::match_partial)) { if (match_results[0].matched) { // Full match. We're done. ec = asio::error_code(); return match_results[0].second - begin; } else { // Partial match. Next search needs to start from beginning of match. search_position = match_results[0].first - begin; } } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, asio::error_code& ec, typename boost::enable_if >::type*) { std::size_t search_position = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position; iterator end = iterator::end(buffers); // Look for a match. std::pair result = match_condition(start, end); if (result.second) { // Full match. We're done. ec = asio::error_code(); return result.first - begin; } else if (result.first != end) { // Partial match. Next search needs to start from beginning of match. search_position = result.first - begin; } else { // No match. Next search can start with the new data. search_position = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_to_read = read_size_helper(b, 65536); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, typename boost::enable_if >::type*) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, match_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } namespace detail { template class read_until_delim_op { public: read_until_delim_op(AsyncReadStream& stream, asio::basic_streambuf& streambuf, char delim, ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), search_position_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits::max)(); std::size_t bytes_to_read; switch (start) { case 1: for (;;) { { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position_; iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(start, end, delim_); if (iter != end) { // Found a match. We're done. search_position_ = iter - begin + 1; bytes_to_read = 0; } // No match yet. Check if buffer is full. else if (streambuf_.size() == streambuf_.max_size()) { search_position_ = not_found; bytes_to_read = 0; } // Need to read some more data. else { // Next search can start with the new data. search_position_ = end - begin; bytes_to_read = read_size_helper(streambuf_, 65536); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); return; default: streambuf_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } const asio::error_code result_ec = (search_position_ == not_found) ? error::not_found : ec; const std::size_t result_n = (ec || search_position_ == not_found) ? 0 : search_position_; handler_(result_ec, result_n); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; char delim_; std::size_t search_position_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_delim_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_delim_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, char delim, ReadHandler handler) { detail::read_until_delim_op< AsyncReadStream, Allocator, ReadHandler>( s, b, delim, handler)( asio::error_code(), 0, 1); } namespace detail { template class read_until_delim_string_op { public: read_until_delim_string_op(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const std::string& delim, ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), search_position_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits::max)(); std::size_t bytes_to_read; switch (start) { case 1: for (;;) { { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position_; iterator end = iterator::end(buffers); // Look for a match. std::pair result = detail::partial_search( start, end, delim_.begin(), delim_.end()); if (result.first != end && result.second) { // Full match. We're done. search_position_ = result.first - begin + delim_.length(); bytes_to_read = 0; } // No match yet. Check if buffer is full. else if (streambuf_.size() == streambuf_.max_size()) { search_position_ = not_found; bytes_to_read = 0; } // Need to read some more data. else { if (result.first != end) { // Partial match. Next search needs to start from beginning of // match. search_position_ = result.first - begin; } else { // Next search can start with the new data. search_position_ = end - begin; } bytes_to_read = read_size_helper(streambuf_, 65536); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); return; default: streambuf_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } const asio::error_code result_ec = (search_position_ == not_found) ? error::not_found : ec; const std::size_t result_n = (ec || search_position_ == not_found) ? 0 : search_position_; handler_(result_ec, result_n); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::string delim_; std::size_t search_position_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_delim_string_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_delim_string_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, ReadHandler handler) { detail::read_until_delim_string_op< AsyncReadStream, Allocator, ReadHandler>( s, b, delim, handler)( asio::error_code(), 0, 1); } namespace detail { template class read_until_expr_op { public: read_until_expr_op(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const boost::regex& expr, ReadHandler handler) : stream_(stream), streambuf_(streambuf), expr_(expr), search_position_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits::max)(); std::size_t bytes_to_read; switch (start) { case 1: for (;;) { { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position_; iterator end = iterator::end(buffers); // Look for a match. boost::match_results >::allocator_type> match_results; bool match = regex_search(start, end, match_results, expr_, boost::match_default | boost::match_partial); if (match && match_results[0].matched) { // Full match. We're done. search_position_ = match_results[0].second - begin; bytes_to_read = 0; } // No match yet. Check if buffer is full. else if (streambuf_.size() == streambuf_.max_size()) { search_position_ = not_found; bytes_to_read = 0; } // Need to read some more data. else { if (match) { // Partial match. Next search needs to start from beginning of // match. search_position_ = match_results[0].first - begin; } else { // Next search can start with the new data. search_position_ = end - begin; } bytes_to_read = read_size_helper(streambuf_, 65536); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); return; default: streambuf_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } const asio::error_code result_ec = (search_position_ == not_found) ? error::not_found : ec; const std::size_t result_n = (ec || search_position_ == not_found) ? 0 : search_position_; handler_(result_ec, result_n); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; RegEx expr_; std::size_t search_position_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_expr_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_expr_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, ReadHandler handler) { detail::read_until_expr_op( s, b, expr, handler)( asio::error_code(), 0, 1); } namespace detail { template class read_until_match_op { public: read_until_match_op(AsyncReadStream& stream, asio::basic_streambuf& streambuf, MatchCondition match_condition, ReadHandler handler) : stream_(stream), streambuf_(streambuf), match_condition_(match_condition), search_position_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { const std::size_t not_found = (std::numeric_limits::max)(); std::size_t bytes_to_read; switch (start) { case 1: for (;;) { { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + search_position_; iterator end = iterator::end(buffers); // Look for a match. std::pair result = match_condition_(start, end); if (result.second) { // Full match. We're done. search_position_ = result.first - begin; bytes_to_read = 0; } // No match yet. Check if buffer is full. else if (streambuf_.size() == streambuf_.max_size()) { search_position_ = not_found; bytes_to_read = 0; } // Need to read some more data. else { if (result.first != end) { // Partial match. Next search needs to start from beginning of // match. search_position_ = result.first - begin; } else { // Next search can start with the new data. search_position_ = end - begin; } bytes_to_read = read_size_helper(streambuf_, 65536); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. stream_.async_read_some(streambuf_.prepare(bytes_to_read), *this); return; default: streambuf_.commit(bytes_transferred); if (ec || bytes_transferred == 0) break; } const asio::error_code result_ec = (search_position_ == not_found) ? error::not_found : ec; const std::size_t result_n = (ec || search_position_ == not_found) ? 0 : search_position_; handler_(result_ec, result_n); } } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; MatchCondition match_condition_; std::size_t search_position_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_match_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_match_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, ReadHandler handler, typename boost::enable_if >::type*) { detail::read_until_match_op< AsyncReadStream, Allocator, MatchCondition, ReadHandler>( s, b, match_condition, handler)( asio::error_code(), 0, 1); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_READ_UNTIL_HPP percona-galera-3-3.8-3390/asio/asio/impl/read_until.ipp000066400000000000000000000746451244131713600225110ustar00rootroot00000000000000// // read_until.ipp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_UNTIL_IPP #define ASIO_READ_UNTIL_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" #include #include #include #include #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" #include "asio/buffers_iterator.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" namespace asio { template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, delim, ec); asio::detail::throw_error(ec); return bytes_transferred; } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim, asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start; iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(start, end, delim); if (iter != end) { // Found a match. We're done. ec = asio::error_code(); return iter - begin + 1; } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); b.commit(s.read_some(b.prepare(bytes_available), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, delim, ec); asio::detail::throw_error(ec); return bytes_transferred; } namespace detail { // Algorithm that finds a subsequence of equal values in a sequence. Returns // (iterator,true) if a full match was found, in which case the iterator // points to the beginning of the match. Returns (iterator,false) if a // partial match was found at the end of the first sequence, in which case // the iterator points to the beginning of the partial match. Returns // (last1,false) if no full or partial match was found. template std::pair partial_search( Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) { for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) { Iterator1 test_iter1 = iter1; Iterator2 test_iter2 = first2; for (;; ++test_iter1, ++test_iter2) { if (test_iter2 == last2) return std::make_pair(iter1, true); if (test_iter1 == last1) { if (test_iter2 != first2) return std::make_pair(iter1, false); else break; } if (*test_iter1 != *test_iter2) break; } } return std::make_pair(last1, false); } } // namespace detail template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start; iterator end = iterator::end(buffers); // Look for a match. std::pair result = asio::detail::partial_search( start, end, delim.begin(), delim.end()); if (result.first != end) { if (result.second) { // Full match. We're done. ec = asio::error_code(); return result.first - begin + delim.length(); } else { // Partial match. Next search needs to start from beginning of match. next_search_start = result.first - begin; } } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); b.commit(s.read_some(b.prepare(bytes_available), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, expr, ec); asio::detail::throw_error(ec); return bytes_transferred; } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start; iterator end = iterator::end(buffers); // Look for a match. boost::match_results match_results; if (boost::regex_search(start, end, match_results, expr, boost::match_default | boost::match_partial)) { if (match_results[0].matched) { // Full match. We're done. ec = asio::error_code(); return match_results[0].second - begin; } else { // Partial match. Next search needs to start from beginning of match. next_search_start = match_results[0].first - begin; } } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); b.commit(s.read_some(b.prepare(bytes_available), ec)); if (ec) return 0; } } template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, asio::error_code& ec, typename boost::enable_if >::type*) { std::size_t next_search_start = 0; for (;;) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start; iterator end = iterator::end(buffers); // Look for a match. std::pair result = match_condition(start, end); if (result.second) { // Full match. We're done. ec = asio::error_code(); return result.first - begin; } else if (result.first != end) { // Partial match. Next search needs to start from beginning of match. next_search_start = result.first - begin; } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { ec = error::not_found; return 0; } // Need more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); b.commit(s.read_some(b.prepare(bytes_available), ec)); if (ec) return 0; } } template inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, typename boost::enable_if >::type*) { asio::error_code ec; std::size_t bytes_transferred = read_until(s, b, match_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } namespace detail { template class read_until_delim_handler { public: read_until_delim_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, char delim, std::size_t next_search_start, ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), next_search_start_(next_search_start), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. if (ec) { std::size_t bytes = 0; handler_(ec, bytes); return; } // Commit received data to streambuf's get area. streambuf_.commit(bytes_transferred); // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start_; iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(start, end, delim_); if (iter != end) { // Found a match. We're done. std::size_t bytes = iter - begin + 1; handler_(ec, bytes); return; } // No match. Check if buffer is full. if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; asio::error_code ec(error::not_found); handler_(ec, bytes); return; } // Next search can start with the new data. next_search_start_ = end - begin; // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; char delim_; std::size_t next_search_start_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_delim_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_delim_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, char delim, ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator end = iterator::end(buffers); // Look for a match. iterator iter = std::find(begin, end, delim); if (iter != end) { // Found a match. We're done. asio::error_code ec; std::size_t bytes = iter - begin + 1; s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } // No match. Check if buffer is full. if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); s.async_read_some(b.prepare(bytes_available), detail::read_until_delim_handler( s, b, delim, end - begin, handler)); } namespace detail { template class read_until_delim_string_handler { public: read_until_delim_string_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const std::string& delim, std::size_t next_search_start, ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), next_search_start_(next_search_start), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. if (ec) { std::size_t bytes = 0; handler_(ec, bytes); return; } // Commit received data to streambuf's get area. streambuf_.commit(bytes_transferred); // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start_; iterator end = iterator::end(buffers); // Look for a match. std::pair result = asio::detail::partial_search( start, end, delim_.begin(), delim_.end()); if (result.first != end) { if (result.second) { // Full match. We're done. std::size_t bytes = result.first - begin + delim_.length(); handler_(ec, bytes); return; } else { // Partial match. Next search needs to start from beginning of match. next_search_start_ = result.first - begin; } } else { // No match. Next search can start with the new data. next_search_start_ = end - begin; } // Check if buffer is full. if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; asio::error_code ec2(error::not_found); handler_(ec2, bytes); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::string delim_; std::size_t next_search_start_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_delim_string_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_delim_string_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator end = iterator::end(buffers); // Look for a match. std::size_t next_search_start; std::pair result = asio::detail::partial_search( begin, end, delim.begin(), delim.end()); if (result.first != end) { if (result.second) { // Full match. We're done. asio::error_code ec; std::size_t bytes = result.first - begin + delim.length(); s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else { // Partial match. Next search needs to start from beginning of match. next_search_start = result.first - begin; } } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); s.async_read_some(b.prepare(bytes_available), detail::read_until_delim_string_handler< AsyncReadStream, Allocator, ReadHandler>( s, b, delim, next_search_start, handler)); } namespace detail { template class read_until_expr_handler { public: read_until_expr_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const boost::regex& expr, std::size_t next_search_start, ReadHandler handler) : stream_(stream), streambuf_(streambuf), expr_(expr), next_search_start_(next_search_start), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. if (ec) { std::size_t bytes = 0; handler_(ec, bytes); return; } // Commit received data to streambuf's get area. streambuf_.commit(bytes_transferred); // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start_; iterator end = iterator::end(buffers); // Look for a match. boost::match_results match_results; if (boost::regex_search(start, end, match_results, expr_, boost::match_default | boost::match_partial)) { if (match_results[0].matched) { // Full match. We're done. std::size_t bytes = match_results[0].second - begin; handler_(ec, bytes); return; } else { // Partial match. Next search needs to start from beginning of match. next_search_start_ = match_results[0].first - begin; } } else { // No match. Next search can start with the new data. next_search_start_ = end - begin; } // Check if buffer is full. if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; asio::error_code ec(error::not_found); handler_(ec, bytes); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; boost::regex expr_; std::size_t next_search_start_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_expr_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_expr_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator end = iterator::end(buffers); // Look for a match. std::size_t next_search_start; boost::match_results match_results; if (boost::regex_search(begin, end, match_results, expr, boost::match_default | boost::match_partial)) { if (match_results[0].matched) { // Full match. We're done. asio::error_code ec; std::size_t bytes = match_results[0].second - begin; s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else { // Partial match. Next search needs to start from beginning of match. next_search_start = match_results[0].first - begin; } } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); s.async_read_some(b.prepare(bytes_available), detail::read_until_expr_handler( s, b, expr, next_search_start, handler)); } namespace detail { template class read_until_match_handler { public: read_until_match_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, MatchCondition match_condition, std::size_t next_search_start, ReadHandler handler) : stream_(stream), streambuf_(streambuf), match_condition_(match_condition), next_search_start_(next_search_start), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. if (ec) { std::size_t bytes = 0; handler_(ec, bytes); return; } // Commit received data to streambuf's get area. streambuf_.commit(bytes_transferred); // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = streambuf_.data(); iterator begin = iterator::begin(buffers); iterator start = begin + next_search_start_; iterator end = iterator::end(buffers); // Look for a match. std::pair result = match_condition_(start, end); if (result.second) { // Full match. We're done. std::size_t bytes = result.first - begin; handler_(ec, bytes); return; } else if (result.first != end) { // Partial match. Next search needs to start from beginning of match. next_search_start_ = result.first - begin; } else { // No match. Next search can start with the new data. next_search_start_ = end - begin; } // Check if buffer is full. if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; asio::error_code ec(error::not_found); handler_(ec, bytes); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; MatchCondition match_condition_; std::size_t next_search_start_; ReadHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, read_until_match_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, read_until_match_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, ReadHandler handler, typename boost::enable_if >::type*) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< Allocator>::const_buffers_type const_buffers_type; typedef asio::buffers_iterator iterator; const_buffers_type buffers = b.data(); iterator begin = iterator::begin(buffers); iterator end = iterator::end(buffers); // Look for a match. std::size_t next_search_start; std::pair result = match_condition(begin, end); if (result.second) { // Full match. We're done. asio::error_code ec; std::size_t bytes = result.first - begin; s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else if (result.first != end) { // Partial match. Next search needs to start from beginning of match. next_search_start = result.first - begin; } else { // No match. Next search can start with the new data. next_search_start = end - begin; } // Check if buffer is full. if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } // Start a new asynchronous read operation to obtain more data. std::size_t bytes_available = std::min(512, b.max_size() - b.size()); s.async_read_some(b.prepare(bytes_available), detail::read_until_match_handler< AsyncReadStream, Allocator, MatchCondition, ReadHandler>( s, b, match_condition, next_search_start, handler)); } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_READ_UNTIL_IPP percona-galera-3-3.8-3390/asio/asio/impl/serial_port_base.hpp000066400000000000000000000024321244131713600236600ustar00rootroot00000000000000// // impl/serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_IMPL_SERIAL_PORT_BASE_HPP #define ASIO_IMPL_SERIAL_PORT_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" namespace asio { inline serial_port_base::baud_rate::baud_rate(unsigned int rate) : value_(rate) { } inline unsigned int serial_port_base::baud_rate::value() const { return value_; } inline serial_port_base::flow_control::type serial_port_base::flow_control::value() const { return value_; } inline serial_port_base::parity::type serial_port_base::parity::value() const { return value_; } inline serial_port_base::stop_bits::type serial_port_base::stop_bits::value() const { return value_; } inline unsigned int serial_port_base::character_size::value() const { return value_; } } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_SERIAL_PORT_BASE_HPP percona-galera-3-3.8-3390/asio/asio/impl/serial_port_base.ipp000066400000000000000000000277541244131713600236770ustar00rootroot00000000000000// // impl/serial_port_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_IMPL_SERIAL_PORT_BASE_IPP #define ASIO_IMPL_SERIAL_PORT_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) #include #include #include "asio/error.hpp" #include "asio/serial_port_base.hpp" #if defined(GENERATING_DOCUMENTATION) # define ASIO_OPTION_STORAGE implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # define ASIO_OPTION_STORAGE DCB #else # define ASIO_OPTION_STORAGE termios #endif #include "asio/detail/push_options.hpp" namespace asio { asio::error_code serial_port_base::baud_rate::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) storage.BaudRate = value_; #else speed_t baud; switch (value_) { // Do POSIX-specified rates first. case 0: baud = B0; break; case 50: baud = B50; break; case 75: baud = B75; break; case 110: baud = B110; break; case 134: baud = B134; break; case 150: baud = B150; break; case 200: baud = B200; break; case 300: baud = B300; break; case 600: baud = B600; break; case 1200: baud = B1200; break; case 1800: baud = B1800; break; case 2400: baud = B2400; break; case 4800: baud = B4800; break; case 9600: baud = B9600; break; case 19200: baud = B19200; break; case 38400: baud = B38400; break; // And now the extended ones conditionally. # ifdef B7200 case 7200: baud = B7200; break; # endif # ifdef B14400 case 14400: baud = B14400; break; # endif # ifdef B57600 case 57600: baud = B57600; break; # endif # ifdef B115200 case 115200: baud = B115200; break; # endif # ifdef B230400 case 230400: baud = B230400; break; # endif # ifdef B460800 case 460800: baud = B460800; break; # endif # ifdef B500000 case 500000: baud = B500000; break; # endif # ifdef B576000 case 576000: baud = B576000; break; # endif # ifdef B921600 case 921600: baud = B921600; break; # endif # ifdef B1000000 case 1000000: baud = B1000000; break; # endif # ifdef B1152000 case 1152000: baud = B1152000; break; # endif # ifdef B2000000 case 2000000: baud = B2000000; break; # endif # ifdef B3000000 case 3000000: baud = B3000000; break; # endif # ifdef B3500000 case 3500000: baud = B3500000; break; # endif # ifdef B4000000 case 4000000: baud = B4000000; break; # endif default: baud = B0; ec = asio::error::invalid_argument; return ec; } # if defined(_BSD_SOURCE) ::cfsetspeed(&storage, baud); # else ::cfsetispeed(&storage, baud); ::cfsetospeed(&storage, baud); # endif #endif ec = asio::error_code(); return ec; } asio::error_code serial_port_base::baud_rate::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_ = storage.BaudRate; #else speed_t baud = ::cfgetospeed(&storage); switch (baud) { // First do those specified by POSIX. case B0: value_ = 0; break; case B50: value_ = 50; break; case B75: value_ = 75; break; case B110: value_ = 110; break; case B134: value_ = 134; break; case B150: value_ = 150; break; case B200: value_ = 200; break; case B300: value_ = 300; break; case B600: value_ = 600; break; case B1200: value_ = 1200; break; case B1800: value_ = 1800; break; case B2400: value_ = 2400; break; case B4800: value_ = 4800; break; case B9600: value_ = 9600; break; case B19200: value_ = 19200; break; case B38400: value_ = 38400; break; // Now conditionally handle a bunch of extended rates. # ifdef B7200 case B7200: value_ = 7200; break; # endif # ifdef B14400 case B14400: value_ = 14400; break; # endif # ifdef B57600 case B57600: value_ = 57600; break; # endif # ifdef B115200 case B115200: value_ = 115200; break; # endif # ifdef B230400 case B230400: value_ = 230400; break; # endif # ifdef B460800 case B460800: value_ = 460800; break; # endif # ifdef B500000 case B500000: value_ = 500000; break; # endif # ifdef B576000 case B576000: value_ = 576000; break; # endif # ifdef B921600 case B921600: value_ = 921600; break; # endif # ifdef B1000000 case B1000000: value_ = 1000000; break; # endif # ifdef B1152000 case B1152000: value_ = 1152000; break; # endif # ifdef B2000000 case B2000000: value_ = 2000000; break; # endif # ifdef B3000000 case B3000000: value_ = 3000000; break; # endif # ifdef B3500000 case B3500000: value_ = 3500000; break; # endif # ifdef B4000000 case B4000000: value_ = 4000000; break; # endif default: value_ = 0; ec = asio::error::invalid_argument; return ec; } #endif ec = asio::error_code(); return ec; } serial_port_base::flow_control::flow_control( serial_port_base::flow_control::type t) : value_(t) { if (t != none && t != software && t != hardware) { std::out_of_range ex("invalid flow_control value"); boost::throw_exception(ex); } } asio::error_code serial_port_base::flow_control::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) storage.fOutxCtsFlow = FALSE; storage.fOutxDsrFlow = FALSE; storage.fTXContinueOnXoff = TRUE; storage.fDtrControl = DTR_CONTROL_ENABLE; storage.fDsrSensitivity = FALSE; storage.fOutX = FALSE; storage.fInX = FALSE; storage.fRtsControl = RTS_CONTROL_ENABLE; switch (value_) { case none: break; case software: storage.fOutX = TRUE; storage.fInX = TRUE; break; case hardware: storage.fOutxCtsFlow = TRUE; storage.fRtsControl = RTS_CONTROL_HANDSHAKE; break; default: break; } #else switch (value_) { case none: storage.c_iflag &= ~(IXOFF | IXON); # if defined(_BSD_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case software: storage.c_iflag |= IXOFF | IXON; # if defined(_BSD_SOURCE) storage.c_cflag &= ~CRTSCTS; # elif defined(__QNXNTO__) storage.c_cflag &= ~(IHFLOW | OHFLOW); # endif break; case hardware: # if defined(_BSD_SOURCE) storage.c_iflag &= ~(IXOFF | IXON); storage.c_cflag |= CRTSCTS; break; # elif defined(__QNXNTO__) storage.c_iflag &= ~(IXOFF | IXON); storage.c_cflag |= (IHFLOW | OHFLOW); break; # else ec = asio::error::operation_not_supported; return ec; # endif default: break; } #endif ec = asio::error_code(); return ec; } asio::error_code serial_port_base::flow_control::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (storage.fOutX && storage.fInX) { value_ = software; } else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE) { value_ = hardware; } else { value_ = none; } #else if (storage.c_iflag & (IXOFF | IXON)) { value_ = software; } # if defined(_BSD_SOURCE) else if (storage.c_cflag & CRTSCTS) { value_ = hardware; } # elif defined(__QNXNTO__) else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW) { value_ = hardware; } # endif else { value_ = none; } #endif ec = asio::error_code(); return ec; } serial_port_base::parity::parity(serial_port_base::parity::type t) : value_(t) { if (t != none && t != odd && t != even) { std::out_of_range ex("invalid parity value"); boost::throw_exception(ex); } } asio::error_code serial_port_base::parity::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) switch (value_) { case none: storage.fParity = FALSE; storage.Parity = NOPARITY; break; case odd: storage.fParity = TRUE; storage.Parity = ODDPARITY; break; case even: storage.fParity = TRUE; storage.Parity = EVENPARITY; break; default: break; } #else switch (value_) { case none: storage.c_iflag |= IGNPAR; storage.c_cflag &= ~(PARENB | PARODD); break; case even: storage.c_iflag &= ~(IGNPAR | PARMRK); storage.c_iflag |= INPCK; storage.c_cflag |= PARENB; storage.c_cflag &= ~PARODD; break; case odd: storage.c_iflag &= ~(IGNPAR | PARMRK); storage.c_iflag |= INPCK; storage.c_cflag |= (PARENB | PARODD); break; default: break; } #endif ec = asio::error_code(); return ec; } asio::error_code serial_port_base::parity::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (storage.Parity == EVENPARITY) { value_ = even; } else if (storage.Parity == ODDPARITY) { value_ = odd; } else { value_ = none; } #else if (storage.c_cflag & PARENB) { if (storage.c_cflag & PARODD) { value_ = odd; } else { value_ = even; } } else { value_ = none; } #endif ec = asio::error_code(); return ec; } serial_port_base::stop_bits::stop_bits( serial_port_base::stop_bits::type t) : value_(t) { if (t != one && t != onepointfive && t != two) { std::out_of_range ex("invalid stop_bits value"); boost::throw_exception(ex); } } asio::error_code serial_port_base::stop_bits::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) switch (value_) { case one: storage.StopBits = ONESTOPBIT; break; case onepointfive: storage.StopBits = ONE5STOPBITS; break; case two: storage.StopBits = TWOSTOPBITS; break; default: break; } #else switch (value_) { case one: storage.c_cflag &= ~CSTOPB; break; case two: storage.c_cflag |= CSTOPB; break; default: ec = asio::error::operation_not_supported; return ec; } #endif ec = asio::error_code(); return ec; } asio::error_code serial_port_base::stop_bits::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (storage.StopBits == ONESTOPBIT) { value_ = one; } else if (storage.StopBits == ONE5STOPBITS) { value_ = onepointfive; } else if (storage.StopBits == TWOSTOPBITS) { value_ = two; } else { value_ = one; } #else value_ = (storage.c_cflag & CSTOPB) ? two : one; #endif ec = asio::error_code(); return ec; } serial_port_base::character_size::character_size(unsigned int t) : value_(t) { if (t < 5 || t > 8) { std::out_of_range ex("invalid character_size value"); boost::throw_exception(ex); } } asio::error_code serial_port_base::character_size::store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) storage.ByteSize = value_; #else storage.c_cflag &= ~CSIZE; switch (value_) { case 5: storage.c_cflag |= CS5; break; case 6: storage.c_cflag |= CS6; break; case 7: storage.c_cflag |= CS7; break; case 8: storage.c_cflag |= CS8; break; default: break; } #endif ec = asio::error_code(); return ec; } asio::error_code serial_port_base::character_size::load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_ = storage.ByteSize; #else if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; } else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; } else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; } else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; } else { // Hmmm, use 8 for now. value_ = 8; } #endif ec = asio::error_code(); return ec; } } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_OPTION_STORAGE #endif // defined(ASIO_HAS_SERIAL_PORT) #endif // ASIO_IMPL_SERIAL_PORT_BASE_IPP percona-galera-3-3.8-3390/asio/asio/impl/src.cpp000066400000000000000000000012661244131713600211310ustar00rootroot00000000000000// // impl/src.cpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #if defined(_MSC_VER) \ || defined(__BORLANDC__) \ || defined(__DMC__) # pragma message ( \ "This file is deprecated. " \ "Please #include instead.") #elif defined(__GNUC__) \ || defined(__HP_aCC) \ || defined(__SUNPRO_CC) \ || defined(__IBMCPP__) # warning "This file is deprecated." # warning "Please #include instead." #endif #include "asio/impl/src.hpp" percona-galera-3-3.8-3390/asio/asio/impl/src.hpp000066400000000000000000000047131244131713600211360ustar00rootroot00000000000000// // impl/src.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_SRC_HPP #define ASIO_IMPL_SRC_HPP #define ASIO_SOURCE #include "asio/detail/config.hpp" #if defined(ASIO_HEADER_ONLY) # error Do not compile Asio library source with ASIO_HEADER_ONLY defined #endif #include "asio/impl/error.ipp" #include "asio/impl/error_code.ipp" #include "asio/impl/io_service.ipp" #include "asio/impl/serial_port_base.ipp" #include "asio/detail/impl/descriptor_ops.ipp" #include "asio/detail/impl/dev_poll_reactor.ipp" #include "asio/detail/impl/epoll_reactor.ipp" #include "asio/detail/impl/eventfd_select_interrupter.ipp" #include "asio/detail/impl/kqueue_reactor.ipp" #include "asio/detail/impl/pipe_select_interrupter.ipp" #include "asio/detail/impl/posix_event.ipp" #include "asio/detail/impl/posix_mutex.ipp" #include "asio/detail/impl/posix_thread.ipp" #include "asio/detail/impl/posix_tss_ptr.ipp" #include "asio/detail/impl/reactive_descriptor_service.ipp" #include "asio/detail/impl/reactive_serial_port_service.ipp" #include "asio/detail/impl/reactive_socket_service_base.ipp" #include "asio/detail/impl/resolver_service_base.ipp" #include "asio/detail/impl/select_reactor.ipp" #include "asio/detail/impl/service_registry.ipp" #include "asio/detail/impl/socket_ops.ipp" #include "asio/detail/impl/socket_select_interrupter.ipp" #include "asio/detail/impl/strand_service.ipp" #include "asio/detail/impl/task_io_service.ipp" #include "asio/detail/impl/throw_error.ipp" #include "asio/detail/impl/timer_queue.ipp" #include "asio/detail/impl/timer_queue_set.ipp" #include "asio/detail/impl/win_iocp_handle_service.ipp" #include "asio/detail/impl/win_iocp_io_service.ipp" #include "asio/detail/impl/win_iocp_serial_port_service.ipp" #include "asio/detail/impl/win_iocp_socket_service_base.ipp" #include "asio/detail/impl/win_event.ipp" #include "asio/detail/impl/win_mutex.ipp" #include "asio/detail/impl/win_thread.ipp" #include "asio/detail/impl/win_tss_ptr.ipp" #include "asio/detail/impl/winsock_init.ipp" #include "asio/ip/impl/address.ipp" #include "asio/ip/impl/address_v4.ipp" #include "asio/ip/impl/address_v6.ipp" #include "asio/ip/impl/host_name.ipp" #include "asio/ip/detail/impl/endpoint.ipp" #include "asio/local/detail/impl/endpoint.ipp" #endif // ASIO_IMPL_SRC_HPP percona-galera-3-3.8-3390/asio/asio/impl/write.hpp000066400000000000000000000306061244131713600215010ustar00rootroot00000000000000// // impl/write.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_WRITE_HPP #define ASIO_IMPL_WRITE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { template std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); b.consume(bytes_transferred); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = write(s, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write(s, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { switch (start) { case 1: buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { stream_.async_write_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncWriteStream& stream_; asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; WriteHandler handler_; }; template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncWriteStream& stream_; asio::mutable_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; }; template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const asio::const_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { stream_.async_write_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncWriteStream& stream_; asio::const_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { detail::write_op( s, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, WriteHandler handler) { async_write(s, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_streambuf_handler { public: write_streambuf_handler(asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), handler_(handler) { } void operator()(const asio::error_code& ec, const std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); handler_(ec, bytes_transferred); } //private: asio::basic_streambuf& streambuf_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write(AsyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler) { async_write(s, b.data(), completion_condition, detail::write_streambuf_handler< AsyncWriteStream, Allocator, WriteHandler>(b, handler)); } template inline void async_write(AsyncWriteStream& s, asio::basic_streambuf& b, WriteHandler handler) { async_write(s, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_WRITE_HPP percona-galera-3-3.8-3390/asio/asio/impl/write.ipp000066400000000000000000000304531244131713600215020ustar00rootroot00000000000000// // write.ipp // ~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WRITE_IPP #define ASIO_WRITE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" namespace asio { template std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); b.consume(bytes_transferred); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = write(s, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write(s, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffers_(buffers), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { switch (start_) { case true: start_ = false; buffers_.prepare(this->check(ec, total_transferred_)); for (;;) { stream_.async_write_some(buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, total_transferred_); } } //private: AsyncWriteStream& stream_; asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; WriteHandler handler_; bool start_; }; template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { std::size_t n = 0; switch (start_) { case true: start_ = false; n = this->check(ec, total_transferred_); for (;;) { stream_.async_write_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, total_transferred_); } } //private: AsyncWriteStream& stream_; asio::mutable_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; bool start_; }; template class write_op : detail::base_from_completion_cond { public: write_op(AsyncWriteStream& stream, const asio::const_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), stream_(stream), buffer_(buffers), total_transferred_(0), handler_(handler), start_(true) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { std::size_t n = 0; switch (start_) { case true: start_ = false; n = this->check(ec, total_transferred_); for (;;) { stream_.async_write_some(asio::buffer( buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, total_transferred_); } } //private: AsyncWriteStream& stream_; asio::const_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; bool start_; }; template inline void* asio_handler_allocate(std::size_t size, write_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { detail::write_op( s, buffers, completion_condition, handler)( asio::error_code(), 0); } template inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, WriteHandler handler) { async_write(s, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_streambuf_handler { public: write_streambuf_handler(asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); handler_(ec, bytes_transferred); } //private: asio::basic_streambuf& streambuf_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write(AsyncWriteStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler) { async_write(s, b.data(), completion_condition, detail::write_streambuf_handler< AsyncWriteStream, Allocator, WriteHandler>(b, handler)); } template inline void async_write(AsyncWriteStream& s, asio::basic_streambuf& b, WriteHandler handler) { async_write(s, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_WRITE_IPP percona-galera-3-3.8-3390/asio/asio/impl/write_at.hpp000066400000000000000000000334061244131713600221660ustar00rootroot00000000000000// // impl/write_at.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IMPL_WRITE_AT_HPP #define ASIO_IMPL_WRITE_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/base_from_completion_cond.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.write_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { std::size_t bytes_transferred = write_at( d, offset, b.data(), completion_condition, ec); b.consume(bytes_transferred); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_at_op : detail::base_from_completion_cond { public: write_at_op(AsyncRandomAccessWriteDevice& device, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), buffers_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { switch (start) { case 1: buffers_.prepare(this->check_for_completion(ec, total_transferred_)); for (;;) { device_.async_write_some_at( offset_ + total_transferred_, buffers_, *this); return; default: total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(this->check_for_completion(ec, total_transferred_)); if ((!ec && bytes_transferred == 0) || buffers_.begin() == buffers_.end()) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessWriteDevice& device_; boost::uint64_t offset_; asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> buffers_; std::size_t total_transferred_; WriteHandler handler_; }; template class write_at_op : detail::base_from_completion_cond { public: write_at_op(AsyncRandomAccessWriteDevice& device, boost::uint64_t offset, const asio::mutable_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { device_.async_write_some_at(offset_ + total_transferred_, asio::buffer(buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessWriteDevice& device_; boost::uint64_t offset_; asio::mutable_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; }; template class write_at_op : detail::base_from_completion_cond { public: write_at_op(AsyncRandomAccessWriteDevice& device, boost::uint64_t offset, const asio::const_buffers_1& buffers, CompletionCondition completion_condition, WriteHandler handler) : detail::base_from_completion_cond< CompletionCondition>(completion_condition), device_(device), offset_(offset), buffer_(buffers), total_transferred_(0), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred, int start = 0) { std::size_t n = 0; switch (start) { case 1: n = this->check_for_completion(ec, total_transferred_); for (;;) { device_.async_write_some_at(offset_ + total_transferred_, asio::buffer(buffer_ + total_transferred_, n), *this); return; default: total_transferred_ += bytes_transferred; if ((!ec && bytes_transferred == 0) || (n = this->check_for_completion(ec, total_transferred_)) == 0 || total_transferred_ == asio::buffer_size(buffer_)) break; } handler_(ec, static_cast(total_transferred_)); } } //private: AsyncRandomAccessWriteDevice& device_; boost::uint64_t offset_; asio::const_buffer buffer_; std::size_t total_transferred_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_at_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_at_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_at_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { detail::write_at_op( d, offset, buffers, completion_condition, handler)( asio::error_code(), 0, 1); } template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, WriteHandler handler) { async_write_at(d, offset, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_at_streambuf_op { public: write_at_streambuf_op( asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), handler_(handler) { } void operator()(const asio::error_code& ec, const std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); handler_(ec, bytes_transferred); } //private: asio::basic_streambuf& streambuf_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_at_streambuf_op* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_at_streambuf_op* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_at_streambuf_op* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler) { async_write_at(d, offset, b.data(), completion_condition, detail::write_at_streambuf_op< AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler)); } template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, WriteHandler handler) { async_write_at(d, offset, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_WRITE_AT_HPP percona-galera-3-3.8-3390/asio/asio/impl/write_at.ipp000066400000000000000000000250021244131713600221600ustar00rootroot00000000000000// // write_at.ipp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WRITE_AT_IPP #define ASIO_WRITE_AT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/push_options.hpp" #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/throw_error.hpp" namespace asio { template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { ec = asio::error_code(); asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.write_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); } return total_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, buffers, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, buffers, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #if !defined(BOOST_NO_IOSTREAM) template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { std::size_t bytes_transferred = write_at( d, offset, b.data(), completion_condition, ec); b.consume(bytes_transferred); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b) { asio::error_code ec; std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec); asio::detail::throw_error(ec); return bytes_transferred; } template inline std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition) { asio::error_code ec; std::size_t bytes_transferred = write_at( d, offset, b, completion_condition, ec); asio::detail::throw_error(ec); return bytes_transferred; } #endif // !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_at_handler { public: typedef asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> buffers_type; write_at_handler(AsyncRandomAccessWriteDevice& stream, boost::uint64_t offset, const buffers_type& buffers, CompletionCondition completion_condition, WriteHandler handler) : stream_(stream), buffers_(buffers), offset_(offset), total_transferred_(0), completion_condition_(completion_condition), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); buffers_.prepare(detail::adapt_completion_condition_result( completion_condition_(ec, total_transferred_))); if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } else { stream_.async_write_some_at( offset_ + total_transferred_, buffers_, *this); } } //private: AsyncRandomAccessWriteDevice& stream_; buffers_type buffers_; boost::uint64_t offset_; std::size_t total_transferred_; CompletionCondition completion_condition_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_at_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_at_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_at_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler) { asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); asio::error_code ec; std::size_t total_transferred = 0; tmp.prepare(detail::adapt_completion_condition_result( completion_condition(ec, total_transferred))); if (tmp.begin() == tmp.end()) { d.get_io_service().post(detail::bind_handler( handler, ec, total_transferred)); return; } d.async_write_some_at(offset, tmp, detail::write_at_handler( d, offset, tmp, completion_condition, handler)); } template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, WriteHandler handler) { async_write_at(d, offset, buffers, transfer_all(), handler); } #if !defined(BOOST_NO_IOSTREAM) namespace detail { template class write_at_streambuf_handler { public: write_at_streambuf_handler( asio::basic_streambuf& streambuf, WriteHandler handler) : streambuf_(streambuf), handler_(handler) { } void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); handler_(ec, bytes_transferred); } //private: asio::basic_streambuf& streambuf_; WriteHandler handler_; }; template inline void* asio_handler_allocate(std::size_t size, write_at_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template inline void asio_handler_deallocate(void* pointer, std::size_t size, write_at_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template inline void asio_handler_invoke(const Function& function, write_at_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } } // namespace detail template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler) { async_write_at(d, offset, b.data(), completion_condition, detail::write_at_streambuf_handler< AsyncRandomAccessWriteDevice, Allocator, WriteHandler>(b, handler)); } template inline void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, WriteHandler handler) { async_write_at(d, offset, b, transfer_all(), handler); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_WRITE_AT_IPP percona-galera-3-3.8-3390/asio/asio/io_service.hpp000066400000000000000000000567061244131713600215460ustar00rootroot00000000000000// // io_service.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IO_SERVICE_HPP #define ASIO_IO_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/detail/noncopyable.hpp" #include "asio/detail/service_registry_fwd.hpp" #include "asio/detail/wrapped_handler.hpp" #include "asio/error_code.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_io_service_fwd.hpp" #else # include "asio/detail/task_io_service_fwd.hpp" #endif #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # include "asio/detail/winsock_init.hpp" #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ || defined(__osf__) # include "asio/detail/signal_init.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { class io_service; template Service& use_service(io_service& ios); template void add_service(io_service& ios, Service* svc); template bool has_service(io_service& ios); #if defined(ASIO_HAS_IOCP) namespace detail { typedef win_iocp_io_service io_service_impl; } #else namespace detail { typedef task_io_service io_service_impl; } #endif /// Provides core I/O functionality. /** * The io_service class provides the core I/O functionality for users of the * asynchronous I/O objects, including: * * @li asio::ip::tcp::socket * @li asio::ip::tcp::acceptor * @li asio::ip::udp::socket * @li asio::deadline_timer. * * The io_service class also includes facilities intended for developers of * custom asynchronous services. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe, with the exception that calling reset() while * there are unfinished run(), run_one(), poll() or poll_one() calls results in * undefined behaviour. * * @par Concepts: * Dispatcher. * * @par Synchronous and asynchronous operations * * Synchronous operations on I/O objects implicitly run the io_service object * for an individual operation. The io_service functions run(), run_one(), * poll() or poll_one() must be called for the io_service to perform * asynchronous operations on behalf of a C++ program. Notification that an * asynchronous operation has completed is delivered by invocation of the * associated handler. Handlers are invoked only by a thread that is currently * calling any overload of run(), run_one(), poll() or poll_one() for the * io_service. * * @par Effect of exceptions thrown from handlers * * If an exception is thrown from a handler, the exception is allowed to * propagate through the throwing thread's invocation of run(), run_one(), * poll() or poll_one(). No other threads that are calling any of these * functions are affected. It is then the responsibility of the application to * catch the exception. * * After the exception has been caught, the run(), run_one(), poll() or * poll_one() call may be restarted @em without the need for an intervening * call to reset(). This allows the thread to rejoin the io_service object's * thread pool without impacting any other threads in the pool. * * For example: * * @code * asio::io_service io_service; * ... * for (;;) * { * try * { * io_service.run(); * break; // run() exited normally * } * catch (my_exception& e) * { * // Deal with exception as appropriate. * } * } * @endcode * * @par Stopping the io_service from running out of work * * Some applications may need to prevent an io_service object's run() call from * returning when there is no more work to do. For example, the io_service may * be being run in a background thread that is launched prior to the * application's asynchronous operations. The run() call may be kept running by * creating an object of type asio::io_service::work: * * @code asio::io_service io_service; * asio::io_service::work work(io_service); * ... @endcode * * To effect a shutdown, the application will then need to call the io_service * object's stop() member function. This will cause the io_service run() call * to return as soon as possible, abandoning unfinished operations and without * permitting ready handlers to be dispatched. * * Alternatively, if the application requires that all operations and handlers * be allowed to finish normally, the work object may be explicitly destroyed. * * @code asio::io_service io_service; * auto_ptr work( * new asio::io_service::work(io_service)); * ... * work.reset(); // Allow run() to exit. @endcode * * @par The io_service class and I/O services * * Class io_service implements an extensible, type-safe, polymorphic set of I/O * services, indexed by service type. An object of class io_service must be * initialised before I/O objects such as sockets, resolvers and timers can be * used. These I/O objects are distinguished by having constructors that accept * an @c io_service& parameter. * * I/O services exist to manage the logical interface to the operating system on * behalf of the I/O objects. In particular, there are resources that are shared * across a class of I/O objects. For example, timers may be implemented in * terms of a single timer queue. The I/O services manage these shared * resources. * * Access to the services of an io_service is via three function templates, * use_service(), add_service() and has_service(). * * In a call to @c use_service(), the type argument chooses a service, * making available all members of the named type. If @c Service is not present * in an io_service, an object of type @c Service is created and added to the * io_service. A C++ program can check if an io_service implements a * particular service with the function template @c has_service(). * * Service objects may be explicitly added to an io_service using the function * template @c add_service(). If the @c Service is already present, the * service_already_exists exception is thrown. If the owner of the service is * not the same object as the io_service parameter, the invalid_service_owner * exception is thrown. * * Once a service reference is obtained from an io_service object by calling * use_service(), that reference remains usable as long as the owning io_service * object exists. * * All I/O service implementations have io_service::service as a public base * class. Custom I/O services may be implemented by deriving from this class and * then added to an io_service using the facilities described above. */ class io_service : private noncopyable { private: typedef detail::io_service_impl impl_type; #if defined(ASIO_HAS_IOCP) friend class detail::win_iocp_overlapped_ptr; #endif public: class work; friend class work; class id; class service; class strand; /// Constructor. ASIO_DECL io_service(); /// Constructor. /** * Construct with a hint about the required level of concurrency. * * @param concurrency_hint A suggestion to the implementation on how many * threads it should allow to run simultaneously. */ ASIO_DECL explicit io_service(std::size_t concurrency_hint); /// Destructor. /** * On destruction, the io_service performs the following sequence of * operations: * * @li For each service object @c svc in the io_service set, in reverse order * of the beginning of service object lifetime, performs * @c svc->shutdown_service(). * * @li Uninvoked handler objects that were scheduled for deferred invocation * on the io_service, or any associated strand, are destroyed. * * @li For each service object @c svc in the io_service set, in reverse order * of the beginning of service object lifetime, performs * delete static_cast(svc). * * @note The destruction sequence described above permits programs to * simplify their resource management by using @c shared_ptr<>. Where an * object's lifetime is tied to the lifetime of a connection (or some other * sequence of asynchronous operations), a @c shared_ptr to the object would * be bound into the handlers for all asynchronous operations associated with * it. This works as follows: * * @li When a single connection ends, all associated asynchronous operations * complete. The corresponding handler objects are destroyed, and all * @c shared_ptr references to the objects are destroyed. * * @li To shut down the whole program, the io_service function stop() is * called to terminate any run() calls as soon as possible. The io_service * destructor defined above destroys all handlers, causing all @c shared_ptr * references to all connection objects to be destroyed. */ ASIO_DECL ~io_service(); /// Run the io_service object's event processing loop. /** * The run() function blocks until all work has finished and there are no * more handlers to be dispatched, or until the io_service has been stopped. * * Multiple threads may call the run() function to set up a pool of threads * from which the io_service may execute handlers. All threads that are * waiting in the pool are equivalent and the io_service may choose any one * of them to invoke a handler. * * The run() function may be safely called again once it has completed only * after a call to reset(). * * @return The number of handlers that were executed. * * @throws asio::system_error Thrown on failure. * * @note The run() function must not be called from a thread that is currently * calling one of run(), run_one(), poll() or poll_one() on the same * io_service object. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ ASIO_DECL std::size_t run(); /// Run the io_service object's event processing loop. /** * The run() function blocks until all work has finished and there are no * more handlers to be dispatched, or until the io_service has been stopped. * * Multiple threads may call the run() function to set up a pool of threads * from which the io_service may execute handlers. All threads that are * waiting in the pool are equivalent and the io_service may choose any one * of them to invoke a handler. * * The run() function may be safely called again once it has completed only * after a call to reset(). * * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. * * @note The run() function must not be called from a thread that is currently * calling one of run(), run_one(), poll() or poll_one() on the same * io_service object. * * The poll() function may also be used to dispatch ready handlers, but * without blocking. */ ASIO_DECL std::size_t run(asio::error_code& ec); /// Run the io_service object's event processing loop to execute at most one /// handler. /** * The run_one() function blocks until one handler has been dispatched, or * until the io_service has been stopped. * * @return The number of handlers that were executed. * * @throws asio::system_error Thrown on failure. */ ASIO_DECL std::size_t run_one(); /// Run the io_service object's event processing loop to execute at most one /// handler. /** * The run_one() function blocks until one handler has been dispatched, or * until the io_service has been stopped. * * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. */ ASIO_DECL std::size_t run_one(asio::error_code& ec); /// Run the io_service object's event processing loop to execute ready /// handlers. /** * The poll() function runs handlers that are ready to run, without blocking, * until the io_service has been stopped or there are no more ready handlers. * * @return The number of handlers that were executed. * * @throws asio::system_error Thrown on failure. */ ASIO_DECL std::size_t poll(); /// Run the io_service object's event processing loop to execute ready /// handlers. /** * The poll() function runs handlers that are ready to run, without blocking, * until the io_service has been stopped or there are no more ready handlers. * * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. */ ASIO_DECL std::size_t poll(asio::error_code& ec); /// Run the io_service object's event processing loop to execute one ready /// handler. /** * The poll_one() function runs at most one handler that is ready to run, * without blocking. * * @return The number of handlers that were executed. * * @throws asio::system_error Thrown on failure. */ ASIO_DECL std::size_t poll_one(); /// Run the io_service object's event processing loop to execute one ready /// handler. /** * The poll_one() function runs at most one handler that is ready to run, * without blocking. * * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. */ ASIO_DECL std::size_t poll_one(asio::error_code& ec); /// Stop the io_service object's event processing loop. /** * This function does not block, but instead simply signals the io_service to * stop. All invocations of its run() or run_one() member functions should * return as soon as possible. Subsequent calls to run(), run_one(), poll() * or poll_one() will return immediately until reset() is called. */ ASIO_DECL void stop(); /// Reset the io_service in preparation for a subsequent run() invocation. /** * This function must be called prior to any second or later set of * invocations of the run(), run_one(), poll() or poll_one() functions when a * previous invocation of these functions returned due to the io_service * being stopped or running out of work. This function allows the io_service * to reset any internal state, such as a "stopped" flag. * * This function must not be called while there are any unfinished calls to * the run(), run_one(), poll() or poll_one() functions. */ ASIO_DECL void reset(); /// Request the io_service to invoke the given handler. /** * This function is used to ask the io_service to execute the given handler. * * The io_service guarantees that the handler will only be called in a thread * in which the run(), run_one(), poll() or poll_one() member functions is * currently being invoked. The handler may be executed inside this function * if the guarantee can be met. * * @param handler The handler to be called. The io_service will make * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode * * @note This function throws an exception only if: * * @li the handler's @c asio_handler_allocate function; or * * @li the handler's copy constructor * * throws an exception. */ template void dispatch(CompletionHandler handler); /// Request the io_service to invoke the given handler and return immediately. /** * This function is used to ask the io_service to execute the given handler, * but without allowing the io_service to call the handler from inside this * function. * * The io_service guarantees that the handler will only be called in a thread * in which the run(), run_one(), poll() or poll_one() member functions is * currently being invoked. * * @param handler The handler to be called. The io_service will make * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode * * @note This function throws an exception only if: * * @li the handler's @c asio_handler_allocate function; or * * @li the handler's copy constructor * * throws an exception. */ template void post(CompletionHandler handler); /// Create a new handler that automatically dispatches the wrapped handler /// on the io_service. /** * This function is used to create a new handler function object that, when * invoked, will automatically pass the wrapped handler to the io_service * object's dispatch function. * * @param handler The handler to be wrapped. The io_service will make a copy * of the handler object as required. The function signature of the handler * must be: @code void handler(A1 a1, ... An an); @endcode * * @return A function object that, when invoked, passes the wrapped handler to * the io_service object's dispatch function. Given a function object with the * signature: * @code R f(A1 a1, ... An an); @endcode * If this function object is passed to the wrap function like so: * @code io_service.wrap(f); @endcode * then the return value is a function object with the signature * @code void g(A1 a1, ... An an); @endcode * that, when invoked, executes code equivalent to: * @code io_service.dispatch(boost::bind(f, a1, ... an)); @endcode */ template #if defined(GENERATING_DOCUMENTATION) unspecified #else detail::wrapped_handler #endif wrap(Handler handler); /// Obtain the service object corresponding to the given type. /** * This function is used to locate a service object that corresponds to * the given service type. If there is no existing implementation of the * service, then the io_service will create a new instance of the service. * * @param ios The io_service object that owns the service. * * @return The service interface implementing the specified service type. * Ownership of the service interface is not transferred to the caller. */ template friend Service& use_service(io_service& ios); /// Add a service object to the io_service. /** * This function is used to add a service to the io_service. * * @param ios The io_service object that owns the service. * * @param svc The service object. On success, ownership of the service object * is transferred to the io_service. When the io_service object is destroyed, * it will destroy the service object by performing: * @code delete static_cast(svc) @endcode * * @throws asio::service_already_exists Thrown if a service of the * given type is already present in the io_service. * * @throws asio::invalid_service_owner Thrown if the service's owning * io_service is not the io_service object specified by the ios parameter. */ template friend void add_service(io_service& ios, Service* svc); /// Determine if an io_service contains a specified service type. /** * This function is used to determine whether the io_service contains a * service object corresponding to the given service type. * * @param ios The io_service object that owns the service. * * @return A boolean indicating whether the io_service contains the service. */ template friend bool has_service(io_service& ios); private: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) detail::winsock_init<> init_; #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ || defined(__osf__) detail::signal_init<> init_; #endif // The service registry. asio::detail::service_registry* service_registry_; // The implementation. impl_type& impl_; }; /// Class to inform the io_service when it has work to do. /** * The work class is used to inform the io_service when work starts and * finishes. This ensures that the io_service object's run() function will not * exit while work is underway, and that it does exit when there is no * unfinished work remaining. * * The work class is copy-constructible so that it may be used as a data member * in a handler class. It is not assignable. */ class io_service::work { public: /// Constructor notifies the io_service that work is starting. /** * The constructor is used to inform the io_service that some work has begun. * This ensures that the io_service object's run() function will not exit * while the work is underway. */ explicit work(asio::io_service& io_service); /// Copy constructor notifies the io_service that work is starting. /** * The constructor is used to inform the io_service that some work has begun. * This ensures that the io_service object's run() function will not exit * while the work is underway. */ work(const work& other); /// Destructor notifies the io_service that the work is complete. /** * The destructor is used to inform the io_service that some work has * finished. Once the count of unfinished work reaches zero, the io_service * object's run() function is permitted to exit. */ ~work(); /// (Deprecated: use get_io_service().) Get the io_service associated with the /// work. asio::io_service& io_service(); /// Get the io_service associated with the work. asio::io_service& get_io_service(); private: // Prevent assignment. void operator=(const work& other); // The io_service. asio::io_service& io_service_; }; /// Class used to uniquely identify a service. class io_service::id : private noncopyable { public: /// Constructor. id() {} }; /// Base class for all io_service services. class io_service::service : private noncopyable { public: /// (Deprecated: use get_io_service().) Get the io_service object that owns /// the service. asio::io_service& io_service(); /// Get the io_service object that owns the service. asio::io_service& get_io_service(); protected: /// Constructor. /** * @param owner The io_service object that owns the service. */ ASIO_DECL service(asio::io_service& owner); /// Destructor. ASIO_DECL virtual ~service(); private: /// Destroy all user-defined handler objects owned by the service. virtual void shutdown_service() = 0; friend class asio::detail::service_registry; struct key { key() : type_info_(0), id_(0) {} const std::type_info* type_info_; const asio::io_service::id* id_; } key_; asio::io_service& owner_; service* next_; }; /// Exception thrown when trying to add a duplicate service to an io_service. class service_already_exists : public std::logic_error { public: ASIO_DECL service_already_exists(); }; /// Exception thrown when trying to add a service object to an io_service where /// the service has a different owner. class invalid_service_owner : public std::logic_error { public: ASIO_DECL invalid_service_owner(); }; namespace detail { // Special derived service id type to keep classes header-file only. template class service_id : public asio::io_service::id { }; // Special service base class to keep classes header-file only. template class service_base : public asio::io_service::service { public: static asio::detail::service_id id; // Constructor. service_base(asio::io_service& io_service) : asio::io_service::service(io_service) { } }; template asio::detail::service_id service_base::id; } // namespace detail } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/io_service.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/impl/io_service.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IO_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/ip/000077500000000000000000000000001244131713600173005ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ip/address.hpp000066400000000000000000000115161244131713600214420ustar00rootroot00000000000000// // ip/address.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_ADDRESS_HPP #define ASIO_IP_ADDRESS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error_code.hpp" #include "asio/ip/address_v4.hpp" #include "asio/ip/address_v6.hpp" #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Implements version-independent IP addresses. /** * The asio::ip::address class provides the ability to use either IP * version 4 or version 6 addresses. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ class address { public: /// Default constructor. ASIO_DECL address(); /// Construct an address from an IPv4 address. ASIO_DECL address(const asio::ip::address_v4& ipv4_address); /// Construct an address from an IPv6 address. ASIO_DECL address(const asio::ip::address_v6& ipv6_address); /// Copy constructor. ASIO_DECL address(const address& other); /// Assign from another address. ASIO_DECL address& operator=(const address& other); /// Assign from an IPv4 address. ASIO_DECL address& operator=( const asio::ip::address_v4& ipv4_address); /// Assign from an IPv6 address. ASIO_DECL address& operator=( const asio::ip::address_v6& ipv6_address); /// Get whether the address is an IP version 4 address. bool is_v4() const { return type_ == ipv4; } /// Get whether the address is an IP version 6 address. bool is_v6() const { return type_ == ipv6; } /// Get the address as an IP version 4 address. ASIO_DECL asio::ip::address_v4 to_v4() const; /// Get the address as an IP version 6 address. ASIO_DECL asio::ip::address_v6 to_v6() const; /// Get the address as a string in dotted decimal format. ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. ASIO_DECL static address from_string(const char* str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. ASIO_DECL static address from_string( const char* str, asio::error_code& ec); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. ASIO_DECL static address from_string(const std::string& str); /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. ASIO_DECL static address from_string( const std::string& str, asio::error_code& ec); /// Compare two addresses for equality. ASIO_DECL friend bool operator==(const address& a1, const address& a2); /// Compare two addresses for inequality. friend bool operator!=(const address& a1, const address& a2) { return !(a1 == a2); } /// Compare addresses for ordering. ASIO_DECL friend bool operator<(const address& a1, const address& a2); /// Compare addresses for ordering. friend bool operator>(const address& a1, const address& a2) { return a2 < a1; } /// Compare addresses for ordering. friend bool operator<=(const address& a1, const address& a2) { return !(a2 < a1); } /// Compare addresses for ordering. friend bool operator>=(const address& a1, const address& a2) { return !(a1 < a2); } private: // The type of the address. enum { ipv4, ipv6 } type_; // The underlying IPv4 address. asio::ip::address_v4 ipv4_address_; // The underlying IPv6 address. asio::ip::address_v6 ipv6_address_; }; #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates asio::ip::address */ template std::basic_ostream& operator<<( std::basic_ostream& os, const address& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/ip/impl/address.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IP_ADDRESS_HPP percona-galera-3-3.8-3390/asio/asio/ip/address_v4.hpp000066400000000000000000000134161244131713600220540ustar00rootroot00000000000000// // ip/address_v4.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_ADDRESS_V4_HPP #define ASIO_IP_ADDRESS_V4_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/socket_types.hpp" #include "asio/detail/winsock_init.hpp" #include "asio/error_code.hpp" #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Implements IP version 4 style addresses. /** * The asio::ip::address_v4 class provides the ability to use and * manipulate IP version 4 addresses. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ class address_v4 { public: /// The type used to represent an address as an array of bytes. typedef boost::array bytes_type; /// Default constructor. address_v4() { addr_.s_addr = 0; } /// Construct an address from raw bytes. ASIO_DECL explicit address_v4(const bytes_type& bytes); /// Construct an address from a unsigned long in host byte order. ASIO_DECL explicit address_v4(unsigned long addr); /// Copy constructor. address_v4(const address_v4& other) : addr_(other.addr_) { } /// Assign from another address. address_v4& operator=(const address_v4& other) { addr_ = other.addr_; return *this; } /// Get the address in bytes, in network byte order. ASIO_DECL bytes_type to_bytes() const; /// Get the address as an unsigned long in host byte order ASIO_DECL unsigned long to_ulong() const; /// Get the address as a string in dotted decimal format. ASIO_DECL std::string to_string() const; /// Get the address as a string in dotted decimal format. ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IP address string in dotted decimal form. ASIO_DECL static address_v4 from_string(const char* str); /// Create an address from an IP address string in dotted decimal form. ASIO_DECL static address_v4 from_string( const char* str, asio::error_code& ec); /// Create an address from an IP address string in dotted decimal form. ASIO_DECL static address_v4 from_string(const std::string& str); /// Create an address from an IP address string in dotted decimal form. ASIO_DECL static address_v4 from_string( const std::string& str, asio::error_code& ec); /// Determine whether the address is a class A address. ASIO_DECL bool is_class_a() const; /// Determine whether the address is a class B address. ASIO_DECL bool is_class_b() const; /// Determine whether the address is a class C address. ASIO_DECL bool is_class_c() const; /// Determine whether the address is a multicast address. ASIO_DECL bool is_multicast() const; /// Compare two addresses for equality. friend bool operator==(const address_v4& a1, const address_v4& a2) { return a1.addr_.s_addr == a2.addr_.s_addr; } /// Compare two addresses for inequality. friend bool operator!=(const address_v4& a1, const address_v4& a2) { return a1.addr_.s_addr != a2.addr_.s_addr; } /// Compare addresses for ordering. friend bool operator<(const address_v4& a1, const address_v4& a2) { return a1.to_ulong() < a2.to_ulong(); } /// Compare addresses for ordering. friend bool operator>(const address_v4& a1, const address_v4& a2) { return a1.to_ulong() > a2.to_ulong(); } /// Compare addresses for ordering. friend bool operator<=(const address_v4& a1, const address_v4& a2) { return a1.to_ulong() <= a2.to_ulong(); } /// Compare addresses for ordering. friend bool operator>=(const address_v4& a1, const address_v4& a2) { return a1.to_ulong() >= a2.to_ulong(); } /// Obtain an address object that represents any address. static address_v4 any() { return address_v4(static_cast(INADDR_ANY)); } /// Obtain an address object that represents the loopback address. static address_v4 loopback() { return address_v4(static_cast(INADDR_LOOPBACK)); } /// Obtain an address object that represents the broadcast address. static address_v4 broadcast() { return address_v4(static_cast(INADDR_BROADCAST)); } /// Obtain an address object that represents the broadcast address that /// corresponds to the specified address and netmask. ASIO_DECL static address_v4 broadcast( const address_v4& addr, const address_v4& mask); /// Obtain the netmask that corresponds to the address, based on its address /// class. ASIO_DECL static address_v4 netmask(const address_v4& addr); private: // The underlying IPv4 address. asio::detail::in4_addr_type addr_; }; #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates asio::ip::address_v4 */ template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v4& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address_v4.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/ip/impl/address_v4.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IP_ADDRESS_V4_HPP percona-galera-3-3.8-3390/asio/asio/ip/address_v6.hpp000066400000000000000000000143431244131713600220560ustar00rootroot00000000000000// // ip/address_v6.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_ADDRESS_V6_HPP #define ASIO_IP_ADDRESS_V6_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/socket_types.hpp" #include "asio/detail/winsock_init.hpp" #include "asio/error_code.hpp" #include "asio/ip/address_v4.hpp" #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Implements IP version 6 style addresses. /** * The asio::ip::address_v6 class provides the ability to use and * manipulate IP version 6 addresses. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ class address_v6 { public: /// The type used to represent an address as an array of bytes. typedef boost::array bytes_type; /// Default constructor. ASIO_DECL address_v6(); /// Construct an address from raw bytes and scope ID. ASIO_DECL explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0); /// Copy constructor. ASIO_DECL address_v6(const address_v6& other); /// Assign from another address. ASIO_DECL address_v6& operator=(const address_v6& other); /// The scope ID of the address. /** * Returns the scope ID associated with the IPv6 address. */ unsigned long scope_id() const { return scope_id_; } /// The scope ID of the address. /** * Modifies the scope ID associated with the IPv6 address. */ void scope_id(unsigned long id) { scope_id_ = id; } /// Get the address in bytes, in network byte order. ASIO_DECL bytes_type to_bytes() const; /// Get the address as a string. ASIO_DECL std::string to_string() const; /// Get the address as a string. ASIO_DECL std::string to_string(asio::error_code& ec) const; /// Create an address from an IP address string. ASIO_DECL static address_v6 from_string(const char* str); /// Create an address from an IP address string. ASIO_DECL static address_v6 from_string( const char* str, asio::error_code& ec); /// Create an address from an IP address string. ASIO_DECL static address_v6 from_string(const std::string& str); /// Create an address from an IP address string. ASIO_DECL static address_v6 from_string( const std::string& str, asio::error_code& ec); /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address. ASIO_DECL address_v4 to_v4() const; /// Determine whether the address is a loopback address. ASIO_DECL bool is_loopback() const; /// Determine whether the address is unspecified. ASIO_DECL bool is_unspecified() const; /// Determine whether the address is link local. ASIO_DECL bool is_link_local() const; /// Determine whether the address is site local. ASIO_DECL bool is_site_local() const; /// Determine whether the address is a mapped IPv4 address. ASIO_DECL bool is_v4_mapped() const; /// Determine whether the address is an IPv4-compatible address. ASIO_DECL bool is_v4_compatible() const; /// Determine whether the address is a multicast address. ASIO_DECL bool is_multicast() const; /// Determine whether the address is a global multicast address. ASIO_DECL bool is_multicast_global() const; /// Determine whether the address is a link-local multicast address. ASIO_DECL bool is_multicast_link_local() const; /// Determine whether the address is a node-local multicast address. ASIO_DECL bool is_multicast_node_local() const; /// Determine whether the address is a org-local multicast address. ASIO_DECL bool is_multicast_org_local() const; /// Determine whether the address is a site-local multicast address. ASIO_DECL bool is_multicast_site_local() const; /// Compare two addresses for equality. ASIO_DECL friend bool operator==( const address_v6& a1, const address_v6& a2); /// Compare two addresses for inequality. friend bool operator!=(const address_v6& a1, const address_v6& a2) { return !(a1 == a2); } /// Compare addresses for ordering. ASIO_DECL friend bool operator<( const address_v6& a1, const address_v6& a2); /// Compare addresses for ordering. friend bool operator>(const address_v6& a1, const address_v6& a2) { return a2 < a1; } /// Compare addresses for ordering. friend bool operator<=(const address_v6& a1, const address_v6& a2) { return !(a2 < a1); } /// Compare addresses for ordering. friend bool operator>=(const address_v6& a1, const address_v6& a2) { return !(a1 < a2); } /// Obtain an address object that represents any address. static address_v6 any() { return address_v6(); } /// Obtain an address object that represents the loopback address. ASIO_DECL static address_v6 loopback(); /// Create an IPv4-mapped IPv6 address. ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); /// Create an IPv4-compatible IPv6 address. ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); private: // The underlying IPv6 address. asio::detail::in6_addr_type addr_; // The scope ID associated with the address. unsigned long scope_id_; }; #if !defined(BOOST_NO_IOSTREAM) /// Output an address as a string. /** * Used to output a human-readable string for a specified address. * * @param os The output stream to which the string will be written. * * @param addr The address to be written. * * @return The output stream. * * @relates asio::ip::address_v6 */ template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v6& addr); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/address_v6.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/ip/impl/address_v6.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IP_ADDRESS_V6_HPP percona-galera-3-3.8-3390/asio/asio/ip/basic_endpoint.hpp000066400000000000000000000141521244131713600227750ustar00rootroot00000000000000// // ip/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_BASIC_ENDPOINT_HPP #define ASIO_IP_BASIC_ENDPOINT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/ip/address.hpp" #include "asio/ip/detail/endpoint.hpp" #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Describes an endpoint for a version-independent IP socket. /** * The asio::ip::basic_endpoint class template describes an endpoint that * may be associated with a particular socket. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * Endpoint. */ template class basic_endpoint { public: /// The protocol type associated with the endpoint. typedef InternetProtocol protocol_type; /// The type of the endpoint structure. This type is dependent on the /// underlying implementation of the socket layer. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined data_type; #else typedef asio::detail::socket_addr_type data_type; #endif /// Default constructor. basic_endpoint() : impl_() { } /// Construct an endpoint using a port number, specified in the host's byte /// order. The IP address will be the any address (i.e. INADDR_ANY or /// in6addr_any). This constructor would typically be used for accepting new /// connections. /** * @par Examples * To initialise an IPv4 TCP endpoint for port 1234, use: * @code * asio::ip::tcp::endpoint ep(asio::ip::tcp::v4(), 1234); * @endcode * * To specify an IPv6 UDP endpoint for port 9876, use: * @code * asio::ip::udp::endpoint ep(asio::ip::udp::v6(), 9876); * @endcode */ basic_endpoint(const InternetProtocol& protocol, unsigned short port_num) : impl_(protocol.family(), port_num) { } /// Construct an endpoint using a port number and an IP address. This /// constructor may be used for accepting connections on a specific interface /// or for making a connection to a remote endpoint. basic_endpoint(const asio::ip::address& addr, unsigned short port_num) : impl_(addr, port_num) { } /// Copy constructor. basic_endpoint(const basic_endpoint& other) : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { impl_ = other.impl_; return *this; } /// The protocol associated with the endpoint. protocol_type protocol() const { if (impl_.is_v4()) return InternetProtocol::v4(); return InternetProtocol::v6(); } /// Get the underlying endpoint in the native type. data_type* data() { return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { return impl_.capacity(); } /// Get the port associated with the endpoint. The port number is always in /// the host's byte order. unsigned short port() const { return impl_.port(); } /// Set the port associated with the endpoint. The port number is always in /// the host's byte order. void port(unsigned short port_num) { impl_.port(port_num); } /// Get the IP address associated with the endpoint. asio::ip::address address() const { return impl_.address(); } /// Set the IP address associated with the endpoint. void address(const asio::ip::address& addr) { impl_.address(addr); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint& e1, const basic_endpoint& e2) { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e1 < e2); } private: // The underlying IP endpoint. asio::ip::detail::endpoint impl_; }; #if !defined(BOOST_NO_IOSTREAM) /// Output an endpoint as a string. /** * Used to output a human-readable string for a specified endpoint. * * @param os The output stream to which the string will be written. * * @param endpoint The endpoint to be written. * * @return The output stream. * * @relates asio::ip::basic_endpoint */ template std::basic_ostream& operator<<( std::basic_ostream& os, const basic_endpoint& endpoint); #endif // !defined(BOOST_NO_IOSTREAM) } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/ip/impl/basic_endpoint.hpp" #endif // ASIO_IP_BASIC_ENDPOINT_HPP percona-galera-3-3.8-3390/asio/asio/ip/basic_resolver.hpp000066400000000000000000000204111244131713600230110ustar00rootroot00000000000000// // ip/basic_resolver.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_BASIC_RESOLVER_HPP #define ASIO_IP_BASIC_RESOLVER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_io_object.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/resolver_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Provides endpoint resolution functionality. /** * The basic_resolver class template provides the ability to resolve a query * to a list of endpoints. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template > class basic_resolver : public basic_io_object { public: /// The protocol type. typedef InternetProtocol protocol_type; /// The endpoint type. typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. typedef basic_resolver_query query; /// The iterator type. typedef basic_resolver_iterator iterator; /// Constructor. /** * This constructor creates a basic_resolver. * * @param io_service The io_service object that the resolver will use to * dispatch handlers for any asynchronous operations performed on the timer. */ explicit basic_resolver(asio::io_service& io_service) : basic_io_object(io_service) { } /// Cancel any asynchronous operations that are waiting on the resolver. /** * This function forces the completion of any pending asynchronous * operations on the host resolver. The handler for each cancelled operation * will be invoked with the asio::error::operation_aborted error code. */ void cancel() { return this->service.cancel(this->implementation); } /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * * @param q A query object that determines what endpoints will be returned. * * @returns A forward-only iterator that can be used to traverse the list * of endpoint entries. * * @throws asio::system_error Thrown on failure. * * @note A default constructed iterator represents the end of the list. * * A successful call to this function is guaranteed to return at least one * entry. */ iterator resolve(const query& q) { asio::error_code ec; iterator i = this->service.resolve(this->implementation, q, ec); asio::detail::throw_error(ec); return i; } /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * * @param q A query object that determines what endpoints will be returned. * * @param ec Set to indicate what error occurred, if any. * * @returns A forward-only iterator that can be used to traverse the list * of endpoint entries. Returns a default constructed iterator if an error * occurs. * * @note A default constructed iterator represents the end of the list. * * A successful call to this function is guaranteed to return at least one * entry. */ iterator resolve(const query& q, asio::error_code& ec) { return this->service.resolve(this->implementation, q, ec); } /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to asynchronously resolve a query into a list of * endpoint entries. * * @param q A query object that determines what endpoints will be returned. * * @param handler The handler to be called when the resolve operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::iterator iterator // Forward-only iterator that can * // be used to traverse the list * // of endpoint entries. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note A default constructed iterator represents the end of the list. * * A successful resolve operation is guaranteed to pass at least one entry to * the handler. */ template void async_resolve(const query& q, ResolveHandler handler) { return this->service.async_resolve(this->implementation, q, handler); } /// Perform reverse resolution of an endpoint to a list of entries. /** * This function is used to resolve an endpoint into a list of endpoint * entries. * * @param e An endpoint object that determines what endpoints will be * returned. * * @returns A forward-only iterator that can be used to traverse the list * of endpoint entries. * * @throws asio::system_error Thrown on failure. * * @note A default constructed iterator represents the end of the list. * * A successful call to this function is guaranteed to return at least one * entry. */ iterator resolve(const endpoint_type& e) { asio::error_code ec; iterator i = this->service.resolve(this->implementation, e, ec); asio::detail::throw_error(ec); return i; } /// Perform reverse resolution of an endpoint to a list of entries. /** * This function is used to resolve an endpoint into a list of endpoint * entries. * * @param e An endpoint object that determines what endpoints will be * returned. * * @param ec Set to indicate what error occurred, if any. * * @returns A forward-only iterator that can be used to traverse the list * of endpoint entries. Returns a default constructed iterator if an error * occurs. * * @note A default constructed iterator represents the end of the list. * * A successful call to this function is guaranteed to return at least one * entry. */ iterator resolve(const endpoint_type& e, asio::error_code& ec) { return this->service.resolve(this->implementation, e, ec); } /// Asynchronously perform reverse resolution of an endpoint to a list of /// entries. /** * This function is used to asynchronously resolve an endpoint into a list of * endpoint entries. * * @param e An endpoint object that determines what endpoints will be * returned. * * @param handler The handler to be called when the resolve operation * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * resolver::iterator iterator // Forward-only iterator that can * // be used to traverse the list * // of endpoint entries. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note A default constructed iterator represents the end of the list. * * A successful resolve operation is guaranteed to pass at least one entry to * the handler. */ template void async_resolve(const endpoint_type& e, ResolveHandler handler) { return this->service.async_resolve(this->implementation, e, handler); } }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_BASIC_RESOLVER_HPP percona-galera-3-3.8-3390/asio/asio/ip/basic_resolver_entry.hpp000066400000000000000000000042401244131713600242340ustar00rootroot00000000000000// // ip/basic_resolver_entry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_BASIC_RESOLVER_ENTRY_HPP #define ASIO_IP_BASIC_RESOLVER_ENTRY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// An entry produced by a resolver. /** * The asio::ip::basic_resolver_entry class template describes an entry * as returned by a resolver. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_resolver_entry { public: /// The protocol type associated with the endpoint entry. typedef InternetProtocol protocol_type; /// The endpoint type associated with the endpoint entry. typedef typename InternetProtocol::endpoint endpoint_type; /// Default constructor. basic_resolver_entry() { } /// Construct with specified endpoint, host name and service name. basic_resolver_entry(const endpoint_type& endpoint, const std::string& host_name, const std::string& service_name) : endpoint_(endpoint), host_name_(host_name), service_name_(service_name) { } /// Get the endpoint associated with the entry. endpoint_type endpoint() const { return endpoint_; } /// Convert to the endpoint associated with the entry. operator endpoint_type() const { return endpoint_; } /// Get the host name associated with the entry. std::string host_name() const { return host_name_; } /// Get the service name associated with the entry. std::string service_name() const { return service_name_; } private: endpoint_type endpoint_; std::string host_name_; std::string service_name_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_BASIC_RESOLVER_ENTRY_HPP percona-galera-3-3.8-3390/asio/asio/ip/basic_resolver_iterator.hpp000066400000000000000000000116011244131713600247230ustar00rootroot00000000000000// // ip/basic_resolver_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP #define ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/shared_ptr.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/ip/basic_resolver_entry.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// An iterator over the entries produced by a resolver. /** * The asio::ip::basic_resolver_iterator class template is used to define * iterators over the results returned by a resolver. * * The iterator's value_type, obtained when the iterator is dereferenced, is: * @code const basic_resolver_entry @endcode * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_resolver_iterator #if defined(GENERATING_DOCUMENTATION) : public std::iterator< #else // defined(GENERATING_DOCUMENTATION) : public boost::iterator< #endif // defined(GENERATING_DOCUMENTATION) std::forward_iterator_tag, const basic_resolver_entry > { public: /// Default constructor creates an end iterator. basic_resolver_iterator() : index_(0) { } /// Create an iterator from an addrinfo list returned by getaddrinfo. static basic_resolver_iterator create( asio::detail::addrinfo_type* address_info, const std::string& host_name, const std::string& service_name) { basic_resolver_iterator iter; if (!address_info) return iter; std::string actual_host_name = host_name; if (address_info->ai_canonname) actual_host_name = address_info->ai_canonname; iter.values_.reset(new values_type); while (address_info) { if (address_info->ai_family == PF_INET || address_info->ai_family == PF_INET6) { using namespace std; // For memcpy. typename InternetProtocol::endpoint endpoint; endpoint.resize(static_cast(address_info->ai_addrlen)); memcpy(endpoint.data(), address_info->ai_addr, address_info->ai_addrlen); iter.values_->push_back( basic_resolver_entry(endpoint, actual_host_name, service_name)); } address_info = address_info->ai_next; } return iter; } /// Create an iterator from an endpoint, host name and service name. static basic_resolver_iterator create( const typename InternetProtocol::endpoint& endpoint, const std::string& host_name, const std::string& service_name) { basic_resolver_iterator iter; iter.values_.reset(new values_type); iter.values_->push_back( basic_resolver_entry( endpoint, host_name, service_name)); return iter; } /// Dereference an iterator. const basic_resolver_entry& operator*() const { return dereference(); } /// Dereference an iterator. const basic_resolver_entry* operator->() const { return &dereference(); } /// Increment operator (prefix). basic_resolver_iterator& operator++() { increment(); return *this; } /// Increment operator (postfix). basic_resolver_iterator operator++(int) { basic_resolver_iterator tmp(*this); ++*this; return tmp; } /// Test two iterators for equality. friend bool operator==(const basic_resolver_iterator& a, const basic_resolver_iterator& b) { return a.equal(b); } /// Test two iterators for inequality. friend bool operator!=(const basic_resolver_iterator& a, const basic_resolver_iterator& b) { return !a.equal(b); } private: void increment() { if (++index_ == values_->size()) { // Reset state to match a default constructed end iterator. values_.reset(); index_ = 0; } } bool equal(const basic_resolver_iterator& other) const { if (!values_ && !other.values_) return true; if (values_ != other.values_) return false; return index_ == other.index_; } const basic_resolver_entry& dereference() const { return (*values_)[index_]; } typedef std::vector > values_type; asio::detail::shared_ptr values_; std::size_t index_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP percona-galera-3-3.8-3390/asio/asio/ip/basic_resolver_query.hpp000066400000000000000000000221551244131713600242450ustar00rootroot00000000000000// // ip/basic_resolver_query.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_BASIC_RESOLVER_QUERY_HPP #define ASIO_IP_BASIC_RESOLVER_QUERY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/socket_ops.hpp" #include "asio/ip/resolver_query_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// An query to be passed to a resolver. /** * The asio::ip::basic_resolver_query class template describes a query * that can be passed to a resolver. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_resolver_query : public resolver_query_base { public: /// The protocol type associated with the endpoint query. typedef InternetProtocol protocol_type; /// Construct with specified service name for any protocol. /** * This constructor is typically used to perform name resolution for local * service binding. * * @param service_name A string identifying the requested service. This may * be a descriptive name or a numeric string corresponding to a port number. * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for local service * binding. * * @note On POSIX systems, service names are typically defined in the file * /etc/services. On Windows, service names may be found in the file * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ basic_resolver_query(const std::string& service_name, resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); hints_.ai_addrlen = 0; hints_.ai_canonname = 0; hints_.ai_addr = 0; hints_.ai_next = 0; } /// Construct with specified service name for a given protocol. /** * This constructor is typically used to perform name resolution for local * service binding with a specific protocol version. * * @param protocol A protocol object, normally representing either the IPv4 or * IPv6 version of an internet protocol. * * @param service_name A string identifying the requested service. This may * be a descriptive name or a numeric string corresponding to a port number. * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for local service * binding. * * @note On POSIX systems, service names are typically defined in the file * /etc/services. On Windows, service names may be found in the file * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ basic_resolver_query(const protocol_type& protocol, const std::string& service_name, resolver_query_base::flags resolve_flags = passive | address_configured) : hints_(), host_name_(), service_name_(service_name) { hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); hints_.ai_addrlen = 0; hints_.ai_canonname = 0; hints_.ai_addr = 0; hints_.ai_next = 0; } /// Construct with specified host name and service name for any protocol. /** * This constructor is typically used to perform name resolution for * communication with remote hosts. * * @param host_name A string identifying a location. May be a descriptive name * or a numeric address string. If an empty string and the passive flag has * been specified, the resolved endpoints are suitable for local service * binding. If an empty string and passive is not specified, the resolved * endpoints will use the loopback address. * * @param service_name A string identifying the requested service. This may * be a descriptive name or a numeric string corresponding to a port number. * May be an empty string, in which case all resolved endpoints will have a * port number of 0. * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with * remote hosts. * * @note On POSIX systems, host names may be locally defined in the file * /etc/hosts. On Windows, host names may be defined in the file * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name * resolution is performed using DNS. Operating systems may use additional * locations when resolving host names (such as NETBIOS names on Windows). * * On POSIX systems, service names are typically defined in the file * /etc/services. On Windows, service names may be found in the file * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ basic_resolver_query(const std::string& host_name, const std::string& service_name, resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { typename InternetProtocol::endpoint endpoint; hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); hints_.ai_protocol = endpoint.protocol().protocol(); hints_.ai_addrlen = 0; hints_.ai_canonname = 0; hints_.ai_addr = 0; hints_.ai_next = 0; } /// Construct with specified host name and service name for a given protocol. /** * This constructor is typically used to perform name resolution for * communication with remote hosts. * * @param protocol A protocol object, normally representing either the IPv4 or * IPv6 version of an internet protocol. * * @param host_name A string identifying a location. May be a descriptive name * or a numeric address string. If an empty string and the passive flag has * been specified, the resolved endpoints are suitable for local service * binding. If an empty string and passive is not specified, the resolved * endpoints will use the loopback address. * * @param service_name A string identifying the requested service. This may * be a descriptive name or a numeric string corresponding to a port number. * May be an empty string, in which case all resolved endpoints will have a * port number of 0. * * @param resolve_flags A set of flags that determine how name resolution * should be performed. The default flags are suitable for communication with * remote hosts. * * @note On POSIX systems, host names may be locally defined in the file * /etc/hosts. On Windows, host names may be defined in the file * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name * resolution is performed using DNS. Operating systems may use additional * locations when resolving host names (such as NETBIOS names on Windows). * * On POSIX systems, service names are typically defined in the file * /etc/services. On Windows, service names may be found in the file * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ basic_resolver_query(const protocol_type& protocol, const std::string& host_name, const std::string& service_name, resolver_query_base::flags resolve_flags = address_configured) : hints_(), host_name_(host_name), service_name_(service_name) { hints_.ai_flags = static_cast(resolve_flags); hints_.ai_family = protocol.family(); hints_.ai_socktype = protocol.type(); hints_.ai_protocol = protocol.protocol(); hints_.ai_addrlen = 0; hints_.ai_canonname = 0; hints_.ai_addr = 0; hints_.ai_next = 0; } /// Get the hints associated with the query. const asio::detail::addrinfo_type& hints() const { return hints_; } /// Get the host name associated with the query. std::string host_name() const { return host_name_; } /// Get the service name associated with the query. std::string service_name() const { return service_name_; } private: asio::detail::addrinfo_type hints_; std::string host_name_; std::string service_name_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_BASIC_RESOLVER_QUERY_HPP percona-galera-3-3.8-3390/asio/asio/ip/detail/000077500000000000000000000000001244131713600205425ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ip/detail/endpoint.hpp000066400000000000000000000067721244131713600231070ustar00rootroot00000000000000// // ip/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_DETAIL_ENDPOINT_HPP #define ASIO_IP_DETAIL_ENDPOINT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/socket_types.hpp" #include "asio/detail/winsock_init.hpp" #include "asio/error_code.hpp" #include "asio/ip/address.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { namespace detail { // Helper class for implementating an IP endpoint. class endpoint { public: // Default constructor. ASIO_DECL endpoint(); // Construct an endpoint using a family and port number. ASIO_DECL endpoint(int family, unsigned short port_num); // Construct an endpoint using an address and port number. ASIO_DECL endpoint(const asio::ip::address& addr, unsigned short port_num); // Copy constructor. endpoint(const endpoint& other) : data_(other.data_) { } // Assign from another endpoint. endpoint& operator=(const endpoint& other) { data_ = other.data_; return *this; } // Get the underlying endpoint in the native type. asio::detail::socket_addr_type* data() { return &data_.base; } // Get the underlying endpoint in the native type. const asio::detail::socket_addr_type* data() const { return &data_.base; } // Get the underlying size of the endpoint in the native type. std::size_t size() const { if (is_v4()) return sizeof(asio::detail::sockaddr_in4_type); else return sizeof(asio::detail::sockaddr_in6_type); } // Set the underlying size of the endpoint in the native type. ASIO_DECL void resize(std::size_t size); // Get the capacity of the endpoint in the native type. std::size_t capacity() const { return sizeof(asio::detail::sockaddr_storage_type); } // Get the port associated with the endpoint. ASIO_DECL unsigned short port() const; // Set the port associated with the endpoint. ASIO_DECL void port(unsigned short port_num); // Get the IP address associated with the endpoint. ASIO_DECL asio::ip::address address() const; // Set the IP address associated with the endpoint. ASIO_DECL void address(const asio::ip::address& addr); // Compare two endpoints for equality. ASIO_DECL friend bool operator==( const endpoint& e1, const endpoint& e2); // Compare endpoints for ordering. ASIO_DECL friend bool operator<( const endpoint& e1, const endpoint& e2); // Determine whether the endpoint is IPv4. bool is_v4() const { return data_.base.sa_family == AF_INET; } #if !defined(BOOST_NO_IOSTREAM) // Convert to a string. ASIO_DECL std::string to_string(asio::error_code& ec) const; #endif // !defined(BOOST_NO_IOSTREAM) private: // The underlying IP socket address. union data_union { asio::detail::socket_addr_type base; asio::detail::sockaddr_storage_type storage; asio::detail::sockaddr_in4_type v4; asio::detail::sockaddr_in6_type v6; } data_; }; } // namespace detail } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/ip/detail/impl/endpoint.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IP_DETAIL_ENDPOINT_HPP percona-galera-3-3.8-3390/asio/asio/ip/detail/impl/000077500000000000000000000000001244131713600215035ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ip/detail/impl/endpoint.ipp000066400000000000000000000110771244131713600240430ustar00rootroot00000000000000// // ip/detail/impl/endpoint.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP #define ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ip/detail/endpoint.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { namespace detail { endpoint::endpoint() : data_() { data_.v4.sin_family = AF_INET; data_.v4.sin_port = 0; data_.v4.sin_addr.s_addr = INADDR_ANY; } endpoint::endpoint(int family, unsigned short port_num) : data_() { using namespace std; // For memcpy. if (family == PF_INET) { data_.v4.sin_family = AF_INET; data_.v4.sin_port = asio::detail::socket_ops::host_to_network_short(port_num); data_.v4.sin_addr.s_addr = INADDR_ANY; } else { data_.v6.sin6_family = AF_INET6; data_.v6.sin6_port = asio::detail::socket_ops::host_to_network_short(port_num); data_.v6.sin6_flowinfo = 0; #if defined(__sun) asio::detail::in6_addr_type tmp_addr = {{IN6ADDR_ANY_INIT}}; #else asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; #endif data_.v6.sin6_addr = tmp_addr; data_.v6.sin6_scope_id = 0; } } endpoint::endpoint(const asio::ip::address& addr, unsigned short port_num) : data_() { using namespace std; // For memcpy. if (addr.is_v4()) { data_.v4.sin_family = AF_INET; data_.v4.sin_port = asio::detail::socket_ops::host_to_network_short(port_num); data_.v4.sin_addr.s_addr = asio::detail::socket_ops::host_to_network_long( addr.to_v4().to_ulong()); } else { data_.v6.sin6_family = AF_INET6; data_.v6.sin6_port = asio::detail::socket_ops::host_to_network_short(port_num); data_.v6.sin6_flowinfo = 0; asio::ip::address_v6 v6_addr = addr.to_v6(); asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); memcpy(data_.v6.sin6_addr.s6_addr, bytes.elems, 16); data_.v6.sin6_scope_id = v6_addr.scope_id(); } } void endpoint::resize(std::size_t size) { if (size > sizeof(asio::detail::sockaddr_storage_type)) { asio::error_code ec(asio::error::invalid_argument); asio::detail::throw_error(ec); } } unsigned short endpoint::port() const { if (is_v4()) { return asio::detail::socket_ops::network_to_host_short( data_.v4.sin_port); } else { return asio::detail::socket_ops::network_to_host_short( data_.v6.sin6_port); } } void endpoint::port(unsigned short port_num) { if (is_v4()) { data_.v4.sin_port = asio::detail::socket_ops::host_to_network_short(port_num); } else { data_.v6.sin6_port = asio::detail::socket_ops::host_to_network_short(port_num); } } asio::ip::address endpoint::address() const { using namespace std; // For memcpy. if (is_v4()) { return asio::ip::address_v4( asio::detail::socket_ops::network_to_host_long( data_.v4.sin_addr.s_addr)); } else { asio::ip::address_v6::bytes_type bytes; memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); return asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); } } void endpoint::address(const asio::ip::address& addr) { endpoint tmp_endpoint(addr, port()); data_ = tmp_endpoint.data_; } bool operator==(const endpoint& e1, const endpoint& e2) { return e1.address() == e2.address() && e1.port() == e2.port(); } bool operator<(const endpoint& e1, const endpoint& e2) { if (e1.address() < e2.address()) return true; if (e1.address() != e2.address()) return false; return e1.port() < e2.port(); } #if !defined(BOOST_NO_IOSTREAM) std::string endpoint::to_string(asio::error_code& ec) const { std::string a = address().to_string(ec); if (ec) return std::string(); std::ostringstream tmp_os; tmp_os.imbue(std::locale::classic()); if (is_v4()) tmp_os << a; else tmp_os << '[' << a << ']'; tmp_os << ':' << port(); return tmp_os.str(); } #endif // !defined(BOOST_NO_IOSTREAM) } // namespace detail } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP percona-galera-3-3.8-3390/asio/asio/ip/detail/socket_option.hpp000066400000000000000000000351241244131713600241400ustar00rootroot00000000000000// // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_DETAIL_SOCKET_OPTION_HPP #define ASIO_IP_DETAIL_SOCKET_OPTION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/ip/address.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { namespace detail { namespace socket_option { // Helper template for implementing multicast enable loopback options. template class multicast_enable_loopback { public: #if defined(__sun) || defined(__osf__) typedef unsigned char ipv4_value_type; typedef unsigned char ipv6_value_type; #elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) typedef unsigned char ipv4_value_type; typedef unsigned int ipv6_value_type; #else typedef int ipv4_value_type; typedef int ipv6_value_type; #endif // Default constructor. multicast_enable_loopback() : ipv4_value_(0), ipv6_value_(0) { } // Construct with a specific option value. explicit multicast_enable_loopback(bool v) : ipv4_value_(v ? 1 : 0), ipv6_value_(v ? 1 : 0) { } // Set the value of the boolean. multicast_enable_loopback& operator=(bool v) { ipv4_value_ = v ? 1 : 0; ipv6_value_ = v ? 1 : 0; return *this; } // Get the current value of the boolean. bool value() const { return !!ipv4_value_; } // Convert to bool. operator bool() const { return !!ipv4_value_; } // Test for false. bool operator!() const { return !ipv4_value_; } // Get the level of the socket option. template int level(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Level; return IPv4_Level; } // Get the name of the socket option. template int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the boolean data. template void* data(const Protocol& protocol) { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the address of the boolean data. template const void* data(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the size of the boolean data. template std::size_t size(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return sizeof(ipv6_value_); return sizeof(ipv4_value_); } // Set the size of the boolean data. template void resize(const Protocol& protocol, std::size_t s) { if (protocol.family() == PF_INET6) { if (s != sizeof(ipv6_value_)) { std::length_error ex("multicast_enable_loopback socket option resize"); boost::throw_exception(ex); } ipv4_value_ = ipv6_value_ ? 1 : 0; } else { if (s != sizeof(ipv4_value_)) { std::length_error ex("multicast_enable_loopback socket option resize"); boost::throw_exception(ex); } ipv6_value_ = ipv4_value_ ? 1 : 0; } } private: ipv4_value_type ipv4_value_; ipv6_value_type ipv6_value_; }; // Helper template for implementing unicast hops options. template class unicast_hops { public: // Default constructor. unicast_hops() : value_(0) { } // Construct with a specific option value. explicit unicast_hops(int v) : value_(v) { } // Set the value of the option. unicast_hops& operator=(int v) { value_ = v; return *this; } // Get the current value of the option. int value() const { return value_; } // Get the level of the socket option. template int level(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Level; return IPv4_Level; } // Get the name of the socket option. template int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the data. template int* data(const Protocol&) { return &value_; } // Get the address of the data. template const int* data(const Protocol&) const { return &value_; } // Get the size of the data. template std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the data. template void resize(const Protocol&, std::size_t s) { if (s != sizeof(value_)) { std::length_error ex("unicast hops socket option resize"); boost::throw_exception(ex); } #if defined(__hpux) if (value_ < 0) value_ = value_ & 0xFF; #endif } private: int value_; }; // Helper template for implementing multicast hops options. template class multicast_hops { public: #if defined(BOOST_WINDOWS) && defined(UNDER_CE) typedef int ipv4_value_type; #else typedef unsigned char ipv4_value_type; #endif typedef int ipv6_value_type; // Default constructor. multicast_hops() : ipv4_value_(0), ipv6_value_(0) { } // Construct with a specific option value. explicit multicast_hops(int v) { if (v < 0 || v > 255) { std::out_of_range ex("multicast hops value out of range"); boost::throw_exception(ex); } ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; } // Set the value of the option. multicast_hops& operator=(int v) { if (v < 0 || v > 255) { std::out_of_range ex("multicast hops value out of range"); boost::throw_exception(ex); } ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; return *this; } // Get the current value of the option. int value() const { return ipv6_value_; } // Get the level of the socket option. template int level(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Level; return IPv4_Level; } // Get the name of the socket option. template int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the data. template void* data(const Protocol& protocol) { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the address of the data. template const void* data(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the size of the data. template std::size_t size(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return sizeof(ipv6_value_); return sizeof(ipv4_value_); } // Set the size of the data. template void resize(const Protocol& protocol, std::size_t s) { if (protocol.family() == PF_INET6) { if (s != sizeof(ipv6_value_)) { std::length_error ex("multicast hops socket option resize"); boost::throw_exception(ex); } if (ipv6_value_ < 0) ipv4_value_ = 0; else if (ipv6_value_ > 255) ipv4_value_ = 255; else ipv4_value_ = (ipv4_value_type)ipv6_value_; } else { if (s != sizeof(ipv4_value_)) { std::length_error ex("multicast hops socket option resize"); boost::throw_exception(ex); } ipv6_value_ = ipv4_value_; } } private: ipv4_value_type ipv4_value_; ipv6_value_type ipv6_value_; }; // Helper template for implementing ip_mreq-based options. template class multicast_request { public: // Default constructor. multicast_request() { ipv4_value_.imr_multiaddr.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); ipv4_value_.imr_interface.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; ipv6_value_.ipv6mr_multiaddr = tmp_addr; ipv6_value_.ipv6mr_interface = 0; } // Construct with multicast address only. explicit multicast_request(const asio::ip::address& multicast_address) { if (multicast_address.is_v6()) { ipv4_value_.imr_multiaddr.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); ipv4_value_.imr_interface.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); using namespace std; // For memcpy. asio::ip::address_v6 ipv6_address = multicast_address.to_v6(); asio::ip::address_v6::bytes_type bytes = ipv6_address.to_bytes(); memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16); ipv6_value_.ipv6mr_interface = 0; } else { ipv4_value_.imr_multiaddr.s_addr = asio::detail::socket_ops::host_to_network_long( multicast_address.to_v4().to_ulong()); ipv4_value_.imr_interface.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; ipv6_value_.ipv6mr_multiaddr = tmp_addr; ipv6_value_.ipv6mr_interface = 0; } } // Construct with multicast address and IPv4 address specifying an interface. explicit multicast_request( const asio::ip::address_v4& multicast_address, const asio::ip::address_v4& network_interface = asio::ip::address_v4::any()) { ipv4_value_.imr_multiaddr.s_addr = asio::detail::socket_ops::host_to_network_long( multicast_address.to_ulong()); ipv4_value_.imr_interface.s_addr = asio::detail::socket_ops::host_to_network_long( network_interface.to_ulong()); #if defined(__sun) asio::detail::in6_addr_type tmp_addr = {{IN6ADDR_ANY_INIT}}; #else asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; #endif ipv6_value_.ipv6mr_multiaddr = tmp_addr; ipv6_value_.ipv6mr_interface = 0; } // Construct with multicast address and IPv6 network interface index. explicit multicast_request( const asio::ip::address_v6& multicast_address, unsigned long network_interface = 0) { ipv4_value_.imr_multiaddr.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); ipv4_value_.imr_interface.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); using namespace std; // For memcpy. asio::ip::address_v6::bytes_type bytes = multicast_address.to_bytes(); memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.elems, 16); ipv6_value_.ipv6mr_interface = network_interface; } // Get the level of the socket option. template int level(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Level; return IPv4_Level; } // Get the name of the socket option. template int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the option data. template const void* data(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the size of the option data. template std::size_t size(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return sizeof(ipv6_value_); return sizeof(ipv4_value_); } private: asio::detail::in4_mreq_type ipv4_value_; asio::detail::in6_mreq_type ipv6_value_; }; // Helper template for implementing options that specify a network interface. template class network_interface { public: // Default constructor. network_interface() { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); ipv6_value_ = 0; } // Construct with IPv4 interface. explicit network_interface(const asio::ip::address_v4& ipv4_interface) { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( ipv4_interface.to_ulong()); ipv6_value_ = 0; } // Construct with IPv6 interface. explicit network_interface(unsigned int ipv6_interface) { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( asio::ip::address_v4::any().to_ulong()); ipv6_value_ = ipv6_interface; } // Get the level of the socket option. template int level(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Level; return IPv4_Level; } // Get the name of the socket option. template int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the option data. template const void* data(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the size of the option data. template std::size_t size(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return sizeof(ipv6_value_); return sizeof(ipv4_value_); } private: asio::detail::in4_addr_type ipv4_value_; unsigned int ipv6_value_; }; } // namespace socket_option } // namespace detail } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_DETAIL_SOCKET_OPTION_HPP percona-galera-3-3.8-3390/asio/asio/ip/host_name.hpp000066400000000000000000000017301244131713600217670ustar00rootroot00000000000000// // ip/host_name.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_HOST_NAME_HPP #define ASIO_IP_HOST_NAME_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Get the current host name. ASIO_DECL std::string host_name(); /// Get the current host name. ASIO_DECL std::string host_name(asio::error_code& ec); } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/ip/impl/host_name.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // ASIO_IP_HOST_NAME_HPP percona-galera-3-3.8-3390/asio/asio/ip/icmp.hpp000066400000000000000000000053021244131713600207410ustar00rootroot00000000000000// // ip/icmp.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_ICMP_HPP #define ASIO_IP_ICMP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/socket_types.hpp" #include "asio/basic_raw_socket.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Encapsulates the flags needed for ICMP. /** * The asio::ip::icmp class contains flags necessary for ICMP sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Protocol, InternetProtocol. */ class icmp { public: /// The type of a ICMP endpoint. typedef basic_endpoint endpoint; /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 ICMP protocol. static icmp v4() { return icmp(IPPROTO_ICMP, PF_INET); } /// Construct to represent the IPv6 ICMP protocol. static icmp v6() { return icmp(IPPROTO_ICMPV6, PF_INET6); } /// Obtain an identifier for the type of the protocol. int type() const { return SOCK_RAW; } /// Obtain an identifier for the protocol. int protocol() const { return protocol_; } /// Obtain an identifier for the protocol family. int family() const { return family_; } /// The ICMP socket type. typedef basic_raw_socket socket; /// The ICMP resolver type. typedef basic_resolver resolver; /// Compare two protocols for equality. friend bool operator==(const icmp& p1, const icmp& p2) { return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_; } /// Compare two protocols for inequality. friend bool operator!=(const icmp& p1, const icmp& p2) { return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_; } private: // Construct with a specific family. explicit icmp(int protocol, int family) : protocol_(protocol), family_(family) { } int protocol_; int family_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_ICMP_HPP percona-galera-3-3.8-3390/asio/asio/ip/impl/000077500000000000000000000000001244131713600202415ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ip/impl/address.hpp000066400000000000000000000024121244131713600223760ustar00rootroot00000000000000// // ip/impl/address.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_HPP #define ASIO_IP_IMPL_ADDRESS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if !defined(BOOST_NO_IOSTREAM) #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { template std::basic_ostream& operator<<( std::basic_ostream& os, const address& addr) { asio::error_code ec; std::string s = addr.to_string(ec); if (ec) { if (os.exceptions() & std::basic_ostream::failbit) asio::detail::throw_error(ec); else os.setstate(std::basic_ostream::failbit); } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); return os; } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_IP_IMPL_ADDRESS_HPP percona-galera-3-3.8-3390/asio/asio/ip/impl/address.ipp000066400000000000000000000074711244131713600224110ustar00rootroot00000000000000// // ip/impl/address.ipp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_IPP #define ASIO_IP_IMPL_ADDRESS_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ip/address.hpp" #include "asio/system_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { address::address() : type_(ipv4), ipv4_address_(), ipv6_address_() { } address::address(const asio::ip::address_v4& ipv4_address) : type_(ipv4), ipv4_address_(ipv4_address), ipv6_address_() { } address::address(const asio::ip::address_v6& ipv6_address) : type_(ipv6), ipv4_address_(), ipv6_address_(ipv6_address) { } address::address(const address& other) : type_(other.type_), ipv4_address_(other.ipv4_address_), ipv6_address_(other.ipv6_address_) { } address& address::operator=(const address& other) { type_ = other.type_; ipv4_address_ = other.ipv4_address_; ipv6_address_ = other.ipv6_address_; return *this; } address& address::operator=(const asio::ip::address_v4& ipv4_address) { type_ = ipv4; ipv4_address_ = ipv4_address; ipv6_address_ = asio::ip::address_v6(); return *this; } address& address::operator=(const asio::ip::address_v6& ipv6_address) { type_ = ipv6; ipv4_address_ = asio::ip::address_v4(); ipv6_address_ = ipv6_address; return *this; } asio::ip::address_v4 address::to_v4() const { if (type_ != ipv4) { std::bad_cast ex; boost::throw_exception(ex); } return ipv4_address_; } asio::ip::address_v6 address::to_v6() const { if (type_ != ipv6) { std::bad_cast ex; boost::throw_exception(ex); } return ipv6_address_; } std::string address::to_string() const { if (type_ == ipv6) return ipv6_address_.to_string(); return ipv4_address_.to_string(); } std::string address::to_string(asio::error_code& ec) const { if (type_ == ipv6) return ipv6_address_.to_string(ec); return ipv4_address_.to_string(ec); } address address::from_string(const char* str) { asio::error_code ec; address addr = from_string(str, ec); asio::detail::throw_error(ec); return addr; } address address::from_string(const char* str, asio::error_code& ec) { asio::ip::address_v6 ipv6_address = asio::ip::address_v6::from_string(str, ec); if (!ec) { address tmp; tmp.type_ = ipv6; tmp.ipv6_address_ = ipv6_address; return tmp; } asio::ip::address_v4 ipv4_address = asio::ip::address_v4::from_string(str, ec); if (!ec) { address tmp; tmp.type_ = ipv4; tmp.ipv4_address_ = ipv4_address; return tmp; } return address(); } address address::from_string(const std::string& str) { return from_string(str.c_str()); } address address::from_string(const std::string& str, asio::error_code& ec) { return from_string(str.c_str(), ec); } bool operator==(const address& a1, const address& a2) { if (a1.type_ != a2.type_) return false; if (a1.type_ == address::ipv6) return a1.ipv6_address_ == a2.ipv6_address_; return a1.ipv4_address_ == a2.ipv4_address_; } bool operator<(const address& a1, const address& a2) { if (a1.type_ < a2.type_) return true; if (a1.type_ > a2.type_) return false; if (a1.type_ == address::ipv6) return a1.ipv6_address_ < a2.ipv6_address_; return a1.ipv4_address_ < a2.ipv4_address_; } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_IMPL_ADDRESS_IPP percona-galera-3-3.8-3390/asio/asio/ip/impl/address_v4.hpp000066400000000000000000000024341244131713600230130ustar00rootroot00000000000000// // ip/impl/address_v4.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_V4_HPP #define ASIO_IP_IMPL_ADDRESS_V4_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if !defined(BOOST_NO_IOSTREAM) #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v4& addr) { asio::error_code ec; std::string s = addr.to_string(ec); if (ec) { if (os.exceptions() & std::basic_ostream::failbit) asio::detail::throw_error(ec); else os.setstate(std::basic_ostream::failbit); } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); return os; } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_IP_IMPL_ADDRESS_V4_HPP percona-galera-3-3.8-3390/asio/asio/ip/impl/address_v4.ipp000066400000000000000000000072041244131713600230140ustar00rootroot00000000000000// // ip/impl/address_v4.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_V4_IPP #define ASIO_IP_IMPL_ADDRESS_V4_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/error.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/ip/address_v4.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { address_v4::address_v4(const address_v4::bytes_type& bytes) { #if UCHAR_MAX > 0xFF if (bytes[0] > 0xFF || bytes[1] > 0xFF || bytes[2] > 0xFF || bytes[3] > 0xFF) { std::out_of_range ex("address_v4 from bytes_type"); boost::throw_exception(ex); } #endif // UCHAR_MAX > 0xFF using namespace std; // For memcpy. memcpy(&addr_.s_addr, bytes.elems, 4); } address_v4::address_v4(unsigned long addr) { #if ULONG_MAX > 0xFFFFFFFF if (addr > 0xFFFFFFFF) { std::out_of_range ex("address_v4 from unsigned long"); boost::throw_exception(ex); } #endif // ULONG_MAX > 0xFFFFFFFF addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr); } address_v4::bytes_type address_v4::to_bytes() const { using namespace std; // For memcpy. bytes_type bytes; memcpy(bytes.elems, &addr_.s_addr, 4); return bytes; } unsigned long address_v4::to_ulong() const { return asio::detail::socket_ops::network_to_host_long(addr_.s_addr); } std::string address_v4::to_string() const { asio::error_code ec; std::string addr = to_string(ec); asio::detail::throw_error(ec); return addr; } std::string address_v4::to_string(asio::error_code& ec) const { char addr_str[asio::detail::max_addr_v4_str_len]; const char* addr = asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, asio::detail::max_addr_v4_str_len, 0, ec); if (addr == 0) return std::string(); return addr; } address_v4 address_v4::from_string(const char* str) { asio::error_code ec; address_v4 addr = from_string(str, ec); asio::detail::throw_error(ec); return addr; } address_v4 address_v4::from_string( const char* str, asio::error_code& ec) { address_v4 tmp; if (asio::detail::socket_ops::inet_pton( AF_INET, str, &tmp.addr_, 0, ec) <= 0) return address_v4(); return tmp; } address_v4 address_v4::from_string(const std::string& str) { return from_string(str.c_str()); } address_v4 address_v4::from_string( const std::string& str, asio::error_code& ec) { return from_string(str.c_str(), ec); } bool address_v4::is_class_a() const { return IN_CLASSA(to_ulong()); } bool address_v4::is_class_b() const { return IN_CLASSB(to_ulong()); } bool address_v4::is_class_c() const { return IN_CLASSC(to_ulong()); } bool address_v4::is_multicast() const { return IN_MULTICAST(to_ulong()); } address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) { return address_v4(addr.to_ulong() | (mask.to_ulong() ^ 0xFFFFFFFF)); } address_v4 address_v4::netmask(const address_v4& addr) { if (addr.is_class_a()) return address_v4(0xFF000000); if (addr.is_class_b()) return address_v4(0xFFFF0000); if (addr.is_class_c()) return address_v4(0xFFFFFF00); return address_v4(0xFFFFFFFF); } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_IMPL_ADDRESS_V4_IPP percona-galera-3-3.8-3390/asio/asio/ip/impl/address_v6.hpp000066400000000000000000000024341244131713600230150ustar00rootroot00000000000000// // ip/impl/address_v6.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_V6_HPP #define ASIO_IP_IMPL_ADDRESS_V6_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if !defined(BOOST_NO_IOSTREAM) #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v6& addr) { asio::error_code ec; std::string s = addr.to_string(ec); if (ec) { if (os.exceptions() & std::basic_ostream::failbit) asio::detail::throw_error(ec); else os.setstate(std::basic_ostream::failbit); } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); return os; } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_IP_IMPL_ADDRESS_V6_HPP percona-galera-3-3.8-3390/asio/asio/ip/impl/address_v6.ipp000066400000000000000000000162721244131713600230230ustar00rootroot00000000000000// // ip/impl/address_v6.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_ADDRESS_V6_IPP #define ASIO_IP_IMPL_ADDRESS_V6_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ip/address_v6.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { address_v6::address_v6() : scope_id_(0) { #if defined(__sun) asio::detail::in6_addr_type tmp_addr = {{IN6ADDR_ANY_INIT}}; #else asio::detail::in6_addr_type tmp_addr = IN6ADDR_ANY_INIT; #endif addr_ = tmp_addr; } address_v6::address_v6(const address_v6::bytes_type& bytes, unsigned long scope_id) : scope_id_(scope_id) { #if UCHAR_MAX > 0xFF for (std::size_t i = 0; i < bytes.size(); ++i) { if (bytes[i] > 0xFF) { std::out_of_range ex("address_v6 from bytes_type"); boost::throw_exception(ex); } } #endif // UCHAR_MAX > 0xFF using namespace std; // For memcpy. memcpy(addr_.s6_addr, bytes.elems, 16); } address_v6::address_v6(const address_v6& other) : addr_(other.addr_), scope_id_(other.scope_id_) { } address_v6& address_v6::operator=(const address_v6& other) { addr_ = other.addr_; scope_id_ = other.scope_id_; return *this; } address_v6::bytes_type address_v6::to_bytes() const { using namespace std; // For memcpy. bytes_type bytes; memcpy(bytes.elems, addr_.s6_addr, 16); return bytes; } std::string address_v6::to_string() const { asio::error_code ec; std::string addr = to_string(ec); asio::detail::throw_error(ec); return addr; } std::string address_v6::to_string(asio::error_code& ec) const { char addr_str[asio::detail::max_addr_v6_str_len]; const char* addr = asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, asio::detail::max_addr_v6_str_len, scope_id_, ec); if (addr == 0) return std::string(); return addr; } address_v6 address_v6::from_string(const char* str) { asio::error_code ec; address_v6 addr = from_string(str, ec); asio::detail::throw_error(ec); return addr; } address_v6 address_v6::from_string( const char* str, asio::error_code& ec) { address_v6 tmp; if (asio::detail::socket_ops::inet_pton( AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) return address_v6(); return tmp; } address_v6 address_v6::from_string(const std::string& str) { return from_string(str.c_str()); } address_v6 address_v6::from_string( const std::string& str, asio::error_code& ec) { return from_string(str.c_str(), ec); } address_v4 address_v6::to_v4() const { if (!is_v4_mapped() && !is_v4_compatible()) { std::bad_cast ex; boost::throw_exception(ex); } address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; return address_v4(v4_bytes); } bool address_v6::is_loopback() const { #if defined(__BORLANDC__) return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); #else using namespace asio::detail; return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; #endif } bool address_v6::is_unspecified() const { #if defined(__BORLANDC__) return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); #else using namespace asio::detail; return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; #endif } bool address_v6::is_link_local() const { using namespace asio::detail; return IN6_IS_ADDR_LINKLOCAL(&addr_) != 0; } bool address_v6::is_site_local() const { using namespace asio::detail; return IN6_IS_ADDR_SITELOCAL(&addr_) != 0; } bool address_v6::is_v4_mapped() const { using namespace asio::detail; return IN6_IS_ADDR_V4MAPPED(&addr_) != 0; } bool address_v6::is_v4_compatible() const { using namespace asio::detail; return IN6_IS_ADDR_V4COMPAT(&addr_) != 0; } bool address_v6::is_multicast() const { using namespace asio::detail; return IN6_IS_ADDR_MULTICAST(&addr_) != 0; } bool address_v6::is_multicast_global() const { using namespace asio::detail; return IN6_IS_ADDR_MC_GLOBAL(&addr_) != 0; } bool address_v6::is_multicast_link_local() const { using namespace asio::detail; return IN6_IS_ADDR_MC_LINKLOCAL(&addr_) != 0; } bool address_v6::is_multicast_node_local() const { using namespace asio::detail; return IN6_IS_ADDR_MC_NODELOCAL(&addr_) != 0; } bool address_v6::is_multicast_org_local() const { using namespace asio::detail; return IN6_IS_ADDR_MC_ORGLOCAL(&addr_) != 0; } bool address_v6::is_multicast_site_local() const { using namespace asio::detail; return IN6_IS_ADDR_MC_SITELOCAL(&addr_) != 0; } bool operator==(const address_v6& a1, const address_v6& a2) { using namespace std; // For memcmp. return memcmp(&a1.addr_, &a2.addr_, sizeof(asio::detail::in6_addr_type)) == 0 && a1.scope_id_ == a2.scope_id_; } bool operator<(const address_v6& a1, const address_v6& a2) { using namespace std; // For memcmp. int memcmp_result = memcmp(&a1.addr_, &a2.addr_, sizeof(asio::detail::in6_addr_type)); if (memcmp_result < 0) return true; if (memcmp_result > 0) return false; return a1.scope_id_ < a2.scope_id_; } address_v6 address_v6::loopback() { address_v6 tmp; #if defined(__sun) asio::detail::in6_addr_type tmp_addr = {{IN6ADDR_LOOPBACK_INIT}}; #else asio::detail::in6_addr_type tmp_addr = IN6ADDR_LOOPBACK_INIT; #endif tmp.addr_ = tmp_addr; return tmp; } address_v6 address_v6::v4_mapped(const address_v4& addr) { address_v4::bytes_type v4_bytes = addr.to_bytes(); bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; return address_v6(v6_bytes); } address_v6 address_v6::v4_compatible(const address_v4& addr) { address_v4::bytes_type v4_bytes = addr.to_bytes(); bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; return address_v6(v6_bytes); } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_IMPL_ADDRESS_V6_IPP percona-galera-3-3.8-3390/asio/asio/ip/impl/basic_endpoint.hpp000066400000000000000000000026651244131713600237440ustar00rootroot00000000000000// // ip/impl/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_BASIC_ENDPOINT_HPP #define ASIO_IP_IMPL_BASIC_ENDPOINT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #if !defined(BOOST_NO_IOSTREAM) #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { template std::basic_ostream& operator<<( std::basic_ostream& os, const basic_endpoint& endpoint) { asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port()); asio::error_code ec; std::string s = tmp_ep.to_string(ec); if (ec) { if (os.exceptions() & std::basic_ostream::failbit) asio::detail::throw_error(ec); else os.setstate(std::basic_ostream::failbit); } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); return os; } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_IP_IMPL_BASIC_ENDPOINT_HPP percona-galera-3-3.8-3390/asio/asio/ip/impl/host_name.ipp000066400000000000000000000024101244131713600227250ustar00rootroot00000000000000// // ip/impl/host_name.ipp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_IMPL_HOST_NAME_IPP #define ASIO_IP_IMPL_HOST_NAME_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/winsock_init.hpp" #include "asio/ip/host_name.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { std::string host_name() { char name[1024]; asio::error_code ec; if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) { asio::detail::throw_error(ec); return std::string(); } return std::string(name); } std::string host_name(asio::error_code& ec) { char name[1024]; if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) return std::string(); return std::string(name); } } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_IMPL_HOST_NAME_IPP percona-galera-3-3.8-3390/asio/asio/ip/multicast.hpp000066400000000000000000000113511244131713600220170ustar00rootroot00000000000000// // ip/multicast.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_MULTICAST_HPP #define ASIO_IP_MULTICAST_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/ip/detail/socket_option.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { namespace multicast { /// Socket option to join a multicast group on a specified interface. /** * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option. * * @par Examples * Setting the option to join a multicast group: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::address multicast_address = * asio::ip::address::from_string("225.0.0.1"); * asio::ip::multicast::join_group option(multicast_address); * socket.set_option(option); * @endcode * * @par Concepts: * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined join_group; #else typedef asio::ip::detail::socket_option::multicast_request< IPPROTO_IP, IP_ADD_MEMBERSHIP, IPPROTO_IPV6, IPV6_JOIN_GROUP> join_group; #endif /// Socket option to leave a multicast group on a specified interface. /** * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option. * * @par Examples * Setting the option to leave a multicast group: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::address multicast_address = * asio::ip::address::from_string("225.0.0.1"); * asio::ip::multicast::leave_group option(multicast_address); * socket.set_option(option); * @endcode * * @par Concepts: * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined leave_group; #else typedef asio::ip::detail::socket_option::multicast_request< IPPROTO_IP, IP_DROP_MEMBERSHIP, IPPROTO_IPV6, IPV6_LEAVE_GROUP> leave_group; #endif /// Socket option for local interface to use for outgoing multicast packets. /** * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::address_v4 local_interface = * asio::ip::address_v4::from_string("1.2.3.4"); * asio::ip::multicast::outbound_interface option(local_interface); * socket.set_option(option); * @endcode * * @par Concepts: * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined outbound_interface; #else typedef asio::ip::detail::socket_option::network_interface< IPPROTO_IP, IP_MULTICAST_IF, IPPROTO_IPV6, IPV6_MULTICAST_IF> outbound_interface; #endif /// Socket option for time-to-live associated with outgoing multicast packets. /** * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::multicast::hops option(4); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::multicast::hops option; * socket.get_option(option); * int ttl = option.value(); * @endcode * * @par Concepts: * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined hops; #else typedef asio::ip::detail::socket_option::multicast_hops< IPPROTO_IP, IP_MULTICAST_TTL, IPPROTO_IPV6, IPV6_MULTICAST_HOPS> hops; #endif /// Socket option determining whether outgoing multicast packets will be /// received on the same socket if it is a member of the multicast group. /** * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::multicast::enable_loopback option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::multicast::enable_loopback option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined enable_loopback; #else typedef asio::ip::detail::socket_option::multicast_enable_loopback< IPPROTO_IP, IP_MULTICAST_LOOP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP> enable_loopback; #endif } // namespace multicast } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_MULTICAST_HPP percona-galera-3-3.8-3390/asio/asio/ip/resolver_query_base.hpp000066400000000000000000000103221244131713600240670ustar00rootroot00000000000000// // ip/resolver_query_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_RESOLVER_QUERY_BASE_HPP #define ASIO_IP_RESOLVER_QUERY_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// The resolver_query_base class is used as a base for the /// basic_resolver_query class templates to provide a common place to define /// the flag constants. class resolver_query_base { public: #if defined(GENERATING_DOCUMENTATION) /// A bitmask type (C++ Std [lib.bitmask.types]). typedef unspecified flags; /// Determine the canonical name of the host specified in the query. static const flags canonical_name = implementation_defined; /// Indicate that returned endpoint is intended for use as a locally bound /// socket endpoint. static const flags passive = implementation_defined; /// Host name should be treated as a numeric string defining an IPv4 or IPv6 /// address and no name resolution should be attempted. static const flags numeric_host = implementation_defined; /// Service name should be treated as a numeric string defining a port number /// and no name resolution should be attempted. static const flags numeric_service = implementation_defined; /// If the query protocol family is specified as IPv6, return IPv4-mapped /// IPv6 addresses on finding no IPv6 addresses. static const flags v4_mapped = implementation_defined; /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. static const flags all_matching = implementation_defined; /// Only return IPv4 addresses if a non-loopback IPv4 address is configured /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address /// is configured for the system. static const flags address_configured = implementation_defined; #else enum flags { canonical_name = AI_CANONNAME, passive = AI_PASSIVE, numeric_host = AI_NUMERICHOST, # if defined(AI_NUMERICSERV) numeric_service = AI_NUMERICSERV, # else numeric_service = 0, # endif // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but // does not implement them. Therefore they are specifically excluded here. # if defined(AI_V4MAPPED) && !defined(__QNXNTO__) v4_mapped = AI_V4MAPPED, # else v4_mapped = 0, # endif # if defined(AI_ALL) && !defined(__QNXNTO__) all_matching = AI_ALL, # else all_matching = 0, # endif # if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) address_configured = AI_ADDRCONFIG # else address_configured = 0 # endif }; // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. friend flags operator&(flags x, flags y) { return static_cast( static_cast(x) & static_cast(y)); } friend flags operator|(flags x, flags y) { return static_cast( static_cast(x) | static_cast(y)); } friend flags operator^(flags x, flags y) { return static_cast( static_cast(x) ^ static_cast(y)); } friend flags operator~(flags x) { return static_cast(static_cast(~x)); } friend flags& operator&=(flags& x, flags y) { x = x & y; return x; } friend flags& operator|=(flags& x, flags y) { x = x | y; return x; } friend flags& operator^=(flags& x, flags y) { x = x ^ y; return x; } #endif protected: /// Protected destructor to prevent deletion through this type. ~resolver_query_base() { } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) private: // Workaround to enable the empty base optimisation with Borland C++. char dummy_; #endif }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_RESOLVER_QUERY_BASE_HPP percona-galera-3-3.8-3390/asio/asio/ip/resolver_service.hpp000066400000000000000000000074421244131713600234010ustar00rootroot00000000000000// // ip/resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_RESOLVER_SERVICE_HPP #define ASIO_IP_RESOLVER_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/error_code.hpp" #include "asio/detail/resolver_service.hpp" #include "asio/io_service.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Default service implementation for a resolver. template class resolver_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base< resolver_service > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The protocol type. typedef InternetProtocol protocol_type; /// The endpoint type. typedef typename InternetProtocol::endpoint endpoint_type; /// The query type. typedef basic_resolver_query query_type; /// The iterator type. typedef basic_resolver_iterator iterator_type; private: // The type of the platform-specific implementation. typedef asio::detail::resolver_service service_impl_type; public: /// The type of a resolver implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// Construct a new resolver service for the specified io_service. explicit resolver_service(asio::io_service& io_service) : asio::detail::service_base< resolver_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new resolver implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a resolver implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Cancel pending asynchronous operations. void cancel(implementation_type& impl) { service_impl_.cancel(impl); } /// Resolve a query to a list of entries. iterator_type resolve(implementation_type& impl, const query_type& query, asio::error_code& ec) { return service_impl_.resolve(impl, query, ec); } /// Asynchronously resolve a query to a list of entries. template void async_resolve(implementation_type& impl, const query_type& query, Handler handler) { service_impl_.async_resolve(impl, query, handler); } /// Resolve an endpoint to a list of entries. iterator_type resolve(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { return service_impl_.resolve(impl, endpoint, ec); } /// Asynchronously resolve an endpoint to a list of entries. template void async_resolve(implementation_type& impl, const endpoint_type& endpoint, ResolveHandler handler) { return service_impl_.async_resolve(impl, endpoint, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_RESOLVER_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/ip/tcp.hpp000066400000000000000000000072551244131713600206100ustar00rootroot00000000000000// // ip/tcp.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_TCP_HPP #define ASIO_IP_TCP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_stream_socket.hpp" #include "asio/detail/socket_option.hpp" #include "asio/detail/socket_types.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Encapsulates the flags needed for TCP. /** * The asio::ip::tcp class contains flags necessary for TCP sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Protocol, InternetProtocol. */ class tcp { public: /// The type of a TCP endpoint. typedef basic_endpoint endpoint; /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 TCP protocol. static tcp v4() { return tcp(PF_INET); } /// Construct to represent the IPv6 TCP protocol. static tcp v6() { return tcp(PF_INET6); } /// Obtain an identifier for the type of the protocol. int type() const { return SOCK_STREAM; } /// Obtain an identifier for the protocol. int protocol() const { return IPPROTO_TCP; } /// Obtain an identifier for the protocol family. int family() const { return family_; } /// The TCP socket type. typedef basic_stream_socket socket; /// The TCP acceptor type. typedef basic_socket_acceptor acceptor; /// The TCP resolver type. typedef basic_resolver resolver; #if !defined(BOOST_NO_IOSTREAM) /// The TCP iostream type. typedef basic_socket_iostream iostream; #endif // !defined(BOOST_NO_IOSTREAM) /// Socket option for disabling the Nagle algorithm. /** * Implements the IPPROTO_TCP/TCP_NODELAY socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::no_delay option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::no_delay option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined no_delay; #else typedef asio::detail::socket_option::boolean< IPPROTO_TCP, TCP_NODELAY> no_delay; #endif /// Compare two protocols for equality. friend bool operator==(const tcp& p1, const tcp& p2) { return p1.family_ == p2.family_; } /// Compare two protocols for inequality. friend bool operator!=(const tcp& p1, const tcp& p2) { return p1.family_ != p2.family_; } private: // Construct with a specific family. explicit tcp(int family) : family_(family) { } int family_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_TCP_HPP percona-galera-3-3.8-3390/asio/asio/ip/udp.hpp000066400000000000000000000050341244131713600206030ustar00rootroot00000000000000// // ip/udp.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_UDP_HPP #define ASIO_IP_UDP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_datagram_socket.hpp" #include "asio/detail/socket_types.hpp" #include "asio/ip/basic_endpoint.hpp" #include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Encapsulates the flags needed for UDP. /** * The asio::ip::udp class contains flags necessary for UDP sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Protocol, InternetProtocol. */ class udp { public: /// The type of a UDP endpoint. typedef basic_endpoint endpoint; /// (Deprecated: use resolver::query.) The type of a resolver query. typedef basic_resolver_query resolver_query; /// (Deprecated: use resolver::iterator.) The type of a resolver iterator. typedef basic_resolver_iterator resolver_iterator; /// Construct to represent the IPv4 UDP protocol. static udp v4() { return udp(PF_INET); } /// Construct to represent the IPv6 UDP protocol. static udp v6() { return udp(PF_INET6); } /// Obtain an identifier for the type of the protocol. int type() const { return SOCK_DGRAM; } /// Obtain an identifier for the protocol. int protocol() const { return IPPROTO_UDP; } /// Obtain an identifier for the protocol family. int family() const { return family_; } /// The UDP socket type. typedef basic_datagram_socket socket; /// The UDP resolver type. typedef basic_resolver resolver; /// Compare two protocols for equality. friend bool operator==(const udp& p1, const udp& p2) { return p1.family_ == p2.family_; } /// Compare two protocols for inequality. friend bool operator!=(const udp& p1, const udp& p2) { return p1.family_ != p2.family_; } private: // Construct with a specific family. explicit udp(int family) : family_(family) { } int family_; }; } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_UDP_HPP percona-galera-3-3.8-3390/asio/asio/ip/unicast.hpp000066400000000000000000000030651244131713600214630ustar00rootroot00000000000000// // ip/unicast.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_UNICAST_HPP #define ASIO_IP_UNICAST_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/ip/detail/socket_option.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { namespace unicast { /// Socket option for time-to-live associated with outgoing unicast packets. /** * Implements the IPPROTO_IP/IP_UNICAST_TTL socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::unicast::hops option(4); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::ip::unicast::hops option; * socket.get_option(option); * int ttl = option.value(); * @endcode * * @par Concepts: * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined hops; #else typedef asio::ip::detail::socket_option::unicast_hops< IPPROTO_IP, IP_TTL, IPPROTO_IPV6, IPV6_UNICAST_HOPS> hops; #endif } // namespace unicast } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_UNICAST_HPP percona-galera-3-3.8-3390/asio/asio/ip/v6_only.hpp000066400000000000000000000032121244131713600214030ustar00rootroot00000000000000// // ip/v6_only.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IP_V6_ONLY_HPP #define ASIO_IP_V6_ONLY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/socket_option.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ip { /// Socket option for determining whether an IPv6 socket supports IPv6 /// communication only. /** * Implements the IPPROTO_IPV6/IP_V6ONLY socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::v6_only option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::v6_only option; * socket.get_option(option); * bool v6_only = option.value(); * @endcode * * @par Concepts: * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined v6_only; #elif defined(IPV6_V6ONLY) typedef asio::detail::socket_option::boolean< IPPROTO_IPV6, IPV6_V6ONLY> v6_only; #else typedef asio::detail::socket_option::boolean< asio::detail::custom_socket_option_level, asio::detail::always_fail_option> v6_only; #endif } // namespace ip } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IP_V6_ONLY_HPP percona-galera-3-3.8-3390/asio/asio/is_read_buffered.hpp000066400000000000000000000030221244131713600226460ustar00rootroot00000000000000// // is_read_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IS_READ_BUFFERED_HPP #define ASIO_IS_READ_BUFFERED_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/buffered_read_stream_fwd.hpp" #include "asio/buffered_stream_fwd.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template char is_read_buffered_helper(buffered_stream* s); template char is_read_buffered_helper(buffered_read_stream* s); struct is_read_buffered_big_type { char data[10]; }; is_read_buffered_big_type is_read_buffered_helper(...); } // namespace detail /// The is_read_buffered class is a traits class that may be used to determine /// whether a stream type supports buffering of read data. template class is_read_buffered { public: #if defined(GENERATING_DOCUMENTATION) /// The value member is true only if the Stream type supports buffering of /// read data. static const bool value; #else BOOST_STATIC_CONSTANT(bool, value = sizeof(detail::is_read_buffered_helper((Stream*)0)) == 1); #endif }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IS_READ_BUFFERED_HPP percona-galera-3-3.8-3390/asio/asio/is_write_buffered.hpp000066400000000000000000000030471244131713600230740ustar00rootroot00000000000000// // is_write_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_IS_WRITE_BUFFERED_HPP #define ASIO_IS_WRITE_BUFFERED_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/buffered_stream_fwd.hpp" #include "asio/buffered_write_stream_fwd.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template char is_write_buffered_helper(buffered_stream* s); template char is_write_buffered_helper(buffered_write_stream* s); struct is_write_buffered_big_type { char data[10]; }; is_write_buffered_big_type is_write_buffered_helper(...); } // namespace detail /// The is_write_buffered class is a traits class that may be used to determine /// whether a stream type supports buffering of written data. template class is_write_buffered { public: #if defined(GENERATING_DOCUMENTATION) /// The value member is true only if the Stream type supports buffering of /// written data. static const bool value; #else BOOST_STATIC_CONSTANT(bool, value = sizeof(detail::is_write_buffered_helper((Stream*)0)) == 1); #endif }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IS_WRITE_BUFFERED_HPP percona-galera-3-3.8-3390/asio/asio/local/000077500000000000000000000000001244131713600177625ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/local/basic_endpoint.hpp000066400000000000000000000120611244131713600234540ustar00rootroot00000000000000// // local/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // 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) // #ifndef ASIO_LOCAL_BASIC_ENDPOINT_HPP #define ASIO_LOCAL_BASIC_ENDPOINT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include "asio/local/detail/endpoint.hpp" #if !defined(BOOST_NO_IOSTREAM) # include #endif // !defined(BOOST_NO_IOSTREAM) #include "asio/detail/push_options.hpp" namespace asio { namespace local { /// Describes an endpoint for a UNIX socket. /** * The asio::local::basic_endpoint class template describes an endpoint * that may be associated with a particular UNIX socket. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * Endpoint. */ template class basic_endpoint { public: /// The protocol type associated with the endpoint. typedef Protocol protocol_type; /// The type of the endpoint structure. This type is dependent on the /// underlying implementation of the socket layer. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined data_type; #else typedef asio::detail::socket_addr_type data_type; #endif /// Default constructor. basic_endpoint() { } /// Construct an endpoint using the specified path name. basic_endpoint(const char* path) : impl_(path) { } /// Construct an endpoint using the specified path name. basic_endpoint(const std::string& path) : impl_(path) { } /// Copy constructor. basic_endpoint(const basic_endpoint& other) : impl_(other.impl_) { } /// Assign from another endpoint. basic_endpoint& operator=(const basic_endpoint& other) { impl_ = other.impl_; return *this; } /// The protocol associated with the endpoint. protocol_type protocol() const { return protocol_type(); } /// Get the underlying endpoint in the native type. data_type* data() { return impl_.data(); } /// Get the underlying endpoint in the native type. const data_type* data() const { return impl_.data(); } /// Get the underlying size of the endpoint in the native type. std::size_t size() const { return impl_.size(); } /// Set the underlying size of the endpoint in the native type. void resize(std::size_t size) { impl_.resize(size); } /// Get the capacity of the endpoint in the native type. std::size_t capacity() const { return impl_.capacity(); } /// Get the path associated with the endpoint. std::string path() const { return impl_.path(); } /// Set the path associated with the endpoint. void path(const char* p) { impl_.path(p); } /// Set the path associated with the endpoint. void path(const std::string& p) { impl_.path(p); } /// Compare two endpoints for equality. friend bool operator==(const basic_endpoint& e1, const basic_endpoint& e2) { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint& e1, const basic_endpoint& e2) { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint& e1, const basic_endpoint& e2) { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint& e1, const basic_endpoint& e2) { return !(e1 < e2); } private: // The underlying UNIX domain endpoint. asio::local::detail::endpoint impl_; }; /// Output an endpoint as a string. /** * Used to output a human-readable string for a specified endpoint. * * @param os The output stream to which the string will be written. * * @param endpoint The endpoint to be written. * * @return The output stream. * * @relates asio::local::basic_endpoint */ template std::basic_ostream& operator<<( std::basic_ostream& os, const basic_endpoint& endpoint) { os << endpoint.path(); return os; } } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_LOCAL_BASIC_ENDPOINT_HPP percona-galera-3-3.8-3390/asio/asio/local/connect_pair.hpp000066400000000000000000000060651244131713600231460ustar00rootroot00000000000000// // local/connect_pair.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_LOCAL_CONNECT_PAIR_HPP #define ASIO_LOCAL_CONNECT_PAIR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_socket.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/local/basic_endpoint.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace local { /// Create a pair of connected sockets. template void connect_pair( basic_socket& socket1, basic_socket& socket2); /// Create a pair of connected sockets. template asio::error_code connect_pair( basic_socket& socket1, basic_socket& socket2, asio::error_code& ec); template inline void connect_pair( basic_socket& socket1, basic_socket& socket2) { asio::error_code ec; connect_pair(socket1, socket2, ec); asio::detail::throw_error(ec); } template inline asio::error_code connect_pair( basic_socket& socket1, basic_socket& socket2, asio::error_code& ec) { // Check that this function is only being used with a UNIX domain socket. asio::local::basic_endpoint* tmp = static_cast(0); (void)tmp; Protocol protocol; asio::detail::socket_type sv[2]; if (asio::detail::socket_ops::socketpair(protocol.family(), protocol.type(), protocol.protocol(), sv, ec) == asio::detail::socket_error_retval) return ec; if (socket1.assign(protocol, sv[0], ec)) { asio::error_code temp_ec; asio::detail::socket_ops::state_type state[2] = { 0, 0 }; asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); return ec; } if (socket2.assign(protocol, sv[1], ec)) { asio::error_code temp_ec; socket1.close(temp_ec); asio::detail::socket_ops::state_type state = 0; asio::detail::socket_ops::close(sv[1], state, true, temp_ec); return ec; } return ec; } } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_LOCAL_CONNECT_PAIR_HPP percona-galera-3-3.8-3390/asio/asio/local/datagram_protocol.hpp000066400000000000000000000035261244131713600242020ustar00rootroot00000000000000// // local/datagram_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP #define ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_datagram_socket.hpp" #include "asio/detail/socket_types.hpp" #include "asio/local/basic_endpoint.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace local { /// Encapsulates the flags needed for datagram-oriented UNIX sockets. /** * The asio::local::datagram_protocol class contains flags necessary for * datagram-oriented UNIX domain sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Protocol. */ class datagram_protocol { public: /// Obtain an identifier for the type of the protocol. int type() const { return SOCK_DGRAM; } /// Obtain an identifier for the protocol. int protocol() const { return 0; } /// Obtain an identifier for the protocol family. int family() const { return AF_UNIX; } /// The type of a UNIX domain endpoint. typedef basic_endpoint endpoint; /// The UNIX domain socket type. typedef basic_datagram_socket socket; }; } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP percona-galera-3-3.8-3390/asio/asio/local/detail/000077500000000000000000000000001244131713600212245ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/local/detail/endpoint.hpp000066400000000000000000000064151244131713600235630ustar00rootroot00000000000000// // local/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // 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) // #ifndef ASIO_LOCAL_DETAIL_ENDPOINT_HPP #define ASIO_LOCAL_DETAIL_ENDPOINT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) #include #include #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace local { namespace detail { // Helper class for implementing a UNIX domain endpoint. class endpoint { public: // Default constructor. ASIO_DECL endpoint(); // Construct an endpoint using the specified path name. ASIO_DECL endpoint(const char* path); // Construct an endpoint using the specified path name. ASIO_DECL endpoint(const std::string& path); // Copy constructor. endpoint(const endpoint& other) : data_(other.data_), path_length_(other.path_length_) { } // Assign from another endpoint. endpoint& operator=(const endpoint& other) { data_ = other.data_; path_length_ = other.path_length_; return *this; } // Get the underlying endpoint in the native type. asio::detail::socket_addr_type* data() { return &data_.base; } // Get the underlying endpoint in the native type. const asio::detail::socket_addr_type* data() const { return &data_.base; } // Get the underlying size of the endpoint in the native type. std::size_t size() const { return path_length_ + offsetof(asio::detail::sockaddr_un_type, sun_path); } // Set the underlying size of the endpoint in the native type. ASIO_DECL void resize(std::size_t size); // Get the capacity of the endpoint in the native type. std::size_t capacity() const { return sizeof(asio::detail::sockaddr_un_type); } // Get the path associated with the endpoint. ASIO_DECL std::string path() const; // Set the path associated with the endpoint. ASIO_DECL void path(const char* p); // Set the path associated with the endpoint. ASIO_DECL void path(const std::string& p); // Compare two endpoints for equality. ASIO_DECL friend bool operator==( const endpoint& e1, const endpoint& e2); // Compare endpoints for ordering. ASIO_DECL friend bool operator<( const endpoint& e1, const endpoint& e2); private: // The underlying UNIX socket address. union data_union { asio::detail::socket_addr_type base; asio::detail::sockaddr_un_type local; } data_; // The length of the path associated with the endpoint. std::size_t path_length_; // Initialise with a specified path. ASIO_DECL void init(const char* path, std::size_t path_length); }; } // namespace detail } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/local/detail/impl/endpoint.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_LOCAL_SOCKETS) #endif // ASIO_LOCAL_DETAIL_ENDPOINT_HPP percona-galera-3-3.8-3390/asio/asio/local/detail/impl/000077500000000000000000000000001244131713600221655ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/local/detail/impl/endpoint.ipp000066400000000000000000000057651244131713600245340ustar00rootroot00000000000000// // local/detail/impl/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Derived from a public domain implementation written by Daniel Casimiro. // // 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) // #ifndef ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP #define ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) #include #include "asio/detail/socket_ops.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/local/detail/endpoint.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace local { namespace detail { endpoint::endpoint() { init("", 0); } endpoint::endpoint(const char* path) { using namespace std; // For strlen. init(path, strlen(path)); } endpoint::endpoint(const std::string& path) { init(path.data(), path.length()); } void endpoint::resize(std::size_t size) { if (size > sizeof(asio::detail::sockaddr_un_type)) { asio::error_code ec(asio::error::invalid_argument); asio::detail::throw_error(ec); } else if (size == 0) { path_length_ = 0; } else { path_length_ = size - offsetof(asio::detail::sockaddr_un_type, sun_path); // The path returned by the operating system may be NUL-terminated. if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) --path_length_; } } std::string endpoint::path() const { return std::string(data_.local.sun_path, path_length_); } void endpoint::path(const char* p) { using namespace std; // For strlen. init(p, strlen(p)); } void endpoint::path(const std::string& p) { init(p.data(), p.length()); } bool operator==(const endpoint& e1, const endpoint& e2) { return e1.path() == e2.path(); } bool operator<(const endpoint& e1, const endpoint& e2) { return e1.path() < e2.path(); } void endpoint::init(const char* path, std::size_t path_length) { if (path_length > sizeof(data_.local.sun_path) - 1) { // The buffer is not large enough to store this address. asio::error_code ec(asio::error::name_too_long); asio::detail::throw_error(ec); } using namespace std; // For memcpy. data_.local = asio::detail::sockaddr_un_type(); data_.local.sun_family = AF_UNIX; memcpy(data_.local.sun_path, path, path_length); path_length_ = path_length; // NUL-terminate normal path names. Names that start with a NUL are in the // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. if (path_length > 0 && data_.local.sun_path[0] == 0) data_.local.sun_path[path_length] = 0; } } // namespace detail } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_LOCAL_SOCKETS) #endif // ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP percona-galera-3-3.8-3390/asio/asio/local/stream_protocol.hpp000066400000000000000000000042311244131713600237070ustar00rootroot00000000000000// // local/stream_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_LOCAL_STREAM_PROTOCOL_HPP #define ASIO_LOCAL_STREAM_PROTOCOL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_stream_socket.hpp" #include "asio/detail/socket_types.hpp" #include "asio/local/basic_endpoint.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace local { /// Encapsulates the flags needed for stream-oriented UNIX sockets. /** * The asio::local::stream_protocol class contains flags necessary for * stream-oriented UNIX domain sockets. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Protocol. */ class stream_protocol { public: /// Obtain an identifier for the type of the protocol. int type() const { return SOCK_STREAM; } /// Obtain an identifier for the protocol. int protocol() const { return 0; } /// Obtain an identifier for the protocol family. int family() const { return AF_UNIX; } /// The type of a UNIX domain endpoint. typedef basic_endpoint endpoint; /// The UNIX domain socket type. typedef basic_stream_socket socket; /// The UNIX domain acceptor type. typedef basic_socket_acceptor acceptor; #if !defined(BOOST_NO_IOSTREAM) /// The UNIX domain iostream type. typedef basic_socket_iostream iostream; #endif // !defined(BOOST_NO_IOSTREAM) }; } // namespace local } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_LOCAL_STREAM_PROTOCOL_HPP percona-galera-3-3.8-3390/asio/asio/placeholders.hpp000066400000000000000000000047051244131713600220540ustar00rootroot00000000000000// // placeholders.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_PLACEHOLDERS_HPP #define ASIO_PLACEHOLDERS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/push_options.hpp" namespace asio { namespace placeholders { #if defined(GENERATING_DOCUMENTATION) /// An argument placeholder, for use with boost::bind(), that corresponds to /// the error argument of a handler for any of the asynchronous functions. unspecified error; /// An argument placeholder, for use with boost::bind(), that corresponds to /// the bytes_transferred argument of a handler for asynchronous functions such /// as asio::basic_stream_socket::async_write_some or /// asio::async_write. unspecified bytes_transferred; /// An argument placeholder, for use with boost::bind(), that corresponds to /// the iterator argument of a handler for asynchronous functions such as /// asio::basic_resolver::resolve. unspecified iterator; #elif defined(__BORLANDC__) || defined(__GNUC__) inline boost::arg<1> error() { return boost::arg<1>(); } inline boost::arg<2> bytes_transferred() { return boost::arg<2>(); } inline boost::arg<2> iterator() { return boost::arg<2>(); } #else namespace detail { template struct placeholder { static boost::arg& get() { static boost::arg result; return result; } }; } #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) static boost::arg<1>& error = asio::placeholders::detail::placeholder<1>::get(); static boost::arg<2>& bytes_transferred = asio::placeholders::detail::placeholder<2>::get(); static boost::arg<2>& iterator = asio::placeholders::detail::placeholder<2>::get(); #else namespace { boost::arg<1>& error = asio::placeholders::detail::placeholder<1>::get(); boost::arg<2>& bytes_transferred = asio::placeholders::detail::placeholder<2>::get(); boost::arg<2>& iterator = asio::placeholders::detail::placeholder<2>::get(); } // namespace #endif #endif } // namespace placeholders } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_PLACEHOLDERS_HPP percona-galera-3-3.8-3390/asio/asio/posix/000077500000000000000000000000001244131713600200325ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/posix/basic_descriptor.hpp000066400000000000000000000215371244131713600240720ustar00rootroot00000000000000// // posix/basic_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_POSIX_BASIC_DESCRIPTOR_HPP #define ASIO_POSIX_BASIC_DESCRIPTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_io_object.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/posix/descriptor_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace posix { /// Provides POSIX descriptor functionality. /** * The posix::basic_descriptor class template provides the ability to wrap a * POSIX descriptor. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_descriptor : public basic_io_object, public descriptor_base { public: /// The native representation of a descriptor. typedef typename DescriptorService::native_type native_type; /// A basic_descriptor is always the lowest layer. typedef basic_descriptor lowest_layer_type; /// Construct a basic_descriptor without opening it. /** * This constructor creates a descriptor without opening it. * * @param io_service The io_service object that the descriptor will use to * dispatch handlers for any asynchronous operations performed on the * descriptor. */ explicit basic_descriptor(asio::io_service& io_service) : basic_io_object(io_service) { } /// Construct a basic_descriptor on an existing native descriptor. /** * This constructor creates a descriptor object to hold an existing native * descriptor. * * @param io_service The io_service object that the descriptor will use to * dispatch handlers for any asynchronous operations performed on the * descriptor. * * @param native_descriptor A native descriptor. * * @throws asio::system_error Thrown on failure. */ basic_descriptor(asio::io_service& io_service, const native_type& native_descriptor) : basic_io_object(io_service) { asio::error_code ec; this->service.assign(this->implementation, native_descriptor, ec); asio::detail::throw_error(ec); } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * layers. Since a basic_descriptor cannot contain any further layers, it * simply returns a reference to itself. * * @return A reference to the lowest layer in the stack of layers. Ownership * is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return *this; } /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of * layers. Since a basic_descriptor cannot contain any further layers, it * simply returns a reference to itself. * * @return A const reference to the lowest layer in the stack of layers. * Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return *this; } /// Assign an existing native descriptor to the descriptor. /* * This function opens the descriptor to hold an existing native descriptor. * * @param native_descriptor A native descriptor. * * @throws asio::system_error Thrown on failure. */ void assign(const native_type& native_descriptor) { asio::error_code ec; this->service.assign(this->implementation, native_descriptor, ec); asio::detail::throw_error(ec); } /// Assign an existing native descriptor to the descriptor. /* * This function opens the descriptor to hold an existing native descriptor. * * @param native_descriptor A native descriptor. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code assign(const native_type& native_descriptor, asio::error_code& ec) { return this->service.assign(this->implementation, native_descriptor, ec); } /// Determine whether the descriptor is open. bool is_open() const { return this->service.is_open(this->implementation); } /// Close the descriptor. /** * This function is used to close the descriptor. Any asynchronous read or * write operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void close() { asio::error_code ec; this->service.close(this->implementation, ec); asio::detail::throw_error(ec); } /// Close the descriptor. /** * This function is used to close the descriptor. Any asynchronous read or * write operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code close(asio::error_code& ec) { return this->service.close(this->implementation, ec); } /// Get the native descriptor representation. /** * This function may be used to obtain the underlying representation of the * descriptor. This is intended to allow access to native descriptor * functionality that is not otherwise provided. */ native_type native() { return this->service.native(this->implementation); } /// Cancel all asynchronous operations associated with the descriptor. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void cancel() { asio::error_code ec; this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the descriptor. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } /// Perform an IO control command on the descriptor. /** * This function is used to execute an IO control command on the descriptor. * * @param command The IO control command to be performed on the descriptor. * * @throws asio::system_error Thrown on failure. * * @sa IoControlCommand @n * asio::posix::descriptor_base::bytes_readable @n * asio::posix::descriptor_base::non_blocking_io * * @par Example * Getting the number of bytes ready to read: * @code * asio::posix::stream_descriptor descriptor(io_service); * ... * asio::posix::stream_descriptor::bytes_readable command; * descriptor.io_control(command); * std::size_t bytes_readable = command.get(); * @endcode */ template void io_control(IoControlCommand& command) { asio::error_code ec; this->service.io_control(this->implementation, command, ec); asio::detail::throw_error(ec); } /// Perform an IO control command on the descriptor. /** * This function is used to execute an IO control command on the descriptor. * * @param command The IO control command to be performed on the descriptor. * * @param ec Set to indicate what error occurred, if any. * * @sa IoControlCommand @n * asio::posix::descriptor_base::bytes_readable @n * asio::posix::descriptor_base::non_blocking_io * * @par Example * Getting the number of bytes ready to read: * @code * asio::posix::stream_descriptor descriptor(io_service); * ... * asio::posix::stream_descriptor::bytes_readable command; * asio::error_code ec; * descriptor.io_control(command, ec); * if (ec) * { * // An error occurred. * } * std::size_t bytes_readable = command.get(); * @endcode */ template asio::error_code io_control(IoControlCommand& command, asio::error_code& ec) { return this->service.io_control(this->implementation, command, ec); } protected: /// Protected destructor to prevent deletion through this type. ~basic_descriptor() { } }; } // namespace posix } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP percona-galera-3-3.8-3390/asio/asio/posix/basic_stream_descriptor.hpp000066400000000000000000000264651244131713600254520ustar00rootroot00000000000000// // posix/basic_stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP #define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/posix/basic_descriptor.hpp" #include "asio/posix/stream_descriptor_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace posix { /// Provides stream-oriented descriptor functionality. /** * The posix::basic_stream_descriptor class template provides asynchronous and * blocking stream-oriented descriptor functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class basic_stream_descriptor : public basic_descriptor { public: /// The native representation of a descriptor. typedef typename StreamDescriptorService::native_type native_type; /// Construct a basic_stream_descriptor without opening it. /** * This constructor creates a stream descriptor without opening it. The * descriptor needs to be opened and then connected or accepted before data * can be sent or received on it. * * @param io_service The io_service object that the stream descriptor will * use to dispatch handlers for any asynchronous operations performed on the * descriptor. */ explicit basic_stream_descriptor(asio::io_service& io_service) : basic_descriptor(io_service) { } /// Construct a basic_stream_descriptor on an existing native descriptor. /** * This constructor creates a stream descriptor object to hold an existing * native descriptor. * * @param io_service The io_service object that the stream descriptor will * use to dispatch handlers for any asynchronous operations performed on the * descriptor. * * @param native_descriptor The new underlying descriptor implementation. * * @throws asio::system_error Thrown on failure. */ basic_stream_descriptor(asio::io_service& io_service, const native_type& native_descriptor) : basic_descriptor(io_service, native_descriptor) { } /// Write some data to the descriptor. /** * This function is used to write data to the stream descriptor. The function * call will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the descriptor. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * descriptor.write_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.write_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the descriptor. /** * This function is used to write data to the stream descriptor. The function * call will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the descriptor. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return this->service.write_some(this->implementation, buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream * descriptor. The function call always returns immediately. * * @param buffers One or more data buffers to be written to the descriptor. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * descriptor.async_write_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_write_some(this->implementation, buffers, handler); } /// Read some data from the descriptor. /** * This function is used to read data from the stream descriptor. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * descriptor.read_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.read_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the descriptor. /** * This function is used to read data from the stream descriptor. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return this->service.read_some(this->implementation, buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream * descriptor. The function call always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the * requested amount of data is read before the asynchronous operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * descriptor.async_read_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_read_some(this->implementation, buffers, handler); } }; } // namespace posix } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP percona-galera-3-3.8-3390/asio/asio/posix/descriptor_base.hpp000066400000000000000000000047171244131713600237240ustar00rootroot00000000000000// // posix/descriptor_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_POSIX_DESCRIPTOR_BASE_HPP #define ASIO_POSIX_DESCRIPTOR_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include "asio/detail/io_control.hpp" #include "asio/detail/socket_option.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace posix { /// The descriptor_base class is used as a base for the basic_stream_descriptor /// class template so that we have a common place to define the associated /// IO control commands. class descriptor_base { public: /// IO control command to set the blocking mode of the descriptor. /** * Implements the FIONBIO IO control command. * * @par Example * @code * asio::posix::stream_descriptor descriptor(io_service); * ... * asio::descriptor_base::non_blocking_io command(true); * descriptor.io_control(command); * @endcode * * @par Concepts: * IoControlCommand. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined non_blocking_io; #else typedef asio::detail::io_control::non_blocking_io non_blocking_io; #endif /// IO control command to get the amount of data that can be read without /// blocking. /** * Implements the FIONREAD IO control command. * * @par Example * @code * asio::posix::stream_descriptor descriptor(io_service); * ... * asio::descriptor_base::bytes_readable command(true); * descriptor.io_control(command); * std::size_t bytes_readable = command.get(); * @endcode * * @par Concepts: * IoControlCommand. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined bytes_readable; #else typedef asio::detail::io_control::bytes_readable bytes_readable; #endif protected: /// Protected destructor to prevent deletion through this type. ~descriptor_base() { } }; } // namespace posix } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP percona-galera-3-3.8-3390/asio/asio/posix/stream_descriptor.hpp000066400000000000000000000017711244131713600243020ustar00rootroot00000000000000// // posix/stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_POSIX_STREAM_DESCRIPTOR_HPP #define ASIO_POSIX_STREAM_DESCRIPTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include "asio/posix/basic_stream_descriptor.hpp" namespace asio { namespace posix { /// Typedef for the typical usage of a stream-oriented descriptor. typedef basic_stream_descriptor<> stream_descriptor; } // namespace posix } // namespace asio #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP percona-galera-3-3.8-3390/asio/asio/posix/stream_descriptor_service.hpp000066400000000000000000000117751244131713600260270ustar00rootroot00000000000000// // posix/stream_descriptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP #define ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/reactive_descriptor_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace posix { /// Default service implementation for a stream descriptor. class stream_descriptor_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif private: // The type of the platform-specific implementation. typedef detail::reactive_descriptor_service service_impl_type; public: /// The type of a stream descriptor implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef service_impl_type::implementation_type implementation_type; #endif /// The native descriptor type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef service_impl_type::native_type native_type; #endif /// Construct a new stream descriptor service for the specified io_service. explicit stream_descriptor_service(asio::io_service& io_service) : asio::detail::service_base(io_service), service_impl_(io_service) { } /// Destroy all user-defined descriptorr objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new stream descriptor implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a stream descriptor implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Assign an existing native descriptor to a stream descriptor. asio::error_code assign(implementation_type& impl, const native_type& native_descriptor, asio::error_code& ec) { return service_impl_.assign(impl, native_descriptor, ec); } /// Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a stream descriptor implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native descriptor implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the descriptor. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Perform an IO control command on the descriptor. template asio::error_code io_control(implementation_type& impl, IoControlCommand& command, asio::error_code& ec) { return service_impl_.io_control(impl, command, ec); } /// Write the given data to the stream. template std::size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return service_impl_.write_some(impl, buffers, ec); } /// Start an asynchronous write. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, WriteHandler descriptorr) { service_impl_.async_write_some(impl, buffers, descriptorr); } /// Read some data from the stream. template std::size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.read_some(impl, buffers, ec); } /// Start an asynchronous read. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, ReadHandler descriptorr) { service_impl_.async_read_some(impl, buffers, descriptorr); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace posix } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/raw_socket_service.hpp000066400000000000000000000223171244131713600232670ustar00rootroot00000000000000// // raw_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_RAW_SOCKET_SERVICE_HPP #define ASIO_RAW_SOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" #else # include "asio/detail/reactive_socket_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a raw socket. template class raw_socket_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; #else typedef detail::reactive_socket_service service_impl_type; #endif public: /// The type of a raw socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef typename service_impl_type::native_type native_type; #endif /// Construct a new raw socket service for the specified io_service. explicit raw_socket_service(asio::io_service& io_service) : asio::detail::service_base< raw_socket_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new raw socket implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a raw socket implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } // Open a new raw socket implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (protocol.type() == SOCK_RAW) service_impl_.open(impl, protocol, ec); else ec = asio::error::invalid_argument; return ec; } /// Assign an existing native socket to a raw socket. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { return service_impl_.assign(impl, protocol, native_socket, ec); } /// Determine whether the socket is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a raw socket implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native socket implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the socket. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Determine whether the socket is at the out-of-band data mark. bool at_mark(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.at_mark(impl, ec); } /// Determine the number of bytes available for reading. std::size_t available(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.available(impl, ec); } // Bind the raw socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { return service_impl_.bind(impl, endpoint, ec); } /// Connect the raw socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { return service_impl_.connect(impl, peer_endpoint, ec); } /// Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, ConnectHandler handler) { service_impl_.async_connect(impl, peer_endpoint, handler); } /// Set a socket option. template asio::error_code set_option(implementation_type& impl, const SettableSocketOption& option, asio::error_code& ec) { return service_impl_.set_option(impl, option, ec); } /// Get a socket option. template asio::error_code get_option(const implementation_type& impl, GettableSocketOption& option, asio::error_code& ec) const { return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. template asio::error_code io_control(implementation_type& impl, IoControlCommand& command, asio::error_code& ec) { return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.local_endpoint(impl, ec); } /// Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.remote_endpoint(impl, ec); } /// Disable sends or receives on the socket. asio::error_code shutdown(implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { return service_impl_.shutdown(impl, what, ec); } /// Send the given data to the peer. template std::size_t send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.send(impl, buffers, flags, ec); } /// Start an asynchronous send. template void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send(impl, buffers, flags, handler); } /// Send raw data to the specified endpoint. template std::size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.send_to(impl, buffers, destination, flags, ec); } /// Start an asynchronous send. template void async_send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send_to(impl, buffers, destination, flags, handler); } /// Receive some data from the peer. template std::size_t receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive(impl, buffers, flags, ec); } /// Start an asynchronous receive. template void async_receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive(impl, buffers, flags, handler); } /// Receive raw data with the endpoint of the sender. template std::size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, ec); } /// Start an asynchronous receive that will get the endpoint of the sender. template void async_receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_RAW_SOCKET_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/read.hpp000066400000000000000000000526421244131713600203250ustar00rootroot00000000000000// // read.hpp // ~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_HPP #define ASIO_READ_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /** * @defgroup read asio::read * * @brief Attempt to read a certain amount of data from a stream before * returning. */ /*@{*/ /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * stream. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read(s, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::read( * s, buffers, * asio::transfer_all()); @endcode */ template std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * stream. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's read_some function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read(s, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition); /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * stream. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's read_some function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec); #if !defined(BOOST_NO_IOSTREAM) /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::read( * s, b, * asio::transfer_all()); @endcode */ template std::size_t read(SyncReadStream& s, basic_streambuf& b); /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's read_some function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. */ template std::size_t read(SyncReadStream& s, basic_streambuf& b, CompletionCondition completion_condition); /// Attempt to read a certain amount of data from a stream before returning. /** * This function is used to read a certain number of bytes of data from a * stream. The call will block until one of the following conditions is true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's read_some function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t read(SyncReadStream& s, basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ /** * @defgroup async_read asio::async_read * * @brief Start an asynchronous operation to read a certain amount of data from * a stream. */ /*@{*/ /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of * data from a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions is * true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. The * program must ensure that the stream performs no other read operations (such * as async_read, the stream's async_read_some function, or any other composed * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * stream. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes copied into the * // buffers. If an error occurred, * // this will be the number of * // bytes successfully transferred * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * asio::async_read(s, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::async_read( * s, buffers, * asio::transfer_all(), * handler); @endcode */ template void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of * data from a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions is * true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * stream. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's async_read_some function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes copied into the * // buffers. If an error occurred, * // this will be the number of * // bytes successfully transferred * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::async_read(s, * asio::buffer(data, size), * asio::transfer_at_least(32), * handler); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler); #if !defined(BOOST_NO_IOSTREAM) /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of * data from a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions is * true: * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. The * program must ensure that the stream performs no other read operations (such * as async_read, the stream's async_read_some function, or any other composed * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes copied into the * // buffers. If an error occurred, * // this will be the number of * // bytes successfully transferred * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note This overload is equivalent to calling: * @code asio::async_read( * s, b, * asio::transfer_all(), * handler); @endcode */ template void async_read(AsyncReadStream& s, basic_streambuf& b, ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data from a /// stream. /** * This function is used to asynchronously read a certain number of bytes of * data from a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions is * true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. The * program must ensure that the stream performs no other read operations (such * as async_read, the stream's async_read_some function, or any other composed * operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_read_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the stream's async_read_some function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes copied into the * // buffers. If an error occurred, * // this will be the number of * // bytes successfully transferred * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_read(AsyncReadStream& s, basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/read.hpp" #endif // ASIO_READ_HPP percona-galera-3-3.8-3390/asio/asio/read_at.hpp000066400000000000000000000536071244131713600210130ustar00rootroot00000000000000// // read_at.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_AT_HPP #define ASIO_READ_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /** * @defgroup read_at asio::read_at * * @brief Attempt to read a certain amount of data at the specified offset * before returning. */ /*@{*/ /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * device. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read_at(d, 42, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::read_at( * d, 42, buffers, * asio::transfer_all()); @endcode */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers); /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * device. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's read_some_at function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read_at(d, 42, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition); /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * device. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's read_some_at function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec); #if !defined(BOOST_NO_IOSTREAM) /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param b The basic_streambuf object into which the data will be read. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::read_at( * d, 42, b, * asio::transfer_all()); @endcode */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, basic_streambuf& b); /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param b The basic_streambuf object into which the data will be read. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's read_some_at function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition); /// Attempt to read a certain amount of data at the specified offset before /// returning. /** * This function is used to read a certain number of bytes of data from a * random access device at the specified offset. The call will block until one * of the following conditions is true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support * the SyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param b The basic_streambuf object into which the data will be read. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's read_some_at function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ /** * @defgroup async_read_at asio::async_read_at * * @brief Start an asynchronous operation to read a certain amount of data at * the specified offset. */ /*@{*/ /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of * data from a random access device at the specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support * the AsyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * device. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes copied into the buffers. If an error * // occurred, this will be the number of bytes successfully * // transferred prior to the error. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * asio::async_read_at(d, 42, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::async_read_at( * d, 42, buffers, * asio::transfer_all(), * handler); @endcode */ template void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of * data from a random access device at the specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li The supplied buffers are full. That is, the bytes transferred is equal to * the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * @param d The device from which the data is to be read. The type must support * the AsyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the * device. Although the buffers object may be copied as necessary, ownership of * the underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's async_read_some_at function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes copied into the buffers. If an error * // occurred, this will be the number of bytes successfully * // transferred prior to the error. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::async_read_at(d, 42, * asio::buffer(data, size), * asio::transfer_at_least(32), * handler); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, ReadHandler handler); #if !defined(BOOST_NO_IOSTREAM) /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of * data from a random access device at the specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support * the AsyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes copied into the buffers. If an error * // occurred, this will be the number of bytes successfully * // transferred prior to the error. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note This overload is equivalent to calling: * @code asio::async_read_at( * d, 42, b, * asio::transfer_all(), * handler); @endcode */ template void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, basic_streambuf& b, ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. /** * This function is used to asynchronously read a certain number of bytes of * data from a random access device at the specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support * the AsyncRandomAccessReadDevice concept. * * @param offset The offset at which the data will be read. * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the read operation is complete. A non-zero * return value indicates the maximum number of bytes to be read on the next * call to the device's async_read_some_at function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes copied into the buffers. If an error * // occurred, this will be the number of bytes successfully * // transferred prior to the error. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/read_at.hpp" #endif // ASIO_READ_AT_HPP percona-galera-3-3.8-3390/asio/asio/read_until.hpp000066400000000000000000001073021244131713600215320ustar00rootroot00000000000000// // read_until.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_READ_UNTIL_HPP #define ASIO_READ_UNTIL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include #include #include #include #include #include #include "asio/basic_streambuf.hpp" #include "asio/detail/regex_fwd.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) template struct has_result_type { template struct inner { struct big { char a[100]; }; static big helper(U, ...); static char helper(U, typename U::result_type* = 0); }; static const T& ref(); enum { value = (sizeof((inner::helper)((ref)())) == 1) }; }; #else // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) template struct has_result_type { struct big { char a[100]; }; template static big helper(U, ...); template static char helper(U, typename U::result_type* = 0); static const T& ref(); enum { value = (sizeof((helper)((ref)())) == 1) }; }; #endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) } // namespace detail /// Type trait used to determine whether a type can be used as a match condition /// function with read_until and async_read_until. template struct is_match_condition { #if defined(GENERATING_DOCUMENTATION) /// The value member is true if the type may be used as a match condition. static const bool value; #else enum { value = boost::is_function::type>::value || detail::has_result_type::value }; #endif }; /** * @defgroup read_until asio::read_until * * @brief Read data into a streambuf until it contains a delimiter, matches a * regular expression, or a function object indicates a match. */ /*@{*/ /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains the specified delimiter. The call will block * until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains the * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter character. * * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. * * @throws asio::system_error Thrown on failure. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond the delimiter. An application will typically leave * that data in the streambuf for a subsequent read_until operation to examine. * * @par Example * To read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * asio::read_until(s, b, '\n'); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode * After the @c read_until operation completes successfully, the buffer @c b * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * delimiter, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim); /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains the specified delimiter. The call will block * until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains the * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter character. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. Returns 0 if an error occurred. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond the delimiter. An application will typically leave * that data in the streambuf for a subsequent read_until operation to examine. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim, asio::error_code& ec); /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains the specified delimiter. The call will block * until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains the * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter string. * * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. * * @throws asio::system_error Thrown on failure. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond the delimiter. An application will typically leave * that data in the streambuf for a subsequent read_until operation to examine. * * @par Example * To read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * asio::read_until(s, b, "\r\n"); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode * After the @c read_until operation completes successfully, the buffer @c b * contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * delimiter, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim); /// Read data into a streambuf until it contains a specified delimiter. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains the specified delimiter. The call will block * until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains the * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter string. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. Returns 0 if an error occurred. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond the delimiter. An application will typically leave * that data in the streambuf for a subsequent read_until operation to examine. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, asio::error_code& ec); /// Read data into a streambuf until some part of the data it contains matches /// a regular expression. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains some data that matches a regular expression. * The call will block until one of the following conditions is true: * * @li A substring of the streambuf's get area matches the regular expression. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains data that * matches the regular expression, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param expr The regular expression. * * @returns The number of bytes in the streambuf's get area up to and including * the substring that matches the regular expression. * * @throws asio::system_error Thrown on failure. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the regular expression. An * application will typically leave that data in the streambuf for a subsequent * read_until operation to examine. * * @par Example * To read data into a streambuf until a CR-LF sequence is encountered: * @code asio::streambuf b; * asio::read_until(s, b, boost::regex("\r\n")); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode * After the @c read_until operation completes successfully, the buffer @c b * contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * match, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c read_until operation. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr); /// Read data into a streambuf until some part of the data it contains matches /// a regular expression. /** * This function is used to read data into the specified streambuf until the * streambuf's get area contains some data that matches a regular expression. * The call will block until one of the following conditions is true: * * @li A substring of the streambuf's get area matches the regular expression. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the streambuf's get area already contains data that * matches the regular expression, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param expr The regular expression. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including * the substring that matches the regular expression. Returns 0 if an error * occurred. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the regular expression. An * application will typically leave that data in the streambuf for a subsequent * read_until operation to examine. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, asio::error_code& ec); /// Read data into a streambuf until a function object indicates a match. /** * This function is used to read data into the specified streambuf until a * user-defined match condition function object, when applied to the data * contained in the streambuf, indicates a successful match. The call will * block until one of the following conditions is true: * * @li The match condition function object returns a std::pair where the second * element evaluates to true. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the match condition function object already indicates * a match, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param match_condition The function object to be called to determine whether * a match exists. The signature of the function object must be: * @code pair match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the * return value is an iterator marking one-past-the-end of the bytes that have * been consumed by the match function. This iterator is used to calculate the * @c begin parameter for any subsequent invocation of the match condition. The * @c second member of the return value is true if a match has been found, false * otherwise. * * @returns The number of bytes in the streambuf's get area that have been fully * consumed by the match function. * * @throws asio::system_error Thrown on failure. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application * will typically leave that data in the streambuf for a subsequent * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a * @c result_type typedef. It must be specialised for other user-defined * function objects. * * @par Examples * To read data into a streambuf until whitespace is encountered: * @code typedef asio::buffers_iterator< * asio::streambuf::const_buffers_type> iterator; * * std::pair * match_whitespace(iterator begin, iterator end) * { * iterator i = begin; * while (i != end) * if (std::isspace(*i++)) * return std::make_pair(i, true); * return std::make_pair(i, false); * } * ... * asio::streambuf b; * asio::read_until(s, b, match_whitespace); * @endcode * * To read data into a streambuf until a matching character is found: * @code class match_char * { * public: * explicit match_char(char c) : c_(c) {} * * template * std::pair operator()( * Iterator begin, Iterator end) const * { * Iterator i = begin; * while (i != end) * if (c_ == *i++) * return std::make_pair(i, true); * return std::make_pair(i, false); * } * * private: * char c_; * }; * * namespace asio { * template <> struct is_match_condition * : public boost::true_type {}; * } // namespace asio * ... * asio::streambuf b; * asio::read_until(s, b, match_char('a')); * @endcode */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, typename boost::enable_if >::type* = 0); /// Read data into a streambuf until a function object indicates a match. /** * This function is used to read data into the specified streambuf until a * user-defined match condition function object, when applied to the data * contained in the streambuf, indicates a successful match. The call will * block until one of the following conditions is true: * * @li The match condition function object returns a std::pair where the second * element evaluates to true. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * read_some function. If the match condition function object already indicates * a match, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param match_condition The function object to be called to determine whether * a match exists. The signature of the function object must be: * @code pair match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the * return value is an iterator marking one-past-the-end of the bytes that have * been consumed by the match function. This iterator is used to calculate the * @c begin parameter for any subsequent invocation of the match condition. The * @c second member of the return value is true if a match has been found, false * otherwise. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area that have been fully * consumed by the match function. Returns 0 if an error occurred. * * @note After a successful read_until operation, the streambuf may contain * additional data beyond that which matched the function object. An application * will typically leave that data in the streambuf for a subsequent * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a * @c result_type typedef. It must be specialised for other user-defined * function objects. */ template std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, asio::error_code& ec, typename boost::enable_if >::type* = 0); /*@}*/ /** * @defgroup async_read_until asio::async_read_until * * @brief Start an asynchronous operation to read data into a streambuf until it * contains a delimiter, matches a regular expression, or a function object * indicates a match. */ /*@{*/ /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains the specified delimiter. * The function call always returns immediately. The asynchronous operation * will continue until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. If * the streambuf's get area already contains the delimiter, this asynchronous * operation completes immediately. The program must ensure that the stream * performs no other read operations (such as async_read, async_read_until, the * stream's async_read_some function, or any other composed operations that * perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains * valid until the handler is called. * * @param delim The delimiter character. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the streambuf's get * // area up to and including the delimiter. * // 0 if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically * leave that data in the streambuf for a subsequent async_read_until operation * to examine. * * @par Example * To asynchronously read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * ... * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { * std::istream is(&b); * std::string line; * std::getline(is, line); * ... * } * } * ... * asio::async_read_until(s, b, '\n', handler); @endcode * After the @c async_read_until operation completes successfully, the buffer * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * delimiter, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, char delim, ReadHandler handler); /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains the specified delimiter. * The function call always returns immediately. The asynchronous operation * will continue until one of the following conditions is true: * * @li The get area of the streambuf contains the specified delimiter. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. If * the streambuf's get area already contains the delimiter, this asynchronous * operation completes immediately. The program must ensure that the stream * performs no other read operations (such as async_read, async_read_until, the * stream's async_read_some function, or any other composed operations that * perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains * valid until the handler is called. * * @param delim The delimiter string. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the streambuf's get * // area up to and including the delimiter. * // 0 if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond the delimiter. An application will typically * leave that data in the streambuf for a subsequent async_read_until operation * to examine. * * @par Example * To asynchronously read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * ... * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { * std::istream is(&b); * std::string line; * std::getline(is, line); * ... * } * } * ... * asio::async_read_until(s, b, "\r\n", handler); @endcode * After the @c async_read_until operation completes successfully, the buffer * @c b contains the delimiter: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * delimiter, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, ReadHandler handler); /// Start an asynchronous operation to read data into a streambuf until some /// part of its data matches a regular expression. /** * This function is used to asynchronously read data into the specified * streambuf until the streambuf's get area contains some data that matches a * regular expression. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions * is true: * * @li A substring of the streambuf's get area matches the regular expression. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. If * the streambuf's get area already contains data that matches the regular * expression, this asynchronous operation completes immediately. The program * must ensure that the stream performs no other read operations (such as * async_read, async_read_until, the stream's async_read_some function, or any * other composed operations that perform reads) until this operation * completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains * valid until the handler is called. * * @param expr The regular expression. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the streambuf's get * // area up to and including the substring * // that matches the regular. expression. * // 0 if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the regular expression. An * application will typically leave that data in the streambuf for a subsequent * async_read_until operation to examine. * * @par Example * To asynchronously read data into a streambuf until a CR-LF sequence is * encountered: * @code asio::streambuf b; * ... * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { * std::istream is(&b); * std::string line; * std::getline(is, line); * ... * } * } * ... * asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode * After the @c async_read_until operation completes successfully, the buffer * @c b contains the data which matched the regular expression: * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode * The call to @c std::getline then extracts the data up to and including the * match, so that the string @c line contains: * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode * The remaining data is left in the buffer @c b as follows: * @code { 'd', 'e', ... } @endcode * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, ReadHandler handler); /// Start an asynchronous operation to read data into a streambuf until a /// function object indicates a match. /** * This function is used to asynchronously read data into the specified * streambuf until a user-defined match condition function object, when applied * to the data contained in the streambuf, indicates a successful match. The * function call always returns immediately. The asynchronous operation will * continue until one of the following conditions is true: * * @li The match condition function object returns a std::pair where the second * element evaluates to true. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function, and is known as a composed operation. If * the match condition function object already indicates a match, this * asynchronous operation completes immediately. The program must ensure that * the stream performs no other read operations (such as async_read, * async_read_until, the stream's async_read_some function, or any other * composed operations that perform reads) until this operation completes. * * @param s The stream from which the data is to be read. The type must support * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param match_condition The function object to be called to determine whether * a match exists. The signature of the function object must be: * @code pair match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator::const_buffers_type> * @endcode * The iterator parameters @c begin and @c end define the range of bytes to be * scanned to determine whether there is a match. The @c first member of the * return value is an iterator marking one-past-the-end of the bytes that have * been consumed by the match function. This iterator is used to calculate the * @c begin parameter for any subsequent invocation of the match condition. The * @c second member of the return value is true if a match has been found, false * otherwise. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // The number of bytes in the streambuf's get * // area that have been fully consumed by the * // match function. O if an error occurred. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note After a successful async_read_until operation, the streambuf may * contain additional data beyond that which matched the function object. An * application will typically leave that data in the streambuf for a subsequent * async_read_until operation to examine. * * @note The default implementation of the @c is_match_condition type trait * evaluates to true for function pointers and function objects with a * @c result_type typedef. It must be specialised for other user-defined * function objects. * * @par Examples * To asynchronously read data into a streambuf until whitespace is encountered: * @code typedef asio::buffers_iterator< * asio::streambuf::const_buffers_type> iterator; * * std::pair * match_whitespace(iterator begin, iterator end) * { * iterator i = begin; * while (i != end) * if (std::isspace(*i++)) * return std::make_pair(i, true); * return std::make_pair(i, false); * } * ... * void handler(const asio::error_code& e, std::size_t size); * ... * asio::streambuf b; * asio::async_read_until(s, b, match_whitespace, handler); * @endcode * * To asynchronously read data into a streambuf until a matching character is * found: * @code class match_char * { * public: * explicit match_char(char c) : c_(c) {} * * template * std::pair operator()( * Iterator begin, Iterator end) const * { * Iterator i = begin; * while (i != end) * if (c_ == *i++) * return std::make_pair(i, true); * return std::make_pair(i, false); * } * * private: * char c_; * }; * * namespace asio { * template <> struct is_match_condition * : public boost::true_type {}; * } // namespace asio * ... * void handler(const asio::error_code& e, std::size_t size); * ... * asio::streambuf b; * asio::async_read_until(s, b, match_char('a'), handler); * @endcode */ template void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, MatchCondition match_condition, ReadHandler handler, typename boost::enable_if >::type* = 0); /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/read_until.hpp" #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_READ_UNTIL_HPP percona-galera-3-3.8-3390/asio/asio/serial_port.hpp000066400000000000000000000016411244131713600217260ustar00rootroot00000000000000// // serial_port.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_SERIAL_PORT_HPP #define ASIO_SERIAL_PORT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_serial_port.hpp" namespace asio { /// Typedef for the typical usage of a serial port. typedef basic_serial_port<> serial_port; } // namespace asio #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_SERIAL_PORT_HPP percona-galera-3-3.8-3390/asio/asio/serial_port_base.hpp000066400000000000000000000111451244131713600227200ustar00rootroot00000000000000// // serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) // // 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) // #ifndef ASIO_SERIAL_PORT_BASE_HPP #define ASIO_SERIAL_PORT_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) # include #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) #include #include "asio/detail/socket_types.hpp" #include "asio/error_code.hpp" #if defined(GENERATING_DOCUMENTATION) # define ASIO_OPTION_STORAGE implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) # define ASIO_OPTION_STORAGE DCB #else # define ASIO_OPTION_STORAGE termios #endif #include "asio/detail/push_options.hpp" namespace asio { /// The serial_port_base class is used as a base for the basic_serial_port class /// template so that we have a common place to define the serial port options. class serial_port_base { public: /// Serial port option to permit changing the baud rate. /** * Implements changing the baud rate for a given serial port. */ class baud_rate { public: explicit baud_rate(unsigned int rate = 0); unsigned int value() const; ASIO_DECL asio::error_code store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; ASIO_DECL asio::error_code load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: unsigned int value_; }; /// Serial port option to permit changing the flow control. /** * Implements changing the flow control for a given serial port. */ class flow_control { public: enum type { none, software, hardware }; ASIO_DECL explicit flow_control(type t = none); type value() const; ASIO_DECL asio::error_code store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; ASIO_DECL asio::error_code load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; }; /// Serial port option to permit changing the parity. /** * Implements changing the parity for a given serial port. */ class parity { public: enum type { none, odd, even }; ASIO_DECL explicit parity(type t = none); type value() const; ASIO_DECL asio::error_code store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; ASIO_DECL asio::error_code load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; }; /// Serial port option to permit changing the number of stop bits. /** * Implements changing the number of stop bits for a given serial port. */ class stop_bits { public: enum type { one, onepointfive, two }; ASIO_DECL explicit stop_bits(type t = one); type value() const; ASIO_DECL asio::error_code store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; ASIO_DECL asio::error_code load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: type value_; }; /// Serial port option to permit changing the character size. /** * Implements changing the character size for a given serial port. */ class character_size { public: ASIO_DECL explicit character_size(unsigned int t = 8); unsigned int value() const; ASIO_DECL asio::error_code store( ASIO_OPTION_STORAGE& storage, asio::error_code& ec) const; ASIO_DECL asio::error_code load( const ASIO_OPTION_STORAGE& storage, asio::error_code& ec); private: unsigned int value_; }; protected: /// Protected destructor to prevent deletion through this type. ~serial_port_base() { } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) private: // Workaround to enable the empty base optimisation with Borland C++. char dummy_; #endif }; } // namespace asio #include "asio/detail/pop_options.hpp" #undef ASIO_OPTION_STORAGE #include "asio/impl/serial_port_base.hpp" #if defined(ASIO_HEADER_ONLY) # include "asio/impl/serial_port_base.ipp" #endif // defined(ASIO_HEADER_ONLY) #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_SERIAL_PORT_BASE_HPP percona-galera-3-3.8-3390/asio/asio/serial_port_service.hpp000066400000000000000000000131651244131713600234520ustar00rootroot00000000000000// // serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SERIAL_PORT_SERVICE_HPP #define ASIO_SERIAL_PORT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include #include #include "asio/detail/reactive_serial_port_service.hpp" #include "asio/detail/win_iocp_serial_port_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/serial_port_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a serial port. class serial_port_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_serial_port_service service_impl_type; #else typedef detail::reactive_serial_port_service service_impl_type; #endif public: /// The type of a serial port implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef service_impl_type::implementation_type implementation_type; #endif /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef service_impl_type::native_type native_type; #endif /// Construct a new serial port service for the specified io_service. explicit serial_port_service(asio::io_service& io_service) : asio::detail::service_base(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new serial port implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a serial port implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Open a serial port. asio::error_code open(implementation_type& impl, const std::string& device, asio::error_code& ec) { return service_impl_.open(impl, device, ec); } /// Assign an existing native handle to a serial port. asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { return service_impl_.assign(impl, native_handle, ec); } /// Determine whether the handle is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a serial port implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native handle implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the handle. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Set a serial port option. template asio::error_code set_option(implementation_type& impl, const SettableSerialPortOption& option, asio::error_code& ec) { return service_impl_.set_option(impl, option, ec); } /// Get a serial port option. template asio::error_code get_option(const implementation_type& impl, GettableSerialPortOption& option, asio::error_code& ec) const { return service_impl_.get_option(impl, option, ec); } /// Send a break sequence to the serial port. asio::error_code send_break(implementation_type& impl, asio::error_code& ec) { return service_impl_.send_break(impl, ec); } /// Write the given data to the stream. template std::size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return service_impl_.write_some(impl, buffers, ec); } /// Start an asynchronous write. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, WriteHandler handler) { service_impl_.async_write_some(impl, buffers, handler); } /// Read some data from the stream. template std::size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.read_some(impl, buffers, ec); } /// Start an asynchronous read. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, ReadHandler handler) { service_impl_.async_read_some(impl, buffers, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_SERIAL_PORT_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/socket_acceptor_service.hpp000066400000000000000000000141211244131713600242700ustar00rootroot00000000000000// // socket_acceptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SOCKET_ACCEPTOR_SERVICE_HPP #define ASIO_SOCKET_ACCEPTOR_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/basic_socket.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" #else # include "asio/detail/reactive_socket_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a socket acceptor. template class socket_acceptor_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename protocol_type::endpoint endpoint_type; private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; #else typedef detail::reactive_socket_service service_impl_type; #endif public: /// The native type of the socket acceptor. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// The native acceptor type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef typename service_impl_type::native_type native_type; #endif /// Construct a new socket acceptor service for the specified io_service. explicit socket_acceptor_service(asio::io_service& io_service) : asio::detail::service_base< socket_acceptor_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new socket acceptor implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a socket acceptor implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Open a new socket acceptor implementation. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { return service_impl_.open(impl, protocol, ec); } /// Assign an existing native acceptor to a socket acceptor. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_acceptor, asio::error_code& ec) { return service_impl_.assign(impl, protocol, native_acceptor, ec); } /// Determine whether the acceptor is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Cancel all asynchronous operations associated with the acceptor. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Bind the socket acceptor to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { return service_impl_.bind(impl, endpoint, ec); } /// Place the socket acceptor into the state where it will listen for new /// connections. asio::error_code listen(implementation_type& impl, int backlog, asio::error_code& ec) { return service_impl_.listen(impl, backlog, ec); } /// Close a socket acceptor implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native acceptor implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Set a socket option. template asio::error_code set_option(implementation_type& impl, const SettableSocketOption& option, asio::error_code& ec) { return service_impl_.set_option(impl, option, ec); } /// Get a socket option. template asio::error_code get_option(const implementation_type& impl, GettableSocketOption& option, asio::error_code& ec) const { return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. template asio::error_code io_control(implementation_type& impl, IoControlCommand& command, asio::error_code& ec) { return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.local_endpoint(impl, ec); } /// Accept a new connection. template asio::error_code accept(implementation_type& impl, basic_socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { return service_impl_.accept(impl, peer, peer_endpoint, ec); } /// Start an asynchronous accept. template void async_accept(implementation_type& impl, basic_socket& peer, endpoint_type* peer_endpoint, AcceptHandler handler) { service_impl_.async_accept(impl, peer, peer_endpoint, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SOCKET_ACCEPTOR_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/socket_base.hpp000066400000000000000000000327701244131713600216740ustar00rootroot00000000000000// // socket_base.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SOCKET_BASE_HPP #define ASIO_SOCKET_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/io_control.hpp" #include "asio/detail/socket_option.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// The socket_base class is used as a base for the basic_stream_socket and /// basic_datagram_socket class templates so that we have a common place to /// define the shutdown_type and enum. class socket_base { public: /// Different ways a socket may be shutdown. enum shutdown_type { #if defined(GENERATING_DOCUMENTATION) /// Shutdown the receive side of the socket. shutdown_receive = implementation_defined, /// Shutdown the send side of the socket. shutdown_send = implementation_defined, /// Shutdown both send and receive on the socket. shutdown_both = implementation_defined #else shutdown_receive = asio::detail::shutdown_receive, shutdown_send = asio::detail::shutdown_send, shutdown_both = asio::detail::shutdown_both #endif }; /// Bitmask type for flags that can be passed to send and receive operations. typedef int message_flags; #if defined(GENERATING_DOCUMENTATION) /// Peek at incoming data without removing it from the input queue. static const int message_peek = implementation_defined; /// Process out-of-band data. static const int message_out_of_band = implementation_defined; /// Specify that the data should not be subject to routing. static const int message_do_not_route = implementation_defined; #else BOOST_STATIC_CONSTANT(int, message_peek = asio::detail::message_peek); BOOST_STATIC_CONSTANT(int, message_out_of_band = asio::detail::message_out_of_band); BOOST_STATIC_CONSTANT(int, message_do_not_route = asio::detail::message_do_not_route); #endif /// Socket option to permit sending of broadcast messages. /** * Implements the SOL_SOCKET/SO_BROADCAST socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::socket_base::broadcast option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::socket_base::broadcast option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined broadcast; #else typedef asio::detail::socket_option::boolean< SOL_SOCKET, SO_BROADCAST> broadcast; #endif /// Socket option to enable socket-level debugging. /** * Implements the SOL_SOCKET/SO_DEBUG socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::debug option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::debug option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined debug; #else typedef asio::detail::socket_option::boolean< SOL_SOCKET, SO_DEBUG> debug; #endif /// Socket option to prevent routing, use local interfaces only. /** * Implements the SOL_SOCKET/SO_DONTROUTE socket option. * * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::socket_base::do_not_route option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::udp::socket socket(io_service); * ... * asio::socket_base::do_not_route option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined do_not_route; #else typedef asio::detail::socket_option::boolean< SOL_SOCKET, SO_DONTROUTE> do_not_route; #endif /// Socket option to send keep-alives. /** * Implements the SOL_SOCKET/SO_KEEPALIVE socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::keep_alive option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::keep_alive option; * socket.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined keep_alive; #else typedef asio::detail::socket_option::boolean< SOL_SOCKET, SO_KEEPALIVE> keep_alive; #endif /// Socket option for the send buffer size of a socket. /** * Implements the SOL_SOCKET/SO_SNDBUF socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::send_buffer_size option(8192); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::send_buffer_size option; * socket.get_option(option); * int size = option.value(); * @endcode * * @par Concepts: * Socket_Option, Integer_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined send_buffer_size; #else typedef asio::detail::socket_option::integer< SOL_SOCKET, SO_SNDBUF> send_buffer_size; #endif /// Socket option for the send low watermark. /** * Implements the SOL_SOCKET/SO_SNDLOWAT socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::send_low_watermark option(1024); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::send_low_watermark option; * socket.get_option(option); * int size = option.value(); * @endcode * * @par Concepts: * Socket_Option, Integer_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined send_low_watermark; #else typedef asio::detail::socket_option::integer< SOL_SOCKET, SO_SNDLOWAT> send_low_watermark; #endif /// Socket option for the receive buffer size of a socket. /** * Implements the SOL_SOCKET/SO_RCVBUF socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::receive_buffer_size option(8192); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::receive_buffer_size option; * socket.get_option(option); * int size = option.value(); * @endcode * * @par Concepts: * Socket_Option, Integer_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined receive_buffer_size; #else typedef asio::detail::socket_option::integer< SOL_SOCKET, SO_RCVBUF> receive_buffer_size; #endif /// Socket option for the receive low watermark. /** * Implements the SOL_SOCKET/SO_RCVLOWAT socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::receive_low_watermark option(1024); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::receive_low_watermark option; * socket.get_option(option); * int size = option.value(); * @endcode * * @par Concepts: * Socket_Option, Integer_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined receive_low_watermark; #else typedef asio::detail::socket_option::integer< SOL_SOCKET, SO_RCVLOWAT> receive_low_watermark; #endif /// Socket option to allow the socket to be bound to an address that is /// already in use. /** * Implements the SOL_SOCKET/SO_REUSEADDR socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::socket_base::reuse_address option(true); * acceptor.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::socket_base::reuse_address option; * acceptor.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined reuse_address; #else typedef asio::detail::socket_option::boolean< SOL_SOCKET, SO_REUSEADDR> reuse_address; #endif /// Socket option to specify whether the socket lingers on close if unsent /// data is present. /** * Implements the SOL_SOCKET/SO_LINGER socket option. * * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::linger option(true, 30); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::linger option; * socket.get_option(option); * bool is_set = option.enabled(); * unsigned short timeout = option.timeout(); * @endcode * * @par Concepts: * Socket_Option, Linger_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined linger; #else typedef asio::detail::socket_option::linger< SOL_SOCKET, SO_LINGER> linger; #endif /// Socket option to report aborted connections on accept. /** * Implements a custom socket option that determines whether or not an accept * operation is permitted to fail with asio::error::connection_aborted. * By default the option is false. * * @par Examples * Setting the option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::socket_base::enable_connection_aborted option(true); * acceptor.set_option(option); * @endcode * * @par * Getting the current option value: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::socket_base::enable_connection_aborted option; * acceptor.get_option(option); * bool is_set = option.value(); * @endcode * * @par Concepts: * Socket_Option, Boolean_Socket_Option. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined enable_connection_aborted; #else typedef asio::detail::socket_option::boolean< asio::detail::custom_socket_option_level, asio::detail::enable_connection_aborted_option> enable_connection_aborted; #endif /// IO control command to set the blocking mode of the socket. /** * Implements the FIONBIO IO control command. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::non_blocking_io command(true); * socket.io_control(command); * @endcode * * @par Concepts: * IO_Control_Command, Boolean_IO_Control_Command. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined non_blocking_io; #else typedef asio::detail::io_control::non_blocking_io non_blocking_io; #endif /// IO control command to get the amount of data that can be read without /// blocking. /** * Implements the FIONREAD IO control command. * * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::socket_base::bytes_readable command(true); * socket.io_control(command); * std::size_t bytes_readable = command.get(); * @endcode * * @par Concepts: * IO_Control_Command, Size_IO_Control_Command. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined bytes_readable; #else typedef asio::detail::io_control::bytes_readable bytes_readable; #endif /// The maximum length of the queue of pending incoming connections. #if defined(GENERATING_DOCUMENTATION) static const int max_connections = implementation_defined; #else BOOST_STATIC_CONSTANT(int, max_connections = SOMAXCONN); #endif protected: /// Protected destructor to prevent deletion through this type. ~socket_base() { } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) private: // Workaround to enable the empty base optimisation with Borland C++. char dummy_; #endif }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SOCKET_BASE_HPP percona-galera-3-3.8-3390/asio/asio/ssl.hpp000066400000000000000000000012701244131713600202020ustar00rootroot00000000000000// // ssl.hpp // ~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_HPP #define ASIO_SSL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/ssl/basic_context.hpp" #include "asio/ssl/context.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/context_service.hpp" #include "asio/ssl/stream.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/stream_service.hpp" #endif // ASIO_SSL_HPP percona-galera-3-3.8-3390/asio/asio/ssl/000077500000000000000000000000001244131713600174715ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ssl/basic_context.hpp000077500000000000000000000322711244131713600230370ustar00rootroot00000000000000// // ssl/basic_context.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_BASIC_CONTEXT_HPP #define ASIO_SSL_BASIC_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/context_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// SSL context. template class basic_context : public context_base, private boost::noncopyable { public: /// The type of the service that will be used to provide context operations. typedef Service service_type; /// The native implementation type of the locking dispatcher. typedef typename service_type::impl_type impl_type; /// Constructor. basic_context(asio::io_service& io_service, method m) : service_(asio::use_service(io_service)), impl_(service_.null()) { service_.create(impl_, m); } /// Destructor. ~basic_context() { service_.destroy(impl_); } /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * context. This is intended to allow access to context functionality that is * not otherwise provided. */ impl_type impl() { return impl_; } /// Set options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The options are bitwise-ored with any existing * value for the options. * * @throws asio::system_error Thrown on failure. */ void set_options(options o) { asio::error_code ec; service_.set_options(impl_, o, ec); asio::detail::throw_error(ec); } /// Set options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The options are bitwise-ored with any existing * value for the options. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code set_options(options o, asio::error_code& ec) { return service_.set_options(impl_, o, ec); } /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the context. * * @param v A bitmask of peer verification modes. The available verify_mode * values are defined in the context_base class. * * @throws asio::system_error Thrown on failure. */ void set_verify_mode(verify_mode v) { asio::error_code ec; service_.set_verify_mode(impl_, v, ec); asio::detail::throw_error(ec); } /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the context. * * @param v A bitmask of peer verification modes. The available verify_mode * values are defined in the context_base class. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code set_verify_mode(verify_mode v, asio::error_code& ec) { return service_.set_verify_mode(impl_, v, ec); } /// Load a certification authority file for performing verification. /** * This function is used to load one or more trusted certification authorities * from a file. * * @param filename The name of a file containing certification authority * certificates in PEM format. * * @throws asio::system_error Thrown on failure. */ void load_verify_file(const std::string& filename) { asio::error_code ec; service_.load_verify_file(impl_, filename, ec); asio::detail::throw_error(ec); } /// Load a certification authority file for performing verification. /** * This function is used to load the certificates for one or more trusted * certification authorities from a file. * * @param filename The name of a file containing certification authority * certificates in PEM format. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code load_verify_file(const std::string& filename, asio::error_code& ec) { return service_.load_verify_file(impl_, filename, ec); } /// Add a directory containing certificate authority files to be used for /// performing verification. /** * This function is used to specify the name of a directory containing * certification authority certificates. Each file in the directory must * contain a single certificate. The files must be named using the subject * name's hash and an extension of ".0". * * @param path The name of a directory containing the certificates. * * @throws asio::system_error Thrown on failure. */ void add_verify_path(const std::string& path) { asio::error_code ec; service_.add_verify_path(impl_, path, ec); asio::detail::throw_error(ec); } /// Add a directory containing certificate authority files to be used for /// performing verification. /** * This function is used to specify the name of a directory containing * certification authority certificates. Each file in the directory must * contain a single certificate. The files must be named using the subject * name's hash and an extension of ".0". * * @param path The name of a directory containing the certificates. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code add_verify_path(const std::string& path, asio::error_code& ec) { return service_.add_verify_path(impl_, path, ec); } /// Use a certificate from a file. /** * This function is used to load a certificate into the context from a file. * * @param filename The name of the file containing the certificate. * * @param format The file format (ASN.1 or PEM). * * @throws asio::system_error Thrown on failure. */ void use_certificate_file(const std::string& filename, file_format format) { asio::error_code ec; service_.use_certificate_file(impl_, filename, format, ec); asio::detail::throw_error(ec); } /// Use a certificate from a file. /** * This function is used to load a certificate into the context from a file. * * @param filename The name of the file containing the certificate. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. */ asio::error_code use_certificate_file(const std::string& filename, file_format format, asio::error_code& ec) { return service_.use_certificate_file(impl_, filename, format, ec); } /// Use a certificate chain from a file. /** * This function is used to load a certificate chain into the context from a * file. * * @param filename The name of the file containing the certificate. The file * must use the PEM format. * * @throws asio::system_error Thrown on failure. */ void use_certificate_chain_file(const std::string& filename) { asio::error_code ec; service_.use_certificate_chain_file(impl_, filename, ec); asio::detail::throw_error(ec); } /// Use a certificate chain from a file. /** * This function is used to load a certificate chain into the context from a * file. * * @param filename The name of the file containing the certificate. The file * must use the PEM format. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code use_certificate_chain_file( const std::string& filename, asio::error_code& ec) { return service_.use_certificate_chain_file(impl_, filename, ec); } /// Use a private key from a file. /** * This function is used to load a private key into the context from a file. * * @param filename The name of the file containing the private key. * * @param format The file format (ASN.1 or PEM). * * @throws asio::system_error Thrown on failure. */ void use_private_key_file(const std::string& filename, file_format format) { asio::error_code ec; service_.use_private_key_file(impl_, filename, format, ec); asio::detail::throw_error(ec); } /// Use a private key from a file. /** * This function is used to load a private key into the context from a file. * * @param filename The name of the file containing the private key. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. */ asio::error_code use_private_key_file(const std::string& filename, file_format format, asio::error_code& ec) { return service_.use_private_key_file(impl_, filename, format, ec); } /// Use an RSA private key from a file. /** * This function is used to load an RSA private key into the context from a * file. * * @param filename The name of the file containing the RSA private key. * * @param format The file format (ASN.1 or PEM). * * @throws asio::system_error Thrown on failure. */ void use_rsa_private_key_file(const std::string& filename, file_format format) { asio::error_code ec; service_.use_rsa_private_key_file(impl_, filename, format, ec); asio::detail::throw_error(ec); } /// Use an RSA private key from a file. /** * This function is used to load an RSA private key into the context from a * file. * * @param filename The name of the file containing the RSA private key. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. */ asio::error_code use_rsa_private_key_file( const std::string& filename, file_format format, asio::error_code& ec) { return service_.use_rsa_private_key_file(impl_, filename, format, ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a file. * * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * * @throws asio::system_error Thrown on failure. */ void use_tmp_dh_file(const std::string& filename) { asio::error_code ec; service_.use_tmp_dh_file(impl_, filename, ec); asio::detail::throw_error(ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a file. * * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code use_tmp_dh_file(const std::string& filename, asio::error_code& ec) { return service_.use_tmp_dh_file(impl_, filename, ec); } /// Set the password callback. /** * This function is used to specify a callback function to obtain password * information about an encrypted key in PEM format. * * @param callback The function object to be used for obtaining the password. * The function signature of the handler must be: * @code std::string password_callback( * std::size_t max_length, // The maximum size for a password. * password_purpose purpose // Whether password is for reading or writing. * ); @endcode * The return value of the callback is a string containing the password. * * @throws asio::system_error Thrown on failure. */ template void set_password_callback(PasswordCallback callback) { asio::error_code ec; service_.set_password_callback(impl_, callback, ec); asio::detail::throw_error(ec); } /// Set the password callback. /** * This function is used to specify a callback function to obtain password * information about an encrypted key in PEM format. * * @param callback The function object to be used for obtaining the password. * The function signature of the handler must be: * @code std::string password_callback( * std::size_t max_length, // The maximum size for a password. * password_purpose purpose // Whether password is for reading or writing. * ); @endcode * The return value of the callback is a string containing the password. * * @param ec Set to indicate what error occurred, if any. */ template asio::error_code set_password_callback(PasswordCallback callback, asio::error_code& ec) { return service_.set_password_callback(impl_, callback, ec); } private: /// The backend service implementation. service_type& service_; /// The underlying native implementation. impl_type impl_; }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_BASIC_CONTEXT_HPP percona-galera-3-3.8-3390/asio/asio/ssl/context.hpp000066400000000000000000000015031244131713600216650ustar00rootroot00000000000000// // ssl/context.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_CONTEXT_HPP #define ASIO_SSL_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/context_service.hpp" namespace asio { namespace ssl { /// Typedef for the typical usage of context. typedef basic_context context; } // namespace ssl } // namespace asio #endif // ASIO_SSL_CONTEXT_HPP percona-galera-3-3.8-3390/asio/asio/ssl/context_base.hpp000077500000000000000000000075631244131713600226760ustar00rootroot00000000000000// // ssl/context_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_CONTEXT_BASE_HPP #define ASIO_SSL_CONTEXT_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/ssl/detail/openssl_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// The context_base class is used as a base for the basic_context class /// template so that we have a common place to define various enums. class context_base { public: /// Different methods supported by a context. enum method { /// Generic SSL version 2. sslv2, /// SSL version 2 client. sslv2_client, /// SSL version 2 server. sslv2_server, /// Generic SSL version 3. sslv3, /// SSL version 3 client. sslv3_client, /// SSL version 3 server. sslv3_server, /// Generic TLS version 1. tlsv1, /// TLS version 1 client. tlsv1_client, /// TLS version 1 server. tlsv1_server, /// Generic SSL/TLS. sslv23, /// SSL/TLS client. sslv23_client, /// SSL/TLS server. sslv23_server }; /// Bitmask type for SSL options. typedef int options; #if defined(GENERATING_DOCUMENTATION) /// Implement various bug workarounds. static const int default_workarounds = implementation_defined; /// Always create a new key when using tmp_dh parameters. static const int single_dh_use = implementation_defined; /// Disable SSL v2. static const int no_sslv2 = implementation_defined; /// Disable SSL v3. static const int no_sslv3 = implementation_defined; /// Disable TLS v1. static const int no_tlsv1 = implementation_defined; #else BOOST_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL); BOOST_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE); BOOST_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2); BOOST_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3); BOOST_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1); #endif /// File format types. enum file_format { /// ASN.1 file. asn1, /// PEM file. pem }; /// Bitmask type for peer verification. typedef int verify_mode; #if defined(GENERATING_DOCUMENTATION) /// No verification. static const int verify_none = implementation_defined; /// Verify the peer. static const int verify_peer = implementation_defined; /// Fail verification if the peer has no certificate. Ignored unless /// verify_peer is set. static const int verify_fail_if_no_peer_cert = implementation_defined; /// Do not request client certificate on renegotiation. Ignored unless /// verify_peer is set. static const int verify_client_once = implementation_defined; #else BOOST_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE); BOOST_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER); BOOST_STATIC_CONSTANT(int, verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT); BOOST_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE); #endif /// Purpose of PEM password. enum password_purpose { /// The password is needed for reading/decryption. for_reading, /// The password is needed for writing/encryption. for_writing }; protected: /// Protected destructor to prevent deletion through this type. ~context_base() { } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) private: // Workaround to enable the empty base optimisation with Borland C++. char dummy_; #endif }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_CONTEXT_BASE_HPP percona-galera-3-3.8-3390/asio/asio/ssl/context_service.hpp000077500000000000000000000115601244131713600234140ustar00rootroot00000000000000// // ssl/context_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_CONTEXT_SERVICE_HPP #define ASIO_SSL_CONTEXT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_context_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// Default service implementation for a context. class context_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { private: // The type of the platform-specific implementation. typedef detail::openssl_context_service service_impl_type; public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The type of the context. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined impl_type; #else typedef service_impl_type::impl_type impl_type; #endif /// Constructor. explicit context_service(asio::io_service& io_service) : asio::detail::service_base(io_service), service_impl_(asio::use_service(io_service)) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { } /// Return a null context implementation. impl_type null() const { return service_impl_.null(); } /// Create a new context implementation. void create(impl_type& impl, context_base::method m) { service_impl_.create(impl, m); } /// Destroy a context implementation. void destroy(impl_type& impl) { service_impl_.destroy(impl); } /// Set options on the context. asio::error_code set_options(impl_type& impl, context_base::options o, asio::error_code& ec) { return service_impl_.set_options(impl, o, ec); } /// Set peer verification mode. asio::error_code set_verify_mode(impl_type& impl, context_base::verify_mode v, asio::error_code& ec) { return service_impl_.set_verify_mode(impl, v, ec); } /// Load a certification authority file for performing verification. asio::error_code load_verify_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { return service_impl_.load_verify_file(impl, filename, ec); } /// Add a directory containing certification authority files to be used for /// performing verification. asio::error_code add_verify_path(impl_type& impl, const std::string& path, asio::error_code& ec) { return service_impl_.add_verify_path(impl, path, ec); } /// Use a certificate from a file. asio::error_code use_certificate_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { return service_impl_.use_certificate_file(impl, filename, format, ec); } /// Use a certificate chain from a file. asio::error_code use_certificate_chain_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { return service_impl_.use_certificate_chain_file(impl, filename, ec); } /// Use a private key from a file. asio::error_code use_private_key_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { return service_impl_.use_private_key_file(impl, filename, format, ec); } /// Use an RSA private key from a file. asio::error_code use_rsa_private_key_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { return service_impl_.use_rsa_private_key_file(impl, filename, format, ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. asio::error_code use_tmp_dh_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { return service_impl_.use_tmp_dh_file(impl, filename, ec); } /// Set the password callback. template asio::error_code set_password_callback(impl_type& impl, PasswordCallback callback, asio::error_code& ec) { return service_impl_.set_password_callback(impl, callback, ec); } private: // The service that provides the platform-specific implementation. service_impl_type& service_impl_; }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_CONTEXT_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/ssl/detail/000077500000000000000000000000001244131713600207335ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/ssl/detail/openssl_context_service.hpp000077500000000000000000000225651244131713600264300ustar00rootroot00000000000000// // ssl/detail/openssl_context_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP #define ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_init.hpp" #include "asio/ssl/detail/openssl_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { namespace detail { class openssl_context_service : public asio::detail::service_base { public: // The native type of the context. typedef ::SSL_CTX* impl_type; // The type for the password callback function object. typedef boost::function password_callback_type; // Constructor. openssl_context_service(asio::io_service& io_service) : asio::detail::service_base(io_service) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { } // Return a null context implementation. static impl_type null() { return 0; } // Create a new context implementation. void create(impl_type& impl, context_base::method m) { switch (m) { /* Not supported in libssl 1.0.0 case context_base::sslv2: impl = ::SSL_CTX_new(::SSLv2_method()); break; case context_base::sslv2_client: impl = ::SSL_CTX_new(::SSLv2_client_method()); break; case context_base::sslv2_server: impl = ::SSL_CTX_new(::SSLv2_server_method()); break; */ case context_base::sslv3: impl = ::SSL_CTX_new(::SSLv3_method()); break; case context_base::sslv3_client: impl = ::SSL_CTX_new(::SSLv3_client_method()); break; case context_base::sslv3_server: impl = ::SSL_CTX_new(::SSLv3_server_method()); break; case context_base::tlsv1: impl = ::SSL_CTX_new(::TLSv1_method()); break; case context_base::tlsv1_client: impl = ::SSL_CTX_new(::TLSv1_client_method()); break; case context_base::tlsv1_server: impl = ::SSL_CTX_new(::TLSv1_server_method()); break; case context_base::sslv23: impl = ::SSL_CTX_new(::SSLv23_method()); break; case context_base::sslv23_client: impl = ::SSL_CTX_new(::SSLv23_client_method()); break; case context_base::sslv23_server: impl = ::SSL_CTX_new(::SSLv23_server_method()); break; default: impl = ::SSL_CTX_new(0); break; } } // Destroy a context implementation. void destroy(impl_type& impl) { if (impl != null()) { if (impl->default_passwd_callback_userdata) { password_callback_type* callback = static_cast( impl->default_passwd_callback_userdata); delete callback; impl->default_passwd_callback_userdata = 0; } ::SSL_CTX_free(impl); impl = null(); } } // Set options on the context. asio::error_code set_options(impl_type& impl, context_base::options o, asio::error_code& ec) { ::SSL_CTX_set_options(impl, o); ec = asio::error_code(); return ec; } // Set peer verification mode. asio::error_code set_verify_mode(impl_type& impl, context_base::verify_mode v, asio::error_code& ec) { ::SSL_CTX_set_verify(impl, v, 0); ec = asio::error_code(); return ec; } // Load a certification authority file for performing verification. asio::error_code load_verify_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Add a directory containing certification authority files to be used for // performing verification. asio::error_code add_verify_path(impl_type& impl, const std::string& path, asio::error_code& ec) { if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Use a certificate from a file. asio::error_code use_certificate_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = asio::error::invalid_argument; return ec; } } if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Use a certificate chain from a file. asio::error_code use_certificate_chain_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Use a private key from a file. asio::error_code use_private_key_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = asio::error::invalid_argument; return ec; } } if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Use an RSA private key from a file. asio::error_code use_rsa_private_key_file(impl_type& impl, const std::string& filename, context_base::file_format format, asio::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = asio::error::invalid_argument; return ec; } } if (::SSL_CTX_use_RSAPrivateKey_file( impl, filename.c_str(), file_type) != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } // Use the specified file to obtain the temporary Diffie-Hellman parameters. asio::error_code use_tmp_dh_file(impl_type& impl, const std::string& filename, asio::error_code& ec) { ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); if (!bio) { ec = asio::error::invalid_argument; return ec; } ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); if (!dh) { ::BIO_free(bio); ec = asio::error::invalid_argument; return ec; } ::BIO_free(bio); int result = ::SSL_CTX_set_tmp_dh(impl, dh); ::DH_free(dh); if (result != 1) { ec = asio::error::invalid_argument; return ec; } ec = asio::error_code(); return ec; } static int password_callback(char* buf, int size, int purpose, void* data) { using namespace std; // For strncat and strlen. if (data) { password_callback_type* callback = static_cast(data); std::string passwd = (*callback)(static_cast(size), purpose ? context_base::for_writing : context_base::for_reading); *buf = '\0'; strncat(buf, passwd.c_str(), size); return strlen(buf); } return 0; } // Set the password callback. template asio::error_code set_password_callback(impl_type& impl, Password_Callback callback, asio::error_code& ec) { // Allocate callback function object if not already present. if (impl->default_passwd_callback_userdata) { password_callback_type* callback_function = static_cast( impl->default_passwd_callback_userdata); *callback_function = callback; } else { password_callback_type* callback_function = new password_callback_type(callback); impl->default_passwd_callback_userdata = callback_function; } // Set the password callback. SSL_CTX_set_default_passwd_cb(impl, &openssl_context_service::password_callback); ec = asio::error_code(); return ec; } private: // Ensure openssl is initialised. openssl_init<> init_; }; } // namespace detail } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_CONTEXT_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/ssl/detail/openssl_init.hpp000077500000000000000000000102451244131713600241570ustar00rootroot00000000000000// // ssl/detail/openssl_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_DETAIL_OPENSSL_INIT_HPP #define ASIO_SSL_DETAIL_OPENSSL_INIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/mutex.hpp" #include "asio/detail/tss_ptr.hpp" #include "asio/ssl/detail/openssl_types.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { namespace detail { template class openssl_init : private boost::noncopyable { private: // Structure to perform the actual initialisation. class do_init { public: do_init() { if (Do_Init) { ::SSL_library_init(); ::SSL_load_error_strings(); ::OpenSSL_add_ssl_algorithms(); mutexes_.resize(::CRYPTO_num_locks()); for (size_t i = 0; i < mutexes_.size(); ++i) mutexes_[i].reset(new asio::detail::mutex); ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func); ::CRYPTO_set_id_callback(&do_init::openssl_id_func); } } ~do_init() { if (Do_Init) { ::CRYPTO_set_id_callback(0); ::CRYPTO_set_locking_callback(0); ::ERR_free_strings(); ::ERR_remove_state(0); ::EVP_cleanup(); ::CRYPTO_cleanup_all_ex_data(); ::CONF_modules_unload(1); ::ENGINE_cleanup(); } } // Helper function to manage a do_init singleton. The static instance of the // openssl_init object ensures that this function is always called before // main, and therefore before any other threads can get started. The do_init // instance must be static in this function to ensure that it gets // initialised before any other global objects try to use it. static boost::shared_ptr instance() { static boost::shared_ptr init(new do_init); return init; } private: static unsigned long openssl_id_func() { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return ::GetCurrentThreadId(); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) void* id = instance()->thread_id_; if (id == 0) instance()->thread_id_ = id = &id; // Ugh. BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*)); return reinterpret_cast(id); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } static void openssl_locking_func(int mode, int n, const char* /*file*/, int /*line*/) { if (mode & CRYPTO_LOCK) instance()->mutexes_[n]->lock(); else instance()->mutexes_[n]->unlock(); } // Mutexes to be used in locking callbacks. std::vector > mutexes_; #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) // The thread identifiers to be used by openssl. asio::detail::tss_ptr thread_id_; #endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) }; public: // Constructor. openssl_init() : ref_(do_init::instance()) { using namespace std; // For memmove. // Ensure openssl_init::instance_ is linked in. openssl_init* tmp = &instance_; memmove(&tmp, &tmp, sizeof(openssl_init*)); } // Destructor. ~openssl_init() { } private: // Instance to force initialisation of openssl at global scope. static openssl_init instance_; // Reference to singleton do_init object to ensure that openssl does not get // cleaned up until the last user has finished with it. boost::shared_ptr ref_; }; template openssl_init openssl_init::instance_; } // namespace detail } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_INIT_HPP percona-galera-3-3.8-3390/asio/asio/ssl/detail/openssl_operation.hpp000077500000000000000000000323441244131713600252200ustar00rootroot00000000000000// // ssl/detail/openssl_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // // 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) // #ifndef ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP #define ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/buffer.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/placeholders.hpp" #include "asio/ssl/detail/openssl_types.hpp" #include "asio/strand.hpp" #include "asio/system_error.hpp" #include "asio/write.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { namespace detail { typedef boost::function ssl_primitive_func; typedef boost::function user_handler_func; // Network send_/recv buffer implementation // // class net_buffer { static const int NET_BUF_SIZE = 16*1024 + 256; // SSL record size + spare unsigned char buf_[NET_BUF_SIZE]; unsigned char* data_start_; unsigned char* data_end_; public: net_buffer() { data_start_ = data_end_ = buf_; } unsigned char* get_unused_start() { return data_end_; } unsigned char* get_data_start() { return data_start_; } size_t get_unused_len() { return (NET_BUF_SIZE - (data_end_ - buf_)); } size_t get_data_len() { return (data_end_ - data_start_); } void data_added(size_t count) { data_end_ += count; data_end_ = data_end_ > (buf_ + NET_BUF_SIZE)? (buf_ + NET_BUF_SIZE): data_end_; } void data_removed(size_t count) { data_start_ += count; if (data_start_ >= data_end_) reset(); } void reset() { data_start_ = buf_; data_end_ = buf_; } bool has_data() { return (data_start_ < data_end_); } }; // class net_buffer // // Operation class // // template class openssl_operation { public: // Constructor for asynchronous operations openssl_operation(ssl_primitive_func primitive, Stream& socket, net_buffer& recv_buf, SSL* session, BIO* ssl_bio, user_handler_func handler, asio::io_service::strand& strand ) : primitive_(primitive) , user_handler_(handler) , strand_(&strand) , recv_buf_(recv_buf) , socket_(socket) , ssl_bio_(ssl_bio) , session_(session) { write_ = boost::bind( &openssl_operation::do_async_write, this, boost::arg<1>(), boost::arg<2>() ); read_ = boost::bind( &openssl_operation::do_async_read, this ); handler_= boost::bind( &openssl_operation::async_user_handler, this, boost::arg<1>(), boost::arg<2>() ); } // Constructor for synchronous operations openssl_operation(ssl_primitive_func primitive, Stream& socket, net_buffer& recv_buf, SSL* session, BIO* ssl_bio) : primitive_(primitive) , strand_(0) , recv_buf_(recv_buf) , socket_(socket) , ssl_bio_(ssl_bio) , session_(session) { write_ = boost::bind( &openssl_operation::do_sync_write, this, boost::arg<1>(), boost::arg<2>() ); read_ = boost::bind( &openssl_operation::do_sync_read, this ); handler_ = boost::bind( &openssl_operation::sync_user_handler, this, boost::arg<1>(), boost::arg<2>() ); } // Start operation // In case of asynchronous it returns 0, in sync mode returns success code // or throws an error... int start() { int rc = primitive_( session_ ); bool is_operation_done = (rc > 0); // For connect/accept/shutdown, the operation // is done, when return code is 1 // for write, it is done, when is retcode > 0 // for read, is is done when retcode > 0 int error_code = !is_operation_done ? ::SSL_get_error( session_, rc ) : 0; int sys_error_code = ERR_get_error(); if (error_code == SSL_ERROR_SSL) return handler_(asio::error_code( sys_error_code, asio::error::get_ssl_category()), rc); bool is_read_needed = (error_code == SSL_ERROR_WANT_READ); bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE || ::BIO_ctrl_pending( ssl_bio_ )); bool is_shut_down_received = ((::SSL_get_shutdown( session_ ) & SSL_RECEIVED_SHUTDOWN) == SSL_RECEIVED_SHUTDOWN); bool is_shut_down_sent = ((::SSL_get_shutdown( session_ ) & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN); if (is_shut_down_sent && is_shut_down_received && is_operation_done && !is_write_needed) // SSL connection is shut down cleanly return handler_(asio::error_code(), 1); if (is_shut_down_received && !is_operation_done) // Shutdown has been requested, while we were reading or writing... // abort our action... return handler_(asio::error::shut_down, 0); if (!is_operation_done && !is_read_needed && !is_write_needed && !is_shut_down_sent) { // The operation has failed... It is not completed and does // not want network communication nor does want to send shutdown out... if (error_code == SSL_ERROR_SYSCALL) { return handler_(asio::error_code( sys_error_code, asio::error::system_category), rc); } else { return handler_(asio::error_code( sys_error_code, asio::error::get_ssl_category()), rc); } } if (!is_operation_done && !is_write_needed) { // We may have left over data that we can pass to SSL immediately if (recv_buf_.get_data_len() > 0) { // Pass the buffered data to SSL int written = ::BIO_write ( ssl_bio_, recv_buf_.get_data_start(), recv_buf_.get_data_len() ); if (written > 0) { recv_buf_.data_removed(written); } else if (written < 0) { if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... return handler_(asio::error::no_recovery, 0); } } return start(); } else if (is_read_needed || (is_shut_down_sent && !is_shut_down_received)) { return read_(); } } // Continue with operation, flush any SSL data out to network... return write_(is_operation_done, rc); } // Private implementation private: typedef boost::function int_handler_func; typedef boost::function write_func; typedef boost::function read_func; ssl_primitive_func primitive_; user_handler_func user_handler_; asio::io_service::strand* strand_; write_func write_; read_func read_; int_handler_func handler_; net_buffer send_buf_; // buffers for network IO // The recv buffer is owned by the stream, not the operation, since there can // be left over bytes after passing the data up to the application, and these // bytes need to be kept around for the next read operation issued by the // application. net_buffer& recv_buf_; Stream& socket_; BIO* ssl_bio_; SSL* session_; // int sync_user_handler(const asio::error_code& error, int rc) { if (!error) return rc; throw asio::system_error(error); } int async_user_handler(asio::error_code error, int rc) { if (rc < 0) { if (!error) error = asio::error::no_recovery; rc = 0; } user_handler_(error, rc); return 0; } // Writes bytes asynchronously from SSL to NET int do_async_write(bool is_operation_done, int rc) { int len = ::BIO_ctrl_pending( ssl_bio_ ); if ( len ) { // There is something to write into net, do it... len = (int)send_buf_.get_unused_len() > len? len: send_buf_.get_unused_len(); if (len == 0) { // In case our send buffer is full, we have just to wait until // previous send to complete... return 0; } // Read outgoing data from bio len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len); if (len > 0) { unsigned char *data_start = send_buf_.get_unused_start(); send_buf_.data_added(len); BOOST_ASSERT(strand_); asio::async_write ( socket_, asio::buffer(data_start, len), strand_->wrap ( boost::bind ( &openssl_operation::async_write_handler, this, is_operation_done, rc, asio::placeholders::error, asio::placeholders::bytes_transferred ) ) ); return 0; } else if (!BIO_should_retry(ssl_bio_)) { // Seems like fatal error // reading from SSL BIO has failed... handler_(asio::error::no_recovery, 0); return 0; } } if (is_operation_done) { // Finish the operation, with success handler_(asio::error_code(), rc); return 0; } // OPeration is not done and writing to net has been made... // start operation again start(); return 0; } void async_write_handler(bool is_operation_done, int rc, const asio::error_code& error, size_t bytes_sent) { if (!error) { // Remove data from send buffer send_buf_.data_removed(bytes_sent); if (is_operation_done) handler_(asio::error_code(), rc); else // Since the operation was not completed, try it again... start(); } else handler_(error, rc); } int do_async_read() { // Wait for new data BOOST_ASSERT(strand_); socket_.async_read_some ( asio::buffer(recv_buf_.get_unused_start(), recv_buf_.get_unused_len()), strand_->wrap ( boost::bind ( &openssl_operation::async_read_handler, this, asio::placeholders::error, asio::placeholders::bytes_transferred ) ) ); return 0; } void async_read_handler(const asio::error_code& error, size_t bytes_recvd) { if (!error) { recv_buf_.data_added(bytes_recvd); // Pass the received data to SSL int written = ::BIO_write ( ssl_bio_, recv_buf_.get_data_start(), recv_buf_.get_data_len() ); if (written > 0) { recv_buf_.data_removed(written); } else if (written < 0) { if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... handler_(asio::error::no_recovery, 0); return; } } // and try the SSL primitive again start(); } else { // Error in network level... // SSL can't continue either... handler_(error, 0); } } // Syncronous functions... int do_sync_write(bool is_operation_done, int rc) { int len = ::BIO_ctrl_pending( ssl_bio_ ); if ( len ) { // There is something to write into net, do it... len = (int)send_buf_.get_unused_len() > len? len: send_buf_.get_unused_len(); // Read outgoing data from bio len = ::BIO_read( ssl_bio_, send_buf_.get_unused_start(), len); if (len > 0) { size_t sent_len = asio::write( socket_, asio::buffer(send_buf_.get_unused_start(), len) ); send_buf_.data_added(len); send_buf_.data_removed(sent_len); } else if (!BIO_should_retry(ssl_bio_)) { // Seems like fatal error // reading from SSL BIO has failed... throw asio::system_error(asio::error::no_recovery); } } if (is_operation_done) // Finish the operation, with success return rc; // Operation is not finished, start again. return start(); } int do_sync_read() { size_t len = socket_.read_some ( asio::buffer(recv_buf_.get_unused_start(), recv_buf_.get_unused_len()) ); // Write data to ssl recv_buf_.data_added(len); // Pass the received data to SSL int written = ::BIO_write ( ssl_bio_, recv_buf_.get_data_start(), recv_buf_.get_data_len() ); if (written > 0) { recv_buf_.data_removed(written); } else if (written < 0) { if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... throw asio::system_error(asio::error::no_recovery); } } // Try the operation again return start(); } }; // class openssl_operation } // namespace detail } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_OPERATION_HPP percona-galera-3-3.8-3390/asio/asio/ssl/detail/openssl_stream_service.hpp000066400000000000000000000355631244131713600262360ustar00rootroot00000000000000// // ssl/detail/stream_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP #define ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include #include #include #include "asio/detail/buffer_sequence_adapter.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/detail/openssl_operation.hpp" #include "asio/ssl/detail/openssl_types.hpp" #include "asio/strand.hpp" #include "asio/system_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { namespace detail { class openssl_stream_service : public asio::detail::service_base { private: enum { max_buffer_size = INT_MAX }; //Base handler for asyncrhonous operations template class base_handler { public: typedef boost::function< void (const asio::error_code&, size_t)> func_t; base_handler(asio::io_service& io_service) : op_(NULL) , io_service_(io_service) , work_(io_service) {} void do_func(const asio::error_code& error, size_t size) { func_(error, size); } void set_operation(openssl_operation* op) { op_ = op; } void set_func(func_t func) { func_ = func; } ~base_handler() { delete op_; } private: func_t func_; openssl_operation* op_; asio::io_service& io_service_; asio::io_service::work work_; }; // class base_handler // Handler for asynchronous IO (write/read) operations template class io_handler : public base_handler { public: io_handler(Handler handler, asio::io_service& io_service) : base_handler(io_service) , handler_(handler) { this->set_func(boost::bind( &io_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } private: Handler handler_; void handler_impl(const asio::error_code& error, size_t size) { std::auto_ptr > this_ptr(this); handler_(error, size); } }; // class io_handler // Handler for asyncrhonous handshake (connect, accept) functions template class handshake_handler : public base_handler { public: handshake_handler(Handler handler, asio::io_service& io_service) : base_handler(io_service) , handler_(handler) { this->set_func(boost::bind( &handshake_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } private: Handler handler_; void handler_impl(const asio::error_code& error, size_t) { std::auto_ptr > this_ptr(this); handler_(error); } }; // class handshake_handler // Handler for asyncrhonous shutdown template class shutdown_handler : public base_handler { public: shutdown_handler(Handler handler, asio::io_service& io_service) : base_handler(io_service), handler_(handler) { this->set_func(boost::bind( &shutdown_handler::handler_impl, this, boost::arg<1>(), boost::arg<2>() )); } private: Handler handler_; void handler_impl(const asio::error_code& error, size_t) { std::auto_ptr > this_ptr(this); handler_(error); } }; // class shutdown_handler public: // The implementation type. typedef struct impl_struct { ::SSL* ssl; ::BIO* ext_bio; net_buffer recv_buf; } * impl_type; // Construct a new stream socket service for the specified io_service. explicit openssl_stream_service(asio::io_service& io_service) : asio::detail::service_base(io_service), strand_(io_service) { } // Destroy all user-defined handler objects owned by the service. void shutdown_service() { } // Return a null stream implementation. impl_type null() const { return 0; } // Create a new stream implementation. template void create(impl_type& impl, Stream& /*next_layer*/, basic_context& context) { impl = new impl_struct; impl->ssl = ::SSL_new(context.impl()); ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); ::BIO* int_bio = 0; impl->ext_bio = 0; ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); ::SSL_set_bio(impl->ssl, int_bio, int_bio); } // Destroy a stream implementation. template void destroy(impl_type& impl, Stream& /*next_layer*/) { if (impl != 0) { ::BIO_free(impl->ext_bio); ::SSL_free(impl->ssl); delete impl; impl = 0; } } // Perform SSL handshaking. template asio::error_code handshake(impl_type& impl, Stream& next_layer, stream_base::handshake_type type, asio::error_code& ec) { try { openssl_operation op( type == stream_base::client ? &ssl_wrap::SSL_connect: &ssl_wrap::SSL_accept, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio); op.start(); } catch (asio::system_error& e) { ec = e.code(); return ec; } ec = asio::error_code(); return ec; } // Start an asynchronous SSL handshake. template void async_handshake(impl_type& impl, Stream& next_layer, stream_base::handshake_type type, Handler handler) { typedef handshake_handler connect_handler; connect_handler* local_handler = new connect_handler(handler, get_io_service()); openssl_operation* op = new openssl_operation ( type == stream_base::client ? &ssl_wrap::SSL_connect: &ssl_wrap::SSL_accept, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio, boost::bind ( &base_handler::do_func, local_handler, boost::arg<1>(), boost::arg<2>() ), strand_ ); local_handler->set_operation(op); strand_.post(boost::bind(&openssl_operation::start, op)); } // Shut down SSL on the stream. template asio::error_code shutdown(impl_type& impl, Stream& next_layer, asio::error_code& ec) { try { openssl_operation op( &ssl_wrap::SSL_shutdown, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio); op.start(); } catch (asio::system_error& e) { ec = e.code(); return ec; } ec = asio::error_code(); return ec; } // Asynchronously shut down SSL on the stream. template void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) { typedef shutdown_handler disconnect_handler; disconnect_handler* local_handler = new disconnect_handler(handler, get_io_service()); openssl_operation* op = new openssl_operation ( &ssl_wrap::SSL_shutdown, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio, boost::bind ( &base_handler::do_func, local_handler, boost::arg<1>(), boost::arg<2>() ), strand_ ); local_handler->set_operation(op); strand_.post(boost::bind(&openssl_operation::start, op)); } // Write some data to the stream. template std::size_t write_some(impl_type& impl, Stream& next_layer, const Const_Buffers& buffers, asio::error_code& ec) { size_t bytes_transferred = 0; try { asio::const_buffer buffer = asio::detail::buffer_sequence_adapter< asio::const_buffer, Const_Buffers>::first(buffers); std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > max_buffer_size) buffer_size = max_buffer_size; else if (buffer_size == 0) { ec = asio::error_code(); return 0; } boost::function send_func = boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation op( send_func, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio ); bytes_transferred = static_cast(op.start()); } catch (asio::system_error& e) { ec = e.code(); return 0; } ec = asio::error_code(); return bytes_transferred; } // Start an asynchronous write. template void async_write_some(impl_type& impl, Stream& next_layer, const Const_Buffers& buffers, Handler handler) { typedef io_handler send_handler; asio::const_buffer buffer = asio::detail::buffer_sequence_adapter< asio::const_buffer, Const_Buffers>::first(buffers); std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > max_buffer_size) buffer_size = max_buffer_size; else if (buffer_size == 0) { get_io_service().post(asio::detail::bind_handler( handler, asio::error_code(), 0)); return; } send_handler* local_handler = new send_handler(handler, get_io_service()); boost::function send_func = boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation* op = new openssl_operation ( send_func, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio, boost::bind ( &base_handler::do_func, local_handler, boost::arg<1>(), boost::arg<2>() ), strand_ ); local_handler->set_operation(op); strand_.post(boost::bind(&openssl_operation::start, op)); } // Read some data from the stream. template std::size_t read_some(impl_type& impl, Stream& next_layer, const Mutable_Buffers& buffers, asio::error_code& ec) { size_t bytes_transferred = 0; try { asio::mutable_buffer buffer = asio::detail::buffer_sequence_adapter< asio::mutable_buffer, Mutable_Buffers>::first(buffers); std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > max_buffer_size) buffer_size = max_buffer_size; else if (buffer_size == 0) { ec = asio::error_code(); return 0; } boost::function recv_func = boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation op(recv_func, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio ); bytes_transferred = static_cast(op.start()); } catch (asio::system_error& e) { ec = e.code(); return 0; } ec = asio::error_code(); return bytes_transferred; } // Start an asynchronous read. template void async_read_some(impl_type& impl, Stream& next_layer, const Mutable_Buffers& buffers, Handler handler) { typedef io_handler recv_handler; asio::mutable_buffer buffer = asio::detail::buffer_sequence_adapter< asio::mutable_buffer, Mutable_Buffers>::first(buffers); std::size_t buffer_size = asio::buffer_size(buffer); if (buffer_size > max_buffer_size) buffer_size = max_buffer_size; else if (buffer_size == 0) { get_io_service().post(asio::detail::bind_handler( handler, asio::error_code(), 0)); return; } recv_handler* local_handler = new recv_handler(handler, get_io_service()); boost::function recv_func = boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), asio::buffer_cast(buffer), static_cast(buffer_size)); openssl_operation* op = new openssl_operation ( recv_func, next_layer, impl->recv_buf, impl->ssl, impl->ext_bio, boost::bind ( &base_handler::do_func, local_handler, boost::arg<1>(), boost::arg<2>() ), strand_ ); local_handler->set_operation(op); strand_.post(boost::bind(&openssl_operation::start, op)); } // Peek at the incoming data on the stream. template std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, const Mutable_Buffers& /*buffers*/, asio::error_code& ec) { ec = asio::error_code(); return 0; } // Determine the amount of data that may be read without blocking. template std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, asio::error_code& ec) { ec = asio::error_code(); return 0; } private: asio::io_service::strand strand_; typedef asio::detail::mutex mutex_type; template struct ssl_wrap { static Mutex ssl_mutex_; static int SSL_accept(SSL *ssl) { typename Mutex::scoped_lock lock(ssl_mutex_); return ::SSL_accept(ssl); } static int SSL_connect(SSL *ssl) { typename Mutex::scoped_lock lock(ssl_mutex_); return ::SSL_connect(ssl); } static int SSL_shutdown(SSL *ssl) { typename Mutex::scoped_lock lock(ssl_mutex_); return ::SSL_shutdown(ssl); } }; }; template Mutex openssl_stream_service::ssl_wrap::ssl_mutex_; } // namespace detail } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_STREAM_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/ssl/detail/openssl_types.hpp000077500000000000000000000013261244131713600243600ustar00rootroot00000000000000// // ssl/detail/openssl_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP #define ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/detail/socket_types.hpp" #endif // ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP percona-galera-3-3.8-3390/asio/asio/ssl/stream.hpp000066400000000000000000000414211244131713600214770ustar00rootroot00000000000000// // ssl/stream.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_STREAM_HPP #define ASIO_SSL_STREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/stream_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// Provides stream-oriented functionality using SSL. /** * The stream class template provides asynchronous and blocking stream-oriented * functionality using SSL. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Example * To use the SSL stream template with an ip::tcp::socket, you would write: * @code * asio::io_service io_service; * asio::ssl::context context(io_service, asio::ssl::context::sslv23); * asio::ssl::stream sock(io_service, context); * @endcode * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncRead_Stream, SyncWriteStream. */ template class stream : public stream_base, private boost::noncopyable { public: /// The type of the next layer. typedef typename boost::remove_reference::type next_layer_type; /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; /// The type of the service that will be used to provide stream operations. typedef Service service_type; /// The native implementation type of the stream. typedef typename service_type::impl_type impl_type; /// Construct a stream. /** * This constructor creates a stream and initialises the underlying stream * object. * * @param arg The argument to be passed to initialise the underlying stream. * * @param context The SSL context to be used for the stream. */ template explicit stream(Arg& arg, basic_context& context) : next_layer_(arg), service_(asio::use_service(next_layer_.get_io_service())), impl_(service_.null()) { service_.create(impl_, next_layer_, context); } /// Destructor. ~stream() { service_.destroy(impl_, next_layer_); } /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. /** * This function may be used to obtain the io_service object that the stream * uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that stream will use to * dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& io_service() { return next_layer_.get_io_service(); } /// Get the io_service associated with the object. /** * This function may be used to obtain the io_service object that the stream * uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that stream will use to * dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& get_io_service() { return next_layer_.get_io_service(); } /// Get a reference to the next layer. /** * This function returns a reference to the next layer in a stack of stream * layers. * * @return A reference to the next layer in the stack of stream layers. * Ownership is not transferred to the caller. */ next_layer_type& next_layer() { return next_layer_; } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * stream layers. * * @return A reference to the lowest layer in the stack of stream layers. * Ownership is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return next_layer_.lowest_layer(); } /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of * stream layers. * * @return A const reference to the lowest layer in the stack of stream * layers. Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return next_layer_.lowest_layer(); } /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * context. This is intended to allow access to stream functionality that is * not otherwise provided. */ impl_type impl() { return impl_; } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @throws asio::system_error Thrown on failure. */ void handshake(handshake_type type) { asio::error_code ec; service_.handshake(impl_, next_layer_, type, ec); asio::detail::throw_error(ec); } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code handshake(handshake_type type, asio::error_code& ec) { return service_.handshake(impl_, next_layer_, type, ec); } /// Start an asynchronous SSL handshake. /** * This function is used to asynchronously perform an SSL handshake on the * stream. This function call always returns immediately. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param handler The handler to be called when the handshake operation * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode */ template void async_handshake(handshake_type type, HandshakeHandler handler) { service_.async_handshake(impl_, next_layer_, type, handler); } /// Shut down SSL on the stream. /** * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * * @throws asio::system_error Thrown on failure. */ void shutdown() { asio::error_code ec; service_.shutdown(impl_, next_layer_, ec); asio::detail::throw_error(ec); } /// Shut down SSL on the stream. /** * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code shutdown(asio::error_code& ec) { return service_.shutdown(impl_, next_layer_, ec); } /// Asynchronously shut down SSL on the stream. /** * This function is used to asynchronously shut down SSL on the stream. This * function call always returns immediately. * * @param handler The handler to be called when the handshake operation * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( * const asio::error_code& error // Result of operation. * ); @endcode */ template void async_shutdown(ShutdownHandler handler) { service_.async_shutdown(impl_, next_layer_, handler); } /// Write some data to the stream. /** * This function is used to write data on the stream. The function call will * block until one or more bytes of data has been written successfully, or * until an error occurs. * * @param buffers The data to be written. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that all * data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = service_.write_some(impl_, next_layer_, buffers, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the stream. /** * This function is used to write data on the stream. The function call will * block until one or more bytes of data has been written successfully, or * until an error occurs. * * @param buffers The data to be written to the stream. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that all * data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return service_.write_some(impl_, next_layer_, buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write one or more bytes of data to * the stream. The function call always returns immediately. * * @param buffers The data to be written to the stream. Although the buffers * object may be copied as necessary, ownership of the underlying buffers is * retained by the caller, which must guarantee that they remain valid until * the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The equivalent function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * * @note The async_write_some operation may not transmit all of the data to * the peer. Consider using the @ref async_write function if you need to * ensure that all data is written before the blocking operation completes. */ template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { service_.async_write_some(impl_, next_layer_, buffers, handler); } /// Read some data from the stream. /** * This function is used to read data from the stream. The function call will * block until one or more bytes of data has been read successfully, or until * an error occurs. * * @param buffers The buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ template std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = service_.read_some(impl_, next_layer_, buffers, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the stream. /** * This function is used to read data from the stream. The function call will * block until one or more bytes of data has been read successfully, or until * an error occurs. * * @param buffers The buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return service_.read_some(impl_, next_layer_, buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read one or more bytes of data from * the stream. The function call always returns immediately. * * @param buffers The buffers into which the data will be read. Although the * buffers object may be copied as necessary, ownership of the underlying * buffers is retained by the caller, which must guarantee that they remain * valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The equivalent function * signature of the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * * @note The async_read_some operation may not read all of the requested * number of bytes. Consider using the @ref async_read function if you need to * ensure that the requested amount of data is read before the asynchronous * operation completes. */ template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { service_.async_read_some(impl_, next_layer_, buffers, handler); } /// Peek at the incoming data on the stream. /** * This function is used to peek at the incoming data on the stream, without * removing it from the input queue. The function call will block until data * has been read successfully or an error occurs. * * @param buffers The buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. */ template std::size_t peek(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = service_.peek(impl_, next_layer_, buffers, ec); asio::detail::throw_error(ec); return s; } /// Peek at the incoming data on the stream. /** * This function is used to peek at the incoming data on the stream, withoutxi * removing it from the input queue. The function call will block until data * has been read successfully or an error occurs. * * @param buffers The buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. */ template std::size_t peek(const MutableBufferSequence& buffers, asio::error_code& ec) { return service_.peek(impl_, next_layer_, buffers, ec); } /// Determine the amount of data that may be read without blocking. /** * This function is used to determine the amount of data, in bytes, that may * be read from the stream without blocking. * * @returns The number of bytes of data that can be read without blocking. * * @throws asio::system_error Thrown on failure. */ std::size_t in_avail() { asio::error_code ec; std::size_t s = service_.in_avail(impl_, next_layer_, ec); asio::detail::throw_error(ec); return s; } /// Determine the amount of data that may be read without blocking. /** * This function is used to determine the amount of data, in bytes, that may * be read from the stream without blocking. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes of data that can be read without blocking. */ std::size_t in_avail(asio::error_code& ec) { return service_.in_avail(impl_, next_layer_, ec); } private: /// The next layer. Stream next_layer_; /// The backend service implementation. service_type& service_; /// The underlying native implementation. impl_type impl_; }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_STREAM_HPP percona-galera-3-3.8-3390/asio/asio/ssl/stream_base.hpp000077500000000000000000000025001244131713600224670ustar00rootroot00000000000000// // ssl/stream_base.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_STREAM_BASE_HPP #define ASIO_SSL_STREAM_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// The stream_base class is used as a base for the asio::ssl::stream /// class template so that we have a common place to define various enums. class stream_base { public: /// Different handshake types. enum handshake_type { /// Perform handshaking as a client. client, /// Perform handshaking as a server. server }; protected: /// Protected destructor to prevent deletion through this type. ~stream_base() { } #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) private: // Workaround to enable the empty base optimisation with Borland C++. char dummy_; #endif }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_STREAM_BASE_HPP percona-galera-3-3.8-3390/asio/asio/ssl/stream_service.hpp000066400000000000000000000126411244131713600232210ustar00rootroot00000000000000// // ssl/stream_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SSL_STREAM_SERVICE_HPP #define ASIO_SSL_STREAM_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/io_service.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/detail/openssl_stream_service.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace ssl { /// Default service implementation for an SSL stream. class stream_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { private: // The type of the platform-specific implementation. typedef detail::openssl_stream_service service_impl_type; public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The type of a stream implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined impl_type; #else typedef service_impl_type::impl_type impl_type; #endif /// Construct a new stream service for the specified io_service. explicit stream_service(asio::io_service& io_service) : asio::detail::service_base(io_service), service_impl_(asio::use_service(io_service)) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { } /// Return a null stream implementation. impl_type null() const { return service_impl_.null(); } /// Create a new stream implementation. template void create(impl_type& impl, Stream& next_layer, basic_context& context) { service_impl_.create(impl, next_layer, context); } /// Destroy a stream implementation. template void destroy(impl_type& impl, Stream& next_layer) { service_impl_.destroy(impl, next_layer); } /// Perform SSL handshaking. template asio::error_code handshake(impl_type& impl, Stream& next_layer, stream_base::handshake_type type, asio::error_code& ec) { return service_impl_.handshake(impl, next_layer, type, ec); } /// Start an asynchronous SSL handshake. template void async_handshake(impl_type& impl, Stream& next_layer, stream_base::handshake_type type, HandshakeHandler handler) { service_impl_.async_handshake(impl, next_layer, type, handler); } /// Shut down SSL on the stream. template asio::error_code shutdown(impl_type& impl, Stream& next_layer, asio::error_code& ec) { return service_impl_.shutdown(impl, next_layer, ec); } /// Asynchronously shut down SSL on the stream. template void async_shutdown(impl_type& impl, Stream& next_layer, ShutdownHandler handler) { service_impl_.async_shutdown(impl, next_layer, handler); } /// Write some data to the stream. template std::size_t write_some(impl_type& impl, Stream& next_layer, const ConstBufferSequence& buffers, asio::error_code& ec) { return service_impl_.write_some(impl, next_layer, buffers, ec); } /// Start an asynchronous write. template void async_write_some(impl_type& impl, Stream& next_layer, const ConstBufferSequence& buffers, WriteHandler handler) { service_impl_.async_write_some(impl, next_layer, buffers, handler); } /// Read some data from the stream. template std::size_t read_some(impl_type& impl, Stream& next_layer, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.read_some(impl, next_layer, buffers, ec); } /// Start an asynchronous read. template void async_read_some(impl_type& impl, Stream& next_layer, const MutableBufferSequence& buffers, ReadHandler handler) { service_impl_.async_read_some(impl, next_layer, buffers, handler); } /// Peek at the incoming data on the stream. template std::size_t peek(impl_type& impl, Stream& next_layer, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.peek(impl, next_layer, buffers, ec); } /// Determine the amount of data that may be read without blocking. template std::size_t in_avail(impl_type& impl, Stream& next_layer, asio::error_code& ec) { return service_impl_.in_avail(impl, next_layer, ec); } private: // The service that provides the platform-specific implementation. service_impl_type& service_impl_; }; } // namespace ssl } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SSL_STREAM_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/strand.hpp000066400000000000000000000166241244131713600207050ustar00rootroot00000000000000// // strand.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_STRAND_HPP #define ASIO_STRAND_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/strand_service.hpp" #include "asio/detail/wrapped_handler.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Provides serialised handler execution. /** * The io_service::strand class provides the ability to post and dispatch * handlers with the guarantee that none of those handlers will execute * concurrently. * * @par Order of handler invocation * Given: * * @li a strand object @c s * * @li an object @c a meeting completion handler requirements * * @li an object @c a1 which is an arbitrary copy of @c a made by the * implementation * * @li an object @c b meeting completion handler requirements * * @li an object @c b1 which is an arbitrary copy of @c b made by the * implementation * * if any of the following conditions are true: * * @li @c s.post(a) happens-before @c s.post(b) * * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is * performed outside the strand * * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is * performed outside the strand * * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are * performed outside the strand * * then @c asio_handler_invoke(a1, &a1) happens-before * @c asio_handler_invoke(b1, &b1). * * Note that in the following case: * @code async_op_1(..., s.wrap(a)); * async_op_2(..., s.wrap(b)); @endcode * the completion of the first async operation will perform @c s.dispatch(a), * and the second will perform @c s.dispatch(b), but the order in which those * are performed is unspecified. That is, you cannot state whether one * happens-before the other. Therefore none of the above conditions are met and * no ordering guarantee is made. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: * Dispatcher. */ class io_service::strand { public: /// Constructor. /** * Constructs the strand. * * @param io_service The io_service object that the strand will use to * dispatch handlers that are ready to be run. */ explicit strand(asio::io_service& io_service) : service_(asio::use_service< asio::detail::strand_service>(io_service)) { service_.construct(impl_); } /// Destructor. /** * Destroys a strand. * * Handlers posted through the strand that have not yet been invoked will * still be dispatched in a way that meets the guarantee of non-concurrency. */ ~strand() { service_.destroy(impl_); } /// (Deprecated: use get_io_service().) Get the io_service associated with /// the strand. /** * This function may be used to obtain the io_service object that the strand * uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that the strand will use to * dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& io_service() { return service_.get_io_service(); } /// Get the io_service associated with the strand. /** * This function may be used to obtain the io_service object that the strand * uses to dispatch handlers for asynchronous operations. * * @return A reference to the io_service object that the strand will use to * dispatch handlers. Ownership is not transferred to the caller. */ asio::io_service& get_io_service() { return service_.get_io_service(); } /// Request the strand to invoke the given handler. /** * This function is used to ask the strand to execute the given handler. * * The strand object guarantees that handlers posted or dispatched through * the strand will not be executed concurrently. The handler may be executed * inside this function if the guarantee can be met. If this function is * called from within a handler that was posted or dispatched through the same * strand, then the new handler will be executed immediately. * * The strand's guarantee is in addition to the guarantee provided by the * underlying io_service. The io_service guarantees that the handler will only * be called in a thread in which the io_service's run member function is * currently being invoked. * * @param handler The handler to be called. The strand will make a copy of the * handler object as required. The function signature of the handler must be: * @code void handler(); @endcode */ template void dispatch(Handler handler) { service_.dispatch(impl_, handler); } /// Request the strand to invoke the given handler and return /// immediately. /** * This function is used to ask the strand to execute the given handler, but * without allowing the strand to call the handler from inside this function. * * The strand object guarantees that handlers posted or dispatched through * the strand will not be executed concurrently. The strand's guarantee is in * addition to the guarantee provided by the underlying io_service. The * io_service guarantees that the handler will only be called in a thread in * which the io_service's run member function is currently being invoked. * * @param handler The handler to be called. The strand will make a copy of the * handler object as required. The function signature of the handler must be: * @code void handler(); @endcode */ template void post(Handler handler) { service_.post(impl_, handler); } /// Create a new handler that automatically dispatches the wrapped handler /// on the strand. /** * This function is used to create a new handler function object that, when * invoked, will automatically pass the wrapped handler to the strand's * dispatch function. * * @param handler The handler to be wrapped. The strand will make a copy of * the handler object as required. The function signature of the handler must * be: @code void handler(A1 a1, ... An an); @endcode * * @return A function object that, when invoked, passes the wrapped handler to * the strand's dispatch function. Given a function object with the signature: * @code R f(A1 a1, ... An an); @endcode * If this function object is passed to the wrap function like so: * @code strand.wrap(f); @endcode * then the return value is a function object with the signature * @code void g(A1 a1, ... An an); @endcode * that, when invoked, executes code equivalent to: * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode */ template #if defined(GENERATING_DOCUMENTATION) unspecified #else detail::wrapped_handler #endif wrap(Handler handler) { return detail::wrapped_handler(*this, handler); } private: asio::detail::strand_service& service_; asio::detail::strand_service::implementation_type impl_; }; /// Typedef for backwards compatibility. typedef asio::io_service::strand strand; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_STRAND_HPP percona-galera-3-3.8-3390/asio/asio/stream_socket_service.hpp000066400000000000000000000173721244131713600237760ustar00rootroot00000000000000// // stream_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_STREAM_SOCKET_SERVICE_HPP #define ASIO_STREAM_SOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/error.hpp" #include "asio/io_service.hpp" #if defined(ASIO_HAS_IOCP) # include "asio/detail/win_iocp_socket_service.hpp" #else # include "asio/detail/reactive_socket_service.hpp" #endif #include "asio/detail/push_options.hpp" namespace asio { /// Default service implementation for a stream socket. template class stream_socket_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base > #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif /// The protocol type. typedef Protocol protocol_type; /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_socket_service service_impl_type; #else typedef detail::reactive_socket_service service_impl_type; #endif public: /// The type of a stream socket implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef typename service_impl_type::implementation_type implementation_type; #endif /// The native socket type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef typename service_impl_type::native_type native_type; #endif /// Construct a new stream socket service for the specified io_service. explicit stream_socket_service(asio::io_service& io_service) : asio::detail::service_base< stream_socket_service >(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new stream socket implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a stream socket implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Open a stream socket. asio::error_code open(implementation_type& impl, const protocol_type& protocol, asio::error_code& ec) { if (protocol.type() == SOCK_STREAM) service_impl_.open(impl, protocol, ec); else ec = asio::error::invalid_argument; return ec; } /// Assign an existing native socket to a stream socket. asio::error_code assign(implementation_type& impl, const protocol_type& protocol, const native_type& native_socket, asio::error_code& ec) { return service_impl_.assign(impl, protocol, native_socket, ec); } /// Determine whether the socket is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a stream socket implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native socket implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the socket. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Determine whether the socket is at the out-of-band data mark. bool at_mark(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.at_mark(impl, ec); } /// Determine the number of bytes available for reading. std::size_t available(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.available(impl, ec); } /// Bind the stream socket to the specified local endpoint. asio::error_code bind(implementation_type& impl, const endpoint_type& endpoint, asio::error_code& ec) { return service_impl_.bind(impl, endpoint, ec); } /// Connect the stream socket to the specified endpoint. asio::error_code connect(implementation_type& impl, const endpoint_type& peer_endpoint, asio::error_code& ec) { return service_impl_.connect(impl, peer_endpoint, ec); } /// Start an asynchronous connect. template void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, ConnectHandler handler) { service_impl_.async_connect(impl, peer_endpoint, handler); } /// Set a socket option. template asio::error_code set_option(implementation_type& impl, const SettableSocketOption& option, asio::error_code& ec) { return service_impl_.set_option(impl, option, ec); } /// Get a socket option. template asio::error_code get_option(const implementation_type& impl, GettableSocketOption& option, asio::error_code& ec) const { return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. template asio::error_code io_control(implementation_type& impl, IoControlCommand& command, asio::error_code& ec) { return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.local_endpoint(impl, ec); } /// Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, asio::error_code& ec) const { return service_impl_.remote_endpoint(impl, ec); } /// Disable sends or receives on the socket. asio::error_code shutdown(implementation_type& impl, socket_base::shutdown_type what, asio::error_code& ec) { return service_impl_.shutdown(impl, what, ec); } /// Send the given data to the peer. template std::size_t send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.send(impl, buffers, flags, ec); } /// Start an asynchronous send. template void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send(impl, buffers, flags, handler); } /// Receive some data from the peer. template std::size_t receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive(impl, buffers, flags, ec); } /// Start an asynchronous receive. template void async_receive(implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive(impl, buffers, flags, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_STREAM_SOCKET_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/streambuf.hpp000066400000000000000000000013531244131713600213730ustar00rootroot00000000000000// // streambuf.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_STREAMBUF_HPP #define ASIO_STREAMBUF_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(BOOST_NO_IOSTREAM) #include "asio/basic_streambuf.hpp" namespace asio { /// Typedef for the typical usage of basic_streambuf. typedef basic_streambuf<> streambuf; } // namespace asio #endif // !defined(BOOST_NO_IOSTREAM) #endif // ASIO_STREAMBUF_HPP percona-galera-3-3.8-3390/asio/asio/system_error.hpp000066400000000000000000000047571244131713600221530ustar00rootroot00000000000000// // system_error.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_SYSTEM_ERROR_HPP #define ASIO_SYSTEM_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include #include #include "asio/error_code.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// The system_error class is used to represent system conditions that /// prevent the library from operating correctly. class system_error : public std::exception { public: /// Construct with an error code. system_error(const error_code& code) : code_(code), context_() { } /// Construct with an error code and context. system_error(const error_code& code, const std::string& context) : code_(code), context_(context) { } /// Copy constructor. system_error(const system_error& other) : std::exception(other), code_(other.code_), context_(other.context_), what_() { } /// Destructor. virtual ~system_error() throw () { } /// Assignment operator. system_error& operator=(const system_error& e) { context_ = e.context_; code_ = e.code_; what_.reset(); return *this; } /// Get a string representation of the exception. virtual const char* what() const throw () { #if !defined(BOOST_NO_EXCEPTIONS) try #endif // !defined(BOOST_NO_EXCEPTIONS) { if (!what_) { std::string tmp(context_); if (tmp.length()) tmp += ": "; tmp += code_.message(); what_.reset(new std::string(tmp)); } return what_->c_str(); } #if !defined(BOOST_NO_EXCEPTIONS) catch (std::exception&) { return "system_error"; } #endif // !defined(BOOST_NO_EXCEPTIONS) } /// Get the error code associated with the exception. error_code code() const { return code_; } private: // The code associated with the error. error_code code_; // The context associated with the error. std::string context_; // The string representation of the error. mutable boost::scoped_ptr what_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_SYSTEM_ERROR_HPP percona-galera-3-3.8-3390/asio/asio/thread.hpp000066400000000000000000000044051244131713600206530ustar00rootroot00000000000000// // thread.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_THREAD_HPP #define ASIO_THREAD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/thread.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// A simple abstraction for starting threads. /** * The asio::thread class implements the smallest possible subset of the * functionality of boost::thread. It is intended to be used only for starting * a thread and waiting for it to exit. If more extensive threading * capabilities are required, you are strongly advised to use something else. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Example * A typical use of asio::thread would be to launch a thread to run an * io_service's event processing loop: * * @par * @code asio::io_service io_service; * // ... * asio::thread t(boost::bind(&asio::io_service::run, &io_service)); * // ... * t.join(); @endcode */ class thread : private noncopyable { public: /// Start a new thread that executes the supplied function. /** * This constructor creates a new thread that will execute the given function * or function object. * * @param f The function or function object to be run in the thread. The * function signature must be: @code void f(); @endcode */ template explicit thread(Function f) : impl_(f) { } /// Destructor. ~thread() { } /// Wait for the thread to exit. /** * This function will block until the thread has exited. * * If this function is not called before the thread object is destroyed, the * thread itself will continue to run until completion. You will, however, * no longer have the ability to wait for it to exit. */ void join() { impl_.join(); } private: detail::thread impl_; }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_THREAD_HPP percona-galera-3-3.8-3390/asio/asio/time_traits.hpp000066400000000000000000000040651244131713600217320ustar00rootroot00000000000000// // time_traits.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_TIME_TRAITS_HPP #define ASIO_TIME_TRAITS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/socket_types.hpp" // Must come before posix_time. #include "asio/detail/push_options.hpp" #include #include "asio/detail/pop_options.hpp" #include "asio/detail/push_options.hpp" namespace asio { /// Time traits suitable for use with the deadline timer. template struct time_traits; /// Time traits specialised for posix_time. template <> struct time_traits { /// The time type. typedef boost::posix_time::ptime time_type; /// The duration type. typedef boost::posix_time::time_duration duration_type; /// Get the current time. static time_type now() { #if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) return boost::posix_time::microsec_clock::universal_time(); #else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) return boost::posix_time::second_clock::universal_time(); #endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) } /// Add a duration to a time. static time_type add(const time_type& t, const duration_type& d) { return t + d; } /// Subtract one time from another. static duration_type subtract(const time_type& t1, const time_type& t2) { return t1 - t2; } /// Test whether one time is less than another. static bool less_than(const time_type& t1, const time_type& t2) { return t1 < t2; } /// Convert to POSIX duration type. static boost::posix_time::time_duration to_posix_duration( const duration_type& d) { return d; } }; } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_TIME_TRAITS_HPP percona-galera-3-3.8-3390/asio/asio/version.hpp000066400000000000000000000012031244131713600210620ustar00rootroot00000000000000// // version.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_VERSION_HPP #define ASIO_VERSION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) // ASIO_VERSION % 100 is the sub-minor version // ASIO_VERSION / 100 % 1000 is the minor version // ASIO_VERSION / 100000 is the major version #define ASIO_VERSION 100408 // 1.4.8 #endif // ASIO_VERSION_HPP percona-galera-3-3.8-3390/asio/asio/windows/000077500000000000000000000000001244131713600203625ustar00rootroot00000000000000percona-galera-3-3.8-3390/asio/asio/windows/basic_handle.hpp000066400000000000000000000153161244131713600234750ustar00rootroot00000000000000// // windows/basic_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_BASIC_HANDLE_HPP #define ASIO_WINDOWS_BASIC_HANDLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include "asio/basic_io_object.hpp" #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Provides Windows handle functionality. /** * The windows::basic_handle class template provides the ability to wrap a * Windows handle. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_handle : public basic_io_object { public: /// The native representation of a handle. typedef typename HandleService::native_type native_type; /// A basic_handle is always the lowest layer. typedef basic_handle lowest_layer_type; /// Construct a basic_handle without opening it. /** * This constructor creates a handle without opening it. * * @param io_service The io_service object that the handle will use to * dispatch handlers for any asynchronous operations performed on the handle. */ explicit basic_handle(asio::io_service& io_service) : basic_io_object(io_service) { } /// Construct a basic_handle on an existing native handle. /** * This constructor creates a handle object to hold an existing native handle. * * @param io_service The io_service object that the handle will use to * dispatch handlers for any asynchronous operations performed on the handle. * * @param native_handle A native handle. * * @throws asio::system_error Thrown on failure. */ basic_handle(asio::io_service& io_service, const native_type& native_handle) : basic_io_object(io_service) { asio::error_code ec; this->service.assign(this->implementation, native_handle, ec); asio::detail::throw_error(ec); } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * layers. Since a basic_handle cannot contain any further layers, it simply * returns a reference to itself. * * @return A reference to the lowest layer in the stack of layers. Ownership * is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return *this; } /// Get a const reference to the lowest layer. /** * This function returns a const reference to the lowest layer in a stack of * layers. Since a basic_handle cannot contain any further layers, it simply * returns a reference to itself. * * @return A const reference to the lowest layer in the stack of layers. * Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return *this; } /// Assign an existing native handle to the handle. /* * This function opens the handle to hold an existing native handle. * * @param native_handle A native handle. * * @throws asio::system_error Thrown on failure. */ void assign(const native_type& native_handle) { asio::error_code ec; this->service.assign(this->implementation, native_handle, ec); asio::detail::throw_error(ec); } /// Assign an existing native handle to the handle. /* * This function opens the handle to hold an existing native handle. * * @param native_handle A native handle. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code assign(const native_type& native_handle, asio::error_code& ec) { return this->service.assign(this->implementation, native_handle, ec); } /// Determine whether the handle is open. bool is_open() const { return this->service.is_open(this->implementation); } /// Close the handle. /** * This function is used to close the handle. Any asynchronous read or write * operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void close() { asio::error_code ec; this->service.close(this->implementation, ec); asio::detail::throw_error(ec); } /// Close the handle. /** * This function is used to close the handle. Any asynchronous read or write * operations will be cancelled immediately, and will complete with the * asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code close(asio::error_code& ec) { return this->service.close(this->implementation, ec); } /// Get the native handle representation. /** * This function may be used to obtain the underlying representation of the * handle. This is intended to allow access to native handle functionality * that is not otherwise provided. */ native_type native() { return this->service.native(this->implementation); } /// Cancel all asynchronous operations associated with the handle. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. */ void cancel() { asio::error_code ec; this->service.cancel(this->implementation, ec); asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the handle. /** * This function causes all outstanding asynchronous read or write operations * to finish immediately, and the handlers for cancelled operations will be * passed the asio::error::operation_aborted error. * * @param ec Set to indicate what error occurred, if any. */ asio::error_code cancel(asio::error_code& ec) { return this->service.cancel(this->implementation, ec); } protected: /// Protected destructor to prevent deletion through this type. ~basic_handle() { } }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_BASIC_HANDLE_HPP percona-galera-3-3.8-3390/asio/asio/windows/basic_random_access_handle.hpp000066400000000000000000000300441244131713600263510ustar00rootroot00000000000000// // windows/basic_random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP #define ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/detail/throw_error.hpp" #include "asio/error.hpp" #include "asio/windows/basic_handle.hpp" #include "asio/windows/random_access_handle_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Provides random-access handle functionality. /** * The windows::basic_random_access_handle class template provides asynchronous * and blocking random-access handle functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template class basic_random_access_handle : public basic_handle { public: /// The native representation of a handle. typedef typename RandomAccessHandleService::native_type native_type; /// Construct a basic_random_access_handle without opening it. /** * This constructor creates a random-access handle without opening it. The * handle needs to be opened before data can be written to or or read from it. * * @param io_service The io_service object that the random-access handle will * use to dispatch handlers for any asynchronous operations performed on the * handle. */ explicit basic_random_access_handle(asio::io_service& io_service) : basic_handle(io_service) { } /// Construct a basic_random_access_handle on an existing native handle. /** * This constructor creates a random-access handle object to hold an existing * native handle. * * @param io_service The io_service object that the random-access handle will * use to dispatch handlers for any asynchronous operations performed on the * handle. * * @param native_handle The new underlying handle implementation. * * @throws asio::system_error Thrown on failure. */ basic_random_access_handle(asio::io_service& io_service, const native_type& native_handle) : basic_handle(io_service, native_handle) { } /// Write some data to the handle at the specified offset. /** * This function is used to write data to the random-access handle. The * function call will block until one or more bytes of the data has been * written successfully, or until an error occurs. * * @param offset The offset at which the data will be written. * * @param buffers One or more data buffers to be written to the handle. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The write_some_at operation may not write all of the data. Consider * using the @ref write_at function if you need to ensure that all data is * written before the blocking operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * handle.write_some_at(42, asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_some_at(boost::uint64_t offset, const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.write_some_at( this->implementation, offset, buffers, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the handle at the specified offset. /** * This function is used to write data to the random-access handle. The * function call will block until one or more bytes of the data has been * written successfully, or until an error occurs. * * @param offset The offset at which the data will be written. * * @param buffers One or more data buffers to be written to the handle. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write_at function if you need to ensure that * all data is written before the blocking operation completes. */ template std::size_t write_some_at(boost::uint64_t offset, const ConstBufferSequence& buffers, asio::error_code& ec) { return this->service.write_some_at( this->implementation, offset, buffers, ec); } /// Start an asynchronous write at the specified offset. /** * This function is used to asynchronously write data to the random-access * handle. The function call always returns immediately. * * @param offset The offset at which the data will be written. * * @param buffers One or more data buffers to be written to the handle. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write_at function if you need to ensure that * all data is written before the asynchronous operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * handle.async_write_some_at(42, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_some_at(boost::uint64_t offset, const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_write_some_at( this->implementation, offset, buffers, handler); } /// Read some data from the handle at the specified offset. /** * This function is used to read data from the random-access handle. The * function call will block until one or more bytes of data has been read * successfully, or until an error occurs. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read_at function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * handle.read_some_at(42, asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_some_at(boost::uint64_t offset, const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.read_some_at( this->implementation, offset, buffers, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the handle at the specified offset. /** * This function is used to read data from the random-access handle. The * function call will block until one or more bytes of data has been read * successfully, or until an error occurs. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read_at function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ template std::size_t read_some_at(boost::uint64_t offset, const MutableBufferSequence& buffers, asio::error_code& ec) { return this->service.read_some_at( this->implementation, offset, buffers, ec); } /// Start an asynchronous read at the specified offset. /** * This function is used to asynchronously read data from the random-access * handle. The function call always returns immediately. * * @param offset The offset at which the data will be read. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read_at function if you need to ensure that * the requested amount of data is read before the asynchronous operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * handle.async_read_some_at(42, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_some_at(boost::uint64_t offset, const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_read_some_at( this->implementation, offset, buffers, handler); } }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP percona-galera-3-3.8-3390/asio/asio/windows/basic_stream_handle.hpp000066400000000000000000000261371244131713600250530ustar00rootroot00000000000000// // windows/basic_stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP #define ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/error.hpp" #include "asio/windows/basic_handle.hpp" #include "asio/windows/stream_handle_service.hpp" #include "asio/detail/throw_error.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Provides stream-oriented handle functionality. /** * The windows::basic_stream_handle class template provides asynchronous and * blocking stream-oriented handle functionality. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class basic_stream_handle : public basic_handle { public: /// The native representation of a handle. typedef typename StreamHandleService::native_type native_type; /// Construct a basic_stream_handle without opening it. /** * This constructor creates a stream handle without opening it. The handle * needs to be opened and then connected or accepted before data can be sent * or received on it. * * @param io_service The io_service object that the stream handle will use to * dispatch handlers for any asynchronous operations performed on the handle. */ explicit basic_stream_handle(asio::io_service& io_service) : basic_handle(io_service) { } /// Construct a basic_stream_handle on an existing native handle. /** * This constructor creates a stream handle object to hold an existing native * handle. * * @param io_service The io_service object that the stream handle will use to * dispatch handlers for any asynchronous operations performed on the handle. * * @param native_handle The new underlying handle implementation. * * @throws asio::system_error Thrown on failure. */ basic_stream_handle(asio::io_service& io_service, const native_type& native_handle) : basic_handle(io_service, native_handle) { } /// Write some data to the handle. /** * This function is used to write data to the stream handle. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the handle. * * @returns The number of bytes written. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * handle.write_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_some(const ConstBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.write_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Write some data to the handle. /** * This function is used to write data to the stream handle. The function call * will block until one or more bytes of the data has been written * successfully, or until an error occurs. * * @param buffers One or more data buffers to be written to the handle. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. */ template std::size_t write_some(const ConstBufferSequence& buffers, asio::error_code& ec) { return this->service.write_some(this->implementation, buffers, ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write data to the stream handle. * The function call always returns immediately. * * @param buffers One or more data buffers to be written to the handle. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The write operation may not transmit all of the data to the peer. * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * handle.async_write_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_some(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_write_some(this->implementation, buffers, handler); } /// Read some data from the handle. /** * This function is used to read data from the stream handle. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @returns The number of bytes read. * * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * handle.read_some(asio::buffer(data, size)); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t read_some(const MutableBufferSequence& buffers) { asio::error_code ec; std::size_t s = this->service.read_some(this->implementation, buffers, ec); asio::detail::throw_error(ec); return s; } /// Read some data from the handle. /** * This function is used to read data from the stream handle. The function * call will block until one or more bytes of data has been read successfully, * or until an error occurs. * * @param buffers One or more buffers into which the data will be read. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ template std::size_t read_some(const MutableBufferSequence& buffers, asio::error_code& ec) { return this->service.read_some(this->implementation, buffers, ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read data from the stream handle. * The function call always returns immediately. * * @param buffers One or more buffers into which the data will be read. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @note The read operation may not read all of the requested number of bytes. * Consider using the @ref async_read function if you need to ensure that the * requested amount of data is read before the asynchronous operation * completes. * * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * handle.async_read_some(asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_read_some(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_read_some(this->implementation, buffers, handler); } }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP percona-galera-3-3.8-3390/asio/asio/windows/overlapped_ptr.hpp000066400000000000000000000052331244131713600241240ustar00rootroot00000000000000// // windows/overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_OVERLAPPED_PTR_HPP #define ASIO_WINDOWS_OVERLAPPED_PTR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ || defined(GENERATING_DOCUMENTATION) #include "asio/detail/noncopyable.hpp" #include "asio/detail/win_iocp_overlapped_ptr.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. /** * A special-purpose smart pointer used to wrap an application handler so that * it can be passed as the LPOVERLAPPED argument to overlapped I/O functions. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ class overlapped_ptr : private noncopyable { public: /// Construct an empty overlapped_ptr. overlapped_ptr() : impl_() { } /// Construct an overlapped_ptr to contain the specified handler. template explicit overlapped_ptr(asio::io_service& io_service, Handler handler) : impl_(io_service, handler) { } /// Destructor automatically frees the OVERLAPPED object unless released. ~overlapped_ptr() { } /// Reset to empty. void reset() { impl_.reset(); } /// Reset to contain the specified handler, freeing any current OVERLAPPED /// object. template void reset(asio::io_service& io_service, Handler handler) { impl_.reset(io_service, handler); } /// Get the contained OVERLAPPED object. OVERLAPPED* get() { return impl_.get(); } /// Get the contained OVERLAPPED object. const OVERLAPPED* get() const { return impl_.get(); } /// Release ownership of the OVERLAPPED object. OVERLAPPED* release() { return impl_.release(); } /// Post completion notification for overlapped operation. Releases ownership. void complete(const asio::error_code& ec, std::size_t bytes_transferred) { impl_.complete(ec, bytes_transferred); } private: detail::win_iocp_overlapped_ptr impl_; }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_OVERLAPPED_PTR_HPP percona-galera-3-3.8-3390/asio/asio/windows/random_access_handle.hpp000066400000000000000000000020451244131713600252100ustar00rootroot00000000000000// // windows/random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP #define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include "asio/windows/basic_random_access_handle.hpp" namespace asio { namespace windows { /// Typedef for the typical usage of a random-access handle. typedef basic_random_access_handle<> random_access_handle; } // namespace windows } // namespace asio #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP percona-galera-3-3.8-3390/asio/asio/windows/random_access_handle_service.hpp000066400000000000000000000120341244131713600267270ustar00rootroot00000000000000// // windows/random_access_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP #define ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include #include #include #include "asio/detail/win_iocp_handle_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Default service implementation for a random-access handle. class random_access_handle_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif private: // The type of the platform-specific implementation. typedef detail::win_iocp_handle_service service_impl_type; public: /// The type of a random-access handle implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef service_impl_type::implementation_type implementation_type; #endif /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef service_impl_type::native_type native_type; #endif /// Construct a new random-access handle service for the specified io_service. explicit random_access_handle_service(asio::io_service& io_service) : asio::detail::service_base< random_access_handle_service>(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new random-access handle implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a random-access handle implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Assign an existing native handle to a random-access handle. asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { return service_impl_.assign(impl, native_handle, ec); } /// Determine whether the handle is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a random-access handle implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native handle implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the handle. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Write the given data at the specified offset. template std::size_t write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, asio::error_code& ec) { return service_impl_.write_some_at(impl, offset, buffers, ec); } /// Start an asynchronous write at the specified offset. template void async_write_some_at(implementation_type& impl, boost::uint64_t offset, const ConstBufferSequence& buffers, WriteHandler handler) { service_impl_.async_write_some_at(impl, offset, buffers, handler); } /// Read some data from the specified offset. template std::size_t read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.read_some_at(impl, offset, buffers, ec); } /// Start an asynchronous read at the specified offset. template void async_read_some_at(implementation_type& impl, boost::uint64_t offset, const MutableBufferSequence& buffers, ReadHandler handler) { service_impl_.async_read_some_at(impl, offset, buffers, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/windows/stream_handle.hpp000066400000000000000000000017411244131713600237040ustar00rootroot00000000000000// // windows/stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_STREAM_HANDLE_HPP #define ASIO_WINDOWS_STREAM_HANDLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include "asio/windows/basic_stream_handle.hpp" namespace asio { namespace windows { /// Typedef for the typical usage of a stream-oriented handle. typedef basic_stream_handle<> stream_handle; } // namespace windows } // namespace asio #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_STREAM_HANDLE_HPP percona-galera-3-3.8-3390/asio/asio/windows/stream_handle_service.hpp000066400000000000000000000112001244131713600254130ustar00rootroot00000000000000// // windows/stream_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP #define ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include #include "asio/detail/win_iocp_handle_service.hpp" #include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace windows { /// Default service implementation for a stream handle. class stream_handle_service #if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service #else : public asio::detail::service_base #endif { public: #if defined(GENERATING_DOCUMENTATION) /// The unique service identifier. static asio::io_service::id id; #endif private: // The type of the platform-specific implementation. typedef detail::win_iocp_handle_service service_impl_type; public: /// The type of a stream handle implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined implementation_type; #else typedef service_impl_type::implementation_type implementation_type; #endif /// The native handle type. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_type; #else typedef service_impl_type::native_type native_type; #endif /// Construct a new stream handle service for the specified io_service. explicit stream_handle_service(asio::io_service& io_service) : asio::detail::service_base(io_service), service_impl_(io_service) { } /// Destroy all user-defined handler objects owned by the service. void shutdown_service() { service_impl_.shutdown_service(); } /// Construct a new stream handle implementation. void construct(implementation_type& impl) { service_impl_.construct(impl); } /// Destroy a stream handle implementation. void destroy(implementation_type& impl) { service_impl_.destroy(impl); } /// Assign an existing native handle to a stream handle. asio::error_code assign(implementation_type& impl, const native_type& native_handle, asio::error_code& ec) { return service_impl_.assign(impl, native_handle, ec); } /// Determine whether the handle is open. bool is_open(const implementation_type& impl) const { return service_impl_.is_open(impl); } /// Close a stream handle implementation. asio::error_code close(implementation_type& impl, asio::error_code& ec) { return service_impl_.close(impl, ec); } /// Get the native handle implementation. native_type native(implementation_type& impl) { return service_impl_.native(impl); } /// Cancel all asynchronous operations associated with the handle. asio::error_code cancel(implementation_type& impl, asio::error_code& ec) { return service_impl_.cancel(impl, ec); } /// Write the given data to the stream. template std::size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, asio::error_code& ec) { return service_impl_.write_some(impl, buffers, ec); } /// Start an asynchronous write. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, WriteHandler handler) { service_impl_.async_write_some(impl, buffers, handler); } /// Read some data from the stream. template std::size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, asio::error_code& ec) { return service_impl_.read_some(impl, buffers, ec); } /// Start an asynchronous read. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, ReadHandler handler) { service_impl_.async_read_some(impl, buffers, handler); } private: // The platform-specific implementation. service_impl_type service_impl_; }; } // namespace windows } // namespace asio #include "asio/detail/pop_options.hpp" #endif // defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // ASIO_WINDOWS_STREAM_HANDLE_SERVICE_HPP percona-galera-3-3.8-3390/asio/asio/write.hpp000066400000000000000000000530211244131713600205340ustar00rootroot00000000000000// // write.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WRITE_HPP #define ASIO_WRITE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /** * @defgroup write asio::write * * @brief Write a certain amount of data to a stream before returning. */ /*@{*/ /// Write all of the supplied data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * stream. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write(s, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::write( * s, buffers, * asio::transfer_all()); @endcode */ template std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); /// Write a certain amount of data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * stream. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's write_some function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write(s, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition); /// Write a certain amount of data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * stream. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's write_some function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec); #if !defined(BOOST_NO_IOSTREAM) /// Write all of the supplied data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::write( * s, b, * asio::transfer_all()); @endcode */ template std::size_t write(SyncWriteStream& s, basic_streambuf& b); /// Write a certain amount of data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's write_some function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. */ template std::size_t write(SyncWriteStream& s, basic_streambuf& b, CompletionCondition completion_condition); /// Write a certain amount of data to a stream before returning. /** * This function is used to write a certain number of bytes of data to a stream. * The call will block until one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's write_some function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t write(SyncWriteStream& s, basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ /** * @defgroup async_write asio::async_write * * @brief Start an asynchronous operation to write a certain amount of data to a * stream. */ /*@{*/ /// Start an asynchronous operation to write all of the supplied data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of * data to a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions * is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function, and is known as a composed operation. The * program must ensure that the stream performs no other write operations (such * as async_write, the stream's async_write_some function, or any other composed * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes written from the * // buffers. If an error occurred, * // this will be less than the sum * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * asio::async_write(s, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of * data to a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions * is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function, and is known as a composed operation. The * program must ensure that the stream performs no other write operations (such * as async_write, the stream's async_write_some function, or any other composed * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's async_write_some function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes written from the * // buffers. If an error occurred, * // this will be less than the sum * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::async_write(s, * asio::buffer(data, size), * asio::transfer_at_least(32), * handler); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler); #if !defined(BOOST_NO_IOSTREAM) /// Start an asynchronous operation to write all of the supplied data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of * data to a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions * is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function, and is known as a composed operation. The * program must ensure that the stream performs no other write operations (such * as async_write, the stream's async_write_some function, or any other composed * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes written from the * // buffers. If an error occurred, * // this will be less than the sum * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_write(AsyncWriteStream& s, basic_streambuf& b, WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data to a /// stream. /** * This function is used to asynchronously write a certain number of bytes of * data to a stream. The function call always returns immediately. The * asynchronous operation will continue until one of the following conditions * is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function, and is known as a composed operation. The * program must ensure that the stream performs no other write operations (such * as async_write, the stream's async_write_some function, or any other composed * operations that perform writes) until this operation completes. * * @param s The stream to which the data is to be written. The type must support * the AsyncWriteStream concept. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_write_some operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the stream's async_write_some function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * const asio::error_code& error, // Result of operation. * * std::size_t bytes_transferred // Number of bytes written from the * // buffers. If an error occurred, * // this will be less than the sum * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_write(AsyncWriteStream& s, basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/write.hpp" #endif // ASIO_WRITE_HPP percona-galera-3-3.8-3390/asio/asio/write_at.hpp000066400000000000000000000535521244131713600212310ustar00rootroot00000000000000// // write_at.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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) // #ifndef ASIO_WRITE_AT_HPP #define ASIO_WRITE_AT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include #include "asio/basic_streambuf_fwd.hpp" #include "asio/error.hpp" #include "asio/detail/push_options.hpp" namespace asio { /** * @defgroup write_at asio::write_at * * @brief Write a certain amount of data at a specified offset before returning. */ /*@{*/ /// Write all of the supplied data at the specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * device. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write_at(d, 42, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. * * @note This overload is equivalent to calling: * @code asio::write_at( * d, offset, buffers, * asio::transfer_all()); @endcode */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers); /// Write a certain amount of data at a specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * device. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's write_some_at function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write_at(d, 42, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition); /// Write a certain amount of data at a specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the * device. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's write_some_at function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec); #if !defined(BOOST_NO_IOSTREAM) /// Write all of the supplied data at the specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param b The basic_streambuf object from which data will be written. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::write_at( * d, 42, b, * asio::transfer_all()); @endcode */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, basic_streambuf& b); /// Write a certain amount of data at a specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param b The basic_streambuf object from which data will be written. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's write_some_at function. * * @returns The number of bytes transferred. * * @throws asio::system_error Thrown on failure. */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition); /// Write a certain amount of data at a specified offset before returning. /** * This function is used to write a certain number of bytes of data to a random * access device at a specified offset. The call will block until one of the * following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support * the SyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param b The basic_streambuf object from which data will be written. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's write_some_at function. * * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes written. If an error occurs, returns the total * number of bytes successfully transferred prior to the error. */ template std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ /** * @defgroup async_write_at asio::async_write_at * * @brief Start an asynchronous operation to write a certain amount of data at * the specified offset. */ /*@{*/ /// Start an asynchronous operation to write all of the supplied data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of * data to a random access device at a specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support * the AsyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes written from the buffers. If an error * // occurred, this will be less than the sum of the buffer sizes. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * asio::async_write_at(d, 42, asio::buffer(data, size), handler); * @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of * data to a random access device at a specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li All of the data in the supplied buffers has been written. That is, the * bytes transferred is equal to the sum of the buffer sizes. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support * the AsyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the * underlying memory blocks is retained by the caller, which must guarantee * that they remain valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's async_write_some_at function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes written from the buffers. If an error * // occurred, this will be less than the sum of the buffer sizes. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::async_write_at(d, 42, * asio::buffer(data, size), * asio::transfer_at_least(32), * handler); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ template void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, WriteHandler handler); #if !defined(BOOST_NO_IOSTREAM) /// Start an asynchronous operation to write all of the supplied data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of * data to a random access device at a specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li An error occurred. * * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support * the AsyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes written from the buffers. If an error * // occurred, this will be less than the sum of the buffer sizes. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, basic_streambuf& b, WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. /** * This function is used to asynchronously write a certain number of bytes of * data to a random access device at a specified offset. The function call * always returns immediately. The asynchronous operation will continue until * one of the following conditions is true: * * @li All of the data in the supplied basic_streambuf has been written. * * @li The completion_condition function object returns 0. * * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support * the AsyncRandomAccessWriteDevice concept. * * @param offset The offset at which the data will be written. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. * * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: * @code std::size_t completion_condition( * // Result of latest async_write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode * A return value of 0 indicates that the write operation is complete. A * non-zero return value indicates the maximum number of bytes to be written on * the next call to the device's async_write_some_at function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( * // Result of operation. * const asio::error_code& error, * * // Number of bytes written from the buffers. If an error * // occurred, this will be less than the sum of the buffer sizes. * std::size_t bytes_transferred * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ template void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, WriteHandler handler); #endif // !defined(BOOST_NO_IOSTREAM) /*@}*/ } // namespace asio #include "asio/detail/pop_options.hpp" #include "asio/impl/write_at.hpp" #endif // ASIO_WRITE_AT_HPP percona-galera-3-3.8-3390/asio/version.txt000066400000000000000000000000061244131713600201570ustar00rootroot000000000000001.4.8 percona-galera-3-3.8-3390/chromium/000077500000000000000000000000001244131713600166255ustar00rootroot00000000000000percona-galera-3-3.8-3390/chromium/AUTHORS000066400000000000000000000220751244131713600177030ustar00rootroot00000000000000# Names should be added to this file with this pattern: # # For individuals: # Name # # For organizations: # Organization # # See python fnmatch module documentation for more information. The Chromium Authors <*@chromium.org> Google Inc. <*@google.com> Mohamed I. Hammad Sergiy Byelozyorov Seo Sanghyeon Alex Scheele Andrew Brampton Paweł Hajdan jr Jesse Miller Szymon Piechowicz James Vega Marco Rodrigues Matthias Reitinger Peter Bright Arthur Lussos Masahiro Yado Yarin Kaul Gaetano Mendola Comodo CA Limited Torchmobile Inc. Craig Schlenter Ibrar Ahmed Naoki Takano Fabien Tassin Kunal Thakar Mohamed Mansour Joshua Roesslein Yong Shin Laszlo Radanyi Raman Tenneti Kyle Nahrgang Kim Christensen Paul Robinson Josué Ratelle Edward Crossman Nikita Ofitserov Sean Bryant Robert Sesek Janwar Dinata Will Hirsch Yoav Zilberberg Joel Stanley Jacob Mandelson Yuri Gorobets Paul Wicks Thiago Farina Viet-Trung Luu Pierre-Antoine LaFayette Song YeWen Philippe Beauchamp Vedran Šajatović Randy Posynick Bruno Calvignac Jaime Soriano Pastor Bryan Donlan Ramkumar Ramachandra Dominic Jodoin Kaspar Brand Clemens Fruhwirth Kevin Lee Helpingstine Bernard Cafarelli Vernon Tang Alexander Sulfrian Philippe Beaudoin Mark Hahnenberg Alex Gartrell Leith Bade James Choi Paul Kehrer Chamal De Silva Jay Soffian Brian G. Merrell Matthew Willis Brian Merrell, Novell Inc. Ryan Sleevi Satoshi Matsuzaki Benjamin Jemlich Ningxin Hu James Wei Haitao Feng Jared Wein Mingmin Xie Michael Gilbert Giuseppe Iuculano James Willcox Shreyas VA Steven Pennington Jorge Villatoro Paul Nettleship David Benjamin Sevan Janiyan Peter Beverloo Lauri Oherd Ben Karel Sam McDonald Magnus Danielsson Kushal Pisavadia Maarten Lankhorst Vipul Bhasin Ryan Norton Dillon Sellars Seshadri Mahalingam Clement Scheelfeldt Skau David Futcher Ramkumar Gokarnesan Matt Arpidone ruben NVIDIA Corporation <*@nvidia.com> Torsten Kurbad Max Perepelitsyn Luke Zarko Felix H. Dahlke Ali Vathi Mathias Bynens Mark Seaborn Amruth Raj Amruth Raj Gajendra Singh Ehsan Akhgari Christopher Dale Sanjoy Pal Mike Tilburg Peter Brophy Robert Goldberg Don Woodward Vinay Anantharaman Naveen Bobbili Vamshikrishna Yellenki Robert Nagy Nayan Kumar K ShankarGanesh K Goutham Jagannatha Rosen Dash Naveen Bobbili Ravi Phaneendra Kasibhatla Rosen Dash Parag Radke Ted Vessenes Yair Yogev Chandra Shekar Vallala Patrasciuc Sorin Cristian Halton Huo Shiliu Wang Gao Chun Clinton Staley Clinton Staley Devlin Cronin Junmin Zhu Cem Kocagil YoungKi Hong Lu Guanqun François Beaufort Eriq Augustine Francois Kritzinger Erik Hill Mao Yujie Pan Deng Aaron Leventhal Peter Collingbourne Aaron Randolph Yumikiyo Osanai Matthew Robertson Mao Yujie Xu Samuel Jin Yang Xinchao He Changbin Shao Stephen Searles Arun Mankuzhi Christophe Dumez Taylor Price Alexandru Chiculita Eric Rescorla Alexandre Abreu Erik Sjölund Simon Arlott Alexey Korepanov Mitchell Rosen Yongsheng Zhu Shouqun Liu Kangyuan Shu Jake Helfert Hongbo Min Anastasios Cassiotis Evangelos Foutras Pavel Ivanov Rene Bolldorf Petar Jovanovic Sergio Carlos Morales Angeles Mihai Maerean Kaustubh Atrawalkar Robert Bear Travis Robert Bear Travis Max Vujovic Jakob Weigert Catalin Badea Joshua Lock Dai Chunyang Joe Thomas Ruben Terrazas Josh Triplett Qiankun Miao Etienne Laurin Yang Gu Timo Reimann Sungguk Lim Martin Bednorz Kamil Jiwa Keene Pan Trevor Perrin Ion Rosca Sylvain Zimmer Sungmann Cho 方觉 (Fang Jue) Evan Peterson J. Ryan Stinnett Matheus Bratfisch Horia Olaru Horia Olaru Opera Software ASA <*@opera.com> Johannes Rudolph Aaron Jacobs Sam Larison Jun Jiang Bobby Powers Patrick Riordan Kenneth Rohde Christiansen Raphael Kubo da Costa Yandex LLC <*@yandex-team.ru> Yoshinori Sano Mrunal Kapade Yael Aharon Haojian Wu Sathish Kuppuswamy Joone Hur Sudarsana Babu Nagineni Jared Shumway Shez Baig percona-galera-3-3.8-3390/chromium/LICENSE000066400000000000000000000030331244131713600176310ustar00rootroot00000000000000// Copyright (c) 2013 The Chromium Authors. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. percona-galera-3-3.8-3390/chromium/aligned_memory.h000066400000000000000000000115451244131713600217770ustar00rootroot00000000000000// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // AlignedMemory is a POD type that gives you a portable way to specify static // or local stack data of a given alignment and size. For example, if you need // static storage for a class, but you want manual control over when the object // is constructed and destructed (you don't want static initialization and // destruction), use AlignedMemory: // // static AlignedMemory my_class; // // // ... at runtime: // new(my_class.void_data()) MyClass(); // // // ... use it: // MyClass* mc = my_class.data_as(); // // // ... later, to destruct my_class: // my_class.data_as()->MyClass::~MyClass(); // // Alternatively, a runtime sized aligned allocation can be created: // // float* my_array = static_cast(AlignedAlloc(size, alignment)); // // // ... later, to release the memory: // AlignedFree(my_array); // // Or using scoped_ptr_malloc: // // scoped_ptr_malloc my_array( // static_cast(AlignedAlloc(size, alignment))); #ifndef BASE_MEMORY_ALIGNED_MEMORY_H_ #define BASE_MEMORY_ALIGNED_MEMORY_H_ //#include "base/basictypes.h" #include "compile_assert.h" #include "compiler_specific.h" #if defined(COMPILER_MSVC) #include #else #include #endif namespace chromium { // AlignedMemory is specialized for all supported alignments. // Make sure we get a compiler error if someone uses an unsupported alignment. template struct AlignedMemory {}; #define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \ template \ class AlignedMemory { \ public: \ ALIGNAS(byte_alignment) unsigned char data_[Size]; \ void* void_data() { return static_cast(data_); } \ const void* void_data() const { \ return static_cast(data_); \ } \ template \ Type* data_as() { return static_cast(void_data()); } \ template \ const Type* data_as() const { \ return static_cast(void_data()); \ } \ private: \ void* operator new(size_t); \ void operator delete(void*); \ } // Specialization for all alignments is required because MSVC (as of VS 2008) // does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param). // Greater than 4096 alignment is not supported by some compilers, so 4096 is // the maximum specified here. BASE_DECL_ALIGNED_MEMORY(1); BASE_DECL_ALIGNED_MEMORY(2); BASE_DECL_ALIGNED_MEMORY(4); BASE_DECL_ALIGNED_MEMORY(8); BASE_DECL_ALIGNED_MEMORY(16); BASE_DECL_ALIGNED_MEMORY(32); BASE_DECL_ALIGNED_MEMORY(64); BASE_DECL_ALIGNED_MEMORY(128); BASE_DECL_ALIGNED_MEMORY(256); BASE_DECL_ALIGNED_MEMORY(512); BASE_DECL_ALIGNED_MEMORY(1024); BASE_DECL_ALIGNED_MEMORY(2048); BASE_DECL_ALIGNED_MEMORY(4096); #undef BASE_DECL_ALIGNED_MEMORY #if defined(OS_ANDROID) || defined(OS_NACL) #include #endif inline void* AlignedAlloc(size_t size, size_t alignment) { void* ptr = NULL; #if defined(COMPILER_MSVC) ptr = _aligned_malloc(size, alignment); #elif defined(OS_ANDROID) || defined(OS_NACL) // Both Android and NaCl technically support posix_memalign(), but do not expose // it in the current version of the library headers used by Chrome. Luckily, // memalign() on both platforms returns pointers which can safely be used with // free(), so we can use it instead. Issues filed with each project for docs: // http://code.google.com/p/android/issues/detail?id=35391 // http://code.google.com/p/chromium/issues/detail?id=138579 ptr = memalign(alignment, size); #else if (posix_memalign(&ptr, alignment, size)) ptr = NULL; #endif return ptr; } inline void AlignedFree(void* ptr) { #if defined(COMPILER_MSVC) _aligned_free(ptr); #else free(ptr); #endif } // Helper class for use with scoped_ptr_malloc. class ScopedPtrAlignedFree { public: inline void operator()(void* ptr) const { AlignedFree(ptr); } }; // Codership: added a convenience wsrapper over AlignedMemory template class AlignedBuffer { public: T* base_ptr() { return buf_.template data_as(); } const T* base_ptr() const { return buf_.template data_as(); } size_t size() const { return capacity; } private: // The buffer itself. It is not of type T because we don't want the // constructors and destructors to be automatically called. Define a POD // buffer of the right size instead. chromium::AlignedMemory buf_; #if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY) CHROMIUM_COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612); #endif }; } // namespace chromium #endif // BASE_MEMORY_ALIGNED_MEMORY_H_ percona-galera-3-3.8-3390/chromium/build_config.h000066400000000000000000000114141244131713600214230ustar00rootroot00000000000000// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This file adds defines about the platform we're currently building on. // Operating System: // OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) // Compiler: // COMPILER_MSVC / COMPILER_GCC // Processor: // ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64) // ARCH_CPU_32_BITS / ARCH_CPU_64_BITS #ifndef BUILD_BUILD_CONFIG_H_ #define BUILD_BUILD_CONFIG_H_ #if defined(__APPLE__) #include #endif // A set of macros to use for platform detection. #if defined(ANDROID) #define OS_ANDROID 1 #elif defined(__APPLE__) #define OS_MACOSX 1 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE #define OS_IOS 1 #endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE #elif defined(__native_client__) #define OS_NACL 1 #elif defined(__linux__) #define OS_LINUX 1 // Use TOOLKIT_GTK on linux if TOOLKIT_VIEWS isn't defined. #if !defined(TOOLKIT_VIEWS) && defined(USE_X11) #define TOOLKIT_GTK #endif #elif defined(_WIN32) #define OS_WIN 1 #define TOOLKIT_VIEWS 1 #elif defined(__FreeBSD__) #define OS_FREEBSD 1 #define TOOLKIT_GTK #elif defined(__OpenBSD__) #define OS_OPENBSD 1 #define TOOLKIT_GTK #elif defined(__sun) #define OS_SOLARIS 1 #define TOOLKIT_GTK #else #error Please add support for your platform in build/build_config.h #endif #if defined(USE_OPENSSL) && defined(USE_NSS) #error Cannot use both OpenSSL and NSS #endif // For access to standard BSD features, use OS_BSD instead of a // more specific macro. #if defined(OS_FREEBSD) || defined(OS_OPENBSD) #define OS_BSD 1 #endif // For access to standard POSIXish features, use OS_POSIX instead of a // more specific macro. #if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) || \ defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) || \ defined(OS_NACL) #define OS_POSIX 1 #endif #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \ !defined(OS_NACL) && !defined(USE_MESSAGEPUMP_LINUX) #define USE_X11 1 // Use X for graphics. #endif // Use tcmalloc #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(NO_TCMALLOC) #define USE_TCMALLOC 1 #endif // Compiler detection. #if defined(__GNUC__) #define COMPILER_GCC 1 #elif defined(_MSC_VER) #define COMPILER_MSVC 1 #else #error Please add support for your compiler in build/build_config.h #endif // Processor architecture detection. For more info on what's defined, see: // http://msdn.microsoft.com/en-us/library/b0084kay.aspx // http://www.agner.org/optimize/calling_conventions.pdf // or with gcc, run: "echo | gcc -E -dM -" #if defined(_M_X64) || defined(__x86_64__) #define ARCH_CPU_X86_FAMILY 1 #define ARCH_CPU_X86_64 1 #define ARCH_CPU_64_BITS 1 #define ARCH_CPU_LITTLE_ENDIAN 1 #elif defined(_M_IX86) || defined(__i386__) #define ARCH_CPU_X86_FAMILY 1 #define ARCH_CPU_X86 1 #define ARCH_CPU_32_BITS 1 #define ARCH_CPU_LITTLE_ENDIAN 1 #elif defined(__ARMEL__) #define ARCH_CPU_ARM_FAMILY 1 #define ARCH_CPU_ARMEL 1 #define ARCH_CPU_32_BITS 1 #define ARCH_CPU_LITTLE_ENDIAN 1 #elif defined(__pnacl__) #define ARCH_CPU_32_BITS 1 #elif defined(__MIPSEL__) #define ARCH_CPU_MIPS_FAMILY 1 #define ARCH_CPU_MIPSEL 1 #define ARCH_CPU_32_BITS 1 #define ARCH_CPU_LITTLE_ENDIAN 1 #elif defined(__PPC__) #if defined(__PPC64__) #define ARCH_CPU_64_BITS 1 #else #define ARCH_CPU_32_BITS 1 #endif #define ARCH_CPU_BIG_ENDIAN 1 #else #error Please add support for your architecture in build/build_config.h #endif // Type detection for wchar_t. #if defined(OS_WIN) #define WCHAR_T_IS_UTF16 #elif defined(OS_POSIX) && defined(COMPILER_GCC) && \ defined(__WCHAR_MAX__) && \ (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff) #define WCHAR_T_IS_UTF32 #elif defined(OS_POSIX) && defined(COMPILER_GCC) && \ defined(__WCHAR_MAX__) && \ (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff) // On Posix, we'll detect short wchar_t, but projects aren't guaranteed to // compile in this mode (in particular, Chrome doesn't). This is intended for // other projects using base who manage their own dependencies and make sure // short wchar works for them. #define WCHAR_T_IS_UTF16 #else #error Please add support for your compiler in build/build_config.h #endif #if defined(__ARMEL__) && !defined(OS_IOS) #define WCHAR_T_IS_UNSIGNED 1 #elif defined(__MIPSEL__) #define WCHAR_T_IS_UNSIGNED 0 #endif #if defined(OS_ANDROID) // The compiler thinks std::string::const_iterator and "const char*" are // equivalent types. #define STD_STRING_ITERATOR_IS_CHAR_POINTER // The compiler thinks base::string16::const_iterator and "char16*" are // equivalent types. #define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER #endif #endif // BUILD_BUILD_CONFIG_H_ percona-galera-3-3.8-3390/chromium/compile_assert.h000066400000000000000000000051641244131713600220150ustar00rootroot00000000000000// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Codership: this is a cut down version of base/basictypes.h to comtain // COMPILE_ASSERT only #ifndef COMPILE_ASSERT_H_ #define COMPILE_ASSERT_H_ // The COMPILE_ASSERT macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. namespace chromium { template struct CompileAssert { }; } // namespace chromium #undef CHROMIUM_COMPILE_ASSERT #define CHROMIUM_COMPILE_ASSERT(expr, msg) \ typedef chromium::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // Implementation details of COMPILE_ASSERT: // // - COMPILE_ASSERT works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outer parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // COMPILE_ASSERT(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. #endif // COMPILE_ASSERT_H_ percona-galera-3-3.8-3390/chromium/compiler_specific.h000066400000000000000000000144021244131713600224560ustar00rootroot00000000000000// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_COMPILER_SPECIFIC_H_ #define BASE_COMPILER_SPECIFIC_H_ #include "build_config.h" #if defined(COMPILER_MSVC) // Macros for suppressing and disabling warnings on MSVC. // // Warning numbers are enumerated at: // http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx // // The warning pragma: // http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx // // Using __pragma instead of #pragma inside macros: // http://msdn.microsoft.com/en-us/library/d9x1s805.aspx // MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and // for the next line of the source file. #define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n)) // MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled. // The warning remains disabled until popped by MSVC_POP_WARNING. #define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ __pragma(warning(disable:n)) // MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level // remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all // warnings. #define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n)) // Pop effects of innermost MSVC_PUSH_* macro. #define MSVC_POP_WARNING() __pragma(warning(pop)) #define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off)) #define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on)) // DEPRECATED // // Prior to r83840 this was used to supress warning C4355 when using |this| as // an argument in constructor initializer lists: // http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx // // C4355 is supressed globally during compilation and existing uses of this // macro should be removed. Refer to http://crbug.com/234765 for details. #define ALLOW_THIS_IN_INITIALIZER_LIST(code) code // Allows exporting a class that inherits from a non-exported base class. // This uses suppress instead of push/pop because the delimiter after the // declaration (either "," or "{") has to be placed before the pop macro. // // Example usage: // class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) { // // MSVC Compiler warning C4275: // non dll-interface class 'Bar' used as base for dll-interface class 'Foo'. // Note that this is intended to be used only when no access to the base class' // static data is done through derived classes or inline methods. For more info, // see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx #define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \ code #else // Not MSVC #define MSVC_SUPPRESS_WARNING(n) #define MSVC_PUSH_DISABLE_WARNING(n) #define MSVC_PUSH_WARNING_LEVEL(n) #define MSVC_POP_WARNING() #define MSVC_DISABLE_OPTIMIZE() #define MSVC_ENABLE_OPTIMIZE() #define ALLOW_THIS_IN_INITIALIZER_LIST(code) code #define NON_EXPORTED_BASE(code) code #endif // COMPILER_MSVC // Annotate a variable indicating it's ok if the variable is not used. // (Typically used to silence a compiler warning when the assignment // is important for some other reason.) // Use like: // int x ALLOW_UNUSED = ...; #if defined(COMPILER_GCC) #define ALLOW_UNUSED __attribute__((unused)) #else #define ALLOW_UNUSED #endif // Annotate a function indicating it should not be inlined. // Use like: // NOINLINE void DoStuff() { ... } #if defined(COMPILER_GCC) #define NOINLINE __attribute__((noinline)) #elif defined(COMPILER_MSVC) #define NOINLINE __declspec(noinline) #else #define NOINLINE #endif // Specify memory alignment for structs, classes, etc. // Use like: // class ALIGNAS(16) MyClass { ... } // ALIGNAS(16) int array[4]; #if defined(COMPILER_MSVC) #define ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) #elif defined(COMPILER_GCC) #define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) #endif // Return the byte alignment of the given type (available at compile time). Use // sizeof(type) prior to checking __alignof to workaround Visual C++ bug: // http://goo.gl/isH0C // Use like: // ALIGNOF(int32) // this would be 4 #if defined(COMPILER_MSVC) #define ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) #elif defined(COMPILER_GCC) #define ALIGNOF(type) __alignof__(type) #endif // Annotate a virtual method indicating it must be overriding a virtual // method in the parent class. // Use like: // virtual void foo() OVERRIDE; #if defined(COMPILER_MSVC) #define OVERRIDE override #elif defined(__clang__) #define OVERRIDE override #else #define OVERRIDE #endif // Annotate a function indicating the caller must examine the return value. // Use like: // int foo() WARN_UNUSED_RESULT; // To explicitly ignore a result, see |ignore_result()| in . #if defined(COMPILER_GCC) #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else #define WARN_UNUSED_RESULT #endif // Tell the compiler a function is using a printf-style format string. // |format_param| is the one-based index of the format string parameter; // |dots_param| is the one-based index of the "..." parameter. // For v*printf functions (which take a va_list), pass 0 for dots_param. // (This is undocumented but matches what the system C headers do.) #if defined(COMPILER_GCC) #define PRINTF_FORMAT(format_param, dots_param) \ __attribute__((format(printf, format_param, dots_param))) #else #define PRINTF_FORMAT(format_param, dots_param) #endif // WPRINTF_FORMAT is the same, but for wide format strings. // This doesn't appear to yet be implemented in any compiler. // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 . #define WPRINTF_FORMAT(format_param, dots_param) // If available, it would look like: // __attribute__((format(wprintf, format_param, dots_param))) // MemorySanitizer annotations. #ifdef MEMORY_SANITIZER extern "C" { void __msan_unpoison(const void *p, unsigned long s); } // extern "C" // Mark a memory region fully initialized. // Use this to annotate code that deliberately reads uninitialized data, for // example a GC scavenging root set pointers from the stack. #define MSAN_UNPOISON(p, s) __msan_unpoison(p, s) #else // MEMORY_SANITIZER #define MSAN_UNPOISON(p, s) #endif // MEMORY_SANITIZER #endif // BASE_COMPILER_SPECIFIC_H_ percona-galera-3-3.8-3390/common/000077500000000000000000000000001244131713600162725ustar00rootroot00000000000000percona-galera-3-3.8-3390/common/common.h000066400000000000000000000014331244131713600177340ustar00rootroot00000000000000/* *Copyright (C) 2012-2014 Codership Oy */ /*! @file Stores some common definitions to be known throughout the modules */ #ifndef COMMON_DEFS_H #define COMMON_DEFS_H #define COMMON_TCP_SCHEME "tcp" #define COMMON_UDP_SCHEME "udp" #define COMMON_SSL_SCHEME "ssl" #define COMMON_DEFAULT_SCHEME COMMON_TCP_SCHEME #define COMMON_BASE_HOST_KEY "base_host" #define COMMON_BASE_PORT_KEY "base_port" #define COMMON_BASE_PORT_DEFAULT "4567" #define COMMON_STATE_FILE "grastate.dat" #define COMMON_VIEW_STAT_FILE "gvwstate.dat" #define COMMON_CONF_SSL_KEY "socket.ssl_key" #define COMMON_CONF_SSL_CERT "socket.ssl_cert" #define COMMON_CONF_SSL_CA "socket.ssl_ca" #define COMMON_CONF_SSL_PSWD_FILE "socket.ssl_password_file" #endif // COMMON_DEFS_H percona-galera-3-3.8-3390/docs/000077500000000000000000000000001244131713600157325ustar00rootroot00000000000000percona-galera-3-3.8-3390/docs/README000066400000000000000000000001021244131713600166030ustar00rootroot00000000000000Documentation moved to https://github.com/codership/documentation percona-galera-3-3.8-3390/galera/000077500000000000000000000000001244131713600162355ustar00rootroot00000000000000percona-galera-3-3.8-3390/galera/SConscript000066400000000000000000000000641244131713600202470ustar00rootroot00000000000000 SConscript(['src/SConscript', 'tests/SConscript']) percona-galera-3-3.8-3390/galera/src/000077500000000000000000000000001244131713600170245ustar00rootroot00000000000000percona-galera-3-3.8-3390/galera/src/SConscript000066400000000000000000000026361244131713600210450ustar00rootroot00000000000000 Import('env') libgaleraxx_env = env.Clone() libgaleraxx_srcs = [ 'mapped_buffer.cpp', 'write_set.cpp', 'data_set.cpp', 'key_set.cpp', 'write_set_ng.cpp', 'trx_handle.cpp', 'key_entry_os.cpp', 'wsdb.cpp', 'certification.cpp', 'galera_service_thd.cpp', 'wsrep_params.cpp', 'replicator_smm_params.cpp', 'gcs_action_source.cpp', 'galera_info.cpp', 'replicator.cpp', 'ist.cpp', 'gcs_dummy.cpp', 'saved_state.cpp' ] libgaleraxx_env.StaticLibrary('galera++', libgaleraxx_srcs) # Environment for multimaster library build mmlib_env = libgaleraxx_env.Clone() mmlib_env.Append(CPPFLAGS = ' -DGALERA_MULTIMASTER') mmlib_env.Replace(SHOBJPREFIX = 'libmmgalera++-') # Environment to compile provider unit (part of multimaster library) # This is needed to hardcode version and revision mmprovider_env = mmlib_env.Clone() Import ('GALERA_VER', 'GALERA_REV') mmprovider_env.Append(CPPFLAGS = ' -DGALERA_VER=\\"' + GALERA_VER + '\\"') mmprovider_env.Append(CPPFLAGS = ' -DGALERA_REV=\\"' + GALERA_REV + '\\"') # env.Append(LIBGALERA_OBJS = libgaleraxx_env.SharedObject(libgaleraxx_srcs)) env.Append(LIBMMGALERA_OBJS = mmlib_env.SharedObject([ 'replicator_smm.cpp', 'replicator_str.cpp', 'replicator_smm_stats.cpp' ])) env.Append(LIBMMGALERA_OBJS = mmprovider_env.SharedObject([ 'wsrep_provider.cpp' ])) percona-galera-3-3.8-3390/galera/src/action_source.hpp000066400000000000000000000005601244131713600223730ustar00rootroot00000000000000// // Copyright (C) 2010-2013 Codership Oy // #ifndef GALERA_ACTION_SOURCE_HPP #define GALERA_ACTION_SOURCE_HPP namespace galera { class ActionSource { public: ActionSource() { } virtual ~ActionSource() { } virtual ssize_t process(void* ctx, bool& exit_loop) = 0; }; } #endif // GALERA_ACTION_SOURCE_HPP percona-galera-3-3.8-3390/galera/src/certification.cpp000066400000000000000000001024401244131713600223540ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "certification.hpp" #include "uuid.hpp" #include "gu_lock.hpp" #include "gu_throw.hpp" #include using namespace galera; static const bool cert_debug_on(false); #define cert_debug \ if (cert_debug_on == false) { } \ else log_info << "cert debug: " #define CERT_PARAM_LOG_CONFLICTS galera::Certification::PARAM_LOG_CONFLICTS static std::string const CERT_PARAM_PREFIX("cert."); std::string const galera::Certification::PARAM_LOG_CONFLICTS(CERT_PARAM_PREFIX + "log_conflicts"); static std::string const CERT_PARAM_MAX_LENGTH (CERT_PARAM_PREFIX + "max_length"); static std::string const CERT_PARAM_LENGTH_CHECK (CERT_PARAM_PREFIX + "length_check"); static std::string const CERT_PARAM_LOG_CONFLICTS_DEFAULT("no"); /*** It is EXTREMELY important that these constants are the same on all nodes. *** Don't change them ever!!! ***/ static std::string const CERT_PARAM_MAX_LENGTH_DEFAULT("16384"); static std::string const CERT_PARAM_LENGTH_CHECK_DEFAULT("127"); void galera::Certification::register_params(gu::Config& cnf) { cnf.add(CERT_PARAM_LOG_CONFLICTS, CERT_PARAM_LOG_CONFLICTS_DEFAULT); /* The defaults below are deliberately not reflected in conf: people * should not know about these dangerous setting unless they read RTFM. */ cnf.add(CERT_PARAM_MAX_LENGTH); cnf.add(CERT_PARAM_LENGTH_CHECK); } /* a function to get around unset defaults in ctor initialization list */ static int max_length(const gu::Config& conf) { if (conf.is_set(CERT_PARAM_MAX_LENGTH)) return conf.get(CERT_PARAM_MAX_LENGTH); else return gu::Config::from_config(CERT_PARAM_MAX_LENGTH_DEFAULT); } /* a function to get around unset defaults in ctor initialization list */ static int length_check(const gu::Config& conf) { if (conf.is_set(CERT_PARAM_LENGTH_CHECK)) return conf.get(CERT_PARAM_LENGTH_CHECK); else return gu::Config::from_config(CERT_PARAM_LENGTH_CHECK_DEFAULT); } void galera::Certification::purge_for_trx_v1to2(TrxHandle* trx) { TrxHandle::CertKeySet& refs(trx->cert_keys_); // Unref all referenced and remove if was referenced only by us for (TrxHandle::CertKeySet::iterator i = refs.begin(); i != refs.end(); ++i) { KeyEntryOS* const kel(i->first); const bool full_key(i->second.first); const bool shared(i->second.second); CertIndex::iterator ci(cert_index_.find(kel)); assert(ci != cert_index_.end()); KeyEntryOS* const ke(*ci); if (shared == false && (ke->ref_trx() == trx || ke->ref_full_trx() == trx)) { ke->unref(trx, full_key); } if (shared == true && (ke->ref_shared_trx() == trx || ke->ref_full_shared_trx() == trx)) { ke->unref_shared(trx, full_key); } if (ke->ref_trx() == 0 && ke->ref_shared_trx() == 0) { assert(ke->ref_full_trx() == 0); assert(ke->ref_full_shared_trx() == 0); delete ke; cert_index_.erase(ci); } if (kel != ke) delete kel; } } void galera::Certification::purge_for_trx_v3(TrxHandle* trx) { const KeySetIn& keys(trx->write_set_in().keyset()); keys.rewind(); // Unref all referenced and remove if was referenced only by us for (long i = 0; i < keys.count(); ++i) { const KeySet::KeyPart& kp(keys.next()); KeySet::Key::Prefix const p(kp.prefix()); KeyEntryNG ke(kp); CertIndexNG::iterator const ci(cert_index_ng_.find(&ke)); // assert(ci != cert_index_ng_.end()); if (gu_unlikely(cert_index_ng_.end() == ci)) { log_warn << "Missing key"; continue; } KeyEntryNG* const kep(*ci); assert(kep->referenced()); if (kep->ref_trx(p) == trx) { kep->unref(p, trx); if (kep->referenced() == false) { cert_index_ng_.erase(ci); delete kep; } } } } void galera::Certification::purge_for_trx(TrxHandle* trx) { if (trx->new_version()) purge_for_trx_v3(trx); else purge_for_trx_v1to2(trx); } /*! for convenience returns true if conflict and false if not */ static inline bool certify_and_depend_v1to2(const galera::KeyEntryOS* const match, galera::TrxHandle* const trx, bool const full_key, bool const exclusive_key, bool const log_conflict) { // 1) if the key is full, match for any trx // 2) if the key is partial, match for trx with full key const galera::TrxHandle* const ref_trx(full_key == true ? match->ref_trx() : match->ref_full_trx()); if (cert_debug_on && ref_trx) { cert_debug << "exclusive match (" << (full_key == true ? "full" : "partial") << ") " << *trx << " <-----> " << *ref_trx; } wsrep_seqno_t const ref_seqno(ref_trx ? ref_trx->global_seqno() : -1); // trx should not have any references in index at this point assert(ref_trx != trx); if (gu_likely(0 != ref_trx)) { // cert conflict takes place if // 1) write sets originated from different nodes, are within cert range // 2) ref_trx is in isolation mode, write sets are within cert range if ((trx->source_id() != ref_trx->source_id() || (ref_trx->flags() & galera::TrxHandle::F_ISOLATION) != 0) && ref_seqno > trx->last_seen_seqno()) { if (gu_unlikely(log_conflict == true)) { log_info << "trx conflict for key " << match->get_key(ref_trx->version()) << ": " << *trx << " <--X--> " << *ref_trx; } return true; } } wsrep_seqno_t depends_seqno(ref_seqno); if (exclusive_key) // exclusive keys must depend on shared refs as well { const galera::TrxHandle* const ref_shared_trx(full_key == true ? match->ref_shared_trx() : match->ref_full_shared_trx()); assert(ref_shared_trx != trx); if (ref_shared_trx) { cert_debug << "shared match (" << (full_key == true ? "full" : "partial") << ") " << *trx << " <-----> " << *ref_shared_trx; depends_seqno = std::max(ref_shared_trx->global_seqno(), depends_seqno); } } trx->set_depends_seqno(std::max(trx->depends_seqno(), depends_seqno)); return false; } static bool certify_v1to2(galera::TrxHandle* trx, galera::Certification::CertIndex& cert_index, const galera::KeyOS& key, bool const store_keys, bool const log_conflicts) { typedef std::list KPS; KPS key_parts(key.key_parts()); KPS::const_iterator begin(key_parts.begin()), end; bool full_key(false); galera::TrxHandle::CertKeySet& key_list(trx->cert_keys()); for (end = begin; full_key == false; end != key_parts.end() ? ++end : end) { full_key = (end == key_parts.end()); galera::Certification::CertIndex::iterator ci; galera::KeyEntryOS ke(key.version(), begin, end, key.flags()); cert_debug << "key: " << ke.get_key() << " (" << (full_key == true ? "full" : "partial") << ")"; bool const shared_key(ke.get_key().flags() & galera::KeyOS::F_SHARED); if (store_keys && (key_list.find(&ke) != key_list.end())) { // avoid certification for duplicates // should be removed once we can eleminate dups on deserialization continue; } galera::KeyEntryOS* kep; if ((ci = cert_index.find(&ke)) == cert_index.end()) { if (store_keys) { kep = new galera::KeyEntryOS(ke); ci = cert_index.insert(kep).first; cert_debug << "created new entry"; } } else { cert_debug << "found existing entry"; // Note: For we skip certification for isolated trxs, only // cert index and key_list is populated. if ((trx->flags() & galera::TrxHandle::F_ISOLATION) == 0 && certify_and_depend_v1to2(*ci, trx, full_key, !shared_key, log_conflicts)) { return false; } if (store_keys) { if (gu_likely( true == ke.get_key().equal_all((*ci)->get_key()))) { kep = *ci; } else { // duplicate with different flags - need to store a copy kep = new galera::KeyEntryOS(ke); } } } if (store_keys) { key_list.insert(std::make_pair(kep, std::make_pair(full_key, shared_key))); } } return true; } galera::Certification::TestResult galera::Certification::do_test_v1to2(TrxHandle* trx, bool store_keys) { cert_debug << "BEGIN CERTIFICATION v1to2: " << *trx; #ifndef NDEBUG // to check that cleanup after cert failure returns cert_index_ // to original size size_t prev_cert_index_size(cert_index_.size()); #endif // NDEBUG galera::TrxHandle::CertKeySet& key_list(trx->cert_keys_); long key_count(0); size_t offset(0); const gu::byte_t* buf(trx->write_set_buffer().first); const size_t buf_len(trx->write_set_buffer().second); while (offset < buf_len) { std::pair k(WriteSet::segment(buf, buf_len, offset)); // Scan over all keys offset = k.first; while (offset < k.first + k.second) { KeyOS key(trx->version()); offset = key.unserialize(buf, buf_len, offset); if (certify_v1to2(trx, cert_index_, key, store_keys, log_conflicts_) == false) { goto cert_fail; } ++key_count; } // Skip data part std::pair d(WriteSet::segment(buf, buf_len, offset)); offset = d.first + d.second; } trx->set_depends_seqno(std::max(trx->depends_seqno(), last_pa_unsafe_)); if (store_keys == true) { for (TrxHandle::CertKeySet::iterator i(key_list.begin()); i != key_list.end();) { KeyEntryOS* const kel(i->first); CertIndex::const_iterator ci(cert_index_.find(kel)); if (ci == cert_index_.end()) { gu_throw_fatal << "could not find key '" << kel->get_key() << "' from cert index"; } KeyEntryOS* const ke(*ci); const bool full_key(i->second.first); const bool shared_key(i->second.second); bool keep(false); if (shared_key == false) { if ((full_key == false && ke->ref_trx() != trx) || (full_key == true && ke->ref_full_trx() != trx)) { ke->ref(trx, full_key); keep = true; } } else { if ((full_key == false && ke->ref_shared_trx() != trx) || (full_key == true && ke->ref_full_shared_trx() != trx)) { ke->ref_shared(trx, full_key); keep = true; } } if (keep) { ++i; } else { // this should not happen with Map, but with List is possible i = key_list.erase(i); if (kel != ke) delete kel; } } if (trx->pa_unsafe()) last_pa_unsafe_ = trx->global_seqno(); key_count_ += key_count; } cert_debug << "END CERTIFICATION (success): " << *trx; return TEST_OK; cert_fail: cert_debug << "END CERTIFICATION (failed): " << *trx; if (store_keys == true) { // Clean up key entries allocated for this trx for (TrxHandle::CertKeySet::iterator i(key_list.begin()); i != key_list.end(); ++i) { KeyEntryOS* const kel(i->first); // Clean up cert_index_ from entries which were added by this trx CertIndex::iterator ci(cert_index_.find(kel)); if (ci != cert_index_.end()) { KeyEntryOS* ke(*ci); if (ke->ref_trx() == 0 && ke->ref_shared_trx() == 0) { // kel was added to cert_index_ by this trx - // remove from cert_index_ and fall through to delete if (ke->get_key().flags() != kel->get_key().flags()) { // two copies of keys in key list, shared and exclusive, // skip the one which was not used to create key entry assert(key_list.find(ke) != key_list.end()); continue; } assert(ke->ref_full_trx() == 0); assert(ke->ref_full_shared_trx() == 0); assert(kel == ke); cert_index_.erase(ci); } else if (ke == kel) { // kel was added and is referenced by another trx - skip it continue; } // else kel != ke : kel is a duplicate of ke with different // flags, fall through to delete } else { assert(0); // we actually should never be here, the key should // be either added to cert_index_ or be there already log_warn << "could not find key '" << kel->get_key() << "' from cert index"; } assert(kel->ref_trx() == 0); assert(kel->ref_shared_trx() == 0); assert(kel->ref_full_trx() == 0); assert(kel->ref_full_shared_trx() == 0); delete kel; } assert(cert_index_.size() == prev_cert_index_size); } return TEST_FAILED; } /*! for convenience returns true if conflict and false if not */ static inline bool certify_and_depend_v3(const galera::KeyEntryNG* const found, const galera::KeySet::KeyPart& key, galera::TrxHandle* const trx, bool const log_conflict) { const galera::TrxHandle* const ref_trx( found->ref_trx(galera::KeySet::Key::P_EXCLUSIVE)); if (cert_debug_on && ref_trx) { cert_debug << "exclusive match: " << *trx << " <-----> " << *ref_trx; } wsrep_seqno_t const ref_seqno(ref_trx ? ref_trx->global_seqno() : -1); // trx should not have any references in index at this point assert(ref_trx != trx); if (gu_likely(0 != ref_trx)) { // cert conflict takes place if // 1) write sets originated from different nodes, are within cert range // 2) ref_trx is in isolation mode, write sets are within cert range if ((trx->source_id() != ref_trx->source_id() || ref_trx->is_toi()) && ref_seqno > trx->last_seen_seqno()) { if (gu_unlikely(log_conflict == true)) { log_info << "trx conflict for key " << key << ": " << *trx << " <--X--> " << *ref_trx; } return true; } } wsrep_seqno_t depends_seqno(ref_seqno); galera::KeySet::Key::Prefix const pfx (key.prefix()); if (pfx == galera::KeySet::Key::P_EXCLUSIVE) // exclusive keys must depend on shared refs as well { const galera::TrxHandle* const ref_shared_trx( found->ref_trx(galera::KeySet::Key::P_SHARED)); assert(ref_shared_trx != trx); if (ref_shared_trx) { cert_debug << "shared match: " << *trx << " <-----> " << *ref_shared_trx; depends_seqno = std::max(ref_shared_trx->global_seqno(), depends_seqno); } } trx->set_depends_seqno(std::max(trx->depends_seqno(), depends_seqno)); return false; } /* returns true on collision, false otherwise */ static bool certify_v3(galera::Certification::CertIndexNG& cert_index_ng, const galera::KeySet::KeyPart& key, galera::TrxHandle* trx, bool const store_keys, bool const log_conflicts) { galera::KeyEntryNG ke(key); galera::Certification::CertIndexNG::iterator ci(cert_index_ng.find(&ke)); if (cert_index_ng.end() == ci) { if (store_keys) { galera::KeyEntryNG* const kep(new galera::KeyEntryNG(ke)); ci = cert_index_ng.insert(kep).first; cert_debug << "created new entry"; } return false; } else { cert_debug << "found existing entry"; galera::KeyEntryNG* const kep(*ci); // Note: For we skip certification for isolated trxs, only // cert index and key_list is populated. return (!trx->is_toi() && certify_and_depend_v3(kep, key, trx, log_conflicts)); } } galera::Certification::TestResult galera::Certification::do_test_v3(TrxHandle* trx, bool store_keys) { cert_debug << "BEGIN CERTIFICATION v3: " << *trx; #ifndef NDEBUG // to check that cleanup after cert failure returns cert_index_ // to original size size_t prev_cert_index_size(cert_index_.size()); #endif // NDEBUG const KeySetIn& key_set(trx->write_set_in().keyset()); long const key_count(key_set.count()); long processed(0); assert(key_count > 0); key_set.rewind(); for (; processed < key_count; ++processed) { const KeySet::KeyPart& key(key_set.next()); if (certify_v3(cert_index_ng_, key, trx, store_keys, log_conflicts_)) { goto cert_fail; } } trx->set_depends_seqno(std::max(trx->depends_seqno(), last_pa_unsafe_)); if (store_keys == true) { assert (key_count == processed); key_set.rewind(); for (long i(0); i < key_count; ++i) { const KeySet::KeyPart& k(key_set.next()); KeyEntryNG ke(k); CertIndexNG::const_iterator ci(cert_index_ng_.find(&ke)); if (ci == cert_index_ng_.end()) { gu_throw_fatal << "could not find key '" << k << "' from cert index"; } KeyEntryNG* const kep(*ci); kep->ref(k.prefix(), k, trx); } if (trx->pa_unsafe()) last_pa_unsafe_ = trx->global_seqno(); key_count_ += key_count; } cert_debug << "END CERTIFICATION (success): " << *trx; return TEST_OK; cert_fail: cert_debug << "END CERTIFICATION (failed): " << *trx; assert (processed < key_count); if (store_keys == true) { /* Clean up key entries allocated for this trx */ key_set.rewind(); /* 'strictly less' comparison is essential in the following loop: * processed key failed cert and was not added to index */ for (long i(0); i < processed; ++i) { KeyEntryNG ke(key_set.next()); // Clean up cert_index_ from entries which were added by this trx CertIndexNG::iterator ci(cert_index_ng_.find(&ke)); if (ci != cert_index_ng_.end()) { KeyEntryNG* kep(*ci); if (kep->referenced() == false) { // kel was added to cert_index_ by this trx - // remove from cert_index_ and fall through to delete cert_index_ng_.erase(ci); } else continue; assert(kep->referenced() == false); delete kep; } else { assert(0); // we actually should never be here, the key should // be either added to cert_index_ or be there already log_warn << "could not find key '" << ke.key() << "' from cert index"; } } assert(cert_index_.size() == prev_cert_index_size); } return TEST_FAILED; } galera::Certification::TestResult galera::Certification::do_test(TrxHandle* trx, bool store_keys) { if (trx->version() != version_) { log_warn << "trx protocol version: " << trx->version() << " does not match certification protocol version: " << version_; return TEST_FAILED; } if (gu_unlikely(trx->last_seen_seqno() < initial_position_ || trx->global_seqno() - trx->last_seen_seqno() > max_length_)) { if (trx->last_seen_seqno() < initial_position_) { if (cert_index_.empty() == false) { log_warn << "last seen seqno below limit for trx " << *trx; } else { log_debug << "last seen seqno below limit for trx " << *trx; } } if (trx->global_seqno() - trx->last_seen_seqno() > max_length_) { log_warn << "certification interval for trx " << *trx << " exceeds the limit of " << max_length_; } return TEST_FAILED; } TestResult res(TEST_FAILED); gu::Lock lock(mutex_); // why do we need that? certification access // must be fully guarded by the local_monitor_ /* initialize parent seqno */ if ((trx->flags() & (TrxHandle::F_ISOLATION | TrxHandle::F_PA_UNSAFE)) || trx_map_.empty()) { trx->set_depends_seqno(trx->global_seqno() - 1); } else { trx->set_depends_seqno( trx_map_.begin()->second->global_seqno() - 1); } switch (version_) { case 1: case 2: res = do_test_v1to2(trx, store_keys); break; case 3: res = do_test_v3(trx, store_keys); break; default: gu_throw_fatal << "certification test for version " << version_ << " not implemented"; } if (store_keys == true && res == TEST_OK) { gu::Lock lock(stats_mutex_); ++n_certified_; deps_dist_ += (trx->global_seqno() - trx->depends_seqno()); cert_interval_ += (trx->global_seqno() - trx->last_seen_seqno() - 1); index_size_ = (cert_index_.size() + cert_index_ng_.size()); } return res; } galera::Certification::TestResult galera::Certification::do_test_preordered(TrxHandle* trx) { assert(trx->new_version()); assert(trx->preordered()); /* we don't want to go any further unless the writeset checksum is ok */ trx->verify_checksum(); // throws /* if checksum failed we need to throw ASAP, let the caller catch it, * flush monitors, save state and abort. */ /* This is a primitive certification test for preordered actions: * it does not handle gaps and relies on general apply monitor for * parallel applying. Ideally there should be a certification object * per source. */ if (gu_unlikely(last_preordered_id_ && (last_preordered_id_ + 1 != trx->trx_id()))) { log_warn << "Gap in preordered stream: source_id '" << trx->source_id() << "', trx_id " << trx->trx_id() << ", previous id " << last_preordered_id_; assert(0); } trx->set_depends_seqno(last_preordered_seqno_ - trx->write_set_in().pa_range() + 1); // +1 compensates for subtracting from a previous seqno, rather than own. last_preordered_seqno_ = trx->global_seqno(); last_preordered_id_ = trx->trx_id(); return TEST_OK; } galera::Certification::Certification(gu::Config& conf, ServiceThd& thd) : version_ (-1), trx_map_ (), cert_index_ (), cert_index_ng_ (), deps_set_ (), service_thd_ (thd), mutex_ (), trx_size_warn_count_ (0), initial_position_ (-1), position_ (-1), safe_to_discard_seqno_ (-1), last_pa_unsafe_ (-1), last_preordered_seqno_ (position_), last_preordered_id_ (0), stats_mutex_ (), n_certified_ (0), deps_dist_ (0), cert_interval_ (0), index_size_ (0), key_count_ (0), max_length_ (max_length(conf)), max_length_check_ (length_check(conf)), log_conflicts_ (conf.get(CERT_PARAM_LOG_CONFLICTS)) {} galera::Certification::~Certification() { log_info << "cert index usage at exit " << cert_index_.size(); log_info << "cert trx map usage at exit " << trx_map_.size(); log_info << "deps set usage at exit " << deps_set_.size(); double avg_cert_interval(0); double avg_deps_dist(0); size_t index_size(0); stats_get(avg_cert_interval, avg_deps_dist, index_size); log_info << "avg deps dist " << avg_deps_dist; log_info << "avg cert interval " << avg_cert_interval; log_info << "cert index size " << index_size; gu::Lock lock(mutex_); for_each(trx_map_.begin(), trx_map_.end(), PurgeAndDiscard(*this)); service_thd_.release_seqno(position_); service_thd_.flush(); } void galera::Certification::assign_initial_position(wsrep_seqno_t seqno, int version) { switch (version) { // value -1 used in initialization when trx protocol version is not // available case -1: case 1: case 2: case 3: break; default: gu_throw_fatal << "certification/trx version " << version << " not supported"; } gu::Lock lock(mutex_); if (seqno >= position_) { std::for_each(trx_map_.begin(), trx_map_.end(), PurgeAndDiscard(*this)); assert(cert_index_.size() == 0); assert(cert_index_ng_.size() == 0); } else { log_warn << "moving position backwards: " << position_ << " -> " << seqno; std::for_each(cert_index_.begin(), cert_index_.end(), gu::DeleteObject()); std::for_each(cert_index_ng_.begin(), cert_index_ng_.end(), gu::DeleteObject()); std::for_each(trx_map_.begin(), trx_map_.end(), Unref2nd()); cert_index_.clear(); cert_index_ng_.clear(); } trx_map_.clear(); service_thd_.release_seqno(position_); service_thd_.flush(); log_info << "Assign initial position for certification: " << seqno << ", protocol version: " << version; initial_position_ = seqno; position_ = seqno; safe_to_discard_seqno_ = seqno; last_pa_unsafe_ = seqno; last_preordered_seqno_ = position_; last_preordered_id_ = 0; version_ = version; } galera::Certification::TestResult galera::Certification::test(TrxHandle* trx, bool bval) { assert(trx->global_seqno() >= 0 && trx->local_seqno() >= 0); const TestResult ret (trx->preordered() ? do_test_preordered(trx) : do_test(trx, bval)); if (gu_unlikely(ret != TEST_OK)) { // make sure that last depends seqno is -1 for trxs that failed // certification trx->set_depends_seqno(WSREP_SEQNO_UNDEFINED); } return ret; } wsrep_seqno_t galera::Certification::get_safe_to_discard_seqno_() const { wsrep_seqno_t retval; if (deps_set_.empty() == true) { retval = safe_to_discard_seqno_; } else { retval = (*deps_set_.begin()) - 1; } return retval; } wsrep_seqno_t galera::Certification::purge_trxs_upto_(wsrep_seqno_t const seqno, bool const handle_gcache) { assert (seqno > 0); TrxMap::iterator purge_bound(trx_map_.upper_bound(seqno)); cert_debug << "purging index up to " << seqno; for_each(trx_map_.begin(), purge_bound, PurgeAndDiscard(*this)); trx_map_.erase(trx_map_.begin(), purge_bound); if (handle_gcache) service_thd_.release_seqno(seqno); if (0 == ((trx_map_.size() + 1) % 10000)) { log_debug << "trx map after purge: length: " << trx_map_.size() << ", requested purge seqno: " << seqno << ", real purge seqno: " << trx_map_.begin()->first - 1; } return seqno; } galera::Certification::TestResult galera::Certification::append_trx(TrxHandle* trx) { // todo: enable when source id bug is fixed assert(trx->source_id() != WSREP_UUID_UNDEFINED); assert(trx->global_seqno() >= 0 && trx->local_seqno() >= 0); assert(trx->global_seqno() > position_); trx->ref(); { gu::Lock lock(mutex_); if (gu_unlikely(trx->global_seqno() != position_ + 1)) { // this is perfectly normal if trx is rolled back just after // replication, keeping the log though log_debug << "seqno gap, position: " << position_ << " trx seqno " << trx->global_seqno(); } if (gu_unlikely((trx->last_seen_seqno() + 1) < trx_map_.begin()->first)) { /* See #733 - for now it is false positive */ cert_debug << "WARNING: last_seen_seqno is below certification index: " << trx_map_.begin()->first << " > " << trx->last_seen_seqno(); } position_ = trx->global_seqno(); if (gu_unlikely(!(position_ & max_length_check_) && (trx_map_.size() > static_cast(max_length_)))) { log_debug << "trx map size: " << trx_map_.size() << " - check if status.last_committed is incrementing"; wsrep_seqno_t trim_seqno(position_ - max_length_); wsrep_seqno_t const stds (get_safe_to_discard_seqno_()); if (trim_seqno > stds) { log_warn << "Attempt to trim certification index at " << trim_seqno << ", above safe-to-discard: " << stds; trim_seqno = stds; } else { cert_debug << "purging index up to " << trim_seqno; } purge_trxs_upto_(trim_seqno, true); } } const TestResult retval(test(trx)); { gu::Lock lock(mutex_); if (trx_map_.insert( std::make_pair(trx->global_seqno(), trx)).second == false) gu_throw_fatal << "duplicate trx entry " << *trx; deps_set_.insert(trx->last_seen_seqno()); assert(deps_set_.size() <= trx_map_.size()); } trx->mark_certified(); return retval; } wsrep_seqno_t galera::Certification::set_trx_committed(TrxHandle* trx) { assert(trx->global_seqno() >= 0 && trx->local_seqno() >= 0 && trx->is_committed() == false); wsrep_seqno_t ret(-1); { gu::Lock lock(mutex_); if (trx->is_certified() == true) { // trxs with depends_seqno == -1 haven't gone through // append_trx DepsSet::iterator i(deps_set_.find(trx->last_seen_seqno())); assert(i != deps_set_.end()); if (deps_set_.size() == 1) safe_to_discard_seqno_ = *i; deps_set_.erase(i); } if (gu_unlikely(index_purge_required())) { ret = get_safe_to_discard_seqno_(); } } trx->mark_committed(); trx->clear(); return ret; } galera::TrxHandle* galera::Certification::get_trx(wsrep_seqno_t seqno) { gu::Lock lock(mutex_); TrxMap::iterator i(trx_map_.find(seqno)); if (i == trx_map_.end()) return 0; i->second->ref(); return i->second; } void galera::Certification::set_log_conflicts(const std::string& str) { try { bool const old(log_conflicts_); log_conflicts_ = gu::Config::from_config(str); if (old != log_conflicts_) { log_info << (log_conflicts_ ? "Enabled" : "Disabled") << " logging of certification conflicts."; } } catch (gu::NotFound& e) { gu_throw_error(EINVAL) << "Bad value '" << str << "' for boolean parameter '" << CERT_PARAM_LOG_CONFLICTS << '\''; } } percona-galera-3-3.8-3390/galera/src/certification.hpp000066400000000000000000000145271244131713600223710ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_CERTIFICATION_HPP #define GALERA_CERTIFICATION_HPP #include "trx_handle.hpp" #include "key_entry_ng.hpp" #include "galera_service_thd.hpp" #include "gu_unordered.hpp" #include "gu_lock.hpp" #include "gu_config.hpp" #include #include #include namespace galera { class Certification { public: static std::string const PARAM_LOG_CONFLICTS; static void register_params(gu::Config&); typedef gu::UnorderedSet CertIndex; typedef gu::UnorderedSet CertIndexNG; private: typedef std::multiset DepsSet; typedef std::map TrxMap; public: typedef enum { TEST_OK, TEST_FAILED } TestResult; Certification(gu::Config& conf, ServiceThd& thd); ~Certification(); void assign_initial_position(wsrep_seqno_t seqno, int versiono); TestResult append_trx(TrxHandle*); TestResult test(TrxHandle*, bool = true); wsrep_seqno_t position() const { return position_; } wsrep_seqno_t get_safe_to_discard_seqno() const { gu::Lock lock(mutex_); return get_safe_to_discard_seqno_(); } wsrep_seqno_t purge_trxs_upto(wsrep_seqno_t const seqno, bool const handle_gcache) { gu::Lock lock(mutex_); const wsrep_seqno_t stds(get_safe_to_discard_seqno_()); // assert(seqno <= get_safe_to_discard_seqno()); // Note: setting trx committed is not done in total order so // safe to discard seqno may decrease. Enable assertion above when // this issue is fixed. return purge_trxs_upto_(std::min(seqno, stds), handle_gcache); } // Set trx corresponding to handle committed. Return purge seqno if // index purge is required, -1 otherwise. wsrep_seqno_t set_trx_committed(TrxHandle*); TrxHandle* get_trx(wsrep_seqno_t); // statistics section void stats_get(double& avg_cert_interval, double& avg_deps_dist, size_t& index_size) const { gu::Lock lock(stats_mutex_); avg_cert_interval = 0; avg_deps_dist = 0; if (n_certified_) { avg_cert_interval = double(cert_interval_) / n_certified_; avg_deps_dist = double(deps_dist_) / n_certified_; } index_size = index_size_; } void stats_reset() { gu::Lock lock(stats_mutex_); cert_interval_ = 0; deps_dist_ = 0; n_certified_ = 0; index_size_ = 0; } bool index_purge_required() { register long const count(key_count_.fetch_and_zero()); return ((count > Certification::purge_interval_ || (trx_map_.size() + 1) % 128 == 0) || (key_count_ += count /* restore count */, false)); } void set_log_conflicts(const std::string& str); private: TestResult do_test(TrxHandle*, bool); TestResult do_test_v1to2(TrxHandle*, bool); TestResult do_test_v3(TrxHandle*, bool); TestResult do_test_preordered(TrxHandle*); void purge_for_trx(TrxHandle*); void purge_for_trx_v1to2(TrxHandle*); void purge_for_trx_v3(TrxHandle*); // unprotected variants for internal use wsrep_seqno_t get_safe_to_discard_seqno_() const; wsrep_seqno_t purge_trxs_upto_(wsrep_seqno_t, bool sync); class PurgeAndDiscard { public: PurgeAndDiscard(Certification& cert) : cert_(cert) { } void operator()(TrxMap::value_type& vt) const { { TrxHandle* trx(vt.second); TrxHandleLock lock(*trx); if (trx->is_committed() == false) { log_warn << "trx not committed in purge and discard: " << *trx; } if (trx->depends_seqno() > -1) { cert_.purge_for_trx(trx); } if (trx->refcnt() > 1) { log_debug << "trx " << trx->trx_id() << " refcnt " << trx->refcnt(); } } vt.second->unref(); } PurgeAndDiscard(const PurgeAndDiscard& other) : cert_(other.cert_) { } private: void operator=(const PurgeAndDiscard&); Certification& cert_; }; int version_; TrxMap trx_map_; CertIndex cert_index_; CertIndexNG cert_index_ng_; DepsSet deps_set_; ServiceThd& service_thd_; gu::Mutex mutex_; size_t trx_size_warn_count_; wsrep_seqno_t initial_position_; wsrep_seqno_t position_; wsrep_seqno_t safe_to_discard_seqno_; wsrep_seqno_t last_pa_unsafe_; wsrep_seqno_t last_preordered_seqno_; wsrep_trx_id_t last_preordered_id_; gu::Mutex stats_mutex_; size_t n_certified_; wsrep_seqno_t deps_dist_; wsrep_seqno_t cert_interval_; size_t index_size_; gu::Atomic key_count_; /* The only reason those are not static constants is because * there might be a need to thange them without recompilation. * see #454 */ int const max_length_; /* Purge trx_map_ when it exceeds this * NOTE: this effectively sets a limit * on trx certification interval */ unsigned int const max_length_check_; /* Mask how often to check */ static int const purge_interval_ = (1UL<<10); bool log_conflicts_; }; } #endif // GALERA_CERTIFICATION_HPP percona-galera-3-3.8-3390/galera/src/data_set.cpp000066400000000000000000000001301244131713600213060ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #include "data_set.hpp" percona-galera-3-3.8-3390/galera/src/data_set.hpp000066400000000000000000000114641244131713600213270ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #ifndef GALERA_DATA_SET_HPP #define GALERA_DATA_SET_HPP #include "gu_rset.hpp" #include "gu_vlq.hpp" namespace galera { class DataSet { public: enum Version { EMPTY = 0, VER1 }; static Version const MAX_VERSION = VER1; static Version version (unsigned int ver) { if (gu_likely (ver <= MAX_VERSION)) return static_cast(ver); gu_throw_error (EINVAL) << "Unrecognized DataSet version: " << ver; } /*! Dummy class to instantiate DataSetOut */ class RecordOut {}; /*! A class to instantiate DataSetIn: provides methods necessary to * iterate over the records serialized into single input buffer */ class RecordIn { public: static size_t serial_size (const gu::byte_t* const buf, size_t const size) { /* There's a single record in a dataset */ return size; } size_t serial_size () const { return size_; } RecordIn (const gu::byte_t* buf, size_t size) : size_(size), buf_(buf) {} gu::Buf buf() { gu::Buf ret = { buf_, size_ }; return ret; } private: ssize_t size_; const gu::byte_t* buf_; }; /* class RecordIn */ }; /* class DataSet */ #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic push # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic ignored "-Weffc++" #endif class DataSetOut : public gu::RecordSetOut { public: DataSetOut () // empty ctor for slave TrxHandle : gu::RecordSetOut(), version_() {} DataSetOut (gu::byte_t* reserved, size_t reserved_size, const BaseName& base_name, DataSet::Version version) : gu::RecordSetOut ( reserved, reserved_size, base_name, check_type (version), ds_to_rs_version(version) ), version_(version) {} size_t append (const void* const src, size_t const size, bool const store) { /* append data as is, don't count as a new record */ gu::RecordSetOut::append (src, size, store, false); /* this will be deserialized using DataSet::RecordIn in DataSetIn */ return size; } DataSet::Version version () const { return count() ? version_ : DataSet::EMPTY; } typedef gu::RecordSet::GatherVector GatherVector; private: // depending on version we may pack data differently DataSet::Version const version_; static gu::RecordSet::CheckType check_type (DataSet::Version ver) { switch (ver) { case DataSet::EMPTY: break; /* Can't create EMPTY DataSetOut */ case DataSet::VER1: return gu::RecordSet::CHECK_MMH128; } throw; } static gu::RecordSet::Version ds_to_rs_version (DataSet::Version ver) { switch (ver) { case DataSet::EMPTY: break; /* Can't create EMPTY DataSetOut */ case DataSet::VER1: return gu::RecordSet::VER1; } throw; } }; class DataSetIn : public gu::RecordSetIn { public: DataSetIn (DataSet::Version ver, const gu::byte_t* buf, size_t size) : gu::RecordSetIn(buf, size, false), version_(ver) {} DataSetIn () : gu::RecordSetIn(), version_(DataSet::EMPTY) {} void init (DataSet::Version ver, const gu::byte_t* buf, size_t size) { gu::RecordSetIn::init(buf, size, false); version_ = ver; } gu::Buf next () const { return gu::RecordSetIn::next().buf(); } private: DataSet::Version version_; }; /* class DataSetIn */ #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) #endif } /* namespace galera */ #endif // GALERA_DATA_SET_HPP percona-galera-3-3.8-3390/galera/src/fsm.hpp000066400000000000000000000133771244131713600203350ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #ifndef GALERA_FSM_HPP #define GALERA_FSM_HPP #include "gu_unordered.hpp" #include "gu_throw.hpp" #include #include namespace galera { class EmptyGuard { public: bool operator()() const { return true; } }; class EmptyAction { public: void operator()() { } }; template class FSM { public: class TransAttr { public: TransAttr() : pre_guard_(0), post_guard_(0), pre_action_(0), post_action_(0) { } std::list pre_guard_; std::list post_guard_; std::list pre_action_; std::list post_action_; }; typedef gu::UnorderedMap TransMap; FSM(State const initial_state) : delete_(true), trans_map_(new TransMap), state_(initial_state), state_hist_() { } FSM(TransMap* const trans_map, State const initial_state) : delete_(false), trans_map_(trans_map), state_(initial_state), state_hist_() { } ~FSM() { if (delete_ == true) delete trans_map_; } void shift_to(State const state) { typename TransMap::iterator i(trans_map_->find(Transition(state_, state))); if (i == trans_map_->end()) { log_fatal << "FSM: no such a transition " << state_ << " -> " << state; // gu_throw_fatal << "FSM: no such a transition " // << state_ << " -> " << state; abort(); // we want to catch it in the stack } typename std::list::const_iterator gi; for (gi = i->second.pre_guard_.begin(); gi != i->second.pre_guard_.end(); ++gi) { if ((*gi)() == false) { log_fatal << "FSM: pre guard failed for " << state_ << " -> " << state; gu_throw_fatal << "FSM: pre guard failed for " << state_ << " -> " << state; } } typename std::list::iterator ai; for (ai = i->second.pre_action_.begin(); ai != i->second.pre_action_.end(); ++ai) { (*ai)(); } state_hist_.push_back(state_); state_ = state; for (ai = i->second.post_action_.begin(); ai != i->second.post_action_.end(); ++ai) { (*ai)(); } for (gi = i->second.post_guard_.begin(); gi != i->second.post_guard_.end(); ++gi) { if ((*gi)() == false) { log_fatal << "FSM: post guard failed for " << state_ << " -> " << state; gu_throw_fatal << "FSM: post guard failed for " << state_ << " -> " << state; } } } const State& operator()() const { return state_; } void add_transition(Transition const& trans) { if (trans_map_->insert( std::make_pair(trans, TransAttr())).second == false) { gu_throw_fatal << "transition " << trans.from() << " -> " << trans.to() << " already exists"; } } void add_pre_guard(Transition const& trans, Guard const& guard) { typename TransMap::iterator i(trans_map_->find(trans)); if (i == trans_map_->end()) { gu_throw_fatal << "no such a transition " << trans.from() << " -> " << trans.to(); } i->second.pre_guard_.push_back(guard); } void add_post_guard(Transition const& trans, Guard const& guard) { typename TransMap::iterator i(trans_map_->find(trans)); if (i == trans_map_->end()) { gu_throw_fatal << "no such a transition " << trans.from() << " -> " << trans.to(); } i->second.post_guard_.push_back(guard); } void add_pre_action(Transition const& trans, Action const& action) { typename TransMap::iterator i(trans_map_->find(trans)); if (i == trans_map_->end()) { gu_throw_fatal << "no such a transition " << trans.from() << " -> " << trans.to(); } i->second.pre_action_.push_back(action); } void add_post_action(Transition const& trans, Action const& action) { typename TransMap::iterator i(trans_map_->find(trans)); if (i == trans_map_->end()) { gu_throw_fatal << "no such a transition " << trans.from() << " -> " << trans.to(); } i->second.post_action_.push_back(action); } private: FSM(const FSM&); void operator=(const FSM&); bool delete_; TransMap* const trans_map_; State state_; std::vector state_hist_; }; } #endif // GALERA_FSM_HPP percona-galera-3-3.8-3390/galera/src/galera_common.hpp000066400000000000000000000022701244131713600223410ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ /*! * @file common.hpp * * @brief Imports definitions from the global common.h */ #ifndef GALERA_COMMON_HPP #define GALERA_COMMON_HPP #if defined(HAVE_COMMON_H) #include #endif #include namespace galera { #if defined(HAVE_COMMON_H) static std::string const TCP_SCHEME(COMMON_TCP_SCHEME); static std::string const UDP_SCHEME(COMMON_UDP_SCHEME); static std::string const SSL_SCHEME(COMMON_SSL_SCHEME); static std::string const BASE_PORT_KEY(COMMON_BASE_PORT_KEY); static std::string const BASE_PORT_DEFAULT(COMMON_BASE_PORT_DEFAULT); static std::string const BASE_HOST_KEY(COMMON_BASE_HOST_KEY); static std::string const GALERA_STATE_FILE(COMMON_STATE_FILE); #else static std::string const TCP_SCHEME("tcp"); static std::string const UDP_SCHEME("udp"); static std::string const SSL_SCHEME("ssl"); static std::string const BASE_PORT_KEY("base_port"); static std::string const BASE_PORT_DEFAULT("4567"); static std::string const BASE_HOST_KEY("base_host"); static std::string const GALERA_STATE_FILE("grastate.dat"); #endif } #endif /* GALERA_COMMON_HPP */ percona-galera-3-3.8-3390/galera/src/galera_exception.hpp000066400000000000000000000031201244131713600230420ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #ifndef GALERA_EXCEPTION_HPP #define GALERA_EXCEPTION_HPP #include "galerautils.hpp" #include "wsrep_api.h" namespace galera { /*! * An exception to handle applier errors and avoid confusing wsrep error codes * with the standard ones */ class ApplyException : public gu::Exception { public: ApplyException (const std::string& msg, int err) : gu::Exception (msg, err) { if (err < 0) // sanity check { log_fatal << "Attempt to throw exception with a " << err << " code"; abort(); } } /* this is just int because we must handle any positive value */ int status () { return get_errno(); } }; static inline const char* wsrep_status_str(wsrep_status_t& status) { switch (status) { case WSREP_OK: return "WSREP_OK"; case WSREP_WARNING: return "WSREP_WARNING"; case WSREP_TRX_MISSING: return "WSREP_TRX_MISSING"; case WSREP_TRX_FAIL: return "WSREP_TRX_FAIL"; case WSREP_BF_ABORT: return "WSREP_BF_ABORT"; case WSREP_CONN_FAIL: return "WSREP_CONN_FAIL"; case WSREP_NODE_FAIL: return "WSREP_NODE_FAIL"; case WSREP_FATAL: return "WSREP_FATAL"; case WSREP_NOT_IMPLEMENTED: return "WSREP_NOT_IMPLEMENTED"; default: return "(unknown code)"; } } /*! * And exception to handle replication errors */ class ReplException : public gu::Exception { public: ReplException (const std::string& msg, int err) : gu::Exception (msg, err) {} }; } #endif /* GALERA_EXCEPTION_HPP */ percona-galera-3-3.8-3390/galera/src/galera_gcs.hpp000066400000000000000000000321251244131713600216270ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_GCS_HPP #define GALERA_GCS_HPP #include "write_set_ng.hpp" #include "wsrep_api.h" #include "gcs.hpp" #include "gu_atomic.hpp" #include "gu_throw.hpp" #include "gu_config.hpp" #include "gu_buf.hpp" #include "gu_status.hpp" #include #include #define GCS_IMPL Gcs namespace galera { class GcsI { public: GcsI() {} virtual ~GcsI() {} virtual ssize_t connect(const std::string& cluster_name, const std::string& cluster_url, bool bootstrap) = 0; virtual ssize_t set_initial_position(const wsrep_uuid_t& uuid, gcs_seqno_t seqno) = 0; virtual void close() = 0; virtual ssize_t recv(gcs_action& act) = 0; typedef WriteSetNG::GatherVector WriteSetVector; virtual ssize_t sendv(const WriteSetVector&, size_t, gcs_act_type_t, bool) = 0; virtual ssize_t send (const void*, size_t, gcs_act_type_t, bool) = 0; virtual ssize_t replv(const WriteSetVector&, gcs_action& act, bool) = 0; virtual ssize_t repl (gcs_action& act, bool) = 0; virtual gcs_seqno_t caused() = 0; virtual ssize_t schedule() = 0; virtual ssize_t interrupt(ssize_t) = 0; virtual ssize_t resume_recv() = 0; virtual ssize_t set_last_applied(gcs_seqno_t) = 0; virtual ssize_t request_state_transfer(int version, const void* req, ssize_t req_len, const std::string& sst_donor, const gu_uuid_t& ist_uuid, gcs_seqno_t ist_seqno, gcs_seqno_t* seqno_l) = 0; virtual ssize_t desync(gcs_seqno_t* seqno_l) = 0; virtual void join(gcs_seqno_t seqno) = 0; virtual gcs_seqno_t local_sequence() = 0; virtual void get_stats(gcs_stats*) const = 0; virtual void flush_stats() = 0; virtual void get_status(gu::Status&) const = 0; /*! @throws NotFound */ virtual void param_set (const std::string& key, const std::string& value) = 0; /*! @throws NotFound */ virtual char* param_get (const std::string& key) const = 0; virtual size_t max_action_size() const = 0; }; class Gcs : public GcsI { public: Gcs(gu::Config& config, gcache::GCache& cache, int repl_proto_ver = 0, int appl_proto_ver = 0, const char* node_name = 0, const char* node_incoming = 0) : conn_(gcs_create(reinterpret_cast(&config), reinterpret_cast(&cache), node_name, node_incoming, repl_proto_ver, appl_proto_ver)) { log_info << "Passing config to GCS: " << config; if (conn_ == 0) gu_throw_fatal << "could not create gcs connection"; } ~Gcs() { gcs_destroy(conn_); } ssize_t connect(const std::string& cluster_name, const std::string& cluster_url, bool const bootstrap) { return gcs_open(conn_, cluster_name.c_str(), cluster_url.c_str(), bootstrap); } ssize_t set_initial_position(const wsrep_uuid_t& uuid, gcs_seqno_t seqno) { return gcs_init(conn_, seqno, uuid.data); } void close() { gcs_close(conn_); } ssize_t recv(struct gcs_action& act) { return gcs_recv(conn_, &act); } ssize_t sendv(const WriteSetVector& actv, size_t act_len, gcs_act_type_t act_type, bool scheduled) { return gcs_sendv(conn_, &actv[0], act_len, act_type, scheduled); } ssize_t send(const void* act, size_t act_len, gcs_act_type_t act_type, bool scheduled) { return gcs_send(conn_, act, act_len, act_type, scheduled); } ssize_t replv(const WriteSetVector& actv, struct gcs_action& act, bool scheduled) { return gcs_replv(conn_, &actv[0], &act, scheduled); } ssize_t repl(struct gcs_action& act, bool scheduled) { return gcs_repl(conn_, &act, scheduled); } gcs_seqno_t caused() { return gcs_caused(conn_); } ssize_t schedule() { return gcs_schedule(conn_); } ssize_t interrupt(ssize_t handle) { return gcs_interrupt(conn_, handle); } ssize_t resume_recv() { return gcs_resume_recv(conn_); } ssize_t set_last_applied(gcs_seqno_t last_applied) { return gcs_set_last_applied(conn_, last_applied); } ssize_t request_state_transfer(int version, const void* req, ssize_t req_len, const std::string& sst_donor, const gu_uuid_t& ist_uuid, gcs_seqno_t ist_seqno, gcs_seqno_t* seqno_l) { return gcs_request_state_transfer(conn_, version, req, req_len, sst_donor.c_str(), &ist_uuid, ist_seqno, seqno_l); } ssize_t desync (gcs_seqno_t* seqno_l) { return gcs_desync(conn_, seqno_l); } void join (gcs_seqno_t seqno) { long const err(gcs_join(conn_, seqno)); if (err < 0) { gu_throw_error (-err) << "gcs_join(" << seqno << ") failed"; } } gcs_seqno_t local_sequence() { return gcs_local_sequence(conn_); } void get_stats(gcs_stats* stats) const { return gcs_get_stats(conn_, stats); } void flush_stats() { return gcs_flush_stats(conn_); } void get_status(gu::Status& status) const { gcs_get_status(conn_, status); } void param_set (const std::string& key, const std::string& value) { long ret = gcs_param_set (conn_, key.c_str(), value.c_str()); if (1 == ret) { throw gu::NotFound(); } else if (ret) { gu_throw_error(-ret) << "Setting '" << key << "' to '" << value << "' failed"; } } char* param_get (const std::string& key) const { gu_throw_error(ENOSYS) << "Not implemented: " << __FUNCTION__; return 0; } size_t max_action_size() const { return GCS_MAX_ACT_SIZE; } private: Gcs(const Gcs&); void operator=(const Gcs&); gcs_conn_t* conn_; }; class DummyGcs : public GcsI { public: DummyGcs(gu::Config& config, gcache::GCache& cache, int repl_proto_ver = 0, int appl_proto_ver = 0, const char* node_name = 0, const char* node_incoming = 0); DummyGcs(); // for unit tests ~DummyGcs(); ssize_t connect(const std::string& cluster_name, const std::string& cluster_url, bool bootstrap); ssize_t set_initial_position(const wsrep_uuid_t& uuid, gcs_seqno_t seqno); void close(); ssize_t recv(gcs_action& act); ssize_t sendv(const WriteSetVector&, size_t, gcs_act_type_t, bool) { return -ENOSYS; } ssize_t send(const void*, size_t, gcs_act_type_t, bool) { return -ENOSYS; } ssize_t replv(const WriteSetVector& actv, gcs_action& act, bool scheduled) { ssize_t ret(set_seqnos(act)); if (gu_likely(0 != gcache_ && ret > 0)) { assert (ret == act.size); gu::byte_t* ptr( reinterpret_cast(gcache_->malloc(act.size))); act.buf = ptr; ssize_t copied(0); for (int i(0); copied < act.size; ++i) { memcpy (ptr + copied, actv[i].ptr, actv[i].size); copied += actv[i].size; } assert (copied == act.size); } return ret; } ssize_t repl(gcs_action& act, bool scheduled) { ssize_t ret(set_seqnos(act)); if (gu_likely(0 != gcache_ && ret > 0)) { assert (ret == act.size); void* ptr(gcache_->malloc(act.size)); memcpy (ptr, act.buf, act.size); act.buf = ptr; } return ret; } gcs_seqno_t caused() { return global_seqno_; } ssize_t schedule() { return 1; } ssize_t interrupt(ssize_t handle); ssize_t resume_recv() { return 0; } ssize_t set_last_applied(gcs_seqno_t last_applied) { gu::Lock lock(mtx_); last_applied_ = last_applied; report_last_applied_ = true; cond_.signal(); return 0; } gcs_seqno_t last_applied() const { return last_applied_; } ssize_t request_state_transfer(int version, const void* req, ssize_t req_len, const std::string& sst_donor, const gu_uuid_t& ist_uuid, gcs_seqno_t ist_seqno, gcs_seqno_t* seqno_l) { *seqno_l = GCS_SEQNO_ILL; return -ENOSYS; } ssize_t desync (gcs_seqno_t* seqno_l) { *seqno_l = GCS_SEQNO_ILL; return -ENOTCONN; } void join(gcs_seqno_t seqno) { gu_throw_error(ENOTCONN); } gcs_seqno_t local_sequence() { gu::Lock lock(mtx_); return ++local_seqno_; } void get_stats(gcs_stats* stats) const { memset (stats, 0, sizeof(*stats)); } void flush_stats() {} void get_status(gu::Status& status) const {} void param_set (const std::string& key, const std::string& value) {} char* param_get (const std::string& key) const { return 0; } size_t max_action_size() const { return 0x7FFFFFFF; } private: typedef enum { S_CLOSED, S_OPEN, S_CONNECTED, S_SYNCED } conn_state_t; ssize_t generate_seqno_action (gcs_action& act, gcs_act_type_t type); ssize_t generate_cc (bool primary); gu::Config* gconf_; gcache::GCache* gcache_; gu::Mutex mtx_; gu::Cond cond_; gcs_seqno_t global_seqno_; gcs_seqno_t local_seqno_; gu_uuid_t uuid_; gcs_seqno_t last_applied_; conn_state_t state_; gu::Lock* schedule_; void* cc_; ssize_t cc_size_; std::string const my_name_; std::string const incoming_; int repl_proto_ver_; int appl_proto_ver_; bool report_last_applied_; ssize_t set_seqnos (gcs_action& act) { act.seqno_g = GCS_SEQNO_ILL; act.seqno_l = GCS_SEQNO_ILL; ssize_t ret(-EBADFD); { gu::Lock lock(mtx_); switch (state_) { case S_CONNECTED: case S_SYNCED: { ++global_seqno_; act.seqno_g = global_seqno_; ++local_seqno_; act.seqno_l = local_seqno_; ret = act.size; break; } case S_CLOSED: ret = -EBADFD; break; case S_OPEN: ret = -ENOTCONN; break; } } return ret; } DummyGcs (const DummyGcs&); DummyGcs& operator=(const DummyGcs&); }; } #endif // GALERA_GCS_HPP percona-galera-3-3.8-3390/galera/src/galera_info.cpp000066400000000000000000000053141244131713600220010ustar00rootroot00000000000000// Copyright (C) 2009-2013 Codership Oy #include "galera_info.hpp" #include #include static size_t view_info_size (int members) { return (sizeof(wsrep_view_info_t) + members * sizeof(wsrep_member_info_t)); } /* create view info out of configuration message */ wsrep_view_info_t* galera_view_info_create (const gcs_act_conf_t* conf, bool st_required) { wsrep_view_info_t* ret = static_cast( malloc(view_info_size(conf ? conf->memb_num : 0))); if (ret) { if (conf) { const char* str = conf->data; int m; wsrep_uuid_t uuid; memcpy(uuid.data, conf->uuid, sizeof(uuid.data)); wsrep_seqno_t seqno = conf->seqno != GCS_SEQNO_ILL ? conf->seqno : WSREP_SEQNO_UNDEFINED; wsrep_gtid_t gtid = { uuid, seqno }; ret->state_id = gtid; ret->view = conf->conf_id; ret->status = conf->conf_id != -1 ? WSREP_VIEW_PRIMARY : WSREP_VIEW_NON_PRIMARY; ret->state_gap = st_required; ret->my_idx = conf->my_idx; ret->memb_num = conf->memb_num; ret->proto_ver = conf->appl_proto_ver; for (m = 0; m < ret->memb_num; m++) { wsrep_member_info_t* member = &ret->members[m]; size_t id_len = strlen(str); gu_uuid_scan (str, id_len, reinterpret_cast(&member->id)); str = str + id_len + 1; strncpy(member->name, str, sizeof(member->name) - 1); member->name[sizeof(member->name) - 1] = '\0'; str = str + strlen(str) + 1; strncpy(member->incoming, str, sizeof(member->incoming) - 1); member->incoming[sizeof(member->incoming) - 1] = '\0'; str = str + strlen(str) + 1; str += sizeof(gcs_seqno_t); // skip cached seqno. } } else { memset(&ret->state_id, 0, sizeof(ret->state_id)); ret->view = -1; ret->status = WSREP_VIEW_NON_PRIMARY; ret->state_gap = false; ret->my_idx = -1; ret->memb_num = 0; ret->proto_ver = -1; } } return ret; } /* make a copy of view info object */ wsrep_view_info_t* galera_view_info_copy (const wsrep_view_info_t* vi) { size_t ret_size = view_info_size (vi->memb_num); wsrep_view_info_t* ret = static_cast(malloc (ret_size)); if (ret) { memcpy (ret, vi, ret_size); } return ret; } percona-galera-3-3.8-3390/galera/src/galera_info.hpp000066400000000000000000000007021244131713600220020ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy #ifndef __GALERA_INFO_H__ #define __GALERA_INFO_H__ #include "gcs.hpp" #include "wsrep_api.h" /* create view info out of configuration message */ extern wsrep_view_info_t* galera_view_info_create (const gcs_act_conf_t* conf, bool st_required); /* make a copy of view info object */ extern wsrep_view_info_t* galera_view_info_copy (const wsrep_view_info_t* vi); #endif // __GALERA_INFO_H__ percona-galera-3-3.8-3390/galera/src/galera_service_thd.cpp000066400000000000000000000075541244131713600233550ustar00rootroot00000000000000/* * Copyright (C) 2010-2013 Codership Oy * * Using broadcasts instead of signals below to wake flush callers due to * theoretical possibility of more than 2 threads involved. */ #include "galera_service_thd.hpp" const uint32_t galera::ServiceThd::A_NONE = 0; static const uint32_t A_LAST_COMMITTED = 1U << 0; static const uint32_t A_RELEASE_SEQNO = 1U << 1; static const uint32_t A_FLUSH = 1U << 30; static const uint32_t A_EXIT = 1U << 31; void* galera::ServiceThd::thd_func (void* arg) { galera::ServiceThd* st = reinterpret_cast(arg); bool exit = false; while (!exit) { galera::ServiceThd::Data data; { gu::Lock lock(st->mtx_); if (A_NONE == st->data_.act_) lock.wait(st->cond_); data = st->data_; st->data_.act_ = A_NONE; // clear pending actions if (data.act_ & A_FLUSH) { if (A_FLUSH == data.act_) { // no other actions scheduled (all previous are "flushed") log_info << "Service thread queue flushed."; st->flush_.broadcast(); } else { // restore flush flag for the next iteration st->data_.act_ |= A_FLUSH; } } } exit = ((data.act_ & A_EXIT)); if (!exit) { if (data.act_ & A_LAST_COMMITTED) { ssize_t const ret (st->gcs_.set_last_applied(data.last_committed_)); if (gu_unlikely(ret < 0)) { log_warn << "Failed to report last committed " << data.last_committed_ << ", " << ret << " (" << strerror (-ret) << ')'; // @todo: figure out what to do in this case } else { log_debug << "Reported last committed: " << data.last_committed_; } } if (data.act_ & A_RELEASE_SEQNO) { try { st->gcache_.seqno_release(data.release_seqno_); } catch (std::exception& e) { log_warn << "Exception releasing seqno " << data.release_seqno_ << ": " << e.what(); } } } } return 0; } galera::ServiceThd::ServiceThd (GcsI& gcs, gcache::GCache& gcache) : gcache_ (gcache), gcs_ (gcs), thd_ (), mtx_ (), cond_ (), flush_ (), data_ () { gu_thread_create (&thd_, NULL, thd_func, this); } galera::ServiceThd::~ServiceThd () { { gu::Lock lock(mtx_); data_.act_ = A_EXIT; cond_.signal(); flush_.broadcast(); } gu_thread_join(thd_, NULL); } void galera::ServiceThd::flush() { gu::Lock lock(mtx_); if (!(data_.act_ & A_EXIT)) { if (data_.act_ == A_NONE) cond_.signal(); data_.act_ |= A_FLUSH; do { lock.wait(flush_); } while (data_.act_ & A_FLUSH); } } void galera::ServiceThd::reset() { gu::Lock lock(mtx_); data_.act_ = A_NONE; data_.last_committed_ = 0; } void galera::ServiceThd::report_last_committed(gcs_seqno_t seqno) { gu::Lock lock(mtx_); if (data_.last_committed_ < seqno) { data_.last_committed_ = seqno; if (data_.act_ == A_NONE) cond_.signal(); data_.act_ |= A_LAST_COMMITTED; } } void galera::ServiceThd::release_seqno(gcs_seqno_t seqno) { gu::Lock lock(mtx_); if (data_.release_seqno_ < seqno) { data_.release_seqno_ = seqno; if (data_.act_ == A_NONE) cond_.signal(); data_.act_ |= A_RELEASE_SEQNO; } } percona-galera-3-3.8-3390/galera/src/galera_service_thd.hpp000066400000000000000000000034361244131713600233550ustar00rootroot00000000000000/* * Copyright (C) 2010-2013 Codership Oy */ #ifndef GALERA_SERVICE_THD_HPP #define GALERA_SERVICE_THD_HPP #include "galera_gcs.hpp" #include #include #include namespace galera { class ServiceThd { public: ServiceThd (GcsI& gcs, gcache::GCache& gcache); ~ServiceThd (); /*! flush all ongoing operations (before processing CC) */ void flush (); /*! reset to initial state before gcs (re)connect */ void reset(); /* !!! * The following methods must be invoked only within a monitor, * so that monitors drain during CC ensures that no outdated * actions are scheduled with the service thread after that. * !!! */ /*! schedule seqno to be reported as last committed */ void report_last_committed (gcs_seqno_t seqno); /*! release write sets up to and including seqno */ void release_seqno (gcs_seqno_t seqno); private: static const uint32_t A_NONE; struct Data { gcs_seqno_t last_committed_; gcs_seqno_t release_seqno_; uint32_t act_; Data() : last_committed_(0), release_seqno_ (0), act_ (A_NONE) {} }; gcache::GCache& gcache_; GcsI& gcs_; gu_thread_t thd_; gu::Mutex mtx_; gu::Cond cond_; // service request condition gu::Cond flush_; // flush condition Data data_; static void* thd_func (void*); ServiceThd (const ServiceThd&); ServiceThd& operator= (const ServiceThd&); }; } #endif /* GALERA_SERVICE_THD_HPP */ percona-galera-3-3.8-3390/galera/src/gcs_action_source.cpp000066400000000000000000000116151244131713600232250ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "replicator.hpp" #include "gcs_action_source.hpp" #include "trx_handle.hpp" #include "gu_serialize.hpp" #include "galera_info.hpp" #include // Exception-safe way to release action pointer when it goes out // of scope class Release { public: Release(struct gcs_action& act, gcache::GCache& gcache) : act_(act), gcache_(gcache) {} ~Release() { switch (act_.type) { case GCS_ACT_TORDERED: break; case GCS_ACT_STATE_REQ: gcache_.free(const_cast(act_.buf)); break; default: ::free(const_cast(act_.buf)); break; } } private: struct gcs_action& act_; gcache::GCache& gcache_; }; static galera::Replicator::State state2repl(const gcs_act_conf_t& conf) { switch (conf.my_state) { case GCS_NODE_STATE_NON_PRIM: if (conf.my_idx >= 0) return galera::Replicator::S_CONNECTED; else return galera::Replicator::S_CLOSING; case GCS_NODE_STATE_PRIM: return galera::Replicator::S_CONNECTED; case GCS_NODE_STATE_JOINER: return galera::Replicator::S_JOINING; case GCS_NODE_STATE_JOINED: return galera::Replicator::S_JOINED; case GCS_NODE_STATE_SYNCED: return galera::Replicator::S_SYNCED; case GCS_NODE_STATE_DONOR: return galera::Replicator::S_DONOR; case GCS_NODE_STATE_MAX:; } gu_throw_fatal << "unhandled gcs state: " << conf.my_state; GU_DEBUG_NORETURN; } galera::GcsActionTrx::GcsActionTrx(TrxHandle::SlavePool& pool, const struct gcs_action& act) : trx_(TrxHandle::New(pool)) // TODO: this dynamic allocation should be unnecessary { assert(act.seqno_l != GCS_SEQNO_ILL); assert(act.seqno_g != GCS_SEQNO_ILL); const gu::byte_t* const buf = static_cast(act.buf); // size_t offset(trx_->unserialize(buf, act.size, 0)); gu_trace(trx_->unserialize(buf, act.size, 0)); //trx_->append_write_set(buf + offset, act.size - offset); // moved to unserialize trx_->set_write_set_buffer(buf + offset, act.size - offset); trx_->set_received(act.buf, act.seqno_l, act.seqno_g); trx_->lock(); } galera::GcsActionTrx::~GcsActionTrx() { assert(trx_->refcnt() >= 1); trx_->unlock(); trx_->unref(); } void galera::GcsActionSource::dispatch(void* const recv_ctx, const struct gcs_action& act, bool& exit_loop) { assert(recv_ctx != 0); assert(act.buf != 0); assert(act.seqno_l > 0); switch (act.type) { case GCS_ACT_TORDERED: { assert(act.seqno_g > 0); GcsActionTrx trx(trx_pool_, act); trx.trx()->set_state(TrxHandle::S_REPLICATING); replicator_.process_trx(recv_ctx, trx.trx()); exit_loop = trx.trx()->exit_loop(); // this is the end of trx lifespan break; } case GCS_ACT_COMMIT_CUT: { wsrep_seqno_t seq; gu::unserialize8(static_cast(act.buf), act.size, 0, seq); replicator_.process_commit_cut(seq, act.seqno_l); break; } case GCS_ACT_CONF: { const gcs_act_conf_t* conf(static_cast(act.buf)); wsrep_view_info_t* view_info( galera_view_info_create(conf, conf->my_state == GCS_NODE_STATE_PRIM) ); replicator_.process_conf_change(recv_ctx, *view_info, conf->repl_proto_ver, state2repl(*conf), act.seqno_l); free(view_info); if (conf->conf_id < 0 && conf->memb_num == 0) { log_debug << "Received SELF-LEAVE. Closing connection."; // called after being shifted to S_CLOSING state. gcs_.close(); } break; } case GCS_ACT_STATE_REQ: replicator_.process_state_req(recv_ctx, act.buf, act.size, act.seqno_l, act.seqno_g); break; case GCS_ACT_JOIN: { wsrep_seqno_t seq; gu::unserialize8(static_cast(act.buf), act.size, 0, seq); replicator_.process_join(seq, act.seqno_l); break; } case GCS_ACT_SYNC: replicator_.process_sync(act.seqno_l); break; default: gu_throw_fatal << "unrecognized action type: " << act.type; } } ssize_t galera::GcsActionSource::process(void* recv_ctx, bool& exit_loop) { struct gcs_action act; ssize_t rc(gcs_.recv(act)); if (rc > 0) { Release release(act, gcache_); ++received_; received_bytes_ += rc; dispatch(recv_ctx, act, exit_loop); } return rc; } percona-galera-3-3.8-3390/galera/src/gcs_action_source.hpp000066400000000000000000000034761244131713600232400ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_GCS_ACTION_SOURCE_HPP #define GALERA_GCS_ACTION_SOURCE_HPP #include "action_source.hpp" #include "galera_gcs.hpp" #include "replicator.hpp" #include "trx_handle.hpp" #include "GCache.hpp" #include "gu_atomic.hpp" namespace galera { class GcsActionSource : public galera::ActionSource { public: GcsActionSource(TrxHandle::SlavePool& sp, GCS_IMPL& gcs, Replicator& replicator, gcache::GCache& gcache) : trx_pool_ (sp ), gcs_ (gcs ), replicator_ (replicator), gcache_ (gcache ), received_ (0 ), received_bytes_(0 ) { } ~GcsActionSource() { log_info << trx_pool_; } ssize_t process(void*, bool& exit_loop); long long received() const { return received_(); } long long received_bytes() const { return received_bytes_(); } private: void dispatch(void*, const gcs_action&, bool& exit_loop); TrxHandle::SlavePool& trx_pool_; GCS_IMPL& gcs_; Replicator& replicator_; gcache::GCache& gcache_; gu::Atomic received_; gu::Atomic received_bytes_; }; class GcsActionTrx { public: GcsActionTrx(TrxHandle::SlavePool& sp, const struct gcs_action& act); ~GcsActionTrx(); TrxHandle* trx() const { return trx_; } private: GcsActionTrx(const GcsActionTrx&); void operator=(const GcsActionTrx&); TrxHandle* trx_; }; } #endif // GALERA_GCS_ACTION_SOURCE_HPP percona-galera-3-3.8-3390/galera/src/gcs_dummy.cpp000066400000000000000000000145041244131713600215230ustar00rootroot00000000000000// // Copyright (C) 2011-2012 Codership Oy // #include "galera_gcs.hpp" namespace galera { DummyGcs::DummyGcs(gu::Config& config, gcache::GCache& cache, int repl_proto_ver, int appl_proto_ver, const char* node_name, const char* node_incoming) : gconf_ (&config), gcache_ (&cache), mtx_ (), cond_ (), global_seqno_ (0), local_seqno_ (0), uuid_ (), last_applied_ (GCS_SEQNO_ILL), state_ (S_OPEN), schedule_ (0), cc_ (0), cc_size_ (0), my_name_ (node_name ? node_name : "not specified"), incoming_ (node_incoming ? node_incoming : "not given"), repl_proto_ver_(repl_proto_ver), appl_proto_ver_(appl_proto_ver), report_last_applied_(false) { gu_uuid_generate (&uuid_, 0, 0); } DummyGcs::DummyGcs() : gconf_ (0), gcache_ (0), mtx_ (), cond_ (), global_seqno_ (0), local_seqno_ (0), uuid_ (), last_applied_ (GCS_SEQNO_ILL), state_ (S_OPEN), schedule_ (0), cc_ (0), cc_size_ (0), my_name_ ("not specified"), incoming_ ("not given"), repl_proto_ver_(1), appl_proto_ver_(1), report_last_applied_(false) { gu_uuid_generate (&uuid_, 0, 0); } DummyGcs::~DummyGcs() { gu::Lock lock(mtx_); assert(0 == schedule_); if (cc_) { assert (cc_size_ > 0); ::free(cc_); } } ssize_t DummyGcs::generate_cc (bool primary) { cc_size_ = sizeof(gcs_act_conf_t) + primary * (my_name_.length() + incoming_.length() + GU_UUID_STR_LEN + 3); cc_ = ::malloc(cc_size_); if (!cc_) { cc_size_ = 0; return -ENOMEM; } gcs_act_conf_t* const cc(reinterpret_cast(cc_)); if (primary) { cc->seqno = global_seqno_; cc->conf_id = 1; memcpy (cc->uuid, &uuid_, sizeof(uuid_)); cc->memb_num = 1; cc->my_idx = 0; cc->my_state = GCS_NODE_STATE_JOINED; cc->repl_proto_ver = repl_proto_ver_; cc->appl_proto_ver = appl_proto_ver_; char* const str(cc->data); ssize_t offt(0); offt += gu_uuid_print (&uuid_, str, GU_UUID_STR_LEN+1) + 1; offt += sprintf (str + offt, "%s", my_name_.c_str()) + 1; sprintf (str + offt, "%s", incoming_.c_str()); } else { cc->seqno = GCS_SEQNO_ILL; cc->conf_id = -1; cc->memb_num = 0; cc->my_idx = -1; cc->my_state = GCS_NODE_STATE_NON_PRIM; } return cc_size_; } ssize_t DummyGcs::connect(const std::string& cluster_name, const std::string& cluster_url, bool bootstrap) { gu::Lock lock(mtx_); ssize_t ret = generate_cc (true); if (ret > 0) { // state_ = S_CONNECTED; cond_.signal(); ret = 0; } return ret; } ssize_t DummyGcs::set_initial_position(const wsrep_uuid_t& uuid, gcs_seqno_t seqno) { gu::Lock lock(mtx_); if (memcmp(&uuid, &GU_UUID_NIL, sizeof(wsrep_uuid_t)) && seqno >= 0) { uuid_ = *(reinterpret_cast(&uuid)); global_seqno_ = seqno; } return 0; } void DummyGcs::close() { log_info << "Closing DummyGcs"; gu::Lock lock(mtx_); generate_cc (false); // state_ = S_CLOSED; cond_.broadcast(); // usleep(100000); // 0.1s } ssize_t DummyGcs::generate_seqno_action (gcs_action& act, gcs_act_type_t type) { gcs_seqno_t* const seqno( reinterpret_cast( ::malloc(sizeof(gcs_seqno_t)))); if (!seqno) return -ENOMEM; *seqno = global_seqno_; ++local_seqno_; act.buf = seqno; act.size = sizeof(gcs_seqno_t); act.seqno_l = local_seqno_; act.type = type; return act.size; } ssize_t DummyGcs::recv(gcs_action& act) { act.seqno_g = GCS_SEQNO_ILL; act.seqno_l = GCS_SEQNO_ILL; gu::Lock lock(mtx_); do { if (cc_) { ++local_seqno_; act.buf = cc_; act.size = cc_size_; act.seqno_l = local_seqno_; act.type = GCS_ACT_CONF; cc_ = 0; cc_size_ = 0; const gcs_act_conf_t* const cc( reinterpret_cast(act.buf)); if (cc->my_idx < 0) { assert (0 == cc->memb_num); state_ = S_CLOSED; } else { assert (1 == cc->memb_num); state_ = S_CONNECTED; } return act.size; } else if (S_CONNECTED == state_) { ssize_t ret = generate_seqno_action(act, GCS_ACT_SYNC); if (ret > 0) state_ = S_SYNCED; return ret; } else if (report_last_applied_) { report_last_applied_ = false; return generate_seqno_action(act, GCS_ACT_COMMIT_CUT); } } while (state_ > S_OPEN && (lock.wait(cond_), true)); switch (state_) { case S_OPEN: return -ENOTCONN; case S_CLOSED: return 0; default: abort(); } } ssize_t DummyGcs::interrupt(ssize_t handle) { log_fatal << "Attempt to interrupt handle: " << handle; abort(); return -ENOSYS; } } percona-galera-3-3.8-3390/galera/src/ist.cpp000066400000000000000000000601501244131713600203310ustar00rootroot00000000000000// // Copyright (C) 2011-2014 Codership Oy // #include "ist.hpp" #include "ist_proto.hpp" #include "gu_logger.hpp" #include "gu_uri.hpp" #include "GCache.hpp" #include "galera_common.hpp" #include #include #include namespace { static std::string const CONF_KEEP_KEYS ("ist.keep_keys"); static bool const CONF_KEEP_KEYS_DEFAULT (true); #ifdef HAVE_ASIO_SSL_HPP static std::string const CONF_SSL_KEY (COMMON_CONF_SSL_KEY); static std::string const CONF_SSL_CERT (COMMON_CONF_SSL_CERT); static std::string const CONF_SSL_CA (COMMON_CONF_SSL_CA); static std::string const CONF_SSL_PSWD_FILE (COMMON_CONF_SSL_PSWD_FILE); #endif /* HAVE_ASIO_SSL_HPP */ static std::string escape_addr(const asio::ip::address& addr) { if (addr.is_v4()) { return addr.to_v4().to_string(); } else { return "[" + addr.to_v6().to_string() + "]"; } } static std::string unescape_addr(const std::string& addr) { std::string ret(addr); size_t pos(ret.find('[')); if (pos != std::string::npos) ret.erase(pos, 1); pos = ret.find(']'); if (pos != std::string::npos) ret.erase(pos, 1); return ret; } template void set_fd_options(S& socket) { long flags(FD_CLOEXEC); if (fcntl(socket.native(), F_SETFD, flags) == -1) { gu_throw_error(errno) << "failed to set FD_CLOEXEC"; } } #ifdef HAVE_ASIO_SSL_HPP class SSLPasswordCallback { public: SSLPasswordCallback(const gu::Config& conf) : conf_(conf) { } std::string get_password() const { std::string file(conf_.get(CONF_SSL_PSWD_FILE)); std::ifstream ifs(file.c_str(), std::ios_base::in); if (ifs.good() == false) { gu_throw_error(errno) << "could not open password file '" << file << "'"; } std::string ret; std::getline(ifs, ret); return ret; } private: const gu::Config& conf_; }; static void prepare_ssl_ctx(const gu::Config& conf, asio::ssl::context& ctx) { // Here we blindly assume that ssl globals have been initialized // by gcomm. ctx.set_verify_mode(asio::ssl::context::verify_peer); SSLPasswordCallback cb(conf); ctx.set_password_callback( boost::bind(&SSLPasswordCallback::get_password, &cb)); ctx.use_private_key_file(conf.get(CONF_SSL_KEY), asio::ssl::context::pem); ctx.use_certificate_file(conf.get(CONF_SSL_CERT), asio::ssl::context::pem); ctx.load_verify_file(conf.get(CONF_SSL_CA, conf.get(CONF_SSL_CERT))); } #endif /* HAVE_ASIO_SSL_HPP */ } namespace galera { namespace ist { class AsyncSender : public Sender { public: AsyncSender(const gu::Config& conf, const std::string& peer, wsrep_seqno_t first, wsrep_seqno_t last, AsyncSenderMap& asmap, int version) : Sender (conf, asmap.gcache(), peer, version), conf_ (conf), peer_ (peer), first_ (first), last_ (last), asmap_ (asmap), thread_() { } const gu::Config& conf() { return conf_; } const std::string& peer() { return peer_; } wsrep_seqno_t first() { return first_; } wsrep_seqno_t last() { return last_; } AsyncSenderMap& asmap() { return asmap_; } pthread_t thread() { return thread_; } private: friend class AsyncSenderMap; const gu::Config& conf_; const std::string peer_; wsrep_seqno_t first_; wsrep_seqno_t last_; AsyncSenderMap& asmap_; pthread_t thread_; }; } } std::string const galera::ist::Receiver::RECV_ADDR("ist.recv_addr"); void galera::ist::register_params(gu::Config& conf) { conf.add(Receiver::RECV_ADDR); conf.add(CONF_KEEP_KEYS); #ifdef HAVE_ASIO_SSL_HPP conf.add(CONF_SSL_KEY); conf.add(CONF_SSL_CERT); conf.add(CONF_SSL_CA); conf.add(CONF_SSL_PSWD_FILE); #endif } galera::ist::Receiver::Receiver(gu::Config& conf, TrxHandle::SlavePool& sp, const char* addr) : io_service_ (), acceptor_ (io_service_), #ifdef HAVE_ASIO_SSL_HPP ssl_ctx_ (io_service_, asio::ssl::context::sslv23), #endif mutex_ (), cond_ (), consumers_ (), current_seqno_(-1), last_seqno_ (-1), conf_ (conf), trx_pool_ (sp), thread_ (), error_code_ (0), version_ (-1), #ifdef HAVE_ASIO_SSL_HPP use_ssl_ (false), #endif running_ (false), ready_ (false) { std::string recv_addr; try /* check if receive address is explicitly set */ { recv_addr = conf_.get(RECV_ADDR); return; } catch (gu::NotSet& e) {} /* if not, check the alternative. TODO: try to find from system. */ if (addr) { try { recv_addr = gu::URI(std::string("tcp://") + addr).get_host(); conf_.set(RECV_ADDR, recv_addr); } catch (gu::NotSet& e) {} } } galera::ist::Receiver::~Receiver() { } extern "C" void* run_receiver_thread(void* arg) { galera::ist::Receiver* receiver(static_cast(arg)); receiver->run(); return 0; } static std::string IST_determine_recv_addr (gu::Config& conf) { std::string recv_addr; try { recv_addr = conf.get(galera::ist::Receiver::RECV_ADDR); } catch (gu::NotFound&) { try { recv_addr = conf.get(galera::BASE_HOST_KEY); } catch (gu::NotSet&) { gu_throw_error(EINVAL) << "Could not determine IST receinve address: '" << galera::ist::Receiver::RECV_ADDR << "' not set."; } } /* check if explicit scheme is present */ if (recv_addr.find("://") == std::string::npos) { #ifdef HAVE_ASIO_SSL_HPP bool ssl(false); try { std::string ssl_key = conf.get(CONF_SSL_KEY); if (ssl_key.length() != 0) ssl = true; } catch (gu::NotSet&) {} if (ssl) recv_addr.insert(0, "ssl://"); else #endif recv_addr.insert(0, "tcp://"); } gu::URI ra_uri(recv_addr); if (!conf.has(galera::BASE_HOST_KEY)) conf.set(galera::BASE_HOST_KEY, ra_uri.get_host()); try /* check for explicit port, TODO: make it possible to use any free port (explicit 0?) */ { ra_uri.get_port(); } catch (gu::NotSet&) /* use gmcast listen port + 1 */ { int port(0); try { port = gu::from_string( // gu::URI(conf.get("gmcast.listen_addr")).get_port() conf.get(galera::BASE_PORT_KEY) ); } catch (...) { port = gu::from_string(galera::BASE_PORT_DEFAULT); } port += 1; recv_addr += ":" + gu::to_string(port); } return recv_addr; } std::string galera::ist::Receiver::prepare(wsrep_seqno_t first_seqno, wsrep_seqno_t last_seqno, int version) { ready_ = false; version_ = version; recv_addr_ = IST_determine_recv_addr(conf_); gu::URI const uri(recv_addr_); try { #ifdef HAVE_ASIO_SSL_HPP if (uri.get_scheme() == "ssl") { log_info << "IST receiver using ssl"; use_ssl_ = true; prepare_ssl_ctx(conf_, ssl_ctx_); } #endif asio::ip::tcp::resolver resolver(io_service_); asio::ip::tcp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port(), asio::ip::tcp::resolver::query::flags(0)); asio::ip::tcp::resolver::iterator i(resolver.resolve(query)); acceptor_.open(i->endpoint().protocol()); acceptor_.set_option(asio::ip::tcp::socket::reuse_address(true)); set_fd_options(acceptor_); acceptor_.bind(*i); acceptor_.listen(); // read recv_addr_ from acceptor_ in case zero port was specified recv_addr_ = uri.get_scheme() + "://" + uri.get_host() + ":" + gu::to_string(acceptor_.local_endpoint().port()); } catch (asio::system_error& e) { recv_addr_ = ""; gu_throw_error(e.code().value()) << "Failed to open IST listener at " << uri.to_string() << "', asio error '" << e.what() << "'"; } current_seqno_ = first_seqno; last_seqno_ = last_seqno; int err; if ((err = pthread_create(&thread_, 0, &run_receiver_thread, this)) != 0) { recv_addr_ = ""; gu_throw_error(err) << "Unable to create receiver thread"; } running_ = true; log_info << "Prepared IST receiver, listening at: " << (uri.get_scheme() + "://" + escape_addr(acceptor_.local_endpoint().address()) + ":" + gu::to_string(acceptor_.local_endpoint().port())); return recv_addr_; } void galera::ist::Receiver::run() { asio::ip::tcp::socket socket(io_service_); #ifdef HAVE_ASIO_SSL_HPP asio::ssl::context ssl_ctx(io_service_, asio::ssl::context::sslv23); asio::ssl::stream ssl_stream(io_service_, ssl_ctx_); #endif try { #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { acceptor_.accept(ssl_stream.lowest_layer()); set_fd_options(ssl_stream.lowest_layer()); ssl_stream.handshake(asio::ssl::stream::server); } else #endif { acceptor_.accept(socket); set_fd_options(socket); } } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "accept() failed" << "', asio error '" << e.what() << "'"; } acceptor_.close(); int ec(0); try { Proto p(trx_pool_, version_, conf_.get(CONF_KEEP_KEYS, CONF_KEEP_KEYS_DEFAULT)); #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { p.send_handshake(ssl_stream); p.recv_handshake_response(ssl_stream); p.send_ctrl(ssl_stream, Ctrl::C_OK); } else #endif { p.send_handshake(socket); p.recv_handshake_response(socket); p.send_ctrl(socket, Ctrl::C_OK); } while (true) { TrxHandle* trx; #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { trx = p.recv_trx(ssl_stream); } else #endif { trx = p.recv_trx(socket); } if (trx != 0) { if (trx->global_seqno() != current_seqno_) { log_error << "unexpected trx seqno: " << trx->global_seqno() << " expected: " << current_seqno_; ec = EINVAL; goto err; } ++current_seqno_; } gu::Lock lock(mutex_); while (ready_ == false || consumers_.empty()) { lock.wait(cond_); } Consumer* cons(consumers_.top()); consumers_.pop(); cons->trx(trx); cons->cond().signal(); if (trx == 0) { log_debug << "eof received, closing socket"; break; } } } catch (asio::system_error& e) { log_error << "got error while reading ist stream: " << e.code(); ec = e.code().value(); } catch (gu::Exception& e) { ec = e.get_errno(); if (ec != EINTR) { log_error << "got exception while reading ist stream: " << e.what(); } } err: gu::Lock lock(mutex_); #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { ssl_stream.lowest_layer().close(); // ssl_stream.shutdown(); } else #endif { socket.close(); } running_ = false; if (ec != EINTR && current_seqno_ - 1 < last_seqno_) { log_error << "IST didn't contain all write sets, expected last: " << last_seqno_ << " last received: " << current_seqno_ - 1; ec = EPROTO; } if (ec != EINTR) { error_code_ = ec; } while (consumers_.empty() == false) { consumers_.top()->cond().signal(); consumers_.pop(); } } void galera::ist::Receiver::ready() { gu::Lock lock(mutex_); ready_ = true; cond_.signal(); } int galera::ist::Receiver::recv(TrxHandle** trx) { Consumer cons; gu::Lock lock(mutex_); if (running_ == false) { if (error_code_ != 0) { gu_throw_error(error_code_) << "IST receiver reported error"; } return EINTR; } consumers_.push(&cons); cond_.signal(); lock.wait(cons.cond()); if (cons.trx() == 0) { if (error_code_ != 0) { gu_throw_error(error_code_) << "IST receiver reported error"; } return EINTR; } *trx = cons.trx(); return 0; } wsrep_seqno_t galera::ist::Receiver::finished() { if (recv_addr_ == "") { log_debug << "IST was not prepared before calling finished()"; } else { interrupt(); int err; if ((err = pthread_join(thread_, 0)) != 0) { log_warn << "Failed to join IST receiver thread: " << err; } acceptor_.close(); gu::Lock lock(mutex_); running_ = false; while (consumers_.empty() == false) { consumers_.top()->cond().signal(); consumers_.pop(); } recv_addr_ = ""; } return (current_seqno_ - 1); } void galera::ist::Receiver::interrupt() { gu::URI uri(recv_addr_); try { asio::ip::tcp::resolver::iterator i; try { asio::ip::tcp::resolver resolver(io_service_); asio::ip::tcp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port(), asio::ip::tcp::resolver::query::flags(0)); i = resolver.resolve(query); } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "failed to resolve host '" << uri.to_string() << "', asio error '" << e.what() << "'"; } #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { asio::ssl::stream ssl_stream(io_service_, ssl_ctx_); ssl_stream.lowest_layer().connect(*i); set_fd_options(ssl_stream.lowest_layer()); ssl_stream.handshake(asio::ssl::stream::client); Proto p(trx_pool_, version_, conf_.get(CONF_KEEP_KEYS, CONF_KEEP_KEYS_DEFAULT)); p.recv_handshake(ssl_stream); p.send_ctrl(ssl_stream, Ctrl::C_EOF); p.recv_ctrl(ssl_stream); } else #endif { asio::ip::tcp::socket socket(io_service_); socket.connect(*i); set_fd_options(socket); Proto p(trx_pool_, version_, conf_.get(CONF_KEEP_KEYS, CONF_KEEP_KEYS_DEFAULT)); p.recv_handshake(socket); p.send_ctrl(socket, Ctrl::C_EOF); p.recv_ctrl(socket); } } catch (asio::system_error& e) { // ignore } } galera::ist::Sender::Sender(const gu::Config& conf, gcache::GCache& gcache, const std::string& peer, int version) : io_service_(), socket_ (io_service_), #ifdef HAVE_ASIO_SSL_HPP ssl_ctx_ (io_service_, asio::ssl::context::sslv23), ssl_stream_(io_service_, ssl_ctx_), #endif conf_ (conf), gcache_ (gcache), #ifdef HAVE_ASIO_SSL_HPP version_ (version), use_ssl_ (false) #else version_ (version) #endif { gu::URI uri(peer); try { asio::ip::tcp::resolver resolver(io_service_); asio::ip::tcp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port(), asio::ip::tcp::resolver::query::flags(0)); asio::ip::tcp::resolver::iterator i(resolver.resolve(query)); #ifdef HAVE_ASIO_SSL_HPP if (uri.get_scheme() == "ssl") { use_ssl_ = true; } if (use_ssl_ == true) { log_info << "IST sender using ssl"; prepare_ssl_ctx(conf, ssl_ctx_); ssl_stream_.lowest_layer().connect(*i); set_fd_options(ssl_stream_.lowest_layer()); ssl_stream_.handshake(asio::ssl::stream::client); } else #endif { socket_.connect(*i); set_fd_options(socket_); } } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "IST sender, failed to connect '" << peer.c_str() << "': " << e.what(); } } galera::ist::Sender::~Sender() { #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { ssl_stream_.lowest_layer().close(); } else #endif { socket_.close(); } gcache_.seqno_unlock(); } void galera::ist::Sender::send(wsrep_seqno_t first, wsrep_seqno_t last) { if (first > last) { gu_throw_error(EINVAL) << "sender send first greater than last: " << first << " > " << last ; } try { TrxHandle::SlavePool unused(1, 0, ""); Proto p(unused, version_, conf_.get(CONF_KEEP_KEYS, CONF_KEEP_KEYS_DEFAULT)); int32_t ctrl; #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { p.recv_handshake(ssl_stream_); p.send_handshake_response(ssl_stream_); ctrl = p.recv_ctrl(ssl_stream_); } else #endif { p.recv_handshake(socket_); p.send_handshake_response(socket_); ctrl = p.recv_ctrl(socket_); } if (ctrl < 0) { gu_throw_error(EPROTO) << "ist send failed, peer reported error: " << ctrl; } std::vector buf_vec( std::min(static_cast(last - first + 1), static_cast(1024))); ssize_t n_read; while ((n_read = gcache_.seqno_get_buffers(buf_vec, first)) > 0) { //log_info << "read " << first << " + " << n_read << " from gcache"; for (wsrep_seqno_t i(0); i < n_read; ++i) { // log_info << "sending " << buf_vec[i].seqno_g(); #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { p.send_trx(ssl_stream_, buf_vec[i]); } else #endif { p.send_trx(socket_, buf_vec[i]); } if (buf_vec[i].seqno_g() == last) { #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { p.send_ctrl(ssl_stream_, Ctrl::C_EOF); } else #endif { p.send_ctrl(socket_, Ctrl::C_EOF); } // wait until receiver closes the connection try { gu::byte_t b; size_t n; #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { n = asio::read(ssl_stream_, asio::buffer(&b, 1)); } else #endif { n = asio::read(socket_, asio::buffer(&b, 1)); } if (n > 0) { log_warn << "received " << n << " bytes, expected none"; } } catch (asio::system_error& e) { } return; } } first += n_read; // resize buf_vec to avoid scanning gcache past last size_t next_size(std::min(static_cast(last - first + 1), static_cast(1024))); if (buf_vec.size() != next_size) { buf_vec.resize(next_size); } } } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "ist send failed: " << e.code() << "', asio error '" << e.what() << "'"; } } extern "C" void* run_async_sender(void* arg) { galera::ist::AsyncSender* as(reinterpret_cast(arg)); log_info << "async IST sender starting to serve " << as->peer().c_str() << " sending " << as->first() << "-" << as->last(); wsrep_seqno_t join_seqno; try { as->send(as->first(), as->last()); join_seqno = as->last(); } catch (gu::Exception& e) { log_error << "async IST sender failed to serve " << as->peer().c_str() << ": " << e.what(); join_seqno = -e.get_errno(); } catch (...) { log_error << "async IST sender, failed to serve " << as->peer().c_str(); throw; } try { as->asmap().remove(as, join_seqno); pthread_detach(as->thread()); delete as; } catch (gu::NotFound& nf) { log_debug << "async IST sender already removed"; } log_info << "async IST sender served"; return 0; } void galera::ist::AsyncSenderMap::run(const gu::Config& conf, const std::string& peer, wsrep_seqno_t first, wsrep_seqno_t last, int version) { gu::Critical crit(monitor_); AsyncSender* as(new AsyncSender(conf, peer, first, last, *this, version)); int err(pthread_create(&as->thread_, 0, &run_async_sender, as)); if (err != 0) { delete as; gu_throw_error(err) << "failed to start sender thread"; } senders_.insert(as); } void galera::ist::AsyncSenderMap::remove(AsyncSender* as, wsrep_seqno_t seqno) { gu::Critical crit(monitor_); std::set::iterator i(senders_.find(as)); if (i == senders_.end()) { throw gu::NotFound(); } senders_.erase(i); } void galera::ist::AsyncSenderMap::cancel() { gu::Critical crit(monitor_); while (senders_.empty() == false) { AsyncSender* as(*senders_.begin()); senders_.erase(*senders_.begin()); int err; as->cancel(); monitor_.leave(); if ((err = pthread_join(as->thread_, 0)) != 0) { log_warn << "pthread_join() failed: " << err; } monitor_.enter(); delete as; } } percona-galera-3-3.8-3390/galera/src/ist.hpp000066400000000000000000000112431244131713600203350ustar00rootroot00000000000000// // Copyright (C) 2011-2014 Codership Oy // #ifndef GALERA_IST_HPP #define GALERA_IST_HPP #include #include "wsrep_api.h" #include "galera_gcs.hpp" #include "trx_handle.hpp" #include "gu_config.hpp" #include "gu_lock.hpp" #include "gu_monitor.hpp" #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wold-style-cast" #include "asio.hpp" #ifdef HAVE_ASIO_SSL_HPP #include "asio/ssl.hpp" #endif #include #include namespace gcache { class GCache; } namespace galera { class TrxHandle; namespace ist { void register_params(gu::Config& conf); class Receiver { public: static std::string const RECV_ADDR; Receiver(gu::Config& conf, TrxHandle::SlavePool&, const char* addr); ~Receiver(); std::string prepare(wsrep_seqno_t, wsrep_seqno_t, int); void ready(); int recv(TrxHandle** trx); wsrep_seqno_t finished(); void run(); private: void interrupt(); std::string recv_addr_; asio::io_service io_service_; asio::ip::tcp::acceptor acceptor_; #ifdef HAVE_ASIO_SSL_HPP asio::ssl::context ssl_ctx_; #endif gu::Mutex mutex_; gu::Cond cond_; class Consumer { public: Consumer() : cond_(), trx_(0) { } ~Consumer() { } gu::Cond& cond() { return cond_; } void trx(TrxHandle* trx) { trx_ = trx; } TrxHandle* trx() const { return trx_; } private: gu::Cond cond_; TrxHandle* trx_; }; std::stack consumers_; wsrep_seqno_t current_seqno_; wsrep_seqno_t last_seqno_; gu::Config& conf_; TrxHandle::SlavePool& trx_pool_; pthread_t thread_; int error_code_; int version_; #ifdef HAVE_ASIO_SSL_HPP bool use_ssl_; #endif bool running_; bool ready_; }; class Sender { public: Sender(const gu::Config& conf, gcache::GCache& gcache, const std::string& peer, int version); ~Sender(); void send(wsrep_seqno_t first, wsrep_seqno_t last); void cancel() { #ifdef HAVE_ASIO_SSL_HPP if (use_ssl_ == true) { ssl_stream_.lowest_layer().close(); } else #endif { socket_.close(); } } private: asio::io_service io_service_; asio::ip::tcp::socket socket_; #ifdef HAVE_ASIO_SSL_HPP asio::ssl::context ssl_ctx_; asio::ssl::stream ssl_stream_; #endif const gu::Config& conf_; gcache::GCache& gcache_; int version_; bool use_ssl_; Sender(const Sender&); void operator=(const Sender&); }; class AsyncSender; class AsyncSenderMap { public: AsyncSenderMap(GCS_IMPL& gcs, gcache::GCache& gcache) : senders_(), monitor_(), gcs_(gcs), gcache_(gcache) { } void run(const gu::Config& conf, const std::string& peer, wsrep_seqno_t, wsrep_seqno_t, int); void remove(AsyncSender*, wsrep_seqno_t); void cancel(); gcache::GCache& gcache() { return gcache_; } private: std::set senders_; // use monitor instead of mutex, it provides cancellation point gu::Monitor monitor_; GCS_IMPL& gcs_; gcache::GCache& gcache_; }; } // namespace ist } // namespace galera #endif // GALERA_IST_HPP percona-galera-3-3.8-3390/galera/src/ist_proto.hpp000066400000000000000000000472551244131713600215740ustar00rootroot00000000000000// // Copyright (C) 2011-2014 Codership Oy // #ifndef GALERA_IST_PROTO_HPP #define GALERA_IST_PROTO_HPP #include "trx_handle.hpp" #include "GCache.hpp" #include "gu_logger.hpp" #include "gu_serialize.hpp" #include "gu_vector.hpp" // // Sender Receiver // connect() -----> accept() // <----- send_handshake() // send_handshake_response() -----> // <----- send_ctrl(OK) // send_trx() -----> // -----> // send_ctrl(EOF) -----> // <----- close() // close() // // Note about protocol/message versioning: // Version is determined by GCS and IST protocol is initialized in total // order. Therefore it is not necessary to negotiate version at IST level, // it should be enough to check that message version numbers match. // namespace galera { namespace ist { class Message { public: typedef enum { T_NONE = 0, T_HANDSHAKE = 1, T_HANDSHAKE_RESPONSE = 2, T_CTRL = 3, T_TRX = 4 } Type; Message(int version = -1, Type type = T_NONE, uint8_t flags = 0, int8_t ctrl = 0, uint64_t len = 0) : version_(version), type_ (type ), flags_ (flags ), ctrl_ (ctrl ), len_ (len ) { } int version() const { return version_; } Type type() const { return type_ ; } uint8_t flags() const { return flags_ ; } int8_t ctrl() const { return ctrl_ ; } uint64_t len() const { return len_ ; } size_t serial_size() const { if (version_ > 3) { // header: version 1 byte, type 1 byte, flags 1 byte, // ctrl field 1 byte return 4 + sizeof(len_); } else { return sizeof(*this); } } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset)const { #ifndef NDEBUG size_t orig_offset(offset); #endif // NDEBUG if (version_ > 3) { offset = gu::serialize1(uint8_t(version_), buf, buflen, offset); offset = gu::serialize1(uint8_t(type_), buf, buflen, offset); offset = gu::serialize1(flags_, buf, buflen, offset); offset = gu::serialize1(ctrl_, buf, buflen, offset); offset = gu::serialize8(len_, buf, buflen, offset); } else { if (buflen < offset + sizeof(*this)) { gu_throw_error(EMSGSIZE) << "buffer too short"; } *reinterpret_cast(buf + offset) = *this; offset += sizeof(*this); } assert((version_ > 3 && offset - orig_offset == 12) || (offset - orig_offset == sizeof(*this))); return offset; } size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) { assert(version_ >= 0); #ifndef NDEBUG size_t orig_offset(offset); #endif // NDEBUG uint8_t u8; if (version_ > 3) { offset = gu::unserialize1(buf, buflen, offset, u8); } else { u8 = *reinterpret_cast(buf + offset); } if (u8 != version_) { gu_throw_error(EPROTO) << "invalid protocol version " << int(u8) << ", expected " << version_; } if (u8 > 3) { version_ = u8; offset = gu::unserialize1(buf, buflen, offset, u8); type_ = static_cast(u8); offset = gu::unserialize1(buf, buflen, offset, flags_); offset = gu::unserialize1(buf, buflen, offset, ctrl_); offset = gu::unserialize8(buf, buflen, offset, len_); } else { if (buflen < offset + sizeof(*this)) { gu_throw_error(EMSGSIZE) <<" buffer too short for version " << version_ << ": " << buflen << " " << offset << " " << sizeof(*this); } *this = *reinterpret_cast(buf + offset); offset += sizeof(*this); } assert((version_ > 3 && offset - orig_offset == 12) || (offset - orig_offset == sizeof(*this))); return offset; } private: int version_; // unfortunately for compatibility with older // versions we must leave it as int (4 bytes) Type type_; uint8_t flags_; int8_t ctrl_; uint64_t len_; }; class Handshake : public Message { public: Handshake(int version = -1) : Message(version, Message::T_HANDSHAKE, 0, 0, 0) { } }; class HandshakeResponse : public Message { public: HandshakeResponse(int version = -1) : Message(version, Message::T_HANDSHAKE_RESPONSE, 0, 0, 0) { } }; class Ctrl : public Message { public: enum { // negative values reserved for error codes C_OK = 0, C_EOF = 1 }; Ctrl(int version = -1, int8_t code = 0) : Message(version, Message::T_CTRL, 0, code, 0) { } }; class Trx : public Message { public: Trx(int version = -1, uint64_t len = 0) : Message(version, Message::T_TRX, 0, 0, len) { } }; class Proto { public: Proto(TrxHandle::SlavePool& sp, int version, bool keep_keys) : trx_pool_ (sp), raw_sent_ (0), real_sent_(0), version_ (version), keep_keys_(keep_keys) { } ~Proto() { if (raw_sent_ > 0) { log_info << "ist proto finished, raw sent: " << raw_sent_ << " real sent: " << real_sent_ << " frac: " << (raw_sent_ == 0 ? 0. : static_cast(real_sent_)/raw_sent_); } } template void send_handshake(ST& socket) { Handshake hs(version_); gu::Buffer buf(hs.serial_size()); size_t offset(hs.serialize(&buf[0], buf.size(), 0)); size_t n(asio::write(socket, asio::buffer(&buf[0], buf.size()))); if (n != offset) { gu_throw_error(EPROTO) << "error sending handshake"; } } template void recv_handshake(ST& socket) { Message msg(version_); gu::Buffer buf(msg.serial_size()); size_t n(asio::read(socket, asio::buffer(&buf[0], buf.size()))); if (n != buf.size()) { gu_throw_error(EPROTO) << "error receiving handshake"; } (void)msg.unserialize(&buf[0], buf.size(), 0); log_debug << "handshake msg: " << msg.version() << " " << msg.type() << " " << msg.len(); switch (msg.type()) { case Message::T_HANDSHAKE: break; case Message::T_CTRL: switch (msg.ctrl()) { case Ctrl::C_EOF: gu_throw_error(EINTR); default: gu_throw_error(EPROTO) << "unexpected ctrl code: " << msg.ctrl(); } break; default: gu_throw_error(EPROTO) << "unexpected message type: " << msg.type(); } if (msg.version() != version_) { gu_throw_error(EPROTO) << "mismatching protocol version: " << msg.version() << " required: " << version_; } // TODO: Figure out protocol versions to use } template void send_handshake_response(ST& socket) { HandshakeResponse hsr(version_); gu::Buffer buf(hsr.serial_size()); size_t offset(hsr.serialize(&buf[0], buf.size(), 0)); size_t n(asio::write(socket, asio::buffer(&buf[0], buf.size()))); if (n != offset) { gu_throw_error(EPROTO) << "error sending handshake response"; } } template void recv_handshake_response(ST& socket) { Message msg(version_); gu::Buffer buf(msg.serial_size()); size_t n(asio::read(socket, asio::buffer(&buf[0], buf.size()))); if (n != buf.size()) { gu_throw_error(EPROTO) << "error receiving handshake"; } (void)msg.unserialize(&buf[0], buf.size(), 0); log_debug << "handshake response msg: " << msg.version() << " " << msg.type() << " " << msg.len(); switch (msg.type()) { case Message::T_HANDSHAKE_RESPONSE: break; case Message::T_CTRL: switch (msg.ctrl()) { case Ctrl::C_EOF: gu_throw_error(EINTR) << "interrupted by ctrl"; default: gu_throw_error(EPROTO) << "unexpected ctrl code: " << msg.ctrl(); } default: gu_throw_error(EINVAL) << "unexpected message type: " << msg.type(); } } template void send_ctrl(ST& socket, int8_t code) { Ctrl ctrl(version_, code); gu::Buffer buf(ctrl.serial_size()); size_t offset(ctrl.serialize(&buf[0], buf.size(), 0)); size_t n(asio::write(socket, asio::buffer(&buf[0],buf.size()))); if (n != offset) { gu_throw_error(EPROTO) << "error sending ctrl message"; } } template int8_t recv_ctrl(ST& socket) { Message msg(version_); gu::Buffer buf(msg.serial_size()); size_t n(asio::read(socket, asio::buffer(&buf[0], buf.size()))); if (n != buf.size()) { gu_throw_error(EPROTO) << "error receiving handshake"; } (void)msg.unserialize(&buf[0], buf.size(), 0); log_debug << "msg: " << msg.version() << " " << msg.type() << " " << msg.len(); switch (msg.type()) { case Message::T_CTRL: break; default: gu_throw_error(EPROTO) << "unexpected message type: " << msg.type(); } return msg.ctrl(); } template void send_trx(ST& socket, const gcache::GCache::Buffer& buffer) { const bool rolled_back(buffer.seqno_d() == -1); galera::WriteSetIn ws; boost::array cbs; size_t payload_size; /* size of the 2nd cbs buffer */ size_t sent; if (gu_unlikely(rolled_back)) { payload_size = 0; } else { if (keep_keys_ || version_ < WS_NG_VERSION) { payload_size = buffer.size(); const void* const ptr(buffer.ptr()); cbs[1] = asio::const_buffer(ptr, payload_size); cbs[2] = asio::const_buffer(ptr, 0); } else { gu::Buf tmp = { buffer.ptr(), buffer.size() }; ws.read_buf (tmp, 0); WriteSetIn::GatherVector out; payload_size = ws.gather (out, false, false); assert (2 == out->size()); cbs[1] = asio::const_buffer(out[0].ptr, out[0].size); cbs[2] = asio::const_buffer(out[1].ptr, out[1].size); } } size_t const trx_meta_size( 8 /* serial_size(buffer.seqno_g()) */ + 8 /* serial_size(buffer.seqno_d()) */ ); Trx trx_msg(version_, trx_meta_size + payload_size); gu::Buffer buf(trx_msg.serial_size() + trx_meta_size); size_t offset(trx_msg.serialize(&buf[0], buf.size(), 0)); offset = gu::serialize8(buffer.seqno_g(), &buf[0], buf.size(), offset); offset = gu::serialize8(buffer.seqno_d(), &buf[0], buf.size(), offset); cbs[0] = asio::const_buffer(&buf[0], buf.size()); if (gu_likely(payload_size)) { sent = asio::write(socket, cbs); } else { sent = asio::write(socket, asio::buffer(cbs[0])); } log_debug << "sent " << sent << " bytes"; } template galera::TrxHandle* recv_trx(ST& socket) { Message msg(version_); gu::Buffer buf(msg.serial_size()); size_t n(asio::read(socket, asio::buffer(&buf[0], buf.size()))); if (n != buf.size()) { gu_throw_error(EPROTO) << "error receiving trx header"; } (void)msg.unserialize(&buf[0], buf.size(), 0); log_debug << "received header: " << n << " bytes, type " << msg.type() << " len " << msg.len(); switch (msg.type()) { case Message::T_TRX: { // TODO: ideally we want to make seqno_g and cert verdict // be a part of msg object above, so that we can skip this // read. The overhead is tiny given that vast majority of // messages will be trx writesets. wsrep_seqno_t seqno_g, seqno_d; buf.resize(sizeof(seqno_g) + sizeof(seqno_d)); n = asio::read(socket, asio::buffer(&buf[0], buf.size())); if (n != buf.size()) { gu_throw_error(EPROTO) << "error reading trx meta data"; } size_t offset(gu::unserialize8(&buf[0], buf.size(), 0, seqno_g)); offset = gu::unserialize8(&buf[0], buf.size(), offset, seqno_d); galera::TrxHandle* trx(galera::TrxHandle::New(trx_pool_)); if (seqno_d == WSREP_SEQNO_UNDEFINED) { if (offset != msg.len()) { gu_throw_error(EINVAL) << "message size " << msg.len() << " does not match expected size " << offset; } } else { MappedBuffer& wbuf(trx->write_set_collection()); size_t const wsize(msg.len() - offset); wbuf.resize(wsize); n = asio::read(socket, asio::buffer(&wbuf[0], wbuf.size())); if (gu_unlikely(n != wbuf.size())) { gu_throw_error(EPROTO) << "error reading write set data"; } trx->unserialize(&wbuf[0], wbuf.size(), 0); } trx->set_received(0, -1, seqno_g); trx->set_depends_seqno(seqno_d); trx->mark_certified(); log_debug << "received trx body: " << *trx; return trx; } case Message::T_CTRL: switch (msg.ctrl()) { case Ctrl::C_EOF: return 0; default: if (msg.ctrl() >= 0) { gu_throw_error(EPROTO) << "unexpected ctrl code: " << msg.ctrl(); } else { gu_throw_error(-msg.ctrl()) <<"peer reported error"; } } default: gu_throw_error(EPROTO) << "unexpected message type: " << msg.type(); } gu_throw_fatal; throw; return 0; // keep compiler happy } private: TrxHandle::SlavePool& trx_pool_; uint64_t raw_sent_; uint64_t real_sent_; int version_; bool keep_keys_; }; } } #endif // GALERA_IST_PROTO_HPP percona-galera-3-3.8-3390/galera/src/key_data.hpp000066400000000000000000000017601244131713600213220ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #ifndef GALERA_KEY_DATA_HPP #define GALERA_KEY_DATA_HPP #include "wsrep_api.h" namespace galera { struct KeyData { const wsrep_buf_t* const parts; long const parts_num; int const proto_ver; wsrep_key_type_t const type; bool const copy; KeyData (int const pv, const wsrep_buf_t* const k, long const kn, wsrep_key_type_t const tp, bool const cp) : parts (k), parts_num (kn), proto_ver (pv), type (tp), copy (cp) {} KeyData (const KeyData& kd) : parts (kd.parts), parts_num(kd.parts_num), proto_ver(kd.proto_ver), type (kd.type), copy (kd.copy) {} bool shared() const { return type == WSREP_KEY_SHARED; } private: KeyData& operator = (const KeyData&); }; /* struct KeyData */ } /* namespace galera */ #endif /* GALERA_KEY_DATA_HPP */ percona-galera-3-3.8-3390/galera/src/key_entry_ng.hpp000066400000000000000000000065531244131713600222430ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #ifndef GALERA_KEY_ENTRY_NG_HPP #define GALERA_KEY_ENTRY_NG_HPP #include "trx_handle.hpp" namespace galera { class TrxHandle; class KeyEntryNG { public: KeyEntryNG(const KeySet::KeyPart& key) : refs_(), key_(key) { std::fill(&refs_[0], &refs_[KeySet::Key::P_LAST], reinterpret_cast(NULL)); } KeyEntryNG(const KeyEntryNG& other) : refs_(), key_(other.key_) { std::copy(&other.refs_[0], &other.refs_[KeySet::Key::P_LAST], &refs_[0]); } const KeySet::KeyPart& key() const { return key_; } void ref(KeySet::Key::Prefix p, const KeySet::KeyPart& k, TrxHandle* trx) { assert(0 == refs_[p] || refs_[p]->global_seqno() <= trx->global_seqno()); refs_[p] = trx; key_ = k; } void unref(KeySet::Key::Prefix p, TrxHandle* trx) { assert(refs_[p] != NULL); if (refs_[p] == trx) { refs_[p] = NULL; } else { assert(refs_[p]->global_seqno() > trx->global_seqno()); assert(0); } } bool referenced() const { bool ret(refs_[0] != NULL); for (int i(1); false == ret && i <= KeySet::Key::P_LAST; ++i) { ret = (refs_[i] != NULL); } return ret; } const TrxHandle* ref_trx(KeySet::Key::Prefix p) const { return refs_[p]; } size_t size() const { return sizeof(*this); } void swap(KeyEntryNG& other) throw() { using std::swap; gu::swap_array(refs_, other.refs_); swap(key_, other.key_); } KeyEntryNG& operator=(KeyEntryNG ke) { swap(ke); return *this; } ~KeyEntryNG() { assert(!referenced()); } private: TrxHandle* refs_[KeySet::Key::P_LAST + 1]; KeySet::KeyPart key_; #ifndef NDEBUG void assert_ref(KeySet::Key::Prefix, TrxHandle*) const; void assert_unref(KeySet::Key::Prefix, TrxHandle*) const; #endif /* NDEBUG */ }; inline void swap(KeyEntryNG& a, KeyEntryNG& b) { a.swap(b); } class KeyEntryHashNG { public: size_t operator()(const KeyEntryNG& ke) const { return ke.key().hash(); } }; class KeyEntryPtrHashNG { public: size_t operator()(const KeyEntryNG* const ke) const { return ke->key().hash(); } }; class KeyEntryEqualNG { public: bool operator()(const KeyEntryNG& left, const KeyEntryNG& right) const { return left.key().matches(right.key()); } }; class KeyEntryPtrEqualNG { public: bool operator()(const KeyEntryNG* const left, const KeyEntryNG* const right) const { return left->key().matches(right->key()); } }; } #endif // GALERA_KEY_ENTRY_HPP percona-galera-3-3.8-3390/galera/src/key_entry_os.cpp000066400000000000000000000031341244131713600222430ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // #include "key_entry_os.hpp" #include "trx_handle.hpp" namespace galera { #ifndef NDEBUG void KeyEntryOS::assert_ref(TrxHandle* trx, bool full_key) const { assert(ref_trx_ == 0 || ref_trx_->global_seqno() <= trx->global_seqno()); if (full_key) { assert(ref_full_trx_ == 0 || (ref_full_trx_->global_seqno() <= trx->global_seqno() && ref_trx_ != 0)); } } void KeyEntryOS::assert_unref(TrxHandle* trx) const { if (ref_full_trx_ != 0 && ref_trx_ == 0) { log_fatal << "dereferencing EXCLUSIVE partial key: " << key_ << " by " << trx->global_seqno() << ", while full key referenced by " << ref_full_trx_->global_seqno(); assert(0); } } void KeyEntryOS::assert_ref_shared(TrxHandle* trx, bool full_key) const { assert(ref_shared_trx_ == 0 || ref_shared_trx_->global_seqno() <= trx->global_seqno()); if (full_key) { assert(ref_full_shared_trx_ == 0 || (ref_full_shared_trx_->global_seqno() <= trx->global_seqno() && ref_shared_trx_ != 0)); } } void KeyEntryOS::assert_unref_shared(TrxHandle* trx) const { if (ref_full_shared_trx_ != 0 && ref_shared_trx_ == 0) { log_fatal << "dereferencing SHARED partial key: " << key_ << " by " << trx->global_seqno() << ", while full key referenced by " << ref_full_shared_trx_->global_seqno(); assert(0); } } #endif /* NDEBUG */ } percona-galera-3-3.8-3390/galera/src/key_entry_os.hpp000066400000000000000000000106101244131713600222450ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // #ifndef GALERA_KEY_ENTRY_OS_HPP #define GALERA_KEY_ENTRY_OS_HPP #include "key_os.hpp" namespace galera { class TrxHandle; class KeyEntryOS { public: KeyEntryOS(const KeyOS& row_key) : key_(row_key), ref_trx_(0), ref_full_trx_(0), ref_shared_trx_(0), ref_full_shared_trx_(0) {} template KeyEntryOS(int version, Ci begin, Ci end, uint8_t flags) : key_(version, begin, end, flags), ref_trx_(0), ref_full_trx_(0), ref_shared_trx_(0), ref_full_shared_trx_(0) {} KeyEntryOS(const KeyEntryOS& other) : key_(other.key_), ref_trx_(other.ref_trx_), ref_full_trx_(other.ref_full_trx_), ref_shared_trx_(other.ref_shared_trx_), ref_full_shared_trx_(other.ref_full_shared_trx_) {} ~KeyEntryOS() { assert(ref_trx_ == 0); assert(ref_full_trx_ == 0); assert(ref_shared_trx_ == 0); assert(ref_full_shared_trx_ == 0); } const KeyOS& get_key() const { return key_; } const KeyOS& get_key(int version) const { return key_; } void ref(TrxHandle* trx, bool full_key) { #ifndef NDEBUG assert_ref(trx, full_key); #endif /* NDEBUG */ ref_trx_ = trx; if (full_key == true) { ref_full_trx_ = trx; } } void unref(TrxHandle* trx, bool full_key) { assert(ref_trx_ != 0); if (ref_trx_ == trx) ref_trx_ = 0; if (full_key == true && ref_full_trx_ == trx) { ref_full_trx_ = 0; } else { #ifndef NDEBUG assert_unref(trx); #endif /* NDEBUG */ } } void ref_shared(TrxHandle* trx, bool full_key) { #ifndef NDEBUG assert_ref_shared(trx, full_key); #endif /* NDEBUG */ ref_shared_trx_ = trx; if (full_key == true) { ref_full_shared_trx_ = trx; } } void unref_shared(TrxHandle* trx, bool full_key) { assert(ref_shared_trx_ != 0); if (ref_shared_trx_ == trx) ref_shared_trx_ = 0; if (full_key == true && ref_full_shared_trx_ == trx) { ref_full_shared_trx_ = 0; } else { #ifndef NDEBUG assert_unref_shared(trx); #endif /* NDEBUG */ } } const TrxHandle* ref_trx() const { return ref_trx_; } const TrxHandle* ref_full_trx() const { return ref_full_trx_; } const TrxHandle* ref_shared_trx() const { return ref_shared_trx_; } const TrxHandle* ref_full_shared_trx() const { return ref_full_shared_trx_; } size_t size() const { return key_.size() + sizeof(*this); } private: void operator=(const KeyEntryOS&); KeyOS key_; TrxHandle* ref_trx_; TrxHandle* ref_full_trx_; TrxHandle* ref_shared_trx_; TrxHandle* ref_full_shared_trx_; #ifndef NDEBUG void assert_ref(TrxHandle*, bool) const; void assert_unref(TrxHandle*) const; void assert_ref_shared(TrxHandle*, bool) const; void assert_unref_shared(TrxHandle*) const; #endif /* NDEBUG */ }; class KeyEntryPtrHash { public: size_t operator()(const KeyEntryOS* const ke) const { return ke->get_key().hash(); } }; class KeyEntryPtrHashAll { public: size_t operator()(const KeyEntryOS* const ke) const { return ke->get_key().hash_with_flags(); } }; class KeyEntryPtrEqual { public: bool operator()(const KeyEntryOS* const left, const KeyEntryOS* const right) const { return left->get_key() == right->get_key(); } }; class KeyEntryPtrEqualAll { public: bool operator()(const KeyEntryOS* const left, const KeyEntryOS* const right) const { return left->get_key().equal_all(right->get_key()); } }; } #endif // GALERA_KEY_ENTRY_HPP percona-galera-3-3.8-3390/galera/src/key_os.hpp000066400000000000000000000220471244131713600210330ustar00rootroot00000000000000// // Copyright (C) 2011-2013 Codership Oy // #ifndef GALERA_KEY_HPP #define GALERA_KEY_HPP #include "wsrep_api.h" #include "gu_hash.h" #include "gu_serialize.hpp" #include "gu_unordered.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_vlq.hpp" #include #include #include #include #include namespace galera { // helper to cast from any kind of pointer to void template static inline void* void_cast(const C* c) { return const_cast(reinterpret_cast(c)); } class KeyPartOS { public: KeyPartOS(const gu::byte_t* buf, size_t buf_size) : buf_(buf), buf_size_(buf_size) { } const gu::byte_t* buf() const { return buf_; } size_t size() const { return buf_size_; } size_t key_len() const { #ifndef GALERA_KEY_VLQ return buf_[0]; #else size_t ret; (void)gu::uleb128_decode(buf_, buf_size_, 0, ret); return ret; #endif } #ifndef GALERA_KEY_VLQ const gu::byte_t* key() const { return buf_ + 1; } #else const gu::byte_t* key() const { size_t not_used; return buf_ + gu::uleb128_decode(buf_, buf_size_, 0, not_used); } #endif bool operator==(const KeyPartOS& other) const { return (other.buf_size_ == buf_size_ && memcmp(other.buf_, buf_, buf_size_) == 0); } private: const gu::byte_t* buf_; size_t buf_size_; }; inline std::ostream& operator<<(std::ostream& os, const KeyPartOS& kp) { const std::ostream::fmtflags prev_flags(os.flags(std::ostream::hex)); const char prev_fill(os.fill('0')); for (const gu::byte_t* i(kp.key()); i != kp.key() + kp.key_len(); ++i) { os << std::setw(2) << static_cast(*i); } os.flags(prev_flags); os.fill(prev_fill); return os; } class KeyOS { public: enum { F_SHARED = 0x1 }; KeyOS(int version) : version_(version), flags_(), keys_() { } KeyOS(int version, const wsrep_buf_t* keys, size_t keys_len, uint8_t flags) : version_(version), flags_ (flags), keys_ () { if (keys_len > 255) { gu_throw_error(EINVAL) << "maximum number of key parts exceeded: " << keys_len; } switch (version) { case 1: case 2: for (size_t i(0); i < keys_len; ++i) { size_t const offset(keys_.size()); size_t key_len(keys[i].len); const gu::byte_t* base(reinterpret_cast( keys[i].ptr)); #ifndef GALERA_KEY_VLQ if (gu_unlikely(key_len > 0xff)) key_len = 0xff; keys_.reserve(offset + 1 + key_len); keys_.insert(keys_.end(), key_len); keys_.insert(keys_.end(), base, base + key_len); #else size_t len_size(gu::uleb128_size(key_len)); keys_.resize(offset + len_size); (void)gu::uleb128_encode( key_len, &keys_[0], keys_.size(), offset); keys_.insert(keys_.end(), base, base + keys[i].key_len); #endif } break; default: gu_throw_fatal << "unsupported key version: " << version_; } } template KeyOS(int version, Ci begin, Ci end, uint8_t flags) : version_(version), flags_(flags), keys_() { for (Ci i(begin); i != end; ++i) { keys_.insert( keys_.end(), i->buf(), i->buf() + i->size()); } } int version() const { return version_; } template C key_parts() const { C ret; size_t i(0); size_t const keys_size(keys_.size()); while (i < keys_size) { #ifndef GALERA_KEY_VLQ size_t key_len(keys_[i] + 1); #else size_t key_len; size_t offset( gu::uleb128_decode(&keys_[0], keys_size, i, key_len)); key_len += offset - i; #endif if (gu_unlikely((i + key_len) > keys_size)) { gu_throw_fatal << "Keys buffer overflow by " << i + key_len - keys_size << " bytes: " << i + key_len << '/' << keys_size; } KeyPartOS kp(&keys_[i], key_len); ret.push_back(kp); i += key_len; } assert(i == keys_size); return ret; } uint8_t flags() const { return flags_; } bool operator==(const KeyOS& other) const { return (keys_ == other.keys_); } bool equal_all(const KeyOS& other) const { return (version_ == other.version_ && flags_ == other.flags_ && keys_ == other.keys_); } size_t size() const { return keys_.size() + sizeof(*this); } size_t hash() const { return gu_table_hash(&keys_[0], keys_.size()); } size_t hash_with_flags() const { return hash() ^ gu_table_hash(&flags_, sizeof(flags_)); } size_t serialize(gu::byte_t*, size_t, size_t) const; size_t unserialize(const gu::byte_t*, size_t, size_t); size_t serial_size() const; private: friend std::ostream& operator<<(std::ostream& os, const KeyOS& key); int version_; uint8_t flags_; gu::Buffer keys_; }; inline std::ostream& operator<<(std::ostream& os, const KeyOS& key) { std::ostream::fmtflags flags(os.flags()); switch (key.version_) { case 2: os << std::hex << static_cast(key.flags()) << " "; // Fall through case 1: { std::deque dq(key.key_parts >()); std::copy(dq.begin(), dq.end(), std::ostream_iterator(os, " ")); break; } default: gu_throw_fatal << "unsupported key version: " << key.version_; } os.flags(flags); return os; } inline size_t KeyOS::serialize(gu::byte_t* buf, size_t buflen, size_t offset) const { switch (version_) { #ifndef GALERA_KEY_VLQ case 1: return gu::serialize2(keys_, buf, buflen, offset); case 2: offset = gu::serialize1(flags_, buf, buflen, offset); return gu::serialize2(keys_, buf, buflen, offset); #else case 1: { size_t keys_size(keys_.size()); offset = gu::uleb128_encode(keys_size, buf, buflen, offset); assert (offset + key_size <= buflen); std::copy(&keys_[0], &keys_[0] + keys_size, buf + offset); return (offset + keys_size); } #endif default: log_fatal << "Internal error: unsupported key version: " << version_; abort(); return 0; } } inline size_t KeyOS::unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) { switch (version_) { #ifndef GALERA_KEY_VLQ case 1: return gu::unserialize2(buf, buflen, offset, keys_); case 2: offset = gu::unserialize1(buf, buflen, offset, flags_); return gu::unserialize2(buf, buflen, offset, keys_); #else case 1: { size_t len; offset = gu::uleb128_decode(buf, buflen, offset, len); keys_.resize(len); std::copy(buf + offset, buf + offset + len, keys_.begin()); return (offset + len); } #endif default: gu_throw_error(EPROTONOSUPPORT) << "unsupported key version: " << version_; } } inline size_t KeyOS::serial_size() const { switch (version_) { #ifndef GALERA_KEY_VLQ case 1: return gu::serial_size2(keys_); case 2: return (gu::serial_size(flags_) + gu::serial_size2(keys_)); #else case 1: { size_t size(gu::uleb128_size(keys_.size())); return (size + keys_.size()); } #endif default: log_fatal << "Internal error: unsupported key version: " << version_; abort(); return 0; } } } #endif // GALERA_KEY_HPP percona-galera-3-3.8-3390/galera/src/key_set.cpp000066400000000000000000000263171244131713600212040ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #include "key_set.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" #include #include // std::transform namespace galera { void KeySet::throw_version(int ver) { gu_throw_error(EINVAL) << "Unsupported KeySet version: " << ver; } static const char* ver_str[KeySet::MAX_VERSION + 1] = { "EMPTY", "FLAT8", "FLAT8A", "FLAT16", "FLAT16A" }; KeySet::Version KeySet::version (const std::string& ver) { std::string tmp(ver); std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::toupper); for (int i(EMPTY); i <= MAX_VERSION; ++i) { if (tmp == ver_str[i]) return version(i); } gu_throw_error(EINVAL) << "Unsupported KeySet version: " << ver; throw; } size_t KeySet::KeyPart::store_annotation (const wsrep_buf_t* const parts, int const part_num, gu::byte_t* buf, int const size) { assert(size >= 0); static size_t const max_len(std::numeric_limits::max()); ann_size_t ann_size; int tmp_size(sizeof(ann_size)); for (int i(0); i <= part_num; ++i) { tmp_size += 1 + std::min(parts[i].len, max_len); } tmp_size = std::min(tmp_size, size); ann_size = std::min(tmp_size, std::numeric_limits::max()); assert (ann_size <= size); ann_size_t const tmp(gu::htog(ann_size)); size_t off(sizeof(tmp)); ::memcpy(buf, &tmp, off); for (int i(0); i <= part_num && off < ann_size; ++i) { size_t const left(ann_size - off - 1); gu::byte_t const part_len (std::min(std::min(parts[i].len, left), max_len)); buf[off] = part_len; ++off; const gu::byte_t* const from( reinterpret_cast(parts[i].ptr)); std::copy(from, from + part_len, buf + off); off += part_len; } assert (off == ann_size); // log_info << "stored annotation of size: " << ann_size; return ann_size; } void KeySet::KeyPart::print_annotation(std::ostream& os, const gu::byte_t* buf) { ann_size_t const ann_size(gu::gtoh( *reinterpret_cast(buf))); size_t const begin(sizeof(ann_size_t)); size_t off(begin); while (off < ann_size) { if (off != begin) os << '/'; gu::byte_t const part_len(buf[off]); ++off; bool const last(ann_size == off + part_len); /* this is an attempt to guess whether we should interpret key part as * a string or numerical value */ bool const alpha(!last || part_len > 8); os << gu::Hexdump (buf + off, part_len, alpha); off += part_len; } } void KeySet::KeyPart::throw_buffer_too_short (size_t expected, size_t got) { gu_throw_error (EINVAL) << "Buffer too short: expected " << expected << ", got " << got; } void KeySet::KeyPart::throw_bad_prefix (gu::byte_t p) { gu_throw_error(EPROTO) << "Unsupported key prefix: " << p; } void KeySet::KeyPart::throw_match_empty_key (Version my, Version other) { gu_throw_error(EINVAL) << "Attempt to match against an empty key (" << my << ',' << other << ')'; } void KeySet::KeyPart::print (std::ostream& os) const { Version const ver(version()); size_t const size(ver != EMPTY ? base_size(ver, data_, 1) : 0); os << '(' << int(exclusive()) << ',' << ver_str[ver] << ')' << gu::Hexdump(data_, size); if (annotated(ver)) { os << "="; print_annotation (os, data_ + size); } } KeySetOut::KeyPart::KeyPart (KeyParts& added, KeySetOut& store, const KeyPart* parent, const KeyData& kd, int const part_num) : hash_ (parent->hash_), part_ (0), value_(reinterpret_cast(kd.parts[part_num].ptr)), size_ (kd.parts[part_num].len), ver_ (parent->ver_), own_ (false) { assert (ver_); uint32_t const s(gu::htog(size_)); hash_.append (&s, sizeof(s)); hash_.append (value_, size_); KeySet::KeyPart::TmpStore ts; KeySet::KeyPart::HashData hd; hash_.gather(hd.buf); /* only leaf part of the key can be exclusive */ bool const leaf (part_num + 1 == kd.parts_num); bool const exclusive (!kd.shared() && leaf); assert (kd.parts_num > part_num); KeySet::KeyPart kp(ts, hd, ver_, exclusive, kd.parts, part_num); #if 0 /* find() way */ /* the reason to use find() first, instead of going straight to insert() * is that we need to insert the part that was persistently stored in the * key set. At the same time we can't yet store the key part in the key set * before we can be sure that it is not a duplicate. Sort of 2PC. */ KeyParts::iterator found(added.find(kp)); if (added.end() != found) { if (exclusive && found->shared()) { /* need to ditch shared and add exclusive version of the key */ added.erase(found); found = added.end(); } else if (leaf || found->exclusive()) { #ifndef NDEBUG if (leaf) log_debug << "KeyPart ctor: full duplicate of " << *found; else log_debug << "Duplicate of exclusive: " << *found; #endif throw DUPLICATE(); } } if (added.end() == found) /* no such key yet, store and add */ { kp.store (store); std::pair res(added.insert(kp)); assert (res.second); found = res.first; } part_ = &(*found); #else /* insert() way */ std::pair const inserted(added.insert(kp)); if (inserted.second) { /* The key part was successfully inserted, store it in the key set buffer */ inserted.first->store (store); } else { /* A matching key part instance is already present in the set, check constraints */ if (exclusive && inserted.first->shared()) { /* The key part instance present in the set has weaker constraint, store this instance as well and update inserted to point there. (we can't update already stored data - it was checksummed, so we have to store a duplicate with a stronger constraint) */ kp.store (store); inserted.first->update_ptr(kp.ptr()); /* It is a hack, but it should be safe to modify key part already inserted into unordered set, as long as modification does not change hash and equality test results. And we get it to point to a duplicate here.*/ } else if (leaf || inserted.first->exclusive()) { /* we don't throw DUPLICATE for branch parts, just ignore them. DUPLICATE is thrown only when the whole key is a duplicate. */ #ifndef NDEBUG if (leaf) log_debug << "KeyPart ctor: full duplicate of " << *inserted.first; else log_debug << "Duplicate of exclusive: " << *inserted.first; #endif throw DUPLICATE(); } } part_ = &(*inserted.first); #endif /* insert() way */ } void KeySetOut::KeyPart::print (std::ostream& os) const { if (part_) os << *part_; else os << "0x0"; os << '(' << gu::Hexdump(value_, size_, true) << ')'; } #define CHECK_PREVIOUS_KEY 1 size_t KeySetOut::append (const KeyData& kd) { int i(0); #ifdef CHECK_PREVIOUS_KEY /* find common ancestor with the previous key */ for (; i < kd.parts_num && size_t(i + 1) < prev_.size() && prev_[i + 1].match(kd.parts[i].ptr, kd.parts[i].len); ++i) { #if 0 log_info << "prev[" << (i+1) << "]\n" << prev_[i+1] << "\nmatches\n" << gu::Hexdump(kd.parts[i].ptr, kd.parts[i].len, true); #endif /* 0 */ } // log_info << "matched " << i << " parts"; /* if we have a fully matched key OR common ancestor is exclusive, return */ if (i > 0) { assert (size_t(i) < prev_.size()); if (prev_[i].exclusive()) { assert (prev_.size() == (i + 1U)); // only leaf can be exclusive. // log_info << "Returning after matching exclusive key:\n"<< prev_[i]; return 0; } if (kd.parts_num == i) /* leaf */ { assert (prev_[i].shared()); if (kd.shared()) { // log_info << "Returning after matching all " << i << " parts"; return 0; } else /* need to add exclusive copy of the key */ --i; } } int const anc(i); const KeyPart* parent(&prev_[anc]); // log_info << "Common ancestor: " << anc << ' ' << *parent; #else KeyPart tmp(prev_[0]); const KeyPart* const parent(&tmp); #endif /* CHECK_PREVIOUS_KEY */ /* create parts that didn't match previous key and add to the set * of preiously added keys. */ size_t const old_size (size()); int j(0); for (; i < kd.parts_num; ++i, ++j) { try { KeyPart kp(added_, *this, parent, kd, i); #ifdef CHECK_PREVIOUS_KEY if (size_t(j) < new_.size()) { new_[j] = kp; } else { new_().push_back (kp); } parent = &new_[j]; #else if (kd.copy) kp.acquire(); if (i + 1 != kd.parts_num) tmp = kp; // <- updating parent for next iteration #endif /* CHECK_PREVIOUS_KEY */ // log_info << "pushed " << kp; } catch (KeyPart::DUPLICATE& e) { assert (i + 1 == kd.parts_num); /* There is a very small probability that child part thows DUPLICATE * even after parent was added as a new key. It does not matter: * a duplicate will be a duplicate in certification as well. */ #ifndef NDEBUG log_debug << "Returning after catching a DUPLICATE. Part: " << i; #endif /* NDEBUG */ goto out; } } assert (i == kd.parts_num); assert (anc + j == kd.parts_num); #ifdef CHECK_PREVIOUS_KEY /* copy new parts to prev_ */ prev_().resize(1 + kd.parts_num); std::copy(new_().begin(), new_().begin() + j, prev_().begin() + anc + 1); /* acquire key part value if it is volatile */ if (kd.copy) for (int k(anc + 1); size_t(k) < prev_.size(); ++k) { prev_[k].acquire(); } #endif /* CHECK_PREVIOUS_KEY */ out: return size() - old_size; } #if 0 const KeyIn& galera::KeySetIn::get_key() const { size_t offset(0); while (offset < keys_.size()) { KeyOS key(version_); if ((offset = unserialize(&keys_[0], keys_.size(), offset, key)) == 0) { gu_throw_fatal << "failed to unserialize key"; } s.push_back(key); } assert(offset == keys_.size()); } #endif } /* namespace galera */ percona-galera-3-3.8-3390/galera/src/key_set.hpp000066400000000000000000000503251244131713600212050ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #ifndef GALERA_KEY_SET_HPP #define GALERA_KEY_SET_HPP #include "gu_rset.hpp" #include "gu_unordered.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" #include "key_data.hpp" namespace galera { /* forward declarations for KeySet::KeyPart */ class KeySetOut; class KeySet { public: enum Version { EMPTY = 0, FLAT8, /* 8-byte hash (flat) */ FLAT8A, /* 8-byte hash (flat), annotated */ FLAT16, /* 16-byte hash (flat) */ FLAT16A, /* 16-byte hash (flat), annotated */ // TREE8, /* 8-byte hash + full serialized key */ MAX_VERSION = FLAT16A }; static Version version (unsigned int ver) { if (gu_likely (ver <= MAX_VERSION)) return static_cast(ver); throw_version(ver); } static Version version (const std::string& ver); class Key { public: enum Prefix { P_SHARED = 0, P_EXCLUSIVE, P_LAST = P_EXCLUSIVE }; }; /* class Key */ /* This class describes what commonly would be referred to as a "key". * It is called KeyPart because it does not fully represent a multi-part * key, but only nth part out of N total. * To fully represent a 3-part key p1:p2:p3 one would need 3 such objects: * for parts p1, p1:p2, p1:p2:p3 */ class KeyPart { public: static size_t const TMP_STORE_SIZE = 4096; static size_t const MAX_HASH_SIZE = 16; struct TmpStore { gu::byte_t buf[TMP_STORE_SIZE]; }; union HashData { gu::byte_t buf[MAX_HASH_SIZE]; uint64_t align; }; /* This ctor creates a serialized representation of a key in tmp store * from a key hash and optional annotation. */ KeyPart (TmpStore& tmp, const HashData& hash, Version const ver, bool const exclusive, const wsrep_buf_t* parts, /* for annotation */ int const part_num ) : data_(tmp.buf) { assert(ver > EMPTY && ver <= MAX_VERSION); /* 16 if ver in { FLAT16, FLAT16A }, 8 otherwise */ int const key_size (8 << (static_cast(ver - FLAT16) <= 1)); memcpy (tmp.buf, hash.buf, key_size); /* use lower bits for header: */ /* clear header bits */ gu::byte_t b = tmp.buf[0] & (~HEADER_MASK); /* set prefix */ if (exclusive) { b |= (Key::P_EXCLUSIVE & PREFIX_MASK); } /* set version */ b |= (ver & VERSION_MASK) << PREFIX_BITS; tmp.buf[0] = b; if (annotated(ver)) { store_annotation(parts, part_num, tmp.buf + key_size,sizeof(tmp.buf) - key_size); } } /* This ctor uses pointer to a permanently stored serialized key part */ KeyPart (const gu::byte_t* const buf, size_t const size) : data_(buf) { if (gu_likely(size >= 8 && serial_size() <= size)) return; throw_buffer_too_short (serial_size(), size); } explicit KeyPart (const gu::byte_t* ptr = NULL) : data_(ptr) {} Key::Prefix prefix() const { gu::byte_t const p(data_[0] & PREFIX_MASK); if (gu_likely(p <= Key::P_LAST)) return static_cast(p); throw_bad_prefix(p); } bool shared() const { return prefix() == Key::P_SHARED; } bool exclusive() const { return prefix() == Key::P_EXCLUSIVE; } static Version version(const gu::byte_t* const buf) { return Version( buf ? (buf[0] >> PREFIX_BITS) & VERSION_MASK : EMPTY); } Version version() const { return KeyPart::version(data_); } KeyPart (const KeyPart& k) : data_(k.data_) {} KeyPart& operator= (const KeyPart& k) { data_ = k.data_; return *this; } /* for hash table */ bool matches (const KeyPart& kp) const { assert (NULL != this->data_); assert (NULL != kp.data_); bool ret(true); // collision by default #if GU_WORDSIZE == 64 const uint64_t* lhs(reinterpret_cast(data_)); const uint64_t* rhs(reinterpret_cast(kp.data_)); #else const uint32_t* lhs(reinterpret_cast(data_)); const uint32_t* rhs(reinterpret_cast(kp.data_)); #endif /* WORDSIZE */ switch (std::min(version(), kp.version())) { case EMPTY: assert(0); throw_match_empty_key(version(), kp.version()); case FLAT16: case FLAT16A: #if GU_WORDSIZE == 64 ret = (lhs[1] == rhs[1]); #else ret = (lhs[2] == rhs[2] && lhs[3] == rhs[3]); #endif /* WORDSIZE */ case FLAT8: case FLAT8A: /* shift is to clear up the header */ #if GU_WORDSIZE == 64 ret = ret && ((gtoh64(lhs[0]) >> HEADER_BITS) == (gtoh64(rhs[0]) >> HEADER_BITS)); #else ret = ret && (lhs[1] == rhs[1] && (gtoh32(lhs[0]) >> HEADER_BITS) == (gtoh32(rhs[0]) >> HEADER_BITS)); #endif /* WORDSIZE */ } return ret; } size_t hash () const { /* Now this leaves uppermost bits always 0. * How bad is it in practice? Is it reasonable to assume that only * lower bits are used in unordered set? */ size_t ret(gu::gtoh(reinterpret_cast(data_)[0]) >> HEADER_BITS); return ret; // (ret ^ (ret << HEADER_BITS)) to cover 0 bits } static size_t serial_size (const gu::byte_t* const buf, size_t const size) { Version const ver(version(buf)); return serial_size (ver, buf, size); } size_t serial_size () const { return KeyPart::serial_size(data_, -1U); } void print (std::ostream& os) const; void swap (KeyPart& other) { using std::swap; swap(data_, other.data_); } const gu::byte_t* ptr() const { return data_; } protected: friend class KeySetOut; /* update data pointer */ void update_ptr(const gu::byte_t* ptr) const { data_ = ptr; } /* update storage of KeyPart already inserted in unordered set */ void store(gu::RecordSetOut& rs) const { data_ = rs.append(data_, serial_size(), true, true).first; // log_info << "Stored key of size: " << serial_size(); } private: static unsigned int const PREFIX_BITS = 2; static gu::byte_t const PREFIX_MASK = (1 << PREFIX_BITS) - 1; static unsigned int const VERSION_BITS = 3; static gu::byte_t const VERSION_MASK = (1 << VERSION_BITS) - 1; static unsigned int const HEADER_BITS = PREFIX_BITS + VERSION_BITS; static gu::byte_t const HEADER_MASK = (1 << HEADER_BITS) - 1; mutable /* to be able to store const object */ const gu::byte_t* data_; // it never owns the buffer static size_t base_size (Version const ver, const gu::byte_t* const buf, size_t const size) { switch (ver) { case FLAT16: case FLAT16A: return 16; case FLAT8: case FLAT8A: return 8; case EMPTY: assert(0); } abort(); } static bool annotated (Version const ver) { return (ver == FLAT16A || ver == FLAT8A); } typedef uint16_t ann_size_t; static size_t serial_size (Version const ver, const gu::byte_t* const buf, size_t const size = -1U) { size_t ret(base_size(ver, buf, size)); assert (ret <= size); if (annotated(ver)) { assert (ret + 2 <= size); ret +=gu::gtoh(*reinterpret_cast(buf + ret)); assert (ret <= size); } return ret; } static size_t store_annotation (const wsrep_buf_t* parts, int part_num, gu::byte_t* buf, int size); static void print_annotation (std::ostream& os, const gu::byte_t* buf); static void throw_buffer_too_short (size_t expected, size_t got) GU_NORETURN; static void throw_bad_prefix (gu::byte_t p) GU_NORETURN; static void throw_match_empty_key (Version my, Version other) GU_NORETURN; }; /* class KeyPart */ class KeyPartHash { public: size_t operator() (const KeyPart& k) const { return k.hash(); } }; class KeyPartEqual { public: bool operator() (const KeyPart& l, const KeyPart& r) const { return (l.matches(r)); } }; /* functor KeyPartEqual */ static void throw_version(int) GU_NORETURN; }; /* class KeySet */ inline void swap (KeySet::KeyPart& a, KeySet::KeyPart& b) { a.swap(b); } inline std::ostream& operator << (std::ostream& os, const KeySet::KeyPart& kp) { kp.print (os); return os; } #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic push # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic ignored "-Weffc++" #endif class KeySetOut : public gu::RecordSetOut { public: typedef gu::UnorderedSet < KeySet::KeyPart, KeySet::KeyPartHash, KeySet::KeyPartEqual > /* This #if decides whether we use straight gu::UnorderedSet for appended * key parts (0), or go for an optimized version (1). Don't remove it. */ #if 0 KeyParts; #else KeyPartSet; /* This is a naive mock up of an "unordered set" that first tries to use * preallocated set of buckets and falls back to a "real" heap-based * unordered set from STL/TR1 when preallocated one is exhausted. * The goal is to make sure that at least 3 keys can be inserted without * the need for dynamic allocation. * In practice, with 64 "buckets" and search depth of 3, the average * number of inserted keys before there is a need to go for heap is 25. * 128 buckets will give you 45 and 256 - around 80. */ class KeyParts { public: KeyParts() : first_(), second_(NULL), first_size_(0) { ::memset(first_, 0, sizeof(first_)); } ~KeyParts() { delete second_; } /* This iterator class is declared for compatibility with * unordered_set. We may actually use a more simple interface here. */ class iterator { public: iterator(const KeySet::KeyPart* kp) : kp_(kp) {} /* This is sort-of a dirty hack to ensure that first_ array * of KeyParts class can be treated like a POD array. * It uses the fact that the only non-static member of * KeySet::KeyPart is gu::byte_t* and so does direct casts between * pointers. I wish someone could make it cleaner. */ iterator(const gu::byte_t** kp) : kp_(reinterpret_cast(kp)) {} const KeySet::KeyPart* operator -> () const { return kp_; } const KeySet::KeyPart& operator * () const { return *kp_; } bool operator == (const iterator& i) const { return (kp_ == i.kp_); } bool operator != (const iterator& i) const { return (kp_ != i.kp_); } private: const KeySet::KeyPart* kp_; }; const iterator end() { return iterator(static_cast(NULL)); } const iterator find(const KeySet::KeyPart& kp) { unsigned int idx(kp.hash()); for (unsigned int i(0); i < FIRST_DEPTH; ++i, ++idx) { idx &= FIRST_MASK; if (0 !=first_[idx] && KeySet::KeyPart(first_[idx]).matches(kp)) { return iterator(&first_[idx]); } } if (second_ && second_->size() > 0) { KeyPartSet::iterator i2(second_->find(kp)); if (i2 != second_->end()) return iterator(&(*i2)); } return end(); } std::pair insert(const KeySet::KeyPart& kp) { unsigned int idx(kp.hash()); for (unsigned int i(0); i < FIRST_DEPTH; ++i, ++idx) { idx &= FIRST_MASK; if (0 == first_[idx]) { first_[idx] = kp.ptr(); ++first_size_; return std::pair(iterator(&first_[idx]), true); } if (KeySet::KeyPart(first_[idx]).matches(kp)) { return std::pair(iterator(&first_[idx]),false); } } if (!second_) { second_ = new KeyPartSet(); // log_info << "Requesting heap at load factor " // << first_size_ << '/' << FIRST_SIZE << " = " // << (double(first_size_)/FIRST_SIZE); } std::pair res = second_->insert(kp); return std::pair(iterator(&(*res.first)), res.second); } iterator erase(iterator it) { unsigned int idx(it->hash()); for (unsigned int i(0); i < FIRST_DEPTH; ++i, ++idx) { idx &= FIRST_MASK; if (first_[idx] && KeySet::KeyPart(first_[idx]).matches(*it)) { first_[idx] = 0; --first_size_; return iterator(&first_[(idx + 1) & FIRST_MASK]); } } if (second_ && second_->size() > 0) { KeyPartSet::iterator it2(second_->erase(second_->find(*it))); if (it2 != second_->end()) return iterator(&(*it2)); } return end(); } size_t size() const { return (first_size_ + second_->size()); } private: static unsigned int const FIRST_MASK = 0x3f; // 63 static unsigned int const FIRST_SIZE = FIRST_MASK + 1; static unsigned int const FIRST_DEPTH = 3; const gu::byte_t* first_[FIRST_SIZE]; KeyPartSet* second_; unsigned int first_size_; }; #endif /* 1 */ class KeyPart { public: KeyPart (KeySet::Version const ver = KeySet::FLAT16) : hash_ (), part_ (0), value_(0), size_ (0), ver_ (ver), own_ (false) { assert (ver_); } /* to throw in KeyPart() ctor in case it is a duplicate */ class DUPLICATE {}; KeyPart (KeyParts& added, KeySetOut& store, const KeyPart* parent, const KeyData& kd, int const part_num); KeyPart (const KeyPart& k) : hash_ (k.hash_), part_ (k.part_), value_(k.value_), size_ (k.size_), ver_ (k.ver_), own_ (k.own_) { assert (ver_); k.own_ = false; } friend void swap (KeyPart& l, KeyPart& r) { using std::swap; swap (l.hash_, r.hash_ ); swap (l.part_, r.part_ ); swap (l.value_, r.value_); swap (l.size_, r.size_ ); swap (l.ver_, r.ver_ ); swap (l.own_, r.own_ ); } KeyPart& operator= (KeyPart k) { swap(*this, k); return *this; } bool match (const void* const v, size_t const s) const { return (size_ == s && !(::memcmp (value_, v, size_))); } bool exclusive () const { return (part_ && part_->exclusive()); } bool shared () const { return !exclusive(); } void acquire() { gu::byte_t* tmp = new gu::byte_t[size_]; std::copy(value_, value_ + size_, tmp); value_ = tmp; own_ = true; } void release() { if (own_) { // log_debug << "released: " << gu::Hexdump(value_, size_, true); delete[] value_; value_ = 0; } own_ = false; } ~KeyPart() { release(); } void print (std::ostream& os) const; typedef gu::RecordSet::GatherVector GatherVector; private: gu::Hash hash_; const KeySet::KeyPart* part_; mutable const gu::byte_t* value_; unsigned int size_; KeySet::Version ver_; mutable bool own_; }; /* class KeySetOut::KeyPart */ KeySetOut () // empty ctor for slave TrxHandle : gu::RecordSetOut(), added_(), prev_ (), new_ (), version_() {} KeySetOut (gu::byte_t* reserved, size_t reserved_size, const BaseName& base_name, KeySet::Version const version) : gu::RecordSetOut ( reserved, reserved_size, base_name, check_type (version), ks_to_rs_version(version) ), added_(), prev_ (), new_ (), version_(version) { assert (version_ != KeySet::EMPTY); KeyPart zero(version_); prev_().push_back(zero); } ~KeySetOut () {} size_t append (const KeyData& kd); KeySet::Version version () { return count() ? version_ : KeySet::EMPTY; } private: // depending on version we may pack data differently KeyParts added_; gu::Vector prev_; gu::Vector new_; KeySet::Version version_; static gu::RecordSet::CheckType check_type (KeySet::Version ver) { switch (ver) { case KeySet::EMPTY: break; /* Can't create EMPTY KeySetOut */ default: return gu::RecordSet::CHECK_MMH128; } KeySet::throw_version(ver); } static gu::RecordSet::Version ks_to_rs_version (KeySet::Version ver) { switch (ver) { case KeySet::EMPTY: break; /* Can't create EMPTY KeySetOut */ default: return gu::RecordSet::VER1; } KeySet::throw_version(ver); } }; /* class KeySetOut */ inline std::ostream& operator << (std::ostream& os, const KeySetOut::KeyPart& kp) { kp.print (os); return os; } class KeySetIn : public gu::RecordSetIn { public: KeySetIn (KeySet::Version ver, const gu::byte_t* buf, size_t size) : gu::RecordSetIn(buf, size, false), version_(ver) {} KeySetIn () : gu::RecordSetIn(), version_(KeySet::EMPTY) {} void init (KeySet::Version ver, const gu::byte_t* buf, size_t size) { gu::RecordSetIn::init(buf, size, false); version_ = ver; } KeySet::KeyPart const next () const { return gu::RecordSetIn::next(); } private: KeySet::Version version_; }; /* class KeySetIn */ #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) #endif } /* namespace galera */ #endif // GALERA_KEY_SET_HPP percona-galera-3-3.8-3390/galera/src/mapped_buffer.cpp000066400000000000000000000073531244131713600223370ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #define _FILE_OFFSET_BITS 64 #include "mapped_buffer.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_macros.h" #include #include #include #include #include // MAP_FAILED is defined as (void *) -1 #pragma GCC diagnostic ignored "-Wold-style-cast" using namespace std; using namespace gu; galera::MappedBuffer::MappedBuffer(const std::string& working_dir, size_t threshold) : working_dir_ (working_dir), file_ (), fd_ (-1), threshold_ (threshold), buf_ (0), buf_size_ (0), real_buf_size_(0) { } galera::MappedBuffer::~MappedBuffer() { if (fd_ != -1) { struct stat st; fstat(fd_, &st); log_debug << "file size " << st.st_size; } clear(); } void galera::MappedBuffer::reserve(size_t sz) { if (real_buf_size_ >= sz) { // no need for reallocation return; } if (sz > threshold_) { // buffer size exceeds in-memory threshold, have to mmap if (gu_unlikely(std::numeric_limits::max() - sz < threshold_)) { sz = std::numeric_limits::max(); } else { sz = (sz/threshold_ + 1)*threshold_; } if (gu_unlikely(sz > static_cast(std::numeric_limits::max()))) { gu_throw_error(EINVAL) << "size exceeds maximum of off_t"; } if (fd_ == -1) { file_ = working_dir_ + "/gmb_XXXXXX"; fd_ = mkstemp(&file_[0]); if (fd_ == -1) { gu_throw_error(errno) << "mkstemp(" << file_ << ") failed"; } if (ftruncate(fd_, sz) == -1) { gu_throw_error(errno) << "ftruncate() failed"; } byte_t* tmp(reinterpret_cast( mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_, 0))); if (tmp == MAP_FAILED) { free(buf_); buf_ = 0; clear(); gu_throw_error(ENOMEM) << "mmap() failed"; } copy(buf_, buf_ + buf_size_, tmp); free(buf_); buf_ = tmp; } else { if (munmap(buf_, real_buf_size_) != 0) { gu_throw_error(errno) << "munmap() failed"; } if (ftruncate(fd_, sz) == -1) { gu_throw_error(errno) << "fruncate() failed"; } byte_t* tmp(reinterpret_cast( mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_, 0))); if (tmp == MAP_FAILED) { buf_ = 0; clear(); gu_throw_error(ENOMEM) << "mmap() failed"; } buf_ = tmp; } } else { sz = min(threshold_, sz*2); byte_t* tmp(reinterpret_cast(realloc(buf_, sz))); if (tmp == 0) { gu_throw_error(ENOMEM) << "realloc failed"; } buf_ = tmp; } real_buf_size_ = sz; } void galera::MappedBuffer::resize(size_t sz) { reserve(sz); buf_size_ = sz; } void galera::MappedBuffer::clear() { if (fd_ != -1) { if (buf_ != 0) munmap(buf_, real_buf_size_); while (close(fd_) == EINTR) { } unlink(file_.c_str()); } else { free(buf_); } fd_ = -1; buf_ = 0; buf_size_ = 0; real_buf_size_ = 0; } percona-galera-3-3.8-3390/galera/src/mapped_buffer.hpp000066400000000000000000000032071244131713600223360ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #ifndef GALERA_MAPPED_BUFFER_HPP #define GALERA_MAPPED_BUFFER_HPP #include #include "gu_buffer.hpp" namespace galera { class MappedBuffer { public: typedef gu::byte_t& reference; typedef gu::byte_t const& const_reference; typedef gu::byte_t* iterator; typedef gu::byte_t const* const_iterator; MappedBuffer(const std::string& working_dir, size_t threshold = 1 << 20); ~MappedBuffer(); reference operator[](size_t i) { return buf_[i]; } const_reference operator[](size_t i) const { return buf_[i]; } void reserve(size_t sz); void resize(size_t sz); void clear(); size_t size() const { return buf_size_; } bool empty() const { return (buf_size_ == 0); } iterator begin() { return buf_; } iterator end() { return (buf_ + buf_size_); } const_iterator begin() const { return buf_; } const_iterator end() const { return (buf_ + buf_size_); } private: MappedBuffer(const MappedBuffer&); void operator=(const MappedBuffer&); const std::string& working_dir_; // working dir for data files std::string file_; int fd_; // file descriptor size_t threshold_; // in-memory threshold gu::byte_t* buf_; // data buffer size_t buf_size_; // buffer size (inserted data size) size_t real_buf_size_; // real buffer size (allocated size) }; } #endif // GALERA_MAPPED_BUFFER_HPP percona-galera-3-3.8-3390/galera/src/monitor.hpp000066400000000000000000000317511244131713600212330ustar00rootroot00000000000000// // Copyright (C) 2010-2013 Codership Oy // #ifndef GALERA_MONITOR_HPP #define GALERA_MONITOR_HPP #include "trx_handle.hpp" #include #include namespace galera { template class Monitor { private: struct Process { Process() : obj_(0), cond_(), wait_cond_(), state_(S_IDLE) { } const C* obj_; gu::Cond cond_; gu::Cond wait_cond_; enum State { S_IDLE, // Slot is free S_WAITING, // Waiting to enter applying critical section S_CANCELED, S_APPLYING, // Applying S_FINISHED // Finished } state_; private: // non-copyable Process(const Process& other); void operator=(const Process&); }; static const ssize_t process_size_ = (1ULL << 16); static const size_t process_mask_ = process_size_ - 1; public: Monitor() : mutex_(), cond_(), last_entered_(-1), last_left_(-1), drain_seqno_(LLONG_MAX), process_(new Process[process_size_]), entered_(0), oooe_(0), oool_(0), win_size_(0) { } ~Monitor() { delete[] process_; if (entered_ > 0) { log_info << "mon: entered " << entered_ << " oooe fraction " << double(oooe_)/entered_ << " oool fraction " << double(oool_)/entered_; } else { log_info << "apply mon: entered 0"; } } void set_initial_position(wsrep_seqno_t seqno) { gu::Lock lock(mutex_); if (last_entered_ == -1 || seqno == -1) { // first call or reset last_entered_ = last_left_ = seqno; } else { // drain monitor up to seqno but don't reset last_entered_ // or last_left_ drain_common(seqno, lock); drain_seqno_ = LLONG_MAX; } if (seqno != -1) { const size_t idx(indexof(seqno)); process_[idx].wait_cond_.broadcast(); } } void enter(C& obj) { const wsrep_seqno_t obj_seqno(obj.seqno()); const size_t idx(indexof(obj_seqno)); gu::Lock lock(mutex_); assert(obj_seqno > last_left_); pre_enter(obj, lock); if (gu_likely(process_[idx].state_ != Process::S_CANCELED)) { assert(process_[idx].state_ == Process::S_IDLE); process_[idx].state_ = Process::S_WAITING; process_[idx].obj_ = &obj; while (may_enter(obj) == false && process_[idx].state_ == Process::S_WAITING) { obj.unlock(); lock.wait(process_[idx].cond_); obj.lock(); } if (process_[idx].state_ != Process::S_CANCELED) { assert(process_[idx].state_ == Process::S_WAITING || process_[idx].state_ == Process::S_APPLYING); process_[idx].state_ = Process::S_APPLYING; ++entered_; oooe_ += ((last_left_ + 1) < obj_seqno); win_size_ += (last_entered_ - last_left_); return; } } assert(process_[idx].state_ == Process::S_CANCELED); process_[idx].state_ = Process::S_IDLE; gu_throw_error(EINTR); } void leave(const C& obj) { #ifndef NDEBUG size_t idx(indexof(obj.seqno())); #endif /* NDEBUG */ gu::Lock lock(mutex_); assert(process_[idx].state_ == Process::S_APPLYING || process_[idx].state_ == Process::S_CANCELED); assert(process_[indexof(last_left_)].state_ == Process::S_IDLE); post_leave(obj, lock); } void self_cancel(C& obj) { wsrep_seqno_t const obj_seqno(obj.seqno()); size_t idx(indexof(obj_seqno)); gu::Lock lock(mutex_); assert(obj_seqno > last_left_); while (obj_seqno - last_left_ >= process_size_) // TODO: exit on error { log_warn << "Trying to self-cancel seqno out of process " << "space: obj_seqno - last_left_ = " << obj_seqno << " - " << last_left_ << " = " << (obj_seqno - last_left_) << ", process_size_: " << process_size_ << ". Deadlock is very likely."; obj.unlock(); lock.wait(cond_); obj.lock(); } assert(process_[idx].state_ == Process::S_IDLE || process_[idx].state_ == Process::S_CANCELED); if (obj_seqno > last_entered_) last_entered_ = obj_seqno; if (obj_seqno <= drain_seqno_) { post_leave(obj, lock); } else { process_[idx].state_ = Process::S_FINISHED; } } void interrupt(const C& obj) { size_t idx (indexof(obj.seqno())); gu::Lock lock(mutex_); while (obj.seqno() - last_left_ >= process_size_) // TODO: exit on error { lock.wait(cond_); } if ((process_[idx].state_ == Process::S_IDLE && obj.seqno() > last_left_ ) || process_[idx].state_ == Process::S_WAITING ) { process_[idx].state_ = Process::S_CANCELED; process_[idx].cond_.signal(); // since last_left + 1 cannot be <= S_WAITING we're not // modifying a window here. No broadcasting. } else { log_debug << "interrupting " << obj.seqno() << " state " << process_[idx].state_ << " le " << last_entered_ << " ll " << last_left_; } } wsrep_seqno_t last_left() const { gu::Lock lock(mutex_); return last_left_; } ssize_t size() const { return process_size_; } bool would_block (wsrep_seqno_t seqno) const { return (seqno - last_left_ >= process_size_ || seqno > drain_seqno_); } void drain(wsrep_seqno_t seqno) { gu::Lock lock(mutex_); while (drain_seqno_ != LLONG_MAX) { lock.wait(cond_); } drain_common(seqno, lock); // there can be some stale canceled entries update_last_left(); drain_seqno_ = LLONG_MAX; cond_.broadcast(); } void wait(wsrep_seqno_t seqno) { gu::Lock lock(mutex_); if (last_left_ < seqno) { size_t idx(indexof(seqno)); lock.wait(process_[idx].wait_cond_); } } void wait(wsrep_seqno_t seqno, const gu::datetime::Date& wait_until) { gu::Lock lock(mutex_); if (last_left_ < seqno) { size_t idx(indexof(seqno)); lock.wait(process_[idx].wait_cond_, wait_until); } } void get_stats(double* oooe, double* oool, double* win_size) { gu::Lock lock(mutex_); if (entered_ > 0) { *oooe = (oooe_ > 0 ? double(oooe_)/entered_ : .0); *oool = (oool_ > 0 ? double(oool_)/entered_ : .0); *win_size = (win_size_ > 0 ? double(win_size_)/entered_ : .0); } else { *oooe = .0; *oool = .0; *win_size = .0; } } void flush_stats() { gu::Lock lock(mutex_); oooe_ = 0; oool_ = 0; win_size_ = 0; entered_ = 0; } private: size_t indexof(wsrep_seqno_t seqno) { return (seqno & process_mask_); } bool may_enter(const C& obj) const { return obj.condition(last_entered_, last_left_); } // wait until it is possible to grab slot in monitor, // update last entered void pre_enter(C& obj, gu::Lock& lock) { assert(last_left_ <= last_entered_); const wsrep_seqno_t obj_seqno(obj.seqno()); while (would_block (obj_seqno)) // TODO: exit on error { obj.unlock(); lock.wait(cond_); obj.lock(); } if (last_entered_ < obj_seqno) last_entered_ = obj_seqno; } void update_last_left() { for (wsrep_seqno_t i = last_left_ + 1; i <= last_entered_; ++i) { Process& a(process_[indexof(i)]); if (Process::S_FINISHED == a.state_) { a.state_ = Process::S_IDLE; last_left_ = i; a.wait_cond_.broadcast(); } else { break; } } assert(last_left_ <= last_entered_); } void wake_up_next() { for (wsrep_seqno_t i = last_left_ + 1; i <= last_entered_; ++i) { Process& a(process_[indexof(i)]); if (a.state_ == Process::S_WAITING && may_enter(*a.obj_) == true) { // We need to set state to APPLYING here because if // it is the last_left_ + 1 and it gets canceled in // the race that follows exit from this function, // there will be nobody to clean up and advance // last_left_. a.state_ = Process::S_APPLYING; a.cond_.signal(); } } } void post_leave(const C& obj, gu::Lock& lock) { const wsrep_seqno_t obj_seqno(obj.seqno()); const size_t idx(indexof(obj_seqno)); if (last_left_ + 1 == obj_seqno) // we're shrinking window { process_[idx].state_ = Process::S_IDLE; last_left_ = obj_seqno; process_[idx].wait_cond_.broadcast(); update_last_left(); oool_ += (last_left_ > obj_seqno); // wake up waiters that may remain above us (last_left_ // now is max) wake_up_next(); } else { process_[idx].state_ = Process::S_FINISHED; } process_[idx].obj_ = 0; assert((last_left_ >= obj_seqno && process_[idx].state_ == Process::S_IDLE) || process_[idx].state_ == Process::S_FINISHED); assert(last_left_ != last_entered_ || process_[indexof(last_left_)].state_ == Process::S_IDLE); if ((last_left_ >= obj_seqno) || // - occupied window shrinked (last_left_ >= drain_seqno_)) // - this is to notify drain that // we reached drain_seqno_ { cond_.broadcast(); } } void drain_common(wsrep_seqno_t seqno, gu::Lock& lock) { log_debug << "draining up to " << seqno; drain_seqno_ = seqno; if (last_left_ > drain_seqno_) { log_debug << "last left greater than drain seqno"; for (wsrep_seqno_t i = drain_seqno_; i <= last_left_; ++i) { const Process& a(process_[indexof(i)]); log_debug << "applier " << i << " in state " << a.state_; } } while (last_left_ < drain_seqno_) lock.wait(cond_); } Monitor(const Monitor&); void operator=(const Monitor&); gu::Mutex mutex_; gu::Cond cond_; wsrep_seqno_t last_entered_; wsrep_seqno_t last_left_; wsrep_seqno_t drain_seqno_; Process* process_; long entered_; // entered long oooe_; // out of order entered long oool_; // out of order left long win_size_; // window between last_left_ and last_entered_ }; } #endif // GALERA_APPLY_MONITOR_HPP percona-galera-3-3.8-3390/galera/src/replicator.cpp000066400000000000000000000005601244131713600216750ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "replicator.hpp" namespace galera { std::string const Replicator::Param::debug_log = "debug"; void Replicator::register_params(gu::Config& conf) { conf.add(Param::debug_log, "no"); } const char* const Replicator::TRIVIAL_SST(WSREP_STATE_TRANSFER_TRIVIAL); } /* namespace galera */ percona-galera-3-3.8-3390/galera/src/replicator.hpp000066400000000000000000000126441244131713600217100ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_REPLICATOR_HPP #define GALERA_REPLICATOR_HPP #include "wsrep_api.h" #include "galera_exception.hpp" #include #include namespace galera { class Statement; class RowId; class TrxHandle; //! @class Galera // // @brief Abstract Galera replicator interface class Replicator { public: struct Param { static std::string const debug_log; }; static const char* const TRIVIAL_SST; typedef enum { S_DESTROYED, S_CLOSED, S_CLOSING, S_CONNECTED, S_JOINING, S_JOINED, S_SYNCED, S_DONOR } State; Replicator() { } virtual ~Replicator() { } virtual wsrep_status_t connect(const std::string& cluster_name, const std::string& cluster_url, const std::string& state_donor, bool bootstrap) = 0; virtual wsrep_status_t close() = 0; virtual wsrep_status_t async_recv(void* recv_ctx) = 0; virtual int trx_proto_ver() const = 0; virtual int repl_proto_ver() const = 0; virtual TrxHandle* get_local_trx(wsrep_trx_id_t, bool) = 0; virtual void unref_local_trx(TrxHandle* trx) = 0; virtual void discard_local_trx(TrxHandle* trx_id) = 0; virtual TrxHandle* local_conn_trx(wsrep_conn_id_t conn_id, bool create) = 0; virtual void discard_local_conn_trx(wsrep_conn_id_t conn_id) = 0; virtual void discard_local_conn(wsrep_conn_id_t conn_id) = 0; virtual wsrep_status_t replicate(TrxHandle* trx, wsrep_trx_meta_t*) = 0; virtual wsrep_status_t pre_commit(TrxHandle* trx, wsrep_trx_meta_t*) =0; virtual wsrep_status_t post_commit(TrxHandle* trx) = 0; virtual wsrep_status_t post_rollback(TrxHandle* trx) = 0; virtual wsrep_status_t replay_trx(TrxHandle* trx, void* replay_ctx) = 0; virtual void abort_trx(TrxHandle* trx) = 0; virtual wsrep_status_t causal_read(wsrep_gtid_t*) = 0; virtual wsrep_status_t to_isolation_begin(TrxHandle* trx, wsrep_trx_meta_t*) = 0; virtual wsrep_status_t to_isolation_end(TrxHandle* trx) = 0; virtual wsrep_status_t preordered_collect(wsrep_po_handle_t& handle, const struct wsrep_buf* data, size_t count, bool copy) = 0; virtual wsrep_status_t preordered_commit(wsrep_po_handle_t& handle, const wsrep_uuid_t& source, uint64_t flags, int pa_range, bool commit) =0; virtual wsrep_status_t sst_sent(const wsrep_gtid_t& state_id, int rcode) = 0; virtual wsrep_status_t sst_received(const wsrep_gtid_t& state_id, const void* state, size_t state_len, int rcode) = 0; // action source interface virtual void process_trx(void* recv_ctx, TrxHandle* trx) = 0; virtual void process_commit_cut(wsrep_seqno_t seq, wsrep_seqno_t seqno_l) = 0; virtual void process_conf_change(void* recv_ctx, const wsrep_view_info_t& view_info, int repl_proto, State next_state, wsrep_seqno_t seqno_l) = 0; virtual void process_state_req(void* recv_ctx, const void* req, size_t req_size, wsrep_seqno_t seqno_l, wsrep_seqno_t donor_seq) = 0; virtual void process_join(wsrep_seqno_t seqno, wsrep_seqno_t seqno_l) = 0; virtual void process_sync(wsrep_seqno_t seqno_l) = 0; virtual const struct wsrep_stats_var* stats_get() const = 0; virtual void stats_reset() = 0; // static void stats_free(struct wsrep_stats_var*) must be declared in // the child class /*! @throws NotFound */ virtual void param_set (const std::string& key, const std::string& value) = 0; /*! @throws NotFound */ virtual std::string param_get (const std::string& key) const = 0; virtual const gu::Config& params() const = 0; virtual wsrep_seqno_t pause() = 0; virtual void resume() = 0; virtual void desync() = 0; virtual void resync() = 0; protected: static void register_params(gu::Config&); }; } #endif // GALERA_REPLICATOR_HPP percona-galera-3-3.8-3390/galera/src/replicator_smm.cpp000066400000000000000000001530031244131713600225520ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "galera_common.hpp" #include "replicator_smm.hpp" #include "galera_exception.hpp" #include "uuid.hpp" #include "galera_info.hpp" #include #include static void apply_trx_ws(void* recv_ctx, wsrep_apply_cb_t apply_cb, wsrep_commit_cb_t commit_cb, const galera::TrxHandle& trx, const wsrep_trx_meta_t& meta) { using galera::TrxHandle; static const size_t max_apply_attempts(4); size_t attempts(1); do { try { if (trx.is_toi()) { log_debug << "Executing TO isolated action: " << trx; } gu_trace(trx.apply(recv_ctx, apply_cb, meta)); if (trx.is_toi()) { log_debug << "Done executing TO isolated action: " << trx.global_seqno(); } break; } catch (galera::ApplyException& e) { if (trx.is_toi()) { log_warn << "Ignoring error for TO isolated action: " << trx; break; } else { int const err(e.status()); if (err > 0) { wsrep_bool_t unused(false); int const rcode( commit_cb( recv_ctx, TrxHandle::trx_flags_to_wsrep_flags(trx.flags()), &meta, &unused, false)); if (WSREP_OK != rcode) { gu_throw_fatal << "Rollback failed. Trx: " << trx; } ++attempts; if (attempts <= max_apply_attempts) { log_warn << e.what() << "\nRetrying " << attempts << "th time"; } } else { GU_TRACE(e); throw; } } } } while (attempts <= max_apply_attempts); if (gu_unlikely(attempts > max_apply_attempts)) { std::ostringstream msg; msg << "Failed to apply trx " << trx.global_seqno() << " " << max_apply_attempts << " times"; throw galera::ApplyException(msg.str(), WSREP_CB_FAILURE); } return; } std::ostream& galera::operator<<(std::ostream& os, ReplicatorSMM::State state) { switch (state) { case ReplicatorSMM::S_DESTROYED: return (os << "DESTROYED"); case ReplicatorSMM::S_CLOSED: return (os << "CLOSED"); case ReplicatorSMM::S_CLOSING: return (os << "CLOSING"); case ReplicatorSMM::S_CONNECTED: return (os << "CONNECTED"); case ReplicatorSMM::S_JOINING: return (os << "JOINING"); case ReplicatorSMM::S_JOINED: return (os << "JOINED"); case ReplicatorSMM::S_SYNCED: return (os << "SYNCED"); case ReplicatorSMM::S_DONOR: return (os << "DONOR"); } gu_throw_fatal << "invalid state " << static_cast(state); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Public ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// galera::ReplicatorSMM::ReplicatorSMM(const struct wsrep_init_args* args) : init_lib_ (reinterpret_cast(args->logger_cb)), config_ (), init_config_ (config_, args->node_address), parse_options_ (config_, args->options), str_proto_ver_ (-1), protocol_version_ (-1), proto_max_ (gu::from_string(config_.get(Param::proto_max))), state_ (S_CLOSED), sst_state_ (SST_NONE), co_mode_ (CommitOrder::from_string( config_.get(Param::commit_order))), data_dir_ (args->data_dir ? args->data_dir : ""), state_file_ (data_dir_.length() ? data_dir_+'/'+GALERA_STATE_FILE : GALERA_STATE_FILE), st_ (state_file_), trx_params_ (data_dir_, -1, KeySet::version(config_.get(Param::key_format)), gu::from_string(config_.get( Param::max_write_set_size))), uuid_ (WSREP_UUID_UNDEFINED), state_uuid_ (WSREP_UUID_UNDEFINED), state_uuid_str_ (), cc_seqno_ (WSREP_SEQNO_UNDEFINED), pause_seqno_ (WSREP_SEQNO_UNDEFINED), app_ctx_ (args->app_ctx), view_cb_ (args->view_handler_cb), apply_cb_ (args->apply_cb), commit_cb_ (args->commit_cb), unordered_cb_ (args->unordered_cb), sst_donate_cb_ (args->sst_donate_cb), synced_cb_ (args->synced_cb), sst_donor_ (), sst_uuid_ (WSREP_UUID_UNDEFINED), sst_seqno_ (WSREP_SEQNO_UNDEFINED), sst_mutex_ (), sst_cond_ (), sst_retry_sec_ (1), gcache_ (config_, data_dir_), gcs_ (config_, gcache_, proto_max_, args->proto_ver, args->node_name, args->node_incoming), service_thd_ (gcs_, gcache_), slave_pool_ (sizeof(TrxHandle), 1024, "SlaveTrxHandle"), as_ (0), gcs_as_ (slave_pool_, gcs_, *this, gcache_), ist_receiver_ (config_, slave_pool_, args->node_address), ist_senders_ (gcs_, gcache_), wsdb_ (), cert_ (config_, service_thd_), local_monitor_ (), apply_monitor_ (), commit_monitor_ (), causal_read_timeout_(config_.get(Param::causal_read_timeout)), receivers_ (), replicated_ (), replicated_bytes_ (), keys_count_ (), keys_bytes_ (), data_bytes_ (), unrd_bytes_ (), local_commits_ (), local_rollbacks_ (), local_cert_failures_(), local_replays_ (), causal_reads_ (), preordered_id_ (), incoming_list_ (""), incoming_mutex_ (), wsrep_stats_ () { // @todo add guards (and perhaps actions) state_.add_transition(Transition(S_CLOSED, S_DESTROYED)); state_.add_transition(Transition(S_CLOSED, S_CONNECTED)); state_.add_transition(Transition(S_CLOSING, S_CLOSED)); state_.add_transition(Transition(S_CONNECTED, S_CLOSING)); state_.add_transition(Transition(S_CONNECTED, S_CONNECTED)); state_.add_transition(Transition(S_CONNECTED, S_JOINING)); // the following is possible only when bootstrapping new cluster // (trivial wsrep_cluster_address) state_.add_transition(Transition(S_CONNECTED, S_JOINED)); // the following are possible on PC remerge state_.add_transition(Transition(S_CONNECTED, S_DONOR)); state_.add_transition(Transition(S_CONNECTED, S_SYNCED)); state_.add_transition(Transition(S_JOINING, S_CLOSING)); // the following is possible if one non-prim conf follows another state_.add_transition(Transition(S_JOINING, S_CONNECTED)); state_.add_transition(Transition(S_JOINING, S_JOINED)); state_.add_transition(Transition(S_JOINED, S_CLOSING)); state_.add_transition(Transition(S_JOINED, S_CONNECTED)); state_.add_transition(Transition(S_JOINED, S_SYNCED)); state_.add_transition(Transition(S_SYNCED, S_CLOSING)); state_.add_transition(Transition(S_SYNCED, S_CONNECTED)); state_.add_transition(Transition(S_SYNCED, S_DONOR)); state_.add_transition(Transition(S_DONOR, S_CLOSING)); state_.add_transition(Transition(S_DONOR, S_CONNECTED)); state_.add_transition(Transition(S_DONOR, S_JOINED)); local_monitor_.set_initial_position(0); wsrep_uuid_t uuid; wsrep_seqno_t seqno; st_.get (uuid, seqno); if (0 != args->state_id && args->state_id->uuid != WSREP_UUID_UNDEFINED && args->state_id->uuid == uuid && seqno == WSREP_SEQNO_UNDEFINED) { /* non-trivial recovery information provided on startup, and db is safe * so use recovered seqno value */ seqno = args->state_id->seqno; } log_debug << "End state: " << uuid << ':' << seqno << " #################"; update_state_uuid (uuid); cc_seqno_ = seqno; // is it needed here? apply_monitor_.set_initial_position(seqno); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.set_initial_position(seqno); cert_.assign_initial_position(seqno, trx_proto_ver()); build_stats_vars(wsrep_stats_); } galera::ReplicatorSMM::~ReplicatorSMM() { log_info << "dtor state: " << state_(); switch (state_()) { case S_CONNECTED: case S_JOINING: case S_JOINED: case S_SYNCED: case S_DONOR: close(); case S_CLOSING: // @todo wait that all users have left the building case S_CLOSED: ist_senders_.cancel(); break; case S_DESTROYED: break; } } wsrep_status_t galera::ReplicatorSMM::connect(const std::string& cluster_name, const std::string& cluster_url, const std::string& state_donor, bool const bootstrap) { sst_donor_ = state_donor; service_thd_.reset(); ssize_t err; wsrep_status_t ret(WSREP_OK); wsrep_seqno_t const seqno(cert_.position()); wsrep_uuid_t const gcs_uuid(seqno < 0 ? WSREP_UUID_UNDEFINED :state_uuid_); log_info << "Setting initial position to " << gcs_uuid << ':' << seqno; if ((err = gcs_.set_initial_position(gcs_uuid, seqno)) != 0) { log_error << "gcs init failed:" << strerror(-err); ret = WSREP_NODE_FAIL; } gcache_.reset(); if (ret == WSREP_OK && (err = gcs_.connect(cluster_name, cluster_url, bootstrap)) != 0) { log_error << "gcs connect failed: " << strerror(-err); ret = WSREP_NODE_FAIL; } if (ret == WSREP_OK) { state_.shift_to(S_CONNECTED); } return ret; } wsrep_status_t galera::ReplicatorSMM::close() { if (state_() != S_CLOSED) { gcs_.close(); } return WSREP_OK; } wsrep_status_t galera::ReplicatorSMM::async_recv(void* recv_ctx) { assert(recv_ctx != 0); if (state_() == S_CLOSED || state_() == S_CLOSING) { log_error <<"async recv cannot start, provider in closed/closing state"; return WSREP_FATAL; } ++receivers_; as_ = &gcs_as_; bool exit_loop(false); wsrep_status_t retval(WSREP_OK); while (WSREP_OK == retval && state_() != S_CLOSING) { ssize_t rc; while (gu_unlikely((rc = as_->process(recv_ctx, exit_loop)) == -ECANCELED)) { recv_IST(recv_ctx); // hack: prevent fast looping until ist controlling thread // resumes gcs prosessing usleep(10000); } if (gu_unlikely(rc <= 0)) { retval = WSREP_CONN_FAIL; } else if (gu_unlikely(exit_loop == true)) { assert(WSREP_OK == retval); if (receivers_.sub_and_fetch(1) > 0) { log_info << "Slave thread exiting on request."; break; } ++receivers_; log_warn << "Refusing exit for the last slave thread."; } } /* exiting loop already did proper checks */ if (!exit_loop && receivers_.sub_and_fetch(1) == 0) { if (state_() != S_CLOSING) { if (retval == WSREP_OK) { log_warn << "Broken shutdown sequence, provider state: " << state_() << ", retval: " << retval; assert (0); } else { // Generate zero view before exit to notify application wsrep_view_info_t* err_view(galera_view_info_create(0, false)); void* fake_sst_req(0); size_t fake_sst_req_len(0); view_cb_(app_ctx_, recv_ctx, err_view, 0, 0, &fake_sst_req, &fake_sst_req_len); free(err_view); } /* avoid abort in production */ state_.shift_to(S_CLOSING); } state_.shift_to(S_CLOSED); } log_debug << "Slave thread exit. Return code: " << retval; return retval; } void galera::ReplicatorSMM::apply_trx(void* recv_ctx, TrxHandle* trx) { assert(trx != 0); assert(trx->global_seqno() > 0); assert(trx->is_certified() == true); assert(trx->global_seqno() > STATE_SEQNO()); assert(trx->is_local() == false); ApplyOrder ao(*trx); CommitOrder co(*trx, co_mode_); gu_trace(apply_monitor_.enter(ao)); trx->set_state(TrxHandle::S_APPLYING); wsrep_trx_meta_t meta = {{state_uuid_, trx->global_seqno() }, trx->depends_seqno()}; gu_trace(apply_trx_ws(recv_ctx, apply_cb_, commit_cb_, *trx, meta)); /* at this point any exception in apply_trx_ws() is fatal, not * catching anything. */ if (gu_likely(co_mode_ != CommitOrder::BYPASS)) { gu_trace(commit_monitor_.enter(co)); } trx->set_state(TrxHandle::S_COMMITTING); wsrep_bool_t exit_loop(false); wsrep_cb_status_t const rcode( commit_cb_( recv_ctx, TrxHandle::trx_flags_to_wsrep_flags(trx->flags()), &meta, &exit_loop, true)); if (gu_unlikely (rcode > 0)) gu_throw_fatal << "Commit failed. Trx: " << trx; if (gu_likely(co_mode_ != CommitOrder::BYPASS)) { commit_monitor_.leave(co); } trx->set_state(TrxHandle::S_COMMITTED); if (trx->local_seqno() != -1) { // trx with local seqno -1 originates from IST (or other source not gcs) report_last_committed(cert_.set_trx_committed(trx)); } /* For now need to keep it inside apply monitor to ensure all processing * ends by the time monitors are drained because of potential gcache * cleanup (and loss of the writeset buffer). Perhaps unordered monitor * is needed here. */ trx->unordered(recv_ctx, unordered_cb_); apply_monitor_.leave(ao); trx->set_exit_loop(exit_loop); } wsrep_status_t galera::ReplicatorSMM::replicate(TrxHandle* trx, wsrep_trx_meta_t* meta) { if (state_() < S_JOINED) return WSREP_TRX_FAIL; assert(trx->state() == TrxHandle::S_EXECUTING || trx->state() == TrxHandle::S_MUST_ABORT); assert(trx->local_seqno() == WSREP_SEQNO_UNDEFINED && trx->global_seqno() == WSREP_SEQNO_UNDEFINED); wsrep_status_t retval(WSREP_TRX_FAIL); if (trx->state() == TrxHandle::S_MUST_ABORT) { must_abort: trx->set_state(TrxHandle::S_ABORTING); return retval; } WriteSetNG::GatherVector actv; gcs_action act; act.type = GCS_ACT_TORDERED; #ifndef NDEBUG act.seqno_g = GCS_SEQNO_ILL; #endif if (trx->new_version()) { act.buf = NULL; act.size = trx->write_set_out().gather(trx->source_id(), trx->conn_id(), trx->trx_id(), actv); } else { trx->set_last_seen_seqno(last_committed()); assert (trx->last_seen_seqno() >= 0); trx->flush(0); const MappedBuffer& wscoll(trx->write_set_collection()); act.buf = &wscoll[0]; act.size = wscoll.size(); assert (act.buf != NULL); assert (act.size > 0); } trx->set_state(TrxHandle::S_REPLICATING); ssize_t rcode(-1); do { assert(act.seqno_g == GCS_SEQNO_ILL); const ssize_t gcs_handle(gcs_.schedule()); if (gu_unlikely(gcs_handle < 0)) { log_debug << "gcs schedule " << strerror(-gcs_handle); trx->set_state(TrxHandle::S_MUST_ABORT); goto must_abort; } trx->set_gcs_handle(gcs_handle); if (trx->new_version()) { trx->set_last_seen_seqno(last_committed()); assert(trx->last_seen_seqno() >= 0); trx->unlock(); assert (act.buf == NULL); // just a sanity check rcode = gcs_.replv(actv, act, true); } else { assert(trx->last_seen_seqno() >= 0); trx->unlock(); assert (act.buf != NULL); rcode = gcs_.repl(act, true); } trx->lock(); } while (rcode == -EAGAIN && trx->state() != TrxHandle::S_MUST_ABORT && (usleep(1000), true)); assert(trx->last_seen_seqno() >= 0); if (rcode < 0) { if (rcode != -EINTR) { log_debug << "gcs_repl() failed with " << strerror(-rcode) << " for trx " << *trx; } assert(rcode != -EINTR || trx->state() == TrxHandle::S_MUST_ABORT); assert(act.seqno_l == GCS_SEQNO_ILL && act.seqno_g == GCS_SEQNO_ILL); assert(NULL == act.buf || !trx->new_version()); if (trx->state() != TrxHandle::S_MUST_ABORT) { trx->set_state(TrxHandle::S_MUST_ABORT); } trx->set_gcs_handle(-1); goto must_abort; } assert(act.buf != NULL); assert(act.size == rcode); assert(act.seqno_l != GCS_SEQNO_ILL); assert(act.seqno_g != GCS_SEQNO_ILL); ++replicated_; replicated_bytes_ += rcode; trx->set_gcs_handle(-1); if (trx->new_version()) { gu_trace(trx->unserialize(static_cast(act.buf), act.size, 0)); trx->update_stats(keys_count_, keys_bytes_, data_bytes_, unrd_bytes_); } trx->set_received(act.buf, act.seqno_l, act.seqno_g); if (trx->state() == TrxHandle::S_MUST_ABORT) { retval = cert_for_aborted(trx); if (retval != WSREP_BF_ABORT) { LocalOrder lo(*trx); ApplyOrder ao(*trx); CommitOrder co(*trx, co_mode_); local_monitor_.self_cancel(lo); apply_monitor_.self_cancel(ao); if (co_mode_ !=CommitOrder::BYPASS) commit_monitor_.self_cancel(co); } else if (meta != 0) { meta->gtid.uuid = state_uuid_; meta->gtid.seqno = trx->global_seqno(); meta->depends_on = trx->depends_seqno(); } if (trx->state() == TrxHandle::S_MUST_ABORT) goto must_abort; } else { retval = WSREP_OK; } assert(trx->last_seen_seqno() >= 0); return retval; } void galera::ReplicatorSMM::abort_trx(TrxHandle* trx) { assert(trx != 0); assert(trx->is_local() == true); log_debug << "aborting trx " << *trx << " " << trx; switch (trx->state()) { case TrxHandle::S_MUST_ABORT: case TrxHandle::S_ABORTING: // guess this is here because we can have a race return; case TrxHandle::S_EXECUTING: trx->set_state(TrxHandle::S_MUST_ABORT); break; case TrxHandle::S_REPLICATING: { trx->set_state(TrxHandle::S_MUST_ABORT); // trx is in gcs repl int rc; if (trx->gcs_handle() > 0 && ((rc = gcs_.interrupt(trx->gcs_handle()))) != 0) { log_debug << "gcs_interrupt(): handle " << trx->gcs_handle() << " trx id " << trx->trx_id() << ": " << strerror(-rc); } break; } case TrxHandle::S_CERTIFYING: { trx->set_state(TrxHandle::S_MUST_ABORT); // trx is waiting in local monitor LocalOrder lo(*trx); trx->unlock(); local_monitor_.interrupt(lo); trx->lock(); break; } case TrxHandle::S_APPLYING: { trx->set_state(TrxHandle::S_MUST_ABORT); // trx is waiting in apply monitor ApplyOrder ao(*trx); trx->unlock(); apply_monitor_.interrupt(ao); trx->lock(); break; } case TrxHandle::S_COMMITTING: trx->set_state(TrxHandle::S_MUST_ABORT); if (co_mode_ != CommitOrder::BYPASS) { // trx waiting in commit monitor CommitOrder co(*trx, co_mode_); trx->unlock(); commit_monitor_.interrupt(co); trx->lock(); } break; default: gu_throw_fatal << "invalid state " << trx->state(); } } wsrep_status_t galera::ReplicatorSMM::pre_commit(TrxHandle* trx, wsrep_trx_meta_t* meta) { assert(trx->state() == TrxHandle::S_REPLICATING); assert(trx->local_seqno() > -1); assert(trx->global_seqno() > -1); assert(trx->last_seen_seqno() >= 0); if (meta != 0) { meta->gtid.uuid = state_uuid_; meta->gtid.seqno = trx->global_seqno(); meta->depends_on = trx->depends_seqno(); } // State should not be checked here: If trx has been replicated, // it has to be certified and potentially applied. #528 // if (state_() < S_JOINED) return WSREP_TRX_FAIL; wsrep_status_t retval(cert_and_catch(trx)); if (gu_unlikely(retval != WSREP_OK)) { assert(trx->state() == TrxHandle::S_MUST_ABORT || trx->state() == TrxHandle::S_MUST_REPLAY_AM || trx->state() == TrxHandle::S_MUST_CERT_AND_REPLAY); if (trx->state() == TrxHandle::S_MUST_ABORT) { trx->set_state(TrxHandle::S_ABORTING); } return retval; } assert(trx->state() == TrxHandle::S_CERTIFYING); assert(trx->global_seqno() > STATE_SEQNO()); trx->set_state(TrxHandle::S_APPLYING); ApplyOrder ao(*trx); CommitOrder co(*trx, co_mode_); bool interrupted(false); try { gu_trace(apply_monitor_.enter(ao)); } catch (gu::Exception& e) { if (e.get_errno() == EINTR) { interrupted = true; } else throw; } if (gu_unlikely(interrupted) || trx->state() == TrxHandle::S_MUST_ABORT) { assert(trx->state() == TrxHandle::S_MUST_ABORT); if (interrupted) trx->set_state(TrxHandle::S_MUST_REPLAY_AM); else trx->set_state(TrxHandle::S_MUST_REPLAY_CM); retval = WSREP_BF_ABORT; } else if ((trx->flags() & TrxHandle::F_COMMIT) != 0) { trx->set_state(TrxHandle::S_COMMITTING); if (co_mode_ != CommitOrder::BYPASS) { try { gu_trace(commit_monitor_.enter(co)); } catch (gu::Exception& e) { if (e.get_errno() == EINTR) { interrupted = true; } else throw; } if (gu_unlikely(interrupted) || trx->state() == TrxHandle::S_MUST_ABORT) { assert(trx->state() == TrxHandle::S_MUST_ABORT); if (interrupted) trx->set_state(TrxHandle::S_MUST_REPLAY_CM); else trx->set_state(TrxHandle::S_MUST_REPLAY); retval = WSREP_BF_ABORT; } } } else { trx->set_state(TrxHandle::S_EXECUTING); } assert((retval == WSREP_OK && (trx->state() == TrxHandle::S_COMMITTING || trx->state() == TrxHandle::S_EXECUTING)) || (retval == WSREP_TRX_FAIL && trx->state() == TrxHandle::S_ABORTING) || (retval == WSREP_BF_ABORT && ( trx->state() == TrxHandle::S_MUST_REPLAY_AM || trx->state() == TrxHandle::S_MUST_REPLAY_CM || trx->state() == TrxHandle::S_MUST_REPLAY))); return retval; } wsrep_status_t galera::ReplicatorSMM::replay_trx(TrxHandle* trx, void* trx_ctx) { assert(trx->state() == TrxHandle::S_MUST_CERT_AND_REPLAY || trx->state() == TrxHandle::S_MUST_REPLAY_AM || trx->state() == TrxHandle::S_MUST_REPLAY_CM || trx->state() == TrxHandle::S_MUST_REPLAY); assert(trx->trx_id() != static_cast(-1)); assert(trx->global_seqno() > STATE_SEQNO()); wsrep_status_t retval(WSREP_OK); switch (trx->state()) { case TrxHandle::S_MUST_CERT_AND_REPLAY: retval = cert_and_catch(trx); if (retval != WSREP_OK) { // apply monitor is self canceled in cert break; } trx->set_state(TrxHandle::S_MUST_REPLAY_AM); // fall through case TrxHandle::S_MUST_REPLAY_AM: { // safety measure to make sure that all preceding trxs finish before // replaying trx->set_depends_seqno(trx->global_seqno() - 1); ApplyOrder ao(*trx); gu_trace(apply_monitor_.enter(ao)); trx->set_state(TrxHandle::S_MUST_REPLAY_CM); // fall through } case TrxHandle::S_MUST_REPLAY_CM: if (co_mode_ != CommitOrder::BYPASS) { CommitOrder co(*trx, co_mode_); gu_trace(commit_monitor_.enter(co)); } trx->set_state(TrxHandle::S_MUST_REPLAY); // fall through case TrxHandle::S_MUST_REPLAY: ++local_replays_; trx->set_state(TrxHandle::S_REPLAYING); try { wsrep_trx_meta_t meta = {{state_uuid_, trx->global_seqno() }, trx->depends_seqno()}; gu_trace(apply_trx_ws(trx_ctx, apply_cb_, commit_cb_, *trx, meta)); wsrep_bool_t unused(false); wsrep_cb_status_t rcode( commit_cb_( trx_ctx, TrxHandle::trx_flags_to_wsrep_flags(trx->flags()), &meta, &unused, true)); if (gu_unlikely(rcode > 0)) gu_throw_fatal << "Commit failed. Trx: " << trx; } catch (gu::Exception& e) { st_.mark_corrupt(); throw; } // apply, commit monitors are released in post commit return WSREP_OK; default: gu_throw_fatal << "Invalid state in replay for trx " << *trx; } log_debug << "replaying failed for trx " << *trx; trx->set_state(TrxHandle::S_ABORTING); return retval; } wsrep_status_t galera::ReplicatorSMM::post_commit(TrxHandle* trx) { if (trx->state() == TrxHandle::S_MUST_ABORT) { // This is possible in case of ALG: BF applier BF aborts // trx that has already grabbed commit monitor and is committing. // However, this should be acceptable assuming that commit // operation does not reserve any more resources and is able // to release already reserved resources. log_debug << "trx was BF aborted during commit: " << *trx; // manipulate state to avoid crash trx->set_state(TrxHandle::S_MUST_REPLAY); trx->set_state(TrxHandle::S_REPLAYING); } assert(trx->state() == TrxHandle::S_COMMITTING || trx->state() == TrxHandle::S_REPLAYING); assert(trx->local_seqno() > -1 && trx->global_seqno() > -1); CommitOrder co(*trx, co_mode_); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.leave(co); ApplyOrder ao(*trx); report_last_committed(cert_.set_trx_committed(trx)); apply_monitor_.leave(ao); trx->set_state(TrxHandle::S_COMMITTED); ++local_commits_; return WSREP_OK; } wsrep_status_t galera::ReplicatorSMM::post_rollback(TrxHandle* trx) { if (trx->state() == TrxHandle::S_MUST_ABORT) { trx->set_state(TrxHandle::S_ABORTING); } assert(trx->state() == TrxHandle::S_ABORTING || trx->state() == TrxHandle::S_EXECUTING); trx->set_state(TrxHandle::S_ROLLED_BACK); // Trx was either rolled back by user or via certification failure, // last committed report not needed since cert index state didn't change. // report_last_committed(); ++local_rollbacks_; return WSREP_OK; } wsrep_status_t galera::ReplicatorSMM::causal_read(wsrep_gtid_t* gtid) { wsrep_seqno_t cseq(static_cast(gcs_.caused())); if (cseq < 0) { log_warn << "gcs_caused() returned " << cseq << " (" << strerror(-cseq) << ')'; return WSREP_TRX_FAIL; } try { // @note: Using timed wait for monitor is currently a hack // to avoid deadlock resulting from race between monitor wait // and drain during configuration change. Instead of this, // monitor should have proper mechanism to interrupt waiters // at monitor drain and disallowing further waits until // configuration change related operations (SST etc) have been // finished. gu::datetime::Date wait_until(gu::datetime::Date::calendar() + causal_read_timeout_); if (gu_likely(co_mode_ != CommitOrder::BYPASS)) { commit_monitor_.wait(cseq, wait_until); } else { apply_monitor_.wait(cseq, wait_until); } if (gtid != 0) { gtid->uuid = state_uuid_; gtid->seqno = cseq; } ++causal_reads_; return WSREP_OK; } catch (gu::Exception& e) { log_debug << "monitor wait failed for causal read: " << e.what(); return WSREP_TRX_FAIL; } } wsrep_status_t galera::ReplicatorSMM::to_isolation_begin(TrxHandle* trx, wsrep_trx_meta_t* meta) { if (meta != 0) { meta->gtid.uuid = state_uuid_; meta->gtid.seqno = trx->global_seqno(); meta->depends_on = trx->depends_seqno(); } assert(trx->state() == TrxHandle::S_REPLICATING); assert(trx->trx_id() == static_cast(-1)); assert(trx->local_seqno() > -1 && trx->global_seqno() > -1); assert(trx->global_seqno() > STATE_SEQNO()); wsrep_status_t retval; switch ((retval = cert_and_catch(trx))) { case WSREP_OK: { ApplyOrder ao(*trx); CommitOrder co(*trx, co_mode_); gu_trace(apply_monitor_.enter(ao)); if (co_mode_ != CommitOrder::BYPASS) try { commit_monitor_.enter(co); } catch (...) { gu_throw_fatal << "unable to enter commit monitor: " << *trx; } trx->set_state(TrxHandle::S_APPLYING); log_debug << "Executing TO isolated action: " << *trx; st_.mark_unsafe(); break; } case WSREP_TRX_FAIL: // Apply monitor is released in cert() in case of failure. trx->set_state(TrxHandle::S_ABORTING); break; default: log_error << "unrecognized retval " << retval << " for to isolation certification for " << *trx; retval = WSREP_FATAL; break; } return retval; } wsrep_status_t galera::ReplicatorSMM::to_isolation_end(TrxHandle* trx) { assert(trx->state() == TrxHandle::S_APPLYING); log_debug << "Done executing TO isolated action: " << *trx; CommitOrder co(*trx, co_mode_); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.leave(co); ApplyOrder ao(*trx); report_last_committed(cert_.set_trx_committed(trx)); apply_monitor_.leave(ao); st_.mark_safe(); return WSREP_OK; } namespace galera { static WriteSetOut* writeset_from_handle (wsrep_po_handle_t& handle, const TrxHandle::Params& trx_params) { WriteSetOut* ret = reinterpret_cast(handle.opaque); if (NULL == ret) { try { ret = new WriteSetOut( // gu::String<256>(trx_params.working_dir_) << '/' << &handle, trx_params.working_dir_, wsrep_trx_id_t(&handle), /* key format is not essential since we're not adding keys */ KeySet::version(trx_params.key_format_), NULL, 0, 0, WriteSetNG::MAX_VERSION, DataSet::MAX_VERSION, DataSet::MAX_VERSION, trx_params.max_write_set_size_); handle.opaque = ret; } catch (std::bad_alloc& ba) { gu_throw_error(ENOMEM) << "Could not create WriteSetOut"; } } return ret; } } /* namespace galera */ wsrep_status_t galera::ReplicatorSMM::preordered_collect(wsrep_po_handle_t& handle, const struct wsrep_buf* const data, size_t const count, bool const copy) { if (gu_unlikely(trx_params_.version_ < WS_NG_VERSION)) return WSREP_NOT_IMPLEMENTED; WriteSetOut* const ws(writeset_from_handle(handle, trx_params_)); for (size_t i(0); i < count; ++i) { ws->append_data(data[i].ptr, data[i].len, copy); } return WSREP_OK; } wsrep_status_t galera::ReplicatorSMM::preordered_commit(wsrep_po_handle_t& handle, const wsrep_uuid_t& source, uint64_t const flags, int const pa_range, bool const commit) { if (gu_unlikely(trx_params_.version_ < WS_NG_VERSION)) return WSREP_NOT_IMPLEMENTED; WriteSetOut* const ws(writeset_from_handle(handle, trx_params_)); if (gu_likely(true == commit)) { ws->set_flags (WriteSetNG::wsrep_flags_to_ws_flags(flags)); /* by loooking at trx_id we should be able to detect gaps / lost events * (however resending is not implemented yet). Something like * * wsrep_trx_id_t const trx_id(cert_.append_preordered(source, ws)); * * begs to be here. */ wsrep_trx_id_t const trx_id(preordered_id_.add_and_fetch(1)); WriteSetNG::GatherVector actv; size_t const actv_size(ws->gather(source, 0, trx_id, actv)); ws->set_preordered (pa_range); // also adds CRC int rcode; do { rcode = gcs_.sendv(actv, actv_size, GCS_ACT_TORDERED, false); } while (rcode == -EAGAIN && (usleep(1000), true)); if (rcode < 0) gu_throw_error(-rcode) << "Replication of preordered writeset failed."; } delete ws; handle.opaque = NULL; return WSREP_OK; } wsrep_status_t galera::ReplicatorSMM::sst_sent(const wsrep_gtid_t& state_id, int const rcode) { assert (rcode <= 0); assert (rcode == 0 || state_id.seqno == WSREP_SEQNO_UNDEFINED); assert (rcode != 0 || state_id.seqno >= 0); if (state_() != S_DONOR) { log_error << "sst sent called when not SST donor, state " << state_(); return WSREP_CONN_FAIL; } gcs_seqno_t seqno(rcode ? rcode : state_id.seqno); if (state_id.uuid != state_uuid_ && seqno >= 0) { // state we have sent no longer corresponds to the current group state // mark an error seqno = -EREMCHG; } try { gcs_.join(seqno); return WSREP_OK; } catch (gu::Exception& e) { log_error << "failed to recover from DONOR state: " << e.what(); return WSREP_CONN_FAIL; } } void galera::ReplicatorSMM::process_trx(void* recv_ctx, TrxHandle* trx) { assert(recv_ctx != 0); assert(trx != 0); assert(trx->local_seqno() > 0); assert(trx->global_seqno() > 0); assert(trx->last_seen_seqno() >= 0); assert(trx->depends_seqno() == -1); assert(trx->state() == TrxHandle::S_REPLICATING); wsrep_status_t const retval(cert_and_catch(trx)); switch (retval) { case WSREP_OK: try { gu_trace(apply_trx(recv_ctx, trx)); } catch (std::exception& e) { st_.mark_corrupt(); log_fatal << "Failed to apply trx: " << *trx; log_fatal << e.what(); log_fatal << "Node consistency compromized, aborting..."; abort(); } break; case WSREP_TRX_FAIL: // certification failed, apply monitor has been canceled trx->set_state(TrxHandle::S_ABORTING); trx->set_state(TrxHandle::S_ROLLED_BACK); break; default: // this should not happen for remote actions gu_throw_error(EINVAL) << "unrecognized retval for remote trx certification: " << retval << " trx: " << *trx; } } void galera::ReplicatorSMM::process_commit_cut(wsrep_seqno_t seq, wsrep_seqno_t seqno_l) { assert(seq > 0); assert(seqno_l > 0); LocalOrder lo(seqno_l); gu_trace(local_monitor_.enter(lo)); if (seq >= cc_seqno_) /* Refs #782. workaround for * assert(seqno >= seqno_released_) in gcache. */ cert_.purge_trxs_upto(seq, true); local_monitor_.leave(lo); log_debug << "Got commit cut from GCS: " << seq; } void galera::ReplicatorSMM::establish_protocol_versions (int proto_ver) { switch (proto_ver) { case 1: trx_params_.version_ = 1; str_proto_ver_ = 0; break; case 2: trx_params_.version_ = 1; str_proto_ver_ = 1; break; case 3: case 4: trx_params_.version_ = 2; str_proto_ver_ = 1; break; case 5: trx_params_.version_ = 3; str_proto_ver_ = 1; break; case 6: trx_params_.version_ = 3; str_proto_ver_ = 2; // gcs intelligent donor selection. // include handling dangling comma in donor string. break; default: log_fatal << "Configuration change resulted in an unsupported protocol " "version: " << proto_ver << ". Can't continue."; abort(); }; protocol_version_ = proto_ver; log_info << "REPL Protocols: " << protocol_version_ << " (" << trx_params_.version_ << ", " << str_proto_ver_ << ")"; } static bool app_wants_state_transfer (const void* const req, ssize_t const req_len) { return (req_len != (strlen(WSREP_STATE_TRANSFER_NONE) + 1) || memcmp(req, WSREP_STATE_TRANSFER_NONE, req_len)); } void galera::ReplicatorSMM::update_incoming_list(const wsrep_view_info_t& view) { static char const separator(','); ssize_t new_size(0); if (view.memb_num > 0) { new_size += view.memb_num - 1; // separators for (int i = 0; i < view.memb_num; ++i) { new_size += strlen(view.members[i].incoming); } } gu::Lock lock(incoming_mutex_); incoming_list_.clear(); incoming_list_.resize(new_size); if (new_size <= 0) return; incoming_list_ = view.members[0].incoming; for (int i = 1; i < view.memb_num; ++i) { incoming_list_ += separator; incoming_list_ += view.members[i].incoming; } } void galera::ReplicatorSMM::process_conf_change(void* recv_ctx, const wsrep_view_info_t& view_info, int repl_proto, State next_state, wsrep_seqno_t seqno_l) { assert(seqno_l > -1); update_incoming_list(view_info); LocalOrder lo(seqno_l); gu_trace(local_monitor_.enter(lo)); wsrep_seqno_t const upto(cert_.position()); apply_monitor_.drain(upto); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.drain(upto); if (view_info.my_idx >= 0) { uuid_ = view_info.members[view_info.my_idx].id; } bool const st_required(state_transfer_required(view_info)); wsrep_seqno_t const group_seqno(view_info.state_id.seqno); const wsrep_uuid_t& group_uuid (view_info.state_id.uuid); if (st_required) { log_info << "State transfer required: " << "\n\tGroup state: " << group_uuid << ":" << group_seqno << "\n\tLocal state: " << state_uuid_<< ":" << STATE_SEQNO(); if (S_CONNECTED != state_()) state_.shift_to(S_CONNECTED); } void* app_req(0); size_t app_req_len(0); const_cast(view_info).state_gap = st_required; wsrep_cb_status_t const rcode( view_cb_(app_ctx_, recv_ctx, &view_info, 0, 0, &app_req, &app_req_len)); if (WSREP_CB_SUCCESS != rcode) { assert(app_req_len <= 0); close(); gu_throw_fatal << "View callback failed. This is unrecoverable, " "restart required."; } else if (st_required && 0 == app_req_len && state_uuid_ != group_uuid) { close(); gu_throw_fatal << "Local state UUID " << state_uuid_ << " is different from group state UUID " << group_uuid << ", and SST request is null: restart required."; } if (view_info.view >= 0) // Primary configuration { establish_protocol_versions (repl_proto); // we have to reset cert initial position here, SST does not contain // cert index yet (see #197). cert_.assign_initial_position(group_seqno, trx_params_.version_); // at this point there is no ongoing master or slave transactions // and no new requests to service thread should be possible service_thd_.flush(); // make sure service thd is idle if (STATE_SEQNO() > 0) gcache_.seqno_release(STATE_SEQNO()); // make sure all gcache buffers are released // record state seqno, needed for IST on DONOR cc_seqno_ = group_seqno; bool const app_wants_st(app_wants_state_transfer(app_req, app_req_len)); if (st_required && app_wants_st) { // GCache::Seqno_reset() happens here request_state_transfer (recv_ctx, group_uuid, group_seqno, app_req, app_req_len); } else { if (view_info.view == 1 || !app_wants_st) { update_state_uuid (group_uuid); apply_monitor_.set_initial_position(group_seqno); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.set_initial_position(group_seqno); } if (state_() == S_CONNECTED || state_() == S_DONOR) { switch (next_state) { case S_JOINING: state_.shift_to(S_JOINING); break; case S_DONOR: if (state_() == S_CONNECTED) { state_.shift_to(S_DONOR); } break; case S_JOINED: state_.shift_to(S_JOINED); break; case S_SYNCED: state_.shift_to(S_SYNCED); synced_cb_(app_ctx_); break; default: log_debug << "next_state " << next_state; break; } } st_.set(state_uuid_, WSREP_SEQNO_UNDEFINED); } if (state_() == S_JOINING && sst_state_ != SST_NONE) { /* There are two reasons we can be here: * 1) we just got state transfer in request_state_transfer() above; * 2) we failed here previously (probably due to partition). */ try { gcs_.join(sst_seqno_); sst_state_ = SST_NONE; } catch (gu::Exception& e) { log_error << "Failed to JOIN the cluster after SST"; } } } else { // Non-primary configuration if (state_uuid_ != WSREP_UUID_UNDEFINED) { st_.set (state_uuid_, STATE_SEQNO()); } if (next_state != S_CONNECTED && next_state != S_CLOSING) { log_fatal << "Internal error: unexpected next state for " << "non-prim: " << next_state << ". Restart required."; abort(); } state_.shift_to(next_state); } local_monitor_.leave(lo); gcs_.resume_recv(); free(app_req); } void galera::ReplicatorSMM::process_join(wsrep_seqno_t seqno_j, wsrep_seqno_t seqno_l) { LocalOrder lo(seqno_l); gu_trace(local_monitor_.enter(lo)); wsrep_seqno_t const upto(cert_.position()); apply_monitor_.drain(upto); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.drain(upto); if (seqno_j < 0 && S_JOINING == state_()) { // #595, @todo: find a way to re-request state transfer log_fatal << "Failed to receive state transfer: " << seqno_j << " (" << strerror (-seqno_j) << "), need to restart."; abort(); } else { state_.shift_to(S_JOINED); } local_monitor_.leave(lo); } void galera::ReplicatorSMM::process_sync(wsrep_seqno_t seqno_l) { LocalOrder lo(seqno_l); gu_trace(local_monitor_.enter(lo)); wsrep_seqno_t const upto(cert_.position()); apply_monitor_.drain(upto); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.drain(upto); state_.shift_to(S_SYNCED); synced_cb_(app_ctx_); local_monitor_.leave(lo); } wsrep_seqno_t galera::ReplicatorSMM::pause() { // Grab local seqno for local_monitor_ wsrep_seqno_t const local_seqno( static_cast(gcs_.local_sequence())); LocalOrder lo(local_seqno); local_monitor_.enter(lo); // Local monitor should take care that concurrent // pause requests are enqueued assert(pause_seqno_ == WSREP_SEQNO_UNDEFINED); pause_seqno_ = local_seqno; // Get drain seqno from cert index wsrep_seqno_t const upto(cert_.position()); apply_monitor_.drain(upto); assert (apply_monitor_.last_left() >= upto); if (co_mode_ != CommitOrder::BYPASS) { commit_monitor_.drain(upto); assert (commit_monitor_.last_left() >= upto); assert (commit_monitor_.last_left() == apply_monitor_.last_left()); } wsrep_seqno_t const ret(STATE_SEQNO()); st_.set(state_uuid_, ret); log_info << "Provider paused at " << state_uuid_ << ':' << ret << " (" << pause_seqno_ << ")"; return ret; } void galera::ReplicatorSMM::resume() { assert(pause_seqno_ != WSREP_SEQNO_UNDEFINED); if (pause_seqno_ == WSREP_SEQNO_UNDEFINED) { gu_throw_error(EALREADY) << "tried to resume unpaused provider"; } st_.set(state_uuid_, WSREP_SEQNO_UNDEFINED); log_info << "resuming provider at " << pause_seqno_; LocalOrder lo(pause_seqno_); pause_seqno_ = WSREP_SEQNO_UNDEFINED; local_monitor_.leave(lo); log_info << "Provider resumed."; } void galera::ReplicatorSMM::desync() { wsrep_seqno_t seqno_l; ssize_t const ret(gcs_.desync(&seqno_l)); if (seqno_l > 0) { LocalOrder lo(seqno_l); // need to process it regardless of ret value if (ret == 0) { /* #706 - the check below must be state request-specific. We are not holding any locks here and must be able to wait like any other action. However practice may prove different, leaving it here as a reminder. if (local_monitor_.would_block(seqno_l)) { gu_throw_error (-EDEADLK) << "Ran out of resources waiting to " << "desync the node. " << "The node must be restarted."; } */ local_monitor_.enter(lo); state_.shift_to(S_DONOR); local_monitor_.leave(lo); } else { local_monitor_.self_cancel(lo); } } if (ret) { gu_throw_error (-ret) << "Node desync failed."; } } void galera::ReplicatorSMM::resync() { gcs_.join(commit_monitor_.last_left()); } ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// //// Private ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /* don't use this directly, use cert_and_catch() instead */ inline wsrep_status_t galera::ReplicatorSMM::cert(TrxHandle* trx) { assert(trx->state() == TrxHandle::S_REPLICATING || trx->state() == TrxHandle::S_MUST_CERT_AND_REPLAY); assert(trx->local_seqno() != WSREP_SEQNO_UNDEFINED); assert(trx->global_seqno() != WSREP_SEQNO_UNDEFINED); assert(trx->last_seen_seqno() >= 0); assert(trx->last_seen_seqno() < trx->global_seqno()); trx->set_state(TrxHandle::S_CERTIFYING); LocalOrder lo(*trx); ApplyOrder ao(*trx); CommitOrder co(*trx, co_mode_); bool interrupted(false); try { gu_trace(local_monitor_.enter(lo)); } catch (gu::Exception& e) { if (e.get_errno() == EINTR) { interrupted = true; } else throw; } wsrep_status_t retval(WSREP_OK); bool const applicable(trx->global_seqno() > STATE_SEQNO()); if (gu_likely (!interrupted)) { switch (cert_.append_trx(trx)) { case Certification::TEST_OK: if (gu_likely(applicable)) { if (trx->state() == TrxHandle::S_CERTIFYING) { retval = WSREP_OK; } else { assert(trx->state() == TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_REPLAY_AM); retval = WSREP_BF_ABORT; } } else { // this can happen after SST position has been submitted // but not all actions preceding SST initial position // have been processed trx->set_state(TrxHandle::S_MUST_ABORT); retval = WSREP_TRX_FAIL; } break; case Certification::TEST_FAILED: if (gu_unlikely(trx->is_toi() && applicable)) // small sanity check { // may happen on configuration change log_warn << "Certification failed for TO isolated action: " << *trx; assert(0); } local_cert_failures_ += trx->is_local(); trx->set_state(TrxHandle::S_MUST_ABORT); retval = WSREP_TRX_FAIL; break; } if (gu_unlikely(WSREP_TRX_FAIL == retval)) { report_last_committed(cert_.set_trx_committed(trx)); } // at this point we are about to leave local_monitor_. Make sure // trx checksum was alright before that. trx->verify_checksum(); // we must do it 'in order' for std::map reasons, so keeping // it inside the monitor gcache_.seqno_assign (trx->action(), trx->global_seqno(), trx->depends_seqno()); local_monitor_.leave(lo); } else { retval = cert_for_aborted(trx); if (WSREP_TRX_FAIL == retval) { local_monitor_.self_cancel(lo); } else { assert(WSREP_BF_ABORT == retval); } } if (gu_unlikely(WSREP_TRX_FAIL == retval && applicable)) { // applicable but failed certification: self-cancel monitors apply_monitor_.self_cancel(ao); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.self_cancel(co); } return retval; } /* pretty much any exception in cert() is fatal as it blocks local_monitor_ */ wsrep_status_t galera::ReplicatorSMM::cert_and_catch(TrxHandle* trx) { try { return cert(trx); } catch (std::exception& e) { log_fatal << "Certification exception: " << e.what(); } catch (...) { log_fatal << "Unknown certification exception"; } abort(); } /* This must be called BEFORE local_monitor_.self_cancel() due to * gcache_.seqno_assign() */ wsrep_status_t galera::ReplicatorSMM::cert_for_aborted(TrxHandle* trx) { Certification::TestResult const res(cert_.test(trx, false)); switch (res) { case Certification::TEST_OK: trx->set_state(TrxHandle::S_MUST_CERT_AND_REPLAY); return WSREP_BF_ABORT; case Certification::TEST_FAILED: if (trx->state() != TrxHandle::S_MUST_ABORT) { trx->set_state(TrxHandle::S_MUST_ABORT); } // Mext step will be monitors release. Make sure that ws was not // corrupted and cert failure is real before procedeing with that. trx->verify_checksum(); gcache_.seqno_assign (trx->action(), trx->global_seqno(), -1); return WSREP_TRX_FAIL; default: log_fatal << "Unexpected return value from Certification::test(): " << res; abort(); } } void galera::ReplicatorSMM::update_state_uuid (const wsrep_uuid_t& uuid) { if (state_uuid_ != uuid) { *(const_cast(&state_uuid_)) = uuid; std::ostringstream os; os << state_uuid_; strncpy(const_cast(state_uuid_str_), os.str().c_str(), sizeof(state_uuid_str_)); } st_.set(uuid, WSREP_SEQNO_UNDEFINED); } void galera::ReplicatorSMM::abort() { gcs_.close(); gu_abort(); } percona-galera-3-3.8-3390/galera/src/replicator_smm.hpp000066400000000000000000000420011244131713600225520ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // //! @file replicator_smm.hpp // // @brief Galera Synchronous Multi-Master replicator // #ifndef GALERA_REPLICATOR_SMM_HPP #define GALERA_REPLICATOR_SMM_HPP #include "replicator.hpp" #include "gu_init.h" #include "GCache.hpp" #include "gcs.hpp" #include "monitor.hpp" #include "wsdb.hpp" #include "certification.hpp" #include "trx_handle.hpp" #include "write_set.hpp" #include "galera_service_thd.hpp" #include "fsm.hpp" #include "gcs_action_source.hpp" #include "ist.hpp" #include "gu_atomic.hpp" #include "saved_state.hpp" #include namespace galera { class ReplicatorSMM : public Replicator { public: typedef enum { SST_NONE, SST_WAIT, SST_REQ_FAILED, SST_FAILED } SstState; static const size_t N_STATES = S_DONOR + 1; ReplicatorSMM(const wsrep_init_args* args); ~ReplicatorSMM(); int trx_proto_ver() const { return trx_params_.version_; } int repl_proto_ver() const{ return protocol_version_; } wsrep_status_t connect(const std::string& cluster_name, const std::string& cluster_url, const std::string& state_donor, bool bootstrap); wsrep_status_t close(); wsrep_status_t async_recv(void* recv_ctx); TrxHandle* get_local_trx(wsrep_trx_id_t trx_id, bool create = false) { return wsdb_.get_trx(trx_params_, uuid_, trx_id, create); } void unref_local_trx(TrxHandle* trx) { assert(trx->refcnt() > 1); trx->unref(); } void discard_local_trx(TrxHandle* trx) { trx->release_write_set_out(); wsdb_.discard_trx(trx->trx_id()); } TrxHandle* local_conn_trx(wsrep_conn_id_t conn_id, bool create) { return wsdb_.get_conn_query(trx_params_, uuid_, conn_id, create); } void discard_local_conn_trx(wsrep_conn_id_t conn_id) { wsdb_.discard_conn_query(conn_id); } void discard_local_conn(wsrep_conn_id_t conn_id) { wsdb_.discard_conn(conn_id); } void apply_trx(void* recv_ctx, TrxHandle* trx); wsrep_status_t replicate(TrxHandle* trx, wsrep_trx_meta_t*); void abort_trx(TrxHandle* trx) ; wsrep_status_t pre_commit(TrxHandle* trx, wsrep_trx_meta_t*); wsrep_status_t replay_trx(TrxHandle* trx, void* replay_ctx); wsrep_status_t post_commit(TrxHandle* trx); wsrep_status_t post_rollback(TrxHandle* trx); wsrep_status_t causal_read(wsrep_gtid_t*); wsrep_status_t to_isolation_begin(TrxHandle* trx, wsrep_trx_meta_t*); wsrep_status_t to_isolation_end(TrxHandle* trx); wsrep_status_t preordered_collect(wsrep_po_handle_t& handle, const struct wsrep_buf* data, size_t count, bool copy); wsrep_status_t preordered_commit(wsrep_po_handle_t& handle, const wsrep_uuid_t& source, uint64_t flags, int pa_range, bool commit); wsrep_status_t sst_sent(const wsrep_gtid_t& state_id, int rcode); wsrep_status_t sst_received(const wsrep_gtid_t& state_id, const void* state, size_t state_len, int rcode); void process_trx(void* recv_ctx, TrxHandle* trx); void process_commit_cut(wsrep_seqno_t seq, wsrep_seqno_t seqno_l); void process_conf_change(void* recv_ctx, const wsrep_view_info_t& view, int repl_proto, State next_state, wsrep_seqno_t seqno_l); void process_state_req(void* recv_ctx, const void* req, size_t req_size, wsrep_seqno_t seqno_l, wsrep_seqno_t donor_seq); void process_join(wsrep_seqno_t seqno, wsrep_seqno_t seqno_l); void process_sync(wsrep_seqno_t seqno_l); const struct wsrep_stats_var* stats_get() const; void stats_reset(); void stats_free(struct wsrep_stats_var*); /*! @throws NotFound */ void set_param (const std::string& key, const std::string& value); /*! @throws NotFound */ void param_set (const std::string& key, const std::string& value); std::string param_get (const std::string& key) const; const gu::Config& params() const { return config_; } wsrep_seqno_t pause(); void resume(); void desync(); void resync(); struct InitConfig { InitConfig(gu::Config&, const char* node_address); }; private: ReplicatorSMM(const ReplicatorSMM&); void operator=(const ReplicatorSMM&); struct Param { static const std::string base_host; static const std::string base_port; static const std::string proto_max; static const std::string key_format; static const std::string commit_order; static const std::string causal_read_timeout; static const std::string max_write_set_size; }; typedef std::pair Default; struct Defaults { std::map map_; Defaults (); }; static const Defaults defaults; // both a list of parameters and a list of default values wsrep_seqno_t last_committed() { return co_mode_ != CommitOrder::BYPASS ? commit_monitor_.last_left() : apply_monitor_.last_left(); } void report_last_committed(wsrep_seqno_t purge_seqno) { if (gu_unlikely(purge_seqno != -1)) { service_thd_.report_last_committed(purge_seqno); } } wsrep_status_t cert(TrxHandle* trx); wsrep_status_t cert_and_catch(TrxHandle* trx); wsrep_status_t cert_for_aborted(TrxHandle* trx); void update_state_uuid (const wsrep_uuid_t& u); void update_incoming_list (const wsrep_view_info_t& v); /* aborts/exits the program in a clean way */ void abort() GU_NORETURN; class LocalOrder { public: LocalOrder(TrxHandle& trx) : seqno_(trx.local_seqno()), trx_(&trx) { } LocalOrder(wsrep_seqno_t seqno) : seqno_(seqno), trx_(0) { } void lock() { if (trx_ != 0) trx_->lock(); } void unlock() { if (trx_ != 0) trx_->unlock(); } wsrep_seqno_t seqno() const { return seqno_; } bool condition(wsrep_seqno_t last_entered, wsrep_seqno_t last_left) const { return (last_left + 1 == seqno_); } private: LocalOrder(const LocalOrder&); wsrep_seqno_t seqno_; TrxHandle* trx_; }; class ApplyOrder { public: ApplyOrder(TrxHandle& trx) : trx_(trx) { } void lock() { trx_.lock(); } void unlock() { trx_.unlock(); } wsrep_seqno_t seqno() const { return trx_.global_seqno(); } bool condition(wsrep_seqno_t last_entered, wsrep_seqno_t last_left) const { return (trx_.is_local() == true || last_left >= trx_.depends_seqno()); } private: ApplyOrder(const ApplyOrder&); TrxHandle& trx_; }; public: class CommitOrder { public: typedef enum { BYPASS = 0, OOOC = 1, LOCAL_OOOC = 2, NO_OOOC = 3 } Mode; static Mode from_string(const std::string& str) { int ret(gu::from_string(str)); switch (ret) { case BYPASS: case OOOC: case LOCAL_OOOC: case NO_OOOC: break; default: gu_throw_error(EINVAL) << "invalid value " << str << " for commit order mode"; } return static_cast(ret); } CommitOrder(TrxHandle& trx, Mode mode) : trx_ (trx ), mode_(mode) { } void lock() { trx_.lock(); } void unlock() { trx_.unlock(); } wsrep_seqno_t seqno() const { return trx_.global_seqno(); } bool condition(wsrep_seqno_t last_entered, wsrep_seqno_t last_left) const { switch (mode_) { case BYPASS: gu_throw_fatal << "commit order condition called in bypass mode"; case OOOC: return true; case LOCAL_OOOC: return trx_.is_local(); // in case of remote trx fall through case NO_OOOC: return (last_left + 1 == trx_.global_seqno()); } gu_throw_fatal << "invalid commit mode value " << mode_; } private: CommitOrder(const CommitOrder&); TrxHandle& trx_; const Mode mode_; }; class StateRequest { public: virtual const void* req () const = 0; virtual ssize_t len () const = 0; virtual const void* sst_req () const = 0; virtual ssize_t sst_len () const = 0; virtual const void* ist_req () const = 0; virtual ssize_t ist_len () const = 0; virtual ~StateRequest() {} }; private: // state machine class Transition { public: Transition(State const from, State const to) : from_(from), to_(to) { } State from() const { return from_; } State to() const { return to_; } bool operator==(Transition const& other) const { return (from_ == other.from_ && to_ == other.to_); } class Hash { public: size_t operator()(Transition const& tr) const { return (gu::HashValue(static_cast(tr.from_)) ^ gu::HashValue(static_cast(tr.to_))); } }; private: State from_; State to_; }; void build_stats_vars (std::vector& stats); void establish_protocol_versions (int version); bool state_transfer_required(const wsrep_view_info_t& view_info); void prepare_for_IST (void*& req, ssize_t& req_len, const wsrep_uuid_t& group_uuid, wsrep_seqno_t group_seqno); void recv_IST(void* recv_ctx); StateRequest* prepare_state_request (const void* sst_req, ssize_t sst_req_len, const wsrep_uuid_t& group_uuid, wsrep_seqno_t group_seqno); void send_state_request (const StateRequest* req); void request_state_transfer (void* recv_ctx, const wsrep_uuid_t& group_uuid, wsrep_seqno_t group_seqno, const void* sst_req, ssize_t sst_req_len); /* local state seqno for internal use (macro mock up) */ wsrep_seqno_t STATE_SEQNO(void) { return apply_monitor_.last_left(); } class InitLib /* Library initialization routines */ { public: InitLib (gu_log_cb_t cb) { gu_init(cb); } }; InitLib init_lib_; gu::Config config_; InitConfig init_config_; // registers configurable parameters and defaults struct ParseOptions { ParseOptions(gu::Config&, const char* opts); } parse_options_; // parse oprtion string supplied on initialization static int const MAX_PROTO_VER; /* * |------------------------------------------------------ * | protocol_version_ | trx version | str_proto_ver_ | * |------------------------------------------------------ * | 1 | 1 | 0 | * | 2 | 1 | 1 | * | 3 | 2 | 1 | * | 4 | 2 | 1 | * | 5 | 3 | 1 | * | 6 | 3 | 2 | * ------------------------------------------------------- */ int str_proto_ver_;// state transfer request protocol int protocol_version_;// general repl layer proto int proto_max_; // maximum allowed proto version FSM state_; SstState sst_state_; // configurable params const CommitOrder::Mode co_mode_; // commit order mode // persistent data location std::string data_dir_; std::string state_file_; SavedState st_; // currently installed trx parameters TrxHandle::Params trx_params_; // identifiers wsrep_uuid_t uuid_; wsrep_uuid_t const state_uuid_; const char state_uuid_str_[37]; wsrep_seqno_t cc_seqno_; // seqno of last CC wsrep_seqno_t pause_seqno_; // local seqno of last pause call // application callbacks void* app_ctx_; wsrep_view_cb_t view_cb_; wsrep_apply_cb_t apply_cb_; wsrep_commit_cb_t commit_cb_; wsrep_unordered_cb_t unordered_cb_; wsrep_sst_donate_cb_t sst_donate_cb_; wsrep_synced_cb_t synced_cb_; // SST std::string sst_donor_; wsrep_uuid_t sst_uuid_; wsrep_seqno_t sst_seqno_; gu::Mutex sst_mutex_; gu::Cond sst_cond_; int sst_retry_sec_; // services gcache::GCache gcache_; GCS_IMPL gcs_; ServiceThd service_thd_; // action sources TrxHandle::SlavePool slave_pool_; ActionSource* as_; GcsActionSource gcs_as_; ist::Receiver ist_receiver_; ist::AsyncSenderMap ist_senders_; // trx processing Wsdb wsdb_; Certification cert_; // concurrency control Monitor local_monitor_; Monitor apply_monitor_; Monitor commit_monitor_; gu::datetime::Period causal_read_timeout_; // counters gu::Atomic receivers_; gu::Atomic replicated_; gu::Atomic replicated_bytes_; gu::Atomic keys_count_; gu::Atomic keys_bytes_; gu::Atomic data_bytes_; gu::Atomic unrd_bytes_; gu::Atomic local_commits_; gu::Atomic local_rollbacks_; gu::Atomic local_cert_failures_; gu::Atomic local_replays_; gu::Atomic causal_reads_; gu::Atomic preordered_id_; // temporary preordered ID // non-atomic stats std::string incoming_list_; mutable gu::Mutex incoming_mutex_; mutable std::vector wsrep_stats_; }; std::ostream& operator<<(std::ostream& os, ReplicatorSMM::State state); } #endif /* GALERA_REPLICATOR_SMM_HPP */ percona-galera-3-3.8-3390/galera/src/replicator_smm_params.cpp000066400000000000000000000134201244131713600241130ustar00rootroot00000000000000/* Copyright (C) 2012-2014 Codership Oy */ #include "replicator_smm.hpp" #include "gcs.hpp" #include "galera_common.hpp" #include "gu_uri.hpp" #include "write_set_ng.hpp" #include "gu_throw.hpp" const std::string galera::ReplicatorSMM::Param::base_host = "base_host"; const std::string galera::ReplicatorSMM::Param::base_port = "base_port"; static const std::string common_prefix = "repl."; const std::string galera::ReplicatorSMM::Param::commit_order = common_prefix + "commit_order"; const std::string galera::ReplicatorSMM::Param::causal_read_timeout = common_prefix + "causal_read_timeout"; const std::string galera::ReplicatorSMM::Param::proto_max = common_prefix + "proto_max"; const std::string galera::ReplicatorSMM::Param::key_format = common_prefix + "key_format"; const std::string galera::ReplicatorSMM::Param::max_write_set_size = common_prefix + "max_ws_size"; int const galera::ReplicatorSMM::MAX_PROTO_VER(6); galera::ReplicatorSMM::Defaults::Defaults() : map_() { map_.insert(Default(Param::base_port, BASE_PORT_DEFAULT)); map_.insert(Default(Param::proto_max, gu::to_string(MAX_PROTO_VER))); map_.insert(Default(Param::key_format, "FLAT8")); map_.insert(Default(Param::commit_order, "3")); map_.insert(Default(Param::causal_read_timeout, "PT30S")); const int max_write_set_size(galera::WriteSetNG::MAX_SIZE); map_.insert(Default(Param::max_write_set_size, gu::to_string(max_write_set_size))); } const galera::ReplicatorSMM::Defaults galera::ReplicatorSMM::defaults; galera::ReplicatorSMM::InitConfig::InitConfig(gu::Config& conf, const char* const node_address) { Replicator::register_params(conf); std::map::const_iterator i; for (i = defaults.map_.begin(); i != defaults.map_.end(); ++i) { if (i->second.empty()) conf.add(i->first); else conf.add(i->first, i->second); } // what is would be a better protection? int const pv(gu::from_string(conf.get(Param::proto_max))); if (pv > MAX_PROTO_VER) { log_warn << "Can't set '" << Param::proto_max << "' to " << pv << ": maximum supported value is " << MAX_PROTO_VER; conf.add(Param::proto_max, gu::to_string(MAX_PROTO_VER)); } conf.add(COMMON_BASE_HOST_KEY); conf.add(COMMON_BASE_PORT_KEY); if (node_address && strlen(node_address) > 0) { gu::URI na(node_address, false); try { std::string const host = na.get_host(); if (host == "0.0.0.0" || host == "0:0:0:0:0:0:0:0" || host == "::") { gu_throw_error(EINVAL) << "Bad value for 'node_address': '" << host << '\''; } conf.set(BASE_HOST_KEY, host); } catch (gu::NotSet& e) {} try { conf.set(BASE_PORT_KEY, na.get_port()); } catch (gu::NotSet& e) {} } /* register variables and defaults from other modules */ gcache::GCache::register_params(conf); if (gcs_register_params(reinterpret_cast(&conf))) { gu_throw_fatal << "Error intializing GCS parameters"; } Certification::register_params(conf); ist::register_params(conf); } galera::ReplicatorSMM::ParseOptions::ParseOptions(gu::Config& conf, const char* const opts) { conf.parse(opts); } /* helper for param_set() below */ void galera::ReplicatorSMM::set_param (const std::string& key, const std::string& value) { if (key == Param::commit_order) { log_error << "setting '" << key << "' during runtime not allowed"; gu_throw_error(EPERM) << "setting '" << key << "' during runtime not allowed"; } else if (key == Param::causal_read_timeout) { causal_read_timeout_ = gu::datetime::Period(value); } else if (key == Param::base_host || key == Param::base_port || key == Param::proto_max) { // nothing to do here, these params take effect only at // provider (re)start } else if (key == Param::key_format) { trx_params_.key_format_ = KeySet::version(value); } else if (key == Param::max_write_set_size) { trx_params_.max_write_set_size_ = gu::from_string(value); } else { log_warn << "parameter '" << "' not found"; assert(0); throw gu::NotFound(); } } void galera::ReplicatorSMM::param_set (const std::string& key, const std::string& value) { try { if (config_.get(key) == value) return; } catch (gu::NotSet&) {} bool found(false); // Note: base_host is treated separately here as it cannot have // default value known at compile time. if (defaults.map_.find(key) != defaults.map_.end() || key == Param::base_host) // is my key? { found = true; set_param (key, value); config_.set (key, value); } if (key == Certification::PARAM_LOG_CONFLICTS) { cert_.set_log_conflicts(value); return; } // this key might be for another module else if (0 != key.find(common_prefix)) { try { gcs_.param_set (key, value); found = true; } catch (gu::NotFound&) {} try { gcache_.param_set (key, value); found = true; } catch (gu::NotFound&) {} } if (!found) throw gu::NotFound(); } std::string galera::ReplicatorSMM::param_get (const std::string& key) const { return config_.get(key); } percona-galera-3-3.8-3390/galera/src/replicator_smm_stats.cpp000066400000000000000000000311101244131713600237620ustar00rootroot00000000000000/* Copyright (C) 2010 Codership Oy */ #include "replicator_smm.hpp" #include "uuid.hpp" // @todo: should be protected static member of the parent class static const size_t GALERA_STAGE_MAX(11); // @todo: should be protected static member of the parent class static const char* state_str[GALERA_STAGE_MAX] = { "Initialized", "Joining", "Joining: preparing for State Transfer", "Joining: requested State Transfer", "Joining: receiving State Transfer", "Joined", "Synced", "Donor/Desynced", "Joining: State Transfer request failed", "Joining: State Transfer failed", "Destroyed" }; // @todo: should be protected static member of the parent class static wsrep_member_status_t state2stats(galera::ReplicatorSMM::State state) { switch (state) { case galera::ReplicatorSMM::S_DESTROYED : case galera::ReplicatorSMM::S_CLOSED : case galera::ReplicatorSMM::S_CLOSING : case galera::ReplicatorSMM::S_CONNECTED : return WSREP_MEMBER_UNDEFINED; case galera::ReplicatorSMM::S_JOINING : return WSREP_MEMBER_JOINER; case galera::ReplicatorSMM::S_JOINED : return WSREP_MEMBER_JOINED; case galera::ReplicatorSMM::S_SYNCED : return WSREP_MEMBER_SYNCED; case galera::ReplicatorSMM::S_DONOR : return WSREP_MEMBER_DONOR; } gu_throw_fatal << "invalid state " << state; } // @todo: should be protected static member of the parent class static const char* state2stats_str(galera::ReplicatorSMM::State state, galera::ReplicatorSMM::SstState sst_state) { using galera::ReplicatorSMM; switch (state) { case galera::ReplicatorSMM::S_DESTROYED : return state_str[10]; case galera::ReplicatorSMM::S_CLOSED : case galera::ReplicatorSMM::S_CLOSING: case galera::ReplicatorSMM::S_CONNECTED: { if (sst_state == ReplicatorSMM::SST_REQ_FAILED) return state_str[8]; else if (sst_state == ReplicatorSMM::SST_FAILED) return state_str[9]; else return state_str[0]; } case galera::ReplicatorSMM::S_JOINING: { if (sst_state == ReplicatorSMM::SST_WAIT) return state_str[4]; else return state_str[1]; } case galera::ReplicatorSMM::S_JOINED : return state_str[5]; case galera::ReplicatorSMM::S_SYNCED : return state_str[6]; case galera::ReplicatorSMM::S_DONOR : return state_str[7]; } gu_throw_fatal << "invalid state " << state; } typedef enum status_vars { STATS_STATE_UUID = 0, STATS_PROTOCOL_VERSION, STATS_LAST_APPLIED, STATS_REPLICATED, STATS_REPLICATED_BYTES, STATS_KEYS_COUNT, STATS_KEYS_BYTES, STATS_DATA_BYTES, STATS_UNRD_BYTES, STATS_RECEIVED, STATS_RECEIVED_BYTES, STATS_LOCAL_COMMITS, STATS_LOCAL_CERT_FAILURES, STATS_LOCAL_REPLAYS, STATS_LOCAL_SEND_QUEUE, STATS_LOCAL_SEND_QUEUE_MAX, STATS_LOCAL_SEND_QUEUE_MIN, STATS_LOCAL_SEND_QUEUE_AVG, STATS_LOCAL_RECV_QUEUE, STATS_LOCAL_RECV_QUEUE_MAX, STATS_LOCAL_RECV_QUEUE_MIN, STATS_LOCAL_RECV_QUEUE_AVG, STATS_LOCAL_CACHED_DOWNTO, STATS_FC_PAUSED_NS, STATS_FC_PAUSED_AVG, STATS_FC_SENT, STATS_FC_RECEIVED, STATS_CERT_DEPS_DISTANCE, STATS_APPLY_OOOE, STATS_APPLY_OOOL, STATS_APPLY_WINDOW, STATS_COMMIT_OOOE, STATS_COMMIT_OOOL, STATS_COMMIT_WINDOW, STATS_LOCAL_STATE, STATS_LOCAL_STATE_COMMENT, STATS_CERT_INDEX_SIZE, STATS_CAUSAL_READS, STATS_CERT_INTERVAL, STATS_INCOMING_LIST, STATS_MAX } StatusVars; static const struct wsrep_stats_var wsrep_stats[STATS_MAX + 1] = { { "local_state_uuid", WSREP_VAR_STRING, { 0 } }, { "protocol_version", WSREP_VAR_INT64, { 0 } }, { "last_committed", WSREP_VAR_INT64, { -1 } }, { "replicated", WSREP_VAR_INT64, { 0 } }, { "replicated_bytes", WSREP_VAR_INT64, { 0 } }, { "repl_keys", WSREP_VAR_INT64, { 0 } }, { "repl_keys_bytes", WSREP_VAR_INT64, { 0 } }, { "repl_data_bytes", WSREP_VAR_INT64, { 0 } }, { "repl_other_bytes", WSREP_VAR_INT64, { 0 } }, { "received", WSREP_VAR_INT64, { 0 } }, { "received_bytes", WSREP_VAR_INT64, { 0 } }, { "local_commits", WSREP_VAR_INT64, { 0 } }, { "local_cert_failures", WSREP_VAR_INT64, { 0 } }, { "local_replays", WSREP_VAR_INT64, { 0 } }, { "local_send_queue", WSREP_VAR_INT64, { 0 } }, { "local_send_queue_max", WSREP_VAR_INT64, { 0 } }, { "local_send_queue_min", WSREP_VAR_INT64, { 0 } }, { "local_send_queue_avg", WSREP_VAR_DOUBLE, { 0 } }, { "local_recv_queue", WSREP_VAR_INT64, { 0 } }, { "local_recv_queue_max", WSREP_VAR_INT64, { 0 } }, { "local_recv_queue_min", WSREP_VAR_INT64, { 0 } }, { "local_recv_queue_avg", WSREP_VAR_DOUBLE, { 0 } }, { "local_cached_downto", WSREP_VAR_INT64, { 0 } }, { "flow_control_paused_ns", WSREP_VAR_INT64, { 0 } }, { "flow_control_paused", WSREP_VAR_DOUBLE, { 0 } }, { "flow_control_sent", WSREP_VAR_INT64, { 0 } }, { "flow_control_recv", WSREP_VAR_INT64, { 0 } }, { "cert_deps_distance", WSREP_VAR_DOUBLE, { 0 } }, { "apply_oooe", WSREP_VAR_DOUBLE, { 0 } }, { "apply_oool", WSREP_VAR_DOUBLE, { 0 } }, { "apply_window", WSREP_VAR_DOUBLE, { 0 } }, { "commit_oooe", WSREP_VAR_DOUBLE, { 0 } }, { "commit_oool", WSREP_VAR_DOUBLE, { 0 } }, { "commit_window", WSREP_VAR_DOUBLE, { 0 } }, { "local_state", WSREP_VAR_INT64, { 0 } }, { "local_state_comment", WSREP_VAR_STRING, { 0 } }, { "cert_index_size", WSREP_VAR_INT64, { 0 } }, { "causal_reads", WSREP_VAR_INT64, { 0 } }, { "cert_interval", WSREP_VAR_DOUBLE, { 0 } }, { "incoming_addresses", WSREP_VAR_STRING, { 0 } }, { 0, WSREP_VAR_STRING, { 0 } } }; void galera::ReplicatorSMM::build_stats_vars ( std::vector& stats) { const struct wsrep_stats_var* ptr(wsrep_stats); do { stats.push_back(*ptr); } while (ptr++->name != 0); stats[STATS_STATE_UUID].value._string = state_uuid_str_; } const struct wsrep_stats_var* galera::ReplicatorSMM::stats_get() const { if (S_DESTROYED == state_()) return 0; std::vector sv(wsrep_stats_); sv[STATS_PROTOCOL_VERSION ].value._int64 = protocol_version_; sv[STATS_LAST_APPLIED ].value._int64 = apply_monitor_.last_left(); sv[STATS_REPLICATED ].value._int64 = replicated_(); sv[STATS_REPLICATED_BYTES ].value._int64 = replicated_bytes_(); sv[STATS_KEYS_COUNT ].value._int64 = keys_count_(); sv[STATS_KEYS_BYTES ].value._int64 = keys_bytes_(); sv[STATS_DATA_BYTES ].value._int64 = data_bytes_(); sv[STATS_UNRD_BYTES ].value._int64 = unrd_bytes_(); sv[STATS_RECEIVED ].value._int64 = gcs_as_.received(); sv[STATS_RECEIVED_BYTES ].value._int64 = gcs_as_.received_bytes(); sv[STATS_LOCAL_COMMITS ].value._int64 = local_commits_(); sv[STATS_LOCAL_CERT_FAILURES].value._int64 = local_cert_failures_(); sv[STATS_LOCAL_REPLAYS ].value._int64 = local_replays_(); struct gcs_stats stats; gcs_.get_stats (&stats); sv[STATS_LOCAL_SEND_QUEUE ].value._int64 = stats.send_q_len; sv[STATS_LOCAL_SEND_QUEUE_MAX].value._int64 = stats.send_q_len_max; sv[STATS_LOCAL_SEND_QUEUE_MIN].value._int64 = stats.send_q_len_min; sv[STATS_LOCAL_SEND_QUEUE_AVG].value._double = stats.send_q_len_avg; sv[STATS_LOCAL_RECV_QUEUE ].value._int64 = stats.recv_q_len; sv[STATS_LOCAL_RECV_QUEUE_MAX].value._int64 = stats.recv_q_len_max; sv[STATS_LOCAL_RECV_QUEUE_MIN].value._int64 = stats.recv_q_len_min; sv[STATS_LOCAL_RECV_QUEUE_AVG].value._double = stats.recv_q_len_avg; sv[STATS_LOCAL_CACHED_DOWNTO ].value._int64 = gcache_.seqno_min(); sv[STATS_FC_PAUSED_NS ].value._int64 = stats.fc_paused_ns; sv[STATS_FC_PAUSED_AVG ].value._double = stats.fc_paused_avg; sv[STATS_FC_SENT ].value._int64 = stats.fc_sent; sv[STATS_FC_RECEIVED ].value._int64 = stats.fc_received; double avg_cert_interval(0); double avg_deps_dist(0); size_t index_size(0); cert_.stats_get(avg_cert_interval, avg_deps_dist, index_size); sv[STATS_CERT_DEPS_DISTANCE ].value._double = avg_deps_dist; sv[STATS_CERT_INTERVAL ].value._double = avg_cert_interval; sv[STATS_CERT_INDEX_SIZE ].value._int64 = index_size; double oooe; double oool; double win; const_cast&>(apply_monitor_). get_stats(&oooe, &oool, &win); sv[STATS_APPLY_OOOE ].value._double = oooe; sv[STATS_APPLY_OOOL ].value._double = oool; sv[STATS_APPLY_WINDOW ].value._double = win; const_cast&>(commit_monitor_). get_stats(&oooe, &oool, &win); sv[STATS_COMMIT_OOOE ].value._double = oooe; sv[STATS_COMMIT_OOOL ].value._double = oool; sv[STATS_COMMIT_WINDOW ].value._double = win; sv[STATS_LOCAL_STATE ].value._int64 = state2stats(state_()); sv[STATS_LOCAL_STATE_COMMENT ].value._string = state2stats_str(state_(), sst_state_); sv[STATS_CAUSAL_READS].value._int64 = causal_reads_(); // Get gcs backend status gu::Status status; gcs_.get_status(status); // Dynamical strings are copied into buffer allocated after stats var array. // Compute space needed. size_t tail_size(0); for (gu::Status::const_iterator i(status.begin()); i != status.end(); ++i) { tail_size += i->first.size() + 1 + i->second.size() + 1; } gu::Lock lock_inc(incoming_mutex_); tail_size += incoming_list_.size() + 1; /* Create a buffer to be passed to the caller. */ // The buffer size needed: // * Space for wsrep_stats_ array // * Space for additional elements from status map // * Trailing space for string store size_t const vec_size( (sv.size() + status.size())*sizeof(struct wsrep_stats_var)); struct wsrep_stats_var* const buf( reinterpret_cast( gu_malloc(vec_size + tail_size))); if (buf) { // Resize sv to have enough space for variables from status sv.resize(sv.size() + status.size()); // Initial tail_buf position char* tail_buf(reinterpret_cast(buf + sv.size())); // Assign incoming list strncpy(tail_buf, incoming_list_.c_str(), incoming_list_.size() + 1); sv[STATS_INCOMING_LIST].value._string = tail_buf; tail_buf += incoming_list_.size() + 1; // Iterate over dynamical status variables and assing strings size_t sv_pos(STATS_INCOMING_LIST + 1); for (gu::Status::const_iterator i(status.begin()); i != status.end(); ++i, ++sv_pos) { // Name strncpy(tail_buf, i->first.c_str(), i->first.size() + 1); sv[sv_pos].name = tail_buf; tail_buf += i->first.size() + 1; // Type sv[sv_pos].type = WSREP_VAR_STRING; // Value strncpy(tail_buf, i->second.c_str(), i->second.size() + 1); sv[sv_pos].value._string = tail_buf; tail_buf += i->second.size() + 1; } assert(sv_pos == sv.size() - 1); // NULL terminate sv[sv_pos].name = 0; sv[sv_pos].type = WSREP_VAR_STRING; sv[sv_pos].value._string = 0; assert(static_cast(tail_buf - reinterpret_cast(buf)) == vec_size + tail_size); assert(reinterpret_cast(buf)[vec_size + tail_size - 1] == '\0'); // Finally copy sv vector to buf memcpy(buf, &sv[0], vec_size); } else { log_warn << "Failed to allocate stats vars buffer to " << (vec_size + tail_size) << " bytes. System is running out of memory."; } return buf; } void galera::ReplicatorSMM::stats_reset() { if (S_DESTROYED == state_()) return; gcs_.flush_stats (); apply_monitor_.flush_stats(); commit_monitor_.flush_stats(); cert_.stats_reset(); } void galera::ReplicatorSMM::stats_free(struct wsrep_stats_var* arg) { gu_free(arg); } percona-galera-3-3.8-3390/galera/src/replicator_str.cpp000066400000000000000000000602511244131713600225700ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "replicator_smm.hpp" #include "uuid.hpp" #include namespace galera { bool ReplicatorSMM::state_transfer_required(const wsrep_view_info_t& view_info) { if (view_info.state_gap) { assert(view_info.view >= 0); if (state_uuid_ == view_info.state_id.uuid) // common history { wsrep_seqno_t const group_seqno(view_info.state_id.seqno); wsrep_seqno_t const local_seqno(STATE_SEQNO()); if (state_() >= S_JOINING) /* See #442 - S_JOINING should be a valid state here */ { return (local_seqno < group_seqno); } else { if (local_seqno > group_seqno) { close(); gu_throw_fatal << "Local state seqno (" << local_seqno << ") is greater than group seqno (" <(req_ + offset))); } void* req (ssize_t offset) const { if (len(offset) > 0) return req_ + offset + sizeof(uint32_t); else return 0; } ssize_t const len_; char* const req_; bool const own_; }; std::string const StateRequest_v1::MAGIC("STRv1"); #ifndef INT32_MAX #define INT32_MAX 0x7fffffff #endif StateRequest_v1::StateRequest_v1 ( const void* const sst_req, ssize_t const sst_req_len, const void* const ist_req, ssize_t const ist_req_len) : len_(MAGIC.length() + 1 + sizeof(uint32_t) + sst_req_len + sizeof(uint32_t) + ist_req_len), req_(reinterpret_cast(malloc(len_))), own_(true) { if (!req_) gu_throw_error (ENOMEM) << "Could not allocate state request v1"; if (sst_req_len > INT32_MAX || sst_req_len < 0) gu_throw_error (EMSGSIZE) << "SST request length (" << sst_req_len << ") unrepresentable"; if (ist_req_len > INT32_MAX || ist_req_len < 0) gu_throw_error (EMSGSIZE) << "IST request length (" << sst_req_len << ") unrepresentable"; char* ptr(req_); strcpy (ptr, MAGIC.c_str()); ptr += MAGIC.length() + 1; uint32_t* tmp(reinterpret_cast(ptr)); *tmp = htogl(sst_req_len); ptr += sizeof(uint32_t); memcpy (ptr, sst_req, sst_req_len); ptr += sst_req_len; tmp = reinterpret_cast(ptr); *tmp = htogl(ist_req_len); ptr += sizeof(uint32_t); memcpy (ptr, ist_req, ist_req_len); assert ((ptr - req_) == (len_ - ist_req_len)); } // takes ownership over str buffer StateRequest_v1::StateRequest_v1 (const void* str, ssize_t str_len) : len_(str_len), req_(reinterpret_cast(const_cast(str))), own_(false) { if (sst_offset() + 2*sizeof(uint32_t) > size_t(len_)) { assert(0); gu_throw_error (EINVAL) << "State transfer request is too short: " << len_ << ", must be at least: " << (sst_offset() + 2*sizeof(uint32_t)); } if (strncmp (req_, MAGIC.c_str(), MAGIC.length())) { assert(0); gu_throw_error (EINVAL) << "Wrong magic signature in state request v1."; } if (sst_offset() + sst_len() + 2*sizeof(uint32_t) > size_t(len_)) { gu_throw_error (EINVAL) << "Malformed state request v1: sst length: " << sst_len() << ", total length: " << len_; } if (ist_offset() + ist_len() + sizeof(uint32_t) != size_t(len_)) { gu_throw_error (EINVAL) << "Malformed state request v1: parsed field " "length " << sst_len() << " is not equal to total request length " << len_; } } static ReplicatorSMM::StateRequest* read_state_request (const void* const req, size_t const req_len) { const char* const str(reinterpret_cast(req)); if (req_len > StateRequest_v1::MAGIC.length() && !strncmp(str, StateRequest_v1::MAGIC.c_str(), StateRequest_v1::MAGIC.length())) { return (new StateRequest_v1(req, req_len)); } else { return (new StateRequest_v0(req, req_len)); } } class IST_request { public: IST_request() : peer_(), uuid_(), last_applied_(), group_seqno_() { } IST_request(const std::string& peer, const wsrep_uuid_t& uuid, wsrep_seqno_t last_applied, wsrep_seqno_t group_seqno) : peer_(peer), uuid_(uuid), last_applied_(last_applied), group_seqno_(group_seqno) { } const std::string& peer() const { return peer_ ; } const wsrep_uuid_t& uuid() const { return uuid_ ; } wsrep_seqno_t last_applied() const { return last_applied_; } wsrep_seqno_t group_seqno() const { return group_seqno_; } private: friend std::ostream& operator<<(std::ostream&, const IST_request&); friend std::istream& operator>>(std::istream&, IST_request&); std::string peer_; wsrep_uuid_t uuid_; wsrep_seqno_t last_applied_; wsrep_seqno_t group_seqno_; }; std::ostream& operator<<(std::ostream& os, const IST_request& istr) { return (os << istr.uuid_ << ":" << istr.last_applied_ << "-" << istr.group_seqno_ << "|" << istr.peer_); } std::istream& operator>>(std::istream& is, IST_request& istr) { char c; return (is >> istr.uuid_ >> c >> istr.last_applied_ >> c >> istr.group_seqno_ >> c >> istr.peer_); } static void get_ist_request(const ReplicatorSMM::StateRequest* str, IST_request* istr) { assert(str->ist_len()); std::string ist_str(reinterpret_cast(str->ist_req()), str->ist_len()); std::istringstream is(ist_str); is >> *istr; } static bool sst_is_trivial (const void* const req, size_t const len) { /* Check that the first string in request == ReplicatorSMM::TRIVIAL_SST */ size_t const trivial_len = strlen(ReplicatorSMM::TRIVIAL_SST) + 1; return (len >= trivial_len && !memcmp (req, ReplicatorSMM::TRIVIAL_SST, trivial_len)); } void ReplicatorSMM::process_state_req(void* recv_ctx, const void* req, size_t req_size, wsrep_seqno_t const seqno_l, wsrep_seqno_t const donor_seq) { assert(recv_ctx != 0); assert(seqno_l > -1); assert(req != 0); LocalOrder lo(seqno_l); gu_trace(local_monitor_.enter(lo)); apply_monitor_.drain(donor_seq); if (co_mode_ != CommitOrder::BYPASS) commit_monitor_.drain(donor_seq); state_.shift_to(S_DONOR); StateRequest* const streq (read_state_request (req, req_size)); // somehow the following does not work, string is initialized beyond // the first \0: //std::string const req_str(reinterpret_cast(streq->sst_req()), // streq->sst_len()); // have to resort to C ways. char* const tmp(strndup(reinterpret_cast(streq->sst_req()), streq->sst_len())); std::string const req_str(tmp); free (tmp); bool const skip_state_transfer (sst_is_trivial(streq->sst_req(), streq->sst_len()) /* compatibility with older garbd, to be removed in * the next release (2.1)*/ || req_str == std::string(WSREP_STATE_TRANSFER_NONE) ); wsrep_seqno_t rcode (0); bool join_now = true; if (!skip_state_transfer) { if (streq->ist_len()) { IST_request istr; get_ist_request(streq, &istr); if (istr.uuid() == state_uuid_) { log_info << "IST request: " << istr; try { gcache_.seqno_lock(istr.last_applied() + 1); } catch(gu::NotFound& nf) { log_info << "IST first seqno " << istr.last_applied() + 1 << " not found from cache, falling back to SST"; // @todo: close IST channel explicitly goto full_sst; } if (streq->sst_len()) // if joiner is waiting for SST, notify it { wsrep_gtid_t state_id = { istr.uuid(),istr.last_applied()}; rcode = sst_donate_cb_(app_ctx_, recv_ctx, streq->sst_req(), streq->sst_len(), &state_id, 0, 0, true); // we will join in sst_sent. join_now = false; } if (rcode >= 0) { try { // Note: End of IST range must be cc_seqno_ instead // of istr.group_seqno() in case there are CCs between // sending and delivering STR. If there are no // intermediate CCs, cc_seqno_ == istr.group_seqno(). // Then duplicate message concern in #746 will be // releaved. ist_senders_.run(config_, istr.peer(), istr.last_applied() + 1, cc_seqno_, protocol_version_); } catch (gu::Exception& e) { log_error << "IST failed: " << e.what(); rcode = -e.get_errno(); } } else { log_error << "Failed to bypass SST: " << -rcode << " (" << strerror (-rcode) << ')'; } goto out; } } full_sst: if (streq->sst_len()) { assert(0 == rcode); wsrep_gtid_t const state_id = { state_uuid_, donor_seq }; rcode = sst_donate_cb_(app_ctx_, recv_ctx, streq->sst_req(), streq->sst_len(), &state_id, 0, 0, false); // we will join in sst_sent. join_now = false; } else { log_warn << "SST request is null, SST canceled."; rcode = -ECANCELED; } } out: delete streq; local_monitor_.leave(lo); if (join_now || rcode < 0) { gcs_.join(rcode < 0 ? rcode : donor_seq); } } void ReplicatorSMM::prepare_for_IST (void*& ptr, ssize_t& len, const wsrep_uuid_t& group_uuid, wsrep_seqno_t const group_seqno) { if (state_uuid_ != group_uuid) { gu_throw_error (EPERM) << "Local state UUID (" << state_uuid_ << ") does not match group state UUID (" << group_uuid << ')'; } wsrep_seqno_t const local_seqno(STATE_SEQNO()); if (local_seqno < 0) { gu_throw_error (EPERM) << "Local state seqno is undefined"; } assert(local_seqno < group_seqno); std::ostringstream os; std::string recv_addr = ist_receiver_.prepare( local_seqno + 1, group_seqno, protocol_version_); os << IST_request(recv_addr, state_uuid_, local_seqno, group_seqno); char* str = strdup (os.str().c_str()); // cppcheck-suppress nullPointer if (!str) gu_throw_error (ENOMEM) << "Failed to allocate IST buffer."; len = strlen(str) + 1; ptr = str; } ReplicatorSMM::StateRequest* ReplicatorSMM::prepare_state_request (const void* const sst_req, ssize_t const sst_req_len, const wsrep_uuid_t& group_uuid, wsrep_seqno_t const group_seqno) { try { switch (str_proto_ver_) { case 0: return new StateRequest_v0 (sst_req, sst_req_len); case 1: case 2: { void* ist_req(0); ssize_t ist_req_len(0); try { gu_trace(prepare_for_IST (ist_req, ist_req_len, group_uuid, group_seqno)); } catch (gu::Exception& e) { log_warn << "Failed to prepare for incremental state transfer: " << e.what() << ". IST will be unavailable."; } StateRequest* ret = new StateRequest_v1 (sst_req, sst_req_len, ist_req, ist_req_len); free (ist_req); return ret; } default: gu_throw_fatal << "Unsupported STR protocol: " << str_proto_ver_; } } catch (std::exception& e) { log_fatal << "State request preparation failed, aborting: " << e.what(); } catch (...) { log_fatal << "State request preparation failed, aborting: unknown exception"; } abort(); } static bool retry_str(int ret) { return (ret == -EAGAIN || ret == -ENOTCONN); } void ReplicatorSMM::send_state_request (const StateRequest* const req) { long ret; long tries = 0; gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; if (req->ist_len()) { IST_request istr; get_ist_request(req, &istr); ist_uuid = to_gu_uuid(istr.uuid()); ist_seqno = istr.last_applied(); } do { tries++; gcs_seqno_t seqno_l; ret = gcs_.request_state_transfer(str_proto_ver_, req->req(), req->len(), sst_donor_, ist_uuid, ist_seqno, &seqno_l); if (ret < 0) { if (!retry_str(ret)) { log_error << "Requesting state transfer failed: " << ret << "(" << strerror(-ret) << ")"; } else if (1 == tries) { log_info << "Requesting state transfer failed: " << ret << "(" << strerror(-ret) << "). " << "Will keep retrying every " << sst_retry_sec_ << " second(s)"; } } if (seqno_l != GCS_SEQNO_ILL) { /* Check that we're not running out of space in monitor. */ if (local_monitor_.would_block(seqno_l)) { long const seconds = sst_retry_sec_ * tries; log_error << "We ran out of resources, seemingly because " << "we've been unsuccessfully requesting state " << "transfer for over " << seconds << " seconds. " << "Please check that there is " << "at least one fully synced member in the group. " << "Application must be restarted."; ret = -EDEADLK; } else { // we are already holding local monitor LocalOrder lo(seqno_l); local_monitor_.self_cancel(lo); } } } while (retry_str(ret) && (usleep(sst_retry_sec_ * 1000000), true)); if (ret >= 0) { if (1 == tries) { log_info << "Requesting state transfer: success, donor: " << ret; } else { log_info << "Requesting state transfer: success after " << tries << " tries, donor: " << ret; } } else { sst_state_ = SST_REQ_FAILED; st_.set(state_uuid_, STATE_SEQNO()); st_.mark_safe(); if (state_() > S_CLOSING) { log_fatal << "State transfer request failed unrecoverably: " << -ret << " (" << strerror(-ret) << "). Most likely " << "it is due to inability to communicate with the " << "cluster primary component. Restart required."; abort(); } else { // connection is being closed, send failure is expected } } } void ReplicatorSMM::request_state_transfer (void* recv_ctx, const wsrep_uuid_t& group_uuid, wsrep_seqno_t const group_seqno, const void* const sst_req, ssize_t const sst_req_len) { assert(sst_req_len >= 0); StateRequest* const req(prepare_state_request(sst_req, sst_req_len, group_uuid, group_seqno)); gu::Lock lock(sst_mutex_); st_.mark_unsafe(); send_state_request (req); state_.shift_to(S_JOINING); sst_state_ = SST_WAIT; /* while waiting for state transfer to complete is a good point * to reset gcache, since it may involve some IO too */ gcache_.seqno_reset(); if (sst_req_len != 0) { if (sst_is_trivial(sst_req, sst_req_len)) { sst_uuid_ = group_uuid; sst_seqno_ = group_seqno; } else { lock.wait(sst_cond_); } if (sst_uuid_ != group_uuid) { log_fatal << "Application received wrong state: " << "\n\tReceived: " << sst_uuid_ << "\n\tRequired: " << group_uuid; sst_state_ = SST_FAILED; log_fatal << "Application state transfer failed. This is " << "unrecoverable condition, restart required."; st_.set(sst_uuid_, sst_seqno_); st_.mark_safe(); abort(); } else { update_state_uuid (sst_uuid_); apply_monitor_.set_initial_position(-1); apply_monitor_.set_initial_position(sst_seqno_); if (co_mode_ != CommitOrder::BYPASS) { commit_monitor_.set_initial_position(-1); commit_monitor_.set_initial_position(sst_seqno_); } log_debug << "Installed new state: " << state_uuid_ << ":" << sst_seqno_; } } else { assert (state_uuid_ == group_uuid); } st_.mark_safe(); if (req->ist_len() > 0) { // IST is prepared only with str proto ver 1 and above if (STATE_SEQNO() < group_seqno) { log_info << "Receiving IST: " << (group_seqno - STATE_SEQNO()) << " writesets, seqnos " << STATE_SEQNO() << "-" << group_seqno; ist_receiver_.ready(); recv_IST(recv_ctx); sst_seqno_ = ist_receiver_.finished(); // Note: apply_monitor_ must be drained to avoid race between // IST appliers and GCS appliers, GCS action source may // provide actions that have already been applied. apply_monitor_.drain(sst_seqno_); log_info << "IST received: " << state_uuid_ << ":" << sst_seqno_; } else { (void)ist_receiver_.finished(); } } delete req; } void ReplicatorSMM::recv_IST(void* recv_ctx) { try { while (true) { TrxHandle* trx(0); int err; if ((err = ist_receiver_.recv(&trx)) == 0) { assert(trx != 0); TrxHandleLock lock(*trx); // Verify checksum before applying. This is also required // to synchronize with possible background checksum thread. trx->verify_checksum(); if (trx->depends_seqno() == -1) { ApplyOrder ao(*trx); apply_monitor_.self_cancel(ao); if (co_mode_ != CommitOrder::BYPASS) { CommitOrder co(*trx, co_mode_); commit_monitor_.self_cancel(co); } } else { // replicating and certifying stages have been // processed on donor, just adjust states here trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_CERTIFYING); try { apply_trx(recv_ctx, trx); } catch (gu::Exception& e) { st_.mark_corrupt(); throw; } } } else { return; } trx->unref(); } } catch (gu::Exception& e) { log_fatal << "receiving IST failed, node restart required: " << e.what(); st_.mark_corrupt(); gcs_.close(); gu_abort(); } } } /* namespace galera */ percona-galera-3-3.8-3390/galera/src/saved_state.cpp000066400000000000000000000135751244131713600220450ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // #include "saved_state.hpp" #include "uuid.hpp" #include #define __STDC_FORMAT_MACROS #include namespace galera { #define VERSION "2.1" #define MAX_SIZE 256 SavedState::SavedState (const std::string& file) : fs_ (0), uuid_ (WSREP_UUID_UNDEFINED), seqno_ (WSREP_SEQNO_UNDEFINED), unsafe_ (0), corrupt_ (false), mtx_ (), written_uuid_ (uuid_), current_len_ (0), total_marks_ (0), total_locks_ (0), total_writes_ (0) { std::ifstream ifs(file.c_str()); std::ofstream ofs; if (ifs.fail()) { log_warn << "Could not open saved state file for reading: " << file; } fs_ = fopen(file.c_str(), "a"); if (!fs_) { log_warn << "Could not open saved state file for writing: " << file; /* We are not reading anything from file we can't write to, since it may be terribly outdated. */ return; } std::string version("0.8"); std::string line; while (getline(ifs, line), ifs.good()) { std::istringstream istr(line); std::string param; istr >> param; if (param[0] == '#') { log_debug << "read comment: " << line; } else if (param == "version:") { istr >> version; // nothing to do with this yet log_debug << "read version: " << version; } else if (param == "uuid:") { try { istr >> uuid_; log_debug << "read saved state uuid: " << uuid_; } catch (gu::Exception& e) { log_error << e.what(); uuid_ = WSREP_UUID_UNDEFINED; } } else if (param == "seqno:") { istr >> seqno_; log_debug << "read saved state seqno: " << seqno_; } else if (param == "cert_index:") { // @todo log_debug << "cert index restore not implemented yet"; } } log_info << "Found saved state: " << uuid_ << ':' << seqno_; #if 0 // we'll probably have it legal if (seqno_ < 0 && uuid_ != WSREP_UUID_UNDEFINED) { log_warn << "Negative seqno with valid UUID: " << uuid_ << ':' << seqno_ << ". Discarding UUID."; uuid_ = WSREP_UUID_UNDEFINED; } #endif written_uuid_ = uuid_; current_len_ = ftell (fs_); log_debug << "Initialized current_len_ to " << current_len_; if (current_len_ <= MAX_SIZE) { fs_ = freopen (file.c_str(), "r+", fs_); } else // normalize file contents { fs_ = freopen (file.c_str(), "w+", fs_); // truncate current_len_ = 0; set (uuid_, seqno_); } } SavedState::~SavedState () { if (fs_) fclose(fs_); } void SavedState::get (wsrep_uuid_t& u, wsrep_seqno_t& s) { gu::Lock lock(mtx_); u = uuid_; s = seqno_; } void SavedState::set (const wsrep_uuid_t& u, wsrep_seqno_t s) { gu::Lock lock(mtx_); ++total_locks_; if (corrupt_) return; uuid_ = u; seqno_ = s; if (0 == unsafe_()) write_and_flush (u, s); else log_debug << "Not writing state: unsafe counter is " << unsafe_(); } /* the goal of unsafe_, written_uuid_, current_len_ below is * 1. avoid unnecessary mutex locks * 2. if locked - avoid unnecessary file writes * 3. if writing - avoid metadata operations, write over existing space */ void SavedState::mark_unsafe() { ++total_marks_; if (1 == unsafe_.add_and_fetch (1)) { gu::Lock lock(mtx_); ++total_locks_; assert (unsafe_() > 0); if (written_uuid_ != WSREP_UUID_UNDEFINED) { write_and_flush (WSREP_UUID_UNDEFINED, WSREP_SEQNO_UNDEFINED); } } } void SavedState::mark_safe() { ++total_marks_; long count = unsafe_.sub_and_fetch (1); assert (count >= 0); if (0 == count) { gu::Lock lock(mtx_); ++total_locks_; if (0 == unsafe_() && (written_uuid_ != uuid_ || seqno_ >= 0)) { assert(false == corrupt_); /* this will write down proper seqno if set() was called too early * (in unsafe state) */ write_and_flush (uuid_, seqno_); } } } void SavedState::mark_corrupt() { /* Half LONG_MAX keeps us equally far from overflow and underflow by mark_unsafe()/mark_safe() calls */ unsafe_ = (std::numeric_limits::max() >> 1); gu::Lock lock(mtx_); ++total_locks_; if (corrupt_) return; uuid_ = WSREP_UUID_UNDEFINED; seqno_ = WSREP_SEQNO_UNDEFINED; corrupt_ = true; write_and_flush (WSREP_UUID_UNDEFINED, WSREP_SEQNO_UNDEFINED); } void SavedState::write_and_flush(const wsrep_uuid_t& u, const wsrep_seqno_t s) { assert (current_len_ <= MAX_SIZE); if (fs_) { if (s >= 0) { log_debug << "Saving state: " << u << ':' << s; } char buf[MAX_SIZE]; const gu_uuid_t* const uu(reinterpret_cast(&u)); int state_len = snprintf (buf, MAX_SIZE - 1, "# GALERA saved state" "\nversion: " VERSION "\nuuid: " GU_UUID_FORMAT "\nseqno: %" PRId64 "\ncert_index:\n", GU_UUID_ARGS(uu), s); int write_size; for (write_size = state_len; write_size < current_len_; ++write_size) buf[write_size] = ' '; // overwrite whatever is there currently rewind(fs_); fwrite(buf, write_size, 1, fs_); fflush(fs_); current_len_ = state_len; written_uuid_ = u; ++total_writes_; } else { log_debug << "Can't save state: output stream is not open."; } } } /* namespace galera */ percona-galera-3-3.8-3390/galera/src/saved_state.hpp000066400000000000000000000027071244131713600220450ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // #ifndef GALERA_SAVED_STATE_HPP #define GALERA_SAVED_STATE_HPP #include "gu_atomic.hpp" #include "gu_mutex.hpp" #include "gu_lock.hpp" #include "wsrep_api.h" #include #include namespace galera { class SavedState { public: SavedState (const std::string& file); ~SavedState (); void get (wsrep_uuid_t& u, wsrep_seqno_t& s); void set (const wsrep_uuid_t& u, wsrep_seqno_t s = WSREP_SEQNO_UNDEFINED); void mark_unsafe(); void mark_safe(); void mark_corrupt(); void stats(long& marks, long& locks, long& writes) { marks = total_marks_(); locks = total_locks_; writes = total_writes_; } private: FILE* fs_; wsrep_uuid_t uuid_; wsrep_seqno_t seqno_; gu::Atomic unsafe_; bool corrupt_; /* this mutex is needed because mark_safe() and mark_corrupt() will be * called outside local monitor, so race is possible */ gu::Mutex mtx_; wsrep_uuid_t written_uuid_; ssize_t current_len_; gu::Atomic total_marks_; long total_locks_; long total_writes_; void write_and_flush (const wsrep_uuid_t& u, const wsrep_seqno_t s); SavedState (const SavedState&); SavedState& operator=(const SavedState&); }; /* class SavedState */ } /* namespace galera */ #endif /* GALERA_SAVED_STATE_HPP */ percona-galera-3-3.8-3390/galera/src/trx_handle.cpp000066400000000000000000000263621244131713600216710ustar00rootroot00000000000000// // Copyright (C) 2010-2013 Codership Oy // #include "trx_handle.hpp" #include "uuid.hpp" #include "galera_exception.hpp" #include "gu_serialize.hpp" const galera::TrxHandle::Params galera::TrxHandle::Defaults(".", -1, KeySet::MAX_VERSION); std::ostream& galera::operator<<(std::ostream& os, TrxHandle::State s) { switch (s) { case TrxHandle::S_EXECUTING: return (os << "EXECUTING"); case TrxHandle::S_MUST_ABORT: return (os << "MUST_ABORT"); case TrxHandle::S_ABORTING: return (os << "ABORTING"); case TrxHandle::S_REPLICATING: return (os << "REPLICATING"); case TrxHandle::S_CERTIFYING: return (os << "CERTIFYING"); case TrxHandle::S_MUST_CERT_AND_REPLAY: return (os << "MUST_CERT_AND_REPLAY"); case TrxHandle::S_MUST_REPLAY_AM: return (os << "MUST_REPLAY_AM"); case TrxHandle::S_MUST_REPLAY_CM: return (os << "MUST_REPLAY_CM"); case TrxHandle::S_MUST_REPLAY: return (os << "MUST_REPLAY"); case TrxHandle::S_REPLAYING: return (os << "REPLAYING"); case TrxHandle::S_APPLYING: return (os << "APPLYING"); case TrxHandle::S_COMMITTING: return (os << "COMMITTING"); case TrxHandle::S_COMMITTED: return (os << "COMMITTED"); case TrxHandle::S_ROLLED_BACK: return (os << "ROLLED_BACK"); } gu_throw_fatal << "invalid state " << static_cast(s); } std::ostream& galera::operator<<(std::ostream& os, const TrxHandle& th) { os << "source: " << th.source_id_ << " version: " << th.version_ << " local: " << th.local_ << " state: " << th.state_() << " flags: " << th.write_set_flags_ << " conn_id: " << int64_t(th.conn_id_) << " trx_id: " << int64_t(th.trx_id_) // for readability << " seqnos (l: " << th.local_seqno_ << ", g: " << th.global_seqno_ << ", s: " << th.last_seen_seqno_ << ", d: " << th.depends_seqno_ << ", ts: " << th.timestamp_ << ")"; if (th.write_set_in().annotated()) { os << "\nAnnotation:\n"; th.write_set_in().write_annotation(os); os << std::endl; } return os; } galera::TrxHandle::Fsm::TransMap galera::TrxHandle::trans_map_; static class TransMapBuilder { public: void add(galera::TrxHandle::State from, galera::TrxHandle::State to) { using galera::TrxHandle; using std::make_pair; typedef TrxHandle::Transition Transition; typedef TrxHandle::Fsm::TransAttr TransAttr; TrxHandle::Fsm::TransMap& trans_map(TrxHandle::trans_map_); trans_map.insert_unique(make_pair(Transition(from, to), TransAttr())); } TransMapBuilder() { using galera::TrxHandle; add(TrxHandle::S_EXECUTING, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_EXECUTING, TrxHandle::S_REPLICATING); add(TrxHandle::S_EXECUTING, TrxHandle::S_ROLLED_BACK); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_MUST_CERT_AND_REPLAY); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_MUST_REPLAY_AM); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_MUST_REPLAY_CM); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_MUST_REPLAY); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_MUST_ABORT, TrxHandle::S_ABORTING); add(TrxHandle::S_ABORTING, TrxHandle::S_ROLLED_BACK); add(TrxHandle::S_REPLICATING, TrxHandle::S_CERTIFYING); add(TrxHandle::S_REPLICATING, TrxHandle::S_MUST_CERT_AND_REPLAY); add(TrxHandle::S_REPLICATING, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_CERTIFYING, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_CERTIFYING, TrxHandle::S_APPLYING); add(TrxHandle::S_CERTIFYING, TrxHandle::S_MUST_CERT_AND_REPLAY); add(TrxHandle::S_CERTIFYING, TrxHandle::S_MUST_REPLAY_AM); // trx replay add(TrxHandle::S_APPLYING, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_APPLYING, TrxHandle::S_COMMITTING); add(TrxHandle::S_COMMITTING, TrxHandle::S_COMMITTED); add(TrxHandle::S_COMMITTING, TrxHandle::S_MUST_ABORT); add(TrxHandle::S_MUST_CERT_AND_REPLAY, TrxHandle::S_CERTIFYING); add(TrxHandle::S_MUST_CERT_AND_REPLAY, TrxHandle::S_ABORTING); add(TrxHandle::S_MUST_REPLAY_AM, TrxHandle::S_MUST_REPLAY_CM); add(TrxHandle::S_MUST_REPLAY_CM, TrxHandle::S_MUST_REPLAY); add(TrxHandle::S_MUST_REPLAY, TrxHandle::S_REPLAYING); add(TrxHandle::S_REPLAYING, TrxHandle::S_COMMITTED); } } trans_map_builder_; size_t galera::TrxHandle::Mac::serialize(gu::byte_t* buf, size_t buflen, size_t offset) const { // header: // type: 1 byte // len: 1 byte return gu::serialize2(uint16_t(0), buf, buflen, offset); } size_t galera::TrxHandle::Mac::unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) { uint16_t hdr; offset = gu::unserialize2(buf, buflen, offset, hdr); switch ((hdr >> 8) & 0xff) { case 0: break; default: log_warn << "unrecognized mac type" << ((hdr >> 8) & 0xff); } // skip over the body offset += (hdr & 0xff); return offset; } size_t galera::TrxHandle::Mac::serial_size() const { return 2; // sizeof(uint16_t); // Hm, isn't is somewhat short for mac? } size_t galera::TrxHandle::serialize(gu::byte_t* buf, size_t buflen, size_t offset)const { if (new_version()) { assert(0); } // we don't use serialize for that uint32_t hdr((version_ << 24) | (write_set_flags_ & 0xff)); offset = gu::serialize4(hdr, buf, buflen, offset); offset = galera::serialize(source_id_, buf, buflen, offset); offset = gu::serialize8(conn_id_, buf, buflen, offset); offset = gu::serialize8(trx_id_, buf, buflen, offset); offset = gu::serialize8(last_seen_seqno_, buf, buflen, offset); offset = gu::serialize8(timestamp_, buf, buflen, offset); if (has_annotation()) { offset = gu::serialize4(annotation_, buf, buflen, offset); } if (has_mac()) { offset = mac_.serialize(buf, buflen, offset); } return offset; } size_t galera::TrxHandle::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset) { try { version_ = WriteSetNG::version(buf, buflen); switch (version_) { case 0: case 1: case 2: write_set_flags_ = buf[0]; write_set_.set_version(version_); offset = 4; offset = galera::unserialize(buf, buflen, offset, source_id_); offset = gu::unserialize8(buf, buflen, offset, conn_id_); offset = gu::unserialize8(buf, buflen, offset, trx_id_); offset = gu::unserialize8(buf, buflen, offset, last_seen_seqno_); assert(last_seen_seqno_ >= 0); offset = gu::unserialize8(buf, buflen, offset, timestamp_); if (has_annotation()) { offset = gu::unserialize4(buf, buflen, offset, annotation_); } if (has_mac()) { offset = mac_.unserialize(buf, buflen, offset); } set_write_set_buffer(buf + offset, buflen - offset); break; case 3: write_set_in_.read_buf (buf, buflen); write_set_flags_ = wsng_flags_to_trx_flags(write_set_in_.flags()); source_id_ = write_set_in_.source_id(); conn_id_ = write_set_in_.conn_id(); trx_id_ = write_set_in_.trx_id(); if (write_set_in_.certified()) { last_seen_seqno_ = WSREP_SEQNO_UNDEFINED; write_set_flags_ |= F_PREORDERED; } else { last_seen_seqno_ = write_set_in_.last_seen(); assert(last_seen_seqno_ >= 0); } timestamp_ = write_set_in_.timestamp(); break; default: gu_throw_error(EPROTONOSUPPORT); } return buflen; } catch (gu::Exception& e) { GU_TRACE(e); log_fatal << "Writeset deserialization failed: " << e.what() << std::endl << "WS flags: " << write_set_flags_ << std::endl << "Trx proto: " << version_ << std::endl << "Trx source: " << source_id_ << std::endl << "Trx conn_id: " << conn_id_ << std::endl << "Trx trx_id: " << trx_id_ << std::endl << "Trx last_seen: " << last_seen_seqno_; throw; } } size_t galera::TrxHandle::serial_size() const { assert (new_version() == false); return (4 // hdr + galera::serial_size(source_id_) + 8 // serial_size(trx.conn_id_) + 8 // serial_size(trx.trx_id_) + 8 // serial_size(trx.last_seen_seqno_) + 8 // serial_size(trx.timestamp_) + (has_annotation() ? gu::serial_size4(annotation_) : 0) + (has_mac() ? mac_.serial_size() : 0)); } void galera::TrxHandle::apply (void* recv_ctx, wsrep_apply_cb_t apply_cb, const wsrep_trx_meta_t& meta) const { wsrep_cb_status_t err(WSREP_CB_SUCCESS); if (new_version()) { const DataSetIn& ws(write_set_in_.dataset()); ws.rewind(); // make sure we always start from the beginning for (ssize_t i = 0; WSREP_CB_SUCCESS == err && i < ws.count(); ++i) { gu::Buf buf = ws.next(); err = apply_cb (recv_ctx, buf.ptr, buf.size, trx_flags_to_wsrep_flags(flags()), &meta); } } else { const gu::byte_t* buf(write_set_buffer().first); const size_t buf_len(write_set_buffer().second); size_t offset(0); while (offset < buf_len && WSREP_CB_SUCCESS == err) { // Skip key segment std::pair k( galera::WriteSet::segment(buf, buf_len, offset)); offset = k.first + k.second; // Data part std::pair d( galera::WriteSet::segment(buf, buf_len, offset)); offset = d.first + d.second; err = apply_cb (recv_ctx, buf + d.first, d.second, trx_flags_to_wsrep_flags(flags()), &meta); } assert(offset == buf_len); } if (gu_unlikely(err > 0)) { std::ostringstream os; os << "Failed to apply app buffer: seqno: " << global_seqno() << ", status: " << err; galera::ApplyException ae(os.str(), err); GU_TRACE(ae); throw ae; } return; } /* we don't care about any failures in applying unordered events */ void galera::TrxHandle::unordered(void* recv_ctx, wsrep_unordered_cb_t cb) const { if (new_version() && NULL != cb && write_set_in_.unrdset().count() > 0) { const DataSetIn& unrd(write_set_in_.unrdset()); for (int i(0); i < unrd.count(); ++i) { const gu::Buf data = unrd.next(); cb(recv_ctx, data.ptr, data.size); } } } percona-galera-3-3.8-3390/galera/src/trx_handle.hpp000066400000000000000000000606751244131713600217030ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_TRX_HANDLE_HPP #define GALERA_TRX_HANDLE_HPP #include "write_set.hpp" #include "mapped_buffer.hpp" #include "fsm.hpp" #include "key_data.hpp" // for append_key() #include "key_entry_os.hpp" #include "write_set_ng.hpp" #include "wsrep_api.h" #include "gu_mutex.hpp" #include "gu_atomic.hpp" #include "gu_datetime.hpp" #include "gu_unordered.hpp" #include "gu_utils.hpp" #include "gu_macros.hpp" #include "gu_mem_pool.hpp" #include namespace galera { static std::string const working_dir = "/tmp"; static int const WS_NG_VERSION = WriteSetNG::VER3; /* new WS version to be used */ class TrxHandle { public: /* signed int here is to detect SIZE < sizeof(TrxHandle) */ static int const LOCAL_STORAGE_SIZE = GU_PAGE_SIZE * 2; // 8K struct Params { std::string working_dir_; int version_; KeySet::Version key_format_; int max_write_set_size_; Params (const std::string& wdir, int ver, KeySet::Version kformat, int max_write_set_size = WriteSetNG::MAX_SIZE) : working_dir_(wdir), version_(ver), key_format_(kformat), max_write_set_size_(max_write_set_size) {} }; static const Params Defaults; enum Flags { F_COMMIT = 1 << 0, F_ROLLBACK = 1 << 1, F_OOC = 1 << 2, F_MAC_HEADER = 1 << 3, F_MAC_PAYLOAD = 1 << 4, F_ANNOTATION = 1 << 5, F_ISOLATION = 1 << 6, F_PA_UNSAFE = 1 << 7, F_PREORDERED = 1 << 8 }; static inline uint32_t wsrep_flags_to_trx_flags (uint32_t flags) { GU_COMPILE_ASSERT( WSREP_FLAG_COMMIT == int(F_COMMIT) && F_COMMIT == 1 && WSREP_FLAG_ROLLBACK == int(F_ROLLBACK) && F_ROLLBACK == 2, flags_dont_match1); uint32_t ret(flags & 0x03); // setting F_COMMIT|F_ROLLBACK in one go if (flags & WSREP_FLAG_ISOLATION) ret |= F_ISOLATION; if (flags & WSREP_FLAG_PA_UNSAFE) ret |= F_PA_UNSAFE; return ret; } static inline uint32_t trx_flags_to_wsrep_flags (uint32_t flags) { GU_COMPILE_ASSERT( WSREP_FLAG_COMMIT == int(F_COMMIT) && F_COMMIT == 1 && WSREP_FLAG_ROLLBACK == int(F_ROLLBACK) && F_ROLLBACK == 2, flags_dont_match2); uint32_t ret(flags & 0x03); // setting F_COMMIT|F_ROLLBACK in one go if (flags & F_ISOLATION) ret |= WSREP_FLAG_ISOLATION; if (flags & F_PA_UNSAFE) ret |= WSREP_FLAG_PA_UNSAFE; return ret; } static inline uint32_t wsng_flags_to_trx_flags (uint32_t flags) { GU_COMPILE_ASSERT( WriteSetNG::F_COMMIT == int(F_COMMIT) && F_COMMIT == 1 && WriteSetNG::F_ROLLBACK == int(F_ROLLBACK) && F_ROLLBACK == 2, flags_dont_match3); uint32_t ret(flags & 0x03); // setting F_COMMIT|F_ROLLBACK in one go if (flags & WriteSetNG::F_TOI) ret |= F_ISOLATION; if (flags & WriteSetNG::F_PA_UNSAFE) ret |= F_PA_UNSAFE; return ret; } bool has_mac() const { return ((write_set_flags_ & (F_MAC_HEADER | F_MAC_PAYLOAD)) != 0); } bool has_annotation() const /* shall return 0 for new writeset ver */ { return ((write_set_flags_ & F_ANNOTATION) != 0); } bool is_toi() const { return ((write_set_flags_ & F_ISOLATION) != 0); } bool pa_unsafe() const { return ((write_set_flags_ & F_PA_UNSAFE) != 0); } bool preordered() const { return ((write_set_flags_ & F_PREORDERED) != 0); } typedef enum { S_EXECUTING, S_MUST_ABORT, S_ABORTING, S_REPLICATING, S_CERTIFYING, S_MUST_CERT_AND_REPLAY, S_MUST_REPLAY_AM, // grab apply_monitor, commit_monitor, replay S_MUST_REPLAY_CM, // commit_monitor, replay S_MUST_REPLAY, // replay S_REPLAYING, S_APPLYING, // grabbing apply monitor, applying S_COMMITTING, // grabbing commit monitor, committing changes S_COMMITTED, S_ROLLED_BACK } State; class Transition { public: Transition(State const from, State const to) : from_(from), to_(to) { } State from() const { return from_; } State to() const { return to_; } bool operator==(Transition const& other) const { return (from_ == other.from_ && to_ == other.to_); } class Hash { public: size_t operator()(Transition const& tr) const { return (gu::HashValue(static_cast(tr.from_)) ^ gu::HashValue(static_cast(tr.to_))); } }; private: State from_; State to_; }; typedef FSM Fsm; static Fsm::TransMap trans_map_; // Placeholder for message authentication code class Mac { public: Mac() { } ~Mac() { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); size_t serial_size() const; }; /* slave trx factory */ typedef gu::MemPool SlavePool; static TrxHandle* New(SlavePool& pool) { assert(pool.buf_size() == sizeof(TrxHandle)); void* const buf(pool.acquire()); return new(buf) TrxHandle(pool); } /* local trx factory */ typedef gu::MemPool LocalPool; static TrxHandle* New(LocalPool& pool, const Params& params, const wsrep_uuid_t& source_id, wsrep_conn_id_t conn_id, wsrep_trx_id_t trx_id) { size_t const buf_size(pool.buf_size()); assert(buf_size >= (sizeof(TrxHandle) + sizeof(WriteSetOut))); void* const buf(pool.acquire()); return new(buf) TrxHandle(pool, params, source_id, conn_id, trx_id, static_cast(buf) + sizeof(TrxHandle), buf_size - sizeof(TrxHandle)); } void lock() const { mutex_.lock(); } void unlock() const { mutex_.unlock(); } int version() const { return version_; } bool new_version() const { return version() >= WS_NG_VERSION; } const wsrep_uuid_t& source_id() const { return source_id_; } wsrep_trx_id_t trx_id() const { return trx_id_; } wsrep_conn_id_t conn_id() const { return conn_id_; } void set_conn_id(wsrep_conn_id_t conn_id) { conn_id_ = conn_id; } bool is_local() const { return local_; } bool is_certified() const { return certified_; } void mark_certified() { if (new_version()) { int dw(0); if (gu_likely(depends_seqno_ >= 0)) { dw = global_seqno_ - depends_seqno_; } write_set_in_.set_seqno(global_seqno_, dw); } certified_ = true; } bool is_committed() const { return committed_; } void mark_committed() { committed_ = true; } void set_received (const void* action, wsrep_seqno_t seqno_l, wsrep_seqno_t seqno_g) { action_ = action; local_seqno_ = seqno_l; global_seqno_ = seqno_g; if (write_set_flags_ & F_PREORDERED) { last_seen_seqno_ = global_seqno_ - 1; } } void set_last_seen_seqno(wsrep_seqno_t last_seen_seqno) { assert (last_seen_seqno >= 0); if (new_version()) write_set_out().set_last_seen(last_seen_seqno); last_seen_seqno_ = last_seen_seqno; } void set_depends_seqno(wsrep_seqno_t seqno_lt) { depends_seqno_ = seqno_lt; } State state() const { return state_(); } void set_state(State state) { state_.shift_to(state); } long gcs_handle() const { return gcs_handle_; } void set_gcs_handle(long gcs_handle) { gcs_handle_ = gcs_handle; } const void* action() const { return action_; } wsrep_seqno_t local_seqno() const { return local_seqno_; } wsrep_seqno_t global_seqno() const { return global_seqno_; } wsrep_seqno_t last_seen_seqno() const { return last_seen_seqno_; } wsrep_seqno_t depends_seqno() const { return depends_seqno_; } uint32_t flags() const { return write_set_flags_; } void set_flags(uint32_t flags) { write_set_flags_ = flags; if (new_version()) { uint16_t ws_flags(flags & 0x07); if (flags & F_ISOLATION) ws_flags |= WriteSetNG::F_TOI; if (flags & F_PA_UNSAFE) ws_flags |= WriteSetNG::F_PA_UNSAFE; write_set_out().set_flags(ws_flags); } } void append_key(const KeyData& key) { /*! protection against protocol change during trx lifetime */ if (key.proto_ver != version_) { gu_throw_error(EINVAL) << "key version '" << key.proto_ver << "' does not match to trx version' " << version_ << "'"; } if (new_version()) { write_set_out().append_key(key); } else { write_set_.append_key(key); } } void append_data(const void* data, const size_t data_len, wsrep_data_type_t type, bool store) { if (new_version()) { switch (type) { case WSREP_DATA_ORDERED: write_set_out().append_data(data, data_len, store); break; case WSREP_DATA_UNORDERED: write_set_out().append_unordered(data, data_len, store); break; case WSREP_DATA_ANNOTATION: write_set_out().append_annotation(data, data_len, store); break; } } else { switch (type) { case WSREP_DATA_ORDERED: write_set_.append_data(data, data_len); break; case WSREP_DATA_UNORDERED: // just ignore unordered for compatibility with // previous versions break; case WSREP_DATA_ANNOTATION: append_annotation(reinterpret_cast(data), data_len); break; } } } static const size_t max_annotation_size_ = (1 << 16); void append_annotation(const gu::byte_t* buf, size_t buf_len) { buf_len = std::min(buf_len, max_annotation_size_ - annotation_.size()); annotation_.insert(annotation_.end(), buf, buf + buf_len); } const gu::Buffer& annotation() const { return annotation_; } const WriteSet& write_set() const { return write_set_; } size_t prepare_write_set_collection() { if (new_version()) assert(0); size_t offset; if (write_set_collection_.empty() == true) { offset = serial_size(); write_set_collection_.resize(offset); } else { offset = write_set_collection_.size(); } (void)serialize(&write_set_collection_[0], offset, 0); return offset; } void append_write_set(const void* data, size_t data_len) { if (new_version()) assert(0); const size_t offset(prepare_write_set_collection()); write_set_collection_.resize(offset + data_len); std::copy(reinterpret_cast(data), reinterpret_cast(data) + data_len, &write_set_collection_[0] + offset); } void append_write_set(const gu::Buffer& ws) { if (new_version()) { /* trx->unserialize() must have done all the job */ } else { const size_t offset(prepare_write_set_collection()); write_set_collection_.resize(offset + ws.size()); std::copy(ws.begin(), ws.end(), &write_set_collection_[0] + offset); } } MappedBuffer& write_set_collection() { return write_set_collection_; } void set_write_set_buffer(const gu::byte_t* buf, size_t buf_len) { write_set_buffer_.first = buf; write_set_buffer_.second = buf_len; } std::pair write_set_buffer() const { // If external write set buffer location not specified, // return location from write_set_collection_. This is still // needed for unit tests and IST which don't use GCache // storage. if (write_set_buffer_.first == 0) { size_t off(serial_size()); if (write_set_collection_.size() < off) { gu_throw_fatal << "Write set buffer not populated"; } return std::make_pair(&write_set_collection_[0] + off, write_set_collection_.size() - off); } return write_set_buffer_; } bool empty() const { if (new_version()) { return write_set_out().is_empty(); } else { return (write_set_.empty() == true && write_set_collection_.size() <= serial_size()); } } void flush(size_t mem_limit) { if (new_version()) { assert(0); return; } if (write_set_.get_key_buf().size() + write_set_.get_data().size() > mem_limit || mem_limit == 0) { gu::Buffer buf(write_set_.serial_size()); (void)write_set_.serialize(&buf[0], buf.size(), 0); append_write_set(buf); write_set_.clear(); } } void clear() { if (new_version()) { return; } write_set_.clear(); write_set_collection_.clear(); } void ref() { ++refcnt_; } void unref() { if (refcnt_.sub_and_fetch(1) == 0) // delete and return to pool { void* const ptr(this); gu::MemPool& mp(mem_pool_); this->~TrxHandle(); mp.recycle(ptr); } } size_t refcnt() const { return refcnt_(); } WriteSetOut& write_set_out() { /* WriteSetOut is a temporary object needed only at the writeset * collection stage. Since it may allocate considerable resources * we dont't want it to linger as long as TrxHandle is needed and * want to destroy it ASAP. So it is located immediately after * TrxHandle in the buffer allocated by TrxHandleWithStore. * I'll be damned if this+1 is not sufficiently well aligned. */ assert(new_version()); assert(wso_); return *reinterpret_cast(this + 1); } const WriteSetOut& write_set_out() const { return write_set_out(); } const WriteSetIn& write_set_in () const { return write_set_in_; } void apply(void* recv_ctx, wsrep_apply_cb_t apply_cb, const wsrep_trx_meta_t& meta) const /* throws */; void unordered(void* recv_ctx, wsrep_unordered_cb_t apply_cb) const; void verify_checksum() const /* throws */ { write_set_in_.verify_checksum(); } void update_stats(gu::Atomic& kc, gu::Atomic& kb, gu::Atomic& db, gu::Atomic& ub) { assert(new_version()); kc += write_set_in_.keyset().count(); kb += write_set_in_.keyset().size(); db += write_set_in_.dataset().size(); ub += write_set_in_.unrdset().size(); } bool exit_loop() const { return exit_loop_; } void set_exit_loop(bool x) { exit_loop_ |= x; } typedef gu::UnorderedMap, KeyEntryPtrHash, KeyEntryPtrEqualAll> CertKeySet; CertKeySet& cert_keys() { return cert_keys_; } size_t serial_size() const; size_t serialize (gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); void release_write_set_out() { if (gu_likely(new_version())) { assert(wso_); write_set_out().~WriteSetOut(); wso_ = false; } } private: /* slave trx ctor */ explicit TrxHandle(gu::MemPool& mp) : source_id_ (WSREP_UUID_UNDEFINED), conn_id_ (-1), trx_id_ (-1), mutex_ (), write_set_collection_(Defaults.working_dir_), state_ (&trans_map_, S_EXECUTING), local_seqno_ (WSREP_SEQNO_UNDEFINED), global_seqno_ (WSREP_SEQNO_UNDEFINED), last_seen_seqno_ (WSREP_SEQNO_UNDEFINED), depends_seqno_ (WSREP_SEQNO_UNDEFINED), timestamp_ (), write_set_ (Defaults.version_), write_set_in_ (), annotation_ (), cert_keys_ (), write_set_buffer_ (0, 0), mem_pool_ (mp), action_ (0), gcs_handle_ (-1), version_ (Defaults.version_), refcnt_ (1), write_set_flags_ (0), local_ (false), certified_ (false), committed_ (false), exit_loop_ (false), wso_ (false), mac_ () {} /* local trx ctor */ TrxHandle(gu::MemPool& mp, const Params& params, const wsrep_uuid_t& source_id, wsrep_conn_id_t conn_id, wsrep_trx_id_t trx_id, gu::byte_t* reserved, size_t reserved_size) : source_id_ (source_id), conn_id_ (conn_id), trx_id_ (trx_id), mutex_ (), write_set_collection_(params.working_dir_), state_ (&trans_map_, S_EXECUTING), local_seqno_ (WSREP_SEQNO_UNDEFINED), global_seqno_ (WSREP_SEQNO_UNDEFINED), last_seen_seqno_ (WSREP_SEQNO_UNDEFINED), depends_seqno_ (WSREP_SEQNO_UNDEFINED), timestamp_ (gu_time_calendar()), write_set_ (params.version_), write_set_in_ (), annotation_ (), cert_keys_ (), write_set_buffer_ (0, 0), mem_pool_ (mp), action_ (0), gcs_handle_ (-1), version_ (params.version_), refcnt_ (1), write_set_flags_ (0), local_ (true), certified_ (false), committed_ (false), exit_loop_ (false), wso_ (new_version()), mac_ () { init_write_set_out(params, reserved, reserved_size); } ~TrxHandle() { if (wso_) release_write_set_out(); } void init_write_set_out(const Params& params, gu::byte_t* store, size_t store_size) { if (wso_) { assert(store); assert(store_size > sizeof(WriteSetOut)); WriteSetOut* wso = &write_set_out(); assert(static_cast(wso) == static_cast(store)); new (wso) WriteSetOut (params.working_dir_, trx_id_, params.key_format_, store + sizeof(WriteSetOut), store_size - sizeof(WriteSetOut), 0, WriteSetNG::MAX_VERSION, DataSet::MAX_VERSION, DataSet::MAX_VERSION, params.max_write_set_size_); } } TrxHandle(const TrxHandle&); void operator=(const TrxHandle& other); wsrep_uuid_t source_id_; wsrep_conn_id_t conn_id_; wsrep_trx_id_t trx_id_; mutable gu::Mutex mutex_; MappedBuffer write_set_collection_; FSM state_; wsrep_seqno_t local_seqno_; wsrep_seqno_t global_seqno_; wsrep_seqno_t last_seen_seqno_; wsrep_seqno_t depends_seqno_; int64_t timestamp_; WriteSet write_set_; WriteSetIn write_set_in_; gu::Buffer annotation_; CertKeySet cert_keys_; // Write set buffer location if stored outside TrxHandle. std::pair write_set_buffer_; gu::MemPool& mem_pool_; const void* action_; long gcs_handle_; int version_; gu::Atomic refcnt_; uint32_t write_set_flags_; bool local_; bool certified_; bool committed_; bool exit_loop_; bool wso_; Mac mac_; friend class Wsdb; friend class Certification; friend std::ostream& operator<<(std::ostream& os, const TrxHandle& trx); friend class TrxHandleWithStore; }; /* class TrxHandle */ std::ostream& operator<<(std::ostream& os, TrxHandle::State s); class TrxHandleLock { public: TrxHandleLock(TrxHandle& trx) : trx_(trx) { trx_.lock(); } ~TrxHandleLock() { trx_.unlock(); } private: TrxHandle& trx_; }; /* class TrxHnadleLock */ template class Unref2nd { public: void operator()(T& t) const { t.second->unref(); } }; } /* namespace galera*/ #endif // GALERA_TRX_HANDLE_HPP percona-galera-3-3.8-3390/galera/src/uuid.hpp000066400000000000000000000030121244131713600204770ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_UUID_HPP #define GALERA_UUID_HPP #include "wsrep_api.h" #include "gu_uuid.hpp" #include namespace galera { inline const gu_uuid_t& to_gu_uuid(const wsrep_uuid_t& uuid) { return *reinterpret_cast(&uuid); } inline gu_uuid_t& to_gu_uuid(wsrep_uuid_t& uuid) { return *reinterpret_cast(&uuid); } inline bool operator==(const wsrep_uuid_t& a, const wsrep_uuid_t& b) { return to_gu_uuid(a) == to_gu_uuid(b); } inline bool operator!=(const wsrep_uuid_t& a, const wsrep_uuid_t& b) { return !(a == b); } inline std::ostream& operator<<(std::ostream& os, const wsrep_uuid_t& uuid) { return os << to_gu_uuid(uuid); } inline std::istream& operator>>(std::istream& is, wsrep_uuid_t& uuid) { return is >> to_gu_uuid(uuid); } inline size_t serial_size(const wsrep_uuid_t& uuid) { return gu_uuid_serial_size(to_gu_uuid(uuid)); } inline size_t serialize(const wsrep_uuid_t& uuid, gu::byte_t* buf, size_t buflen, size_t offset) { return gu_uuid_serialize(to_gu_uuid(uuid), buf, buflen, offset); } inline size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, wsrep_uuid_t& uuid) { return gu_uuid_unserialize(buf, buflen, offset, to_gu_uuid(uuid)); } } #endif // GALERA_UUID_HPP percona-galera-3-3.8-3390/galera/src/write_set.cpp000066400000000000000000000063741244131713600215470ustar00rootroot00000000000000// // Copyright (C) 2010-2013 Codership Oy // #include "write_set.hpp" #include "gu_serialize.hpp" #include "gu_logger.hpp" size_t galera::WriteSet::serialize(gu::byte_t* buf, size_t buf_len, size_t offset) const { offset = gu::serialize4(keys_, buf, buf_len, offset); offset = gu::serialize4(data_, buf, buf_len, offset); return offset; } size_t galera::WriteSet::unserialize(const gu::byte_t* buf, size_t buf_len, size_t offset) { keys_.clear(); offset = gu::unserialize4(buf, buf_len, offset, keys_); offset = gu::unserialize4(buf, buf_len, offset, data_); return offset; } size_t galera::WriteSet::serial_size() const { return (gu::serial_size4(keys_) + gu::serial_size4(data_)); } std::pair galera::WriteSet::segment(const gu::byte_t* buf, size_t buf_len, size_t offset) { uint32_t data_len; offset = gu::unserialize4(buf, buf_len, offset, data_len); if (gu_unlikely(offset + data_len > buf_len)) { #ifdef NDEBUG gu_throw_error(EMSGSIZE); #else gu_throw_error(EMSGSIZE) << "offset: " << offset << ", data_len: " << data_len << ", buf_len: " << buf_len; #endif /* NDEBUG */ } return std::pair(offset, data_len); } size_t galera::WriteSet::keys(const gu::byte_t* buf, size_t buf_len, size_t offset, int version, KeySequence& ks) { std::pair seg(segment(buf, buf_len, offset)); offset = seg.first; const size_t seg_end(seg.first + seg.second); assert(seg_end <= buf_len); while (offset < seg_end) { KeyOS key(version); if ((offset = key.unserialize(buf, buf_len, offset)) == 0) { gu_throw_fatal << "failed to unserialize key"; } ks.push_back(key); } assert(offset == seg_end); return offset; } void galera::WriteSet::append_key(const KeyData& kd) { KeyOS key (kd.proto_ver, kd.parts, kd.parts_num, (kd.shared() ? galera::KeyOS::F_SHARED : 0) ); const size_t hash(key.hash()); std::pair range(key_refs_.equal_range(hash)); for (KeyRefMap::const_iterator i(range.first); i != range.second; ++i) { KeyOS cmp(version_); (void)cmp.unserialize(&keys_[0], keys_.size(), i->second); if (key == cmp && key.flags() == cmp.flags()) return; } size_t key_size(key.serial_size()); size_t offset(keys_.size()); keys_.resize(offset + key_size); (void)key.serialize(&keys_[0], keys_.size(), offset); (void)key_refs_.insert(std::make_pair(hash, offset)); } void galera::WriteSet::get_keys(KeySequence& s) const { size_t offset(0); while (offset < keys_.size()) { KeyOS key(version_); if ((offset = key.unserialize(&keys_[0], keys_.size(), offset)) == 0) { gu_throw_fatal << "failed to unserialize key"; } s.push_back(key); } assert(offset == keys_.size()); } percona-galera-3-3.8-3390/galera/src/write_set.hpp000066400000000000000000000041721244131713600215460ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #ifndef GALERA_WRITE_SET_HPP #define GALERA_WRITE_SET_HPP #include "key_os.hpp" #include "key_data.hpp" #include "wsrep_api.h" #include "gu_buffer.hpp" #include "gu_logger.hpp" #include "gu_unordered.hpp" #include #include #include namespace galera { class WriteSet { public: typedef std::deque KeySequence; WriteSet(int version) : version_(version), keys_(), key_refs_(), data_() { } void set_version(int version) { version_ = version; } const gu::Buffer& get_data() const { return data_; } void append_key(const KeyData&); void append_data(const void*data, size_t data_len) { data_.reserve(data_.size() + data_len); data_.insert(data_.end(), reinterpret_cast(data), reinterpret_cast(data) + data_len); } void get_keys(KeySequence&) const; const gu::Buffer& get_key_buf() const { return keys_; } bool empty() const { return (data_.size() == 0 && keys_.size() == 0); } void clear() { keys_.clear(), key_refs_.clear(), data_.clear(); } // Return offset to beginning of key or data segment and length // of that segment static std::pair segment(const gu::byte_t*, size_t, size_t); // Scan key sequence from buffer, return offset from the beginning of // buffer after scan. static size_t keys(const gu::byte_t*, size_t, size_t, int, KeySequence&); size_t serialize(gu::byte_t*, size_t, size_t) const; size_t unserialize(const gu::byte_t*, size_t, size_t); size_t serial_size() const; private: typedef gu::UnorderedMultimap KeyRefMap; int version_; gu::Buffer keys_; KeyRefMap key_refs_; gu::Buffer data_; }; } #endif // GALERA_WRITE_SET_HPP percona-galera-3-3.8-3390/galera/src/write_set_ng.cpp000066400000000000000000000224071244131713600222260ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // #include "write_set_ng.hpp" #include "gu_time.h" #include #include namespace galera { WriteSetNG::Header::Offsets::Offsets ( int a01, int a02, int a03, int a04, int a05, int a06, int a07, int a08, int a09, int a10, int a11, int a12 ) : header_ver_ (a01), header_size_ (a02), sets_ (a03), flags_ (a04), pa_range_ (a05), last_seen_ (a06), seqno_ (a07), timestamp_ (a08), source_id_ (a09), conn_id_ (a10), trx_id_ (a11), crc_ (a12) {} WriteSetNG::Header::Offsets const WriteSetNG::Header::V3 ( V3_HEADER_VERS_OFF, V3_HEADER_SIZE_OFF, V3_SETS_OFF, V3_FLAGS_OFF, V3_PA_RANGE_OFF, V3_LAST_SEEN_OFF, V3_SEQNO_OFF, V3_TIMESTAMP_OFF, V3_SOURCE_ID_OFF, V3_CONN_ID_OFF, V3_TRX_ID_OFF, V3_CRC_OFF ); size_t WriteSetNG::Header::gather (KeySet::Version const kver, DataSet::Version const dver, bool unord, bool annot, uint16_t const flags, const wsrep_uuid_t& source, const wsrep_conn_id_t& conn, const wsrep_trx_id_t& trx, GatherVector& out) { GU_COMPILE_ASSERT(MAX_VERSION <= 15, header_version_too_big); GU_COMPILE_ASSERT(KeySet::MAX_VERSION <= 15, keyset_version_too_big); GU_COMPILE_ASSERT(DataSet::MAX_VERSION <= 3, dataset_version_too_big); assert (uint(ver_) <= MAX_VERSION); assert (uint(kver) <= KeySet::MAX_VERSION); assert (uint(dver) <= DataSet::MAX_VERSION); local_[V3_MAGIC_OFF] = MAGIC_BYTE; local_[V3_HEADER_VERS_OFF] = (version() << 4) | VER3; local_[V3_HEADER_SIZE_OFF] = size(); local_[V3_SETS_OFF] = (kver << 4) | (dver << 2) | (unord * V3_UNORD_FLAG) | (annot * V3_ANNOT_FLAG); uint16_t* const fl(reinterpret_cast(local_ + V3_FLAGS_OFF)); uint16_t* const pa(reinterpret_cast(local_ + V3_PA_RANGE_OFF)); *fl = gu::htog(flags); *pa = 0; // certified ws will have dep. window of at least 1 wsrep_uuid_t* const sc(reinterpret_cast(local_ + V3_SOURCE_ID_OFF)); *sc = source; uint64_t* const cn(reinterpret_cast(local_ + V3_CONN_ID_OFF)); uint64_t* const tx(reinterpret_cast(local_ + V3_TRX_ID_OFF)); *cn = gu::htog(conn); *tx = gu::htog(trx); gu::Buf const buf = { ptr_, size() }; out->push_back(buf); return buf.size; } void WriteSetNG::Header::set_last_seen(const wsrep_seqno_t& last_seen) { assert (ptr_); assert (size_ > 0); uint64_t* const ls (reinterpret_cast(ptr_ +V3_LAST_SEEN_OFF)); uint64_t* const ts (reinterpret_cast(ptr_ +V3_TIMESTAMP_OFF)); *ls = gu::htog(last_seen); *ts = gu::htog(gu_time_monotonic()); update_checksum (ptr_, size() - V3_CHECKSUM_SIZE); } void WriteSetNG::Header::set_seqno(const wsrep_seqno_t& seqno, uint16_t const pa_range) { assert (ptr_); assert (size_ > 0); assert (seqno > 0); uint16_t* const pa(reinterpret_cast(ptr_ + V3_PA_RANGE_OFF)); uint64_t* const sq(reinterpret_cast(ptr_ + V3_SEQNO_OFF)); *pa = gu::htog(pa_range); *sq = gu::htog(seqno); update_checksum (ptr_, size() - V3_CHECKSUM_SIZE); } gu::Buf WriteSetNG::Header::copy(bool const include_keys, bool const include_unrd) const { assert (ptr_ != &local_[0]); assert (size_t(size()) <= sizeof(local_)); gu::byte_t* const lptr(&local_[0]); ::memcpy (lptr, ptr_, size_); gu::byte_t const mask(0x0c | (0xf0 * include_keys) | (0x02 * include_unrd)); lptr[V3_SETS_OFF] &= mask; // zero up versions of non-included sets update_checksum (lptr, size() - V3_CHECKSUM_SIZE); gu::Buf ret = { lptr, size_ }; return ret; } void WriteSetNG::Header::Checksum::verify (Version ver, const void* const ptr, ssize_t const hsize) { assert (hsize > 0); type_t check(0), hcheck(0); size_t const csize(hsize - V3_CHECKSUM_SIZE); compute (ptr, csize, check); hcheck = *(reinterpret_cast( reinterpret_cast(ptr) + csize )); if (gu_likely(check == hcheck)) return; gu_throw_error (EINVAL) << "Header checksum mismatch: computed " << std::hex << std::setfill('0') << std::setw(sizeof(check) << 1) << check << ", found " << std::setw(sizeof(hcheck) << 1) << hcheck; } const char WriteSetOut::keys_suffix[] = "_keys"; const char WriteSetOut::data_suffix[] = "_data"; const char WriteSetOut::unrd_suffix[] = "_unrd"; const char WriteSetOut::annt_suffix[] = "_annt"; void WriteSetIn::init (ssize_t const st) { assert(false == check_thr_); const gu::byte_t* const pptr (header_.payload()); ssize_t const psize(size_ - header_.size()); assert (psize >= 0); KeySet::Version const kver(header_.keyset_ver()); if (kver != KeySet::EMPTY) gu_trace(keys_.init (kver, pptr, psize)); assert (false == check_); assert (false == check_thr_); if (gu_likely(st > 0)) /* checksum enforced */ { if (size_ >= st) { /* buffer too big, start checksumming in background */ int const err(pthread_create (&check_thr_id_, NULL, checksum_thread, this)); if (gu_likely(0 == err)) { check_thr_ = true; return; } log_warn << "Starting checksum thread failed: " << err << '(' << ::strerror(err) << ')'; /* fall through to checksum in foreground */ } checksum(); checksum_fin(); } else /* checksum skipped, pretend it's alright */ { check_ = true; } } void WriteSetIn::checksum() { const gu::byte_t* pptr (header_.payload()); ssize_t psize(size_ - header_.size()); assert (psize >= 0); try { if (keys_.size() > 0) { gu_trace(keys_.checksum()); psize -= keys_.size(); assert (psize >= 0); pptr += keys_.size(); } DataSet::Version const dver(header_.dataset_ver()); if (gu_likely(dver != DataSet::EMPTY)) { assert (psize > 0); gu_trace(data_.init(dver, pptr, psize)); gu_trace(data_.checksum()); size_t tmpsize(data_.size()); psize -= tmpsize; pptr += tmpsize; assert (psize >= 0); if (header_.has_unrd()) { gu_trace(unrd_.init(dver, pptr, psize)); gu_trace(unrd_.checksum()); size_t tmpsize(unrd_.size()); psize -= tmpsize; pptr += tmpsize; } if (header_.has_annt()) { annt_ = new DataSetIn(); gu_trace(annt_->init(dver, pptr, psize)); // we don't care for annotation checksum - it is not a reason // to throw an exception and abort execution // gu_trace(annt_->checksum()); #ifndef NDEBUG psize -= annt_->size(); #endif } } #ifndef NDEBUG assert (psize == 0); #endif check_ = true; } catch (std::exception& e) { log_error << e.what(); } catch (...) { log_error << "Non-standard exception in WriteSet::checksum()"; } } void WriteSetIn::write_annotation(std::ostream& os) const { annt_->rewind(); ssize_t const count(annt_->count()); for (ssize_t i = 0; os.good() && i < count; ++i) { gu::Buf abuf = annt_->next(); os.write(static_cast(abuf.ptr), abuf.size); } } size_t WriteSetIn::gather(GatherVector& out, bool include_keys, bool include_unrd) const { if (include_keys && include_unrd) { gu::Buf buf = { header_.ptr(), size_ }; out->push_back(buf); return size_; } else { out->reserve(out->size() + 4); gu::Buf buf(header_.copy(include_keys, include_unrd)); out->push_back(buf); size_t ret(buf.size); if (include_keys) { buf = keys_.buf(); out->push_back(buf); ret += buf.size; } buf = data_.buf(); out->push_back (buf); ret += buf.size; if (include_unrd) { buf = unrd_.buf(); out->push_back(buf); ret += buf.size; } if (annotated()) { buf = annt_->buf(); out->push_back (buf); ret += buf.size; } return ret; } } } /* namespace galera */ percona-galera-3-3.8-3390/galera/src/write_set_ng.hpp000066400000000000000000000647011244131713600222360ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // /* * Planned writeset composition (not to scale): * * [WS header][ key set ][ data set ][ unordered set ] * * WS header contains common info: total size, set versions etc. * Key set and data set are always present, unordered set is optional. */ #ifndef GALERA_WRITE_SET_NG_HPP #define GALERA_WRITE_SET_NG_HPP #include "wsrep_api.h" #include "key_set.hpp" #include "data_set.hpp" #include "gu_serialize.hpp" #include "gu_vector.hpp" #include #include #include #include namespace galera { class WriteSetNG { public: static int const MAX_SIZE = 0x7fffffff; static int const MAX_PA_RANGE = 0x0000ffff; enum Version { VER3 = 3 }; /* Max header version that we can understand */ static Version const MAX_VERSION = VER3; /* Parses beginning of the header to detect writeset version and * returns it as raw integer for backward compatibility * static Version version(int v) will convert it to enum */ static int version(const void* const buf, size_t const buflen) { if (gu_likely(buflen >= 4)) { const gu::byte_t* const b(static_cast(buf)); if (b[0] == Header::MAGIC_BYTE && b[1] >= ((VER3 << 4) | VER3) && b[2] >= 32 /* header size will hardly ever go below 32 */) { int const min_ver(b[1] & 0x0f); int const max_ver(b[1] >> 4); if (min_ver <= max_ver) /* sanity check */ { /* supported situations: return max supported version */ if (max_ver < MAX_VERSION) return max_ver; if (min_ver <= MAX_VERSION) return MAX_VERSION; /* unsupported situation: minimum required version is * greater than maximum known */ return min_ver; } } else if (0 == b[1] && 0 == b[2] && b[3] <= 2) { /* header from 2.x and before */ return b[3]; } /* unrecognized header, fall through to error */ } return -1; } static Version version(int v) { switch (v) { case VER3: return VER3; } gu_throw_error (EPROTO) << "Unrecognized writeset version: " << v; } /* These flags should be fixed to wire protocol version and so * technically can't be initialized to WSREP_FLAG_xxx macros as the * latter may arbitrarily change. */ enum Flags { F_COMMIT = 1 << 0, F_ROLLBACK = 1 << 1, F_TOI = 1 << 2, F_PA_UNSAFE = 1 << 3, F_COMMUTATIVE = 1 << 4, F_NATIVE = 1 << 5 }; /* this takes care of converting wsrep API flags to on-the-wire flags */ static uint32_t wsrep_flags_to_ws_flags (uint32_t const flags); typedef gu::RecordSet::GatherVector GatherVector; /* TODO: separate metadata access from physical representation in * future versions */ class Header { public: static unsigned char const MAGIC_BYTE = 'G'; static Version version(const gu::Buf& buf) { /* the following will throw if version is not supported */ return WriteSetNG::version (WriteSetNG::version(buf.ptr, buf.size)); } static unsigned char size(Version ver) { switch (ver) { case VER3: return V3_SIZE; } log_fatal << "Unknown writeset version: " << ver; abort(); // want to dump core right here } /* This is for WriteSetOut */ explicit Header (Version ver) : local_(), ptr_(local_), ver_(ver), size_(size(ver)), chksm_() { assert (size_t(size_) <= sizeof(local_)); } size_t gather (KeySet::Version kver, DataSet::Version const dver, bool unord, bool annot, uint16_t flags, const wsrep_uuid_t& source, const wsrep_conn_id_t& conn, const wsrep_trx_id_t& trx, GatherVector& out); /* records last_seen, timestamp and CRC before replication */ void set_last_seen (const wsrep_seqno_t& ls); /* records partial seqno, pa_range, timestamp and CRC before * replication (for preordered events)*/ void set_preordered (uint16_t pa_range) { uint16_t* const pa(reinterpret_cast (ptr_ + V3_PA_RANGE_OFF)); *pa = gu::htog(pa_range); set_last_seen (0); } /* This is for WriteSetIn */ explicit Header (const gu::Buf& buf) : local_(), ptr_ (reinterpret_cast( const_cast(buf.ptr))), ver_ (version(buf)), size_ (check_size(ver_, ptr_, buf.size)), chksm_(ver_, ptr_, size_) {} Header () : local_(), ptr_(NULL), ver_(), size_(0), chksm_() {} /* for late WriteSetIn initialization */ void read_buf (const gu::Buf& buf) { ver_ = version(buf); ptr_ = reinterpret_cast(const_cast(buf.ptr)); size_ = check_size (ver_, ptr_, buf.size); Checksum::verify(ver_, ptr_, size_); } Version version() const { return ver_; } unsigned char size() const { return size_; } const gu::byte_t* ptr() const { return ptr_; } KeySet::Version keyset_ver() const { return KeySet::version((ptr_[V3_SETS_OFF] & 0xf0) >> 4); } bool has_keys() const { return keyset_ver() != KeySet::EMPTY; } bool has_unrd() const { return (ptr_[V3_SETS_OFF] & V3_UNORD_FLAG); } bool has_annt() const { return (ptr_[V3_SETS_OFF] & V3_ANNOT_FLAG); } DataSet::Version dataset_ver() const { return DataSet::version((ptr_[V3_SETS_OFF] & 0x0c) >> 2); } DataSet::Version unrdset_ver() const { return has_unrd() ? dataset_ver() : DataSet::EMPTY; } DataSet::Version anntset_ver() const { return has_annt() ? dataset_ver() : DataSet::EMPTY; } uint16_t flags() const { return gu::gtoh( *(reinterpret_cast(ptr_ + V3_FLAGS_OFF)) ); } uint16_t pa_range() const { return gu::gtoh( *(reinterpret_cast(ptr_ + V3_PA_RANGE_OFF)) ); } wsrep_seqno_t last_seen() const { assert (pa_range() == 0); return seqno_priv(); } wsrep_seqno_t seqno() const { assert (pa_range() > 0); return seqno_priv(); } long long timestamp() const { return gu::gtoh( *(reinterpret_cast(ptr_+ V3_TIMESTAMP_OFF)) ); } const wsrep_uuid_t& source_id() const { return *(reinterpret_cast (ptr_ + V3_SOURCE_ID_OFF)); } wsrep_trx_id_t conn_id() const { return gu::gtoh( *(reinterpret_cast(ptr_ + V3_CONN_ID_OFF)) ); } wsrep_trx_id_t trx_id() const { return gu::gtoh( *(reinterpret_cast(ptr_ + V3_TRX_ID_OFF)) ); } const gu::byte_t* payload() const { return ptr_ + size(); } /* to set seqno and parallel applying range after certification */ void set_seqno(const wsrep_seqno_t& seqno, uint16_t pa_range); gu::Buf copy(bool include_keys, bool include_unrd) const; private: static ssize_t check_size (Version const ver, const gu::byte_t* const buf, ssize_t const bufsize) { assert (bufsize > 4); ssize_t const hsize(buf[V3_HEADER_SIZE_OFF]); if (gu_unlikely(hsize > bufsize)) { gu_throw_error (EMSGSIZE) << "Input buffer size " << bufsize << " smaller than header size " << hsize; } return hsize; } static int const V3_CHECKSUM_SIZE = 8; class Checksum { public: typedef uint64_t type_t; /* produce value (corrected for endianness) */ static void compute (const void* ptr, size_t size, type_t& value) { gu::FastHash::digest (ptr, size, value); value = gu::htog(value); } static void verify (Version ver, const void* ptr, ssize_t size); Checksum () {} Checksum (Version ver, const void* ptr, ssize_t size) { verify (ver, ptr, size); } private: GU_COMPILE_ASSERT(sizeof(type_t) == V3_CHECKSUM_SIZE, uhoh); }; static unsigned char const V3_ANNOT_FLAG = 0x01; static unsigned char const V3_UNORD_FLAG = 0x02; /* Fist 8 bytes of header: 0: 'G' - "magic" byte 1: bits 4-7: header version bits 0-3: minimum compatible version 2: header size (payload offset) 3: bits 4-7: keyset version bits 2-3: dataset version bit 1: has unordered set bit 0: has annotation 4-5: flags 6-7: PA range all multibyte integers are in little-endian encoding */ static int const V3_MAGIC_OFF = 0; static int const V3_HEADER_VERS_OFF = V3_MAGIC_OFF + 1; static int const V3_HEADER_SIZE_OFF = V3_HEADER_VERS_OFF + 1; static int const V3_SETS_OFF = V3_HEADER_SIZE_OFF + 1; static int const V3_FLAGS_OFF = V3_SETS_OFF + 1; static int const V3_PA_RANGE_OFF = V3_FLAGS_OFF + 2; static int const V3_LAST_SEEN_OFF = V3_PA_RANGE_OFF + 2; static int const V3_SEQNO_OFF = V3_LAST_SEEN_OFF; // seqno takes place of last seen static int const V3_TIMESTAMP_OFF = V3_LAST_SEEN_OFF + 8; static int const V3_SOURCE_ID_OFF = V3_TIMESTAMP_OFF + 8; static int const V3_CONN_ID_OFF = V3_SOURCE_ID_OFF + 16; static int const V3_TRX_ID_OFF = V3_CONN_ID_OFF + 8; static int const V3_CRC_OFF = V3_TRX_ID_OFF + 8; static int const V3_SIZE = V3_CRC_OFF + 8; // 64 struct Offsets { int const header_ver_; int const header_size_; int const sets_; int const flags_; int const pa_range_; int const last_seen_; int const seqno_; int const timestamp_; int const source_id_; int const conn_id_; int const trx_id_; int const crc_; Offsets(int, int, int, int, int, int, int, int, int, int, int, int); }; static Offsets const V3; static int const MAX_HEADER_SIZE = V3_SIZE; mutable gu::byte_t local_[MAX_HEADER_SIZE]; gu::byte_t* ptr_; Version ver_; gu::byte_t size_; Checksum chksm_; wsrep_seqno_t seqno_priv() const { return gu::gtoh( *(reinterpret_cast(ptr_+ V3_LAST_SEEN_OFF)) ); } static void update_checksum(gu::byte_t* const ptr, size_t const size) { Checksum::type_t cval; Checksum::compute (ptr, size, cval); *reinterpret_cast(ptr + size) = cval; } }; /* class Header */ private: static bool const WRITESET_FLAGS_MATCH_API_FLAGS = (WSREP_FLAG_COMMIT == F_COMMIT && WSREP_FLAG_ROLLBACK == F_ROLLBACK && WSREP_FLAG_ISOLATION == F_TOI && WSREP_FLAG_PA_UNSAFE == F_PA_UNSAFE && WSREP_FLAG_COMMUTATIVE == F_COMMUTATIVE && WSREP_FLAG_NATIVE == F_NATIVE); /* this assert should be removed when wsrep API flags become * explicitly incompatible with wirteset flags */ GU_COMPILE_ASSERT(WRITESET_FLAGS_MATCH_API_FLAGS, flags_incompatible); template static inline uint32_t wsrep_flags_to_ws_flags_tmpl (uint32_t const flags) { uint32_t ret(0); if (flags & WSREP_FLAG_COMMIT) ret |= F_COMMIT; if (flags & WSREP_FLAG_ROLLBACK) ret |= F_ROLLBACK; if (flags & WSREP_FLAG_ISOLATION) ret |= F_TOI; if (flags & WSREP_FLAG_PA_UNSAFE) ret |= F_PA_UNSAFE; if (flags & WSREP_FLAG_COMMUTATIVE) ret |= F_COMMUTATIVE; if (flags & WSREP_FLAG_NATIVE) ret |= F_NATIVE; return ret; } }; /* class WriteSetNG */ /* specialization for the case when WS flags fully match API flags */ template <> inline uint32_t WriteSetNG::wsrep_flags_to_ws_flags_tmpl(uint32_t const flags) { return flags; } inline uint32_t WriteSetNG::wsrep_flags_to_ws_flags (uint32_t const flags) { return wsrep_flags_to_ws_flags_tmpl (flags); } class WriteSetOut { public: typedef gu::RecordSetOutBase::BaseName BaseName; WriteSetOut (const std::string& dir_name, wsrep_trx_id_t id, KeySet::Version kver, gu::byte_t* reserved, size_t reserved_size, uint16_t flags = 0, WriteSetNG::Version ver = WriteSetNG::MAX_VERSION, DataSet::Version dver = DataSet::MAX_VERSION, DataSet::Version uver = DataSet::MAX_VERSION, size_t max_size = WriteSetNG::MAX_SIZE) : header_(ver), base_name_(dir_name, id), /* 1/8 of reserved (aligned by 8) goes to key set */ kbn_ (base_name_), keys_ (reserved, (reserved_size >>= 6, reserved_size <<= 3, reserved_size), kbn_, kver), /* 5/8 of reserved goes to data set */ dbn_ (base_name_), data_ (reserved + reserved_size, reserved_size*5, dbn_, dver), /* 2/8 of reserved goes to unordered set */ ubn_ (base_name_), unrd_ (reserved + reserved_size*6, reserved_size*2, ubn_, uver), /* annotation set is not allocated unless requested */ abn_ (base_name_), annt_ (NULL), left_ (max_size - keys_.size() - data_.size() - unrd_.size() - header_.size()), flags_ (flags) {} ~WriteSetOut() { delete annt_; } void append_key(const KeyData& k) { left_ -= keys_.append(k); } void append_data(const void* data, size_t data_len, bool store) { left_ -= data_.append(data, data_len, store); } void append_unordered(const void* data, size_t data_len, bool store) { left_ -= unrd_.append(data, data_len, store); } void append_annotation(const void* data, size_t data_len, bool store) { if (NULL == annt_) { annt_ = new DataSetOut(NULL, 0, abn_, DataSet::MAX_VERSION); left_ -= annt_->size(); } left_ -= annt_->append(data, data_len, store); } void set_flags(uint16_t flags) { flags_ = flags; } void add_flags(uint16_t flags) { flags_ |= flags; } void mark_toi() { flags_ |= WriteSetNG::F_TOI; } void mark_pa_unsafe() { flags_ |= WriteSetNG::F_PA_UNSAFE; } bool is_empty() const { return ((data_.count() + keys_.count() + unrd_.count() + (annt_ ? annt_->count() : 0)) == 0); } /* !!! This returns header without checksum! * * Use set_last_seen() to finalize it. */ size_t gather(const wsrep_uuid_t& source, const wsrep_conn_id_t& conn, const wsrep_trx_id_t& trx, WriteSetNG::GatherVector& out) { check_size(); out->reserve (out->size() + keys_.page_count() + data_.page_count() + unrd_.page_count() + 1 /* global header */); size_t out_size (header_.gather (keys_.version(), data_.version(), unrd_.version() != DataSet::EMPTY, NULL != annt_, flags_, source, conn, trx, out)); out_size += keys_.gather(out); out_size += data_.gather(out); out_size += unrd_.gather(out); if (NULL != annt_) out_size += annt_->gather(out); return out_size; } void set_last_seen (const wsrep_seqno_t& ls) { header_.set_last_seen(ls); } void set_preordered (ssize_t pa_range) { assert (pa_range >= 0); /* By current convention pa_range is off by 1 from wsrep API def. * 0 meaning failed certification. */ pa_range++; /* cap PA range by maximum we can represent */ if (gu_unlikely(pa_range > WriteSetNG::MAX_PA_RANGE)) pa_range = WriteSetNG::MAX_PA_RANGE; header_.set_preordered(pa_range + 1); } private: struct BaseNameCommon { const std::string& dir_name_; unsigned long long const id_; BaseNameCommon(const std::string& dir_name, unsigned long long id) : dir_name_(dir_name), id_ (id) {} }; template class BaseNameImpl : public BaseName { const BaseNameCommon& data_; public: BaseNameImpl (const BaseNameCommon& data) : data_(data) {} void print(std::ostream& os) const { os << data_.dir_name_ << "/0x" << std::hex << std::setfill('0') << std::setw(8) << data_.id_ << suffix_; } }; /* class BaseNameImpl */ static const char keys_suffix[]; static const char data_suffix[]; static const char unrd_suffix[]; static const char annt_suffix[]; WriteSetNG::Header header_; BaseNameCommon base_name_; BaseNameImpl kbn_; KeySetOut keys_; BaseNameImpl dbn_; DataSetOut data_; BaseNameImpl ubn_; DataSetOut unrd_; BaseNameImpl abn_; DataSetOut* annt_; ssize_t left_; uint16_t flags_; void check_size() { if (gu_unlikely(left_ < 0)) gu_throw_error (EMSGSIZE) << "Maximum writeset size exceeded by " << -left_; } WriteSetOut (const WriteSetOut&); WriteSetOut& operator= (const WriteSetOut); }; /* class WriteSetOut */ class WriteSetIn { public: WriteSetIn (const gu::Buf& buf, ssize_t const st = SIZE_THRESHOLD) : header_(buf), size_ (buf.size), keys_ (), data_ (), unrd_ (), annt_ (NULL), check_thr_id_(), check_thr_(false), check_ (false) { init (st); } WriteSetIn () : header_(), size_ (0), keys_ (), data_ (), unrd_ (), annt_ (NULL), check_thr_id_(), check_thr_(false), check_ (false) {} /* WriteSetIn(buf) == WriteSetIn() + read_buf(buf) */ void read_buf (const gu::Buf& buf, ssize_t const st = SIZE_THRESHOLD) { assert (0 == size_); assert (false == check_); header_.read_buf (buf); size_ = buf.size; init (st); } void read_buf (const gu::byte_t* const ptr, ssize_t const len) { assert (ptr != NULL); assert (len >= 0); gu::Buf tmp = { ptr, len }; read_buf (tmp); } ~WriteSetIn () { if (gu_unlikely(check_thr_)) { /* checksum was performed in a parallel thread */ pthread_join (check_thr_id_, NULL); } delete annt_; } uint16_t flags() const { return header_.flags(); } bool is_toi() const { return flags() & WriteSetNG::F_TOI; } bool pa_unsafe() const { return flags() & WriteSetNG::F_PA_UNSAFE; } int pa_range() const { return header_.pa_range(); } bool certified() const { return header_.pa_range(); } wsrep_seqno_t last_seen() const { return header_.last_seen(); } wsrep_seqno_t seqno() const { return header_.seqno(); } long long timestamp() const { return header_.timestamp(); } const wsrep_uuid_t& source_id() const { return header_.source_id(); } wsrep_conn_id_t conn_id() const { return header_.conn_id(); } wsrep_trx_id_t trx_id() const { return header_.trx_id(); } const KeySetIn& keyset() const { return keys_; } const DataSetIn& dataset() const { return data_; } const DataSetIn& unrdset() const { return unrd_; } bool annotated() const { return (annt_ != NULL); } void write_annotation(std::ostream& os) const; /* This should be called right after certification verdict is obtained * and before it is finalized. */ void verify_checksum() const /* throws */ { if (gu_unlikely(check_thr_)) { /* checksum was performed in a parallel thread */ pthread_join (check_thr_id_, NULL); check_thr_ = false; checksum_fin(); } } void set_seqno(const wsrep_seqno_t& seqno, ssize_t pa_range) { assert (seqno > 0); assert (pa_range >= 0); /* cap PA range by maximum we can represent */ if (gu_unlikely(pa_range > WriteSetNG::MAX_PA_RANGE)) pa_range = WriteSetNG::MAX_PA_RANGE; header_.set_seqno (seqno, pa_range); } typedef gu::Vector GatherVector; /* can return pointer to internal storage: out can be used only * within object scope. */ size_t gather(GatherVector& out, bool include_keys, bool include_unrd) const; private: WriteSetNG::Header header_; ssize_t size_; KeySetIn keys_; DataSetIn data_; DataSetIn unrd_; DataSetIn* annt_; pthread_t check_thr_id_; bool mutable check_thr_; bool check_; static size_t const SIZE_THRESHOLD = 1 << 22; /* 4Mb */ void checksum (); /* checksums writeset, stores result in check_ */ void checksum_fin() const { if (gu_unlikely(!check_)) { gu_throw_error(EINVAL) << "Writeset checksum failed"; } } static void* checksum_thread (void* arg) { WriteSetIn* ws(reinterpret_cast(arg)); ws->checksum(); return NULL; } /* late initialization after default constructor */ void init (ssize_t size_threshold); WriteSetIn (const WriteSetIn&); WriteSetIn& operator=(WriteSetIn); }; } /* namespace galera */ #endif // GALERA_WRITE_SET_HPP percona-galera-3-3.8-3390/galera/src/wsdb.cpp000066400000000000000000000101371244131713600204710ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ #include "wsdb.hpp" #include "trx_handle.hpp" #include "write_set.hpp" #include "gu_lock.hpp" #include "gu_throw.hpp" void galera::Wsdb::print(std::ostream& os) const { os << "trx map:\n"; for (galera::Wsdb::TrxMap::const_iterator i = trx_map_.begin(); i != trx_map_.end(); ++i) { os << i->first << " " << *i->second << "\n"; } os << "conn query map:\n"; for (galera::Wsdb::ConnMap::const_iterator i = conn_map_.begin(); i != conn_map_.end(); ++i) { os << i->first << " "; } os << "\n"; } galera::Wsdb::Wsdb() : trx_pool_ (TrxHandle::LOCAL_STORAGE_SIZE, 512, "LocalTrxHandle"), trx_map_ (), trx_mutex_ (), conn_map_ (), conn_mutex_() {} galera::Wsdb::~Wsdb() { log_info << "wsdb trx map usage " << trx_map_.size() << " conn query map usage " << conn_map_.size(); log_info << trx_pool_; // With debug builds just print trx and query maps to stderr // and don't clean up to let valgrind etc to detect leaks. #ifndef NDEBUG std::cerr << *this; #else for_each(trx_map_.begin(), trx_map_.end(), Unref2nd()); #endif // !NDEBUG } inline galera::TrxHandle* galera::Wsdb::find_trx(wsrep_trx_id_t const trx_id) { gu::Lock lock(trx_mutex_); TrxMap::iterator const i(trx_map_.find(trx_id)); return (trx_map_.end() == i ? 0 : i->second); } inline galera::TrxHandle* galera::Wsdb::create_trx(const TrxHandle::Params& params, const wsrep_uuid_t& source_id, wsrep_trx_id_t const trx_id) { TrxHandle* trx(TrxHandle::New(trx_pool_, params, source_id, -1, trx_id)); gu::Lock lock(trx_mutex_); std::pair i (trx_map_.insert(std::make_pair(trx_id, trx))); if (gu_unlikely(i.second == false)) gu_throw_fatal; return i.first->second; } galera::TrxHandle* galera::Wsdb::get_trx(const TrxHandle::Params& params, const wsrep_uuid_t& source_id, wsrep_trx_id_t const trx_id, bool const create) { TrxHandle* retval(find_trx(trx_id)); if (0 == retval && create) retval = create_trx(params, source_id, trx_id); if (retval != 0) retval->ref(); return retval; } galera::Wsdb::Conn* galera::Wsdb::get_conn(wsrep_conn_id_t const conn_id, bool const create) { gu::Lock lock(conn_mutex_); ConnMap::iterator i(conn_map_.find(conn_id)); if (conn_map_.end() == i) { if (create == true) { std::pair p (conn_map_.insert(std::make_pair(conn_id, Conn(conn_id)))); if (gu_unlikely(p.second == false)) gu_throw_fatal; return &p.first->second; } return 0; } return &(i->second); } galera::TrxHandle* galera::Wsdb::get_conn_query(const TrxHandle::Params& params, const wsrep_uuid_t& source_id, wsrep_trx_id_t const conn_id, bool const create) { Conn* const conn(get_conn(conn_id, create)); if (0 == conn) return 0; if (conn->get_trx() == 0 && create == true) { TrxHandle* trx (TrxHandle::New(trx_pool_, params, source_id, conn_id, -1)); conn->assign_trx(trx); } return conn->get_trx(); } void galera::Wsdb::discard_trx(wsrep_trx_id_t trx_id) { gu::Lock lock(trx_mutex_); TrxMap::iterator i; if ((i = trx_map_.find(trx_id)) != trx_map_.end()) { i->second->unref(); trx_map_.erase(i); } } void galera::Wsdb::discard_conn_query(wsrep_conn_id_t conn_id) { gu::Lock lock(conn_mutex_); ConnMap::iterator i; if ((i = conn_map_.find(conn_id)) != conn_map_.end()) { i->second.assign_trx(0); } } void galera::Wsdb::discard_conn(wsrep_conn_id_t conn_id) { gu::Lock lock(conn_mutex_); ConnMap::iterator i; if ((i = conn_map_.find(conn_id)) != conn_map_.end()) { conn_map_.erase(i); } } percona-galera-3-3.8-3390/galera/src/wsdb.hpp000066400000000000000000000056051244131713600205020ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #ifndef GALERA_WSDB_HPP #define GALERA_WSDB_HPP #include "trx_handle.hpp" #include "wsrep_api.h" #include "gu_unordered.hpp" namespace galera { class Wsdb { class Conn { public: Conn(wsrep_conn_id_t conn_id) : conn_id_(conn_id), trx_(0) { } Conn(const Conn& other) : conn_id_(other.conn_id_), trx_(other.trx_) { } ~Conn() { if (trx_ != 0) trx_->unref(); } void assign_trx(TrxHandle* trx) { if (trx_ != 0) trx_->unref(); trx_ = trx; } TrxHandle* get_trx() { return trx_; } private: void operator=(const Conn&); wsrep_conn_id_t conn_id_; TrxHandle* trx_; }; class TrxHash { public: size_t operator()(const wsrep_trx_id_t& key) const { return key; } }; typedef gu::UnorderedMap TrxMap; class ConnHash { public: size_t operator()(const wsrep_conn_id_t& key) const { return key; } }; typedef gu::UnorderedMap ConnMap; public: TrxHandle* get_trx(const TrxHandle::Params& params, const wsrep_uuid_t& source_id, wsrep_trx_id_t trx_id, bool create = false); void discard_trx(wsrep_trx_id_t trx_id); TrxHandle* get_conn_query(const TrxHandle::Params&, const wsrep_uuid_t&, wsrep_conn_id_t conn_id, bool create = false); void discard_conn(wsrep_conn_id_t conn_id); void discard_conn_query(wsrep_conn_id_t conn_id); Wsdb(); ~Wsdb(); void print(std::ostream& os) const; private: // Find existing trx handle in the map TrxHandle* find_trx(wsrep_trx_id_t trx_id); // Create new trx handle TrxHandle* create_trx(const TrxHandle::Params& params, const wsrep_uuid_t& source_id, wsrep_trx_id_t trx_id); Conn* get_conn(wsrep_conn_id_t conn_id, bool create); static const size_t trx_mem_limit_ = 1 << 20; TrxHandle::LocalPool trx_pool_; TrxMap trx_map_; gu::Mutex trx_mutex_; ConnMap conn_map_; gu::Mutex conn_mutex_; }; inline std::ostream& operator<<(std::ostream& os, const Wsdb& w) { w.print(os); return os; } } #endif // GALERA_WSDB_HPP percona-galera-3-3.8-3390/galera/src/wsrep_api.h000066400000000000000000001152561244131713600212000ustar00rootroot00000000000000/* Copyright (C) 2009-2013 Codership Oy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /*! @file wsrep API declaration. HOW TO READ THIS FILE. Due to C language rules this header layout doesn't lend itself to intuitive reading. So here's the scoop: in the end this header declares two main types: * struct wsrep_init_args and * struct wsrep wsrep_init_args contains initialization parameters for wsrep provider like names, addresses, etc. and pointers to callbacks. The callbacks will be called by provider when it needs to do something application-specific, like log a message or apply a writeset. It should be passed to init() call from wsrep API. It is an application part of wsrep API contract. struct wsrep is the interface to wsrep provider. It contains all wsrep API calls. It is a provider part of wsrep API contract. Finally, wsrep_load() method loads (dlopens) wsrep provider library. It is defined in wsrep_loader.c unit and is part of libwsrep.a (which is not a wsrep provider, but a convenience library). wsrep_unload() does the reverse. */ #ifndef WSREP_H #define WSREP_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /************************************************************************** * * * wsrep replication API * * * **************************************************************************/ #define WSREP_INTERFACE_VERSION "25" /*! Empty backend spec */ #define WSREP_NONE "none" /*! * @brief log severity levels, passed as first argument to log handler */ typedef enum wsrep_log_level { WSREP_LOG_FATAL, //!< Unrecoverable error, application must quit. WSREP_LOG_ERROR, //!< Operation failed, must be repeated. WSREP_LOG_WARN, //!< Unexpected condition, but no operational failure. WSREP_LOG_INFO, //!< Informational message. WSREP_LOG_DEBUG //!< Debug message. Shows only of compiled with debug. } wsrep_log_level_t; /*! * @brief error log handler * * All messages from wsrep provider are directed to this * handler, if present. * * @param level log level * @param message log message */ typedef void (*wsrep_log_cb_t)(wsrep_log_level_t, const char *); /*! * Certain provider capabilities application may want to know about */ #define WSREP_CAP_MULTI_MASTER ( 1ULL << 0 ) #define WSREP_CAP_CERTIFICATION ( 1ULL << 1 ) #define WSREP_CAP_PARALLEL_APPLYING ( 1ULL << 2 ) #define WSREP_CAP_TRX_REPLAY ( 1ULL << 3 ) #define WSREP_CAP_ISOLATION ( 1ULL << 4 ) #define WSREP_CAP_PAUSE ( 1ULL << 5 ) #define WSREP_CAP_CAUSAL_READS ( 1ULL << 6 ) #define WSREP_CAP_CAUSAL_TRX ( 1ULL << 7 ) #define WSREP_CAP_INCREMENTAL_WRITESET ( 1ULL << 8 ) #define WSREP_CAP_SESSION_LOCKS ( 1ULL << 9 ) #define WSREP_CAP_DISTRIBUTED_LOCKS ( 1ULL << 10 ) #define WSREP_CAP_CONSISTENCY_CHECK ( 1ULL << 11 ) #define WSREP_CAP_UNORDERED ( 1ULL << 12 ) #define WSREP_CAP_ANNOTATION ( 1ULL << 13 ) #define WSREP_CAP_PREORDERED ( 1ULL << 14 ) /*! * Writeset flags * * COMMIT the writeset and all preceding writesets must be committed * ROLLBACK all preceding writesets in a transaction must be rolled back * ISOLATION the writeset must be applied AND committed in isolation * PA_UNSAFE the writeset cannot be applied in parallel * COMMUTATIVE the order in which the writeset is applied does not matter * NATIVE the writeset contains another writeset in this provider format * * Note that some of the flags are mutually exclusive (e.g. COMMIT and * ROLLBACK). */ #define WSREP_FLAG_COMMIT ( 1ULL << 0 ) #define WSREP_FLAG_ROLLBACK ( 1ULL << 1 ) #define WSREP_FLAG_ISOLATION ( 1ULL << 2 ) #define WSREP_FLAG_PA_UNSAFE ( 1ULL << 3 ) #define WSREP_FLAG_COMMUTATIVE ( 1ULL << 4 ) #define WSREP_FLAG_NATIVE ( 1ULL << 5 ) typedef uint64_t wsrep_trx_id_t; //!< application transaction ID typedef uint64_t wsrep_conn_id_t; //!< application connection ID typedef int64_t wsrep_seqno_t; //!< sequence number of a writeset, etc. #ifdef __cplusplus typedef bool wsrep_bool_t; #else typedef _Bool wsrep_bool_t; //!< should be the same as standard (C99) bool #endif /* __cplusplus */ /*! undefined seqno */ #define WSREP_SEQNO_UNDEFINED (-1) /*! wsrep provider status codes */ typedef enum wsrep_status { WSREP_OK = 0, //!< success WSREP_WARNING, //!< minor warning, error logged WSREP_TRX_MISSING, //!< transaction is not known by wsrep WSREP_TRX_FAIL, //!< transaction aborted, server can continue WSREP_BF_ABORT, //!< trx was victim of brute force abort WSREP_SIZE_EXCEEDED, //!< data exceeded maximum supported size WSREP_CONN_FAIL, //!< error in client connection, must abort WSREP_NODE_FAIL, //!< error in node state, wsrep must reinit WSREP_FATAL, //!< fatal error, server must abort WSREP_NOT_IMPLEMENTED //!< feature not implemented } wsrep_status_t; /*! wsrep callbacks status codes */ typedef enum wsrep_cb_status { WSREP_CB_SUCCESS = 0, //!< success (as in "not critical failure") WSREP_CB_FAILURE //!< critical failure (consistency violation) /* Technically, wsrep provider has no use for specific failure codes since * there is nothing it can do about it but abort execution. Therefore any * positive number shall indicate a critical failure. Optionally that value * may be used by provider to come to a consensus about state consistency * in a group of nodes. */ } wsrep_cb_status_t; /*! * UUID type - for all unique IDs */ typedef struct wsrep_uuid { uint8_t data[16]; } wsrep_uuid_t; /*! Undefined UUID */ static const wsrep_uuid_t WSREP_UUID_UNDEFINED = {{0,}}; /*! UUID string representation length, terminating '\0' not included */ #define WSREP_UUID_STR_LEN 36 /*! * Scan UUID from string * @return length of UUID string representation or negative error code */ extern int wsrep_uuid_scan (const char* str, size_t str_len, wsrep_uuid_t* uuid); /*! * Print UUID to string * @return length of UUID string representation or negative error code */ extern int wsrep_uuid_print (const wsrep_uuid_t* uuid, char* str, size_t str_len); #define WSREP_MEMBER_NAME_LEN 32 //!< maximum logical member name length #define WSREP_INCOMING_LEN 256 //!< max Domain Name length + 0x00 /*! * Global transaction identifier */ typedef struct wsrep_gtid { wsrep_uuid_t uuid; /*!< History UUID */ wsrep_seqno_t seqno; /*!< Sequence number */ } wsrep_gtid_t; /*! Undefined GTID */ static const wsrep_gtid_t WSREP_GTID_UNDEFINED = {{{0, }}, -1}; /*! Minimum number of bytes guaranteed to store GTID string representation, * terminating '\0' not included (36 + 1 + 20) */ #define WSREP_GTID_STR_LEN 57 /*! * Scan GTID from string * @return length of GTID string representation or negative error code */ extern int wsrep_gtid_scan(const char* str, size_t str_len, wsrep_gtid_t* gtid); /*! * Print GTID to string * @return length of GTID string representation or negative error code */ extern int wsrep_gtid_print(const wsrep_gtid_t* gtid, char* str, size_t str_len); /*! * Transaction meta data */ typedef struct wsrep_trx_meta { wsrep_gtid_t gtid; /*!< Global transaction identifier */ wsrep_seqno_t depends_on; /*!< Sequence number part of the last transaction this transaction depends on */ } wsrep_trx_meta_t; /*! * member status */ typedef enum wsrep_member_status { WSREP_MEMBER_UNDEFINED, //!< undefined state WSREP_MEMBER_JOINER, //!< incomplete state, requested state transfer WSREP_MEMBER_DONOR, //!< complete state, donates state transfer WSREP_MEMBER_JOINED, //!< complete state WSREP_MEMBER_SYNCED, //!< complete state, synchronized with group WSREP_MEMBER_ERROR, //!< this and above is provider-specific error code WSREP_MEMBER_MAX } wsrep_member_status_t; /*! * static information about a group member (some fields are tentative yet) */ typedef struct wsrep_member_info { wsrep_uuid_t id; //!< group-wide unique member ID char name[WSREP_MEMBER_NAME_LEN]; //!< human-readable name char incoming[WSREP_INCOMING_LEN]; //!< address for client requests } wsrep_member_info_t; /*! * group status */ typedef enum wsrep_view_status { WSREP_VIEW_PRIMARY, //!< primary group configuration (quorum present) WSREP_VIEW_NON_PRIMARY, //!< non-primary group configuration (quorum lost) WSREP_VIEW_DISCONNECTED, //!< not connected to group, retrying. WSREP_VIEW_MAX } wsrep_view_status_t; /*! * view of the group */ typedef struct wsrep_view_info { wsrep_gtid_t state_id; //!< global state ID wsrep_seqno_t view; //!< global view number wsrep_view_status_t status; //!< view status wsrep_bool_t state_gap; //!< gap between global and local states int my_idx; //!< index of this member in the view int memb_num; //!< number of members in the view int proto_ver; //!< application protocol agreed on the view wsrep_member_info_t members[1];//!< array of member information } wsrep_view_info_t; /*! * Magic string to tell provider to engage into trivial (empty) state transfer. * No data will be passed, but the node shall be considered JOINED. * Should be passed in sst_req parameter of wsrep_view_cb_t. */ #define WSREP_STATE_TRANSFER_TRIVIAL "trivial" /*! * Magic string to tell provider not to engage in state transfer at all. * The member will stay in WSREP_MEMBER_UNDEFINED state but will keep on * receiving all writesets. * Should be passed in sst_req parameter of wsrep_view_cb_t. */ #define WSREP_STATE_TRANSFER_NONE "none" /*! * @brief group view handler * * This handler is called in total order corresponding to the group * configuration change. It is to provide a vital information about * new group view. If view info indicates existence of discontinuity * between group and member states, state transfer request message * should be filled in by the callback implementation. * * @note Currently it is assumed that sst_req is allocated using * malloc()/calloc()/realloc() and it will be freed by * wsrep implementation. * * @param app_ctx application context * @param recv_ctx receiver context * @param view new view on the group * @param state current state * @param state_len lenght of current state * @param sst_req location to store SST request * @param sst_req_len location to store SST request length or error code, * value of 0 means no SST. */ typedef enum wsrep_cb_status (*wsrep_view_cb_t) ( void* app_ctx, void* recv_ctx, const wsrep_view_info_t* view, const char* state, size_t state_len, void** sst_req, size_t* sst_req_len ); /*! * @brief apply callback * * This handler is called from wsrep library to apply replicated writeset * Must support brute force applying for multi-master operation * * @param recv_ctx receiver context pointer provided by the application * @param data data buffer containing the writeset * @param size data buffer size * @param flags WSREP_FLAG_... flags * @param meta transaction meta data of the writeset to be applied * * @return success code: * @retval WSREP_OK * @retval WSREP_NOT_IMPLEMENTED appl. does not support the writeset format * @retval WSREP_ERROR failed to apply the writeset */ typedef enum wsrep_cb_status (*wsrep_apply_cb_t) ( void* recv_ctx, const void* data, size_t size, uint32_t flags, const wsrep_trx_meta_t* meta ); /*! * @brief commit callback * * This handler is called to commit the changes made by apply callback. * * @param recv_ctx receiver context pointer provided by the application * @param flags WSREP_FLAG_... flags * @param meta transaction meta data of the writeset to be committed * @param exit set to true to exit recv loop * @param commit true - commit writeset, false - rollback writeset * * @return success code: * @retval WSREP_OK * @retval WSREP_ERROR call failed */ typedef enum wsrep_cb_status (*wsrep_commit_cb_t) ( void* recv_ctx, uint32_t flags, const wsrep_trx_meta_t* meta, wsrep_bool_t* exit, wsrep_bool_t commit ); /*! * @brief unordered callback * * This handler is called to execute unordered actions (actions that need not * to be executed in any particular order) attached to writeset. * * @param recv_ctx receiver context pointer provided by the application * @param data data buffer containing the writeset * @param size data buffer size */ typedef enum wsrep_cb_status (*wsrep_unordered_cb_t) ( void* recv_ctx, const void* data, size_t size ); /*! * @brief a callback to donate state snapshot * * This handler is called from wsrep library when it needs this node * to deliver state to a new cluster member. * No state changes will be committed for the duration of this call. * Wsrep implementation may provide internal state to be transmitted * to new cluster member for initial state. * * @param app_ctx application context * @param recv_ctx receiver context * @param msg state transfer request message * @param msg_len state transfer request message length * @param gtid current state ID on this node * @param state current wsrep internal state buffer * @param state_len current wsrep internal state buffer len * @param bypass bypass snapshot transfer, only transfer uuid:seqno pair */ typedef enum wsrep_cb_status (*wsrep_sst_donate_cb_t) ( void* app_ctx, void* recv_ctx, const void* msg, size_t msg_len, const wsrep_gtid_t* state_id, const char* state, size_t state_len, wsrep_bool_t bypass ); /*! * @brief a callback to signal application that wsrep state is synced * with cluster * * This callback is called after wsrep library has got in sync with * rest of the cluster. * * @param app_ctx application context */ typedef void (*wsrep_synced_cb_t) (void* app_ctx); /*! * Initialization parameters for wsrep provider. */ struct wsrep_init_args { void* app_ctx; //!< Application context for callbacks /* Configuration parameters */ const char* node_name; //!< Symbolic name of this node (e.g. hostname) const char* node_address; //!< Address to be used by wsrep provider const char* node_incoming; //!< Address for incoming client connections const char* data_dir; //!< Directory where wsrep files are kept if any const char* options; //!< Provider-specific configuration string int proto_ver; //!< Max supported application protocol version /* Application initial state information. */ const wsrep_gtid_t* state_id; //!< Application state GTID const char* state; //!< Initial state for wsrep provider size_t state_len; //!< Length of state buffer /* Application callbacks */ wsrep_log_cb_t logger_cb; //!< logging handler wsrep_view_cb_t view_handler_cb; //!< group view change handler /* Applier callbacks */ wsrep_apply_cb_t apply_cb; //!< apply callback wsrep_commit_cb_t commit_cb; //!< commit callback wsrep_unordered_cb_t unordered_cb; //!< callback for unordered actions /* State Snapshot Transfer callbacks */ wsrep_sst_donate_cb_t sst_donate_cb; //!< starting to donate wsrep_synced_cb_t synced_cb; //!< synced with group }; /*! Type of the stats variable value in struct wsrep_status_var */ typedef enum wsrep_var_type { WSREP_VAR_STRING, //!< pointer to null-terminated string WSREP_VAR_INT64, //!< int64_t WSREP_VAR_DOUBLE //!< double } wsrep_var_type_t; /*! Generalized stats variable representation */ struct wsrep_stats_var { const char* name; //!< variable name wsrep_var_type_t type; //!< variable value type union { int64_t _int64; double _double; const char* _string; } value; //!< variable value }; /*! Abstract data buffer structure */ typedef struct wsrep_buf { const void* ptr; /*!< Pointer to data buffer */ size_t len; /*!< Length of buffer */ } wsrep_buf_t; /*! Key struct used to pass certification keys for transaction handling calls. * A key consists of zero or more key parts. */ typedef struct wsrep_key { const wsrep_buf_t* key_parts; /*!< Array of key parts */ size_t key_parts_num; /*!< Number of key parts */ } wsrep_key_t; /*! Key type: * EXCLUSIVE conflicts with any key type * SEMI reserved. If not supported, should be interpeted as EXCLUSIVE * SHARED conflicts only with EXCLUSIVE keys */ typedef enum wsrep_key_type { WSREP_KEY_SHARED = 0, WSREP_KEY_SEMI, WSREP_KEY_EXCLUSIVE } wsrep_key_type_t; /*! Data type: * ORDERED state modification event that should be applied and committed * in order. * UNORDERED some action that does not modify state and execution of which is * optional and does not need to happen in order. * ANNOTATION (human readable) writeset annotation. */ typedef enum wsrep_data_type { WSREP_DATA_ORDERED = 0, WSREP_DATA_UNORDERED, WSREP_DATA_ANNOTATION } wsrep_data_type_t; /*! Transaction handle struct passed for wsrep transaction handling calls */ typedef struct wsrep_ws_handle { wsrep_trx_id_t trx_id; //!< transaction ID void* opaque; //!< opaque provider transaction context data } wsrep_ws_handle_t; /*! * @brief Helper method to reset trx writeset handle state when trx id changes * * Instead of passing wsrep_ws_handle_t directly to wsrep calls, * wrapping handle with this call offloads bookkeeping from * application. */ static inline wsrep_ws_handle_t* wsrep_ws_handle_for_trx( wsrep_ws_handle_t* ws_handle, wsrep_trx_id_t trx_id) { if (ws_handle->trx_id != trx_id) { ws_handle->trx_id = trx_id; ws_handle->opaque = NULL; } return ws_handle; } /*! * A handle for processing preordered actions. * Must be initialized to WSREP_PO_INITIALIZER before use. */ typedef struct wsrep_po_handle { void* opaque; } wsrep_po_handle_t; static const wsrep_po_handle_t WSREP_PO_INITIALIZER = { NULL }; typedef struct wsrep wsrep_t; /*! * wsrep interface for dynamically loadable libraries */ struct wsrep { const char *version; //!< interface version string /*! * @brief Initializes wsrep provider * * @param wsrep provider handle * @param args wsrep initialization parameters */ wsrep_status_t (*init) (wsrep_t* wsrep, const struct wsrep_init_args* args); /*! * @brief Returns provider capabilities flag bitmap * * @param wsrep provider handle */ uint64_t (*capabilities) (wsrep_t* wsrep); /*! * @brief Passes provider-specific configuration string to provider. * * @param wsrep provider handle * @param conf configuration string * * @retval WSREP_OK configuration string was parsed successfully * @retval WSREP_WARNING could't not parse conf string, no action taken */ wsrep_status_t (*options_set) (wsrep_t* wsrep, const char* conf); /*! * @brief Returns provider-specific string with current configuration values. * * @param wsrep provider handle * * @return a dynamically allocated string with current configuration * parameter values */ char* (*options_get) (wsrep_t* wsrep); /*! * @brief Opens connection to cluster * * Returns when either node is ready to operate as a part of the clsuter * or fails to reach operating status. * * @param wsrep provider handle * @param cluster_name unique symbolic cluster name * @param cluster_url URL-like cluster address (backend://address) * @param state_donor name of the node to be asked for state transfer. * @param bootstrap a flag to request initialization of a new wsrep * service rather then a connection to the existing one. * clister_url may still carry important initialization * parameters, like backend spec and/or listen address. */ wsrep_status_t (*connect) (wsrep_t* wsrep, const char* cluster_name, const char* cluster_url, const char* state_donor, wsrep_bool_t bootstrap); /*! * @brief Closes connection to cluster. * * If state_uuid and/or state_seqno is not NULL, will store final state * in there. * * @param wsrep this wsrep handler */ wsrep_status_t (*disconnect)(wsrep_t* wsrep); /*! * @brief start receiving replication events * * This function never returns * * @param wsrep provider handle * @param recv_ctx receiver context */ wsrep_status_t (*recv)(wsrep_t* wsrep, void* recv_ctx); /*! * @brief Replicates/logs result of transaction to other nodes and allocates * required resources. * * Must be called before transaction commit. Returns success code, which * caller must check. * In case of WSREP_OK, starts commit critical section, transaction can * commit. Otherwise transaction must rollback. * * @param wsrep provider handle * @param ws_handle writeset of committing transaction * @param conn_id connection ID * @param flags fine tuning the replication WSREP_FLAG_* * @param meta transaction meta data * * @retval WSREP_OK cluster-wide commit succeeded * @retval WSREP_TRX_FAIL must rollback transaction * @retval WSREP_CONN_FAIL must close client connection * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*pre_commit)(wsrep_t* wsrep, wsrep_conn_id_t conn_id, wsrep_ws_handle_t* ws_handle, uint32_t flags, wsrep_trx_meta_t* meta); /*! * @brief Releases resources after transaction commit. * * Ends commit critical section. * * @param wsrep provider handle * @param ws_handle writeset of committing transaction * @retval WSREP_OK post_commit succeeded */ wsrep_status_t (*post_commit) (wsrep_t* wsrep, wsrep_ws_handle_t* ws_handle); /*! * @brief Releases resources after transaction rollback. * * @param wsrep provider handle * @param ws_handle writeset of committing transaction * @retval WSREP_OK post_rollback succeeded */ wsrep_status_t (*post_rollback)(wsrep_t* wsrep, wsrep_ws_handle_t* ws_handle); /*! * @brief Replay trx as a slave writeset * * If local trx has been aborted by brute force, and it has already * replicated before this abort, we must try if we can apply it as * slave trx. Note that slave nodes see only trx writesets and certification * test based on write set content can be different to DBMS lock conflicts. * * @param wsrep provider handle * @param ws_handle writeset of committing transaction * @param trx_ctx transaction context * * @retval WSREP_OK cluster commit succeeded * @retval WSREP_TRX_FAIL must rollback transaction * @retval WSREP_BF_ABORT brute force abort happened after trx replicated * must rollback transaction and try to replay * @retval WSREP_CONN_FAIL must close client connection * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*replay_trx)(wsrep_t* wsrep, wsrep_ws_handle_t* ws_handle, void* trx_ctx); /*! * @brief Abort pre_commit() call of another thread. * * It is possible, that some high-priority transaction needs to abort * another transaction which is in pre_commit() call waiting for resources. * * The kill routine checks that abort is not attmpted against a transaction * which is front of the caller (in total order). * * @param wsrep provider handle * @param bf_seqno seqno of brute force trx, running this cancel * @param victim_trx transaction to be aborted, and which is committing * * @retval WSREP_OK abort secceded * @retval WSREP_WARNING abort failed */ wsrep_status_t (*abort_pre_commit)(wsrep_t* wsrep, wsrep_seqno_t bf_seqno, wsrep_trx_id_t victim_trx); /*! * @brief Appends a row reference to transaction writeset * * Both copy flag and key_type can be ignored by provider (key type * interpreted as WSREP_KEY_EXCLUSIVE). * * @param wsrep provider handle * @param ws_handle writeset handle * @param keys array of keys * @param count length of the array of keys * @param type type ot the key * @param copy can be set to FALSE if keys persist through commit. */ wsrep_status_t (*append_key)(wsrep_t* wsrep, wsrep_ws_handle_t* ws_handle, const wsrep_key_t* keys, size_t count, enum wsrep_key_type type, wsrep_bool_t copy); /*! * @brief Appends data to transaction writeset * * This method can be called any time before commit and it * appends a number of data buffers to transaction writeset. * * Both copy and unordered flags can be ignored by provider. * * @param wsrep provider handle * @param ws_handle writeset handle * @param data array of data buffers * @param count buffer count * @param type type of data * @param copy can be set to FALSE if data persists through commit. */ wsrep_status_t (*append_data)(wsrep_t* wsrep, wsrep_ws_handle_t* ws_handle, const struct wsrep_buf* data, size_t count, enum wsrep_data_type type, wsrep_bool_t copy); /*! * @brief Get causal ordering for read operation * * This call will block until causal ordering with all possible * preceding writes in the cluster is guaranteed. If pointer to * gtid is non-null, the call stores the global transaction ID * of the last transaction which is guaranteed to be ordered * causally before this call. * * @param wsrep provider handle * @param gtid location to store GTID */ wsrep_status_t (*causal_read)(wsrep_t* wsrep, wsrep_gtid_t* gtid); /*! * @brief Clears allocated connection context. * * Whenever a new connection ID is passed to wsrep provider through * any of the API calls, a connection context is allocated for this * connection. This call is to explicitly notify provider to close the * connection. * * @param wsrep provider handle * @param conn_id connection ID * @param query the 'set database' query * @param query_len length of query (does not end with 0) */ wsrep_status_t (*free_connection)(wsrep_t* wsrep, wsrep_conn_id_t conn_id); /*! * @brief Replicates a query and starts "total order isolation" section. * * Replicates the action spec and returns success code, which caller must * check. Total order isolation continues until to_execute_end() is called. * * @param wsrep provider handle * @param conn_id connection ID * @param keys array of keys * @param keys_num lenght of the array of keys * @param action action buffer array to be executed * @param count action buffer count * @param meta transaction meta data * * @retval WSREP_OK cluster commit succeeded * @retval WSREP_CONN_FAIL must close client connection * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*to_execute_start)(wsrep_t* wsrep, wsrep_conn_id_t conn_id, const wsrep_key_t* keys, size_t keys_num, const struct wsrep_buf* action, size_t count, wsrep_trx_meta_t* meta); /*! * @brief Ends the total order isolation section. * * Marks the end of total order isolation. TO locks are freed * and other transactions are free to commit from this point on. * * @param wsrep provider handle * @param conn_id connection ID * * @retval WSREP_OK cluster commit succeeded * @retval WSREP_CONN_FAIL must close client connection * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*to_execute_end)(wsrep_t* wsrep, wsrep_conn_id_t conn_id); /*! * @brief Collects preordered replication events into a writeset. * * @param wsrep wsrep provider handle * @param handle a handle associated with a given writeset * @param data an array of data buffers. * @param count length of data buffer array. * @param copy whether provider needs to make a copy of events. * * @retval WSREP_OK cluster-wide commit succeeded * @retval WSREP_TRX_FAIL operation failed (e.g. trx size exceeded limit) * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*preordered_collect) (wsrep_t* wsrep, wsrep_po_handle_t* handle, const struct wsrep_buf* data, size_t count, wsrep_bool_t copy); /*! * @brief "Commits" preordered writeset to cluster. * * The contract is that the writeset will be committed in the same (partial) * order this method was called. Frees resources associated with the writeset * handle and reinitializes the handle. * * @param wsrep wsrep provider handle * @param po_handle a handle associated with a given writeset * @param source_id ID of the event producer, also serves as the partial order * or stream ID - events with different source_ids won't be * ordered with respect to each other. * @param flags WSREP_FLAG_... flags * @param pa_range the number of preceding events this event can be processed * in parallel with. A value of 0 means strict serial * processing. Note: commits always happen in wsrep order. * @param commit 'true' to commit writeset to cluster (replicate) or * 'false' to rollback (cancel) the writeset. * * @retval WSREP_OK cluster-wide commit succeeded * @retval WSREP_TRX_FAIL operation failed (e.g. NON-PRIMARY component) * @retval WSREP_NODE_FAIL must close all connections and reinit */ wsrep_status_t (*preordered_commit) (wsrep_t* wsrep, wsrep_po_handle_t* handle, const wsrep_uuid_t* source_id, uint32_t flags, int pa_range, wsrep_bool_t commit); /*! * @brief Signals to wsrep provider that state snapshot has been sent to * joiner. * * @param wsrep provider handle * @param state_id state ID * @param rcode 0 or negative error code of the operation. */ wsrep_status_t (*sst_sent)(wsrep_t* wsrep, const wsrep_gtid_t* state_id, int rcode); /*! * @brief Signals to wsrep provider that new state snapshot has been received. * May deadlock if called from sst_prepare_cb. * * @param wsrep provider handle * @param state_id state ID * @param state initial state provided by SST donor * @param state_len length of state buffer * @param rcode 0 or negative error code of the operation. */ wsrep_status_t (*sst_received)(wsrep_t* wsrep, const wsrep_gtid_t* state_id, const void* state, size_t state_len, int rcode); /*! * @brief Generate request for consistent snapshot. * * If successfull, this call will generate internally SST request * which in turn triggers calling SST donate callback on the nodes * specified in donor_spec. If donor_spec is null, callback is * called only locally. This call will block until sst_sent is called * from callback. * * @param wsrep provider handle * @param msg context message for SST donate callback * @param msg_len length of context message * @param donor_spec list of snapshot donors */ wsrep_status_t (*snapshot)(wsrep_t* wsrep, const void* msg, size_t msg_len, const char* donor_spec); /*! * @brief Returns an array of status variables. * Array is terminated by Null variable name. * * @param wsrep provider handle * @return array of struct wsrep_status_var. */ struct wsrep_stats_var* (*stats_get) (wsrep_t* wsrep); /*! * @brief Release resources that might be associated with the array. * * @param wsrep provider handle. * @param var_array array returned by stats_get(). */ void (*stats_free) (wsrep_t* wsrep, struct wsrep_stats_var* var_array); /*! * @brief Reset some stats variables to inital value, provider-dependent. * * @param wsrep provider handle. */ void (*stats_reset) (wsrep_t* wsrep); /*! * @brief Pauses writeset applying/committing. * * @return global sequence number of the paused state or negative error code. */ wsrep_seqno_t (*pause) (wsrep_t* wsrep); /*! * @brief Resumes writeset applying/committing. */ wsrep_status_t (*resume) (wsrep_t* wsrep); /*! * @brief Desynchronize from cluster * * Effectively turns off flow control for this node, allowing it * to fall behind the cluster. */ wsrep_status_t (*desync) (wsrep_t* wsrep); /*! * @brief Request to resynchronize with cluster. * * Effectively turns on flow control. Asynchronous - actual synchronization * event to be deliverred via sync_cb. */ wsrep_status_t (*resync) (wsrep_t* wsrep); /*! * @brief Acquire global named lock * * @param wsrep wsrep provider handle * @param name lock name * @param shared shared or exclusive lock * @param owner 64-bit owner ID * @param tout timeout in nanoseconds. * 0 - return immediately, -1 wait forever. * @return wsrep status or negative error code * @retval -EDEADLK lock was already acquired by this thread * @retval -EBUSY lock was busy */ wsrep_status_t (*lock) (wsrep_t* wsrep, const char* name, wsrep_bool_t shared, uint64_t owner, int64_t tout); /*! * @brief Release global named lock * * @param wsrep wsrep provider handle * @param name lock name * @param owner 64-bit owner ID * @return wsrep status or negative error code * @retval -EPERM lock does not belong to this owner */ wsrep_status_t (*unlock) (wsrep_t* wsrep, const char* name, uint64_t owner); /*! * @brief Check if global named lock is locked * * @param wsrep wsrep provider handle * @param name lock name * @param owner if not NULL will contain 64-bit owner ID * @param node if not NULL will contain owner's node UUID * @return true if lock is locked */ wsrep_bool_t (*is_locked) (wsrep_t* wsrep, const char* name, uint64_t* conn, wsrep_uuid_t* node); /*! * wsrep provider name */ const char* provider_name; /*! * wsrep provider version */ const char* provider_version; /*! * wsrep provider vendor name */ const char* provider_vendor; /*! * @brief Frees allocated resources before unloading the library. * @param wsrep provider handle */ void (*free)(wsrep_t* wsrep); void *dlh; //!< reserved for future use void *ctx; //!< reserved for implemetation private context }; /*! * * @brief Loads wsrep library * * @param spec path to wsrep library. If NULL or WSREP_NONE initialises dummy * pass-through implementation. * @param hptr wsrep handle * @param log_cb callback to handle loader messages. Otherwise writes to stderr. * * @return zero on success, errno on failure */ int wsrep_load(const char* spec, wsrep_t** hptr, wsrep_log_cb_t log_cb); /*! * @brief Unloads wsrep library and frees associated resources * * @param hptr wsrep handler pointer */ void wsrep_unload(wsrep_t* hptr); #ifdef __cplusplus } #endif #endif /* WSREP_H */ percona-galera-3-3.8-3390/galera/src/wsrep_params.cpp000066400000000000000000000030211244131713600222270ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "wsrep_params.hpp" void wsrep_set_params (galera::Replicator& repl, const char* params) { if (!params) return; std::vector > pv; gu::Config::parse (pv, params); for (size_t i(0); i < pv.size(); ++i) { const std::string& key(pv[i].first); const std::string& value(pv[i].second); try { if (key == galera::Replicator::Param::debug_log) { bool val(gu::from_string(value)); if (val == true) { gu_conf_debug_on(); } else { gu_conf_debug_off(); } } else { log_debug << "Setting param '" << key << "' = '" << value << '\''; repl.param_set(key, value); } } catch (gu::NotFound&) { log_warn << "Unknown parameter '" << key << "'"; gu_throw_error(EINVAL) << "Unknown parameter' " << key << "'"; } catch (gu::Exception& e) { log_warn << "Setting parameter '" << key << "' to '" << value << "' failed: " << e.what(); throw; } } } char* wsrep_get_params(const galera::Replicator& repl) { std::ostringstream os; os << repl.params(); return strdup(os.str().c_str()); } percona-galera-3-3.8-3390/galera/src/wsrep_params.hpp000066400000000000000000000005341244131713600222420ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #ifndef WSREP_PARAMS_HPP #define WSREP_PARAMS_HPP #include "wsrep_api.h" #include "galerautils.hpp" #include "replicator.hpp" void wsrep_set_params (galera::Replicator& repl, const char* params); char* wsrep_get_params(const galera::Replicator& repl); #endif /* WSREP_PARAMS_HPP */ percona-galera-3-3.8-3390/galera/src/wsrep_provider.cpp000066400000000000000000000626121244131713600226110ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "key_data.hpp" #if defined(GALERA_MULTIMASTER) #include "replicator_smm.hpp" #define REPL_CLASS galera::ReplicatorSMM #else #error "Not implemented" #endif #include "wsrep_params.hpp" #include using galera::KeyOS; using galera::WriteSet; using galera::TrxHandle; using galera::TrxHandleLock; extern "C" wsrep_status_t galera_init(wsrep_t* gh, const struct wsrep_init_args* args) { assert(gh != 0); try { gh->ctx = new REPL_CLASS (args); wsrep_set_params(*reinterpret_cast(gh->ctx), args->options); return WSREP_OK; } catch (gu::Exception& e) { log_error << e.what(); } catch (std::exception& e) { log_error << e.what(); } catch (gu::NotFound& e) { /* Unrecognized parameter (logged by gu::Config::set()) */ } #ifdef NDEBUG catch (...) { log_fatal << "non-standard exception"; } #endif return WSREP_NODE_FAIL; } extern "C" uint64_t galera_capabilities(wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); static uint64_t const v4_caps(WSREP_CAP_MULTI_MASTER | WSREP_CAP_CERTIFICATION | WSREP_CAP_PARALLEL_APPLYING | WSREP_CAP_TRX_REPLAY | WSREP_CAP_ISOLATION | WSREP_CAP_PAUSE | WSREP_CAP_CAUSAL_READS); static uint64_t const v5_caps(WSREP_CAP_INCREMENTAL_WRITESET | WSREP_CAP_UNORDERED | WSREP_CAP_PREORDERED); uint64_t caps(v4_caps); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); if (repl->repl_proto_ver() >= 5) caps |= v5_caps; return caps; } extern "C" void galera_tear_down(wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); if (repl != 0) { delete repl; gh->ctx = 0; } } extern "C" wsrep_status_t galera_parameters_set (wsrep_t* gh, const char* params) { assert(gh != 0); // cppcheck-suppress nullPointer assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); // cppcheck-suppress nullPointer if (gh) { try { wsrep_set_params (*repl, params); return WSREP_OK; } catch (gu::NotFound&) { log_warn << "Unrecognized parameter in '" << params << "'"; return WSREP_WARNING; } catch (std::exception& e) { log_debug << e.what(); // better logged in wsrep_set_params } } else { log_error << "Attempt to set parameter(s) on uninitialized replicator."; } return WSREP_NODE_FAIL; } extern "C" char* galera_parameters_get (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); try { REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); return wsrep_get_params(*repl); } catch (std::exception& e) { log_error << e.what(); return 0; } catch (...) { log_fatal << "non-standard exception"; return 0; } } extern "C" wsrep_status_t galera_connect (wsrep_t* gh, const char* cluster_name, const char* cluster_url, const char* state_donor, wsrep_bool_t bootstrap) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { return repl->connect(cluster_name, cluster_url, state_donor ? state_donor : "", bootstrap); } catch (std::exception& e) { log_error << e.what(); return WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } } extern "C" wsrep_status_t galera_disconnect(wsrep_t *gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { return repl->close(); } catch (std::exception& e) { log_error << e.what(); return WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } } extern "C" wsrep_status_t galera_recv(wsrep_t *gh, void *recv_ctx) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); #ifdef NDEBUG try { #endif /* NDEBUG */ return repl->async_recv(recv_ctx); #ifdef NDEBUG } catch (gu::Exception& e) { log_error << e.what(); switch (e.get_errno()) { case ENOTRECOVERABLE: return WSREP_FATAL; default: return WSREP_NODE_FAIL; } } catch (std::exception& e) { log_error << e.what(); } catch (...) { log_fatal << "non-standard exception"; } #endif // NDEBUG return WSREP_FATAL; } static TrxHandle* get_local_trx(REPL_CLASS* const repl, wsrep_ws_handle_t* const handle, bool const create) { TrxHandle* trx; assert(handle != 0); if (handle->opaque != 0) { trx = static_cast(handle->opaque); assert(trx->trx_id() == handle->trx_id || wsrep_trx_id_t(-1) == handle->trx_id); trx->ref(); } else { trx = repl->get_local_trx(handle->trx_id, create); handle->opaque = trx; } return trx; } extern "C" wsrep_status_t galera_replay_trx(wsrep_t* gh, wsrep_ws_handle_t* trx_handle, void* recv_ctx) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(get_local_trx(repl, trx_handle, false)); assert(trx != 0); wsrep_status_t retval; try { TrxHandleLock lock(*trx); retval = repl->replay_trx(trx, recv_ctx); } catch (std::exception& e) { log_warn << "failed to replay trx: " << *trx; log_warn << e.what(); retval = WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } repl->unref_local_trx(trx); return retval; } extern "C" wsrep_status_t galera_abort_pre_commit(wsrep_t* gh, wsrep_seqno_t bf_seqno, wsrep_trx_id_t victim_trx) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); wsrep_status_t retval; TrxHandle* trx(repl->get_local_trx(victim_trx)); if (!trx) return WSREP_OK; try { TrxHandleLock lock(*trx); repl->abort_trx(trx); retval = WSREP_OK; } catch (std::exception& e) { log_error << e.what(); retval = WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } repl->unref_local_trx(trx); return retval; } static inline void discard_local_trx(REPL_CLASS* repl, wsrep_ws_handle_t* ws_handle, TrxHandle* trx) { repl->unref_local_trx(trx); repl->discard_local_trx(trx); ws_handle->opaque = 0; } extern "C" wsrep_status_t galera_post_commit (wsrep_t* gh, wsrep_ws_handle_t* ws_handle) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(get_local_trx(repl, ws_handle, false)); if (trx == 0) { log_debug << "trx " << ws_handle->trx_id << " not found"; return WSREP_OK; } wsrep_status_t retval; try { TrxHandleLock lock(*trx); retval = repl->post_commit(trx); } catch (std::exception& e) { log_error << e.what(); retval = WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } discard_local_trx(repl, ws_handle, trx); return retval; } extern "C" wsrep_status_t galera_post_rollback(wsrep_t* gh, wsrep_ws_handle_t* ws_handle) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(get_local_trx(repl, ws_handle, false)); if (trx == 0) { log_debug << "trx " << ws_handle->trx_id << " not found"; return WSREP_OK; } wsrep_status_t retval; try { TrxHandleLock lock(*trx); retval = repl->post_rollback(trx); } catch (std::exception& e) { log_error << e.what(); retval = WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } discard_local_trx(repl, ws_handle, trx); return retval; } static inline void append_data_array (TrxHandle* const trx, const struct wsrep_buf* const data, size_t const count, wsrep_data_type_t const type, bool const copy) { for (size_t i(0); i < count; ++i) { trx->append_data(data[i].ptr, data[i].len, type, copy); } } extern "C" wsrep_status_t galera_pre_commit(wsrep_t* const gh, wsrep_conn_id_t const conn_id, wsrep_ws_handle_t* const trx_handle, uint32_t const flags, wsrep_trx_meta_t* const meta) { assert(gh != 0); assert(gh->ctx != 0); if (meta != 0) { meta->gtid = WSREP_GTID_UNDEFINED; meta->depends_on = WSREP_SEQNO_UNDEFINED; } REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(get_local_trx(repl, trx_handle, /*rbr_data != 0*/ false)); if (trx == 0) { // no data to replicate return WSREP_OK; } wsrep_status_t retval; try { TrxHandleLock lock(*trx); trx->set_conn_id(conn_id); // /* rbr_data should clearly persist over pre_commit() call */ // append_data_array (trx, rbr_data, rbr_data_len, false, false); trx->set_flags(TrxHandle::wsrep_flags_to_trx_flags(flags)); retval = repl->replicate(trx, meta); assert((!(retval == WSREP_OK || retval == WSREP_BF_ABORT) || trx->global_seqno() > 0)); if (retval == WSREP_OK) { assert(trx->last_seen_seqno() >= 0); retval = repl->pre_commit(trx, meta); } assert(retval == WSREP_OK || retval == WSREP_TRX_FAIL || retval == WSREP_BF_ABORT); } catch (gu::Exception& e) { log_error << e.what(); if (e.get_errno() == EMSGSIZE) retval = WSREP_SIZE_EXCEEDED; else retval = WSREP_NODE_FAIL; } catch (std::exception& e) { log_error << e.what(); retval = WSREP_NODE_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } repl->unref_local_trx(trx); return retval; } extern "C" wsrep_status_t galera_append_key(wsrep_t* const gh, wsrep_ws_handle_t* const trx_handle, const wsrep_key_t* const keys, size_t const keys_num, wsrep_key_type_t const key_type, wsrep_bool_t const copy) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(get_local_trx(repl, trx_handle, true)); assert(trx != 0); wsrep_status_t retval; try { TrxHandleLock lock(*trx); for (size_t i(0); i < keys_num; ++i) { galera::KeyData k (repl->trx_proto_ver(), keys[i].key_parts, keys[i].key_parts_num, key_type, copy); trx->append_key(k); } retval = WSREP_OK; } catch (std::exception& e) { log_warn << e.what(); retval = WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } repl->unref_local_trx(trx); return retval; } extern "C" wsrep_status_t galera_append_data(wsrep_t* const wsrep, wsrep_ws_handle_t* const trx_handle, const struct wsrep_buf* const data, size_t const count, wsrep_data_type_t const type, wsrep_bool_t const copy) { assert(wsrep != 0); assert(wsrep->ctx != 0); assert(data != NULL); assert(count > 0); if (data == NULL) { // no data to replicate return WSREP_OK; } REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(wsrep->ctx)); TrxHandle* trx(get_local_trx(repl, trx_handle, true)); assert(trx != 0); wsrep_status_t retval; try { TrxHandleLock lock(*trx); if (WSREP_DATA_ORDERED == type) append_data_array(trx, data, count, type, copy); retval = WSREP_OK; } catch (std::exception& e) { log_warn << e.what(); retval = WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } repl->unref_local_trx(trx); return retval; } extern "C" wsrep_status_t galera_causal_read(wsrep_t* const wsrep, wsrep_gtid_t* const gtid) { assert(wsrep != 0); assert(wsrep->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(wsrep->ctx)); wsrep_status_t retval; try { retval = repl->causal_read(gtid); } catch (std::exception& e) { log_warn << e.what(); retval = WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } return retval; } extern "C" wsrep_status_t galera_free_connection(wsrep_t* const gh, wsrep_conn_id_t const conn_id) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { repl->discard_local_conn(conn_id); return WSREP_OK; } catch (std::exception& e) { log_warn << e.what(); return WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } } extern "C" wsrep_status_t galera_to_execute_start(wsrep_t* const gh, wsrep_conn_id_t const conn_id, const wsrep_key_t* const keys, size_t const keys_num, const struct wsrep_buf* const data, size_t const count, wsrep_trx_meta_t* const meta) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); TrxHandle* trx(repl->local_conn_trx(conn_id, true)); assert(trx != 0); wsrep_status_t retval; try { TrxHandleLock lock(*trx); for (size_t i(0); i < keys_num; ++i) { galera::KeyData k(repl->trx_proto_ver(), keys[i].key_parts, keys[i].key_parts_num, WSREP_KEY_EXCLUSIVE,false); trx->append_key(k); } append_data_array(trx, data, count, WSREP_DATA_ORDERED, false); trx->set_flags(TrxHandle::wsrep_flags_to_trx_flags( WSREP_FLAG_COMMIT | WSREP_FLAG_ISOLATION)); retval = repl->replicate(trx, meta); assert((retval == WSREP_OK && trx->global_seqno() > 0) || (retval != WSREP_OK && trx->global_seqno() < 0)); if (retval == WSREP_OK) { retval = repl->to_isolation_begin(trx, meta); } } catch (std::exception& e) { log_warn << e.what(); retval = WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; retval = WSREP_FATAL; } if (retval != WSREP_OK) // galera_to_execute_end() won't be called { repl->discard_local_conn_trx(conn_id); // trx is not needed anymore if (trx->global_seqno() < 0) // no seqno -> no index -> no automatic purging { trx->unref(); // implicit destructor } } return retval; } extern "C" wsrep_status_t galera_to_execute_end(wsrep_t* const gh, wsrep_conn_id_t const conn_id) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); wsrep_status_t retval; TrxHandle* trx(repl->local_conn_trx(conn_id, false)); try { TrxHandleLock lock(*trx); repl->to_isolation_end(trx); repl->discard_local_conn_trx(conn_id); return WSREP_OK; // trx will be unreferenced (destructed) during purge } catch (std::exception& e) { log_warn << e.what(); return WSREP_CONN_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } return retval; } extern "C" wsrep_status_t galera_preordered_collect (wsrep_t* const gh, wsrep_po_handle_t* const handle, const struct wsrep_buf* const data, size_t const count, wsrep_bool_t const copy) { assert(gh != 0); assert(gh->ctx != 0); assert(handle != 0); assert(data != 0); assert(count > 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { return repl->preordered_collect(*handle, data, count, copy); } catch (std::exception& e) { log_warn << e.what(); return WSREP_TRX_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } } extern "C" wsrep_status_t galera_preordered_commit (wsrep_t* const gh, wsrep_po_handle_t* const handle, const wsrep_uuid_t* const source_id, uint32_t const flags, int const pa_range, wsrep_bool_t const commit) { assert(gh != 0); assert(gh->ctx != 0); assert(handle != 0); assert(source_id != 0 || false == commit); assert(pa_range >= 0 || false == commit); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { return repl->preordered_commit(*handle, *source_id, flags, pa_range, commit); } catch (std::exception& e) { log_warn << e.what(); return WSREP_TRX_FAIL; } catch (...) { log_fatal << "non-standard exception"; return WSREP_FATAL; } } extern "C" wsrep_status_t galera_sst_sent (wsrep_t* const gh, const wsrep_gtid_t* const state_id, int const rcode) { assert(gh != 0); assert(gh->ctx != 0); assert(state_id != 0); assert(rcode <= 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); return repl->sst_sent(*state_id, rcode); } extern "C" wsrep_status_t galera_sst_received (wsrep_t* const gh, const wsrep_gtid_t* const state_id, const void* const state, size_t const state_len, int const rcode) { assert(gh != 0); assert(gh->ctx != 0); assert(state_id != 0); assert(rcode <= 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); if (rcode < 0) { assert(state_id->seqno == WSREP_SEQNO_UNDEFINED); } return repl->sst_received(*state_id, state, state_len, rcode); } extern "C" wsrep_status_t galera_snapshot(wsrep_t* wsrep, const void* msg, size_t msg_len, const char* donor_spec) { return WSREP_NOT_IMPLEMENTED; } extern "C" struct wsrep_stats_var* galera_stats_get (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS* repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); return const_cast(repl->stats_get()); } extern "C" void galera_stats_free (wsrep_t* gh, struct wsrep_stats_var* s) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS* repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); return repl->stats_free(s); //REPL_CLASS::stats_free(s); } extern "C" void galera_stats_reset (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS* repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); repl->stats_reset(); } extern "C" wsrep_seqno_t galera_pause (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { return repl->pause(); } catch (gu::Exception& e) { log_error << e.what(); return -e.get_errno(); } } extern "C" wsrep_status_t galera_resume (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { repl->resume(); return WSREP_OK; } catch (gu::Exception& e) { log_error << e.what(); return WSREP_NODE_FAIL; } } extern "C" wsrep_status_t galera_desync (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { repl->desync(); return WSREP_OK; } catch (gu::Exception& e) { log_error << e.what(); return WSREP_TRX_FAIL; } } extern "C" wsrep_status_t galera_resync (wsrep_t* gh) { assert(gh != 0); assert(gh->ctx != 0); REPL_CLASS * repl(reinterpret_cast< REPL_CLASS * >(gh->ctx)); try { repl->resync(); return WSREP_OK; } catch (gu::Exception& e) { log_error << e.what(); return WSREP_NODE_FAIL; } } extern "C" wsrep_status_t galera_lock (wsrep_t* gh, const char* name, wsrep_bool_t shared, uint64_t owner, int64_t timeout) { assert(gh != 0); assert(gh->ctx != 0); return WSREP_NOT_IMPLEMENTED; } extern "C" wsrep_status_t galera_unlock (wsrep_t* gh, const char* name, uint64_t owner) { assert(gh != 0); assert(gh->ctx != 0); return WSREP_OK; } extern "C" bool galera_is_locked (wsrep_t* gh, const char* name, uint64_t* owner, wsrep_uuid_t* node) { assert(gh != 0); assert(gh->ctx != 0); return false; } static wsrep_t galera_str = { WSREP_INTERFACE_VERSION, &galera_init, &galera_capabilities, &galera_parameters_set, &galera_parameters_get, &galera_connect, &galera_disconnect, &galera_recv, &galera_pre_commit, &galera_post_commit, &galera_post_rollback, &galera_replay_trx, &galera_abort_pre_commit, &galera_append_key, &galera_append_data, &galera_causal_read, &galera_free_connection, &galera_to_execute_start, &galera_to_execute_end, &galera_preordered_collect, &galera_preordered_commit, &galera_sst_sent, &galera_sst_received, &galera_snapshot, &galera_stats_get, &galera_stats_free, &galera_stats_reset, &galera_pause, &galera_resume, &galera_desync, &galera_resync, &galera_lock, &galera_unlock, &galera_is_locked, "Galera", GALERA_VER "(r" GALERA_REV ")", "Codership Oy ", &galera_tear_down, NULL, NULL }; /* Prototype to make compiler happy */ extern "C" int wsrep_loader(wsrep_t *hptr); extern "C" int wsrep_loader(wsrep_t *hptr) { if (!hptr) return EINVAL; try { *hptr = galera_str; } catch (...) { return ENOTRECOVERABLE; } return WSREP_OK; } percona-galera-3-3.8-3390/galera/tests/000077500000000000000000000000001244131713600173775ustar00rootroot00000000000000percona-galera-3-3.8-3390/galera/tests/SConscript000066400000000000000000000021151244131713600214100ustar00rootroot00000000000000 Import('check_env') env = check_env.Clone() env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) env.Prepend(LIBS=File('#/gcomm/src/libgcomm.a')) env.Prepend(LIBS=File('#/gcs/src/libgcs.a')) env.Prepend(LIBS=File('#/galera/src/libgalera++.a')) env.Prepend(LIBS=File('#/gcache/src/libgcache.a')) galera_check = env.Program(target='galera_check', source=Split(''' galera_check.cpp data_set_check.cpp key_set_check.cpp write_set_ng_check.cpp write_set_check.cpp trx_handle_check.cpp service_thd_check.cpp ist_check.cpp saved_state_check.cpp ''')) stamp = "galera_check.passed" env.Test(stamp, galera_check) env.Alias("test", stamp) Clean(galera_check, ['#/galera_check.log', 'ist_check.cache']) percona-galera-3-3.8-3390/galera/tests/data_set_check.cpp000066400000000000000000000160671244131713600230360ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #undef NDEBUG #include "../src/data_set.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" #include using namespace galera; class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; class TestRecord { public: TestRecord (size_t size, const char* str) : size_(size), buf_(reinterpret_cast(::malloc(size_))), str_(reinterpret_cast(buf_) + sizeof(uint32_t)), own_(true) { if (0 == buf_) throw std::runtime_error("failed to allocate record"); void* tmp = const_cast(buf_); *reinterpret_cast(tmp) = htog32(size_); ::strncpy (const_cast(str_), str, size_ - 4); } TestRecord (const void* const buf, ssize_t const size) : size_(TestRecord::serial_size(buf, size)), buf_(buf), str_(reinterpret_cast(buf_) + sizeof(uint32_t)), own_(false) {} TestRecord (const TestRecord& t) : size_(t.size_), buf_(t.buf_), str_(t.str_), own_(false) {} virtual ~TestRecord () { if (own_) free (const_cast(buf_)); } const void* buf() const { return buf_; } const char* c_str() const { return str_; } ssize_t serial_size() const { return my_serial_size(); } static ssize_t serial_size(const void* const buf, ssize_t const size) { check_buf (buf, size, 1); return gtoh32 (*reinterpret_cast(buf)); } bool operator!= (const TestRecord& t) const { return (size_ != t.size_ || ::memcmp(buf_, t.buf_, size_)); } bool operator== (const TestRecord& t) const { return (!(*this != t)); } private: size_t const size_; const void* const buf_; const char* const str_; bool const own_; ssize_t my_serial_size () const { return size_; }; ssize_t my_serialize_to (void* buf, ssize_t size) const { check_buf (buf, size, size_); ::memcpy (buf, buf_, size_); return size_; } static void check_buf (const void* const buf, ssize_t const size, ssize_t min_size) { if (gu_unlikely (buf == 0 || size < min_size)) throw std::length_error("buffer too short"); } TestRecord& operator= (const TestRecord&); }; START_TEST (ver0) { size_t const MB = 1 << 20; TestRecord rout0(128, "abc0"); TestRecord rout1(127, "abc1"); TestRecord rout2(126, "012345"); TestRecord rout3(125, "defghij"); TestRecord rout4(3*MB, "klm"); TestRecord rout5(1*MB, "qpr"); std::vector records; records.push_back (&rout0); records.push_back (&rout1); records.push_back (&rout2); records.push_back (&rout3); records.push_back (&rout4); records.push_back (&rout5); gu::byte_t reserved[1024]; TestBaseName str("data_set_test"); DataSetOut dset_out(reserved, sizeof(reserved), str, DataSet::VER1); size_t offset(dset_out.size()); // this should be allocated inside current page offset += dset_out.append (rout0.buf(), rout0.serial_size(), true); fail_if (dset_out.size() != offset, "expected: %zu, got %zu", offset, dset_out.size()); // this should trigger new page since not stored offset += dset_out.append (rout1.buf(), rout1.serial_size(), false); fail_if (dset_out.size() != offset); // this should trigger new page since previous one was not stored offset += dset_out.append (rout2.buf(), rout2.serial_size(), true); fail_if (dset_out.size() != offset); // this should trigger a new page, since not stored offset += dset_out.append (rout3.buf(), rout3.serial_size(), false); fail_if (dset_out.size() != offset); // this should trigger new page, because won't fit in the current page offset += dset_out.append (rout4.buf(), rout4.serial_size(), true); fail_if (dset_out.size() != offset); // this should trigger new page, because 4MB RAM limit exceeded offset += dset_out.append (rout5.buf(), rout5.serial_size(), false); fail_if (dset_out.size() != offset); fail_if (1 != size_t(dset_out.count())); DataSetOut::GatherVector out_bufs; out_bufs().reserve (dset_out.page_count()); size_t min_out_size(0); for (size_t i = 0; i < records.size(); ++i) { min_out_size += records[i]->serial_size(); } size_t const out_size (dset_out.gather (out_bufs)); fail_if (out_size <= min_out_size || out_size > offset); fail_if (out_bufs->size() != static_cast(dset_out.page_count()), "Expected %zu buffers, got: %zd", dset_out.page_count(), out_bufs->size()); /* concatenate all buffers into one */ std::vector in_buf; in_buf.reserve(out_size); mark_point(); for (size_t i = 0; i < out_bufs->size(); ++i) { fail_if (0 == out_bufs[i].ptr); log_info << "\nadding buf " << i << ": " << gu::Hexdump(out_bufs[i].ptr, std::min(out_bufs[i].size, 24), true); size_t old_size = in_buf.size(); const gu::byte_t* ptr (reinterpret_cast(out_bufs[i].ptr)); in_buf.insert (in_buf.end(), ptr, ptr + out_bufs[i].size); fail_if (old_size + out_bufs[i].size != in_buf.size()); } fail_if (in_buf.size() != out_size, "Sent buf size: %zu, recvd buf size: %zu", out_size, in_buf.size()); log_info << "Resulting DataSet buffer:\n" << gu::Hexdump(in_buf.data(), 32, false) << '\n' << gu::Hexdump(in_buf.data(), 32, true); galera::DataSetIn const dset_in(dset_out.version(), in_buf.data(), in_buf.size()); fail_if (dset_in.size() != dset_out.size()); fail_if (dset_in.count() != dset_out.count()); for (ssize_t i = 0; i < dset_in.count(); ++i) { gu::Buf data = dset_in.next(); TestRecord const rin(data.ptr, data.size); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } galera::DataSetIn dset_in_empty; dset_in_empty.init(dset_out.version(), in_buf.data(), in_buf.size()); fail_if (dset_in_empty.size() != dset_out.size()); fail_if (dset_in_empty.count() != dset_out.count()); for (ssize_t i = 0; i < dset_in_empty.count(); ++i) { gu::Buf data = dset_in_empty.next(); TestRecord const rin(data.ptr, data.size); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } } END_TEST Suite* data_set_suite () { TCase* t = tcase_create ("DataSet"); tcase_add_test (t, ver0); tcase_set_timeout(t, 60); Suite* s = suite_create ("DataSet"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galera/tests/galera_check.cpp000066400000000000000000000030301244131713600224670ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ #include #include #include #include /* * Suite descriptions: forward-declare and add to array */ typedef Suite* (*suite_creator_t) (void); extern Suite* data_set_suite(); extern Suite* key_set_suite(); extern Suite* write_set_ng_suite(); extern Suite* write_set_suite(); extern Suite* trx_handle_suite(); extern Suite* service_thd_suite(); extern Suite* ist_suite(); extern Suite* saved_state_suite(); static suite_creator_t suites[] = { data_set_suite, key_set_suite, write_set_ng_suite, write_set_suite, trx_handle_suite, service_thd_suite, ist_suite, saved_state_suite, 0 }; extern "C" { #include } #define LOG_FILE "galera_check.log" int main(int argc, char* argv[]) { bool no_fork = (argc >= 2 && std::string(argv[1]) == "nofork"); FILE* log_file = 0; if (!no_fork) { log_file = fopen (LOG_FILE, "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); int failed = 0; for (int i = 0; suites[i] != 0; ++i) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all(sr, CK_NORMAL); failed += srunner_ntests_failed(sr); srunner_free(sr); } if (log_file != 0) fclose(log_file); printf ("Total tests failed: %d\n", failed); return failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } percona-galera-3-3.8-3390/galera/tests/ist_check.cpp000066400000000000000000000242721244131713600220460ustar00rootroot00000000000000// // Copyright (C) 2011-2014 Codership Oy // #include "ist.hpp" #include "ist_proto.hpp" #include "trx_handle.hpp" #include "uuid.hpp" #include "monitor.hpp" #include "GCache.hpp" #include "gu_arch.h" #include "replicator_smm.hpp" #include using namespace galera; // Message tests START_TEST(test_ist_message) { using namespace galera::ist; Message m3(3, Message::T_HANDSHAKE, 0x2, 3, 1001); #if 0 /* This is a check for the old (broken) format */ #if GU_WORDSIZE == 32 fail_unless(serial_size(m3) == 20, "serial size %zu != 20", serial_size(m3)); #elif GU_WORDSIZE == 64 fail_unless(serial_size(m3) == 24, "serial size %zu != 24", serial_size(m3)); #endif #endif /* 0 */ gu::Buffer buf(m3.serial_size()); m3.serialize(&buf[0], buf.size(), 0); Message mu3(3); mu3.unserialize(&buf[0], buf.size(), 0); fail_unless(mu3.version() == 3); fail_unless(mu3.type() == Message::T_HANDSHAKE); fail_unless(mu3.flags() == 0x2); fail_unless(mu3.ctrl() == 3); fail_unless(mu3.len() == 1001); Message m4(4, Message::T_HANDSHAKE, 0x2, 3, 1001); fail_unless(m4.serial_size() == 12); buf.clear(); buf.resize(m4.serial_size()); m4.serialize(&buf[0], buf.size(), 0); Message mu4(4); mu4.unserialize(&buf[0], buf.size(), 0); fail_unless(mu4.version() == 4); fail_unless(mu4.type() == Message::T_HANDSHAKE); fail_unless(mu4.flags() == 0x2); fail_unless(mu4.ctrl() == 3); fail_unless(mu4.len() == 1001); } END_TEST // IST tests static pthread_barrier_t start_barrier; class TestOrder { public: TestOrder(galera::TrxHandle& trx) : trx_(trx) { } void lock() { } void unlock() { } wsrep_seqno_t seqno() const { return trx_.global_seqno(); } bool condition(wsrep_seqno_t last_entered, wsrep_seqno_t last_left) const { return (last_left >= trx_.depends_seqno()); } private: galera::TrxHandle& trx_; }; struct sender_args { gcache::GCache& gcache_; const std::string& peer_; wsrep_seqno_t first_; wsrep_seqno_t last_; int version_; sender_args(gcache::GCache& gcache, const std::string& peer, wsrep_seqno_t first, wsrep_seqno_t last, int version) : gcache_(gcache), peer_ (peer), first_ (first), last_ (last), version_(version) { } }; struct receiver_args { std::string listen_addr_; wsrep_seqno_t first_; wsrep_seqno_t last_; size_t n_receivers_; TrxHandle::SlavePool& trx_pool_; int version_; receiver_args(const std::string listen_addr, wsrep_seqno_t first, wsrep_seqno_t last, size_t n_receivers, TrxHandle::SlavePool& sp, int version) : listen_addr_(listen_addr), first_ (first), last_ (last), n_receivers_(n_receivers), trx_pool_ (sp), version_ (version) { } }; struct trx_thread_args { galera::ist::Receiver& receiver_; galera::Monitor monitor_; trx_thread_args(galera::ist::Receiver& receiver) : receiver_(receiver), monitor_() { } }; extern "C" void* sender_thd(void* arg) { mark_point(); const sender_args* sargs(reinterpret_cast(arg)); gu::Config conf; galera::ReplicatorSMM::InitConfig(conf, NULL); pthread_barrier_wait(&start_barrier); galera::ist::Sender sender(conf, sargs->gcache_, sargs->peer_, sargs->version_); mark_point(); sender.send(sargs->first_, sargs->last_); return 0; } extern "C" void* trx_thread(void* arg) { trx_thread_args* targs(reinterpret_cast(arg)); pthread_barrier_wait(&start_barrier); targs->receiver_.ready(); while (true) { galera::TrxHandle* trx(0); int err; if ((err = targs->receiver_.recv(&trx)) != 0) { assert(trx == 0); log_info << "terminated with " << err; return 0; } TestOrder to(*trx); targs->monitor_.enter(to); targs->monitor_.leave(to); trx->unref(); } return 0; } extern "C" void* receiver_thd(void* arg) { mark_point(); receiver_args* rargs(reinterpret_cast(arg)); gu::Config conf; galera::ReplicatorSMM::InitConfig(conf, NULL); mark_point(); conf.set(galera::ist::Receiver::RECV_ADDR, rargs->listen_addr_); galera::ist::Receiver receiver(conf, rargs->trx_pool_, 0); rargs->listen_addr_ = receiver.prepare(rargs->first_, rargs->last_, rargs->version_); mark_point(); std::vector threads(rargs->n_receivers_); trx_thread_args trx_thd_args(receiver); for (size_t i(0); i < threads.size(); ++i) { log_info << "starting trx thread " << i; pthread_create(&threads[0] + i, 0, &trx_thread, &trx_thd_args); } trx_thd_args.monitor_.set_initial_position(rargs->first_ - 1); pthread_barrier_wait(&start_barrier); trx_thd_args.monitor_.wait(rargs->last_); for (size_t i(0); i < threads.size(); ++i) { log_info << "joining trx thread " << i; pthread_join(threads[i], 0); } receiver.finished(); return 0; } static int select_trx_version(int protocol_version) { // see protocol version table in replicator_smm.hpp switch (protocol_version) { case 1: case 2: return 1; case 3: case 4: return 2; case 5: return 3; } fail("unknown protocol version %i", protocol_version); return -1; } static void test_ist_common(int const version) { using galera::KeyData; using galera::TrxHandle; using galera::KeyOS; TrxHandle::LocalPool lp(TrxHandle::LOCAL_STORAGE_SIZE, 4, "ist_common"); TrxHandle::SlavePool sp(sizeof(TrxHandle), 4, "ist_common"); int const trx_version(select_trx_version(version)); TrxHandle::Params const trx_params("", trx_version, galera::KeySet::MAX_VERSION); gu::Config conf; galera::ReplicatorSMM::InitConfig(conf, NULL); std::string gcache_file("ist_check.cache"); conf.set("gcache.name", gcache_file); std::string dir("."); std::string receiver_addr("tcp://127.0.0.1:0"); wsrep_uuid_t uuid; gu_uuid_generate(reinterpret_cast(&uuid), 0, 0); gcache::GCache* gcache = new gcache::GCache(conf, dir); mark_point(); // populate gcache for (size_t i(1); i <= 10; ++i) { TrxHandle* trx(TrxHandle::New(lp, trx_params, uuid, 1234+i, 5678+i)); const wsrep_buf_t key[2] = { {"key1", 4}, {"key2", 4} }; trx->append_key(KeyData(trx_version, key, 2, WSREP_KEY_EXCLUSIVE,true)); trx->append_data("bar", 3, WSREP_DATA_ORDERED, true); assert (i > 0); int last_seen(i - 1); int pa_range(i); gu::byte_t* ptr(0); if (trx_version < 3) { trx->set_last_seen_seqno(last_seen); size_t trx_size(trx->serial_size()); ptr = static_cast(gcache->malloc(trx_size)); trx->serialize(ptr, trx_size, 0); } else { galera::WriteSetNG::GatherVector bufs; ssize_t trx_size(trx->write_set_out().gather(trx->source_id(), trx->conn_id(), trx->trx_id(), bufs)); trx->set_last_seen_seqno(last_seen); ptr = static_cast(gcache->malloc(trx_size)); /* concatenate buffer vector */ gu::byte_t* p(ptr); for (size_t k(0); k < bufs->size(); ++k) { ::memcpy(p, bufs[k].ptr, bufs[k].size); p += bufs[k].size; } assert ((p - ptr) == trx_size); gu::Buf ws_buf = { ptr, trx_size }; galera::WriteSetIn wsi(ws_buf); assert (wsi.last_seen() == last_seen); assert (wsi.pa_range() == 0); wsi.set_seqno(i, pa_range); assert (wsi.seqno() == int64_t(i)); assert (wsi.pa_range() == pa_range); } gcache->seqno_assign(ptr, i, i - pa_range); trx->unref(); } mark_point(); receiver_args rargs(receiver_addr, 1, 10, 1, sp, version); sender_args sargs(*gcache, rargs.listen_addr_, 1, 10, version); pthread_barrier_init(&start_barrier, 0, 1 + 1 + rargs.n_receivers_); pthread_t sender_thread, receiver_thread; pthread_create(&sender_thread, 0, &sender_thd, &sargs); mark_point(); usleep(100000); pthread_create(&receiver_thread, 0, &receiver_thd, &rargs); mark_point(); pthread_join(sender_thread, 0); pthread_join(receiver_thread, 0); mark_point(); delete gcache; mark_point(); unlink(gcache_file.c_str()); } START_TEST(test_ist_v1) { test_ist_common(1); } END_TEST START_TEST(test_ist_v2) { test_ist_common(2); } END_TEST START_TEST(test_ist_v3) { test_ist_common(3); } END_TEST START_TEST(test_ist_v4) { test_ist_common(4); } END_TEST START_TEST(test_ist_v5) { test_ist_common(5); } END_TEST Suite* ist_suite() { Suite* s = suite_create("ist"); TCase* tc; tc = tcase_create("test_ist_message"); tcase_add_test(tc, test_ist_message); suite_add_tcase(s, tc); tc = tcase_create("test_ist_v1"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test_ist_v1); suite_add_tcase(s, tc); tc = tcase_create("test_ist_v2"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test_ist_v2); suite_add_tcase(s, tc); tc = tcase_create("test_ist_v3"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test_ist_v3); suite_add_tcase(s, tc); tc = tcase_create("test_ist_v4"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test_ist_v4); suite_add_tcase(s, tc); tc = tcase_create("test_ist_v5"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test_ist_v5); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galera/tests/key_set_check.cpp000066400000000000000000000165521244131713600227140ustar00rootroot00000000000000/* copyright (C) 2013 Codership Oy * * $Id$ */ #undef NDEBUG #include "test_key.hpp" #include "../src/key_set.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" #include using namespace galera; class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; static size_t version_to_hash_size (KeySet::Version const ver) { switch (ver) { case KeySet::FLAT16: fail("FLAT16 is not supported by test"); case KeySet::FLAT16A: return 16; case KeySet::FLAT8: fail ("FLAT8 is not supported by test"); case KeySet::FLAT8A: return 8; default: fail ("Unsupported KeySet verison: %d", ver); } abort(); } START_TEST (ver0) { KeySet::Version const tk_ver(KeySet::FLAT16A); size_t const base_size(version_to_hash_size(tk_ver)); gu::byte_t reserved[1024]; TestBaseName const str("key_set_test"); KeySetOut kso (reserved, sizeof(reserved), str, tk_ver); fail_if (kso.count() != 0); size_t total_size(kso.size()); log_info << "Start size: " << total_size; TestKey tk0(tk_ver, SHARED, false, "a0"); kso.append(tk0()); fail_if (kso.count() != 1); total_size += base_size + 2 + 1*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); kso.append(tk0()); fail_if (kso.count() != 1); fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); TestKey tk1(tk_ver, SHARED, true, "a0", "a1", "a2"); mark_point(); kso.append(tk1()); fail_if (kso.count() != 3, "key count: expected 3, got %d", kso.count()); total_size += base_size + 2 + 2*4; total_size += base_size + 2 + 3*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); TestKey tk2(tk_ver, EXCLUSIVE, false, "a0", "a1", "b2"); kso.append(tk2()); fail_if (kso.count() != 4, "key count: expected 4, got %d", kso.count()); total_size += base_size + 2 + 3*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* it is a duplicate, but it should add an exclusive verision of the key */ TestKey tk3(tk_ver, EXCLUSIVE, true, "a0", "a1"); log_info << "######## Appending exclusive duplicate tk3: begin"; kso.append(tk3()); log_info << "######## Appending exclusive duplicate tk3: end"; fail_if (kso.count() != 5, "key count: expected 5, got %d", kso.count()); total_size += base_size + 2 + 2*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* tk3 should make it impossible to add anything past a0:a1 */ TestKey tk4(tk_ver, EXCLUSIVE, false, "a0", "a1", "c2"); kso.append(tk4()); fail_if (kso.count() != 5, "key count: expected 5, got %d", kso.count()); fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* adding shared key should have no effect */ TestKey tk5(tk_ver, SHARED, true, "a0", "a1"); kso.append(tk5()); fail_if (kso.count() != 5, "key count: expected 5, got %d", kso.count()); fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* tk5 should not make any changes */ TestKey tk6(tk_ver, EXCLUSIVE, false, "a0", "a1", "c2"); kso.append(tk6()); fail_if (kso.count() != 5, "key count: expected 5, got %d", kso.count()); fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* a0:b1:... should still be possible, should add 2 keys: b1 and c2 */ TestKey tk7(tk_ver, EXCLUSIVE, true, "a0", "b1", "c2"); kso.append(tk7()); fail_if (kso.count() != 7, "key count: expected 7, got %d", kso.count()); total_size += base_size + 2 + 2*4; total_size += base_size + 2 + 3*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); /* make sure a0:b1:b2 is possible despite we have a0:a1:b2 already * (should be no collision on b2) */ TestKey tk8(tk_ver, EXCLUSIVE, false, "a0", "b1", "b2"); kso.append(tk8()); fail_if (kso.count() != 8, "key count: expected 8, got %d", kso.count()); total_size += base_size + 2 + 3*4; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); log_info << "size before huge key: " << total_size; char huge_key[2048]; memset (huge_key, 'x', sizeof(huge_key)); huge_key[ sizeof(huge_key) - 1 ] = 0; TestKey tk9(tk_ver, EXCLUSIVE, false, huge_key, huge_key, huge_key); kso.append(tk9()); fail_if (kso.count() != 11, "key count: expected 11, got %d", kso.count()); total_size += base_size + 2 + 1*256; total_size += base_size + 2 + 2*256; total_size += base_size + 2 + 3*256; fail_if (total_size != kso.size(), "Size: %zu, expected: %zu", kso.size(), total_size); log_info << "End size: " << kso.size(); KeySetOut::GatherVector out; out->reserve(kso.page_count()); size_t const out_size(kso.gather(out)); log_info << "Gather size: " << out_size << ", buf count: " << out->size(); std::vector in; in.reserve(out_size); for (size_t i(0); i < out->size(); ++i) { const gu::byte_t* ptr(reinterpret_cast(out[i].ptr)); in.insert (in.end(), ptr, ptr + out[i].size); } fail_if (in.size() != out_size); KeySetIn ksi (kso.version(), in.data(), in.size()); fail_if (ksi.count() != kso.count(), "Received keys: %zu, expected: %zu", ksi.count(), kso.count()); fail_if (ksi.size() != kso.size(), "Received size: %zu, expected: %zu", ksi.size(), kso.size()); try { ksi.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } int shared(0); // to stiffle clang complaints about unused variables for (int i(0); i < ksi.count(); ++i) { KeySet::KeyPart kp(ksi.next()); shared += kp.shared(); } KeySetIn ksi_empty; fail_if (ksi_empty.count() != 0, "Received keys: %zu, expected: %zu", ksi_empty.count(), 0); fail_if (ksi_empty.size() != 0, "Received size: %zu, expected: %zu", ksi_empty.size(), 0); ksi_empty.init (kso.version(), in.data(), in.size()); fail_if (ksi_empty.count() != kso.count(), "Received keys: %zu, expected: %zu", ksi_empty.count(), kso.count()); fail_if (ksi_empty.size() != kso.size(), "Received size: %zu, expected: %zu", ksi_empty.size(), kso.size()); try { ksi_empty.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } for (int i(0); i < ksi_empty.count(); ++i) { KeySet::KeyPart kp(ksi_empty.next()); shared += kp.shared(); } ksi_empty.rewind(); for (int i(0); i < ksi_empty.count(); ++i) { KeySet::KeyPart kp(ksi_empty.next()); shared += kp.shared(); } fail_if(0 == shared); } END_TEST Suite* key_set_suite () { TCase* t = tcase_create ("KeySet"); tcase_add_test (t, ver0); tcase_set_timeout(t, 60); Suite* s = suite_create ("KeySet"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galera/tests/saved_state_check.cpp000066400000000000000000000107721244131713600235510ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ #include "../src/saved_state.hpp" #include "../src/uuid.hpp" #include #include #include #define __STDC_FORMAT_MACROS #include static volatile bool stop(false); using namespace galera; static void* thread_routine (void* arg) { SavedState* st(reinterpret_cast(arg)); do { st->mark_unsafe(); st->mark_safe(); } while (!stop); return NULL; } static const int max_threads(16); static pthread_t threads[max_threads]; static void start_threads(void* arg) { stop = false; for (int ret = 0; ret < max_threads; ++ret) { pthread_t t; int err = pthread_create (&t, NULL, thread_routine, arg); fail_if (err, "Failed to start thread %d: %d (%s)", ret, err, strerror(err)); threads[ret] = t; } } static void stop_threads() { stop = true; for (int t = 0; t < max_threads; ++t) { pthread_join(threads[t], NULL); } } static const char* fname("grastate.dat"); START_TEST(test_basic) { unlink (fname); wsrep_uuid_t uuid; wsrep_seqno_t seqno; { SavedState st(fname); st.get(uuid, seqno); fail_if (uuid != WSREP_UUID_UNDEFINED); fail_if (seqno != WSREP_SEQNO_UNDEFINED); gu_uuid_from_string("b2c01654-8dfe-11e1-0800-a834d641cfb5", to_gu_uuid(uuid)); seqno = 2345234LL; st.set(uuid, seqno); } { SavedState st(fname); wsrep_uuid_t u; wsrep_seqno_t s; st.get(u, s); fail_if (u != uuid); fail_if (s != seqno); } } END_TEST #define TEST_USLEEP 2500 // 2.5ms START_TEST(test_unsafe) { SavedState st(fname); wsrep_uuid_t uuid; wsrep_seqno_t seqno; st.get(uuid, seqno); fail_if (uuid == WSREP_UUID_UNDEFINED); fail_if (seqno == WSREP_SEQNO_UNDEFINED); st.set(uuid, WSREP_SEQNO_UNDEFINED); for (int i = 0; i < 100; ++i) { start_threads(&st); mark_point(); usleep (TEST_USLEEP); st.set(uuid, i); // make sure that state is not lost if set concurrently mark_point(); usleep (TEST_USLEEP); stop_threads(); mark_point(); st.get(uuid, seqno); fail_if (uuid == WSREP_UUID_UNDEFINED); fail_if (seqno != i); } long marks, locks, writes; st.stats(marks, locks, writes); log_info << "Total marks: " << marks << ", total writes: " << writes << ", total locks: " << locks << "\nlocks ratio: " << (double(locks)/marks) << "\nwrites ratio: " << (double(writes)/locks); } END_TEST START_TEST(test_corrupt) { wsrep_uuid_t uuid; wsrep_seqno_t seqno; { SavedState st(fname); st.get(uuid, seqno); fail_if (uuid == WSREP_UUID_UNDEFINED); fail_if (seqno == WSREP_SEQNO_UNDEFINED); st.set(uuid, WSREP_SEQNO_UNDEFINED); } long marks(0), locks(0), writes(0); for (int i = 0; i < 100; ++i) { SavedState st(fname); // explicitly overwrite corruption mark. st.set (uuid, seqno); start_threads(&st); mark_point(); usleep (TEST_USLEEP); st.mark_corrupt(); st.set (uuid, seqno); // make sure that corrupt stays usleep (TEST_USLEEP); mark_point(); stop_threads(); mark_point(); wsrep_uuid_t u; wsrep_seqno_t s; st.get(u, s); // make sure that mark_corrupt() stays fail_if (u != WSREP_UUID_UNDEFINED); fail_if (s != WSREP_SEQNO_UNDEFINED); long m, l, w; st.stats(m, l, w); marks += m; locks += l; writes += w; } log_info << "Total marks: " << marks << ", total locks: " << locks << ", total writes: " << writes << "\nlocks ratio: " << (double(locks)/marks) << "\nwrites ratio: " << (double(writes)/locks); unlink (fname); } END_TEST #define WAIT_FOR(cond) \ { int count = 1000; while (--count && !(cond)) { usleep (TEST_USLEEP); }} Suite* saved_state_suite() { Suite* s = suite_create ("saved_state"); TCase* tc; tc = tcase_create ("saved_state"); tcase_add_test (tc, test_basic); tcase_add_test (tc, test_unsafe); tcase_add_test (tc, test_corrupt); tcase_set_timeout(tc, 120); suite_add_tcase (s, tc); return s; } percona-galera-3-3.8-3390/galera/tests/service_thd_check.cpp000066400000000000000000000056341244131713600235470ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ #define __STDC_FORMAT_MACROS #include "../src/galera_service_thd.hpp" #include "../src/replicator_smm.hpp" #include #include #include namespace { class TestEnv { public: TestEnv() : conf_ (), init_ (conf_, NULL), gcache_ (conf_, "."), gcs_ (conf_, gcache_) {} gcache::GCache& gcache() { return gcache_; } galera::DummyGcs& gcs() { return gcs_; } private: gu::Config conf_; galera::ReplicatorSMM::InitConfig init_; gcache::GCache gcache_; galera::DummyGcs gcs_; }; } using namespace galera; START_TEST(service_thd1) { TestEnv env; ServiceThd* thd = new ServiceThd(env.gcs(), env.gcache()); fail_if (thd == 0); delete thd; } END_TEST #define TEST_USLEEP 1000 // 1ms #define WAIT_FOR(cond) \ { int count = 1000; while (--count && !(cond)) { usleep (TEST_USLEEP); }} START_TEST(service_thd2) { TestEnv env; DummyGcs& conn(env.gcs()); ServiceThd* thd = new ServiceThd(conn, env.gcache()); fail_if (thd == 0); conn.set_last_applied(0); gcs_seqno_t seqno = 1; thd->report_last_committed (seqno); thd->flush(); WAIT_FOR(conn.last_applied() == seqno); fail_if (conn.last_applied() != seqno, "seqno = %" PRId64 ", expected %" PRId64, conn.last_applied(), seqno); seqno = 5; thd->report_last_committed (seqno); thd->flush(); WAIT_FOR(conn.last_applied() == seqno); fail_if (conn.last_applied() != seqno, "seqno = %" PRId64 ", expected %" PRId64, conn.last_applied(), seqno); thd->report_last_committed (3); thd->flush(); WAIT_FOR(conn.last_applied() == seqno); fail_if (conn.last_applied() != seqno, "seqno = %" PRId64 ", expected %" PRId64, conn.last_applied(), seqno); thd->reset(); seqno = 3; thd->report_last_committed (seqno); thd->flush(); WAIT_FOR(conn.last_applied() == seqno); fail_if (conn.last_applied() != seqno, "seqno = %" PRId64 ", expected %" PRId64, conn.last_applied(), seqno); delete thd; } END_TEST START_TEST(service_thd3) { TestEnv env; ServiceThd* thd = new ServiceThd(env.gcs(), env.gcache()); fail_if (thd == 0); // so far for empty GCache the following should be a noop. thd->release_seqno(-1); thd->release_seqno(2345); thd->release_seqno(234645676); delete thd; } END_TEST Suite* service_thd_suite() { Suite* s = suite_create ("service_thd"); TCase* tc; tc = tcase_create ("service_thd"); tcase_add_test (tc, service_thd1); tcase_add_test (tc, service_thd2); tcase_add_test (tc, service_thd3); suite_add_tcase (s, tc); return s; } percona-galera-3-3.8-3390/galera/tests/test_key.hpp000066400000000000000000000046511244131713600217450ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef _TEST_KEY_HPP_ #define _TEST_KEY_HPP_ #include "../src/key_data.hpp" #include "../src/key_set.hpp" // for version_to_hash_size #include // for version_to_hash_size #include #include using namespace galera; class TestKey { public: TestKey (int a, int ver, bool exclusive, std::vector parts, bool copy = true) : parts_ (), ver_ (ver), exclusive_(exclusive), copy_ (copy) { parts_.reserve(parts.size()); for (size_t i = 0; i < parts.size(); ++i) { size_t p_len(parts[i] ? strlen(parts[i]) + 1 : 0); wsrep_buf_t b = { parts[i], p_len }; parts_.push_back(b); } } TestKey (int ver, bool exclusive, bool copy, const char* part0, const char* part1 = 0, const char* part2 = 0, const char* part3 = 0, const char* part4 = 0, const char* part5 = 0, const char* part6 = 0, const char* part7 = 0, const char* part8 = 0, const char* part9 = 0 ) : parts_ (), ver_ (ver), exclusive_(exclusive), copy_ (copy) { parts_.reserve(10); (push_back(part0) && push_back(part1) && push_back(part2) && push_back(part3) && push_back(part4) && push_back(part5) && push_back(part6) && push_back(part7) && push_back(part8) && push_back(part9)); } KeyData operator() () { return KeyData (ver_, parts_.data(), parts_.size(), exclusive_ ? WSREP_KEY_EXCLUSIVE : WSREP_KEY_SHARED, copy_); } private: std::vector parts_; int const ver_; bool const exclusive_; bool const copy_; bool push_back (const char* const p) { size_t p_len(-1); if (p && (p_len = strlen(p) + 1) > 0) { wsrep_buf_t b = { p, p_len }; parts_.push_back(b); return true; } return false; } }; enum { SHARED = false, EXCLUSIVE = true }; #endif /* _TEST_KEY_HPP_ */ percona-galera-3-3.8-3390/galera/tests/trx_handle_check.cpp000066400000000000000000000156601244131713600234000ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // #include "trx_handle.hpp" #include "uuid.hpp" #include using namespace std; using namespace galera; START_TEST(test_states) { TrxHandle::LocalPool tp(TrxHandle::LOCAL_STORAGE_SIZE, 16, "test_states"); wsrep_uuid_t uuid = {{1, }}; // first check basic stuff // 1) initial state is executing // 2) invalid state changes are caught // 3) valid state changes change state TrxHandle* trx(TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1)); log_info << *trx; fail_unless(trx->state() == TrxHandle::S_EXECUTING); #if 0 // now setting wrong state results in abort try { trx->set_state(TrxHandle::S_COMMITTED); fail(""); } catch (...) { fail_unless(trx->state() == TrxHandle::S_EXECUTING); } #endif trx->set_state(TrxHandle::S_REPLICATING); fail_unless(trx->state() == TrxHandle::S_REPLICATING); trx->unref(); // abort before replication trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_ABORTING); trx->set_state(TrxHandle::S_ROLLED_BACK); trx->unref(); // aborted during replication and does not certify trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_ABORTING); trx->set_state(TrxHandle::S_ROLLED_BACK); trx->unref(); // aborted during replication and certifies but does not certify // during replay (is this even possible?) trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_CERT_AND_REPLAY); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_ABORTING); trx->set_state(TrxHandle::S_ROLLED_BACK); trx->unref(); // aborted during replication, certifies and commits trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_CERT_AND_REPLAY); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_MUST_REPLAY_AM); trx->set_state(TrxHandle::S_MUST_REPLAY_CM); trx->set_state(TrxHandle::S_MUST_REPLAY); trx->set_state(TrxHandle::S_REPLAYING); trx->set_state(TrxHandle::S_COMMITTED); trx->unref(); // aborted during certification, replays and commits trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_CERT_AND_REPLAY); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_MUST_REPLAY_AM); trx->set_state(TrxHandle::S_MUST_REPLAY_CM); trx->set_state(TrxHandle::S_MUST_REPLAY); trx->set_state(TrxHandle::S_REPLAYING); trx->set_state(TrxHandle::S_COMMITTED); trx->unref(); // aborted while waiting applying, replays and commits trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_APPLYING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_REPLAY_AM); trx->set_state(TrxHandle::S_MUST_REPLAY_CM); trx->set_state(TrxHandle::S_MUST_REPLAY); trx->set_state(TrxHandle::S_REPLAYING); trx->set_state(TrxHandle::S_COMMITTED); trx->unref(); // aborted while waiting for commit order, replays and commits trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_APPLYING); trx->set_state(TrxHandle::S_COMMITTING); trx->set_state(TrxHandle::S_MUST_ABORT); trx->set_state(TrxHandle::S_MUST_REPLAY_CM); trx->set_state(TrxHandle::S_MUST_REPLAY); trx->set_state(TrxHandle::S_REPLAYING); trx->set_state(TrxHandle::S_COMMITTED); trx->unref(); // smooth operation trx = TrxHandle::New(tp, TrxHandle::Defaults, uuid, -1, 1); trx->set_state(TrxHandle::S_REPLICATING); trx->set_state(TrxHandle::S_CERTIFYING); trx->set_state(TrxHandle::S_APPLYING); trx->set_state(TrxHandle::S_COMMITTING); trx->set_state(TrxHandle::S_COMMITTED); trx->unref(); } END_TEST START_TEST(test_serialization) { TrxHandle::LocalPool lp(4096, 16, "serialization_lp"); TrxHandle::SlavePool sp(sizeof(TrxHandle), 16, "serialization_sp"); int const version(0); galera::TrxHandle::Params const trx_params("", version,KeySet::MAX_VERSION); wsrep_uuid_t uuid; gu_uuid_generate(reinterpret_cast(&uuid), 0, 0); TrxHandle* trx(TrxHandle::New(lp, trx_params, uuid, 4567, 8910)); fail_unless(trx->serial_size() == 4 + 16 + 8 + 8 + 8 + 8); trx->set_flags(trx->flags() | TrxHandle::F_MAC_HEADER); fail_unless(trx->serial_size() == 4 + 16 + 8 + 8 + 8 + 8 + 2); trx->set_flags(trx->flags() & ~TrxHandle::F_MAC_HEADER); fail_unless(trx->serial_size() == 4 + 16 + 8 + 8 + 8 + 8); trx->append_annotation(reinterpret_cast("foobar"), strlen("foobar")); trx->set_flags(trx->flags() | TrxHandle::F_ANNOTATION); fail_unless(trx->serial_size() == 4 + 16 + 8 + 8 + 8 + 8 + 4 + 6); trx->set_flags(trx->flags() & ~TrxHandle::F_ANNOTATION); fail_unless(trx->serial_size() == 4 + 16 + 8 + 8 + 8 + 8); trx->set_last_seen_seqno(0); TrxHandle* trx2(TrxHandle::New(sp)); std::vector buf(trx->serial_size()); fail_unless(trx->serialize(&buf[0], buf.size(), 0) > 0); fail_unless(trx2->unserialize(&buf[0], buf.size(), 0) > 0); trx->set_flags(trx->flags() | TrxHandle::F_MAC_PAYLOAD); buf.resize(trx->serial_size()); fail_unless(trx->serialize(&buf[0], buf.size(), 0) > 0); fail_unless(trx2->unserialize(&buf[0], buf.size(), 0) > 0); trx->set_flags(trx->flags() | TrxHandle::F_ANNOTATION); buf.resize(trx->serial_size()); fail_unless(trx->serialize(&buf[0], buf.size(), 0) > 0); fail_unless(trx2->unserialize(&buf[0], buf.size(), 0) > 0); fail_unless(trx2->serial_size() == trx->serial_size(), "got serial_size(*trx2) = %zu, serial_size(*trx) = %zu", trx2->serial_size(), trx->serial_size()); trx2->unref(); trx->unref(); } END_TEST Suite* trx_handle_suite() { Suite* s = suite_create("trx_handle"); TCase* tc; tc = tcase_create("test_states"); tcase_add_test(tc, test_states); suite_add_tcase(s, tc); tc = tcase_create("test_serialization"); tcase_add_test(tc, test_serialization); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galera/tests/write_set_check.cpp000066400000000000000000000502151244131713600232500ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ #include "write_set.hpp" #include "mapped_buffer.hpp" #include "gu_logger.hpp" #include "certification.hpp" #include "replicator_smm.hpp" #include "wsdb.cpp" #include "gcs_action_source.hpp" #include "galera_service_thd.hpp" #include #include namespace { class TestEnv { public: TestEnv() : conf_ (), init_ (conf_, NULL), gcache_ (conf_, "."), gcs_ (conf_, gcache_), thd_ (gcs_, gcache_) {} ~TestEnv() {} gu::Config& conf() { return conf_; } galera::ServiceThd& thd() { return thd_; } private: // REMOVE galera::Certification::register_params(conf); gu::Config conf_; galera::ReplicatorSMM::InitConfig init_; gcache::GCache gcache_; galera::DummyGcs gcs_; galera::ServiceThd thd_; }; } using namespace std; using namespace galera; typedef std::vector KeyPartSequence; START_TEST(test_key1) { static char k1[16]; static char k2[256]; static char k3[1 << 21]; static char k4[(1 << 22) - 5]; memset(k1, 0xab, sizeof(k1)); memset(k2, 0xcd, sizeof(k2)); memset(k3, 0x9e, sizeof(k3)); memset(k4, 0x8f, sizeof(k4)); const wsrep_buf_t kiovec[4] = { {k1, sizeof k1 }, {k2, sizeof k2 }, {k3, sizeof k3 }, {k4, sizeof k4 } }; KeyOS key(1, kiovec, 4, 0); size_t expected_size(0); #ifndef GALERA_KEY_VLQ expected_size += 1 + std::min(sizeof k1, size_t(0xff)); expected_size += 1 + std::min(sizeof k2, size_t(0xff)); expected_size += 1 + std::min(sizeof k3, size_t(0xff)); expected_size += 1 + std::min(sizeof k4, size_t(0xff)); expected_size += sizeof(uint16_t); #else expected_size += gu::uleb128_size(sizeof k1) + sizeof k1; expected_size += gu::uleb128_size(sizeof k2) + sizeof k2; expected_size += gu::uleb128_size(sizeof k3) + sizeof k3; expected_size += gu::uleb128_size(sizeof k4) + sizeof k4; expected_size += gu::uleb128_size(expected_size); #endif fail_unless(key.serial_size() == expected_size, "%ld <-> %ld", key.serial_size(), expected_size); KeyPartSequence kp(key.key_parts()); fail_unless(kp.size() == 4); gu::Buffer buf(key.serial_size()); key.serialize(&buf[0], buf.size(), 0); KeyOS key2(1); key2.unserialize(&buf[0], buf.size(), 0); fail_unless(key2 == key); } END_TEST START_TEST(test_key2) { static char k1[16]; static char k2[256]; static char k3[1 << 21]; static char k4[(1 << 22) - 5]; memset(k1, 0xab, sizeof(k1)); memset(k2, 0xcd, sizeof(k2)); memset(k3, 0x9e, sizeof(k3)); memset(k4, 0x8f, sizeof(k4)); const wsrep_buf_t kiovec[4] = { {k1, sizeof k1 }, {k2, sizeof k2 }, {k3, sizeof k3 }, {k4, sizeof k4 } }; KeyOS key(2, kiovec, 4, 0); size_t expected_size(0); expected_size += 1; // flags #ifndef GALERA_KEY_VLQ expected_size += 1 + std::min(sizeof k1, size_t(0xff)); expected_size += 1 + std::min(sizeof k2, size_t(0xff)); expected_size += 1 + std::min(sizeof k3, size_t(0xff)); expected_size += 1 + std::min(sizeof k4, size_t(0xff)); expected_size += sizeof(uint16_t); #else expected_size += gu::uleb128_size(sizeof k1) + sizeof k1; expected_size += gu::uleb128_size(sizeof k2) + sizeof k2; expected_size += gu::uleb128_size(sizeof k3) + sizeof k3; expected_size += gu::uleb128_size(sizeof k4) + sizeof k4; expected_size += gu::uleb128_size(expected_size); #endif fail_unless(key.serial_size() == expected_size, "%ld <-> %ld", key.serial_size(), expected_size); KeyPartSequence kp(key.key_parts()); fail_unless(kp.size() == 4); gu::Buffer buf(key.serial_size()); key.serialize(&buf[0], buf.size(), 0); KeyOS key2(2); key2.unserialize(&buf[0], buf.size(), 0); fail_unless(key2 == key); } END_TEST START_TEST(test_write_set1) { WriteSet ws(1); const wsrep_buf_t key1[2] = { {void_cast("dbt\0t1"), 6}, {void_cast("aaa") , 3} }; const wsrep_buf_t key2[2] = { {void_cast("dbt\0t2"), 6}, {void_cast("bbbb"), 4} }; const char* rbr = "rbrbuf"; size_t rbr_len = 6; log_info << "ws0 " << ws.serial_size(); ws.append_key(KeyData(1, key1, 2, WSREP_KEY_EXCLUSIVE, true)); log_info << "ws1 " << ws.serial_size(); ws.append_key(KeyData(1, key2, 2, WSREP_KEY_EXCLUSIVE, true)); log_info << "ws2 " << ws.serial_size(); ws.append_data(rbr, rbr_len); gu::Buffer rbrbuf(rbr, rbr + rbr_len); log_info << "rbrlen " << gu::serial_size4(rbrbuf); log_info << "wsrbr " << ws.serial_size(); gu::Buffer buf(ws.serial_size()); ws.serialize(&buf[0], buf.size(), 0); size_t expected_size = 4 // row key sequence size #ifndef GALERA_KEY_VLQ + 2 + 1 + 6 + 1 + 3 // key1 + 2 + 1 + 6 + 1 + 4 // key2 #else + 1 + 1 + 6 + 1 + 3 // key1 + 1 + 1 + 6 + 1 + 4 // key2 #endif + 4 + 6; // rbr fail_unless(buf.size() == expected_size, "%zd <-> %zd <-> %zd", buf.size(), expected_size, ws.serial_size()); WriteSet ws2(0); size_t ret = ws2.unserialize(&buf[0], buf.size(), 0); fail_unless(ret == expected_size); WriteSet::KeySequence rks; ws.get_keys(rks); WriteSet::KeySequence rks2; ws.get_keys(rks2); fail_unless(rks2 == rks); fail_unless(ws2.get_data() == ws.get_data()); } END_TEST START_TEST(test_write_set2) { WriteSet ws(2); const wsrep_buf_t key1[2] = { {void_cast("dbt\0t1"), 6}, {void_cast("aaa") , 3} }; const wsrep_buf_t key2[2] = { {void_cast("dbt\0t2"), 6}, {void_cast("bbbb"), 4} }; const char* rbr = "rbrbuf"; size_t rbr_len = 6; log_info << "ws0 " << ws.serial_size(); ws.append_key(KeyData(2, key1, 2, WSREP_KEY_EXCLUSIVE, true)); log_info << "ws1 " << ws.serial_size(); ws.append_key(KeyData(2, key2, 2, WSREP_KEY_EXCLUSIVE, true)); log_info << "ws2 " << ws.serial_size(); ws.append_data(rbr, rbr_len); gu::Buffer rbrbuf(rbr, rbr + rbr_len); log_info << "rbrlen " << gu::serial_size4(rbrbuf); log_info << "wsrbr " << ws.serial_size(); gu::Buffer buf(ws.serial_size()); ws.serialize(&buf[0], buf.size(), 0); size_t expected_size = 4 // row key sequence size #ifndef GALERA_KEY_VLQ + 2 + 1 + 1 + 6 + 1 + 3 // key1 + 2 + 1 + 1 + 6 + 1 + 4 // key2 #else + 1 + 1 + 6 + 1 + 3 // key1 + 1 + 1 + 6 + 1 + 4 // key2 #endif + 4 + 6; // rbr fail_unless(buf.size() == expected_size, "%zd <-> %zd <-> %zd", buf.size(), expected_size, ws.serial_size()); WriteSet ws2(2); size_t ret = ws2.unserialize(&buf[0], buf.size(), 0); fail_unless(ret == expected_size); WriteSet::KeySequence rks; ws.get_keys(rks); WriteSet::KeySequence rks2; ws2.get_keys(rks2); fail_unless(rks2 == rks); fail_unless(ws2.get_data() == ws.get_data()); } END_TEST START_TEST(test_mapped_buffer) { string wd("/tmp"); MappedBuffer mb(wd, 1 << 8); mb.resize(16); for (size_t i = 0; i < 16; ++i) { mb[i] = static_cast(i); } mb.resize(1 << 8); for (size_t i = 0; i < 16; ++i) { fail_unless(mb[i] == static_cast(i)); } for (size_t i = 16; i < (1 << 8); ++i) { mb[i] = static_cast(i); } mb.resize(1 << 20); for (size_t i = 0; i < (1 << 8); ++i) { fail_unless(mb[i] == static_cast(i)); } for (size_t i = 0; i < (1 << 20); ++i) { mb[i] = static_cast(i); } } END_TEST static TrxHandle::LocalPool lp(TrxHandle::LOCAL_STORAGE_SIZE, 4, "ws_local_pool"); static TrxHandle::SlavePool sp(sizeof(TrxHandle), 4, "ws_slave_pool"); START_TEST(test_cert_hierarchical_v1) { log_info << "test_cert_hierarchical_v1"; struct wsinfo_ { wsrep_uuid_t uuid; wsrep_conn_id_t conn_id; wsrep_trx_id_t trx_id; wsrep_buf_t key[3]; size_t iov_len; wsrep_seqno_t local_seqno; wsrep_seqno_t global_seqno; wsrep_seqno_t last_seen_seqno; wsrep_seqno_t expected_depends_seqno; int flags; Certification::TestResult result; } wsi[] = { // 1 - 3, test symmetric case for dependencies // 1: no dependencies { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 1, 1, 0, 0, 0, Certification::TEST_OK}, // 2: depends on 1, no conflict { { {1, } }, 1, 1, { {void_cast("1"), 1}, {void_cast("1"), 1} }, 2, 2, 2, 0, 1, 0, Certification::TEST_OK}, // 3: depends on 2, no conflict { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 3, 3, 0, 2, 0, Certification::TEST_OK}, // 4 - 8, test symmetric case for conflicts // 4: depends on 3, no conflict { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 4, 4, 3, 3, 0, Certification::TEST_OK}, // 5: conflict with 4 { { {2, } }, 1, 1, { {void_cast("1"), 1}, {void_cast("1"), 1} }, 2, 5, 5, 3, -1, 0, Certification::TEST_FAILED}, // 6: depends on 4 (failed 5 not present in index), no conflict { { {2, } }, 1, 1, { {void_cast("1"), 1}, {void_cast("1"), 1} }, 2, 6, 6, 5, 4, 0, Certification::TEST_OK}, // 7: conflicts with 6 { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 7, 7, 5, -1, 0, Certification::TEST_FAILED}, // 8: to isolation: must not conflict, depends on global_seqno - 1 { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 8, 8, 5, 7, TrxHandle::F_ISOLATION, Certification::TEST_OK}, // 9: to isolation: must not conflict, depends on global_seqno - 1 { { {2, } }, 1, 1, { {void_cast("1"), 1}, }, 1, 9, 9, 5, 8, TrxHandle::F_ISOLATION, Certification::TEST_OK}, }; size_t nws(sizeof(wsi)/sizeof(wsi[0])); TestEnv env; galera::Certification cert(env.conf(), env.thd()); int const version(1); cert.assign_initial_position(0, version); galera::TrxHandle::Params const trx_params("", version,KeySet::MAX_VERSION); mark_point(); for (size_t i(0); i < nws; ++i) { TrxHandle* trx(TrxHandle::New(lp, trx_params, wsi[i].uuid, wsi[i].conn_id, wsi[i].trx_id)); trx->append_key(KeyData(1, wsi[i].key, wsi[i].iov_len, WSREP_KEY_EXCLUSIVE, true)); trx->set_last_seen_seqno(wsi[i].last_seen_seqno); trx->set_flags(trx->flags() | wsi[i].flags); trx->flush(0); // serialize/unserialize to verify that ver1 trx is serializable const galera::MappedBuffer& wc(trx->write_set_collection()); gu::Buffer buf(wc.size()); std::copy(&wc[0], &wc[0] + wc.size(), &buf[0]); trx->unref(); trx = TrxHandle::New(sp); size_t offset(trx->unserialize(&buf[0], buf.size(), 0)); log_info << "ws[" << i << "]: " << buf.size() - offset; trx->append_write_set(&buf[0] + offset, buf.size() - offset); trx->set_received(0, wsi[i].local_seqno, wsi[i].global_seqno); Certification::TestResult result(cert.append_trx(trx)); fail_unless(result == wsi[i].result, "g: %lld r: %d er: %d", trx->global_seqno(), result, wsi[i].result); fail_unless(trx->depends_seqno() == wsi[i].expected_depends_seqno, "wsi: %zu g: %lld ld: %lld eld: %lld", i, trx->global_seqno(), trx->depends_seqno(), wsi[i].expected_depends_seqno); cert.set_trx_committed(trx); trx->unref(); } } END_TEST START_TEST(test_cert_hierarchical_v2) { log_info << "test_cert_hierarchical_v2"; const int version(2); struct wsinfo_ { wsrep_uuid_t uuid; wsrep_conn_id_t conn_id; wsrep_trx_id_t trx_id; wsrep_buf_t key[3]; size_t iov_len; bool shared; wsrep_seqno_t local_seqno; wsrep_seqno_t global_seqno; wsrep_seqno_t last_seen_seqno; wsrep_seqno_t expected_depends_seqno; int flags; Certification::TestResult result; } wsi[] = { // 1 - 4: shared - shared // First four cases are shared keys, they should not collide or // generate dependency // 1: no dependencies { { {1, } }, 1, 1, { {void_cast("1"), 1}, }, 1, true, 1, 1, 0, 0, 0, Certification::TEST_OK}, // 2: no dependencies { { {1, } }, 1, 2, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 2, 2, 0, 0, 0, Certification::TEST_OK}, // 3: no dependencies { { {2, } }, 1, 3, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 3, 3, 0, 0, 0, Certification::TEST_OK}, // 4: no dependencies { { {3, } }, 1, 4, { {void_cast("1"), 1}, }, 1, true, 4, 4, 0, 0, 0, Certification::TEST_OK}, // 5: shared - exclusive // 5: depends on 4 { { {2, } }, 1, 5, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, false, 5, 5, 0, 4, 0, Certification::TEST_OK}, // 6 - 8: exclusive - shared // 6: collides with 5 { { {1, } }, 1, 6, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 6, 6, 4, -1, 0, Certification::TEST_FAILED}, // 7: collides with 5 { { {1, } }, 1, 7, { {void_cast("1"), 1}, }, 1, true, 7, 7, 4, -1, 0, Certification::TEST_FAILED}, // 8: collides with 5 { { {1, } }, 1, 8, { {void_cast("1"), 1}, {void_cast("1"), 1}, {void_cast("1"), 1}}, 3, true, 8, 8, 4, -1, 0, Certification::TEST_FAILED}, // 9 - 10: shared key shadows dependency to 5 // 9: depends on 5 { { {2, } }, 1, 9, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 9, 9, 0, 5, 0, Certification::TEST_OK}, // 10: depends on 5 { { {2, } }, 1, 10, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 10, 10, 6, 5, 0, Certification::TEST_OK}, // 11 - 13: exclusive - shared - exclusive dependency { { {2, } }, 1, 11, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, false, 11, 11, 10, 10, 0, Certification::TEST_OK}, { { {2, } }, 1, 12, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, true, 12, 12, 10, 11, 0, Certification::TEST_OK}, { { {2, } }, 1, 13, { {void_cast("1"), 1}, {void_cast("1"), 1}, }, 2, false, 13, 13, 10, 12, 0, Certification::TEST_OK}, }; size_t nws(sizeof(wsi)/sizeof(wsi[0])); TestEnv env; galera::Certification cert(env.conf(), env.thd()); cert.assign_initial_position(0, version); galera::TrxHandle::Params const trx_params("", version,KeySet::MAX_VERSION); mark_point(); for (size_t i(0); i < nws; ++i) { TrxHandle* trx(TrxHandle::New(lp, trx_params, wsi[i].uuid, wsi[i].conn_id, wsi[i].trx_id)); trx->append_key(KeyData(version, wsi[i].key, wsi[i].iov_len, (wsi[i].shared ? WSREP_KEY_SHARED : WSREP_KEY_EXCLUSIVE), true)); trx->set_last_seen_seqno(wsi[i].last_seen_seqno); trx->set_flags(trx->flags() | wsi[i].flags); trx->flush(0); // serialize/unserialize to verify that ver1 trx is serializable const galera::MappedBuffer& wc(trx->write_set_collection()); gu::Buffer buf(wc.size()); std::copy(&wc[0], &wc[0] + wc.size(), &buf[0]); trx->unref(); trx = TrxHandle::New(sp); size_t offset(trx->unserialize(&buf[0], buf.size(), 0)); log_info << "ws[" << i << "]: " << buf.size() - offset; trx->append_write_set(&buf[0] + offset, buf.size() - offset); trx->set_received(0, wsi[i].local_seqno, wsi[i].global_seqno); Certification::TestResult result(cert.append_trx(trx)); fail_unless(result == wsi[i].result, "g: %lld res: %d exp: %d", trx->global_seqno(), result, wsi[i].result); fail_unless(trx->depends_seqno() == wsi[i].expected_depends_seqno, "wsi: %zu g: %lld ld: %lld eld: %lld", i, trx->global_seqno(), trx->depends_seqno(), wsi[i].expected_depends_seqno); cert.set_trx_committed(trx); trx->unref(); } } END_TEST START_TEST(test_trac_726) { log_info << "test_trac_726"; const int version(2); TestEnv env; galera::Certification cert(env.conf(), env.thd()); galera::TrxHandle::Params const trx_params("", version,KeySet::MAX_VERSION); wsrep_uuid_t uuid1 = {{1, }}; wsrep_uuid_t uuid2 = {{2, }}; cert.assign_initial_position(0, version); mark_point(); wsrep_buf_t key1 = {void_cast("1"), 1}; wsrep_buf_t key2 = {void_cast("2"), 1}; { TrxHandle* trx(TrxHandle::New(lp, trx_params, uuid1, 0, 0)); trx->append_key(KeyData(version, &key1, 1, WSREP_KEY_EXCLUSIVE, true)); trx->set_last_seen_seqno(0); trx->flush(0); // serialize/unserialize to verify that ver1 trx is serializable const galera::MappedBuffer& wc(trx->write_set_collection()); gu::Buffer buf(wc.size()); std::copy(&wc[0], &wc[0] + wc.size(), &buf[0]); trx->unref(); trx = TrxHandle::New(sp); size_t offset(trx->unserialize(&buf[0], buf.size(), 0)); trx->append_write_set(&buf[0] + offset, buf.size() - offset); trx->set_received(0, 1, 1); Certification::TestResult result(cert.append_trx(trx)); fail_unless(result == Certification::TEST_OK); cert.set_trx_committed(trx); trx->unref(); } { TrxHandle* trx(TrxHandle::New(lp, trx_params, uuid2, 0, 0)); trx->append_key(KeyData(version, &key2, 1, WSREP_KEY_EXCLUSIVE, true)); trx->append_key(KeyData(version, &key2, 1, WSREP_KEY_SHARED, true)); trx->append_key(KeyData(version, &key1, 1, WSREP_KEY_EXCLUSIVE, true)); trx->set_last_seen_seqno(0); trx->flush(0); // serialize/unserialize to verify that ver1 trx is serializable const galera::MappedBuffer& wc(trx->write_set_collection()); gu::Buffer buf(wc.size()); std::copy(&wc[0], &wc[0] + wc.size(), &buf[0]); trx->unref(); trx = TrxHandle::New(sp); size_t offset(trx->unserialize(&buf[0], buf.size(), 0)); trx->append_write_set(&buf[0] + offset, buf.size() - offset); trx->set_received(0, 2, 2); Certification::TestResult result(cert.append_trx(trx)); fail_unless(result == Certification::TEST_FAILED); cert.set_trx_committed(trx); trx->unref(); } } END_TEST Suite* write_set_suite() { Suite* s = suite_create("write_set"); TCase* tc; tc = tcase_create("test_key1"); tcase_add_test(tc, test_key1); suite_add_tcase(s, tc); tc = tcase_create("test_key2"); tcase_add_test(tc, test_key2); suite_add_tcase(s, tc); tc = tcase_create("test_write_set1"); tcase_add_test(tc, test_write_set1); suite_add_tcase(s, tc); tc = tcase_create("test_write_set2"); tcase_add_test(tc, test_write_set2); suite_add_tcase(s, tc); tc = tcase_create("test_mapped_buffer"); tcase_add_test(tc, test_mapped_buffer); suite_add_tcase(s, tc); tc = tcase_create("test_cert_hierarchical_v1"); tcase_add_test(tc, test_cert_hierarchical_v1); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_cert_hierarchical_v2"); tcase_add_test(tc, test_cert_hierarchical_v2); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_trac_726"); tcase_add_test(tc, test_trac_726); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galera/tests/write_set_ng_check.cpp000066400000000000000000000231731244131713600237370ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #undef NDEBUG #include "test_key.hpp" #include "../src/write_set_ng.hpp" #include "gu_uuid.h" #include "gu_logger.hpp" #include "gu_hexdump.hpp" #include using namespace galera; START_TEST (ver3_basic) { uint16_t const flag1(0xabcd); wsrep_uuid_t source; gu_uuid_generate (reinterpret_cast(&source), NULL, 0); wsrep_conn_id_t const conn(652653); wsrep_trx_id_t const trx(99994952); std::string const dir("."); wsrep_trx_id_t trx_id(1); WriteSetOut wso (dir, trx_id, KeySet::FLAT8A, 0, 0, flag1,WriteSetNG::VER3); fail_unless (wso.is_empty()); // keep SHARED here, see loop below TestKey tk0(KeySet::MAX_VERSION, SHARED, true, "a0"); wso.append_key(tk0()); fail_if (wso.is_empty()); uint64_t const data_out_volatile(0xaabbccdd); uint32_t const data_out_persistent(0xffeeddcc); uint16_t const flag2(0x1234); { uint64_t const d(data_out_volatile); wso.append_data (&d, sizeof(d), true); } wso.append_data (&data_out_persistent, sizeof(data_out_persistent), false); wso.add_flags (flag2); uint16_t const flags(flag1 | flag2); WriteSetNG::GatherVector out; size_t const out_size(wso.gather(source, conn, trx, out)); log_info << "Gather size: " << out_size << ", buf count: " << out->size(); wsrep_seqno_t const last_seen(1); wsrep_seqno_t const seqno(2); int const pa_range(seqno - last_seen); wso.set_last_seen(last_seen); /* concatenate all out buffers */ std::vector in; in.reserve(out_size); for (size_t i(0); i < out->size(); ++i) { const gu::byte_t* ptr(static_cast(out[i].ptr)); in.insert (in.end(), ptr, ptr + out[i].size); } fail_if (in.size() != out_size); gu::Buf const in_buf = { in.data(), static_cast(in.size()) }; /* read ws buffer and "certify" */ { mark_point(); WriteSetIn wsi(in_buf); mark_point(); wsi.verify_checksum(); wsrep_seqno_t const ls(wsi.last_seen()); fail_if (ls != last_seen, "Found last seen: %lld, expected: %lld", ls, last_seen); fail_if (wsi.flags() != flags); fail_if (0 == wsi.timestamp()); fail_if (wsi.annotated()); mark_point(); const KeySetIn& ksi(wsi.keyset()); fail_if (ksi.count() != 1); mark_point(); int shared(0); for (int i(0); i < ksi.count(); ++i) { KeySet::KeyPart kp(ksi.next()); shared += kp.shared(); } fail_unless(shared > 0); wsi.verify_checksum(); wsi.set_seqno (seqno, pa_range); fail_unless(wsi.certified(), "wsi.certified: %d" "\nwsi.pa_range = %lld\n pa_range = %lld", static_cast(wsi.certified()), wsi.pa_range(), pa_range); } /* repeat reading buffer after "certification" */ { WriteSetIn wsi(in_buf); mark_point(); wsi.verify_checksum(); fail_unless(wsi.certified()); fail_if (wsi.seqno() != seqno); fail_if (wsi.flags() != flags); fail_if (0 == wsi.timestamp()); mark_point(); const KeySetIn& ksi(wsi.keyset()); fail_if (ksi.count() != 1); mark_point(); int shared(0); for (int i(0); i < ksi.count(); ++i) { KeySet::KeyPart kp(ksi.next()); shared += kp.shared(); } fail_unless(shared > 0); wsi.verify_checksum(); mark_point(); const DataSetIn& dsi(wsi.dataset()); fail_if (dsi.count() != 1); mark_point(); gu::Buf const d(dsi.next()); fail_if (d.size != sizeof(data_out_volatile) + sizeof(data_out_persistent)); const char* dptr = static_cast(d.ptr); fail_if (*(reinterpret_cast(dptr)) != data_out_volatile); fail_if (*(reinterpret_cast (dptr + sizeof(data_out_volatile))) != data_out_persistent); mark_point(); const DataSetIn& usi(wsi.unrdset()); fail_if (usi.count() != 0); fail_if (usi.size() != 0); } mark_point(); try /* this is to test checksum after set_seqno() */ { WriteSetIn wsi(in_buf); mark_point(); wsi.verify_checksum(); fail_unless(wsi.certified()); fail_if (wsi.pa_range() != pa_range); fail_if (wsi.seqno() != seqno); fail_if (memcmp(&wsi.source_id(), &source, sizeof(source))); fail_if (wsi.conn_id() != conn); fail_if (wsi.trx_id() != trx); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } mark_point(); /* this is to test reassembly without keys and unordered data after gather() * + late initialization */ try { WriteSetIn tmp_wsi(in_buf); WriteSetIn::GatherVector out; mark_point(); tmp_wsi.verify_checksum(); gu_trace(tmp_wsi.gather(out, false, false)); // no keys or unrd /* concatenate all out buffers */ std::vector in; in.reserve(out_size); for (size_t i(0); i < out->size(); ++i) { const gu::byte_t* ptr (static_cast(out[i].ptr)); in.insert (in.end(), ptr, ptr + out[i].size); } mark_point(); gu::Buf tmp_buf = { in.data(), static_cast(in.size()) }; WriteSetIn wsi; // first - create an empty writeset wsi.read_buf(tmp_buf); // next - initialize from buffer wsi.verify_checksum(); fail_unless(wsi.certified()); fail_if (wsi.pa_range() != pa_range); fail_if (wsi.seqno() != seqno); fail_if (wsi.keyset().count() != 0); fail_if (wsi.dataset().count() == 0); fail_if (wsi.unrdset().count() != 0); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } in[in.size() - 1] ^= 1; // corrupted the last byte (payload) mark_point(); try /* this is to test payload corruption */ { WriteSetIn wsi(in_buf); mark_point(); wsi.verify_checksum(); fail("payload corruption slipped through 1"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } try /* this is to test background checksumming + corruption */ { WriteSetIn wsi(in_buf, 2); mark_point(); try { wsi.verify_checksum(); fail("payload corruption slipped through 2"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } catch (std::exception& e) { fail("%s", e.what()); } in[2] ^= 1; // corrupted 3rd byte of header try /* this is to test header corruption */ { WriteSetIn wsi(in_buf, 2 /* this should postpone payload checksum */); wsi.verify_checksum(); fail("header corruption slipped through"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST START_TEST (ver3_annotation) { uint16_t const flag1(0xabcd); wsrep_uuid_t source; gu_uuid_generate (reinterpret_cast(&source), NULL, 0); wsrep_conn_id_t const conn(652653); wsrep_trx_id_t const trx(99994952); std::string const dir("."); wsrep_trx_id_t trx_id(1); WriteSetOut wso (dir, trx_id, KeySet::FLAT16, 0, 0, flag1,WriteSetNG::VER3); fail_unless (wso.is_empty()); TestKey tk0(KeySet::MAX_VERSION, SHARED, true, "key0"); wso.append_key(tk0()); fail_if (wso.is_empty()); uint64_t const data(0xaabbccdd); std::string const annotation("0xaabbccdd"); uint16_t const flag2(0x1234); wso.append_data (&data, sizeof(data), true); wso.append_annotation (annotation.c_str(), annotation.size(), true); wso.add_flags (flag2); uint16_t const flags(flag1 | flag2); WriteSetNG::GatherVector out; size_t const out_size(wso.gather(source, conn, trx, out)); log_info << "Gather size: " << out_size << ", buf count: " << out->size(); wsrep_seqno_t const last_seen(1); wso.set_last_seen(last_seen); /* concatenate all out buffers */ std::vector in; in.reserve(out_size); for (size_t i(0); i < out->size(); ++i) { const gu::byte_t* ptr(static_cast(out[i].ptr)); in.insert (in.end(), ptr, ptr + out[i].size); } fail_if (in.size() != out_size); gu::Buf const in_buf = { in.data(), static_cast(in.size()) }; /* read buffer into WriteSetIn */ mark_point(); WriteSetIn wsi(in_buf); mark_point(); wsi.verify_checksum(); wsrep_seqno_t const ls(wsi.last_seen()); fail_if (ls != last_seen, "Found last seen: %lld, expected: %lld", ls, last_seen); fail_if (wsi.flags() != flags); fail_if (0 == wsi.timestamp()); wsi.verify_checksum(); fail_if (!wsi.annotated()); /* check that annotation has survived */ std::ostringstream os; wsi.write_annotation(os); std::string const res(os.str()); fail_if(annotation.length() != res.length()); fail_if(annotation != res); } END_TEST Suite* write_set_ng_suite () { TCase* t = tcase_create ("WriteSet"); tcase_add_test (t, ver3_basic); tcase_add_test (t, ver3_annotation); tcase_set_timeout(t, 60); Suite* s = suite_create ("WriteSet"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/000077500000000000000000000000001244131713600173165ustar00rootroot00000000000000percona-galera-3-3.8-3390/galerautils/ChangeLog000066400000000000000000000027021244131713600210710ustar00rootroot000000000000002009-09-20 Alex Added RegEx class for matching strings with POSIX regular expressions. Renamed URL class to URI to better reflect what it does. Added get_host(), get_user() and get_port() methods and a unit test. Modularized galerautils++ unit tests. Version 0.3.5 2009-09-17 Alex Added gu_utils.hpp to hold general-purpose templates and functions (now with to_string() template functions). Logger class cleanups. Exception class cleanups. Added stack tracing macro. New Throw class for composing verbose exception messages. Version 0.3.4 2009-09-01 Alex Added a simple option line parser. Some optimizations and cleanups. Version 0.3.3 2009-07-07 Alex Slightly changed gu_fifo interface. Added gu_lock_step object. Version 0.3.2. 2009-06-21 Alex Moved TO monitor module from GCS to galerautils. Version 0.3.1. 2009-06-08 Alex Started galerautils++ project. Added galerautils.hpp and C++-style logger and assert variants. Version 0.3.0. 2008-11-16 Alex Added gu_fifo_t class for mallocless FIFO queue. Version 0.2.9. 2008-03-23 Alex Added gu_timeval_diff() and gu_clock_diff() functions. Bumped interface version. 2008-02-21 Teemu Made DBUG thread safe. 2007-11-01 Alex Fixed thread safe compilation without MySQL Tagged release 0.2.5 2007-10-18 Alex Fixed compilation. Added gtohl/htogl/gtohs/htogs functions. Tagged release 0.2.4 percona-galera-3-3.8-3390/galerautils/README000066400000000000000000000011201244131713600201700ustar00rootroot00000000000000libgalerautils is a library of utilities commonly used by Galera project. Current release includes logging, mutex and malloc debug functions and convenience macros. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. libgalerautils is free software. Please see the file COPYING for details. For documentation, please see the files in the doc subdirectory. For building and installation instructions please see the INSTALL file. percona-galera-3-3.8-3390/galerautils/SConscript000066400000000000000000000001401244131713600213230ustar00rootroot00000000000000# SConscript for building galerautils SConscript(Split('''src/SConscript tests/SConscript''')) percona-galera-3-3.8-3390/galerautils/doc/000077500000000000000000000000001244131713600200635ustar00rootroot00000000000000percona-galera-3-3.8-3390/galerautils/doc/Doxyfile000066400000000000000000001436671244131713600216120ustar00rootroot00000000000000# Doxyfile 1.4.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = GCS # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.2.3 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h *.hpp # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO percona-galera-3-3.8-3390/galerautils/src/000077500000000000000000000000001244131713600201055ustar00rootroot00000000000000percona-galera-3-3.8-3390/galerautils/src/SConscript000066400000000000000000000060611244131713600221220ustar00rootroot00000000000000Import('env', 'x86', 'sysname') libgalerautils_env = env.Clone() # C part libgalerautils_sources = [ 'gu_abort.c', 'gu_dbug.c', 'gu_fifo.c', 'gu_lock_step.c', 'gu_log.c', 'gu_mem.c', 'gu_mmh3.c', 'gu_spooky.c', 'gu_crc32c.c', 'gu_rand.c', 'gu_mutex.c', 'gu_hexdump.c', 'gu_to.c', 'gu_utils.c', 'gu_uuid.c', 'gu_backtrace.c', 'gu_limits.c', 'gu_time.c', 'gu_init.c' ] libgalerautils_objs = libgalerautils_env.SharedObject(libgalerautils_sources) crc32c_sources = [ '#/www.evanjones.ca/crc32c.c' ] crc32c_env = env.Clone() crc32c_env.Append(CPPFLAGS = ' -DWITH_GALERA') crc32c_sources = [ '#/www.evanjones.ca/crc32c.c' ] crc32c_objs = crc32c_env.SharedObject(crc32c_sources) if x86 != 0: crc32c_env.Append(CFLAGS = ' -msse4.2') if sysname == 'sunos': # Ideally we want to simply strip SSE4.2 flag from the resulting # crc32.pic.o # (see http://ffmpeg.org/pipermail/ffmpeg-user/2013-March/013977.html) # but that requires some serious scons-fu, so we just don't # compile hardware support in if host CPU does not have it. from subprocess import check_call try: check_call("isainfo -v | grep sse4.2 >/dev/null 2>&1", shell=True); except: libgalerautils_env.Append(CPPFLAGS = ' -DCRC32C_NO_HARDWARE') crc32c_env.Append(CPPFLAGS = ' -DCRC32C_NO_HARDWARE') libgalerautils_env.StaticLibrary('galerautils', libgalerautils_objs + crc32c_objs) env.Append(LIBGALERA_OBJS = libgalerautils_objs + crc32c_objs) #env.Append(LIBGALERA_OBJS = libgalerautils_env.SharedObject( # libgalerautils_sources)) #env.Append(LIBGALERA_OBJS = crc32c_objs) libgalerautilsxx_env = env.Clone() # disable old style cast warnings libgalerautilsxx_env.Append(CXXFLAGS = ' -Wno-old-style-cast') # C++ part libgalerautilsxx_sources = [ 'gu_vlq.cpp', 'gu_datetime.cpp', 'gu_exception.cpp', 'gu_logger.cpp', 'gu_prodcons.cpp', 'gu_regex.cpp', 'gu_string_utils.cpp', 'gu_uri.cpp', 'gu_buffer.cpp', 'gu_utils++.cpp', 'gu_config.cpp', 'gu_fdesc.cpp', 'gu_mmap.cpp', 'gu_alloc.cpp', 'gu_rset.cpp', 'gu_resolver.cpp', 'gu_histogram.cpp', 'gu_stats.cpp' ] #libgalerautilsxx_objs = libgalerautilsxx_env.Object( # libgalerautilsxx_sources) libgalerautilsxx_sobjs = libgalerautilsxx_env.SharedObject( libgalerautilsxx_sources) #hexdump_obj = libgalerautilsxx_env.Object('gu_hexdump++','gu_hexdump.cpp') hexdump_sobj = libgalerautilsxx_env.SharedObject('gu_hexdump++','gu_hexdump.cpp') #libgalerautilsxx_objs += hexdump_obj libgalerautilsxx_sobjs += hexdump_sobj #if '-DGALERA_USE_GU_NETWORK' in libgalerautils_env['CPPFLAGS']: # libgalerautilsxx_sources = [libgalerautilsxx_sources, # 'gu_resolver.cpp'] libgalerautilsxx_env.StaticLibrary('galerautils++', libgalerautilsxx_sobjs) env.Append(LIBGALERA_OBJS = libgalerautilsxx_sobjs) percona-galera-3-3.8-3390/galerautils/src/avalanche.c000066400000000000000000000051011244131713600221700ustar00rootroot00000000000000/* * Copyright (c) 2012 Codership Oy * * This program is to measure avalanche effect of different hash * implementations, for that it uses 1M of random 8-byte keys. * Use #define macro below to define the implementation to test. * * Compilation: g++ -DHAVE_ENDIAN_H -DHAVE_BYTESWAP_H -O3 -Wall -Wno-unused avalanche.c \ gu_mmh3.c gu_spooky.c -o avalanche && time ./avalanche * Visualization in gnuplot: unset cbtics set xrange [-0.5:64.5] set yrange [-0.5:64.5] set cbrange [0.0:1.0] set xlabel 'Hash bit' set ylabel 'Flipped bit in message' set cblabel 'Hash bit flip probability [0.0 - 1.0]' set palette rgbformula 7,7,7 plot 'avalanche.out' matrix with image */ #include "gu_hash.h" #include #include #include uint64_t flip_count[64*64] = { 0, }; //#define HASH gu_mmh128_64 #define HASH gu_fast_hash64 int main (int argc, char* argv[]) { int n_keys = 1 << 20; int i, j, k; /* collect statistics */ for (k = 0; k < n_keys; k++) { uint64_t key_part = rand(); uint64_t const key = (key_part << 32) + rand(); uint64_t const hash = HASH (&key, sizeof(key)); for (j = 0; j < 64; j++) { uint64_t const flipped_key = key ^ (GU_LONG_LONG(0x01) << j); uint64_t const flipped_hash = HASH (&flipped_key, sizeof(flipped_key)); uint64_t flipped_bits = hash ^ flipped_hash; for (i = 0; i < 64; i++) { int const idx = j * 64 + i; flip_count[idx] += flipped_bits & GU_LONG_LONG(0x01); flipped_bits >>= 1; } } } /* print statistics */ char out_name [256] = { 0, }; snprintf(out_name, sizeof(out_name) - 1, "%s.out", argv[0]); FILE* const out = fopen(out_name, "w"); if (!out) { fprintf (stderr, "Could not open file for writing: '%s': %d (%s)", out_name, errno, strerror(errno)); return errno; } uint64_t base = n_keys; double min_stat = 1.0; double max_stat = 0.0; for (j = 0; j < 64; j++) { for (i = 0; i < 64; i++) { int const idx = j * 64 + i; double stat = (((double)(flip_count[idx]))/base); min_stat = min_stat > stat ? stat : min_stat; max_stat = max_stat < stat ? stat : max_stat; fprintf (out, "%6.4f%c", stat, 63 == i ? '\n' : '\t'); } } fclose(out); printf ("%6.4f : %6.4f (delta: %6.4f)\n", min_stat, max_stat, max_stat - min_stat); return 0; } percona-galera-3-3.8-3390/galerautils/src/galerautils.h000066400000000000000000000013221244131713600225700ustar00rootroot00000000000000// Copyright (C) 2007-2009 Codership Oy /** * @file GaleraUtils main header file * * $Id$ */ #ifndef _galerautils_h_ #define _galerautils_h_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include "gu_macros.h" #include "gu_limits.h" #include "gu_byteswap.h" #include "gu_time.h" #include "gu_log.h" #include "gu_conf.h" #include "gu_assert.h" #include "gu_mem.h" #include "gu_mutex.h" #include "gu_dbug.h" #include "gu_fifo.h" #include "gu_uuid.h" #include "gu_to.h" #include "gu_lock_step.h" #include "gu_utils.h" #include "gu_config.h" #include "gu_abort.h" #include "gu_errno.h" #include "gu_atomic.h" #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _galerautils_h_ */ percona-galera-3-3.8-3390/galerautils/src/galerautils.hpp000066400000000000000000000014441244131713600231350ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /*! * @file GaleraUtils main header file * * $Id$ */ #ifndef _galerautils_hpp_ #define _galerautils_hpp_ #include "gu_exception.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_assert.hpp" #include "gu_mutex.hpp" #include "gu_cond.hpp" #include "gu_lock.hpp" #include "gu_monitor.hpp" #include "gu_macros.hpp" #include "gu_utils.hpp" #include "gu_convert.hpp" //#include "gu_string.hpp" #include "gu_config.hpp" #include "gu_prodcons.hpp" extern "C" { #include "gu_macros.h" #include "gu_limits.h" #include "gu_byteswap.h" #include "gu_time.h" #include "gu_conf.h" #include "gu_mem.h" #include "gu_dbug.h" #include "gu_fifo.h" #include "gu_uuid.h" //#include "gu_utils.h" // gu_abort() } #endif /* _galerautils_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_abort.c000066400000000000000000000012561244131713600220570ustar00rootroot00000000000000// Copyright (C) 2011-2013 Codership Oy /** * @file Clean abort function * * $Id$ */ #include "gu_abort.h" #include "gu_system.h" #include "gu_log.h" #include /* for setrlimit() */ #include /* for signal() */ #include /* for abort() */ void gu_abort (void) { /* avoid coredump */ struct rlimit core_limits = { 0, 0 }; setrlimit (RLIMIT_CORE, &core_limits); /* restore default SIGABRT handler */ signal (SIGABRT, SIG_DFL); #if defined(GU_SYS_PROGRAM_NAME) gu_info ("%s: Terminated.", GU_SYS_PROGRAM_NAME); #else gu_info ("Program terminated."); #endif abort(); } percona-galera-3-3.8-3390/galerautils/src/gu_abort.h000066400000000000000000000006501244131713600220610ustar00rootroot00000000000000// Copyright (C) 2012-2013 Codership Oy /** * @file "Clean" abort function to avoid stack and core dumps * * $Id$ */ #ifndef _gu_abort_h_ #define _gu_abort_h_ #ifdef __cplusplus extern "C" { #endif #include "gu_macros.h" /* This function is for clean aborts, when we can't gracefully exit otherwise */ extern void gu_abort() GU_NORETURN; #ifdef __cplusplus } #endif #endif /* _gu_abort_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_alloc.cpp000066400000000000000000000110671244131713600224030ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /*! * @file allocator main functions * * $Id$ */ #include "gu_alloc.hpp" #include "gu_throw.hpp" #include "gu_assert.hpp" #include #include // for std::setfill() and std::setw() gu::Allocator::HeapPage::HeapPage (page_size_type const size) : Page (reinterpret_cast(::malloc(size)), size) { if (0 == base_ptr_) gu_throw_error (ENOMEM); } gu::Allocator::Page* gu::Allocator::HeapStore::my_new_page (page_size_type const size) { if (gu_likely(size <= left_)) { page_size_type const page_size( std::min(std::max(size, page_size_type(PAGE_SIZE)), left_)); /* ^^^^^^ this is to make GCC with -O0 flag * to understand that PAGE_SIZE participates in a constant expression: * otherwise it will complain about undefined reference to PAGE_SIZE.*/ Page* ret = new HeapPage (page_size); assert (ret != 0); left_ -= page_size; return ret; } gu_throw_error (ENOMEM) << "out of memory in RAM pool"; } gu::Allocator::FilePage::FilePage (const std::string& name, page_size_type const size) : Page (0, 0), fd_ (name, size, false, false), mmap_(fd_, true) { base_ptr_ = reinterpret_cast(mmap_.ptr); ptr_ = base_ptr_; left_ = mmap_.size; } gu::Allocator::Page* gu::Allocator::FileStore::my_new_page (page_size_type const size) { Page* ret = 0; try { std::ostringstream fname; fname << base_name_ << '.' << std::dec << std::setfill('0') << std::setw(6) << n_; ret = new FilePage(fname.str(), std::max(size, page_size_)); assert (ret != 0); ++n_; } catch (std::exception& e) { gu_throw_error(ENOMEM) << e.what(); } return ret; } #ifdef GU_ALLOCATOR_DEBUG void gu::Allocator::add_current_to_bufs() { page_size_type const current_size (current_page_->size()); if (current_size) { if (bufs_->empty() || bufs_->back().ptr != current_page_->base()) { Buf b = { current_page_->base(), current_size }; bufs_->push_back (b); } else { bufs_->back().size = current_size; } } } size_t gu::Allocator::gather (std::vector& out) const { if (bufs_().size()) out.insert (out.end(), bufs_().begin(), bufs_().end()); Buf b = { current_page_->base(), current_page_->size() }; out.push_back (b); return size_; } #endif /* GU_ALLOCATOR_DEBUG */ gu::byte_t* gu::Allocator::alloc (page_size_type const size, bool& new_page) { new_page = false; if (gu_unlikely(0 == size)) return 0; byte_t* ret = current_page_->alloc (size); if (gu_unlikely(0 == ret)) { Page* np = 0; try { np = current_store_->new_page(size); } catch (Exception& e) { if (current_store_ != &heap_store_) throw; /* no fallbacks left */ /* fallback to disk store */ current_store_ = &file_store_; np = current_store_->new_page(size); } assert (np != 0); // it should have thrown above pages_().push_back (np); #ifdef GU_ALLOCATOR_DEBUG add_current_to_bufs(); #endif /* GU_ALLOCATOR_DEBUG */ current_page_ = np; new_page = true; ret = np->alloc (size); assert (ret != 0); // the page should be sufficiently big } size_ += size; return ret; } gu::Allocator::BaseNameDefault const gu::Allocator::BASE_NAME_DEFAULT; gu::Allocator::Allocator (const BaseName& base_name, byte_t* reserved, page_size_type reserved_size, heap_size_type max_ram, page_size_type disk_page_size) : first_page_ (reserved, reserved_size), current_page_ (&first_page_), heap_store_ (max_ram), file_store_ (base_name, disk_page_size), current_store_(&heap_store_), pages_ (), #ifdef GU_ALLOCATOR_DEBUG bufs_ (), #endif /* GU_ALLOCATOR_DEBUG */ size_ (0) { assert (NULL != reserved || 0 == reserved_size); assert (current_page_ != 0); pages_->push_back (current_page_); } gu::Allocator::~Allocator () { for (int i(pages_->size() - 1); i > 0 /* don't delete first_page_ - we didn't allocate it */; --i) { delete (pages_[i]); } } percona-galera-3-3.8-3390/galerautils/src/gu_alloc.hpp000066400000000000000000000125731244131713600224130ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /*! * @file Continuous buffer allocator for RecordSet * * $Id$ */ #ifndef _GU_ALLOC_HPP_ #define _GU_ALLOC_HPP_ #include "gu_string.hpp" #include "gu_fdesc.hpp" #include "gu_mmap.hpp" #include "gu_buf.hpp" #include "gu_vector.hpp" #include "gu_macros.h" // gu_likely() #include "gu_limits.h" // GU_PAGE_SIZE #include // realloc(), free() #include #include namespace gu { class Allocator { public: class BaseName { public: virtual void print(std::ostream& os) const = 0; virtual ~BaseName() {} }; // this questionable optimization reduces Allocator size by 8 // probably not worth the loss of generality. typedef unsigned int page_size_type; // max page size typedef page_size_type heap_size_type; // max heap store size explicit Allocator (const BaseName& base_name = BASE_NAME_DEFAULT, byte_t* reserved = NULL, page_size_type reserved_size = 0, heap_size_type max_heap = (1U << 22), /* 4M */ page_size_type disk_page_size = (1U << 26)); /* 64M */ ~Allocator (); /*! @param new_page - true if not adjucent to previous allocation */ byte_t* alloc (page_size_type const size, bool& new_page); /* Total allocated size */ size_t size () const { return size_; } /* Total count of pages */ size_t count() const { return pages_->size(); } #ifdef GU_ALLOCATOR_DEBUG /* appends own vector of Buf structures to the passed one, * should be called only after all allocations have been made. * returns sum of all appended buffers' sizes (same as size()) */ size_t gather (std::vector& out) const; #endif /* GU_ALLOCATOR_DEBUG */ /* After we allocated 3 heap pages, spilling vector into heap should not * be an issue. */ static size_t const INITIAL_VECTOR_SIZE = 4; private: class Page /* base class for memory and file pages */ { public: Page (byte_t* ptr, size_t size) : base_ptr_(ptr), ptr_ (base_ptr_), left_ (size) {} virtual ~Page() {}; byte_t* alloc (size_t size) { byte_t* ret = NULL; if (gu_likely(size <= left_)) { ret = ptr_; ptr_ += size; left_ -= size; } return ret; } const byte_t* base() const { return base_ptr_; } ssize_t size() const { return ptr_ - base_ptr_; } protected: byte_t* base_ptr_; byte_t* ptr_; page_size_type left_; Page& operator=(const Page&); Page (const Page&); }; class HeapPage : public Page { public: HeapPage (page_size_type max_size); ~HeapPage () { free (base_ptr_); } }; class FilePage : public Page { public: FilePage (const std::string& name, page_size_type size); ~FilePage () { fd_.unlink(); } private: FileDescriptor fd_; MMap mmap_; }; class PageStore { public: Page* new_page (page_size_type size) { return my_new_page(size); } protected: virtual ~PageStore() {} private: virtual Page* my_new_page (page_size_type size) = 0; }; class HeapStore : public PageStore { public: HeapStore (heap_size_type max) : PageStore(), left_(max) {} ~HeapStore () {} private: /* to avoid too frequent allocation, make it 64K */ static page_size_type const PAGE_SIZE = GU_PAGE_SIZE * 16; heap_size_type left_; Page* my_new_page (page_size_type const size); }; class FileStore : public PageStore { public: FileStore (const BaseName& base_name, page_size_type page_size) : PageStore(), base_name_(base_name), page_size_(page_size), n_ (0) {} ~FileStore() {} const BaseName& base_name() const { return base_name_; } int size() const { return n_; } private: const BaseName& base_name_; page_size_type const page_size_; int n_; Page* my_new_page (page_size_type const size); FileStore (const FileStore&); FileStore& operator= (const FileStore&); }; Page first_page_; Page* current_page_; HeapStore heap_store_; FileStore file_store_; PageStore* current_store_; gu::Vector pages_; #ifdef GU_ALLOCATOR_DEBUG gu::Vector bufs_; void add_current_to_bufs(); #endif /* GU_ALLOCATOR_DEBUG */ size_t size_; Allocator(const gu::Allocator&); const Allocator& operator=(const gu::Allocator&); class BaseNameDefault : public BaseName { public: BaseNameDefault() {} // this is seemingly required by the standard void print(std::ostream& os) const { os << "alloc"; } }; static BaseNameDefault const BASE_NAME_DEFAULT; }; /* class Allocator */ inline std::ostream& operator<< (std::ostream& os, const Allocator::BaseName& bn) { bn.print(os); return os; } } /* namespace gu */ #endif /* _GU_ALLOC_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_arch.h000066400000000000000000000026051244131713600216710ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file CPU architecture related functions/macros * * $Id$ */ #ifndef _gu_arch_h_ #define _gu_arch_h_ #if defined(HAVE_ENDIAN_H) # include #elif defined(HAVE_SYS_ENDIAN_H) /* FreeBSD */ # include #elif defined(HAVE_SYS_BYTEORDER_H) # include #elif defined(__APPLE__) # include #else # error "No byte order header file detected" #endif #if defined(__BYTE_ORDER) # if __BYTE_ORDER == __LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(_BYTE_ORDER) /* FreeBSD */ # if _BYTE_ORDER == _LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(__APPLE__) && defined(__DARWIN_BYTE_ORDER) # if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN # define GU_LITTLE_ENDIAN # endif #elif defined(__sun__) # if !defined(_BIG_ENDIAN) # define GU_LITTLE_ENDIAN # endif #else # error "Byte order not defined" #endif #if defined(__sun__) # define GU_WORDSIZE 64 /* Solaris 11 is only 64-bit ATM */ #elif defined(__APPLE__) || defined(__FreeBSD__) # include # define GU_WORDSIZE __WORDSIZE #else # include # define GU_WORDSIZE __WORDSIZE #endif #if (GU_WORDSIZE != 32) && (GU_WORDSIZE != 64) # error "Unsupported wordsize" #endif /* I'm not aware of the platforms that don't, but still */ #define GU_ALLOW_UNALIGNED_READS 1 #endif /* _gu_arch_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_assert.h000066400000000000000000000010421244131713600222470ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * @file Assert macro definition * * $Id$ */ #ifndef _gu_assert_h_ #define _gu_assert_h_ #include "gu_log.h" #ifndef DEBUG_ASSERT #include #else #include #undef assert /** Assert that sleeps instead of aborting the program, saving it for gdb */ #define assert(expr) if (!(expr)) { \ gu_fatal ("Assertion (%s) failed", __STRING(expr)); \ while(1) sleep(1); } #endif /* DEBUG_ASSERT */ #endif /* _gu_assert_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_assert.hpp000066400000000000000000000012761244131713600226200ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /** * @file Assert macro definition * * $Id$ */ #ifndef _gu_assert_hpp_ #define _gu_assert_hpp_ #ifndef DEBUG_ASSERT #include #else #include #undef assert #include "gu_logger.hpp" /** Assert that sleeps instead of aborting the program, saving it for gdb */ #define assert(expr) \ if (!(expr)) { \ log_fatal << "Assertion (" << __STRING(expr) << ") failed"; \ while(1) sleep(1); \ } #endif /* DEBUG_ASSERT */ #endif /* _gu_assert_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_atomic.h000066400000000000000000000066011244131713600222300ustar00rootroot00000000000000// Copyright (C) 2013-2014 Codership Oy /** * @file Atomic memory access functions. At the moment these follow * __atomic_XXX convention from GCC. */ #ifndef GU_ATOMIC_H #define GU_ATOMIC_H #ifdef __cplusplus extern "C" { #endif // So far in tests full memory sync shows the most consistent performance - // and it's the safest. @todo: reassess this later. #define GU_ATOMIC_SYNC_DEFAULT GU_ATOMIC_SYNC_FULL #ifdef __GNUC__ #if defined(__ATOMIC_RELAXED) // use __atomic_XXX builtins #define GU_ATOMIC_SYNC_NONE __ATOMIC_RELAXED #define GU_ATOMIC_SYNC_DEPEND __ATOMIC_ACQ_REL #define GU_ATOMIC_SYNC_FULL __ATOMIC_SEQ_CST #define gu_atomic_fetch_and_add(ptr, val) \ __atomic_fetch_add(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_sub(ptr, val) \ __atomic_fetch_sub(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_or(ptr, val) \ __atomic_fetch_or(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_and(ptr, val) \ __atomic_fetch_and(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_xor(ptr, val) \ __atomic_fetch_xor(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_fetch_and_nand(ptr, val) \ __atomic_fetch_nand(ptr, val,GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_add_and_fetch(ptr, val) \ __atomic_add_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_sub_and_fetch(ptr, val) \ __atomic_sub_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_or_and_fetch(ptr, val) \ __atomic_or_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_and_and_fetch(ptr, val) \ __atomic_and_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_xor_and_fetch(ptr, val) \ __atomic_xor_fetch(ptr, val, GU_ATOMIC_SYNC_DEFAULT) #define gu_atomic_nand_and_fetch(ptr, val) \ __atomic_nand_fetch(ptr, val,GU_ATOMIC_SYNC_DEFAULT) // stores contents of vptr into ptr #define gu_atomic_set(ptr, vptr) \ __atomic_store(ptr, vptr, GU_ATOMIC_SYNC_DEFAULT) // loads contents of ptr to vptr #define gu_atomic_get(ptr, vptr) \ __atomic_load(ptr, vptr, GU_ATOMIC_SYNC_DEFAULT) #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) // use __sync_XXX builtins #define GU_ATOMIC_SYNC_NONE 0 #define GU_ATOMIC_SYNC_DEPEND 0 #define GU_ATOMIC_SYNC_FULL 0 #define gu_atomic_fetch_and_add __sync_fetch_and_add #define gu_atomic_fetch_and_sub __sync_fetch_and_sub #define gu_atomic_fetch_and_or __sync_fetch_and_or #define gu_atomic_fetch_and_and __sync_fetch_and_and #define gu_atomic_fetch_and_xor __sync_fetch_and_xor #define gu_atomic_fetch_and_nand __sync_fetch_and_nand #define gu_atomic_add_and_fetch __sync_add_and_fetch #define gu_atomic_sub_and_fetch __sync_sub_and_fetch #define gu_atomic_or_and_fetch __sync_or_and_fetch #define gu_atomic_and_and_fetch __sync_and_and_fetch #define gu_atomic_xor_and_fetch __sync_xor_and_fetch #define gu_atomic_nand_and_fetch __sync_nand_and_fetch #define gu_atomic_set(ptr, vptr) \ while (!__sync_bool_compare_and_swap(ptr, *ptr, *vptr)); #define gu_atomic_get(ptr, vptr) *vptr = __sync_fetch_and_or(ptr, 0) #else #error "This GCC version does not support 8-byte atomics on this platform. Use GCC >= 4.7.x." #endif /* __ATOMIC_RELAXED */ #else /* __GNUC__ */ #error "Compiler not supported" #endif #ifdef __cplusplus } #endif #endif /* !GU_ATOMIC_H */ percona-galera-3-3.8-3390/galerautils/src/gu_atomic.hpp000066400000000000000000000033111244131713600225630ustar00rootroot00000000000000// // Copyright (C) 2010-2014 Codership Oy // // // @todo Check that the at least the following gcc versions are supported // gcc version 4.1.2 20080704 (Red Hat 4.1.2-48) // #ifndef GU_ATOMIC_HPP #define GU_ATOMIC_HPP #include "gu_atomic.h" #include namespace gu { template class Atomic { public: Atomic(I i = 0) : i_(i) { } I operator()() const { I i; gu_atomic_get(&i_, &i); return i; } Atomic& operator=(I i) { gu_atomic_set(&i_, &i); return *this; } I fetch_and_zero() { return gu_atomic_fetch_and_and(&i_, 0); } I fetch_and_add(I i) { return gu_atomic_fetch_and_add(&i_, i); } I add_and_fetch(I i) { return gu_atomic_add_and_fetch(&i_, i); } I sub_and_fetch(I i) { return gu_atomic_sub_and_fetch(&i_, i); } Atomic& operator++() { gu_atomic_fetch_and_add(&i_, 1); return *this; } Atomic& operator--() { gu_atomic_fetch_and_sub(&i_, 1); return *this; } Atomic& operator+=(I i) { gu_atomic_fetch_and_add(&i_, i); return *this; } bool operator!=(I i) { return (operator()() != i); } private: #if !defined(__ATOMIC_RELAXED) // implementation of gu_atomic_get() via __sync_fetch_and_or() // is not read-only for GCC mutable #endif I i_; }; } #endif // ::GU_ATOMIC_HPP percona-galera-3-3.8-3390/galerautils/src/gu_backtrace.c000066400000000000000000000011071244131713600226620ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy #include "gu_backtrace.h" #include "gu_log.h" #ifdef __GNUC__ #include #include char** gu_backtrace(int* size) { char** strings; void** array = malloc(*size * sizeof(void*)); if (!array) { gu_error("could not allocate memory for %d pointers\n", *size); return NULL; } *size = backtrace(array, *size); strings = backtrace_symbols(array, *size); free(array); return strings; } #else char **gu_backtrace(int* size) { return NULL; } #endif /* */ percona-galera-3-3.8-3390/galerautils/src/gu_backtrace.h000066400000000000000000000014111244131713600226650ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy #ifndef GU_BACKTRACE_H #define GU_BACKTRACE_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /*! * Get current backtrace. Return buffer will contain backtrace symbols if * available. NULL pointer is returned if getting backtrace is not supported * on current platform. Maximum number of frames in backtrace is passed * in size parameter, number of frames in returned backtrace is assigned * in size parameter on return. * * @param size Pointer to integer containing maximum number of frames * in backtrace * * @return Allocated array of strings containing backtrace symbols */ char** gu_backtrace(int* size); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* GU_BACKTRACE_H */ percona-galera-3-3.8-3390/galerautils/src/gu_backtrace.hpp000066400000000000000000000025651244131713600232400ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy #ifndef GU_BACKTRACE_HPP #define GU_BACKTRACE_HPP #include "gu_backtrace.h" #include #include namespace gu { /*! * Utility class to print backtraces. */ class Backtrace { public: /*! * Construct backtrace object. * * @param Maximum number of backtrace symbols resolved (default 50). */ Backtrace(int size = 50) : symbols_size_(size), symbols_(gu_backtrace(&symbols_size_)) { } ~Backtrace() { free(symbols_); } /*! * Print backtrace into ostream. * * @param os Ostream to print backtrace into. * @param delim Delimiter separating backtrace symbols. */ void print(std::ostream& os, char delim = '\n') { if (symbols_ != 0) { for (int i(0); i < symbols_size_; ++i) { os << symbols_[i] << delim; } } else { os << "no backtrace available"; } } private: Backtrace(const Backtrace&); void operator=(const Backtrace&); int symbols_size_; char** symbols_; }; } #endif // GU_BACKTRACE_HPP percona-galera-3-3.8-3390/galerautils/src/gu_buf.h000066400000000000000000000005151244131713600215260ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /** * @file generic buffer declaration * * $Id$ */ #ifndef _gu_buf_h_ #define _gu_buf_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif struct gu_buf { const void* ptr; ssize_t size; }; #ifdef __cplusplus } #endif #endif /* _gu_buf_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_buf.hpp000066400000000000000000000003761244131713600220730ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /** * @file generic buffer declaration * * $Id$ */ #ifndef _GU_BUF_HPP_ #define _GU_BUF_HPP_ #include "gu_buf.h" namespace gu { typedef struct gu_buf Buf; } #endif /* _GU_BUF_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_buffer.cpp000066400000000000000000000001311244131713600225500ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // #include "gu_buffer.hpp" percona-galera-3-3.8-3390/galerautils/src/gu_buffer.hpp000066400000000000000000000006241244131713600225640ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ /*! * Byte buffer class. This is thin wrapper to std::vector */ #ifndef GU_BUFFER_HPP #define GU_BUFFER_HPP #include "gu_types.hpp" // for gu::byte_t #include #include namespace gu { typedef std::vector Buffer; typedef boost::shared_ptr SharedBuffer; } #endif // GU_BUFFER_HPP percona-galera-3-3.8-3390/galerautils/src/gu_byteswap.h000066400000000000000000000065561244131713600226230ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file Byte swapping functions/macros * * $Id$ */ #ifndef _gu_byteswap_h_ #define _gu_byteswap_h_ #include "gu_arch.h" #include "gu_types.h" #include "gu_macros.h" /* * Platform-dependent macros */ #if defined(_MSC_VER) #include #define GU_ROTL32(x,y) _rotl(x,y) #define GU_ROTL64(x,y) _rotl64(x,y) #else /* !defined(_MSC_VER) */ static GU_FORCE_INLINE uint32_t GU_ROTL32 (uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } static GU_FORCE_INLINE uint64_t GU_ROTL64 (uint64_t x, int8_t r) { return (x << r) | (x >> (64 - r)); } #endif /* !defined(_MSC_VER) */ /* * End of paltform-dependent macros */ #if defined(HAVE_BYTESWAP_H) # include // for bswap_16(x), bswap_32(x), bswap_64(x) #elif defined(__APPLE__) # include // for OSSwapInt16(x), etc. #endif /* HAVE_BYTESWAP_H */ #if defined(__APPLE__) /* do not use OSSwapIntXX, because gcc44 gives old-style cast warnings */ # define gu_bswap16 _OSSwapInt16 # define gu_bswap32 _OSSwapInt32 # define gu_bswap64 _OSSwapInt64 #elif defined(__FreeBSD__) /* do not use bswapXX, because gcc44 gives old-style cast warnings */ # define gu_bswap16 __bswap16_var # define gu_bswap32 __bswap32_var # define gu_bswap64 __bswap64_var #elif defined(__sun__) # define gu_bswap16 BSWAP_16 # define gu_bswap32 BSWAP_32 # define gu_bswap64 BSWAP_64 #elif defined(bswap16) # define gu_bswap16 bswap16 # define gu_bswap32 bswap32 # define gu_bswap64 bswap64 #elif defined(bswap_16) # define gu_bswap16 bswap_16 # define gu_bswap32 bswap_32 # define gu_bswap64 bswap_64 #else # error "No byteswap macros are defined" #endif /* @note: there are inline functions behind these macros below, * so typesafety is taken care of... However C++ still has issues: */ #ifdef __cplusplus // To pacify C++. Not loosing much optimization on 2 bytes anyways. #include #undef gu_bswap16 static GU_FORCE_INLINE uint16_t gu_bswap16(uint16_t const x) // Even though x is declared as 'uint16_t', g++-4.4.1 still treats results // of operations with it as 'int' and freaks out on return with -Wconversion. { return static_cast((x >> 8) | (x << 8)); } #endif // __cplusplus #if defined(GU_LITTLE_ENDIAN) /* convert to/from Little Endian representation */ #define gu_le16(x) (x) #define gu_le32(x) (x) #define gu_le64(x) (x) /* convert to/from Big Endian representation */ #define gu_be16(x) gu_bswap16(x) #define gu_be32(x) gu_bswap32(x) #define gu_be64(x) gu_bswap64(x) #else /* Big-Endian */ /* convert to/from Little Endian representation */ #define gu_le16(x) gu_bswap16(x) #define gu_le32(x) gu_bswap32(x) #define gu_le64(x) gu_bswap64(x) /* convert to/from Big Endian representation */ #define gu_be16(x) (x) #define gu_be32(x) (x) #define gu_be64(x) (x) #endif /* Big-Endian */ /* Analogues to htonl and friends. Since we'll be dealing mostly with * little-endian architectures, there is more sense to use little-endian * as default */ #define htogs(x) gu_le16(x) #define gtohs(x) htogs(x) #define htogl(x) gu_le32(x) #define gtohl(x) htogl(x) /* Analogues to htogs() and friends, suffixed with type width */ #define htog16(x) gu_le16(x) #define gtoh16(x) htog16(x) #define htog32(x) gu_le32(x) #define gtoh32(x) htog32(x) #define htog64(x) gu_le64(x) #define gtoh64(x) htog64(x) #endif /* _gu_byteswap_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_byteswap.hpp000066400000000000000000000024601244131713600231510ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file Endian conversion templates for serialization * * $Id$ */ #ifndef _gu_byteswap_hpp_ #define _gu_byteswap_hpp_ #include "gu_byteswap.h" #include namespace gu { /* General template: undefined */ template T gtoh (const T& val) { // to generate error on compilation rather then linking return val.this_template_does_not_support_this_type(); } /* Specialized templates */ template <> GU_FORCE_INLINE uint8_t gtoh (const uint8_t& val) { return val; } template <> GU_FORCE_INLINE uint16_t gtoh (const uint16_t& val) { return gtoh16(val); } template <> GU_FORCE_INLINE unsigned int gtoh (const unsigned int& val) { return gtoh32(val); } #if __LONG_MAX__ == __INT_MAX__ template <> GU_FORCE_INLINE unsigned long gtoh (const unsigned long& val) { return gtoh32(val); } #elif __LONG_MAX__ == __LONG_LONG_MAX__ template <> GU_FORCE_INLINE unsigned long gtoh (const unsigned long& val) { return gtoh64(val); } #else # error can not determine size of long #endif template <> GU_FORCE_INLINE unsigned long long gtoh (const unsigned long long& val) { return gtoh64(val); } template T htog (const T& val) { return gtoh(val); } } /* namespace gu */ #endif /* _gu_byteswap_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_cond.hpp000066400000000000000000000031061244131713600222340ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef __GU_COND__ #define __GU_COND__ #include #include #include #include "gu_macros.h" #include "gu_exception.hpp" // TODO: make exceptions more verbose namespace gu { class Cond { friend class Lock; // non-copyable Cond(const Cond&); void operator=(const Cond&); protected: pthread_cond_t mutable cond; long mutable ref_count; public: Cond () : cond(), ref_count(0) { pthread_cond_init (&cond, NULL); } ~Cond () { int ret; while (EBUSY == (ret = pthread_cond_destroy(&cond))) { usleep (100); } if (gu_unlikely(ret != 0)) { log_fatal << "pthread_cond_destroy() failed: " << ret << " (" << strerror(ret) << ". Aborting."; ::abort(); } } inline void signal () const { if (ref_count > 0) { int ret = pthread_cond_signal (&cond); if (gu_unlikely(ret != 0)) throw Exception("pthread_cond_signal() failed", ret); } } inline void broadcast () const { if (ref_count > 0) { int ret = pthread_cond_broadcast (&cond); if (gu_unlikely(ret != 0)) throw Exception("pthread_cond_broadcast() failed", ret); } } }; } #endif // __GU_COND__ percona-galera-3-3.8-3390/galerautils/src/gu_conf.h000066400000000000000000000010201244131713600216670ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * @file * Configuration interface for libgalerautils * * $Id$ */ #ifndef _gu_conf_h_ #define _gu_conf_h_ /* Logging options */ #include #include "gu_log.h" extern int gu_conf_set_log_file (FILE* file); extern int gu_conf_set_log_callback (gu_log_cb_t callback); extern int gu_conf_self_tstamp_on (); extern int gu_conf_self_tstamp_off (); extern int gu_conf_debug_on (); extern int gu_conf_debug_off (); #endif // _gu_conf_h_ percona-galera-3-3.8-3390/galerautils/src/gu_config.cpp000066400000000000000000000266351244131713600225650ustar00rootroot00000000000000// Copyright (C) 2010-2014 Codership Oy /** * @file * Configuration management implementation * * $Id$ */ #include "gu_config.h" #include "gu_config.hpp" #include "gu_logger.hpp" #include "gu_assert.hpp" const char gu::Config::PARAM_SEP = ';'; // parameter separator const char gu::Config::KEY_VALUE_SEP = '='; // key-value separator const char gu::Config::ESCAPE = '\\'; // escape symbol void gu::Config::parse ( std::vector >& params_vector, const std::string& param_list) { assert(params_vector.empty()); // we probably want a clean list if (param_list.empty()) return; std::vector pv = gu::tokenize (param_list, PARAM_SEP, ESCAPE); for (size_t i = 0; i < pv.size(); ++i) { std::vector kvv = gu::tokenize (pv[i], KEY_VALUE_SEP, ESCAPE, true); assert(kvv.size() > 0); gu::trim(kvv[0]); const std::string& key = kvv[0]; if (!key.empty()) { if (kvv.size() == 1) { gu_throw_error(EINVAL) <<"Key without value: '" << key <<"' at position '" << i << "' in parameter list."; } if (kvv.size() > 2) { gu_throw_error(EINVAL) <<"More than one value for key '" << key <<"' at '" << pv[i] << "' in parameter list."; } gu::trim(kvv[1]); std::string& value = kvv[1]; params_vector.push_back(std::make_pair(key, value)); } else if (kvv.size() > 1) { gu_throw_error(EINVAL) << "Empty key at '" << pv[i] << "' in parameter list."; } } } void gu::Config::parse (const std::string& param_list) { if (param_list.empty()) return; std::vector > pv; parse (pv, param_list); bool not_found(false); for (size_t i = 0; i < pv.size(); ++i) { const std::string& key (pv[i].first); const std::string& value(pv[i].second); try { set(key, value); } catch (NotFound& e) { log_error << "Unrecognized parameter '" << key << '\''; /* Throw later so that all invalid parameters get logged.*/ not_found = true; } log_debug << "Set parameter '" << key << "' = '" << value << "'"; } if (not_found) throw gu::NotFound(); } gu::Config::Config() : params_() {} void gu::Config::set_longlong (const std::string& key, long long val) { const char* num_mod = ""; /* Shift preserves sign! */ if (val != 0) { if (!(val & ((1LL << 40) - 1))) { val >>= 40; num_mod = "T"; } else if (!(val & ((1 << 30) - 1))) { val >>= 30; num_mod = "G"; } else if (!(val & ((1 << 20) - 1))) { val >>= 20; num_mod = "M"; } else if (!(val & ((1 << 10) - 1))) { val >>= 10; num_mod = "K"; } } std::ostringstream ost; ost << val << num_mod; set (key, ost.str()); } void gu::Config::check_conversion (const char* str, const char* endptr, const char* type) { if (endptr == str || endptr[0] != '\0') { gu_throw_error(EINVAL) << "Invalid value '" << str << "' for " << type << " type."; } } char gu::Config::overflow_char(long long ret) { if (ret >= CHAR_MIN && ret <= CHAR_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (char)."; } short gu::Config::overflow_short(long long ret) { if (ret >= SHRT_MIN && ret <= SHRT_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (short)."; } int gu::Config::overflow_int(long long ret) { if (ret >= INT_MIN && ret <= INT_MAX) return ret; gu_throw_error(EOVERFLOW) << "Value " << ret << " too large for requested type (int)."; } void gu::Config::print (std::ostream& os, bool const notset) const { struct _print_param { void operator() (std::ostream& os, bool const notset, param_map_t::const_iterator& pi) { const Parameter& p(pi->second); if (p.is_set() || notset) { os << pi->first << " = " << p.value() << "; "; } } } print_param; for (param_map_t::const_iterator pi(params_.begin()); pi != params_.end(); ++pi) { print_param(os, notset, pi); } } std::ostream& gu::operator<<(std::ostream& ost, const gu::Config& c) { c.print(ost); return ost; } gu_config_t* gu_config_create (void) { try { return (reinterpret_cast(new gu::Config())); } catch (gu::Exception& e) { log_error << "Failed to create configuration object: " << e.what(); return 0; } } void gu_config_destroy (gu_config_t* cnf) { if (cnf) { gu::Config* conf = reinterpret_cast(cnf); delete conf; } else { log_error << "Null configuration object in " << __FUNCTION__; assert (0); } } static int config_check_set_args (gu_config_t* cnf, const char* key, const char* func) { if (cnf && key && key[0] != '\0') return 0; if (!cnf) { log_fatal << "Null configuration object in " << func; } if (!key) { log_fatal << "Null key in " << func; } else if (key[0] == '\0') { log_fatal << "Empty key in " << func; } assert (0); return -EINVAL; } static int config_check_get_args (gu_config_t* cnf, const char* key, const void* val_ptr, const char* func) { if (cnf && key && key[0] != '\0' && val_ptr) return 0; if (!cnf) { log_error << "Null configuration object in " << func; } if (!key) { log_error << "Null key in " << func; } else if (key[0] == '\0') { log_error << "Empty key in " << func; } if (!val_ptr) { log_error << "Null value pointer in " << func; } assert (0); return -EINVAL; } bool gu_config_has (gu_config_t* cnf, const char* key) { if (config_check_set_args (cnf, key, __FUNCTION__)) return false; gu::Config* conf = reinterpret_cast(cnf); return (conf->has (key)); } bool gu_config_is_set (gu_config_t* cnf, const char* key) { if (config_check_set_args (cnf, key, __FUNCTION__)) return false; gu::Config* conf = reinterpret_cast(cnf); return (conf->is_set (key)); } int gu_config_add (gu_config_t* cnf, const char* key, const char* const val) { if (config_check_set_args (cnf, key, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { if (val != NULL) conf->add (key, val); else conf->add (key); return 0; } catch (std::exception& e) { log_error << "Error adding parameter '" << key << "': " << e.what(); return -1; } catch (...) { log_error << "Unknown exception adding parameter '" << key << "'"; return -1; } } int gu_config_get_string (gu_config_t* cnf, const char* key, const char** val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key).c_str(); return 0; } catch (gu::NotFound&) { return 1; } } int gu_config_get_int64 (gu_config_t* cnf, const char* key, int64_t* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_double (gu_config_t* cnf, const char* key, double* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_ptr (gu_config_t* cnf, const char* key, void** val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } int gu_config_get_bool (gu_config_t* cnf, const char* key, bool* val) { if (config_check_get_args (cnf, key, val, __FUNCTION__)) return -EINVAL; gu::Config* conf = reinterpret_cast(cnf); try { *val = conf->get(key); return 0; } catch (gu::NotFound&) { return 1; } catch (gu::NotSet&) { return 1; } catch (gu::Exception& e) { log_error << "Failed to parse parameter '" << key << "': " << e.what(); return -e.get_errno(); } } #include void gu_config_set_string (gu_config_t* cnf, const char* key, const char* val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); assert (cnf); gu::Config* conf = reinterpret_cast(cnf); conf->set (key, val); } void gu_config_set_int64 (gu_config_t* cnf, const char* key, int64_t val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set (key, val); } void gu_config_set_double (gu_config_t* cnf, const char* key, double val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } void gu_config_set_ptr (gu_config_t* cnf, const char* key, const void* val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } void gu_config_set_bool (gu_config_t* cnf, const char* key, bool val) { if (config_check_set_args (cnf, key, __FUNCTION__)) abort(); gu::Config* conf = reinterpret_cast(cnf); conf->set(key, val); } ssize_t gu_config_print (gu_config_t* cnf, char* buf, ssize_t buf_len) { std::ostringstream os; os << *(reinterpret_cast(cnf)); const std::string& str = os.str(); strncpy (buf, str.c_str(), buf_len - 1); buf[buf_len - 1] = '\0'; return str.length(); } percona-galera-3-3.8-3390/galerautils/src/gu_config.h000066400000000000000000000033551244131713600222240ustar00rootroot00000000000000// Copyright (C) 2010-2014 Codership Oy /** * @file * C-interface for configuration management * * $Id$ */ #ifndef _gu_config_h_ #define _gu_config_h_ #include #include #include // for ssize_t #ifdef __cplusplus extern "C" { #endif typedef struct gu_config gu_config_t; gu_config_t* gu_config_create (void); void gu_config_destroy (gu_config_t* cnf); bool gu_config_has (gu_config_t* cnf, const char* key); bool gu_config_is_set (gu_config_t* cnf, const char* key); /* before setting a parameter, it must be added to a known parameter list*/ int gu_config_add (gu_config_t* cnf, const char* key, const char* val /*can be NULL*/); /* Getters/setters return 0 on success, 1 when key not set/not found, * negative error code in case of other errors (conversion failed and such) */ int gu_config_get_string (gu_config_t* cnf, const char* key, const char** val); int gu_config_get_int64 (gu_config_t* cnf, const char* key, int64_t* val); int gu_config_get_double (gu_config_t* cnf, const char* key, double* val); int gu_config_get_ptr (gu_config_t* cnf, const char* key, void** val); int gu_config_get_bool (gu_config_t* cnf, const char* key, bool* val); void gu_config_set_string (gu_config_t* cnf, const char* key, const char* val); void gu_config_set_int64 (gu_config_t* cnf, const char* key, int64_t val); void gu_config_set_double (gu_config_t* cnf, const char* key, double val); void gu_config_set_ptr (gu_config_t* cnf, const char* key, const void* val); void gu_config_set_bool (gu_config_t* cnf, const char* key, bool val); ssize_t gu_config_print (gu_config_t* cnf, char* buf, ssize_t buf_len); #ifdef __cplusplus } #endif #endif /* _gu_config_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_config.hpp000066400000000000000000000156121244131713600225630ustar00rootroot00000000000000// Copyright (C) 2010-2014 Codership Oy /** * @file * Configuration management class * * $Id$ */ #ifndef _gu_config_hpp_ #define _gu_config_hpp_ #include "gu_string_utils.hpp" #include "gu_exception.hpp" #include "gu_utils.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include #include namespace gu { class Config; } extern "C" const char* gu_str2ll (const char* str, long long* ll); class gu::Config { public: static const char PARAM_SEP; // parameter separator static const char KEY_VALUE_SEP; // key-value separator static const char ESCAPE; // escape symbol Config (); bool has (const std::string& key) const { return (params_.find(key) != params_.end()); } bool is_set (const std::string& key) const { param_map_t::const_iterator const i(params_.find(key)); if (i != params_.end()) { return i->second.is_set(); } else { throw NotFound(); } } /* adds parameter to the known parameter list */ void add (const std::string& key) { if (!has(key)) { params_[key] = Parameter(); } } /* adds parameter to the known parameter list and sets its value */ void add (const std::string& key, const std::string& value) { if (!has(key)) { params_[key] = Parameter(value); } } /* sets a known parameter to some value, otherwise throws NotFound */ void set (const std::string& key, const std::string& value) { param_map_t::iterator const i(params_.find(key)); if (i != params_.end()) { i->second.set(value); } else { #ifndef NDEBUG log_error << key << " not recognized."; #endif throw NotFound(); } } void set (const std::string& key, const char* value) { set(key, std::string(value)); } /* Parse a string of semicolumn separated key=value pairs into a vector. * Throws Exception in case of parsing error. */ static void parse (std::vector >& params_vector, const std::string& params_string); /* Parse a string of semicolumn separated key=value pairs and * set the values. * Throws NotFound if key was not explicitly added before. */ void parse (const std::string& params_string); /* General template for integer types */ template void set (const std::string& key, T val) { set_longlong (key, val); } /*! @throws NotSet, NotFound */ const std::string& get (const std::string& key) const { param_map_t::const_iterator const i(params_.find(key)); if (i == params_.end()) throw NotFound(); if (i->second.is_set()) return i->second.value(); log_debug << key << " not set."; throw NotSet(); } const std::string& get (const std::string& key, const std::string& def) const { try { return get(key); } catch (NotSet&) { return def ; } } /*! @throws NotFound */ template inline T get (const std::string& key) const { return from_config (get(key)); } template inline T get(const std::string& key, const T& def) const { try { return get(key); } catch (NotSet&) { return def; } } void print (std::ostream& os, bool include_not_set = false) const; /*! Convert string configuration values to other types. * General template for integers, specialized templates follow below. */ template static inline T from_config (const std::string& value) { const char* str = value.c_str(); long long ret; const char* endptr = gu_str2ll (str, &ret); check_conversion (str, endptr, "integer"); switch (sizeof(T)) { case 1: return overflow_char (ret); case 2: return overflow_short (ret); case 4: return overflow_int (ret); default: return ret; } } /* iterator stuff */ class Parameter { public: explicit Parameter(const std::string& value) : value_(value), set_(true) {} Parameter() : value_(), set_(false) {} const std::string& value() const { return value_; } bool is_set() const { return set_ ; } void set(const std::string& value) { value_ = value; set_ = true; } private: std::string value_; bool set_; }; typedef std::map param_map_t; typedef param_map_t::const_iterator const_iterator; const_iterator begin() const { return params_.begin(); } const_iterator end() const { return params_.end(); } private: static void check_conversion (const char* ptr, const char* endptr, const char* type); static char overflow_char(long long ret); static short overflow_short(long long ret); static int overflow_int(long long ret); void set_longlong (const std::string& key, long long value); param_map_t params_; }; extern "C" const char* gu_str2dbl (const char* str, double* dbl); extern "C" const char* gu_str2bool (const char* str, bool* bl); extern "C" const char* gu_str2ptr (const char* str, void** ptr); namespace gu { std::ostream& operator<<(std::ostream&, const gu::Config&); /*! Specialized templates for "funny" types */ template <> inline double Config::from_config (const std::string& value) { const char* str = value.c_str(); double ret; const char* endptr = gu_str2dbl (str, &ret); check_conversion (str, endptr, "double"); return ret; } template <> inline bool Config::from_config (const std::string& value) { const char* str = value.c_str(); bool ret; const char* endptr = gu_str2bool (str, &ret); check_conversion (str, endptr, "boolean"); return ret; } template <> inline void* Config::from_config (const std::string& value) { const char* str = value.c_str(); void* ret; const char* endptr = gu_str2ptr (str, &ret); check_conversion (str, endptr, "pointer"); return ret; } template <> inline void Config::set (const std::string& key, const void* value) { set (key, to_string(value)); } template <> inline void Config::set (const std::string& key, double val) { set (key, to_string(val)); } template <> inline void Config::set (const std::string& key, bool val) { const char* val_str(val ? "YES" : "NO"); // YES/NO is most generic set (key, val_str); } } #endif /* _gu_config_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_convert.hpp000066400000000000000000000067531244131713600230040ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /** * @file Routines for safe integer conversion * * $Id$ */ #ifndef _gu_convert_hpp_ #define _gu_convert_hpp_ #include "gu_macros.h" #include "gu_throw.hpp" #include namespace gu { /*! * Converts from type FROM to type TO with range checking. * Generic template is for the case sizeof(FROM) > sizeof(TO). * * @param from value to convert * @param to destination (provides type TO for template instantiation) * @return value cast to TO */ template inline TO convert (const FROM& from, const TO& to) { if (gu_unlikely(from > std::numeric_limits::max() || from < std::numeric_limits::min())) { // @todo: figure out how to print type name without RTTI gu_throw_error (ERANGE) << from << " is unrepresentable with " << (std::numeric_limits::is_signed ? "signed" : "unsigned") << " " << sizeof(TO) << " bytes."; } return static_cast(from); } /* Specialized templates are for signed conversion */ template <> inline long long convert (const unsigned long long& from, const long long& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long long'"; } return static_cast(from); } template <> inline unsigned long long convert (const long long& from, const unsigned long long& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long long'"; } return static_cast(from); } template <> inline long convert (const unsigned long& from, const long& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long'"; } return static_cast(from); } template <> inline unsigned long convert (const long& from, const unsigned long& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long'"; } return static_cast(from); } template <> inline int convert (const unsigned int& from, const int& to) { if (gu_unlikely(from > static_cast (std::numeric_limits::max()))) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'long'"; } return static_cast(from); } template <> inline unsigned int convert (const int& from, const unsigned int& to) { if (gu_unlikely(from < 0)) { gu_throw_error (ERANGE) << from << " is unrepresentable with 'unsigned long'"; } return static_cast(from); } } #endif /* _gu_convert_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_crc.hpp000066400000000000000000000013161244131713600220610ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * @file header for various CRC stuff * * $Id$ */ #ifndef GU_CRC_HPP #define GU_CRC_HPP #include "gu_crc32c.h" namespace gu { class CRC32C { public: CRC32C() : state_(GU_CRC32C_INIT) {} void append(const void* const data, size_t const size) { gu_crc32c_append (&state_, data, size); } uint32_t get() const { return gu_crc32c_get(state_); } uint32_t operator() () const { return get(); } static uint32_t digest(const void* const data, size_t const size) { return gu_crc32c(data, size); } private: gu_crc32c_t state_; }; /* class CRC32C */ } /* namespace gu */ #endif /* GU_CRC_HPP */ percona-galera-3-3.8-3390/galerautils/src/gu_crc32c.c000066400000000000000000000013331244131713600220230ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * $Id$ */ #include "gu_crc32c.h" #include "gu_log.h" #include CRC32CFunctionPtr gu_crc32c_func = crc32cSlicingBy8; // some sensible default void gu_crc32c_configure() { gu_crc32c_func = detectBestCRC32C(); #if !defined(CRC32C_NO_HARDWARE) if (gu_crc32c_func == crc32cHardware64 || gu_crc32c_func == crc32cHardware32) { gu_info ("CRC-32C: using hardware acceleration."); } else #endif /* !CRC32C_NO_HARDWARE */ if (gu_crc32c_func == crc32cSlicingBy8) { gu_info ("CRC-32C: using \"slicing-by-8\" algorithm."); } else { gu_fatal ("unexpected CRC-32C implementation."); abort(); } } percona-galera-3-3.8-3390/galerautils/src/gu_crc32c.h000066400000000000000000000021101244131713600220220ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * @file Interface to CRC-32C implementation from www.evanjones.ca * * $Id$ */ #ifndef _GU_CRC32C_H_ #define _GU_CRC32C_H_ #if defined(__cplusplus) extern "C" { #endif #include "www.evanjones.ca/crc32c.h" #include "gu_macros.h" #include "gu_byteswap.h" /*! Call this to configure CRC32C to use the best available implementation */ extern void gu_crc32c_configure(); extern CRC32CFunctionPtr gu_crc32c_func; typedef uint32_t gu_crc32c_t; static gu_crc32c_t const GU_CRC32C_INIT = 0xFFFFFFFF; static GU_FORCE_INLINE void gu_crc32c_init (gu_crc32c_t* crc) { *crc = GU_CRC32C_INIT; } static GU_FORCE_INLINE void gu_crc32c_append (gu_crc32c_t* crc, const void* data, size_t size) { *crc = gu_crc32c_func (*crc, data, size); } static GU_FORCE_INLINE uint32_t gu_crc32c_get (gu_crc32c_t crc) { return (~(crc)); } static GU_FORCE_INLINE uint32_t gu_crc32c (const void* data, size_t size) { return (~(gu_crc32c_func (GU_CRC32C_INIT, data, size))); } #if defined(__cplusplus) } #endif #endif /* _GU_CRC32C_H_ */ percona-galera-3-3.8-3390/galerautils/src/gu_datetime.cpp000066400000000000000000000055071244131713600231070ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #include "gu_datetime.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" extern "C" { #include "gu_time.h" } std::ostream& gu::datetime::operator<<(std::ostream& os, const Date& d) { os << d.get_utc(); return os; } std::ostream& gu::datetime::operator<<(std::ostream& os, const Period& p) { os << "P"; int64_t nsecs(p.get_nsecs()); if (nsecs/Year > 0) { os << (nsecs/Year) << "Y"; nsecs %= Year; } if (nsecs/Month > 0) { os << (nsecs/Month) << "M"; nsecs %= Month; } if (nsecs/Day > 0) { os << (nsecs/Day) << "D"; nsecs %= Day; } if (nsecs > 0) { os << "T"; } if (nsecs/Hour > 0) { os << (nsecs/Hour) << "H"; nsecs %= Hour; } if (nsecs/Min > 0) { os << (nsecs/Min) << "M"; nsecs %= Min; } if (double(nsecs)/Sec >= 1.e-9) { os << (double(nsecs)/Sec) << "S"; } return os; } void gu::datetime::Date::parse(const std::string& str) { if (str == "") { return; } gu_throw_fatal << "not implemented"; } const char* const gu::datetime::Period::period_regex = "^(P)(([0-9]+)Y)?(([0-9]+)M)?(([0-9]+)D)?" /* 1 23 45 67 */ "((T)?(([0-9]+)H)?(([0-9]+)M)?(([0-9]+)(\\.([0-9]+))?S)?)?"; /* 89 11 13 15 16 */ enum { GU_P = 1, GU_YEAR = 3, GU_MONTH = 5, GU_DAY = 7, GU_HOUR = 10, GU_MIN = 12, GU_SEC = 15, GU_SEC_D = 16, GU_NUM_PARTS = 17 }; gu::RegEx const gu::datetime::Period::regex(period_regex); void gu::datetime::Period::parse(const std::string& str) { std::vector parts = regex.match(str, GU_NUM_PARTS); if (parts[GU_P].is_set() == false) { if (str == "") { return; } else { gu_throw_error (EINVAL) << "Period " << str << " not valid"; } } if (parts[GU_YEAR].is_set()) { nsecs += from_string(parts[GU_YEAR].str())*Year; } if (parts[GU_MONTH].is_set()) { nsecs += from_string(parts[GU_MONTH].str())*Month; } if (parts[GU_DAY].is_set()) { nsecs += from_string(parts[GU_DAY].str())*Day; } if (parts[GU_HOUR].is_set()) { nsecs += from_string(parts[GU_HOUR].str())*Hour; } if (parts[GU_MIN].is_set()) { nsecs += from_string(parts[GU_MIN].str())*Min; } if (parts[GU_SEC].is_set()) { long long s(from_string(parts[GU_SEC].str())); nsecs += s*Sec; } if (parts[GU_SEC_D].is_set()) { double d(from_string(parts[GU_SEC_D].str())); nsecs += static_cast(d*Sec); } } percona-galera-3-3.8-3390/galerautils/src/gu_datetime.hpp000066400000000000000000000146511244131713600231140ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! * @file Date/time manipulation classes providing nanosecond resolution. */ #ifndef __GU_DATETIME__ #define __GU_DATETIME__ #include "gu_exception.hpp" #include "gu_regex.hpp" #include "gu_time.h" #include #include #include namespace gu { namespace datetime { /* Multiplier constants */ const long long NSec = 1; const long long USec = 1000*NSec; const long long MSec = 1000*USec; const long long Sec = 1000*MSec; const long long Min = 60*Sec; const long long Hour = 60*Min; const long long Day = 24*Hour; const long long Month = 30*Day; const long long Year = 12*Month; /*! * @brief Class representing time periods instead of * system clock time. */ class Period { public: /*! * @brief Constructor * * Duration format is PnYnMnDTnHnMnS where Y is year, M is month, * D is day, T is the time designator separating date and time * parts, H denotes hours, M (after T) is minutes and S seconds. * * All other n:s are expected to be integers except the one * before S which can be decimal to represent fractions of second. * * @param str Time period represented in ISO8601 duration format. */ Period(const std::string& str = "") : nsecs() { if (str != "") parse(str); } Period(const long long nsecs_) : nsecs(nsecs_) { } static Period min() { return 0; } static Period max() { return std::numeric_limits::max();} bool operator==(const Period& cmp) const { return (nsecs == cmp.nsecs); } bool operator<(const Period& cmp) const { return (nsecs < cmp.nsecs); } bool operator>=(const Period& cmp) const { return !(*this < cmp); } Period operator+(const long long add) const { return (nsecs + add); } Period operator-(const long long dec) const { return (nsecs - dec); } Period operator*(const long long mul) const { return (nsecs*mul); } Period operator/(const long long div) const { return (nsecs/div); } long long get_nsecs() const { return nsecs; } Period operator+(const Period& add) const { return (nsecs + add.nsecs); } Period operator-(const Period& dec) const { return (nsecs - dec.nsecs); } private: friend class Date; friend std::istream& operator>>(std::istream&, Period&); static const char* const period_regex; /*! regexp string */ static RegEx const regex; /*! period string parser */ /*! * @brief Parse period string. */ void parse(const std::string&); long long nsecs; }; /*! * @brief Date/time representation. * * @todo Parsing date from string is not implemented yet, * only possible to get current system time or * maximum time. */ class Date { public: /*! * @brief Get system time. * @note This call should be deprecated in favor of calendar() * and monotonic(). */ static inline Date now() { return gu_time_monotonic(); } /*! * @brief Get time from system-wide realtime clock. */ static inline Date calendar() { return gu_time_calendar(); } /*! * @brief Get time from monotonic clock. */ static inline Date monotonic() { return gu_time_monotonic(); } /*! * @brief Get maximum representable timestamp. */ static inline Date max() { return std::numeric_limits::max(); } /*! * @brief Get zero time */ static inline Date zero() { return 0; } /*! * Return 64-bit timestamp representing system time in nanosecond * resolution. */ long long get_utc() const { return utc; } /* Standard comparision operators */ bool operator==(const Date cmp) const { return (utc == cmp.utc); } bool operator<(const Date cmp) const { return (utc < cmp.utc); } /*! * @brief Add period to Date */ Date operator+(const Period& add) const { return (utc + add.get_nsecs()); } /*! * @brief Decrement period from Date */ Date operator-(const Period& dec) const { return (utc - dec.get_nsecs()); } Period operator-(const Date& dec) const { return (utc - dec.utc); } Date(const long long utc_ = 0) : utc(utc_) { } /*! convert to timespec - for internal use */ void _timespec(timespec& ts) const { ts.tv_sec = utc / 1000000000L; ts.tv_nsec = utc % 1000000000L; } private: long long utc; /*!< System time in nanosecond precision */ /*! * @brief Parse date from string. * @todo Not implemented yet */ void parse(const std::string& str_); }; /*! * @brief Output operator for Date class. * @todo Not implemented yet */ std::ostream& operator<<(std::ostream&, const Date&); /*! * @brief Output operator for Period type. */ std::ostream& operator<<(std::ostream&, const Period&); inline std::string to_string(const Period& p) { std::ostringstream os; os << p; return os.str(); } inline std::istream& operator>>(std::istream& is, Period& p) { std::string str; is >> str; p.parse(str); return is; } } // namespace datetime } // namespace gu #endif // __GU_DATETIME__ percona-galera-3-3.8-3390/galerautils/src/gu_dbug.c000066400000000000000000001513621244131713600216750ustar00rootroot00000000000000/****************************************************************************** * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * * * This previously copyrighted work has been placed into the public * * domain by the author and may be freely used for any purpose, * * private or commercial. * * * * Because of the number of inquiries I was receiving about the use * * of this product in commercially developed works I have decided to * * simply make it public domain to further its unrestricted use. I * * specifically would be most happy to see this material become a * * part of the standard Unix distributions by AT&T and the Berkeley * * Computer Science Research Group, and a standard part of the GNU * * system from the Free Software Foundation. * * * * I would appreciate it, as a courtesy, if this notice is left in * * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of mer- * * chantability or fitness for any particular purpose. * * * ****************************************************************************** */ /* * FILE * * dbug.c runtime support routines for dbug package * * SCCS * * @(#)dbug.c 1.25 7/25/89 * * DESCRIPTION * * These are the runtime support routines for the dbug package. * The dbug package has two main components; the user include * file containing various macro definitions, and the runtime * support routines which are called from the macro expansions. * * Externally visible functions in the runtime support module * use the naming convention pattern "_db_xx...xx_", thus * they are unlikely to collide with user defined function names. * * AUTHOR(S) * * Fred Fish (base code) * Enhanced Software Technologies, Tempe, AZ * asuvax!mcdphx!estinc!fnf * * Binayak Banerjee (profiling enhancements) * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: * DBUG_DUMP - To dump a pice of memory. * PUSH_FLAG "O" - To be used insted of "o" if we don't * want flushing (for slow systems) * PUSH_FLAG "A" - as 'O', but we will append to the out file instead * of creating a new one. * Check of malloc on entry/exit (option "S") * * Alexey Yurchenko: * - Renamed global symbols for use with galera project to avoid * collisions with other software (notably MySQL) * * Teemu Ollakka: * - Slight cleanups, removed some MySQL dependencies. * - All global variables should now have _gu_db prefix. * - Thread -> state mapping for multithreaded programs. * - Changed initialization so that it is done on the first * call to _gu_db_push(). * * $Id$ */ #include #include #include #include #include #include #ifndef GU_DBUG_ON #define GU_DBUG_ON #endif #include "gu_dbug.h" /* Make a new type: bool_t */ typedef enum { FALSE = (0 != 0), TRUE = (!FALSE) } bool_t; #define _VARARGS(X) X #define FN_LIBCHAR 1024 #define FN_REFLEN 1024 #define NullS "" #include #if defined(MSDOS) || defined(__WIN__) #include #endif #ifdef _GU_DBUG_CONDITION_ #define _GU_DBUG_START_CONDITION_ "d:t" #else #define _GU_DBUG_START_CONDITION_ "" #endif /* * Manifest constants that should not require any changes. */ #define EOS '\000' /* End Of String marker */ /* * Manifest constants which may be "tuned" if desired. */ #define PRINTBUF 1024 /* Print buffer size */ #define INDENT 2 /* Indentation per trace level */ #define MAXDEPTH 200 /* Maximum trace depth default */ /* * The following flags are used to determine which * capabilities the user has enabled with the state * push macro. */ #define TRACE_ON 000001 /* Trace enabled */ #define DEBUG_ON 000002 /* Debug enabled */ #define FILE_ON 000004 /* File name print enabled */ #define LINE_ON 000010 /* Line number print enabled */ #define DEPTH_ON 000020 /* Function nest level print enabled */ #define PROCESS_ON 000040 /* Process name print enabled */ #define NUMBER_ON 000100 /* Number each line of output */ #define PROFILE_ON 000200 /* Print out profiling code */ #define PID_ON 000400 /* Identify each line with process id */ #define SANITY_CHECK_ON 001000 /* Check my_malloc on GU_DBUG_ENTER */ #define FLUSH_ON_WRITE 002000 /* Flush on every write */ #define TRACING (_gu_db_stack -> flags & TRACE_ON) #define DEBUGGING (_gu_db_stack -> flags & DEBUG_ON) #define PROFILING (_gu_db_stack -> flags & PROFILE_ON) #define STREQ(a,b) (strcmp(a,b) == 0) #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) /* * Typedefs to make things more obvious.??? */ #ifndef __WIN__ typedef int BOOLEAN; #else #define BOOLEAN BOOL #endif /* * Make it easy to change storage classes if necessary. */ #define IMPORT extern /* Names defined externally */ #define EXPORT /* Allocated here, available globally */ #define AUTO auto /* Names to be allocated on stack */ #define REGISTER register /* Names to be placed in registers */ /* * The default file for profiling. Could also add another flag * (G?) which allowed the user to specify this. * * If the automatic variables get allocated on the stack in * reverse order from their declarations, then define AUTOS_REVERSE. * This is used by the code that keeps track of stack usage. For * forward allocation, the difference in the dbug frame pointers * represents stack used by the callee function. For reverse allocation, * the difference represents stack used by the caller function. * */ #define PROF_FILE "dbugmon.out" #define PROF_EFMT "E\t%ld\t%s\n" #define PROF_SFMT "S\t%lx\t%lx\t%s\n" #define PROF_XFMT "X\t%ld\t%s\n" #ifdef M_I386 /* predefined by xenix 386 compiler */ #define AUTOS_REVERSE 1 #endif /* * Variables which are available externally but should only * be accessed via the macro package facilities. */ FILE *_gu_db_fp_ = (FILE*) 0; /* Output stream, default stderr */ char *_gu_db_process_ = (char*) "dbug"; /* Pointer to process name; argv[0] */ FILE *_gu_db_pfp_ = (FILE*) 0; /* Profile stream, 'dbugmon.out' */ BOOLEAN _gu_db_on_ = FALSE; /* TRUE if debugging currently on */ BOOLEAN _gu_db_pon_ = FALSE; /* TRUE if profile currently on */ BOOLEAN _gu_no_db_ = TRUE; /* TRUE if no debugging at all */ /* * Externally supplied functions. */ IMPORT int _sanity(const char *file, uint line); /* * The user may specify a list of functions to trace or * debug. These lists are kept in a linear linked list, * a very simple implementation. */ struct link { char *str; /* Pointer to link's contents */ struct link *next_link; /* Pointer to the next link */ }; /* * Debugging states can be pushed or popped off of a * stack which is implemented as a linked list. Note * that the head of the list is the current state and the * stack is pushed by adding a new state to the head of the * list or popped by removing the first link. */ struct state { int flags; /* Current state flags */ int maxdepth; /* Current maximum trace depth */ uint delay; /* Delay after each output line */ int sub_level; /* Sub this from code_state->level */ FILE* out_file; /* Current output stream */ FILE* prof_file; /* Current profiling stream */ char name[FN_REFLEN]; /* Name of output file */ struct link* functions; /* List of functions */ struct link* p_functions; /* List of profiled functions */ struct link* keywords; /* List of debug keywords */ struct link* processes; /* List of process names */ struct state* next_state; /* Next state in the list */ }; /* * Local variables not seen by user. */ static struct state* _gu_db_stack = 0; typedef struct st_code_state { int lineno; /* Current debugger output line number */ int level; /* Current function nesting level */ const char* func; /* Name of current user function */ const char* file; /* Name of current user file */ char** framep; /* Pointer to current frame */ int jmplevel; /* Remember nesting level at setjmp () */ const char* jmpfunc; /* Remember current function for setjmp */ const char* jmpfile; /* Remember current file for setjmp */ /* * The following variables are used to hold the state information * between the call to _gu_db_pargs_() and _gu_db_doprnt_(), during * expansion of the GU_DBUG_PRINT macro. This is the only macro * that currently uses these variables. * * These variables are currently used only by _gu_db_pargs_() and * _gu_db_doprnt_(). */ uint u_line; /* User source code line number */ const char* u_keyword; /* Keyword for current macro */ int locked; /* If locked with _gu_db_lock_file */ } CODE_STATE; /* Parse a debug command string */ static struct link *ListParse(char *ctlp); /* Make a fresh copy of a string */ static char *StrDup(const char *str); /* Open debug output stream */ static void GU_DBUGOpenFile(const char *name, int append); #ifndef THREAD /* Open profile output stream */ static FILE *OpenProfile(const char *name); /* Profile if asked for it */ static BOOLEAN DoProfile(void); /* Return current user time (ms) */ static unsigned long Clock(void); #endif /* Close debug output stream */ static void CloseFile(FILE * fp); /* Push current debug state */ static void PushState(void); /* Test for tracing enabled */ static BOOLEAN DoTrace(CODE_STATE * state); /* Test to see if file is writable */ #if !(!defined(HAVE_ACCESS) || defined(MSDOS)) static BOOLEAN Writable(char *pathname); /* Change file owner and group */ static void ChangeOwner(char *pathname); /* Allocate memory for runtime support */ #endif static char *DbugMalloc(int size); /* Remove leading pathname components */ static char *BaseName(const char *pathname); static void DoPrefix(uint line); static void FreeList(struct link *linkp); static void Indent(int indent); static BOOLEAN InList(struct link *linkp, const char *cp); static void dbug_flush(CODE_STATE *); static void DbugExit(const char *why); static int DelayArg(int value); /* Supplied in Sys V runtime environ */ /* Break string into tokens */ static char *static_strtok(char *s1, char chr); /* * Miscellaneous printf format strings. */ #define ERR_MISSING_RETURN "%s: missing GU_DBUG_RETURN or GU_DBUG_VOID_RETURN macro in function \"%s\"\n" #define ERR_OPEN "%s: can't open debug output stream \"%s\": " #define ERR_CLOSE "%s: can't close debug file: " #define ERR_ABORT "%s: debugger aborting because %s\n" #define ERR_CHOWN "%s: can't change owner/group of \"%s\": " /* * Macros and defines for testing file accessibility under UNIX and MSDOS. */ #undef EXISTS #if !defined(HAVE_ACCESS) || defined(MSDOS) #define EXISTS(pathname) (FALSE) /* Assume no existance */ #define Writable(name) (TRUE) #else #define EXISTS(pathname) (access (pathname, F_OK) == 0) #define WRITABLE(pathname) (access (pathname, W_OK) == 0) #endif #ifndef MSDOS #define ChangeOwner(name) #endif /* * Translate some calls among different systems. */ #if defined(unix) || defined(xenix) || defined(VMS) || defined(__NetBSD__) # define Delay(A) sleep((uint) A) #elif defined(AMIGA) IMPORT int Delay(); /* Pause for given number of ticks */ #else static int Delay(int ticks); #endif /* ** Macros to allow dbugging with threads */ #ifdef THREAD #include pthread_once_t _gu_db_once = PTHREAD_ONCE_INIT; pthread_mutex_t _gu_db_mutex = PTHREAD_MUTEX_INITIALIZER; struct state_map { pthread_t th; CODE_STATE *state; struct state_map *prev; struct state_map *next; }; #define _GU_DB_STATE_MAP_BUCKETS (1 << 7) static struct state_map *_gu_db_state_map[_GU_DB_STATE_MAP_BUCKETS]; /* * This hash is probably good enough. Golden ratio 2654435761U from * http://www.concentric.net/~Ttwang/tech/inthash.htm * * UPDATE: it is good enough for input with significant variation in * 32 lower bits. */ static inline unsigned long pt_hash(const pthread_t th) { unsigned long k = (unsigned long)th; uint64_t ret = 2654435761U * k; // since we're returning a masked hash key, all considerations // for "reversibility" can be dropped. Instead we can help // higher input bits influence lower output bits. XOR rules. return (ret ^ (ret >> 32)) & (_GU_DB_STATE_MAP_BUCKETS - 1); } static CODE_STATE *state_map_find(const pthread_t th) { unsigned int key = pt_hash(th); struct state_map *sm = _gu_db_state_map[key]; while (sm && sm->th != th) sm = sm->next; return sm ? sm->state : NULL; } void state_map_insert(const pthread_t th, CODE_STATE *state) { unsigned int key; struct state_map *sm; assert(state_map_find(th) == NULL); key = pt_hash(th); sm = malloc(sizeof(struct state_map)); sm->state = state; sm->th = th; pthread_mutex_lock(&_gu_db_mutex); sm->prev = NULL; sm->next = _gu_db_state_map[key]; if (sm->next) sm->next->prev = sm; _gu_db_state_map[key] = sm; pthread_mutex_unlock(&_gu_db_mutex); } void state_map_erase(const pthread_t th) { unsigned int key; struct state_map *sm; key = pt_hash(th); sm = _gu_db_state_map[key]; while (sm && sm->th != th) sm = sm->next; assert(sm); pthread_mutex_lock(&_gu_db_mutex); if (sm->prev) { sm->prev->next = sm->next; } else { assert(_gu_db_state_map[key] == sm); _gu_db_state_map[key] = sm->next; } if (sm->next) sm->next->prev = sm->prev; pthread_mutex_unlock(&_gu_db_mutex); free(sm); } static CODE_STATE * code_state(void) { CODE_STATE *state = 0; if ((state = state_map_find(pthread_self())) == NULL) { state = malloc(sizeof(CODE_STATE)); memset(state, 0, sizeof(CODE_STATE)); state->func = "?func"; state->file = "?file"; state->u_keyword = "?"; state_map_insert(pthread_self(), state); } return state; } static void code_state_cleanup(CODE_STATE *state) { if (state->level == 0) { state_map_erase(pthread_self()); free(state); } } static void _gu_db_init() { if (!_gu_db_fp_) _gu_db_fp_ = stderr; /* Output stream, default stderr */ memset(_gu_db_state_map, 0, sizeof(_gu_db_state_map)); } #else /* !THREAD */ #define _gu_db_init() #define code_state() (&static_code_state) #define code_state_cleanup(A) do {} while (0) #define pthread_mutex_lock(A) {} #define pthread_mutex_unlock(A) {} static CODE_STATE static_code_state = { 0, 0, "?func", "?file", NULL, 0, NULL, NULL, 0, "?", 0 }; #endif /* * FUNCTION * * _gu_db_push_ push current debugger state and set up new one * * SYNOPSIS * * VOID _gu_db_push_ (control) * char *control; * * DESCRIPTION * * Given pointer to a debug control string in "control", pushes * the current debug state, parses the control string, and sets * up a new debug state. * * The only attribute of the new state inherited from the previous * state is the current function nesting level. This can be * overridden by using the "r" flag in the control string. * * The debug control string is a sequence of colon separated fields * as follows: * * ::...: * * Each field consists of a mandatory flag character followed by * an optional "," and comma separated list of modifiers: * * flag[,modifier,modifier,...,modifier] * * The currently recognized flag characters are: * * d Enable output from GU_DBUG_ macros for * for the current state. May be followed * by a list of keywords which selects output * only for the GU_DBUG macros with that keyword. * A null list of keywords implies output for * all macros. * * D Delay after each debugger output line. * The argument is the number of tenths of seconds * to delay, subject to machine capabilities. * I.E. -#D,20 is delay two seconds. * * f Limit debugging and/or tracing, and profiling to the * list of named functions. Note that a null list will * disable all functions. The appropriate "d" or "t" * flags must still be given, this flag only limits their * actions if they are enabled. * * F Identify the source file name for each * line of debug or trace output. * * i Identify the process with the pid for each line of * debug or trace output. * * g Enable profiling. Create a file called 'dbugmon.out' * containing information that can be used to profile * the program. May be followed by a list of keywords * that select profiling only for the functions in that * list. A null list implies that all functions are * considered. * * L Identify the source file line number for * each line of debug or trace output. * * n Print the current function nesting depth for * each line of debug or trace output. * * N Number each line of dbug output. * * o Redirect the debugger output stream to the * specified file. The default output is stderr. * * O As O but the file is really flushed between each * write. When neaded the file is closed and reopened * between each write. * * p Limit debugger actions to specified processes. * A process must be identified with the * GU_DBUG_PROCESS macro and match one in the list * for debugger actions to occur. * * P Print the current process name for each * line of debug or trace output. * * r When pushing a new state, do not inherit * the previous state's function nesting level. * Useful when the output is to start at the * left margin. * * S Do function _sanity(_file_,_line_) at each * debugged function until _sanity() returns * something that differs from 0. * (Moustly used with my_malloc) * * t Enable function call/exit trace lines. * May be followed by a list (containing only * one modifier) giving a numeric maximum * trace level, beyond which no output will * occur for either debugging or tracing * macros. The default is a compile time * option. * * Some examples of debug control strings which might appear * on a shell command line (the "-#" is typically used to * introduce a control string to an application program) are: * * -#d:t * -#d:f,main,subr1:F:L:t,20 * -#d,input,output,files:n * * For convenience, any leading "-#" is stripped off. * */ void _gu_db_push_(const char *control) { register char *scan; register struct link *temp; CODE_STATE *state; char *new_str; pthread_once(&_gu_db_once, &_gu_db_init); if (control && *control == '-') { if (*++control == '#') control++; } if (*control) _gu_no_db_ = FALSE; /* We are using dbug after all */ else return; new_str = StrDup(control); PushState(); state = code_state(); scan = static_strtok(new_str, ':'); for (; scan != NULL; scan = static_strtok((char *) NULL, ':')) { switch (*scan++) { case 'd': _gu_db_on_ = TRUE; _gu_db_stack->flags |= DEBUG_ON; if (*scan++ == ',') { _gu_db_stack->keywords = ListParse(scan); } break; case 'D': _gu_db_stack->delay = 0; if (*scan++ == ',') { temp = ListParse(scan); _gu_db_stack->delay = DelayArg(atoi(temp->str)); FreeList(temp); } break; case 'f': if (*scan++ == ',') { _gu_db_stack->functions = ListParse(scan); } break; case 'F': _gu_db_stack->flags |= FILE_ON; break; case 'i': _gu_db_stack->flags |= PID_ON; break; #ifndef THREAD case 'g': _gu_db_pon_ = TRUE; if (OpenProfile(PROF_FILE)) { _gu_db_stack->flags |= PROFILE_ON; if (*scan++ == ',') _gu_db_stack->p_functions = ListParse(scan); } break; #endif case 'L': _gu_db_stack->flags |= LINE_ON; break; case 'n': _gu_db_stack->flags |= DEPTH_ON; break; case 'N': _gu_db_stack->flags |= NUMBER_ON; break; case 'A': case 'O': _gu_db_stack->flags |= FLUSH_ON_WRITE; case 'a': case 'o': if (*scan++ == ',') { temp = ListParse(scan); GU_DBUGOpenFile(temp->str, (int) (scan[-2] == 'A' || scan[-2] == 'a')); FreeList(temp); } else { GU_DBUGOpenFile("-", 0); } break; case 'p': if (*scan++ == ',') { _gu_db_stack->processes = ListParse(scan); } break; case 'P': _gu_db_stack->flags |= PROCESS_ON; break; case 'r': _gu_db_stack->sub_level = state->level; break; case 't': _gu_db_stack->flags |= TRACE_ON; if (*scan++ == ',') { temp = ListParse(scan); _gu_db_stack->maxdepth = atoi(temp->str); FreeList(temp); } break; case 'S': _gu_db_stack->flags |= SANITY_CHECK_ON; break; } } free(new_str); } /* * FUNCTION * * _gu_db_pop_ pop the debug stack * * DESCRIPTION * * Pops the debug stack, returning the debug state to its * condition prior to the most recent _gu_db_push_ invocation. * Note that the pop will fail if it would remove the last * valid state from the stack. This prevents user errors * in the push/pop sequence from screwing up the debugger. * Maybe there should be some kind of warning printed if the * user tries to pop too many states. * */ void _gu_db_pop_() { register struct state *discard; discard = _gu_db_stack; if (discard != NULL && discard->next_state != NULL) { _gu_db_stack = discard->next_state; _gu_db_fp_ = _gu_db_stack->out_file; _gu_db_pfp_ = _gu_db_stack->prof_file; if (discard->keywords != NULL) { FreeList(discard->keywords); } if (discard->functions != NULL) { FreeList(discard->functions); } if (discard->processes != NULL) { FreeList(discard->processes); } if (discard->p_functions != NULL) { FreeList(discard->p_functions); } CloseFile(discard->out_file); if (discard->prof_file) CloseFile(discard->prof_file); free((char *) discard); if (!(_gu_db_stack->flags & DEBUG_ON)) _gu_db_on_ = 0; } else { _gu_db_on_ = 0; } } /* * FUNCTION * * _gu_db_enter_ process entry point to user function * * SYNOPSIS * * VOID _gu_db_enter_ (_func_, _file_, _line_, * _sfunc_, _sfile_, _slevel_, _sframep_) * char *_func_; points to current function name * char *_file_; points to current file name * int _line_; called from source line number * char **_sfunc_; save previous _func_ * char **_sfile_; save previous _file_ * int *_slevel_; save previous nesting level * char ***_sframep_; save previous frame pointer * * DESCRIPTION * * Called at the beginning of each user function to tell * the debugger that a new function has been entered. * Note that the pointers to the previous user function * name and previous user file name are stored on the * caller's stack (this is why the ENTER macro must be * the first "executable" code in a function, since it * allocates these storage locations). The previous nesting * level is also stored on the callers stack for internal * self consistency checks. * * Also prints a trace line if tracing is enabled and * increments the current function nesting depth. * * Note that this mechanism allows the debugger to know * what the current user function is at all times, without * maintaining an internal stack for the function names. * */ void _gu_db_enter_(const char *_func_, const char *_file_, uint _line_, const char **_sfunc_, const char **_sfile_, uint * _slevel_, char ***_sframep_ __attribute__ ((unused))) { register CODE_STATE *state; if (!_gu_no_db_) { int save_errno = errno; state = code_state(); *_sfunc_ = state->func; *_sfile_ = state->file; state->func = (char *) _func_; state->file = (char *) _file_; /* BaseName takes time !! */ *_slevel_ = ++state->level; #ifndef THREAD *_sframep_ = state->framep; state->framep = (char **) _sframep_; if (DoProfile()) { long stackused; if (*state->framep == NULL) { stackused = 0; } else { stackused = ((long) (*state->framep)) - ((long) (state->framep)); stackused = stackused > 0 ? stackused : -stackused; } (void) fprintf(_gu_db_pfp_, PROF_EFMT, Clock(), state->func); #ifdef AUTOS_REVERSE (void) fprintf(_gu_db_pfp_, PROF_SFMT, state->framep, stackused, *_sfunc_); #else (void) fprintf(_gu_db_pfp_, PROF_SFMT, (ulong) state->framep, stackused, state->func); #endif (void) fflush(_gu_db_pfp_); } #endif if (DoTrace(state)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(_line_); Indent(state->level); (void) fprintf(_gu_db_fp_, ">%s\n", state->func); dbug_flush(state); /* This does a unlock */ } #ifdef SAFEMALLOC if (_gu_db_stack->flags & SANITY_CHECK_ON) if (_sanity(_file_, _line_)) /* Check of my_malloc */ _gu_db_stack->flags &= ~SANITY_CHECK_ON; #endif errno = save_errno; } } /* * FUNCTION * * _gu_db_return_ process exit from user function * * SYNOPSIS * * VOID _gu_db_return_ (_line_, _sfunc_, _sfile_, _slevel_) * int _line_; current source line number * char **_sfunc_; where previous _func_ is to be retrieved * char **_sfile_; where previous _file_ is to be retrieved * int *_slevel_; where previous level was stashed * * DESCRIPTION * * Called just before user function executes an explicit or implicit * return. Prints a trace line if trace is enabled, decrements * the current nesting level, and restores the current function and * file names from the defunct function's stack. * */ void _gu_db_return_(uint _line_, const char **_sfunc_, const char **_sfile_, uint * _slevel_) { CODE_STATE *state; if (!_gu_no_db_) { int save_errno = errno; if (!(state = code_state())) return; /* Only happens at end of program */ if (_gu_db_stack->flags & (TRACE_ON | DEBUG_ON | PROFILE_ON)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); if (state->level != (int) *_slevel_) (void) fprintf(_gu_db_fp_, ERR_MISSING_RETURN, _gu_db_process_, state->func); else { #ifdef SAFEMALLOC if (_gu_db_stack->flags & SANITY_CHECK_ON) if (_sanity(*_sfile_, _line_)) _gu_db_stack->flags &= ~SANITY_CHECK_ON; #endif #ifndef THREAD if (DoProfile()) (void) fprintf(_gu_db_pfp_, PROF_XFMT, Clock(), state->func); #endif if (DoTrace(state)) { DoPrefix(_line_); Indent(state->level); (void) fprintf(_gu_db_fp_, "<%s\n", state->func); } } dbug_flush(state); } state->level = *_slevel_ - 1; state->func = *_sfunc_; state->file = *_sfile_; #ifndef THREAD if (state->framep != NULL) state->framep = (char **) *state->framep; #endif errno = save_errno; code_state_cleanup(state); } } /* * FUNCTION * * _gu_db_pargs_ log arguments for subsequent use by _gu_db_doprnt_() * * SYNOPSIS * * VOID _gu_db_pargs_ (_line_, keyword) * int _line_; * char *keyword; * * DESCRIPTION * * The new universal printing macro GU_DBUG_PRINT, which replaces * all forms of the GU_DBUG_N macros, needs two calls to runtime * support routines. The first, this function, remembers arguments * that are used by the subsequent call to _gu_db_doprnt_(). * */ void _gu_db_pargs_(uint _line_, const char *keyword) { CODE_STATE *state = code_state(); state->u_line = _line_; state->u_keyword = (char *) keyword; } /* * FUNCTION * * _gu_db_doprnt_ handle print of debug lines * * SYNOPSIS * * VOID _gu_db_doprnt_ (format, va_alist) * char *format; * va_dcl; * * DESCRIPTION * * When invoked via one of the GU_DBUG macros, tests the current keyword * set by calling _gu_db_pargs_() to see if that macro has been selected * for processing via the debugger control string, and if so, handles * printing of the arguments via the format string. The line number * of the GU_DBUG macro in the source is found in u_line. * * Note that the format string SHOULD NOT include a terminating * newline, this is supplied automatically. * */ #include void _gu_db_doprnt_(const char *format, ...) { va_list args; CODE_STATE *state; state = code_state(); va_start(args, format); if (_gu_db_keyword_(state->u_keyword)) { int save_errno = errno; if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(state->u_line); if (TRACING) { Indent(state->level + 1); } else { (void) fprintf(_gu_db_fp_, "%s: ", state->func); } (void) fprintf(_gu_db_fp_, "%s: ", state->u_keyword); (void) vfprintf(_gu_db_fp_, format, args); va_end(args); (void) fputc('\n', _gu_db_fp_); dbug_flush(state); errno = save_errno; } va_end(args); code_state_cleanup(state); } /* * FUNCTION * * _gu_db_dump_ dump a string until '\0' is found * * SYNOPSIS * * void _gu_db_dump_ (_line_,keyword,memory,length) * int _line_; current source line number * char *keyword; * char *memory; Memory to print * int length; Bytes to print * * DESCRIPTION * Dump N characters in a binary array. * Is used to examine corrputed memory or arrays. */ void _gu_db_dump_(uint _line_, const char *keyword, const char *memory, uint length) { int pos; char dbuff[90]; CODE_STATE *state; state = code_state(); if (_gu_db_keyword_((char *) keyword)) { if (!state->locked) pthread_mutex_lock(&_gu_db_mutex); DoPrefix(_line_); if (TRACING) { Indent(state->level + 1); pos = min(max(state->level - _gu_db_stack->sub_level, 0) * INDENT, 80); } else { fprintf(_gu_db_fp_, "%s: ", state->func); } sprintf(dbuff, "%s: Memory: %lx Bytes: (%d)\n", keyword, (ulong) memory, length); (void) fputs(dbuff, _gu_db_fp_); pos = 0; while (length-- > 0) { uint tmp = *((unsigned char *) memory++); if ((pos += 3) >= 80) { fputc('\n', _gu_db_fp_); pos = 3; } fputc(_gu_dig_vec[((tmp >> 4) & 15)], _gu_db_fp_); fputc(_gu_dig_vec[tmp & 15], _gu_db_fp_); fputc(' ', _gu_db_fp_); } (void) fputc('\n', _gu_db_fp_); dbug_flush(state); } code_state_cleanup(state); } /* * FUNCTION * * ListParse parse list of modifiers in debug control string * * SYNOPSIS * * static struct link *ListParse (ctlp) * char *ctlp; * * DESCRIPTION * * Given pointer to a comma separated list of strings in "cltp", * parses the list, building a list and returning a pointer to it. * The original comma separated list is destroyed in the process of * building the linked list, thus it had better be a duplicate * if it is important. * * Note that since each link is added at the head of the list, * the final list will be in "reverse order", which is not * significant for our usage here. * */ static struct link * ListParse(char *ctlp) { REGISTER char *start; REGISTER struct link *new_malloc; REGISTER struct link *head; head = NULL; while (*ctlp != EOS) { start = ctlp; while (*ctlp != EOS && *ctlp != ',') { ctlp++; } if (*ctlp == ',') { *ctlp++ = EOS; } new_malloc = (struct link *) DbugMalloc(sizeof(struct link)); new_malloc->str = StrDup(start); new_malloc->next_link = head; head = new_malloc; } return (head); } /* * FUNCTION * * InList test a given string for member of a given list * * SYNOPSIS * * static BOOLEAN InList (linkp, cp) * struct link *linkp; * char *cp; * * DESCRIPTION * * Tests the string pointed to by "cp" to determine if it is in * the list pointed to by "linkp". Linkp points to the first * link in the list. If linkp is NULL then the string is treated * as if it is in the list (I.E all strings are in the null list). * This may seem rather strange at first but leads to the desired * operation if no list is given. The net effect is that all * strings will be accepted when there is no list, and when there * is a list, only those strings in the list will be accepted. * */ static BOOLEAN InList(struct link *linkp, const char *cp) { REGISTER struct link *scan; REGISTER BOOLEAN result; if (linkp == NULL) { result = TRUE; } else { result = FALSE; for (scan = linkp; scan != NULL; scan = scan->next_link) { if (STREQ(scan->str, cp)) { result = TRUE; break; } } } return (result); } /* * FUNCTION * * PushState push current state onto stack and set up new one * * SYNOPSIS * * static VOID PushState () * * DESCRIPTION * * Pushes the current state on the state stack, and inits * a new state. The only parameter inherited from the previous * state is the function nesting level. This action can be * inhibited if desired, via the "r" flag. * * The state stack is a linked list of states, with the new * state added at the head. This allows the stack to grow * to the limits of memory if necessary. * */ static void PushState() { REGISTER struct state *new_malloc; new_malloc = (struct state *) DbugMalloc(sizeof(struct state)); new_malloc->flags = 0; new_malloc->delay = 0; new_malloc->maxdepth = MAXDEPTH; new_malloc->sub_level = 0; new_malloc->out_file = stderr; new_malloc->prof_file = (FILE *) 0; new_malloc->functions = NULL; new_malloc->p_functions = NULL; new_malloc->keywords = NULL; new_malloc->processes = NULL; new_malloc->next_state = _gu_db_stack; _gu_db_stack = new_malloc; } /* * FUNCTION * * DoTrace check to see if tracing is current enabled * * SYNOPSIS * * static BOOLEAN DoTrace (stack) * * DESCRIPTION * * Checks to see if tracing is enabled based on whether the * user has specified tracing, the maximum trace depth has * not yet been reached, the current function is selected, * and the current process is selected. Returns TRUE if * tracing is enabled, FALSE otherwise. * */ static BOOLEAN DoTrace(CODE_STATE * state) { register BOOLEAN trace = FALSE; if (TRACING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->functions, state->func) && InList(_gu_db_stack->processes, _gu_db_process_)) trace = TRUE; return (trace); } /* * FUNCTION * * DoProfile check to see if profiling is current enabled * * SYNOPSIS * * static BOOLEAN DoProfile () * * DESCRIPTION * * Checks to see if profiling is enabled based on whether the * user has specified profiling, the maximum trace depth has * not yet been reached, the current function is selected, * and the current process is selected. Returns TRUE if * profiling is enabled, FALSE otherwise. * */ #ifndef THREAD static BOOLEAN DoProfile() { REGISTER BOOLEAN profile; CODE_STATE *state; state = code_state(); profile = FALSE; if (PROFILING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->p_functions, state->func) && InList(_gu_db_stack->processes, _gu_db_process_)) profile = TRUE; return (profile); } #endif /* * FUNCTION * * _gu_db_keyword_ test keyword for member of keyword list * * SYNOPSIS * * BOOLEAN _gu_db_keyword_ (keyword) * char *keyword; * * DESCRIPTION * * Test a keyword to determine if it is in the currently active * keyword list. As with the function list, a keyword is accepted * if the list is null, otherwise it must match one of the list * members. When debugging is not on, no keywords are accepted. * After the maximum trace level is exceeded, no keywords are * accepted (this behavior subject to change). Additionally, * the current function and process must be accepted based on * their respective lists. * * Returns TRUE if keyword accepted, FALSE otherwise. * */ BOOLEAN _gu_db_keyword_(const char *keyword) { REGISTER BOOLEAN result; CODE_STATE *state; state = code_state(); result = FALSE; if (DEBUGGING && state->level <= _gu_db_stack->maxdepth && InList(_gu_db_stack->functions, state->func) && InList(_gu_db_stack->keywords, keyword) && InList(_gu_db_stack->processes, _gu_db_process_)) result = TRUE; return (result); } /* * FUNCTION * * Indent indent a line to the given indentation level * * SYNOPSIS * * static VOID Indent (indent) * int indent; * * DESCRIPTION * * Indent a line to the given level. Note that this is * a simple minded but portable implementation. * There are better ways. * * Also, the indent must be scaled by the compile time option * of character positions per nesting level. * */ static void Indent(int indent) { REGISTER int count; indent = max(indent - 1 - _gu_db_stack->sub_level, 0) * INDENT; for (count = 0; count < indent; count++) { if ((count % INDENT) == 0) fputc('|', _gu_db_fp_); else fputc(' ', _gu_db_fp_); } } /* * FUNCTION * * FreeList free all memory associated with a linked list * * SYNOPSIS * * static VOID FreeList (linkp) * struct link *linkp; * * DESCRIPTION * * Given pointer to the head of a linked list, frees all * memory held by the list and the members of the list. * */ static void FreeList(struct link *linkp) { REGISTER struct link *old; while (linkp != NULL) { old = linkp; linkp = linkp->next_link; if (old->str != NULL) { free(old->str); } free((char *) old); } } /* * FUNCTION * * StrDup make a duplicate of a string in new memory * * SYNOPSIS * * static char *StrDup (my_string) * char *string; * * DESCRIPTION * * Given pointer to a string, allocates sufficient memory to make * a duplicate copy, and copies the string to the newly allocated * memory. Failure to allocated sufficient memory is immediately * fatal. * */ static char * StrDup(const char *str) { register char *new_malloc; new_malloc = DbugMalloc((int) strlen(str) + 1); (void) strcpy(new_malloc, str); return (new_malloc); } /* * FUNCTION * * DoPrefix print debugger line prefix prior to indentation * * SYNOPSIS * * static VOID DoPrefix (_line_) * int _line_; * * DESCRIPTION * * Print prefix common to all debugger output lines, prior to * doing indentation if necessary. Print such information as * current process name, current source file name and line number, * and current function nesting depth. * */ static void DoPrefix(uint _line_) { CODE_STATE *state; state = code_state(); state->lineno++; if (_gu_db_stack->flags & PID_ON) { #ifdef THREAD (void) fprintf(_gu_db_fp_, "%5d:(thread %lu):", (int)getpid(), (unsigned long)pthread_self()); #else (void) fprintf(_gu_db_fp_, "%5d: ", (int) getpid()); #endif /* THREAD */ } if (_gu_db_stack->flags & NUMBER_ON) { (void) fprintf(_gu_db_fp_, "%5d: ", state->lineno); } if (_gu_db_stack->flags & PROCESS_ON) { (void) fprintf(_gu_db_fp_, "%s: ", _gu_db_process_); } if (_gu_db_stack->flags & FILE_ON) { (void) fprintf(_gu_db_fp_, "%14s: ", BaseName(state->file)); } if (_gu_db_stack->flags & LINE_ON) { (void) fprintf(_gu_db_fp_, "%5d: ", _line_); } if (_gu_db_stack->flags & DEPTH_ON) { (void) fprintf(_gu_db_fp_, "%4d: ", state->level); } } /* * FUNCTION * * GU_DBUGOpenFile open new output stream for debugger output * * SYNOPSIS * * static VOID GU_DBUGOpenFile (name) * char *name; * * DESCRIPTION * * Given name of a new file (or "-" for stdout) opens the file * and sets the output stream to the new file. * */ static void GU_DBUGOpenFile(const char *name, int append) { REGISTER FILE *fp; REGISTER BOOLEAN newfile; if (name != NULL) { strcpy(_gu_db_stack->name, name); if (strcmp(name, "-") == 0) { _gu_db_fp_ = stdout; _gu_db_stack->out_file = _gu_db_fp_; _gu_db_stack->flags |= FLUSH_ON_WRITE; } else { if (!Writable((char *) name)) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_, name); perror(""); fflush(stderr); } else { newfile = !EXISTS(name); if (!(fp = fopen(name, append ? "a+" : "w"))) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_, name); perror(""); fflush(stderr); } else { _gu_db_fp_ = fp; _gu_db_stack->out_file = fp; if (newfile) { ChangeOwner(name); } } } } } } /* * FUNCTION * * OpenProfile open new output stream for profiler output * * SYNOPSIS * * static FILE *OpenProfile (name) * char *name; * * DESCRIPTION * * Given name of a new file, opens the file * and sets the profiler output stream to the new file. * * It is currently unclear whether the prefered behavior is * to truncate any existing file, or simply append to it. * The latter behavior would be desirable for collecting * accumulated runtime history over a number of separate * runs. It might take some changes to the analyzer program * though, and the notes that Binayak sent with the profiling * diffs indicated that append was the normal mode, but this * does not appear to agree with the actual code. I haven't * investigated at this time [fnf; 24-Jul-87]. */ #ifndef THREAD static FILE * OpenProfile(const char *name) { REGISTER FILE *fp; REGISTER BOOLEAN newfile; fp = 0; if (!Writable(name)) { (void) fprintf(_gu_db_fp_, ERR_OPEN, _gu_db_process_, name); perror(""); dbug_flush(0); (void) Delay(_gu_db_stack->delay); } else { newfile = !EXISTS(name); if (!(fp = fopen(name, "w"))) { (void) fprintf(_gu_db_fp_, ERR_OPEN, _gu_db_process_, name); perror(""); dbug_flush(0); } else { _gu_db_pfp_ = fp; _gu_db_stack->prof_file = fp; if (newfile) { ChangeOwner(name); } } } return fp; } #endif /* * FUNCTION * * CloseFile close the debug output stream * * SYNOPSIS * * static VOID CloseFile (fp) * FILE *fp; * * DESCRIPTION * * Closes the debug output stream unless it is standard output * or standard error. * */ static void CloseFile(FILE * fp) { if (fp != stderr && fp != stdout) { if (fclose(fp) == EOF) { pthread_mutex_lock(&_gu_db_mutex); (void) fprintf(_gu_db_fp_, ERR_CLOSE, _gu_db_process_); perror(""); dbug_flush(0); } } } /* * FUNCTION * * DbugExit print error message and exit * * SYNOPSIS * * static VOID DbugExit (why) * char *why; * * DESCRIPTION * * Prints error message using current process name, the reason for * aborting (typically out of memory), and exits with status 1. * This should probably be changed to use a status code * defined in the user's debugger include file. * */ static void DbugExit(const char *why) { (void) fprintf(stderr, ERR_ABORT, _gu_db_process_, why); (void) fflush(stderr); exit(1); } /* * FUNCTION * * DbugMalloc allocate memory for debugger runtime support * * SYNOPSIS * * static long *DbugMalloc (size) * int size; * * DESCRIPTION * * Allocate more memory for debugger runtime support functions. * Failure to to allocate the requested number of bytes is * immediately fatal to the current process. This may be * rather unfriendly behavior. It might be better to simply * print a warning message, freeze the current debugger state, * and continue execution. * */ static char * DbugMalloc(int size) { register char *new_malloc; if (!(new_malloc = (char *) malloc((unsigned int) size))) DbugExit("out of memory"); return (new_malloc); } /* * As strtok but two separators in a row are changed to one * separator (to allow directory-paths in dos). */ static char * static_strtok(char *s1, char separator) { static char *end = NULL; register char *rtnval, *cpy; rtnval = NULL; if (s1 != NULL) end = s1; if (end != NULL && *end != EOS) { rtnval = cpy = end; do { if ((*cpy++ = *end++) == separator) { if (*end != separator) { cpy--; /* Point at separator */ break; } end++; /* Two separators in a row, skipp one */ } } while (*end != EOS); *cpy = EOS; /* Replace last separator */ } return (rtnval); } /* * FUNCTION * * BaseName strip leading pathname components from name * * SYNOPSIS * * static char *BaseName (pathname) * char *pathname; * * DESCRIPTION * * Given pointer to a complete pathname, locates the base file * name at the end of the pathname and returns a pointer to * it. * */ static char * BaseName(const char *pathname) { register const char *base; base = strrchr(pathname, FN_LIBCHAR); // if (base++ == NullS) - this doesn't make sense if (NULL == base || '\0' == base[1]) base = pathname; return ((char *) base); } /* * FUNCTION * * Writable test to see if a pathname is writable/creatable * * SYNOPSIS * * static BOOLEAN Writable (pathname) * char *pathname; * * DESCRIPTION * * Because the debugger might be linked in with a program that * runs with the set-uid-bit (suid) set, we have to be careful * about opening a user named file for debug output. This consists * of checking the file for write access with the real user id, * or checking the directory where the file will be created. * * Returns TRUE if the user would normally be allowed write or * create access to the named file. Returns FALSE otherwise. * */ #ifndef Writable static BOOLEAN Writable(char *pathname) { REGISTER BOOLEAN granted; REGISTER char *lastslash; granted = FALSE; if (EXISTS(pathname)) { if (WRITABLE(pathname)) { granted = TRUE; } } else { lastslash = strrchr(pathname, '/'); if (lastslash != NULL) { *lastslash = EOS; } else { pathname = "."; } if (WRITABLE(pathname)) { granted = TRUE; } if (lastslash != NULL) { *lastslash = '/'; } } return (granted); } #endif /* * FUNCTION * * ChangeOwner change owner to real user for suid programs * * SYNOPSIS * * static VOID ChangeOwner (pathname) * * DESCRIPTION * * For unix systems, change the owner of the newly created debug * file to the real owner. This is strictly for the benefit of * programs that are running with the set-user-id bit set. * * Note that at this point, the fact that pathname represents * a newly created file has already been established. If the * program that the debugger is linked to is not running with * the suid bit set, then this operation is redundant (but * harmless). * */ #ifndef ChangeOwner static void ChangeOwner(char *pathname) { if (chown(pathname, getuid(), getgid()) == -1) { (void) fprintf(stderr, ERR_CHOWN, _gu_db_process_, pathname); perror(""); (void) fflush(stderr); } } #endif /* * FUNCTION * * _gu_db_setjmp_ save debugger environment * * SYNOPSIS * * VOID _gu_db_setjmp_ () * * DESCRIPTION * * Invoked as part of the user's GU_DBUG_SETJMP macro to save * the debugger environment in parallel with saving the user's * environment. * */ #ifdef HAVE_LONGJMP void _gu_db_setjmp_() { CODE_STATE *state; state = code_state(); state->jmplevel = state->level; state->jmpfunc = state->func; state->jmpfile = state->file; } /* * FUNCTION * * _gu_db_longjmp_ restore previously saved debugger environment * * SYNOPSIS * * VOID _gu_db_longjmp_ () * * DESCRIPTION * * Invoked as part of the user's GU_DBUG_LONGJMP macro to restore * the debugger environment in parallel with restoring the user's * previously saved environment. * */ void _gu_db_longjmp_() { CODE_STATE *state; state = code_state(); state->level = state->jmplevel; if (state->jmpfunc) { state->func = state->jmpfunc; } if (state->jmpfile) { state->file = state->jmpfile; } } #endif /* * FUNCTION * * DelayArg convert D flag argument to appropriate value * * SYNOPSIS * * static int DelayArg (value) * int value; * * DESCRIPTION * * Converts delay argument, given in tenths of a second, to the * appropriate numerical argument used by the system to delay * that that many tenths of a second. For example, on the * amiga, there is a system call "Delay()" which takes an * argument in ticks (50 per second). On unix, the sleep * command takes seconds. Thus a value of "10", for one * second of delay, gets converted to 50 on the amiga, and 1 * on unix. Other systems will need to use a timing loop. * */ #ifdef AMIGA #define HZ (50) /* Probably in some header somewhere */ #endif static int DelayArg(int value) { uint delayarg = 0; #if (unix || xenix) delayarg = value / 10; /* Delay is in seconds for sleep () */ #endif #ifdef AMIGA delayarg = (HZ * value) / 10; /* Delay in ticks for Delay () */ #endif return (delayarg); } /* * A dummy delay stub for systems that do not support delays. * With a little work, this can be turned into a timing loop. */ #if ! defined(Delay) && ! defined(AMIGA) static int Delay(int ticks) { return ticks; } #endif /* * FUNCTION * * perror perror simulation for systems that don't have it * * SYNOPSIS * * static VOID perror (s) * char *s; * * DESCRIPTION * * Perror produces a message on the standard error stream which * provides more information about the library or system error * just encountered. The argument string s is printed, followed * by a ':', a blank, and then a message and a newline. * * An undocumented feature of the unix perror is that if the string * 's' is a null string (NOT a NULL pointer!), then the ':' and * blank are not printed. * * This version just complains about an "unknown system error". * */ /* flush dbug-stream, free mutex lock & wait delay */ /* This is because some systems (MSDOS!!) dosn't flush fileheader */ /* and dbug-file isn't readable after a system crash !! */ static void dbug_flush(CODE_STATE * state) { #ifndef THREAD if (_gu_db_stack->flags & FLUSH_ON_WRITE) #endif { #if defined(MSDOS) || defined(__WIN__) if (_gu_db_fp_ != stdout && _gu_db_fp_ != stderr) { if (!(freopen(_gu_db_stack->name, "a", _gu_db_fp_))) { (void) fprintf(stderr, ERR_OPEN, _gu_db_process_,_gu_db_stack->name); fflush(stderr); _gu_db_fp_ = stdout; _gu_db_stack->out_file = _gu_db_fp_; _gu_db_stack->flags |= FLUSH_ON_WRITE; } } else #endif { (void) fflush(_gu_db_fp_); if (_gu_db_stack->delay) (void) Delay(_gu_db_stack->delay); } } if (!state || !state->locked) pthread_mutex_unlock(&_gu_db_mutex); } /* dbug_flush */ void _gu_db_lock_file() { CODE_STATE *state; state = code_state(); pthread_mutex_lock(&_gu_db_mutex); state->locked = 1; } void _gu_db_unlock_file() { CODE_STATE *state; state = code_state(); state->locked = 0; pthread_mutex_unlock(&_gu_db_mutex); } /* * Here we need the definitions of the clock routine. Add your * own for whatever system that you have. */ #ifndef THREAD #if defined(HAVE_GETRUSAGE) #include #include /* extern int getrusage(int, struct rusage *); */ /* * Returns the user time in milliseconds used by this process so * far. */ static unsigned long Clock() { struct rusage ru; (void) getrusage(RUSAGE_SELF, &ru); return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000)); } #elif defined(MSDOS) || defined(__WIN__) || defined(OS2) static ulong Clock() { return clock() * (1000 / Cmy_pthread_mutex_lockS_PER_SEC); } #elif defined (amiga) struct DateStamp { /* Yes, this is a hack, but doing it right */ long ds_Days; /* is incredibly ugly without splitting this */ long ds_Minute; /* off into a separate file */ long ds_Tick; }; static int first_clock = TRUE; static struct DateStamp begin; static struct DateStamp elapsed; static unsigned long Clock() { register struct DateStamp *now; register unsigned long millisec = 0; extern VOID *AllocMem(); now = (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), 0L); if (now != NULL) { if (first_clock == TRUE) { first_clock = FALSE; (void) DateStamp(now); begin = *now; } (void) DateStamp(now); millisec = 24 * 3600 * (1000 / HZ) * (now->ds_Days - begin.ds_Days); millisec += 60 * (1000 / HZ) * (now->ds_Minute - begin.ds_Minute); millisec += (1000 / HZ) * (now->ds_Tick - begin.ds_Tick); (void) FreeMem(now, (long) sizeof(struct DateStamp)); } return (millisec); } #else static unsigned long Clock() { return (0); } #endif /* RUSAGE */ #endif /* THREADS */ #ifdef NO_VARARGS /* * Fake vfprintf for systems that don't support it. If this * doesn't work, you are probably SOL... */ static int vfprintf(stream, format, ap) FILE *stream; char *format; va_list ap; { int rtnval; ARGS_DCL; ARG0 = va_arg(ap, ARGS_TYPE); ARG1 = va_arg(ap, ARGS_TYPE); ARG2 = va_arg(ap, ARGS_TYPE); ARG3 = va_arg(ap, ARGS_TYPE); ARG4 = va_arg(ap, ARGS_TYPE); ARG5 = va_arg(ap, ARGS_TYPE); ARG6 = va_arg(ap, ARGS_TYPE); ARG7 = va_arg(ap, ARGS_TYPE); ARG8 = va_arg(ap, ARGS_TYPE); ARG9 = va_arg(ap, ARGS_TYPE); rtnval = fprintf(stream, format, ARGS_LIST); return (rtnval); } #endif /* NO_VARARGS */ char _gu_dig_vec[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; percona-galera-3-3.8-3390/galerautils/src/gu_dbug.h000066400000000000000000000145321244131713600216770ustar00rootroot00000000000000/****************************************************************************** * * * N O T I C E * * * * Copyright Abandoned, 1987, Fred Fish * * * * * * This previously copyrighted work has been placed into the public * * domain by the author and may be freely used for any purpose, * * private or commercial. * * * * Because of the number of inquiries I was receiving about the use * * of this product in commercially developed works I have decided to * * simply make it public domain to further its unrestricted use. I * * specifically would be most happy to see this material become a * * part of the standard Unix distributions by AT&T and the Berkeley * * Computer Science Research Group, and a standard part of the GNU * * system from the Free Software Foundation. * * * * I would appreciate it, as a courtesy, if this notice is left in * * all copies and derivative works. Thank you. * * * * The author makes no warranty of any kind with respect to this * * product and explicitly disclaims any implied warranties of mer- * * chantability or fitness for any particular purpose. * * * ****************************************************************************** */ /* * FILE * * dbug.c runtime support routines for dbug package * * SCCS * * @(#)dbug.c 1.25 7/25/89 * * DESCRIPTION * * These are the runtime support routines for the dbug package. * The dbug package has two main components; the user include * file containing various macro definitions, and the runtime * support routines which are called from the macro expansions. * * Externally visible functions in the runtime support module * use the naming convention pattern "_db_xx...xx_", thus * they are unlikely to collide with user defined function names. * * AUTHOR(S) * * Fred Fish (base code) * Enhanced Software Technologies, Tempe, AZ * asuvax!mcdphx!estinc!fnf * * Binayak Banerjee (profiling enhancements) * seismo!bpa!sjuvax!bbanerje * * Michael Widenius: * DBUG_DUMP - To dump a pice of memory. * PUSH_FLAG "O" - To be used instead of "o" if we don't * want flushing (for slow systems) * PUSH_FLAG "A" - as 'O', but we will append to the out file instead * of creating a new one. * Check of malloc on entry/exit (option "S") * * Alexey Yurchenko: * Renamed global symbols for use with galera project to avoid * collisions with other software (notably MySQL) * * $Id$ */ #ifndef _dbug_h #define _dbug_h #include #include typedef unsigned int uint; typedef unsigned long ulong; #define THREAD 1 #ifdef __cplusplus extern "C" { #endif extern char _gu_dig_vec[]; extern FILE* _gu_db_fp_; #define GU_DBUG_FILE _gu_db_fp_ #if defined(GU_DBUG_ON) && !defined(_lint) extern int _gu_db_on_; extern int _gu_no_db_; extern char* _gu_db_process_; extern int _gu_db_keyword_(const char* keyword); extern void _gu_db_setjmp_ (void); extern void _gu_db_longjmp_(void); extern void _gu_db_push_ (const char* control); extern void _gu_db_pop_ (void); extern void _gu_db_enter_ (const char* _func_, const char* _file_, uint _line_, const char** _sfunc_, const char** _sfile_, uint* _slevel_, char***); extern void _gu_db_return_ (uint _line_, const char** _sfunc_, const char** _sfile_, uint* _slevel_); extern void _gu_db_pargs_ (uint _line_, const char* keyword); extern void _gu_db_doprnt_ (const char* format, ...); extern void _gu_db_dump_ (uint _line_, const char *keyword, const char *memory, uint length); extern void _gu_db_lock_file (void); extern void _gu_db_unlock_file(void); #define GU_DBUG_ENTER(a) \ const char *_gu_db_func_, *_gu_db_file_; \ uint _gu_db_level_; \ char **_gu_db_framep_; \ _gu_db_enter_ (a, __FILE__, __LINE__, &_gu_db_func_, &_gu_db_file_, \ &_gu_db_level_, &_gu_db_framep_) #define GU_DBUG_LEAVE \ (_gu_db_return_ (__LINE__, &_gu_db_func_, &_gu_db_file_, \ &_gu_db_level_)) #define GU_DBUG_RETURN(a1) {GU_DBUG_LEAVE; return(a1);} #define GU_DBUG_VOID_RETURN {GU_DBUG_LEAVE; return; } #define GU_DBUG_EXECUTE(keyword,a1) \ {if (_gu_db_on_) {if (_gu_db_keyword_ (keyword)) { a1 }}} #define GU_DBUG_PRINT(keyword,arglist) \ {if (_gu_db_on_) {_gu_db_pargs_(__LINE__,keyword); \ _gu_db_doprnt_ arglist;}} #define GU_DBUG_PUSH(a1) _gu_db_push_ (a1) #define GU_DBUG_POP() _gu_db_pop_ () #define GU_DBUG_PROCESS(a1) (_gu_db_process_ = a1) #define GU_DBUG_SETJMP(a1) (_gu_db_setjmp_ (), setjmp (a1)) #define GU_DBUG_LONGJMP(a1,a2) (_gu_db_longjmp_ (), longjmp (a1, a2)) #define GU_DBUG_DUMP(keyword,a1,a2)\ {if (_gu_db_on_) {_gu_db_dump_(__LINE__,keyword,a1,a2);}} #define GU_DBUG_IN_USE (_gu_db_fp_ && _gu_db_fp_ != stderr) #define GU_DEBUGGER_OFF _no_gu_db_=1;_gu_db_on_=0; #define GU_DEBUGGER_ON _no_gu_db_=0 #define GU_DBUG_my_pthread_mutex_lock_FILE { _gu_db_lock_file(); } #define GU_DBUG_my_pthread_mutex_unlock_FILE { _gu_db_unlock_file(); } #define GU_DBUG_ASSERT(A) assert(A) #else /* No debugger */ #define GU_DBUG_ENTER(a1) #define GU_DBUG_RETURN(a1) return(a1) #define GU_DBUG_VOID_RETURN return #define GU_DBUG_EXECUTE(keyword,a1) {} #define GU_DBUG_PRINT(keyword,arglist) {} #define GU_DBUG_PUSH(a1) {} #define GU_DBUG_POP() {} #define GU_DBUG_PROCESS(a1) {} #define GU_DBUG_SETJMP setjmp #define GU_DBUG_LONGJMP longjmp #define GU_DBUG_DUMP(keyword,a1,a2) {} #define GU_DBUG_IN_USE 0 #define GU_DEBUGGER_OFF #define GU_DEBUGGER_ON #define GU_DBUG_my_pthread_mutex_lock_FILE #define GU_DBUG_my_pthread_mutex_unlock_FILE #define GU_DBUG_ASSERT(A) {} #endif #ifdef __cplusplus } #endif #endif percona-galera-3-3.8-3390/galerautils/src/gu_digest.hpp000066400000000000000000000102751244131713600225750ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file Message digest interface. * * $Id$ */ #ifndef GU_DIGEST_HPP #define GU_DIGEST_HPP #include "gu_hash.h" #include "gu_vec16.h" #include "gu_byteswap.hpp" #include "gu_serializable.hpp" #include "gu_macros.hpp" namespace gu { /* Just making MMH3 not derive from Digest reduced TrxHandle size from * 4560 bytes to 4256. 304 bytes of vtable pointers... */ class MMH3 { public: MMH3 () : ctx_() { gu_mmh128_init (&ctx_); } ~MMH3 () {} template static int digest (const void* const in, size_t size, T& out) { byte_t tmp[16]; gu_mmh128(in, size, tmp); int const s(std::min(sizeof(T), sizeof(tmp))); ::memcpy (&out, tmp, s); return s; } /* experimental */ template static T digest (const void* const in, size_t size) { switch (sizeof(T)) { case 1: return gu_mmh128_32(in, size); case 2: return gu_mmh128_32(in, size); case 4: return gu_mmh128_32(in, size); case 8: return gu_mmh128_64(in, size); } throw; } void append (const void* const buf, size_t const size) { gu_mmh128_append (&ctx_, buf, size); } template int gather (void* const buf) const { GU_COMPILE_ASSERT(size >= 16, wrong_buf_size); gather16 (buf); return 16; } int gather (void* const buf, size_t const size) const { byte_t tmp[16]; gather16(tmp); int const s(std::min(size, sizeof(tmp))); ::memcpy (buf, tmp, s); return s; } void gather16 (void* const buf) const { gu_mmh128_get (&ctx_, buf); } uint64_t gather8() const { return gu_mmh128_get64 (&ctx_); } uint32_t gather4() const { return gu_mmh128_get32 (&ctx_); } // a questionable feature template int operator() (T& out) const { return gather(&out); } private: gu_mmh128_ctx_t ctx_; }; /* class MMH3 */ template <> inline int MMH3::digest (const void* const in, size_t size, uint8_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint16_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint32_t& out) { out = gu_mmh128_32(in, size); return sizeof(out); } template <> inline int MMH3::digest (const void* const in, size_t size, uint64_t& out) { out = gu_mmh128_64(in, size); return sizeof(out); } template <> inline int MMH3::gather<8> (void* const out) const { *(static_cast(out)) = gather8(); return 8; } template <> inline int MMH3::gather<4> (void* const out) const { *(static_cast(out)) = gather4(); return 4; } typedef MMH3 Hash; class FastHash { public: template static int digest (const void* const in, size_t size, T& out) { byte_t tmp[16]; gu_fast_hash128(in, size, tmp); int const s(std::min(sizeof(T), sizeof(tmp))); ::memcpy (&out, tmp, s); return s; } /* experimental */ template static T digest (const void* const in, size_t size) { switch (sizeof(T)) { case 1: return gu_fast_hash32(in, size); case 2: return gu_fast_hash32(in, size); case 4: return gu_fast_hash32(in, size); case 8: return gu_fast_hash64(in, size); } throw; } }; /* FastHash */ template <> inline int FastHash::digest (const void* const in, size_t size, uint8_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint16_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint32_t& out) { out = gu_fast_hash32(in, size); return sizeof(out); } template <> inline int FastHash::digest (const void* const in, size_t size, uint64_t& out) { out = gu_fast_hash64(in, size); return sizeof(out); } } /* namespace gu */ #endif /* GU_DIGEST_HPP */ percona-galera-3-3.8-3390/galerautils/src/gu_errno.h000066400000000000000000000013131244131713600220740ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef GU_ERRNO_H #define GU_ERRNO_H #include #if defined(__APPLE__) || defined(__FreeBSD__) # define GU_ELAST ELAST #else /* must be high enough to not collide with system errnos but lower than 256 */ # define GU_ELAST 200 #endif #ifndef EBADFD # define EBADFD (GU_ELAST+1) #endif #ifndef EREMCHG # define EREMCHG (GU_ELAST+2) #endif #ifndef ENOTUNIQ # define ENOTUNIQ (GU_ELAST+3) #endif #ifndef ERESTART # define ERESTART (GU_ELAST+4) #endif #ifndef ENOTRECOVERABLE # define ENOTRECOVERABLE (GU_ELAST+5) #endif #ifndef ENODATA # define ENODATA (GU_ELAST+6) #endif #endif /* GU_STR_H */ percona-galera-3-3.8-3390/galerautils/src/gu_exception.cpp000066400000000000000000000007141244131713600233040ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #include #include "gu_utils.hpp" #include "gu_exception.hpp" namespace gu { void Exception::trace (const char* file, const char* func, int line) { msg.reserve (msg.length() + ::strlen(file) + ::strlen(func) + 15); msg += "\n\t at "; msg += file; msg += ':'; msg += func; msg += "():"; msg += to_string(line); } } percona-galera-3-3.8-3390/galerautils/src/gu_exception.hpp000066400000000000000000000023121244131713600233050ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GU_EXCEPTION__ #define __GU_EXCEPTION__ #include #include #include "gu_errno.h" namespace gu { /*! Some utility exceptions to indicate special conditions. */ class NotSet {}; class NotFound {}; class Exception: public std::exception { public: Exception (const std::string& msg_, int err_) : msg (msg_), err (err_) {} virtual ~Exception () throw() {} const char* what () const throw() { return msg.c_str(); } int get_errno () const { return err; } void trace (const char* file, const char* func, int line); private: std::string msg; const int err; }; } /* to mark a place where exception was caught */ #define GU_TRACE(_exception_) _exception_.trace(__FILE__, __FUNCTION__, __LINE__) #ifndef NDEBUG /* enabled together with assert() */ #define gu_trace(_expr_) \ try { _expr_; } catch (gu::Exception& e) { GU_TRACE(e); throw; } #else #define gu_trace(_expr_) _expr_ #endif // NDEBUG #endif // __GU_EXCEPTION__ percona-galera-3-3.8-3390/galerautils/src/gu_fdesc.cpp000066400000000000000000000125251244131713600223750ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ #include "gu_fdesc.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" extern "C" { #include "gu_limits.h" } #if !defined(_XOPEN_SOURCE) && !defined(__APPLE__) #define _XOPEN_SOURCE 600 #endif #include #include #include #ifndef O_CLOEXEC // CentOS < 6.0 does not have it #define O_CLOEXEC 0 #endif #ifndef O_NOATIME #define O_NOATIME 0 #endif namespace gu { static int const OPEN_FLAGS = O_RDWR | O_NOATIME | O_CLOEXEC; static int const CREATE_FLAGS = OPEN_FLAGS | O_CREAT /*| O_TRUNC*/; FileDescriptor::FileDescriptor (const std::string& fname, bool const sync) : name_(fname), fd_ (open (name_.c_str(), OPEN_FLAGS, S_IRUSR | S_IWUSR)), size_(lseek (fd_, 0, SEEK_END)), sync_(sync) { constructor_common(); } FileDescriptor::FileDescriptor (const std::string& fname, size_t const size, bool const allocate, bool const sync) : name_(fname), fd_ (open (fname.c_str(), CREATE_FLAGS, S_IRUSR | S_IWUSR)), size_(size), sync_(sync) { constructor_common(); off_t const current_size(lseek (fd_, 0, SEEK_END)); if (current_size < size_) { if (allocate) { // reserve space that hasn't been reserved prealloc (current_size); } else { write_byte (size_ - 1); // reserve size } } else if (current_size > size_) { log_debug << "Truncating '" << name_<< "' to " << size_<< " bytes."; if (ftruncate(fd_, size_)) { gu_throw_error(errno) << "Failed to truncate '" << name_ << "' to " << size_ << " bytes."; } } else { log_debug << "Reusing existing '" << name_ << "'."; } } void FileDescriptor::constructor_common() { if (fd_ < 0) { gu_throw_error(errno) << "Failed to open file '" + name_ + '\''; } #if !defined(__APPLE__) /* Darwin does not have posix_fadvise */ /* benefits are questionable int err(posix_fadvise (value, 0, size, POSIX_FADV_SEQUENTIAL)); if (err != 0) { log_warn << "Failed to set POSIX_FADV_SEQUENTIAL on " << name << ": " << err << " (" << strerror(err) << ")"; } */ #endif log_debug << "Opened file '" << name_ << "'"; log_debug << "File descriptor: " << fd_; } FileDescriptor::~FileDescriptor () { if (sync_ && fsync(fd_) != 0) { int const err(errno); log_error << "Failed to flush file '" << name_ << "': " << err << " (" << strerror(err) << '\''; } if (close(fd_) != 0) { int const err(errno); log_error << "Failed to close file '" << name_ << "': " << err << " (" << strerror(err) << '\''; } else { log_debug << "Closed file '" << name_ << "'"; } } void FileDescriptor::flush () const { log_debug << "Flushing file '" << name_ << "'"; if (fsync (fd_) < 0) { gu_throw_error(errno) << "fsync() failed on '" + name_ + '\''; } log_debug << "Flushed file '" << name_ << "'"; } bool FileDescriptor::write_byte (off_t offset) { byte_t const byte (0); if (lseek (fd_, offset, SEEK_SET) != offset) gu_throw_error(errno) << "lseek() failed on '" << name_ << '\''; if (write (fd_, &byte, sizeof(byte)) != sizeof(byte)) gu_throw_error(errno) << "write() failed on '" << name_ << '\''; return true; } /*! prealloc() fallback */ void FileDescriptor::write_file (off_t const start) { // last byte of the start page off_t offset = (start / GU_PAGE_SIZE + 1) * GU_PAGE_SIZE - 1; log_info << "Preallocating " << (size_ - start) << '/' << size_ << " bytes in '" << name_ << "'..."; while (offset < size_ && write_byte (offset)) { offset += GU_PAGE_SIZE; } if (offset >= size_ && write_byte (size_ - 1) && fsync (fd_) == 0) { return; } gu_throw_error (errno) << "File preallocation failed"; } void FileDescriptor::prealloc(off_t const start) { off_t const diff (size_ - start); log_debug << "Preallocating " << diff << '/' << size_ << " bytes in '" << name_ << "'..."; #if defined(__APPLE__) if (0 != fcntl (fd_, F_SETSIZE, size_) && 0 != ftruncate (fd_, size_)) #else if (0 != posix_fallocate (fd_, start, diff)) #endif { if (EINVAL == errno && start >= 0 && diff > 0) { // FS does not support the operation, try physical write write_file (start); } else { gu_throw_error (errno) << "File preallocation failed"; } } } } percona-galera-3-3.8-3390/galerautils/src/gu_fdesc.hpp000066400000000000000000000025421244131713600224000ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ #ifndef __GU_FDESC_HPP__ #define __GU_FDESC_HPP__ #include "gu_exception.hpp" #include "gu_types.hpp" // for off_t, byte_t #include namespace gu { class FileDescriptor { public: /* open existing file */ FileDescriptor (const std::string& fname, bool sync = true); /* (re)create file */ FileDescriptor (const std::string& fname, size_t length, bool allocate = true, bool sync = true); ~FileDescriptor (); int get() const { return fd_; } const std::string& name() const { return name_; } off_t size() const { return size_; } void flush() const; void unlink() const { ::unlink (name_.c_str()); } private: std::string const name_; int const fd_; off_t const size_; bool const sync_; // sync on close bool write_byte (off_t offset); void write_file (off_t start = 0); void prealloc (off_t start = 0); void constructor_common(); FileDescriptor (const FileDescriptor&); FileDescriptor& operator = (const FileDescriptor); }; } /* namespace gu */ #endif /* __GU_FDESC_HPP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_fifo.c000066400000000000000000000331251244131713600216730ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * Queue (FIFO) class implementation * * The driving idea behind this class is avoiding mallocs * at all costs on one hand, on the other - make it almost * as infinite as an ordinary linked list. FIFO properties * help achieving that. * * When needed this FIFO can be made very big, holding * millions or even billions of items while taking up * minimum space when there are few items in the queue. */ #define _DEFAULT_SOURCE #include #include #include #include "gu_assert.h" #include "gu_limits.h" #include "gu_mem.h" #include "gu_mutex.h" #include "gu_log.h" #include "gu_fifo.h" #include "galerautils.h" struct gu_fifo { ulong col_shift; ulong col_mask; ulong rows_num; ulong head; ulong tail; ulong row_size; ulong length; ulong length_mask; ulong alloc; long get_wait; long put_wait; long long q_len; long long q_len_samples; uint item_size; uint used; uint used_max; uint used_min; int get_err; bool closed; gu_mutex_t lock; gu_cond_t get_cond; gu_cond_t put_cond; void* rows[]; }; /* Don't make rows less than 1K */ #define GCS_FIFO_MIN_ROW_POWER 10 typedef unsigned long long ull; /* constructor */ gu_fifo_t *gu_fifo_create (size_t length, size_t item_size) { int row_pwr = GCS_FIFO_MIN_ROW_POWER; ull row_len = 1 << row_pwr; ull row_size = row_len * item_size; int array_pwr = 1; // need at least 2 rows for alteration ull array_len = 1 << array_pwr; ull array_size = array_len * sizeof(void*); gu_fifo_t *ret = NULL; if (length > 0 && item_size > 0) { /* find the best ratio of width and height: * the size of a row array must be equal to that of the row */ while (array_len * row_len < length) { if (array_size < row_size) { array_pwr++; array_len = 1 << array_pwr; array_size = array_len * sizeof(void*); } else { row_pwr++; row_len = 1 << row_pwr; row_size = row_len * item_size; } } ull alloc_size = array_size + sizeof (gu_fifo_t); if (alloc_size > (size_t)-1) { gu_error ("Initial FIFO size %llu exceeds size_t range %zu", alloc_size, (size_t)-1); return NULL; } ull max_size = array_len * row_size + alloc_size; if (max_size > (size_t)-1) { gu_error ("Maximum FIFO size %llu exceeds size_t range %zu", max_size, (size_t)-1); return NULL; } if (max_size > gu_avphys_bytes()) { gu_error ("Maximum FIFO size %llu exceeds available memory " "limit %llu", max_size, gu_avphys_bytes()); return NULL; } if ((array_len * row_len) > (ull)GU_LONG_MAX) { gu_error ("Resulting queue length %llu exceeds max allowed %ld", array_len * row_len, GU_LONG_MAX); return NULL; } gu_debug ("Creating FIFO buffer of %llu elements of size %llu, " "memory min used: %zu, max used: %zu", array_len * row_len, item_size, alloc_size, alloc_size + array_len*row_size); ret = gu_malloc (alloc_size); if (ret) { memset (ret, 0, alloc_size); ret->col_shift = row_pwr; ret->col_mask = row_len - 1; ret->rows_num = array_len; ret->length = row_len * array_len; ret->length_mask = ret->length - 1; ret->item_size = item_size; ret->row_size = row_size; ret->alloc = alloc_size; gu_mutex_init (&ret->lock, NULL); gu_cond_init (&ret->get_cond, NULL); gu_cond_init (&ret->put_cond, NULL); } else { gu_error ("Failed to allocate %zu bytes for FIFO", alloc_size); } } return ret; } // defined as macro for proper line reporting #define fifo_lock(q) \ if (gu_likely (0 == gu_mutex_lock (&q->lock))) {} \ else { \ gu_fatal ("Failed to lock queue"); \ abort(); \ } static inline int fifo_unlock (gu_fifo_t* q) { return -gu_mutex_unlock (&q->lock); } /* lock the queue */ void gu_fifo_lock (gu_fifo_t *q) { fifo_lock(q); } /* unlock the queue */ void gu_fifo_release (gu_fifo_t *q) { fifo_unlock(q); } static int fifo_flush (gu_fifo_t* q) { int ret = 0; /* if there are items in the queue, wait until they are all fetched */ while (q->used > 0 && 0 == ret) { /* will make getters to signal every time item is removed */ gu_warn ("Waiting for %lu items to be fetched.", q->used); q->put_wait++; ret = gu_cond_wait (&q->put_cond, &q->lock); } return ret; } static void fifo_close (gu_fifo_t* q) { if (!q->closed) { q->closed = true; /* force putters to quit */ /* don't overwrite existing get_err status, see gu_fifo_resume_gets() */ if (!q->get_err) q->get_err = -ENODATA; // signal all the idle waiting threads gu_cond_broadcast (&q->put_cond); q->put_wait = 0; gu_cond_broadcast (&q->get_cond); q->get_wait = 0; #if 0 (void) fifo_flush (q); #endif } } void gu_fifo_close (gu_fifo_t* q) { fifo_lock (q); fifo_close (q); fifo_unlock (q); } void gu_fifo_open (gu_fifo_t* q) { fifo_lock (q); q->closed = false; q->get_err = 0; fifo_unlock (q); } /* lock the queue and wait if it is empty */ static inline int fifo_lock_get (gu_fifo_t *q) { int ret = 0; fifo_lock(q); while (0 == ret && !(ret = q->get_err) && 0 == q->used) { q->get_wait++; ret = -gu_cond_wait (&q->get_cond, &q->lock); } return ret; } /* unlock the queue after getting item */ static inline int fifo_unlock_get (gu_fifo_t *q) { assert (q->used < q->length || 0 == q->length); if (q->put_wait > 0) { q->put_wait--; gu_cond_signal (&q->put_cond); } return fifo_unlock(q); } /* lock the queue and wait if it is full */ static inline int fifo_lock_put (gu_fifo_t *q) { int ret = 0; fifo_lock(q); while (0 == ret && q->used == q->length && !q->closed) { q->put_wait++; ret = -gu_cond_wait (&q->put_cond, &q->lock); } return ret; } /* unlock the queue after putting an item */ static inline int fifo_unlock_put (gu_fifo_t *q) { assert (q->used > 0); if (q->get_wait > 0) { q->get_wait--; gu_cond_signal (&q->get_cond); } return fifo_unlock(q); } #define FIFO_ROW(q,x) ((x) >> q->col_shift) /* div by row width */ #define FIFO_COL(q,x) ((x) & q->col_mask) /* remnant */ #define FIFO_PTR(q,x) \ ((uint8_t*)q->rows[FIFO_ROW(q, x)] + FIFO_COL(q, x) * q->item_size) /* Increment and roll over */ #define FIFO_INC(q,x) (((x) + 1) & q->length_mask) /*! If FIFO is not empty, returns pointer to the head item and locks FIFO, * otherwise blocks. Or returns NULL if FIFO is closed. */ void* gu_fifo_get_head (gu_fifo_t* q, int* err) { *err = fifo_lock_get (q); if (gu_likely(-ECANCELED != *err && q->used)) { return (FIFO_PTR(q, q->head)); } else { assert (q->get_err); fifo_unlock (q); return NULL; } } /*! Advances FIFO head and unlocks FIFO. */ void gu_fifo_pop_head (gu_fifo_t* q) { if (FIFO_COL(q, q->head) == q->col_mask) { /* removing last unit from the row */ ulong row = FIFO_ROW (q, q->head); assert (q->rows[row] != NULL); gu_free (q->rows[row]); q->rows[row] = NULL; q->alloc -= q->row_size; } q->head = FIFO_INC(q, q->head); q->used--; if (gu_unlikely(q->used < q->used_min)) { q->used_min = q->used; } if (fifo_unlock_get(q)) { gu_fatal ("Faled to unlock queue to get item."); abort(); } } /*! If FIFO is not full, returns pointer to the tail item and locks FIFO, * otherwise blocks. Or returns NULL if FIFO is closed. */ void* gu_fifo_get_tail (gu_fifo_t* q) { fifo_lock_put (q); if (gu_likely(!q->closed)) { // stop adding items when closed ulong row = FIFO_ROW(q, q->tail); assert (q->used < q->length); // check if row is allocated and allocate if not. if (NULL == q->rows[row] && NULL == (q->alloc += q->row_size, q->rows[row] = gu_malloc(q->row_size))) { q->alloc -= q->row_size; } else { return ((uint8_t*)q->rows[row] + FIFO_COL(q, q->tail) * q->item_size); } #if 0 // for debugging if (NULL == q->rows[row]) { gu_debug ("Allocating row %lu of queue %p, rows %p", row, q, q->rows); if (NULL == (q->rows[row] = gu_malloc(q->row_size))) { gu_debug ("Allocating row %lu failed", row); fifo_unlock (q); return NULL; } q->alloc += q->row_size; } return (q->rows[row] + FIFO_COL(q, q->tail) * q->item_size); #endif } fifo_unlock (q); return NULL; } /*! Advances FIFO tail and unlocks FIFO. */ void gu_fifo_push_tail (gu_fifo_t* q) { q->tail = FIFO_INC(q, q->tail); q->q_len += q->used; q->used++; if (gu_unlikely(q->used > q->used_max)) { q->used_max = q->used; } q->q_len_samples++; if (fifo_unlock_put(q)) { gu_fatal ("Faled to unlock queue to put item."); abort(); } } /*! returns how many items are in the queue */ long gu_fifo_length (gu_fifo_t* q) { return q->used; } /*! returns how many items were in the queue per push_tail() */ void gu_fifo_stats_get (gu_fifo_t* q, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg) { fifo_lock (q); *q_len = q->used; *q_len_max = q->used_max; *q_len_min = q->used_min; long long len = q->q_len; long long samples = q->q_len_samples; fifo_unlock (q); if (len >= 0 && samples >= 0) { if (samples > 0) { *q_len_avg = ((double)len) / samples; } else { assert (0 == len); *q_len_avg = 0.0; } } else { *q_len_avg = -1.0; } } void gu_fifo_stats_flush(gu_fifo_t* q) { fifo_lock (q); q->used_max = q->used; q->used_min = q->used; q->q_len = 0; q->q_len_samples = 0; fifo_unlock (q); } /* destructor - would block until all members are dequeued */ void gu_fifo_destroy (gu_fifo_t *queue) { fifo_lock (queue); { if (!queue->closed) fifo_close(queue); fifo_flush (queue); } fifo_unlock (queue); assert (queue->tail == queue->head); while (gu_cond_destroy (&queue->put_cond)) { fifo_lock (queue); gu_cond_signal (&queue->put_cond); fifo_unlock (queue); /* when thread sees that ret->used == 0, it must terminate */ } while (gu_cond_destroy (&queue->get_cond)) { fifo_lock (queue); gu_cond_signal (&queue->get_cond); fifo_unlock (queue); /* when thread sees that ret->used == 0, it must terminate */ } while (gu_mutex_destroy (&queue->lock)) continue; /* only one row migth be left */ { ulong row = FIFO_ROW(queue, queue->tail); if (queue->rows[row]) { assert (FIFO_COL(queue, queue->tail) != 0); gu_free (queue->rows[row]); queue->alloc -= queue->row_size; } else { assert (FIFO_COL(queue, queue->tail) == 0); } gu_free (queue); } } char *gu_fifo_print (gu_fifo_t *queue) { size_t tmp_len = 4096; char tmp[tmp_len]; char *ret; snprintf (tmp, tmp_len, "Queue (%p):\n" "\tlength = %lu\n" "\trows = %lu\n" "\tcolumns = %lu\n" "\tused = %u (%zu bytes)\n" "\talloctd = %lu bytes\n" "\thead = %lu, tail = %lu\n" "\tavg.len = %f" //", next = %lu" , (void*)queue, queue->length, queue->rows_num, queue->col_mask + 1, queue->used, (size_t)queue->used * queue->item_size, queue->alloc, queue->head, queue->tail, queue->q_len_samples > 0 ? ((double)queue->q_len)/queue->q_len_samples : 0.0 //, queue->next ); ret = strdup (tmp); return ret; } int gu_fifo_cancel_gets (gu_fifo_t* q) { if (q->get_err && -ENODATA != q->get_err) { gu_error ("Attempt to cancel FIFO gets in state: %d (%s)", q->get_err, strerror(-q->get_err)); return -EBADFD; } assert (!q->get_err || q->closed); q->get_err = -ECANCELED; /* force getters to quit with specific error */ if (q->get_wait) { gu_cond_broadcast (&q->get_cond); q->get_wait = 0; } return 0; } int gu_fifo_resume_gets (gu_fifo_t* q) { int ret = -1; fifo_lock(q); if (-ECANCELED == q->get_err) { q->get_err = q->closed ? -ENODATA : 0; ret = 0; } else { gu_error ("Attempt to resume FIFO gets in state: %d (%s)", q->get_err, strerror(-q->get_err)); ret = -EBADFD; } fifo_unlock(q); return ret; } percona-galera-3-3.8-3390/galerautils/src/gu_fifo.h000066400000000000000000000047331244131713600217030ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * Queue (FIFO) class definition * * The driving idea behind this class is avoiding malloc()'s * at all costs on one hand, on the other - make it almost * as infinite as an ordinary linked list. FIFO properties * help to achieve that. * * When needed this FIFO can be made very big, holding * millions or even billions of items while taking up * minimum space when there are few items in the queue. * malloc()'s do happen, but once per thousand of pushes and * allocate multiples of pages, thus reducing memory fragmentation. */ #ifndef _gu_fifo_h_ #define _gu_fifo_h_ #include typedef struct gu_fifo gu_fifo_t; /*! constructor */ extern gu_fifo_t* gu_fifo_create (size_t length, size_t unit); /*! puts FIFO into closed state, waking up waiting threads */ extern void gu_fifo_close (gu_fifo_t *queue); /*! (re)opens FIFO */ extern void gu_fifo_open (gu_fifo_t *queue); /*! destructor - would block until all members are dequeued */ extern void gu_fifo_destroy (gu_fifo_t *queue); /*! for logging purposes */ extern char* gu_fifo_print (gu_fifo_t *queue); /*! Lock FIFO */ extern void gu_fifo_lock (gu_fifo_t *q); /*! Release FIFO */ extern void gu_fifo_release (gu_fifo_t *q); /*! Lock FIFO and get pointer to head item * @param err contains error code if retval is NULL (otherwise - undefined): -ENODATA - queue closed, -ECANCELED - gets were canceled on the queue * @retval pointer to head item or NULL if error occured */ extern void* gu_fifo_get_head (gu_fifo_t* q, int* err); /*! Advance FIFO head pointer and release FIFO. */ extern void gu_fifo_pop_head (gu_fifo_t* q); /*! Lock FIFO and get pointer to tail item */ extern void* gu_fifo_get_tail (gu_fifo_t* q); /*! Advance FIFO tail pointer and release FIFO. */ extern void gu_fifo_push_tail (gu_fifo_t* q); /*! Return how many items are in the queue (unprotected) */ extern long gu_fifo_length (gu_fifo_t* q); /*! Return how many items were in the queue on average per push_tail() */ extern void gu_fifo_stats_get (gu_fifo_t* q, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg); /*! Flush stats counters */ extern void gu_fifo_stats_flush(gu_fifo_t* q); /*! Cancel getters (must be called while holding a FIFO lock) */ extern int gu_fifo_cancel_gets (gu_fifo_t* q); /*! Resume get operations */ extern int gu_fifo_resume_gets (gu_fifo_t* q); #endif // _gu_fifo_h_ percona-galera-3-3.8-3390/galerautils/src/gu_fnv.h000066400000000000000000000131161244131713600215440ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /*! * @file * * This header file defines FNV hash functions for 3 hash sizes: * 4, 8 and 16 bytes. * * Be wary of bitshift multiplication "optimization" (FNV_BITSHIFT_OPTIMIZATION): * FNV authors used to claim marginal speedup when using it, however on core2 * CPU it has shown no speedup for fnv32a and more than 2x slowdown for fnv64a * and fnv128a. Disabled by default. * * FNV vs. FNVa: FNVa has a better distribution: multiplication happens after * XOR and hence propagates XOR effect to all bytes of the hash. * Hence by default functions perform FNVa. GU_FNV_NORMAL macro * is needed for unit tests. * * gu_fnv*_internal() functions are endian-unsafe, their output should be * converted to little-endian format if it is to be exported to other machines. */ #ifndef _gu_fnv_h_ #define _gu_fnv_h_ #include "gu_int128.h" #include #include #include #include // ssize_t #include #define GU_FNV32_PRIME 16777619UL #define GU_FNV32_SEED 2166136261UL #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV32_MUL(_x) _x *= GU_FNV32_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV32_MUL(_x) \ _x += (_x << 1) + (_x << 4) + (_x << 7) + (_x << 8) + (_x << 24) #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #if !defined(GU_FNV_NORMAL) # define GU_FNV32_ITERATION(_s,_b) _s ^= _b; GU_FNV32_MUL(_s); #else # define GU_FNV32_ITERATION(_s,_b) GU_FNV32_MUL(_s); _s ^= _b; #endif static GU_FORCE_INLINE void gu_fnv32a_internal (const void* buf, ssize_t const len, uint32_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; while (bp + 2 <= be) { GU_FNV32_ITERATION(*seed,*bp++); GU_FNV32_ITERATION(*seed,*bp++); } if (bp < be) { GU_FNV32_ITERATION(*seed,*bp++); } assert(be == bp); } #define GU_FNV64_PRIME 1099511628211ULL #define GU_FNV64_SEED 14695981039346656037ULL #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV64_MUL(_x) _x *= GU_FNV64_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV64_MUL(_x) \ _x +=(_x << 1) + (_x << 4) + (_x << 5) + (_x << 7) + (_x << 8) + (_x << 40); #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #if !defined(GU_FNV_NORMAL) # define GU_FNV64_ITERATION(_s,_b) _s ^= _b; GU_FNV64_MUL(_s); #else # define GU_FNV64_ITERATION(_s,_b) GU_FNV64_MUL(_s); _s ^= _b; #endif static GU_FORCE_INLINE void gu_fnv64a_internal (const void* buf, ssize_t const len, uint64_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; while (bp + 2 <= be) { GU_FNV64_ITERATION(*seed,*bp++); GU_FNV64_ITERATION(*seed,*bp++); } if (bp < be) { GU_FNV64_ITERATION(*seed,*bp++); } assert(be == bp); } static gu_uint128_t const GU_SET128(GU_FNV128_PRIME, 0x0000000001000000ULL, 0x000000000000013BULL); static gu_uint128_t const GU_SET128(GU_FNV128_SEED, 0x6C62272E07BB0142ULL, 0x62B821756295C58DULL); #if defined(__SIZEOF_INT128__) #define GU_FNV128_XOR(_s,_b) _s ^= _b #if !defined(GU_FNVBITSHIFT_OPTIMIZATION) # define GU_FNV128_MUL(_x) _x *= GU_FNV128_PRIME #else /* GU_FNVBITSHIFT_OPTIMIZATION */ # define GU_FNV128_MUL(_x) \ _x +=(_x << 1) + (_x << 3) + (_x << 4) + (_x << 5) + (_x << 8) + (_x << 88); #endif /* GU_FNVBITSHIFT_OPTIMIZATION */ #else /* ! __SIZEOF_INT128__ */ #define GU_FNV128_XOR(_s,_b) (_s).u32[GU_32LO] ^= _b #if defined(GU_FNV128_FULL_MULTIPLICATION) # define GU_FNV128_MUL(_x) GU_MUL128_INPLACE(_x, GU_FNV128_PRIME) #else /* no FULL_MULTIPLICATION */ # define GU_FNV128_MUL(_x) { \ uint32_t carry = \ (((_x).u64[GU_64LO] & 0x00000000ffffffffULL) * 0x013b) >> 32; \ carry = (((_x).u64[GU_64LO] >> 32) * 0x013b + carry) >> 32; \ (_x).u64[GU_64HI] *= 0x013b; \ (_x).u64[GU_64HI] += ((_x).u64[GU_64LO] << 24) + carry; \ (_x).u64[GU_64LO] *= 0x013b; \ } #endif /* FULL_MULTIPLICATION */ #endif /* ! __SIZEOF_INT128__ */ #if !defined(GU_FNV_NORMAL) # define GU_FNV128_ITERATION(_s,_b) GU_FNV128_XOR(_s,_b); GU_FNV128_MUL(_s); #else # define GU_FNV128_ITERATION(_s,_b) GU_FNV128_MUL(_s); GU_FNV128_XOR(_s,_b); #endif inline static void gu_fnv128a_internal (const void* buf, ssize_t const len, gu_uint128_t* seed) { const uint8_t* bp = (const uint8_t*)buf; const uint8_t* const be = bp + len; /* this manual loop unrolling seems to be essential */ while (bp + 8 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp + 4 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp + 2 <= be) { GU_FNV128_ITERATION(*seed, *bp++); GU_FNV128_ITERATION(*seed, *bp++); } if (bp < be) { GU_FNV128_ITERATION(*seed, *bp++); } assert(be == bp); } #endif /* _gu_fnv_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_fnv_bench.c000066400000000000000000000140311244131713600226730ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /*! * @file Benchmark for different hash implementations: * fnv32, fnv64, fnv128, mmh3, md5 from libssl and md5 from crypto++ * * To compile on Ubuntu: g++ -DHAVE_ENDIAN_H -DHAVE_BYTESWAP_H -DGALERA_LOG_H_ENABLE_CXX \ -O3 -march=native -msse4 -Wall -Werror -I../.. gu_fnv_bench.c gu_crc32c.c \ gu_mmh3.c gu_spooky.c gu_log.c ../../www.evanjones.ca/crc32c.c \ -lssl -lcrypto -lcrypto++ -o gu_fnv_bench * * on CentOS some play with -lcrypto++ may be needed (also see includes below) * * To run: * gu_fnv_bench */ #include "gu_crc32c.h" #include "gu_fnv.h" #include "gu_mmh3.h" #include "gu_spooky.h" #include "gu_hash.h" #include #include #include #include #include #define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 #include //#include enum algs { CRC32sw, CRC32hw, FNV32, FNV64, FNV128, MMH32, MMH128, SPOOKYS, SPOOKY, MD5SSL, MD5CPP, FAST128, TABLE }; static int timer (const void* const buf, ssize_t const len, long long const loops, enum algs const type) { double begin, end; struct timeval tv; const char* alg = "undefined"; size_t volatile h; // this variable serves to prevent compiler from // optimizing out the calls gettimeofday (&tv, NULL); begin = (double)tv.tv_sec + 1.e-6 * tv.tv_usec; long long i; #ifdef EXTERNAL_LOOP #define EXTERNAL_LOOP_BEGIN for (i = 0; i < loops; i++) { #define EXTERNAL_LOOP_END } #define INTERNAL_LOOP_BEGIN #define INTERNAL_LOOP_END #else #define EXTERNAL_LOOP_BEGIN #define EXTERNAL_LOOP_END #define INTERNAL_LOOP_BEGIN for (i = 0; i < loops; i++) { #define INTERNAL_LOOP_END } #endif EXTERNAL_LOOP_BEGIN switch (type) { case CRC32sw: case CRC32hw: { if (CRC32sw == type) alg = "crc32sw"; else alg = "crc32hw"; INTERNAL_LOOP_BEGIN // gu_crc32c_t crc = GU_CRC32C_INIT; h = gu_crc32c (buf, len); // h = hash; INTERNAL_LOOP_END break; } case FNV32: { alg = "fnv32a"; INTERNAL_LOOP_BEGIN uint32_t hash = GU_FNV32_SEED; gu_fnv32a_internal (buf, len, &hash); h = hash; INTERNAL_LOOP_END break; } case FNV64: { alg = "fnv64a"; INTERNAL_LOOP_BEGIN uint64_t hash = GU_FNV64_SEED;; gu_fnv64a_internal (buf, len, &hash); h = hash; INTERNAL_LOOP_END break; } case FNV128: { alg = "fnv128"; INTERNAL_LOOP_BEGIN gu_uint128_t hash = GU_FNV128_SEED; gu_fnv128a_internal (buf, len, &hash); #if defined(__SIZEOF_INT128__) h = hash; #else h = hash.u32[GU_32LO]; #endif INTERNAL_LOOP_END break; } case MMH32: { alg = "mmh32"; INTERNAL_LOOP_BEGIN h = gu_mmh32 (buf, len); INTERNAL_LOOP_END break; } case MMH128: { alg = "mmh128"; INTERNAL_LOOP_BEGIN gu_uint128_t hash; gu_mmh128 (buf, len, &hash); #if defined(__SIZEOF_INT128__) h = hash; #else h = hash.u32[GU_32LO]; #endif INTERNAL_LOOP_END break; } case SPOOKYS: { alg = "SpookyS"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_spooky_short (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case SPOOKY: { alg = "Spooky"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_spooky_inline (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case MD5SSL: { alg = "md5ssl"; INTERNAL_LOOP_BEGIN unsigned char md[MD5_DIGEST_LENGTH]; MD5 ((const unsigned char*)buf, len, md); INTERNAL_LOOP_END break; } case MD5CPP: { alg = "md5cpp"; INTERNAL_LOOP_BEGIN unsigned char md[16]; CryptoPP::Weak::MD5().CalculateDigest(md, (const byte*)buf, len); INTERNAL_LOOP_END break; } case FAST128: { alg = "fast128"; INTERNAL_LOOP_BEGIN uint64_t hash[2]; gu_fast_hash128 (buf, len, hash); h = hash[0]; INTERNAL_LOOP_END break; } case TABLE: { alg = "table"; INTERNAL_LOOP_BEGIN h = gu_table_hash (buf, len); INTERNAL_LOOP_END break; } } EXTERNAL_LOOP_END gettimeofday (&tv, NULL); end = (double)tv.tv_sec + 1.e-6 * tv.tv_usec; end -= begin; return printf ("%s: %lld loops, %6.3f seconds, %8.3f Mb/sec%s\n", alg, loops, end, (double)(loops * len)/end/1024/1024, h ? "" : " "); } int main (int argc, char* argv[]) { ssize_t buf_size = (1<<20); // 1Mb long long loops = 10000; if (argc > 1) buf_size = strtoll (argv[1], NULL, 10); if (argc > 2) loops = strtoll (argv[2], NULL, 10); /* initialization of data buffer */ ssize_t buf_size_int = buf_size / sizeof(int) + 1; int* buf = (int*) malloc (buf_size_int * sizeof(int)); if (!buf) return ENOMEM; while (buf_size_int) buf[--buf_size_int] = rand(); timer (buf, buf_size, loops, CRC32sw); CRC32CFunctionPtr const old = gu_crc32c_func; gu_crc32c_configure(); if (old != gu_crc32c_func) timer(buf, buf_size, loops, CRC32hw); timer (buf, buf_size, loops, FNV32); timer (buf, buf_size, loops, FNV64); timer (buf, buf_size, loops, FNV128); timer (buf, buf_size, loops, MMH32); timer (buf, buf_size, loops, MMH128); // timer (buf, buf_size, loops, SPOOKYS); timer (buf, buf_size, loops, SPOOKY); // timer (buf, buf_size, loops, MD5SSL); // timer (buf, buf_size, loops, MD5CPP); timer (buf, buf_size, loops, FAST128); timer (buf, buf_size, loops, TABLE); return 0; } percona-galera-3-3.8-3390/galerautils/src/gu_hash.h000066400000000000000000000100731244131713600216750ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file Defines 3 families of standard Galera hash methods * * 1) gu_hash - a general use universal hash: 128, 64 and 32-bit variants. * * 2) gu_fast_hash - optimized for 64-bit Intel CPUs, limited to whole message * only, also comes in 128, 64 and 32-bit flavors. * 3) gu_table_hash - possibly even faster, platform-optimized, globally * inconsistent hash functions to be used only in local hash * tables. Only size_t variants defined. * * 128-bit result is returned through void* parameter as a byte array in * canonical order. * 64/32-bit results are returned as uint64_t/uint32_t integers and thus in host * byte order (require conversion to network/Galera byte order for serialization). * * $Id$ */ #ifndef _gu_hash_h_ #define _gu_hash_h_ #ifdef __cplusplus extern "C" { #endif #include "gu_fnv.h" #include "gu_mmh3.h" #include "gu_spooky.h" /* * General purpose globally consistent _fast_ hash, if in doubt use that. */ /* This is to hash multipart message */ #define gu_hash_t gu_mmh128_ctx_t #define gu_hash_init(_hash) gu_mmh128_init(_hash) #define gu_hash_append(_hash, _msg, _len) gu_mmh128_append(_hash, _msg, _len) #define gu_hash_get128(_hash, _res) gu_mmh128_get(_hash, _res) #define gu_hash_get64(_hash) gu_mmh128_get64(_hash) #define gu_hash_get32(_hash) gu_mmh128_get32(_hash) /* This is to hash a whole message in one go */ #define gu_hash128(_msg, _len, _res) gu_mmh128(_msg, _len, _res) #define gu_hash64(_msg, _len) gu_mmh128_64(_msg, _len) #define gu_hash32(_msg, _len) gu_mmh128_32(_msg, _len) /* * Hash optimized for speed, can't do multipart messages, but should still * be usable as global identifier */ #define GU_SHORT64_LIMIT 16 #define GU_MEDIUM64_LIMIT 512 static GU_INLINE void gu_fast_hash128 (const void* const msg, size_t const len, void* const res) { if (len < GU_MEDIUM64_LIMIT) { gu_mmh128 (msg, len, res); } else { gu_spooky128 (msg, len, res); } } static GU_FORCE_INLINE uint64_t gu_fast_hash64_short (const void* const msg, size_t const len) { uint64_t res = GU_FNV64_SEED; gu_fnv64a_internal (msg, len, &res); /* mix to improve avalanche effect */ res *= GU_ROTL64(res, 56); return res ^ GU_ROTL64(res, 43); } #define gu_fast_hash64_medium gu_mmh128_64 #define gu_fast_hash64_long gu_spooky64 static GU_INLINE uint64_t gu_fast_hash64 (const void* const msg, size_t const len) { if (len < GU_SHORT64_LIMIT) { return gu_fast_hash64_short (msg, len); } else if (len < GU_MEDIUM64_LIMIT) { return gu_fast_hash64_medium (msg, len); } else { return gu_fast_hash64_long (msg, len); } } #define gu_fast_hash32_short gu_mmh32 #define gu_fast_hash32_medium gu_mmh128_32 #define gu_fast_hash32_long gu_spooky32 #define GU_SHORT32_LIMIT 32 #define GU_MEDIUM32_LIMIT 512 static GU_INLINE uint32_t gu_fast_hash32 (const void* const msg, size_t const len) { if (len < GU_SHORT32_LIMIT) { return gu_fast_hash32_short (msg, len); } else if (len < GU_MEDIUM32_LIMIT) { return gu_fast_hash32_medium (msg, len); } else { return gu_fast_hash32_long (msg, len); } } /* * Platform-optimized hashes only for local hash tables, don't produce globally * consistent results. No 128-bit version for obvious reasons. * * Resulting gu_table_hash() will be the fastest hash function returning size_t */ #if GU_WORDSIZE == 64 #define gu_table_hash gu_fast_hash64 /* size_t is normally 64-bit here */ #elif GU_WORDSIZE == 32 /* on 32-bit platform MurmurHash32 is only insignificantly slower than FNV32a * on messages < 10 bytes but produces far better hash. */ #define gu_table_hash gu_mmh32 /* size_t is normally 32-bit here */ #else /* GU_WORDSIZE neither 64 nor 32 bits */ # error Unsupported wordsize! #endif #ifdef __cplusplus } #endif #endif /* _gu_hash_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_hexdump.c000066400000000000000000000036231244131713600224220ustar00rootroot00000000000000// Copyright (C) 2012-2013 Codership Oy /** * @file Functions to dump buffer contents in a readable form * * $Id$ */ #include "gu_hexdump.h" #include "gu_macros.h" #define GU_ASCII_0 0x30 #define GU_ASCII_10 0x3a #define GU_ASCII_A 0x41 #define GU_ASCII_a 0x61 #define GU_ASCII_A_10 (GU_ASCII_A - GU_ASCII_10) #define GU_ASCII_a_10 (GU_ASCII_a - GU_ASCII_10) static GU_FORCE_INLINE int _hex_code (uint8_t const x) { return (x + GU_ASCII_0 + (x > 9)*GU_ASCII_a_10); } static GU_FORCE_INLINE void _write_byte_binary (char* const str, uint8_t const byte) { str[0] = _hex_code(byte >> 4); str[1] = _hex_code(byte & 0x0f); } static GU_FORCE_INLINE void _write_byte_alpha (char* const str, uint8_t const byte) { str[0] = (char)byte; str[1] = '.'; } #define GU_ASCII_ALPHA_START 0x20U /* ' ' */ #define GU_ASCII_ALPHA_END 0x7eU /* '~' */ #define GU_ASCII_ALPHA_INTERVAL (GU_ASCII_ALPHA_END - GU_ASCII_ALPHA_START) static GU_FORCE_INLINE bool _byte_is_alpha (uint8_t const byte) { return (byte - GU_ASCII_ALPHA_START <= GU_ASCII_ALPHA_INTERVAL); } /*! Dumps contents of the binary buffer into a readable form */ void gu_hexdump(const void* buf, ssize_t const buf_size, char* str, ssize_t str_size, bool alpha) { const uint8_t* b = (uint8_t*)buf; ssize_t i; str_size--; /* reserve a space for \0 */ for (i = 0; i < buf_size && str_size > 1;) { if (alpha && _byte_is_alpha (b[i])) _write_byte_alpha (str, b[i]); else _write_byte_binary (str, b[i]); str += 2; str_size -= 2; i++; if (0 == (i % 4) && str_size > 0 && i < buf_size) { /* insert space after every 4 bytes and newline after every 32 */ str[0] = (i % GU_HEXDUMP_BYTES_PER_LINE) ? ' ' : '\n'; str_size--; str++; } } str[0] = '\0'; } percona-galera-3-3.8-3390/galerautils/src/gu_hexdump.cpp000066400000000000000000000015211244131713600227550ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file operator << for hexdump - definiton * * $Id$ */ #include "gu_hexdump.hpp" #include "gu_hexdump.h" #include "gu_logger.hpp" namespace gu { static size_t const hexdump_bytes_per_go(GU_HEXDUMP_BYTES_PER_LINE * 2); static size_t const hexdump_reserve_string( hexdump_bytes_per_go*2 /* chars */ + hexdump_bytes_per_go/4 /* whitespace */ + 1 /* \0 */ ); std::ostream& Hexdump::to_stream (std::ostream& os) const { char str[hexdump_reserve_string]; size_t off(0); while (off < size_) { size_t const to_print(std::min(size_ - off, hexdump_bytes_per_go)); gu_hexdump (buf_ + off, to_print, str, sizeof(str), alpha_); off += to_print; os << str; if (off < size_) os << '\n'; } return os; } } // namespace gu percona-galera-3-3.8-3390/galerautils/src/gu_hexdump.h000066400000000000000000000017761244131713600224360ustar00rootroot00000000000000// Copyright (C) 2012-2013 Codership Oy /** * @file Functions to dump binary buffer contents in a readable form * * $Id$ */ #ifndef _gu_hexdump_h_ #define _gu_hexdump_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif /* This makes it 32*2 + 7 spaces = 71 character per line - just short of 80 */ #define GU_HEXDUMP_BYTES_PER_LINE 32 /*! Dumps contents of the binary buffer in a readable form to a 0-terminated * string of length not exeeding str_size - 1 * @param buf input binary buffer * @param but_size size of the input buffer * @param str target string buffer (will be always 0-terminated) * @param str_size string buffer size (including terminating 0) * @param alpha dump alphanumeric characters as they are, padded with '.' * (e.g. D.u.m.p.) */ extern void gu_hexdump(const void* buf, ssize_t buf_size, char* str, ssize_t str_size, bool alpha); #ifdef __cplusplus } #endif #endif /* _gu_hexdump_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_hexdump.hpp000066400000000000000000000020171244131713600227630ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file operator << for hexdumps. * * Usage: std::cout << gu::Hexdump(ptr, size) * * $Id$ */ #ifndef _GU_HEXDUMP_HPP_ #define _GU_HEXDUMP_HPP_ #include "gu_types.hpp" #include namespace gu { class Hexdump { public: Hexdump (const void* const buf, size_t const size, bool const alpha = false) : buf_ (reinterpret_cast(buf)), size_ (size), alpha_(alpha) {} std::ostream& to_stream (std::ostream& os) const; // according to clang C++98 wants copy ctor to be public for temporaries Hexdump (const Hexdump& h) : buf_(h.buf_), size_(h.size_), alpha_(h.alpha_) {} private: const byte_t* const buf_; size_t const size_; bool const alpha_; Hexdump& operator = (const Hexdump&); }; inline std::ostream& operator << (std::ostream& os, const Hexdump& h) { return h.to_stream(os); } } #endif /* _GU_HEXDUMP_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_histogram.cpp000066400000000000000000000042041244131713600233010ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #include "gu_histogram.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" #include "gu_string_utils.hpp" // strsplit() #include #include #include #include gu::Histogram::Histogram(const std::string& vals) : cnt_() { std::vector varr = gu::strsplit(vals, ','); for (std::vector::const_iterator i = varr.begin(); i != varr.end(); ++i) { double val; std::istringstream is(*i); is >> val; if (is.fail()) { gu_throw_fatal << "Parse error"; } if (cnt_.insert(std::make_pair(val, 0)).second == false) { gu_throw_fatal << "Failed to insert value: " << val; } } } void gu::Histogram::insert(const double val) { if (val < 0.0) { log_warn << "Negative value (" << val << "), discarding"; return; } // Returns element that has key greater to val, // the correct bin is one below that std::map::iterator i(cnt_.upper_bound(val)); if (i == cnt_.end()) { ++cnt_.rbegin()->second; } else if (i == cnt_.begin()) { log_warn << "value " << val << " below histogram range, discarding"; } else { --i; ++i->second; } } void gu::Histogram::clear() { for (std::map::iterator i = cnt_.begin(); i != cnt_.end(); ++i) { i->second = 0; } } std::ostream& gu::operator<<(std::ostream& os, const Histogram& hs) { std::map::const_iterator i, i_next; long long norm = 0; for (i = hs.cnt_.begin(); i != hs.cnt_.end(); ++i) { norm += i->second; } for (i = hs.cnt_.begin(); i != hs.cnt_.end(); i = i_next) { i_next = i; ++i_next; os << i->first << ":" << std::fabs(double(i->second)/double(norm)); if (i_next != hs.cnt_.end()) os << ","; } return os; } std::string gu::Histogram::to_string() const { std::ostringstream os; os << *this; return os.str(); } percona-galera-3-3.8-3390/galerautils/src/gu_histogram.hpp000066400000000000000000000010761244131713600233120ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef _gu_histogram_hpp_ #define _gu_histogram_hpp_ #include #include namespace gu { class Histogram { public: Histogram(const std::string&); void insert(const double); void clear(); friend std::ostream& operator<<(std::ostream&, const Histogram&); std::string to_string() const; private: std::map cnt_; }; std::ostream& operator<<(std::ostream&, const Histogram&); } #endif // _gu_histogram_hpp_ percona-galera-3-3.8-3390/galerautils/src/gu_init.c000066400000000000000000000007271244131713600217150ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * $Id$ */ #include "gu_conf.h" #include "gu_limits.h" #include "gu_abort.h" #include "gu_crc32c.h" void gu_init (gu_log_cb_t log_cb) { gu_conf_set_log_callback (log_cb); if (gu_page_size() != GU_PAGE_SIZE) { gu_fatal("GU_PAGE_SIZE(%u) does not maptch real system page size(%zu)", GU_PAGE_SIZE, gu_page_size()); gu_abort(); } gu_crc32c_configure(); } percona-galera-3-3.8-3390/galerautils/src/gu_init.h000066400000000000000000000006321244131713600217150ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * $Id$ */ /*! @file Common initializer for various galerautils parts. Currently it is * logger and CRC32C implementation. */ #ifndef _GU_INIT_H_ #define _GU_INIT_H_ #if defined(__cplusplus) extern "C" { #endif #include "gu_log.h" extern void gu_init (gu_log_cb_t log_cb); #if defined(__cplusplus) } #endif #endif /* _GU_INIT_H_ */ percona-galera-3-3.8-3390/galerautils/src/gu_int128.h000066400000000000000000000125231244131713600220010ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file 128-bit arithmetic macros. This is so far needed only for FNV128 * hash algorithm * * $Id$ */ #ifndef _gu_int128_h_ #define _gu_int128_h_ #include "gu_arch.h" #include "gu_byteswap.h" #include #if defined(__SIZEOF_INT128__) typedef int __attribute__((__mode__(__TI__))) int128_t; typedef unsigned int __attribute__((__mode__(__TI__))) uint128_t; typedef int128_t gu_int128_t; typedef uint128_t gu_uint128_t; #define GU_SET128(_a, hi64, lo64) _a = (((uint128_t)hi64) << 64) + lo64 #define GU_MUL128_INPLACE(_a, _b) _a *= _b #define GU_IMUL128_INPLACE(_a, _b) GU_MUL128_INPLACE(_a, _b) #define GU_EQ128(_a, _b) (_a == _b) #else /* Uncapable of 16-byte integer arythmetic */ #if defined(GU_LITTLE_ENDIAN) #define GU_64LO 0 #define GU_64HI 1 #define GU_32LO 0 #define GU_32HI 3 #define GU_32_0 0 #define GU_32_1 1 #define GU_32_2 2 #define GU_32_3 3 typedef union gu_int128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t lo; uint64_t mid; int32_t hi;}__attribute__((packed)) m; #ifdef __cplusplus gu_int128() : m() {} gu_int128(int64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; } #endif } gu_int128_t; typedef union gu_uint128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t lo; uint64_t mid; uint32_t hi;}__attribute__((packed)) m; #ifdef __cplusplus gu_uint128() : m() {} gu_uint128(uint64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; } #endif } gu_uint128_t; #ifdef __cplusplus #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64) #else #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { lo64, hi64 } } #endif #define GU_MUL128_INPLACE(_a,_b) { \ uint64_t m00 = (uint64_t)(_a).u32[0] * (_b).u32[0]; \ uint64_t m10 = (uint64_t)(_a).u32[1] * (_b).u32[0]; \ uint64_t m20 = (uint64_t)(_a).u32[2] * (_b).u32[0]; \ uint64_t m01 = (uint64_t)(_a).u32[0] * (_b).u32[1]; \ uint64_t m02 = (uint64_t)(_a).u32[0] * (_b).u32[2]; \ uint64_t m11 = (uint64_t)(_a).u32[1] * (_b).u32[1]; \ uint32_t m30 = (_a).u32[3] * (_b).u32[0]; \ uint32_t m21 = (_a).u32[2] * (_b).u32[1]; \ uint32_t m12 = (_a).u32[1] * (_b).u32[2]; \ uint32_t m03 = (_a).u32[0] * (_b).u32[3]; \ (_a).u64[GU_64LO] = m00; (_a).u64[GU_64HI] = 0; \ (_a).m.mid += m10; (_a).m.hi += ((_a).m.mid < m10); \ (_a).m.mid += m01; (_a).m.hi += ((_a).m.mid < m01); \ (_a).u64[GU_64HI] += m20 + m11 + m02; \ (_a).u32[GU_32HI] += m30 + m21 + m12 + m03; \ } #else /* Big-Endian */ #define GU_64HI 0 #define GU_64LO 1 #define GU_32HI 0 #define GU_32LO 3 typedef union gu_int128 { uint64_t u64[2]; uint32_t u32[4]; struct {int32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m; #ifdef __cplusplus gu_int128() {} gu_int128(int64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; } #endif } gu_int128_t; typedef union gu_uint128 { uint64_t u64[2]; uint32_t u32[4]; struct {uint32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m; #ifdef __cplusplus gu_uint128() {} gu_uint128(uint64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; } #endif } gu_uint128_t; #ifdef __cplusplus #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64) #else #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { hi64, lo64 } } #endif #define GU_MUL128_INPLACE(_a,_b) { \ uint64_t m33 = (uint64_t)_a.u32[3] * _b.u32[3]; \ uint64_t m23 = (uint64_t)_a.u32[2] * _b.u32[3]; \ uint64_t m13 = (uint64_t)_a.u32[1] * _b.u32[3]; \ uint64_t m32 = (uint64_t)_a.u32[3] * _b.u32[2]; \ uint64_t m31 = (uint64_t)_a.u32[3] * _b.u32[1]; \ uint64_t m22 = (uint64_t)_a.u32[2] * _b.u32[2]; \ uint32_t m30 = _a.u32[3] * _b.u32[0]; \ uint32_t m21 = _a.u32[2] * _b.u32[1]; \ uint32_t m12 = _a.u32[1] * _b.u32[2]; \ uint32_t m03 = _a.u32[0] * _b.u32[3]; \ _a.u64[GU_64LO] = m00; _a.u64[GU_64HI] = 0; \ _a.m.mid += m23; _a.m.hi += (_a.m.mid < m23); \ _a.m.mid += m32; _a.m.hi += (_a.m.mid < m32); \ _a.u64[GU_64HI] += m13 + m22 + m31; \ _a.u32[GU_32HI] += m30 + m21 + m12 + m03; \ } #endif /* Big-Endian */ #define GU_IMUL128_INPLACE(_a, _b) { \ uint32_t sign = ((_a).u32[GU_32HI] ^ (_b).u32[GU_32HI]) & 0x80000000UL; \ GU_MUL128_INPLACE (_a, _b); \ (_a).u32[GU_32HI] |= sign; \ } #define GU_EQ128(_a, _b) (!memcmp(&_a,&_b,sizeof(_a))) #endif /* __SIZEOF_INT128__ */ /* Not sure how to make it both portable, efficient and still follow the * signature of other byteswap functions at the same time. * So this one does inplace conversion. */ #ifdef __cplusplus extern "C" { #endif static inline void gu_bswap128 (gu_uint128_t* const arg) { uint64_t* x = (uint64_t*)arg; uint64_t tmp = gu_bswap64(x[0]); x[0] = gu_bswap64(x[1]); x[1] = tmp; } #ifdef __cplusplus } #endif #ifdef GU_LITTLE_ENDIAN # define gu_le128(x) {} # define gu_be128(x) gu_bswap128(x) #else # define gu_le128(x) gu_bswap128(x) # define gu_be128(x) {} #endif /* GU_LITTLE_ENDIAN */ #define htog128(x) gu_le128(x) #define gtoh128(x) htog128(x) #endif /* _gu_int128_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_limits.c000066400000000000000000000052301244131713600222450ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file system limit macros * * $Id:$ */ #include #include #include #include "gu_limits.h" #include "gu_log.h" #if defined(__APPLE__) #include // doesn't seem to be used directly, but jst in case #include long gu_darwin_phys_pages (void) { /* Note: singleton pattern would be useful here */ vm_statistics64_data_t vm_stat; unsigned int count = HOST_VM_INFO64_COUNT; kern_return_t ret = host_statistics64 (mach_host_self (), HOST_VM_INFO64, (host_info64_t) &vm_stat, &count); if (ret != KERN_SUCCESS) { gu_error ("host_statistics64 failed with code %d", ret); return 0; } /* This gives a value a little less than physical memory of computer */ return vm_stat.free_count + vm_stat.active_count + vm_stat.inactive_count + vm_stat.wire_count; /* Exact value may be obtain via sysctl ({CTL_HW, HW_MEMSIZE}) */ /* Note: sysctl is 60% slower compared to host_statistics64 */ } long gu_darwin_avphys_pages (void) { vm_statistics64_data_t vm_stat; unsigned int count = HOST_VM_INFO64_COUNT; kern_return_t ret = host_statistics64 (mach_host_self (), HOST_VM_INFO64, (host_info64_t) &vm_stat, &count); if (ret != KERN_SUCCESS) { gu_error ("host_statistics64 failed with code %d", ret); return 0; } /* Note: * vm_stat.free_count == vm_page_free_count + vm_page_speculative_count */ return vm_stat.free_count - vm_stat.speculative_count; } #elif defined(__FreeBSD__) #include // VM_TOTAL #include // struct vmtotal #include long gu_freebsd_avphys_pages (void) { /* TODO: 1) sysctlnametomib may be called once */ /* 2) vm.stats.vm.v_cache_count is potentially free memory too */ int mib_vm_stats_vm_v_free_count[4]; size_t mib_sz = 4; int rc = sysctlnametomib ("vm.stats.vm.v_free_count", mib_vm_stats_vm_v_free_count, &mib_sz); if (rc != 0) { gu_error ("sysctlnametomib(vm.stats.vm.v_free_count) failed, code %d", rc); return 0; } unsigned int vm_stats_vm_v_free_count; size_t sz = sizeof (vm_stats_vm_v_free_count); rc = sysctl (mib_vm_stats_vm_v_free_count, mib_sz, &vm_stats_vm_v_free_count, &sz, NULL, 0); if (rc != 0) { gu_error ("sysctl(vm.stats.vm.v_free_count) failed with code %d", rc); return 0; } return vm_stats_vm_v_free_count; } #endif /* __FreeBSD__ */ percona-galera-3-3.8-3390/galerautils/src/gu_limits.h000066400000000000000000000035041244131713600222540ustar00rootroot00000000000000// Copyright (C) 2008 Codership Oy /** * @file system limit macros * * $Id$ */ #ifndef _gu_limits_h_ #define _gu_limits_h_ #include #ifdef __cplusplus extern "C" { #endif # if defined(__APPLE__) long gu_darwin_phys_pages (void); long gu_darwin_avphys_pages (void); # elif defined(__FreeBSD__) long gu_freebsd_avphys_pages (void); # endif #ifdef __cplusplus } #endif #if defined(__APPLE__) static inline size_t gu_page_size() { return getpagesize(); } static inline size_t gu_phys_pages() { return gu_darwin_phys_pages(); } static inline size_t gu_avphys_pages() { return gu_darwin_avphys_pages(); } #elif defined(__FreeBSD__) static inline size_t gu_page_size() { return sysconf(_SC_PAGESIZE); } static inline size_t gu_phys_pages() { return sysconf(_SC_PHYS_PAGES); } static inline size_t gu_avphys_pages() { return gu_freebsd_avphys_pages(); } #else /* !__APPLE__ && !__FreeBSD__ */ static inline size_t gu_page_size() { return sysconf(_SC_PAGESIZE); } static inline size_t gu_phys_pages() { return sysconf(_SC_PHYS_PAGES); } static inline size_t gu_avphys_pages() { return sysconf(_SC_AVPHYS_PAGES); } #endif /* !__APPLE__ && !__FreeBSD__ */ /* We need this as a compile-time constant. Runtime check is implemented * in gu_init.c */ #define GU_PAGE_SIZE 4096 static inline size_t gu_avphys_bytes() { // to detect overflow on systems with >4G of RAM, see #776 unsigned long long avphys = gu_avphys_pages(); avphys *= gu_page_size(); size_t max = -1; return (avphys < max ? avphys : max); } #include #define GU_ULONG_MAX ULONG_MAX #define GU_LONG_MAX LONG_MAX #define GU_LONG_MIN LONG_MIN #define GU_ULONG_LONG_MAX ULLONG_MAX #define GU_LONG_LONG_MAX LLONG_MAX #define GU_LONG_LONG_MIN LLONG_MIN #endif /* _gu_limits_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_lock.hpp000066400000000000000000000032351244131713600222440ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GU_LOCK__ #define __GU_LOCK__ #include #include #include "gu_exception.hpp" #include "gu_logger.hpp" #include "gu_mutex.hpp" #include "gu_cond.hpp" #include "gu_datetime.hpp" namespace gu { class Lock { pthread_mutex_t* const value; Lock (const Lock&); Lock& operator=(const Lock&); public: Lock (const Mutex& mtx) : value(&mtx.value) { int err = pthread_mutex_lock (value); if (gu_unlikely(err)) { std::string msg = "Mutex lock failed: "; msg = msg + strerror(err); throw Exception(msg.c_str(), err); } } virtual ~Lock () { int err = pthread_mutex_unlock (value); if (gu_unlikely(err)) { log_fatal << "Mutex unlock failed: " << err << " (" << strerror(err) << "), Aborting."; ::abort(); } // log_debug << "Unlocked mutex " << value; } inline void wait (const Cond& cond) { cond.ref_count++; pthread_cond_wait (&(cond.cond), value); cond.ref_count--; } inline void wait (const Cond& cond, const datetime::Date& date) { timespec ts; date._timespec(ts); cond.ref_count++; int ret = pthread_cond_timedwait (&(cond.cond), value, &ts); cond.ref_count--; if (gu_unlikely(ret)) gu_throw_error(ret); } }; } #endif /* __GU_LOCK__ */ percona-galera-3-3.8-3390/galerautils/src/gu_lock_step.c000066400000000000000000000067111244131713600227340ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #include // abort() #include // error codes #include #include #include // strerror() #include "gu_log.h" #include "gu_assert.h" #include "gu_time.h" #include "gu_lock_step.h" void gu_lock_step_init (gu_lock_step_t* ls) { gu_mutex_init (&ls->mtx, NULL); gu_cond_init (&ls->cond, NULL); ls->wait = 0; ls->cont = 0; ls->enabled = false; } void gu_lock_step_destroy (gu_lock_step_t* ls) { // this is not really fool-proof, but that's not for fools to use while (gu_lock_step_cont(ls, 10)) {}; gu_cond_destroy (&ls->cond); gu_mutex_destroy (&ls->mtx); assert (0 == ls->wait); } void gu_lock_step_enable (gu_lock_step_t* ls, bool enable) { if (!gu_mutex_lock (&ls->mtx)) { ls->enabled = enable; gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } } void gu_lock_step_wait (gu_lock_step_t* ls) { if (!gu_mutex_lock (&ls->mtx)) { if (ls->enabled) { if (!ls->cont) { // wait for signal ls->wait++; gu_cond_wait (&ls->cond, &ls->mtx); } else { // signal to signaller gu_cond_signal (&ls->cond); ls->cont--; } } gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } } /* returns how many waiters are there */ long gu_lock_step_cont (gu_lock_step_t* ls, long timeout_ms) { long ret = -1; if (!gu_mutex_lock (&ls->mtx)) { if (ls->enabled) { if (ls->wait > 0) { // somebody's waiting ret = ls->wait; gu_cond_signal (&ls->cond); ls->wait--; } else if (timeout_ms > 0) { // wait for waiter // what a royal mess with times! Why timeval exists? struct timeval now; struct timespec timeout; long err; gettimeofday (&now, NULL); gu_timeval_add (&now, timeout_ms * 0.001); timeout.tv_sec = now.tv_sec; timeout.tv_nsec = now.tv_usec * 1000; ls->cont++; do { err = gu_cond_timedwait (&ls->cond, &ls->mtx, &timeout); } while (EINTR == err); assert ((0 == err) || (ETIMEDOUT == err && ls->cont > 0)); ret = (0 == err); // successful rendezvous with waiter ls->cont -= (0 != err); // self-decrement in case of error } else if (timeout_ms < 0) { // wait forever long err; ls->cont++; err = gu_cond_wait (&ls->cond, &ls->mtx); ret = (0 == err); // successful rendezvous with waiter ls->cont -= (0 != err); // self-decrement in case of error } else { // don't wait ret = 0; } } gu_mutex_unlock (&ls->mtx); } else { gu_fatal ("Mutex lock failed"); assert (0); abort(); } return ret; } percona-galera-3-3.8-3390/galerautils/src/gu_lock_step.h000066400000000000000000000016421244131713600227370ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ // This is a small class to facilitate lock-stepping in multithreaded unit tests #ifndef _gu_lock_step_h_ #define _gu_lock_step_h_ #include #include "gu_mutex.h" typedef struct gu_lock_step { gu_mutex_t mtx; gu_cond_t cond; long wait; long cont; bool enabled; } gu_lock_step_t; extern void gu_lock_step_init (gu_lock_step_t* ls); /* enable or disable lock-stepping */ extern void gu_lock_step_enable (gu_lock_step_t* ls, bool enable); extern void gu_lock_step_wait (gu_lock_step_t* ls); /* returns how many waiters there were, * waits for timeout_ms milliseconds if no waiters, if timeout_ms < 0 waits forever, * if 0 - no wait at all */ extern long gu_lock_step_cont (gu_lock_step_t* ls, long timeout_ms); extern void gu_lock_step_destroy (gu_lock_step_t* ls); #endif /* _gu_lock_step_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_log.c000066400000000000000000000077521244131713600215400ustar00rootroot00000000000000// Copyright (C) 2007-2014 Codership Oy /** * @file Logging functions definitions * * $Id$ */ #include #include #include #include #include #include #include #include "gu_log.h" #include "gu_macros.h" /* Global configurable variables */ static FILE* gu_log_file = NULL; bool gu_log_self_tstamp = false; gu_log_severity_t gu_log_max_level = GU_LOG_INFO; int gu_conf_set_log_file (FILE *file) { gu_debug ("Log file changed by application"); if (file) { gu_log_file = file; } else { gu_log_file = stderr; } return 0; } int gu_conf_self_tstamp_on () { gu_debug ("Turning self timestamping on"); gu_log_self_tstamp = true; return 0; } int gu_conf_self_tstamp_off () { gu_debug ("Turning self timestamping off"); gu_log_self_tstamp = false; return 0; } int gu_conf_debug_on () { gu_log_max_level = GU_LOG_DEBUG; gu_debug ("Turning debug logging on"); return 0; } int gu_conf_debug_off () { gu_debug ("Turning debug logging off"); gu_log_max_level = GU_LOG_INFO; return 0; } /** Returns current timestamp in the provided buffer */ static inline int log_tstamp (char* tstamp, size_t const len) { int ret = 0; struct tm date; struct timeval time; gettimeofday (&time, NULL); localtime_r (&time.tv_sec, &date); /* 23 symbols */ ret = snprintf (tstamp, len, "%04d-%02d-%02d %02d:%02d:%02d.%03d ", date.tm_year + 1900, date.tm_mon + 1, date.tm_mday, date.tm_hour, date.tm_min, date.tm_sec, (int)time.tv_usec / 1000); return ret; } const char* gu_log_level_str[GU_LOG_DEBUG + 2] = { "FATAL: ", "ERROR: ", " WARN: ", " INFO: ", "DEBUG: ", "XXXXX: " }; /** * @function * Default logging function: simply writes to stderr or gu_log_file if set. */ void gu_log_cb_default (int severity, const char* msg) { FILE* log_file = gu_log_file ? gu_log_file : stderr; fputs (msg, log_file); fputc ('\n', log_file); fflush (log_file); } /** * Log function handle. * Can be changed by application through gu_conf_set_log_callback() */ gu_log_cb_t gu_log_cb = gu_log_cb_default; int gu_conf_set_log_callback (gu_log_cb_t callback) { if (callback) { gu_debug ("Logging function changed by application"); gu_log_cb = callback; } else { gu_debug ("Logging function restored to default"); gu_log_cb = gu_log_cb_default; } return 0; } int gu_log (gu_log_severity_t severity, const char* file, const char* function, const int line, ...) { va_list ap; int max_string = 2048; char string[max_string]; /** @note: this can cause stack overflow * in kernel mode (both Linux and Windows). */ char* str = string; int len; if (gu_log_self_tstamp) { len = log_tstamp (str, max_string); str += len; max_string -= len; } if (gu_likely(max_string > 0)) { const char* log_level_str = gu_log_cb_default == gu_log_cb ? gu_log_level_str[severity] : ""; /* provide file:func():line info only if debug logging is on */ if (gu_likely(!gu_log_debug && severity > GU_LOG_ERROR)) { len = snprintf (str, max_string, "%s", log_level_str); } else { len = snprintf (str, max_string, "%s%s:%s():%d: ", log_level_str, file, function, line); } str += len; max_string -= len; va_start (ap, line); { const char* format = va_arg (ap, const char*); if (gu_likely(max_string > 0 && NULL != format)) { vsnprintf (str, max_string, format, ap); } } va_end (ap); } /* actual logging */ gu_log_cb (severity, string); return 0; } percona-galera-3-3.8-3390/galerautils/src/gu_log.h000066400000000000000000000053001244131713600215300ustar00rootroot00000000000000// Copyright (C) 2007-2014 Codership Oy /** * @file Logging API * * $Id$ */ #ifndef _gu_log_h_ #define _gu_log_h_ #include "gu_macros.h" #include /* For NULL */ #if defined(__cplusplus) extern "C" { #endif /** * @typedef * Defines severity classes for log messages: * FATAL - is a fatal malfunction of the library which cannot be recovered * from. Application must close. * error - error condition in the library which prevents further normal * operation but can be recovered from by the application. E.g. EAGAIN. * warn - some abnormal condition which library can recover from by itself. * * info - just an informative log message. * * debug - debugging message. */ typedef enum gu_log_severity { GU_LOG_FATAL, GU_LOG_ERROR, GU_LOG_WARN, GU_LOG_INFO, GU_LOG_DEBUG } gu_log_severity_t; /** * @typedef * Defines a type of callback function that application can provide * to do the logging */ typedef void (*gu_log_cb_t) (int severity, const char* msg); /** Helper for macros defined below. Should not be called directly. */ extern int gu_log (gu_log_severity_t severity, const char* file, const char* function, const int line, ...); /** This variable is made global only for the purpose of using it in * gu_debug() macro and avoid calling gu_log() when debug is off. * Don't use it directly! */ extern gu_log_severity_t gu_log_max_level; #define gu_log_debug (GU_LOG_DEBUG == gu_log_max_level) #if defined(__cplusplus) } #endif #if !defined(__cplusplus) || defined(GALERA_LOG_H_ENABLE_CXX) // NOTE: don't add "\n" here even if you really want to do it #define GU_LOG_C(level, ...)\ gu_log(level, __FILE__, __PRETTY_FUNCTION__, __LINE__,\ __VA_ARGS__, NULL) /** * @name Logging macros. * Must be implemented as macros to report the location of the code where * they are called. */ /*@{*/ #define gu_fatal(...) GU_LOG_C(GU_LOG_FATAL, __VA_ARGS__, NULL) #define gu_error(...) GU_LOG_C(GU_LOG_ERROR, __VA_ARGS__, NULL) #define gu_warn(...) GU_LOG_C(GU_LOG_WARN, __VA_ARGS__, NULL) #define gu_info(...) GU_LOG_C(GU_LOG_INFO, __VA_ARGS__, NULL) #define gu_debug(...) if (gu_unlikely(gu_log_debug)) \ { GU_LOG_C(GU_LOG_DEBUG, __VA_ARGS__, NULL); } /*@}*/ #endif /* __cplusplus */ #endif /* _gu_log_h_ */ #ifdef __GU_LOGGER__ // C++ logger should use the same stuff, so export it #ifndef _gu_log_extra_ #define _gu_log_extra_ extern "C" { extern bool gu_log_self_tstamp; extern gu_log_cb_t gu_log_cb; extern void gu_log_cb_default (int, const char*); extern const char* gu_log_level_str[]; } #endif /* _gu_log_extra_ */ #endif /* __GU_LOGGER__ */ percona-galera-3-3.8-3390/galerautils/src/gu_logger.cpp000066400000000000000000000065771244131713600226020ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 */ #include #include #include #include #include #include "gu_logger.hpp" #include "gu_string_utils.hpp" // strsplit #include #include #include using std::string; using std::vector; using std::set; namespace gu { class DebugFilter { set filter; public: DebugFilter() : filter() { if (::getenv("LOGGER_DEBUG_FILTER")) { set_filter(::getenv("LOGGER_DEBUG_FILTER")); } } ~DebugFilter() {} void set_filter(const string& str) { vector dvec = gu::strsplit(str, ','); for (vector::const_iterator i = dvec.begin(); i != dvec.end(); ++i) { filter.insert(*i); } } size_t size() const { return filter.size(); } bool is_set(const string& str) const { return filter.find(str) != filter.end() || filter.find(str.substr(0, str.find_first_of(":"))) != filter.end(); } }; static DebugFilter debug_filter; void Logger::set_debug_filter(const string& str) { debug_filter.set_filter(str); } bool Logger::no_debug(const string& file, const string& func, const int line) { return debug_filter.size() > 0 && debug_filter.is_set(func) == false; } #ifndef _gu_log_h_ void Logger::enable_tstamp (bool yes) { do_timestamp = yes; } void Logger::enable_debug (bool yes) { if (yes) { max_level = LOG_DEBUG; } else { max_level = LOG_INFO; } } void Logger::default_logger (int lvl, const char* msg) { fputs (msg, stderr); fputc ('\n', stderr); fflush (stderr); } void Logger::set_logger (LogCallback cb) { if (0 == cb) { logger = default_logger; } else { logger = cb; } } static const char* level_str[LOG_MAX] = { "FATAL: ", "ERROR: ", " WARN: ", " INFO: ", "DEBUG: " }; bool Logger::do_timestamp = false; LogLevel Logger::max_level = LOG_INFO; LogCallback Logger::logger = default_logger; #else #define do_timestamp (gu_log_self_tstamp == true) #define level_str gu_log_level_str #endif // _gu_log_h_ void Logger::prepare_default() { if (do_timestamp) { using namespace std; struct tm date; struct timeval time; gettimeofday (&time, NULL); localtime_r (&time.tv_sec, &date); os << date.tm_year + 1900 << '-' << setw(2) << setfill('0') << (date.tm_mon + 1) << '-' << setw(2) << setfill('0') << date.tm_mday << ' ' << setw(2) << setfill('0') << date.tm_hour << ':' << setw(2) << setfill('0') << date.tm_min << ':' << setw(2) << setfill('0') << date.tm_sec << '.' << setw(3) << setfill('0') << (time.tv_usec / 1000) << ' '; } os << level_str[level]; } } percona-galera-3-3.8-3390/galerautils/src/gu_logger.hpp000066400000000000000000000066271244131713600226030ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 * * It looks ugly because it has to integrate with C logger - * in order to produce identical output */ #ifndef __GU_LOGGER__ #define __GU_LOGGER__ #include extern "C" { #include "gu_log.h" #include "gu_conf.h" } namespace gu { // some portability stuff #ifdef _gu_log_h_ enum LogLevel { LOG_FATAL = GU_LOG_FATAL, LOG_ERROR = GU_LOG_ERROR, LOG_WARN = GU_LOG_WARN, LOG_INFO = GU_LOG_INFO, LOG_DEBUG = GU_LOG_DEBUG, LOG_MAX }; typedef gu_log_cb_t LogCallback; #else enum LogLevel { LOG_FATAL, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_MAX }; typedef void (*LogCallback) (int, const char*); #endif class Logger { private: Logger(const Logger&); Logger& operator =(const Logger&); void prepare_default (); const LogLevel level; #ifndef _gu_log_h_ static LogLevel max_level; static bool do_timestamp; static LogCallback logger; static void default_logger (int, const char*); #else #define max_level gu_log_max_level #define logger gu_log_cb #define default_logger gu_log_cb_default #endif protected: std::ostringstream os; public: Logger(LogLevel _level = LOG_INFO) : level (_level), os () {} virtual ~Logger() { logger (level, os.str().c_str()); } std::ostringstream& get(const char* file, const char* func, int line) { if (default_logger == logger) { prepare_default(); // prefix with timestamp and log level } /* provide file:func():line info only when debug logging is on */ if (static_cast(LOG_DEBUG) == static_cast(max_level)) { os << file << ':' << func << "():" << line << ": "; } return os; } static bool no_log (LogLevel lvl) { return (static_cast(lvl) > static_cast(max_level)); } static void set_debug_filter(const std::string&); static bool no_debug(const std::string&, const std::string&, const int); #ifndef _gu_log_h_ static void enable_tstamp (bool); static void enable_debug (bool); static void set_logger (LogCallback); #endif }; #define GU_LOG_CPP(level) \ if (gu::Logger::no_log(level) || \ (level == gu::LOG_DEBUG && \ gu::Logger::no_debug(__FILE__, __FUNCTION__, __LINE__))) {} \ else gu::Logger(level).get(__FILE__, __FUNCTION__, __LINE__) // USAGE: LOG(level) << item_1 << item_2 << ... << item_n; #define log_fatal GU_LOG_CPP(gu::LOG_FATAL) #define log_error GU_LOG_CPP(gu::LOG_ERROR) #define log_warn GU_LOG_CPP(gu::LOG_WARN) #define log_info GU_LOG_CPP(gu::LOG_INFO) #define log_debug GU_LOG_CPP(gu::LOG_DEBUG) } #endif // __GU_LOGGER__ percona-galera-3-3.8-3390/galerautils/src/gu_macros.h000066400000000000000000000035321244131713600222400ustar00rootroot00000000000000// Copyright (C) 2007-2013 Codership Oy /** * @file Miscellaneous macros * * $Id$ */ #ifndef _gu_macros_h_ #define _gu_macros_h_ /* * Platform-dependent macros */ #if defined(_MSC_VER) # define GU_NORETURN __declspec(noreturn) # define GU_INLINE __forceinline # define GU_FORCE_INLINE __forceinline # define GU_UNUSED # define GU_LONG(x) (x) # define GU_ULONG(x) (x) # define GU_LONG_LONG(x) (x) # define GU_ULONG_LONG(x) (x) # define GU_DEBUG_NORETURN #else /* !defined(_MSC_VER) */ # define GU_NORETURN __attribute__((noreturn)) # define GU_INLINE inline # define GU_FORCE_INLINE inline __attribute__((always_inline)) # define GU_UNUSED __attribute__((unused)) # define GU_LONG(x) (x##L) # define GU_ULONG(x) (x##LU) # define GU_LONG_LONG(x) (x##LL) # define GU_ULONG_LONG(x) (x##LLU) # ifndef __OPTIMIZE__ # define GU_DEBUG_NORETURN abort(); # else # define GU_DEBUG_NORETURN # endif #endif /* !defined(_MSC_VER) */ /* * End of paltform-dependent macros */ /* "Shamelessly stolen" (tm) goods from Linux kernel */ /* * min()/max() macros that also do * strict type-checking.. See the * "unnecessary" pointer comparison. */ #if 0 // typeof() is not in C99 #define GU_MAX(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) #define GU_MIN(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #endif #define gu_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #if __GNUC__ >= 3 # define gu_likely(x) __builtin_expect((x), 1) # define gu_unlikely(x) __builtin_expect((x), 0) #else # define gu_likely(x) (x) # define gu_unlikely(x) (x) #endif #endif /* _gu_macros_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_macros.hpp000066400000000000000000000013071244131713600225760ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /** * @file Miscellaneous C++-related macros * * $Id$ */ #ifndef _gu_macros_hpp_ #define _gu_macros_hpp_ /* To protect against "old-style" casts in libc macros * must be included after respective libc headers */ #if defined(SIG_IGN) extern "C" { static void (* const GU_SIG_IGN)(int) = SIG_IGN; } #endif #if defined(MAP_FAILED) extern "C" { static const void* const GU_MAP_FAILED = MAP_FAILED; } #endif namespace gu { template struct CompileAssert {}; } /* namespace gu */ #define GU_COMPILE_ASSERT(expr,msg) \ typedef gu::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] __attribute__((unused)) #endif /* _gu_macros_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_mem.c000066400000000000000000000101131244131713600215160ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * Debugging versions of memmory functions * * $Id$ */ #include #include #include #include "gu_mem.h" #include "gu_log.h" /* Some global counters - can be inspected by gdb */ static volatile ssize_t gu_mem_total = 0; static volatile ssize_t gu_mem_allocs = 0; static volatile ssize_t gu_mem_reallocs = 0; static volatile ssize_t gu_mem_frees = 0; typedef struct mem_head { const char* file; unsigned int line; size_t used; size_t allocated; uint32_t signature; } mem_head_t; #define MEM_SIGNATURE 0x13578642 /**< Our special marker */ // Returns pointer to the first byte after the head structure #define TAIL(head) ((void*)((mem_head_t*)(head) + 1)) // Returns pointer to the head preceding tail #define HEAD(tail) ((mem_head_t*)(tail) - 1) void* gu_malloc_dbg (size_t size, const char* file, unsigned int line) { if (size) { size_t const total_size = size + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) malloc (total_size); if (ret) { gu_mem_total += total_size; gu_mem_allocs++; ret->signature = MEM_SIGNATURE; ret->allocated = total_size; ret->used = size; ret->file = file; ret->line = line; // cppcheck-suppress memleak return TAIL(ret); } } return NULL; } void* gu_calloc_dbg (size_t nmemb, size_t size, const char* file, unsigned int line) { if (size != 0 && nmemb != 0) { size_t const total_size = size*nmemb + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) calloc (total_size, 1); if (ret) { size_t const total_size = size*nmemb + sizeof(mem_head_t); gu_mem_total += total_size; gu_mem_allocs++; ret->signature = MEM_SIGNATURE; ret->allocated = total_size; ret->used = size; ret->file = file; ret->line = line; return TAIL(ret); } } return NULL; } void* gu_realloc_dbg (void* ptr, size_t size, const char* file, unsigned int line) { if (ptr) { if (size > 0) { mem_head_t* const old = HEAD(ptr); if (MEM_SIGNATURE != old->signature) { gu_error ("Attempt to realloc uninitialized pointer at " "file: %s, line: %d", file, line); assert (0); } size_t const total_size = size + sizeof(mem_head_t); mem_head_t* const ret = (mem_head_t*) realloc (old, total_size); if (ret) { gu_mem_reallocs++; gu_mem_total -= ret->allocated; // old size ret->allocated = total_size; gu_mem_total += ret->allocated; // new size ret->used = size; ret->file = file; ret->line = line; return TAIL(ret); } else { // realloc failed return NULL; } } else { gu_free_dbg (ptr, file, line); return NULL; } } else { return gu_malloc_dbg (size, file, line); } return NULL; } void gu_free_dbg (void* ptr, const char* file, unsigned int line) { mem_head_t* head; if (NULL == ptr) { gu_debug ("Attempt to free NULL pointer at file: %s, line: %d", file, line); return; /* As per specification - no operation is performed */ } head = HEAD(ptr); if (MEM_SIGNATURE != head->signature) { gu_error ("Attempt to free uninitialized pointer " "at file: %s, line: %d", file, line); assert (0); } if (0 == head->used) { gu_error ("Attempt to free pointer the second time at " "file: %s, line: %d. " "Was allocated at file: %s, line: %d.", file, line, head->file, head->line); assert (0); } gu_mem_total -= head->allocated; gu_mem_frees++; head->allocated = 0; head->used = 0; free (head); } void gu_mem_stats (ssize_t* total, ssize_t* allocs, ssize_t* reallocs, ssize_t* deallocs) { *total = gu_mem_total; *allocs = gu_mem_allocs; *reallocs = gu_mem_reallocs; *deallocs = gu_mem_frees; } percona-galera-3-3.8-3390/galerautils/src/gu_mem.h000066400000000000000000000040041244131713600215250ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * @file * Declarations of memory allocation functions and macros * * $Id$ */ #ifndef _gu_mem_h_ #define _gu_mem_h_ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** @name Functions to help with dynamic allocation debugging. * Take additional __FILE__ and __LINE__ arguments. Should be * used as part of macros defined below */ /*@{*/ void* gu_malloc_dbg (size_t size, const char* file, unsigned int line); void* gu_calloc_dbg (size_t nmemb, size_t size, const char* file, unsigned int line); void* gu_realloc_dbg (void* ptr, size_t size, const char* file, unsigned int line); void gu_free_dbg (void* ptr, const char* file, unsigned int line); /*@}*/ /** Reports statistics on the current amount of allocated memory * total number of allocations and deallocations */ void gu_mem_stats (ssize_t* total, ssize_t* allocs, ssize_t* reallocs, ssize_t* deallocs); /** @name Applications should use the following macros */ /*@{*/ #ifdef DEBUG_MALLOC #define gu_malloc(S) gu_malloc_dbg ((S), __FILE__, __LINE__) #define gu_calloc(N,S) gu_calloc_dbg ((N), (S), __FILE__, __LINE__) #define gu_realloc(P,S) gu_realloc_dbg ((P), (S), __FILE__, __LINE__) #define gu_free(P) gu_free_dbg ((P), __FILE__, __LINE__) #else /* !DEBUG_MALLOC - use standard allocation routines */ #define gu_malloc(S) malloc ((S)) #define gu_calloc(N,S) calloc ((N), (S)) #define gu_realloc(P,S) realloc ((P), (S)) #define gu_free(P) free ((P)) #endif /* DEBUG_MALLOC */ /** Convenience macros - to avoid code clutter */ #define GU_MALLOC(type) (type*) gu_malloc (sizeof(type)) #define GU_MALLOCN(N,type) (type*) gu_malloc ((N) * sizeof(type)) #define GU_CALLOC(N,type) (type*) gu_calloc ((N), sizeof(type)) #define GU_REALLOC(P,N,type) (type*) gu_realloc((P), (N) * sizeof(type)) /*@}*/ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_mem_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_mem_pool.hpp000066400000000000000000000130151244131713600231200ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /** * @file Self-adjusting pool of same size memory buffers. * * How it works: pool is never allowed to keep more than half of total * allocated buffers (plus min_count), so at least half of buffers must be * in use. As more than half goes out of use they will be deallocated rather * than placed back in the pool. * * $Id$ */ #ifndef _GU_MEM_POOL_HPP_ #define _GU_MEM_POOL_HPP_ #include "gu_lock.hpp" #include "gu_macros.hpp" #include #include #include //#include // std::bad_alloc namespace gu { typedef std::vector MemPoolVector; /* Since we specialize this template iwth thread_safe=true parameter below, * this makes it implicit thread_safe=false specialization. */ template class MemPool { public: explicit MemPool(int buf_size, int reserve = 0, const char* name = "") : pool_ (), hits_ (0), misses_ (0), allocd_ (0), name_ (name), buf_size_ (buf_size), reserve_ (reserve) { assert(buf_size > 0); assert(reserve >= 0); pool_.reserve(reserve_); } ~MemPool() { /* all buffers must be returned to pool before destruction */ assert(pool_.size() == allocd_); for (size_t i(0); i < pool_.size(); ++i) { assert(pool_[i]); free(pool_[i]); } } void* acquire() { void* ret(from_pool()); if (!ret) ret = alloc(); return ret; } void recycle(void* buf) { if (!to_pool(buf)) free(buf); } void print(std::ostream& os) const { double hr(hits_); if (hr > 0) { assert(misses_ > 0); hr /= hits_ + misses_; } os << "MemPool(" << name_ << "): hit ratio: " << hr << ", misses: " << misses_ << ", in use: " << allocd_ - pool_.size() << ", in pool: " << pool_.size(); } size_t buf_size() const { return buf_size_; } protected: /* from_pool() and to_pool() will need to be called under mutex * in thread-safe version, so all object data are modified there. * alloc() and free() then can be called outside critical section. */ void* from_pool() { void* ret(NULL); if (pool_.size() > 0) { ret = pool_.back(); assert(ret); pool_.pop_back(); ++hits_; } else { ++allocd_; ++misses_; } return ret; } // returns false if buffer can't be returned to pool bool to_pool(void* buf) { assert(buf); bool const ret(reserve_ + allocd_/2 > pool_.size()); if (ret) { pool_.push_back(buf); } else { assert(allocd_ > 0); --allocd_; } return ret; } void* alloc() { return (operator new(buf_size_)); } void free(void* const buf) { assert(buf); operator delete(buf); } friend class MemPool; private: MemPoolVector pool_; size_t hits_; size_t misses_; size_t allocd_; const char* const name_; unsigned int const buf_size_; unsigned int const reserve_; MemPool (const MemPool&); MemPool operator= (const MemPool&); }; /* class MemPool: thread-unsafe */ /* Thread-safe MemPool specialization. * Even though MemPool technically IS-A MemPool, the need to * overload nearly all public methods and practical uselessness of * polymorphism in this case make inheritance undesirable. */ template <> class MemPool { public: explicit MemPool(int buf_size, int reserve = 0, const char* name = "") : base_(buf_size, reserve, name), mtx_ () {} ~MemPool() {} void* acquire() { void* ret; { Lock lock(mtx_); ret = base_.from_pool(); } if (!ret) ret = base_.alloc(); return ret; } void recycle(void* buf) { bool pooled; { Lock lock(mtx_); pooled = base_.to_pool(buf); } if (!pooled) base_.free(buf); } void print(std::ostream& os) const { Lock lock(mtx_); base_.print(os); } size_t buf_size() const { return base_.buf_size(); } private: MemPool base_; Mutex mtx_; }; /* class MemPool: thread-safe */ template std::ostream& operator << (std::ostream& os, const MemPool& mp) { mp.print(os); return os; } typedef MemPool MemPoolUnsafe; typedef MemPool MemPoolSafe; } /* namespace gu */ #endif /* _GU_MEM_POOL_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_mmap.cpp000066400000000000000000000046401244131713600222420ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ #include "gu_mmap.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" #include #include // to avoid -Wold-style-cast extern "C" { static const void* const GU_MAP_FAILED = MAP_FAILED; } namespace gu { MMap::MMap (const FileDescriptor& fd, bool const sequential) : size (fd.size()), ptr (mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd.get(), 0)), mapped (ptr != GU_MAP_FAILED) { if (!mapped) { gu_throw_error(errno) << "mmap() on '" << fd.name() << "' failed"; } #if !defined(__sun__) && !defined(__APPLE__) && !defined(__FreeBSD__) /* Solaris, Darwin, and FreeBSD do not have MADV_DONTFORK */ if (posix_madvise (ptr, size, MADV_DONTFORK)) { int const err(errno); log_warn << "Failed to set MADV_DONTFORK on " << fd.name() << ": " << err << " (" << strerror(err) << ")"; } #endif /* benefits are questionable */ if (sequential && posix_madvise (ptr, size, MADV_SEQUENTIAL)) { int const err(errno); log_warn << "Failed to set MADV_SEQUENTIAL on " << fd.name() << ": " << err << " (" << strerror(err) << ")"; } log_debug << "Memory mapped: " << ptr << " (" << size << " bytes)"; } void MMap::dont_need() const { if (posix_madvise(reinterpret_cast(ptr), size, MADV_DONTNEED)) { log_warn << "Failed to set MADV_DONTNEED on " << ptr << ": " << errno << " (" << strerror(errno) << ')'; } } void MMap::sync () const { log_info << "Flushing memory map to disk..."; if (msync (ptr, size, MS_SYNC) < 0) { gu_throw_error(errno) << "msync(" << ptr << ", " << size << ") failed"; } } void MMap::unmap () { if (munmap (ptr, size) < 0) { gu_throw_error(errno) << "munmap(" << ptr << ", " << size << ") failed"; } mapped = false; log_debug << "Memory unmapped: " << ptr << " (" << size <<" bytes)"; } MMap::~MMap () { if (mapped) unmap(); } } percona-galera-3-3.8-3390/galerautils/src/gu_mmap.hpp000066400000000000000000000010761244131713600222470ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ #ifndef __GCACHE_MMAP__ #define __GCACHE_MMAP__ #include "gu_fdesc.hpp" namespace gu { class MMap { public: size_t const size; void* const ptr; MMap (const FileDescriptor& fd, bool sequential = false); ~MMap (); void dont_need() const; void sync() const; void unmap(); private: bool mapped; // This class is definitely non-copyable MMap (const MMap&); MMap& operator = (const MMap); }; } /* namespace gu */ #endif /* __GCACHE_MMAP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_mmh3.c000066400000000000000000000070761244131713600216220ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file MurmurHash3 implementation * (slightly rewritten from the refrence C++ impl.) * * $Id$ */ #include "gu_mmh3.h" void gu_mmh3_32 (const void* const key, int const len, uint32_t const seed, void* const out) { uint32_t const res = _mmh32_seed (key, len, seed); *((uint32_t*)out) = gu_le32(res); } //----------------------------------------------------------------------------- #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ void gu_mmh3_x86_128 (const void* key, const int len, const uint32_t seed, void* out) { const uint8_t* data = (const uint8_t*)key; const int nblocks = len >> 4; uint32_t h1 = seed; uint32_t h2 = seed; uint32_t h3 = seed; uint32_t h4 = seed; const uint32_t c1 = 0x239b961b; const uint32_t c2 = 0xab0e9789; const uint32_t c3 = 0x38b34ae5; const uint32_t c4 = 0xa1e38b93; //---------- // body const uint32_t* blocks = (const uint32_t*)(data + (nblocks << 4)); int i; for(i = -nblocks; i; i++) { uint32_t k1 = gu_le32(blocks[(i << 2) + 0]); uint32_t k2 = gu_le32(blocks[(i << 2) + 1]); uint32_t k3 = gu_le32(blocks[(i << 2) + 2]); uint32_t k4 = gu_le32(blocks[(i << 2) + 3]); k1 *= c1; k1 = GU_ROTL32(k1,15); k1 *= c2; h1 ^= k1; h1 = GU_ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b; k2 *= c2; k2 = GU_ROTL32(k2,16); k2 *= c3; h2 ^= k2; h2 = GU_ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747; k3 *= c3; k3 = GU_ROTL32(k3,17); k3 *= c4; h3 ^= k3; h3 = GU_ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35; k4 *= c4; k4 = GU_ROTL32(k4,18); k4 *= c1; h4 ^= k4; h4 = GU_ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17; } //---------- // tail const uint8_t * tail = (const uint8_t*)(blocks); uint32_t k1 = 0; uint32_t k2 = 0; uint32_t k3 = 0; uint32_t k4 = 0; switch(len & 15) { case 15: k4 ^= tail[14] << 16; case 14: k4 ^= tail[13] << 8; case 13: k4 ^= tail[12] << 0; k4 *= c4; k4 = GU_ROTL32(k4,18); k4 *= c1; h4 ^= k4; case 12: k3 ^= tail[11] << 24; case 11: k3 ^= tail[10] << 16; case 10: k3 ^= tail[ 9] << 8; case 9: k3 ^= tail[ 8] << 0; k3 *= c3; k3 = GU_ROTL32(k3,17); k3 *= c4; h3 ^= k3; case 8: k2 ^= tail[ 7] << 24; case 7: k2 ^= tail[ 6] << 16; case 6: k2 ^= tail[ 5] << 8; case 5: k2 ^= tail[ 4] << 0; k2 *= c2; k2 = GU_ROTL32(k2,16); k2 *= c3; h2 ^= k2; case 4: k1 ^= tail[ 3] << 24; case 3: k1 ^= tail[ 2] << 16; case 2: k1 ^= tail[ 1] << 8; case 1: k1 ^= tail[ 0] << 0; k1 *= c1; k1 = GU_ROTL32(k1,15); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len; h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; h1 = _mmh3_fmix32(h1); h2 = _mmh3_fmix32(h2); h3 = _mmh3_fmix32(h3); h4 = _mmh3_fmix32(h4); h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; ((uint32_t*)out)[0] = gu_le32(h1); ((uint32_t*)out)[1] = gu_le32(h2); ((uint32_t*)out)[2] = gu_le32(h3); ((uint32_t*)out)[3] = gu_le32(h4); } #endif /* 0 */ //----------------------------------------------------------------------------- void gu_mmh3_x64_128 (const void* key, int len, uint32_t const seed, void* const out) { uint64_t* const res = (uint64_t*)out; _mmh3_128_seed (key, len, seed, seed, res); res[0] = gu_le64(res[0]); res[1] = gu_le64(res[1]); } percona-galera-3-3.8-3390/galerautils/src/gu_mmh3.h000066400000000000000000000246111244131713600216210ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file MurmurHash3 header * * This code is based on the refrence C++ MurMurHash3 implementation by its * author Austin Appleby, who released it to public domain. * * $Id$ */ #ifndef _gu_mmh3_h_ #define _gu_mmh3_h_ #include "gu_byteswap.h" #include // for memset() and memcpy() #ifdef __cplusplus extern "C" { #endif //----------------------------------------------------------------------------- // Finalization mix - force all bits of a hash block to avalanche static GU_FORCE_INLINE uint32_t _mmh3_fmix32 (uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; h *= 0xc2b2ae35; h ^= h >> 16; return h; } static GU_FORCE_INLINE uint64_t _mmh3_fmix64 (uint64_t k) { k ^= k >> 33; k *= GU_ULONG_LONG(0xff51afd7ed558ccd); k ^= k >> 33; k *= GU_ULONG_LONG(0xc4ceb9fe1a85ec53); k ^= k >> 33; return k; } //----------------------------------------------------------------------------- static uint32_t const _mmh3_32_c1 = 0xcc9e2d51; static uint32_t const _mmh3_32_c2 = 0x1b873593; static GU_FORCE_INLINE void _mmh3_block_32 (uint32_t k1, uint32_t* h1) { k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; *h1 ^= k1; *h1 = GU_ROTL32(*h1,13); *h1 *= 5; *h1 += 0xe6546b64; } static GU_FORCE_INLINE void _mmh3_blocks_32 (const uint32_t* const blocks,size_t const nblocks,uint32_t* h1) { //---------- // body size_t i; for (i = 0; i < nblocks; i++) { //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here _mmh3_block_32 (gu_le32(blocks[i]), h1);/* convert from little-endian */ } } static GU_FORCE_INLINE uint32_t _mmh3_tail_32 (const uint8_t* const tail, size_t const len, uint32_t h1) { //---------- // tail #if 0 /* Reference implementation */ uint32_t k1 = 0; switch(len & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; h1 ^= k1; }; #else /* Optimized implementation */ size_t const shift = (len & 3) << 3; if (shift) { uint32_t k1 = gu_le32(((uint32_t*)tail)[0]) & (0x00ffffff>>(24-shift)); k1 *= _mmh3_32_c1; k1 = GU_ROTL32(k1,15); k1 *= _mmh3_32_c2; h1 ^= k1; } #endif /* Optimized implementation */ //---------- // finalization h1 ^= len; h1 = _mmh3_fmix32(h1); return h1; } static GU_FORCE_INLINE uint32_t _mmh32_seed (const void* key, size_t const len, uint32_t seed) { size_t const nblocks = len >> 2; const uint32_t* const blocks = (const uint32_t*)key; const uint8_t* const tail = (const uint8_t*)(blocks + nblocks); _mmh3_blocks_32 (blocks, nblocks, &seed); return _mmh3_tail_32 (tail, len, seed); } // same as FNV32 seed static uint32_t const GU_MMH32_SEED = GU_ULONG(2166136261); /*! A function to hash buffer in one go */ #define gu_mmh32(_buf, _len) \ _mmh32_seed (_buf, _len, GU_MMH32_SEED); /* * 128-bit MurmurHash3 */ static uint64_t const _mmh3_128_c1 = GU_ULONG_LONG(0x87c37b91114253d5); static uint64_t const _mmh3_128_c2 = GU_ULONG_LONG(0x4cf5ad432745937f); static GU_FORCE_INLINE void _mmh3_128_block (uint64_t k1, uint64_t k2, uint64_t* h1, uint64_t* h2) { k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; *h1 ^= k1; *h1 = GU_ROTL64(*h1,27); *h1 += *h2; *h1 *= 5; *h1 += 0x52dce729; k2 *= _mmh3_128_c2; k2 = GU_ROTL64(k2,33); k2 *= _mmh3_128_c1; *h2 ^= k2; *h2 = GU_ROTL64(*h2,31); *h2 += *h1; *h2 *= 5; *h2 += 0x38495ab5; } static GU_FORCE_INLINE void _mmh3_128_blocks (const uint64_t* const blocks, size_t const nblocks, uint64_t* h1, uint64_t* h2) { //---------- // body size_t i; for(i = 0; i < nblocks; i++) { //----------------------------------------------------------------------------- // Block read - if your platform needs to do endian-swapping or can only // handle aligned reads, do the conversion here uint64_t k1 = gu_le64(blocks[i]); i++; uint64_t k2 = gu_le64(blocks[i]); _mmh3_128_block (k1, k2, h1, h2); } } static GU_FORCE_INLINE void _mmh3_128_tail (const uint8_t* const tail, size_t const len, uint64_t h1, uint64_t h2, uint64_t* const out) { //---------- // tail uint64_t k1 = 0; uint64_t k2 = 0; switch(len & 15) { case 15: k2 ^= ((uint64_t)tail[14]) << 48; case 14: k2 ^= ((uint64_t)tail[13]) << 40; case 13: k2 ^= ((uint64_t)tail[12]) << 32; case 12: k2 ^= ((uint64_t)tail[11]) << 24; case 11: k2 ^= ((uint64_t)tail[10]) << 16; case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; case 9: k2 ^= ((uint64_t)tail[ 8]) << 0; k2 *= _mmh3_128_c2; k2 = GU_ROTL64(k2,33); k2 *= _mmh3_128_c1; h2 ^= k2; k1 = gu_le64(((uint64_t*)tail)[0]); k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; h1 ^= k1; break; case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; case 1: k1 ^= ((uint64_t)tail[ 0]) << 0; k1 *= _mmh3_128_c1; k1 = GU_ROTL64(k1,31); k1 *= _mmh3_128_c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h1 += h2; h2 += h1; h1 = _mmh3_fmix64(h1); h2 = _mmh3_fmix64(h2); h1 += h2; h2 += h1; out[0] = h1; out[1] = h2; } static GU_FORCE_INLINE void _mmh3_128_seed (const void* const key, size_t const len, uint64_t s1, uint64_t s2, uint64_t* const out) { size_t const nblocks = (len >> 4) << 1; /* using 64-bit half-blocks */ const uint64_t* const blocks = (const uint64_t*)(key); const uint8_t* const tail = (const uint8_t*)(blocks + nblocks); _mmh3_128_blocks (blocks, nblocks, &s1, &s2); _mmh3_128_tail (tail, len, s1, s2, out); } // same as FNV128 seed static uint64_t const GU_MMH128_SEED1 = GU_ULONG_LONG(0x6C62272E07BB0142); static uint64_t const GU_MMH128_SEED2 = GU_ULONG_LONG(0x62B821756295C58D); /* returns hash in the canonical byte order, as a byte array */ static GU_FORCE_INLINE void gu_mmh128 (const void* const msg, size_t const len, void* const out) { _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, (uint64_t*)out); uint64_t* const res = (uint64_t*)out; res[0] = gu_le64(res[0]); res[1] = gu_le64(res[1]); } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint64_t gu_mmh128_64 (const void* const msg, size_t len) { uint64_t res[2]; _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, res); return res[0]; } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint32_t gu_mmh128_32 (const void* const msg, size_t len) { uint64_t res[2]; _mmh3_128_seed (msg, len, GU_MMH128_SEED1, GU_MMH128_SEED2, res); return (uint32_t)res[0]; } /* * Functions to hash message by parts * (only 128-bit version, 32-bit is not relevant any more) */ typedef struct gu_mmh128_ctx { uint64_t hash[2]; uint64_t tail[2]; size_t length; } gu_mmh128_ctx_t; /*! Initialize/reset MMH context with a particular seed. * The seed is two 8-byte _integers_, obviously in HOST BYTE ORDER. * Should not be used directly. */ static GU_INLINE void _mmh128_init_seed (gu_mmh128_ctx_t* const mmh, uint64_t const s1, uint64_t const s2) { memset (mmh, 0, sizeof(*mmh)); mmh->hash[0] = s1; mmh->hash[1] = s2; } /*! Initialize MMH context with a default Galera seed. */ #define gu_mmh128_init(_mmh) \ _mmh128_init_seed (_mmh, GU_MMH128_SEED1, GU_MMH128_SEED2); /*! Apeend message part to hash context */ static GU_INLINE void gu_mmh128_append (gu_mmh128_ctx_t* const mmh, const void* part, size_t len) { size_t tail_len = mmh->length & 15; mmh->length += len; if (tail_len) /* there's something in the tail */// do we need this if()? { size_t const to_fill = 16 - tail_len; void* const tail_end = (uint8_t*)mmh->tail + tail_len; if (len >= to_fill) /* we can fill a full block */ { memcpy (tail_end, part, to_fill); _mmh3_128_block (gu_le64(mmh->tail[0]), gu_le64(mmh->tail[1]), &mmh->hash[0], &mmh->hash[1]); part = ((char*)part) + to_fill; len -= to_fill; } else { memcpy (tail_end, part, len); return; } } size_t const nblocks = (len >> 4) << 1; /* using 64-bit half-blocks */ const uint64_t* const blocks = (const uint64_t*)(part); _mmh3_128_blocks (blocks, nblocks, &mmh->hash[0], &mmh->hash[1]); /* save possible trailing bytes to tail */ memcpy (mmh->tail, blocks + nblocks, len & 15); } /*! Get the accumulated message hash (does not change the context) */ static GU_INLINE void gu_mmh128_get (const gu_mmh128_ctx_t* const mmh, void* const res) { uint64_t* const r = (uint64_t*)res; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], r); r[0] = gu_le64(r[0]); r[1] = gu_le64(r[1]); } static GU_INLINE uint64_t gu_mmh128_get64 (const gu_mmh128_ctx_t* const mmh) { uint64_t res[2]; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], res); return res[0]; } static GU_INLINE uint32_t gu_mmh128_get32 (const gu_mmh128_ctx_t* const mmh) { uint64_t res[2]; _mmh3_128_tail ((const uint8_t*)mmh->tail, mmh->length, mmh->hash[0], mmh->hash[1], res); return (uint32_t)res[0]; } /* * Below are fuctions with reference signatures for implementation verification */ extern void gu_mmh3_32 (const void* key, int len, uint32_t seed, void* out); #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ extern void gu_mmh3_x86_128 (const void* key, int len, uint32_t seed, void* out); #endif /* 0 */ extern void gu_mmh3_x64_128 (const void* key, int len, uint32_t seed, void* out); #ifdef __cplusplus } #endif #endif /* _gu_mmh3_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_monitor.hpp000066400000000000000000000033061244131713600230020ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! * @file gu_monitor.hpp * * */ #ifndef __GU_MONITOR_HPP__ #define __GU_MONITOR_HPP__ #include #include namespace gu { class Monitor; class Critical; } class gu::Monitor { int mutable refcnt; Mutex mutex; Cond cond; #ifndef NDEBUG pthread_t mutable holder; #endif // copy contstructor and operator= disabled by mutex and cond members. // but on Darwin, we got an error 'class gu::Monitor' has pointer data members // so make non-copyable explicitly Monitor(const Monitor&); void operator=(const Monitor&); public: #ifndef NDEBUG Monitor() : refcnt(0), mutex(), cond(), holder(0) {} #else Monitor() : refcnt(0), mutex(), cond() {} #endif ~Monitor() {} void enter() const { Lock lock(mutex); // Teemu, pthread_equal() check seems redundant, refcnt too (counted in cond) // while (refcnt > 0 && pthread_equal(holder, pthread_self()) == 0) while (refcnt) { lock.wait(cond); } refcnt++; #ifndef NDEBUG holder = pthread_self(); #endif } void leave() const { Lock lock(mutex); assert(refcnt > 0); assert(pthread_equal(holder, pthread_self()) != 0); refcnt--; if (refcnt == 0) { cond.signal(); } } }; class gu::Critical { const Monitor& mon; Critical (const Critical&); Critical& operator= (const Critical&); public: Critical(const Monitor& m) : mon(m) { mon.enter(); } ~Critical() { mon.leave(); } }; #endif /* __GU_MONITOR_HPP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_mutex.c000066400000000000000000000236051244131713600221140ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * Debug versions of thread functions * * $Id$ */ #include #include #include #include "galerautils.h" /* Is it usable? */ static const struct gu_mutex gu_mutex_init = { .target_mutex = PTHREAD_MUTEX_INITIALIZER, .control_mutex = PTHREAD_MUTEX_INITIALIZER, .lock_waiter_count = 0, .cond_waiter_count = 0, .holder_count = 0, .thread = 0, // unknown thread .file = __FILE__, .line = __LINE__ }; int gu_mutex_init_dbg (struct gu_mutex *m, const pthread_mutexattr_t* attr, const char *file, unsigned int line) { m->file = file; m->line = line; m->lock_waiter_count = 0; m->cond_waiter_count = 0; m->holder_count = 0; m->thread = pthread_self(); pthread_mutex_init(&m->control_mutex, NULL); pthread_mutex_init(&m->target_mutex, attr); return 0; // as per pthread spec } int gu_mutex_lock_dbg(struct gu_mutex *m, const char *file, unsigned int line) { int err = 0; pthread_mutex_lock(&m->control_mutex); { if (m->holder_count > 0 && pthread_equal(pthread_self(), m->thread)) { // Have to explicitly submit file and line info as they come // from a totally different place gu_fatal("Second mutex lock attempt by the same thread, %lu, " "at %s:%d, first locked at %s:%d", pthread_self(), file, line, m->file, m->line); assert(0); err = EDEADLK; /* return error in case assert is not defined */ } m->lock_waiter_count++; } /* unlocking control mutex here since we may block waiting for target * mutext and unlocking target mutex again involves locking the control */ pthread_mutex_unlock(&m->control_mutex); if (err) return err; /* request the actual mutex */ if ((err = pthread_mutex_lock(&m->target_mutex))) { /* This i a valid situation - mutex could be destroyed */ gu_debug("%lu mutex lock error (%d: %s) at %s:%d", pthread_self(), err, strerror(err), file, line); return err; } /* need control mutex for info field changes */ if ((err = pthread_mutex_lock(&m->control_mutex))) { // do we need this check - it's only a control mutex? gu_fatal("%lu mutex lock error (%d: %s) at %s:%d", pthread_self(), err, strerror(err), file, line); assert(0); } else { if (gu_likely(m->holder_count == 0)) { m->thread = pthread_self(); m->lock_waiter_count--; m->holder_count++; m->file = file; m->line = line; } else { gu_fatal("Mutex lock granted %d times at %s:%d", m->holder_count, file, line); assert(0); } pthread_mutex_unlock(&m->control_mutex); } /* we have to return 0 here since target mutex was successfully locked */ return 0; } int gu_mutex_unlock_dbg (struct gu_mutex *m, const char *file, unsigned int line) { int err = 0; pthread_mutex_lock(&m->control_mutex); { /** must take into account that mutex unlocking can happen in * cleanup handlers when thread is terminated in cond_wait(). * Then holder_count would still be 0 (see gu_cond_wait()), * but cond_waiter - not */ if (m->holder_count == 0 && m->cond_waiter_count == 0) { gu_fatal ("%lu attempts to unlock unlocked mutex at %s:%d. " "Last use at %s:%d", pthread_self(), file, line, m->file ? m->file : "" , m->line); assert(0); } if (m->holder_count > 0 && !pthread_equal(pthread_self(), m->thread)) { /** last time pthread_t was unsigned long int */ gu_fatal ("%lu attempts to unlock mutex owned by %lu at %s:%d. " "Locked at %s:%d", pthread_self(), m->thread, file, line, m->file, m->line); assert(0); return EPERM; /** return in case assert is undefined */ } err = pthread_mutex_unlock (&m->target_mutex); if (gu_likely(!err)) { m->file = file; m->line = line; m->thread = 0; /* At this point it is difficult to say if we're unlocking * normally or from cancellation handler, if holder_count not 0 - * assume it is normal unlock, otherwise we decrement * cond_waiter_count */ if (gu_likely(m->holder_count)) { m->holder_count--; } else { if (gu_likely(0 != m->cond_waiter_count)) { m->cond_waiter_count--; } else { gu_fatal ("Internal galerautils error: both holder_count " "and cond_waiter_count are 0"); assert (0); } } } else { gu_fatal("Error: (%d,%d) during mutex unlock at %s:%d", err, errno, file, line); assert(0); } } pthread_mutex_unlock(&m->control_mutex); return err; } int gu_mutex_destroy_dbg (struct gu_mutex *m, const char *file, unsigned int line) { int err=0; pthread_mutex_lock(&m->control_mutex); { if (!m->file) { gu_fatal("%lu attempts to destroy uninitialized mutex at %s:%d", pthread_self(), file, line); assert(0); } if (m->holder_count != 0) { if (pthread_self() == m->thread) { gu_fatal ("%lu attempts to destroy mutex locked by " "itself at %s:%d", pthread_self(), m->file, m->line); assert (0); /* logical error in program */ } else { gu_debug("%lu attempts to destroy a mutex at %s:%d " "locked by %lu at %s:%d (not error)", pthread_self(), file, line, m->thread, m->file, m->line); // assert (0); // DELETE when not needed! } } if (m->cond_waiter_count != 0) { gu_debug("%lu attempts to destroy a mutex at %s:%d " "that is waited by %d thread(s)", pthread_self(), file, line, m->cond_waiter_count); assert (m->cond_waiter_count > 0); } if ((err = pthread_mutex_destroy(&m->target_mutex))) { gu_debug("Error (%d: %s, %d) during mutex destroy at %s:%d", err, strerror(err), errno, file, line); pthread_mutex_unlock (&m->control_mutex); return err; } m->file = 0; m->line = 0; m->thread = 0; } pthread_mutex_unlock(&m->control_mutex); while (pthread_mutex_destroy(&m->control_mutex)); return err; } int gu_cond_wait_dbg (pthread_cond_t *cond, struct gu_mutex *m, const char *file, unsigned int line) { int err = 0; // Unfortunately count updates here are not atomic with cond_wait. // But cond_wait() semantics does not allow them to be. pthread_mutex_lock (&m->control_mutex); { if (gu_unlikely(m->holder_count <= 0)) { gu_fatal ("%lu tries to wait for condition on unlocked mutex " "at %s %d", pthread_self(), file, line); assert (0); } else if (!pthread_equal(pthread_self(), m->thread)) { gu_fatal ("%lu tries to wait for condition on the mutex that" "belongs to %lu at %s %d", pthread_self(), m->thread, file, line); assert (0); } /** pthread_cond_wait frees the mutex */ m->holder_count--; m->cond_waiter_count++; m->thread = 0; assert (m->holder_count >= 0); } pthread_mutex_unlock(&m->control_mutex); if ((err = pthread_cond_wait (cond, &m->target_mutex))) { gu_fatal("Error (%d: %s, %d) during cond_wait at %s:%d", err, strerror(err), errno, file, line); assert(0); } pthread_mutex_lock (&m->control_mutex); { /** acquired mutex again */ m->holder_count++; m->cond_waiter_count--; m->thread = pthread_self(); } pthread_mutex_unlock(&m->control_mutex); return err; } #if defined(__APPLE__) int pthread_barrier_init (pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count) { if(count == 0) { errno = EINVAL; return -1; } if(pthread_mutex_init (&barrier->mutex, 0) < 0) { return -1; } if(pthread_cond_init (&barrier->cond, 0) < 0) { pthread_mutex_destroy (&barrier->mutex); return -1; } barrier->tripCount = count; barrier->count = 0; return 0; } int pthread_barrier_destroy (pthread_barrier_t *barrier) { pthread_cond_destroy (&barrier->cond); pthread_mutex_destroy (&barrier->mutex); return 0; } int pthread_barrier_wait (pthread_barrier_t *barrier) { pthread_mutex_lock (&barrier->mutex); ++(barrier->count); if(barrier->count >= barrier->tripCount) { barrier->count = 0; pthread_cond_broadcast (&barrier->cond); pthread_mutex_unlock (&barrier->mutex); return 1; } else { pthread_cond_wait (&barrier->cond, &(barrier->mutex)); pthread_mutex_unlock (&barrier->mutex); return 0; } } #endif /* __APPLE__ */ percona-galera-3-3.8-3390/galerautils/src/gu_mutex.h000066400000000000000000000073351244131713600221230ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy /** * @file Special mutex replacements for debugging/porting * * $Id$ */ #ifndef _gu_mutex_h_ #define _gu_mutex_h_ #include struct gu_mutex { pthread_mutex_t target_mutex; //!< for critical section pthread_mutex_t control_mutex; //!< for mutex operations volatile int lock_waiter_count; //!< # of threads waiting for lock volatile int cond_waiter_count; //!< # of threads waiting for cond volatile int holder_count; //!< must be 0 or 1 volatile pthread_t thread; /* point in source code, where called from */ volatile const char *file; volatile int line; }; /** @name Usual mutex operations storing FILE and LINE information */ /*@{*/ int gu_mutex_init_dbg (struct gu_mutex *mutex, const pthread_mutexattr_t *attr, const char *file, unsigned int line); int gu_mutex_lock_dbg (struct gu_mutex *mutex, const char *file, unsigned int line); int gu_mutex_unlock_dbg (struct gu_mutex *mutex, const char *file, unsigned int line); int gu_mutex_destroy_dbg (struct gu_mutex *mutex, const char *file, unsigned int line); int gu_cond_wait_dbg (pthread_cond_t *cond, struct gu_mutex *mutex, const char *file, unsigned int line); /*@}*/ /** Shorter mutex API for applications. * Depending on compile-time flags application will either use * debug or normal version of the mutex API */ /*@{*/ #ifdef DEBUG_MUTEX typedef struct gu_mutex gu_mutex_t; #define gu_mutex_init(M,A) gu_mutex_init_dbg ((M),(A), __FILE__, __LINE__) #define gu_mutex_lock(M) gu_mutex_lock_dbg ((M), __FILE__, __LINE__) #define gu_mutex_unlock(M) gu_mutex_unlock_dbg ((M), __FILE__, __LINE__) #define gu_mutex_destroy(M) gu_mutex_destroy_dbg((M), __FILE__, __LINE__) #define gu_cond_wait(S,M) gu_cond_wait_dbg ((S),(M), __FILE__, __LINE__) #define GU_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, \ PTHREAD_MUTEX_INITIALIZER, \ 0,0,0,0,0,0 } #else /* DEBUG_MUTEX not defined - use regular pthread functions */ typedef pthread_mutex_t gu_mutex_t; #define gu_mutex_init(M,A) pthread_mutex_init ((M),(A)) #define gu_mutex_lock(M) pthread_mutex_lock ((M)) #define gu_mutex_unlock(M) pthread_mutex_unlock ((M)) #define gu_mutex_destroy(M) pthread_mutex_destroy((M)) #define gu_cond_wait(S,M) pthread_cond_wait ((S),(M)) #define GU_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #endif /* DEBUG_MUTEX */ /*@}*/ /* The following typedefs and macros don't do anything now, * but may be used later */ typedef pthread_t gu_thread_t; typedef pthread_cond_t gu_cond_t; #define gu_thread_create pthread_create #define gu_thread_join pthread_join #define gu_thread_cancel pthread_cancel #define gu_thread_exit pthread_exit #define gu_cond_init pthread_cond_init #define gu_cond_destroy pthread_cond_destroy #define gu_cond_signal pthread_cond_signal #define gu_cond_broadcast pthread_cond_broadcast #define gu_cond_timedwait pthread_cond_timedwait #if defined(__APPLE__) #ifdef __cplusplus extern "C" { #endif typedef int pthread_barrierattr_t; typedef struct { pthread_mutex_t mutex; pthread_cond_t cond; int count; int tripCount; } pthread_barrier_t; int pthread_barrier_init (pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count); int pthread_barrier_destroy (pthread_barrier_t *barrier); int pthread_barrier_wait (pthread_barrier_t *barrier); #ifdef __cplusplus } #endif #endif /* __APPLE__ */ #endif /* _gu_mutex_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_mutex.hpp000066400000000000000000000034301244131713600224530ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GU_MUTEX__ #define __GU_MUTEX__ #include #include #include #include "gu_macros.h" #include "gu_mutex.h" #include "gu_throw.hpp" namespace gu { class Mutex { public: Mutex () : value() { gu_mutex_init (&value, NULL); // always succeeds } ~Mutex () { int err = gu_mutex_destroy (&value); if (gu_unlikely(err != 0)) { gu_throw_error (err) << "pthread_mutex_destroy()"; } } void lock() { gu_mutex_lock(&value); } void unlock() { gu_mutex_unlock(&value); } protected: gu_mutex_t mutable value; private: Mutex (const Mutex&); Mutex& operator= (const Mutex&); friend class Lock; }; class RecursiveMutex { public: RecursiveMutex() : mutex_() { pthread_mutexattr_t mattr; pthread_mutexattr_init(&mattr); pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mutex_, &mattr); pthread_mutexattr_destroy(&mattr); } ~RecursiveMutex() { pthread_mutex_destroy(&mutex_); } void lock() { if (pthread_mutex_lock(&mutex_)) gu_throw_fatal; } void unlock() { if (pthread_mutex_unlock(&mutex_)) gu_throw_fatal; } private: RecursiveMutex(const RecursiveMutex&); void operator=(const RecursiveMutex&); pthread_mutex_t mutex_; }; } #endif /* __GU_MUTEX__ */ percona-galera-3-3.8-3390/galerautils/src/gu_prodcons.cpp000066400000000000000000000034161244131713600231370ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy #include "gu_prodcons.hpp" #include #include using namespace std; class gu::prodcons::MessageQueue { public: MessageQueue() : que() { } bool empty() const { return que.empty(); } size_t size() const { return que.size(); } const Message& front() const { return que.front(); } void pop_front() { que.pop_front(); } void push_back(const Message& msg) { que.push_back(msg); } private: std::deque que; }; void gu::prodcons::Producer::send(const Message& msg, Message* ack) { cons.queue_and_wait(msg, ack); } const gu::prodcons::Message* gu::prodcons::Consumer::get_next_msg() { const Message* ret = 0; Lock lock(mutex); if (mque->empty() == false) { ret = &mque->front(); } return ret; } void gu::prodcons::Consumer::queue_and_wait(const Message& msg, Message* ack) { Lock lock(mutex); mque->push_back(msg); if (mque->size() == 1) { notify(); } lock.wait(msg.get_producer().get_cond()); assert(&rque->front().get_producer() == &msg.get_producer()); if (ack) { *ack = rque->front(); } rque->pop_front(); if (rque->empty() == false) { rque->front().get_producer().get_cond().signal(); } } void gu::prodcons::Consumer::return_ack(const Message& ack) { Lock lock(mutex); assert(&ack.get_producer() == &mque->front().get_producer()); rque->push_back(ack); mque->pop_front(); if (rque->size() == 1) { ack.get_producer().get_cond().signal(); } } gu::prodcons::Consumer::Consumer() : mutex(), mque(new MessageQueue), rque(new MessageQueue) { } gu::prodcons::Consumer::~Consumer() { delete mque; delete rque; } percona-galera-3-3.8-3390/galerautils/src/gu_prodcons.hpp000066400000000000000000000102141244131713600231360ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id:$ */ /*! * @file gu_prodcons.hpp Synchronous producer/consumer interface */ #include "gu_lock.hpp" // For byte_t #include "gu_buffer.hpp" /* Forward declarations */ namespace gu { namespace prodcons { class MessageData; class Message; class MessageQueue; class Producer; class Consumer; } } class gu::prodcons::MessageData { public: virtual ~MessageData() { } }; /*! * @brief Message class for Producer/Consumer communication */ class gu::prodcons::Message { Producer* producer; /*! Producer associated to this message */ int val; /*! Integer value (command/errno) */ const MessageData* data; public: /*! * @brief Constructor * * @param prod_ Producer associated to the message * @param data_ Message data * @param val_ Integer value associated to the message */ Message(Producer* prod_ = 0, const MessageData* data_ = 0, int val_ = -1) : producer(prod_), val(val_), data(data_) { } Message(const Message& msg) : producer(msg.producer), val(msg.val), data(msg.data) { } Message& operator=(const Message& msg) { producer = msg.producer; val = msg.val; data = msg.data; return *this; } /*! * @brief Get producer associated to the message * * @return Producer associated to the message */ Producer& get_producer() const { return *producer; } /*! * @brief Get data associated to the message * * @return Data associated to the message */ const MessageData* get_data() const { return data; } /*! * @brief Get int value associated to the message * * @return Int value associated to the message */ int get_val() const { return val; } }; /*! * @brief Producer interface */ class gu::prodcons::Producer { gu::Cond cond; /*! Condition variable */ Consumer& cons; /*! Consumer associated to this producer */ /*! * @brief Return reference to condition variable * * @return Reference to condition variable */ Cond& get_cond() { return cond; } friend class Consumer; public: /*! * @brief Consturctor * * @param cons_ Consumer associated to this producer */ Producer(Consumer& cons_) : cond(), cons(cons_) { } /*! * @brief Send message to the consumer and wait for response * * @param[in] msg Message to be sent to consumer * @param[out] ack Ack message returned by the Consumer, containing error code */ void send(const Message& msg, Message* ack); }; /*! * @brief Consumer interface */ class gu::prodcons::Consumer { Mutex mutex; /*! Mutex for internal locking */ MessageQueue* mque; /*! Message queue for producer messages */ MessageQueue* rque; /*! Message queue for ack messages */ Consumer(const Consumer&); void operator=(const Consumer&); protected: /*! * @brief Get the first message from the message queue * * Get the first message from the message queue. Note that * this method does not remove the first message from message queue. * * @return Next message from the message queue */ const Message* get_next_msg(); /*! * @brief Return ack message for the producer * * Return ack message for the producer. Note that this method * pops the first message from the message queue. * * @param msg Ack message corresponding the current head of mque */ void return_ack(const Message& msg); /*! * @brief Virtual method to notify consumer about queued message */ virtual void notify() = 0; public: /*! * @brief Default constructor */ Consumer(); /*! * @brief Default destructor */ virtual ~Consumer(); /*! * @brief Queue message and wait for ack * * @param[in] msg Message to be queued * @param[out] ack Ack returned by consumer */ void queue_and_wait(const Message& msg, Message* ack); }; percona-galera-3-3.8-3390/galerautils/src/gu_profile.hpp000066400000000000000000000206061244131713600227550ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // /*! * @file gu_profile.hpp * * @brief Lightweight profiling utility. * * Profiling utility suitable for getting runtime code profile information * with minimal overhead. Macros profile_enter() and profile_leave() * can be inserted around the code and will be expanded to profiling * code if GU_PROFILE is defined. * * Example usage: * @code * * Profile prof("prof"); * * void func() * { * if (is_true()) * { * profile_enter(prof); // This is line 227 * // Do something * // ... * profile_leave(prof); * } * else * { * profile_enter(prof); // This is line 250 * // Do something else * // ... * profile_leave(prof); * } * } * * // Somewhere else in your code * log_info << prof; * @endcode * */ #ifndef GU_PROFILE_HPP #define GU_PROFILE_HPP #include "gu_time.h" #include "gu_datetime.hpp" #include "gu_lock.hpp" #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) #include #elif defined(HAVE_UNORDERED_MAP) #include #elif defined(HAVE_TR1_UNORDERED_MAP) #include #else #include #endif // HAVE_BOOST_UNORDERED_MAP_HPP #include namespace gu { namespace prof { class Key; class KeyHash; class Point; class Profile; std::ostream& operator<<(std::ostream&, const Key&); std::ostream& operator<<(std::ostream&, const Profile&); } } /*! * Profile key storing human readable point description :: * and entry time. */ class gu::prof::Key { public: Key(const char* const file, const char* const func, const int line) : file_(file), func_(func), line_(line) { } bool operator==(const Key& cmp) const { return (line_ == cmp.line_ && func_ == cmp.func_ && file_ == cmp.file_); } bool operator<(const Key& cmp) const { return (line_ < cmp.line_ || (line_ == cmp.line_ && (func_ < cmp.func_ || (func_ == cmp.func_ && file_ < cmp.file_)))); } std::string to_string() const { std::ostringstream os; os << *this; return os.str(); } private: friend class KeyHash; friend class Point; friend class Profile; friend std::ostream& operator<<(std::ostream& os, const Key&); const char* const file_; const char* const func_; const int line_; }; #ifdef HAVE_BOOST_UNORDERED_MAP_HPP class gu::prof::KeyHash { public: size_t operator()(const Key& key) const { return boost::hash_value(key.file_) ^ boost::hash_value(key.func_) ^ boost::hash_value(key.line_); } }; #endif // HAVE_BOOST_UNORDERED_MAP_HPP inline std::ostream& gu::prof::operator<<(std::ostream& os, const gu::prof::Key& key) { return os << key.file_ << ":" << key.func_ << ":" << key.line_; } class gu::prof::Point { public: Point(const Profile& prof, const char* file, const char* func, const int line); ~Point(); private: friend class Profile; const Profile& prof_; const Key key_; mutable long long int enter_time_calendar_; mutable long long int enter_time_thread_cputime_; }; /*! * Profile class for collecting statistics about profile points. */ class gu::prof::Profile { struct PointStats { PointStats(long long int count = 0, long long int time_calendar = 0, long long int time_thread_cputime = 0) : count_ (count ), time_calendar_ (time_calendar ), time_thread_cputime_(time_thread_cputime) { } PointStats operator+(const PointStats& add) const { return PointStats(count_ + add.count_, time_calendar_ + add.time_calendar_, time_thread_cputime_+ add.time_thread_cputime_); } long long int count_; long long int time_calendar_; long long int time_thread_cputime_; }; #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_map Map; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_map Map; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_map Map; #else typedef std::map Map; #endif public: /*! * Default constructor. * * @param name_ Name identifying the profile in ostream output. */ Profile(const std::string& name = "profile") : name_(name), start_time_calendar_(gu_time_calendar()), start_time_thread_cputime_(gu_time_thread_cputime()), mutex_(), points_() { } void enter(const Point& point) const { point.enter_time_calendar_ = gu_time_calendar(); point.enter_time_thread_cputime_ = gu_time_thread_cputime(); gu::Lock lock(mutex_); points_[point.key_].count_++; } void leave(const Point& point) const { long long int t_cal(gu_time_calendar()); long long int t_thdcpu(gu_time_thread_cputime()); gu::Lock lock(mutex_); PointStats& pointst(points_[point.key_]); pointst.time_calendar_ += (t_cal - point.enter_time_calendar_); pointst.time_thread_cputime_ += (t_thdcpu - point.enter_time_thread_cputime_); } void clear() const { gu::Lock lock(mutex_); points_.clear(); } friend std::ostream& operator<<(std::ostream&, const Profile&); std::string const name_; long long int const start_time_calendar_; long long int const start_time_thread_cputime_; gu::Mutex mutex_; mutable Map points_; }; inline gu::prof::Point::Point(const Profile& prof, const char* file, const char* func, const int line) : prof_(prof), key_(file, func, line), enter_time_calendar_(), enter_time_thread_cputime_() { prof_.enter(*this); } inline gu::prof::Point::~Point() { prof_.leave(*this); } // // Ostream operator for Profile class. // inline std::ostream& gu::prof::operator<<(std::ostream& os, const Profile& prof) { Profile::PointStats cumul; char prev_fill(os.fill()); os.fill(' '); os << "\nprofile name: " << prof.name_; os << std::left << std::fixed << std::setprecision(3); os << "\n\n"; os << std::setw(40) << "point"; os << std::setw(10) << "count"; os << std::setw(10) << "calendar"; os << std::setw(10) << "cpu"; os << "\n" << std::setfill('-') << std::setw(70) << "" << std::setfill(' ') << "\n"; for (Profile::Map::const_iterator i = prof.points_.begin(); i != prof.points_.end(); ++i) { os << std::setw(40) << std::left << i->first.to_string(); os << std::right; os << std::setw(10) << i->second.count_; os << std::setw(10) << double(i->second.time_calendar_)*1.e-9; os << std::setw(10) << double(i->second.time_thread_cputime_)*1.e-9; os << std::left; os << "\n"; cumul = cumul + i->second; } os << "\ntot count : " << cumul.count_; os << "\ntot calendar time : " << double(cumul.time_calendar_)*1.e-9; os << "\ntot thread cputime: " << double(cumul.time_thread_cputime_)*1.e-9; os << "\ntot ct since ctor : " << double(gu::datetime::Date::now().get_utc() - prof.start_time_calendar_)*1.e-9; os.fill(prev_fill); return os; } // // Convenience macros for defining profile entry and leave points. // If GU_PROFILE is undefined, these macros expand to no-op. // #ifdef GU_PROFILE #define profile_enter(__p) \ do { \ const gu::prof::Point __point((__p), __FILE__, \ __FUNCTION__, __LINE__); \ #define profile_leave(__p) \ } while (0) #else #define profile_enter(__p) #define profile_leave(__p) #endif // GU_PROFILE #endif // GU_PROFILE_HPP percona-galera-3-3.8-3390/galerautils/src/gu_rand.c000066400000000000000000000017611244131713600216750ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file routines to generate "random" seeds for RNGs by collecting some easy * entropy. * * gu_rand_seed_long() goes for srand48() * * gu_rand_seed_int() goes for srand() and rand_r() * * $Id$ */ #include "gu_rand.h" #include "gu_hash.h" /*! Structure to hold entropy data. * Should be at least 20 bytes on 32-bit systems and 28 bytes on 64-bit */ struct gu_rse { long long time; const void* heap_ptr; const void* stack_ptr; long pid; }; typedef struct gu_rse gu_rse_t; long int gu_rand_seed_long (long long time, const void* heap_ptr, pid_t pid) { gu_rse_t rse = { time, heap_ptr, &time, pid }; return gu_fast_hash64_medium (&rse, sizeof(rse)); } #if GU_WORDSIZE == 32 unsigned int gu_rand_seed_int (long long time, const void* heap_ptr, pid_t pid) { gu_rse_t rse = { time, heap_ptr, &time, pid }; return gu_fast_hash32_short (&rse, sizeof(rse)); } #endif /* GU_WORDSIZE == 32 */ percona-galera-3-3.8-3390/galerautils/src/gu_rand.h000066400000000000000000000012431244131713600216750ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file routines to generate "random" seeds for RNGs by collecting some easy * entropy. * * gu_rand_seed_long() goes for srand48() * * gu_rand_seed_int() goes for srand() and rand_r() * * $Id$ */ #ifndef _gu_rand_h_ #define _gu_rand_h_ #include "gu_arch.h" #include // for pid_t extern long int gu_rand_seed_long (long long time, const void* heap_ptr, pid_t pid); #if GU_WORDSIZE == 32 extern unsigned int gu_rand_seed_int (long long time, const void* heap_ptr, pid_t pid); #else #define gu_rand_seed_int gu_rand_seed_long #endif /* GU_WORDSIZE */ #endif /* _gu_rand_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_regex.cpp000066400000000000000000000022521244131713600224170ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /** * @file Regular expressions parser based on POSIX regex functions in * * $Id$ */ #include "gu_utils.hpp" #include "gu_regex.hpp" namespace gu { using std::string; using std::vector; string RegEx::strerror (int rc) const { char buf[128]; regerror(rc, ®ex, buf, sizeof(buf)); return string (buf); } static inline RegEx::Match regmatch2Match (const string& str, const regmatch_t& rm) { if (rm.rm_so == -1) return RegEx::Match(); return RegEx::Match (str.substr(rm.rm_so, rm.rm_eo - rm.rm_so)); } vector RegEx::match (const string& str, size_t num) const { vector ret; int rc; VLA matches(num); if ((rc = regexec(®ex, str.c_str(), num, &matches, 0))) { gu_throw_error (EINVAL) << "regexec(" << str << "): " << strerror(rc); } for (size_t i = 0; i < num; ++i) { ret.push_back (regmatch2Match (str, matches[i])); } return ret; } } percona-galera-3-3.8-3390/galerautils/src/gu_regex.hpp000066400000000000000000000034441244131713600224300ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy /** * @file Regular expressions parser based on POSIX regex functions in * * $Id$ */ #ifndef _gu_regex_hpp_ #define _gu_regex_hpp_ #include #include #include #include "gu_throw.hpp" namespace gu { class RegEx { regex_t regex; std::string strerror (int rc) const; public: /*! * @param expr regular expression string */ RegEx (const std::string& expr) : regex() { int rc; if ((rc = regcomp(®ex, expr.c_str(), REG_EXTENDED)) != 0) { gu_throw_fatal << "regcomp(" << expr << "): " << strerror(rc); } } ~RegEx () { regfree (®ex); } /*! * This class is to differentiate between an empty and unset strings. * @todo: find a proper name for it and move to gu_utils.hpp */ class Match { std::string value; bool set; public: Match() : value(), set(false) {} Match(const std::string& s) : value(s), set(true) {} // throws NotSet const std::string& str() const { if (set) return value; throw NotSet(); } bool is_set() const { return set; } }; /*! * @brief Matches given string * * @param str string to match with expression * @param num number of matches to return * * @return vector of matched substrings */ std::vector match (const std::string& str, size_t num) const; }; } #endif /* _gu_regex_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_reserved_container.hpp000066400000000000000000000161601244131713600251760ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /*! * ReservedContainer template. It is a wrapper for a container and a reserved * buffer to allocate elements from. * * For more rationale see * http://src.chromium.org/chrome/trunk/src/base/containers/stack_container.h * * It is not called "StackContainer" because it is not only for objects * allocated on the stack. * * $Id$ */ #ifndef _GU_RESERVED_CONTAINER_ #define _GU_RESERVED_CONTAINER_ #include "chromium/aligned_memory.h" #include "gu_logger.hpp" #include // size_t, ptrdiff_t and NULL #include // malloc() and free() #include #include // placement new and std::bad_alloc namespace gu { /*! * ReservedAllocator is an allocator for STL containers that can use a * prealocated buffer (supplied at construction time) for initial container * storage allocation. If the number of elements exceeds buffer capacity, it * overflows to heap. * * Unlike the Chromium code, this does not derive from std::allocator, but * implements the whole thing. * * NOTE1: container must support reserve() method. * * NOTE2: it won't work with containers that require allocator to have default * constructor, like std::basic_string */ template class ReservedAllocator { public: typedef chromium::AlignedBuffer Buffer; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; typedef size_t size_type; // making size_type unsigned int does not seem to reduce footprint typedef ptrdiff_t difference_type; template struct rebind { typedef ReservedAllocator other; }; T* address(T& t) const { return &t; } const T* address(const T& t) const { return &t; } size_type max_size() const { return size_type(-1)/2/sizeof(T); } void construct (T* const p, const T& t) const { new (p) T(t); } void destroy (T* const p) const { p->~T(); } // Storage allocated from this can't be deallocated from other bool operator==(const ReservedAllocator& other) const { return (buffer_ == other.buffer_); } bool operator!=(const ReservedAllocator& other) const { return !(*this == other); } ReservedAllocator(Buffer& buf, size_type n = 0) : buffer_(&buf), used_(n) {} ReservedAllocator(const ReservedAllocator& other) : buffer_(other.buffer_), used_(other.used_) { // log_debug << "Copy ctor\n"; } template ReservedAllocator(const ReservedAllocator&) : buffer_(NULL), used_(reserved) { // log_debug << "Rebinding ctor\n"; } ~ReservedAllocator() {} T* allocate(size_type const n, void* hint = NULL) { if (n == 0) return NULL; if (reserved - used_ >= n /* && buffer_ != NULL */) { assert (buffer_ != NULL); if (diagnostic) { log_info << "Allocating " << n << '/' << (reserved - used_) << " from reserve"; } T* const ret(buffer_->base_ptr() + used_); used_ += n; return ret; } if (n <= max_size()) { if (diagnostic) { log_warn << "Allocating " << n << " from heap"; } void* ret = malloc(n * sizeof(T)); if (NULL != ret) return static_cast(ret); } throw std::bad_alloc(); } void deallocate(T* const p, size_type const n) { if (size_type(p - buffer_->base_ptr()) < reserved) { assert (used_ > 0); if (buffer_->base_ptr() + used_ == p + n) { /* last allocated buffer, can shrink */ used_ -= n; } else { /* cannot recycle reserved space in this case */ assert(p + n <= buffer_->base_ptr() + used_); } } else { free(p); } } size_type used() const { return used_; } private: /* even though we initially allocate buffer in ReservedContainer directly * before this, STL containers insist on copying allocators, so we need * a pointer to buffer to be an explicit member (and waste another 8 bytes*/ Buffer* buffer_; size_type used_; ReservedAllocator& operator=(const ReservedAllocator&); }; /* class ReservedAllocator */ /*! * ReservedContainer is a wrapper for * - fixed size nicely aligned buffer * - ReservedAllocator that uses the buffer * - container type that uses allocator * * the point is to have a container allocated on the stack to use stack buffer * for element storage. */ template class ReservedContainer { public: ReservedContainer() : buffer_ (), /* Actual Allocator instance used by container_ should be * copy-constructed from the temporary passed to container ctor. * Copy-construction preserves pointer to buffer, which is not * temporary. This works at least with std::vector */ container_(Allocator(buffer_)) { /* Make the container use most of the buffer by reserving our buffer * size before doing anything else. */ container_.reserve(reserved); } /* * Getters for the actual container. * * Danger: any copies of this made using the copy constructor must have * shorter lifetimes than the source. The copy will share the same allocator * and therefore the same stack buffer as the original. Use std::copy to * copy into a "real" container for longer-lived objects. */ ContainerType& container() { return container_; } const ContainerType& container() const { return container_; } ContainerType& operator()() { return container_; } const ContainerType& operator()() const { return container_; } /* * Support operator-> to get to the container. * This allows nicer syntax like: * ReservedContainer<...> foo; * std::sort(foo->begin(), foo->end()); */ ContainerType* operator->() { return &container_; } const ContainerType* operator->() const { return &container_; } /* For testing only */ typedef typename ContainerType::value_type ContainedType; const ContainedType* reserved_buffer() const { return buffer_.base_ptr(); } private: typedef ReservedAllocator Allocator; typedef typename Allocator::Buffer Buffer; Buffer buffer_; ContainerType container_; /* Note that container will use another instance of Allocator, copy * constructed from allocator_, so any changes won't be re*/ ReservedContainer(const ReservedContainer&); ReservedContainer& operator=(const ReservedContainer&); }; /* class ReservedContainer */ } /* namespace gu */ #endif /* _GU_RESERVED_CONTAINER_ */ percona-galera-3-3.8-3390/galerautils/src/gu_resolver.cpp000066400000000000000000000334651244131713600231600ustar00rootroot00000000000000// Copyright (C) 2009-2013 Codership Oy #include "gu_resolver.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" #include "gu_throw.hpp" #include "gu_uri.hpp" #include #include #include // for close() #include #include #include #define BSD_COMP /* For SIOCGIFCONF et al on Solaris */ #include #include #include #if defined(__APPLE__) || defined(__FreeBSD__) # include # define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP # define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #else /* !__APPLE__ && !__FreeBSD__ */ extern "C" /* old style cast */ { static int const GU_SIOCGIFCONF = SIOCGIFCONF; static int const GU_SIOCGIFINDEX = SIOCGIFINDEX; } #endif /* !__APPLE__ && !__FreeBSD__ */ //using namespace std; using std::make_pair; // Map from scheme string to addrinfo class SchemeMap { public: typedef std::map Map; typedef Map::const_iterator const_iterator; SchemeMap() : ai_map() { ai_map.insert(make_pair("tcp", get_addrinfo(0, AF_UNSPEC, SOCK_STREAM, 0))); ai_map.insert(make_pair("ssl", get_addrinfo(0, AF_UNSPEC, SOCK_STREAM, 0))); ai_map.insert(make_pair("udp", get_addrinfo(0, AF_UNSPEC, SOCK_DGRAM, 0))); // TODO: } const_iterator find(const std::string& key) const { return ai_map.find(key); } const_iterator end() const { return ai_map.end(); } static const addrinfo* get_addrinfo(const_iterator i) { return &i->second; } private: Map ai_map; struct addrinfo get_addrinfo(int flags, int family, int socktype, int protocol) { struct addrinfo ret = { flags, family, socktype, protocol, #if defined(__FreeBSD__) 0, // FreeBSD gives ENOMEM error with non-zero value #else sizeof(struct sockaddr), #endif 0, 0, 0 }; return ret; } }; static SchemeMap scheme_map; // Helper to copy addrinfo structs. static void copy(const addrinfo& from, addrinfo& to) { to.ai_flags = from.ai_flags; to.ai_family = from.ai_family; to.ai_socktype = from.ai_socktype; to.ai_protocol = from.ai_protocol; to.ai_addrlen = from.ai_addrlen; if (from.ai_addr != 0) { if ((to.ai_addr = reinterpret_cast(malloc(to.ai_addrlen))) == 0) { gu_throw_fatal << "out of memory while trying to allocate " << to.ai_addrlen << " bytes"; } memcpy(to.ai_addr, from.ai_addr, to.ai_addrlen); } to.ai_canonname = 0; to.ai_next = 0; } ///////////////////////////////////////////////////////////////////////// // Sockaddr implementation ///////////////////////////////////////////////////////////////////////// bool gu::net::Sockaddr::is_multicast() const { switch (sa_->sa_family) { case AF_INET: return IN_MULTICAST(ntohl(reinterpret_cast(sa_)->sin_addr.s_addr)); case AF_INET6: return IN6_IS_ADDR_MULTICAST(&reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } bool gu::net::Sockaddr::is_anyaddr() const { switch (sa_->sa_family) { case AF_INET: return (ntohl(reinterpret_cast(sa_)->sin_addr.s_addr) == INADDR_ANY); case AF_INET6: return IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } gu::net::Sockaddr::Sockaddr(const sockaddr* sa, socklen_t sa_len) : sa_ (0 ), sa_len_(sa_len) { if ((sa_ = reinterpret_cast(malloc(sa_len_))) == 0) { gu_throw_fatal; } memcpy(sa_, sa, sa_len_); } gu::net::Sockaddr::Sockaddr(const Sockaddr& s) : sa_ (0 ), sa_len_(s.sa_len_) { if ((sa_ = reinterpret_cast(malloc(sa_len_))) == 0) { gu_throw_fatal; } memcpy(sa_, s.sa_, sa_len_); } gu::net::Sockaddr::~Sockaddr() { free(sa_); } ///////////////////////////////////////////////////////////////////////// // MReq implementation ///////////////////////////////////////////////////////////////////////// static unsigned int get_ifindex_by_addr(const gu::net::Sockaddr& addr) { if (addr.is_anyaddr() == true) { return 0; } unsigned int idx(-1); int err(0); #if defined(__APPLE__) || defined(__FreeBSD__) struct ifaddrs *if_addrs = NULL; struct ifaddrs *if_addr = NULL; if (getifaddrs (&if_addrs) != 0) { err = errno; goto out; } for (if_addr = if_addrs; if_addr != NULL; if_addr = if_addr->ifa_next) { try { gu::net::Sockaddr sa (if_addr->ifa_addr, sizeof (struct sockaddr)); if (sa.get_family () == addr.get_family () && memcmp (sa.get_addr (), addr.get_addr (), addr.get_addr_len ()) == 0) { idx = if_nametoindex (if_addr->ifa_name); goto out; } } catch (gu::Exception& e) { } } out: # else /* !__APPLE__ && !__FreeBSD__ */ struct ifconf ifc; memset(&ifc, 0, sizeof(struct ifconf)); ifc.ifc_len = 16*sizeof(struct ifreq); std::vector ifr(16); ifc.ifc_req = &ifr[0]; int fd(socket(AF_INET, SOCK_DGRAM, 0)); if (fd == -1) { err = errno; gu_throw_error(err) << "could not create socket"; } if ((err = ioctl(fd, GU_SIOCGIFCONF, &ifc)) == -1) { err = errno; goto out; } log_debug << "read: " << ifc.ifc_len; for (size_t i(0); i < ifc.ifc_len/sizeof(struct ifreq); ++i) { struct ifreq* ifrp(&ifr[i]); try { log_debug << "read: " << ifrp->ifr_name; gu::net::Sockaddr sa(&ifrp->ifr_addr, sizeof(struct sockaddr)); if (sa.get_family() == addr.get_family() && memcmp(sa.get_addr(), addr.get_addr(), addr.get_addr_len()) == 0) { if ((err = ioctl(fd, GU_SIOCGIFINDEX, ifrp, sizeof(struct ifreq))) == -1) { err = errno; } #if defined(__linux__) idx = ifrp->ifr_ifindex; #elif defined(__sun__) idx = ifrp->ifr_index; #else # error "Unsupported ifreq structure" #endif goto out; } } catch (gu::Exception& e) { } } out: close(fd); #endif /* !__APPLE__ && !__FreeBSD__ */ if (err != 0) { gu_throw_error(err) << "failed to get interface index"; } else { log_debug << "returning ifindex: " << idx; } return idx; } gu::net::MReq::MReq(const Sockaddr& mcast_addr, const Sockaddr& if_addr) : mreq_ ( 0), mreq_len_ ( 0), ipproto_ ( 0), add_membership_opt_ (-1), drop_membership_opt_(-1), multicast_if_opt_ (-1), multicast_loop_opt_ (-1), multicast_ttl_opt_ (-1) { log_debug << mcast_addr.get_family() << " " << if_addr.get_family(); if (mcast_addr.get_family() != if_addr.get_family()) { gu_throw_fatal << "address families do not match: " << mcast_addr.get_family() << ", " << if_addr.get_family(); } if (mcast_addr.get_family() != AF_INET && mcast_addr.get_family() != AF_INET6) { gu_throw_fatal << "Mreq: address family " << mcast_addr.get_family() << " not supported"; } get_ifindex_by_addr(if_addr); mreq_len_ = (mcast_addr.get_family() == AF_INET ? sizeof(struct ip_mreq) : sizeof(struct ipv6_mreq)); if ((mreq_ = malloc(mreq_len_)) == 0) { gu_throw_fatal << "could not allocate memory"; } memset(mreq_, 0, mreq_len_); switch (mcast_addr.get_family()) { case AF_INET: { struct ip_mreq* mr(reinterpret_cast(mreq_)); mr->imr_multiaddr.s_addr = *reinterpret_cast(mcast_addr.get_addr()); mr->imr_interface.s_addr = *reinterpret_cast(if_addr.get_addr()); ipproto_ = IPPROTO_IP; add_membership_opt_ = IP_ADD_MEMBERSHIP; drop_membership_opt_ = IP_DROP_MEMBERSHIP; multicast_if_opt_ = IP_MULTICAST_IF; multicast_loop_opt_ = IP_MULTICAST_LOOP; multicast_ttl_opt_ = IP_MULTICAST_TTL; break; } case AF_INET6: { struct ipv6_mreq* mr(reinterpret_cast(mreq_)); mr->ipv6mr_multiaddr = *reinterpret_cast(mcast_addr.get_addr()); mr->ipv6mr_interface = get_ifindex_by_addr(if_addr); ipproto_ = IPPROTO_IPV6; add_membership_opt_ = IPV6_ADD_MEMBERSHIP; drop_membership_opt_ = IPV6_DROP_MEMBERSHIP; multicast_loop_opt_ = IPV6_MULTICAST_LOOP; multicast_ttl_opt_ = IPV6_MULTICAST_HOPS; break; } } } gu::net::MReq::~MReq() { free(mreq_); } const void* gu::net::MReq::get_multicast_if_value() const { switch (ipproto_) { case IPPROTO_IP: return &reinterpret_cast(mreq_)->imr_interface; case IPPROTO_IPV6: return &reinterpret_cast(mreq_)->ipv6mr_interface; default: gu_throw_fatal << "get_multicast_if_value() not implemented for: " << ipproto_; } } int gu::net::MReq::get_multicast_if_value_size() const { switch (ipproto_) { case IPPROTO_IP: return sizeof(reinterpret_cast(mreq_)->imr_interface); case IPPROTO_IPV6: return sizeof(reinterpret_cast(mreq_)->ipv6mr_interface); default: gu_throw_fatal << "get_multicast_if_value_size() not implemented for: " << ipproto_; } } ///////////////////////////////////////////////////////////////////////// // Addrinfo implementation ///////////////////////////////////////////////////////////////////////// gu::net::Addrinfo::Addrinfo(const addrinfo& ai) : ai_() { copy(ai, ai_); } gu::net::Addrinfo::Addrinfo(const Addrinfo& ai) : ai_() { copy(ai.ai_, ai_); } gu::net::Addrinfo::Addrinfo(const Addrinfo& ai, const Sockaddr& sa) : ai_() { if (ai.get_addrlen() != sa.get_sockaddr_len()) { gu_throw_fatal; } copy(ai.ai_, ai_); memcpy(ai_.ai_addr, &sa.get_sockaddr(), ai_.ai_addrlen); } gu::net::Addrinfo::~Addrinfo() { free(ai_.ai_addr); } std::string gu::net::Addrinfo::to_string() const { static const size_t max_addr_str_len = (6 /* tcp|udp:// */ + INET6_ADDRSTRLEN + 2 /* [] */ + 6 /* :portt */); std::string ret; ret.reserve(max_addr_str_len); Sockaddr addr(ai_.ai_addr, ai_.ai_addrlen); switch (get_socktype()) { case SOCK_STREAM: ret += "tcp://"; break; case SOCK_DGRAM: ret += "udp://"; break; default: gu_throw_error(EINVAL) << "invalid socktype: " << get_socktype(); } char dst[INET6_ADDRSTRLEN + 1]; if (inet_ntop(get_family(), addr.get_addr(), dst, sizeof(dst)) == 0) { gu_throw_error(errno) << "inet ntop failed"; } switch (get_family()) { case AF_INET: ret += dst; break; case AF_INET6: ret += "["; ret += dst; ret += "]"; break; default: gu_throw_error(EINVAL) << "invalid address family: " << get_family(); } ret += ":" + gu::to_string(ntohs(addr.get_port())); ret.reserve(0); // free unused space if possible return ret; } ///////////////////////////////////////////////////////////////////////// // Public methods ///////////////////////////////////////////////////////////////////////// gu::net::Addrinfo gu::net::resolve(const URI& uri) { SchemeMap::const_iterator i(scheme_map.find(uri.get_scheme())); if (i == scheme_map.end()) { gu_throw_error(EINVAL) << "invalid scheme: " << uri.get_scheme(); } try { std::string host(uri.get_host()); // remove [] if this is IPV6 address size_t pos(host.find_first_of('[')); if (pos != std::string::npos) { host.erase(pos, pos + 1); pos = host.find_first_of(']'); if (pos == std::string::npos) { gu_throw_error(EINVAL) << "invalid host: " << uri.get_host(); } host.erase(pos, pos + 1); } int err; addrinfo* ai(0); try { err = getaddrinfo(host.c_str(), uri.get_port().c_str(), SchemeMap::get_addrinfo(i), &ai); } catch (NotSet&) { err = getaddrinfo(host.c_str(), NULL, SchemeMap::get_addrinfo(i), &ai); } if (err != 0) { // Use EHOSTUNREACH as generic error number in case errno // is zero. Real error should be apparent from exception message gu_throw_error(errno == 0 ? EHOSTUNREACH : errno) << "getaddrinfo failed with error '" << gai_strerror(err) << "' (" << err << ") for " << uri.to_string(); } // Assume that the first entry is ok Addrinfo ret(*ai); freeaddrinfo(ai); return ret; } catch (NotFound& nf) { gu_throw_error(EINVAL) << "invalid URI: " << uri.to_string(); } } percona-galera-3-3.8-3390/galerautils/src/gu_resolver.hpp000066400000000000000000000164471244131713600231660ustar00rootroot00000000000000/* * Copyright (C) 2008-2012 Codership Oy * * $Id$ */ /*! * @file gu_resolver.hpp Simple resolver utility */ #ifndef __GU_RESOLVER_HPP__ #define __GU_RESOLVER_HPP__ #include "gu_throw.hpp" #include #include #include #include // Forward declarations namespace gu { class URI; } // namespace gu // Declarations namespace gu { namespace net { /*! * @class Sockaddr * * @brief Class encapsulating struct sockaddr. * * Class encapsulating struct sockaddr and providing * simple interface to access sockaddr fields. */ class Sockaddr; /*! * @class IMReq * * @brief Class encapsulating imreq structs. */ class MReq; /*! * @class Addrinfo * * @brief Class encapsulating struct addrinfo. * * Class encapsulating struct addrinfo and providing interface * to access addrinfo fields. */ class Addrinfo; /*! * Resolve address given in @uri * * @return Addrinfo object representing address * * @throw gu::Exception in case of failure */ Addrinfo resolve(const gu::URI& uri); } // namespace net } // namespace gu class gu::net::Sockaddr { public: /*! * Default constuctor. * * @param sa Pointer to sockaddr struct * @param sa_len Length of sockaddr struct */ Sockaddr(const sockaddr* sa, socklen_t sa_len); /*! * Copy constructor. * * @param sa Reference to Sockaddr */ Sockaddr(const Sockaddr& sa); /*! * Destructor */ ~Sockaddr(); /*! * Get address family. * * @return Address family */ sa_family_t get_family() const { return sa_->sa_family; } /*! * Get port in network byte order. This is applicable only * for AF_INET, AF_INET6. * * @return Port in nework byte order */ unsigned short get_port() const { switch(sa_->sa_family) { case AF_INET: return reinterpret_cast(sa_)->sin_port; case AF_INET6: return reinterpret_cast(sa_)->sin6_port; default: gu_throw_fatal; } } /*! * Get pointer to address. Return value is pointer to void, * user must do casting by himself. * * @todo: Figure out how this could be done in type safe way. * * @return Void pointer to address element. */ const void* get_addr() const { switch(sa_->sa_family) { case AF_INET: return &reinterpret_cast(sa_)->sin_addr; case AF_INET6: return &reinterpret_cast(sa_)->sin6_addr; default: gu_throw_fatal << "invalid address family: " << sa_->sa_family; } } socklen_t get_addr_len() const { switch(sa_->sa_family) { case AF_INET: return sizeof(reinterpret_cast(sa_)->sin_addr); case AF_INET6: return sizeof(reinterpret_cast(sa_)->sin6_addr); default: gu_throw_fatal; } } /*! * Get non-const reference to sockaddr struct. * * @return Non-const reference to sockaddr struct. */ sockaddr& get_sockaddr() { return *sa_; } /*! * Get const reference to sockaddr struct. * * @return Const reference to sockaddr struct. */ const sockaddr& get_sockaddr() const { return *sa_; } /*! * Get length of sockaddr struct. * * @return Length of sockaddr struct */ socklen_t get_sockaddr_len() const { return sa_len_; } bool is_multicast() const; bool is_broadcast() const; bool is_anyaddr() const; static Sockaddr get_anyaddr(const Sockaddr& sa) { Sockaddr ret(sa); switch(ret.sa_->sa_family) { case AF_INET: reinterpret_cast(ret.sa_)->sin_addr.s_addr = 0; break; case AF_INET6: memset(&reinterpret_cast(ret.sa_)->sin6_addr, 0, sizeof(struct in6_addr)); break; default: gu_throw_fatal << "invalid address family: " << ret.sa_->sa_family; } return ret; } Sockaddr& operator=(const Sockaddr& sa) { memcpy(sa_, sa.sa_, sa_len_); return *this; } private: sockaddr* sa_; socklen_t sa_len_; }; class gu::net::MReq { public: MReq(const Sockaddr& mcast_addr, const Sockaddr& if_addr); ~MReq(); const void* get_mreq() const { return mreq_; } socklen_t get_mreq_len() const { return mreq_len_; } int get_ipproto() const { return ipproto_; } int get_add_membership_opt() const { return add_membership_opt_; } int get_drop_membership_opt() const { return drop_membership_opt_; } int get_multicast_if_opt() const { return multicast_if_opt_; } int get_multicast_loop_opt() const { return multicast_loop_opt_; } int get_multicast_ttl_opt() const { return multicast_ttl_opt_; } const void* get_multicast_if_value() const; int get_multicast_if_value_size() const; private: MReq(const MReq&); void operator=(const MReq&); void* mreq_; socklen_t mreq_len_; int ipproto_; int add_membership_opt_; int drop_membership_opt_; int multicast_if_opt_; int multicast_loop_opt_; int multicast_ttl_opt_; }; class gu::net::Addrinfo { public: /*! * Default constructor. * * @param ai Const reference to addrinfo struct */ Addrinfo(const addrinfo& ai); /*! * Copy costructor. * * @param ai Const reference to Addrinfo object to copy */ Addrinfo(const Addrinfo& ai); /*! * Copy constructor that replaces @ai sockaddr struct. * * @param ai Const reference to Addrinfo object to copy * @param sa Const reference to Sockaddr struct that replaces * @ai sockaddr data */ Addrinfo(const Addrinfo& ai, const Sockaddr& sa); /*! * Destructor. */ ~Addrinfo(); /*! * Get address family, AF_INET, AF_INET6 etc. * * @return Address family */ int get_family() const { return ai_.ai_family; } /*! * Get socket type, SOCK_STREAM, SOCK_DGRAM etc * * @return Socket type */ int get_socktype() const { return ai_.ai_socktype; } /*! * Get protocol. * * @return Protocol */ int get_protocol() const { return ai_.ai_protocol; } /*! * Get length of associated sockaddr struct * * @return Length of associated sockaddr struct */ socklen_t get_addrlen() const { return ai_.ai_addrlen; } /*! * Get associated Sockaddr object. * * @return Associated Sockaddr object */ Sockaddr get_addr() const { return Sockaddr(ai_.ai_addr, ai_.ai_addrlen); } /*! * Get string representation of the addrinfo. * * @return String representation of the addrinfo */ std::string to_string() const; private: addrinfo ai_; }; #endif /* __GU_RESOLVER_HPP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_rset.cpp000066400000000000000000000255461244131713600222750ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /*! * @file common RecordSet implementation * * Record set is a collection of serialized records of the same type. * * It stores them in an iovec-like collection of buffers before sending * and restores from a single buffer when receiving. * * $Id$ */ #include "gu_rset.hpp" #include "gu_vlq.hpp" #include "gu_hexdump.hpp" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_hash.h" #include namespace gu { void RecordSetOutBase::post_alloc (bool const new_page, const byte_t* const ptr, ssize_t const size) { if (new_page) { Buf b = { ptr, size }; bufs_->push_back (b); } else { bufs_->back().size += size; } size_ += size; } void RecordSetOutBase::post_append (bool const new_page, const byte_t* const ptr, ssize_t const size) { check_.append (ptr, size); post_alloc (new_page, ptr, size); } static int check_size (RecordSet::CheckType const ct) { switch (ct) { case RecordSet::CHECK_NONE: return 0; case RecordSet::CHECK_MMH32: return 4; case RecordSet::CHECK_MMH64: return 8; case RecordSet::CHECK_MMH128: return 16; #define MAX_CHECKSUM_SIZE 16 } log_fatal << "Non-existing RecordSet::CeckType value: " << ct; abort(); } #define VER1_CRC_SIZE sizeof(uint32_t) static int header_size_max_v0() { return 1 + /* version + checksum type */ 9 + /* max payload size in vlq format */ 9 + /* max record count in vlq format */ VER1_CRC_SIZE; /* header checksum */ } int RecordSetOutBase::header_size_max() const { switch (version_) { case EMPTY: assert (0); break; case VER1: return header_size_max_v0(); } log_fatal << "Unsupported RecordSet::Version value: " << version_; abort(); } static int header_size_v1(ssize_t size, ssize_t const count) { int hsize = header_size_max_v0(); assert (size > hsize); assert (count > 0); /* need to converge on the header size as it depends on the total size */ do { int new_hsize = 1 + /* version + checksum type */ uleb128_size(size) + /* size in vlq format */ uleb128_size(count) + /* count in vlq format */ VER1_CRC_SIZE; /* header checksum */ assert (new_hsize <= hsize); if (new_hsize == hsize) break; size -= hsize - new_hsize; hsize = new_hsize; } while (true); assert (hsize > 0); assert (size > hsize); return hsize; } int RecordSetOutBase::header_size() const { switch (version_) { case EMPTY: assert(0); break; case VER1: return header_size_v1 (size_, count_); } log_fatal << "Unsupported RecordSet::Version value: " << version_; abort(); } ssize_t RecordSetOutBase::write_header (byte_t* const buf, ssize_t const size) { int const csize(check_size(check_type_)); assert (header_size_max() + csize <= size); ssize_t const hdr_offset(header_size_max() - header_size()); assert (hdr_offset >= 0); size_ -= hdr_offset; int off(hdr_offset); buf[off] = (static_cast(version_) << 4) | /* upper 4 bytes: ver */ (static_cast(check_type_) & 0x0f); off += 1; off += uleb128_encode(size_, buf + off, size - off); off += uleb128_encode(count_, buf + off, size - off); /* write header CRC */ uint32_t const crc(gu_fast_hash32(buf + hdr_offset, off - hdr_offset)); *(reinterpret_cast(buf + off)) = htog(crc); off += VER1_CRC_SIZE; /* append payload checksum */ if (check_type_ != CHECK_NONE) { assert (csize <= size - off); check_.append (buf + hdr_offset, off - hdr_offset); /* append header */ check_.gather (buf + off, csize); } return hdr_offset; } ssize_t RecordSetOutBase::gather (GatherVector& out) { if (count_) { byte_t* const ptr = reinterpret_cast(const_cast(bufs_->front().ptr)); ssize_t const offset = write_header (ptr, bufs_->front().size); bufs_->front().ptr = ptr + offset; bufs_->front().size -= offset; // size_ is taken care of in write_header() out->insert (out->end(), bufs_->begin(), bufs_->end()); return size_; } else { return 0; } } RecordSet::RecordSet (Version ver, CheckType const ct) : size_ (0), count_ (0), version_ (ver), check_type_(ct) { if (gu_unlikely(uint(version_) > MAX_VERSION)) { gu_throw_error (EPROTO) << "Unsupported header version: " << version_; } } RecordSetOutBase::RecordSetOutBase (byte_t* reserved, size_t reserved_size, const BaseName& base_name, CheckType const ct, Version const version #ifdef GU_RSET_CHECK_SIZE ,ssize_t const max_size #endif ) : RecordSet (version, ct), #ifdef GU_RSET_CHECK_SIZE max_size_ (max_size), #endif alloc_ (base_name, reserved, reserved_size), check_ (), bufs_ (), prev_stored_(true) { /* reserve space for header */ size_ = header_size_max() + check_size(check_type_); bool unused; byte_t* ptr = alloc_.alloc (size_, unused); Buf b = { ptr, size_ }; bufs_->push_back (b); } static inline RecordSet::Version header_version (const byte_t* buf, ssize_t const size) { assert (NULL != buf); assert (size > 0); uint const ver((buf[0] & 0xf0) >> 4); assert (ver > 0); if (gu_likely(ver <= RecordSet::MAX_VERSION)) return static_cast(ver); gu_throw_error (EPROTO) << "Unsupported RecordSet version: " << ver; } static inline RecordSet::CheckType ver1_check_type (const byte_t* buf, ssize_t const size) { assert (size > 0); int const ct(buf[0] & 0x0f); switch (ct) { case RecordSet::CHECK_NONE: return RecordSet::CHECK_NONE; case RecordSet::CHECK_MMH32: return RecordSet::CHECK_MMH32; case RecordSet::CHECK_MMH64: return RecordSet::CHECK_MMH64; case RecordSet::CHECK_MMH128: return RecordSet::CHECK_MMH128; } gu_throw_error (EPROTO) << "Unsupported RecordSet checksum type: " << ct; } static inline RecordSet::CheckType header_check_type(RecordSet::Version ver, const byte_t* ptr, ssize_t const size) { assert (size > 0); switch (ver) { case RecordSet::EMPTY: assert(0); return RecordSet::CHECK_NONE; case RecordSet::VER1: return ver1_check_type (ptr, size); } gu_throw_error (EPROTO) << "Unsupported RecordSet version: " << ver; } void RecordSet::init (const byte_t* const ptr, ssize_t const size) { assert (EMPTY == version_); assert (size >= 0); assert (NULL != ptr || 0 == size); assert (NULL == ptr || 0 != size); if (gu_likely ((ptr && size))) { version_ = header_version (ptr, size); check_type_ = header_check_type (version_, ptr, size); } } void RecordSetInBase::parse_header_v1 (size_t const size) { assert (size > 1); int off = 1; off += uleb128_decode (head_ + off, size - off, size_); if (gu_unlikely(static_cast(size_) > static_cast(size))) { gu_throw_error (EPROTO) << "RecordSet size " << size_ << " exceeds buffer size " << size << "\nfirst 4 bytes: " << gu::Hexdump(head_, 4); } off += uleb128_decode (head_ + off, size - off, count_); if (gu_unlikely(static_cast(size_) < static_cast(count_))) { gu_throw_error (EPROTO) << "Corrupted RecordSet header: count " << count_ << " exceeds size " << size_; } /* verify header CRC */ uint32_t const crc_comp(gu_fast_hash32(head_, off)); uint32_t const crc_orig( gtoh(*(reinterpret_cast(head_ + off)))); if (gu_unlikely(crc_comp != crc_orig)) { gu_throw_error (EPROTO) << "RecordSet header CRC mismatch: " << std::showbase << std::internal << std::hex << std::setfill('0') << std::setw(10) << "\ncomputed: " << crc_comp << "\nfound: " << crc_orig << std::dec; } off += VER1_CRC_SIZE; /* checksum is between header and records */ begin_ = off + check_size(check_type_); } /* returns false if checksum matched and true if failed */ void RecordSetInBase::checksum() const { int const cs(check_size(check_type_)); if (cs > 0) /* checksum records */ { Hash check; check.append (head_ + begin_, size_ - begin_); /* records */ check.append (head_, begin_ - cs); /* header */ assert(cs <= MAX_CHECKSUM_SIZE); byte_t result[MAX_CHECKSUM_SIZE]; check.gather(result); const byte_t* const stored_checksum(head_ + begin_ - cs); if (gu_unlikely(memcmp (result, stored_checksum, cs))) { gu_throw_error(EINVAL) << "RecordSet checksum does not match:" << "\ncomputed: " << gu::Hexdump(result, cs) << "\nfound: " << gu::Hexdump(stored_checksum, cs); } } } RecordSetInBase::RecordSetInBase (const byte_t* const ptr, size_t const size, bool const check_now) : RecordSet (), head_ (), next_ (), begin_ () { init (ptr, size, check_now); } void RecordSetInBase::init (const byte_t* const ptr, size_t const size, bool const check_now) { assert (EMPTY == version_); RecordSet::init (ptr, size); head_ = ptr; switch (version_) { case EMPTY: return; case VER1: parse_header_v1(size); // should set begin_ } if (check_now) checksum(); next_ = begin_; assert (size_ > 0); assert (count_ >= 0); assert (count_ <= size_); assert (begin_ > 0); assert (begin_ <= size_); assert (next_ == begin_); } void RecordSetInBase::throw_error (Error code) const { switch (code) { case E_PERM: gu_throw_error (EPERM) << "Access beyond record set end."; case E_FAULT: gu_throw_error (EFAULT) << "Corrupted record set: record extends " << next_ << " beyond set boundary " << size_; } log_fatal << "Unknown error in RecordSetIn."; abort(); } } /* namespace gu */ percona-galera-3-3.8-3390/galerautils/src/gu_rset.hpp000066400000000000000000000261601244131713600222730ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy */ /*! * @file common RecordSet interface * * Record set is a collection of serialized records of the same type. * * It stores them in an iovec-like collection of buffers before sending * and restores from a single buffer when receiving. * * $Id$ */ #ifndef _GU_RSET_HPP_ #define _GU_RSET_HPP_ #include "gu_vector.hpp" #include "gu_alloc.hpp" #include "gu_digest.hpp" #ifdef GU_RSET_CHECK_SIZE # include "gu_throw.hpp" #endif #include namespace gu { class RecordSet { public: enum Version { EMPTY = 0, VER1 }; static Version const MAX_VERSION = VER1; enum CheckType { CHECK_NONE = 0, CHECK_MMH32, CHECK_MMH64, CHECK_MMH128 }; /*! return total size of a RecordSet */ size_t size() const { return size_; } /*! return number of records in the record set */ int count() const { return count_; } typedef gu::Vector GatherVector; protected: ssize_t size_; int count_; Version version_; CheckType check_type_; /* ctor for RecordSetOut */ RecordSet (Version const version, CheckType const ct); /* ctor for RecordSetIn */ RecordSet () : size_(0), count_(0), version_(EMPTY), check_type_(CHECK_NONE) {} void init (const byte_t* buf, ssize_t size); ~RecordSet() {} }; #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic push # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic ignored "-Weffc++" #endif /*! class to store records in buffer(s) to send out */ class RecordSetOutBase : public RecordSet { public: typedef Allocator::BaseName BaseName; /*! return number of disjoint pages in the record set */ ssize_t page_count() const { return bufs_->size(); } /*! return vector of RecordSet fragments in adjusent order */ ssize_t gather (GatherVector& out); protected: RecordSetOutBase() : RecordSet() {} RecordSetOutBase (byte_t* reserved, size_t reserved_size, const BaseName& base_name, /* basename for on-disk * allocator */ CheckType ct, Version version = MAX_VERSION #ifdef GU_RSET_CHECK_SIZE ,ssize_t max_size = 0x7fffffff #endif ); /* this is to emulate partial specialization of function template through * overloading by parameter */ template struct HasPtr{}; /* variant for classes that don't provide ptr() method and need to be * explicitly serialized to internal storage */ template void process (const R& record, const byte_t*& ptr, bool& new_page, size_t const size, bool, HasPtr) { byte_t* const dst(alloc_.alloc (size, new_page)); new_page = (new_page || !prev_stored_); ptr = dst; #ifdef NDEBUG record.serialize_to (dst, size); #else size_t const ssize (record.serialize_to (dst, size)); assert (ssize == size); #endif } /* variant for classes that have ptr() method and can be either serialized * or referenced */ template void process (const R& record, const byte_t*& ptr, bool& new_page, size_t const size, bool const store, HasPtr) { if (store) { process (record, ptr, new_page, size, true, HasPtr()); } else { ptr = record.ptr(); new_page = true; } } template std::pair append_base (const R& record, bool const store = true, bool const new_record = true) { ssize_t const size (record.serial_size()); #ifdef GU_RSET_CHECK_SIZE if (gu_unlikely(size > max_size_ - size_)) gu_throw_error(EMSGSIZE); #endif bool new_page; const byte_t* ptr; process (record, ptr, new_page, size, store, HasPtr()); prev_stored_ = store; // make sure there is at least one record count_ += new_record || (0 == count_); post_append (new_page, ptr, size); return std::pair(ptr, size); } private: #ifdef GU_RSET_CHECK_SIZE ssize_t const max_size_; #endif Allocator alloc_; Hash check_; Vector bufs_; bool prev_stored_; void post_alloc (bool const new_page, const byte_t* const ptr, ssize_t const size); void post_append (bool const new_page, const byte_t* const ptr, ssize_t const size); int header_size () const; int header_size_max () const; /* Writes the header to the end of provided buffer, returns header * offset from ptr */ ssize_t write_header (byte_t* ptr, ssize_t size); }; /*! This is a small wrapper template for RecordSetOutBase to avoid templating * the whole thing instead of just the two append methods. */ template class RecordSetOut : public RecordSetOutBase { public: typedef RecordSetOutBase::BaseName BaseName; RecordSetOut() : RecordSetOutBase() {} RecordSetOut (byte_t* reserved, size_t reserved_size, const BaseName& base_name, CheckType ct, Version version = MAX_VERSION #ifdef GU_RSET_CHECK_SIZE ,ssize_t max_size = 0x7fffffff #endif ) : RecordSetOutBase (reserved, reserved_size, base_name, ct, version #ifdef GU_RSET_CHECK_SIZE ,max_size #endif ) {} std::pair append (const R& r) { return append_base (r); // return append_base (r); old append_base() method } std::pair append (const void* const src, ssize_t const size, bool const store = true, bool const new_record = true) { assert (src); assert (size); BufWrap bw (src, size); return append_base (bw, store, new_record); // return append_base (src, size, store); - old append_base() method } private: /*! a wrapper class to represent ptr and size as a serializable object: * simply defines serial_size(), ptr() and serialize_to() methods */ class BufWrap { const byte_t* const ptr_; size_t const size_; public: BufWrap (const void* const ptr, size_t const size) : ptr_(reinterpret_cast(ptr)), size_(size) {} size_t serial_size() const { return size_; } const byte_t* ptr() const { return ptr_; } size_t serialize_to (byte_t* const dst, size_t) const { ::memcpy (dst, ptr_, size_); return size_; } }; RecordSetOut (const RecordSetOut&); RecordSetOut& operator = (const RecordSetOut&); }; /*! class to recover records from a buffer */ class RecordSetInBase : public RecordSet { public: RecordSetInBase (const byte_t* buf,/* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_now = true); /* checksum now */ /* this is a "delayed constructor", for the object created empty */ void init (const byte_t* buf, /* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_now = true); /* checksum now */ void rewind() const { next_ = begin_; } void checksum() const; // throws if checksum fails gu::Buf buf() const { gu::Buf ret = { head_, size_ }; return ret; } protected: template void next_base (Buf& n) const { if (gu_likely (next_ < size_)) { size_t const next_size(R::serial_size(head_ + next_, size_ -next_)); /* sanity check */ if (gu_likely (next_ + next_size <= size_t(size_))) { n.ptr = head_ + next_; n.size = next_size; next_ += next_size; return; } throw_error (E_FAULT); } assert (next_ == size_); throw_error (E_PERM); } template R next_base () const { if (gu_likely (next_ < size_)) { R const rec(head_ + next_, size_ - next_); size_t const tmp_size(rec.serial_size()); /* sanity check */ if (gu_likely (next_ + tmp_size <= size_t(size_))) { next_ += tmp_size; return rec; } throw_error (E_FAULT); } assert (next_ == size_); throw_error (E_PERM); } private: const byte_t* head_; /* pointer to header */ ssize_t mutable next_; /* offset to next record */ short begin_; /* offset to first record */ /* size_ from parent class is offset past all records */ /* takes total size of the supplied buffer */ void parse_header_v1 (size_t size); enum Error { E_PERM, E_FAULT }; GU_NORETURN void throw_error (Error code) const; /* shallow copies here - we're not allocating anything */ RecordSetInBase (const RecordSetInBase& r) : RecordSet (r), head_ (r.head_), next_ (r.next_), begin_ (r.begin_) {} RecordSetInBase& operator= (const RecordSetInBase r); #if 0 { std::swap(head_, r.head_); std::swap(next_, r.next_); std::swap(begin, r.begin_); } #endif }; /* class RecordSetInBase */ /*! This is a small wrapper template for RecordSetInBase to avoid templating * the whole thing instead of just the two next methods. */ template class RecordSetIn : public RecordSetInBase { public: RecordSetIn (const void* buf,/* pointer to the beginning of buffer */ size_t size, /* total size of buffer */ bool check_first = true) /* checksum now */ : RecordSetInBase (reinterpret_cast(buf), size, check_first) {} RecordSetIn () : RecordSetInBase (NULL, 0, false) {} void next (Buf& n) const { next_base (n); } R next () const { return next_base (); } }; /* class RecordSetIn */ #if defined(__GNUG__) # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) # pragma GCC diagnostic pop # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || (__GNUC__ > 4) #endif } /* namespace gu */ #endif /* _GU_RSET_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_serializable.hpp000066400000000000000000000060311244131713600237570ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file Declaration of serializeble interface that all serializable classes * should inherit. * * $Id$ */ #ifndef GU_SERIALIZABLE_HPP #define GU_SERIALIZABLE_HPP #include "gu_types.hpp" #include "gu_throw.hpp" #include "gu_assert.hpp" #include #include // for std::length_error namespace gu { class Serializable { public: /*! returns the size of a buffer required to serialize the object */ ssize_t serial_size () const { return my_serial_size(); } /*! * serializes this object into buf and returns serialized size * * @param buf pointer to buffer * @param size size of buffer * @return serialized size * * may throw exceptions */ ssize_t serialize_to (void* const buf, ssize_t const size) const { return my_serialize_to (buf, size); } /*! * serializes this object into byte vector v, reallocating it if needed * returns the size of serialized object */ ssize_t serialize_to (std::vector& v) const { size_t const old_size (v.size()); size_t const new_size (serial_size() + old_size); try { v.resize (new_size, 0); } catch (std::length_error& l) { gu_throw_error(EMSGSIZE) << "length_error: " << l.what(); } catch (...) { gu_throw_error(ENOMEM) << "could not resize to " << new_size << " bytes"; } try { return serialize_to (&v[old_size], new_size - old_size); } catch (...) { v.resize (old_size); throw; } } protected: ~Serializable() {} private: virtual ssize_t my_serial_size () const = 0; virtual ssize_t my_serialize_to (void* buf, ssize_t size) const = 0; }; static inline std::vector& operator << (std::vector& out, const Serializable& s) { s.serialize_to (out); return out; } #if 0 // seems to be a pointless idea class DeSerializable { public: /* serial size of an object stored at ptr, may be not implemented */ template static ssize_t serial_size (const byte_t* const buf, ssize_t const size) { assert (size > 0); return DS::my_serial_size (buf, size); } /* serial size of an object stored at ptr, may be not implemented */ ssize_t deserialize_from (const byte_t* const buf, ssize_t const size) { assert (size > 0); return my_deserialize_from (buf, size); } ssize_t deserialize_from (const std::vector& in,size_t const offset) { return deserialize_from (&in[offset], in.size() - offset); } protected: ~DeSerializable() {} private: /* serial size of an object stored at ptr, may be not implemented */ virtual ssize_t my_deserialize_from (const byte_t* buf, ssize_t size) = 0; }; #endif // 0 } /* namespace gu */ #endif /* GU_SERIALIZABLE_HPP */ percona-galera-3-3.8-3390/galerautils/src/gu_serialize.hpp000066400000000000000000000255701244131713600233110ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ /*! * @file Helper templates for serialization/unserialization. * As we are usually working on little endian platforms, integer * storage order is little-endian - in other words we use "Galera" * order, which is by default little-endian. * * What is going on down there? Templates are good. However we do * not serialize the value of size_t variable into sizeof(size_t) * bytes. We serialize it into a globally consistent, fixed number * of bytes, regardless of the local size of size_t variable. * * Hence templating by the source variable size should not be used. * Instead there are functions/templates that serialize to an explicit * number of bytes. * * @todo Templates are safe to use with integer types only. Adjust them * to work also with classes that have special serialization * routines. * @todo Make buffer serialization functions Buffer class methods. * @todo Alignment issues. */ #ifndef GU_SERIALIZE_HPP #define GU_SERIALIZE_HPP #include "gu_throw.hpp" #include "gu_byteswap.hpp" #include "gu_buffer.hpp" #include "gu_macros.hpp" #include namespace gu { template inline size_t serial_size(const T& t) { return t.serial_size(); } template <> inline size_t serial_size(const uint8_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint16_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint32_t& b) { return sizeof(b); } template <> inline size_t serial_size(const uint64_t& b) { return sizeof(b); } /* Should not be used directly! */ template inline size_t __private_serialize(const FROM& f, void* const buf, size_t const buflen, size_t const offset) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer1); GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer2); GU_COMPILE_ASSERT(sizeof(FROM) == sizeof(TO), size_differs); size_t const ret = offset + sizeof(TO); if (gu_unlikely(ret > buflen)) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } void* const pos(reinterpret_cast(buf) + offset); *reinterpret_cast(pos) = htog(f); return ret; } /* Should not be used directly! */ template inline size_t __private_unserialize(const void* const buf, size_t const buflen, size_t const offset, TO& t) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer1); GU_COMPILE_ASSERT(std::numeric_limits::is_integer, not_integer2); GU_COMPILE_ASSERT(sizeof(FROM) == sizeof(TO), size_differs); size_t const ret = offset + sizeof(t); if (gu_unlikely(ret > buflen)) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } const void* const pos(reinterpret_cast(buf) + offset); t = gtoh(*reinterpret_cast(pos)); return ret; } template GU_FORCE_INLINE size_t serialize1(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize1(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize2(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize2(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize4(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize4(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template GU_FORCE_INLINE size_t serialize8(const T& t, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(t, buf, buflen, offset); } template GU_FORCE_INLINE size_t unserialize8(const void* const buf, size_t const buflen, size_t const offset, T& t) { return __private_unserialize(buf, buflen, offset, t); } template inline size_t __private_serial_size(const Buffer& sb) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, must_be_integer); if (sb.size() > std::numeric_limits::max()) gu_throw_error(ERANGE) << sb.size() << " unrepresentable in " << sizeof(ST) << " bytes."; return sizeof(ST) + sb.size(); } GU_FORCE_INLINE size_t serial_size1(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size2(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size4(const Buffer& sb) { return __private_serial_size(sb); } GU_FORCE_INLINE size_t serial_size8(const Buffer& sb) { return __private_serial_size(sb); } template inline size_t __private_serialize(const Buffer& b, void* const buf, size_t const buflen, size_t offset) { size_t const ret = offset + __private_serial_size(b); if (ret > buflen) { gu_throw_error(EMSGSIZE) << ret << " > " << buflen; } offset = __private_serialize(static_cast(b.size()), buf, buflen, offset); copy(b.begin(), b.end(), reinterpret_cast(buf) + offset); return ret; } template inline size_t __private_unserialize(const void* const buf, size_t const buflen, size_t offset, Buffer& b) { GU_COMPILE_ASSERT(std::numeric_limits::is_integer, must_be_integer); ST len(0); size_t ret = offset + sizeof(len); if (ret > buflen) gu_throw_error(EMSGSIZE) << ret << " > " << buflen; offset = __private_unserialize(buf, buflen, offset, len); ret += len; if (ret > buflen) gu_throw_error(EMSGSIZE) << ret << " > " << buflen; b.resize(len); const byte_t* const ptr(reinterpret_cast(buf)); copy(ptr + offset, ptr + ret, b.begin()); return ret; } GU_FORCE_INLINE size_t serialize1(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize1(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize2(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize2(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize4(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize4(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } GU_FORCE_INLINE size_t serialize8(const Buffer& b, void* const buf, size_t const buflen, size_t const offset) { return __private_serialize(b, buf, buflen, offset); } GU_FORCE_INLINE size_t unserialize8(const void* const buf, size_t const buflen, size_t const offset, Buffer& b) { return __private_unserialize(buf, buflen, offset, b); } } // namespace gu #endif // GU_SERIALIZE_HPP percona-galera-3-3.8-3390/galerautils/src/gu_spooky.c000066400000000000000000000004401244131713600222660ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /** * @file external Spooky hash implementation to avoid code bloat * * $Id$ */ #include "gu_spooky.h" void gu_spooky128_host (const void* const msg, size_t const len, uint64_t* res) { gu_spooky_inline (msg, len, res); } percona-galera-3-3.8-3390/galerautils/src/gu_spooky.h000066400000000000000000000325541244131713600223060ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /*! * @file Spooky hash by Bob Jenkins: * http://www.burtleburtle.net/bob/c/spooky.h * * Original author comments preserved in C++ style. * Original code is public domain * * $Id$ */ #ifndef _gu_spooky_h_ #define _gu_spooky_h_ #include "gu_types.h" #include "gu_byteswap.h" #ifdef __cplusplus extern "C" { #endif #include // for memcpy() /*! GCC complains about 'initializer element is not constant', hence macros */ #define _spooky_numVars 12 #define _spooky_blockSize 96 /* (_spooky_numVars * 8) */ #define _spooky_bufSize 192 /* (_spooky_blockSize * 2) */ static uint64_t const _spooky_const = GU_ULONG_LONG(0xDEADBEEFDEADBEEF); // // This is used if the input is 96 bytes long or longer. // // The internal state is fully overwritten every 96 bytes. // Every input bit appears to cause at least 128 bits of entropy // before 96 other bytes are combined, when run forward or backward // For every input bit, // Two inputs differing in just that input bit // Where "differ" means xor or subtraction // And the base value is random // When run forward or backwards one Mix // I tried 3 pairs of each; they all differed by at least 212 bits. // static GU_FORCE_INLINE void _spooky_mix( const uint64_t *data, uint64_t* s0, uint64_t* s1, uint64_t* s2, uint64_t* s3, uint64_t* s4, uint64_t* s5, uint64_t* s6, uint64_t* s7, uint64_t* s8, uint64_t* s9, uint64_t* sA, uint64_t* sB) { *s0 += gu_le64(data[0]); *s2 ^= *sA; *sB ^= *s0; *s0 =GU_ROTL64(*s0,11); *sB += *s1; *s1 += gu_le64(data[1]); *s3 ^= *sB; *s0 ^= *s1; *s1 =GU_ROTL64(*s1,32); *s0 += *s2; *s2 += gu_le64(data[2]); *s4 ^= *s0; *s1 ^= *s2; *s2 =GU_ROTL64(*s2,43); *s1 += *s3; *s3 += gu_le64(data[3]); *s5 ^= *s1; *s2 ^= *s3; *s3 =GU_ROTL64(*s3,31); *s2 += *s4; *s4 += gu_le64(data[4]); *s6 ^= *s2; *s3 ^= *s4; *s4 =GU_ROTL64(*s4,17); *s3 += *s5; *s5 += gu_le64(data[5]); *s7 ^= *s3; *s4 ^= *s5; *s5 =GU_ROTL64(*s5,28); *s4 += *s6; *s6 += gu_le64(data[6]); *s8 ^= *s4; *s5 ^= *s6; *s6 =GU_ROTL64(*s6,39); *s5 += *s7; *s7 += gu_le64(data[7]); *s9 ^= *s5; *s6 ^= *s7; *s7 =GU_ROTL64(*s7,57); *s6 += *s8; *s8 += gu_le64(data[8]); *sA ^= *s6; *s7 ^= *s8; *s8 =GU_ROTL64(*s8,55); *s7 += *s9; *s9 += gu_le64(data[9]); *sB ^= *s7; *s8 ^= *s9; *s9 =GU_ROTL64(*s9,54); *s8 += *sA; *sA += gu_le64(data[10]); *s0 ^= *s8; *s9 ^= *sA; *sA =GU_ROTL64(*sA,22); *s9 += *sB; *sB += gu_le64(data[11]); *s1 ^= *s9; *sA ^= *sB; *sB =GU_ROTL64(*sB,46); *sA += *s0; } // // Mix all 12 inputs together so that h0, h1 are a hash of them all. // // For two inputs differing in just the input bits // Where "differ" means xor or subtraction // And the base value is random, or a counting value starting at that bit // The final result will have each bit of h0, h1 flip // For every input bit, // with probability 50 +- .3% // For every pair of input bits, // with probability 50 +- 3% // // This does not rely on the last Mix() call having already mixed some. // Two iterations was almost good enough for a 64-bit result, but a // 128-bit result is reported, so End() does three iterations. // static GU_FORCE_INLINE void _spooky_end_part( uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3, uint64_t* h4, uint64_t* h5, uint64_t* h6, uint64_t* h7, uint64_t* h8, uint64_t* h9, uint64_t* h10,uint64_t* h11) { *h11+= *h1; *h2 ^= *h11; *h1 = GU_ROTL64(*h1,44); *h0 += *h2; *h3 ^= *h0; *h2 = GU_ROTL64(*h2,15); *h1 += *h3; *h4 ^= *h1; *h3 = GU_ROTL64(*h3,34); *h2 += *h4; *h5 ^= *h2; *h4 = GU_ROTL64(*h4,21); *h3 += *h5; *h6 ^= *h3; *h5 = GU_ROTL64(*h5,38); *h4 += *h6; *h7 ^= *h4; *h6 = GU_ROTL64(*h6,33); *h5 += *h7; *h8 ^= *h5; *h7 = GU_ROTL64(*h7,10); *h6 += *h8; *h9 ^= *h6; *h8 = GU_ROTL64(*h8,13); *h7 += *h9; *h10^= *h7; *h9 = GU_ROTL64(*h9,38); *h8 += *h10; *h11^= *h8; *h10= GU_ROTL64(*h10,53); *h9 += *h11; *h0 ^= *h9; *h11= GU_ROTL64(*h11,42); *h10+= *h0; *h1 ^= *h10; *h0 = GU_ROTL64(*h0,54); } static GU_FORCE_INLINE void _spooky_end( uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3, uint64_t* h4, uint64_t* h5, uint64_t* h6, uint64_t* h7, uint64_t* h8, uint64_t* h9, uint64_t* h10,uint64_t* h11) { #if 0 _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); #endif int i; for (i = 0; i < 3; i++) { _spooky_end_part(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); } } // // The goal is for each bit of the input to expand into 128 bits of // apparent entropy before it is fully overwritten. // n trials both set and cleared at least m bits of h0 h1 h2 h3 // n: 2 m: 29 // n: 3 m: 46 // n: 4 m: 57 // n: 5 m: 107 // n: 6 m: 146 // n: 7 m: 152 // when run forwards or backwards // for all 1-bit and 2-bit diffs // with diffs defined by either xor or subtraction // with a base of all zeros plus a counter, or plus another bit, or random // static GU_FORCE_INLINE void _spooky_short_mix(uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3) { *h2 = GU_ROTL64(*h2,50); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,52); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,30); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,41); *h1 += *h2; *h3 ^= *h1; *h2 = GU_ROTL64(*h2,54); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,48); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,38); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,37); *h1 += *h2; *h3 ^= *h1; *h2 = GU_ROTL64(*h2,62); *h2 += *h3; *h0 ^= *h2; *h3 = GU_ROTL64(*h3,34); *h3 += *h0; *h1 ^= *h3; *h0 = GU_ROTL64(*h0,5); *h0 += *h1; *h2 ^= *h0; *h1 = GU_ROTL64(*h1,36); *h1 += *h2; *h3 ^= *h1; } // // Mix all 4 inputs together so that h0, h1 are a hash of them all. // // For two inputs differing in just the input bits // Where "differ" means xor or subtraction // And the base value is random, or a counting value starting at that bit // The final result will have each bit of h0, h1 flip // For every input bit, // with probability 50 +- .3% (it is probably better than that) // For every pair of input bits, // with probability 50 +- .75% (the worst case is approximately that) // static GU_FORCE_INLINE void _spooky_short_end(uint64_t* h0, uint64_t* h1, uint64_t* h2, uint64_t* h3) { *h3 ^= *h2; *h2 = GU_ROTL64(*h2,15); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,52); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,26); *h1 += *h0; *h2 ^= *h1; *h1 = GU_ROTL64(*h1,51); *h2 += *h1; *h3 ^= *h2; *h2 = GU_ROTL64(*h2,28); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,9); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,47); *h1 += *h0; *h2 ^= *h1; *h1 = GU_ROTL64(*h1,54); *h2 += *h1; *h3 ^= *h2; *h2 = GU_ROTL64(*h2,32); *h3 += *h2; *h0 ^= *h3; *h3 = GU_ROTL64(*h3,25); *h0 += *h3; *h1 ^= *h0; *h0 = GU_ROTL64(*h0,63); *h1 += *h0; } // // short hash ... it could be used on any message, // but it's used by Spooky just for short messages. // static GU_INLINE void gu_spooky_short_host( const void* const message, size_t const length, uint64_t* const hash) { union { const uint8_t* p8; uint32_t* p32; uint64_t* p64; #if !GU_ALLOW_UNALIGNED_READS size_t i; #endif /* !GU_ALLOW_UNALIGNED_READS */ } u; u.p8 = (const uint8_t *)message; #if !GU_ALLOW_UNALIGNED_READS if (u.i & 0x7) { uint64_t buf[_spooky_numVars << 1]; memcpy(buf, message, length); u.p64 = buf; } #endif /* !GU_ALLOW_UNALIGNED_READS */ size_t remainder = length & 0x1F; /* length%32 */ /* author version : */ // uint64_t a = gu_le64(*hash[0]); // uint64_t b = gu_le64(*hash[1]); /* consistent seed version: */ uint64_t a = 0; uint64_t b = 0; uint64_t c = _spooky_const; uint64_t d = _spooky_const; if (length > 15) { const uint64_t *end = u.p64 + ((length >> 5) << 2); /* (length/32)*4 */ // handle all complete sets of 32 bytes for (; u.p64 < end; u.p64 += 4) { c += gu_le64(u.p64[0]); d += gu_le64(u.p64[1]); _spooky_short_mix(&a, &b, &c, &d); a += gu_le64(u.p64[2]); b += gu_le64(u.p64[3]); } //Handle the case of 16+ remaining bytes. if (remainder >= 16) { c += gu_le64(u.p64[0]); d += gu_le64(u.p64[1]); _spooky_short_mix(&a, &b, &c, &d); u.p64 += 2; remainder -= 16; } } // Handle the last 0..15 bytes, and its length d = ((uint64_t)length) << 56; switch (remainder) { case 15: d += ((uint64_t)u.p8[14]) << 48; case 14: d += ((uint64_t)u.p8[13]) << 40; case 13: d += ((uint64_t)u.p8[12]) << 32; case 12: d += gu_le32(u.p32[2]); c += gu_le64(u.p64[0]); break; case 11: d += ((uint64_t)u.p8[10]) << 16; case 10: d += ((uint64_t)u.p8[9]) << 8; case 9: d += (uint64_t)u.p8[8]; case 8: c += gu_le64(u.p64[0]); break; case 7: c += ((uint64_t)u.p8[6]) << 48; case 6: c += ((uint64_t)u.p8[5]) << 40; case 5: c += ((uint64_t)u.p8[4]) << 32; case 4: c += gu_le32(u.p32[0]); break; case 3: c += ((uint64_t)u.p8[2]) << 16; case 2: c += ((uint64_t)u.p8[1]) << 8; case 1: c += (uint64_t)u.p8[0]; break; case 0: c += _spooky_const; d += _spooky_const; } _spooky_short_end(&a, &b, &c, &d); // @note - in native-endian order! hash[0] = a; hash[1] = b; } static GU_FORCE_INLINE void gu_spooky_short( const void* message, size_t length, void* const hash) { uint64_t* const u64 = (uint64_t*)hash; gu_spooky_short_host(message, length, u64); u64[0] = gu_le64(u64[0]); u64[1] = gu_le64(u64[1]); } // do the whole hash in one call static GU_INLINE void gu_spooky_inline ( const void* const message, size_t const length, uint64_t* const hash) { #ifdef GU_USE_SPOOKY_SHORT if (length < _spooky_bufSize) { gu_spooky_short_base (message, length, hash); return; } #endif /* GU_USE_SPOOKY_SHORT */ uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11; uint64_t buf[_spooky_numVars]; uint64_t* end; union { const uint8_t* p8; uint64_t* p64; #if !GU_ALLOW_UNALIGNED_READS size_t i; #endif /* !GU_ALLOW_UNALIGNED_READS */ } u; size_t remainder; /* this is how the author wants it: a possibility for different seeds h0=h3=h6=h9 = gu_le64(hash[0]); h1=h4=h7=h10 = gu_le64(hash[1]); * this is how we want it - constant seed */ h0=h3=h6=h9 = 0; h1=h4=h7=h10 = 0; h2=h5=h8=h11 = _spooky_const; u.p8 = (const uint8_t*) message; end = u.p64 + (length/_spooky_blockSize)*_spooky_numVars; // handle all whole _spooky_blockSize blocks of bytes #if !GU_ALLOW_UNALIGNED_READS if ((u.i & 0x7) == 0) { #endif /* !GU_ALLOW_UNALIGNED_READS */ while (u.p64 < end) { _spooky_mix(u.p64, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); u.p64 += _spooky_numVars; } #if !GU_ALLOW_UNALIGNED_READS } else { while (u.p64 < end) { memcpy(buf, u.p64, _spooky_blockSize); _spooky_mix(buf, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); u.p64 += _spooky_numVars; } } #endif /* !GU_ALLOW_UNALIGNED_READS */ // handle the last partial block of _spooky_blockSize bytes remainder = (length - ((const uint8_t*)end - (const uint8_t*)message)); memcpy(buf, end, remainder); memset(((uint8_t*)buf) + remainder, 0, _spooky_blockSize - remainder); ((uint8_t*)buf)[_spooky_blockSize - 1] = remainder; _spooky_mix(buf, &h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); // do some final mixing _spooky_end(&h0,&h1,&h2,&h3,&h4,&h5,&h6,&h7,&h8,&h9,&h10,&h11); /*! @note: in native order */ hash[0] = h0; hash[1] = h1; } /* As is apparent from the gu_spooky_inline(), Spooky hash is enormous. * Since it has advantage only on long messages, it makes sense to make it * a regular function to avoid code bloat. * WARNING: does not do final endian conversion! */ extern void gu_spooky128_host (const void* const msg, size_t const len, uint64_t* res); /* returns hash in the canonical byte order, as a byte array */ static GU_FORCE_INLINE void gu_spooky128 (const void* const msg, size_t const len, void* const res) { uint64_t* const r = (uint64_t*)res; gu_spooky128_host (msg, len, r); r[0] = gu_le64(r[0]); r[1] = gu_le64(r[1]); } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint64_t gu_spooky64 (const void* const msg, size_t const len) { uint64_t res[2]; gu_spooky128_host (msg, len, res); return res[0]; } /* returns hash as an integer, in host byte-order */ static GU_FORCE_INLINE uint32_t gu_spooky32 (const void* const msg, size_t const len) { uint64_t res[2]; gu_spooky128_host (msg, len, res); return (uint32_t)res[0]; } #ifdef __cplusplus } #endif #endif /* _gu_spooky_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_stats.cpp000066400000000000000000000032111244131713600224370ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #include #include #include #include "gu_macros.h" #include "gu_stats.hpp" // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance // http://www.johndcook.com/standard_deviation.html void gu::Stats::insert(const double val) { n_++; if (gu_unlikely(n_ == 1)) { old_m_ = new_m_ = val; old_s_ = new_s_ = 0.0; min_ = val; max_ = val; } else { new_m_ = old_m_ + (val - old_m_) / n_; new_s_ = old_s_ + (val - old_m_) * (val - new_m_); old_m_ = new_m_; old_s_ = new_s_; min_ = std::min(min_, val); max_ = std::max(max_, val); } } // I guess it's okay to assign 0.0 if no data. double gu::Stats::min() const { return gu_likely(n_ > 0) ? min_ : 0.0; } double gu::Stats::max() const { return gu_likely(n_ > 0) ? max_ : 0.0; } double gu::Stats::mean() const { return gu_likely(n_ > 0) ? new_m_ : 0.0; } double gu::Stats::variance() const { // n_ > 1 ? new_s_ / (n_ - 1) : 0.0; // is to compute unbiased sample variance // not population variance. return gu_likely(n_ > 0) ? new_s_ / n_ : 0.0; } double gu::Stats::std_dev() const { return sqrt(variance()); } std::string gu::Stats::to_string() const { std::ostringstream os; os << *this; return os.str(); } std::ostream& gu::operator<<(std::ostream& os, const gu::Stats& stats) { return (os << stats.min() << "/" << stats.mean() << "/" << stats.max() << "/" << stats.std_dev() << "/" << stats.times()); } percona-galera-3-3.8-3390/galerautils/src/gu_stats.hpp000066400000000000000000000017411244131713600224520ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef _gu_stats_hpp_ #define _gu_stats_hpp_ #include namespace gu { class Stats { public: Stats():n_(0), old_m_(), new_m_(), old_s_(), new_s_(), min_(), max_() {} void insert(const double); void clear() { n_ = 0; } unsigned int times() const { return n_; } double min() const; double max() const; double mean() const; double variance() const; double std_dev() const; friend std::ostream& operator<<(std::ostream&, const Stats&); std::string to_string() const; private: unsigned int n_; double old_m_; double new_m_; double old_s_; double new_s_; double min_; double max_; }; std::ostream& operator<<(std::ostream&, const Stats&); } #endif // _gu_stats_hpp_ percona-galera-3-3.8-3390/galerautils/src/gu_status.hpp000066400000000000000000000016501244131713600226360ustar00rootroot00000000000000// Copyright (C) 2014 Codership Oy //! // @file // Common class for gathering Galera wide status. The class is simple // string based key-value store. // #ifndef GU_STATUS_HPP #define GU_STATUS_HPP #include "gu_exception.hpp" #include #include namespace gu { class Status { public: typedef std::map VarMap; typedef VarMap::iterator iterator; typedef VarMap::const_iterator const_iterator; Status() : vars_() { } void insert(const std::string& key, const std::string& val) { vars_.insert(std::make_pair(key, val)); } const_iterator begin() { return vars_.begin(); } const_iterator end() { return vars_.end(); } size_t size() const { return vars_.size(); } private: VarMap vars_; }; } #endif // !GU_STATUS_HPP percona-galera-3-3.8-3390/galerautils/src/gu_str.h000066400000000000000000000105741244131713600215700ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #ifndef GU_STR_H #define GU_STR_H #include #include #include #include /*! * Append after position */ static inline char* gu_str_append(char* str, size_t* off, const char* app, size_t app_len) { char* tmp; assert(str == NULL || *(str + *off - 1) == '\0'); tmp = realloc(str, *off + app_len + 1); if (tmp != NULL) { memcpy(tmp + *off, app, app_len + 1); *off += app_len + 1; } return tmp; } /*! * Get next string after position */ static inline const char* gu_str_next(const char* str) { return strchr(str, '\0') + 1; } /*! * Advance position starting from over n */ static inline const char* gu_str_advance(const char* str, size_t n) { const char* ptr = str; while (n-- > 0) { ptr = gu_str_next(ptr); } return ptr; } /* * Utilities to construct and scan tables from null terminated strings. * The table format is the following: * * name\0\columns\0\rows\0 * colname0\0colname1\0... * elem00\0elem01\0elem02\0... * elem10\0elem11\0elem\12\... * . * . * . */ static inline char* gu_str_table_set_name(char* str, size_t* off, const char* name) { return gu_str_append(str, off, name, strlen(name)); } static inline const char* gu_str_table_get_name(const char* str) { return str; } static inline char* gu_str_table_append_size(char* str, size_t* off, size_t n) { char buf[10]; size_t len = snprintf(buf, sizeof(buf), "%zu", n); return gu_str_append(str, off, buf, len); } static inline char* gu_str_table_set_n_cols(char* str, size_t* off, size_t n) { return gu_str_table_append_size(str, off, n); } static inline size_t gu_str_table_get_n_cols(const char* str) { str = gu_str_advance(str, 1); return strtoul(str, NULL, 0); } static inline char* gu_str_table_set_n_rows(char* str, size_t* off, size_t n) { return gu_str_table_append_size(str, off, n); } static inline size_t gu_str_table_get_n_rows(const char* str) { str = gu_str_advance(str, 2); return strtoul(str, NULL, 0); } static inline char* gu_str_table_set_cols(char* str, size_t *off, size_t n, const char* cols[]) { size_t i; for (i = 0; i < n; ++i) { str = gu_str_append(str, off, cols[i], strlen(cols[i])); } return str; } static inline char* gu_str_table_append_row(char* str, size_t *off, size_t n, const char* row[]) { size_t i; for (i = 0; i < n; ++i) { str = gu_str_append(str, off, row[i], strlen(row[i])); } return str; } static inline const char* gu_str_table_get_cols(const char* str, size_t n, char const* row[]) { size_t i; str = gu_str_advance(str, 3); for (i = 0; i < n; i++) { row[i] = str; str = gu_str_next(str); } return str; } static inline const char* gu_str_table_rows_begin(const char* str, size_t n) { return gu_str_advance(str, 3 + n); } static inline const char* gu_str_table_row_get(const char* str, size_t n, char const* row[]) { size_t i; for (i = 0; i < n; ++i) { row[i] = str; str = gu_str_next(str); } return str; } static inline void gu_str_table_print_row(FILE* file, size_t n, const char* const row[]) { size_t i; for (i = 0; i < n; ++i) { fprintf(file, "%s ", row[i]); } fprintf(file, "\n"); } static inline void gu_str_table_print(FILE* file, const char* str) { size_t i; size_t n_cols, n_rows; const char* ptr; char const**vec; fprintf(file, "%s\n", gu_str_table_get_name(str)); n_cols = gu_str_table_get_n_cols(str); n_rows = gu_str_table_get_n_rows(str); vec = malloc(n_cols*sizeof(char*)); ptr = gu_str_table_get_cols(str, n_cols, vec); gu_str_table_print_row(file, n_cols, vec); for (i = 0; i < n_rows; ++i) { ptr = gu_str_table_row_get(ptr, n_cols, vec); gu_str_table_print_row(file, n_cols, vec); } free(vec); } #endif /* GU_STR_H */ percona-galera-3-3.8-3390/galerautils/src/gu_string.hpp000066400000000000000000000172151244131713600226250ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /*! * @file string class template that allows to allows to allocate initial storage * to hold string data together with the object. If storage is exhausted, * it transparently overflows to heap. */ #ifndef _GU_STRING_HPP_ #define _GU_STRING_HPP_ #include "gu_vector.hpp" #include #include // std::bad_alloc #include #include // realloc() #include // strlen(), strcmp() #include // snprintf() #include #include "gu_macros.h" // gu_likely() namespace gu { /* container for a printf()-like format */ struct Fmt { explicit Fmt(const char* f) : fmt_(f) {} const char* const fmt_; }; template class StringBase { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef size_t size_type; size_type size() const { return size_; } size_type length()const { return size(); } pointer c_str() { return str_; } const_pointer c_str() const { return str_; } StringBase& operator<< (const Fmt& f) { fmt_ = f.fmt_; return *this; } StringBase& operator<< (const StringBase& s) { size_type const n(s.size()); append_string (s.c_str(), n); return *this; } StringBase& operator<< (const char* s) { size_type const n(::strlen(s)); append_string (s, n); return *this; } StringBase& operator<< (const std::string& s) { append_string (s.c_str(), s.length()); return *this; } StringBase& operator<< (const bool& b) { // following std::boolalpha if (b) append_string ("true", 4); else append_string ("false", 5); return *this; } StringBase& operator<< (const double& d) { convert ("%f", std::numeric_limits::digits10, d); return *this; } StringBase& operator<< (const void* const ptr) { /* not using %p here seeing that it may be not universally supported */ static size_type const ptr_len(sizeof(ptr) == 4 ? 11 : 19 ); static const char* const fmt(sizeof(ptr) == 4 ? "0x%08lx":"0x%016lx"); convert (fmt, ptr_len, reinterpret_cast(ptr)); return *this; } StringBase& operator<< (const long long &i) { convert ("%lld", 21, i); return *this; } StringBase& operator<< (const unsigned long long &i) { convert ("%llu", 20, i); return *this; } StringBase& operator<< (const int &i) { convert ("%d", 11, i); return *this; } StringBase& operator<< (const unsigned int &i) { convert ("%u", 10, i); return *this; } StringBase& operator<< (const short &i) { convert ("%hd", 6, i); return *this; } StringBase& operator<< (const unsigned short &i) { convert ("%hu", 5, i); return *this; } StringBase& operator<< (const char &c) { convert ("%c", 1, c); return *this; } StringBase& operator<< (const unsigned char &c) { convert ("%hhu", 3, c); return *this; } template StringBase& operator+= (const X& x) { return operator<<(x); } bool operator== (const StringBase& other) { return (size() == other.size() && !::strcmp(c_str(), other.c_str())); } bool operator== (const std::string& other) { return (size() == other.size() && !::strcmp(c_str(), other.c_str())); } bool operator== (const char* s) { size_type const s_size(::strlen(s)); return (size() == s_size && !::strcmp(c_str(), s)); } template bool operator!= (const X& x) { return !operator==(x); } void clear() { derived_clear(); }; StringBase& operator= (const StringBase& other) { clear(); append_string (other.c_str(), other.size()); return *this; } StringBase& operator= (const char* const other) { clear(); append_string (other, ::strlen(other)); return *this; } protected: pointer str_; // points to an adequately sized memory area const char* fmt_; size_type size_; virtual void reserve (size_type n) = 0; virtual void derived_clear() = 0; // real clear must happen in derived class void append_string (const_pointer const s, size_type const n) { reserve(size_ + n + 1); std::copy(s, s + n, &str_[size_]); size_ += n; str_[size_] = 0; } template void convert (const char* const format, size_type max_len, const X& x) { ++max_len; // add null termination reserve(size_ + max_len); int const n(snprintf(&str_[size_], max_len, fmt_ ? fmt_ : format, x)); assert(n > 0); assert(size_type(n) < max_len); if (gu_likely(n > 0)) size_ += n; str_[size_] = 0; // null-terminate even if snprintf() failed. fmt_ = NULL; } StringBase(pointer init_buf) : str_(init_buf), fmt_(NULL), size_(0) {} virtual ~StringBase() {} private: StringBase(const StringBase&); }; /* class StringBase */ template std::ostream& operator<< (std::ostream& os, const gu::StringBase& s) { os << s.c_str(); return os; } template class String : public StringBase { public: typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef size_t size_type; String() : StringBase(buf_), reserved_(capacity), buf_() { buf_[0] = 0; } explicit String(const StringBase& s) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s.c_str(), s.size()); } String(const T* s, size_type n) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s, n); } explicit String(const char* s) : StringBase(buf_), reserved_(capacity), buf_() { size_type const n(strlen(s)); append_string (s, n); } explicit String(const std::string& s) : StringBase(buf_), reserved_(capacity), buf_() { append_string (s.c_str(), s.length()); } #if 0 String& operator= (String other) { using namespace std; swap(other); return *this; } #endif template String& operator= (const X& x) { base::operator=(x); return *this; } ~String() { if (base::str_ != buf_) ::free(base::str_); } private: size_type reserved_; value_type buf_[capacity]; typedef StringBase base; void reserve (size_type const n) { if (n <= reserved_) return; assert (n > capacity); bool const overflow(buf_ == base::str_); pointer const tmp (static_cast (::realloc(overflow ? NULL : base::str_, n * sizeof(value_type)))); if (NULL == tmp) throw std::bad_alloc(); if (overflow) std::copy(buf_, buf_ + base::size_, tmp); base::str_ = tmp; reserved_ = n; } void derived_clear() { if (base::str_ != buf_) ::free(base::str_); base::str_ = buf_; base::size_ = 0; buf_[0] = 0; reserved_ = capacity; } void append_string (const_pointer s, size_type n) { base::append_string(s, n); } }; /* class String */ } /* namespace gu */ #endif /* _GU_STRING_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_string_utils.cpp000066400000000000000000000044761244131713600240450ustar00rootroot00000000000000// Copyright (C) 2009-2010 Codership Oy #include "gu_string_utils.hpp" #include "gu_assert.hpp" #include using std::string; using std::vector; vector gu::strsplit(const string& s, char sep) { vector ret; size_t pos, prev_pos = 0; while ((pos = s.find_first_of(sep, prev_pos)) != string::npos) { ret.push_back(s.substr(prev_pos, pos - prev_pos)); prev_pos = pos + 1; } if (s.length() > prev_pos) { ret.push_back(s.substr(prev_pos, s.length() - prev_pos)); } return ret; } vector gu::tokenize(const string& s, const char sep, const char esc, const bool empty) { vector ret; size_t pos, prev_pos, search_pos; prev_pos = search_pos = 0; while ((pos = s.find_first_of(sep, search_pos)) != string::npos) { assert (pos >= prev_pos); if (esc != '\0' && pos > search_pos && esc == s[pos - 1]) { search_pos = pos + 1; continue; } if (pos > prev_pos || empty) { string t = s.substr(prev_pos, pos - prev_pos); // get rid of escapes size_t p, search_p = 0; while ((p = t.find_first_of(esc, search_p)) != string::npos && esc != '\0') { if (p > search_p) { t.erase(p, 1); search_p = p + 1; } } ret.push_back(t); } prev_pos = search_pos = pos + 1; } if (s.length() > prev_pos) { ret.push_back(s.substr(prev_pos, s.length() - prev_pos)); } else if (s.length() == prev_pos && empty) { assert(0 == prev_pos || s[prev_pos - 1] == sep); ret.push_back(""); } return ret; } void gu::trim (string& s) { const ssize_t s_length = s.length(); for (ssize_t begin = 0; begin < s_length; ++begin) { if (!isspace(s[begin])) { for (ssize_t end = s_length - 1; end >= begin; --end) { if (!isspace(s[end])) { s = s.substr(begin, end - begin + 1); return; } } assert(0); } } s.clear(); } percona-galera-3-3.8-3390/galerautils/src/gu_string_utils.hpp000066400000000000000000000017661244131713600240510ustar00rootroot00000000000000// Copyright (C) 2009-2010 Codership Oy #ifndef __GU_STRING_UTILS_HPP__ #define __GU_STRING_UTILS_HPP__ #include #include namespace gu { /*! * @brief Split string into tokens using given separator * * @param sep token separator */ std::vector strsplit(const std::string& s, char sep = ' '); /*! * @brief Split string into tokens using given separator and escape. * * @param sep token separator * @param esc separator escape sequence ('\0' to disable escapes) * @param empty whether to return empty tokens */ std::vector tokenize(const std::string& s, char sep = ' ', char esc = '\\', bool empty = false); /*! Remove non-alnum symbols from the beginning and end of string */ void trim (std::string& s); } #endif /* __GU_STRING_UTILS_HPP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_system.h000066400000000000000000000015121244131713600222740ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @system/os/platform dependent functions/macros * * $Id$ */ #ifndef _gu_system_h_ #define _gu_system_h_ #define _GNU_SOURCE // program_invocation_name, program_invocation_short_name #include #include // getexecname, getprogname #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* See: http://lists.gnu.org/archive/html/bug-gnulib/2010-12/txtrjMzutB7Em.txt * for implementation of GU_SYS_PROGRAM_NAME on other platforms */ #if defined(__sun__) # define GU_SYS_PROGRAM_NAME getexecname () #elif defined(__APPLE__) || defined(__FreeBSD__) # define GU_SYS_PROGRAM_NAME getprogname () #elif defined(__linux__) # define GU_SYS_PROGRAM_NAME program_invocation_name #endif #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_system_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_throw.hpp000066400000000000000000000051131244131713600224540ustar00rootroot00000000000000/* * Copyright (C) 2009-2013 Codership Oy * * $Id$ */ /*! * @file Classes to allow throwing more verbose exceptions. Should be only * used from one-line macros below. Concrete classes intended to be final. */ #ifndef __GU_THROW__ #define __GU_THROW__ #include #include #include #include #include "gu_macros.h" #include "gu_exception.hpp" namespace gu { /*! "base" class */ class ThrowBase { protected: const char* const file; const char* const func; int const line; std::ostringstream os; ThrowBase (const char* file_, const char* func_, int line_) : file (file_), func (func_), line (line_), os () {} private: ThrowBase (const ThrowBase&); ThrowBase& operator= (const ThrowBase&); friend class ThrowError; friend class ThrowFatal; }; /* final*/ class ThrowError //: public ThrowBase { public: ThrowError (const char* file_, const char* func_, int line_, int err_) : base (file_, func_, line_), err (err_) {} ~ThrowError() GU_NORETURN { base.os << ": " << err << " (" << ::strerror(err) << ')'; Exception e(base.os.str(), err); e.trace (base.file, base.func, base.line); // cppcheck-suppress exceptThrowInDestructor throw e; } std::ostringstream& msg () { return base.os; } private: ThrowBase base; int const err; }; /* final*/ class ThrowFatal { public: ThrowFatal (const char* file, const char* func, int line) : base (file, func, line) {} ~ThrowFatal () GU_NORETURN { base.os << " (FATAL)"; Exception e(base.os.str(), ENOTRECOVERABLE); e.trace (base.file, base.func, base.line); // cppcheck-suppress exceptThrowInDestructor throw e; } std::ostringstream& msg () { return base.os; } private: ThrowBase base; }; } // Usage: gu_throw_xxxxx << msg1 << msg2 << msg3; #define gu_throw_error(err_) \ gu::ThrowError(__FILE__, __FUNCTION__, __LINE__, err_).msg() #define gu_throw_fatal \ gu::ThrowFatal(__FILE__, __FUNCTION__, __LINE__).msg() #endif // __GU_THROW__ percona-galera-3-3.8-3390/galerautils/src/gu_time.c000066400000000000000000000144221244131713600217050ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file time manipulation functions/macros * * $Id: $ */ #if defined(__APPLE__) #include #include // struct timespec #include // gettimeofday #include // clock_get_time #include // host_get_clock_service #include // mach_absolute_time, mach_timebase_info #include #include "gu_time.h" #define NSEC_PER_SEC 1000000000 #define NSEC_PER_USEC 1000 # if defined(__LP64__) // OS X comm page time offsets // see http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/osfmk/i386/cpu_capabilities.h #define nt_tsc_base "0x50" #define nt_scale "0x58" #define nt_shift "0x5c" #define nt_ns_base "0x60" #define nt_generation "0x68" #define gtod_generation "0x6c" #define gtod_ns_base "0x70" #define gtod_sec_base "0x78" static inline int64_t nanotime (void) { int64_t ntime; __asm volatile ( "mov $0x7fffffe00000, %%rbx;" /* comm page base */ "0:" /* Loop trying to take a consistent snapshot of the time parameters. */ "movl "gtod_generation"(%%rbx), %%r8d;" "testl %%r8d, %%r8d;" "jz 1f;" "movl "nt_generation"(%%rbx), %%r9d;" "testl %%r9d, %%r9d;" "jz 0b;" "rdtsc;" "movq "nt_tsc_base"(%%rbx), %%r10;" "movl "nt_scale"(%%rbx), %%r11d;" "movq "nt_ns_base"(%%rbx), %%r12;" "cmpl "nt_generation"(%%rbx), %%r9d;" "jne 0b;" "movq "gtod_ns_base"(%%rbx), %%r13;" "movq "gtod_sec_base"(%%rbx), %%r14;" "cmpl "gtod_generation"(%%rbx), %%r8d;" "jne 0b;" /* Gathered all the data we need. Compute time. */ /* ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base - gtod_ns_base + gtod_sec_base*1e9 */ /* The multiply and shift extracts the top 64 bits of the 96-bit product. */ "shlq $32, %%rdx;" "addq %%rdx, %%rax;" "subq %%r10, %%rax;" "mulq %%r11;" "shrdq $32, %%rdx, %%rax;" "addq %%r12, %%rax;" "subq %%r13, %%rax;" "imulq $1000000000, %%r14;" "addq %%r14, %%rax;" "jmp 2f;" "1:" /* Fall back to system call (usually first call in this thread). */ "movq %%rsp, %%rdi;" /* rdi must be non-nil, unused */ "movq $0, %%rsi;" "movl $(0x2000000+116), %%eax;" /* SYS_gettimeofday */ "syscall; /* may destroy rcx and r11 */" /* sec is in rax, usec in rdx */ /* return nsec in rax */ "imulq $1000000000, %%rax;" "imulq $1000, %%rdx;" "addq %%rdx, %%rax;" "2:" : "=a"(ntime) : /* no input parameters */ : "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14" ); return ntime; } static inline int64_t nanouptime (void) { int64_t ntime; __asm volatile ( "movabs $0x7fffffe00000, %%rbx;" /* comm page base */ "0:" /* Loop trying to take a consistent snapshot of the time parameters. */ "movl "nt_generation"(%%rbx), %%r9d;" "testl %%r9d, %%r9d;" "jz 0b;" "rdtsc;" "movq "nt_tsc_base"(%%rbx), %%r10;" "movl "nt_scale"(%%rbx), %%r11d;" "movq "nt_ns_base"(%%rbx), %%r12;" "cmpl "nt_generation"(%%rbx), %%r9d;" "jne 0b;" /* Gathered all the data we need. Compute time. */ /* ((tsc - nt_tsc_base) * nt_scale) >> 32 + nt_ns_base */ /* The multiply and shift extracts the top 64 bits of the 96-bit product. */ "shlq $32, %%rdx;" "addq %%rdx, %%rax;" "subq %%r10, %%rax;" "mulq %%r11;" "shrdq $32, %%rdx, %%rax;" "addq %%r12, %%rax;" : "=a"(ntime) : /* no input parameters */ : "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%r9", "%r10", "%r11", "%r12" ); return ntime; } int clock_gettime (clockid_t clk_id, struct timespec * tp) { int64_t abstime = 0; if (tp == NULL) { return EFAULT; } switch (clk_id) { case CLOCK_REALTIME: abstime = nanotime (); break; case CLOCK_MONOTONIC: abstime = nanouptime (); break; default: errno = EINVAL; return -1; } tp->tv_sec = abstime / (uint64_t)NSEC_PER_SEC; tp->tv_nsec = (uint32_t)(abstime % (uint64_t)NSEC_PER_SEC); return 0; } #else /* !__LP64__ */ static struct mach_timebase_info g_mti; int clock_gettime (clockid_t clk_id, struct timespec * tp) { int64_t abstime = 0; mach_timebase_info_data_t mti; /* {uint32_t numer, uint32_t denom} */ if (tp == NULL) { return EFAULT; } switch (clk_id) { case CLOCK_REALTIME: struct timeval tv; if (gettimeofday (&tv, NULL) != 0) { return -1; } tp->tv_sec = tv.tv_sec; tp->tv_nsec = tv.tv_usec * NSEC_PER_USEC; return 0; case CLOCK_MONOTONIC: abstime = mach_absolute_time (); break; default: errno = EINVAL; return -1; } if (g_mti.denom == 0) { struct mach_timebase_info mti; mach_timebase_info (&mti); g_mti.numer = mti.numer; OSMemoryBarrier (); g_mti.denom = mti.denom; } nanos = (uint64_t)(abstime * (((double)g_mti.numer) / ((double)g_mti.denom))); tp->tv_sec = nanos / (uint64_t)NSEC_PER_SEC; tp->tv_nsec = (uint32_t)(nanos % (uint64_t)NSEC_PER_SEC); return 0; } #endif /* !__LP64__ */ #else /* !__APPLE__ */ #ifdef __GNUC__ // error: ISO C forbids an empty translation unit int dummy_var_gu_time; #endif #endif /* __APPLE__ */ percona-galera-3-3.8-3390/galerautils/src/gu_time.h000066400000000000000000000057751244131713600217250ustar00rootroot00000000000000// Copyright (C) 2008 Codership Oy /** * @file time manipulation functions/macros * * $Id$ */ #ifndef _gu_time_h_ #define _gu_time_h_ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** Returns seconds */ static inline double gu_timeval_diff (struct timeval* left, struct timeval* right) { register long long diff = left->tv_sec; diff = ((diff - right->tv_sec)*1000000LL) + left->tv_usec - right->tv_usec; return (((double)diff) * 1.0e-06); } static inline void gu_timeval_add (struct timeval* t, double s) { double ret = (double)t->tv_sec + ((double)t->tv_usec) * 1.0e-06 + s; t->tv_sec = (long)ret; t->tv_usec = (long)((ret - (double)t->tv_sec) * 1.0e+06); } static const double SEC_PER_CLOCK = ((double)1.0)/CLOCKS_PER_SEC; /** Returns seconds */ static inline double gu_clock_diff (clock_t left, clock_t right) { return ((double)(left - right)) * SEC_PER_CLOCK; } #include "gu_limits.h" // for GU_LONG_LONG_MAX #include /** * New time interface * * All funcitons return nanoseconds. */ /* Maximum date representable by long long and compatible with timespec */ #define GU_TIME_ETERNITY 9223372035999999999LL #if defined(__APPLE__) /* synced with linux/time.h */ # define CLOCK_REALTIME 0 # define CLOCK_MONOTONIC 1 typedef int clockid_t; int clock_gettime (clockid_t clk_id, struct timespec * tp); #endif /* __APPLE__ */ static inline long long gu_time_getres() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_getres (CLOCK_REALTIME, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return 1000LL; // assumed resolution of gettimeofday() in nanoseconds #endif } static inline long long gu_time_calendar() { #if _POSIX_TIMERS > 0 || defined(__APPLE__) struct timespec tmp; clock_gettime (CLOCK_REALTIME, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else struct timeval tmp; gettimeofday (&tmp, NULL); return ((tmp.tv_sec * 1000000000LL) + (tmp.tv_usec * 1000LL)); #endif } static inline long long gu_time_monotonic() { #if defined(_POSIX_MONOTONIC_CLOCK) || defined(__APPLE__) struct timespec tmp; clock_gettime (CLOCK_MONOTONIC, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else struct timeval tmp; gettimeofday (&tmp, NULL); return ((tmp.tv_sec * 1000000000LL) + (tmp.tv_usec * 1000LL)); #endif } #ifdef CLOCK_PROCESS_CPUTIME_ID static inline long long gu_time_process_cputime() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return -1; #endif } #endif /* CLOCK_PROCESS_CPUTIME_ID */ static inline long long gu_time_thread_cputime() { #if _POSIX_TIMERS > 0 struct timespec tmp; clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tmp); return ((tmp.tv_sec * 1000000000LL) + tmp.tv_nsec); #else return -1; #endif } #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_time_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_to.c000066400000000000000000000265121244131713600213740ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! \file \brief Total order access "class" implementation. * Although gcs_repl() and gcs_recv() calls return sequence * numbers in total order, there are concurrency issues between * application threads and they can grab critical section * mutex out of order. Wherever total order access to critical * section is required, these functions can be used to do this. */ #include #include #include #include // abort() #include "gu_log.h" #include "gu_assert.h" #include "gu_mem.h" #include "gu_mutex.h" #include "gu_to.h" #define TO_USE_SIGNAL 1 typedef enum { HOLDER = 0, //!< current TO holder WAIT, //!< actively waiting in the queue CANCELED, //!< Waiter has canceled its to request INTERRUPTED,//!< marked to be interrupted RELEASED, //!< has been released, free entry now } waiter_state_t; typedef struct { #ifdef TO_USE_SIGNAL gu_cond_t cond; #else pthread_mutex_t mtx; // have to use native pthread for double locking #endif waiter_state_t state; } to_waiter_t; struct gu_to { volatile gu_seqno_t seqno; size_t used; /* number of active waiters */ ssize_t qlen; size_t qmask; to_waiter_t* queue; gu_mutex_t lock; }; /** Returns pointer to the waiter with the given seqno */ static inline to_waiter_t* to_get_waiter (gu_to_t* to, gu_seqno_t seqno) { // Check for queue overflow. Tell application that it should wait. if (seqno >= to->seqno + to->qlen) { return NULL; } return (to->queue + (seqno & to->qmask)); } gu_to_t *gu_to_create (int len, gu_seqno_t seqno) { gu_to_t *ret; assert (seqno >= 0); if (len <= 0) { gu_error ("Negative length parameter: %d", len); return NULL; } ret = GU_CALLOC (1, gu_to_t); if (ret) { /* Make queue length a power of 2 */ ret->qlen = 1; while (ret->qlen < len) { // unsigned, can be bigger than any integer ret->qlen = ret->qlen << 1; } ret->qmask = ret->qlen - 1; ret->seqno = seqno; ret->queue = GU_CALLOC (ret->qlen, to_waiter_t); if (ret->queue) { ssize_t i; for (i = 0; i < ret->qlen; i++) { to_waiter_t *w = ret->queue + i; #ifdef TO_USE_SIGNAL gu_cond_init (&w->cond, NULL); #else pthread_mutex_init (&w->mtx, NULL); #endif w->state = RELEASED; } gu_mutex_init (&ret->lock, NULL); return ret; } gu_free (ret); } return NULL; } long gu_to_destroy (gu_to_t** to) { gu_to_t *t = *to; long ret; ssize_t i; gu_mutex_lock (&t->lock); if (t->used) { gu_mutex_unlock (&t->lock); return -EBUSY; } for (i = 0; i < t->qlen; i++) { to_waiter_t *w = t->queue + i; #ifdef TO_USE_SIGNAL if (gu_cond_destroy (&w->cond)) { // @todo: what if someone is waiting? gu_warn ("Failed to destroy condition %d. Should not happen", i); } #else if (pthread_mutex_destroy (&w->mtx)) { // @todo: what if someone is waiting? gu_warn ("Failed to destroy mutex %d. Should not happen", i); } #endif } t->qlen = 0; gu_mutex_unlock (&t->lock); /* What else can be done here? */ ret = gu_mutex_destroy (&t->lock); if (ret) return -ret; // application can retry gu_free (t->queue); gu_free (t); *to = NULL; return 0; } long gu_to_grab (gu_to_t* to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock(&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if (seqno < to->seqno) { gu_mutex_unlock(&to->lock); return -ECANCELED; } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ switch (w->state) { case INTERRUPTED: w->state = RELEASED; err = -EINTR; break; case CANCELED: err = -ECANCELED; break; case RELEASED: if (seqno == to->seqno) { w->state = HOLDER; } else if (seqno < to->seqno) { gu_error("Trying to grab outdated seqno"); err = -ECANCELED; } else { /* seqno > to->seqno, wait for my turn */ w->state = WAIT; to->used++; #ifdef TO_USE_SIGNAL gu_cond_wait(&w->cond, &to->lock); #else pthread_mutex_lock (&w->mtx); pthread_mutex_unlock (&to->lock); pthread_mutex_lock (&w->mtx); // wait for unlock by other thread pthread_mutex_lock (&to->lock); pthread_mutex_unlock (&w->mtx); #endif to->used--; switch (w->state) { case WAIT:// should be most probable assert (seqno == to->seqno); w->state = HOLDER; break; case INTERRUPTED: w->state = RELEASED; err = -EINTR; break; case CANCELED: err = -ECANCELED; break; case RELEASED: /* this waiter has been cancelled */ assert(seqno < to->seqno); err = -ECANCELED; break; default: gu_fatal("Invalid cond wait exit state %d, seqno %llu(%llu)", w->state, seqno, to->seqno); abort(); } } break; default: gu_fatal("TO queue over wrap"); abort(); } gu_mutex_unlock(&to->lock); return err; } static inline long to_wake_waiter (to_waiter_t* w) { long err = 0; if (w->state == WAIT) { #ifdef TO_USE_SIGNAL err = gu_cond_signal (&w->cond); #else err = pthread_mutex_unlock (&w->mtx); #endif if (err) { gu_fatal ("gu_cond_signal failed: %d", err); } } return err; } static inline void to_release_and_wake_next (gu_to_t* to, to_waiter_t* w) { w->state = RELEASED; /* * Iterate over CANCELED waiters and set states as RELEASED * We look for waiter in the head of queue, which guarantees that * to_get_waiter() will always return a valid waiter pointer */ for (to->seqno++; (w = to_get_waiter(to, to->seqno)) && w && w->state == CANCELED; to->seqno++) { w->state = RELEASED; } to_wake_waiter (w); } long gu_to_release (gu_to_t *to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock(&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ if (seqno == to->seqno) { to_release_and_wake_next (to, w); } else if (seqno > to->seqno) { if (w->state != CANCELED) { gu_fatal("Illegal state in premature release: %d", w->state); abort(); } /* Leave state CANCELED so that real releaser can iterate */ } else { /* */ if (w->state != RELEASED) { gu_fatal("Outdated seqno and state not RELEASED: %d", w->state); abort(); } } gu_mutex_unlock(&to->lock); return err; } gu_seqno_t gu_to_seqno (gu_to_t* to) { return to->seqno - 1; } long gu_to_cancel (gu_to_t *to, gu_seqno_t seqno) { long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } // Check for queue overflow. This is totally unrecoverable. Abort. if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); abort(); } /* we have a valid waiter now */ if ((seqno > to->seqno) || (seqno == to->seqno && w->state != HOLDER)) { err = to_wake_waiter (w); w->state = CANCELED; } else if (seqno == to->seqno && w->state == HOLDER) { gu_warn("tried to cancel current TO holder, state %d seqno %llu", w->state, seqno); err = -ECANCELED; } else { gu_warn("trying to cancel used seqno: state %d cancel seqno = %llu, " "TO seqno = %llu", w->state, seqno, to->seqno); err = -ECANCELED; } gu_mutex_unlock (&to->lock); return err; } long gu_to_self_cancel(gu_to_t *to, gu_seqno_t seqno) { long err = 0; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ if (seqno > to->seqno) { // most probable case w->state = CANCELED; } else if (seqno == to->seqno) { // have to wake the next waiter as if we grabbed and now releasing TO to_release_and_wake_next (to, w); } else { // (seqno < to->seqno) // This waiter must have been canceled or even released by preceding // waiter. Do nothing. } gu_mutex_unlock(&to->lock); return err; } long gu_to_interrupt (gu_to_t *to, gu_seqno_t seqno) { long rcode = 0; long err; to_waiter_t *w; assert (seqno >= 0); if ((err = gu_mutex_lock (&to->lock))) { gu_fatal("Mutex lock failed (%d): %s", err, strerror(err)); abort(); } if (seqno >= to->seqno) { if ((w = to_get_waiter (to, seqno)) == NULL) { gu_mutex_unlock(&to->lock); return -EAGAIN; } /* we have a valid waiter now */ switch (w->state) { case HOLDER: gu_debug ("trying to interrupt in use seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; break; case CANCELED: gu_debug ("trying to interrupt canceled seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; break; case WAIT: gu_debug ("signaling to interrupt wait seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); rcode = to_wake_waiter (w); case RELEASED: w->state = INTERRUPTED; break; case INTERRUPTED: gu_debug ("TO waiter interrupt already seqno: seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); break; } } else { gu_debug ("trying to interrupt used seqno: cancel seqno = %llu, " "TO seqno = %llu", seqno, to->seqno); /* gu_mutex_unlock (&to->lock); */ rcode = -ERANGE; } gu_mutex_unlock (&to->lock); return rcode; } percona-galera-3-3.8-3390/galerautils/src/gu_to.h000066400000000000000000000104041244131713600213720ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! * @file gu_to.h Public TO monitor API */ #ifndef _gu_to_h_ #define _gu_to_h_ #ifdef __cplusplus extern "C" { #endif #include #include #include /*! @typedef @brief Sequence number type. */ typedef int64_t gu_seqno_t; /*! Total Order object */ typedef struct gu_to gu_to_t; /*! @brief Creates TO object. * TO object can be used to serialize access to application * critical section using sequence number. * * @param len A length of the waiting queue. Should be no less than the * possible maximum number of threads competing for the resource, * but should not be too high either. Perhaps 1024 is good enough * for most applications. * @param seqno A starting sequence number * (the first to be used by gu_to_grab()). * @return Pointer to TO object or NULL in case of error. */ extern gu_to_t* gu_to_create (int len, gu_seqno_t seqno); /*! @brief Destroys TO object. * * @param to A pointer to TO object to be destroyed * @return 0 in case of success, negative code in case of error. * In particular -EBUSY means the object is used by other threads. */ extern long gu_to_destroy (gu_to_t** to); /*! @brief Grabs TO resource in the specified order. * On successful return the mutex associated with specified TO is locked. * Must be released gu_to_release(). @see gu_to_release * * @param to TO resource to be acquired. * @param seqno The order at which TO resouce should be aquired. For any N * gu_to_grab (to, N) will return exactly after * gu_to_release (to, N-1). * @return 0 in case of success, negative code in case of error. * -EAGAIN means that there are too many threads waiting for TO * already. It is safe to try again later. * -ECANCEL if waiter was canceled, seqno is skipped in TO * -EINTR if wait was interrupted, must retry grabbing later */ extern long gu_to_grab (gu_to_t* to, gu_seqno_t seqno); /*! @brief Releases TO specified resource. * On succesful return unlocks the mutex associated with TO. * TO must be previously acquired with gu_to_grab(). @see gu_to_grab * * @param to TO resource that was previously acquired with gu_to_grab(). * @param seqno The same number with which gu_to_grab() was called. * @return 0 in case of success, negative code in case of error. Any error * here is an application error - attempt to release TO resource * out of order (not paired with gu_to_grab()). */ extern long gu_to_release (gu_to_t* to, gu_seqno_t seqno); /*! @brief The last sequence number that had been used to access TO object. * Note that since no locks are held, it is a conservative estimation. * It is guaranteed however that returned seqno is no longer in use. * * @param to A pointer to TO object. * @return GCS sequence number. Since GCS TO sequence starts with 1, this * sequence can start with 0. */ extern gu_seqno_t gu_to_seqno (gu_to_t* to); /*! @brief cancels a TO monitor waiter making it return immediately * It is assumed that the caller is currenly holding the TO. * The to-be-cancelled waiter can be some later transaction but also * some earlier transaction. Tests have shown that the latter case * can also happen. * * @param to A pointer to TO object. * @param seqno Seqno of the waiter object to be cancelled * @return 0 for success and -ERANGE, if trying to cancel an earlier * transaction */ extern long gu_to_cancel (gu_to_t *to, gu_seqno_t seqno); /*! * Self cancel to without attempting to enter critical secion */ extern long gu_to_self_cancel(gu_to_t *to, gu_seqno_t seqno); /*! @brief interrupts from TO monitor waiting state. * Seqno remains valid in the queue and later seqnos still need to * wait for this seqno to be released. * * The caller can (and must) later try gu_to_grab() again or cancel * the seqno with gu_to_self_cancel(). * * @param to A pointer to TO object. * @param seqno Seqno of the waiter object to be interrupted * @return 0 for success and -ERANGE, if trying to interrupt an already * used transaction */ extern long gu_to_interrupt (gu_to_t *to, gu_seqno_t seqno); #ifdef __cplusplus } #endif #endif // _gu_to_h_ percona-galera-3-3.8-3390/galerautils/src/gu_types.h000066400000000000000000000007631244131713600221230ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file Location of some "standard" types definitions * * $Id$ */ #ifndef _gu_types_h_ #define _gu_types_h_ #include /* intXX_t and friends */ #include /* bool */ #include /* ssize_t */ #include /* ptrdiff_t */ #include /* off_t */ #ifdef __cplusplus extern "C" { #endif typedef unsigned char gu_byte_t; #ifdef __cplusplus } #endif #endif /* _gu_types_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_types.hpp000066400000000000000000000004241244131713600224550ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file Location of some "standard" types definitions * * $Id$ */ #ifndef _GU_TYPES_HPP_ #define _GU_TYPES_HPP_ #include "gu_types.h" namespace gu { typedef gu_byte_t byte_t; } #endif /* _GU_TYPES_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_unordered.hpp000066400000000000000000000144031244131713600233020ustar00rootroot00000000000000// // Copyright (C) 2010 Codership Oy // //! // @file gu_unordered.hpp unordered_[multi]map definition // // We still have environments where neither boost or std unordered // stuff is available. Wrapper classes are provided for alternate // implementations with standard semantics. // // For usage see either boost or tr1 specifications for unordered_[multi]map // #ifndef GU_UNORDERED_HPP #define GU_UNORDERED_HPP #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) #include #include #elif defined(HAVE_UNORDERED_MAP) #include #include #elif defined(HAVE_TR1_UNORDERED_MAP) #include #include #else #error "no unordered map available" #endif #include "gu_throw.hpp" namespace gu { template class UnorderedHash { public: #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::hash Type; #elif defined(HAVE_UNORDERED_MAP) typedef std::hash Type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::hash Type; #endif size_t operator()(const K& k) const { return Type()(k); } }; template size_t HashValue(const K& key) { return UnorderedHash()(key); } template , class P = std::equal_to, class A = std::allocator > class UnorderedSet { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_set type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_set type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_set type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedSet() : impl_() { } explicit UnorderedSet(A a) : impl_(a) { } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } std::pair insert(const value_type& k) { return impl_.insert(k); } iterator insert_unique(const value_type& k) { std::pair ret(insert(k)); if (ret.second == false) gu_throw_fatal << "insert unique failed"; return ret.first; } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } iterator erase(iterator i) { return impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } void clear() { impl_.clear(); } void rehash(size_t n) { impl_.rehash(n); } #if defined(HAVE_UNORDERED_MAP) void reserve(size_t n) { impl_.reserve(n); } #endif }; template , class P = std::equal_to, class A = std::allocator > > class UnorderedMap { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_map type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_map type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_map type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedMap() : impl_() { } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } std::pair insert(const std::pair& kv) { return impl_.insert(kv); } iterator insert_unique(const std::pair& kv) { std::pair ret(insert(kv)); if (ret.second == false) gu_throw_fatal << "insert unique failed"; return ret.first; } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } iterator erase(iterator i) { return impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } void clear() { impl_.clear(); } void rehash(size_t n) { impl_.rehash(n); } }; template > class UnorderedMultimap { #if defined(HAVE_BOOST_UNORDERED_MAP_HPP) typedef boost::unordered_multimap type; #elif defined(HAVE_UNORDERED_MAP) typedef std::unordered_multimap type; #elif defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_multimap type; #endif type impl_; public: typedef typename type::value_type value_type; typedef typename type::iterator iterator; typedef typename type::const_iterator const_iterator; UnorderedMultimap() : impl_() { } void clear() { impl_.clear(); } iterator begin() { return impl_.begin(); } const_iterator begin() const { return impl_.begin(); } iterator end() { return impl_.end(); } const_iterator end() const { return impl_.end(); } iterator insert(const std::pair& kv) { return impl_.insert(kv); } iterator find(const K& key) { return impl_.find(key); } const_iterator find(const K& key) const { return impl_.find(key); } std::pair equal_range(const K& key) { return impl_.equal_range(key); } std::pair equal_range(const K& key) const { return impl_.equal_range(key); } void erase(iterator i) { impl_.erase(i); } size_t size() const { return impl_.size(); } bool empty() const { return impl_.empty(); } }; } #endif // GU_UNORDERED_HPP percona-galera-3-3.8-3390/galerautils/src/gu_uri.cpp000066400000000000000000000173471244131713600221170ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! @todo: scheme and host parts should be normalized to lower case except for * %-encodings, which should go upper-case */ #include #include #include #include "gu_assert.h" #include "gu_throw.hpp" #include "gu_logger.hpp" #include "gu_string_utils.hpp" // strsplit() #include "gu_uri.hpp" using std::string; using std::vector; using std::multimap; static void parse_authority (const string& auth, gu::RegEx::Match& user, gu::RegEx::Match& host, gu::RegEx::Match& port) { size_t pos1, pos2; pos1 = auth.find_first_of ('@'); if (pos1 != string::npos) { user = gu::RegEx::Match (auth.substr(0, pos1)); pos1 += 1; // pos1 now points past the first occurence of @, // which may be past the end of the string. } else { pos1 = 0; } pos2 = auth.find_last_of (':'); if (pos2 != string::npos && pos2 >= pos1) { host = gu::RegEx::Match (auth.substr (pos1, pos2 - pos1)); // according to RFC 3986 empty port (nothing after :) should be treated // as unspecified, so make sure that it is not 0-length. if ((pos2 + 1) < auth.length()) { port = gu::RegEx::Match (auth.substr (pos2 + 1)); if ((port.str().find_first_not_of ("0123456789") != string::npos) || // @todo: possible port range is not determined in RFC 3986 (65535 < gu::from_string (port.str()))) { log_debug << "\n\tauth: '" << auth << "'" << "\n\thost: '" << host.str() << "'" << "\n\tport: '" << port.str() << "'" << "\n\tpos1: " << pos1 << ", pos2: " << pos2; gu_throw_error (EINVAL) << "Can't parse port number from '" << port.str() << "'"; } } } else { host = gu::RegEx::Match (auth.substr (pos1)); } } static gu::URIQueryList extract_query_list(const string& s, const string& query) { gu::URIQueryList ret; // scan all key=value pairs vector qlist = gu::strsplit(query, '&'); for (vector::const_iterator i = qlist.begin(); i != qlist.end(); ++i) { vector kvlist = gu::strsplit(*i, '='); if (kvlist.size() != 2) { gu_throw_error (EINVAL) << "Invalid URI query part: '" << *i << "'"; } ret.insert(make_pair(kvlist[0], kvlist[1])); } return ret; } gu::URI::URI(const string& uri_str, bool const strict) : modified_ (true), // recompose to normalize on the first call to_string() str_ (uri_str), scheme_ (), authority_ (), path_ (), fragment_ (), query_list_() { parse(uri_str, strict); } /*! regexp suggested by RFC 3986 to parse URI into 5 canonical parts */ const char* const gu::URI::uri_regex_ = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; /* 12 3 4 5 6 7 8 9 */ /*! positions of URI components as matched by the above pattern */ enum { SCHEME = 2, AUTHORITY = 4, PATH = 5, QUERY = 7, FRAGMENT = 9, NUM_PARTS }; gu::RegEx const gu::URI::regex_(uri_regex_); static string const UNSET_SCHEME("unset://"); void gu::URI::parse (const string& uri_str, bool const strict) { log_debug << "URI: " << uri_str; vector parts; if (!strict && uri_str.find("://") == std::string::npos) { string tmp = UNSET_SCHEME + uri_str; parts = regex_.match (tmp, NUM_PARTS); } else { parts = regex_.match (uri_str, NUM_PARTS); scheme_ = parts[SCHEME]; //set scheme only if it was explicitly provided } if (strict && (!scheme_.is_set() || !scheme_.str().length())) { gu_throw_error (EINVAL) << "URI '" << uri_str << "' has empty scheme"; } try { std::vector auth_list( strsplit(parts[AUTHORITY].str(), ',')); for (size_t i(0); i < auth_list.size(); ++i) { Authority auth; parse_authority (auth_list[i], auth.user_, auth.host_, auth.port_); authority_.push_back(auth); } } catch (NotSet&) { authority_.push_back(Authority()); } path_ = parts[PATH]; if (!parts[AUTHORITY].is_set() && !path_.is_set()) { gu_throw_error (EINVAL) << "URI '" << uri_str << "' has no hierarchical part"; } try { query_list_ = extract_query_list(str_, parts[QUERY].str()); } catch (NotSet&) {} fragment_ = parts[FRAGMENT]; #if 0 try { log_debug << "Base URI: " << scheme.str() << "://" << get_authority(); } catch (NotSet&) {} #endif } std::string gu::URI::get_authority(const gu::URI::Authority& authority) const { const RegEx::Match& user(authority.user_); const RegEx::Match& host(authority.host_); const RegEx::Match& port(authority.port_); if (!user.is_set() && !host.is_set()) throw NotSet(); size_t auth_len = 0; if (user.is_set()) auth_len += user.str().length() + 1; if (host.is_set()) { auth_len += host.str().length(); if (port.is_set()) auth_len += port.str().length() + 1; } string auth; auth.reserve (auth_len); if (user.is_set()) { auth += user.str(); auth += '@'; } if (host.is_set()) { auth += host.str(); if (port.is_set()) { auth += ':'; auth += port.str(); } } return auth; } string gu::URI::get_authority() const { if (authority_.empty()) return ""; return get_authority(authority_.front()); } void gu::URI::recompose() const { size_t l = str_.length(); str_.clear (); str_.reserve (l); // resulting string length will be close to this if (scheme_.is_set()) { str_ += scheme_.str(); str_ += ':'; } str_ += "//"; for (AuthorityList::const_iterator i(authority_.begin()); i != authority_.end(); ++i) { AuthorityList::const_iterator i_next(i); ++i_next; try { string auth = get_authority(*i); str_ += auth; } catch (NotSet&) {} if (i_next != authority_.end()) str_ += ","; } if (path_.is_set()) str_ += path_.str(); if (query_list_.size() > 0) { str_ += '?'; } URIQueryList::const_iterator i = query_list_.begin(); while (i != query_list_.end()) { str_ += i->first + '=' + i->second; URIQueryList::const_iterator i_next = i; ++i_next; if (i_next != query_list_.end()) { str_ += '&'; } i = i_next; } if (fragment_.is_set()) { str_ += '#'; str_ += fragment_.str(); } } void gu::URI::set_query_param(const string& key, const string& val, bool override) { if (override == false) { query_list_.insert(make_pair(key, val)); } else { URIQueryList::iterator i(query_list_.find(key)); if (i == query_list_.end()) { query_list_.insert(make_pair(key, val)); } else { i->second = val; } } modified_ = true; } const std::string& gu::URI::get_option (const std::string& name) const { gu::URIQueryList::const_iterator i = query_list_.find(name); if (i == query_list_.end()) throw NotFound(); return i->second; } percona-galera-3-3.8-3390/galerautils/src/gu_uri.hpp000066400000000000000000000152551244131713600221200ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy * * $Id$ */ /*! * @file gu_url.hpp * * @brief Utility to parse URIs * * Follows http://tools.ietf.org/html/rfc3986 * * @author Teemu Ollakka */ #ifndef __GU_URI_HPP__ #define __GU_URI_HPP__ #include #include #include #include "gu_utils.hpp" #include "gu_regex.hpp" namespace gu { /*! * @brief URIQueryList * * std::multimap is used to implement query list in URI. * @todo This should be changed to real class having get_key(), * get_value() methods for iterators and to get rid of std::multimap * dependency in header. */ typedef std::multimap URIQueryList; /*! * @brief Utility class to parse URIs */ class URI { public: /*! * @class Helper class for authority list representation. */ class Authority { public: /*! * @brief Get "user" part of authority * * @return user substring * @throws NotSet */ const std::string& user() const { return user_.str(); } /*! * @brief Get "host" part of authority * * @return host substring * @throws NotSet */ const std::string& host() const { return host_.str(); } /*! * @brief Get "port" part of authority * * @return port * @throws NotSet */ const std::string& port() const { return port_.str(); } private: friend class gu::URI; Authority() : user_(), host_(), port_() { } RegEx::Match user_; RegEx::Match host_; RegEx::Match port_; }; typedef std::vector AuthorityList; /*! * @brief Construct URI from string * * @param strict if true, throw exception when scheme is not found, * else use a default one * @throws std::invalid_argument if URI is not valid * @throws std::logic_error in case of internal error * @throws NotSet */ URI (const std::string&, bool strict = true); /*! * @brief Get URI string * @return URI string */ const std::string& to_string() const { if (modified_) recompose(); return str_; } /*! * @brief Get URI scheme * * @return URI scheme (always set) * @throws NotSet */ const std::string& get_scheme() const { return scheme_.str(); } /*! * @brief Get URI authority component * * @return URI authority substring * @throws NotSet */ std::string get_authority() const; /*! * @brief Get "user" part of the first entry in authority list * * @return User substring * @throws NotSet */ const std::string& get_user() const { if (authority_.empty()) throw NotSet(); return authority_.front().user(); } /*! * @brief Get "host" part of the first entry in authority list * * @return Host substring * @throws NotSet */ const std::string& get_host() const { if (authority_.empty()) throw NotSet(); return authority_.front().host(); } /*! * @brief Get "port" part of the first entry in authority list * * @return Port substring * @throws NotSet */ const std::string& get_port() const { if (authority_.empty()) throw NotSet(); return authority_.front().port(); } /*! * @brief Get authority list * * @return Authority list */ const AuthorityList& get_authority_list() const { return authority_; } /*! * @brief Get URI path * * @return URI path (always set) */ const std::string& get_path() const { return path_.str(); } /*! * @brief Get URI path * * @return URI path * @throws NotSet */ const std::string& get_fragment() const { return fragment_.str(); } /*! * @brief Add query param to URI */ void set_query_param(const std::string&, const std::string&, bool override); void set_option(const std::string& key, const std::string& val) { set_query_param(key, val, true); } void append_option(const std::string& key, const std::string& val) { set_query_param(key, val, false); } /*! * @brief Get URI query list */ const URIQueryList& get_query_list() const { return query_list_; } /*! * @brief return opton by name, * @throws NotFound */ const std::string& get_option(const std::string&) const; const std::string& get_option(const std::string& opt, const std::string& def) const { try { return get_option(opt); } catch (NotFound& ) { return def ; } } private: bool modified_; mutable std::string str_; /*! URI string */ RegEx::Match scheme_; /*! URI scheme part */ AuthorityList authority_; RegEx::Match path_; /*! URI path part */ RegEx::Match fragment_; /*! URI fragment part */ URIQueryList query_list_; /*! URI query list */ /*! * @brief Parse URI from str */ void parse (const std::string& s, bool strict); /*! * @brief Recompose URI in str */ void recompose() const; /*! @throws NotSet */ std::string get_authority(const Authority&) const; static const char* const uri_regex_; /*! regexp string to parse URI */ static RegEx const regex_; /*! URI regexp parser */ }; inline std::ostream& operator<<(std::ostream& os, const URI& uri) { os << uri.to_string(); return os; } } #endif /* __GU_URI_HPP__ */ percona-galera-3-3.8-3390/galerautils/src/gu_utils++.cpp000066400000000000000000000020321244131713600225670ustar00rootroot00000000000000// Copyright (C) 2009-2011 Codership Oy /** * @file General-purpose functions and templates * * $Id$ */ #include "gu_utils.hpp" #include "gu_string_utils.hpp" #include namespace gu { bool _to_bool (const std::string& s) { std::istringstream iss(s); bool ret; if ((iss >> ret).fail()) { /* if 1|0 didn't work, try true|false */ iss.clear(); iss.seekg(0); if ((iss >> std::boolalpha >> ret).fail()) { /* try on/off and yes/no */ std::string tmp(s); gu::trim(tmp); if (tmp.length() >=2 && tmp.length() <= 3) { std::transform (tmp.begin(), tmp.end(), tmp.begin(), static_cast(std::tolower)); if (tmp == "yes" || tmp == "on") return true; if (tmp == "off" || tmp == "no") return false; } throw NotFound(); } } return ret; } } // namespace gu percona-galera-3-3.8-3390/galerautils/src/gu_utils.c000066400000000000000000000040011244131713600220770ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy /** * @file Miscellaneous utility functions * * $Id$ */ #include "gu_utils.h" #include #include #include #include #include const char* gu_str2ll (const char* str, long long* ll) { char* ret; int shift = 0; long long llret = strtoll (str, &ret, 0); switch (ret[0]) { case 't': case 'T': shift += 10; case 'g': case 'G': shift += 10; case 'm': case 'M': shift += 10; case 'k': case 'K': shift += 10; ret++; if (llret == ((llret << (shift + 1)) >> (shift + 1))) { llret <<= shift; } else { /* ERANGE */ if (llret > 0) llret = LLONG_MAX; else llret = LLONG_MIN; } default: *ll = llret; } return ret; } const char* gu_str2dbl (const char* str, double* dbl) { char* ret; *dbl = strtod (str, &ret); return ret; } const char* gu_str2bool (const char* str, bool* b) { size_t len = strlen(str); int res = -1; /* no conversion */ switch (len) { case 1: switch (str[0]) { case '0': case 'N': case 'n': res = 0; break; case '1': case 'Y': case 'y': res = 1; break; } break; case 2: if (!strcasecmp(str, "on")) res = 1; if (!strcasecmp(str, "no")) res = 0; break; case 3: if (!strcasecmp(str, "off")) res = 0; if (!strcasecmp(str, "yes")) res = 1; break; case 4: if (!strcasecmp(str, "true")) res = 1; if (!strcasecmp(str, "sure")) res = 1; if (!strcasecmp(str, "nope")) res = 0; break; case 5: if (!strcasecmp(str, "false")) res = 0; break; } *b = (res > 0); return (res >= 0) ? (str + len) : str; } const char* gu_str2ptr (const char* str, void** ptr) { char* ret; *ptr = (void*) (intptr_t)strtoll (str, &ret, 16); return ret; } percona-galera-3-3.8-3390/galerautils/src/gu_utils.h000066400000000000000000000015731244131713600221170ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy /** * @file Miscellaneous utility functions * * $Id$ */ #ifndef _gu_utils_h_ #define _gu_utils_h_ #include #ifdef __cplusplus extern "C" { #endif /* * The string conversion functions below are slighly customized * versions of standard libc functions designed to understand 'on'/'off' and * K/M/G size modifiers and the like. * * They return pointer to the next character after conversion: * - if (ret == str) no conversion was made * - if (ret[0] == '\0') whole string was converted */ extern const char* gu_str2ll (const char* str, long long* ll); extern const char* gu_str2dbl (const char* str, double* dbl); extern const char* gu_str2bool (const char* str, bool* b); extern const char* gu_str2ptr (const char* str, void** ptr); #ifdef __cplusplus } #endif #endif /* _gu_utils_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_utils.hpp000066400000000000000000000076661244131713600224700ustar00rootroot00000000000000// Copyright (C) 2009-2010 Codership Oy /** * @file General-purpose functions and templates * * $Id$ */ #ifndef _gu_utils_hpp_ #define _gu_utils_hpp_ #include #include #include #include #include "gu_exception.hpp" //#include "gu_string.hpp" namespace gu { /* * String conversion functions for primitive types */ /*! Generic to_string() template function */ template inline std::string to_string(const T& x, std::ios_base& (*f)(std::ios_base&) = std::dec) { std::ostringstream out; out << std::showbase << f << x; return out.str(); } /*! Specialized template: make bool translate into 'true' or 'false' */ template <> inline std::string to_string(const bool& x, std::ios_base& (*f)(std::ios_base&)) { std::ostringstream out; out << std::boolalpha << x; return out.str(); } /*! Specialized template: make double to print with full precision */ template <> inline std::string to_string(const double& x, std::ios_base& (*f)(std::ios_base&)) { const int sigdigits = std::numeric_limits::digits10; // or perhaps std::numeric_limits::max_digits10? std::ostringstream out; out << std::setprecision(sigdigits) << x; return out.str(); } /*! Generic from_string() template. Default base is decimal. * @throws NotFound */ template inline T from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&) = std::dec) { std::istringstream iss(s); T ret; try { if ((iss >> f >> ret).fail()) throw NotFound(); } catch (gu::Exception& e) { throw NotFound(); } return ret; } /*! Specialized template for reading strings. This is to avoid throwing * NotFound in case of empty string. */ template <> inline std::string from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&)) { return s; } /*! Specialized template for reading pointers. Default base is hex. * @throws NotFound */ template <> inline void* from_string(const std::string& s, std::ios_base& (*f)(std::ios_base&)) { std::istringstream iss(s); void* ret; if ((iss >> std::hex >> ret).fail()) throw NotFound(); return ret; } extern "C" const char* gu_str2bool (const char* str, bool* bl); /*! Specialized template for reading bool. Tries both 1|0 and true|false * @throws NotFound */ template <> inline bool from_string (const std::string& s, std::ios_base& (*f)(std::ios_base&)) { bool ret; const char* endptr(gu_str2bool(s.c_str(), &ret)); if (endptr == 0 || *endptr != '\0') throw NotFound(); return ret; } /*! * Substitute for the Variable Length Array on the stack from C99. * Provides automatic deallocation when out of scope: * * void foo(size_t n) { VLA bar(n); bar[0] = 5; throw; } */ template class VLA { T* array; VLA (const VLA&); VLA& operator= (const VLA&); public: VLA (size_t n) : array(new T[n]) {} ~VLA () { delete[] array; } T* operator& () { return array; } T& operator[] (size_t i) { return array[i]; } }; /*! * Object deletion operator. Convenient with STL containers containing * pointers. Example: * * @code * void cleanup() * { * for_each(container.begin(), container.end(), DeleteObject()); * container.clear(); * } * * @endcode */ class DeleteObject { public: template void operator()(T* t) { delete t; } }; /*! swap method for arrays, which does't seem to be built in all compilers */ template inline void swap_array(T (&a)[N], T (&b)[N]) { for (size_t n(0); n < N; ++n) std::swap(a[n], b[n]); } } // namespace gu #endif /* _gu_utils_hpp_ */ percona-galera-3-3.8-3390/galerautils/src/gu_uuid.c000066400000000000000000000115161244131713600217160ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #include "gu_uuid.h" #include "gu_byteswap.h" #include "gu_log.h" #include "gu_assert.h" #include "gu_mutex.h" #include "gu_time.h" #include "gu_rand.h" #include // for rand_r() #include // for memcmp() #include // for fopen() et al #include // for gettimeofday() #include // for getpid() #include // for errno #include const gu_uuid_t GU_UUID_NIL = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; #define UUID_NODE_LEN 6 /** Returns 64-bit system time in 100 nanoseconds */ static uint64_t uuid_get_time () { static long long check = 0; static gu_mutex_t mtx = GU_MUTEX_INITIALIZER; long long t; gu_mutex_lock (&mtx); do { t = gu_time_calendar() / 100; } while (check == t); check = t; gu_mutex_unlock (&mtx); return (t + 0x01B21DD213814000LL); // offset since the start of 15 October 1582 } #ifndef UUID_URAND // This function can't be called too often, // apparently due to lack of entropy in the pool. /** Fills node part of the uuid with true random data from /dev/urand */ static int uuid_urand_node (uint8_t* node, size_t node_len) { static const char urand_name[] = "/dev/urandom"; FILE* urand; size_t i = 0; int c; urand = fopen (urand_name, "r"); if (NULL == urand) { gu_debug ("Failed to open %s for reading (%d).", urand_name, -errno); return -errno; } while (i < node_len && (c = fgetc (urand)) != EOF) { node[i] = (uint8_t) c; i++; } fclose (urand); return 0; } #else #define uuid_urand_node(a,b) true #endif /** Fills node part with pseudorandom data from rand_r() */ static void uuid_rand_node (uint8_t* node, size_t node_len) { unsigned int seed = gu_rand_seed_int (gu_time_calendar(), node, getpid()); size_t i; for (i = 0; i < node_len; i++) { uint32_t r = (uint32_t) rand_r (&seed); /* combine all bytes into the lowest byte */ node[i] = (uint8_t)((r) ^ (r >> 8) ^ (r >> 16) ^ (r >> 24)); } } static inline void uuid_fill_node (uint8_t* node, size_t node_len) { if (uuid_urand_node (node, node_len)) { uuid_rand_node (node, node_len); } } void gu_uuid_generate (gu_uuid_t* uuid, const void* node, size_t node_len) { assert (NULL != uuid); assert (NULL == node || 0 != node_len); uint32_t* uuid32 = (uint32_t*) uuid->data; uint16_t* uuid16 = (uint16_t*) uuid->data; uint64_t uuid_time = uuid_get_time (); uint16_t clock_seq = gu_rand_seed_int (uuid_time, &GU_UUID_NIL, getpid()); /* time_low */ uuid32[0] = gu_be32 (uuid_time & 0xFFFFFFFF); /* time_mid */ uuid16[2] = gu_be16 ((uuid_time >> 32) & 0xFFFF); /* time_high_and_version */ uuid16[3] = gu_be16 (((uuid_time >> 48) & 0x0FFF) | (1 << 12)); /* clock_seq_and_reserved */ uuid16[4] = gu_be16 ((clock_seq & 0x3FFF) | 0x8000); /* node */ if (NULL != node && 0 != node_len) { memcpy (&uuid->data[10], node, node_len > UUID_NODE_LEN ? UUID_NODE_LEN : node_len); } else { uuid_fill_node (&uuid->data[10], UUID_NODE_LEN); uuid->data[10] |= 0x02; /* mark as "locally administered" */ } return; } /** * Compare two UUIDs * @return -1, 0, 1 if left is respectively less, equal or greater than right */ long gu_uuid_compare (const gu_uuid_t* left, const gu_uuid_t* right) { return memcmp (left, right, sizeof(gu_uuid_t)); } static uint64_t uuid_time (const gu_uuid_t* uuid) { uint64_t uuid_time; /* time_high_and_version */ uuid_time = gu_be16 (((uint16_t*)uuid->data)[3]) & 0x0FFF; /* time_mid */ uuid_time = (uuid_time << 16) + gu_be16 (((uint16_t*)uuid->data)[2]); /* time_low */ uuid_time = (uuid_time << 32) + gu_be32 (((uint32_t*)uuid->data)[0]); return uuid_time; } /** * Compare ages of two UUIDs * @return -1, 0, 1 if left is respectively younger, equal or older than right */ long gu_uuid_older (const gu_uuid_t* left, const gu_uuid_t* right) { uint64_t time_left = uuid_time (left); uint64_t time_right = uuid_time (right); if (time_left < time_right) return 1; if (time_left > time_right) return -1; return 0; } ssize_t gu_uuid_print(const gu_uuid_t* uuid, char* buf, size_t buflen) { if (buflen < GU_UUID_STR_LEN) return -1; return sprintf(buf, GU_UUID_FORMAT, GU_UUID_ARGS(uuid)); } ssize_t gu_uuid_scan(const char* buf, size_t buflen, gu_uuid_t* uuid) { ssize_t ret; if (buflen < GU_UUID_STR_LEN) return -1; ret = sscanf(buf, GU_UUID_FORMAT_SCANF, GU_UUID_ARGS_SCANF(uuid)); if (ret != sizeof(uuid->data)) return -1; return ret; } percona-galera-3-3.8-3390/galerautils/src/gu_uuid.h000066400000000000000000000055271244131713600217300ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Universally Unique IDentifier. RFC 4122. * Time-based implementation. * */ #ifndef _gu_uuid_h_ #define _gu_uuid_h_ #include "gu_types.h" #ifdef __cplusplus extern "C" { #endif /*! UUID internally is represented as a BE integer which allows using * memcmp() as comparison function and straightforward printing */ #define GU_UUID_LEN 16 typedef struct { uint8_t data[GU_UUID_LEN]; } gu_uuid_t; extern const gu_uuid_t GU_UUID_NIL; /*! length of string representation */ #define GU_UUID_STR_LEN 36 /*! Macros for pretty printing */ #define GU_UUID_FORMAT \ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" #define GU_UUID_ARGS(uuid) \ (uuid)->data[ 0], (uuid)->data[ 1], (uuid)->data[ 2], (uuid)->data[ 3],\ (uuid)->data[ 4], (uuid)->data[ 5], (uuid)->data[ 6], (uuid)->data[ 7],\ (uuid)->data[ 8], (uuid)->data[ 9], (uuid)->data[10], (uuid)->data[11],\ (uuid)->data[12], (uuid)->data[13], (uuid)->data[14], (uuid)->data[15] /* this is used for scanf, variables are by reference */ #define GU_UUID_FORMAT_SCANF \ "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" #define GU_UUID_ARGS_SCANF(uuid) \ &(uuid)->data[ 0], &(uuid)->data[ 1], &(uuid)->data[ 2], &(uuid)->data[ 3],\ &(uuid)->data[ 4], &(uuid)->data[ 5], &(uuid)->data[ 6], &(uuid)->data[ 7],\ &(uuid)->data[ 8], &(uuid)->data[ 9], &(uuid)->data[10], &(uuid)->data[11],\ &(uuid)->data[12], &(uuid)->data[13], &(uuid)->data[14], &(uuid)->data[15] /*! * Generates new UUID. * If node is NULL, will generate random (if /dev/urand is present) or * pseudorandom data instead. * @param uuid * pointer to uuid_t * @param node * some unique data that goes in place of "node" field in the UUID * @param node_len * length of the node buffer */ extern void gu_uuid_generate (gu_uuid_t* uuid, const void* node, size_t node_len); /*! * Compare two UUIDs according to RFC * @return -1, 0, 1 if left is respectively less, equal or greater than right */ extern long gu_uuid_compare (const gu_uuid_t* left, const gu_uuid_t* right); /*! * Compare ages of two UUIDs * @return -1, 0, 1 if left is respectively younger, equal or older than right */ extern long gu_uuid_older (const gu_uuid_t* left, const gu_uuid_t* right); /*! * Print UUID into buffer * @return Number of bytes printed (not including trailing '\0') or -1 on error. */ extern ssize_t gu_uuid_print(const gu_uuid_t* uuid, char* buf, size_t buflen); /*! * Scan UUID from buffer * @return Number of bytes read (should match to sizeof(uuid)) or -1 on error */ extern ssize_t gu_uuid_scan(const char* buf, size_t buflen, gu_uuid_t* uuid); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _gu_uuid_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_uuid.hpp000066400000000000000000000100271244131713600222570ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy * */ #ifndef _gu_uuid_hpp_ #define _gu_uuid_hpp_ #include "gu_uuid.h" #include "gu_assert.hpp" #include "gu_buffer.hpp" #include inline bool operator==(const gu_uuid_t& a, const gu_uuid_t& b) { return gu_uuid_compare(&a, &b) == 0; } inline bool operator!=(const gu_uuid_t& a, const gu_uuid_t& b) { return !(a == b); } inline std::ostream& operator<<(std::ostream& os, const gu_uuid_t& uuid) { char uuid_buf[GU_UUID_STR_LEN + 1]; ssize_t ret(gu_uuid_print(&uuid, uuid_buf, sizeof(uuid_buf))); (void)ret; assert(ret == GU_UUID_STR_LEN); uuid_buf[GU_UUID_STR_LEN] = '\0'; return (os << uuid_buf); } inline ssize_t gu_uuid_from_string(const std::string& s, gu_uuid_t& uuid) { ssize_t ret(gu_uuid_scan(s.c_str(), s.size(), &uuid)); if (ret == -1) { gu_throw_error(EINVAL) << "could not parse UUID from '" << s << '\'' ; } return ret; } inline std::istream& operator>>(std::istream& is, gu_uuid_t& uuid) { char str[GU_UUID_STR_LEN + 1]; is.width(GU_UUID_STR_LEN + 1); is >> str; gu_uuid_from_string(str, uuid); return is; } inline size_t gu_uuid_serial_size(const gu_uuid_t& uuid) { return sizeof(uuid.data); } inline size_t gu_uuid_serialize(const gu_uuid_t& uuid, gu::byte_t* buf, size_t buflen, size_t offset) { if (offset + gu_uuid_serial_size(uuid) > buflen) gu_throw_error (EMSGSIZE) << gu_uuid_serial_size(uuid) << " > " << (buflen - offset); memcpy(buf + offset, uuid.data, gu_uuid_serial_size(uuid)); offset += gu_uuid_serial_size(uuid); return offset; } inline size_t gu_uuid_unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, gu_uuid_t& uuid) { if (offset + gu_uuid_serial_size(uuid) > buflen) gu_throw_error (EMSGSIZE) << gu_uuid_serial_size(uuid) << " > " << (buflen - offset); memcpy(uuid.data, buf + offset, gu_uuid_serial_size(uuid)); offset += gu_uuid_serial_size(uuid); return offset; } namespace gu { class UUID; } class gu::UUID { public: UUID() : uuid_(GU_UUID_NIL) {} UUID(const void* node, const size_t node_len) : uuid_() { gu_uuid_generate(&uuid_, node, node_len); } UUID(gu_uuid_t uuid) : uuid_(uuid) {} virtual ~UUID() {} size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { return gu_uuid_unserialize(buf, buflen, offset, uuid_); } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { return gu_uuid_serialize(uuid_, buf, buflen, offset); } static size_t serial_size() { return sizeof(gu_uuid_t); } const gu_uuid_t* uuid_ptr() const { return &uuid_; } bool operator<(const UUID& cmp) const { return (gu_uuid_compare(&uuid_, &cmp.uuid_) < 0); } bool operator==(const UUID& cmp) const { return (gu_uuid_compare(&uuid_, &cmp.uuid_) == 0); } bool older(const UUID& cmp) const { return (gu_uuid_older(&uuid_, &cmp.uuid_) > 0); } std::ostream& write_stream(std::ostream& os) const { char uuid_buf[GU_UUID_STR_LEN + 1]; ssize_t ret(gu_uuid_print(&uuid_, uuid_buf, sizeof(uuid_buf))); (void)ret; assert(ret == GU_UUID_STR_LEN); uuid_buf[GU_UUID_STR_LEN] = '\0'; return (os << uuid_buf); } std::istream& read_stream(std::istream& is) { char str[GU_UUID_STR_LEN + 1]; is.width(GU_UUID_STR_LEN + 1); is >> str; ssize_t ret(gu_uuid_scan(str, GU_UUID_STR_LEN, &uuid_)); if (ret == -1) gu_throw_error(EINVAL) << "could not parse UUID from '" << str << '\'' ; return is; } protected: gu_uuid_t uuid_; }; // class UUID #endif // _gu_uuid_hpp_ percona-galera-3-3.8-3390/galerautils/src/gu_vec16.h000066400000000000000000000035271244131713600217040ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /** * @file 16-byte "vector" type and operations - mostly for checksums/hashes * * $Id$ */ #ifndef _gu_vec16_h_ #define _gu_vec16_h_ #include "gu_macros.h" #include "gu_byteswap.h" #include #include #include /* bool */ #ifdef __cplusplus extern "C" { #endif /* this type will generate SIMD instructions where possible: good for XORing */ typedef unsigned long gu_vec16__ __attribute__ ((vector_size (16))); typedef union gu_vec16 { gu_vec16__ vec_; uint64_t int_[2]; /* for equality we better use scalar type * since we need scalar return */ } gu_vec16_t; static GU_FORCE_INLINE gu_vec16_t gu_vec16_from_byte (unsigned char b) { gu_vec16_t ret; memset (&ret, b, sizeof(ret)); return ret; } static GU_FORCE_INLINE gu_vec16_t gu_vec16_from_ptr (const void* ptr) { gu_vec16_t ret; memcpy (&ret, ptr, sizeof(ret)); return ret; } static GU_FORCE_INLINE gu_vec16_t gu_vec16_xor (gu_vec16_t l, gu_vec16_t r) { gu_vec16_t ret; ret.vec_ = (l.vec_ ^ r.vec_); return ret; } static GU_FORCE_INLINE bool gu_vec16_neq (gu_vec16_t l, gu_vec16_t r) { return (l.int_[0] != r.int_[0] || l.int_[1] != r.int_[1]); } static GU_FORCE_INLINE bool gu_vec16_eq (gu_vec16_t l, gu_vec16_t r) { return !(gu_vec16_neq (l, r)); } static GU_FORCE_INLINE gu_vec16_t gu_vec16_bswap (gu_vec16_t x) { gu_vec16_t ret; ret.int_[0] = gu_bswap64 (x.int_[1]); ret.int_[1] = gu_bswap64 (x.int_[0]); return ret; } #ifdef __cplusplus } static GU_FORCE_INLINE gu_vec16_t operator^ (const gu_vec16_t& l, const gu_vec16_t& r) { return (gu_vec16_xor (l, r)); } static GU_FORCE_INLINE bool operator== (const gu_vec16_t& l, const gu_vec16_t& r) { return (gu_vec16_eq (l, r)); } #endif #endif /* _gu_vec16_h_ */ percona-galera-3-3.8-3390/galerautils/src/gu_vector.hpp000066400000000000000000000105151244131713600226150ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy /*! * @file implementation of STL vector functionality "on the stack", that is * with initial buffer for allocations reserved inside the object: * * gu::Vector v; * v().resize(5); // uses internal buffer (in this case on the stack) * v().resize(20); // overflows into heap * * In many cases, when the number of elements in a vector is predictably low or * even known exactly, this will save us from going to heap just to allocate * few elements. * * Rather than manually rewriting all std::vector methods, we return * a reference to std::vector object via operator(). operator[] is also * rewritten to provide the familiar v[i] interface. * * $Id$ */ #ifndef _GU_VECTOR_HPP_ #define _GU_VECTOR_HPP_ #include "gu_reserved_container.hpp" #include namespace gu { /* gu::VectorBase is an interface to generalize gu::Vector template over * capacity so that it is possible to pass gu::Vector objects * by reference to gu::VectorBase */ template class VectorBase { public: typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef typename ReservedAllocator::size_type size_type; virtual reference operator[] (size_type i) = 0; virtual const_reference operator[] (size_type i) const = 0; virtual size_type size () const = 0; virtual void reserve (size_type n) = 0; virtual void resize (size_type n, value_type val = value_type()) = 0; // Now iterators, which I have no time for ATM. Leaving unfinished. protected: VectorBase() {} virtual ~VectorBase() {} }; /* a base class to be used as a member of other classes */ template ::size_type capacity> class Vector { public: Vector() : rv_() {} Vector(const Vector& other) : rv_() { rv_().assign(other().begin(), other().end()); } Vector& operator= (Vector other) { using namespace std; swap(other); return *this; } typedef ReservedAllocator Allocator; typedef std::vector ContainerType; ContainerType& operator() () { return rv_.container(); } const ContainerType& operator() () const { return rv_.container(); } ContainerType* operator-> () { return rv_.operator->(); } const ContainerType* operator-> () const { return rv_.operator->(); } typedef typename VectorBase::size_type size_type; T& operator[] (size_type i) { return operator()()[i]; } const T& operator[] (size_type i) const { return operator()()[i]; } size_type size () const { return operator()().size(); } void reserve (size_type n) { operator()().reserve(n); } typedef typename VectorBase::value_type value_type; void resize (size_type n, value_type val = value_type()) { operator()().resize(n, val); } bool in_heap() const // for testing { return (rv_.reserved_buffer() != &rv_.container()[0]); } private: ReservedContainer rv_; }; /* class Vector*/ /* Vector class derived from VectorBase - to be passed as a parameter */ template ::size_type capacity> class VectorDerived : public VectorBase { public: typedef typename VectorBase::size_type size_type; typedef typename VectorBase::value_type value_type; typedef typename VectorBase::reference reference; typedef typename VectorBase::const_reference const_reference; VectorDerived() : VectorBase(), v_() {} template ::size_type C> VectorDerived(const Vector& other) : VectorBase(), v_() { v_().assign(other().begin(), other().end()); } reference operator[] (size_type i) { return v_[i]; } const_reference operator[] (size_type i) const { return v_[i]; } size_type size () const { return v_.size(); } void reserve (size_type n) { v_.reserve(); } void resize (size_type n, value_type val = value_type()) { v_.resize(); } private: Vector v_; }; /* class VectorDerived */ } /* namespace gu */ #endif /* _GU_VECTOR_HPP_ */ percona-galera-3-3.8-3390/galerautils/src/gu_vlq.cpp000066400000000000000000000032631244131713600221120ustar00rootroot00000000000000// // Copyright (C) 2013 Codership Oy // //! // @file Variable-length quantity encoding for integers // // Unsigned integers: Implementation uses using unsigned LEB128, // see for example http://en.wikipedia.org/wiki/LEB128. // // Signed integers: TODO // #include "gu_vlq.hpp" namespace gu { /* checks helper for the uleb128_decode() */ void uleb128_decode_checks (const byte_t* buf, size_t buflen, size_t offset, size_t avail_bits) { // Check if trying to read past last byte in buffer without // encountering byte without 0x80 bit set. if (offset >= buflen) { gu_throw_error(EINVAL) << "read value is not uleb128 representation, missing " << "terminating byte before end of input"; } assert(avail_bits > 0); if (avail_bits < 7) { // mask to check if the remaining value can be represented // with available bits gu::byte_t mask(~((1 << avail_bits) - 1)); if ((buf[offset] & mask) != 0) { gu_throw_error(EOVERFLOW) << "read value not representable with avail bits: " << avail_bits << " mask: 0x" << std::hex << static_cast(mask) << " buf: 0x" << std::hex << static_cast(buf[offset]) << " excess: 0x" << std::hex << static_cast(mask & buf[offset]); } } } } /* namespace gu */ percona-galera-3-3.8-3390/galerautils/src/gu_vlq.hpp000066400000000000000000000112451244131713600221160ustar00rootroot00000000000000// // Copyright (C) 2011-2013 Codership Oy // //! // @file Variable-length quantity encoding for integers // // Unsigned integers: Implementation uses using unsigned LEB128, // see for example http://en.wikipedia.org/wiki/LEB128. // // Signed integers: TODO // #ifndef GU_VLQ_HPP #define GU_VLQ_HPP #include "gu_buffer.hpp" #include "gu_throw.hpp" #include "gu_macros.h" #define GU_VLQ_CHECKS #define GU_VLQ_ALEX namespace gu { //! // @brief Retun number of bytes required to represent given value in ULEB128 // representation. // // @param value Unsigned value // // @return Number of bytes required for value representation // template inline size_t uleb128_size(UI value) { size_t i(1); value >>= 7; for (; value != 0; value >>= 7, ++i) {} return i; } //! // @brief Encode unsigned type to ULEB128 representation // // @param value // @param buf // @param buflen // @param offset // // @return Offset // template inline size_t uleb128_encode(UI value, byte_t* buf, size_t buflen, size_t offset) { #ifdef GU_VLQ_ALEX assert (offset < buflen); buf[offset] = value & 0x7f; while (value >>= 7) { buf[offset] |= 0x80; ++offset; #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #else assert(offset < buflen); #endif /* GU_VLQ_CHECKS */ buf[offset] = value & 0x7f; } return offset + 1; #else /* GU_VLQ_ALEX */ do { #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #else assert(offset < buflen); #endif /* GU_VLQ_CHECKS */ buf[offset] = value & 0x7f; value >>= 7; if (gu_unlikely(value != 0)) { buf[offset] |= 0x80; } ++offset; } while (value != 0); return offset; #endif /* GU_VLQ_ALEX */ } template inline size_t uleb128_encode(UI value, byte_t* buf, size_t buflen) { return uleb128_encode(value, buf, buflen, 0); } /* checks helper for the uleb128_decode() below */ extern void uleb128_decode_checks (const byte_t* buf, size_t buflen, size_t offset, size_t avail_bits); //! // @brief Decode unsigned type from ULEB128 representation // // @param buf // @param buflen // @param offset // @param value // // @return Offset // template inline size_t uleb128_decode(const byte_t* buf, size_t buflen, size_t offset, UI& value) { // initial check for overflow, at least one byte must be readable #ifdef GU_VLQ_CHECKS if (gu_unlikely(offset >= buflen)) gu_throw_fatal; #endif #ifdef GU_VLQ_ALEX value = buf[offset] & 0x7f; size_t shift(0); while (buf[offset] & 0x80) { ++offset; shift +=7; #ifdef GU_VLQ_CHECKS ssize_t left_bits((sizeof(UI) << 3) - shift); if (gu_unlikely(offset >= buflen || left_bits < 7)) uleb128_decode_checks (buf, buflen, offset, left_bits); #endif value |= (UI(buf[offset] & 0x7f) << shift); } return offset + 1; #else /* GU_VLQ_ALEX */ value = 0; size_t shift(0); while (true) { value |= (UI(buf[offset] & 0x7f) << shift); if (gu_likely((buf[offset] & 0x80) == 0)) { // last byte ++offset; break; } ++offset; shift += 7; #ifdef GU_VLQ_CHECKS ssize_t left_bits((sizeof(UI) << 3) - shift); if (gu_unlikely(offset >= buflen || left_bits < 7)) uleb128_decode_checks (buf, buflen, offset, left_bits); #endif } return offset; #endif /* GU_VLQ_ALEX */ } template inline size_t uleb128_decode(const byte_t* buf, size_t buflen, UI& value) { return uleb128_decode(buf, buflen, 0, value); } } #endif // GU_VLQ_HPP percona-galera-3-3.8-3390/galerautils/tests/000077500000000000000000000000001244131713600204605ustar00rootroot00000000000000percona-galera-3-3.8-3390/galerautils/tests/SConscript000066400000000000000000000041071244131713600224740ustar00rootroot00000000000000 Import('check_env') env = check_env.Clone() env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) gu_tests = env.Program(target = 'gu_tests', source = Split(''' gu_tests.c gu_mem_test.c gu_vec_test.c gu_bswap_test.c gu_fnv_test.c gu_mmh3_test.c gu_spooky_test.c gu_crc32c_test.c gu_hash_test.c gu_time_test.c gu_fifo_test.c gu_uuid_test.c gu_dbug_test.c gu_lock_step_test.c gu_str_test.c gu_utils_test.c ''')) env.Test("gu_tests.passed", gu_tests) env.Alias("test", "gu_tests.passed") Clean(gu_tests, '#/gu_tests.log') gu_testspp = env.Program(target = 'gu_tests++', source = Split(''' gu_atomic_test.cpp gu_vector_test.cpp gu_string_test.cpp gu_vlq_test.cpp gu_digest_test.cpp gu_mem_pool_test.cpp gu_alloc_test.cpp gu_rset_test.cpp gu_string_utils_test.cpp gu_uri_test.cpp gu_config_test.cpp gu_net_test.cpp gu_datetime_test.cpp gu_histogram_test.cpp gu_stats_test.cpp gu_tests++.cpp ''')) env.Test("gu_tests++.passed", gu_testspp) env.Alias("test", "gu_tests++.passed") Clean(gu_testspp, '#/gu_tests++.log') percona-galera-3-3.8-3390/galerautils/tests/gu_alloc_test.cpp000066400000000000000000000042631244131713600240150ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy // $Id$ #include "../src/gu_alloc.hpp" #include "gu_alloc_test.hpp" class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; START_TEST (basic) { ssize_t const extra_size(1 << 12); /* extra size to force new page */ gu::byte_t reserved[extra_size]; const char test0[] = "test0"; ssize_t const test0_size(sizeof(test0)); const char test1[] = "test1"; ssize_t const test1_size(sizeof(test1) + extra_size); TestBaseName test_name("gu_alloc_test"); gu::Allocator a(test_name, reserved, sizeof(reserved), sizeof(test1), 1 << 16); mark_point(); void* p; size_t r, s = 0; bool n; r = 0; s += r; mark_point(); p = a.alloc(r, n); fail_if (p != 0); fail_if (n); fail_if (a.size() != s); r = test0_size; s += r; mark_point(); p = a.alloc(r, n); fail_if (0 == p); fail_if (n); fail_if (a.size() != s); strcpy (reinterpret_cast(p), test0); r = test1_size; s += r; mark_point(); p = a.alloc(r, n); fail_if (0 == p); fail_if (!n); /* new page must be allocated */ fail_if (a.size() != s); strcpy (reinterpret_cast(p), test1); r = 0; s += r; mark_point(); p = a.alloc(r, n); fail_if (p != 0); fail_if (n); fail_if (a.size() != s); #ifdef GU_ALLOCATOR_DEBUG std::vector out; out.reserve (a.count()); mark_point(); size_t out_size = a.gather (out); fail_if (out_size != test0_size + test1_size); fail_if (out.size() != 2); fail_if (out[0].size != test0_size); fail_if (strcmp(reinterpret_cast(out[0].ptr), test0)); fail_if (out[1].size != test1_size); fail_if (strcmp(reinterpret_cast(out[1].ptr), test1)); #endif /* GU_ALLOCATOR_DEBUG */ } END_TEST Suite* gu_alloc_suite () { TCase* t = tcase_create ("Allocator"); tcase_add_test (t, basic); Suite* s = suite_create ("gu::Allocator"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_alloc_test.hpp000066400000000000000000000003171244131713600240160ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_alloc_test__ #define __gu_alloc_test__ #include extern Suite *gu_alloc_suite(void); #endif /* __gu_alloc_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_atomic_test.cpp000066400000000000000000000103031244131713600241670ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_atomic.hpp" #include "gu_atomic_test.hpp" #include "gu_limits.h" #include START_TEST(test_sanity_c) { int64_t i, j, k; i = 1; j = 0; k = 3; gu_atomic_set(&i, &j); fail_if(j != 0); fail_if(i != 0); gu_atomic_get(&i, &k); fail_if(i != 0); fail_if(k != 0); j = gu_atomic_fetch_and_add (&i, 7); fail_if(j != 0); fail_if(i != 7); j = gu_atomic_fetch_and_sub (&i, 10); fail_if(j != 7); fail_if(i != -3); j = gu_atomic_fetch_and_or (&i, 15); fail_if(j != -3); fail_if(i != -1); j = gu_atomic_fetch_and_and (&i, 5); fail_if(j != -1); fail_if(i != 5); j = gu_atomic_fetch_and_xor (&i, 3); fail_if(j != 5); fail_if(i != 6); j = gu_atomic_fetch_and_nand(&i, 15); fail_if(j != 6); fail_if(i != -7); j = gu_atomic_add_and_fetch (&i, 7); fail_if(j != 0); fail_if(i != 0); j = gu_atomic_sub_and_fetch (&i, -2); fail_if(j != 2); fail_if(i != 2); j = gu_atomic_or_and_fetch (&i, 5); fail_if(j != 7); fail_if(i != 7); j = gu_atomic_and_and_fetch (&i, 13); fail_if(j != 5); fail_if(i != 5); j = gu_atomic_xor_and_fetch (&i, 15); fail_if(j != 10); fail_if(i != 10); j = gu_atomic_nand_and_fetch(&i, 7); fail_if(j != -3); fail_if(i != -3); } END_TEST START_TEST(test_sanity_cxx) { gu::Atomic i(1); int64_t const k(3); fail_if(i() != 1); fail_if(i() == k); fail_if((i = k) != k); fail_if(i() != k); fail_if(i.fetch_and_zero() != k); fail_if(i() != 0); fail_if(i.fetch_and_add(5) != 0); fail_if(i() != 5); fail_if(i.add_and_fetch(3) != 8); fail_if(i() != 8); fail_if((++i)() != 9); fail_if(i() != 9); fail_if((--i)() != 8); fail_if(i() != 8); i += 3; fail_if(i() != 11); } END_TEST // we want it sufficiently long to test above least 4 bytes, but sufficiently // short to avoid overflow static long long const increment(333333333333LL); // number of add/sub thread pairs static int const n_threads(8); // maximum iterations number (to guarantee no overflow) static int const max_iter(GU_LONG_LONG_MAX/increment/n_threads); // number of iterations capped at 1M, just in case static int const iterations(max_iter > 1000000 ? 1000000 : max_iter); static void* add_loop(void* arg) { int64_t* const var(static_cast(arg)); for (int i(iterations); --i;) { gu_atomic_fetch_and_add(var, increment); } return NULL; } static void* sub_loop(void* arg) { int64_t* const var(static_cast(arg)); for (int i(iterations); --i;) { gu_atomic_fetch_and_sub(var, increment); } return NULL; } static int start_threads(pthread_t* threads, int64_t* var) { for (int i(0); i < n_threads; ++i) { pthread_t* const add_thr(&threads[i * 2]); pthread_t* const sub_thr(add_thr + 1); int const add_err(pthread_create(add_thr, NULL, add_loop, var)); int const sub_err(pthread_create(sub_thr, NULL, sub_loop, var)); if (add_err != 0) return add_err; if (sub_err != 0) return sub_err; } return 0; } static int join_threads(pthread_t* threads) { for (int i(0); i < n_threads; ++i) { pthread_t* const add_thr(&threads[i * 2]); pthread_t* const sub_thr(add_thr + 1); int const add_err(pthread_join(*add_thr, NULL)); int const sub_err(pthread_join(*sub_thr, NULL)); if (add_err != 0) return add_err; if (sub_err != 0) return sub_err; } return 0; } // This may not catch concurrency problems every time. But sometimes it should // (if there are any). START_TEST(test_concurrency) { fail_if(iterations < 1000000); int64_t var(0); pthread_t threads[n_threads * 2]; fail_if(start_threads(threads, &var)); fail_if(join_threads(threads)); fail_if(0 != var); } END_TEST Suite* gu_atomic_suite() { TCase* t1 = tcase_create ("sanity"); tcase_add_test (t1, test_sanity_c); tcase_add_test (t1, test_sanity_cxx); TCase* t2 = tcase_create ("concurrency"); tcase_add_test (t2, test_concurrency); tcase_set_timeout(t2, 60); Suite* s = suite_create ("gu::Atomic"); suite_add_tcase (s, t1); suite_add_tcase (s, t2); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_atomic_test.hpp000066400000000000000000000003141244131713600241750ustar00rootroot00000000000000// Copyright (C) 2014 Codership Oy // $Id$ #ifndef __gu_atomic_test__ #define __gu_atomic_test__ #include Suite *gu_atomic_suite(void); #endif /* __gu_atomic_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_bswap_test.c000066400000000000000000000026751244131713600235040ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "gu_bswap_test.h" #include "../src/gu_byteswap.h" START_TEST (gu_bswap_test) { // need volatile to prevent compile-time optimization volatile uint16_t s = 0x1234; volatile uint32_t i = 0x12345678; volatile uint64_t l = 0x1827364554637281LL; uint16_t sle, sbe; uint32_t ile, ibe; uint64_t lle, lbe; // first conversion sle = gu_le16(s); sbe = gu_be16(s); ile = gu_le32(i); ibe = gu_be32(i); lle = gu_le64(l); lbe = gu_be64(l); #if __BYTE_ORDER == __LITTLE_ENDIAN fail_if (s != sle); fail_if (i != ile); fail_if (l != lle); fail_if (s == sbe); fail_if (i == ibe); fail_if (l == lbe); #else fail_if (s == sle); fail_if (i == ile); fail_if (l == lle); fail_if (s != sbe); fail_if (i != ibe); fail_if (l != lbe); #endif /* __BYTE_ORDER */ // second conversion sle = gu_le16(sle); sbe = gu_be16(sbe); ile = gu_le32(ile); ibe = gu_be32(ibe); lle = gu_le64(lle); lbe = gu_be64(lbe); fail_if (s != sle); fail_if (i != ile); fail_if (l != lle); fail_if (s != sbe); fail_if (i != ibe); fail_if (l != lbe); } END_TEST Suite *gu_bswap_suite(void) { Suite *s = suite_create("Galera byteswap functions"); TCase *tc = tcase_create("gu_bswap"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_bswap_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_bswap_test.h000066400000000000000000000002641244131713600235010ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_bswap_test__ #define __gu_bswap_test__ Suite *gu_bswap_suite(void); #endif /* __gu_bswap_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_config_test.cpp000066400000000000000000000035451244131713600241720ustar00rootroot00000000000000// Copyright (C) 2013-2014 Codership Oy // $Id$ #include "../src/gu_config.hpp" #include "gu_config_test.hpp" static std::string const key("test_key"); static std::string const another_key("another_key"); static std::string const str_value("123"); static long long const int_value( 123 ); START_TEST (gu_config_test) { gu::Config cnf; std::string svalue; long long ivalue; fail_if(cnf.has(key)); try { cnf.is_set(key); fail("gu::NotFound expected"); } catch(gu::NotFound&) {} cnf.add(key); fail_unless(cnf.has(key)); fail_if(cnf.is_set(key)); #define SUFFIX_CHECK(_suf_,_shift_) \ svalue = str_value + _suf_; \ cnf.set(key, svalue); \ fail_unless(cnf.is_set(key)); \ fail_unless(cnf.get(key) == svalue); \ ivalue = cnf.get(key); \ fail_if(ivalue != (int_value << _shift_)); SUFFIX_CHECK('T', 40); // check overflow checks try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} try { ivalue = cnf.get(key); fail("gu::Exception expected"); } catch (gu::Exception&) {} SUFFIX_CHECK('G', 30); SUFFIX_CHECK('M', 20); SUFFIX_CHECK('K', 10); // try { cnf.add(key, str_value); fail("gu::Exception expected"); } // catch (gu::Exception& e) {} cnf.add(another_key, str_value); fail_unless(cnf.is_set(another_key)); ivalue = cnf.get(another_key); fail_if(ivalue != int_value); } END_TEST Suite *gu_config_suite(void) { Suite *s = suite_create("gu::Config"); TCase *tc = tcase_create("gu_config_test"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_config_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_config_test.hpp000066400000000000000000000003231244131713600241660ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_config_test__ #define __gu_config_test__ #include extern Suite *gu_config_suite(void); #endif /* __gu_config_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_crc32c_test.c000066400000000000000000000064121244131713600234400ustar00rootroot00000000000000/* * Copyright (C) 2013-2014 Codership Oy * * $Id$ */ #include "../src/gu_crc32c.h" #include "gu_crc32c_test.h" #include #define long_input \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" \ "0123456789abcdef0123456789ABCDEF" #define long_output 0x7e5806b3 struct test_pair { const char* input; uint32_t output; }; //#define test_vector_length 6 /* * boost::crc_optimal<32, 0x1EDC6F41, 0, 0, true, true> crc; */ static struct test_pair test_vector[] = { { "", 0x00000000 }, { "1", 0x90f599e3 }, { "22", 0x47b26cf9 }, { "333", 0x4cb6e5c8 }, { "4444", 0xfb8150f7 }, { "55555", 0x23874b2f }, { "666666", 0xfad65244 }, { "7777777", 0xe4cbaa36 }, { "88888888", 0xda8901c2 }, { "123456789", 0xe3069283 }, // taken from SCTP mailing list { "My", 0xc7600404 }, // taken from { "test", 0x86a072c0 }, // http://www.zorc.breitbandkatze.de/crc.html { "vector", 0xa0b8f38a }, { long_input, long_output}, { NULL, 0x0 } }; static void test_function(void) { int i; for (i = 0; test_vector[i].input != NULL; i++) { const char* const input = test_vector[i].input; uint32_t const output = test_vector[i].output; uint32_t ret = gu_crc32c(input, strlen(input)); fail_if(ret != output, "Input '%s' resulted in %#08x, expected %#08x\n", input, ret, output); } const char* const input = long_input; uint32_t const output = long_output; int const size = strlen(input); int offset = 0; gu_crc32c_t crc; gu_crc32c_init(&crc); #define CRC_APPEND(x) gu_crc32c_append(&crc, &input[offset], x); offset += x; CRC_APPEND(1); CRC_APPEND(3); CRC_APPEND(5); CRC_APPEND(7); CRC_APPEND(13); CRC_APPEND(15); mark_point(); CRC_APPEND(0); CRC_APPEND(27); CRC_APPEND(43); CRC_APPEND(64); int tail = size - offset; fail_if (tail < 0); CRC_APPEND(tail); uint32_t ret = gu_crc32c_get (crc); fail_if (ret != output, "Generated %#08x, expected %#08x\n", ret, output); } START_TEST(test_Sarwate) { gu_crc32c_func = crc32cSarwate; test_function(); } END_TEST START_TEST(test_SlicingBy4) { gu_crc32c_func = crc32cSlicingBy4; test_function(); } END_TEST START_TEST(test_SlicingBy8) { gu_crc32c_func = crc32cSlicingBy8; test_function(); } END_TEST // will run a hardware test, if available START_TEST(test_hardware) { gu_crc32c_configure(); test_function(); } END_TEST Suite *gu_crc32c_suite(void) { Suite *suite = suite_create("CRC32C implementation"); TCase *sw = tcase_create("test_sw"); suite_add_tcase (suite, sw); tcase_add_test (sw, test_Sarwate); tcase_add_test (sw, test_SlicingBy4); tcase_add_test (sw, test_SlicingBy8); TCase *hw = tcase_create("test_hw"); suite_add_tcase (suite, hw); tcase_add_test (hw, test_hardware); return suite; } percona-galera-3-3.8-3390/galerautils/tests/gu_crc32c_test.h000066400000000000000000000003331244131713600234410ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_crc32c_test_h__ #define __gu_crc32c_test_h__ #include Suite* gu_crc32c_suite(void); #endif /* __gu_crc32c_test_h__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_datetime_test.cpp000066400000000000000000000065721244131713600245240ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #include "gu_datetime.hpp" #include "gu_logger.hpp" #include "gu_utils.hpp" #include "gu_datetime_test.hpp" using namespace gu; using namespace gu::datetime; START_TEST(test_units) { fail_unless(NSec == 1LL); fail_unless(USec == 1000LL); fail_unless(MSec == 1000LL*1000LL); fail_unless(Sec == 1000LL*1000LL*1000LL); fail_unless(Min == 60LL*1000LL*1000LL*1000LL); fail_unless(Hour == 60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Day == 24LL*60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Month == 30LL*24LL*60LL*60LL*1000LL*1000LL*1000LL); fail_unless(Year == 12LL*30LL*24LL*60LL*60LL*1000LL*1000LL*1000LL); } END_TEST START_TEST(test_period) { // Zero periods fail_unless(Period("").get_nsecs() == 0); fail_unless(Period("P").get_nsecs() == 0); fail_unless(Period("PT").get_nsecs() == 0); // Year-mon-day fail_unless(Period("P3Y").get_nsecs() == 3*Year); fail_unless(Period("P5M").get_nsecs() == 5*Month); fail_unless(Period("P37D").get_nsecs() == 37*Day); fail_unless(Period("P3Y17M").get_nsecs() == 3*Year + 17*Month); fail_unless(Period("P5Y66D").get_nsecs() == 5*Year + 66*Day); fail_unless(Period("P37M44D").get_nsecs() == 37*Month + 44*Day); fail_unless(Period("P3YT").get_nsecs() == 3*Year); fail_unless(Period("P5MT").get_nsecs() == 5*Month); fail_unless(Period("P37DT").get_nsecs() == 37*Day); fail_unless(Period("P3Y17MT").get_nsecs() == 3*Year + 17*Month); fail_unless(Period("P5Y66DT").get_nsecs() == 5*Year + 66*Day); fail_unless(Period("P37M44DT").get_nsecs() == 37*Month + 44*Day); // Hour-min-sec fail_unless(Period("PT3H").get_nsecs() == 3*Hour); fail_unless(Period("PT5M").get_nsecs() == 5*Min); fail_unless(Period("P37S").get_nsecs() == 37*Sec); // fail_unless(Period("PT3.578777S").get_nsecs() == 3*Sec + 578*MSec + 777*USec); fail_unless(Period("PT0.5S").get_nsecs() == 500*MSec); // fail_unless(Period("PT5H7M3.578777S").get_nsecs() == 5*Hour + 7*Min + 3*Sec + 578*MSec + 777*USec); // @todo these should fail fail_unless(Period("PT.S").get_nsecs() == 0); fail_unless(Period("PT.D").get_nsecs() == 0); } END_TEST START_TEST(test_date) { Date d1(Date::now()); Date d2 = d1 + Period("PT6S"); fail_unless(d2.get_utc() == d1.get_utc() + 6*Sec); fail_unless(d2 - Period("PT6S") == d1); Date max(Date::max()); fail_unless(d1 < max); } END_TEST START_TEST(test_trac_712) { try { Period p; p = gu::from_string("0x3"); // used to throw gu::Exception } catch (gu::NotFound& nf) { } } END_TEST Suite* gu_datetime_suite() { Suite* s = suite_create("gu::datetime"); TCase* tc; tc = tcase_create("test_units"); tcase_add_test(tc, test_units); suite_add_tcase(s, tc); tc = tcase_create("test_period"); tcase_add_test(tc, test_period); suite_add_tcase(s, tc); tc = tcase_create("test_date"); tcase_add_test(tc, test_date); suite_add_tcase(s, tc); tc = tcase_create("test_trac_712"); tcase_add_test(tc, test_trac_712); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_datetime_test.hpp000066400000000000000000000003411244131713600245150ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #ifndef __gu_datetime_test_hpp__ #define __gu_datetime_test_hpp__ #include Suite* gu_datetime_suite(); #endif // __gu_datetime_test_hpp__ percona-galera-3-3.8-3390/galerautils/tests/gu_dbug_test.c000066400000000000000000000031501244131713600232760ustar00rootroot00000000000000// Copyright (C) 2008 Codership Oy // $Id$ /* Pthread yield */ #define _GNU_SOURCE 1 #include #include #include #include #include "gu_dbug_test.h" #include "../src/gu_dbug.h" static void cf() { GU_DBUG_ENTER("cf"); GU_DBUG_PRINT("galera", ("hello from cf")); sched_yield(); GU_DBUG_VOID_RETURN; } static void bf() { GU_DBUG_ENTER("bf"); GU_DBUG_PRINT("galera", ("hello from bf")); sched_yield(); cf(); GU_DBUG_VOID_RETURN; } static void af() { GU_DBUG_ENTER("af"); GU_DBUG_PRINT("galera", ("hello from af")); sched_yield(); bf(); GU_DBUG_VOID_RETURN; } static time_t stop = 0; static void *dbg_thr(void *arg) { while (time(NULL) < stop) { af(); } pthread_exit(NULL); } START_TEST(gu_dbug_test) { int i; #define N_THREADS 10 pthread_t th[N_THREADS]; /* Log > /dev/null */ GU_DBUG_FILE = fopen("/dev/null", "a+"); /* These should not produce output yet */ af(); af(); af(); /* Start logging */ GU_DBUG_PUSH("d:t:i"); GU_DBUG_PRINT("galera", ("Start logging")); af(); af(); af(); /* Run few threads concurrently */ stop = time(NULL) + 2; for (i = 0; i < N_THREADS; i++) pthread_create(&th[i], NULL, &dbg_thr, NULL); for (i = 0; i < N_THREADS; i++) pthread_join(th[i], NULL); } END_TEST Suite *gu_dbug_suite(void) { Suite *s = suite_create("Galera dbug functions"); TCase *tc = tcase_create("gu_dbug"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_dbug_test); tcase_set_timeout(tc, 60); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_dbug_test.h000066400000000000000000000002601244131713600233020ustar00rootroot00000000000000// Copyright (C) 2008 Codership Oy // $Id$ #ifndef __gu_dbug_test__ #define __gu_dbug_test__ Suite *gu_dbug_suite(void); #endif /* __gu_dbug_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_digest_test.cpp000066400000000000000000000217101244131713600241760ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /* * This unit test is mostly to check that Galera hash definitions didn't change: * correctness of hash algorithms definitions is checked in respective unit * tests. * * By convention checks are made against etalon byte arrays, so integers must be * converted to little-endian. * * $Id$ */ #include "../src/gu_digest.hpp" #include "gu_digest_test.hpp" #include "../src/gu_hexdump.hpp" #include "../src/gu_logger.hpp" /* checks equivalence of two buffers, returns true if check fails and logs * buffer contents. */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { log_info << "expected hash value:\n" << gu::Hexdump(exp, size) << "\nfound:\n" << gu::Hexdump(got, size) << "\n"; return true; } return false; } static const char test_msg[2048] = { 0, }; #define GU_HASH_TEST_LENGTH 43 /* some random prime */ static const uint8_t gu_hash128_check[16] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84,0x73,0x41,0x3F,0xA5,0xEB,0x27,0x40,0x2F }; static const uint8_t gu_hash64_check[8] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84 }; static const uint8_t gu_hash32_check[4] = { 0xFA,0x2C,0x78,0x67 }; /* Tests partial hashing functions */ START_TEST (gu_hash_test) { gu::Hash hash_one; hash_one.append(test_msg, GU_HASH_TEST_LENGTH); uint8_t res128_one[16]; hash_one.gather(res128_one); fail_if (check (gu_hash128_check, res128_one, sizeof(res128_one)), "gu::Hash::gather() failed in single mode."); gu::Hash::digest(test_msg, GU_HASH_TEST_LENGTH, res128_one); fail_if (check (gu_hash128_check, res128_one, sizeof(res128_one)), "gu::Hash::digest() failed."); gu::Hash hash_multi; int off = 0; hash_multi.append(test_msg, 16); off += 16; hash_multi.append(test_msg + off, 15); off += 15; hash_multi.append(test_msg + off, 7); off += 7; hash_multi.append(test_msg + off, 5); off += 5; fail_if (off != GU_HASH_TEST_LENGTH); uint8_t res128_multi[16]; hash_multi.gather(res128_multi); fail_if (check (gu_hash128_check, res128_multi, sizeof(res128_multi)), "gu::Hash::gather() failed in multi mode."); uint64_t res64; hash_multi.gather(&res64); uint64_t const res(gu_hash64(test_msg, GU_HASH_TEST_LENGTH)); fail_if (res != res64, "got 0x%0llx, expected 0x%llx", res64, res); res64 = gu_le64(res64); fail_if (check (gu_hash64_check, &res64, sizeof(res64)), "gu::Hash::gather() failed."); uint32_t res32; hash_one(res32); fail_if (gu_hash32(test_msg, GU_HASH_TEST_LENGTH) != res32); res32 = gu_le32(res32); fail_if (check (gu_hash32_check, &res32, sizeof(res32)), "gu::Hash::gather() failed."); } END_TEST static const uint8_t fast_hash128_check0 [16] = { 0xA9,0xCE,0x5A,0x56,0x0C,0x0B,0xF7,0xD6,0x63,0x4F,0x6F,0x81,0x0E,0x0B,0xF2,0x0A }; static const uint8_t fast_hash128_check511 [16] = { 0xC6,0x7F,0x4C,0xE7,0x6F,0xE0,0xDA,0x14,0xCC,0x9F,0x21,0x76,0xAF,0xB5,0x12,0x1A }; static const uint8_t fast_hash128_check512 [16] = { 0x38,0x8D,0x2B,0x90,0xC8,0x7F,0x11,0x53,0x3F,0xB4,0x32,0xC1,0xD7,0x2B,0x04,0x39 }; static const uint8_t fast_hash128_check2011[16] = { 0xB7,0xCE,0x75,0xC7,0xB4,0x31,0xBC,0xC8,0x95,0xB3,0x41,0xB8,0x5B,0x8E,0x77,0xF9 }; static const uint8_t fast_hash64_check0 [8] = { 0x6C, 0x55, 0xB8, 0xA1, 0x02, 0xC6, 0x21, 0xCA }; static const uint8_t fast_hash64_check15 [8] = { 0x28, 0x49, 0xE8, 0x34, 0x7A, 0xAB, 0x49, 0x34 }; static const uint8_t fast_hash64_check16 [8] = { 0x44, 0x40, 0x2C, 0x82, 0xD3, 0x8D, 0xAA, 0xFE }; static const uint8_t fast_hash64_check511 [8] = { 0xC6, 0x7F, 0x4C, 0xE7, 0x6F, 0xE0, 0xDA, 0x14 }; static const uint8_t fast_hash64_check512 [8] = { 0x38, 0x8D, 0x2B, 0x90, 0xC8, 0x7F, 0x11, 0x53 }; static const uint8_t fast_hash64_check2011[8] = { 0xB7, 0xCE, 0x75, 0xC7, 0xB4, 0x31, 0xBC, 0xC8 }; static const uint8_t fast_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t fast_hash32_check31 [4] = { 0x1E, 0xFF, 0x48, 0x38 }; static const uint8_t fast_hash32_check32 [4] = { 0x63, 0xC2, 0x53, 0x0D }; static const uint8_t fast_hash32_check511 [4] = { 0xC6, 0x7F, 0x4C, 0xE7 }; static const uint8_t fast_hash32_check512 [4] = { 0x38, 0x8D, 0x2B, 0x90 }; static const uint8_t fast_hash32_check2011[4] = { 0xB7, 0xCE, 0x75, 0xC7 }; /* Tests fast hash functions */ START_TEST (gu_fast_hash_test) { uint8_t res128[16]; gu::FastHash::digest (test_msg, 0, res128); fail_if (check (fast_hash128_check0, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 511, res128); fail_if (check (fast_hash128_check511, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 512, res128); fail_if (check (fast_hash128_check512, res128, sizeof(res128))); gu::FastHash::digest (test_msg, 2011, res128); fail_if (check (fast_hash128_check2011, res128, sizeof(res128))); uint64_t res64; res64 = gu::FastHash::digest(test_msg, 0); res64 = gu_le64(res64); fail_if (check (fast_hash64_check0, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,15); res64 = gu_le64(res64); fail_if (check (fast_hash64_check15, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,16); res64 = gu_le64(res64); fail_if (check (fast_hash64_check16, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,511); res64 =gu_le64(res64); fail_if (check (fast_hash64_check511, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,512); res64 =gu_le64(res64); fail_if (check (fast_hash64_check512, &res64, sizeof(res64))); res64 = gu::FastHash::digest(test_msg,2011);res64 =gu_le64(res64); fail_if (check (fast_hash64_check2011, &res64, sizeof(res64))); uint32_t res32; res32 = gu::FastHash::digest(test_msg, 0); res32 = gu_le32(res32); fail_if (check (fast_hash32_check0, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,31); res32 = gu_le32(res32); fail_if (check (fast_hash32_check31, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,32); res32 = gu_le32(res32); fail_if (check (fast_hash32_check32, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,511); res32 =gu_le32(res32); fail_if (check (fast_hash32_check511, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,512); res32 =gu_le32(res32); fail_if (check (fast_hash32_check512, &res32, sizeof(res32))); res32 = gu::FastHash::digest(test_msg,2011); res32=gu_le32(res32); fail_if (check (fast_hash32_check2011, &res32, sizeof(res32))); } END_TEST #if SKIP_TABLE_FUNCTIONS /* Tests table hash functions: * - for 64-bit platforms table hash should be identical to fast 64-bit hash, * - for 32-bit platforms table hash is different. */ #if GU_WORDSIZE == 64 START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 8); res = gu_table_hash (test_msg, 0); res = gu_le64(res); fail_if (check (fast_hash64_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 15); res = gu_le64(res); fail_if (check (fast_hash64_check15, &res, sizeof(res))); res = gu_table_hash (test_msg, 16); res = gu_le64(res); fail_if (check (fast_hash64_check16, &res, sizeof(res))); res = gu_table_hash (test_msg, 511); res = gu_le64(res); fail_if (check (fast_hash64_check511, &res, sizeof(res))); res = gu_table_hash (test_msg, 512); res = gu_le64(res); fail_if (check (fast_hash64_check512, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le64(res); fail_if (check (fast_hash64_check2011, &res, sizeof(res))); } END_TEST #elif GU_WORDSIZE == 32 static const uint8_t table_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t table_hash32_check32 [4] = { 0x65, 0x16, 0x17, 0x42 }; static const uint8_t table_hash32_check2011[4] = { 0xF9, 0xBC, 0xEF, 0x7A }; START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 4); res = gu_table_hash (test_msg, 0); res = gu_le32(res); fail_if (check (table_hash32_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 32); res = gu_le32(res); fail_if (check (table_hash32_check32, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le32(res); fail_if (check (table_hash32_check2011, &res, sizeof(res))); } END_TEST #else /* GU_WORDSIZE == 32 */ # error "Unsupported word size" #endif #endif // SKIP_TABLE_FUNCTIONS Suite *gu_digest_suite(void) { Suite *s = suite_create("gu::Hash"); TCase *tc = tcase_create("gu_hash"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_hash_test); tcase_add_test (tc, gu_fast_hash_test); // tcase_add_test (tc, gu_table_hash_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_digest_test.hpp000066400000000000000000000003231244131713600242000ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_digest_test__ #define __gu_digest_test__ #include extern Suite *gu_digest_suite(void); #endif /* __gu_digest_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_fifo_test.c000066400000000000000000000127161244131713600233100ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #include #include "gu_fifo_test.h" #include "../src/galerautils.h" #define FIFO_LENGTH 10000L START_TEST (gu_fifo_test) { gu_fifo_t* fifo; long i; size_t* item; long used; fifo = gu_fifo_create (0, 1); fail_if (fifo != NULL); fifo = gu_fifo_create (1, 0); fail_if (fifo != NULL); fifo = gu_fifo_create (1, 1); fail_if (fifo == NULL); gu_fifo_close (fifo); mark_point(); gu_fifo_destroy (fifo); mark_point(); fifo = gu_fifo_create (FIFO_LENGTH, sizeof(i)); fail_if (fifo == NULL); fail_if (gu_fifo_length(fifo) != 0, "fifo->used is %lu for an empty FIFO", gu_fifo_length(fifo)); // fill FIFO for (i = 0; i < FIFO_LENGTH; i++) { item = gu_fifo_get_tail (fifo); fail_if (item == NULL, "could not get item %ld", i); *item = i; gu_fifo_push_tail (fifo); } used = i; fail_if (gu_fifo_length(fifo) != used, "used is %zu, expected %zu", used, gu_fifo_length(fifo)); // test pop for (i = 0; i < used; i++) { int err; item = gu_fifo_get_head (fifo, &err); fail_if (item == NULL, "could not get item %ld", i); fail_if (*item != (ulong)i, "got %ld, expected %ld", *item, i); gu_fifo_pop_head (fifo); } fail_if (gu_fifo_length(fifo) != 0, "gu_fifo_length() for empty queue is %ld", gu_fifo_length(fifo)); gu_fifo_close (fifo); int err; item = gu_fifo_get_head (fifo, &err); fail_if (item != NULL); fail_if (err != -ENODATA); gu_fifo_destroy (fifo); } END_TEST static pthread_mutex_t sync_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t sync_cond = PTHREAD_COND_INITIALIZER; #define ITEM 12345 static void* cancel_thread (void* arg) { gu_fifo_t* q = arg; /* sync with parent */ pthread_mutex_lock (&sync_mtx); pthread_cond_signal (&sync_cond); pthread_mutex_unlock (&sync_mtx); size_t* item; int err; /* try to get from non-empty queue */ item = gu_fifo_get_head (q, &err); fail_if (NULL != item, "Got item %p: %zu", item, item ? *item : 0); fail_if (-ECANCELED != err); /* signal end of the first gu_fifo_get_head() */ pthread_mutex_lock (&sync_mtx); pthread_cond_signal (&sync_cond); /* wait until gets are resumed */ pthread_cond_wait (&sync_cond, &sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL == item); fail_if (ITEM != *item); gu_fifo_pop_head (q); /* signal end of the 2nd gu_fifo_get_head() */ pthread_cond_signal (&sync_cond); pthread_mutex_unlock (&sync_mtx); /* try to get from empty queue (should block) */ item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ECANCELED != err); /* signal end of the 3rd gu_fifo_get_head() */ pthread_mutex_lock (&sync_mtx); pthread_cond_signal (&sync_cond); /* wait until fifo is closed */ pthread_cond_wait (&sync_cond, &sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ECANCELED != err); /* signal end of the 4th gu_fifo_get_head() */ pthread_cond_signal (&sync_cond); /* wait until fifo is resumed */ pthread_cond_wait (&sync_cond, &sync_mtx); pthread_mutex_unlock (&sync_mtx); item = gu_fifo_get_head (q, &err); fail_if (NULL != item); fail_if (-ENODATA != err); return NULL; } START_TEST(gu_fifo_cancel_test) { gu_fifo_t* q = gu_fifo_create (FIFO_LENGTH, sizeof(size_t)); size_t* item = gu_fifo_get_tail (q); fail_if (item == NULL); *item = ITEM; gu_fifo_push_tail (q); pthread_mutex_lock (&sync_mtx); pthread_t thread; pthread_create (&thread, NULL, cancel_thread, q); /* sync with child thread */ gu_fifo_lock (q); pthread_cond_wait (&sync_cond, &sync_mtx); int err; err = gu_fifo_cancel_gets (q); fail_if (0 != err); err = gu_fifo_cancel_gets (q); fail_if (-EBADFD != err); /* allow the first gu_fifo_get_head() */ gu_fifo_release (q); mark_point(); /* wait for the first gu_fifo_get_head() to complete */ pthread_cond_wait (&sync_cond, &sync_mtx); err = gu_fifo_resume_gets (q); fail_if (0 != err); err = gu_fifo_resume_gets (q); fail_if (-EBADFD != err); /* signal that now gets are resumed */ pthread_cond_signal (&sync_cond); /* wait for the 2nd gu_fifo_get_head() to complete */ pthread_cond_wait (&sync_cond, &sync_mtx); /* wait a bit to make sure 3rd gu_fifo_get_head() is blocked * (even if it is not - still should work)*/ usleep (100000 /* 0.1s */); err = gu_fifo_cancel_gets (q); fail_if (0 != err); /* wait for the 3rd gu_fifo_get_head() to complete */ pthread_cond_wait (&sync_cond, &sync_mtx); gu_fifo_close (q); // closes for puts, but the q still must be canceled pthread_cond_signal (&sync_cond); /* wait for the 4th gu_fifo_get_head() to complete */ pthread_cond_wait (&sync_cond, &sync_mtx); gu_fifo_resume_gets (q); // resumes gets pthread_cond_signal (&sync_cond); pthread_mutex_unlock (&sync_mtx); mark_point(); pthread_join(thread, NULL); } END_TEST Suite *gu_fifo_suite(void) { Suite *s = suite_create("Galera FIFO functions"); TCase *tc = tcase_create("gu_fifo"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_fifo_test); tcase_add_test (tc, gu_fifo_cancel_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_fifo_test.h000066400000000000000000000002601244131713600233040ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_fifo_test__ #define __gu_fifo_test__ Suite *gu_fifo_suite(void); #endif /* __gu_fifo_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_fnv_test.c000066400000000000000000000033461244131713600231550ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #include "gu_fnv_test.h" #include static const char* const test_buf = "chongo /\\../\\"; // enable normal FNV mode for reference hash checking #define GU_FNV_NORMAL #include "../src/gu_fnv.h" START_TEST (gu_fnv32_test) { uint32_t ret = 0; gu_fnv32a_internal (test_buf, strlen(test_buf), &ret); fail_if (GU_FNV32_SEED != ret, "FNV32 failed: expected %"PRIu32", got %"PRIu32, GU_FNV32_SEED, ret); } END_TEST START_TEST (gu_fnv64_test) { uint64_t ret = 0; gu_fnv64a_internal (test_buf, strlen(test_buf), &ret); fail_if (GU_FNV64_SEED != ret, "FNV64 failed: expected %"PRIu64", got %"PRIu64, GU_FNV64_SEED, ret); } END_TEST START_TEST (gu_fnv128_test) { gu_uint128_t GU_SET128(ret, 0, 0); gu_fnv128a_internal (test_buf, strlen(test_buf), &ret); #if defined(__SIZEOF_INT128__) fail_if (!GU_EQ128(GU_FNV128_SEED, ret), "FNV128 failed: expected %"PRIx64" %"PRIx64", got %"PRIx64" %"PRIx64, (uint64_t)(GU_FNV128_SEED >> 64), (uint64_t)GU_FNV128_SEED, (uint64_t)(ret >> 64), (uint64_t)ret); #else fail_if (!GU_EQ128(GU_FNV128_SEED, ret), "FNV128 failed: expected %"PRIx64" %"PRIx64", got %"PRIx64" %"PRIx64, GU_FNV128_SEED.u64[GU_64HI], GU_FNV128_SEED.u64[GU_64LO], ret.u64[GU_64HI], ret.u64[GU_64LO]); #endif } END_TEST Suite *gu_fnv_suite(void) { Suite *s = suite_create("FNV hash"); TCase *tc_fnv = tcase_create("gu_fnv"); suite_add_tcase (s, tc_fnv); tcase_add_test(tc_fnv, gu_fnv32_test); tcase_add_test(tc_fnv, gu_fnv64_test); tcase_add_test(tc_fnv, gu_fnv128_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_fnv_test.h000066400000000000000000000003071244131713600231540ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_fnv_test__ #define __gu_fnv_test__ #include extern Suite *gu_fnv_suite(void); #endif /* __gu_fnv_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_hash_test.c000066400000000000000000000177111244131713600233100ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /* * This unit test is mostly to check that Galera hash definitions didn't change: * correctness of hash algorithms definitions is checked in respective unit * tests. * * By convention checks are made against etalon byte arrays, so integers must be * converted to little-endian. * * $Id$ */ #include "gu_hash_test.h" #include "../src/gu_hash.h" #include "../src/gu_log.h" #include "../src/gu_hexdump.h" /* checks equivalence of two buffers, returns true if check fails and logs * buffer contents. */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { ssize_t str_size = size * 2.2 + 1; char c[str_size], r[str_size]; gu_hexdump (exp, size, c, sizeof(c), false); gu_hexdump (got, size, r, sizeof(r), false); gu_info ("expected hash value:\n%s\nfound:\n%s\n", c, r); return true; } return false; } static const char test_msg[2048] = { 0, }; #define GU_HASH_TEST_LENGTH 43 /* some random prime */ static const uint8_t gu_hash128_check[16] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84,0x73,0x41,0x3F,0xA5,0xEB,0x27,0x40,0x2F }; static const uint8_t gu_hash64_check[8] = { 0xFA,0x2C,0x78,0x67,0x35,0x99,0xD9,0x84 }; static const uint8_t gu_hash32_check[4] = { 0xFA,0x2C,0x78,0x67 }; /* Tests partial hashing functions */ START_TEST (gu_hash_test) { gu_hash_t h; gu_hash_init(&h); gu_hash_append(&h, test_msg, GU_HASH_TEST_LENGTH); uint8_t res128[16]; gu_hash_get128 (&h, res128); fail_if (check (gu_hash128_check, res128, sizeof(res128)), "gu_hash_get128() failed."); uint64_t res64 = gu_hash_get64(&h); fail_if (gu_hash64(test_msg, GU_HASH_TEST_LENGTH) != res64); res64 = gu_le64(res64); fail_if (check (gu_hash64_check, &res64, sizeof(res64)), "gu_hash_get64() failed."); uint32_t res32 = gu_hash_get32(&h); fail_if (gu_hash32(test_msg, GU_HASH_TEST_LENGTH) != res32); res32 = gu_le32(res32); fail_if (check (gu_hash32_check, &res32, sizeof(res32)), "gu_hash_get32() failed."); } END_TEST static const uint8_t fast_hash128_check0 [16] = { 0xA9,0xCE,0x5A,0x56,0x0C,0x0B,0xF7,0xD6,0x63,0x4F,0x6F,0x81,0x0E,0x0B,0xF2,0x0A }; static const uint8_t fast_hash128_check511 [16] = { 0xC6,0x7F,0x4C,0xE7,0x6F,0xE0,0xDA,0x14,0xCC,0x9F,0x21,0x76,0xAF,0xB5,0x12,0x1A }; static const uint8_t fast_hash128_check512 [16] = { 0x38,0x8D,0x2B,0x90,0xC8,0x7F,0x11,0x53,0x3F,0xB4,0x32,0xC1,0xD7,0x2B,0x04,0x39 }; static const uint8_t fast_hash128_check2011[16] = { 0xB7,0xCE,0x75,0xC7,0xB4,0x31,0xBC,0xC8,0x95,0xB3,0x41,0xB8,0x5B,0x8E,0x77,0xF9 }; static const uint8_t fast_hash64_check0 [8] = { 0x6C, 0x55, 0xB8, 0xA1, 0x02, 0xC6, 0x21, 0xCA }; static const uint8_t fast_hash64_check15 [8] = { 0x28, 0x49, 0xE8, 0x34, 0x7A, 0xAB, 0x49, 0x34 }; static const uint8_t fast_hash64_check16 [8] = { 0x44, 0x40, 0x2C, 0x82, 0xD3, 0x8D, 0xAA, 0xFE }; static const uint8_t fast_hash64_check511 [8] = { 0xC6, 0x7F, 0x4C, 0xE7, 0x6F, 0xE0, 0xDA, 0x14 }; static const uint8_t fast_hash64_check512 [8] = { 0x38, 0x8D, 0x2B, 0x90, 0xC8, 0x7F, 0x11, 0x53 }; static const uint8_t fast_hash64_check2011[8] = { 0xB7, 0xCE, 0x75, 0xC7, 0xB4, 0x31, 0xBC, 0xC8 }; static const uint8_t fast_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t fast_hash32_check31 [4] = { 0x1E, 0xFF, 0x48, 0x38 }; static const uint8_t fast_hash32_check32 [4] = { 0x63, 0xC2, 0x53, 0x0D }; static const uint8_t fast_hash32_check511 [4] = { 0xC6, 0x7F, 0x4C, 0xE7 }; static const uint8_t fast_hash32_check512 [4] = { 0x38, 0x8D, 0x2B, 0x90 }; static const uint8_t fast_hash32_check2011[4] = { 0xB7, 0xCE, 0x75, 0xC7 }; /* Tests fast hash functions */ START_TEST (gu_fast_hash_test) { uint8_t res128[16]; gu_fast_hash128 (test_msg, 0, res128); fail_if (check (fast_hash128_check0, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 511, res128); fail_if (check (fast_hash128_check511, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 512, res128); fail_if (check (fast_hash128_check512, res128, sizeof(res128))); gu_fast_hash128 (test_msg, 2011, res128); fail_if (check (fast_hash128_check2011, res128, sizeof(res128))); uint64_t res64; res64 = gu_fast_hash64 (test_msg, 0); res64 = gu_le64(res64); fail_if (check (fast_hash64_check0, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 15); res64 = gu_le64(res64); fail_if (check (fast_hash64_check15, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 16); res64 = gu_le64(res64); fail_if (check (fast_hash64_check16, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 511); res64 = gu_le64(res64); fail_if (check (fast_hash64_check511, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 512); res64 = gu_le64(res64); fail_if (check (fast_hash64_check512, &res64, sizeof(res64))); res64 = gu_fast_hash64 (test_msg, 2011); res64 = gu_le64(res64); fail_if (check (fast_hash64_check2011, &res64, sizeof(res64))); uint32_t res32; res32 = gu_fast_hash32 (test_msg, 0); res32 = gu_le32(res32); fail_if (check (fast_hash32_check0, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 31); res32 = gu_le32(res32); fail_if (check (fast_hash32_check31, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 32); res32 = gu_le32(res32); fail_if (check (fast_hash32_check32, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 511); res32 = gu_le32(res32); fail_if (check (fast_hash32_check511, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 512); res32 = gu_le32(res32); fail_if (check (fast_hash32_check512, &res32, sizeof(res32))); res32 = gu_fast_hash32 (test_msg, 2011); res32 = gu_le32(res32); fail_if (check (fast_hash32_check2011, &res32, sizeof(res32))); } END_TEST /* Tests table hash functions: * - for 64-bit platforms table hash should be identical to fast 64-bit hash, * - for 32-bit platforms table hash is different. */ #if GU_WORDSIZE == 64 START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 8); res = gu_table_hash (test_msg, 0); res = gu_le64(res); fail_if (check (fast_hash64_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 15); res = gu_le64(res); fail_if (check (fast_hash64_check15, &res, sizeof(res))); res = gu_table_hash (test_msg, 16); res = gu_le64(res); fail_if (check (fast_hash64_check16, &res, sizeof(res))); res = gu_table_hash (test_msg, 511); res = gu_le64(res); fail_if (check (fast_hash64_check511, &res, sizeof(res))); res = gu_table_hash (test_msg, 512); res = gu_le64(res); fail_if (check (fast_hash64_check512, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le64(res); fail_if (check (fast_hash64_check2011, &res, sizeof(res))); } END_TEST #elif GU_WORDSIZE == 32 static const uint8_t table_hash32_check0 [4] = { 0x0B, 0x7C, 0x3E, 0xAB }; static const uint8_t table_hash32_check32 [4] = { 0x65, 0x16, 0x17, 0x42 }; static const uint8_t table_hash32_check2011[4] = { 0xF9, 0xBC, 0xEF, 0x7A }; START_TEST (gu_table_hash_test) { size_t res; fail_if (sizeof(res) > 4); res = gu_table_hash (test_msg, 0); res = gu_le32(res); fail_if (check (table_hash32_check0, &res, sizeof(res))); res = gu_table_hash (test_msg, 32); res = gu_le32(res); fail_if (check (table_hash32_check32, &res, sizeof(res))); res = gu_table_hash (test_msg, 2011); res = gu_le32(res); fail_if (check (table_hash32_check2011, &res, sizeof(res))); } END_TEST #else /* GU_WORDSIZE == 32 */ # error "Unsupported word size" #endif Suite *gu_hash_suite(void) { Suite *s = suite_create("Galera hash"); TCase *tc = tcase_create("gu_hash"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_hash_test); tcase_add_test (tc, gu_fast_hash_test); tcase_add_test (tc, gu_table_hash_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_hash_test.h000066400000000000000000000003131244131713600233030ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_hash_test__ #define __gu_hash_test__ #include extern Suite *gu_hash_suite(void); #endif /* __gu_hash_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_histogram_test.cpp000066400000000000000000000013411244131713600247120ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_histogram.hpp" #include "../src/gu_logger.hpp" #include #include "gu_histogram_test.hpp" using namespace gu; START_TEST(test_histogram) { Histogram hs("0.0,0.0005,0.001,0.002,0.005,0.01,0.02,0.05,0.1,0.5,1.,5."); hs.insert(0.001); log_info << hs; for (size_t i = 0; i < 1000; ++i) { hs.insert(double(::rand())/RAND_MAX); } log_info << hs; hs.clear(); log_info << hs; } END_TEST Suite* gu_histogram_suite() { TCase* t = tcase_create ("test_histogram"); tcase_add_test (t, test_histogram); Suite* s = suite_create ("gu::Histogram"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_histogram_test.hpp000066400000000000000000000003321244131713600247160ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef __gu_histogram_test__ #define __gu_histogram_test__ #include extern Suite *gu_histogram_suite(void); #endif // __gu_histogram_test__ percona-galera-3-3.8-3390/galerautils/tests/gu_lock_step_test.c000066400000000000000000000070341244131713600243450ustar00rootroot00000000000000/* * Copyright (C) 2008-2010 Codership Oy * * $Id$ */ #include #include // usleep() #include // strerror() #include "../src/gu_log.h" #include "../src/gu_lock_step.h" #include "gu_lock_step_test.h" #define TEST_USLEEP 1000 // 1ms #define WAIT_FOR(cond) \ { int count = 1000; while (--count && !(cond)) { usleep (TEST_USLEEP); }} gu_lock_step_t LS; static void* lock_step_thread (void* arg) { gu_lock_step_wait (&LS); return NULL; } START_TEST (gu_lock_step_test) { const long timeout = 500; // 500 ms long ret; gu_thread_t thr1, thr2; gu_lock_step_init (&LS); fail_if (LS.wait != 0); fail_if (LS.enabled != false); // first try with lock-stepping disabled ret = gu_thread_create (&thr1, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(0 == LS.wait); // 10ms fail_if (LS.wait != 0); // by default lock-step is disabled ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (-1 != ret); // enable lock-step gu_lock_step_enable (&LS, true); fail_if (LS.enabled != true); ret = gu_lock_step_cont (&LS, timeout); fail_if (0 != ret); // nobody's waiting ret = gu_thread_create (&thr1, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(1 == LS.wait); // 10ms fail_if (LS.wait != 1); ret = gu_thread_create (&thr2, NULL, lock_step_thread, NULL); fail_if (ret != 0); WAIT_FOR(2 == LS.wait); // 10ms fail_if (LS.wait != 2); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 2); // there were 2 waiters fail_if (LS.wait != 1); // 1 waiter remains ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 1); fail_if (LS.wait != 0); // 0 waiters remain ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_thread_join (thr2, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 0); // there were 0 waiters fail_if (LS.wait != 0, "Expected LS.wait to be 0, found: %ld", LS.wait); gu_lock_step_destroy (&LS); } END_TEST #define RACE_ITERATIONS 1000 static void* lock_step_race (void* arg) { long i; for (i = 0; i < RACE_ITERATIONS; i++) gu_lock_step_wait (&LS); return NULL; } START_TEST (gu_lock_step_race) { const long timeout = 500; // 500 ms long ret, i; gu_thread_t thr1; gu_lock_step_init (&LS); gu_lock_step_enable (&LS, true); fail_if (LS.enabled != true); ret = gu_thread_create (&thr1, NULL, lock_step_race, NULL); fail_if (ret != 0); for (i = 0; i < RACE_ITERATIONS; i++) { ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 1, "No waiter at iteration: %ld", i); } fail_if (LS.wait != 0); // 0 waiters remain ret = gu_thread_join (thr1, NULL); fail_if (ret != 0, "gu_thread_join() failed: %ld (%s)", ret, strerror(ret)); ret = gu_lock_step_cont (&LS, timeout); fail_if (ret != 0); } END_TEST Suite *gu_lock_step_suite(void) { Suite *suite = suite_create("Galera LOCK_STEP utils"); TCase *tcase = tcase_create("gu_lock_step"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gu_lock_step_test); tcase_add_test (tcase, gu_lock_step_race); return suite; } percona-galera-3-3.8-3390/galerautils/tests/gu_lock_step_test.h000066400000000000000000000003241244131713600243450ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gu_lock_step_test__ #define __gu_lock_step_test__ extern Suite *gu_lock_step_suite(void); #endif /* __gu_lock_step_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_mem_pool_test.cpp000066400000000000000000000023011244131713600245210ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy // $Id$ #define TEST_SIZE 1024 #include "gu_mem_pool.hpp" #include "gu_mem_pool_test.hpp" START_TEST (unsafe) { gu::MemPoolUnsafe mp(10, 1, "unsafe"); void* const buf0(mp.acquire()); fail_if(NULL == buf0); void* const buf1(mp.acquire()); fail_if(NULL == buf1); fail_if(buf0 == buf1); mp.recycle(buf0); void* const buf2(mp.acquire()); fail_if(NULL == buf2); fail_if(buf0 != buf2); log_info << mp; mp.recycle(buf1); mp.recycle(buf2); } END_TEST START_TEST (safe) { gu::MemPoolSafe mp(10, 1, "safe"); void* const buf0(mp.acquire()); fail_if(NULL == buf0); void* const buf1(mp.acquire()); fail_if(NULL == buf1); fail_if(buf0 == buf1); mp.recycle(buf0); void* const buf2(mp.acquire()); fail_if(NULL == buf2); fail_if(buf0 != buf2); log_info << mp; mp.recycle(buf1); mp.recycle(buf2); } END_TEST Suite *gu_mem_pool_suite(void) { Suite *s = suite_create("gu::MemPool"); TCase *tc_mem = tcase_create("gu_mem_pool"); suite_add_tcase (s, tc_mem); tcase_add_test(tc_mem, unsafe); tcase_add_test(tc_mem, safe); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_mem_pool_test.hpp000066400000000000000000000003331244131713600245310ustar00rootroot00000000000000// Copyright (C) 2013 Codership Oy // $Id$ #ifndef __gu_mem_pool_test__ #define __gu_mem_pool_test__ #include extern Suite *gu_mem_pool_suite(void); #endif /* __gu_mem_pool_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_mem_test.c000066400000000000000000000035151244131713600231400ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #define DEBUG_MALLOC // turn on the debugging code #define TEST_SIZE 1024 #include #include #include #include #include "gu_mem_test.h" #include "../src/galerautils.h" START_TEST (gu_mem_test) { void* ptr1; void* ptr2; int res; int i; ptr1 = gu_malloc (0); fail_if (NULL != ptr1, "Zero memory allocated, non-NULL pointer returned"); mark_point(); ptr1 = gu_malloc (TEST_SIZE); fail_if (NULL == ptr1, "NULL pointer returned for allocation" " errno: %s", strerror (errno)); mark_point(); ptr2 = memset (ptr1, 0xab, TEST_SIZE); fail_if (ptr2 != ptr1, "Memset changed pointer"); ptr2 = NULL; mark_point(); ptr2 = gu_realloc (ptr2, TEST_SIZE); fail_if (NULL == ptr2, "NULL pointer returned for reallocation" " errno: %s", strerror (errno)); memcpy (ptr2, ptr1, TEST_SIZE); mark_point(); ptr1 = gu_realloc (ptr1, TEST_SIZE + TEST_SIZE); res = memcmp (ptr1, ptr2, TEST_SIZE); fail_if (res != 0, "Realloc changed the contents of the memory"); mark_point(); ptr1 = gu_realloc (ptr1, 0); fail_if (res != 0, "Realloc to 0 didn't return NULL"); mark_point(); ptr1 = gu_calloc (1, TEST_SIZE); fail_if (NULL == ptr1, "NULL pointer returned for allocation" " errno: %s", strerror (errno)); for (i = 0; i < TEST_SIZE; i++) { res = ((char*)ptr1)[i]; if (res != 0) break; } fail_if (res != 0, "Calloc didn't clear up the memory"); mark_point(); gu_free (ptr1); mark_point(); gu_free (ptr2); } END_TEST Suite *gu_mem_suite(void) { Suite *s = suite_create("Galera memory utils"); TCase *tc_mem = tcase_create("gu_mem"); suite_add_tcase (s, tc_mem); tcase_add_test(tc_mem, gu_mem_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_mem_test.h000066400000000000000000000002631244131713600231420ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_mem_test__ #define __gu_mem_test__ extern Suite *gu_mem_suite(void); #endif /* __gu_mem_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_mmh3_test.c000066400000000000000000000216701244131713600232300ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #include "gu_mmh3_test.h" #include "../src/gu_mmh3.h" #include "../src/gu_log.h" #include "../src/gu_hexdump.h" /* This is to verify all tails plus block + all tails. Max block is 16 bytes */ static const char test_input[] = "0123456789ABCDEF0123456789abcde"; typedef struct hash32 { uint8_t h[4]; } hash32_t; #define NUM_32_TESTS 8 /* 0 to 7 bytes */ static const hash32_t test_output32[NUM_32_TESTS] = { {{ 0x0b, 0x7c, 0x3e, 0xab }}, /* '' */ {{ 0xba, 0xeb, 0x75, 0x97 }}, /* '0' */ {{ 0x5d, 0x5c, 0x21, 0x60 }}, /* '01' */ {{ 0x4b, 0xff, 0x61, 0x41 }}, /* '012' */ {{ 0x35, 0x3b, 0x57, 0xca }}, /* '0123' */ {{ 0x09, 0xdd, 0x77, 0xf9 }}, /* '01234' */ {{ 0x1f, 0x3c, 0x29, 0x7b }}, /* '012345' */ {{ 0xe1, 0xbe, 0x2d, 0xce }} /* '0123456' */ }; typedef struct hash128 { uint8_t h[16]; } hash128_t; #define NUM_128_TESTS 32 /* 0 to 31 bytes */ static const hash128_t test_output128[NUM_128_TESTS] = { {{ 0xa9,0xce,0x5a,0x56,0x0c,0x0b,0xf7,0xd6,0x63,0x4f,0x6f,0x81,0x0e,0x0b,0xf2,0x0a }}, {{ 0x72,0xa1,0x46,0xa3,0x73,0x03,0x49,0x85,0x30,0xb9,0x52,0xaa,0x3b,0x00,0xad,0x23 }}, {{ 0x4f,0x32,0xa2,0x15,0x91,0x00,0xea,0xaa,0x59,0x90,0x48,0x30,0xe5,0x86,0x50,0xee }}, {{ 0x55,0xfe,0x86,0x3b,0x9c,0x67,0xc6,0xee,0x5c,0x06,0x34,0xd0,0xe5,0x15,0xfb,0xdd }}, {{ 0x3a,0x50,0x35,0xe5,0x72,0x75,0xa5,0x5e,0x46,0x3d,0x0e,0x23,0xbb,0x17,0x5a,0x66 }}, {{ 0x3b,0xff,0xb5,0x1a,0x93,0x0c,0x77,0x9a,0x40,0x5f,0x62,0x0c,0x40,0x15,0x0b,0x6e }}, {{ 0x7c,0xf8,0xf9,0xd2,0xfa,0x5a,0x8b,0x51,0x65,0x3c,0xa5,0x0e,0xa2,0xca,0x0a,0x87 }}, {{ 0x95,0x69,0x33,0x98,0xe4,0xb2,0x2a,0x21,0xd4,0x23,0x21,0x80,0xb1,0x00,0x46,0xbb }}, {{ 0x92,0xca,0xd3,0xbb,0x39,0x16,0x96,0xb5,0x3a,0x61,0x58,0x53,0xbb,0xf8,0xc4,0xb0 }}, {{ 0x36,0xf0,0xa3,0xc8,0xdc,0x5e,0x46,0x20,0x12,0xcf,0xad,0x3f,0xda,0xd5,0x95,0x7a }}, {{ 0xb9,0x71,0x76,0x54,0xd3,0x74,0x9b,0x31,0x93,0xb2,0xd9,0xbf,0xad,0x78,0x49,0x7e }}, {{ 0x39,0x75,0xc6,0x34,0x38,0x65,0x60,0x32,0xb1,0xa3,0x02,0xd2,0xba,0x47,0x0b,0xc3 }}, {{ 0x37,0xcd,0xe3,0x34,0x7d,0x2d,0xa4,0xdc,0xf3,0x51,0xd1,0x1e,0x46,0xb8,0x1a,0xd4 }}, {{ 0xa0,0xf6,0xff,0xc6,0xcd,0x50,0xdf,0xa2,0x59,0x36,0x8d,0xdf,0x09,0x57,0x14,0x7b }}, {{ 0xeb,0x58,0x42,0xca,0x56,0xb5,0x94,0x16,0x10,0x86,0x38,0x5b,0x2c,0x4a,0x13,0x84 }}, {{ 0x5d,0xee,0x3a,0x5b,0x45,0x5f,0x92,0x7d,0x42,0x91,0x8a,0x7b,0xb6,0xc7,0xde,0xd9 }}, {{ 0x63,0xff,0xe5,0x55,0x38,0x3d,0xd6,0x5d,0xa4,0xad,0xcb,0xf6,0x0a,0xc3,0xd9,0x12 }}, {{ 0x86,0x15,0xd3,0x5a,0x47,0x81,0x3f,0xea,0x6b,0xbc,0x3b,0x82,0xd0,0x49,0xda,0x5d }}, {{ 0xb7,0x41,0xc9,0xf5,0x94,0x3f,0x91,0xa5,0x56,0x68,0x9c,0x12,0xc7,0xa1,0xd9,0x45 }}, {{ 0xb7,0x7c,0x2f,0x60,0xe3,0x2b,0x6a,0xd6,0x5e,0x24,0x6c,0xaf,0x8c,0x83,0x99,0xc7 }}, {{ 0x62,0xdb,0xad,0xab,0xda,0x51,0x82,0x0b,0x04,0xe6,0x7a,0x88,0xaa,0xae,0xfd,0xce }}, {{ 0x70,0x89,0xd2,0x6a,0x35,0x80,0x19,0xa4,0x71,0x0e,0x5c,0x68,0x33,0xf5,0x0c,0x67 }}, {{ 0x05,0xb3,0x50,0x50,0xbe,0x8d,0xaa,0x6e,0x32,0x02,0x1b,0x5e,0xe6,0xb7,0x5f,0x72 }}, {{ 0x85,0x60,0x7c,0x7a,0xdf,0xaa,0x67,0xc6,0xed,0x3e,0x7e,0x13,0x84,0x2c,0xd4,0x28 }}, {{ 0x51,0x4a,0xe3,0x56,0xe0,0x5f,0x7d,0x42,0xfb,0x41,0xec,0xfe,0xff,0xa4,0x74,0x13 }}, {{ 0xb8,0xc0,0xc1,0x01,0xc2,0x74,0xbb,0x84,0xc8,0xca,0x16,0x9c,0x6b,0xf3,0x3e,0x4d }}, {{ 0xab,0xd0,0x4a,0xc5,0xa4,0xc8,0xce,0xf4,0xf2,0xf5,0x2f,0xdc,0x22,0x4f,0x20,0xda }}, {{ 0x36,0x25,0x28,0x74,0xf0,0x4c,0x36,0x38,0xd2,0x9a,0x64,0xf8,0x11,0xcf,0xaf,0x28 }}, {{ 0x8b,0x79,0x18,0x09,0x14,0x19,0x3c,0xa0,0x5b,0x62,0x4d,0x09,0x18,0xdd,0x6a,0x89 }}, {{ 0xc0,0xae,0x4f,0x67,0x45,0x01,0x00,0xb7,0x75,0xc5,0x1c,0x56,0xdf,0x55,0x7c,0x04 }}, {{ 0xcd,0x5a,0xda,0xea,0xbc,0xfb,0x8d,0xc7,0x8a,0xd3,0xc6,0x70,0x12,0x34,0x82,0x84 }}, {{ 0x69,0x53,0x0d,0xc3,0x4d,0xd4,0x33,0xe9,0x00,0x1b,0x27,0x06,0x27,0x7f,0x48,0xf7 }} }; typedef void (*hash_f_t) (const void* key, int len, uint32_t seed, void* out); /* Verification code from the original SMHasher test suite */ static void smhasher_verification (hash_f_t hash, size_t const hashbytes, uint32_t* const res) { ssize_t const n_tests = 256; uint8_t key[n_tests]; uint8_t hashes[hashbytes * n_tests]; uint8_t final[hashbytes]; /* Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as * the seed */ ssize_t i; for(i = 0; i < n_tests; i++) { key[i] = (uint8_t)i; hash (key, i, n_tests - i, &hashes[i * hashbytes]); } /* Then hash the result array */ hash (hashes, hashbytes * n_tests, 0, final); memcpy (res, final, sizeof(*res)); } static hash32_t smhasher_checks[3] = { {{ 0xE3, 0x7E, 0xF5, 0xB0 }}, /* mmh3_32 */ {{ 0x2A, 0xE6, 0xEC, 0xB3 }}, /* mmh3_x86_128 */ {{ 0x69, 0xBA, 0x84, 0x63 }} /* mmh3_x64_128 */ }; /* returns true if check fails */ static bool check (const void* const exp, const void* const got, ssize_t size) { if (memcmp (exp, got, size)) { ssize_t str_size = size * 2.2 + 1; char c[str_size], r[str_size]; gu_hexdump (exp, size, c, sizeof(c), false); gu_hexdump (got, size, r, sizeof(r), false); gu_info ("expected MurmurHash3:\n%s\nfound:\n%s\n", c, r); return true; } return false; } START_TEST (gu_mmh32_test) { int i; uint32_t out; smhasher_verification (gu_mmh3_32, sizeof(out), &out); fail_if (check (&smhasher_checks[0], &out, sizeof(out)), "gu_mmh3_32 failed."); for (i = 0; i < NUM_32_TESTS; i++) { uint32_t res = gu_mmh32 (test_input, i); res = gu_le32(res); fail_if(check (&test_output32[i], &res, sizeof(res)), "gu_mmh32() failed at step %d",i); } } END_TEST #if 0 /* x86 variant is faulty and unsuitable for short keys, ignore */ START_TEST (gu_mmh128_x86_test) { int i; uint32_t out32; smhasher_verification (gu_mmh3_x86_128, sizeof(hash128_t), &out32); fail_if (check (&smhasher_checks[1], &out32, sizeof(out32)), "gu_mmh3_x86_128 failed."); for (i = 0; i < NUM_128_TESTS; i++) { hash128_t out; gu_mmh3_x86_128 (test_input, i, GU_MMH32_SEED, &out); check (&test_output128[i], &out, sizeof(out)); } } END_TEST #endif /* 0 */ START_TEST (gu_mmh128_x64_test) { int i; uint32_t out32; smhasher_verification (gu_mmh3_x64_128, sizeof(hash128_t), &out32); fail_if (check (&smhasher_checks[2], &out32, sizeof(out32)), "gu_mmh3_x64_128 failed."); for (i = 0; i < NUM_128_TESTS; i++) { hash128_t out; gu_mmh128 (test_input, i, &out); fail_if(check (&test_output128[i], &out, sizeof(out)), "gu_mmh128() failed at step %d", i); } } END_TEST /* Tests partial hashing functions */ START_TEST (gu_mmh128_partial) { hash128_t part; gu_mmh128_ctx_t ctx; gu_mmh128_init (&ctx); gu_mmh128_append (&ctx, test_input, 31); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[31], &part, sizeof(part)), "gu_mmh128_get() failed at one go"); gu_mmh128_init (&ctx); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[0], &part, sizeof(part)), "gu_mmh128_get() failed at init"); gu_mmh128_append (&ctx, test_input + 0, 0); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[0], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 0); gu_mmh128_append (&ctx, test_input + 0, 1); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[1], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 1); gu_mmh128_append (&ctx, test_input + 1, 2); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[3], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 3); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[3], &part, sizeof(part)), "gu_mmh128_get() failed at length %d again", 3); gu_mmh128_append (&ctx, test_input + 3, 20); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[23], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 23); gu_mmh128_append (&ctx, test_input + 23, 0); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[23], &part, sizeof(part)), "gu_mmh128_get() failed at length %d again", 23); gu_mmh128_append (&ctx, test_input + 23, 3); gu_mmh128_append (&ctx, test_input + 26, 3); gu_mmh128_append (&ctx, test_input + 29, 2); gu_mmh128_get (&ctx, &part); fail_if(check (&test_output128[31], &part, sizeof(part)), "gu_mmh128_get() failed at length %d", 31); } END_TEST Suite *gu_mmh3_suite(void) { Suite *s = suite_create("MurmurHash3"); TCase *tc = tcase_create("gu_mmh3"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_mmh32_test); // tcase_add_test (tc, gu_mmh128_x86_test); tcase_add_test (tc, gu_mmh128_x64_test); tcase_add_test (tc, gu_mmh128_partial); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_mmh3_test.h000066400000000000000000000003131244131713600232240ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_mmh3_test__ #define __gu_mmh3_test__ #include extern Suite *gu_mmh3_suite(void); #endif /* __gu_mmh3_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_net_test.cpp000066400000000000000000000037741244131713600235170ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy #include #include #include #include #include #include #include #include #include "gu_logger.hpp" #include "gu_uri.hpp" #include "gu_resolver.hpp" #include "gu_lock.hpp" #include "gu_prodcons.hpp" #include "gu_net_test.hpp" using std::vector; using std::string; using std::deque; using std::mem_fun; using std::for_each; using namespace gu; using namespace gu::net; using namespace gu::prodcons; START_TEST(test_resolver) { std::string tcp_lh4("tcp://127.0.0.1:2002"); Addrinfo tcp_lh4_ai(resolve(tcp_lh4)); fail_unless(tcp_lh4_ai.get_family() == AF_INET); fail_unless(tcp_lh4_ai.get_socktype() == SOCK_STREAM); fail_unless(tcp_lh4_ai.to_string() == tcp_lh4, "%s != %s", tcp_lh4_ai.to_string().c_str(), tcp_lh4.c_str()); std::string tcp_lh6("tcp://[::1]:2002"); Addrinfo tcp_lh6_ai(resolve(tcp_lh6)); fail_unless(tcp_lh6_ai.get_family() == AF_INET6); fail_unless(tcp_lh6_ai.get_socktype() == SOCK_STREAM); fail_unless(tcp_lh6_ai.to_string() == tcp_lh6, "%s != %s", tcp_lh6_ai.to_string().c_str(), tcp_lh6.c_str()); std::string lh("tcp://localhost:2002"); Addrinfo lh_ai(resolve(lh)); fail_unless(lh_ai.to_string() == "tcp://127.0.0.1:2002" || lh_ai.to_string() == "tcp://[::1]:2002"); } END_TEST START_TEST(trac_288) { try { string url("tcp://do-not-resolve:0"); (void)resolve(url); } catch (Exception& e) { log_debug << "exception was " << e.what(); } } END_TEST Suite* gu_net_suite() { Suite* s = suite_create("galerautils++ Networking"); TCase* tc; tc = tcase_create("test_resolver"); tcase_add_test(tc, test_resolver); suite_add_tcase(s, tc); tc = tcase_create("trac_288"); tcase_add_test(tc, trac_288); #if 0 /* bogus test, commenting out for now */ suite_add_tcase(s, tc); #endif return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_net_test.hpp000066400000000000000000000003071244131713600235110ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_net_test__ #define __gu_net_test__ #include extern Suite *gu_net_suite(void); #endif /* __gu_net_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_rset_test.cpp000066400000000000000000000273171244131713600237050ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #undef NDEBUG #include "../src/gu_rset.hpp" #include "gu_rset_test.hpp" #include "gu_logger.hpp" #include "gu_hexdump.hpp" class TestBaseName : public gu::Allocator::BaseName { std::string str_; public: TestBaseName(const char* name) : str_(name) {} void print(std::ostream& os) const { os << str_; } }; class TestRecord : public gu::Serializable { public: TestRecord (size_t size, const char* str) : Serializable(), size_(size), buf_(reinterpret_cast(::malloc(size_))), str_(reinterpret_cast(buf_ + sizeof(uint32_t))), own_(true) { fail_if (size_ > 0x7fffffff); if (0 == buf_) throw std::runtime_error("failed to allocate record"); gu::byte_t* tmp = const_cast(buf_); *reinterpret_cast(tmp) = htog32(size_); ::strncpy (const_cast(str_), str, size_ - 4); } TestRecord (const gu::byte_t* const buf, ssize_t const size) : Serializable(), size_(TestRecord::serial_size(buf, size)), buf_(buf), str_(reinterpret_cast(buf_ + sizeof(uint32_t))), own_(false) {} TestRecord (const TestRecord& t) : size_(t.size_), buf_(t.buf_), str_(t.str_), own_(false) {} virtual ~TestRecord () { if (own_) free (const_cast(buf_)); } const gu::byte_t* buf() const { return buf_; } const char* c_str() const { return str_; } ssize_t serial_size() const { return my_serial_size(); } static ssize_t serial_size(const gu::byte_t* const buf, ssize_t const size) { check_buf (buf, size, 1); return gtoh32 (*reinterpret_cast(buf)); } bool operator!= (const TestRecord& t) const { return (::strcmp(str_, t.str_)); } bool operator== (const TestRecord& t) const { return (!(*this != t)); } private: size_t const size_; const gu::byte_t* const buf_; const char* const str_; bool const own_; ssize_t my_serial_size () const { return size_; }; ssize_t my_serialize_to (void* buf, ssize_t size) const { check_buf (buf, size, size_); ::memcpy (buf, buf_, size_); return size_; } static void check_buf (const void* const buf, ssize_t const size, ssize_t min_size) { if (gu_unlikely (buf == 0 || size < min_size)) throw std::length_error("buffer too short"); } TestRecord& operator= (const TestRecord&); }; START_TEST (ver0) { size_t const MB = 1 << 20; // the choice of sizes below is based on default allocator memory store size // of 4MB. If it is changed, these need to be changed too. TestRecord rout0(120, "abc0"); fail_if (rout0.serial_size() != 120); fail_if (gtoh32(*reinterpret_cast(rout0.buf())) != 120); TestRecord rout1(121, "abc1"); TestRecord rout2(122, "012345"); TestRecord rout3(123, "defghij"); TestRecord rout4(3*MB, "klm"); TestRecord rout5(1*MB, "qpr"); std::vector records; records.push_back (&rout0); records.push_back (&rout1); records.push_back (&rout2); records.push_back (&rout3); records.push_back (&rout4); records.push_back (&rout5); gu::byte_t reserved[1024]; TestBaseName str("gu_rset_test"); gu::RecordSetOut rset_out(reserved, sizeof(reserved), str, gu::RecordSet::CHECK_MMH64, gu::RecordSet::VER1); size_t offset(rset_out.size()); fail_if (1 != rset_out.page_count()); std::pair rp; int rsize; const void* rout_ptrs[7]; // this should be allocated inside current page rp = rset_out.append (rout0); rout_ptrs[0] = rp.first; rsize = rp.second; fail_if (rsize != rout0.serial_size()); fail_if (rsize < 0); fail_if (rsize != TestRecord::serial_size(rp.first, rsize)); offset += rsize; fail_if (rset_out.size() != offset); fail_if (1 != rset_out.page_count()); // this should trigger new page since not stored rp = rset_out.append (rout1.buf(), rout1.serial_size(), false); rout_ptrs[1] = rp.first; rsize = rp.second; fail_if (rsize != rout1.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (2 != rset_out.page_count()); // this should trigger new page since previous one was not stored rp = rset_out.append (rout2); rout_ptrs[2] = rp.first; rsize = rp.second; fail_if (rsize != rout2.serial_size()); fail_if (rsize < 0); fail_if (rsize != TestRecord::serial_size(rp.first, rsize)); offset += rsize; fail_if (rset_out.size() != offset); fail_if (3 != rset_out.page_count(), "Expected %d pages, found %zu", 3, rset_out.page_count()); //***** test partial record appending *****// // this should be allocated inside the current page. rp = rset_out.append (rout3.buf(), 3); // rout_ptrs[2] = rp.first; rsize = rp.second; offset += rp.second; fail_if (3 != rset_out.page_count()); // this should trigger a new page, since not stored rp = rset_out.append (rout3.buf() + 3, rout3.serial_size() - 3, false, false); rout_ptrs[3] = rp.first; rsize += rp.second; fail_if (rsize != rout3.serial_size()); offset += rp.second; fail_if (rset_out.size() != offset); fail_if (4 != rset_out.page_count()); // this should trigger new page, because won't fit in the current page rp = rset_out.append (rout4); rout_ptrs[4] = rp.first; rsize = rp.second; fail_if (rsize != rout4.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (5 != rset_out.page_count()); // this should trigger new page, because 4MB RAM limit exceeded rp = rset_out.append (rout5); rout_ptrs[5] = rp.first; rsize = rp.second; fail_if (rsize != rout5.serial_size()); offset += rsize; fail_if (rset_out.size() != offset); fail_if (6 != rset_out.page_count(), "Expected %d pages, found %zu", 5, rset_out.page_count()); fail_if (records.size() != size_t(rset_out.count())); gu::RecordSet::GatherVector out_bufs; out_bufs->reserve (rset_out.page_count()); size_t min_out_size(0); for (size_t i = 0; i < records.size(); ++i) { min_out_size += records[i]->serial_size(); } size_t const out_size (rset_out.gather (out_bufs)); fail_if (out_size <= min_out_size || out_size > offset); fail_if (out_bufs->size() != static_cast(rset_out.page_count()), "Expected %zu buffers, got: %zd", rset_out.page_count(), out_bufs->size()); /* concatenate all buffers into one */ std::vector in_buf; in_buf.reserve(out_size); mark_point(); for (size_t i = 0; i < out_bufs->size(); ++i) { // 0th fragment starts with header, so it it can't be used in this check fail_if (i > 0 && rout_ptrs[i] != out_bufs[i].ptr, "Record pointers don't mathch after gather(). " "old: %p, new: %p", rout_ptrs[i],out_bufs[i].ptr); ssize_t size = gtoh32( *reinterpret_cast(out_bufs[i].ptr)); const char* str = reinterpret_cast(out_bufs[i].ptr) + sizeof(uint32_t); // 0th fragment starts with header, so it it can't be used in this check fail_if (i > 0 && size <= ssize_t(sizeof(uint32_t)), "Expected size > 4, got %zd(%#010zx). i = %zu, buf = %s", size, size, i, str); // the above variables make have sense only on certain pages // hence ifs below size_t k = i; switch (i) { case 3: break; // 4th page is partial 4th record case 1: case 2: fail_if (::strcmp(str, records[k]->c_str()), "Buffer %zu: appending '%s', expected '%s'", i, str, records[k]->c_str()); } if (i == 1 || i == 4) { fail_if (size != records[k]->serial_size(), "Buffer %zu: appending size %zd, expected %zd", i, size, records[k]->serial_size()); } log_info << "\nadding buf " << i << ": " << gu::Hexdump(out_bufs[i].ptr, std::min(out_bufs[i].size, 24), true); size_t old_size = in_buf.size(); const gu::byte_t* const begin (reinterpret_cast(out_bufs[i].ptr)); in_buf.insert (in_buf.end(), begin, begin + out_bufs[i].size); fail_if (old_size + out_bufs[i].size != in_buf.size()); } fail_if (in_buf.size() != out_size, "Sent buf size: %zu, recvd buf size: %zu", out_size, in_buf.size()); log_info << "Resulting RecordSet buffer:\n" << gu::Hexdump(in_buf.data(), 32, false) << '\n' << gu::Hexdump(in_buf.data(), 32, true); gu::RecordSetIn const rset_in(in_buf.data(), in_buf.size()); fail_if (rset_in.size() != rset_out.size()); fail_if (rset_in.count() != rset_out.count()); for (ssize_t i = 0; i < rset_in.count(); ++i) { TestRecord const rin(rset_in.next()); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } /* Test checksum method: */ try { rset_in.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } /* test buf() method */ gu::RecordSetIn const rset_in_buf(rset_in.buf().ptr, rset_in.buf().size); fail_if(rset_in.count() != rset_in_buf.count()); fail_if(rset_in.size() != rset_in_buf.size()); fail_if (rset_in.buf().ptr != rset_in_buf.buf().ptr); for (ssize_t i = 0; i < rset_in_buf.count(); ++i) { TestRecord const rin(rset_in_buf.next()); fail_if (rin != *records[i], "Record %d failed: expected %s, found %s", i, records[i]->c_str(), rin.c_str()); } /* test empty RecordSetIn creation with subsequent initialization */ gu::RecordSetIn rset_in_empty; fail_if (rset_in_empty.size() != 0); fail_if (rset_in_empty.count() != 0); try { TestRecord const rin(rset_in_empty.next()); fail ("next() succeeded on an empty writeset"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EPERM); } rset_in_empty.init(in_buf.data(), in_buf.size(), true); fail_if (rset_in_empty.size() != rset_out.size()); fail_if (rset_in_empty.count() != rset_out.count()); /* Try some data corruption: swap a bit */ in_buf[10] ^= 1; try { rset_in.checksum(); fail("checksum() didn't throw on corrupted set"); } catch (std::exception& e) {} try { rset_in_empty.checksum(); fail("checksum() didn't throw on corrupted set"); } catch (std::exception& e) {} } END_TEST START_TEST (empty) { gu::RecordSetIn const rset_in(0, 0); fail_if (0 != rset_in.size()); fail_if (0 != rset_in.count()); try { rset_in.checksum(); } catch (std::exception& e) { fail("%s", e.what()); } } END_TEST Suite* gu_rset_suite () { TCase* t = tcase_create ("RecordSet"); tcase_add_test (t, ver0); tcase_add_test (t, empty); tcase_set_timeout(t, 60); Suite* s = suite_create ("gu::RecordSet"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_rset_test.hpp000066400000000000000000000003121244131713600236740ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_rset_test__ #define __gu_rset_test__ #include Suite *gu_rset_suite(void); #endif /* __gu_rset_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_spooky_test.c000066400000000000000000000174301244131713600237070ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy /*! * Original Bob Jenkins' test implementation: * http://www.burtleburtle.net/bob/c/testspooky.cpp * * $Id$ */ #include "gu_spooky_test.h" #include "../src/gu_spooky.h" #include "../src/gu_hexdump.h" #define BUFSIZE 512 static uint64_t const expected[BUFSIZE] = { 0xa24295ec, 0xfe3a05ce, 0x257fd8ef, 0x3acd5217, 0xfdccf85c, 0xc7b5f143, 0x3b0c3ff0, 0x5220f13c, 0xa6426724, 0x4d5426b4, 0x43e76b26, 0x051bc437, 0xd8f28a02, 0x23ccc30e, 0x811d1a2d, 0x039128d4, 0x9cd96a73, 0x216e6a8d, 0x97293fe8, 0xe4fc6d09, 0x1ad34423, 0x9722d7e4, 0x5a6fdeca, 0x3c94a7e1, 0x81a9a876, 0xae3f7c0e, 0x624b50ee, 0x875e5771, 0x0095ab74, 0x1a7333fb, 0x056a4221, 0xa38351fa, 0x73f575f1, 0x8fded05b, 0x9097138f, 0xbd74620c, 0x62d3f5f2, 0x07b78bd0, 0xbafdd81e, 0x0638f2ff, 0x1f6e3aeb, 0xa7786473, 0x71700e1d, 0x6b4625ab, 0xf02867e1, 0xb2b2408f, 0x9ce21ce5, 0xa62baaaf, 0x26720461, 0x434813ee, 0x33bc0f14, 0xaaab098a, 0x750af488, 0xc31bf476, 0x9cecbf26, 0x94793cf3, 0xe1a27584, 0xe80c4880, 0x1299f748, 0x25e55ed2, 0x405e3feb, 0x109e2412, 0x3e55f94f, 0x59575864, 0x365c869d, 0xc9852e6a, 0x12c30c62, 0x47f5b286, 0xb47e488d, 0xa6667571, 0x78220d67, 0xa49e30b9, 0x2005ef88, 0xf6d3816d, 0x6926834b, 0xe6116805, 0x694777aa, 0x464af25b, 0x0e0e2d27, 0x0ea92eae, 0x602c2ca9, 0x1d1d79c5, 0x6364f280, 0x939ee1a4, 0x3b851bd8, 0x5bb6f19f, 0x80b9ed54, 0x3496a9f1, 0xdf815033, 0x91612339, 0x14c516d6, 0xa3f0a804, 0x5e78e975, 0xf408bcd9, 0x63d525ed, 0xa1e459c3, 0xfde303af, 0x049fc17f, 0xe7ed4489, 0xfaeefdb6, 0x2b1b2fa8, 0xc67579a6, 0x5505882e, 0xe3e1c7cb, 0xed53bf30, 0x9e628351, 0x8fa12113, 0x7500c30f, 0xde1bee00, 0xf1fefe06, 0xdc759c00, 0x4c75e5ab, 0xf889b069, 0x695bf8ae, 0x47d6600f, 0xd2a84f87, 0xa0ca82a9, 0x8d2b750c, 0xe03d8cd7, 0x581fea33, 0x969b0460, 0x36c7b7de, 0x74b3fd20, 0x2bb8bde6, 0x13b20dec, 0xa2dcee89, 0xca36229d, 0x06fdb74e, 0x6d9a982d, 0x02503496, 0xbdb4e0d9, 0xbd1f94cf, 0x6d26f82d, 0xcf5e41cd, 0x88b67b65, 0x3e1b3ee4, 0xb20e5e53, 0x1d9be438, 0xcef9c692, 0x299bd1b2, 0xb1279627, 0x210b5f3d, 0x5569bd88, 0x9652ed43, 0x7e8e0f8c, 0xdfa01085, 0xcd6d6343, 0xb8739826, 0xa52ce9a0, 0xd33ef231, 0x1b4d92c2, 0xabfa116d, 0xcdf47800, 0x3a4eefdc, 0xd01f3bcf, 0x30a32f46, 0xfb54d851, 0x06a98f67, 0xbdcd0a71, 0x21a00949, 0xfe7049c9, 0x67ef46d2, 0xa1fabcbc, 0xa4c72db4, 0x4a8a910d, 0x85a890ad, 0xc37e9454, 0xfc3d034a, 0x6f46cc52, 0x742be7a8, 0xe94ecbc5, 0x5f993659, 0x98270309, 0x8d1adae9, 0xea6e035e, 0x293d5fae, 0x669955b3, 0x5afe23b5, 0x4c74efbf, 0x98106505, 0xfbe09627, 0x3c00e8df, 0x5b03975d, 0x78edc83c, 0x117c49c6, 0x66cdfc73, 0xfa55c94f, 0x5bf285fe, 0x2db49b7d, 0xfbfeb8f0, 0xb7631bab, 0x837849f3, 0xf77f3ae5, 0x6e5db9bc, 0xfdd76f15, 0x545abf92, 0x8b538102, 0xdd5c9b65, 0xa5adfd55, 0xecbd7bc5, 0x9f99ebdd, 0x67500dcb, 0xf5246d1f, 0x2b0c061c, 0x927a3747, 0xc77ba267, 0x6da9f855, 0x6240d41a, 0xe9d1701d, 0xc69f0c55, 0x2c2c37cf, 0x12d82191, 0x47be40d3, 0x165b35cd, 0xb7db42e1, 0x358786e4, 0x84b8fc4e, 0x92f57c28, 0xf9c8bbd7, 0xab95a33d, 0x11009238, 0xe9770420, 0xd6967e2a, 0x97c1589f, 0x2ee7e7d3, 0x32cc86da, 0xe47767d1, 0x73e9b61e, 0xd35bac45, 0x835a62bb, 0x5d9217b0, 0x43f3f0ed, 0x8a97911e, 0x4ec7eb55, 0x4b5a988c, 0xb9056683, 0x45456f97, 0x1669fe44, 0xafb861b8, 0x8e83a19c, 0x0bab08d6, 0xe6a145a9, 0xc31e5fc2, 0x27621f4c, 0x795692fa, 0xb5e33ab9, 0x1bc786b6, 0x45d1c106, 0x986531c9, 0x40c9a0ec, 0xff0fdf84, 0xa7359a42, 0xfd1c2091, 0xf73463d4, 0x51b0d635, 0x1d602fb4, 0xc56b69b7, 0x6909d3f7, 0xa04d68f4, 0x8d1001a7, 0x8ecace50, 0x21ec4765, 0x3530f6b0, 0x645f3644, 0x9963ef1e, 0x2b3c70d5, 0xa20c823b, 0x8d26dcae, 0x05214e0c, 0x1993896d, 0x62085a35, 0x7b620b67, 0x1dd85da2, 0x09ce9b1d, 0xd7873326, 0x063ff730, 0xf4ff3c14, 0x09a49d69, 0x532062ba, 0x03ba7729, 0xbd9a86cc, 0xe26d02a7, 0x7ccbe5d3, 0x4f662214, 0x8b999a66, 0x3d0b92b4, 0x70b210f0, 0xf5b8f16f, 0x32146d34, 0x430b92bf, 0x8ab6204c, 0x35e6e1ff, 0xc2f6c2fa, 0xa2df8a1a, 0x887413ec, 0x7cb7a69f, 0x7ac6dbe6, 0x9102d1cb, 0x8892a590, 0xc804fe3a, 0xdfc4920a, 0xfc829840, 0x8910d2eb, 0x38a210fd, 0x9d840cc9, 0x7b9c827f, 0x3444ca0c, 0x071735ab, 0x5e9088e4, 0xc995d60e, 0xbe0bb942, 0x17b089ae, 0x050e1054, 0xcf4324f7, 0x1e3e64dd, 0x436414bb, 0xc48fc2e3, 0x6b6b83d4, 0x9f6558ac, 0x781b22c5, 0x7147cfe2, 0x3c221b4d, 0xa5602765, 0x8f01a4f0, 0x2a9f14ae, 0x12158cb8, 0x28177c50, 0x1091a165, 0x39e4e4be, 0x3e451b7a, 0xd965419c, 0x52053005, 0x0798aa53, 0xe6773e13, 0x1207f671, 0xd2ef998b, 0xab88a38f, 0xc77a8482, 0xa88fb031, 0x5199e0cd, 0x01b30536, 0x46eeb0ef, 0x814259ff, 0x9789a8cf, 0x376ec5ac, 0x7087034a, 0x948b6bdd, 0x4281e628, 0x2c848370, 0xd76ce66a, 0xe9b6959e, 0x24321a8e, 0xdeddd622, 0xb890f960, 0xea26c00a, 0x55e7d8b2, 0xeab67f09, 0x9227fb08, 0xeebbed06, 0xcac1b0d1, 0xb6412083, 0x05d2b0e7, 0x9037624a, 0xc9702198, 0x2c8d1a86, 0x3e7d416e, 0xc3f1a39f, 0xf04bdce4, 0xc88cdb61, 0xbdc89587, 0x4d29b63b, 0x6f24c267, 0x4b529c87, 0x573f5a53, 0xdb3316e9, 0x288eb53b, 0xd2c074bd, 0xef44a99a, 0x2b404d2d, 0xf6706464, 0xfe824f4c, 0xc3debaf8, 0x12f44f98, 0x03135e76, 0xb4888e7f, 0xb6b2325d, 0x3a138259, 0x513c83ec, 0x2386d214, 0x94555500, 0xfbd1522d, 0xda2af018, 0x15b054c0, 0x5ad654e6, 0xb6ed00aa, 0xa2f2180e, 0x5f662825, 0xecd11366, 0x1de5e99d, 0x07afd2ad, 0xcf457b04, 0xe631e10b, 0x83ae8a21, 0x709f0d59, 0x3e278bf9, 0x246816db, 0x9f5e8fd3, 0xc5b5b5a2, 0xd54a9d5c, 0x4b6f2856, 0x2eb5a666, 0xfc68bdd4, 0x1ed1a7f8, 0x98a34b75, 0xc895ada9, 0x2907cc69, 0x87b0b455, 0xddaf96d9, 0xe7da15a6, 0x9298c82a, 0x72bd5cab, 0x2e2a6ad4, 0x7f4b6bb8, 0x525225fe, 0x985abe90, 0xac1fd6e1, 0xb8340f23, 0x92985159, 0x7d29501d, 0xe75dc744, 0x687501b4, 0x92077dc3, 0x58281a67, 0xe7e8e9be, 0xd0e64fd1, 0xb2eb0a30, 0x0e1feccd, 0xc0dc4a9e, 0x5c4aeace, 0x2ca5b93c, 0xee0ec34f, 0xad78467b, 0x0830e76e, 0x0df63f8b, 0x2c2dfd95, 0x9b41ed31, 0x9ff4cddc, 0x1590c412, 0x2366fc82, 0x7a83294f, 0x9336c4de, 0x2343823c, 0x5b681096, 0xf320e4c2, 0xc22b70e2, 0xb5fbfb2a, 0x3ebc2fed, 0x11af07bd, 0x429a08c5, 0x42bee387, 0x58629e33, 0xfb63b486, 0x52135fbe, 0xf1380e60, 0x6355de87, 0x2f0bb19a, 0x167f63ac, 0x507224cf, 0xf7c99d00, 0x71646f50, 0x74feb1ca, 0x5f9abfdd, 0x278f7d68, 0x70120cd7, 0x4281b0f2, 0xdc8ebe5c, 0x36c32163, 0x2da1e884, 0x61877598, 0xbef04402, 0x304db695, 0xfa8e9add, 0x503bac31, 0x0fe04722, 0xf0d59f47, 0xcdc5c595, 0x918c39dd, 0x0cad8d05, 0x6b3ed1eb, 0x4d43e089, 0x7ab051f8, 0xdeec371f, 0x0f4816ae, 0xf8a1a240, 0xd15317f6, 0xb8efbf0b, 0xcdd05df8, 0x4fd5633e, 0x7cf19668, 0x25d8f422, 0x72d156f2, 0x2a778502, 0xda7aefb9, 0x4f4f66e8, 0x19db6bff, 0x74e468da, 0xa754f358, 0x7339ec50, 0x139006f6, 0xefbd0b91, 0x217e9a73, 0x939bd79c }; START_TEST (gu_spooky_test) { uint8_t buf[BUFSIZE]; size_t i; for (i = 0; i < BUFSIZE; ++i) { uint32_t res; buf[i] = i+128; /* It looks like values for messages under bufSize are for the "short" * algorithm, incompatible with the real one. */ if (i < _spooky_bufSize) { /* using 128-bit version */ uint64_t h[2]; gu_spooky_short (buf, i, h); res = (uint32_t)gu_le64(h[0]); } else { /* using 32-bit version */ res = gu_spooky32 (buf, i); } if (res != expected[i]) { fail ("%d: expected: 0x%.8lX, found: 0x%.8lX", i, expected[i], res); } } } END_TEST Suite *gu_spooky_suite(void) { Suite *s = suite_create("Spooky hash"); TCase *tc = tcase_create("gu_spooky"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_spooky_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_spooky_test.h000066400000000000000000000003231244131713600237050ustar00rootroot00000000000000// Copyright (C) 2012 Codership Oy // $Id$ #ifndef __gu_spooky_test__ #define __gu_spooky_test__ #include extern Suite *gu_spooky_suite(void); #endif /* __gu_spooky_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_stats_test.cpp000066400000000000000000000024241244131713600240560ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #include "../src/gu_stats.hpp" #include "gu_stats_test.hpp" #include #include using namespace gu; static inline bool double_equal(double a, double b) { return (std::fabs(a - b) <= std::fabs(a + b) * std::numeric_limits::epsilon()); } START_TEST(test_stats) { Stats st; st.insert(10.0); st.insert(20.0); st.insert(30.0); fail_if(!double_equal(st.mean(), 20.0)); fail_if(!double_equal(st.variance() * 3, 200.0), "%e != 0", st.variance()*3-200.0); fail_if(!double_equal(st.min(), 10.0)); fail_if(!double_equal(st.max(), 30.0)); st.clear(); st.insert(10.0); fail_if(!double_equal(st.mean(), 10.0)); fail_if(!double_equal(st.variance(), 0.0)); fail_if(!double_equal(st.min(), 10.0)); fail_if(!double_equal(st.max(), 10.0)); st.clear(); fail_if(!double_equal(st.mean(), 0.0)); fail_if(!double_equal(st.variance(), 0.0)); fail_if(!double_equal(st.min(), 0.0)); fail_if(!double_equal(st.max(), 0.0)); } END_TEST Suite* gu_stats_suite() { TCase* t = tcase_create ("test_stats"); tcase_add_test (t, test_stats); Suite* s = suite_create ("gu::Stats"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_stats_test.hpp000066400000000000000000000003121244131713600240550ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef __gu_stats_test__ #define __gu_stats_test__ #include extern Suite *gu_stats_suite(void); #endif // __gu_stats_test__ percona-galera-3-3.8-3390/galerautils/tests/gu_str_test.c000066400000000000000000000046741244131713600232010ustar00rootroot00000000000000 #include "gu_str.h" #include START_TEST(test_append) { const char* strs[3] = { "t", "ttt", "tttttttt" }; char* str = NULL; size_t off = 0; size_t i; for (i = 0; i < 3; ++i) { str = gu_str_append(str, &off, strs[i], strlen(strs[i])); } free(str); } END_TEST START_TEST(test_scan) { const char* strs[5] = { "1", "234", "56789abc", "4657777777777", "345" }; char* str = NULL; size_t off = 0; size_t len = 0; size_t i; const char* ptr; for (i = 0; i < 5; ++i) { str = gu_str_append(str, &off, strs[i], strlen(strs[i])); len += strlen(strs[i]) + 1; } ptr = str; for (i = 0; i < 5; ++i) { fail_unless(strcmp(ptr, strs[i]) == 0); ptr = gu_str_next(ptr); } fail_unless(ptr == len + str); for (i = 0; i < 5; ++i) { ptr = gu_str_advance(str, i); fail_unless(strcmp(ptr, strs[i]) == 0); } free(str); } END_TEST START_TEST(test_str_table) { size_t n_cols = 5; char const* col_names[5] = { "col1", "column2", "foo", "bar", "zzz" }; size_t n_rows = 255; const char* row[5] = {"dddd", "asdfasdf", "sadfdf", "", "a"}; const char* name = "test_table"; char* str = NULL; size_t off = 0; size_t i; str = gu_str_table_set_name(str, &off, name); fail_unless(strcmp(gu_str_table_get_name(str), name) == 0); str = gu_str_table_set_n_cols(str, &off, n_cols); fail_unless(gu_str_table_get_n_cols(str) == n_cols); str = gu_str_table_set_n_rows(str, &off, n_rows); fail_unless(gu_str_table_get_n_rows(str) == n_rows); str = gu_str_table_set_cols(str, &off, n_cols, col_names); for (i = 0; i < n_rows; ++i) { str = gu_str_table_append_row(str, &off, n_cols, row); } mark_point(); FILE* tmp = fopen("/dev/null", "w"); fail_if (NULL == tmp); gu_str_table_print(tmp, str); fclose(tmp); free(str); } END_TEST Suite* gu_str_suite() { Suite* s = suite_create("Galera Str util suite"); TCase* tc; tc = tcase_create("test_append"); tcase_add_test(tc, test_append); suite_add_tcase(s, tc); tc = tcase_create("test_scan"); tcase_add_test(tc, test_scan); suite_add_tcase(s, tc); tc = tcase_create("test_str_table"); tcase_add_test(tc, test_str_table); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_str_test.h000066400000000000000000000002541244131713600231740ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy #ifndef __gu_str_test__ #define __gu_str_test__ extern Suite *gu_str_suite(void); #endif /* __gu_str_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_string_test.cpp000066400000000000000000000053261244131713600242320ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "../src/gu_string.hpp" #include "gu_string_test.hpp" START_TEST (ctor_test) { gu::String<8> str1; // default fail_if (str1.size() != 0); fail_if (strlen(str1.c_str()) != 0); const char* const test_string1("test"); gu::String<8> str2(test_string1); // from char* fail_if (str2.size() != strlen(test_string1)); fail_if (strcmp(str2.c_str(), test_string1)); gu::String<2> str3(str2); // copy ctor fail_if (str3.size() != str2.size()); fail_if (strcmp(str2.c_str(), str3.c_str())); std::string const std_string(str3.c_str()); gu::String<4> str4(std_string); // from std::string fail_if (str4.size() != strlen(test_string1)); fail_if (strcmp(str4.c_str(), test_string1)); gu::String<5> str5(test_string1, 2); fail_if (str5.size() != 2); fail_if (strncmp(str5.c_str(), test_string1, 2)); } END_TEST START_TEST (func_test) { gu::String<16> str; fail_if (str.size() != 0); fail_if (strlen(str.c_str()) != 0); const char* const buf_ptr(str.c_str()); str = "one"; str << std::string("two") << gu::String<8>("three"); fail_if (strcmp(str.c_str(), "onetwothree")); fail_if (str.c_str() != buf_ptr); str += "blast!"; // this should spill to heap fail_if (strcmp(str.c_str(), "onetwothreeblast!"), "expected 'onetwothreeblast!' got '%s'", str.c_str()); fail_if (str.c_str() == buf_ptr); str = gu::String<2>("back to stack"); fail_if (str != "back to stack"); fail_if (str != gu::String<>("back to stack")); fail_if (str != std::string("back to stack")); fail_if (str.c_str() != buf_ptr); typedef void* pointer; // conversions fail_if ((gu::String<>() << true) != "true"); fail_if ((gu::String<>() << 0.0123) != "0.012300"); if (sizeof(pointer) == 4) fail_if ((gu::String<>() << pointer(0xdeadbeef))!="0xdeadbeef"); else fail_if ((gu::String<>() << pointer(0xdeadbeef))!="0x00000000deadbeef"); fail_if ((gu::String<>() << 1234567890) != "1234567890"); fail_if ((gu::String<>() << 12345U) != "12345"); fail_if ((gu::String<>() << 'a') != "a"); fail_if ((gu::String<>() << 0xdeadbeef) != "3735928559"); fail_if ((gu::String<>() << gu::Fmt("%010x") << 0xdeadbeef) !="00deadbeef"); } END_TEST Suite* gu_string_suite(void) { Suite* s = suite_create ("gu::String"); TCase* t = tcase_create ("ctor_test"); tcase_add_test (t, ctor_test); suite_add_tcase (s, t); t = tcase_create ("func_test"); tcase_add_test (t, func_test); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_string_test.hpp000066400000000000000000000003311244131713600242260ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_string_test__ #define __gu_string_test__ #include extern Suite *gu_string_suite(void); #endif /* __gu_string_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_string_utils_test.cpp000066400000000000000000000053361244131713600254530ustar00rootroot00000000000000// Copyright (C) 2009-2010 Codership Oy #include "gu_string_utils.hpp" #include "gu_string_utils_test.hpp" using std::string; using std::vector; START_TEST(test_strsplit) { string str = "foo bar baz"; vector vec = gu::strsplit(str, ' '); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); } END_TEST START_TEST(test_tokenize) { vector vec = gu::tokenize("", 'a', 'b', false); fail_unless(vec.size() == 0); vec = gu::tokenize("", 'a', 'b', true); fail_unless(vec.size() == 1); fail_unless(vec[0] == ""); vec = gu::tokenize("a", 'a', 'b', false); fail_unless(vec.size() == 0); vec = gu::tokenize("a", 'a', 'b', true); fail_unless(vec.size() == 2); fail_unless(vec[0] == ""); fail_unless(vec[1] == ""); vec = gu::tokenize("foo bar baz"); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); vec = gu::tokenize("foo\\ bar baz"); fail_unless(vec.size() == 2); fail_unless(vec[0] == "foo bar", "expected 'foo bar', found '%s'", vec[0].c_str()); fail_unless(vec[1] == "baz"); vec = gu::tokenize("foo\\;;bar;;baz;", ';', '\\', false); fail_unless(vec.size() == 3); fail_unless(vec[0] == "foo;"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == "baz"); vec = gu::tokenize("foo\\;;bar;;baz;", ';', '\\', true); fail_unless(vec.size() == 5, "vetor length %zu, expected 5", vec.size()); fail_unless(vec[0] == "foo;"); fail_unless(vec[1] == "bar"); fail_unless(vec[2] == ""); fail_unless(vec[3] == "baz"); fail_unless(vec[4] == ""); } END_TEST START_TEST(test_trim) { string full1 = ".,wklerf joweji"; string full2 = full1; gu::trim (full2); fail_if (full1 != full2); string part = " part "; gu::trim (part); fail_if (part.length() != 4); fail_if (0 != part.compare("part")); string empty; gu::trim (empty); fail_if (!empty.empty()); empty += ' '; empty += '\t'; empty += '\n'; empty += '\f'; fail_if (empty.empty()); gu::trim (empty); fail_if (!empty.empty(), "string contents: '%s', expected empty", empty.c_str()); } END_TEST Suite* gu_string_utils_suite(void) { Suite* s = suite_create("String Utils"); TCase* tc; tc = tcase_create("strsplit"); tcase_add_test(tc, test_strsplit); suite_add_tcase(s, tc); tc = tcase_create("tokenize"); tcase_add_test(tc, test_tokenize); suite_add_tcase(s, tc); tc = tcase_create("trim"); tcase_add_test(tc, test_trim); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_string_utils_test.hpp000066400000000000000000000003531244131713600254520ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_string_utils_test__ #define __gu_string_utils_test__ #include extern Suite* gu_string_utils_suite(void); #endif /* __gu_string_utils_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_tests++.cpp000066400000000000000000000016601244131713600231520ustar00rootroot00000000000000// Copyright (C) 2009 Codership Oy #include #include #include extern "C" { #include "../src/gu_conf.h" } #include "gu_tests++.hpp" int main(int argc, char* argv[]) { bool no_fork = (argc >= 2 && std::string(argv[1]) == "nofork"); FILE* log_file = 0; if (!no_fork) { log_file = fopen (LOG_FILE, "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); int failed = 0; for (int i = 0; suites[i] != 0; ++i) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all(sr, CK_NORMAL); failed += srunner_ntests_failed(sr); srunner_free(sr); } if (log_file != 0) fclose(log_file); printf ("Total tests failed: %d\n", failed); return failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } percona-galera-3-3.8-3390/galerautils/tests/gu_tests++.hpp000066400000000000000000000021261244131713600231550ustar00rootroot00000000000000// Copyright (C) 2009-2014 Codership Oy // $Id$ /*! * @file: package specific part of the main test file. */ #ifndef __gu_testspp_hpp__ #define __gu_testspp_hpp__ #define LOG_FILE "gu_tests++.log" #include "gu_atomic_test.hpp" #include "gu_vector_test.hpp" #include "gu_string_test.hpp" #include "gu_vlq_test.hpp" #include "gu_digest_test.hpp" #include "gu_mem_pool_test.hpp" #include "gu_alloc_test.hpp" #include "gu_rset_test.hpp" #include "gu_string_utils_test.hpp" #include "gu_uri_test.hpp" #include "gu_config_test.hpp" #include "gu_net_test.hpp" #include "gu_datetime_test.hpp" #include "gu_histogram_test.hpp" #include "gu_stats_test.hpp" typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gu_atomic_suite, gu_vector_suite, gu_string_suite, gu_vlq_suite, gu_digest_suite, gu_mem_pool_suite, gu_alloc_suite, gu_rset_suite, gu_string_utils_suite, gu_uri_suite, gu_config_suite, gu_net_suite, gu_datetime_suite, gu_histogram_suite, gu_stats_suite, 0 }; #endif /* __gu_testspp_hpp__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_tests.c000066400000000000000000000034531244131713600224660ustar00rootroot00000000000000// Copyright (C) 2007-2012 Codership Oy // $Id$ #include // printf() #include // strcmp() #include // EXIT_SUCCESS | EXIT_FAILURE #include #include "../src/gu_conf.h" #include "gu_mem_test.h" #include "gu_vec_test.h" #include "gu_bswap_test.h" #include "gu_fnv_test.h" #include "gu_mmh3_test.h" #include "gu_spooky_test.h" #include "gu_crc32c_test.h" #include "gu_hash_test.h" #include "gu_dbug_test.h" #include "gu_time_test.h" #include "gu_fifo_test.h" #include "gu_uuid_test.h" #include "gu_lock_step_test.h" #include "gu_str_test.h" #include "gu_utils_test.h" typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gu_mem_suite, gu_vec_suite, gu_bswap_suite, gu_fnv_suite, gu_mmh3_suite, gu_spooky_suite, gu_crc32c_suite, gu_hash_suite, gu_dbug_suite, gu_time_suite, gu_fifo_suite, gu_uuid_suite, gu_lock_step_suite, gu_str_suite, gu_utils_suite, NULL }; int main(int argc, char* argv[]) { int no_fork = ((argc > 1) && !strcmp(argv[1], "nofork")) ? 1 : 0; int i = 0; int failed = 0; FILE* log_file = NULL; if (!no_fork) { log_file = fopen ("gu_tests.log", "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); while (suites[i]) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all (sr, CK_NORMAL); failed += srunner_ntests_failed (sr); srunner_free (sr); i++; } if (log_file) { fclose (log_file); } printf ("Total tests failed: %d\n", failed); return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } percona-galera-3-3.8-3390/galerautils/tests/gu_time_test.c000066400000000000000000000015741244131713600233230ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "gu_time_test.h" #include "../src/gu_time.h" START_TEST (gu_time_test) { struct timeval left = { 1, 900000 }; // 1.9 sec struct timeval right = { 5, 400000 }; // 5.4 sec double diff, tolerance = 1.0e-15; // double precision tolerance diff = gu_timeval_diff (&left, &right); fail_if (fabs(3.5 + diff) > tolerance, "Expected %f, got %f, delta: %e", -3.5, diff, 3.5 + diff); diff = gu_timeval_diff (&right, &left); fail_if (fabs(3.5 - diff) > tolerance, "Expected %f, got %f, delta: %e", 3.5, diff, 3.5 - diff); } END_TEST Suite *gu_time_suite(void) { Suite *s = suite_create("Galera time functions"); TCase *tc = tcase_create("gu_time"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_time_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_time_test.h000066400000000000000000000002601244131713600233170ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_time_test__ #define __gu_time_test__ Suite *gu_time_suite(void); #endif /* __gu_time_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_to_test.c000066400000000000000000000220341244131713600230010ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include // printf() #include // strerror() #include // strtol(), exit(), EXIT_SUCCESS, EXIT_FAILURE #include // errno #include // gettimeofday() #include // usleep() #include #include struct thread_ctx { pthread_t thread; long thread_id; long stat_grabs; // how many times gcs_to_grab() was successful long stat_cancels;// how many times gcs_to_cancel() was called long stat_fails; // how many times gcs_to_grab() failed long stat_self; // how many times gcs_self_cancel() was called }; /* returns a semirandom number (hash) from seqno */ static inline ulong my_rnd (uint64_t x) { x = 2654435761U * x; // http://www.concentric.net/~Ttwang/tech/inthash.htm return (ulong)(x ^ (x >> 32)); // combine upper and lower halfs for better // randomness } /* whether to cancel self */ static inline ulong self_cancel (ulong rnd) { return !(rnd & 0xf); // will return TRUE once in 16 } /* how many other seqnos to cancel */ static inline ulong cancel (ulong rnd) { #if 0 // this causes probablity of conflict 88% // and average conflicts per seqno 3.5. Reveals a lot of corner cases return (rnd & 0x70) >> 4; // returns 0..7 #else // this is more realistic. // probability of conflict 25%, conflict rate 0.375 ulong ret = (rnd & 0x70) >> 4; // returns 0,0,0,0,0,0,1,2 if (gu_likely(ret < 5)) return 0; else return (ret - 5); #endif } /* offset of seqnos to cancel */ static inline ulong cancel_offset (ulong rnd) { return ((rnd & 0x700) >> 8) + 1; // returns 1 - 8 } static gu_to_t* to = NULL; static ulong thread_max = 16; // default number of threads static gu_seqno_t seqno_max = 1<<20; // default number of seqnos to check /* mutex to synchronize threads start */ static pthread_mutex_t start = PTHREAD_MUTEX_INITIALIZER; static const unsigned int t = 10; // optimal sleep time static const struct timespec tsleep = { 0, 10000000 }; // 10 ms void* run_thread(void* ctx) { struct thread_ctx* thd = ctx; gu_seqno_t seqno = thd->thread_id; // each thread starts with own offset // to guarantee uniqueness of seqnos // without having to lock mutex pthread_mutex_lock (&start); // wait for start signal pthread_mutex_unlock (&start); while (seqno < seqno_max) { long ret; ulong rnd = my_rnd(seqno); if (gu_unlikely(self_cancel(rnd))) { // printf("Self-cancelling %8llu\n", (unsigned long long)seqno); while ((ret = gu_to_self_cancel(to, seqno)) == -EAGAIN) usleep (t); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_self_cancel(%llu) returned %ld (%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } else { // printf ("Self-cancel success (%llu)\n", (unsigned long long)seqno); thd->stat_self++; } } else { // printf("Grabbing %8llu\n", (unsigned long long)seqno); while ((ret = gu_to_grab (to, seqno)) == -EAGAIN) nanosleep (&tsleep, NULL); if (gu_unlikely(ret)) { if (gu_likely(-ECANCELED == ret)) { // printf ("canceled (%llu)\n", (unsigned long long)seqno); thd->stat_fails++; } else { fprintf (stderr, "gu_to_grab(%llu) returned %ld (%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } } else { long cancels = cancel(rnd); // printf ("success (%llu), cancels = %ld\n", (unsigned long long)seqno, cancels); if (gu_likely(cancels)) { long offset = cancel_offset (rnd); gu_seqno_t cancel_seqno = seqno + offset; while (cancels-- && (cancel_seqno < seqno_max)) { ret = gu_to_cancel(to, cancel_seqno); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_cancel(%llu) by %llu " "failed: %s\n", (unsigned long long)cancel_seqno, (unsigned long long)seqno, strerror (-ret)); exit (EXIT_FAILURE); } else { // printf ("%llu canceled %llu\n", // seqno, cancel_seqno); cancel_seqno += offset; thd->stat_cancels++; } } } thd->stat_grabs++; ret = gu_to_release(to, seqno); if (gu_unlikely(ret)) { fprintf (stderr, "gu_to_release(%llu) failed: %ld(%s)\n", (unsigned long long)seqno, ret, strerror(-ret)); exit (EXIT_FAILURE); } } } seqno += thread_max; // this together with unique starting point // guarantees that seqnos are unique } // printf ("Thread %ld exiting. Last seqno = %llu\n", // thd->thread_id, (unsigned long long)(seqno - thread_max)); return NULL; } int main (int argc, char* argv[]) { // minimum to length required by internal logic ulong to_len = cancel(0xffffffff) * cancel_offset(0xffffffff); errno = 0; if (argc > 1) seqno_max = (1 << atol(argv[0])); if (argc > 2) thread_max = (1 << atol(argv[1])); if (errno) { fprintf (stderr, "Usage: %s [seqno [threads]]\nBoth seqno and threads" "are exponents of 2^n.\n", argv[0]); exit(errno); } printf ("Starting with %lu threads and %llu maximum seqno.\n", thread_max, (unsigned long long)seqno_max); /* starting with 0, enough space for all threads and cancels */ // 4 is a magic number to get it working without excessive sleep on amd64 to_len = to_len > thread_max ? to_len : thread_max; to_len *= 4; to = gu_to_create (to_len, 0); if (to != NULL) { printf ("Created TO monitor of length %lu\n", to_len); } else { exit (-ENOMEM); } /* main block */ { long i, ret; clock_t start_clock, stop_clock; double time_spent; struct thread_ctx thread[thread_max]; pthread_mutex_lock (&start); { /* initialize threads */ for (i = 0; i < thread_max; i++) { thread[i].thread_id = i; thread[i].stat_grabs = 0; thread[i].stat_cancels = 0; thread[i].stat_fails = 0; thread[i].stat_self = 0; ret = pthread_create(&(thread[i].thread), NULL, run_thread, &thread[i]); if (ret) { fprintf (stderr, "Failed to create thread %ld: %s", i, strerror(ret)); exit (EXIT_FAILURE); } } start_clock = clock(); } pthread_mutex_unlock (&start); // release threads /* wait for threads to complete and accumulate statistics */ pthread_join (thread[0].thread, NULL); for (i = 1; i < thread_max; i++) { pthread_join (thread[i].thread, NULL); thread[0].stat_grabs += thread[i].stat_grabs; thread[0].stat_cancels += thread[i].stat_cancels; thread[0].stat_fails += thread[i].stat_fails; thread[0].stat_self += thread[i].stat_self; } stop_clock = clock(); time_spent = gu_clock_diff (stop_clock,start_clock); /* print statistics */ printf ("%llu seqnos in %.3f seconds (%.3f seqno/sec)\n", (unsigned long long)seqno_max, time_spent, ((double) seqno_max)/time_spent); printf ("Overhead at 10000 actions/second: %.2f%%\n", (time_spent * 10000 * 100/* for % */)/seqno_max); printf ("Grabbed: %9lu\n" "Failed: %9lu\n" "Self-cancelled: %9lu\n" "Canceled: %9lu (can exceed total number of seqnos)\n", thread[0].stat_grabs, thread[0].stat_fails, thread[0].stat_self, thread[0].stat_cancels ); if (seqno_max != (thread[0].stat_grabs+thread[0].stat_fails+thread[0].stat_self)) { fprintf (stderr, "Error: total number of grabbed, failed and " "self-cancelled waiters does not match total seqnos.\n"); exit (EXIT_FAILURE); } } return 0; } percona-galera-3-3.8-3390/galerautils/tests/gu_uri_test.cpp000066400000000000000000000313571244131713600235260ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #include #include #include "../src/gu_uri.hpp" #include "../src/gu_exception.hpp" #include "../src/gu_logger.hpp" #include "gu_uri_test.hpp" using std::string; using std::pair; using gu::URI; using gu::URIQueryList; using gu::NotSet; using gu::NotFound; using gu::Exception; START_TEST (uri_test1) // checking normal URI { const string scheme("scheme"); const string user ("user:pswd"); const string host ("[::ffff:192.168.0.1]"); // IPv4 over IPv6 const string port ("4567"); const string path ("/path1/path2"); const string opt1 ("opt1"); const string val1 ("val1"); const string opt2 ("opt2"); const string val2 ("val2"); const string query (opt1 + '=' + val1 + '&' + opt2 + '=' + val2); const string frag ("frag"); string auth = user + "@" + host + ":" + port; string uri_str = scheme + "://" + auth + path + "?" + query + "#" + frag; try { URI uri(uri_str); try { fail_if (scheme != uri.get_scheme(), "Scheme '%s' != '%s'", scheme.c_str(), uri.get_scheme().c_str()); } catch (NotSet&) { fail ("Scheme not set in '%s'", uri_str.c_str()); } try { fail_if (user != uri.get_user(), "User info '%s' != '%s'", user.c_str(), uri.get_user().c_str()); } catch (NotSet&) { fail ("User info not set in '%s'", uri_str.c_str()); } try { fail_if (host != uri.get_host(), "Host '%s' != '%s'", host.c_str(), uri.get_host().c_str()); } catch (NotSet&) { fail ("Host not set in '%s'", uri_str.c_str()); } try { fail_if (port != uri.get_port(), "Port '%s' != '%s'", port.c_str(), uri.get_port().c_str()); } catch (NotSet&) { fail ("Port not set in '%s'", uri_str.c_str()); } try { fail_if (path != uri.get_path(), "Path '%s' != '%s'", path.c_str(), uri.get_path().c_str()); } catch (NotSet&) { fail ("Path not set in '%s'", uri_str.c_str()); } try { fail_if (frag != uri.get_fragment(), "Fragment '%s' != '%s'", frag.c_str(), uri.get_fragment().c_str()); } catch (NotSet&) { fail ("Fragment not set in '%s'", uri_str.c_str()); } try { fail_if (auth != uri.get_authority(), "Authority '%s' != '%s'", auth.c_str(), uri.get_authority().c_str()); } catch (NotSet&) { fail ("Authority not set in '%s'", uri_str.c_str()); } URIQueryList ql = uri.get_query_list(); fail_if (ql.size() != 2, "Query list size %zu, expected 2", ql.size()); URIQueryList::const_iterator i = ql.begin(); fail_if (i->first != opt1, "got option '%s', expected '%s'", i->first.c_str(), opt1.c_str()); fail_if (i->second != val1, "got value '%s', expected '%s'", i->second.c_str(), val1.c_str()); ++i; fail_if (i->first != opt2, "got option '%s', expected '%s'", i->first.c_str(), opt2.c_str()); fail_if (i->second != val2, "got value '%s', expected '%s'", i->second.c_str(), val2.c_str()); fail_if (val1 != uri.get_option(opt1)); fail_if (val2 != uri.get_option(opt2)); try { uri.get_option("xxx"); fail ("Expected NotFound exception"); } catch (NotFound&) {} URI simple ("gcomm+pc://192.168.0.1"); } catch (Exception& e) { fail (e.what()); } } END_TEST START_TEST (uri_test2) // checking corner cases { #ifdef NDEBUG try { URI uri(""); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("scheme:"); } catch (Exception& e) { fail ("URI should be valid."); } mark_point(); #ifdef NDEBUG try { URI uri(":path"); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("a://b:c?d=e#f"); fail ("URI should have failed."); } catch (Exception& e) {} mark_point(); try { URI uri("a://b:99999?d=e#f"); fail ("URI should have failed."); } catch (Exception& e) {} mark_point(); #ifdef NDEBUG try { URI uri("?query"); fail ("URI should have failed."); } catch (Exception& e) {} #endif mark_point(); try { URI uri("scheme:path"); try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_host(); fail ("Host should be unset"); } catch (NotSet&) {} try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} try { uri.get_authority(); fail ("Authority should be unset"); } catch (NotSet&) {} try { uri.get_fragment(); fail ("Fragment should be unset"); } catch (NotSet&) {} fail_if (uri.get_query_list().size() != 0, "Query list must be empty"); } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme:///path"); try { fail_if (uri.get_authority() != ""); } catch (NotSet&) { fail ("Authority should be set"); } try { uri.get_host(); fail("Host should be unset"); } catch (NotSet&) { } try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} try { fail_if (uri.get_path().length() != 5); } catch (NotSet&) { fail ("Path should be 5 characters long"); } } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://@/path"); try { fail_if (uri.get_authority() != "@"); } catch (NotSet&) { fail ("Authority should be set"); } try { fail_if (uri.get_user() != ""); } catch (NotSet&) { fail ("User should be set"); } try { fail_if (uri.get_host() != ""); } catch (NotSet&) { fail ("Host should be set"); } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://@:/path"); try { fail_if (uri.get_authority() != "@"); } catch (NotSet&) { fail ("Authority should be set"); } try { fail_if (uri.get_user() != ""); } catch (NotSet&) { fail ("User should be set"); } try { fail_if (uri.get_host() != ""); } catch (NotSet&) { fail ("Host should be set"); } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} } catch (Exception& e) { fail (e.what()); } mark_point(); try { URI uri("scheme://"); try { fail_if (uri.get_authority() != ""); } catch (NotSet&) { fail ("Authority should be set"); } try { uri.get_user(); fail ("User should be unset"); } catch (NotSet&) {} try { uri.get_host(); fail("Host should be unset"); } catch (NotSet&) { } try { uri.get_port(); fail ("Port should be unset"); } catch (NotSet&) {} // According to http://tools.ietf.org/html/rfc3986#section-3.3 try { fail_if (uri.get_path() != ""); } catch (NotSet&) { fail ("Path should be set to empty"); } } catch (Exception& e) { fail (e.what()); } } END_TEST START_TEST (uri_test3) // Test from gcomm { #ifdef NDEBUG try { URI too_simple("http"); fail("too simple accepted"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } #endif URI empty_auth("http://"); fail_unless(empty_auth.get_scheme() == "http"); fail_unless(empty_auth.get_authority() == ""); URI simple_valid1("http://example.com"); fail_unless(simple_valid1.get_scheme() == "http"); fail_unless(simple_valid1.get_authority() == "example.com"); fail_unless(simple_valid1.get_path() == ""); fail_unless(simple_valid1.get_query_list().size() == 0); URI with_path("http://example.com/path/to/file.html"); fail_unless(with_path.get_scheme() == "http"); fail_unless(with_path.get_authority() == "example.com"); fail_unless(with_path.get_path() == "/path/to/file.html"); fail_unless(with_path.get_query_list().size() == 0); URI with_query("http://example.com?key1=val1&key2=val2"); fail_unless(with_query.get_scheme() == "http"); fail_unless(with_query.get_authority() == "example.com"); fail_unless(with_query.get_path() == ""); const URIQueryList& qlist = with_query.get_query_list(); fail_unless(qlist.size() == 2); URIQueryList::const_iterator i; i = qlist.find("key1"); fail_unless(i != qlist.end() && i->second == "val1"); i = qlist.find("key2"); fail_unless(i != qlist.end() && i->second == "val2"); URI with_uri_in_query("gcomm+gmcast://localhost:10001?gmcast.node=gcomm+tcp://localhost:10002&gmcast.node=gcomm+tcp://localhost:10003"); fail_unless(with_uri_in_query.get_scheme() == "gcomm+gmcast"); fail_unless(with_uri_in_query.get_authority() == "localhost:10001"); const URIQueryList& qlist2 = with_uri_in_query.get_query_list(); fail_unless(qlist2.size() == 2); pair ii; ii = qlist2.equal_range("gmcast.node"); fail_unless(ii.first != qlist2.end()); for (i = ii.first; i != ii.second; ++i) { fail_unless(i->first == "gmcast.node"); URI quri(i->second); fail_unless(quri.get_scheme() == "gcomm+tcp"); fail_unless(quri.get_authority().substr(0, string("localhost:1000").size()) == "localhost:1000"); } try { URI invalid1("http://example.com/?key1"); fail("invalid query accepted"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST START_TEST(uri_non_strict) { std::string const ip("1.2.3.4"); std::string const port("789"); std::string const addr(ip + ':' + port); try { URI u(ip); fail("Strict mode passed without scheme"); } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL, "Expected errno %d, got %d", EINVAL, e.get_errno()); } try { URI u(addr, false); fail_if (u.get_host() != ip); fail_if (u.get_port() != port); try { u.get_scheme(); fail("Scheme is '%s', should be unset", u.get_scheme().c_str()); } catch (gu::NotSet&) {} } catch (gu::Exception& e) { fail_if (e.get_errno() != EINVAL); } } END_TEST START_TEST(uri_test_multihost) { try { gu::URI uri("tcp://host1,host2"); fail_unless(uri.get_authority_list().size() == 2); try { uri.get_authority_list()[0].user(); fail("User should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[0].host() == "host1"); try { uri.get_authority_list()[0].port(); fail("Port should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[1].host() == "host2"); } catch (gu::Exception& e) { fail(e.what()); } try { gu::URI uri("tcp://host1:1234,host2:,host3:3456"); fail_unless(uri.get_authority_list().size() == 3); try { uri.get_authority_list()[0].user(); fail("User should not be set"); } catch (NotSet&) { } fail_unless(uri.get_authority_list()[0].host() == "host1"); fail_unless(uri.get_authority_list()[0].port() == "1234"); fail_unless(uri.get_authority_list()[1].host() == "host2"); } catch (gu::Exception& e) { fail(e.what()); } } END_TEST Suite *gu_uri_suite(void) { Suite *s = suite_create("galerautils++ URI"); TCase *tc = tcase_create("URI"); suite_add_tcase (s, tc); tcase_add_test (tc, uri_test1); tcase_add_test (tc, uri_test2); tcase_add_test (tc, uri_test3); tcase_add_test (tc, uri_non_strict); tcase_add_test (tc, uri_test_multihost); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_uri_test.hpp000066400000000000000000000003071244131713600235220ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gu_uri_test__ #define __gu_uri_test__ #include extern Suite *gu_uri_suite(void); #endif /* __gu_uri_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_utils_test.c000066400000000000000000000057061244131713600235260ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy // $Id$ #include #include "gu_utils_test.h" #include "../src/gu_utils.h" #include #include START_TEST (gu_strconv_test) { long long llret; const char* strret; strret = gu_str2ll ("-1a", &llret); fail_if (strret[0] != 'a'); fail_if (-1 != llret); strret = gu_str2ll ("1K", &llret); fail_if (strret[0] != '\0'); fail_if ((1 << 10) != llret); strret = gu_str2ll ("-1m", &llret); fail_if (strret[0] != '\0'); fail_if (-(1 << 20) != llret); strret = gu_str2ll ("354G0", &llret); fail_if (strret[0] != '0'); fail_if ((354LL << 30) != llret); strret = gu_str2ll ("0m", &llret); fail_if (strret[0] != '\0'); fail_if (0 != llret); strret = gu_str2ll ("-999999999999999g", &llret); fail_if (strret[0] != '\0'); fail_if (LLONG_MIN != llret); bool b; strret = gu_str2bool ("-1a", &b); fail_if (strret[0] != '-'); fail_if (false != b); strret = gu_str2bool ("-1", &b); fail_if (strret[0] != '-'); fail_if (false != b); strret = gu_str2bool ("1a", &b); fail_if (strret[0] != '1'); fail_if (false != b); strret = gu_str2bool ("35", &b); fail_if (strret[0] != '3'); fail_if (false != b); strret = gu_str2bool ("0k", &b); fail_if (strret[0] != '0'); fail_if (false != b); strret = gu_str2bool ("1", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("0", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("Onn", &b); fail_if (strret[0] != 'O'); fail_if (false != b); strret = gu_str2bool ("oFf", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("offt", &b); fail_if (strret[0] != 'o'); fail_if (false != b); strret = gu_str2bool ("On", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("tru", &b); fail_if (strret[0] != 't'); fail_if (false != b); strret = gu_str2bool ("trUE", &b); fail_if (strret[0] != '\0'); fail_if (true != b); strret = gu_str2bool ("truEth", &b); fail_if (strret[0] != 't'); fail_if (false != b); strret = gu_str2bool (" fALsE", &b); fail_if (strret[0] != ' '); fail_if (false != b); strret = gu_str2bool ("fALsE", &b); fail_if (strret[0] != '\0'); fail_if (false != b); strret = gu_str2bool ("fALsEth", &b); fail_if (strret[0] != 'f'); fail_if (false != b); void* ptr; strret = gu_str2ptr ("-01234abc", &ptr); fail_if (strret[0] != '\0'); fail_if (-0x1234abcLL != (intptr_t)ptr, "Expected %lld, got %lld", -0x1234abcLL, (intptr_t)ptr); } END_TEST Suite *gu_utils_suite(void) { Suite *s = suite_create("Galera misc utils functions"); TCase *tc = tcase_create("gu_utils"); suite_add_tcase (s, tc); tcase_add_test (tc, gu_strconv_test); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_utils_test.h000066400000000000000000000002641244131713600235250ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy // $Id$ #ifndef __gu_utils_test__ #define __gu_utils_test__ Suite *gu_utils_suite(void); #endif /* __gu_utils_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_uuid_test.c000066400000000000000000000021471244131713600233300ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include #include "../src/gu_log.h" #include "../src/gu_uuid.h" #include "gu_uuid_test.h" START_TEST (gu_uuid_test) { size_t uuid_num = 10; gu_uuid_t uuid[uuid_num]; size_t i; uuid[0] = GU_UUID_NIL; gu_uuid_generate (&uuid[0], NULL, 0); fail_if (!memcmp (&uuid[0], &GU_UUID_NIL, sizeof(gu_uuid_t))); fail_if (!gu_uuid_compare(&uuid[0], &GU_UUID_NIL)); for (i = 1; i < uuid_num; i++) { uuid[i] = GU_UUID_NIL; gu_uuid_generate (&uuid[i], NULL, 0); fail_if (!gu_uuid_compare(&uuid[i], &GU_UUID_NIL)); fail_if (!gu_uuid_compare(&uuid[i], &uuid[i - 1])); fail_if (1 != gu_uuid_older (&uuid[i - 1], &uuid[i])); fail_if (-1 != gu_uuid_older (&uuid[i], &uuid[i - 1])); } } END_TEST Suite *gu_uuid_suite(void) { Suite *suite = suite_create("Galera UUID utils"); TCase *tcase = tcase_create("gu_uuid"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gu_uuid_test); return suite; } percona-galera-3-3.8-3390/galerautils/tests/gu_uuid_test.h000066400000000000000000000003001244131713600233220ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gu_uuid_test__ #define __gu_uuid_test__ extern Suite *gu_uuid_suite(void); #endif /* __gu_uuid_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_vec_test.c000066400000000000000000000017151244131713600231370ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "gu_vec_test.h" #include "../src/gu_vec16.h" START_TEST (vec16_test) { gu_vec16_t v1 = gu_vec16_from_byte (0); gu_vec16_t v2 = gu_vec16_from_byte (0); gu_vec16_t v3 = gu_vec16_from_byte (7); fail_if (!gu_vec16_eq(v1, v2)); fail_if (gu_vec16_eq(v1, v3)); unsigned char a1[16], a2[16], a3[16]; fail_if (sizeof(v1) != sizeof(a1)); unsigned int i; for (i = 0; i < sizeof(a1); i++) { a1[i] = i; a2[i] = i * i; a3[i] = a1[i] ^ a2[i]; } v1 = gu_vec16_from_ptr (a1); v2 = gu_vec16_from_ptr (a2); fail_if (gu_vec16_eq(v1, v2)); v3 = gu_vec16_xor (v1, v2); fail_if (memcmp (&v3, a3, sizeof(a3))); } END_TEST Suite* gu_vec_suite(void) { TCase* t = tcase_create ("vec16"); tcase_add_test (t, vec16_test); Suite* s = suite_create ("Vector math"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_vec_test.h000066400000000000000000000003141244131713600231360ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_vec_test__ #define __gu_vec_test__ #include extern Suite *gu_vec_suite(void); #endif /* __gu_vec_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_vector_test.cpp000066400000000000000000000024651244131713600242270ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #include "../src/gu_vector.hpp" #include "gu_vector_test.hpp" START_TEST (simple_test) { // we are not to test the whole vector functionality, it is provided // by incorporated std::vector. We just need to see that allocator // works as expected gu::Vector v1; v1->reserve(12); fail_if (v1->size() != 0); v1->push_back(12); fail_if (v1->size() != 1); v1->resize(11); fail_if (v1->size() != 11); fail_if (v1.in_heap() != false); v1[10]=1; fail_if (v1[10] != v1()[10]); gu::Vector v2(v1); fail_if (v2->size() != v1->size()); fail_if (v1[10] != v2[10]); fail_if (&v1[10] == &v2[10]); v2[10]=2; fail_if (v1[10] == v2[10]); v2() = v1(); fail_if (v1[10] != v2[10]); fail_if (&v1[0] == &v2[0]); fail_if (v2.in_heap() != false); v2->resize(32); fail_if (v2.in_heap() != true); fail_if (v1.in_heap() != false); v2[25]=1; v1->resize(32); fail_if (v1.in_heap() != true); v1[25]=2; fail_if (v1[25] == v2[25]); } END_TEST Suite* gu_vector_suite(void) { TCase* t = tcase_create ("simple_test"); tcase_add_test (t, simple_test); Suite* s = suite_create ("gu::Vector"); suite_add_tcase (s, t); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_vector_test.hpp000066400000000000000000000003311244131713600242220ustar00rootroot00000000000000/* Copyright (C) 2013 Codership Oy * * $Id$ */ #ifndef __gu_vector_test__ #define __gu_vector_test__ #include extern Suite *gu_vector_suite(void); #endif /* __gu_vector_test__ */ percona-galera-3-3.8-3390/galerautils/tests/gu_vlq_test.cpp000066400000000000000000000201601244131713600235170ustar00rootroot00000000000000// // Copyright (C) 2011 Codership Oy // #include "gu_vlq.hpp" #include "gu_vlq_test.hpp" #include "gu_logger.hpp" #include #include #include #include #include static struct valval { const unsigned long long val; const size_t size; } valarr[] = { {0x00 , 1}, {0x01 , 1}, {0x7fULL , 1}, {0x80ULL , 2}, {0x3fffULL , 2}, {0x4000ULL , 3}, {0x1fffffULL , 3}, {0x200000ULL , 4}, {0x0fffffffULL , 4}, {0x10000000ULL , 5}, {0x07ffffffffULL , 5}, {0x0800000000ULL , 6}, {0x03ffffffffffULL , 6}, {0x040000000000ULL , 7}, {0x01ffffffffffffULL , 7}, {0x02000000000000ULL , 8}, {0x00ffffffffffffffULL, 8}, {0x0100000000000000ULL, 9}, {0x7fffffffffffffffULL, 9}, {0x8000000000000000ULL, 10}, {0xffffffffffffffffULL, 10} }; // http://www.cplusplus.com/faq/sequences/arrays/sizeof-array/ template inline size_t SizeOfArray( const T(&)[ N ] ) { return N; } START_TEST(test_uleb128_size) { for (size_t i(0); i < SizeOfArray(valarr); ++i) { size_t size(gu::uleb128_size(valarr[i].val)); fail_unless(size == valarr[i].size, "got size %z, expected %z for value 0x%llx", size, valarr[i].size, valarr[i].val); } } END_TEST START_TEST(test_uleb128_encode) { std::vector buf; for (size_t i(0); i < SizeOfArray(valarr); ++i) { buf.resize(valarr[i].size); size_t offset(gu::uleb128_encode(valarr[i].val, &buf[0], buf.size(), 0)); fail_unless(offset == valarr[i].size, "got offset %zu, expected %zu for value 0x%llx", offset, valarr[i].size, valarr[i].val); } } END_TEST START_TEST(test_uleb128_decode) { std::vector buf; for (size_t i(0); i < SizeOfArray(valarr); ++i) { buf.resize(valarr[i].size); size_t offset(gu::uleb128_encode(valarr[i].val, &buf[0], buf.size(), 0)); unsigned long long val; try { offset = gu::uleb128_decode(&buf[0], buf.size(), 0, val); fail_unless(offset == valarr[i].size, "got offset %zu, expected %zu for value 0x%llx", offset, valarr[i].size, valarr[i].val); fail_unless(val == valarr[i].val, "got value 0x%llx, expected 0x%llx", val, valarr[i].val); } catch (gu::Exception& e) { fail("Exception in round %zu for encoding of size %zu: %s", i, valarr[i].size, e.what()); } } } END_TEST START_TEST(test_uleb128_misc) { std::vector buf(10); // check uint8_t whole range for (size_t i(0); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint8_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uint16_t whole range for (size_t i(0); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint16_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uint32_t: 0 -> 1^20 for (size_t i(0); i < (1 << 20); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint32_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // check uin32_t: max - 1^20 -> max for (uint64_t i(std::numeric_limits::max() - (1 << 20)); i <= std::numeric_limits::max(); ++i) { (void)gu::uleb128_encode(static_cast(i), &buf[0], buf.size(), 0); uint32_t val; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val); if (i != val) fail("0x%x != 0x%x", i, val); } // uint64_t is tested for representation byte boundaries earlier, // run test just for random values for (size_t i(0); i < (1 << 16); ++i) { unsigned long long val(static_cast(rand()) * static_cast(rand())); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); unsigned long long val2; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, val2); if (val != val2) fail("0x%llx != 0x%llx", val, val2); } { // check that exception is thrown if target type is not // wide enough // uint8_t uint64_t val(static_cast(std::numeric_limits::max()) + 1); buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint8_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // uint16_t val = static_cast(std::numeric_limits::max()) + 1; buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint16_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // uint32_t val = static_cast(std::numeric_limits::max()) + 1; buf.resize(gu::uleb128_size(val)); (void)gu::uleb128_encode(val, &buf[0], buf.size(), 0); try { uint32_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // check that exception is thrown if terminating byte is missing buf.resize(buf.size() - 1); try { uint64_t cval; (void)gu::uleb128_decode(&buf[0], buf.size(), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } // finally check the representation that cannot be stored with // uint64_t gu::byte_t b[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, // <--- up here 9 * 7 = 63 bits 0x02}; // <--- requires two additional bits try { uint64_t cval; (void)gu::uleb128_decode(b, SizeOfArray(b), 0, cval); fail("exception was not thrown"); } catch (gu::Exception& e) { log_info << "expected exception: " << e.what(); } } } END_TEST Suite* gu_vlq_suite() { Suite* s(suite_create("gu::vlq")); TCase* tc; tc = tcase_create("test_uleb128_size"); tcase_add_test(tc, test_uleb128_size); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_encode"); tcase_add_test(tc, test_uleb128_encode); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_decode"); tcase_add_test(tc, test_uleb128_decode); suite_add_tcase(s, tc); tc = tcase_create("test_uleb128_misc"); tcase_add_test(tc, test_uleb128_misc); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/galerautils/tests/gu_vlq_test.hpp000066400000000000000000000002661244131713600235310ustar00rootroot00000000000000// // Copyright (C) 2011 Codership Oy // #ifndef GU_VLQ_TEST_HPP #define GU_VLQ_TEST_HPP #include Suite* gu_vlq_suite(); #endif // GU_VLQ_TEST_HPP percona-galera-3-3.8-3390/garb/000077500000000000000000000000001244131713600157155ustar00rootroot00000000000000percona-galera-3-3.8-3390/garb/SConscript000066400000000000000000000027011244131713600177270ustar00rootroot00000000000000# Copyright (C) 2011 Codership Oy Import('env', 'libboost_program_options', 'static_ssl', 'with_ssl') garb_env = env.Clone() garb_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) garb_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) garb_env.Prepend(LIBS=File('#/gcomm/src/libgcomm.a')) garb_env.Prepend(LIBS=File('#/gcs/src/libgcs4garb.a')) if libboost_program_options: garb_env.Append(LIBS=libboost_program_options) # special environment for garb_config.cpp conf_env = garb_env.Clone() Import('GALERA_VER', 'GALERA_REV') conf_env.Append(CPPFLAGS = ' -DGALERA_VER=\\"' + GALERA_VER + '\\"') conf_env.Append(CPPFLAGS = ' -DGALERA_REV=\\"' + GALERA_REV + '\\"') if static_ssl == 1: garb_env.Append(LIBPATH = [with_ssl]) garb_env.Append(LIBS=File('%s/libssl.a' %(with_ssl))) garb_env.Append(LIBS=File('%s/libcrypto.a' %(with_ssl))) garb_env.Append(LIBS=File('%s/libz.a' %(with_ssl))) garb_env.Append(LIBS=['dl']) garb = garb_env.Program(target = 'garbd', source = Split(''' garb_logger.cpp garb_gcs.cpp garb_recv_loop.cpp garb_main.cpp ''') + conf_env.SharedObject(['garb_config.cpp']) ) percona-galera-3-3.8-3390/garb/files/000077500000000000000000000000001244131713600170175ustar00rootroot00000000000000percona-galera-3-3.8-3390/garb/files/freebsd/000077500000000000000000000000001244131713600204315ustar00rootroot00000000000000percona-galera-3-3.8-3390/garb/files/freebsd/garb.sh000066400000000000000000000061771244131713600217130ustar00rootroot00000000000000#!/bin/sh # # garb.sh for rc.d usage (c) 2013 Codership Oy # $Id$ # PROVIDE: garb # REQUIRE: LOGIN # KEYWORD: shutdown # # Add the following line to /etc/rc.conf to enable Galera Arbitrator Daemon (garbd): # garb_enable (bool): Set to "NO" by default. # Set it to "YES" to enable Galera Arbitrator Daemon. # garb_galera_nodes (str): A space-separated list of node addresses (address[:port]) in the cluster # (default empty). # garb_galera_group (str): Galera cluster name, should be the same as on the rest of the nodes. # (default empty). # Optional: # garb_galera_options (str): Optional Galera internal options string (e.g. SSL settings) # see http://www.codership.com/wiki/doku.php?id=galera_parameters # (default empty). # garb_log_file (str): Log file for garbd (default empty). Optional, by default logs to syslog # garb_pid_file (str): Custum PID file path and name. # Default to "/var/run/garb.pid". # . /etc/rc.subr name="garb" rcvar=garb_enable load_rc_config $name # set defaults : ${garb_enable="NO"} : ${garb_galera_nodes=""} : ${garb_galera_group=""} : ${garb_galera_options=""} : ${garb_log_file=""} : ${garb_pid_file="/var/run/garb.pid"} procname="/usr/local/bin/garbd" command="/usr/sbin/daemon" command_args="-c -f -u nobody -p $garb_pid_file $procname" start_precmd="${name}_prestart" #start_cmd="${name}_start" start_postcmd="${name}_poststart" stop_precmd="${name}_prestop" #stop_cmd="${name}_stop" #stop_postcmd="${name}_poststop" #extra_commands="reload" #reload_cmd="${name}_reload" export LD_LIBRARY_PATH=/usr/local/lib/gcc44 garb_prestart() { [ "$(id -ur)" != "0" ] && err 4 "root rights are required to start $name" [ -r "$garb_pid_file" ] && err 0 "$procname is already running with PID $(cat $garb_pid_file)" [ -x "$procname" ] || err 5 "$procname is not found" # check that node addresses are configured [ -z "$garb_galera_nodes" ] && err 6 "List of garb_galera_nodes is not configured" [ -z "$garb_galera_group" ] && err 6 "garb_galera_group name is not configured" GALERA_PORT=${GALERA_PORT:-4567} # Find a working node for ADDRESS in ${garb_galera_nodes} 0; do HOST=$(echo $ADDRESS | cut -d \: -f 1) PORT=$(echo $ADDRESS | cut -d \: -f 2) PORT=${PORT:-$GALERA_PORT} nc -z $HOST $PORT >/dev/null 2>&1 && break done [ ${ADDRESS} == "0" ] && err 1 "None of the nodes in $garb_galera_nodes is accessible" command_args="$command_args -a gcomm://$ADDRESS" [ -n "$garb_galera_group" ] && command_args="$command_args -g $garb_galera_group" [ -n "$garb_galera_options" ] && command_args="$command_args -o $garb_galera_options" [ -n "$garb_log_file" ] && command_args="$command_args -l $garb_log_file" return 0 } garb_poststart() { local timeout=15 while [ ! -f "$garb_pid_file" -a $timeout -gt 0 ]; do timeout=$(( timeout - 1 )) sleep 1 done return 0 } garb_prestop() { [ "$(id -ur)" != "0" ] && err 4 "root rights are required to stop $name" [ -r $garb_pid_file ] || err 0 "" return 0 } run_rc_command "$1" percona-galera-3-3.8-3390/garb/files/garb-systemd000077500000000000000000000032431244131713600213500ustar00rootroot00000000000000#!/bin/bash -ue # config=/etc/sysconfig/garb log_failure() { echo " ERROR! $@" } program_start() { echo "Starting garbd" /usr/bin/garbd $* } start() { if grep -q -E '^# REMOVE' $config;then log_failure "Garbd config $config is not configured yet" return 0 fi # Check that node addresses are configured if [[ -z "${GALERA_NODES:-}" ]]; then log_failure "List of GALERA_NODES is not configured" return 6 fi if [[ -z "${GALERA_GROUP:-}" ]]; then log_failure "GALERA_GROUP name is not configured" return 6 fi GALERA_PORT=${GALERA_PORT:-4567} # Find a working node for ADDRESS in ${GALERA_NODES} 0; do HOST=$(echo $ADDRESS | cut -d \: -f 1 ) PORT=$(echo $ADDRESS | cut -s -d \: -f 2 ) PORT=${PORT:-$GALERA_PORT} if [[ -x `which nc` ]] && nc -h 2>&1 | grep -q -- '-z';then nc -z $HOST $PORT >/dev/null && break elif [[ -x `which nmap` ]];then nmap -Pn -p$PORT $HOST | awk "\$1 ~ /$PORT/ {print \$2}" | grep -q open && break else log_failure "Neither netcat nor nmap are present for zero I/O scanning" return 1 fi done if [ ${ADDRESS} == "0" ]; then log_failure "None of the nodes in $GALERA_NODES is accessible" return 1 fi OPTIONS=" -a gcomm://$ADDRESS " [ -n "${GALERA_GROUP:-}" ] && OPTIONS="$OPTIONS -g $GALERA_GROUP" [ -n "${GALERA_OPTIONS:-}" ] && OPTIONS="$OPTIONS -o $GALERA_OPTIONS" [ -n "${LOG_FILE:-}" ] && OPTIONS="$OPTIONS -l $LOG_FILE" program_start $OPTIONS } # See how we were called. case "$1" in start) start ;; *) echo $"Usage: $0 {start}" exit 2 esac exit $? percona-galera-3-3.8-3390/garb/files/garb.cnf000066400000000000000000000011341244131713600204210ustar00rootroot00000000000000# Copyright (C) 2012 Codership Oy # This config file is to be sourced by garb service script. # REMOVE THIS AFTER CONFIGURATION # A space-separated list of node addresses (address[:port]) in the cluster # GALERA_NODES="" # Galera cluster name, should be the same as on the rest of the nodes. # GALERA_GROUP="" # Optional Galera internal options string (e.g. SSL settings) # see http://www.codership.com/wiki/doku.php?id=galera_parameters # GALERA_OPTIONS="" # Log file for garbd. Optional, by default logs to syslog # Deprecated for CentOS7, use journalctl to query the log for garbd # LOG_FILE="" percona-galera-3-3.8-3390/garb/files/garb.service000066400000000000000000000004561244131713600213210ustar00rootroot00000000000000# Systemd service file for garbd [Unit] Description=Galera Arbitrator Daemon After=network.target syslog.target [Install] WantedBy=multi-user.target Alias=garbd.service [Service] User=nobody EnvironmentFile=/etc/sysconfig/garb ExecStart=/usr/bin/garb-systemd start TimeoutSec=2m PrivateTmp=false percona-galera-3-3.8-3390/garb/files/garb.sh000077500000000000000000000123661244131713600203010ustar00rootroot00000000000000#!/bin/bash # # Copyright (C) 2012-2013 Codership Oy # # init.d script for garbd # # chkconfig: - 99 01 # config: /etc/sysconfig/garb | /etc/default/garb # # Provides: garb # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Should-Start: $network $named $time # Should-Stop: $network $named $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Galera Arbitrator Daemon # Description: Garbd is used as part of clusters that have only two # real Galera servers and need an extra # node to arbitrate split brain situations. ### END INIT INFO # Source function library. if [ -f /etc/redhat-release ]; then . /etc/init.d/functions . /etc/sysconfig/network config=/etc/sysconfig/garb else . /lib/lsb/init-functions config=/etc/default/garbd fi log_failure() { if [ -f /etc/redhat-release ]; then echo -n $* failure "$*" echo else log_failure_msg "$*" fi } PIDFILE=/var/run/garbd prog="/usr/bin/garbd" program_start() { local rcode local gpid if [ -f /etc/redhat-release ]; then if [ -r $PIDFILE ];then gpid=$(cat $PIDFILE) echo -n $"Stale pid file found at $PIDFILE" if [[ -n ${gpid:-} ]] && kill -0 $gpid;then echo -n $"Garbd already running wiht PID $gpid" exit 17 else echo -n $"Removing stale pid file $PIDFILE" rm -f $PIDFILE fi fi echo -n $"Starting $prog: " runuser nobody -c "$prog $*" >/dev/null rcode=$? sleep 2 [ $rcode -eq 0 ] && pidof $prog > $PIDFILE \ && echo_success || echo_failure echo else if [ -r $PIDFILE ];then gpid=$(cat $PIDFILE) log_daemon_msg "Stale pid file found at $PIDFILE" if [[ -n ${gpid:-} ]] && kill -0 $gpid;then log_daemon_msg "Garbd already running wiht PID $gpid" exit 17 else log_daemon_msg "Removing stale pid file $PIDFILE" rm -f $PIDFILE fi fi if [ -r $PIDFILE ];then log_daemon_msg "Stale pid file with $(cat $PIDFILE)" fi log_daemon_msg "Starting $prog: " start-stop-daemon --start --quiet -c nobody --background \ --exec $prog -- $* rcode=$? # Hack: sleep a bit to give garbd some time to fork sleep 2 [ $rcode -eq 0 ] && pidof $prog > $PIDFILE log_end_msg $rcode fi return $rcode } program_stop() { local rcode if [ -f /etc/redhat-release ]; then echo -n $"Shutting down $prog: " killproc -p $PIDFILE rcode=$? [ $rcode -eq 0 ] && echo_success || echo_failure # echo else start-stop-daemon --stop --quiet --oknodo --retry TERM/30/KILL/5 \ --pidfile $PIDFILE rcode=$? log_end_msg $rcode fi [ $rcode -eq 0 ] && rm -f $PIDFILE return $rcode } program_status() { if [ -f /etc/redhat-release ]; then status $prog else status_of_proc -p $PIDFILE "$prog" garb fi } start() { [ "$EUID" != "0" ] && return 4 [ "$NETWORKING" = "no" ] && return 1 if grep -q -E '^# REMOVE' $config; then log_failure "Garbd config $config is not configured yet" return 0 fi if [ -r $PIDFILE ]; then log_failure "$prog is already running with PID $(cat ${PIDFILE})" return 3 # ESRCH fi [ -x $prog ] || return 5 [ -f $config ] && . $config # Check that node addresses are configured if [ -z "$GALERA_NODES" ]; then log_failure "List of GALERA_NODES is not configured" return 6 fi if [ -z "$GALERA_GROUP" ]; then log_failure "GALERA_GROUP name is not configured" return 6 fi GALERA_PORT=${GALERA_PORT:-4567} # Find a working node for ADDRESS in ${GALERA_NODES} 0; do HOST=$(echo $ADDRESS | cut -d \: -f 1 ) PORT=$(echo $ADDRESS | cut -s -d \: -f 2 ) PORT=${PORT:-$GALERA_PORT} if [[ -x `which nc` ]] && nc -h 2>&1 | grep -q -- '-z';then nc -z $HOST $PORT >/dev/null && break elif [[ -x `which nmap` ]];then nmap -Pn -p$PORT $HOST | awk "\$1 ~ /$PORT/ {print \$2}" | grep -q open && break else log_failure "Neither netcat nor nmap are present for zero I/O scanning" return 1 fi done if [ ${ADDRESS} == "0" ]; then log_failure "None of the nodes in $GALERA_NODES is accessible" return 1 fi OPTIONS="-d -a gcomm://$ADDRESS" [ -n "$GALERA_GROUP" ] && OPTIONS="$OPTIONS -g $GALERA_GROUP" [ -n "$GALERA_OPTIONS" ] && OPTIONS="$OPTIONS -o $GALERA_OPTIONS" [ -n "$LOG_FILE" ] && OPTIONS="$OPTIONS -l $LOG_FILE" program_start $OPTIONS } stop() { [ "$EUID" != "0" ] && return 4 [ -r $PIDFILE ] || return 3 # ESRCH program_stop } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) program_status ;; restart|reload|force-reload) restart ;; condrestart) if status $prog > /dev/null; then stop start fi ;; *) echo $"Usage: $0 {start|stop|status|restart|reload}" exit 2 esac exit 0 percona-galera-3-3.8-3390/garb/files/garbd.troff000066400000000000000000000035501244131713600211430ustar00rootroot00000000000000.\" Process this file with .\" groff -man -Tascii foo.1 .\" .TH garbd 1 "SEPTEMBER 2014" Linux "User Manuals" .SH NAME garbd \- arbitrator daemon for Galera cluster .SH SYNOPSIS .B garbd [options] [ .I group address .B ] .SH DESCRIPTION .B garbd joins Galera cluster as an additional node for the purpose of establishing quorum in case of network partitioning. It can do so by serving: .RS a) as an odd node to prevent split-brains; .RE .RS b) as a reference connection point outside a datacenter. .RE Arbitrator node must see all messages that the other nodes of the cluster see, however it does not process them any further and just discards them. As such it does not store any cluster state and can't be used to bootstrap the cluster, so it only can join existing cluster. .\" .BR xyzzy (1) .SH OPTIONS .IP -a, --address group address in Galera format. .IP -c, --cfg configuration file if different from system-wide. .IP -d, --daemon become daemon. .IP -g, --group group name. .IP -l, --log log file to log messages to. If not specified, .B garbd will log to standard output or syslog if run as daemon. .IP -n, --name arbitrotor node name. .IP -o, --options Galera options list. It is likely to be the same as on other nodes of the cluster. .IP --sst a string that contains SST request to trigger state snapshot dump (state backup) on one of the other nodes. For details refer to Galera documentation at http://www.galeracluster.com .IP --donor desired donor node name (for state dump). .SH FILES .I /etc/default/garb .RS The system wide configuration file for system service script on Debian-derived systems. .RE .I /etc/sysconfig/garb .RS The system wide configuration file for system service script on Red Hat-derived systems. .RE .SH BUGS See Galera bug tracker at https://github.com/codership/galera .SH AUTHOR Codership Oy .\".SH "SEE ALSO" .\".BR bar (1), percona-galera-3-3.8-3390/garb/garb_config.cpp000066400000000000000000000076221244131713600206700ustar00rootroot00000000000000/* Copyright (C) 2011-2013 Codership Oy */ #include "gu_crc32c.h" #include "garb_config.hpp" #include "garb_logger.hpp" #include "gcs.hpp" #include #include namespace po = boost::program_options; #include #include namespace garb { std::string const Config::DEFAULT_SST(WSREP_STATE_TRANSFER_TRIVIAL); Config::Config (int argc, char* argv[]) : daemon_ (false), name_ (GCS_ARBITRATOR_NAME), address_ (), group_ ("my_test_cluster"), sst_ (DEFAULT_SST), donor_ (), options_ (), log_ (), cfg_ (), exit_ (false) { po::options_description other ("Other options"); other.add_options() ("version,v", "Print version & exit") ("help,h", "Show help message & exit") ; // only these are read from cfg file po::options_description config ("Configuration"); config.add_options() ("daemon,d", "Become daemon") ("name,n", po::value(&name_), "Node name") ("address,a",po::value(&address_), "Group address") ("group,g", po::value(&group_), "Group name") ("sst", po::value(&sst_), "SST request string") ("donor", po::value(&donor_), "SST donor name") ("options,o",po::value(&options_), "GCS/GCOMM option list") ("log,l", po::value(&log_), "Log file") ; po::options_description cfg_opt; config.add_options() ("cfg,c", po::value(&cfg_), "Configuration file") ; // these are accepted on the command line po::options_description cmdline_opts; cmdline_opts.add(config).add(cfg_opt).add(other); // we can submit address without option po::positional_options_description p; p.add("address", -1); po::variables_map vm; store(po::command_line_parser(argc, argv). options(cmdline_opts).positional(p).run(), vm); notify(vm); if (vm.count("help")) { std::cerr << "\nUsage: " << argv[0] << " [options] [group address]\n" << cmdline_opts << std::endl; exit_= true; return; } if (vm.count("version")) { log_info << GALERA_VER << ".r" << GALERA_REV; exit_= true; return; } if (vm.count("cfg")) { std::ifstream ifs(cfg_.c_str()); if (!ifs.good()) { gu_throw_error(ENOENT) << "Failed to open configuration file '" << cfg_ << "' for reading."; } store(parse_config_file(ifs, config), vm); notify(vm); } if (!vm.count("address")) { gu_throw_error(EDESTADDRREQ) << "Group address not specified"; } if (!vm.count("group")) { gu_throw_error(EDESTADDRREQ) << "Group name not specified"; } if (vm.count("daemon")) { daemon_ = true; } if (options_.length() > 0) options_ += "; "; options_ += "gcs.fc_limit=9999999; gcs.fc_factor=1.0; gcs.fc_master_slave=yes"; // this block must be the very last. gu_conf_self_tstamp_on(); if (vm.count("log")) { set_logfile (log_); } else if (daemon_) /* if no log file given AND daemon operation requested - * log to syslog */ { gu_conf_self_tstamp_off(); set_syslog(); } gu_crc32c_configure(); } std::ostream& operator << (std::ostream& os, const Config& c) { os << "\n\tdaemon: " << c.daemon() << "\n\tname: " << c.name() << "\n\taddress: " << c.address() << "\n\tgroup: " << c.group() << "\n\tsst: " << c.sst() << "\n\tdonor: " << c.donor() << "\n\toptions: " << c.options() << "\n\tcfg: " << c.cfg() << "\n\tlog: " << c.log(); return os; } } percona-galera-3-3.8-3390/garb/garb_config.hpp000066400000000000000000000025321244131713600206700ustar00rootroot00000000000000/* Copyright (C) 2011-2013 Codership Oy */ #ifndef _GARB_CONFIG_HPP_ #define _GARB_CONFIG_HPP_ #include #include #include namespace garb { class Config { public: static std::string const DEFAULT_SST; // default (empty) SST request Config (int argc, char* argv[]); ~Config () {} bool daemon() const { return daemon_ ; } const std::string& name() const { return name_ ; } const std::string& address() const { return address_; } const std::string& group() const { return group_ ; } const std::string& sst() const { return sst_ ; } const std::string& donor() const { return donor_ ; } const std::string& options() const { return options_; } const std::string& cfg() const { return cfg_ ; } const std::string& log() const { return log_ ; } bool exit() const { return exit_ ; } private: bool daemon_; std::string name_; std::string address_; std::string group_; std::string sst_; std::string donor_; std::string options_; std::string log_; std::string cfg_; bool exit_; /* Exit on --help or --version */ }; /* class Config */ std::ostream& operator << (std::ostream&, const Config&); } /* namespace garb */ #endif /* _GARB_CONFIG_HPP_ */ percona-galera-3-3.8-3390/garb/garb_gcs.cpp000066400000000000000000000073411244131713600201750ustar00rootroot00000000000000/* * Copyright (C) 2011-2014 Codership Oy */ #include "garb_gcs.hpp" namespace garb { static int const REPL_PROTO_VER(127); static int const APPL_PROTO_VER(127); Gcs::Gcs (gu::Config& gconf, const std::string& name, const std::string& address, const std::string& group) : closed_ (true), gcs_ (gcs_create (reinterpret_cast(&gconf), NULL, name.c_str(), "", REPL_PROTO_VER, APPL_PROTO_VER)) { if (!gcs_) { gu_throw_fatal << "Failed to create GCS object"; } ssize_t ret = gcs_open (gcs_, group.c_str(), address.c_str(), false); if (ret < 0) { gcs_destroy (gcs_); gu_throw_error(-ret) << "Failed to open connection to group"; } closed_ = false; } Gcs::~Gcs () { if (!closed_) { log_warn << "Destroying non-closed object, bad idea"; close (); } gcs_destroy (gcs_); } void Gcs::recv (gcs_action& act) { again: ssize_t ret = gcs_recv(gcs_, &act); if (gu_unlikely(ret < 0)) { if (-ECANCELED == ret) { ret = gcs_resume_recv (gcs_); if (0 == ret) goto again; } log_fatal << "Receiving from group failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "Receiving from group failed"; } } void Gcs::request_state_transfer (const std::string& request, const std::string& donor) { gcs_seqno_t order; log_info << "Sending state transfer request: '" << request << "', size: " << request.length(); /* Need to substitute the first ':' for \0 */ ssize_t req_len = request.length() + 1 /* \0 */; char* const req_str(reinterpret_cast(::malloc( req_len + 1 /* potentially need one more \0 */))); // cppcheck-suppress nullPointer if (!req_str) { gu_throw_error (ENOMEM) << "Cannot allocate " << req_len << " bytes for state transfer request"; } ::strcpy(req_str, request.c_str()); char* column_ptr = ::strchr(req_str, ':'); if (column_ptr) { *column_ptr = '\0'; } else /* append an empty string */ { req_str[req_len] = '\0'; req_len++; } ssize_t ret; do { gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; // for garb we use the lowest str_version. ret = gcs_request_state_transfer (gcs_, 0, req_str, req_len, donor.c_str(), &ist_uuid, ist_seqno, &order); } while (-EAGAIN == ret && (usleep(1000000), true)); free (req_str); if (ret < 0) { log_fatal << "State transfer request failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "State transfer request failed"; } } void Gcs::join (gcs_seqno_t seqno) { ssize_t ret = gcs_join (gcs_, seqno); if (ret < 0) { log_fatal << "Joining group failed: " << ret << " (" << strerror(-ret) << ")"; gu_throw_error(-ret) << "Joining group failed"; } } void Gcs::set_last_applied (gcs_seqno_t seqno) { (void) gcs_set_last_applied(gcs_, seqno); } void Gcs::close () { if (!closed_) { ssize_t ret = gcs_close (gcs_); if (ret < 0) { log_error << "Failed to close connection to group"; } else { closed_ = true; } } else { log_warn << "Attempt to close a closed connection"; } } } /* namespace garb */ percona-galera-3-3.8-3390/garb/garb_gcs.hpp000066400000000000000000000014231244131713600201750ustar00rootroot00000000000000/* Copyright (C) 2011-2013 Codership Oy */ #ifndef _GARB_GCS_HPP_ #define _GARB_GCS_HPP_ #include #include namespace garb { class Gcs { public: Gcs (gu::Config& conf, const std::string& name, const std::string& address, const std::string& group); ~Gcs (); void recv (gcs_action& act); void request_state_transfer (const std::string& request, const std::string& donor); void join (gcs_seqno_t); void set_last_applied(gcs_seqno_t); void close (); private: bool closed_; gcs_conn_t* gcs_; Gcs (const Gcs&); Gcs& operator= (const Gcs&); }; /* class Gcs */ } /* namespace garb */ #endif /* _GARB_GCS_HPP_ */ percona-galera-3-3.8-3390/garb/garb_logger.cpp000066400000000000000000000020571244131713600206770ustar00rootroot00000000000000/* Copyright (C) 2011 Codership Oy */ #include "garb_logger.hpp" #include #include namespace garb { void set_logfile (const std::string& fname) { FILE* log_file = fopen (fname.c_str(), "a"); if (!log_file) { gu_throw_error (ENOENT) << "Failed to open '" << fname << "' for appending"; } gu_conf_set_log_file (log_file); } static void log_to_syslog (int level, const char* msg) { int p = LOG_NOTICE; switch (level) { case GU_LOG_FATAL: p = LOG_CRIT; break; case GU_LOG_ERROR: p = LOG_ERR; break; case GU_LOG_WARN: p = LOG_WARNING; break; case GU_LOG_INFO: p = LOG_INFO; break; case GU_LOG_DEBUG: p = LOG_DEBUG; break; } syslog (p | LOG_DAEMON, "%s", msg); } void set_syslog () { openlog ("garbd", LOG_PID, LOG_DAEMON); gu_conf_set_log_callback (log_to_syslog); } } /* namespace garb */ percona-galera-3-3.8-3390/garb/garb_logger.hpp000066400000000000000000000005001244131713600206730ustar00rootroot00000000000000/* Copyright (C) 2011 Codership Oy */ #ifndef _GARB_LOGGER_HPP_ #define _GARB_LOGGER_HPP_ #include #include namespace garb { extern void set_logfile (const std::string& fname); extern void set_syslog (); } /* namespace garb */ #endif /* _GARB_LOGGER_HPP_ */ percona-galera-3-3.8-3390/garb/garb_main.cpp000066400000000000000000000041531244131713600203430ustar00rootroot00000000000000/* Copyright (C) 2011 Codership Oy */ #include "garb_config.hpp" #include "garb_recv_loop.hpp" #include #include #include // exit() #include // setsid(), chdir() #include // open() namespace garb { void become_daemon () { if (pid_t pid = fork()) { if (pid > 0) // parent { exit(0); } else { // I guess we want this to go to stderr as well; std::cerr << "Failed to fork daemon process: " << errno << " (" << strerror(errno) << ")"; gu_throw_error(errno) << "Failed to fork daemon process"; } } // child if (setsid()<0) // become a new process leader, detach from terminal { gu_throw_error(errno) << "setsid() failed"; } if (chdir("/")) // detach from potentially removable block devices { gu_throw_error(errno) << "chdir(\"/\") failed"; } // umask(0); // A second fork ensures the process cannot acquire a controlling // terminal. if (pid_t pid = fork()) { if (pid > 0) { exit(0); } else { gu_throw_error(errno) << "Second fork failed"; } } // Close the standard streams. This decouples the daemon from the // terminal that started it. close(0); close(1); close(2); // Bind standard fds (0, 1, 2) to /dev/null for (int fd = 0; fd < 3; ++fd) { if (open("/dev/null", O_RDONLY) < 0) { gu_throw_error(errno) << "Unable to open /dev/null for fd " << fd; } } } int main (int argc, char* argv[]) { Config config(argc, argv); if (config.exit()) return 0; log_info << "Read config: " << config << std::endl; if (config.daemon()) become_daemon(); RecvLoop loop (config); return 0; } } /* namespace garb */ int main (int argc, char* argv[]) { try { return garb::main (argc, argv); } catch (std::exception& e) { log_fatal << e.what(); return 1; } } percona-galera-3-3.8-3390/garb/garb_recv_loop.cpp000066400000000000000000000051651244131713600214130ustar00rootroot00000000000000/* Copyright (C) 2011-2014 Codership Oy */ #include "garb_recv_loop.hpp" #include namespace garb { static Gcs* global_gcs(0); void signal_handler (int signum) { log_info << "Received signal " << signum; global_gcs->close(); } RecvLoop::RecvLoop (const Config& config) : config_(config), gconf_ (), params_(gconf_), parse_ (gconf_, config_.options()), gcs_ (gconf_, config_.name(), config_.address(), config_.group()) { /* set up signal handlers */ global_gcs = &gcs_; struct sigaction sa; memset (&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; if (sigaction (SIGTERM, &sa, NULL)) { gu_throw_error(errno) << "Falied to install signal hadler for signal " << "SIGTERM"; } if (sigaction (SIGINT, &sa, NULL)) { gu_throw_error(errno) << "Falied to install signal hadler for signal " << "SIGINT"; } loop(); } void RecvLoop::loop() { while (1) { gcs_action act; gcs_.recv (act); switch (act.type) { case GCS_ACT_TORDERED: if (gu_unlikely(!(act.seqno_g & 127))) /* == report_interval_ of 128 */ { gcs_.set_last_applied (act.seqno_g); } break; case GCS_ACT_COMMIT_CUT: break; case GCS_ACT_STATE_REQ: gcs_.join (-ENOSYS); /* we can't donate state */ break; case GCS_ACT_CONF: { const gcs_act_conf_t* const cc (reinterpret_cast(act.buf)); if (cc->conf_id > 0) /* PC */ { if (GCS_NODE_STATE_PRIM == cc->my_state) { gcs_.request_state_transfer (config_.sst(),config_.donor()); gcs_.join(cc->seqno); } } else if (cc->memb_num == 0) // SELF-LEAVE after closing connection { log_info << "Exiting main loop"; return; } if (config_.sst() != Config::DEFAULT_SST) { // we requested custom SST, so we're done here gcs_.close(); } break; } case GCS_ACT_JOIN: case GCS_ACT_SYNC: case GCS_ACT_FLOW: case GCS_ACT_SERVICE: case GCS_ACT_ERROR: case GCS_ACT_UNKNOWN: break; } if (act.buf) { free (const_cast(act.buf)); } } } } /* namespace garb */ percona-galera-3-3.8-3390/garb/garb_recv_loop.hpp000066400000000000000000000016761244131713600214230ustar00rootroot00000000000000/* Copyright (C) 2011-2014 Codership Oy */ #ifndef _GARB_RECV_LOOP_HPP_ #define _GARB_RECV_LOOP_HPP_ #include "garb_gcs.hpp" #include "garb_config.hpp" #include #include namespace garb { class RecvLoop { public: RecvLoop (const Config&); ~RecvLoop () {} private: void loop(); const Config& config_; gu::Config gconf_; struct RegisterParams { RegisterParams(gu::Config& cnf) { if (gcs_register_params(reinterpret_cast(&cnf))) { gu_throw_fatal << "Error initializing GCS parameters"; } } } params_; struct ParseOptions { ParseOptions(gu::Config& cnf, const std::string& opt) { cnf.parse(opt); } } parse_; Gcs gcs_; }; /* RecvLoop */ } /* namespace garb */ #endif /* _GARB_RECV_LOOP_HPP_ */ percona-galera-3-3.8-3390/gcache/000077500000000000000000000000001244131713600162145ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/AUTHORS000066400000000000000000000000421244131713600172600ustar00rootroot00000000000000Codership Oy percona-galera-3-3.8-3390/gcache/ChangeLog000066400000000000000000000000001244131713600177540ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/Makefile.am000066400000000000000000000010111244131713600202410ustar00rootroot00000000000000# Copyright (C) 2009 Codership Oy # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # #EXTRA_DIST = reconf configure SUBDIRS = src percona-galera-3-3.8-3390/gcache/NEWS000066400000000000000000000000001244131713600167010ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/README000066400000000000000000000015151244131713600170760ustar00rootroot00000000000000GCache is a library to provide transparent on-disk memory buffer cache. The purpose is to allow (almost) arbitrarily big action cache without RAM consumption. It provides the usual malloc(), realloc(), free() calls plus: void seqno_assign(void*, int64_t) - assign GCS seqno to a buffer pointed to. int64_t seqno_lock_min() - get the lowest seqno present in cache, return its value. void* seqno_get_buf(int64_t) - get a pointer to buffer with a given seqno, unlock previously locked seqno and lock the current one. void seqno_release() - release currently locked seqno. Details will be determined during development. It exploits the fact that action buffers are allocated and discarded in order close to their TO. percona-galera-3-3.8-3390/gcache/SConscript000066400000000000000000000001401244131713600202210ustar00rootroot00000000000000# SConscript for building galerautils SConscript(Split('''src/SConscript tests/SConscript''')) percona-galera-3-3.8-3390/gcache/bootstrap.sh000077500000000000000000000012501244131713600205660ustar00rootroot00000000000000#!/bin/sh # This script bootraps the build process for the freshly checked # working copy LOG=$0.log run_prog() { echo -n "Running $1... " $* 1>$LOG 2>&1 && echo "Ok" && rm -f $LOG || \ (echo "Failed. See $LOG"; return 1) } set -e # Make aclocal to search for m4 macros in /usr/local if test -d /usr/local/share/aclocal then ACLOCAL_OPTS=" -I /usr/local/share/aclocal " fi if test -x "$(which autoreconf)" then export ACLOCAL="aclocal $ACLOCAL_OPTS" run_prog autoreconf -fisv else run_prog libtoolize && \ run_prog aclocal $ACLOCAL_OPTS && \ run_prog autoheader configure.ac && \ run_prog automake -af && \ run_prog autoconf fi # percona-galera-3-3.8-3390/gcache/configure.ac000066400000000000000000000061221244131713600205030ustar00rootroot00000000000000# Copyright (C) 2009 Codership Oy # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # AC_PREREQ(2.50) AC_INIT([libgcache], [0.1.0], [info@codership.com]) AC_CONFIG_SRCDIR([config.h.in]) AC_CANONICAL_SYSTEM AC_CONFIG_HEADER([config.h]) AM_INIT_AUTOMAKE AC_PREFIX_DEFAULT(/usr/local) # Prevent configure from guessing default CFLAGS CFLAGS="$CFLAGS" CXXFLAGS="$CXXFLAGS" # Check for debug AC_ARG_ENABLE(debug, AC_HELP_STRING([--disable-debug], [disable debugging code [[default=enabled]]]),, enable_debug="yes") if test "$enable_debug" != "no" then AM_CFLAGS="-O1 -g -fno-inline" AM_CPPFLAGS="-D_FORTIFY_SOURCE=1" else AM_CFLAGS="-O3 -g" AM_CPPFLAGS="-DNDEBUG" fi AM_CONDITIONAL(ENABLE_DEBUG, test "$enable_debug" != "no") # Checks for programs. AC_PROG_AWK AC_LANG([C++]) AC_PROG_CXX AC_REQUIRE_CPP AC_PROG_LIBTOOL AC_LANG_PUSH([C]) # AM_PATH_CHECK() is broken and doesn't #include # m4-1.4.13 can no longer handle obsolete AM_PATH_CHECK so we have to switch to # PKG_CHECK_MODULES. However CentOS-5.0 has an outdated check version, so # by checking m4 version we're trying to deduce which check macro to use. m4_define(m4_version, m4_esyscmd(m4 --version | head -n1 | cut -d \ -f 4)) m4_if(m4_version_compare(m4_version,1.4.10), 1, [PKG_CHECK_MODULES([CHECK], [check >= 0.9.4])], [AM_PATH_CHECK()] ) AC_LANG_POP([C]) # Checks for libraries. AC_CHECK_LIB([pthread], [pthread_testcancel],, AC_MSG_ERROR([*** POSIX threads not found! ***])) AC_CHECK_LIB([galerautils], [gu_malloc_dbg],, AC_MSG_ERROR([*** galerautils not found! ***])) AC_CHECK_LIB([galerautils++], [main],, AC_MSG_ERROR([*** galerautils++ not found! ***])) # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([stdint.h stdlib.h string.h sys/time.h unistd.h endian.h byteswap.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE # Checks for library functions. AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday localtime_r memset strdup strerror strrchr strtol]) AC_CONFIG_FILES([Makefile src/Makefile]) AM_CFLAGS="$AM_CFLAGS -Wall -Werror -Wextra -pedantic -Wno-unused-parameter" AM_CXXFLAGS="$AM_CFLAGS -ansi -Weffc++ -Wold-style-cast -Wconversion" AM_CXXFLAGS="$AM_CXXFLAGS -fno-rtti -Wno-long-long" AM_CFLAGS="$AM_CFLAGS -std=c99" AM_LDFLAGS="-Wl,--warn-common -Wl,--fatal-warnings" AC_SUBST(AM_CFLAGS) AC_SUBST(AM_CXXFLAGS) AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_LDFLAGS) AC_OUTPUT AC_MSG_NOTICE([]) AC_MSG_NOTICE([ CFLAGS: $CFLAGS]) AC_MSG_NOTICE([AM_CFLAGS: $AM_CFLAGS]) AC_MSG_NOTICE([ CXXFLAGS: $CXXFLAGS]) AC_MSG_NOTICE([AM_CXXFLAGS: $AM_CXXFLAGS]) AC_MSG_NOTICE([ CPPFLAGS: $CPPFLAGS]) AC_MSG_NOTICE([AM_CPPFLAGS: $AM_CPPFLAGS]) AC_MSG_NOTICE([ LDFLAGS: $LDFLAGS]) AC_MSG_NOTICE([AM_LDFLAGS: $AM_LDFLAGS]) AC_MSG_NOTICE([ LIBS: $LIBS]) AC_MSG_NOTICE([]) percona-galera-3-3.8-3390/gcache/src/000077500000000000000000000000001244131713600170035ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/src/GCache.cpp000066400000000000000000000063261244131713600206300ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include #include #include #include "gcache_bh.hpp" #include "GCache.hpp" namespace gcache { void GCache::reset() { mem.reset(); rb.reset(); ps.reset(); mallocs = 0; reallocs = 0; seqno_locked = SEQNO_NONE; seqno_max = SEQNO_NONE; seqno_released = SEQNO_NONE; seqno2ptr.clear(); #ifndef NDEBUG buf_tracker.clear(); #endif } void GCache::constructor_common() {} GCache::GCache (gu::Config& cfg, const std::string& data_dir) : config (cfg), params (config, data_dir), mtx (), cond (), seqno2ptr (), mem (params.mem_size(), seqno2ptr), rb (params.rb_name(), params.rb_size(), seqno2ptr), ps (params.dir_name(), params.keep_pages_size(), params.page_size(), /* keep last page if PS is the only storage */ !((params.mem_size() + params.rb_size()) > 0)), mallocs (0), reallocs (0), frees (0), seqno_locked(SEQNO_NONE), seqno_max (SEQNO_NONE), seqno_released(0) #ifndef NDEBUG ,buf_tracker() #endif { constructor_common (); } GCache::~GCache () { gu::Lock lock(mtx); log_debug << "\n" << "GCache mallocs : " << mallocs << "\n" << "GCache reallocs: " << reallocs << "\n" << "GCache frees : " << frees; } /*! prints object properties */ void print (std::ostream& os) {} } #include "gcache.h" gcache_t* gcache_create (gu_config_t* conf, const char* data_dir) { gcache::GCache* gc = new gcache::GCache ( *reinterpret_cast(conf), data_dir); return reinterpret_cast(gc); } void gcache_destroy (gcache_t* gc) { gcache::GCache* gcache = reinterpret_cast(gc); delete gcache; } void* gcache_malloc (gcache_t* gc, size_t size) { gcache::GCache* gcache = reinterpret_cast(gc); return gcache->malloc (size); } void gcache_free (gcache_t* gc, const void* ptr) { gcache::GCache* gcache = reinterpret_cast(gc); gcache->free (const_cast(ptr)); } void* gcache_realloc (gcache_t* gc, void* ptr, size_t size) { gcache::GCache* gcache = reinterpret_cast(gc); return gcache->realloc (ptr, size); } int64_t gcache_seqno_min (gcache_t* gc) { gcache::GCache* gcache = reinterpret_cast(gc); return gcache->seqno_min (); } #if DEPRECATED void gcache_seqno_init (gcache_t* gc, int64_t seqno) { gcache::GCache* gcache = reinterpret_cast(gc); gcache->seqno_init (seqno); } void gcache_seqno_assign(gcache_t* gc, const void* ptr, int64_t seqno) { gcache::GCache* gcache = reinterpret_cast(gc); gcache->seqno_assign (ptr, seqno, -1, false); } void gcache_seqno_release(gcache_t* gc, const void* ptr) { gcache::GCache* gcache = reinterpret_cast(gc); gcache->seqno_release (); } #endif percona-galera-3-3.8-3390/gcache/src/GCache.hpp000066400000000000000000000147451244131713600206410ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #ifndef __GCACHE_H__ #define __GCACHE_H__ #include "gcache_mem_store.hpp" #include "gcache_rb_store.hpp" #include "gcache_page_store.hpp" #include "gu_types.hpp" #include #include #include #ifndef NDEBUG #include #endif #include namespace gcache { class GCache { public: static void register_params(gu::Config& cfg) { Params::register_params(cfg); } /*! * Creates a new gcache file in "gcache.name" conf parameter or * in data_dir. If file already exists, it gets overwritten. */ GCache (gu::Config& cfg, const std::string& data_dir); virtual ~GCache(); /*! prints object properties */ void print (std::ostream& os); /* Resets storage */ void reset(); /* Memory allocation functions */ void* malloc (ssize_t size); void free (void* ptr); void* realloc (void* ptr, ssize_t size); /* Seqno related functions */ /*! * Reinitialize seqno sequence (after SST or such) * Clears seqno->ptr map // and sets seqno_min to seqno. */ void seqno_reset (/*int64_t seqno*/); /*! * Assign sequence number to buffer pointed to by ptr */ void seqno_assign (const void* ptr, int64_t seqno_g, int64_t seqno_d); /*! * Release (free) buffers up to seqno */ void seqno_release (int64_t seqno); /*! * Returns smallest seqno present in history */ int64_t seqno_min() const { gu::Lock lock(mtx); if (gu_likely(!seqno2ptr.empty())) return seqno2ptr.begin()->first; else return -1; } /*! * Move lock to a given seqno. * @throws gu::NotFound if seqno is not in the cache. */ void seqno_lock (int64_t const seqno_g); /*! DEPRECATED * Get pointer to buffer identified by seqno. * Moves lock to the given seqno. * @throws NotFound */ const void* seqno_get_ptr (int64_t seqno_g, int64_t& seqno_d, ssize_t& size); class Buffer { public: Buffer() : seqno_g_(), ptr_(), size_(), seqno_d_() { } Buffer (const Buffer& other) : seqno_g_(other.seqno_g_), ptr_ (other.ptr_), size_ (other.size_), seqno_d_(other.seqno_d_) { } Buffer& operator= (const Buffer& other) { seqno_g_ = other.seqno_g_; ptr_ = other.ptr_; size_ = other.size_; seqno_d_ = other.seqno_d_; return *this; } int64_t seqno_g() const { return seqno_g_; } const gu::byte_t* ptr() const { return ptr_; } ssize_t size() const { return size_; } int64_t seqno_d() const { return seqno_d_; } protected: void set_ptr (const void* p) { ptr_ = reinterpret_cast(p); } void set_other (ssize_t s, int64_t g, int64_t d) { size_ = s; seqno_g_ = g; seqno_d_ = d; } private: int64_t seqno_g_; const gu::byte_t* ptr_; ssize_t size_; int64_t seqno_d_; friend class GCache; }; /*! * Fills a vector with Buffer objects starting with seqno start * until either vector length or seqno map is exhausted. * Moves seqno lock to start. * * @retval number of buffers filled (<= v.size()) */ ssize_t seqno_get_buffers (std::vector& v, int64_t start); /*! * Releases any seqno locks present. */ void seqno_unlock (); /*! @throws NotFound */ void param_set (const std::string& key, const std::string& val); static size_t const PREAMBLE_LEN; private: void free_common (BufferHeader*); gu::Config& config; class Params { public: static void register_params(gu::Config&); Params(gu::Config&, const std::string&); const std::string& rb_name() const { return rb_name_; } const std::string& dir_name() const { return dir_name_; } ssize_t mem_size() const { return mem_size_; } ssize_t rb_size() const { return rb_size_; } ssize_t page_size() const { return page_size_; } ssize_t keep_pages_size() const { return keep_pages_size_; } void mem_size (ssize_t s) { mem_size_ = s; } void page_size (ssize_t s) { page_size_ = s; } void keep_pages_size (ssize_t s) { keep_pages_size_ = s; } private: std::string const rb_name_; std::string const dir_name_; ssize_t mem_size_; ssize_t const rb_size_; ssize_t page_size_; ssize_t keep_pages_size_; } params; gu::Mutex mtx; gu::Cond cond; typedef std::map seqno2ptr_t; typedef seqno2ptr_t::iterator seqno2ptr_iter_t; typedef std::pair seqno2ptr_pair_t; seqno2ptr_t seqno2ptr; MemStore mem; RingBuffer rb; PageStore ps; long long mallocs; long long reallocs; long long frees; int64_t seqno_locked; int64_t seqno_max; int64_t seqno_released; #ifndef NDEBUG std::set buf_tracker; #endif void constructor_common(); /* returns true when successfully discards all seqnos up to s */ bool discard_seqno (int64_t s); // disable copying GCache (const GCache&); GCache& operator = (const GCache&); }; } #endif /* __GCACHE_H__ */ percona-galera-3-3.8-3390/gcache/src/GCache_memops.cpp000066400000000000000000000114431244131713600222040ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "GCache.hpp" #include namespace gcache { bool GCache::discard_seqno (int64_t seqno) { for (seqno2ptr_t::iterator i = seqno2ptr.begin(); i != seqno2ptr.end() && i->first <= seqno;) { BufferHeader* bh(ptr2BH (i->second)); if (gu_likely(BH_is_released(bh))) { assert (bh->seqno_g == i->first); assert (bh->seqno_g <= seqno); assert (bh->seqno_g <= seqno_released); seqno2ptr.erase (i++); // post ++ is significant! bh->seqno_g = SEQNO_ILL; // will never be reused switch (bh->store) { case BUFFER_IN_MEM: mem.discard (bh); break; case BUFFER_IN_RB: rb.discard (bh); break; case BUFFER_IN_PAGE: ps.discard (bh); break; default: log_fatal << "Corrupt buffer header: " << bh; abort(); } } else { return false; } } return true; } void* GCache::malloc (ssize_t size) { size += sizeof(BufferHeader); gu::Lock lock(mtx); void* ptr; mallocs++; ptr = mem.malloc(size); if (0 == ptr) ptr = rb.malloc(size); if (0 == ptr) ptr = ps.malloc(size); #ifndef NDEBUG if (0 != ptr) buf_tracker.insert (ptr); #endif return ptr; } void GCache::free_common (BufferHeader* const bh) { assert(bh->seqno_g != SEQNO_ILL); BH_release(bh); if (gu_likely(SEQNO_NONE != bh->seqno_g)) { #ifndef NDEBUG if (!(seqno_released + 1 == bh->seqno_g || SEQNO_NONE == seqno_released)) { log_fatal << "OOO release: seqno_released " << seqno_released << ", releasing " << bh->seqno_g; } assert(seqno_released + 1 == bh->seqno_g || SEQNO_NONE == seqno_released); #endif seqno_released = bh->seqno_g; } #ifndef NDEBUG void* const ptr(bh + 1); std::set::iterator it = buf_tracker.find(ptr); if (it == buf_tracker.end()) { log_fatal << "Have not allocated this ptr: " << ptr; abort(); } buf_tracker.erase(it); #endif frees++; switch (bh->store) { case BUFFER_IN_MEM: mem.free (bh); break; case BUFFER_IN_RB: rb.free (bh); break; case BUFFER_IN_PAGE: if (gu_likely(bh->seqno_g > 0)) { discard_seqno (bh->seqno_g); } else { assert(bh->seqno_g != SEQNO_ILL); bh->seqno_g = SEQNO_ILL; ps.discard (bh); } break; } rb.assert_size_free(); } void GCache::free (void* ptr) { if (gu_likely(0 != ptr)) { BufferHeader* const bh(ptr2BH(ptr)); gu::Lock lock(mtx); free_common (bh); } else { log_warn << "Attempt to free a null pointer"; assert(0); } } // this will crash if ptr == 0 void* GCache::realloc (void* ptr, ssize_t size) { size += sizeof(BufferHeader); void* new_ptr(0); BufferHeader* const bh(ptr2BH(ptr)); if (gu_unlikely(bh->seqno_g > 0)) // sanity check { log_fatal << "Internal program error: changing size of an ordered" << " buffer, seqno: " << bh->seqno_g << ". Aborting."; abort(); } gu::Lock lock(mtx); reallocs++; MemOps* store(0); switch (bh->store) { case BUFFER_IN_MEM: store = &mem; break; case BUFFER_IN_RB: store = &rb; break; case BUFFER_IN_PAGE: store = &ps; break; default: log_fatal << "Memory corruption: unrecognized store: " << bh->store; abort(); } new_ptr = store->realloc (ptr, size); if (0 == new_ptr) { new_ptr = malloc (size); if (0 != new_ptr) { memcpy (new_ptr, ptr, bh->size - sizeof(BufferHeader)); store->free (bh); } } #ifndef NDEBUG if (ptr != new_ptr && 0 != new_ptr) { std::set::iterator it = buf_tracker.find(ptr); if (it != buf_tracker.end()) buf_tracker.erase(it); it = buf_tracker.find(new_ptr); } #endif return new_ptr; } } percona-galera-3-3.8-3390/gcache/src/GCache_seqno.cpp000066400000000000000000000203471244131713600220340ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "SeqnoNone.hpp" #include "gcache_bh.hpp" #include "GCache.hpp" #include #include #include #include // sched_yeild() namespace gcache { /*! * Reinitialize seqno sequence (after SST or such) * Clears seqno->ptr map // and sets seqno_min to seqno. */ void GCache::seqno_reset () { gu::Lock lock(mtx); seqno_released = SEQNO_NONE; if (gu_unlikely(seqno2ptr.empty())) return; /* order is significant here */ rb.seqno_reset(); mem.seqno_reset(); seqno2ptr.clear(); } /*! * Assign sequence number to buffer pointed to by ptr */ void GCache::seqno_assign (const void* const ptr, int64_t const seqno_g, int64_t const seqno_d) { gu::Lock lock(mtx); BufferHeader* bh = ptr2BH(ptr); assert (SEQNO_NONE == bh->seqno_g); assert (SEQNO_ILL == bh->seqno_d); assert (!BH_is_released(bh)); if (gu_likely(seqno_g > seqno_max)) { seqno2ptr.insert (seqno2ptr.end(), seqno2ptr_pair_t(seqno_g, ptr)); seqno_max = seqno_g; } else { // this should never happen. seqnos should be assinged in TO. const std::pair& res( seqno2ptr.insert (seqno2ptr_pair_t(seqno_g, ptr))); if (false == res.second) { gu_throw_fatal <<"Attempt to reuse the same seqno: " << seqno_g <<". New ptr = " << ptr << ", previous ptr = " << res.first->second; } } bh->seqno_g = seqno_g; bh->seqno_d = seqno_d; } void GCache::seqno_release (int64_t const seqno) { assert (seqno > 0); /* The number of buffers scheduled for release is unpredictable, so * we want to allow some concurrency in cache access by releasing * buffers in small batches */ static int const min_batch_size(32); /* Although extremely unlikely, theoretically concurrent access may * lead to elements being added faster than released. The following is * to control and possibly disable concurrency in that case. We start * with min_batch_size and increase it if necessary. */ size_t old_gap(-1); int batch_size(min_batch_size); bool loop(false); do { /* if we're doing this loop repeatedly, allow other threads to run*/ if (loop) sched_yield(); gu::Lock lock(mtx); assert(seqno >= seqno_released); seqno2ptr_iter_t it(seqno2ptr.upper_bound(seqno_released)); if (gu_unlikely(it == seqno2ptr.end())) { /* This means that there are no element with * seqno following seqno_released - and this should not * generally happen. But it looks like stopcont test does it. */ if (0 != seqno_released) { log_debug << "Releasing seqno " << seqno << " before " << seqno_released + 1 << " was assigned."; } return; } assert(seqno_max >= seqno_released); /* here we check if (seqno_max - seqno_released) is decreasing * and if not - increase the batch_size (linearly) */ size_t const new_gap(seqno_max - seqno_released); batch_size += (new_gap >= old_gap) * min_batch_size; old_gap = new_gap; int64_t const start(it->first - 1); int64_t const end (seqno - start >= 2*batch_size ? start + batch_size : seqno); #if 0 log_info << "############ releasing " << (seqno - start) << " buffers, batch_size: " << batch_size << ", end: " << end; #endif for (;(loop = (it != seqno2ptr.end())) && it->first <= end;) { assert(it->first != SEQNO_NONE); BufferHeader* const bh(ptr2BH(it->second)); assert (bh->seqno_g == it->first); #ifndef NDEBUG if (!(seqno_released + 1 == it->first || seqno_released == SEQNO_NONE)) { log_info << "seqno_released: " << seqno_released << "; it->first: " << it->first << "; seqno2ptr.begin: " <first << "\nstart: " << start << "; end: " << end << " batch_size: " << batch_size << "; gap: " << new_gap << "; seqno_max: " << seqno_max; assert(seqno_released + 1 == it->first || seqno_released == SEQNO_NONE); } #endif ++it; /* free_common() below may erase current element, * so advance iterator before calling free_common()*/ if (gu_likely(!BH_is_released(bh))) free_common(bh); } assert (loop || seqno == seqno_released); loop = (end < seqno) && loop; } while(loop); } /*! * Move lock to a given seqno. Throw gu::NotFound if seqno is not in cache. * @throws NotFound */ void GCache::seqno_lock (int64_t const seqno_g) { gu::Lock lock(mtx); if (seqno2ptr.find(seqno_g) == seqno2ptr.end()) throw gu::NotFound(); if (seqno_locked != SEQNO_NONE) { cond.signal(); } seqno_locked = seqno_g; } /*! * Get pointer to buffer identified by seqno. * Moves lock to the given seqno. * @throws NotFound */ const void* GCache::seqno_get_ptr (int64_t const seqno_g, int64_t& seqno_d, ssize_t& size) { const void* ptr(0); { gu::Lock lock(mtx); seqno2ptr_iter_t p = seqno2ptr.find(seqno_g); if (p != seqno2ptr.end()) { if (seqno_locked != SEQNO_NONE) { cond.signal(); } seqno_locked = seqno_g; ptr = p->second; } else { throw gu::NotFound(); } } assert (ptr); const BufferHeader* const bh (ptr2BH(ptr)); // this can result in IO seqno_d = bh->seqno_d; size = bh->size - sizeof(BufferHeader); return ptr; } ssize_t GCache::seqno_get_buffers (std::vector& v, int64_t const start) { ssize_t const max(v.size()); assert (max > 0); ssize_t found(0); { gu::Lock lock(mtx); seqno2ptr_iter_t p = seqno2ptr.find(start); if (p != seqno2ptr.end()) { if (seqno_locked != SEQNO_NONE) { cond.signal(); } seqno_locked = start; do { assert (p->first == (start + found)); assert (p->second); v[found].set_ptr(p->second); } while (++found < max && ++p != seqno2ptr.end() && p->first == (start + found)); /* the latter condition ensures seqno continuty, #643 */ } } // the following may cause IO for (ssize_t i(0); i < found; ++i) { const BufferHeader* const bh (ptr2BH(v[i].ptr())); assert (bh->seqno_g == (start + i)); v[i].set_other (bh->size - sizeof(BufferHeader), bh->seqno_g, bh->seqno_d); } return found; } /*! * Releases any history locks present. */ void GCache::seqno_unlock () { gu::Lock lock(mtx); seqno_locked = SEQNO_NONE; cond.signal(); } } percona-galera-3-3.8-3390/gcache/src/Makefile.am000066400000000000000000000014141244131713600210370ustar00rootroot00000000000000# Copyright (C) 2009 Codership Oy # GCACHE_SRCS = \ FileDescriptor.cpp \ MMap.cpp \ GCache.cpp \ GCache_header.cpp \ GCache_memops.cpp \ GCache_seqno.cpp # Describe libGCACHE library target #include_HEADERS = GCache.hpp lib_LTLIBRARIES = libgcache.la libgcache_la_SOURCES = $(GCACHE_SRCS) $(GCACHE_INCS) INTERFACE = 1 REVISION = 0 AGE = 0 libgcache_la_LDFLAGS = \ @AM_LDFLAGS@ -version-info $(INTERFACE):$(REVISION):$(AGE) # Desclibe GCACHE_test binary target noinst_PROGRAMS = test test_SOURCES = test.cpp test_LDADD = $(lib_LTLIBRARIES) test_LDFLAGS = @AM_LDFLAGS@ -static .PHONY: lib test tags lib: $(lib_LTLIBRARIES) #test: GCACHE_test tags: TAGS #SUBDIRS = unit_tests # percona-galera-3-3.8-3390/gcache/src/SConscript000066400000000000000000000012121244131713600210110ustar00rootroot00000000000000 Import('env') gcache_env = env.Clone() gcache_sources = Split (''' GCache_seqno.cpp gcache_params.cpp gcache_page.cpp gcache_page_store.cpp gcache_rb_store.cpp gcache_mem_store.cpp GCache_memops.cpp GCache.cpp ''') gcache_env.StaticLibrary('gcache', gcache_sources) test_env = gcache_env.Clone() test_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) test_env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) test_env.Prepend(LIBS=File('libgcache.a')) test_env.Program(source='test.cpp') env.Append(LIBGALERA_OBJS = gcache_env.SharedObject(gcache_sources)) percona-galera-3-3.8-3390/gcache/src/SeqnoNone.hpp000066400000000000000000000004671244131713600214300ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef __GCACHE_SEQNO_NONE__ #define __GCACHE_SEQNO_NONE__ //#include #include namespace gcache { static int64_t const SEQNO_NONE = 0; static int64_t const SEQNO_ILL = -1; } #endif /* __GCACHE_SEQNO_NONE__ */ percona-galera-3-3.8-3390/gcache/src/gcache.h000066400000000000000000000012641244131713600203710ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! * @file C-interface to GCache. */ #ifndef _gcache_h_ #define _gcache_h_ #include #ifdef __cplusplus extern "C" { #endif #include "gu_config.h" typedef struct _gcache gcache_t; extern gcache_t* gcache_create (gu_config_t* conf, const char* data_dir); extern void gcache_destroy (gcache_t* gc); extern void* gcache_malloc (gcache_t* gc, size_t size); extern void gcache_free (gcache_t* gc, const void* ptr); extern void* gcache_realloc (gcache_t* gc, void* ptr, size_t size); extern int64_t gcache_seqno_min (gcache_t* gc); #ifdef __cplusplus } #endif #endif /* _gcache_h_ */ percona-galera-3-3.8-3390/gcache/src/gcache_bh.hpp000066400000000000000000000041021244131713600213740ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * */ #ifndef __GCACHE_BUFHEAD__ #define __GCACHE_BUFHEAD__ #include #include #include #include "SeqnoNone.hpp" #include "gcache_memops.hpp" namespace gcache { static uint32_t const BUFFER_RELEASED = 1 << 0; enum StorageType { BUFFER_IN_MEM, BUFFER_IN_RB, BUFFER_IN_PAGE }; struct BufferHeader { int64_t seqno_g; int64_t seqno_d; int64_t size; /*! total buffer size, including header */ MemOps* ctx; uint32_t flags; int32_t store; }__attribute__((__packed__)); #define BH_cast(ptr) reinterpret_cast(ptr) static inline BufferHeader* ptr2BH (const void* ptr) { return (static_cast(const_cast(ptr)) - 1); } static inline void BH_clear (BufferHeader* const bh) { memset (bh, 0, sizeof(BufferHeader)); } static inline void BH_assert_clear (const BufferHeader* const bh) { assert(0 == bh->seqno_g); assert(0 == bh->seqno_d); assert(0 == bh->size); assert(0 == bh->ctx); assert(0 == bh->flags); assert(0 == bh->store); } static inline bool BH_is_released (const BufferHeader* const bh) { return (bh->flags & BUFFER_RELEASED); } static inline void BH_release (BufferHeader* const bh) { assert(!BH_is_released(bh)); bh->flags |= BUFFER_RELEASED; } static inline BufferHeader* BH_next(BufferHeader* bh) { return BH_cast((reinterpret_cast(bh) + bh->size)); } static inline std::ostream& operator << (std::ostream& os, const BufferHeader* const bh) { os << "seqno_g: " << bh->seqno_g << ", seqno_d: " << bh->seqno_d << ", size: " << bh->size << ", ctx: " << bh->ctx << ", flags: " << bh->flags << ". store: " << bh->store; return os; } } #endif /* __GCACHE_BUFHEAD__ */ percona-galera-3-3.8-3390/gcache/src/gcache_mem_store.cpp000066400000000000000000000032621244131713600227760ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ #include "gcache_mem_store.hpp" #include "gcache_page_store.hpp" namespace gcache { bool MemStore::have_free_space (ssize_t size) { while ((size_ + size > max_size_) && !seqno2ptr_.empty()) { /* try to free some released bufs */ seqno2ptr_iter_t const i (seqno2ptr_.begin()); BufferHeader* const bh (ptr2BH (i->second)); if (BH_is_released(bh)) /* discard buffer */ { seqno2ptr_.erase(i); bh->seqno_g = SEQNO_ILL; switch (bh->store) { case BUFFER_IN_MEM: discard(bh); break; case BUFFER_IN_RB: bh->ctx->discard(bh); break; case BUFFER_IN_PAGE: { Page* const page (static_cast(bh->ctx)); PageStore* const ps (PageStore::page_store(page)); ps->discard(bh); break; } default: log_fatal << "Corrupt buffer header: " << bh; abort(); } } else { break; } } return (size_ + size <= max_size_); } void MemStore::seqno_reset() { for (std::set::iterator buf(allocd_.begin()); buf != allocd_.end();) { std::set::iterator tmp(buf); ++buf; BufferHeader* const bh(ptr2BH(*tmp)); if (bh->seqno_g != SEQNO_NONE) { assert (BH_is_released(bh)); allocd_.erase (tmp); size_ -= bh->size; ::free (bh); } } } } /* namespace gcache */ percona-galera-3-3.8-3390/gcache/src/gcache_mem_store.hpp000066400000000000000000000065101244131713600230020ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file mem store class */ #ifndef _gcache_mem_store_hpp_ #define _gcache_mem_store_hpp_ #include "gcache_memops.hpp" #include "gcache_bh.hpp" #include #include namespace gcache { class MemStore : public MemOps { typedef std::map seqno2ptr_t; typedef seqno2ptr_t::iterator seqno2ptr_iter_t; public: MemStore (ssize_t max_size, seqno2ptr_t& seqno2ptr) : max_size_ (max_size), size_ (0), allocd_ (), seqno2ptr_(seqno2ptr) {} void reset () { for (std::set::iterator buf(allocd_.begin()); buf != allocd_.end(); ++buf) { ::free (*buf); } allocd_.clear(); size_ = 0; } ~MemStore () { reset(); } void* malloc (ssize_t size) { if (size > max_size_ || have_free_space(size) == false) return 0; assert (size_ + size <= max_size_); BufferHeader* bh (BH_cast (::malloc (size))); if (gu_likely(0 != bh)) { allocd_.insert(bh); bh->size = size; bh->seqno_g = SEQNO_NONE; bh->seqno_d = SEQNO_ILL; bh->flags = 0; bh->store = BUFFER_IN_MEM; bh->ctx = this; size_ += size; return (bh + 1); } return 0; } void free (BufferHeader* bh) { assert(bh->size > 0); assert(bh->size <= size_); assert(bh->store == BUFFER_IN_MEM); assert(bh->ctx == this); if (SEQNO_NONE == bh->seqno_g) discard (bh); } void* realloc (void* ptr, ssize_t size) { BufferHeader* bh(0); ssize_t old_size(0); if (ptr) { bh = ptr2BH(ptr); assert (SEQNO_NONE == bh->seqno_g); old_size = bh->size; } ssize_t const diff_size(size - old_size); if (size > max_size_ || have_free_space(diff_size) == false) return 0; assert (size_ + diff_size <= max_size_); void* tmp = ::realloc (bh, size); if (tmp) { allocd_.erase(bh); allocd_.insert(tmp); bh = BH_cast(tmp); assert (bh->size == old_size); bh->size = size; size_ += diff_size; return (bh + 1); } return 0; } void discard (BufferHeader* bh) { assert (BH_is_released(bh)); size_ -= bh->size; ::free (bh); allocd_.erase(bh); } void set_max_size (ssize_t size) { max_size_ = size; } void seqno_reset(); // for unit tests only ssize_t _allocd () const { return size_; } private: bool have_free_space (ssize_t size); ssize_t max_size_; ssize_t size_; std::set allocd_; seqno2ptr_t& seqno2ptr_; }; } #endif /* _gcache_mem_store_hpp_ */ percona-galera-3-3.8-3390/gcache/src/gcache_memops.hpp000066400000000000000000000013131244131713600223040ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file memory operations interface */ #ifndef _gcache_memops_hpp_ #define _gcache_memops_hpp_ #include namespace gcache { struct BufferHeader; class MemOps { public: MemOps() {} virtual ~MemOps() {} virtual void* malloc (ssize_t size) = 0; virtual void free (BufferHeader* bh) = 0; virtual void* realloc (void* ptr, ssize_t size) = 0; virtual void discard (BufferHeader* bh) = 0; virtual void reset () = 0; }; } #endif /* _gcache_memops_hpp_ */ percona-galera-3-3.8-3390/gcache/src/gcache_page.cpp000066400000000000000000000064171244131713600217250ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file page file class implementation */ #include "gcache_page.hpp" // for posix_fadvise() #if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE 600 #endif #include static ssize_t check_size (ssize_t size) { if (size < 0) gu_throw_error(EINVAL) << "Negative page size: " << size; return size; } void gcache::Page::reset () { if (gu_unlikely (used_ > 0)) { log_fatal << "Attempt to reset a page '" << name() << "' used by " << used_ << " buffers. Aborting."; abort(); } space_ = mmap_.size; next_ = static_cast(mmap_.ptr); } void gcache::Page::drop_fs_cache() const { mmap_.dont_need(); #if !defined(__APPLE__) int const err (posix_fadvise (fd_.get(), 0, fd_.size(), POSIX_FADV_DONTNEED)); if (err != 0) { log_warn << "Failed to set POSIX_FADV_DONTNEED on " << fd_.name() << ": " << err << " (" << strerror(err) << ")"; } #endif } gcache::Page::Page (void* ps, const std::string& name, ssize_t size) : fd_ (name, check_size(size), false, false), mmap_ (fd_), ps_ (ps), next_ (static_cast(mmap_.ptr)), space_(mmap_.size), used_ (0) { log_info << "Created page " << name << " of size " << space_ << " bytes"; BH_clear (reinterpret_cast(next_)); } void* gcache::Page::malloc (ssize_t size) { if (size <= space_) { BufferHeader* bh(BH_cast(next_)); bh->size = size; bh->seqno_g = SEQNO_NONE; bh->seqno_d = SEQNO_ILL; bh->ctx = this; bh->flags = 0; bh->store = BUFFER_IN_PAGE; space_ -= size; next_ += size; used_++; #ifndef NDEBUG if (space_ >= static_cast(sizeof(BufferHeader))) { BH_clear (BH_cast(next_)); assert (reinterpret_cast(bh + 1) < next_); } assert (next_ <= static_cast(mmap_.ptr) + mmap_.size); #endif return (bh + 1); } else { log_debug << "Failed to allocate " << size << " bytes, space left: " << space_ << " bytes, total allocated: " << next_ - static_cast(mmap_.ptr); return 0; } } void* gcache::Page::realloc (void* ptr, ssize_t size) { BufferHeader* bh(ptr2BH(ptr)); if (bh == BH_cast(next_ - bh->size)) // last buffer, can shrink and expand { ssize_t const diff_size (size - bh->size); if (gu_likely (diff_size < space_)) { bh->size += diff_size; space_ -= diff_size; next_ += diff_size; BH_clear (BH_cast(next_)); return ptr; } else return 0; // not enough space in this page } else { if (gu_likely(size > bh->size)) { void* const ret (malloc (size)); if (ret) { memcpy (ret, ptr, bh->size - sizeof(BufferHeader)); used_--; } return ret; } else { // do nothing, we can't shrink the buffer, it is locked return ptr; } } } percona-galera-3-3.8-3390/gcache/src/gcache_page.hpp000066400000000000000000000030641244131713600217250ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file page file class */ #ifndef _gcache_page_hpp_ #define _gcache_page_hpp_ #include "gcache_memops.hpp" #include "gcache_bh.hpp" #include "gu_fdesc.hpp" #include "gu_mmap.hpp" #include namespace gcache { class Page : public MemOps { public: Page (void* ps, const std::string& name, ssize_t size); ~Page () {} void* malloc (ssize_t size); void free (BufferHeader* bh) { assert (bh >= mmap_.ptr); assert (static_cast(bh) <= (static_cast(mmap_.ptr) + mmap_.size - sizeof(BufferHeader))); assert (used_ > 0); used_--; } void* realloc (void* ptr, ssize_t size); void discard (BufferHeader* ptr) {} ssize_t used () const { return used_; } ssize_t size () const /* total page size */ { return mmap_.size - sizeof(BufferHeader); } const std::string& name() const { return fd_.name(); } void reset (); /* Drop filesystem cache on the file */ void drop_fs_cache() const; void* parent() const { return ps_; } private: gu::FileDescriptor fd_; gu::MMap mmap_; void* const ps_; uint8_t* next_; ssize_t space_; ssize_t used_; Page(const gcache::Page&); Page& operator=(const gcache::Page&); }; } #endif /* _gcache_page_hpp_ */ percona-galera-3-3.8-3390/gcache/src/gcache_page_store.cpp000066400000000000000000000132031244131713600231300ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file page store implementation */ #include "gcache_page_store.hpp" #include "gcache_bh.hpp" #include #include #include static const std::string base_name ("gcache.page."); static std::string make_base_name (const std::string& dir_name) { if (dir_name.empty()) { return base_name; } else { if (dir_name[dir_name.length() - 1] == '/') { return (dir_name + base_name); } else { return (dir_name + '/' + base_name); } } } static std::string make_page_name (const std::string& base_name, ssize_t count) { std::ostringstream os; os << base_name << std::setfill ('0') << std::setw (6) << count; return os.str(); } static void* remove_file (void* __restrict__ arg) { char* const file_name (static_cast(arg)); if (NULL != file_name) { if (remove (file_name)) { int err = errno; log_error << "Failed to remove page file '" << file_name << "': " << gu::to_string(err) << " (" << strerror(err) << ")"; } else { log_info << "Deleted page " << file_name; } free (file_name); } else { log_error << "Null file name in " << __FUNCTION__; } pthread_exit(NULL); } bool gcache::PageStore::delete_page () { Page* const page = pages_.front(); if (page->used() > 0) return false; pages_.pop_front(); char* const file_name(strdup(page->name().c_str())); total_size_ -= page->size(); if (current_ == page) current_ = 0; delete page; #ifdef GCACHE_DETACH_THREAD pthread_t delete_thr_; #else if (delete_thr_ != pthread_t(-1)) pthread_join (delete_thr_, NULL); #endif /* GCACHE_DETACH_THERAD */ int err = pthread_create (&delete_thr_, &delete_page_attr_, remove_file, file_name); if (0 != err) { delete_thr_ = pthread_t(-1); gu_throw_error(err) << "Failed to create page file deletion thread"; } return true; } /* Deleting pages only from the beginning kinda means that some free pages * can be locked in the middle for a while. Leaving it like that for simplicity * for now. */ void gcache::PageStore::cleanup () { while (total_size_ > keep_size_ && pages_.size() > keep_page_ && delete_page()) {} } void gcache::PageStore::reset () { while (pages_.size() > 0 && delete_page()) {}; } inline void gcache::PageStore::new_page (ssize_t size) { Page* const page(new Page(this, make_page_name (base_name_, count_), size)); pages_.push_back (page); total_size_ += size; current_ = page; count_++; } gcache::PageStore::PageStore (const std::string& dir_name, ssize_t keep_size, ssize_t page_size, bool keep_page) : base_name_ (make_base_name(dir_name)), keep_size_ (keep_size), page_size_ (page_size), keep_page_ (keep_page), count_ (0), pages_ (), current_ (0), total_size_(0), delete_page_attr_() #ifndef GCACHE_DETACH_THREAD , delete_thr_(pthread_t(-1)) #endif /* GCACHE_DETACH_THREAD */ { int err = pthread_attr_init (&delete_page_attr_); if (0 != err) { gu_throw_error(err) << "Failed to initialize page file deletion " << "thread attributes"; } #ifdef GCACHE_DETACH_THREAD err = pthread_attr_setdetachstate (&delete_page_attr_, PTHREAD_CREATE_DETACHED); if (0 != err) { pthread_attr_destroy (&delete_page_attr_); gu_throw_error(err) << "Failed to set DETACHED attribute to " << "page file deletion thread"; } #endif /* GCACHE_DETACH_THREAD */ } gcache::PageStore::~PageStore () { try { while (pages_.size() && delete_page()) {}; #ifndef GCACHE_DETACH_THREAD if (delete_thr_ != pthread_t(-1)) pthread_join (delete_thr_, NULL); #endif /* GCACHE_DETACH_THREAD */ } catch (gu::Exception& e) { log_error << e.what() << " in ~PageStore()"; // abort() ? } if (pages_.size() > 0) { log_error << "Could not delete " << pages_.size() << " page files: some buffers are still \"mmapped\"."; } pthread_attr_destroy (&delete_page_attr_); } inline void* gcache::PageStore::malloc_new (ssize_t size) { void* ret = 0; try { new_page (page_size_ > size ? page_size_ : size); ret = current_->malloc (size); cleanup(); } catch (gu::Exception& e) { log_error << "Cannot create new cache page (out of disk space?): " << e.what(); // abort(); } return ret; } void* gcache::PageStore::malloc (ssize_t size) { if (gu_likely (0 != current_)) { register void* ret = current_->malloc (size); if (gu_likely(0 != ret)) return ret; current_->drop_fs_cache(); } return malloc_new (size); } void* gcache::PageStore::realloc (void* ptr, ssize_t size) { assert(ptr != 0); BufferHeader* const bh(ptr2BH(ptr)); Page* const page(static_cast(bh->ctx)); void* ret(page->realloc(ptr, size)); if (0 != ret) return ret; ret = malloc_new (size); if (gu_likely(0 != ret)) { ssize_t const ptr_size(bh->size - sizeof(BufferHeader)); memcpy (ret, ptr, size > ptr_size ? ptr_size : size); free_page_ptr (page, bh); } return ret; } percona-galera-3-3.8-3390/gcache/src/gcache_page_store.hpp000066400000000000000000000045431244131713600231440ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file page store class */ #ifndef _gcache_page_store_hpp_ #define _gcache_page_store_hpp_ #include "gcache_memops.hpp" #include "gcache_page.hpp" #include #include namespace gcache { class PageStore : public MemOps { public: PageStore (const std::string& dir_name, ssize_t keep_size, ssize_t page_size, bool keep_page); ~PageStore (); static PageStore* page_store(const Page* p) { return static_cast(p->parent()); } void* malloc (ssize_t size); void free (BufferHeader* bh) { assert(0); } void* realloc (void* ptr, ssize_t size); void discard (BufferHeader* bh) { assert(BH_is_released(bh)); assert(SEQNO_ILL == bh->seqno_g); free_page_ptr(static_cast(bh->ctx), bh); } void reset(); ssize_t count() const { return count_; } // for unit tests void set_page_size (ssize_t size) { page_size_ = size; } void set_keep_size (ssize_t size) { keep_size_ = size; } private: std::string const base_name_; /* /.../.../gcache.page. */ ssize_t keep_size_; /* how much pages to keep after freeing*/ ssize_t page_size_; /* min size of the individual page */ bool const keep_page_; /* whether to keep the last page */ ssize_t count_; std::deque pages_; Page* current_; ssize_t total_size_; pthread_attr_t delete_page_attr_; #ifndef GCACHE_DETACH_THREAD pthread_t delete_thr_; #endif /* GCACHE_DETACH_THREAD */ void new_page (ssize_t size); // returns true if a page could be deleted bool delete_page (); // cleans up extra pages. void cleanup (); void* malloc_new (ssize_t size) ; void free_page_ptr (Page* page, BufferHeader* bh) { page->free(bh); if (0 == page->used()) cleanup(); } PageStore(const gcache::PageStore&); PageStore& operator=(const gcache::PageStore&); }; } #endif /* _gcache_page_store_hpp_ */ percona-galera-3-3.8-3390/gcache/src/gcache_params.cpp000066400000000000000000000107621244131713600222720ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "GCache.hpp" static const std::string GCACHE_PARAMS_DIR ("gcache.dir"); static const std::string GCACHE_DEFAULT_DIR (""); static const std::string GCACHE_PARAMS_RB_NAME ("gcache.name"); static const std::string GCACHE_DEFAULT_RB_NAME ("galera.cache"); static const std::string GCACHE_PARAMS_MEM_SIZE ("gcache.mem_size"); static const std::string GCACHE_DEFAULT_MEM_SIZE ("0"); static const std::string GCACHE_PARAMS_RB_SIZE ("gcache.size"); static const std::string GCACHE_DEFAULT_RB_SIZE ("128M"); static const std::string GCACHE_PARAMS_PAGE_SIZE ("gcache.page_size"); static const std::string GCACHE_DEFAULT_PAGE_SIZE (GCACHE_DEFAULT_RB_SIZE); static const std::string GCACHE_PARAMS_KEEP_PAGES_SIZE("gcache.keep_pages_size"); static const std::string GCACHE_DEFAULT_KEEP_PAGES_SIZE("0"); void gcache::GCache::Params::register_params(gu::Config& cfg) { cfg.add(GCACHE_PARAMS_DIR, GCACHE_DEFAULT_DIR); cfg.add(GCACHE_PARAMS_RB_NAME, GCACHE_DEFAULT_RB_NAME); cfg.add(GCACHE_PARAMS_MEM_SIZE, GCACHE_DEFAULT_MEM_SIZE); cfg.add(GCACHE_PARAMS_RB_SIZE, GCACHE_DEFAULT_RB_SIZE); cfg.add(GCACHE_PARAMS_PAGE_SIZE, GCACHE_DEFAULT_PAGE_SIZE); cfg.add(GCACHE_PARAMS_KEEP_PAGES_SIZE, GCACHE_DEFAULT_KEEP_PAGES_SIZE); } static const std::string& name_value (gu::Config& cfg, const std::string& data_dir) { std::string dir(cfg.get(GCACHE_PARAMS_DIR)); /* fallback to data_dir if gcache dir is not set */ if (GCACHE_DEFAULT_DIR == dir && !data_dir.empty()) { dir = data_dir; cfg.set (GCACHE_PARAMS_DIR, dir); } std::string rb_name(cfg.get (GCACHE_PARAMS_RB_NAME)); /* prepend directory name to RB file name if the former is not empty and * the latter is not an absolute path */ if ('/' != rb_name[0] && !dir.empty()) { rb_name = dir + '/' + GCACHE_DEFAULT_RB_NAME; cfg.set (GCACHE_PARAMS_RB_NAME, rb_name); } return cfg.get(GCACHE_PARAMS_RB_NAME); } gcache::GCache::Params::Params (gu::Config& cfg, const std::string& data_dir) : rb_name_ (name_value (cfg, data_dir)), dir_name_ (cfg.get(GCACHE_PARAMS_DIR)), mem_size_ (cfg.get(GCACHE_PARAMS_MEM_SIZE)), rb_size_ (cfg.get(GCACHE_PARAMS_RB_SIZE)), page_size_(cfg.get(GCACHE_PARAMS_PAGE_SIZE)), keep_pages_size_(cfg.get(GCACHE_PARAMS_KEEP_PAGES_SIZE)) {} void gcache::GCache::param_set (const std::string& key, const std::string& val) { if (key == GCACHE_PARAMS_RB_NAME) { gu_throw_error(EPERM) << "Can't change ring buffer name in runtime."; } else if (key == GCACHE_PARAMS_DIR) { gu_throw_error(EPERM) << "Can't change data dir in runtime."; } else if (key == GCACHE_PARAMS_MEM_SIZE) { ssize_t tmp_size = gu::Config::from_config(val); if (tmp_size < 0) gu_throw_error(EINVAL) << "Negative memory buffer size"; gu::Lock lock(mtx); /* locking here serves two purposes: ensures atomic setting of config * and params.ram_size and syncs with malloc() method */ config.set(key, tmp_size); params.mem_size(tmp_size); mem.set_max_size(params.mem_size()); } else if (key == GCACHE_PARAMS_RB_SIZE) { gu_throw_error(EPERM) << "Can't change ring buffer size in runtime."; } else if (key == GCACHE_PARAMS_PAGE_SIZE) { ssize_t tmp_size = gu::Config::from_config(val); if (tmp_size < 0) gu_throw_error(EINVAL) << "Negative page buffer size"; gu::Lock lock(mtx); /* locking here serves two purposes: ensures atomic setting of config * and params.ram_size and syncs with malloc() method */ config.set(key, tmp_size); params.page_size(tmp_size); ps.set_page_size(params.page_size()); } else if (key == GCACHE_PARAMS_KEEP_PAGES_SIZE) { ssize_t tmp_size = gu::Config::from_config(val); if (tmp_size < 0) gu_throw_error(EINVAL) << "Negative keep pages size"; gu::Lock lock(mtx); /* locking here serves two purposes: ensures atomic setting of config * and params.ram_size and syncs with malloc() method */ config.set(key, tmp_size); params.keep_pages_size(tmp_size); ps.set_keep_size(params.keep_pages_size()); } else { throw gu::NotFound(); } } percona-galera-3-3.8-3390/gcache/src/gcache_rb_store.cpp000066400000000000000000000340341244131713600226240ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ #include "gcache_rb_store.hpp" #include "gcache_page_store.hpp" #include "gcache_mem_store.hpp" #include #include namespace gcache { static size_t check_size (ssize_t s) { if (s < 0) gu_throw_error(EINVAL) << "Negative cache file size: " << s; return s + RingBuffer::pad_size() + sizeof(BufferHeader); } void RingBuffer::reset() { first_ = start_; next_ = start_; BH_clear (BH_cast(next_)); size_free_ = size_cache_; size_used_ = 0; size_trail_= 0; // mallocs_ = 0; // reallocs_ = 0; } void RingBuffer::constructor_common() {} RingBuffer::RingBuffer (const std::string& name, ssize_t size, std::map & seqno2ptr) : fd_ (name, check_size(size)), mmap_ (fd_), open_ (true), preamble_ (static_cast(mmap_.ptr)), header_ (reinterpret_cast(preamble_ + PREAMBLE_LEN)), start_ (reinterpret_cast(header_ + HEADER_LEN)), end_ (reinterpret_cast(preamble_ + mmap_.size)), first_ (start_), next_ (first_), size_cache_(end_ - start_ - sizeof(BufferHeader)), size_free_ (size_cache_), size_used_ (0), size_trail_(0), // mallocs_ (0), // reallocs_ (0), seqno2ptr_ (seqno2ptr) { constructor_common (); BH_clear (BH_cast(next_)); } RingBuffer::~RingBuffer () { open_ = false; mmap_.sync(); mmap_.unmap(); } /* discard all seqnos preceeding and including seqno */ bool RingBuffer::discard_seqno (int64_t seqno) { for (seqno2ptr_t::iterator i = seqno2ptr_.begin(); i != seqno2ptr_.end() && i->first <= seqno;) { seqno2ptr_t::iterator j(i); ++i; BufferHeader* const bh (ptr2BH (j->second)); if (gu_likely (BH_is_released(bh))) { seqno2ptr_.erase (j); bh->seqno_g = SEQNO_ILL; // will never be accessed by seqno switch (bh->store) { case BUFFER_IN_RB: discard(bh); break; case BUFFER_IN_MEM: { MemStore* const ms(static_cast(bh->ctx)); ms->discard(bh); break; } case BUFFER_IN_PAGE: { Page* const page (static_cast(bh->ctx)); PageStore* const ps (PageStore::page_store(page)); ps->discard(bh); break; } default: log_fatal << "Corrupt buffer header: " << bh; abort(); } } else { return false; } } return true; } // returns pointer to buffer data area or 0 if no space found BufferHeader* RingBuffer::get_new_buffer (ssize_t const size) { assert_size_free(); assert (size > 0); BH_assert_clear(BH_cast(next_)); uint8_t* ret(next_); ssize_t const size_next (size + sizeof(BufferHeader)); if (ret >= first_) { assert (0 == size_trail_); // try to find space at the end ssize_t const end_size(end_ - ret); if (end_size >= size_next) { assert(size_free_ >= size); goto found_space; } else { // no space at the end, go from the start size_trail_ = end_size; ret = start_; } } assert (ret <= first_); if ((first_ - ret) >= size_next) { assert(size_free_ >= size); } while ((first_ - ret) < size_next) { // try to discard first buffer to get more space BufferHeader* bh = BH_cast(first_); if (!BH_is_released(bh) /* true also when first_ == next_ */ || (bh->seqno_g > 0 && !discard_seqno (bh->seqno_g))) { // can't free any more space, so no buffer, next_ is unchanged // and revert size_trail_ if it was set above if (next_ >= first_) size_trail_ = 0; assert_sizes(); return 0; } assert (first_ != next_); /* buffer is either discarded already, or it must have seqno */ assert (SEQNO_ILL == bh->seqno_g); first_ += bh->size; assert_size_free(); if (gu_unlikely(0 == (BH_cast(first_))->size)) { // empty header: check if we fit at the end and roll over if not assert(first_ >= next_); assert(first_ >= ret); first_ = start_; // WRONG if (first_ != ret) size_trail_ = 0; // we're now contiguous: first_ < next_ assert_size_free(); if ((end_ - ret) >= size_next) { assert(size_free_ >= size); size_trail_ = 0; goto found_space; } else { size_trail_ = end_ - ret; ret = start_; } } } #ifndef NDEBUG if ((first_ - ret) < size_next) { log_fatal << "Assertion ((first - ret) >= size_next) failed: " << std::endl << "first offt = " << (first_ - start_) << std::endl << "next offt = " << (next_ - start_) << std::endl << "end offt = " << (end_ - start_) << std::endl << "ret offt = " << (ret - start_) << std::endl << "size_next = " << size_next << std::endl; abort(); } #endif found_space: size_used_ += size; assert (size_used_ <= size_cache_); size_free_ -= size; assert (size_free_ >= 0); BufferHeader* const bh(BH_cast(ret)); bh->size = size; bh->seqno_g = SEQNO_NONE; bh->seqno_d = SEQNO_ILL; bh->flags = 0; bh->store = BUFFER_IN_RB; bh->ctx = this; next_ = ret + size; assert (next_ + sizeof(BufferHeader) <= end_); BH_clear (BH_cast(next_)); assert_sizes(); return bh; } void* RingBuffer::malloc (ssize_t size) { void* ret(0); // We can reliably allocate continuous buffer which is 1/2 // of a total cache space. So compare to half the space if (size <= (size_cache_ / 2) && size <= (size_cache_ - size_used_)) { BufferHeader* const bh (get_new_buffer (size)); BH_assert_clear(BH_cast(next_)); // mallocs_++; if (gu_likely (0 != bh)) ret = bh + 1; } assert_sizes(); return ret; // "out of memory" } void RingBuffer::free (BufferHeader* const bh) { assert(BH_is_released(bh)); size_used_ -= bh->size; assert(size_used_ >= 0); if (SEQNO_NONE == bh->seqno_g) { bh->seqno_g = SEQNO_ILL; discard (bh); } } void* RingBuffer::realloc (void* ptr, ssize_t const size) { assert_sizes(); assert (NULL != ptr); assert (size > 0); // We can reliably allocate continuous buffer which is twice as small // as total cache area. So compare to half the space if (size > (size_cache_ / 2)) return 0; BufferHeader* const bh(ptr2BH(ptr)); // reallocs_++; // first check if we can grow this buffer by allocating // adjacent buffer { ssize_t const adj_size(size - bh->size); if (adj_size <= 0) return ptr; uint8_t* const adj_ptr(reinterpret_cast(BH_next(bh))); if (adj_ptr == next_) { ssize_t const size_trail_saved(size_trail_); void* const adj_buf (get_new_buffer (adj_size)); BH_assert_clear(BH_cast(next_)); if (adj_ptr == adj_buf) { bh->size = next_ - static_cast(ptr) + sizeof(BufferHeader); return ptr; } else // adjacent buffer allocation failed, return it back { next_ = adj_ptr; BH_clear (BH_cast(next_)); size_used_ -= adj_size; size_free_ += adj_size; if (next_ < first_) size_trail_ = size_trail_saved; } } } BH_assert_clear(BH_cast(next_)); assert_sizes(); // find non-adjacent buffer void* ptr_new = malloc (size); if (ptr_new != 0) { memcpy (ptr_new, ptr, bh->size - sizeof(BufferHeader)); free (bh); } BH_assert_clear(BH_cast(next_)); assert_sizes(); return ptr_new; } void RingBuffer::seqno_reset() { if (size_cache_ == size_free_) return; /* Find the last seqno'd RB buffer. It is likely to be close to the * end of released buffers chain. */ BufferHeader* bh(0); for (seqno2ptr_t::reverse_iterator r(seqno2ptr_.rbegin()); r != seqno2ptr_.rend(); ++r) { BufferHeader* const b(ptr2BH(r->second)); if (BUFFER_IN_RB == b->store) { #ifndef NDEBUG if (!BH_is_released(b)) { log_fatal << "Buffer " << reinterpret_cast(r->second) << ", seqno_g " << b->seqno_g << ", seqno_d " << b->seqno_d << " is not released."; assert(0); } #endif bh = b; break; } } if (!bh) return; assert(bh->size > 0); assert(BH_is_released(bh)); /* Seek the first unreleased buffer. * This should be called in isolation, when all seqno'd buffers are * freed, and the only unreleased buffers should come only from new * configuration. There should be no seqno'd buffers after it. */ ssize_t const old(size_free_); assert (0 == size_trail_ || first_ > next_); first_ = reinterpret_cast(bh); while (BH_is_released(bh)) // next_ is never released - no endless loop { first_ = reinterpret_cast(BH_next(bh)); if (gu_unlikely (0 == bh->size && first_ != next_)) { // rollover assert (first_ > next_); first_ = start_; } bh = BH_cast(first_); } BH_assert_clear(BH_cast(next_)); if (first_ == next_) { log_info << "GCache DEBUG: RingBuffer::seqno_reset(): full reset"; /* empty RB, reset it completely */ reset(); return; } assert ((BH_cast(first_))->size > 0); assert (first_ != next_); assert ((BH_cast(first_))->seqno_g == SEQNO_NONE); assert (!BH_is_released(BH_cast(first_))); /* Estimate how much space remains */ if (first_ < next_) { /* start_ first_ next_ end_ * | |###########| | */ size_used_ = next_ - first_; size_free_ = size_cache_ - size_used_; size_trail_ = 0; } else { /* start_ next_ first_ end_ * |#######| |#####| | * ^size_trail_ */ assert(size_trail_ > 0); size_free_ = first_ - next_ + size_trail_ - sizeof(BufferHeader); size_used_ = size_cache_ - size_free_; } assert_sizes(); assert(size_free_ < size_cache_); log_info << "GCache DEBUG: RingBuffer::seqno_reset(): discarded " << (size_free_ - old) << " bytes"; /* There is a small but non-0 probability that some released buffers * are locked within yet unreleased aborted local actions. * Seek all the way to next_, invalidate seqnos and update size_free_ */ assert(first_ != next_); assert(bh == BH_cast(first_)); long total(1); long locked(0); bh = BH_next(bh); while (bh != BH_cast(next_)) { if (gu_likely (bh->size > 0)) { total++; if (bh->seqno_g != SEQNO_NONE) { // either released or already discarded buffer assert (BH_is_released(bh)); bh->seqno_g = SEQNO_ILL; discard (bh); locked++; } else { assert(!BH_is_released(bh)); } bh = BH_next(bh); } else // rollover { assert (BH_cast(next_) < bh); bh = BH_cast(start_); } } log_info << "GCache DEBUG: RingBuffer::seqno_reset(): found " << locked << '/' << total << " locked buffers"; assert_sizes(); } void RingBuffer::print (std::ostream& os) const { os << "\nstart_ : " << reinterpret_cast(start_) << "\nend_ : " << reinterpret_cast(end_) << "\nfirst : " << first_ - start_ << "\nnext : " << next_ - start_ << "\nsize : " << size_cache_ << "\nfree : " << size_free_ << "\nused : " << size_used_; } } percona-galera-3-3.8-3390/gcache/src/gcache_rb_store.hpp000066400000000000000000000074251244131713600226350ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy */ /*! @file ring buffer storage class */ #ifndef _gcache_rb_store_hpp_ #define _gcache_rb_store_hpp_ #include "gcache_memops.hpp" #include "gcache_bh.hpp" #include "gu_fdesc.hpp" #include "gu_mmap.hpp" #include #include #include namespace gcache { class RingBuffer : public MemOps { public: RingBuffer (const std::string& name, ssize_t size, std::map& seqno2ptr); ~RingBuffer (); void* malloc (ssize_t size); void free (BufferHeader* bh); void* realloc (void* ptr, ssize_t size); void discard (BufferHeader* const bh) { assert (BH_is_released(bh)); assert (SEQNO_ILL == bh->seqno_g); size_free_ += bh->size; assert (size_free_ <= size_cache_); } ssize_t size () const { return size_cache_; } ssize_t rb_size () const { return fd_.size(); } const std::string& rb_name() const { return fd_.name(); } void reset(); void seqno_reset(); /* returns true when successfully discards all seqnos up to s */ bool discard_seqno (int64_t s); void print (std::ostream& os) const; static ssize_t pad_size() { RingBuffer* rb(0); // cppcheck-suppress nullPointer return (PREAMBLE_LEN * sizeof(*(rb->preamble_)) + // cppcheck-suppress nullPointer HEADER_LEN * sizeof(*(rb->header_))); } void assert_size_free() const { #ifndef NDEBUG if (next_ >= first_) { /* start_ first_ next_ end_ * | |###########| | */ assert(size_free_ >= (size_cache_ - (next_ - first_))); } else { /* start_ next_ first_ end_ * |#######| |#####| | */ assert(size_free_ >= (first_ - next_)); } assert (size_free_ <= size_cache_); #endif } void assert_size_trail() const { #ifndef NDEBUG if (next_ >= first_) assert(0 == size_trail_); else assert(size_trail_ >= ssize_t(sizeof(BufferHeader))); #endif } void assert_sizes() const { assert_size_trail(); assert_size_free(); } private: static ssize_t const PREAMBLE_LEN = 1024; static ssize_t const HEADER_LEN = 32; gu::FileDescriptor fd_; gu::MMap mmap_; bool open_; char* const preamble_; // ASCII text preamble int64_t* const header_; // cache binary header uint8_t* const start_; // start of cache area uint8_t* const end_; // first byte after cache area uint8_t* first_; // pointer to the first (oldest) buffer uint8_t* next_; // pointer to the next free space ssize_t const size_cache_; ssize_t size_free_; ssize_t size_used_; ssize_t size_trail_; typedef std::map seqno2ptr_t; seqno2ptr_t& seqno2ptr_; BufferHeader* get_new_buffer (ssize_t size); void constructor_common(); RingBuffer(const gcache::RingBuffer&); RingBuffer& operator=(const gcache::RingBuffer&); }; inline std::ostream& operator<< (std::ostream& os, const RingBuffer& rb) { rb.print(os); return os; } } /* namespace gcache */ #endif /* _gcache_rb_store_hpp_ */ percona-galera-3-3.8-3390/gcache/src/pasture/000077500000000000000000000000001244131713600204665ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/src/pasture/Cond.hpp000066400000000000000000000014251244131713600220640ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef __GCACHE_COND__ #define __GCACHE_COND__ #include #include #include namespace gcache { class Cond { friend class Lock; protected: pthread_cond_t cond; long ref_count; public: Cond () throw() : ref_count(0) { pthread_cond_init (&cond, NULL); }; ~Cond () { while (EBUSY == pthread_cond_destroy(&cond)) { usleep (100); }; }; inline void signal () { if (ref_count > 0) pthread_cond_signal (&cond); } inline void broadcast () { if (ref_count > 0) pthread_cond_broadcast (&cond); } }; } #endif percona-galera-3-3.8-3390/gcache/src/pasture/Exception.cpp000066400000000000000000000010151244131713600231250ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #include #include "Exception.hpp" namespace gcache { Exception::Exception (const char* msg_str, int errno) throw() : _errno(errno) { strncpy (msg, msg_str, EXCEPTION_MSG_SIZE); msg[EXCEPTION_MSG_SIZE - 1] = '\0'; } ///* Exception::Exception (const char* msg_str) throw() : _errno(0) { strncpy (msg, msg_str, EXCEPTION_MSG_SIZE); msg[EXCEPTION_MSG_SIZE - 1] = '\0'; } //*/ } percona-galera-3-3.8-3390/gcache/src/pasture/Exception.hpp000066400000000000000000000012151244131713600231340ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GCACHE_EXCEPTION__ #define __GCACHE_EXCEPTION__ #include namespace gcache { class Exception: public std::exception { private: #define EXCEPTION_MSG_SIZE 256 char msg[EXCEPTION_MSG_SIZE]; const int _errno; public: Exception (const char* msg_str, int) throw(); Exception (const char* msg_str) throw(); virtual ~Exception () throw() {}; virtual const char* what () const throw() { return msg; }; int get_errno () const throw() { return _errno; }; }; } #endif // __GCACHE_EXCEPTION__ percona-galera-3-3.8-3390/gcache/src/pasture/Lock.hpp000066400000000000000000000020021244131713600220610ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GCACHE_LOCK__ #define __GCACHE_LOCK__ #include #include #include "Exception.hpp" #include #include "Mutex.hpp" #include "Cond.hpp" namespace gcache { class Lock { private: pthread_mutex_t* value; public: Lock (Mutex& mtx) { value = &mtx.value; int err = pthread_mutex_lock (value); if (err) { std::string msg = "Mutex lock failed: "; msg = msg + strerror(err); throw Exception(msg.c_str(), err); } }; virtual ~Lock () { pthread_mutex_unlock (value); log_debug << "Unlocked mutex " << value; }; inline void wait (Cond& cond) { cond.ref_count++; pthread_cond_wait (&(cond.cond), value); cond.ref_count--; }; }; } #endif /* __GCACHE_LOCK__ */ percona-galera-3-3.8-3390/gcache/src/pasture/Logger.cpp000066400000000000000000000041211244131713600224070ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 */ #include #include #include #include #include "Logger.hpp" namespace gcache { void Logger::enable_tstamp (bool yes) { do_timestamp = yes; } void Logger::enable_debug (bool yes) { if (yes) { max_level = LOG_DEBUG; } else { max_level = LOG_INFO; } } void Logger::default_logger (int lvl, const char* msg) { fputs (msg, stderr); fflush (stderr); } void Logger::set_logger (LogCallback cb) { if (0 == cb) { logger = default_logger; } else { logger = cb; } } static const char* level_str[LOG_MAX] = { "FATAL: ", "ERROR: ", " WARN: ", " INFO: ", "DEBUG: " }; void Logger::prepare_default() { if (do_timestamp) { using namespace std; struct tm date; struct timeval time; gettimeofday (&time, NULL); localtime_r (&time.tv_sec, &date); // save original format flags // ios_base::fmtflags original_flags = os.flags(); os << date.tm_year + 1900 << '-' << setw(2) << setfill('0') << date.tm_mon + 1 << '-' << setw(2) << setfill('0') << date.tm_mday << ' ' << setw(2) << setfill('0') << date.tm_hour << ':' << setw(2) << setfill('0') << date.tm_min << ':' << setw(2) << setfill('0') << date.tm_sec << '.' << setw(3) << setfill('0') << ((int)time.tv_usec / 1000) << ' '; // restore original format flags // os.flags(original_flags); } os << level_str[level]; } bool Logger::do_timestamp = false; LogLevel Logger::max_level = LOG_INFO; LogCallback Logger::logger = default_logger; } percona-galera-3-3.8-3390/gcache/src/pasture/Logger.hpp000066400000000000000000000055751244131713600224320ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * This code is based on an excellent article at Dr.Dobb's: * http://www.ddj.com/cpp/201804215?pgno=1 */ #ifndef __GCACHE_LOGGER__ #define __GCACHE_LOGGER__ #include //#include namespace gcache { // some portability stuff #ifdef WSREP_H enum LogLevel { LOG_FATAL = WSREP_LOG_FATAL, LOG_ERROR = WSREP_LOG_ERROR, LOG_WARN = WSREP_LOG_WARN, LOG_INFO = WSREP_LOG_INFO, LOG_DEBUG = WSREP_LOG_DEBUG, LOG_MAX }; typedef wsrep_log_cb_t LogCallback; #else enum LogLevel { LOG_FATAL, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_MAX }; typedef void (*LogCallback) (int, const char*); #endif class Logger { public: Logger() {}; virtual inline ~Logger(); // this function returns a stream for further logging. // std::ostringstream& get(TLogLevel level = logINFO); inline std::ostringstream& get(const LogLevel lvl, const char* file, const char* func, const int line); public: static void enable_tstamp (bool); static void enable_debug (bool); static void set_logger (LogCallback); static inline bool no_log (LogLevel lvl) { return (lvl > max_level); }; protected: std::ostringstream os; private: Logger(const Logger&); Logger& operator =(const Logger&); private: static LogLevel max_level; static bool do_timestamp; static LogCallback logger; static void default_logger (int, const char*); void prepare_default (); LogLevel level; }; Logger::~Logger() { os << std::endl; logger (level, os.str().c_str()); } std::ostringstream& Logger::get(const LogLevel lvl, const char* file, const char* func, const int line) { // fancy original stuff // os << std::string(level > logDEBUG ? 0 : level - logDEBUG, '\t'); level = lvl; if (logger == default_logger) { // put in timestamp and log level line prepare_default(); } return os; } } #define LOG(level) \ if (Logger::no_log(level)) ; \ else Logger().get(level, __FILE__, __PRETTY_FUNCTION__, __LINE__) #define log_fatal LOG(LOG_FATAL) #define log_error LOG(LOG_ERROR) #define log_warn LOG(LOG_WARN) #define log_info LOG(LOG_INFO) #define log_debug LOG(LOG_DEBUG) #endif // __GCACHE_LOGGER__ percona-galera-3-3.8-3390/gcache/src/pasture/Mutex.hpp000066400000000000000000000015171244131713600223050ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * */ #ifndef __GCACHE_MUTEX__ #define __GCACHE_MUTEX__ #include #include #include "Exception.hpp" #include namespace gcache { class Mutex { friend class Lock; protected: pthread_mutex_t value; public: Mutex () { pthread_mutex_init (&value, NULL); }; virtual ~Mutex () { int err = pthread_mutex_destroy (&value); if (gu_unlikely(err != 0)) { log_fatal << "pthread_mutex_destroy() failed: " << err << " (" << strerror(err) << "). Aborting."; ::abort(); } log_debug << "Destroyed mutex " << &value; }; }; } #endif /* __GCACHE_MUTEX__ */ percona-galera-3-3.8-3390/gcache/src/pasture/gcache_rb_header.cpp000066400000000000000000000135251244131713600244050ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #include "gcache_rb_header.hpp" #include #include #include #include namespace gcache { enum records { HEADER_LEN = 0, HEADER_VERSION, FILE_OPEN, FILE_SIZE, DATA_OFFSET, FIRST_OFFSET, NEXT_OFFSET, SEQNO_MIN, SEQNO_MAX }; void RingBuffer::header_read () { std::ostringstream error; error << "Can't load gcache data file: "; if (version != static_cast(header[HEADER_VERSION])) { error << "unsupported version: " << header[HEADER_VERSION]; throw gu::Exception (error.str().c_str(), ECANCELED); } if (mmap.size != static_cast(header[FILE_SIZE])) { error << "file size does not match, declared: " << header[FILE_SIZE] << ", real: " << mmap.size; throw gu::Exception (error.str().c_str(), ECANCELED); } ssize_t data_offset = start - static_cast(mmap.ptr); if (data_offset != header[DATA_OFFSET]) { error << "data offset " << header[DATA_OFFSET] << " does not match derived: " << data_offset; throw gu::Exception (error.str().c_str(), ECANCELED); } if (true == header[FILE_OPEN]) { log_warn << "Gcache data file was not gracefully closed, " << "discarding data."; reset_cache (); return; } if (size_cache <= header[FIRST_OFFSET]) { log_warn << "Bogus first buffer offset, discarding data."; reset_cache (); return; } if (size_cache <= header[NEXT_OFFSET]) { log_warn << "Bogus next buffer offset, discarding data."; reset_cache (); return; } seqno_min = header[SEQNO_MIN]; seqno_max = header[SEQNO_MAX]; if ((seqno_min == SEQNO_NONE && seqno_max != SEQNO_NONE) || (seqno_min != SEQNO_NONE && seqno_max == SEQNO_NONE)) { log_warn << "Inconsistent seqno's: " << seqno_min << ", " << seqno_max << ", discarding data."; reset_cache (); return; } if (seqno_min > seqno_max) { log_warn << "Minimum seqno > maximum seqno (" << seqno_min << " > " << seqno_max << "), discarding data."; reset_cache (); return; } first = start + header[FIRST_OFFSET]; next = start + header[NEXT_OFFSET]; /* Validate all buffers and populate seqno map */ log_info << "Validating cached buffers..."; uint8_t* buf = first; BufferHeader* bh = reinterpret_cast(buf); while (bh->size > 0) { if (bh->seqno != SEQNO_NONE) { seqno2ptr.insert (std::pair(bh->seqno, bh + 1)); } if (!BH_is_released (bh)) { log_warn << "Unreleased buffer found. Releasing."; BH_release (bh); } buf += bh->size; if (buf > (end - sizeof(BufferHeader))) break; bh = reinterpret_cast(buf); if (0 == bh->size && buf != next) { // buffer list continues from the beginning buf = start; bh = reinterpret_cast(buf); } } if (buf != next) { log_warn << "Cache metadata corrupted: failed to validate " << "allocated buffers. Discarding data."; reset_cache(); return; } log_info << "Validating cached buffers done."; if (seqno_min != SEQNO_NONE) { log_info << "Checking for gaps in sequence numbers..."; for (int64_t seqno = seqno_min; seqno <= seqno_max; seqno++) { if (seqno2ptr.find(seqno) == seqno2ptr.end()) { log_warn << "Discontinuity in sequence numbers: " << seqno << " is missing. Discarding data."; reset_cache(); return; } } log_info << "Checking for gaps in sequence numbers..."; } } void RingBuffer::header_write () { header[HEADER_LEN] = header_len; header[HEADER_VERSION] = version; header[FILE_OPEN] = open; header[FILE_SIZE] = mmap.size; header[DATA_OFFSET] = start - static_cast(mmap.ptr); header[FIRST_OFFSET] = first - start; header[NEXT_OFFSET] = next - start; header[SEQNO_MIN] = seqno_min; header[SEQNO_MAX] = seqno_max; } void RingBuffer::preamble_write () { std::ostringstream pstream; pstream << "* GCache data file *" << std::endl << "--------------------" << std::endl << "Version : " << header[HEADER_VERSION] << std::endl << "Size : " << header[FILE_SIZE] << "bytes" << std::endl << "Closed : " << (header[FILE_OPEN]?"no":"yes") << std::endl << "Data offset : " << header[DATA_OFFSET] << std::endl << "First buffer : " << header[FIRST_OFFSET] << std::endl << "Next buffer : " << header[NEXT_OFFSET] << std::endl << "Min. seqno : " << header[SEQNO_MIN] << std::endl << "Max. seqno : " << header[SEQNO_MAX] << std::endl << "Ordered buffers : " << (header[SEQNO_MAX] - header[SEQNO_MIN]) << std::endl << "--------------------" << std::endl; strncpy (preamble, pstream.str().c_str(), PREAMBLE_LEN - 1); preamble[PREAMBLE_LEN - 1] = '\0'; } } percona-galera-3-3.8-3390/gcache/src/test.cpp000066400000000000000000000017141244131713600204710ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * */ #include #include "GCache.hpp" using namespace gcache; int main (int argc, char* argv[]) { int ret = 0; std::string fname = "test.cache"; gu_conf_self_tstamp_on (); gu_conf_debug_on (); log_info << "Start"; log_debug << "DEBUG output enabled"; if (argc > 1) fname.assign(argv[1]); // take supplied file name if any gu::Config conf; GCache::register_params(conf); conf.parse("gcache.name = test.cache; gcache.size = 16K"); GCache* cache = new GCache (conf, ""); log_info << ""; log_info << "...do something..."; log_info << ""; delete cache; log_info << "Exit: " << ret; try { throw gu::Exception ("My test exception", EINVAL); } catch (gu::Exception& e) { log_info << "Exception caught: " << e.what() << ", errno: " << e.get_errno(); } return ret; } percona-galera-3-3.8-3390/gcache/tests/000077500000000000000000000000001244131713600173565ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcache/tests/SConscript000066400000000000000000000011261244131713600213700ustar00rootroot00000000000000 Import('check_env') env = check_env.Clone() env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) env.Prepend(LIBS=File('#/gcache/src/libgcache.a')) gcache_tests = env.Program(target = 'gcache_tests', source = Glob('*.cpp')) # source = Split(''' # gcache_tests.cpp # ''')) stamp="gcache_tests.passed" env.Test(stamp, gcache_tests) env.Alias("test", stamp) Clean(gcache_tests, ['#/gcache_tests.log', '#/gcache.page.000000', '#/rb_test']) percona-galera-3-3.8-3390/gcache/tests/gcache_mem_test.cpp000066400000000000000000000037541244131713600232020ustar00rootroot00000000000000/* * Copyright (C) 2011-2014 Codership Oy * * $Id$ */ #include "gcache_mem_store.hpp" #include "gcache_bh.hpp" #include "gcache_mem_test.hpp" using namespace gcache; START_TEST(test1) { ssize_t const bh_size (sizeof(gcache::BufferHeader)); ssize_t const mem_size (3 + 2*bh_size); std::map s2p; MemStore ms(mem_size, s2p); void* buf1 = ms.malloc (1 + bh_size); fail_if (NULL == buf1); BufferHeader* bh1(ptr2BH(buf1)); fail_if (bh1->seqno_g != SEQNO_NONE); fail_if (BH_is_released(bh1)); void* buf2 = ms.malloc (1 + bh_size); fail_if (NULL == buf2); fail_if (buf1 == buf2); void* buf3 = ms.malloc (1 + bh_size); fail_if (NULL != buf3); buf1 = ms.realloc (buf1, 2 + bh_size); fail_if (NULL == buf1); bh1 = ptr2BH(buf1); fail_if (bh1->seqno_g != SEQNO_NONE); fail_if (BH_is_released(bh1)); BufferHeader* bh2(ptr2BH(buf2)); fail_if (bh2->seqno_g != SEQNO_NONE); fail_if (BH_is_released(bh2)); bh2->seqno_g = 1; /* freeing seqno'd buffer should only release it, but not discard */ BH_release(bh2); ms.free (bh2); fail_if (!BH_is_released(bh2)); buf3 = ms.malloc (1 + bh_size); fail_if (NULL != buf3); /* discarding a buffer should finally free some space for another */ ms.discard(bh2); buf3 = ms.malloc (1 + bh_size); fail_if (NULL == buf3); /* freeing unseqno'd buffer should free space immeditely */ bh1 = ptr2BH(buf1); BH_release(bh1); ms.free (bh1); void* buf4 = ms.malloc (2 + bh_size); fail_if (NULL == buf4); BufferHeader* bh3(ptr2BH(buf3)); BH_release(bh3); ms.free (bh3); BufferHeader* bh4(ptr2BH(buf4)); BH_release(bh4); ms.free (bh4); fail_if (ms._allocd()); } END_TEST Suite* gcache_mem_suite() { Suite* s = suite_create("gcache::MemStore"); TCase* tc; tc = tcase_create("test"); tcase_add_test(tc, test1); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/gcache/tests/gcache_mem_test.hpp000066400000000000000000000003631244131713600232000ustar00rootroot00000000000000/* * Copyright (C) 2011 Codership Oy * * $Id$ */ #ifndef __gcache_mem_test_hpp__ #define __gcache_mem_test_hpp__ extern "C" { #include } extern Suite* gcache_mem_suite(); #endif // __gcache_mem_test_hpp__ percona-galera-3-3.8-3390/gcache/tests/gcache_page_test.cpp000066400000000000000000000045331244131713600233340ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy * * $Id$ */ #include "gcache_page_store.hpp" #include "gcache_bh.hpp" #include "gcache_page_test.hpp" using namespace gcache; void ps_free (void* ptr) { BufferHeader* const bh(ptr2BH(ptr)); BH_release (bh); bh->seqno_g = SEQNO_ILL; } START_TEST(test1) { const char* const dir_name = ""; ssize_t const bh_size = sizeof(gcache::BufferHeader); ssize_t const keep_size = 1; ssize_t const page_size = 2 + bh_size; gcache::PageStore ps (dir_name, keep_size, page_size, false); mark_point(); void* buf = ps.malloc (3 + bh_size); fail_if (0 == buf); void* tmp = ps.realloc (buf, 2 + bh_size); fail_if (buf != tmp); tmp = ps.realloc (buf, 4 + bh_size); // here new page should be allocated fail_if (0 == tmp); fail_if (buf == tmp); ps_free(tmp); ps.discard (ptr2BH(tmp)); } END_TEST START_TEST(test2) { const char* const dir_name = ""; ssize_t const bh_size = sizeof(gcache::BufferHeader); ssize_t const keep_size = 1; ssize_t page_size = (1 << 20) + bh_size; gcache::PageStore ps (dir_name, keep_size, page_size, false); mark_point(); uint8_t* buf = static_cast(ps.malloc (page_size)); fail_if (0 == buf); while (--page_size) { buf[page_size] = page_size; } mark_point(); ps_free(buf); ps.discard (ptr2BH(buf)); } END_TEST START_TEST(test3) // check that all page size is efficiently used { const char* const dir_name = ""; ssize_t const keep_size = 1; ssize_t const page_size = 1024; gcache::PageStore ps (dir_name, keep_size, page_size, false); mark_point(); ssize_t ptr_size = (page_size / 2); void* ptr1 = ps.malloc (ptr_size); fail_if (0 == ptr1); void* ptr2 = ps.malloc (ptr_size); fail_if (0 == ptr2); fail_if (ps.count() != 1, "ps.count() = %zd, expected 1", ps.count()); // check that ptr2 is adjacent to ptr1 void* tmp = static_cast(ptr1) + ptr_size; fail_if (tmp != ptr2, "tmp = %p, ptr2 = %p", tmp, ptr2); } END_TEST Suite* gcache_page_suite() { Suite* s = suite_create("gcache::PageStore"); TCase* tc; tc = tcase_create("test"); tcase_add_test(tc, test1); tcase_add_test(tc, test2); tcase_add_test(tc, test3); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/gcache/tests/gcache_page_test.hpp000066400000000000000000000003671244131713600233420ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy * * $Id$ */ #ifndef __gcache_page_test_hpp__ #define __gcache_page_test_hpp__ extern "C" { #include } extern Suite* gcache_page_suite(); #endif // __gcache_page_test_hpp__ percona-galera-3-3.8-3390/gcache/tests/gcache_rb_test.cpp000066400000000000000000000041261244131713600230210ustar00rootroot00000000000000/* * Copyright (C) 2011-2014 Codership Oy * * $Id$ */ #include "gcache_rb_store.hpp" #include "gcache_bh.hpp" #include "gcache_rb_test.hpp" using namespace gcache; START_TEST(test1) { std::string const rb_name = "rb_test"; ssize_t const bh_size = sizeof(gcache::BufferHeader); ssize_t const rb_size (4 + 2*bh_size); std::map s2p; RingBuffer rb(rb_name, rb_size, s2p); fail_if (rb.size() != rb_size, "Expected %zd, got %zd", rb_size, rb.size()); void* buf1 = rb.malloc (3 + bh_size); fail_if (NULL != buf1); // > 1/2 size buf1 = rb.malloc (1 + bh_size); fail_if (NULL == buf1); BufferHeader* bh1(ptr2BH(buf1)); fail_if (bh1->seqno_g != SEQNO_NONE); fail_if (BH_is_released(bh1)); void* buf2 = rb.malloc (2 + bh_size); fail_if (NULL == buf2); fail_if (BH_is_released(bh1)); BufferHeader* bh2(ptr2BH(buf2)); fail_if (bh2->seqno_g != SEQNO_NONE); fail_if (BH_is_released(bh2)); void* tmp = rb.realloc (buf1, 2 + bh_size); fail_if (bh2->seqno_g != SEQNO_NONE); fail_if (NULL != tmp); BH_release(bh2); rb.free (bh2); tmp = rb.realloc (buf1, 2 + bh_size); fail_if (NULL != tmp); BH_release(bh1); rb.free (bh1); fail_if (!BH_is_released(bh1)); buf1 = rb.malloc (1 + bh_size); fail_if (NULL == buf1); tmp = rb.realloc (buf1, 2 + bh_size); fail_if (NULL == tmp); fail_if (tmp != buf1); buf2 = rb.malloc (1 + bh_size); fail_if (NULL == buf2); tmp = rb.realloc (buf2, 2 + bh_size); fail_if (NULL == tmp); fail_if (tmp != buf2); tmp = rb.malloc (1 + bh_size); fail_if (NULL != tmp); BH_release(ptr2BH(buf1)); rb.free(ptr2BH(buf1)); BH_release(ptr2BH(buf2)); rb.free(ptr2BH(buf2)); tmp = rb.malloc (2 + bh_size); fail_if (NULL == tmp); mark_point(); } END_TEST Suite* gcache_rb_suite() { Suite* ts = suite_create("gcache::RbStore"); TCase* tc = tcase_create("test"); tcase_set_timeout(tc, 60); tcase_add_test(tc, test1); suite_add_tcase(ts, tc); return ts; } percona-galera-3-3.8-3390/gcache/tests/gcache_rb_test.hpp000066400000000000000000000003571244131713600230300ustar00rootroot00000000000000/* * Copyright (C) 2011 Codership Oy * * $Id$ */ #ifndef __gcache_rb_test_hpp__ #define __gcache_rb_test_hpp__ extern "C" { #include } extern Suite* gcache_rb_suite(); #endif // __gcache_rb_test_hpp__ percona-galera-3-3.8-3390/gcache/tests/gcache_tests.cpp000066400000000000000000000016571244131713600225270ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy #include #include #include extern "C" { #include } #include "gcache_tests.hpp" int main(int argc, char* argv[]) { bool no_fork = (argc >= 2 && std::string(argv[1]) == "nofork"); FILE* log_file = 0; if (!no_fork) { log_file = fopen (LOG_FILE, "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); } gu_conf_debug_on(); int failed = 0; for (int i = 0; suites[i] != 0; ++i) { SRunner* sr = srunner_create(suites[i]()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all(sr, CK_NORMAL); failed += srunner_ntests_failed(sr); srunner_free(sr); } if (log_file != 0) fclose(log_file); printf ("Total tests failed: %d\n", failed); return failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } percona-galera-3-3.8-3390/gcache/tests/gcache_tests.hpp000066400000000000000000000010431244131713600225210ustar00rootroot00000000000000// Copyright (C) 2010-2011 Codership Oy // $Id$ /*! * @file: package specific part of the main test file. */ #ifndef __gcache_tests_hpp__ #define __gcache_tests_hpp__ #define LOG_FILE "gcache_tests.log" #include "gcache_mem_test.hpp" #include "gcache_rb_test.hpp" #include "gcache_page_test.hpp" extern "C" { #include } typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gcache_mem_suite, gcache_rb_suite, gcache_page_suite, 0 }; #endif /* __gcache_tests_hpp__ */ percona-galera-3-3.8-3390/gcomm/000077500000000000000000000000001244131713600161045ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcomm/SConscript000066400000000000000000000001411244131713600201120ustar00rootroot00000000000000# SCons build script for building gcomm SConscript(Split('''src/SConscript test/SConscript''')) percona-galera-3-3.8-3390/gcomm/doc/000077500000000000000000000000001244131713600166515ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcomm/doc/Doxyfile000066400000000000000000001437051244131713600203710ustar00rootroot00000000000000# Doxyfile 1.4.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = GComm # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.2.3 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src ../src/gcomm # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h *.hpp # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO percona-galera-3-3.8-3390/gcomm/src/000077500000000000000000000000001244131713600166735ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcomm/src/SConscript000066400000000000000000000015141244131713600207060ustar00rootroot00000000000000# Import('env') libgcomm_sources = [ 'conf.cpp', 'defaults.cpp', 'datagram.cpp', 'evs_consensus.cpp', 'evs_input_map2.cpp', 'evs_message2.cpp', 'evs_node.cpp', 'evs_proto.cpp', 'gmcast.cpp', 'gmcast_proto.cpp', 'pc.cpp', 'pc_proto.cpp', 'protonet.cpp', 'protostack.cpp', 'transport.cpp', 'uuid.cpp', 'view.cpp', 'socket.cpp'] libgcomm_env = env.Clone() libgcomm_env.Append(CXXFLAGS = ' -fno-strict-aliasing') if '-DHAVE_ASIO_HPP' in libgcomm_env['CPPFLAGS']: # ASIO sources need to be built with relaxed C++ flags libgcomm_sources.extend([ 'asio_tcp.cpp', 'asio_udp.cpp', 'asio_protonet.cpp']) libgcomm_env.StaticLibrary('gcomm', libgcomm_sources) env.Append(LIBGALERA_OBJS = libgcomm_env.SharedObject(libgcomm_sources)) percona-galera-3-3.8-3390/gcomm/src/asio_addr.hpp000066400000000000000000000025131244131713600213320ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #ifndef GCOMM_ASIO_ADDR_HPP #define GCOMM_ASIO_ADDR_HPP #include "gu_exception.hpp" #include "asio_protonet.hpp" #include #include namespace gcomm { static inline std::string escape_addr(const asio::ip::address& addr) { if (addr.is_v4()) { return addr.to_v4().to_string(); } else { return "[" + addr.to_v6().to_string() + "]"; } } static inline std::string unescape_addr(const std::string& addr) { std::string ret(addr); size_t pos(ret.find('[')); if (pos != std::string::npos) ret.erase(pos, 1); pos = ret.find(']'); if (pos != std::string::npos) ret.erase(pos, 1); return ret; } static inline std::string anyaddr(const asio::ip::address& addr) { if (addr.is_v4() == true) { return addr.to_v4().any().to_string(); } else { return addr.to_v6().any().to_string(); } gu_throw_fatal; } } template void set_fd_options(S& socket) { long flags(FD_CLOEXEC); if (fcntl(socket.native(), F_SETFD, flags) == -1) { gu_throw_error(errno) << "failed to set FD_CLOEXEC"; } } #endif // GCOMM_ASIO_ADDR_HPP percona-galera-3-3.8-3390/gcomm/src/asio_protonet.cpp000066400000000000000000000172241244131713600222720ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #include "asio_tcp.hpp" #include "asio_udp.hpp" #include "asio_addr.hpp" #include "asio_protonet.hpp" #include "socket.hpp" #include "gcomm/util.hpp" #include "gcomm/conf.hpp" #include "gu_logger.hpp" #include #include #include #include #ifdef HAVE_ASIO_SSL_HPP namespace { static std::string get_file(const gu::Config& conf, const std::string& fname) { try { return conf.get(fname); } catch (gu::NotSet& e) { log_error << "could not find '" << fname << "' from configuration"; throw; } } static void set_cipher_list(SSL_CTX* ssl_ctx, gu::Config& conf) { std::string cipher_list( conf.get(gcomm::Conf::SocketSslCipherList, "AES128-SHA")); if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.c_str()) == 0) { gu_throw_error(EINVAL) << "could not set cipher list, check that " << "the list is valid: "<< cipher_list; } conf.set(gcomm::Conf::SocketSslCipherList, cipher_list); } static void set_compression(gu::Config& conf) { bool compression( conf.get(gcomm::Conf::SocketSslCompression, true));; if (compression == false) { log_info << "disabling SSL compression"; sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); } conf.set(gcomm::Conf::SocketSslCompression, compression); } } std::string gcomm::AsioProtonet::get_ssl_password() const { std::string file(get_file(conf_, Conf::SocketSslPasswordFile)); std::ifstream ifs(file.c_str(), std::ios_base::in); if (ifs.good() == false) { gu_throw_error(errno) << "could not open password file '" << file << "'"; } std::string ret; std::getline(ifs, ret); return ret; } #endif // HAVE_ASIO_SSL_HPP gcomm::AsioProtonet::AsioProtonet(gu::Config& conf, int version) : gcomm::Protonet(conf, "asio", version), mutex_(), poll_until_(gu::datetime::Date::max()), io_service_(), timer_(io_service_), #ifdef HAVE_ASIO_SSL_HPP ssl_context_(io_service_, asio::ssl::context::sslv23), #endif // HAVE_ASIO_SSL_HPP mtu_(1 << 15), checksum_(NetHeader::checksum_type( conf.get(gcomm::Conf::SocketChecksum, NetHeader::CS_CRC32C))) { conf.set(gcomm::Conf::SocketChecksum, checksum_); #ifdef HAVE_ASIO_SSL_HPP // use ssl if either private key or cert file is specified bool use_ssl(conf_.is_set(Conf::SocketSslPrivateKeyFile) == true || conf_.is_set(Conf::SocketSslCertificateFile) == true); try { // overrides use_ssl if set explicitly use_ssl = conf_.get(Conf::SocketUseSsl); } catch (gu::NotSet& nf) {} if (use_ssl == true) { conf_.set(Conf::SocketUseSsl, true); log_info << "initializing ssl context"; set_compression(conf_); set_cipher_list(ssl_context_.impl(), conf_); ssl_context_.set_verify_mode(asio::ssl::context::verify_peer); ssl_context_.set_password_callback( boost::bind(&gcomm::AsioProtonet::get_ssl_password, this)); // private key file (required) const std::string private_key_file( get_file(conf_, Conf::SocketSslPrivateKeyFile)); try { ssl_context_.use_private_key_file( private_key_file, asio::ssl::context::pem); } catch (gu::NotFound& e) { log_error << "could not load private key file '" << private_key_file << "'"; throw; } catch (std::exception& e) { log_error << "could not use private key file '" << private_key_file << "': " << e.what(); throw; } // certificate file (required) const std::string certificate_file( get_file(conf_, Conf::SocketSslCertificateFile)); try { ssl_context_.use_certificate_file(certificate_file, asio::ssl::context::pem); } catch (std::exception& e) { log_error << "could not load certificate file'" << certificate_file << "': " << e.what(); throw; } // verify file (optional, defaults to certificate_file) const std::string verify_file( conf_.get(Conf::SocketSslVerifyFile, certificate_file)); try { ssl_context_.load_verify_file(verify_file); } catch (std::exception& e) { log_error << "could not load verify file '" << verify_file << "': " << e.what(); throw; } conf_.set(Conf::SocketSslVerifyFile, verify_file); } #endif // HAVE_ASIO_SSL_HPP } gcomm::AsioProtonet::~AsioProtonet() { } void gcomm::AsioProtonet::enter() { mutex_.lock(); } void gcomm::AsioProtonet::leave() { mutex_.unlock(); } gcomm::SocketPtr gcomm::AsioProtonet::socket(const gu::URI& uri) { if (uri.get_scheme() == "tcp" || uri.get_scheme() == "ssl") { return boost::shared_ptr(new AsioTcpSocket(*this, uri)); } else if (uri.get_scheme() == "udp") { return boost::shared_ptr(new AsioUdpSocket(*this, uri)); } else { gu_throw_fatal << "scheme '" << uri.get_scheme() << "' not implemented"; } } gcomm::Acceptor* gcomm::AsioProtonet::acceptor(const gu::URI& uri) { return new AsioTcpAcceptor(*this, uri); } gu::datetime::Period handle_timers_helper(gcomm::Protonet& pnet, const gu::datetime::Period& period) { const gu::datetime::Date now(gu::datetime::Date::now()); const gu::datetime::Date stop(now + period); const gu::datetime::Date next_time(pnet.handle_timers()); const gu::datetime::Period sleep_p(std::min(stop - now, next_time - now)); return (sleep_p < 0 ? 0 : sleep_p); } void gcomm::AsioProtonet::event_loop(const gu::datetime::Period& period) { io_service_.reset(); poll_until_ = gu::datetime::Date::now() + period; const gu::datetime::Period p(handle_timers_helper(*this, period)); timer_.expires_from_now(boost::posix_time::nanosec(p.get_nsecs())); timer_.async_wait(boost::bind(&AsioProtonet::handle_wait, this, asio::placeholders::error)); io_service_.run(); } void gcomm::AsioProtonet::dispatch(const SocketId& id, const Datagram& dg, const ProtoUpMeta& um) { for (std::deque::iterator i = protos_.begin(); i != protos_.end(); ++i) { (*i)->dispatch(id, dg, um); } } void gcomm::AsioProtonet::interrupt() { io_service_.stop(); } void gcomm::AsioProtonet::handle_wait(const asio::error_code& ec) { gu::datetime::Date now(gu::datetime::Date::now()); const gu::datetime::Period p(handle_timers_helper(*this, poll_until_ - now)); using std::rel_ops::operator>=; if (ec == asio::error_code() && poll_until_ >= now) { timer_.expires_from_now(boost::posix_time::nanosec(p.get_nsecs())); timer_.async_wait(boost::bind(&AsioProtonet::handle_wait, this, asio::placeholders::error)); } else { io_service_.stop(); } } percona-galera-3-3.8-3390/gcomm/src/asio_protonet.hpp000066400000000000000000000032001244131713600222640ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #ifndef GCOMM_ASIO_PROTONET_HPP #define GCOMM_ASIO_PROTONET_HPP #include "gcomm/protonet.hpp" #include "socket.hpp" #include "gu_monitor.hpp" #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wold-style-cast" #include "asio.hpp" #ifdef HAVE_ASIO_SSL_HPP #include "asio/ssl.hpp" #endif // HAVE_ASIO_SSL_HPP #include #include #include namespace gcomm { class AsioProtonet; } class gcomm::AsioProtonet : public gcomm::Protonet { public: AsioProtonet(gu::Config& conf, int version = 0); ~AsioProtonet(); void event_loop(const gu::datetime::Period& p); void dispatch(const SocketId&, const Datagram&, const ProtoUpMeta&); void interrupt(); SocketPtr socket(const gu::URI&); gcomm::Acceptor* acceptor(const gu::URI&); void enter(); void leave(); size_t mtu() const { return mtu_; } #ifdef HAVE_ASIO_SSL_HPP std::string get_ssl_password() const; #endif // HAVE_ASIO_SSL_HPP private: friend class AsioTcpSocket; friend class AsioTcpAcceptor; friend class AsioUdpSocket; AsioProtonet(const AsioProtonet&); void handle_wait(const asio::error_code& ec); gu::RecursiveMutex mutex_; gu::datetime::Date poll_until_; asio::io_service io_service_; asio::deadline_timer timer_; #ifdef HAVE_ASIO_SSL_HPP asio::ssl::context ssl_context_; #endif /* HAVE_ASIO_SSL_HPP */ size_t mtu_; NetHeader::checksum_t checksum_; }; #endif // GCOMM_ASIO_PROTONET_HPP percona-galera-3-3.8-3390/gcomm/src/asio_tcp.cpp000066400000000000000000000622551244131713600212120ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ #include "asio_tcp.hpp" #include "asio_addr.hpp" #include "gcomm/util.hpp" #include "gcomm/common.hpp" #define FAILED_HANDLER(_e) failed_handler(_e, __FUNCTION__, __LINE__) gcomm::AsioTcpSocket::AsioTcpSocket(AsioProtonet& net, const gu::URI& uri) : Socket (uri), net_ (net), socket_ (net.io_service_), #ifdef HAVE_ASIO_SSL_HPP ssl_socket_ (0), #endif /* HAVE_ASIO_SSL_HPP */ send_q_ (), recv_buf_ (net_.mtu() + NetHeader::serial_size_), recv_offset_ (0), state_ (S_CLOSED), local_addr_ (), remote_addr_ () { log_debug << "ctor for " << id(); } gcomm::AsioTcpSocket::~AsioTcpSocket() { log_debug << "dtor for " << id(); close_socket(); #ifdef HAVE_ASIO_SSL_HPP delete ssl_socket_; ssl_socket_ = 0; #endif /* HAVE_ASIO_SSL_HPP */ } void gcomm::AsioTcpSocket::failed_handler(const asio::error_code& ec, const std::string& func, int line) { log_debug << "failed handler from " << func << ":" << line << " socket " << id() << " " << socket_.native() << " error " << ec << " " << socket_.is_open() << " state " << state(); try { log_debug << "local endpoint " << local_addr() << " remote endpoint " << remote_addr(); } catch (...) { } const State prev_state(state()); if (state() != S_CLOSED) { state_ = S_FAILED; } if (prev_state != S_FAILED && prev_state != S_CLOSED) { net_.dispatch(id(), Datagram(), ProtoUpMeta(ec.value())); } } #ifdef HAVE_ASIO_SSL_HPP namespace { static const char* get_cipher(SSL* ssl) { return SSL_get_cipher_name(ssl); } static const char* get_compression(SSL* ssl) { return SSL_COMP_get_name(SSL_get_current_compression(ssl)); } static std::string extra_error_info(const asio::error_code& ec) { std::ostringstream os; if (ec.category() == asio::error::get_ssl_category()) { char errstr[120] = {0, }; ERR_error_string_n(ec.value(), errstr, sizeof(errstr)); os << ec.value() << ": '" << errstr << "'"; } return os.str(); } } void gcomm::AsioTcpSocket::handshake_handler(const asio::error_code& ec) { if (ec) { log_error << "handshake with remote endpoint " << remote_addr() << " failed: " << ec << ": '" << ec.message() << "' ( " << extra_error_info(ec) << ")"; FAILED_HANDLER(ec); return; } if (ssl_socket_ == 0) { log_error << "handshake handler called for non-SSL socket " << id() << " " << remote_addr() << " <-> " << local_addr(); FAILED_HANDLER(asio::error_code(EPROTO, asio::error::system_category)); return; } log_info << "SSL handshake successful, " << "remote endpoint " << remote_addr() << " local endpoint " << local_addr() << " cipher: " << get_cipher(ssl_socket_->impl()->ssl) << " compression: " << get_compression(ssl_socket_->impl()->ssl); state_ = S_CONNECTED; net_.dispatch(id(), Datagram(), ProtoUpMeta(ec.value())); async_receive(); } #endif /* HAVE_ASIO_SSL_HPP */ void gcomm::AsioTcpSocket::connect_handler(const asio::error_code& ec) { Critical crit(net_); try { if (ec) { FAILED_HANDLER(ec); return; } else { assign_local_addr(); assign_remote_addr(); #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { ssl_socket_->lowest_layer().set_option( asio::ip::tcp::no_delay(true)); set_fd_options(ssl_socket_->lowest_layer()); log_debug << "socket " << id() << " connected, remote endpoint " << remote_addr() << " local endpoint " << local_addr(); ssl_socket_->async_handshake( asio::ssl::stream::client, boost::bind(&AsioTcpSocket::handshake_handler, shared_from_this(), asio::placeholders::error) ); } else { #endif /* HAVE_ASIO_SSL_HPP */ socket_.set_option(asio::ip::tcp::no_delay(true)); set_fd_options(socket_); log_debug << "socket " << id() << " connected, remote endpoint " << remote_addr() << " local endpoint " << local_addr(); state_ = S_CONNECTED; net_.dispatch(id(), Datagram(), ProtoUpMeta(ec.value())); async_receive(); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } } catch (asio::system_error& e) { FAILED_HANDLER(e.code()); } } void gcomm::AsioTcpSocket::connect(const gu::URI& uri) { try { Critical crit(net_); asio::ip::tcp::resolver resolver(net_.io_service_); // Give query flags explicitly to avoid having AI_ADDRCONFIG in // underlying getaddrinfo() hint flags. asio::ip::tcp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port(), asio::ip::tcp::resolver::query::flags(0)); asio::ip::tcp::resolver::iterator i(resolver.resolve(query)); #ifdef HAVE_ASIO_SSL_HPP if (uri.get_scheme() == SSL_SCHEME) { ssl_socket_ = new asio::ssl::stream( net_.io_service_, net_.ssl_context_ ); ssl_socket_->lowest_layer().async_connect( *i, boost::bind(&AsioTcpSocket::connect_handler, shared_from_this(), asio::placeholders::error) ); } else { #endif /* HAVE_ASIO_SSL_HPP */ const std::string bind_ip = uri.get_option(gcomm::Socket::OptIfAddr, ""); if (!bind_ip.empty()) { socket_.open(i->endpoint().protocol()); asio::ip::tcp::endpoint ep( asio::ip::address::from_string(bind_ip), // connect from any port. 0); socket_.bind(ep); } socket_.async_connect(*i, boost::bind(&AsioTcpSocket::connect_handler, shared_from_this(), asio::placeholders::error)); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ state_ = S_CONNECTING; } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "error while connecting to remote host " << uri.to_string() << "', asio error '" << e.what() << "'"; } } void gcomm::AsioTcpSocket::close() { Critical crit(net_); if (state() == S_CLOSED || state() == S_CLOSING) return; log_debug << "closing " << id() << " state " << state() << " send_q size " << send_q_.size(); if (send_q_.empty() == true || state() != S_CONNECTED) { close_socket(); state_ = S_CLOSED; } else { state_ = S_CLOSING; } } void gcomm::AsioTcpSocket::write_handler(const asio::error_code& ec, size_t bytes_transferred) { Critical crit(net_); if (state() != S_CONNECTED && state() != S_CLOSING) { log_debug << "write handler for " << id() << " state " << state(); #ifdef HAVE_ASIO_SSL_HPP if (ec.category() == asio::error::get_ssl_category()) { log_warn << "write_handler(): " << ec.message() << " (" << extra_error_info(ec) << ")"; } #endif return; } if (!ec) { gcomm_assert(send_q_.empty() == false); gcomm_assert(send_q_.front().len() >= bytes_transferred); while (send_q_.empty() == false && bytes_transferred >= send_q_.front().len()) { const Datagram& dg(send_q_.front()); bytes_transferred -= dg.len(); send_q_.pop_front(); } gcomm_assert(bytes_transferred == 0); if (send_q_.empty() == false) { const Datagram& dg(send_q_.front()); boost::array cbs; cbs[0] = asio::const_buffer(dg.header() + dg.header_offset(), dg.header_len()); cbs[1] = asio::const_buffer(&dg.payload()[0], dg.payload().size()); write_one(cbs); } else if (state_ == S_CLOSING) { log_debug << "deferred close of " << id(); close_socket(); state_ = S_CLOSED; } } else if (state_ == S_CLOSING) { log_debug << "deferred close of " << id() << " error " << ec; close_socket(); state_ = S_CLOSED; } else { FAILED_HANDLER(ec); } } int gcomm::AsioTcpSocket::send(const Datagram& dg) { Critical crit(net_); if (state() != S_CONNECTED) { return ENOTCONN; } NetHeader hdr(static_cast(dg.len()), net_.version_); if (net_.checksum_ != NetHeader::CS_NONE) { hdr.set_crc32(crc32(net_.checksum_, dg), net_.checksum_); } send_q_.push_back(dg); // makes copy of dg Datagram& priv_dg(send_q_.back()); priv_dg.set_header_offset(priv_dg.header_offset() - NetHeader::serial_size_); serialize(hdr, priv_dg.header(), priv_dg.header_size(), priv_dg.header_offset()); if (send_q_.size() == 1) { boost::array cbs; cbs[0] = asio::const_buffer(priv_dg.header() + priv_dg.header_offset(), priv_dg.header_len()); cbs[1] = asio::const_buffer(&priv_dg.payload()[0], priv_dg.payload().size()); write_one(cbs); } return 0; } void gcomm::AsioTcpSocket::read_handler(const asio::error_code& ec, const size_t bytes_transferred) { Critical crit(net_); if (ec) { #ifdef HAVE_ASIO_SSL_HPP if (ec.category() == asio::error::get_ssl_category()) { log_warn << "read_handler(): " << ec.message() << " (" << extra_error_info(ec) << ")"; } #endif FAILED_HANDLER(ec); return; } if (state() != S_CONNECTED && state() != S_CLOSING) { log_debug << "read handler for " << id() << " state " << state(); return; } recv_offset_ += bytes_transferred; while (recv_offset_ >= NetHeader::serial_size_) { NetHeader hdr; try { unserialize(&recv_buf_[0], recv_buf_.size(), 0, hdr); } catch (gu::Exception& e) { FAILED_HANDLER(asio::error_code(e.get_errno(), asio::error::system_category)); return; } if (recv_offset_ >= hdr.len() + NetHeader::serial_size_) { Datagram dg( gu::SharedBuffer( new gu::Buffer(&recv_buf_[0] + NetHeader::serial_size_, &recv_buf_[0] + NetHeader::serial_size_ + hdr.len()))); if (net_.checksum_ != NetHeader::CS_NONE) { #ifdef TEST_NET_CHECKSUM_ERROR long rnd(rand()); if (rnd % 10000 == 0) { hdr.set_crc32(net_.checksum_, static_cast(rnd)); } #endif /* TEST_NET_CHECKSUM_ERROR */ if (check_cs (hdr, dg)) { log_warn << "checksum failed, hdr: len=" << hdr.len() << " has_crc32=" << hdr.has_crc32() << " has_crc32c=" << hdr.has_crc32c() << " crc32=" << hdr.crc32(); FAILED_HANDLER(asio::error_code( EPROTO, asio::error::system_category)); return; } } ProtoUpMeta um; net_.dispatch(id(), dg, um); recv_offset_ -= NetHeader::serial_size_ + hdr.len(); if (recv_offset_ > 0) { memmove(&recv_buf_[0], &recv_buf_[0] + NetHeader::serial_size_ + hdr.len(), recv_offset_); } } else { break; } } boost::array mbs; mbs[0] = asio::mutable_buffer(&recv_buf_[0] + recv_offset_, recv_buf_.size() - recv_offset_); read_one(mbs); } size_t gcomm::AsioTcpSocket::read_completion_condition( const asio::error_code& ec, const size_t bytes_transferred) { Critical crit(net_); if (ec) { #ifdef HAVE_ASIO_SSL_HPP if (ec.category() == asio::error::get_ssl_category()) { log_warn << "read_completion_condition(): " << ec.message() << " (" << extra_error_info(ec) << ")"; } #endif FAILED_HANDLER(ec); return 0; } if (state() != S_CONNECTED && state() != S_CLOSING) { log_debug << "read completion condition for " << id() << " state " << state(); return 0; } if (recv_offset_ + bytes_transferred >= NetHeader::serial_size_) { NetHeader hdr; try { unserialize(&recv_buf_[0], NetHeader::serial_size_, 0, hdr); } catch (gu::Exception& e) { log_warn << "unserialize error " << e.what(); FAILED_HANDLER(asio::error_code(e.get_errno(), asio::error::system_category)); return 0; } if (recv_offset_ + bytes_transferred >= NetHeader::serial_size_ + hdr.len()) { return 0; } } return (recv_buf_.size() - recv_offset_); } void gcomm::AsioTcpSocket::async_receive() { Critical crit(net_); gcomm_assert(state() == S_CONNECTED); boost::array mbs; mbs[0] = asio::mutable_buffer(&recv_buf_[0], recv_buf_.size()); read_one(mbs); } size_t gcomm::AsioTcpSocket::mtu() const { return net_.mtu(); } std::string gcomm::AsioTcpSocket::local_addr() const { return local_addr_; } std::string gcomm::AsioTcpSocket::remote_addr() const { return remote_addr_; } void gcomm::AsioTcpSocket::read_one(boost::array& mbs) { #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { async_read(*ssl_socket_, mbs, boost::bind(&AsioTcpSocket::read_completion_condition, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred), boost::bind(&AsioTcpSocket::read_handler, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); } else { #endif /* HAVE_ASIO_SSL_HPP */ async_read(socket_, mbs, boost::bind(&AsioTcpSocket::read_completion_condition, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred), boost::bind(&AsioTcpSocket::read_handler, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } void gcomm::AsioTcpSocket::write_one( const boost::array& cbs) { #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { async_write(*ssl_socket_, cbs, boost::bind(&AsioTcpSocket::write_handler, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); } else { #endif /* HAVE_ASIO_SSL_HPP */ async_write(socket_, cbs, boost::bind(&AsioTcpSocket::write_handler, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } void gcomm::AsioTcpSocket::close_socket() { try { #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { // close underlying transport before calling shutdown() // to avoid blocking ssl_socket_->lowest_layer().close(); ssl_socket_->shutdown(); } else { #endif /* HAVE_ASIO_SSL_HPP */ socket_.close(); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } catch (...) { } } void gcomm::AsioTcpSocket::assign_local_addr() { #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { local_addr_ = gcomm::uri_string( gcomm::SSL_SCHEME, gcomm::escape_addr( ssl_socket_->lowest_layer().local_endpoint().address()), gu::to_string( ssl_socket_->lowest_layer().local_endpoint().port()) ); } else { #endif /* HAVE_ASIO_SSL_HPP */ local_addr_ = gcomm::uri_string( gcomm::TCP_SCHEME, gcomm::escape_addr(socket_.local_endpoint().address()), gu::to_string(socket_.local_endpoint().port()) ); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } void gcomm::AsioTcpSocket::assign_remote_addr() { #ifdef HAVE_ASIO_SSL_HPP if (ssl_socket_ != 0) { remote_addr_ = gcomm::uri_string( gcomm::SSL_SCHEME, gcomm::escape_addr( ssl_socket_->lowest_layer().remote_endpoint().address()), gu::to_string( ssl_socket_->lowest_layer().remote_endpoint().port()) ); } else { #endif /* HAVE_ASIO_SSL_HPP */ remote_addr_ = uri_string( gcomm::TCP_SCHEME, gcomm::escape_addr(socket_.remote_endpoint().address()), gu::to_string(socket_.remote_endpoint().port()) ); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } gcomm::AsioTcpAcceptor::AsioTcpAcceptor(AsioProtonet& net, const gu::URI& uri) : Acceptor (uri), net_ (net), acceptor_ (net_.io_service_), accepted_socket_() { } gcomm::AsioTcpAcceptor::~AsioTcpAcceptor() { close(); } void gcomm::AsioTcpAcceptor::accept_handler( SocketPtr socket, const asio::error_code& error) { if (!error) { AsioTcpSocket* s(static_cast(socket.get())); try { s->assign_local_addr(); s->assign_remote_addr(); #ifdef HAVE_ASIO_SSL_HPP if (s->ssl_socket_ != 0) { s->ssl_socket_->lowest_layer().set_option( asio::ip::tcp::no_delay(true)); set_fd_options(s->ssl_socket_->lowest_layer()); log_debug << "socket " << s->id() << " connected, remote endpoint " << s->remote_addr() << " local endpoint " << s->local_addr(); s->ssl_socket_->async_handshake( asio::ssl::stream::server, boost::bind(&AsioTcpSocket::handshake_handler, s->shared_from_this(), asio::placeholders::error)); s->state_ = Socket::S_CONNECTING; } else { #endif /* HAVE_ASIO_SSL_HP */ s->socket_.set_option(asio::ip::tcp::no_delay(true)); set_fd_options(s->socket_); s->state_ = Socket::S_CONNECTED; #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ accepted_socket_ = socket; log_debug << "accepted socket " << socket->id(); net_.dispatch(id(), Datagram(), ProtoUpMeta(error.value())); } catch (asio::system_error& e) { // socket object should be freed automatically when it // goes out of scope log_debug << "accept failed: " << e.what(); } AsioTcpSocket* new_socket(new AsioTcpSocket(net_, uri_)); #ifdef HAVE_ASIO_SSL_HPP if (uri_.get_scheme() == SSL_SCHEME) { new_socket->ssl_socket_ = new asio::ssl::stream( net_.io_service_, net_.ssl_context_); acceptor_.async_accept(new_socket->ssl_socket_->lowest_layer(), boost::bind(&AsioTcpAcceptor::accept_handler, this, SocketPtr(new_socket), asio::placeholders::error)); } else { #endif /* HAVE_ASIO_SSL_HPP */ acceptor_.async_accept(new_socket->socket_, boost::bind(&AsioTcpAcceptor::accept_handler, this, SocketPtr(new_socket), asio::placeholders::error)); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } else { log_warn << "accept handler: " << error; } } void gcomm::AsioTcpAcceptor::listen(const gu::URI& uri) { try { asio::ip::tcp::resolver resolver(net_.io_service_); // Give query flags explicitly to avoid having AI_ADDRCONFIG in // underlying getaddrinfo() hint flags. asio::ip::tcp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port(), asio::ip::tcp::resolver::query::flags(0)); asio::ip::tcp::resolver::iterator i(resolver.resolve(query)); acceptor_.open(i->endpoint().protocol()); acceptor_.set_option(asio::ip::tcp::socket::reuse_address(true)); set_fd_options(acceptor_); acceptor_.bind(*i); acceptor_.listen(); AsioTcpSocket* new_socket(new AsioTcpSocket(net_, uri)); #ifdef HAVE_ASIO_SSL_HPP if (uri_.get_scheme() == SSL_SCHEME) { new_socket->ssl_socket_ = new asio::ssl::stream( net_.io_service_, net_.ssl_context_); acceptor_.async_accept(new_socket->ssl_socket_->lowest_layer(), boost::bind(&AsioTcpAcceptor::accept_handler, this, SocketPtr(new_socket), asio::placeholders::error)); } else { #endif /* HAVE_ASIO_SSL_HPP */ acceptor_.async_accept(new_socket->socket_, boost::bind(&AsioTcpAcceptor::accept_handler, this, SocketPtr(new_socket), asio::placeholders::error)); #ifdef HAVE_ASIO_SSL_HPP } #endif /* HAVE_ASIO_SSL_HPP */ } catch (asio::system_error& e) { log_error << e.what(); gu_throw_error(e.code().value()) << "error while trying to listen '" << uri.to_string() << "', asio error '" << e.what() << "'"; } } std::string gcomm::AsioTcpAcceptor::listen_addr() const { try { return uri_string( uri_.get_scheme(), escape_addr(acceptor_.local_endpoint().address()), gu::to_string(acceptor_.local_endpoint().port()) ); } catch (asio::system_error& e) { gu_throw_error(e.code().value()) << "failed to read listen addr " << "', asio error '" << e.what() << "'"; } } void gcomm::AsioTcpAcceptor::close() { try { acceptor_.close(); } catch (...) { } } gcomm::SocketPtr gcomm::AsioTcpAcceptor::accept() { if (accepted_socket_->state() == Socket::S_CONNECTED) { accepted_socket_->async_receive(); } return accepted_socket_; } percona-galera-3-3.8-3390/gcomm/src/asio_tcp.hpp000066400000000000000000000062621244131713600212130ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #ifndef GCOMM_ASIO_TCP_HPP #define GCOMM_ASIO_TCP_HPP #include "socket.hpp" #include "asio_protonet.hpp" #include #include #include #include #include namespace gcomm { class AsioTcpSocket; class AsioTcpAcceptor; } // TCP Socket implementation class gcomm::AsioTcpSocket : public gcomm::Socket, public boost::enable_shared_from_this { public: AsioTcpSocket(AsioProtonet& net, const gu::URI& uri); ~AsioTcpSocket(); void failed_handler(const asio::error_code& ec, const std::string& func, int line); #ifdef HAVE_ASIO_SSL_HPP void handshake_handler(const asio::error_code& ec); #endif // HAVE_ASIO_SSL_HPP void connect_handler(const asio::error_code& ec); void connect(const gu::URI& uri); void close(); void write_handler(const asio::error_code& ec, size_t bytes_transferred); int send(const Datagram& dg); size_t read_completion_condition( const asio::error_code& ec, const size_t bytes_transferred); void read_handler(const asio::error_code& ec, const size_t bytes_transferred); void async_receive(); size_t mtu() const; std::string local_addr() const; std::string remote_addr() const; State state() const { return state_; } SocketId id() const { return &socket_; } private: friend class gcomm::AsioTcpAcceptor; AsioTcpSocket(const AsioTcpSocket&); void operator=(const AsioTcpSocket&); void read_one(boost::array& mbs); void write_one(const boost::array& cbs); void close_socket(); // call to assign local/remote addresses at the point where it // is known that underlying socket is live void assign_local_addr(); void assign_remote_addr(); AsioProtonet& net_; asio::ip::tcp::socket socket_; #ifdef HAVE_ASIO_SSL_HPP asio::ssl::stream* ssl_socket_; #endif // HAVE_ASIO_SSL_HPP std::deque send_q_; std::vector recv_buf_; size_t recv_offset_; State state_; // Querying addresses from failed socket does not work, // so need to maintain copy for diagnostics logging std::string local_addr_; std::string remote_addr_; }; class gcomm::AsioTcpAcceptor : public gcomm::Acceptor { public: AsioTcpAcceptor(AsioProtonet& net, const gu::URI& uri); ~AsioTcpAcceptor(); void accept_handler( SocketPtr socket, const asio::error_code& error); void listen(const gu::URI& uri); std::string listen_addr() const; void close(); SocketPtr accept(); State state() const { gu_throw_fatal << "TODO:"; } SocketId id() const { return &acceptor_; } private: AsioProtonet& net_; asio::ip::tcp::acceptor acceptor_; SocketPtr accepted_socket_; }; #endif // GCOMM_ASIO_TCP_HPP percona-galera-3-3.8-3390/gcomm/src/asio_udp.cpp000066400000000000000000000161101244131713600212010ustar00rootroot00000000000000/* * Copyright (C) 2010-2012 Codership Oy */ #include "asio_udp.hpp" #include "asio_addr.hpp" #include "gcomm/util.hpp" #include "gcomm/common.hpp" #include #include static bool is_multicast(const asio::ip::udp::endpoint& ep) { if (ep.address().is_v4() == true) { return ep.address().to_v4().is_multicast(); } else if (ep.address().is_v6() == true) { return ep.address().to_v6().is_multicast(); } gu_throw_fatal; } static void join_group(asio::ip::udp::socket& socket, const asio::ip::udp::endpoint& ep, const asio::ip::address& local_if) { gcomm_assert(is_multicast(ep) == true); if (ep.address().is_v4() == true) { socket.set_option(asio::ip::multicast::join_group(ep.address().to_v4(), local_if.to_v4())); socket.set_option(asio::ip::multicast::outbound_interface(local_if.to_v4())); } else { gu_throw_fatal << "mcast interface not implemented"; socket.set_option(asio::ip::multicast::join_group(ep.address().to_v6())); } } static void leave_group(asio::ip::udp::socket& socket, asio::ip::udp::endpoint& ep) { // gcomm_assert(is_multicast(ep) == true); // socket.set_option(asio::ip::multicast::leave_group(ep.address().to_v4())); } gcomm::AsioUdpSocket::AsioUdpSocket(AsioProtonet& net, const gu::URI& uri) : Socket(uri), net_(net), state_(S_CLOSED), socket_(net_.io_service_), target_ep_(), source_ep_(), recv_buf_((1 << 15) + NetHeader::serial_size_) { } gcomm::AsioUdpSocket::~AsioUdpSocket() { close(); } void gcomm::AsioUdpSocket::connect(const gu::URI& uri) { gcomm_assert(state() == S_CLOSED); Critical crit(net_); asio::ip::udp::resolver resolver(net_.io_service_); asio::ip::udp::resolver::query query(unescape_addr(uri.get_host()), uri.get_port()); asio::ip::udp::resolver::iterator conn_i(resolver.resolve(query)); target_ep_ = conn_i->endpoint(); socket_.open(conn_i->endpoint().protocol()); socket_.set_option(asio::ip::udp::socket::reuse_address(true)); socket_.set_option(asio::ip::udp::socket::linger(true, 1)); set_fd_options(socket_); asio::ip::udp::socket::non_blocking_io cmd(true); socket_.io_control(cmd); const std::string if_addr( unescape_addr( uri.get_option("socket.if_addr", anyaddr(conn_i->endpoint().address())))); asio::ip::address local_if(asio::ip::address::from_string(if_addr)); if (is_multicast(conn_i->endpoint()) == true) { join_group(socket_, conn_i->endpoint(), local_if); socket_.set_option( asio::ip::multicast::enable_loopback( gu::from_string(uri.get_option("socket.if_loop", "false")))); socket_.set_option( asio::ip::multicast::hops( gu::from_string(uri.get_option("socket.mcast_ttl", "1")))); socket_.bind(*conn_i); } else { socket_.bind( asio::ip::udp::endpoint( local_if, gu::from_string(uri.get_port()))); } async_receive(); state_ = S_CONNECTED; } void gcomm::AsioUdpSocket::close() { Critical crit(net_); if (state() != S_CLOSED) { if (is_multicast(target_ep_) == true) { leave_group(socket_, target_ep_); } socket_.close(); } state_ = S_CLOSED; } int gcomm::AsioUdpSocket::send(const Datagram& dg) { Critical crit(net_); boost::array cbs; NetHeader hdr(dg.len(), net_.version_); if (net_.checksum_ != NetHeader::CS_NONE) { hdr.set_crc32(crc32(net_.checksum_, dg), net_.checksum_); } gu::byte_t buf[NetHeader::serial_size_]; serialize(hdr, buf, sizeof(buf), 0); cbs[0] = asio::const_buffer(buf, sizeof(buf)); cbs[1] = asio::const_buffer(dg.header() + dg.header_offset(), dg.header_len()); cbs[2] = asio::const_buffer(&dg.payload()[0], dg.payload().size()); try { socket_.send_to(cbs, target_ep_); } catch (asio::system_error& err) { log_warn << "Error: " << err.what(); return err.code().value(); } return 0; } void gcomm::AsioUdpSocket::read_handler(const asio::error_code& ec, size_t bytes_transferred) { if (ec) { // return; } if (bytes_transferred >= NetHeader::serial_size_) { Critical crit(net_); NetHeader hdr; try { unserialize(&recv_buf_[0], NetHeader::serial_size_, 0, hdr); } catch (gu::Exception& e) { log_warn << "hdr unserialize failed: " << e.get_errno(); return; } if (NetHeader::serial_size_ + hdr.len() != bytes_transferred) { log_warn << "len " << hdr.len() << " does not match to bytes transferred" << bytes_transferred; } else { Datagram dg( gu::SharedBuffer( new gu::Buffer(&recv_buf_[0] + NetHeader::serial_size_, &recv_buf_[0] + NetHeader::serial_size_ + hdr.len()))); if (net_.checksum_ == true && check_cs(hdr, dg)) { log_warn << "checksum failed, hdr: len=" << hdr.len() << " has_crc32=" << hdr.has_crc32() << " has_crc32c=" << hdr.has_crc32c() << " crc32=" << hdr.crc32(); } else { net_.dispatch(id(), dg, ProtoUpMeta()); } } } else { log_warn << "short read of " << bytes_transferred; } async_receive(); } void gcomm::AsioUdpSocket::async_receive() { Critical crit(net_); boost::array mbs; mbs[0] = asio::mutable_buffer(&recv_buf_[0], recv_buf_.size()); socket_.async_receive_from(mbs, source_ep_, boost::bind(&AsioUdpSocket::read_handler, shared_from_this(), asio::placeholders::error, asio::placeholders::bytes_transferred)); } size_t gcomm::AsioUdpSocket::mtu() const { return (1 << 15); } std::string gcomm::AsioUdpSocket::local_addr() const { return uri_string(UDP_SCHEME, escape_addr(socket_.local_endpoint().address()), gu::to_string(socket_.local_endpoint().port())); } std::string gcomm::AsioUdpSocket::remote_addr() const { return uri_string(UDP_SCHEME, escape_addr(socket_.remote_endpoint().address()), gu::to_string(socket_.remote_endpoint().port())); } percona-galera-3-3.8-3390/gcomm/src/asio_udp.hpp000066400000000000000000000021621244131713600212100ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy */ #ifndef GCOMM_ASIO_UDP_HPP #define GCOMM_ASIO_UDP_HPP #include "socket.hpp" #include "asio_protonet.hpp" #include #include namespace gcomm { class AsioUdpSocket; class AsioProtonet; } class gcomm::AsioUdpSocket : public gcomm::Socket, public boost::enable_shared_from_this { public: AsioUdpSocket(AsioProtonet& net, const gu::URI& uri); ~AsioUdpSocket(); void connect(const gu::URI& uri); void close(); int send(const Datagram& dg); void read_handler(const asio::error_code&, size_t); void async_receive(); size_t mtu() const; std::string local_addr() const; std::string remote_addr() const; State state() const { return state_; } SocketId id() const { return &socket_; } private: AsioProtonet& net_; State state_; asio::ip::udp::socket socket_; asio::ip::udp::endpoint target_ep_; asio::ip::udp::endpoint source_ep_; std::vector recv_buf_; }; #endif // GCOMM_ASIO_UDP_HPP percona-galera-3-3.8-3390/gcomm/src/conf.cpp000066400000000000000000000173411244131713600203320ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "gcomm/conf.hpp" #include "defaults.hpp" #include "common.h" static std::string const Delim = "."; // Protonet std::string const gcomm::Conf::ProtonetBackend("protonet.backend"); std::string const gcomm::Conf::ProtonetVersion("protonet.version"); // TCP static std::string const SocketPrefix("socket" + Delim); std::string const gcomm::Conf::TcpNonBlocking = SocketPrefix + "non_blocking"; std::string const gcomm::Conf::SocketUseSsl = SocketPrefix + "ssl"; std::string const gcomm::Conf::SocketSslVerifyFile = COMMON_CONF_SSL_CA; std::string const gcomm::Conf::SocketSslCertificateFile = COMMON_CONF_SSL_CERT; std::string const gcomm::Conf::SocketSslPrivateKeyFile = COMMON_CONF_SSL_KEY; std::string const gcomm::Conf::SocketSslPasswordFile = COMMON_CONF_SSL_PSWD_FILE; std::string const gcomm::Conf::SocketSslCipherList = SocketPrefix + "ssl_cipher"; std::string const gcomm::Conf::SocketSslCompression = SocketPrefix + "ssl_compression"; std::string const gcomm::Conf::SocketChecksum = SocketPrefix + "checksum"; // GMCast std::string const gcomm::Conf::GMCastScheme = "gmcast"; static std::string const GMCastPrefix(gcomm::Conf::GMCastScheme + Delim); std::string const gcomm::Conf::GMCastVersion = GMCastPrefix + "version"; std::string const gcomm::Conf::GMCastGroup = GMCastPrefix + "group"; std::string const gcomm::Conf::GMCastListenAddr = GMCastPrefix + "listen_addr"; std::string const gcomm::Conf::GMCastMCastAddr = GMCastPrefix + "mcast_addr"; std::string const gcomm::Conf::GMCastMCastPort = GMCastPrefix + "mcast_port"; std::string const gcomm::Conf::GMCastMCastTTL = GMCastPrefix + "mcast_ttl"; std::string const gcomm::Conf::GMCastTimeWait = GMCastPrefix + "time_wait"; std::string const gcomm::Conf::GMCastPeerTimeout = GMCastPrefix + "peer_timeout"; std::string const gcomm::Conf::GMCastMaxInitialReconnectAttempts = GMCastPrefix + "mira"; std::string const gcomm::Conf::GMCastPeerAddr = GMCastPrefix + "peer_addr"; std::string const gcomm::Conf::GMCastIsolate = GMCastPrefix + "isolate"; std::string const gcomm::Conf::GMCastSegment = GMCastPrefix + "segment"; // EVS std::string const gcomm::Conf::EvsScheme = "evs"; static std::string const EvsPrefix(gcomm::Conf::EvsScheme + Delim); std::string const gcomm::Conf::EvsVersion = EvsPrefix + "version"; std::string const gcomm::Conf::EvsViewForgetTimeout = EvsPrefix + "view_forget_timeout"; std::string const gcomm::Conf::EvsInactiveTimeout = EvsPrefix + "inactive_timeout"; std::string const gcomm::Conf::EvsSuspectTimeout = EvsPrefix + "suspect_timeout"; std::string const gcomm::Conf::EvsInactiveCheckPeriod = EvsPrefix + "inactive_check_period"; std::string const gcomm::Conf::EvsInstallTimeout = EvsPrefix + "install_timeout"; std::string const gcomm::Conf::EvsKeepalivePeriod = EvsPrefix + "keepalive_period"; std::string const gcomm::Conf::EvsJoinRetransPeriod = EvsPrefix + "join_retrans_period"; std::string const gcomm::Conf::EvsStatsReportPeriod = EvsPrefix + "stats_report_period"; std::string const gcomm::Conf::EvsDebugLogMask = EvsPrefix + "debug_log_mask"; std::string const gcomm::Conf::EvsInfoLogMask = EvsPrefix + "info_log_mask"; std::string const gcomm::Conf::EvsSendWindow = EvsPrefix + "send_window"; std::string const gcomm::Conf::EvsUserSendWindow = EvsPrefix + "user_send_window"; std::string const gcomm::Conf::EvsUseAggregate = EvsPrefix + "use_aggregate"; std::string const gcomm::Conf::EvsCausalKeepalivePeriod = EvsPrefix + "causal_keepalive_period"; std::string const gcomm::Conf::EvsMaxInstallTimeouts = EvsPrefix + "max_install_timeouts"; std::string const gcomm::Conf::EvsDelayMargin = EvsPrefix + "delay_margin"; std::string const gcomm::Conf::EvsDelayedKeepPeriod = EvsPrefix + "delayed_keep_period"; std::string const gcomm::Conf::EvsEvict = EvsPrefix + "evict"; std::string const gcomm::Conf::EvsAutoEvict = EvsPrefix + "auto_evict"; // PC std::string const gcomm::Conf::PcScheme = "pc"; static std::string const PcPrefix(gcomm::Conf::PcScheme + Delim); std::string const gcomm::Conf::PcVersion = PcPrefix + "version"; std::string const gcomm::Conf::PcIgnoreSb = PcPrefix + "ignore_sb"; std::string const gcomm::Conf::PcIgnoreQuorum = PcPrefix + "ignore_quorum"; std::string const gcomm::Conf::PcChecksum = PcPrefix + "checksum"; std::string const gcomm::Conf::PcLinger = PcPrefix + "linger"; std::string const gcomm::Conf::PcAnnounceTimeout = PcPrefix + "announce_timeout"; std::string const gcomm::Conf::PcNpvo = PcPrefix + "npvo"; std::string const gcomm::Conf::PcBootstrap = PcPrefix + "bootstrap"; std::string const gcomm::Conf::PcWaitPrim = PcPrefix + "wait_prim"; std::string const gcomm::Conf::PcWaitPrimTimeout = PcPrefix + "wait_prim_timeout"; std::string const gcomm::Conf::PcWeight = PcPrefix + "weight"; std::string const gcomm::Conf::PcRecovery = PcPrefix + "recovery"; void gcomm::Conf::register_params(gu::Config& cnf) { #define GCOMM_CONF_ADD(_x_) cnf.add(_x_); #define GCOMM_CONF_ADD_DEFAULT(_x_) cnf.add(_x_, Defaults::_x_); GCOMM_CONF_ADD (COMMON_BASE_HOST_KEY); GCOMM_CONF_ADD (COMMON_BASE_PORT_KEY); GCOMM_CONF_ADD_DEFAULT(ProtonetBackend); GCOMM_CONF_ADD_DEFAULT(ProtonetVersion); GCOMM_CONF_ADD (TcpNonBlocking); GCOMM_CONF_ADD (SocketUseSsl); GCOMM_CONF_ADD (SocketSslVerifyFile); GCOMM_CONF_ADD (SocketSslCertificateFile); GCOMM_CONF_ADD (SocketSslPrivateKeyFile); GCOMM_CONF_ADD (SocketSslPasswordFile); GCOMM_CONF_ADD (SocketSslCipherList); GCOMM_CONF_ADD (SocketSslCompression); GCOMM_CONF_ADD_DEFAULT(SocketChecksum); GCOMM_CONF_ADD_DEFAULT(GMCastVersion); GCOMM_CONF_ADD (GMCastGroup); GCOMM_CONF_ADD (GMCastListenAddr); GCOMM_CONF_ADD (GMCastMCastAddr); GCOMM_CONF_ADD (GMCastMCastPort); GCOMM_CONF_ADD (GMCastMCastTTL); GCOMM_CONF_ADD (GMCastMCastAddr); GCOMM_CONF_ADD (GMCastTimeWait); GCOMM_CONF_ADD (GMCastPeerTimeout); GCOMM_CONF_ADD (GMCastMaxInitialReconnectAttempts); GCOMM_CONF_ADD (GMCastPeerAddr); GCOMM_CONF_ADD (GMCastIsolate); GCOMM_CONF_ADD_DEFAULT(GMCastSegment); GCOMM_CONF_ADD (EvsVersion); GCOMM_CONF_ADD_DEFAULT(EvsViewForgetTimeout); GCOMM_CONF_ADD_DEFAULT(EvsSuspectTimeout); GCOMM_CONF_ADD_DEFAULT(EvsInactiveTimeout); GCOMM_CONF_ADD_DEFAULT(EvsInactiveCheckPeriod); GCOMM_CONF_ADD (EvsInstallTimeout); GCOMM_CONF_ADD (EvsKeepalivePeriod); GCOMM_CONF_ADD_DEFAULT(EvsJoinRetransPeriod); GCOMM_CONF_ADD_DEFAULT(EvsStatsReportPeriod); GCOMM_CONF_ADD (EvsDebugLogMask); GCOMM_CONF_ADD (EvsInfoLogMask); GCOMM_CONF_ADD_DEFAULT(EvsSendWindow); GCOMM_CONF_ADD_DEFAULT(EvsUserSendWindow); GCOMM_CONF_ADD (EvsUseAggregate); GCOMM_CONF_ADD (EvsCausalKeepalivePeriod); GCOMM_CONF_ADD_DEFAULT(EvsMaxInstallTimeouts); GCOMM_CONF_ADD_DEFAULT(EvsDelayMargin); GCOMM_CONF_ADD_DEFAULT(EvsDelayedKeepPeriod); GCOMM_CONF_ADD (EvsEvict); GCOMM_CONF_ADD_DEFAULT(EvsAutoEvict); GCOMM_CONF_ADD_DEFAULT(PcVersion); GCOMM_CONF_ADD_DEFAULT(PcIgnoreSb); GCOMM_CONF_ADD_DEFAULT(PcIgnoreQuorum); GCOMM_CONF_ADD_DEFAULT(PcChecksum); GCOMM_CONF_ADD_DEFAULT(PcAnnounceTimeout); GCOMM_CONF_ADD (PcLinger); GCOMM_CONF_ADD_DEFAULT(PcNpvo); GCOMM_CONF_ADD (PcBootstrap); GCOMM_CONF_ADD_DEFAULT(PcWaitPrim); GCOMM_CONF_ADD_DEFAULT(PcWaitPrimTimeout); GCOMM_CONF_ADD_DEFAULT(PcWeight); GCOMM_CONF_ADD_DEFAULT(PcRecovery); #undef GCOMM_CONF_ADD #undef GCOMM_CONF_ADD_DEFAULT } percona-galera-3-3.8-3390/gcomm/src/datagram.cpp000066400000000000000000000056551244131713600211720ustar00rootroot00000000000000/* * Copyright (C) 2013 Codership Oy */ #include "gcomm/datagram.hpp" #include "gu_crc.hpp" // CRC-32C - optimized and potentially accelerated #include "gu_logger.hpp" #include "gu_throw.hpp" #include // CRC32 - backward compatible gcomm::NetHeader::checksum_t gcomm::NetHeader::checksum_type (int i) { switch(i) { case CS_NONE: log_info << "Message checksums disabled."; return CS_NONE; case CS_CRC32: log_info << "Using CRC-32 (backward-compatible) for message checksums."; return CS_CRC32; case CS_CRC32C: log_info << "Using CRC-32C for message checksums."; return CS_CRC32C; } log_warn << "Ignoring unknown checksum type: " << i << ". Falling back to CRC-32."; return CS_CRC32; } uint16_t gcomm::crc16(const gcomm::Datagram& dg, size_t offset) { assert(offset < dg.len()); gu::byte_t lenb[4]; gu::serialize4(static_cast(dg.len() - offset), lenb, sizeof(lenb), 0); boost::crc_16_type crc; crc.process_block(lenb, lenb + sizeof(lenb)); if (offset < dg.header_len()) { crc.process_block(dg.header_ + dg.header_offset_ + offset, dg.header_ + dg.header_size_); offset = 0; } else { offset -= dg.header_len(); } crc.process_block(&(*dg.payload_)[0] + offset, &(*dg.payload_)[0] + dg.payload_->size()); return crc.checksum(); } uint32_t gcomm::crc32(gcomm::NetHeader::checksum_t const type, const gcomm::Datagram& dg, size_t offset) { boost::crc_32_type crc; gu::byte_t lenb[4]; gu::serialize4(static_cast(dg.len() - offset), lenb, sizeof(lenb), 0); if (NetHeader::CS_CRC32 == type) { boost::crc_32_type crc; crc.process_block(lenb, lenb + sizeof(lenb)); if (offset < dg.header_len()) { crc.process_block(dg.header_ + dg.header_offset_ + offset, dg.header_ + dg.header_size_); offset = 0; } else { offset -= dg.header_len(); } crc.process_block(&(*dg.payload_)[0] + offset, &(*dg.payload_)[0] + dg.payload_->size()); return crc.checksum(); } else if (NetHeader::CS_CRC32C == type) { gu::CRC32C crc; crc.append (lenb, sizeof(lenb)); if (offset < dg.header_len()) { crc.append (dg.header_ + dg.header_offset_ + offset, dg.header_size_ - dg.header_offset_ - offset); offset = 0; } else { offset -= dg.header_len(); } crc.append (&(*dg.payload_)[0] + offset, dg.payload_->size() - offset); return crc(); } gu_throw_error(EINVAL) << "Unsupported checksum algorithm: " << type; } percona-galera-3-3.8-3390/gcomm/src/defaults.cpp000066400000000000000000000053071244131713600212130ustar00rootroot00000000000000/* * Copyright (C) 2012-2014 Codership Oy */ #include "defaults.hpp" #include "gcomm/common.hpp" namespace gcomm { #ifdef HAVE_ASIO_HPP std::string const Defaults::ProtonetBackend = "asio"; #else #error "Only asio protonet backend is currently supported" #endif /* HAVE_ASIO_HPP */ std::string const Defaults::ProtonetVersion = "0"; std::string const Defaults::SocketChecksum = "2"; std::string const Defaults::GMCastVersion = "0"; std::string const Defaults::GMCastTcpPort = BASE_PORT_DEFAULT; std::string const Defaults::GMCastSegment = "0"; std::string const Defaults::GMCastTimeWait = "PT5S"; std::string const Defaults::GMCastPeerTimeout = "PT3S"; std::string const Defaults::EvsViewForgetTimeout = "PT24H"; std::string const Defaults::EvsViewForgetTimeoutMin = "PT1S"; std::string const Defaults::EvsInactiveCheckPeriod = "PT0.5S"; std::string const Defaults::EvsSuspectTimeout = "PT5S"; std::string const Defaults::EvsSuspectTimeoutMin = "PT0.1S"; std::string const Defaults::EvsInactiveTimeout = "PT15S"; std::string const Defaults::EvsInactiveTimeoutMin = "PT0.1S"; std::string const Defaults::EvsRetransPeriod = "PT1S"; std::string const Defaults::EvsRetransPeriodMin = "PT0.1S"; std::string const Defaults::EvsJoinRetransPeriod = "PT1S"; std::string const Defaults::EvsStatsReportPeriod = "PT1M"; std::string const Defaults::EvsStatsReportPeriodMin = "PT1S"; std::string const Defaults::EvsSendWindow = "4"; std::string const Defaults::EvsSendWindowMin = "1"; std::string const Defaults::EvsUserSendWindow = "2"; std::string const Defaults::EvsUserSendWindowMin = "1"; std::string const Defaults::EvsMaxInstallTimeouts = "3"; std::string const Defaults::EvsDelayMargin = "PT1S"; std::string const Defaults::EvsDelayedKeepPeriod = "PT30S"; std::string const Defaults::EvsAutoEvict = "0"; std::string const Defaults::PcAnnounceTimeout = "PT3S"; std::string const Defaults::PcChecksum = "false"; std::string const Defaults::PcIgnoreQuorum = "false"; std::string const Defaults::PcIgnoreSb = PcIgnoreQuorum; std::string const Defaults::PcNpvo = "false"; std::string const Defaults::PcVersion = "0"; std::string const Defaults::PcWaitPrim = "true"; std::string const Defaults::PcWaitPrimTimeout = "P30S"; std::string const Defaults::PcWeight = "1"; std::string const Defaults::PcRecovery = "1"; } percona-galera-3-3.8-3390/gcomm/src/defaults.hpp000066400000000000000000000047121244131713600212170ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #ifndef GCOMM_DEFAULTS_HPP #define GCOMM_DEFAULTS_HPP #include namespace gcomm { struct Defaults { static std::string const ProtonetBackend ; static std::string const ProtonetVersion ; static std::string const SocketChecksum ; static std::string const GMCastVersion ; static std::string const GMCastTcpPort ; static std::string const GMCastSegment ; static std::string const GMCastTimeWait ; static std::string const GMCastPeerTimeout ; static std::string const EvsViewForgetTimeout ; static std::string const EvsViewForgetTimeoutMin ; static std::string const EvsInactiveCheckPeriod ; static std::string const EvsSuspectTimeout ; static std::string const EvsSuspectTimeoutMin ; static std::string const EvsInactiveTimeout ; static std::string const EvsInactiveTimeoutMin ; static std::string const EvsRetransPeriod ; static std::string const EvsRetransPeriodMin ; static std::string const EvsJoinRetransPeriod ; static std::string const EvsStatsReportPeriod ; static std::string const EvsStatsReportPeriodMin ; static std::string const EvsSendWindow ; static std::string const EvsSendWindowMin ; static std::string const EvsUserSendWindow ; static std::string const EvsUserSendWindowMin ; static std::string const EvsMaxInstallTimeouts ; static std::string const EvsDelayMargin ; static std::string const EvsDelayedKeepPeriod ; static std::string const EvsAutoEvict ; static std::string const PcAnnounceTimeout ; static std::string const PcChecksum ; static std::string const PcIgnoreQuorum ; static std::string const PcIgnoreSb ; static std::string const PcNpvo ; static std::string const PcVersion ; static std::string const PcWaitPrim ; static std::string const PcWaitPrimTimeout ; static std::string const PcWeight ; static std::string const PcRecovery ; }; } #endif // GCOMM_DEFAULTS_HPP percona-galera-3-3.8-3390/gcomm/src/evs_consensus.cpp000066400000000000000000000425561244131713600223100ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "evs_consensus.hpp" #include "evs_message2.hpp" #include "evs_input_map2.hpp" #include "evs_node.hpp" #include "evs_proto.hpp" #include "gcomm/view.hpp" #include "gu_logger.hpp" #include // Disable debug logging until debug mask is available here #define evs_log_debug(i) if ((proto_.debug_mask_ & gcomm::evs::Proto::D_CONSENSUS) == 0) \ {} else log_debug << proto_.uuid() << " " // // Helpers // class LeaveSeqCmpOp { public: bool operator()(const gcomm::evs::MessageNodeList::value_type& a, const gcomm::evs::MessageNodeList::value_type& b) const { using gcomm::evs::MessageNode; using gcomm::evs::MessageNodeList; const MessageNode& aval(MessageNodeList::value(a)); const MessageNode& bval(MessageNodeList::value(b)); gcomm_assert(aval.leaving() != false && bval.leaving() != false); const gcomm::evs::seqno_t asec(aval.leave_seq()); const gcomm::evs::seqno_t bsec(bval.leave_seq()); gcomm_assert(asec != -1 && bsec != -1); return (asec < bsec); } }; class RangeLuCmp { public: bool operator()(const gcomm::evs::MessageNodeList::value_type& a, const gcomm::evs::MessageNodeList::value_type& b) const { return (gcomm::evs::MessageNodeList::value(a).im_range().lu() < gcomm::evs::MessageNodeList::value(b).im_range().lu()); } }; class SafeSeqCmp { public: bool operator()(const gcomm::evs::MessageNodeList::value_type& a, const gcomm::evs::MessageNodeList::value_type& b) const { return (gcomm::evs::MessageNodeList::value(a).safe_seq() < gcomm::evs::MessageNodeList::value(b).safe_seq()); } }; // // // bool gcomm::evs::Consensus::equal(const Message& m1, const Message& m2) const { gcomm_assert(m1.type() == Message::T_JOIN || m1.type() == Message::T_INSTALL); gcomm_assert(m2.type() == Message::T_JOIN || m2.type() == Message::T_INSTALL); // Seq and aru seq are comparable only if coming from same view if (m1.source_view_id() == m2.source_view_id()) { if (m1.seq() != m2.seq()) { evs_log_debug(D_CONSENSUS) << "seq not equal " << m1.seq() << " " << m2.seq(); return false; } if (m1.aru_seq() != m2.aru_seq()) { evs_log_debug(D_CONSENSUS) << "aruseq not equal " << m1.aru_seq() << " " << m2.aru_seq(); return false; } } MessageNodeList nl1, nl2; // When comparing messages from same source whole node list is comparable, // otherwise only operational part of it. if (m1.source() == m2.source()) { for_each(m1.node_list().begin(), m1.node_list().end(), SelectNodesOp(nl1, m1.source_view_id(), true, true)); for_each(m2.node_list().begin(), m2.node_list().end(), SelectNodesOp(nl2, m2.source_view_id(), true, true)); } else { for_each(m1.node_list().begin(), m1.node_list().end(), SelectNodesOp(nl1, ViewId(), true, false)); for_each(m2.node_list().begin(), m2.node_list().end(), SelectNodesOp(nl2, ViewId(), true, false)); } evs_log_debug(D_CONSENSUS) << "nl1: " << nl1 << " nl2: " << nl2; return (nl1 == nl2); } gcomm::evs::seqno_t gcomm::evs::Consensus::highest_reachable_safe_seq() const { std::list seq_list; for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); const JoinMessage* jm(node.join_message()); const LeaveMessage* lm(node.leave_message()); if ((jm == 0 && current_view_.is_member(NodeMap::key(i)) == true) || (jm != 0 && jm->source_view_id() == current_view_.id()) || (lm != 0 && lm->source_view_id() == current_view_.id())) { if (lm != 0) { if (proto_.is_all_suspected(uuid) == false) { seq_list.push_back(lm->seq()); } } else if (node.operational() == false) { seq_list.push_back( std::min( input_map_.safe_seq(node.index()), input_map_.range(node.index()).lu() - 1)); } else { seq_list.push_back(input_map_.range(node.index()).hs()); } } } return *std::min_element(seq_list.begin(), seq_list.end()); } gcomm::evs::seqno_t gcomm::evs::Consensus::safe_seq_wo_all_susupected_leaving_nodes() const { seqno_t safe_seq(-2); for(NodeMap::const_iterator i = proto_.known_.begin(); i != proto_.known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); if (node.index() != std::numeric_limits::max()) { if (node.operational() == false && node.leave_message() && proto_.is_all_suspected(uuid)) { continue; } seqno_t ss = input_map_.safe_seq(node.index()); if (safe_seq == -2 || ss < safe_seq) { safe_seq = ss; } } } return safe_seq; } namespace gcomm { namespace evs { class FilterAllSuspectedOp { public: FilterAllSuspectedOp(MessageNodeList& nl, const Proto& proto) : nl_(nl), proto_(proto) {} void operator()(const MessageNodeList::value_type& vt) const { const UUID& uuid(MessageNodeList::key(vt)); if (!proto_.is_all_suspected(uuid)) { nl_.insert_unique(vt); } } private: MessageNodeList& nl_; const Proto& proto_; }; } // evs } // gcomm bool gcomm::evs::Consensus::is_consistent_highest_reachable_safe_seq( const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); gcomm_assert(msg.source_view_id() == current_view_.id()); const MessageNodeList& node_list(msg.node_list()); // Same view MessageNodeList same_view; for_each(node_list.begin(), node_list.end(), SelectNodesOp(same_view, current_view_.id(), true, false)); MessageNodeList::const_iterator max_hs_i(max_element(same_view.begin(), same_view.end(), RangeHsCmp())); gcomm_assert(max_hs_i != same_view.end()); // Max highest seen const seqno_t max_hs( MessageNodeList::value(max_hs_i).im_range().hs()); seqno_t max_reachable_safe_seq(max_hs); // Leaving Nodes MessageNodeList t_leaving; for_each(node_list.begin(), node_list.end(), SelectNodesOp(t_leaving, current_view_.id(), false, true)); MessageNodeList leaving; for_each(t_leaving.begin(), t_leaving.end(), FilterAllSuspectedOp(leaving, proto_)); if (leaving.empty() == false) { const MessageNodeList::const_iterator min_leave_seq_i( std::min_element(leaving.begin(), leaving.end(), LeaveSeqCmpOp())); gcomm_assert(min_leave_seq_i != leaving.end()); const seqno_t min_leave_seq( MessageNodeList::value(min_leave_seq_i).leave_seq()); max_reachable_safe_seq = std::min(max_reachable_safe_seq, min_leave_seq); } // Partitioning nodes MessageNodeList partitioning; for_each(node_list.begin(), node_list.end(), SelectNodesOp(partitioning, current_view_.id(), false, false)); if (partitioning.empty() == false) { MessageNodeList::const_iterator min_part_safe_seq_i( std::min_element(partitioning.begin(), partitioning.end(), SafeSeqCmp())); gcomm_assert(min_part_safe_seq_i != partitioning.end()); const seqno_t min_part_safe_seq( MessageNodeList::value(min_part_safe_seq_i).safe_seq()); max_reachable_safe_seq = std::min(max_reachable_safe_seq, min_part_safe_seq); MessageNodeList::const_iterator min_part_lu_i( std::min_element(partitioning.begin(), partitioning.end(), RangeLuCmp())); gcomm_assert(min_part_lu_i != partitioning.end()); const seqno_t min_part_lu(MessageNodeList::value(min_part_lu_i).im_range().lu() - 1); max_reachable_safe_seq = std::min(max_reachable_safe_seq, min_part_lu); } evs_log_debug(D_CONSENSUS) << " max reachable safe seq " << max_reachable_safe_seq << " highest reachable safe seq " << highest_reachable_safe_seq() << " max_hs " << max_hs << " input map max hs " << input_map_.max_hs() << " input map safe_seq " << input_map_.safe_seq() << " safe seq wo suspected leaving nodes " << safe_seq_wo_all_susupected_leaving_nodes(); return (input_map_.max_hs() == max_hs && highest_reachable_safe_seq() == max_reachable_safe_seq && // input_map_.safe_seq() == max_reachable_safe_seq); safe_seq_wo_all_susupected_leaving_nodes() == max_reachable_safe_seq); } bool gcomm::evs::Consensus::is_consistent_input_map(const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); gcomm_assert(msg.source_view_id() == current_view_.id()); if (msg.aru_seq() != input_map_.aru_seq()) { evs_log_debug(D_CONSENSUS) << "message aru seq " << msg.aru_seq() << " not consistent with input map aru seq " << input_map_.aru_seq(); return false; } if (msg.seq() != input_map_.safe_seq()) { evs_log_debug(D_CONSENSUS) << "message safe seq " << msg.seq() << " not consistent with input map safe seq " << input_map_.safe_seq(); return false; } Map local_insts, msg_insts; for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); if (current_view_.is_member(uuid) == true) { gu_trace((void)local_insts.insert_unique( std::make_pair(uuid, input_map_.range(node.index())))); } } const MessageNodeList& m_insts(msg.node_list()); for (MessageNodeList::const_iterator i = m_insts.begin(); i != m_insts.end(); ++i) { const UUID& msg_uuid(MessageNodeList::key(i)); const MessageNode& msg_inst(MessageNodeList::value(i)); if (msg_inst.view_id() == current_view_.id()) { gu_trace((void)msg_insts.insert_unique( std::make_pair(msg_uuid, msg_inst.im_range()))); } } evs_log_debug(D_CONSENSUS) << " msg_insts " << msg_insts << " local_insts " << local_insts; return (msg_insts == local_insts); } bool gcomm::evs::Consensus::is_consistent_partitioning(const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); gcomm_assert(msg.source_view_id() == current_view_.id()); // Compare instances that were present in the current view but are // not proceeding in the next view. Map local_insts, msg_insts; for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); if (node.operational() == false && node.leave_message() == 0 && current_view_.is_member(uuid) == true) { gu_trace((void)local_insts.insert_unique( std::make_pair(uuid, input_map_.range(node.index())))); } } const MessageNodeList& m_insts = msg.node_list(); for (MessageNodeList::const_iterator i = m_insts.begin(); i != m_insts.end(); ++i) { const UUID& m_uuid(MessageNodeList::key(i)); const MessageNode& m_inst(MessageNodeList::value(i)); if (m_inst.operational() == false && m_inst.leaving() == false && m_inst.view_id() == current_view_.id()) { gu_trace((void)msg_insts.insert_unique( std::make_pair(m_uuid, m_inst.im_range()))); } } evs_log_debug(D_CONSENSUS) << " msg insts:\n" << msg_insts << " local insts:\n" << local_insts; return (msg_insts == local_insts); } bool gcomm::evs::Consensus::is_consistent_leaving(const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); gcomm_assert(msg.source_view_id() == current_view_.id()); // Compare instances that were present in the current view but are // not proceeding in the next view. Map local_insts, msg_insts; for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& inst(NodeMap::value(i)); const LeaveMessage* lm(inst.leave_message()); if (inst.operational() == false && lm != 0 && lm->source_view_id() == current_view_.id()) { gu_trace((void)local_insts.insert_unique( std::make_pair(uuid, input_map_.range(inst.index())))); } } const MessageNodeList& m_insts = msg.node_list(); for (MessageNodeList::const_iterator i = m_insts.begin(); i != m_insts.end(); ++i) { const UUID& m_uuid(MessageNodeList::key(i)); const MessageNode& m_inst(MessageNodeList::value(i)); if (m_inst.operational() == false && m_inst.leaving() == true && m_inst.view_id() == current_view_.id()) { gu_trace((void)msg_insts.insert_unique( std::make_pair(m_uuid, m_inst.im_range()))); } } evs_log_debug(D_CONSENSUS) << " msg insts " << msg_insts << " local insts " << local_insts; return (local_insts == msg_insts); } bool gcomm::evs::Consensus::is_consistent_same_view(const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); gcomm_assert(msg.source_view_id() == current_view_.id()); if (is_consistent_highest_reachable_safe_seq(msg) == false) { evs_log_debug(D_CONSENSUS) << "highest reachable safe seq not consistent"; return false; } if (is_consistent_input_map(msg) == false) { evs_log_debug(D_CONSENSUS) << "input map not consistent with " << msg; return false; } if (is_consistent_partitioning(msg) == false) { evs_log_debug(D_CONSENSUS) << "partitioning not consistent with " << msg; return false; } if (is_consistent_leaving(msg) == false) { evs_log_debug(D_CONSENSUS) << "leaving not consistent with " << msg; return false; } return true; } bool gcomm::evs::Consensus::is_consistent(const Message& msg) const { gcomm_assert(msg.type() == Message::T_JOIN || msg.type() == Message::T_INSTALL); const JoinMessage* my_jm = NodeMap::value(known_.find_checked(proto_.uuid())).join_message(); if (my_jm == 0) { return false; } if (msg.source_view_id() == current_view_.id()) { return (is_consistent_same_view(msg) == true && equal(msg, *my_jm) == true); } else { return equal(msg, *my_jm); } } bool gcomm::evs::Consensus::is_consensus() const { const JoinMessage* my_jm = NodeMap::value(known_.find_checked(proto_.uuid())).join_message(); if (my_jm == 0) { evs_log_debug(D_CONSENSUS) << "no own join message"; return false; } if (is_consistent_same_view(*my_jm) == false) { evs_log_debug(D_CONSENSUS) << "own join message not consistent"; return false; } for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const Node& inst(NodeMap::value(i)); if (inst.operational() == true) { const JoinMessage* jm = inst.join_message(); if (jm == 0) { evs_log_debug(D_CONSENSUS) << "no join message for " << NodeMap::key(i); return false; } // call is_consistent() instead of equal() to enforce strict // check for messages originating from the same view (#541) if (is_consistent(*jm) == false) { evs_log_debug(D_CONSENSUS) << "join message " << *jm << " not consistent with my join " << *my_jm; return false; } } } return true; } percona-galera-3-3.8-3390/gcomm/src/evs_consensus.hpp000066400000000000000000000036111244131713600223020ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #ifndef GCOMM_EVS_CONSENSUS_HPP #define GCOMM_EVS_CONSENSUS_HPP #include "evs_seqno.hpp" namespace gcomm { class UUID; class View; namespace evs { class NodeMap; class InputMap; class Message; class Consensus; class Proto; } } class gcomm::evs::Consensus { public: Consensus(const Proto& proto, const NodeMap& known, const InputMap& input_map, const View& current_view) : proto_ (proto), known_ (known), input_map_ (input_map), current_view_(current_view) { } /*! * Compare two messages if they are equal in consensus context. */ bool equal(const Message&, const Message&) const; /*! * Compute highest reachable safe seq from local state. * * @return Highest reachable safe seq. */ seqno_t highest_reachable_safe_seq() const; // input map safe seq but without considering // all suspected leaving nodes. seqno_t safe_seq_wo_all_susupected_leaving_nodes() const; /*! * Check if highest reachable safe seq according to message * consistent with local state. */ bool is_consistent_highest_reachable_safe_seq(const Message&) const; /*! * Check if message aru seq, safe seq and node ranges matches to * local state. */ bool is_consistent_input_map(const Message&) const; bool is_consistent_partitioning(const Message&) const; bool is_consistent_leaving(const Message&) const; bool is_consistent_same_view(const Message&) const; bool is_consistent(const Message&) const; bool is_consensus() const; private: const Proto& proto_; const NodeMap& known_; const InputMap& input_map_; const View& current_view_; }; #endif // GCOMM_EVS_CONSENSUS_HPP percona-galera-3-3.8-3390/gcomm/src/evs_input_map2.cpp000066400000000000000000000257231244131713600223430ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "evs_input_map2.hpp" #include "gcomm/util.hpp" #include "gu_exception.hpp" #include "gu_logger.hpp" #include "gu_buffer.hpp" #include #include ////////////////////////////////////////////////////////////////////////// // // Static operators and functions // ////////////////////////////////////////////////////////////////////////// // Compare node index LUs class NodeIndexLUCmpOp { public: bool operator()(const gcomm::evs::InputMapNodeIndex::value_type& a, const gcomm::evs::InputMapNodeIndex::value_type& b) const { return (a.range().lu() < b.range().lu()); } }; class NodeIndexHSCmpOp { public: bool operator()(const gcomm::evs::InputMapNodeIndex::value_type& a, const gcomm::evs::InputMapNodeIndex::value_type& b) const { return (a.range().hs() < b.range().hs()); } }; // Compare node index safe seqs class NodeIndexSafeSeqCmpOp { public: bool operator()(const gcomm::evs::InputMapNodeIndex::value_type& a, const gcomm::evs::InputMapNodeIndex::value_type& b) const { return a.safe_seq() < b.safe_seq(); } }; ////////////////////////////////////////////////////////////////////////// // // Ostream operators // ////////////////////////////////////////////////////////////////////////// std::ostream& gcomm::evs::operator<<(std::ostream& os, const InputMapNode& in) { return (os << "node: {" << "idx=" << in.index() << "," << "range=" << in.range() << "," << "safe_seq=" << in.safe_seq() << "}"); } std::ostream& gcomm::evs::operator<<(std::ostream& os, const InputMapNodeIndex& ni) { copy(ni.begin(), ni.end(), std::ostream_iterator(os, " ")); return os; } std::ostream& gcomm::operator<<(std::ostream& os, const InputMapMsgKey& mk) { return (os << "(" << mk.index() << "," << mk.seq() << ")"); } std::ostream& gcomm::evs::operator<<(std::ostream& os, const InputMapMsg& m) { return (os << m.msg()); } std::ostream& gcomm::evs::operator<<(std::ostream& os, const InputMap& im) { return (os << "evs::input_map: {" << "aru_seq=" << im.aru_seq() << "," << "safe_seq=" << im.safe_seq() << "," << "node_index=" << *im.node_index_ #ifndef NDEBUG << "," << "msg_index=" << *im.msg_index_ << "," << "recovery_index=" << *im.recovery_index_ #endif // !NDEBUG << "}"); } ////////////////////////////////////////////////////////////////////////// // // Constructors/destructors // ////////////////////////////////////////////////////////////////////////// gcomm::evs::InputMap::InputMap() : window_ (-1), safe_seq_ (-1), aru_seq_ (-1), node_index_ (new InputMapNodeIndex()), msg_index_ (new InputMapMsgIndex()), recovery_index_ (new InputMapMsgIndex()), n_msgs_ (O_SAFE + 1), max_droppable_ (16) { } gcomm::evs::InputMap::~InputMap() { clear(); delete node_index_; delete msg_index_; delete recovery_index_; } ////////////////////////////////////////////////////////////////////////// // // Public member functions // ////////////////////////////////////////////////////////////////////////// void gcomm::evs::InputMap::reset(const size_t nodes, const seqno_t window) { gcomm_assert(msg_index_->empty() == true && recovery_index_->empty() == true && accumulate(n_msgs_.begin(), n_msgs_.end(), 0) == 0); node_index_->clear(); window_ = window; log_debug << " size " << node_index_->size(); gu_trace(node_index_->resize(nodes, InputMapNode())); for (size_t i = 0; i < nodes; ++i) { node_index_->at(i).set_index(i); } log_debug << *node_index_ << " size " << node_index_->size(); } gcomm::evs::seqno_t gcomm::evs::InputMap::min_hs() const { seqno_t ret; gcomm_assert(node_index_->empty() == false); ret = min_element(node_index_->begin(), node_index_->end(), NodeIndexHSCmpOp())->range().hs(); return ret; } gcomm::evs::seqno_t gcomm::evs::InputMap::max_hs() const { seqno_t ret; gcomm_assert(node_index_->empty() == false); ret = max_element(node_index_->begin(), node_index_->end(), NodeIndexHSCmpOp())->range().hs(); return ret; } void gcomm::evs::InputMap::set_safe_seq(const size_t uuid, const seqno_t seq) { gcomm_assert(seq != -1); // @note This assertion does not necessarily hold. Some other // instance may well have higher all received up to seqno // than this (due to packet loss). Commented out... and left // for future reference. // gcomm_assert(aru_seq != seqno_t::max() && seq <= aru_seq); // Update node safe seq. Must (at least should) be updated // in monotonically increasing order if node works ok. InputMapNode& node(node_index_->at(uuid)); gcomm_assert(seq >= node.safe_seq()) << "node.safe_seq=" << node.safe_seq() << " seq=" << seq; node.set_safe_seq(seq); // Update global safe seq which must be monotonically increasing. InputMapNodeIndex::const_iterator min = min_element(node_index_->begin(), node_index_->end(), NodeIndexSafeSeqCmpOp()); const seqno_t minval = min->safe_seq(); gcomm_assert(minval >= safe_seq_); safe_seq_ = minval; // Global safe seq must always be smaller than equal to aru seq gcomm_assert(safe_seq_ <= aru_seq_); // Cleanup recovery index cleanup_recovery_index(); } void gcomm::evs::InputMap::clear() { if (msg_index_->empty() == false) { log_warn << "discarding " << msg_index_->size() << " messages from message index"; } msg_index_->clear(); if (recovery_index_->empty() == false) { log_debug << "discarding " << recovery_index_->size() << " messages from recovery index"; } recovery_index_->clear(); node_index_->clear(); aru_seq_ = -1; safe_seq_ = -1; fill(n_msgs_.begin(), n_msgs_.end(), 0); } gcomm::evs::Range gcomm::evs::InputMap::insert(const size_t uuid, const UserMessage& msg, const Datagram& rb) { Range range; // Only insert messages with meaningful seqno gcomm_assert(msg.seq() > -1); // User should check aru_seq before inserting. This check is left // also in optimized builds since violating it may cause duplicate // messages. gcomm_assert(aru_seq_ < msg.seq()) << "aru seq " << aru_seq_ << " msg seq " << msg.seq() << " index size " << msg_index_->size(); gcomm_assert(uuid < node_index_->size()); InputMapNode& node((*node_index_)[uuid]); range = node.range(); // User should check LU before inserting. This check is left // also in optimized builds since violating it may cause duplicate // messages gcomm_assert(range.lu() <= msg.seq()) << "lu " << range.lu() << " > " << msg.seq(); // Check whether this message has already been seen if (msg.seq() < node.range().lu() || (msg.seq() <= node.range().hs() && recovery_index_->find(InputMapMsgKey(node.index(), msg.seq())) != recovery_index_->end())) { return node.range(); } // Loop over message seqno range and insert messages when not // already found for (seqno_t s = msg.seq(); s <= msg.seq() + msg.seq_range(); ++s) { InputMapMsgIndex::iterator msg_i; if (range.hs() < s) { msg_i = msg_index_->end(); } else { msg_i = msg_index_->find(InputMapMsgKey(node.index(), s)); } if (msg_i == msg_index_->end()) { Datagram ins_dg(s == msg.seq() ? Datagram(rb) : Datagram()); gu_trace((void)msg_index_->insert_unique( std::make_pair( InputMapMsgKey(node.index(), s), InputMapMsg( (s == msg.seq() ? msg : UserMessage(msg.version(), msg.source(), msg.source_view_id(), s, msg.aru_seq(), 0, O_DROP)), ins_dg)))); ++n_msgs_[msg.order()]; } // Update highest seen if (range.hs() < s) { range.set_hs(s); } // Update lowest unseen if (range.lu() == s) { seqno_t i(s); do { ++i; } while ( i <= range.hs() && (msg_index_->find(InputMapMsgKey(node.index(), i)) != msg_index_->end() || recovery_index_->find(InputMapMsgKey(node.index(), i)) != recovery_index_->end())); range.set_lu(i); } } node.set_range(range); update_aru(); return range; } void gcomm::evs::InputMap::erase(iterator i) { const UserMessage& msg(InputMapMsgIndex::value(i).msg()); --n_msgs_[msg.order()]; gu_trace(recovery_index_->insert_unique(*i)); gu_trace(msg_index_->erase(i)); } gcomm::evs::InputMap::iterator gcomm::evs::InputMap::find(const size_t uuid, const seqno_t seq) const { iterator ret; const InputMapNode& node(node_index_->at(uuid)); const InputMapMsgKey key(node.index(), seq); gu_trace(ret = msg_index_->find(key)); return ret; } gcomm::evs::InputMap::iterator gcomm::evs::InputMap::recover(const size_t uuid, const seqno_t seq) const { iterator ret; const InputMapNode& node(node_index_->at(uuid)); const InputMapMsgKey key(node.index(), seq); gu_trace(ret = recovery_index_->find_checked(key)); return ret; } ////////////////////////////////////////////////////////////////////////// // // Private member functions // ////////////////////////////////////////////////////////////////////////// inline void gcomm::evs::InputMap::update_aru() { InputMapNodeIndex::const_iterator min = min_element(node_index_->begin(), node_index_->end(), NodeIndexLUCmpOp()); const seqno_t minval = min->range().lu(); /* aru_seq must not decrease */ gcomm_assert(minval - 1 >= aru_seq_); aru_seq_ = minval - 1; } void gcomm::evs::InputMap::cleanup_recovery_index() { gcomm_assert(node_index_->size() > 0); InputMapMsgIndex::iterator i = recovery_index_->lower_bound( InputMapMsgKey(0, safe_seq_ + 1)); recovery_index_->erase(recovery_index_->begin(), i); } percona-galera-3-3.8-3390/gcomm/src/evs_input_map2.hpp000066400000000000000000000230611244131713600223410ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! * @file Input map for EVS messaging. Provides simple interface for * handling messages with different safety guarantees. * * @note When operating with iterators, note that evs::Message * accessed through iterator may have different sequence * number as it position dictates. Use sequence number * found from key part. * * @todo Fix issue in above note if feasible. */ #ifndef EVS_INPUT_MAP2_HPP #define EVS_INPUT_MAP2_HPP #include "evs_message2.hpp" #include "gcomm/map.hpp" #include "gcomm/datagram.hpp" #include namespace gcomm { /* Forward declarations */ class InputMapMsgKey; std::ostream& operator<<(std::ostream&, const InputMapMsgKey&); namespace evs { class InputMapMsg; std::ostream& operator<<(std::ostream&, const InputMapMsg&); class InputMapMsgIndex; class InputMapNode; std::ostream& operator<<(std::ostream&, const InputMapNode&); typedef std::vector InputMapNodeIndex; std::ostream& operator<<(std::ostream&, const InputMapNodeIndex&); class InputMap; } } /* Internal msg representation */ class gcomm::InputMapMsgKey { public: InputMapMsgKey(const size_t index, const evs::seqno_t seq) : index_ (index), seq_ (seq) { } size_t index() const { return index_; } evs::seqno_t seq () const { return seq_; } bool operator<(const InputMapMsgKey& cmp) const { return (seq_ < cmp.seq_ || (seq_ == cmp.seq_ && index_ < cmp.index_)); } private: size_t const index_; evs::seqno_t const seq_; }; /* Internal message representation */ class gcomm::evs::InputMapMsg { public: InputMapMsg(const UserMessage& msg, const Datagram& rb) : msg_(msg), rb_ (rb) { } InputMapMsg(const InputMapMsg& m) : msg_(m.msg_), rb_ (m.rb_) { } ~InputMapMsg() { } const UserMessage& msg () const { return msg_; } const Datagram& rb () const { return rb_; } private: void operator=(const InputMapMsg&); UserMessage const msg_; Datagram rb_; }; #if defined(GALERA_USE_BOOST_POOL_ALLOC) #include class gcomm::evs::InputMapMsgIndex : public Map, boost::fast_pool_allocator< std::pair, boost::default_user_allocator_new_delete, boost::details::pool::null_mutex > > > {}; #else /* GALERA_USE_BOOST_POOL_ALLOC */ class gcomm::evs::InputMapMsgIndex : public Map {}; #endif /* GALERA_USE_BOOST_POOL_ALLOC */ /* Internal node representation */ class gcomm::evs::InputMapNode { public: InputMapNode() : idx_(), range_(0, -1), safe_seq_(-1) { } void set_range (const Range r) { range_ = r; } void set_safe_seq (const seqno_t s) { safe_seq_ = s; } void set_index (const size_t i) { idx_ = i; } Range range () const { return range_; } seqno_t safe_seq () const { return safe_seq_; } size_t index () const { return idx_; } private: size_t idx_; Range range_; seqno_t safe_seq_; }; /*! * Input map for messages. * */ class gcomm::evs::InputMap { public: /* Iterators exposed to user */ typedef InputMapMsgIndex::iterator iterator; typedef InputMapMsgIndex::const_iterator const_iterator; /*! * Default constructor. */ InputMap(); /*! * Default destructor. */ ~InputMap(); /*! * Get current value of aru_seq. * * @return Current value of aru_seq */ seqno_t aru_seq () const { return aru_seq_; } /*! * Get current value of safe_seq. * * @return Current value of safe_seq */ seqno_t safe_seq() const { return safe_seq_; } /*! * Set sequence number safe for node. * * @param uuid Node uuid * @param seq Sequence number to be set safe * * @throws FatalException if node was not found or sequence number * was not in the allowed range */ void set_safe_seq(const size_t uuid, const seqno_t seq); /*! * Get current value of safe_seq for node. * * @param uuid Node uuid * * @return Safe sequence number for node * * @throws FatalException if node was not found */ seqno_t safe_seq(const size_t uuid) const { return node_index_->at(uuid).safe_seq(); } /*! * Get current range parameter for node * * @param uuid Node uuid * * @return Range parameter for node * * @throws FatalException if node was not found */ Range range (const size_t uuid) const { return node_index_->at(uuid).range(); } seqno_t min_hs() const; seqno_t max_hs() const; /*! * Get iterator to the beginning of the input map * * @return Iterator pointing to the first element */ iterator begin() const { return msg_index_->begin(); } /*! * Get iterator next to the last element of the input map * * @return Iterator pointing past the last element */ iterator end () const { return msg_index_->end(); } /*! * Check if message pointed by iterator fulfills O_SAFE condition. * * @return True or false */ bool is_safe (iterator i) const { const seqno_t seq(InputMapMsgIndex::key(i).seq()); return (seq <= safe_seq_); } /*! * Check if message pointed by iterator fulfills O_AGREED condition. * * @return True or false */ bool is_agreed(iterator i) const { const seqno_t seq(InputMapMsgIndex::key(i).seq()); return (seq <= aru_seq_); } /*! * Check if message pointed by iterator fulfills O_FIFO condition. * * @return True or false */ bool is_fifo (iterator i) const { const seqno_t seq(InputMapMsgIndex::key(i).seq()); const InputMapNode& node((*node_index_)[ InputMapMsgIndex::key(i).index()]); return (node.range().lu() > seq); } bool has_deliverables() const { if (msg_index_->empty() == false) { if (n_msgs_[O_FIFO] > 0 && is_fifo(msg_index_->begin())) return true; else if (n_msgs_[O_AGREED] > 0 && is_agreed(msg_index_->begin())) return true; else if (n_msgs_[O_SAFE] > 0 && is_safe(msg_index_->begin())) return true; else if (n_msgs_[O_DROP] > max_droppable_) return true; return false; } else { return false; } } /*! * Insert new message into input map. * * @param uuid Node uuid of the message source * @param msg EVS message * @param rb ReadBuf pointer associated to message * @param offset Offset to the beginning of the payload * * @return Range parameter of the node * * @throws FatalException if node not found or message sequence * number is out of allowed range */ Range insert(const size_t uuid, const UserMessage& msg, const Datagram& dg = Datagram()); /*! * Erase message pointed by iterator. Note that message may still * be recovered through recover() method as long as it does not * fulfill O_SAFE constraint. * * @param i Iterator * * @throws FatalException if iterator is not valid */ void erase(iterator i); /*! * Find message. * * @param uuid Message source node uuid * @param seq Message sequence numeber * * @return Iterator pointing to message or at end() if message was not found * * @throws FatalException if node was not found */ iterator find(const size_t uuid, const seqno_t seq) const; /*! * Recover message. * * @param uuid Message source node uuid * @param seq Message sequence number * * @return Iterator pointing to the message * * @throws FatalException if node or message was not found */ iterator recover(const size_t uuid, const seqno_t seq) const; /*! * */ void reset(const size_t, const seqno_t = 256); /*! * Clear input map state. */ void clear(); private: friend std::ostream& operator<<(std::ostream&, const InputMap&); /* Non-copyable */ InputMap(const InputMap&); void operator=(const InputMap&); /*! * Update aru_seq value to represent current state. */ void update_aru(); /*! * Clean up recovery index. All messages up to safe_seq are removed. */ void cleanup_recovery_index(); seqno_t window_; seqno_t safe_seq_; /*!< Safe seqno */ seqno_t aru_seq_; /*!< All received upto seqno */ InputMapNodeIndex* node_index_; /*!< Index of nodes */ InputMapMsgIndex* msg_index_; /*!< Index of messages */ InputMapMsgIndex* recovery_index_; /*!< Recovery index */ std::vector n_msgs_; size_t max_droppable_; }; #endif // EVS_INPUT_MAP2_HPP percona-galera-3-3.8-3390/gcomm/src/evs_message2.cpp000066400000000000000000000501511244131713600217640ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy * * $Id$ */ #include "evs_message2.hpp" #include "gu_exception.hpp" #include "gu_logger.hpp" std::ostream& gcomm::evs::operator<<(std::ostream& os, const gcomm::evs::MessageNode& node) { os << " {"; os << "o=" << node.operational() << ","; os << "s=" << node.suspected() << ","; os << "e=" << node.evicted() << ","; os << "ls=" << node.leave_seq() << ","; os << "vid=" << node.view_id() << ","; os << "ss=" << node.safe_seq() << ","; os << "ir=" << node.im_range() << ","; os << "}"; return os; } std::ostream& gcomm::evs::operator<<(std::ostream& os, const gcomm::evs::Message& msg) { os << "{"; os << "v=" << static_cast(msg.version()) << ","; os << "t=" << msg.type() << ","; os << "ut=" << static_cast(msg.user_type()) << ","; os << "o=" << msg.order() << ","; os << "s=" << msg.seq() << ","; os << "sr=" << msg.seq_range() << ","; os << "as=" << msg.aru_seq() << ","; os << "f=" << static_cast(msg.flags()) << ","; os << "src=" << msg.source() << ","; os << "srcvid=" << msg.source_view_id() << ","; os << "insvid=" << msg.install_view_id() << ","; os << "ru=" << msg.range_uuid() << ","; os << "r=" << msg.range() << ","; os << "fs=" << msg.fifo_seq() << ","; os << "nl=(\n" << msg.node_list() << ")\n"; os << "}"; return os; } size_t gcomm::evs::MessageNode::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { uint8_t b = static_cast((operational_ == true ? F_OPERATIONAL : 0) | (suspected_ == true ? F_SUSPECTED : 0) | (evicted_ == true ? F_EVICTED : 0)); gu_trace(offset = gu::serialize1(b, buf, buflen, offset)); gu_trace(offset = gu::serialize1(segment_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(leave_seq_, buf, buflen, offset)); gu_trace(offset = view_id_.serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize8(safe_seq_, buf, buflen, offset)); gu_trace(offset = im_range_.serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::MessageNode::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset) { uint8_t b; gu_trace(offset = gu::unserialize1(buf, buflen, offset, b)); if ((b & ~(F_OPERATIONAL | F_SUSPECTED | F_EVICTED)) != 0) { log_warn << "unknown flags: " << static_cast(b); } operational_ = b & F_OPERATIONAL; suspected_ = b & F_SUSPECTED; evicted_ = b & F_EVICTED; gu_trace(offset = gu::unserialize1(buf, buflen, offset, segment_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, leave_seq_)); gu_trace(offset = view_id_.unserialize(buf, buflen, offset)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, safe_seq_)); gu_trace(offset = im_range_.unserialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::MessageNode::serial_size() { return 2 + // 4 bytes reserved for flags sizeof(seqno_t) + ViewId::serial_size() + sizeof(seqno_t) + Range::serial_size(); } bool gcomm::evs::Message::operator==(const Message& cmp) const { return (version_ == cmp.version_ && type_ == cmp.type_ && user_type_ == cmp.user_type_ && order_ == cmp.order_ && seq_ == cmp.seq_ && seq_range_ == cmp.seq_range_ && aru_seq_ == cmp.aru_seq_ && fifo_seq_ == cmp.fifo_seq_ && flags_ == cmp.flags_ && source_ == cmp.source_ && source_view_id_ == cmp.source_view_id_ && install_view_id_ == cmp.install_view_id_ && range_uuid_ == cmp.range_uuid_ && range_ == cmp.range_ && node_list_ == cmp.node_list_); } // // Header format: // 0 1 2 3 // | 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 | // |-----------------------------------------------------------------| // | zv | t | o | flags | real version | reserved | // |-----------------------------------------------------------------| // | fifo_seq | // | ... | // |-----------------------------------------------------------------| // | source | // | ... | // | ... | // | ... | // |-----------------------------------------------------------------| // |-----------------------------------------------------------------| // | source view id | // | ... | // | ... | // | ... | // | ... | // |-----------------------------------------------------------------| // // // zv - zeroversion // if zeroversion is 0, message version is 0, otherwise it is // read from real version // t - type // o - order // size_t gcomm::evs::Message::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { uint8_t zeroversion; switch (type_) { case T_JOIN: case T_INSTALL: zeroversion = 0; break; default: zeroversion = (version_ != 0 ? 1 : 0); } uint8_t b = static_cast(zeroversion | (type_ << 2) | (order_ << 5)); gu_trace(offset = gu::serialize1(b, buf, buflen, offset)); gu_trace(offset = gu::serialize1(flags_, buf, buflen, offset)); gu_trace(offset = gu::serialize1(version_, buf, buflen, offset)); gu_trace(offset = gu::serialize1(uint8_t(0), buf, buflen, offset)); gu_trace(offset = gu::serialize8(fifo_seq_, buf, buflen, offset)); if (flags_ & F_SOURCE) { gu_trace(offset = source_.serialize(buf, buflen, offset)); } gu_trace(offset = source_view_id_.serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::Message::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset) { uint8_t b; gu_trace(offset = gu::unserialize1(buf, buflen, offset, b)); // The message version will be read from offset 16 regardless what is // the zeroversion value. The only purpose of zeroversion is to // make pre 3.8 nodes to discard messages in new format. type_ = static_cast((b >> 2) & 0x7); if (type_ <= T_NONE || type_ > T_DELAYED_LIST) { gu_throw_error(EINVAL) << "invalid type " << type_; } order_ = static_cast((b >> 5) & 0x7); if (order_ < O_DROP || order_ > O_SAFE) { gu_throw_error(EINVAL) << "invalid safety prefix " << order_; } gu_trace(offset = gu::unserialize1(buf, buflen, offset, flags_)); gu_trace(offset = gu::unserialize1(buf, buflen, offset, version_)); switch (type_) { case T_JOIN: case T_INSTALL: // Join and install message will always remain protocol zero, // version check is not applicable. break; default: if (version_ > GCOMM_PROTOCOL_MAX_VERSION) { gu_throw_error(EPROTONOSUPPORT) << "protocol version " << static_cast(version_) << " not supported"; } break; } uint8_t reserved; gu_trace(offset = gu::unserialize1(buf, buflen, offset, reserved)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, fifo_seq_)); if (flags_ & F_SOURCE) { gu_trace(offset = source_.unserialize(buf, buflen, offset)); } gu_trace(offset = source_view_id_.unserialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::Message::serial_size() const { return (1 + // version | type | order 1 + // flags 2 + // pad sizeof(fifo_seq_) + // fifo_seq ((flags_ & F_SOURCE) ? UUID::serial_size() : 0) + ViewId::serial_size()); // source_view_id } size_t gcomm::evs::UserMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize1(user_type_, buf, buflen, offset)); gcomm_assert(seq_range_ <= seqno_t(0xff)); uint8_t b = static_cast(seq_range_); gu_trace(offset = gu::serialize1(b, buf, buflen, offset)); gu_trace(offset = gu::serialize2(uint16_t(0), buf, buflen, offset)); gu_trace(offset = gu::serialize8(seq_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(aru_seq_, buf, buflen, offset)); return offset; } size_t gcomm::evs::UserMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } gu_trace(offset = gu::unserialize1(buf, buflen, offset, user_type_)); uint8_t b; gu_trace(offset = gu::unserialize1(buf, buflen, offset, b)); seq_range_ = b; uint16_t pad; gu_trace(offset = gu::unserialize2(buf, buflen, offset, pad)); if (pad != 0) { log_warn << "invalid pad: " << pad; } gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_)); return offset; } size_t gcomm::evs::UserMessage::serial_size() const { return Message::serial_size() + // Header 1 + // User type 1 + // Seq range 2 + // Pad/reserved sizeof(seqno_t) + // Seq sizeof(seqno_t); // Aru seq } size_t gcomm::evs::AggregateMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = gu::serialize1(flags_, buf, buflen, offset)); gu_trace(offset = gu::serialize1(user_type_, buf, buflen, offset)); gu_trace(offset = gu::serialize2(len_, buf, buflen, offset)); return offset; } size_t gcomm::evs::AggregateMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset) { gu_trace(offset = gu::unserialize1(buf, buflen, offset, flags_)); gu_trace(offset = gu::unserialize1(buf, buflen, offset, user_type_)); gu_trace(offset = gu::unserialize2(buf, buflen, offset, len_)); return offset; } size_t gcomm::evs::AggregateMessage::serial_size() const { return sizeof(flags_) + sizeof(len_) + sizeof(user_type_); } size_t gcomm::evs::DelegateMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::DelegateMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } return offset; } size_t gcomm::evs::DelegateMessage::serial_size() const { return Message::serial_size(); } size_t gcomm::evs::GapMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize8(seq_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(aru_seq_, buf, buflen, offset)); gu_trace(offset = range_uuid_.serialize(buf, buflen, offset)); gu_trace(offset = range_.serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::GapMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_)); gu_trace(offset = range_uuid_.unserialize(buf, buflen, offset)); gu_trace(offset = range_.unserialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::GapMessage::serial_size() const { return (Message::serial_size() + 2 * sizeof(seqno_t) + UUID::serial_size() + Range::serial_size()); } size_t gcomm::evs::JoinMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize8(seq_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(aru_seq_, buf, buflen, offset)); gu_trace(offset = node_list_.serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::JoinMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_)); node_list_.clear(); gu_trace(offset = node_list_.unserialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::JoinMessage::serial_size() const { return (Message::serial_size() + 2 * sizeof(seqno_t) + node_list_.serial_size()); } size_t gcomm::evs::InstallMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize8(seq_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(aru_seq_, buf, buflen, offset)); gu_trace(offset = install_view_id_.serialize(buf, buflen, offset)); gu_trace(offset = node_list_.serialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::InstallMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_)); gu_trace(offset = install_view_id_.unserialize(buf, buflen, offset)); node_list_.clear(); gu_trace(offset = node_list_.unserialize(buf, buflen, offset)); return offset; } size_t gcomm::evs::InstallMessage::serial_size() const { return (Message::serial_size() + 2 * sizeof(seqno_t) + ViewId::serial_size() + node_list_.serial_size()); } size_t gcomm::evs::LeaveMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize8(seq_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(aru_seq_, buf, buflen, offset)); return offset; } size_t gcomm::evs::LeaveMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } gu_trace(offset = gu::unserialize8(buf, buflen, offset, seq_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, aru_seq_)); return offset; } size_t gcomm::evs::LeaveMessage::serial_size() const { return (Message::serial_size() + 2 * sizeof(seqno_t)); } size_t gcomm::evs::DelayedListMessage::serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = Message::serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize1(static_cast(delayed_list_.size()), buf, buflen, offset)); for (DelayedList::const_iterator i(delayed_list_.begin()); i != delayed_list_.end(); ++i) { gu_trace(offset = i->first.serialize(buf, buflen, offset)); gu_trace(offset = gu::serialize1(i->second, buf, buflen, offset)); } return offset; } size_t gcomm::evs::DelayedListMessage::unserialize(const gu::byte_t* const buf, size_t const buflen, size_t offset, bool skip_header) { if (skip_header == false) { gu_trace(offset = Message::unserialize(buf, buflen, offset)); } delayed_list_.clear(); uint8_t list_sz(0); gu_trace(offset = gu::unserialize1(buf, buflen, offset, list_sz)); for (uint8_t i(0); i < list_sz; ++i) { UUID uuid; uint8_t cnt; gu_trace(offset = uuid.unserialize(buf, buflen, offset)); gu_trace(offset = gu::unserialize1(buf, buflen, offset, cnt)); delayed_list_.insert(std::make_pair(uuid, cnt)); } return offset; } size_t gcomm::evs::DelayedListMessage::serial_size() const { return (Message::serial_size() + gu::serial_size(uint8_t(0)) + std::min( delayed_list_.size(), static_cast(std::numeric_limits::max())) * (UUID::serial_size() + gu::serial_size(uint8_t(0)))); } percona-galera-3-3.8-3390/gcomm/src/evs_message2.hpp000066400000000000000000000552421244131713600217770ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ #ifndef EVS_MESSAGE2_HPP #define EVS_MESSAGE2_HPP #include "gcomm/order.hpp" #include "gcomm/view.hpp" #include "gcomm/map.hpp" #include "evs_seqno.hpp" #include "protocol_version.hpp" #include "gu_datetime.hpp" #include "gu_convert.hpp" namespace gcomm { namespace evs { class MessageNode; std::ostream& operator<<(std::ostream&, const MessageNode&); class MessageNodeList; class Message; std::ostream& operator<<(std::ostream&, const Message&); class UserMessage; class AggregateMessage; std::ostream& operator<<(std::ostream&, const AggregateMessage&); class DelegateMessage; class GapMessage; class JoinMessage; class LeaveMessage; class InstallMessage; class DelayedListMessage; class SelectNodesOp; class RangeLuCmp; class RangeHsCmp; } } class gcomm::evs::MessageNode { public: MessageNode(const bool operational = false, const bool suspected = false, const SegmentId segment = 0, const bool evicted = false, const seqno_t leave_seq = -1, const ViewId& view_id = ViewId(V_REG), const seqno_t safe_seq = -1, const Range im_range = Range()) : operational_(operational), suspected_ (suspected ), segment_ (segment ), evicted_ (evicted ), leave_seq_ (leave_seq ), view_id_ (view_id ), safe_seq_ (safe_seq ), im_range_ (im_range ) { } MessageNode(const MessageNode& mn) : operational_ (mn.operational_), suspected_ (mn.suspected_ ), segment_ (mn.segment_ ), evicted_ (mn.evicted_ ), leave_seq_ (mn.leave_seq_ ), view_id_ (mn.view_id_ ), safe_seq_ (mn.safe_seq_ ), im_range_ (mn.im_range_ ) { } bool operational() const { return operational_ ; } bool suspected() const { return suspected_ ; } bool evicted() const { return evicted_ ; } bool leaving() const { return (leave_seq_ != -1) ; } seqno_t leave_seq() const { return leave_seq_ ; } const ViewId& view_id() const { return view_id_ ; } seqno_t safe_seq() const { return safe_seq_ ; } Range im_range() const { return im_range_ ; } SegmentId segment() const { return segment_ ; } bool operator==(const MessageNode& cmp) const { return (operational_ == cmp.operational_ && suspected_ == cmp.suspected_ && leave_seq_ == cmp.leave_seq_ && view_id_ == cmp.view_id_ && safe_seq_ == cmp.safe_seq_ && im_range_ == cmp.im_range_); } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); static size_t serial_size(); private: enum { F_OPERATIONAL = 1 << 0, F_SUSPECTED = 1 << 1, F_EVICTED = 1 << 2 }; bool operational_; // Is operational bool suspected_; SegmentId segment_; bool evicted_; // Evicted out of the cluster seqno_t leave_seq_; ViewId view_id_; // Current view as seen by source of this message seqno_t safe_seq_; // Safe seq as seen... Range im_range_; // Input map range as seen... }; class gcomm::evs::MessageNodeList : public gcomm::Map { }; /*! * EVS message class */ class gcomm::evs::Message { public: enum Type { T_NONE = 0, T_USER = 1, /*!< User generated message */ T_DELEGATE = 2, /*!< Delegate message */ T_GAP = 3, /*!< Gap message */ T_JOIN = 4, /*!< Join message */ T_INSTALL = 5, /*!< Install message */ T_LEAVE = 6, /*!< Leave message */ T_DELAYED_LIST = 7 /*!< Evict list message */ }; typedef std::map DelayedList; static const uint8_t F_MSG_MORE = 0x1; /*!< Sender has more messages to send */ static const uint8_t F_RETRANS = 0x2; /*!< Message is resent upon request */ /*! * @brief Message source has been set explicitly via set_source() */ static const uint8_t F_SOURCE = 0x4; static const uint8_t F_AGGREGATE= 0x8; /*!< Message contains aggregated payload */ static const uint8_t F_COMMIT = 0x10; static const uint8_t F_BC = 0x20;/*!< Message was sent in backward compatibility mode */ /*! * Get version of the message * * @return Version number */ uint8_t version() const { return version_; } /*! * Get type of the message * * @return Message type */ Type type() const { return type_; } /*! * Check wheter message is of membership type * * @return True if message is of membership type, otherwise false */ bool is_membership() const { return (type_ == T_JOIN || type_ == T_INSTALL || type_ == T_LEAVE || type_ == T_DELAYED_LIST); } /*! * Get user type of the message. This is applicable only for * messages of type T_USER. * * @return User type of the message. */ uint8_t user_type() const { return user_type_; } /*! * Get message order type. * * @return Order type of the message. */ Order order() const { return order_; } /*! * Get sequence number associated to the message. * * @return Const reference to sequence number associated to the message. */ seqno_t seq() const { return seq_; } /*! * Get sequence numer range associated to the message. * * @return Sequence number range associated to the message. */ seqno_t seq_range() const { return seq_range_; } /*! * Get all-received-upto sequence number associated the the message. * * @return All-received-upto sequence number associated to the message. */ seqno_t aru_seq() const { return aru_seq_; } void set_flags(uint8_t flags) { flags_ = flags; } /*! * Get message flags. * * @return Message flags. */ uint8_t flags() const { return flags_; } /*! * Set message source * * @param uuid Source node uuid */ void set_source(const UUID& uuid) { source_ = uuid; flags_ |= F_SOURCE; } /*! * Get message source UUID. * * @return Message source UUID. */ const UUID& source() const { return source_; } /*! * Get message source view id, view where the message was originated * from. * * @return Message source view id. */ const gcomm::ViewId& source_view_id() const { return source_view_id_; } const gcomm::ViewId& install_view_id() const { return install_view_id_; } /*! * Get range UUID associated to the message. * * @return Range UUID associated to the message. */ const UUID& range_uuid() const { return range_uuid_; } /*! * Get range associated to the message. * * @return Range associated to the message. */ Range range() const { return range_; } /*! * Get fifo sequence number associated to the message. This is * applicable only for messages of membership type. * * @return Fifo sequence number associated to the message. */ int64_t fifo_seq() const { return fifo_seq_; } /*! * Get message node list. * * @return Const reference to message node list. */ const MessageNodeList& node_list() const { return node_list_; } /*! * Get timestamp associated to the message. */ gu::datetime::Date tstamp() const { return tstamp_; } size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); bool operator==(const Message& cmp) const; /*! * Copy constructor. */ Message(const Message& msg) : version_ (msg.version_), type_ (msg.type_), user_type_ (msg.user_type_), order_ (msg.order_), seq_ (msg.seq_), seq_range_ (msg.seq_range_), aru_seq_ (msg.aru_seq_), fifo_seq_ (msg.fifo_seq_), flags_ (msg.flags_), source_ (msg.source_), source_view_id_ (msg.source_view_id_), install_view_id_ (msg.install_view_id_), range_uuid_ (msg.range_uuid_), range_ (msg.range_), tstamp_ (msg.tstamp_), node_list_ (msg.node_list_), delayed_list_ (msg.delayed_list_) { } Message& operator=(const Message& msg) { version_ = msg.version_; type_ = msg.type_; user_type_ = msg.user_type_; order_ = msg.order_; seq_ = msg.seq_; seq_range_ = msg.seq_range_; aru_seq_ = msg.aru_seq_; fifo_seq_ = msg.fifo_seq_; flags_ = msg.flags_; source_ = msg.source_; source_view_id_ = msg.source_view_id_; install_view_id_ = msg.install_view_id_; range_uuid_ = msg.range_uuid_; range_ = msg.range_; tstamp_ = msg.tstamp_; node_list_ = msg.node_list_; delayed_list_ = msg.delayed_list_; return *this; } virtual ~Message() { } /*! Default constructor */ Message(const uint8_t version = 0, const Type type = T_NONE, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const ViewId& install_view_id = ViewId(), const uint8_t user_type = 0xff, const Order order = O_DROP, const int64_t fifo_seq = -1, const seqno_t seq = -1, const seqno_t seq_range = -1, const seqno_t aru_seq = -1, const uint8_t flags = 0, const UUID& range_uuid = UUID(), const Range range = Range(), const MessageNodeList& node_list = MessageNodeList()) : version_ (version), type_ (type), user_type_ (user_type), order_ (order), seq_ (seq), seq_range_ (seq_range), aru_seq_ (aru_seq), fifo_seq_ (fifo_seq), flags_ (flags), source_ (source), source_view_id_ (source_view_id), install_view_id_ (install_view_id), range_uuid_ (range_uuid), range_ (range), tstamp_ (gu::datetime::Date::now()), node_list_ (node_list), delayed_list_ () { } protected: size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t serial_size() const; // Version number: // For User, Gap, Leave messages that are exchanged only within a group // the version is minimum commonly supported version among the group, // computed during GATHER phase. // For Join, Install messages version is maximum supported protocol // version by the joiner. uint8_t version_; Type type_; uint8_t user_type_; Order order_; seqno_t seq_; seqno_t seq_range_; seqno_t aru_seq_; int64_t fifo_seq_; uint8_t flags_; UUID source_; ViewId source_view_id_; ViewId install_view_id_; UUID range_uuid_; Range range_; gu::datetime::Date tstamp_; MessageNodeList node_list_; DelayedList delayed_list_; }; /*! * User message class. */ class gcomm::evs::UserMessage : public Message { public: UserMessage(const int version = -1, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const seqno_t seq = -1, const seqno_t aru_seq = -1, const seqno_t seq_range = 0, const Order order = O_SAFE, const int64_t fifo_seq = -1, const uint8_t user_type = 0xff, const uint8_t flags = 0) : Message(version, Message::T_USER, source, source_view_id, ViewId(), user_type, order, fifo_seq, seq, seq_range, aru_seq, flags, UUID(), Range()) { } void set_aru_seq(const seqno_t as) { aru_seq_ = as; } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::AggregateMessage { public: AggregateMessage(const int flags = 0, const size_t len = 0, const uint8_t user_type = 0xff) : flags_ (gu::convert(flags, uint8_t(0))), user_type_(user_type), len_ (gu::convert(len, uint16_t(0))) { } int flags() const { return flags_; } size_t len() const { return len_; } uint8_t user_type() const { return user_type_; } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); size_t serial_size() const; bool operator==(const AggregateMessage& cmp) const { return (flags_ == cmp.flags_ && len_ == cmp.len_ && user_type_ == cmp.user_type_); } private: uint8_t flags_; uint8_t user_type_; uint16_t len_; }; inline std::ostream& gcomm::evs::operator<<(std::ostream& os, const AggregateMessage& am) { return (os << "{flags=" << am.flags() << ",len=" << am.len() << "}"); } class gcomm::evs::DelegateMessage : public Message { public: DelegateMessage(const int version = -1, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const int64_t fifo_seq = -1) : Message(version, T_DELEGATE, source, source_view_id, ViewId(), 0xff, O_UNRELIABLE, fifo_seq) { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::GapMessage : public Message { public: GapMessage(const int version = -1, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const seqno_t seq = -1, const seqno_t aru_seq = -1, const int64_t fifo_seq = -1, const UUID& range_uuid = UUID::nil(), const Range range = Range(), const uint8_t flags = 0) : Message(version, T_GAP, source, source_view_id, ViewId(), 0xff, O_UNRELIABLE, fifo_seq, seq, -1, aru_seq, flags, range_uuid, range) { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::JoinMessage : public Message { public: JoinMessage(const int max_version = 0, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const seqno_t seq = -1, const seqno_t aru_seq = -1, const int64_t fifo_seq = -1, const MessageNodeList& node_list = MessageNodeList()) : Message(max_version, Message::T_JOIN, source, source_view_id, ViewId(), 0xff, O_UNRELIABLE, fifo_seq, seq, -1, aru_seq, 0, UUID(), Range(), node_list) { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::InstallMessage : public Message { public: InstallMessage(const int max_version = 0, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const ViewId& install_view_id = ViewId(), const seqno_t seq = -1, const seqno_t aru_seq = -1, const int64_t fifo_seq = -1, const MessageNodeList& node_list = MessageNodeList()) : Message(max_version, Message::T_INSTALL, source, source_view_id, install_view_id, 0xff, O_UNRELIABLE, fifo_seq, seq, -1, aru_seq, F_SOURCE, UUID(), Range(), node_list) { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::LeaveMessage : public Message { public: LeaveMessage(const int version = -1, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const seqno_t seq = -1, const seqno_t aru_seq = -1, const int64_t fifo_seq = -1, const uint8_t flags = 0) : Message(version, T_LEAVE, source, source_view_id, ViewId(), 0xff, O_UNRELIABLE, fifo_seq, seq, -1, aru_seq, flags) { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; }; class gcomm::evs::DelayedListMessage : public Message { public: DelayedListMessage(const int version = -1, const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const seqno_t fifo_seq = -1) : Message(version, T_DELAYED_LIST, source, source_view_id, ViewId(), 0xff, O_DROP, fifo_seq) { } void add(const UUID& uuid, uint16_t cnt) { delayed_list_.insert(std::make_pair(uuid, cnt)); } const DelayedList& delayed_list() const { return delayed_list_; } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, bool skip_header = false); size_t serial_size() const; bool operator==(const DelayedListMessage& cmp) const { return (delayed_list_ == cmp.delayed_list_); } private: }; class gcomm::evs::SelectNodesOp { public: SelectNodesOp(MessageNodeList& nl, const gcomm::ViewId& view_id, const bool operational, const bool leaving) : nl_ (nl), view_id_ (view_id), operational_ (operational), leaving_ (leaving) { } void operator()(const MessageNodeList::value_type& vt) const { const MessageNode& node(MessageNodeList::value(vt)); if ((view_id_ == ViewId() || node.view_id() == view_id_ ) && ((operational_ == true && leaving_ == true ) || (node.operational() == operational_ && node.leaving() == leaving_ ) ) ) { nl_.insert_unique(vt); } } private: MessageNodeList& nl_; ViewId const view_id_; bool const operational_; bool const leaving_; }; class gcomm::evs::RangeLuCmp { public: bool operator()(const MessageNodeList::value_type& a, const MessageNodeList::value_type& b) const { gcomm_assert(MessageNodeList::value(a).view_id() == MessageNodeList::value(b).view_id()); return (MessageNodeList::value(a).im_range().lu() < MessageNodeList::value(b).im_range().lu()); } }; class gcomm::evs::RangeHsCmp { public: bool operator()(const MessageNodeList::value_type& a, const MessageNodeList::value_type& b) const { gcomm_assert(MessageNodeList::value(a).view_id() == MessageNodeList::value(b).view_id()); return (MessageNodeList::value(a).im_range().hs() < MessageNodeList::value(b).im_range().hs()); } }; #endif // EVS_MESSAGE2_HPP percona-galera-3-3.8-3390/gcomm/src/evs_node.cpp000066400000000000000000000064361244131713600212120ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "evs_node.hpp" #include "evs_proto.hpp" #include "evs_message2.hpp" #include std::ostream& gcomm::evs::operator<<(std::ostream& os, const gcomm::evs::Node& n) { os << "{"; os << "o=" << n.operational() << ","; os << "s=" << n.suspected() << ","; os << "i=" << n.installed() << ","; os << "fs=" << n.fifo_seq() << ","; if (n.join_message() != 0) { os << "jm=\n" << *n.join_message() << ",\n"; } if (n.leave_message() != 0) { os << "lm=\n" << *n.leave_message() << ",\n"; } os << "}"; return os; } gcomm::evs::Node::Node(const Node& n) : proto_ (n.proto_), index_ (n.index_), operational_ (n.operational_), suspected_ (n.suspected_), inactive_ (n.inactive_), committed_ (n.committed_), installed_ (n.installed_), join_message_ (n.join_message_ != 0 ? new JoinMessage(*n.join_message_) : 0), leave_message_ (n.leave_message_ != 0 ? new LeaveMessage(*n.leave_message_) : 0), delayed_list_message_ (n.delayed_list_message_ != 0 ? new DelayedListMessage(*n.delayed_list_message_) : 0), tstamp_ (n.tstamp_), seen_tstamp_ (n.seen_tstamp_), fifo_seq_ (n.fifo_seq_), segment_ (n.segment_) { } gcomm::evs::Node::~Node() { delete join_message_; delete leave_message_; } void gcomm::evs::Node::set_join_message(const JoinMessage* jm) { if (join_message_ != 0) { delete join_message_; } if (jm != 0) { join_message_ = new JoinMessage(*jm); } else { join_message_ = 0; } } void gcomm::evs::Node::set_leave_message(const LeaveMessage* lm) { if (leave_message_ != 0) { delete leave_message_; } if (lm != 0) { leave_message_ = new LeaveMessage(*lm); } else { leave_message_ = 0; } } void gcomm::evs::Node::set_delayed_list_message(const DelayedListMessage* elm) { if (delayed_list_message_ != 0) { delete delayed_list_message_; } delayed_list_message_ = (elm == 0 ? 0 : new DelayedListMessage(*elm)); } bool gcomm::evs::Node::is_suspected() const { return suspected_; } bool gcomm::evs::Node::is_inactive() const { return inactive_; } void gcomm::evs::InspectNode::operator()(std::pair& p) const { Node& node(p.second); gu::datetime::Date now(gu::datetime::Date::now()); if (node.tstamp() + node.proto_.suspect_timeout_ < now) { if (node.suspected_ == false) { log_debug << "declaring node with index " << node.index_ << " suspected, timeout " << node.proto_.suspect_timeout_; } node.suspected_ = true; } else { node.suspected_ = false; } if (node.tstamp() + node.proto_.inactive_timeout_ < now) { if (node.inactive_ == false) { log_debug << "declaring node with index " << node.index_ << " inactive "; } node.inactive_ = true; } else { node.inactive_ = false; } } percona-galera-3-3.8-3390/gcomm/src/evs_node.hpp000066400000000000000000000104071244131713600212100ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef EVS_NODE_HPP #define EVS_NODE_HPP #include "evs_message2.hpp" #include "gcomm/map.hpp" #include "gcomm/uuid.hpp" #include "gu_datetime.hpp" #include "gu_logger.hpp" #include #include namespace gcomm { namespace evs { class Node; class NodeMap; std::ostream& operator<<(std::ostream&, const Node&); class InspectNode; class OperationalSelect; class Proto; } } class gcomm::evs::Node { public: Node(const Proto& proto) : proto_ (proto), index_ (std::numeric_limits::max()), operational_ (true), suspected_ (false), inactive_ (false), committed_ (false), installed_ (false), join_message_ (0), leave_message_ (0), delayed_list_message_(0), tstamp_ (gu::datetime::Date::now()), seen_tstamp_ (tstamp_), fifo_seq_ (-1), segment_ (0) {} Node(const Node& n); ~Node(); void set_index(const size_t idx) { index_ = idx; } size_t index() const { return index_; } void set_operational(const bool op) { gcomm_assert(op == false); operational_ = op; } bool operational() const { return operational_; } void set_suspected(const bool s) { suspected_ = s; } bool suspected() const { return suspected_; } void set_committed(const bool comm) { committed_ = comm; } bool committed() const { return committed_; } void set_installed(const bool inst) { installed_ = inst; } bool installed() const { return installed_; } void set_join_message(const JoinMessage* msg); const JoinMessage* join_message() const { return join_message_; } void set_leave_message(const LeaveMessage* msg); const LeaveMessage* leave_message() const { return leave_message_; } void set_delayed_list_message(const DelayedListMessage* msg); const DelayedListMessage *delayed_list_message() const { return delayed_list_message_; } void set_tstamp(const gu::datetime::Date& t) { tstamp_ = t; } const gu::datetime::Date& tstamp() const { return tstamp_; } void set_seen_tstamp(const gu::datetime::Date& t) { seen_tstamp_ = t; } const gu::datetime::Date& seen_tstamp() const { return seen_tstamp_; } void set_fifo_seq(const int64_t seq) { fifo_seq_ = seq; } int64_t fifo_seq() const { return fifo_seq_; } SegmentId segment() const { return segment_; } bool is_inactive() const; bool is_suspected() const; private: void operator=(const Node&); friend class InspectNode; const Proto& proto_; // Index for input map size_t index_; // True if instance is considered to be operational (has produced messages) bool operational_; bool suspected_; bool inactive_; // True if it is known that the instance has committed to install message bool committed_; // True if it is known that the instance has installed current view bool installed_; // Last received JOIN message JoinMessage* join_message_; // Leave message LeaveMessage* leave_message_; // Delayed list message DelayedListMessage* delayed_list_message_; // Timestamp denoting the last time a message from node // advanced input map state or membership protocol. This is used // for determining if the node should become suspected/inactive. gu::datetime::Date tstamp_; // Timestamp denoting the time when the node was seen last time. // This is used to decide if the node should be considered delayed. gu::datetime::Date seen_tstamp_; int64_t fifo_seq_; SegmentId segment_; }; class gcomm::evs::NodeMap : public Map { }; class gcomm::evs::OperationalSelect { public: OperationalSelect(NodeMap& nm_) : nm(nm_) { } void operator()(const NodeMap::value_type& vt) const { if (NodeMap::value(vt).operational() == true) { nm.insert_unique(vt); } } private: NodeMap& nm; }; class gcomm::evs::InspectNode { public: void operator()(std::pair& p) const; }; #endif // EVS_NODE_HPP percona-galera-3-3.8-3390/gcomm/src/evs_proto.cpp000066400000000000000000004720501244131713600214270ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #ifdef PROFILE_EVS_PROTO #define GCOMM_PROFILE 1 #else #undef GCOMM_PROFILE #endif // PROFILE_EVS_PROTO #include "evs_proto.hpp" #include "evs_message2.hpp" #include "evs_input_map2.hpp" #include "gcomm/transport.hpp" #include "gcomm/conf.hpp" #include "gcomm/util.hpp" #include "defaults.hpp" #include #include #include #include #include #include using namespace std::rel_ops; // Convenience macros for debug and info logging #define evs_log_debug(__mask__) \ if ((debug_mask_ & (__mask__)) == 0) { } \ else log_debug << self_string() << ": " #define evs_log_info(__mask__) \ if ((info_mask_ & (__mask__)) == 0) { } \ else log_info << self_string() << ": " gcomm::evs::Proto::Proto(gu::Config& conf, const UUID& my_uuid, SegmentId segment, const gu::URI& uri, const size_t mtu, const View* rst_view) : Protolay(conf), timers_(), version_(check_range(Conf::EvsVersion, param(conf, uri, Conf::EvsVersion, "0"), 0, GCOMM_PROTOCOL_MAX_VERSION + 1)), debug_mask_(param(conf, uri, Conf::EvsDebugLogMask, "0x1", std::hex)), info_mask_(param(conf, uri, Conf::EvsInfoLogMask, "0x0", std::hex)), last_stats_report_(gu::datetime::Date::now()), collect_stats_(true), hs_agreed_("0.0,0.0001,0.00031623,0.001,0.0031623,0.01,0.031623,0.1,0.31623,1.,3.1623,10.,31.623"), hs_safe_("0.0,0.0001,0.00031623,0.001,0.0031623,0.01,0.031623,0.1,0.31623,1.,3.1623,10.,31.623"), hs_local_causal_("0.0,0.0001,0.00031623,0.001,0.0031623,0.01,0.031623,0.1,0.31623,1.,3.1623,10.,31.623"), safe_deliv_latency_(), send_queue_s_(0), n_send_queue_s_(0), sent_msgs_(7, 0), retrans_msgs_(0), recovered_msgs_(0), recvd_msgs_(7, 0), delivered_msgs_(O_LOCAL_CAUSAL + 1), send_user_prof_ ("send_user"), send_gap_prof_ ("send_gap"), send_join_prof_ ("send_join"), send_install_prof_ ("send_install"), send_leave_prof_ ("send_leave"), consistent_prof_ ("consistent"), consensus_prof_ ("consensus"), shift_to_prof_ ("shift_to"), input_map_prof_ ("input_map"), delivery_prof_ ("delivery"), delivering_(false), my_uuid_(my_uuid), segment_(segment), known_(), self_i_(), view_forget_timeout_( check_range(Conf::EvsViewForgetTimeout, param( conf, uri, Conf::EvsViewForgetTimeout, Defaults::EvsViewForgetTimeout), gu::from_string( Defaults::EvsViewForgetTimeoutMin), gu::datetime::Period::max())), inactive_timeout_( check_range(Conf::EvsInactiveTimeout, param( conf, uri, Conf::EvsInactiveTimeout, Defaults::EvsInactiveTimeout), gu::from_string( Defaults::EvsInactiveTimeoutMin), gu::datetime::Period::max())), suspect_timeout_( check_range(Conf::EvsSuspectTimeout, param( conf, uri, Conf::EvsSuspectTimeout, Defaults::EvsSuspectTimeout), gu::from_string( Defaults::EvsSuspectTimeoutMin), gu::datetime::Period::max())), inactive_check_period_( check_range(Conf::EvsInactiveCheckPeriod, param( conf, uri, Conf::EvsInactiveCheckPeriod, Defaults::EvsInactiveCheckPeriod), gu::datetime::Period::min(), suspect_timeout_/2 + 1)), retrans_period_( check_range(Conf::EvsKeepalivePeriod, param( conf, uri, Conf::EvsKeepalivePeriod, Defaults::EvsRetransPeriod), gu::from_string( Defaults::EvsRetransPeriodMin), suspect_timeout_/3 + 1)), install_timeout_( check_range(Conf::EvsInstallTimeout, param( conf, uri, Conf::EvsInstallTimeout, gu::to_string(inactive_timeout_/2)), retrans_period_, inactive_timeout_ + 1)), join_retrans_period_( check_range(Conf::EvsJoinRetransPeriod, param( conf, uri, Conf::EvsJoinRetransPeriod, Defaults::EvsJoinRetransPeriod), gu::from_string( Defaults::EvsRetransPeriodMin), gu::datetime::Period::max())), stats_report_period_( check_range(Conf::EvsStatsReportPeriod, param( conf, uri, Conf::EvsStatsReportPeriod, Defaults::EvsStatsReportPeriod), gu::from_string( Defaults::EvsStatsReportPeriodMin), gu::datetime::Period::max())), causal_keepalive_period_(retrans_period_), delay_margin_(param( conf, uri, Conf::EvsDelayMargin, Defaults::EvsDelayMargin)), delayed_keep_period_(param( conf, uri, Conf::EvsDelayedKeepPeriod, Defaults::EvsDelayedKeepPeriod)), last_inactive_check_ (gu::datetime::Date::now()), last_causal_keepalive_ (gu::datetime::Date::now()), current_view_(0, ViewId(V_TRANS, my_uuid, rst_view ? rst_view -> id().seq() + 1 : 0)), previous_view_(), previous_views_(), gather_views_(), input_map_(new InputMap()), causal_queue_(), consensus_(*this, known_, *input_map_, current_view_), install_message_(0), max_view_id_seq_(0), attempt_seq_(1), max_install_timeouts_( check_range(Conf::EvsMaxInstallTimeouts, param(conf, uri, Conf::EvsMaxInstallTimeouts, Defaults::EvsMaxInstallTimeouts), 0, std::numeric_limits::max())), install_timeout_count_(0), fifo_seq_(-1), last_sent_(-1), send_window_( check_range(Conf::EvsSendWindow, param(conf, uri, Conf::EvsSendWindow, Defaults::EvsSendWindow), gu::from_string(Defaults::EvsSendWindowMin), std::numeric_limits::max())), user_send_window_( check_range(Conf::EvsUserSendWindow, param(conf, uri, Conf::EvsUserSendWindow, Defaults::EvsUserSendWindow), gu::from_string(Defaults::EvsUserSendWindowMin), send_window_ + 1)), output_(), send_buf_(), max_output_size_(128), mtu_(mtu), use_aggregate_(param(conf, uri, Conf::EvsUseAggregate, "true")), self_loopback_(false), state_(S_CLOSED), shift_to_rfcnt_(0), pending_leave_(false), isolation_end_(gu::datetime::Date::zero()), delayed_list_(), auto_evict_(param(conf, uri, Conf::EvsAutoEvict, Defaults::EvsAutoEvict)) { log_info << "EVS version " << version_; conf.set(Conf::EvsVersion, gu::to_string(version_)); conf.set(Conf::EvsViewForgetTimeout, gu::to_string(view_forget_timeout_)); conf.set(Conf::EvsSuspectTimeout, gu::to_string(suspect_timeout_)); conf.set(Conf::EvsInactiveTimeout, gu::to_string(inactive_timeout_)); conf.set(Conf::EvsKeepalivePeriod, gu::to_string(retrans_period_)); conf.set(Conf::EvsInactiveCheckPeriod, gu::to_string(inactive_check_period_)); conf.set(Conf::EvsJoinRetransPeriod, gu::to_string(join_retrans_period_)); conf.set(Conf::EvsInstallTimeout, gu::to_string(install_timeout_)); conf.set(Conf::EvsStatsReportPeriod, gu::to_string(stats_report_period_)); conf.set(Conf::EvsCausalKeepalivePeriod, gu::to_string(causal_keepalive_period_)); conf.set(Conf::EvsSendWindow, gu::to_string(send_window_)); conf.set(Conf::EvsUserSendWindow, gu::to_string(user_send_window_)); conf.set(Conf::EvsUseAggregate, gu::to_string(use_aggregate_)); conf.set(Conf::EvsDebugLogMask, gu::to_string(debug_mask_, std::hex)); conf.set(Conf::EvsInfoLogMask, gu::to_string(info_mask_, std::hex)); conf.set(Conf::EvsMaxInstallTimeouts, gu::to_string(max_install_timeouts_)); conf.set(Conf::EvsDelayMargin, gu::to_string(delay_margin_)); conf.set(Conf::EvsDelayedKeepPeriod, gu::to_string(delayed_keep_period_)); conf.set(Conf::EvsAutoEvict, gu::to_string(auto_evict_)); // known_.insert_unique( std::make_pair(my_uuid_, Node(*this))); self_i_ = known_.begin(); assert(NodeMap::value(self_i_).operational() == true); NodeMap::value(self_i_).set_index(0); input_map_->reset(1); current_view_.add_member(my_uuid_, segment_); // we don't need to store previous views, do we ? if (rst_view) { previous_view_ = *rst_view; previous_views_.insert( std::make_pair(rst_view -> id(), gu::datetime::Date::now())); } if (mtu_ != std::numeric_limits::max()) { send_buf_.reserve(mtu_); } } gcomm::evs::Proto::~Proto() { output_.clear(); delete install_message_; delete input_map_; } bool gcomm::evs::Proto::set_param(const std::string& key, const std::string& val) { if (key == gcomm::Conf::EvsVersion) { version_ = check_range(Conf::EvsVersion, gu::from_string(val), 0, GCOMM_PROTOCOL_MAX_VERSION + 1); conf_.set(Conf::EvsVersion, gu::to_string(version_)); // trigger configuration change to propagate version shift_to(S_GATHER, true); return true; } else if (key == gcomm::Conf::EvsSendWindow) { send_window_ = check_range(Conf::EvsSendWindow, gu::from_string(val), user_send_window_, std::numeric_limits::max()); conf_.set(Conf::EvsSendWindow, gu::to_string(send_window_)); return true; } else if (key == gcomm::Conf::EvsUserSendWindow) { user_send_window_ = check_range( Conf::EvsUserSendWindow, gu::from_string(val), gu::from_string(Defaults::EvsUserSendWindowMin), send_window_ + 1); conf_.set(Conf::EvsUserSendWindow, gu::to_string(user_send_window_)); return true; } else if (key == gcomm::Conf::EvsMaxInstallTimeouts) { max_install_timeouts_ = check_range( Conf::EvsMaxInstallTimeouts, gu::from_string(val), 0, std::numeric_limits::max()); conf_.set(Conf::EvsMaxInstallTimeouts, gu::to_string(max_install_timeouts_)); return true; } else if (key == Conf::EvsStatsReportPeriod) { stats_report_period_ = check_range( Conf::EvsStatsReportPeriod, gu::from_string(val), gu::from_string(Defaults::EvsStatsReportPeriodMin), gu::datetime::Period::max()); conf_.set(Conf::EvsStatsReportPeriod, gu::to_string(stats_report_period_)); reset_timer(T_STATS); return true; } else if (key == Conf::EvsInfoLogMask) { info_mask_ = gu::from_string(val, std::hex); conf_.set(Conf::EvsInfoLogMask, gu::to_string(info_mask_, std::hex)); return true; } else if (key == Conf::EvsDebugLogMask) { debug_mask_ = gu::from_string(val, std::hex); conf_.set(Conf::EvsDebugLogMask, gu::to_string(debug_mask_, std::hex)); return true; } else if (key == Conf::EvsSuspectTimeout) { suspect_timeout_ = check_range( Conf::EvsSuspectTimeout, gu::from_string(val), gu::from_string(Defaults::EvsSuspectTimeoutMin), gu::datetime::Period::max()); conf_.set(Conf::EvsSuspectTimeout, gu::to_string(suspect_timeout_)); reset_timer(T_INACTIVITY); return true; } else if (key == Conf::EvsInactiveTimeout) { inactive_timeout_ = check_range( Conf::EvsInactiveTimeout, gu::from_string(val), gu::from_string(Defaults::EvsInactiveTimeoutMin), gu::datetime::Period::max()); conf_.set(Conf::EvsInactiveTimeout, gu::to_string(inactive_timeout_)); reset_timer(T_INACTIVITY); return true; } else if (key == Conf::EvsKeepalivePeriod) { retrans_period_ = check_range( Conf::EvsKeepalivePeriod, gu::from_string(val), gu::from_string(Defaults::EvsRetransPeriodMin), gu::datetime::Period::max()); conf_.set(Conf::EvsKeepalivePeriod, gu::to_string(retrans_period_)); reset_timer(T_RETRANS); return true; } else if (key == Conf::EvsCausalKeepalivePeriod) { causal_keepalive_period_ = check_range( Conf::EvsCausalKeepalivePeriod, gu::from_string(val), gu::datetime::Period(0), gu::datetime::Period::max()); conf_.set(Conf::EvsCausalKeepalivePeriod, gu::to_string(causal_keepalive_period_)); // no timer reset here, causal keepalives don't rely on timer return true; } else if (key == Conf::EvsJoinRetransPeriod) { join_retrans_period_ = check_range( Conf::EvsJoinRetransPeriod, gu::from_string(val), gu::from_string(Defaults::EvsRetransPeriodMin), gu::datetime::Period::max()); conf_.set(Conf::EvsJoinRetransPeriod, gu::to_string(join_retrans_period_)); reset_timer(T_RETRANS); return true; } else if (key == Conf::EvsInstallTimeout) { install_timeout_ = check_range( Conf::EvsInstallTimeout, gu::from_string(val), retrans_period_*2, inactive_timeout_ + 1); conf_.set(Conf::EvsInstallTimeout, gu::to_string(install_timeout_)); reset_timer(T_INSTALL); return true; } else if (key == Conf::EvsUseAggregate) { use_aggregate_ = gu::from_string(val); conf_.set(Conf::EvsUseAggregate, gu::to_string(use_aggregate_)); return true; } else if (key == Conf::EvsDelayMargin) { delay_margin_ = gu::from_string(val); conf_.set(Conf::EvsDelayMargin, gu::to_string(delay_margin_)); return true; } else if (key == Conf::EvsDelayedKeepPeriod) { delayed_keep_period_ = gu::from_string(val); conf_.set(Conf::EvsDelayedKeepPeriod, gu::to_string(delayed_keep_period_)); return true; } else if (key == Conf::EvsEvict) { if (val.size()) { UUID uuid; std::istringstream is(val); uuid.read_stream(is); log_info << "Evicting node " << uuid << " permanently from cluster"; evict(uuid); if (state() == S_OPERATIONAL && current_view_.is_member(uuid) == true) { shift_to(S_GATHER, true); } } else { Protolay::EvictList::const_iterator i, i_next; for (i = evict_list().begin(); i != evict_list().end(); i = i_next) { i_next = i, ++i_next; log_info << "unevicting " << Protolay::EvictList::key(i); unevict(Protolay::EvictList::key(i)); } } return true; } else if (key == Conf::EvsAutoEvict) { auto_evict_ = gu::from_string(val); conf_.set(Conf::EvsAutoEvict, gu::to_string(auto_evict_)); return true; } else if (key == Conf::EvsViewForgetTimeout || key == Conf::EvsInactiveCheckPeriod) { gu_throw_error(EPERM) << "can't change value for '" << key << "' during runtime"; } return false; } void gcomm::evs::Proto::handle_get_status(gu::Status& status) const { status.insert("evs_state", to_string(state_)); status.insert("evs_repl_latency", safe_deliv_latency_.to_string()); std::string delayed_list_str; for (DelayedList::const_iterator i(delayed_list_.begin()); i != delayed_list_.end(); ++i) { if (is_evicted(i->first) == false || current_view_.is_member(i->first) == true) { delayed_list_str += i->first.full_str() + ":" + i->second.addr() + ":" + gu::to_string(i->second.state_change_cnt()); delayed_list_str += ","; } } // Strip trailing comma if (delayed_list_str.empty() == false) { delayed_list_str.resize(delayed_list_str.size() - 1); } status.insert("evs_delayed", delayed_list_str); std::string evict_list_str; for (Protolay::EvictList::const_iterator i(evict_list().begin()); i != evict_list().end(); ) { evict_list_str += EvictList::key(i).full_str(); if (++i != evict_list().end()) evict_list_str += ","; } status.insert("evs_evict_list", evict_list_str); if (info_mask_ & I_STATISTICS) { status.insert("evs_safe_hs", hs_safe_.to_string()); status.insert("evs_causal_hs", hs_local_causal_.to_string()); status.insert("evs_outq_avg", gu::to_string(std::fabs(double(send_queue_s_)/ double(n_send_queue_s_)))); status.insert("evs_sent_user", gu::to_string(sent_msgs_[Message::T_USER])); status.insert("evs_sent_delegate", gu::to_string(sent_msgs_[Message::T_DELEGATE])); status.insert("evs_sent_gap", gu::to_string(sent_msgs_[Message::T_GAP])); status.insert("evs_sent_join", gu::to_string(sent_msgs_[Message::T_JOIN])); status.insert("evs_sent_install", gu::to_string(sent_msgs_[Message::T_INSTALL])); status.insert("evs_sent_leave", gu::to_string(sent_msgs_[Message::T_LEAVE])); status.insert("evs_retransmitted", gu::to_string(retrans_msgs_)); status.insert("evs_recovered", gu::to_string(recovered_msgs_)); status.insert("evs_deliv_safe", gu::to_string(delivered_msgs_[O_SAFE])); } } std::ostream& gcomm::evs::operator<<(std::ostream& os, const Proto& p) { os << "evs::proto(" << p.self_string() << ", " << p.to_string(p.state()) << ") {\n"; os << "current_view=" << p.current_view_ << ",\n"; os << "input_map=" << *p.input_map_ << ",\n"; os << "fifo_seq=" << p.fifo_seq_ << ",\n"; os << "last_sent=" << p.last_sent_ << ",\n"; os << "known:\n"; for (NodeMap::const_iterator i(p.known_.begin()); i != p.known_.end(); ++i) { os << NodeMap::key(i) << " at " << p.get_address(NodeMap::key(i)) << "\n"; os << NodeMap::value(i) << "\n"; } if (p.install_message_ != 0) os << "install msg=" << *p.install_message_ << "\n"; os << " }"; return os; } std::string gcomm::evs::Proto::stats() const { std::ostringstream os; os << "\n\tnodes " << current_view_.members().size(); os << "\n\tagreed deliv hist {" << hs_agreed_ << "} "; os << "\n\tsafe deliv hist {" << hs_safe_ << "} "; os << "\n\tcaus deliv hist {" << hs_local_causal_ << "} "; os << "\n\toutq avg " << double(send_queue_s_)/double(n_send_queue_s_); os << "\n\tsent {"; std::copy(sent_msgs_.begin(), sent_msgs_.end(), std::ostream_iterator(os, ",")); os << "}\n\tsent per sec {"; const double norm(double(gu::datetime::Date::now().get_utc() - last_stats_report_.get_utc())/gu::datetime::Sec); std::vector result(7, norm); std::transform(sent_msgs_.begin(), sent_msgs_.end(), result.begin(), result.begin(), std::divides()); std::copy(result.begin(), result.end(), std::ostream_iterator(os, ",")); os << "}\n\trecvd { "; std::copy(recvd_msgs_.begin(), recvd_msgs_.end(), std::ostream_iterator(os, ",")); os << "}\n\trecvd per sec {"; std::fill(result.begin(), result.end(), norm); std::transform(recvd_msgs_.begin(), recvd_msgs_.end(), result.begin(), result.begin(), std::divides()); std::copy(result.begin(), result.end(), std::ostream_iterator(os, ",")); os << "}\n\tretransmitted " << retrans_msgs_ << " "; os << "\n\trecovered " << recovered_msgs_; os << "\n\tdelivered {"; std::copy(delivered_msgs_.begin(), delivered_msgs_.end(), std::ostream_iterator(os, ", ")); os << "}\n\teff(delivered/sent) " << double(accumulate(delivered_msgs_.begin() + 1, delivered_msgs_.begin() + O_SAFE + 1, 0)) /double(accumulate(sent_msgs_.begin(), sent_msgs_.end(), 0)); return os.str(); } void gcomm::evs::Proto::reset_stats() { hs_agreed_.clear(); hs_safe_.clear(); hs_local_causal_.clear(); safe_deliv_latency_.clear(); send_queue_s_ = 0; n_send_queue_s_ = 0; last_stats_report_ = gu::datetime::Date::now(); } bool gcomm::evs::Proto::is_msg_from_previous_view(const Message& msg) { ViewList::const_iterator i; if ((i = previous_views_.find(msg.source_view_id())) != previous_views_.end()) { evs_log_debug(D_FOREIGN_MSGS) << " message " << msg << " from previous view " << i->first; return true; } // If node is in current view, check message source view seq, if it is // smaller than current view seq then the message is also from some // previous (but unknown to us) view NodeList::const_iterator ni(current_view_.members().find(msg.source())); if (ni != current_view_.members().end()) { if (msg.source_view_id().seq() < current_view_.id().seq()) { log_warn << "stale message from unknown origin " << msg; return true; } } return false; } void gcomm::evs::Proto::handle_inactivity_timer() { gu_trace(check_inactive()); gu_trace(cleanup_views()); gu_trace(cleanup_evicted()); } void gcomm::evs::Proto::handle_retrans_timer() { evs_log_debug(D_TIMERS) << "retrans timer"; if (state() == S_GATHER) { if (install_message_ != 0) { // Retransmit install message if representative and all commit // gaps have not been received yet. if (is_all_committed() == false && install_message_->source() == uuid()) { evs_log_debug(D_INSTALL_MSGS) << "retrans install"; gu::Buffer buf; install_message_->set_flags( install_message_->flags() | Message::F_RETRANS); (void)serialize(*install_message_, buf); Datagram dg(buf); // Must not be sent as delegate, newly joining node // will filter them out in handle_msg(). gu_trace(send_down(dg, ProtoDownMeta())); } evs_log_debug(D_GAP_MSGS) << "resend commit gap"; // Resend commit gap gu_trace(send_gap(EVS_CALLER, UUID::nil(), install_message_->install_view_id(), Range(), true)); } else { evs_log_debug(D_JOIN_MSGS) << "retrans join"; gu_trace(send_join(true)); } } else if (state() == S_INSTALL) { gcomm_assert(install_message_ != 0); gu_trace(send_gap(EVS_CALLER, UUID::nil(), install_message_->install_view_id(), Range(), true)); gu_trace(send_gap(EVS_CALLER, UUID::nil(), install_message_->install_view_id(), Range())); } else if (state() == S_OPERATIONAL) { const seqno_t prev_last_sent(last_sent_); evs_log_debug(D_TIMERS) << "send user timer, last_sent=" << last_sent_; Datagram dg; gu_trace((void)send_user(dg, 0xff, O_DROP, -1, -1)); if (prev_last_sent == last_sent_) { log_warn << "could not send keepalive"; } } else if (state() == S_LEAVING) { evs_log_debug(D_TIMERS) << "send leave timer"; profile_enter(send_leave_prof_); send_leave(false); profile_leave(send_leave_prof_); } } void gcomm::evs::Proto::isolate(gu::datetime::Period period) { isolation_end_ = gu::datetime::Date::now() + period; } void gcomm::evs::Proto::handle_install_timer() { gcomm_assert(state() == S_GATHER || state() == S_INSTALL); log_warn << self_string() << " install timer expired"; bool is_cons(consensus_.is_consensus()); bool is_repr(is_representative(uuid())); evs_log_info(I_STATE) << "before inspection:"; evs_log_info(I_STATE) << "consensus: " << is_cons; evs_log_info(I_STATE) << "repr : " << is_repr; evs_log_info(I_STATE) << "state dump for diagnosis:"; std::cerr << *this << std::endl; if (install_timeout_count_ < max_install_timeouts_ ) { // before reaching max_install_timeouts, declare only inconsistent // nodes as inactive for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& node_uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); if (node_uuid != uuid() && (node.join_message() == 0 || consensus_.is_consistent(*node.join_message()) == false)) { evs_log_info(I_STATE) << " setting source " << NodeMap::key(i) << " as inactive due to expired install timer"; set_inactive(NodeMap::key(i)); } } } else if (install_timeout_count_ == max_install_timeouts_) { // max install timeouts reached, declare all other nodes // as inactive for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { if (NodeMap::key(i) != uuid()) { evs_log_info(I_STATE) << " setting source " << NodeMap::key(i) << " as inactive due to expired install timer"; set_inactive(NodeMap::key(i)); } } log_info << "max install timeouts reached, will isolate node " << "for " << suspect_timeout_ + inactive_timeout_; isolate(suspect_timeout_ + inactive_timeout_); } else if (install_timeout_count_ > max_install_timeouts_) { log_info << "going to give up, state dump for diagnosis:"; std::cerr << *this << std::endl; gu_throw_fatal << self_string() << " failed to form singleton view after exceeding " << "max_install_timeouts " << max_install_timeouts_ << ", giving up"; } if (install_message_ != 0) { for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { if (NodeMap::value(i).committed() == false) { log_info << self_string() << " node " << NodeMap::key(i) << " failed to commit for install message, " << "declaring inactive"; if (NodeMap::key(i) != uuid()) { set_inactive(NodeMap::key(i)); } } } } else { log_info << "no install message received"; } shift_to(S_GATHER, true); is_cons = consensus_.is_consensus(); is_repr = is_representative(uuid()); evs_log_info(I_STATE) << "after inspection:"; evs_log_info(I_STATE) << "consensus: " << is_cons; evs_log_info(I_STATE) << "repr : " << is_repr; if (is_cons == true && is_repr == true) { send_install(EVS_CALLER); } install_timeout_count_++; } void gcomm::evs::Proto::handle_stats_timer() { reset_stats(); #ifdef GCOMM_PROFILE evs_log_info(I_PROFILING) << "\nprofiles:\n"; evs_log_info(I_PROFILING) << send_user_prof_ << "\n"; evs_log_info(I_PROFILING) << send_gap_prof_ << "\n"; evs_log_info(I_PROFILING) << send_join_prof_ << "\n"; evs_log_info(I_PROFILING) << send_install_prof_ << "\n"; evs_log_info(I_PROFILING) << send_leave_prof_ << "\n"; evs_log_info(I_PROFILING) << consistent_prof_ << "\n"; evs_log_info(I_PROFILING) << consensus_prof_ << "\n"; evs_log_info(I_PROFILING) << shift_to_prof_ << "\n"; evs_log_info(I_PROFILING) << input_map_prof_ << "\n"; evs_log_info(I_PROFILING) << delivery_prof_ << "\n"; #endif // GCOMM_PROFILE } class TimerSelectOp { public: TimerSelectOp(const gcomm::evs::Proto::Timer t_) : t(t_) { } bool operator()(const gcomm::evs::Proto::TimerList::value_type& vt) const { return (gcomm::evs::Proto::TimerList::value(vt) == t); } private: gcomm::evs::Proto::Timer const t; }; gu::datetime::Date gcomm::evs::Proto::next_expiration(const Timer t) const { gcomm_assert(state() != S_CLOSED); gu::datetime::Date now(gu::datetime::Date::now()); switch (t) { case T_INACTIVITY: return (now + inactive_check_period_); case T_RETRANS: switch (state()) { case S_OPERATIONAL: case S_LEAVING: return (now + retrans_period_); case S_GATHER: case S_INSTALL: return (now + join_retrans_period_); default: gu_throw_fatal; } case T_INSTALL: switch (state()) { case S_GATHER: case S_INSTALL: return (now + install_timeout_); default: return gu::datetime::Date::max(); } case T_STATS: return (now + stats_report_period_); } gu_throw_fatal; } void timer_list_erase_by_type(gcomm::evs::Proto::TimerList& timer_list, gcomm::evs::Proto::Timer timer) { gcomm::evs::Proto::TimerList::iterator i, i_next; for (i = timer_list.begin(); i != timer_list.end(); i = i_next) { i_next = i, ++i_next; if (gcomm::evs::Proto::TimerList::value(i) == timer) { timer_list.erase(i); } } } void gcomm::evs::Proto::reset_timer(Timer t) { timer_list_erase_by_type(timers_, t); timers_.insert(std::make_pair(next_expiration(t), t)); } void gcomm::evs::Proto::cancel_timer(Timer t) { timer_list_erase_by_type(timers_, t); } gu::datetime::Date gcomm::evs::Proto::handle_timers() { gu::datetime::Date now(gu::datetime::Date::now()); while (timers_.empty() == false && TimerList::key(timers_.begin()) <= now) { Timer t(TimerList::value(timers_.begin())); timers_.erase(timers_.begin()); switch (t) { case T_INACTIVITY: handle_inactivity_timer(); break; case T_RETRANS: handle_retrans_timer(); break; case T_INSTALL: handle_install_timer(); break; case T_STATS: handle_stats_timer(); break; } if (state() == S_CLOSED) { return gu::datetime::Date::max(); } reset_timer(t); } if (timers_.empty() == true) { evs_log_debug(D_TIMERS) << "no timers set"; return gu::datetime::Date::max(); } return TimerList::key(timers_.begin()); } void gcomm::evs::Proto::check_inactive() { const gu::datetime::Date now(gu::datetime::Date::now()); if (last_inactive_check_ + inactive_check_period_*3 < now) { log_warn << "last inactive check more than " << inactive_check_period_*3 << " ago (" << (now - last_inactive_check_) << "), skipping check"; last_inactive_check_ = now; return; } NodeMap::value(self_i_).set_tstamp(gu::datetime::Date::now()); std::for_each(known_.begin(), known_.end(), InspectNode()); bool has_inactive(false); size_t n_suspected(0); bool do_send_delayed_list(false); // Iterate over known nodes and check inactive/suspected/delayed status for (NodeMap::iterator i(known_.begin()); i != known_.end(); ++i) { if (i == self_i_) continue; // No need to check self const UUID& node_uuid(NodeMap::key(i)); Node& node(NodeMap::value(i)); if (node_uuid != uuid() && (node.is_inactive() == true || node.is_suspected() == true )) { if (node.operational() == true && node.is_inactive() == true) { log_info << self_string() << " detected inactive node: " << node_uuid; } else if (node.is_suspected() == true && node.is_inactive() == false) { log_info << self_string() << " suspecting node: " << node_uuid; } if (node.is_inactive() == true) { set_inactive(node_uuid); } if (node.is_suspected() == true && node.operational() == true) { ++n_suspected; if (node.join_message() == 0) { log_info << self_string() << " suspected node without join message, declaring inactive"; set_inactive(node_uuid); } } has_inactive = true; } DelayedList::iterator dli(delayed_list_.find(node_uuid)); if (node.seen_tstamp() + retrans_period_ + delay_margin_ <= now) { if (node.index() != std::numeric_limits::max()) { // Delayed node in group, check input map state and request // message recovery if necessary Range range(input_map_->range(node.index())); evs_log_info(I_STATE) << "delayed " << node_uuid << " requesting range " << Range(range.lu(), last_sent_); if (last_sent_ >= range.lu()) { // Request recovering message from all nodes (indicated // by last arg) to increase probablity of receiving the // message. gu_trace(send_gap(EVS_CALLER, node_uuid, current_view_.id(), Range(range.lu(), last_sent_), false, true)); } } if (dli == delayed_list_.end()) { delayed_list_.insert( std::make_pair(node_uuid, DelayedEntry(get_address(node_uuid)))); } else { dli->second.set_tstamp(now); dli->second.set_state(DelayedEntry::S_DELAYED, delayed_keep_period_, now); evs_log_debug(D_STATE) << "set '" << dli->first << "' delayed state to S_DELAYED , cnt = " << dli->second.state_change_cnt(); // todo(dirlt): make threshold as a configurable variable ? if (dli->second.state_change_cnt() > 0) { do_send_delayed_list = true; } } } else if (dli != delayed_list_.end()) { const size_t prev_cnt(dli->second.state_change_cnt()); dli->second.set_state(DelayedEntry::S_OK, delayed_keep_period_, now); if (prev_cnt != dli->second.state_change_cnt()) { dli->second.set_tstamp(now); } evs_log_debug(D_STATE) << "set '" << dli->first << "' delayed state to S_OK. prev_cnt = " << prev_cnt << ", cur_cnt = " << dli->second.state_change_cnt(); if (dli->second.state_change_cnt() > 0) { do_send_delayed_list = true; } } } // Clean up delayed list and evict list messages { DelayedList::iterator i, i_next; for (i = delayed_list_.begin(); i != delayed_list_.end(); i = i_next) { i_next = i, ++i_next; // State change count has decayed back to zero // or node is already evicted and not in the current view // anymore. if ((i->second.state_change_cnt() == 0 && i->second.state() == DelayedEntry::S_OK) || (is_evicted(i->first) == true && current_view_.is_member(i->first) == false)) { log_debug << "remove '" << i->first << "' from delayed_list"; delayed_list_.erase(i); } } for (NodeMap::iterator i(known_.begin()); i != known_.end(); ++i) { Node& node(NodeMap::value(i)); const DelayedListMessage* const elm(node.delayed_list_message()); if (elm != 0 && elm->tstamp() + delayed_keep_period_ < now) { log_info << "discarding expired elm from " << elm->source(); node.set_delayed_list_message(0); } } } if (current_view_.version() > 0 && do_send_delayed_list == true && auto_evict_ > 0) { send_delayed_list(); } // All other nodes are under suspicion, set all others as inactive. // This will speed up recovery when this node has been isolated from // other group. Note that this should be done only if known size is // greater than 2 in order to avoid immediate split brain. if (known_.size() > 2 && n_suspected + 1 == known_.size()) { for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { if (NodeMap::key(i) != uuid()) { evs_log_info(I_STATE) << " setting source " << NodeMap::key(i) << " inactive (other nodes under suspicion)"; set_inactive(NodeMap::key(i)); } } } if (has_inactive == true && state() == S_OPERATIONAL) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_GATHER, true)); profile_leave(shift_to_prof_); } else if (has_inactive == true && state() == S_LEAVING && n_operational() == 1) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_CLOSED)); profile_leave(shift_to_prof_); } last_inactive_check_ = now; // Check if isolation period has ended if (isolation_end_ != gu::datetime::Date::zero() && isolation_end_ <= now) { log_info << "ending isolation"; isolation_end_ = gu::datetime::Date::zero(); } } void gcomm::evs::Proto::set_inactive(const UUID& node_uuid) { NodeMap::iterator i; gcomm_assert(node_uuid != uuid()); gu_trace(i = known_.find_checked(node_uuid)); evs_log_debug(D_STATE) << "setting " << node_uuid << " inactive"; Node& node(NodeMap::value(i)); node.set_tstamp(gu::datetime::Date::zero()); node.set_join_message(0); // node.set_leave_message(0); node.set_operational(false); } bool gcomm::evs::Proto::is_inactive(const UUID& uuid) const { NodeMap::const_iterator i; gu_trace(i = known_.find_checked(uuid)); const Node& node(NodeMap::value(i)); return (node.operational() == false); } void gcomm::evs::Proto::cleanup_foreign(const InstallMessage& im) { NodeMap::iterator i, i_next; for (i = known_.begin(); i != known_.end(); i = i_next) { const UUID& uuid(NodeMap::key(i)); i_next = i, ++i_next; const MessageNodeList::const_iterator mni(im.node_list().find(uuid)); if (mni == im.node_list().end() || MessageNodeList::value(mni).operational() == false) { known_.erase(i); } } } void gcomm::evs::Proto::cleanup_views() { gu::datetime::Date now(gu::datetime::Date::now()); ViewList::iterator i, i_next; for (i = previous_views_.begin(); i != previous_views_.end(); i = i_next) { i_next = i, ++i_next; if (i->second + view_forget_timeout_ <= now) { evs_log_debug(D_STATE) << " erasing view: " << i->first; previous_views_.erase(i); } } } void gcomm::evs::Proto::cleanup_evicted() { gu::datetime::Date now(gu::datetime::Date::now()); Protolay::EvictList::const_iterator i, i_next; for (i = evict_list().begin(); i != evict_list().end(); i = i_next) { i_next = i, ++i_next; if (Protolay::EvictList::value(i) + view_forget_timeout_ <= now) { log_info << "unevicting " << Protolay::EvictList::key(i); unevict(Protolay::EvictList::key(i)); } } } size_t gcomm::evs::Proto::n_operational() const { NodeMap::const_iterator i; size_t ret = 0; for (i = known_.begin(); i != known_.end(); ++i) { if (i->second.operational() == true) ret++; } return ret; } void gcomm::evs::Proto::deliver_reg_view(const InstallMessage& im, const View& prev_view) { View view(im.version(), im.install_view_id()); for (MessageNodeList::const_iterator i(im.node_list().begin()); i != im.node_list().end(); ++i) { const UUID& uuid(MessageNodeList::key(i)); const MessageNode& mn(MessageNodeList::value(i)); // 1) Operational nodes will be members of new view // 2) Operational nodes that were not present in previous // view are going also to joined set // 3) Leaving nodes go to left set // 4) All other nodes present in previous view but not in // member of left set are considered partitioned if (mn.operational() == true) { view.add_member(uuid, mn.segment()); if (prev_view.is_member(uuid) == false) { view.add_joined(uuid, mn.segment()); } } else if (mn.leaving() == true) { view.add_left(uuid, mn.segment()); } else { // Partitioned set is constructed after this loop } // If node has been evicted, it should have been added to // evicted list via JOIN messages. assert(mn.evicted() == false || is_evicted(uuid) == true); } // Loop over previous view and add each node not in new view // member of left set as partitioned. for (NodeList::const_iterator i(prev_view.members().begin()); i != prev_view.members().end(); ++i) { const UUID& uuid(NodeList::key(i)); const gcomm::Node& mn(NodeList::value(i)); if (view.is_member(uuid) == false && view.is_leaving(uuid) == false) { view.add_partitioned(uuid, mn.segment()); } } evs_log_info(I_VIEWS) << "delivering view " << view; // This node must be a member of the view it delivers and // view id UUID must be of one of the members. gcomm_assert(view.is_member(uuid()) == true); gcomm_assert(view.is_member(view.id().uuid()) == true) << "view id UUID " << view.id().uuid() << " not found from reg view members " << view.members() << " must abort to avoid possibility of two groups " << "with the same view id"; set_stable_view(view); ProtoUpMeta up_meta(UUID::nil(), ViewId(), &view); send_up(Datagram(), up_meta); } void gcomm::evs::Proto::deliver_trans_view(const InstallMessage& im, const View& curr_view) { // Trans view is intersection of members in curr_view // and members going to be in the next view that come from // curr_view according to install message View view(current_view_.version(), ViewId(V_TRANS, curr_view.id().uuid(), curr_view.id().seq())); for (MessageNodeList::const_iterator i(im.node_list().begin()); i != im.node_list().end(); ++i) { const UUID& uuid(MessageNodeList::key(i)); const MessageNode& mn(MessageNodeList::value(i)); if (curr_view.id() == mn.view_id() && curr_view.is_member(uuid) == true) { // 1) Operational nodes go to next view // 2) Leaving nodes go to left set // 3) All other nodes present in previous view but not in // member of left set are considered partitioned if (mn.operational() == true) { view.add_member(uuid, mn.segment()); } else if (mn.leaving() == true) { view.add_left(uuid, mn.segment()); } else { // Partitioned set is constructed after this loop } } } // Loop over current view and add each node not in new view // member of left set as partitioned. for (NodeList::const_iterator i(curr_view.members().begin()); i != curr_view.members().end(); ++i) { const UUID& uuid(NodeList::key(i)); const gcomm::Node& mn(NodeList::value(i)); if (view.is_member(uuid) == false && view.is_leaving(uuid) == false) { view.add_partitioned(uuid, mn.segment()); } } // This node must be a member of the view it delivers and // if the view is the last transitional, view must have // exactly one member and no-one in left set. gcomm_assert(view.is_member(uuid()) == true); evs_log_info(I_VIEWS) << " delivering view " << view; ProtoUpMeta up_meta(UUID::nil(), ViewId(), &view); gu_trace(send_up(Datagram(), up_meta)); } void gcomm::evs::Proto::deliver_empty_view() { View view(0, V_REG); evs_log_info(I_VIEWS) << "delivering view " << view; ProtoUpMeta up_meta(UUID::nil(), ViewId(), &view); send_up(Datagram(), up_meta); } void gcomm::evs::Proto::setall_committed(bool val) { for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { NodeMap::value(i).set_committed(val); } } // Check if commit gaps from all known nodes found from install message have // been seen. bool gcomm::evs::Proto::is_all_committed() const { gcomm_assert(install_message_ != 0); for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& inst(NodeMap::value(i)); if (install_message_->node_list().find(uuid) != install_message_->node_list().end() && inst.operational() == true && inst.committed() == false) { return false; } } return true; } void gcomm::evs::Proto::setall_installed(bool val) { for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { NodeMap::value(i).set_installed(val); } } // Check if gaps from new view from all known nodes found from install // message have been seen. bool gcomm::evs::Proto::is_all_installed() const { gcomm_assert(install_message_ != 0); for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& inst(NodeMap::value(i)); if (install_message_->node_list().find(uuid) != install_message_->node_list().end() && inst.operational() == true && inst.installed() == false) { return false; } } return true; } void gcomm::evs::Proto::cleanup_joins() { for (NodeMap::iterator i = known_.begin(); i != known_.end(); ++i) { NodeMap::value(i).set_join_message(0); } } bool gcomm::evs::Proto::is_representative(const UUID& uuid) const { for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { if (NodeMap::value(i).operational() == true && NodeMap::value(i).is_inactive() == false) { assert(NodeMap::value(i).leave_message() == 0); if (NodeMap::value(i).leave_message() != 0) { log_warn << "operational node " << NodeMap::key(i) << " with leave message: " << NodeMap::value(i); continue; } return (uuid == NodeMap::key(i)); } } return false; } bool gcomm::evs::Proto::is_all_suspected(const UUID& uuid) const { for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const Node& node(NodeMap::value(i)); if (node.operational() == true) { const JoinMessage* jm(node.join_message()); if (!jm) return false; const MessageNodeList::const_iterator j(jm->node_list().find(uuid)); if (!(j != jm->node_list().end() && MessageNodeList::value(j).suspected())) return false; } } return true; } ///////////////////////////////////////////////////////////////////////////// // Message sending ///////////////////////////////////////////////////////////////////////////// bool gcomm::evs::Proto::is_flow_control(const seqno_t seq, const seqno_t win) const { gcomm_assert(seq != -1 && win != -1); const seqno_t base(input_map_->safe_seq()); if (seq > base + win) { return true; } return false; } int gcomm::evs::Proto::send_user(Datagram& dg, uint8_t const user_type, Order const order, seqno_t const win, seqno_t const up_to_seqno, size_t const n_aggregated) { assert(state() == S_LEAVING || state() == S_GATHER || state() == S_OPERATIONAL); assert(dg.offset() == 0); assert(n_aggregated == 1 || output_.size() >= n_aggregated); gcomm_assert(up_to_seqno == -1 || up_to_seqno >= last_sent_); gcomm_assert(up_to_seqno == -1 || win == -1); int ret; const seqno_t seq(last_sent_ + 1); if (win != -1 && is_flow_control(seq, win) == true) { return EAGAIN; } // seq_range max 0xff because of Message seq_range_ field limitation seqno_t seq_range( std::min(up_to_seqno == -1 ? 0 : up_to_seqno - seq, evs::seqno_t(0xff))); seqno_t last_msg_seq(seq + seq_range); uint8_t flags; // If output queue wont contain messages after this patch, // up_to_seqno is given (msg completion) or flow contol would kick in // at next batch, don't set F_MSG_MORE. if (output_.size() <= n_aggregated || up_to_seqno != -1 || (win != -1 && is_flow_control(last_msg_seq + 1, win) == true)) { flags = 0; } else { flags = Message::F_MSG_MORE; } if (n_aggregated > 1) { flags |= Message::F_AGGREGATE; } // Maximize seq range in the case next message batch won't be sent // immediately. if ((flags & Message::F_MSG_MORE) == 0 && up_to_seqno == -1) { seq_range = input_map_->max_hs() - seq; seq_range = std::max(static_cast(0), seq_range); seq_range = std::min(static_cast(0xff), seq_range); if (seq_range != 0) { log_debug << "adjusted seq range to: " << seq_range; last_msg_seq = seq + seq_range; } } gcomm_assert(last_msg_seq >= seq && last_msg_seq - seq <= 0xff); gcomm_assert(seq_range >= 0 && seq_range <= 0xff); UserMessage msg(version_, uuid(), current_view_.id(), seq, input_map_->aru_seq(), seq_range, order, ++fifo_seq_, user_type, flags); // Insert first to input map to determine correct aru seq Range range; gu_trace(range = input_map_->insert(NodeMap::value(self_i_).index(), msg, dg)); gcomm_assert(range.hs() == last_msg_seq) << msg << " " << *input_map_ << " " << *this; last_sent_ = last_msg_seq; assert(range.hs() == last_sent_); update_im_safe_seq(NodeMap::value(self_i_).index(), input_map_->aru_seq()); msg.set_aru_seq(input_map_->aru_seq()); evs_log_debug(D_USER_MSGS) << " sending " << msg; gu_trace(push_header(msg, dg)); if ((ret = send_down(dg, ProtoDownMeta())) != 0) { log_debug << "send failed: " << strerror(ret); } gu_trace(pop_header(msg, dg)); sent_msgs_[Message::T_USER]++; if (delivering_ == false && input_map_->has_deliverables() == true) { gu_trace(deliver()); } gu_trace(deliver_local()); return 0; } size_t gcomm::evs::Proto::aggregate_len() const { bool is_aggregate(false); size_t ret(0); AggregateMessage am; std::deque >::const_iterator i(output_.begin()); const Order ord(i->second.order()); ret += i->first.len() + am.serial_size(); for (++i; i != output_.end() && i->second.order() == ord; ++i) { if (ret + i->first.len() + am.serial_size() <= mtu()) { ret += i->first.len() + am.serial_size(); is_aggregate = true; } else { break; } } evs_log_debug(D_USER_MSGS) << "is aggregate " << is_aggregate << " ret " << ret; return (is_aggregate == true ? ret : 0); } int gcomm::evs::Proto::send_user(const seqno_t win) { gcomm_assert(output_.empty() == false); gcomm_assert(state() == S_OPERATIONAL); gcomm_assert(win <= send_window_); int ret; size_t alen; if (use_aggregate_ == true && (alen = aggregate_len()) > 0) { // Messages can be aggregated into single message send_buf_.resize(alen); size_t offset(0); size_t n(0); std::deque >::iterator i(output_.begin()); Order ord(i->second.order()); while ((alen > 0 && i != output_.end())) { const Datagram& dg(i->first); const ProtoDownMeta dm(i->second); AggregateMessage am(0, dg.len(), dm.user_type()); gcomm_assert(alen >= dg.len() + am.serial_size()); gu_trace(offset = am.serialize(&send_buf_[0], send_buf_.size(), offset)); std::copy(dg.header() + dg.header_offset(), dg.header() + dg.header_size(), &send_buf_[0] + offset); offset += (dg.header_len()); std::copy(dg.payload().begin(), dg.payload().end(), &send_buf_[0] + offset); offset += dg.payload().size(); alen -= dg.len() + am.serial_size(); ++n; ++i; } Datagram dg(gu::SharedBuffer(new gu::Buffer(send_buf_.begin(), send_buf_.end()))); if ((ret = send_user(dg, 0xff, ord, win, -1, n)) == 0) { while (n-- > 0) { output_.pop_front(); } } } else { std::pair wb(output_.front()); if ((ret = send_user(wb.first, wb.second.user_type(), wb.second.order(), win, -1)) == 0) { output_.pop_front(); } } return ret; } void gcomm::evs::Proto::complete_user(const seqno_t high_seq) { gcomm_assert(state() == S_OPERATIONAL || state() == S_GATHER); evs_log_debug(D_USER_MSGS) << "completing seqno to " << high_seq;; Datagram wb; int err; profile_enter(send_user_prof_); err = send_user(wb, 0xff, O_DROP, -1, high_seq); profile_leave(send_user_prof_); if (err != 0) { log_debug << "failed to send completing msg " << strerror(err) << " seq=" << high_seq << " send_window=" << send_window_ << " last_sent=" << last_sent_; } } int gcomm::evs::Proto::send_delegate(Datagram& wb) { DelegateMessage dm(version_, uuid(), current_view_.id(), ++fifo_seq_); push_header(dm, wb); int ret = send_down(wb, ProtoDownMeta()); pop_header(dm, wb); sent_msgs_[Message::T_DELEGATE]++; return ret; } void gcomm::evs::Proto::send_gap(EVS_CALLER_ARG, const UUID& range_uuid, const ViewId& source_view_id, const Range range, const bool commit, const bool req_all) { gcomm_assert((commit == false && source_view_id == current_view_.id()) || install_message_ != 0); // TODO: Investigate if gap sending can be somehow limited, // message loss happen most probably during congestion and // flooding network with gap messages won't probably make // conditions better uint8_t flags(0); if (commit == true) flags |= Message::F_COMMIT; if (req_all) flags |= Message::F_RETRANS; GapMessage gm(version_, uuid(), source_view_id, (source_view_id == current_view_.id() ? last_sent_ : (commit == true ? install_message_->fifo_seq() : -1)), (source_view_id == current_view_.id() ? input_map_->aru_seq() : -1), ++fifo_seq_, range_uuid, range, flags); evs_log_debug(D_GAP_MSGS) << EVS_LOG_METHOD << gm; gu::Buffer buf; serialize(gm, buf); Datagram dg(buf); int err = send_down(dg, ProtoDownMeta()); if (err != 0) { log_debug << "send failed: " << strerror(err); } sent_msgs_[Message::T_GAP]++; gu_trace(handle_gap(gm, self_i_)); } void gcomm::evs::Proto::populate_node_list(MessageNodeList* node_list) const { for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& node_uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); MessageNode mnode(node.operational(), node.suspected(), is_evicted(node_uuid)); if (node_uuid != uuid()) { const JoinMessage* jm(node.join_message()); const LeaveMessage* lm(node.leave_message()); // if (jm != 0) { const ViewId& nsv(jm->source_view_id()); const MessageNode& mn(MessageNodeList::value(jm->node_list().find_checked(node_uuid))); mnode = MessageNode(node.operational(), node.is_suspected(), node.segment(), is_evicted(node_uuid), -1, jm->source_view_id(), (nsv == current_view_.id() ? input_map_->safe_seq(node.index()) : mn.safe_seq()), (nsv == current_view_.id() ? input_map_->range(node.index()) : mn.im_range())); } else if (lm != 0) { const ViewId& nsv(lm->source_view_id()); mnode = MessageNode(node.operational(), node.is_suspected(), node.segment(), is_evicted(node_uuid), lm->seq(), nsv, (nsv == current_view_.id() ? input_map_->safe_seq(node.index()) : -1), (nsv == current_view_.id() ? input_map_->range(node.index()) : Range())); } else if (current_view_.is_member(node_uuid) == true) { mnode = MessageNode(node.operational(), node.is_suspected(), node.segment(), is_evicted(node_uuid), -1, current_view_.id(), input_map_->safe_seq(node.index()), input_map_->range(node.index())); } } else { mnode = MessageNode(true, false, node.segment(), is_evicted(node_uuid), -1, current_view_.id(), input_map_->safe_seq(node.index()), input_map_->range(node.index())); } gu_trace((void)node_list->insert_unique(std::make_pair(node_uuid, mnode))); } // Iterate over evicted_list and add evicted nodes not yet in node list. for (Protolay::EvictList::const_iterator i(evict_list().begin()); i != evict_list().end(); ++i) { if (node_list->find(Protolay::EvictList::key(i)) == node_list->end()) { // default arguments are evil. MessageNode mnode(false, false, 0, true); gu_trace((void)node_list->insert_unique( std::make_pair(Protolay::EvictList::key(i), mnode))); } } evs_log_debug(D_CONSENSUS) << "populate node list:\n" << *node_list; } const gcomm::evs::JoinMessage& gcomm::evs::Proto::create_join() { MessageNodeList node_list; gu_trace(populate_node_list(&node_list)); JoinMessage jm(version_, uuid(), current_view_.id(), input_map_->safe_seq(), input_map_->aru_seq(), ++fifo_seq_, node_list); NodeMap::value(self_i_).set_join_message(&jm); evs_log_debug(D_JOIN_MSGS) << " created join message " << jm; return *NodeMap::value(self_i_).join_message(); } void gcomm::evs::Proto::set_join(const JoinMessage& jm, const UUID& source) { NodeMap::iterator i; gu_trace(i = known_.find_checked(source)); NodeMap::value(i).set_join_message(&jm);; } void gcomm::evs::Proto::set_leave(const LeaveMessage& lm, const UUID& source) { NodeMap::iterator i; gu_trace(i = known_.find_checked(source)); Node& inst(NodeMap::value(i)); if (inst.leave_message()) { evs_log_debug(D_LEAVE_MSGS) << "Duplicate leave:\told: " << *inst.leave_message() << "\tnew: " << lm; } else { inst.set_leave_message(&lm); } } void gcomm::evs::Proto::send_join(bool handle) { assert(output_.empty() == true); JoinMessage jm(create_join()); gu::Buffer buf; serialize(jm, buf); Datagram dg(buf); int err = send_down(dg, ProtoDownMeta()); if (err != 0) { log_debug << "send failed: " << strerror(err); } sent_msgs_[Message::T_JOIN]++; if (handle == true) { handle_join(jm, self_i_); } } void gcomm::evs::Proto::send_leave(bool handle) { gcomm_assert(state() == S_LEAVING); // If no messages have been sent, generate one dummy to // trigger message acknowledgement mechanism if (last_sent_ == -1 && output_.empty() == true) { Datagram wb; gu_trace(send_user(wb, 0xff, O_DROP, -1, -1)); } /* Move all pending messages from output to input map */ while (output_.empty() == false) { std::pair wb = output_.front(); if (send_user(wb.first, wb.second.user_type(), wb.second.order(), -1, -1) != 0) { gu_throw_fatal << "send_user() failed"; } output_.pop_front(); } LeaveMessage lm(version_, uuid(), current_view_.id(), last_sent_, input_map_->aru_seq(), ++fifo_seq_); evs_log_debug(D_LEAVE_MSGS) << "sending leave msg " << lm; gu::Buffer buf; serialize(lm, buf); Datagram dg(buf); int err = send_down(dg, ProtoDownMeta()); if (err != 0) { log_debug << "send failed " << strerror(err); } sent_msgs_[Message::T_LEAVE]++; if (handle == true) { handle_leave(lm, self_i_); } } struct ViewIdCmp { bool operator()(const gcomm::evs::NodeMap::value_type& a, const gcomm::evs::NodeMap::value_type& b) const { using gcomm::evs::NodeMap; gcomm_assert(NodeMap::value(a).join_message() != 0 && NodeMap::value(b).join_message() != 0); return (NodeMap::value(a).join_message()->source_view_id().seq() < NodeMap::value(b).join_message()->source_view_id().seq()); } }; struct ProtoVerCmp { bool operator()(const gcomm::evs::NodeMap::value_type& a, const gcomm::evs::NodeMap::value_type& b) const { using gcomm::evs::NodeMap; gcomm_assert(NodeMap::value(a).join_message() != 0 && NodeMap::value(b).join_message() != 0); return (NodeMap::value(a).join_message()->version() < NodeMap::value(b).join_message()->version()); } }; void gcomm::evs::Proto::send_install(EVS_CALLER_ARG) { gcomm_assert(consensus_.is_consensus() == true && is_representative(uuid()) == true) << *this; // Select list of operational nodes from known NodeMap oper_list; for_each(known_.begin(), known_.end(), OperationalSelect(oper_list)); NodeMap::const_iterator max_node = max_element(oper_list.begin(), oper_list.end(), ViewIdCmp()); // Compute maximum known view id seq max_view_id_seq_ = std::max(max_view_id_seq_, NodeMap::value(max_node).join_message()->source_view_id().seq()); // Compute highest commonly supported protocol version. // Oper_list is non-empty, join message existence is asserted. const int version( NodeMap::value( std::min_element(oper_list.begin(), oper_list.end(), ProtoVerCmp())).join_message()->version()); MessageNodeList node_list; populate_node_list(&node_list); InstallMessage imsg(version, uuid(), current_view_.id(), ViewId(V_REG, uuid(), max_view_id_seq_ + attempt_seq_), input_map_->safe_seq(), input_map_->aru_seq(), ++fifo_seq_, node_list); ++attempt_seq_; evs_log_debug(D_INSTALL_MSGS) << EVS_LOG_METHOD << imsg; evs_log_info(I_STATE) << "sending install message" << imsg; gcomm_assert(consensus_.is_consistent(imsg)); gu::Buffer buf; serialize(imsg, buf); Datagram dg(buf); int err = send_down(dg, ProtoDownMeta()); if (err != 0) { log_debug << "send failed: " << strerror(err); } sent_msgs_[Message::T_INSTALL]++; handle_install(imsg, self_i_); } void gcomm::evs::Proto::send_delayed_list() { DelayedListMessage elm(version_, uuid(), current_view_.id(), ++fifo_seq_); for (DelayedList::const_iterator i(delayed_list_.begin()); i != delayed_list_.end(); ++i) { elm.add(i->first, i->second.state_change_cnt()); } gu::Buffer buf; serialize(elm, buf); Datagram dg(buf); (void)send_down(dg, ProtoDownMeta()); handle_delayed_list(elm, self_i_); } void gcomm::evs::Proto::resend(const UUID& gap_source, const Range range) { gcomm_assert(gap_source != uuid()); gcomm_assert(range.lu() <= range.hs()) << "lu (" << range.lu() << ") > hs(" << range.hs() << ")"; if (range.lu() <= input_map_->safe_seq()) { evs_log_debug(D_RETRANS) << self_string() << "lu (" << range.lu() << ") <= safe_seq(" << input_map_->safe_seq() << "), can't recover message"; return; } evs_log_debug(D_RETRANS) << " retrans requested by " << gap_source << " " << range.lu() << " -> " << range.hs(); seqno_t seq(range.lu()); while (seq <= range.hs()) { InputMap::iterator msg_i = input_map_->find(NodeMap::value(self_i_).index(), seq); if (msg_i == input_map_->end()) { gu_trace(msg_i = input_map_->recover(NodeMap::value(self_i_).index(), seq)); } const UserMessage& msg(InputMapMsgIndex::value(msg_i).msg()); gcomm_assert(msg.source() == uuid()); Datagram rb(InputMapMsgIndex::value(msg_i).rb()); assert(rb.offset() == 0); UserMessage um(msg.version(), msg.source(), msg.source_view_id(), msg.seq(), input_map_->aru_seq(), msg.seq_range(), msg.order(), msg.fifo_seq(), msg.user_type(), static_cast( Message::F_RETRANS | (msg.flags() & Message::F_AGGREGATE))); push_header(um, rb); int err = send_down(rb, ProtoDownMeta()); if (err != 0) { log_debug << "send failed: " << strerror(err); break; } else { evs_log_debug(D_RETRANS) << "retransmitted " << um; } seq = seq + msg.seq_range() + 1; retrans_msgs_++; } } void gcomm::evs::Proto::recover(const UUID& gap_source, const UUID& range_uuid, const Range range) { gcomm_assert(gap_source != uuid()) << "gap_source (" << gap_source << ") == uuid() (" << uuid() << " state " << *this; gcomm_assert(range.lu() <= range.hs()) << "lu (" << range.lu() << ") > hs (" << range.hs() << ")"; if (range.lu() <= input_map_->safe_seq()) { evs_log_debug(D_RETRANS) << "lu (" << range.lu() << ") <= safe_seq(" << input_map_->safe_seq() << "), can't recover message"; return; } const Node& range_node(NodeMap::value(known_.find_checked(range_uuid))); const Range im_range(input_map_->range(range_node.index())); evs_log_debug(D_RETRANS) << " recovering message from " << range_uuid << " requested by " << gap_source << " requested range " << range << " available " << im_range; seqno_t seq(range.lu()); while (seq <= range.hs() && seq <= im_range.hs()) { InputMap::iterator msg_i = input_map_->find(range_node.index(), seq); if (msg_i == input_map_->end()) { try { gu_trace(msg_i = input_map_->recover(range_node.index(), seq)); } catch (...) { seq = seq + 1; continue; } } const UserMessage& msg(InputMapMsgIndex::value(msg_i).msg()); assert(msg.source() == range_uuid); Datagram rb(InputMapMsgIndex::value(msg_i).rb()); assert(rb.offset() == 0); UserMessage um(msg.version(), msg.source(), msg.source_view_id(), msg.seq(), msg.aru_seq(), msg.seq_range(), msg.order(), msg.fifo_seq(), msg.user_type(), static_cast( Message::F_SOURCE | Message::F_RETRANS | (msg.flags() & Message::F_AGGREGATE))); push_header(um, rb); int err = send_delegate(rb); if (err != 0) { log_debug << "send failed: " << strerror(err); break; } else { evs_log_debug(D_RETRANS) << "recover " << um; } seq = seq + msg.seq_range() + 1; recovered_msgs_++; } } void gcomm::evs::Proto::handle_foreign(const Message& msg) { // no need to handle foreign LEAVE message if (msg.type() == Message::T_LEAVE) { return; } // Don't handle foreing messages in install phase. // This includes not only INSTALL state, but also // GATHER state after receiving install message. if (install_message_ != 0) { evs_log_debug(D_FOREIGN_MSGS) << " dropping foreign message from " << msg.source() << " in install state"; return; } if (is_msg_from_previous_view(msg) == true) { return; } const UUID& source(msg.source()); evs_log_info(I_STATE) << " detected new message source " << source; NodeMap::iterator i; gu_trace(i = known_.insert_unique( std::make_pair(source, Node(*this)))); assert(NodeMap::value(i).operational() == true); if (state() == S_JOINING || state() == S_GATHER || state() == S_OPERATIONAL) { evs_log_info(I_STATE) << " shift to GATHER due to foreign message from " << msg.source(); gu_trace(shift_to(S_GATHER, false)); // Reset install timer each time foreign message is seen to // synchronize install timers. reset_timer(T_INSTALL); } // Set join message after shift to recovery, shift may clean up // join messages if (msg.type() == Message::T_JOIN) { set_join(static_cast(msg), msg.source()); } send_join(true); } void gcomm::evs::Proto::handle_msg(const Message& msg, const Datagram& rb, bool direct) { assert(msg.type() <= Message::T_DELAYED_LIST); if (msg.type() > Message::T_DELAYED_LIST) { return; } if (state() == S_CLOSED) { return; } if (isolation_end_ != gu::datetime::Date::zero()) { evs_log_debug(D_STATE) << " dropping message due to isolation"; // Isolation period is on return; } if (msg.source() == uuid()) { evs_log_debug(D_FOREIGN_MSGS) << " dropping own message"; return; } if (msg.version() > GCOMM_PROTOCOL_MAX_VERSION) { log_info << "incompatible protocol version " << static_cast(msg.version()); return; } gcomm_assert(msg.source() != UUID::nil()); // Figure out if the message is from known source NodeMap::iterator ii = known_.find(msg.source()); if (ii == known_.end()) { gu_trace(handle_foreign(msg)); return; } Node& node(NodeMap::value(ii)); if (direct == true) { node.set_seen_tstamp(gu::datetime::Date::now()); } if (node.operational() == false && node.leave_message() == 0 && (msg.flags() & Message::F_RETRANS) == 0) { // We have set this node unoperational and there was // probably good reason to do so. Don't accept messages // from it before new view has been formed. // Exceptions: // - Node that is leaving // - Retransmitted messages. // why we accept retransimted messages? // a node sends a message, some nodes(A) get it, but some(B) don't // then this node is non-operational(or unreachable) // so A need to send B the missing message(in envelope as delegate message) // otherwise the input map will not be consistent forever. // and user message in delegate message always comes with F_RETRANS flag. evs_log_debug(D_FOREIGN_MSGS) << " dropping message from unoperational source " << node; return; } // Filter out non-fifo messages if (msg.fifo_seq() != -1 && (msg.flags() & Message::F_RETRANS) == 0) { if (node.fifo_seq() >= msg.fifo_seq()) { evs_log_debug(D_FOREIGN_MSGS) << "droppoing non-fifo message " << msg << " fifo seq " << node.fifo_seq(); return; } else { node.set_fifo_seq(msg.fifo_seq()); } } // Accept non-membership messages only from current view // or from view to be installed if (msg.is_membership() == false && msg.source_view_id() != current_view_.id() && (install_message_ == 0 || install_message_->install_view_id() != msg.source_view_id())) { // If source node seems to be operational but it has proceeded // into new view, mark it as unoperational in order to create // intermediate views before re-merge. if (node.installed() == true && node.operational() == true && is_msg_from_previous_view(msg) == false && state() != S_LEAVING) { evs_log_info(I_STATE) << " detected new view from operational source " << msg.source() << ": " << msg.source_view_id(); // Note: Commented out, this causes problems with // attempt_seq. Newly (remotely?) generated install message // followed by commit gap may cause undesired // node inactivation and shift to gather. // // set_inactive(msg.source()); // gu_trace(shift_to(S_GATHER, true)); } evs_log_debug(D_FOREIGN_MSGS) << "dropping non-membership message from foreign view"; return; } else if (NodeMap::value(ii).index() == std::numeric_limits::max() && msg.source_view_id() == current_view_.id()) { log_warn << "Message from node that claims to come from same view but is not in current view " << msg; assert(0); return; } recvd_msgs_[msg.type()]++; switch (msg.type()) { case Message::T_USER: gu_trace(handle_user(static_cast(msg), ii, rb)); break; case Message::T_DELEGATE: gu_trace(handle_delegate(static_cast(msg), ii, rb)); break; case Message::T_GAP: gu_trace(handle_gap(static_cast(msg), ii)); break; case Message::T_JOIN: gu_trace(handle_join(static_cast(msg), ii)); break; case Message::T_LEAVE: gu_trace(handle_leave(static_cast(msg), ii)); break; case Message::T_INSTALL: gu_trace(handle_install(static_cast(msg), ii)); break; case Message::T_DELAYED_LIST: gu_trace(handle_delayed_list( static_cast(msg), ii)); break; default: log_warn << "invalid message type " << msg.type(); } } //////////////////////////////////////////////////////////////////////// // Protolay interface //////////////////////////////////////////////////////////////////////// size_t gcomm::evs::Proto::unserialize_message(const UUID& source, const Datagram& rb, Message* msg) { size_t offset; const gu::byte_t* begin(gcomm::begin(rb)); const size_t available(gcomm::available(rb)); gu_trace(offset = msg->unserialize(begin, available, 0)); if ((msg->flags() & Message::F_SOURCE) == 0) { assert(source != UUID::nil()); gcomm_assert(source != UUID::nil()); msg->set_source(source); } switch (msg->type()) { case Message::T_NONE: gu_throw_fatal; break; case Message::T_USER: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_DELEGATE: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_GAP: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_JOIN: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_INSTALL: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_LEAVE: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; case Message::T_DELAYED_LIST: gu_trace(offset = static_cast(*msg).unserialize( begin, available, offset, true)); break; } return (offset + rb.offset()); } void gcomm::evs::Proto::handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { Message msg; if (state() == S_CLOSED || um.source() == uuid() || is_evicted(um.source())) { // Silent drop return; } gcomm_assert(um.source() != UUID::nil()); try { size_t offset; gu_trace(offset = unserialize_message(um.source(), rb, &msg)); handle_msg(msg, Datagram(rb, offset), (msg.flags() & Message::F_RETRANS) == 0); } catch (gu::Exception& e) { switch (e.get_errno()) { case EPROTONOSUPPORT: log_warn << e.what(); break; case EINVAL: log_warn << "invalid message: " << msg; break; default: log_fatal << "exception caused by message: " << msg; std::cerr << " state after handling message: " << *this; throw; } } } int gcomm::evs::Proto::handle_down(Datagram& wb, const ProtoDownMeta& dm) { if (state() == S_GATHER || state() == S_INSTALL) { return EAGAIN; } else if (state() != S_OPERATIONAL) { log_warn << "user message in state " << to_string(state()); return ENOTCONN; } if (dm.order() == O_LOCAL_CAUSAL) { gu::datetime::Date now(gu::datetime::Date::now()); if (causal_queue_.empty() == true && last_sent_ == input_map_->safe_seq() && causal_keepalive_period_ > gu::datetime::Period(0) && last_causal_keepalive_ + causal_keepalive_period_ > now) { hs_local_causal_.insert(0.0); deliver_causal(dm.user_type(), last_sent_, wb); } else { seqno_t causal_seqno(input_map_->aru_seq()); if (causal_keepalive_period_ == gu::datetime::Period(0) || last_causal_keepalive_ + causal_keepalive_period_ <= now) { // generate traffic to make sure that group is live Datagram dg; int err(send_user(dg, 0xff, O_DROP, -1, -1)); if (err != 0) { return err; } // reassign causal_seqno to be last_sent: // in order to make sure that the group is live, // safe seqno must be advanced and in this case // safe seqno equals to aru seqno. causal_seqno = last_sent_; last_causal_keepalive_ = now; } causal_queue_.push_back(CausalMessage(dm.user_type(), causal_seqno, wb)); } return 0; } send_queue_s_ += output_.size(); ++n_send_queue_s_; int ret = 0; if (output_.empty() == true) { int err; err = send_user(wb, dm.user_type(), dm.order(), user_send_window_, -1); switch (err) { case EAGAIN: { output_.push_back(std::make_pair(wb, dm)); // Fall through } case 0: ret = 0; break; default: log_error << "send error: " << err; ret = err; } } else if (output_.size() < max_output_size_) { output_.push_back(std::make_pair(wb, dm)); } else { ret = EAGAIN; } return ret; } int gcomm::evs::Proto::send_down(Datagram& dg, const ProtoDownMeta& dm) { if (isolation_end_ != gu::datetime::Date::zero()) { // Node has isolated itself, don't emit any messages return 0; } else { return Protolay::send_down(dg, dm); } } ///////////////////////////////////////////////////////////////////////////// // State handler ///////////////////////////////////////////////////////////////////////////// void gcomm::evs::Proto::shift_to(const State s, const bool send_j) { if (shift_to_rfcnt_ > 0) gu_throw_fatal << *this; shift_to_rfcnt_++; static const bool allowed[S_MAX][S_MAX] = { // CLOSED JOINING LEAVING GATHER INSTALL OPERAT { false, true, false, false, false, false }, // CLOSED { false, false, true, true, false, false }, // JOINING { true, false, false, false, false, false }, // LEAVING { false, false, true, true, true, false }, // GATHER { false, false, false, true, false, true }, // INSTALL { false, false, true, true, false, false } // OPERATIONAL }; assert(s < S_MAX); if (allowed[state_][s] == false) { gu_throw_fatal << "Forbidden state transition: " << to_string(state_) << " -> " << to_string(s); } if (state() != s) { evs_log_info(I_STATE) << " state change: " << to_string(state_) << " -> " << to_string(s); } switch (s) { case S_CLOSED: { gcomm_assert(state() == S_LEAVING); gu_trace(deliver()); gu_trace(deliver_local()); setall_installed(false); NodeMap::value(self_i_).set_installed(true); // Construct install message containing only one node for // last trans view. MessageNodeList node_list; (void)node_list.insert_unique( std::make_pair(uuid(), MessageNode(true, false, NodeMap::value(self_i_).segment(), false, -1, current_view_.id(), input_map_->safe_seq( NodeMap::value(self_i_).index()), input_map_->range( NodeMap::value(self_i_).index())))); InstallMessage im(0, uuid(), current_view_.id(), ViewId(V_REG, uuid(), current_view_.id().seq() + 1), input_map_->safe_seq(), input_map_->aru_seq(), ++fifo_seq_, node_list); gu_trace(deliver_trans_view(im, current_view_)); gu_trace(deliver_trans()); gu_trace(deliver_local(true)); gcomm_assert(causal_queue_.empty() == true); if (collect_stats_ == true) { handle_stats_timer(); } gu_trace(deliver_empty_view()); cleanup_foreign(im); cleanup_views(); timers_.clear(); state_ = S_CLOSED; break; } case S_JOINING: state_ = S_JOINING; reset_timer(T_STATS); break; case S_LEAVING: state_ = S_LEAVING; reset_timer(T_INACTIVITY); reset_timer(T_RETRANS); reset_timer(T_INSTALL); break; case S_GATHER: { setall_committed(false); setall_installed(false); delete install_message_; install_message_ = 0; if (state() == S_OPERATIONAL) { profile_enter(send_user_prof_); while (output_.empty() == false) { int err; gu_trace(err = send_user(-1)); if (err != 0) { gu_throw_fatal << self_string() << "send_user() failed in shifto " << "to S_GATHER: " << strerror(err); } } profile_leave(send_user_prof_); } else { gcomm_assert(output_.empty() == true); } State prev_state(state_); state_ = S_GATHER; if (send_j == true) { profile_enter(send_join_prof_); gu_trace(send_join(false)); profile_leave(send_join_prof_); } gcomm_assert(state() == S_GATHER); reset_timer(T_INACTIVITY); if (prev_state == S_OPERATIONAL || prev_state == S_JOINING) { reset_timer(T_RETRANS); reset_timer(T_INSTALL); } break; } case S_INSTALL: { gcomm_assert(install_message_ != 0); gcomm_assert(is_all_committed() == true); state_ = S_INSTALL; reset_timer(T_INACTIVITY); reset_timer(T_RETRANS); break; } case S_OPERATIONAL: { gcomm_assert(output_.empty() == true); gcomm_assert(install_message_ != 0); gcomm_assert(NodeMap::value(self_i_).join_message() != 0 && consensus_.equal( *NodeMap::value(self_i_).join_message(), *install_message_)) << "install message not consistent with own join, state: " << *this; gcomm_assert(is_all_installed() == true); gu_trace(deliver()); gu_trace(deliver_local()); gu_trace(deliver_trans_view(*install_message_, current_view_)); gu_trace(deliver_trans()); gu_trace(deliver_local(true)); gcomm_assert(causal_queue_.empty() == true); input_map_->clear(); if (collect_stats_ == true) { handle_stats_timer(); } // End of previous view // Construct new view and shift to S_OPERATIONAL before calling // deliver_reg_view(). Reg view delivery may trigger message // exchange on upper layer and operating view is needed to // handle messages. previous_view_ = current_view_; std::copy(gather_views_.begin(), gather_views_.end(), std::inserter(previous_views_, previous_views_.end())); gather_views_.clear(); if (install_message_->version() > current_view_.version()) { log_info << "EVS version upgrade " << current_view_.version() << " -> " << static_cast(install_message_->version()); } else if (install_message_->version() < current_view_.version()) { log_info << "EVS version downgrade " << current_view_.version() << " -> " << static_cast(install_message_->version()); } current_view_ = View(install_message_->version(), install_message_->install_view_id()); size_t idx = 0; const MessageNodeList& imnl(install_message_->node_list()); for (MessageNodeList::const_iterator i(imnl.begin()); i != imnl.end(); ++i) { const UUID& uuid(MessageNodeList::key(i)); const MessageNode& n(MessageNodeList::value(i)); // Add operational nodes to new view, assign input map index NodeMap::iterator nmi(known_.find(uuid)); gcomm_assert(nmi != known_.end()) << "node " << uuid << " not found from known map"; if (n.operational() == true) { current_view_.add_member(uuid, NodeMap::value(nmi).segment()); NodeMap::value(nmi).set_index(idx++); } else { NodeMap::value(nmi).set_index( std::numeric_limits::max()); } } if (previous_view_.id().type() == V_REG && previous_view_.members() == current_view_.members()) { evs_log_info(I_VIEWS) << "subsequent views have same members, prev view " << previous_view_ << " current view " << current_view_; } input_map_->reset(current_view_.members().size()); last_sent_ = -1; state_ = S_OPERATIONAL; deliver_reg_view(*install_message_, previous_view_); cleanup_foreign(*install_message_); cleanup_views(); cleanup_joins(); delete install_message_; install_message_ = 0; attempt_seq_ = 1; install_timeout_count_ = 0; profile_enter(send_gap_prof_); gu_trace(send_gap(EVS_CALLER, UUID::nil(), current_view_.id(), Range()));; profile_leave(send_gap_prof_); gcomm_assert(state() == S_OPERATIONAL); reset_timer(T_INACTIVITY); reset_timer(T_RETRANS); cancel_timer(T_INSTALL); break; } default: gu_throw_fatal << "invalid state"; } shift_to_rfcnt_--; } //////////////////////////////////////////////////////////////////////////// // Message delivery //////////////////////////////////////////////////////////////////////////// void gcomm::evs::Proto::deliver_causal(uint8_t user_type, seqno_t seqno, const Datagram& datagram) { send_up(datagram, ProtoUpMeta(uuid(), current_view_.id(), 0, user_type, O_LOCAL_CAUSAL, seqno)); ++delivered_msgs_[O_LOCAL_CAUSAL]; } void gcomm::evs::Proto::deliver_local(bool trans) { // local causal const seqno_t causal_seq(trans == false ? input_map_->safe_seq() : last_sent_); gu::datetime::Date now(gu::datetime::Date::now()); while (causal_queue_.empty() == false && causal_queue_.front().seqno() <= causal_seq) { const CausalMessage& cm(causal_queue_.front()); hs_local_causal_.insert(double(now.get_utc() - cm.tstamp().get_utc())/gu::datetime::Sec); deliver_causal(cm.user_type(), cm.seqno(), cm.datagram()); causal_queue_.pop_front(); } } void gcomm::evs::Proto::validate_reg_msg(const UserMessage& msg) { if (msg.source_view_id() != current_view_.id()) { // Note: This implementation should guarantee same view delivery, // this is sanity check for that. gu_throw_fatal << "reg validate: not current view"; } // Update statistics for locally generated messages if (msg.source() == uuid()) { if (msg.order() == O_SAFE) { gu::datetime::Date now(gu::datetime::Date::now()); double lat(double(now.get_utc() - msg.tstamp().get_utc())/ gu::datetime::Sec); if (info_mask_ & I_STATISTICS) hs_safe_.insert(lat); safe_deliv_latency_.insert(lat); } else if (msg.order() == O_AGREED) { if (info_mask_ & I_STATISTICS) { gu::datetime::Date now(gu::datetime::Date::now()); hs_agreed_.insert(double(now.get_utc() - msg.tstamp().get_utc())/gu::datetime::Sec); } } } } void gcomm::evs::Proto::deliver_finish(const InputMapMsg& msg) { if ((msg.msg().flags() & Message::F_AGGREGATE) == 0) { ++delivered_msgs_[msg.msg().order()]; if (msg.msg().order() != O_DROP) { gu_trace(validate_reg_msg(msg.msg())); profile_enter(delivery_prof_); ProtoUpMeta um(msg.msg().source(), msg.msg().source_view_id(), 0, msg.msg().user_type(), msg.msg().order(), msg.msg().seq()); try { send_up(msg.rb(), um); } catch (...) { log_info << msg.msg() << " " << msg.rb().len(); throw; } profile_leave(delivery_prof_); } } else { gu_trace(validate_reg_msg(msg.msg())); size_t offset(0); while (offset < msg.rb().len()) { ++delivered_msgs_[msg.msg().order()]; AggregateMessage am; gu_trace(am.unserialize(&msg.rb().payload()[0], msg.rb().payload().size(), offset)); Datagram dg( gu::SharedBuffer( new gu::Buffer( &msg.rb().payload()[0] + offset + am.serial_size(), &msg.rb().payload()[0] + offset + am.serial_size() + am.len()))); ProtoUpMeta um(msg.msg().source(), msg.msg().source_view_id(), 0, am.user_type(), msg.msg().order(), msg.msg().seq()); gu_trace(send_up(dg, um)); offset += am.serial_size() + am.len(); } gcomm_assert(offset == msg.rb().len()); } } void gcomm::evs::Proto::deliver() { if (delivering_ == true) { gu_throw_fatal << "Recursive enter to delivery"; } delivering_ = true; if (state() != S_OPERATIONAL && state() != S_GATHER && state() != S_INSTALL && state() != S_LEAVING) { gu_throw_fatal << "invalid state: " << to_string(state()); } evs_log_debug(D_DELIVERY) << " aru_seq=" << input_map_->aru_seq() << " safe_seq=" << input_map_->safe_seq(); InputMapMsgIndex::iterator i, i_next; for (i = input_map_->begin(); i != input_map_->end(); i = i_next) { i_next = i; ++i_next; const InputMapMsg& msg(InputMapMsgIndex::value(i)); bool deliver = false; switch (msg.msg().order()) { case O_SAFE: if (input_map_->is_safe(i) == true) { deliver = true; } break; case O_AGREED: if (input_map_->is_agreed(i) == true) { deliver = true; } break; case O_FIFO: case O_DROP: if (input_map_->is_fifo(i) == true) { deliver = true; } break; default: gu_throw_fatal << "invalid safety prefix " << msg.msg().order(); } if (deliver == true) { deliver_finish(msg); gu_trace(input_map_->erase(i)); } else if (input_map_->has_deliverables() == false) { break; } } delivering_ = false; } void gcomm::evs::Proto::deliver_trans() { if (delivering_ == true) { gu_throw_fatal << "Recursive enter to delivery"; } delivering_ = true; if (state() != S_INSTALL && state() != S_LEAVING) gu_throw_fatal << "invalid state"; evs_log_debug(D_DELIVERY) << " aru_seq=" << input_map_->aru_seq() << " safe_seq=" << input_map_->safe_seq(); // In transitional configuration we must deliver all messages that // are fifo. This is because: // - We know that it is possible to deliver all fifo messages originated // from partitioned component as safe in partitioned component // - Aru in this component is at least the max known fifo seq // from partitioned component due to message recovery // - All FIFO messages originated from this component must be // delivered to fulfill self delivery requirement and // - FIFO messages originated from this component qualify as AGREED // in transitional configuration InputMap::iterator i, i_next; for (i = input_map_->begin(); i != input_map_->end(); i = i_next) { i_next = i; ++i_next; const InputMapMsg& msg(InputMapMsgIndex::value(i)); bool deliver = false; switch (msg.msg().order()) { case O_SAFE: case O_AGREED: case O_FIFO: case O_DROP: if (input_map_->is_fifo(i) == true) { deliver = true; } break; default: gu_throw_fatal; } if (deliver == true) { if (install_message_ != 0) { const MessageNode& mn( MessageNodeList::value( install_message_->node_list().find_checked( msg.msg().source()))); if (msg.msg().seq() <= mn.im_range().hs()) { deliver_finish(msg); } else { gcomm_assert(mn.operational() == false); log_info << "filtering out trans message higher than " << "install message hs " << mn.im_range().hs() << ": " << msg.msg(); } } else { deliver_finish(msg); } gu_trace(input_map_->erase(i)); } } // Sanity check: // There must not be any messages left that // - Are originated from outside of trans conf and are FIFO // - Are originated from trans conf for (i = input_map_->begin(); i != input_map_->end(); i = i_next) { i_next = i; ++i_next; const InputMapMsg& msg(InputMapMsgIndex::value(i)); NodeMap::iterator ii; gu_trace(ii = known_.find_checked(msg.msg().source())); if (NodeMap::value(ii).installed() == true) { gu_throw_fatal << "Protocol error in transitional delivery " << "(self delivery constraint)"; } else if (input_map_->is_fifo(i) == true) { gu_throw_fatal << "Protocol error in transitional delivery " << "(fifo from partitioned component)"; } gu_trace(input_map_->erase(i)); } delivering_ = false; } ///////////////////////////////////////////////////////////////////////////// // Message handlers ///////////////////////////////////////////////////////////////////////////// gcomm::evs::seqno_t gcomm::evs::Proto::update_im_safe_seq(const size_t uuid, const seqno_t seq) { const seqno_t im_safe_seq(input_map_->safe_seq(uuid)); if (im_safe_seq < seq) { input_map_->set_safe_seq(uuid, seq); } return im_safe_seq; } void gcomm::evs::Proto::handle_user(const UserMessage& msg, NodeMap::iterator ii, const Datagram& rb) { assert(ii != known_.end()); assert(state() != S_CLOSED && state() != S_JOINING); Node& inst(NodeMap::value(ii)); evs_log_debug(D_USER_MSGS) << "received " << msg; if (msg.source_view_id() != current_view_.id()) { if (state() == S_LEAVING) { // Silent drop return; } if (is_msg_from_previous_view(msg) == true) { evs_log_debug(D_FOREIGN_MSGS) << "user message " << msg << " from previous view"; return; } if (inst.operational() == false) { evs_log_debug(D_STATE) << "dropping message from unoperational source " << msg.source(); return; } else if (inst.installed() == false) { if (install_message_ != 0 && msg.source_view_id() == install_message_->install_view_id()) { assert(state() == S_GATHER || state() == S_INSTALL); evs_log_debug(D_STATE) << " recovery user message " << msg; // This is possible if install timer expires just before // new view is established on this node and retransmitted // install message is received just before user this message. if (state() == S_GATHER) { // Sanity check MessageNodeList::const_iterator self( install_message_->node_list().find(uuid())); gcomm_assert(self != install_message_->node_list().end() && MessageNodeList::value(self).operational() == true); // Mark all operational nodes in install message as // committed for (MessageNodeList::const_iterator mi = install_message_->node_list().begin(); mi != install_message_->node_list().end(); ++mi) { if (MessageNodeList::value(mi).operational() == true) { NodeMap::iterator jj; gu_trace(jj = known_.find_checked( MessageNodeList::key(mi))); NodeMap::value(jj).set_committed(true); } } shift_to(S_INSTALL); } // Other instances installed view before this one, so it is // safe to shift to S_OPERATIONAL // Mark all operational nodes in install message as installed for (MessageNodeList::const_iterator mi = install_message_->node_list().begin(); mi != install_message_->node_list().end(); ++mi) { if (MessageNodeList::value(mi).operational() == true) { NodeMap::iterator jj; gu_trace(jj = known_.find_checked( MessageNodeList::key(mi))); NodeMap::value(jj).set_installed(true); } } inst.set_tstamp(gu::datetime::Date::now()); profile_enter(shift_to_prof_); gu_trace(shift_to(S_OPERATIONAL)); profile_leave(shift_to_prof_); if (pending_leave_ == true) { close(); } // proceed to process actual user message } else { return; } } else { log_debug << self_string() << " unhandled user message " << msg; return; } } gcomm_assert(msg.source_view_id() == current_view_.id()); // note: #gh40 bool shift_to_gather = false; if (install_message_) { const MessageNode& mn( MessageNodeList::value( install_message_->node_list().find_checked( msg.source()))); if (!mn.operational()) return ; if (mn.operational() && msg.seq() > mn.im_range().hs()) { shift_to_gather = true; } } Range range; Range prev_range; seqno_t prev_aru; seqno_t prev_safe; profile_enter(input_map_prof_); prev_aru = input_map_->aru_seq(); prev_range = input_map_->range(inst.index()); // Insert only if msg seq is greater or equal than current lowest unseen if (msg.seq() >= prev_range.lu()) { Datagram im_dgram(rb, rb.offset()); im_dgram.normalize(); gu_trace(range = input_map_->insert(inst.index(), msg, im_dgram)); if (range.lu() > prev_range.lu()) { inst.set_tstamp(gu::datetime::Date::now()); } } else { range = prev_range; } // Update im safe seq for self update_im_safe_seq(NodeMap::value(self_i_).index(), input_map_->aru_seq()); // Update safe seq for message source prev_safe = update_im_safe_seq(inst.index(), msg.aru_seq()); profile_leave(input_map_prof_); // Check for missing messages if (range.hs() > range.lu() && (msg.flags() & Message::F_RETRANS) == 0 ) { evs_log_debug(D_RETRANS) << " requesting retrans from " << msg.source() << " " << range << " due to input map gap, aru " << input_map_->aru_seq(); profile_enter(send_gap_prof_); gu_trace(send_gap(EVS_CALLER, msg.source(), current_view_.id(), range)); profile_leave(send_gap_prof_); } // Seqno range completion and acknowledgement const seqno_t max_hs(input_map_->max_hs()); if (output_.empty() == true && (state() == S_OPERATIONAL || state() == S_GATHER) && (msg.flags() & Message::F_MSG_MORE) == 0 && (last_sent_ < max_hs)) { // Message not originated from this instance, output queue is empty // and last_sent seqno should be advanced gu_trace(complete_user(max_hs)); } else if (output_.empty() == true && input_map_->aru_seq() != prev_aru) { // Output queue empty and aru changed, send gap to inform others evs_log_debug(D_GAP_MSGS) << "sending empty gap"; profile_enter(send_gap_prof_); gu_trace(send_gap(EVS_CALLER, UUID::nil(), current_view_.id(), Range())); profile_leave(send_gap_prof_); } // Send messages if (state() == S_OPERATIONAL) { profile_enter(send_user_prof_); while (output_.empty() == false) { int err; gu_trace(err = send_user(send_window_)); if (err != 0) { break; } } profile_leave(send_user_prof_); } // Deliver messages profile_enter(delivery_prof_); if (input_map_->has_deliverables() == true) { gu_trace(deliver()); } gu_trace(deliver_local()); profile_leave(delivery_prof_); // If in recovery state, send join each time input map aru seq reaches // last sent and either input map aru or safe seq has changed. if (state() == S_GATHER && consensus_.highest_reachable_safe_seq() == input_map_->aru_seq() && (prev_aru != input_map_->aru_seq() || prev_safe != input_map_->safe_seq()) && (msg.flags() & Message::F_RETRANS) == 0) { gcomm_assert(output_.empty() == true); if (consensus_.is_consensus() == false) { profile_enter(send_join_prof_); gu_trace(send_join()); profile_leave(send_join_prof_); } } if (shift_to_gather) { shift_to(S_GATHER, true); } } void gcomm::evs::Proto::handle_delegate(const DelegateMessage& msg, NodeMap::iterator ii, const Datagram& rb) { gcomm_assert(ii != known_.end()); evs_log_debug(D_DELEGATE_MSGS) << "delegate message " << msg; Message umsg; size_t offset; gu_trace(offset = unserialize_message(UUID::nil(), rb, &umsg)); gu_trace(handle_msg(umsg, Datagram(rb, offset), false)); } void gcomm::evs::Proto::handle_gap(const GapMessage& msg, NodeMap::iterator ii) { assert(ii != known_.end()); assert(state() != S_CLOSED && state() != S_JOINING); Node& inst(NodeMap::value(ii)); evs_log_debug(D_GAP_MSGS) << "gap message " << msg; if ((msg.flags() & Message::F_COMMIT) != 0) { log_debug << self_string() << " commit gap from " << msg.source(); if (state() == S_GATHER && install_message_ != 0 && install_message_->install_view_id() == msg.source_view_id() && install_message_->fifo_seq() == msg.seq()) { inst.set_committed(true); inst.set_tstamp(gu::datetime::Date::now()); if (is_all_committed() == true) { shift_to(S_INSTALL); gu_trace(send_gap(EVS_CALLER, UUID::nil(), install_message_->install_view_id(), Range()));; } } else if (state() == S_GATHER && install_message_ != 0 && install_message_->install_view_id() == msg.source_view_id() && install_message_->fifo_seq() < msg.seq()) { // new install message has been generated shift_to(S_GATHER, true); } else { evs_log_debug(D_GAP_MSGS) << " unhandled commit gap " << msg; } return; } else if (state() == S_INSTALL && install_message_ != 0 && install_message_->install_view_id() == msg.source_view_id()) { evs_log_debug(D_STATE) << "install gap " << msg; inst.set_installed(true); inst.set_tstamp(gu::datetime::Date::now()); if (is_all_installed() == true) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_OPERATIONAL)); profile_leave(shift_to_prof_); if (pending_leave_ == true) { close(); } } return; } else if (msg.source_view_id() != current_view_.id()) { if (state() == S_LEAVING) { // Silently drop return; } if (is_msg_from_previous_view(msg) == true) { evs_log_debug(D_FOREIGN_MSGS) << "gap message from previous view"; return; } if (inst.operational() == false) { evs_log_debug(D_STATE) << "dropping message from unoperational source " << msg.source(); } else if (inst.installed() == false) { evs_log_debug(D_STATE) << "dropping message from uninstalled source " << msg.source(); } else { log_debug << "unhandled gap message " << msg; } return; } gcomm_assert(msg.source_view_id() == current_view_.id()); // seqno_t prev_safe; profile_enter(input_map_prof_); prev_safe = update_im_safe_seq(inst.index(), msg.aru_seq()); // Deliver messages and update tstamp only if safe_seq changed // for the source. if (prev_safe != input_map_->safe_seq(inst.index())) { inst.set_tstamp(gu::datetime::Date::now()); } profile_leave(input_map_prof_); // if (msg.range_uuid() == uuid()) { if (msg.range().hs() > last_sent_ && (state() == S_OPERATIONAL || state() == S_GATHER)) { // This could be leaving node requesting messages up to // its last sent. gu_trace(complete_user(msg.range().hs())); } const seqno_t upper_bound( std::min(msg.range().hs(), last_sent_)); if (msg.range().lu() <= upper_bound) { gu_trace(resend(msg.source(), Range(msg.range().lu(), upper_bound))); } } else if ((msg.flags() & Message::F_RETRANS) != 0 && msg.source() != uuid()) { gu_trace(recover(msg.source(), msg.range_uuid(), msg.range())); } // if (state() == S_OPERATIONAL) { if (output_.empty() == false) { profile_enter(send_user_prof_); while (output_.empty() == false) { int err; gu_trace(err = send_user(send_window_)); if (err != 0) break; } profile_leave(send_user_prof_); } else { const seqno_t max_hs(input_map_->max_hs()); if (last_sent_ < max_hs) { gu_trace(complete_user(max_hs)); } } } profile_enter(delivery_prof_); if (input_map_->has_deliverables() == true) { gu_trace(deliver()); } gu_trace(deliver_local()); profile_leave(delivery_prof_); // if (state() == S_GATHER && consensus_.highest_reachable_safe_seq() == input_map_->aru_seq() && prev_safe != input_map_->safe_seq() ) { gcomm_assert(output_.empty() == true); if (consensus_.is_consensus() == false) { profile_enter(send_join_prof_); gu_trace(send_join()); profile_leave(send_join_prof_); } } } bool gcomm::evs::Proto::update_im_safe_seqs(const MessageNodeList& node_list) { bool updated = false; // Update input map state for (MessageNodeList::const_iterator i = node_list.begin(); i != node_list.end(); ++i) { const UUID& node_uuid(MessageNodeList::key(i)); const Node& local_node(NodeMap::value(known_.find_checked(node_uuid))); const MessageNode& node(MessageNodeList::value(i)); gcomm_assert(node.view_id() == current_view_.id()); const seqno_t safe_seq(node.safe_seq()); seqno_t prev_safe_seq; gu_trace(prev_safe_seq = update_im_safe_seq(local_node.index(), safe_seq)); if (prev_safe_seq != safe_seq && input_map_->safe_seq(local_node.index()) == safe_seq) { updated = true; } } return updated; } void gcomm::evs::Proto::retrans_user(const UUID& nl_uuid, const MessageNodeList& node_list) { for (MessageNodeList::const_iterator i = node_list.begin(); i != node_list.end(); ++i) { const UUID& node_uuid(MessageNodeList::key(i)); const MessageNode& mn(MessageNodeList::value(i)); const Node& n(NodeMap::value(known_.find_checked(node_uuid))); const Range r(input_map_->range(n.index())); if (node_uuid == uuid() && mn.im_range().lu() != r.lu()) { // Source member is missing messages from us gcomm_assert(mn.im_range().hs() <= last_sent_); gu_trace(resend(nl_uuid, Range(mn.im_range().lu(), last_sent_))); } else if ((mn.operational() == false || mn.leaving() == true) && node_uuid != uuid() && (mn.im_range().lu() < r.lu() || mn.im_range().hs() < r.hs())) { gu_trace(recover(nl_uuid, node_uuid, Range(mn.im_range().lu(), r.hs()))); } } } void gcomm::evs::Proto::retrans_leaves(const MessageNodeList& node_list) { for (NodeMap::const_iterator li = known_.begin(); li != known_.end(); ++li) { const Node& local_node(NodeMap::value(li)); if (local_node.leave_message() != 0 && local_node.is_inactive() == false) { MessageNodeList::const_iterator msg_li( node_list.find(NodeMap::key(li))); if (msg_li == node_list.end() || MessageNodeList::value(msg_li).leaving() == false) { const LeaveMessage& lm(*NodeMap::value(li).leave_message()); LeaveMessage send_lm(lm.version(), lm.source(), lm.source_view_id(), lm.seq(), lm.aru_seq(), lm.fifo_seq(), Message::F_RETRANS | Message::F_SOURCE); gu::Buffer buf; serialize(send_lm, buf); Datagram dg(buf); gu_trace(send_delegate(dg)); } } } } class SelectSuspectsOp { public: SelectSuspectsOp(gcomm::evs::MessageNodeList& nl) : nl_(nl) { } void operator()(const gcomm::evs::MessageNodeList::value_type& vt) const { if (gcomm::evs::MessageNodeList::value(vt).suspected() == true) { nl_.insert_unique(vt); } } private: gcomm::evs::MessageNodeList& nl_; }; void gcomm::evs::Proto::check_suspects(const UUID& source, const MessageNodeList& nl) { assert(source != uuid()); MessageNodeList suspected; for_each(nl.begin(), nl.end(), SelectSuspectsOp(suspected)); for (MessageNodeList::const_iterator i(suspected.begin()); i != suspected.end(); ++i) { const UUID& node_uuid(MessageNodeList::key(i)); const MessageNode& node(MessageNodeList::value(i)); if (node.suspected() == true) { if (node_uuid != uuid()) { size_t s_cnt(0); // Iterate over join messages to see if majority of current // view agrees with the suspicion for (NodeMap::const_iterator j(known_.begin()); j != known_.end(); ++j) { const JoinMessage* jm(NodeMap::value(j).join_message()); if (jm != 0 && jm->source() != node_uuid && current_view_.is_member(jm->source()) == true) { MessageNodeList::const_iterator mni(jm->node_list().find(node_uuid)); if (mni != jm->node_list().end()) { const MessageNode& mn(MessageNodeList::value(mni)); if (mn.suspected() == true) { ++s_cnt; } } } } const Node& kn(NodeMap::value(known_.find_checked(node_uuid))); if (kn.operational() == true && s_cnt > current_view_.members().size()/2) { evs_log_info(I_STATE) << " declaring suspected " << node_uuid << " as inactive"; set_inactive(node_uuid); } } } } } void gcomm::evs::Proto::cross_check_inactives(const UUID& source, const MessageNodeList& nl) { assert(source != uuid()); // Do elimination by suspect status NodeMap::const_iterator source_i(known_.find_checked(source)); for (MessageNodeList::const_iterator i(nl.begin()); i != nl.end(); ++i) { const UUID& node_uuid(MessageNodeList::key(i)); const MessageNode& node(MessageNodeList::value(i)); if (node.operational() == false) { NodeMap::iterator local_i(known_.find(node_uuid)); if (local_i != known_.end() && node_uuid != uuid()) { const Node& local_node(NodeMap::value(local_i)); if (local_node.suspected()) { // This node is suspecting and the source node has // already set inactve, mark also locally inactive. set_inactive(node_uuid); } } } } } // Asymmetry elimination: // 1a) Find all joins that has this node marked as operational and which // this node considers operational // 1b) Mark all operational nodes without join message unoperational // 2) Iterate over join messages gathered in 1a, find all // unoperational entries and mark them unoperational too void gcomm::evs::Proto::asymmetry_elimination() { // Allow some time to pass from setting install timers to get // join messages accumulated. const gu::datetime::Date now(gu::datetime::Date::now()); TimerList::const_iterator ti( find_if(timers_.begin(), timers_.end(), TimerSelectOp(T_INSTALL))); assert(ti != timers_.end()); if (ti == timers_.end()) { log_warn << "install timer not set in asymmetry_elimination()"; return; } if (install_timeout_ - suspect_timeout_ < TimerList::key(ti) - now) { // No check yet return; } // Record initial operational state for logging std::vector oparr_before(known_.size()); size_t index(0); for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { oparr_before[index] = (NodeMap::value(i).operational() == true); index++; } std::list joins; // Compose list of join messages for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { const UUID& node_uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); const JoinMessage* jm(node.join_message()); if (jm != 0) { MessageNodeList::const_iterator self_ref( jm->node_list().find(uuid())); if (node.operational() == true && self_ref != jm->node_list().end() && MessageNodeList::value(self_ref).operational() == true) { joins.push_back(NodeMap::value(i).join_message()); } } else if (node.operational() == true) { evs_log_info(I_STATE) << "marking operational node " << node_uuid << " without " << "join message inactive in asymmetry elimination"; set_inactive(node_uuid); } } // Setting node inactive may remove join message and so invalidate // pointer in joins list, so collect set of UUIDs to set inactive // and do inactivation in separate loop. std::set to_inactive; // Iterate over join messages and collect nodes to be set inactive for (std::list::const_iterator i(joins.begin()); i != joins.end(); ++i) { for (MessageNodeList::const_iterator j((*i)->node_list().begin()); j != (*i)->node_list().end(); ++j) { if (MessageNodeList::value(j).operational() == false) { to_inactive.insert(MessageNodeList::key(j)); } } } joins.clear(); for (std::set::const_iterator i(to_inactive.begin()); i != to_inactive.end(); ++i) { NodeMap::const_iterator ni(known_.find(*i)); if (ni != known_.end()) { if (NodeMap::value(ni).operational() == true) { evs_log_info(I_STATE) << "setting " << *i << " inactive in asymmetry elimination"; set_inactive(*i); } } else { log_warn << "node " << *i << " not found from known list in ae"; } } // Compute final state and log if it has changed std::vector oparr_after(known_.size()); index = 0; for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { oparr_after[index] = (NodeMap::value(i).operational() == true); index++; } if (oparr_before != oparr_after) { evs_log_info(I_STATE) << "before asym elimination"; if (info_mask_ & I_STATE) { std::copy(oparr_before.begin(), oparr_before.end(), std::ostream_iterator(std::cerr, " ")); std::cerr << "\n"; } evs_log_info(I_STATE) << "after asym elimination"; if (info_mask_ & I_STATE) { std::copy(oparr_after.begin(), oparr_after.end(), std::ostream_iterator(std::cerr, " ")); std::cerr << "\n"; } } } // For each node thas has no join message associated, iterate over other // known nodes' join messages to find out if the node without join message // should be declared inactive. void gcomm::evs::Proto::check_unseen() { for (NodeMap::iterator i(known_.begin()); i != known_.end(); ++i) { const UUID& node_uuid(NodeMap::key(i)); Node& node(NodeMap::value(i)); if (node_uuid != uuid() && current_view_.is_member(node_uuid) == false && node.join_message() == 0 && node.operational() == true) { evs_log_debug(D_STATE) << "checking operational unseen " << node_uuid; size_t cnt(0), inact_cnt(0); for (NodeMap::iterator j(known_.begin()); j != known_.end(); ++j) { const JoinMessage* jm(NodeMap::value(j).join_message()); if (jm == 0 || NodeMap::key(j) == uuid()) { continue; } MessageNodeList::const_iterator mn_i; for (mn_i = jm->node_list().begin(); mn_i != jm->node_list().end(); ++mn_i) { NodeMap::const_iterator known_i( known_.find(MessageNodeList::key(mn_i))); if (known_i == known_.end() || (MessageNodeList::value(mn_i).operational() == true && NodeMap::value(known_i).join_message() == 0)) { evs_log_debug(D_STATE) << "all joins not locally present for " << NodeMap::key(j) << " join message node list"; return; } } if ((mn_i = jm->node_list().find(node_uuid)) != jm->node_list().end()) { const MessageNode& mn(MessageNodeList::value(mn_i)); evs_log_debug(D_STATE) << "found " << node_uuid << " from " << NodeMap::key(j) << " join message: " << mn.view_id() << " " << mn.operational(); if (mn.view_id() != ViewId(V_REG)) { ++cnt; if (mn.operational() == false) ++inact_cnt; } } } if (cnt > 0 && cnt == inact_cnt) { evs_log_info(I_STATE) << "unseen node marked inactive by others (cnt=" << cnt << ", inact_cnt=" << inact_cnt << ")"; set_inactive(node_uuid); } } } } // Iterate over all join messages. If some node has nil view id and suspected // flag true in all present join messages, declare it inactive. void gcomm::evs::Proto::check_nil_view_id() { size_t join_counts(0); std::map nil_counts; for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { const JoinMessage* jm(NodeMap::value(i).join_message()); if (jm == 0) { continue; } ++join_counts; for (MessageNodeList::const_iterator j(jm->node_list().begin()); j != jm->node_list().end(); ++j) { const MessageNode& mn(MessageNodeList::value(j)); if (mn.view_id() == ViewId(V_REG)) { // todo: investigate why removing mn.suspected() == true // condition causes some unit tests to fail if (mn.suspected() == true) { const UUID& uuid(MessageNodeList::key(j)); ++nil_counts[uuid]; } } } } for (std::map::const_iterator i(nil_counts.begin()); i != nil_counts.end(); ++i) { if (i->second == join_counts && is_inactive(i->first) == false) { log_info << "node " << i->first << " marked with nil view id and suspected in all present" << " join messages, declaring inactive"; set_inactive(i->first); } } } void gcomm::evs::Proto::handle_join(const JoinMessage& msg, NodeMap::iterator ii) { assert(ii != known_.end()); assert(state() != S_CLOSED); Node& inst(NodeMap::value(ii)); evs_log_debug(D_JOIN_MSGS) << " " << msg; if (state() == S_LEAVING) { if (msg.source_view_id() == current_view_.id()) { inst.set_tstamp(gu::datetime::Date::now()); MessageNodeList same_view; for_each(msg.node_list().begin(), msg.node_list().end(), SelectNodesOp(same_view, current_view_.id(), true, true)); profile_enter(input_map_prof_); if (update_im_safe_seqs(same_view) == true) { profile_enter(send_leave_prof_); gu_trace(send_leave(false)); profile_leave(send_leave_prof_); } for (NodeMap::const_iterator i = known_.begin(); i != known_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); const Node& node(NodeMap::value(i)); if (current_view_.is_member(uuid) == true) { const Range r(input_map_->range(node.index())); if (r.lu() <= last_sent_) { send_gap(EVS_CALLER, uuid, current_view_.id(), Range(r.lu(), last_sent_)); } } } profile_leave(input_map_prof_); gu_trace(retrans_user(msg.source(), same_view)); } return; } else if (is_msg_from_previous_view(msg) == true) { return; } else if (install_message_ != 0) { // Note: don't send join from this branch yet, join is // sent at the end of this method if (install_message_->source() == msg.source()) { evs_log_info(I_STATE) << "shift to gather due to representative " << msg.source() << " join"; if (msg.source_view_id() == install_message_->install_view_id()) { // Representative reached operational state, we follow // Other instances installed view before this one, so it is // safe to shift to S_OPERATIONAL // Mark all operational nodes in install message as installed for (MessageNodeList::const_iterator mi = install_message_->node_list().begin(); mi != install_message_->node_list().end(); ++mi) { if (MessageNodeList::value(mi).operational() == true) { NodeMap::iterator jj; gu_trace(jj = known_.find_checked( MessageNodeList::key(mi))); NodeMap::value(jj).set_installed(true); } } inst.set_tstamp(gu::datetime::Date::now()); if (state() == S_INSTALL) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_OPERATIONAL)); profile_leave(shift_to_prof_); if (pending_leave_ == true) { close(); return; } // proceed to process actual join message } else { log_warn << self_string() << "received join message from new " << "view while in GATHER, dropping"; return; } } gu_trace(shift_to(S_GATHER, false)); } else if (consensus_.is_consistent(*install_message_) == true) { return; // Commented out: It seems to be better strategy to // just wait source of inconsistent join to time out // instead of shifting to gather. #443 // if (consensus_.is_consistent(msg) == true) // { // return; // } // else // { // log_warn << "join message not consistent " << msg; // log_info << "state (stderr): "; // std::cerr << *this << std::endl; // // gu_trace(shift_to(S_GATHER, false)); // } } else { evs_log_info(I_STATE) << "shift to GATHER, install message is " << "inconsistent when handling join from " << msg.source() << " " << msg.source_view_id(); evs_log_info(I_STATE) << "state: " << *this; gu_trace(shift_to(S_GATHER, false)); } } else if (state() != S_GATHER) { evs_log_info(I_STATE) << " shift to GATHER while handling join message from " << msg.source() << " " << msg.source_view_id(); gu_trace(shift_to(S_GATHER, false)); } gcomm_assert(output_.empty() == true); // If source node is member of current view but has already // formed new view, mark it unoperational if (current_view_.is_member(msg.source()) == true && msg.source_view_id().seq() > current_view_.id().seq()) { evs_log_info(I_STATE) << " join source has already formed new view, marking inactive"; set_inactive(msg.source()); return; } // Collect view ids to gather_views_ list. // Add unseen nodes to known list and evicted nodes to evicted list. // Evicted nodes must also be added to known list for GATHER time // bookkeeping. // No need to adjust node state here, it is done later on in // check_suspects()/cross_check_inactives(). for (MessageNodeList::const_iterator i(msg.node_list().begin()); i != msg.node_list().end(); ++i) { NodeMap::iterator ni(known_.find(MessageNodeList::key(i))); const UUID mn_uuid(MessageNodeList::key(i)); const MessageNode& mn(MessageNodeList::value(i)); gather_views_.insert(std::make_pair(mn.view_id(), gu::datetime::Date::now())); if (ni == known_.end()) { known_.insert_unique( std::make_pair(mn_uuid, Node(*this))); } // Evict nodes according to join message if (mn_uuid != uuid() && mn.evicted() == true) { set_inactive(mn_uuid); if (is_evicted(mn_uuid) == false) { evict(mn_uuid); } } } // Timestamp source if it sees processing node as operational. // Adjust local entry operational status. MessageNodeList::const_iterator self(msg.node_list().find(uuid())); if (msg.node_list().end() != self) { if(MessageNodeList::value(self).operational() == true) { inst.set_tstamp(gu::datetime::Date::now()); } else { evs_log_info(I_STATE) << " declaring source " << msg.source() << " as inactive (mutual exclusion)"; set_inactive(msg.source()); } } inst.set_join_message(&msg); // Select nodes that are coming from the same view as seen by // message source MessageNodeList same_view; for_each(msg.node_list().begin(), msg.node_list().end(), SelectNodesOp(same_view, current_view_.id(), true, true)); // Find out self from node list MessageNodeList::const_iterator nlself_i(same_view.find(uuid())); // Other node coming from the same view if (msg.source() != uuid() && msg.source_view_id() == current_view_.id()) { gcomm_assert(nlself_i != same_view.end()); // Update input map state (void)update_im_safe_seqs(same_view); // Find out max hs and complete up to that if needed MessageNodeList::const_iterator max_hs_i( max_element(same_view.begin(), same_view.end(), RangeHsCmp())); const seqno_t max_hs(MessageNodeList::value(max_hs_i).im_range().hs()); if (last_sent_ < max_hs) { gu_trace(complete_user(max_hs)); } } // gu_trace(retrans_user(msg.source(), same_view)); // Retrans leave messages that others are missing gu_trace(retrans_leaves(same_view)); // Make cross check to resolve conflict if two nodes // declare each other inactive. There is no need to make // this for own messages. if (msg.source() != uuid()) { gu_trace(check_suspects(msg.source(), same_view)); gu_trace(cross_check_inactives(msg.source(), same_view)); gu_trace(check_unseen()); gu_trace(check_nil_view_id()); } // Eliminate asymmetry according to operational status flags in // join messages gu_trace(asymmetry_elimination()); // If current join message differs from current state, send new join const JoinMessage* curr_join(NodeMap::value(self_i_).join_message()); MessageNodeList new_nl; populate_node_list(&new_nl); if (curr_join == 0 || (curr_join->aru_seq() != input_map_->aru_seq() || curr_join->seq() != input_map_->safe_seq() || curr_join->node_list() != new_nl)) { gu_trace(create_join()); if (consensus_.is_consensus() == false) { send_join(false); } } if (consensus_.is_consensus() == true) { if (is_representative(uuid()) == true) { gu_trace(send_install(EVS_CALLER)); } } } void gcomm::evs::Proto::handle_leave(const LeaveMessage& msg, NodeMap::iterator ii) { assert(ii != known_.end()); assert(state() != S_CLOSED && state() != S_JOINING); Node& node(NodeMap::value(ii)); evs_log_debug(D_LEAVE_MSGS) << "leave message " << msg; if (msg.source() != uuid() && node.is_inactive() == true) { evs_log_debug(D_LEAVE_MSGS) << "dropping leave from already inactive"; return; } node.set_leave_message(&msg); if (msg.source() == uuid()) { // The last one to live, instant close. Otherwise continue // serving until it becomes apparent that others have // leave message. if (current_view_.members().size() == 1) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_CLOSED)); profile_leave(shift_to_prof_); } } else { // Always set node nonoperational if leave message is seen node.set_operational(false); if (msg.source_view_id() != current_view_.id() || is_msg_from_previous_view(msg) == true) { // Silent drop return; } const seqno_t prev_safe_seq(update_im_safe_seq(node.index(), msg.aru_seq())); if (prev_safe_seq != input_map_->safe_seq(node.index())) { node.set_tstamp(gu::datetime::Date::now()); } if (state() == S_OPERATIONAL) { profile_enter(shift_to_prof_); evs_log_info(I_STATE) << " shift to GATHER when handling leave from " << msg.source() << " " << msg.source_view_id(); gu_trace(shift_to(S_GATHER, true)); profile_leave(shift_to_prof_); } else if (state() == S_GATHER && prev_safe_seq != input_map_->safe_seq(node.index())) { profile_enter(send_join_prof_); gu_trace(send_join()); profile_leave(send_join_prof_); } } } void gcomm::evs::Proto::handle_install(const InstallMessage& msg, NodeMap::iterator ii) { assert(ii != known_.end()); assert(state() != S_CLOSED && state() != S_JOINING); Node& inst(NodeMap::value(ii)); evs_log_debug(D_INSTALL_MSGS) << "install msg " << msg; if (state() == S_LEAVING) { // Check if others have receievd leave message or declared // as unoperational before shifting to closed. MessageNodeList::const_iterator mn_i(msg.node_list().find(uuid())); if (mn_i != msg.node_list().end()) { const MessageNode& mn(MessageNodeList::value(mn_i)); if (mn.operational() == false || mn.leaving() == true) { profile_enter(shift_to_prof_); gu_trace(shift_to(S_CLOSED)); profile_leave(shift_to_prof_); } } return; } else if (state() == S_OPERATIONAL) { // Drop install messages in operational state. evs_log_debug(D_INSTALL_MSGS) << "dropping install message in already installed view"; return; } else if (inst.operational() == false) { // Message source is not seen as operational, must not accept // anything from it. evs_log_debug(D_INSTALL_MSGS) << "install message source " << msg.source() << " is not operational, discarding message"; return; } else if (is_msg_from_previous_view(msg) == true) { // Delayed install message evs_log_debug(D_FOREIGN_MSGS) << " dropping install message from previous view"; return; } else if (install_message_ != 0) { if (msg.source() == install_message_->source() && msg.install_view_id().seq() > install_message_->install_view_id().seq()) { // Representative regenerated install message evs_log_debug(D_INSTALL_MSGS) << "regenerated install message"; setall_committed(false); setall_installed(false); delete install_message_; install_message_ = 0; // Fall through to process new install message } else if (msg.source() == install_message_->source()) { // Duplicate or delayed install message evs_log_debug(D_INSTALL_MSGS) << "duplicate or delayed install message"; return; } else { MessageNodeList::const_iterator self(msg.node_list().find(uuid())); if (msg.node_list().end() == self || MessageNodeList::value(self).operational() == false) { evs_log_debug(D_INSTALL_MSGS) << "dropping install message, processing node not in " << "new view"; } else { // Two nodes decided to generate install message simultaneously, // shift to gather to combine groups in install messages. log_warn << self_string() << " shift to GATHER due to conflicting install " << "messages"; gu_trace(shift_to(S_GATHER)); } return; } } else if (inst.installed() == true) { log_warn << self_string() << " shift to GATHER due to inconsistent state"; profile_enter(shift_to_prof_); gu_trace(shift_to(S_GATHER)); profile_leave(shift_to_prof_); return; } // Construct join from install message so that the most recent // information from representative is updated to local state. if (msg.source() != uuid()) { const MessageNode& mn( MessageNodeList::value( msg.node_list().find_checked(msg.source()))); JoinMessage jm(msg.version(), msg.source(), mn.view_id(), msg.seq(), msg.aru_seq(), msg.fifo_seq(), msg.node_list()); handle_join(jm, ii); } // Drop install message if processing node won't be part of the // view to be installed. // Don't set nodes that are forming another view inactive here, // they should enter new view shortly after install message // delivery and should be ready to restart GATHER round. MessageNodeList::const_iterator self(msg.node_list().find(uuid())); if (msg.node_list().end() == self || MessageNodeList::value(self).operational() == false) { evs_log_debug(D_INSTALL_MSGS) << "dropping install message, processing node not in new view"; return; } // Proceed to install phase assert(install_message_ == 0); // Run through known nodes and remove each entry that is // not member of current view or present in install message. // This is to prevent inconsistent view of group when first message(s) // from new node are received after install message on representative // and before install message on other nodes. bool changed(false); NodeMap::iterator i, i_next; for (NodeMap::iterator i(known_.begin()); i != known_.end(); i = i_next) { i_next = i, ++i_next; const UUID& uuid(NodeMap::key(i)); if (msg.node_list().find(uuid) == msg.node_list().end() && current_view_.members().find(uuid) == current_view_.members().end()) { log_info << self_string() << " temporarily discarding known " << uuid << " due to received install message"; known_.erase(i); changed = true; } } // Recreate join message to match current state, otherwise is_consistent() // below will fail. if (changed == true) { (void)create_join(); } // See if install message is consistent with local state. // Is_consistent() checks only local state and local join // message in case other nodes have already been seen and reported // nodes that will not be in the next view. if (consensus_.is_consistent(msg) == true) { inst.set_tstamp(gu::datetime::Date::now()); install_message_ = new InstallMessage(msg); assert(install_message_->source() != UUID::nil()); assert(install_message_->flags() != 0); profile_enter(send_gap_prof_); // Send commit gap gu_trace(send_gap(EVS_CALLER, UUID::nil(), install_message_->install_view_id(), Range(), true)); profile_leave(send_gap_prof_); } else { evs_log_debug(D_INSTALL_MSGS) << "install message " << msg << " not consistent with state " << *this; profile_enter(shift_to_prof_); gu_trace(shift_to(S_GATHER, true)); profile_leave(shift_to_prof_); } } void gcomm::evs::Proto::handle_delayed_list(const DelayedListMessage& msg, NodeMap::iterator ii) { if (auto_evict_ == 0) { // Ignore evict list messages if auto_evict_ is disabled. return; } Node& node(NodeMap::value(ii)); node.set_delayed_list_message(&msg); gu::datetime::Date now(gu::datetime::Date::now()); // Construct a list of evict candidates that appear in evict list messages // with cnt greater than local auto_evict_. If evict candidate is reported // by majority of the current group, evict process is triggered. // UUID -> over auto_evict_, total count typedef std::map > Evicts; Evicts evicts; bool found(false); for (NodeMap::const_iterator i(known_.begin()); i != known_.end(); ++i) { const DelayedListMessage* const dlm( NodeMap::value(i).delayed_list_message()); if (dlm == 0) { continue; } else if (dlm->delayed_list().find(uuid()) != dlm->delayed_list().end()) { evs_log_debug(D_STATE) << "found self " << uuid() << " from evict list from " << msg.source() << " at " << get_address(msg.source()); continue; } else if (dlm->tstamp() + delayed_keep_period_ < now) { evs_log_debug(D_STATE) << "ignoring expired evict message"; continue; } for (DelayedListMessage::DelayedList::const_iterator dlm_i(dlm->delayed_list().begin()); dlm_i != dlm->delayed_list().end(); ++dlm_i) { if (dlm_i->second <= 1) { // Don't consider entries with single delayed event as // evict candidates. continue; } std::pair eir( evicts.insert( std::make_pair( dlm_i->first, std::make_pair(0, 0)))); evs_log_debug(D_STATE) << "eir " << eir.first->first << " " << eir.first->second.first << " " << eir.first->second.second; ++eir.first->second.second; // total count if (dlm_i->second >= auto_evict_) { ++eir.first->second.first; // over threshold count found = true; } } } // Evict candidates that have reached threshold count for (Evicts::const_iterator i(evicts.begin()); found == true && i != evicts.end(); ++i) { if (is_evicted(i->first) == true) { // Already evicted, avoid spamming continue; } evs_log_info(I_STATE) << "evict candidate " << i->first << " " << i->second.first << " " << i->second.second; // If the candidate is in the current view, require majority // of the view to agree. If the candidate is not in the current // view, require majority of known nodes to agree. Ability to // evict nodes outside of the group (even while in non-PC) is // needed to stabilize cluster also in the case that nodes // have already partitioned. // TODO: Record stable views from PC and use weights from there // accordingly (need to be added to view). if (i->second.first != 0 && ((current_view_.is_member(i->first) && i->second.second > current_view_.members().size()/2) || i->second.second > known_.size()/2)) { log_warn << "evicting member " << i->first << " at " << get_address(i->first) << " permanently from group"; evict(i->first); if (state() == S_OPERATIONAL) { shift_to(S_GATHER, true); } } } } percona-galera-3-3.8-3390/gcomm/src/evs_proto.hpp000066400000000000000000000411551244131713600214320ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ /*! * @file evs_proto.hpp * * @brief EVS protocol implementation header. */ #ifndef GCOMM_EVS_PROTO_HPP #define GCOMM_EVS_PROTO_HPP #include "gcomm/protolay.hpp" #include "gcomm/view.hpp" #include "gcomm/transport.hpp" #include "gcomm/map.hpp" #include "gu_histogram.hpp" #include "gu_stats.hpp" #include "profile.hpp" #include "evs_seqno.hpp" #include "evs_node.hpp" #include "evs_consensus.hpp" #include "protocol_version.hpp" #include "gu_datetime.hpp" #include #include #include #include namespace gcomm { namespace evs { class Message; class MessageNodeList; class UserMessage; class DelegateMessage; class GapMessage; class JoinMessage; class InstallMessage; class LeaveMessage; class InputMap; class InputMapMsg; class Proto; std::ostream& operator<<(std::ostream&, const Proto&); // // Helper class for getting the location where // certain methods are called from. // // Example usage: // Method prototype: // void fun(EVS_CALLER_ARG, int a) // // Calling: // fun(EVS_CALLER, a) // // Logging inside function: // log_debug << EVS_LOG_METHOD << "log message" // class Caller { public: Caller(const char* const file, const int line) : file_(file), line_(line) { } friend std::ostream& operator<<(std::ostream&, const Caller&); private: const char* const file_; const int line_; }; inline std::ostream& operator<<(std::ostream& os, const Caller& caller) { return (os << caller.file_ << ": " << caller.line_ << ": "); } #define EVS_CALLER_ARG const Caller& caller #define EVS_CALLER Caller(__FILE__, __LINE__) #define EVS_LOG_METHOD __FUNCTION__ << " called from " << caller } } /*! * @brief Class implementing EVS protocol */ class gcomm::evs::Proto : public Protolay { public: enum State { S_CLOSED, S_JOINING, S_LEAVING, S_GATHER, S_INSTALL, S_OPERATIONAL, S_MAX }; static std::string to_string(const State s) { switch (s) { case S_CLOSED: return "CLOSED"; case S_JOINING: return "JOINING"; case S_LEAVING: return "LEAVING"; case S_GATHER: return "GATHER"; case S_INSTALL: return "INSTALL"; case S_OPERATIONAL: return "OPERATIONAL"; default: gu_throw_fatal << "Invalid state"; } } friend std::ostream& operator<<(std::ostream&, const Proto&); friend class Consensus; /*! * Default constructor. */ Proto(gu::Config& conf, const UUID& my_uuid, SegmentId segment, const gu::URI& uri = gu::URI("evs://"), const size_t mtu = std::numeric_limits::max(), const View* rst_view = NULL); ~Proto(); const UUID& uuid() const { return my_uuid_; } std::string self_string() const { std::ostringstream os; os << "evs::proto(" << uuid() << ", " << to_string(state()) << ", " << current_view_.id() << ")"; return os.str(); } State state() const { return state_; } size_t known_size() const { return known_.size(); } bool is_output_empty() const { return output_.empty(); } std::string stats() const; void reset_stats(); bool is_flow_control(const seqno_t, const seqno_t win) const; int send_user(Datagram&, uint8_t, Order, seqno_t, seqno_t, size_t n_aggregated = 1); size_t mtu() const { return mtu_; } size_t aggregate_len() const; int send_user(const seqno_t); void complete_user(const seqno_t); int send_delegate(Datagram&); void send_gap(EVS_CALLER_ARG, const UUID&, const ViewId&, const Range, bool commit = false, bool req_all = false); const JoinMessage& create_join(); void send_join(bool tval = true); void set_join(const JoinMessage&, const UUID&); void set_leave(const LeaveMessage&, const UUID&); void send_leave(bool handle = true); void send_install(EVS_CALLER_ARG); void send_delayed_list(); void resend(const UUID&, const Range); void recover(const UUID&, const UUID&, const Range); void retrans_user(const UUID&, const MessageNodeList&); void retrans_leaves(const MessageNodeList&); void set_inactive(const UUID&); bool is_inactive(const UUID&) const; void check_inactive(); // Clean up foreign nodes according to install message. void cleanup_foreign(const InstallMessage&); void cleanup_views(); void cleanup_evicted(); void cleanup_joins(); size_t n_operational() const; void validate_reg_msg(const UserMessage&); void deliver_finish(const InputMapMsg&); void deliver(); void deliver_local(bool trans = false); void deliver_causal(uint8_t user_type, seqno_t seqno, const Datagram&); void validate_trans_msg(const UserMessage&); void deliver_trans(); void deliver_reg_view(const InstallMessage&, const View&); void deliver_trans_view(const InstallMessage&, const View&); void deliver_empty_view(); void setall_committed(bool val); bool is_all_committed() const; void setall_installed(bool val); bool is_all_installed() const; bool is_install_message() const { return install_message_ != 0; } bool is_representative(const UUID& pid) const; void shift_to(const State, const bool send_j = true); bool is_all_suspected(const UUID& uuid) const; const View& current_view() const { return current_view_; } // Message handlers private: /*! * Update input map safe seq * @param uuid Node uuid * @param seq Sequence number * @return Input map seqno before updating */ seqno_t update_im_safe_seq(const size_t uuid, const seqno_t seq); /*! * Update input map safe seqs according to message node list. Only * inactive nodes are allowed to be in */ bool update_im_safe_seqs(const MessageNodeList&); bool is_msg_from_previous_view(const Message&); void check_suspects(const UUID&, const MessageNodeList&); void cross_check_inactives(const UUID&, const MessageNodeList&); void check_unseen(); void check_nil_view_id(); void asymmetry_elimination(); void handle_foreign(const Message&); void handle_user(const UserMessage&, NodeMap::iterator, const Datagram&); void handle_delegate(const DelegateMessage&, NodeMap::iterator, const Datagram&); void handle_gap(const GapMessage&, NodeMap::iterator); void handle_join(const JoinMessage&, NodeMap::iterator); void handle_leave(const LeaveMessage&, NodeMap::iterator); void handle_install(const InstallMessage&, NodeMap::iterator); void handle_delayed_list(const DelayedListMessage&, NodeMap::iterator); void populate_node_list(MessageNodeList*) const; void isolate(gu::datetime::Period period); public: static size_t unserialize_message(const UUID&, const Datagram&, Message*); void handle_msg(const Message& msg, const Datagram& dg = Datagram(), bool direct = true); // Protolay void handle_up(const void*, const Datagram&, const ProtoUpMeta&); int handle_down(Datagram& wb, const ProtoDownMeta& dm); int send_down(Datagram& dg, const ProtoDownMeta& dm); void handle_stable_view(const View& view) { set_stable_view(view); } void handle_fencing(const UUID& uuid) { } void connect(bool first) { gu_trace(shift_to(S_JOINING)); gu_trace(send_join(first)); } void close(bool force = false) { // shifting to S_LEAVING from S_INSTALL is troublesome, // instead of that raise a boolean flag to indicate that // shifting to S_LEAVING should be done once S_OPERATIONAL // is reached // // #760 - pending leave should be done also from S_GATHER, // changing state to S_LEAVING resets timers and may prevent // remaining nodes to reach new group until install timer // times out log_debug << self_string() << " closing in state " << state(); if (state() != S_GATHER && state() != S_INSTALL) { gu_trace(shift_to(S_LEAVING)); gu_trace(send_leave()); pending_leave_ = false; } else { pending_leave_ = true; } } void close(const UUID& uuid) { set_inactive(uuid); } bool set_param(const std::string& key, const std::string& val); void handle_get_status(gu::Status& status) const; // gu::datetime::Date functions do appropriate actions for timer handling // and return next expiration time private: public: enum Timer { T_INACTIVITY, T_RETRANS, T_INSTALL, T_STATS }; /*! * Internal timer list */ typedef MultiMap TimerList; private: TimerList timers_; public: // These need currently to be public for unit tests void handle_inactivity_timer(); void handle_retrans_timer(); void handle_install_timer(); void handle_stats_timer(); gu::datetime::Date next_expiration(const Timer) const; void reset_timer(Timer); void cancel_timer(Timer); gu::datetime::Date handle_timers(); /*! * @brief Flags controlling what debug information is logged if * debug logging is turned on. */ enum DebugFlags { D_STATE = 1 << 0, /*!< State changes */ D_TIMERS = 1 << 1, /*!< Timer handling */ D_CONSENSUS = 1 << 2, /*!< Consensus protocol */ D_USER_MSGS = 1 << 3, /*!< User messages */ D_DELEGATE_MSGS = 1 << 4, /*!< Delegate messages */ D_GAP_MSGS = 1 << 5, /*!< Gap messages */ D_JOIN_MSGS = 1 << 6, /*!< Join messages */ D_INSTALL_MSGS = 1 << 7, /*!< Install messages */ D_LEAVE_MSGS = 1 << 8, /*!< Leave messages */ D_FOREIGN_MSGS = 1 << 9, /*!< Foreing messages */ D_RETRANS = 1 << 10, /*!< Retransmitted/recovered messages */ D_DELIVERY = 1 << 11 /*!< Message delivery */ }; /*! * @brief Flags controlling what info log is printed in logs. */ enum InfoFlags { I_VIEWS = 1 << 0, /*!< View changes */ I_STATE = 1 << 1, /*!< State change information */ I_STATISTICS = 1 << 2, /*!< Statistics */ I_PROFILING = 1 << 3 /*!< Profiling information */ }; private: int version_; int debug_mask_; int info_mask_; gu::datetime::Date last_stats_report_; bool collect_stats_; gu::Histogram hs_agreed_; gu::Histogram hs_safe_; gu::Histogram hs_local_causal_; gu::Stats safe_deliv_latency_; long long int send_queue_s_; long long int n_send_queue_s_; std::vector sent_msgs_; long long int retrans_msgs_; long long int recovered_msgs_; std::vector recvd_msgs_; std::vector delivered_msgs_; prof::Profile send_user_prof_; prof::Profile send_gap_prof_; prof::Profile send_join_prof_; prof::Profile send_install_prof_; prof::Profile send_leave_prof_; prof::Profile consistent_prof_; prof::Profile consensus_prof_; prof::Profile shift_to_prof_; prof::Profile input_map_prof_; prof::Profile delivery_prof_; bool delivering_; UUID my_uuid_; SegmentId segment_; // // Known instances friend class Node; friend class InspectNode; NodeMap known_; NodeMap::iterator self_i_; // gu::datetime::Period view_forget_timeout_; gu::datetime::Period inactive_timeout_; gu::datetime::Period suspect_timeout_; gu::datetime::Period inactive_check_period_; gu::datetime::Period retrans_period_; gu::datetime::Period install_timeout_; gu::datetime::Period join_retrans_period_; gu::datetime::Period stats_report_period_; gu::datetime::Period causal_keepalive_period_; gu::datetime::Period delay_margin_; gu::datetime::Period delayed_keep_period_; gu::datetime::Date last_inactive_check_; gu::datetime::Date last_causal_keepalive_; // Current view id // ViewId current_view; View current_view_; View previous_view_; typedef std::map ViewList; // List of previously seen views from which messages should not be // accepted anymore ViewList previous_views_; // Seen views in gather state, will be copied to previous views // when shifting to operational ViewList gather_views_; // Map containing received messages and aru/safe seqnos InputMap* input_map_; // Helper container for local causal messages class CausalMessage { public: CausalMessage(uint8_t user_type, seqno_t seqno, const Datagram& datagram) : user_type_(user_type), seqno_ (seqno ), datagram_ (datagram ), tstamp_ (gu::datetime::Date::now()) { } uint8_t user_type() const { return user_type_; } seqno_t seqno() const { return seqno_ ; } const Datagram& datagram() const { return datagram_ ; } const gu::datetime::Date& tstamp() const { return tstamp_ ; } private: uint8_t user_type_; seqno_t seqno_; Datagram datagram_; gu::datetime::Date tstamp_; }; // Queue containing local causal messages std::deque causal_queue_; // Consensus module Consensus consensus_; // Last received install message InstallMessage* install_message_; // Highest seen view id seqno uint32_t max_view_id_seq_; // Install attempt counter uint32_t attempt_seq_; // Install timeout counting int max_install_timeouts_; int install_timeout_count_; // Sequence number to maintain membership message FIFO order int64_t fifo_seq_; // Last sent seq seqno_t last_sent_; // Protocol send window size seqno_t send_window_; // User send window size seqno_t user_send_window_; // Output message queue std::deque > output_; std::vector send_buf_; uint32_t max_output_size_; size_t mtu_; bool use_aggregate_; bool self_loopback_; State state_; int shift_to_rfcnt_; bool pending_leave_; gu::datetime::Date isolation_end_; class DelayedEntry { public: typedef enum { S_OK, S_DELAYED } State; DelayedEntry(const std::string& addr) : addr_ (addr), tstamp_(gu::datetime::Date::now()), state_(S_DELAYED), state_change_cnt_(1) { } const std::string& addr() const { return addr_; } void set_tstamp(gu::datetime::Date tstamp) { tstamp_ = tstamp; } gu::datetime::Date tstamp() const { return tstamp_; } void set_state(State state, const gu::datetime::Period decay_period, const gu::datetime::Date now) { if (state == S_DELAYED && state_ != state) { // Limit to 0xff, see DelayedList format in DelayedListMessage // restricts this value to uint8_t max. if (state_change_cnt_ < 0xff) ++state_change_cnt_; } else if (state == S_OK && tstamp_ + decay_period < now) { if (state_change_cnt_ > 0) --state_change_cnt_; } state_ = state; } State state() const {return state_; } size_t state_change_cnt() const { return state_change_cnt_; } private: const std::string addr_; gu::datetime::Date tstamp_; State state_; size_t state_change_cnt_; }; typedef std::map DelayedList; DelayedList delayed_list_; size_t auto_evict_; // non-copyable Proto(const Proto&); void operator=(const Proto&); }; #endif // EVS_PROTO_HPP percona-galera-3-3.8-3390/gcomm/src/evs_seqno.hpp000066400000000000000000000032501244131713600214060ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #ifndef EVS_SEQNO_HPP #define EVS_SEQNO_HPP #include "gcomm/types.hpp" #include "gu_serialize.hpp" //#include // for uint16_t #include #include namespace gcomm { namespace evs { typedef int64_t seqno_t; class Range; std::ostream& operator<<(std::ostream&, const Range&); } } /*! * */ class gcomm::evs::Range { public: Range(const seqno_t lu = -1, const seqno_t hs = -1) : lu_(lu), hs_(hs) {} seqno_t lu() const { return lu_; } seqno_t hs() const { return hs_; } void set_lu(const seqno_t s) { lu_ = s; } void set_hs(const seqno_t s) { hs_ = s; } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const { gu_trace(offset = gu::serialize8(lu_, buf, buflen, offset)); gu_trace(offset = gu::serialize8(hs_, buf, buflen, offset)); return offset; } size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) { gu_trace(offset = gu::unserialize8(buf, buflen, offset, lu_)); gu_trace(offset = gu::unserialize8(buf, buflen, offset, hs_)); return offset; } static size_t serial_size() { return 2 * sizeof(seqno_t); } bool operator==(const Range& cmp) const { return (lu_ == cmp.lu_ && hs_ == cmp.hs_); } private: seqno_t lu_; /*!< Lowest unseen seqno */ seqno_t hs_; /*!< Highest seen seqno */ }; inline std::ostream& gcomm::evs::operator<<(std::ostream& os, const gcomm::evs::Range& r) { return (os << "[" << r.lu() << "," << r.hs() << "]"); } #endif // EVS_SEQNO_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/000077500000000000000000000000001244131713600177755ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcomm/src/gcomm/common.hpp000066400000000000000000000016621244131713600220030ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ /*! * @file common.hpp * * @brief Imports definitions from the global common.h */ #ifndef GCOMM_COMMON_HPP #define GCOMM_COMMON_HPP #if defined(HAVE_COMMON_H) #include #endif #include namespace gcomm { #if defined(HAVE_COMMON_H) static std::string const TCP_SCHEME(COMMON_TCP_SCHEME); static std::string const UDP_SCHEME(COMMON_UDP_SCHEME); static std::string const SSL_SCHEME(COMMON_SSL_SCHEME); static std::string const BASE_PORT_KEY(COMMON_BASE_PORT_KEY); static std::string const BASE_PORT_DEFAULT(COMMON_BASE_PORT_DEFAULT); #else static std::string const TCP_SCHEME("tcp"); static std::string const UDP_SCHEME("udp"); static std::string const SSL_SCHEME("ssl"); static std::string const BASE_PORT_KEY("base_port"); static std::string const BASE_PORT_DEFAULT("4567"); #endif } #endif /* GCOMM_COMMON_HPP */ percona-galera-3-3.8-3390/gcomm/src/gcomm/conf.hpp000066400000000000000000000472671244131713600214530ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ /*! * @file conf.hpp * * @brief Configuration parameters and utility templates. */ #ifndef GCOMM_CONF_HPP #define GCOMM_CONF_HPP #include "gu_config.hpp" #include "gu_uri.hpp" #include "gu_throw.hpp" namespace gcomm { /*! * Configuration parameter definitions. * * Transport definition and configuration parameters are passed to * Transport::create() in the URI form. URI scheme part defines * which transport is returned. Currently recognized are "tcp", "gmcast" * and "pc". This will change in the future. * * URI format is the following: * gcomm://[[:]][?=&=]... * The key/value pairs can be used to pass configuration parameters to * gcomm layers. * * Time periods as parameter values follow ISO8601 duration representation * (as represented in http://en.wikipedia.org/wiki/ISO_8601#Durations). * Examples: * - PT1S - one second * - PT1M30S = one minute 30 secs * - P1DT6H = one day, 6 hours * * To get subsecond resolution, second part can be represented as decimal * number, but currently it is not recommended due to bug in Period * parsing routine (rounding errors can result inaccurate boundary * value checking). */ struct Conf { static std::string const ProtonetBackend; static std::string const ProtonetVersion; /*! * @brief TCP non-blocking flag ("socket.non_blocking") * * Parameter value is boolean (passed 0 or 1) denoting whether * the socket should or should not be in non-blocking state. */ static std::string const TcpNonBlocking; /*! * @brief Use SSL sockets for communication * * Boolean describing whether underlying transport should use SSL * connections. */ static std::string const SocketUseSsl; /*! * @brief File containing CA certificates in PEM format * ("socket.ssl_verify_file") */ static std::string const SocketSslVerifyFile; /*! * @brief File containing certificate to use in PEM format * ("socket.ssl_certificate_file") */ static std::string const SocketSslCertificateFile; /*! * @brief File containing private key associated with certificate * ("socket.ssl_private_key_file") * * If private key file is protected with password, * SocketSslPasswordFile ("socket.ssl_password_file") must also be set. */ static std::string const SocketSslPrivateKeyFile; /*! * @brief File containing password used to protect private key file * ("socket.ssl_password_file") */ static std::string const SocketSslPasswordFile; /*! * @brief Cipher list for SSL connections (socket.ssl_cipher_list) */ static std::string const SocketSslCipherList; /*! * @brief Disable compression boolean (socket.ssl_disable_compression) */ static std::string const SocketSslCompression; /*! * @brief Algorithm for message checksums: * 0 - none (backward compatible) * 1 - CRC-32 (backward compatible) * 2 - CRC-32C (optimized and potentially HW-accelerated on Intel CPUs) */ static std::string const SocketChecksum; /*! * @brief GMCast scheme for transport URI ("gmcast") */ static std::string const GMCastScheme; /*! * @brief GMCast protocol version */ static std::string const GMCastVersion; /*! * @brief GMCast group name ("gmcast.group") * * String denoting group name. Max length of string is 16. Peer nodes * accept GMCast connection only if the group names match. */ static std::string const GMCastGroup; /*! * @brief GMCast listening address ("gmcast.listen_addr") * * Listening address for GMCast. Address is currently passed in * URI format (for example tcp://192.168.3.1:4567) and it should * be passed as the last configuration parameter in order to * avoid confusion. If parameter value is undefined, GMCast * starts listening all interfaces at default port 4567. */ static std::string const GMCastListenAddr; /*! * @brief GMCast multicast address ("gmcast.mcast_addr") * * Multicast address for GMCast. By default multicast socket * is bound to the same interface as conf::GMCastListenAddr. * If multicast interface must be specified, the only way * to do it is currently via listening address configuration. */ static std::string const GMCastMCastAddr; /*! * @brief GMCast multicast port ("gmcast.mcast_port") * * Multicast port for GMCast. By default multicast uses the * same port as GMCast TCP connections. */ static std::string const GMCastMCastPort; /*! * @brief GMCast multicast TTL ("gmcast.mcast_ttl") * * This parameter controls multicast packet TTL. By default it * is set to 1 and usually it should not be changed unless * adviced so. This means that multicast is limited to single LAN * segment. */ static std::string const GMCastMCastTTL; static std::string const GMCastTimeWait; static std::string const GMCastPeerTimeout; /*! * @brief Maximum initial reconnect attempts * * Maximum initial reconnect attempts for address reported by peer. */ static std::string const GMCastMaxInitialReconnectAttempts; /*! * @brief Add or remove peer address. * * Setting value to add:://: will inject new peer * address in address list. Setting value to del:://: * will remove peer address from list (via forget procedure). */ static std::string const GMCastPeerAddr; /*! * @brief Isolate node from peers * * Setting this value to 'true' closes all conections * and will prevent forming of new connections until * value is set again to 'false'. This parameter should be * used for testing purposes only and it will not be visible * in global configuration array. */ static std::string const GMCastIsolate; /*! * @brief Segment identifier for segmentation. */ static std::string const GMCastSegment; /*! * @brief EVS scheme for transport URI ("evs") */ static std::string const EvsScheme; /*! * @brief EVS protocol version */ static std::string const EvsVersion; /*! * @brief EVS view forget timeout ("evs.view_forget_timeout") * * This timeout controls how long information about * known group views is maintained. This information is needed * to filter out delayed messages from previous views that are not * live anymore. Default value is 5 minutes and there is usually not * need to change it. */ static std::string const EvsViewForgetTimeout; /*! * @brief EVS suspect timeout ("evs.suspect_timeout") * * This timeout controls how long node can remain silent until * it is put under suspicion. If majority of the current group * agree that the node is under suspicion, it is discarded from * group and new group view is formed immediately. If majority * of the group does not agree about suspicion, Conf::EvsInactiveTimeout * is waited until forming of new group will be attempted. * Default value is 5 seconds. */ static std::string const EvsSuspectTimeout; /*! * @brief EVS inactive timeout ("evs.inactive_timeout") * * This timeout control how long node can remain completely silent * until it is discarded from the group. This is hard limit, unlike * Conf::EvsSuspectTimeout, and the node is discarded even if it * becomes live during the formation of the new group. Default value * is 15 seconds. */ static std::string const EvsInactiveTimeout; /*! * @brief EVS inactive check period ("evs.inactive_check_period") * * This period controls how often node liveness is checked. Default * is 1 second and there is no need to change this unless * Conf::EvsSuspectTimeout or Conf::EvsInactiveTimeout is adjusted * to smaller value. Default value is 1 second, minimum is 0.1 seconds * and maximum is Conf::EvsSuspectTimeout/2. */ static std::string const EvsInactiveCheckPeriod; static std::string const EvsInstallTimeout; /*! * @brief EVS keepalive period ("evs.keepalive_period") * * This timeout controls how often keepalive messages are * sent into network. Node liveness is determined with * these keepalives, so the value sould be significantly smaller * than Conf::EvsSuspectTimeout. Default value is 1 second, * minimum is 0.1 seconds and maximum is Conf::EvsSuspectTimeout/3. */ static std::string const EvsKeepalivePeriod; /*! * @brief EVS join retransmission period ("evs.join_retrans_period") * * This parameter controls how often join messages are retransmitted * during group formation. There is usually no need to adjust * this value. Default value is 0.3 seconds, minimum is 0.1 seconds * and maximum is Conf::EvsSuspectTimeout/3. */ static std::string const EvsJoinRetransPeriod; /*! * @brief EVS statistics reporting period ("evs.stats_report_period") * * This parameters controls how often statistics information is * printed in the log. This parameter has effect only if * statistics reporting is enabled via Conf::EvsInfoLogMask. Default * value is 1 minute. */ static std::string const EvsStatsReportPeriod; /*! * @brief EVS debug log mask ("evs.debug_log_mask") * * This mask controls what debug information is printed in the logs * if debug logging is turned on. Mask value is bitwise-or * from values gcomm::evs::Proto::DebugFlags. By default only * state information is printed. */ static std::string const EvsDebugLogMask; /*! * @brief EVS info log mask ("evs.info_log_mask") * * This mask controls what info log is printed in the logs. * Mask value is bitwise-or from values gcomm::evs::Proto::InfoFlags. */ static std::string const EvsInfoLogMask; /*! * @brief EVS send window ("evs.send_window") * * This parameter controls how many messages protocol layer is * allowed to send without getting all acknowledgements for any of them. * Default value is 32. */ static std::string const EvsSendWindow; /*! * @brief EVS user send window ("evs.user_send_window") * * Like Conf::EvsSendWindow, but for messages for which sending * is initiated by call from upper layer. Default value is 16. */ static std::string const EvsUserSendWindow; /*! * @brief EVS message aggregation mode ("evs.use_aggregate") * * This parameter controls whether EVS is allowed to aggregate * several user messages into one message. By default this option * is enabled and there should be no need to disable it unless * adviced so. */ static std::string const EvsUseAggregate; /*! * @brief Period to generate keepalives for causal messages * */ static std::string const EvsCausalKeepalivePeriod; /*! * @brief EVS maximum install timeouts ("evs.max_install_timeouts") * * This parameter controls how many install attempts are done * before declaring other nodes as inactive and trying to re-establish * group via singleton views. */ static std::string const EvsMaxInstallTimeouts; /*! * @brief Margin over keepalive period after which node is declared * delayed. This should be greater than the largest RTT * between cluster nodes. */ static std::string const EvsDelayMargin; /*! * @brief Period which determines how long delayed node is kept in * delayed list after it becomes responsive again. * * The actual time that node stays in delayed list is * EvsDelayedKeepPeriod times the number of changes between * OK and DELAYED state. */ static std::string const EvsDelayedKeepPeriod; /*! * @brief List of nodes (UUIDs) that should be evicted permanently from * cluster. * * Setting value to nil UUID will clear the evict list. */ static std::string const EvsEvict; /*! * @brief Autoevict threshold. */ static std::string const EvsAutoEvict; /*! * @brief PC scheme for transport URI ("pc") */ static std::string const PcScheme; /*! * @brief PC protocol version */ static std::string const PcVersion; /*! * @brief PC split-brain mode * * This parameter controls whether PC is allowed to continue * operation despite of possible split brain condition. */ static std::string const PcIgnoreSb; /*! * @brief PC quorum mode * * This parameter controls whether PC is allowed to continue * operation despite of quorum loss. */ static std::string const PcIgnoreQuorum; /*! * @brief PC message checksumming * * This parameter controls whether PC layer does message * checksumming. */ static std::string const PcChecksum; /*! * @brief PC starup announce timeout */ static std::string const PcAnnounceTimeout; /*! * @brief PC close linger timeout */ static std::string const PcLinger; /*! * @brief PC newer prim view overrides */ static std::string const PcNpvo; /*! * @brief If set during runtime bootstraps new PC */ static std::string const PcBootstrap; /*! * @brief Wait for prim comp unconditionally if set to true */ static std::string const PcWaitPrim; /*! * @brief Timeout on waiting for primary component */ static std::string const PcWaitPrimTimeout; /*! * @brief Node weight in prim comp voting */ static std::string const PcWeight; /*! * @brief PC recovery from cluster crash */ static std::string const PcRecovery; static void register_params(gu::Config&); }; // Helper templates to read configuration parameters. template T _conf_param(const gu::URI& uri, const std::string& param, const T* default_value = 0, const T* min_value = 0, const T* max_value = 0) { T ret; try { ret = gu::from_string(uri.get_option(param)); } catch (gu::NotFound& e) { // cppcheck-suppress nullPointer if (default_value == 0) { gu_throw_error(EINVAL) << "param " << param << " not found from uri " << uri.to_string(); } // cppcheck-suppress nullPointer ret = *default_value; } if (min_value != 0 && *min_value > ret) { gu_throw_error(EINVAL) << "param " << param << " value " << ret << " out of range " << "min allowed " << *min_value; } if (max_value != 0 && *max_value < ret) { gu_throw_error(EINVAL) << "param " << param << " value " << ret << " out of range " << "max allowed " << *max_value; } return ret; } template T conf_param(const gu::URI& uri, const std::string& param) { return _conf_param(uri, param, 0, 0, 0); } template T conf_param_def(const gu::URI& uri, const std::string& param, const T& default_value) { return _conf_param(uri, param, &default_value); } template T conf_param_range(const gu::URI& uri, const std::string& param, const T& min_value, const T& max_value) { return _conf_param(uri, param, 0, &min_value, &max_value); } template T conf_param_def_min(const gu::URI& uri, const std::string& param, const T& default_value, const T& min_value) { return _conf_param(uri, param, &default_value, &min_value); } template T conf_param_def_max(const gu::URI& uri, const std::string& param, const T& default_value, const T& max_value) { return _conf_param(uri, param, &default_value, reinterpret_cast(0), &max_value); } template T conf_param_def_range(const gu::URI& uri, const std::string& param, const T& default_value, const T& min_value, const T& max_value) { return _conf_param(uri, param, &default_value, &min_value, &max_value); } template T param(gu::Config& conf, const gu::URI& uri, const std::string& key, const std::string& def, std::ios_base& (*f)(std::ios_base&) = std::dec) { std::string ret(def); ret = conf.get(key, ret); return gu::from_string(uri.get_option(key, ret), f); } template T check_range(const std::string& key, const T& val, const T& min, const T& max) { if (val < min || val >= max) { gu_throw_error(ERANGE) << "param '" << key << "' value " << val << " out of range [" << min << "," << max << ")"; } return val; } } // namespace gcomm #endif // GCOMM_CONF_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/datagram.hpp000066400000000000000000000206651244131713600222770ustar00rootroot00000000000000/* * Copyright (C) 2010-2013 Codership Oy */ #ifndef GCOMM_DATAGRAM_HPP #define GCOMM_DATAGRAM_HPP #include "gu_buffer.hpp" #include "gu_serialize.hpp" #include "gu_utils.hpp" #include #include #include namespace gcomm { //! // @class NetHeader // // @brief Header for datagrams sent over network // // Header structure is the following (MSB first) // // | version(4) | reserved(2) | F_CRC(2) | len(24) | // | CRC(32) | // class NetHeader { public: typedef enum checksum { CS_NONE = 0, CS_CRC32, CS_CRC32C } checksum_t; static checksum_t checksum_type (int i); NetHeader() : len_(), crc32_() { } NetHeader(uint32_t len, int version) : len_(len), crc32_(0) { if (len > len_mask_) gu_throw_error(EINVAL) << "msg too long " << len_; len_ |= (static_cast(version) << version_shift_); } uint32_t len() const { return (len_ & len_mask_); } void set_crc32(uint32_t crc32, checksum_t type) { assert (CS_CRC32 == type || CS_CRC32C == type); crc32_ = crc32; CS_CRC32 == type ? len_ |= F_CRC32 : len_ |= F_CRC32C; } bool has_crc32() const { return (len_ & F_CRC32); } bool has_crc32c() const { return (len_ & F_CRC32C); } uint32_t crc32() const { return crc32_; } int version() const { return ((len_ & version_mask_) >> version_shift_); } friend size_t serialize(const NetHeader& hdr, gu::byte_t* buf, size_t buflen, size_t offset); friend size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, NetHeader& hdr); friend size_t serial_size(const NetHeader& hdr); static const size_t serial_size_ = 8; private: static const uint32_t len_mask_ = 0x00ffffff; static const uint32_t flags_mask_ = 0x0f000000; static const uint32_t flags_shift_ = 24; static const uint32_t version_mask_ = 0xf0000000; static const uint32_t version_shift_ = 28; enum { F_CRC32 = 1 << 24, /* backward compatible */ F_CRC32C = 1 << 25 }; uint32_t len_; uint32_t crc32_; }; inline size_t serialize(const NetHeader& hdr, gu::byte_t* buf, size_t buflen, size_t offset) { offset = gu::serialize4(hdr.len_, buf, buflen, offset); offset = gu::serialize4(hdr.crc32_, buf, buflen, offset); return offset; } inline size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset, NetHeader& hdr) { offset = gu::unserialize4(buf, buflen, offset, hdr.len_); offset = gu::unserialize4(buf, buflen, offset, hdr.crc32_); switch (hdr.version()) { case 0: if ((hdr.len_ & NetHeader::flags_mask_) & ~(NetHeader::F_CRC32 | NetHeader::F_CRC32C)) { gu_throw_error(EPROTO) << "invalid flags " << ((hdr.len_ & NetHeader::flags_mask_) >> NetHeader::flags_shift_); } break; default: gu_throw_error(EPROTO) << "invalid protocol version " << hdr.version(); } return offset; } inline size_t serial_size(const NetHeader& hdr) { return NetHeader::serial_size_; } /*! * @brief Datagram container * * Datagram class provides consistent interface for managing * datagrams/byte buffers. */ class Datagram { public: Datagram() : header_ (), header_offset_(header_size_), payload_ (new gu::Buffer()), offset_ (0) { } /*! * @brief Construct new datagram from byte buffer * * @param[in] buf Const pointer to data buffer * @param[in] buflen Length of data buffer * * @throws std::bad_alloc */ Datagram(const gu::Buffer& buf, size_t offset = 0) : header_ (), header_offset_(header_size_), payload_ (new gu::Buffer(buf)), offset_ (offset) { assert(offset_ <= payload_->size()); } Datagram(const gu::SharedBuffer& buf, size_t offset = 0) : header_ (), header_offset_(header_size_), payload_ (buf), offset_ (offset) { assert(offset_ <= payload_->size()); } /*! * @brief Copy constructor. * * @note Only for normalized datagrams. * * @param[in] dgram Datagram to make copy from * @param[in] off * @throws std::bad_alloc */ Datagram(const Datagram& dgram, size_t off = std::numeric_limits::max()) : // header_(dgram.header_), header_offset_(dgram.header_offset_), payload_(dgram.payload_), offset_(off == std::numeric_limits::max() ? dgram.offset_ : off) { assert(offset_ <= dgram.len()); memcpy(header_ + header_offset_, dgram.header_ + dgram.header_offset(), dgram.header_len()); } /*! * @brief Destruct datagram */ ~Datagram() { } void normalize() { const gu::SharedBuffer old_payload(payload_); payload_ = gu::SharedBuffer(new gu::Buffer); payload_->reserve(header_len() + old_payload->size() - offset_); if (header_len() > offset_) { payload_->insert(payload_->end(), header_ + header_offset_ + offset_, header_ + header_size_); offset_ = 0; } else { offset_ -= header_len(); } header_offset_ = header_size_; payload_->insert(payload_->end(), old_payload->begin() + offset_, old_payload->end()); offset_ = 0; } gu::byte_t* header() { return header_; } const gu::byte_t* header() const { return header_; } size_t header_size() const { return header_size_; } size_t header_len() const { return (header_size_ - header_offset_); } size_t header_offset() const { return header_offset_; } void set_header_offset(const size_t off) { // assert(off <= header_size_); if (off > header_size_) gu_throw_fatal << "out of hdrspace"; header_offset_ = off; } const gu::Buffer& payload() const { assert(payload_ != 0); return *payload_; } gu::Buffer& payload() { assert(payload_ != 0); return *payload_; } size_t len() const { return (header_size_ - header_offset_ + payload_->size()); } size_t offset() const { return offset_; } private: friend uint16_t crc16(const Datagram&, size_t); friend uint32_t crc32(NetHeader::checksum_t, const Datagram&, size_t); static const size_t header_size_ = 128; gu::byte_t header_[header_size_]; size_t header_offset_; gu::SharedBuffer payload_; size_t offset_; }; uint16_t crc16(const Datagram& dg, size_t offset = 0); uint32_t crc32(NetHeader::checksum_t type, const Datagram& dg, size_t offset = 0); /* returns true if checksum fails */ inline bool check_cs (const NetHeader& hdr, const Datagram& dg) { if (hdr.has_crc32c()) return (crc32(NetHeader::CS_CRC32C, dg) != hdr.crc32()); if (hdr.has_crc32()) return (crc32(NetHeader::CS_CRC32, dg) != hdr.crc32()); return (hdr.crc32() != 0); } } /* namespace gcomm */ #endif // GCOMM_DATAGRAM_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/exception.hpp000066400000000000000000000010661244131713600225070ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ /*! * @file exception.hpp * * @brief GComm exception definitions. */ #ifndef GCOMM_EXCEPTION_HPP #define GCOMM_EXCEPTION_HPP #include "gu_throw.hpp" /*! * Assert macro for runtime condition checking. This should be used * for conditions that may depend on external input and are required * to validate correct protocol operation. */ #define gcomm_assert(cond_) \ if ((cond_) == false) gu_throw_fatal << #cond_ << ": " #endif // GCOMM_EXCEPTION_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/map.hpp000066400000000000000000000170331244131713600212670ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ /*! * @file map.hpp * * This file contains templates that are thin wrappers for std::map * and std::multimap with some extra functionality. */ #ifndef GCOMM_MAP_HPP #define GCOMM_MAP_HPP #include "gu_serialize.hpp" #include #include #include #include "gcomm/exception.hpp" #include "gcomm/types.hpp" namespace gcomm { template class MapBase { typedef C MapType; public: typedef typename MapType::iterator iterator; typedef typename MapType::const_iterator const_iterator; typedef typename MapType::reverse_iterator reverse_iterator; typedef typename MapType::const_reverse_iterator const_reverse_iterator; typedef typename MapType::value_type value_type; typedef typename MapType::const_reference const_reference; typedef typename MapType::key_type key_type; typedef typename MapType::mapped_type mapped_type; protected: MapType map_; public: MapBase() : map_() {} virtual ~MapBase() {} iterator begin() { return map_.begin(); } iterator end() { return map_.end(); } iterator find(const K& k) { return map_.find(k); } iterator find_checked(const K& k) { iterator ret = map_.find(k); if (ret == map_.end()) { gu_throw_fatal << "element " << k << " not found"; } return ret; } iterator lower_bound(const K& k) { return map_.lower_bound(k); } const_iterator begin() const { return map_.begin(); } const_iterator end() const { return map_.end(); } const_reverse_iterator rbegin() const { return map_.rbegin(); } const_reverse_iterator rend() const { return map_.rend(); } const_iterator find(const K& k) const { return map_.find(k); } const_iterator find_checked(const K& k) const { const_iterator ret = map_.find(k); if (ret == map_.end()) { gu_throw_fatal << "element " << k << " not found"; } return ret; } mapped_type& operator[](const key_type& k) { return map_[k]; } void erase(iterator i) { map_.erase(i); } void erase(iterator i, iterator j) { map_.erase(i, j); } void erase(const K& k) { map_.erase(k); } void clear() { map_.clear(); } size_t size() const { return map_.size(); } bool empty() const { return map_.empty(); } size_t serialize(gu::byte_t* const buf, size_t const buflen, size_t offset) const { gu_trace(offset = gu::serialize4( static_cast(size()), buf, buflen, offset)); for (const_iterator i = map_.begin(); i != map_.end(); ++i) { gu_trace(offset = key(i).serialize(buf, buflen, offset)); gu_trace(offset = value(i).serialize(buf, buflen, offset)); } return offset; } size_t unserialize(const gu::byte_t* buf, size_t const buflen, size_t offset) { uint32_t len; // Clear map in case this object is reused map_.clear(); gu_trace(offset = gu::unserialize4(buf, buflen, offset, len));; for (uint32_t i = 0; i < len; ++i) { K k; V v; gu_trace(offset = k.unserialize(buf, buflen, offset)); gu_trace(offset = v.unserialize(buf, buflen, offset)); if (map_.insert(std::make_pair(k, v)).second == false) { gu_throw_fatal << "Failed to unserialize map"; } } return offset; } size_t serial_size() const { return sizeof(uint32_t) + size()*(K::serial_size() + V::serial_size()); } bool operator==(const MapBase& other) const { return (map_ == other.map_); } bool operator!=(const MapBase& other) const { return !(map_ == other.map_); } static const K& key(const_iterator i) { return i->first; } static const K& key(iterator i) { return i->first; } static const V& value(const_iterator i) { return i->second; } static V& value(iterator i) { return i->second; } static const K& key(const value_type& vt) { return vt.first; } static V& value(value_type& vt) { return vt.second; } static const V& value(const value_type& vt) { return vt.second; } }; // @todo For some reason map key must be declared in gcomm namespace // in order this to work. Find out the reason why and fix. template std::ostream& operator<<(std::ostream& os, const std::pair& p) { return (os << "\t" << p.first << "," << p.second << "\n"); } template std::ostream& operator<<(std::ostream& os, const MapBase& map) { std::copy(map.begin(), map.end(), std::ostream_iterator >(os, "")); return os; } template > class Map : public MapBase { public: typedef typename MapBase::iterator iterator; std::pair insert(const std::pair& p) { return MapBase::map_.insert(p); } template void insert(InputIterator first, InputIterator last) { MapBase::map_.insert(first, last); } iterator insert_unique(const typename MapBase::value_type& p) { std::pair ret = MapBase::map_.insert(p); if (false == ret.second) { gu_throw_fatal << "duplicate entry " << "key=" << MapBase::key(p) << " " << "value=" << MapBase::value(p) << " " << "map=" << *this; } return ret.first; } }; template > class MultiMap : public MapBase { public: typedef typename MapBase::iterator iterator; typedef typename MapBase::const_iterator const_iterator; typedef typename MapBase::value_type value_type; typedef typename MapBase::const_reference const_reference; iterator insert(const std::pair& p) { return MapBase::map_.insert(p); } iterator insert(iterator position, const value_type& vt) { return MapBase::map_.insert(position, vt); } std::pair equal_range(const K& k) const { return MapBase::map_.equal_range(k); } }; } #endif /* GCOMM_MAP_HPP */ percona-galera-3-3.8-3390/gcomm/src/gcomm/order.hpp000066400000000000000000000027241244131713600216260ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy * * $Id$ */ /*! * @file order.hpp * * @brief Message order type enumeration. */ #ifndef GCOMM_ORDER_HPP #define GCOMM_ORDER_HPP namespace gcomm { /*! * @brief Message order type enumeration. */ enum Order { /*! Message will not be delivered, for protocol use only. */ O_DROP = 0, /*! Message delivery is unreliable, for protocol use only. */ O_UNRELIABLE = 1, /*! Message will be delivered in source fifo order. */ O_FIFO = 2, /*! * Message will be delivered in same order on all nodes * if it is delivered. */ O_AGREED = 3, /*! * Message will be delivered in safe order, it is guaranteed * that all the nodes in group have received the message. */ O_SAFE = 4, /*! * Message will be delivered only locally and delivery will fulfill the * following property: * * Let M_c be message tagged with O_LOCAL_CAUSAL ordering requirement. * Any message M_a which is delivered on any node so that delivery * has causal precedence on generating M_c will be delivered locally * before M_c. * * Note that the causality is guaranteed only with respect to * already delivered messages. */ O_LOCAL_CAUSAL = 8 }; } #endif // GCOMM_ORDER_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/protolay.hpp000066400000000000000000000261471244131713600223710ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ /*! * @file protolay.hpp * * @brief Protocol layer interface definitions. * * Protocol layer interface allows construction of protocol stacks * with consistent interface to send messages upwards or downwards in * stack. */ #ifndef GCOMM_PROTOLAY_HPP #define GCOMM_PROTOLAY_HPP #include "gcomm/view.hpp" #include "gcomm/exception.hpp" #include "gcomm/order.hpp" #include "gcomm/datagram.hpp" #include "gu_logger.hpp" #include "gu_datetime.hpp" #include "gu_config.hpp" #include "gu_status.hpp" #include #include #include // Declarations namespace gcomm { /*! * @class ProtoUpMeta * * Container for metadata passed upwards in protocol stack. */ class ProtoUpMeta; std::ostream& operator<<(std::ostream&, const ProtoUpMeta&); /*! * @class ProtoDownMeta * * Container for metadata passed downwards in protocol stack. */ class ProtoDownMeta; /*! * @class Protolay * * Protocol layer interface. */ class Protolay; /*! * @class Toplay * * Protolay that is on the top of the protocol stack. */ class Toplay; /*! * @class Bottomlay * * Protolay that is on the bottom of the protocol stack. */ class Bottomlay; void connect(Protolay*, Protolay*); void disconnect(Protolay*, Protolay*); } /* message context to pass up with the data buffer? */ class gcomm::ProtoUpMeta { public: ProtoUpMeta(const int err_no) : source_(), source_view_id_(), user_type_(), order_(), to_seq_(), err_no_(err_no), view_(0) { } ProtoUpMeta(const UUID source = UUID::nil(), const ViewId source_view_id = ViewId(), const View* view = 0, const uint8_t user_type = 0xff, const Order order = O_DROP, const int64_t to_seq = -1, const int err_no = 0) : source_ (source ), source_view_id_ (source_view_id ), user_type_ (user_type ), order_ (order ), to_seq_ (to_seq ), err_no_ (err_no ), view_ (view != 0 ? new View(*view) : 0) { } ProtoUpMeta(const ProtoUpMeta& um) : source_ (um.source_ ), source_view_id_ (um.source_view_id_ ), user_type_ (um.user_type_ ), order_ (um.order_ ), to_seq_ (um.to_seq_ ), err_no_ (um.err_no_ ), view_ (um.view_ ? new View(*um.view_) : 0) { } ~ProtoUpMeta() { delete view_; } const UUID& source() const { return source_; } const ViewId& source_view_id() const { return source_view_id_; } uint8_t user_type() const { return user_type_; } Order order() const { return order_; } int64_t to_seq() const { return to_seq_; } int err_no() const { return err_no_; } bool has_view() const { return view_ != 0; } const View& view() const { return *view_; } private: ProtoUpMeta& operator=(const ProtoUpMeta&); UUID const source_; ViewId const source_view_id_; uint8_t const user_type_; Order const order_; int64_t const to_seq_; int const err_no_; View* const view_; }; inline std::ostream& gcomm::operator<<(std::ostream& os, const ProtoUpMeta& um) { os << "proto_up_meta: { "; if (not (um.source() == UUID::nil())) { os << "source=" << um.source() << ","; } if (um.source_view_id().type() != V_NONE) { os << "source_view_id=" << um.source_view_id() << ","; } os << "user_type=" << static_cast(um.user_type()) << ","; os << "to_seq=" << um.to_seq() << ","; if (um.has_view() == true) { os << "view=" << um.view(); } os << "}"; return os; } /* message context to pass down? */ class gcomm::ProtoDownMeta { public: ProtoDownMeta(const uint8_t user_type = 0xff, const Order order = O_SAFE, const UUID& uuid = UUID::nil(), const int segment = 0) : user_type_ (user_type), order_ (order), source_ (uuid), segment_ (segment) { } uint8_t user_type() const { return user_type_; } Order order() const { return order_; } const UUID& source() const { return source_; } int segment() const { return segment_; } private: const uint8_t user_type_; const Order order_; const UUID source_; const int segment_; }; class gcomm::Protolay { public: typedef Map EvictList; virtual ~Protolay() {} virtual void connect(bool) { } virtual void close(bool force = false) { } virtual void close(const UUID& uuid) { } /* apparently handles data from upper layer. what is return value? */ virtual int handle_down (Datagram&, const ProtoDownMeta&) = 0; virtual void handle_up (const void*, const Datagram&, const ProtoUpMeta&) = 0; void set_up_context(Protolay *up) { if (std::find(up_context_.begin(), up_context_.end(), up) != up_context_.end()) { gu_throw_fatal << "up context already exists"; } up_context_.push_back(up); } void set_down_context(Protolay *down) { if (std::find(down_context_.begin(), down_context_.end(), down) != down_context_.end()) { gu_throw_fatal << "down context already exists"; } down_context_.push_back(down); } void unset_up_context(Protolay* up) { CtxList::iterator i; if ((i = std::find(up_context_.begin(), up_context_.end(), up)) == up_context_.end()) { gu_throw_fatal << "up context does not exist"; } up_context_.erase(i); } void unset_down_context(Protolay* down) { CtxList::iterator i; if ((i = std::find(down_context_.begin(), down_context_.end(), down)) == down_context_.end()) { gu_throw_fatal << "down context does not exist"; } down_context_.erase(i); } /* apparently passed data buffer to the upper layer */ void send_up(const Datagram& dg, const ProtoUpMeta& up_meta) { if (up_context_.empty() == true) { gu_throw_fatal << this << " up context(s) not set"; } CtxList::iterator i, i_next; for (i = up_context_.begin(); i != up_context_.end(); i = i_next) { i_next = i, ++i_next; (*i)->handle_up(this, dg, up_meta); } } /* apparently passes data buffer to lower layer, what is return value? */ int send_down(Datagram& dg, const ProtoDownMeta& down_meta) { if (down_context_.empty() == true) { log_warn << this << " down context(s) not set"; return ENOTCONN; } int ret = 0; for (CtxList::iterator i = down_context_.begin(); i != down_context_.end(); ++i) { const size_t hdr_offset(dg.header_offset()); int err = (*i)->handle_down(dg, down_meta); // Verify that lower layer rolls back any modifications to // header if (hdr_offset != dg.header_offset()) { gu_throw_fatal; } if (err != 0) { ret = err; } } return ret; } virtual void handle_stable_view(const View& view) { } void set_stable_view(const View& view) { for (CtxList::iterator i(down_context_.begin()); i != down_context_.end(); ++i) { (*i)->handle_stable_view(view); } } virtual void handle_evict(const UUID& uuid) { } void evict(const UUID& uuid) { evict_list_.insert(std::make_pair(uuid, gu::datetime::Date::now())); handle_evict(uuid); for (CtxList::iterator i(down_context_.begin()); i != down_context_.end(); ++i) { (*i)->evict(uuid); } } void unevict(const UUID& uuid) { evict_list_.erase(uuid); for (CtxList::iterator i(down_context_.begin()); i != down_context_.end(); ++i) { (*i)->unevict(uuid); } } bool is_evicted(const UUID& uuid) const { if (down_context_.empty()) { return (evict_list_.find(uuid) != evict_list_.end()); } else { return (*down_context_.begin())->is_evicted(uuid); } } const EvictList& evict_list() const { return evict_list_; } virtual void handle_get_status(gu::Status& status) const { } void get_status(gu::Status& status) const { for (CtxList::const_iterator i(down_context_.begin()); i != down_context_.end(); ++i) { (*i)->get_status(status); } handle_get_status(status); } std::string get_address(const UUID& uuid) const { if (down_context_.empty()) return handle_get_address(uuid); else return (*down_context_.begin())->get_address(uuid); } virtual std::string handle_get_address(const UUID& uuid) const { return "(unknown)"; } virtual gu::datetime::Date handle_timers() { return gu::datetime::Date::max(); } virtual bool set_param(const std::string& key, const std::string& val) { return false; } const Protolay* id() const { return this; } protected: Protolay(gu::Config& conf) : conf_(conf), up_context_(0), down_context_(0), evict_list_() { } gu::Config& conf_; private: typedef std::list CtxList; CtxList up_context_; CtxList down_context_; EvictList evict_list_; Protolay (const Protolay&); Protolay& operator=(const Protolay&); }; class gcomm::Toplay : public Protolay { public: Toplay(gu::Config& conf) : Protolay(conf) { } private: int handle_down(Datagram& dg, const ProtoDownMeta& dm) { gu_throw_fatal << "Toplay handle_down() called"; } }; class gcomm::Bottomlay : public Protolay { public: Bottomlay(gu::Config& conf) : Protolay(conf) { } private: void handle_up(const void* id, const Datagram&, const ProtoUpMeta& um) { gu_throw_fatal << "Bottomlay handle_up() called"; } }; inline void gcomm::connect(Protolay* down, Protolay* up) { down->set_up_context(up); up->set_down_context(down); } inline void gcomm::disconnect(Protolay* down, Protolay* up) { down->unset_up_context(up); up->unset_down_context(down); } #endif /* GCOMM_PROTOLAY_HPP */ percona-galera-3-3.8-3390/gcomm/src/gcomm/protonet.hpp000066400000000000000000000052521244131713600223640ustar00rootroot00000000000000// // Copyright (C) 2009 Codership Oy // //! // @file protonet.hpp // // This file defines protonet interface used by gcomm. // #ifndef GCOMM_PROTONET_HPP #define GCOMM_PROTONET_HPP #include "gu_uri.hpp" #include "gu_datetime.hpp" #include "protostack.hpp" #include "gu_config.hpp" #include "socket.hpp" #include #include #ifndef GCOMM_PROTONET_MAX_VERSION #define GCOMM_PROTONET_MAX_VERSION 0 #endif // GCOMM_PROTONET_MAX_VERSION namespace gcomm { // Forward declarations class Protonet; } //! // Abstract Protonet interface class // class gcomm::Protonet { public: Protonet(gu::Config& conf, const std::string& type, int version) : protos_ (), version_(version), conf_ (conf), type_ (type) { } virtual ~Protonet() { } //! // Insert Protostack to be handled by Protonet // // @param pstack Pointer to Protostack // void insert(Protostack* pstack); //! // Erase Protostack from Protonet to stop dispatching events // to Protostack // // @param pstack Pointer to Protostack // void erase(Protostack* pstack); //! // Create new Socket // // @param uri URI to specify Socket type // // @return Socket // virtual gcomm::SocketPtr socket(const gu::URI& uri) = 0; //! // Create new Acceptor // // @param uri URI to specify Acceptor type // // @return Acceptor // virtual Acceptor* acceptor(const gu::URI& uri) = 0; //! // Dispatch events until period p has passed or event // loop is interrupted. // // @param p Period to run event_loop(), negative value means forever // virtual void event_loop(const gu::datetime::Period& p) = 0; //! // Iterate over Protostacks and handle timers // // @return Time of next known timer expiration // gu::datetime::Date handle_timers(); //! // Interrupt event loop // virtual void interrupt() = 0; //! // Enter Protonet critical section // virtual void enter() = 0; //! // Leave Protonet critical section // virtual void leave() = 0; bool set_param(const std::string& key, const std::string& val); gu::Config& conf() { return conf_; } //! // Factory method for creating Protonets // static Protonet* create(gu::Config& conf); const std::string& type() const { return type_; } virtual size_t mtu() const = 0; protected: std::deque protos_; int version_; static const int max_version_ = GCOMM_PROTONET_MAX_VERSION; gu::Config& conf_; private: std::string type_; }; #endif // GCOMM_PROTONET_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/protostack.hpp000066400000000000000000000015641244131713600227050ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef GCOMM_PROTOSTACK_HPP #define GCOMM_PROTOSTACK_HPP #include "gcomm/protolay.hpp" #include "gu_lock.hpp" #include #include namespace gcomm { class Socket; class Acceptor; class Protostack; class Protonet; class BoostProtonet; } class gcomm::Protostack { public: Protostack() : protos_(), mutex_() { } void push_proto(Protolay* p); void pop_proto(Protolay* p); gu::datetime::Date handle_timers(); void dispatch(const void* id, const Datagram& dg, const ProtoUpMeta& um); bool set_param(const std::string&, const std::string&); void enter() { mutex_.lock(); } void leave() { mutex_.unlock(); } private: friend class Protonet; std::deque protos_; gu::Mutex mutex_; }; #endif // GCOMM_PROTOSTACK_HPP percona-galera-3-3.8-3390/gcomm/src/gcomm/transport.hpp000066400000000000000000000050511244131713600225430ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ /*! * @file transport.hpp * * @brief Transport interface. */ #ifndef _GCOMM_TRANSPORT_HPP_ #define _GCOMM_TRANSPORT_HPP_ #include "gcomm/uuid.hpp" #include "gcomm/protolay.hpp" #include "gcomm/protostack.hpp" #include "gcomm/protonet.hpp" #include "gu_uri.hpp" namespace gcomm { /*! * @class Transport * * @brief Transport interface */ class Transport; } /*! * */ class gcomm::Transport : public Protolay { public: virtual ~Transport(); virtual size_t mtu() const = 0; virtual const UUID& uuid() const = 0; virtual std::string local_addr() const; virtual std::string remote_addr() const; int err_no() const; virtual void connect(bool start_prim) { gu_throw_fatal << "connect(start_prim) not supported"; } virtual void connect() // if not overloaded, will default to connect(bool) { connect(false); } virtual void connect(const gu::URI& uri) { gu_throw_fatal << "connect(URI) not supported"; } virtual void close(bool force = false) = 0; virtual void close(const UUID& uuid) { gu_throw_error(ENOTSUP) << "close(UUID) not supported by " << uri_.get_scheme(); } virtual void listen(); virtual std::string listen_addr() const { gu_throw_fatal << "not supported"; } virtual Transport* accept(); virtual void handle_accept(Transport*) { gu_throw_error(ENOTSUP) << "handle_accept() not supported by" << uri_.get_scheme(); } virtual void handle_connect() { gu_throw_error(ENOTSUP) << "handle_connect() not supported by" << uri_.get_scheme(); } virtual int handle_down(Datagram&, const ProtoDownMeta&) = 0; virtual void handle_up (const void*, const Datagram&, const ProtoUpMeta&) = 0; virtual void handle_stable_view(const View& view) { } Protostack& pstack() { return pstack_; } Protonet& pnet() { return pnet_; } static Transport* create(Protonet&, const std::string&); static Transport* create(Protonet&, const gu::URI&); protected: Transport (Protonet&, const gu::URI&); Protostack pstack_; Protonet& pnet_; gu::URI uri_; int error_no_; private: Transport (const Transport&); Transport& operator=(const Transport&); }; #endif // _GCOMM_TRANSPORT_HPP_ percona-galera-3-3.8-3390/gcomm/src/gcomm/types.hpp000066400000000000000000000043101244131713600216500ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #ifndef _GCOMM_TYPES_HPP_ #define _GCOMM_TYPES_HPP_ #include "gcomm/exception.hpp" #include "gu_byteswap.hpp" #include "gu_buffer.hpp" #include #include #include namespace gcomm { template class String { public: String(const std::string& str = "") : str_(str) { if (str_.size() > str_size_) { gu_throw_error(EMSGSIZE); } } virtual ~String() { } size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const { if (buflen < offset + str_size_) { gu_throw_error (EMSGSIZE) << str_size_ << " > " << (buflen-offset); } std::string ser_str(str_); ser_str.resize(str_size_, '\0'); (void)std::copy(ser_str.data(), ser_str.data() + ser_str.size(), buf + offset); return offset + str_size_; } size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset) { if (buflen < offset + str_size_) { gu_throw_error (EMSGSIZE) << str_size_ << " > " << (buflen-offset); } str_.assign(reinterpret_cast(buf) + offset, str_size_); const size_t tc(str_.find_first_of('\0')); if (tc != std::string::npos) { str_.resize(tc); } return offset + str_size_; } static size_t serial_size() { return str_size_; } const std::string& to_string() const { return str_; } bool operator==(const String& cmp) const { return (str_ == cmp.str_); } private: static const size_t str_size_ = SZ ; std::string str_; /* Human readable name if any */ }; template inline std::ostream& operator<<(std::ostream& os, const String& str) { return (os << str.to_string()); } } // namespace gcomm #endif /* _GCOMM_TYPES_HPP_ */ percona-galera-3-3.8-3390/gcomm/src/gcomm/util.hpp000066400000000000000000000052021244131713600214620ustar00rootroot00000000000000/* * Copyright (C) 2012 Codership Oy */ #ifndef _GCOMM_UTIL_HPP_ #define _GCOMM_UTIL_HPP_ #include "gcomm/datagram.hpp" #include "gu_logger.hpp" #include "gu_throw.hpp" #include namespace gcomm { inline std::string uri_string (const std::string& scheme, const std::string& addr, const std::string& port = std::string("")) { if (port.length() > 0) return (scheme + "://" + addr + ':' + port); else return (scheme + "://" + addr); } inline bool host_is_any (const std::string& host) { return (host.length() == 0 || host == "0.0.0.0" || host.find ("::/128") <= 1); } template size_t serialize(const C& c, gu::Buffer& buf) { const size_t prev_size(buf.size()); buf.resize(buf.size() + c.serial_size()); size_t ret; gu_trace(ret = c.serialize(&buf[0] + prev_size, buf.size(), prev_size)); assert(ret == prev_size + c.serial_size()); return ret; } template size_t unserialize(const gu::Buffer& buf, size_t offset, C& c) { size_t ret; gu_trace(ret = c.unserialize(buf, buf.size(), offset)); return ret; } template void push_header(const M& msg, Datagram& dg) { if (dg.header_offset() < msg.serial_size()) { gu_throw_fatal; } msg.serialize(dg.header(), dg.header_size(), dg.header_offset() - msg.serial_size()); dg.set_header_offset(dg.header_offset() - msg.serial_size()); } template void pop_header(const M& msg, Datagram& dg) { assert(dg.header_size() >= dg.header_offset() + msg.serial_size()); dg.set_header_offset(dg.header_offset() + msg.serial_size()); } inline const gu::byte_t* begin(const Datagram& dg) { return (dg.offset() < dg.header_len() ? dg.header() + dg.header_offset() + dg.offset() : &dg.payload()[0] + (dg.offset() - dg.header_len())); } inline size_t available(const Datagram& dg) { return (dg.offset() < dg.header_len() ? dg.header_len() - dg.offset() : dg.payload().size() - (dg.offset() - dg.header_len())); } template class Critical { public: Critical(M& monitor) : monitor_(monitor) { monitor_.enter(); } ~Critical() { monitor_.leave(); } private: M& monitor_; }; } // namespace gcomm #endif // _GCOMM_UTIL_HPP_ percona-galera-3-3.8-3390/gcomm/src/gcomm/uuid.hpp000066400000000000000000000035541244131713600214630ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef _GCOMM_UUID_HPP_ #define _GCOMM_UUID_HPP_ #include "gcomm/exception.hpp" #include "gcomm/types.hpp" #include "gu_utils.hpp" #include "gu_assert.hpp" #include "gu_byteswap.h" #include "gu_uuid.hpp" #include #include namespace gcomm { class UUID; std::ostream& operator<<(std::ostream&, const UUID&); } class gcomm::UUID : public gu::UUID { public: UUID() : gu::UUID() {} UUID(const void* node, const size_t node_len) : gu::UUID(node, node_len) {} UUID(const int32_t idx) : gu::UUID() { assert(idx > 0); memcpy(&uuid_, &idx, sizeof(idx)); } static const UUID& nil() { return uuid_nil_; } std::ostream& to_stream(std::ostream& os, bool full) const { std::ios_base::fmtflags saved = os.flags(); if (full == true) { os << uuid_; } else { os << std::hex << std::setfill('0') << std::setw(2) << static_cast(uuid_.data[0]) << std::setfill('0') << std::setw(2) << static_cast(uuid_.data[1]) << std::setfill('0') << std::setw(2) << static_cast(uuid_.data[2]) << std::setfill('0') << std::setw(2) << static_cast(uuid_.data[3]); } os.flags(saved); return os; } // Prefer the above function over this one std::string full_str() const { std::ostringstream os; to_stream(os, true); return os.str(); } private: static const UUID uuid_nil_; UUID(gu_uuid_t uuid) : gu::UUID(uuid) {} }; inline std::ostream& gcomm::operator<<(std::ostream& os, const UUID& uuid) { return uuid.to_stream (os, false); } #endif // _GCOMM_UUID_HPP_ percona-galera-3-3.8-3390/gcomm/src/gcomm/view.hpp000066400000000000000000000156451244131713600214730ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ /*! * @file Group view class (used in the ProtoUpMeta (protolay.hpp) */ #ifndef _GCOMM_VIEW_HPP_ #define _GCOMM_VIEW_HPP_ #include "gcomm/uuid.hpp" #include "gcomm/types.hpp" #include "gcomm/map.hpp" namespace gcomm { typedef enum { V_NONE = -1, V_REG = 0, V_TRANS = 1, V_NON_PRIM = 2, V_PRIM = 3 } ViewType; class ViewId { public: ViewId(const ViewType type = V_NONE, const UUID& uuid = UUID::nil(), const uint32_t seq = 0) : type_(type), uuid_(uuid), seq_ (seq) { } ViewId(const ViewType type, const ViewId& vi) : type_(type), uuid_(vi.uuid()), seq_ (vi.seq()) { } virtual ~ViewId() { } ViewType type() const { return type_; } const UUID& uuid() const { return uuid_; } uint32_t seq() const { return seq_; } size_t unserialize(const gu::byte_t* buf, size_t buflen, size_t offset); size_t serialize(gu::byte_t* buf, size_t buflen, size_t offset) const; static size_t serial_size() { return UUID::serial_size() + sizeof(reinterpret_cast(0)->seq_); } bool operator<(const ViewId& cmp) const { // View ordering: // 1) view seq less than // 2) uuid newer than // 3) type less than return (seq_ < cmp.seq_ || (seq_ == cmp.seq_ && (cmp.uuid_.older(uuid_) || (uuid_ == cmp.uuid_ && type_ < cmp.type_) ) ) ); } bool operator==(const ViewId& cmp) const { return (seq_ == cmp.seq_ && type_ == cmp.type_ && uuid_ == cmp.uuid_); } bool operator!=(const ViewId& cmp) const { return !(*this == cmp); } std::ostream& write_stream(std::ostream& os) const { os << static_cast(type_) << " "; uuid_.write_stream(os); os << " " << seq_; return os; } std::istream& read_stream(std::istream& is) { int t; is >> t; type_ = static_cast(t); uuid_.read_stream(is); is >> seq_; return is; } private: ViewType type_; UUID uuid_; // uniquely identifies the sequence of group views (?) uint32_t seq_; // position in the sequence (?) }; std::ostream& operator<<(std::ostream&, const ViewId&); typedef uint8_t SegmentId; class Node { public: Node(SegmentId segment = 0) : segment_(segment) { } SegmentId segment() const { return segment_; } bool operator==(const Node& cmp) const { return true; } bool operator<(const Node& cmp) const { return true; } std::ostream& write_stream(std::ostream& os) const { os << static_cast(segment_); return os; } std::istream& read_stream(std::istream& is) { int seg; is >> seg; segment_ = static_cast(seg); return is; } private: SegmentId segment_; }; inline std::ostream& operator<<(std::ostream& os, const Node& n) { return (os << static_cast(n.segment()) ); } class NodeList : public gcomm::Map { }; class View { public: View() : version_ (-1), bootstrap_ (false), view_id_ (V_NONE), members_ (), joined_ (), left_ (), partitioned_ () { } View(int version, const ViewId& view_id, bool bootstrap = false) : version_ (version), bootstrap_ (bootstrap), view_id_ (view_id), members_ (), joined_ (), left_ (), partitioned_ () { } ~View() {} int version() const { return version_; } void add_member (const UUID& pid, SegmentId segment); void add_members (NodeList::const_iterator begin, NodeList::const_iterator end); void add_joined (const UUID& pid, SegmentId segment); void add_left (const UUID& pid, SegmentId segment); void add_partitioned (const UUID& pid, SegmentId segment); const NodeList& members () const; const NodeList& joined () const; const NodeList& left () const; const NodeList& partitioned () const; NodeList& members() { return members_; } bool is_member(const UUID& uuid) const { return members_.find(uuid) != members_.end(); } bool is_joining(const UUID& uuid) const { return joined_.find(uuid) != joined_.end(); } bool is_leaving(const UUID& uuid) const { return left_.find(uuid) != left_.end(); } bool is_partitioning(const UUID& uuid) const { return partitioned_.find(uuid) != partitioned_.end(); } ViewType type () const; const ViewId& id () const; const UUID& representative () const; bool is_empty() const; bool is_bootstrap() const { return bootstrap_; } std::ostream& write_stream(std::ostream& os) const; std::istream& read_stream(std::istream& is); private: int version_; // view protocol version, derived from evs group bool bootstrap_; // Flag indicating if view was bootstrapped ViewId view_id_; // View identifier NodeList members_; // List of members in view NodeList joined_; // List of newly joined members in view NodeList left_; // Fracefully left members from previous view NodeList partitioned_; // Partitioned members from previous view }; bool operator==(const gcomm::View&, const gcomm::View&); std::ostream& operator<<(std::ostream&, const View&); class ViewState { public: ViewState(UUID& my_uuid, View& view): my_uuid_(my_uuid), view_(view) { } std::ostream& write_stream(std::ostream& os) const; std::istream& read_stream(std::istream& is); void write_file(const char* fname = NULL) const; bool read_file(const char* fname = NULL); static void remove_file(const char* fname = NULL); bool operator== (const ViewState& vst) const { return my_uuid_ == vst.my_uuid_ && view_ == vst.view_; } private: UUID& my_uuid_; View& view_; }; } // namespace gcomm #endif // _GCOMM_VIEW_HPP_ percona-galera-3-3.8-3390/gcomm/src/gmcast.cpp000066400000000000000000001501521244131713600206610ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "gmcast.hpp" #include "gmcast_proto.hpp" #include "gcomm/common.hpp" #include "gcomm/conf.hpp" #include "gcomm/util.hpp" #include "gcomm/map.hpp" #include "defaults.hpp" #include "gu_convert.hpp" #include "gu_resolver.hpp" using namespace std::rel_ops; using gcomm::gmcast::Proto; using gcomm::gmcast::ProtoMap; using gcomm::gmcast::Link; using gcomm::gmcast::LinkMap; using gcomm::gmcast::Message; const long gcomm::GMCast::max_retry_cnt_(std::numeric_limits::max()); static void set_tcp_defaults (gu::URI* uri) { // what happens if there is already this parameter? uri->set_option(gcomm::Conf::TcpNonBlocking, gu::to_string(1)); } static bool check_tcp_uri(const gu::URI& uri) { return (uri.get_scheme() == gcomm::TCP_SCHEME || uri.get_scheme() == gcomm::SSL_SCHEME); } static std::string get_scheme(bool use_ssl) { if (use_ssl == true) { return gcomm::SSL_SCHEME; } return gcomm::TCP_SCHEME; } gcomm::GMCast::GMCast(Protonet& net, const gu::URI& uri, const UUID* my_uuid) : Transport (net, uri), version_(check_range(Conf::GMCastVersion, param(conf_, uri, Conf::GMCastVersion, "0"), 0, max_version_ + 1)), segment_ (check_range(Conf::GMCastSegment, param(conf_, uri, Conf::GMCastSegment, "0"), 0, 255)), my_uuid_ (my_uuid ? *my_uuid : UUID(0, 0)), use_ssl_ (param(conf_, uri, Conf::SocketUseSsl, "false")), // @todo: technically group name should be in path component group_name_ (param(conf_, uri, Conf::GMCastGroup, "")), listen_addr_ ( param( conf_, uri, Conf::GMCastListenAddr, get_scheme(use_ssl_) + "://0.0.0.0")), // how to make it IPv6 safe? initial_addrs_(), mcast_addr_ (param(conf_, uri, Conf::GMCastMCastAddr, "")), bind_ip_ (""), mcast_ttl_ (check_range( Conf::GMCastMCastTTL, param(conf_, uri, Conf::GMCastMCastTTL, "1"), 1, 256)), listener_ (0), mcast_ (), pending_addrs_(), remote_addrs_ (), addr_blacklist_(), relaying_ (false), isolate_ (false), proto_map_ (new ProtoMap()), relay_set_ (), segment_map_ (), self_index_ (std::numeric_limits::max()), time_wait_ (param( conf_, uri, Conf::GMCastTimeWait, Defaults::GMCastTimeWait)), check_period_ ("PT0.5S"), peer_timeout_ (param( conf_, uri, Conf::GMCastPeerTimeout, Defaults::GMCastPeerTimeout)), max_initial_reconnect_attempts_( param(conf_, uri, Conf::GMCastMaxInitialReconnectAttempts, gu::to_string(max_retry_cnt_))), next_check_ (gu::datetime::Date::now()) { log_info << "GMCast version " << version_; if (group_name_ == "") { gu_throw_error (EINVAL) << "Group not defined in URL: " << uri_.to_string(); } set_initial_addr(uri_); try { listen_addr_ = uri_.get_option (Conf::GMCastListenAddr); } catch (gu::NotFound&) {} try { gu::URI uri(listen_addr_); /* check validity of the address */ } catch (gu::Exception&) { /* most probably no scheme, try to append one and see if it succeeds */ listen_addr_ = uri_string(get_scheme(use_ssl_), listen_addr_); gu_trace(gu::URI uri(listen_addr_)); } gu::URI listen_uri(listen_addr_); if (check_tcp_uri(listen_uri) == false) { gu_throw_error (EINVAL) << "listen addr '" << listen_addr_ << "' does not specify supported protocol"; } if (gu::net::resolve(listen_uri).get_addr().is_anyaddr() == false) { // bind outgoing connections to the same address as listening. gu_trace(bind_ip_ = listen_uri.get_host()); } std::string port(Defaults::GMCastTcpPort); try { port = listen_uri.get_port(); } catch (gu::NotSet&) { // if no listen port is set for listen address in the options, // see if base port was configured try { port = conf_.get(BASE_PORT_KEY); } catch (gu::NotSet&) { // if no base port configured, try port from the connection address try { port = uri_.get_port(); } catch (gu::NotSet&) {} } listen_addr_ += ":" + port; } conf_.set(BASE_PORT_KEY, port); listen_addr_ = gu::net::resolve(listen_addr_).to_string(); // resolving sets scheme to tcp, have to rewrite for ssl if (use_ssl_ == true) { listen_addr_.replace(0, 3, gcomm::SSL_SCHEME); } std::set::iterator iaself(initial_addrs_.find(listen_addr_)); if (iaself != initial_addrs_.end()) { log_debug << "removing own listen address '" << *iaself << "' from initial address list"; initial_addrs_.erase(iaself); } if (mcast_addr_ != "") { try { port = uri_.get_option(Conf::GMCastMCastPort); } catch (gu::NotFound&) {} mcast_addr_ = gu::net::resolve( uri_string(gcomm::UDP_SCHEME, mcast_addr_, port)).to_string(); } log_info << self_string() << " listening at " << listen_addr_; log_info << self_string() << " multicast: " << mcast_addr_ << ", ttl: " << mcast_ttl_; conf_.set(Conf::GMCastListenAddr, listen_addr_); conf_.set(Conf::GMCastMCastAddr, mcast_addr_); conf_.set(Conf::GMCastVersion, gu::to_string(version_)); conf_.set(Conf::GMCastTimeWait, gu::to_string(time_wait_)); conf_.set(Conf::GMCastMCastTTL, gu::to_string(mcast_ttl_)); conf_.set(Conf::GMCastPeerTimeout, gu::to_string(peer_timeout_)); conf_.set(Conf::GMCastSegment, gu::to_string(segment_)); } gcomm::GMCast::~GMCast() { if (listener_ != 0) close(); delete proto_map_; } void gcomm::GMCast::set_initial_addr(const gu::URI& uri) { const gu::URI::AuthorityList& al(uri.get_authority_list()); for (gu::URI::AuthorityList::const_iterator i(al.begin()); i != al.end(); ++i) { std::string host; try { host = i->host(); } catch (gu::NotSet& ns) { gu_throw_error(EINVAL) << "Unset host in URL " << uri; } if (host_is_any(host)) continue; std::string port; try { port = i->port(); } catch (gu::NotSet& ) { try { port = conf_.get(BASE_PORT_KEY); } catch (gu::NotFound&) { port = Defaults::GMCastTcpPort; } } std::string initial_uri = uri_string(get_scheme(use_ssl_), host, port); std::string initial_addr; try { initial_addr = gu::net::resolve(initial_uri).to_string(); } catch (gu::Exception& ) { log_warn << "Failed to resolve " << initial_uri; continue; } // resolving sets scheme to tcp, have to rewrite for ssl if (use_ssl_ == true) { initial_addr.replace(0, 3, gcomm::SSL_SCHEME); } if (check_tcp_uri(initial_addr) == false) { gu_throw_error (EINVAL) << "initial addr '" << initial_addr << "' is not valid"; } log_debug << self_string() << " initial addr: " << initial_addr; initial_addrs_.insert(initial_addr); } } void gcomm::GMCast::connect_precheck(bool start_prim) { if (!start_prim && initial_addrs_.empty()) { gu_throw_fatal << "No address to connect"; } } void gcomm::GMCast::connect() { pstack_.push_proto(this); log_debug << "gmcast " << uuid() << " connect"; gu::URI listen_uri(listen_addr_); set_tcp_defaults (&listen_uri); listener_ = pnet().acceptor(listen_uri); gu_trace (listener_->listen(listen_uri)); if (!mcast_addr_.empty()) { gu::URI mcast_uri( mcast_addr_ + '?' + gcomm::Socket::OptIfAddr + '=' + gu::URI(listen_addr_).get_host()+'&' + gcomm::Socket::OptNonBlocking + "=1&" + gcomm::Socket::OptMcastTTL + '=' + gu::to_string(mcast_ttl_) ); mcast_ = pnet().socket(mcast_uri); gu_trace(mcast_->connect(mcast_uri)); } if (!initial_addrs_.empty()) { for (std::set::const_iterator i(initial_addrs_.begin()); i != initial_addrs_.end(); ++i) { insert_address(*i, UUID(), pending_addrs_); AddrList::iterator ai(pending_addrs_.find(*i)); AddrList::value(ai).set_max_retries(max_retry_cnt_); gu_trace (gmcast_connect(*i)); } } } void gcomm::GMCast::connect(const gu::URI& uri) { set_initial_addr(uri); connect(); } void gcomm::GMCast::close(bool force) { log_debug << "gmcast " << uuid() << " close"; pstack_.pop_proto(this); if (mcast_ != 0) { mcast_->close(); // delete mcast; // mcast = 0; } gcomm_assert(listener_ != 0); listener_->close(); delete listener_; listener_ = 0; segment_map_.clear(); for (ProtoMap::iterator i = proto_map_->begin(); i != proto_map_->end(); ++i) { delete ProtoMap::value(i); } proto_map_->clear(); pending_addrs_.clear(); remote_addrs_.clear(); } // Erase proto entry in safe manner // 1) Erase from relay_set_ // 2) Erase from proto_map_ // 3) Delete proto entry void gcomm::GMCast::erase_proto(gmcast::ProtoMap::iterator i) { Proto* p(ProtoMap::value(i)); std::set::iterator si(relay_set_.find(p->socket().get())); if (si != relay_set_.end()) { relay_set_.erase(si); } proto_map_->erase(i); delete p; } void gcomm::GMCast::gmcast_accept() { SocketPtr tp; try { tp = listener_->accept(); } catch (gu::Exception& e) { log_warn << e.what(); return; } if (isolate_ == true) { log_debug << "dropping accepted socket due to isolation"; tp->close(); return; } Proto* peer = new Proto ( *this, version_, tp, listener_->listen_addr(), "", mcast_addr_, segment_, group_name_); std::pair ret = proto_map_->insert(std::make_pair(tp->id(), peer)); if (ret.second == false) { delete peer; gu_throw_fatal << "Failed to add peer to map"; } if (tp->state() == Socket::S_CONNECTED) { peer->send_handshake(); } else { log_debug << "accepted socket is connecting"; } log_debug << "handshake sent"; } void gcomm::GMCast::gmcast_connect(const std::string& remote_addr) { if (remote_addr == listen_addr_) return; gu::URI connect_uri(remote_addr); set_tcp_defaults (&connect_uri); if (!bind_ip_.empty()) { connect_uri.set_option(gcomm::Socket::OptIfAddr, bind_ip_); } SocketPtr tp = pnet().socket(connect_uri); try { tp->connect(connect_uri); } catch (gu::Exception& e) { log_debug << "Connect failed: " << e.what(); // delete tp; return; } Proto* peer = new Proto ( *this, version_, tp, listener_->listen_addr(), remote_addr, mcast_addr_, segment_, group_name_); std::pair ret = proto_map_->insert(std::make_pair(tp->id(), peer)); if (ret.second == false) { delete peer; gu_throw_fatal << "Failed to add peer to map"; } ret.first->second->wait_handshake(); } void gcomm::GMCast::gmcast_forget(const UUID& uuid, const gu::datetime::Period& wait_period) { /* Close all proto entries corresponding to uuid */ ProtoMap::iterator pi, pi_next; for (pi = proto_map_->begin(); pi != proto_map_->end(); pi = pi_next) { pi_next = pi, ++pi_next; Proto* rp = ProtoMap::value(pi); if (rp->remote_uuid() == uuid) { erase_proto(pi); } } /* Set all corresponding entries in address list to have retry cnt * greater than max retries and next reconnect time after some period */ AddrList::iterator ai; for (ai = remote_addrs_.begin(); ai != remote_addrs_.end(); ++ai) { AddrEntry& ae(AddrList::value(ai)); if (ae.uuid() == uuid) { log_info << "forgetting " << uuid << " (" << AddrList::key(ai) << ")"; ProtoMap::iterator pi, pi_next; for (pi = proto_map_->begin(); pi != proto_map_->end(); pi = pi_next) { pi_next = pi, ++pi_next; if (ProtoMap::value(pi)->remote_addr() == AddrList::key(ai)) { log_info << "deleting entry " << AddrList::key(ai); erase_proto(pi); } } ae.set_max_retries(0); ae.set_retry_cnt(1); gu::datetime::Date now(gu::datetime::Date::now()); // Don't reduce next reconnect time if it is set greater than // requested if ((now + wait_period > ae.next_reconnect()) || (ae.next_reconnect() == gu::datetime::Date::max())) { ae.set_next_reconnect(gu::datetime::Date::now() + wait_period); } else { log_debug << "not decreasing next reconnect for " << uuid; } } } /* Update state */ update_addresses(); } void gcomm::GMCast::handle_connected(Proto* rp) { const SocketPtr tp(rp->socket()); assert(tp->state() == Socket::S_CONNECTED); log_debug << "transport " << tp << " connected"; if (rp->state() == Proto::S_INIT) { log_debug << "sending hanshake"; // accepted socket was waiting for underlying transport // handshake to finish rp->send_handshake(); } } void gcomm::GMCast::handle_established(Proto* est) { log_debug << self_string() << " connection established to " << est->remote_uuid() << " " << est->remote_addr(); if (is_evicted(est->remote_uuid())) { log_warn << "Closing connection to evicted node " << est->remote_uuid(); erase_proto(proto_map_->find_checked(est->socket()->id())); update_addresses(); return; } if (est->remote_uuid() == uuid()) { std::set::iterator ia_i(initial_addrs_.find(est->remote_addr())); if (ia_i != initial_addrs_.end()) { initial_addrs_.erase(ia_i); } AddrList::iterator i(pending_addrs_.find(est->remote_addr())); if (i != pending_addrs_.end()) { if (addr_blacklist_.find(est->remote_addr()) == addr_blacklist_.end()) { log_warn << self_string() << " address '" << est->remote_addr() << "' points to own listening address, blacklisting"; } pending_addrs_.erase(i); addr_blacklist_.insert(make_pair(est->remote_addr(), AddrEntry(gu::datetime::Date::now(), gu::datetime::Date::now(), est->remote_uuid()))); } erase_proto(proto_map_->find_checked(est->socket()->id())); update_addresses(); return; } // If address is found from pending_addrs_, move it to remote_addrs list // and set retry cnt to -1 const std::string& remote_addr(est->remote_addr()); AddrList::iterator i(pending_addrs_.find(remote_addr)); if (i != pending_addrs_.end()) { log_debug << "Erasing " << remote_addr << " from panding list"; pending_addrs_.erase(i); } if ((i = remote_addrs_.find(remote_addr)) == remote_addrs_.end()) { log_debug << "Inserting " << remote_addr << " to remote list"; insert_address (remote_addr, est->remote_uuid(), remote_addrs_); i = remote_addrs_.find(remote_addr); } else if (AddrList::value(i).uuid() != est->remote_uuid()) { log_info << "remote endpoint " << est->remote_addr() << " changed identity " << AddrList::value(i).uuid() << " -> " << est->remote_uuid(); remote_addrs_.erase(i); i = remote_addrs_.insert_unique( make_pair(est->remote_addr(), AddrEntry(gu::datetime::Date::now(), gu::datetime::Date::max(), est->remote_uuid()))); } if (AddrList::value(i).retry_cnt() > AddrList::value(i).max_retries()) { log_warn << "discarding established (time wait) " << est->remote_uuid() << " (" << est->remote_addr() << ") "; erase_proto(proto_map_->find(est->socket()->id())); update_addresses(); return; } // send_up(Datagram(), p->remote_uuid()); // init retry cnt to -1 to avoid unnecessary logging at first attempt // max retries will be readjusted in handle stable view AddrList::value(i).set_retry_cnt(-1); AddrList::value(i).set_max_retries(max_initial_reconnect_attempts_); // Cleanup all previously established entries with same // remote uuid. It is assumed that the most recent connection // is usually the healthiest one. ProtoMap::iterator j, j_next; for (j = proto_map_->begin(); j != proto_map_->end(); j = j_next) { j_next = j, ++j_next; Proto* p(ProtoMap::value(j)); if (p->remote_uuid() == est->remote_uuid()) { if (p->handshake_uuid() < est->handshake_uuid()) { log_debug << self_string() << " cleaning up duplicate " << p->socket() << " after established " << est->socket(); erase_proto(j); } else if (p->handshake_uuid() > est->handshake_uuid()) { log_debug << self_string() << " cleaning up established " << est->socket() << " which is duplicate of " << p->socket(); erase_proto(proto_map_->find_checked(est->socket()->id())); update_addresses(); return; } else { assert(p == est); } } } AddrList::iterator ali(find_if(remote_addrs_.begin(), remote_addrs_.end(), AddrListUUIDCmp(est->remote_uuid()))); if (ali != remote_addrs_.end()) { AddrList::value(ali).set_last_connect(); } else { log_warn << "peer " << est->remote_addr() << " not found from remote addresses"; } update_addresses(); } void gcomm::GMCast::handle_failed(Proto* failed) { log_debug << "handle failed: " << *failed; const std::string& remote_addr = failed->remote_addr(); bool found_ok(false); for (ProtoMap::const_iterator i = proto_map_->begin(); i != proto_map_->end(); ++i) { Proto* p(ProtoMap::value(i)); if (p != failed && p->state() <= Proto::S_OK && p->remote_addr() == failed->remote_addr()) { log_debug << "found live " << *p; found_ok = true; break; } } if (found_ok == false && remote_addr != "") { AddrList::iterator i; if ((i = pending_addrs_.find(remote_addr)) != pending_addrs_.end() || (i = remote_addrs_.find(remote_addr)) != remote_addrs_.end()) { AddrEntry& ae(AddrList::value(i)); ae.set_retry_cnt(ae.retry_cnt() + 1); gu::datetime::Date rtime = gu::datetime::Date::now() + gu::datetime::Period("PT1S"); log_debug << self_string() << " setting next reconnect time to " << rtime << " for " << remote_addr; ae.set_next_reconnect(rtime); } } erase_proto(proto_map_->find_checked(failed->socket()->id())); update_addresses(); } bool gcomm::GMCast::is_connected(const std::string& addr, const UUID& uuid) const { for (ProtoMap::const_iterator i = proto_map_->begin(); i != proto_map_->end(); ++i) { Proto* conn = ProtoMap::value(i); if (addr == conn->remote_addr() || uuid == conn->remote_uuid()) { return true; } } return false; } void gcomm::GMCast::insert_address (const std::string& addr, const UUID& uuid, AddrList& alist) { if (addr == listen_addr_) { gu_throw_fatal << "Trying to add self addr " << addr << " to addr list"; } if (alist.insert(make_pair(addr, AddrEntry(gu::datetime::Date::now(), gu::datetime::Date::now(), uuid))).second == false) { log_warn << "Duplicate entry: " << addr; } else { log_debug << self_string() << ": new address entry " << uuid << ' ' << addr; } } void gcomm::GMCast::update_addresses() { LinkMap link_map; std::set uuids; /* Add all established connections into uuid_map and update * list of remote addresses */ ProtoMap::iterator i, i_next; for (i = proto_map_->begin(); i != proto_map_->end(); i = i_next) { i_next = i, ++i_next; Proto* rp = ProtoMap::value(i); if (rp->state() == Proto::S_OK) { if (rp->remote_addr() == "" || rp->remote_uuid() == UUID::nil()) { gu_throw_fatal << "Protocol error: local: (" << my_uuid_ << ", '" << listen_addr_ << "'), remote: (" << rp->remote_uuid() << ", '" << rp->remote_addr() << "')"; } if (remote_addrs_.find(rp->remote_addr()) == remote_addrs_.end()) { log_warn << "Connection exists but no addr on addr list for " << rp->remote_addr(); insert_address(rp->remote_addr(), rp->remote_uuid(), remote_addrs_); } if (uuids.insert(rp->remote_uuid()).second == false) { // Duplicate entry, drop this one // @todo Deeper inspection about the connection states log_debug << self_string() << " dropping duplicate entry"; erase_proto(i); } else { link_map.insert(Link(rp->remote_uuid(), rp->remote_addr(), rp->mcast_addr())); } } } /* Send topology change message containing only established * connections */ for (ProtoMap::iterator i = proto_map_->begin(); i != proto_map_->end(); ++i) { Proto* gp = ProtoMap::value(i); // @todo: a lot of stuff here is done for each connection, including // message creation and serialization. Need a mcast_msg() call // and move this loop in there. if (gp->state() == Proto::S_OK) gp->send_topology_change(link_map); } /* Add entries reported by all other nodes to address list to * get complete view of existing uuids/addresses */ for (ProtoMap::iterator i = proto_map_->begin(); i != proto_map_->end(); ++i) { Proto* rp = ProtoMap::value(i); if (rp->state() == Proto::S_OK) { for (LinkMap::const_iterator j = rp->link_map().begin(); j != rp->link_map().end(); ++j) { const UUID& link_uuid(LinkMap::key(j)); const std::string& link_addr(LinkMap::value(j).addr()); gcomm_assert(link_uuid != UUID::nil() && link_addr != ""); if (addr_blacklist_.find(link_addr) != addr_blacklist_.end()) { log_info << self_string() << " address '" << link_addr << "' pointing to uuid " << link_uuid << " is blacklisted, skipping"; continue; } if (link_uuid != uuid() && remote_addrs_.find(link_addr) == remote_addrs_.end() && pending_addrs_.find(link_addr) == pending_addrs_.end()) { log_debug << self_string() << " conn refers to but no addr in addr list for " << link_addr; insert_address(link_addr, link_uuid, remote_addrs_); AddrList::iterator pi(remote_addrs_.find(link_addr)); assert(pi != remote_addrs_.end()); AddrEntry& ae(AddrList::value(pi)); // init retry cnt to -1 to avoid unnecessary logging // at first attempt // max retries will be readjusted in handle stable view ae.set_retry_cnt(-1); ae.set_max_retries(max_initial_reconnect_attempts_); // Add some randomness for first reconnect to avoid // simultaneous connects gu::datetime::Date rtime(gu::datetime::Date::now()); rtime = rtime + ::rand() % (100*gu::datetime::MSec); ae.set_next_reconnect(rtime); next_check_ = std::min(next_check_, rtime); } } } } // Build multicast tree log_debug << self_string() << " --- mcast tree begin ---"; segment_map_.clear(); Segment& local_segment(segment_map_[segment_]); if (mcast_ != 0) { log_debug << mcast_addr_; local_segment.push_back(mcast_.get()); } self_index_ = 0; for (ProtoMap::const_iterator i(proto_map_->begin()); i != proto_map_->end(); ++i) { const Proto& p(*ProtoMap::value(i)); log_debug << "Proto: " << p; if (p.remote_segment() == segment_) { if (p.state() == Proto::S_OK && (p.mcast_addr() == "" || p.mcast_addr() != mcast_addr_)) { local_segment.push_back(p.socket().get()); if (p.remote_uuid() < uuid()) { ++self_index_; } } } else { if (p.state() == Proto::S_OK) { Segment& remote_segment(segment_map_[p.remote_segment()]); remote_segment.push_back(p.socket().get()); } } } log_debug << self_string() << " self index: " << self_index_; log_debug << self_string() << " --- mcast tree end ---"; } void gcomm::GMCast::reconnect() { if (isolate_ == true) { log_debug << "skipping reconnect due to isolation"; return; } /* Loop over known remote addresses and connect if proto entry * does not exist */ gu::datetime::Date now = gu::datetime::Date::now(); AddrList::iterator i, i_next; for (i = pending_addrs_.begin(); i != pending_addrs_.end(); i = i_next) { i_next = i, ++i_next; const std::string& pending_addr(AddrList::key(i)); const AddrEntry& ae(AddrList::value(i)); if (is_connected (pending_addr, UUID::nil()) == false && ae.next_reconnect() <= now) { if (ae.retry_cnt() > ae.max_retries()) { log_info << "cleaning up pending addr " << pending_addr; pending_addrs_.erase(i); continue; // no reference to pending_addr after this } else if (ae.next_reconnect() <= now) { log_debug << "connecting to pending " << pending_addr; gmcast_connect (pending_addr); } } } for (i = remote_addrs_.begin(); i != remote_addrs_.end(); i = i_next) { i_next = i, ++i_next; const std::string& remote_addr(AddrList::key(i)); const AddrEntry& ae(AddrList::value(i)); const UUID& remote_uuid(ae.uuid()); gcomm_assert(remote_uuid != uuid()); if (is_connected(remote_addr, remote_uuid) == false && ae.next_reconnect() <= now) { if (ae.retry_cnt() > ae.max_retries()) { log_info << " cleaning up " << remote_uuid << " (" << remote_addr << ")"; remote_addrs_.erase(i); continue;//no reference to remote_addr or remote_uuid after this } else if (ae.next_reconnect() <= now) { if (ae.retry_cnt() % 30 == 0) { log_info << self_string() << " reconnecting to " << remote_uuid << " (" << remote_addr << "), attempt " << ae.retry_cnt(); } gmcast_connect(remote_addr); } else { // } } } } namespace { class CmpUuidCounts { public: CmpUuidCounts(const std::set& uuids, gcomm::SegmentId preferred_segment) : uuids_(uuids), preferred_segment_(preferred_segment) { } size_t count(const gcomm::gmcast::Proto* p) const { size_t cnt(0); for (std::set::const_iterator i(uuids_.begin()); i != uuids_.end(); ++i) { for (gcomm::gmcast::LinkMap::const_iterator lm_i(p->link_map().begin()); lm_i != p->link_map().end(); ++lm_i) { if (lm_i->uuid() == *i) { ++cnt; break; } } } return cnt; } bool operator()(const gcomm::gmcast::Proto* a, const gcomm::gmcast::Proto* b) const { size_t ac(count(a)); size_t bc(count(b)); // if counts are equal, prefer peer from the same segment return (ac < bc || (ac == bc && a->remote_segment() != preferred_segment_)); } private: const std::set& uuids_; gcomm::SegmentId preferred_segment_; }; } void gcomm::GMCast::check_liveness() { std::set live_uuids; // iterate over proto map and mark all timed out entries as failed gu::datetime::Date now(gu::datetime::Date::now()); for (ProtoMap::iterator i(proto_map_->begin()); i != proto_map_->end(); ) { ProtoMap::iterator i_next(i); ++i_next; Proto* p(ProtoMap::value(i)); if (p->state() > Proto::S_INIT && p->state() < Proto::S_FAILED && p->tstamp() + peer_timeout_ < now) { log_debug << self_string() << " connection to peer " << p->remote_uuid() << " with addr " << p->remote_addr() << " timed out"; p->set_state(Proto::S_FAILED); handle_failed(p); } else if (p->state() == Proto::S_OK) { if (p->tstamp() + peer_timeout_*2/3 < now) { p->send_keepalive(); } if (p->state() == Proto::S_FAILED) { handle_failed(p); } else { live_uuids.insert(p->remote_uuid()); } } i = i_next; } bool should_relay(false); // iterate over addr list and check if there is at least one live // proto entry associated to each addr entry std::set nonlive_uuids; std::string nonlive_peers; for (AddrList::const_iterator i(remote_addrs_.begin()); i != remote_addrs_.end(); ++i) { const AddrEntry& ae(AddrList::value(i)); if (ae.retry_cnt() <= ae.max_retries() && live_uuids.find(ae.uuid()) == live_uuids.end()) { // log_info << self_string() // << " missing live proto entry for " << ae.uuid(); nonlive_uuids.insert(ae.uuid()); nonlive_peers += AddrList::key(i) + " "; should_relay = true; } else if (ae.last_connect() + peer_timeout_ > now) { log_debug << "continuing relaying for " << (ae.last_connect() + peer_timeout_ - now); should_relay = true; } } if (should_relay == true) { if (relaying_ == false) { log_info << self_string() << " turning message relay requesting on, nonlive peers: " << nonlive_peers; relaying_ = true; } relay_set_.clear(); // build set of protos having OK status std::set proto_set; for (ProtoMap::iterator i(proto_map_->begin()); i != proto_map_->end(); ++i) { Proto* p(ProtoMap::value(i)); if (p->state() == Proto::S_OK) { proto_set.insert(p); } } // find minimal set of proto entries required to reach maximum set // of nonlive peers while (nonlive_uuids.empty() == false && proto_set.empty() == false) { std::set::iterator maxel( std::max_element(proto_set.begin(), proto_set.end(), CmpUuidCounts(nonlive_uuids, segment_))); Proto* p(*maxel); log_debug << "relay set maxel :" << *p << " count: " << CmpUuidCounts(nonlive_uuids, segment_).count(p); relay_set_.insert(p->socket().get()); const LinkMap& lm(p->link_map()); for (LinkMap::const_iterator lm_i(lm.begin()); lm_i != lm.end(); ++lm_i) { nonlive_uuids.erase((*lm_i).uuid()); } proto_set.erase(maxel); } } else if (relaying_ == true && should_relay == false) { log_info << self_string() << " turning message relay requesting off"; relay_set_.clear(); relaying_ = false; } } gu::datetime::Date gcomm::GMCast::handle_timers() { const gu::datetime::Date now(gu::datetime::Date::now()); if (now >= next_check_) { check_liveness(); reconnect(); next_check_ = now + check_period_; } return next_check_; } void send(gcomm::Socket* s, gcomm::Datagram& dg) { int err; if ((err = s->send(dg)) != 0) { log_debug << "failed to send to " << s->remote_addr() << ": (" << err << ") " << strerror(err); } } void gcomm::GMCast::relay(const Message& msg, const Datagram& dg, const void* exclude_id) { Datagram relay_dg(dg); relay_dg.normalize(); Message relay_msg(msg); // reset all relay flags from message to be relayed relay_msg.set_flags(relay_msg.flags() & ~(Message::F_RELAY | Message::F_SEGMENT_RELAY)); // if F_RELAY is set in received message, relay to all peers except // the originator if (msg.flags() & Message::F_RELAY) { gu_trace(push_header(relay_msg, relay_dg)); for (SegmentMap::iterator i(segment_map_.begin()); i != segment_map_.end(); ++i) { Segment& segment(i->second); for (Segment::iterator j(segment.begin()); j != segment.end(); ++j) { if ((*j)->id() != exclude_id) { send(*j, relay_dg); } } } } else if (msg.flags() & Message::F_SEGMENT_RELAY) { if (relay_set_.empty() == false) { // send message to all nodes in relay set to reach // nodes in local segment that are not directly reachable relay_msg.set_flags(relay_msg.flags() | Message::F_RELAY); gu_trace(push_header(relay_msg, relay_dg)); for (std::set::iterator ri(relay_set_.begin()); ri != relay_set_.end(); ++ri) { send(*ri, relay_dg); } gu_trace(pop_header(relay_msg, relay_dg)); relay_msg.set_flags(relay_msg.flags() & ~Message::F_RELAY); } if (msg.segment_id() == segment_) { log_warn << "message with F_SEGMENT_RELAY from own segment, " << "source " << msg.source_uuid(); } // Relay to local segment gu_trace(push_header(relay_msg, relay_dg)); Segment& segment(segment_map_[segment_]); for (Segment::iterator i(segment.begin()); i != segment.end(); ++i) { send(*i, relay_dg); } } else { log_warn << "GMCast::relay() called without relay flags set"; } } void gcomm::GMCast::handle_up(const void* id, const Datagram& dg, const ProtoUpMeta& um) { ProtoMap::iterator i; if (listener_ == 0) { return; } if (id == listener_->id()) { gmcast_accept(); } else if (mcast_.get() != 0 && id == mcast_->id()) { Message msg; try { if (dg.offset() < dg.header_len()) { gu_trace(msg.unserialize(dg.header(), dg.header_size(), dg.header_offset() + dg.offset())); } else { gu_trace(msg.unserialize(&dg.payload()[0], dg.len(), dg.offset())); } } catch (gu::Exception& e) { GU_TRACE(e); log_warn << e.what(); return; } if (msg.type() >= Message::T_USER_BASE) { gu_trace(send_up(Datagram(dg, dg.offset() + msg.serial_size()), ProtoUpMeta(msg.source_uuid()))); } else { log_warn << "non-user message " << msg.type() << " from multicast socket"; } } else if ((i = proto_map_->find(id)) != proto_map_->end()) { Proto* p(ProtoMap::value(i)); if (dg.len() > 0) { const Proto::State prev_state(p->state()); if (prev_state == Proto::S_FAILED) { log_warn << "unhandled failed proto"; handle_failed(p); return; } Message msg; try { msg.unserialize(&dg.payload()[0], dg.len(), dg.offset()); } catch (gu::Exception& e) { GU_TRACE(e); log_warn << e.what(); p->set_state(Proto::S_FAILED); handle_failed(p); return; } if (msg.type() >= Message::T_USER_BASE) { if (evict_list().empty() == false && evict_list().find(msg.source_uuid()) != evict_list().end()) { return; } if (msg.flags() & (Message::F_RELAY | Message::F_SEGMENT_RELAY)) { relay(msg, Datagram(dg, dg.offset() + msg.serial_size()), id); } p->set_tstamp(gu::datetime::Date::now()); send_up(Datagram(dg, dg.offset() + msg.serial_size()), ProtoUpMeta(msg.source_uuid())); return; } else { try { p->set_tstamp(gu::datetime::Date::now()); gu_trace(p->handle_message(msg)); } catch (gu::Exception& e) { log_warn << "handling gmcast protocol message failed: " << e.what(); handle_failed(p); if (e.get_errno() == ENOTRECOVERABLE) { throw; } return; } if (p->state() == Proto::S_FAILED) { handle_failed(p); return; } else if (p->changed() == true) { update_addresses(); check_liveness(); reconnect(); } } if (prev_state != Proto::S_OK && p->state() == Proto::S_OK) { handle_established(p); } } else if (p->socket()->state() == Socket::S_CONNECTED && (p->state() == Proto::S_HANDSHAKE_WAIT || p->state() == Proto::S_INIT)) { handle_connected(p); } else if (p->socket()->state() == Socket::S_CONNECTED) { log_warn << "connection " << p->socket()->id() << " closed by peer"; p->set_state(Proto::S_FAILED); handle_failed(p); } else { log_debug << "socket in state " << p->socket()->state(); p->set_state(Proto::S_FAILED); handle_failed(p); } } else { // log_info << "proto entry " << id << " not found"; } } int gcomm::GMCast::handle_down(Datagram& dg, const ProtoDownMeta& dm) { Message msg(version_, Message::T_USER_BASE, uuid(), 1, segment_); // handle relay set first, skip these peers below if (relay_set_.empty() == false) { msg.set_flags(msg.flags() | Message::F_RELAY); gu_trace(push_header(msg, dg)); for (std::set::iterator ri(relay_set_.begin()); ri != relay_set_.end(); ++ri) { send(*ri, dg); } gu_trace(pop_header(msg, dg)); msg.set_flags(msg.flags() & ~Message::F_RELAY); } for (SegmentMap::iterator si(segment_map_.begin()); si != segment_map_.end(); ++si) { uint8_t segment_id(si->first); Segment& segment(si->second); if (segment_id != segment_) { size_t target_idx((self_index_ + segment_id) % segment.size()); msg.set_flags(msg.flags() | Message::F_SEGMENT_RELAY); // skip peers that are in relay set if (relay_set_.empty() == true || relay_set_.find(segment[target_idx]) == relay_set_.end()) { gu_trace(push_header(msg, dg)); send(segment[target_idx], dg); gu_trace(pop_header(msg, dg)); } } else { msg.set_flags(msg.flags() & ~Message::F_SEGMENT_RELAY); gu_trace(push_header(msg, dg)); for (Segment::iterator i(segment.begin()); i != segment.end(); ++i) { // skip peers that are in relay set if (relay_set_.empty() == true || relay_set_.find(*i) == relay_set_.end()) { send(*i, dg); } } gu_trace(pop_header(msg, dg)); } } return 0; } void gcomm::GMCast::handle_stable_view(const View& view) { log_debug << "GMCast::handle_stable_view: " << view; if (view.type() == V_PRIM) { // discard addr list entries not in view std::set gmcast_lst; for (AddrList::const_iterator i(remote_addrs_.begin()); i != remote_addrs_.end(); ++i) { gmcast_lst.insert(i->second.uuid()); } std::set view_lst; for (NodeList::const_iterator i(view.members().begin()); i != view.members().end(); ++i) { view_lst.insert(i->first); } std::list diff; std::set_difference(gmcast_lst.begin(), gmcast_lst.end(), view_lst.begin(), view_lst.end(), std::back_inserter(diff)); // Forget partitioned entries, allow them to reconnect // in time_wait_/2. Left nodes are given time_wait_ ban for // reconnecting when handling V_REG below. for (std::list::const_iterator i(diff.begin()); i != diff.end(); ++i) { gmcast_forget(*i, time_wait_/2); } // mark nodes in view as stable for (std::set::const_iterator i(view_lst.begin()); i != view_lst.end(); ++i) { AddrList::iterator ai; if ((ai = find_if(remote_addrs_.begin(), remote_addrs_.end(), AddrListUUIDCmp(*i))) != remote_addrs_.end()) { ai->second.set_retry_cnt(-1); ai->second.set_max_retries(max_retry_cnt_); } } // iterate over pending address list and discard entries without UUID for (AddrList::iterator i(pending_addrs_.begin()); i != pending_addrs_.end(); ) { AddrList::iterator i_next(i); ++i_next; const AddrEntry& ae(AddrList::value(i)); if (ae.uuid() == UUID()) { const std::string addr(AddrList::key(i)); log_info << "discarding pending addr without UUID: " << addr; for (ProtoMap::iterator pi(proto_map_->begin()); pi != proto_map_->end();) { ProtoMap::iterator pi_next(pi); ++pi_next; Proto* p(ProtoMap::value(pi)); if (p->remote_addr() == addr) { log_info << "discarding pending addr proto entry " << p; erase_proto(pi); } pi = pi_next; } pending_addrs_.erase(i); } i = i_next; } } else if (view.type() == V_REG) { for (NodeList::const_iterator i(view.members().begin()); i != view.members().end(); ++i) { AddrList::iterator ai; if ((ai = find_if(remote_addrs_.begin(), remote_addrs_.end(), AddrListUUIDCmp(NodeList::key(i)))) != remote_addrs_.end()) { log_info << "declaring " << NodeList::key(i) << " at " << handle_get_address(NodeList::key(i)) << " stable"; ai->second.set_retry_cnt(-1); ai->second.set_max_retries(max_retry_cnt_); } } // Forget left nodes for (NodeList::const_iterator i(view.left().begin()); i != view.left().end(); ++i) { gmcast_forget(NodeList::key(i), time_wait_); } } check_liveness(); for (ProtoMap::const_iterator i(proto_map_->begin()); i != proto_map_->end(); ++i) { log_debug << "proto: " << *ProtoMap::value(i); } } void gcomm::GMCast::handle_evict(const UUID& uuid) { if (is_evicted(uuid) == true) { return; } gmcast_forget(uuid, time_wait_); } std::string gcomm::GMCast::handle_get_address(const UUID& uuid) const { AddrList::const_iterator ali( find_if(remote_addrs_.begin(), remote_addrs_.end(), AddrListUUIDCmp(uuid))); return (ali == remote_addrs_.end() ? "" : AddrList::key(ali)); } void gcomm::GMCast::add_or_del_addr(const std::string& val) { if (val.compare(0, 4, "add:") == 0) { gu::URI uri(val.substr(4)); std::string addr(gu::net::resolve(uri_string(get_scheme(use_ssl_), uri.get_host(), uri.get_port())).to_string()); log_info << "inserting address '" << addr << "'"; insert_address(addr, UUID(), remote_addrs_); AddrList::iterator ai(remote_addrs_.find(addr)); AddrList::value(ai).set_max_retries( max_initial_reconnect_attempts_); AddrList::value(ai).set_retry_cnt(-1); } else if (val.compare(0, 4, "del:") == 0) { std::string addr(val.substr(4)); AddrList::iterator ai(remote_addrs_.find(addr)); if (ai != remote_addrs_.end()) { ProtoMap::iterator pi, pi_next; for (pi = proto_map_->begin(); pi != proto_map_->end(); pi = pi_next) { pi_next = pi, ++pi_next; Proto* rp = ProtoMap::value(pi); if (rp->remote_addr() == AddrList::key(ai)) { log_info << "deleting entry " << AddrList::key(ai); erase_proto(pi); } } AddrEntry& ae(AddrList::value(ai)); ae.set_max_retries(0); ae.set_retry_cnt(1); ae.set_next_reconnect(gu::datetime::Date::now() + time_wait_); update_addresses(); } else { log_info << "address '" << addr << "' not found from remote addrs list"; } } else { gu_throw_error(EINVAL) << "invalid addr spec '" << val << "'"; } } bool gcomm::GMCast::set_param(const std::string& key, const std::string& val) { if (key == Conf::GMCastMaxInitialReconnectAttempts) { max_initial_reconnect_attempts_ = gu::from_string(val); return true; } else if (key == Conf::GMCastPeerAddr) { try { add_or_del_addr(val); } catch (gu::NotFound& nf) { gu_throw_error(EINVAL) << "invalid addr spec '" << val << "'"; } catch (gu::NotSet& ns) { gu_throw_error(EINVAL) << "invalid addr spec '" << val << "'"; } return true; } else if (key == Conf::GMCastIsolate) { isolate_ = gu::from_string(val); log_info << "turning isolation " << (isolate_ == true ? "on" : "off"); if (isolate_ == true) { // delete all entries in proto map ProtoMap::iterator pi, pi_next; for (pi = proto_map_->begin(); pi != proto_map_->end(); pi = pi_next) { pi_next = pi, ++pi_next; erase_proto(pi); } segment_map_.clear(); } return true; } else if (key == Conf::GMCastGroup || key == Conf::GMCastListenAddr || key == Conf::GMCastMCastAddr || key == Conf::GMCastMCastPort || key == Conf::GMCastMCastTTL || key == Conf::GMCastTimeWait || key == Conf::GMCastPeerTimeout || key == Conf::GMCastSegment) { gu_throw_error(EPERM) << "can't change value for '" << key << "' during runtime"; } return false; } percona-galera-3-3.8-3390/gcomm/src/gmcast.hpp000066400000000000000000000171641244131713600206730ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ /* * Generic multicast transport. Uses tcp connections if real multicast * is not available. */ #ifndef GCOMM_GMCAST_HPP #define GCOMM_GMCAST_HPP #include "gmcast_proto.hpp" #include "gcomm/uuid.hpp" #include "gcomm/exception.hpp" #include "gcomm/transport.hpp" #include "gcomm/types.hpp" #include #ifndef GCOMM_GMCAST_MAX_VERSION #define GCOMM_GMCAST_MAX_VERSION 0 #endif // GCOMM_GMCAST_MAX_VERSION namespace gcomm { namespace gmcast { class Proto; class Node; class Message; } class GMCast : public Transport { public: GMCast (Protonet&, const gu::URI&, const UUID* my_uuid = NULL); ~GMCast(); // Protolay interface void handle_up(const void*, const Datagram&, const ProtoUpMeta&); int handle_down(Datagram&, const ProtoDownMeta&); void handle_stable_view(const View& view); void handle_evict(const UUID& uuid); std::string handle_get_address(const UUID& uuid) const; bool set_param(const std::string& key, const std::string& val); // Transport interface const UUID& uuid() const { return my_uuid_; } SegmentId segment() const { return segment_; } void connect_precheck(bool start_prim); void connect(); void connect(const gu::URI&); void close(bool force = false); void close(const UUID& uuid) { gmcast_forget(uuid, time_wait_); } void listen() { gu_throw_fatal << "gmcast transport listen not implemented"; } std::string listen_addr() const { if (listener_ == 0) { gu_throw_error(ENOTCONN) << "not connected"; } return listener_->listen_addr(); } Transport* accept() { gu_throw_fatal << "gmcast transport accept not implemented"; } size_t mtu() const { return pnet_.mtu() - (4 + UUID::serial_size()); } private: GMCast (const GMCast&); GMCast& operator=(const GMCast&); static const long max_retry_cnt_; class AddrEntry { public: AddrEntry(const gu::datetime::Date& last_seen, const gu::datetime::Date& next_reconnect, const UUID& uuid) : uuid_ (uuid), last_seen_ (last_seen), next_reconnect_ (next_reconnect), last_connect_ (0), retry_cnt_ (0), max_retries_ (0) { } const UUID& uuid() const { return uuid_; } void set_last_seen(const gu::datetime::Date& d) { last_seen_ = d; } const gu::datetime::Date& last_seen() const { return last_seen_; } void set_next_reconnect(const gu::datetime::Date& d) { next_reconnect_ = d; } const gu::datetime::Date& next_reconnect() const { return next_reconnect_; } void set_last_connect() { last_connect_ = gu::datetime::Date::now(); } const gu::datetime::Date& last_connect() const { return last_connect_; } void set_retry_cnt(const int r) { retry_cnt_ = r; } int retry_cnt() const { return retry_cnt_; } void set_max_retries(int mr) { max_retries_ = mr; } int max_retries() const { return max_retries_; } private: friend std::ostream& operator<<(std::ostream&, const AddrEntry&); void operator=(const AddrEntry&); UUID uuid_; gu::datetime::Date last_seen_; gu::datetime::Date next_reconnect_; gu::datetime::Date last_connect_; int retry_cnt_; int max_retries_; }; typedef Map AddrList; class AddrListUUIDCmp { public: AddrListUUIDCmp(const UUID& uuid) : uuid_(uuid) { } bool operator()(const AddrList::value_type& cmp) const { return (cmp.second.uuid() == uuid_); } private: UUID uuid_; }; int version_; static const int max_version_ = GCOMM_GMCAST_MAX_VERSION; uint8_t segment_; UUID my_uuid_; bool use_ssl_; std::string group_name_; std::string listen_addr_; std::set initial_addrs_; std::string mcast_addr_; std::string bind_ip_; int mcast_ttl_; Acceptor* listener_; SocketPtr mcast_; AddrList pending_addrs_; AddrList remote_addrs_; AddrList addr_blacklist_; bool relaying_; bool isolate_; gmcast::ProtoMap* proto_map_; std::set relay_set_; typedef std::vector Segment; typedef std::map SegmentMap; SegmentMap segment_map_; // self index in local segment when ordered by UUID size_t self_index_; gu::datetime::Period time_wait_; gu::datetime::Period check_period_; gu::datetime::Period peer_timeout_; int max_initial_reconnect_attempts_; gu::datetime::Date next_check_; gu::datetime::Date handle_timers(); // Erase ProtoMap entry in a safe way so that all lookup lists // become properly updated. void erase_proto(gmcast::ProtoMap::iterator); // Accept new connection void gmcast_accept(); // Initialize connecting to remote host void gmcast_connect(const std::string&); // Forget node void gmcast_forget(const gcomm::UUID&, const gu::datetime::Period&); // Handle proto entry that has established connection to remote host void handle_connected(gmcast::Proto*); // Handle proto entry that has succesfully finished handshake // sequence void handle_established(gmcast::Proto*); // Handle proto entry that has failed void handle_failed(gmcast::Proto*); // Check if there exists connection that matches to either // remote addr or uuid bool is_connected(const std::string& addr, const UUID& uuid) const; // Inset address to address list void insert_address(const std::string& addr, const UUID& uuid, AddrList&); // Scan through proto entries and update address lists void update_addresses(); // void check_liveness(); void relay(const gmcast::Message& msg, const Datagram& dg, const void* exclude_id); // Reconnecting void reconnect(); void set_initial_addr(const gu::URI&); void add_or_del_addr(const std::string&); std::string self_string() const { std::ostringstream os; os << '(' << my_uuid_ << ", '" << listen_addr_ << "')"; return os.str(); } friend std::ostream& operator<<(std::ostream&, const AddrEntry&); }; inline std::ostream& operator<<(std::ostream& os, const GMCast::AddrEntry& ae) { return (os << ae.uuid_ << " last_seen=" << ae.last_seen_ << " next_reconnect=" << ae.next_reconnect_ << " retry_cnt=" << ae.retry_cnt_); } } #endif // GCOMM_GMCAST_HPP percona-galera-3-3.8-3390/gcomm/src/gmcast_link.hpp000066400000000000000000000047451244131713600217110ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef GCOMM_GMCAST_LINK_HPP #define GCOMM_GMCAST_LINK_HPP #include "gcomm/uuid.hpp" #include #include namespace gcomm { namespace gmcast { class Link; class LinkMapCmp; class LinkMap; std::ostream& operator<<(std::ostream& os, const LinkMap&); } } class gcomm::gmcast::Link { public: Link(const gcomm::UUID& uuid, const std::string& addr, const std::string& mcast_addr) : uuid_ (uuid), addr_ (addr), mcast_addr_(mcast_addr) { } bool operator==(const Link& cmp) const { return (uuid_ == cmp.uuid_ && addr_ == cmp.addr_); } bool operator<(const Link& cmp) const { return (uuid_ < cmp.uuid_ || (uuid_ == cmp.uuid_ && addr_ < cmp.addr_)); } const gcomm::UUID& uuid() const { return uuid_; } const std::string& addr() const { return addr_; } const std::string& mcast_addr() const { return mcast_addr_; } private: UUID uuid_; std::string addr_; std::string mcast_addr_; }; class gcomm::gmcast::LinkMap { typedef std::set MType; public: LinkMap() : link_map_() { } typedef MType::iterator iterator; typedef MType::const_iterator const_iterator; typedef MType::value_type value_type; std::pair insert(const Link& i) { return link_map_.insert(i); } iterator begin() { return link_map_.begin(); } const_iterator begin() const { return link_map_.begin(); } iterator end() { return link_map_.end(); } const_iterator end() const { return link_map_.end(); } const_iterator find(const value_type& vt) const { return link_map_.find(vt); } size_t size() const { return link_map_.size(); } static const UUID& key(const_iterator i) { return i->uuid(); } static const Link& value(const_iterator i) { return *i; } static const UUID& key(const value_type& vt) { return vt.uuid(); } static const Link& value(const value_type& vt) { return vt; } bool operator==(const LinkMap& cmp) const { return (link_map_ == cmp.link_map_); } private: MType link_map_; }; inline std::ostream& gcomm::gmcast::operator<<(std::ostream& os, const LinkMap& lm) { for (LinkMap::const_iterator i = lm.begin(); i != lm.end(); ++i) { os << "\n(" << LinkMap::key(i) << "," << LinkMap::value(i).addr() << ")"; } return (os << "\n"); } #endif // GCOMM_GMCAST_LINK_HPP percona-galera-3-3.8-3390/gcomm/src/gmcast_message.hpp000066400000000000000000000264521244131713600223770ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #ifndef GCOMM_GMCAST_MESSAGE_HPP #define GCOMM_GMCAST_MESSAGE_HPP #include "gcomm/types.hpp" #include "gcomm/uuid.hpp" #include "gmcast_node.hpp" #include "gcomm/map.hpp" namespace gcomm { namespace gmcast { class Message; } } class gcomm::gmcast::Message { public: enum Flags { F_GROUP_NAME = 1 << 0, F_NODE_NAME = 1 << 1, F_NODE_ADDRESS_OR_ERROR = 1 << 2, F_NODE_LIST = 1 << 3, F_HANDSHAKE_UUID = 1 << 4, // relay message to all peers in the same segment (excluding source) // and to all other segments except source segment F_RELAY = 1 << 5, // relay message to all peers in the same segment F_SEGMENT_RELAY = 1 << 6 }; enum Type { T_INVALID = 0, T_HANDSHAKE = 1, T_HANDSHAKE_RESPONSE = 2, T_OK = 3, T_FAIL = 4, T_TOPOLOGY_CHANGE = 5, T_KEEPALIVE = 6, /* Leave room for future use */ T_USER_BASE = 8, T_MAX = 255 }; class NodeList : public Map { }; private: gu::byte_t version_; Type type_; gu::byte_t flags_; gu::byte_t segment_id_; gcomm::UUID handshake_uuid_; gcomm::UUID source_uuid_; gcomm::String<64> node_address_or_error_; gcomm::String<32> group_name_; Message& operator=(const Message&); NodeList node_list_; public: static const char* type_to_string (Type t) { static const char* str[T_MAX] = { "INVALID", "HANDSHAKE", "HANDSHAKE_RESPONSE", "HANDSHAKE_OK", "HANDSHAKE_FAIL", "TOPOLOGY_CHANGE", "KEEPALIVE", "RESERVED_7", "USER_BASE" }; if (T_MAX > t) return str[t]; return "UNDEFINED PACKET TYPE"; } Message(const Message& msg) : version_ (msg.version_), type_ (msg.type_), flags_ (msg.flags_), segment_id_ (msg.segment_id_), handshake_uuid_ (msg.handshake_uuid_), source_uuid_ (msg.source_uuid_), node_address_or_error_ (msg.node_address_or_error_), group_name_ (msg.group_name_), node_list_ (msg.node_list_) { } /* Default ctor */ Message () : version_ (0), type_ (T_INVALID), flags_ (0), segment_id_ (0), handshake_uuid_ (), source_uuid_ (), node_address_or_error_ (), group_name_ (), node_list_ () {} /* Ctor for handshake */ Message (int version, const Type type, const UUID& handshake_uuid, const UUID& source_uuid, uint8_t segment_id) : version_ (version), type_ (type), flags_ (F_HANDSHAKE_UUID), segment_id_ (segment_id), handshake_uuid_ (handshake_uuid), source_uuid_ (source_uuid), node_address_or_error_ (), group_name_ (), node_list_ () { if (type_ != T_HANDSHAKE) gu_throw_fatal << "Invalid message type " << type_to_string(type_) << " in handshake constructor"; } /* ok, fail and keepalive */ Message (int version, const Type type, const UUID& source_uuid, uint8_t segment_id, const std::string& error) : version_ (version), type_ (type), flags_ (error.size() > 0 ? F_NODE_ADDRESS_OR_ERROR : 0), segment_id_ (segment_id), handshake_uuid_ (), source_uuid_ (source_uuid), node_address_or_error_ (error), group_name_ (), node_list_ () { if (type_ != T_OK && type_ != T_FAIL && type_ != T_KEEPALIVE) gu_throw_fatal << "Invalid message type " << type_to_string(type_) << " in ok/fail/keepalive constructor"; } /* Ctor for user message */ Message (int version, const Type type, const UUID& source_uuid, const int ttl, uint8_t segment_id) : version_ (version), type_ (type), flags_ (0), segment_id_ (segment_id), handshake_uuid_ (), source_uuid_ (source_uuid), node_address_or_error_ (), group_name_ (), node_list_ () { if (type_ < T_USER_BASE) gu_throw_fatal << "Invalid message type " << type_to_string(type_) << " in user message constructor"; } /* Ctor for handshake response */ Message (int version, const Type type, const gcomm::UUID& handshake_uuid, const gcomm::UUID& source_uuid, const std::string& node_address, const std::string& group_name, uint8_t segment_id) : version_ (version), type_ (type), flags_ (F_GROUP_NAME | F_NODE_ADDRESS_OR_ERROR | F_HANDSHAKE_UUID), segment_id_ (segment_id), handshake_uuid_ (handshake_uuid), source_uuid_ (source_uuid), node_address_or_error_ (node_address), group_name_ (group_name), node_list_ () { if (type_ != T_HANDSHAKE_RESPONSE) gu_throw_fatal << "Invalid message type " << type_to_string(type_) << " in handshake response constructor"; } /* Ctor for topology change */ Message (int version, const Type type, const gcomm::UUID& source_uuid, const std::string& group_name, const NodeList& nodes) : version_ (version), type_ (type), flags_ (F_GROUP_NAME | F_NODE_LIST), segment_id_ (0), handshake_uuid_ (), source_uuid_ (source_uuid), node_address_or_error_ (), group_name_ (group_name), node_list_ (nodes) { if (type_ != T_TOPOLOGY_CHANGE) gu_throw_fatal << "Invalid message type " << type_to_string(type_) << " in topology change constructor"; } ~Message() { } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { size_t off; gu_trace (off = gu::serialize1(version_, buf, buflen, offset)); gu_trace (off = gu::serialize1(static_cast(type_),buf,buflen,off)); gu_trace (off = gu::serialize1(flags_, buf, buflen, off)); gu_trace (off = gu::serialize1(segment_id_, buf, buflen, off)); gu_trace (off = source_uuid_.serialize(buf, buflen, off)); if (flags_ & F_HANDSHAKE_UUID) { gu_trace(off = handshake_uuid_.serialize(buf, buflen, off)); } if (flags_ & F_NODE_ADDRESS_OR_ERROR) { gu_trace (off = node_address_or_error_.serialize(buf, buflen, off)); } if (flags_ & F_GROUP_NAME) { gu_trace (off = group_name_.serialize(buf, buflen, off)); } if (flags_ & F_NODE_LIST) { gu_trace(off = node_list_.serialize(buf, buflen, off)); } return off; } size_t read_v0(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off; gu::byte_t t; gu_trace (off = gu::unserialize1(buf, buflen, offset, t)); type_ = static_cast(t); switch (type_) { case T_HANDSHAKE: case T_HANDSHAKE_RESPONSE: case T_OK: case T_FAIL: case T_TOPOLOGY_CHANGE: case T_KEEPALIVE: case T_USER_BASE: break; default: gu_throw_error(EINVAL) << "invalid message type " << static_cast(type_); } gu_trace (off = gu::unserialize1(buf, buflen, off, flags_)); gu_trace (off = gu::unserialize1(buf, buflen, off, segment_id_)); gu_trace (off = source_uuid_.unserialize(buf, buflen, off)); if (flags_ & F_HANDSHAKE_UUID) { gu_trace(off = handshake_uuid_.unserialize(buf, buflen, off)); } if (flags_ & F_NODE_ADDRESS_OR_ERROR) { gu_trace (off = node_address_or_error_.unserialize(buf, buflen, off)); } if (flags_ & F_GROUP_NAME) { gu_trace (off = group_name_.unserialize(buf, buflen, off)); } if (flags_ & F_NODE_LIST) { gu_trace(off = node_list_.unserialize(buf, buflen, off)); } return off; } size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off; gu_trace (off = gu::unserialize1(buf, buflen, offset, version_)); switch (version_) { case 0: gu_trace (return read_v0(buf, buflen, off)); default: gu_throw_error(EPROTONOSUPPORT) << "Unsupported/unrecognized gmcast protocol version: " << version_; } } size_t serial_size() const { return 4 /* Common header: version, type, flags, segment_id */ + source_uuid_.serial_size() + (flags_ & F_HANDSHAKE_UUID ? handshake_uuid_.serial_size() : 0) /* GMCast address if set */ + (flags_ & F_NODE_ADDRESS_OR_ERROR ? node_address_or_error_.serial_size() : 0) /* Group name if set */ + (flags_ & F_GROUP_NAME ? group_name_.serial_size() : 0) /* Node list if set */ + (flags_ & F_NODE_LIST ? node_list_.serial_size() : 0); } int version() const { return version_; } Type type() const { return type_; } void set_flags(uint8_t f) { flags_ = f; } uint8_t flags() const { return flags_; } uint8_t segment_id() const { return segment_id_; } const UUID& handshake_uuid() const { return handshake_uuid_; } const UUID& source_uuid() const { return source_uuid_; } const std::string& node_address() const { return node_address_or_error_.to_string(); } const std::string& error() const { return node_address_or_error_.to_string(); } const std::string& group_name() const { return group_name_.to_string(); } const NodeList& node_list() const { return node_list_; } }; #endif // GCOMM_GMCAST_MESSAGE_HPP percona-galera-3-3.8-3390/gcomm/src/gmcast_node.hpp000066400000000000000000000032331244131713600216700ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #ifndef GMCAST_NODE_HPP #define GMCAST_NODE_HPP #include "gcomm/types.hpp" #include "gcomm/uuid.hpp" #include "gu_serialize.hpp" namespace gcomm { namespace gmcast { class Node; std::ostream& operator<<(std::ostream&, const Node&); } } class gcomm::gmcast::Node { public: Node(const std::string& addr = "") : addr_(addr), mcast_addr_("") { } const std::string& addr() const { return addr_.to_string(); } const std::string& mcast_addr() const { return mcast_addr_.to_string(); } size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off; uint32_t bits; gu_trace (off = gu::unserialize4(buf, buflen, offset, bits)); gu_trace (off = addr_.unserialize(buf, buflen, off)); gu_trace (off = mcast_addr_.unserialize(buf, buflen, off)); return off; } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { size_t off; uint32_t bits(0); gu_trace (off = gu::serialize4(bits, buf, buflen, offset)); gu_trace (off = addr_.serialize(buf, buflen, off)); gu_trace (off = mcast_addr_.serialize(buf, buflen, off)); return off; } static size_t serial_size() { return (4 + 2 * ADDR_SIZE); } private: static const size_t ADDR_SIZE = 64; gcomm::String addr_; gcomm::String mcast_addr_; }; inline std::ostream& gcomm::gmcast::operator<<(std::ostream& os, const Node& n) { return os; } #endif // GMCAST_NODE_HPP percona-galera-3-3.8-3390/gcomm/src/gmcast_proto.cpp000066400000000000000000000213421244131713600221020ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "gmcast_proto.hpp" #include "gmcast.hpp" #include "gu_uri.hpp" using std::rel_ops::operator!=; const gcomm::UUID& gcomm::gmcast::Proto::local_uuid() const { return gmcast_.uuid(); } std::ostream& gcomm::gmcast::operator<<(std::ostream& os, const Proto& p) { os << "v=" << p.version_ << "," << "lu=" << p.gmcast_.uuid() << "," << "ru=" << p.remote_uuid_ << "," << "ls=" << static_cast(p.local_segment_) << "," << "rs=" << static_cast(p.remote_segment_) << "," << "la=" << p.local_addr_ << "," << "ra=" << p.remote_addr_ << "," << "mc=" << p.mcast_addr_ << "," << "gn=" << p.group_name_ << "," << "ch=" << p.changed_ << "," << "st=" << gcomm::gmcast::Proto::to_string(p.state_) << "," << "pr=" << p.propagate_remote_ << "," << "tp=" << p.tp_ << "," << "ts=" << p.tstamp_; return os; } void gcomm::gmcast::Proto:: set_state(State new_state) { log_debug << "State change: " << to_string(state_) << " -> " << to_string(new_state); static const bool allowed[][7] = { // INIT HS_SENT HS_WAIT HSR_SENT OK FAILED CLOSED { false, true, true, false, false, true, false },// INIT { false, false, false, false, true, true, false },// HS_SENT { false, false, false, true, false, true, false },// HS_WAIT { false, false, false, false, true, true, false },// HSR_SENT { false, false, false, false, true, true, true },// OK { false, false, false, false, false, true, true },// FAILED { false, false, false, false, false, false, false } // CLOSED }; if (!allowed[state_][new_state]) { gu_throw_fatal << "Invalid state change: " << to_string(state_) << " -> " << to_string(new_state); } state_ = new_state; } void gcomm::gmcast::Proto::send_msg(const Message& msg) { gu::Buffer buf; gu_trace(serialize(msg, buf)); Datagram dg(buf); int ret = tp_->send(dg); // @todo: This can happen during congestion, figure out how to // avoid terminating connection with topology change messages. if (ret != 0) { log_debug << "Send failed: " << strerror(ret); set_state(S_FAILED); } } void gcomm::gmcast::Proto::send_handshake() { handshake_uuid_ = UUID(0, 0); Message hs (version_, Message::T_HANDSHAKE, handshake_uuid_, gmcast_.uuid(), local_segment_); send_msg(hs); set_state(S_HANDSHAKE_SENT); } void gcomm::gmcast::Proto::wait_handshake() { if (state() != S_INIT) gu_throw_fatal << "Invalid state: " << to_string(state()); set_state(S_HANDSHAKE_WAIT); } void gcomm::gmcast::Proto::handle_handshake(const Message& hs) { if (state() != S_HANDSHAKE_WAIT) gu_throw_fatal << "Invalid state: " << to_string(state()); if (hs.version() != version_) { log_warn << "incompatible protocol version: " << hs.version(); set_state(S_FAILED); return; } handshake_uuid_ = hs.handshake_uuid(); remote_uuid_ = hs.source_uuid(); remote_segment_ = hs.segment_id(); Message hsr (version_, Message::T_HANDSHAKE_RESPONSE, handshake_uuid_, gmcast_.uuid(), local_addr_, group_name_, local_segment_); send_msg(hsr); set_state(S_HANDSHAKE_RESPONSE_SENT); } void gcomm::gmcast::Proto::handle_handshake_response(const Message& hs) { if (state() != S_HANDSHAKE_SENT) gu_throw_fatal << "Invalid state: " << to_string(state()); const std::string& grp = hs.group_name(); try { if (grp != group_name_) { log_info << "handshake failed, my group: '" << group_name_ << "', peer group: '" << grp << "'"; Message failed(version_, Message::T_FAIL, gmcast_.uuid(), local_segment_, "invalid group"); send_msg(failed); set_state(S_FAILED); return; } remote_uuid_ = hs.source_uuid(); remote_segment_ = hs.segment_id(); gu::URI remote_uri(tp_->remote_addr()); remote_addr_ = uri_string(remote_uri.get_scheme(), remote_uri.get_host(), gu::URI(hs.node_address()).get_port()); if (gmcast_.is_evicted(remote_uuid_) == true) { log_info << "peer " << remote_uuid_ << " from " << remote_addr_ << " has been evicted out, rejecting connection"; Message failed(version_, Message::T_FAIL, gmcast_.uuid(), local_segment_, "evicted"); send_msg(failed); set_state(S_FAILED); return; } propagate_remote_ = true; Message ok(version_, Message::T_OK, gmcast_.uuid(), local_segment_, ""); send_msg(ok); set_state(S_OK); } catch (std::exception& e) { log_warn << "Parsing peer address '" << hs.node_address() << "' failed: " << e.what(); Message nok (version_, Message::T_FAIL, gmcast_.uuid(), local_segment_, "invalid node address"); send_msg (nok); set_state(S_FAILED); } } void gcomm::gmcast::Proto::handle_ok(const Message& hs) { if (state_ == S_OK) { log_debug << "handshake ok: " << *this; } propagate_remote_ = true; set_state(S_OK); } void gcomm::gmcast::Proto::handle_failed(const Message& hs) { log_warn << "handshake with " << remote_uuid_ << " " << remote_addr_ << " failed: '" << hs.error() << "'"; set_state(S_FAILED); if (hs.error() == "evicted") { // otherwise node use the uuid in view state file. // which is probably still in other nodes evict list. ViewState::remove_file(); gu_throw_fatal << "this node has been evicted out of the cluster, " << "gcomm backend restart is required"; } } void gcomm::gmcast::Proto::handle_topology_change(const Message& msg) { const Message::NodeList& nl(msg.node_list()); LinkMap new_map; for (Message::NodeList::const_iterator i = nl.begin(); i != nl.end(); ++i) { new_map.insert(Link(Message::NodeList::key(i), Message::NodeList::value(i).addr(), Message::NodeList::value(i).mcast_addr())); if (Message::NodeList::key(i) == remote_uuid() && mcast_addr_ == "" && Message::NodeList::value(i).mcast_addr() != "") { mcast_addr_ = Message::NodeList::value(i).mcast_addr(); } } if (link_map_ != new_map) { changed_ = true; } link_map_ = new_map; } void gcomm::gmcast::Proto::handle_keepalive(const Message& msg) { log_debug << "keepalive: " << *this; Message ok(version_, Message::T_OK, gmcast_.uuid(), local_segment_, ""); send_msg(ok); } void gcomm::gmcast::Proto::send_topology_change(LinkMap& um) { Message::NodeList nl; for (LinkMap::const_iterator i = um.begin(); i != um.end(); ++i) { if (LinkMap::key(i) == UUID::nil() || LinkMap::value(i).addr() == "") gu_throw_fatal << "nil uuid or empty address"; nl.insert_unique( std::make_pair(LinkMap::key(i), Node(LinkMap::value(i).addr()))); } Message msg(version_, Message::T_TOPOLOGY_CHANGE, gmcast_.uuid(), group_name_, nl); send_msg(msg); } void gcomm::gmcast::Proto::send_keepalive() { log_debug << "sending keepalive: " << *this; Message msg(version_, Message::T_KEEPALIVE, gmcast_.uuid(), local_segment_, ""); send_msg(msg); } void gcomm::gmcast::Proto::handle_message(const Message& msg) { switch (msg.type()) { case Message::T_HANDSHAKE: handle_handshake(msg); break; case Message::T_HANDSHAKE_RESPONSE: handle_handshake_response(msg); break; case Message::T_OK: handle_ok(msg); break; case Message::T_FAIL: handle_failed(msg); break; case Message::T_TOPOLOGY_CHANGE: handle_topology_change(msg); break; case Message::T_KEEPALIVE: handle_keepalive(msg); break; default: gu_throw_fatal << "invalid message type: " << msg.type(); } } percona-galera-3-3.8-3390/gcomm/src/gmcast_proto.hpp000066400000000000000000000104041244131713600221040ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef GCOMM_GMCAST_PROTO_HPP #define GCOMM_GMCAST_PROTO_HPP #include "gu_datetime.hpp" #include "gcomm/uuid.hpp" #include "gcomm/util.hpp" #include "socket.hpp" #include "gmcast_message.hpp" #include "gmcast_link.hpp" namespace gcomm { class GMCast; namespace gmcast { class Proto; class ProtoMap; std::ostream& operator<<(std::ostream& os, const Proto& p); } } class gcomm::gmcast::Proto { public: enum State { S_INIT, S_HANDSHAKE_SENT, S_HANDSHAKE_WAIT, S_HANDSHAKE_RESPONSE_SENT, S_OK, S_FAILED, S_CLOSED }; public: void set_state(State new_state); State state() const { return state_; } static std::string to_string (State s) { switch (s) { case S_INIT: return "INIT"; case S_HANDSHAKE_SENT: return "HANDSHAKE_SENT"; case S_HANDSHAKE_WAIT: return "HANDSHAKE_WAIT"; case S_HANDSHAKE_RESPONSE_SENT: return "HANDSHAKE_RESPONSE_SENT"; case S_OK: return "OK"; case S_FAILED: return "FAILED"; case S_CLOSED: return "CLOSED"; default: return "UNKNOWN"; } } Proto (const GMCast& gmcast, int version, SocketPtr tp, const std::string& local_addr, const std::string& remote_addr, const std::string& mcast_addr, uint8_t local_segment, const std::string& group_name) : version_ (version), handshake_uuid_ (), remote_uuid_ (), local_segment_ (local_segment), remote_segment_ (0), local_addr_ (local_addr), remote_addr_ (remote_addr), mcast_addr_ (mcast_addr), group_name_ (group_name), changed_ (false), state_ (S_INIT), propagate_remote_ (false), tp_ (tp), link_map_ (), tstamp_ (gu::datetime::Date::now()), gmcast_ (gmcast) { } ~Proto() { tp_->close(); } void send_msg(const Message& msg); void send_handshake(); void wait_handshake(); void handle_handshake(const Message& hs); void handle_handshake_response(const Message& hs); void handle_ok(const Message& hs); void handle_failed(const Message& hs); void handle_topology_change(const Message& msg); void handle_keepalive(const Message& msg); void send_topology_change(LinkMap& um); void handle_message(const Message& msg); void send_keepalive(); const gcomm::UUID& handshake_uuid() const { return handshake_uuid_; } const gcomm::UUID& local_uuid() const; const gcomm::UUID& remote_uuid() const { return remote_uuid_; } uint8_t remote_segment() const { return remote_segment_; } SocketPtr socket() const { return tp_; } const std::string& remote_addr() const { return remote_addr_; } const std::string& mcast_addr() const { return mcast_addr_; } const LinkMap& link_map() const { return link_map_; } bool changed() { bool ret = changed_; changed_ = false; return ret; } int version() const { return version_; } void set_tstamp(gu::datetime::Date ts) { tstamp_ = ts; } gu::datetime::Date tstamp() const { return tstamp_; } private: friend std::ostream& operator<<(std::ostream&, const Proto&); Proto(const Proto&); void operator=(const Proto&); int version_; gcomm::UUID handshake_uuid_; gcomm::UUID remote_uuid_; uint8_t local_segment_; uint8_t remote_segment_; std::string local_addr_; std::string remote_addr_; std::string mcast_addr_; std::string group_name_; bool changed_; State state_; bool propagate_remote_; SocketPtr tp_; LinkMap link_map_; gu::datetime::Date tstamp_; const GMCast& gmcast_; }; class gcomm::gmcast::ProtoMap : public Map { }; #endif // !GCOMM_GMCAST_PROTO_HPP percona-galera-3-3.8-3390/gcomm/src/pc.cpp000066400000000000000000000174661244131713600200170ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #include "pc.hpp" #include "pc_proto.hpp" #include "evs_proto.hpp" #include "evs_message2.hpp" #include "gmcast.hpp" #include "defaults.hpp" #include "gcomm/conf.hpp" #include "gcomm/util.hpp" #include "gu_datetime.hpp" void gcomm::PC::handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (pc_recovery_ && um.err_no() == 0 && um.has_view() && um.view().id().type() == V_PRIM) { ViewState vst(const_cast(uuid()), const_cast(um.view())); log_info << "save pc into disk"; vst.write_file(); } send_up(rb, um); } int gcomm::PC::handle_down(Datagram& wb, const ProtoDownMeta& dm) { if (wb.len() == 0) { gu_throw_error(EMSGSIZE); } return send_down(wb, dm); } size_t gcomm::PC::mtu() const { // TODO: if (gmcast_ == 0) gu_throw_fatal << "not open"; evs::UserMessage evsm; pc::UserMessage pcm(0, 0); if (gmcast_->mtu() < 2*evsm.serial_size() + pcm.serial_size()) { gu_throw_fatal << "transport max msg size too small: " << gmcast_->mtu(); } return gmcast_->mtu() - 2*evsm.serial_size() - pcm.serial_size(); } const gcomm::UUID& gcomm::PC::uuid() const { return gmcast_->uuid(); } std::string gcomm::PC::listen_addr() const { return gmcast_->listen_addr(); } void gcomm::PC::connect(bool start_prim) { try { // for backward compatibility with old approach: gcomm://0.0.0.0 start_prim = (start_prim || host_is_any (uri_.get_host())); } catch (gu::NotSet& ns) { start_prim = true; } bool wait_prim( gu::from_string( uri_.get_option(Conf::PcWaitPrim, Defaults::PcWaitPrim))); const gu::datetime::Period wait_prim_timeout( gu::from_string( uri_.get_option(Conf::PcWaitPrimTimeout, Defaults::PcWaitPrimTimeout))); // --wsrep-new-cluster specified in command line // or cluster address as gcomm://0.0.0.0 or gcomm:// // should take precedence. otherwise it's not able to bootstrap. if (start_prim) { log_info << "start_prim is enabled, turn off pc_recovery"; } else if (pc_recovery_) { wait_prim = false; } pstack_.push_proto(gmcast_); pstack_.push_proto(evs_); pstack_.push_proto(pc_); pstack_.push_proto(this); pnet().insert(&pstack_); gmcast_->connect_precheck(start_prim); gmcast_->connect(); closed_ = false; evs_->shift_to(evs::Proto::S_JOINING); pc_->connect(start_prim); // Due to #658 there is limited announce period after which // node is allowed to proceed to non-prim if other nodes // are not detected. gu::datetime::Date try_until(gu::datetime::Date::now() + announce_timeout_); while (start_prim == false && evs_->known_size() <= 1) { // Send join messages without handling them evs_->send_join(false); pnet().event_loop(gu::datetime::Sec/2); if (try_until < gu::datetime::Date::now()) { break; } } log_debug << "PC/EVS Proto initial state: " << *evs_; if (evs_->state() != evs::Proto::S_OPERATIONAL) { log_debug << "PC/EVS Proto sending join request"; evs_->send_join(); } gcomm_assert(evs_->state() == evs::Proto::S_GATHER || evs_->state() == evs::Proto::S_INSTALL || evs_->state() == evs::Proto::S_OPERATIONAL); // - Due to #658 we loop here only if node is told to start in prim. // - Fix for #680, bypass waiting prim only if explicitly required try_until = gu::datetime::Date::now() + wait_prim_timeout; while ((wait_prim == true || start_prim == true) && pc_->state() != pc::Proto::S_PRIM) { pnet().event_loop(gu::datetime::Sec/2); if (try_until < gu::datetime::Date::now()) { pc_->close(); evs_->close(); gmcast_->close(); pnet().erase(&pstack_); pstack_.pop_proto(this); pstack_.pop_proto(pc_); pstack_.pop_proto(evs_); pstack_.pop_proto(gmcast_); gu_throw_error(ETIMEDOUT) << "failed to reach primary view"; } } pc_->set_mtu(mtu()); } void gcomm::PC::connect(const gu::URI& uri) { uri_ = uri; connect(); } void gcomm::PC::close(bool force) { if (force == true) { log_info << "Forced PC close"; gmcast_->close(); // Don't bother closing PC and EVS at this point. Currently // there is no way of knowing why forced close was issued, // so graceful close of PC and/or EVS may not be safe. // pc_->close(); // evs_->close(); } else { log_debug << "PC/EVS Proto leaving"; pc_->close(); evs_->close(); gu::datetime::Date wait_until(gu::datetime::Date::now() + linger_); do { pnet().event_loop(gu::datetime::Sec/2); } while (evs_->state() != evs::Proto::S_CLOSED && gu::datetime::Date::now() < wait_until); if (evs_->state() != evs::Proto::S_CLOSED) { evs_->shift_to(evs::Proto::S_CLOSED); } if (pc_->state() != pc::Proto::S_CLOSED) { log_warn << "PCProto didn't reach closed state"; } gmcast_->close(); } pnet().erase(&pstack_); pstack_.pop_proto(this); pstack_.pop_proto(pc_); pstack_.pop_proto(evs_); pstack_.pop_proto(gmcast_); ViewState::remove_file(); closed_ = true; } void gcomm::PC::handle_get_status(gu::Status& status) const { status.insert("gcomm_uuid", uuid().full_str()); } gcomm::PC::PC(Protonet& net, const gu::URI& uri) : Transport (net, uri), gmcast_ (0), evs_ (0), pc_ (0), closed_ (true), linger_ (param( conf_, uri, Conf::PcLinger, "PT20S")), announce_timeout_(param( conf_, uri, Conf::PcAnnounceTimeout, Defaults::PcAnnounceTimeout)), pc_recovery_ (param(conf_, uri, Conf::PcRecovery, Defaults::PcRecovery)), rst_uuid_(), rst_view_() { if (uri_.get_scheme() != Conf::PcScheme) { log_fatal << "invalid uri: " << uri_.to_string(); } conf_.set(Conf::PcRecovery, gu::to_string(pc_recovery_)); bool restored = false; ViewState vst(rst_uuid_, rst_view_); if (pc_recovery_) { if (vst.read_file()) { log_info << "restore pc from disk successfully"; restored = true; } else { log_info << "restore pc from disk failed"; } } else { log_info << "skip pc recovery and remove state file"; ViewState::remove_file(); } gmcast_ = new GMCast(pnet(), uri_, restored ? &rst_uuid_ : NULL); const UUID& uuid(gmcast_->uuid()); if (uuid == UUID::nil()) { gu_throw_fatal << "invalid UUID: " << uuid; } evs::UserMessage evsum; evs_ = new evs::Proto(pnet().conf(), uuid, gmcast_->segment(), uri_, gmcast_->mtu() - 2*evsum.serial_size(), restored ? &rst_view_ : NULL); pc_ = new pc::Proto (pnet().conf(), uuid, gmcast_->segment(), uri_, restored ? &rst_view_ : NULL); conf_.set(Conf::PcLinger, gu::to_string(linger_)); } gcomm::PC::~PC() { if (!closed_) { try { close(); } catch (...) { } sleep(1); // half-hearted attempt to avoid race with client threads } delete gmcast_; delete evs_; delete pc_; } percona-galera-3-3.8-3390/gcomm/src/pc.hpp000066400000000000000000000025471244131713600200160ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "gcomm/transport.hpp" namespace gcomm { class GMCast; namespace evs { class Proto; } namespace pc { class Proto; } class PC : public Transport { public: PC (Protonet&, const gu::URI&); ~PC(); void connect(bool start_prim = false); void connect(const gu::URI&); std::string listen_addr() const; void close(bool force = false); void handle_up(const void*, const Datagram&, const ProtoUpMeta&); int handle_down(Datagram&, const ProtoDownMeta&); const UUID& uuid() const; size_t mtu() const; void handle_get_status(gu::Status& status) const; private: GMCast* gmcast_; // GMCast transport evs::Proto* evs_; // EVS protocol layer pc::Proto* pc_; // PC protocol layer bool closed_; // flag for destructor // Period to wait graceful leave gu::datetime::Period linger_; gu::datetime::Period announce_timeout_; bool pc_recovery_; UUID rst_uuid_; View rst_view_; PC(const PC&); void operator=(const PC&); }; } // namespace gcomm percona-galera-3-3.8-3390/gcomm/src/pc_message.hpp000066400000000000000000000264031244131713600215170ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #ifndef PC_MESSAGE_HPP #define PC_MESSAGE_HPP #include "gcomm/view.hpp" #include "gcomm/types.hpp" #include "gcomm/uuid.hpp" #include "gcomm/map.hpp" #include "gu_serialize.hpp" #include "protocol_version.hpp" #include namespace gcomm { namespace pc { class Node; class NodeMap; class Message; class UserMessage; class StateMessage; class InstallMessage; std::ostream& operator<<(std::ostream&, const Node&); std::ostream& operator<<(std::ostream&, const Message&); bool operator==(const Message&, const Message&); } } class gcomm::pc::Node { public: enum Flags { F_PRIM = 0x1, F_WEIGHT = 0x2, F_UN = 0x4, F_EVICTED = 0x8 }; Node(const bool prim = false, const bool un = false, const bool evicted = false, const uint32_t last_seq = std::numeric_limits::max(), const ViewId& last_prim = ViewId(V_NON_PRIM), const int64_t to_seq = -1, const int weight = -1, const SegmentId segment = 0) : prim_ (prim ), un_ (un ), evicted_ (evicted ), last_seq_ (last_seq ), last_prim_ (last_prim), to_seq_ (to_seq ), weight_ (weight), segment_ (segment) { } void set_prim (const bool val) { prim_ = val ; } void set_un (const bool un) { un_ = un ; } void set_evicted (const bool evicted) { evicted_ = evicted ; } void set_last_seq (const uint32_t seq) { last_seq_ = seq ; } void set_last_prim (const ViewId& last_prim) { last_prim_ = last_prim; } void set_to_seq (const uint64_t seq) { to_seq_ = seq ; } void set_weight (const int weight) { weight_ = weight ; } void set_segment (const SegmentId segment) { segment_ = segment ; } bool prim() const { return prim_ ; } bool un() const { return un_ ; } bool evicted() const { return evicted_ ; } uint32_t last_seq() const { return last_seq_ ; } const ViewId& last_prim() const { return last_prim_; } int64_t to_seq() const { return to_seq_ ; } int weight() const { return weight_ ; } SegmentId segment() const { return segment_ ; } // // Serialized header // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // | flags | segment id | weight ¡ // size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off = offset; uint32_t header; gu_trace (off = gu::unserialize4(buf, buflen, off, header)); prim_ = header & F_PRIM; un_ = header & F_UN; if (header & F_WEIGHT) { weight_ = header >> 24; } else { weight_ = -1; } evicted_ = header & F_EVICTED; segment_ = (header >> 16) & 0xff; gu_trace (off = gu::unserialize4(buf, buflen, off, last_seq_)); gu_trace (off = last_prim_.unserialize(buf, buflen, off)); gu_trace (off = gu::unserialize8(buf, buflen, off, to_seq_)); return off; } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { size_t off = offset; uint32_t header = 0; header |= prim_ ? F_PRIM : 0; header |= un_ ? F_UN : 0; if (weight_ >= 0) { header |= F_WEIGHT; header |= weight_ << 24; } header |= evicted_ ? F_EVICTED : 0; header |= static_cast(segment_) << 16; gu_trace (off = gu::serialize4(header, buf, buflen, off)); gu_trace (off = gu::serialize4(last_seq_, buf, buflen, off)); gu_trace (off = last_prim_.serialize(buf, buflen, off)); gu_trace (off = gu::serialize8(to_seq_, buf, buflen, off)); assert (serial_size() == (off - offset)); return off; } static size_t serial_size() { Node* node(reinterpret_cast(0)); // header return (sizeof(uint32_t) + sizeof(node->last_seq_) + ViewId::serial_size() + sizeof(node->to_seq_)); } bool operator==(const Node& cmp) const { return (prim() == cmp.prim() && un() == cmp.un() && last_seq() == cmp.last_seq() && last_prim() == cmp.last_prim() && to_seq() == cmp.to_seq() && weight() == cmp.weight() && segment() == cmp.segment() ); } std::string to_string() const { std::ostringstream ret; ret << "prim=" << prim_ << ",un=" << un_ << ",last_seq=" << last_seq_ << ",last_prim=" << last_prim_ << ",to_seq=" << to_seq_ << ",weight=" << weight_ << ",segment=" << static_cast(segment_); return ret.str(); } private: bool prim_; // Is node in prim comp bool un_; // The prim status of the node is unknown bool evicted_; // Node has been evicted permanently from the group uint32_t last_seq_; // Last seen message seq from the node ViewId last_prim_; // Last known prim comp view id for the node int64_t to_seq_; // Last known TO seq for the node int weight_; // Node weight SegmentId segment_; }; inline std::ostream& gcomm::pc::operator<<(std::ostream& os, const Node& n) { return (os << n.to_string()); } class gcomm::pc::NodeMap : public Map { }; class gcomm::pc::Message { public: enum Type {T_NONE, T_STATE, T_INSTALL, T_USER, T_MAX}; enum { F_CRC16 = 0x1, F_BOOTSTRAP = 0x2, F_WEIGHT_CHANGE = 0x4 }; static const char* to_string(Type t) { static const char* str[T_MAX] = { "NONE", "STATE", "INSTALL", "USER" }; if (t < T_MAX) return str[t]; return "unknown"; } Message(const int version = -1, const Type type = T_NONE, const uint32_t seq = 0, const NodeMap& node_map = NodeMap()) : version_ (version ), flags_ (0 ), type_ (type ), seq_ (seq ), crc16_ (0 ), node_map_(node_map) { // Note: // PC message wire format has room only for version numbers up to 15. // At version 15 (latest) the wire format must change to match // 8 bit version width of EVS. assert(version < 15); } Message(const Message& msg) : version_ (msg.version_ ), flags_ (msg.flags_ ), type_ (msg.type_ ), seq_ (msg.seq_ ), crc16_ (msg.crc16_ ), node_map_(msg.node_map_) { } virtual ~Message() { } int version() const { return version_; } Type type() const { return type_; } uint32_t seq() const { return seq_; } void flags(int flags) { flags_ = flags; } int flags() const { return flags_; } void checksum(uint16_t crc16, bool flag) { crc16_ = crc16; if (flag == true) { flags_ |= F_CRC16; } else { flags_ &= ~F_CRC16; } } uint16_t checksum() const { return crc16_; } const NodeMap& node_map() const { return node_map_; } NodeMap& node_map() { return node_map_; } const Node& node(const UUID& uuid) const { return NodeMap::value(node_map_.find_checked(uuid)); } Node& node(const UUID& uuid) { return NodeMap::value(node_map_.find_checked(uuid)); } size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off; uint32_t b; node_map_.clear(); gu_trace (off = gu::unserialize4(buf, buflen, offset, b)); version_ = b & 0x0f; if (version_ > GCOMM_PROTOCOL_MAX_VERSION) gu_throw_error (EPROTONOSUPPORT) << "Unsupported protocol varsion: " << version_; flags_ = (b & 0xf0) >> 4; type_ = static_cast((b >> 8) & 0xff); if (type_ <= T_NONE || type_ >= T_MAX) gu_throw_error (EINVAL) << "Bad type value: " << type_; crc16_ = ((b >> 16) & 0xffff); gu_trace (off = gu::unserialize4(buf, buflen, off, seq_)); if (type_ == T_STATE || type_ == T_INSTALL) { gu_trace (off = node_map_.unserialize(buf, buflen, off)); } return off; } size_t serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { size_t off; uint32_t b; b = crc16_; b <<= 8; b |= type_ & 0xff; b <<= 8; b |= version_ & 0x0f; b |= (flags_ << 4) & 0xf0; gu_trace (off = gu::serialize4(b, buf, buflen, offset)); gu_trace (off = gu::serialize4(seq_, buf, buflen, off)); if (type_ == T_STATE || type_ == T_INSTALL) { gu_trace (off = node_map_.serialize(buf, buflen, off)); } assert (serial_size() == (off - offset)); return off; } size_t serial_size() const { // header return (sizeof(uint32_t) + sizeof(seq_) + (type_ == T_STATE || type_ == T_INSTALL ? node_map_.serial_size() : 0)); } std::string to_string() const { std::ostringstream ret; ret << "pcmsg{ type=" << to_string(type_) << ", seq=" << seq_; ret << ", flags=" << std::setw(2) << std::hex << flags_; ret << ", node_map {" << node_map() << "}"; ret << '}'; return ret.str(); } private: Message& operator=(const Message&); int version_; // Message version int flags_; // Flags Type type_; // Message type uint32_t seq_; // Message seqno uint16_t crc16_; // 16-bit crc NodeMap node_map_; // Message node map }; inline std::ostream& gcomm::pc::operator<<(std::ostream& os, const Message& m) { return (os << m.to_string()); } class gcomm::pc::StateMessage : public Message { public: StateMessage(int version) : Message(version, Message::T_STATE, 0) {} }; class gcomm::pc::InstallMessage : public Message { public: InstallMessage(int version) : Message(version, Message::T_INSTALL, 0) {} }; class gcomm::pc::UserMessage : public Message { public: UserMessage(int version, uint32_t seq) : Message(version, Message::T_USER, seq) {} }; inline bool gcomm::pc::operator==(const Message& a, const Message& b) { return (a.version() == b.version() && a.checksum() == b.checksum() && a.type() == b.type() && a.seq() == b.seq() && a.node_map() == b.node_map()); } #endif // PC_MESSAGE_HPP percona-galera-3-3.8-3390/gcomm/src/pc_proto.cpp000066400000000000000000001470611244131713600212350ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "pc_proto.hpp" #include "pc_message.hpp" #include "gcomm/util.hpp" #include "gu_logger.hpp" #include "gu_macros.h" #include #include using std::rel_ops::operator!=; using std::rel_ops::operator>; // // Helpers // class SelectPrimOp { public: SelectPrimOp(gcomm::pc::Proto::SMMap& states) : states_(states) { } void operator()(const gcomm::pc::Proto::SMMap::value_type& vt) const { const gcomm::UUID& uuid(gcomm::pc::Proto::SMMap::key(vt)); const gcomm::pc::Message& msg(gcomm::pc::Proto::SMMap::value(vt)); const gcomm::pc::NodeMap& nm(msg.node_map()); gcomm::pc::NodeMap::const_iterator nm_i(nm.find(uuid)); if (nm_i == nm.end()) { gu_throw_error(EPROTO) << "protocol error, self not found from " << uuid << " state msg node list"; } if (gcomm::pc::NodeMap::value(nm_i).prim() == true) { states_.insert(vt); } } private: gcomm::pc::Proto::SMMap& states_; }; class ToSeqCmpOp { public: bool operator()(const gcomm::pc::Proto::SMMap::value_type& a, const gcomm::pc::Proto::SMMap::value_type& b) const { const gcomm::pc::Node& astate( gcomm::pc::NodeMap::value( gcomm::pc::Proto::SMMap::value(a).node_map() .find_checked(gcomm::pc::Proto::SMMap::key(a)))); const gcomm::pc::Node& bstate( gcomm::pc::NodeMap::value( gcomm::pc::Proto::SMMap::value(b).node_map() .find_checked(gcomm::pc::Proto::SMMap::key(b)))); return (astate.to_seq() < bstate.to_seq()); } }; // Return max to seq found from states, -1 if states is empty static int64_t get_max_to_seq(const gcomm::pc::Proto::SMMap& states) { if (states.empty() == true) return -1; gcomm::pc::Proto::SMMap::const_iterator max_i( max_element(states.begin(), states.end(), ToSeqCmpOp())); const gcomm::pc::Node& state( gcomm::pc::Proto::SMMap::value(max_i).node( gcomm::pc::Proto::SMMap::key(max_i))); return state.to_seq(); } static void checksum(gcomm::pc::Message& msg, gcomm::Datagram& dg) { uint16_t crc16(gcomm::crc16(dg, 4)); msg.checksum(crc16, true); gcomm::pop_header(msg, dg); gcomm::push_header(msg, dg); } static void test_checksum(gcomm::pc::Message& msg, const gcomm::Datagram& dg, size_t offset) { uint16_t msg_crc16(msg.checksum()); uint16_t crc16(gcomm::crc16(dg, offset + 4)); if (crc16 != msg_crc16) { gu_throw_fatal << "Message checksum failed"; } } std::ostream& gcomm::pc::operator<<(std::ostream& os, const gcomm::pc::Proto& p) { os << "pc::Proto{"; os << "uuid=" << p.my_uuid_ << ","; os << "start_prim=" << p.start_prim_ << ","; os << "npvo=" << p.npvo_ << ","; os << "ignore_sb=" << p.ignore_sb_ << ","; os << "ignore_quorum=" << p.ignore_quorum_ << ","; os << "state=" << p.state_ << ","; os << "last_sent_seq=" << p.last_sent_seq_ << ","; os << "checksum=" << p.checksum_ << ","; os << "instances=\n" << p.instances_ << ","; os << "state_msgs=\n" << p.state_msgs_ << ","; os << "current_view=" << p.current_view_ << ","; os << "pc_view=" << p.pc_view_ << ","; // os << "views=" << p.views_ << ","; os << "mtu=" << p.mtu_ << "}"; return os; } // // // void gcomm::pc::Proto::send_state() { log_debug << self_id() << " sending state"; StateMessage pcs(current_view_.version()); NodeMap& im(pcs.node_map()); for (NodeMap::iterator i = instances_.begin(); i != instances_.end(); ++i) { // Assume all nodes in the current view have reached current to_seq Node& local_state(NodeMap::value(i)); if (current_view_.is_member(NodeMap::key(i)) == true) { local_state.set_to_seq(to_seq()); } if (is_evicted(NodeMap::key(i)) == true) { local_state.set_evicted(true); } im.insert_unique(std::make_pair(NodeMap::key(i), local_state)); } log_debug << self_id() << " local to seq " << to_seq(); log_debug << self_id() << " sending state: " << pcs; gu::Buffer buf; serialize(pcs, buf); Datagram dg(buf); if (send_down(dg, ProtoDownMeta())) { gu_throw_fatal << "pass down failed"; } } void gcomm::pc::Proto::send_install(bool bootstrap, int weight) { gcomm_assert(bootstrap == false || weight == -1); log_debug << self_id() << " send install"; InstallMessage pci(current_view_.version()); NodeMap& im(pci.node_map()); for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { if (current_view_.members().find(SMMap::key(i)) != current_view_.members().end()) { gu_trace( im.insert_unique( std::make_pair( SMMap::key(i), SMMap::value(i).node((SMMap::key(i)))))); } } if (bootstrap == true) { pci.flags(pci.flags() | InstallMessage::F_BOOTSTRAP); log_debug << self_id() << " sending PC bootstrap message " << pci; } else if (weight != -1) { pci.flags(pci.flags() | InstallMessage::F_WEIGHT_CHANGE); Node& self(pci.node(uuid())); self.set_weight(weight); log_info << self_id() << " sending PC weight change message " << pci; } else { log_debug << self_id() << " sending install: " << pci; } gu::Buffer buf; serialize(pci, buf); Datagram dg(buf); int ret = send_down(dg, ProtoDownMeta()); if (ret != 0) { log_warn << self_id() << " sending install message failed: " << strerror(ret); } } void gcomm::pc::Proto::deliver_view(bool bootstrap) { View v(pc_view_.version(), pc_view_.id(), bootstrap); for (NodeMap::const_iterator i = instances_.begin(); i != instances_.end(); ++i) { if (current_view_.members().find(NodeMap::key(i)) == current_view_.members().end()) { v.add_partitioned(NodeMap::key(i), NodeMap::value(i).segment()); } else { v.add_member(NodeMap::key(i), NodeMap::value(i).segment()); } } ProtoUpMeta um(UUID::nil(), ViewId(), &v); log_info << v; send_up(Datagram(), um); set_stable_view(v); if (v.id().type() == V_NON_PRIM && rst_view_ && !start_prim_) { // pc recovery process. uint32_t max_view_seqno = 0; bool check = true; for(NodeMap::const_iterator i = instances_.begin(); i != instances_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); // just consider property of nodes in restored view. if (rst_view_ -> members().find(uuid) != rst_view_ -> members().end()) { const Node& node(NodeMap::value(i)); const ViewId& last_prim(node.last_prim()); if (last_prim.type() != V_NON_PRIM || last_prim.uuid() != rst_view_ -> id().uuid()) { log_warn << "node uuid: " << uuid << " last_prim(type: " << last_prim.type() << ", uuid: " << last_prim.uuid() << ") is inconsistent to " << "restored view(type: V_NON_PRIM, uuid: " << rst_view_ ->id().uuid(); check = false; break; } max_view_seqno = std::max(max_view_seqno, last_prim.seq()); } } if (check) { assert(max_view_seqno != 0); log_debug << "max_view_seqno = " << max_view_seqno << ", rst_view_seqno = " << rst_view_ -> id().seq(); log_debug << "rst_view = "; log_debug << *rst_view_; log_debug << "deliver_view = "; log_debug << v; if (rst_view_ -> id().seq() == max_view_seqno && rst_view_ -> members() == v.members()) { log_info << "promote to primary component"; // since all of them are non-primary component // we need to bootstrap. send_install(true); // clear rst_view after pc is formed, otherwise // there would be network partition when sending // install message. and if rst_view is cleared here, // then pc recovery will never happen again. } } } // if pc is formed by normal process(start_prim_=true) instead of // pc recovery process, rst_view_ won't be clear. // however this will prevent pc remerge(see is_prim function) // so we have to clear rst_view_ once pc is formed.. if (v.id().type() == V_PRIM && rst_view_) { log_info << "clear restored view"; rst_view_ = NULL; } } void gcomm::pc::Proto::mark_non_prim() { pc_view_ = View(current_view_.version(), ViewId(V_NON_PRIM, current_view_.id())); for (NodeMap::iterator i = instances_.begin(); i != instances_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); Node& inst(NodeMap::value(i)); if (current_view_.members().find(uuid) != current_view_.members().end()) { inst.set_prim(false); pc_view_.add_member(uuid, inst.segment()); } } set_prim(false); } void gcomm::pc::Proto::shift_to(const State s) { // State graph static const bool allowed[S_MAX][S_MAX] = { // Closed { false, false, false, false, false, true }, // States exch { true, false, true, false, true, true }, // Install { true, false, false, true, true, true }, // Prim { true, false, false, false, true, true }, // Trans { true, true, false, false, false, true }, // Non-prim { true, false, false, true, true, true } }; if (allowed[state()][s] == false) { gu_throw_fatal << "Forbidden state transtion: " << to_string(state()) << " -> " << to_string(s); } switch (s) { case S_CLOSED: break; case S_STATES_EXCH: state_msgs_.clear(); break; case S_INSTALL: break; case S_PRIM: { pc_view_ = View(current_view_.version(), ViewId(V_PRIM, current_view_.id())); for (NodeMap::iterator i = instances_.begin(); i != instances_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); Node& inst(NodeMap::value(i)); NodeList::const_iterator nli; if ((nli = current_view_.members().find(uuid)) != current_view_.members().end()) { inst.set_prim(true); inst.set_last_prim(ViewId(V_PRIM, current_view_.id())); inst.set_last_seq(0); inst.set_to_seq(to_seq()); pc_view_.add_member(uuid, inst.segment()); } else { inst.set_prim(false); } } last_sent_seq_ = 0; set_prim(true); break; } case S_TRANS: break; case S_NON_PRIM: mark_non_prim(); break; default: ; } log_debug << self_id() << " shift_to: " << to_string(state()) << " -> " << to_string(s) << " prim " << prim() << " last prim " << last_prim() << " to_seq " << to_seq(); state_ = s; } void gcomm::pc::Proto::handle_first_trans(const View& view) { gcomm_assert(state() == S_NON_PRIM); gcomm_assert(view.type() == V_TRANS); if (start_prim_ == true) { if (view.members().size() > 1 || view.is_empty()) { gu_throw_fatal << "Corrupted view"; } if (NodeList::key(view.members().begin()) != uuid()) { gu_throw_fatal << "Bad first UUID: " << NodeList::key(view.members().begin()) << ", expected: " << uuid(); } set_last_prim(ViewId(V_PRIM, view.id())); set_prim(true); } current_view_ = view; shift_to(S_TRANS); } // Compute weighted sum of members in node list. If member cannot be found // from node_map its weight is assumed to be zero. static size_t weighted_sum(const gcomm::NodeList& node_list, const gcomm::pc::NodeMap& node_map) { size_t sum(0); for (gcomm::NodeList::const_iterator i(node_list.begin()); i != node_list.end(); ++i) { int weight(0); gcomm::pc::NodeMap::const_iterator node_i( node_map.find(gcomm::NodeList::key(i))); if (node_i != node_map.end()) { const gcomm::pc::Node& node(gcomm::pc::NodeMap::value(node_i)); gcomm_assert(node.weight() >= 0 && node.weight() <= 0xff); weight = node.weight(); } else { weight = 0; } sum += weight; } return sum; } // Check if all members in node_list have weight associated. This is needed // to fall back to backwards compatibility mode during upgrade (all weights are // assumed to be one). See have_quorum() and have_split_brain() below. static bool have_weights(const gcomm::NodeList& node_list, const gcomm::pc::NodeMap& node_map) { for (gcomm::NodeList::const_iterator i(node_list.begin()); i != node_list.end(); ++i) { gcomm::pc::NodeMap::const_iterator node_i( node_map.find(gcomm::NodeList::key(i))); if (node_i != node_map.end()) { const gcomm::pc::Node& node(gcomm::pc::NodeMap::value(node_i)); if (node.weight() == -1) { return false; } } } return true; } bool gcomm::pc::Proto::have_quorum(const View& view, const View& pc_view) const { if (have_weights(view.members(), instances_) && have_weights(view.left(), instances_) && have_weights(pc_view.members(), instances_)) { return (weighted_sum(view.members(), instances_) * 2 + weighted_sum(view.left(), instances_) > weighted_sum(pc_view.members(), instances_)); } else { return (view.members().size()*2 + view.left().size() > pc_view.members().size()); } } bool gcomm::pc::Proto::have_split_brain(const View& view) const { if (have_weights(view.members(), instances_) && have_weights(view.left(), instances_) && have_weights(pc_view_.members(), instances_)) { return (weighted_sum(view.members(), instances_) * 2 + weighted_sum(view.left(), instances_) == weighted_sum(pc_view_.members(), instances_)); } else { return (view.members().size()*2 + view.left().size() == pc_view_.members().size()); } } void gcomm::pc::Proto::handle_trans(const View& view) { gcomm_assert(view.id().type() == V_TRANS); gcomm_assert(view.id().uuid() == current_view_.id().uuid() && view.id().seq() == current_view_.id().seq()); gcomm_assert(view.version() == current_view_.version()); log_debug << self_id() << " \n\n current view " << current_view_ << "\n\n next view " << view << "\n\n pc view " << pc_view_; if (have_quorum(view, pc_view_) == false) { if (closing_ == false && ignore_sb_ == true && have_split_brain(view)) { // configured to ignore split brain log_warn << "Ignoring possible split-brain " << "(allowed by configuration) from view:\n" << current_view_ << "\nto view:\n" << view; } else if (closing_ == false && ignore_quorum_ == true) { // configured to ignore lack of quorum log_warn << "Ignoring lack of quorum " << "(allowed by configuration) from view:\n" << current_view_ << "\nto view:\n" << view; } else { current_view_ = view; // shift_to(S_NON_PRIM); mark_non_prim(); deliver_view(); shift_to(S_TRANS); return; } } else { log_debug << self_id() << " quorum ok"; } current_view_ = view; shift_to(S_TRANS); } void gcomm::pc::Proto::handle_reg(const View& view) { gcomm_assert(view.type() == V_REG); gcomm_assert(state() == S_TRANS); if (view.is_empty() == false && view.id().seq() <= current_view_.id().seq()) { gu_throw_fatal << "Non-increasing view ids: current view " << current_view_.id() << " new view " << view.id(); } if (current_view_.version() < view.version()) { log_info << "PC protocol upgrade " << current_view_.version() << " -> " << view.version(); } else if (current_view_.version() > view.version()) { log_info << "PC protocol downgrade " << current_view_.version() << " -> " << view.version(); } current_view_ = view; views_.push_back(current_view_); if (current_view_.is_empty() == true) { shift_to(S_NON_PRIM); deliver_view(); shift_to(S_CLOSED); } else { shift_to(S_STATES_EXCH); send_state(); } } void gcomm::pc::Proto::handle_view(const View& view) { // We accept only EVS TRANS and REG views if (view.type() != V_TRANS && view.type() != V_REG) { gu_throw_fatal << "Invalid view type"; } // Make sure that self exists in view if (view.is_empty() == false && view.is_member(uuid()) == false) { gu_throw_fatal << "Self not found from non empty view: " << view; } log_debug << self_id() << " " << view; if (view.type() == V_TRANS) { if (current_view_.type() == V_NONE) { handle_first_trans(view); } else { handle_trans(view); } } else { handle_reg(view); } } // Validate state message agains local state void gcomm::pc::Proto::validate_state_msgs() const { // #622, #638 Compute max TO seq among states from prim SMMap prim_state_msgs; std::for_each(state_msgs_.begin(), state_msgs_.end(), SelectPrimOp(prim_state_msgs)); const int64_t max_to_seq(get_max_to_seq(prim_state_msgs)); for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { const UUID& msg_source_uuid(SMMap::key(i)); const Node& msg_source_state(SMMap::value(i).node(msg_source_uuid)); const NodeMap& msg_state_map(SMMap::value(i).node_map()); for (NodeMap::const_iterator si = msg_state_map.begin(); si != msg_state_map.end(); ++si) { const UUID& uuid(NodeMap::key(si)); const Node& msg_state(NodeMap::value(si)); const Node& local_state(NodeMap::value(instances_.find_checked(uuid))); if (prim() == true && msg_source_state.prim() == true && msg_state.prim() == true) { if (current_view_.is_member(uuid) == true) { // Msg source claims to come from prim view and this node // is in prim. All message prim view states must be equal // to local ones. if (msg_state.weight() == -1) { // backwards compatibility, ignore weight in state check gcomm_assert( msg_state.prim() == local_state.prim() && msg_state.last_seq() == local_state.last_seq() && msg_state.last_prim() == local_state.last_prim() && msg_state.to_seq() == local_state.to_seq()) << self_id() << " node " << uuid << " prim state message and local states not consistent:" << " msg node " << msg_state << " local state " << local_state; } else { gcomm_assert(msg_state == local_state) << self_id() << " node " << uuid << " prim state message and local states not consistent:" << " msg node " << msg_state << " local state " << local_state; } gcomm_assert(msg_state.to_seq() == max_to_seq) << self_id() << " node " << uuid << " to seq not consistent with local state:" << " max to seq " << max_to_seq << " msg state to seq " << msg_state.to_seq(); } } else if (prim() == true) { log_debug << self_id() << " node " << uuid << " from " << msg_state.last_prim() << " joining " << last_prim(); } else if (msg_state.prim() == true) { // @todo: Cross check with other state messages coming from prim log_debug << self_id() << " joining to " << msg_state.last_prim(); } } } } // @note This method is currently for sanity checking only. RTR is not // implemented yet. bool gcomm::pc::Proto::requires_rtr() const { bool ret = false; // Find maximum reported to_seq const int64_t max_to_seq(get_max_to_seq(state_msgs_)); for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { NodeMap::const_iterator ii( SMMap::value(i).node_map().find_checked(SMMap::key(i))); const Node& inst = NodeMap::value(ii); const int64_t to_seq = inst.to_seq(); const ViewId last_prim = inst.last_prim(); if (to_seq != -1 && to_seq != max_to_seq && last_prim.type() != V_NON_PRIM) { log_debug << self_id() << " RTR is needed: " << to_seq << " / " << last_prim; ret = true; } } return ret; } void gcomm::pc::Proto::cleanup_instances() { gcomm_assert(state() == S_PRIM); gcomm_assert(current_view_.type() == V_REG); NodeMap::iterator i, i_next; for (i = instances_.begin(); i != instances_.end(); i = i_next) { i_next = i, ++i_next; const UUID& uuid(NodeMap::key(i)); if (current_view_.is_member(uuid) == false) { log_debug << self_id() << " cleaning up instance " << uuid; instances_.erase(i); } else { // Clear unknow status from nodes in current view here. // New PC has been installed and if paritioning happens, // we either know for sure that the other partitioned component ends // up in non-prim, or in other case we have valid PC view to // deal with in case of remerge. NodeMap::value(i).set_un(false); } } } bool gcomm::pc::Proto::is_prim() const { bool prim(false); ViewId last_prim(V_NON_PRIM); int64_t to_seq(-1); // Check if any of instances claims to come from prim view for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { const Node& state(SMMap::value(i).node(SMMap::key(i))); if (state.prim() == true) { log_info << "Node " << SMMap::key(i) << " state prim"; prim = true; last_prim = state.last_prim(); to_seq = state.to_seq(); break; } } // Verify that all members are either coming from the same prim // view or from non-prim for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { const Node& state(SMMap::value(i).node(SMMap::key(i))); if (state.prim() == true) { if (state.last_prim() != last_prim) { gu_throw_fatal << self_id() << " last prims not consistent"; } if (state.to_seq() != to_seq) { gu_throw_fatal << self_id() << " TO seqs not consistent"; } } else { log_debug << "Non-prim " << SMMap::key(i) <<" from " << state.last_prim() << " joining prim"; } } // No members coming from prim view, check if last known prim // view can be recovered (majority of members from last prim alive) if (prim == false) { gcomm_assert(last_prim == ViewId(V_NON_PRIM)) << last_prim << " != " << ViewId(V_NON_PRIM); // First determine if there are any nodes still in unknown state. std::set un; for (NodeMap::const_iterator i(instances_.begin()); i != instances_.end(); ++i) { if (NodeMap::value(i).un() == true && current_view_.members().find(NodeMap::key(i)) == current_view_.members().end()) { un.insert(NodeMap::key(i)); } } if (un.empty() == false) { std::ostringstream oss; std::copy(un.begin(), un.end(), std::ostream_iterator(oss, " ")); log_info << "Nodes " << oss.str() << "are still in unknown state, " << "unable to rebootstrap new prim"; return false; } // Collect last prim members and evicted from state messages MultiMap last_prim_uuids; std::set evicted; for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { for (NodeMap::const_iterator j = SMMap::value(i).node_map().begin(); j != SMMap::value(i).node_map().end(); ++j) { const UUID& uuid(NodeMap::key(j)); const Node& inst(NodeMap::value(j)); if (inst.last_prim().type() != V_NON_PRIM && std::find::iterator, std::pair >( last_prim_uuids.begin(), last_prim_uuids.end(), std::make_pair(inst.last_prim(), uuid)) == last_prim_uuids.end()) { last_prim_uuids.insert(std::make_pair(inst.last_prim(), uuid)); } if (inst.evicted() == true) { evicted.insert(uuid); } } } if (last_prim_uuids.empty() == true) { log_warn << "no nodes coming from prim view, prim not possible"; return false; } // Construct greatest view set of UUIDs ignoring evicted ones std::set greatest_view; // Get range of UUIDs in greatest views const ViewId greatest_view_id(last_prim_uuids.rbegin()->first); std::pair::const_iterator, MultiMap::const_iterator> gvi = last_prim_uuids.equal_range(greatest_view_id); // Iterate over range and insert into greatest view if not evicted for (MultiMap::const_iterator i = gvi.first; i != gvi.second; ++i) { if (evicted.find(MultiMap::value(i)) == evicted.end()) { std::pair::iterator, bool> iret = greatest_view.insert( MultiMap::value(i)); // Assert that inserted UUID was unique gcomm_assert(iret.second == true); } } log_debug << self_id() << " greatest view id " << greatest_view_id; // Compute list of present view members std::set present; for (NodeList::const_iterator i = current_view_.members().begin(); i != current_view_.members().end(); ++i) { present.insert(NodeList::key(i)); } // Compute intersection of present and greatest view. If the // intersection size is the same as greatest view size, // it is safe to rebootstrap PC. std::set intersection; set_intersection(greatest_view.begin(), greatest_view.end(), present.begin(), present.end(), inserter(intersection, intersection.begin())); log_debug << self_id() << " intersection size " << intersection.size() << " greatest view size " << greatest_view.size(); if (intersection.size() == greatest_view.size()) { log_info << "re-bootstrapping prim from partitioned components"; prim = true; } } return prim; } void gcomm::pc::Proto::handle_state(const Message& msg, const UUID& source) { gcomm_assert(msg.type() == Message::T_STATE); gcomm_assert(state() == S_STATES_EXCH); gcomm_assert(state_msgs_.size() < current_view_.members().size()); log_debug << self_id() << " handle state from " << source << " " << msg; // Early check for possibly conflicting primary components. The one // with greater view id may continue (as it probably has been around // for longer timer). However, this should be configurable policy. if (prim() == true) { const Node& si(NodeMap::value(msg.node_map().find(source))); if (si.prim() == true && si.last_prim() != last_prim()) { log_warn << self_id() << " conflicting prims: my prim: " << last_prim() << " other prim: " << si.last_prim(); if ((npvo_ == true && last_prim() < si.last_prim()) || (npvo_ == false && last_prim() > si.last_prim())) { log_warn << self_id() << " discarding other prim view: " << (npvo_ == true ? "newer" : "older" ) << " overrides"; return; } else { gu_throw_fatal << self_id() << " aborting due to conflicting prims: " << (npvo_ == true ? "newer" : "older" ) << " overrides"; } } } state_msgs_.insert_unique(std::make_pair(source, msg)); if (state_msgs_.size() == current_view_.members().size()) { // Insert states from previously unseen nodes into local state map for (SMMap::const_iterator i = state_msgs_.begin(); i != state_msgs_.end(); ++i) { const NodeMap& sm_im(SMMap::value(i).node_map()); for (NodeMap::const_iterator j = sm_im.begin(); j != sm_im.end(); ++j) { const UUID& sm_uuid(NodeMap::key(j)); const Node& sm_node(NodeMap::value(j)); NodeMap::iterator local_node_i(instances_.find(sm_uuid)); if (local_node_i == instances_.end()) { const Node& sm_state(NodeMap::value(j)); instances_.insert_unique(std::make_pair(sm_uuid, sm_state)); } else { Node& local_node(NodeMap::value(local_node_i)); if (local_node.weight() == -1 && sm_node.weight() != -1) { // backwards compatibility: override weight for // instances which have been reported by old nodes // but have weights associated anyway local_node.set_weight(sm_node.weight()); } else if (local_node.weight() != sm_node.weight() && SMMap::key(i) == NodeMap::key(local_node_i)) { log_warn << self_id() << "overriding reported weight for " << NodeMap::key(local_node_i); local_node.set_weight(sm_node.weight()); } if (prim() == false && sm_node.un() == true && // note #92 local_node_i != self_i_) { // If coming from non-prim, set local instance status // to unknown if any of the state messages has it // marked unknown. If coming from prim, there is // no need to set this as it is known if the node // corresponding to local instance is in primary. local_node.set_un(true); } } } } // Validate that all state messages are consistent before proceeding gu_trace(validate_state_msgs()); if (is_prim() == true) { // @note Requires RTR does not actually have effect, but let it // be for debugging purposes until a while (void)requires_rtr(); shift_to(S_INSTALL); if (current_view_.members().find(uuid()) == current_view_.members().begin()) { send_install(false); } } else { // #571 Deliver NON-PRIM views in all cases. shift_to(S_NON_PRIM); deliver_view(); } } } void gcomm::pc::Proto::handle_install(const Message& msg, const UUID& source) { if (state() == S_PRIM) { if ((msg.flags() & Message::F_WEIGHT_CHANGE) == 0) { log_warn << "non weight changing install in S_PRIM: " << msg; } else { NodeMap::iterator local_i(instances_.find(source)); const Node& msg_n(msg.node(source)); log_info << self_id() << " changing node " << source << " weight (reg) " << NodeMap::value(local_i).weight() << " -> " << msg_n.weight(); NodeMap::value(local_i).set_weight(msg_n.weight()); if (source == uuid()) { conf_.set(gcomm::Conf::PcWeight, gu::to_string(msg_n.weight())); } } return; } else if (state() == S_TRANS) { handle_trans_install(msg, source); return; } gcomm_assert(msg.type() == Message::T_INSTALL); gcomm_assert(state() == S_INSTALL || state() == S_NON_PRIM); if ((msg.flags() & Message::F_BOOTSTRAP) == 0) { log_debug << self_id() << " handle install from " << source << " " << msg; } else { log_debug << self_id() << " handle bootstrap install from " << source << " " << msg; if (state() == S_INSTALL) { log_info << "ignoring bootstrap install in " << to_string(state()) << " state"; return; } } // Validate own state NodeMap::const_iterator mi(msg.node_map().find_checked(uuid())); const Node& m_state(NodeMap::value(mi)); if (m_state.weight() == -1) { // backwards compatibility, ignore weight in state check const Node& self_state(NodeMap::value(self_i_)); if ((m_state.prim() == self_state.prim() && m_state.last_seq() == self_state.last_seq() && m_state.last_prim() == self_state.last_prim() && m_state.to_seq() == self_state.to_seq()) == false) { gu_throw_fatal << self_id() << "Install message self state does not match, " << "message state: " << m_state << ", local state: " << NodeMap::value(self_i_); } } else { if (m_state != NodeMap::value(self_i_)) { gu_throw_fatal << self_id() << "Install message self state does not match, " << "message state: " << m_state << ", local state: " << NodeMap::value(self_i_); } } // Set TO seqno according to install message int64_t to_seq(-1); bool prim_found(false); for (mi = msg.node_map().begin(); mi != msg.node_map().end(); ++mi) { const Node& m_state = NodeMap::value(mi); // check that all TO seqs coming from prim are same if (m_state.prim() == true && to_seq != -1) { if (m_state.to_seq() != to_seq) { gu_throw_fatal << "Install message TO seqnos inconsistent"; } } if (m_state.prim() == true) { prim_found = true; to_seq = std::max(to_seq, m_state.to_seq()); } } if (prim_found == false) { // #277 // prim comp was restored from non-prims, find out max known TO seq for (mi = msg.node_map().begin(); mi != msg.node_map().end(); ++mi) { const Node& m_state = NodeMap::value(mi); to_seq = std::max(to_seq, m_state.to_seq()); } log_debug << "assigning TO seq to " << to_seq << " after restoring prim"; } log_debug << self_id() << " setting TO seq to " << to_seq; set_to_seq(to_seq); shift_to(S_PRIM); deliver_view(msg.flags() & Message::F_BOOTSTRAP); cleanup_instances(); } namespace { class ViewUUIDLT { public: bool operator()(const gcomm::NodeList::value_type& a, const gcomm::NodeList::value_type& b) const { return (a.first < b.first); } }; } // When delivering install message in trans view quorum has to be re-evaluated // as the partitioned component may have installed prim view due to higher // weight. To do this, we construct pc view that would have been installed // if install message was delivered in reg view and make quorum computation // against it. // // It is not actually known if partitioned component installed new PC, so // we mark partitioned nodes states as unknown. This is to provide deterministic // way to prevent automatic rebootstrapping of PC if some of the seen nodes // is in unknown state. void gcomm::pc::Proto::handle_trans_install(const Message& msg, const UUID& source) { gcomm_assert(msg.type() == Message::T_INSTALL); gcomm_assert(state() == S_TRANS); gcomm_assert(current_view_.type() == V_TRANS); if ((msg.flags() & Message::F_BOOTSTRAP) != 0) { log_info << "Dropping bootstrap install in TRANS state"; return; } gcomm_assert(have_quorum(current_view_, pc_view_) == true); if ((msg.flags() & Message::F_WEIGHT_CHANGE) != 0) { NodeList nl; nl.insert(current_view_.members().begin(), current_view_.members().end()); nl.insert(current_view_.left().begin(), current_view_.left().end()); if (std::includes(nl.begin(), nl.end(), pc_view_.members().begin(), pc_view_.members().end(), ViewUUIDLT()) == false) { // Weight changing install message delivered in trans view // and previous pc view has partitioned. // // Need to be very conservative: We don't know what happened to // weight change message in partitioned component, so it may not be // safe to do quorum calculation. Shift to non-prim and // wait until partitioned component comes back (or prim is // rebootstrapped). // // It would be possible to do more fine grained decisions // based on the source of the message, but to keep things simple // always go to non-prim, this is very cornerish case after all. log_info << "Weight changing trans install leads to non-prim"; mark_non_prim(); deliver_view(); for (NodeMap::const_iterator i(msg.node_map().begin()); i != msg.node_map().end(); ++i) { if (current_view_.members().find(NodeMap::key(i)) == current_view_.members().end()) { NodeMap::iterator local_i(instances_.find(NodeMap::key(i))); if (local_i == instances_.end()) { log_warn << "Node " << NodeMap::key(i) << " not found from instances"; } else { if (NodeMap::key(i) == source) { NodeMap::value(local_i).set_weight( NodeMap::value(i).weight()); if (source == uuid()) { conf_.set(gcomm::Conf::PcWeight, gu::to_string(NodeMap::value(i).weight())); } } NodeMap::value(local_i).set_un(true); } } } } else { NodeMap::iterator local_i(instances_.find(source)); const Node& msg_n(msg.node(source)); log_info << self_id() << " changing node " << source << " weight (trans) " << NodeMap::value(local_i).weight() << " -> " << msg_n.weight(); NodeMap::value(local_i).set_weight(msg_n.weight()); if (source == uuid()) { conf_.set(gcomm::Conf::PcWeight, gu::to_string(msg_n.weight())); } } } else { View new_pc_view(current_view_.version(), ViewId(V_PRIM, current_view_.id())); for (NodeMap::iterator i(instances_.begin()); i != instances_.end(); ++i) { const UUID& uuid(NodeMap::key(i)); NodeMap::const_iterator ni(msg.node_map().find(uuid)); if (ni != msg.node_map().end()) { new_pc_view.add_member(uuid, 0); } } if (have_quorum(current_view_, new_pc_view) == false || pc_view_.type() == V_NON_PRIM) { log_info << "Trans install leads to non-prim"; mark_non_prim(); deliver_view(); // Mark all nodes in install msg node map but not in current // view with unknown status. It is not known if they delivered // install message in reg view and so formed new PC. for (NodeMap::const_iterator i(msg.node_map().begin()); i != msg.node_map().end(); ++i) { if (current_view_.members().find(NodeMap::key(i)) == current_view_.members().end()) { NodeMap::iterator local_i(instances_.find(NodeMap::key(i))); if (local_i == instances_.end()) { log_warn << "Node " << NodeMap::key(i) << " not found from instances"; } else { NodeMap::value(local_i).set_un(true); } } } } } } void gcomm::pc::Proto::handle_user(const Message& msg, const Datagram& dg, const ProtoUpMeta& um) { int64_t curr_to_seq(-1); if (prim() == true) { if (um.order() == O_SAFE) { set_to_seq(to_seq() + 1); curr_to_seq = to_seq(); } } else if (current_view_.members().find(um.source()) == current_view_.members().end()) { gcomm_assert(current_view_.type() == V_TRANS); // log_debug << self_id() // << " dropping message from out of view source in non-prim"; return; } if (um.order() == O_SAFE) { Node& state(NodeMap::value(instances_.find_checked(um.source()))); if (state.last_seq() + 1 != msg.seq()) { gu_throw_fatal << "gap in message sequence: source=" << um.source() << " expected_seq=" << state.last_seq() + 1 << " seq=" << msg.seq(); } state.set_last_seq(msg.seq()); } Datagram up_dg(dg, dg.offset() + msg.serial_size()); gu_trace(send_up(up_dg, ProtoUpMeta(um.source(), pc_view_.id(), 0, um.user_type(), um.order(), curr_to_seq))); } void gcomm::pc::Proto::handle_msg(const Message& msg, const Datagram& rb, const ProtoUpMeta& um) { // EVS provides send view delivery, so this assertion // should always hold. assert(msg.version() == current_view_.version()); enum Verdict { ACCEPT, DROP, FAIL }; static const Verdict verdicts[S_MAX][Message::T_MAX] = { // Msg types // NONE, STATE, INSTALL, USER { FAIL, FAIL, FAIL, FAIL }, // Closed { FAIL, ACCEPT, FAIL, FAIL }, // States exch { FAIL, FAIL, ACCEPT, FAIL }, // INSTALL { FAIL, FAIL, ACCEPT, ACCEPT }, // PRIM { FAIL, DROP, ACCEPT, ACCEPT }, // TRANS { FAIL, ACCEPT, ACCEPT, ACCEPT } // NON-PRIM }; Message::Type msg_type(msg.type()); Verdict verdict (verdicts[state()][msg.type()]); if (verdict == FAIL) { gu_throw_fatal << "Invalid input, message " << msg.to_string() << " in state " << to_string(state()); } else if (verdict == DROP) { log_debug << "Dropping input, message " << msg.to_string() << " in state " << to_string(state()); return; } switch (msg_type) { case Message::T_STATE: gu_trace(handle_state(msg, um.source())); break; case Message::T_INSTALL: gu_trace(handle_install(msg, um.source())); break; case Message::T_USER: gu_trace(handle_user(msg, rb, um)); break; default: gu_throw_fatal << "Invalid message"; } } void gcomm::pc::Proto::handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (um.has_view() == true) { handle_view(um.view()); } else { Message msg; const gu::byte_t* b(gcomm::begin(rb)); const size_t available(gcomm::available(rb)); try { (void)msg.unserialize(b, available, 0); } catch (gu::Exception& e) { switch (e.get_errno()) { case EPROTONOSUPPORT: if (prim() == false) { gu_throw_fatal << e.what() << " terminating"; } else { log_warn << "unknown/unsupported protocol version: " << msg.version() << " dropping message"; return; } break; default: GU_TRACE(e); throw; } } if (checksum_ == true && msg.flags() & Message::F_CRC16) { test_checksum(msg, rb, rb.offset()); } try { handle_msg(msg, rb, um); } catch (gu::Exception& e) { log_error << "caught exception in PC, state dump to stderr follows:"; std::cerr << *this << std::endl; throw; } } } int gcomm::pc::Proto::handle_down(Datagram& dg, const ProtoDownMeta& dm) { switch (state()) { case S_CLOSED: case S_NON_PRIM: // Not connected to primary component return ENOTCONN; case S_STATES_EXCH: case S_INSTALL: case S_TRANS: // Transient error return EAGAIN; case S_PRIM: // Allowed to send, fall through break; case S_MAX: gu_throw_fatal << "invalid state " << state(); } if (gu_unlikely(dg.len() > mtu())) { return EMSGSIZE; } uint32_t seq(dm.order() == O_SAFE ? last_sent_seq_ + 1 : last_sent_seq_); UserMessage um(current_view_.version(), seq); push_header(um, dg); if (checksum_ == true) { checksum(um, dg); } int ret = send_down(dg, dm); if (ret == 0) { last_sent_seq_ = seq; } else if (ret != EAGAIN) { log_warn << "Proto::handle_down: " << strerror(ret); } pop_header(um, dg); return ret; } bool gcomm::pc::Proto::set_param(const std::string& key, const std::string& value) { if (key == gcomm::Conf::PcIgnoreSb) { ignore_sb_ = gu::from_string(value); conf_.set(gcomm::Conf::PcIgnoreSb, value); return true; } else if (key == gcomm::Conf::PcIgnoreQuorum) { ignore_quorum_ = gu::from_string(value); conf_.set(gcomm::Conf::PcIgnoreQuorum, value); return true; } else if (key == gcomm::Conf::PcBootstrap) { if (state() != S_NON_PRIM) { log_info << "ignoring '" << key << "' in state " << to_string(state()); } else { send_install(true); } return true; } else if (key == gcomm::Conf::PcWeight) { if (state() != S_PRIM) { gu_throw_error(EAGAIN) << "can't change weightm: state not S_PRIM, retry again"; } else { int w(gu::from_string(value)); if (w < 0 || w > 255) { gu_throw_error(ERANGE) << "value " << w << " for '" << key << "' out of range"; } weight_ = w; send_install(false, weight_); return true; } } else if (key == Conf::PcChecksum || key == Conf::PcAnnounceTimeout || key == Conf::PcLinger || key == Conf::PcNpvo || key == Conf::PcWaitPrim || key == Conf::PcWaitPrimTimeout || key == Conf::PcRecovery) { gu_throw_error(EPERM) << "can't change value for '" << key << "' during runtime"; } return false; } percona-galera-3-3.8-3390/gcomm/src/pc_proto.hpp000066400000000000000000000165251244131713600212420ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef GCOMM_PC_PROTO_HPP #define GCOMM_PC_PROTO_HPP #include #include #include "gcomm/uuid.hpp" #include "gcomm/protolay.hpp" #include "gcomm/conf.hpp" #include "pc_message.hpp" #include "defaults.hpp" #include "gu_uri.hpp" #ifndef GCOMM_PC_MAX_VERSION #define GCOMM_PC_MAX_VERSION 0 #endif // GCOMM_PC_MAX_VERSION namespace gcomm { namespace pc { class Proto; std::ostream& operator<<(std::ostream& os, const Proto& p); } } class gcomm::pc::Proto : public Protolay { public: enum State { S_CLOSED, S_STATES_EXCH, S_INSTALL, S_PRIM, S_TRANS, S_NON_PRIM, S_MAX }; static std::string to_string(const State s) { switch (s) { case S_CLOSED: return "CLOSED"; case S_STATES_EXCH: return "STATES_EXCH"; case S_INSTALL: return "INSTALL"; case S_TRANS: return "TRANS"; case S_PRIM: return "PRIM"; case S_NON_PRIM: return "NON_PRIM"; default: gu_throw_fatal << "Invalid state"; } } Proto(gu::Config& conf, const UUID& uuid, SegmentId segment, const gu::URI& uri = gu::URI("pc://"), View* rst_view = NULL) : Protolay(conf), my_uuid_ (uuid), start_prim_ (), npvo_ (param(conf, uri, Conf::PcNpvo, Defaults::PcNpvo)), ignore_quorum_ (param(conf, uri, Conf::PcIgnoreQuorum, Defaults::PcIgnoreQuorum)), ignore_sb_ (param(conf, uri, Conf::PcIgnoreSb, gu::to_string(ignore_quorum_))), closing_ (false), state_ (S_CLOSED), last_sent_seq_ (0), checksum_ (param(conf, uri, Conf::PcChecksum, Defaults::PcChecksum)), instances_ (), self_i_ (instances_.insert_unique(std::make_pair(uuid, Node()))), state_msgs_ (), current_view_ (0, V_NONE), pc_view_ (0, V_NON_PRIM), views_ (), mtu_ (std::numeric_limits::max()), weight_ (check_range(Conf::PcWeight, param(conf, uri, Conf::PcWeight, Defaults::PcWeight), 0, 0xff)), rst_view_ () { set_weight(weight_); NodeMap::value(self_i_).set_segment(segment); if (rst_view) { set_restored_view(rst_view); } conf.set(Conf::PcNpvo, gu::to_string(npvo_)); conf.set(Conf::PcIgnoreQuorum, gu::to_string(ignore_quorum_)); conf.set(Conf::PcIgnoreSb, gu::to_string(ignore_sb_)); conf.set(Conf::PcChecksum, gu::to_string(checksum_)); conf.set(Conf::PcWeight, gu::to_string(weight_)); } ~Proto() { } const UUID& uuid() const { return my_uuid_; } bool prim() const { return NodeMap::value(self_i_).prim(); } void set_prim(const bool val) { NodeMap::value(self_i_).set_prim(val); } void mark_non_prim(); const ViewId& last_prim() const { return NodeMap::value(self_i_).last_prim(); } void set_last_prim(const ViewId& vid) { gcomm_assert(vid.type() == V_PRIM); NodeMap::value(self_i_).set_last_prim(vid); } uint32_t last_seq() const { return NodeMap::value(self_i_).last_seq(); } void set_last_seq(const uint32_t seq) { NodeMap::value(self_i_).set_last_seq(seq); } int64_t to_seq() const { return NodeMap::value(self_i_).to_seq(); } void set_to_seq(const int64_t seq) { NodeMap::value(self_i_).set_to_seq(seq); } void set_weight(int weight) { NodeMap::value(self_i_).set_weight(weight); } class SMMap : public Map { }; const View& current_view() const { return current_view_; } const UUID& self_id() const { return my_uuid_; } State state() const { return state_; } void shift_to (State); void send_state (); void send_install(bool bootstrap, int weight = -1); void handle_first_trans (const View&); void handle_trans (const View&); void handle_reg (const View&); void handle_msg (const Message&, const Datagram&, const ProtoUpMeta&); void handle_up (const void*, const Datagram&, const ProtoUpMeta&); int handle_down (Datagram&, const ProtoDownMeta&); void connect(bool first) { log_debug << self_id() << " start_prim " << first; start_prim_ = first; closing_ = false; shift_to(S_NON_PRIM); } void close(bool force = false) { closing_ = true; } void handle_view (const View&); bool set_param(const std::string& key, const std::string& val); void set_mtu(size_t mtu) { mtu_ = mtu; } size_t mtu() const { return mtu_; } void set_restored_view(View* rst_view) { gcomm_assert(state_ == S_CLOSED); rst_view_ = rst_view; NodeMap::value(self_i_).set_last_prim( // set last prim just for exchanging uuid and seq. // but actually restored view is not actual prim view. ViewId(V_NON_PRIM, rst_view -> id().uuid(), rst_view -> id().seq())); } const View* restored_view() const { return rst_view_; } private: friend std::ostream& operator<<(std::ostream& os, const Proto& p); Proto (const Proto&); Proto& operator=(const Proto&); bool requires_rtr() const; bool is_prim() const; bool have_quorum(const View&, const View&) const; bool have_split_brain(const View&) const; void validate_state_msgs() const; void cleanup_instances(); void handle_state(const Message&, const UUID&); void handle_install(const Message&, const UUID&); void handle_trans_install(const Message&, const UUID&); void handle_user(const Message&, const Datagram&, const ProtoUpMeta&); void deliver_view(bool bootstrap = false); UUID const my_uuid_; // Node uuid bool start_prim_; // Is allowed to start in prim comp bool npvo_; // Newer prim view overrides bool ignore_quorum_; // Ignore lack of quorum bool ignore_sb_; // Ignore split-brain condition bool closing_; // Protocol is in closing stage State state_; // State uint32_t last_sent_seq_; // Msg seqno of last sent message bool checksum_; // Enable message checksumming NodeMap instances_; // Map of known node instances NodeMap::iterator self_i_; // Iterator pointing to self node instance SMMap state_msgs_; // Map of received state messages View current_view_; // EVS view View pc_view_; // PC view std::list views_; // List of seen views size_t mtu_; // Maximum transmission unit int weight_; // Node weight in voting View* rst_view_; // restored PC view }; #endif // PC_PROTO_HPP percona-galera-3-3.8-3390/gcomm/src/profile.hpp000066400000000000000000000157711244131713600210570ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ /*! * @file profile.hpp * * @brief Lightweight profiling utility. * * Profiling utility suitable for getting runtime code profile information * with minimal overhead. Macros profile_enter() and profile_leave() * can be inserted around the code and will be expanded to profiling * code if GCOMM_PROFILE is defined. * * Example usage: * @code * * Profile prof("prof"); * * void func() * { * if (is_true()) * { * profile_enter(prof); // This is line 227 * // Do something * // ... * profile_leave(prof); * } * else * { * profile_enter(prof); // This is line 250 * // Do something else * // ... * profile_leave(prof); * } * } * * // Somewhere else in your code * log_info << prof; * @endcode * */ #ifndef GCOMM_PROFILE_HPP #define GCOMM_PROFILE_HPP extern "C" { #include "gu_time.h" } #include #include namespace prof { // Forward declarations class Key; class Point; class Profile; std::ostream& operator<<(std::ostream&, const Key&); std::ostream& operator<<(std::ostream&, const Profile&); } /*! * Profile key storing human readable point description :: * and entry time. */ class prof::Key { public: Key(const char* const file, const char* const func, const int line) : file_(file), func_(func), line_(line) { } bool operator==(const Key& cmp) const { return (line_ == cmp.line_ && func_ == cmp.func_ && file_ == cmp.file_); } bool operator<(const Key& cmp) const { return (line_ < cmp.line_ || (line_ == cmp.line_ && (func_ < cmp.func_ || (func_ == cmp.func_ && file_ < cmp.file_)))); } std::string to_string() const { std::ostringstream os; os << *this; return os.str(); } private: friend class Point; friend class Profile; friend std::ostream& operator<<(std::ostream& os, const Key&); const char* const file_; const char* const func_; const int line_; }; inline std::ostream& prof::operator<<(std::ostream& os, const prof::Key& key) { return os << key.file_ << ":" << key.func_ << ":" << key.line_; } class prof::Point { public: Point(const Profile& prof, const char* file, const char* func, const int line); ~Point(); private: friend class Profile; const Profile& prof_; const Key key_; mutable long long int enter_time_calendar_; mutable long long int enter_time_thread_cputime_; }; /*! * Profile class for collecting statistics about profile points. */ class prof::Profile { struct PointStats { PointStats(long long int count = 0, long long int time_calendar = 0, long long int time_thread_cputime = 0) : count_ (count ), time_calendar_ (time_calendar ), time_thread_cputime_(time_thread_cputime) { } PointStats operator+(const PointStats& add) const { return PointStats(count_ + add.count_, time_calendar_ + add.time_calendar_, time_thread_cputime_ + add.time_thread_cputime_); } long long int count_; long long int time_calendar_; long long int time_thread_cputime_; }; public: /*! * Default constructor. * * @param name_ Name identifying the profile in ostream output. */ Profile(const std::string& name = "profile") : name_(name), start_time_calendar_(gu_time_calendar()), start_time_thread_cputime_(gu_time_thread_cputime()), points_() { } void enter(const Point& point) const { points_[point.key_].count_++; point.enter_time_calendar_ = gu_time_calendar(); point.enter_time_thread_cputime_ = gu_time_thread_cputime(); } void leave(const Point& point) const { long long int t_cal(gu_time_calendar()); long long int t_thdcpu(gu_time_thread_cputime()); points_[point.key_].time_calendar_ += (t_cal - point.enter_time_calendar_); points_[point.key_].time_thread_cputime_ += (t_thdcpu - point.enter_time_thread_cputime_); } void clear() { points_.clear(); } friend std::ostream& operator<<(std::ostream&, const Profile&); typedef std::map Map; std::string const name_; long long int const start_time_calendar_; long long int const start_time_thread_cputime_; mutable Map points_; }; inline prof::Point::Point(const Profile& prof, const char* file, const char* func, const int line) : prof_(prof), key_(file, func, line), enter_time_calendar_(), enter_time_thread_cputime_() { prof_.enter(*this); } inline prof::Point::~Point() { prof_.leave(*this); } /*! * Ostream operator for Profile class. */ inline std::ostream& prof::operator<<(std::ostream& os, const Profile& prof) { Profile::PointStats cumul; char prev_fill(os.fill()); os.fill(' '); os << "\nprofile name: " << prof.name_; os << std::left << std::fixed << std::setprecision(3); os << "\n\n"; os << std::setw(40) << "point"; os << std::setw(10) << "count"; os << std::setw(10) << "calendar"; os << std::setw(10) << "cpu"; os << "\n" << std::setfill('-') << std::setw(70) << "" << std::setfill(' ') << "\n"; for (Profile::Map::const_iterator i = prof.points_.begin(); i != prof.points_.end(); ++i) { os << std::setw(40) << std::left << i->first.to_string(); os << std::right; os << std::setw(10) << i->second.count_; os << std::setw(10) << double(i->second.time_calendar_)*1.e-9; os << std::setw(10) << double(i->second.time_thread_cputime_)*1.e-9; os << std::left; os << "\n"; cumul = cumul + i->second; } os << "\ntot count : " << cumul.count_; os << "\ntot calendar time : " << double(cumul.time_calendar_)*1.e-9; os << "\ntot thread cputime: " << double(cumul.time_thread_cputime_)*1.e-9; os << "\ntot ct since ctor : " << double(gu::datetime::Date::now().get_utc() - prof.start_time_calendar_)*1.e-9; os.fill(prev_fill); return os; } /* * Convenience macros for defining profile entry and leave points. * If GCOMM_PROFILE is undefined, these macros expand to no-op. */ #ifdef GCOMM_PROFILE #define profile_enter(__p) do { \ const prof::Point __point((__p), __FILE__, __FUNCTION__, __LINE__); \ #define profile_leave(__p) \ } while (0) #else #define profile_enter(__p) #define profile_leave(__p) #endif // GCOMM_PROFILE #endif // GCOMM_PROFILE_HPP percona-galera-3-3.8-3390/gcomm/src/protocol_version.hpp000066400000000000000000000003171244131713600230130ustar00rootroot00000000000000/* * Copyright (C) 2014 Codership Oy */ #ifndef GCOMM_PROTOCOL_VERSION_HPP #define GCOMM_PROTOCOL_VERSION_HPP #define GCOMM_PROTOCOL_MAX_VERSION 1 #endif // GCOMM_PROTOCOL_VERSION_HPP percona-galera-3-3.8-3390/gcomm/src/protonet.cpp000066400000000000000000000037031244131713600212540ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * * $Id$ */ #ifdef HAVE_ASIO_HPP #include "asio_protonet.hpp" #endif // HAVE_ASIO_HPP #include "gcomm/util.hpp" #include "gcomm/conf.hpp" void gcomm::Protonet::insert(Protostack* pstack) { log_debug << "insert pstack " << pstack; if (find(protos_.begin(), protos_.end(), pstack) != protos_.end()) { gu_throw_fatal; } protos_.push_back(pstack); } void gcomm::Protonet::erase(Protostack* pstack) { log_debug << "erase pstack " << pstack; std::deque::iterator i; if ((i = find(protos_.begin(), protos_.end(), pstack)) == protos_.end()) { gu_throw_fatal; } protos_.erase(i); } gu::datetime::Date gcomm::Protonet::handle_timers() { Critical crit(*this); gu::datetime::Date next_time(gu::datetime::Date::max()); { for (std::deque::iterator i = protos_.begin(); i != protos_.end(); ++i) { next_time = std::min(next_time, (*i)->handle_timers()); } } return next_time; } bool gcomm::Protonet::set_param(const std::string& key, const std::string& val) { bool ret(false); for (std::deque::iterator i(protos_.begin()); i != protos_.end(); ++i) { ret |= (*i)->set_param(key, val); } return ret; } gcomm::Protonet* gcomm::Protonet::create(gu::Config& conf) { const std::string backend(conf.get(Conf::ProtonetBackend)); const int version(conf.get(Conf::ProtonetVersion)); if (version > max_version_) { gu_throw_error(EINVAL) << "invalid protonet version: " << version; } log_info << "protonet " << backend << " version " << version; if (backend == "asio") return new AsioProtonet(conf, version); gu_throw_fatal << Conf::ProtonetBackend << " '" << backend << "' not supported"; throw; return 0; // keep compiler happy } percona-galera-3-3.8-3390/gcomm/src/protostack.cpp000066400000000000000000000034451244131713600215760ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "gcomm/protostack.hpp" #include "socket.hpp" #include "gcomm/util.hpp" void gcomm::Protostack::push_proto(Protolay* p) { Critical crit(*this); protos_.push_front(p); // connect the pushed Protolay that's now on top // with the one that was previously on top, // if we had one, of course. if (protos_.size() > 1) { gcomm::connect(protos_[1], p); } } void gcomm::Protostack::pop_proto(Protolay* p) { Critical crit(*this); assert(protos_.front() == p); if (protos_.front() != p) { log_warn << "Protolay " << p << " is not protostack front"; return; } protos_.pop_front(); if (protos_.begin() != protos_.end()) { gcomm::disconnect(*protos_.begin(), p); } } gu::datetime::Date gcomm::Protostack::handle_timers() { gu::datetime::Date ret(gu::datetime::Date::max()); Critical crit(*this); for (std::deque::reverse_iterator i = protos_.rbegin(); i != protos_.rend(); ++i) { gu::datetime::Date t((*i)->handle_timers()); if (t < ret) ret = t; } return ret; } void gcomm::Protostack::dispatch(const void* id, const Datagram& dg, const ProtoUpMeta& um) { Critical crit(*this); if (protos_.empty() == false) { protos_.back()->handle_up(id, dg, um); } } bool gcomm::Protostack::set_param(const std::string& key, const std::string& val) { bool ret(false); for (std::deque::iterator i(protos_.begin()); i != protos_.end(); ++i) { ret |= (*i)->set_param(key, val); } return ret; } percona-galera-3-3.8-3390/gcomm/src/socket.cpp000066400000000000000000000010351244131713600206660ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // #include "socket.hpp" static const std::string SocketOptPrefix = "socket."; const std::string gcomm::Socket::OptNonBlocking = SocketOptPrefix + "non_blocking"; const std::string gcomm::Socket::OptIfAddr = SocketOptPrefix + "if_addr"; const std::string gcomm::Socket::OptIfLoop = SocketOptPrefix + "if_loop"; const std::string gcomm::Socket::OptCRC32 = SocketOptPrefix + "crc32"; const std::string gcomm::Socket::OptMcastTTL = SocketOptPrefix + "mcast_ttl"; percona-galera-3-3.8-3390/gcomm/src/socket.hpp000066400000000000000000000042561244131713600207030ustar00rootroot00000000000000// // Copyright (C) 2009 Codership Oy // //! // @file socket.hpp Socket interface. // // This file defines socket interface used by gcomm. Currently socket interface // provides synchronous send() but only async_recv(). // #ifndef GCOMM_SOCKET_HPP #define GCOMM_SOCKET_HPP #include "gcomm/datagram.hpp" #include "gu_uri.hpp" namespace gcomm { typedef const void* SocketId; //!< Socket Identifier class Socket; //!< Socket interface typedef boost::shared_ptr SocketPtr; class Acceptor; //!< Acceptor interfacemat } class gcomm::Socket { public: typedef enum { S_CLOSED, S_CONNECTING, S_CONNECTED, S_FAILED, S_CLOSING } State; /*! * Symbolic option names (to specify in URI) */ static const std::string OptNonBlocking; /*! socket.non_blocking */ static const std::string OptIfAddr; /*! socket.if_addr */ static const std::string OptIfLoop; /*! socket.if_loop */ static const std::string OptCRC32; /*! socket.crc32 */ static const std::string OptMcastTTL; /*! socket.mcast_ttl */ Socket(const gu::URI& uri) : uri_(uri) { } virtual ~Socket() { } virtual void connect(const gu::URI& uri) = 0; virtual void close() = 0; virtual int send(const Datagram& dg) = 0; virtual void async_receive() = 0; virtual size_t mtu() const = 0; virtual std::string local_addr() const = 0; virtual std::string remote_addr() const = 0; virtual State state() const = 0; virtual SocketId id() const = 0; protected: const gu::URI uri_; }; class gcomm::Acceptor { public: typedef enum { S_CLOSED, S_LISTENING, S_FAILED } State; Acceptor(const gu::URI& uri) : uri_(uri) { } virtual ~Acceptor() { } virtual void listen(const gu::URI& uri) = 0; virtual std::string listen_addr() const = 0; virtual void close() = 0; virtual State state() const = 0; virtual SocketPtr accept() = 0; virtual SocketId id() const = 0; protected: const gu::URI uri_; }; #endif // GCOMM_SOCKET_HPP percona-galera-3-3.8-3390/gcomm/src/transport.cpp000066400000000000000000000030151244131713600214320ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #include "gcomm/transport.hpp" #include "socket.hpp" #include "gmcast.hpp" #include "pc.hpp" #include "gcomm/conf.hpp" // Public methods const gcomm::UUID& gcomm::Transport::uuid() const { gu_throw_fatal << "UUID not supported by " + uri_.get_scheme(); } std::string gcomm::Transport::local_addr() const { gu_throw_fatal << "get local url not supported"; } std::string gcomm::Transport::remote_addr() const { gu_throw_fatal << "get remote url not supported"; } int gcomm::Transport::err_no() const { return error_no_; } void gcomm::Transport::listen() { gu_throw_fatal << "not supported"; } gcomm::Transport* gcomm::Transport::accept() { gu_throw_fatal << "not supported"; } // CTOR/DTOR gcomm::Transport::Transport(Protonet& pnet, const gu::URI& uri) : Protolay(pnet.conf()), pstack_(), pnet_(pnet), uri_(uri), error_no_(0) { } gcomm::Transport::~Transport() { } gcomm::Transport* gcomm::Transport::create(Protonet& pnet, const gu::URI& uri) { const std::string& scheme = uri.get_scheme(); if (scheme == Conf::GMCastScheme) { return new GMCast(pnet, uri); } else if (scheme == Conf::PcScheme) { return new PC(pnet, uri); } gu_throw_fatal << "scheme '" << uri.get_scheme() << "' not supported"; } gcomm::Transport* gcomm::Transport::create(Protonet& pnet, const std::string& uri_str) { return create(pnet, gu::URI(uri_str)); } percona-galera-3-3.8-3390/gcomm/src/uuid.cpp000066400000000000000000000002441244131713600203450ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "gcomm/uuid.hpp" const gcomm::UUID gcomm::UUID::uuid_nil_ = gcomm::UUID(GU_UUID_NIL); percona-galera-3-3.8-3390/gcomm/src/view.cpp000066400000000000000000000176001244131713600203550ustar00rootroot00000000000000/* * Copyright (C) 2009-2012 Codership Oy */ #include "common/common.h" #include "gcomm/view.hpp" #include "gcomm/types.hpp" #include "gcomm/util.hpp" #include "gu_logger.hpp" #include "gu_exception.hpp" #include #include size_t gcomm::ViewId::unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset) { size_t off; gu_trace (off = uuid_.unserialize(buf, buflen, offset)); uint32_t w; gu_trace (off = gu::unserialize4(buf, buflen, off, w)); seq_ = w & 0x3fffffff; type_ = static_cast(w >> 30); return off; } size_t gcomm::ViewId::serialize(gu::byte_t* buf, const size_t buflen, const size_t offset) const { size_t off; gcomm_assert(type_ != V_NONE); gu_trace (off = uuid_.serialize(buf, buflen, offset)); uint32_t w((seq_ & 0x3fffffff) | (type_ << 30)); gu_trace (off = gu::serialize4(w, buf, buflen, off)); return off; } static std::string to_string(const gcomm::ViewType type) { switch (type) { case gcomm::V_TRANS: return "TRANS"; case gcomm::V_REG: return "REG"; case gcomm::V_NON_PRIM: return "NON_PRIM"; case gcomm::V_PRIM: return "PRIM"; default: return "UNKNOWN"; // gcomm_throw_fatal << "Invalid type value"; } } std::ostream& gcomm::operator<<(std::ostream& os, const gcomm::ViewId& vi) { return (os << "view_id(" << ::to_string(vi.type()) << "," << vi.uuid() << "," << vi.seq()) << ")"; } void gcomm::View::add_member(const UUID& pid, SegmentId segment) { gu_trace((void)members_.insert_unique(std::make_pair(pid, Node(segment)))); } void gcomm::View::add_members(NodeList::const_iterator begin, NodeList::const_iterator end) { for (NodeList::const_iterator i = begin; i != end; ++i) { gu_trace((void)members_.insert_unique( std::make_pair(NodeList::key(i), NodeList::value(i)))); } } void gcomm::View::add_joined(const UUID& pid, SegmentId segment) { gu_trace((void)joined_.insert_unique(std::make_pair(pid, Node(segment)))); } void gcomm::View::add_left(const UUID& pid, SegmentId segment) { gu_trace((void)left_.insert_unique(std::make_pair(pid, Node(segment)))); } void gcomm::View::add_partitioned(const UUID& pid, SegmentId segment) { gu_trace((void)partitioned_.insert_unique(std::make_pair(pid, Node(segment)))); } const gcomm::NodeList& gcomm::View::members() const { return members_; } const gcomm::NodeList& gcomm::View::joined() const { return joined_; } const gcomm::NodeList& gcomm::View::left() const { return left_; } const gcomm::NodeList& gcomm::View::partitioned() const { return partitioned_; } gcomm::ViewType gcomm::View::type() const { return view_id_.type(); } const gcomm::ViewId& gcomm::View::id() const { return view_id_; } const gcomm::UUID& gcomm::View::representative() const { if (members_.empty()) { return UUID::nil(); } else { return NodeList::key(members_.begin()); } } bool gcomm::View::is_empty() const { return (view_id_.uuid() == UUID::nil() && members_.size() == 0); } bool gcomm::operator==(const gcomm::View& a, const gcomm::View& b) { return (a.id() == b.id() && a.members() == b.members() && a.joined() == b.joined() && a.left() == b.left() && a.partitioned() == b.partitioned()); } std::ostream& gcomm::operator<<(std::ostream& os, const gcomm::View& view) { os << "view("; if (view.is_empty() == true) { os << "(empty)"; } else { os << view.id(); os << " memb {\n"; os << view.members(); os << "} joined {\n"; os << view.joined(); os << "} left {\n"; os << view.left(); os << "} partitioned {\n"; os << view.partitioned(); os << "}"; } os << ")"; return os; } std::ostream& gcomm::View::write_stream(std::ostream& os) const { os << "#vwbeg" << std::endl; os << "view_id: "; view_id_.write_stream(os) << std::endl; os << "bootstrap: " << bootstrap_ << std::endl; for(NodeList::const_iterator it = members_.begin(); it != members_.end(); ++it) { const UUID& uuid(it -> first); const Node& node(it -> second); os << "member: "; uuid.write_stream(os) << " "; node.write_stream(os) << std::endl; } os << "#vwend" << std::endl; return os; } std::istream& gcomm::View::read_stream(std::istream& is) { std::string line; while(is.good()) { getline(is, line); std::istringstream istr(line); std::string param; istr >> param; if (param == "#vwbeg") continue; else if (param == "#vwend") break; if (param == "view_id:") { view_id_.read_stream(istr); } else if (param == "bootstrap:") { istr >> bootstrap_; } else if (param == "member:") { UUID uuid; Node node(0); uuid.read_stream(istr); node.read_stream(istr); add_member(uuid, node.segment()); } } return is; } std::ostream& gcomm::ViewState::write_stream(std::ostream& os) const { os << "my_uuid: "; my_uuid_.write_stream(os) << std::endl; view_.write_stream(os); return os; } std::istream& gcomm::ViewState::read_stream(std::istream& is) { std::string param; std::string line; while(is.good()) { getline(is, line); std::istringstream istr(line); istr >> param; if (param == "my_uuid:") { my_uuid_.read_stream(istr); } else if (param == "#vwbeg") { // read from next line. view_.read_stream(is); } } return is; } void gcomm::ViewState::write_file(const char* fname) const { if (fname == NULL) fname = COMMON_VIEW_STAT_FILE; // write to temporary file first. std::string tmp(fname); tmp += ".tmp"; FILE* fout = fopen(tmp.c_str(), "w"); if (fout == NULL) { log_warn << "open file(" << tmp << ") failed(" << strerror(errno) << ")"; return ; } std::ostringstream os; try { write_stream(os); } catch (const std::exception& e) { log_warn << "write ostringstream failed(" << e.what() << ")"; fclose(fout); return ; } std::string content(os.str()); if (fwrite(content.c_str(), content.size(), 1, fout) == 0) { log_warn << "write file(" << tmp << ") failed(" << strerror(errno) << ")"; fclose(fout); return ; } // fflush is called inside. if (fclose(fout) != 0){ log_warn << "close file(" << tmp << ") failed(" << strerror(errno) << ")"; return ; } // rename atomically. if (rename(tmp.c_str(), fname) != 0) { log_warn << "rename file(" << tmp << ") to file(" << fname << ") failed(" << strerror(errno) << ")"; } } bool gcomm::ViewState::read_file(const char* fname) { if (fname == NULL) fname = COMMON_VIEW_STAT_FILE; if (access(fname, R_OK) != 0) { log_warn << "access file(" << fname << ") failed(" << strerror(errno) << ")"; return false; } try { std::ifstream ifs(fname, std::ifstream::in); read_stream(ifs); ifs.close(); return true; } catch (const std::exception& e) { log_warn << "read file(" << fname << ") failed(" << e.what() << ")"; return false; } } void gcomm::ViewState::remove_file(const char* fname) { if (fname == NULL) fname = COMMON_VIEW_STAT_FILE; (void) unlink(fname); } percona-galera-3-3.8-3390/gcomm/test/000077500000000000000000000000001244131713600170635ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcomm/test/SConscript000066400000000000000000000015211244131713600210740ustar00rootroot00000000000000 Import('check_env') env = check_env.Clone() env.Prepend(LIBS=File('#/galerautils/src/libgalerautils.a')) env.Prepend(LIBS=File('#/galerautils/src/libgalerautils++.a')) env.Prepend(LIBS=File('#/gcomm/src/libgcomm.a')) gcomm_check = env.Program(target = 'check_gcomm', source = Split(''' check_gcomm.cpp check_trace.cpp check_types.cpp check_util.cpp check_gmcast.cpp check_evs2.cpp check_pc.cpp ''')) env.Test("gcomm_check.passed", gcomm_check) Clean(gcomm_check, '#/check_gcomm.log') ssl_test = env.Program(target = 'ssl_test', source = ['ssl_test.cpp']) percona-galera-3-3.8-3390/gcomm/test/check_evs2.cpp000066400000000000000000001706061244131713600216150ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * * $Id$ */ /*! * @file Unit tests for refactored EVS */ #include "evs_proto.hpp" #include "evs_input_map2.hpp" #include "evs_message2.hpp" #include "evs_seqno.hpp" #include "check_gcomm.hpp" #include "check_templ.hpp" #include "check_trace.hpp" #include "gcomm/conf.hpp" #include #include #include #include "check.h" using namespace std; using namespace std::rel_ops; using namespace gu::datetime; using namespace gcomm; using namespace gcomm::evs; using gu::DeleteObject; void init_rand() { unsigned int seed(static_cast(time(0))); log_info << "rand seed " << seed; srand(seed); } void init_rand(unsigned int seed) { log_info << "rand seed " << seed; srand(seed); } START_TEST(test_range) { log_info << "START"; Range r(3, 6); check_serialization(r, 2 * sizeof(seqno_t), Range()); } END_TEST START_TEST(test_message) { log_info << "START"; UUID uuid1(0, 0); ViewId view_id(V_TRANS, uuid1, 4567); seqno_t seq(478), aru_seq(456), seq_range(7); UserMessage um(0, uuid1, view_id, seq, aru_seq, seq_range, O_SAFE, 75433, 0xab, Message::F_SOURCE); fail_unless(um.serial_size() % 4 == 0); check_serialization(um, um.serial_size(), UserMessage()); AggregateMessage am(0xab, 17457, 0x79); check_serialization(am, 4, AggregateMessage()); DelegateMessage dm(0, uuid1, view_id); dm.set_source(uuid1); check_serialization(dm, dm.serial_size(), DelegateMessage()); MessageNodeList node_list; node_list.insert(make_pair(uuid1, MessageNode())); node_list.insert(make_pair(UUID(2), MessageNode(true, false, 254, true, 1, ViewId(V_REG), 5, Range(7, 8)))); JoinMessage jm(0, uuid1, view_id, 8, 5, 27, node_list); jm.set_source(uuid1); check_serialization(jm, jm.serial_size(), JoinMessage()); InstallMessage im(0, uuid1, view_id, ViewId(V_REG, view_id.uuid(), view_id.seq()), 8, 5, 27, node_list); im.set_source(uuid1); check_serialization(im, im.serial_size(), InstallMessage()); LeaveMessage lm(0, uuid1, view_id, 45, 88, 3456); lm.set_source(uuid1); check_serialization(lm, lm.serial_size(), LeaveMessage()); DelayedListMessage dlm(0, uuid1, view_id, 4576); dlm.add(UUID(2), 23); dlm.add(UUID(3), 45); dlm.add(UUID(5), 255); check_serialization(dlm, dlm.serial_size(), DelayedListMessage()); } END_TEST START_TEST(test_input_map_insert) { log_info << "START"; UUID uuid1(1), uuid2(2); InputMap im; ViewId view(V_REG, uuid1, 0); try { im.insert(0, UserMessage(0, uuid1, view, 0)); fail(""); } catch (...) { } im.reset(1); im.insert(0, UserMessage(0, uuid1, view, 0)); im.clear(); im.reset(2); for (seqno_t s = 0; s < 10; ++s) { im.insert(0, UserMessage(0, uuid1, view, s)); im.insert(1, UserMessage(0, uuid2, view, s)); } for (seqno_t s = 0; s < 10; ++s) { InputMap::iterator i = im.find(0, s); fail_if(i == im.end()); fail_unless(InputMapMsgIndex::value(i).msg().source() == uuid1); fail_unless(InputMapMsgIndex::value(i).msg().seq() == s); i = im.find(1, s); fail_if(i == im.end()); fail_unless(InputMapMsgIndex::value(i).msg().source() == uuid2); fail_unless(InputMapMsgIndex::value(i).msg().seq() == s); } } END_TEST START_TEST(test_input_map_find) { log_info << "START"; InputMap im; UUID uuid1(1); ViewId view(V_REG, uuid1, 0); im.reset(1); im.insert(0, UserMessage(0, uuid1, view, 0)); fail_if(im.find(0, 0) == im.end()); im.insert(0, UserMessage(0, uuid1, view, 2)); im.insert(0, UserMessage(0, uuid1, view, 4)); im.insert(0, UserMessage(0, uuid1, view, 7)); fail_if(im.find(0, 2) == im.end()); fail_if(im.find(0, 4) == im.end()); fail_if(im.find(0, 7) == im.end()); fail_unless(im.find(0, 3) == im.end()); fail_unless(im.find(0, 5) == im.end()); fail_unless(im.find(0, 6) == im.end()); fail_unless(im.find(0, 8) == im.end()); } END_TEST START_TEST(test_input_map_safety) { log_info << "START"; InputMap im; UUID uuid1(1); size_t index1(0); ViewId view(V_REG, uuid1, 0); im.reset(1); im.insert(index1, UserMessage(0, uuid1, view, 0)); fail_unless(im.aru_seq() == 0); im.insert(index1, UserMessage(0, uuid1, view, 1)); fail_unless(im.aru_seq() == 1); im.insert(index1, UserMessage(0, uuid1, view, 2)); fail_unless(im.aru_seq() == 2); im.insert(index1, UserMessage(0, uuid1, view, 3)); fail_unless(im.aru_seq() == 3); im.insert(index1, UserMessage(0, uuid1, view, 5)); fail_unless(im.aru_seq() == 3); im.insert(index1, UserMessage(0, uuid1, view, 4)); fail_unless(im.aru_seq() == 5); InputMap::iterator i = im.find(index1, 0); fail_unless(im.is_fifo(i) == true); fail_unless(im.is_agreed(i) == true); fail_if(im.is_safe(i) == true); im.set_safe_seq(index1, 0); fail_unless(im.is_safe(i) == true); im.set_safe_seq(index1, 5); i = im.find(index1, 5); fail_unless(im.is_safe(i) == true); im.insert(index1, UserMessage(0, uuid1, view, 7)); im.set_safe_seq(index1, im.aru_seq()); i = im.find(index1, 7); fail_if(im.is_safe(i) == true); } END_TEST START_TEST(test_input_map_erase) { log_info << "START"; InputMap im; size_t index1(0); UUID uuid1(1); ViewId view(V_REG, uuid1, 1); im.reset(1); for (seqno_t s = 0; s < 10; ++s) { im.insert(index1, UserMessage(0, uuid1, view, s)); } for (seqno_t s = 0; s < 10; ++s) { InputMap::iterator i = im.find(index1, s); fail_unless(i != im.end()); im.erase(i); i = im.find(index1, s); fail_unless(i == im.end()); (void)im.recover(index1, s); } im.set_safe_seq(index1, 9); try { im.recover(index1, 9); fail(""); } catch (...) { } } END_TEST START_TEST(test_input_map_overwrap) { log_info << "START"; InputMap im; const size_t n_nodes(5); ViewId view(V_REG, UUID(1), 1); vector uuids; for (size_t n = 0; n < n_nodes; ++n) { uuids.push_back(UUID(static_cast(n + 1))); } im.reset(n_nodes); Date start(Date::now()); size_t cnt(0); seqno_t last_safe(-1); for (seqno_t seq = 0; seq < 100000; ++seq) { for (size_t i = 0; i < n_nodes; ++i) { UserMessage um(0, uuids[i], view, seq); (void)im.insert(i, um); if ((seq + 5) % 10 == 0) { last_safe = um.seq() - 3; im.set_safe_seq(i, last_safe); for (InputMap::iterator ii = im.begin(); ii != im.end() && im.is_safe(ii) == true; ii = im.begin()) { im.erase(ii); } } cnt++; } gcomm_assert(im.aru_seq() == seq); gcomm_assert(im.safe_seq() == last_safe); } Date stop(Date::now()); double div(double(stop.get_utc() - start.get_utc())/gu::datetime::Sec); log_info << "input map msg rate " << double(cnt)/div; } END_TEST class InputMapInserter { public: InputMapInserter(InputMap& im) : im_(im) { } void operator()(const pair& p) const { im_.insert(p.first, p.second); } private: InputMap& im_; }; START_TEST(test_input_map_random_insert) { log_info << "START"; init_rand(); seqno_t window(1024); seqno_t n_seqnos(1024); size_t n_uuids(4); vector uuids(n_uuids); vector > msgs(static_cast(n_uuids*n_seqnos)); ViewId view_id(V_REG, UUID(1), 1); InputMap im; for (size_t i = 0; i < n_uuids; ++i) { uuids[i] = (static_cast(i + 1)); } im.reset(n_uuids, window); for (seqno_t j = 0; j < n_seqnos; ++j) { for (size_t i = 0; i < n_uuids; ++i) { msgs[static_cast(j*n_uuids) + i] = make_pair(i, UserMessage(0, uuids[i], view_id, j)); } } vector > random_msgs(msgs); random_shuffle(random_msgs.begin(), random_msgs.end()); for_each(random_msgs.begin(), random_msgs.end(), InputMapInserter(im)); size_t n = 0; for (InputMap::iterator i = im.begin(); i != im.end(); ++i) { const InputMapMsg& msg(InputMapMsgIndex::value(i)); fail_unless(msg.msg() == msgs[n].second); fail_if(im.is_safe(i) == true); ++n; } fail_unless(im.aru_seq() == n_seqnos - 1); fail_unless(im.safe_seq() == -1); for (size_t i = 0; i < n_uuids; ++i) { fail_unless(im.range(i) == Range(n_seqnos, n_seqnos - 1)); im.set_safe_seq(i, n_seqnos - 1); } fail_unless(im.safe_seq() == n_seqnos - 1); } END_TEST static Datagram* get_msg(DummyTransport* tp, Message* msg, bool release = true) { Datagram* rb = tp->out(); if (rb != 0) { gu_trace(Proto::unserialize_message(tp->uuid(), *rb, msg)); if (release == true) { delete rb; } } return rb; } static void single_join(DummyTransport* t, Proto* p) { Message jm, im, gm; // Initial state is joining p->shift_to(Proto::S_JOINING); // Send join must produce emitted join message p->send_join(); Datagram* rb = get_msg(t, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); // Install message is emitted at the end of JOIN handling // 'cause this is the only instance and is always consistent // with itself rb = get_msg(t, &im); fail_unless(rb != 0); fail_unless(im.type() == Message::T_INSTALL); // Handling INSTALL message emits three gap messages, // one for receiving install message (commit gap), one for // shift to install and one for shift to operational rb = get_msg(t, &gm); fail_unless(rb != 0); fail_unless(gm.type() == Message::T_GAP); fail_unless((gm.flags() & Message::F_COMMIT) != 0); rb = get_msg(t, &gm); fail_unless(rb != 0); fail_unless(gm.type() == Message::T_GAP); fail_unless((gm.flags() & Message::F_COMMIT) == 0); rb = get_msg(t, &gm); fail_unless(rb != 0); fail_unless(gm.type() == Message::T_GAP); fail_unless((gm.flags() & Message::F_COMMIT) == 0); // State must have evolved JOIN -> S_GATHER -> S_INSTALL -> S_OPERATIONAL fail_unless(p->state() == Proto::S_OPERATIONAL); // Handle join message again, must stay in S_OPERATIONAL, must not // emit anything p->handle_msg(jm); rb = get_msg(t, &gm); fail_unless(rb == 0); fail_unless(p->state() == Proto::S_OPERATIONAL); } class DummyUser : public Toplay { public: DummyUser(gu::Config& conf) : Toplay(conf) { } void handle_up(const void*, const Datagram&, const ProtoUpMeta&) { } private: }; START_TEST(test_proto_single_join) { log_info << "START"; gu::Config conf; mark_point(); gcomm::Conf::register_params(conf); UUID uuid(1); DummyTransport t(uuid); mark_point(); DummyUser u(conf); mark_point(); Proto p(conf, uuid, 0); mark_point(); gcomm::connect(&t, &p); gcomm::connect(&p, &u); single_join(&t, &p); } END_TEST static void double_join(DummyTransport* t1, Proto* p1, DummyTransport* t2, Proto* p2) { Message jm; Message im; Message gm; Message gm2; Message msg; Datagram* rb; // Initial states check p2->shift_to(Proto::S_JOINING); fail_unless(p1->state() == Proto::S_OPERATIONAL); fail_unless(p2->state() == Proto::S_JOINING); // Send join message, don't self handle immediately // Expected output: one join message p2->send_join(false); fail_unless(p2->state() == Proto::S_JOINING); rb = get_msg(t2, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(t2, &msg); fail_unless(rb == 0); // Handle node 2's join on node 1 // Expected output: shift to S_GATHER and one join message p1->handle_msg(jm); fail_unless(p1->state() == Proto::S_GATHER); rb = get_msg(t1, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(t1, &msg); fail_unless(rb == 0); // Handle node 1's join on node 2 // Expected output: shift to S_GATHER and one join message p2->handle_msg(jm); fail_unless(p2->state() == Proto::S_GATHER); rb = get_msg(t2, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(t2, &msg); fail_unless(rb == 0); // Handle node 2's join on node 1 // Expected output: Install and commit gap messages, state stays in S_GATHER p1->handle_msg(jm); fail_unless(p1->state() == Proto::S_GATHER); rb = get_msg(t1, &im); fail_unless(rb != 0); fail_unless(im.type() == Message::T_INSTALL); rb = get_msg(t1, &gm); fail_unless(rb != 0); fail_unless(gm.type() == Message::T_GAP); fail_unless((gm.flags() & Message::F_COMMIT) != 0); rb = get_msg(t1, &msg); fail_unless(rb == 0); // Handle install message on node 2 // Expected output: commit gap message and state stays in S_RECOVERY p2->handle_msg(im); fail_unless(p2->state() == Proto::S_GATHER); rb = get_msg(t2, &gm2); fail_unless(rb != 0); fail_unless(gm2.type() == Message::T_GAP); fail_unless((gm2.flags() & Message::F_COMMIT) != 0); rb = get_msg(t2, &msg); fail_unless(rb == 0); // Handle gap messages // Expected output: Both nodes shift to S_INSTALL, // both send gap messages p1->handle_msg(gm2); fail_unless(p1->state() == Proto::S_INSTALL); Message gm12; rb = get_msg(t1, &gm12); fail_unless(rb != 0); fail_unless(gm12.type() == Message::T_GAP); fail_unless((gm12.flags() & Message::F_COMMIT) == 0); rb = get_msg(t1, &msg); fail_unless(rb == 0); p2->handle_msg(gm); fail_unless(p2->state() == Proto::S_INSTALL); Message gm22; rb = get_msg(t2, &gm22); fail_unless(rb != 0); fail_unless(gm22.type() == Message::T_GAP); fail_unless((gm22.flags() & Message::F_COMMIT) == 0); rb = get_msg(t2, &msg); fail_unless(rb == 0); // Handle final gap messages, expected output shift to operational // and gap message p1->handle_msg(gm22); fail_unless(p1->state() == Proto::S_OPERATIONAL); rb = get_msg(t1, &msg); fail_unless(rb != 0); fail_unless(msg.type() == Message::T_GAP); fail_unless((msg.flags() & Message::F_COMMIT) == 0); rb = get_msg(t1, &msg); fail_unless(rb == 0); p2->handle_msg(gm12); fail_unless(p2->state() == Proto::S_OPERATIONAL); rb = get_msg(t2, &msg); fail_unless(rb != 0); fail_unless(msg.type() == Message::T_GAP); fail_unless((msg.flags() & Message::F_COMMIT) == 0); rb = get_msg(t2, &msg); fail_unless(rb == 0); } START_TEST(test_proto_double_join) { log_info << "START"; gu::Config conf; mark_point(); gcomm::Conf::register_params(conf); UUID uuid1(1), uuid2(2); DummyTransport t1(uuid1), t2(uuid2); mark_point(); DummyUser u1(conf), u2(conf); mark_point(); Proto p1(conf, uuid1, 0), p2(conf, uuid2, 0); gcomm::connect(&t1, &p1); gcomm::connect(&p1, &u1); gcomm::connect(&t2, &p2); gcomm::connect(&p2, &u2); single_join(&t1, &p1); double_join(&t1, &p1, &t2, &p2); } END_TEST static gu::Config gu_conf; static DummyNode* create_dummy_node(size_t idx, int version, const string& suspect_timeout = "PT1H", const string& inactive_timeout = "PT1H", const string& retrans_period = "PT10M") { // reset conf to avoid stale config in case of nofork gu_conf = gu::Config(); gcomm::Conf::register_params(gu_conf); string conf = "evs://?" + Conf::EvsViewForgetTimeout + "=PT1H&" + Conf::EvsInactiveCheckPeriod + "=" + to_string(Period(suspect_timeout)/3) + "&" + Conf::EvsSuspectTimeout + "=" + suspect_timeout + "&" + Conf::EvsInactiveTimeout + "=" + inactive_timeout + "&" + Conf::EvsKeepalivePeriod + "=" + retrans_period + "&" + Conf::EvsJoinRetransPeriod + "=" + retrans_period + "&" + Conf::EvsInfoLogMask + "=0x7" + "&" + Conf::EvsVersion + "=" + gu::to_string(version); if (::getenv("EVS_DEBUG_MASK") != 0) { conf += "&" + Conf::EvsDebugLogMask + "=" + ::getenv("EVS_DEBUG_MASK"); } list protos; UUID uuid(static_cast(idx)); protos.push_back(new DummyTransport(uuid, false)); protos.push_back(new Proto(gu_conf, uuid, 0, conf)); return new DummyNode(gu_conf, idx, protos); } namespace { gcomm::evs::Proto* evs_from_dummy(DummyNode* dn) { return reinterpret_cast(dn->protos().back()); } } static void join_node(PropagationMatrix* p, DummyNode* n, bool first = false) { gu_trace(p->insert_tp(n)); gu_trace(n->connect(first)); } static void send_n(DummyNode* node, const size_t n) { for (size_t i = 0; i < n; ++i) { gu_trace(node->send()); } } static void set_cvi(vector& nvec, size_t i_begin, size_t i_end, size_t seq) { for (size_t i = i_begin; i <= i_end; ++i) { nvec[i]->set_cvi(ViewId(V_REG, nvec[i_begin]->uuid(), static_cast(seq))); } } template class ViewSeq { public: ViewSeq() { } bool operator()(const C& a, const C& b) const { return (a->trace().current_view_trace().view().id().seq() < b->trace().current_view_trace().view().id().seq()); } }; static uint32_t get_max_view_seq(const std::vector& dnv, size_t i, size_t j) { if (i == dnv.size()) return static_cast(-1); return (*std::max_element(dnv.begin() + i, dnv.begin() + j, ViewSeq()))->trace().current_view_trace().view().id().seq(); } START_TEST(test_proto_join_n) { log_info << "START (join_n)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back(create_dummy_node(i, 0))); } uint32_t max_view_seq(0); for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(false)); max_view_seq = get_max_view_seq(dn, 0, i); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_join_n_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (join_n_w_user_msg)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; // @todo This test should terminate without these timeouts const string suspect_timeout("PT1H"); const string inactive_timeout("PT1H"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } uint32_t max_view_seq(0); for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); for (size_t j = 0; j <= i; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } gu_trace(prop.propagate_until_empty()); for (size_t j = 0; j <= i; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } max_view_seq = get_max_view_seq(dn, 0, i); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_join_n_lossy) { gu_conf_self_tstamp_on(); log_info << "START (join_n_lossy)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT1H"); const string inactive_timeout("PT1H"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } uint32_t max_view_seq(0); for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, max_view_seq + 1); for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, 0.9); prop.set_loss(j, i + 1, 0.9); } gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, 0, i); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_join_n_lossy_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (join_n_lossy_w_user_msg)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT1H"); const string inactive_timeout("PT1H"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } uint32_t max_view_seq(0); for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, max_view_seq + 1); for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, 0.9); prop.set_loss(j, i + 1, 0.9); } gu_trace(prop.propagate_until_cvi(true)); for (size_t j = 0; j < i; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } max_view_seq = get_max_view_seq(dn, 0, i); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_leave_n) { gu_conf_self_tstamp_on(); log_info << "START (leave_n)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back(create_dummy_node(i, 0))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(true)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t i = 0; i < n_nodes; ++i) { dn[i]->close(); dn[i]->set_cvi(V_REG); set_cvi(dn, i + 1, n_nodes - 1, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, i + 1, n_nodes); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_leave_n_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (leave_n_w_user_msg)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT1H"); const string inactive_timeout("PT1H"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = i; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } dn[i]->close(); dn[i]->set_cvi(V_REG); set_cvi(dn, i + 1, n_nodes - 1, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, i + 1, n_nodes); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_leave_n_lossy) { gu_conf_self_tstamp_on(); log_info << "START (leave_n_lossy)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, 0.9); prop.set_loss(j, i + 1, 0.9); } } for (size_t i = 0; i < n_nodes; ++i) { dn[i]->set_cvi(V_REG); set_cvi(dn, i + 1, n_nodes - 1, max_view_seq + 1); dn[i]->close(); gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, i + 1, n_nodes); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_leave_n_lossy_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (leave_n_lossy_w_user_msg)"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, 0.9); prop.set_loss(j, i + 1, 0.9); } } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = i; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } dn[i]->set_cvi(V_REG); set_cvi(dn, i + 1, n_nodes - 1, max_view_seq + 1); dn[i]->close(); gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, i + 1, n_nodes); } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST // Generic test code for split/merge cases static void test_proto_split_merge_gen(const size_t n_nodes, const bool send_msgs, const double loss) { PropagationMatrix prop; vector dn; const string suspect_timeout("PT1.2S"); const string inactive_timeout("PT1.2S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, loss); prop.set_loss(j, i + 1, loss); } } vector split; for (size_t i = 0; i < n_nodes; ++i) { split.push_back(static_cast(i + 1)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t i = 1; i < n_nodes; ++i) { if (send_msgs == true) { for (size_t k = 0; k < 5; ++k) { for (size_t j = 0; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 1 + j)); } gu_trace(prop.propagate_n(7)); } } log_info << "split " << i; for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { gu_trace(prop.set_loss(split[j], split[k], 0.)); gu_trace(prop.set_loss(split[k], split[j], 0.)); } } set_cvi(dn, 0, i - 1, max_view_seq + 1); set_cvi(dn, i, n_nodes - 1, max_view_seq + 1); if (send_msgs == true) { for (size_t j = 0; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 5 + rand() % 4)); } } gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, 0, n_nodes); log_info << "merge " << i; for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { gu_trace(prop.set_loss(split[j], split[k], loss)); gu_trace(prop.set_loss(split[k], split[j], loss)); } } set_cvi(dn, 0, n_nodes - 1, max_view_seq + 1); if (send_msgs == true) { for (size_t j = 0; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 5 + rand() % 4)); } } gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, 0, n_nodes); } gu_trace(prop.propagate_until_empty()); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } START_TEST(test_proto_split_merge) { gu_conf_self_tstamp_on(); log_info << "START (split_merge)"; init_rand(); test_proto_split_merge_gen(4, false, 1.); } END_TEST START_TEST(test_proto_split_merge_lossy) { gu_conf_self_tstamp_on(); log_info << "START (split_merge_lossy)"; init_rand(); test_proto_split_merge_gen(4, false, .9); } END_TEST START_TEST(test_proto_split_merge_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (split_merge_w_user_msg)"; init_rand(); test_proto_split_merge_gen(4, true, 1.); } END_TEST START_TEST(test_proto_split_merge_lossy_w_user_msg) { gu_conf_self_tstamp_on(); log_info << "START (split_merge_lossy_w_user_msg)"; init_rand(); test_proto_split_merge_gen(4, true, .9); } END_TEST START_TEST(test_proto_stop_cont) { log_info << "START"; init_rand(); const size_t n_nodes(4); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.31S"); const string inactive_timeout("PT0.31S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t view_seq = n_nodes + 1; for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = 0; j < n_nodes; ++j) { if (j != i) { dn[j]->close(dn[i]->uuid()); } } set_cvi(dn, 0, n_nodes - 1, view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); view_seq += 2; } gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_arbitrate) { log_info << "START"; const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT0.5S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t view_seq = n_nodes + 1; dn[0]->close(dn[1]->uuid()); dn[1]->close(dn[0]->uuid()); dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq)); dn[2]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq)); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), view_seq)); gu_trace(prop.propagate_until_cvi(true)); dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq + 1)); dn[1]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq + 1)); dn[2]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq + 1)); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_proto_split_two) { log_info << "START"; const size_t n_nodes(2); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.31S"); const string inactive_timeout("PT0.31S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t view_seq = n_nodes + 1; dn[0]->close(dn[1]->uuid()); dn[1]->close(dn[0]->uuid()); dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq)); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), view_seq)); gu_trace(prop.propagate_until_cvi(true)); dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq + 1)); dn[1]->set_cvi(ViewId(V_REG, dn[0]->uuid(), view_seq + 1)); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_aggreg) { log_info << "START"; const size_t n_nodes(2); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.31S"); const string inactive_timeout("PT0.31S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(send_n(dn[i], 8)); } gu_trace(prop.propagate_until_empty()); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_trac_538) { gu_conf_self_tstamp_on(); log_info << "START (test_trac_538)"; init_rand(); const size_t n_nodes(5); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT2S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes - 1; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes - 1)); gu_trace(join_node(&prop, dn[n_nodes - 1], false)); for (size_t i = 1; i <= n_nodes; ++i) { if (i != n_nodes - 1) { prop.set_loss(i, n_nodes - 1, 0); prop.set_loss(n_nodes - 1, i, 0); } } set_cvi(dn, 0, n_nodes - 1, max_view_seq + 1); dn[n_nodes - 2]->set_cvi(ViewId(V_REG, n_nodes - 1, max_view_seq + 1)); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_trac_552) { gu_conf_self_tstamp_on(); log_info << "START (trac_552)"; init_rand(); const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < n_nodes; ++i) { for (size_t j = 1; j < i + 1; ++j) { prop.set_loss(i + 1, j, 0.9); prop.set_loss(j, i + 1, 0.9); } } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); for (size_t j = 0; j < n_nodes; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } dn[0]->set_cvi(V_REG); dn[1]->set_cvi(V_REG); set_cvi(dn, 2, n_nodes - 1, max_view_seq + 1); dn[0]->close(); dn[1]->close(); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_trac_607) { gu_conf_self_tstamp_on(); log_info << "START (trac_607)"; const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); dn[0]->set_cvi(V_REG); dn[0]->close(); while (evs_from_dummy(dn[1])->state() != Proto::S_INSTALL) { prop.propagate_n(1); } // this used to cause exception: // Forbidden state transition: INSTALL -> LEAVING (FATAL) dn[1]->close(); // expected behavior: // dn[1], dn[2] reach S_OPERATIONAL and then dn[1] leaves gracefully set_cvi(dn, 1, n_nodes - 1, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); max_view_seq = get_max_view_seq(dn, 0, n_nodes); dn[1]->set_cvi(V_REG); set_cvi(dn, 2, 2, max_view_seq + 1); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_trac_724) { gu_conf_self_tstamp_on(); log_info << "START (trac_724)"; init_rand(); const size_t n_nodes(2); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } // Slightly asymmetric settings and evs.use_aggregate=false to // allow completion window to grow over 0xff. Proto* evs0(evs_from_dummy(dn[0])); bool ret(evs0->set_param("evs.use_aggregate", "false")); fail_unless(ret == true); ret = evs0->set_param("evs.send_window", "1024"); fail_unless(ret == true); ret = evs0->set_param("evs.user_send_window", "515"); Proto* evs1(evs_from_dummy(dn[1])); ret = evs1->set_param("evs.use_aggregate", "false"); fail_unless(ret == true); ret = evs1->set_param("evs.send_window", "1024"); fail_unless(ret == true); ret = evs1->set_param("evs.user_send_window", "512"); prop.set_loss(1, 2, 0.); for (size_t i(0); i < 256; ++i) { dn[0]->send(); dn[0]->send(); dn[1]->send(); gu_trace(prop.propagate_until_empty()); } dn[0]->send(); prop.set_loss(1, 2, 1.); dn[0]->send(); gu_trace(prop.propagate_until_empty()); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_trac_760) { gu_conf_self_tstamp_on(); log_info << "START (trac_760)"; init_rand(); const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(send_n(dn[i], 2)); } gu_trace(prop.propagate_until_empty()); uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); gu_trace(send_n(dn[0], 1)); gu_trace(send_n(dn[1], 1)); // gu_trace(send_n(dn[2], 1)); set_cvi(dn, 0, 1, max_view_seq + 1); dn[2]->set_cvi(V_REG); dn[2]->close(); Proto* evs0(evs_from_dummy(dn[0])); Proto* evs1(evs_from_dummy(dn[1])); while (evs1->state() != Proto::S_GATHER && evs0->state() != Proto::S_GATHER) { gu_trace(prop.propagate_n(1)); } dn[1]->close(); gu_trace(prop.propagate_until_cvi(true)); gu_trace(check_trace(dn)); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_gh_41) { gu_conf_self_tstamp_on(); log_info << "START (gh_41)"; const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } // Generate partitioning so that the node with smallest UUID // creates singleton view log_info << "partition"; prop.set_loss(1, 2, 0.); prop.set_loss(2, 1, 0.); prop.set_loss(1, 3, 0.); prop.set_loss(3, 1, 0.); uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), max_view_seq + 1)); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); dn[2]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); prop.propagate_until_cvi(true); // Merge groups and make node 1 leave so that nodes 2 and 3 see // leave message from unknown origin log_info << "merge"; prop.set_loss(1, 2, 1.); prop.set_loss(2, 1, 1.); prop.set_loss(1, 3, 1.); prop.set_loss(3, 1, 1.); // Send message so that nodes 2 and 3 shift to GATHER. This must be done // because LEAVE message is ignored in handle_foreign() dn[0]->send(); dn[0]->close(); dn[0]->set_cvi(V_REG); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 2)); dn[2]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 2)); prop.propagate_until_cvi(true); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_gh_37) { gu_conf_self_tstamp_on(); log_info << "START (gh_37)"; const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); // node 0 is gonna to leave for(size_t i = 2; i <= n_nodes; i++) { // leaving node(LN) is able to send messages to remaining nodes. // prop.set_loss(1, i, 0.); // but remaining nodes(RNS) won't be able to ack these messages. prop.set_loss(i, 1, 0.); // so RNS aru_seq are the same and higher than LN aru_seq. } // LN ss=-1, ir=[2,1] // RNS ss=1, ir=[2,1] dn[0]->send(); dn[0]->send(); dn[0]->close(); dn[0]->set_cvi(V_REG); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); dn[2]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); prop.propagate_until_cvi(true); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_gh_40) { gu_conf_self_tstamp_on(); log_info << "START (gh_40)"; const size_t n_nodes(3); PropagationMatrix prop; vector dn; const string suspect_timeout("PT0.5S"); const string inactive_timeout("PT1S"); const string retrans_period("PT0.1S"); for (size_t i = 1; i <= n_nodes; ++i) { gu_trace(dn.push_back( create_dummy_node(i, 0, suspect_timeout, inactive_timeout, retrans_period))); } for (size_t i = 0; i < n_nodes; ++i) { gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, i + 1); gu_trace(prop.propagate_until_cvi(false)); } uint32_t max_view_seq(get_max_view_seq(dn, 0, n_nodes)); // ss=0, ir=[1,0]; dn[0]->send(); gu_trace(prop.propagate_until_empty()); log_info << "gh_40 all got operational state"; // cut dn[0] from dn[1] and dn[2]. for (size_t i = 2; i <= n_nodes; ++i) { prop.set_loss(1, i, 0.); prop.set_loss(i, 1, 0.); } // ss=0, ir=[2,1]; // dn[1] send msg(seq=1) dn[1]->send(); Proto* evs1 = evs_from_dummy(dn[1]); Proto* evs2 = evs_from_dummy(dn[2]); fail_if(evs1->state() != Proto::S_OPERATIONAL); fail_if(evs2->state() != Proto::S_OPERATIONAL); evs1->set_inactive(dn[0]->uuid()); evs2->set_inactive(dn[0]->uuid()); evs1->check_inactive(); evs2->check_inactive(); fail_if(evs1->state() != Proto::S_GATHER); fail_if(evs2->state() != Proto::S_GATHER); while(!(evs1->state() == Proto::S_GATHER && evs1->is_install_message())) { gu_trace(prop.propagate_n(1)); } // dn[0] comes back. // here we have to set message F_RETRANS // otherwise handle_msg ignores this msg. // @todo:why? // dn[0] ack dn[1] msg(seq=1) with flags F_RETRANS. Datagram dg1 = dn[0]->create_datagram(); UserMessage msg1(0, dn[0]->uuid(), ViewId(V_REG, dn[0]->uuid(), max_view_seq), 1, 0, 0, O_DROP, 1, 0xff, Message::F_RETRANS); // dn[0] msg(seq=2) leak into dn[1] input_map. Datagram dg2 = dn[0]->create_datagram(); UserMessage msg2(0, dn[0]->uuid(), ViewId(V_REG, dn[0]->uuid(), max_view_seq), 2, 0, 0, O_SAFE, 2, 0xff, Message::F_RETRANS); // so for dn[1] // input_map: ss=0, ir=[3,2] // install message: ss=0, ir=[2,1] // seq 1 = O_SAFE message.(initiated by self) // seq 2 = O_DROP message.(complete_user) push_header(msg1, dg1); evs1->handle_up(0, dg1, ProtoUpMeta(dn[0]->uuid())); push_header(msg2, dg2); log_info << "evs1 handle msg " << msg2; log_info << "before handle msg: " << *evs1; evs1->handle_up(0, dg2, ProtoUpMeta(dn[0]->uuid())); log_info << "after handle msg: " << *evs1; dn[0]->set_cvi(ViewId(V_REG, dn[0]->uuid(), max_view_seq + 1)); dn[1]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); dn[2]->set_cvi(ViewId(V_REG, dn[1]->uuid(), max_view_seq + 1)); prop.propagate_until_cvi(true); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_gh_100) { log_info << "START (test_gh_100)"; gu::Config conf; mark_point(); gcomm::Conf::register_params(conf); conf.set("evs.info_log_mask", "0x3"); conf.set("evs.debug_log_mask", "0xa0"); UUID uuid1(1), uuid2(2); DummyTransport t1(uuid1), t2(uuid2); mark_point(); DummyUser u1(conf), u2(conf); mark_point(); Proto p1(conf, uuid1, 0, gu::URI("evs://"), 10000, 0); // Start p2 view seqno from higher value than p1 View p2_rst_view(0, ViewId(V_REG, uuid2, 3)); Proto p2(conf, uuid2, 0, gu::URI("evs://"), 10000, &p2_rst_view); gcomm::connect(&t1, &p1); gcomm::connect(&p1, &u1); gcomm::connect(&t2, &p2); gcomm::connect(&p2, &u2); single_join(&t1, &p1); // The following is from double_join(). Process messages until // install message is generated. After that handle install timer // on p1 and verify that the newly generated install message has // greater install view id seqno than the first one. Message jm; Message im; Message im2; Message gm; Message gm2; Message msg; Datagram* rb; // Initial states check p2.shift_to(Proto::S_JOINING); fail_unless(p1.state() == Proto::S_OPERATIONAL); fail_unless(p2.state() == Proto::S_JOINING); // Send join message, don't self handle immediately // Expected output: one join message p2.send_join(false); fail_unless(p2.state() == Proto::S_JOINING); rb = get_msg(&t2, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(&t2, &msg); fail_unless(rb == 0); // Handle node 2's join on node 1 // Expected output: shift to S_GATHER and one join message p1.handle_msg(jm); fail_unless(p1.state() == Proto::S_GATHER); rb = get_msg(&t1, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(&t1, &msg); fail_unless(rb == 0); // Handle node 1's join on node 2 // Expected output: shift to S_GATHER and one join message p2.handle_msg(jm); fail_unless(p2.state() == Proto::S_GATHER); rb = get_msg(&t2, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(&t2, &msg); fail_unless(rb == 0); // Handle node 2's join on node 1 // Expected output: Install and commit gap messages, state stays in S_GATHER p1.handle_msg(jm); fail_unless(p1.state() == Proto::S_GATHER); rb = get_msg(&t1, &im); fail_unless(rb != 0); fail_unless(im.type() == Message::T_INSTALL); rb = get_msg(&t1, &gm); fail_unless(rb != 0); fail_unless(gm.type() == Message::T_GAP); fail_unless((gm.flags() & Message::F_COMMIT) != 0); rb = get_msg(&t1, &msg); fail_unless(rb == 0); // usleep(1100000); // Handle timers to to generate shift to GATHER p1.handle_inactivity_timer(); p1.handle_install_timer(); rb = get_msg(&t1, &jm); fail_unless(rb != 0); fail_unless(jm.type() == Message::T_JOIN); rb = get_msg(&t1, &im2); fail_unless(rb != 0); fail_unless(im2.type() == Message::T_INSTALL); fail_unless(im2.install_view_id().seq() > im.install_view_id().seq()); } END_TEST START_TEST(test_evs_protocol_upgrade) { log_info << "START (test_evs_protocol_upgrade)"; PropagationMatrix prop; vector dn; uint32_t view_seq(0); for (int i(0); i <= GCOMM_PROTOCOL_MAX_VERSION; ++i) { gu_trace(dn.push_back(create_dummy_node(i + 1, i))); gu_trace(join_node(&prop, dn[i], i == 0 ? true : false)); set_cvi(dn, 0, i, view_seq + 1); gu_trace(prop.propagate_until_cvi(false)); ++view_seq; for (int j(0); j <= i; ++j) { fail_unless(evs_from_dummy(dn[j])->current_view().version() == 0); gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } } for (int i(0); i < GCOMM_PROTOCOL_MAX_VERSION; ++i) { for (int j(i); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } dn[i]->close(); dn[i]->set_cvi(V_REG); set_cvi(dn, i + 1, GCOMM_PROTOCOL_MAX_VERSION, view_seq); gu_trace(prop.propagate_until_cvi(true)); ++view_seq; for (int j(i + 1); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } gu_trace(prop.propagate_until_empty()); } fail_unless(evs_from_dummy(dn[GCOMM_PROTOCOL_MAX_VERSION])->current_view().version() == GCOMM_PROTOCOL_MAX_VERSION); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST Suite* evs2_suite() { Suite* s = suite_create("gcomm::evs"); TCase* tc; bool skip(false); if (skip == false) { tc = tcase_create("test_range"); tcase_add_test(tc, test_range); suite_add_tcase(s, tc); tc = tcase_create("test_message"); tcase_add_test(tc, test_message); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_insert"); tcase_add_test(tc, test_input_map_insert); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_find"); tcase_add_test(tc, test_input_map_find); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_safety"); tcase_add_test(tc, test_input_map_safety); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_erase"); tcase_add_test(tc, test_input_map_erase); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_overwrap"); tcase_add_test(tc, test_input_map_overwrap); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_input_map_random_insert"); tcase_add_test(tc, test_input_map_random_insert); suite_add_tcase(s, tc); tc = tcase_create("test_proto_single_join"); tcase_add_test(tc, test_proto_single_join); suite_add_tcase(s, tc); tc = tcase_create("test_proto_double_join"); tcase_add_test(tc, test_proto_double_join); suite_add_tcase(s, tc); tc = tcase_create("test_proto_join_n"); tcase_add_test(tc, test_proto_join_n); suite_add_tcase(s, tc); tc = tcase_create("test_proto_join_n_w_user_msg"); tcase_add_test(tc, test_proto_join_n_w_user_msg); suite_add_tcase(s, tc); tc = tcase_create("test_proto_join_n_lossy"); tcase_add_test(tc, test_proto_join_n_lossy); suite_add_tcase(s, tc); tc = tcase_create("test_proto_join_n_lossy_w_user_msg"); tcase_add_test(tc, test_proto_join_n_lossy_w_user_msg); suite_add_tcase(s, tc); tc = tcase_create("test_proto_leave_n"); tcase_add_test(tc, test_proto_leave_n); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_proto_leave_n_w_user_msg"); tcase_add_test(tc, test_proto_leave_n_w_user_msg); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_proto_leave_n_lossy"); tcase_add_test(tc, test_proto_leave_n_lossy); tcase_set_timeout(tc, 25); suite_add_tcase(s, tc); tc = tcase_create("test_proto_leave_n_lossy_w_user_msg"); tcase_add_test(tc, test_proto_leave_n_lossy_w_user_msg); tcase_set_timeout(tc, 25); suite_add_tcase(s, tc); tc = tcase_create("test_proto_split_merge"); tcase_add_test(tc, test_proto_split_merge); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_proto_split_merge_lossy"); tcase_add_test(tc, test_proto_split_merge_lossy); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); tc = tcase_create("test_proto_split_merge_w_user_msg"); tcase_add_test(tc, test_proto_split_merge_w_user_msg); tcase_set_timeout(tc, 60); suite_add_tcase(s, tc); tc = tcase_create("test_proto_split_merge_lossy_w_user_msg"); tcase_add_test(tc, test_proto_split_merge_lossy_w_user_msg); tcase_set_timeout(tc, 60); suite_add_tcase(s, tc); tc = tcase_create("test_proto_stop_cont"); tcase_add_test(tc, test_proto_stop_cont); tcase_set_timeout(tc, 10); suite_add_tcase(s, tc); tc = tcase_create("test_proto_split_two"); tcase_add_test(tc, test_proto_split_two); suite_add_tcase(s, tc); tc = tcase_create("test_aggreg"); tcase_add_test(tc, test_aggreg); suite_add_tcase(s, tc); tc = tcase_create("test_proto_arbitrate"); tcase_add_test(tc, test_proto_arbitrate); suite_add_tcase(s, tc); tc = tcase_create("test_trac_538"); tcase_add_test(tc, test_trac_538); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_trac_552"); tcase_add_test(tc, test_trac_552); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_trac_607"); tcase_add_test(tc, test_trac_607); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_trac_724"); tcase_add_test(tc, test_trac_724); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_trac_760"); tcase_add_test(tc, test_trac_760); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_gh_41"); tcase_add_test(tc, test_gh_41); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_gh_37"); tcase_add_test(tc, test_gh_37); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_gh_40"); tcase_add_test(tc, test_gh_40); tcase_set_timeout(tc, 5); suite_add_tcase(s, tc); tc = tcase_create("test_gh_100"); tcase_add_test(tc, test_gh_100); suite_add_tcase(s, tc); tc = tcase_create("test_evs_protocol_upgrade"); tcase_add_test(tc, test_evs_protocol_upgrade); suite_add_tcase(s, tc); } return s; } percona-galera-3-3.8-3390/gcomm/test/check_gcomm.cpp000066400000000000000000000041721244131713600220320ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "check_gcomm.hpp" #include "gu_string_utils.hpp" // strsplit() #include "gu_exception.hpp" #include "gu_logger.hpp" #include #include #include #include #include #include #include // * suits = 0; if (argc > 1 && !strcmp(argv[1],"nofork")) { srunner_set_fork_status(sr, CK_NOFORK); } else if (argc > 1 && strcmp(argv[1], "nolog") == 0) { /* no log redirection */} else { // running in the background, loggin' to file FILE* log_file = fopen ("check_gcomm.log", "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); // redirect occasional stderr there as well if (dup2(fileno(log_file), 2) < 0) { perror("dup2() failed: "); return EXIT_FAILURE; } } if (::getenv("CHECK_GCOMM_DEBUG")) { gu_log_max_level = GU_LOG_DEBUG; //gu::Logger::enable_debug(true); } log_info << "check_gcomm, start tests"; if (::getenv("CHECK_GCOMM_SUITES")) { suits = new vector(gu::strsplit(::getenv("CHECK_GCOMM_SUITES"), ',')); } for (size_t i = 0; suites[i].suite != 0; ++i) { if (suits == 0 || find(suits->begin(), suits->end(), suites[i].name) != suits->end()) { srunner_add_suite(sr, suites[i].suite()); } } delete suits; suits = 0; srunner_run_all(sr, CK_NORMAL); log_info << "check_gcomm, run all tests"; int n_fail = srunner_ntests_failed(sr); srunner_free(sr); return n_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } percona-galera-3-3.8-3390/gcomm/test/check_gcomm.hpp000066400000000000000000000014541244131713600220370ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef CHECK_GCOMM_HPP #define CHECK_GCOMM_HPP struct Suite; /* Tests for various common types */ Suite* types_suite(); /* Tests for utilities */ Suite* util_suite(); /* Tests for logger */ Suite* logger_suite(); /* Tests for message buffer implementations */ Suite* buffer_suite(); /* Tests for event loop */ Suite* event_suite(); /* Tests for concurrency handling (mutex, cond, thread, etc.)*/ Suite* concurrent_suite(); /* Tests for TCP transport */ Suite* tcp_suite(); /* Tests for GMcast transport */ Suite* gmcast_suite(); /* Tests for EVS transport */ Suite* evs_suite(); /* Better evs suite */ Suite* evs2_suite(); /* Tests for VS trasport */ Suite* vs_suite(); /* Tests for PC transport */ Suite* pc_suite(); #endif // CHECK_GCOMM_HPP percona-galera-3-3.8-3390/gcomm/test/check_gmcast.cpp000066400000000000000000000254011244131713600222040ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "check_gcomm.hpp" #include "gcomm/protostack.hpp" #include "gcomm/conf.hpp" #include "gmcast.hpp" #include "gmcast_message.hpp" using namespace std; using namespace gcomm; using namespace gcomm::gmcast; using namespace gu::datetime; using gu::byte_t; using gu::Buffer; #include // Note: Not all tests are run by default as they require default port to be // used or listen port to be known beforehand. static bool run_all_tests(false); // Note: Multicast test(s) not run by default. static bool test_multicast(false); string mcast_param("gmcast.mcast_addr=239.192.0.11&gmcast.mcast_port=4567"); START_TEST(test_gmcast_multicast) { string uri1("gmcast://?gmcast.group=test&gmcast.mcast_addr=239.192.0.11"); gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr pnet(Protonet::create(conf)); Transport* gm1(Transport::create(*pnet, uri1)); gm1->connect(); gm1->close(); delete gm1; } END_TEST START_TEST(test_gmcast_w_user_messages) { class User : public Toplay { Transport* tp_; size_t recvd_; Protostack pstack_; explicit User(const User&); void operator=(User&); public: User(Protonet& pnet, const std::string& listen_addr, const std::string& remote_addr) : Toplay(pnet.conf()), tp_(0), recvd_(0), pstack_() { string uri("gmcast://"); uri += remote_addr; // != 0 ? remote_addr : ""; uri += "?"; uri += "tcp.non_blocking=1"; uri += "&"; uri += "gmcast.group=testgrp"; uri += "&gmcast.time_wait=PT0.5S"; if (test_multicast == true) { uri += "&" + mcast_param; } uri += "&gmcast.listen_addr=tcp://"; uri += listen_addr; tp_ = Transport::create(pnet, uri); } ~User() { delete tp_; } void start(const std::string& peer = "") { if (peer == "") { tp_->connect(); } else { tp_->connect(peer); } pstack_.push_proto(tp_); pstack_.push_proto(this); } void stop() { pstack_.pop_proto(this); pstack_.pop_proto(tp_); tp_->close(); } void handle_timer() { byte_t buf[16]; memset(buf, 0xa5, sizeof(buf)); Datagram dg(Buffer(buf, buf + sizeof(buf))); send_down(dg, ProtoDownMeta()); } void handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (rb.len() < rb.offset() + 16) { gu_throw_fatal << "offset error"; } char buf[16]; memset(buf, 0xa5, sizeof(buf)); // cppcheck-suppress uninitstring if (memcmp(buf, &rb.payload()[0] + rb.offset(), 16) != 0) { gu_throw_fatal << "content mismatch"; } recvd_++; } size_t recvd() const { return recvd_; } void set_recvd(size_t val) { recvd_ = val; } Protostack& pstack() { return pstack_; } std::string listen_addr() const { return tp_->listen_addr(); } }; log_info << "START"; gu::Config conf; gcomm::Conf::register_params(conf); mark_point(); auto_ptr pnet(Protonet::create(conf)); mark_point(); User u1(*pnet, "127.0.0.1:0", ""); pnet->insert(&u1.pstack()); log_info << "u1 start"; u1.start(); pnet->event_loop(Sec/10); fail_unless(u1.recvd() == 0); log_info << "u2 start"; User u2(*pnet, "127.0.0.1:0", u1.listen_addr().erase(0, strlen("tcp://"))); pnet->insert(&u2.pstack()); u2.start(); while (u1.recvd() <= 50 || u2.recvd() <= 50) { u1.handle_timer(); u2.handle_timer(); pnet->event_loop(Sec/10); } log_info << "u3 start"; User u3(*pnet, "127.0.0.1:0", u2.listen_addr().erase(0, strlen("tcp://"))); pnet->insert(&u3.pstack()); u3.start(); while (u3.recvd() <= 50) { u1.handle_timer(); u2.handle_timer(); pnet->event_loop(Sec/10); } log_info << "u4 start"; User u4(*pnet, "127.0.0.1:0", u2.listen_addr().erase(0, strlen("tcp://"))); pnet->insert(&u4.pstack()); u4.start(); while (u4.recvd() <= 50) { u1.handle_timer(); u2.handle_timer(); pnet->event_loop(Sec/10); } log_info << "u1 stop"; u1.stop(); pnet->erase(&u1.pstack()); pnet->event_loop(3*Sec); log_info << "u1 start"; pnet->insert(&u1.pstack()); u1.start(u2.listen_addr()); u1.set_recvd(0); u2.set_recvd(0); u3.set_recvd(0); u4.set_recvd(0); for (size_t i(0); i < 30; ++i) { u1.handle_timer(); u2.handle_timer(); pnet->event_loop(Sec/10); } fail_unless(u1.recvd() != 0); fail_unless(u2.recvd() != 0); fail_unless(u3.recvd() != 0); fail_unless(u4.recvd() != 0); pnet->erase(&u4.pstack()); pnet->erase(&u3.pstack()); pnet->erase(&u2.pstack()); pnet->erase(&u1.pstack()); u1.stop(); u2.stop(); u3.stop(); u4.stop(); pnet->event_loop(0); } END_TEST // not run by default, hard coded port START_TEST(test_gmcast_auto_addr) { log_info << "START"; gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr pnet(Protonet::create(conf)); Transport* tp1 = Transport::create(*pnet, "gmcast://?gmcast.group=test"); Transport* tp2 = Transport::create(*pnet, "gmcast://127.0.0.1:4567" "?gmcast.group=test&gmcast.listen_addr=tcp://127.0.0.1:10002"); pnet->insert(&tp1->pstack()); pnet->insert(&tp2->pstack()); tp1->connect(); tp2->connect(); pnet->event_loop(Sec); pnet->erase(&tp2->pstack()); pnet->erase(&tp1->pstack()); tp1->close(); tp2->close(); delete tp1; delete tp2; pnet->event_loop(0); } END_TEST START_TEST(test_gmcast_forget) { gu_conf_self_tstamp_on(); log_info << "START"; gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr pnet(Protonet::create(conf)); Transport* tp1 = Transport::create(*pnet, "gmcast://" "?gmcast.group=test&gmcast.listen_addr=tcp://127.0.0.1:0"); pnet->insert(&tp1->pstack()); tp1->connect(); Transport* tp2 = Transport::create(*pnet, std::string("gmcast://") + tp1->listen_addr().erase( 0, strlen("tcp://")) + "?gmcast.group=test&gmcast.listen_addr=tcp://127.0.0.1:0"); Transport* tp3 = Transport::create(*pnet, std::string("gmcast://") + tp1->listen_addr().erase( 0, strlen("tcp://")) + "?gmcast.group=test&gmcast.listen_addr=tcp://127.0.0.1:0"); pnet->insert(&tp2->pstack()); pnet->insert(&tp3->pstack()); tp2->connect(); tp3->connect(); pnet->event_loop(Sec); UUID uuid1 = tp1->uuid(); tp1->close(); tp2->close(uuid1); tp3->close(uuid1); pnet->event_loop(10*Sec); tp1->connect(); // @todo Implement this using User class above and verify that // tp2 and tp3 communicate with each other but now with tp1 log_info << "####"; pnet->event_loop(Sec); pnet->erase(&tp3->pstack()); pnet->erase(&tp2->pstack()); pnet->erase(&tp1->pstack()); tp1->close(); tp2->close(); tp3->close(); delete tp1; delete tp2; delete tp3; pnet->event_loop(0); } END_TEST // not run by default, hard coded port START_TEST(test_trac_380) { gu_conf_self_tstamp_on(); log_info << "START"; gu::Config conf; gcomm::Conf::register_params(conf); std::auto_ptr pnet(gcomm::Protonet::create(conf)); // caused either assertion or exception gcomm::Transport* tp1(gcomm::Transport::create( *pnet, "gmcast://127.0.0.1:4567?" "gmcast.group=test")); pnet->insert(&tp1->pstack()); tp1->connect(); try { pnet->event_loop(Sec); } catch (gu::Exception& e) { fail_unless(e.get_errno() == EINVAL, "unexpected errno: %d, cause %s", e.get_errno(), e.what()); } pnet->erase(&tp1->pstack()); tp1->close(); delete tp1; pnet->event_loop(0); } END_TEST START_TEST(test_trac_828) { gu_conf_self_tstamp_on(); log_info << "START (test_trac_828)"; gu::Config conf; gcomm::Conf::register_params(conf); std::auto_ptr pnet(gcomm::Protonet::create(conf)); // If the bug is present, this will throw because of own address being // in address list. try { Transport* tp(gcomm::Transport::create( *pnet, "gmcast://127.0.0.1:4567?" "gmcast.group=test&" "gmcast.listen_addr=tcp://127.0.0.1:4567")); delete tp; } catch (gu::Exception& e) { fail("test_trac_828, expcetion thrown because of having own address " "in address list"); } } END_TEST Suite* gmcast_suite() { Suite* s = suite_create("gmcast"); TCase* tc; if (test_multicast == true) { tc = tcase_create("test_gmcast_multicast"); tcase_add_test(tc, test_gmcast_multicast); suite_add_tcase(s, tc); } tc = tcase_create("test_gmcast_w_user_messages"); tcase_add_test(tc, test_gmcast_w_user_messages); tcase_set_timeout(tc, 30); suite_add_tcase(s, tc); if (run_all_tests == true) { // not run by default, hard coded port tc = tcase_create("test_gmcast_auto_addr"); tcase_add_test(tc, test_gmcast_auto_addr); suite_add_tcase(s, tc); } tc = tcase_create("test_gmcast_forget"); tcase_add_test(tc, test_gmcast_forget); tcase_set_timeout(tc, 20); suite_add_tcase(s, tc); if (run_all_tests == true) { // not run by default, hard coded port tc = tcase_create("test_trac_380"); tcase_add_test(tc, test_trac_380); suite_add_tcase(s, tc); } tc = tcase_create("test_trac_828"); tcase_add_test(tc, test_trac_828); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/gcomm/test/check_pc.cpp000066400000000000000000003722701244131713600213410ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "check_gcomm.hpp" #include "pc_message.hpp" #include "pc_proto.hpp" #include "evs_proto.hpp" #include "check_templ.hpp" #include "check_trace.hpp" #include "gcomm/conf.hpp" #include "gu_errno.h" #include #include #include #include using namespace std; using namespace std::rel_ops; using namespace gu::datetime; using namespace gcomm; using namespace gcomm::pc; using gu::byte_t; using gu::Buffer; using gu::Exception; using gu::URI; using gu::DeleteObject; START_TEST(test_pc_messages) { StateMessage pcs(0); pc::NodeMap& sim(pcs.node_map()); sim.insert(std::make_pair(UUID(0,0), pc::Node(true, false, false, 6, ViewId(V_PRIM, UUID(0, 0), 9), 42, -1))); sim.insert(std::make_pair(UUID(0,0), pc::Node(false, true, false, 88, ViewId(V_PRIM, UUID(0, 0), 3), 472, 0))); sim.insert(std::make_pair(UUID(0,0), pc::Node(true, false, true, 78, ViewId(V_PRIM, UUID(0, 0), 87), 52, 1))); size_t expt_size = 4 // hdr + 4 // seq + 4 + 3*(UUID::serial_size() + sizeof(uint32_t) + 4 + 20 + 8); // NodeMap check_serialization(pcs, expt_size, StateMessage(-1)); InstallMessage pci(0); pc::NodeMap& iim = pci.node_map(); iim.insert(std::make_pair(UUID(0,0), pc::Node(true, true, true, 6, ViewId(V_PRIM, UUID(0, 0), 9), 42, -1))); iim.insert(std::make_pair(UUID(0,0), pc::Node(false, false, false, 88, ViewId(V_NON_PRIM, UUID(0, 0), 3), 472, 0))); iim.insert(std::make_pair(UUID(0,0), pc::Node(true, false, false, 78, ViewId(V_PRIM, UUID(0, 0), 87), 52, 1))); iim.insert(std::make_pair(UUID(0,0), pc::Node(false, true, true, 457, ViewId(V_NON_PRIM, UUID(0, 0), 37), 56, 0xff))); expt_size = 4 // hdr + 4 // seq + 4 + 4*(UUID::serial_size() + sizeof(uint32_t) + 4 + 20 + 8); // NodeMap check_serialization(pci, expt_size, InstallMessage(-1)); UserMessage pcu(0, 7); pcu.checksum(0xfefe, true); expt_size = 4 + 4; check_serialization(pcu, expt_size, UserMessage(-1, -1U)); fail_unless(pcu.serial_size() % 4 == 0); } END_TEST class PCUser : public Toplay { public: PCUser(gu::Config& conf, const UUID& uuid, DummyTransport *tp, Proto* pc) : Toplay(conf), views_(), uuid_(uuid), tp_(tp), pc_(pc) { gcomm::connect(tp_, pc_); gcomm::connect(pc_, this); } const UUID& uuid() const { return uuid_; } DummyTransport* tp() { return tp_; } Proto* pc() { return pc_; } void handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (um.has_view() == true) { const View& view(um.view()); log_info << view; fail_unless(view.type() == V_PRIM || view.type() == V_NON_PRIM); views_.push_back(View(view)); } } void send() { byte_t pl[4] = {1, 2, 3, 4}; Buffer buf(pl, pl + sizeof(pl)); Datagram dg(buf); fail_unless(send_down(dg, ProtoDownMeta()) == 0); } private: PCUser(const PCUser&); void operator=(const PCUser&); list views_; UUID uuid_; DummyTransport* tp_; Proto* pc_; }; void get_msg(Datagram* rb, Message* msg, bool release = true) { assert(msg != 0); if (rb == 0) { log_info << "get_msg: (null)"; } else { // assert(rb->get_header().size() == 0 && rb->get_offset() == 0); const byte_t* begin(gcomm::begin(*rb)); const size_t available(gcomm::available(*rb)); fail_unless(msg->unserialize(begin, available, 0) != 0); log_info << "get_msg: " << msg->to_string(); if (release) delete rb; } } void single_boot(int version, PCUser* pu1) { ProtoUpMeta sum1(pu1->uuid()); View vt0(version, ViewId(V_TRANS, pu1->uuid(), 0)); vt0.add_member(pu1->uuid(), 0); ProtoUpMeta um1(UUID::nil(), ViewId(), &vt0); pu1->pc()->connect(true); // pu1->pc()->shift_to(Proto::S_JOINING); pu1->pc()->handle_up(0, Datagram(), um1); fail_unless(pu1->pc()->state() == Proto::S_TRANS); View vr1(version, ViewId(V_REG, pu1->uuid(), 1)); vr1.add_member(pu1->uuid(), 0); ProtoUpMeta um2(UUID::nil(), ViewId(), &vr1); pu1->pc()->handle_up(0, Datagram(), um2); fail_unless(pu1->pc()->state() == Proto::S_STATES_EXCH); Datagram* rb = pu1->tp()->out(); fail_unless(rb != 0); Message sm1; get_msg(rb, &sm1); fail_unless(sm1.type() == Message::T_STATE); fail_unless(sm1.node_map().size() == 1); { const pc::Node& pi1 = pc::NodeMap::value(sm1.node_map().begin()); fail_unless(pi1.prim() == true); fail_unless(pi1.last_prim() == ViewId(V_PRIM, pu1->uuid(), 0)); } pu1->pc()->handle_msg(sm1, Datagram(), sum1); fail_unless(pu1->pc()->state() == Proto::S_INSTALL); rb = pu1->tp()->out(); fail_unless(rb != 0); Message im1; get_msg(rb, &im1); fail_unless(im1.type() == Message::T_INSTALL); fail_unless(im1.node_map().size() == 1); { const pc::Node& pi1 = pc::NodeMap::value(im1.node_map().begin()); fail_unless(pi1.prim() == true); fail_unless(pi1.last_prim() == ViewId(V_PRIM, pu1->uuid(), 0)); } pu1->pc()->handle_msg(im1, Datagram(), sum1); fail_unless(pu1->pc()->state() == Proto::S_PRIM); } START_TEST(test_pc_view_changes_single) { log_info << "START (test_pc_view_changes_single)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(0, 0); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); } END_TEST static void double_boot(int version, PCUser* pu1, PCUser* pu2) { ProtoUpMeta pum1(pu1->uuid()); ProtoUpMeta pum2(pu2->uuid()); View t11(version, ViewId(V_TRANS, pu1->pc()->current_view().id())); t11.add_member(pu1->uuid(), 0); pu1->pc()->handle_view(t11); fail_unless(pu1->pc()->state() == Proto::S_TRANS); View t12(version, ViewId(V_TRANS, pu2->uuid(), 0)); t12.add_member(pu2->uuid(), 0); // pu2->pc()->shift_to(Proto::S_JOINING); pu2->pc()->connect(false); pu2->pc()->handle_view(t12); fail_unless(pu2->pc()->state() == Proto::S_TRANS); View r1(version, ViewId(V_REG, pu1->uuid(), pu1->pc()->current_view().id().seq() + 1)); r1.add_member(pu1->uuid(), 0); r1.add_member(pu2->uuid(), 0); pu1->pc()->handle_view(r1); fail_unless(pu1->pc()->state() == Proto::S_STATES_EXCH); pu2->pc()->handle_view(r1); fail_unless(pu2->pc()->state() == Proto::S_STATES_EXCH); Datagram* rb = pu1->tp()->out(); fail_unless(rb != 0); Message sm1; get_msg(rb, &sm1); fail_unless(sm1.type() == Message::T_STATE); rb = pu2->tp()->out(); fail_unless(rb != 0); Message sm2; get_msg(rb, &sm2); fail_unless(sm2.type() == Message::T_STATE); rb = pu1->tp()->out(); fail_unless(rb == 0); rb = pu2->tp()->out(); fail_unless(rb == 0); pu1->pc()->handle_msg(sm1, Datagram(), pum1); rb = pu1->tp()->out(); fail_unless(rb == 0); fail_unless(pu1->pc()->state() == Proto::S_STATES_EXCH); pu1->pc()->handle_msg(sm2, Datagram(), pum2); fail_unless(pu1->pc()->state() == Proto::S_INSTALL); pu2->pc()->handle_msg(sm1, Datagram(), pum1); rb = pu2->tp()->out(); fail_unless(rb == 0); fail_unless(pu2->pc()->state() == Proto::S_STATES_EXCH); pu2->pc()->handle_msg(sm2, Datagram(), pum2); fail_unless(pu2->pc()->state() == Proto::S_INSTALL); Message im1; UUID imsrc; if (pu1->uuid() < pu2->uuid()) { rb = pu1->tp()->out(); imsrc = pu1->uuid(); } else { rb = pu2->tp()->out(); imsrc = pu2->uuid(); } fail_unless(rb != 0); get_msg(rb, &im1); fail_unless(im1.type() == Message::T_INSTALL); fail_unless(pu1->tp()->out() == 0); fail_unless(pu2->tp()->out() == 0); ProtoUpMeta ipum(imsrc); pu1->pc()->handle_msg(im1, Datagram(), ipum); fail_unless(pu1->pc()->state() == Proto::S_PRIM); pu2->pc()->handle_msg(im1, Datagram(), ipum); fail_unless(pu2->pc()->state() == Proto::S_PRIM); } // Form PC for three instances. static void triple_boot(int version, PCUser* pu1, PCUser* pu2, PCUser* pu3) { fail_unless(pu1->uuid() < pu2->uuid() && pu2->uuid() < pu3->uuid()); // trans views { View tr12(version, ViewId(V_TRANS, pu1->pc()->current_view().id())); tr12.add_member(pu1->uuid(), 0); tr12.add_member(pu2->uuid(), 0); ProtoUpMeta trum12(UUID::nil(), ViewId(), &tr12); pu1->pc()->handle_up(0, Datagram(), trum12); pu2->pc()->handle_up(0, Datagram(), trum12); fail_unless(pu1->pc()->state() == Proto::S_TRANS); fail_unless(pu2->pc()->state() == Proto::S_TRANS); pu3->pc()->connect(false); View tr3(version, ViewId(V_TRANS, pu3->uuid(), 0)); tr3.add_member(pu3->uuid(), 0); ProtoUpMeta trum3(UUID::nil(), ViewId(), &tr3); pu3->pc()->handle_up(0, Datagram(), trum3); fail_unless(pu3->pc()->state() == Proto::S_TRANS); } // reg view { View reg(version, ViewId(V_REG, pu1->uuid(), pu1->pc()->current_view().id().seq() + 1)); reg.add_member(pu1->uuid(), 0); reg.add_member(pu2->uuid(), 0); reg.add_member(pu3->uuid(), 0); ProtoUpMeta pum(UUID::nil(), ViewId(), ®); pu1->pc()->handle_up(0, Datagram(), pum); pu2->pc()->handle_up(0, Datagram(), pum); pu3->pc()->handle_up(0, Datagram(), pum); fail_unless(pu1->pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2->pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3->pc()->state() == Proto::S_STATES_EXCH); } // states exch { Datagram* dg(pu1->tp()->out()); fail_unless(dg != 0); pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); delete dg; dg = pu2->tp()->out(); fail_unless(dg != 0); pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid())); pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid())); pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu2->uuid())); delete dg; dg = pu3->tp()->out(); fail_unless(dg != 0); pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid())); pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid())); pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu3->uuid())); delete dg; fail_unless(pu1->pc()->state() == Proto::S_INSTALL); fail_unless(pu2->pc()->state() == Proto::S_INSTALL); fail_unless(pu3->pc()->state() == Proto::S_INSTALL); } // install { Datagram* dg(pu1->tp()->out()); fail_unless(dg != 0); pu1->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); pu2->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); pu3->pc()->handle_up(0, *dg, ProtoUpMeta(pu1->uuid())); delete dg; fail_unless(pu1->pc()->state() == Proto::S_PRIM); fail_unless(pu2->pc()->state() == Proto::S_PRIM); fail_unless(pu3->pc()->state() == Proto::S_PRIM); } } START_TEST(test_pc_view_changes_double) { log_info << "START (test_pc_view_changes_double)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); Datagram* rb; View tnp(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tnp.add_member(uuid1, 0); pu1.pc()->handle_view(tnp); fail_unless(pu1.pc()->state() == Proto::S_TRANS); View reg(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg.add_member(uuid1, 0); pu1.pc()->handle_view(reg); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); rb = pu1.tp()->out(); fail_unless(rb != 0); pu1.pc()->handle_up(0, *rb, ProtoUpMeta(uuid1)); fail_unless(pu1.pc()->state() == Proto::S_NON_PRIM); delete rb; View tpv2(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tpv2.add_member(uuid2, 0); tpv2.add_left(uuid1, 0); pu2.pc()->handle_view(tpv2); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu2.tp()->out() == 0); View rp2(0, ViewId(V_REG, uuid2, pu1.pc()->current_view().id().seq() + 1)); rp2.add_member(uuid2, 0); rp2.add_left(uuid1, 0); pu2.pc()->handle_view(rp2); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); rb = pu2.tp()->out(); fail_unless(rb != 0); Message sm2; get_msg(rb, &sm2); fail_unless(sm2.type() == Message::T_STATE); fail_unless(pu2.tp()->out() == 0); pu2.pc()->handle_msg(sm2, Datagram(), pum2); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); rb = pu2.tp()->out(); fail_unless(rb != 0); Message im2; get_msg(rb, &im2); fail_unless(im2.type() == Message::T_INSTALL); pu2.pc()->handle_msg(im2, Datagram(), pum2); fail_unless(pu2.pc()->state() == Proto::S_PRIM); } END_TEST /* Test that UUID ordering does not matter when starting nodes */ START_TEST(test_pc_view_changes_reverse) { log_info << "START (test_pc_view_changes_reverse)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); single_boot(0, &pu2); double_boot(0, &pu2, &pu1); } END_TEST START_TEST(test_pc_state1) { log_info << "START (test_pc_state1)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM // n2: JOINING -> STATES_EXCH -> RTR -> PRIM double_boot(0, &pu1, &pu2); fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); // PRIM -> TRANS -> STATES_EXCH -> RTR -> TRANS -> STATES_EXCH -> RTR ->PRIM View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(uuid1, 0); tr1.add_member(uuid2, 0); pu1.pc()->handle_view(tr1); pu2.pc()->handle_view(tr1); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu1.tp()->out() == 0); fail_unless(pu2.tp()->out() == 0); View reg2(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg2.add_member(uuid1, 0); reg2.add_member(uuid2, 0); pu1.pc()->handle_view(reg2); pu2.pc()->handle_view(reg2); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); Message msg; get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); pu2.pc()->handle_msg(msg, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu2.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum2); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_INSTALL); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); View tr2(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr2.add_member(uuid1, 0); tr2.add_member(uuid2, 0); pu1.pc()->handle_view(tr2); pu2.pc()->handle_view(tr2); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); Message im; if (uuid1 < uuid2) { get_msg(pu1.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum1); pu2.pc()->handle_msg(im, Datagram(), pum1); } else { get_msg(pu2.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum2); pu2.pc()->handle_msg(im, Datagram(), pum2); } fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg3.add_member(uuid1, 0); reg3.add_member(uuid2, 0); pu1.pc()->handle_view(reg3); pu2.pc()->handle_view(reg3); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); pu2.pc()->handle_msg(msg, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu2.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum2); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_INSTALL); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); if (uuid1 < uuid2) { get_msg(pu1.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum1); pu2.pc()->handle_msg(im, Datagram(), pum1); } else { get_msg(pu2.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum2); pu2.pc()->handle_msg(im, Datagram(), pum2); } fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); } END_TEST START_TEST(test_pc_state2) { log_info << "START (test_pc_state2)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM // n2: JOINING -> STATES_EXCH -> RTR -> PRIM double_boot(0, &pu1, &pu2); fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); // PRIM -> TRANS -> STATES_EXCH -> TRANS -> STATES_EXCH -> RTR -> PRIM View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(uuid1, 0); tr1.add_member(uuid2, 0); pu1.pc()->handle_view(tr1); pu2.pc()->handle_view(tr1); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu1.tp()->out() == 0); fail_unless(pu2.tp()->out() == 0); View reg2(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg2.add_member(uuid1, 0); reg2.add_member(uuid2, 0); pu1.pc()->handle_view(reg2); pu2.pc()->handle_view(reg2); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); View tr2(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr2.add_member(uuid1, 0); tr2.add_member(uuid2, 0); pu1.pc()->handle_view(tr2); pu2.pc()->handle_view(tr2); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); Message msg; get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); pu2.pc()->handle_msg(msg, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); get_msg(pu2.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum2); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg3.add_member(uuid1, 0); reg3.add_member(uuid2, 0); pu1.pc()->handle_view(reg3); pu2.pc()->handle_view(reg3); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); pu2.pc()->handle_msg(msg, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu2.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum2); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_INSTALL); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); Message im; if (uuid1 < uuid2) { get_msg(pu1.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum1); pu2.pc()->handle_msg(im, Datagram(), pum1); } else { get_msg(pu2.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum2); pu2.pc()->handle_msg(im, Datagram(), pum2); } fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); } END_TEST START_TEST(test_pc_state3) { log_info << "START (test_pc_state3)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); // n1: PRIM -> TRANS -> STATES_EXCH -> RTR -> PRIM // n2: JOINING -> STATES_EXCH -> RTR -> PRIM double_boot(0, &pu1, &pu2); fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); // PRIM -> NON_PRIM -> STATES_EXCH -> RTR -> NON_PRIM -> STATES_EXCH -> ... // -> NON_PRIM -> STATES_EXCH -> RTR -> NON_PRIM View tr11(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr11.add_member(uuid1, 0); pu1.pc()->handle_view(tr11); View tr12(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr12.add_member(uuid2, 0); pu2.pc()->handle_view(tr12); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu1.tp()->out() == 0); fail_unless(pu2.tp()->out() == 0); View reg21(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg21.add_member(uuid1, 0); pu1.pc()->handle_view(reg21); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); View reg22(0, ViewId(V_REG, uuid2, pu2.pc()->current_view().id().seq() + 1)); reg22.add_member(uuid2, 0); pu2.pc()->handle_view(reg22); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); Message msg; get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); get_msg(pu2.tp()->out(), &msg); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_NON_PRIM); fail_unless(pu2.pc()->state() == Proto::S_NON_PRIM); View tr21(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr21.add_member(uuid1, 0); pu1.pc()->handle_view(tr21); View tr22(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr22.add_member(uuid2, 0); pu2.pc()->handle_view(tr22); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu1.tp()->out() == 0); fail_unless(pu2.tp()->out() == 0); View reg3(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg3.add_member(uuid1, 0); reg3.add_member(uuid2, 0); pu1.pc()->handle_view(reg3); pu2.pc()->handle_view(reg3); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu1.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum1); pu2.pc()->handle_msg(msg, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); get_msg(pu2.tp()->out(), &msg); pu1.pc()->handle_msg(msg, Datagram(), pum2); pu2.pc()->handle_msg(msg, Datagram(), pum2); fail_unless(pu1.pc()->state() == Proto::S_INSTALL); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); Message im; if (uuid1 < uuid2) { get_msg(pu1.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum1); pu2.pc()->handle_msg(im, Datagram(), pum1); } else { get_msg(pu2.tp()->out(), &im); pu1.pc()->handle_msg(im, Datagram(), pum2); pu2.pc()->handle_msg(im, Datagram(), pum2); } fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); } END_TEST START_TEST(test_pc_conflicting_prims) { log_info << "START (test_pc_conflicting_prims)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); single_boot(0, &pu2); View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(uuid1, 0); pu1.pc()->handle_view(tr1); View tr2(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr2.add_member(uuid2, 0); pu2.pc()->handle_view(tr2); View reg(0, ViewId(V_REG, uuid1, tr1.id().seq() + 1)); reg.add_member(uuid1, 0); reg.add_member(uuid2, 0); pu1.pc()->handle_view(reg); pu2.pc()->handle_view(reg); Message msg1, msg2; /* First node must discard msg2 and stay in states exch waiting for * trans view */ get_msg(pu1.tp()->out(), &msg1); get_msg(pu2.tp()->out(), &msg2); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); pu1.pc()->handle_msg(msg1, Datagram(), pum1); pu1.pc()->handle_msg(msg2, Datagram(), pum2); /* Second node must abort */ try { pu2.pc()->handle_msg(msg1, Datagram(), pum1); fail("not aborted"); } catch (Exception& e) { log_info << e.what(); } fail_unless(pu1.tp()->out() == 0); View tr3(0, ViewId(V_TRANS, reg.id())); tr3.add_member(uuid1, 0); pu1.pc()->handle_view(tr3); View reg3(0, ViewId(V_REG, uuid1, tr3.id().seq() + 1)); reg3.add_member(uuid1, 0); pu1.pc()->handle_view(reg3); get_msg(pu1.tp()->out(), &msg1); pu1.pc()->handle_msg(msg1, Datagram(), pum1); get_msg(pu1.tp()->out(), &msg1); pu1.pc()->handle_msg(msg1, Datagram(), pum1); fail_unless(pu1.pc()->state() == Proto::S_PRIM); } END_TEST START_TEST(test_pc_conflicting_prims_npvo) { log_info << "START (test_pc_conflicting_npvo)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0, URI("pc://?pc.npvo=true")); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf, uuid2, 0, URI("pc://?pc.npvo=true")); DummyTransport tp2; PCUser pu2(conf, uuid2, &tp2, &pc2); single_boot(0, &pu2); View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(uuid1, 0); pu1.pc()->handle_view(tr1); View tr2(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr2.add_member(uuid2, 0); pu2.pc()->handle_view(tr2); View reg(0, ViewId(V_REG, uuid1, tr1.id().seq() + 1)); reg.add_member(uuid1, 0); reg.add_member(uuid2, 0); pu1.pc()->handle_view(reg); pu2.pc()->handle_view(reg); Message msg1, msg2; /* First node must discard msg2 and stay in states exch waiting for * trans view */ get_msg(pu1.tp()->out(), &msg1); get_msg(pu2.tp()->out(), &msg2); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); pu1.pc()->handle_msg(msg1, Datagram(), pum1); pu2.pc()->handle_msg(msg1, Datagram(), pum1); /* First node must abort */ try { pu1.pc()->handle_msg(msg2, Datagram(), pum2); fail("not aborted"); } catch (Exception& e) { log_info << e.what(); } fail_unless(pu2.tp()->out() == 0); View tr3(0, ViewId(V_TRANS, reg.id())); tr3.add_member(uuid2, 0); pu2.pc()->handle_view(tr3); View reg3(0, ViewId(V_REG, uuid2, tr3.id().seq() + 1)); reg3.add_member(uuid2, 0); pu2.pc()->handle_view(reg3); get_msg(pu2.tp()->out(), &msg2); pu2.pc()->handle_msg(msg2, Datagram(), pum2); get_msg(pu2.tp()->out(), &msg2); pu2.pc()->handle_msg(msg2, Datagram(), pum2); fail_unless(pu2.pc()->state() == Proto::S_PRIM); } END_TEST static void join_node(PropagationMatrix* p, DummyNode* n, bool first) { log_info << first; gu_trace(p->insert_tp(n)); gu_trace(n->connect(first)); } static void send_n(DummyNode* node, const size_t n) { for (size_t i = 0; i < n; ++i) { gu_trace(node->send()); } } static void set_cvi(vector& nvec, size_t i_begin, size_t i_end, size_t seq, ViewType type) { for (size_t i = i_begin; i <= i_end; ++i) { nvec[i]->set_cvi(ViewId(type, type == V_NON_PRIM ? nvec[0]->uuid() : nvec[i_begin]->uuid(), static_cast(type == V_NON_PRIM ? seq - 1 : seq))); } } struct InitGuConf { explicit InitGuConf(gu::Config& conf) { gcomm::Conf::register_params(conf); } }; static gu::Config& static_gu_conf() { static gu::Config conf; static InitGuConf init(conf); return conf; } static DummyNode* create_dummy_node(size_t idx, int version, const string& suspect_timeout = "PT1H", const string& inactive_timeout = "PT1H", const string& retrans_period = "PT20M", int weight = 1) { gu::Config& gu_conf(static_gu_conf()); gcomm::Conf::register_params(gu_conf); const string conf = "evs://?" + Conf::EvsViewForgetTimeout + "=PT1H&" + Conf::EvsInactiveCheckPeriod + "=" + to_string(Period(suspect_timeout)/3) + "&" + Conf::EvsSuspectTimeout + "=" + suspect_timeout + "&" + Conf::EvsInactiveTimeout + "=" + inactive_timeout + "&" + Conf::EvsKeepalivePeriod + "=" + retrans_period + "&" + Conf::EvsJoinRetransPeriod + "=" + retrans_period + "&" + Conf::EvsInstallTimeout + "=" + inactive_timeout + "&" + Conf::PcWeight + "=" + gu::to_string(weight) + "&" + Conf::EvsVersion + "=" + gu::to_string(version) + "&" + Conf::EvsInfoLogMask + "=" + "0x3"; list protos; UUID uuid(static_cast(idx)); protos.push_back(new DummyTransport(uuid, false)); protos.push_back(new evs::Proto(gu_conf, uuid, 0, conf)); protos.push_back(new Proto(gu_conf, uuid, 0, conf)); return new DummyNode(gu_conf, idx, protos); } namespace { gcomm::pc::Proto* pc_from_dummy(DummyNode* dn) { return reinterpret_cast(dn->protos().back()); } } static ViewType view_type(const size_t i_begin, const size_t i_end, const size_t n_nodes) { return (((i_end - i_begin + 1)*2 > n_nodes) ? V_PRIM : V_NON_PRIM); } START_TEST(test_pc_split_merge) { log_info << "START (test_pc_split_merge)"; size_t n_nodes(5); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; mark_point(); for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } mark_point(); for (size_t i = 1; i < n_nodes; ++i) { for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { prop.split(j + 1, k + 1); } } ++view_seq; log_info << "split " << i << " view seq " << view_seq; set_cvi(dn, 0, i - 1, view_seq, view_type(0, i - 1, n_nodes)); set_cvi(dn, i, n_nodes - 1, view_seq, view_type(i,n_nodes - 1,n_nodes)); gu_trace(prop.propagate_until_cvi(true)); for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { prop.merge(j + 1, k + 1); } } ++view_seq; log_info << "merge " << i << " view seq " << view_seq; set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); } mark_point(); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_pc_split_merge_w_user_msg) { log_info << "START (test_pc_split_merge_w_user_msg)"; size_t n_nodes(5); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 1; i < n_nodes; ++i) { for (size_t j = 0; j < n_nodes; ++j) { send_n(dn[j], ::rand() % 5); } for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { prop.split(j + 1, k + 1); } } ++view_seq; log_info << "split " << i << " view seq " << view_seq; set_cvi(dn, 0, i - 1, view_seq, view_type(0, i - 1, n_nodes)); set_cvi(dn, i, n_nodes - 1, view_seq, view_type(i, n_nodes - 1, n_nodes)); gu_trace(prop.propagate_until_cvi(true)); for (size_t j = 0; j < n_nodes; ++j) { send_n(dn[j], ::rand() % 5); } for (size_t j = 0; j < i; ++j) { for (size_t k = i; k < n_nodes; ++k) { prop.merge(j + 1, k + 1); } } ++view_seq; log_info << "merge " << i << " view seq " << view_seq; set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); } check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_pc_complete_split_merge) { log_info << "START (test_pc_complete_split_merge)"; size_t n_nodes(5); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.31S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period)); log_info << "i " << i; gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } for (size_t i = 0; i < 5; ++i) { for (size_t j = 0; j < n_nodes; ++j) { send_n(dn[j], ::rand() % 5); } prop.propagate_n(9 + ::rand() % 5); for (size_t j = 0; j < n_nodes; ++j) { for (size_t k = 0; k < n_nodes; ++k) { if (j != k) { prop.split(j + 1, k + 1); } } } ++view_seq; log_info << "split " << i << " view seq " << view_seq; set_cvi(dn, 0, n_nodes - 1, view_seq, V_NON_PRIM); gu_trace(prop.propagate_until_cvi(true)); for (size_t j = 0; j < n_nodes; ++j) { for (size_t k = 0; k < n_nodes; ++k) { if (j != k) { prop.merge(j + 1, k + 1); } } } ++view_seq; log_info << "merge " << i << " view seq " << view_seq; set_cvi(dn, 0, n_nodes - 1, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); } check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_pc_protocol_upgrade) { log_info << "START (test_pc_protocol_upgrade)"; vector dn; PropagationMatrix prop; uint32_t view_seq(0); for (int i(0); i <= GCOMM_PROTOCOL_MAX_VERSION; ++i) { dn.push_back(create_dummy_node(i + 1, i)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); ++view_seq; for (int j(0); j <= i; ++j) { fail_unless(pc_from_dummy(dn[j])->current_view().version() == 0); gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } } for (int i(0); i < GCOMM_PROTOCOL_MAX_VERSION; ++i) { for (int j(i); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } dn[i]->close(); dn[i]->set_cvi(V_NON_PRIM); set_cvi(dn, i + 1, GCOMM_PROTOCOL_MAX_VERSION, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); ++view_seq; for (int j(i + 1); j <= GCOMM_PROTOCOL_MAX_VERSION; ++j) { gu_trace(send_n(dn[j], 5 + ::rand() % 4)); } gu_trace(prop.propagate_until_empty()); } fail_unless(pc_from_dummy(dn[GCOMM_PROTOCOL_MAX_VERSION])->current_view().version() == GCOMM_PROTOCOL_MAX_VERSION); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST class PCUser2 : public Toplay { Transport* tp_; bool sending_; uint8_t my_type_; bool send_; Period send_period_; Date next_send_; PCUser2(const PCUser2&); void operator=(const PCUser2); public: PCUser2(Protonet& net, const string& uri, const bool send = true) : Toplay(net.conf()), tp_(Transport::create(net, uri)), sending_(false), my_type_(static_cast(1 + ::rand()%4)), send_(send), send_period_("PT0.05S"), next_send_(Date::max()) { } ~PCUser2() { delete tp_; } void start() { gcomm::connect(tp_, this); tp_->connect(); gcomm::disconnect(tp_, this); tp_->pstack().push_proto(this); } void stop() { sending_ = false; tp_->pstack().pop_proto(this); gcomm::connect(tp_, this); tp_->close(); gcomm::disconnect(tp_, this); } void handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (um.has_view()) { const View& view(um.view()); log_info << view; if (view.type() == V_PRIM && send_ == true) { sending_ = true; next_send_ = Date::now() + send_period_; } } else { // log_debug << "received message: " << um.get_to_seq(); fail_unless(rb.len() - rb.offset() == 16); if (um.source() == tp_->uuid()) { fail_unless(um.user_type() == my_type_); } } } Protostack& pstack() { return tp_->pstack(); } Date handle_timers() { Date now(Date::now()); if (now >= next_send_) { byte_t buf[16]; memset(buf, 0xa, sizeof(buf)); Datagram dg(Buffer(buf, buf + sizeof(buf))); // dg.get_header().resize(128); // dg.set_header_offset(128); int ret = send_down(dg, ProtoDownMeta(my_type_, rand() % 10 == 0 ? O_SAFE : O_LOCAL_CAUSAL)); if (ret != 0) { // log_debug << "send down " << ret; } next_send_ = next_send_ + send_period_; } return next_send_; } std::string listen_addr() const { return tp_->listen_addr(); } }; START_TEST(test_pc_transport) { log_info << "START (test_pc_transport)"; gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr net(Protonet::create(conf)); PCUser2 pu1(*net, "pc://?" "evs.info_log_mask=0xff&" "gmcast.listen_addr=tcp://127.0.0.1:0&" "gmcast.group=pc&" "gmcast.time_wait=PT0.5S&" "pc.recovery=0&" "node.name=n1"); gu_conf_self_tstamp_on(); pu1.start(); net->event_loop(5*Sec); PCUser2 pu2(*net, std::string("pc://") + pu1.listen_addr().erase(0, strlen("tcp://")) + "?evs.info_log_mask=0xff&" "gmcast.group=pc&" "gmcast.time_wait=PT0.5S&" "gmcast.listen_addr=tcp://127.0.0.1:0&" "pc.recovery=0&" "node.name=n2"); PCUser2 pu3(*net, std::string("pc://") + pu1.listen_addr().erase(0, strlen("tcp://")) + "?evs.info_log_mask=0xff&" "gmcast.group=pc&" "gmcast.time_wait=PT0.5S&" "gmcast.listen_addr=tcp://127.0.0.1:0&" "pc.recovery=0&" "node.name=n3"); pu2.start(); net->event_loop(5*Sec); pu3.start(); net->event_loop(5*Sec); pu3.stop(); net->event_loop(5*Sec); pu2.stop(); net->event_loop(5*Sec); pu1.stop(); log_info << "cleanup"; net->event_loop(0); log_info << "finished"; } END_TEST START_TEST(test_trac_191) { log_info << "START (test_trac_191)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1), uuid2(2), uuid3(3), uuid4(4); Proto p(conf, uuid4, 0); DummyTransport tp(uuid4, true); // gcomm::connect(&tp, &p); PCUser pu(conf, uuid4, &tp, &p); p.shift_to(Proto::S_NON_PRIM); View t0(0, ViewId(V_TRANS, uuid4, 0)); t0.add_member(uuid4, 0); p.handle_view(t0); View r5(0, ViewId(V_REG, uuid2, 5)); r5.add_member(uuid3, 0); r5.add_member(uuid4, 0); p.handle_view(r5); Datagram* dg = tp.out(); fail_unless(dg != 0); Message sm4; get_msg(dg, &sm4); fail_unless(sm4.type() == Message::T_STATE); // Handle first sm from uuid3 StateMessage sm3(0); pc::NodeMap& im3(sm3.node_map()); im3.insert_unique(make_pair(uuid1, pc::Node(true, false, false, 254, ViewId(V_PRIM, uuid1, 3), 20))); im3.insert_unique(make_pair(uuid2, pc::Node(true, false, false, 254, ViewId(V_PRIM, uuid1, 3), 20))); im3.insert_unique(make_pair(uuid3, pc::Node(false, false, false, 254, ViewId(V_PRIM, uuid1, 3), 25))); p.handle_msg(sm3, Datagram(), ProtoUpMeta(uuid3)); p.handle_msg(sm4, Datagram(), ProtoUpMeta(uuid4)); } END_TEST START_TEST(test_trac_413) { log_info << "START (test_trac_413)"; class TN : gcomm::Toplay // test node { public: TN(gu::Config conf, const UUID& uuid) : Toplay(conf), p_(conf, uuid, 0), tp_(uuid, true) { gcomm::connect(&tp_, &p_); gcomm::connect(&p_, this); } const UUID& uuid() const { return p_.uuid(); } gcomm::pc::Proto& p() { return p_; } DummyTransport& tp() { return tp_; } void handle_up(const void* id, const Datagram& dg, const gcomm::ProtoUpMeta& um) { // void } private: pc::Proto p_; DummyTransport tp_; }; gu::Config conf; gcomm::Conf::register_params(conf); TN n1(conf, 1), n2(conf, 2), n3(conf, 3); // boot to first prim { gcomm::View tr(0, ViewId(V_TRANS, n1.uuid(), 0)); tr.members().insert_unique(std::make_pair(n1.uuid(), 0)); n1.p().connect(true); n1.p().handle_view(tr); Datagram* dg(n1.tp().out()); fail_unless(dg == 0 && n1.p().state() == gcomm::pc::Proto::S_TRANS); gcomm::View reg(0, ViewId(V_REG, n1.uuid(), 1)); reg.members().insert_unique(std::make_pair(n1.uuid(), 0)); n1.p().handle_view(reg); dg = n1.tp().out(); fail_unless(dg != 0 && n1.p().state() == gcomm::pc::Proto::S_STATES_EXCH); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); delete dg; dg = n1.tp().out(); fail_unless(dg != 0 && n1.p().state() == gcomm::pc::Proto::S_INSTALL); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); delete dg; dg = n1.tp().out(); fail_unless(dg == 0 && n1.p().state() == gcomm::pc::Proto::S_PRIM); } // add remaining nodes { gcomm::View tr(0, ViewId(V_TRANS, n1.uuid(), 1)); tr.members().insert_unique(std::make_pair(n1.uuid(), 0)); n1.p().handle_view(tr); } { gcomm::View tr(0, ViewId(V_TRANS, n2.uuid(), 0)); tr.members().insert_unique(std::make_pair(n2.uuid(), 0)); n2.p().connect(false); n2.p().handle_view(tr); } { gcomm::View tr(0, ViewId(V_TRANS, n3.uuid(), 0)); tr.members().insert_unique(std::make_pair(n3.uuid(), 0)); n3.p().connect(false); n3.p().handle_view(tr); } { gcomm::View reg(0, ViewId(V_REG, n1.uuid(), 2)); reg.members().insert_unique(std::make_pair(n1.uuid(), 0)); reg.members().insert_unique(std::make_pair(n2.uuid(), 0)); reg.members().insert_unique(std::make_pair(n3.uuid(), 0)); n1.p().handle_view(reg); n2.p().handle_view(reg); n3.p().handle_view(reg); Datagram* dg(n1.tp().out()); fail_unless(dg != 0); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); delete dg; dg = n2.tp().out(); fail_unless(dg != 0); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid())); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid())); delete dg; dg = n3.tp().out(); fail_unless(dg != 0); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid())); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid())); delete dg; dg = n1.tp().out(); fail_unless(dg != 0); n1.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n1.uuid())); delete dg; fail_unless(n1.tp().out() == 0 && n1.p().state() == gcomm::pc::Proto::S_PRIM); fail_unless(n2.tp().out() == 0 && n2.p().state() == gcomm::pc::Proto::S_PRIM); fail_unless(n3.tp().out() == 0 && n3.p().state() == gcomm::pc::Proto::S_PRIM); } mark_point(); // drop n1 from view and deliver only state messages in // the following reg view { gcomm::View tr(0, gcomm::ViewId(V_TRANS, n1.uuid(), 2)); tr.members().insert_unique(std::make_pair(n2.uuid(), 0)); tr.members().insert_unique(std::make_pair(n3.uuid(), 0)); n2.p().handle_view(tr); n3.p().handle_view(tr); gcomm::View reg(0, gcomm::ViewId(V_REG, n2.uuid(), 3)); reg.members().insert_unique(std::make_pair(n2.uuid(), 0)); reg.members().insert_unique(std::make_pair(n3.uuid(), 0)); n2.p().handle_view(reg); n3.p().handle_view(reg); Datagram* dg(n2.tp().out()); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n2.uuid())); delete dg; dg = n3.tp().out(); n2.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid())); n3.p().handle_up(0, *dg, gcomm::ProtoUpMeta(n3.uuid())); delete dg; } mark_point(); // drop n2 from view and make sure that n3 ends in non-prim { gcomm::View tr(0, gcomm::ViewId(V_TRANS, n2.uuid(), 3)); tr.members().insert_unique(std::make_pair(n3.uuid(), 0)); n3.p().handle_view(tr); fail_unless(n3.tp().out() == 0 && n3.p().state() == gcomm::pc::Proto::S_TRANS); gcomm::View reg(0, gcomm::ViewId(V_REG, n3.uuid(), 4)); reg.members().insert_unique(std::make_pair(n3.uuid(), 0)); n3.p().handle_view(reg); fail_unless(n3.p().state() == gcomm::pc::Proto::S_STATES_EXCH); Datagram* dg(n3.tp().out()); fail_unless(dg != 0); n3.p().handle_up(0, *dg, ProtoUpMeta(n3.uuid())); dg = n3.tp().out(); fail_unless(dg == 0 && n3.p().state() == gcomm::pc::Proto::S_NON_PRIM, "%p %d", dg, n3.p().state()); } } END_TEST START_TEST(test_fifo_violation) { log_info << "START (test_fifo_violation)"; gu::Config conf; gcomm::Conf::register_params(conf); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); assert(pc1.state() == Proto::S_PRIM); pu1.send(); pu1.send(); Datagram* dg1(tp1.out()); fail_unless(dg1 != 0); Datagram* dg2(tp1.out()); fail_unless(dg2 != 0); try { pc1.handle_up(0, *dg2, ProtoUpMeta(uuid1, ViewId(), 0, 0xff, O_SAFE)); fail(""); } catch (Exception& e) { fail_unless(e.get_errno() == ENOTRECOVERABLE); } delete dg1; delete dg2; } END_TEST START_TEST(test_checksum) { log_info << "START (test_checksum)"; gu::Config conf; gcomm::Conf::register_params(conf); conf.set(Conf::PcChecksum, gu::to_string(true)); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf, uuid1, 0); DummyTransport tp1; PCUser pu1(conf, uuid1, &tp1, &pc1); single_boot(0, &pu1); assert(pc1.state() == Proto::S_PRIM); pu1.send(); Datagram* dg(tp1.out()); fail_unless(dg != 0); dg->normalize(); pc1.handle_up(0, *dg, ProtoUpMeta(uuid1)); delete dg; pu1.send(); dg = tp1.out(); fail_unless(dg != 0); dg->normalize(); *(&dg->payload()[0] + dg->payload().size() - 1) ^= 0x10; try { pc1.handle_up(0, *dg, ProtoUpMeta(uuid1)); fail(""); } catch (Exception& e) { fail_unless(e.get_errno() == ENOTRECOVERABLE); } delete dg; } END_TEST START_TEST(test_set_param) { log_info << "START (test_pc_transport)"; gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr net(Protonet::create(conf)); PCUser2 pu1(*net, "pc://?" "evs.info_log_mask=0xff&" "gmcast.listen_addr=tcp://127.0.0.1:0&" "gmcast.group=pc&" "gmcast.time_wait=PT0.5S&" "pc.recovery=0&" "node.name=n1"); pu1.start(); // no such a parameter fail_unless(net->set_param("foo.bar", "1") == false); const evs::seqno_t send_window( gu::from_string(conf.get("evs.send_window"))); const evs::seqno_t user_send_window( gu::from_string(conf.get("evs.user_send_window"))); try { net->set_param("evs.send_window", gu::to_string(user_send_window - 1)); fail("exception not thrown"); } catch (gu::Exception& e) { fail_unless(e.get_errno() == ERANGE, "%d: %s", e.get_errno(), e.what()); } try { net->set_param("evs.user_send_window", gu::to_string(send_window + 1)); fail("exception not thrown"); } catch (gu::Exception& e) { fail_unless(e.get_errno() == ERANGE, "%d: %s", e.get_errno(), e.what()); } // Note: These checks may have to change if defaults are changed fail_unless(net->set_param( "evs.send_window", gu::to_string(send_window - 1)) == true); fail_unless(gu::from_string(conf.get("evs.send_window")) == send_window - 1); fail_unless(net->set_param( "evs.user_send_window", gu::to_string(user_send_window + 1)) == true); fail_unless(gu::from_string( conf.get("evs.user_send_window")) == user_send_window + 1); pu1.stop(); } END_TEST START_TEST(test_trac_599) { class D : public gcomm::Toplay { public: D(gu::Config& conf) : gcomm::Toplay(conf) { } void handle_up(const void* id, const Datagram& dg, const gcomm::ProtoUpMeta& um) { } }; gu::Config conf; gcomm::Conf::register_params(conf); D d(conf); std::auto_ptr pnet(gcomm::Protonet::create(conf)); std::auto_ptr tp( gcomm::Transport::create (*pnet,"pc://?gmcast.group=test&gmcast.listen_addr=tcp://127.0.0.1:0" "&pc.recovery=0")); gcomm::connect(tp.get(), &d); gu::Buffer buf(10); Datagram dg(buf); int err; err = tp->send_down(dg, gcomm::ProtoDownMeta()); fail_unless(err == ENOTCONN, "%d", err); tp->connect(true); buf.resize(tp->mtu()); Datagram dg2(buf); err = tp->send_down(dg2, gcomm::ProtoDownMeta()); fail_unless(err == 0, "%d", err); buf.resize(buf.size() + 1); Datagram dg3(buf); err = tp->send_down(dg3, gcomm::ProtoDownMeta()); fail_unless(err == EMSGSIZE, "%d", err); pnet->event_loop(gu::datetime::Sec); tp->close(); } END_TEST // test for forced teardown START_TEST(test_trac_620) { gu::Config conf; gcomm::Conf::register_params(conf); auto_ptr net(Protonet::create(conf)); Transport* tp(Transport::create(*net, "pc://?" "evs.info_log_mask=0xff&" "gmcast.listen_addr=tcp://127.0.0.1:0&" "gmcast.group=pc&" "gmcast.time_wait=PT0.5S&" "pc.recovery=0&" "node.name=n1")); class D : public gcomm::Toplay { public: D(gu::Config& conf) : gcomm::Toplay(conf) { } void handle_up(const void* id, const Datagram& dg, const gcomm::ProtoUpMeta& um) { } }; D d(conf); gcomm::connect(tp, &d); tp->connect(true); tp->close(true); gcomm::disconnect(tp, &d); delete tp; } END_TEST START_TEST(test_trac_277) { log_info << "START (test_trac_277)"; size_t n_nodes(3); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } log_info << "generate messages"; send_n(dn[0], 1); send_n(dn[1], 1); send_n(dn[2], 1); gu_trace(prop.propagate_until_empty()); log_info << "isolate 3"; prop.split(1, 3); prop.split(2, 3); ++view_seq; set_cvi(dn, 0, 1, view_seq, V_PRIM); set_cvi(dn, 2, 2, view_seq, V_NON_PRIM); gu_trace(prop.propagate_until_cvi(true)); log_info << "isolate 1 and 2"; ++view_seq; prop.split(1, 2); set_cvi(dn, 0, 1, view_seq, V_NON_PRIM); gu_trace(prop.propagate_until_cvi(true)); log_info << "merge 1 and 2"; ++view_seq; prop.merge(1, 2); set_cvi(dn, 0, 1, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); log_info << "merge 3"; ++view_seq; prop.merge(1, 3); prop.merge(2, 3); set_cvi(dn, 0, 2, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST // This test checks the case when another node of two node cluster // crashes or becomes completely isolated and prim view of cluster // is established by starting third instance directly in prim mode. START_TEST(test_trac_622_638) { log_info << "START (test_trac_622_638)"; vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; // Create two node cluster and make it split. First node is // considered crashed after split (stay isolated in non-prim). dn.push_back(create_dummy_node(1, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[0], true)); set_cvi(dn, 0, 0, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); dn.push_back(create_dummy_node(2, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[1], false)); set_cvi(dn, 0, 1, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); log_info << "generate messages"; send_n(dn[0], 1); send_n(dn[1], 1); gu_trace(prop.propagate_until_empty()); log_info << "isolate 1 and 2"; prop.split(1, 2); ++view_seq; set_cvi(dn, 0, 0, view_seq, V_NON_PRIM); set_cvi(dn, 1, 1, view_seq, V_NON_PRIM); gu_trace(prop.propagate_until_cvi(true)); // Add third node which will be connected with node 2. This will // be started with prim status. dn.push_back(create_dummy_node(3, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[2], true)); prop.split(1, 3); // avoid 1 <-> 3 communication ++view_seq; set_cvi(dn, 1, 2, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); check_trace(dn); for_each(dn.begin(), dn.end(), DeleteObject()); } END_TEST START_TEST(test_weighted_quorum) { log_info << "START (test_weighted_quorum)"; size_t n_nodes(3); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period, i)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } // split node 3 (weight 2) out, node 3 should remain in prim while // nodes 1 and 2 (weights 0 + 1 = 1) should end up in non-prim prop.split(1, 3); prop.split(2, 3); ++view_seq; set_cvi(dn, 0, 1, view_seq, V_NON_PRIM); set_cvi(dn, 2, 2, view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(true)); } END_TEST // // The scenario is the following (before fix): // // - Two nodes 2 and 3 started with weights 1 // - Third node 1 with weight 3 is brought in the cluster // (becomes representative) // - Partitioning to (1) and (2, 3) happens so that INSTALL message is // delivered on 2 and 3 in TRANS and on 1 in REG // - Node 1 forms PC // - Nodes 2 and 3 renegotiate and form PC too because node 1 was not present // in the previous PC // // What should happen is that nodes 2 and 3 recompute quorum on handling // install message and shift to non-PC // START_TEST(test_weighted_partitioning_1) { log_info << "START (test_weighted_partitioning_1)"; gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); single_boot(0, &pu3); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "1"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu3, &pu2); gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "3"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); // trans views { View tr1(0, ViewId(V_TRANS, uuid1, 0)); tr1.add_member(uuid1, 0); pu1.pc()->connect(false); ProtoUpMeta um1(UUID::nil(), ViewId(), &tr1); pu1.pc()->handle_up(0, Datagram(), um1); View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(uuid2, 0); tr23.add_member(uuid3, 0); ProtoUpMeta um23(UUID::nil(), ViewId(), &tr23); pu2.pc()->handle_up(0, Datagram(), um23); pu3.pc()->handle_up(0, Datagram(), um23); } // reg view { View reg(0, ViewId(V_REG, uuid1, pu2.pc()->current_view().id().seq() + 1)); reg.add_member(uuid1, 0); reg.add_member(uuid2, 0); reg.add_member(uuid3, 0); ProtoUpMeta um(UUID::nil(), ViewId(), ®); pu1.pc()->handle_up(0, Datagram(), um); pu2.pc()->handle_up(0, Datagram(), um); pu3.pc()->handle_up(0, Datagram(), um); } // states exch { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); delete dg; dg = pu2.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); delete dg; fail_unless(pu2.tp()->out() == 0); fail_unless(pu3.tp()->out() == 0); } // install msg { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); fail_unless(pu1.pc()->state() == Proto::S_PRIM); // trans view for 2 and 3 View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(uuid2, 0); tr23.add_member(uuid3, 0); tr23.add_partitioned(uuid1, 0); ProtoUpMeta trum23(UUID::nil(), ViewId(), &tr23); pu2.pc()->handle_up(0, Datagram(), trum23); pu3.pc()->handle_up(0, Datagram(), trum23); // 2 and 3 handle install pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); delete dg; // reg view for 2 and 3 View reg23(0, ViewId(V_REG, uuid2, pu2.pc()->current_view().id().seq() + 1)); reg23.add_member(uuid2, 0); reg23.add_member(uuid3, 0); ProtoUpMeta rum23(UUID::nil(), ViewId(), ®23); pu2.pc()->handle_up(0, Datagram(), rum23); pu3.pc()->handle_up(0, Datagram(), rum23); // states exch dg = pu2.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); delete dg; // 2 and 3 should end up in non prim fail_unless(pu2.pc()->state() == Proto::S_NON_PRIM, "state: %s", Proto::to_string(pu2.pc()->state()).c_str()); fail_unless(pu3.pc()->state() == Proto::S_NON_PRIM, "state: %s", Proto::to_string(pu3.pc()->state()).c_str()); } } END_TEST // // - Two nodes 2 and 3 started with weights 1 // - Third node 1 with weight 3 is brought in the cluster // (becomes representative) // - Partitioning to (1) and (2, 3) happens so that INSTALL message is // delivered in trans view on all nodes // - All nodes should end up in non-prim, nodes 2 and 3 because they don't know // if node 1 ended up in prim (see test_weighted_partitioning_1 above), // node 1 because it hasn't been in primary before and fails to deliver // install message in reg view // START_TEST(test_weighted_partitioning_2) { log_info << "START (test_weighted_partitioning_2)"; gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); single_boot(0, &pu3); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "1"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu3, &pu2); gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "3"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); // trans views { View tr1(0, ViewId(V_TRANS, uuid1, 0)); tr1.add_member(uuid1, 0); pu1.pc()->connect(false); ProtoUpMeta um1(UUID::nil(), ViewId(), &tr1); pu1.pc()->handle_up(0, Datagram(), um1); View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(uuid2, 0); tr23.add_member(uuid3, 0); ProtoUpMeta um23(UUID::nil(), ViewId(), &tr23); pu2.pc()->handle_up(0, Datagram(), um23); pu3.pc()->handle_up(0, Datagram(), um23); } // reg view { View reg(0, ViewId(V_REG, uuid1, pu2.pc()->current_view().id().seq() + 1)); reg.add_member(uuid1, 0); reg.add_member(uuid2, 0); reg.add_member(uuid3, 0); ProtoUpMeta um(UUID::nil(), ViewId(), ®); pu1.pc()->handle_up(0, Datagram(), um); pu2.pc()->handle_up(0, Datagram(), um); pu3.pc()->handle_up(0, Datagram(), um); } // states exch { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); delete dg; dg = pu2.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); delete dg; fail_unless(pu2.tp()->out() == 0); fail_unless(pu3.tp()->out() == 0); } // install msg { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); // trans view for 1 View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(uuid1, 0); tr1.add_partitioned(uuid2, 0); tr1.add_partitioned(uuid3, 0); ProtoUpMeta trum1(UUID::nil(), ViewId(), &tr1); pu1.pc()->handle_up(0, Datagram(), trum1); fail_unless(pu1.pc()->state() == Proto::S_TRANS); // 1 handle install pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); fail_unless(pu1.pc()->state() == Proto::S_TRANS); // trans view for 2 and 3 View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(uuid2, 0); tr23.add_member(uuid3, 0); tr23.add_partitioned(uuid1, 0); ProtoUpMeta trum23(UUID::nil(), ViewId(), &tr23); pu2.pc()->handle_up(0, Datagram(), trum23); pu3.pc()->handle_up(0, Datagram(), trum23); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu3.pc()->state() == Proto::S_TRANS); // 2 and 3 handle install pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu3.pc()->state() == Proto::S_TRANS); delete dg; // reg view for 1 View reg1(0, ViewId(V_REG, uuid1, pu1.pc()->current_view().id().seq() + 1)); reg1.add_member(uuid1, 0); ProtoUpMeta rum1(UUID::nil(), ViewId(), ®1); pu1.pc()->handle_up(0, Datagram(), rum1); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); // reg view for 2 and 3 View reg23(0, ViewId(V_REG, uuid2, pu2.pc()->current_view().id().seq() + 1)); reg23.add_member(uuid2, 0); reg23.add_member(uuid3, 0); ProtoUpMeta rum23(UUID::nil(), ViewId(), ®23); pu2.pc()->handle_up(0, Datagram(), rum23); pu3.pc()->handle_up(0, Datagram(), rum23); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3.pc()->state() == Proto::S_STATES_EXCH); // states exch dg = pu1.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(uuid1)); fail_unless(pu1.pc()->state() == Proto::S_NON_PRIM, "state: %s", Proto::to_string(pu1.pc()->state()).c_str()); delete dg; dg = pu2.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid2)); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(uuid3)); delete dg; fail_unless(pu2.pc()->state() == Proto::S_NON_PRIM, "state: %s", Proto::to_string(pu2.pc()->state()).c_str()); fail_unless(pu3.pc()->state() == Proto::S_NON_PRIM, "state: %s", Proto::to_string(pu3.pc()->state()).c_str()); } } END_TEST // // - Nodes 1-3 started with equal weights // - Weight for node 1 is changed to 3 // - Group splits to (1), (2, 3) // - Weigh changing message is delivered in reg view in (1) and in // trans in (2, 3) // - Expected outcome: 1 stays in prim, 2 and 3 end up in non-prim // START_TEST(test_weight_change_partitioning_1) { log_info << "START (test_weight_change_partitioning_1)"; gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "1"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "1"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); triple_boot(0, &pu1, &pu2, &pu3); // weight change { pu1.pc()->set_param("pc.weight", "3"); Datagram* install_dg(pu1.tp()->out()); fail_unless(install_dg != 0); // node 1 handle weight change install, proceed to singleton prim pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_partitioned(pu2.uuid(), 0); tr1.add_partitioned(pu3.uuid(), 0); pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pu1.pc()->state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, pu1.uuid(), pu1.pc()->current_view().id().seq() + 1)); reg1.add_member(pu1.uuid(), 0); pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); delete dg; fail_unless(pu1.pc()->state() == Proto::S_INSTALL); dg = pu1.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); delete dg; fail_unless(pu1.pc()->state() == Proto::S_PRIM); // nodes 2 and 3 go to trans, handle install View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(pu2.uuid(), 0); tr23.add_member(pu3.uuid(), 0); tr23.add_partitioned(pu1.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu3.pc()->state() == Proto::S_TRANS); pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); View reg23(0, ViewId(V_REG, pu2.uuid(), pu2.pc()->current_view().id().seq() + 1)); reg23.add_member(pu2.uuid(), 0); reg23.add_member(pu3.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3.pc()->state() == Proto::S_STATES_EXCH); dg = pu2.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); delete dg; fail_unless(pu2.pc()->state() == Proto::S_NON_PRIM); fail_unless(pu3.pc()->state() == Proto::S_NON_PRIM); delete install_dg; } } END_TEST // // - Nodes 2 and 3 start with weight 1, node 1 with weight 3 // - Weight for node 1 is changed to 1 // - Group splits to (1), (2, 3) // - Weigh changing message is delivered in reg view in (1) and in // trans in (2, 3) // - Expected outcome: all nodes go non-prim // START_TEST(test_weight_change_partitioning_2) { log_info << "START (test_weight_change_partitioning_2)"; gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "3"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "1"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); triple_boot(0, &pu1, &pu2, &pu3); // weight change { pu1.pc()->set_param("pc.weight", "1"); Datagram* install_dg(pu1.tp()->out()); fail_unless(install_dg != 0); // node 1 handle weight change install, proceed to singleton prim pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); View tr1(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_partitioned(pu2.uuid(), 0); tr1.add_partitioned(pu3.uuid(), 0); pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pu1.pc()->state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, pu1.uuid(), pu1.pc()->current_view().id().seq() + 1)); reg1.add_member(pu1.uuid(), 0); pu1.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); delete dg; fail_unless(pu1.pc()->state() == Proto::S_NON_PRIM); // nodes 2 and 3 go to trans, handle install View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(pu2.uuid(), 0); tr23.add_member(pu3.uuid(), 0); tr23.add_partitioned(pu1.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu3.pc()->state() == Proto::S_TRANS); pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); View reg23(0, ViewId(V_REG, pu2.uuid(), pu2.pc()->current_view().id().seq() + 1)); reg23.add_member(pu2.uuid(), 0); reg23.add_member(pu3.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3.pc()->state() == Proto::S_STATES_EXCH); dg = pu2.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); delete dg; fail_unless(pu2.pc()->state() == Proto::S_NON_PRIM); fail_unless(pu3.pc()->state() == Proto::S_NON_PRIM); delete install_dg; } } END_TEST // // Weight changing message is delivered in transitional view when new node is // joining. All nodes should end up in prim. // START_TEST(test_weight_change_joining) { log_info << "START (test_weight_change_joining)"; gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "1"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "1"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); // weight change { pu1.pc()->set_param("pc.weight", "1"); Datagram* install_dg(pu1.tp()->out()); fail_unless(install_dg != 0); // trans views { View tr12(0, ViewId(V_TRANS, pu1.pc()->current_view().id())); tr12.add_member(pu1.uuid(), 0); tr12.add_member(pu2.uuid(), 0); ProtoUpMeta trum12(UUID::nil(), ViewId(), &tr12); pu1.pc()->handle_up(0, Datagram(), trum12); pu2.pc()->handle_up(0, Datagram(), trum12); fail_unless(pu1.pc()->state() == Proto::S_TRANS); fail_unless(pu2.pc()->state() == Proto::S_TRANS); // deliver weight change install in trans view pu1.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->connect(false); View tr3(0, ViewId(V_TRANS, pu3.uuid(), 0)); tr3.add_member(pu3.uuid(), 0); ProtoUpMeta trum3(UUID::nil(), ViewId(), &tr3); pu3.pc()->handle_up(0, Datagram(), trum3); fail_unless(pu3.pc()->state() == Proto::S_TRANS); } // reg view { View reg(0, ViewId(V_REG, pu1.uuid(), pu1.pc()->current_view().id().seq() + 1)); reg.add_member(pu1.uuid(), 0); reg.add_member(pu2.uuid(), 0); reg.add_member(pu3.uuid(), 0); ProtoUpMeta pum(UUID::nil(), ViewId(), ®); pu1.pc()->handle_up(0, Datagram(), pum); pu2.pc()->handle_up(0, Datagram(), pum); pu3.pc()->handle_up(0, Datagram(), pum); fail_unless(pu1.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3.pc()->state() == Proto::S_STATES_EXCH); } // states exch { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); delete dg; dg = pu2.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); delete dg; fail_unless(pu1.pc()->state() == Proto::S_INSTALL); fail_unless(pu2.pc()->state() == Proto::S_INSTALL); fail_unless(pu3.pc()->state() == Proto::S_INSTALL); } // install { Datagram* dg(pu1.tp()->out()); fail_unless(dg != 0); pu1.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); delete dg; fail_unless(pu1.pc()->state() == Proto::S_PRIM); fail_unless(pu2.pc()->state() == Proto::S_PRIM); fail_unless(pu3.pc()->state() == Proto::S_PRIM); } delete install_dg; } } END_TEST // // One of the nodes leaves gracefully from group and weight change message // is delivered in trans view. Remaining nodes must not enter non-prim. // START_TEST(test_weight_change_leaving) { log_info << "START (test_weight_change_leaving)"; gu::Config conf1; gcomm::Conf::register_params(conf1); conf1.set("pc.weight", "3"); UUID uuid1(1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); conf2.set("pc.weight", "2"); UUID uuid2(2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); conf3.set("pc.weight", "1"); UUID uuid3(3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); triple_boot(0, &pu1, &pu2, &pu3); // weight change { // change weight for node 2 while node 1 leaves the group gracefully pu2.pc()->set_param("pc.weight", "1"); Datagram* install_dg(pu2.tp()->out()); fail_unless(install_dg != 0); // nodes 2 and 3 go to trans, handle install View tr23(0, ViewId(V_TRANS, pu2.pc()->current_view().id())); tr23.add_member(pu2.uuid(), 0); tr23.add_member(pu3.uuid(), 0); tr23.add_left(pu1.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr23)); fail_unless(pu2.pc()->state() == Proto::S_TRANS); fail_unless(pu3.pc()->state() == Proto::S_TRANS); pu2.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); pu3.pc()->handle_up(0, *install_dg, ProtoUpMeta(pu1.uuid())); View reg23(0, ViewId(V_REG, pu2.uuid(), pu2.pc()->current_view().id().seq() + 1)); reg23.add_member(pu2.uuid(), 0); reg23.add_member(pu3.uuid(), 0); pu2.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); pu3.pc()->handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®23)); fail_unless(pu2.pc()->state() == Proto::S_STATES_EXCH); fail_unless(pu3.pc()->state() == Proto::S_STATES_EXCH); Datagram* dg(pu2.tp()->out()); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); delete dg; dg = pu3.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); delete dg; fail_unless(pu2.pc()->state() == Proto::S_INSTALL); fail_unless(pu3.pc()->state() == Proto::S_INSTALL); dg = pu2.tp()->out(); fail_unless(dg != 0); pu2.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); pu3.pc()->handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); delete dg; fail_unless(pu2.pc()->state() == Proto::S_PRIM); fail_unless(pu3.pc()->state() == Proto::S_PRIM); delete install_dg; } } END_TEST // node1 and node2 are a cluster. // before node3 joins, node2 lost connection to node1 and node3. // after node1 and node3 merged, node2 joins. // we expect all nodes are a cluster, and they are all in prim state. static void _test_join_split_cluster( const UUID& uuid1, const UUID& uuid2, const UUID& uuid3) { // construct restored view. const UUID& prim_uuid = uuid1 < uuid2 ? uuid1 : uuid2; View rst_view(0, ViewId(V_PRIM, prim_uuid, 0)); rst_view.add_member(uuid1, 0); rst_view.add_member(uuid2, 0); gu::Config conf1; gcomm::Conf::register_params(conf1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); pc1.set_restored_view(&rst_view); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); pc2.set_restored_view(&rst_view); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); // assume previous cluster is node1 and node3. const UUID& prim_uuid2 = uuid1 < uuid3 ? uuid1 : uuid3; View rst_view2(0, ViewId(V_PRIM, prim_uuid2, 0)); rst_view2.add_member(uuid1, 0); rst_view2.add_member(uuid3, 0); pc3.set_restored_view(&rst_view2); { uint32_t seq = pc1.current_view().id().seq(); const UUID& reg_uuid = pu1.uuid() < pu3.uuid() ? pu1.uuid() : pu3.uuid(); // node1 View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_partitioned(pu2.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, reg_uuid, seq + 1)); reg1.add_member(pu1.uuid(), 0); reg1.add_member(pu3.uuid(), 0); reg1.add_joined(pu3.uuid(), 0); reg1.add_partitioned(pu2.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); // node3 View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu3.uuid(), 0); pc3.connect(false); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, reg_uuid, seq + 1)); reg3.add_member(pu1.uuid(), 0); reg3.add_member(pu3.uuid(), 0); reg3.add_joined(pu1.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®3)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); Datagram* dg1(pu1.tp()->out()); fail_unless(dg1 != 0); Datagram* dg3(pu3.tp()->out()); fail_unless(dg3 != 0); pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc1.state() == Proto::S_NON_PRIM); pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc3.state() == Proto::S_NON_PRIM); delete dg1; delete dg3; } { // node2 uint32_t seq = pc2.current_view().id().seq(); View tr2(0, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pu2.uuid(), 0); tr2.add_partitioned(pu1.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); fail_unless(pc2.state() == Proto::S_TRANS); View reg2(0, ViewId(V_REG, pc2.uuid(), seq + 1)); reg2.add_member(pu2.uuid(), 0); reg2.add_partitioned(pu1.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®2)); fail_unless(pc2.state() == Proto::S_STATES_EXCH); Datagram* dg2(pu2.tp()->out()); fail_unless(dg2 != 0); pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); fail_unless(pc2.state() == Proto::S_NON_PRIM); } { View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_member(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); View tr2(0, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pu2.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); fail_unless(pc2.state() == Proto::S_TRANS); View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu1.uuid(), 0); tr3.add_member(pu3.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); int seq = pc1.current_view().id().seq(); const UUID& reg_uuid1 = pu1.uuid() < pu2.uuid() ? pu1.uuid() : pu2.uuid(); const UUID& reg_uuid = reg_uuid1 < pu3.uuid() ? reg_uuid1 : pu3.uuid(); View reg1(0, ViewId(V_REG, reg_uuid, seq + 1)); reg1.add_member(pu1.uuid(), 0); reg1.add_member(pu2.uuid(), 0); reg1.add_member(pu3.uuid(), 0); reg1.add_joined(pu2.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); View reg2(0, ViewId(V_REG, reg_uuid, seq + 1)); reg2.add_member(pu1.uuid(), 0); reg2.add_member(pu2.uuid(), 0); reg2.add_member(pu3.uuid(), 0); reg2.add_joined(pu1.uuid(), 0); reg2.add_joined(pu3.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®2)); fail_unless(pc2.state() == Proto::S_STATES_EXCH); Datagram* dg1(pu1.tp()->out()); Datagram* dg2(pu2.tp()->out()); Datagram* dg3(pu3.tp()->out()); pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc1.state() == Proto::S_INSTALL); pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc2.state() == Proto::S_INSTALL); pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc3.state() == Proto::S_INSTALL); delete dg1; delete dg2; delete dg3; Datagram* dg = 0; PCUser* pcs[3] = {&pu1, &pu2, &pu3}; for (int i=0; i<3; i++) { if (pcs[i]->uuid() == reg_uuid) { dg = pcs[i]->tp()->out(); fail_unless(dg != 0); } else { fail_if(pcs[i]->tp()->out()); } } pc1.handle_up(0, *dg, ProtoUpMeta(reg_uuid)); pc2.handle_up(0, *dg, ProtoUpMeta(reg_uuid)); pc3.handle_up(0, *dg, ProtoUpMeta(reg_uuid)); fail_unless(pc1.state() == Proto::S_PRIM); fail_unless(pc2.state() == Proto::S_PRIM); fail_unless(pc3.state() == Proto::S_PRIM); } } START_TEST(test_join_split_cluster) { log_info << "START (test_join_split_cluster)"; gu_conf_debug_on(); UUID uuid1(1); UUID uuid2(2); UUID uuid3(3); _test_join_split_cluster(uuid1, uuid2, uuid3); _test_join_split_cluster(uuid2, uuid1, uuid3); _test_join_split_cluster(uuid2, uuid3, uuid1); } END_TEST START_TEST(test_trac_762) { log_info << "START (trac_762)"; size_t n_nodes(3); vector dn; PropagationMatrix prop; const string suspect_timeout("PT0.35S"); const string inactive_timeout("PT0.7S"); const string retrans_period("PT0.1S"); uint32_t view_seq = 0; for (size_t i = 0; i < n_nodes; ++i) { dn.push_back(create_dummy_node(i + 1, 0, suspect_timeout, inactive_timeout, retrans_period)); gu_trace(join_node(&prop, dn[i], i == 0)); set_cvi(dn, 0, i, ++view_seq, V_PRIM); gu_trace(prop.propagate_until_cvi(false)); } log_info << "split 1"; // split group so that node 3 becomes isolated prop.split(1, 3); prop.split(2, 3); ++view_seq; set_cvi(dn, 0, 1, view_seq, V_PRIM); set_cvi(dn, 2, 2, view_seq, V_NON_PRIM); gu_trace(prop.propagate_until_cvi(true)); mark_point(); log_info << "remerge 1"; // detach PC layer from EVS and lower layers, attach to DummyTransport for (size_t i(0); i < n_nodes; ++i) { std::list::iterator li0(dn[i]->protos().begin()); std::list::iterator li1(li0); ++li1; assert(li1 != dn[i]->protos().end()); std::list::iterator li2(li1); ++li2; assert(li2 != dn[i]->protos().end()); gcomm::disconnect(*li0, *li1); gcomm::disconnect(*li1, *li2); delete *li0; delete *li1; dn[i]->protos().pop_front(); dn[i]->protos().pop_front(); DummyTransport* tp(new DummyTransport(dn[i]->uuid(), true)); dn[i]->protos().push_front(tp); gcomm::connect(tp, *li2); } Proto* pc1(pc_from_dummy(dn[0])); DummyTransport* tp1(reinterpret_cast( dn[0]->protos().front())); Proto* pc2(pc_from_dummy(dn[1])); DummyTransport* tp2(reinterpret_cast( dn[1]->protos().front())); Proto* pc3(pc_from_dummy(dn[2])); DummyTransport* tp3(reinterpret_cast( dn[2]->protos().front())); // remerge group, process event by event so that nodes 1 and 2 handle // install message in reg view and reach prim view, node 3 partitions and // handles install in trans view and marks nodes 1 and 2 to have un state { View tr1(0, ViewId(V_TRANS, tp1->uuid(), view_seq)); tr1.add_member(tp1->uuid(), 0); tr1.add_member(tp2->uuid(), 0); pc1->handle_view(tr1); pc2->handle_view(tr1); View tr2(0, ViewId(V_TRANS, tp3->uuid(), view_seq)); tr2.add_member(tp3->uuid(), 0); pc3->handle_view(tr2); ++view_seq; View reg(0, ViewId(V_REG, tp1->uuid(), view_seq)); reg.add_member(tp1->uuid(), 0); reg.add_member(tp2->uuid(), 0); reg.add_member(tp3->uuid(), 0); pc1->handle_view(reg); pc2->handle_view(reg); pc3->handle_view(reg); // states exch Datagram* dg(tp1->out()); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); delete dg; dg = tp2->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); delete dg; dg = tp3->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); delete dg; // install message dg = tp1->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); View tr3(0, ViewId(V_TRANS, tp1->uuid(), view_seq)); tr3.add_member(tp1->uuid(), 0); tr3.add_member(tp2->uuid(), 0); tr3.add_partitioned(tp3->uuid(), 0); pc1->handle_view(tr3); pc2->handle_view(tr3); View tr4(0, ViewId(V_TRANS, tp1->uuid(), view_seq)); tr4.add_member(tp3->uuid(), 0); tr4.add_partitioned(tp1->uuid(), 0); tr4.add_partitioned(tp2->uuid(), 0); pc3->handle_view(tr4); pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); delete dg; } ++view_seq; // ... intermediate reg/trans views // 1 and 2 { View reg(0, ViewId(V_REG, tp1->uuid(), view_seq)); reg.add_member(tp1->uuid(), 0); reg.add_member(tp2->uuid(), 0); pc1->handle_view(reg); pc2->handle_view(reg); View tr(0, ViewId(V_TRANS, tp1->uuid(), view_seq)); tr.add_member(tp1->uuid(), 0); tr.add_member(tp2->uuid(), 0); pc1->handle_view(tr); pc2->handle_view(tr); Datagram* dg(tp1->out()); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); delete dg; dg = tp2->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); delete dg; } // 3 { View reg(0, ViewId(V_REG, tp3->uuid(), view_seq)); reg.add_member(tp3->uuid(), 0); pc3->handle_view(reg); Datagram* dg(tp3->out()); fail_unless(dg != 0); pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); delete dg; View tr(0, ViewId(V_TRANS, tp3->uuid(), view_seq)); tr.add_member(tp3->uuid(), 0); pc3->handle_view(tr); } // Remerge and PC crash should occur if bug is present. ++view_seq; { View reg(0, ViewId(V_REG, tp1->uuid(), view_seq)); reg.add_member(tp1->uuid(), 0); reg.add_member(tp2->uuid(), 0); reg.add_member(tp3->uuid(), 0); pc1->handle_view(reg); pc2->handle_view(reg); pc3->handle_view(reg); // State msgs Datagram* dg(tp1->out()); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); delete dg; dg = tp2->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp2->uuid())); delete dg; dg = tp3->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp3->uuid())); delete dg; // Install msg dg = tp1->out(); fail_unless(dg != 0); pc1->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc2->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); pc3->handle_up(0, *dg, ProtoUpMeta(tp1->uuid())); fail_unless(tp1->out() == 0); fail_unless(tp2->out() == 0); fail_unless(tp3->out() == 0); } } END_TEST START_TEST(test_gh_92) { UUID uuid1(1), uuid2(2), uuid3(3); gu::Config conf1; gcomm::Conf::register_params(conf1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(0, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(0, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); triple_boot(0, &pu1, &pu2, &pu3); uint32_t seq = pc1.current_view().id().seq(); Datagram* im = 0; Datagram* dg = 0; // they split into three parts. { View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_partitioned(pu2.uuid(), 0); tr1.add_partitioned(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, uuid1, seq + 1)); reg1.add_member(pu1.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); dg = pu1.tp()->out(); pc1.handle_up(0, *dg, ProtoUpMeta(pu1.uuid())); fail_unless(pc1.state() == Proto::S_NON_PRIM); View tr2(0, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pu2.uuid(), 0); tr2.add_partitioned(pu1.uuid(), 0); tr2.add_partitioned(pu3.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); fail_unless(pc2.state() == Proto::S_TRANS); View reg2(0, ViewId(V_REG, uuid2, seq + 1)); reg2.add_member(pu2.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®2)); fail_unless(pc2.state() == Proto::S_STATES_EXCH); dg = pu2.tp()->out(); pc2.handle_up(0, *dg, ProtoUpMeta(pu2.uuid())); fail_unless(pc2.state() == Proto::S_NON_PRIM); View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu3.uuid(), 0); tr3.add_partitioned(pu1.uuid(), 0); tr3.add_partitioned(pu2.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid3, seq + 1)); reg3.add_member(pu3.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®3)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); dg = pu3.tp()->out(); pc3.handle_up(0, *dg, ProtoUpMeta(pu3.uuid())); fail_unless(pc3.state() == Proto::S_NON_PRIM); } seq += 1; // they try to merge into a primary component, but fails when sending install message. { View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, uuid1, seq + 1)); reg1.add_member(pu1.uuid(), 0); reg1.add_member(pu2.uuid(), 0); reg1.add_member(pu3.uuid(), 0); reg1.add_joined(pu2.uuid(), 0); reg1.add_joined(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); View tr2(0, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pu2.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); fail_unless(pc2.state() == Proto::S_TRANS); View reg2(0, ViewId(V_REG, uuid1, seq + 1)); reg2.add_member(pu1.uuid(), 0); reg2.add_member(pu2.uuid(), 0); reg2.add_member(pu3.uuid(), 0); reg2.add_joined(pu1.uuid(), 0); reg2.add_joined(pu3.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®2)); fail_unless(pc2.state() == Proto::S_STATES_EXCH); View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu3.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid1, seq + 1)); reg3.add_member(pu1.uuid(), 0); reg3.add_member(pu2.uuid(), 0); reg3.add_member(pu3.uuid(), 0); reg3.add_joined(pu1.uuid(), 0); reg3.add_joined(pu2.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®3)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); Datagram* dg1(pu1.tp()->out()); Datagram* dg2(pu2.tp()->out()); Datagram* dg3(pu3.tp()->out()); fail_unless(dg1 != 0); fail_unless(dg2 != 0); fail_unless(dg3 != 0); pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); delete dg1; delete dg2; delete dg3; fail_unless(pc1.state() == Proto::S_INSTALL); fail_unless(pc2.state() == Proto::S_INSTALL); fail_unless(pc3.state() == Proto::S_INSTALL); im = pu1.tp()->out(); fail_unless(im != 0); fail_unless(pu2.tp()->out() == 0); fail_unless(pu3.tp()->out() == 0); } seq += 1; // node3 is separate from node1 and node2. // they get the stale install message when they get transient view. { View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_member(pu2.uuid(), 0); tr1.add_partitioned(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); fail_unless(pc2.state() == Proto::S_TRANS); pc1.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); fail_unless(pc1.state() == Proto::S_TRANS); fail_unless(pc2.state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, uuid1, seq + 1)); reg1.add_member(pu1.uuid(), 0); reg1.add_member(pu2.uuid(), 0); reg1.add_partitioned(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); fail_unless(pc2.state() == Proto::S_STATES_EXCH); Datagram* dg1(pu1.tp()->out()); Datagram* dg2(pu2.tp()->out()); fail_unless(dg1 != 0); fail_unless(dg2 != 0); pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); fail_unless(pc1.state() == Proto::S_NON_PRIM); fail_unless(pc2.state() == Proto::S_NON_PRIM); View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu3.uuid(), 0); tr3.add_partitioned(pu1.uuid(), 0); tr3.add_partitioned(pu2.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); pc3.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); fail_unless(pc3.state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid3, seq + 1)); reg3.add_member(pu3.uuid(), 0); reg3.add_partitioned(pu1.uuid(), 0); reg3.add_partitioned(pu2.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®3)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); Datagram* dg3(pu3.tp()->out()); fail_unless(dg3 != 0); pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); fail_unless(pc3.state() == Proto::S_NON_PRIM); } seq += 1; // then they try to merge into a primary component again. { View tr1(0, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pu1.uuid(), 0); tr1.add_member(pu2.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); fail_unless(pc1.state() == Proto::S_TRANS); fail_unless(pc2.state() == Proto::S_TRANS); View reg1(0, ViewId(V_REG, uuid1, seq + 1)); reg1.add_member(pu1.uuid(), 0); reg1.add_member(pu2.uuid(), 0); reg1.add_member(pu3.uuid(), 0); reg1.add_joined(pu3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); fail_unless(pc1.state() == Proto::S_STATES_EXCH); fail_unless(pc2.state() == Proto::S_STATES_EXCH); View tr3(0, ViewId(V_TRANS, pc3.current_view().id())); tr3.add_member(pu3.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr3)); fail_unless(pc3.state() == Proto::S_TRANS); View reg3(0, ViewId(V_REG, uuid1, seq + 1)); reg3.add_member(pu1.uuid(), 0); reg3.add_member(pu2.uuid(), 0); reg3.add_member(pu3.uuid(), 0); reg3.add_joined(pu1.uuid(), 0); reg3.add_joined(pu2.uuid(), 0); pc3.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®3)); fail_unless(pc3.state() == Proto::S_STATES_EXCH); Datagram* dg1(pu1.tp()->out()); Datagram* dg2(pu2.tp()->out()); Datagram* dg3(pu3.tp()->out()); fail_unless(dg1 != 0); fail_unless(dg2 != 0); fail_unless(dg3 != 0); pc1.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc1.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc1.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); pc2.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc2.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); pc3.handle_up(0, *dg1, ProtoUpMeta(pu1.uuid())); pc3.handle_up(0, *dg2, ProtoUpMeta(pu2.uuid())); pc3.handle_up(0, *dg3, ProtoUpMeta(pu3.uuid())); delete dg1; delete dg2; delete dg3; fail_unless(pc1.state() == Proto::S_INSTALL); fail_unless(pc2.state() == Proto::S_INSTALL); fail_unless(pc3.state() == Proto::S_INSTALL); im = pu1.tp()->out(); fail_unless(im != 0); fail_unless(pu2.tp()->out() == 0); fail_unless(pu3.tp()->out() == 0); pc1.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); pc2.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); pc3.handle_up(0, *im, ProtoUpMeta(pu1.uuid())); fail_unless(pc1.state() == Proto::S_PRIM); fail_unless(pc2.state() == Proto::S_PRIM); fail_unless(pc3.state() == Proto::S_PRIM); } } END_TEST // Nodes 1, 2, 3. Node 3 will be evicted from group while group is // fully partitioned. After remerging 1 and 2 they should reach // primary component. START_TEST(test_prim_after_evict) { log_info << "START(test_prim_after_evict)"; UUID uuid1(1), uuid2(2), uuid3(3); gu::Config conf1; gcomm::Conf::register_params(conf1); ProtoUpMeta pum1(uuid1); Proto pc1(conf1, uuid1, 0); DummyTransport tp1; PCUser pu1(conf1, uuid1, &tp1, &pc1); single_boot(1, &pu1); gu::Config conf2; gcomm::Conf::register_params(conf2); ProtoUpMeta pum2(uuid2); Proto pc2(conf2, uuid2, 0); DummyTransport tp2; PCUser pu2(conf2, uuid2, &tp2, &pc2); double_boot(1, &pu1, &pu2); gu::Config conf3; gcomm::Conf::register_params(conf3); ProtoUpMeta pum3(uuid3); Proto pc3(conf3, uuid3, 0); DummyTransport tp3; PCUser pu3(conf3, uuid3, &tp3, &pc3); triple_boot(1, &pu1, &pu2, &pu3); // Node 1 partitions { // Trans view View tr1(1, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pc1.uuid(), 0); tr1.add_partitioned(pc2.uuid(), 0); tr1.add_partitioned(pc3.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); // Reg view View reg1(1, ViewId(V_REG, pc1.uuid(), tr1.id().seq() + 1)); reg1.add_member(pc1.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®1)); // States exch Datagram* dg(tp1.out()); fail_unless(dg != 0); pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid())); delete dg; // Non-prim dg = tp1.out(); fail_unless(dg == 0); fail_unless(pc1.state() == Proto::S_NON_PRIM); } // Node 2 partitions { // Trans view View tr2(1, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pc2.uuid(), 0); tr2.add_partitioned(pc1.uuid(), 0); tr2.add_partitioned(pc3.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); // Reg view View reg2(1, ViewId(V_REG, pc2.uuid(), tr2.id().seq() + 1)); reg2.add_member(pc2.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®2)); // States exch Datagram* dg(tp2.out()); fail_unless(dg != 0); pc2.handle_up(0, *dg, ProtoUpMeta(pc2.uuid())); delete dg; // Non-prim dg = tp2.out(); fail_unless(dg == 0); fail_unless(pc2.state() == Proto::S_NON_PRIM); } // Just forget about node3, it is gone forever // Nodes 1 and 2 set node3 evicted pc1.evict(pc3.uuid()); pc2.evict(pc3.uuid()); // Nodes 1 and 2 merge and should reach Prim { // Trans view for node 1 View tr1(1, ViewId(V_TRANS, pc1.current_view().id())); tr1.add_member(pc1.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr1)); Datagram *dg(tp1.out()); fail_unless(dg == 0); fail_unless(pc1.state() == Proto::S_TRANS); // Trans view for node 2 View tr2(1, ViewId(V_TRANS, pc2.current_view().id())); tr2.add_member(pc2.uuid(), 0); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), &tr2)); dg = tp2.out(); fail_unless(dg == 0); fail_unless(pc2.state() == Proto::S_TRANS); // Reg view for nodes 1 and 2 View reg(1, ViewId(V_REG, pc1.uuid(), tr1.id().seq() + 1)); reg.add_member(pc1.uuid(), 0); reg.add_member(pc2.uuid(), 0); pc1.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®)); pc2.handle_up(0, Datagram(), ProtoUpMeta(UUID::nil(), ViewId(), ®)); // States exchange fail_unless(pc1.state() == Proto::S_STATES_EXCH); fail_unless(pc2.state() == Proto::S_STATES_EXCH); // State message from node 1 dg = tp1.out(); fail_unless(dg != 0); pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid())); pc2.handle_up(0, *dg, ProtoUpMeta(pc1.uuid())); delete dg; dg = tp1.out(); fail_unless(dg == 0); // State message from node 2 dg = tp2.out(); fail_unless(dg != 0); pc1.handle_up(0, *dg, ProtoUpMeta(pc2.uuid())); pc2.handle_up(0, *dg, ProtoUpMeta(pc2.uuid())); delete dg; dg = tp2.out(); fail_unless(dg == 0); // Install fail_unless(pc1.state() == Proto::S_INSTALL, "state is %s", Proto::to_string(pc1.state()).c_str()); fail_unless(pc2.state() == Proto::S_INSTALL, "state is %s", Proto::to_string(pc2.state()).c_str()); // Install message from node 1 dg = tp1.out(); fail_unless(dg != 0); pc1.handle_up(0, *dg, ProtoUpMeta(pc1.uuid())); pc2.handle_up(0, *dg, ProtoUpMeta(pc1.uuid())); delete dg; // Prim dg = tp1.out(); fail_unless(dg == 0); dg = tp2.out(); fail_unless(dg == 0); fail_unless(pc1.state() == Proto::S_PRIM); fail_unless(pc2.state() == Proto::S_PRIM); } } END_TEST Suite* pc_suite() { Suite* s = suite_create("gcomm::pc"); TCase* tc; bool skip = false; if (!skip) { tc = tcase_create("test_pc_messages"); tcase_add_test(tc, test_pc_messages); suite_add_tcase(s, tc); tc = tcase_create("test_pc_view_changes_single"); tcase_add_test(tc, test_pc_view_changes_single); suite_add_tcase(s, tc); tc = tcase_create("test_pc_view_changes_double"); tcase_add_test(tc, test_pc_view_changes_double); suite_add_tcase(s, tc); tc = tcase_create("test_pc_view_changes_reverse"); tcase_add_test(tc, test_pc_view_changes_reverse); suite_add_tcase(s, tc); tc = tcase_create("test_pc_state1"); tcase_add_test(tc, test_pc_state1); suite_add_tcase(s, tc); tc = tcase_create("test_pc_state2"); tcase_add_test(tc, test_pc_state2); suite_add_tcase(s, tc); tc = tcase_create("test_pc_state3"); tcase_add_test(tc, test_pc_state3); suite_add_tcase(s, tc); tc = tcase_create("test_pc_conflicting_prims"); tcase_add_test(tc, test_pc_conflicting_prims); suite_add_tcase(s, tc); tc = tcase_create("test_pc_conflicting_prims_npvo"); tcase_add_test(tc, test_pc_conflicting_prims_npvo); suite_add_tcase(s, tc); tc = tcase_create("test_pc_split_merge"); tcase_add_test(tc, test_pc_split_merge); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_pc_split_merge_w_user_msg"); tcase_add_test(tc, test_pc_split_merge_w_user_msg); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_pc_complete_split_merge"); tcase_add_test(tc, test_pc_complete_split_merge); tcase_set_timeout(tc, 25); suite_add_tcase(s, tc); tc = tcase_create("test_pc_protocol_upgrade"); tcase_add_test(tc, test_pc_protocol_upgrade); tcase_set_timeout(tc, 25); suite_add_tcase(s, tc); tc = tcase_create("test_pc_transport"); tcase_add_test(tc, test_pc_transport); tcase_set_timeout(tc, 35); suite_add_tcase(s, tc); tc = tcase_create("test_trac_191"); tcase_add_test(tc, test_trac_191); suite_add_tcase(s, tc); tc = tcase_create("test_trac_413"); tcase_add_test(tc, test_trac_413); suite_add_tcase(s, tc); tc = tcase_create("test_fifo_violation"); tcase_add_test(tc, test_fifo_violation); suite_add_tcase(s, tc); tc = tcase_create("test_checksum"); tcase_add_test(tc, test_checksum); suite_add_tcase(s, tc); tc = tcase_create("test_set_param"); tcase_add_test(tc, test_set_param); suite_add_tcase(s, tc); tc = tcase_create("test_trac_599"); tcase_add_test(tc, test_trac_599); suite_add_tcase(s, tc); tc = tcase_create("test_trac_620"); tcase_add_test(tc, test_trac_620); suite_add_tcase(s, tc); tc = tcase_create("test_trac_277"); tcase_add_test(tc, test_trac_277); suite_add_tcase(s, tc); tc = tcase_create("test_trac_622_638"); tcase_add_test(tc, test_trac_622_638); suite_add_tcase(s, tc); tc = tcase_create("test_weighted_quorum"); tcase_add_test(tc, test_weighted_quorum); suite_add_tcase(s, tc); tc = tcase_create("test_weighted_partitioning_1"); tcase_add_test(tc, test_weighted_partitioning_1); suite_add_tcase(s, tc); tc = tcase_create("test_weighted_partitioning_2"); tcase_add_test(tc, test_weighted_partitioning_2); suite_add_tcase(s, tc); tc = tcase_create("test_weight_change_partitioning_1"); tcase_add_test(tc, test_weight_change_partitioning_1); suite_add_tcase(s, tc); tc = tcase_create("test_weight_change_partitioning_2"); tcase_add_test(tc, test_weight_change_partitioning_2); suite_add_tcase(s, tc); tc = tcase_create("test_weight_change_joining"); tcase_add_test(tc, test_weight_change_joining); suite_add_tcase(s, tc); tc = tcase_create("test_weight_change_leaving"); tcase_add_test(tc, test_weight_change_leaving); suite_add_tcase(s, tc); tc = tcase_create("test_trac_762"); tcase_add_test(tc, test_trac_762); tcase_set_timeout(tc, 15); suite_add_tcase(s, tc); tc = tcase_create("test_join_split_cluster"); tcase_add_test(tc, test_join_split_cluster); suite_add_tcase(s, tc); tc = tcase_create("test_gh_92"); tcase_add_test(tc, test_gh_92); suite_add_tcase(s, tc); tc = tcase_create("test_prim_after_evict"); tcase_add_test(tc, test_prim_after_evict); suite_add_tcase(s, tc); } return s; } percona-galera-3-3.8-3390/gcomm/test/check_templ.hpp000066400000000000000000000046171244131713600220620ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #ifndef GCOMM_CHECK_TEMPL_HPP #define GCOMM_CHECK_TEMPL_HPP #include "gcomm/types.hpp" #include "gcomm/transport.hpp" #include #include #include namespace gcomm { template void check_serialization(const T& c, const size_t expected_size, const T& default_c) { fail_unless(c.serial_size() == expected_size, "size = %lu expected = %lu", c.serial_size(), expected_size); gu::byte_t* buf = new gu::byte_t[expected_size + 7]; size_t ret; // Check that what is written gets also read try { (void)c.serialize(buf, expected_size, 1); std::ostringstream os; os << c; fail("exception not thrown for %s", os.str().c_str()); } catch (gu::Exception& e) { // OK } fail_unless(c.serialize(buf, expected_size, 0) == expected_size); T c2(default_c); // Commented out. This test happened to work because default // protocol version for messages was zero and if the second // byte of the buffer contained something else, exception was // thrown. Now that the version can be different from zero, // the outcome of this check depends on message structure. // try // { // size_t res(c2.unserialize(buf, expected_size, 1)); // std::ostringstream os; // os << c; // fail("exception not thrown for %s, result %zu expected %zu", // os.str().c_str(), res, expected_size); // } // catch (gu::Exception& e) // { // // OK // } ret = c2.unserialize(buf, expected_size, 0); fail_unless(ret == expected_size, "expected %zu ret %zu", expected_size, ret); if ((c == c2) == false) { log_warn << "\n\t" << c << " !=\n\t" << c2; } fail_unless(c == c2); // Check that read/write return offset properly fail_unless(c.serialize(buf, expected_size + 7, 5) == expected_size + 5); fail_unless(c2.unserialize(buf, expected_size + 7, 5) == expected_size + 5); fail_unless(c == c2); delete[] buf; } } // namespace gcomm #endif // CHECK_TEMPL_HPP percona-galera-3-3.8-3390/gcomm/test/check_trace.cpp000066400000000000000000000315561244131713600220340ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * * $Id$ */ /*! * @brief Check trace implementation */ #include "check_trace.hpp" #include "gcomm/conf.hpp" using namespace std; using namespace gu; using namespace gcomm; struct CheckTraceConfInit { explicit CheckTraceConfInit(gu::Config& conf) { gcomm::Conf::register_params(conf); } }; // This is to avoid static initialization fiasco with gcomm::Conf static members // Ideally it is the latter which should be wrapped in a function, but, unless // this is used to initialize another static object, it should be fine. gu::Config& check_trace_conf() { static gu::Config conf; static CheckTraceConfInit const check_trace_conf_init(conf); return conf; } ostream& gcomm::operator<<(ostream& os, const TraceMsg& msg) { return (os << "(" << msg.source() << "," << msg.source_view_id() << "," << msg.seq() << ")"); } ostream& gcomm::operator<<(ostream& os, const ViewTrace& vtr) { os << vtr.view() << ": "; copy(vtr.msgs().begin(), vtr.msgs().end(), ostream_iterator(os, " ")); return os; } ostream& gcomm::operator<<(ostream& os, const Trace& tr) { os << "trace: \n"; os << tr.view_traces(); return os; } ostream& gcomm::operator<<(ostream& os, const Channel& ch) { return (os << "(" << ch.latency() << "," << ch.loss() << ")"); } ostream& gcomm::operator<<(ostream& os, const Channel* chp) { return (os << *chp); } ostream& gcomm::operator<<(ostream& os, const MatrixElem& me) { return (os << "(" << me.ii() << "," << me.jj() << ")"); } ostream& gcomm::operator<<(ostream& os, const PropagationMatrix& prop) { os << "("; copy(prop.prop_.begin(), prop.prop_.end(), ostream_iterator(os, ",")); os << ")"; return os; } class LinkOp { public: LinkOp(DummyNode& node, ChannelMap& prop) : node_(node), prop_(prop) { } void operator()(NodeMap::value_type& l) { if (NodeMap::key(l) != node_.index()) { ChannelMap::iterator ii; gu_trace(ii = prop_.insert_unique( make_pair(MatrixElem(node_.index(), NodeMap::key(l)), new Channel(check_trace_conf())))); gcomm::connect(ChannelMap::value(ii), node_.protos().front()); gu_trace(ii = prop_.insert_unique( make_pair(MatrixElem(NodeMap::key(l), node_.index()), new Channel(check_trace_conf())))); gcomm::connect(ChannelMap::value(ii), NodeMap::value(l)->protos().front()); } } private: DummyNode& node_; ChannelMap& prop_; }; class PropagateOp { public: PropagateOp(NodeMap& tp) : tp_(tp) { } void operator()(ChannelMap::value_type& vt) { ChannelMsg cmsg(vt.second->get()); if (cmsg.rb().len() != 0) { NodeMap::iterator i(tp_.find(vt.first.jj())); gcomm_assert(i != tp_.end()); gu_trace(NodeMap::value(i)->protos().front()->handle_up( &tp_, cmsg.rb(), ProtoUpMeta(cmsg.source()))); } } private: NodeMap& tp_; }; class ExpireTimersOp { public: ExpireTimersOp() { } void operator()(NodeMap::value_type& vt) { NodeMap::value(vt)->handle_timers(); } }; void gcomm::Channel::put(const Datagram& rb, const UUID& source) { Datagram dg(rb); // if (dg.is_normalized() == false) // { // dg.normalize(); // } queue_.push_back(make_pair(latency_, ChannelMsg(dg, source))); } ChannelMsg gcomm::Channel::get() { while (queue_.empty() == false) { pair& p(queue_.front()); if (p.first == 0) { // todo: packet loss goes here if (loss() < 1.) { double rnd(double(rand())/double(RAND_MAX)); if (loss() < rnd) { queue_.pop_front(); return ChannelMsg(Datagram(), UUID::nil()); } } ChannelMsg ret(p.second); queue_.pop_front(); return ret; } else { --p.first; return ChannelMsg(Datagram(), UUID::nil()); } } return ChannelMsg(Datagram(), UUID::nil()); } gcomm::PropagationMatrix::~PropagationMatrix() { for_each(prop_.begin(), prop_.end(), ChannelMap::DeleteObject()); } void gcomm::PropagationMatrix::insert_tp(DummyNode* t) { gu_trace(tp_.insert_unique(make_pair(t->index(), t))); for_each(tp_.begin(), tp_.end(), LinkOp(*t, prop_)); } void gcomm::PropagationMatrix::set_latency(const size_t ii, const size_t jj, const size_t lat) { ChannelMap::iterator i; gu_trace(i = prop_.find_checked(MatrixElem(ii, jj))); ChannelMap::value(i)->set_latency(lat); } void gcomm::PropagationMatrix::set_loss(const size_t ii, const size_t jj, const double loss) { ChannelMap::iterator i; gu_trace(i = prop_.find_checked(MatrixElem(ii, jj))); ChannelMap::value(i)->set_loss(loss); } void gcomm::PropagationMatrix::split(const size_t ii, const size_t jj) { set_loss(ii, jj, 0.); set_loss(jj, ii, 0.); } void gcomm::PropagationMatrix::merge(const size_t ii, const size_t jj, const double loss) { set_loss(ii, jj, loss); set_loss(jj, ii, loss); } void gcomm::PropagationMatrix::expire_timers() { for_each(tp_.begin(), tp_.end(), ExpireTimersOp()); } void gcomm::PropagationMatrix::propagate_n(size_t n) { while (n-- > 0) { for_each(prop_.begin(), prop_.end(), PropagateOp(tp_)); } } void gcomm::PropagationMatrix::propagate_until_empty() { do { for_each(prop_.begin(), prop_.end(), PropagateOp(tp_)); } while (count_channel_msgs() > 0); } void gcomm::PropagationMatrix::propagate_until_cvi(bool handle_timers) { bool all_in = false; do { propagate_n(10); all_in = all_in_cvi(); if (all_in == false && handle_timers == true) { expire_timers(); } } while (all_in == false); } size_t gcomm::PropagationMatrix::count_channel_msgs() const { size_t ret = 0; for (ChannelMap::const_iterator i = prop_.begin(); i != prop_.end(); ++i) { ret += ChannelMap::value(i)->n_msgs(); } return ret; } bool gcomm::PropagationMatrix::all_in_cvi() const { for (map::const_iterator i = tp_.begin(); i != tp_.end(); ++i) { if (i->second->in_cvi() == false) { return false; } } return true; } static void check_traces(const Trace& t1, const Trace& t2) { for (Trace::ViewTraceMap::const_iterator i = t1.view_traces().begin(); i != t1.view_traces().end(); ++i) { Trace::ViewTraceMap::const_iterator j = t2.view_traces().find(Trace::ViewTraceMap::key(i)); if (j == t2.view_traces().end()) continue; ViewType type = i->first.type(); // @todo Proper checks for PRIM and NON_PRIM if (type == V_TRANS || type == V_REG) { Trace::ViewTraceMap::const_iterator i_next(i); ++i_next; Trace::ViewTraceMap::const_iterator j_next(j); ++j_next; if (type == V_TRANS) { // if next reg view is same, then views and msgs are the same. if (i_next != t1.view_traces().end() && j_next != t2.view_traces().end() && i_next->first == j_next->first) { gcomm_assert(*i == *j) << "trace differ: \n\n" << *i << "\n\n" << *j << "\n\n" "next views: \n\n" << *i_next << "\n\n" << *j_next; } } if (type == V_REG) { // members are same all the times. gcomm_assert(i->second.view().members() == j->second.view().members()) << "trace differ: \n\n" << *i << "\n\n" << *j; // if next trans view has same members, then msgs are the same. if (i_next != t1.view_traces().end() && j_next != t2.view_traces().end()) { if (i_next->second.view().members() == j_next->second.view().members()) { gcomm_assert(i->second.msgs() == j->second.msgs()) << "trace differ: \n\n" << *i << "\n\n" << *j << "\n\n" "next views: \n\n" << *i_next << "\n\n" << *j_next; } else { // if not, then members should be disjoint. std::map output; std::set_intersection(i_next->second.view().members().begin(), i_next->second.view().members().end(), j_next->second.view().members().begin(), j_next->second.view().members().end(), std::inserter(output,output.begin())); gcomm_assert(output.size() == 0) << "trace differ: \n\n" << *i << "\n\n" << *j << "\n\n" "next views: \n\n" << *i_next << "\n\n" << *j_next; } } // if previous trans view id is the same. // the reg view should be the same. // if previous trans view id is not same. // intersections of joined, left, partitioned sets are empty. if (i == t1.view_traces().begin() || j == t2.view_traces().begin()) continue; Trace::ViewTraceMap::const_iterator i_prev(i); --i_prev; Trace::ViewTraceMap::const_iterator j_prev(j); --j_prev; if (i_prev->first == j_prev->first) { gcomm_assert(i->second.view() == j->second.view()) << "trace differ: \n\n" << *i << "\n\n" << *j << "\n\n" "previous views: \n\n" << *i_prev << "\n\n" << *j_prev; } else { std::map output; int joined_size = 0, left_size = 0, part_size = 0; std::set_intersection(i->second.view().joined().begin(), i->second.view().joined().end(), j->second.view().joined().begin(), j->second.view().joined().end(), std::inserter(output, output.begin())); joined_size = output.size(); output.clear(); std::set_intersection(i->second.view().left().begin(), i->second.view().left().end(), j->second.view().left().begin(), j->second.view().left().end(), std::inserter(output, output.begin())); left_size = output.size(); output.clear(); std::set_intersection(i->second.view().partitioned().begin(), i->second.view().partitioned().end(), j->second.view().partitioned().begin(), j->second.view().partitioned().end(), std::inserter(output, output.begin())); part_size = output.size(); output.clear(); gcomm_assert(i->second.view().members() == j->second.view().members() && joined_size == 0 && left_size == 0 && part_size == 0) << "trace differ: \n\n" << *i << "\n\n" << *j << "\n\n" "previous views: \n\n" << *i_prev << "\n\n" << *j_prev; } } } } } class CheckTraceOp { public: CheckTraceOp(const vector& nvec) : nvec_(nvec) { } void operator()(const DummyNode* n) const { for (vector::const_iterator i = nvec_.begin(); i != nvec_.end(); ++i) { if ((*i)->index() != n->index()) { gu_trace(check_traces((*i)->trace(), n->trace())); } } } private: const vector& nvec_; }; void gcomm::check_trace(const vector& nvec) { for_each(nvec.begin(), nvec.end(), CheckTraceOp(nvec)); } percona-galera-3-3.8-3390/gcomm/test/check_trace.hpp000066400000000000000000000371601244131713600220360ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy * * $Id$ */ /*! * Classes for tracing views and messages */ #include "gu_uri.hpp" #include "gu_datetime.hpp" #include "gcomm/datagram.hpp" #include "gcomm/uuid.hpp" #include "gcomm/protolay.hpp" #include "gcomm/protostack.hpp" #include "gcomm/transport.hpp" #include "gcomm/map.hpp" #include "gcomm/util.hpp" #include #include #include gu::Config& check_trace_conf(); namespace gcomm { class TraceMsg { public: TraceMsg(const UUID& source = UUID::nil(), const ViewId& source_view_id = ViewId(), const int64_t seq = -1) : source_(source), source_view_id_(source_view_id), seq_(seq) { } const UUID& source() const { return source_; } const ViewId& source_view_id() const { return source_view_id_; } int64_t seq() const { return seq_; } bool operator==(const TraceMsg& cmp) const { return (source_ == cmp.source_ && source_view_id_ == cmp.source_view_id_ && seq_ == cmp.seq_ ); } private: UUID source_; ViewId source_view_id_; int64_t seq_; }; std::ostream& operator<<(std::ostream& os, const TraceMsg& msg); class ViewTrace { public: ViewTrace(const View& view) : view_(view), msgs_() { } void insert_msg(const TraceMsg& msg) { switch (view_.type()) { case V_REG: gcomm_assert(view_.id() == msg.source_view_id()); gcomm_assert(contains(msg.source()) == true) << "msg source " << msg.source() << " not int view " << view_; break; case V_TRANS: gcomm_assert(view_.id().uuid() == msg.source_view_id().uuid() && view_.id().seq() == msg.source_view_id().seq()); break; case V_NON_PRIM: break; case V_PRIM: gcomm_assert(view_.id() == msg.source_view_id()) << " view id " << view_.id() << " source view " << msg.source_view_id(); gcomm_assert(contains(msg.source()) == true); break; case V_NONE: gu_throw_fatal; break; } if (view_.type() != V_NON_PRIM) { msgs_.push_back(msg); } } const View& view() const { return view_; } const std::deque& msgs() const { return msgs_; } bool operator==(const ViewTrace& cmp) const { // Note: Cannot compare joining members since seen differently // on different merging subsets return (view_.members() == cmp.view_.members() && view_.left() == cmp.view_.left() && view_.partitioned() == cmp.view_.partitioned() && msgs_ == cmp.msgs_ ); } private: bool contains(const UUID& uuid) const { return (view_.members().find(uuid) != view_.members().end() || view_.left().find(uuid) != view_.left().end() || view_.partitioned().find(uuid) !=view_.partitioned().end()); } View view_; std::deque msgs_; }; std::ostream& operator<<(std::ostream& os, const ViewTrace& vtr); class Trace { public: class ViewTraceMap : public Map { }; Trace() : views_(), current_view_(views_.end()) { } void insert_view(const View& view) { gu_trace(current_view_ = views_.insert_unique( std::make_pair(view.id(), ViewTrace(view)))); log_debug << view; } void insert_msg(const TraceMsg& msg) { gcomm_assert(current_view_ != views_.end()) << "no view set before msg delivery"; gu_trace(ViewTraceMap::value(current_view_).insert_msg(msg)); } const ViewTraceMap& view_traces() const { return views_; } const ViewTrace& current_view_trace() const { gcomm_assert(current_view_ != views_.end()); return ViewTraceMap::value(current_view_); } private: ViewTraceMap views_; ViewTraceMap::iterator current_view_; }; std::ostream& operator<<(std::ostream& os, const Trace& tr); class DummyTransport : public Transport { UUID uuid_; std::deque out_; bool queue_; public: DummyTransport(const UUID& uuid = UUID::nil(), bool queue = true, const gu::URI& uri = gu::URI("dummy:")) : Transport(*std::auto_ptr (Protonet::create(check_trace_conf())), uri), uuid_(uuid), out_(), queue_(queue) {} ~DummyTransport() { out_.clear(); } const UUID& uuid() const { return uuid_; } size_t mtu() const { return (1U << 31); } void connect(bool first) { } void close(bool force) { } void close(const UUID&) { } void connect() { } void listen() { gu_throw_fatal << "not implemented"; } Transport *accept() { gu_throw_fatal << "not implemented"; return 0; } void handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { send_up(rb, um); } int handle_down(Datagram& wb, const ProtoDownMeta& dm) { if (queue_ == true) { // assert(wb.header().size() == 0); out_.push_back(new Datagram(wb)); return 0; } else { gu_trace(return send_down(wb, ProtoDownMeta(0xff, O_UNRELIABLE, uuid_))); } } Datagram* out() { if (out_.empty()) { return 0; } Datagram* rb = out_.front(); out_.pop_front(); return rb; } }; class DummyNode : public Toplay { public: DummyNode(gu::Config& conf, const size_t index, const std::list& protos) : Toplay (conf), index_ (index), uuid_ (UUID(static_cast(index))), protos_ (protos), cvi_ (), tr_ (), curr_seq_(0) { gcomm_assert(protos_.empty() == false); std::list::iterator i, i_next; i = i_next = protos_.begin(); for (++i_next; i_next != protos_.end(); ++i, ++i_next) { gu_trace(gcomm::connect(*i, *i_next)); } gu_trace(gcomm::connect(*i, this)); } ~DummyNode() { std::list::iterator i, i_next; i = i_next = protos_.begin(); for (++i_next; i_next != protos_.end(); ++i, ++i_next) { gu_trace(gcomm::disconnect(*i, *i_next)); } gu_trace(gcomm::disconnect(*i, this)); std::for_each(protos_.begin(), protos_.end(), gu::DeleteObject()); } const UUID& uuid() const { return uuid_; } std::list& protos() { return protos_; } size_t index() const { return index_; } void connect(bool first) { gu_trace(std::for_each(protos_.rbegin(), protos_.rend(), std::bind2nd( std::mem_fun(&Protolay::connect), first))); } void close(bool force = false) { for (std::list::iterator i = protos_.begin(); i != protos_.end(); ++i) { (*i)->close(); } // gu_trace(std::for_each(protos.rbegin(), protos.rend(), // std::mem_fun(&Protolay::close))); } void close(const UUID& uuid) { for (std::list::iterator i = protos_.begin(); i != protos_.end(); ++i) { (*i)->close(uuid); } // gu_trace(std::for_each(protos.rbegin(), protos.rend(), // std::mem_fun(&Protolay::close))); } void send() { const int64_t seq(curr_seq_); gu::byte_t buf[sizeof(seq)]; size_t sz; gu_trace(sz = gu::serialize8(seq, buf, sizeof(buf), 0)); Datagram dg(gu::Buffer(buf, buf + sz)); int err = send_down(dg, ProtoDownMeta(0)); if (err != 0) { log_debug << "failed to send: " << strerror(err); } else { ++curr_seq_; } } Datagram create_datagram() { const int64_t seq(curr_seq_); gu::byte_t buf[sizeof(seq)]; size_t sz; gu_trace(sz = gu::serialize8(seq, buf, sizeof(buf), 0)); return Datagram (gu::Buffer(buf, buf + sz)); } const Trace& trace() const { return tr_; } void set_cvi(const ViewId& vi) { log_debug << uuid() << " setting cvi to " << vi; cvi_ = vi; } bool in_cvi() const { for (Trace::ViewTraceMap::const_reverse_iterator i( tr_.view_traces().rbegin()); i != tr_.view_traces().rend(); ++i) { if (i->first.uuid() == cvi_.uuid() && i->first.type() == cvi_.type() && i->first.seq() >= cvi_.seq()) { return true; } } return false; } void handle_up(const void* cid, const Datagram& rb, const ProtoUpMeta& um) { if (rb.len() != 0) { gcomm_assert((um.source() == UUID::nil()) == false); // assert(rb.header().size() == 0); const gu::byte_t* begin(gcomm::begin(rb)); const size_t available(gcomm::available(rb)); // log_debug << um.source() << " " << uuid() // << " " << available ; // log_debug << rb.len() << " " << rb.offset() << " " // << rb.header_len(); if (available != 8) { log_info << "check_trace fail"; } gcomm_assert(available == 8); int64_t seq; gu_trace(gu::unserialize8(begin, available, 0, seq)); tr_.insert_msg(TraceMsg(um.source(), um.source_view_id(), seq)); } else { gcomm_assert(um.has_view() == true); tr_.insert_view(um.view()); } } gu::datetime::Date handle_timers() { std::for_each(protos_.begin(), protos_.end(), std::mem_fun(&Protolay::handle_timers)); return gu::datetime::Date::max(); } private: size_t index_; UUID uuid_; std::list protos_; ViewId cvi_; Trace tr_; int64_t curr_seq_; }; class ChannelMsg { public: ChannelMsg(const Datagram& rb, const UUID& source) : rb_(rb), source_(source) { } const Datagram& rb() const { return rb_; } const UUID& source() const { return source_; } private: Datagram rb_; UUID source_; }; class Channel : public Bottomlay { public: Channel(gu::Config& conf, const size_t ttl = 1, const size_t latency = 1, const double loss = 1.) : Bottomlay(conf), ttl_(ttl), latency_(latency), loss_(loss), queue_() { } ~Channel() { } int handle_down(Datagram& wb, const ProtoDownMeta& dm) { gcomm_assert((dm.source() == UUID::nil()) == false); gu_trace(put(wb, dm.source())); return 0; } void put(const Datagram& rb, const UUID& source); ChannelMsg get(); void set_ttl(const size_t t) { ttl_ = t; } size_t ttl() const { return ttl_; } void set_latency(const size_t l) { gcomm_assert(l > 0); latency_ = l; } size_t latency() const { return latency_; } void set_loss(const double l) { loss_ = l; } double loss() const { return loss_; } size_t n_msgs() const { return queue_.size(); } private: size_t ttl_; size_t latency_; double loss_; std::deque > queue_; }; std::ostream& operator<<(std::ostream& os, const Channel& ch); std::ostream& operator<<(std::ostream& os, const Channel* ch); class MatrixElem { public: MatrixElem(const size_t ii, const size_t jj) : ii_(ii), jj_(jj) { } size_t ii() const { return ii_; } size_t jj() const { return jj_; } bool operator<(const MatrixElem& cmp) const { return (ii_ < cmp.ii_ || (ii_ == cmp.ii_ && jj_ < cmp.jj_)); } private: size_t ii_; size_t jj_; }; std::ostream& operator<<(std::ostream& os, const MatrixElem& me); class ChannelMap : public Map { public: struct DeleteObject { void operator()(ChannelMap::value_type& vt) { delete ChannelMap::value(vt); } }; }; class NodeMap : public Map { public: struct DeleteObject { void operator()(NodeMap::value_type& vt) { delete NodeMap::value(vt); } }; }; class PropagationMatrix { public: PropagationMatrix() : tp_(), prop_() { } ~PropagationMatrix(); void insert_tp(DummyNode* t); void set_latency(const size_t ii, const size_t jj, const size_t lat); void set_loss(const size_t ii, const size_t jj, const double loss); void split(const size_t ii, const size_t jj); void merge(const size_t ii, const size_t jj, const double loss = 1.0); void propagate_n(size_t n); void propagate_until_empty(); void propagate_until_cvi(bool handle_timers); friend std::ostream& operator<<(std::ostream&,const PropagationMatrix&); private: void expire_timers(); size_t count_channel_msgs() const; bool all_in_cvi() const; NodeMap tp_; ChannelMap prop_; }; std::ostream& operator<<(std::ostream& os, const PropagationMatrix& prop); // Cross check traces from vector of dummy nodes void check_trace(const std::vector& nvec); } // namespace gcomm percona-galera-3-3.8-3390/gcomm/test/check_types.cpp000066400000000000000000000045251244131713600220760ustar00rootroot00000000000000/* * Copyright (C) 2009 Codership Oy */ #include "check_gcomm.hpp" #include "gcomm/view.hpp" #include "gcomm/types.hpp" #include "gcomm/map.hpp" #include #include #include #include using std::pair; using std::make_pair; using std::string; #include "check_templ.hpp" #include using namespace gcomm; START_TEST(test_uuid) { UUID uuid; fail_unless(uuid.full_str() == "00000000-0000-0000-0000-000000000000", "%s", uuid.full_str().c_str()); for (size_t i = 0; i < 159; ++i) { UUID uuidrnd(0, 0); log_debug << uuidrnd; } UUID uuid1(0, 0); UUID uuid2(0, 0); fail_unless(uuid1 < uuid2); // Verify that short UUID notation matches with first 8 chars // of full uuid string. std::string full(uuid1.full_str()); std::ostringstream os; os << uuid1; fail_unless(full.compare(0, 8, os.str()) == 0, "%s != %s", full.c_str(), os.str().c_str()); } END_TEST START_TEST(test_view) { const UUID uuid1(1); const UUID uuid2(2); const UUID uuid3(3); // View id ordering: // 1) view seq less than // 2) uuid newer than (higher timestamp, greater leading bytes) // 3) view type (reg, trans, non-prim, prim) ViewId v1(V_REG, uuid2, 1); ViewId v2(V_REG, uuid1, 1); ViewId v3(V_TRANS, uuid1, 1); ViewId v4(V_TRANS, uuid3, 2); ViewId v5(V_REG, uuid2, 2); ViewId v6(V_REG, uuid1, 2); ViewId v7(V_TRANS, uuid1, 2); fail_unless(v1 < v2); fail_unless(v2 < v3); fail_unless(v3 < v4); fail_unless(v4 < v5); fail_unless(v5 < v6); fail_unless(v6 < v7); ViewId vid; fail_unless(vid.uuid() == UUID()); fail_unless(vid.seq() == 0); UUID uuid(0, 0); vid = ViewId(V_REG, uuid, 7); fail_unless(vid.uuid() == uuid); fail_unless(vid.seq() == 7); NodeList nl; for (size_t i = 0; i < 7; ++i) { nl.insert(make_pair(UUID(0, 0), Node(0))); } fail_unless(nl.size() == 7); } END_TEST Suite* types_suite() { Suite* s = suite_create("types"); TCase* tc; tc = tcase_create("test_uuid"); tcase_add_test(tc, test_uuid); suite_add_tcase(s, tc); tc = tcase_create("test_view"); tcase_add_test(tc, test_view); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/gcomm/test/check_util.cpp000066400000000000000000000132361244131713600217060ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ #include "gcomm/util.hpp" #include "gcomm/protonet.hpp" #include "gcomm/datagram.hpp" #include "gcomm/conf.hpp" #ifdef HAVE_ASIO_HPP #include "asio_protonet.hpp" #endif // HAVE_ASIO_HPP #include "check_gcomm.hpp" #include "gu_logger.hpp" #include #include #include #include #include using std::vector; using std::numeric_limits; using std::string; using namespace gcomm; using gu::Exception; using gu::byte_t; using gu::Buffer; START_TEST(test_datagram) { // Header check gcomm::NetHeader hdr(42, 0); fail_unless(hdr.len() == 42); fail_unless(hdr.has_crc32() == false); fail_unless(hdr.version() == 0); hdr.set_crc32(1234, NetHeader::CS_CRC32); fail_unless(hdr.has_crc32() == true); fail_unless(hdr.len() == 42); gcomm::NetHeader hdr1(42, 1); fail_unless(hdr1.len() == 42); fail_unless(hdr1.has_crc32() == false); fail_unless(hdr1.version() == 1); gu::byte_t hdrbuf[NetHeader::serial_size_]; fail_unless(serialize(hdr1, hdrbuf, sizeof(hdrbuf), 0) == NetHeader::serial_size_); try { unserialize(hdrbuf, sizeof(hdrbuf), 0, hdr); fail(""); } catch (Exception& e) { // ok } gu::byte_t b[128]; for (gu::byte_t i = 0; i < sizeof(b); ++i) { b[i] = i; } gu::Buffer buf(b, b + sizeof(b)); gcomm::Datagram dg(buf); fail_unless(dg.len() == sizeof(b)); // Normal copy construction gcomm::Datagram dgcopy(buf); fail_unless(dgcopy.len() == sizeof(b)); fail_unless(memcmp(dgcopy.header() + dgcopy.header_offset(), dg.header() + dg.header_offset(), dg.header_len()) == 0); fail_unless(dgcopy.payload() == dg.payload()); // Copy construction from offset of 16 gcomm::Datagram dg16(dg, 16); log_info << dg16.len(); fail_unless(dg16.len() - dg16.offset() == sizeof(b) - 16); for (gu::byte_t i = 0; i < sizeof(b) - 16; ++i) { fail_unless(dg16.payload()[i + dg16.offset()] == i + 16); } #if 0 // Normalize datagram, all data is moved into payload, data from // beginning to offset is discarded. Normalization must not change // dg dg16.normalize(); fail_unless(dg16.len() == sizeof(b) - 16); for (byte_t i = 0; i < sizeof(b) - 16; ++i) { fail_unless(dg16.payload()[i] == i + 16); } fail_unless(dg.len() == sizeof(b)); for (byte_t i = 0; i < sizeof(b); ++i) { fail_unless(dg.payload()[i] == i); } Datagram dgoff(buf, 16); dgoff.header().resize(8); dgoff.set_header_offset(4); fail_unless(dgoff.len() == buf.size() + 4); fail_unless(dgoff.header_offset() == 4); fail_unless(dgoff.header().size() == 8); for (byte_t i = 0; i < 4; ++i) { *(&dgoff.header()[0] + i) = i; } dgoff.normalize(); fail_unless(dgoff.len() == sizeof(b) - 16 + 4); fail_unless(dgoff.header_offset() == 0); fail_unless(dgoff.header().size() == 0); #endif // 0 } END_TEST #if defined(HAVE_ASIO_HPP) START_TEST(test_asio) { gu::Config conf; gcomm::Conf::register_params(conf); AsioProtonet pn(conf); string uri_str("tcp://127.0.0.1:0"); Acceptor* acc = pn.acceptor(uri_str); acc->listen(uri_str); uri_str = acc->listen_addr(); SocketPtr cl = pn.socket(uri_str); cl->connect(uri_str); pn.event_loop(gu::datetime::Sec); SocketPtr sr = acc->accept(); fail_unless(sr->state() == Socket::S_CONNECTED); vector buf(cl->mtu()); for (size_t i = 0; i < buf.size(); ++i) { buf[i] = static_cast(i & 0xff); } for (size_t i = 0; i < 13; ++i) { Datagram dg(Buffer(&buf[0], &buf[0] + buf.size())); cl->send(dg); } pn.event_loop(gu::datetime::Sec); delete acc; } END_TEST #endif // HAVE_ASIO_HPP START_TEST(test_protonet) { gu::Config conf; gcomm::Conf::register_params(conf); Protonet* pn(Protonet::create(conf)); pn->event_loop(1); } END_TEST START_TEST(test_view_state) { // compare view. UUID view_uuid(NULL, 0); ViewId view_id(V_TRANS, view_uuid, 789); UUID m1(NULL, 0); UUID m2(NULL, 0); View view(0, view_id, true); view.add_member(m1, 0); view.add_member(m2, 1); View view2; { std::ostringstream os; view.write_stream(os); std::istringstream is(os.str()); view2.read_stream(is); fail_unless(view == view2); } // compare view state. UUID my_uuid(NULL, 0); ViewState vst(my_uuid, view); UUID my_uuid_2; View view_2; ViewState vst2(my_uuid_2, view_2); { std::ostringstream os; vst.write_stream(os); std::istringstream is(os.str()); vst2.read_stream(is); fail_unless(vst == vst2); } const char* fname = "/tmp/gvwstate.dat"; // test write file and read file. vst.write_file(fname); UUID my_uuid_3; View view_3; ViewState vst3(my_uuid_3, view_3); vst3.read_file(fname); fail_unless(vst == vst3); unlink(fname); } END_TEST Suite* util_suite() { Suite* s = suite_create("util"); TCase* tc; tc = tcase_create("test_datagram"); tcase_add_test(tc, test_datagram); suite_add_tcase(s, tc); #ifdef HAVE_ASIO_HPP tc = tcase_create("test_asio"); tcase_add_test(tc, test_asio); suite_add_tcase(s, tc); #endif // HAVE_ASIO_HPP tc = tcase_create("test_protonet"); tcase_add_test(tc, test_protonet); suite_add_tcase(s, tc); tc = tcase_create("test_view_state"); tcase_add_test(tc, test_view_state); suite_add_tcase(s, tc); return s; } percona-galera-3-3.8-3390/gcomm/test/ssl_test.cpp000066400000000000000000000112671244131713600214360ustar00rootroot00000000000000/* Copyrignt (C) 2014 Codership Oy */ #include "gcomm/protonet.hpp" #include "gcomm/util.hpp" #include "gcomm/conf.hpp" #include #include static gu::Config conf; class Client : public gcomm::Toplay { public: Client(gcomm::Protonet& pnet, const std::string& uri) : gcomm::Toplay(conf), uri_ (uri), pnet_ (pnet), pstack_(), socket_(pnet_.socket(uri)), msg_ () { pstack_.push_proto(this); pnet_.insert(&pstack_); } ~Client() { pnet_.erase(&pstack_); pstack_.pop_proto(this); socket_->close(); } void connect(bool f = false) { socket_->connect(uri_); } std::string msg() const { return std::string(msg_.begin(), msg_.end()); } void handle_up(const void* id, const gcomm::Datagram& dg, const gcomm::ProtoUpMeta& um) { if (um.err_no() != 0) { log_error << "socket failed: " << um.err_no(); socket_->close(); throw std::exception(); } else { assert(id == socket_->id()); msg_.insert(msg_.begin(), gcomm::begin(dg), gcomm::begin(dg) + gcomm::available(dg)); } } private: gu::URI uri_; gcomm::Protonet& pnet_; gcomm::Protostack pstack_; gcomm::SocketPtr socket_; gu::Buffer msg_; }; class Server : public gcomm::Toplay { public: Server(gcomm::Protonet& pnet, const std::string& uri) : gcomm::Toplay(conf), uri_(uri), pnet_(pnet), pstack_(), listener_(), smap_(), msg_("hello ssl") { pstack_.push_proto(this); pnet_.insert(&pstack_); listener_ = pnet_.acceptor(uri_); } ~Server() { delete listener_; pnet_.erase(&pstack_); pstack_.pop_proto(this); } void listen() { listener_->listen(uri_); } void handle_up(const void* id, const gcomm::Datagram& dg, const gcomm::ProtoUpMeta& um) { if (id == listener_->id()) { gcomm::SocketPtr socket(listener_->accept()); if (smap_.insert( std::make_pair(socket->id(), socket)).second == false) { throw std::logic_error("duplicate socket entry"); } return; } std::map::iterator si(smap_.find(id)); if (si == smap_.end()) { throw std::logic_error("could not find socket from map"); } gcomm::SocketPtr socket(si->second); if (socket->state() == gcomm::Socket::S_CONNECTED) { gcomm::Datagram msg; msg.payload().resize(msg_.size()); std::copy(msg_.begin(), msg_.end(), msg.payload().begin()); socket->send(msg); } else if (socket->state() == gcomm::Socket::S_CLOSED || socket->state() == gcomm::Socket::S_FAILED) { std::cerr << "socket " << id << " failed" << std::endl; socket->close(); smap_.erase(id); } else { std::cerr << "socket state: " << socket->state() << std::endl; } } private: Server(const Server&); void operator=(const Server&); gu::URI uri_; gcomm::Protonet& pnet_; gcomm::Protostack pstack_; gcomm::Acceptor* listener_; std::map smap_; const std::string msg_; }; int main(int argc, char* argv[]) { if (argc != 4) { std::cerr << "usage: " << argv[0] << " <-s|-c> " << std::endl; return 1; } gu::Config conf; gcomm::Conf::register_params(conf); conf.parse(argv[2]); std::auto_ptr pnet(gcomm::Protonet::create(conf)); if (std::string("-s") == argv[1]) { Server server(*pnet, argv[3]); server.listen(); while (true) { pnet->event_loop(gu::datetime::Period(1 * gu::datetime::Sec)); } } else if (std::string("-c") == argv[1]) { Client client(*pnet, argv[3]); client.connect(); while (true) { pnet->event_loop(gu::datetime::Period(1*gu::datetime::MSec)); std::string msg(client.msg()); if (msg != "") { std::cout << "read message from server: '" << msg << "'" << std::endl; break; } } } return 0; } percona-galera-3-3.8-3390/gcs/000077500000000000000000000000001244131713600155565ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcs/ChangeLog000066400000000000000000000055271244131713600173410ustar00rootroot000000000000002010-07-18 Alex Substituted gcs_slave_queue_len() with gcs_get_stats() to return a wider range of gcs performance statistics. At this time it includes average slave queue length, average send queue length, fraction of time spent paused and number of flow control events sent and received. 2010-06-16 Alex Added gcs_interrupt() call to be able to interrupt scheduled threads. Version 0.13.1 2010-05-31 Alex Added flow control monitor and ability to synchronize with gcs_send() and gcs_repl() calls thus guranteeing FIFO order. Version 0.13.0 2010-05-20 Alex Added gcs_slave_queue_len() query to API. 2009-11-21 Alex Extended state message to contain previous primary configuraiton info. Many bugfixes and cleanups. Version 0.12.0 2009-08-09 Alex Added possibility to specify desired donor. Version 0.11.0 2009-08-06 Alex Refactored interface. Now connection URL is supplied to gcs_open() and not gcs_create(). It is done to satisfy wsrep API changes and is generally cleaner as it separates library initialisation from connection establishment. Version: 0.10.0 2009-07-21 Alex Added node name and incoming address arguments to gcs_create(). Thus it should be possible to give nodes sensible names and see them in logs. Version: 0.9.0 2009-06-21 Alex Moved TO module out of the library. Since it no longer offers this interface, bumped minor version: 0.8.0 2008-11-16 Alex Many bugfixes. Fixed handling of self-leave meassages. Switched to "mallocless" FIFO implementaiton in gu_fifo.c Resolved apparent race condition and optimized FC message sending. Package version 0.7.2 2008-11-09 Alex Changed state transfer protocol to require join message to be sent by both parties involved in state transfer. Package version 0.7.1, library interface 9.0.0. 2008-10-21 Alex First implementation of state transfer request protocol. Bumped package version to 0.7.0, library interface to 8.0.0. 2008-09-29 Alex (postfactum) State exchange (GCS state exchange, not application state exchange) implemented. Now we have some sort of quourum calculations and global-scope sequence numbers. New nodes can join without having to restart the whole group. Bumped package version to 0.6.0. 2008-08-01 Alex (postfactum) START/STOP-based flow control. A little bit ahead of the plan. 2008-07-30 Alex Added gcs_join() and gcs_wait() getting closer to final API. gcs_join() moves conneciton to JOINED state. gcs_wait() blocks waiting for the group memebers to catch up. 2008-05-14 Alex Added gcs_create() and gcs_destroy() for safe and clean initialization and deinitialization of GCS connection handle. 2008-03-23 Alex Added gcs_set_last_applied() and gcs_get_last_applied() - calls for voting for the last applied action. percona-galera-3-3.8-3390/gcs/README000066400000000000000000000011511244131713600164340ustar00rootroot00000000000000Welcome to libgcs - Group Communication system abstraction library. libgcs is intended to simplify the use of Group Communication semantics in applications which are not initially targeted for it. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, to the extent permitted by law; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. libgcs is free software. Please see the file COPYING for details. For documentation, please see the files in the doc subdirectory. For building and installation instructions please see the INSTALL file. percona-galera-3-3.8-3390/gcs/SConscript000066400000000000000000000000351244131713600175660ustar00rootroot00000000000000SConscript('src/SConscript') percona-galera-3-3.8-3390/gcs/doc/000077500000000000000000000000001244131713600163235ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcs/doc/Coding_conventions.txt000066400000000000000000000053361244131713600227230ustar00rootroot00000000000000These coding conventions were not set from the very beginning. They emerged as a result of coding. Therefore they have some practical basis for it. Not all code adheres to them, but that's what it should be like. Attempt was made to justify at least some of these conventions, but it's not about right or wrong really. It's about consistency. 1. Indentation. Tab width is 4, tabs filled with spaces. No real tabs. There is a controversy about this issue among programmers. In defense of this decision I can say that indentation is some sort of ASCII art and ASCII art does not always work good with tabs, especially when you need to alter it by hand. In other words: spaces are less flexible, but more predictable. 2. Braces position. Opening brace on the same line as the statement, see example below. 3. Spaces between tokens. See example below. 4. Function declarations/definitions. See example below. 5. Naming conventions. All names and identifiers are all lower case with underscores except macros which are all UPPER case. 5.1 File names. All C file names are prefixed with 'gcs' to avoid collisions in the file namespace with headers from other software. Prefix is followed by the module name. If module consists of more than one unit, unit names follow module name. Like gcs_module_unit1.[h|c], gcs_module_unit2.[h|c] and so on. 5.2 Symbol names. All global symbols - exported through header files - are prefixed with 'gcs' (or 'GCS' where appropriate) followed by the module name. This is done again to avoid namespace collisions with the third party software and with global symbols from other modules that may be called similarly. Static symbols defined in the *.c files simply start with the module name. This is done to easily distinguish between global and static symbols and to prevent collisions of static symbols from different modules when doing tags search. Example: int gcs_module_external_var; static int module_static_function (int a, int b) { int c; if (a < b) { c = b - a; } else { c = a - b; } return c; } 6. Long lines. Lines should not exceed 80 characters in length. One more reason to use spaces instead of tabs. (Suppose you have tabs of width 4 and then some other person reads the code with tabs width of 8. Many lines will grow more than 80 characters and may not fit in the screen.) 7. Spaces at the end of line. Should be avoided to minimize the diff. 8. NO COMPILER WARNINGS WHATSOEVER. These conventions are not set in stone and can be altered eventually. However, for the sake of consistency, try to follow these conventions unless there is a REAL (and well articulated) need to do otherwise. IF IN DOUBT - SEE HOW SIMILAR THINGS ARE DONE IN RECENT FILES. percona-galera-3-3.8-3390/gcs/doc/Doxyfile000066400000000000000000001436611244131713600200440ustar00rootroot00000000000000# Doxyfile 1.4.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = GCS # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.2.3 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./ # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, # Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, # Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, # Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, # Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that a graph may be further truncated if the graph's # image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH # and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), # the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO percona-galera-3-3.8-3390/gcs/doc/GCS_Architecture.odt000066400000000000000000000726551244131713600221700ustar00rootroot00000000000000PK ŸO7^Æ2 ''mimetypeapplication/vnd.oasis.opendocument.textPK ŸO7 content.xmlí][sã6–~ß_Òd§ìlKâE¢$Oì.'©éImw:5íìníK "!‰Ó$ÁðbYyʘ×Ý—ýiù%{À;)‰”ä¶:‘SqKÄpÎw®Aú«×O®CYÚÜ»í©¥G˜grËö–·½þÚŸö^ßýËW|±°Mvcq3v™õMîEð/Þ^x#[o{qàÝpÚáG]ÞDæ ÷™—öº)R߈¹ä•0Ú8­» âbïˆ=Em;#m©/·ŸY{[]·íŒ´j±û‚·íü:ýÔ]ŸFv…‹'Çö>ÞöVQäß ‡ëõz°ÖD4ø°qçÜé0ô”ʵM¥1-9d`OýP¶wOò@WÜ¥jà ²e_ÿ{Ï¢#ï¸ÇÆø3õyø—¼PbÙ·#fa?1«ÃlM,w˜î‘6õ}3¾MÛ¢äõBò£gC~d['n =žwÈ;Û3WÛáÍ(ŽŸ,ÑùVc8fhùž­Éßa$o»ú*„'ª<àKúþ’y,°!¶Éx³vdMÞ^ß>u¸¶Ãð„¨h'„åhÞþƒõšì0o9rúᶈœ\§qÒF¶Ùãd¡Zü.1ûƒšÍ•0éÓ€.ê¯Ò¸€¥³øÒ—½þÆ(VÚ?iÊOj/<ëØ÷H˜Adò .j×>uì%$˜Äad/6éÐÉ×~ƒÁàk@²[P'”R˜Þ!vˆ ÐÖ‹s¯Ÿ'÷’Ft/ŒX¸{  FgýdrǶzÍ$kÛ²Ír …É…·,ðsÙ_×Ì^® (€zÀ*9†lèCåH½íÍXa;ì)!h¯˜Ñ‘Ž¡½¸i‘à˜BöçÜÚ¼¸ÆQΑ8vX&xûò1kò{lú{lö{LU~·’TÛ|’Wóœ³dÇÕCç,ÙAÅ~É^¾ÎP*4> É*@J%ÔVéô——î *䳑î R䳑î zäs‘NÛQ“táÍXÐeâ%ÃaË>Õ…4'+Þ?-ÄOw$ÿSò˜ÌKé†ÝòtuÚ¿@“ªøQvdù1áŽä{b½™ucrGm­¤l±Ìʬ';òÞ³šXm·»Aëù5ì}Û³#˜Íl/ÝCÍÇ‘­]vw¨«>Ô¡=àn?â~­5@è6.p˜wwØ"j ¨Ž dXÃç¾í-œ˜y }îá8v$ÞKÁñŠ ¿ãÏ4g@;| v­ú@çcÆË v>¯­Ê.Šy^ÅÔÎ+äKŠ2Ÿ^|马vÀ³­ÊÂ(àa‹†)ÿòR¯Üö~t¢€.laÆù.1«—+;{ð¼)”âOÒÂ!§Ø°5VþõTáÚ–å°”çµB¾X„ïž03©š"– í›­í%>/¶Öhkµ¾…‡ÙÌ02û8™1´R‚vÛ+J¨9 úØî3«Ÿ šñxß±];ú㪽vÚú µc}5›½ˆÚÿx*«N?HeÌ`ÆéùEe;UV{n²…ÊðUGIÒÎÖeJ1»¹4øq-D9‰:©“0ÏÂWH|ù壬FRC™M³1Nf ~ãS ßå‚ê⨊X¯ZdE¸¥Õ¼¥)/´ÉÛ.–Øh‰µg\»–”÷’Þ%Æ™¯ ð§TFJÚæt±ô‡›+–*OS ý¢¼íÛ!µgxÏJ{êh:ºho»öN³›¥ë¦i—ÄýitvðvVÙãÚ¬­S¿Ê[`lËfÙ6ë›ä«|G`nE#s•î$;ÔüˆŠXÛƒ Ïmu~±¶fk;dîR'U'b£ÁïÈ^å‹)}ùªä«|-㨵Ë 4<ÇaÙÛ];lWÅ÷ïó8HÍíëoq4îh—¬Žú?xóÓè¢N.ð¼pšÍLE™Âû³Zö–¦5¾®Ê:4µŒRÔ¾˜Ås˜ÅÁ¦ŸfÏãN þáÖ×´' ø~¶ì Uø‹ï¬ ÜBï7ã0óNÙèûΦo±ܺïr‹˜‘glØÏR®äÍñõ‹òÀe‡¾C7}GâEÝÉÁ ô\´ÛïâK@œæ: ö¾åþ¸Qàãу|+ÿøQ~P¨µUýˆÔééûÊðjïîÍ7È}`®ìˆ™Q0ò ùÑfkr…Pˆ  ]'Ó­’ü†ði]a§Œ#Û)þ m|V7ç_À–-|:¾ -‰ùpr÷ KýòT#P’µÔh '3;ù[ypFjzõ Oêê4» —ÔŠ8¸K*%m }êÕ ƽ»oÜX hâàÿhs€¦:‚Ž©¾|øT¸¸ÕaÌÁßÀùúáŠú¬öÓfìíØ+%ìÀ^Õ±×u½ˆýh0™Nµ2öº>+`?L$aÞ ÿÕ_2î²(؈h_sÜ&! ÑTCI~ÙÄ¢Îë…B^/&ð¿V¦HÄ>ÐA ‘.̹e/l@¿ñÅ_ISƈ/þÕ;‚Ë©ß9‰JäoJžœ1¼‚“§ÿÊ«ÿM¾O•>+­D|“¸.²DÑ2vèmï •ô†»z¨µÊžZµ‡`­¿w&½¹ ¸»ã¨ÚñõB'_"xCÙîÞãzo•üÛëÅhϬFS¿Ö³Nšzƒ¬F>+T¥¤ð¹ŠÍ/Re&õ–¬ÿÔ‡ÚÅvcWDõÆvú$Û%› 4›=clò1¤íÓ€Só«´¡:Ž&³OMÔÁ´ÉŸ5šL‡žUc‰Å×Þ΀2Ò·*Þî è2i‹žÐÊïòŠäPÏBR÷@³/lÔÍ>¿ßhöÍ´%Ðì¯gLûûÕ" pø%˜6¢fÒ¨8Þ3k-Â$ÜîCgÚ ‡/1Õµáv¶ÛiÛ¸¦/Ô3ˆk™¬âZ›JëÐúµ1èémcž10fyšÆ õÁHîÆm“ÐeaH—ì™Eܲ[ l·F½ÏÆz]|u<ÒËe\°[)þl‡ôû"Íß™ÉìGÛ[’„R’™¸ÞE«€QkW Ú…"sÛ»íº¨Í8ªmó‚6P&MŽ2S+yA7Š ±<–Ñrar×½d¼eÈ7aÄÜ*| D†@­y¹Ö6*êtV ú–ÑF9–h4QfOGú‰C¹v\JšU9 )©D£dÝ%GךFi6ޫ牮UmWL¦J9*ʬ!J¨G®žï ÷{žsÝœ³ÇÛR+wÇ4Co¨»'…V¹ðO*{ª£‰¶¡cKòôÖãßæ>Ùè6'¡ÖKoHÁ³Üÿ 5µ1™”rиºc­Ì´Ù‘‚Ðm—Üì\T6»pÛHTFECTgÓJQ92 4š<¦ïˆD'»¯ÚÕšš«¶Ö4SšîT¬IŒ’5õÉ ÉóÖ;8 ¥¹PézK†¢Ô²nÉF hÚ©“nón¦º³7ɺc£´€‚¡0¸ðGÛ¯c…¯4°ì_Xå‚5ÁZ9‰VŒÄ¾\^…¨Ù(\KaÓ¸\žYŠkq|ÿ,ÌëRX £ 3 ’Ü|úŸ YäA¹Æðö2’'Vxp.” lp.æEÎæ%)î†×UGm€Ü‘ûÂÓ!ÁG”%¡íúBá˜aY±õ¤Jô©É\7B›ðY<‡är0A¾ û9¶ÐèŠÇ!ûȘS7s¶¢ÎI†ò7¾fÀj(6+BlmÅ#‰ß®¯hˆðÍ\âY˜`¾)r"0EbÀFä#S0“À¹þí×ÿ™ã{*E¿ýú¿8À©¹J• âA‹hxCÀäùZ½Å½?SŸ‡‰H¸Â±©·!â@;ÿ„„d{r—ÞßÞ±'“ùéá 2 äï f¤Ü¶H{‘ U§µ!Àž]æò`#&—È\Ÿ šwÕ‘‰’‚¹ˆÌQªä$é ñx" ¿°-ô ¬Î[‚Õ5“–—µ§âC6¥éo®®ÅLâtLrã}@š(¤ëƒ)¤T§´6˜S°| ¦©8"!—††µ! Ô8<2ˆ$ø°': „&ËFs@öCæR0ˆ¹øÆl0ûû·`ÁÔI\L7ÙÃ}EÞ|SmM@óõ+˜4ФÃ{ 5‡/a|úa„¼`¥àC€^pbc¡Ç¤±â+@j‚‡þ¥Kzf¬Ÿ K€Å»ºš jË] 'ö8z_ƒ9…QÁ¾Á‚脨zIH¡‡h4‡©W íb9¿°'§¿ÿö}Ë<®uÉãªØ#tù#K‘ç"¤p˜ßŶá€Ü;NF"mJÀeR Ö˘cœ3+>_'“vÃãHD2@ž:Ñf@®~ô-4Íß~ý'Æ·ò˜Õîß•†ª…Él,ˆvŠBRL’Ò^Ä 3‰ É0–cU$lÉQ3†By0ئÎÁ:\(N Ç àX pƒ$(tSŒrâmgø8™•xCjN"Ç-â'FQìJ…´ë·WÈóu’36àz%‚1×’Y÷瘱‹YÈŒ$úRq`«a9e²pjÀ‹‹™ ”%õPä+uüÌÂrÎOLøöDîKA./ªP|¼NÆæ1G[´X~qaE((ÆáÔZÄ´Ö2!ê"Ôÿ‰“#®¡-—) ä*uºB[ Ãi gœþž ô"³æ¡iý+™yÅ}T¾$¢hïØ-²#HÈÐM vEÓÒXŒ»@ŸB=f5µBš|ɇËÃæ Ùh'—Ÿ ÔÎ^Õ$»ëì„A¯áJ«NH×`ŸÏ¢yÇgÍqÕ%æê<:e‰y Uz$ÃsŽû׉„»@æÎœºäÅ0r*#F“¬‡À&Q™Œ’;¥mUž€>¬D™ÞTlá@5+÷7 ×+eÆ¡¦ˆ‰É bÑ_ËÉ$K€qX‡ÚÑ&‹Ž2Ý% ¡!„2lÉ4ÀlŒ¥L¶È B´^q˜ 3¹´š‚.佌U\ ¶ÚÆ~²S%*~ɨð‚d¸0]Še BÆÍÜc¨¬cÐl¼ ¢eÎŽŒ'×í‚å0 6çßäk_Òoi-&^šÿÞý?PKP݃«õ®PK ŸO7 layout-cachecd`d(àc``àd``Ñ2PKXsØîPK ŸO7 styles.xmlÍZ[¯Û¸~ï¯\lßdK¾ÛM²Èv±ÝI𤝠Z¢m6)”/ùõÞ$ʦ|t.-NØÄœÃáÌpø‘Ô»ŸÏe1„Ñ÷£tœŒ"L3–º?úöõ·x5úùßޱݎdx“³¬.1•±—‹:S±1Â÷£šÓ C‚ˆ E%™mX…©ë´ñÑ=”iÑʆv×`¿·Äg9´³Âvú¢íð‘5ØïstÚYaÁ§~÷Úù,ŠxÇ⌕’äÊŠsAè÷÷£ƒ”Õf29NãÓlÌø~’®×뉖6g ®ªy¡Qy6ÁVƒ‰I:N'[b‰†Ú§°¾I´.·˜v ’è&ªâ¸œÇ}k²âƒsCƒ»áåÃÃ;Ëý¾%’‡ž˜¬&ŸA¨ÿ÷ùS› ¼:–Âv\•qR ž¦Aûýc©ªƒY ÚÜi’Ì'æ·‡>Ý…Ÿ8‘˜{ðì.ÞcŠ9ÒÁ­¾g›ö`¡ÕíÚû‡'"Ä+zeúŠny±mÿÆ{Âãt¹\<2ë&«4 šG â„.â±’éÕC{Œ½ª‚ó¶JÜ9ÿ¶£§´»?¡H©þO©=ä…rØ"¢ô9q¿J™'‡ÝYd8«¥Þ |TU(õEê*"éâ§6J'Löˆö–ytOhz9q¸oƒžÞ @÷N¦÷ƒ4}{Aš ÒÜ’ÓfNgN pzbì®W™Œ•:•ÏŽmX{#ï×ÿÌèº÷œ°Þ [¡T¬r×¥'nùßP¥èÊ+n~`*GOÜ ¼‚ß»è·Iór¦m¢¡gZ¢óÙ=¬%ýDeôb;(wÃ!Æaï¤ïàÿjÞVŸã«ôè„øíúœ®Ï¯˜SDë»›S¯”¯·²~©‹ëÕmÞÈDx[0°è ÓÐoŸX=Êuü¹nž¯ïðžgS3n!¦yŸ$l S¯<ÒZ¦—›·E‚õÒ{¹ÇjiÝ ˜‘•šqý=¤*‡ÞW Z[ûñ‚ºÿÀÏœÀ‘÷=„] ¼ÊW•é(€¹:ºiɉäê w5ž.f–^hÁÁ^=¤éxÙyt¹š£|(c 40ûÀ_1'"ün9_õÑ»…ë–H>¬æ=DÒ‰¥ë}³´~ØsÒ~Š‘%ê¿Â~n‘h”Œ§«ÖÇëíÅÃ¥³ug¬õŸln´ÀòWßCvHªÒAè>fùb{Vº~í2ë4.ѹ5Ll¿è±+ç`“3Š}>x\ÜU&°òCwРÙz¡á0åÿ©…4ËÂ,Ó<Ùåë´½p¼úÅ`e¾›×#õÀ£LüÉz·ŠÚ%z»&­ D¢ÑÑŒf•¦»o4¾ÍíZö*ÕöIøcùÿPK)Ãø© l/PK ŸO7meta.xml”A›0…ïýíÕ1†„$°j•zÚC“CO•cOˆ»`#cšäß0°u¥ýæ›7ÏÆ&y½•…÷L-µJ}² |×Bª<õ‡ïhç¿f_}>KThÞ” ,*Á2¯mU5u¥ÔoŒ¢šÕ²¦Š•PSË©®@-tNÓ~Sn…T况¶¢_¯×Õ5Zi“c²ßïq_QÁ'®jLÑS‚c( ›Pc²"xd»„φêØy$­õ4¨Ã]è~\kìÖ¾7læáø²ñ¬:Ó,é­sP`˜Õ&{kÝÞfn«ðå¨äÍ{ÔWFÿnq¼ J²~ùÖÈB =‰Ö ^ºRI+Y¸^ýZÀ îÞ¯Æð ¨w=´-1×ܯÚüH0 Y»Á‘øF4ÜQ²º¹Dpúù¸Y±Gç-""›CÒMLÉ®]?¢2RYètÿl 3bÖ²ˆ¾=1mgDdÞõ‘»`*oX(tüÙ‡˜$ç ¢=)•#~çÔÙz;-t75$à,¯WºË–ú?ÔY{ÄÇÏ`ásXô¶ž°éÅÖ¶ýxµ•ÜÁ– @\7ʦ~{ñÝý(ÛXŠúÔ]Å¥ZÍÈpÒ Ë «.S •«6b7›xPù¥mà¶ÝÇPŠb²ï’ã‡'„ÿ÷óÉþPKAøÄ#îºPK ŸO7Thumbnails/thumbnail.pngŒ»eT[ÍöKK ´h¡-î^¬¸»»»µ¸{pV¤8/RÜ]ƒ„B‹»/nAA‚<ÿó®uÞçKvVÖž™k2÷Üó»föŽÑP“Ç~Kò[QAF ymAAy‚†ü§å_AA‘žU”‘Ôñý Í}“©ó·ãf-òë†\¹ŒÄY ™×š[8Ó¯Úìð8Tâ”ñ›ˆ/³rvöŽRWÕS«è:†·SÚ^Äc¢™HH|üð>)(5ˆèK$DÀüÑáì0ñó4¯$ ´Sðyÿ°¬s²B»L-÷¹±°î_õmߟF†ý—¬6!•L´- ú§´Âž`TÒµu…ô™”VÔ`D1N²'†"9Í>^ŠÌõÿïé‹×[3nFÍŸ´2e/û)Ÿ4p(ÅX8˜˜’S†-ElóƒZwYÌc8ÁÏgÝž“¢ú‘XÄøû¶3úæA-ÍN®¾³¯ý‘Ã1ŒyL5ÆmµÉ×E‰b042¢öÉDç•V?0b¾NåfÕ3±ÙuCìó F70žÍë±`h áÞöSv帀˜SÊã\»áémߎPÇÀ€{Y¶],u]zÖØÉ4ZA7k°x×@él^GÇÅÚ4yÊ SÐ1»!8¸ûẠœÆ¬]:ŠŠnqˆ‰‰Ù]–篔ÎaÎŽ¼Vrf˜xÄÔ;#®aËŽuo^ z·Ÿƒ;à Æ»ì¸17#,ud~—ãüÎË®Á—90¨+Ðøû÷ï]Çu`³§ÛAq%3³<¶A¿ý\Æbðå„p‰~Ù»™ ³€Tra í]ˆm>Üf<›^Ôÿ*º$>¯m ¸þQ ¯ê ù‚ÁäÚuésÒ082̘ϊ,õ£D9cdœÃiøú¼w´­Ζ%Ð*¿ |<67É÷ÙŽçOHçßà¾ÿæÜ…›¸pÖímY\>†.Öå³Mêê›Ò³è×6?Ãɬ­­‘C1ù“ŸÎ›- _+GOIMèN¹Çe yGÃNa7)tzCOâCëgKU/Z>øÁ†K\7z`ˆãºÑt6cÖwÓÿ5¾{9)ÞæKZõe»öÍýC°û¥6é ÃÒú—}ßø S¿¤¡=+.ãø¯´Zí¦¥(üv’ ƒ”@“àópʡӵNçXuÜ>?àÓe>f÷ßÉàë&lìGˆ%eàùï¥`Œç«Yõ•H_¤†|{ûŠ«Ó5a=ôã…šTdYy•㓬ôy1¬˜1u wqºf‘ܰ,¡)ÝYÏ}íT¸ÈóÃ%l—Ùv]ïZ<€~ä0s¢,ÅNÆ×Ú¾‡¶Þَ㮞 ùr M}G+·t†C.¤p¹7îŒ 4ó• Föt%ë…àÈjvÍ}œËfŒ(§² ‡yŠÂþWvNŸºÇ…fPz¾Œòù‚²µ e§âúí¦dèAZZ,5ÿáÞÌqÅ!ïà (øtçýL ."™h1;u,á@Á4R°ù¯ª¼üÜ·}Ø)äúŸ×Fuðù~£øüäCYªŸr¸/œÞþã¾c?/67½áíºò¯µ¤Žb9z<~¿&ôµ³—vZ‘%ü'¹Ú“wèu½Îú¸œï1 {<nìI:Úƒ qMßüBÙAg0Ç¥)æF‡Îz\l¶¯°wž4í §Š~ÿ:DÉ)Ô"ºØ\q$÷ùYmÖ½ü9כƄIy¯Ÿ“a0³PtŠzKLéb¿sé ‘ýǘŒçÝ sŠÑ{äçõA®ÔsS0ÑKùfúVbyW2 9†D߈Ðå—Ž$8ËLê#†ž‹|ñÉéc èÆ£»éšàã”çDàöAu -Ïa Þ!™ÂèÿJ\N "ŽšÃ¤i¦d¾’¡ú¿ó—©òy%¥|ù÷ïoï¿?F¨Õ?³#§êIάïfEá6ŸÓ’†¥yW Š«ˆôœŒÂ‘‘ÅÄOÁë4Þâ=ÕíFëѦI±¦'â¤þÒ.’}烰טnË}Ó¥ûÁ®à}haàSàq{Døûs²ÁžxR~£¶—d½C©ü±ÅÎÆ€yÐø²ý=fgóUú‹j6HñlÓž¶†-iðß!^Iï_n9½:¤2Êás®¾g[šÖ¿X¨pœÌ½&Ýx—€ŠG¹C˜$® ‹°²Ý1û)ÆnÏ®vx:÷ öÒ½Dˆ¨+ª ŸÓy™gEkÆbkë-ÝŸ¿±x* ü–X÷ñü… 9ôn“«êÏâö¹ÎþWíu³Š£ÀÀÆ¢SîFyxóïR@8çCôÌ}‡üyßO}º,M Ñî"o' êD¨+ÝtRŒ½xê|RGIãŵ—Ælž´U§›A7‡À{g'90µ2}B¤ÐÖ"Ié›BþY°x†‹^B©À'…þªåx8t@¦ HòÐB×5b ]ÉÁ±’"/†ýVb®¨ø)«ÊsNôa¸b€a;éô>[é.•KËöå/Ên?ÍÍ'c›¥lù.KOlI@òɲ`¤ÐÄG ÛîR59»5ým9teyÌ,Ò—5`/üœ@íù•Òˆ9UˆjF¦¢±õƸ!‰6ÈÙ¿1'ù¥?é×ÐQz6£p´WÞ,QÆEQQ,>^ÇTÜí8ä‚E<£aÅ[!ѧ©x´µÅe?[:âºuþ¯R¯Ì°iÎXïÌŒÞoü²æöMÇ?mfæa½= ÄËeEÍ›Ò~¶z¹ÕíF@÷c]Û8?yú»ÇåK›xOÇ¿GÕo?áQ”.é¹Â¸ ÏO¯÷À^SF|.«´„f:zµ«ì¹ÂmÉ5ƘÖç›––2êô\î%ò¼J[ƒ²œ¸¬Ä\—x¿î36Þlât‚ë}ËîÀR ÇB:ß•c‹­cõ´Ì4³µ¤<MAÍi}}øökBê8äŸ2RR<˜™ìX¬­Ó컟J¥&R³õüú#×®÷œ!ZL²²QŦîû‚“e€Ήƒ‹o™€F6,gd- ñÜô„t«š!’­g+LP#Ÿ”\Ùè“j§ÞH½ØöN·nSqõVR©ˆ¡ p¹õ¤‚†oQÜBÆÕÚòËÊÒ` †è9PœêÙƒÿ×¼ÿÉÒ ÄáàKÒ!;¶L‚ÉvwTÖa€í¨WÄLþÞ&¡e´Îfîð¬OÆžáBî?úF´ F¶~Ãz¿Vt²Ä™ ,™ØW|UK¹êÖ/`Œn"´1„}DÛÒzäÍ¡à{rZ<®$ –šöYÎÿÐ5÷ØoJ|t™f æOü“X–ÁnG®ó(ÖÈö_‰„·Züï%½ÏšÌ)U‘yCž)KÚÖ½1{á0¯^=àkŸ2¼£¶÷¬ÉzÚzŒ:­)•|;³üï³äN—óÀµ€$¶º!É…T#ãcü±!F)Ó7•‡M¿ÒÐ Õ ÒL 9ê¼ÚD Só­q)Yµ$#Í•õ6í‰ÓN+HÀÙð-³¶®Ã;ZÒŸ)$a?i¥›Q)/sé¬KJ`3 À¹ØO>ÅEôŽžAëþ~$a Ü(›7FäÝUi5ûÔ¬uhï}ü0|d=:#uZc|œG8]²õz8&*O´©ÿ™@ò™ ½? [eu_ª:ãØ‹b(âS»ÓæÂÖöŒXô€CÛÊd_vÝniÏ4Z÷`QW¾ï•&à­è~!y¸PÓy²ÚaЏ¡dZisM‹'5̸0°_iÍu‚4j"AÎB:óyeuµìÒXQQ±á1è|S²éù•ýHUi4[-¢XCá$^àû iýŽ%üèµ6ù“{ÿqï –Ü)r5ANºÜ±¬Ël“À‹ «}>lÄ×'´ÈÕ<½ÙaÞè#›ÿdpF:Eãáb¹%m’Vð{CÓçHùª“½¡BC3%˜;×+À÷HvUm¶ß0K ä{*}ýì¶."8GâAÉ3c%5˜€Íp3WaÞ²ñ*«x>—k·ÒÀ©Ç~¶Ç%H”ªÝeÖ %¬Î°IK.Ql¶””ÿ”¬óqF¹lÁ°”‡WJ‹ÿE3<øPØ(cÞn›ø/þܱ¾3ñ±fÅCqM&di_5×ýÇcV²j~ƒ£Ø“A0·cúš¹ñ¸éÆ‚hƸ?uEžPÁ+i5QÝvsvrÌ·'À›oZBÃýs-¶êöó{Ñ6ëæLPa€’/®¥½¢âŒ—jhÒqÄ é¨…¥2§V|{²Æm#LÒ:Ï®âw× ƒ;ö³'gÏ~{Äð‚¼ýðí7¬\Å·>Дè²a . §TÂá4í?÷C9…#ÖÐü©$Þ¯þ¶ÀÂæ3$P“­‚Íöö•¹¹©º.ÅÂÖ„}F€b°èfGs^Z›Õ?1°Ûç‡D'“N=›U÷¨À.߆jÑц•VÅ<Ák ÷†.°ñÎî·bMþrTÂW.‹E´¤ù–°ó|‰G$~n ª‹p¦_³ð¯YÅà&ðî?ÿ[³Ç>=ÇCëªË“öزó´TÍÃðàaøËê§¾Z´ö=Þ¾I’È’°K".ÁÐt}•lLË…xj¤³¯ÑuûÒ¯¡—Îv#JêBgÛ”›ˆæzO|ñìF1[z«³ñHO½7K™.j¯SœÖ‡!y<:Y3û,ìØzç±»óþÇ™JݼÀ‡‹ç}_ùX_^¨ãP°¶ü¢Æìkåuôá]Œs cQ —ÒÚÿ\ ~Âb!˜ø§Ú¤ÏÀjû÷Îë­$­Ñ½2ŸÒå^¼øŠh†bn¿[F¯ãFOÚãíMdzqsôÐÁô#iS´½äˆB®£kùÇÉ,Ë n“1 ”÷ЧïÍL¿¡øOý•öŒëè¦R»óB‹ê¦ÁfxÍ×<¦|Ȥ(£­z«ß4€ ÕP´Q½ Ÿ™šwzƒûëZ’Î×2êñï²±V™œ°RêÙ•éTÖQ8†¬¯X8XRõóµT²éò]W™Ð‘€›‚Š^½æ½µ›1³Ÿ­Í}Øn±Ï´,×1°AlмÓ+9(àÚÀ˜çÙx±®í>c,—Å:RçÒÏŽ¤ÔÎ%õð€JÛ÷.ÿ„ãŽWhCA;¤zµÍuÅʱ±%}"ïY°²&A;ølfb?=çgJOÖ|,m¸×·þ•9?2ýj"®0ib´.ö6>vÊ NÂúL›žùüìÄÜ1š”šÛœôNú\ }äÇÐŽ¤ãwG±D¹hma×jk;è£àFj™zâîŽ|{Ÿ gðÅ¿gø¢õ¿½J”Ôâ3¯1N8h@Å¡Džœ¸ÚfAJN"&›Åz¾$îÆÌÇ´åL¥éÍVçdë­æ»'–è÷%øXy² UZO÷/õjœ®x@"Çœ5Ù òò¡G pð#×iŸô»–ÚÑÝå~Àíöxtp(ñ+øgZ#ýïÇ¢ŸBˆ§ƒÇ5mJufÝR…üœzÕÔwww\®ë"ìŸjöƲh È´ž‘ɘãx|Ów,““G'%CÿCН#Ú¡!3#¶;Ê–ÅÁ^Ìg#î;°¯éÌ|÷H͵„4„sb€h¡­î›õÔC›l”côþ ìú¦Óv’ÂïbkÝòâZ<Õƒúîh¾ªÄçl6(þ¤ÙsÝRqmEú)È=ÒœYC­gÀ@ 0K.ú.wH uçÕŒ2i÷…’`…íXæW–ïÓ÷½•ï‚vܼZÈšØ,Ø—‘%–”lQìBÛœ 4HòMA¦qåý‰\6ja¯ª*½šÆ…§´t^,·T9·ÜËšãOK!-àõW&&¦úä$ªÒ ï+¨€×îܶ‡eISYáUµ üs¤‰Î¿[¸ßïQ*kxiþ°E¥{i´‹Mʧ°ÑD[ú÷Zàô¡YKm; þxÙð èßhFY‘î]x¹éjKâ`¸ƒƒ‘£‘Í%ÞRäžPz©!Aí׌„t!–õ.+eÁmj*]xf²·Cw»<¡5Ÿ¾ 1 ø”«»ú¢—W¥ç®§”=rì§ ·5 sÄÙ¹¢)”îÇ4½7ŸÅBáO ï«Õ wÂôÅ¥Ÿ!v„=3ÂTyø˜¢EÙ[Cqj×*ãüm® ÉÍøx`AcÞœcv)A֎¥ ˜&õˆšÂ#lNžTê.™èÿlÜ`*Ë’µr—Ãé L7Hy"yK8áAÇÔÚIžÅë]~uØ›}Õ¯1F‰m±¢Ù>ïô!M©ñž þpÁÃb ¾Ó׿P„O‰W;âÖŒ˜ÂÑ)Yœ—›«gýŽ›N¿Ó@,€xqUr<üШ4Ç›Åþÿ f=4:ÖÔ H×qÒÓt@È”Íæ‘0·Ú‹ÌŠÃ‡e”ŒH,ÿÛ†póq¥€E?˜â8µnbdOó›liÍ+@Àãs2pA°°J78.z ÞŸ( ¶ùJffÊdGÒFK‚îqæÌç*¾&H̽Ø$Í‹(¾ÇŽª@¼a0‰ÔH*¾ „W­¶h”{šæ‡gqÏIc²ÇÝ.í·ß½,(t¼xwo/Ž\X¨َa{»þþÐìз}ôt ÝyˆÍÅãÓù„°«:uzæ—¿vG3Œ´šžÞ¦ºÕuØDROR@Ú\][àú"žáÇuÌf¢çSM¸ùô=“®ѢÞS.ÌuQrÉÙ9†šîK)„›örl„NÚè<óñN³§‚aÍž…éGGU¶Vù'÷_Þ¿¨¿¬pÇʸê1ÊñdlT?éH¦B¬Ô ·á¬ÚG¶T Ë2‰“¼i²: Ò´ºä2"Ñ݉ÐXSÓ•òúP{¾¦¨h±nƒM:ꚇͪ„Õ¤}½ÕDëãîŽ-ާ¢ÔñJ/…ž„$DltŸ¡Ó•9ÕW·›á~§„ùú$Æa=ð[!þbXªq¸Tž‡’y–°O Ò­-¼v¿¢n ¾8zy'ÙMìáÔBùõ`G·³¿Oœk@w¼åó÷c{ß^¯äËÂÿÙ°¨~d[þrScÚ©‰{F_¥çÜÆ¦“HAUµEùp&÷)L!ƒõÙûéNÛb¦H=?6- ÍŽdÅÕ_¤_Û‚Tð2íTRfâUaÖz®L½“~f,Џ˜”Lï$u´’퇘µfI,§ bW/ Â]§ Ùª×22ž•ëÅŽbw;fÓ§FíbŠZâ0WÜ òæãO’ÔÔ´‹ò¦?ýö$V”f-sýö.8kÈtò>MbÓѬ!k÷9Yºî´Ý›#G{-#RX5K¹«=ù 7`štà\¸7.q6$HsMÀqk "¯ÐÔ‡D"‰]»s‘ Ë<•ÉWï©Þ”9M!›‚éJ·Æ‡EPD*õ±¢i¾¾£l×6_ƒß]Mqc¡‰?…8ëçñSgÒâyÝèÕªt¥Ñ‡-CCjQô9tNÈÅæÔoAƒæ¶e¾¿[Éáè&FåØ.Z×k“»w#IÙ ÄïèsêaáÀÑ?,`æ¦ü`…ëÀM%¬F;»ÊÇ­äVw]ú»«U®¸ë¾r‘qbêA]½ Ïò{8—®wçÐŒ’f_ðŒ´etÔÔ°'—µÚ¢j3}.¹%mÁéJË8~Ka—ÊÇ.XñO­ù;œ“Ô™ÔëŸe*]«xÁ`Õ¶ë¢;­FðT:úÉR³ÑNš‚ädp©w7g$‚:EÝ 7!7eí0µÖ1óWxëã’¬¹”›µ¼fKN&`o:\ñ>`]á¯M©qLWÞ? šþ½önïb©¡ÝØy‘L]cÛz¶Zßû›0³°$ö‘{¸=›Ù¯4ÄªŽ¢“-uÎ^£9¦w³8uøã’Qß<ŸrÌ”Ù*Ÿ#ð„“µî’1kàíóؿ”¬A@Î'†µ{ý;wÍ#|Û¶‰ƒÁ‰ÝVÙÎÎŒ*ÝóO‰8§Éù`;X©|øMêú»‹-“Äü%G!6ÓöžûSsåÒ\7z®Óluæsöþóìn‰¬q±iâo)Z…]‰ö]6Ù©Õª“›FkóD¬èa7KÜùˆf ïM…”ÜÀ£†•E—…xßí\Å‹â‰?þcþÇòÑ¥ýš#ü2{½¹š©vÞª]Aö;WÕ|wTÚIZÏPWज़×óIÓ¤Õj»»æþýšÇºß>$©Ás¢%ôuŒ¹ŠÐu"™ Vß: ÒÇÅʤ¦ýëZqE̳±³·ÂW*´I3ng_©r037¯ÊJ5ZÅ`ï+mpOФúÎjØ%þã_iÄffäM{ý5Ú²hä!m³ETgÜ61À%vñ‡zS¬˜êôùì3F@o5ñËUøóV,Gú7LÂe‰›?).‹µ¹q¢FqëH ‡ôu:Ëü˜SÚ,QÎ0z™Šþ{!&RÈnª€¡§A½[Üs1@ê+ŒLݸ¸ÍÛ‰âfìí›/I3²§‰Ó –ò2h÷1”Õ.D¥j¹àùxÀÈækðñ ß{hÛÊ®ØmïØbëOe…%ˆn€wÑ„À‡Ã¸>SZc8æ3š.ov‹Œ,Xc_}¤&‰\þ“)mžuH“oÅ'‰@ý‹'õ#EÈØ¬+ÄéS%ëHÖo7W¦úM!,„rǤ#$!Y¥ü“ã(¤œ®ïµu¢ˆI½DñiPÏÐÐL'…¤lýÈ­dXrc 7ŒÎÚ°yÕÀÜ?¶UÊ.«jÅ_Áá$¡®›oÉ]ˆÚŒÇ*8éà®WkÌ™›ñÕ¼âö£øÒž"°­æ!—º{G³7’ˆGMò¹¶Ï‘þzP ðêN·ZqhšT-Â…ÔŸ* ¡ÐßÓÿ ´ï»œäH kåê«u— ´é›9…h;Yr4u ÍbÜ”½ËÍ®nþ`ÿ‘cI»ô§ÉÜœ„^ƒºüõ+‹:¾ó sÔÚ-°u.4¶š‘ûüÜ­¥&Ö¡îŸZc|£x¶žký; À§çio/Û7 é|ŠÇ^¡Vü´Td<2F¯~äú?{>|ÿÕÅYÕTc‚ì øªDÛ)ÎÚåÇ€aÏ¿HwoʆJÞS®áÍÿ‚#{oF9Êö ÄøÔƒ]*aôŒà84@-kH‚ËÝËíÓêÄ6‘]哿Ø=ª¢:tž*j÷>g‹¤6*&v„"ªÑxÁÅRVaÜÚ ´t€4Ú]W\þÇDHn‚lò¦»D4È!ªGX9óKå‰XŠioÌS£½ÂBèõÉ1™ŽSå[š‰—ê#Š¢|žÙg*rn^мž7»ª*Çt,5¿ý>t[ ä‘/®ÖÙi¾¬z"$Œi>Ô¸$j¥\b™o[žŒ‰Ëu:UûÙæ©Ðú-äÑ”pŽ?‘W×€—"Dq Ýç(\Š$ç’ÊŠeqpv å9Ó8fļ‡â>€†’fe…¼«”P½s\‚æi x~ÛœÉ8¯iŽÅ¹på8’ßíg>'ì´x„*dPÐ5 ßÄ Q¥dph5>cüçµßï¦ãzRJ~ì”ïo& ‡),ž˜$ó­)@³9ˆ®ˆé#¿ ªñÑ­ÉÒ`ìá'÷‘Ó8¦ë½K„ëQm¯CiÒ>èÖjÍ[<ƒÑe'òŒZ%~)tNèÒ™<,'wÁVtvå×zbí×puƒ| ÐEÿFîîýæj«(T±Úf¤)SÁ‡´Ðß`¬%Ý•Š·–”~é:áî¹’Ñô|Îýk Sû<ßÚŸ¦ûìW‡åä²zí#òi¦º¢Ïî(‘¿ÎßV0E—#g¯\ðOVf:<|‡–÷‰ë ¹’'(²xû{ަ”­Éç'ãKzjÚþf.wì$‘Š©y–ÓG~" ´×9.–ÍXHÙ¨ ß8(k_­3~®Ýc9²  k´BCšO4ƒúwsU°~ªj5m9h–§ý:jJN]±ÝKÏÃÄ!¢ÓÒú%ÖFëúî…àí´·½.ó†.+}•·ò7ˆùÕ“½ð‰ô“¶Àí4NÌoj?ý-ŸðfŠ)Cš»qh•OÝIýãZ—©rhòô³€âÙˆàk¢º‡zSŽ´ç{ì åxïË Væ ¿ñ’Ù?O|ÀbÍíE5ääA SqŒŠ-Ù-xɼaÈúA6jgó{îÌEuVO›Ìwì –ñ§=(¬d¯)P½Á7M×̤§¿u‰¾êfè_ãÛ‹óa+ UŽL§`ýz#ÿ`JÊ o=«)š€Ã|Ǥ3Õº˜‚·jö€@ •e¥K÷wG'GŠäèÁØA'Ú„Î@ÖÌÀ°øøéGD²n޼~ô_ñ ˜ÛXhÅqš4ôúa¼x3E’æ…û¡Hüšíõ ²Q°úà§-ÏžØBåO¶’NàRä!¨´Ïä,Zæ‚ÆsøºnpŒ{ðZäµ?øÞõS>Q­uúd¨‹?þÐüÑuÞ‡Ùøµ­Š —RŒµÆ¨%E4àÚ7W"…3œÍë¸óß©ñàFÀY·™™YÞÕÁ´ô²áïÔ-«>AƒÉN7K7H¢t>ÑÅ o*¨íÝÝX e\:¡|~¿þ;³ðn´L0 ÁŽõ:.'„wcóêï+?6^uõõIÙCKÁÖ£;÷'r¯Q8äÅH>jô†.ë¼çý£ò# ¤šCëyM|û/ÂxÓ¹¡{ÿ¯/ZÔíX ÜMÓïŠe1µ>¶,š]Nˆ?ÞƒËˇ¸Ù¼ã-—z|ÎÌþÛ¨Ž:½¨ˆ4Ö»ª)hœû yÇjÞ³J*äeWKÐ7; Ñé MÙÏY¡ð‚í [ì˜ËLæœÜ.§Cpœw†’=Æ8—.çéŸATôÅ8$¯^Ò½JkõØU‚€à¨k$`å°·Žé9ØÛ3óK,Ô#í¶W 9?ð)p2‰Rúáýû!yÊ ºn8lBpŸŒE},¸j›Õà àv ž´;èþz8N\ÜœüÃðˆ4ó?¤ï€°Xßœ®]Ê-ŽF¼!°š.”EæR¾8˜Âý5Úðã8W,é,ø¦ó'w_ü—¸ qÜ Áü®»½œÖ8ÆŸna"—cÜ뛿á×~—{~ÅÒ\Î=¦µ £JŒ] 3r_ÿž„`ÌõJ!·¤ªc" {Ÿ0ùçáŠ?h”ªdY$"¿i¥'5Ãö¨a eþ|;(Þ¥šÃ7¼Ô`éü¨a^$H÷Ÿö4 ‚Ï¿£}!Z›»žæ™þãÇ 9Q§ÿÎÎ=Æy— ævôŽM|wÆ“ùv2¸6-`à®B¹FûHu´Úzkuãv€ßaÕ²ÆÕÈÙSÊ9Ç»¯úZKÊA»½·ìXxã.a-qXf¬ŒFøôߣ.Ü„›À¡$êäãÚÎ Ï5NÛ±LêEs`wÍíÍW—¢OsÄ‚@㎛½¡ÞÃ+F†Ù¼Â\“d®äQüÉ7‹ÏÙ¨ÅãÓþd?Üþñ€wÝ­û½æ¤1Ô·Z¶¹Ö„®dt ÿd‡Õë9)j >×.õºvqâ×t.u¼Ç[m¾jµY 8xZä2 ¼ø» ¼­³GÇ&¡›>SˆO] ˆ‡Á¾åHùŒ»Ò§R;U7ª:’ÄÍøH,k¬¡Å˜<ÖðCê^GÐÛD~b¾Ùt˜i\Kj72znxz!…º”‘5KeƒÍXøyü±yG””åp{ÝŸÓ͈Ïùzǽsš2Ǻ’áxËq¼4ºå­ÐXó‹xËU.ij6ƒO>x§Æx‚„±†qFÉ¡™nM&Ó©Üü‘ÛΈۨ-SíµºÈEÄàø·¹Ò–æ5N­WÝpˆm>$ƒÓËÐìë›$îÀ"}ù8¢Ð=eÁƒ”éÑ!lº×¢(Þž'‡¥Œ ­Q :¼]9† ¸ã—âûÿ2¤TPsÖ½G%6æk´ËÔZ@„R„j‚D –£ûÙˆk¨²#áݱùó'Æ<_ •mXþCðÉOPÓfR´@¹!ç\¶|Õó~Ï»úx¸#mI]S,gé.=­„) ¢BEú«ªŸûö–!ÞEº©r]jöëq$ŠáNI¸&ŸÕÕþ(Ÿ‹€ŸEk2!î›ÁBºY. /Êl ü*챂ŒËú Gœ{ìÉ÷?••hLpïõjŒ¬‡z‰ÜLkvÁ8º‹=ÏO÷œÐIA?[=h]6‰ãÁS‹ã¢){cÞ’==¯—ÐíwÝ FÈ]|æÐxØ"ŸŸvì#ÀÖ^1e£PÜM¯_ U¹Ùì¹z¸Mï)§øY!öŒC­Ãœ‡sM;ù*Ú$þvÇmÁ+‰µû]• ¦U¥‡êÀ#w¶3_Mq™õÉ<¾ØÜ—·QJf–ݾw^Í”ž/=‘Jx5ª³%45%š«/ZkÁII½&U®NàÙ>?'zv¶úQP Ý?ÜœÏ6<÷ÆÞUKjâøFR^¯¡XÏß¼jñ=#"l^®œ·ø^XTñ7èZª– /óI ÁYŠ™!“±˜ᑺª#Ò…ò ºl½:Ùéf#Í¥é«Á9I|yñÆÎ ÄR]7ë­";¡óß¶‰‰ÛÔÓŽ›Ô–ç$>Låê<¢ðÉGÍ‘bÌJÌE´:¸ªŸŠõR€d°P¹êÕÿûù#³ÿ;Oí.ðÃ.'Ôîê‹É ƒBYÞëúÛåÅžMt(Fô×UÁ¶9FžµÖúÝd¢Ü~óL@‘ûó¹qc¥–ÃÊR2—Ç\¿½¬<щ¤×©*ÛËmIUÛ9Í)_¹ºÐc8Žý˜€l!ܰ†Ý„´kßÛûõn&—õwç €Ó{ÌòÜM1ÞWömÚ´’øö“TN"áNydÊ£eþYJß÷•÷¾‚MùÍÖ{]WæI)Š‹ílÀ¯ƒsê(ÀÑÄ€Ÿ­K½gT{^Á@È£ýªz-¶Æ“ãt\8ÍJ¯xMMõÆ ôáW5ãOÔi¬^tÙÒ¼ÝR†ª¾CLt–ª<ý–¿Ò£YÉŽñ"Ê`ïÞp6#K>‡¾N›´8ßw´òoÙçPiºîˆ±Pè'¬ üîI–NÀÚ%Ï×Hñ–þáxãŽX T æE¿š¨ðŒôg ›êÿqipš:«àJÑA]¦#É0!¾ŠýTÿ«²Ö5jÙg8‘]ïQÆf2úËžy6úmõä+ÝùÎÈ!V¤î>‹y 'þ"/åc×î–l¹Ëc¶qta\4oý™*йí5Ë9\Ô?Mg #ƒ a“{ö 9dJéç}Î~Øo½ÑèΙÂÒô)N›;` ô9,4M±`蟪óÇ ð%ÉÆéË™nÏPVÅ/ÃûÝ‚ˆLLOn„ÿ­´œ!u{ùOsKuÕíòõH=’i4äFÎJëbE3.-.W¦¶Ó&§VbÔÁ¤­¸«"¼ä÷ Á²AF)éâyñ]µÈ3 ò‰UÏV„ ýbÖ—ð=È0HÂöø4üÿ³¢ 1­Þçüó’3}Q«úQøø|ôMö þtàé×ýKòÚÞ |?N+ôTž¶–ûhÄ(!ÐuðuŽCƹǟÁö £¼G–c¬)íþþêÞ‹–"ÇÎ`q‚'áSÑÞ’ù8i‘Z\nºý}~碣`§KKÊÚîÛm}!1×E³u¼âyµšžÎ› 8ðnÔ<áŽv ¦‘Œ÷i5%|>¢2­FýÀHÕ‹M¥Þ2Ü(~”át3x©ýÛ»úúÔ)TþßW}¶I×™ÅÓ‰~èò85`®Év2Ó¯%>M1=ÍM†ºÄOh_>\Îýp2àXÚ_Öƒ”õ`{WvêÎJz?`ÏQ æAµ]ñ—9À Ãòð`ìûægPˆ#á"LîÆÃ±hSåGŒíSM±ð2,pàÃåýÐîÌFp>Ñ?å‘I] JIé|âükKÜnŠWuc¼5{”V©×‰W=À„RìÆŒEB{z€ó~Å4¼rAŽáv¿þâeT›Ö˜¹6Ðʋ´Ð~¼ÚõîËe,¶rO¢yõ0‘°«_;‘-Ò ç¥š¼T”<Uuɯ+埘¹o> _tŸMöl~%];,šÚN†» ÖªÝùÐö‰@.*¾íf6 Ó1r5wùãž_Âjž¸ùÿÑhoê1>—ÚC 1X%+¼°é<§\º+Rx11Üḹ̦([¼\²Lœ?ß×#O³q3Ù¸Ðþ䛡§µèG’Va´NÔÃÄ?xàÕ/*„LEé°’†~Ô‰‡"_Jwß>ÈÂÜy©vf¿UÖ™Râ:­“Ĩe—øèæcNÈg)”yäýÍ04?ºˆÁ‹«‚לʨ7KS ·_Ìeµ¨ùE{õ0ÍùÏø¼”ÝMàõý,ˆ;¸¥^tö¾ÐÛ8øþêÎõ(Ïô´ /É®)®…ŠðÚ¸v.óØáäô™ÿ^~m®_Œï”DLyV#„òÄê,?d§“–y2—©æèA}á9½µj~YÎáæ‘Â7Óg‹5F&—‹Ç;"Fe§êpl÷ã” „Ê&Ç6¸–¥¶½/X`~ì} ŠÞžÙz„Ü(R ùZÖ—êmIÿ0½ùè·Æµ=áÅfT´~ó£Rå™Tæ¹ýÇ{ÿÚT;ýMF7'²t$쀆ë¾ÛØUÓó”4ÉØ™Ç%*IC¸ÝfäÂå=óiµß^v”‚të¡+µH”š¸éþìÜ Çh2<[Ÿ-ð’¼c€•T`"i$QzO‹JDgÙ1e@ê%Ž%g'zp½šIvk6ÕB’k»A7ø•;oÇß,Ä@çEL9ïžù@Å{Yææ×|9ÎpôE{~‰úH½:å×WýE®¤¨#eº$û‹ž¹Zñ˜*EfRÄ´‰« i=iT8 ÔÃâ¨C[WÎo›Pù{œ›kãûÿ-,#Òö¹¢>¥$¯R}2‡V,1M7MÎ}ÿ“ð·‘fídàßf¶ÉƇn9Ÿº;î)màÇÅà11°‹ªÍÆDš_tL’žð~e£5íæv;±ÊY«pã]‡¥QœÞÂ|³ûUE) ¥éÔÇùWå6U“ƒÙ–Õàpÿ|h­(I®ŠÙÑGPþÃ<ßü_‹kÛïƒIë‘YÁQ7Ë¡¸>„ÉÊeäÝâšHÂ[ù_‹b$º3JGûy8}Hà “ësñŸOϨ34%'œŸ¹n[ÿS.Ð\ R@/uN®Ë‹…e.,ìçúœP)>(#{'ÇõçN'uk;ìÀquÓÖrãö|h@|ð¸ÚÙKˆ)ð#°'¡{<~~Ú"ßÒù¨š ˆÒ3Û¾r_ \¤Çùµ±wöœh?½ÃáoZ»ˆŽjFKP(p”’³±˜6"t âí“˽®*&½ö¦K` o±G€¹—GðoŒ–3}=GéWÇ7“2<8ó¡µãÆ–($¹.ûú6Zràsù«;@ø°MiÓË9D8n ïLg3ŒÃ©RœwJÚý†Í5DPLÞöÂM¿²ÿ#÷Yýj{àØá‡¢&¸û#ÓÙhPrnÔ:Ãôc§¾CÿÍ äNgG…$@Äòýˆ¤Ö¯šîuxCYÞœZÝ¥(i²öØåå™Þ΋u/ûärCO.ŽÄÿ!L=Qí;|CûP {¦kq-ÂÖnÐJøÐ„ƒÉáZg6ƒ´á¹ó: jÒﲉ;í{¶k“^ïƒé°!ß’½¨8'Oè¡Èª $åï-Š£ %–h­ûé*R¾º 2¸Èª±~‹ U?”ªhCý4Ê9?íž9¾üOöW²MŠŠþ;±…“r÷‘³«o)ˇڡHÍ«A7kÞÔR_T„Áæ¯×zo¼_ÌÆ=‚°¼&Šª¤·ÿÏz¼þ;®Q.¦—[ÅçÚò¦Ó~uÉÛ6?È›5‘ Œ3+´äÀ²w•Íï¾³ÚH{ñb.ã§ÿS>3¬w>¬¿ùËÂ!»’7!•[–WÝ¿åD‰ãÐÜ`)¿ƒogŸ\ ©$žÞI‡JKOÙ5\…í½B»Ó}u'$|ms Àþ¾ò¯­‰qÖÚÇj ï´„, mÀý4Ûù…˜ÎгYäWО‹=vÐàýñ‹?—ÎoÎyß°j;[`ƒÿ›W:͵bUŒ”׺¡cÆ„U.ZÐÜ’§=Ü•|ªWúôò¶àŸ_#‰ùÂ&öúõkÅÑc5;;·,+¿âOÒÉ×1mˆ”ðSeÆ?G(èdXy'ѧÚòÞ‹orO‰°ãJþJÄ^CWÑ çÞ´Ÿu]&@DCTQ]€—(!nÿì¨ÈÐ>eçoüŽl'÷ºØ)[ÜÆ™ /RçM*ÂÿEMŒ7=Ó:.C@äµÓZrQèB,°…K.7kwû5_s¢uœÓ˜,>X”šLÿjÞ‹üܽ~Æ=Fȳ¾8±Ý0Òî¾mÊšEì´,[â»)yÕäÏ‰ŠƒaRa«¿æ¿Ù%@üÜ6D·[ïòã æùácOßBÊóZ9¢GbêEŽO}‘÷¯`F¯O!lI„³ïW:ÞÐÍiF“£“÷Vоó«äÆÙ–˜ž2ÅáKR»ÔnçdU( %›OVÈ;B8r‡J¢ç ½Éô/¨>ŤöѨA•~ñªQú:Ù.î¹Sæ±2fÍìJW°adzä´ÛþH(·Þÿº-¶™/7Õƒ¢U~™±'¿]h½‰ ¸ÚÙf'ùÞœ²LîÛN`@9èñýÒéÀ &¡Ñ-öry6›¨¡4—¯òä í´…Z«üõÇ2ZÚÇu:í)Çð0ó@·Å '‹ œÐmy‹W‡ª^Ë<4<,^^šºj ó¯ÙÛŽã¶À‘y á}5åÞÕ4.žÉ·[Ëç¶÷/ªï‹yøè=yþ*‹xÏÖ?ÃÀÿHêŒ7VôK¥¢¢˜Ê²‡!ìçßlê`=©Í~r¢Ê¢$Í÷üÏ›DÙ!˜´Ï@0*.I/½Ç'ºá|°qžo]Ç6v×Öœyßo¯)”ì¿æä^&…PÓbéŠfG0gþ)WÖ,öQi•´%ß]­Ì554{Ùu̇ð fß«?$&Z%0 CSŸ'»TíðhËW¿kw&$œZjîƒ==|;QÜÝFÿ3j„Ã'ap®½ÜYå_TÔjº¦ ´D3>}±²åU1C›cÈ’£õq/Z¯Ežü•àRµö;¬•Ì­ö%ÙØ~I+¹õßY/|·,3Wýñ¤D¤þ÷Xž˜Læ¹ÍÄÏCûólª€Æãƒ"oKKI~7€ÊW¡w™\¸¤|cž„÷sÃ`§~^Tå¬<ÿ#fÜT²:[ïKYNAê5øž;çûÌíÕ‡‡X­ÃGËXÆšàÔð¬s&‡j›<…ã¯`hOä{¡]ÆjiÑ¢œ¡9[í&Ñ ‘Yéªç¤¨;t¸¶(q9~íu’I©Ï?NŸc]·¶XíGìÖŽt¼ëí2hßrêÔ˜Ô|‚^«ŠyŠz\^r(•ì«YÅ–­ºüt:j}ÆÅçþ1gX…´ôÒ³ûy¤š+EÇx“@}ùN>' d«¾›¡è•Y½nr0u|%Õ”´îøŠrÇm»müÓê—í`áú½ÅñªSºíw|zAöyשD(;{eÞ®mcÃN]3‹Íˆ'Éçãâ/>)rŸ¦ìz(cœú‚E¿ÉçËÀ›Áøk)'Ó.ï‚Äæòªc½^‚»?äTäÀ¥“œ4ÉçèkÀ=ø‚4ôÂæ…ŠXðYOÆÆ¿ÛL`¨ø'Ûd”#ÖóO¿ŸªuP‰rà½å k¦®³vß[Ü䩌Wt—¬PáÖTØ3á (‰1U„æPíÙ£nÿQ*eñ>þÆ+{éY_7’ù¬ê)o!ˆD±€8ªñÏЄ…ÿï~b”Sû¤¼XB YrXÑŠÅ2^>.ͱú;Ž‚_¤¾»v?Û³¡ 70¢…]÷£¹Šy#>°)W^<—¤¤e{W‘ÆyiìÍúC›oìI»}3– f÷ؘËIú¤ùýuw–0ji+Fc|Y€…c)m·ƒÀÒùsq«7„ª³X¼=¶"q뇉wµé‹B÷…× Lõ W-†eï øØ>÷t9M@%9!|& 6öOŸÐ¨Ï{¤Åÿi‚ËuXÛyú}3*¬Üuü;oÌ—jæW³›:€‘ê~§¥cBçüWE²ž0ï¹ÎoC°é åê·ÏÖ l[/†ùJ¶´Íè£ÉØ ËNo=Ÿdu ›ÒŒ‡öcë—‰ÁþU›ÏJÄñ•“ÓÓ&˜/©Å£ý¥k£<íS’§þ{'2½ýô•Õs&šcç„ ÒEÇÃCBXP:’L¹˜Úc]´Ù&TpÂ@Ý€)[£R3³<Âæú.qzÌUZŽÌ÷Gâ”l&”.0B£­Ô°O‹[sÞ¼~AuQõïn•.Ýè@løBHÒØJÐÉ 9¡œÝTO=ò|a??§òLO“…pãp½ÎZ%u„ù{<Æõ»‡T%UA¨«§æ©àv…¥Ø½€ËÃí¯—€Æ½/ZvWml¦C 7îĶü |q_ÓZÆþ¬¸ÃbV>î3wLÇ1ÎoGS9±;wÚ=ñ†À‰âÕ‹-U§®y¸d*ZÓô—¤Ê yŽ~S”÷ãYC>¿±MÂyÜÂ,Î]zŒ8éðøÂ¹Sô¹‚QâIqâxqÀ_š#Åž'S‹cãóuÁ%ŽQûâì¾Â œºh9¾Iðûö­AVuM0=8¨þƒ3ó­pßÈ ‡éRÊ]{ê.Á z¨\^‰–5íï¤vð‹ÇMÕ ¾åp‰×²îf$½P¿P2A¿ûÂm?aFšÓ1êoÍX!½ñFL7M•dL.\²òZŒåóBèA¦Óe“cÍSçÿ ]±øîÔfœÄ#>U¸™Ò{ŒðS± V*»50S“*×R¿ ¡ŽG,>¹óïšhÀšY4¢téUáÇu#ÔœéÈú!yyÎQY)iÓlf’OhSXw噣Ë*t;EE5ÌUVŠ=™ / µ8žß&øãJ£/é1“í.g#À3ÏŸ‰}o=FX—Sx=r…®öòFÐz†×lgŽð|¡K› žUÖ¹¬Ñ¨©ØGq¡"R=K™ä#,ÛcÓg”:Œ iyÔ±)êñ@¯©AE–K9Â/ivô7·³|ŸŸ£†ß?tãaA´—¼ªÝSÞ¾ä°EaÀr¦Ó|\ž÷-PòÚ„ž „gú7Þ 5ïrNƒ.&2ïýô…Í«Ÿ¤\Óõçù’ýo»šév¯&MrB–(óiž›_±§¯òâ-ÃTäFsæê~Ãs6}¯èMïçõÍMÇÕÿN_ײ‰¦'šßÏb‚@‹ó«’±•GðΛAì¤C³¦Îòªœ:án¼ c5V–éÀc(ØŒ´8mÎNøŠØ'ËåÇw~¶Š²X£”p==b;³¼¸*~ƒÝ~ºÄÅ5äcñ|ðí¿(h,•B|'à'i~¼’²T‡7(ÖmSDQìG¨/ý}çùJÎ73}¹'ÛB ÁÕ,Ó‹7ó{¶•Áà›õQ®ÞipO@&£ÊÜkjK]Ü4Š|¶Ý¬·ìXy\JL>BG_=•Õ¢Õ„öNq$s[¬“Tsè{ç —1ŽØ¤Èe\Æwq;âùÉŒ·ÛmŸéó€_•ù¿ÐH’ÞÙ¤±FF²KE¬~Þ·¡²Iœ'ÄשG“Ñ鮚À–‹I¨oæÚ93à6ÛTdãxá«“Z¤«ïí:—Pw ¡˜ß8ÔÍøNvœn>Ù_€+ª,zw<53Ç»¯EêƒÔL¢áÚòM,ÈŠWxò×F!&Ú­ÿQ¸¯Í5Ü«¡¸Ûm yÊv¿Xs†¡ZË®âQ^Q²p`L?ù’HbƒZ­d-ìÚý:ÿY7$ç|‡#‰‚X<}Ï;R)ZsÌOæún¢ 7õ-ؼùèÿ™×§KGûJ6<ë\ô-ëúq—¯Ö›Ò.í¹cõåuuø¯§³•—_þ™\±cß•/6Žuç¿O–»ßîP[\ò1øÛêóæO?üî0g¶„W¿ Qÿík®§i½óbmÌÝÐÙRy÷þýœ°ìõ–ÿ¥oó÷¯5Kp¾´šeÏ+çEÿ'Ÿõ.Iž´ãéç›o’_–Ö©I¯—ß±kò'– ÷V2ý•²ŠKðúo¶6~ëí×_wdþùn|GñîR¾k£ü˜‹W׳ÄÊ~Ë|³MJ%FüJïý6¯§¯6ÞqùZ|!ùâæuÓ‚{}«ö)*¦¾=Rìå}=qûî:©)™Íkök^Þ|Þ.›}nÉÏgɧç èášõøFÀ]OÉæ7¤ÊýÏ?ýµG¥øÛyÕ%µ¥zQ¬¼gÖšeõ®w_çx¨ô ßõº3½N¯?]réoUxõ|Áq¦ðÓ;Ërö½4üS–´_îúŽ*›œweWLaœ¼øVéÅ ñë›;¬“^0§Ý2£/Ù¹4ÝÆzË«Ûé¯?OÒ®“Ýê¸øGðîÆWåþ^pæ\»v×¹ÞïÏnHn`4ï›ûËrÇ,ƒyÓ˜Ë)Øg~í/Øþ[\!Töìê¼:ã—“%ͶN=έu/ànç^ûy²·b#®~­4z¹â#sþË®º½R"åz÷”¦Z­ò“Ö»(³=¥ðΓºÌ—×Ôí®ø·Ž_ËÙª$}QÛÎs3»36-x­è´„›¢³/>ügÜÐð±ü¬Ô= ðtõsYç”ÐPK¶CR°rC DPK ŸO7'Configurations2/accelerator/current.xmlPKPK ŸO7Configurations2/progressbar/PK ŸO7Configurations2/floater/PK ŸO7Configurations2/popupmenu/PK ŸO7Configurations2/menubar/PK ŸO7Configurations2/toolbar/PK ŸO7Configurations2/images/Bitmaps/PK ŸO7Configurations2/statusbar/PK ŸO7 settings.xmlÍZÛrâ8}߯Hñº•Á@ÈT”¹îc›l p"$¯$cÈ×oÛ@v’ÀLÖàªÍC(,©»uÔ—Ó2w?6+zµ&BzœÝgrß´Ìa.Ç[Üg¬±qý=ó£òÇŸÏ=—”1wƒaêZ¥`м‚åL–wÃ÷™@°2GÒ“e†VD–•[æ>a‡eåŸg—ce»'ê±—ûÌR)¿œÍ†aø-,|ãb‘Í•J¥l:Ü’ ~‘\¨\ÅÅq±¹Ü_ £Yš„Wlx  <ü9:O ïþø¨/_¯H»@ êÛ)MHj€|" ÁW&QÁG'N–ÐÞkÑñÚþ|¶LÈghˆ÷ö¥’ñcù#1ò1^Ìþ1‚ˆ¼ˆñ§ë‰Á…ãaLGÑ:»ºt Ì€û‰úBX2Lj<ˆôŸj™ bóé^jö÷ë«dá±°‹Ä ÿrý¹Ùä·Ç Üò1RÇøË!™žáÆ5†ršVq4M!InoªCà1•ܰõg6×Óˆ½É¹ÛÜ5Kš³Í™ÝW=Ôÿ‡ÃÜdh½úcÜ¢O»Êj.׸ù]YÏݰû~ª­ë]½6ß«º¾4á³áŸ¹*y£¦¡=™ú¦Æª[dµÙô¡dFE§5yíLªÜ)ŒÖÉÃk·®·Â£?ƒ9OÓ‘ïäoJV³´Å­Ç%šÛOùRˆìÉë`Üh;¶±åi0kãiOsìI€ëZØ©ë²[ ÃÚª·v`í¬9 qsQê>Ûn«'gÓu`ÞOãyd÷è`¬·-£ÚæKnNnb›‡þðÉÆÔÊÓÛÙØ¯öô*àQ­;ùÍÚ¥ÕíÌîùnž®g¿6ô ÜÖD³`×»¦Ù·íÖ°mH4û/“g'_\;Óp‡ö(ÞÃ|ÂÝé²\6¡ºÑÓÜF¯aÚÅ`6}4Ÿì‘gqkåsK§ÆkaLLZ4„5;ŸÒz=Û’€üý}Bò±`\ÈüRg¸J{‘¢£üPCÔ h\ÑÓ*8•¯¶)UÌ·úRã+_uÞ§9aBê½CÏð„Td™z`½`å8^¸]æŒØÒ˜¬|8ŸËt€GNÇ„ PòÈ4P²ÆN‡!Ú!ÿ«ä.:à¦\?æ1¿©šFiÐ}Ÿn-ID)tyñû…à :på6ùHLÞU /ЭÉdw#Õg5ÊeŽE¡ÒÅwn{y`¢]4)w­ïoë"z‘Å×ã*Ή§¹KÂ\Òá 8£ŸŽö'A=_—oYQg.XK°-`ª0è6nÒÀÍðÅiº@-Î= ¼(¢O“ÂMÎd2“.¨æª ­*¨SoÁ -™Šû.½_©IPœ÷FÖïå‹X-Hw¹>ŠqÅÓ´)Pí êXXŒ5«Úy¤Ö©d‘¸þ^_O¦åCqwÚ`9†¡8˰ÕPòà±à½Ñ xÌ)wÔVWu©¨÷,Ϋ»dLé·BÞ$›HrL|¦ñä› nã^nb£ ÂpÝ``p‰Kj‹³F<Œw$ÿk‘áèuØz›ì†@›(ù8¬<õsÃgá½9êtŸÂáŸÆg J¡Áqê‚T)„ûÎÉí®,\0Æ dtÆc®ôÎ'?> )~"gû0ìœÉ×zŒòU³Ÿé|9²°#§{åÏM—³JºR—ŽÿŘ÷aFæ±çžžæ…üÕr—ŸPKÝrèT­PK ŸO7^Æ2 ''mimetypePK ŸO7P݃«õ® Mcontent.xmlPK ŸO7XsØî 1layout-cachePK ŸO7)Ãø© l/ }styles.xmlPK ŸO7AøÄ#îº^!meta.xmlPK ŸO7¶CR°rC D‚#Thumbnails/thumbnail.pngPK ŸO7':gConfigurations2/accelerator/current.xmlPK ŸO7‘gConfigurations2/progressbar/PK ŸO7ËgConfigurations2/floater/PK ŸO7hConfigurations2/popupmenu/PK ŸO79hConfigurations2/menubar/PK ŸO7ohConfigurations2/toolbar/PK ŸO7¥hConfigurations2/images/Bitmaps/PK ŸO7âhConfigurations2/statusbar/PK ŸO7Õû„ù! isettings.xmlPK ŸO7ÝrèT­ØoMETA-INF/manifest.xmlPK(oqpercona-galera-3-3.8-3390/gcs/doc/GCS_Architecture.png000066400000000000000000001024061244131713600221520ustar00rootroot00000000000000‰PNG  IHDR´ˆäþ[bKGDÿÿÿ ½§“ pHYsaa¨?§itIME×  ºL  IDATxÚìÝwTYð7HoR”ª" ˆ¨X@A°®ì°b]ÁÎÚ×Þu]»®‚{Ãöµ  Rm ( ‚tPé=ßãfó…„žßñxÈdrgîdîÌ3wJXl6›þ%E€p€p€põLppðܹsUUU9Clllºw”Vw– OeK× Ä"¨œ‚‚‚Ç{zz¾}û¶¸¸ØÜÜ|îܹ–––l6{Ô¨QÑÑÑÜã—””HHT5އ……™ššÖä³Ëª£"<µÉ’©ŽÊ–®;Â7xðବ¬íÛ·÷ïß_FFæÝ»w'NdFxóæ²²2÷Güüüª>Ý“'OÖpM«£"<µÉ’©ŽÊ–®;@ÁÂã“*Ñgеk×øøøÐÐPmmmî·Ž?>}út6›Íf³™£a6±ÏŸ?·oß>77·&›­È+R+µ¨\e«ãK¨pÍ@…=z444tñâÅ<É€ˆÆ÷3w³XÜÃçÍ›§¦¦Æ=0((è—_~‘““ÓÕÕݳgϘ999óæÍkܸ±Á‹/ˆhÈ!¹¹¹Lá’’ü»ýbbb†®¬¬,//oiiÉ|0$$ÄÕÕµiÓ¦ÉÉÉcÆŒQPP055õòòb>Rö»ÂTäëׯ'NTSSSPP>|x||¼ 9)] ¾ÆÅÅ;VYYYYYyĈŸ?.wáðÅwÆÊ˜7žÊò¼$¢ØØØ~ýúÉÊÊÚÛÛ”@L° ‚¬­­‰èÝ»weÆÝÄš5kÆÓâÂÃÜœ233W¯^MD§OŸæsûö퉉‰çÏŸ'¢öíÛ—.“/333"úðáÃÍ›7‰ÈØØ˜Ífkjj2ܰaCjjjHHkîÞ½[î»åV$11±Y³f666±±±qqq]ºt4'˜––¦§§7hР´´´/^¨¨¨hjjÆÅÅ•»pxš1áç­ô˾}û^¸p!777((ˆ)ÍÄÖl€ STT$"¦c\ÈpðýûwžÝÌøñã™Cd6›‘‘ADÌ®‹ù›ˆòòòØlv~~>5jÔHÈpбcÇV­Z±Ù좢""’””d³Ùéééœ"ÌhÇŽ#¢¾}û–ûn¹qvv&¢ÀÀ@æåþýûŒŒ͉0.[¶Œé$`^þñÇD4mÚ´rA3&ü¼•~)--ýüùsæïׯ_#Âü·‡ ¢üü|áÃAII Ïn¦ô) 999¾cr¿²ÃïÞ½{666œ‘K—GDÊÊÊå¾[nEtttˆ¨°°P˜9¦@ÎîŸéb!"MMÍr²gL˜y+ýÒÐÐPZZzæÌ™oß¾EC„ø±±1ýóÏ?‡ƒÒ/™‹rrr*ôÁrÃAVVÖ¨Q£ÔÔÔ®]»VÆ ‰HFF¦ïò­HZZšsRn5âyyyÜ÷‡A3V•y»sçNÓ¦M™#FŒà[8€À‰6lØ0æ”|U iܸ1={öL´ó¶téÒ«W¯^¸paĈeŒ–™™ID-[¶¬Ä»<˜g=|ø°rsRš††EEEý¼jZB‚ˆ +º(ÍXUæÍÖÖöŸþ9tèP»ví®_¿Î¹þ$4tIIIMš4Ñ××/}àèååÕ³gOö¿'³‰¨¸¸¸ôK6›=räH"jÕªUhh(›Íö÷÷ïÕ«稈JJJ¸;Ò™–Ûl™ë!˜S¥{83ÌÜŒ°lÙ²rß-·"öööLE"##Ùl¶ŸŸ_ç΢ž—¥ œ9s&sÉ!ó2,,ŒˆV­ZUîÂá!hÆÊ˜·r+KD~~~ÌßgΜ‘••EsœV€Ÿ|}}UTTŒ/_¾üíÛ·’’’œœœ'Ož4kÖŒ¹’îåË—Ì~åÕ«WÜ/˜BBBdee9·ÌÉÊÊúûû3%3™ÐÀ\õÆù sËßýû÷™RšžžÓ«qáÂæF;oooÎ.ÐÅÅåÛ·o‘‘‘&&&-Z´à¤2Þ-·"oÞ¼‘““c***ª««_ºt©Œ9á©Eé™; ÔÕÕýüü222ìíí[¶lùíÛ·rA3VƼ ª,ó’YP¾¾¾ùùù×®]cò°9û° IIIÉÊʶhÑb̘1ÌžýÿÏÌ)ý’ñüùsKKKiiéŽ;þý÷ßÂ|p×®] ]ºt‰‰‰á;WgΜQTT477÷î]Ïž=õôô¨R8@2›mûÌÑ~Ø¢’ëw5Ì @ÃjÚ•j}ÕÚôþÛÚ`¯Q#)¡Šù òáÉ™ ¢É)¡^äƒJ†$d¤„ºŸ¨R— T8à~„ú  Î¦ìVª)P¥.A¨X8@‡b@u¤D„:E‹@¼“bÔ¯ˆ€|Pýí<¨@8@·’ÿ Uö®„Jˆ¬ öù .äôˆg,¨ÉýèϼÏÙ£¯[W¥âx>þïKÄä¨1è0eD "çu¢H ÈÈȵ×y l8À9$ƒJ¦„ Ed@>@ψwÛ¶#™ê]8@·º DÖ‘À ù NêôÂø%‘ßb Û ,¨ÞFŠFWÙç|Øû î,„Ùïã´BÃí3`³Ý±èþ¿ÎXPÐèÐâê ,¨Ë˜“ XPx " @Â΄¨tÂ4Dè<@8¡ Û áBç @Eàœ Â ‚káá žÄ"€ÚÅb93°ÙîeŒ–’’9cÆé“'§¨ªÊOštÜÕµ¯¹¹–^¹Â¾¾ºt4&僄D#ËVû´s\wÑžçñYï¾<¿r2:彬”‚Ép ƒþ›®N`ÆÉÊû~áÅŽ·_|Y,‰î&#º ^Ù±ì§oåo¸2nÍèsR’2ÜÃ[p}érR Í›´¶íàÔ¶¹5÷[D„§{Õhqµ‰ÉœˆÀWZZö°a÷ìqPU•'¢;íG:´g£…¶VeyþñÆëÏwí­\uÕZåäg¾ùòì€Ïžqî…žŠHk³DGÕðGNj`Ôƒ]·gqÞ=òpE»æÖz¬(,Îîµñêør'ý·œ”‚ïG¯>m¸‡»ýúêKÚÇ-W'ý9鞢L㌼ôèÇG®œÜ{-ç­#Oµhb‚/®Ö¡ÅN+@=0}ºÇºuC,-õ™—J/Îtv>“…#ðÈ/#îùG¯¹v{ôššJ6’V–Wïn2b´åÿ…ƒ˜Ô°èdzmw5S7–h¤ª¨ÙÏlÂüû8#|J émj/+%¯$«j×qÊο–;]ÿˆÛv¦~I /*)äÎbIè5iCDÊrjTä›ö6µŸÔkõõ×9oé55e±°QB‹„¨·X,çøøï66Û%$\¬­ÿà~ëÆÐ1c܇ýëÂ…îñ¯_qt<2dÈ‹+ÐoìçUPPlkÛ–{ ŽŽŠƒƒÅ_=Æ!Èý7g˜M’”âÈs\þðí¹þ&IüÿþX_£]#‰Ÿ}ŠZö¾êQ\Rļ´n=¬ì‰þÈIý'ù]ûÝ;êõzññf¹3Ù¾¹Mò/ø²ª£ÅÑ¥K[ddæ°XÎ&&kˆÈÒrkPÐ <(è‹•Õ6´8@8QZ¼øòæÍ#Š‹½x±Œ3ðÔ)w÷§»w;xxL¹x1ÀÃÃóÖ“'û÷=qbòñã/îßr*—.Þ¡ôðáÃ;ðl Û»/Ï´;ó l¢¬Ë}Fÿc|€¡&Ÿe{p†?óÇä^kÓ2Ö\õ,ìjQI¡ª‚FÙ¼Œôn¯×Cª‘´™^€Ï÷JJŠËžÉèÔêJ:ø²ª£Åyxø­^íµk—}fæ^6Û=<|Í›÷˾}8ŸÝ»÷á¼y}ÐâáDiÒ$«Þ½Y¬ÿ{”é–-ÞGŽLjÞ\UMMáС Û·ßå¼µ{·ƒ††RÓ¦J{ö8œ<ùBÈ©„…%èë7)=ÜÀ É‡ øù–$'­È=Äù°÷?"ÊÈIU”U)£)I™É½×θ/.-rÓåñŸï•=QÿHï.†ˆˆÅ’hÛ¬ÛËO>¥Ç Žþ›ˆò s>ß;|™]‡Éø²ª£ÅmÞì}æÌôž=¤¥ÿ»¶ÌÁÁüñ㈔”L"JIÉ|ú4ÒÁÁ-JÉPy¶+=ðóç]Ýÿk$%ùÐV­4’“3«8õ’6 OXLNFé[V"÷qù¡__Ť|Øv}ʲ'ô›¶%"Y•¼‚,y岋ÒRi9®û²œ‚̯•`5êlЗïh±©¿e'›6³b^v7±ëö,+£A<—yð{qI‘¤„”–ªþ(ËùÝŒ‡à˪ŽÖ¡C3ž‘¥¥%§Lévøð³•+¹»?›2ÅZJªZ @µÓÑQyñb™®nYÇ£?&êé© Y ©©öçÏ)¥‡GE¥¶m‹iZiu ˆz`ÛÁ‰3D‚%¡¯ÑŽˆ 4Ú3CÚ·è“ÞF·« Bœ[ü1ÑGE¾)ÉK+·Y¶Íkª pàq+'?cöQ+îQ˜¾Î9 ¨Ö§§§þêU´!ïwêÜÓÆfûÂ…ýÎ}z-¸á´ˆ˜«kß1cÜcŠ‹KxÞZ´èRjjVbb†«ëÅ™3{ Y ½½ù¡¥‡{y…8:Z` bkæä|,.-¢Œq†˜ÿêvMlîO?\Ùë=—ó2ðó}Îß2RryY|‹*.)zõùî:û‹î38ÿ68\¹|‚§|¨™·|¹Ý„ Çîß+((⮭ݸ[7ƒI“Ž[[ji)£Åz &üö[?99é‰ú”\TT¢­Ý8>~;ó–¥¥þÌ™gŠ‹K.ì×µkKž2:(ý($++YY)ŸwÜ}ª ?®\ ~òd‘¨f›ç9<Œzý4C­CÍÿ¼ù«]Ç)] mÕµr ²>%†p£®¨mi4ðàÝEÃ-\´U 2sÓŸ…_vuÙðãœq®½: !!iÙÊNBBòVÐÑ.†¶¥§UP”w+ðp'ý>|H(((ân‰óçÿbeµíåËßùX3-ê8›]~¨g±XîÈþu‹³«*».çÃe?‘Pô«˹ÒSLOÏ<øÀÎc¬­ ‰(99sôh·Ý»DõHËÙ}fß|ÀW= ŸC¼ñüœš•ÿCVJA¯i›ÖÃyúùCcžzûšþ©‘„¤i3«Ñ– šü»w>l±ÁñêóðëO®‘…AGëÅÒ’²ÂÂAÝD”’’9}ú)©ªªò'ÿí7Q>Ì•³©&àá¾ öá ÆZÂA 8­õCÓ¦J7nÌaþ>sfZ5M¥ìþÄ@‹ƒ$B ©/ÇL‚’ 4\|s€ðW$ 4 |€ˆÈ¼#"ÂòÁÏ¿áxÏ/ "Ô.ÜLjpPó" €ÀЀˆP—öLlìŠ@Ø]Î, "4$¸Uáá@·Â½ïÁ™DQ“Ä"h°X,g,„ŽÄõëŽÌø%h4:@·A]\WÙl¶+4 ßJn6¬zºi°;HžžD¨¹]l½ÝV`7$ªý…0û}œV‹CRœ\¨‡½8Ñ€dPg! "4”],’  "@ýŽH€|€ˆ€ˆ€d€pˆ€$„¨™ÎìQêoP@2@8€jÉ8¿€ˆPO»  Ú»° áÊß#@ðøäêíó¡tD <€Ä"ðI$„¨é|€½"b Àÿå"b"v$ˆT~g±áêPD@J@D€w\þï*ÁyY‹ç8“F,¨Ë𫌠{ÃñoJ¨á£¨­Í¾0û}ô •Ö~:ÁÆ¢ú–- ÅA%àVFq |Ü›~g ú‡á !Š ~Æ.)AD„ "úúéí.ç>)_£x†#"Â@uçä¶Ž}Fj4oÅ÷]D¨(\P¿¥ÅGÜ¿¸ü¤Ù£ñ<ë¦zÄÖ½Ó¶6ï­×Æ<)æãçÐç…ù¹eGô"zÄYfzòó'\¶_q_:æÝ Ÿ&:ú?ÒÇ.Ù×Õn|IM­É‘#—‰híÚêêMÏœñæ.yÍ×£G¯ÄdzÝÜ.¸¸82¹ Ù¿ë³gáDÏž;w¹«ë”OŸÂ9wqqts»Àýñ… §}úþè‘Ï™3Þnnç9erc>W|çÎõË—O‘¿ÿ··øú~TA!Gà S§°ØìòûY,º ¡: SºV\ÚµÐb€£~;Ë{§þôõ:¶þÒ–„Àã澆§^•ýc <±@ì¿Sg VÙOdÎ÷¿2l˜ÍíÛ/MLþ[zææÍ☿åää?Îîڵ僡ÊÊ9ãôïßéàÁ³FFm‚ƒ_­[·ÐËË·ì QéB8oåååÈsf˜ûZæïüü<}}9¾#”.-#㻉‰*ów颸VPÈÑÊ^žØPˆjÕf¿kû…»˜?˜g,ò$ƒ¼œLÏ-.ŸCŸ«iëµï>¸«Ýx澆²¬×"ðÕ¶mÇY³/]êìåå˹³499g×›˜øU^^{ȤIΧN¹mܸ×ÓóÈøñÓyŠe®p乎¡t!²²reϧŒŒ¬ð•RVV){„Ò¬ÊhP+pZ ábž±È3ðöÑÌ} Cg®û‘š°eR—ÔøhãÎ½Š <6L[b«ýçôîKít˜g2QRÌÇ[‡×s"N4ðX°`UNNö™3‡9CÔÔšðŒ£®Þ4--™{ȨQ||®¥¤$=|è=t¨ÏøœóÜ;×Ò…T“’ï-­°°€o+7 @]ñ%,¹¯¡µE‡…»õÛvíj7^EC—óc ;î'ÏÞéåå¶úÙµ#YßSïzl äéEhàé-OLüJDRRR{öœØ¶m¥§ç‘´´"4h”›ÛÎÜÜœˆˆãÆÙÑ A£/_>]\\ñÁÚº)**õí;è×_Çôï?DP@^^®¯ïC"ÊÍÍá[ˆ¤¤dzzjPÐKfNâãc™JII1—úø\“’’"¢ØØh"JJŠ'¢¤¤N¸1Ÿ*,,X´hÏÀŒŒ'N "KK¾r4@8€:Šï} Ù?ÒøüXC ãÎ}^Ü:ÙÚ¢w E… <"˜›7'¢ÎÞÐØ®]§©Sç,Y2³}{/¯\ùÇ«W¾&&*Ӧܰa­X±5 ÀÏÈHiî܉ ®e>åääòê•ïøñ3J—ïævÁÅeìÀ]dddŒÚìØ±–o!ÇíÛ×L]½)3'-¸>Ãbz ˆÈÒRŸˆ:uÒ%¢Nt8U(5QGsóæC‡Úó̉ƒCß>}ì Œÿüó0•® £AÝ ¡6áÌtÝäwËãÕ³ù9Y ÑaF{ÌÞåòøúéM¿î¸ŸÌóHæ‹;]Ã^>(..’Sl½éW"ÊËÉ||ù`ï1³Ÿ\>4nÙ_*ºD¤×ƼµEŸ·¾·™¤~Ú7Ï®ô¹œh@ψ cóÞ‹?aþ~zÅ]I¥©¬‚²BcuS«œq2Òýûƒ„wOýù1ðñ¶©ÝXÄêØgäÀ©¿7’”B/ˆ§äØHÛ)ËØìy%α!Ñï_M^sœI ~7ONY{¢µEŸØ!§7ýZT˜?böæÒ½õ%"p~zဉ+܉('ã›ç—7NX›š‘:¯’F IDAT–xríd‹cµ L‰èÁÙ=:­Úu±GDm­íºÚ~÷JPiu?"ÔÓ. g DOM[oâJw"ÊÍúñäò!»ÉË8c~xyŸy‚Bzâ—§WÜ‚ÿ¾†kÐsâI¿åÚ‹ï“¿DHJ˪kë1Ÿ\>ÔX]«SŸQÌËð×¢ÞÏÝ}33=yãøŽí¬Š‹‹În›=iÕ³Cê]/B=ê6ÀB„¨,KS¯5÷äØO¶S–±$~vUÞ9¹ÍràD Ý࿯äÏÙsSB¢ÑûwÜ—Ùx-’y 3"BõE,7(N+@µsZ}ÔfØ4æïØÁá¯ÚN^JD†fÝdäÎlv.*ÈokmçzðßdÀp¢áÄM\ä›®vã5õZçeg(«k-9ú쟷þL³Îü–bÐÞJ˜*×a€…PGu2yÚ†Óù9YÛ§wÏHKÔÔkýû©W’RÒ^‡VU¨D@8±"-§ÐҴ˶)VÁ®æeg4’”bQeöXˆH€pb‚Åb9­96zÁŸ÷=w­ÕZ¢‘ä™k+]"‚h%D}ØêÔu–¥ÔüžJõ:”`5¨| e³ÙÂ4c\Ý Õ×t±vAõí°v ÚG–±dþ˜Ú­×˜Y]íÆK4’¬•Å—^öòf¿[@¬à¦Çª=ýüÎj°Ö¥† §@<#N4T:Läçdq–XQA¾ç—½/èÕØs‹KQA>3NàƒK«GͶúù«Zì’’nk–Øjϵ–;¸pxvF:O.a³ÙÞÇ61#ì™ÝVWIÎäüny¬wh7ÛJz½C»è÷üª½z¤Ñ\k¹ÙVÒ›Æwúúœ¸g΀ß~Q›m%½Ëå—×wÏ1SäÌ<÷ ªß©G½õß:Ùr¶•ôâþ'ÖNn€«N+@íÓ`킚húª‚Üì cÍæZË_ãd`Ö¾gv?×Þ*•«#6"dëä®smä/ïY<}óÙø½ã‚D¨M¸ êÔªÈÐâªONæ÷µ£Mþ¼—ˆ¯VÖaöûè9àÝ_¢¡:<½âV˜Ÿ›Ÿ›}ûèÆx‰_ý‚pð_DÀ‰†êãï}Ƶê’šé 1£]ÿÄ©Ëp·ÀÿuàŽ†j²ô˜o L¿­€pP½YA„¡îtBÔ…9ÁþለÍv¯Ýê°XÎug6 .Ã5åO‹Íµl¶{­'@8«^\®X/¾&,„D„D„D¾„QîéëTDØ´É[FfÎùó¯k¦úsæœSP˜ôk ÔÑ^„U«­_?´wïÖDÔ½ûv‘̤½½ûË—ÿð}믿ÆíÜiß®ÏpQMê‘î‹6"DD$ii)‘¯ïÒªÏ[rræ§O)z‚FøçŸTiiއ߈dÒ€p€^„ÊG„§O#-,¶¨¨¸Þ¸*##£¬¼€Årþð!ˆ.¼$)9‹ó¡ÀÀYÙ9ïßÇ{xø©ªþvê”?§œ«Wƒ Wš˜¬9uÊ_Ccñúõ·tu—†„ÄJJÎ"¢ïßs&L8&/?wРýÌøyÙÙùl6{Õ*¯Æ<{É=é+®+*ÎÏÉ)(**qu½¨¤4ßÏ/Šˆ’’2ìíÝ•”æ³XÎÌ¿øøïµ¾ð±"Ôˆ Œóç_Ï{ÎÍm§O›V¯¾Ñ½{+ss½ÆuèÐÌÔT›ˆÜÜž$%íà<ÈÈÜ\ïøñÉ7o¾QWWxòdÑŽ÷˜áGú®Zåuîܯϟ/;zÔwРvk×™3§ÏÎöl¶{AAÑÀûûö5IIÙ•Â|ÄÇç™Y³?ÿ¼×³§ÑÌ™=ed¤¸'½eË)ÒÒ’..gììÚöíkÒºµ&9:16ÖüúuûÛ·kee¥Ølw|õ šˆž¸|ùµ;wæ[Xè5i¢Èf³{õ2&¢+W‚&L°dÆ<¸ý³g‘ÜŸºyóMZZö!f††M¿|I'¢ÈÈäõëo=xàÚµkKuu…¬¬¼¡C͈èîÝ÷}ûšÑÞ½,-õ§M³QP ßÀ)çÇÜnÝ  0 ˆŽ‰Iã™ôÓ§‘³gŸ6ͦsçwî¼/**!¢€€˜±c»HH°.^ èÔ©9¾n„¨@D(wœõëo­^=˜9òöõý”߬™jVVþƒaãÆuaÆ9vlò¶mwb˜—EE%÷ïøí·¾DôüùçnÝ ˆhÛ¶;¿ÿnÇ”“””‘<`€é—/éiiÙffºDäáá7}º ÷¤‹‹K||Þéé©õèaôý{S÷¤‹ŠJÎ{íà`nmm×¶­Ž††mÜ8ÌÒr«¦æâ7oâ.]ª¿˜€[jtÿ]­îÞ}?zt'"JOÏÞ¹ó>Ómpûö[ ½fÍT™q”•eOžœ2cÆ)楯ï§š39`×®sæôf>2vìÏ0±lÙUC%%Ù;wÞ÷éÓšÅbQDD’±±&EG§—0åtîÜÂÁÁ‚ˆ||Þ3Säž´¯ï'KKý~ýÚÑ›7qœ«UT䟙¹ïúõÙºº8¡€p"URÂþü9%,,aåÊ뺺*;6¿t)ðúõÛyz¾$"ËÙß?*/¯0&&ùÈÍ›¡-Z¨egçoØpKAAzÈ3"ÊÌÌ‹ŒLŽý¶víÍüü¢Þ½}|Þ=xÖ¯ŸÉÍ›oˆHCCÉß?êÆP‡Ã……ÅDtóæ›!CÚ3eÞ¾ý¶_¿6çνæžôÍ›¡‹õgF Œ16ÖTR’%¢õë‡ |`ûö»·nÍ•••bÂÁ A?ÃÁljaa &&ZÜ“¾yó••>3Bddr``Œ‰‰VXXÂÌ™=‚ƒ¿tî¼ÙÂbËݻﱉ ›]~O‹ÅÂÍ!P}›c¬]PGÖÆj]-X¢ý¹äˆˆ$ÏGÖÖëØqãÓ§K”•eÙlöíÛoœN¤§ïjÇÃrF«¯Åõ\˜ý>zêŸââ’£G}Gî\‹óæéù2++ÿû÷ÜÈÈä6m´ñ½ˆ I,€zÇÒr[`` 5j$áâÒ³VæÁÃcêêÕ^ \PV–µµm{éÒL|/PkVÔú< ÞaøðumÉT÷é¡§ˆpí  ”OÖ@81„ÓC" jç§– NÑâJ~N+TÆ»çÞkFµæ¼üsFª—)’B*1󵫯j ®©¹pÀf³±¸¡¾+ÌÏ]=ʸ0?W$¥yn•ô%‚órÉÑgUß„U¢ÊUùÌÉMm5ÕÚÙ‚Åý¯þÙ×À^s@ÏÀ‚ÿ¾&§ ìëuL$¥m¼Q•Ôb•7]‹¬•ù¬¾Z»½*^q:€ˆVž <ôªk;€ €(Ì+T  óê;ÿÛ§ì¦þþ%™(*È?µaúòAÍC_ç[;AË¡µ®P•ËÀ3“ÏîaN@_=‘áäº)̼e}O%¢§WÝW m9×Fþäº)…ù¹|+^ïƒáàÿ¼ô>Ó¾Ç)iY³Cî]()þ¯çÙcô„¨oŸÝrýëþÊ3÷ÏìŒzë_ÆðÒ<ÖOKŒgþýèÎÉmóöyo¹mj5àÈïŽDtd¹£ã¢={Ÿü0iÉ…?çÑæQDäÀ^~Ò¿t!ÿ¼{yïÌ—?¯î}òcÐôU'Ö8}ð¿GD§7ýšî}ls÷3v>LµuZzvÛìJT™ñ%¹âüè*3ðôæ™3ÿ¸´ß7»ÿ¤Å¥çÓcÝÔÄèp_¯cÃfmlÑÆüæáu|k'h9T¢Öªrxf²ã\‡…»u ÚNYïÁŒ0yÍq"úíàE•&÷.Þ¿¸øÈÓíwâUšê\ØéÊ·âP7áv „aù{Ÿî2`,±$$Úv³å>ÀÝtýÙN^&¯¬ªÕÒdÄœ-—w/*cxi[nDqþ¾ud½Ã¢=ªÍ7Ѷ>­° ˆIJv°‘’‘ë1jfvFz¹…øœØ:né¦Í ¥däºÚê¼þöÑD´Ù+ŠˆFÎÛ¦gj!)%m=l*gÏZ¡*3z;Ì‘UPÖ1l7q…Ûý3;™Ò2r™éÉDÔÌȬôFvë­"2µì¯ÒTgöÎë«Ï†ªßåP‰ZW¨Êeà™I‰F’}Ç»Ê)6þÈŒID&]ûу³»'­>ª¦ÕB^I¥ÿÄE/½Ïl¹]ºâõ: á/8¨X8ÀePOÅ~ þ–gj5€yÙ}ÄŒgw³KJ~îeå¹G6êÜóKxPÃK“’‘ãüýþu3#3æï&ºÌu‹k/¾‹~ÿꯅÖ Ð4“Ü…D=ÑhÞŠó²‹íؘD$)%MD,ÖÏf(%-[RR\‰*ó0hß-6âçÞnÖÎëw=þØ9³wØËû¥Çd.VÐhaÄ=oíø.‡JÔZø*—ïLÚMýÝûøæïž»9Ãã"߬fÀœwXØ·IA^3<G@eÅ5T¸çùê#¿[9ßf[Is6÷q¡.òYRRZJFVøá¥Invϰˆ '‡–Œ2ïg¿ãA²03\X_Àuÿacu-i9…ê«rqQ!g'Ýܸã²~C×]Þ»äùãÂL‹íø-‡ê®ui¹Y?V44“f=†¤%DÇG½Ïþ‘òøúÞ§?g˜]R|àE®{›ó¯Š×ŸÔ;xB"ˆ¹â¢ÂWwÏ­»ø^ÛÀ”30)æãáåý9‡¤y9LWALx ™5gLAÃÑ1lþê¡y?{îë§-<ôPSOØçé·³Œ‹mÕ±;ó2-!¦µE‘W™ãSˆokóÞÜCŒÍ{ÏÛs{óDs›aÓÊßÚñ]ÕZk¾‚]1hß­Œ¯Ànò²;'·iéµ6ïg/+¯Ä ÔÖ7ýâÛ¦k?æeÀ½ ÅòP§çNWJ…º ¨×0è?€z¡ /ÇëàªN}F©ë´ä®®£/#§xûèÆ¼œLfˆ×¡ÕyÙi 1wþf7ygLAÿ%ÅÑ÷ä¯D”žø…ówÇy×ÿZ‘ü%²¤¸èÙµ#;gö&¢œŒôÄèð¬ï©Ì%ñù9YD$#§û18øÑUfîBO_ueï’˜ÅE…ß’ã.í^dë´„Ù_Ñ÷”xf~¤&Ñ·ä¸JTY^Iåþ™yÙñŸß]Ý¿l¨ó:Îv$öc0ÅG½gܹ瓩uQA>wÉ|kÇw9T¢ÖÂT™Ù.1³óñç\e~rùÐÙm³™„Áw&‰È¼¿Côû×Îïëí0‡³Yûeìü³[gÅE¾),ÈûûÂþˆ '|+^¿ö Ð`“›Í®h2 "V%>óó“,¤NÍf«úV¤3{Gü{oý¡—…~v•m™dHDrŠ÷<þîlÁ·ì¯«û–*ª69w+s3{|‡sopÝØÜѽSÞ=µ½0?·m7;ÇÅ{U4tžÛ{ý¯Í[ ŸµéòžÅz=»÷±M>'¶ê´uÞ~YM«O!.y\•ÿ¶éȹ[ÛYä™hé—ªr|Ôû³[gýóþU³VfŽKö´·âÔËiÍ1ïc›‹‹ §®÷hmч{>¢GDªšÍ·Ýþ™"ßÚñ]DTÑZ Så²÷[nü£®ÓRÐL‘ω­_?r=xŸûHúç®»Ûós³:ý2züòƒó{(–®¸x„ñÛŒ£G„'Tr_éO"@ÝUÜš`+ÓìkÛÛ~v‡^ÃÅõëæ®§Å ŠY€dÀ¨Ò5l6ù꯴øèä/‘f=†Šqùn¢±ÝF2¨ÆpÀÉXÛ þbnëÏHKTV×f8ˆ’â¢k­è?qKO|«ýbÃÜqŸ?ªb2 ‘<‰ý/\¨õÑâšD´ÄV[Èá 6O4_b«­c`ÚË~6o ¾ÇÎ…‡•»ü°4–HJù¿YÈ5Däûñj ’X ÐâDXGlRªgÚþÛqˆt €`8=„p 2èŽ@8„@8ÎU €µ#€p N‰U8èÑ£¾ ¨EèŽø/cÕJ{ÀcwÆÇÊ€‡ýKR =Xîÿyòä –;ÔÍ£je8 éÒ¥‹´´tË–-===¹ßòöö633“‘‘éÚµkXX˜³³3Ó­¬¬˜|||Ú´iÃÿÎ;:t––655½rå ÷8...ÊÊÊúúúOŸ>eÞòòòÒÕÕUPPprrBóhÈpNAdËQ$Œ}}}srr8 ¦¦ÆþðáÃ=zÄÆÆÆÇǯ\¹²}ûöÌ7ÇýY---Îÿ¾}û~úô)''ÇÓÓS^^þîÝ»l6[WW—ˆ–.]úúõëüüüƒ¶mÛ–ùˆ††ÆóçÏÙlvhh¨k5@´+!@×F´8†È.Üh׮ݻw°°PZZšSl¯^½vïÞݹsg"ŠŠŠ²³³‹ˆˆà¹`$77W^^ž2bĈmÛ¶™˜˜0oíØ±ÃËËëÙ³g222%%%Lß@^^ž¢¢bQQµlÙrÏž=#FŒ@Ô«§¹HúPGÖF±_qA"»E¸_½zµiÓ¦çÏŸ§§§sŠ•——ÏÈÈ””,ûËã QUUMIIáŒgdd”››[úSœ—!!!³fÍ’‘‘Y¹reÿþýñ¥bSP"»æàÉ“'£F²··ONNæ9m‘‘‘!|9ùùùL`hii)((”ý‘Ž;úùù­[·nÉ’%ÇÇ— P'ÂÁ´iÓ>|8iÒ¤FqoÛ¶íÇ…/ÇÒÒ’¹t€Ó§Oa>Ø»wïÛ·o¯X±_*@éééááá©©©S¦L!¢¬¬,fø¼yóV¬XYTTtäȑ޽{‘‚‚BppðÕ«W™—_¾|!¢¯_¿ѪU«–,YPXX·hÑ¢%K–0)ˆâãã™bˆ(..ŽˆX,Vpp0½ÿ¾Ün¾p¯ÀDueãž={äååÍÌÌnܸall¼dÉÎ[Û·ooÒ¤‰‚‚ÂèÑ£ãââØlöÆååå»téÃ}rˆÿâÅ‹ÆÆÆRRR:tðööæ¾È–3÷K":vì˜AóæÍ=z„«Lqí4îV@‹ƒ:q·@¥Õ°BYq·€ˆO+€øÀñ´xÀµ#€p5ÝÑ †pí Â@ @w´xÀµ#P Käa©  &‰|W.)òXà€®9–³Ö¨Ck£Ø¯Š ¡Å5„ïQÐþW„AR$3ÄÀ&jWÃÜ1µæì‘«žªX,@ FUÿ‰ÑÊ_ˆdP7SB¯ÿ«d8@2q=ê‚z¹®ª˜* êE>¨\D¨p8@2ä}€ú’*×…P± ‘  :bÔ‘•Û7Fz @$1¶oT}#Ó—IE;„ H ~[@ÌU´óájar @Eá&‘ä¡ÂÎ)@ÃŒ­ z[a¨`8@· +@C€îh€ „lˆÇÂò²„@„@J„@,€†×Ž  ­ˆž$b2æ»hP¦õ· h}Pl¶;BÍ`±œ±Äx¯/ä¾§þ¶8f®§óÖ‡p8¨ ô.ˆ®9„@8€†·2"ˆ ÎU €`èŽ@81„ÓC€pBµ#"ƒsÕÀ~x  Ah-öÿ«ŒP£âã±Ä,€ÊÃièþA8„Ápá€Ƞ;á@ì°XÎ¥¦¤d~ðÛ·"š4éx`` ÝÑU„¦‡pØ+;×ÍKKË6ìàŠUUå‰hçNû .`#hzhz€p ÕôéëÖ ±´Ôg^jh(]¼8ÓÙùLvv¾Ø×]G‡Åüa™zwïÞZ$EÑë'š^ Àµ#PU…妮¾PFfN×®[ybþ¥K[ddæ°XÎ&&kxŽ]X,g!b""’hj.nÔÈ…§¨7BÇŒq:ô¯ ¸Ë¿v-ØÊj›ŒÌœæÍ—_¿Â]ÚÁƒÜgoï~õj0Ï„üü¢ ŠmmÛþÿ.SÅÁÁ⯿‹ý·GDÁÁ_EXæ’%3£¢"ª’W8_¿þ -N˜¦'¨ÝU¢é±XÎññßml¶KH¸X[ÿÁýߦÇwê––[ƒ‚¾p­f_¬¬¶¡é!€8Û³çá Aí>}Ú”œ¼£ÿ6S§žä¼åáá·zµ×®]ö™™{Ùl÷ð𠜷ØlwæærÙÙíëÓ§õÛ·k quꔿ»ûÓÝ»<<¦\¼àááÇùÈ™3/ÿãÇžU«-Xp3ü?î^½|üød7·‰/^|æ™Ð¥KÇw(=ÇwàÙŠ%--]"ÒÔÔa™þþŸ+ýÙߣ‰U´é•Ñî*ÑôˆhñâË›7(.>ôâÅ2Î@AMïÔçÍûeß¾GœÏîÝûpÞ¼>u¹éáÚ„¨ª7æÌ˜Ñ]UU¾qc¹5k†|øÀykófï3g¦÷ìi$-]Õglçæddä²þ¿ÍnÙâ}äȤæÍUÕÔš°}û]Î[W®¸tîÜBVVjÊëØØoœáýõ÷ã´µ««+ìØ1†gBaa úúMJÏ€Aîª5L>>×ôô¤utXzzÒ>>׈¨¤¤dÓ¦¥&&*;j{zñö¾Ú¢…÷D$--Sº(¾c–.pÆŒÑLçÁÛ=òéÙ³ ™aÞŽþ4th7==î2kRMvG jz"lwŒI“¬z÷6fýÛÔôøNÝÁÁüñ㈔”L"JIÉ|ú4ÒÁÁMO’lJ IDATìá·´¤¤Œ={>~úí[NIÉÇèè´š‰d*·nÍݺÕçС'ÉÉ™ÖÖ†›7èÔ©9}þœ¢«ûßÑŒ¤$Ÿ¨*##Éfÿ7W ?ŒŒ4*:%%lVƒ?–pqqts»0pàHŸk..Ž11û÷oUSkôõæÍK»wo(**:zôÊ€Ã8#*jÍW¾còè北Ãb~*ÂÌL355YÐ̨ªª'''>zäsæŒ÷‹Ëžºx7=¶;ÆÀíJÔôøN]ZZrÊ”n‡?[¹r»û³)S¬¥¤¡é!€8³µÝ»bÅ@{{smíÆjj ²²s8oéé©¿zmcc(è³l6›%\»ïСÙùó¿Qvvþ¥KC†øúõ"ÒÑQyñb™®®Šð3¬§§™lb¢Å÷]SSíÏŸSJŠJmÛV§×………Ž$¢G‘§ç‘Båå§8:NáÚüA€€/|ÇT ½zm` /hf^¾üG__nÚ´yÂL]¼›^¹í®BMOAMOÐÔ{ÚØl_¸°ÿñãϹOO é‰1œVhÐbbÒµ´·o¯›’’É}Á-_n7a±û÷à ŠJ°ysÕG>VhZl6;'§ ;»@AAšâêÚwÌ÷ÀÀ˜ââ! ™5«×o¿]LMÍJJÊX¸ðÏ»ööæ7n„–þ”—Wˆ££¾n‰‰_åå8/9]ýåÞï hLž¹ÉÊÊ•Q ŒŒl]X 5y®ZPÓ+»ÝU®é•&¨é šº¶vãnÝ &M:nmm¨¥¥\º@4=ô€X9yrГӉøøïmÚh/Y2àܹל·¦O·‘‘‘\ºôʇ EÚÚãã·sµù93fœ ú¢©©œ˜øgÙSiÙrELL‹ÅRS“ïÓ§õíÛó˜á¿ýÖONNzâÄãŸ>%•ðL‚¯… ûIKKNœx¼qc¹qãºìÞý€û]++YY)ŸwÜ]© ?®\ ~òdQü~ýýŸ®[·ðÎþW„©«7MKKæ\ÀÈéê§ò~ïXИ<B%š^Ùí®¢MOAM¯Œ©ÏŸÿ‹•Õ¶—/ç[`jz¸•áªjøðÜ×OœhÉýîĉ–œ‹¥K_³}ì˜ÓàÁ7–³¶6$¢ääL‡ÃnndÄþÛLHˆcþ×ÖnV\\þváÂéNN.Ì»RRR>>טÓüRRRD4hÐèË—O»¸,þüùã”)ØÑòòr^QnnŽœœ|bâW¦K€¹‚Ϙ¥ |ñⓤ¤dzzjtôgfD«£Ó¼ôÌÄÆFQRR¼¦¦NRR§âÚmPvÓ+£ÝU´é•qSߦWÆÔ--õ˾E¢!7=±„Ó VÔÔnܘ½mÛæ® ^Ú³ÇÁÂB¯vçÊÙ‚UûsóæÌÿ::¬æÍ%û÷ïôõk̘1“˜wÝÜ.¸¸8êè°˜ã~"Z±bk@€Ÿ‘‘Òܹ.\ëævÁÅeìÀ]dddŒÚìØ±–ˆ:wnÆùŸƒï˜¥ $¢áÃÇöík¦®Þ”)Á¢ß™ažœÓ©“.uê¤Ã©‹¸~Shzâ”óÄ‹ûRpþc°X襩˜-XÂßô\]«‘€G²ÔúŒUGM+Ñx¶Ve”àlñóò~¨" o¸JïTø–PZ\lz·>g ì³ÊÝe”¿|pZD@,·D"äÀæÞñpþÆ&¬îoFëø×„¦Õá –÷=H øš îÚ»÷áæÍ>]»¶¼uk.–F¹»Š:^&ˆ|©ŠªÀM›¼7n¼íá1eìØ.hP7á‚DøÉÝýééÓ/ß¿_žX»sboïþòå?BŽÐ½ûv1Yþl˜Öý/H$ßѪUƒÖ¯Ú»wëºßëccD;Bψ›ÍˆY½úƽ{ š6UúôiS-ÎLrræ§O)e\äÌ3‚¯ïÒz±étЉ YÝù¦ø~GÕôED$ñ}šPju¿1z õêµ³k×­))™C†ü%#3çåËz÷ÞÉù-–«Wƒ Wš˜¬9uÊ_CcqI ;))ÃÞÞ]Ii>óÓ±,–³£ã%¥ùiiÙ¾¾Ÿ´´–\»Ìf³—/¿ª¬¼àÉ“"JHø1fŒ»¼üÜ Ž1Å®Xq]Qq~NNAQQ‰«ëE%¥ù~~Q6ÜÒÕ]+)9‹ïÔׯÿo„ÀÀeå,–3óË.99óçŸWUýMWwÙƒa‚&Q+KXÐ^§^'ƒ‡½»wo-6­ ô%"ÿ‚ž>´°Ø¢¢âzãF¨ŒŒ$ßvQ+íQÌ#NÒ¡çDµÍZüÇwüÈݲeĉ/âã¿köèaDDGúîÚõàܹ_ ›ŽyhРv,GÇ#66†ÇŽMþò%½K—-¹¹ˆèôiÿ¼¼ÂG—-³}öìSZZ¶…EË_-~ûökçÎ-†?¸t©íÞ½ŽFF«˜‰nÙ2Âܼ…´´¤‹Ë™1cÌ££S[·ÖìÖÍ ==§E µ… ûñúÚµC¾}ûo„ÆíÚußÔT;?¿hȱ±Û^¼ø¹eKõ¾}w/]: 33¯t»¨•öØ`# @9îÝû°rå@"ºsçýÆÃFŽìDD‘‘Éë×ßzùr¹ŽŽ eeå jFD1û÷•`]¼Àü¾"ݼù¦¸¸dÉ[)©FÓ§{(+ËŽÓùС'­ZiìÙópáÂ~cÆt¾q#ÔÊÊ€û@êîÝÓ¦Ù´j¥qçÎû¢¢"º{÷=ó+M‚¦Îˆ®\ š0Á’ˆ6n¼=yr·É“»Ñ€¦‰‰?ʘbH¼zݲ¥¬ØT§Z¿ððÄå˯½x±”Y™Ùlv¯^Æ‚ÚE­´Ç†Ö¡\8­”“SôÅÚÚ°°°8<<‘ó›ÈÛ¶Ýùýw;fs””‘<`€)mÜ8ÌÒr«¦æâ7oâ.]r&¢ÂÂâ‡í¬ ää¤ÂÃïÞý`kÛöû÷_ßOƒ·¿p! }{Ý;ïÏ›w~ß¾±LáEE%çνvp0·¶6 kÛVGCCéË—ô´´l33]ASç!++ÿÁƒ°q㺑—Wˆ““SrVV~óæj‚&Q[;ž:ž JJJ6mZjb¢Ò±£¶§çoï«-ZHéè°ôô¤}|®ñGZZ†ˆ¢£? ØEOO†3åççÍŸïd` ߯_ÇèèÏhbë×ßZ½z0³2ûú~ÊÎÎoÖL•o»¨•öØ # €°ž<‰èÒEOVVêÙ³HKK}ίÁÞ¾ý–s«Õ²eWml •”d‰HEEþàÁñ™™û®_ŸÍüêëÓ§‘;·`~IÙË+dîÜ>Ëùø¼ïÒE¯E µˆˆ¤öFD$ùú.m×îç¯òøú~²´Ôïׯ ½yÇ\ÓtçÎû>}Z33Àwê<#XXè5k¦Êf³38³}ú´ÿøñ]MøÚ¿«šZ“  ¯¿ÿ¾uÿþ­kÖ¸=z%>žÍ<ç˜ï8ÌÀn_¸pßÍí ÖˆnÝzke¥Ïž™™™ûmíÚ›ùùE½{ûø¼#¢E‹.}ÿžËé-$¢[·ÞŒÑ‘ùÛÏ/jùr;f ­m[OÏ—ºº*ׯÏÚ±cÌÍ›¡«W{ýÛíºhQæïÀÀccÍsç^?xÖ¯ŸÉÍ›oM{„ë×Clçéù’Åb©ªÊߺõ&7·ðâÅ€óç_/^Ü_Ð$ðuóåéydâDgyyGÇ)þþQ_ FDŽ,,,ä;3pÆŒÊÊ*Ü£Ñõëç]]§´l);qâ ÿ§X¼%%ìÏŸSÂÂV®¼®««Ò±cóK—ù¶‹ZibÖqˆƣGííÍ™ÍG÷î­8Ã]]ûöí»ÛÕõÂìÙ½ Š^½Š–`……%ÌœÙ#8øKçΛ-,¶Ü½ûž9n°³kKDññß³³ó%%%˜£€€SS‡ÿòË.]Ýe.tëføo8xÃÙðEF&Ƙ˜h¥¤d>}Éñ:÷QQ)1††M‰èàÁñ..žšš‹ïß»ys®¬¬” Iàëæ+1ñ«¼¼ç¥Ï5==i÷/2óŒS†ä䄸x6óïóçl,Þ•+õì¹cÍš[·ŽLNÎ|ü8¢E 5¾í¢VÚ##”†^ª÷ªø30QQ©«V]?{v†ãwì¸ñéÓ%Êʲl6ûöí·NN'ÒÓw7 S©^ªÐ·Y+?¼Ô©“Î;šš?;·õô¤ÝÜ. 8’ˆtt~ÎÏ8ÜoñüÝ¡ƒVhh-ßÈP¹^òw}ªï ЫÞúðÃKB¬Àå/ô4\mÚ¬ýþ=gãÆÛ›7þSÑÑižž/³²ò¿ÏŒLnÓFKR 4úòåÓÅÅŬ­­æååúú>$¢ÜÜœÒã$$Äs7cjj2ÅÇÇþ[Ú(7·¹¹9Ƴ­/ ¡v÷(hP§ 4\ªªò]»nur²Ò×o"ü§<<¦:ôDMí7#£U1—.ÍÄ’+Vl ð32Rš;wâÂ…kÝÜ.¸¸Œ8°‹ŒŒ¬‘Q›;Ö–Çܼ9uì¨MDffšDdaÑ‚)måÊ?^½ò51Q™6mä† {°xÑ¡ÞÁi…z¯Nýº¼ø71=­ ~*qZ-N%ªž÷n^º|rÏ„µ§-,,…•œÜ_ÿh\­¦mçñ6½pª˜J–YXxÔo.„¨^ïv~ÞO£¸¬“udË‚®'HÉ@EûÌqzת©½jŒjk·qÆœ¬ !ÄußCß¼_?3-ù×ÙŸ}Ñ¡üÔ·Š Ÿ¶õòÄnÎÉHëuëÂñý«g|2k«……åÉ?_9½oúoWÕë0ù ·¯·\*_ÙI_%ï^÷Û³üëSWUtt <±û—™ŸŽ˜¿»w×É=\ÇE¿=rV£¶=œ=œÜùó‘- Zöø¨E×\j5:`óá_æg¥§ßXû½bæžP!D§º×}ÙJnÓ©Ïçã¢ßýCõz¯XYË[÷bÌO½–ßЀI&‘¯{¸-¥‹m¹Š‰"\j¨¦¬ðϽwãâÜ!Þ“7üãÙ°¥"*äê×oÕTÿ¯¼œl+¹4Z&M±–—Q(ò¤ÇÚóK³U­^[}¢µ­êqxзÚM¤ÇU\k~¿+X£žö2S“íÊWÒ·"!§ªº¿¤zÚ¢ÛûVLÓXŠB£Ú–VÖJ…˜y  ¬åúšâ™ëøÍŽëáAþÖͼsùœE¨—£sM Ô!_tÖ§ûÐ)×ϹàÉ5‚ŽïÈ׆LUþî9`ü¥ÈKÍÚ]<ºã?»»…¥g£VBˆš½eB¥"o™oƪ‹JÕŸtúÔÛò9¿Ôm2Ò’ ¼Þ¸Ý›÷n]20CNvVvV†êi‡jr[û’ÕÖºÖ18àÔŠ‰ï6½Ïü£±FSkš‘š4íÚúêÓ¤}ÏG1áÑaAiI„­{.ø†.Áo…ª‘&JLòxÎIJ»Aò;l pC"ù¥E·A®›|ÅÀ<Ξ B/ŸU=½xx»á2ó;¿Â¥VÃ[þÇ ÌÐóÓoÎî^£ÑuOÿ±rñ¨nÒcÏF­Ô×âQ̽º^¯ýK«¼ÜœO ‘Ÿê\ÇMß~ÝOþkãÜS¿¯xµï¨2vå ¼¡K,õL 1£„9$¥R™ßd öiòJ…ZMÛöò™ñã§m˜}W©P¤%'\9½O}ž×>³uΈ¨«9Ù™'¶/ 8%“„㢥y’âc„‰±Q:çO|)„ÈÍÎR/6áA„âqì}!Ä«ýFïùyjlDˆ"/÷Ìî5 †wÒ¨§ƒ³G«–ï|%/7çqìý?WÏØ¿æ»SWI3¼ùÉÿþX<ñÞ‹y¹9‰±Q;Žï6h¢BZ´F=5ž†_÷{æB…^>{ôןî\ñMMzTƾœG}¯¶½?nÑõÕ GýéïMó²2R_~í½þ_-·±µWe_¡W驯ücÚ—BTrrŸ{ Bc½Tÿrxóož—“•Ѱu÷~W¬êª]Ï+§÷\7ë~è5K+ëÞ]ßûb^OÕ«—ŽîÜ»üñÑwk6xgÔœFmzh/EßScæYuQyÓïÈ/3?M}ïÕ¥_¿ ‹g hÞwüÂ¥ÿ~g”öüÏ\ÇcÛïùyjU÷—z˜ùû¢ M;õ~oÌ·žÎ!¥hš±HJ9xð`½zõRSS‡^®\¹êÕ«8pàÑ£Gýû÷···¯Q£Æ‰'T3¯\¹ÒÃÃÃÖÖvðàÁéééJ¥rÏž=...vvv”¶«ö¥Rèååemmíáá±eËU)))=zôprrRŸ¨sAúJá(X8Mvvv×®]SÉÍÍMììì”J¥‡‡ÇãÇ Ì“žž®^‡f͚ݸqC©TúùùµmÛV©TªÏ‘‘¡qF×x‘‘aiiY°p ý833Sã¿´WÐ@e’““ééæ\\\„³fÍ ÈÌÌ\°`‹‹Ëĉ/]º”••µfÍšºuëJsþöÛo¯½öÚ½{÷§L™2|øp¥RYµjÕsçÎ)•Ê+W®H;ö¥RY§N³gϦ§§/[¶¬råʪ0þü„„„»wïvîÜYakk«oAúJá(p8P*•Ó§OoÓ¦B¡P½¤}b¶²²ÊÉÉQŸ¢=zV¬X1fÌ¥R9lذõë×y/_¾ü®]»4ÞÁ>h·Få¥ÅiŒIøw˜E8мRÆTõ“ììl éq«V­Â¤Çñññvvv …ÂÃÃc÷îÝêjOQ*• 6T¨ZÜ;ï¼£*0,,¬uëÖ¤¯d€Â„ƒììì¦M›®\¹Rõ’“““ÆÌÎÎÎ÷ïßWŸ¢=z’““ÝÝÝ,ͦ=Eâçç׫W¯Ê•+« tuu½wïžôøêÕ«...d d€|‰ŒŒBDEEIOV¯^«T*GŒ1þü´´´   ®]»*•ÊQ£FÍ;7777((¨V­ZÚóDEE !"""T‹ðññi×®jàS}†»wï !¤´-„ˆŒŒ”úTHHH~;••U\\Üùóç¥•Š‰‰Q*•>T-NZ´t•hT^ éééGB¤¥¥©ƒB¡˜2eŠÂÙÙ™p@8ÐýT.—K·Øh;qâDÓ¦M×­[§oÊÉ“']]]7oÞœ››«*påÊ•=zôOJJjݺõþýûŸ¹ Ëá(ÀÞ«¾OŸ>]šrâĉäää·ß~ÛÚÚºN:Ò­)))½{÷¶µµ}ùå—7oÞ, ¨Ï£]``` Âßß_{‰úwêÔIõ± kkë}ûöÓé àìì,}ªÂÀ"ÜÜÜÔ6Ô+¿k×.¹\Þ°aógÏÖ¯_„ ʯ5ØÙÙ­]»¶N: t?mÖ¬Ù‘#GTÓûí7õÙ¢¢¢4†ªÔ§Ô¬YóÖ­[FGG÷ìÙÓÝÝÝÉÉé×_Uý£áé\@içää$ ïçååmÛ¶M.—›[§ãR$Šæ{¤‘(ihK’Ò~*Í3f̘#F\½z533séÒ¥§N’>_+ä   {{{S„ ·nÝŠ2dˆ"55UÑ«W¯… FDDmÚ´®]»²]KQÆç  Ðé9 „€NG8(ÑøÉfxzÖ@8˜† €p€~\"@‘a8  €‘¸V <íE{™ÞÀsVäwÌÙ/I±`ÕEîèA>øx±Û íæ°+ÒéLó~Qñ¥Uák#aWò^i•U'å§„‚‡™LF `b‡WÀöáÂÿÀDoH$PbSB!o,H8 `Âù ßá€dÀ$Iwê&– ò¤e P˜ƒ¯ã/‡fErF¤Ô[£`CƆ)Ðè(|§Õ†Cà9³¢ ðüày¾1ËïçŒ9àjŠp-ÀKÀ‹Ý9Á{ÓÈEH˜~x Ó—¯ÁÂ^ÀjäDàyb8 ÌåíŠ8pÃè½@8È `š[#o; !ÕtpïH‘ €1€pR€pb`ÃÑáÀ»@7_e,Ý%Ê€g>+B$ÀXJå*á9É|hÂ=®ä÷A/¾»¯pYá ã€p0AÜp@8„@8ÀHÜ;B8€"õj€p ÃÑá`‚¸>[ÒÒ²h€®G8@©·gÏå~ýÖ¼ùæÒmÛ.¨O?~üÖ»ï®tpgcóyË–sÔ³ùΗ¼¼fÛØ|.“ùÔ«7]£À‡“;w^¸zõõ‰ûö]yÿýU½zý¼}ûEÕD™Ìg÷î@oï¹66Ÿ»»µgÏeÕKË—ŸìÑcIŸ>«ví 4f-‚ƒöë·ÆÉi‚¥ågµÒ¹è/ýŸ²³óºuk¨1ÝÅ¥bß¾^?ÿ|’=ÊÜx8Ú4ºžTZtôã¶mçYX|Ö¦ÍÏìz:W¤U«9ª"¼½çÒõJ+šÀdœ:¼té2™<¶^½jª’U³éãîþÕ¸q¯÷êÕ¤V-GÕáÉÀ¢ ¼ô=–|ùåë]»6ЮCvvn… c32–i4 }Áä{Ó37±ªÇ©ï¦Ñõ¤ÙÝ£G#c­oE²³sëÔ™~áÂGÇrqq)-[Î þÞÚÚ²À]>X gg7##&ÈÓ³J\\ªêéÇɋ;y28<<>11]¡x²[„‡?jÚÔMg çÎÝ‘ÉDvv®Æô;wâ\]'?Ý{¬t\–²±±Ríy11IµkWÍWå÷ï5gΡ+NÅÆ¦´iSkÖ¬·_~ÙÝÈE~é…B)ã~g˜Y×û÷ÌÝÈøEë\¹ÜjÈÖ«WŸùúë7V­:3dHõd@×+-&èæÍOÏ*ª§Ýº-ž:µGŸ>Í+T®l_¦ÌçÒtÿð¶mki—°nÝ ›7c XàÀèòå˨¦»¸TôõìêZÑÈšxx8„„Ī޾£iS·ß~ûT‘––µs神=—Ý¿ÿCýÌ¥7hà|çNœÎ—ÂÂâ6taG‚Yu=} ,ZߊøøthÛvÞ¸q]Ö¯?çë;ù9w=cF€ðLÜh:ÆßŸ“ôå—;||Ú«¦ß»—P­Z…Æ]ãâR†ݨšþÕWÝ?úhÝ‘#7µß¦!ê×wž>½ç€ëòòª‰cÇv~ÿýU—.ÝSŸhÀˆ¿ürG||êÇÉãÆí4~]”JezzvZZ¶½½¼`‹~æÒûôi¾oßÿ¸wïå~ý¼Ø£ÌMÏ(¦Ôõ´X´¾qv®ÐºuÍ×·iS«Zµòt=Fð"µjå9|ø–¼<Åĉ]›7zpãÆ!ƒmˆŽ~\¿¾óĉ]U7TòI[«I“þ¸q#&;;×Ù¹Btô<õ»t©çNÜØ±;–.ý@šòå—¯ÛÚÊ X››«Ðþ ãÆ½.—[ °¾BÛ?l±páÑg®ESïÝ{$“É*W¶{õÕºŒ.Ø¢Ÿ¹toïšeÊX:t]c5&&é?OϳêzúX´3æ5oï¹~~S´ ¤ë• ÜXºißã%$¤½ùæ² ÞoӿɏhllÊ{ï­\¸°¯Î›Åè &ß› pC"Š»ëå·rYÁˆ}øÙíÃe˜¯Ê•í÷í9wî_ªïp7nç¢E†Oèzæ€Ë xô}ÓûóOæèXnß¾ÏUO·lù˜­º^©îz PZ10 ÐõP’qY`:øUF†£Â ‰kÕá`‚¸w„pèÇå!†£Â ‰kÕá`‚¸w„pèÇå!†£Â ‰kÕá`‚¸w„pèÇå!†£Â #XÑ¥LæC#…çã%3æÊ=„”t¥÷*©ê¦!.ô‚¶QIÃe¼àÌ­ÅÀó åô8@>@,á¥3ìÏ'˜|§#@Àh0Ý·kŀ⎌Õpò¿*£áäÀôG ´{™™L@8ù )¥?š„ù<»ѹ@8@©ÇàȦàèññõÉ(qh©oùE÷@ñZt^êÒwýKšþb'85jayÁÖ´Ÿg› 0dJ¥¡ã¯LÆ/òÍî¸ïРs1|Þ—pY%tüÀðÛ F¦j’ €pò`šÉ€XÂL9Èo2 ps9ð•X×ÏœþnÝ’Sl1Õ§`~Öž}ø…$ Àž}c÷$Â$|ÃÚÆÖ©zíöïútê3²¥Méé‘ð ¢È{Êä7ÜÇÞ7PlNVÆw6¾íе­úô¯Þ¬žø0ÒÈúíCŠéc&únÎÉùÚ[Œ¹‘‘”ÅtóÁJÿ¼©›/!æ‰]áŸ;ïÐý·>ûîØÖ…çþR€Ò¾ß\ë>kÏÃ3žØmk_þìÞuÓgî1r¹9ÙEXá¢-Ms{ýrQñõ–K+üsé$+ÂÌ4È,,<x !ÊUr´°°´+_©iÇÞ£8¼ùÇ”f%·)Žf±çlî>tJÄ­³²ñõ 8U„.ÚÒ4·WýæBˆêõ^±°°¤S ð‚ÃR©ävq˜êøæHÈc£TO#ƒ/ÏÔb¤·|j¯~‡~UŸóú¹ƒß}ÐäóÖ6sµŒ¹{S½¿l;Rú UUOïZ5µWQmí6Î’“•!„¸î{è›÷ëg¦%ÿ:û³/:”Ÿú–gHÀiU!Á§¾ÿ°é˜å.þÍ@m“âcî^÷kÜîÍf{ûþ¹A{†°«ÿ|Û¯ñØNm]¤šxåÔÞÉ=\G·³ß0}—lË,©UçñVU,7;kówŸ|õ†ûå“{ ´ƒv#h”¦*Põ/A¾}ÿaÓ‘Þò}ÿã™Magÿ½»×Ψ¹ßÁ-Û÷´–—iÒ¾×ÅÃÛyšƒí·&¯?7iÝÙS¬ <¾KšøË¬áÃعôlZ—„³ö…ImûÕÆóBˆM3†>¿uvﺷF|_½~ó?WÏÐ×:A£4!Ħo?~~Kz|÷ºßá-ó?ûq×âSIo|ò¿ ÓÝ8Ø@Sä‹F%_í7ªï¸….5ùv“4Ãàéë«V¯ýåò£e+VÑÞ(:Wœdj2ò†cÃ(™GÆ"1º½—lLû²‹Gu³´²®ïÝEõ’¥•u­¦m­mlÛ¿;<-9A5}ÿšoûŽ_T©ª[…*Îm{œ“©z)ôòÙŸ>{íõ¾lõÆ»²Bˆ£[œ¶¶rµêvå*v0Þïà¥R9ko˜âÑs=xYYËÛ¼5TuÝ¿æ»÷ÆþX­F=ûò•»šd æçþÒ¢ëB™…EÃÖÝ4Æ6„ú~^ƾ¼K­F¦®<²e4Qnc›’+„p«ÝDûÔ2gÿ=!DƒV]*:ºŒ\°gÚÖËúÚÁ@#¨›½/LõøÐ†9NZæèVËÚÆ¶e÷þ½|¾=°ö{M‘/•´°´êܬmÙ 7/I3ÄF†XZY×kÙYçF™ýg¸öŠ“ `¶øm”²Áƒ"ÿå…Ÿÿɲ´²ÎÍÎLMzôð^ðŽ_¶íý±tÒýfÇõð ÿëfÞ¹|Ný_ƒ.¸Õn"=®âZSu7âß›ç]=ýç¨Eû\j¨fŽ ¹úõ[5Õÿ=/'[º'@&{r”·–—Q(ò¤Ç7Î<}½ô¸¢£‹¾jGÞLŒjàÝUzÚîía?èìýÆ@™…ŽÄ_³qëÈà'g» öl3âØÖEo|òuýV]4r!DÕêµÕ'êl} Aýc!§ªº¿¤zÚ¢ÛûVL³²–ëkŠ|ÑYÉîC§\?{ä‚=Bˆ£¿.ìøþ}Eª€ÆŠ“ `žÃÂøË  ä䃢?°²–Ëd2kÛJUÝêµxmÀÔ•¿//½pjÅÄw›¿ÞgþÑXþ‘–¬]T¹ŠŽ•ªºUøï]©È[æ›±ê¢RõgønÁŒÔ¤ÜÜgßóÿÏþMéɉ#½åÒuôq«D_¹xt‡Î™órsT'i÷:Í&oø§—ÏŒßO<·o½1M¤»ô4‚9ÙYÙYª§ªÉmí ¹ù2R“¦½S[_%›´ïù(&<:,(-éÑå“{Z÷\°RBî$<Ÿd òuÏù¦šÔYZYçý{ñ~Ó·[qÌû·Ç»ÔjxËÿ˜öÿ¶ykhó.}WOî#ÝÇ qölzù¬êéÅÃÛ WÀ¹fƒÿüýï9L!t}>0/7Çÿïm3v©ŸÞ¾ûãÖ_æè<„^>[·y'õ)ušw½èÀžeSií ¯ ðlÔ**øŠê飘{u½^-äö 8þGÍÆ­ l¬îƒ'ÿµqî©ßW4½O»rÛ(%gÀ€d€ç D~oH$ÀdòR©¼wó’"ñadnv–R¡HIŒ <¾kÙ—½>š²Rš'=9áAø­ÔÇñg Bd¥§JÓ_í7zÏÏSc#By¹gv¯Y0¼Sƒ!Äã¸è—_}çµƬ™Ò/=å±4ókŒÙ:gDTÈÕœìÌÛ—œ’΋ÒüÒž¾ðî L; ä7.”Þaޱ(¸!fªä|x@ zkhl¬~Æ%€‘ Ô<ÿ³À„H ¦–НGL>(¨ob­ „ƒg/…@PÜNW9ýßµ“ @8L' h+ªN¡Z±àE '<·ã—@8L<"²S JZD(îs6É„Àô#B;—J&Õå†â»fD2á0ýˆ¯~ÁPAéH(ƒÉ„ÀŒò‘ý‚¡‚ÒDÑ]?â( Â`á™ý‚X`æ $sŒ:»F‡øÒ…X`ÎdÂ`¦A»k0Z@D €p€X@D €p@×ù€X`nAç‘d BP’ @8À€t ! @8ˆ à?C$ ˆÐÌ*A804#GK³KÄÂ@2@¾óà€ÉÇÁ¥ä?"päá0Ùd@,ùÐfA€däWû¸öÚ¿ô €R¬C|ä€p³U<á K‘¡Bä¥ç%žH êT}BuÕK7‡Ý¬5«V›°6nŸ»Ý™zçéûÚ3£G5ü­aË€–;U¼5ì–z¼ð˜äQ¾EùºËë¶ o#„ˆÛ¿7¾é¾¦­®·’W“ßùúŽ"øËàôôˆ…ÕTk}»µÛh·ÐI¡R¡wgÜ­·¶^ËÀ–)St¿±ÖS”K)Q?G5ØÔ MX÷qî·GÞN<‘<68=$=zu´ógïÛÞ®Ã]C¾ ‰\é:ÒµuHk÷qî!B„ÆÌÖ2 ¥z5¼Î?¹˜b`u‚ǧ‡¤®¶v;·¸ÔB:C7û«™v9:WÓp5€|8WýÜÇ3¾¾×û^—YË*u¬ôôDo-+ß²¼E çAι‰¹ªé?FÔœUÓÆÅFî$¯öQ5E–BõR²_òÕw®ºŽp­Ú§ª¥½¥âþÊûµÕ¶q³±ª`å:Â5vg¬PŠ–[ !<§y–mVV&—9õwÊÉxRøüÏžvµí¬*Y¹vÓYg}ˆ\Ykn­25ÊX”±¨ú^UÉ "Z\h!„pë^¶qY ¹…ó'ÎÙ²=§{–mRV&—9õsÊËB3›»z5lkÙJ ¬Žtš7\m}í¬N½«i¸ |Z äC»ûídÖ2E–"'!'ãNFØ´0§þNŽï8 !šŸižñSD²²ú¿¤¦Ø7°——ñ(£º1jiÔ£¿5ÜÚ°Œ{ÕÌiAiš_øÏXEŽâÉÍÿžz,l,”yOnÁK<‘X{Imé±¼š\gõU É7ÉÖÓV5›ã;Ž÷æÜ³(óŸ7 ‹–YË„B!ŒœM÷¶Ëô­Žz±úª­¯ÿSµrt®¦áj ù r™tî±q±±q±)S½Ì•žW¤pä›të³[žÿól°©ÁÙjgŸþRä¥äYUÒìkÖU¬m\llœþóöZ©P¶jkacì^nJ®2[)ägÒSE–B‘©°,kù$[T•K£%…žjëmg=žÛjò±F˜.+…È V2eî““Að˜à&»šTí[UfùŸáe»zvÏè¸ÞéC'ÇÞŽ7?¹)ÝÇðdæ:vÉ矾!ŽÛg¸vuì¤+èBéͺöçúôU \óriAiª§YQYÚV(úöÉQ®žÞUÓSm}í¬ÏsXM€p˜%¥H½’*„ȺŸ¥ÈV…Èy”¿?>裠ÚóŸŒêç>ÎMIÏIÈ ,„ÈKË“¦» s Ÿž–¡ÌU>øåÁÕÞW¥o@Ê~íð¦ƒË§.7‡ÝÌMzríÜu¸kèÄдiŠ,EôÚè$ß$!DVä“ù¥y²f !²¢³„Õ'T¿3ùÎãSŠû«î !ü½ü5ê®]izõqÕÃf„¥^NUæ(³¢³Â¦‡¹r˺¯cYš‹¾Ÿeälej”‰Ù£ÈR¤¦„ÍB\hyÁÀê ‚Á,vôÂÝs ñ ‰B&,ËZ–m\Ösºg¹æå¤i÷Wߟnëi[cj°oÂz8x~ã)½µ,*ji”"SQéµJµf×òkâ§:—dÇfû5ô³«g—›Û*¨•âþŠûQK£òÒòz9¼4ï%K;KÕÒ¥UÐx·+.lZ˜ÌJVgYЉ¡5gÖ¬üzeúkT@îüä:Dü¾øðÙá™™vuì<§yVê\Éð²4ÛáY³5ÚÙ(d\Hî£Ü*oW©5»V`çÀš3k}¤ï5ÊÑYmíñSDä¢Hûzöõ××·q³Ñ(G{5 Ô¹÷¦ðk f‘ ÂÌ —ááá€üQ*•ÚÐäq ÀSÆÿ³ðØ÷1P|="J´G‡ù5ö;WýÜíÏoŸq®V嬤ߞBd„eȬe;TÔ˜Sgi÷WÞ¯½¨¶›U+×®±;c[ø·B¸u/Û¸¬…ÜÂùçìÙžÓ=Ë6)+“Ëœú9e„e°ÂP¢™Ûnn¹4òj韛'UÝǺG.ŠTï‡8ë›SCZPÚ…æ¤ËçëžWd(„å%r !„=y*³– ;PZYÑ€I²odßìP³¤sIw¾¾“=<Û©¿“¢r×Êá³ÃÓo¥[Wµ~tð‘ç O}sjF+…²mT[ ÞNèÆ50r0xPjTh[¡Ñ¶Fá3ߌq\³1¦Jï*–e- ̩ήŽ]òùdÕÓ¸=qìNá ”¾÷²©×R…i·Ò,ìžöô*½«¤¦D¯ŽvþØÙÀœ–v–©×Rã÷Ç_í}Uá:Ü5tbhÚ4E–"zmt’oRÖý,!Döƒliþì‡ÙÚO¥y6J.+Àó™|r!íZÚÍ¡7•¹Ê:Ëê¨&Ê,eNýœŸ}lWÛÎÀœn_¸]yóŠ}=ûúëë !œ>tÊ}œ{ýýëyiy½^š÷’¯‡¯¯±ŸÔ’~ü´Ÿú7ó7ùv&À$ñQF˜£ñ4>ªgV®÷½î<ÔÙ¡‡{ÉÐ‰Ë 0G§«œ6ÛuÏŒÌ̸“áÐd@2À™çO5*s•á3Ã]GºÒõI€Üs³Îfõµ‰³¢²\|\\>vaë“ ¸çfßÌìk•A2ž‰±E˜;ó¼¾’@8È Æâ²ðogÉ„\bÉ š|X „àP Â`îù@0„€“I<ä3‚hçÁ±  " h èÜ^"0@Fò± ÐÌ‚!b@8@D „Db@8Pˆˆ@J(NW9-mwá %0Nð:€p”¬”@P „…“ 8 „ "™ ÐH ù¥º»LÓO ÒÙ®C|ÚD# h·Í3 BóÌ €pàAAÅT¯A¨Ê€@61”Šè óôO^dt(ò0aø|Ïé 0ý0Áù sdAÂÐëÿ·d7J5Ð/IEND®B`‚percona-galera-3-3.8-3390/gcs/doc/GCS_connection_states.txt000066400000000000000000000117741244131713600233140ustar00rootroot00000000000000 GCS CONNECTION STATES (from the application viewpoint) Since GCS is a library to be utilized by an application, it has to export some sort of a Group handle to the application. So far this handle was attempted to have a connection-oriented socket semantics. Reasons for that being: 1) It is better to expand on a well understood and established concept rather than invent something. 2) The whole idea of GCS is to avoid exporting Group Communication concepts to application. It is much easier to work with a socket. 3) The main point of the Group is a linearly serialized stream of messages with a Group being a single source/sink of the messages. This effectively makes Group communication a point-to-point connection. Initially this seemed rather plain to me: when we're part of the primary configuration, we can send and receive messages. When not - all calls just return -ENOTCONN. However, there are certain aspects to GC that make its interpretation as a socket not so straightforward. These are configuration changes, primary/non-primary configurations and state snapshot. For the demo these were deemed not essential and were not addressed. As we're moving on this has to be addressed since we have to settle the API the sooner the better. Basically it goes this way. Whenever DBMS process joins the primary configuration any other way than by configuration change from the previous primary configuration, it has to take a state snapshot (be it incremental or complete) and only after that it can be considered a part of the quorum. It could be done the following way: 1) Process receives configuration change message and decides whether it needs to take a state snapshot. 2) If "yes" then it sends snapshot request message. One of quorum members is dispatches snapshot to the joiner. 3) When the snapshot is complete, the joiner sends the final join message. (maybe "join" is not a good term here, but I'll use it just for now) 4) When the join message is received, every configuration member puts the process in the quorum member list. Only now the process is a full-fledged member of the Group. Note that I've been speaking of two separate memberships here: "configuration" and "quorum". A process is a member of the configuration as soon as it receives a configuration change message (bear in mind, I'm assuming Spread as a communication backend now), so it can receive and theoretically - send messages. However, it does not have the up-to-date state and in case of DBMS: 1) Cannot really apply messages (write sets in our case). 2) Cannot give a snapshot in case of another configuration change, so it cannot be used in quorum calculation. All this makes the process a sort of the "2nd grade" configuration member until it gets a snapshot. The problem is that every configuration member has to be notified when the snapshot is complete, hence we need this "join" message. As a result, state machine for the GCS connection will get one more state: own JOIN message received +-------------------------+ ______ | V V \ gcs_open() +----------+ +---------------+ | conf. -------------->| GCS_OPEN | | GCS_CONNECTED | | change +----------+ +---------------+ | to PRIM ^ | \______/ +-------------------------+ own LEAVE message received, conf. change to NON-PRIM Rough explanation: GCS_OPEN (perhaps should be split into OPEN_PRIM and OPEN_NON_PRIM). Only snapshot request and join messages are allowed. Attempt to send anything else results in -ENOTCONN. Attempt to send join message when in non-primary configuration should result in -ECONNREFUSED. GCS_CONNECTED. Attempt to send snapshot request or join message results in -EISCONN. Application messages are sent alright. When GCS_CONNECTED->GCS_OPEN change happens all pending GCS calls return -ECONNRESET. So GCS API is about to get more complicated. And here we have two alternatives: 1) Implicitly expose GCS connection state to the application through those error codes. Application will have to keep its own track of GCS connection state and not forget to send join message. In this case API can stay the same, but it's usage will get a bit more complicated. 2) Application can provide request_snapshot(), send_snapshot() and receive_snapshot() callbacks to the library. Then all this could be handled by the library and application would not have to know anything about snapshot request or join messages. This won't simplify the application much though: callbacks will have to be able to communicate and synchronize with other threads, since in this case application will have no control on when the send or receive callback is called. This also would mean additional 4 parameters for gcs_open() (3 callbacks + context) and make GCS connection much less of a "socket". percona-galera-3-3.8-3390/gcs/src/000077500000000000000000000000001244131713600163455ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcs/src/SConscript000066400000000000000000000052271244131713600203650ustar00rootroot00000000000000# Import('env') # Clone environment as we need to tune compilation flags libgcs_env = env.Clone() # Backends (TODO: Get from global options) libgcs_env.Append(CPPFLAGS = ' -DGCS_USE_GCOMM') # For C-style logging libgcs_env.Append(CPPFLAGS = ' -DGALERA_LOG_H_ENABLE_CXX -Wno-variadic-macros') # Disable old style cast warns until code is fixed libgcs_env.Append(CPPFLAGS = ' -Wno-old-style-cast') # Allow zero sized arrays libgcs_env.Replace(CCFLAGS = libgcs_env['CCFLAGS'].replace('-pedantic', '')) libgcs_env.Append(CPPFLAGS = ' -Wno-missing-field-initializers') libgcs_env.Append(CPPFLAGS = ' -Wno-effc++') print libgcs_env['CFLAGS'] print libgcs_env['CCFLAGS'] print libgcs_env['CPPFLAGS'] print libgcs_env['CXXFLAGS'] gcs4garb_env = libgcs_env.Clone() libgcs_sources = Split(''' gcs_params.cpp gcs_conf.cpp gcs_fifo_lite.cpp gcs_msg_type.cpp gcs_comp_msg.cpp gcs_sm.cpp gcs_backend.cpp gcs_dummy.cpp gcs_act_proto.cpp gcs_defrag.cpp gcs_state_msg.cpp gcs_node.cpp gcs_group.cpp gcs_core.cpp gcs_fc.cpp gcs.cpp gcs_gcomm.cpp ''') #libgcs_env.VariantDir('.gcs', '.', duplicate=0) libgcs_env.StaticLibrary('gcs', libgcs_sources) # TODO: How to tell scons portably that C++ linker should be used # and program should be linked statically gcs_test_env = libgcs_env.Clone() gcs_test_env.Prepend(LIBS = File('#/galerautils/src/libgalerautils.a')) gcs_test_env.Prepend(LIBS = File('#/galerautils/src/libgalerautils++.a')) gcs_test_env.Prepend(LIBS = File('#/gcomm/src/libgcomm.a')) gcs_test_env.Prepend(LIBS = File('#/gcache/src/libgcache.a')) gcs_test_env.Prepend(LIBS = File('#/gcs/src/libgcs.a')) gcs_test_env.Program(target = 'gcs_test', source = 'gcs_test.cpp', LINK = libgcs_env['CXX']) SConscript('unit_tests/SConscript') # env.Append(LIBGALERA_OBJS = libgcs_env.SharedObject(libgcs_sources)) gcs4garb_env.Append(CPPFLAGS = ' -DGCS_FOR_GARB') garb_obj_dir = '.garb' gcs4garb_env.VariantDir(garb_obj_dir, '.', duplicate = 0) #garb_objects = [os.path.splitext(src)[0] + '_garb' + # env['OBJSUFFIX'] for src in libgcs_sources] garb_sources = [ garb_obj_dir + '/' + src for src in libgcs_sources ] gcs4garb_env.StaticLibrary('gcs4garb', garb_sources) Clean('.', garb_obj_dir) percona-galera-3-3.8-3390/gcs/src/gcs.cpp000066400000000000000000001770031244131713600176350ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * Top-level application interface implementation. */ #include #include #include #include #include #include #include #include "gcs_priv.hpp" #include "gcs_params.hpp" #include "gcs_fc.hpp" #include "gcs_seqno.hpp" #include "gcs_core.hpp" #include "gcs_fifo_lite.hpp" #include "gcs_sm.hpp" #include "gcs_gcache.hpp" const char* gcs_node_state_to_str (gcs_node_state_t state) { static const char* str[GCS_NODE_STATE_MAX + 1] = { "NON-PRIMARY", "PRIMARY", "JOINER", "DONOR", "JOINED", "SYNCED", "UNKNOWN" }; if (state < GCS_NODE_STATE_MAX) return str[state]; return str[GCS_NODE_STATE_MAX]; } const char* gcs_act_type_to_str (gcs_act_type_t type) { static const char* str[GCS_ACT_UNKNOWN + 1] = { "TORDERED", "COMMIT_CUT", "STATE_REQUEST", "CONFIGURATION", "JOIN", "SYNC", "FLOW", "SERVICE", "ERROR", "UNKNOWN" }; if (type < GCS_ACT_UNKNOWN) return str[type]; return str[GCS_ACT_UNKNOWN]; } static const long GCS_MAX_REPL_THREADS = 16384; typedef enum { GCS_CONN_SYNCED, // caught up with the rest of the group GCS_CONN_JOINED, // state transfer complete GCS_CONN_DONOR, // in state transfer, donor GCS_CONN_JOINER, // in state transfer, joiner GCS_CONN_PRIMARY, // in primary conf, needs state transfer GCS_CONN_OPEN, // just connected to group, non-primary GCS_CONN_CLOSED, GCS_CONN_DESTROYED, GCS_CONN_ERROR, GCS_CONN_STATE_MAX } gcs_conn_state_t; #define GCS_CLOSED_ERROR -EBADFD; // file descriptor in bad state static const char* gcs_conn_state_str[GCS_CONN_STATE_MAX] = { "SYNCED", "JOINED", "DONOR/DESYNCED", "JOINER", "PRIMARY", "OPEN", "CLOSED", "DESTROYED", "ERROR" }; static bool const GCS_FC_STOP = true; static bool const GCS_FC_CONT = false; /** Flow control message */ struct gcs_fc_event { uint32_t conf_id; // least significant part of configuraiton seqno uint32_t stop; // boolean value } __attribute__((__packed__)); struct gcs_conn { long my_idx; long memb_num; char* my_name; char* channel; char* socket; gcs_conn_state_t state; gu_config_t* config; bool config_is_local; struct gcs_params params; gcache_t* gcache; gcs_sm_t* sm; gcs_seqno_t local_act_id; /* local seqno of the action */ gcs_seqno_t global_seqno; /* A queue for threads waiting for replicated actions */ gcs_fifo_lite_t* repl_q; gu_thread_t send_thread; /* A queue for threads waiting for received actions */ gu_fifo_t* recv_q; ssize_t recv_q_size; gu_thread_t recv_thread; /* Message receiving timeout - absolute date in nanoseconds */ long long timeout; /* Flow Control */ gu_mutex_t fc_lock; uint32_t conf_id; // configuration ID long stop_sent; // how many STOPs - CONTs were sent long stop_count; // counts stop requests received long queue_len; // slave queue length long upper_limit; // upper slave queue limit long lower_limit; // lower slave queue limit long fc_offset; // offset for catchup phase gcs_conn_state_t max_fc_state; // maximum state when FC is enabled long stats_fc_sent; // FC stats counters long stats_fc_received; // gcs_fc_t stfc; // state transfer FC object /* #603, #606 join control */ bool volatile need_to_join; gcs_seqno_t volatile join_seqno; /* sync control */ bool sync_sent; /* gcs_core object */ gcs_core_t* core; // the context that is returned by // the core group communication system int inner_close_count; // how many times _close has been called. int outer_close_count; // how many times gcs_close has been called. }; // Oh C++, where art thou? struct gcs_recv_act { struct gcs_act_rcvd rcvd; gcs_seqno_t local_id; }; struct gcs_repl_act { const struct gu_buf* act_in; struct gcs_action* action; gu_mutex_t wait_mutex; gu_cond_t wait_cond; gcs_repl_act(const struct gu_buf* a_act_in, struct gcs_action* a_action) : act_in(a_act_in), action(a_action) { } }; /*! Releases resources associated with parameters */ static void _cleanup_params (gcs_conn_t* conn) { if (conn->config_is_local) gu_config_destroy(conn->config); } /*! Creates local configuration object if no external is submitted */ static long _init_params (gcs_conn_t* conn, gu_config_t* conf) { long rc; conn->config = conf; conn->config_is_local = false; if (!conn->config) { conn->config = gu_config_create(); if (conn->config) { conn->config_is_local = true; } else { rc = -ENOMEM; goto enomem; } } rc = gcs_params_init (&conn->params, conn->config); if (!rc) return 0; _cleanup_params (conn); enomem: gu_error ("Parameter initialization failed: %s", strerror (-rc)); return rc; } /* Creates a group connection handle */ gcs_conn_t* gcs_create (gu_config_t* const conf, gcache_t* const gcache, const char* const node_name, const char* const inc_addr, int const repl_proto_ver, int const appl_proto_ver) { gcs_conn_t* conn = GU_CALLOC (1, gcs_conn_t); if (!conn) { gu_error ("Could not allocate GCS connection handle: %s", strerror (ENOMEM)); return NULL; } if (_init_params (conn, conf)) { goto init_params_failed; } if (gcs_fc_init (&conn->stfc, conn->params.recv_q_hard_limit, conn->params.recv_q_soft_limit, conn->params.max_throttle)) { gu_error ("FC initialization failed"); goto fc_init_failed; } conn->state = GCS_CONN_DESTROYED; conn->core = gcs_core_create (conf, gcache, node_name, inc_addr, repl_proto_ver, appl_proto_ver); if (!conn->core) { gu_error ("Failed to create core."); goto core_create_failed; } conn->repl_q = gcs_fifo_lite_create (GCS_MAX_REPL_THREADS, sizeof (struct gcs_repl_act*)); if (!conn->repl_q) { gu_error ("Failed to create repl_q."); goto repl_q_failed; } { size_t recv_q_len = gu_avphys_bytes() / sizeof(struct gcs_recv_act) / 4; gu_debug ("Requesting recv queue len: %zu", recv_q_len); conn->recv_q = gu_fifo_create (recv_q_len, sizeof(struct gcs_recv_act)); } if (!conn->recv_q) { gu_error ("Failed to create recv_q."); goto recv_q_failed; } conn->sm = gcs_sm_create(1<<16, 1); if (!conn->sm) { gu_error ("Failed to create send monitor"); goto sm_create_failed; } conn->state = GCS_CONN_CLOSED; conn->my_idx = -1; conn->local_act_id = GCS_SEQNO_FIRST; conn->global_seqno = 0; conn->fc_offset = 0; conn->timeout = GU_TIME_ETERNITY; conn->gcache = gcache; conn->max_fc_state = conn->params.sync_donor ? GCS_CONN_DONOR : GCS_CONN_JOINED; gu_mutex_init (&conn->fc_lock, NULL); return conn; // success sm_create_failed: gu_fifo_destroy (conn->recv_q); recv_q_failed: gcs_fifo_lite_destroy (conn->repl_q); repl_q_failed: gcs_core_destroy (conn->core); core_create_failed: fc_init_failed: _cleanup_params (conn); init_params_failed: gu_free (conn); gu_error ("Failed to create GCS connection handle."); return NULL; // failure } long gcs_init (gcs_conn_t* conn, gcs_seqno_t seqno, const uint8_t uuid[GU_UUID_LEN]) { if (GCS_CONN_CLOSED == conn->state) { return gcs_core_init (conn->core, seqno, (const gu_uuid_t*)uuid); } else { gu_error ("State must be CLOSED"); if (conn->state < GCS_CONN_CLOSED) return -EBUSY; else // DESTROYED return -EBADFD; } } /*! * Checks if we should freak out on send/recv errors. * Sometimes errors are ok, e.g. when attempting to send FC_CONT message * on a closing connection. This can happen because GCS connection state * change propagation from lower layers to upper layers is not atomic. * * @param err error code returned by send/recv function * @param warning warning to log if necessary * @return 0 if error can be ignored, original err value if not */ static long gcs_check_error (long err, const char* warning) { switch (err) { case -ENOTCONN: case -ECONNABORTED: if (NULL != warning) { gu_warn ("%s: %d (%s)", warning, err, strerror(-err)); } err = 0; break; default:; } return err; } static inline long gcs_send_fc_event (gcs_conn_t* conn, bool stop) { struct gcs_fc_event fc = { htogl(conn->conf_id), stop }; return gcs_core_send_fc (conn->core, &fc, sizeof(fc)); } /* To be called under slave queue lock. Returns true if FC_STOP must be sent */ static inline bool gcs_fc_stop_begin (gcs_conn_t* conn) { long err = 0; bool ret = (conn->stop_count <= 0 && conn->stop_sent <= 0 && conn->queue_len > (conn->upper_limit + conn->fc_offset) && conn->state <= conn->max_fc_state && !(err = gu_mutex_lock (&conn->fc_lock))); if (gu_unlikely(err)) { gu_fatal ("Mutex lock failed: %d (%s)", err, strerror(err)); abort(); } conn->stop_sent += ret; return ret; } /* Complement to gcs_fc_stop_begin. */ static inline long gcs_fc_stop_end (gcs_conn_t* conn) { long ret; gu_debug ("SENDING FC_STOP (local seqno: %lld, fc_offset: %ld)", conn->local_act_id, conn->fc_offset); ret = gcs_send_fc_event (conn, GCS_FC_STOP); if (ret >= 0) { ret = 0; conn->stats_fc_sent++; } else { conn->stop_sent--; assert (conn->stop_sent >= 0); } gu_mutex_unlock (&conn->fc_lock); ret = gcs_check_error (ret, "Failed to send FC_STOP signal"); return ret; } /* To be called under slave queue lock. Returns true if FC_CONT must be sent */ static inline bool gcs_fc_cont_begin (gcs_conn_t* conn) { long err = 0; bool queue_decreased = (conn->fc_offset > conn->queue_len && (conn->fc_offset = conn->queue_len, true)); bool ret = (conn->stop_sent > 0 && (conn->lower_limit >= conn->queue_len || queue_decreased) && conn->state <= conn->max_fc_state && !(err = gu_mutex_lock (&conn->fc_lock))); if (gu_unlikely(err)) { gu_fatal ("Mutex lock failed: %d (%s)", err, strerror(err)); abort(); } conn->stop_sent -= ret; // decrement optimistically to allow for parallel // recv threads return ret; } /* Complement to gcs_fc_cont_begin() */ static inline long gcs_fc_cont_end (gcs_conn_t* conn) { long ret; assert (GCS_CONN_DONOR >= conn->state); gu_debug ("SENDING FC_CONT (local seqno: %lld, fc_offset: %ld)", conn->local_act_id, conn->fc_offset); ret = gcs_send_fc_event (conn, GCS_FC_CONT); if (gu_likely (ret >= 0)) { ret = 0; } conn->stop_sent += (ret != 0); // fix count in case of error gu_mutex_unlock (&conn->fc_lock); ret = gcs_check_error (ret, "Failed to send FC_CONT signal"); return ret; } /* To be called under slave queue lock. Returns true if SYNC must be sent */ static inline bool gcs_send_sync_begin (gcs_conn_t* conn) { if (gu_unlikely(GCS_CONN_JOINED == conn->state)) { if (conn->lower_limit >= conn->queue_len && !conn->sync_sent) { // tripped lower slave queue limit, send SYNC message conn->sync_sent = true; return true; } #if 0 else { gu_info ("Not sending SYNC: state = %s, queue_len = %ld, " "lower_limit = %ld, sync_sent = %s", gcs_conn_state_str[conn->state], conn->queue_len, conn->lower_limit, conn->sync_sent ? "true" : "false"); } #endif } return false; } static inline long gcs_send_sync_end (gcs_conn_t* conn) { long ret = 0; gu_debug ("SENDING SYNC"); ret = gcs_core_send_sync (conn->core, 0); if (gu_likely (ret >= 0)) { ret = 0; } else { conn->sync_sent = false; } ret = gcs_check_error (ret, "Failed to send SYNC signal"); return ret; } static inline long gcs_send_sync (gcs_conn_t* conn) { if (gcs_send_sync_begin (conn)) { return gcs_send_sync_end (conn); } else { return 0; } } /*! * State transition functions - just in case we want to add something there. * @todo: need to be reworked, see #231 */ static bool gcs_shift_state (gcs_conn_t* conn, gcs_conn_state_t new_state) { static const bool allowed [GCS_CONN_STATE_MAX][GCS_CONN_STATE_MAX] = { // SYNCED JOINED DONOR JOINER PRIM OPEN CLOSED DESTR { false, true, false, false, false, false, false, false }, // SYNCED { false, false, true, true, false, false, false, false }, // JOINED { true, true, false, false, false, false, false, false }, // DONOR { false, false, false, false, true, false, false, false }, // JOINER { true, true, true, true, true, true, false, false }, // PRIMARY { true, true, true, true, true, false, true, false }, // OPEN { true, true, true, true, true, true, false, false }, // CLOSED { false, false, false, false, false, false, true, false } // DESTROYED }; gcs_conn_state_t old_state = conn->state; if (!allowed[new_state][old_state]) { if (old_state != new_state) { gu_warn ("Shifting %s -> %s is not allowed (TO: %lld)", gcs_conn_state_str[old_state], gcs_conn_state_str[new_state], conn->global_seqno); } return false; } gu_info ("Shifting %s -> %s (TO: %lld)", gcs_conn_state_str[old_state], gcs_conn_state_str[new_state], conn->global_seqno); conn->state = new_state; return true; } static void gcs_become_open (gcs_conn_t* conn) { gcs_shift_state (conn, GCS_CONN_OPEN); } static long gcs_set_pkt_size (gcs_conn_t *conn, long pkt_size) { if (conn->state != GCS_CONN_CLOSED) return -EPERM; // #600 workaround long ret = gcs_core_set_pkt_size (conn->core, pkt_size); if (ret >= 0) { conn->params.max_packet_size = ret; gu_config_set_int64 (conn->config, GCS_PARAMS_MAX_PKT_SIZE, conn->params.max_packet_size); } return ret; } static long _release_flow_control (gcs_conn_t* conn) { int err = 0; if (gu_unlikely(err = gu_mutex_lock (&conn->fc_lock))) { gu_fatal ("Mutex lock failed: %d (%s)", err, strerror(err)); abort(); } if (conn->stop_sent) { assert (1 == conn->stop_sent); conn->stop_sent--; err = gcs_fc_cont_end (conn); } else { gu_mutex_unlock (&conn->fc_lock); } return err; } static void gcs_become_primary (gcs_conn_t* conn) { if (!gcs_shift_state (conn, GCS_CONN_PRIMARY)) { gu_fatal ("Protocol violation, can't continue"); gcs_close (conn); abort(); } long ret; if ((ret = _release_flow_control (conn))) { gu_fatal ("Failed to release flow control: %ld (%s)", ret, strerror(ret)); gcs_close (conn); abort(); } } static void gcs_become_joiner (gcs_conn_t* conn) { if (!gcs_shift_state (conn, GCS_CONN_JOINER)) { gu_fatal ("Protocol violation, can't continue"); assert (0); abort(); } if (gcs_fc_init (&conn->stfc, conn->params.recv_q_hard_limit, conn->params.recv_q_soft_limit, conn->params.max_throttle)) { gu_fatal ("Becoming JOINER: FC initialization failed, can't continue."); abort(); } gcs_fc_reset (&conn->stfc, conn->recv_q_size); gcs_fc_debug (&conn->stfc, conn->params.fc_debug); } // returns 1 if accepts, 0 if rejects, negative error code if fails. static long gcs_become_donor (gcs_conn_t* conn) { if (gcs_shift_state (conn, GCS_CONN_DONOR)) { long err = 0; if (conn->max_fc_state < GCS_CONN_DONOR) { err = _release_flow_control (conn); } return (0 == err ? 1 : err); } gu_warn ("Rejecting State Transfer Request in state '%s'. " "Joiner should be restarted.", gcs_conn_state_str[conn->state]); if (conn->state < GCS_CONN_OPEN){ ssize_t err; gu_warn ("Received State Transfer Request in wrong state %s. " "Rejecting.", gcs_conn_state_str[conn->state]); // reject the request. // error handling currently is way too simplistic err = gcs_join (conn, -EPROTO); if (err < 0 && !(err == -ENOTCONN || err == -EBADFD)) { gu_fatal ("Failed to send State Transfer Request rejection: " "%zd (%s)", err, (strerror (-err))); assert (0); return -ENOTRECOVERABLE; // failed to clear donor status, } } return 0; // do not pass to application } static long _release_sst_flow_control (gcs_conn_t* conn) { long ret = 0; do { if (conn->stop_sent > 0) { ret = gcs_send_fc_event (conn, GCS_FC_CONT); conn->stop_sent -= (ret >= 0); } } while (ret < 0 && -EAGAIN == ret); // we need to send CONT here at all costs ret = gcs_check_error (ret, "Failed to release SST flow control."); return ret; } static void gcs_become_joined (gcs_conn_t* conn) { long ret; if (GCS_CONN_JOINER == conn->state) { ret = _release_sst_flow_control (conn); if (ret < 0) { gu_fatal ("Releasing SST flow control failed: %ld (%s)", ret, strerror (-ret)); abort(); } conn->timeout = GU_TIME_ETERNITY; } /* See also gcs_handle_act_conf () for a case of cluster bootstrapping */ if (gcs_shift_state (conn, GCS_CONN_JOINED)) { conn->fc_offset = conn->queue_len; conn->need_to_join = false; gu_debug("Become joined, FC offset %ld", conn->fc_offset); /* One of the cases when the node can become SYNCED */ if ((ret = gcs_send_sync (conn))) { gu_warn ("Sending SYNC failed: %ld (%s)", ret, strerror (-ret)); } } else { assert (0); } } static void gcs_become_synced (gcs_conn_t* conn) { gcs_shift_state (conn, GCS_CONN_SYNCED); conn->sync_sent = false; gu_debug("Become synced, FC offset %ld", conn->fc_offset); conn->fc_offset = 0; } /* to be called under protection of both recv_q and fc_lock */ static void _set_fc_limits (gcs_conn_t* conn) { /* Killing two birds with one stone: flat FC profile for master-slave setups * plus #440: giving single node some slack at some math correctness exp.*/ double fn = conn->params.fc_master_slave ? 1.0 : sqrt(conn->memb_num); conn->upper_limit = conn->params.fc_base_limit * fn + .5; conn->lower_limit = conn->upper_limit * conn->params.fc_resume_factor + .5; gu_info ("Flow-control interval: [%ld, %ld]", conn->lower_limit, conn->upper_limit); } /*! Handles flow control events * (this is frequent, so leave it inlined) */ static inline void gcs_handle_flow_control (gcs_conn_t* conn, const struct gcs_fc_event* fc) { if (gtohl(fc->conf_id) != (uint32_t)conn->conf_id) { // obsolete fc request return; } conn->stop_count += ((fc->stop != 0) << 1) - 1; // +1 if !0, -1 if 0 conn->stats_fc_received += (fc->stop != 0); if (1 == conn->stop_count) { gcs_sm_pause (conn->sm); // first STOP request } else if (0 == conn->stop_count) { gcs_sm_continue (conn->sm); // last CONT request } return; } static void _reset_pkt_size(gcs_conn_t* conn) { if (conn->state != GCS_CONN_CLOSED) return; // #600 workaround long ret; if (0 > (ret = gcs_core_set_pkt_size (conn->core, conn->params.max_packet_size))) { gu_warn ("Failed to set packet size: %ld (%s)", ret, strerror(-ret)); } } static long _join (gcs_conn_t* conn, gcs_seqno_t seqno) { long err; while (-EAGAIN == (err = gcs_core_send_join (conn->core, seqno))) usleep (10000); switch (err) { case -ENOTCONN: gu_warn ("Sending JOIN failed: %d (%s). " "Will retry in new primary component.", err, strerror(-err)); case 0: return 0; default: gu_error ("Sending JOIN failed: %d (%s).", err, strerror(-err)); return err; } } /*! Handles configuration action */ // TODO: this function does not provide any way for recv_thread to gracefully // exit in case of self-leave message. static void gcs_handle_act_conf (gcs_conn_t* conn, const void* action) { const gcs_act_conf_t* conf = (const gcs_act_conf_t*)action; long ret; conn->my_idx = conf->my_idx; gu_fifo_lock(conn->recv_q); { /* reset flow control as membership is most likely changed */ if (!gu_mutex_lock (&conn->fc_lock)) { conn->stop_sent = 0; conn->stop_count = 0; conn->conf_id = conf->conf_id; conn->memb_num = conf->memb_num; _set_fc_limits (conn); gu_mutex_unlock (&conn->fc_lock); } else { gu_fatal ("Failed to lock mutex."); abort(); } conn->sync_sent = false; // need to wake up send monitor if it was paused during CC gcs_sm_continue(conn->sm); } gu_fifo_release (conn->recv_q); if (conf->conf_id < 0) { if (0 == conf->memb_num) { assert (conf->my_idx < 0); gu_info ("Received SELF-LEAVE. Closing connection."); gcs_shift_state (conn, GCS_CONN_CLOSED); } else { gu_info ("Received NON-PRIMARY."); assert (GCS_NODE_STATE_NON_PRIM == conf->my_state); gcs_become_open (conn); conn->global_seqno = conf->seqno; } return; } assert (conf->conf_id >= 0); /* */ if (conf->memb_num < 1) { gu_fatal ("Internal error: PRIMARY configuration with %d nodes", conf->memb_num); abort(); } if (conf->my_idx < 0 || conf->my_idx >= conf->memb_num) { gu_fatal ("Internal error: index of this node (%d) is out of bounds: " "[%d, %d]", conf->my_idx, 0, conf->memb_num - 1); abort(); } if (conf->my_state < GCS_NODE_STATE_PRIM) { gu_fatal ("Internal error: NON-PRIM node state in PRIM configuraiton"); abort(); } /* */ conn->global_seqno = conf->seqno; /* at this point we have established protocol version, * so can set packet size */ // Ticket #600: commented out as unsafe under load _reset_pkt_size(conn); const gcs_conn_state_t old_state = conn->state; switch (conf->my_state) { case GCS_NODE_STATE_PRIM: gcs_become_primary(conn); return; /* Below are not real state transitions, rather state recovery, * so bypassing state transition matrix */ case GCS_NODE_STATE_JOINER: conn->state = GCS_CONN_JOINER; break; case GCS_NODE_STATE_DONOR: conn->state = GCS_CONN_DONOR; break; case GCS_NODE_STATE_JOINED: conn->state = GCS_CONN_JOINED; break; case GCS_NODE_STATE_SYNCED: conn->state = GCS_CONN_SYNCED; break; default: gu_fatal ("Internal error: unrecognized node state: %d", conf->my_state); abort(); } if (old_state != conn->state) { gu_info ("Restored state %s -> %s (%lld)", gcs_conn_state_str[old_state], gcs_conn_state_str[conn->state], conn->global_seqno); } switch (conn->state) { case GCS_CONN_JOINED: /* One of the cases when the node can become SYNCED */ { bool send_sync = false; gu_fifo_lock(conn->recv_q); { send_sync = gcs_send_sync_begin(conn); } gu_fifo_release (conn->recv_q); if (send_sync && (ret = gcs_send_sync_end (conn))) { gu_warn ("CC: sending SYNC failed: %ld (%s)", ret, strerror (-ret)); } } break; case GCS_CONN_JOINER: case GCS_CONN_DONOR: /* #603, #606 - duplicate JOIN msg in case we lost it */ assert (conf->conf_id >= 0); if (conn->need_to_join) _join (conn, conn->join_seqno); break; default: break; } } static long gcs_handle_act_state_req (gcs_conn_t* conn, struct gcs_act_rcvd* rcvd) { if ((gcs_seqno_t)conn->my_idx == rcvd->id) { int const donor_idx = (int)rcvd->id; // to pacify valgrind gu_debug("Got GCS_ACT_STATE_REQ to %i, my idx: %ld", donor_idx, conn->my_idx); // rewrite to pass global seqno for application rcvd->id = conn->global_seqno; return gcs_become_donor (conn); } else { if (rcvd->id >= 0) { gcs_become_joiner (conn); } return 1; // pass to gcs_request_state_transfer() caller. } } /*! Allocates buffer with malloc to pass to the upper layer. */ static long gcs_handle_state_change (gcs_conn_t* conn, const struct gcs_act* act) { gu_debug ("Got '%s' dated %lld", gcs_act_type_to_str (act->type), gcs_seqno_gtoh(*(gcs_seqno_t*)act->buf)); void* buf = malloc (act->buf_len); if (buf) { memcpy (buf, act->buf, act->buf_len); /* initially act->buf points to internal static recv buffer. No leak here */ ((struct gcs_act*)act)->buf = buf; return 1; } else { gu_fatal ("Could not allocate state change action (%zd bytes)", act->buf_len); abort(); return -ENOMEM; } } /*! * Performs work requred by action in current context. * @return negative error code, 0 if action should be discarded, 1 if should be * passed to application. */ static long gcs_handle_actions (gcs_conn_t* conn, struct gcs_act_rcvd* rcvd) { long ret = 0; switch (rcvd->act.type) { case GCS_ACT_FLOW: assert (sizeof(struct gcs_fc_event) == rcvd->act.buf_len); gcs_handle_flow_control (conn, (const gcs_fc_event*)rcvd->act.buf); break; case GCS_ACT_CONF: gcs_handle_act_conf (conn, rcvd->act.buf); ret = 1; break; case GCS_ACT_STATE_REQ: ret = gcs_handle_act_state_req (conn, rcvd); break; case GCS_ACT_JOIN: ret = gcs_handle_state_change (conn, &rcvd->act); if (gcs_seqno_gtoh(*(gcs_seqno_t*)rcvd->act.buf) < 0 && GCS_CONN_JOINER == conn->state) gcs_become_primary (conn); else gcs_become_joined (conn); break; case GCS_ACT_SYNC: ret = gcs_handle_state_change (conn, &rcvd->act); gcs_become_synced (conn); break; default: break; } return ret; } static inline void GCS_FIFO_PUSH_TAIL (gcs_conn_t* conn, ssize_t size) { conn->recv_q_size += size; gu_fifo_push_tail(conn->recv_q); } /* Returns true if timeout was handled and false otherwise */ static bool _handle_timeout (gcs_conn_t* conn) { bool ret; long long now = gu_time_calendar(); /* TODO: now the only point for timeout is flow control (#412), * later we might need to handle more timers. */ if (conn->timeout <= now) { ret = ((GCS_CONN_JOINER != conn->state) || (_release_sst_flow_control (conn) >= 0)); } else { gu_error ("Unplanned timeout! (tout: %lld, now: %lld)", conn->timeout, now); ret = false; } conn->timeout = GU_TIME_ETERNITY; return ret; } static long _check_recv_queue_growth (gcs_conn_t* conn, ssize_t size) { assert (GCS_CONN_JOINER == conn->state); long ret = 0; long long pause = gcs_fc_process (&conn->stfc, size); if (pause > 0) { /* replication needs throttling */ if (conn->stop_sent <= 0) { if ((ret = gcs_send_fc_event (conn, GCS_FC_STOP)) >= 0) { conn->stop_sent++; ret = 0; } else { ret = gcs_check_error (ret, "Failed to send SST FC_STOP."); } } if (gu_likely(pause != GU_TIME_ETERNITY)) { if (GU_TIME_ETERNITY == conn->timeout) { conn->timeout = gu_time_calendar(); } conn->timeout += pause; // we need to track pauses regardless } else if (conn->timeout != GU_TIME_ETERNITY) { conn->timeout = GU_TIME_ETERNITY; gu_warn ("Replication paused until state transfer is complete " "due to reaching hard limit on the writeset queue size."); } return ret; } else { return pause; // 0 or error code } } static long _close(gcs_conn_t* conn, bool join_recv_thread) { /* all possible races in connection closing should be resolved by * the following call, it is thread-safe */ long ret; if (gu_atomic_fetch_and_add(&conn->inner_close_count, 1) != 0) { return -EALREADY; } if (!(ret = gcs_sm_close (conn->sm))) { // we ignore return value on purpose. the reason is // we can not tell why self-leave message is generated. // there are two possible reasons. // 1. gcs_core_close is called. // 2. GCommConn::run() caught exception. (void)gcs_core_close (conn->core); if (join_recv_thread) { /* if called from gcs_close(), we need to synchronize with gcs_recv_thread at this point */ if ((ret = gu_thread_join (conn->recv_thread, NULL))) { gu_error ("Failed to join recv_thread(): %d (%s)", -ret, strerror(-ret)); } else { gu_info ("recv_thread() joined."); } /* recv_thread() is supposed to set state to CLOSED when exiting */ assert (GCS_CONN_CLOSED == conn->state); } gu_info ("Closing replication queue."); struct gcs_repl_act** act_ptr; /* At this point (state == CLOSED) no new threads should be able to * queue for repl (check gcs_repl()), and recv thread is joined, so no * new actions will be received. Abort threads that are still waiting * in repl queue */ while ((act_ptr = (struct gcs_repl_act**)gcs_fifo_lite_get_head (conn->repl_q))) { struct gcs_repl_act* act = *act_ptr; gcs_fifo_lite_pop_head (conn->repl_q); /* This will wake up repl threads in repl_q - * they'll quit on their own, * they don't depend on the conn object after waking */ gu_mutex_lock (&act->wait_mutex); gu_cond_signal (&act->wait_cond); gu_mutex_unlock (&act->wait_mutex); } gcs_fifo_lite_close (conn->repl_q); /* wake all gcs_recv() threads () */ // FIXME: this can block waiting for applicaiton threads to fetch all // items. In certain situations this can block forever. Ticket #113 gu_info ("Closing slave action queue."); gu_fifo_close (conn->recv_q); } return ret; } /* * gcs_recv_thread() receives whatever actions arrive from group, * and performs necessary actions based on action type. */ static void *gcs_recv_thread (void *arg) { gcs_conn_t* conn = (gcs_conn_t*)arg; ssize_t ret = -ECONNABORTED; // To avoid race between gcs_open() and the following state check in while() gu_cond_t tmp_cond; /* TODO: rework when concurrency in SM is allowed */ gu_cond_init (&tmp_cond, NULL); gcs_sm_enter(conn->sm, &tmp_cond, false, true); gcs_sm_leave(conn->sm); gu_cond_destroy (&tmp_cond); while (conn->state < GCS_CONN_CLOSED) { gcs_seqno_t this_act_id = GCS_SEQNO_ILL; struct gcs_repl_act** repl_act_ptr; struct gcs_act_rcvd rcvd; ret = gcs_core_recv (conn->core, &rcvd, conn->timeout); if (gu_unlikely(ret <= 0)) { if (-ETIMEDOUT == ret && _handle_timeout(conn)) continue; struct gcs_recv_act* err_act = (struct gcs_recv_act*) gu_fifo_get_tail(conn->recv_q); assert (NULL == rcvd.act.buf); assert (0 == rcvd.act.buf_len); assert (GCS_ACT_ERROR == rcvd.act.type); assert (GCS_SEQNO_ILL == rcvd.id); err_act->rcvd = rcvd; err_act->local_id = GCS_SEQNO_ILL; GCS_FIFO_PUSH_TAIL (conn, rcvd.act.buf_len); gu_debug ("gcs_core_recv returned %d: %s", ret, strerror(-ret)); break; } // gu_info ("Received action type: %d, size: %d, global seqno: %lld", // act_type, act_size, (long long)act_id); assert (rcvd.act.type < GCS_ACT_ERROR); assert (ret == rcvd.act.buf_len); if (gu_unlikely(rcvd.act.type >= GCS_ACT_STATE_REQ)) { ret = gcs_handle_actions (conn, &rcvd); if (gu_unlikely(ret < 0)) { // error gu_debug ("gcs_handle_actions returned %d: %s", ret, strerror(-ret)); break; } if (gu_likely(ret <= 0)) continue; // not for application } /* deliver to application (note matching assert in the bottom-half of * gcs_repl()) */ if (gu_likely (rcvd.act.type != GCS_ACT_TORDERED || (rcvd.id > 0 && (conn->global_seqno = rcvd.id)))) { /* successful delivery - increment local order */ this_act_id = gu_atomic_fetch_and_add(&conn->local_act_id, 1); } if (NULL != rcvd.local && (repl_act_ptr = (struct gcs_repl_act**) gcs_fifo_lite_get_head (conn->repl_q)) && (gu_likely ((*repl_act_ptr)->act_in == rcvd.local) || /* at this point repl_q is locked and we need to unlock it and * return false to fall to the 'else' branch; unlikely case */ (gcs_fifo_lite_release (conn->repl_q), false))) { /* local action from repl_q */ struct gcs_repl_act* repl_act = *repl_act_ptr; gcs_fifo_lite_pop_head (conn->repl_q); assert (repl_act->action->type == rcvd.act.type); assert (repl_act->action->size == rcvd.act.buf_len || repl_act->action->type == GCS_ACT_STATE_REQ); repl_act->action->buf = rcvd.act.buf; repl_act->action->seqno_g = rcvd.id; repl_act->action->seqno_l = this_act_id; gu_mutex_lock (&repl_act->wait_mutex); gu_cond_signal (&repl_act->wait_cond); gu_mutex_unlock (&repl_act->wait_mutex); } else if (gu_likely(this_act_id >= 0)) { /* remote/non-repl'ed action */ struct gcs_recv_act* recv_act = (struct gcs_recv_act*)gu_fifo_get_tail (conn->recv_q); if (gu_likely (NULL != recv_act)) { recv_act->rcvd = rcvd; recv_act->local_id = this_act_id; conn->queue_len = gu_fifo_length (conn->recv_q) + 1; bool send_stop = gcs_fc_stop_begin (conn); // release queue GCS_FIFO_PUSH_TAIL (conn, rcvd.act.buf_len); if (gu_unlikely(GCS_CONN_JOINER == conn->state)) { ret = _check_recv_queue_growth (conn, rcvd.act.buf_len); assert (ret <= 0); if (ret < 0) break; } if (gu_unlikely(send_stop) && (ret = gcs_fc_stop_end(conn))) { gu_error ("gcs_fc_stop() returned %d: %s", ret, strerror(-ret)); break; } } else { assert (GCS_CONN_CLOSED == conn->state); ret = -EBADFD; break; } // gu_info("Received foreign action of type %d, size %d, id=%llu, " // "action %p", rcvd.act.type, rcvd.act.buf_len, // this_act_id, rcvd.act.buf); } else if (conn->my_idx == rcvd.sender_idx) { gu_fatal("Protocol violation: unordered local action not in repl_q:" " { {%p, %zd, %s}, %ld, %lld }.", rcvd.act.buf, rcvd.act.buf_len, gcs_act_type_to_str(rcvd.act.type), rcvd.sender_idx, rcvd.id); assert(0); ret = -ENOTRECOVERABLE; break; } else { gu_fatal ("Protocol violation: unordered remote action: " "{ {%p, %zd, %s}, %ld, %lld }", rcvd.act.buf, rcvd.act.buf_len, gcs_act_type_to_str(rcvd.act.type), rcvd.sender_idx, rcvd.id); assert (0); ret = -ENOTRECOVERABLE; break; } } if (ret > 0) { ret = 0; } else if (ret < 0) { /* In case of error call _close() to release repl_q waiters. */ (void)_close(conn, false); gcs_shift_state (conn, GCS_CONN_CLOSED); } gu_info ("RECV thread exiting %d: %s", ret, strerror(-ret)); return NULL; } /* Opens connection to group */ long gcs_open (gcs_conn_t* conn, const char* channel, const char* url, bool const bootstrap) { long ret = 0; if ((ret = gcs_sm_open(conn->sm))) return ret; // open in case it is closed gu_cond_t tmp_cond; /* TODO: rework when concurrency in SM is allowed */ gu_cond_init (&tmp_cond, NULL); if ((ret = gcs_sm_enter (conn->sm, &tmp_cond, false, true))) { gu_error("Failed to enter send monitor: %d (%s)", ret, strerror(-ret)); return ret; } if (GCS_CONN_CLOSED == conn->state) { if (!(ret = gcs_core_open (conn->core, channel, url, bootstrap))) { _reset_pkt_size(conn); if (!(ret = gu_thread_create (&conn->recv_thread, NULL, gcs_recv_thread, conn))) { gcs_fifo_lite_open(conn->repl_q); gu_fifo_open(conn->recv_q); gcs_shift_state (conn, GCS_CONN_OPEN); gu_info ("Opened channel '%s'", channel); conn->inner_close_count = 0; conn->outer_close_count = 0; goto out; } else { gu_error ("Failed to create main receive thread: %ld (%s)", ret, strerror(-ret)); } gcs_core_close (conn->core); } else { gu_error ("Failed to open channel '%s' at '%s': %d (%s)", channel, url, ret, strerror(-ret)); } } else { gu_error ("Bad GCS connection state: %d (%s)", conn->state, gcs_conn_state_str[conn->state]); ret = -EBADFD; } out: gcs_sm_leave (conn->sm); gu_cond_destroy (&tmp_cond); return ret; } /* Closes group connection */ /* After it returns, application should have all time in the world to cancel * and join threads which try to access the handle, before calling gcs_destroy() * on it. */ long gcs_close (gcs_conn_t *conn) { long ret; if (gu_atomic_fetch_and_add(&conn->outer_close_count, 1) != 0) { return -EALREADY; } if ((ret = _close(conn, true)) == -EALREADY) { gu_info("recv_thread() already closing, joining thread."); /* _close() has already been called by gcs_recv_thread() and it is taking care of cleanup, just join the thread */ if ((ret = gu_thread_join (conn->recv_thread, NULL))) { gu_error ("Failed to join recv_thread(): %d (%s)", -ret, strerror(-ret)); } else { gu_info ("recv_thread() joined."); } } /* recv_thread() is supposed to set state to CLOSED when exiting */ assert (GCS_CONN_CLOSED == conn->state); return ret; } /* Frees resources associated with GCS connection handle */ long gcs_destroy (gcs_conn_t *conn) { long err; gu_cond_t tmp_cond; gu_cond_init (&tmp_cond, NULL); if ((err = gcs_sm_enter (conn->sm, &tmp_cond, false, true))) // need an error here { if (GCS_CONN_CLOSED != conn->state) { if (GCS_CONN_CLOSED > conn->state) gu_error ("Attempt to call gcs_destroy() before gcs_close(): " "state = %d", conn->state); gu_cond_destroy (&tmp_cond); return -EBADFD; } /* this should cancel all recv calls */ gu_fifo_destroy (conn->recv_q); gcs_shift_state (conn, GCS_CONN_DESTROYED); //DELETE conn->err = -EBADFD; /* we must unlock the mutex here to allow unfortunate threads * to acquire the lock and give up gracefully */ } else { gcs_sm_leave (conn->sm); gu_cond_destroy (&tmp_cond); err = -EBADFD; return err; } gu_cond_destroy (&tmp_cond); gcs_sm_destroy (conn->sm); if ((err = gcs_fifo_lite_destroy (conn->repl_q))) { gu_debug ("Error destroying repl FIFO: %d (%s)", err, strerror(-err)); return err; } if ((err = gcs_core_destroy (conn->core))) { gu_debug ("Error destroying core: %d (%s)", err, strerror(-err)); return err; } /* This must not last for long */ while (gu_mutex_destroy (&conn->fc_lock)); _cleanup_params (conn); gu_free (conn); return 0; } /* Puts action in the send queue and returns */ long gcs_sendv (gcs_conn_t* const conn, const struct gu_buf* const act_bufs, size_t const act_size, gcs_act_type_t const act_type, bool const scheduled) { if (gu_unlikely(act_size > GCS_MAX_ACT_SIZE)) return -EMSGSIZE; long ret = -ENOTCONN; /*! locking connection here to avoid race with gcs_close() * @note: gcs_repl() and gcs_recv() cannot lock connection * because they block indefinitely waiting for actions */ gu_cond_t tmp_cond; gu_cond_init (&tmp_cond, NULL); if (!(ret = gcs_sm_enter (conn->sm, &tmp_cond, scheduled, true))) { while ((GCS_CONN_OPEN >= conn->state) && (ret = gcs_core_send (conn->core, act_bufs, act_size, act_type)) == -ERESTART); gcs_sm_leave (conn->sm); gu_cond_destroy (&tmp_cond); } return ret; } long gcs_schedule (gcs_conn_t* conn) { return gcs_sm_schedule (conn->sm); } long gcs_interrupt (gcs_conn_t* conn, long handle) { return gcs_sm_interrupt (conn->sm, handle); } gcs_seqno_t gcs_caused(gcs_conn_t* conn) { return gcs_core_caused(conn->core); } /* Puts action in the send queue and returns after it is replicated */ long gcs_replv (gcs_conn_t* const conn, //!size > GCS_MAX_ACT_SIZE)) return -EMSGSIZE; long ret; assert (act); assert (act->size > 0); act->seqno_l = GCS_SEQNO_ILL; act->seqno_g = GCS_SEQNO_ILL; /* This is good - we don't have to do a copy because we wait */ struct gcs_repl_act repl_act(act_in, act); gu_mutex_init (&repl_act.wait_mutex, NULL); gu_cond_init (&repl_act.wait_cond, NULL); /* Send action and wait for signal from recv_thread * we need to lock a mutex before we can go wait for signal */ if (!(ret = gu_mutex_lock (&repl_act.wait_mutex))) { // Lock here does the following: // 1. serializes gcs_core_send() access between gcs_repl() and // gcs_send() // 2. avoids race with gcs_close() and gcs_destroy() if (!(ret = gcs_sm_enter (conn->sm, &repl_act.wait_cond, scheduled, true))) { struct gcs_repl_act** act_ptr; //#ifndef NDEBUG const void* const orig_buf = act->buf; //#endif // some hack here to achieve one if() instead of two: // ret = -EAGAIN part is a workaround for #569 // if (conn->state >= GCS_CONN_CLOSE) or (act_ptr == NULL) // ret will be -ENOTCONN if ((ret = -EAGAIN, conn->upper_limit >= conn->queue_len || act->type != GCS_ACT_TORDERED) && (ret = -ENOTCONN, GCS_CONN_OPEN >= conn->state) && (act_ptr = (struct gcs_repl_act**)gcs_fifo_lite_get_tail (conn->repl_q))) { *act_ptr = &repl_act; gcs_fifo_lite_push_tail (conn->repl_q); // Keep on trying until something else comes out while ((ret = gcs_core_send (conn->core, act_in, act->size, act->type)) == -ERESTART) {} if (ret < 0) { /* remove item from the queue, it will never be delivered */ gu_warn ("Send action {%p, %zd, %s} returned %d (%s)", act->buf, act->size,gcs_act_type_to_str(act->type), ret, strerror(-ret)); if (!gcs_fifo_lite_remove (conn->repl_q)) { gu_fatal ("Failed to remove unsent item from repl_q"); assert(0); ret = -ENOTRECOVERABLE; } } else { assert (ret == (ssize_t)act->size); } } gcs_sm_leave (conn->sm); assert(ret); /* now we can go waiting for action delivery */ if (ret >= 0) { gu_cond_wait (&repl_act.wait_cond, &repl_act.wait_mutex); #ifndef GCS_FOR_GARB /* assert (act->buf != 0); */ if (act->buf == 0) { /* Recv thread purged repl_q before action was delivered */ ret = -ENOTCONN; goto out; } #else assert (act->buf == 0); #endif /* GCS_FOR_GARB */ if (act->seqno_g < 0) { assert (GCS_SEQNO_ILL == act->seqno_l || GCS_ACT_TORDERED != act->type); if (act->seqno_g == GCS_SEQNO_ILL) { /* action was not replicated for some reason */ assert (orig_buf == act->buf); ret = -EINTR; } else { /* core provided an error code in global seqno */ assert (orig_buf != act->buf); ret = act->seqno_g; act->seqno_g = GCS_SEQNO_ILL; } if (orig_buf != act->buf) // action was allocated in gcache { gu_debug("Freeing gcache buffer %p after receiving %d", act->buf, ret); gcs_gcache_free (conn->gcache, act->buf); act->buf = orig_buf; } } } } #ifndef GCS_FOR_GARB out: #endif /* GCS_FOR_GARB */ gu_mutex_unlock (&repl_act.wait_mutex); } gu_mutex_destroy (&repl_act.wait_mutex); gu_cond_destroy (&repl_act.wait_cond); #ifdef GCS_DEBUG_GCS // gu_debug ("\nact_size = %u\nact_type = %u\n" // "act_id = %llu\naction = %p (%s)\n", // act->size, act->type, act->seqno_g, act->buf, act->buf); #endif return ret; } long gcs_request_state_transfer (gcs_conn_t *conn, int version, const void *req, size_t size, const char *donor, const gu_uuid_t* ist_uuid, gcs_seqno_t ist_seqno, gcs_seqno_t *local) { long ret = -ENOMEM; size_t donor_len = strlen(donor) + 1; // include terminating \0 size_t rst_size = size + donor_len + sizeof(*ist_uuid) + sizeof(ist_seqno) + 2; // for simplicity, allocate maximum space what we need here. char* rst = (char*)gu_malloc (rst_size); *local = GCS_SEQNO_ILL; if (rst) { gu_debug("ist_uuid[" GU_UUID_FORMAT "], ist_seqno[%lld]", GU_UUID_ARGS(ist_uuid), (long long)ist_seqno); int offset = 0; // version 0,1 /* RST format: |donor name|\0|app request| * anything more complex will require a special (de)serializer. * NOTE: this is sender part. Check gcs_group_handle_state_request() * for the receiver part. */ if (version < 2) { memcpy (rst + offset, donor, donor_len); offset += donor_len; memcpy (rst + offset, req, size); rst_size = size + donor_len; } // version 2(expose joiner's seqno and smart donor selection) // RST format: |donor_name|\0|'V'|version|ist_uuid|ist_seqno|app_request| // we expect 'version' could be hold by 'char' // since app_request v0 starts with sst method name // and app_request v1 starts with 'STRv1' // and ist_uuid starts with hex character in lower case. // it's safe to use 'V' as separator. else { memcpy (rst + offset, donor, donor_len); offset += donor_len; rst[offset++] = 'V'; rst[offset++] = (char)version; memcpy (rst + offset, ist_uuid, sizeof(*ist_uuid)); offset += sizeof(*ist_uuid); *(gcs_seqno_t*) (rst + offset) = gcs_seqno_htog(ist_seqno); offset += sizeof(ist_seqno); memcpy (rst + offset, req, size); } struct gcs_action action; action.buf = rst; action.size = (ssize_t)rst_size; action.type = GCS_ACT_STATE_REQ; ret = gcs_repl(conn, &action, false); gu_free (rst); *local = action.seqno_l; if (ret > 0) { assert (action.buf != rst); #ifndef GCS_FOR_GARB assert (action.buf != NULL); gcs_gcache_free (conn->gcache, action.buf); #else assert (action.buf == NULL); #endif assert (ret == (ssize_t)rst_size); assert (action.seqno_g >= 0); assert (action.seqno_l > 0); // on joiner global seqno stores donor index // on donor global seqno stores global seqno ret = action.seqno_g; } else { assert (/*action.buf == NULL ||*/ action.buf == rst); } } return ret; } long gcs_desync (gcs_conn_t* conn, gcs_seqno_t* local) { gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; // for desync operation we use the lowest str_version. long ret = gcs_request_state_transfer (conn, 0, "", 1, GCS_DESYNC_REQ, &ist_uuid, ist_seqno, local); if (ret >= 0) { return 0; } else { return ret; } } static inline void GCS_FIFO_POP_HEAD (gcs_conn_t* conn, ssize_t size) { assert (conn->recv_q_size >= size); conn->recv_q_size -= size; gu_fifo_pop_head (conn->recv_q); } /* Returns when an action from another process is received */ long gcs_recv (gcs_conn_t* conn, struct gcs_action* action) { int err; struct gcs_recv_act* recv_act = NULL; assert (action); if ((recv_act = (struct gcs_recv_act*)gu_fifo_get_head (conn->recv_q, &err))) { conn->queue_len = gu_fifo_length (conn->recv_q) - 1; bool send_cont = gcs_fc_cont_begin (conn); bool send_sync = gcs_send_sync_begin (conn); action->buf = (void*)recv_act->rcvd.act.buf; action->size = recv_act->rcvd.act.buf_len; action->type = recv_act->rcvd.act.type; action->seqno_g = recv_act->rcvd.id; action->seqno_l = recv_act->local_id; if (gu_unlikely (GCS_ACT_CONF == action->type)) { err = gu_fifo_cancel_gets (conn->recv_q); if (err) { gu_fatal ("Internal logic error: failed to cancel recv_q " "\"gets\": %d (%s). Aborting.", err, strerror(-err)); gu_abort(); } } GCS_FIFO_POP_HEAD (conn, action->size); // release the queue if (gu_unlikely(send_cont) && (err = gcs_fc_cont_end(conn))) { // We have successfully received an action, but failed to send // important control message. What do we do? Inability to send CONT // can block the whole cluster. There are only conn->queue_len - 1 // attempts to do that (that's how many times we'll get here). // Perhaps if the last attempt fails, we should crash. if (conn->queue_len > 0) { gu_warn ("Failed to send CONT message: %d (%s). " "Attempts left: %ld", err, strerror(-err), conn->queue_len); } else { gu_fatal ("Last opportunity to send CONT message failed: " "%d (%s). Aborting to avoid cluster lock-up...", err, strerror(-err)); gcs_close(conn); gu_abort(); } } else if (gu_unlikely(send_sync) && (err = gcs_send_sync_end (conn))) { gu_warn ("Failed to send SYNC message: %d (%s). Will try later.", err, strerror(-err)); } return action->size; } else { action->buf = NULL; action->size = 0; action->type = GCS_ACT_ERROR; action->seqno_g = GCS_SEQNO_ILL; action->seqno_l = GCS_SEQNO_ILL; switch (err) { case -ENODATA: assert (GCS_CONN_CLOSED == conn->state); return GCS_CLOSED_ERROR; default: return err; } } } long gcs_resume_recv (gcs_conn_t* conn) { int ret = GCS_CLOSED_ERROR; ret = gu_fifo_resume_gets (conn->recv_q); if (ret) { if (conn->state < GCS_CONN_CLOSED) { gu_fatal ("Internal logic error: failed to resume \"gets\" on " "recv_q: %d (%s). Aborting.", ret, strerror (-ret)); gcs_close (conn); gu_abort(); } else { ret = GCS_CLOSED_ERROR; } } return ret; } long gcs_wait (gcs_conn_t* conn) { if (gu_likely(GCS_CONN_SYNCED == conn->state)) { return (conn->stop_count > 0 || (conn->queue_len > conn->upper_limit)); } else { switch (conn->state) { case GCS_CONN_OPEN: return -ENOTCONN; case GCS_CONN_CLOSED: case GCS_CONN_DESTROYED: return GCS_CLOSED_ERROR; default: return -EAGAIN; // wait until get sync } } } long gcs_conf_set_pkt_size (gcs_conn_t *conn, long pkt_size) { if (conn->params.max_packet_size == pkt_size) return pkt_size; return gcs_set_pkt_size (conn, pkt_size); } long gcs_set_last_applied (gcs_conn_t* conn, gcs_seqno_t seqno) { gu_cond_t cond; gu_cond_init (&cond, NULL); long ret = gcs_sm_enter (conn->sm, &cond, false, false); if (!ret) { ret = gcs_core_set_last_applied (conn->core, seqno); gcs_sm_leave (conn->sm); } gu_cond_destroy (&cond); return ret; } long gcs_join (gcs_conn_t* conn, gcs_seqno_t seqno) { conn->join_seqno = seqno; conn->need_to_join = true; return _join (conn, seqno); } gcs_seqno_t gcs_local_sequence(gcs_conn_t* conn) { return gu_atomic_fetch_and_add(&conn->local_act_id, 1); } void gcs_get_stats (gcs_conn_t* conn, struct gcs_stats* stats) { gu_fifo_stats_get (conn->recv_q, &stats->recv_q_len, &stats->recv_q_len_max, &stats->recv_q_len_min, &stats->recv_q_len_avg); stats->recv_q_size = conn->recv_q_size; gcs_sm_stats_get (conn->sm, &stats->send_q_len, &stats->send_q_len_max, &stats->send_q_len_min, &stats->send_q_len_avg, &stats->fc_paused_ns, &stats->fc_paused_avg); stats->fc_sent = conn->stats_fc_sent; stats->fc_received = conn->stats_fc_received; } void gcs_flush_stats(gcs_conn_t* conn) { gu_fifo_stats_flush(conn->recv_q); gcs_sm_stats_flush (conn->sm); conn->stats_fc_sent = 0; conn->stats_fc_received = 0; } void gcs_get_status(gcs_conn_t* conn, gu::Status& status) { if (conn->state < GCS_CONN_CLOSED) { gcs_core_get_status(conn->core, status); } } static long _set_fc_limit (gcs_conn_t* conn, const char* value) { long long limit; const char* const endptr = gu_str2ll(value, &limit); if (limit > 0LL && *endptr == '\0') { if (limit > LONG_MAX) limit = LONG_MAX; gu_fifo_lock(conn->recv_q); { if (!gu_mutex_lock (&conn->fc_lock)) { conn->params.fc_base_limit = limit; _set_fc_limits (conn); gu_config_set_int64 (conn->config, GCS_PARAMS_FC_LIMIT, conn->params.fc_base_limit); gu_mutex_unlock (&conn->fc_lock); } else { gu_fatal ("Failed to lock mutex."); abort(); } } gu_fifo_release (conn->recv_q); return 0; } else { return -EINVAL; } } static long _set_fc_factor (gcs_conn_t* conn, const char* value) { double factor; const char* const endptr = gu_str2dbl(value, &factor); if (factor >= 0.0 && factor <= 1.0 && *endptr == '\0') { if (factor == conn->params.fc_resume_factor) return 0; gu_fifo_lock(conn->recv_q); { if (!gu_mutex_lock (&conn->fc_lock)) { conn->params.fc_resume_factor = factor; _set_fc_limits (conn); gu_config_set_double (conn->config, GCS_PARAMS_FC_FACTOR, conn->params.fc_resume_factor); gu_mutex_unlock (&conn->fc_lock); } else { gu_fatal ("Failed to lock mutex."); abort(); } } gu_fifo_release (conn->recv_q); return 0; } else { return -EINVAL; } } static long _set_fc_debug (gcs_conn_t* conn, const char* value) { bool debug; const char* const endptr = gu_str2bool(value, &debug); if (*endptr == '\0') { if (conn->params.fc_debug == debug) return 0; conn->params.fc_debug = debug; gcs_fc_debug (&conn->stfc, debug); gu_config_set_bool (conn->config, GCS_PARAMS_FC_DEBUG, debug); return 0; } else { return -EINVAL; } } static long _set_sync_donor (gcs_conn_t* conn, const char* value) { bool sd; const char* const endptr = gu_str2bool (value, &sd); if (endptr[0] != '\0') return -EINVAL; if (conn->params.sync_donor != sd) { conn->params.sync_donor = sd; conn->max_fc_state = sd ? GCS_CONN_DONOR : GCS_CONN_JOINED; } return 0; } static long _set_pkt_size (gcs_conn_t* conn, const char* value) { long long pkt_size; const char* const endptr = gu_str2ll (value, &pkt_size); if (pkt_size > 0 && *endptr == '\0') { if (pkt_size > LONG_MAX) pkt_size = LONG_MAX; if (conn->params.max_packet_size == pkt_size) return 0; long ret = gcs_set_pkt_size (conn, pkt_size); if (ret >= 0) { ret = 0; gu_config_set_int64(conn->config,GCS_PARAMS_MAX_PKT_SIZE,pkt_size); } return ret; } else { // gu_warn ("Invalid value for %s: '%s'", GCS_PARAMS_PKT_SIZE, value); return -EINVAL; } } static long _set_recv_q_hard_limit (gcs_conn_t* conn, const char* value) { long long limit; const char* const endptr = gu_str2ll (value, &limit); if (limit > 0 && *endptr == '\0') { if (limit > LONG_MAX) limit = LONG_MAX; long long limit_fixed = limit * gcs_fc_hard_limit_fix; if (conn->params.recv_q_hard_limit == limit_fixed) return 0; gu_config_set_int64 (conn->config, GCS_PARAMS_RECV_Q_HARD_LIMIT, limit); conn->params.recv_q_hard_limit = limit_fixed; return 0; } else { return -EINVAL; } } static long _set_recv_q_soft_limit (gcs_conn_t* conn, const char* value) { double dbl; const char* const endptr = gu_str2dbl (value, &dbl); if (dbl >= 0.0 && dbl < 1.0 && *endptr == '\0') { if (dbl == conn->params.recv_q_soft_limit) return 0; gu_config_set_double (conn->config, GCS_PARAMS_RECV_Q_SOFT_LIMIT, dbl); conn->params.recv_q_soft_limit = dbl; return 0; } else { return -EINVAL; } } static long _set_max_throttle (gcs_conn_t* conn, const char* value) { double dbl; const char* const endptr = gu_str2dbl (value, &dbl); if (dbl >= 0.0 && dbl < 1.0 && *endptr == '\0') { if (dbl == conn->params.max_throttle) return 0; gu_config_set_double (conn->config, GCS_PARAMS_MAX_THROTTLE, dbl); conn->params.max_throttle = dbl; return 0; } else { return -EINVAL; } } bool gcs_register_params (gu_config_t* const conf) { return (gcs_params_register (conf) | gcs_core_register (conf)); } long gcs_param_set (gcs_conn_t* conn, const char* key, const char *value) { if (!strcmp (key, GCS_PARAMS_FC_LIMIT)) { return _set_fc_limit (conn, value); } else if (!strcmp (key, GCS_PARAMS_FC_FACTOR)) { return _set_fc_factor (conn, value); } else if (!strcmp (key, GCS_PARAMS_FC_DEBUG)) { return _set_fc_debug (conn, value); } else if (!strcmp (key, GCS_PARAMS_SYNC_DONOR)) { return _set_sync_donor (conn, value); } else if (!strcmp (key, GCS_PARAMS_MAX_PKT_SIZE)) { return _set_pkt_size (conn, value); } else if (!strcmp (key, GCS_PARAMS_RECV_Q_HARD_LIMIT)) { return _set_recv_q_hard_limit (conn, value); } else if (!strcmp (key, GCS_PARAMS_RECV_Q_SOFT_LIMIT)) { return _set_recv_q_soft_limit (conn, value); } else if (!strcmp (key, GCS_PARAMS_MAX_THROTTLE)) { return _set_max_throttle (conn, value); } else { return gcs_core_param_set (conn->core, key, value); } } const char* gcs_param_get (gcs_conn_t* conn, const char* key) { gu_warn ("Not implemented: %s", __FUNCTION__); return NULL; } percona-galera-3-3.8-3390/gcs/src/gcs.hpp000066400000000000000000000425441244131713600176430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /*! * @file gcs.c Public GCS API */ #ifndef _gcs_h_ #define _gcs_h_ #include #include #include #include #include "gu_config.h" #include "gu_buf.h" #include "gcache.h" #include "gu_errno.h" #include "gu_uuid.h" #include "gu_status.hpp" /*! @typedef @brief Sequence number type. */ typedef int64_t gcs_seqno_t; /*! @def @brief Illegal sequence number. Action not serialized. */ static const gcs_seqno_t GCS_SEQNO_ILL = -1; /*! @def @brief Empty state. No actions applied. */ static const gcs_seqno_t GCS_SEQNO_NIL = 0; /*! @def @brief Start of the sequence */ static const gcs_seqno_t GCS_SEQNO_FIRST = 1; /*! @def @brief history UUID length */ #define GCS_UUID_LEN 16 /*! @def @brief maximum supported size of an action (2GB - 1) */ #define GCS_MAX_ACT_SIZE 0x7FFFFFFF /*! Connection handle type */ typedef struct gcs_conn gcs_conn_t; /*! @brief Creates GCS connection handle. * * @param conf gu_config_t* configuration object, can be null. * @param cache pointer to the gcache object. * @param node_name human readable name of the node, can be null. * @param inc_addr address at which application accepts incoming requests. * Used for load balancing, can be null. * @param repl_proto_ver max replicator protocol version. * @param appl_proto_ver max application ptotocol version. * @return pointer to GCS connection handle, NULL in case of failure. */ extern gcs_conn_t* gcs_create (gu_config_t* conf, gcache_t* cache, const char* node_name, const char* inc_addr, int repl_proto_ver, int appl_proto_ver); /*! @brief Initialize group history values (optional). * Serves to provide group history persistence after process restart (in case * these data were saved somewhere on persistent storage or the like). If these * values are provided, it is only a hint for the group, as they might be * outdated. Actual seqno and UUID are returned in GCS_ACT_CONF action (see * below) and are determined by quorum. * * This function must be called before gcs_open() or after gcs_close(). * * @param seqno Sequence number of the application state (last action applied). * Should be negative for undefined state. * @param uuid UUID of the sequence (group ID). * Should be all zeroes for undefined state. * * @return 0 in case of success, -EBUSY if conneciton is already opened, * -EBADFD if connection object is being destroyed. */ extern long gcs_init (gcs_conn_t *conn, gcs_seqno_t seqno, const uint8_t uuid[GCS_UUID_LEN]); /*! @brief Opens connection to group (joins channel). * * @param conn connection object * @param channel a name of the channel to join. It must uniquely identify * the channel. If the channel with such name does not exist, * it is created. Processes that joined the same channel * receive the same actions. * @param url an URL-like string that specifies backend communication * driver in the form "TYPE://ADDRESS?options". For gcomm * backend it can be "gcomm://localhost:4567", for dummy backend * ADDRESS field is ignored. * Currently supported backend types: "dummy", "vsbes", "gcomm" * @param bootstrap bootstrap a new group * * @return negative error code, 0 in case of success. */ extern long gcs_open (gcs_conn_t *conn, const char *channel, const char *url, bool bootstrap); /*! @brief Closes connection to group. * * @param conn connection handle * @return negative error code or 0 in case of success. */ extern long gcs_close (gcs_conn_t *conn); /*! @brief Frees resources associuated with connection handle. * * @param conn connection handle * @return negative error code or 0 in case of success. */ extern long gcs_destroy (gcs_conn_t *conn); /*! @brief Deprecated. Waits until the group catches up. * This call checks if any member of the group (including this one) has a * long slave queue. Should be called before gcs_repl(), gcs_send(). * * @return negative error code, 1 if wait is required, 0 otherwise */ extern long gcs_wait (gcs_conn_t *conn); /*! @typedef @brief Action types. * There is a conceptual difference between "messages" * and "actions". Messages are ELEMENTARY pieces of information * atomically delivered by group communication. They are typically * limited in size to a single IP packet. Events generated by group * communication layer must be delivered as a single message. * * For the purpose of this work "action" is a higher level concept * introduced to overcome the message size limitation. Application * replicates information in actions of ARBITRARY size that are * fragmented into as many messages as needed. As such actions * can be delivered only in primary configuration, when total order * of underlying messages is established. * The best analogy for action/message concept would be word/letter. * * The purpose of GCS library is to hide message handling from application. * Therefore application deals only with "actions". * Application can only send actions of types GCS_ACT_TORDERED, * GCS_ACT_COMMIT_CUT and GCS_ACT_STATE_REQ. * Actions of type GCS_ACT_SYNC, GCS_ACT_CONF are generated by the library. */ typedef enum gcs_act_type { /* ordered actions */ GCS_ACT_TORDERED, //! action representing state change, will be assigned // global seqno GCS_ACT_COMMIT_CUT, //! group-wide action commit cut GCS_ACT_STATE_REQ, //! request for state transfer GCS_ACT_CONF, //! new configuration GCS_ACT_JOIN, //! joined group (received all state data) GCS_ACT_SYNC, //! synchronized with group GCS_ACT_FLOW, //! flow control GCS_ACT_SERVICE, //! service action, sent by GCS GCS_ACT_ERROR, //! error happened while receiving the action GCS_ACT_UNKNOWN //! undefined/unknown action type } gcs_act_type_t; /*! String representations of action types */ extern const char* gcs_act_type_to_str(gcs_act_type_t); /*! @brief Sends a vector of buffers as a single action to group and returns. * A copy of action will be returned through gcs_recv() call, or discarded * in case it is not delivered by group. * For a better means to replicate an action see gcs_repl(). @see gcs_repl() * * @param conn group connection handle * @param act_bufs action buffer vector * @param act_size total action size (the sum of buffer sizes) * @param act_type action type * @param scheduled whether the call was scheduled by gcs_schedule() * @return negative error code, action size in case of success * @retval -EINTR thread was interrupted while waiting to enter the monitor */ extern long gcs_sendv (gcs_conn_t* conn, const struct gu_buf* act_bufs, size_t act_size, gcs_act_type_t act_type, bool scheduled); /*! A wrapper for single buffer communication */ static inline long gcs_send (gcs_conn_t* const conn, const void* const act, size_t const act_size, gcs_act_type_t const act_type, bool const scheduled) { struct gu_buf const buf = { act, static_cast(act_size) }; return gcs_sendv (conn, &buf, act_size, act_type, scheduled); } /*!*/ struct gcs_action { const void* buf; /*! unlike input, output goes as a single buffer */ ssize_t size; gcs_seqno_t seqno_g; gcs_seqno_t seqno_l; gcs_act_type_t type; }; /*! @brief Replicates a vector of buffers as a single action. * Sends action to group and blocks until it is received. Upon return global * and local IDs are set. Arguments are the same as in gcs_recv(). * @see gcs_recv() * * @param conn group connection handle * @param act_in action buffer vector (total size is passed in action) * @param action action struct * @param scheduled whether the call was preceded by gcs_schedule() * @return negative error code, action size in case of success * @retval -EINTR: thread was interrupted while waiting to enter the monitor */ extern long gcs_replv (gcs_conn_t* conn, const struct gu_buf* act_in, struct gcs_action* action, bool scheduled); /*! A wrapper for single buffer communication */ static inline long gcs_repl (gcs_conn_t* const conn, struct gcs_action* const action, bool const scheduled) { struct gu_buf const buf = { action->buf, action->size }; return gcs_replv (conn, &buf, action, scheduled); } /*! @brief Receives an action from group. * Blocks if no actions are available. Action buffer is allocated by GCS * and must be freed by application when action is no longer needed. * Also sets global and local action IDs. Global action ID uniquely identifies * action in the history of the group and can be used to identify the state * of the application for state snapshot purposes. Local action ID is a * monotonic gapless number sequence starting with 1 which can be used * to serialize access to critical sections. * * @param conn group connection handle * @param action action object * @return negative error code, action size in case of success, * @retval 0 on connection close */ extern long gcs_recv (gcs_conn_t* conn, struct gcs_action* action); /*! * @brief Schedules entry to CGS send monitor. * Locks send monitor and should be quickly followed by gcs_repl()/gcs_send() * * @retval 0 - won't queue * @retval >0 - queue handle * @retval -EAGAIN - too many queued threads * @retval -EBADFD - connection is closed */ extern long gcs_schedule (gcs_conn_t* conn); /*! * @brief Interrupt a thread waiting to enter send monitor. * * @param conn GCS connection * @param handle queue handle returned by @func gcs_schedule(). Must be > 0 * * @retval 0 success * @retval -ESRCH no such thread/already interrupted */ extern long gcs_interrupt (gcs_conn_t* conn, long handle); /*! * Resume receivng from group. * * @param conn GCS connection * * @retval 0 success * @retval -EBADFD connection is in closed state */ extern long gcs_resume_recv (gcs_conn_t* conn); /*! * After action with this seqno is applied, this thread is guaranteed to see * all the changes made by the client, even on other nodes. * * @return global sequence number or negative error code */ extern gcs_seqno_t gcs_caused(gcs_conn_t* conn); /*! @brief Sends state transfer request * Broadcasts state transfer request which will be passed to one of the * suitable group members. * * @param conn connection to group * @param ver STR version. * @param req opaque byte array that contains data required for * the state transfer (application dependent) * @param size request size * @param donor desired state transfer donor name. Supply empty string to * choose automatically. * @param seqno response to request was ordered with this seqno. * Must be skipped in local queues. * @return negative error code, index of state transfer donor in case of success * (notably, -EAGAIN means try later, -EHOSTUNREACH means desired donor * is unavailable) */ extern long gcs_request_state_transfer (gcs_conn_t *conn, int ver, const void *req, size_t size, const char *donor, const gu_uuid_t* ist_uuid, gcs_seqno_t ist_seqno, gcs_seqno_t *seqno); /*! @brief Turns off flow control on the node. * Effectively desynchronizes the node from the cluster (while the node keeps on * receiving all the actions). Requires gcs_join() to return to normal. * * @param conn connection to group * @param seqno response to request was ordered with this seqno. * Must be skipped in local queues. * @return negative error code, 0 in case of success. */ extern long gcs_desync (gcs_conn_t* conn, gcs_seqno_t* seqno); /*! @brief Informs group on behalf of donor that state stransfer is over. * If status is non-negative, joiner will be considered fully joined to group. * * @param conn opened connection to group * @param status negative error code in case of state transfer failure, * 0 or (optional) seqno corresponding to transferred state. * @return negative error code, 0 in case of success */ extern long gcs_join (gcs_conn_t *conn, gcs_seqno_t status); /*! @brief Allocate local seqno for accessing local resources. * * * @param conn connection to group * @return local seqno, negative error code in case of error */ extern gcs_seqno_t gcs_local_sequence(gcs_conn_t* conn); /////////////////////////////////////////////////////////////////////////////// /* Service functions */ /*! Informs group about the last applied action on this node */ extern long gcs_set_last_applied (gcs_conn_t* conn, gcs_seqno_t seqno); /* GCS Configuration */ /*! Registers configurable parameters with conf object * @return false if success, true if error happened */ extern bool gcs_register_params (gu_config_t* conf); /*! sets the key to a given value * * @return 0 in case of success, 1 if key not found or negative error code */ extern long gcs_param_set (gcs_conn_t* conn, const char* key, const char *value); /*! returns the value of the key * * @return NULL if key not found */ extern const char* gcs_param_get (gcs_conn_t* conn, const char* key); /* Logging options */ extern long gcs_conf_set_log_file (FILE *file); extern long gcs_conf_set_log_callback (void (*logger) (int, const char*)); extern long gcs_conf_self_tstamp_on (); extern long gcs_conf_self_tstamp_off (); extern long gcs_conf_debug_on (); extern long gcs_conf_debug_off (); /* Sending options (deprecated, use gcs_param_set instead) */ /* Sets maximum DESIRED network packet size. * For best results should be multiple of MTU */ extern long gcs_conf_set_pkt_size (gcs_conn_t *conn, long pkt_size); #define GCS_DEFAULT_PKT_SIZE 64500 /* 43 Eth. frames to carry max IP packet */ /* * Configuration action */ /*! Possible node states */ typedef enum gcs_node_state { GCS_NODE_STATE_NON_PRIM, /// in non-primary configuration, outdated state GCS_NODE_STATE_PRIM, /// in primary conf, needs state transfer GCS_NODE_STATE_JOINER, /// in primary conf, receiving state transfer GCS_NODE_STATE_DONOR, /// joined, donating state transfer GCS_NODE_STATE_JOINED, /// contains full state GCS_NODE_STATE_SYNCED, /// syncronized with group GCS_NODE_STATE_MAX } gcs_node_state_t; /*! Convert state code to null-terminates string */ extern const char* gcs_node_state_to_str (gcs_node_state_t state); /*! New configuration action */ typedef struct gcs_act_conf { gcs_seqno_t seqno; //! last global seqno applied by this group gcs_seqno_t conf_id; //! configuration ID (-1 if non-primary) uint8_t uuid[GCS_UUID_LEN];/// group UUID long memb_num; //! number of members in configuration long my_idx; //! index of this node in the configuration gcs_node_state_t my_state; //! current node state int repl_proto_ver; //! replicator protocol version to use int appl_proto_ver; //! application protocol version to use char data[1]; /*! member array (null-terminated ID, name, * incoming address, 8-byte cached seqno) */ } gcs_act_conf_t; typedef struct gcs_backend_stats { struct stats_t { const char* key; const char* value; }* stats; void* ctx; } gcs_backend_stats_t; struct gcs_stats { double send_q_len_avg; //! average send queue length per send call double recv_q_len_avg; //! average recv queue length per queued action long long fc_paused_ns; //! total nanoseconds spent in paused state double fc_paused_avg; //! faction of time paused due to flow control long long fc_sent; //! flow control stops sent long long fc_received; //! flow control stops received size_t recv_q_size; //! current recv queue size int recv_q_len; //! current recv queue length int recv_q_len_max; //! maximum recv queue length int recv_q_len_min; //! minimum recv queue length int send_q_len; //! current send queue length int send_q_len_max; //! maximum send queue length int send_q_len_min; //! minimum send queue length gcs_backend_stats_t backend_stats; //! backend stats. }; /*! Fills stats struct */ extern void gcs_get_stats (gcs_conn_t *conn, struct gcs_stats* stats); /*! flushes stats counters */ extern void gcs_flush_stats(gcs_conn_t *conn); void gcs_get_status(gcs_conn_t* conn, gu::Status& status); /*! A node with this name will be treated as a stateless arbitrator */ #define GCS_ARBITRATOR_NAME "garb" #endif // _gcs_h_ percona-galera-3-3.8-3390/gcs/src/gcs_act.hpp000066400000000000000000000016621244131713600204660ustar00rootroot00000000000000/* * Copyright (C) 2008-2011 Codership Oy * * $Id$ */ #ifndef _gcs_act_h_ #define _gcs_act_h_ #include "gcs.hpp" struct gcs_act { const void* buf; ssize_t buf_len; gcs_act_type_t type; gcs_act() { } gcs_act(const void* b, ssize_t bl, gcs_act_type_t t) : buf(b), buf_len(bl), type(t) { } gcs_act(const gcs_act& a) : buf(a.buf), buf_len(a.buf_len), type(a.type) { } }; struct gcs_act_rcvd { struct gcs_act act; const struct gu_buf* local; // local buffer vector if any gcs_seqno_t id; // global total order seqno int sender_idx; gcs_act_rcvd() { } gcs_act_rcvd(const gcs_act& a, const struct gu_buf* loc, gcs_seqno_t i, int si) : act(a), local(loc), id(i), sender_idx(si) { } }; #endif /* _gcs_act_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_act_proto.cpp000066400000000000000000000077051244131713600217100ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /* * Interface to action protocol * (to be extended to support protocol versions, currently supports only v0) */ #include #include "gcs_act_proto.hpp" /* Version 0 header structure bytes: 00 01 07 08 11 12 15 16 19 20 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--- |PV| act_id | act_size | frag_no |AT|reserved| data... +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--- PV - protocol version AT - action type */ static const size_t PROTO_PV_OFFSET = 0; static const size_t PROTO_ACT_ID_OFFSET = 0; static const size_t PROTO_ACT_SIZE_OFFSET = 8; static const size_t PROTO_FRAG_NO_OFFSET = 12; static const size_t PROTO_AT_OFFSET = 16; static const size_t PROTO_DATA_OFFSET = 20; static const gcs_seqno_t PROTO_ACT_ID_MAX = 0x00FFFFFFFFFFFFLL; static const unsigned int PROTO_FRAG_NO_MAX = 0xFFFFFFFF; static const unsigned char PROTO_AT_MAX = 0xFF; static const int PROTO_VERSION = GCS_ACT_PROTO_MAX; #define PROTO_MAX_HDR_SIZE PROTO_DATA_OFFSET // for now /*! Writes header data into actual header of the message. * Remainig fragment buf and length is in frag->frag and frag->frag_len * * @return 0 on success */ long gcs_act_proto_write (gcs_act_frag_t* frag, void* buf, size_t buf_len) { #ifdef GCS_DEBUG_PROTO if ((frag->act_id > PROTO_ACT_ID_MAX) || (frag->act_size > GCS_MAX_ACT_SIZE) || (frag->frag_no > PROTO_FRAG_NO_MAX) || (frag->act_type > PROTO_AT_MAX)) { gu_error ("Exceeded protocol limits: %d(%d), %d(%d), %d(%d), %d(%d)", frag->act_id, PROTO_ACT_ID_MAX, frag->act_size, GCS_MAX_ACT_SIZE, frag->frag_no, PROTO_FRAG_NO_MAX, frag->act_type, PROTO_AT_MAX); return -EOVERFLOW; } if (frag->proto_ver != PROTO_VERSION) return -EPROTO; if (buf_len < PROTO_DATA_OFFSET) return -EMSGSIZE; #endif // assert (frag->act_size <= PROTO_ACT_SIZE_MAX); ((uint64_t*)buf)[0] = gu_be64(frag->act_id); ((uint32_t*)buf)[2] = htogl ((uint32_t)frag->act_size); ((uint32_t*)buf)[3] = htogl (frag->frag_no); ((uint8_t *)buf)[PROTO_PV_OFFSET] = frag->proto_ver; ((uint8_t *)buf)[PROTO_AT_OFFSET] = frag->act_type; frag->frag = (uint8_t*)buf + PROTO_DATA_OFFSET; frag->frag_len = buf_len - PROTO_DATA_OFFSET; return 0; } /*! Reads header data from the actual header of the message * Remainig fragment buf and length is in frag->frag and frag->frag_len * * @return 0 on success */ long gcs_act_proto_read (gcs_act_frag_t* frag, const void* buf, size_t buf_len) { frag->proto_ver = ((uint8_t*)buf)[PROTO_PV_OFFSET]; if (gu_unlikely(buf_len < PROTO_DATA_OFFSET)) { gu_error ("Action message too short: %zu, expected at least %d", buf_len, PROTO_DATA_OFFSET); return -EBADMSG; } if (gu_unlikely(frag->proto_ver > PROTO_VERSION)) { gu_error ("Bad protocol version %d, expected %d", frag->proto_ver, PROTO_VERSION); return -EPROTO; // this fragment should be dropped } ((uint8_t*)buf)[PROTO_PV_OFFSET] = 0x0; frag->act_id = gu_be64(*(uint64_t*)buf); frag->act_size = gtohl (((uint32_t*)buf)[2]); frag->frag_no = gtohl (((uint32_t*)buf)[3]); frag->act_type = static_cast( ((uint8_t*)buf)[PROTO_AT_OFFSET]); frag->frag = ((uint8_t*)buf) + PROTO_DATA_OFFSET; frag->frag_len = buf_len - PROTO_DATA_OFFSET; /* return 0 or -EMSGSIZE */ return ((frag->act_size > GCS_MAX_ACT_SIZE) * -EMSGSIZE); } /*! Returns protocol header size */ long gcs_act_proto_hdr_size (long version) { if (gu_unlikely(GCS_ACT_PROTO_MAX < version)) return -EPROTONOSUPPORT; if (gu_unlikely(version < 0)) return PROTO_MAX_HDR_SIZE; // safe return PROTO_DATA_OFFSET; } percona-galera-3-3.8-3390/gcs/src/gcs_act_proto.hpp000066400000000000000000000034531244131713600217110ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * Interface to action protocol * (to be extended to support protocol versions, currently supports only v0) */ #ifndef _gcs_act_proto_h_ #define _gcs_act_proto_h_ #include "gcs.hpp" // for gcs_seqno_t #include #include typedef uint8_t gcs_proto_t; /*! Supported protocol range (for now only version 0 is supported) */ #define GCS_ACT_PROTO_MAX 0 /*! Internal action fragment data representation */ typedef struct gcs_act_frag { gcs_seqno_t act_id; size_t act_size; const void* frag; // shall override it only once size_t frag_len; unsigned long frag_no; gcs_act_type_t act_type; int proto_ver; } gcs_act_frag_t; /*! Writes header data into actual header of the message. * Remainig fragment buf and length is in frag->frag and frag->frag_len */ extern long gcs_act_proto_write (gcs_act_frag_t* frag, void* buf, size_t buf_len); /*! Reads header data from the actual header of the message * Remainig fragment buf and length is in frag->frag and frag->frag_len */ extern long gcs_act_proto_read (gcs_act_frag_t* frag, const void* buf, size_t buf_len); /*! Increments fragment counter when action remains the same. * * @return non-negative counter value on success */ static inline long gcs_act_proto_inc (void* buf) { uint32_t frag_no = gtohl(((uint32_t*)buf)[3]) + 1; #ifdef GCS_DEBUG_PROTO if (!frag_no) return -EOVERFLOW; #endif ((uint32_t*)buf)[3] = htogl(frag_no); return frag_no; } /*! Returns protocol header size */ extern long gcs_act_proto_hdr_size (long version); /*! Returns message protocol version */ static inline int gcs_act_proto_ver (void* buf) { return *((uint8_t*)buf); } #endif /* _gcs_act_proto_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_backend.cpp000066400000000000000000000047671244131713600213120ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /*********************************************************/ /* This unit initializes the backend given backend URI */ /*********************************************************/ #include #include #include #include #include "gcs_backend.hpp" #include "gcs_dummy.hpp" #ifdef GCS_USE_SPREAD #include "gcs_spread.h" #endif /* GCS_USE_SPREAD */ #ifdef GCS_USE_VS #include "gcs_vs.h" #endif /* GCS_USE_VS */ #ifdef GCS_USE_GCOMM #include "gcs_gcomm.hpp" #endif /* GCS_USE_GCOMM */ bool gcs_backend_register(gu_config_t* const conf) { bool ret = false; #ifdef GCS_USE_GCOMM ret |= gcs_gcomm_register(conf); #endif /* GCS_USE_GCOMM */ #ifdef GCS_USE_VS #endif /* GCS_USE_VS */ #ifdef GCS_USE_SPREAD #endif /* GCS_USE_SPREAD */ ret |= gcs_dummy_register(conf); return ret; } /* Static array describing backend ID - open() pairs */ static struct { const char* id; gcs_backend_create_t create; } const backend[] = { #ifdef GCS_USE_GCOMM { "gcomm", gcs_gcomm_create}, #endif /* GCS_USE_GCOMM */ #ifdef GCS_USE_VS { "vsbes", gcs_vs_create }, #endif /* GCS_USE_VS */ #ifdef GCS_USE_SPREAD { "spread", gcs_spread_create }, #endif /* GCS_USE_SPREAD */ { "dummy", gcs_dummy_create }, { NULL, NULL } // terminating pair }; static const char backend_sep[] = "://"; /* Returns true if backend matches, false otherwise */ static bool backend_type_is (const char* uri, const char* type, const size_t len) { if (len == strlen(type)) { if (!strncmp (uri, type, len)) return true; } return false; } long gcs_backend_init (gcs_backend_t* const bk, const char* const uri, gu_config_t* const conf) { const char* sep; assert (NULL != bk); assert (NULL != uri); sep = strstr (uri, backend_sep); if (NULL != sep) { size_t type_len = sep - uri; const char* addr = sep + strlen(backend_sep); long i; /* try to match any of specified backends */ for (i = 0; backend[i].id != NULL; i++) { if (backend_type_is (uri, backend[i].id, type_len)) return backend[i].create (bk, addr, conf); } /* no backends matched */ gu_error ("Backend not supported: %s", uri); return -ESOCKTNOSUPPORT; } gu_error ("Invalid backend URI: %s", uri); return -EINVAL; } percona-galera-3-3.8-3390/gcs/src/gcs_backend.hpp000066400000000000000000000136471244131713600213140ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * This header defines GC backend interface. * Since we can't know backend context in advance, * we have to use type void*. Kind of unsafe. */ #ifndef _gcs_backend_h_ #define _gcs_backend_h_ #include "gcs.hpp" #include "gcs_recv_msg.hpp" #include #include #include typedef struct gcs_backend_conn gcs_backend_conn_t; typedef struct gcs_backend gcs_backend_t; /* * The macros below are declarations of backend functions * (kind of function signatures) */ /*! Registers configuration parameters with config */ #define GCS_BACKEND_REGISTER_FN(fn) \ bool fn (gu_config_t* cnf) /*! Allocates backend context and sets up the backend structure */ #define GCS_BACKEND_CREATE_FN(fn) \ long fn (gcs_backend_t* backend, \ const char* const addr, \ gu_config_t* const cnf) /*! Deallocates backend context */ #define GCS_BACKEND_DESTROY_FN(fn) \ long fn (gcs_backend_t* backend) /*! Puts backend handle into operating state */ #define GCS_BACKEND_OPEN_FN(fn) \ long fn (gcs_backend_t* backend, \ const char* const channel, \ bool const bootstrap) /*! Puts backend handle into non-operating state */ #define GCS_BACKEND_CLOSE_FN(fn) \ long fn (gcs_backend_t* backend) /*! * Send a message from the backend. * * @param backend * a pointer to the backend handle * @param buf * a buffer to copy the message to * @param len * length of the supplied buffer * @param msg_type * type of the message * @return * negative error code in case of error * OR * amount of bytes sent */ #define GCS_BACKEND_SEND_FN(fn) \ long fn (gcs_backend_t* const backend, \ const void* const buf, \ size_t const len, \ gcs_msg_type_t const msg_type) /*! * Receive a message from the backend. * * @param backend * a pointer to the backend object * @param buf * a buffer to copy the message to * @param len * length of the supplied buffer * @param msg_type * type of the message * @param sender_id * unique sender ID in this configuration * @param timeout * absolute timeout date in nanoseconds * @return * negative error code in case of error * OR * the length of the message, so if it is bigger * than len, it has to be reread with a bigger buffer */ #define GCS_BACKEND_RECV_FN(fn) \ long fn (gcs_backend_t* const backend, \ gcs_recv_msg_t* const msg, \ long long const timeout) /* for lack of better place define it here */ static const long GCS_SENDER_NONE = -1; /** When there's no sender */ /*! Returns symbolic name of the backend */ #define GCS_BACKEND_NAME_FN(fn) \ const char* fn (void) /*! * Returns the size of the message such that resulting network packet won't * exceed given value (basically, pkt_size - headers). * * @param backend * backend handle * @param pkt_size * desired size of a network packet * @return * - message size coresponding to the desired network packet size OR * - maximum message size the backend supports if requested packet size * is too big OR * - negative amount by which the packet size must be increased in order * to send at least 1 byte. */ #define GCS_BACKEND_MSG_SIZE_FN(fn) \ long fn (gcs_backend_t* const backend, \ long const pkt_size) /*! * @param backend * backend handle * @param key * parameter name * @param value * parameter value * @return 1 if parameter not recognized, 0 in case of success and negative * error code in case of error */ #define GCS_BACKEND_PARAM_SET_FN(fn) \ long fn (gcs_backend_t* backend, \ const char* key, \ const char* value) /*! * @param backend * backend handle * @param key * parameter name * @return NULL if parameter not recognized */ #define GCS_BACKEND_PARAM_GET_FN(fn) \ const char* fn (gcs_backend_t* backend, \ const char* key) /*! * @param backend * backend handle * @param status * reference to status variable map */ #define GCS_BACKEND_STATUS_GET_FN(fn) \ void fn(gcs_backend_t* backend, \ gu::Status& status) typedef GCS_BACKEND_CREATE_FN ((*gcs_backend_create_t)); typedef GCS_BACKEND_DESTROY_FN ((*gcs_backend_destroy_t)); typedef GCS_BACKEND_OPEN_FN ((*gcs_backend_open_t)); typedef GCS_BACKEND_CLOSE_FN ((*gcs_backend_close_t)); typedef GCS_BACKEND_SEND_FN ((*gcs_backend_send_t)); typedef GCS_BACKEND_RECV_FN ((*gcs_backend_recv_t)); typedef GCS_BACKEND_NAME_FN ((*gcs_backend_name_t)); typedef GCS_BACKEND_MSG_SIZE_FN ((*gcs_backend_msg_size_t)); typedef GCS_BACKEND_PARAM_SET_FN ((*gcs_backend_param_set_t)); typedef GCS_BACKEND_PARAM_GET_FN ((*gcs_backend_param_get_t)); typedef GCS_BACKEND_STATUS_GET_FN ((*gcs_backend_status_get_t)); struct gcs_backend { gcs_backend_conn_t* conn; gcs_backend_open_t open; gcs_backend_close_t close; gcs_backend_destroy_t destroy; gcs_backend_send_t send; gcs_backend_recv_t recv; gcs_backend_name_t name; gcs_backend_msg_size_t msg_size; gcs_backend_param_set_t param_set; gcs_backend_param_get_t param_get; gcs_backend_status_get_t status_get; }; /*! * Registers backends' parameters with config. */ bool gcs_backend_register(gu_config_t* conf); /*! * Initializes preallocated backend object and opens backend connection * (sort of like 'new') */ long gcs_backend_init (gcs_backend_t* bk, const char* uri, gu_config_t* cnf); #endif /* _gcs_backend_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_comp_msg.cpp000066400000000000000000000073251244131713600215200ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /* * Interface to membership messages - implementation * */ #include #include #include #include #define GCS_COMP_MSG_ACCESS #include "gcs_comp_msg.hpp" static inline int comp_msg_size (int memb_num) { return (sizeof(gcs_comp_msg_t) + memb_num * sizeof(gcs_comp_memb_t)); } /*! Allocates membership object and zeroes it */ gcs_comp_msg_t* gcs_comp_msg_new (bool prim, bool bootstrap, int my_idx, int memb_num, int error) { gcs_comp_msg_t* ret; assert ((memb_num > 0 && my_idx >= 0) || (memb_num == 0 && my_idx == -1)); ret = static_cast(gu_calloc (1, comp_msg_size(memb_num))); if (NULL != ret) { ret->primary = prim; ret->bootstrap = bootstrap; ret->my_idx = my_idx; ret->memb_num = memb_num; ret->error = error; } return ret; } gcs_comp_msg_t* gcs_comp_msg_leave (int error) { return gcs_comp_msg_new (false, false, -1, 0, error); } /*! Destroys component message */ void gcs_comp_msg_delete (gcs_comp_msg_t* comp) { gu_free (comp); } /*! Returns total size of the component message */ int gcs_comp_msg_size (const gcs_comp_msg_t* comp) { assert (comp); return comp_msg_size (comp->memb_num); } /*! Adds a member to the component message * Returns an index of the member or negative error code */ int gcs_comp_msg_add (gcs_comp_msg_t* comp, const char* id, gcs_segment_t const segment) { size_t id_len; int i; assert (comp); assert (id); /* check id length */ id_len = strlen (id); if (!id_len) return -EINVAL; if (id_len > GCS_COMP_MEMB_ID_MAX_LEN) return -ENAMETOOLONG; int free_slot = -1; /* find the free id slot and check for id uniqueness */ for (i = 0; i < comp->memb_num; i++) { if (0 == comp->memb[i].id[0] && free_slot < 0) free_slot = i; if (0 == strcmp (comp->memb[i].id, id)) return -ENOTUNIQ; } if (free_slot < 0) return -1; memcpy (comp->memb[free_slot].id, id, id_len); comp->memb[free_slot].segment = segment; return free_slot; } /*! Creates a copy of the component message */ gcs_comp_msg_t* gcs_comp_msg_copy (const gcs_comp_msg_t* comp) { size_t size = gcs_comp_msg_size(comp); gcs_comp_msg_t* ret = static_cast(gu_malloc (size)); if (ret) memcpy (ret, comp, size); return ret; } /*! Returns member ID by index, NULL if none */ const gcs_comp_memb_t* gcs_comp_msg_member (const gcs_comp_msg_t* comp, int idx) { if (0 <= idx && idx < comp->memb_num) return &comp->memb[idx]; else return NULL; } /*! Returns member index by ID, -1 if none */ int gcs_comp_msg_idx (const gcs_comp_msg_t* comp, const char* id) { size_t id_len = strlen(id); int idx = comp->memb_num; if (id_len > 0 && id_len <= GCS_COMP_MEMB_ID_MAX_LEN) for (idx = 0; idx < comp->memb_num; idx++) if (0 == strcmp (comp->memb[idx].id, id)) break; if (comp->memb_num == idx) return -1; else return idx; } /*! Returns primary status of the component */ bool gcs_comp_msg_primary (const gcs_comp_msg_t* comp) { return comp->primary; } /*! Retruns bootstrap flag of the component */ bool gcs_comp_msg_bootstrap(const gcs_comp_msg_t* comp) { return comp->bootstrap; } /*! Returns our own index in the membership */ int gcs_comp_msg_self (const gcs_comp_msg_t* comp) { return comp->my_idx; } /*! Returns number of members in the component */ int gcs_comp_msg_num (const gcs_comp_msg_t* comp) { return comp->memb_num; } int gcs_comp_msg_error(const gcs_comp_msg_t* comp) { return comp->error; } percona-galera-3-3.8-3390/gcs/src/gcs_comp_msg.hpp000066400000000000000000000061611244131713600215220ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /* * Interface to component messages * */ #ifndef _gcs_component_h_ #define _gcs_component_h_ #include #include // should accommodate human readable UUID (without trailing \0) #define GCS_COMP_MEMB_ID_MAX_LEN GU_UUID_STR_LEN /*! members of the same segment are physically closer than the others */ typedef uint8_t gcs_segment_t; typedef struct gcs_comp_memb { char id[GCS_COMP_MEMB_ID_MAX_LEN + 1]; /// ID assigned by the backend gcs_segment_t segment; } gcs_comp_memb_t; #ifdef GCS_COMP_MSG_ACCESS typedef struct gcs_comp_msg { int my_idx; /// this node's index in membership int memb_num; /// number of members in configuration bool primary; /// 1 if we have a quorum, 0 if not bool bootstrap; /// 1 if primary was bootstrapped int error; /// error code gcs_comp_memb_t memb[1]; /// member array } gcs_comp_msg_t; #else typedef struct gcs_comp_msg gcs_comp_msg_t; #endif /*! Allocates new component message * @param prim whether component is primary or not * @param bootstrap whether prim was bootstrapped * @param my_idx this node index in the membership * @param memb_num number of members in component * @param error error code * @return * allocated message buffer */ extern gcs_comp_msg_t* gcs_comp_msg_new (bool prim, bool bootstrap, int my_idx, int memb_num, int error); /*! Standard empty "leave" component message (to be returned on shutdown) */ extern gcs_comp_msg_t* gcs_comp_msg_leave (int error); /*! Destroys component message */ extern void gcs_comp_msg_delete (gcs_comp_msg_t* comp); /*! Adds a member to the component message * Returns an index of the member or negative error code: * -1 when membership is full * -ENOTUNIQ when name collides with one that is in membership already * -ENAMETOOLONG wnen memory allocation for new name fails */ extern int gcs_comp_msg_add (gcs_comp_msg_t* comp, const char* id, gcs_segment_t segment); /*! Returns total size of the component message */ extern int gcs_comp_msg_size (const gcs_comp_msg_t* comp); /*! Creates a copy of the component message */ extern gcs_comp_msg_t* gcs_comp_msg_copy (const gcs_comp_msg_t* comp); /*! Returns member ID by index, NULL if none */ extern const gcs_comp_memb_t* gcs_comp_msg_member (const gcs_comp_msg_t* comp, int idx); /*! Returns member index by ID, -1 if none */ extern int gcs_comp_msg_idx (const gcs_comp_msg_t* comp, const char* id); /*! Returns primary status of the component */ extern bool gcs_comp_msg_primary (const gcs_comp_msg_t* comp); /*! Returns bootstrap flag */ extern bool gcs_comp_msg_bootstrap(const gcs_comp_msg_t* comp); /*! Returns our own idx */ extern int gcs_comp_msg_self (const gcs_comp_msg_t* comp); /*! Returns number of members in the component */ extern int gcs_comp_msg_num (const gcs_comp_msg_t* comp); /*! Returns error code of the component message */ extern int gcs_comp_msg_error(const gcs_comp_msg_t* comp); #endif /* _gcs_component_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_conf.cpp000066400000000000000000000011351244131713600206320ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* Logging options */ #include #include "gcs.hpp" long gcs_conf_set_log_file (FILE *file) { return gu_conf_set_log_file (file); } long gcs_conf_set_log_callback (void (*logger) (int, const char*)) { return gu_conf_set_log_callback (logger); } long gcs_conf_self_tstamp_on () { return gu_conf_self_tstamp_on (); } long gcs_conf_self_tstamp_off () { return gu_conf_self_tstamp_off (); } long gcs_conf_debug_on () { return gu_conf_debug_on (); } long gcs_conf_debug_off () { return gu_conf_debug_off (); } percona-galera-3-3.8-3390/gcs/src/gcs_core.cpp000066400000000000000000001305231244131713600206410ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ * * * Implementation of the generic communication layer. * See gcs_core.h */ #include "gu_throw.hpp" #define GCS_COMP_MSG_ACCESS #include "gcs_core.hpp" #include "gcs_backend.hpp" #include "gcs_comp_msg.hpp" #include "gcs_fifo_lite.hpp" #include "gcs_group.hpp" #include "gcs_gcache.hpp" #include // for mempcpy #include bool gcs_core_register (gu_config_t* conf) { return gcs_backend_register(conf); } const size_t CORE_FIFO_LEN = (1 << 10); // 1024 elements (no need to have more) const size_t CORE_INIT_BUF_SIZE = (1 << 16); // 65K - IP packet size typedef enum core_state { CORE_PRIMARY, CORE_EXCHANGE, CORE_NON_PRIMARY, CORE_CLOSED, CORE_DESTROYED } core_state_t; struct gcs_core { gu_config_t* config; gcache_t* cache; /* connection per se */ long prim_comp_no; core_state_t state; /* protocol */ int proto_ver; /* send part */ gu_mutex_t send_lock; // serves 3 purposes: // 1) serializes access to backend send() call // 2) synchronizes with configuration changes // 3) synchronizes with close() call void* send_buf; size_t send_buf_len; gcs_seqno_t send_act_no; /* recv part */ gcs_recv_msg_t recv_msg; /* local action FIFO */ gcs_fifo_lite_t* fifo; /* group context */ gcs_group_t group; /* backend part */ size_t msg_size; gcs_backend_t backend; // message IO context #ifdef GCS_CORE_TESTING gu_lock_step_t ls; // to lock-step in unit tests gu_uuid_t state_uuid; #endif }; // this is to pass local action info from send to recv thread. typedef struct core_act { gcs_seqno_t sent_act_id; const void* action; size_t action_size; } core_act_t; typedef struct causal_act { gcs_seqno_t* act_id; gu_mutex_t* mtx; gu_cond_t* cond; } causal_act_t; static int const GCS_PROTO_MAX = 0; gcs_core_t* gcs_core_create (gu_config_t* const conf, gcache_t* const cache, const char* const node_name, const char* const inc_addr, int const repl_proto_ver, int const appl_proto_ver) { assert (conf); gcs_core_t* core = GU_CALLOC (1, gcs_core_t); if (NULL != core) { core->config = conf; core->cache = cache; // Need to allocate something, otherwise Spread 3.17.3 freaks out. core->recv_msg.buf = gu_malloc(CORE_INIT_BUF_SIZE); if (core->recv_msg.buf) { core->recv_msg.buf_len = CORE_INIT_BUF_SIZE; core->send_buf = GU_CALLOC(CORE_INIT_BUF_SIZE, char); if (core->send_buf) { core->send_buf_len = CORE_INIT_BUF_SIZE; core->fifo = gcs_fifo_lite_create (CORE_FIFO_LEN, sizeof (core_act_t)); if (core->fifo) { gu_mutex_init (&core->send_lock, NULL); core->proto_ver = -1; // shall be bumped in gcs_group_act_conf() gcs_group_init (&core->group, cache, node_name, inc_addr, GCS_PROTO_MAX, repl_proto_ver, appl_proto_ver); core->state = CORE_CLOSED; core->send_act_no = 1; // 0 == no actions sent #ifdef GCS_CORE_TESTING gu_lock_step_init (&core->ls); core->state_uuid = GU_UUID_NIL; #endif return core; // success } gu_free (core->send_buf); } gu_free (core->recv_msg.buf); } gu_free (core); } return NULL; // failure } long gcs_core_init (gcs_core_t* core, gcs_seqno_t seqno, const gu_uuid_t* uuid) { if (core->state == CORE_CLOSED) { return gcs_group_init_history (&core->group, seqno, uuid); } else { gu_error ("State must be CLOSED"); if (core->state < CORE_CLOSED) return -EBUSY; else // DESTROYED return -EBADFD; } } long gcs_core_open (gcs_core_t* core, const char* channel, const char* url, bool const bstrap) { long ret; if (core->state != CORE_CLOSED) { gu_debug ("gcs_core->state isn't CLOSED: %d", core->state); return -EBADFD; } if (core->backend.conn) { assert (core->backend.destroy); core->backend.destroy (&core->backend); memset (&core->backend, 0, sizeof(core->backend)); } gu_debug ("Initializing backend IO layer"); if (!(ret = gcs_backend_init (&core->backend, url, core->config))){ assert (NULL != core->backend.conn); if (!(ret = core->backend.open (&core->backend, channel, bstrap))) { gcs_fifo_lite_open (core->fifo); core->state = CORE_NON_PRIMARY; } else { gu_error ("Failed to open backend connection: %d (%s)", ret, strerror(-ret)); core->backend.destroy (&core->backend); } } else { gu_error ("Failed to initialize backend using '%s': %d (%s)", url, ret, strerror(-ret)); } return ret; } /* Translates different core states into standard errors */ static inline ssize_t core_error (core_state_t state) { switch (state) { case CORE_EXCHANGE: return -EAGAIN; case CORE_NON_PRIMARY: return -ENOTCONN; case CORE_CLOSED: return -ECONNABORTED; case CORE_DESTROYED: return -EBADFD; default: assert(0); return -ENOTRECOVERABLE; } } /*! * Performs an attempt at sending a message (action fragment) with all * required checks while holding a lock, ensuring exclusive access to backend. * * restart flag may be raised if configuration changes and new nodes are * added - that would require all previous members to resend partially sent * actions. */ static inline ssize_t core_msg_send (gcs_core_t* core, const void* msg, size_t msg_len, gcs_msg_type_t msg_type) { ssize_t ret; if (gu_unlikely(0 != gu_mutex_lock (&core->send_lock))) abort(); { if (gu_likely((CORE_PRIMARY == core->state) || (CORE_EXCHANGE == core->state && GCS_MSG_STATE_MSG == msg_type))) { ret = core->backend.send (&core->backend, msg, msg_len, msg_type); if (ret > 0 && ret != (ssize_t)msg_len && GCS_MSG_ACTION != msg_type) { // could not send message in one piece gu_error ("Failed to send complete message of %s type: " "sent %zd out of %zu bytes.", gcs_msg_type_string[msg_type], ret, msg_len); ret = -EMSGSIZE; } } else { ret = core_error (core->state); if (ret >= 0) { gu_fatal ("GCS internal state inconsistency: " "expected error condition."); abort(); // ret = -ENOTRECOVERABLE; } } } gu_mutex_unlock (&core->send_lock); // gu_debug ("returning: %d (%s)", ret, strerror(-ret)); return ret; } /*! * Repeats attempt at sending the message if -EAGAIN was returned * by core_msg_send() */ static inline ssize_t core_msg_send_retry (gcs_core_t* core, const void* buf, size_t buf_len, gcs_msg_type_t type) { ssize_t ret; while ((ret = core_msg_send (core, buf, buf_len, type)) == -EAGAIN) { /* wait for primary configuration - sleep 0.01 sec */ gu_debug ("Backend requested wait"); usleep (10000); } // gu_debug ("returning: %d (%s)", ret, strerror(-ret)); return ret; } ssize_t gcs_core_send (gcs_core_t* const conn, const struct gu_buf* const action, size_t act_size, gcs_act_type_t const act_type) { ssize_t ret = 0; ssize_t sent = 0; gcs_act_frag_t frg; ssize_t send_size; const unsigned char proto_ver = conn->proto_ver; const ssize_t hdr_size = gcs_act_proto_hdr_size (proto_ver); core_act_t* local_act; assert (action != NULL); assert (act_size > 0); /* * Action header will be replicated with every message. * It may seem like an extra overhead, but it is tiny * so far and simplifies A LOT. */ /* Initialize action constants */ frg.act_size = act_size; frg.act_type = act_type; frg.act_id = conn->send_act_no; /* incremented for every new action */ frg.frag_no = 0; frg.proto_ver = proto_ver; if ((ret = gcs_act_proto_write (&frg, conn->send_buf, conn->send_buf_len))) return ret; if ((local_act = (core_act_t*)gcs_fifo_lite_get_tail (conn->fifo))) { *local_act = (core_act_t){ conn->send_act_no, action, act_size }; gcs_fifo_lite_push_tail (conn->fifo); } else { ret = core_error (conn->state); gu_error ("Failed to access core FIFO: %d (%s)", ret, strerror (-ret)); return ret; } int idx = 0; const uint8_t* ptr = (const uint8_t*)action[idx].ptr; size_t left = action[idx].size; do { const size_t chunk_size = act_size < frg.frag_len ? act_size : frg.frag_len; /* Here is the only time we have to cast frg.frag */ char* dst = (char*)frg.frag; size_t to_copy = chunk_size; while (to_copy > 0) { // gather action bufs into one if (to_copy < left) { memcpy (dst, ptr, to_copy); ptr += to_copy; left -= to_copy; to_copy = 0; } else { memcpy (dst, ptr, left); dst += left; to_copy -= left; idx++; ptr = (const uint8_t*)action[idx].ptr; left = action[idx].size; } } send_size = hdr_size + chunk_size; #ifdef GCS_CORE_TESTING gu_lock_step_wait (&conn->ls); // pause after every fragment gu_info ("Sent %p of size %zu. Total sent: %zu, left: %zu", (char*)conn->send_buf + hdr_size, chunk_size, sent, act_size); #endif ret = core_msg_send_retry (conn, conn->send_buf, send_size, GCS_MSG_ACTION); #ifdef GCS_CORE_TESTING // gu_lock_step_wait (&conn->ls); // pause after every fragment // gu_info ("Sent %p of size %zu, ret: %zd. Total sent: %zu, left: %zu", // conn->send_buf + hdr_size, chunk_size, ret, sent, act_size); #endif if (gu_likely(ret > hdr_size)) { assert (ret <= send_size); ret -= hdr_size; sent += ret; act_size -= ret; if (gu_unlikely((size_t)ret < chunk_size)) { /* Could not send all that was copied: */ /* 1. adjust frag_len, don't copy more than we could send */ frg.frag_len = ret; /* 2. move ptr back to point at the first unsent byte */ size_t move_back = chunk_size - ret; size_t ptrdiff = ptr - (uint8_t*)action[idx].ptr; do { if (move_back <= ptrdiff) { ptr -= move_back; left = action[idx].size - ptrdiff + move_back; break; } else { assert (idx > 0); move_back -= ptrdiff; idx--; ptrdiff = action[idx].size; ptr = (uint8_t*)action[idx].ptr + ptrdiff; } } while (true); } } else { if (ret >= 0) { // we managed to send less than a header, fail gu_fatal ("Cannot send message: header is too big"); ret = -ENOTRECOVERABLE; } /* At this point we have an unsent action in local FIFO * and parts of this action already could have been received * by other group members. * (first parts of action might be even received by this node, * so that there is nothing to remove, but we cannot know for sure) * * 1. Action will never be received completely by this node. Hence * action must be removed from fifo on behalf of sending thr.: */ gcs_fifo_lite_remove (conn->fifo); /* 2. Members will have to discard received fragments. * Two reasons could lead us here: new member(s) in configuration * change or broken connection (leave group). In both cases other * members discard fragments */ goto out; } } while (act_size && gcs_act_proto_inc(conn->send_buf)); assert (0 == act_size); /* successfully sent action, increment send counter */ conn->send_act_no++; ret = sent; out: // gu_debug ("returning: %d (%s)", ret, strerror(-ret)); return ret; } /* A helper for gcs_core_recv(). * Deals with fetching complete message from backend * and reallocates recv buf if needed */ static inline long core_msg_recv (gcs_backend_t* backend, gcs_recv_msg_t* recv_msg, long long timeout) { long ret; ret = backend->recv (backend, recv_msg, timeout); while (gu_unlikely(ret > recv_msg->buf_len)) { /* recv_buf too small, reallocate */ /* sometimes - like in case of component message, we may need to * do reallocation 2 times. This should be fixed in backend */ void* msg = gu_realloc (recv_msg->buf, ret); gu_debug ("Reallocating buffer from %d to %d bytes", recv_msg->buf_len, ret); if (msg) { /* try again */ recv_msg->buf = msg; recv_msg->buf_len = ret; ret = backend->recv (backend, recv_msg, timeout); /* should be either an error or an exact match */ assert ((ret < 0) || (ret >= recv_msg->buf_len)); } else { /* realloc unsuccessfull, old recv_buf remains */ gu_error ("Failed to reallocate buffer to %d bytes", ret); ret = -ENOMEM; break; } } if (gu_unlikely(ret < 0)) { gu_debug ("returning %d: %s\n", ret, strerror(-ret)); } return ret; } /*! * Helper for gcs_core_recv(). Handles GCS_MSG_ACTION. * * @return action size, negative error code or 0 to continue. */ static inline ssize_t core_handle_act_msg (gcs_core_t* core, struct gcs_recv_msg* msg, struct gcs_act_rcvd* act) { ssize_t ret = -1; gcs_group_t* group = &core->group; gcs_act_frag_t frg; bool my_msg = (gcs_group_my_idx(group) == msg->sender_idx); bool not_commonly_supported_version = false; assert (GCS_MSG_ACTION == msg->type); if ((CORE_PRIMARY == core->state) || my_msg){//should always handle own msgs if (gu_unlikely(gcs_act_proto_ver(msg->buf) != gcs_core_group_protocol_version(core))) { gu_info ("Message with protocol version %d != highest commonly supported: %d. ", gcs_act_proto_ver(msg->buf), gcs_core_group_protocol_version(core)); not_commonly_supported_version = true; if (!my_msg) { gu_info ("Discard message from member %d because of " "not commonly supported version.", msg->sender_idx); return 0; } else { gu_info ("Resend message because of " "not commonly supported version."); } } ret = gcs_act_proto_read (&frg, msg->buf, msg->size); if (gu_unlikely(ret)) { gu_fatal ("Error parsing action fragment header: %zd (%s).", ret, strerror (-ret)); assert (0); return -ENOTRECOVERABLE; } ret = gcs_group_handle_act_msg (group, &frg, msg, act, not_commonly_supported_version); if (ret > 0) { /* complete action received */ assert (ret == act->act.buf_len); #ifndef GCS_FOR_GARB assert (NULL != act->act.buf); #else assert (NULL == act->act.buf); // act->act.buf_len = 0; #endif act->sender_idx = msg->sender_idx; if (gu_likely(!my_msg)) { /* foreign action, must be passed from gcs_group */ assert (GCS_ACT_TORDERED != act->act.type || act->id > 0); } else { /* local action, get from FIFO, should be there already */ core_act_t* local_act; gcs_seqno_t sent_act_id; if ((local_act = (core_act_t*)gcs_fifo_lite_get_head ( core->fifo))){ act->local = (const struct gu_buf*)local_act->action; act->act.buf_len = local_act->action_size; sent_act_id = local_act->sent_act_id; gcs_fifo_lite_pop_head (core->fifo); assert (NULL != act->local); /* NOTE! local_act cannot be used after this point */ /* sanity check */ if (gu_unlikely(sent_act_id != frg.act_id)) { gu_fatal ("FIFO violation: expected sent_act_id %lld " "found %lld", sent_act_id, frg.act_id); ret = -ENOTRECOVERABLE; } if (gu_unlikely(act->act.buf_len != ret)) { gu_fatal ("Send/recv action size mismatch: %zd/%zd", act->act.buf_len, ret); ret = -ENOTRECOVERABLE; } } else { gu_fatal ("FIFO violation: queue empty when local action " "received"); ret = -ENOTRECOVERABLE; } assert (act->id < 0 || CORE_PRIMARY == core->state); if (gu_unlikely(CORE_PRIMARY != core->state)) { // there can be a tiny race with gcs_core_close(), // so CORE_CLOSED allows TO delivery. assert (act->id < 0 /*#275|| CORE_CLOSED == core->state*/); if (act->id < 0) act->id = core_error (core->state); } } if (gu_unlikely(GCS_ACT_STATE_REQ == act->act.type && ret > 0 && // note: #gh74. // if lingering STR sneaks in when core->state != CORE_PRIMARY // act->id != GCS_SEQNO_ILL (most likely act->id == -EAGAIN) core->state == CORE_PRIMARY)) { #ifdef GCS_FOR_GARB /* ignoring state requests from other nodes (not allocated) */ if (my_msg) { if (act->act.buf_len != act->local[0].size) { gu_fatal ("Protocol violation: state request is fragmented." " Aborting."); abort(); } act->act.buf = act->local[0].ptr; #endif ret = gcs_group_handle_state_request (group, act); assert (ret <= 0 || ret == act->act.buf_len); #ifdef GCS_FOR_GARB if (ret < 0) gu_fatal ("Handling state request failed: %d",ret); act->act.buf = NULL; } else { act->act.buf_len = 0; act->act.type = GCS_ACT_ERROR; act->id = GCS_SEQNO_ILL; act->sender_idx = -1; ret = 0; } #endif } // gu_debug ("Received action: seqno: %lld, sender: %d, size: %d, " // "act: %p", act->id, msg->sender_idx, ret, act->buf); // gu_debug ("%s", (char*) act->buf); } else if (gu_unlikely(ret < 0)){ gu_fatal ("Failed to handle action fragment: %zd (%s)", ret, strerror(-ret)); assert (0); return -ENOTRECOVERABLE; } } else { /* Non-primary conf, foreign message - ignore */ gu_warn ("Action message in non-primary configuration from " "member %d", msg->sender_idx); ret = 0; } #ifndef NDEBUG if (ret <= 0) { assert (GCS_SEQNO_ILL == act->id); assert (GCS_ACT_ERROR == act->act.type); } #endif return ret; } /*! * Helper for gcs_core_recv(). Handles GCS_MSG_LAST. * * @return action size, negative error code or 0 to continue. */ static ssize_t core_handle_last_msg (gcs_core_t* core, struct gcs_recv_msg* msg, struct gcs_act* act) { assert (GCS_MSG_LAST == msg->type); if (gcs_group_is_primary(&core->group)) { gcs_seqno_t commit_cut = gcs_group_handle_last_msg (&core->group, msg); if (commit_cut) { /* commit cut changed */ if ((act->buf = malloc (sizeof (commit_cut)))) { act->type = GCS_ACT_COMMIT_CUT; /* #701 - everything that goes into the action buffer * is expected to be serialized. */ *((gcs_seqno_t*)act->buf) = gcs_seqno_htog(commit_cut); act->buf_len = sizeof(commit_cut); return act->buf_len; } else { gu_fatal ("Out of memory for GCS_ACT_COMMIT_CUT"); return -ENOMEM; } } } else { /* Non-primary - ignore last message */ gu_warn ("Last Applied Action message " "in non-primary configuration from member %d", msg->sender_idx); } return 0; } /*! * Helper for gcs_core_recv(). Handles GCS_MSG_COMPONENT. * * @return action size, negative error code or 0 to continue. */ static ssize_t core_handle_comp_msg (gcs_core_t* core, struct gcs_recv_msg* msg, struct gcs_act* act) { ssize_t ret = 0; gcs_group_t* group = &core->group; assert (GCS_MSG_COMPONENT == msg->type); if (msg->size < (ssize_t)sizeof(gcs_comp_msg_t)) { gu_error ("Malformed component message. Ignoring"); return 0; } ret = gcs_group_handle_comp_msg (group, (const gcs_comp_msg_t*)msg->buf); switch (ret) { case GCS_GROUP_PRIMARY: /* New primary configuration. This happens if: * - this is first node in group OR * - some nodes disappeared no new nodes appeared * No need for state exchange, return new conf_act right away */ if (gu_mutex_lock (&core->send_lock)) abort(); { assert (CORE_EXCHANGE != core->state); if (CORE_NON_PRIMARY == core->state) core->state = CORE_PRIMARY; } gu_mutex_unlock (&core->send_lock); ret = gcs_group_act_conf (group, act, &core->proto_ver); if (ret < 0) { gu_fatal ("Failed create PRIM CONF action: %d (%s)", ret, strerror (-ret)); assert (0); ret = -ENOTRECOVERABLE; } assert (ret == act->buf_len); break; case GCS_GROUP_WAIT_STATE_UUID: /* New members, need state exchange. If representative, send UUID */ if (gu_mutex_lock (&core->send_lock)) abort(); { // if state is CLOSED or DESTROYED we don't do anything if (CORE_CLOSED > core->state) { if (0 == gcs_group_my_idx(group)) { // I'm representative gu_uuid_t uuid; gu_uuid_generate (&uuid, NULL, 0); #ifdef GCS_CORE_TESTING if (gu_uuid_compare(&core->state_uuid, &GU_UUID_NIL)) { uuid = core->state_uuid; } #endif ret = core->backend.send (&core->backend, &uuid, sizeof(uuid), GCS_MSG_STATE_UUID); if (ret < 0) { // if send() failed, it means new configuration change // is on the way. Probably should ignore. gu_warn ("Failed to send state UUID: %d (%s)", ret, strerror (-ret)); } else { gu_info ("STATE_EXCHANGE: sent state UUID: " GU_UUID_FORMAT, GU_UUID_ARGS(&uuid)); } } else { gu_info ("STATE EXCHANGE: Waiting for state UUID."); } core->state = CORE_EXCHANGE; } ret = 0; // no action to return, continue } gu_mutex_unlock (&core->send_lock); break; case GCS_GROUP_NON_PRIMARY: /* Lost primary component */ if (gu_mutex_lock (&core->send_lock)) abort(); { if (core->state < CORE_CLOSED) { ret = gcs_group_act_conf (group, act, &core->proto_ver); if (ret < 0) { gu_fatal ("Failed create NON-PRIM CONF action: %d (%s)", ret, strerror (-ret)); assert (0); ret = -ENOTRECOVERABLE; } if (gcs_group_my_idx(group) == -1) { // self-leave gcs_fifo_lite_close (core->fifo); core->state = CORE_CLOSED; if (gcs_comp_msg_error((const gcs_comp_msg_t*)msg->buf)) { ret = -gcs_comp_msg_error( (const gcs_comp_msg_t*)msg->buf); free(const_cast(act->buf)); act->buf = NULL; act->buf_len = 0; act->type = GCS_ACT_ERROR; gu_info("comp msg error in core %d", -ret); } } else { // regular non-prim core->state = CORE_NON_PRIMARY; } } else { // ignore in production? assert(0); } } gu_mutex_unlock (&core->send_lock); assert (ret == act->buf_len || ret < 0); break; case GCS_GROUP_WAIT_STATE_MSG: gu_fatal ("Internal error: gcs_group_handle_comp() returned " "WAIT_STATE_MSG. Can't continue."); ret = -ENOTRECOVERABLE; assert(0); default: gu_fatal ("Failed to handle component message: %d (%s)!", ret, strerror (-ret)); assert(0); } return ret; } /*! * Helper for gcs_core_recv(). Handles GCS_MSG_STATE_UUID. * * @return negative error code or 0 to continue. */ static ssize_t core_handle_uuid_msg (gcs_core_t* core, gcs_recv_msg_t* msg) { ssize_t ret = 0; gcs_group_t* group = &core->group; assert (GCS_MSG_STATE_UUID == msg->type); if (GCS_GROUP_WAIT_STATE_UUID == gcs_group_state (group)) { ret = gcs_group_handle_uuid_msg (group, msg); switch (ret) { case GCS_GROUP_WAIT_STATE_MSG: // Need to send state message for state exchange { gcs_state_msg_t* state = gcs_group_get_state (group); if (state) { size_t state_len = gcs_state_msg_len (state); uint8_t state_buf[state_len]; const gu_uuid_t* state_uuid = gcs_state_msg_uuid (state); gcs_state_msg_write (state_buf, state); ret = core_msg_send_retry (core, state_buf, state_len, GCS_MSG_STATE_MSG); if (ret > 0) { gu_info ("STATE EXCHANGE: sent state msg: " GU_UUID_FORMAT, GU_UUID_ARGS(state_uuid)); } else { // This may happen if new configuraiton chage goes on. // What shall we do in this case? Is it unrecoverable? gu_error ("STATE EXCHANGE: failed for: "GU_UUID_FORMAT ": %d (%s)", GU_UUID_ARGS(state_uuid), ret, strerror(-ret)); } gcs_state_msg_destroy (state); } else { gu_fatal ("Failed to allocate state object."); ret = -ENOTRECOVERABLE; } } break; case GCS_GROUP_WAIT_STATE_UUID: // In case of stray state uuid message break; default: assert(ret < 0); gu_error ("Failed to handle state UUID: %d (%s)", ret, strerror (-ret)); } } return ret; } /*! * Helper for gcs_core_recv(). Handles GCS_MSG_STATE_MSG. * * @return action size, negative error code or 0 to continue. */ static ssize_t core_handle_state_msg (gcs_core_t* core, struct gcs_recv_msg* msg, struct gcs_act* act) { ssize_t ret = 0; gcs_group_t* group = &core->group; assert (GCS_MSG_STATE_MSG == msg->type); if (GCS_GROUP_WAIT_STATE_MSG == gcs_group_state (group)) { ret = gcs_group_handle_state_msg (group, msg); switch (ret) { case GCS_GROUP_PRIMARY: case GCS_GROUP_NON_PRIMARY: // state exchange is over, create configuration action if (gu_mutex_lock (&core->send_lock)) abort(); { // if core is closing we do nothing if (CORE_CLOSED > core->state) { assert (CORE_EXCHANGE == core->state); switch (ret) { case GCS_GROUP_PRIMARY: core->state = CORE_PRIMARY; break; case GCS_GROUP_NON_PRIMARY: core->state = CORE_NON_PRIMARY; break; default: assert (0); } } } gu_mutex_unlock (&core->send_lock); ret = gcs_group_act_conf (group, act, &core->proto_ver); if (ret < 0) { gu_fatal ("Failed create CONF action: %d (%s)", ret, strerror (-ret)); assert (0); ret = -ENOTRECOVERABLE; } assert (ret == act->buf_len); break; case GCS_GROUP_WAIT_STATE_MSG: // waiting for more state messages ret = 0; break; default: assert (ret < 0); gu_error ("Failed to handle state message: %d (%s)", ret, strerror (-ret)); } } return ret; } /*! * Some service actions are for internal use and consist of a single message * (FLOW, JOIN, SYNC) * In this case we can simply use msg->buf as an action buffer, since we * can guarantee that we don't deallocate it. Action here is just a wrapper * to deliver message to the upper level. */ static ssize_t core_msg_to_action (gcs_core_t* core, struct gcs_recv_msg* msg, struct gcs_act* act) { ssize_t ret = 0; gcs_group_t* group = &core->group; if (GCS_GROUP_PRIMARY == gcs_group_state (group)) { gcs_act_type_t act_type; switch (msg->type) { case GCS_MSG_FLOW: // most frequent ret = 1; act_type = GCS_ACT_FLOW; break; case GCS_MSG_JOIN: ret = gcs_group_handle_join_msg (group, msg); assert (gcs_group_my_idx(group) == msg->sender_idx || 0 >= ret); if (-ENOTRECOVERABLE == ret) { core->backend.close(&core->backend); // See #165. // There is nobody to pass this error to for graceful shutdown: // application thread is blocked waiting for SST. gu_abort(); } act_type = GCS_ACT_JOIN; break; case GCS_MSG_SYNC: ret = gcs_group_handle_sync_msg (group, msg); act_type = GCS_ACT_SYNC; break; default: gu_error ("Iternal error. Unexpected message type %s from ld%", gcs_msg_type_string[msg->type], msg->sender_idx); assert (0); ret = -EPROTO; } if (ret > 0) { act->type = act_type; act->buf = msg->buf; act->buf_len = msg->size; ret = msg->size; } } else { gu_warn ("%s message from member %ld in non-primary configuration. " "Ignored.", gcs_msg_type_string[msg->type], msg->sender_idx); } return ret; } static long core_msg_causal(gcs_core_t* conn, struct gcs_recv_msg* msg) { causal_act_t* act; if (gu_unlikely(msg->size != sizeof(*act))) { gu_error("invalid causal act len %ld, expected %ld", msg->size, sizeof(*act)); return -EPROTO; } gcs_seqno_t const causal_seqno = GCS_GROUP_PRIMARY == conn->group.state ? conn->group.act_id : GCS_SEQNO_ILL; act = (causal_act_t*)msg->buf; gu_mutex_lock(act->mtx); *act->act_id = causal_seqno; gu_cond_signal(act->cond); gu_mutex_unlock(act->mtx); return msg->size; } /*! Receives action */ ssize_t gcs_core_recv (gcs_core_t* conn, struct gcs_act_rcvd* recv_act, long long timeout) { // struct gcs_act_rcvd recv_act; struct gcs_recv_msg* recv_msg = &conn->recv_msg; ssize_t ret = 0; static struct gcs_act_rcvd zero_act( gcs_act(NULL, 0, GCS_ACT_ERROR), NULL, -1, // GCS_SEQNO_ILL -1); *recv_act = zero_act; /* receive messages from group and demultiplex them * until finally some complete action is ready */ do { assert (recv_act->act.buf == NULL); assert (recv_act->act.buf_len == 0); assert (recv_act->act.type == GCS_ACT_ERROR); assert (recv_act->id == GCS_SEQNO_ILL); assert (recv_act->sender_idx == -1); ret = core_msg_recv (&conn->backend, recv_msg, timeout); if (gu_unlikely (ret <= 0)) { goto out; /* backend error while receiving message */ } switch (recv_msg->type) { case GCS_MSG_ACTION: ret = core_handle_act_msg(conn, recv_msg, recv_act); assert (ret == recv_act->act.buf_len || ret <= 0); assert (recv_act->sender_idx >= 0 || ret == 0); break; case GCS_MSG_LAST: ret = core_handle_last_msg(conn, recv_msg, &recv_act->act); assert (ret >= 0); // hang on error in debug mode assert (ret == recv_act->act.buf_len); break; case GCS_MSG_COMPONENT: ret = core_handle_comp_msg (conn, recv_msg, &recv_act->act); // assert (ret >= 0); // hang on error in debug mode assert (ret == recv_act->act.buf_len || ret <= 0); break; case GCS_MSG_STATE_UUID: ret = core_handle_uuid_msg (conn, recv_msg); // assert (ret >= 0); // hang on error in debug mode ret = 0; // continue waiting for state messages break; case GCS_MSG_STATE_MSG: ret = core_handle_state_msg (conn, recv_msg, &recv_act->act); assert (ret >= 0); // hang on error in debug mode assert (ret == recv_act->act.buf_len); break; case GCS_MSG_JOIN: case GCS_MSG_SYNC: case GCS_MSG_FLOW: ret = core_msg_to_action (conn, recv_msg, &recv_act->act); assert (ret == recv_act->act.buf_len || ret <= 0); break; case GCS_MSG_CAUSAL: ret = core_msg_causal(conn, recv_msg); assert(recv_msg->sender_idx == gcs_group_my_idx(&conn->group)); assert(ret == recv_msg->size || ret <= 0); ret = 0; // continue waiting for messages break; default: // this normaly should not happen, shall we bother with // protection? gu_warn ("Received unsupported message type: %d, length: %d, " "sender: %d", recv_msg->type, recv_msg->size, recv_msg->sender_idx); // continue looping } } while (0 == ret); /* end of recv loop */ out: assert (ret || GCS_ACT_ERROR == recv_act->act.type); assert (ret == recv_act->act.buf_len || ret < 0); assert (recv_act->id <= GCS_SEQNO_ILL || recv_act->act.type == GCS_ACT_TORDERED || recv_act->act.type == GCS_ACT_STATE_REQ); // <- dirty hack assert (recv_act->sender_idx >= 0 || recv_act->act.type != GCS_ACT_TORDERED); // gu_debug ("Returning %d", ret); if (ret < 0) { assert (recv_act->id < 0); if (GCS_ACT_TORDERED == recv_act->act.type && recv_act->act.buf) { gcs_gcache_free (conn->cache, recv_act->act.buf); recv_act->act.buf = NULL; } if (-ENOTRECOVERABLE == ret) { conn->backend.close(&conn->backend); gu_abort(); } } return ret; } long gcs_core_close (gcs_core_t* core) { long ret; if (!core) return -EBADFD; if (gu_mutex_lock (&core->send_lock)) return -EBADFD; if (core->state >= CORE_CLOSED) { ret = -EBADFD; } else { ret = core->backend.close (&core->backend); } gu_mutex_unlock (&core->send_lock); return ret; } long gcs_core_destroy (gcs_core_t* core) { core_act_t* tmp; if (!core) return -EBADFD; if (gu_mutex_lock (&core->send_lock)) return -EBADFD; { if (CORE_CLOSED != core->state) { if (core->state < CORE_CLOSED) gu_error ("Calling destroy() before close()."); gu_mutex_unlock (&core->send_lock); return -EBADFD; } if (core->backend.conn) { gu_debug ("Calling backend.destroy()"); core->backend.destroy (&core->backend); } core->state = CORE_DESTROYED; } gu_mutex_unlock (&core->send_lock); /* at this point all send attempts are isolated */ /* after that we must be able to destroy mutexes */ while (gu_mutex_destroy (&core->send_lock)); /* now noone will interfere */ while ((tmp = (core_act_t*)gcs_fifo_lite_get_head (core->fifo))) { // whatever is in tmp.action is allocated by app., just forget it. gcs_fifo_lite_pop_head (core->fifo); } gcs_fifo_lite_destroy (core->fifo); gcs_group_free (&core->group); /* free buffers */ gu_free (core->recv_msg.buf); gu_free (core->send_buf); #ifdef GCS_CORE_TESTING gu_lock_step_destroy (&core->ls); #endif gu_free (core); return 0; } gcs_proto_t gcs_core_group_protocol_version (const gcs_core_t* conn) { return conn->proto_ver; } long gcs_core_set_pkt_size (gcs_core_t* core, long pkt_size) { long hdr_size, msg_size; uint8_t* new_send_buf = NULL; long ret = 0; if (core->state >= CORE_CLOSED) { gu_error ("Attempt to set packet size on a closed connection."); return -EBADFD; } hdr_size = gcs_act_proto_hdr_size (core->proto_ver); if (hdr_size < 0) return hdr_size; msg_size = core->backend.msg_size (&core->backend, pkt_size); if (msg_size <= hdr_size) { gu_warn ("Requested packet size %d is too small, " "using smallest possible: %d", pkt_size, pkt_size + (hdr_size - msg_size + 1)); msg_size = hdr_size + 1; } gu_info ("Changing maximum packet size to %ld, resulting msg size: %ld", pkt_size, msg_size); ret = msg_size - hdr_size; // message payload if (core->send_buf_len == (size_t)msg_size) return ret; if (gu_mutex_lock (&core->send_lock)) abort(); { if (core->state != CORE_DESTROYED) { new_send_buf = (uint8_t*)gu_realloc (core->send_buf, msg_size); if (new_send_buf) { core->send_buf = new_send_buf; core->send_buf_len = msg_size; memset (core->send_buf, 0, hdr_size); // to pacify valgrind gu_debug ("Message payload (action fragment size): %ld", ret); } else { ret = -ENOMEM; } } else { ret = -EBADFD; } } gu_mutex_unlock (&core->send_lock); return ret; } static inline long core_send_seqno (gcs_core_t* core, gcs_seqno_t seqno, gcs_msg_type_t msg_type) { gcs_seqno_t const htogs = gcs_seqno_htog (seqno); ssize_t ret = core_msg_send_retry (core, &htogs, sizeof(htogs), msg_type); if (ret > 0) { assert(ret == sizeof(seqno)); ret = 0; } return ret; } long gcs_core_set_last_applied (gcs_core_t* core, gcs_seqno_t seqno) { return core_send_seqno (core, seqno, GCS_MSG_LAST); } long gcs_core_send_join (gcs_core_t* core, gcs_seqno_t seqno) { return core_send_seqno (core, seqno, GCS_MSG_JOIN); } long gcs_core_send_sync (gcs_core_t* core, gcs_seqno_t seqno) { return core_send_seqno (core, seqno, GCS_MSG_SYNC); } long gcs_core_send_fc (gcs_core_t* core, const void* fc, size_t fc_size) { ssize_t ret; ret = core_msg_send_retry (core, fc, fc_size, GCS_MSG_FLOW); if (ret == (ssize_t)fc_size) { ret = 0; } return ret; } gcs_seqno_t gcs_core_caused(gcs_core_t* core) { long ret; gcs_seqno_t act_id = GCS_SEQNO_ILL; gu_mutex_t mtx; gu_cond_t cond; causal_act_t act = {&act_id, &mtx, &cond}; gu_mutex_init (&mtx, NULL); gu_cond_init (&cond, NULL); gu_mutex_lock (&mtx); { ret = core_msg_send_retry (core, &act, sizeof(act), GCS_MSG_CAUSAL); if (ret == sizeof(act)) { gu_cond_wait (&cond, &mtx); } else { assert (ret < 0); act_id = ret; } } gu_mutex_unlock (&mtx); gu_mutex_destroy (&mtx); gu_cond_destroy (&cond); return act_id; } long gcs_core_param_set (gcs_core_t* core, const char* key, const char* value) { if (core->backend.conn) { return core->backend.param_set (&core->backend, key, value); } else { return 1; } } const char* gcs_core_param_get (gcs_core_t* core, const char* key) { if (core->backend.conn) { return core->backend.param_get (&core->backend, key); } else { return NULL; } } void gcs_core_get_status(gcs_core_t* core, gu::Status& status) { if (gu_mutex_lock(&core->send_lock)) gu_throw_fatal << "could not lock mutex"; if (core->state < CORE_CLOSED) { core->backend.status_get(&core->backend, status); } gu_mutex_unlock(&core->send_lock); } #ifdef GCS_CORE_TESTING gcs_backend_t* gcs_core_get_backend (gcs_core_t* core) { return &core->backend; } void gcs_core_send_lock_step (gcs_core_t* core, bool enable) { gu_lock_step_enable (&core->ls, enable); } long gcs_core_send_step (gcs_core_t* core, long timeout_ms) { return gu_lock_step_cont (&core->ls, timeout_ms); } void gcs_core_set_state_uuid (gcs_core_t* core, const gu_uuid_t* uuid) { core->state_uuid = *uuid; } const gcs_group_t* gcs_core_get_group (const gcs_core_t* core) { return &core->group; } gcs_fifo_lite_t* gcs_core_get_fifo (gcs_core_t* core) { return core->fifo; } #endif /* GCS_CORE_TESTING */ percona-galera-3-3.8-3390/gcs/src/gcs_core.hpp000066400000000000000000000134231244131713600206450ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * This header defines generic communication layer * which implements basic open/close/send/receive * functions. Its purpose is to implement all * functionality common to all group communication * uses. Currently this amounts to action * fragmentation/defragmentation and invoking backend * functions. * In the course of development it has become clear * that such fuctionality must be collected in a * separate layer. * Application abstraction layer is based on this one * and uses those functions for its own purposes. */ #ifndef _gcs_core_h_ #define _gcs_core_h_ #include #include #include #include "gcs.hpp" #include "gcs_act.hpp" #include "gcs_act_proto.hpp" #include /* 'static' method to register configuration variables */ extern bool gcs_core_register (gu_config_t* conf); struct gcs_core; typedef struct gcs_core gcs_core_t; /* * Allocates context resources private to * generic communicaton layer - send/recieve buffers and the like. */ extern gcs_core_t* gcs_core_create (gu_config_t* conf, gcache_t* cache, const char* node_name, const char* inc_addr, int repl_proto_ver, int appl_proto_ver); /* initializes action history (global seqno, group UUID). See gcs.h */ extern long gcs_core_init (gcs_core_t* core, gcs_seqno_t seqno, const gu_uuid_t* uuid); /* * gcs_core_open() opens connection * Return values: * zero - success * negative - error code */ extern long gcs_core_open (gcs_core_t* conn, const char* channel, const char* url, bool bootstrap); /* * gcs_core_close() puts connection in a closed state, * cancelling all ongoing calls. * Return values: * zero - success * negative - error code */ extern long gcs_core_close (gcs_core_t* conn); /* * gcs_core_destroy() frees resources allocated by gcs_core_create() * Return values: * zero - success * negative - error code */ extern long gcs_core_destroy (gcs_core_t* conn); /* * gcs_core_send() atomically sends action to group. * * NOT THREAD SAFE! Access should be serialized. * * Return values: * non-negative - amount of action bytes sent (sans headers) * negative - error code * -EAGAIN - operation should be retried * -ENOTCONN - connection to primary component lost * * NOTE: Successful return code here does not guarantee delivery to group. * The real status of action is determined only in gcs_core_recv() call. */ extern ssize_t gcs_core_send (gcs_core_t* core, const struct gu_buf* act, size_t act_size, gcs_act_type_t act_type); /* * gcs_core_recv() blocks until some action is received from group. * * @param repl_buf ptr to replicated action local buffer (NULL otherwise) * @param timeout absolute timeout date (as in pthread_cond_timedwait()) * * Return values: * non-negative - the size of action received * negative - error code * * @retval -ETIMEDOUT means no messages were received until timeout. * * NOTE: Action status (replicated or not) is carried in act_id. E.g. -ENOTCONN * means connection to primary component was lost while sending, * -ERESTART means that action delivery was interrupted and it must be * resent. */ extern ssize_t gcs_core_recv (gcs_core_t* conn, struct gcs_act_rcvd* recv_act, long long timeout); /* group protocol version */ extern gcs_proto_t gcs_core_group_protocol_version (const gcs_core_t* conn); /* Configuration functions */ /* Sets maximum message size to achieve requested network packet size. * In case of failure returns negative error code, in case of success - * resulting message payload size (size of action fragment) */ extern long gcs_core_set_pkt_size (gcs_core_t* conn, long pkt_size); /* sends this node's last applied value to group */ extern long gcs_core_set_last_applied (gcs_core_t* core, gcs_seqno_t seqno); /* sends status of the ended snapshot (snapshot seqno or error code) */ extern long gcs_core_send_join (gcs_core_t* core, gcs_seqno_t seqno); /* sends SYNC notice, seqno currently has no meaning */ extern long gcs_core_send_sync (gcs_core_t* core, gcs_seqno_t seqno); /* sends flow control message */ extern long gcs_core_send_fc (gcs_core_t* core, const void* fc, size_t fc_size); extern gcs_seqno_t gcs_core_caused(gcs_core_t* core); extern long gcs_core_param_set (gcs_core_t* core, const char* key, const char* value); extern const char* gcs_core_param_get (gcs_core_t* core, const char* key); void gcs_core_get_status(gcs_core_t* core, gu::Status& status); #ifdef GCS_CORE_TESTING /* gcs_core_send() interface does not allow enough concurrency control to model * various race conditions for unit testing - it is not atomic. The functions * below expose gcs_core unit internals solely for the purpose of testing */ #include "gcs_msg_type.hpp" #include "gcs_backend.hpp" extern gcs_backend_t* gcs_core_get_backend (gcs_core_t* core); // switches lock-step mode on/off extern void gcs_core_send_lock_step (gcs_core_t* core, bool enable); // step through action send process (send another fragment). // returns positive number if there was a send thread waiting for it. extern long gcs_core_send_step (gcs_core_t* core, long timeout_ms); extern void gcs_core_set_state_uuid (gcs_core_t* core, const gu_uuid_t* uuid); #include "gcs_group.hpp" extern const gcs_group_t* gcs_core_get_group (const gcs_core_t* core); #include "gcs_fifo_lite.hpp" extern gcs_fifo_lite_t* gcs_core_get_fifo (gcs_core_t* core); #endif /* GCS_CORE_TESTING */ #endif /* _gcs_core_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_defrag.cpp000066400000000000000000000125271244131713600211440ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include "gcs_act_proto.hpp" #include "gcs_defrag.hpp" #define DF_ALLOC() \ do { \ df->head = static_cast(gcs_gcache_malloc (df->cache, df->size)); \ \ if(gu_likely(df->head != NULL)) \ df->tail = df->head; \ else { \ gu_error ("Could not allocate memory for new " \ "action of size: %zd", df->size); \ assert(0); \ return -ENOMEM; \ } \ } while (0) /*! * Handle action fragment * * Unless a whole action is returned, contents of act is undefined * * In order to optimize branch prediction used gu_likely macros and odered and * nested if/else blocks according to branch probability. * * @return 0 - success, * size of action - success, full action received, * negative - error. * * TODO: this function is too long, figure out a way to factor it into several * smaller ones. Note that it is called for every GCS_MSG_ACTION message * so it should be optimal. */ ssize_t gcs_defrag_handle_frag (gcs_defrag_t* df, const gcs_act_frag_t* frg, struct gcs_act* act, bool local) { if (df->received) { /* another fragment of existing action */ df->frag_no++; /* detect possible error condition */ if (gu_unlikely((df->sent_id != frg->act_id) || (df->frag_no != frg->frag_no))) { if (local && df->reset && (df->sent_id == frg->act_id) && (0 == frg->frag_no)) { /* df->sent_id was aborted halfway and is being taken care of * by the sender thread. Forget about it. * Reinit counters and continue with the new action. * Note that for local actions no memory allocation is made.*/ gu_debug ("Local action %lld reset.", frg->act_id); df->frag_no = 0; df->received = 0; df->tail = df->head; df->reset = false; if (df->size != frg->act_size) { df->size = frg->act_size; #ifndef GCS_FOR_GARB if (df->cache !=NULL) { gcache_free (df->cache, df->head); } else { free ((void*)df->head); } DF_ALLOC(); #endif /* GCS_FOR_GARB */ } } else { gu_error ("Unordered fragment received. Protocol error."); gu_error ("Expected: %llu:%ld, received: %llu:%ld", df->sent_id, df->frag_no, frg->act_id, frg->frag_no); gu_error ("Contents: '%.*s'", frg->frag_len, (char*)frg->frag); df->frag_no--; // revert counter in hope that we get good frag assert(0); return -EPROTO; } } } else { /* new action */ if (gu_likely(0 == frg->frag_no)) { df->size = frg->act_size; df->sent_id = frg->act_id; df->reset = false; #ifndef GCS_FOR_GARB DF_ALLOC(); #else /* we don't store actions locally at all */ df->head = NULL; df->tail = df->head; #endif } else { /* not a first fragment */ if (!local && df->reset) { /* can happen after configuration change, just ignore this message calmly */ gu_debug ("Ignoring fragment %lld:%ld after action reset", frg->act_id, frg->frag_no); return 0; } else { ((char*)frg->frag)[frg->frag_len - 1] = '\0'; gu_error ("Unordered fragment received. Protocol error."); gu_error ("Expected: any:0(first), received: %lld:%ld", frg->act_id, frg->frag_no); gu_error ("Contents: '%s', local: %s, reset: %s", (char*)frg->frag, local ? "yes" : "no", df->reset ? "yes" : "no"); assert(0); return -EPROTO; } } } df->received += frg->frag_len; assert (df->received <= df->size); #ifndef GCS_FOR_GARB assert (df->tail); memcpy (df->tail, frg->frag, frg->frag_len); df->tail += frg->frag_len; #else /* we skip memcpy since have not allocated any buffer */ assert (NULL == df->tail); assert (NULL == df->head); #endif if (df->received == df->size) { act->buf = df->head; act->buf_len = df->received; gcs_defrag_init (df, df->cache); return act->buf_len; } else { return 0; } } percona-galera-3-3.8-3390/gcs/src/gcs_defrag.hpp000066400000000000000000000037321244131713600211470ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! * Receiving action context */ #ifndef _gcs_defrag_h_ #define _gcs_defrag_h_ #include // for memset() #include #include #include "gcs.hpp" // for gcs_seqno_t et al. #include "gcs_act_proto.hpp" #include "gcs_act.hpp" #include "gcs_gcache.hpp" #include typedef struct gcs_defrag { gcache_t* cache; gcs_seqno_t sent_id; // sent id (unique for a node) uint8_t* head; // head of action buffer uint8_t* tail; // tail of action data size_t size; size_t received; ulong frag_no; // number of fragment received bool reset; } gcs_defrag_t; static inline void gcs_defrag_init (gcs_defrag_t* df, gcache_t* cache) { memset (df, 0, sizeof (*df)); df->cache = cache; df->sent_id = GCS_SEQNO_ILL; } /*! * Handle received action fragment * * @return 0 - success, * size of action - success, full action received, * negative - error. */ extern ssize_t gcs_defrag_handle_frag (gcs_defrag_t* df, const gcs_act_frag_t* frg, struct gcs_act* act, bool local); /*! Deassociate, but don't deallocate action resources */ static inline void gcs_defrag_forget (gcs_defrag_t* df) { gcs_defrag_init (df, df->cache); } /*! Free resources associated with defrag (for lost node cleanup) */ static inline void gcs_defrag_free (gcs_defrag_t* df) { #ifndef GCS_FOR_GARB if (df->head) { gcs_gcache_free (df->cache, df->head); // df->head, df->tail will be zeroed in gcs_defrag_init() below } #else assert(NULL == df->head); #endif gcs_defrag_init (df, df->cache); } /*! Mark current action as reset */ static inline void gcs_defrag_reset (gcs_defrag_t* df) { df->reset = true; } #endif /* _gcs_defrag_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_dummy.cpp000066400000000000000000000230351244131713600210430ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * Dummy backend implementation * */ #include #include #include #include #include #include #include #define GCS_COMP_MSG_ACCESS // for gcs_comp_memb_t #ifndef GCS_DUMMY_TESTING #define GCS_DUMMY_TESTING #endif #include "gcs_dummy.hpp" typedef struct dummy_msg { gcs_msg_type_t type; ssize_t len; long sender_idx; uint8_t buf[]; } dummy_msg_t; static inline dummy_msg_t* dummy_msg_create (gcs_msg_type_t const type, size_t const len, long const sender, const void* const buf) { dummy_msg_t *msg = NULL; if ((msg = static_cast(gu_malloc (sizeof(dummy_msg_t) + len)))) { memcpy (msg->buf, buf, len); msg->len = len; msg->type = type; msg->sender_idx = sender; } return msg; } static inline long dummy_msg_destroy (dummy_msg_t *msg) { if (msg) { gu_free (msg); } return 0; } typedef enum dummy_state { DUMMY_DESTROYED, DUMMY_CLOSED, DUMMY_NON_PRIM, DUMMY_TRANS, DUMMY_PRIM, } dummy_state_t; typedef struct gcs_backend_conn { gu_fifo_t* gc_q; /* "serializator" */ volatile dummy_state_t state; gcs_seqno_t msg_id; const size_t max_pkt_size; const size_t hdr_size; const size_t max_send_size; long my_idx; long memb_num; gcs_comp_memb_t* memb; } dummy_t; static GCS_BACKEND_DESTROY_FN(dummy_destroy) { dummy_t* dummy = backend->conn; if (!dummy || dummy->state != DUMMY_CLOSED) return -EBADFD; // gu_debug ("Deallocating message queue (serializer)"); gu_fifo_destroy (dummy->gc_q); if (dummy->memb) gu_free (dummy->memb); gu_free (dummy); backend->conn = NULL; return 0; } static GCS_BACKEND_SEND_FN(dummy_send) { int err = 0; dummy_t* dummy = backend->conn; if (gu_unlikely(NULL == dummy)) return -EBADFD; if (gu_likely(DUMMY_PRIM == dummy->state)) { err = gcs_dummy_inject_msg (backend, buf, len, msg_type, backend->conn->my_idx); } else { static long send_error[DUMMY_PRIM] = { -EBADFD, -EBADFD, -ENOTCONN, -EAGAIN }; err = send_error[dummy->state]; } return err; } static GCS_BACKEND_RECV_FN(dummy_recv) { long ret = 0; dummy_t* conn = backend->conn; msg->sender_idx = GCS_SENDER_NONE; msg->type = GCS_MSG_ERROR; assert (conn); /* skip it if we already have popped a message from the queue * in the previous call */ if (gu_likely(DUMMY_CLOSED <= conn->state)) { int err; dummy_msg_t** ptr = static_cast( gu_fifo_get_head (conn->gc_q, &err)); if (gu_likely(ptr != NULL)) { dummy_msg_t* dmsg = *ptr; assert (NULL != dmsg); msg->type = dmsg->type; msg->sender_idx = dmsg->sender_idx; ret = dmsg->len; msg->size = ret; if (gu_likely(dmsg->len <= msg->buf_len)) { gu_fifo_pop_head (conn->gc_q); memcpy (msg->buf, dmsg->buf, dmsg->len); dummy_msg_destroy (dmsg); } else { // supplied recv buffer too short, leave the message in queue memcpy (msg->buf, dmsg->buf, msg->buf_len); gu_fifo_release (conn->gc_q); } } else { ret = -EBADFD; // closing gu_debug ("Returning %d: %s", ret, strerror(-ret)); } } else { ret = -EBADFD; } return ret; } static GCS_BACKEND_NAME_FN(dummy_name) { return "built-in dummy backend"; } static GCS_BACKEND_MSG_SIZE_FN(dummy_msg_size) { const long max_pkt_size = backend->conn->max_pkt_size; if (pkt_size > max_pkt_size) { gu_warn ("Requested packet size: %d, maximum possible packet size: %d", pkt_size, max_pkt_size); return (max_pkt_size - backend->conn->hdr_size); } return (pkt_size - backend->conn->hdr_size); } static GCS_BACKEND_OPEN_FN(dummy_open) { long ret = -ENOMEM; dummy_t* dummy = backend->conn; gcs_comp_msg_t* comp; if (!dummy) { gu_debug ("Backend not initialized"); return -EBADFD; } if (!bootstrap) { dummy->state = DUMMY_TRANS; return 0; } comp = gcs_comp_msg_new (true, false, 0, 1, 0); if (comp) { ret = gcs_comp_msg_add (comp, "11111111-2222-3333-4444-555555555555",0); assert (0 == ret); // we have only one member, index = 0 dummy->state = DUMMY_TRANS; // required by gcs_dummy_set_component() ret = gcs_dummy_set_component (backend, comp); // install new component if (ret >= 0) { // queue the message ret = gcs_comp_msg_size(comp); ret = gcs_dummy_inject_msg (backend, comp, ret, GCS_MSG_COMPONENT, GCS_SENDER_NONE); if (ret > 0) ret = 0; } gcs_comp_msg_delete (comp); } gu_debug ("Opened backend connection: %d (%s)", ret, strerror(-ret)); return ret; } static GCS_BACKEND_CLOSE_FN(dummy_close) { long ret = -ENOMEM; dummy_t* dummy = backend->conn; gcs_comp_msg_t* comp; if (!dummy) return -EBADFD; comp = gcs_comp_msg_leave (0); if (comp) { ret = gcs_comp_msg_size(comp); ret = gcs_dummy_inject_msg (backend, comp, ret, GCS_MSG_COMPONENT, GCS_SENDER_NONE); // Here's a race condition - some other thread can send something // after leave message. But caller should guarantee serial access. gu_fifo_close (dummy->gc_q); if (ret > 0) ret = 0; gcs_comp_msg_delete (comp); } dummy->state = DUMMY_CLOSED; return ret; } static GCS_BACKEND_PARAM_SET_FN(dummy_param_set) { return 1; } static GCS_BACKEND_PARAM_GET_FN(dummy_param_get) { return NULL; } GCS_BACKEND_STATUS_GET_FN(dummy_status_get) { } GCS_BACKEND_CREATE_FN(gcs_dummy_create) { long ret = -ENOMEM; dummy_t* dummy = NULL; if (!(dummy = GU_CALLOC(1, dummy_t))) goto out0; dummy->state = DUMMY_CLOSED; *(size_t*)(&dummy->max_pkt_size) = (size_t) sysconf (_SC_PAGESIZE); *(size_t*)(&dummy->hdr_size) = sizeof(dummy_msg_t); *(size_t*)(&dummy->max_send_size) = dummy->max_pkt_size - dummy->hdr_size; if (!(dummy->gc_q = gu_fifo_create (1 << 16, sizeof(void*)))) goto out1; backend->conn = NULL; backend->open = dummy_open; backend->close = dummy_close; backend->destroy = dummy_destroy; backend->send = dummy_send; backend->recv = dummy_recv; backend->name = dummy_name; backend->msg_size = dummy_msg_size; backend->param_set = dummy_param_set; backend->param_get = dummy_param_get; backend->status_get = dummy_status_get; backend->conn = dummy; // set data return 0; out1: gu_free (dummy); out0: backend->conn = NULL; return ret; } GCS_BACKEND_REGISTER_FN(gcs_dummy_register) { return false; } /*! Injects a message in the message queue to produce a desired msg sequence. */ long gcs_dummy_inject_msg (gcs_backend_t* backend, const void* buf, size_t buf_len, gcs_msg_type_t type, long sender_idx) { long ret; size_t send_size = buf_len < backend->conn->max_send_size ? buf_len : backend->conn->max_send_size; dummy_msg_t* msg = dummy_msg_create (type, send_size, sender_idx, buf); if (msg) { dummy_msg_t** ptr = static_cast( gu_fifo_get_tail (backend->conn->gc_q)); if (gu_likely(ptr != NULL)) { *ptr = msg; gu_fifo_push_tail (backend->conn->gc_q); ret = send_size; } else { dummy_msg_destroy (msg); ret = -EBADFD; // closed } } else { ret = -ENOMEM; } return ret; } /*! Sets the new component view. * The same component message should be injected in the queue separately * (see gcs_dummy_inject_msg()) in order to model different race conditions */ long gcs_dummy_set_component (gcs_backend_t* backend, const gcs_comp_msg_t* comp) { dummy_t* dummy = backend->conn; long new_num = gcs_comp_msg_num (comp); long i; assert (dummy->state > DUMMY_CLOSED); if (dummy->memb_num != new_num) { void* tmp = gu_realloc (dummy->memb, new_num * sizeof(gcs_comp_memb_t)); if (NULL == tmp) return -ENOMEM; dummy->memb = static_cast(tmp); dummy->memb_num = new_num; } for (i = 0; i < dummy->memb_num; i++) { strcpy ((char*)&dummy->memb[i], gcs_comp_msg_member(comp, i)->id); } dummy->my_idx = gcs_comp_msg_self(comp); dummy->state = gcs_comp_msg_primary(comp) ? DUMMY_PRIM : DUMMY_NON_PRIM; gu_debug ("Setting state to %s", DUMMY_PRIM == dummy->state ? "DUMMY_PRIM" : "DUMMY_NON_PRIM"); return 0; } /*! Is needed to set transitional state */ long gcs_dummy_set_transitional (gcs_backend_t* backend) { backend->conn->state = DUMMY_TRANS; return 0; } percona-galera-3-3.8-3390/gcs/src/gcs_dummy.hpp000066400000000000000000000022541244131713600210500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * Dummy backend specification */ #ifndef _gcs_dummy_h_ #define _gcs_dummy_h_ #include "gcs_backend.hpp" #include "gcs_comp_msg.hpp" extern GCS_BACKEND_REGISTER_FN (gcs_dummy_register); extern GCS_BACKEND_CREATE_FN (gcs_dummy_create); #ifdef GCS_DUMMY_TESTING /* * What follows is an API for unit testing */ /*! Injects a message in the message queue to produce a desired msg sequence. */ extern long gcs_dummy_inject_msg (gcs_backend_t* backend, const void* msg, size_t len, gcs_msg_type_t type, long sender_idx); /*! Sets the new component view. * The same component message should be injected in the queue separately * (see gcs_dummy_inject_msg()) in order to model different race conditions */ extern long gcs_dummy_set_component (gcs_backend_t* backend, const gcs_comp_msg_t* comp); /*! Is needed to set transitional state */ extern long gcs_dummy_set_transitional (gcs_backend_t* backend); #endif /* GCS_DUMMY_TESTING */ #endif /* _gcs_dummy_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_fc.cpp000066400000000000000000000151641244131713600203040ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy * * $Id$ */ /*! @file This unit contains Flow Control parts deemed worthy to be * taken out of gcs.c */ #include "gcs_fc.hpp" #include #include double const gcs_fc_hard_limit_fix = 0.9; //! allow for some overhead static double const min_sleep = 0.001; //! minimum sleep period (s) /*! Initializes operational constants before opening connection to group * @return -EINVAL if wrong values are submitted */ int gcs_fc_init (gcs_fc_t* fc, ssize_t hard_limit, // slave queue hard limit double soft_limit, // soft limit as a fraction of hard limit double max_throttle) { assert (fc); if (hard_limit < 0) { gu_error ("Bad value for slave queue hard limit: %zd (should be > 0)", hard_limit); return -EINVAL; } if (soft_limit < 0.0 || soft_limit >= 1.0) { gu_error ("Bad value for slave queue soft limit: %f " "(should belong to [0.0,1.0) )", soft_limit); return -EINVAL; } if (max_throttle < 0.0 || max_throttle >= 1.0) { gu_error ("Bad value for max throttle: %f " "(should belong to [0.0,1.0) )", max_throttle); return -EINVAL; } memset (fc, 0, sizeof(*fc)); fc->hard_limit = hard_limit; fc->soft_limit = fc->hard_limit * soft_limit; fc->max_throttle = max_throttle; return 0; } /*! Reinitializes object at the beginning of state transfer */ void gcs_fc_reset (gcs_fc_t* const fc, ssize_t const queue_size) { assert (fc != NULL); assert (queue_size >= 0); fc->init_size = queue_size; fc->size = fc->init_size; fc->start = gu_time_monotonic(); fc->last_sleep = 0; fc->act_count = 0; fc->max_rate = -1.0; fc->scale = 0.0; fc->offset = 0.0; fc->sleep_count= 0; fc->sleeps = 0.0; } /* * The idea here is that there is no flow control up until slave queue size * reaches soft limit. * After that flow control gradually slows down replication rate by emitting FC * events in order to buy more time for state transfer. * Replication rate goes linearly from normal rate at soft limit to max_throttle * fraction at hard limit, at which point -ENOMEM is returned as replication * becomes prohibitively slow. * * replication * speed * ^ * |--------. <- normal replication rate * | .\ * | . \ * | . \ * | . \ speed = fc->size * fc->scale + fc->offset * | . \ * | . \ * | . \ | * | . \ | * | . \| * | . + <- throttle limit * | . | * | . | * +--------+---------+----> slave queue size * soft hard * limit limit */ /*! Processes a new action added to a slave queue. * @return length of sleep in nanoseconds or negative error code * or GU_TIME_ETERNITY for complete stop */ long long gcs_fc_process (gcs_fc_t* fc, ssize_t act_size) { fc->size += act_size; fc->act_count++; if (fc->size <= fc->soft_limit) { /* normal operation */ if (gu_unlikely(fc->debug > 0 && !(fc->act_count % fc->debug))) { gu_info ("FC: queue size: %zdb (%4.1f%% of soft limit)", fc->size, ((double)fc->size)/fc->soft_limit*100.0); } return 0; } else if (fc->size >= fc->hard_limit) { if (0.0 == fc->max_throttle) { /* we can accept total service outage */ return GU_TIME_ETERNITY; } else { gu_error ("Recv queue hard limit exceeded. Can't continue."); return -ENOMEM; } } // else if (!(fc->act_count & 7)) { // do this for every 8th action else { long long end = gu_time_monotonic(); double interval = ((end - fc->start) * 1.0e-9); if (gu_unlikely (0 == fc->last_sleep)) { /* just tripped the soft limit, preparing constants for throttle */ fc->max_rate = (double)(fc->size - fc->init_size) / interval; double s = (1.0 - fc->max_throttle)/(fc->soft_limit-fc->hard_limit); assert (s < 0.0); fc->scale = s * fc->max_rate; fc->offset = (1.0 - s*fc->soft_limit) * fc->max_rate; // calculate time interval from the soft limit interval = interval * (double)(fc->size - fc->soft_limit) / (fc->size - fc->init_size); assert (interval >= 0.0); // Move reference point to soft limit fc->last_sleep = fc->soft_limit; fc->start = end - interval * 1000000000; gu_warn("Soft recv queue limit exceeded, starting replication " "throttle. Measured avg. rate: %f bytes/sec; " "Throttle parameters: scale=%f, offset=%f", fc->max_rate, fc->scale, fc->offset); } /* throttling operation */ double desired_rate = fc->size * fc->scale + fc->offset; // linear decay //double desired_rate = fc->max_rate * fc->max_throttle; // square wave assert (desired_rate <= fc->max_rate); double sleep = (double)(fc->size - fc->last_sleep) / desired_rate - interval; if (gu_unlikely(fc->debug > 0 && !(fc->act_count % fc->debug))) { gu_info ("FC: queue size: %zdb, length: %zd, " "measured rate: %fb/s, desired rate: %fb/s, " "interval: %5.3fs, sleep: %5.4fs. " "Sleeps initiated: %zd, for a total of %6.3fs", fc->size, fc->act_count, ((double)(fc->size - fc->last_sleep))/interval, desired_rate, interval, sleep, fc->sleep_count, fc->sleeps); fc->sleep_count = 0; fc->sleeps = 0.0; } if (gu_likely(sleep < min_sleep)) { #if 0 gu_info ("Skipping sleep: desired_rate = %f, sleep = %f (%f), " "interval = %f, fc->scale = %f, fc->offset = %f, " "fc->size = %zd", desired_rate, sleep, min_sleep, interval, fc->scale, fc->offset, fc->size); #endif return 0; } fc->last_sleep = fc->size; fc->start = end; fc->sleep_count++; fc->sleeps += sleep; return (1000000000LL * sleep); } return 0; } void gcs_fc_debug (gcs_fc_t* fc, long debug_level) { fc->debug = debug_level; } percona-galera-3-3.8-3390/gcs/src/gcs_fc.hpp000066400000000000000000000036761244131713600203160ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy * * $Id$ */ /*! @file This unit contains Flow Control parts deemed worthy to be * taken out of gcs.c */ #ifndef _gcs_fc_h_ #define _gcs_fc_h_ #include #include #include typedef struct gcs_fc { ssize_t hard_limit; // hard limit for slave queue size ssize_t soft_limit; // soft limit for slave queue size, after it FC kicks in double max_throttle; // limit on how much we can throttle replication ssize_t init_size; // initial queue size ssize_t size; // current queue size ssize_t last_sleep; // queue size when last sleep happened ssize_t act_count; // action count double max_rate; // normal replication data rate (byte/s) double scale; // data rate scale factor double offset; // data rate offset (rate = scale*size + offset) long long start; // beginning of the time interval (nanosec, monotonic) long debug; // how often to print debug messages, 0 - never ssize_t sleep_count; double sleeps; } gcs_fc_t; extern double const gcs_fc_hard_limit_fix; //! allow for some overhead /*! Initializes operational constants before oprning connection to group */ extern int gcs_fc_init (gcs_fc_t* fc, ssize_t hard_limit, // hard limit double soft_limit, // soft limit as a fraction of hard limit double max_throttle); /*! Reinitializes object at the beginning of state transfer */ extern void gcs_fc_reset (gcs_fc_t* fc, ssize_t queue_size); /*! Processes a new action added to a slave queue. * @return nanoseconds to sleep or -ENOMEM in case of hitting * hard limit or GU_TIME_ETERNITY to pause forever */ extern long long gcs_fc_process (gcs_fc_t* fc, ssize_t act_size); /*! Print debug info every debug_level'th call to gcs_fc_process. */ extern void gcs_fc_debug (gcs_fc_t* fc, long debug_level); #endif /* _gcs_fc_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_fifo_lite.cpp000066400000000000000000000102251244131713600216450ustar00rootroot00000000000000/* * Copyright (C) 2008-2011 Codership Oy * * $Id$ * * FIFO "class" customized for particular purpose * (here I decided to sacrifice generality for efficiency). * Implements simple fixed size "mallocless" FIFO. * Except gcs_fifo_create() there are two types of fifo * access methods - protected and unprotected. Unprotected * methods assume that calling routines implement their own * protection, and thus are simplified for speed. */ #include #include "gcs_fifo_lite.hpp" /* Creates FIFO object. Since it practically consists of array of (void*), * the length can be chosen arbitrarily high - to minimize the risk * of overflow situation. */ gcs_fifo_lite_t* gcs_fifo_lite_create (size_t length, size_t item_size) { gcs_fifo_lite_t* ret = NULL; uint64_t l = 1; /* check limits */ if (length < 1 || item_size < 1) return NULL; /* Find real length. It must be power of 2*/ while (l < length) l = l << 1; if (l * item_size > (uint64_t)GU_LONG_MAX) { gu_error ("Resulting FIFO size %lld exceeds signed limit: %lld", (long long)(l*item_size), (long long)GU_LONG_MAX); return NULL; } ret = GU_CALLOC (1, gcs_fifo_lite_t); if (ret) { ret->length = l; ret->item_size = item_size; ret->mask = ret->length - 1; ret->closed = true; ret->queue = gu_malloc (ret->length * item_size); if (ret->queue) { gu_mutex_init (&ret->lock, NULL); gu_cond_init (&ret->put_cond, NULL); gu_cond_init (&ret->get_cond, NULL); /* everything else must be initialized to 0 by calloc */ } else { gu_free (ret); ret = NULL; } } return ret; } void gcs_fifo_lite_close (gcs_fifo_lite_t* fifo) { GCS_FIFO_LITE_LOCK; if (fifo->closed) { gu_error ("Trying to close a closed FIFO"); assert(0); } else { fifo->closed = true; // wake whoever is waiting fifo->put_wait = 0; gu_cond_broadcast (&fifo->put_cond); fifo->get_wait = 0; gu_cond_broadcast (&fifo->get_cond); } gu_mutex_unlock (&fifo->lock); } void gcs_fifo_lite_open (gcs_fifo_lite_t* fifo) { GCS_FIFO_LITE_LOCK; if (!fifo->closed) { gu_error ("Trying to open an open FIFO."); assert(0); } else { fifo->closed = false; } gu_mutex_unlock(&fifo->lock); } long gcs_fifo_lite_destroy (gcs_fifo_lite_t* f) { if (f) { if (gu_mutex_lock (&f->lock)) { abort(); } if (f->destroyed) { gu_mutex_unlock (&f->lock); return -EALREADY; } f->closed = true; f->destroyed = true; /* get rid of "put" threads waiting for lock or signal */ while (pthread_cond_destroy (&f->put_cond)) { if (f->put_wait <= 0) { gu_fatal ("Can't destroy condition while nobody's waiting"); abort(); } f->put_wait = 0; gu_cond_broadcast (&f->put_cond); } while (f->used) { /* there are some items in FIFO - and that means * no gcs_fifo_lite_safe_get() is waiting on condition */ gu_mutex_unlock (&f->lock); /* let them get remaining items from FIFO, * we don't know how to deallocate them ourselves. * unfortunately this may take some time */ usleep (10000); /* sleep a bit to avoid busy loop */ gu_mutex_lock (&f->lock); } f->length = 0; /* now all we have - "get" threads waiting for lock or signal */ while (pthread_cond_destroy (&f->get_cond)) { if (f->get_wait <= 0) { gu_fatal ("Can't destroy condition while nobody's waiting"); abort(); } f->get_wait = 0; gu_cond_broadcast (&f->get_cond); } /* at this point there are only functions waiting for lock */ gu_mutex_unlock (&f->lock); while (gu_mutex_destroy (&f->lock)) { /* this should be fast provided safe get and safe put are * wtitten correctly. They should immediately freak out. */ gu_mutex_lock (&f->lock); gu_mutex_unlock (&f->lock); } /* now nobody's waiting for anything */ gu_free (f->queue); gu_free (f); return 0; } return -EINVAL; } percona-galera-3-3.8-3390/gcs/src/gcs_fifo_lite.hpp000066400000000000000000000113101244131713600216460ustar00rootroot00000000000000/* * Copyright (C) 2008-2011 Codership Oy * * $Id$ * * FIFO "class" customized for particular purpose * (here I decided to sacrifice generality for efficiency). * Implements fixed size "mallocless" FIFO (read "ring buffer"). * Except gcs_fifo_create() there are two types of fifo * access methods - protected and unprotected. Unprotected * methods assume that calling routines implement their own * protection, and thus are simplified for speed. */ #ifndef _GCS_FIFO_LITE_H_ #define _GCS_FIFO_LITE_H_ #include #include #include #include #include #include #include "gcs.hpp" typedef struct gcs_fifo_lite { long length; ulong item_size; ulong mask; ulong head; ulong tail; long used; bool closed; bool destroyed; long put_wait; long get_wait; gu_cond_t put_cond; gu_cond_t get_cond; gu_mutex_t lock; void* queue; } gcs_fifo_lite_t; /* Creates FIFO object. Since it practically consists of array of (void*), * the length can be chosen arbitrarily high - to minimize the risk * of overflow situation. */ gcs_fifo_lite_t* gcs_fifo_lite_create (size_t length, size_t item_size); void gcs_fifo_lite_close (gcs_fifo_lite_t* fifo); void gcs_fifo_lite_open (gcs_fifo_lite_t* fifo); long gcs_fifo_lite_destroy (gcs_fifo_lite_t* fifo); static inline void* _gcs_fifo_lite_tail (gcs_fifo_lite_t* f) { return ((char*)f->queue + f->tail * f->item_size); } static inline void* _gcs_fifo_lite_head (gcs_fifo_lite_t* f) { return ((char*)f->queue + f->head * f->item_size); } #define GCS_FIFO_LITE_LOCK \ if (gu_unlikely (gu_mutex_lock (&fifo->lock))) { \ gu_fatal ("Mutex lock failed."); \ abort(); \ } /*! If FIFO is not full, returns pointer to the tail item and locks FIFO, * otherwise blocks. Or returns NULL if FIFO is closed. */ static inline void* gcs_fifo_lite_get_tail (gcs_fifo_lite_t* fifo) { void* ret = NULL; GCS_FIFO_LITE_LOCK; while (!fifo->closed && fifo->used >= fifo->length) { fifo->put_wait++; gu_cond_wait (&fifo->put_cond, &fifo->lock); } if (gu_likely(!fifo->closed)) { assert (fifo->used < fifo->length); ret = _gcs_fifo_lite_tail (fifo); } else { gu_mutex_unlock (&fifo->lock); } return ret; } /*! Advances FIFO tail and unlocks FIFO */ static inline void gcs_fifo_lite_push_tail (gcs_fifo_lite_t* fifo) { fifo->tail = (fifo->tail + 1) & fifo->mask; fifo->used++; assert (fifo->used <= fifo->length); if (fifo->get_wait > 0) { fifo->get_wait--; gu_cond_signal (&fifo->get_cond); } gu_mutex_unlock (&fifo->lock); } /*! If FIFO is not empty, returns pointer to the head item and locks FIFO, * or returns NULL if FIFO is empty. Blocking behaviour disabled since * it is not needed in GCS: recv_thread should never block. */ static inline void* gcs_fifo_lite_get_head (gcs_fifo_lite_t* fifo) { void* ret = NULL; GCS_FIFO_LITE_LOCK; /* Uncomment this for blocking behaviour while (!fifo->closed && 0 == fifo->used) { fifo->get_wait++; gu_cond_wait (&fifo->get_cond, &fifo->lock); } */ if (gu_likely(fifo->used > 0)) { ret = _gcs_fifo_lite_head (fifo); } else { gu_mutex_unlock (&fifo->lock); } return ret; } /*! Advances FIFO head and unlocks FIFO */ static inline void gcs_fifo_lite_pop_head (gcs_fifo_lite_t* fifo) { fifo->head = (fifo->head + 1) & fifo->mask; fifo->used--; assert (fifo->used != -1); if (fifo->put_wait > 0) { fifo->put_wait--; gu_cond_signal (&fifo->put_cond); } gu_mutex_unlock (&fifo->lock); } /*! Unlocks FIFO */ static inline long gcs_fifo_lite_release (gcs_fifo_lite_t* fifo) { return (gu_mutex_unlock (&fifo->lock)); } /*! Removes item from tail, returns true if success */ static inline bool gcs_fifo_lite_remove (gcs_fifo_lite_t* const fifo) { bool ret = false; assert (fifo); GCS_FIFO_LITE_LOCK; if (fifo->used) { fifo->tail = (fifo->tail - 1) & fifo->mask; fifo->used--; ret = true; if (fifo->put_wait > 0) { fifo->put_wait--; gu_cond_signal (&fifo->put_cond); } } gu_mutex_unlock (&fifo->lock); return ret; } static inline bool gcs_fifo_lite_not_full (const gcs_fifo_lite_t* const fifo) { return (fifo->used < fifo->length); } #endif /* _GCS_FIFO_LITE_H_ */ percona-galera-3-3.8-3390/gcs/src/gcs_gcache.hpp000066400000000000000000000011001244131713600211140ustar00rootroot00000000000000/* * Copyright (C) 2011 Codership Oy * * $Id$ */ #ifndef _gcs_gcache_h_ #define _gcs_gcache_h_ #include static inline void* gcs_gcache_malloc (gcache_t* gcache, size_t size) { if (gu_likely(gcache != NULL)) return gcache_malloc (gcache, size); else return malloc (size); } static inline void gcs_gcache_free (gcache_t* gcache, const void* buf) { #ifndef GCS_FOR_GARB if (gu_likely (gcache != NULL)) gcache_free (gcache, buf); else #endif free ((void*)buf); } #endif /* _gcs_gcache_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_gcomm.cpp000066400000000000000000000523331244131713600210150ustar00rootroot00000000000000/* * Copyright (C) 2009-2014 Codership Oy */ /*! * @file GComm GCS Backend implementation * * @todo Figure out if there is lock-free way to handle RecvBuf * push/pop operations. * */ #include "gcs_gcomm.hpp" // We access data comp msg struct directly #define GCS_COMP_MSG_ACCESS 1 #include "gcs_comp_msg.hpp" #include #include "gu_backtrace.hpp" #include "gcomm/transport.hpp" #include "gcomm/util.hpp" #include "gcomm/conf.hpp" #ifdef PROFILE_GCS_GCOMM #define GCOMM_PROFILE 1 #else #undef GCOMM_PROFILE #endif // PROFILE_GCS_GCOMM #include "profile.hpp" #include using namespace std; using namespace gu; using namespace gu::prodcons; using namespace gu::datetime; using namespace gcomm; using namespace prof; class RecvBufData { public: RecvBufData(const size_t source_idx, const Datagram& dgram, const ProtoUpMeta& um) : source_idx_(source_idx), dgram_ (dgram), um_ (um) { } size_t get_source_idx() const { return source_idx_; } const Datagram& get_dgram() const { return dgram_; } const ProtoUpMeta& get_um() const { return um_; } private: size_t source_idx_; Datagram dgram_; ProtoUpMeta um_; }; #if defined(GALERA_USE_BOOST_POOL_ALLOC) #include typedef deque > #else typedef deque #endif /* GALERA_USE_BOOST_POOL_ALLOC */ RecvBufQueue; class RecvBuf { private: class Waiting { public: Waiting (bool& w) : w_(w) { w_ = true; } ~Waiting() { w_ = false; } private: bool& w_; }; public: RecvBuf() : mutex_(), cond_(), queue_(), waiting_(false) { } void push_back(const RecvBufData& p) { Lock lock(mutex_); queue_.push_back(p); if (waiting_ == true) { cond_.signal(); } } const RecvBufData& front(const Date& timeout) { Lock lock(mutex_); while (queue_.empty()) { Waiting w(waiting_); if (gu_likely (timeout == GU_TIME_ETERNITY)) { lock.wait(cond_); } else { lock.wait(cond_, timeout); } } assert (false == waiting_); return queue_.front(); } void pop_front() { Lock lock(mutex_); assert(queue_.empty() == false); queue_.pop_front(); } private: Mutex mutex_; Cond cond_; RecvBufQueue queue_; bool waiting_; }; class MsgData : public MessageData { public: MsgData(const byte_t* data, const size_t data_size, const gcs_msg_type_t msg_type) : data_ (data), data_size_(data_size), msg_type_ (msg_type) { } const byte_t* get_data() const { return data_; } size_t get_data_size() const { return data_size_; } gcs_msg_type_t get_msg_type() const { return msg_type_; } public: MsgData(const MsgData&); void operator=(const MsgData&); const byte_t* data_; size_t data_size_; gcs_msg_type_t msg_type_; }; class GCommConn : public Consumer, public Toplay { public: GCommConn(const URI& u, gu::Config& cnf) : Toplay(cnf), conf_(cnf), uuid_(), thd_(), uri_(u), net_(Protonet::create(conf_)), tp_(0), mutex_(), refcnt_(0), terminated_(false), error_(0), recv_buf_(), current_view_(), prof_("gcs_gcomm") { log_info << "backend: " << net_->type(); } ~GCommConn() { delete net_; } const gcomm::UUID& get_uuid() const { return uuid_; } static void* run_fn(void* arg) { static_cast(arg)->run(); return 0; } void connect(bool) { } void connect(const string& channel, bool const bootstrap) { if (tp_ != 0) { gu_throw_fatal << "backend connection already open"; } uri_.set_option("gmcast.group", channel); tp_ = Transport::create(*net_, uri_); gcomm::connect(tp_, this); if (bootstrap) { log_info << "gcomm: bootstrapping new group '" << channel << '\''; } else { string peer; URI::AuthorityList::const_iterator i, i_next; for (i = uri_.get_authority_list().begin(); i != uri_.get_authority_list().end(); ++i) { i_next = i; ++i_next; string host; string port; try { host = i->host(); } catch (NotSet&) { } try { port = i->port(); } catch (NotSet&) { } peer += host != "" ? host + ":" + port : ""; if (i_next != uri_.get_authority_list().end()) { peer += ","; } } log_info << "gcomm: connecting to group '" << channel << "', peer '" << peer << "'"; } tp_->connect(bootstrap); uuid_ = tp_->uuid(); int err; if ((err = pthread_create(&thd_, 0, &run_fn, this)) != 0) { gu_throw_error(err); } log_info << "gcomm: connected"; } void close(bool force = false) { if (tp_ == 0) { log_warn << "gcomm: backend already closed"; return; } { gcomm::Critical crit(*net_); log_info << "gcomm: terminating thread"; terminate(); } log_info << "gcomm: joining thread"; pthread_join(thd_, 0); { gcomm::Critical crit(*net_); log_info << "gcomm: closing backend"; tp_->close(error_ != 0 || force == true); gcomm::disconnect(tp_, this); delete tp_; tp_ = 0; } const Message* msg; while ((msg = get_next_msg()) != 0) { return_ack(Message(&msg->get_producer(), 0, -ECONNABORTED)); } log_info << "gcomm: closed"; log_debug << prof_; } void run(); void notify() { net_->interrupt(); } void terminate() { Lock lock(mutex_); terminated_ = true; net_->interrupt(); } void handle_up (const void* id, const Datagram& dg, const ProtoUpMeta& um); void queue_and_wait(const Message& msg, Message* ack); RecvBuf& get_recv_buf() { return recv_buf_; } size_t get_mtu() const { if (tp_ == 0) { gu_throw_fatal << "GCommConn::get_mtu(): " << "backend connection not open"; } return tp_->mtu(); } Protonet& get_pnet() { return *net_; } gu::Config& get_conf() { return conf_; } int get_error() const { return error_; } void get_status(gu::Status& status) const { if (tp_ != 0) tp_->get_status(status); } class Ref { public: Ref(gcs_backend_t* ptr, bool unset = false) : conn_(0) { if (ptr->conn != 0) { conn_ = reinterpret_cast(ptr->conn)->ref(unset); if (unset == true) { ptr->conn = 0; } } } ~Ref() { if (conn_ != 0) { conn_->unref(); } } GCommConn* get() { return conn_; } private: Ref(const Ref&); void operator=(const Ref&); GCommConn* conn_; }; private: GCommConn(const GCommConn&); void operator=(const GCommConn&); GCommConn* ref(const bool unsetting) { return this; } void unref() { } gu::Config& conf_; gcomm::UUID uuid_; pthread_t thd_; URI uri_; Protonet* net_; Transport* tp_; Mutex mutex_; size_t refcnt_; bool terminated_; int error_; RecvBuf recv_buf_; View current_view_; Profile prof_; }; void GCommConn::handle_up(const void* id, const Datagram& dg, const ProtoUpMeta& um) { if (um.err_no() != 0) { error_ = um.err_no(); // force backend close close(true); recv_buf_.push_back(RecvBufData(numeric_limits::max(), dg, um)); } else if (um.has_view() == true) { current_view_ = um.view(); recv_buf_.push_back(RecvBufData(numeric_limits::max(), dg, um)); if (current_view_.is_empty()) { log_debug << "handle_up: self leave"; } } else { size_t idx(0); for (NodeList::const_iterator i = current_view_.members().begin(); i != current_view_.members().end(); ++i) { if (NodeList::key(i) == um.source()) { profile_enter(prof_); recv_buf_.push_back(RecvBufData(idx, dg, um)); profile_leave(prof_); break; } ++idx; } assert(idx < current_view_.members().size()); } } void GCommConn::queue_and_wait(const Message& msg, Message* ack) { { Lock lock(mutex_); if (terminated_ == true) { *ack = Message(&msg.get_producer(), 0, -ECONNABORTED); return; } } profile_enter(prof_); Consumer::queue_and_wait(msg, ack); profile_leave(prof_); } void GCommConn::run() { while (true) { { Lock lock(mutex_); if (terminated_ == true) { break; } } try { net_->event_loop(Sec); } catch (gu::Exception& e) { log_error << "exception from gcomm, backend must be restarted: " << e.what(); // Commented out due to Backtrace() not producing proper // backtraces. // log_info << "attempting to get backtrace:"; // Backtrace().print(std::cerr); gcomm::Critical crit(get_pnet()); handle_up(0, Datagram(), ProtoUpMeta(gcomm::UUID::nil(), ViewId(V_NON_PRIM), 0, 0xff, O_DROP, -1, e.get_errno())); break; } #if 0 // Disabled catching unknown exceptions due to Backtrace() not // producing proper backtraces. We let the application crash // and deal with diagnostics. catch (...) { log_error << "unknow exception from gcomm, backend must be restarted"; log_info << "attempting to get backtrace:"; Backtrace().print(std::cerr); gcomm::Critical crit(get_pnet()); handle_up(0, Datagram(), ProtoUpMeta(gcomm::UUID::nil(), ViewId(V_NON_PRIM), 0, 0xff, O_DROP, -1, gu::Exception::E_UNSPEC)); break; } #endif } } //////////////////////////////////////////////////////////////////////////// // // Backend interface implementation // //////////////////////////////////////////////////////////////////////////// static GCS_BACKEND_MSG_SIZE_FN(gcomm_msg_size) { GCommConn::Ref ref(backend); if (ref.get() == 0) { return -1; } return ref.get()->get_mtu(); } static GCS_BACKEND_SEND_FN(gcomm_send) { GCommConn::Ref ref(backend); if (gu_unlikely(ref.get() == 0)) { return -EBADFD; } GCommConn& conn(*ref.get()); Datagram dg( SharedBuffer( new Buffer(reinterpret_cast(buf), reinterpret_cast(buf) + len))); gcomm::Critical crit(conn.get_pnet()); if (gu_unlikely(conn.get_error() != 0)) { return -ECONNABORTED; } int err = conn.send_down( dg, ProtoDownMeta(msg_type, msg_type == GCS_MSG_CAUSAL ? O_LOCAL_CAUSAL : O_SAFE)); return (err == 0 ? len : -err); } static void fill_cmp_msg(const View& view, const gcomm::UUID& my_uuid, gcs_comp_msg_t* cm) { size_t n(0); for (NodeList::const_iterator i = view.members().begin(); i != view.members().end(); ++i) { const gcomm::UUID& uuid(NodeList::key(i)); log_debug << "member: " << n << " uuid: " << uuid << " segment: " << static_cast(i->second.segment()); // (void)snprintf(cm->memb[n].id, GCS_COMP_MEMB_ID_MAX_LEN, "%s", // uuid._str().c_str()); long ret = gcs_comp_msg_add (cm, uuid.full_str().c_str(), i->second.segment()); if (ret < 0) { gu_throw_error(-ret) << "Failed to add member '" << uuid << "' to component message."; } if (uuid == my_uuid) { log_debug << "my index " << n; cm->my_idx = n; } ++n; } } static GCS_BACKEND_RECV_FN(gcomm_recv) { GCommConn::Ref ref(backend); if (gu_unlikely(ref.get() == 0)) return -EBADFD; try { GCommConn& conn(*ref.get()); RecvBuf& recv_buf(conn.get_recv_buf()); const RecvBufData& d(recv_buf.front(timeout)); msg->sender_idx = d.get_source_idx(); const Datagram& dg(d.get_dgram()); const ProtoUpMeta& um(d.get_um()); if (gu_likely(dg.len() != 0)) { assert(dg.len() > dg.offset()); const byte_t* b(gcomm::begin(dg)); const ssize_t pload_len(gcomm::available(dg)); msg->size = pload_len; if (gu_likely(pload_len <= msg->buf_len)) { memcpy(msg->buf, b, pload_len); msg->type = static_cast(um.user_type()); recv_buf.pop_front(); } else { msg->type = GCS_MSG_ERROR; } } else if (um.err_no() != 0) { gcs_comp_msg_t* cm(gcs_comp_msg_leave(ECONNABORTED)); const ssize_t cm_size(gcs_comp_msg_size(cm)); if (cm_size <= msg->buf_len) { memcpy(msg->buf, cm, cm_size); recv_buf.pop_front(); msg->type = GCS_MSG_COMPONENT; } else { msg->type = GCS_MSG_ERROR; } gcs_comp_msg_delete(cm); } else { assert(um.has_view() == true); const View& view(um.view()); assert(view.type() == V_PRIM || view.type() == V_NON_PRIM); gcs_comp_msg_t* cm(gcs_comp_msg_new(view.type() == V_PRIM, view.is_bootstrap(), view.is_empty() ? -1 : 0, view.members().size(), 0)); const ssize_t cm_size(gcs_comp_msg_size(cm)); if (cm->my_idx == -1) { log_debug << "gcomm recv: self leave"; } msg->size = cm_size; if (gu_likely(cm_size <= msg->buf_len)) { fill_cmp_msg(view, conn.get_uuid(), cm); memcpy(msg->buf, cm, cm_size); recv_buf.pop_front(); msg->type = GCS_MSG_COMPONENT; } else { msg->type = GCS_MSG_ERROR; } gcs_comp_msg_delete(cm); } return msg->size; } catch (Exception& e) { long err = e.get_errno(); if (ETIMEDOUT != err) { log_error << e.what(); } return -err; } } static GCS_BACKEND_NAME_FN(gcomm_name) { static const char *name = "gcomm"; return name; } static GCS_BACKEND_OPEN_FN(gcomm_open) { GCommConn::Ref ref(backend); if (ref.get() == 0) { return -EBADFD; } GCommConn& conn(*ref.get()); try { gcomm::Critical crit(conn.get_pnet()); conn.connect(channel, bootstrap); } catch (Exception& e) { log_error << "failed to open gcomm backend connection: " << e.get_errno() << ": " << e.what(); return -e.get_errno(); } return 0; } static GCS_BACKEND_CLOSE_FN(gcomm_close) { GCommConn::Ref ref(backend); if (ref.get() == 0) { return -EBADFD; } GCommConn& conn(*ref.get()); try { // Critical section is entered inside close() call. // gcomm::Critical crit(conn.get_pnet()); conn.close(); } catch (Exception& e) { log_error << "failed to close gcomm backend connection: " << e.get_errno() << ": " << e.what(); gcomm::Critical crit(conn.get_pnet()); conn.handle_up(0, Datagram(), ProtoUpMeta(gcomm::UUID::nil(), ViewId(V_NON_PRIM), 0, 0xff, O_DROP, -1, e.get_errno())); // #661: Pretend that closing was successful, backend should be // in unusable state anyway. This allows gcs to finish shutdown // sequence properly. } return 0; } static GCS_BACKEND_DESTROY_FN(gcomm_destroy) { GCommConn::Ref ref(backend, true); if (ref.get() == 0) { log_warn << "could not get reference to backend conn"; return -EBADFD; } GCommConn* conn(ref.get()); try { delete conn; } catch (Exception& e) { log_warn << "conn destroy failed: " << e.get_errno(); return -e.get_errno(); } return 0; } static GCS_BACKEND_PARAM_SET_FN(gcomm_param_set) { GCommConn::Ref ref(backend); if (ref.get() == 0) { return -EBADFD; } GCommConn& conn(*ref.get()); try { gcomm::Critical crit(conn.get_pnet()); if (gu_unlikely(conn.get_error() != 0)) { return -ECONNABORTED; } if (conn.get_pnet().set_param(key, value) == false) { log_debug << "param " << key << " not recognized"; return 1; } else { return 0; } } catch (gu::Exception& e) { log_warn << "error setting param " << key << " to value " << value << ": " << e.what(); return -e.get_errno(); } catch (gu::NotFound& nf) { log_warn << "error setting param " << key << " to value " << value; return -EINVAL; } catch (gu::NotSet& nf) { log_warn << "error setting param " << key << " to value " << value; return -EINVAL; } catch (...) { log_fatal << "gcomm param set: caught unknown exception"; return -ENOTRECOVERABLE; } } static GCS_BACKEND_PARAM_GET_FN(gcomm_param_get) { return NULL; } static GCS_BACKEND_STATUS_GET_FN(gcomm_status_get) { GCommConn::Ref ref(backend); if (ref.get() == 0) { gu_throw_error(-EBADFD); } GCommConn& conn(*ref.get()); gcomm::Critical crit(conn.get_pnet()); conn.get_status(status); } GCS_BACKEND_REGISTER_FN(gcs_gcomm_register) { try { gcomm::Conf::register_params(*reinterpret_cast(cnf)); return false; } catch (...) { return true; } } GCS_BACKEND_CREATE_FN(gcs_gcomm_create) { GCommConn* conn(0); if (!cnf) { log_error << "Null config object passed to constructor."; return -EINVAL; } try { gu::URI uri(std::string("pc://") + addr); gu::Config& conf(*reinterpret_cast(cnf)); conn = new GCommConn(uri, conf); } catch (Exception& e) { log_error << "failed to create gcomm backend connection: " << e.get_errno() << ": " << e.what(); return -e.get_errno(); } backend->open = gcomm_open; backend->close = gcomm_close; backend->destroy = gcomm_destroy; backend->send = gcomm_send; backend->recv = gcomm_recv; backend->name = gcomm_name; backend->msg_size = gcomm_msg_size; backend->param_set = gcomm_param_set; backend->param_get = gcomm_param_get; backend->status_get = gcomm_status_get; backend->conn = reinterpret_cast(conn); return 0; } percona-galera-3-3.8-3390/gcs/src/gcs_gcomm.hpp000066400000000000000000000004271244131713600210170ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ #ifndef _gcs_gcomm_h_ #define _gcs_gcomm_h_ #include "gcs_backend.hpp" extern GCS_BACKEND_REGISTER_FN(gcs_gcomm_register); extern GCS_BACKEND_CREATE_FN(gcs_gcomm_create); #endif /* _gcs_vs_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_group.cpp000066400000000000000000001422621244131713600210500ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ #include "gcs_group.hpp" #include "gcs_gcache.hpp" #include "gcs_priv.hpp" #include const char* gcs_group_state_str[GCS_GROUP_STATE_MAX] = { "NON_PRIMARY", "WAIT_STATE_UUID", "WAIT_STATE_MSG", "PRIMARY" }; int gcs_group_init (gcs_group_t* group, gcache_t* const cache, const char* node_name, const char* inc_addr, gcs_proto_t const gcs_proto_ver, int const repl_proto_ver, int const appl_proto_ver) { // here we also create default node instance. group->cache = cache; group->act_id = GCS_SEQNO_ILL; group->conf_id = GCS_SEQNO_ILL; group->state_uuid = GU_UUID_NIL; group->group_uuid = GU_UUID_NIL; group->num = 1; // this must be removed (#474) group->my_idx = 0; // this must be -1 (#474) group->my_name = strdup(node_name ? node_name : NODE_NO_NAME); group->my_address = strdup(inc_addr ? inc_addr : NODE_NO_ADDR); group->state = GCS_GROUP_NON_PRIMARY; group->last_applied = GCS_SEQNO_ILL; // mark for recalculation group->last_node = -1; group->frag_reset = true; // just in case group->nodes = GU_CALLOC(group->num, gcs_node_t); // this must be removed (#474) if (!group->nodes) return -ENOMEM; // this should be removed (#474) /// this should be removed (#474) gcs_node_init (&group->nodes[group->my_idx], group->cache, NODE_NO_ID, group->my_name, group->my_address, gcs_proto_ver, repl_proto_ver, appl_proto_ver, 0); group->prim_uuid = GU_UUID_NIL; group->prim_seqno = GCS_SEQNO_ILL; group->prim_num = 0; group->prim_state = GCS_NODE_STATE_NON_PRIM; *(gcs_proto_t*)&group->gcs_proto_ver = gcs_proto_ver; *(int*)&group->repl_proto_ver = repl_proto_ver; *(int*)&group->appl_proto_ver = appl_proto_ver; group->quorum = GCS_QUORUM_NON_PRIMARY; group->last_applied_proto_ver = -1; return 0; } int gcs_group_init_history (gcs_group_t* group, gcs_seqno_t seqno, const gu_uuid_t* uuid) { bool negative_seqno = (seqno < 0); bool nil_uuid = !gu_uuid_compare (uuid, &GU_UUID_NIL); if (negative_seqno && !nil_uuid) { gu_error ("Non-nil history UUID with negative seqno (%lld) makes " "no sense.", (long long) seqno); return -EINVAL; } else if (!negative_seqno && nil_uuid) { gu_error ("Non-negative state seqno requires non-nil history UUID."); return -EINVAL; } group->act_id = seqno; group->group_uuid = *uuid; return 0; } /* Initialize nodes array from component message */ static inline gcs_node_t* group_nodes_init (const gcs_group_t* group, const gcs_comp_msg_t* comp) { const long my_idx = gcs_comp_msg_self (comp); const long nodes_num = gcs_comp_msg_num (comp); gcs_node_t* ret = GU_CALLOC (nodes_num, gcs_node_t); long i; if (ret) { for (i = 0; i < nodes_num; i++) { const gcs_comp_memb_t* memb = gcs_comp_msg_member(comp, i); assert(NULL != memb); if (my_idx != i) { gcs_node_init (&ret[i], group->cache, memb->id, NULL, NULL, -1, -1, -1, memb->segment); } else { // this node gcs_node_init (&ret[i], group->cache, memb->id, group->my_name, group->my_address, group->gcs_proto_ver, group->repl_proto_ver, group->appl_proto_ver, memb->segment); } } } else { gu_error ("Could not allocate %ld x %z bytes", nodes_num, sizeof(gcs_node_t)); } return ret; } /* Free nodes array */ static void group_nodes_free (gcs_group_t* group) { int i; /* cleanup after disappeared members */ for (i = 0; i < group->num; i++) { gcs_node_free (&group->nodes[i]); } if (group->nodes) gu_free (group->nodes); group->nodes = NULL; group->num = 0; group->my_idx = -1; } void gcs_group_free (gcs_group_t* group) { if (group->my_name) free ((char*)group->my_name); if (group->my_address) free ((char*)group->my_address); group_nodes_free (group); } /* Reset nodes array without breaking the statistics */ static inline void group_nodes_reset (gcs_group_t* group) { int i; /* reset recv_acts at the nodes */ for (i = 0; i < group->num; i++) { if (i != group->my_idx) { gcs_node_reset (&group->nodes[i]); } else { gcs_node_reset_local (&group->nodes[i]); } } group->frag_reset = true; } /* Find node with the smallest last_applied */ static inline void group_redo_last_applied (gcs_group_t* group) { long n; long last_node = -1; gu_seqno_t last_applied = GU_LONG_LONG_MAX; for (n = 0; n < group->num; n++) { const gcs_node_t* const node = &group->nodes[n]; gcs_seqno_t const seqno = node->last_applied; bool count = node->count_last_applied; if (gu_unlikely (0 == group->last_applied_proto_ver)) { /* @note: this may be removed after quorum v1 is phased out */ count = (GCS_NODE_STATE_SYNCED == node->status || GCS_NODE_STATE_DONOR == node->status); } // gu_debug ("last_applied[%ld]: %lld", n, seqno); /* NOTE: It is crucial for consistency that last_applied algorithm * is absolutely identical on all nodes. Therefore for the * generality sake and future compatibility we have to assume * non-blocking donor. * GCS_BLOCKING_DONOR should never be defined unless in some * very custom builds. Commenting it out for safety sake. */ //#ifndef GCS_BLOCKING_DONOR if (count //#else // if ((GCS_NODE_STATE_SYNCED == node->status) /* ignore donor */ //#endif && (seqno < last_applied)) { assert (seqno >= 0); last_applied = seqno; last_node = n; } // extra diagnostic, ignore //else if (!count) { gu_warn("not counting %d", n); } } if (gu_likely (last_node >= 0)) { group->last_applied = last_applied; group->last_node = last_node; } } static void group_go_non_primary (gcs_group_t* group) { if (group->my_idx >= 0) { assert(group->num > 0); assert(group->nodes); group->nodes[group->my_idx].status = GCS_NODE_STATE_NON_PRIM; //@todo: Perhaps the same has to be applied to the rest of the nodes[]? } else { assert(-1 == group->my_idx); assert(0 == group->num); assert(NULL == group->nodes); } group->state = GCS_GROUP_NON_PRIMARY; group->conf_id = GCS_SEQNO_ILL; // what else? Do we want to change anything about the node here? } static const char group_empty_id[GCS_COMP_MEMB_ID_MAX_LEN + 1] = { 0, }; static void group_check_donor (gcs_group_t* group) { gcs_node_state_t const my_state = group->nodes[group->my_idx].status; const char* const donor_id = group->nodes[group->my_idx].donor; if (GCS_NODE_STATE_JOINER == my_state && memcmp (donor_id, group_empty_id, sizeof(group_empty_id))) { long i; for (i = 0; i < group->num; i++) { if (i != group->my_idx && !memcmp (donor_id, group->nodes[i].id, sizeof (group->nodes[i].id))) return; } gu_warn ("Donor %s is no longer in the group. State transfer cannot " "be completed, need to abort. Aborting...", donor_id); gu_abort(); } return; } /*! Processes state messages and sets group parameters accordingly */ static void group_post_state_exchange (gcs_group_t* group) { const gcs_state_msg_t* states[group->num]; gcs_state_quorum_t* quorum = &group->quorum; bool new_exchange = gu_uuid_compare (&group->state_uuid, &GU_UUID_NIL); long i; /* Collect state messages from nodes. */ /* Looping here every time is suboptimal, but simply counting state messages * is not straightforward too: nodes may disappear, so the final count may * include messages from the disappeared nodes. * Let's put it this way: looping here is reliable and not that expensive.*/ for (i = 0; i < group->num; i++) { states[i] = group->nodes[i].state_msg; if (NULL == states[i] || (new_exchange && gu_uuid_compare (&group->state_uuid, gcs_state_msg_uuid(states[i])))) return; // not all states from THIS state exch. received, wait } gu_debug ("STATE EXCHANGE: "GU_UUID_FORMAT" complete.", GU_UUID_ARGS(&group->state_uuid)); gcs_state_msg_get_quorum (states, group->num, quorum); if (quorum->version >= 0) { if (quorum->version < 2) { group->last_applied_proto_ver = 0; } else { group->last_applied_proto_ver = 1; } } else { gu_fatal ("Negative quorum version: %d", quorum->version); abort(); } // Update each node state based on quorum outcome: // is it up to date, does it need SST and stuff for (i = 0; i < group->num; i++) { gcs_node_update_status (&group->nodes[i], quorum); } if (quorum->primary) { // primary configuration if (new_exchange) { // new state exchange happened group->state = GCS_GROUP_PRIMARY; group->act_id = quorum->act_id; group->conf_id = quorum->conf_id + 1; group->group_uuid = quorum->group_uuid; group->prim_uuid = group->state_uuid; group->state_uuid = GU_UUID_NIL; } else { // no state exchange happend, processing old state messages assert (GCS_GROUP_PRIMARY == group->state); group->conf_id++; } group->prim_seqno = group->conf_id; group->prim_num = 0; for (i = 0; i < group->num; i++) { group->prim_num += gcs_node_is_joined (group->nodes[i].status); } assert (group->prim_num > 0); } else { // non-primary configuration group_go_non_primary (group); } gu_info ("Quorum results:" "\n\tversion = %u," "\n\tcomponent = %s," "\n\tconf_id = %lld," "\n\tmembers = %d/%d (joined/total)," "\n\tact_id = %lld," "\n\tlast_appl. = %lld," "\n\tprotocols = %d/%d/%d (gcs/repl/appl)," "\n\tgroup UUID = "GU_UUID_FORMAT, quorum->version, quorum->primary ? "PRIMARY" : "NON-PRIMARY", quorum->conf_id, group->prim_num, group->num, quorum->act_id, group->last_applied, quorum->gcs_proto_ver, quorum->repl_proto_ver, quorum->appl_proto_ver, GU_UUID_ARGS(&quorum->group_uuid)); group_check_donor(group); } // does basic sanity check of the component message (in response to #145) static void group_check_comp_msg (bool prim, long my_idx, long members) { if (my_idx >= 0) { if (my_idx < members) return; } else { if (!prim && (0 == members)) return; } gu_fatal ("Malformed component message from backend: " "%s, idx = %ld, members = %ld", prim ? "PRIMARY" : "NON-PRIMARY", my_idx, members); assert (0); gu_abort (); } gcs_group_state_t gcs_group_handle_comp_msg (gcs_group_t* group, const gcs_comp_msg_t* comp) { long new_idx, old_idx; gcs_node_t* new_nodes = NULL; ulong new_memb = 0; const bool prim_comp = gcs_comp_msg_primary (comp); const bool bootstrap = gcs_comp_msg_bootstrap(comp); const long new_my_idx = gcs_comp_msg_self (comp); const long new_nodes_num = gcs_comp_msg_num (comp); group_check_comp_msg (prim_comp, new_my_idx, new_nodes_num); if (new_my_idx >= 0) { gu_info ("New COMPONENT: primary = %s, bootstrap = %s, my_idx = %ld, " "memb_num = %ld", prim_comp ? "yes" : "no", bootstrap ? "yes" : "no", new_my_idx, new_nodes_num); new_nodes = group_nodes_init (group, comp); if (!new_nodes) { gu_fatal ("Could not allocate memory for %ld-node component.", gcs_comp_msg_num (comp)); assert(0); return (gcs_group_state_t)-ENOMEM; } if (GCS_GROUP_PRIMARY == group->state) { gu_debug ("#281: Saving %s over %s", gcs_node_state_to_str(group->nodes[group->my_idx].status), gcs_node_state_to_str(group->prim_state)); group->prim_state = group->nodes[group->my_idx].status; } } else { // Self-leave message gu_info ("Received self-leave message."); assert (0 == new_nodes_num); assert (!prim_comp); } if (prim_comp) { /* Got PRIMARY COMPONENT - Hooray! */ assert (new_my_idx >= 0); if (group->state == GCS_GROUP_PRIMARY) { /* we come from previous primary configuration, relax */ } else if (bootstrap) { /* Is there need to initialize something else in this case? */ group->nodes[group->my_idx].bootstrap = true; } else { const bool first_component = #ifndef GCS_CORE_TESTING (1 == group->num) && !strcmp (NODE_NO_ID, group->nodes[0].id); #else (1 == group->num); #endif if (1 == new_nodes_num && first_component) { /* bootstrap new configuration */ assert (GCS_GROUP_NON_PRIMARY == group->state); assert (1 == group->num); assert (0 == group->my_idx); // This bootstraps initial primary component for state exchange gu_uuid_generate (&group->prim_uuid, NULL, 0); group->prim_seqno = 0; group->prim_num = 1; group->state = GCS_GROUP_PRIMARY; if (group->act_id < 0) { // no history provided: start a new one group->act_id = GCS_SEQNO_NIL; gu_uuid_generate (&group->group_uuid, NULL, 0); gu_info ("Starting new group from scratch: "GU_UUID_FORMAT, GU_UUID_ARGS(&group->group_uuid)); } // the following should be removed under #474 group->nodes[0].status = GCS_NODE_STATE_JOINED; /* initialize node ID to the one given by the backend - this way * we'll be recognized as coming from prev. conf. in node array * remap below */ strncpy ((char*)group->nodes[0].id, new_nodes[0].id, sizeof (new_nodes[0].id) - 1); group->nodes[0].segment = new_nodes[0].segment; } } } else { group_go_non_primary (group); } /* Remap old node array to new one to preserve action continuity */ for (new_idx = 0; new_idx < new_nodes_num; new_idx++) { /* find member index in old component by unique member id */ for (old_idx = 0; old_idx < group->num; old_idx++) { // just scan through old group if (!strcmp(group->nodes[old_idx].id, new_nodes[new_idx].id)) { /* the node was in previous configuration with us */ /* move node context to new node array */ gcs_node_move (&new_nodes[new_idx], &group->nodes[old_idx]); break; } } /* if wasn't found in new configuration, new member - * need to do state exchange */ new_memb |= (old_idx == group->num); } /* free old nodes array */ group_nodes_free (group); group->my_idx = new_my_idx; group->num = new_nodes_num; group->nodes = new_nodes; if (gcs_comp_msg_primary(comp) || bootstrap) { /* TODO: for now pretend that we always have new nodes and perform * state exchange because old states can carry outdated node status. * (also protocol voting needs to be redone) * However this means aborting ongoing actions. Find a way to avoid * this extra state exchange. Generate new state messages on behalf * of other nodes? see #238 */ new_memb = true; /* if new nodes joined, reset ongoing actions and state messages */ if (new_memb) { group_nodes_reset (group); group->state = GCS_GROUP_WAIT_STATE_UUID; group->state_uuid = GU_UUID_NIL; // prepare for state exchange } else { if (GCS_GROUP_PRIMARY == group->state) { /* since we don't have any new nodes since last PRIMARY, we skip state exchange */ group_post_state_exchange (group); } } group_redo_last_applied (group); } return group->state; } gcs_group_state_t gcs_group_handle_uuid_msg (gcs_group_t* group, const gcs_recv_msg_t* msg) { assert (msg->size == sizeof(gu_uuid_t)); if (GCS_GROUP_WAIT_STATE_UUID == group->state && 0 == msg->sender_idx /* check that it is from the representative */) { group->state_uuid = *(gu_uuid_t*)msg->buf; group->state = GCS_GROUP_WAIT_STATE_MSG; } else { gu_warn ("Stray state UUID msg: "GU_UUID_FORMAT " from node %ld (%s), current group state %s", GU_UUID_ARGS((gu_uuid_t*)msg->buf), msg->sender_idx, group->nodes[msg->sender_idx].name, gcs_group_state_str[group->state]); } return group->state; } static void group_print_state_debug(gcs_state_msg_t* state) { size_t str_len = 1024; char state_str[str_len]; gcs_state_msg_snprintf (state_str, str_len, state); gu_info ("%s", state_str); } gcs_group_state_t gcs_group_handle_state_msg (gcs_group_t* group, const gcs_recv_msg_t* msg) { if (GCS_GROUP_WAIT_STATE_MSG == group->state) { gcs_state_msg_t* state = gcs_state_msg_read (msg->buf, msg->size); if (state) { const gu_uuid_t* state_uuid = gcs_state_msg_uuid (state); if (!gu_uuid_compare(&group->state_uuid, state_uuid)) { gu_info ("STATE EXCHANGE: got state msg: "GU_UUID_FORMAT " from %d (%s)", GU_UUID_ARGS(state_uuid), msg->sender_idx, gcs_state_msg_name(state)); if (gu_log_debug) group_print_state_debug(state); gcs_node_record_state (&group->nodes[msg->sender_idx], state); group_post_state_exchange (group); } else { gu_debug ("STATE EXCHANGE: stray state msg: "GU_UUID_FORMAT " from node %ld (%s), current state UUID: " GU_UUID_FORMAT, GU_UUID_ARGS(state_uuid), msg->sender_idx, gcs_state_msg_name(state), GU_UUID_ARGS(&group->state_uuid)); if (gu_log_debug) group_print_state_debug(state); gcs_state_msg_destroy (state); } } else { gu_warn ("Could not parse state message from node %d", msg->sender_idx, group->nodes[msg->sender_idx].name); } } return group->state; } /*! Returns new last applied value if it has changes, 0 otherwise */ gcs_seqno_t gcs_group_handle_last_msg (gcs_group_t* group, const gcs_recv_msg_t* msg) { gcs_seqno_t seqno; assert (GCS_MSG_LAST == msg->type); assert (sizeof(gcs_seqno_t) == msg->size); seqno = gcs_seqno_gtoh(*(gcs_seqno_t*)(msg->buf)); // This assert is too restrictive. It requires application to send // last applied messages while holding TO, otherwise there's a race // between threads. // assert (seqno >= group->last_applied); gcs_node_set_last_applied (&group->nodes[msg->sender_idx], seqno); if (msg->sender_idx == group->last_node && seqno > group->last_applied) { /* node that was responsible for the last value, has changed it. * need to recompute it */ gcs_seqno_t old_val = group->last_applied; group_redo_last_applied (group); if (old_val < group->last_applied) { gu_debug ("New COMMIT CUT %lld after %lld from %d", (long long)group->last_applied, (long long)seqno, msg->sender_idx); return group->last_applied; } } return 0; } /*! return true if this node is the sender to notify the calling thread of * success */ int gcs_group_handle_join_msg (gcs_group_t* group, const gcs_recv_msg_t* msg) { int const sender_idx = msg->sender_idx; gcs_node_t* sender = &group->nodes[sender_idx]; assert (GCS_MSG_JOIN == msg->type); // TODO: define an explicit type for the join message, like gcs_join_msg_t assert (msg->size == sizeof(gcs_seqno_t)); if (GCS_NODE_STATE_DONOR == sender->status || GCS_NODE_STATE_JOINER == sender->status) { int j; gcs_seqno_t seqno = gcs_seqno_gtoh(*(gcs_seqno_t*)msg->buf); gcs_node_t* peer = NULL; const char* peer_id = NULL; const char* peer_name = "left the group"; int peer_idx = -1; bool from_donor = false; const char* st_dir = NULL; // state transfer direction symbol if (GCS_NODE_STATE_DONOR == sender->status) { peer_id = sender->joiner; from_donor = true; st_dir = "to"; assert (group->last_applied_proto_ver >= 0); if (0 == group->last_applied_proto_ver) { /* #454 - we don't switch to JOINED here, * instead going straignt to SYNCED */ } else { assert(sender->count_last_applied); sender->status = GCS_NODE_STATE_JOINED; } } else { peer_id = sender->donor; st_dir = "from"; if (group->quorum.version < 2) { // #591 remove after quorum v1 is phased out sender->status = GCS_NODE_STATE_JOINED; group->prim_num++; } else { if (seqno >= 0) { sender->status = GCS_NODE_STATE_JOINED; group->prim_num++; } else { sender->status = GCS_NODE_STATE_PRIM; } } } // Try to find peer. for (j = 0; j < group->num; j++) { // #483 if (j == sender_idx) continue; if (!memcmp(peer_id, group->nodes[j].id, sizeof (group->nodes[j].id))) { peer_idx = j; peer = &group->nodes[peer_idx]; peer_name = peer->name; break; } } if (j == group->num) { gu_warn ("Could not find peer: %s", peer_id); } if (seqno < 0) { gu_warn ("%d.%d (%s): State transfer %s %d.%d (%s) failed: %d (%s)", sender_idx, sender->segment, sender->name, st_dir, peer_idx, peer ? peer->segment : -1, peer_name, (int)seqno, strerror((int)-seqno)); if (from_donor && peer_idx == group->my_idx && GCS_NODE_STATE_JOINER == group->nodes[peer_idx].status) { // this node will be waiting for SST forever. If it has only // one recv thread there is no (generic) way to wake it up. gu_fatal ("Will never receive state. Need to abort."); // return to core to shutdown the backend before aborting return -ENOTRECOVERABLE; } if (group->quorum.version < 2 && !from_donor && // #591 sender_idx == group->my_idx) { // remove after quorum v1 is phased out gu_fatal ("Faield to receive state. Need to abort."); return -ENOTRECOVERABLE; } } else { if (sender_idx == peer_idx) { gu_info ("Member %d.%d (%s) resyncs itself to group", sender_idx, sender->segment, sender->name); } else { gu_info ("%d.%d (%s): State transfer %s %d.%d (%s) complete.", sender_idx, sender->segment, sender->name, st_dir, peer_idx, peer ? peer->segment : -1, peer_name); } } } else { if (GCS_NODE_STATE_PRIM == sender->status) { gu_warn("Rejecting JOIN message from %d.%d (%s): new State Transfer" " required.", sender_idx, sender->segment, sender->name); } else { // should we freak out and throw an error? gu_warn("Protocol violation. JOIN message sender %d.%d (%s) is not " "in state transfer (%s). Message ignored.", sender_idx, sender->segment, sender->name, gcs_node_state_to_str(sender->status)); } return 0; } return (sender_idx == group->my_idx); } int gcs_group_handle_sync_msg (gcs_group_t* group, const gcs_recv_msg_t* msg) { int const sender_idx = msg->sender_idx; gcs_node_t* sender = &group->nodes[sender_idx]; assert (GCS_MSG_SYNC == msg->type); if (GCS_NODE_STATE_JOINED == sender->status || /* #454 - at this layer we jump directly from DONOR to SYNCED */ (0 == group->last_applied_proto_ver && GCS_NODE_STATE_DONOR == sender->status)) { sender->status = GCS_NODE_STATE_SYNCED; sender->count_last_applied = true; group_redo_last_applied (group);//from now on this node must be counted gu_info ("Member %d.%d (%s) synced with group.", sender_idx, sender->segment, sender->name); return (sender_idx == group->my_idx); } else { if (GCS_NODE_STATE_SYNCED != sender->status) { gu_warn ("SYNC message sender from non-JOINED %d.%d (%s). Ignored.", sender_idx, sender->segment, sender->name); } else { gu_debug ("Redundant SYNC message from %d.%d (%s).", sender_idx, sender->segment, sender->name); } return 0; } } static inline bool group_node_is_stateful (const gcs_group_t* group, const gcs_node_t* node) { if (group->quorum.version < 3) { return strcmp (node->name, GCS_ARBITRATOR_NAME); } else { return ((gcs_node_flags(node) & GCS_STATE_ARBITRATOR) == 0); } } static int group_find_node_by_state (const gcs_group_t* const group, int const joiner_idx, gcs_node_state_t const status) { gcs_segment_t const segment = group->nodes[joiner_idx].segment; int idx; int donor = -1; bool hnss = false; /* have nodes in the same segment */ for (idx = 0; idx < group->num; idx++) { if (joiner_idx == idx) continue; /* skip joiner */ gcs_node_t* node = &group->nodes[idx]; if (node->status >= status && group_node_is_stateful (group, node)) donor = idx; /* potential donor */ if (segment == node->segment) { if (donor == idx) return donor; /* found suitable donor in the * same segment */ if (node->status >= GCS_NODE_STATE_JOINER) hnss = true;; } } /* Have not found suitable donor in the same segment. */ if (!hnss && donor >= 0) { if (joiner_idx == group->my_idx) { gu_warn ("There are no nodes in the same segment that will ever " "be able to become donors, yet there is a suitable donor " "outside. Will use that one."); } return donor; } else { /* wait for a suitable donor to appear in the same segment */ return -EAGAIN; } } static int group_find_node_by_name (const gcs_group_t* const group, int const joiner_idx, const char* const name, int const name_len, gcs_node_state_t const status) { int idx; for (idx = 0; idx < group->num; idx++) { gcs_node_t* node = &group->nodes[idx]; if (!strncmp(node->name, name, name_len)) { if (joiner_idx == idx) { return -EHOSTDOWN; } else if (node->status >= status) { return idx; } else if (node->status >= GCS_NODE_STATE_JOINER) { /* will eventually become SYNCED */ return -EAGAIN; } else { /* technically we could return -EDEADLK here, but as long as * it is not -EAGAIN, it does not matter. If the node is in a * PRIMARY state, it is as good as not found. */ break; } } } return -EHOSTUNREACH; } /* Calls group_find_node_by_name() for each name in comma-separated list, * falls back to group_find_node_by_state() if name (or list) is empty. */ static int group_for_each_donor_in_string (const gcs_group_t* const group, int const str_version, int const joiner_idx, const char* const str, int const str_len, gcs_node_state_t const status) { assert (str != NULL); const char* begin = str; const char* end; int err = -EHOSTDOWN; /* worst error */ /* dangling comma */ bool const dcomma = (str_len && str[str_len-1] == ',' && str_version >= 2); do { end = strchr(begin, ','); int len; if (NULL == end) { len = str_len - (begin - str); } else { len = end - begin; } assert (len >= 0); int idx; if (len > 0) { idx = group_find_node_by_name (group, joiner_idx, begin, len, status); } else { if (err == -EAGAIN && !dcomma) { /* -EAGAIN here means that at least one of the nodes in the * list will be available later, so don't try others. * (Proto 1 UPDATE: unless there is a dangling comma) */ idx = err; } else { idx = group_find_node_by_state(group, joiner_idx, status); } } if (idx >= 0) return idx; /* once we hit -EAGAIN, don't try to change error code: this means * that at least one of the nodes in the list will become available. */ if (-EAGAIN != err) err = idx; begin = end + 1; /* skip comma */ } while (end != NULL); return err; } static gcs_seqno_t group_lowest_cached_seqno(const gcs_group_t* const group) { gcs_seqno_t ret = GCS_SEQNO_ILL; int idx = 0; for (idx = 0; idx < group->num; idx++) { gcs_seqno_t seq = gcs_node_cached(&group->nodes[idx]); if (seq != GCS_SEQNO_ILL) { if (ret == GCS_SEQNO_ILL || seq < ret) { ret = seq; } } } return ret; } static int group_find_ist_donor_by_name (const gcs_group_t* const group, int joiner_idx, const char* name, int name_len, gcs_seqno_t ist_seqno, gcs_node_state_t status) { int idx = 0; for (idx = 0; idx < group->num; idx++) { gcs_node_t* node = &group->nodes[idx]; gcs_seqno_t cached = gcs_node_cached(node); if (strncmp(node->name, name, name_len) == 0 && joiner_idx != idx && node->status >= status && cached != GCS_SEQNO_ILL && // ist potentially possible (ist_seqno + 1) >= cached) { return idx; } } return -1; } static int group_find_ist_donor_by_name_in_string ( const gcs_group_t* const group, int joiner_idx, const char* str, int str_len, gcs_seqno_t ist_seqno, gcs_node_state_t status) { assert (str != NULL); const char* begin = str; const char* end; gu_debug("ist_seqno[%lld]", (long long)ist_seqno); // return the highest cached seqno node. int ret = -1; do { end = strchr(begin, ','); int len = 0; if (end == NULL) { len = str_len - (begin - str); } else { len = end - begin; } assert (len >= 0); if (len == 0) break; int idx = group_find_ist_donor_by_name( group, joiner_idx, begin, len, ist_seqno, status); if (idx >= 0) { if (ret == -1 || gcs_node_cached(&group->nodes[idx]) >= gcs_node_cached(&group->nodes[ret])) { ret = idx; } } begin = end + 1; } while (end != NULL); if (ret == -1) { gu_debug("not found"); } else { gu_debug("found. name[%s], seqno[%lld]", group->nodes[ret].name, (long long)gcs_node_cached(&group->nodes[ret])); } return ret; } static int group_find_ist_donor_by_state (const gcs_group_t* const group, int joiner_idx, gcs_seqno_t ist_seqno, gcs_node_state_t status) { gcs_node_t* joiner = &group->nodes[joiner_idx]; gcs_segment_t joiner_segment = joiner->segment; // find node who is ist potentially possible. // first highest cached seqno local node. // then highest cached seqno remote node. int idx = 0; int local_idx = -1; int remote_idx = -1; for (idx = 0; idx < group->num; idx++) { if (joiner_idx == idx) continue; gcs_node_t* const node = &group->nodes[idx]; gcs_seqno_t const node_cached = gcs_node_cached(node); if (node->status >= status && group_node_is_stateful(group, node) && node_cached != GCS_SEQNO_ILL && node_cached <= (ist_seqno + 1)) { int* const idx_ptr = (joiner_segment == node->segment) ? &local_idx : &remote_idx; if (*idx_ptr == -1 || node_cached >= gcs_node_cached(&group->nodes[*idx_ptr])) { *idx_ptr = idx; } } } if (local_idx >= 0) { gu_debug("local found. name[%s], seqno[%lld]", group->nodes[local_idx].name, (long long)gcs_node_cached(&group->nodes[local_idx])); return local_idx; } if (remote_idx >= 0) { gu_debug("remote found. name[%s], seqno[%lld]", group->nodes[remote_idx].name, (long long)gcs_node_cached(&group->nodes[remote_idx])); return remote_idx; } gu_debug("not found."); return -1; } static int group_find_ist_donor (const gcs_group_t* const group, int str_version, int joiner_idx, const char* str, int str_len, gcs_seqno_t ist_seqno, gcs_node_state_t status) { int idx = -1; gcs_seqno_t conf_seqno = group->quorum.act_id; gcs_seqno_t lowest_cached_seqno = group_lowest_cached_seqno(group); if (lowest_cached_seqno == GCS_SEQNO_ILL) { gu_debug("fallback to sst. lowest_cached_seqno == GCS_SEQNO_ILL"); return -1; } gcs_seqno_t const max_cached_range = conf_seqno - lowest_cached_seqno; gcs_seqno_t safety_gap = max_cached_range >> 7; /* 1.0 / 128 ~= 0.008 */ safety_gap = safety_gap < (1 << 20) ? safety_gap : (1 << 20); /* Be sensible and don't reserve more than 1M */ gcs_seqno_t safe_ist_seqno = lowest_cached_seqno + safety_gap; gu_debug("ist_seqno[%lld], lowest_cached_seqno[%lld]," "conf_seqno[%lld], safe_ist_seqno[%lld]", (long long)ist_seqno, (long long)lowest_cached_seqno, (long long)conf_seqno, (long long)safe_ist_seqno); if (ist_seqno < safe_ist_seqno) { // unsafe to perform ist. gu_debug("fallback to sst. ist_seqno < safe_ist_seqno"); return -1; } if (str_len) { // find ist donor by name. idx = group_find_ist_donor_by_name_in_string( group, joiner_idx, str, str_len, ist_seqno, status); if (idx >= 0) return idx; } // find ist donor by status. idx = group_find_ist_donor_by_state( group, joiner_idx, ist_seqno, status); if (idx >= 0) return idx; return -1; } int gcs_group_find_donor(const gcs_group_t* group, int const str_version, int const joiner_idx, const char* const donor_string, int const donor_len, const gu_uuid_t* ist_uuid, gcs_seqno_t ist_seqno) { static gcs_node_state_t const min_donor_state = GCS_NODE_STATE_SYNCED; /* try to find ist donor first. if it fails, fallbacks to find sst donor*/ int donor_idx = -1; if (str_version >= 2 && gu_uuid_compare(&group->group_uuid, ist_uuid) == 0) { assert (ist_seqno != GCS_SEQNO_ILL); donor_idx = group_find_ist_donor(group, str_version, joiner_idx, donor_string, donor_len, ist_seqno, min_donor_state); } if (donor_idx < 0) { /* if donor_string is empty, it will fallback to find_node_by_state() */ donor_idx = group_for_each_donor_in_string (group, str_version, joiner_idx, donor_string, donor_len, min_donor_state); } return donor_idx; } /*! * Selects and returns the index of state transfer donor, if available. * Updates donor and joiner status if state transfer is possible * * @return * donor index or negative error code: * -EHOSTUNREACH if reqiested donor is not available * -EAGAIN if there were no nodes in the proper state. */ static int group_select_donor (gcs_group_t* group, int const str_version, int const joiner_idx, const char* const donor_string, const gu_uuid_t* ist_uuid, gcs_seqno_t ist_seqno, bool const desync) { static gcs_node_state_t const min_donor_state = GCS_NODE_STATE_SYNCED; int donor_idx; int const donor_len = strlen(donor_string); bool const required_donor = (donor_len > 0); if (desync) { /* sender wants to become "donor" itself */ assert(donor_len > 0); gcs_node_state_t const st = group->nodes[joiner_idx].status; if (st >= min_donor_state) donor_idx = joiner_idx; else donor_idx = -EAGAIN; } else { donor_idx = gcs_group_find_donor(group, str_version, joiner_idx, donor_string, donor_len, ist_uuid, ist_seqno); } if (donor_idx >= 0) { assert(donor_idx != joiner_idx || desync); gcs_node_t* const joiner = &group->nodes[joiner_idx]; gcs_node_t* const donor = &group->nodes[donor_idx]; if (desync) { gu_info ("Member %d.%d (%s) desyncs itself from group", donor_idx, donor->segment, donor->name); } else { gu_info ("Member %d.%d (%s) requested state transfer from '%s'. " "Selected %d.%d (%s)(%s) as donor.", joiner_idx, joiner->segment, joiner->name, required_donor ? donor_string : "*any*", donor_idx, donor->segment, donor->name, gcs_node_state_to_str(donor->status)); } // reserve donor, confirm joiner (! assignment order is significant !) joiner->status = GCS_NODE_STATE_JOINER; donor->status = GCS_NODE_STATE_DONOR; memcpy (donor->joiner, joiner->id, GCS_COMP_MEMB_ID_MAX_LEN+1); memcpy (joiner->donor, donor->id, GCS_COMP_MEMB_ID_MAX_LEN+1); } else { gu_warn ("Member %d.%d (%s) requested state transfer from '%s', " "but it is impossible to select State Transfer donor: %s", joiner_idx, group->nodes[joiner_idx].segment, group->nodes[joiner_idx].name, required_donor ? donor_string : "*any*", strerror (-donor_idx)); } return donor_idx; } /* Cleanup ignored state request */ void gcs_group_ignore_action (gcs_group_t* group, struct gcs_act_rcvd* act) { if (act->act.type <= GCS_ACT_STATE_REQ) { gcs_gcache_free (group->cache, act->act.buf); } act->act.buf = NULL; act->act.buf_len = 0; act->act.type = GCS_ACT_ERROR; act->sender_idx = -1; assert (GCS_SEQNO_ILL == act->id); } static bool group_desync_request (const char* const donor) { return (strlen (GCS_DESYNC_REQ) == strlen(donor) && !strcmp(GCS_DESYNC_REQ, donor)); } /* NOTE: check gcs_request_state_transfer() for sender part. */ /*! Returns 0 if request is ignored, request size if it should be passed up */ int gcs_group_handle_state_request (gcs_group_t* group, struct gcs_act_rcvd* act) { // pass only to sender and to one potential donor const char* donor_name = (const char*)act->act.buf; size_t donor_name_len = strlen(donor_name); int donor_idx = -1; int const joiner_idx = act->sender_idx; const char* joiner_name = group->nodes[joiner_idx].name; gcs_node_state_t joiner_status = group->nodes[joiner_idx].status; bool const desync = group_desync_request (donor_name); gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; int str_version = 1; // actually it's 0 or 1. if (act->act.buf_len != (ssize_t)(donor_name_len + 1) && donor_name[donor_name_len + 1] == 'V') { str_version = (int)donor_name[donor_name_len + 2]; } if (str_version >= 2) { const char* ist_buf = donor_name + donor_name_len + 3; memcpy(&ist_uuid, ist_buf, sizeof(ist_uuid)); ist_seqno = gcs_seqno_gtoh(*(gcs_seqno_t*)(ist_buf + sizeof(ist_uuid))); // change act.buf's content to original version. // and it's safe to change act.buf_len size_t head = donor_name_len + 3 + sizeof(ist_uuid) + sizeof(ist_seqno); memmove((char*)act->act.buf + donor_name_len + 1, (char*)act->act.buf + head, act->act.buf_len - head); act->act.buf_len -= sizeof(ist_uuid) + sizeof(ist_seqno) + 2; } assert (GCS_ACT_STATE_REQ == act->act.type); if (joiner_status != GCS_NODE_STATE_PRIM && !desync) { const char* joiner_status_string = gcs_node_state_to_str(joiner_status); if (group->my_idx == joiner_idx) { gu_error ("Requesting state transfer while in %s. " "Ignoring.", joiner_status_string); act->id = -ECANCELED; return act->act.buf_len; } else { gu_error ("Member %d.%d (%s) requested state transfer, " "but its state is %s. Ignoring.", joiner_idx, group->nodes[joiner_idx].segment, joiner_name, joiner_status_string); gcs_group_ignore_action (group, act); return 0; } } donor_idx = group_select_donor(group, str_version, joiner_idx, donor_name, &ist_uuid, ist_seqno, desync); assert (donor_idx != joiner_idx || desync || donor_idx < 0); assert (donor_idx == joiner_idx || !desync || donor_idx < 0); if (group->my_idx != joiner_idx && group->my_idx != donor_idx) { // if neither DONOR nor JOINER, ignore request gcs_group_ignore_action (group, act); return 0; } else if (group->my_idx == donor_idx) { act->act.buf_len -= donor_name_len + 1; memmove (*(void**)&act->act.buf, ((char*)act->act.buf) + donor_name_len + 1, act->act.buf_len); // now action starts with request, like it was supplied by application, // see gcs_request_state_transfer() } // Return index of donor (or error) in the seqno field to sender. // It will be used to detect error conditions (no availabale donor, // donor crashed and the like). // This may be ugly, well, any ideas? act->id = donor_idx; return act->act.buf_len; } static ssize_t group_memb_record_size (gcs_group_t* group) { ssize_t ret = 0; long idx; for (idx = 0; idx < group->num; idx++) { ret += strlen(group->nodes[idx].id) + 1; ret += strlen(group->nodes[idx].name) + 1; ret += strlen(group->nodes[idx].inc_addr) + 1; ret += sizeof(gcs_seqno_t); // cached seqno } return ret; } /* Creates new configuration action */ ssize_t gcs_group_act_conf (gcs_group_t* group, struct gcs_act* act, int* gcs_proto_ver) { // if (*gcs_proto_ver < group->quorum.gcs_proto_ver) // *gcs_proto_ver = group->quorum.gcs_proto_ver; // only go up, see #482 // else if (group->quorum.gcs_proto_ver >= 0 && // group->quorum.gcs_proto_ver < *gcs_proto_ver) { // gu_warn ("Refusing GCS protocol version downgrade from %d to %d", // *gcs_proto_ver, group->quorum.gcs_proto_ver); // } // actually we allow gcs protocol version downgrade. // because if message version is inconsistent with gcs protocol version // gcs requires resending message with correct gcs protocol version. *gcs_proto_ver = group->quorum.gcs_proto_ver; ssize_t conf_size = sizeof(gcs_act_conf_t) + group_memb_record_size(group); gcs_act_conf_t* conf = static_cast(malloc (conf_size)); if (conf) { long idx; conf->seqno = group->act_id; conf->conf_id = group->conf_id; conf->memb_num = group->num; conf->my_idx = group->my_idx; conf->repl_proto_ver = group->quorum.repl_proto_ver; conf->appl_proto_ver = group->quorum.appl_proto_ver; memcpy (conf->uuid, &group->group_uuid, sizeof (gu_uuid_t)); if (group->num) { assert (conf->my_idx >= 0); conf->my_state = group->nodes[group->my_idx].status; char* ptr = &conf->data[0]; for (idx = 0; idx < group->num; idx++) { strcpy (ptr, group->nodes[idx].id); ptr += strlen(ptr) + 1; strcpy (ptr, group->nodes[idx].name); ptr += strlen(ptr) + 1; strcpy (ptr, group->nodes[idx].inc_addr); ptr += strlen(ptr) + 1; gcs_seqno_t cached = gcs_node_cached(&group->nodes[idx]); memcpy(ptr, &cached, sizeof(cached)); ptr += sizeof(cached); } } else { // self leave message assert (conf->conf_id < 0); assert (conf->my_idx < 0); conf->my_state = GCS_NODE_STATE_NON_PRIM; } act->buf = conf; act->buf_len = conf_size; act->type = GCS_ACT_CONF; return conf_size; } else { return -ENOMEM; } } // for future use in fake state exchange (in unit tests et.al. See #237, #238) static gcs_state_msg_t* group_get_node_state (const gcs_group_t* const group, long const node_idx) { const gcs_node_t* const node = &group->nodes[node_idx]; uint8_t flags = 0; if (0 == node_idx) flags |= GCS_STATE_FREP; if (node->count_last_applied) flags |= GCS_STATE_FCLA; if (node->bootstrap) flags |= GCS_STATE_FBOOTSTRAP; #ifdef GCS_FOR_GARB flags |= GCS_STATE_ARBITRATOR; int64_t const cached = GCS_SEQNO_ILL; #else int64_t const cached = /* group->cache check is needed for unit tests */ group->cache ? gcache_seqno_min(group->cache) : GCS_SEQNO_ILL; #endif /* GCS_FOR_GARB */ return gcs_state_msg_create ( &group->state_uuid, &group->group_uuid, &group->prim_uuid, group->prim_seqno, group->act_id, cached, group->prim_num, group->prim_state, node->status, node->name, node->inc_addr, node->gcs_proto_ver, node->repl_proto_ver, node->appl_proto_ver, flags ); } /*! Returns state message object for this node */ gcs_state_msg_t* gcs_group_get_state (const gcs_group_t* group) { return group_get_node_state (group, group->my_idx); } percona-galera-3-3.8-3390/gcs/src/gcs_group.hpp000066400000000000000000000166371244131713600210630ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * This header defines node specific context we need to maintain */ #ifndef _gcs_group_h_ #define _gcs_group_h_ #include #include #include "gcs_node.hpp" #include "gcs_recv_msg.hpp" #include "gcs_seqno.hpp" #include "gcs_state_msg.hpp" #include typedef enum gcs_group_state { GCS_GROUP_NON_PRIMARY, GCS_GROUP_WAIT_STATE_UUID, GCS_GROUP_WAIT_STATE_MSG, GCS_GROUP_PRIMARY, GCS_GROUP_STATE_MAX } gcs_group_state_t; extern const char* gcs_group_state_str[]; typedef struct gcs_group { gcache_t* cache; gcs_seqno_t act_id; // current(last) action seqno gcs_seqno_t conf_id; // current configuration seqno gu_uuid_t state_uuid; // state exchange id gu_uuid_t group_uuid; // group UUID long num; // number of nodes long my_idx; // my index in the group const char* my_name; const char* my_address; gcs_group_state_t state; // group state: PRIMARY | NON_PRIMARY gcs_seqno_t last_applied; // last_applied action group-wide long last_node; // node that reported last_applied bool frag_reset; // indicate that fragmentation was reset gcs_node_t* nodes; // array of node contexts /* values from the last primary component */ gu_uuid_t prim_uuid; gu_seqno_t prim_seqno; long prim_num; gcs_node_state_t prim_state; /* max supported protocols */ gcs_proto_t const gcs_proto_ver; int const repl_proto_ver; int const appl_proto_ver; gcs_state_quorum_t quorum; int last_applied_proto_ver; gcs_group() : gcs_proto_ver(0), repl_proto_ver(0), appl_proto_ver(0) { } } gcs_group_t; /*! * Initialize group at startup */ extern int gcs_group_init (gcs_group_t* group, gcache_t* cache, const char* node_name, ///< can be null const char* inc_addr, ///< can be null gcs_proto_t gcs_proto_ver, int repl_proto_ver, int appl_proto_ver); /*! * Initialize group action history parameters. See gcs.h */ extern int gcs_group_init_history (gcs_group_t* group, gcs_seqno_t seqno, const gu_uuid_t* uuid); /*! * Free group resources */ extern void gcs_group_free (gcs_group_t* group); /*! Forget the action if it is not to be delivered */ extern void gcs_group_ignore_action (gcs_group_t* group, struct gcs_act_rcvd* rcvd); /*! * Handles component message - installs new membership, * cleans old one. * * @return * group state in case of success or * negative error code. */ extern gcs_group_state_t gcs_group_handle_comp_msg (gcs_group_t* group, const gcs_comp_msg_t* msg); extern gcs_group_state_t gcs_group_handle_uuid_msg (gcs_group_t* group, const gcs_recv_msg_t* msg); extern gcs_group_state_t gcs_group_handle_state_msg (gcs_group_t* group, const gcs_recv_msg_t* msg); extern gcs_seqno_t gcs_group_handle_last_msg (gcs_group_t* group, const gcs_recv_msg_t* msg); /*! @return 0 for success, 1 for (success && i_am_sender) * or negative error code */ extern int gcs_group_handle_join_msg (gcs_group_t* group, const gcs_recv_msg_t* msg); /*! @return 0 for success, 1 for (success && i_am_sender) * or negative error code */ extern int gcs_group_handle_sync_msg (gcs_group_t* group, const gcs_recv_msg_t* msg); /*! @return 0 if request is ignored, request size if it should be passed up */ extern int gcs_group_handle_state_request (gcs_group_t* group, struct gcs_act_rcvd* act); /*! * Handles action message. Is called often - therefore, inlined * * @return negative - error code, 0 - continue, positive - complete action */ static inline ssize_t gcs_group_handle_act_msg (gcs_group_t* const group, const gcs_act_frag_t* const frg, const gcs_recv_msg_t* const msg, struct gcs_act_rcvd* const rcvd, bool not_commonly_supported_version = false) { long const sender_idx = msg->sender_idx; bool const local = (sender_idx == group->my_idx); ssize_t ret; assert (GCS_MSG_ACTION == msg->type); assert (sender_idx < group->num); assert (frg->act_id > 0); assert (frg->act_size > 0); // clear reset flag if set by own first fragment after reset flag was set group->frag_reset = (group->frag_reset && (!local || (0 != frg->frag_no))); ret = gcs_node_handle_act_frag (&group->nodes[sender_idx], frg, &rcvd->act, local); if (ret > 0) { assert (ret == rcvd->act.buf_len); rcvd->act.type = frg->act_type; if (gu_likely(GCS_ACT_TORDERED == rcvd->act.type && GCS_GROUP_PRIMARY == group->state && group->nodes[sender_idx].status >= GCS_NODE_STATE_DONOR && !(group->frag_reset && local) && !not_commonly_supported_version)) { /* Common situation - * increment and assign act_id only for totally ordered actions * and only in PRIM (skip messages while in state exchange) */ rcvd->id = ++group->act_id; } else if (GCS_ACT_TORDERED == rcvd->act.type) { /* Rare situations */ if (local) { /* Let the sender know that it failed */ rcvd->id = -ERESTART; gu_debug("Returning -ERESTART for TORDERED action: group->state" " = %s, sender->status = %s, frag_reset = %s, " "buf = %p", gcs_group_state_str[group->state], gcs_node_state_to_str(group->nodes[sender_idx].status), group->frag_reset ? "true" : "false", rcvd->act.buf); } else { /* Just ignore it */ ret = 0; gcs_group_ignore_action (group, rcvd); } } } return ret; } static inline gcs_group_state_t gcs_group_state (const gcs_group_t* group) { return group->state; } static inline bool gcs_group_is_primary (const gcs_group_t* group) { return (GCS_GROUP_PRIMARY == group->state); } static inline int gcs_group_my_idx (const gcs_group_t* group) { return group->my_idx; } /*! * Creates new configuration action * @param group group handle * @param act GCS action object * @param proto protocol version gcs should use for this configuration */ extern ssize_t gcs_group_act_conf (gcs_group_t* group, struct gcs_act* act, int* proto); /*! Returns state object for state message */ extern gcs_state_msg_t* gcs_group_get_state (const gcs_group_t* group); /*! * find a donor and return its index, if available. pure function. * @return donor index of negative error code. * -EHOSTUNREACH if no available donor. * -EHOSTDOWN if donor is joiner. * -EAGAIN if no node in proper state. */ extern int gcs_group_find_donor(const gcs_group_t* group, int const str_version, int const joiner_idx, const char* const donor_string, int const donor_len, const gu_uuid_t* ist_uuid, gcs_seqno_t ist_seqno); #endif /* _gcs_group_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_msg_type.cpp000066400000000000000000000004501244131713600215330ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include "gcs_msg_type.hpp" const char* gcs_msg_type_string[GCS_MSG_MAX] = { "ERROR", "ACTION", "LAST", "COMPONENT", "STATE_UUID", "STATE_MSG", "JOIN", "SYNC", "FLOW", "CAUSAL" }; percona-galera-3-3.8-3390/gcs/src/gcs_msg_type.hpp000066400000000000000000000025361244131713600215470ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Message types. */ #ifndef _gcs_msg_type_h_ #define _gcs_msg_type_h_ // NOTE! When changing this enumaration, make sure to change // gcs_msg_type_string[] in gcs_msg_type.c typedef enum gcs_msg_type { GCS_MSG_ERROR, // error happened when recv() GCS_MSG_ACTION, // action fragment GCS_MSG_LAST, // report about last applied action GCS_MSG_COMPONENT, // new component GCS_MSG_STATE_UUID,// state exchange UUID message GCS_MSG_STATE_MSG, // state exchange message GCS_MSG_JOIN, // massage saying that the node completed state transfer GCS_MSG_SYNC, // message saying that the node has synced with group GCS_MSG_FLOW, // flow control message GCS_MSG_CAUSAL, // causality token GCS_MSG_MAX } gcs_msg_type_t; extern const char* gcs_msg_type_string[GCS_MSG_MAX]; /* Types of private actions - should not care, * must be defined and used by the application */ /* Types of regular configuration mesages (both PRIM/NON_PRIM) */ typedef enum gcs_reg_type { GCS_REG_JOIN, // caused by member JOIN GCS_REG_LEAVE, // caused by member LEAVE GCS_REG_DISCONNECT, // caused by member DISCONNECT GCS_REG_NETWORK // caused by NETWORK failure? } gcs_reg_type_t; #endif // _gcs_message_h_ percona-galera-3-3.8-3390/gcs/src/gcs_node.cpp000066400000000000000000000155301244131713600206360ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include "gcs_node.hpp" /*! Initialize node context */ void gcs_node_init (gcs_node_t* const node, gcache_t* cache, const char* const id, const char* const name, const char* const inc_addr, int const gcs_proto_ver, int const repl_proto_ver, int const appl_proto_ver, gcs_segment_t const segment) { assert(strlen(id) > 0); assert(strlen(id) < sizeof(node->id)); memset (node, 0, sizeof (gcs_node_t)); strncpy ((char*)node->id, id, sizeof(node->id) - 1); node->bootstrap = false; node->status = GCS_NODE_STATE_NON_PRIM; node->name = strdup (name ? name : NODE_NO_NAME); node->inc_addr = strdup (inc_addr ? inc_addr : NODE_NO_ADDR); gcs_defrag_init (&node->app, cache); // GCS_ACT_TORDERED goes only here gcs_defrag_init (&node->oob, NULL); node->gcs_proto_ver = gcs_proto_ver; node->repl_proto_ver = repl_proto_ver; node->appl_proto_ver = appl_proto_ver; node->segment = segment; } /*! Move data from one node object to another */ void gcs_node_move (gcs_node_t* dst, gcs_node_t* src) { if (dst->name) free ((char*)dst->name); if (dst->inc_addr) free ((char*)dst->inc_addr); if (dst->state_msg) gcs_state_msg_destroy ((gcs_state_msg_t*)dst->state_msg); memcpy (dst, src, sizeof (gcs_node_t)); gcs_defrag_forget (&src->app); gcs_defrag_forget (&src->oob); src->name = NULL; src->inc_addr = NULL; src->state_msg = NULL; } /*! Mark node's buffers as reset (local node only) */ void gcs_node_reset_local (gcs_node_t* node) { gcs_defrag_reset (&node->app); gcs_defrag_reset (&node->oob); } /*! Reset node's receive buffers */ void gcs_node_reset (gcs_node_t* node) { gcs_defrag_free (&node->app); gcs_defrag_free (&node->oob); gcs_node_reset_local (node); } /*! Deallocate resources associated with the node object */ void gcs_node_free (gcs_node_t* node) { gcs_node_reset (node); if (node->name) { free ((char*)node->name); // was strdup'ed node->name = NULL; } if (node->inc_addr) { free ((char*)node->inc_addr); // was strdup'ed node->inc_addr = NULL; } if (node->state_msg) { gcs_state_msg_destroy ((gcs_state_msg_t*)node->state_msg); node->state_msg = NULL; } } /*! Record state message from the node */ void gcs_node_record_state (gcs_node_t* node, gcs_state_msg_t* state_msg) { if (node->state_msg) { gcs_state_msg_destroy ((gcs_state_msg_t*)node->state_msg); } node->state_msg = state_msg; // copy relevant stuff from state msg into node node->status = gcs_state_msg_current_state (state_msg); gcs_state_msg_get_proto_ver (state_msg, &node->gcs_proto_ver, &node->repl_proto_ver, &node->appl_proto_ver); if (node->name) free ((char*)node->name); node->name = strdup (gcs_state_msg_name (state_msg)); if (node->inc_addr) free ((char*)node->inc_addr); node->inc_addr = strdup (gcs_state_msg_inc_addr (state_msg)); } /*! Update node status according to quorum decisions */ void gcs_node_update_status (gcs_node_t* node, const gcs_state_quorum_t* quorum) { if (quorum->primary) { const gu_uuid_t* node_group_uuid = gcs_state_msg_group_uuid ( node->state_msg); const gu_uuid_t* quorum_group_uuid = &quorum->group_uuid; // TODO: what to do when quorum.proto is not supported by this node? if (!gu_uuid_compare (node_group_uuid, quorum_group_uuid)) { // node was a part of this group gcs_seqno_t node_act_id = gcs_state_msg_received (node->state_msg); if (node_act_id == quorum->act_id) { const gcs_node_state_t last_prim_state = gcs_state_msg_prim_state (node->state_msg); if (GCS_NODE_STATE_NON_PRIM == last_prim_state) { // the node just joined, but already is up to date: node->status = GCS_NODE_STATE_JOINED; gu_debug ("#281 Setting %s state to %s", node->name, gcs_node_state_to_str(node->status)); } else { // Keep node state from the previous primary comp. node->status = last_prim_state; gu_debug ("#281,#298 Carry over last prim state for %s: %s", node->name, gcs_node_state_to_str(node->status)); } } else { // gap in sequence numbers, needs a snapshot, demote status if (node->status > GCS_NODE_STATE_PRIM) { gu_info ("'%s' demoted %s->PRIMARY due to gap in history: " "%lld - %lld", node->name, gcs_node_state_to_str(node->status), node_act_id, quorum->act_id); } node->status = GCS_NODE_STATE_PRIM; } } else { // node joins completely different group, clear all status if (node->status > GCS_NODE_STATE_PRIM) { gu_info ("'%s' has a different history, demoted %s->PRIMARY", node->name, gcs_node_state_to_str(node->status)); } node->status = GCS_NODE_STATE_PRIM; } switch (node->status) { case GCS_NODE_STATE_DONOR: case GCS_NODE_STATE_SYNCED: node->count_last_applied = true; break; case GCS_NODE_STATE_JOINED: node->count_last_applied =(gcs_state_msg_flags (node->state_msg) & GCS_STATE_FCLA); break; case GCS_NODE_STATE_JOINER: case GCS_NODE_STATE_PRIM: node->count_last_applied = false; break; case GCS_NODE_STATE_NON_PRIM: case GCS_NODE_STATE_MAX: gu_fatal ("Internal logic error: state %d in " "primary configuration. Aborting.", node->status); abort(); break; } } else { /* Probably don't want to change anything here, quorum was a failure * anyway. This could be due to this being transient component, lacking * joined nodes from the configuraiton. May be next component will be * better. * * UPDATE (28.06.2011): as #477 shows, we need some consistency here: */ node->status = GCS_NODE_STATE_NON_PRIM; } /* Clear bootstrap flag so that it does not get carried to * subsequent configuration changes. */ node->bootstrap = false; } percona-galera-3-3.8-3390/gcs/src/gcs_node.hpp000066400000000000000000000105361244131713600206440ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /*! * Node context */ #ifndef _gcs_node_h_ #define _gcs_node_h_ #include #include "gcs.hpp" #include "gcs_defrag.hpp" #include "gcs_comp_msg.hpp" #include "gcs_state_msg.hpp" #include #define NODE_NO_ID "undefined" #define NODE_NO_NAME "unspecified" #define NODE_NO_ADDR "unspecified" struct gcs_node { gcs_defrag_t app; // defragmenter for application actions gcs_defrag_t oob; // defragmenter for out-of-band service acts. // globally unique id from a component message char id[GCS_COMP_MEMB_ID_MAX_LEN + 1]; // to track snapshot status char joiner[GCS_COMP_MEMB_ID_MAX_LEN + 1]; char donor [GCS_COMP_MEMB_ID_MAX_LEN + 1]; const char* name; // human-given name const char* inc_addr; // incoming address - for load balancer const gcs_state_msg_t* state_msg;// state message gcs_seqno_t last_applied; // last applied action on that node int gcs_proto_ver;// supported protocol versions int repl_proto_ver; int appl_proto_ver; gcs_node_state_t status; // node status gcs_segment_t segment; bool count_last_applied; // should it be counted bool bootstrap; // is part of prim comp bootstrap process }; typedef struct gcs_node gcs_node_t; /*! Initialize node context */ extern void gcs_node_init (gcs_node_t* node, gcache_t* gcache, const char* id, const char* name, ///< can be null const char* inc_addr, ///< can be null int gcs_proto_ver, int repl_proto_ver, int appl_proto_ver, gcs_segment_t segment); /*! Move data from one node object to another */ extern void gcs_node_move (gcs_node_t* dest, gcs_node_t* src); /*! Deallocate resources associated with the node object */ extern void gcs_node_free (gcs_node_t* node); /*! Reset node's receive buffers */ extern void gcs_node_reset (gcs_node_t* node); /*! Mark node's buffers as reset, but don't do it actually (local node only) */ extern void gcs_node_reset_local (gcs_node_t* node); /*! * Handles action message. Is called often - therefore, inlined * * @return */ static inline ssize_t gcs_node_handle_act_frag (gcs_node_t* node, const gcs_act_frag_t* frg, struct gcs_act* act, bool local) { if (gu_likely(GCS_ACT_SERVICE != frg->act_type)) { return gcs_defrag_handle_frag (&node->app, frg, act, local); } else if (GCS_ACT_SERVICE == frg->act_type) { return gcs_defrag_handle_frag (&node->oob, frg, act, local); } else { gu_warn ("Unrecognised action type: %d", frg->act_type); assert(0); return -EPROTO; } } static inline void gcs_node_set_last_applied (gcs_node_t* node, gcs_seqno_t seqno) { if (gu_unlikely(seqno < node->last_applied)) { gu_warn ("Received bogus LAST message: %lld, from node %s, " "expected >= %lld. Ignoring.", seqno, node->id, node->last_applied); } else { node->last_applied = seqno; } } static inline gcs_seqno_t gcs_node_get_last_applied (gcs_node_t* node) { return node->last_applied; } /*! Record state message from the node */ extern void gcs_node_record_state (gcs_node_t* node, gcs_state_msg_t* state); /*! Update node status according to quorum decisions */ extern void gcs_node_update_status (gcs_node_t* node, const gcs_state_quorum_t* quorum); static inline gcs_node_state_t gcs_node_get_status (const gcs_node_t* node) { return node->status; } static inline gcs_seqno_t gcs_node_cached (const gcs_node_t* node) { /* node->state_msg check is needed in NON-PRIM situations, where no * state message exchange happens */ if (node->state_msg) return gcs_state_msg_cached(node->state_msg); else return GCS_SEQNO_ILL; } static inline uint8_t gcs_node_flags (const gcs_node_t* node) { return gcs_state_msg_flags(node->state_msg); } static inline bool gcs_node_is_joined (const gcs_node_state_t st) { return (st >= GCS_NODE_STATE_DONOR); } #endif /* _gcs_node_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_params.cpp000066400000000000000000000152231244131713600211730ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy * * $Id$ */ #include "gcs_params.hpp" #define __STDC_FORMAT_MACROS #include #include const char* const GCS_PARAMS_FC_FACTOR = "gcs.fc_factor"; const char* const GCS_PARAMS_FC_LIMIT = "gcs.fc_limit"; const char* const GCS_PARAMS_FC_MASTER_SLAVE = "gcs.fc_master_slave"; const char* const GCS_PARAMS_FC_DEBUG = "gcs.fc_debug"; const char* const GCS_PARAMS_SYNC_DONOR = "gcs.sync_donor"; const char* const GCS_PARAMS_MAX_PKT_SIZE = "gcs.max_packet_size"; const char* const GCS_PARAMS_RECV_Q_HARD_LIMIT = "gcs.recv_q_hard_limit"; const char* const GCS_PARAMS_RECV_Q_SOFT_LIMIT = "gcs.recv_q_soft_limit"; const char* const GCS_PARAMS_MAX_THROTTLE = "gcs.max_throttle"; static const char* const GCS_PARAMS_FC_FACTOR_DEFAULT = "1.0"; static const char* const GCS_PARAMS_FC_LIMIT_DEFAULT = "16"; static const char* const GCS_PARAMS_FC_MASTER_SLAVE_DEFAULT = "no"; static const char* const GCS_PARAMS_FC_DEBUG_DEFAULT = "0"; static const char* const GCS_PARAMS_SYNC_DONOR_DEFAULT = "no"; static const char* const GCS_PARAMS_MAX_PKT_SIZE_DEFAULT = "64500"; static ssize_t const GCS_PARAMS_RECV_Q_HARD_LIMIT_DEFAULT = SSIZE_MAX; static const char* const GCS_PARAMS_RECV_Q_SOFT_LIMIT_DEFAULT = "0.25"; static const char* const GCS_PARAMS_MAX_THROTTLE_DEFAULT = "0.25"; bool gcs_params_register(gu_config_t* conf) { bool ret = 0; ret |= gu_config_add (conf, GCS_PARAMS_FC_FACTOR, GCS_PARAMS_FC_FACTOR_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_FC_LIMIT, GCS_PARAMS_FC_LIMIT_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_FC_MASTER_SLAVE, GCS_PARAMS_FC_MASTER_SLAVE_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_FC_DEBUG, GCS_PARAMS_FC_DEBUG_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_SYNC_DONOR, GCS_PARAMS_SYNC_DONOR_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_MAX_PKT_SIZE, GCS_PARAMS_MAX_PKT_SIZE_DEFAULT); char tmp[32] = { 0, }; snprintf (tmp, sizeof(tmp) - 1, "%lld", (long long)GCS_PARAMS_RECV_Q_HARD_LIMIT_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_RECV_Q_HARD_LIMIT, tmp); ret |= gu_config_add (conf, GCS_PARAMS_RECV_Q_SOFT_LIMIT, GCS_PARAMS_RECV_Q_SOFT_LIMIT_DEFAULT); ret |= gu_config_add (conf, GCS_PARAMS_MAX_THROTTLE, GCS_PARAMS_MAX_THROTTLE_DEFAULT); return ret; } static long params_init_bool (gu_config_t* conf, const char* const name, bool* const var) { bool val; long rc = gu_config_get_bool(conf, name, &val); if (rc < 0) { /* Cannot parse parameter value */ gu_error ("Bad %s value", name); return rc; } else if (rc > 0) { assert(0); val = false; rc = -EINVAL; } *var = val; return rc; } static long params_init_long (gu_config_t* conf, const char* const name, long min_val, long max_val, long* const var) { int64_t val; long rc = gu_config_get_int64(conf, name, &val); if (rc < 0) { /* Cannot parse parameter value */ gu_error ("Bad %s value", name); return rc; } else { /* Found parameter value */ if (max_val == min_val) { max_val = LONG_MAX; min_val = LONG_MIN; } if (val < min_val || val > max_val) { gu_error ("%s value out of range [%ld, %ld]: %"PRIi64, name, min_val, max_val, val); return -EINVAL; } } *var = val; return 0; } static long params_init_int64 (gu_config_t* conf, const char* const name, int64_t const min_val, int64_t const max_val, int64_t* const var) { int64_t val; long rc = gu_config_get_int64(conf, name, &val); if (rc < 0) { /* Cannot parse parameter value */ gu_error ("Bad %s value", name); return rc; } else { /* Found parameter value */ if ((min_val != max_val) && (val < min_val || val > max_val)) { gu_error ("%s value out of range [%"PRIi64", %"PRIi64"]: %"PRIi64, name, min_val, max_val, val); return -EINVAL; } } *var = val; return 0; } static long params_init_double (gu_config_t* conf, const char* const name, double const min_val, double const max_val, double* const var) { double val; long rc = gu_config_get_double(conf, name, &val); if (rc < 0) { /* Cannot parse parameter value */ gu_error ("Bad %s value", name); return rc; } else { /* Found parameter value */ if ((min_val != max_val) && (val < min_val || val > max_val)) { gu_error ("%s value out of range [%f, %f]: %f", name, min_val, max_val, val); return -EINVAL; } } *var = val; return 0; } long gcs_params_init (struct gcs_params* params, gu_config_t* config) { long ret; if ((ret = params_init_long (config, GCS_PARAMS_FC_LIMIT, 0, LONG_MAX, ¶ms->fc_base_limit))) return ret; if ((ret = params_init_long (config, GCS_PARAMS_FC_DEBUG, 0, LONG_MAX, ¶ms->fc_debug))) return ret; if ((ret = params_init_long (config, GCS_PARAMS_MAX_PKT_SIZE, 0,LONG_MAX, ¶ms->max_packet_size))) return ret; if ((ret = params_init_double (config, GCS_PARAMS_FC_FACTOR, 0.0, 1.0, ¶ms->fc_resume_factor))) return ret; if ((ret = params_init_double (config, GCS_PARAMS_RECV_Q_SOFT_LIMIT, 0.0, 1.0 - 1.e-9, ¶ms->recv_q_soft_limit))) return ret; if ((ret = params_init_double (config, GCS_PARAMS_MAX_THROTTLE, 0.0, 1.0 - 1.e-9, ¶ms->max_throttle))) return ret; int64_t tmp; if ((ret = params_init_int64 (config, GCS_PARAMS_RECV_Q_HARD_LIMIT, 0, 0, &tmp))) return ret; params->recv_q_hard_limit = tmp * 0.9; // allow for some meta overhead if ((ret = params_init_bool (config, GCS_PARAMS_FC_MASTER_SLAVE, ¶ms->fc_master_slave))) return ret; if ((ret = params_init_bool (config, GCS_PARAMS_SYNC_DONOR, ¶ms->sync_donor))) return ret; return 0; } percona-galera-3-3.8-3390/gcs/src/gcs_params.hpp000066400000000000000000000023071244131713600211770ustar00rootroot00000000000000/* * Copyright (C) 2010-2014 Codership Oy * * $Id$ */ #ifndef _gcs_params_h_ #define _gcs_params_h_ #include "galerautils.h" struct gcs_params { double fc_resume_factor; double recv_q_soft_limit; double max_throttle; ssize_t recv_q_hard_limit; long fc_base_limit; long max_packet_size; long fc_debug; bool fc_master_slave; bool sync_donor; }; extern const char* const GCS_PARAMS_FC_FACTOR; extern const char* const GCS_PARAMS_FC_LIMIT; extern const char* const GCS_PARAMS_FC_MASTER_SLAVE; extern const char* const GCS_PARAMS_FC_DEBUG; extern const char* const GCS_PARAMS_SYNC_DONOR; extern const char* const GCS_PARAMS_MAX_PKT_SIZE; extern const char* const GCS_PARAMS_RECV_Q_HARD_LIMIT; extern const char* const GCS_PARAMS_RECV_Q_SOFT_LIMIT; extern const char* const GCS_PARAMS_MAX_THROTTLE; /*! Register configuration parameters */ extern bool gcs_params_register(gu_config_t* config); /*! Initializes parameters from config * * @return 0 in case of success, * -EINVAL if some values were set incorrectly in config */ extern long gcs_params_init (struct gcs_params* params, gu_config_t* config); #endif /* _gcs_params_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_priv.hpp000066400000000000000000000004121244131713600206670ustar00rootroot00000000000000/* * Copyright (C) 2011 Codership Oy * * $Id$ */ /*! * @file gcs_priv.h Global declarations private to GCS */ #ifndef _gcs_priv_h_ #define _gcs_priv_h_ #include "gcs.hpp" #define GCS_DESYNC_REQ "self-desync" #endif /* _gcs_priv_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_recv_msg.hpp000066400000000000000000000011451244131713600215200ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*! * Receiving message context */ #ifndef _gcs_recv_msg_h_ #define _gcs_recv_msg_h_ #include "gcs_msg_type.hpp" typedef struct gcs_recv_msg { void* buf; int buf_len; int size; int sender_idx; gcs_msg_type_t type; gcs_recv_msg() { } gcs_recv_msg(void* b, long bl, long sz, long si, gcs_msg_type_t t) : buf(b), buf_len(bl), size(sz), sender_idx(si), type(t) { } } gcs_recv_msg_t; #endif /* _gcs_recv_msg_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_seqno.hpp000066400000000000000000000006441244131713600210430ustar00rootroot00000000000000/* * Copyright (C) 2008-2012 Codership Oy * * $Id$ */ /* * Operations on seqno. */ #ifndef _gcs_seqno_h_ #define _gcs_seqno_h_ #include "galerautils.h" #include "gcs.hpp" #define gcs_seqno_le(x) ((gcs_seqno_t)gu_le64(x)) #define gcs_seqno_be(x) ((gcs_seqno_t)gu_be64(x)) #define gcs_seqno_htog(x) ((gcs_seqno_t)htog64(x)) #define gcs_seqno_gtoh gcs_seqno_htog #endif /* _gcs_seqno_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_sm.cpp000066400000000000000000000114361244131713600203310ustar00rootroot00000000000000/* * Copyright (C) 2010 Codership Oy * * $Id$ */ /*! * @file GCS Send Monitor. To ensure fair (FIFO) access to gcs_core_send() */ #include "gcs_sm.hpp" #include static void sm_init_stats (gcs_sm_stats_t* stats) { stats->sample_start = gu_time_monotonic(); stats->pause_start = 0; stats->paused_ns = 0; stats->paused_sample = 0; stats->send_q_samples = 0; stats->send_q_len = 0; stats->send_q_len_max = 0; stats->send_q_len_min = 0; } gcs_sm_t* gcs_sm_create (long len, long n) { if ((len < 2 /* 2 is minimum */) || (len & (len - 1))) { gu_error ("Monitor length parameter is not a power of 2: %ld", len); return NULL; } if (n < 1) { gu_error ("Invalid monitor concurrency parameter: %ld", n); return NULL; } size_t sm_size = sizeof(gcs_sm_t) + len * sizeof(((gcs_sm_t*)(0))->wait_q[0]); gcs_sm_t* sm = static_cast(gu_malloc(sm_size)); if (sm) { sm_init_stats (&sm->stats); gu_mutex_init (&sm->lock, NULL); #ifdef GCS_SM_GRAB_RELEASE gu_cond_init (&sm->cond, NULL); sm->cond_wait = 0; #endif /* GCS_SM_GRAB_RELEASE */ sm->wait_q_len = len; sm->wait_q_mask = sm->wait_q_len - 1; sm->wait_q_head = 1; sm->wait_q_tail = 0; sm->users = 0; sm->users_max = 0; sm->users_min = 0; sm->entered = 0; sm->ret = 0; #ifdef GCS_SM_CONCURRENCY sm->cc = n; // concurrency param. #endif /* GCS_SM_CONCURRENCY */ sm->pause = false; sm->wait_time = gu::datetime::Sec; memset (sm->wait_q, 0, sm->wait_q_len * sizeof(sm->wait_q[0])); } return sm; } long gcs_sm_close (gcs_sm_t* sm) { gu_info ("Closing send monitor..."); if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); sm->ret = -EBADFD; if (sm->pause) _gcs_sm_continue_common (sm); gu_cond_t cond; gu_cond_init (&cond, NULL); // in case the queue is full while (sm->users >= (long)sm->wait_q_len) { gu_mutex_unlock (&sm->lock); usleep(1000); gu_mutex_lock (&sm->lock); } while (sm->users > 0) { // wait for cleared queue sm->users++; GCS_SM_INCREMENT(sm->wait_q_tail); _gcs_sm_enqueue_common (sm, &cond, true); sm->users--; GCS_SM_INCREMENT(sm->wait_q_head); } gu_cond_destroy (&cond); gu_mutex_unlock (&sm->lock); gu_info ("Closed send monitor."); return 0; } long gcs_sm_open (gcs_sm_t* sm) { long ret = -1; if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); if (-EBADFD == sm->ret) /* closed */ { sm->ret = 0; } ret = sm->ret; gu_mutex_unlock (&sm->lock); if (ret) { gu_error ("Can't open send monitor: wrong state %d", ret); } return ret; } void gcs_sm_destroy (gcs_sm_t* sm) { gu_mutex_destroy(&sm->lock); gu_free (sm); } void gcs_sm_stats_get (gcs_sm_t* sm, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg, long long* paused_ns, double* paused_avg) { gcs_sm_stats_t tmp; long long now; bool paused; if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); *q_len_max = sm->users_max; *q_len_min = sm->users_min; *q_len = sm->users; tmp = sm->stats; now = gu_time_monotonic(); paused = sm->pause; gu_mutex_unlock (&sm->lock); if (paused) { // taking sample in a middle of a pause tmp.paused_ns += now - tmp.pause_start; } *paused_ns = tmp.paused_ns; if (gu_likely(tmp.paused_ns >= 0)) { *paused_avg = ((double)(tmp.paused_ns - tmp.paused_sample)) / (now - tmp.sample_start); } else { *paused_avg = -1.0; } if (gu_likely(tmp.send_q_len >= 0 && tmp.send_q_samples >= 0)){ if (gu_likely(tmp.send_q_samples > 0)) { *q_len_avg = ((double)tmp.send_q_len) / tmp.send_q_samples; } else { *q_len_avg = 0.0; } } else { *q_len_avg = -1.0; } } void gcs_sm_stats_flush(gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); long long const now = gu_time_monotonic(); sm->stats.sample_start = now; sm->stats.paused_sample = sm->stats.paused_ns; if (sm->pause) // append elapsed pause time { sm->stats.paused_sample += now - sm->stats.pause_start; } sm->stats.send_q_len = 0; sm->stats.send_q_len_max = 0; sm->stats.send_q_len_min = 0; sm->stats.send_q_samples = 0; sm->users_max = sm->users; sm->users_min = sm->users; gu_mutex_unlock (&sm->lock); } percona-galera-3-3.8-3390/gcs/src/gcs_sm.hpp000066400000000000000000000312301244131713600203300ustar00rootroot00000000000000/* * Copyright (C) 2010-2013 Codership Oy * * $Id$ */ /*! * @file GCS Send Monitor. To ensure fair (FIFO) access to gcs_core_send() */ #ifndef _gcs_sm_h_ #define _gcs_sm_h_ #include "gu_datetime.hpp" #include #include #ifdef GCS_SM_CONCURRENCY #define GCS_SM_CC sm->cc #else #define GCS_SM_CC 1 #endif /* GCS_SM_CONCURRENCY */ typedef struct gcs_sm_user { gu_cond_t* cond; bool wait; } gcs_sm_user_t; typedef struct gcs_sm_stats { long long sample_start;// beginning of the sample period long long pause_start; // start of the pause long long paused_ns; // total nanoseconds paused long long paused_sample; // paused_ns at the beginning of the sample long long send_q_samples; long long send_q_len; long long send_q_len_max; long long send_q_len_min; } gcs_sm_stats_t; typedef struct gcs_sm { gcs_sm_stats_t stats; gu_mutex_t lock; #ifdef GCS_SM_GRAB_RELEASE gu_cond_t cond; long cond_wait; #endif /* GCS_SM_GRAB_RELEASE */ unsigned long wait_q_len; unsigned long wait_q_mask; unsigned long wait_q_head; unsigned long wait_q_tail; long users; long users_min; long users_max; long entered; long ret; #ifdef GCS_SM_CONCURRENCY long cc; #endif /* GCS_SM_CONCURRENCY */ bool pause; gu::datetime::Period wait_time; gcs_sm_user_t wait_q[]; } gcs_sm_t; /*! * Creates send monitor * * @param len size of the monitor, should be a power of 2 * @param n concurrency parameter (how many users can enter at the same time) */ extern gcs_sm_t* gcs_sm_create (long len, long n); /*! * Closes monitor for entering and makes all users to exit with error. * (entered users are not affected). Blocks until everybody exits */ extern long gcs_sm_close (gcs_sm_t* sm); /*! * (Re)opens monitor for entering. */ extern long gcs_sm_open (gcs_sm_t* sm); /*! * Deallocates resources associated with the monitor */ extern void gcs_sm_destroy (gcs_sm_t* sm); #define GCS_SM_INCREMENT(cursor) (cursor = ((cursor + 1) & sm->wait_q_mask)) static inline void _gcs_sm_wake_up_next (gcs_sm_t* sm) { long woken = sm->entered; assert (woken >= 0); assert (woken <= GCS_SM_CC); while (woken < GCS_SM_CC && sm->users > 0) { if (gu_likely(sm->wait_q[sm->wait_q_head].wait)) { assert (NULL != sm->wait_q[sm->wait_q_head].cond); // gu_debug ("Waking up: %lu", sm->wait_q_head); gu_cond_signal (sm->wait_q[sm->wait_q_head].cond); woken++; } else { /* skip interrupted */ assert (NULL == sm->wait_q[sm->wait_q_head].cond); gu_debug ("Skipping interrupted: %lu", sm->wait_q_head); sm->users--; if (gu_unlikely(sm->users < sm->users_min)) { sm->users_min = sm->users; } GCS_SM_INCREMENT(sm->wait_q_head); } } assert (woken <= GCS_SM_CC); assert (sm->users >= 0); } /* wake up whoever might be waiting there */ static inline void _gcs_sm_wake_up_waiters (gcs_sm_t* sm) { #ifdef GCS_SM_GRAB_RELEASE if (gu_unlikely(sm->cond_wait)) { assert (sm->cond_wait > 0); sm->cond_wait--; gu_cond_signal (&sm->cond); } else #endif /* GCS_SM_GRAB_RELEASE */ if (!sm->pause) { _gcs_sm_wake_up_next(sm); } else { /* gcs_sm_continue() will do the rest */ } } static inline void _gcs_sm_leave_common (gcs_sm_t* sm) { assert (sm->entered < GCS_SM_CC); assert (sm->users > 0); sm->users--; if (gu_unlikely(sm->users < sm->users_min)) { sm->users_min = sm->users; } assert (false == sm->wait_q[sm->wait_q_head].wait); assert (NULL == sm->wait_q[sm->wait_q_head].cond); GCS_SM_INCREMENT(sm->wait_q_head); _gcs_sm_wake_up_waiters (sm); } static inline bool _gcs_sm_enqueue_common (gcs_sm_t* sm, gu_cond_t* cond, bool block) { unsigned long tail = sm->wait_q_tail; sm->wait_q[tail].cond = cond; sm->wait_q[tail].wait = true; bool ret; if (block == true) { gu_cond_wait (cond, &sm->lock); assert(tail == sm->wait_q_head || false == sm->wait_q[tail].wait); assert(sm->wait_q[tail].cond == cond || false == sm->wait_q[tail].wait); sm->wait_q[tail].cond = NULL; ret = sm->wait_q[tail].wait; sm->wait_q[tail].wait = false; } else { gu::datetime::Date abstime(gu::datetime::Date::calendar()); abstime = abstime + sm->wait_time; struct timespec ts; abstime._timespec(ts); int waitret = gu_cond_timedwait(cond, &sm->lock, &ts); sm->wait_q[tail].cond = NULL; // sm->wait_time is incremented by second each time cond wait // times out, reset back to one second when cond wait // succeeds. if (waitret == 0) { ret = sm->wait_q[tail].wait; sm->wait_time = std::max(sm->wait_time*2/3, gu::datetime::Period(gu::datetime::Sec)); } else if (waitret == ETIMEDOUT) { if (sm->wait_time < 10 * gu::datetime::Sec) { gu_debug("send monitor wait timed out, waited for %s", to_string(sm->wait_time).c_str()); } else { gu_warn("send monitor wait timed out, waited for %s", to_string(sm->wait_time).c_str()); } ret = false; sm->wait_time = sm->wait_time + gu::datetime::Sec; } else { gu_error("send monitor timedwait failed with %d: %s", waitret, strerror(waitret)); ret = false; } sm->wait_q[tail].wait = false; } return ret; } #ifdef GCS_SM_CONCURRENCY #define GCS_SM_HAS_TO_WAIT \ (sm->users > (sm->entered + 1) || sm->entered >= GCS_SM_CC || sm->pause) #else #define GCS_SM_HAS_TO_WAIT (sm->users > 1 || sm->pause) #endif /* GCS_SM_CONCURRENCY */ /*! * Synchronize with entry order to the monitor. Must be always followed by * gcs_sm_enter(sm, cond, true) * * @retval -EAGAIN - out of space * @retval -EBADFD - monitor closed * @retval >= 0 queue handle */ static inline long gcs_sm_schedule (gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); long ret = sm->ret; if (gu_likely((sm->users < (long)sm->wait_q_len) && (0 == ret))) { sm->users++; if (gu_unlikely(sm->users > sm->users_max)) { sm->users_max = sm->users; } GCS_SM_INCREMENT(sm->wait_q_tail); /* even if we don't queue, cursor * needs to be advanced */ sm->stats.send_q_samples++; if (GCS_SM_HAS_TO_WAIT) { ret = sm->wait_q_tail + 1; // waiter handle /* here we want to distinguish between FC pause and real queue */ sm->stats.send_q_len += sm->users - 1; } return ret; // success } else if (0 == ret) { assert (sm->users == (long)sm->wait_q_len); ret = -EAGAIN; } assert(ret < 0); gu_mutex_unlock (&sm->lock); return ret; } /*! * Enter send monitor critical section * * @param sm send monitor object * @param cond condition to signal to wake up thread in case of wait * @param block if true block until entered or send monitor is closed, * if false enter wait times out eventually * * @retval -EAGAIN - out of space * @retval -EBADFD - monitor closed * @retval -EINTR - was interrupted by another thread * @retval 0 - successfully entered */ static inline long gcs_sm_enter (gcs_sm_t* sm, gu_cond_t* cond, bool scheduled, bool block) { long ret = 0; /* if scheduled and no queue */ if (gu_likely (scheduled || (ret = gcs_sm_schedule(sm)) >= 0)) { if (GCS_SM_HAS_TO_WAIT) { if (gu_likely(_gcs_sm_enqueue_common (sm, cond, block))) { ret = sm->ret; } else { ret = -EINTR; } } assert (ret <= 0); if (gu_likely(0 == ret)) { assert(sm->users > 0); assert(sm->entered < GCS_SM_CC); sm->entered++; } else { if (gu_likely(-EINTR == ret)) { /* was interrupted, will be handled by someone else */ } else { /* monitor is closed, wake up others */ assert(sm->users > 0); _gcs_sm_leave_common(sm); } } gu_mutex_unlock (&sm->lock); } return ret; } static inline void gcs_sm_leave (gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); sm->entered--; assert(sm->entered >= 0); _gcs_sm_leave_common(sm); gu_mutex_unlock (&sm->lock); } static inline void gcs_sm_pause (gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); /* don't pause closed monitor */ if (gu_likely(0 == sm->ret) && !sm->pause) { sm->stats.pause_start = gu_time_monotonic(); sm->pause = true; } gu_mutex_unlock (&sm->lock); } static inline void _gcs_sm_continue_common (gcs_sm_t* sm) { sm->pause = false; _gcs_sm_wake_up_next(sm); /* wake up next waiter if any */ } static inline void gcs_sm_continue (gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); if (gu_likely(sm->pause)) { _gcs_sm_continue_common (sm); sm->stats.paused_ns += gu_time_monotonic() - sm->stats.pause_start; } else { gu_debug ("Trying to continue unpaused monitor"); } gu_mutex_unlock (&sm->lock); } /*! * Interrupts waiter identified by handle (returned by gcs_sm_schedule()) * * @retval 0 - success * @retval -ESRCH - waiter is not in the queue. For practical purposes * it is impossible to discern already interrupted waiter and * the waiter that has entered the monitor */ static inline long gcs_sm_interrupt (gcs_sm_t* sm, long handle) { assert (handle > 0); long ret; if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); handle--; if (gu_likely(sm->wait_q[handle].wait)) { assert (sm->wait_q[handle].cond != NULL); sm->wait_q[handle].wait = false; gu_cond_signal (sm->wait_q[handle].cond); sm->wait_q[handle].cond = NULL; ret = 0; if (!sm->pause && handle == (long)sm->wait_q_head) { /* gcs_sm_interrupt() was called right after the waiter was * signaled by gcs_sm_continue() or gcs_sm_leave() but before * the waiter has woken up. Wake up the next waiter */ _gcs_sm_wake_up_next(sm); } } else { ret = -ESRCH; } gu_mutex_unlock (&sm->lock); return ret; } /*! * Each call to this function resets stats and starts new sampling interval * * @param q_len current send queue length * @param q_len_avg set to an average number of preceding users seen by each * new one (not including itself) (-1 if stats overflown) * @param q_len_max maximum send queue length since last call * @param q_len_min minimum send queue length since last call * @param paused_ns total time paused (nanoseconds) * @param paused_avg set to a fraction of time which monitor spent in a paused * state (-1 if stats overflown) */ extern void gcs_sm_stats_get (gcs_sm_t* sm, int* q_len, int* q_len_max, int* q_len_min, double* q_len_avg, long long* paused_ns, double* paused_avg); /*! resets average/max/min stats calculation */ extern void gcs_sm_stats_flush(gcs_sm_t* sm); #ifdef GCS_SM_GRAB_RELEASE /*! Grabs sm object for out-of-order access * @return 0 or negative error code */ static inline long gcs_sm_grab (gcs_sm_t* sm) { long ret; if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); while (!(ret = sm->ret) && sm->entered >= GCS_SM_CC) { sm->cond_wait++; gu_cond_wait (&sm->cond, &sm->lock); } if (ret) { assert (ret < 0); _gcs_sm_wake_up_waiters (sm); } else { assert (sm->entered < GCS_SM_CC); sm->entered++; } gu_mutex_unlock (&sm->lock); return ret; } /*! Releases sm object after gcs_sm_grab() */ static inline void gcs_sm_release (gcs_sm_t* sm) { if (gu_unlikely(gu_mutex_lock (&sm->lock))) abort(); sm->entered--; _gcs_sm_wake_up_waiters (sm); gu_mutex_unlock (&sm->lock); } #endif /* GCS_SM_GRAB_RELEASE */ #endif /* _gcs_sm_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_spread.cpp000066400000000000000000000464231244131713600211740ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /*****************************************/ /* Implementation of Spread GC backend */ /*****************************************/ #include #include #include #include #include #include #include "gcs_spread.h" #include "gcs_comp_msg.h" #define SPREAD_MAX_GROUPS 256 #if (GCS_COMP_MEMB_ID_MAX_LEN < MAX_GROUP_NAME) #error "GCS_COMP_MEMB_ID_MAX_LEN is smaller than Spread's MAX_GROUP_NAME" #error "This can make creation of component message impossible." #endif typedef struct string_array { int32 max_strings; int32 num_strings; char strings[0][MAX_GROUP_NAME]; } string_array_t; static string_array_t* string_array_alloc (const long n) { string_array_t *ret = NULL; ret = gu_malloc (sizeof (string_array_t) + n * MAX_GROUP_NAME); if (ret) { ret->max_strings = n; ret->num_strings = 0; } return ret; } static void string_array_free (string_array_t *a) { gu_free (a); } typedef enum spread_config { SPREAD_REGULAR, SPREAD_TRANSITIONAL } spread_config_t; typedef struct gcs_backend_conn { char *socket; char *channel; char *priv_name; char *priv_group; char *sender; long msg_type; long my_id; /* process ID returned with REG_MEMB message */ long config_id; // long memb_num; string_array_t *memb; string_array_t *groups; gcs_comp_msg_t *comp_msg; spread_config_t config; /* type of configuration: regular or trans */ mailbox mbox; } spread_t; /* this function converts socket address from conventional * "addr:port" notation to Spread's "port@addr" notation */ static long gcs_to_spread_socket (const char const *socket, char **sp_socket) { char *colon = strrchr (socket, ':'); size_t addr_len = colon - socket; size_t port_len = strlen (socket) - addr_len - 1; char *sps = NULL; if (!colon) return -EADDRNOTAVAIL; sps = (char *) strdup (socket); if (!sps) return -ENOMEM; memcpy (sps, colon+1, port_len); memcpy (sps + port_len + 1, socket, addr_len); sps[port_len] = '@'; *sp_socket = sps; return 0; } static const char* spread_default_socket = "localhost:4803"; static long spread_create (spread_t** spread, const char* socket) { long err = 0; spread_t *sp = GU_CALLOC (1, spread_t); *spread = NULL; if (!sp) { err = -ENOMEM; goto out0; } if (NULL == socket || strlen(socket) == 0) socket = spread_default_socket; err = gcs_to_spread_socket (socket, &sp->socket); if (err < 0) { goto out1; } sp->priv_name = GU_CALLOC (MAX_PRIVATE_NAME, char); if (!sp->priv_name) { err = -ENOMEM; goto out3; } sp->priv_group = GU_CALLOC (MAX_GROUP_NAME, char); if (!sp->priv_group) { err = -ENOMEM; goto out4; } sp->sender = GU_CALLOC (MAX_GROUP_NAME, char); if (!sp->sender) { err = -ENOMEM; goto out5; } sp->groups = string_array_alloc (SPREAD_MAX_GROUPS); if (!sp->groups) { err = -ENOMEM; goto out6; } sp->memb = string_array_alloc (SPREAD_MAX_GROUPS); if (!sp->memb) { err = -ENOMEM; goto out7; } sp->config = SPREAD_TRANSITIONAL; sp->config_id = -1; sp->comp_msg = NULL; gu_debug ("sp->priv_group: %p", sp->priv_group); *spread = sp; return err; out7: string_array_free (sp->groups); out6: gu_free (sp->sender); out5: gu_free (sp->priv_group); out4: gu_free (sp->priv_name); out3: free (sp->socket); out1: gu_free (sp); out0: return err; } /* Compiles a string of MAX_PRIVATE_NAME characters out of a supplied string and a number, returns -1 if digits overflow */ long spread_priv_name (char *name, const char *string, long n) { /* must make sure that it does not overflow MAX_PRIVATE_NAME */ long max_digit = 2; long max_string = MAX_PRIVATE_NAME - max_digit; long len = snprintf (name, max_string + 1, "%s", string); if (len > max_string) len = max_string; // truncated gu_debug ("len = %d, max_string = %d, MAX_PRIVATE_NAME = %d\n", len, (int)max_string, MAX_PRIVATE_NAME); len = snprintf (name + len, max_digit + 1, "_%d", (int)n); if (len > max_digit) return -1; // overflow return 0; } static GCS_BACKEND_CLOSE_FN(spread_close) { long err = 0; spread_t *spread = backend->conn; if (!spread) return -EBADFD; err = SP_leave (spread->mbox, spread->channel); if (err) { switch (err) { case ILLEGAL_GROUP: return -EADDRNOTAVAIL; case ILLEGAL_SESSION: return -ENOTCONN; case CONNECTION_CLOSED: return -ECONNRESET; default: return -EOPNOTSUPP; } } else { return 0; } } static GCS_BACKEND_DESTROY_FN(spread_destroy) { long err = 0; spread_t *spread = backend->conn; if (!spread) return -EBADFD; err = SP_disconnect (spread->mbox); if (spread->memb) string_array_free (spread->memb); if (spread->groups) string_array_free (spread->groups); if (spread->sender) gu_free (spread->sender); if (spread->priv_name) gu_free (spread->priv_name); if (spread->priv_group) gu_free (spread->priv_group); if (spread->channel) free (spread->channel); // obtained by strdup() if (spread->socket) free (spread->socket); if (spread->comp_msg) gcs_comp_msg_delete(spread->comp_msg); gu_free (spread); backend->conn = NULL; if (err) { switch (err) { case ILLEGAL_GROUP: return -EADDRNOTAVAIL; case ILLEGAL_SESSION: return -ENOTCONN; case CONNECTION_CLOSED: return -ECONNRESET; default: return -EOPNOTSUPP; } } else { return 0; } } static GCS_BACKEND_SEND_FN(spread_send) { long ret = 0; spread_t *spread = backend->conn; if (SPREAD_TRANSITIONAL == spread->config) return -EAGAIN; /* can it be that not all of the message is sent? */ ret = SP_multicast (spread->mbox, // mailbox SAFE_MESS, // service type spread->channel, // destination group (short)msg_type, // message from application len, // message length (const char*)buf // message buffer ); if (ret != len) { if (ret > 0) return -ECONNRESET; /* Failed to send the whole message */ switch (ret) { case ILLEGAL_SESSION: return -ENOTCONN; case CONNECTION_CLOSED: return -ECONNRESET; default: return -EOPNOTSUPP; } } #ifdef GCS_DEBUG_SPREAD // gu_debug ("spread_send: message sent: %p, len: %d\n", buf, ret); #endif return ret; } /* Substitutes old member array for new (taken from groups), * creates new groups buffer. */ static inline long spread_update_memb (spread_t* spread) { string_array_t* new_groups = string_array_alloc (SPREAD_MAX_GROUPS); if (!new_groups) return -ENOMEM; string_array_free (spread->memb); spread->memb = spread->groups; spread->groups = new_groups; return 0; } /* Temporarily this is done by simple iteration through the whole list. * for a cluster of 2-3 nodes this is probably most optimal. * But it clearly needs to be improved. */ static inline long spread_sender_id (const spread_t* const spread, const char* const sender_name) { long id; for (id = 0; id < spread->memb->num_strings; id++) { if (!strncmp(sender_name, spread->memb->strings[id], MAX_GROUP_NAME)) return id; } return GCS_SENDER_NONE; } static gcs_comp_msg_t* spread_comp_create (long my_id, long config_id, long memb_num, char names[][MAX_GROUP_NAME]) { gcs_comp_msg_t* comp = gcs_comp_msg_new (memb_num > 0, my_id, memb_num); long ret = -ENOMEM; if (comp) { long i; for (i = 0; i < memb_num; i++) { ret = gcs_comp_msg_add (comp, names[i]); if (ret != i) { gcs_comp_msg_delete (comp); goto fatal; } } gu_debug ("Created a component message of length %d.", gcs_comp_msg_size(comp)); return comp; } fatal: gu_fatal ("Failed to allocate component message: %s", strerror(-ret)); return NULL; } /* This function actually finalizes component message delivery: * it makes sure that the caller will receive the message and only then * changes handle state (spread->config)*/ static long spread_comp_deliver (spread_t* spread, void* buf, long len, gcs_msg_type_t* msg_type) { long ret; assert (spread->comp_msg); ret = gcs_comp_msg_size (spread->comp_msg); if (ret <= len) { memcpy (buf, spread->comp_msg, ret); spread->config = SPREAD_REGULAR; gcs_comp_msg_delete (spread->comp_msg); spread->comp_msg = NULL; *msg_type = GCS_MSG_COMPONENT; gu_debug ("Component message delivered (length %ld)", ret); } else { // provided buffer is too small for a message: // simply return required size } return ret; } static GCS_BACKEND_RECV_FN(spread_recv) { long ret = 0; spread_t *spread = backend->conn; service serv_type; int16 mess_type; int32 endian_mismatch; /* in case of premature exit */ *sender_idx = GCS_SENDER_NONE; *msg_type = GCS_MSG_ERROR; if (spread->comp_msg) { /* undelivered regular component message */ return spread_comp_deliver (spread, buf, len, msg_type); } if (!len) { // Spread does not seem to tolerate 0-sized buffer return 4096; } while (1) /* Loop while we don't receive the right message */ { ret = SP_receive (spread->mbox, // mailbox/connection &serv_type, // service type: // REGULAR_MESS/MEMBERSHIP_MESS spread->sender, // private group name of a sender spread->groups->max_strings, &spread->groups->num_strings, spread->groups->strings, &mess_type, // app. defined message type &endian_mismatch, len, // maximum message length (char*)buf // message buffer ); // gcs_log ("gcs_spread_recv: SP_receive returned\n"); // gcs_log ("endian_mismatch = %d\n", endian_mismatch); // /* seems there is a bug in either libsp or spread daemon */ // if (spread->groups->num_strings < 0 && ret > 0) // ret = GROUPS_TOO_SHORT; /* First, handle errors */ if (ret < 0) { switch (ret) { case BUFFER_TOO_SHORT: { if (Is_membership_mess (serv_type)) { // Ignore this error as membership messages don't fill // the buffer. Spread seems to have a bug - it returns // BUFFER_TOO_SHORT if you pass zero-length buffer for it. gu_debug ("BUFFER_TOO_SHORT in membership message."); ret = 0; break; } /* return required buffer size to caller */ gu_debug ("Error in SP_receive: BUFFER_TOO_SHORT"); gu_debug ("Supplied buffer len: %d, required: %d", len, (int) -endian_mismatch); gu_debug ("Message type: %d, sender: %d", mess_type, spread_sender_id (spread, spread->sender)); return -endian_mismatch; } case GROUPS_TOO_SHORT: { /* reallocate groups */ size_t num_groups = -spread->groups->num_strings; gu_warn ("Error in SP_receive: GROUPS_TOO_SHORT. " "Expect failure."); string_array_free (spread->groups); spread->groups = string_array_alloc (num_groups); if (!spread->groups) return -ENOMEM; /* try again */ continue; } case ILLEGAL_SESSION: gu_debug ("Error in SP_receive: ILLEGAL_SESSION"); return -ECONNABORTED; case CONNECTION_CLOSED: gu_debug ("Error in SP_receive: CONNECTION_CLOSED"); return -ECONNABORTED; case ILLEGAL_MESSAGE: gu_debug ("Error in SP_receive: ILLEGAL_MESSAGE"); continue; // wait for a legal one? default: gu_fatal ("unknown error = %d", ret); return -ENOTRECOVERABLE; } } /* At this point message was successfully received * and stored in buffer. */ if (Is_regular_mess (serv_type)) { // gu_debug ("received REGULAR message of type %d\n", // mess_type); assert (endian_mismatch >= 0); /* BUFFER_TOO_SMALL * must be handled before */ if (endian_mismatch) { gu_debug ("Spread returned ENDIAN_MISMATCH. Ignored."); } *msg_type = mess_type; *sender_idx = spread_sender_id (spread, spread->sender); assert (*sender_idx >= 0); assert (*sender_idx < spread->memb->num_strings); break; } else if (Is_membership_mess (serv_type)) { if (strncmp (spread->channel, spread->sender, MAX_GROUP_NAME)) continue; // wrong group/channel if (Is_transition_mess (serv_type)) { spread->config = SPREAD_TRANSITIONAL; gu_info ("Received TRANSITIONAL message"); continue; } else if (Is_reg_memb_mess (serv_type)) { //assert (spread->groups->num_strings > 0); spread->my_id = mess_type; gu_info ("Received REGULAR MEMBERSHIP " "in group \'%s\' with %d(%d) members " "where I'm member %d\n", spread->sender, spread->groups->num_strings, spread->groups->max_strings, spread->my_id); spread->config_id++; gu_debug ("Configuration number: %d", spread->config_id); spread->comp_msg = spread_comp_create (spread->my_id, spread->config_id, spread->groups->num_strings, spread->groups->strings); if (!spread->comp_msg) return -ENOTRECOVERABLE; /* Update membership info */ if ((ret = spread_update_memb(spread))) return ret; if (Is_caused_join_mess (serv_type)) { gu_info ("due to JOIN"); } else if (Is_caused_leave_mess (serv_type)) { gu_info ("due to LEAVE"); } else if (Is_caused_disconnect_mess (serv_type)) { gu_info ("due to DISCONNECT"); } else if (Is_caused_network_mess (serv_type)) { gu_info ("due to NETWORK"); } else { gu_warn ("unknown REG_MEMB message"); } ret = spread_comp_deliver (spread, buf, len, msg_type); } else if (Is_caused_leave_mess (serv_type)) { gu_info ("received SELF LEAVE message"); // *msg_type = GCS_MSG_COMPONENT; // memset (buf, 0, len); // trivial component spread->comp_msg = gcs_comp_msg_leave (); ret = spread_comp_deliver (spread, buf, len, msg_type); } else { gu_warn ("received unknown MEMBERSHIP message"); continue; // must do something ??? } } else if (Is_reject_mess (serv_type)) { gu_info ("received REJECTED message form %s", spread->sender); continue; } else /* Unknown message type */ { gu_warn ("received message of unknown type"); continue; } /* If we reached this point we have successfully received a message */ break; } /* message is already in buf and its length in ret */ return ret; } static GCS_BACKEND_NAME_FN(spread_name) { static char str[128]; int maj, min, patch; SP_version (&maj, &min, &patch); snprintf (str, 128, "Spread %d.%d.%d", maj, min, patch); return str; } /* Spread packet structure seem to be: * 42 bytes - Ethernet + IP + UDP header, 32 bytes Spread packet header + * 80 byte Spread message header present only in the first packet */ static GCS_BACKEND_MSG_SIZE_FN(spread_msg_size) { long ps = pkt_size; long frames = 0; const long eth_frame_size = 1514; const long spread_header_size = 154; // total headers in Spread packet const long spread_max_pkt_size = 31794; // 21 Ethernet frames if (pkt_size <= spread_header_size) { ps = spread_header_size + 1; gu_warn ("Requested packet size %d is too small, " "minimum possible is %d", pkt_size, ps); return pkt_size - ps; } if (pkt_size > spread_max_pkt_size) { ps = spread_max_pkt_size; gu_warn ("Requested packet size %d is too big, " "using maximum possible: %d", pkt_size, ps); } frames = ps / eth_frame_size; frames += ((frames * eth_frame_size) < ps); // one incomplete frame return (ps - frames * (42 + 32) - 80); } static GCS_BACKEND_OPEN_FN(spread_open) { long err = 0; spread_t* spread = backend->conn; if (!spread) return -EBADFD; if (!channel) { gu_error ("No channel supplied."); return -EINVAL; } spread->channel = strdup (channel); if (!spread->channel) return -ENOMEM; err = SP_join (spread->mbox, spread->channel); if (err) { switch (err) /* translate error codes */ { case ILLEGAL_GROUP: err = -EADDRNOTAVAIL; break; case ILLEGAL_SESSION: err = -EADDRNOTAVAIL; break; case CONNECTION_CLOSED: err = -ENETRESET; break; default: err = -ENOTCONN; break; } gu_error ("%s", strerror (-err)); return err; } gu_info ("Joined channel: %s", spread->channel); return err; } #if defined(__linux__) extern char *program_invocation_short_name; #endif GCS_BACKEND_CREATE_FN(gcs_spread_create) { long err = 0; long n = 0; spread_t* spread = NULL; backend->conn = NULL; if (!socket) { gu_error ("No socket supplied."); err = -EINVAL; goto out0; } if ((err = spread_create (&spread, socket))) goto out0; do { /* Try to generate unique name */ if (spread_priv_name (spread->priv_name, #if defined(__sun__) getexecname (), #elif defined(__APPLE__) || defined(__FreeBSD__) getprogname (), #elif defined(__linux__) program_invocation_short_name, #else "unknown", #endif n++)) { /* Failed to generate a name in the form * program_name_number. Let spread do it for us */ gu_free (spread->priv_name); spread->priv_name = NULL; } err = SP_connect (spread->socket, spread->priv_name, 0, 1, &spread->mbox, spread->priv_group); } while (REJECT_NOT_UNIQUE == err); if (err < 0) { gu_debug ("Spread connect error"); switch (err) /* translate error codes */ { case ILLEGAL_SPREAD: err = -ESOCKTNOSUPPORT; break; case COULD_NOT_CONNECT: err = -ENETUNREACH; break; case CONNECTION_CLOSED: err = -ENETRESET; break; case REJECT_ILLEGAL_NAME: err = -EADDRNOTAVAIL; gu_error ("Spread returned REJECT_ILLEGAL_NAME"); break; case REJECT_NO_NAME: err = -EDESTADDRREQ; gu_error ("Spread returned REJECT_NO_NAME." "Spread protocol error"); break; case REJECT_VERSION: default: gu_error ("Generic Spread error code: %d", err); err = -EPROTONOSUPPORT; break; } goto out1; } else { assert (err == ACCEPT_SESSION); err = 0; } gu_debug ("Connected to Spread: priv_name = %s, priv_group = %s", spread->priv_name, spread->priv_group); backend->conn = spread; backend->open = spread_open; backend->close = spread_close; backend->send = spread_send; backend->recv = spread_recv; backend->name = spread_name; backend->msg_size = spread_msg_size; backend->destroy = spread_destroy; return err; out1: spread_destroy (backend); out0: gu_error ("Creating Spread backend failed: %s (%d)", strerror (-err), err); return err; } percona-galera-3-3.8-3390/gcs/src/gcs_spread.hpp000066400000000000000000000004171244131713600211720ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ /* * Definition of Spread GC backend */ #ifndef _gcs_spread_h_ #define _gcs_spread_h_ #include "gcs_backend.h" extern GCS_BACKEND_CREATE_FN (gcs_spread_create); #endif /* _gcs_spread_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_state_msg.cpp000066400000000000000000000674241244131713600217100ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /* * Interface to state messages - implementation * */ #define __STDC_LIMIT_MACROS #include #include #include #define GCS_STATE_MSG_VER 3 #define GCS_STATE_MSG_ACCESS #include "gcs_state_msg.hpp" #include "gcs_node.hpp" gcs_state_msg_t* gcs_state_msg_create (const gu_uuid_t* state_uuid, const gu_uuid_t* group_uuid, const gu_uuid_t* prim_uuid, gcs_seqno_t prim_seqno, gcs_seqno_t received, gcs_seqno_t cached, int prim_joined, gcs_node_state_t prim_state, gcs_node_state_t current_state, const char* name, const char* inc_addr, int gcs_proto_ver, int repl_proto_ver, int appl_proto_ver, uint8_t flags) { #define CHECK_PROTO_RANGE(LEVEL) \ if (LEVEL < (int)0 || LEVEL > (int)UINT8_MAX) { \ gu_error ("#LEVEL value %d is out of range [0, %d]", LEVEL,UINT8_MAX); \ return NULL; \ } CHECK_PROTO_RANGE(gcs_proto_ver); CHECK_PROTO_RANGE(repl_proto_ver); CHECK_PROTO_RANGE(appl_proto_ver); size_t name_len = strlen(name) + 1; size_t addr_len = strlen(inc_addr) + 1; gcs_state_msg_t* ret = static_cast( gu_calloc (1, sizeof (gcs_state_msg_t) + name_len + addr_len)); if (ret) { ret->state_uuid = *state_uuid; ret->group_uuid = *group_uuid; ret->prim_uuid = *prim_uuid; ret->prim_joined = prim_joined; ret->prim_seqno = prim_seqno; ret->received = received; ret->cached = cached; ret->prim_state = prim_state; ret->current_state = current_state; ret->version = GCS_STATE_MSG_VER; ret->gcs_proto_ver = gcs_proto_ver; ret->repl_proto_ver= repl_proto_ver; ret->appl_proto_ver= appl_proto_ver; ret->name = (char*)(ret + 1); ret->inc_addr = ret->name + name_len; ret->flags = flags; // tmp is a workaround for some combination of GCC flags which don't // allow passing ret->name and ret->inc_addr directly even with casting // char* tmp = (char*)ret->name; strcpy ((char*)ret->name, name); // tmp = (char*)ret->inc_addr; strcpy ((char*)ret->inc_addr, inc_addr); } return ret; } void gcs_state_msg_destroy (gcs_state_msg_t* state) { gu_free (state); } /* Returns length needed to serialize gcs_state_msg_t for sending */ size_t gcs_state_msg_len (gcs_state_msg_t* state) { return ( sizeof (int8_t) + // version (reserved) sizeof (int8_t) + // flags sizeof (int8_t) + // gcs_proto_ver sizeof (int8_t) + // repl_proto_ver sizeof (int8_t) + // prim_state sizeof (int8_t) + // curr_state sizeof (int16_t) + // prim_joined sizeof (gu_uuid_t) + // state_uuid sizeof (gu_uuid_t) + // group_uuid sizeof (gu_uuid_t) + // conf_uuid sizeof (int64_t) + // received sizeof (int64_t) + // prim_seqno strlen (state->name) + 1 + strlen (state->inc_addr) + 1 + // V1-2 stuff sizeof (uint8_t) + // appl_proto_ver (in preparation for V1) // V3 stuff sizeof (int64_t) // cached ); } #define STATE_MSG_FIELDS_V0(buf) \ int8_t* version = (int8_t*)buf; \ int8_t* flags = version + 1; \ int8_t* gcs_proto_ver = flags + 1; \ int8_t* repl_proto_ver = gcs_proto_ver + 1; \ int8_t* prim_state = repl_proto_ver + 1; \ int8_t* curr_state = prim_state + 1; \ int16_t* prim_joined = (int16_t*)(curr_state + 1); \ gu_uuid_t* state_uuid = (gu_uuid_t*)(prim_joined + 1); \ gu_uuid_t* group_uuid = state_uuid + 1; \ gu_uuid_t* prim_uuid = group_uuid + 1; \ int64_t* received = (int64_t*)(prim_uuid + 1); \ int64_t* prim_seqno = received + 1; \ char* name = (char*)(prim_seqno + 1); #define CONST_STATE_MSG_FIELDS_V0(buf) \ const int8_t* version = (int8_t*)buf; \ const int8_t* flags = version + 1; \ const int8_t* gcs_proto_ver = flags + 1; \ const int8_t* repl_proto_ver = gcs_proto_ver + 1; \ const int8_t* prim_state = repl_proto_ver + 1; \ const int8_t* curr_state = prim_state + 1; \ const int16_t* prim_joined = (int16_t*)(curr_state + 1); \ const gu_uuid_t* state_uuid = (gu_uuid_t*)(prim_joined + 1); \ const gu_uuid_t* group_uuid = state_uuid + 1; \ const gu_uuid_t* prim_uuid = group_uuid + 1; \ const int64_t* received = (int64_t*)(prim_uuid + 1); \ const int64_t* prim_seqno = received + 1; \ const char* name = (char*)(prim_seqno + 1); /* Serialize gcs_state_msg_t into buf */ ssize_t gcs_state_msg_write (void* buf, const gcs_state_msg_t* state) { STATE_MSG_FIELDS_V0(buf); char* inc_addr = name + strlen (state->name) + 1; uint8_t* appl_proto_ver = (uint8_t*)(inc_addr + strlen(state->inc_addr) + 1); int64_t* cached = (int64_t*)(appl_proto_ver + 1); *version = GCS_STATE_MSG_VER; *flags = state->flags; *gcs_proto_ver = state->gcs_proto_ver; *repl_proto_ver = state->repl_proto_ver; *prim_state = state->prim_state; *curr_state = state->current_state; *prim_joined = htog16(((int16_t)state->prim_joined)); *state_uuid = state->state_uuid; *group_uuid = state->group_uuid; *prim_uuid = state->prim_uuid; *received = htog64(state->received); *prim_seqno = htog64(state->prim_seqno); strcpy (name, state->name); strcpy (inc_addr, state->inc_addr); *appl_proto_ver = state->appl_proto_ver; // in preparation for V1 *cached = htog64(state->cached); return ((uint8_t*)(cached + 1) - (uint8_t*)buf); } /* De-serialize gcs_state_msg_t from buf */ gcs_state_msg_t* gcs_state_msg_read (const void* const buf, ssize_t const buf_len) { assert (buf_len > 0); /* beginning of the message is always version 0 */ CONST_STATE_MSG_FIELDS_V0(buf); const char* inc_addr = name + strlen (name) + 1; int appl_proto_ver = 0; uint8_t* appl_ptr = (uint8_t*)(inc_addr + strlen(inc_addr) + 1); if (*version >= 1) { assert(buf_len >= (uint8_t*)(appl_ptr + 1) - (uint8_t*)buf); appl_proto_ver = *appl_ptr; } int64_t cached = GCS_SEQNO_ILL; int64_t* cached_ptr = (int64_t*)(appl_ptr + 1); if (*version >= 3) { assert(buf_len >= (uint8_t*)(cached_ptr + 1) - (uint8_t*)buf); cached = gtoh64(*cached_ptr); } gcs_state_msg_t* ret = gcs_state_msg_create ( state_uuid, group_uuid, prim_uuid, gtoh64(*prim_seqno), gtoh64(*received), cached, gtoh16(*prim_joined), (gcs_node_state_t)*prim_state, (gcs_node_state_t)*curr_state, name, inc_addr, *gcs_proto_ver, *repl_proto_ver, appl_proto_ver, *flags ); if (ret) ret->version = *version; // dirty hack return ret; } /* Print state message contents to buffer */ int gcs_state_msg_snprintf (char* str, size_t size, const gcs_state_msg_t* state) { str[size - 1] = '\0'; // preventive termination return snprintf (str, size - 1, "\n\tVersion : %d" "\n\tFlags : %#02hhx" "\n\tProtocols : %d / %d / %d" "\n\tState : %s" "\n\tPrim state : %s" "\n\tPrim UUID : "GU_UUID_FORMAT "\n\tPrim seqno : %lld" "\n\tFirst seqno : %lld" "\n\tLast seqno : %lld" "\n\tPrim JOINED : %d" "\n\tState UUID : "GU_UUID_FORMAT "\n\tGroup UUID : "GU_UUID_FORMAT "\n\tName : '%s'" "\n\tIncoming addr: '%s'\n", state->version, state->flags, state->gcs_proto_ver, state->repl_proto_ver, state->appl_proto_ver, gcs_node_state_to_str(state->current_state), gcs_node_state_to_str(state->prim_state), GU_UUID_ARGS(&state->prim_uuid), (long long)state->prim_seqno, (long long)state->cached, (long long)state->received, state->prim_joined, GU_UUID_ARGS(&state->state_uuid), GU_UUID_ARGS(&state->group_uuid), state->name, state->inc_addr ); } /* Get state uuid */ const gu_uuid_t* gcs_state_msg_uuid (const gcs_state_msg_t* state) { return &state->state_uuid; } /* Get group uuid */ const gu_uuid_t* gcs_state_msg_group_uuid (const gcs_state_msg_t* state) { return &state->group_uuid; } /* Get action seqno */ gcs_seqno_t gcs_state_msg_received (const gcs_state_msg_t* state) { return state->received; } /* Get first cached action seqno */ gcs_seqno_t gcs_state_msg_cached (const gcs_state_msg_t* state) { return state->cached; } /* Get current node state */ gcs_node_state_t gcs_state_msg_current_state (const gcs_state_msg_t* state) { return state->current_state; } /* Get node state */ gcs_node_state_t gcs_state_msg_prim_state (const gcs_state_msg_t* state) { return state->prim_state; } /* Get node name */ const char* gcs_state_msg_name (const gcs_state_msg_t* state) { return state->name; } /* Get node incoming address */ const char* gcs_state_msg_inc_addr (const gcs_state_msg_t* state) { return state->inc_addr; } /* Get supported protocols */ void gcs_state_msg_get_proto_ver (const gcs_state_msg_t* state, int* gcs_proto_ver, int* repl_proto_ver, int* appl_proto_ver) { *gcs_proto_ver = state->gcs_proto_ver; *repl_proto_ver = state->repl_proto_ver; *appl_proto_ver = state->appl_proto_ver; } /* Get state message flags */ uint8_t gcs_state_msg_flags (const gcs_state_msg_t* state) { return state->flags; } /* Returns the node which is most representative of a group */ static const gcs_state_msg_t* state_nodes_compare (const gcs_state_msg_t* left, const gcs_state_msg_t* right) { assert (0 == gu_uuid_compare(&left->group_uuid, &right->group_uuid)); /* Allow GCS_SEQNO_ILL seqnos if bootstrapping from non-prim */ assert ((gcs_state_msg_flags(left) & GCS_STATE_FBOOTSTRAP) || left->prim_seqno != GCS_SEQNO_ILL); assert ((gcs_state_msg_flags(right) & GCS_STATE_FBOOTSTRAP) || right->prim_seqno != GCS_SEQNO_ILL); if (left->received < right->received) { assert (left->prim_seqno <= right->prim_seqno); return right; } else if (left->received > right->received) { assert (left->prim_seqno >= right->prim_seqno); return left; } else { // act_id's are equal, choose the one with higher prim_seqno. if (left->prim_seqno < right->prim_seqno) { return right; } else { return left; } } } /* Helper - just prints out all significant (JOINED) nodes */ static void state_report_uuids (char* buf, size_t buf_len, const gcs_state_msg_t* states[], long states_num, gcs_node_state_t min_state) { long j; for (j = 0; j < states_num; j++) { if (states[j]->current_state >= min_state) { int written = gcs_state_msg_snprintf (buf, buf_len, states[j]); buf += written; buf_len -= written; } } } #define GCS_STATE_MAX_LEN 722 #define GCS_STATE_BAD_REP ((gcs_state_msg_t*)-1) /*! checks for inherited primary configuration, returns representative * @retval (void*)-1 in case of fatal error */ static const gcs_state_msg_t* state_quorum_inherit (const gcs_state_msg_t* states[], long states_num, gcs_state_quorum_t* quorum) { /* They all must have the same group_uuid or otherwise quorum is impossible. * Of those we need to find at least one that has complete state - * status >= GCS_STATE_JOINED. If we find none - configuration is * non-primary. * Of those with the status >= GCS_STATE_JOINED we choose the most * representative: with the highest act_seqno and prim_seqno. */ long i, j; const gcs_state_msg_t* rep = NULL; // find at least one JOINED/DONOR (donor was once joined) for (i = 0; i < states_num; i++) { if (gcs_node_is_joined(states[i]->current_state)) { rep = states[i]; break; } } if (!rep) { size_t buf_len = states_num * GCS_STATE_MAX_LEN; char* buf = static_cast(gu_malloc (buf_len)); if (buf) { state_report_uuids (buf, buf_len, states, states_num, GCS_NODE_STATE_NON_PRIM); #ifdef GCS_CORE_TESTING gu_warn ("Quorum: No node with complete state:\n%s", buf); #else /* Print buf into stderr in order to message truncation * of application logger. */ gu_warn ("Quorum: No node with complete state:\n"); fprintf(stderr, "%s\n", buf); #endif /* GCS_CORE_TESTING */ gu_free (buf); } return NULL; } // Check that all JOINED/DONOR have the same group UUID // and find most updated for (j = i + 1; j < states_num; j++) { if (gcs_node_is_joined(states[j]->current_state)) { if (gu_uuid_compare (&rep->group_uuid, &states[j]->group_uuid)) { // for now just freak out and print all conflicting nodes size_t buf_len = states_num * GCS_STATE_MAX_LEN; char* buf = static_cast(gu_malloc (buf_len)); if (buf) { state_report_uuids (buf, buf_len, states, states_num, GCS_NODE_STATE_DONOR); gu_fatal("Quorum impossible: conflicting group UUIDs:\n%s"); gu_free (buf); } else { gu_fatal("Quorum impossible: conflicting group UUIDs"); } return GCS_STATE_BAD_REP; } rep = state_nodes_compare (rep, states[j]); } } quorum->act_id = rep->received; quorum->conf_id = rep->prim_seqno; quorum->group_uuid = rep->group_uuid; quorum->primary = true; return rep; } struct candidate /* remerge candidate */ { gu_uuid_t prim_uuid; // V0 compatibility (0.8.1) gu_uuid_t state_uuid; gcs_seqno_t state_seqno; const gcs_state_msg_t* rep; int prim_joined; int found; gcs_seqno_t prim_seqno; }; static bool state_match_candidate (const gcs_state_msg_t* const s, struct candidate* const c, int const state_exchange_version) { switch (state_exchange_version) { case 0: // V0 compatibility (0.8.1) return (0 == gu_uuid_compare(&s->prim_uuid, &c->prim_uuid)); default: return ((0 == gu_uuid_compare(&s->group_uuid, &c->state_uuid)) && (s->received == c->state_seqno) && // what if they are different components. // but have same group uuid and received(0) // see gh24. (s->prim_seqno == c->prim_seqno)); } } /* try to find representative remerge candidate */ static const struct candidate* state_rep_candidate (const struct candidate* const c, int const c_num) { assert (c_num > 0); const struct candidate* rep = &c[0]; gu_uuid_t const state_uuid = rep->state_uuid; gcs_seqno_t state_seqno = rep->state_seqno; gcs_seqno_t prim_seqno = rep->prim_seqno; int i; for (i = 1; i < c_num; i++) { if (!gu_uuid_compare(&c[i].state_uuid, &GU_UUID_NIL)) { /* Ignore nodes with undefined state uuid, they have been * added to group before remerge and have clean state. */ continue; } else if (gu_uuid_compare(&state_uuid, &GU_UUID_NIL) && gu_uuid_compare(&state_uuid, &c[i].state_uuid)) { /* There are candidates from different groups */ return NULL; } assert (prim_seqno != c[i].prim_seqno || state_seqno != c[i].state_seqno); if (prim_seqno < c[i].prim_seqno) { rep = &c[i]; prim_seqno = rep->prim_seqno; } else if (prim_seqno == c[i].prim_seqno && state_seqno < c[i].state_seqno) { rep = &c[i]; state_seqno = rep->state_seqno; } } return rep; } /*! checks for full prim remerge after non-prim */ static const gcs_state_msg_t* state_quorum_remerge (const gcs_state_msg_t* const states[], long const states_num, bool const bootstrap, gcs_state_quorum_t* const quorum) { struct candidate* candidates = GU_CALLOC(states_num, struct candidate); if (!candidates) { gu_error ("Quorum: could not allocate %zd bytes for re-merge check.", states_num * sizeof(struct candidate)); return NULL; } int i, j; int candidates_found = 0; /* 1. Sort and count all nodes who have ever been JOINED by primary * component UUID */ for (i = 0; i < states_num; i++) { bool cond; if (bootstrap) { cond = gcs_state_msg_flags(states[i]) & GCS_STATE_FBOOTSTRAP; if (cond) gu_debug("found node %s with bootstrap flag", gcs_state_msg_name(states[i])); } else { cond = gcs_node_is_joined(states[i]->prim_state); } if (cond) { if (!bootstrap && GCS_NODE_STATE_JOINER == states[i]->current_state) { /* Joiner always has an undefined state * (and it should be its prim_state!) */ gu_warn ("Inconsistent state message from %d (%s): current " "state is %s, but the primary state was %s.", i, states[i]->name, gcs_node_state_to_str(states[i]->current_state), gcs_node_state_to_str(states[i]->prim_state)); continue; } assert(bootstrap || gu_uuid_compare(&states[i]->prim_uuid, &GU_UUID_NIL)); for (j = 0; j < candidates_found; j++) { if (state_match_candidate (states[i], &candidates[j], quorum->version)) { assert(states[i]->prim_joined == candidates[j].prim_joined); // comment out following two lines for pc recovery // when nodes recoveried from state files, if their states // match, so candidates[j].found > 0. // However their prim_joined == 0. // assert(candidates[j].found < candidates[j].prim_joined); // assert(candidates[j].found > 0); candidates[j].found++; candidates[j].rep = state_nodes_compare (candidates[j].rep, states[i]); break; } } if (j == candidates_found) { // we don't have this candidate in the list yet candidates[j].prim_uuid = states[i]->prim_uuid; candidates[j].state_uuid = states[i]->group_uuid; candidates[j].state_seqno = states[i]->received; candidates[j].prim_joined = states[i]->prim_joined; candidates[j].rep = states[i]; candidates[j].found = 1; candidates[j].prim_seqno = states[i]->prim_seqno; candidates_found++; assert(candidates_found <= states_num); } } } const gcs_state_msg_t* rep = NULL; if (candidates_found) { assert (candidates_found > 0); const struct candidate* const rc = state_rep_candidate (candidates, candidates_found); if (!rc) { gu_error ("Found more than one %s primary component candidate.", bootstrap ? "bootstrap" : "re-merged"); rep = NULL; } else { if (bootstrap) { gu_info ("Bootstrapped primary "GU_UUID_FORMAT" found: %d.", GU_UUID_ARGS(&rc->prim_uuid), rc->found); } else { gu_info ("%s re-merge of primary "GU_UUID_FORMAT" found: " "%d of %d.", rc->found == rc->prim_joined ? "Full" : "Partial", GU_UUID_ARGS(&rc->prim_uuid), rc->found, rc->prim_joined); } rep = rc->rep; assert (NULL != rep); assert (bootstrap || gcs_node_is_joined(rep->prim_state)); quorum->act_id = rep->received; quorum->conf_id = rep->prim_seqno; quorum->group_uuid = rep->group_uuid; quorum->primary = true; } } else { assert (0 == candidates_found); gu_warn ("No %s primary component found.", bootstrap ? "bootstrapped" : "re-merged"); } gu_free (candidates); return rep; } #if 0 // REMOVE WHEN NO LONGER NEEDED FOR REFERENCE /*! Checks for prim comp bootstrap */ static const gcs_state_msg_t* state_quorum_bootstrap (const gcs_state_msg_t* const states[], long const states_num, gcs_state_quorum_t* const quorum) { struct candidate* candidates = GU_CALLOC(states_num, struct candidate); if (!candidates) { gu_error ("Quorum: could not allocate %zd bytes for re-merge check.", states_num * sizeof(struct candidate)); return NULL; } int i, j; int candidates_found = 0; /* 1. Sort and count all nodes which have bootstrap flag set */ for (i = 0; i < states_num; i++) { if (gcs_state_msg_flags(states[i]) & GCS_STATE_FBOOTSTRAP) { gu_debug("found node %s with bootstrap flag", gcs_state_msg_name(states[i])); for (j = 0; j < candidates_found; j++) { if (state_match_candidate (states[i], &candidates[j], quorum->version)) { assert(states[i]->prim_joined == candidates[j].prim_joined); assert(candidates[j].found > 0); candidates[j].found++; candidates[j].rep = state_nodes_compare (candidates[j].rep, states[i]); break; } } if (j == candidates_found) { // we don't have this candidate in the list yet candidates[j].prim_uuid = states[i]->prim_uuid; candidates[j].state_uuid = states[i]->group_uuid; candidates[j].state_seqno = states[i]->received; candidates[j].prim_joined = states[i]->prim_joined; candidates[j].rep = states[i]; candidates[j].found = 1; candidates_found++; assert(candidates_found <= states_num); } } } const gcs_state_msg_t* rep = NULL; if (candidates_found) { assert (candidates_found > 0); const struct candidate* const rc = state_rep_candidate (candidates, candidates_found); if (!rc) { gu_error ("Found more than one bootstrap primary component " "candidate."); rep = NULL; } else { gu_info ("Bootstrapped primary "GU_UUID_FORMAT" found: %d.", GU_UUID_ARGS(&rc->prim_uuid), rc->found); rep = rc->rep; assert (NULL != rep); quorum->act_id = rep->received; quorum->conf_id = rep->prim_seqno; quorum->group_uuid = rep->group_uuid; quorum->primary = true; } } else { assert (0 == candidates_found); gu_warn ("No bootstrapped primary component found."); } gu_free (candidates); return rep; } #endif // 0 /* Get quorum decision from state messages */ long gcs_state_msg_get_quorum (const gcs_state_msg_t* states[], long states_num, gcs_state_quorum_t* quorum) { assert (states_num > 0); assert (NULL != states); long i; const gcs_state_msg_t* rep = NULL; *quorum = GCS_QUORUM_NON_PRIMARY; // pessimistic assumption /* find lowest commonly supported state exchange version */ quorum->version = states[0]->version; for (i = 1; i < states_num; i++) { if (quorum->version > states[i]->version) { quorum->version = states[i]->version; } } rep = state_quorum_inherit (states, states_num, quorum); if (!quorum->primary && rep != GCS_STATE_BAD_REP) { rep = state_quorum_remerge (states, states_num, false, quorum); } if (!quorum->primary && rep != GCS_STATE_BAD_REP) { rep = state_quorum_remerge (states, states_num, true, quorum); } if (!quorum->primary) { gu_error ("Failed to establish quorum."); return 0; } assert (rep != NULL); // select the highest commonly supported protocol: min(proto_max) #define INIT_PROTO_VER(LEVEL) quorum->LEVEL = rep->LEVEL INIT_PROTO_VER(gcs_proto_ver); INIT_PROTO_VER(repl_proto_ver); INIT_PROTO_VER(appl_proto_ver); for (i = 0; i < states_num; i++) { #define CHECK_MIN_PROTO_VER(LEVEL) \ if (states[i]->LEVEL < quorum->LEVEL) { \ quorum->LEVEL = states[i]->LEVEL; \ } // if (!gu_uuid_compare(&states[i]->group_uuid, &quorum->group_uuid)) { CHECK_MIN_PROTO_VER(gcs_proto_ver); CHECK_MIN_PROTO_VER(repl_proto_ver); CHECK_MIN_PROTO_VER(appl_proto_ver); // } } if (quorum->version < 2) {;} // for future generations if (quorum->version < 1) { // appl_proto_ver is not supported by all members assert (quorum->repl_proto_ver <= 1); if (1 == quorum->repl_proto_ver) quorum->appl_proto_ver = 1; else quorum->appl_proto_ver = 0; } return 0; } percona-galera-3-3.8-3390/gcs/src/gcs_state_msg.hpp000066400000000000000000000130461244131713600217040ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /* * Interface to state messages * */ #ifndef _gcs_state_msg_h_ #define _gcs_state_msg_h_ #include "gcs.hpp" #include "gcs_seqno.hpp" #include "gcs_act_proto.hpp" #include #include /* State flags */ #define GCS_STATE_FREP 0x01 // group representative #define GCS_STATE_FCLA 0x02 // count last applied (for JOINED node) #define GCS_STATE_FBOOTSTRAP 0x04 // part of prim bootstrap process #define GCS_STATE_ARBITRATOR 0x08 // arbitrator or otherwise incomplete node #ifdef GCS_STATE_MSG_ACCESS typedef struct gcs_state_msg { gu_uuid_t state_uuid; // UUID of the current state exchange gu_uuid_t group_uuid; // UUID of the group gu_uuid_t prim_uuid; // last PC state UUID gcs_seqno_t prim_seqno; // last PC state seqno gcs_seqno_t received; // last action seqno (received up to) gcs_seqno_t cached; // earliest action cached const char* name; // human assigned node name const char* inc_addr; // incoming address string int version; // version of state message int gcs_proto_ver; int repl_proto_ver; int appl_proto_ver; int prim_joined; // number of joined nodes in its last PC gcs_node_state_t prim_state; // state of the node in its last PC gcs_node_state_t current_state; // current state of the node uint8_t flags; } gcs_state_msg_t; #else typedef struct gcs_state_msg gcs_state_msg_t; #endif /*! Quorum decisions */ typedef struct gcs_state_quorum { gu_uuid_t group_uuid; //! group UUID gcs_seqno_t act_id; //! next global seqno gcs_seqno_t conf_id; //! configuration id bool primary; //! primary configuration or not int version; //! state excahnge version (max understood by all) int gcs_proto_ver; int repl_proto_ver; int appl_proto_ver; } gcs_state_quorum_t; #define GCS_QUORUM_NON_PRIMARY (gcs_state_quorum_t){ \ GU_UUID_NIL, \ GCS_SEQNO_ILL, \ GCS_SEQNO_ILL, \ false, \ -1, -1, -1, -1 \ } extern gcs_state_msg_t* gcs_state_msg_create (const gu_uuid_t* state_uuid, const gu_uuid_t* group_uuid, const gu_uuid_t* prim_uuid, gcs_seqno_t prim_seqno, gcs_seqno_t received, gcs_seqno_t cached, int prim_joined, gcs_node_state_t prim_state, gcs_node_state_t current_state, const char* name, const char* inc_addr, int gcs_proto_ver, int repl_proto_ver, int appl_proto_ver, uint8_t flags); extern void gcs_state_msg_destroy (gcs_state_msg_t* state); /* Returns length needed to serialize gcs_state_msg_t for sending */ extern size_t gcs_state_msg_len (gcs_state_msg_t* state); /* Serialize gcs_state_msg_t into message */ extern ssize_t gcs_state_msg_write (void* msg, const gcs_state_msg_t* state); /* De-serialize gcs_state_msg_t from message */ extern gcs_state_msg_t* gcs_state_msg_read (const void* msg, ssize_t msg_len); /* Get state uuid */ extern const gu_uuid_t* gcs_state_msg_uuid (const gcs_state_msg_t* state); /* Get group uuid */ extern const gu_uuid_t* gcs_state_msg_group_uuid (const gcs_state_msg_t* state); /* Get last PC uuid */ //extern const gu_uuid_t* //gcs_state_prim_uuid (const gcs_state_msg_t* state); /* Get last received action seqno */ extern gcs_seqno_t gcs_state_msg_received (const gcs_state_msg_t* state); /* Get lowest cached action seqno */ extern gcs_seqno_t gcs_state_msg_cached (const gcs_state_msg_t* state); /* Get current node state */ extern gcs_node_state_t gcs_state_msg_current_state (const gcs_state_msg_t* state); /* Get last prim node state */ extern gcs_node_state_t gcs_state_msg_prim_state (const gcs_state_msg_t* state); /* Get node name */ extern const char* gcs_state_msg_name (const gcs_state_msg_t* state); /* Get node incoming address */ extern const char* gcs_state_msg_inc_addr (const gcs_state_msg_t* state); /* Get supported protocols */ extern void gcs_state_msg_get_proto_ver (const gcs_state_msg_t* state, int* gcs_proto_ver, int* repl_proto_ver, int* appl_proto_ver); /* Get state message flags */ extern uint8_t gcs_state_msg_flags (const gcs_state_msg_t* state); /*! Get quorum decision from state messages * * @param[in] states array of state message pointers * @param[in] states_num length of array * @param[out] quorum quorum calculations result * @retval 0 if there were no errors during processing. Quorum results are in * quorum parameter */ extern long gcs_state_msg_get_quorum (const gcs_state_msg_t* states[], long states_num, gcs_state_quorum_t* quorum); /* Print state message contents to buffer */ extern int gcs_state_msg_snprintf (char* str, size_t size, const gcs_state_msg_t* msg); #endif /* _gcs_state_msg_h_ */ percona-galera-3-3.8-3390/gcs/src/gcs_test.cpp000066400000000000000000000556311244131713600206760ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ /***********************************************************/ /* This program imitates 3rd party application and */ /* tests GCS library in a dummy standalone configuration */ /***********************************************************/ #include #include #include #include #include #include #include #include #include #include #include "gcs.hpp" #include "gcs_test.hpp" #define USE_WAIT #define gcs_malloc(a) ((a*) malloc (sizeof (a))) static pthread_mutex_t gcs_test_lock = PTHREAD_MUTEX_INITIALIZER; static gcache_t* gcache = NULL; typedef struct gcs_test_log { FILE *file; pthread_mutex_t lock; } gcs_test_log_t; #define SEND_LOG "/dev/shm/gcs_test_send.log" #define RECV_LOG "/dev/shm/gcs_test_recv.log" static gcs_test_log_t *send_log, *recv_log; static bool throughput = true; // bench for throughput static bool total = true; // also enable TO locking typedef enum { GCS_TEST_SEND, GCS_TEST_RECV, GCS_TEST_REPL } gcs_test_repl_t; typedef struct gcs_test_thread { pthread_t thread; long id; struct gcs_action act; long n_tries; void* msg; char* log_msg; } gcs_test_thread_t; #define MAX_MSG_LEN (1 << 16) static long gcs_test_thread_create (gcs_test_thread_t *t, long id, long n_tries) { t->id = id; t->msg = calloc (MAX_MSG_LEN, sizeof(char)); t->act.buf = t->msg; t->act.size = MAX_MSG_LEN; t->act.seqno_g = GCS_SEQNO_ILL; t->act.seqno_l = GCS_SEQNO_ILL; t->act.type = GCS_ACT_TORDERED; t->n_tries = n_tries; if (t->msg) { t->log_msg = (char*)calloc (MAX_MSG_LEN, sizeof(char)); if (t->log_msg) return 0; } return -ENOMEM; } static long gcs_test_thread_destroy (gcs_test_thread_t *t) { if (t->msg) free (t->msg); if (t->log_msg) free (t->log_msg); return 0; } typedef struct gcs_test_thread_pool { long n_threads; long n_tries; long n_started; gcs_test_repl_t type; gcs_test_thread_t *threads; } gcs_test_thread_pool_t; static long gcs_test_thread_pool_create (gcs_test_thread_pool_t *pool, const gcs_test_repl_t type, const long n_threads, const long n_tries) { long err = 0; long i; // pool = gcs_malloc (gcs_test_thread_pool_t); // if (!pool) { err = errno; goto out; } pool->n_threads = n_threads; pool->type = type; pool->n_tries = n_tries; pool->n_started = 0; pool->threads = (gcs_test_thread_t *) calloc (pool->n_threads, sizeof (gcs_test_thread_t)); if (!pool->threads) { err = errno; fprintf (stderr, "Failed to allocate %ld thread objects: %ld (%s)\n", n_threads, err, strerror(err)); goto out1; } for (i = 0; i < pool->n_threads; i++) { if ((err = gcs_test_thread_create (pool->threads + i, i, n_tries))) { err = errno; fprintf (stderr, "Failed to create thread object %ld: %ld (%s)\n", i, err, strerror(err)); goto out2; } } // printf ("Created %ld thread objects\n", i); return 0; out2: while (i) { i--; gcs_test_thread_destroy (pool->threads + i); } free (pool->threads); out1: free (pool); //out: return err; } static void gcs_test_thread_pool_destroy (gcs_test_thread_pool_t* pool) { long i; if (pool->threads) { for (i = 0; i < pool->n_threads; i++) { gcs_test_thread_destroy (pool->threads + i); } free (pool->threads); } } static pthread_mutex_t make_msg_lock = PTHREAD_MUTEX_INITIALIZER; //static long total_tries; static inline long test_make_msg (char* msg, const long mlen) { static gcs_seqno_t count = 1; long len = 0; if (!throughput) { pthread_mutex_lock (&make_msg_lock); count++; pthread_mutex_unlock (&make_msg_lock); len = snprintf (msg, mlen, "%10d %9llu %s", rand(), (unsigned long long)count++, gcs_test_data); } else { len = rand() % mlen + 1; // just random length, we don't care about // contents } if (len >= mlen) return mlen; else return len; } static long test_log_open (gcs_test_log_t **log, const char *name) { char real_name[1024]; gcs_test_log_t *l = gcs_malloc (gcs_test_log_t); if (!l) return errno; snprintf (real_name, 1024, "%s.%lld", name, (long long)getpid()); // cppcheck-suppress memleak if (!(l->file = fopen (real_name, "w"))) return errno; pthread_mutex_init (&l->lock, NULL); *log = l; return 0; } static long test_log_close (gcs_test_log_t **log) { long err = 0; gcs_test_log_t *l = *log; if (l) { pthread_mutex_lock (&l->lock); err = fclose (l->file); pthread_mutex_unlock (&l->lock); pthread_mutex_destroy (&l->lock); } return err; } static inline long gcs_test_log_msg (gcs_test_log_t *log, const char *msg) { long err = 0; err = fprintf (log->file, "%s\n", msg); return err; } gcs_conn_t *gcs = NULL; gu_to_t *to = NULL; long msg_sent = 0; long msg_recvd = 0; long msg_repld = 0; long msg_len = 0; size_t size_sent = 0; size_t size_repld = 0; size_t size_recvd = 0; static inline long test_recv_log_create(gcs_test_thread_t* thread) { return snprintf (thread->log_msg, MAX_MSG_LEN - 1, "Thread %3ld(REPL): act_id = %lld, local_act_id = %lld, " "len = %lld: %s", thread->id, (long long)thread->act.seqno_g, (long long)thread->act.seqno_l, (long long)thread->act.size, (const char*)thread->act.buf); } static inline long test_send_log_create(gcs_test_thread_t* thread) { return snprintf (thread->log_msg, MAX_MSG_LEN - 1, "Thread %3ld (REPL): len = %lld, %s", thread->id, (long long) thread->act.size, (const char*)thread->act.buf); } static inline long test_log_msg (gcs_test_log_t* log, const char* msg) { long ret; pthread_mutex_lock (&log->lock); ret = fprintf (recv_log->file, "%s\n", msg); pthread_mutex_lock (&log->lock); return ret; } static inline long test_log_in_to (gu_to_t* to, gcs_seqno_t seqno, const char* msg) { long ret = 0; while ((ret = gu_to_grab (to, seqno)) == -EAGAIN) usleep(10000); if (!ret) {// success if (msg != NULL) gcs_test_log_msg (recv_log, msg); ret = gu_to_release (to, seqno); } return ret; } static gcs_seqno_t group_seqno = 0; static inline long test_send_last_applied (gcs_conn_t* gcs, gcs_seqno_t my_seqno) { long ret = 0; #define SEND_LAST_MASK ((1 << 14) - 1) // every 16K seqno if (!(my_seqno & SEND_LAST_MASK)) { ret = gcs_set_last_applied (gcs, my_seqno); if (ret) { fprintf (stderr,"gcs_set_last_applied(%lld) returned %ld\n", (long long)my_seqno, ret); } // if (!throughput) { fprintf (stdout, "Last applied: my = %lld, group = %lld\n", (long long)my_seqno, (long long)group_seqno); // } } return ret; } static inline long test_before_send (gcs_test_thread_t* thread) { #ifdef USE_WAIT static const struct timespec wait = { 0, 10000000 }; #endif long ret = 0; /* create a message */ thread->act.size = test_make_msg ((char*)thread->msg, msg_len); thread->act.buf = thread->msg; if (thread->act.size <= 0) return -1; if (!throughput) { /* log message before replication */ ret = test_send_log_create (thread); ret = test_log_msg (send_log, thread->log_msg); } #ifdef USE_WAIT while ((ret = gcs_wait(gcs)) && ret > 0) nanosleep (&wait, NULL); #endif return ret; } static inline long test_after_recv (gcs_test_thread_t* thread) { long ret; if (!throughput) { /* log message after replication */ ret = test_recv_log_create (thread); ret = test_log_in_to (to, thread->act.seqno_l, thread->log_msg); } else if (total) { ret = test_log_in_to (to, thread->act.seqno_l, NULL); } else { gu_to_self_cancel (to, thread->act.seqno_l); } ret = test_send_last_applied (gcs, thread->act.seqno_g); // fprintf (stdout, "SEQNO applied %lld", thread->local_act_id); if (thread->act.type == GCS_ACT_TORDERED) gcache_free (gcache, thread->act.buf); return ret; } void *gcs_test_repl (void *arg) { gcs_test_thread_t *thread = (gcs_test_thread_t*)arg; // long i = thread->n_tries; long ret = 0; pthread_mutex_lock (&gcs_test_lock); pthread_mutex_unlock (&gcs_test_lock); while (thread->n_tries) { ret = test_before_send (thread); if (ret < 0) break; /* replicate message */ ret = gcs_repl (gcs, &thread->act, false); if (ret < 0) { assert (thread->act.seqno_g == GCS_SEQNO_ILL); assert (thread->act.seqno_l == GCS_SEQNO_ILL); break; } msg_repld++; size_repld += thread->act.size; // usleep ((rand() & 1) << 1); test_after_recv (thread); // puts (thread->log_msg); fflush (stdout); } // fprintf (stderr, "REPL thread %ld exiting: %s\n", // thread->id, strerror(-ret)); return NULL; } void *gcs_test_send (void *arg) { long ret = 0; gcs_test_thread_t *thread = (gcs_test_thread_t*)arg; // long i = thread->n_tries; pthread_mutex_lock (&gcs_test_lock); pthread_mutex_unlock (&gcs_test_lock); while (thread->n_tries) { ret = test_before_send (thread); if (ret < 0) break; /* send message to group */ ret = gcs_send (gcs, thread->act.buf, thread->act.size, GCS_ACT_TORDERED, false); if (ret < 0) break; //sleep (1); msg_sent++; size_sent += thread->act.size; } // fprintf (stderr, "SEND thread %ld exiting: %s\n", // thread->id, strerror(-ret)); return NULL; } static void gcs_test_handle_configuration (gcs_conn_t* gcs, gcs_test_thread_t* thread) { long ret; static gcs_seqno_t conf_id = 0; gcs_act_conf_t* conf = (gcs_act_conf_t*)thread->msg; gu_uuid_t ist_uuid = {{0, }}; gcs_seqno_t ist_seqno = GCS_SEQNO_ILL; fprintf (stdout, "Got GCS_ACT_CONF: Conf: %lld, " "seqno: %lld, members: %ld, my idx: %ld, local seqno: %lld\n", (long long)conf->conf_id, (long long)conf->seqno, conf->memb_num, conf->my_idx, (long long)thread->act.seqno_l); fflush (stdout); // NOTE: what really needs to be checked is seqno and group_uuid, but here // we don't keep track of them (and don't do real transfers), // so for simplicity, just check conf_id. while (-EAGAIN == (ret = gu_to_grab (to, thread->act.seqno_l))); if (0 == ret) { if (conf->my_state == GCS_NODE_STATE_PRIM) { gcs_seqno_t seqno, s; fprintf (stdout,"Gap in configurations: ours: %lld, group: %lld.\n", (long long)conf_id, (long long)conf->conf_id); fflush (stdout); fprintf (stdout, "Requesting state transfer up to %lld: %s\n", (long long)conf->seqno, // this is global seqno strerror (-gcs_request_state_transfer (gcs, 0, &conf->seqno, sizeof(conf->seqno), "", &ist_uuid, ist_seqno, &seqno))); // pretend that state transfer is complete, cancel every action up // to seqno for (s = thread->act.seqno_l + 1; s <= seqno; s++) { gu_to_self_cancel (to, s); // this is local seqno } fprintf (stdout, "Sending JOIN: %s\n", strerror(-gcs_join(gcs, 0))); fflush (stdout); } gcs_resume_recv (gcs); gu_to_release (to, thread->act.seqno_l); } else { fprintf (stderr, "Failed to grab TO: %ld (%s)", ret, strerror(ret)); } conf_id = conf->conf_id; } void *gcs_test_recv (void *arg) { long ret = 0; gcs_test_thread_t *thread = (gcs_test_thread_t*)arg; while (thread->n_tries) { /* receive message from group */ while ((ret = gcs_recv (gcs, &thread->act)) == -ECANCELED) { usleep (10000); } if (ret <= 0) { fprintf (stderr, "gcs_recv() %s: %ld (%s). Thread exits.\n", ret < 0 ? "failed" : "connection closed", ret, strerror(-ret)); assert (thread->act.buf == NULL); assert (thread->act.size == 0); assert (thread->act.seqno_g == GCS_SEQNO_ILL); assert (thread->act.seqno_l == GCS_SEQNO_ILL); assert (thread->act.type == GCS_ACT_ERROR); break; } assert (thread->act.type < GCS_ACT_ERROR); msg_recvd++; size_recvd += thread->act.size; switch (thread->act.type) { case GCS_ACT_TORDERED: test_after_recv (thread); //puts (thread->log_msg); fflush (stdout); break; case GCS_ACT_COMMIT_CUT: group_seqno = *(gcs_seqno_t*)thread->act.buf; gu_to_self_cancel (to, thread->act.seqno_l); break; case GCS_ACT_CONF: gcs_test_handle_configuration (gcs, thread); break; case GCS_ACT_STATE_REQ: fprintf (stdout, "Got STATE_REQ\n"); gu_to_grab (to, thread->act.seqno_l); fprintf (stdout, "Sending JOIN: %s\n", strerror(-gcs_join(gcs, 0))); fflush (stdout); gu_to_release (to, thread->act.seqno_l); break; case GCS_ACT_JOIN: fprintf (stdout, "Joined\n"); gu_to_self_cancel (to, thread->act.seqno_l); break; case GCS_ACT_SYNC: fprintf (stdout, "Synced\n"); gu_to_self_cancel (to, thread->act.seqno_l); break; default: fprintf (stderr, "Unexpected action type: %d\n", thread->act.type); } } // fprintf (stderr, "RECV thread %ld exiting: %s\n", // thread->id, strerror(-ret)); return NULL; } static long gcs_test_thread_pool_start (gcs_test_thread_pool_t *pool) { long i; long err = 0; void * (* thread_routine) (void *); switch (pool->type) { case GCS_TEST_REPL: thread_routine = gcs_test_repl; break; case GCS_TEST_SEND: thread_routine = gcs_test_send; break; case GCS_TEST_RECV: thread_routine = gcs_test_recv; break; default: fprintf (stderr, "Bad repl type %u\n", pool->type); return -1; } for (i = 0; i < pool->n_threads; i++) { if ((err = pthread_create (&pool->threads[i].thread, NULL, thread_routine, &pool->threads[i]))) break; } pool->n_started = i; printf ("Started %ld threads of %s type (pool: %p)\n", pool->n_started, GCS_TEST_REPL == pool->type ? "REPL" : (GCS_TEST_SEND == pool->type ? "SEND" :"RECV"), (void*)pool); return 0; } static long gcs_test_thread_pool_join (const gcs_test_thread_pool_t *pool) { long i; for (i = 0; i < pool->n_started; i++) { pthread_join (pool->threads[i].thread, NULL); } return 0; } static long gcs_test_thread_pool_stop (const gcs_test_thread_pool_t *pool) { long i; for (i = 0; i < pool->n_started; i++) { pool->threads[i].n_tries = 0; } return 0; } long gcs_test_thread_pool_cancel (const gcs_test_thread_pool_t *pool) { long i; printf ("Canceling pool: %p\n", (void*)pool); fflush(stdout); printf ("pool type: %u, pool threads: %ld\n", pool->type, pool->n_started); fflush(stdout); for (i = 0; i < pool->n_started; i++) { printf ("Cancelling %ld\n", i); fflush(stdout); pthread_cancel (pool->threads[i].thread); pool->threads[i].n_tries = 0; } return 0; } typedef struct gcs_test_conf { long n_tries; long n_repl; long n_send; long n_recv; const char* backend; } gcs_test_conf_t; static const char* DEFAULT_BACKEND = "dummy://"; static long gcs_test_conf (gcs_test_conf_t *conf, long argc, char *argv[]) { char *endptr; /* defaults */ conf->n_tries = 10; conf->n_repl = 10; conf->n_send = 0; conf->n_recv = 1; conf->backend = DEFAULT_BACKEND; switch (argc) { case 6: conf->n_recv = strtol (argv[5], &endptr, 10); if ('\0' != *endptr) goto error; case 5: conf->n_send = strtol (argv[4], &endptr, 10); if ('\0' != *endptr) goto error; case 4: conf->n_repl = strtol (argv[3], &endptr, 10); if ('\0' != *endptr) goto error; case 3: conf->n_tries = strtol (argv[2], &endptr, 10); if ('\0' != *endptr) goto error; case 2: conf->backend = argv[1]; break; default: break; } printf ("Config: n_tries = %ld, n_repl = %ld, n_send = %ld, n_recv = %ld, " "backend = %s\n", conf->n_tries, conf->n_repl, conf->n_send, conf->n_recv, conf->backend); return 0; error: printf ("Usage: %s [backend] [tries:%ld] [repl threads:%ld] " "[send threads: %ld] [recv threads: %ld]\n", argv[0], conf->n_tries, conf->n_repl, conf->n_send, conf->n_recv); exit (EXIT_SUCCESS); } static inline void test_print_stat (long msgs, size_t size, double interval) { printf ("%7ld (%7.1f per sec.) / %7zuKb (%7.1f Kb/s)\n", msgs, (double)msgs/interval, size >> 10, (double)(size >> 10)/interval); } int main (int argc, char *argv[]) { long err = 0; gcs_test_conf_t conf; gcs_test_thread_pool_t repl_pool, send_pool, recv_pool; const char *channel = "my_channel"; struct timeval t_begin, t_end; gu_config_t* gconf; bool bstrap; gcs_conf_debug_on(); // turn on debug messages if ((err = gcs_test_conf (&conf, argc, argv))) goto out; if (!throughput) { if ((err = test_log_open (&send_log, SEND_LOG))) goto out; if ((err = test_log_open (&recv_log, RECV_LOG))) goto out; } to = gu_to_create ((conf.n_repl + conf.n_recv + 1)*2, GCS_SEQNO_FIRST); if (!to) goto out; // total_tries = conf.n_tries * (conf.n_repl + conf.n_send); printf ("Opening connection: channel = %s, backend = %s\n", channel, conf.backend); gconf = gu_config_create (); if (!gconf) goto out; if (gu_config_add(gconf, "gcache.size", "0")) goto out; if (gu_config_add(gconf, "gcache.page_size", "1M")) goto out; if (!(gcache = gcache_create (gconf, ""))) goto out; if (!(gcs = gcs_create (gconf, gcache, NULL, NULL, 0, 0))) goto out; puts ("debug"); fflush(stdout); /* the following hack won't work if there is 0.0.0.0 in URL options */ bstrap = (NULL != strstr(conf.backend, "0.0.0.0")); if ((err = gcs_open (gcs, channel, conf.backend, bstrap))) goto out; printf ("Connected\n"); msg_len = 1300; if (msg_len > MAX_MSG_LEN) msg_len = MAX_MSG_LEN; gcs_conf_set_pkt_size (gcs, 7570); // to test fragmentation if ((err = gcs_test_thread_pool_create (&repl_pool, GCS_TEST_REPL, conf.n_repl, conf.n_tries))) goto out; if ((err = gcs_test_thread_pool_create (&send_pool, GCS_TEST_SEND, conf.n_send, conf.n_tries))) goto out; if ((err = gcs_test_thread_pool_create (&recv_pool, GCS_TEST_RECV, conf.n_recv, conf.n_tries))) goto out; pthread_mutex_lock (&gcs_test_lock); gcs_test_thread_pool_start (&recv_pool); gcs_test_thread_pool_start (&repl_pool); gcs_test_thread_pool_start (&send_pool); printf ("Press any key to start the load:"); fgetc (stdin); puts ("Started load."); gettimeofday (&t_begin, NULL); printf ("Waiting for %ld seconds\n", conf.n_tries); fflush (stdout); pthread_mutex_unlock (&gcs_test_lock); usleep (conf.n_tries*1000000); puts ("Stopping SEND and REPL threads..."); fflush(stdout); fflush(stderr); gcs_test_thread_pool_stop (&send_pool); gcs_test_thread_pool_stop (&repl_pool); puts ("Threads stopped."); gcs_test_thread_pool_join (&send_pool); gcs_test_thread_pool_join (&repl_pool); puts ("SEND and REPL threads joined."); printf ("Closing GCS connection... "); if ((err = gcs_close (gcs))) goto out; puts ("done."); gcs_test_thread_pool_join (&recv_pool); puts ("RECV threads joined."); gettimeofday (&t_end, NULL); { double interval = (t_end.tv_sec - t_begin.tv_sec) + 0.000001*t_end.tv_usec - 0.000001*t_begin.tv_usec; printf ("Actions sent: "); test_print_stat (msg_sent, size_sent, interval); printf ("Actions received: "); test_print_stat (msg_recvd, size_recvd, interval); printf ("Actions replicated: "); test_print_stat (msg_repld, size_repld, interval); puts("---------------------------------------------------------------"); printf ("Total throughput: "); test_print_stat (msg_repld + msg_recvd, size_repld + size_recvd, interval); printf ("Overhead at 10000 actions/sec: %5.2f%%\n", 1000000.0 * interval / (msg_repld + msg_recvd)); puts(""); } printf ("Press any key to exit the program:\n"); fgetc (stdin); printf ("Freeing GCS connection handle..."); if ((err = gcs_destroy (gcs))) goto out; gcs = NULL; printf ("done\n"); fflush (stdout); printf ("Destroying GCache object:\n"); gcache_destroy (gcache); gcs_test_thread_pool_destroy (&repl_pool); gcs_test_thread_pool_destroy (&send_pool); gcs_test_thread_pool_destroy (&recv_pool); gu_to_destroy(&to); if (!throughput) { printf ("Closing send log\n"); test_log_close (&send_log); printf ("Closing recv log\n"); test_log_close (&recv_log); } { ssize_t total; ssize_t allocs; ssize_t reallocs; ssize_t deallocs; void gu_mem_stats (ssize_t*, ssize_t*, ssize_t*, ssize_t*); gu_mem_stats (&total, &allocs, &reallocs, &deallocs); printf ("Memory statistics:\n" "Memory still allocated: %10lld\n" "Times allocated: %10lld\n" "Times reallocated: %10lld\n" "Times freed: %10lld\n", (long long)total, (long long)allocs, (long long)reallocs, (long long)deallocs); } return 0; out: printf ("Error: %ld (%s)\n", err, strerror (-err)); return err; } percona-galera-3-3.8-3390/gcs/src/gcs_test.hpp000066400000000000000000000104741244131713600206770ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef _gcs_test_h_ #define _gcs_test_h_ // some data to test bugger packets static char gcs_test_data[] = "001 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "002 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "003 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "004 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "005 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "006 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "007 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "008 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "009 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "010 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "011 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "012 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "013 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "014 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "015 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "016 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "017 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "018 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "019 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "020 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "021 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "022 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "023 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "024 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "025 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "026 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "027 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "028 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "029 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "030 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "031 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "032 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "033 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "034 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "035 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "036 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "037 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "038 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "039 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "040 456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" "041 4567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234" ; #endif percona-galera-3-3.8-3390/gcs/src/gcs_test.sh000077500000000000000000000010561244131713600205210ustar00rootroot00000000000000#!/bin/sh # # This script checks the output of the gcs_test program # to verify that all actions that were sent were received # intact # # $Id$ SEND_LOG="gcs_test_send.log" RECV_LOG="gcs_test_recv.log" echo "Sent action count: $(wc -l $SEND_LOG)" echo "Received action count: $(wc -l $RECV_LOG)" SEND_MD5=$(cat "$SEND_LOG" | awk '{ print $4 " " $5 }'| sort -n -k 2 | tee sort_send | md5sum) echo "send_log md5: $SEND_MD5" RECV_MD5=$(cat "$RECV_LOG" | awk '{ print $4 " " $5 }'| sort -n -k 2 | tee sort_recv | md5sum) echo "recv_log md5: $RECV_MD5" # percona-galera-3-3.8-3390/gcs/src/unit_tests/000077500000000000000000000000001244131713600205465ustar00rootroot00000000000000percona-galera-3-3.8-3390/gcs/src/unit_tests/SConscript000066400000000000000000000047331244131713600225670ustar00rootroot00000000000000 Import('check_env') env = check_env.Clone() # For C-style logging env.Append(CPPFLAGS = ' -DGALERA_LOG_H_ENABLE_CXX -Wno-variadic-macros') # Disable old style cast warns until code is fixed env.Append(CPPFLAGS = ' -Wno-old-style-cast') # Allow zero sized arrays env.Replace(CCFLAGS = env['CCFLAGS'].replace('-pedantic', '')) env.Append(CPPFLAGS = ' -Wno-missing-field-initializers') env.Append(CPPFLAGS = ' -Wno-effc++') gcs_tests_sources = Split(''' gcs_tests.cpp gcs_fifo_test.cpp ../gcs_fifo_lite.cpp gcs_sm_test.cpp ../gcs_sm.cpp gcs_comp_test.cpp ../gcs_comp_msg.cpp gcs_state_msg_test.cpp ../gcs_state_msg.cpp gcs_backend_test.cpp ../gcs_backend.cpp gcs_proto_test.cpp ../gcs_act_proto.cpp gcs_defrag_test.cpp ../gcs_defrag.cpp gcs_node_test.cpp ../gcs_node.cpp gcs_group_test.cpp gcs_memb_test.cpp ../gcs_group.cpp gcs_core_test.cpp ../gcs_core.cpp ../gcs_dummy.cpp ../gcs_msg_type.cpp ../gcs.cpp ../gcs_params.cpp gcs_fc_test.cpp ../gcs_fc.cpp ''') #env.Append(CPPFLAGS = ' -DGCS_USE_GCOMM -DGCS_CORE_TESTING -DGCS_DUMMY_TESTING') env.Append(CPPFLAGS = ' -DGCS_CORE_TESTING -DGCS_DUMMY_TESTING') env.Append(LIBS = File('#/gcache/src/libgcache.a')) env.Append(LIBS = File('#/gcomm/src/libgcomm.a')) env.Append(LIBS = File('#/galerautils/src/libgalerautils++.a')) env.Append(LIBS = File('#/galerautils/src/libgalerautils.a')) env.Append(LIBS = ['m']) gcs_tests = env.Program(target = 'gcs_tests', source = gcs_tests_sources, OBJPREFIX = 'gcs-tests-', LINK = env['CXX']) env.Test("gcs_tests.passed", gcs_tests) env.Alias("test", "gcs_tests.passed") Clean(gcs_tests, '#/gcs_tests.log') percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_backend_test.cpp000066400000000000000000000046241244131713600245420ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ #include #include #include #include #include #include #include "../gcs_backend.hpp" #include "gcs_backend_test.hpp" // Fake backend definitons. Must be global for gcs_backend.c to see GCS_BACKEND_NAME_FN(gcs_test_name) { return "DUMMIEEEE!"; } GCS_BACKEND_CREATE_FN(gcs_test_create) { backend->name = gcs_test_name; return 0; } GCS_BACKEND_NAME_FN(gcs_spread_name) { return "SPREAT"; } GCS_BACKEND_CREATE_FN(gcs_spread_create) { backend->name = gcs_spread_name; return 0; } GCS_BACKEND_NAME_FN(gcs_vs_name) { return "vsssssssss"; } GCS_BACKEND_CREATE_FN(gcs_vs_create) { backend->name = gcs_vs_name; return 0; } GCS_BACKEND_NAME_FN(gcs_gcomm_name) { return "gCOMMMMM!!!"; } GCS_BACKEND_CREATE_FN(gcs_gcomm_create) { backend->name = gcs_gcomm_name; return 0; } START_TEST (gcs_backend_test) { gcs_backend_t backend; long ret; gu_config_t* config = gu_config_create (); fail_if (config == NULL); ret = gcs_backend_init (&backend, "wrong://kkk", config); fail_if (ret != -ESOCKTNOSUPPORT); ret = gcs_backend_init (&backend, "spread:", config); fail_if (ret != -EINVAL); ret = gcs_backend_init (&backend, "dummy://", config); fail_if (ret != 0, "ret = %d (%s)", ret, strerror(-ret)); // fail_if (backend.name != gcs_test_name); this test is broken since we can // no longer use global gcs_dummy_create() symbol because linking with real // gcs_dummy.o ret = gcs_backend_init (&backend, "gcomm://0.0.0.0:4567", config); #ifdef GCS_USE_GCOMM fail_if (ret != 0, "ret = %d (%s)", ret, strerror(-ret)); fail_if (backend.name != gcs_gcomm_name); #else fail_if (ret != -ESOCKTNOSUPPORT); #endif // ret = gcs_backend_init (&backend, "vsbes://kkk"); // fail_if (ret != 0, "ret = %d (%s)", ret, strerror(-ret)); // fail_if (backend.name != gcs_vs_name); // ret = gcs_backend_init (&backend, "spread://"); // fail_if (ret != 0, "ret = %d (%s)", ret, strerror(-ret)); // fail_if (backend.name != gcs_spread_name); } END_TEST Suite *gcs_backend_suite(void) { Suite *suite = suite_create("GCS backend interface"); TCase *tcase = tcase_create("gcs_backend"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_backend_test); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_backend_test.hpp000066400000000000000000000003171244131713600245420ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_backend_test__ #define __gcs_backend_test__ extern Suite *gcs_backend_suite(void); #endif /* __gu_backend_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_comp_test.cpp000066400000000000000000000112431244131713600241040ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include #include #include #define GCS_COMP_MSG_ACCESS #include "../gcs_comp_msg.hpp" #include "gcs_comp_test.hpp" static gcs_comp_memb_t const members[] = { { "0", 0 }, { "88888888", 1 }, { "1", 5 }, { "7777777", 1 }, { "22", 3 }, { "666666", 4 }, { "333", 5 }, { "55555", 5 }, { "4444", 0 } }; static char long_id[] = "just make it longer when the test starts to fail because of increased limit"; static void check_msg_identity (const gcs_comp_msg_t* m, const gcs_comp_msg_t* n) { long i; fail_if (n->primary != m->primary); fail_if (n->my_idx != m->my_idx); fail_if (n->memb_num != m->memb_num); for (i = 0; i < m->memb_num; i++) { fail_if (strlen(n->memb[i].id) != strlen(m->memb[i].id), "member %d id len does not match: %d vs %d", i, strlen(n->memb[i].id), strlen(m->memb[i].id)); fail_if (strncmp (n->memb[i].id, m->memb[i].id, GCS_COMP_MEMB_ID_MAX_LEN), "member %d IDs don't not match: got '%s', should be '%s'", i, members[i], m->memb[i].id); fail_if (n->memb[i].segment != m->memb[i].segment, "member %d segments don't not match: got '%d', should be '%d'", i, (int)members[i].segment, (int)m->memb[i].segment); } } START_TEST (gcs_comp_test) { long memb_num = sizeof(members)/sizeof(members[0]); long my_idx = getpid() % memb_num; long prim = my_idx % 2; gcs_comp_msg_t* m = gcs_comp_msg_new (prim, false, my_idx, memb_num, 0); gcs_comp_msg_t* n = NULL; size_t buf_len = gcs_comp_msg_size (m); char buf[buf_len]; long i, j; long ret; fail_if (NULL == m); fail_if (memb_num != gcs_comp_msg_num (m)); fail_if (my_idx != gcs_comp_msg_self (m)); // add members except for the last for (i = 0; i < memb_num - 1; i++) { ret = gcs_comp_msg_add (m, members[i].id, members[i].segment); fail_if (ret != i, "gcs_comp_msg_add() returned %d, expected %d", ret, i); } // try to add a id that was added already if (my_idx < i) { j = my_idx; } else { j = i - 1; } ret = gcs_comp_msg_add (m, members[j].id, members[j].segment); fail_if (ret != -ENOTUNIQ, "gcs_comp_msg_add() returned %d, expected " "-ENOTUNIQ (%d)", ret, -ENOTUNIQ); // try to add empty id ret = gcs_comp_msg_add (m, "", 0); fail_if (ret != -EINVAL, "gcs_comp_msg_add() returned %d, expected " "-EINVAL (%d)", ret, -EINVAL); // try to add id that is too long ret = gcs_comp_msg_add (m, long_id, 3); fail_if (ret != -ENAMETOOLONG, "gcs_comp_msg_add() returned %d, expected " "-ENAMETOOLONG (%d)", ret, -ENAMETOOLONG); // add final id ret = gcs_comp_msg_add (m, members[i].id, members[i].segment); fail_if (ret != i, "gcs_comp_msg_add() returned %d, expected %d", ret, i); // check that all added correctly for (i = 0; i < memb_num; i++) { const char* const id = gcs_comp_msg_member(m, i)->id; fail_if (strcmp (members[i].id, id), "Memeber %ld (%s) recorded as %s", i, members[i].id, id); } // check that memcpy preserves the message // (it can be treated just as a byte array) memcpy (buf, m, buf_len); n = (gcs_comp_msg_t*) buf; check_msg_identity (m, n); gcs_comp_msg_delete (m); mark_point(); // check that gcs_comp_msg_copy() works m = gcs_comp_msg_copy (n); fail_if (NULL == m); check_msg_identity (m, n); gcs_comp_msg_delete (m); // test gcs_comp_msg_member() fail_unless (NULL == gcs_comp_msg_member (n, -1)); for (i = 0; i < memb_num; i++) { const char* id = gcs_comp_msg_member (n, i)->id; fail_if (NULL == id); fail_if (strcmp(members[i].id, id)); } fail_unless (NULL == gcs_comp_msg_member (n, i)); // test gcs_comp_msg_idx() fail_if (-1 != gcs_comp_msg_idx (n, "")); fail_if (-1 != gcs_comp_msg_idx (n, long_id)); for (i = 0; i < memb_num; i++) fail_if (i != gcs_comp_msg_idx (n, members[i].id)); // test gcs_comp_msg_primary() fail_if (n->primary != gcs_comp_msg_primary(n)); } END_TEST Suite *gcs_comp_suite(void) { Suite *suite = suite_create("GCS component message"); TCase *tcase = tcase_create("gcs_comp"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_comp_test); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_comp_test.hpp000066400000000000000000000003031244131713600241040ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_comp_test__ #define __gcs_comp_test__ extern Suite *gcs_comp_suite(void); #endif /* __gu_comp_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_core_test.cpp000066400000000000000000001017271244131713600241050ustar00rootroot00000000000000/* * Copyright (C) 2008-2013 Codership Oy * * $Id$ */ /* * @file * * Defines unit tests for gcs_core (and as a result tests gcs_group and * a dummy backend which gcs_core depends on) * * Most of the checks require independent sending and receiving threads. * Approach 1 is to start separate threads for both sending and receiving * and use the current thread of execution to sychronize between them: * * CORE_RECV_START(act_r) * CORE_SEND_START(act_s) * while (gcs_core_send_step(Core)) { // step through action fragments * (do something) * }; * CORE_SEND_END(act_s, ret) // check return code * CORE_RECV_END(act_r, size, type) // makes checks against size and type * * A simplified approach 2 is: * * CORE_SEND_START(act_s) * while (gcs_core_send_step(Core)) { // step through action fragments * (do something) * }; * CORE_SEND_END(act_s, ret) // check return code * CORE_RECV_ACT(act_r, size, type) // makes checks agains size and type * * In the first approach group messages will be received concurrently. * In the second approach messages will wait in queue and be fetched afterwards * */ #include "gcs_core_test.hpp" #define GCS_STATE_MSG_ACCESS #include "../gcs_core.hpp" #include "../gcs_dummy.hpp" #include "../gcs_seqno.hpp" #include "../gcs_state_msg.hpp" #include #include #include extern ssize_t gcs_tests_get_allocated(); static const long UNKNOWN_SIZE = 1234567890; // some unrealistic number static gcs_core_t* Core = NULL; static gcs_backend_t* Backend = NULL; static gcs_seqno_t Seqno = 0; typedef struct action { const struct gu_buf* in; void* out; const void* local; ssize_t size; gcs_act_type_t type; gcs_seqno_t seqno; gu_thread_t thread; action() { } action(const struct gu_buf* a_in, void* a_out, const void* a_local, ssize_t a_size, gcs_act_type_t a_type, gcs_seqno_t a_seqno, gu_thread_t a_thread) : in (a_in), out (a_out), local (a_local), size (a_size), type (a_type), seqno (a_seqno), thread (a_thread) { } } action_t; //static struct action_t RecvAct; static const ssize_t FRAG_SIZE = 4; // desirable action fragment size // 1-fragment action static const char act1_str[] = "101"; static const struct gu_buf act1[1] = { { act1_str, sizeof(act1_str) } }; // 2-fragment action, with buffers aligned with FRAG_SIZE static const char act2_str[] = "202122"; static const struct gu_buf act2[2] = { { "2021", 4 }, { "22", 3 } /* 4 + 3 = 7 = sizeof(act2_str) */ }; // 3-fragment action, with unaligned buffers static const char act3_str[] = "3031323334"; static const struct gu_buf act3[] = { { "303", 3 }, { "13", 2 }, { "23", 2 }, { "334", 4 } /* 3 + 2 + 2 + 4 = 11 = sizeof(act3_str) */ }; // action receive thread, returns after first action received, stores action // in the passed action_t object, uses global Core to receive static void* core_recv_thread (void* arg) { action_t* act = (action_t*)arg; // @todo: refactor according to new gcs_act types struct gcs_act_rcvd recv_act; act->size = gcs_core_recv (Core, &recv_act, GU_TIME_ETERNITY); act->out = (void*)recv_act.act.buf; act->local = recv_act.local; act->type = recv_act.act.type; act->seqno = recv_act.id; return (NULL); } // this macro logs errors from within a function #define FAIL_IF(expr, format, ...) \ if (expr) { \ gu_fatal ("FAIL: "format, __VA_ARGS__, NULL); \ fail_if (true, format, __VA_ARGS__, NULL); \ return true; \ } /* * Huge macros which follow below cannot be functions for the purpose * of correct line reporting. */ // Start a thread to receive an action // args: action_t object static inline bool CORE_RECV_START(action_t* act) { return (0 != gu_thread_create (&act->thread, NULL, core_recv_thread, act)); } static bool COMMON_RECV_CHECKS(action_t* act, const char* buf, ssize_t size, gcs_act_type_t type, gcs_seqno_t* seqno) { FAIL_IF (size != UNKNOWN_SIZE && size != act->size, "gcs_core_recv(): expected %lld, returned %zd (%s)", (long long) size, act->size, strerror (-act->size)); FAIL_IF (act->type != type, "type does not match: expected %d, got %d", type, act->type); FAIL_IF (act->size > 0 && act->out == NULL, "null buffer received with positive size: %zu", act->size); if (act->type == GCS_ACT_STATE_REQ) return false; // action is ordered only if it is of type GCS_ACT_TORDERED and not an error if (act->seqno >= GCS_SEQNO_NIL) { FAIL_IF (GCS_ACT_TORDERED != act->type, "GCS_ACT_TORDERED != act->type (%d), while act->seqno: %lld", act->type, (long long)act->seqno); FAIL_IF ((*seqno + 1) != act->seqno, "expected seqno %lld, got %lld", (long long)(*seqno + 1), (long long)act->seqno); *seqno = *seqno + 1; } if (NULL != buf) { if (GCS_ACT_TORDERED == act->type) { // local action buffer should not be copied FAIL_IF (act->local != act->in, "Received buffer ptr is not the same as sent: %p != %p", act->in, act->local, NULL); FAIL_IF (memcmp (buf, act->out, act->size), "Received buffer contents is not the same as sent: " "'%s' != '%s'", buf, (char*)act->out); } else { FAIL_IF (act->local == buf, "Received the same buffer ptr as sent", NULL); FAIL_IF (memcmp (buf, act->out, act->size), "Received buffer contents is not the same as sent", NULL); } } return false; } // Wait for recv thread to complete, perform required checks // args: action_t, expected size, expected type static bool CORE_RECV_END(action_t* act, const void* buf, ssize_t size, gcs_act_type_t type) { { int ret = gu_thread_join (act->thread, NULL); act->thread = (gu_thread_t)-1; FAIL_IF(0 != ret, "Failed to join recv thread: %ld (%s)", ret, strerror (ret)); } return COMMON_RECV_CHECKS (act, (const char*)buf, size, type, &Seqno); } // Receive action in one call, perform required checks // args: pointer to action_t, expected size, expected type static bool CORE_RECV_ACT (action_t* act, const void* buf, // single buffer action repres. ssize_t size, gcs_act_type_t type) { struct gcs_act_rcvd recv_act; act->size = gcs_core_recv (Core, &recv_act, GU_TIME_ETERNITY); act->out = (void*)recv_act.act.buf; act->local = recv_act.local; act->type = recv_act.act.type; act->seqno = recv_act.id; return COMMON_RECV_CHECKS (act, (const char*)buf, size, type, &Seqno); } // Sending always needs to be done via separate thread (uses lock-stepping) void* core_send_thread (void* arg) { action_t* act = (action_t*)arg; // use seqno field to pass the return code, it is signed 8-byte integer act->seqno = gcs_core_send (Core, act->in, act->size, act->type); return (NULL); } // Start a thread to send an action // args: action_t object static bool CORE_SEND_START(action_t* act) { return (0 != gu_thread_create (&act->thread, NULL, core_send_thread, act)); } // Wait for send thread to complete, perform required checks // args: action_t, expected return code static bool CORE_SEND_END(action_t* act, long ret) { { long _ret = gu_thread_join (act->thread, NULL); act->thread = (gu_thread_t)-1; FAIL_IF (0 != _ret, "Failed to join recv thread: %ld (%s)", _ret, strerror (_ret)); } FAIL_IF (ret != act->seqno, "gcs_core_send(): expected %lld, returned %lld (%s)", (long long) ret, (long long) act->seqno, strerror (-act->seqno)); return false; } // check if configuration is the one that we expected static long core_test_check_conf (const gcs_act_conf_t* conf, bool prim, long my_idx, long memb_num) { long ret = 0; if ((conf->conf_id >= 0) != prim) { gu_error ("Expected %s conf, received %s", prim ? "PRIMARY" : "NON-PRIMARY", (conf->conf_id >= 0) ? "PRIMARY" : "NON-PRIMARY"); ret = -1; } if (conf->my_idx != my_idx) { gu_error ("Expected my_idx = %ld, got %ld", my_idx, conf->my_idx); ret = -1; } if (conf->my_idx != my_idx) { gu_error ("Expected my_idx = %ld, got %ld", my_idx, conf->my_idx); ret = -1; } return ret; } static long core_test_set_payload_size (ssize_t s) { long ret; const ssize_t arbitrary_pkt_size = s + 64; // big enough for payload to fit ret = gcs_core_set_pkt_size (Core, arbitrary_pkt_size); if (ret <= 0) { gu_error("set_pkt_size(%zd) returned: %ld (%s)", arbitrary_pkt_size, ret, strerror (-ret)); return ret; } ret = gcs_core_set_pkt_size (Core, arbitrary_pkt_size - ret + s); if (ret != s) { gu_error("set_pkt_size() returned: %ld instead of %zd", ret, s); return ret; } return 0; } // Initialises core and backend objects + some common tests static inline void core_test_init (bool bootstrap = true, const char* name = "core_test") { long ret; action_t act; mark_point(); gu_config_t* config = gu_config_create (); fail_if (config == NULL); Core = gcs_core_create (config, NULL, name, "aaa.bbb.ccc.ddd:xxxx", 0, 0); fail_if (NULL == Core); Backend = gcs_core_get_backend (Core); fail_if (NULL == Backend); Seqno = 0; // reset seqno ret = core_test_set_payload_size (FRAG_SIZE); fail_if (-EBADFD != ret, "Expected -EBADFD, got: %ld (%s)", ret, strerror(-ret)); ret = gcs_core_open (Core, "yadda-yadda", "owkmevc", 1); fail_if (-EINVAL != ret, "Expected -EINVAL, got %ld (%s)", ret, strerror(-ret)); ret = gcs_core_open (Core, "yadda-yadda", "dummy://", bootstrap); fail_if (0 != ret, "Failed to open core connection: %ld (%s)", ret, strerror(-ret)); if (!bootstrap) { gcs_core_send_lock_step (Core, true); mark_point(); return; } // receive first configuration message fail_if (CORE_RECV_ACT (&act, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act.out, bootstrap, 0, 1)); free (act.out); // this will configure backend to have desired fragment size ret = core_test_set_payload_size (FRAG_SIZE); fail_if (0 != ret, "Failed to set up the message payload size: %ld (%s)", ret, strerror(-ret)); // try to send an action to check that everything's alright ret = gcs_core_send (Core, act1, sizeof(act1_str), GCS_ACT_TORDERED); fail_if (ret != sizeof(act1_str), "Expected %d, got %d (%s)", sizeof(act1_str), ret, strerror (-ret)); gu_warn ("Next CORE_RECV_ACT fails under valgrind"); act.in = act1; fail_if (CORE_RECV_ACT (&act, act1_str, sizeof(act1_str),GCS_ACT_TORDERED)); ret = gcs_core_send_join (Core, Seqno); fail_if (ret != 0, "gcs_core_send_join(): %ld (%s)", ret, strerror(-ret)); // no action to be received (we're joined already) ret = gcs_core_send_sync (Core, Seqno); fail_if (ret != 0, "gcs_core_send_sync(): %ld (%s)", ret, strerror(-ret)); fail_if (CORE_RECV_ACT(&act,NULL,sizeof(gcs_seqno_t),GCS_ACT_SYNC)); fail_if (Seqno != gcs_seqno_gtoh(*(gcs_seqno_t*)act.out)); gcs_core_send_lock_step (Core, true); mark_point(); } // cleans up core and backend objects static inline void core_test_cleanup () { long ret; char tmp[1]; action_t act; fail_if (NULL == Core); fail_if (NULL == Backend); // to fetch self-leave message fail_if (CORE_RECV_START (&act)); ret = gcs_core_close (Core); fail_if (0 != ret, "Failed to close core: %ld (%s)", ret, strerror (-ret)); ret = CORE_RECV_END (&act, NULL, UNKNOWN_SIZE, GCS_ACT_CONF); fail_if (ret, "ret: %ld (%s)", ret, strerror(-ret)); free (act.out); // check that backend is closed too ret = Backend->send (Backend, tmp, sizeof(tmp), GCS_MSG_ACTION); fail_if (ret != -EBADFD); ret = gcs_core_destroy (Core); fail_if (0 != ret, "Failed to destroy core: %ld (%s)", ret, strerror (-ret)); { ssize_t allocated; allocated = gcs_tests_get_allocated(); fail_if (0 != allocated, "Expected 0 allocated bytes, found %zd", allocated); } } // just a smoke test for core API START_TEST (gcs_core_test_api) { core_test_init (); fail_if (NULL == Core); fail_if (NULL == Backend); long ret; long tout = 100; // 100 ms timeout const struct gu_buf* act = act3; const void* act_buf = act3_str; size_t act_size = sizeof(act3_str); action_t act_s(act, NULL, NULL, act_size, GCS_ACT_TORDERED, -1, (gu_thread_t)-1); action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)-1, -1, (gu_thread_t)-1); long i = 5; // test basic fragmentaiton while (i--) { long frags = (act_size - 1)/FRAG_SIZE + 1; gu_info ("Iteration %ld: act: %s, size: %zu, frags: %ld", i, act, act_size, frags); fail_if (CORE_SEND_START (&act_s)); while ((ret = gcs_core_send_step (Core, 3*tout)) > 0) { frags--; gu_info ("frags: %ld", frags); // usleep (1000); } fail_if (ret != 0, "gcs_core_send_step() returned: %ld (%s)", ret, strerror(-ret)); fail_if (frags != 0, "frags = %ld, instead of 0", frags); fail_if (CORE_SEND_END (&act_s, act_size)); fail_if (CORE_RECV_ACT (&act_r, act_buf, act_size, GCS_ACT_TORDERED)); ret = gcs_core_set_last_applied (Core, Seqno); fail_if (ret != 0, "gcs_core_set_last_applied(): %ld (%s)", ret, strerror(-ret)); fail_if (CORE_RECV_ACT (&act_r, NULL, sizeof(gcs_seqno_t), GCS_ACT_COMMIT_CUT)); fail_if (Seqno != gcs_seqno_gtoh(*(gcs_seqno_t*)act_r.out)); free (act_r.out); } // send fake flow control action, its contents is not important gcs_core_send_fc (Core, act, act_size); fail_if (ret != 0, "gcs_core_send_fc(): %ld (%s)", ret, strerror(-ret)); fail_if (CORE_RECV_ACT(&act_r, act, act_size, GCS_ACT_FLOW)); core_test_cleanup (); } END_TEST // do a single send step, compare with the expected result static inline bool CORE_SEND_STEP (gcs_core_t* core, long timeout, long ret) { long err = gcs_core_send_step (core, timeout); FAIL_IF (err < 0, "gcs_core_send_step(): %ld (%s)", err, strerror (-err)); if (ret >= 0) { FAIL_IF (err != ret, "gcs_core_send_step(): expected %ld, got %ld", ret, err); } return false; } static bool DUMMY_INJECT_COMPONENT (gcs_backend_t* backend, const gcs_comp_msg_t* comp) { long ret = gcs_dummy_inject_msg (Backend, comp, gcs_comp_msg_size(comp), GCS_MSG_COMPONENT, GCS_SENDER_NONE); FAIL_IF (ret <= 0, "gcs_dummy_inject_msg(): %ld (%s)", ret, strerror(ret)); return false; } static bool DUMMY_INSTALL_COMPONENT (gcs_backend_t* backend, const gcs_comp_msg_t* comp) { bool primary = gcs_comp_msg_primary (comp); long my_idx = gcs_comp_msg_self (comp); long members = gcs_comp_msg_num (comp); action_t act; FAIL_IF (gcs_dummy_set_component(Backend, comp), "", NULL); FAIL_IF (DUMMY_INJECT_COMPONENT (Backend, comp), "", NULL); FAIL_IF (CORE_RECV_ACT (&act, NULL, UNKNOWN_SIZE, GCS_ACT_CONF), "", NULL); FAIL_IF (core_test_check_conf((const gcs_act_conf_t*)act.out, primary, my_idx, members), "", NULL); free (act.out); return false; } START_TEST (gcs_core_test_own) { long const tout = 1000; // 100 ms timeout const struct gu_buf* act = act2; const void* act_buf = act2_str; size_t act_size = sizeof(act2_str); action_t act_s(act, NULL, NULL, act_size, GCS_ACT_TORDERED, -1, (gu_thread_t)-1); action_t act_r(act, NULL, NULL, -1, (gcs_act_type_t)-1, -1, (gu_thread_t)-1); // Create primary and non-primary component messages gcs_comp_msg_t* prim = gcs_comp_msg_new (true, false, 0, 1, 0); gcs_comp_msg_t* non_prim = gcs_comp_msg_new (false, false, 0, 1, 0); fail_if (NULL == prim); fail_if (NULL == non_prim); gcs_comp_msg_add (prim, "node1", 0); gcs_comp_msg_add (non_prim, "node1", 1); core_test_init (); ///////////////////////////////////////////// /// check behaviour in transitional state /// ///////////////////////////////////////////// fail_if (CORE_RECV_START (&act_r)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag usleep (10000); // resolve race between sending and setting transitional gcs_dummy_set_transitional (Backend); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag fail_if (CORE_SEND_STEP (Core, tout, 0)); // no frags left fail_if (NULL != act_r.out); // should not have received anything fail_if (gcs_dummy_set_component (Backend, prim)); // return to PRIM state fail_if (CORE_SEND_END (&act_s, act_size)); fail_if (CORE_RECV_END (&act_r, act_buf, act_size, GCS_ACT_TORDERED)); /* * TEST CASE 1: Action was sent successfully, but NON_PRIM component * happened before any fragment could be delivered. * EXPECTED OUTCOME: action is received with -ENOTCONN instead of global * seqno */ fail_if (DUMMY_INJECT_COMPONENT (Backend, non_prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag fail_if (CORE_SEND_END (&act_s, act_size)); fail_if (gcs_dummy_set_component(Backend, non_prim)); fail_if (CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, false, 0, 1)); free (act_r.out); fail_if (CORE_RECV_ACT (&act_r, act_buf, act_size, GCS_ACT_TORDERED)); fail_if (-ENOTCONN != act_r.seqno, "Expected -ENOTCONN, received %ld (%s)", act_r.seqno, strerror (-act_r.seqno)); /* * TEST CASE 2: core in NON_PRIM state. There is attempt to send an * action. * EXPECTED OUTCOME: CORE_SEND_END should return -ENOTCONN after 1st * fragment send fails. */ fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (CORE_SEND_STEP (Core, tout, 0)); // bail out after 1st frag fail_if (CORE_SEND_END (&act_s, -ENOTCONN)); /* * TEST CASE 3: Backend in NON_PRIM state. There is attempt to send an * action. * EXPECTED OUTCOME: CORE_SEND_END should return -ENOTCONN after 1st * fragment send fails. */ fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (gcs_dummy_set_component(Backend, non_prim)); fail_if (DUMMY_INJECT_COMPONENT (Backend, non_prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (CORE_SEND_END (&act_s, -ENOTCONN)); fail_if (CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, false, 0, 1)); free (act_r.out); /* * TEST CASE 4: Action was sent successfully, but NON_PRIM component * happened in between delivered fragments. * EXPECTED OUTCOME: action is received with -ENOTCONN instead of global * seqno. */ fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (DUMMY_INJECT_COMPONENT (Backend, non_prim)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag fail_if (CORE_SEND_END (&act_s, act_size)); fail_if (CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, false, 0, 1)); free (act_r.out); fail_if (CORE_RECV_ACT (&act_r, act_buf, act_size, GCS_ACT_TORDERED)); fail_if (-ENOTCONN != act_r.seqno, "Expected -ENOTCONN, received %ld (%s)", act_r.seqno, strerror (-act_r.seqno)); /* * TEST CASE 5: Action is being sent and received concurrently. In between * two fragments recv thread receives NON_PRIM and then PRIM components. * EXPECTED OUTCOME: CORE_RECV_ACT should receive the action with -ERESTART * instead of seqno. */ fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag usleep (100000); // make sure 1st fragment gets in before new component fail_if (DUMMY_INSTALL_COMPONENT (Backend, non_prim)); fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag fail_if (CORE_SEND_END (&act_s, act_size)); fail_if (CORE_RECV_ACT (&act_r, act_buf, act_size, GCS_ACT_TORDERED)); fail_if (-ERESTART != act_r.seqno, "Expected -ERESTART, received %ld (%s)", act_r.seqno, strerror (-act_r.seqno)); /* * TEST CASE 6: Action has 3 fragments, 2 were sent successfully but the * 3rd failed because backend is in NON_PRIM. In addition NON_PRIM component * happened in between delivered fragments. * subcase 1: new component received first * subcase 2: 3rd fragment is sent first * EXPECTED OUTCOME: CORE_SEND_END should return -ENOTCONN after 3rd * fragment send fails. */ act = act3; act_buf = act3_str; act_size = sizeof(act3_str); act_s.in = act; act_s.size = act_size; // subcase 1 fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (DUMMY_INJECT_COMPONENT (Backend, non_prim)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag usleep (500000); // fail_if_seq fail_if (gcs_dummy_set_component(Backend, non_prim)); fail_if (CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, false, 0, 1)); free (act_r.out); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 3rd frag fail_if (CORE_SEND_END (&act_s, -ENOTCONN)); // subcase 2 fail_if (DUMMY_INSTALL_COMPONENT (Backend, prim)); fail_if (CORE_SEND_START (&act_s)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 1st frag fail_if (DUMMY_INJECT_COMPONENT (Backend, non_prim)); fail_if (CORE_SEND_STEP (Core, tout, 1)); // 2nd frag usleep (1000000); fail_if (gcs_dummy_set_component(Backend, non_prim)); fail_if (CORE_SEND_STEP (Core, 4*tout, 1)); // 3rd frag fail_if (CORE_RECV_ACT (&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, false, 0, 1)); free (act_r.out); fail_if (CORE_SEND_END (&act_s, -ENOTCONN)); gu_free (prim); gu_free (non_prim); core_test_cleanup (); } END_TEST /* * Disabled test because it is too slow and timeouts on crowded * build systems like e.g. build.opensuse.org START_TEST (gcs_core_test_gh74) { core_test_init(true, "node1"); // set frag size large enough to avoid fragmentation. gu_info ("set payload size = 1024"); core_test_set_payload_size(1024); // new primary comp message. gcs_comp_msg_t* prim = gcs_comp_msg_new (true, false, 0, 2, 0); fail_if (NULL == prim); gcs_comp_msg_add(prim, "node1", 0); gcs_comp_msg_add(prim, "node2", 1); // construct state transform request. static const char* req_ptr = "12345"; static const size_t req_size = 6; static const char* donor = ""; // from *any* static const size_t donor_len = strlen(donor) + 1; size_t act_size = req_size + donor_len; char* act_ptr = 0; act_ptr = (char*)gu_malloc(act_size); memcpy(act_ptr, donor, donor_len); memcpy(act_ptr + donor_len, req_ptr, req_size); // serialize request into message. gcs_act_frag_t frg; frg.proto_ver = gcs_core_group_protocol_version(Core); frg.frag_no = 0; frg.act_id = 1; frg.act_size = act_size; frg.act_type = GCS_ACT_STATE_REQ; char msg_buf[1024]; fail_if(gcs_act_proto_write(&frg, msg_buf, sizeof(msg_buf))); memcpy(const_cast(frg.frag), act_ptr, act_size); size_t msg_size = act_size + gcs_act_proto_hdr_size(frg.proto_ver); // gu_free(act_ptr); // state exchange message. gu_uuid_t state_uuid; gu_uuid_generate(&state_uuid, NULL, 0); gcs_core_set_state_uuid(Core, &state_uuid); // construct uuid message from node1. size_t uuid_len = sizeof(state_uuid); char uuid_buf[uuid_len]; memcpy(uuid_buf, &state_uuid, uuid_len); gcs_state_msg_t* state_msg = NULL; const gcs_group_t* group = gcs_core_get_group(Core); // state exchange message from node1 state_msg = gcs_group_get_state(group); state_msg->state_uuid = state_uuid; size_t state_len = gcs_state_msg_len (state_msg); char state_buf[state_len]; gcs_state_msg_write (state_buf, state_msg); gcs_state_msg_destroy (state_msg); // state exchange message from node2 state_msg = gcs_state_msg_create(&state_uuid, &GU_UUID_NIL, &GU_UUID_NIL, GCS_SEQNO_ILL, GCS_SEQNO_ILL, GCS_SEQNO_ILL, 0, GCS_NODE_STATE_NON_PRIM, GCS_NODE_STATE_PRIM, "node2", "127.0.0.1", group->gcs_proto_ver, group->repl_proto_ver, group->appl_proto_ver, 0); size_t state_len2 = gcs_state_msg_len (state_msg); char state_buf2[state_len2]; gcs_state_msg_write (state_buf2, state_msg); gcs_state_msg_destroy (state_msg); action_t act_r(NULL, NULL, NULL, -1, (gcs_act_type_t)-1, -1, (gu_thread_t)-1); // ========== from node1's view ========== fail_if (gcs_dummy_set_component(Backend, prim)); fail_if (DUMMY_INJECT_COMPONENT(Backend, prim)); gu_free(prim); CORE_RECV_START(&act_r); // we have to start another thread here. // otherwise messages to node1 can not be in right order. for(;;) { usleep(10000); // make sure node1 already changed its status to WAIT_STATE_MSG if (gcs_group_state(group) == GCS_GROUP_WAIT_STATE_MSG) { break; } } // then STR sneaks before new configuration is delivered. fail_if (gcs_dummy_inject_msg(Backend, msg_buf, msg_size, GCS_MSG_ACTION, 1) != (int)msg_size); // then state exchange message from node2. fail_if (gcs_dummy_inject_msg(Backend, state_buf2, state_len2, GCS_MSG_STATE_MSG, 1) != (int)state_len2); // expect STR is lost here. fail_if (CORE_RECV_END(&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, true, 0, 2)); free(act_r.out); core_test_cleanup(); // ========== from node2's view ========== core_test_init(false, "node2"); // set frag size large enough to avoid fragmentation. gu_info ("set payload size = 1024"); core_test_set_payload_size(1024); prim = gcs_comp_msg_new (true, false, 1, 2, 0); fail_if (NULL == prim); gcs_comp_msg_add(prim, "node1", 0); gcs_comp_msg_add(prim, "node2", 1); // node1 and node2 joins. // now node2's status == GCS_NODE_STATE_PRIM fail_if (gcs_dummy_set_component(Backend, prim)); fail_if (DUMMY_INJECT_COMPONENT(Backend, prim)); gu_free(prim); fail_if (gcs_dummy_inject_msg(Backend, uuid_buf, uuid_len, GCS_MSG_STATE_UUID, 0) != (int)uuid_len); fail_if (gcs_dummy_inject_msg(Backend, state_buf, state_len, GCS_MSG_STATE_MSG, 0) != (int)state_len); fail_if (CORE_RECV_ACT(&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, true, 1, 2)); free(act_r.out); // then node3 joins. prim = gcs_comp_msg_new (true, false, 1, 3, 0); fail_if (NULL == prim); gcs_comp_msg_add(prim, "node1", 0); gcs_comp_msg_add(prim, "node2", 1); gcs_comp_msg_add(prim, "node3", 2); fail_if (gcs_dummy_set_component(Backend, prim)); fail_if (DUMMY_INJECT_COMPONENT(Backend, prim)); gu_free(prim); // generate a new state uuid. gu_uuid_generate(&state_uuid, NULL, 0); memcpy(uuid_buf, &state_uuid, uuid_len); // state exchange message from node3 group = gcs_core_get_group(Core); state_msg = gcs_state_msg_create(&state_uuid, &GU_UUID_NIL, &GU_UUID_NIL, GCS_SEQNO_ILL, GCS_SEQNO_ILL, GCS_SEQNO_ILL, 0, GCS_NODE_STATE_NON_PRIM, GCS_NODE_STATE_PRIM, "node3", "127.0.0.1", group->gcs_proto_ver, group->repl_proto_ver, group->appl_proto_ver, 0); size_t state_len3 = gcs_state_msg_len (state_msg); char state_buf3[state_len3]; gcs_state_msg_write (state_buf3, state_msg); gcs_state_msg_destroy (state_msg); // updating state message from node1. group = gcs_core_get_group(Core); state_msg = gcs_group_get_state(group); state_msg->flags = GCS_STATE_FREP | GCS_STATE_FCLA; state_msg->prim_state = GCS_NODE_STATE_JOINED; state_msg->current_state = GCS_NODE_STATE_SYNCED; state_msg->state_uuid = state_uuid; state_msg->name = "node1"; gcs_state_msg_write(state_buf, state_msg); gcs_state_msg_destroy(state_msg); fail_if (gcs_dummy_inject_msg(Backend, uuid_buf, uuid_len, GCS_MSG_STATE_UUID, 0) != (int)uuid_len); fail_if (gcs_dummy_inject_msg(Backend, state_buf, state_len, GCS_MSG_STATE_MSG, 0) != (int)state_len); // STR sneaks. // we have to make same message exists in sender queue too. // otherwise we will get following log // "FIFO violation: queue empty when local action received" const struct gu_buf act = {act_ptr, (ssize_t)act_size}; action_t act_s(&act, NULL, NULL, act_size, GCS_ACT_STATE_REQ, -1, (gu_thread_t)-1); CORE_SEND_START(&act_s); for(;;) { usleep(10000); gcs_fifo_lite_t* fifo = gcs_core_get_fifo(Core); void* item = gcs_fifo_lite_get_head(fifo); if (item) { gcs_fifo_lite_release(fifo); break; } } fail_if (gcs_dummy_inject_msg(Backend, msg_buf, msg_size, GCS_MSG_ACTION, 1) != (int)msg_size); fail_if (gcs_dummy_inject_msg(Backend, state_buf3, state_len3, GCS_MSG_STATE_MSG, 2) != (int)state_len3); // expect STR and id == -EAGAIN. fail_if (CORE_RECV_ACT(&act_r, act_ptr, act_size, GCS_ACT_STATE_REQ)); fail_if (act_r.seqno != -EAGAIN); free(act_r.out); fail_if (CORE_RECV_ACT(&act_r, NULL, UNKNOWN_SIZE, GCS_ACT_CONF)); fail_if (core_test_check_conf((const gcs_act_conf_t*)act_r.out, true, 1, 3)); free(act_r.out); // core_test_cleanup(); // ========== gu_free(act_ptr); } END_TEST */ #if 0 // requires multinode support from gcs_dummy START_TEST (gcs_core_test_foreign) { core_test_init (); core_test_cleanup (); } END_TEST #endif // 0 Suite *gcs_core_suite(void) { Suite *suite = suite_create("GCS core context"); TCase *tcase = tcase_create("gcs_core"); suite_add_tcase (suite, tcase); tcase_set_timeout(tcase, 60); bool skip = false; if (skip == false) { tcase_add_test (tcase, gcs_core_test_api); tcase_add_test (tcase, gcs_core_test_own); // tcase_add_test (tcase, gcs_core_test_foreign); // tcase_add_test (tcase, gcs_core_test_gh74); } return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_core_test.hpp000066400000000000000000000003271244131713600241040ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_core_test__ #define __gcs_core_test__ #include extern Suite *gcs_core_suite(void); #endif /* __gu_core_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_defrag_test.cpp000066400000000000000000000114721244131713600244020ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include #include "gcs_defrag_test.hpp" #include "../gcs_defrag.hpp" #define TRUE (0 == 0) #define FALSE (!TRUE) static void defrag_check_init (gcs_defrag_t* defrag) { fail_if (defrag->sent_id != GCS_SEQNO_ILL); fail_if (defrag->head != NULL); fail_if (defrag->tail != NULL); fail_if (defrag->size != 0); fail_if (defrag->received != 0); fail_if (defrag->frag_no != 0); } START_TEST (gcs_defrag_test) { ssize_t ret; // The Action char act_buf[] = "Test action smuction"; size_t act_len = sizeof (act_buf); // lengths of three fragments of the action size_t frag1_len = act_len / 3; size_t frag2_len = frag1_len; size_t frag3_len = act_len - frag1_len - frag2_len; // pointer to the three fragments of the action const char* frag1 = act_buf; const char* frag2 = frag1 + frag1_len; const char* frag3 = frag2 + frag2_len; // recv fragments gcs_act_frag_t frg1, frg2, frg3, frg4; gcs_defrag_t defrag; struct gcs_act recv_act; void* tail; mark_point(); #ifndef NDEBUG // debug build breaks this test due to asserts return; #endif // Initialize message parameters frg1.act_id = getpid(); frg1.act_size = act_len; frg1.frag = frag1; frg1.frag_len = frag1_len; frg1.frag_no = 0; frg1.act_type = GCS_ACT_TORDERED; frg1.proto_ver = 0; // normal fragments frg2 = frg3 = frg1; frg2.frag = frag2; frg2.frag_len = frag2_len; frg2.frag_no = frg1.frag_no + 1; frg3.frag = frag3; frg3.frag_len = frag3_len; frg3.frag_no = frg2.frag_no + 1; // bad fragmets to be tried instead of frg2 frg4 = frg2; frg4.frag = "junk"; frg4.frag_len = strlen("junk"); frg4.act_id = frg2.act_id + 1; // wrong action id mark_point(); // ready for the first fragment gcs_defrag_init (&defrag, NULL); defrag_check_init (&defrag); mark_point(); // 1. Try fragment that is not the first ret = gcs_defrag_handle_frag (&defrag, &frg3, &recv_act, FALSE); fail_if (ret != -EPROTO); mark_point(); defrag_check_init (&defrag); // should be no changes // 2. Try first fragment ret = gcs_defrag_handle_frag (&defrag, &frg1, &recv_act, FALSE); fail_if (ret != 0); fail_if (defrag.head == NULL); fail_if (defrag.received != frag1_len); fail_if (defrag.tail != defrag.head + defrag.received); tail = defrag.tail; #define TRY_WRONG_2ND_FRAGMENT(frag) \ ret = gcs_defrag_handle_frag (&defrag, frag, &recv_act, FALSE); \ fail_if (ret != -EPROTO); \ fail_if (defrag.received != frag1_len); \ fail_if (defrag.tail != tail); // 3. Try first fragment again TRY_WRONG_2ND_FRAGMENT(&frg1); // 4. Try third fragment TRY_WRONG_2ND_FRAGMENT(&frg3); // 5. Try fouth fragment TRY_WRONG_2ND_FRAGMENT(&frg4); // 6. Try second fragment ret = gcs_defrag_handle_frag (&defrag, &frg2, &recv_act, FALSE); fail_if (ret != 0); fail_if (defrag.received != frag1_len + frag2_len); fail_if (defrag.tail != defrag.head + defrag.received); // 7. Try third fragment, last one ret = gcs_defrag_handle_frag (&defrag, &frg3, &recv_act, FALSE); fail_if (ret != (long)act_len); // 8. Check the action fail_if (recv_act.buf_len != (long)act_len); fail_if (strncmp((const char*)recv_act.buf, act_buf, act_len), "Action received: '%s', expected '%s'",recv_act.buf,act_buf); defrag_check_init (&defrag); // should be empty // memleak in recv_act.buf ! // 9. Try the same with local action ret = gcs_defrag_handle_frag (&defrag, &frg1, &recv_act, TRUE); fail_if (ret != 0); // fail_if (defrag.head != NULL); (and now we may allocate it for cache) ret = gcs_defrag_handle_frag (&defrag, &frg2, &recv_act, TRUE); fail_if (ret != 0); // fail_if (defrag.head != NULL); (and now we may allocate it for cache) ret = gcs_defrag_handle_frag (&defrag, &frg3, &recv_act, TRUE); fail_if (ret != (long)act_len); // fail_if (defrag.head != NULL); (and now we may allocate it for cache) // 10. Check the action fail_if (recv_act.buf_len != (long)act_len); // fail_if (recv_act.buf != NULL); (and now we may allocate it for cache) defrag_check_init (&defrag); // should be empty // memleack in recv_act.buf ! } END_TEST Suite *gcs_defrag_suite(void) { Suite *suite = suite_create("GCS defragmenter"); TCase *tcase = tcase_create("gcs_defrag"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_defrag_test); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_defrag_test.hpp000066400000000000000000000003131244131713600243770ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_defrag_test__ #define __gcs_defrag_test__ extern Suite *gcs_defrag_suite(void); #endif /* __gu_defrag_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_fc_test.cpp000066400000000000000000000100551244131713600235360ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy // $Id$ #include "gcs_fc_test.hpp" #include "../gcs_fc.hpp" #include #include START_TEST(gcs_fc_test_limits) { gcs_fc_t fc; int ret; ret = gcs_fc_init (&fc, 16, 0.5, 0.1); fail_if (ret != 0); ret = gcs_fc_init (&fc, -1, 0.5, 0.1); fail_if (ret != -EINVAL); ret = gcs_fc_init (&fc, 16, 1.0, 0.1); fail_if (ret != -EINVAL); ret = gcs_fc_init (&fc, 16, 0.5, 1.0); fail_if (ret != -EINVAL); } END_TEST /* This is a macro to preserve line numbers in fail_if() output */ #define SKIP_N_ACTIONS(fc_,n_) \ { \ int i; \ for (i = 0; i < n_; ++i) \ { \ long long ret = gcs_fc_process (fc_, 0); \ fail_if (ret != 0, "0-sized action #%d returned %d (%s)", \ i, ret, strerror(-ret)); \ } \ } START_TEST(gcs_fc_test_basic) { gcs_fc_t fc; int ret; long long pause; ret = gcs_fc_init (&fc, 16, 0.5, 0.1); fail_if (ret != 0); gcs_fc_reset (&fc, 8); usleep (1000); SKIP_N_ACTIONS(&fc, 7); /* Here we exceed soft limit almost instantly, which should give a very high * data rate and as a result a need to sleep */ pause = gcs_fc_process (&fc, 7); fail_if(pause <= 0, "Soft limit trip returned %lld (%s)", pause, strerror(-pause)); gcs_fc_reset (&fc, 7); usleep (1000); SKIP_N_ACTIONS(&fc, 7); /* Here we reach soft limit almost instantly, which should give a very high * data rate, but soft limit is not exceeded, so no sleep yet. */ pause = gcs_fc_process (&fc, 1); fail_if(pause != 0, "Soft limit touch returned %lld (%s)", pause, strerror(-pause)); SKIP_N_ACTIONS(&fc, 7); usleep (1000); pause = gcs_fc_process (&fc, 7); fail_if(pause <= 0, "Soft limit trip returned %lld (%s)", pause, strerror(-pause)); /* hard limit excess should be detected instantly */ pause = gcs_fc_process (&fc, 1); fail_if(pause != -ENOMEM, "Hard limit trip returned %lld (%s)", pause, strerror(-pause)); } END_TEST static inline bool double_equals (double a, double b) { static double const eps = 0.001; double diff = (a - b) / (a + b); // roughly relative difference return !(diff > eps || diff < -eps); } START_TEST(gcs_fc_test_precise) { gcs_fc_t fc; long long ret; struct timespec p10ms = {0, 10000000 }; // 10 ms ret = gcs_fc_init (&fc, 2000, 0.5, 0.5); fail_if (ret != 0); gcs_fc_reset (&fc, 500); SKIP_N_ACTIONS(&fc, 7); nanosleep (&p10ms, NULL); ret = gcs_fc_process (&fc, 1000); fail_if(ret <= 0, "Soft limit trip returned %d (%s)", ret, strerror(-ret)); // measured data rate should be ~100000 b/s // slave queue length should be half-way between soft limit and hard limit // desired rate should be half between 1.0 and 0.5 of full rate -> 75000 b/s // excess over soft limit is 500 and corresponding interval: 5ms // (500/5ms == 100000 b/s) // additional sleep must be 1.6667 ms (500/(5 + 1.6667) ~ 75000 b/s) double const correction = 100000.0/fc.max_rate; // due to imprecise sleep double const expected_sleep = 0.001666667*correction; double sleep = ((double)ret)*1.0e-9; fail_if(!double_equals(sleep, expected_sleep), "Sleep: %f, expected %f", sleep, expected_sleep); } END_TEST Suite *gcs_fc_suite(void) { Suite *s = suite_create("GCS state transfer FC"); TCase *tc = tcase_create("gcs_fc"); suite_add_tcase (s, tc); tcase_add_test (tc, gcs_fc_test_limits); tcase_add_test (tc, gcs_fc_test_basic); tcase_add_test (tc, gcs_fc_test_precise); return s; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_fc_test.hpp000066400000000000000000000003001244131713600235330ustar00rootroot00000000000000// Copyright (C) 2010 Codership Oy // $Id$ #ifndef __gcs_fc_test__ #define __gcs_fc_test__ #include Suite *gcs_fc_suite(void); #endif /* __gcs_fc_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_fifo_test.cpp000066400000000000000000000057241244131713600241000ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #include #include "gcs_fifo_test.hpp" #include "../gcs_fifo_lite.hpp" #define FIFO_LENGTH 10 START_TEST (gcs_fifo_lite_test) { gcs_fifo_lite_t* fifo; long ret; long i; long* item; fifo = gcs_fifo_lite_create (0, 1); fail_if (fifo != NULL); fifo = gcs_fifo_lite_create (1, 0); fail_if (fifo != NULL); fifo = gcs_fifo_lite_create (1, 1); fail_if (fifo == NULL); ret = gcs_fifo_lite_destroy (fifo); fail_if (ret != 0, "gcs_fifo_lite_destroy() returned %d", ret); fifo = gcs_fifo_lite_create (FIFO_LENGTH, sizeof(i)); fail_if (fifo == NULL); fail_if (fifo->used != 0, "fifo->used is %z for an empty FIFO", fifo->used); gcs_fifo_lite_open (fifo); // fill FIFO for (i = 1; i <= FIFO_LENGTH; i++) { item = (long*)gcs_fifo_lite_get_tail (fifo); fail_if (NULL == item, "gcs_fifo_lite_get_tail() returned NULL"); *item = i; gcs_fifo_lite_push_tail (fifo); } fail_if (fifo->used != FIFO_LENGTH, "fifo->used is %zu, expected %zu", fifo->used, FIFO_LENGTH); // test remove for (i = 1; i <= FIFO_LENGTH; i++) { ret = gcs_fifo_lite_remove (fifo); fail_if (0 == ret, "gcs_fifo_lite_remove() failed, i = %ld", i); } fail_if (fifo->used != 0, "fifo->used is %zu, expected %zu", fifo->used, 0); // try remove on empty queue ret = gcs_fifo_lite_remove (fifo); fail_if (0 != ret, "gcs_fifo_lite_remove() from empty FIFO returned true"); // it should be possible to fill FIFO again for (i = 1; i <= FIFO_LENGTH; i++) { item = (long*)gcs_fifo_lite_get_tail (fifo); fail_if (NULL == item, "gcs_fifo_lite_get_tail() returned NULL"); *item = i; gcs_fifo_lite_push_tail (fifo); } fail_if (fifo->used != FIFO_LENGTH, "fifo->used is %zu, expected %zu", fifo->used, FIFO_LENGTH); // test get for (i = 1; i <= FIFO_LENGTH; i++) { item = (long*)gcs_fifo_lite_get_head (fifo); fail_if (NULL == item, "gcs_fifo_lite_get_head() returned NULL"); fail_if (*item != i, "gcs_fifo_lite_get_head() returned %ld, " "expected %ld", *item, i); gcs_fifo_lite_release (fifo); item = (long*)gcs_fifo_lite_get_head (fifo); fail_if (NULL == item, "gcs_fifo_lite_get_head() returned NULL"); fail_if (*item != i, "gcs_fifo_lite_get_head() returned %ld, " "expected %ld", *item, i); gcs_fifo_lite_pop_head (fifo); } fail_if (fifo->used != 0, "fifo->used for empty queue is %ld", fifo->used); ret = gcs_fifo_lite_destroy (fifo); fail_if (ret != 0, "gcs_fifo_lite_destroy() failed: %d", ret); } END_TEST Suite *gcs_fifo_suite(void) { Suite *s = suite_create("GCS FIFO functions"); TCase *tc = tcase_create("gcs_fifo"); suite_add_tcase (s, tc); tcase_add_test (tc, gcs_fifo_lite_test); return s; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_fifo_test.hpp000066400000000000000000000002641244131713600240770ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gcs_fifo_test__ #define __gcs_fifo_test__ Suite *gcs_fifo_suite(void); #endif /* __gcs_fifo_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_group_test.cpp000066400000000000000000000517521244131713600243130ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ #include #include #include #include #include #include "gcs_group_test.hpp" #include "../gcs_group.hpp" #include "../gcs_act_proto.hpp" #include "../gcs_comp_msg.hpp" #define TRUE (0 == 0) #define FALSE (!TRUE) /* * header will be written to buf from frg, act_len of payload will be copied * from act, msg structure will be filled in */ static void msg_write (gcs_recv_msg_t* msg, gcs_act_frag_t* frg, char* buf, size_t buf_len, const char* data, size_t data_len, long sender_idx, gcs_msg_type_t type) { long ret; ret = gcs_act_proto_write (frg, buf, buf_len); fail_if (ret, "error code: %d", ret); fail_if (frg->frag == NULL); fail_if (frg->frag_len < data_len, "Resulting frag_len %lu is less than required act_len %lu\n" "Refactor the test and increase buf_len.", frg->frag_len,data_len); memcpy ((void*)frg->frag, data, data_len); msg->buf = buf; msg->buf_len = buf_len; msg->size = (buf_len - frg->frag_len + data_len); msg->sender_idx = sender_idx; msg->type = type; } static long new_component (gcs_group_t* group, const gcs_comp_msg_t* comp) { long ret = gcs_group_handle_comp_msg (group, comp); // modelling real state exchange is really tedious here, just fake it // group->state = GCS_GROUP_PRIMARY; return ret; } // just pretend we received SYNC message //#define RECEIVE_SYNC() group.new_memb = FALSE; #define RECEIVE_SYNC() #define LOCALHOST "localhost" #define REMOTEHOST "remotehost" #define DISTANTHOST "distanthost" // This tests tests configuration changes START_TEST (gcs_group_configuration) { ssize_t ret; gcs_group_t group; gcs_seqno_t seqno = 1; // The Action const char act_buf[] = "Test action smuction"; ssize_t act_len = sizeof (act_buf); // lengths of three fragments of the action long frag1_len = act_len / 3; long frag2_len = frag1_len; long frag3_len = act_len - frag1_len - frag2_len; // pointer to the three fragments of the action const char* frag1 = act_buf; const char* frag2 = frag1 + frag1_len; const char* frag3 = frag2 + frag2_len; // message buffers const long buf_len = 64; char buf1[buf_len], buf2[buf_len], buf3[buf_len], buf4[buf_len], buf5[buf_len]; // recv message structures gcs_recv_msg_t msg1, msg2, msg3, msg4, msg5; gcs_act_frag_t frg1, frg2, frg3, frg4, frg5, frg; struct gcs_act_rcvd r_act; struct gcs_act* act = &r_act.act; gcs_comp_msg_t* comp; mark_point(); #ifndef NDEBUG // debug build breaks the test due to asserts return; #endif // Initialize message parameters frg1.act_id = getpid(); frg1.act_size = act_len; frg1.frag = NULL; frg1.frag_len = 0; frg1.frag_no = 0; frg1.act_type = GCS_ACT_TORDERED; frg1.proto_ver = 0; // normal fragments frg2 = frg3 = frg1; frg2.frag_no = frg1.frag_no + 1; frg3.frag_no = frg2.frag_no + 1; // bad fragmets to be tried instead of frg2 frg4 = frg5 = frg2; frg4.act_id = frg2.act_id + 1; // wrong action id frg5.act_type = GCS_ACT_SERVICE; // wrong action type mark_point(); msg_write (&msg1, &frg1, buf1, buf_len, frag1, frag1_len, 0,GCS_MSG_ACTION); msg_write (&msg2, &frg2, buf2, buf_len, frag2, frag2_len, 0,GCS_MSG_ACTION); msg_write (&msg3, &frg3, buf3, buf_len, frag3, frag3_len, 0,GCS_MSG_ACTION); msg_write (&msg4, &frg4, buf4, buf_len, "4444", 4, 0, GCS_MSG_ACTION); msg_write (&msg5, &frg5, buf5, buf_len, "55555", 5, 0, GCS_MSG_ACTION); mark_point(); // ready gcs_group_init (&group, NULL, "my node", "my addr", 0, 0, 0); fail_if (gcs_group_is_primary(&group)); fail_if (group.num != 1); // Prepare first primary component message containing only one node comp = gcs_comp_msg_new (TRUE, false, 0, 1, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0)); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (!gcs_group_new_members(&group)); RECEIVE_SYNC(); #define TRY_MESSAGE(msg) \ ret = gcs_act_proto_read (&frg, (msg).buf, (msg).size); \ ret = gcs_group_handle_act_msg (&group, &frg, &(msg), &r_act); // 1. Try fragment that is not the first memset (&r_act, 0, sizeof(r_act)); // ret = gcs_group_handle_act_msg (&group, &frg, &msg3, &r_act); TRY_MESSAGE(msg3); fail_if (ret != -EPROTO); fail_if (act->buf != NULL); fail_if (act->buf_len != 0); mark_point(); // 2. Try first fragment // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf != NULL); fail_if (act->buf_len != 0); #define TRY_WRONG_2ND_FRAGMENT(frag) \ /*ret = gcs_group_handle_act_msg (&group, &frag, &r_act);*/ \ TRY_MESSAGE(frag); \ fail_if (ret != -EPROTO); \ fail_if (act->buf_len != 0); // 3. Try first fragment again gu_debug (""); TRY_WRONG_2ND_FRAGMENT(msg1); gu_debug (""); // 4. Try third fragment TRY_WRONG_2ND_FRAGMENT(msg3); // 5. Try fouth fragment TRY_WRONG_2ND_FRAGMENT(msg4); // 6. Try fifth fragment TRY_WRONG_2ND_FRAGMENT(msg5); // 7. Try correct second fragment // ret = gcs_group_handle_act_msg (&group, &msg2, &r_act); TRY_MESSAGE(msg2); fail_if (ret != 0); fail_if (act->buf != NULL); act->buf = (void*)0x12354; // shall be NULLed fail_if (act->buf_len != 0); // 8. Try third fragment, last one // ret = gcs_group_handle_act_msg (&group, &msg3, &r_act); TRY_MESSAGE(msg3); fail_if (ret != act_len); fail_if (r_act.sender_idx != 0); fail_if (act->buf != NULL); // local action, must be fetched from local fifo fail_if (act->buf_len != act_len); fail_if (r_act.id != seqno, "Expected seqno %llu, found %llu", seqno, r_act.id); seqno++; // cleanup memset (&r_act, 0, sizeof(r_act)); // 10. New component message gcs_comp_msg_delete (comp); comp = gcs_comp_msg_new (TRUE, false, 1, 2, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, REMOTEHOST, 1) < 0); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (!gcs_group_new_members(&group)); RECEIVE_SYNC(); // 11. Try the same with foreign action (now my index is 1, sender is 0) // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); // ret = gcs_group_handle_act_msg (&group, &msg2, &r_act); TRY_MESSAGE(msg2); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); // ret = gcs_group_handle_act_msg (&group, &msg3, &r_act); TRY_MESSAGE(msg3); fail_if (ret != act_len, "Expected ret = %zd, got %zd", act_len, ret); fail_if (act->buf_len != act_len); fail_if (act->buf == NULL); fail_if (strncmp((const char*)act->buf, act_buf, act_len), "Action received: '%s', expected '%s'", act_buf); fail_if (r_act.sender_idx != 0); fail_if (act->type != GCS_ACT_TORDERED); fail_if (r_act.id != seqno, "Expected seqno %llu, found %llu", seqno, r_act.id); seqno++; // cleanup free ((void*)act->buf); memset (&r_act, 0, sizeof(r_act)); // 12. Try foreign action with a new node joined in the middle. gcs_comp_msg_delete (comp); comp = gcs_comp_msg_new (TRUE, false, 1, 3, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, REMOTEHOST, 1) < 0); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST,2) < 0); // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (!gcs_group_new_members(&group)); RECEIVE_SYNC(); // now I must be able to resend the action from scratch // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); // ret = gcs_group_handle_act_msg (&group, &msg2, &r_act); TRY_MESSAGE(msg2); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); // ret = gcs_group_handle_act_msg (&group, &msg3, &r_act); TRY_MESSAGE(msg3); fail_if (ret != act_len); fail_if (act->buf_len != act_len); fail_if (act->buf == NULL); fail_if (strncmp((const char*)act->buf, act_buf, act_len), "Action received: '%s', expected '%s'", act_buf); fail_if (r_act.sender_idx != 0); fail_if (act->type != GCS_ACT_TORDERED); fail_if (r_act.id != seqno, "Expected seqno %llu, found %llu", seqno, r_act.id); seqno++; // cleanup free ((void*)act->buf); memset (&r_act, 0, sizeof(r_act)); // 13. Try to send an action with one node disappearing in the middle // and order of nodes changed // 13.1 Each node sends a message // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); msg_write (&msg1, &frg1, buf1, buf_len, frag1, frag1_len, 1,GCS_MSG_ACTION); // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); msg_write (&msg1, &frg1, buf1, buf_len, frag1, frag1_len, 2,GCS_MSG_ACTION); // ret = gcs_group_handle_act_msg (&group, &msg1, &r_act); TRY_MESSAGE(msg1); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); // 13.2 configuration changes, one node disappears // (REMOTEHOST, LOCALHOST, DISTANTHOST) -> (LOCALHOST, REMOTEHOST) gcs_comp_msg_delete (comp); comp = gcs_comp_msg_new (TRUE, false, 0, 2, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); fail_if (gcs_comp_msg_add (comp, REMOTEHOST,1) < 0); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (gcs_group_new_members(&group), "Nodes: %d: node0 - '%s', " // "node1 - '%s'", group.num, // group.nodes[0].id, group.nodes[1].id); RECEIVE_SYNC(); gcs_comp_msg_delete (comp); return; // 13.3 now I just continue sending messages // ret = gcs_group_handle_act_msg (&group, &msg2, &r_act); // local TRY_MESSAGE(msg2); fail_if (ret != 0, "%d (%s)", ret, strerror(-ret)); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); msg_write (&msg2, &frg2, buf2, buf_len, frag2, frag2_len, 1,GCS_MSG_ACTION); // ret = gcs_group_handle_act_msg (&group, &msg2, &r_act); // foreign TRY_MESSAGE(msg2); fail_if (ret != 0); fail_if (act->buf_len != 0); fail_if (act->buf != NULL); act->buf = (void*)0x11111; // shall be NULLed below when local act is recvd // ret = gcs_group_handle_act_msg (&group, &msg3, &r_act); // local TRY_MESSAGE(msg3); fail_if (ret != act_len); fail_if (act->buf_len != act_len); fail_if (act->buf != NULL); fail_if (r_act.sender_idx != 0); fail_if (act->type != GCS_ACT_TORDERED); fail_if (r_act.id != seqno, "Expected seqno %llu, found %llu", seqno, r_act.id); seqno++; msg_write (&msg3, &frg3, buf3, buf_len, frag3, frag3_len, 1,GCS_MSG_ACTION); // ret = gcs_group_handle_act_msg (&group, &msg3, &r_act); // foreign TRY_MESSAGE(msg3); fail_if (ret != act_len); fail_if (act->buf_len != act_len); fail_if (act->buf == NULL); fail_if (strncmp((const char*)act->buf, act_buf, act_len), "Action received: '%s', expected '%s'", act_buf); fail_if (r_act.sender_idx != 1); fail_if (act->type != GCS_ACT_TORDERED); fail_if (r_act.id != seqno, "Expected seqno %llu, found %llu", seqno, r_act.id); seqno++; // cleanup free ((void*)act->buf); memset (&r_act, 0, sizeof(r_act)); // Leave group comp = gcs_comp_msg_new (FALSE, false, -1, 0, 0); fail_if (comp == NULL); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (gcs_group_is_primary(&group)); // comment until implemented: fail_if (!gcs_group_new_members(&group)); RECEIVE_SYNC(); } END_TEST static inline void group_set_last_msg (gcs_recv_msg_t* msg, gcs_seqno_t seqno) { *(gcs_seqno_t*)(msg->buf) = gcs_seqno_htog (seqno); } static inline gcs_seqno_t group_get_last_msg (gcs_recv_msg_t* msg) { return gcs_seqno_gtoh(*(gcs_seqno_t*)(msg->buf)); } // This tests last applied functionality START_TEST(gcs_group_last_applied) { long ret; gcs_group_t group; gcs_comp_msg_t* comp; gcs_recv_msg_t msg0, msg1, msg2, msg3; uint8_t buf0[sizeof(gcs_seqno_t)]; uint8_t buf1[sizeof(gcs_seqno_t)]; uint8_t buf2[sizeof(gcs_seqno_t)]; uint8_t buf3[sizeof(gcs_seqno_t)]; // set up message structures msg0.type = GCS_MSG_LAST; msg0.buf_len = sizeof(gcs_seqno_t); msg0.size = sizeof(gcs_seqno_t); msg1 = msg2 = msg3 = msg0; msg0.buf = buf0; msg1.buf = buf1; msg2.buf = buf2; msg3.buf = buf3; msg0.sender_idx = 0; msg1.sender_idx = 1; msg2.sender_idx = 2; msg3.sender_idx = 3; // Create 4-node component comp = gcs_comp_msg_new (TRUE, false, 0, 4, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); fail_if (gcs_comp_msg_add (comp, REMOTEHOST, 1) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"1",2) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"2",2) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"2",2) >= 0); gcs_group_init(&group, NULL, "", "", 0, 0, 1); mark_point(); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (!gcs_group_new_members(&group)); RECEIVE_SYNC(); // 0, 0, 0, 0 fail_if (group.last_applied != 0); group_set_last_msg (&msg0, 1); fail_if (1 != group_get_last_msg(&msg0)); gcs_group_handle_last_msg (&group, &msg0); // 1, 0, 0, 0 fail_if (group.last_applied != 0); // smallest is still 0 group_set_last_msg (&msg1, 2); gcs_group_handle_last_msg (&group, &msg1); // 1, 2, 0, 0 fail_if (group.last_applied != 0); // smallest is still 0 group_set_last_msg (&msg2, 3); gcs_group_handle_last_msg (&group, &msg2); // 1, 2, 3, 0 fail_if (group.last_applied != 0); // smallest is still 0 group_set_last_msg (&msg3, 4); gcs_group_handle_last_msg (&group, &msg3); // 1, 2, 3, 4 fail_if (group.last_applied != 1); // now must be 1 group_set_last_msg (&msg1, 6); gcs_group_handle_last_msg (&group, &msg1); // 1, 6, 3, 4 fail_if (group.last_applied != 1); // now must still be 1 group_set_last_msg (&msg0, 7); gcs_group_handle_last_msg (&group, &msg0); // 7, 6, 3, 4 fail_if (group.last_applied != 3); // now must be 3 group_set_last_msg (&msg3, 8); gcs_group_handle_last_msg (&group, &msg3); // 7, 6, 3, 8 fail_if (group.last_applied != 3); // must still be 3 // remove the lagging node gcs_comp_msg_delete(comp); comp = gcs_comp_msg_new (TRUE, false, 0, 3, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); fail_if (gcs_comp_msg_add (comp, REMOTEHOST, 1) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"2",2) < 0); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (gcs_group_new_members(&group)); RECEIVE_SYNC(); // 7, 6, 8 fail_if (group.last_applied != 6, "Expected %u, got %llu\nGroup: %d: %s, %s, %s", 6, group.last_applied, group.num, group.nodes[0].id, group.nodes[1].id,group.nodes[2].id); // add new node gcs_comp_msg_delete(comp); comp = gcs_comp_msg_new (TRUE, false, 0, 4, 0); fail_if (comp == NULL); fail_if (gcs_comp_msg_add (comp, LOCALHOST, 0) < 0); fail_if (gcs_comp_msg_add (comp, REMOTEHOST, 1) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"2",2) < 0); fail_if (gcs_comp_msg_add (comp, DISTANTHOST"1",2) < 0); ret = new_component (&group, comp); fail_if (ret < 0); // fail_if (!gcs_group_is_primary(&group)); // fail_if (!gcs_group_new_members(&group)); // 7, 6, 8, 0 fail_if (group.last_applied != 0); } END_TEST START_TEST(test_gcs_group_find_donor) { gcs_group_t group; gcs_group_init(&group, NULL, "", "", 0, 0, 0); const char* s_group_uuid = "0d0d0d0d-0d0d-0d0d-0d0d-0d0d0d0d0d0d"; gu_uuid_scan(s_group_uuid, strlen(s_group_uuid), &group.group_uuid); gu_uuid_t* group_uuid = &group.group_uuid; gu_uuid_t empty_uuid; memset(&empty_uuid, 0, sizeof(empty_uuid)); // five nodes // idx name segment seqno // 0th home0 0 90 // 1th home1 0 95 // 2th home2 0 105 // 3th home3 0(joiner)100 // 4th home4 1 90 // 5th home5 1 95 // 6th home6 1 105 const int number = 7; group.nodes = (gcs_node_t*)malloc(sizeof(gcs_node_t) * number); group.num = number; const gcs_seqno_t seqnos[] = {90, 95, 105, 100, 90, 95, 105}; gcs_node_t* nodes = group.nodes; const int joiner = 3; const gcs_seqno_t ist_seqno = 100; for(int i = 0; i < number; i++) { char name[32]; snprintf(name, sizeof(name), "home%d", i); gcs_node_init(&nodes[i], NULL, name, name, "", 0, 0, 0, i > joiner ? 1 : 0); nodes[i].status = GCS_NODE_STATE_SYNCED; nodes[i].state_msg = gcs_state_msg_create( &empty_uuid, &empty_uuid, &empty_uuid, 0, 0, seqnos[i], 0, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_SYNCED, "", "", 0, 0, 0, 0); } group.quorum.act_id = 0; // in safe range. fail_if (group.quorum.gcs_proto_ver != -1); fail_if (group.gcs_proto_ver != 0); int donor = -1; const int sv = 2; // str version. #define SARGS(s) s, strlen(s) //========== sst ========== donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home3"), &empty_uuid, GCS_SEQNO_ILL); fail_if(donor != -EHOSTDOWN); donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home1,home2"), &empty_uuid, GCS_SEQNO_ILL); fail_if(donor != 1); nodes[1].status = GCS_NODE_STATE_JOINER; donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home1,home2"), &empty_uuid, GCS_SEQNO_ILL); fail_if(donor != 2); nodes[1].status = GCS_NODE_STATE_SYNCED; // handle dangling comma. donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home3,"), &empty_uuid, GCS_SEQNO_ILL); fail_if(donor != 0); // ========== ist ========== // by name. donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home0,home1,home2"), group_uuid, ist_seqno); fail_if(donor != 1); group.quorum.act_id = 1498; // not in safe range. donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home2"), group_uuid, ist_seqno); fail_if(donor != 2); group.quorum.act_id = 1497; // in safe range. in segment. donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home2"), group_uuid, ist_seqno); fail_if(donor != 1); group.quorum.act_id = 1497; // in safe range. cross segment. nodes[0].status = GCS_NODE_STATE_JOINER; nodes[1].status = GCS_NODE_STATE_JOINER; nodes[2].status = GCS_NODE_STATE_JOINER; donor = gcs_group_find_donor(&group, sv, joiner, SARGS("home2"), group_uuid, ist_seqno); fail_if(donor != 5); nodes[0].status = GCS_NODE_STATE_SYNCED; nodes[1].status = GCS_NODE_STATE_SYNCED; nodes[2].status = GCS_NODE_STATE_SYNCED; #undef SARGS // todo: free for(int i = 0; i < number; i++) { gcs_state_msg_destroy((gcs_state_msg_t*)nodes[i].state_msg); } free(nodes); } END_TEST Suite *gcs_group_suite(void) { Suite *suite = suite_create("GCS group context"); TCase *tcase = tcase_create("gcs_group"); TCase *tcase_ignore = tcase_create("gcs_group"); suite_add_tcase (suite, tcase); tcase_add_test (tcase_ignore, gcs_group_configuration); tcase_add_test (tcase_ignore, gcs_group_last_applied); tcase_add_test (tcase, test_gcs_group_find_donor); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_group_test.hpp000066400000000000000000000003071244131713600243060ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_group_test__ #define __gcs_group_test__ extern Suite *gcs_group_suite(void); #endif /* __gu_group_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_memb_test.cpp000066400000000000000000000363731244131713600241010ustar00rootroot00000000000000/* * Copyright (C) 2011-2013 Codership Oy * * $Id$ */ #include #include "gcs_memb_test.hpp" #include "../gcs_group.hpp" #include "../gcs_comp_msg.hpp" #include #include struct node { gcs_group_t group; char id[GCS_COMP_MEMB_ID_MAX_LEN + 1]; /// ID assigned by the backend }; #define MAX_NODES 10 struct group { struct node* nodes[MAX_NODES]; int nodes_num; }; /* delivers new component message to all memebers */ static long deliver_component_msg (struct group* group, bool prim) { int i; for (i = 0; i < group->nodes_num; i++) { gcs_comp_msg_t* msg = gcs_comp_msg_new (prim, false, i, group->nodes_num, 0); if (msg) { int j; for (j = 0; j < group->nodes_num; j++) { const struct node* const node = group->nodes[j]; long ret = gcs_comp_msg_add (msg, node->id, j); fail_if (j != ret, "Failed to add %d member: %ld (%s)", j, ret, strerror(-ret)); } /* check component message */ fail_if (i != gcs_comp_msg_self(msg)); fail_if (group->nodes_num != gcs_comp_msg_num(msg)); for (j = 0; j < group->nodes_num; j++) { const char* const src_id = group->nodes[j]->id; const char* const dst_id = gcs_comp_msg_member(msg, j)->id; fail_if (strcmp(src_id, dst_id), "%d node id %s, recorded in comp msg as %s", j, src_id, dst_id); // gcs_segment_t const src_seg = group->nodes[j]->segment; gcs_segment_t const dst_seg = gcs_comp_msg_member(msg, j)->segment; fail_if (j != dst_seg, "%d node segment %d, recorded in comp msg as %d", j, j, (int)dst_seg); } gcs_group_state_t ret = gcs_group_handle_comp_msg (&(group->nodes[i]->group), msg); fail_if (ret != GCS_GROUP_WAIT_STATE_UUID); gcs_comp_msg_delete (msg); /* check that uuids are properly recorded in internal structures */ for (j = 0; j < group->nodes_num; j++) { const char* src_id = group->nodes[j]->id; const char* dst_id = group->nodes[i]->group.nodes[j].id; fail_if (strcmp(src_id, dst_id), "%d node id %s, recorded at node %d as %s", j, src_id, i, dst_id); } } else { return -ENOMEM; } } return 0; } #if 0 static long group_send_msg (struct group* group, gcs_group_t* node, const void* msg, ssize_t msg_len) { return 0; } #endif static long perform_state_exchange (struct group* group) { /* first deliver state uuid message */ gu_uuid_t state_uuid; gu_uuid_generate (&state_uuid, NULL, 0); gcs_recv_msg_t uuid_msg(&state_uuid, sizeof (state_uuid), sizeof (state_uuid), 0, GCS_MSG_STATE_UUID); gcs_group_state_t state; int i; for (i = 0; i < group->nodes_num; i++) { state = gcs_group_handle_uuid_msg (&(group->nodes[i]->group),&uuid_msg); fail_if (state != GCS_GROUP_WAIT_STATE_MSG, "Wrong group state after STATE_UUID message. " "Expected: %d, got: %d", GCS_GROUP_WAIT_STATE_MSG, state); } /* complete state message exchange */ for (i = 0; i < group->nodes_num; i++) { /* create state message from node i */ gcs_state_msg_t* state = gcs_group_get_state (&(group->nodes[i]->group)); fail_if (NULL == state); ssize_t state_len = gcs_state_msg_len (state); uint8_t state_buf[state_len]; gcs_state_msg_write (state_buf, state); gcs_recv_msg_t state_msg(state_buf, sizeof (state_buf), sizeof (state_buf), i, GCS_MSG_STATE_MSG); /* deliver to each of the nodes */ int j; for (j = 0; j < group->nodes_num; j++) { gcs_group_state_t ret = gcs_group_handle_state_msg (&(group->nodes[j]->group), &state_msg); if (group->nodes_num - 1 == i) { // a message from the last node fail_if (ret != GCS_GROUP_PRIMARY, "Handling state msg failed: sender %d, receiver %d", i, j); } else { fail_if (ret != GCS_GROUP_WAIT_STATE_MSG, "Handling state msg failed: sender %d, receiver %d", i, j); } } gcs_state_msg_destroy (state); } return 0; } static long group_add_node (struct group* group, struct node* node, bool new_id) { if (new_id) { gu_uuid_t node_uuid; gu_uuid_generate (&node_uuid, NULL, 0); gu_uuid_print (&node_uuid, (char*)node->id, sizeof (node->id)); gu_debug ("Node %d (%p) UUID: %s", group->nodes_num, node, node->id); } group->nodes[group->nodes_num] = node; group->nodes_num++; /* check that all node ids are different */ int i; for (i = 0; i < group->nodes_num; i++) { int j; for (j = i+1; j < group->nodes_num; j++) { fail_if (!strcmp (group->nodes[i]->id, group->nodes[j]->id), "%d (%p) and %d (%p) have the same id: %s/%s", i, group->nodes[i], j,group->nodes[j], group->nodes[i]->id, group->nodes[j]->id); } } /* deliver new component message to all nodes */ long ret = deliver_component_msg (group, true); fail_if (ret != 0, "Component message delivery failed: %d (%s)", ret, strerror(-ret)); /* deliver state exchange uuid */ ret = perform_state_exchange (group); fail_if (ret != 0, "State exchange failed: %d (%s)", ret, strerror(-ret)); return 0; } /* NOTE: this function uses simplified and determinitstic algorithm where * dropped node is always replaced by the last one in group. * For our purposes (reproduction of #465) it fits perfectly. */ static struct node* group_drop_node (struct group* group, int idx) { struct node* dropped = group->nodes[idx]; group->nodes[idx] = group->nodes[group->nodes_num - 1]; group->nodes[group->nodes_num - 1] = NULL; group->nodes_num--; if (group->nodes_num > 0) { deliver_component_msg (group, true); perform_state_exchange (group); } return dropped; } static gcs_node_state_t get_node_state (struct node* node) { return node->group.nodes[node->group.my_idx].status; } /* for delivery of GCS_MSG_SYNC or GCS_MSG_JOIN msg*/ static long deliver_join_sync_msg (struct group* const group, int const src, gcs_msg_type_t type) { gcs_seqno_t seqno = group->nodes[src]->group.act_id; gcs_recv_msg_t msg(&seqno, sizeof (seqno), sizeof (seqno), src, type); long ret = -1; int i; for (i = 0; i < group->nodes_num; i++) { gcs_group_t* const gr = &group->nodes[i]->group; switch (type) { case GCS_MSG_JOIN: ret = gcs_group_handle_join_msg(gr, &msg); if (i == src) { fail_if (ret != 1, "%d failed to handle own JOIN message: %d (%s)", i, ret, strerror (-ret)); } else { fail_if (ret != 0, "%d failed to handle other JOIN message: %d (%s)", i, ret, strerror (-ret)); } break; case GCS_MSG_SYNC: ret = gcs_group_handle_sync_msg(gr, &msg); if (i == src) { fail_if (ret != 1 && gr->nodes[src].status == GCS_NODE_STATE_JOINED, "%d failed to handle own SYNC message: %d (%s)", i, ret, strerror (-ret)); } else { fail_if (ret != 0, "%d failed to handle other SYNC message: %d (%s)", i, ret, strerror (-ret)); } break; default: fail ("wrong message type: %d", type); } } return ret; } static bool verify_node_state_across_group (struct group* group, int const idx, gcs_node_state_t const check) { bool ret = false; int i; for (i = 0; i < group->nodes_num; i++) { gcs_node_state_t state = group->nodes[i]->group.nodes[idx].status; if (check != state) { gu_error("At node %d node's %d status is not %d, but %d", i, idx, check, state); ret = true; } } return ret; } /* start SST on behald of node idx (joiner) */ static long group_sst_start (struct group* group, int const src_idx, const char* donor) { ssize_t const req_len = strlen (donor) + 2; // leave one byte as sst request payload int donor_idx = -1; int i; for (i = 0; i < group->nodes_num; i++) { // sst request is expected to be dynamically allocated char* req_buf = (char*)malloc (req_len); fail_if (NULL == req_buf); sprintf (req_buf, "%s", donor); struct gcs_act_rcvd req( gcs_act(req_buf, req_len, GCS_ACT_STATE_REQ), NULL, GCS_SEQNO_ILL, src_idx); long ret; ret = gcs_group_handle_state_request (&group->nodes[i]->group, &req); if (ret < 0) { // don't fail here, we may want to test negatives gu_error (ret < 0, "Handling state request to '%s' failed: %d (%s)", donor, ret, strerror (-ret)); return ret; } if (i == src_idx) { fail_if (ret != req_len); free (req_buf); // passed to joiner } else { if (ret > 0) { if (donor_idx < 0) { fail_if (req.id != i); donor_idx = i; free (req_buf); // passed to donor } else { fail ("More than one donor selected: %d, first donor: %d", i, donor_idx); } } } } fail_if (donor_idx < 0, "Failed to select donor"); for (i = 0; i < group->nodes_num; i++) { gcs_node_state_t state; gcs_group_t* gr = &group->nodes[i]->group; state = gr->nodes[donor_idx].status; fail_if (state != GCS_NODE_STATE_DONOR, "%d is not donor at %d", donor_idx, i); state = gr->nodes[src_idx].status; fail_if (state != GCS_NODE_STATE_JOINER, "%d is not joiner at %d", src_idx, i); /* check that donor and joiner point at each other */ fail_if (memcmp (gr->nodes[donor_idx].joiner, gr->nodes[src_idx].id, GCS_COMP_MEMB_ID_MAX_LEN+1), "Donor points at wrong joiner: expected %s, got %s", gr->nodes[src_idx].id, gr->nodes[donor_idx].joiner); fail_if (memcmp (gr->nodes[src_idx].donor, gr->nodes[donor_idx].id, GCS_COMP_MEMB_ID_MAX_LEN+1), "Joiner points at wrong donor: expected %s, got %s", gr->nodes[donor_idx].id, gr->nodes[src_idx].donor); } return 0; } /* Thes test was specifically created to reproduce #465 */ START_TEST(gcs_memb_test_465) { struct group group; group.nodes_num = 0; struct node nodes[MAX_NODES]; int i; ssize_t ret = 0; // initialize individual node structures for (i = 0; i < MAX_NODES; i++) { int const str_len = 32; char name_str[str_len]; char addr_str[str_len]; sprintf(name_str, "node%d", i); sprintf(addr_str, "addr%d", i); gcs_group_init (&nodes[i].group, NULL, name_str, addr_str, 0, 0, 0); } gcs_node_state_t node_state; // bootstrap the cluster group_add_node (&group, &nodes[0], true); fail_if (nodes[0].group.state != GCS_GROUP_PRIMARY); node_state = get_node_state (&nodes[0]); fail_if (node_state != GCS_NODE_STATE_JOINED); deliver_join_sync_msg (&group, 0, GCS_MSG_SYNC); node_state = get_node_state (&nodes[0]); fail_if (node_state != GCS_NODE_STATE_SYNCED); group_add_node (&group, &nodes[1], true); fail_if (nodes[1].group.state != GCS_GROUP_PRIMARY); node_state = get_node_state (&nodes[1]); fail_if (node_state != GCS_NODE_STATE_PRIM); // need sst group_add_node (&group, &nodes[2], true); fail_if (nodes[2].group.state != GCS_GROUP_PRIMARY); node_state = get_node_state (&nodes[2]); fail_if (node_state != GCS_NODE_STATE_PRIM); // need sst fail_if (verify_node_state_across_group (&group, 0, GCS_NODE_STATE_SYNCED)); group_sst_start (&group, 2, nodes[0].group.nodes[0].name); deliver_join_sync_msg (&group, 0, GCS_MSG_JOIN); // end of donor SST deliver_join_sync_msg (&group, 0, GCS_MSG_SYNC); // donor synced deliver_join_sync_msg (&group, 2, GCS_MSG_SYNC); // joiner can't sync fail_if (verify_node_state_across_group (&group, 2, GCS_NODE_STATE_JOINER)); deliver_join_sync_msg (&group, 2, GCS_MSG_JOIN); // end of joiner SST deliver_join_sync_msg (&group, 2, GCS_MSG_SYNC); // joiner synced fail_if (verify_node_state_across_group (&group, 0, GCS_NODE_STATE_SYNCED)); fail_if (verify_node_state_across_group (&group, 1, GCS_NODE_STATE_PRIM)); fail_if (verify_node_state_across_group (&group, 2, GCS_NODE_STATE_SYNCED)); group_sst_start (&group, 1, nodes[0].group.nodes[0].name); deliver_join_sync_msg (&group, 0, GCS_MSG_JOIN); // end of donor SST deliver_join_sync_msg (&group, 1, GCS_MSG_JOIN); // end of joiner SST struct node* dropped = group_drop_node (&group, 1); fail_if (NULL == dropped); /* After that, according to #465, node 1 shifted from SYNCED to PRIMARY */ fail_if (verify_node_state_across_group (&group, 1, GCS_NODE_STATE_SYNCED)); struct gcs_act act; int proto_ver = -1; ret = gcs_group_act_conf (&group.nodes[1]->group, &act, &proto_ver); fail_if (ret <= 0, "gcs_group_act_cnf() retruned %zd (%s)", ret, strerror (-ret)); fail_if (ret != act.buf_len); fail_if (proto_ver != 0 /* current version */, "proto_ver = %d", proto_ver); const gcs_act_conf_t* conf = (const gcs_act_conf_t*)act.buf; fail_if (NULL == conf); fail_if (conf->my_idx != 1); /* according to #465 this was GCS_NODE_STATE_PRIM */ fail_if (conf->my_state != GCS_NODE_STATE_SYNCED); deliver_join_sync_msg (&group, 0, GCS_MSG_SYNC); // donor synced fail_if (verify_node_state_across_group (&group, 0, GCS_NODE_STATE_SYNCED)); } END_TEST Suite *gcs_memb_suite(void) { Suite *suite = suite_create("GCS membership changes"); TCase *tcase = tcase_create("gcs_memb"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_memb_test_465); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_memb_test.hpp000066400000000000000000000003041244131713600240670ustar00rootroot00000000000000/* * Copyright (C) 2011 Codership Oy * * $Id$ */ #ifndef __gcs_memb_test__ #define __gcs_memb_test__ extern Suite *gcs_memb_suite(void); #endif /* __gu_group_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_node_test.cpp000066400000000000000000000032161244131713600240740ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include #include "gcs_node_test.hpp" #include "../gcs_node.hpp" #define NODE_ID "owpiefd[woie" #define NODE_NAME "strange name" #define NODE_ADDR "0.0.0.0:0" START_TEST (gcs_node_test) { /* this is a small unit test as node unit does almost nothing */ gcs_node_t node1, node2; static const gcs_seqno_t seqno = 333; gcs_node_init (&node1, NULL, NODE_ID, NODE_NAME, NODE_ADDR, 0, 0, 0, 0); gcs_node_init (&node2, NULL, "baka", NULL, NULL, 0, 0, 0, 0); fail_if (strcmp(node1.id, NODE_ID), "Expected node id '%s', found '%s'", NODE_ID, node1.id); fail_if (strcmp(node1.name, NODE_NAME), "Expected node name '%s', " "found '%s'", NODE_NAME, node1.name); fail_if (strcmp(node1.inc_addr, NODE_ADDR), "Expected node id '%s', " "found '%s'", NODE_ADDR, node1.inc_addr); fail_if (gcs_node_get_last_applied(&node1)); gcs_node_set_last_applied (&node1, seqno); mark_point(); gcs_node_move (&node2, &node1); fail_if (seqno != gcs_node_get_last_applied (&node2), "move didn't preserve last_applied"); fail_if (strcmp(node2.id, NODE_ID), "Expected node id '%s', found '%s'", NODE_ID, node2.id); gcs_node_reset (&node1); mark_point(); gcs_node_free (&node2); } END_TEST Suite *gcs_node_suite(void) { Suite *suite = suite_create("GCS node context"); TCase *tcase = tcase_create("gcs_node"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_node_test); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_node_test.hpp000066400000000000000000000003031244131713600240730ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_node_test__ #define __gcs_node_test__ extern Suite *gcs_node_suite(void); #endif /* __gu_node_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_proto_test.cpp000066400000000000000000000074411244131713600243160ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #include #include #include #include "../gcs_act_proto.hpp" #include "gcs_proto_test.hpp" static long frgcmp (gcs_act_frag_t* f1, gcs_act_frag_t* f2) { if ( (f1->act_id == f2->act_id) && (f1->act_size == f2->act_size) && (f1->act_type == f2->act_type) && (f1->frag_len == f2->frag_len) && // expect to point (f1->frag == f2->frag) // at the same buffer here ) return 0; else return -1; } START_TEST (gcs_proto_test) { const char act_send[] = "Test action smuction"; const char* act_send_ptr = act_send; char act_recv[] = "owoeijrvfokpvfcsdnfvkmk;l"; char* act_recv_ptr = act_recv; const size_t buf_len = 32; char buf[buf_len]; gcs_act_frag_t frg_send, frg_recv; long ret; frg_send.act_id = getpid(); frg_send.act_size = strlen (act_send); frg_send.frag = NULL; frg_send.frag_len = 0; frg_send.frag_no = 0; frg_send.act_type = (gcs_act_type_t)0; frg_send.proto_ver = 0; // set up action header ret = gcs_act_proto_write (&frg_send, buf, buf_len); fail_if (ret, "error code: %d", ret); fail_if (frg_send.frag == NULL); fail_if (frg_send.frag_len == 0); fail_if (strlen(act_send) < frg_send.frag_len, "Expected fragmentation, but action seems to fit in buffer" " - increase send action length"); // write action to the buffer, it should not fit strncpy ((char*)frg_send.frag, act_send_ptr, frg_send.frag_len); act_send_ptr += frg_send.frag_len; // message was sent and received, now parse the header ret = gcs_act_proto_read (&frg_recv, buf, buf_len); fail_if (ret, "error code: %d", ret); fail_if (frg_recv.frag == NULL); fail_if (frg_recv.frag_len == 0); fail_if (frgcmp (&frg_send, &frg_recv), "Sent and recvd headers are not identical"); fail_if (frg_send.frag_no != frg_recv.frag_no, "Fragment numbers are not identical: %d %d", frg_send.frag_no, frg_recv.frag_no); // read the fragment into receiving action buffer // FIXME: this works by sheer luck - only because strncpy() pads // the remaining buffer space with 0 strncpy (act_recv_ptr, (const char*)frg_recv.frag, frg_recv.frag_len); act_recv_ptr += frg_recv.frag_len; // send the second fragment. Increment the fragment counter gcs_act_proto_inc (buf); // should be 1 now // write action to the buffer, it should fit now strncpy ((char*)frg_send.frag, act_send_ptr, frg_send.frag_len); // act_send_ptr += frg_send.frag_len; // message was sent and received, now parse the header ret = gcs_act_proto_read (&frg_recv, buf, buf_len); fail_if (ret, "error code: %d", ret); fail_if (frgcmp (&frg_send, &frg_recv), "Sent and recvd headers are not identical"); fail_if (frg_send.frag_no + 1 != frg_recv.frag_no, "Fragment numbers are not sequential: %d %d", frg_send.frag_no, frg_recv.frag_no); // read the fragment into receiving action buffer // FIXME: this works by sheer luck - only because strncpy() pads // the remaining buffer space with 0 strncpy (act_recv_ptr, (const char*)frg_recv.frag, frg_recv.frag_len); fail_if (strlen(act_recv_ptr) >= frg_send.frag_len, "Fragment does not seem to fit in buffer: '%s'(%d)", strlen(act_recv_ptr), act_recv_ptr); // check that actions are identical fail_if (strcmp(act_send, act_recv), "Actions don't match: '%s' -- '%s'", act_send, act_recv); } END_TEST Suite *gcs_proto_suite(void) { Suite *suite = suite_create("GCS core protocol"); TCase *tcase = tcase_create("gcs_proto"); suite_add_tcase (suite, tcase); tcase_add_test (tcase, gcs_proto_test); return suite; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_proto_test.hpp000066400000000000000000000003071244131713600243150ustar00rootroot00000000000000/* * Copyright (C) 2008 Codership Oy * * $Id$ */ #ifndef __gcs_proto_test__ #define __gcs_proto_test__ extern Suite *gcs_proto_suite(void); #endif /* __gu_proto_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_sm_test.cpp000066400000000000000000000367121244131713600235750ustar00rootroot00000000000000// Copyright (C) 2010-2013 Codership Oy // $Id$ #include "../gcs_sm.hpp" #include #include #include "gcs_sm_test.hpp" #define TEST_USLEEP 10000 /* we can't use pthread functions for waiting for certain conditions */ #define WAIT_FOR(cond) \ { int count = 1000; while (--count && !(cond)) { usleep (1000); }} START_TEST (gcs_sm_test_basic) { int ret; gcs_sm_t* sm = gcs_sm_create(2, 1); fail_if(!sm); gu_cond_t cond; gu_cond_init (&cond, NULL); int i; for (i = 1; i < 5; i++) { ret = gcs_sm_enter(sm, &cond, false, true); fail_if(ret, "gcs_sm_enter() failed: %d (%s)", ret, strerror(-ret)); fail_if(sm->users != 1, "users = %ld, expected 1", sm->users); fail_if(sm->entered != 1, "entered = %d, expected 1", sm->entered); gcs_sm_leave(sm); fail_if(sm->entered != 0, "entered = %d, expected %d", sm->entered, 0); } ret = gcs_sm_close(sm); fail_if(ret); gcs_sm_destroy(sm); gu_cond_destroy(&cond); } END_TEST volatile long simple_ret; static void* simple_thread(void* arg) { gcs_sm_t* sm = (gcs_sm_t*) arg; gu_cond_t cond; gu_cond_init (&cond, NULL); if (0 == (simple_ret = gcs_sm_enter (sm, &cond, false, true))) { usleep(1000); gcs_sm_leave (sm); } gu_cond_destroy (&cond); return NULL; } START_TEST (gcs_sm_test_simple) { int ret; gcs_sm_t* sm = gcs_sm_create(4, 1); fail_if(!sm); gu_cond_t cond; gu_cond_init (&cond, NULL); ret = gcs_sm_enter(sm, &cond, false, true); fail_if(ret, "gcs_sm_enter() failed: %d (%s)", ret, strerror(-ret)); fail_if(sm->users != 1, "users = %ld, expected 1", sm->users); fail_if(sm->entered != true, "entered = %d, expected %d", sm->users, true); gu_thread_t t1, t2, t3, t4; gu_thread_create (&t1, NULL, simple_thread, sm); gu_thread_create (&t2, NULL, simple_thread, sm); gu_thread_create (&t3, NULL, simple_thread, sm); WAIT_FOR ((long)sm->wait_q_len == sm->users); fail_if((long)sm->wait_q_len != sm->users, "wait_q_len = %lu, users = %ld", sm->wait_q_len, sm->users); gu_thread_create (&t4, NULL, simple_thread, sm); mark_point(); gu_thread_join (t4, NULL); // there's no space in the queue fail_if (simple_ret != -EAGAIN); fail_if (0 != sm->wait_q_tail, "wait_q_tail = %lu, expected 0", sm->wait_q_tail); fail_if (1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); fail_if (4 != sm->users, "users = %lu, expected 4", sm->users); gu_info ("Calling gcs_sm_leave()"); gcs_sm_leave(sm); fail_unless(4 > sm->users, "users = %lu, expected 4", sm->users); gu_info ("Calling gcs_sm_close()"); ret = gcs_sm_close(sm); fail_if(ret); gu_thread_join(t1, NULL); gu_thread_join(t2, NULL); gu_thread_join(t3, NULL); gcs_sm_destroy(sm); gu_cond_destroy(&cond); } END_TEST static volatile int order = 0; // global variable to trac the order of events static void* closing_thread (void* data) { gcs_sm_t* sm = (gcs_sm_t*)data; fail_if(order != 0, "order is %d, expected 0", order); order = 1; int ret = gcs_sm_close(sm); fail_if(ret); fail_if(order != 2, "order is %d, expected 2", order); gcs_sm_destroy(sm); return NULL; } START_TEST (gcs_sm_test_close) { order = 0; gcs_sm_t* sm = gcs_sm_create(2, 1); fail_if(!sm); gu_cond_t cond; gu_cond_init (&cond, NULL); int ret = gcs_sm_enter(sm, &cond, false, true); fail_if(ret, "gcs_sm_enter() failed: %d (%s)", ret, strerror(-ret)); fail_if(sm->users != 1, "users = %ld, expected 1", sm->users); fail_if(order != 0); fail_if(1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); fail_if(1 != sm->wait_q_tail, "wait_q_tail = %lu, expected 1", sm->wait_q_tail); gu_thread_t thr; gu_thread_create (&thr, NULL, closing_thread, sm); WAIT_FOR(1 == order); fail_if(order != 1, "order is %d, expected 1", order); usleep(TEST_USLEEP); // make sure closing_thread() blocks in gcs_sm_close() fail_if(sm->users != 2, "users = %ld, expected 2", sm->users); gu_info ("Started close thread, users = %ld", sm->users); fail_if(1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); fail_if(0 != sm->wait_q_tail, "wait_q_tail = %lu, expected 0", sm->wait_q_tail); fail_if(1 != sm->entered); order = 2; gcs_sm_leave(sm); mark_point(); gu_thread_join(thr, NULL); gu_cond_destroy(&cond); } END_TEST static volatile int pause_order = 0; static void* pausing_thread (void* data) { gu_info ("pausing_thread start, pause_order = %d", pause_order); gcs_sm_t* sm = (gcs_sm_t*)data; gu_cond_t cond; gu_cond_init (&cond, NULL); gcs_sm_schedule (sm); gu_info ("pausing_thread scheduled, pause_order = %d", pause_order); fail_if (pause_order != 0, "pause_order = %d, expected 0"); pause_order = 1; gcs_sm_enter (sm, &cond, true, true); gu_info ("pausing_thread entered, pause_order = %d", pause_order); fail_if (pause_order != 2, "pause_order = %d, expected 2"); pause_order = 3; usleep(TEST_USLEEP); gcs_sm_leave (sm); mark_point(); gu_cond_destroy(&cond); gu_info ("pausing_thread exit, pause_order = %d", pause_order); return NULL; } START_TEST (gcs_sm_test_pause) { int q_len; int q_len_max; int q_len_min; double q_len_avg; long long paused_ns; double paused_avg; gcs_sm_t* sm = gcs_sm_create(4, 1); fail_if(!sm); fail_if(1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); gu_cond_t cond; gu_cond_init (&cond, NULL); gu_thread_t thr; gcs_sm_stats_get (sm, &q_len, &q_len_max, &q_len_min, &q_len_avg, &paused_ns, &paused_avg); fail_if (paused_ns != 0.0); fail_if (paused_avg != 0.0); fail_if (q_len_avg != 0.0); fail_if (q_len != 0); fail_if (q_len_max != 0); fail_if (q_len_min != 0); // Test attempt to enter paused monitor pause_order = 0; gcs_sm_pause (sm); gu_thread_create (&thr, NULL, pausing_thread, sm); WAIT_FOR(1 == pause_order); fail_if (pause_order != 1, "pause_order = %d, expected 1"); usleep(TEST_USLEEP); // make sure pausing_thread blocked in gcs_sm_enter() pause_order = 2; // testing taking stats in the middle of the pause pt. 1 gcs_sm_stats_get (sm, &q_len, &q_len_max, &q_len_min, &q_len_avg, &paused_ns, &paused_avg); fail_if (paused_ns <= 0.0); fail_if (paused_avg <= 0.0); fail_if (q_len_avg != 0.0); gu_info ("Calling gcs_sm_continue()"); gcs_sm_continue (sm); gu_thread_join (thr, NULL); fail_if (pause_order != 3, "pause_order = %d, expected 3"); fail_if(2 != sm->wait_q_head, "wait_q_head = %lu, expected 2", sm->wait_q_head); fail_if(1 != sm->wait_q_tail, "wait_q_tail = %lu, expected 1", sm->wait_q_tail); // testing taking stats in the middle of the pause pt. 2 long long tmp; gcs_sm_stats_get (sm, &q_len, &q_len_max, &q_len_min, &q_len_avg, &tmp, &paused_avg); fail_if (tmp <= paused_ns); paused_ns = tmp; fail_if (paused_avg <= 0.0); fail_if (q_len_avg != 0.0); gcs_sm_stats_flush(sm); // Testing scheduling capability gcs_sm_schedule (sm); fail_if(2 != sm->wait_q_tail, "wait_q_tail = %lu, expected 2", sm->wait_q_tail); gu_thread_create (&thr, NULL, pausing_thread, sm); usleep (TEST_USLEEP); // no changes in pause_order fail_if (pause_order != 3, "pause_order = %d, expected 3"); pause_order = 0; int ret = gcs_sm_enter(sm, &cond, true, true); fail_if (ret, "gcs_sm_enter() failed: %d (%s)", ret, strerror(-ret)); // released monitor lock, thr should continue and schedule, // set pause_order to 1 WAIT_FOR(1 == pause_order); fail_if (pause_order != 1, "pause_order = %d, expected 1"); fail_if (sm->users != 2, "users = %ld, expected 2", sm->users); fail_if(2 != sm->wait_q_head, "wait_q_head = %lu, expected 2", sm->wait_q_head); fail_if(3 != sm->wait_q_tail, "wait_q_tail = %lu, expected 3", sm->wait_q_tail); gcs_sm_stats_get (sm, &q_len, &q_len_max, &q_len_min, &q_len_avg, &tmp, &paused_avg); fail_if (tmp < paused_ns); paused_ns = tmp; fail_if (paused_avg != 0.0); fail_if (q_len != sm->users, "found q_len %d, expected = %d", q_len, sm->users); fail_if (q_len_max != q_len, "found q_len_max %d, expected = %d", q_len_max, q_len); fail_if (q_len_min != 0, "found q_len_min %d, expected = 0", q_len_min); fail_if ((q_len_avg - 0.5) > 0.0000001 || (q_len_avg - 0.5) < -0.0000001); gcs_sm_stats_flush(sm); gu_info ("Started pause thread, users = %ld", sm->users); // Now test pausing when monitor is in entered state pause_order = 2; gcs_sm_pause (sm); usleep (TEST_USLEEP); gcs_sm_continue (sm); // nothing should continue, since monitor is entered usleep (TEST_USLEEP); fail_if (pause_order != 2, "pause_order = %d, expected 2"); fail_if (sm->entered != 1, "entered = %ld, expected 1", sm->entered); // Now test pausing when monitor is left gcs_sm_pause (sm); fail_if (sm->users != 2, "users = %ld, expected 2", sm->users); gcs_sm_leave (sm); fail_if (sm->users != 1, "users = %ld, expected 1", sm->users); fail_if (sm->entered != 0, "entered = %ld, expected 1", sm->entered); fail_if(3 != sm->wait_q_head, "wait_q_head = %lu, expected 3", sm->wait_q_head); fail_if(3 != sm->wait_q_tail, "wait_q_tail = %lu, expected 3", sm->wait_q_tail); usleep (TEST_USLEEP); // nothing should change, since monitor is paused fail_if (pause_order != 2, "pause_order = %d, expected 2"); fail_if (sm->entered != 0, "entered = %ld, expected 0", sm->entered); fail_if (sm->users != 1, "users = %ld, expected 1", sm->users); gcs_sm_continue (sm); // paused thread should continue WAIT_FOR(3 == pause_order); fail_if (pause_order != 3, "pause_order = %d, expected 3"); gcs_sm_stats_get (sm, &q_len, &q_len_max, &q_len_min, &q_len_avg, &tmp, &paused_avg); fail_if (tmp <= paused_ns); paused_ns = tmp; fail_if (paused_avg <= 0.0); fail_if (q_len_avg != 0.0); gcs_sm_enter (sm, &cond, false, true); // by now paused thread exited monitor fail_if (sm->entered != 1, "entered = %ld, expected 1", sm->entered); fail_if (sm->users != 1, "users = %ld, expected 1", sm->users); fail_if(0 != sm->wait_q_head, "wait_q_head = %lu, expected 0", sm->wait_q_head); fail_if(0 != sm->wait_q_tail, "wait_q_tail = %lu, expected 0", sm->wait_q_tail); gcs_sm_leave (sm); fail_if(1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); mark_point(); gu_cond_destroy(&cond); gcs_sm_close (sm); mark_point(); gu_thread_join(thr, NULL); gcs_sm_destroy (sm); } END_TEST static volatile long global_handle = 0; static volatile long global_ret = 0; static void* interrupt_thread(void* arg) { gcs_sm_t* sm = (gcs_sm_t*) arg; global_handle = gcs_sm_schedule (sm); if (global_handle >= 0) { pthread_cond_t cond; pthread_cond_init (&cond, NULL); if (0 == (global_ret = gcs_sm_enter (sm, &cond, true, true))) { gcs_sm_leave (sm); } pthread_cond_destroy (&cond); } return NULL; } #define TEST_CREATE_THREAD(thr, tail, h, u) \ global_handle = -1; \ gu_thread_create (thr, NULL, interrupt_thread, sm); \ WAIT_FOR(global_handle == h); \ fail_if (sm->wait_q_tail != tail, "wait_q_tail = %lu, expected %lu", \ sm->wait_q_tail, tail); \ fail_if (global_handle != h, "global_handle = %ld, expected %ld", \ global_handle, h); \ fail_if (sm->users != u, "users = %ld, expected %ld", sm->users, u); #define TEST_INTERRUPT_THREAD(h, t) \ ret = gcs_sm_interrupt (sm, (h)); \ fail_if (ret != 0); \ gu_thread_join ((t), NULL); \ fail_if (global_ret != -EINTR, "global_ret = %ld, expected %ld (-EINTR)", \ global_ret, -EINTR); START_TEST (gcs_sm_test_interrupt) { gcs_sm_t* sm = gcs_sm_create(4, 1); fail_if(!sm); gu_cond_t cond; gu_cond_init (&cond, NULL); gu_thread_t thr1; gu_thread_t thr2; gu_thread_t thr3; long handle = gcs_sm_schedule (sm); fail_if (handle != 0, "handle = %ld, expected 0"); fail_if (sm->wait_q_tail != 1, "wait_q_tail = %lu, expected 1", sm->wait_q_tail); long ret = gcs_sm_enter (sm, &cond, true, true); fail_if (ret != 0); /* 1. Test interrupting blocked by previous thread */ TEST_CREATE_THREAD(&thr1, 2, 3, 2); TEST_CREATE_THREAD(&thr2, 3, 4, 3); TEST_INTERRUPT_THREAD(3, thr1); gcs_sm_leave (sm); // this should let 2nd enter monitor gu_thread_join (thr2, NULL); fail_if (global_ret != 0, "global_ret = %ld, expected 0", global_ret); fail_if (sm->users != 0, "users = %ld, expected 0", sm->users); ret = gcs_sm_interrupt (sm, 4); // try to interrupt 2nd which has exited fail_if (ret != -ESRCH); /* 2. Test interrupting blocked by pause */ gcs_sm_pause (sm); TEST_CREATE_THREAD(&thr1, 0, 1, 1); TEST_INTERRUPT_THREAD(1, thr1); TEST_CREATE_THREAD(&thr2, 1, 2, 2); /* test queueing after interrupted */ TEST_CREATE_THREAD(&thr3, 2, 3, 3); TEST_INTERRUPT_THREAD(3, thr3); /* test interrupting last waiter */ gcs_sm_continue (sm); gu_thread_join (thr2, NULL); fail_if (global_ret != 0, "global_ret = %ld, expected 0", global_ret); /* 3. Unpausing totally interrupted monitor */ gcs_sm_pause (sm); TEST_CREATE_THREAD(&thr1, 3, 4, 1); TEST_INTERRUPT_THREAD(4, thr1); TEST_CREATE_THREAD(&thr1, 0, 1, 2); TEST_INTERRUPT_THREAD(1, thr1); gcs_sm_continue (sm); /* check that monitor is still functional */ ret = gcs_sm_enter (sm, &cond, false, true); fail_if (ret != 0); fail_if(1 != sm->wait_q_head, "wait_q_head = %lu, expected 1", sm->wait_q_head); fail_if(1 != sm->wait_q_tail, "wait_q_tail = %lu, expected 1", sm->wait_q_tail); fail_if (sm->users != 1, "users = %ld, expected 1", sm->users); TEST_CREATE_THREAD(&thr1, 2, 3, 2); gu_info ("Calling gcs_sm_leave()"); gcs_sm_leave (sm); pthread_join (thr1, NULL); fail_if (global_ret != 0, "global_ret = %ld, expected 0", global_ret); pthread_cond_destroy (&cond); gcs_sm_close (sm); gcs_sm_destroy (sm); } END_TEST Suite *gcs_send_monitor_suite(void) { Suite *s = suite_create("GCS send monitor"); TCase *tc = tcase_create("gcs_sm"); suite_add_tcase (s, tc); tcase_add_test (tc, gcs_sm_test_basic); tcase_add_test (tc, gcs_sm_test_simple); tcase_add_test (tc, gcs_sm_test_close); tcase_add_test (tc, gcs_sm_test_pause); tcase_add_test (tc, gcs_sm_test_interrupt); return s; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_sm_test.hpp000066400000000000000000000002661244131713600235750ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gcs_sm_test__ #define __gcs_sm_test__ Suite *gcs_send_monitor_suite(void); #endif /* __gcs_sm_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_state_msg_test.cpp000066400000000000000000000534021244131713600251370ustar00rootroot00000000000000// Copyright (C) 2007-2013 Codership Oy // $Id$ #include #include #include "gcs_state_msg_test.hpp" #define GCS_STATE_MSG_ACCESS #include "../gcs_state_msg.hpp" static int const QUORUM_VERSION = 3; START_TEST (gcs_state_msg_test_basic) { ssize_t send_len, ret; gu_uuid_t state_uuid; gu_uuid_t group_uuid; gu_uuid_t prim_uuid; gcs_state_msg_t* send_state; gcs_state_msg_t* recv_state; gu_uuid_generate (&state_uuid, NULL, 0); gu_uuid_generate (&group_uuid, NULL, 0); gu_uuid_generate (&prim_uuid, NULL, 0); send_state = gcs_state_msg_create (&state_uuid, &group_uuid, &prim_uuid, 457, // prim_seqno 3465, // last received seq. 2345, // last cached seq. 5, // prim_joined GCS_NODE_STATE_JOINED, // prim_state GCS_NODE_STATE_NON_PRIM, // current_state "My Name", // name "192.168.0.1:2345", // inc_addr 0, // gcs_proto_ver 1, // repl_proto_ver 1, // appl_proto_ver GCS_STATE_FREP // flags ); fail_if (NULL == send_state); send_len = gcs_state_msg_len (send_state); fail_if (send_len < 0, "gcs_state_msg_len() returned %zd (%s)", send_len, strerror (-send_len)); { uint8_t send_buf[send_len]; ret = gcs_state_msg_write (send_buf, send_state); fail_if (ret != send_len, "Return value does not match send_len: " "expected %zd, got %zd", send_len, ret); recv_state = gcs_state_msg_read (send_buf, send_len); fail_if (NULL == recv_state); } fail_if (send_state->flags != recv_state->flags); fail_if (send_state->gcs_proto_ver != recv_state->gcs_proto_ver); fail_if (send_state->repl_proto_ver != recv_state->repl_proto_ver); fail_if (send_state->appl_proto_ver != recv_state->appl_proto_ver); fail_if (recv_state->appl_proto_ver != 1, "appl_proto_ver: %d", recv_state->appl_proto_ver); fail_if (send_state->received != recv_state->received, "Last received seqno: sent %lld, recv %lld", send_state->received, recv_state->received); fail_if (send_state->cached != recv_state->cached, "Last cached seqno: sent %lld, recv %lld", send_state->cached, recv_state->cached); fail_if (send_state->prim_seqno != recv_state->prim_seqno); fail_if (send_state->current_state != recv_state->current_state); fail_if (send_state->prim_state != recv_state->prim_state); fail_if (send_state->prim_joined != recv_state->prim_joined); fail_if (gu_uuid_compare (&recv_state->state_uuid, &state_uuid)); fail_if (gu_uuid_compare (&recv_state->group_uuid, &group_uuid)); fail_if (gu_uuid_compare (&recv_state->prim_uuid, &prim_uuid)); fail_if (strcmp(send_state->name, recv_state->name)); fail_if (strcmp(send_state->inc_addr, recv_state->inc_addr)); { size_t str_len = 1024; char send_str[str_len]; char recv_str[str_len]; fail_if (gcs_state_msg_snprintf (send_str, str_len, send_state) <= 0); fail_if (gcs_state_msg_snprintf (recv_str, str_len, recv_state) <= 0); // no longer true fail_if (strncmp (send_str, recv_str, str_len)); } gcs_state_msg_destroy (send_state); gcs_state_msg_destroy (recv_state); } END_TEST START_TEST (gcs_state_msg_test_quorum_inherit) { gcs_state_msg_t* st[3] = { NULL, }; gu_uuid_t state_uuid; gu_uuid_t group1_uuid, group2_uuid; gu_uuid_t prim1_uuid, prim2_uuid; gu_uuid_generate (&state_uuid, NULL, 0); gu_uuid_generate (&group1_uuid, NULL, 0); gu_uuid_generate (&group2_uuid, NULL, 0); gu_uuid_generate (&prim1_uuid, NULL, 0); gu_uuid_generate (&prim2_uuid, NULL, 0); gcs_seqno_t prim1_seqno = 123; gcs_seqno_t prim2_seqno = 834; gcs_seqno_t act1_seqno = 345; gcs_seqno_t act2_seqno = 239472508908LL; gcs_state_quorum_t quorum; mark_point(); /* First just nodes from different groups and configurations, none JOINED */ st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno - 1, act2_seqno - 1, act2_seqno-1, 5, GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM, "node0", "", 0, 1, 1, 0); fail_if(NULL == st[0]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno - 1, 3, GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno, act2_seqno, act2_seqno - 2, 5, GCS_NODE_STATE_PRIM, GCS_NODE_STATE_PRIM, "node2", "", 0, 1, 1, 1); fail_if(NULL == st[2]); gu_info (" Inherited 1"); int ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (false != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL)); fail_if (GCS_SEQNO_ILL != quorum.act_id); fail_if (GCS_SEQNO_ILL != quorum.conf_id); fail_if (-1 != quorum.gcs_proto_ver); fail_if (-1 != quorum.repl_proto_ver); fail_if (-1 != quorum.appl_proto_ver); /* now make node1 inherit PC */ gcs_state_msg_destroy (st[1]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno - 3, 3, GCS_NODE_STATE_JOINED, GCS_NODE_STATE_DONOR, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); gu_info (" Inherited 2"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group1_uuid)); fail_if (act1_seqno != quorum.act_id); fail_if (prim1_seqno != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); /* now make node0 inherit PC (should yield conflicting uuids) */ gcs_state_msg_destroy (st[0]); st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno - 1, act2_seqno - 1, -1, 5, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_SYNCED, "node0", "", 0, 1, 1, 0); fail_if(NULL == st[0]); gu_info (" Inherited 3"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (false != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL)); fail_if (GCS_SEQNO_ILL != quorum.act_id); fail_if (GCS_SEQNO_ILL != quorum.conf_id); fail_if (-1 != quorum.gcs_proto_ver); fail_if (-1 != quorum.repl_proto_ver); fail_if (-1 != quorum.appl_proto_ver); /* now make node1 non-joined again: group2 should win */ gcs_state_msg_destroy (st[1]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno -3, 3, GCS_NODE_STATE_JOINED, GCS_NODE_STATE_PRIM, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); gu_info (" Inherited 4"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group2_uuid)); fail_if (act2_seqno - 1 != quorum.act_id); fail_if (prim2_seqno - 1 != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); /* now make node2 joined: it should become a representative */ gcs_state_msg_destroy (st[2]); st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno, act2_seqno, act2_seqno - 2, 5, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_SYNCED, "node2", "", 0, 1, 1, 0); fail_if(NULL == st[2]); gu_info (" Inherited 5"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group2_uuid)); fail_if (act2_seqno != quorum.act_id); fail_if (prim2_seqno != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); gcs_state_msg_destroy (st[0]); gcs_state_msg_destroy (st[1]); gcs_state_msg_destroy (st[2]); } END_TEST START_TEST (gcs_state_msg_test_quorum_remerge) { gcs_state_msg_t* st[3] = { NULL, }; gu_uuid_t state_uuid; gu_uuid_t group1_uuid, group2_uuid; gu_uuid_t prim0_uuid, prim1_uuid, prim2_uuid; gu_uuid_generate (&state_uuid, NULL, 0); gu_uuid_generate (&group1_uuid, NULL, 0); gu_uuid_generate (&group2_uuid, NULL, 0); gu_uuid_generate (&prim0_uuid, NULL, 0); gu_uuid_generate (&prim1_uuid, NULL, 0); gu_uuid_generate (&prim2_uuid, NULL, 0); gcs_seqno_t prim1_seqno = 123; gcs_seqno_t prim2_seqno = 834; gcs_seqno_t act1_seqno = 345; gcs_seqno_t act2_seqno = 239472508908LL; gcs_state_quorum_t quorum; mark_point(); /* First just nodes from different groups and configurations, none JOINED */ st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim0_uuid, prim2_seqno - 1, act2_seqno - 1,act2_seqno -2, 5, GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM, "node0", "", 0, 1, 1, 0); fail_if(NULL == st[0]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno - 3, 3, GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno, act2_seqno, -1, 5, GCS_NODE_STATE_JOINER,GCS_NODE_STATE_NON_PRIM, "node2", "", 0, 1, 1, 1); fail_if(NULL == st[2]); gu_info (" Remerged 1"); int ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (false != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL)); fail_if (GCS_SEQNO_ILL != quorum.act_id); fail_if (GCS_SEQNO_ILL != quorum.conf_id); fail_if (-1 != quorum.gcs_proto_ver); fail_if (-1 != quorum.repl_proto_ver); fail_if (-1 != quorum.appl_proto_ver); /* Now make node0 to be joined at least once */ gcs_state_msg_destroy (st[0]); st[0] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim0_uuid, prim2_seqno - 1, act2_seqno - 1, -1, 5, GCS_NODE_STATE_DONOR, GCS_NODE_STATE_NON_PRIM, "node0", "", 0, 1, 1, 0); fail_if(NULL == st[0]); gu_info (" Remerged 2"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group2_uuid)); fail_if (act2_seqno - 1 != quorum.act_id); fail_if (prim2_seqno - 1 != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); /* Now make node2 to be joined too */ gcs_state_msg_destroy (st[2]); st[2] = gcs_state_msg_create (&state_uuid, &group2_uuid, &prim2_uuid, prim2_seqno, act2_seqno, act2_seqno - 3, 5, GCS_NODE_STATE_JOINED,GCS_NODE_STATE_NON_PRIM, "node2", "", 0, 1, 1, 1); fail_if(NULL == st[2]); gu_info (" Remerged 3"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group2_uuid)); fail_if (act2_seqno != quorum.act_id); fail_if (prim2_seqno != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); /* now make node1 joined too: conflict */ gcs_state_msg_destroy (st[1]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno, 3, GCS_NODE_STATE_SYNCED,GCS_NODE_STATE_NON_PRIM, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); gu_info (" Remerged 4"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (false != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &GU_UUID_NIL)); fail_if (GCS_SEQNO_ILL != quorum.act_id); fail_if (GCS_SEQNO_ILL != quorum.conf_id); fail_if (-1 != quorum.gcs_proto_ver); fail_if (-1 != quorum.repl_proto_ver); fail_if (-1 != quorum.appl_proto_ver); /* now make node1 current joiner: should be ignored */ gcs_state_msg_destroy (st[1]); st[1] = gcs_state_msg_create (&state_uuid, &group1_uuid, &prim1_uuid, prim1_seqno, act1_seqno, act1_seqno - 2, 3, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_JOINER, "node1", "", 0, 1, 0, 0); fail_if(NULL == st[1]); gu_info (" Remerged 5"); ret = gcs_state_msg_get_quorum ((const gcs_state_msg_t**)st, sizeof(st)/sizeof(gcs_state_msg_t*), &quorum); fail_if (0 != ret); fail_if (QUORUM_VERSION != quorum.version); fail_if (true != quorum.primary); fail_if (0 != gu_uuid_compare(&quorum.group_uuid, &group2_uuid)); fail_if (act2_seqno != quorum.act_id); fail_if (prim2_seqno != quorum.conf_id); fail_if (0 != quorum.gcs_proto_ver); fail_if (1 != quorum.repl_proto_ver); fail_if (0 != quorum.appl_proto_ver); gcs_state_msg_destroy (st[0]); gcs_state_msg_destroy (st[1]); gcs_state_msg_destroy (st[2]); } END_TEST START_TEST(gcs_state_msg_test_gh24) { gcs_state_msg_t* st[7] = { NULL, }; gu_uuid_t state_uuid, group_uuid; gu_uuid_generate(&state_uuid, NULL, 0); gu_uuid_generate(&group_uuid, NULL, 0); gu_uuid_t prim_uuid1, prim_uuid2; gu_uuid_generate(&prim_uuid1, NULL, 0); gu_uuid_generate(&prim_uuid2, NULL, 0); gcs_seqno_t prim_seqno1 = 37; int prim_joined1 = 3; gcs_seqno_t prim_seqno2 = 35; int prim_joined2 = 6; gcs_seqno_t received = 0; gcs_seqno_t cached = 0; gcs_state_quorum_t quorum; // first three are 35. st[0] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2, prim_seqno2, received, cached, prim_joined2, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home0", "", 0, 4, 2, 2); fail_unless(st[0] != 0); st[1] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2, prim_seqno2, received, cached, prim_joined2, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home1", "", 0, 4, 2, 2); fail_unless(st[1] != 0); st[2] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid2, prim_seqno2, received, cached, prim_joined2, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home2", "", 0, 4, 2, 2); fail_unless(st[2] != 0); // last four are 37. st[3] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1, prim_seqno1, received, cached, prim_joined1, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home3", "", 0, 4, 2, 3); fail_unless(st[3] != 0); st[4] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1, prim_seqno1, received, cached, prim_joined1, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home4", "", 0, 4, 2, 2); fail_unless(st[4] != 0); st[5] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1, prim_seqno1, received, cached, prim_joined1, GCS_NODE_STATE_SYNCED, GCS_NODE_STATE_NON_PRIM, "home5", "", 0, 4, 2, 2); fail_unless(st[5] != 0); st[6] = gcs_state_msg_create(&state_uuid, &group_uuid, &prim_uuid1, prim_seqno1, received, cached, prim_joined1, GCS_NODE_STATE_PRIM, GCS_NODE_STATE_NON_PRIM, "home6", "", 0, 4, 2, 2); fail_unless(st[6] != 0); int ret = gcs_state_msg_get_quorum((const gcs_state_msg_t**)st, 7, &quorum); fail_unless(ret == 0); fail_unless(quorum.primary == true); fail_unless(quorum.conf_id == prim_seqno1); // // but we just have first five nodes, we don't have prim. // // because prim_joined=3 but there are only 2 joined nodes. // ret = gcs_state_msg_get_quorum((const gcs_state_msg_t**)st, 5, // &quorum); // fail_unless(ret == 0); // fail_unless(quorum.primary == false); for(int i=0;i<7;i++) gcs_state_msg_destroy(st[i]); } END_TEST Suite *gcs_state_msg_suite(void) { Suite *s = suite_create("GCS state message"); TCase *tc_basic = tcase_create("gcs_state_msg_basic"); TCase *tc_inherit = tcase_create("gcs_state_msg_inherit"); TCase *tc_remerge = tcase_create("gcs_state_msg_remerge"); suite_add_tcase (s, tc_basic); tcase_add_test (tc_basic, gcs_state_msg_test_basic); suite_add_tcase (s, tc_inherit); tcase_add_test (tc_inherit, gcs_state_msg_test_quorum_inherit); suite_add_tcase (s, tc_remerge); tcase_add_test (tc_remerge, gcs_state_msg_test_quorum_remerge); tcase_add_test (tc_remerge, gcs_state_msg_test_gh24); return s; } percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_state_msg_test.hpp000066400000000000000000000003101244131713600251320ustar00rootroot00000000000000// Copyright (C) 2007 Codership Oy // $Id$ #ifndef __gcs_state_msg_test__ #define __gcs_state_msg_test__ Suite *gcs_state_msg_suite(void); #endif /* __gcs_state_msg_test__ */ percona-galera-3-3.8-3390/gcs/src/unit_tests/gcs_tests.cpp000066400000000000000000000040571244131713600232560ustar00rootroot00000000000000/* * Copyright (C) 2008-2014 Codership Oy * * $Id$ */ #include // printf() #include // strcmp() #include // EXIT_SUCCESS | EXIT_FAILURE #include #include #include "gcs_comp_test.hpp" #include "gcs_sm_test.hpp" #include "gcs_state_msg_test.hpp" #include "gcs_fifo_test.hpp" #include "gcs_proto_test.hpp" #include "gcs_defrag_test.hpp" #include "gcs_node_test.hpp" #include "gcs_memb_test.hpp" #include "gcs_group_test.hpp" #include "gcs_backend_test.hpp" #include "gcs_core_test.hpp" #include "gcs_fc_test.hpp" typedef Suite *(*suite_creator_t)(void); static suite_creator_t suites[] = { gcs_comp_suite, gcs_send_monitor_suite, gcs_state_msg_suite, gcs_fifo_suite, gcs_proto_suite, gcs_defrag_suite, gcs_node_suite, gcs_memb_suite, gcs_group_suite, gcs_backend_suite, gcs_core_suite, gcs_fc_suite, NULL }; int main(int argc, char* argv[]) { int no_fork = ((argc > 1) && !strcmp(argv[1], "nofork")) ? 1 : 0; int i = 0; int failed = 0; FILE* log_file = NULL; log_file = fopen ("gcs_tests.log", "w"); if (!log_file) return EXIT_FAILURE; gu_conf_set_log_file (log_file); gu_conf_debug_on(); gu_conf_self_tstamp_on(); while (suites[i]) { SRunner* sr = srunner_create(suites[i]()); gu_info ("#########################"); gu_info ("Test %d.", i); gu_info ("#########################"); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all (sr, CK_NORMAL); failed += srunner_ntests_failed (sr); srunner_free (sr); i++; } fclose (log_file); printf ("Total test failed: %d\n", failed); return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } /* When the suite compiled in debug mode, returns number of allocated bytes */ ssize_t gcs_tests_get_allocated() { ssize_t total; ssize_t allocs; ssize_t reallocs; ssize_t deallocs; void gu_mem_stats (ssize_t*, ssize_t*, ssize_t*, ssize_t*); gu_mem_stats (&total, &allocs, &reallocs, &deallocs); return total; } percona-galera-3-3.8-3390/packages/000077500000000000000000000000001244131713600165605ustar00rootroot00000000000000percona-galera-3-3.8-3390/packages/rpm/000077500000000000000000000000001244131713600173565ustar00rootroot00000000000000percona-galera-3-3.8-3390/packages/rpm/README000066400000000000000000000534221244131713600202440ustar00rootroot00000000000000Codership Oy http://www.codership.com DISCLAIMER THIS SOFTWARE PROVIDED "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. IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. Trademark Information. All trademarks are the property of their respective owners. Licensing Information. Galera is copyright (c) 2007-2013 Codership Oy Please see COPYING file that came with this distribution. This product uses asio C++ library which is Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) licensed under Boost Software License. This product uses CRC-32C implementation from http://www.evanjones.ca which is licensed under MIT License. This product uses aligned buffer implementation from Chromium Project which is copyright Chromium Authors and licensed under Chromium License Source code can be found at https://launchpad.net/galera GALERA v3.x CONTENTS: ========= 1. WHAT IS GALERA 2. GALERA USE CASES 3. GALERA CONFIGURATION PARAMETERS 4. GALERA ARBITRATOR 5. WRITESET CACHE 6. INCREMENTAL STATE TRANSFER 7. SPECIAL NOTES 1. WHAT IS GALERA Galera is a synchronous multi-master replication engine that provides its service through wsrep API (https://launchpad.net/wsrep). It features optimistic transaction execution and commit time replication and certification of writesets. Since it replicates only final changes to the database it is transparent to triggers, stored procedures and non-deterministic functions. Galera nodes are connected to each other in a N-to-N fashion through a group communication backend which provides automatic reconfiguration in the event of a node failure or a new node added to cluster: ,-------. ,-------. ,--------. | node1 |-----| node2 |<---| client | `-------' G `-------' `--------' \ / ,-------. ,--------. | node3 |<---| client | `-------' `--------' Node states are synchronized by replicating transaction changes at commit time. The cluster is virtually synchronous: this means that each node commits transactions in exactly the same order, although not necessarily at the same physical moment. (The latter is not that important as it may seem, since in most cases DBMS gives no guarantee on when the transaction is actually processed.) Built-in flow control keeps nodes within fraction of a second from each other, this is more than enough for most practical purposes. Main features of a Galera database cluster: * Truly highly available: no committed transaction is ever lost in case of a node crash. All nodes always have consistent state. * True multi-master: all cluster nodes can handle WRITE load concurrently. * Highly transparent. (See SPECIAL NOTES below) * Scalable even with WRITE-intensive applications. * Automatic synchronization of new nodes. 2. GALERA USE CASES There is a number of ways how Galera replication can be utilized. They can be categorized in three groups: 1) Seeking High Availability only. In this case client application connects to only one node, the rest serving as hot backups: ,-------------. | application | `-------------' | | | DB backups ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <===== cluster nodes =====> In the case of primary node failure or maintenance shutdown application can instantly switch to another node without any special failover procedure. 2) Seeking High Availability and improved performance through uniform load distribution. If there are several client connections to the database, they can be uniformly distributed between cluster nodes resulting in better performance. The exact degree of performance improvement depends on application's load profile. Note, that transaction rollback rate may also increase. ,-------------. | clients | `-------------' | | | | ,-------------. | application | `-------------' / | \ ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <===== cluster nodes =====> In the case of a node failure application can keep on using the remaining healthy nodes. In this setup application can also be clustered with a dedicated application instance per database node, thus achieving HA not only for the database, but for the whole application stack: ,-------------. | clients | `-------------' // || \\ ,------. ,------. ,------. | app1 | | app2 | | app3 | `------' `------' `------' | | | ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <====== cluster nodes ======> 3) Seeking High Availability and improved performance through smart load distribution. Uniform load distribution can cause undesirably high rollback rate. Directing transactions which access the same set of tables to the same node can considerably improve performance by reducing the number of rollbacks. Also, if your application can distinguish between read/write and read-only transactions, the following configuration may be quite efficient: ,---------------------. | application | `---------------------' writes / | reads \ reads ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <========= cluster nodes =========> 3. GALERA PARAMETERS 3.1 Cluster URL. Galera can use URL (RFC 3986) syntax for addressing with optional parameters passed in the URL query part. Galera cluster address looks as follows: ://[?option1=value1[&option2=value2]] e.g.: gcomm://192.168.0.1:4567?gmcast.listen_addr=0.0.0.0:5678 Currently Galera supports the following backends: 'dummy' - is a bypass backend for debugging/profiling purposes. It does not connect to or replicate anything and the rest of the URL address string is ignored. 'gcomm' - is a Codership's own Group Communication backend that provides Virtual Synchrony quality of service. It uses TCP for membership service and TCP (and UDP multicast as of version 0.8) for data replication. Normally one would use just the simplest form of the address URL: gcomm:// - if one wants to start a new cluster. gcomm://
- if one wants to join an existing cluster. In that case
is the address of one of the cluster members 3.2 Galera parameters. There is quite a few galera configuration parameters which affect its behavior and performance. Of particular interest to an end-user are the following: To configure gcomm listen address: gmcast.listen_addr To configure how fast cluster reacts on node failure or connection loss: evs.suspect_timeout evs.inactive_timeout evs.inactive_check_period evs.keepalive_period To fine-tune performance (especially in high latency networks): evs.user_send_window evs.send_window To relax or tighten replication flow control: gcs.fc_limit gcs.fc_factor For a full parameter list please see http://www.codership.com/wiki/doku.php?id=galera_parameters 3.2.1 GMCast parameters group. All parameters in this group are prefixed by 'gmcast.' (see example above). group String denoting group name. Max length of string is 16. Peer nodes accept GMCast connection only if the group names match. It is set automatically from wsrep options. listen_addr Listening address for GMCast. Address is currently passed in URI format (for example tcp://192.168.3.1:4567) and it should be passed as the last configuration parameter in order to avoid confusion. If parameter value is undefined, GMCast starts listening all interfaces at default port 4567 mcast_addr Multicast address in dotted decimal notation, enables using multicast to transmit group communication messages. Defaults to none. Must have the same value on all nodes. mcast_port Port used for UDP multicast messages. Defaults to listen_addr port. Must have same value on all of the nodes. mcast_ttl Time to live for multicast packets. Defaults to 1. 3.2.2 EVS parameter group. All parameters in this group are prefixed by 'evs.'. All values for the timeout options below should follow ISO 8601 standard for the time interval representation (e.g. 02:01:37.2 -> PT2H1M37.2S == PT121M37.2S == PT7297.2S) suspect_timeout This timeout controls how long node can remain silent until it is put under suspicion. If majority of the current group agree that the node is under suspicion, it is discarded from group and new group view is formed immediately. If majority of the group does not agree about suspicion, is waited until forming of new group will be attempted. Default value is 5 seconds. inactive_timeout This timeout control how long node can remain completely silent until it is discarded from the group. This is hard limit, unlike , and the node is discarded even if it becomes live during the formation of the new group (so it is inclusive of ). Default value is 15 seconds. inactive_check_period This period controls how often node liveness is checked. Default is 1 second and there is no need to change this unless or is adjusted to smaller value. Minimum is 0.1 seconds and maximum is /2. keepalive_period This timeout controls how often keepalive messages are sent into network. Node liveness is determined with these keepalives, so the value sould be considerably smaller than . Default value is 1 second, minimum is 0.1 seconds and maximum is /3. consensus_timeout This timeout defines how long forming of new group is attempted. If there is no consensus after this time has passed since starting of consensus protocol, every node discards all other nodes from the group and forming of new group is attempted through singleton groups. Default value is 30 seconds, minimum is and maximum is *5. join_retrans_period This parameter controls how often join messages are retransmitted during group formation. There is usually no need to adjust this value. Default value is 0.3 seconds, minimum is 0.1 seconds and maximum is /3. view_forget_timeout This timeout controls how long information about known group views is maintained. This information is needed to filter out delayed messages from previous views that are not live anymore. Default value is 5 minutes and there is usually no need to change it. debug_log_mask This mask controls what debug information is printed in the logs if debug logging is turned on. Mask value is bitwise-OR from values gcomm::evs::Proto::DebugFlags. By default only state information is printed. info_log_mask This mask controls what info log is printed in the logs. Mask value is bitwise-or from values gcomm::evs::Proto::InfoFlags. stats_report_period This parameter controls how often statistics information is printed in the log. This parameter has effect only if statistics reporting is enabled via Conf::EvsInfoLogMask. Default value is 1 minute. send_window This parameter controls how many messages protocol layer is allowed to send without getting all acknowledgements for any of them. Default value is 32. user_send_window Like , but for messages which sending is initiated by a call from the upper layer. Default value is 16. 3.2.3 GCS parameter group All parameters in this group are prefixed by 'gcs.'. fc_debug Post debug statistics about SST flow control every that many writesets. Default: 0. fc_factor Resume replication after recv queue drops below that fraction of gcs.fc_limit. For fc_master_slave = NO this is limit is also scaled. Default: 1.0. fc_limit Pause replication if recv queue exceeds that many writesets. Default: 16. For master-slave setups this number can be increased considerably. fc_master_slave When this is NO then the effective gcs.fc_limit is multipled by sqrt( number of cluster members ). Default: NO. sync_donor Should we enable flow control in DONOR state the same way as in SYNCED state. Useful for non-blocking state transfers. Default: NO. max_packet_size All writesets exceeding that size will be fragmented. Default: 32616. max_throttle How much we can throttle replication rate during state transfer (to avoid running out of memory). Set it to 0.0 if stopping replication is acceptable for the sake of completing state transfer. Default: 0.25. recv_q_hard_limit Maximum allowed size of recv queue. This should normally be half of (RAM + swap). If this limit is exceeded, Galera will abort the server. Default: LLONG_MAX. recv_q_soft_limit A fraction of gcs.recv_q_hard_limit after which replication rate will be throttled. Default: 0.25. The degree of throttling is a linear function of recv queue size and goes from 1.0 (“full rateâ€) at gcs.recv_q_soft_limit to gcs.max_throttle at gcs.recv_q_hard_limit. Note that “full rateâ€, as estimated between 0 and gcs.recv_q_soft_limit is a very approximate estimate of a regular replication rate. 3.2.4 Replicator parameter group All parameters in this group are prefixed by 'replicator.'. commit_order Whether we should allow Out-Of-Order committing (improves parallel applying performance). Possible settings: 0 – BYPASS: all commit order monitoring is turned off (useful for measuring performance penalty) 1 – OOOC: allow out of order committing for all transactions 2 – LOCAL_OOOC: allow out of order committing only for local transactions 3 – NO_OOOC: no out of order committing is allowed (strict total order committing) Default: 3. 3.2.5 GCache parameter group All parameters in this group are prefixed by 'gcache.'. dir Directory where GCache should place its files. Default: working directory. name Name of the main store file (ring buffer). Default: “galera.cacheâ€. size Size of the main store file (ring buffer). This will be preallocated on startup. Default: 128Mb. page_size Size of a page in the page store. The limit on overall page store is free disk space. Pages are prefixed by “gcache.pageâ€. Default: 128Mb. keep_pages_size Total size of the page store pages to keep for caching purposes. If only page storage is enabled, one page is always present. Default: 0. mem_size Size of the malloc() store (read: RAM). For configurations with spare RAM. Default: 0. 3.2.6 SSL parameters All parameters in this group are prefixed by 'socket.'. ssl_cert Certificate file in PEM format. ssl_key A private key for the certificate above, unencrypted, in PEM format. ssl A boolean value to disable SSL even if certificate and key are configured. Default: yes (SSL is enabled if ssl_cert and ssl_key are set) To generate private key/certificate pair the following command may be used: $ openssl req -new -x509 -days 365000 -nodes -keyout key.pem -out cert.pem Using short-living (in most web examples - 1 year) certificates is not advised as it will lead to complete cluster shutdown when certificate expires. 3.2.7 Incremental State Transfer parameters All parameters in this group are prefixed by 'ist.'. recv_addr Address to receive incremental state transfer at. Setting this parameter turns on incremental state transfer. IST will use SSL if SSL is configured as described above. No default. 4. GALERA ARBITRATOR Galera arbitrator found in this package is a small stateless daemon that can serve as a lightweight cluster member to * avoid split brain condition in a cluster with an otherwise even membership. * request consistent state snapshots for backup purposes. Example usage: ,---------. | garbd | `---------' ,---------. | ,---------. | clients | | | clients | `---------' | `---------' \ | / \ ,---. / (' `) ( WAN ) (. ,) / `---' \ / \ ,---------. ,---------. | node1 | | node2 | `---------' `---------' Data Center 1 Data Center 2 In this example, if one of the data centers loses WAN connection, the node that sees arbitrator (and therefore sees clients) will continue the operation. garbd accepts the same Galera options as the regular Galera node. Note that at the moment garbd needs to see all replication traffic (although it does not store it anywhere), so placing it in a location with poor connectivity to the rest of the cluster may lead to cluster performance degradation. Arbitrator failure does not affect cluster operation and a new instance can be reattached to cluster at any time. There can be several arbitrators in the cluster, although practicality of it is questionable. 5. WRITESET CACHE Starting with version 1.0 Galera stores writesets in a special cache. It's purpose is to improve control of Galera memory usage and offload writeset storage to disk. Galera cache has 3 types of stores: 1. A permanent in-memory store, where writesets are allocated by a default OS memory allocator. It can be useful for systems with spare RAM. It has a hard size limit. By default it is disabled (size set to 0). 2. A permanent ring-buffer file which is preallocated on disk during cache initialization. It is intended as the main writeset store. By default its size is 128Mb. 3. An on-demand page store, which allocates memory-mapped page files during runtime as necessary. Default page size is 128Mb, but it can be bigger if it needs to store a bigger writeset. The size of page store is limited by the free disk space. By default page files are deleted when not in use, but a limit can be set on the total size of the page files to keep. When all other stores are disabled, at least one page file is always present on disk. Allocation algorithm is as follows: all stores are tried in the above order. If a store does not have enough space to allocate the writeset, then the next store is tried. Page store should always succeed unless the writeset is bigger than the available disk space. By default Galera cache allocates files in the working directory of the process, but a dedicated location can be specified. For configuration parameters see GCache group above (p. 3.2.5). NOTE: Since all cache files are memory-mapped, the process may appear to use more memory than it actually does. 6. INCREMENTAL STATE TRANSFER (IST) Galera 2.x introduces a long awaited functionality: incremental state transfer. The idea is that if a) the joining node state UUID is the same as that of the group and b) all of the writesets that it missed can be found in the donor's Gcache then instead of whole state snapshot it will receive the missing writesets and catch up with the group by replaying them. For example: - local node state is 5a76ef62-30ec-11e1-0800-dba504cf2aab:197222 - group state is 5a76ef62-30ec-11e1-0800-dba504cf2aab:201913 - if writeset number 197223 is still in the donor's GCache, it will send writests 197223-201913 to joiner instead of the whole state. IST can dramatically speed up remerging node into cluster. It also non-blocking on the donor. The most important parameter for IST (besides 'ist.recv_addr') is GCache size on donor. The bigger it is, the more writesets can be stored in it and the bigger seqno gaps can be closed with IST. On the other hand, if GCache is much bigger than the state size, serving IST may be less efficient than sending state snapshot. 7. SPECIAL NOTES 7.1 DEADLOCK ON COMMIT In multi-master mode transaction commit operation may return a deadlock error. This is a consequence of writeset certification and is a fundamental property of Galera. If deadlock on commit cannot be tolerated by application, Galera can still be used on a condition that all write operations to a given table are performed on the same node. This still has an advantage over the "traditional" master-slave replication: write load can still be distributed between nodes and since replication is synchronous, failover is trivial. 7.2 "SPLIT-BRAIN" CONDITION Galera cluster is fully distributed and does not use any sort of centralized arbitrator, thus having no single point of failure. However, like any cluster of that kind it may fall to a dreaded "split-brain" condition where half of the cluster nodes suddenly disappear (e.g. due to network failure). In general case, having no information about the fate of disappeared nodes remaining nodes cannot continue to process requests and modify their states. While such situation is generally considered negligibly probable in a multi-node cluster (normally nodes fail one at a time), in 2-node cluster a single node failure can lead to this, thus making 3 nodes a minimum requirement for a highly-available cluster. Galera arbitrator (see above) can serve as an odd stateless cluster node to help avoid the possibility of an even cluster split. percona-galera-3-3.8-3390/packages/rpm/README-MySQL000066400000000000000000000134141244131713600212040ustar00rootroot00000000000000Codership Oy http://www.codership.com DISCLAIMER THIS SOFTWARE PROVIDED "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. IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. Trademark Information. MySQL and other trademarks are the property of their respective owners. Licensing Information. Please see COPYING file that came with this distribution. Source code can be found at http://www.codership.com/en/downloads/galera ABOUT THIS DOCUMENT This document briefly explains how to use Galera wsrep provider with MySQL RDBMS. For more information check http://www.codership.com/wiki/doku.php Using MySQL with GALERA v2.x CONTENTS: ========= 1. WHAT IS MYSQL/GALERA CLUSTER 2. MYSQL/GALERA NODE SETUP 3. CONNECTING TO CLUSTER 4. LIMITATIONS 1. WHAT IS MYSQL/GALERA CLUSTER MySQL/Galera cluster is a synchronous multi-master cluster solution for InnoDB engine based on wsrep API (https://launchpad.net/wsrep) which Galera is implementation of. It requires MySQL server patched to use this API (https://launchpad.net/codership-mysql). Node states are synchronized by replicating transaction changes at commit time. The cluster is virtually synchronous: this means that each node commits transactions in exactly the same order, although not necessarily at the same physical moment. (The latter is not that important as it may seem, since in most cases DBMS gives no guarantee on when the transaction is actually processed.) Built-in flow control keeps nodes within fraction of a second from each other, this is more than enough for most practical purposes. From the client perspective that means: * Truly highly available: no committed transaction is ever lost in case of a node crash. * Highly transparent: with few exceptions each node can be treated as a normal standalone MySQL/InnoDB server. * True multi-master: all cluster nodes can modify the same table concurrently. * Scalable even with WRITE-intensive applications. 2. MYSQL/GALERA NODE SETUP To setup MySQL/Galera node you will need to 1) Install wsrep-patched MySQL from https://launchpad.net/codership-mysql/0.7. Please see the documentation that comes with it about first time node setup. 2) Configure it to use Galera library as a wsrep provider. For that set wsrep_provider option to wsrep_provider=/usr/lib/galera/libgalera_smm.so (DEB systems) or wsrep_provider=/usr/lib64/galera/libgalera_smm.so (RPM systems). 3) Start MySQL server. 3. CONNECTING TO CLUSTER To join the cluster you will need to set global wsrep_cluster_address variable either in wsrep.cnf file or from the command line (the latter is recommended to avoid automatic connection to failed nodes). E.g. mysql> SET GLOBAL wsrep_cluster_address='gcomm://'; to bootstrap a new cluster, or mysql> SET GLOBAL wsrep_cluster_address='gcomm://:4567'; to join existing cluster. Upon connecting to initial node, the server will obtain the list of other nodes and connect to each of them. There is a number of options that can be passed to Galera with the wsrep_cluster_address string. See README for details. After connecting to cluster the new node will synchronize its state by receiving state snapshot form one of the peers. For the duration of this procedure both nodes may be unable to process client requests. Other nodes are unaffected by this. 4. SETTING GALERA PARAMETERS IN MYSQL To configure Galera parameteres set wsrep_provider_options variable either in my.cnf or in the command line: wsrep_provider_options="gcs.fc_limit = 128; gcs.fc_master_slave = yes" Certain parameteres can be changed in runtime: mysql> SET GLOBAL wsrep_provider_options="evs.send_window=16"; will only change the value of evs.send_window parameter. For the list of all Galera parameters see main README and http://www.codership.com/wiki. mysql> SHOW VARIABLES like 'wsrep_provider_options'; Will show all parameters and their current values. 5. LIMITATIONS 1) Currently replication works only with InnoDB storage engine. Any writes to tables of other types, including system (mysql.*) tables are not replicated. However, DDL statements are replicated in statement level, and changes to mysql.* tables will get replicated that way. So, you can safely issue: CREATE USER..., but issuing: INSERT INTO mysql.user..., will not be replicated. 2) DELETE operation is unsupported on tables without primary keys. Rows in tables without primary keys may appear in different order on different nodes. As a result SELECT...LIMIT... may return slightly different sets. 3) Unsupported queries: * LOCK/UNLOCK tables is not supported in multimaster configuration. * lock functions (GET_LOCK(), RELEASE_LOCK()... ) 4) Query log cannot be directed to table. If you enable query logging, you must forward the log to a file: log_output = FILE Use general_log and general_log_file to choose query logging and the log file name 5) Maximum allowed transaction size is defined by wsrep_max_ws_rows and wsrep_max_ws_size. Anything bigger (e.g. huge LOAD DATA) will be rejected. 6) Due to cluster level optimistic concurrency control, transaction issuing COMMIT may still be aborted at that stage. There can be two transactions writing to same rows and committing in separate cluster nodes, and only one of the them can successfully commit. The failing one will be aborted. For cluster level aborts, MySQL/galera cluster gives back deadlock error code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)). 7) XA transactions can not be supported due to possible rollback on commit. percona-galera-3-3.8-3390/packages/rpm/percona-xtradb-cluster-galera.spec000066400000000000000000000155041244131713600260600ustar00rootroot00000000000000# Copyright (c) 2011, Percona Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # 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; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston # MA 02110-1301 USA. %define src_dir percona-xtradb-cluster-galera-3 %define docs /usr/share/doc/%{src_dir} %define src_dir2 percona-xtradb-cluster-garbd-3 %define docs2 /usr/share/doc/%{src_dir2} Prefix: %{_prefix} %define rhelver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') %if "%rhelver" == "5" %define boost_req boost141-devel %define gcc_req gcc44-c++ %else %define boost_req boost-devel %define gcc_req gcc-c++ %endif %if %{undefined scons_args} %define scons_args %{nil} %endif %if %{undefined galera_version} %define galera_version 3.8 %endif %if %{undefined galera_revision} %define galera_revision %{revision} %endif %if %{undefined pxcg_revision} %define pxcg_revision %{revno} %endif %ifarch i686 %define scons_arch arch=i686 %else %define scons_arch %{nil} %endif %bcond_with systemd # %if %{with systemd} %define systemd 1 %else %if 0%{?rhel} > 6 %define systemd 1 %else %define systemd 0 %endif %endif %define redhatversion %(lsb_release -rs | awk -F. '{ print $1}') %define distribution rhel%{redhatversion} %if "%rhel" == "7" %define distro_requires chkconfig nmap %else %define distro_requires chkconfig nc %endif Name: Percona-XtraDB-Cluster-galera-3 Version: %{galera_version} Release: 1.%{pxcg_revision}.%{?distribution} Summary: Galera libraries of Percona XtraDB Cluster Group: Applications/Databases License: GPLv3 URL: http://www.percona.com/ Source0: percona-xtradb-cluster-galera-3.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) Provides: Percona-XtraDB-Cluster-galera-25 galera3 Obsoletes: Percona-XtraDB-Cluster-galera-56 Conflicts: Percona-XtraDB-Cluster-galera-2 BuildRequires: scons check-devel glibc-devel %{gcc_req} openssl-devel %{boost_req} check-devel %description This package contains the Galera library required by Percona XtraDB Cluster. %package -n Percona-XtraDB-Cluster-garbd-3 Summary: Garbd component of Percona XtraDB Cluster Group: Applications/Databases Provides: garbd3 Requires: %{distro_requires} %if 0%{?systemd} BuildRequires: systemd %endif %if 0%{?systemd} Requires(post): systemd Requires(preun): systemd Requires(postun): systemd %else Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig Requires(preun): /sbin/service %endif %description -n Percona-XtraDB-Cluster-garbd-3 This package contains the garb binary and init scripts. %prep %setup -q -n %{src_dir} %build %if "%rhelver" == "5" export CC=gcc44 export CXX=g++44 %endif scons %{?_smp_mflags} revno=%{galera_revision} version=%{galera_version} boost_pool=0 garb/garbd libgalera_smm.so %{scons_arch} %{scons_args} %install rm -rf $RPM_BUILD_ROOT mkdir -p "$RPM_BUILD_ROOT" install -d $RPM_BUILD_ROOT%{_sysconfdir}/{init.d,sysconfig} install -m 644 $RPM_BUILD_DIR/%{src_dir}/garb/files/garb.cnf \ $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/garb install -d "$RPM_BUILD_ROOT/%{_bindir}" install -d "$RPM_BUILD_ROOT/%{_libdir}" %if 0%{?systemd} install -D -m 644 $RPM_BUILD_DIR/%{src_dir}/garb/files/garb.service \ $RPM_BUILD_ROOT/%{_unitdir}/garb.service install -m 755 $RPM_BUILD_DIR/%{src_dir}/garb/files/garb-systemd \ $RPM_BUILD_ROOT/%{_bindir}/garb-systemd %else install -m 755 $RPM_BUILD_DIR/%{src_dir}/garb/files/garb.sh \ $RPM_BUILD_ROOT%{_sysconfdir}/init.d/garb %endif install -m 755 "$RPM_BUILD_DIR/%{src_dir}/garb/garbd" \ "$RPM_BUILD_ROOT/%{_bindir}/" install -d "$RPM_BUILD_ROOT/%{_libdir}/galera3" install -m 755 "$RPM_BUILD_DIR/%{src_dir}/libgalera_smm.so" \ "$RPM_BUILD_ROOT/%{_libdir}/galera3/" ln -s "galera3/libgalera_smm.so" "$RPM_BUILD_ROOT/%{_libdir}/" install -d $RPM_BUILD_ROOT%{docs} install -m 644 $RPM_BUILD_DIR/%{src_dir}/COPYING \ $RPM_BUILD_ROOT%{docs}/COPYING install -m 644 $RPM_BUILD_DIR/%{src_dir}/packages/rpm/README \ $RPM_BUILD_ROOT%{docs}/README install -m 644 $RPM_BUILD_DIR/%{src_dir}/packages/rpm/README-MySQL \ $RPM_BUILD_ROOT%{docs}/README-MySQL install -m 644 $RPM_BUILD_DIR/%{src_dir}/asio/LICENSE_1_0.txt \ $RPM_BUILD_ROOT%{docs}/LICENSE.asio install -m 644 $RPM_BUILD_DIR/%{src_dir}/www.evanjones.ca/LICENSE \ $RPM_BUILD_ROOT%{docs}/LICENSE.crc32c install -m 644 $RPM_BUILD_DIR/%{src_dir}/chromium/LICENSE \ $RPM_BUILD_ROOT%{docs}/LICENSE.chromium install -d $RPM_BUILD_ROOT%{docs2} install -m 644 $RPM_BUILD_DIR/%{src_dir}/COPYING \ $RPM_BUILD_ROOT%{docs2}/COPYING install -m 644 $RPM_BUILD_DIR/%{src_dir}/packages/rpm/README \ $RPM_BUILD_ROOT%{docs2}/README install -d $RPM_BUILD_ROOT%{_mandir}/man1 install -m 644 $RPM_BUILD_DIR/%{src_dir}/garb/files/garbd.troff \ $RPM_BUILD_ROOT%{_mandir}/man1/garbd.1 %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) # This is a symlink %attr(0755,root,root) %{_libdir}/libgalera_smm.so %attr(0755,root,root) %{_libdir}/galera3/libgalera_smm.so %attr(0755,root,root) %dir %{docs} %doc %attr(0644,root,root) %{docs}/COPYING %doc %attr(0644,root,root) %{docs}/README %doc %attr(0644,root,root) %{docs}/README-MySQL %doc %attr(0644,root,root) %{docs}/LICENSE.asio %doc %attr(0644,root,root) %{docs}/LICENSE.crc32c %doc %attr(0644,root,root) %{docs}/LICENSE.chromium %files -n Percona-XtraDB-Cluster-garbd-3 %defattr(-,root,root,-) %config(noreplace,missingok) %{_sysconfdir}/sysconfig/garb %if 0%{?systemd} %attr(0644, root, root) %{_unitdir}/garb.service %attr(0755,root,root) %{_bindir}/garb-systemd %else %attr(0755,root,root) %{_sysconfdir}/init.d/garb %endif %attr(0755,root,root) %{_bindir}/garbd %doc %attr(0644,root,root) %{docs2}/COPYING %doc %attr(0644,root,root) %{docs2}/README %doc %attr(644, root, man) %{_mandir}/man1/garbd.1* %post -n Percona-XtraDB-Cluster-garbd-3 %if 0%{?systemd} %systemd_post garb %endif %preun -n Percona-XtraDB-Cluster-garbd-3 %if 0%{?systemd} %systemd_preun garb %endif %postun -n Percona-XtraDB-Cluster-garbd-3 %if 0%{?systemd} %systemd_postun_with_restart garb %endif %changelog * Thu May 15 2014 Raghavendra Prabhu - Split the packaging for garbd. - Library is now installed in /usr/lib/galera2 with a symlink to /usr/lib/ for compatibility. - Few cleanups. percona-galera-3-3.8-3390/scripts/000077500000000000000000000000001244131713600164715ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/build.sh000077500000000000000000000230421244131713600201300ustar00rootroot00000000000000#!/bin/bash -eu # $Id$ get_cores() { case $OS in "Linux") echo "$(grep -c ^processor /proc/cpuinfo)" ;; "SunOS") echo "$(psrinfo | wc -l)" ;; "Darwin" | "FreeBSD") echo "$(sysctl -n hw.ncpu)" ;; *) echo "CPU information not available: unsupported OS: '$OS'" >/dev/stderr echo 1 ;; esac } usage() { cat << EOF Usage: build.sh [OPTIONS] Options: --stage --last-stage -s|--scratch build everything from scratch -c|--configure reconfigure the build system (implies -s) -b|--bootstap rebuild the build system (implies -c) -o|--opt configure build with debug disabled (implies -c) -d|--debug configure build with debug enabled (implies -c) --dl set debug level for Scons build (1, implies -c) -r|--release release number -m32/-m64 build 32/64-bit binaries for x86 -p|--package build RPM and DEB packages at the end. --with-spread configure build with spread backend (implies -c to gcs) --source build source packages --sb skip actual build, use the existing binaries --scons build using Scons build system (yes) --so Sconscript option -j|--jobs how many parallel jobs to use for Scons (1) "\nSet DISABLE_GCOMM/DISABLE_VSBES to 'yes' to disable respective modules" EOF } OS=$(uname) # disable building vsbes by default DISABLE_VSBES=${DISABLE_VSBES:-"yes"} DISABLE_GCOMM=${DISABLE_GCOMM:-"no"} PACKAGE=${PACKAGE:-"no"} SKIP_BUILD=${SKIP_BUILD:-"no"} RELEASE=${RELEASE:-""} SOURCE=${SOURCE:-"no"} DEBUG=${DEBUG:-"no"} DEBUG_LEVEL=${DEBUG_LEVEL:-"0"} SCONS=${SCONS:-"yes"} SCONS_OPTS=${SCONS_OPTS:-""} export JOBS=${JOBS:-"$(get_cores)"} SCRATCH=${SCRATCH:-"no"} OPT="yes" NO_STRIP=${NO_STRIP:-"no"} WITH_SPREAD="no" RUN_TESTS=${RUN_TESTS:-1} if [ "$OS" == "FreeBSD" ]; then chown=/usr/sbin/chown true=/usr/bin/true epm=/usr/local/bin/epm else chown=/bin/chown true=/bin/true epm=/usr/bin/epm fi EXTRA_SYSROOT=${EXTRA_SYSROOT:-""} if [ "$OS" == "Darwin" ]; then if which -s port && test -x /opt/local/bin/port; then EXTRA_SYSROOT=/opt/local elif which -s brew && test -x /usr/local/bin/brew; then EXTRA_SYSROOT=/usr/local elif which -s fink && test -x /sw/bin/fink; then EXTRA_SYSROOT=/sw fi elif [ "$OS" == "FreeBSD" ]; then EXTRA_SYSROOT=/usr/local fi which dpkg >/dev/null 2>&1 && DEBIAN=${DEBIAN:-1} || DEBIAN=${DEBIAN:-0} if [ "$OS" == "FreeBSD" ]; then CC=${CC:-"gcc48"} CXX=${CXX:-"g++48"} LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-"/usr/local/lib/$(basename $CC)"} else CC=${CC:-"gcc"} CXX=${CXX:-"g++"} fi if ccache -V > /dev/null 2>&1 then echo "$CC" | grep "ccache" > /dev/null || CC="ccache $CC" echo "$CXX" | grep "ccache" > /dev/null || CXX="ccache $CXX" fi export CC CXX LD_LIBRARY_PATH CFLAGS=${CFLAGS:-"-O2"} CXXFLAGS=${CXXFLAGS:-"$CFLAGS"} CPPFLAGS=${CPPFLAGS:-} initial_stage="galerautils" last_stage="galera" gainroot="" TARGET=${TARGET:-""} # default target while test $# -gt 0 do case $1 in --stage) initial_stage=$2 shift ;; --last-stage) last_stage=$2 shift ;; --gainroot) gainroot=$2 shift ;; -b|--bootstrap) BOOTSTRAP="yes" # Bootstrap the build system ;; -c|--configure) CONFIGURE="yes" # Reconfigure the build system ;; -s|--scratch) SCRATCH="yes" # Build from scratch (run make clean) ;; -o|--opt) OPT="yes" # Compile without debug ;; -d|--debug) DEBUG="yes" # Compile with debug NO_STRIP="yes" ;; -r|--release) RELEASE="$2" shift ;; -m32) CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" SCRATCH="yes" TARGET="i686" ;; -m64) CFLAGS="$CFLAGS -m64" CXXFLAGS="$CXXFLAGS -m64" SCRATCH="yes" TARGET="x86_64" ;; -p|--package) PACKAGE="yes" # build binary packages ;; --with*-spread) WITH_SPREAD="$1" ;; --help) usage exit 0 ;; --source) SOURCE="yes" ;; --sb) SKIP_BUILD="yes" ;; --scons) SCONS="yes" ;; --so) SCONS_OPTS="$SCONS_OPTS $2" shift ;; -j|--jobs) JOBS=$2 shift ;; --dl) DEBUG_LEVEL=$2 shift ;; *) if test ! -z "$1"; then echo "Unrecognized option: $1" fi usage exit 1 ;; esac shift done # check whether sudo accepts -E to preserve environment if [ "$PACKAGE" == "yes" ] then echo "testing sudo" if sudo -E $true >/dev/null 2>&1 then echo "sudo accepts -E" SUDO="sudo -E" else echo "sudo does not accept param -E" if [ $(id -ur) != 0 ] then echo "error, must build as root" exit 1 else echo "I'm root, can continue" SUDO="" fi fi fi if [ "$OPT" == "yes" ]; then CONFIGURE="yes"; conf_flags="--disable-debug --disable-dbug"; fi if [ "$DEBUG" == "yes" ]; then CONFIGURE="yes"; fi if [ -n "$WITH_SPREAD" ]; then CONFIGURE="yes"; fi if [ "$CONFIGURE" == "yes" ] && [ "$SCONS" != "yes" ]; then SCRATCH="yes"; fi # Be quite verbose set -x # Build process base directory build_base=$(cd $(dirname $0)/..; pwd -P) get_arch() { if ! [ -z "$TARGET" ] then if [ "$TARGET" == "i686" ] then echo "i386" else echo "amd64" fi elif [ "$OS" == "Darwin" ]; then if file $build_base/gcs/src/gcs.o | grep "i386" >/dev/null 2>&1 then echo "i386" else echo "amd64" fi else if file $build_base/gcs/src/gcs.o | grep "80386" >/dev/null 2>&1 then echo "i386" else echo "amd64" fi fi } build_packages() { local PKG_DIR=$build_base/scripts/packages pushd $PKG_DIR local ARCH=$(get_arch) local WHOAMI=$(whoami) export BUILD_BASE=$build_base export GALERA_VER=$RELEASE if [ $DEBIAN -eq 0 ] && [ "$ARCH" == "amd64" ] then ARCH="x86_64" export x86_64=$ARCH # for epm fi export $ARCH local STRIP_OPT="" [ "$NO_STRIP" == "yes" ] && STRIP_OPT="-g" $SUDO rm -rf $ARCH set +e if [ $DEBIAN -ne 0 ]; then # build DEB ./deb.sh $GALERA_VER elif [ "$OS" == "FreeBSD" ]; then if test "$NO_STRIP" != "yes"; then strip $build_base/{garb/garbd,libgalera_smm.so} fi ./freebsd.sh $GALERA_VER else # build RPM ./rpm.sh $GALERA_VER fi local RET=$? set -e popd if [ $DEBIAN -ne 0 ]; then mv -f $PKG_DIR/$ARCH/*.deb ./ elif [ "$OS" == "FreeBSD" ]; then mv -f $PKG_DIR/*.tbz ./ else mv -f $PKG_DIR/*.rpm ./ fi return $RET } build_source() { local module="$1" shift local build_dir="$build_base/$module" pushd $build_dir if [ ! -x "configure" ]; then ./bootstrap.sh; fi if [ ! -s "Makefile" ]; then ./configure; fi local src_base_name="lib${module}-" rm -rf "${src_base_name}"*.tar.gz make dist || (echo $?; echo "make dist failed"; echo) local ret=$(ls "${src_base_name}"*.tar.gz) popd echo $build_dir/$ret } build_sources() { local module local srcs="" for module in "galerautils" "gcomm" "gcs" "galera" do src=$(build_source $module | tail -n 1) srcs="$srcs $src" done local ret="galera-source-r$RELEASE.tar" tar --transform 's/.*\///' -cf $ret $srcs \ "source/README" "source/COPYING" "source/build.sh" # return absolute path for scripts echo $PWD/$ret } pushd "$build_base" #GALERA_REV="$(svnversion | sed s/\:/,/g)" #if [ "$GALERA_REV" == "exported" ] #then GALERA_REV=$(git log --pretty=oneline | wc -l) || \ GALERA_REV=$(bzr revno --tree -q) || \ GALERA_REV=$(svn info >&/dev/null && svnversion | sed s/\:/,/g) || \ GALERA_REV=$(echo "XXXX") export GALERA_REV #fi popd #if [ -z "$RELEASE" ] #then # RELEASE=$GALERA_REV #fi if [ "$SCONS" == "yes" ] # Build using Scons then # Scons variant dir, defaults to GALERA_SRC export SCONS_VD=$build_base scons_args="-C $build_base revno=$GALERA_REV tests=$RUN_TESTS" [ -n "$TARGET" ] && scons_args="$scons_args arch=$TARGET" [ -n "$RELEASE" ] && scons_args="$scons_args version=$RELEASE" [ "$DEBUG" == "yes" ] && scons_args="$scons_args debug=$DEBUG_LEVEL" [ -n "$EXTRA_SYSROOT" ] && scons_args="$scons_args extra_sysroot=$EXTRA_SYSROOT" if [ "$SCRATCH" == "yes" ] then scons -Q -c --conf=force $scons_args $SCONS_OPTS fi if [ "$SKIP_BUILD" != "yes" ] then scons $scons_args -j $JOBS $SCONS_OPTS fi elif test "$SKIP_BUILD" == "no"; then # Build using autotools echo "Error: autotools not supported anymore! Nothing was built." exit 1 fi # SKIP_BUILD / SCONS if test "$PACKAGE" == "yes" then build_packages fi if test "$SOURCE" == "yes" then build_sources fi percona-galera-3-3.8-3390/scripts/mysql/000077500000000000000000000000001244131713600176365ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/LICENSE000066400000000000000000000000661244131713600206450ustar00rootroot00000000000000See ./mysql/LICENSE.mysql and ./galera/LICENSE.galera percona-galera-3-3.8-3390/scripts/mysql/LICENSE.mysql000066400000000000000000000451771244131713600220250ustar00rootroot00000000000000 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. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YYYY NAME OF AUTHOR This program is free software; you can redistribute it and/or modify it under the terms of the 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) 19YY 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. SIGNATURE OF TY COON, 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. percona-galera-3-3.8-3390/scripts/mysql/QUICK_START000066400000000000000000000073231244131713600214170ustar00rootroot00000000000000MySQL/Galera Demo Quick Start Guide =================================== version 0.8.x This is an informal guide to quick setup of MySQL/Galera demo cluster for experienced MySQL users. For more detailed information please see README. MySQL/Galera cluster is a multi-master MySQL server cluster. It provides - True high-availability (no committed transaction is lost, no single point of failure) - Performance scalability even for write-intensive loads. - Semantics of a single MySQL server. This distribution is all you need to install and run MySQL/Galera cluster. You don't need to be root or to uninstall/disable any software. MYSQL CLUSTER IN 3 EASY STEPS: Suppose you have three networked computers Node1, Node2, Node3 of roughly the same performance and Node1 has IP address 192.168.1.1 1. Copy and unpack this distribution on each node to the directory of your choice (hereafter INSTALL_DIR). The location must have at least 1Gb of free space for database files. 2. Start first MySQL server on Node1: /mysql-galera -g gcomm:// start 3. Start remaining nodes: /mysql-galera -g gcomm://192.168.1.1 start NOTE1: First node of the cluster is started by supplying an empty gcomm address. When you want to add a node to a cluster, you must supply an address of any working cluster node. NOTE2: Beginning from the second node, each node you start will automatically copy the contents of the database from one of the working nodes. Allow some time for it to complete - it depends on the size of the database. mysql-galera script will return when copying is done and node is ready to use. See README for details. That's it. You've got a multi-master MySQL/Galera cluster. Node1, Node2 and Node3 will now synchronize all writes with the rest of the cluster. Root password is 'rootpass' and there is also 'test' user with password 'testpass' and privileges on 'test.*'. You can now populate your database with mysqldump by loading your database dump to (any) one of the nodes. LIMITATIONS: 1. Currently replication works only with InnoDB storage engine. Any writes to tables of other types, including system (mysql.*) tables are not replicated. (GRANT command is an exception and is replicated) 2. Rows in tables without primary keys may appear in different order on different nodes. As a result SELECT...LIMIT... may return slightly different sets. DELETE operation on such tables is not supported. 3. Unsupported in this release: commands: LOAD DATA may result in a transaction that is too big and will be rejected. features: LOCKed sessions and locking functions. Use at your own risk. QUICK ANSWERS: 1. Yes, it works anywhere TCP works, including Amazon EC2(TM). 2. Yes, it'd be faster if there were a dedicated network for replication connections and a separate network for MySQL client connections. 3. Yes, it is highly configurable and flexible. For more info see README, mysql-galera --help and my.cnf that comes with the distribution. 4. If your application cannot utilize more than one server, you can use TCP connection balancer like GLB (http://www.codership.com/products/downloads) or pen (http://siag.nu/pen/). Note however, that SQL traffic balancing is very CPU consuming (due to high number of small packets), so it is recommended to have a dedicated machine for load balancer. 5. The patch for MySQL can be obtained at https://code.launchpad.net/codership-mysql 6. Galera 0.8 sources can be obtained at https://code.launchpad.net/galera Please direct all your suggestions, opinions and inquiries to info@codership.com or (better) our mailing list at http://groups.google.com/group/codership-team percona-galera-3-3.8-3390/scripts/mysql/README000066400000000000000000000606711244131713600205300ustar00rootroot00000000000000Codership Oy http://www.codership.com DISCLAIMER THIS SOFTWARE PROVIDED "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. IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. Trademark Information. MySQL is a trademark or registered trademark of Sun Microsystems, Inc. or its subsidiaries in the US and other countries. Other marks are the property of their respective owners. Licensing Information. Please see ./mysql/LICENSE.mysql and ./galera/LICENSE.galera Project source code can be found at wsrep API: https://launchpad.net/wsrep/ MySQL patch: https://launchpad.net/codership-mysql/ Galera libs: https://launchpad.net/galera/ ABOUT THIS DOCUMENT This document covers issues specific to this MySQL/Galera demo distribution. It does not cover the use or administration of MySQL server per se. The reader is assumed to know how to install, configure, administer and use MySQL server. MYSQL/GALERA v23.x demo package CONTENTS: ========= 0. WHAT IS MYSQL/GALERA CLUSTER 1. CLUSTER SETUP 1.1 INSTALLATION 1.2 CLUSTER URL 1.3 STARTING THE FIRST NODE OF A CLUSTER 1.4 STARTING REMAINING NODES 2. USING THE CLUSTER 2.1 LOADING DATA TO A CLUSTER 2.2 CONNECTING APPLICATION TO A CLUSTER 2.3 LOAD BALANCER 2.4 ADDING NEW NODE TO A CLUSTER 2.5 A "REFERENCE NODE" 2.6 "SPLIT-BRAIN" CONDITION 3. CONFIGURATION 3.1 MANDATORY MYSQL OPTIONS 3.2 OPTIONAL OPTIMIZATIONS 3.3 WSREP OPTIONS 3.4 CONFIGURING LOCAL MYSQL CLIENTS 3.5 FIREWALLS 4. Using MySQL/Galera in Amazon EC2 5. LIMITATIONS 0. WHAT IS MYSQL/GALERA CLUSTER MySQL/Galera cluster is a synchronous multi-master MySQL server cluster. Cluster nodes are connected to each other in a N-to-N fashion through a group communication backend which provides automatic reconfiguration in the event of a node failure or a new node added to cluster: ,--------. ,--------. ,--------. | mysqld |----| mysqld |<---| client | `--------' `--------' `--------' \ / ,--------. ,--------. | mysqld |<---| client | `--------' `--------' With few exceptions each cluster node can be used like a standalone MySQL server and supports most of MySQL features including transactions, triggers and stored procedures. Node states are synchronized by replicating transaction changes at commit time. The cluster is virtually synchronous: this means that each node commits transactions in exactly the same order, although not necessarily at the same physical moment. (The latter is not that important as it may seem, since in most cases DBMS gives no guarantee on when the transaction is actually processed.) Built-in flow control keeps nodes within fraction of a second from each other, this is more than enough for most practical purposes. Main features of MySQL/Galera cluster: * Truly highly available: no committed transaction is ever lost in case of a node crash. All nodes always have consistent state. * True multi-master: all cluster nodes can modify the same table concurrently. * Highly transparent: the cluster is intended as a drop-in replacement for a single MySQL server. (See LIMITATIONS below) * Scalable even with WRITE-intensive applications. This demo distribution contains all software you'll need to setup MySQL/Galera cluster. It is essentially a self-contained MySQL server installation with its own configuration file, data directory and preconfigured empty database. You don't need administrative privileges or to uninstall/disable previously installed MySQL server to use this distribution. 1. CLUSTER SETUP To setup MySQL/Galera cluster you will need several networked computers - one for each mysqld instance you plan to use. For best performance those computers should be of approximately same configuration: Galera replication is synchronous and one overloaded machine may slow down the whole cluster. This however depends on load distribution. The node that does not handle client connections can be considerably slower. It takes 3 steps to set up the cluster: 1) Copy this distribution to all prospective nodes of the cluster and unpack it to location of your choice. 2) Start the first node to begin a new cluster. 3) Start remaining nodes pointing to the first one. (NOTE: You can easily set up the cluster on a single computer. However this makes little sense, as you won't see the the benefits of high availability and scalability. Hence it is not covered by this document.) 1.1 INSTALLATION Just copy and unpack the distribution on the prospective cluster nodes to wherever you have privileges. The distribution was designed to be able to run on most systems without reconfiguration. It is a self-contained MySQL installation and comes with its own data directory and a preconfigured empty database with users 'root' (password 'rootpass') and 'test' (password 'testpass', privileges on schema 'test'). As a result default installation will require at least 1Gb of free space for InnoDB files (will be created on first start). This requirement, as well as other MySQL and Galera options can be changed by editing configuration file which can be found at /mysql/etc/my.cnf. Please see CONFIGURATION chapter for the details on editable parameters. 1.2 CLUSTER URL Cluster URL is a connection handle that will be used by a new node to connect to the rest of the cluster. Its form is backend-specific and backend is determined by URL schema. Default is 'dummy' which means no replication. This demo comes with a distributed group communication backend which schema is 'gcomm'. 1.3 STARTING THE FIRST NODE OF A CLUSTER /mysql-galera is a special MySQL startup script that sets proper options (including data directory path) for mysqld. If you're running it as a superuser, you have to make sure there is 'mysql' user in the system and it has sufficient privileges on the installation directory (see MySQL Manual about running mysqld as root). The first node of a cluster has nowhere to connect to, therefore it has to start with an empty cluster address (note that it still initializes gcomm backend): /mysql-galera -g gcomm:// start 1.4 STARTING REMAINING NODES To add another node to the cluster it must be given the address of one of the existing cluster nodes. Thus, if the first cluster node has IP address 192.168.1.1, then the second will be started like this: /mysql-galera -g gcomm://192.168.1.1 start The third node can use either the first or the second node address and so on. It might take few minutes to start mysqld for the first time as it will have to create required InnoDB files. For full description of mysql-galera options and commands see: /mysql-galera --help 2. USING THE CLUSTER After you have successfully started all cluster nodes, the cluster is ready to use. From the client point of view each cluster node works like a usual MySQL server - client-side application does not have to be changed in any way. Each node can be accessed independently and asynchronously. Just direct SQL load to any one or more of the cluster nodes. For most practical purposes you can treat MySQL/Galera cluster as a single MySQL server listening on multiple interfaces with the exception that you might see transaction deadlocks where you previously didn't. 2.1 LOADING DATA TO CLUSTER Initially distribution database is empty. You can populate it by loading the dump of your data to any one of the nodes. It will be automatically replicated to others. Please note that this release supports only InnoDB storage engine. 2.2 CONNECTING APPLICATION TO CLUSTER As was mentioned above, for the client application each node looks like a normal MySQL server and can be used independently. This creates considerable flexibility in the way the cluster can be utilized. The approaches can be categorized in three groups: 1) Seeking High Availability only. It is similar to traditional MySQL master-slave replication. In this case client application connects to only one node, the rest serving as hot backups / read-only slaves: ,-------------. | application | `-------------' | | | DB backups/read-only slaves ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <===== cluster nodes =====> In the case of primary node failure application can instantly switch to another node without any preparations. This is also a most transparent mode: COMMITs will never return deadlocks and table locks can be used too. 2) Seeking High Availability and improved performance through uniform load distribution. If there are several client connections to the database, they can be uniformly distributed between cluster nodes resulting in better performance. The exact degree of performance improvement depends on application's SQL profile. Note, that transaction rollback rate may also increase. ,-------------. | clients | `-------------' | | | | ,-------------. | application | `-------------' / | \ ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <===== cluster nodes =====> In the case of a node failure application can keep on using the remaining healthy nodes. In this setup application can also be clustered with a dedicated application instance per database node, thus achieving HA not only for the database, but for the whole application stack: ,-------------. | clients | `-------------' // || \\ ,------. ,------. ,------. | app1 | | app2 | | app3 | `------' `------' `------' | | | ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <====== cluster nodes ======> 3) Seeking High Availability and improved performance through smart load distribution. Uniform load distribution can cause undesirably high rollback rate. Directing transactions which access the same set of tables to the same node can considerably improve performance by reducing the number of rollbacks. Also, if your application can distinguish between read/write and read-only transactions, the following configuration may be quite efficient: ,---------------------. | application | `---------------------' writes / | reads \ reads ,-------. ,-------. ,-------. | node1 | | node2 | | node3 | `-------' `-------' `-------' <========= cluster nodes =========> 2.3 LOAD BALANCER If your application cannot utilize several database servers (most don't) you will need to use SQL proxy or a TCP load balancer to distribute load between the MySQL/Galera nodes. This is needed not only to increase performance, but also for a quick switch in case of a node failure. If performance of your application is DBMS-bound, you can run the balancer on the same machine as application/client. Be aware, however, that SQL load balancing might be a CPU hungry operation: usually SQL traffic consists of many small packets. For best results we recommend to carefully examine CPU consumption of the balancer and if needed dedicate a separate machine for it. Unlike traditional MySQL master-slave cluster, MySQL/Galera cluster does not require any SQL traffic filtering, it is highly transparent and plain TCP connection balancer will suffice. TCP connection balancers that were successfully used with MySQL/Galera: - Pen (http://siag.nu/pen/) - GLB (http://www.codership.com/en/downloads/glb) 2.4 ADDING NEW NODE TO A CLUSTER With 0.7 series of releases Codership removes the main obstacle towards using MySQL/Galera in production: inability to add/replace nodes in the working cluster. This distribution features automatic state snapshot transfer to newly joined node. Until node receives state snapshot it won't execute any queries. Detailed state snapshot transfer sequence diagram can be found in http://www.codership.com/files/presentations/Galera_OSC_2009.pdf The process of joining new node into the cluster consists of two phases: 1) State snapshot transfer (SST) from an established cluster member. Depending on the SST method neither joining node, nor SST donor can apply any transactions for the duration of this phase. Transactions replicated by other nodes are buffered in the queue. 2) Catch-up phase when both donor and joiner try to catch up with the cluster by applying transactions buffered in the queue. Using them as working nodes should be avoided. Duration of this phase depends on the load profile and duration of the first phase. NOTE: Transaction buffering is currently happening in memory, so prepare enough swap space. By default cluster chooses the most suitable node to receive state transfer from. There is also an option wsrep_sst_donor to specify desired state snapshot source in my.cnf or on the command line. See CONFIGURATION section for descriptions of all relevant configuration options. In most situations (like cluster on EC2) this distribution should work with default settings. At this point there is only one state transfer method supported and it is based on mysqldump. Although it is relatively slow, it provides complete cloning of the donor state, including system tables and thus is most compliant. 2.5 A "REFERENCE NODE" For practical purposes we recommend to reserve a "reference node" in the cluster. A "reference node" is a node that does not receive SQL load. Having such node in a cluster serves several purposes: 1) Data consistency: since this node does not process any SQL load on its own, it has the lowest probability of transaction conflicts and therefore - indeterministic conflict resolution. In the event of discovered database inconsistencies in the cluster this node will have the most relevant database. 2) Data safety: since this node does not process any SQL load on its own, it has the lowest probability of failing with catastrophic consequences. In the event of total cluster failure (e.g. blackout) this will be the best node to restore cluster from. 3) High availability: a reference node can serve as a dedicated state snapshot donor. Since it does not serve any clients, they won't experience service interruptions and load balancer won't need reconfiguration during SST. Even with the current TCP-based group communication the overhead of having one extra silent node is negligible for most loads. 2.6 "SPLIT-BRAIN" CONDITION Galera cluster is fully distributed and does not use any sort of centralized arbitrator, thus having no single point of failure. However, like any cluster of that kind it may fall to a dreaded "split-brain" condition where half or more nodes of the cluster suddenly disappear (e.g. due to network failure). In general case, having no information about the fate of disappeared nodes, remaining nodes cannot continue to process requests and modify their states. While such situation is generally considered negligibly probable in a multi-node cluster (normally nodes fail one by one), in 2-node cluster a single node failure can lead to this, thus making 3 nodes a minimum requirement for a highly-available cluster. Dedicated Galera packages (not this distribution) contain a lightweight "arbitrator" daemon which can serve as an odd node substitute in situations where cluster size is limited to 2 real nodes. 3. CONFIGURATION Each MySQL/Galera node is configured just like the usual MySQL server, we just added some configuration variables to my.cnf. In addition some options can be passed to mysql-galera startup script (see mysql-galera --help). 3.1 MANDATORY MYSQL OPTIONS binlog_format=ROW This option is required to use row-level replication as opposed to statement-level. For performance and consistency considerations don't change that. As a side effect, binlog, if turned on, can be ROW only. In future this option won't have special meaning. innodb_autoinc_lock_mode=2 This is a required parameter. Without it INSERTs into tables with AUTO_INCREMENT column may fail. autoinc lock modes 0 and 1 can cause unresolved deadlock, and make system unresponsive. innodb_locks_unsafe_for_binlog=1 This setting is required for relaiable parallel applying operation. Mandatory options are hardcoded both in distribution's my.cnf file and in mysql-galera script. 3.2 OPTIONAL OPTIMIZATIONS While not required for correct operation of MySQL/Galera cluster, the following options may be safely set due to the guarantees of synchronous replication: innodb_flush_log_at_trx_commit=0 3.3 WSREP OPTIONS Here WSREP stands for Write-Set REPlication - a synchronous replication API that Codership is developing for transactional databases. Galera is a library that implements WSREP services. Default values are shown. All options are optional except for wsrep_provider and wsrep_cluster_address. wsrep_provider=none A full path to the library that implements WSREP interface. If none is specified, the server behaves almost like a normal mysqld, with slight overhead. mysql-galera script automatically substitutes it to point to Galera implementation shipped with the distribution. It can be overridden with WSREP environment variable. wsrep_provider_options= Provider-specific option string. See http://www.codership.com/wiki for details. wsrep_cluster_address="dummy://" Group Communication System address. Depends on the WSREP provider. This distribution recognizes "dummy://" and "gcomm://
[:port]" Default port is 4567. mysql> set global wsrep_cluster_address=
; will (re)establish connection to ADDRESS. This can be used to change cluster connection in runtime. wsrep_cluster_name="my_wsrep_cluster" Logical cluster name, must be the same for all nodes of the cluster. wsrep_node_name= Human readable node name. Defaults to hostname. wsrep_slave_threads=1 Number of threads dedicated to processing of writesets from other nodes. For better performance we recommend few per CPU core. wsrep_dbug_option Options for the built-in DBUG library (independent from what MySQL uses). Empty by default. Not used in 0.8. wsrep_debug=0 Enable debug-level logging. wsrep_convert_LOCK_to_trx=0 Implicitly convert locking sessions into transactions inside mysqld. By itself it does not mean support for locking sessions, but it prevents the database from going into logically inconsistent state. Disabled by default because of possible memory issues with DB dumps that contain LOCK statements. wsrep_retry_autocommit=1 Retry autocommit queries and single statement transactions should they fail certification test. This is analogous to rescheduling an autocommit query should it go into deadlock with other transactions in the database lock manager. wsrep_auto_increment_control=1 Automatically adjust auto_increment_increment and auto_increment_offset variables based on the number of nodes in the cluster. Significantly reduces certification conflic rate for INSERTS. wsrep_drupal_282555_workaround=1 MySQL seems to have an obscure bug when INSERT into table with AUTO_INCREMENT column with NULL value for that column can fail with a duplicate key error. When this option is on, it retries such INSERTs. Required for stable Drupal operation. Documented at: http://bugs.mysql.com/bug.php?id=41984 http://drupal.org/node/282555 wsrep_sst_method=mysqldump What method to use to copy database state to a newly joined node. Currently supported methods: - mysqldump: generally slow (except on small datasets), but most tested - rsync: the fastest method, especially on large datasets - rsync_wan: same as rsync, but uses deltaxfer to minimize network traffic. wsrep_sst_receive_address= Address at which this node wants to receive state snapshot. Defaults to mysqld bind address, and if that is not specified (0.0.0.0) - to the first IP of eth0 + mysqld bind port. wsrep_sst_auth= Authentication information needed for state transfer. Depends on the state transfer method. For mysqldump-based SST it is : and should be the same on all nodes - it is used to authenticate with both state snapshot receiver and state snapshot donor. In this distribution it is preconfigured to "root:rootpass". wsrep_sst_donor= A name of the node which should serve as state snapshot donor. This allows to control which node will serve state snapshot request. By default the most suitable node is chosen by GCS. 3.4 CONFIGURING LOCAL MYSQL CLIENTS This MySQL/Galera distribution runs mysqld in the "sandbox". Thus mysql clients won't find mysqld socket at default system location. Running mysql client without explicitly specifying socket or port (via --socket or --host/--port options) may, therefore, result in the following: $ mysql -uroot -prootpass ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) Most applications that use libmysqlclient to connect to MySQL server can be instructed to look in the correct place by adding a following section to system-wide my.cnf file: [client] socket = /mysql/var/mysqld.sock 3.5 FIREWALLS If there are any firewalls used, they should be configured to allow connections between the nodes at the following ports: 3306 - for mysqldump state snapshot transfer 4567 - for replication traffic E.g. to configure iptables to allow connections from a local subnet: iptables -A INPUT -i eth0 -p tcp -m tcp \ --source 192.168.0.1/24 --dport 3306 -j ACCEPT iptables -A INPUT -i eth0 -p tcp -m tcp \ --source 192.168.0.1/24 --dport 4567 -j ACCEPT Substitute real values for IP address of your node and netmask. Better yet, use VPN. 4. Using MySQL/Galera distribution in Amazon EC2 MySQL/Galera works anywhere TCP/IP works. Therefore using MySQL/Galera distribution in Amazon EC2 environment is no different than in LAN. Just launch several instances of your favorite AMI, copy and unpack the distribution, and start the servers. Don't forget to use external addresses if your nodes are running in different accessibility zones (obviously running in different accessibility zones degrades performance somewhat). NOTE: this distribution may be binary incompatible with some older Linux distributions. Please use CentOS 5.0 or newer. 5. LIMITATIONS 1) Currently replication works only with InnoDB storage engine. Any writes to tables of other types, including system (mysql.*) tables are not replicated. However, DDL statements are replicated in statement level, and changes to mysql.* tables will get replicated that way. So, you can safely issue: CREATE USER..., but issuing: INSERT INTO mysql.user..., will not be replicated. 2) DELETE operation is not supported on tables without primary keys. Rows in tables without primary keys may appear in different order on different nodes. As a result SELECT...LIMIT... may return slightly different sets. 3) Unsupported queries: * LOAD DATA size is limited to ~1Gb * lock functions (GET_LOCK(), RELEASE_LOCK()... ) 4) Locking sessions (LOCK TABLES...UNLOCK) are not supported in multi-master mode. However if there's only one node that executes locking sessions, then it'll work. 5) Transaction isolation level should be REPEATABLE_READ (the default). Galera implements implicit snapshot isolation for cluster wide transactions. 6) Due to cluster level optimistic concurrency control, transaction issuing COMMIT may still be aborted at that stage. There can be two transactions writing to same rows and committing in separate cluster nodes, and only one of the them can successfully commit. The failing one, will be aborted. For cluster level aborts, MySQL/galera cluster gives back deadlock error code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)). 7) Query log cannot be directed to table. If you enable query logging, you must forward the log to a file: log_output = FILE Use general_log and general_log_file to choose query logging and the log file name 8) XA transactions can not be supported due to possible rollback on commit. percona-galera-3-3.8-3390/scripts/mysql/build.sh000077500000000000000000000631731244131713600213060ustar00rootroot00000000000000#!/bin/bash -ex if test -z "$MYSQL_SRC" then echo "MYSQL_SRC variable pointing at MySQL/wsrep sources is not set. Can't continue." exit -1 fi use_mysql_5.1_sources() { MYSQL_MAJOR="5.1" export MYSQL_MAJOR # for DEB build export MYSQL_MAJOR_VER="5" export MYSQL_MINOR_VER="1" MYSQL_VER=`grep AC_INIT $MYSQL_SRC/configure.in | awk -F '[' '{ print $3 }' | awk -F ']' '{ print $1 }'` } use_mariadb_5.1_sources() { use_mysql_5.1_sources } use_mysql_5.5_sources() { export MYSQL_MAJOR_VER=`grep MYSQL_VERSION_MAJOR $MYSQL_SRC/VERSION | cut -d = -f 2` export MYSQL_MINOR_VER=`grep MYSQL_VERSION_MINOR $MYSQL_SRC/VERSION | cut -d = -f 2` export MYSQL_PATCH_VER=`grep MYSQL_VERSION_PATCH $MYSQL_SRC/VERSION | cut -d = -f 2` MYSQL_MAJOR=$MYSQL_MAJOR_VER.$MYSQL_MINOR_VER export MYSQL_MAJOR # for DEB build MYSQL_VER=$MYSQL_MAJOR.$MYSQL_PATCH_VER } if test -f "$MYSQL_SRC/configure.in" then use_mysql_5.1_sources elif test -f "$MYSQL_SRC/VERSION" then use_mysql_5.5_sources else echo "Unknown MySQL version in MYSQL_SRC path. Versions 5.1 and 5.5 are supported. Can't continue." exit -1 fi # Initializing variables to defaults uname -m | grep -q i686 && CPU=pentium || CPU=amd64 # this works for x86 Solaris too BOOTSTRAP=no DEBUG=no DEBUG_LEVEL=0 GALERA_DEBUG=no NO_STRIP=no RELEASE="" TAR=no BIN_DIST=no PACKAGE=no INSTALL=no CONFIGURE=no SKIP_BUILD=no SKIP_CONFIGURE=no SKIP_CLIENTS=no SCRATCH=no SCONS="yes" JOBS=1 GCOMM_IMPL=${GCOMM_IMPL:-"galeracomm"} TARGET="" MYSQLD_BINARY="mysqld" SYNC_BEFORE_PACK=${SYNC_BEFORE_PACK:-""} OS=$(uname) case "$OS" in "Linux") JOBS=$(grep -c ^processor /proc/cpuinfo) ;; "SunOS") JOBS=$(psrinfo | wc -l) ;; "Darwin" | "FreeBSD") JOBS="$(sysctl -n hw.ncpu)" ;; *) echo "CPU information not available: unsupported OS: '$OS'";; esac if [ "$OS" == "FreeBSD" ]; then CC=${CC:-"gcc48"} CXX=${CXX:-"g++48"} LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-"/usr/local/lib/$(basename $CC)"} else CC=${CC:-"gcc"} CXX=${CXX:-"g++"} fi CC=${CC:+$(which "$CC" 2>/dev/null)} CXX=${CXX:+$(which "$CXX" 2>/dev/null)} export CC CXX LD_LIBRARY_PATH EXTRA_SYSROOT=${EXTRA_SYSROOT:-""} if [ "$OS" == "Darwin" ]; then if which -s port && test -x /opt/local/bin/port; then EXTRA_SYSROOT=/opt/local elif which -s brew && test -x /usr/local/bin/brew; then EXTRA_SYSROOT=/usr/local elif which -s fink && test -x /sw/bin/fink; then EXTRA_SYSROOT=/sw fi elif [ "$OS" == "FreeBSD" ]; then EXTRA_SYSROOT=/usr/local fi usage() { cat < --last-stage -s|--scratch build everything from scratch -c|--configure reconfigure the build system (implies -s) -b|--bootstap rebuild the build system (implies -c) -o|--opt configure build with debug disabled (implies -c) -m32/-m64 build 32/64-bit binaries on x86 -d|--debug configure build with debug enabled (implies -c) -dl|--debug-level set debug level (1, implies -c) --gd|--galera-debug only galera debug build (optimized mysqld) --with-spread configure build with Spread (implies -c) --no-strip prevent stripping of release binaries -j|--jobs number of parallel compilation jobs (${JOBS}) -p|--package create DEB/RPM packages (depending on the distribution) --bin create binary tar package -t|--tar create a demo test distribution --sb|--skip-build skip the actual build, use the existing binaries --sc|--skip-configure skip configure --skip-clients don't include client binaries in test package --scons use scons to build galera libraries (yes) -r|--release , otherwise revisions will be used -s and -b options affect only Galera build. EOF } # Parse command line while test $# -gt 0 do case $1 in -b|--bootstrap) BOOTSTRAP="yes" # Bootstrap the build system CONFIGURE="yes" ;; --bin) BIN_DIST="yes" ;; -c|--configure) CONFIGURE="yes" # Reconfigure the build system ;; -s|--scratch) SCRATCH="yes" # Build from scratch (run make clean) ;; -o|--opt) OPT="yes" # Compile without debug ;; -d|--debug) DEBUG="yes" # Compile with debug NO_STRIP="yes" # Don't strip the binaries ;; --dl|--debug-level) shift; DEBUG_LEVEL=$1 ;; --gd|--galera-debug) GALERA_DEBUG="yes" ;; -r|--release) RELEASE="$2" # Compile without debug shift ;; -t|--tar) TAR="yes" # Create a TGZ package ;; -i|--install) INSTALL="yes" ;; -p|--package) PACKAGE="yes" # Create a DEB package CONFIGURE="yes" # don't forget to reconfigure with --prefix=/usr ;; -j|--jobs) shift; JOBS=$1 ;; --no-strip) NO_STRIP="yes" # Don't strip the binaries ;; --with*-spread) WITH_SPREAD="$1" ;; -m32) CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" CONFIGURE="yes" CPU="pentium" TARGET="i686" ;; -m64) CFLAGS="$CFLAGS -m64" CXXFLAGS="$CXXFLAGS -m64" CONFIGURE="yes" CPU="amd64" TARGET="x86_64" ;; --sb|--skip-build) SKIP_BUILD="yes" ;; --sc|--skip-configure) SKIP_CONFIGURE="yes" ;; --skip-clients) SKIP_CLIENTS="yes" ;; --scons) SCONS="yes" ;; --help) usage exit 0 ;; *) echo "Unrecognized option: $1" usage exit 1 ;; esac shift done if [ "$PACKAGE" == "yes" -a "$OS" == "Linux" ] then # check whether sudo accepts -E to preserve environment echo "testing sudo" if sudo -E $(which epm) --version >/dev/null 2>&1 then echo "sudo accepts -E" SUDO_ENV="sudo -E" SUDO="sudo" else echo "sudo does not accept param -E" if [ $(id -ur) != 0 ] then echo "error, must build as root" exit 1 else SUDO_ENV="" SUDO="" echo "I'm root, can continue" fi fi # If packaging with epm, make sure that mysql user exists in build system to # get file ownerships right. echo "Checking for mysql user and group for epm:" getent passwd mysql >/dev/null if [ $? != 0 ] then echo "Error: user 'mysql' does not exist" exit 1 else echo "User 'mysql' ok" fi getent group mysql >/dev/null if [ $? != 0 ] then echo "Error: group 'mysql' doest not exist" exit 1 else echo "Group 'mysql' ok" fi fi if [ "$OPT" == "yes" ]; then CONFIGURE="yes"; fi if [ "$DEBUG" == "yes" ]; then CONFIGURE="yes"; fi if [ "$INSTALL" == "yes" ]; then TAR="yes"; fi if [ "$SKIP_BUILD" == "yes" ]; then CONFIGURE="no"; fi which dpkg >/dev/null 2>&1 && DEBIAN=1 || DEBIAN=0 # export command options for Galera build export BOOTSTRAP CONFIGURE SCRATCH OPT DEBUG WITH_SPREAD CFLAGS CXXFLAGS \ PACKAGE CPU TARGET SKIP_BUILD RELEASE DEBIAN SCONS JOBS DEBUG_LEVEL set -eu # Absolute path of this script folder BUILD_ROOT=$(cd $(dirname $0); pwd -P) GALERA_SRC=${GALERA_SRC:-$BUILD_ROOT/../../} # Source paths are either absolute or relative to script, get absolute MYSQL_SRC=$(cd $MYSQL_SRC; pwd -P; cd $BUILD_ROOT) GALERA_SRC=$(cd $GALERA_SRC; pwd -P; cd $BUILD_ROOT) if [ "$MYSQL_MAJOR" = "5.1" ] then MYSQL_BUILD_DIR="$MYSQL_SRC" else [ "$DEBUG" == "yes" ] \ && MYSQL_BUILD_DIR="$MYSQL_SRC/build_debug" \ || MYSQL_BUILD_DIR="$MYSQL_SRC/build_release" fi ###################################### ## ## ## Build Galera ## ## ## ###################################### # Also obtain SVN revision information if [ "$TAR" == "yes" -o "$BIN_DIST" == "yes" ] then cd $GALERA_SRC debug_opt="" if [ $GALERA_DEBUG == "yes" ] then debug_opt="-d" fi scripts/build.sh $debug_opt # options are passed via environment variables GALERA_REV=$(bzr revno --tree -q) || \ GALERA_REV=$(svn info >&/dev/null && svnversion | sed s/\:/,/g) || \ GALERA_REV=$(echo "XXXX") fi ###################################### ## ## ## Build MySQL ## ## ## ###################################### # Obtain MySQL version and revision number cd $MYSQL_SRC WSREP_REV=$(bzr revno --tree -q) || \ WSREP_REV="XXXX" # this does not work on an unconfigured source MYSQL_VER=$(grep '#define VERSION' $MYSQL_SRC/include/config.h | sed s/\"//g | cut -d ' ' -f 3 | cut -d '-' -f 1-2) if [ "$PACKAGE" == "yes" ] || [ "$BIN_DIST" == "yes" ] then # fetch and patch pristine sources cd ${TMPDIR:-/tmp} mysql_tag=mysql-$MYSQL_VER if [ "$SKIP_BUILD" == "no" ] || [ ! -d $mysql_tag ] then mysql_orig_tar_gz=$mysql_tag.tar.gz url2=http://ftp.sunet.se/pub/unix/databases/relational/mysql/Downloads/MySQL-$MYSQL_MAJOR url1=ftp://sunsite.informatik.rwth-aachen.de/pub/mirror/www.mysql.com/Downloads/MySQL-$MYSQL_MAJOR if [ ! -r $mysql_orig_tar_gz ] then echo "Downloading $mysql_orig_tar_gz... currently works only for 5.1.x" wget -N $url1/$mysql_orig_tar_gz || wget -N $url2/$mysql_orig_tar_gz fi echo "Getting wsrep patch..." patch_file=$(${BUILD_ROOT}/get_patch.sh $mysql_tag $MYSQL_SRC) echo "Patching source..." rm -rf $mysql_tag # need clean sources for a patch tar -xzf $mysql_orig_tar_gz cd $mysql_tag/ patch -p1 -f < $patch_file >/dev/null || : # chmod a+x ./BUILD/*wsrep CONFIGURE="yes" else cd $mysql_tag/ fi MYSQL_SRC=$(pwd -P) MYSQL_BUILD_DIR=$MYSQL_SRC if [ "$CONFIGURE" == "yes" ] then echo "Regenerating config files" time ./BUILD/autorun.sh fi fi echo "Building mysqld" export WSREP_REV export MAKE="make -j$JOBS" if [ "$SKIP_BUILD" == "no" ] then if [ "$CONFIGURE" == "yes" ] && [ "$SKIP_CONFIGURE" == "no" ] then rm -f config.status BUILD_OPT="" if [ "$OS" == "FreeBSD" ]; then # don't use INSTALL_LAYOUT=STANDALONE(default), it assumes prefix=. CMAKE_LAYOUT_OPTIONS=( -DCMAKE_INSTALL_PREFIX="/usr/local" \ -DINSTALL_LAYOUT=RPM \ -DMYSQL_UNIX_ADDR="/tmp/mysql.sock" \ -DINSTALL_BINDIR="bin" \ -DINSTALL_DOCDIR="share/doc/mysql" \ -DINSTALL_DOCREADMEDIR="share/doc/mysql" \ -DINSTALL_INCLUDEDIR="include/mysql" \ -DINSTALL_INFODIR="info" \ -DINSTALL_LIBDIR="lib/mysql" \ -DINSTALL_MANDIR="man" \ -DINSTALL_MYSQLDATADIR="/var/db/mysql" \ -DINSTALL_MYSQLSHAREDIR="share/mysql" \ -DINSTALL_MYSQLTESTDIR="share/mysql/tests" \ -DINSTALL_PLUGINDIR="lib/mysql/plugin" \ -DINSTALL_SBINDIR="libexec" \ -DINSTALL_SCRIPTDIR="bin" \ -DINSTALL_SHAREDIR="share" \ -DINSTALL_SQLBENCHDIR="share/mysql" \ -DINSTALL_SUPPORTFILESDIR="share/mysql" \ -DWITH_UNIT_TESTS=0 \ -DWITH_LIBEDIT=0 \ -DWITH_LIBWRAP=1 \ ) else [ $DEBIAN -ne 0 ] && \ MYSQL_SOCKET_PATH="/var/run/mysqld/mysqld.sock" || \ MYSQL_SOCKET_PATH="/var/lib/mysql/mysql.sock" CMAKE_LAYOUT_OPTIONS=( \ -DINSTALL_LAYOUT=RPM \ -DCMAKE_INSTALL_PREFIX="/usr" \ -DINSTALL_SBINDIR="/usr/sbin" \ -DMYSQL_DATADIR="/var/lib/mysql" \ -DMYSQL_UNIX_ADDR=$MYSQL_SOCKET_PATH \ -DCMAKE_OSX_ARCHITECTURES=$(uname -m) \ ) fi [ -n "$EXTRA_SYSROOT" ] && \ CMAKE_LAYOUT_OPTIONS+=( \ -DCMAKE_PREFIX_PATH="$EXTRA_SYSROOT" \ ) if [ $MYSQL_MAJOR = "5.1" ] then # This will be put to --prefix by SETUP.sh. export MYSQL_BUILD_PREFIX="/usr" export wsrep_configs="--libexecdir=/usr/sbin \ --localstatedir=/var/lib/mysql/ \ --with-unix-socket-path=$MYSQL_SOCKET_PATH \ --with-extra-charsets=all \ --with-ssl" [ "$DEBUG" = "yes" ] && BUILD_OPT="-debug" BUILD/compile-${CPU}${BUILD_OPT}-wsrep > /dev/null else # CMake build [ "$DEBUG" = "yes" ] \ && BUILD_OPT="-DCMAKE_BUILD_TYPE=Debug -DDEBUG_EXTNAME=OFF" \ || BUILD_OPT="-DCMAKE_BUILD_TYPE=RelWithDebInfo" # like in RPM spec [ "$MYSQL_MAJOR_VER$MYSQL_MINOR_VER" -ge "56" ] \ && MEMCACHED_OPT="-DWITH_LIBEVENT=yes -DWITH_INNODB_MEMCACHED=ON" \ || MEMCACHED_OPT="" if [ "$MYSQL_BUILD_DIR" != "$MYSQL_SRC" ] then [ "$BOOTSTRAP" = "yes" ] && rm -rf $MYSQL_BUILD_DIR [ -d "$MYSQL_BUILD_DIR" ] || mkdir -p $MYSQL_BUILD_DIR fi pushd $MYSQL_BUILD_DIR cmake \ ${CC:+-DCMAKE_C_COMPILER="$CC"} \ ${CXX:+-DCMAKE_CXX_COMPILER="$CXX"} \ -DBUILD_CONFIG=mysql_release \ "${CMAKE_LAYOUT_OPTIONS[@]}" \ $BUILD_OPT \ -DWITH_WSREP=1 \ -DWITH_EXTRA_CHARSETS=all \ -DWITH_SSL=yes \ -DWITH_ZLIB=system \ $MEMCACHED_OPT \ $MYSQL_SRC \ && make -j $JOBS -S && popd || exit 1 fi else # just recompile and relink with old configuration [ $MYSQL_MAJOR != "5.1" ] && pushd $MYSQL_BUILD_DIR make -j $JOBS -S > /dev/null [ $MYSQL_MAJOR != "5.1" ] && popd fi fi # SKIP_BUILD # gzip manpages # this should be rather fast, so we can repeat it every time if [ "$PACKAGE" == "yes" ] then cd $MYSQL_SRC/man && for i in *.1 *.8; do gzip -c $i > $i.gz; done || : fi ###################################### ## ## ## Making of demo tarball ## ## ## ###################################### install_mysql_5.1_demo() { MYSQL_LIBS=$MYSQL_DIST_DIR/lib/mysql MYSQL_PLUGINS=$MYSQL_DIST_DIR/lib/mysql/plugin MYSQL_CHARSETS=$MYSQL_DIST_DIR/share/mysql/charsets # BSD-based OSes does not have -D option on 'install' install -m 755 -d $MYSQL_DIST_DIR/share/mysql/english install -m 644 $MYSQL_SRC/sql/share/english/errmsg.sys $MYSQL_DIST_DIR/share/mysql/english/errmsg.sys install -m 755 -d $MYSQL_DIST_DIR/sbin install -m 755 $MYSQL_SRC/sql/mysqld $MYSQL_DIST_DIR/sbin/mysqld if [ "$SKIP_CLIENTS" == "no" ] then # Hack alert: # install libmysqlclient.so as libmysqlclient.so.16 as client binaries # seem to be linked against explicit version. Figure out better way to # deal with this. install -m 755 -d $MYSQL_LIBS install -m 755 $MYSQL_SRC/libmysql/.libs/libmysqlclient.so $MYSQL_LIBS/libmysqlclient.so.16 fi if test -f $MYSQL_SRC/storage/innodb_plugin/.libs/ha_innodb_plugin.so then install -m 755 -d $MYSQL_PLUGINS install -m 755 $MYSQL_SRC/storage/innodb_plugin/.libs/ha_innodb_plugin.so \ $MYSQL_PLUGINS/ha_innodb_plugin.so fi install -m 755 -d $MYSQL_BINS install -m 644 $MYSQL_SRC/sql/share/english/errmsg.sys $MYSQL_DIST_DIR/share/mysql/english/errmsg.sys install -m 755 -d $MYSQL_DIST_DIR/sbin install -m 755 $MYSQL_SRC/sql/mysqld $MYSQL_DIST_DIR/sbin/mysqld if [ "$SKIP_CLIENTS" == "no" ] then # Hack alert: # install libmysqlclient.so as libmysqlclient.so.16 as client binaries # seem to be linked against explicit version. Figure out better way to # deal with this. install -m 755 -d $MYSQL_LIBS install -m 755 $MYSQL_SRC/libmysql/.libs/libmysqlclient.so $MYSQL_LIBS/libmysqlclient.so.16 fi if test -f $MYSQL_SRC/storage/innodb_plugin/.libs/ha_innodb_plugin.so then install -m 755 -d $MYSQL_PLUGINS install -m 755 $MYSQL_SRC/storage/innodb_plugin/.libs/ha_innodb_plugin.so \ $MYSQL_PLUGINS/ha_innodb_plugin.so fi install -m 755 -d $MYSQL_BINS if [ "$SKIP_CLIENTS" == "no" ] then if [ -x $MYSQL_SRC/client/.libs/mysql ] # MySQL then MYSQL_CLIENTS=$MYSQL_SRC/client/.libs elif [ -x $MYSQL_SRC/client/mysql ] # MariaDB then MYSQL_CLIENTS=$MYSQL_SRC/client else echo "Can't find MySQL clients. Aborting." exit 1 fi install -m 755 -s -t $MYSQL_BINS $MYSQL_CLIENTS/mysql install -m 755 -s -t $MYSQL_BINS $MYSQL_CLIENTS/mysqldump install -m 755 -s -t $MYSQL_BINS $MYSQL_CLIENTS/mysqladmin fi install -m 755 -t $MYSQL_BINS $MYSQL_SRC/scripts/wsrep_sst_common install -m 755 -t $MYSQL_BINS $MYSQL_SRC/scripts/wsrep_sst_mysqldump install -m 755 -t $MYSQL_BINS $MYSQL_SRC/scripts/wsrep_sst_rsync install -m 755 -d $MYSQL_CHARSETS install -m 644 -t $MYSQL_CHARSETS $MYSQL_SRC/sql/share/charsets/*.xml install -m 644 -t $MYSQL_CHARSETS $MYSQL_SRC/sql/share/charsets/README } install_mysql_5.5_dist() { export DESTDIR=$BUILD_ROOT/dist/mysql mkdir -p $DESTDIR pushd $MYSQL_BUILD_DIR make install popd unset DESTDIR } install_mysql_5.5_demo() { export DESTDIR=$BUILD_ROOT/dist/mysql mkdir -p $DESTDIR pushd $MYSQL_BUILD_DIR cmake -DCMAKE_INSTALL_COMPONENT=Server -P cmake_install.cmake cmake -DCMAKE_INSTALL_COMPONENT=Client -P cmake_install.cmake cmake -DCMAKE_INSTALL_COMPONENT=SharedLibraries -P cmake_install.cmake cmake -DCMAKE_INSTALL_COMPONENT=ManPages -P cmake_install.cmake [ "$DEBUG" == "yes" ] && cmake -DCMAKE_INSTALL_COMPONENT=Debuginfo -P cmake_install.cmake popd unset DESTDIR pushd $MYSQL_DIST_DIR [ -d usr/local ] && ( mv usr/local/* ./ && rmdir usr/local ) # FreeBSD [ -d libexec -a ! -d sbin ] && mv libexec sbin # FreeBSD mv usr/* ./ && rmdir usr [ -d lib64 -a ! -d lib ] && mv lib64 lib popd } if [ $TAR == "yes" ]; then echo "Creating demo distribution" # Create build directory structure DIST_DIR=$BUILD_ROOT/dist MYSQL_DIST_DIR=$DIST_DIR/mysql MYSQL_DIST_CNF=$MYSQL_DIST_DIR/etc/my.cnf GALERA_DIST_DIR=$DIST_DIR/galera MYSQL_BINS=$MYSQL_DIST_DIR/bin cd $BUILD_ROOT rm -rf $DIST_DIR # Install required MySQL files in the DIST_DIR if [ $MYSQL_MAJOR == "5.1" ]; then install_mysql_5.1_demo install -m 755 -d $(dirname $MYSQL_DIST_CNF) install -m 644 my-5.1.cnf $MYSQL_DIST_CNF else install_mysql_5.5_demo > /dev/null install -m 755 -d $(dirname $MYSQL_DIST_CNF) install -m 644 my-5.5.cnf $MYSQL_DIST_CNF fi cat $MYSQL_BUILD_DIR/support-files/wsrep.cnf | \ sed 's/root:$/root:rootpass/' >> $MYSQL_DIST_CNF pushd $MYSQL_BINS; ln -s wsrep_sst_rsync wsrep_sst_rsync_wan; popd tar -xzf mysql_var_$MYSQL_MAJOR.tgz -C $MYSQL_DIST_DIR install -m 644 LICENSE.mysql $MYSQL_DIST_DIR # Copy required Galera libraries GALERA_BINS=$GALERA_DIST_DIR/bin GALERA_LIBS=$GALERA_DIST_DIR/lib install -m 755 -d $GALERA_DIST_DIR install -m 644 ../../LICENSE $GALERA_DIST_DIR/LICENSE.galera install -m 755 -d $GALERA_BINS install -m 755 -d $GALERA_LIBS if [ "$SCONS" == "yes" ] then SCONS_VD=$GALERA_SRC cp -P $SCONS_VD/garb/garbd $GALERA_BINS cp -P $SCONS_VD/libgalera_smm.so $GALERA_LIBS if [ "$OS" == "Darwin" -a "$DEBUG" == "yes" ]; then cp -P -R $SCONS_VD/garb/garbd.dSYM $GALERA_BINS cp -P -R $SCONS_VD/libgalera_smm.so.dSYM $GALERA_LIBS fi else echo "Autotools compilation not supported any more." exit 1 fi install -m 644 LICENSE $DIST_DIR install -m 755 mysql-galera $DIST_DIR install -m 644 README $DIST_DIR install -m 644 QUICK_START $DIST_DIR # Strip binaries if not instructed otherwise if test "$NO_STRIP" != "yes" then for d in $GALERA_BINS $GALERA_LIBS \ $MYSQL_DIST_DIR/bin $MYSQL_DIST_DIR/lib $MYSQL_DIST_DIR/sbin do for f in $d/* do file $f | grep 'not stripped' >/dev/null && strip $f || : done done fi fi # if [ $TAR == "yes" ] if [ "$BIN_DIST" == "yes" ]; then . bin_dist.sh fi if [ "$TAR" == "yes" ] || [ "$BIN_DIST" == "yes" ]; then if [ "$RELEASE" != "" ] then GALERA_RELEASE="galera-$RELEASE-$(uname -m)" else GALERA_RELEASE="$WSREP_REV,$GALERA_REV" fi RELEASE_NAME=$(echo mysql-$MYSQL_VER-$GALERA_RELEASE | sed s/\:/_/g) rm -rf $RELEASE_NAME mv $DIST_DIR $RELEASE_NAME # Hack to avoid 'file changed as we read it'-error if test -n "$SYNC_BEFORE_PACK" then echo "syncing disks" sync sleep 1 fi # Pack the release tar -czf $RELEASE_NAME.tgz $RELEASE_NAME fi # if [ $TAR == "yes" || "$BIN_DIST" == "yes" ] if [ "$TAR" == "yes" ] && [ "$INSTALL" == "yes" ]; then cmd="$GALERA_SRC/tests/scripts/command.sh" $cmd stop $cmd install $RELEASE_NAME.tgz fi get_arch() { if ! [ -z "$TARGET" ] then if [ "$TARGET" == "i686" ] then echo "i386" else echo "amd64" fi elif [ "$OS" == "Darwin" ]; then if file $MYSQL_SRC/sql/mysqld | grep "i386" >/dev/null 2>&1 then echo "i386" else echo "amd64" fi else if file $MYSQL_SRC/sql/mysqld | grep "80386" >/dev/null 2>&1 then echo "i386" else echo "amd64" fi fi } build_linux_packages() { pushd $GALERA_SRC/scripts/mysql local ARCH=$(get_arch) local WHOAMI=$(whoami) if [ $DEBIAN -eq 0 ] && [ "$ARCH" == "amd64" ]; then ARCH="x86_64" export x86_64=$ARCH # for epm fi local STRIP_OPT="" [ "$NO_STRIP" == "yes" ] && STRIP_OPT="-g" export MYSQL_VER MYSQL_SRC GALERA_SRC RELEASE_NAME MYSQLD_BINARY export WSREP_VER=${RELEASE:-"$WSREP_REV"} echo $MYSQL_SRC $MYSQL_VER $ARCH rm -rf $ARCH set +e if [ $DEBIAN -ne 0 ]; then #build DEB local deb_basename="mysql-server-wsrep" pushd debian $SUDO_ENV $(which epm) -n -m "$ARCH" -a "$ARCH" -f "deb" \ --output-dir $ARCH $STRIP_OPT $deb_basename RET=$? $SUDO /bin/chown -R $WHOAMI.users $ARCH else # build RPM echo "RPMs are now built by a separate script." return 1 fi popd return $RET } build_freebsd_packages() { echo "Creating FreeBSD packages" # Create build directory structure DIST_DIR=$BUILD_ROOT/dist/mysql MYSQL_DIST_DIR=$DIST_DIR/usr/local MYSQL_DIST_CNF=$MYSQL_DIST_DIR/share/mysql/my_wsrep.cnf MYSQL_BINS=$MYSQL_DIST_DIR/bin MYSQL_CLIENT_LICENSE_DIR=$MYSQL_DIST_DIR/share/licenses/mysql-client-${MYSQL_VER}_wsrep_${RELEASE} MYSQL_SERVER_LICENSE_DIR=$MYSQL_DIST_DIR/share/licenses/mysql-server-${MYSQL_VER}_wsrep_${RELEASE} MYSQL_SERVER_DOC_DIR=$MYSQL_DIST_DIR/share/doc/mysql${MYSQL_MAJOR_VER}${MYSQL_MINOR_VER}-server_wsrep cd $BUILD_ROOT rm -rf $BUILD_ROOT/dist install_mysql_5.5_dist > /dev/null install -m 755 -d $(dirname $MYSQL_DIST_CNF) install -m 644 my-5.5.cnf $MYSQL_DIST_CNF cat $MYSQL_BUILD_DIR/support-files/wsrep.cnf | \ sed 's/root:$/root:rootpass/' >> $MYSQL_DIST_CNF pushd $MYSQL_BINS; ln -s wsrep_sst_rsync wsrep_sst_rsync_wan; popd install -m 755 -d "$MYSQL_CLIENT_LICENSE_DIR" install -m 644 ../../LICENSE "$MYSQL_CLIENT_LICENSE_DIR/GPLv3" install -m 644 freebsd/LICENSE "$MYSQL_CLIENT_LICENSE_DIR" install -m 644 freebsd/catalog.mk "$MYSQL_CLIENT_LICENSE_DIR" install -m 755 -d "$MYSQL_SERVER_LICENSE_DIR" install -m 644 ../../LICENSE "$MYSQL_SERVER_LICENSE_DIR/GPLv3" install -m 644 freebsd/LICENSE "$MYSQL_SERVER_LICENSE_DIR" install -m 644 freebsd/catalog.mk "$MYSQL_SERVER_LICENSE_DIR" install -m 755 -d "$MYSQL_SERVER_DOC_DIR" install -m 644 README "$MYSQL_SERVER_DOC_DIR" install -m 644 QUICK_START "$MYSQL_SERVER_DOC_DIR" # Strip binaries if not instructed otherwise if test "$NO_STRIP" != "yes" then for d in $MYSQL_DIST_DIR/bin $MYSQL_DIST_DIR/lib $MYSQL_DIST_DIR/libexec do for f in $d/* do file $f | grep 'not stripped' >/dev/null && strip $f || : done done fi pwd ./freebsd.sh $MYSQL_VER $RELEASE rm -rf $BUILD_ROOT/dist } if [ "$PACKAGE" == "yes" ]; then case "$OS" in Linux) build_linux_packages ;; FreeBSD) build_freebsd_packages mv *.tbz ../.. ;; *) echo "packages for $OS are not supported." return 1 ;; esac fi # percona-galera-3-3.8-3390/scripts/mysql/centos/000077500000000000000000000000001244131713600211315ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/centos/init.centos000077500000000000000000000103071244131713600233150ustar00rootroot00000000000000#!/bin/bash # # mysqld This shell script takes care of starting and stopping # the MySQL subsystem (mysqld). # # chkconfig: - 64 36 # description: MySQL database server. # processname: mysqld # config: /etc/my.cnf # pidfile: /var/run/mysqld/mysqld.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network prog="MySQL" # extract value of a MySQL option from config files # Usage: get_mysql_option SECTION VARNAME DEFAULT # result is returned in $result # We use my_print_defaults which prints all options from multiple files, # with the more specific ones later; hence take the last match. get_mysql_option(){ result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1` if [ -z "$result" ]; then # not found, use default result="$3" fi } get_mysql_option mysqld datadir "/var/lib/mysql" datadir="$result" get_mysql_option mysqld socket "$datadir/mysql.sock" socketfile="$result" get_mysql_option mysqld_safe log-error "/var/log/mysqld.log" errlogfile="$result" get_mysql_option mysqld_safe pid-file "/var/run/mysqld/mysqld.pid" mypidfile="$result" start(){ touch "$errlogfile" chown mysql:mysql "$errlogfile" chmod 0640 "$errlogfile" [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile" if [ ! -d "$datadir/mysql" ] ; then action $"Initializing MySQL database: " /usr/bin/mysql_install_db --wsrep-on=0 --datadir="$datadir" --user=mysql ret=$? chown -R mysql:mysql "$datadir" if [ $ret -ne 0 ] ; then return $ret fi fi chown mysql:mysql "$datadir" chmod 0755 "$datadir" # Pass all the options determined above, to ensure consistent behavior. # In many cases mysqld_safe would arrive at the same conclusions anyway # but we need to be sure. /usr/bin/mysqld_safe --datadir="$datadir" --socket="$socketfile" \ --log-error="$errlogfile" --pid-file="$mypidfile" \ --user=mysql >/dev/null 2>&1 & ret=$? # Spin for a maximum of N seconds waiting for the server to come up. # Rather than assuming we know a valid username, accept an "access # denied" response as meaning the server is functioning. if [ $ret -eq 0 ]; then STARTTIMEOUT=30 while [ $STARTTIMEOUT -gt 0 ]; do RESPONSE=`/usr/bin/mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1` && break echo "$RESPONSE" | grep -q "Access denied for user" && break sleep 1 let STARTTIMEOUT=${STARTTIMEOUT}-1 done if [ $STARTTIMEOUT -eq 0 ]; then echo "Timeout error occurred trying to start MySQL Daemon." action $"Starting $prog: " /bin/false ret=1 else action $"Starting $prog: " /bin/true fi else action $"Starting $prog: " /bin/false fi [ $ret -eq 0 ] && touch /var/lock/subsys/mysqld return $ret } stop(){ MYSQLPID=`cat "$mypidfile" 2>/dev/null ` if [ -n "$MYSQLPID" ]; then /bin/kill "$MYSQLPID" >/dev/null 2>&1 ret=$? if [ $ret -eq 0 ]; then STOPTIMEOUT=60 while [ $STOPTIMEOUT -gt 0 ]; do /bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break sleep 1 let STOPTIMEOUT=${STOPTIMEOUT}-1 done if [ $STOPTIMEOUT -eq 0 ]; then echo "Timeout error occurred trying to stop MySQL Daemon." ret=1 action $"Stopping $prog: " /bin/false else rm -f /var/lock/subsys/mysqld rm -f "$socketfile" action $"Stopping $prog: " /bin/true fi else action $"Stopping $prog: " /bin/false fi else ret=1 action $"Stopping $prog: " /bin/false fi return $ret } restart(){ stop start } condrestart(){ [ -e /var/lock/subsys/mysqld ] && restart || : } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status mysqld ;; restart) restart ;; condrestart) condrestart ;; *) echo $"Usage: $0 {start|stop|status|condrestart|restart}" exit 1 esac exit $? percona-galera-3-3.8-3390/scripts/mysql/centos/init.oracle000077500000000000000000000277031244131713600232770ustar00rootroot00000000000000#!/bin/sh # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # MySQL daemon start/stop script. # Usually this is put in /etc/init.d (at least on machines SYSV R4 based # systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/K01mysql. # When this is done the mysql server will be started when the machine is # started and shut down when the systems goes down. # Comments to support chkconfig on RedHat Linux # chkconfig: 2345 64 36 # description: A very fast and reliable SQL database engine. # Comments to support LSB init script conventions ### BEGIN INIT INFO # Provides: mysql # Required-Start: $local_fs $network $remote_fs # Should-Start: ypbind nscd ldap ntpd xntpd # Required-Stop: $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop MySQL # Description: MySQL is a very fast and reliable SQL database engine. ### END INIT INFO # If you install MySQL on some other places than /, then you # have to do one of the following things for this script to work: # # - Run this script from within the MySQL installation directory # - Create a /etc/my.cnf file with the following information: # [mysqld] # basedir= # - Add the above to any other configuration file (for example ~/.my.ini) # and copy my_print_defaults to /usr/bin # - Add the path to the mysql-installation-directory to the basedir variable # below. # # If you want to affect other MySQL variables, you should make your changes # in the /etc/my.cnf, ~/.my.cnf or other MySQL configuration files. # If you change base dir, you must also change datadir. These may get # overwritten by settings in the MySQL configuration files. basedir= datadir= # Default value, in seconds, afterwhich the script should timeout waiting # for server start. # Value here is overriden by value in my.cnf. # 0 means don't wait at all # Negative numbers mean to wait indefinitely service_startup_timeout=900 # The following variables are only set for letting mysql.server find things. # Set some defaults pid_file= server_pid_file= use_mysqld_safe=1 user=mysql if test -z "$basedir" then basedir=/ bindir=/usr/bin if test -z "$datadir" then datadir=/var/lib/mysql fi sbindir=/usr/sbin libexecdir=/usr/sbin else bindir="$basedir/bin" if test -z "$datadir" then datadir="$basedir/data" fi sbindir="$basedir/sbin" libexecdir="$basedir/libexec" fi # datadir_set is used to determine if datadir was set (and so should be # *not* set inside of the --basedir= handler.) datadir_set= # # Use LSB init script functions for printing messages, if possible # lsb_functions="/lib/lsb/init-functions" if test -f $lsb_functions ; then . $lsb_functions else log_success_msg() { echo " SUCCESS! $@" } log_failure_msg() { echo " ERROR! $@" } fi PATH=/sbin:/usr/sbin:/bin:/usr/bin:$basedir/bin export PATH mode=$1 # start or stop shift other_args="$*" # uncommon, but needed when called from an RPM upgrade action # Expected: "--skip-networking --skip-grant-tables" # They are not checked here, intentionally, as it is the resposibility # of the "spec" file author to give correct arguments only. case `echo "testing\c"`,`echo -n testing` in *c*,-n*) echo_n= echo_c= ;; *c*,*) echo_n=-n echo_c= ;; *) echo_n= echo_c='\c' ;; esac parse_server_arguments() { for arg do case "$arg" in --basedir=*) basedir=`echo "$arg" | sed -e 's/^[^=]*=//'` bindir="$basedir/bin" if test -z "$datadir_set"; then datadir="$basedir/data" fi sbindir="$basedir/sbin" libexecdir="$basedir/libexec" ;; --datadir=*) datadir=`echo "$arg" | sed -e 's/^[^=]*=//'` datadir_set=1 ;; --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --pid-file=*) server_pid_file=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --service-startup-timeout=*) service_startup_timeout=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --use-mysqld_safe) use_mysqld_safe=1;; --use-manager) use_mysqld_safe=0;; esac done } parse_manager_arguments() { for arg do case "$arg" in --pid-file=*) pid_file=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; --user=*) user=`echo "$arg" | sed -e 's/^[^=]*=//'` ;; esac done } wait_for_pid () { verb="$1" manager_pid="$2" # process ID of the program operating on the pid-file i=0 avoid_race_condition="by checking again" while test $i -ne $service_startup_timeout ; do case "$verb" in 'created') # wait for a PID-file to pop into existence. test -s $pid_file && i='' && break ;; 'removed') # wait for this PID-file to disappear test ! -s $pid_file && i='' && break ;; *) echo "wait_for_pid () usage: wait_for_pid created|removed manager_pid" exit 1 ;; esac # if manager isn't running, then pid-file will never be updated if test -n "$manager_pid"; then if kill -0 "$manager_pid" 2>/dev/null; then : # the manager still runs else # The manager may have exited between the last pid-file check and now. if test -n "$avoid_race_condition"; then avoid_race_condition="" continue # Check again. fi # there's nothing that will affect the file. log_failure_msg "Manager of pid-file quit without updating file." return 1 # not waiting any more. fi fi echo $echo_n ".$echo_c" i=`expr $i + 1` sleep 1 done if test -z "$i" ; then log_success_msg return 0 else log_failure_msg return 1 fi } # Get arguments from the my.cnf file, # the only group, which is read from now on is [mysqld] if test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" elif test -x $bindir/my_print_defaults then print_defaults="$bindir/my_print_defaults" elif test -x $bindir/mysql_print_defaults then print_defaults="$bindir/mysql_print_defaults" else # Try to find basedir in /etc/my.cnf conf=/etc/my.cnf print_defaults= if test -r $conf then subpat='^[^=]*basedir[^=]*=\(.*\)$' dirs=`sed -e "/$subpat/!d" -e 's//\1/' $conf` for d in $dirs do d=`echo $d | sed -e 's/[ ]//g'` if test -x "$d/bin/my_print_defaults" then print_defaults="$d/bin/my_print_defaults" break fi if test -x "$d/bin/mysql_print_defaults" then print_defaults="$d/bin/mysql_print_defaults" break fi done fi # Hope it's in the PATH ... but I doubt it test -z "$print_defaults" && print_defaults="my_print_defaults" fi # # Read defaults file from 'basedir'. If there is no defaults file there # check if it's in the old (depricated) place (datadir) and read it from there # extra_args="" if test -r "$basedir/my.cnf" then extra_args="-e $basedir/my.cnf" else if test -r "$datadir/my.cnf" then extra_args="-e $datadir/my.cnf" fi fi parse_server_arguments `$print_defaults $extra_args mysqld server mysql_server mysql.server` # Look for the pidfile parse_manager_arguments `$print_defaults $extra_args manager` # # Set pid file if not given # if test -z "$pid_file" then pid_file=$datadir/mysqlmanager-`/bin/hostname`.pid else case "$pid_file" in /* ) ;; * ) pid_file="$datadir/$pid_file" ;; esac fi if test -z "$server_pid_file" then server_pid_file=$datadir/`/bin/hostname`.pid else case "$server_pid_file" in /* ) ;; * ) server_pid_file="$datadir/$server_pid_file" ;; esac fi case "$mode" in 'start') # Start daemon # Safeguard (relative paths, core dumps..) cd $basedir manager=$bindir/mysqlmanager if test -x $libexecdir/mysqlmanager then manager=$libexecdir/mysqlmanager elif test -x $sbindir/mysqlmanager then manager=$sbindir/mysqlmanager fi echo $echo_n "Starting MySQL" if test -x $manager -a "$use_mysqld_safe" = "0" then if test -n "$other_args" then log_failure_msg "MySQL manager does not support options '$other_args'" exit 1 fi # Give extra arguments to mysqld with the my.cnf file. This script may # be overwritten at next upgrade. "$manager" \ --mysqld-safe-compatible \ --user="$user" \ --pid-file="$pid_file" >/dev/null 2>&1 & wait_for_pid created $!; return_value=$? # Make lock for RedHat / SuSE if test -w /var/lock/subsys then touch /var/lock/subsys/mysqlmanager fi exit $return_value elif test -x $bindir/mysqld_safe then # Give extra arguments to mysqld with the my.cnf file. This script # may be overwritten at next upgrade. pid_file=$server_pid_file $bindir/mysqld_safe --datadir=$datadir --pid-file=$server_pid_file $other_args >/dev/null 2>&1 & wait_for_pid created $!; return_value=$? # Make lock for RedHat / SuSE if test -w /var/lock/subsys then touch /var/lock/subsys/mysql fi exit $return_value else log_failure_msg "Couldn't find MySQL manager ($manager) or server ($bindir/mysqld_safe)" fi ;; 'stop') # Stop daemon. We use a signal here to avoid having to know the # root password. # The RedHat / SuSE lock directory to remove lock_dir=/var/lock/subsys/mysqlmanager # If the manager pid_file doesn't exist, try the server's if test ! -s "$pid_file" then pid_file=$server_pid_file lock_dir=/var/lock/subsys/mysql fi if test -s "$pid_file" then mysqlmanager_pid=`cat $pid_file` if (kill -0 $mysqlmanager_pid 2>/dev/null) then echo $echo_n "Shutting down MySQL" kill $mysqlmanager_pid # mysqlmanager should remove the pid_file when it exits, so wait for it. wait_for_pid removed "$mysqlmanager_pid"; return_value=$? else log_failure_msg "MySQL manager or server process #$mysqlmanager_pid is not running!" rm $pid_file fi # delete lock for RedHat / SuSE if test -f $lock_dir then rm -f $lock_dir fi exit $return_value else log_failure_msg "MySQL manager or server PID file could not be found!" fi ;; 'restart') # Stop the service and regardless of whether it was # running or not, start it again. if $0 stop $other_args; then $0 start $other_args else log_failure_msg "Failed to stop running server, so refusing to try to start." exit 1 fi ;; 'reload'|'force-reload') if test -s "$server_pid_file" ; then read mysqld_pid < $server_pid_file kill -HUP $mysqld_pid && log_success_msg "Reloading service MySQL" touch $server_pid_file else log_failure_msg "MySQL PID file could not be found!" exit 1 fi ;; 'status') # First, check to see if pid file exists if test -s "$server_pid_file" ; then read mysqld_pid < $server_pid_file if kill -0 $mysqld_pid 2>/dev/null ; then log_success_msg "MySQL running ($mysqld_pid)" exit 0 else log_failure_msg "MySQL is not running, but PID file exists" exit 1 fi else # Try to find appropriate mysqld process mysqld_pid=`pidof $libexecdir/mysqld` if test -z $mysqld_pid ; then if test "$use_mysqld_safe" = "0" ; then lockfile=/var/lock/subsys/mysqlmanager else lockfile=/var/lock/subsys/mysql fi if test -f $lockfile ; then log_failure_msg "MySQL is not running, but lock exists" exit 2 fi log_failure_msg "MySQL is not running" exit 3 else log_failure_msg "MySQL is running but PID file could not be found" exit 4 fi fi ;; *) # usage echo "Usage: $0 {start|stop|restart|reload|force-reload|status} [ MySQL server options ]" exit 1 ;; esac exit 0 percona-galera-3-3.8-3390/scripts/mysql/centos/my.cnf000066400000000000000000000010441244131713600222450ustar00rootroot00000000000000[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Default to using old password format for compatibility with mysql 3.x # clients (those using the mysqlclient10 compatibility package). old_passwords=1 [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid # # * IMPORTANT: Additional settings that can override those from this file! # The files must end with '.cnf', otherwise they'll be ignored. # WSREP NOTE: additional wsrep configuration is in wsrep.cnf # !includedir /etc/mysql/conf.d/ percona-galera-3-3.8-3390/scripts/mysql/centos/mysql-wsrep.list000066400000000000000000000063731244131713600243420ustar00rootroot00000000000000# This is a MySQ L-wsrep package description for ESP package manager # CentOS specific part %requires /bin/sh %requires /sbin/install-info %requires /sbin/ldconfig %requires /usr/sbin/useradd %requires bash %requires chkconfig %requires coreutils %requires grep %requires libc.so.6 %requires libcrypt.so.1 %requires libcrypto.so.6 %requires libdl.so.2 %requires libgcc_s.so.1 %requires libm.so.6 %requires libncurses.so.5 %requires libnsl.so.1 %requires libpthread.so.0 %requires libssl.so.6 %requires libstdc++.so.6 %requires libz.so.1 %requires procps %requires rtld(GNU_HASH) %requires shadow-utils # Required MySQL packages # for PHP-mysql on RHEL5: # %requires MySQL-shared-compat $MYSQL_VER # for mysqldump SST: # %requires MySQL-client-community $MYSQL_VER %provides MySQL %provides MySQL-server %provides mysql %provides mysql-server # Conflicting mysql packages #%incompat mysql-server $prefix=/usr $CONF_DST=/etc/mysql d 755 root root $CONF_DST - c 644 root root /etc/my.cnf $GALERA_SRC/scripts/mysql/centos/my.cnf d 755 root root $CONF_DST/conf.d d 755 root root /etc/rc.d/init.d - f 755 root root /etc/rc.d/init.d/mysql $GALERA_SRC/scripts/mysql/centos/init.oracle d 755 root root /etc/rc.d/logrotate.d - f 755 root root /etc/rc.d/logrotate.d/mysql $MYSQL_SRC/support-files/mysql-log-rotate %if x86_64 # CentOS (read Red Hat) never fails to screw up things $LIBS_DST=${prefix}/lib64/mysql %else $LIBS_DST=${prefix}/lib/mysql %endif $SHAR_DST=${prefix}/share/mysql $SBIN_DST=${prefix}/sbin $BINS_DST=${prefix}/bin $DOCS_DST=${prefix}/share/doc/MySQL-server-$MYSQL_VER $MAN_DST=${prefix}/share/man # Commented out CentOS pieces of code which don't seem to make sense here $mysql_datadir=/var/lib/mysql #d 755 root root ${mysql_data} - %preinstall < /dev/null 2>&1 echo "Giving mysqld 5 seconds to exit nicely" sleep 5 fi EOF_PREINSTALL # Postinstall script is a combination of those from CentOS and MySQL RPMs %postinstall < /dev/null || true useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL Server" \ -g mysql mysql 2> /dev/null || true # in case user existed usermod -g mysql mysql 2> /dev/null || true /bin/chown -R mysql:mysql ${CONF_DST} /bin/chmod 0755 ${mysql_datadir} /bin/touch /var/log/mysqld.log /bin/chown -R mysql:mysql ${mysql_datadir} /usr/bin/mysql_install_db --rpm --user=mysql --wsrep-on=0 /bin/chown -R mysql:mysql ${mysql_datadir} /bin/chmod -R og-rw ${mysql_datadir}/mysql if [ -x /etc/init.d/mysql ] ; then /etc/init.d/mysql start echo "Giving mysqld 2 seconds to start" sleep 2 fi sleep 2 EOF_POSTINSTALL %preremove </dev/null 2>&1 || : /sbin/chkconfig --del mysql fi EOF_PREREMOVE #%postremove </dev/null 2>&1 || : #fi #EOF_POSTREMOVE # percona-galera-3-3.8-3390/scripts/mysql/centos/mysqld_safe000077500000000000000000000445121244131713600233740ustar00rootroot00000000000000#!/bin/sh # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # # Script to start the MySQL daemon and restart it if it dies unexpectedly # # This should be executed in the MySQL base directory if you are using a # binary installation that is not installed in its compile-time default # location # # mysql.server works by first doing a cd to the base directory and from there # executing mysqld_safe KILL_MYSQLD=1; MYSQLD= niceness=0 # Initial logging status: error log is not open, and not using syslog logging=init want_syslog=0 syslog_tag= user='mysql' pid_file= err_log= syslog_tag_mysqld=mysqld syslog_tag_mysqld_safe=mysqld_safe trap '' 1 2 3 15 # we shouldn't let anyone kill us umask 007 defaults= case "$1" in --no-defaults|--defaults-file=*|--defaults-extra-file=*) defaults="$1"; shift ;; esac usage () { cat <> "$err_log" ;; syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac } log_error () { log_generic daemon.error "$@" >&2 } log_notice () { log_generic daemon.notice "$@" } eval_log_error () { cmd="$1" case $logging in file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;; syslog) # mysqld often prefixes its messages with a timestamp, which is # redundant when logging to syslog (which adds its own timestamp) # However, we don't strip the timestamp with sed here, because # sed buffers output (only GNU sed supports a -u (unbuffered) option) # which means that messages may not get sent to syslog until the # mysqld process quits. cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac #echo "Running mysqld: [$cmd]" eval "$cmd" } shell_quote_string() { # This sed command makes sure that any special chars are quoted, # so the arg gets passed exactly to the server. echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } wsrep_pick_url() { [ $# -eq 0 ] return 0 if ! which nc >/dev/null; then log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." return 1 fi local url # Assuming URL in the form scheme://host:port # If host and port are not NULL, the liveness of URL is assumed to be tested # If port part is absent, the url is returned literally and unconditionally # If every URL has port but none is reachable, nothing is returned for url in `echo $@ | sed s/,/\ /g` 0; do local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` local port=`echo $url | cut -d \: -f 3` [ -z "$port" ] && break nc -z "$host" $port >/dev/null && break done if [ "$url" == "0" ]; then log_error "ERROR: none of the URLs in '$@' is reachable." return 1 fi echo $url } # Run mysqld with --wsrep-recover and parse recovered position from log. # Position will be stored in wsrep_start_position_opt global. wsrep_recovery() { cmd="$@" wr_logfile=$(mktemp) log_notice "WSREP: Running position recovery" $cmd --log_error=$wr_logfile --wsrep-recover rp=$(grep "WSREP: Recovered position:" $wr_logfile) if [ -z "$rp" ]; then skipped=$(grep WSREP $wr_logfile | grep "skipping position recovery") if [ -z "$skipped" ]; then log_error "WSREP: Failed to recover position: " \ `cat $wr_logfile`; else log_notice "WSREP: Position recovery skipped" fi else start_pos=$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ | sed 's/^[ \t]*//') wsrep_start_position_opt="--wsrep_start_position=$start_pos" log_notice "WSREP: Recovered position $start_pos" fi rm $wr_logfile } parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on # the command line) into the args variable. pick_args= if test "$1" = PICK-ARGS-FROM-ARGV then pick_args=1 shift fi for arg do val=`echo "$arg" | sed -e "s;--[^=]*=;;"` case "$arg" in # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*) DATADIR="$val" ;; --pid-file=*) pid_file="$val" ;; --user=*) user="$val"; SET_USER=1 ;; # these might have been set in a [mysqld_safe] section of my.cnf # they are added to mysqld command line to override settings from my.cnf --log-error=*) err_log="$val" ;; --port=*) mysql_tcp_port="$val" ;; --socket=*) mysql_unix_port="$val" ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; --mysqld=*) MYSQLD="$val" ;; --mysqld-version=*) if test -n "$val" then MYSQLD="mysqld-$val" else MYSQLD="mysqld" fi ;; --nice=*) niceness="$val" ;; --open-files-limit=*) open_files="$val" ;; --open_files_limit=*) open_files="$val" ;; --skip-kill-mysqld*) KILL_MYSQLD=0 ;; --syslog) want_syslog=1 ;; --skip-syslog) want_syslog=0 ;; --syslog-tag=*) syslog_tag="$val" ;; --timezone=*) TZ="$val"; export TZ; ;; --wsrep[-_]urls=*) wsrep_urls="$val"; ;; --help) usage ;; *) if test -n "$pick_args" then append_arg_to_args "$arg" fi ;; esac done } # # First, try to find BASEDIR and ledir (where mysqld is) # if echo '/usr/share/mysql' | grep '^/' > /dev/null then relpkgdata=`echo '/usr/share/mysql' | sed -e 's,^/,,' -e 's,^/,,' -e 's,^,./,'` else # pkgdatadir is not relative to prefix relpkgdata='/usr/share/mysql' fi MY_PWD=`pwd` # Check for the directories we would expect from a binary release install if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" then # BASEDIR is already overridden on command line. Do not re-set. # Use BASEDIR to discover le. if test -x "$MY_BASEDIR_VERSION/libexec/mysqld" then ledir="$MY_BASEDIR_VERSION/libexec" else ledir="$MY_BASEDIR_VERSION/bin" fi elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are ledir="$MY_PWD/bin" # Where mysqld is # Check for the directories we would expect from a source install elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are ledir="$MY_PWD/libexec" # Where mysqld is # Since we didn't find anything, used the compiled-in defaults else MY_BASEDIR_VERSION='/' ledir='/usr/sbin' fi # # Second, try to find the data directory # # Try where the binary installs put it if test -d $MY_BASEDIR_VERSION/data/mysql then DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then defaults="--defaults-extra-file=$DATADIR/my.cnf" fi # Next try where the source installs put it elif test -d $MY_BASEDIR_VERSION/var/mysql then DATADIR=$MY_BASEDIR_VERSION/var # Or just give up and use our compiled-in default else DATADIR=/var/lib/mysql fi if test -z "$MYSQL_HOME" then if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then log_error "WARNING: Found two instances of my.cnf - $MY_BASEDIR_VERSION/my.cnf and $DATADIR/my.cnf IGNORING $DATADIR/my.cnf" MYSQL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then log_error "WARNING: Found $DATADIR/my.cnf The data directory is a deprecated location for my.cnf, please move it to $MY_BASEDIR_VERSION/my.cnf" MYSQL_HOME=$DATADIR else MYSQL_HOME=$MY_BASEDIR_VERSION fi fi export MYSQL_HOME # Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] # and then merge with the command line arguments if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults" then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults" elif test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" elif test -x /usr/bin/my_print_defaults then print_defaults="/usr/bin/my_print_defaults" elif test -x /usr/bin/mysql_print_defaults then print_defaults="/usr/bin/mysql_print_defaults" else print_defaults="my_print_defaults" fi append_arg_to_args () { args="$args "`shell_quote_string "$1"` } args= SET_USER=2 parse_arguments `$print_defaults $defaults --loose-verbose mysqld server` if test $SET_USER -eq 2 then SET_USER=0 fi parse_arguments `$print_defaults $defaults --loose-verbose mysqld_safe safe_mysqld` parse_arguments PICK-ARGS-FROM-ARGV "$@" # Determine what logging facility to use # Ensure that 'logger' exists, if it's requested if [ $want_syslog -eq 1 ] then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then log_error "--syslog requested, but no 'logger' program found. Please ensure that 'logger' is in your PATH, or do not specify the --syslog option to mysqld_safe." exit 1 fi fi if [ -n "$err_log" -o $want_syslog -eq 0 ] then if [ -n "$err_log" ] then # mysqld adds ".err" if there is no extension on the --log-error # argument; must match that here, or mysqld_safe will write to a # different log file than mysqld # mysqld does not add ".err" to "--log-error=foo."; it considers a # trailing "." as an extension if expr "$err_log" : '.*\.[^/]*$' > /dev/null then : else err_log="$err_log".err fi case "$err_log" in /* ) ;; * ) err_log="$DATADIR/$err_log" ;; esac else err_log=$DATADIR/`/bin/hostname`.err fi append_arg_to_args "--log-error=$err_log" if [ $want_syslog -eq 1 ] then # User explicitly asked for syslog, so warn that it isn't used log_error "Can't log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect." fi # Log to err_log file log_notice "Logging to '$err_log'." logging=file else if [ -n "$syslog_tag" ] then # Sanitize the syslog tag syslog_tag=`echo "$syslog_tag" | sed -e 's/[^a-zA-Z0-9_-]/_/g'` syslog_tag_mysqld_safe="${syslog_tag_mysqld_safe}-$syslog_tag" syslog_tag_mysqld="${syslog_tag_mysqld}-$syslog_tag" fi log_notice "Logging to syslog." logging=syslog fi USER_OPTION="" if test -w / -o "$USER" = "root" then if test "$user" != "root" -o $SET_USER = 1 then USER_OPTION="--user=$user" fi # Change the err log to the right user, if it is in use if [ $want_syslog -eq 0 ]; then touch "$err_log" chown $user "$err_log" fi if test -n "$open_files" then ulimit -n $open_files fi fi if test -n "$open_files" then append_arg_to_args "--open-files-limit=$open_files" fi safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-/var/lib/mysql/mysql.sock}} # Make sure that directory for $safe_mysql_unix_port exists mysql_unix_port_dir=`dirname $safe_mysql_unix_port` if [ ! -d $mysql_unix_port_dir ] then mkdir $mysql_unix_port_dir chown $user $mysql_unix_port_dir chmod 755 $mysql_unix_port_dir fi # If the user doesn't specify a binary, we assume name "mysqld" if test -z "$MYSQLD" then MYSQLD=mysqld fi if test ! -x "$ledir/$MYSQLD" then log_error "The file $ledir/$MYSQLD does not exist or is not executable. Please cd to the mysql installation directory and restart this script from there as follows: ./bin/mysqld_safe& See http://dev.mysql.com/doc/mysql/en/mysqld-safe.html for more information" exit 1 fi if test -z "$pid_file" then pid_file="$DATADIR/`/bin/hostname`.pid" else case "$pid_file" in /* ) ;; * ) pid_file="$DATADIR/$pid_file" ;; esac fi append_arg_to_args "--pid-file=$pid_file" if test -n "$mysql_unix_port" then append_arg_to_args "--socket=$mysql_unix_port" fi if test -n "$mysql_tcp_port" then append_arg_to_args "--port=$mysql_tcp_port" fi if test $niceness -eq 0 then NOHUP_NICENESS="nohup" else NOHUP_NICENESS="nohup nice -$niceness" fi # Using nice with no args to get the niceness level is GNU-specific. # This check could be extended for other operating systems (e.g., # BSD could use "nohup sh -c 'ps -o nice -p $$' | tail -1"). # But, it also seems that GNU nohup is the only one which messes # with the priority, so this is okay. if nohup nice > /dev/null 2>&1 then normal_niceness=`nice` nohup_niceness=`nohup nice 2>/dev/null` numeric_nice_values=1 for val in $normal_niceness $nohup_niceness do case "$val" in -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \ [0-9] | [0-9][0-9] | [0-9][0-9][0-9] ) ;; * ) numeric_nice_values=0 ;; esac done if test $numeric_nice_values -eq 1 then nice_value_diff=`expr $nohup_niceness - $normal_niceness` if test $? -eq 0 && test $nice_value_diff -gt 0 && \ nice --$nice_value_diff echo testing > /dev/null 2>&1 then # nohup increases the priority (bad), and we are permitted # to lower the priority with respect to the value the user # might have been given niceness=`expr $niceness - $nice_value_diff` NOHUP_NICENESS="nice -$niceness nohup" fi fi else if nohup echo testing > /dev/null 2>&1 then : else # nohup doesn't work on this system NOHUP_NICENESS="" fi fi # Try to set the core file size (even if we aren't root) because many systems # don't specify a hard limit on core file size. if test -n "$core_file_size" then ulimit -c $core_file_size fi # # If there exists an old pid file, check if the daemon is already running # Note: The switches to 'ps' may depend on your operating system if test -f "$pid_file" then PID=`cat "$pid_file"` if /bin/kill -0 $PID > /dev/null 2> /dev/null then if /bin/ps wwwp $PID | grep -v " grep" | grep -v mysqld_safe | grep -- "$MYSQLD" > /dev/null then # The pid contains a mysqld process log_error "A mysqld process already exists" exit 1 fi fi rm -f "$pid_file" if test -f "$pid_file" then log_error "Fatal error: Can't remove the pid file: $pid_file Please remove it manually and start $0 again; mysqld daemon not started" exit 1 fi fi # # Uncomment the following lines if you want all tables to be automatically # checked and repaired during startup. You should add sensible key_buffer # and sort_buffer values to my.cnf to improve check performance or require # less disk space. # Alternatively, you can start mysqld with the "myisam-recover" option. See # the manual for details. # # echo "Checking tables in $DATADIR" # $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI # $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM # Does this work on all systems? #if type ulimit | grep "shell builtin" > /dev/null #then # ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems #fi cmd="$NOHUP_NICENESS" for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION" do cmd="$cmd "`shell_quote_string "$i"` done cmd="$cmd $args" # Avoid 'nohup: ignoring input' warning nohup_redir="" test -n "$NOHUP_NICENESS" && nohup_redir=" < /dev/null" log_notice "Starting $MYSQLD daemon with databases from $DATADIR" while true do rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address if [ -z "$url" ] then wsrep_recovery "$cmd" eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir" else wsrep_recovery "$cmd" eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir" fi if test ! -f "$pid_file" # This is removed if normal shutdown then break fi if true && test $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) # but should work for the rest of the servers. # The only thing is ps x => redhat 5 gives warnings when using ps -x. # kill -9 is used or the process won't react on the kill. numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` log_notice "Number of processes running now: $numofproces" I=1 while test "$I" -le "$numofproces" do PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` for T in $PROC do break done # echo "TEST $I - $T **" if kill -9 $T then log_error "$MYSQLD process hanging, pid $T - killed" else break fi I=`expr $I + 1` done fi log_notice "mysqld restarted" done log_notice "mysqld from pid file $pid_file ended" percona-galera-3-3.8-3390/scripts/mysql/debian/000077500000000000000000000000001244131713600210605ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/5.1.list000066400000000000000000000211371244131713600222640ustar00rootroot00000000000000# This is a MySQL-wsrep package description for ESP package manager %include common.list %requires mysql-client-5.1 5.1.41 %provides mysql-server-core-5.1 %provides mysql-server-5.1 ############################################## # Below files sorted into paragraphs # # in the path alphabetical order # ############################################## d 755 root root $BINS_DST - f 755 root root $BINS_DST/msql2mysql $MYSQL_SRC/scripts/msql2mysql f 755 root root $BINS_DST/myisamchk $MYSQL_SRC/storage/myisam/myisamchk f 755 root root $BINS_DST/myisamlog $MYSQL_SRC/storage/myisam/myisamlog f 755 root root $BINS_DST/myisampack $MYSQL_SRC/storage/myisam/myisampack f 755 root root $BINS_DST/mysql_convert_table_format $MYSQL_SRC/scripts/mysql_convert_table_format f 755 root root $BINS_DST/mysql_fix_privilege_tables $MYSQL_SRC/scripts/mysql_fix_privilege_tables f 755 root root $BINS_DST/mysql_install_db $MYSQL_SRC/scripts/mysql_install_db f 755 root root $BINS_DST/mysql_secure_installation $MYSQL_SRC/scripts/mysql_secure_installation f 755 root root $BINS_DST/mysql_setpermission $MYSQL_SRC/scripts/mysql_setpermission f 755 root root $BINS_DST/mysql_tzinfo_to_sql $MYSQL_SRC/sql/mysql_tzinfo_to_sql f 755 root root $BINS_DST/mysql_upgrade $MYSQL_SRC/client/.libs/mysql_upgrade f 755 root root $BINS_DST/mysql_zap $MYSQL_SRC/scripts/mysql_zap f 755 root root $BINS_DST/mysqlbinlog $MYSQL_SRC/client/.libs/mysqlbinlog f 755 root root $BINS_DST/mysqld_multi $MYSQL_SRC/scripts/mysqld_multi f 755 root root $BINS_DST/mysqld_safe $GALERA_SRC/scripts/mysql/debian/mysqld_safe-5.1 f 755 root root $BINS_DST/mysqlhotcopy $MYSQL_SRC/scripts/mysqlhotcopy f 755 root root $BINS_DST/mysqltest $MYSQL_SRC/client/.libs/mysqltest f 755 root root $BINS_DST/replace $MYSQL_SRC/extra/replace f 755 root root $BINS_DST/resolve_stack_dump $MYSQL_SRC/extra/resolve_stack_dump f 755 root root $BINS_DST/resolveip $MYSQL_SRC/extra/resolveip d 755 root root $LIBS_DST - d 755 root root $LIBS_DST/plugin - f 755 root root $LIBS_DST/plugin/ha_innodb_plugin.so.0.0.0 $MYSQL_SRC/storage/innodb_plugin/.libs/ha_innodb_plugin.so.0.0.0 l 000 root root $LIBS_DST/plugin/ha_innodb_plugin.so.0 ha_innodb_plugin.so.0.0.0 l 000 root root $LIBS_DST/plugin/ha_innodb_plugin.so ha_innodb_plugin.so.0.0.0 # /usr/share/doc/... d 755 root root $DOCS_DST - f 644 root root $DOCS_DST/COPYING $MYSQL_SRC/COPYING d 755 root root $DOCS_DST/examples - f 644 root root $DOCS_DST/examples $MYSQL_SRC/support-files/*.cnf # manpages d 755 root root $MAN_DST/man1 - f 644 root root $MAN_DST/man1/innochecksum.1.gz $MYSQL_SRC/man/innochecksum.1.gz f 644 root root $MAN_DST/man1/msql2mysql.1.gz $MYSQL_SRC/man/msql2mysql.1.gz f 644 root root $MAN_DST/man1/myisamchk.1.gz $MYSQL_SRC/man/myisamchk.1.gz f 644 root root $MAN_DST/man1/myisamlog.1.gz $MYSQL_SRC/man/myisamlog.1.gz f 644 root root $MAN_DST/man1/myisampack.1.gz $MYSQL_SRC/man/myisampack.1.gz f 644 root root $MAN_DST/man1/mysql_convert_table_format.1.gz $MYSQL_SRC/man/mysql_convert_table_format.1.gz f 644 root root $MAN_DST/man1/mysql_fix_privilege_tables.1.gz $MYSQL_SRC/man/mysql_fix_privilege_tables.1.gz f 644 root root $MAN_DST/man1/mysql_install_db.1.gz $MYSQL_SRC/man/mysql_install_db.1.gz f 644 root root $MAN_DST/man1/mysql_secure_installation.1.gz $MYSQL_SRC/man/mysql_secure_installation.1.gz f 644 root root $MAN_DST/man1/mysql_setpermission.1.gz $MYSQL_SRC/man/mysql_setpermission.1.gz f 644 root root $MAN_DST/man1/mysql_tzinfo_to_sql.1.gz $MYSQL_SRC/man/mysql_tzinfo_to_sql.1.gz f 644 root root $MAN_DST/man1/mysql_upgrade.1.gz $MYSQL_SRC/man/mysql_upgrade.1.gz f 644 root root $MAN_DST/man1/mysql_zap.1.gz $MYSQL_SRC/man/mysql_zap.1.gz f 644 root root $MAN_DST/man1/mysqlbinlog.1.gz $MYSQL_SRC/man/mysqlbinlog.1.gz f 644 root root $MAN_DST/man1/mysqld_multi.1.gz $MYSQL_SRC/man/mysqld_multi.1.gz f 644 root root $MAN_DST/man1/mysqld_safe.1.gz $MYSQL_SRC/man/mysqld_safe.1.gz f 644 root root $MAN_DST/man1/mysqlhotcopy.1.gz $MYSQL_SRC/man/mysqlhotcopy.1.gz f 644 root root $MAN_DST/man1/mysqltest.1.gz $MYSQL_SRC/man/mysqltest.1.gz l 000 root root $MAN_DST/man1/mysqltest_embedded.1.gz mysqltest.1.gz f 644 root root $MAN_DST/man1/replace.1.gz $MYSQL_SRC/man/replace.1.gz f 644 root root $MAN_DST/man1/resolve_stack_dump.1.gz $MYSQL_SRC/man/resolve_stack_dump.1.gz f 644 root root $MAN_DST/man1/resolveip.1.gz $MYSQL_SRC/man/resolveip.1.gz d 755 root root $MAN_DST/man8 - f 644 root root $MAN_DST/man8/mysqld.8.gz $MYSQL_SRC/man/mysqld.8.gz d 755 root root $SBIN_DST - f 755 root root $SBIN_DST/mysqld $MYSQL_SRC/sql/mysqld d 755 root root $SHAR_DST/mysql-test - l 000 root root $SHAR_DST/mysql-test/mtr mysql-test-run.pl l 000 root root $SHAR_DST/mysql-test/mysql-test-run mysql-test-run.pl f 644 root root $SHAR_DST $MYSQL_SRC/support-files/config.*.ini f 644 root root $SHAR_DST/errmsg.txt $MYSQL_SRC/sql/share/errmsg.txt f 644 root root $SHAR_DST $MYSQL_SRC/scripts/*.sql f 644 root root $SHAR_DST/mysqld_multi.server $MYSQL_SRC/support-files/mysqld_multi.server f 644 root root $SHAR_DST/ndb-config-2-node.ini $MYSQL_SRC/support-files/ndb-config-2-node.ini d 755 root root $SHAR_DST/charsets - f 644 root root $SHAR_DST/charsets $MYSQL_SRC/sql/share/charsets/* $lang00=czech d 755 root root $SHAR_DST/${lang00} - f 644 root root $SHAR_DST/${lang00} $MYSQL_SRC/sql/share/${lang00}/* $lang01=danish d 755 root root $SHAR_DST/${lang01} - f 644 root root $SHAR_DST/${lang01} $MYSQL_SRC/sql/share/${lang01}/* $lang02=dutch d 755 root root $SHAR_DST/${lang02} - f 644 root root $SHAR_DST/${lang02} $MYSQL_SRC/sql/share/${lang02}/* $lang03=english d 755 root root $SHAR_DST/${lang03} - f 644 root root $SHAR_DST/${lang03} $MYSQL_SRC/sql/share/${lang03}/* $lang04=estonian d 755 root root $SHAR_DST/${lang04} - f 644 root root $SHAR_DST/${lang04} $MYSQL_SRC/sql/share/${lang04}/* $lang05=french d 755 root root $SHAR_DST/${lang05} - f 644 root root $SHAR_DST/${lang05} $MYSQL_SRC/sql/share/${lang05}/* $lang06=german d 755 root root $SHAR_DST/${lang06} - f 644 root root $SHAR_DST/${lang06} $MYSQL_SRC/sql/share/${lang06}/* $lang07=greek d 755 root root $SHAR_DST/${lang07} - f 644 root root $SHAR_DST/${lang07} $MYSQL_SRC/sql/share/${lang07}/* $lang08=hungarian d 755 root root $SHAR_DST/${lang08} - f 644 root root $SHAR_DST/${lang08} $MYSQL_SRC/sql/share/${lang08}/* $lang09=italian d 755 root root $SHAR_DST/${lang09} - f 644 root root $SHAR_DST/${lang09} $MYSQL_SRC/sql/share/${lang09}/* $lang10=japanese d 755 root root $SHAR_DST/${lang10} - f 644 root root $SHAR_DST/${lang10} $MYSQL_SRC/sql/share/${lang10}/* $lang11=korean d 755 root root $SHAR_DST/${lang11} - f 644 root root $SHAR_DST/${lang11} $MYSQL_SRC/sql/share/${lang11}/* $lang12=norwegian d 755 root root $SHAR_DST/${lang12} - f 644 root root $SHAR_DST/${lang12} $MYSQL_SRC/sql/share/${lang12}/* $lang13=norwegian-ny d 755 root root $SHAR_DST/${lang13} - f 644 root root $SHAR_DST/${lang13} $MYSQL_SRC/sql/share/${lang13}/* $lang14=polish d 755 root root $SHAR_DST/${lang14} - f 644 root root $SHAR_DST/${lang14} $MYSQL_SRC/sql/share/${lang14}/* $lang15=portuguese d 755 root root $SHAR_DST/${lang15} - f 644 root root $SHAR_DST/${lang15} $MYSQL_SRC/sql/share/${lang15}/* $lang16=romanian d 755 root root $SHAR_DST/${lang16} - f 644 root root $SHAR_DST/${lang16} $MYSQL_SRC/sql/share/${lang16}/* $lang17=russian d 755 root root $SHAR_DST/${lang17} - f 644 root root $SHAR_DST/${lang17} $MYSQL_SRC/sql/share/${lang17}/* $lang18=serbian d 755 root root $SHAR_DST/${lang18} - f 644 root root $SHAR_DST/${lang18} $MYSQL_SRC/sql/share/${lang18}/* $lang19=slovak d 755 root root $SHAR_DST/${lang19} - f 644 root root $SHAR_DST/${lang19} $MYSQL_SRC/sql/share/${lang19}/* $lang20=spanish d 755 root root $SHAR_DST/${lang20} - f 644 root root $SHAR_DST/${lang20} $MYSQL_SRC/sql/share/${lang20}/* $lang21=swedish d 755 root root $SHAR_DST/${lang21} - f 644 root root $SHAR_DST/${lang21} $MYSQL_SRC/sql/share/${lang21}/* $lang22=ukrainian d 755 root root $SHAR_DST/${lang22} - f 644 root root $SHAR_DST/${lang22} $MYSQL_SRC/sql/share/${lang22}/* #d 755 mysql root /var/run/mysqld - #d 755 mysql adm /var/log/mysql - d 755 root root /var/lib/mysql-upgrade - # percona-galera-3-3.8-3390/scripts/mysql/debian/5.5.list000066400000000000000000000252321244131713600222700ustar00rootroot00000000000000# This is a MySQL-wsrep package description for ESP package manager %include common.list %requires libaio1 %requires mysql-client %replaces mysql-server-core-5.5 0.0.0 ${mysql_version} %replaces mysql-server-5.5 0.0.0 ${mysql_version} %provides mysql-server-core-5.5 %provides mysql-server-5.5 ############################################## # Below files sorted into paragraphs # # in the path alphabetical order # ############################################## d 755 root root $BINS_DST - #in client f 755 root root $BINS_DST/innochecksum $MYSQL_SRC/extra/innochecksum f 755 root root $BINS_DST/msql2mysql $MYSQL_SRC/scripts/msql2mysql #in client f 755 root root $BINS_DST/my_print_defaults $MYSQL_SRC/extra/my_print_defaults f 755 root root $BINS_DST/myisamchk $MYSQL_SRC/storage/myisam/myisamchk f 755 root root $BINS_DST/myisamlog $MYSQL_SRC/storage/myisam/myisamlog f 755 root root $BINS_DST/myisampack $MYSQL_SRC/storage/myisam/myisampack f 755 root root $BINS_DST/mysql_convert_table_format $MYSQL_SRC/scripts/mysql_convert_table_format #f 755 root root $BINS_DST/mysql_fix_privilege_tables $MYSQL_SRC/scripts/mysql_fix_privilege_tables f 755 root root $BINS_DST/mysql_install_db $MYSQL_SRC/scripts/mysql_install_db f 755 root root $BINS_DST/mysql_secure_installation $MYSQL_SRC/scripts/mysql_secure_installation f 755 root root $BINS_DST/mysql_setpermission $MYSQL_SRC/scripts/mysql_setpermission f 755 root root $BINS_DST/mysql_tzinfo_to_sql $MYSQL_SRC/sql/mysql_tzinfo_to_sql f 755 root root $BINS_DST/mysql_upgrade $MYSQL_SRC/client/mysql_upgrade f 755 root root $BINS_DST/mysql_zap $MYSQL_SRC/scripts/mysql_zap f 755 root root $BINS_DST/mysqlbinlog $MYSQL_SRC/client/mysqlbinlog f 755 root root $BINS_DST/mysqld_multi $MYSQL_SRC/scripts/mysqld_multi f 755 root root $BINS_DST/mysqld_safe $GALERA_SRC/scripts/mysql/debian/mysqld_safe-5.5 #f 755 root root $BINS_DST/mysqld_safe $MYSQL_SRC/scripts/mysqld_safe f 755 root root $BINS_DST/mysqlhotcopy $MYSQL_SRC/scripts/mysqlhotcopy f 755 root root $BINS_DST/mysqltest $MYSQL_SRC/client/mysqltest #in client f 755 root root $BINS_DST/perror $MYSQL_SRC/extra/perror f 755 root root $BINS_DST/replace $MYSQL_SRC/extra/replace f 755 root root $BINS_DST/resolve_stack_dump $MYSQL_SRC/extra/resolve_stack_dump f 755 root root $BINS_DST/resolveip $MYSQL_SRC/extra/resolveip f 755 root root $BINS_DST/wsrep_sst_xtrabackup $MYSQL_SRC/scripts/wsrep_sst_xtrabackup d 755 root root $LIBS_DST - d 755 root root $PLUGIN_DST - f 755 root root $PLUGIN_DST/adt_null.so $MYSQL_SRC/plugin/audit_null/adt_null.so f 755 root root $PLUGIN_DST/auth.so $MYSQL_SRC/plugin/auth/auth.so f 755 root root $PLUGIN_DST/auth_socket.so $MYSQL_SRC/plugin/auth/auth_socket.so f 755 root root $PLUGIN_DST/auth_test_plugin.so $MYSQL_SRC/plugin/auth/auth_test_plugin.so f 755 root root $PLUGIN_DST/libdaemon_example.so $MYSQL_SRC/plugin/daemon_example/libdaemon_example.so f 755 root root $PLUGIN_DST/mypluglib.so $MYSQL_SRC/plugin/fulltext/mypluglib.so f 755 root root $PLUGIN_DST/qa_auth_client.so $MYSQL_SRC/plugin/auth/qa_auth_client.so f 755 root root $PLUGIN_DST/qa_auth_interface.so $MYSQL_SRC/plugin/auth/qa_auth_interface.so f 755 root root $PLUGIN_DST/qa_auth_server.so $MYSQL_SRC/plugin/auth/qa_auth_server.so f 755 root root $PLUGIN_DST/semisync_master.so $MYSQL_SRC/plugin/semisync/semisync_master.so f 755 root root $PLUGIN_DST/semisync_slave.so $MYSQL_SRC/plugin/semisync/semisync_slave.so d 755 root root $SBIN_DST - f 755 root root $SBIN_DST/$MYSQLD_BINARY $MYSQL_SRC/sql/$MYSQLD_BINARY # /usr/share/doc/... d 755 root root $DOCS_DST - f 644 root root $DOCS_DST/COPYING $MYSQL_SRC/COPYING f 644 root root $DOCS_DST/ChangeLog $MYSQL_SRC/Docs/ChangeLog f 644 root root $DOCS_DST/INFO_BIN $MYSQL_SRC/Docs/INFO_BIN f 644 root root $DOCS_DST/INFO_SRC $MYSQL_SRC/Docs/INFO_SRC f 644 root root $DOCS_DST/INSTALL-BINARY $MYSQL_SRC/Docs/INSTALL-BINARY f 644 root root $DOCS_DST/README $MYSQL_SRC/README f 644 root root $DOCS_DST/myisam.txt $MYSQL_SRC/Docs/myisam.txt # f 644 root root $DOCS_DST/mysql.info $MYSQL_SRC/Docs/mysql.info f 644 root root $DOCS_DST/sp-imp-spec.txt $MYSQL_SRC/Docs/sp-imp-spec.txt # manpages d 755 root root $MAN_DST/man1 - f 644 root root $MAN_DST/man1/comp_err.1.gz $MYSQL_SRC/man/comp_err.1.gz #in client f 644 root root $MAN_DST/man1/innochecksum.1.gz $MYSQL_SRC/man/innochecksum.1.gz f 644 root root $MAN_DST/man1/msql2mysql.1.gz $MYSQL_SRC/man/msql2mysql.1.gz #in client f 644 root root $MAN_DST/man1/my_print_defaults.1.gz $MYSQL_SRC/man/my_print_defaults.1.gz f 644 root root $MAN_DST/man1/myisamchk.1.gz $MYSQL_SRC/man/myisamchk.1.gz f 644 root root $MAN_DST/man1/myisamlog.1.gz $MYSQL_SRC/man/myisamlog.1.gz f 644 root root $MAN_DST/man1/myisampack.1.gz $MYSQL_SRC/man/myisampack.1.gz f 644 root root $MAN_DST/man1/mysql.server.1.gz $MYSQL_SRC/man/mysql.server.1.gz f 644 root root $MAN_DST/man1/mysql_convert_table_format.1.gz $MYSQL_SRC/man/mysql_convert_table_format.1.gz #f 644 root root $MAN_DST/man1/mysql_fix_privilege_tables.1.gz $MYSQL_SRC/man/mysql_fix_privilege_tables.1.gz f 644 root root $MAN_DST/man1/mysql_install_db.1.gz $MYSQL_SRC/man/mysql_install_db.1.gz f 644 root root $MAN_DST/man1/mysql_secure_installation.1.gz $MYSQL_SRC/man/mysql_secure_installation.1.gz f 644 root root $MAN_DST/man1/mysql_setpermission.1.gz $MYSQL_SRC/man/mysql_setpermission.1.gz f 644 root root $MAN_DST/man1/mysql_tzinfo_to_sql.1.gz $MYSQL_SRC/man/mysql_tzinfo_to_sql.1.gz f 644 root root $MAN_DST/man1/mysql_upgrade.1.gz $MYSQL_SRC/man/mysql_upgrade.1.gz f 644 root root $MAN_DST/man1/mysql_zap.1.gz $MYSQL_SRC/man/mysql_zap.1.gz f 644 root root $MAN_DST/man1/mysqlbinlog.1.gz $MYSQL_SRC/man/mysqlbinlog.1.gz f 644 root root $MAN_DST/man1/mysqld_multi.1.gz $MYSQL_SRC/man/mysqld_multi.1.gz f 644 root root $MAN_DST/man1/mysqld_safe.1.gz $MYSQL_SRC/man/mysqld_safe.1.gz f 644 root root $MAN_DST/man1/mysqlhotcopy.1.gz $MYSQL_SRC/man/mysqlhotcopy.1.gz f 644 root root $MAN_DST/man1/mysqltest.1.gz $MYSQL_SRC/man/mysqltest.1.gz #in client f 644 root root $MAN_DST/man1/perror.1.gz $MYSQL_SRC/man/perror.1.gz f 644 root root $MAN_DST/man1/replace.1.gz $MYSQL_SRC/man/replace.1.gz f 644 root root $MAN_DST/man1/resolve_stack_dump.1.gz $MYSQL_SRC/man/resolve_stack_dump.1.gz f 644 root root $MAN_DST/man1/resolveip.1.gz $MYSQL_SRC/man/resolveip.1.gz d 755 root root $MAN_DST/man8 - f 644 root root $MAN_DST/man8/mysqld.8.gz $MYSQL_SRC/man/mysqld.8.gz f 644 root root $SHAR_DST $MYSQL_SRC/support-files/config.*.ini f 644 root root $SHAR_DST $MYSQL_SRC/scripts/*.sql f 644 root root $SHAR_DST/binary-configure $MYSQL_SRC/support-files/binary-configure f 644 root root $SHAR_DST/errmsg-utf8.txt $MYSQL_SRC/sql/share/errmsg-utf8.txt f 644 root root $SHAR_DST $MYSQL_SRC/support-files/my-*.cnf f 644 root root $SHAR_DST/mysql-log-rotate $MYSQL_SRC/support-files/mysql-log-rotate f 755 root root $SHAR_DST/mysql.server $MYSQL_SRC/support-files/mysql.server f 644 root root $SHAR_DST/mysqld_multi.server $MYSQL_SRC/support-files/mysqld_multi.server # f 644 root root $SHAR_DST/ndb-config-2-node.ini $MYSQL_SRC/support-files/ndb-config-2-node.ini d 755 root root $SHAR_DST/charsets - f 644 root root $SHAR_DST/charsets $MYSQL_SRC/sql/share/charsets/* $lang00=czech d 755 root root $SHAR_DST/${lang00} - f 644 root root $SHAR_DST/${lang00} $MYSQL_SRC/sql/share/${lang00}/* $lang01=danish d 755 root root $SHAR_DST/${lang01} - f 644 root root $SHAR_DST/${lang01} $MYSQL_SRC/sql/share/${lang01}/* $lang02=dutch d 755 root root $SHAR_DST/${lang02} - f 644 root root $SHAR_DST/${lang02} $MYSQL_SRC/sql/share/${lang02}/* $lang03=english d 755 root root $SHAR_DST/${lang03} - f 644 root root $SHAR_DST/${lang03} $MYSQL_SRC/sql/share/${lang03}/* $lang04=estonian d 755 root root $SHAR_DST/${lang04} - f 644 root root $SHAR_DST/${lang04} $MYSQL_SRC/sql/share/${lang04}/* $lang05=french d 755 root root $SHAR_DST/${lang05} - f 644 root root $SHAR_DST/${lang05} $MYSQL_SRC/sql/share/${lang05}/* $lang06=german d 755 root root $SHAR_DST/${lang06} - f 644 root root $SHAR_DST/${lang06} $MYSQL_SRC/sql/share/${lang06}/* $lang07=greek d 755 root root $SHAR_DST/${lang07} - f 644 root root $SHAR_DST/${lang07} $MYSQL_SRC/sql/share/${lang07}/* $lang08=hungarian d 755 root root $SHAR_DST/${lang08} - f 644 root root $SHAR_DST/${lang08} $MYSQL_SRC/sql/share/${lang08}/* $lang09=italian d 755 root root $SHAR_DST/${lang09} - f 644 root root $SHAR_DST/${lang09} $MYSQL_SRC/sql/share/${lang09}/* $lang10=japanese d 755 root root $SHAR_DST/${lang10} - f 644 root root $SHAR_DST/${lang10} $MYSQL_SRC/sql/share/${lang10}/* $lang11=korean d 755 root root $SHAR_DST/${lang11} - f 644 root root $SHAR_DST/${lang11} $MYSQL_SRC/sql/share/${lang11}/* $lang12=norwegian d 755 root root $SHAR_DST/${lang12} - f 644 root root $SHAR_DST/${lang12} $MYSQL_SRC/sql/share/${lang12}/* $lang13=norwegian-ny d 755 root root $SHAR_DST/${lang13} - f 644 root root $SHAR_DST/${lang13} $MYSQL_SRC/sql/share/${lang13}/* $lang14=polish d 755 root root $SHAR_DST/${lang14} - f 644 root root $SHAR_DST/${lang14} $MYSQL_SRC/sql/share/${lang14}/* $lang15=portuguese d 755 root root $SHAR_DST/${lang15} - f 644 root root $SHAR_DST/${lang15} $MYSQL_SRC/sql/share/${lang15}/* $lang16=romanian d 755 root root $SHAR_DST/${lang16} - f 644 root root $SHAR_DST/${lang16} $MYSQL_SRC/sql/share/${lang16}/* $lang17=russian d 755 root root $SHAR_DST/${lang17} - f 644 root root $SHAR_DST/${lang17} $MYSQL_SRC/sql/share/${lang17}/* $lang18=serbian d 755 root root $SHAR_DST/${lang18} - f 644 root root $SHAR_DST/${lang18} $MYSQL_SRC/sql/share/${lang18}/* $lang19=slovak d 755 root root $SHAR_DST/${lang19} - f 644 root root $SHAR_DST/${lang19} $MYSQL_SRC/sql/share/${lang19}/* $lang20=spanish d 755 root root $SHAR_DST/${lang20} - f 644 root root $SHAR_DST/${lang20} $MYSQL_SRC/sql/share/${lang20}/* $lang21=swedish d 755 root root $SHAR_DST/${lang21} - f 644 root root $SHAR_DST/${lang21} $MYSQL_SRC/sql/share/${lang21}/* $lang22=ukrainian d 755 root root $SHAR_DST/${lang22} - f 644 root root $SHAR_DST/${lang22} $MYSQL_SRC/sql/share/${lang22}/* d 755 mysql root /var/run/mysqld - # percona-galera-3-3.8-3390/scripts/mysql/debian/5.6.list000066400000000000000000000255721244131713600223000ustar00rootroot00000000000000# This is a MySQL-wsrep package description for ESP package manager %include common.list %requires libaio1 %requires mysql-client %replaces mysql-server-5.6 0.0.0 ${mysql_version} %replaces mysql-server-5.5 0.0.0 ${mysql_version} %provides mysql-server-5.6 ############################################## # Below files sorted into paragraphs # # in the path alphabetical order # ############################################## d 755 root root $BINS_DST - #in client f 755 root root $BINS_DST/innochecksum $MYSQL_SRC/extra/innochecksum f 755 root root $BINS_DST/msql2mysql $MYSQL_SRC/scripts/msql2mysql #in client f 755 root root $BINS_DST/my_print_defaults $MYSQL_SRC/extra/my_print_defaults f 755 root root $BINS_DST/myisamchk $MYSQL_SRC/storage/myisam/myisamchk f 755 root root $BINS_DST/myisamlog $MYSQL_SRC/storage/myisam/myisamlog f 755 root root $BINS_DST/myisampack $MYSQL_SRC/storage/myisam/myisampack f 755 root root $BINS_DST/mysql_convert_table_format $MYSQL_SRC/scripts/mysql_convert_table_format #f 755 root root $BINS_DST/mysql_fix_privilege_tables $MYSQL_SRC/scripts/mysql_fix_privilege_tables f 755 root root $BINS_DST/mysql_install_db $MYSQL_SRC/scripts/mysql_install_db f 755 root root $BINS_DST/mysql_secure_installation $MYSQL_SRC/scripts/mysql_secure_installation f 755 root root $BINS_DST/mysql_setpermission $MYSQL_SRC/scripts/mysql_setpermission f 755 root root $BINS_DST/mysql_tzinfo_to_sql $MYSQL_SRC/sql/mysql_tzinfo_to_sql f 755 root root $BINS_DST/mysql_upgrade $MYSQL_SRC/client/mysql_upgrade f 755 root root $BINS_DST/mysql_zap $MYSQL_SRC/scripts/mysql_zap f 755 root root $BINS_DST/mysqlbinlog $MYSQL_SRC/client/mysqlbinlog f 755 root root $BINS_DST/mysqld_multi $MYSQL_SRC/scripts/mysqld_multi f 755 root root $BINS_DST/mysqld_safe $GALERA_SRC/scripts/mysql/debian/mysqld_safe-5.5 #f 755 root root $BINS_DST/mysqld_safe $MYSQL_SRC/scripts/mysqld_safe f 755 root root $BINS_DST/mysqlhotcopy $MYSQL_SRC/scripts/mysqlhotcopy f 755 root root $BINS_DST/mysqltest $MYSQL_SRC/client/mysqltest #in client f 755 root root $BINS_DST/perror $MYSQL_SRC/extra/perror f 755 root root $BINS_DST/replace $MYSQL_SRC/extra/replace f 755 root root $BINS_DST/resolve_stack_dump $MYSQL_SRC/extra/resolve_stack_dump f 755 root root $BINS_DST/resolveip $MYSQL_SRC/extra/resolveip f 755 root root $BINS_DST/wsrep_sst_xtrabackup $MYSQL_SRC/scripts/wsrep_sst_xtrabackup d 755 root root $LIBS_DST - d 755 root root $PLUGIN_DST - f 755 root root $PLUGIN_DST/adt_null.so $MYSQL_SRC/plugin/audit_null/adt_null.so f 755 root root $PLUGIN_DST/auth.so $MYSQL_SRC/plugin/auth/auth.so f 755 root root $PLUGIN_DST/auth_socket.so $MYSQL_SRC/plugin/auth/auth_socket.so f 755 root root $PLUGIN_DST/auth_test_plugin.so $MYSQL_SRC/plugin/auth/auth_test_plugin.so f 755 root root $PLUGIN_DST/innodb_engine.so $MYSQL_SRC/plugin/innodb_memcached/innodb_memcache/innodb_engine.so f 755 root root $PLUGIN_DST/libdaemon_example.so $MYSQL_SRC/plugin/daemon_example/libdaemon_example.so f 755 root root $PLUGIN_DST/libmemcached.so $MYSQL_SRC/plugin/innodb_memcached/daemon_memcached/libmemcached.so f 755 root root $PLUGIN_DST/mypluglib.so $MYSQL_SRC/plugin/fulltext/mypluglib.so f 755 root root $PLUGIN_DST/qa_auth_client.so $MYSQL_SRC/plugin/auth/qa_auth_client.so f 755 root root $PLUGIN_DST/qa_auth_interface.so $MYSQL_SRC/plugin/auth/qa_auth_interface.so f 755 root root $PLUGIN_DST/qa_auth_server.so $MYSQL_SRC/plugin/auth/qa_auth_server.so f 755 root root $PLUGIN_DST/semisync_master.so $MYSQL_SRC/plugin/semisync/semisync_master.so f 755 root root $PLUGIN_DST/semisync_slave.so $MYSQL_SRC/plugin/semisync/semisync_slave.so f 755 root root $PLUGIN_DST/validate_password.so $MYSQL_SRC/plugin/password_validation/validate_password.so d 755 root root $SBIN_DST - f 755 root root $SBIN_DST/$MYSQLD_BINARY $MYSQL_SRC/sql/$MYSQLD_BINARY # /usr/share/doc/... d 755 root root $DOCS_DST - f 644 root root $DOCS_DST/COPYING $MYSQL_SRC/COPYING f 644 root root $DOCS_DST/ChangeLog $MYSQL_SRC/Docs/ChangeLog f 644 root root $DOCS_DST/INFO_BIN $MYSQL_SRC/Docs/INFO_BIN f 644 root root $DOCS_DST/INFO_SRC $MYSQL_SRC/Docs/INFO_SRC f 644 root root $DOCS_DST/INSTALL-BINARY $MYSQL_SRC/Docs/INSTALL-BINARY f 644 root root $DOCS_DST/README $MYSQL_SRC/README f 644 root root $DOCS_DST/myisam.txt $MYSQL_SRC/Docs/myisam.txt f 644 root root $DOCS_DST/sp-imp-spec.txt $MYSQL_SRC/Docs/sp-imp-spec.txt # manpages d 755 root root $MAN_DST/man1 - f 644 root root $MAN_DST/man1/comp_err.1.gz $MYSQL_SRC/man/comp_err.1.gz #in client f 644 root root $MAN_DST/man1/innochecksum.1.gz $MYSQL_SRC/man/innochecksum.1.gz f 644 root root $MAN_DST/man1/msql2mysql.1.gz $MYSQL_SRC/man/msql2mysql.1.gz #in client f 644 root root $MAN_DST/man1/my_print_defaults.1.gz $MYSQL_SRC/man/my_print_defaults.1.gz f 644 root root $MAN_DST/man1/myisamchk.1.gz $MYSQL_SRC/man/myisamchk.1.gz f 644 root root $MAN_DST/man1/myisamlog.1.gz $MYSQL_SRC/man/myisamlog.1.gz f 644 root root $MAN_DST/man1/myisampack.1.gz $MYSQL_SRC/man/myisampack.1.gz f 644 root root $MAN_DST/man1/mysql.server.1.gz $MYSQL_SRC/man/mysql.server.1.gz f 644 root root $MAN_DST/man1/mysql_convert_table_format.1.gz $MYSQL_SRC/man/mysql_convert_table_format.1.gz #f 644 root root $MAN_DST/man1/mysql_fix_privilege_tables.1.gz $MYSQL_SRC/man/mysql_fix_privilege_tables.1.gz f 644 root root $MAN_DST/man1/mysql_install_db.1.gz $MYSQL_SRC/man/mysql_install_db.1.gz f 644 root root $MAN_DST/man1/mysql_secure_installation.1.gz $MYSQL_SRC/man/mysql_secure_installation.1.gz f 644 root root $MAN_DST/man1/mysql_setpermission.1.gz $MYSQL_SRC/man/mysql_setpermission.1.gz f 644 root root $MAN_DST/man1/mysql_tzinfo_to_sql.1.gz $MYSQL_SRC/man/mysql_tzinfo_to_sql.1.gz f 644 root root $MAN_DST/man1/mysql_upgrade.1.gz $MYSQL_SRC/man/mysql_upgrade.1.gz f 644 root root $MAN_DST/man1/mysql_zap.1.gz $MYSQL_SRC/man/mysql_zap.1.gz f 644 root root $MAN_DST/man1/mysqlbinlog.1.gz $MYSQL_SRC/man/mysqlbinlog.1.gz f 644 root root $MAN_DST/man1/mysqld_multi.1.gz $MYSQL_SRC/man/mysqld_multi.1.gz f 644 root root $MAN_DST/man1/mysqld_safe.1.gz $MYSQL_SRC/man/mysqld_safe.1.gz f 644 root root $MAN_DST/man1/mysqlhotcopy.1.gz $MYSQL_SRC/man/mysqlhotcopy.1.gz f 644 root root $MAN_DST/man1/mysqltest.1.gz $MYSQL_SRC/man/mysqltest.1.gz #in client f 644 root root $MAN_DST/man1/perror.1.gz $MYSQL_SRC/man/perror.1.gz f 644 root root $MAN_DST/man1/replace.1.gz $MYSQL_SRC/man/replace.1.gz f 644 root root $MAN_DST/man1/resolve_stack_dump.1.gz $MYSQL_SRC/man/resolve_stack_dump.1.gz f 644 root root $MAN_DST/man1/resolveip.1.gz $MYSQL_SRC/man/resolveip.1.gz d 755 root root $MAN_DST/man8 - f 644 root root $MAN_DST/man8/mysqld.8.gz $MYSQL_SRC/man/mysqld.8.gz f 644 root root $SHAR_DST $MYSQL_SRC/support-files/config.*.ini f 644 root root $SHAR_DST $MYSQL_SRC/scripts/*.sql f 644 root root $SHAR_DST/binary-configure $MYSQL_SRC/support-files/binary-configure f 644 root root $SHAR_DST/errmsg-utf8.txt $MYSQL_SRC/sql/share/errmsg-utf8.txt f 644 root root $SHAR_DST $MYSQL_SRC/support-files/my-*.cnf f 644 root root $SHAR_DST/mysql-log-rotate $MYSQL_SRC/support-files/mysql-log-rotate f 755 root root $SHAR_DST/mysql.server $MYSQL_SRC/support-files/mysql.server f 644 root root $SHAR_DST/mysqld_multi.server $MYSQL_SRC/support-files/mysqld_multi.server # f 644 root root $SHAR_DST/ndb-config-2-node.ini $MYSQL_SRC/support-files/ndb-config-2-node.ini d 755 root root $SHAR_DST/charsets - f 644 root root $SHAR_DST/charsets $MYSQL_SRC/sql/share/charsets/* $lang00=czech d 755 root root $SHAR_DST/${lang00} - f 644 root root $SHAR_DST/${lang00} $MYSQL_SRC/sql/share/${lang00}/* $lang01=danish d 755 root root $SHAR_DST/${lang01} - f 644 root root $SHAR_DST/${lang01} $MYSQL_SRC/sql/share/${lang01}/* $lang02=dutch d 755 root root $SHAR_DST/${lang02} - f 644 root root $SHAR_DST/${lang02} $MYSQL_SRC/sql/share/${lang02}/* $lang03=english d 755 root root $SHAR_DST/${lang03} - f 644 root root $SHAR_DST/${lang03} $MYSQL_SRC/sql/share/${lang03}/* $lang04=estonian d 755 root root $SHAR_DST/${lang04} - f 644 root root $SHAR_DST/${lang04} $MYSQL_SRC/sql/share/${lang04}/* $lang05=french d 755 root root $SHAR_DST/${lang05} - f 644 root root $SHAR_DST/${lang05} $MYSQL_SRC/sql/share/${lang05}/* $lang06=german d 755 root root $SHAR_DST/${lang06} - f 644 root root $SHAR_DST/${lang06} $MYSQL_SRC/sql/share/${lang06}/* $lang07=greek d 755 root root $SHAR_DST/${lang07} - f 644 root root $SHAR_DST/${lang07} $MYSQL_SRC/sql/share/${lang07}/* $lang08=hungarian d 755 root root $SHAR_DST/${lang08} - f 644 root root $SHAR_DST/${lang08} $MYSQL_SRC/sql/share/${lang08}/* $lang09=italian d 755 root root $SHAR_DST/${lang09} - f 644 root root $SHAR_DST/${lang09} $MYSQL_SRC/sql/share/${lang09}/* $lang10=japanese d 755 root root $SHAR_DST/${lang10} - f 644 root root $SHAR_DST/${lang10} $MYSQL_SRC/sql/share/${lang10}/* $lang11=korean d 755 root root $SHAR_DST/${lang11} - f 644 root root $SHAR_DST/${lang11} $MYSQL_SRC/sql/share/${lang11}/* $lang12=norwegian d 755 root root $SHAR_DST/${lang12} - f 644 root root $SHAR_DST/${lang12} $MYSQL_SRC/sql/share/${lang12}/* $lang13=norwegian-ny d 755 root root $SHAR_DST/${lang13} - f 644 root root $SHAR_DST/${lang13} $MYSQL_SRC/sql/share/${lang13}/* $lang14=polish d 755 root root $SHAR_DST/${lang14} - f 644 root root $SHAR_DST/${lang14} $MYSQL_SRC/sql/share/${lang14}/* $lang15=portuguese d 755 root root $SHAR_DST/${lang15} - f 644 root root $SHAR_DST/${lang15} $MYSQL_SRC/sql/share/${lang15}/* $lang16=romanian d 755 root root $SHAR_DST/${lang16} - f 644 root root $SHAR_DST/${lang16} $MYSQL_SRC/sql/share/${lang16}/* $lang17=russian d 755 root root $SHAR_DST/${lang17} - f 644 root root $SHAR_DST/${lang17} $MYSQL_SRC/sql/share/${lang17}/* $lang18=serbian d 755 root root $SHAR_DST/${lang18} - f 644 root root $SHAR_DST/${lang18} $MYSQL_SRC/sql/share/${lang18}/* $lang19=slovak d 755 root root $SHAR_DST/${lang19} - f 644 root root $SHAR_DST/${lang19} $MYSQL_SRC/sql/share/${lang19}/* $lang20=spanish d 755 root root $SHAR_DST/${lang20} - f 644 root root $SHAR_DST/${lang20} $MYSQL_SRC/sql/share/${lang20}/* $lang21=swedish d 755 root root $SHAR_DST/${lang21} - f 644 root root $SHAR_DST/${lang21} $MYSQL_SRC/sql/share/${lang21}/* $lang22=ukrainian d 755 root root $SHAR_DST/${lang22} - f 644 root root $SHAR_DST/${lang22} $MYSQL_SRC/sql/share/${lang22}/* d 755 mysql root /var/run/mysqld - # percona-galera-3-3.8-3390/scripts/mysql/debian/common.list000066400000000000000000000130021244131713600232410ustar00rootroot00000000000000# This is a MySQL-wsrep package description for ESP package manager # Debian specific part %product wsrep-enabled MySQL server %copyright MySQL AB, Codership Oy, All Rights Reserved %vendor Codership Oy %license COPYING %readme README %description MySQL server + wsrep patch (https://launchpad.net/codership-mysql) $mysql_version=${MYSQL_VER} $wsrep_version=${WSREP_VER} %version ${mysql_version}-${wsrep_version} %requires psmisc %requires debianutils 1.6 %requires libc6 2.4 %requires libdbi-perl %requires libdbd-mysql-perl 1.2202 %requires libgcc1 4.1.1 %requires libncurses5 5.6 %requires libstdc++6 4.1.1 %requires libwrap0 7.6 %requires perl %requires zlib1g 1.1.4 %requires lsof %replaces mysql-server-core 0.0.0 ${mysql_version} %replaces mysql-server-core-5.0 0.0.0 ${mysql_version} %replaces mysql-server-core-5.1 0.0.0 ${mysql_version} %replaces mysql-server 0.0.0 ${mysql_version} %replaces mysql-server-5.0 0.0.0 ${mysql_version} %replaces mysql-server-5.1 0.0.0 ${mysql_version} %provides mysql-server-core %provides mysql-server #%incompat mysql-server-core #%incompat mysql-server-core-4.1 #%incompat mysql-server-core-5.0 #%incompat mysql-server-core-5.1 #%incompat mysql-server #%incompat mysql-server-4.1 #%incompat mysql-server-5.0 #%incompat mysql-server-5.1 $prefix=/usr $CONF_DST=/etc/mysql $LIBS_DST=${prefix}/lib/mysql $PLUGIN_DST=${LIBS_DST}/plugin $SHAR_DST=${prefix}/share/mysql $SBIN_DST=${prefix}/sbin $BINS_DST=${prefix}/bin $DOCS_DST=${prefix}/share/doc/mysql-server-${MYSQL_MAJOR_VER}.${MYSQL_MINOR_VER} $MAN_DST=${prefix}/share/man # Distribution dependent files $SRC=$GALERA_SRC/scripts/mysql/debian $ETC=$SRC/etc d 755 root root /etc/init.d - f 755 root root /etc/init.d/mysql $SRC/mysql d 755 root root /etc/logrotate.d - f 755 root root /etc/logrotate.d/mysql-server $ETC/logrotate.d/mysql-server d 755 root root /etc/logcheck - d 755 root root /etc/logcheck/ignore.d.paranoid - f 644 root root /etc/logcheck/ignore.d.paranoid/mysql-server-${MYSQL_MAJOR_VER}_${MYSQL_MINOR_VER} $ETC/logcheck/ignore.d.paranoid/mysql-server-5_1 d 755 root root /etc/logcheck/ignore.d.server - f 644 root root /etc/logcheck/ignore.d.server/mysql-server-${MYSQL_MAJOR_VER}_${MYSQL_MINOR_VER} $ETC/logcheck/ignore.d.server/mysql-server-5_1 d 755 root root /etc/logcheck/ignore.d.workstation - f 644 root root /etc/logcheck/ignore.d.workstation/mysql-server-${MYSQL_MAJOR_VER}_${MYSQL_MINOR_VER} $ETC/logcheck/ignore.d.workstation/mysql-server-5_1 d 755 root root $CONF_DST f 755 root root $CONF_DST/debian-start $ETC/mysql/debian-start d 755 root root $CONF_DST/conf.d f 644 root root $CONF_DST/conf.d/mysqld_safe_syslog.cnf $ETC/mysql/conf.d/mysqld_safe_syslog.cnf d 755 root root $SHAR_DST - f 755 root root $SHAR_DST/debian-start.inc.sh $SRC/debian-start.inc.sh f 755 root root $SHAR_DST/echo_stderr $SRC/echo_stderr f 755 root root $BINS_DST/my_print_defaults_wsrep $MYSQL_SRC/extra/my_print_defaults ########################## # wsrep-specific files # ########################## c 640 mysql mysql $CONF_DST/conf.d/wsrep.cnf $MYSQL_SRC/support-files/wsrep.cnf f 755 root root $BINS_DST/wsrep_sst_common $MYSQL_SRC/scripts/wsrep_sst_common f 755 root root $BINS_DST/wsrep_sst_mysqldump $MYSQL_SRC/scripts/wsrep_sst_mysqldump f 755 root root $BINS_DST/wsrep_sst_rsync $MYSQL_SRC/scripts/wsrep_sst_rsync l 755 root root $BINS_DST/wsrep_sst_rsync_wan wsrep_sst_rsync #f 755 root root $BINS_DST/wsrep_sst_xtrabackup $MYSQL_SRC/scripts/wsrep_sst_xtrabackup f 644 root root $DOCS_DST/README-wsrep $MYSQL_SRC/Docs/README-wsrep f 644 root root $SHAR_DST/wsrep.cnf $MYSQL_SRC/support-files/wsrep.cnf f 644 root root $SHAR_DST/wsrep_notify $MYSQL_SRC/support-files/wsrep_notify ################################## # Distribution dependent scripts # ################################## $mysql_data=/var/lib/mysql # Add mysql group and user if there are none %preinstall </dev/null || addgroup --system mysql >/dev/null getent passwd mysql >/dev/null || \ adduser --system --disabled-login --ingroup mysql --home ${mysql_data} \ --gecos "MySQL Server" --shell /bin/false mysql >/dev/null [ -e "$BINS_DST/my_print_defaults" ] || \ ( cd $BINS_DST && ln -sf my_print_defaults_wsrep my_print_defaults ) EOF_PREINSTALL %postinstall </dev/null || exit $ ldconfig -n $LIBS_DST #test -d ${mysql_data} || (mysql_install_db --user=mysql --datadir=${mysql_data}) # it seems that we can run mysql_install_db regardless of existing tables. mysql_install_db --wsrep-on=0 --user=mysql --datadir=${mysql_data} --basedir=/usr # This is a fix/workaround for AppArmor profile provided with mysql-server deb [ ! -d /etc/apparmor.d/disable ] || \ ( cd /etc/apparmor.d/disable && ln -sf ../usr.sbin.mysqld ./ ) [ ! -x /etc/init.d/apparmor ] || /etc/init.d/apparmor restart EOF_POSTINSTALL %preremove </dev/null || exit $ [ ! -L $BINS_DST/my_print_defaults ] || rm -rf $BINS_DST/my_print_defaults [ ! -L /etc/apparmor.d/disable/usr.sbin.mysqld ] || rm -rf /etc/apparmor.d/disable/usr.sbin.mysqld [ ! -x /etc/init.d/apparmor ] || /etc/init.d/apparmor restart EOF_PREREMOVE # percona-galera-3-3.8-3390/scripts/mysql/debian/debian-start.inc.sh000077500000000000000000000050551244131713600245510ustar00rootroot00000000000000#!/bin/bash # # This file is included by /etc/mysql/debian-start # ## Check all unclosed tables. # - Requires the server to be up. # - Is supposed to run silently in background. function check_for_crashed_tables() { set -e set -u # But do it in the background to not stall the boot process. logger -p daemon.info -i -t$0 "Triggering myisam-recover for all MyISAM tables" # Checking for $? is unreliable so the size of the output is checked. # Some table handlers like HEAP do not support CHECK TABLE. tempfile=`tempfile` # We have to use xargs in this case, because a for loop barfs on the # spaces in the thing to be looped over. LC_ALL=C $MYSQL --skip-column-names --batch -e ' select concat('\''select count(*) into @discard from `'\'', TABLE_SCHEMA, '\''`.`'\'', TABLE_NAME, '\''`'\'') from information_schema.TABLES where ENGINE='\''MyISAM'\' | \ xargs -i $MYSQL --skip-column-names --silent --batch \ --force -e "{}" >$tempfile if [ -s $tempfile ]; then ( /bin/echo -e "\n" \ "Improperly closed tables are also reported if clients are accessing\n" \ "the tables *now*. A list of current connections is below.\n"; $MYADMIN processlist status ) >> $tempfile # Check for presence as a dependency on mailx would require an MTA. if [ -x /usr/bin/mailx ]; then mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile fi (echo "$MYCHECK_SUBJECT"; cat $tempfile) | logger -p daemon.warn -i -t$0 fi rm $tempfile } ## Check for tables needing an upgrade. # - Requires the server to be up. # - Is supposed to run silently in background. function upgrade_system_tables_if_necessary() { set -e set -u logger -p daemon.info -i -t$0 "Upgrading MySQL tables if necessary." # Filter all "duplicate column", "duplicate key" and "unknown column" # errors as the script is designed to be idempotent. LC_ALL=C $MYUPGRADE \ 2>&1 \ | egrep -v '^(1|@had|ERROR (1054|1060|1061))' \ | logger -p daemon.warn -i -t$0 } ## Check for the presence of both, root accounts with and without password. # This might have been caused by a bug related to mysql_install_db (#418672). function check_root_accounts() { set -e set -u logger -p daemon.info -i -t$0 "Checking for insecure root accounts." ret=$( echo "SELECT count(*) FROM mysql.user WHERE user='root' and password='';" | $MYSQL --skip-column-names ) if [ "$ret" -ne "0" ]; then logger -p daemon.warn -i -t$0 "WARNING: mysql.user contains $ret root accounts without password!" fi } percona-galera-3-3.8-3390/scripts/mysql/debian/echo_stderr000077500000000000000000000000331244131713600233030ustar00rootroot00000000000000#!/bin/bash echo "$*" 1>&2 percona-galera-3-3.8-3390/scripts/mysql/debian/etc/000077500000000000000000000000001244131713600216335ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/init.d/000077500000000000000000000000001244131713600230205ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/init.d/mysql000077500000000000000000000125071244131713600241200ustar00rootroot00000000000000#!/bin/bash # ### BEGIN INIT INFO # Provides: mysql # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Should-Start: $network $named $time # Should-Stop: $network $named $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start and stop the mysql database server daemon # Description: Controls the main MySQL database server daemon "mysqld" # and its wrapper script "mysqld_safe". ### END INIT INFO # set -e set -u ${DEBIAN_SCRIPT_DEBUG:+ set -v -x} test -x /usr/sbin/mysqld || exit 0 . /lib/lsb/init-functions SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) CONF=/etc/mysql/my.cnf MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" # priority can be overriden and "-s" adds output to stderr ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i" # Safeguard (relative paths, core dumps..) cd / umask 077 # mysqladmin likes to read /root/.my.cnf. This is usually not what I want # as many admins e.g. only store a password without a username there and # so break my scripts. export HOME=/etc/mysql/ ## Fetch a particular option from mysql's invocation. # # Usage: void mysqld_get_param option mysqld_get_param() { /usr/sbin/mysqld --print-defaults \ | tr " " "\n" \ | grep -- "--$1" \ | tail -n 1 \ | cut -d= -f2 } ## Do some sanity checks before even trying to start mysqld. sanity_checks() { # check for config file if [ ! -r /etc/mysql/my.cnf ]; then log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" echo "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER fi # check for diskspace shortage datadir=`mysqld_get_param datadir` if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then log_failure_msg "$0: ERROR: The partition with $datadir is too full!" echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER exit 1 fi } ## Checks if there is a server running and if so if it is accessible. # # check_alive insists on a pingable server # check_dead also fails if there is a lost mysqld in the process list # # Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn] mysqld_status () { ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? )) ps_alive=0 pidfile=`mysqld_get_param pid-file` if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi if [ "$1" = "check_alive" -a $ping_alive = 1 ] || [ "$1" = "check_dead" -a $ping_alive = 0 -a $ps_alive = 0 ]; then return 0 # EXIT_SUCCESS else if [ "$2" = "warn" ]; then echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug fi return 1 # EXIT_FAILURE fi } # # main() # case "${1:-''}" in 'start') sanity_checks; # Start daemon log_daemon_msg "Starting MySQL database server" "mysqld" if mysqld_status check_alive nowarn; then log_progress_msg "already running" log_end_msg 0 else # Could be removed during boot test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld # Start MySQL! /usr/bin/mysqld_safe > /dev/null 2>&1 & # 6s was reported in #352070 to be too few when using ndbcluster for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do sleep 1 if mysqld_status check_alive nowarn ; then break; fi log_progress_msg "." done if mysqld_status check_alive warn; then log_end_msg 0 # Now start mysqlcheck or whatever the admin wants. output=$(/etc/mysql/debian-start) [ -n "$output" ] && log_action_msg "$output" else log_end_msg 1 log_failure_msg "Please take a look at the syslog" fi fi ;; 'stop') # * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible # at least for cron, we can rely on it here, too. (although we have # to specify it explicit as e.g. sudo environments points to the normal # users home and not /root) log_daemon_msg "Stopping MySQL database server" "mysqld" if ! mysqld_status check_dead nowarn; then set +e shutdown_out=`$MYADMIN shutdown 2>&1`; r=$? set -e if [ "$r" -ne 0 ]; then log_end_msg 1 [ "$VERBOSE" != "no" ] && log_failure_msg "Error: $shutdown_out" log_daemon_msg "Killing MySQL database server by signal" "mysqld" killall -15 mysqld server_down= for i in 1 2 3 4 5 6 7 8 9 10; do sleep 1 if mysqld_status check_dead nowarn; then server_down=1; break; fi done if test -z "$server_down"; then killall -9 mysqld; fi fi fi if ! mysqld_status check_dead warn; then log_end_msg 1 log_failure_msg "Please stop MySQL manually and read /usr/share/doc/mysql-server-5.1/README.Debian.gz!" exit -1 else log_end_msg 0 fi ;; 'restart') set +e; $SELF stop; set -e $SELF start ;; 'reload'|'force-reload') log_daemon_msg "Reloading MySQL database server" "mysqld" $MYADMIN reload log_end_msg 0 ;; 'status') if mysqld_status check_alive nowarn; then log_action_msg "$($MYADMIN version)" else log_action_msg "MySQL is stopped." exit 3 fi ;; *) echo "Usage: $SELF start|stop|restart|reload|force-reload|status" exit 1 ;; esac percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/000077500000000000000000000000001244131713600234125ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.paranoid/000077500000000000000000000000001244131713600267135ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.paranoid/mysql-server-5_1000066400000000000000000000013101244131713600316640ustar00rootroot00000000000000/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ /etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ /etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ mysqld\[[0-9]+\]: $ mysqld\[[0-9]+\]: Version: .* socket: '/var/run/mysqld/mysqld.sock' port: 3306$ mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ mysqld_safe\[[0-9]+\]: started$ usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.server/000077500000000000000000000000001244131713600264245ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.server/mysql-server-5_1000066400000000000000000000043361244131713600314100ustar00rootroot00000000000000/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ /etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ /etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ /etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ mysqld\[[0-9]+\]: ?$ mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed mysqld\[[0-9]+\]: .*InnoDB: Started; mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ mysqld\[[0-9]+\]: Version: .* socket mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ mysqld_safe\[[0-9]+\]: ?$ mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ mysqld_safe\[[0-9]+\]: ended$ mysqld_safe\[[0-9]+\]: http://www.mysql.com$ mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ mysqld_safe\[[0-9]+\]: started$ mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$ mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$ mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$ usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.workstation/000077500000000000000000000000001244131713600275025ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logcheck/ignore.d.workstation/mysql-server-5_1000066400000000000000000000043361244131713600324660ustar00rootroot00000000000000/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ /etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ /etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ /etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ mysqld\[[0-9]+\]: ?$ mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed mysqld\[[0-9]+\]: .*InnoDB: Started; mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ mysqld\[[0-9]+\]: Version: .* socket mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ mysqld_safe\[[0-9]+\]: ?$ mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ mysqld_safe\[[0-9]+\]: ended$ mysqld_safe\[[0-9]+\]: http://www.mysql.com$ mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ mysqld_safe\[[0-9]+\]: started$ mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$ mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$ mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$ usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$ usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$ percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logrotate.d/000077500000000000000000000000001244131713600240555ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/logrotate.d/mysql-server000066400000000000000000000015051244131713600264520ustar00rootroot00000000000000# - I put everything in one block and added sharedscripts, so that mysql gets # flush-logs'd only once. # Else the binary logs would automatically increase by n times every day. # - The error log is obsolete, messages go to syslog now. /var/log/mysql.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log { daily rotate 7 missingok create 640 mysql adm compress sharedscripts postrotate test -x /usr/bin/mysqladmin || exit 0 # If this fails, check debian.conf! MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then # Really no mysqld or rather a missing debian-sys-maint user? # If this occurs and is not a error please report a bug. if ps cax | grep -q mysqld; then exit 1 fi else $MYADMIN flush-logs fi endscript } percona-galera-3-3.8-3390/scripts/mysql/debian/etc/mysql/000077500000000000000000000000001244131713600230005ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/mysql/conf.d/000077500000000000000000000000001244131713600241475ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/debian/etc/mysql/conf.d/mysqld_safe_syslog.cnf000066400000000000000000000000251244131713600305430ustar00rootroot00000000000000[mysqld_safe] syslog percona-galera-3-3.8-3390/scripts/mysql/debian/etc/mysql/debian-start000077500000000000000000000022561244131713600253100ustar00rootroot00000000000000#!/bin/bash # # This script is executed by "/etc/init.d/mysql" on every (re)start. # # Changes to this file will be preserved when updating the Debian package. # source /usr/share/mysql/debian-start.inc.sh MYSQL="/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf" MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" MYUPGRADE="/usr/bin/mysql_upgrade --defaults-extra-file=/etc/mysql/debian.cnf" MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf" MYCHECK_SUBJECT="WARNING: mysqlcheck has found corrupt tables" MYCHECK_PARAMS="--all-databases --fast --silent" MYCHECK_RCPT="root" # The following commands should be run when the server is up but in background # where they do not block the server start and in one shell instance so that # they run sequentially. They are supposed not to echo anything to stdout. # If you want to disable the check for crashed tables comment # "check_for_crashed_tables" out. # (There may be no output to stdout inside the background process!) echo "Checking for corrupt, not cleanly closed and upgrade needing tables." ( upgrade_system_tables_if_necessary; check_root_accounts; check_for_crashed_tables; ) >&2 & exit 0 percona-galera-3-3.8-3390/scripts/mysql/debian/my.cnf000066400000000000000000000101271244131713600221760ustar00rootroot00000000000000# # The MySQL database server configuration file. # # You can copy this to one of: # - "/etc/mysql/my.cnf" to set global options, # - "~/.my.cnf" to set user-specific options. # # One can use all long options that the program supports. # Run program with --help to get a list of available options and with # --print-defaults to see which it would actually understand and use. # # For explanations see # http://dev.mysql.com/doc/mysql/en/server-system-variables.html # This will be passed to all mysql clients # It has been reported that passwords should be enclosed with ticks/quotes # escpecially if they contain "#" chars... # Remember to edit /etc/mysql/debian.cnf when changing the socket location. [client] port = 3306 socket = /var/run/mysqld/mysqld.sock # Here is entries for some specific programs # The following values assume you have at least 32M ram # This was formally known as [safe_mysqld]. Both versions are currently parsed. [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] # # * Basic Settings # # # * IMPORTANT # If you make changes to these settings and your system uses apparmor, you may # also need to also adjust /etc/apparmor.d/usr.sbin.mysqld. # user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp skip-external-locking # # Instead of skip-networking the default is now to listen only on # localhost which is more compatible and is not less secure. # WSREP NOTE: for state transfer to work, bind-address should be an address # of external interface! If you define it explicitely, see SST # options in /etc/mysql/conf.d/wsrep.cnf #bind-address = 127.0.0.1 # # * Fine Tuning # key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K thread_cache_size = 8 # This replaces the startup script and checks MyISAM tables if needed # the first time they are touched myisam-recover = BACKUP #max_connections = 100 #table_cache = 64 #thread_concurrency = 10 # # * Query Cache Configuration # query_cache_limit = 1M query_cache_size = 16M # # * Logging and Replication # # Both location gets rotated by the cronjob. # Be aware that this log type is a performance killer. # As of 5.1 you can enable the log at runtime! #general_log_file = /var/log/mysql/mysql.log #general_log = 1 # # Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf. # # Here you can see queries with especially long duration #log_slow_queries = /var/log/mysql/mysql-slow.log #long_query_time = 2 #log-queries-not-using-indexes # # The following can be used as easy to replay backup logs or for replication. # note: if you are setting up a replication slave, see README.Debian about # other settings you may need to change. # WSREP NOTE: traditional MySQL replication and binlogging is not supported # and untested with this patch. Some binlog options may cause mysqld # crash. #server-id = 1 #log_bin = /var/log/mysql/mysql-bin.log #expire_logs_days = 10 #max_binlog_size = 100M #binlog_do_db = include_database_name #binlog_ignore_db = include_database_name # # * InnoDB # # InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/. # Read the manual for more InnoDB related options. There are many! # WSREP NOTE: check /etc/mysql/conf.d/wsrep.cnf for some mandatory InnoDB # options. Don't try to override them! # # * Security Features # # Read the manual, too, if you want chroot! # chroot = /var/lib/mysql/ # # For generating SSL certificates I recommend the OpenSSL GUI "tinyca". # # ssl-ca=/etc/mysql/cacert.pem # ssl-cert=/etc/mysql/server-cert.pem # ssl-key=/etc/mysql/server-key.pem [mysqldump] quick quote-names max_allowed_packet = 16M [mysql] #no-auto-rehash # faster start of mysql but no tab completition [isamchk] key_buffer = 16M # # * IMPORTANT: Additional settings that can override those from this file! # The files must end with '.cnf', otherwise they'll be ignored. # WSREP NOTE: additional wsrep configuration is in wsrep.cnf # !includedir /etc/mysql/conf.d/ percona-galera-3-3.8-3390/scripts/mysql/debian/mysql000077500000000000000000000137431244131713600221630ustar00rootroot00000000000000#!/bin/bash # ### BEGIN INIT INFO # Provides: mysql # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Should-Start: $network $named $time # Should-Stop: $network $named $time # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start and stop the mysql database server daemon # Description: Controls the main MySQL database server daemon "mysqld" # and its wrapper script "mysqld_safe". ### END INIT INFO # set -e set -u ${DEBIAN_SCRIPT_DEBUG:+ set -v -x} test -x /usr/sbin/mysqld || exit 0 . /lib/lsb/init-functions SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) CONF=/etc/mysql/my.cnf # MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" # priority can be overriden and "-s" adds output to stderr ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i" # Safeguard (relative paths, core dumps..) cd / umask 077 # mysqladmin likes to read /root/.my.cnf. This is usually not what I want # as many admins e.g. only store a password without a username there and # so break my scripts. export HOME=/etc/mysql/ ## Fetch a particular option from mysql's invocation. # # Usage: void mysqld_get_param option mysqld_get_param() { /usr/sbin/mysqld --print-defaults \ | tr " " "\n" \ | grep -- "--$1" \ | tail -n 1 \ | cut -d= -f2 } # Determine parameters once per script invocation datadir=`mysqld_get_param datadir` [ -z "$datadir" ] && datadir="/var/lib/mysql" pidfile=`mysqld_get_param pid-file` [ -z "$pidfile" ] && pidfile="$datadir/$(hostname).pid" ## Do some sanity checks before even trying to start mysqld. sanity_checks() { # check for config file if [ ! -r /etc/mysql/my.cnf ]; then log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" echo "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER fi # check for diskspace shortage if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then log_failure_msg "$0: ERROR: The partition with $datadir is too full!" echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER exit 1 fi } ## Checks if there is a server running and if so if it is accessible. # # check_alive insists on a pingable server # check_dead also fails if there is a lost mysqld in the process list # # Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn] mysqld_status() { # ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? )) ps_alive=0 if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi if [ "$1" = "check_alive" -a $ps_alive = 1 ] || [ "$1" = "check_dead" -a $ps_alive = 0 ]; then return 0 # EXIT_SUCCESS else if [ "$2" = "warn" ]; then # echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug echo -e "$ps_alive processes alive\n" | $ERR_LOGGER -p daemon.debug fi return 1 # EXIT_FAILURE fi } # # main() # cmd=${1:-''} [ $# -ge 1 ] && shift other_args="$*" case "$cmd" in 'start') sanity_checks; # Start daemon log_daemon_msg "Starting MySQL database server" "mysqld" if mysqld_status check_alive nowarn; then log_progress_msg "already running" log_end_msg 0 else # Could be removed during boot test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld # Check for additional wsrep options WSREP_OPTS=${WSREP_OPTS:-""} WSREP_PROVIDER=${WSREP_PROVIDER:-""} WSREP_CLUSTER_ADDRESS=${WSREP_CLUSTER_ADDRESS:-""} test -n "$WSREP_PROVIDER" && \ WSREP_OPTS="$WSREP_OPTS --wsrep_provider=$WSREP_PROVIDER" test -n "$WSREP_CLUSTER_ADDRESS" && \ WSREP_OPTS="$WSREP_OPTS --wsrep_cluster_address=$WSREP_CLUSTER_ADDRESS" # Start MySQL!. /usr/bin/mysqld_safe $WSREP_OPTS $other_args > /dev/null 2>&1 & # 6s was reported in #352070 to be too few when using ndbcluster for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do sleep 1 if mysqld_status check_alive nowarn ; then break; fi log_progress_msg "." done if mysqld_status check_alive warn; then log_end_msg 0 # Now start mysqlcheck or whatever the admin wants. # output=$(/etc/mysql/debian-start) # [ -n "$output" ] && log_action_msg "$output" else log_end_msg 1 log_failure_msg "Please take a look at the syslog" fi fi ;; 'stop') # * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible # at least for cron, we can rely on it here, too. (although we have # to specify it explicit as e.g. sudo environments points to the normal # users home and not /root) log_daemon_msg "Stopping MySQL database server" "mysqld" if ! mysqld_status check_dead nowarn; then log_daemon_msg "Killing MySQL database server by signal" "mysqld" pid=$(cat $pidfile || echo 0) if [ $pid -eq 0 ]; then log_failure_msg "Failed to get MySQL server pid" exit 1 fi kill -15 $pid server_down= for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do log_progress_msg "." sleep 1 if mysqld_status check_dead nowarn; then server_down=1; break; fi done fi if ! mysqld_status check_dead warn; then log_end_msg 1 log_failure_msg "Please stop MySQL manually and read /usr/share/doc/mysql-server-5.1/README.Debian.gz!" exit -1 else log_end_msg 0 fi ;; 'restart') set +e; $SELF stop; set -e $SELF start $other_args ;; 'reload'|'force-reload') log_daemon_msg "Reloading MySQL database server" "mysqld" $MYADMIN reload log_end_msg 0 ;; 'status') if mysqld_status check_alive nowarn; then # log_action_msg "$($MYADMIN version)" log_action_msg "MySQL is running (PID: $(cat $pidfile))" else log_action_msg "MySQL is stopped." exit 3 fi ;; *) echo "Usage: $SELF start|stop|restart|reload|force-reload|status" exit 1 ;; esac percona-galera-3-3.8-3390/scripts/mysql/debian/mysql-server-wsrep.list000066400000000000000000000000351244131713600255620ustar00rootroot00000000000000%include ${MYSQL_MAJOR}.list percona-galera-3-3.8-3390/scripts/mysql/debian/mysqld_safe-5.1000077500000000000000000000431261244131713600236240ustar00rootroot00000000000000#!/bin/sh # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # # Script to start the MySQL daemon and restart it if it dies unexpectedly # # This should be executed in the MySQL base directory if you are using a # binary installation that is not installed in its compile-time default # location # # mysql.server works by first doing a cd to the base directory and from there # executing mysqld_safe KILL_MYSQLD=1; MYSQLD= niceness=0 # Initial logging status: error log is not open, and not using syslog logging=init want_syslog=0 syslog_tag= user='mysql' pid_file= err_log= syslog_tag_mysqld=mysqld syslog_tag_mysqld_safe=mysqld_safe umask 007 defaults= case "$1" in --no-defaults|--defaults-file=*|--defaults-extra-file=*) defaults="$1"; shift ;; esac usage () { cat <> "$err_log" ;; syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac } log_error () { log_generic daemon.error "$@" >&2 } log_notice () { log_generic daemon.notice "$@" } eval_log_error () { cmd="$1" case $logging in file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;; syslog) # mysqld often prefixes its messages with a timestamp, which is # redundant when logging to syslog (which adds its own timestamp) # However, we don't strip the timestamp with sed here, because # sed buffers output (only GNU sed supports a -u (unbuffered) option) # which means that messages may not get sent to syslog until the # mysqld process quits. cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error & wait" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac #echo "Running mysqld: [$cmd]" eval "$cmd" } shell_quote_string() { # This sed command makes sure that any special chars are quoted, # so the arg gets passed exactly to the server. echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } wsrep_pick_url() { [ $# -eq 0 ] return 0 if ! which nc >/dev/null; then log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." return 1 fi local url # Assuming URL in the form scheme://host:port # If host and port are not NULL, the liveness of URL is assumed to be tested # If port part is absent, the url is returned literally and unconditionally # If every URL has port but none is reachable, nothing is returned for url in `echo $@ | sed s/,/\ /g` 0; do local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` local port=`echo $url | cut -d \: -f 3` [ -z "$port" ] && break nc -z "$host" $port >/dev/null && break done if [ "$url" == "0" ]; then log_error "ERROR: none of the URLs in '$@' is reachable." return 1 fi echo $url } parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on # the command line) into the args variable. pick_args= if test "$1" = PICK-ARGS-FROM-ARGV then pick_args=1 shift fi for arg do val=`echo "$arg" | sed -e "s;--[^=]*=;;"` case "$arg" in # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*) DATADIR="$val" ;; --pid-file=*) pid_file="$val" ;; --user=*) user="$val"; SET_USER=1 ;; # these might have been set in a [mysqld_safe] section of my.cnf # they are added to mysqld command line to override settings from my.cnf --log-error=*) err_log="$val" ;; --port=*) mysql_tcp_port="$val" ;; --socket=*) mysql_unix_port="$val" ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; --mysqld=*) MYSQLD="$val" ;; --mysqld-version=*) if test -n "$val" then MYSQLD="mysqld-$val" else MYSQLD="mysqld" fi ;; --nice=*) niceness="$val" ;; --open-files-limit=*) open_files="$val" ;; --open_files_limit=*) open_files="$val" ;; --skip-kill-mysqld*) KILL_MYSQLD=0 ;; --syslog) want_syslog=1 ;; --skip-syslog) want_syslog=0 ;; --syslog-tag=*) syslog_tag="$val" ;; --timezone=*) TZ="$val"; export TZ; ;; --wsrep[-_]urls=*) wsrep_urls="$val"; ;; --help) usage ;; *) if test -n "$pick_args" then append_arg_to_args "$arg" fi ;; esac done } # # First, try to find BASEDIR and ledir (where mysqld is) # if echo '/usr/share/mysql' | grep '^/usr' > /dev/null then relpkgdata=`echo '/usr/share/mysql' | sed -e 's,^/usr,,' -e 's,^/,,' -e 's,^,./,'` else # pkgdatadir is not relative to prefix relpkgdata='/usr/share/mysql' fi MY_PWD=`pwd` # Check for the directories we would expect from a binary release install if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" then # BASEDIR is already overridden on command line. Do not re-set. # Use BASEDIR to discover le. if test -x "$MY_BASEDIR_VERSION/libexec/mysqld" then ledir="$MY_BASEDIR_VERSION/libexec" else ledir="$MY_BASEDIR_VERSION/bin" fi elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are ledir="$MY_PWD/bin" # Where mysqld is # Check for the directories we would expect from a source install elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are ledir="$MY_PWD/libexec" # Where mysqld is # Since we didn't find anything, used the compiled-in defaults else MY_BASEDIR_VERSION='/usr' ledir='/usr/sbin' fi # # Second, try to find the data directory # # Try where the binary installs put it if test -d $MY_BASEDIR_VERSION/data/mysql then DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then defaults="--defaults-extra-file=$DATADIR/my.cnf" fi # Next try where the source installs put it elif test -d $MY_BASEDIR_VERSION/var/mysql then DATADIR=$MY_BASEDIR_VERSION/var # Or just give up and use our compiled-in default else DATADIR=/var/lib/mysql fi if test -z "$MYSQL_HOME" then if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then log_error "WARNING: Found two instances of my.cnf - $MY_BASEDIR_VERSION/my.cnf and $DATADIR/my.cnf IGNORING $DATADIR/my.cnf" MYSQL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then log_error "WARNING: Found $DATADIR/my.cnf The data directory is a deprecated location for my.cnf, please move it to $MY_BASEDIR_VERSION/my.cnf" MYSQL_HOME=$DATADIR else MYSQL_HOME=$MY_BASEDIR_VERSION fi fi export MYSQL_HOME # Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] # and then merge with the command line arguments if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults" then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults" elif test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" elif test -x /usr/bin/my_print_defaults then print_defaults="/usr/bin/my_print_defaults" elif test -x /usr/bin/mysql_print_defaults then print_defaults="/usr/bin/mysql_print_defaults" else print_defaults="my_print_defaults" fi append_arg_to_args () { args="$args "`shell_quote_string "$1"` } args= SET_USER=2 parse_arguments `$print_defaults $defaults --loose-verbose mysqld server` if test $SET_USER -eq 2 then SET_USER=0 fi parse_arguments `$print_defaults $defaults --loose-verbose mysqld_safe safe_mysqld` parse_arguments PICK-ARGS-FROM-ARGV "$@" # Determine what logging facility to use # Ensure that 'logger' exists, if it's requested if [ $want_syslog -eq 1 ] then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then log_error "--syslog requested, but no 'logger' program found. Please ensure that 'logger' is in your PATH, or do not specify the --syslog option to mysqld_safe." exit 1 fi fi if [ -n "$err_log" -o $want_syslog -eq 0 ] then if [ -n "$err_log" ] then # mysqld adds ".err" if there is no extension on the --log-error # argument; must match that here, or mysqld_safe will write to a # different log file than mysqld # mysqld does not add ".err" to "--log-error=foo."; it considers a # trailing "." as an extension if expr "$err_log" : '.*\.[^/]*$' > /dev/null then : else err_log="$err_log".err fi case "$err_log" in /* ) ;; * ) err_log="$DATADIR/$err_log" ;; esac else err_log=$DATADIR/`/bin/hostname`.err fi append_arg_to_args "--log-error=$err_log" if [ $want_syslog -eq 1 ] then # User explicitly asked for syslog, so warn that it isn't used log_error "Can't log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect." fi # Log to err_log file log_notice "Logging to '$err_log'." logging=file else if [ -n "$syslog_tag" ] then # Sanitize the syslog tag syslog_tag=`echo "$syslog_tag" | sed -e 's/[^a-zA-Z0-9_-]/_/g'` syslog_tag_mysqld_safe="${syslog_tag_mysqld_safe}-$syslog_tag" syslog_tag_mysqld="${syslog_tag_mysqld}-$syslog_tag" fi log_notice "Logging to syslog." logging=syslog fi USER_OPTION="" if test -w / -o "$USER" = "root" then if test "$user" != "root" -o $SET_USER = 1 then USER_OPTION="--user=$user" fi # Change the err log to the right user, if it is in use if [ $want_syslog -eq 0 ]; then touch "$err_log" chown $user "$err_log" fi if test -n "$open_files" then ulimit -n $open_files fi fi if test -n "$open_files" then append_arg_to_args "--open-files-limit=$open_files" fi safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-/var/run/mysqld/mysqld.sock}} # Make sure that directory for $safe_mysql_unix_port exists mysql_unix_port_dir=`dirname $safe_mysql_unix_port` if [ ! -d $mysql_unix_port_dir ] then mkdir $mysql_unix_port_dir chown $user $mysql_unix_port_dir chmod 755 $mysql_unix_port_dir fi # If the user doesn't specify a binary, we assume name "mysqld" if test -z "$MYSQLD" then MYSQLD=mysqld fi if test ! -x "$ledir/$MYSQLD" then log_error "The file $ledir/$MYSQLD does not exist or is not executable. Please cd to the mysql installation directory and restart this script from there as follows: ./bin/mysqld_safe& See http://dev.mysql.com/doc/mysql/en/mysqld-safe.html for more information" exit 1 fi if test -z "$pid_file" then pid_file="$DATADIR/`/bin/hostname`.pid" else case "$pid_file" in /* ) ;; * ) pid_file="$DATADIR/$pid_file" ;; esac fi append_arg_to_args "--pid-file=$pid_file" if test -n "$mysql_unix_port" then append_arg_to_args "--socket=$mysql_unix_port" fi if test -n "$mysql_tcp_port" then append_arg_to_args "--port=$mysql_tcp_port" fi if test $niceness -eq 0 then NOHUP_NICENESS="nohup" else NOHUP_NICENESS="nohup nice -$niceness" fi # Using nice with no args to get the niceness level is GNU-specific. # This check could be extended for other operating systems (e.g., # BSD could use "nohup sh -c 'ps -o nice -p $$' | tail -1"). # But, it also seems that GNU nohup is the only one which messes # with the priority, so this is okay. if nohup nice > /dev/null 2>&1 then normal_niceness=`nice` nohup_niceness=`nohup nice 2>/dev/null` numeric_nice_values=1 for val in $normal_niceness $nohup_niceness do case "$val" in -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \ [0-9] | [0-9][0-9] | [0-9][0-9][0-9] ) ;; * ) numeric_nice_values=0 ;; esac done if test $numeric_nice_values -eq 1 then nice_value_diff=`expr $nohup_niceness - $normal_niceness` if test $? -eq 0 && test $nice_value_diff -gt 0 && \ nice --$nice_value_diff echo testing > /dev/null 2>&1 then # nohup increases the priority (bad), and we are permitted # to lower the priority with respect to the value the user # might have been given niceness=`expr $niceness - $nice_value_diff` NOHUP_NICENESS="nice -$niceness nohup" fi fi else if nohup echo testing > /dev/null 2>&1 then : else # nohup doesn't work on this system NOHUP_NICENESS="" fi fi # Try to set the core file size (even if we aren't root) because many systems # don't specify a hard limit on core file size. if test -n "$core_file_size" then ulimit -c $core_file_size fi # # If there exists an old pid file, check if the daemon is already running # Note: The switches to 'ps' may depend on your operating system if test -f "$pid_file" then PID=`cat "$pid_file"` if /bin/kill -0 $PID > /dev/null 2> /dev/null then if /bin/ps wwwp $PID | grep -v " grep" | grep -v mysqld_safe | grep -- "$MYSQLD" > /dev/null then # The pid contains a mysqld process log_error "A mysqld process already exists" exit 1 fi fi rm -f "$pid_file" if test -f "$pid_file" then log_error "Fatal error: Can't remove the pid file: $pid_file Please remove it manually and start $0 again; mysqld daemon not started" exit 1 fi fi # # From now on, we catch signals to do a proper shutdown of mysqld # when signalled to do so. # trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh & wait' 1 # HUP trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM # # Uncomment the following lines if you want all tables to be automatically # checked and repaired during startup. You should add sensible key_buffer # and sort_buffer values to my.cnf to improve check performance or require # less disk space. # Alternatively, you can start mysqld with the "myisam-recover" option. See # the manual for details. # # echo "Checking tables in $DATADIR" # $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI # $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM # Does this work on all systems? #if type ulimit | grep "shell builtin" > /dev/null #then # ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems #fi cmd="$NOHUP_NICENESS" for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "$USER_OPTION" do cmd="$cmd "`shell_quote_string "$i"` done cmd="$cmd $args" # Avoid 'nohup: ignoring input' warning test -n "$NOHUP_NICENESS" && cmd="$cmd < /dev/null" log_notice "Starting $MYSQLD daemon with databases from $DATADIR" while true do rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address if [ -z "$url" ] then eval_log_error "$cmd" else eval_log_error "$cmd --wsrep_cluster_address=$url" fi if test ! -f "$pid_file" # This is removed if normal shutdown then break fi if true && test $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) # but should work for the rest of the servers. # The only thing is ps x => redhat 5 gives warnings when using ps -x. # kill -9 is used or the process won't react on the kill. numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` log_notice "Number of processes running now: $numofproces" I=1 while test "$I" -le "$numofproces" do PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` for T in $PROC do break done # echo "TEST $I - $T **" if kill -9 $T then log_error "$MYSQLD process hanging, pid $T - killed" else break fi I=`expr $I + 1` done fi log_notice "mysqld restarted" done log_notice "mysqld from pid file $pid_file ended" percona-galera-3-3.8-3390/scripts/mysql/debian/mysqld_safe-5.5000077500000000000000000000632311244131713600236270ustar00rootroot00000000000000#!/bin/sh # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB # This file is public domain and comes with NO WARRANTY of any kind # # Script to start the MySQL daemon and restart it if it dies unexpectedly # # This should be executed in the MySQL base directory if you are using a # binary installation that is not installed in its compile-time default # location # # mysql.server works by first doing a cd to the base directory and from there # executing mysqld_safe # Initialize script globals KILL_MYSQLD=1; MYSQLD= niceness=0 mysqld_ld_preload= mysqld_ld_library_path= # Initial logging status: error log is not open, and not using syslog logging=init want_syslog=0 syslog_tag= user='mysql' pid_file= err_log= syslog_tag_mysqld=mysqld syslog_tag_mysqld_safe=mysqld_safe umask 007 defaults= case "$1" in --no-defaults|--defaults-file=*|--defaults-extra-file=*) defaults="$1"; shift ;; esac usage () { cat <> "$err_log" ;; syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac } log_error () { log_generic daemon.error "$@" >&2 } log_notice () { log_generic daemon.notice "$@" } eval_log_error () { local cmd="$1" case $logging in file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;; syslog) # mysqld often prefixes its messages with a timestamp, which is # redundant when logging to syslog (which adds its own timestamp) # However, we don't strip the timestamp with sed here, because # sed buffers output (only GNU sed supports a -u (unbuffered) option) # which means that messages may not get sent to syslog until the # mysqld process quits. cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error & wait" ;; *) echo "Internal program error (non-fatal):" \ " unknown logging method '$logging'" >&2 ;; esac #echo "Running mysqld: [$cmd]" eval "$cmd" } shell_quote_string() { # This sed command makes sure that any special chars are quoted, # so the arg gets passed exactly to the server. echo "$1" | sed -e 's,\([^a-zA-Z0-9/_.=-]\),\\\1,g' } wsrep_pick_url() { [ $# -eq 0 ] return 0 if ! which nc >/dev/null; then log_error "ERROR: nc tool not found in PATH! Make sure you have it installed." return 1 fi local url # Assuming URL in the form scheme://host:port # If host and port are not NULL, the liveness of URL is assumed to be tested # If port part is absent, the url is returned literally and unconditionally # If every URL has port but none is reachable, nothing is returned for url in `echo $@ | sed s/,/\ /g` 0; do local host=`echo $url | cut -d \: -f 2 | sed s/^\\\/\\\///` local port=`echo $url | cut -d \: -f 3` [ -z "$port" ] && break nc -z "$host" $port >/dev/null && break done if [ "$url" == "0" ]; then log_error "ERROR: none of the URLs in '$@' is reachable." return 1 fi echo $url } # Run mysqld with --wsrep-recover and parse recovered position from log. # Position will be stored in wsrep_start_position_opt global. wsrep_start_position_opt="" wsrep_recover_position() { local mysqld_cmd="$@" local wr_logfile=$(mktemp) local euid=$(id -u) local ret=0 [ "$euid" = "0" ] && chown $user $wr_logfile chmod 600 $wr_logfile log_notice "WSREP: Running position recovery with --log_error=$wr_logfile" $mysqld_cmd --log_error=$wr_logfile --wsrep-recover local rp="$(grep 'WSREP: Recovered position:' $wr_logfile)" if [ -z "$rp" ]; then local skipped="$(grep WSREP $wr_logfile | grep 'skipping position recovery')" if [ -z "$skipped" ]; then log_error "WSREP: Failed to recover position: " `cat $wr_logfile`; ret=1 else log_notice "WSREP: Position recovery skipped" fi else local start_pos="$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ | sed 's/^[ \t]*//')" log_notice "WSREP: Recovered position $start_pos" wsrep_start_position_opt="--wsrep_start_position=$start_pos" fi rm $wr_logfile return $ret } parse_arguments() { # We only need to pass arguments through to the server if we don't # handle them here. So, we collect unrecognized options (passed on # the command line) into the args variable. pick_args= if test "$1" = PICK-ARGS-FROM-ARGV then pick_args=1 shift fi for arg do # the parameter after "=", or the whole $arg if no match val=`echo "$arg" | sed -e 's;^--[^=]*=;;'` # what's before "=", or the whole $arg if no match optname=`echo "$arg" | sed -e 's/^\(--[^=]*\)=.*$/\1/'` # replace "_" by "-" ; mysqld_safe must accept "_" like mysqld does. optname_subst=`echo "$optname" | sed 's/_/-/g'` arg=`echo $arg | sed "s/^$optname/$optname_subst/"` case "$arg" in # these get passed explicitly to mysqld --basedir=*) MY_BASEDIR_VERSION="$val" ;; --datadir=*) DATADIR="$val" ;; --pid-file=*) pid_file="$val" ;; --plugin-dir=*) PLUGIN_DIR="$val" ;; --user=*) user="$val"; SET_USER=1 ;; # these might have been set in a [mysqld_safe] section of my.cnf # they are added to mysqld command line to override settings from my.cnf --log-error=*) err_log="$val" ;; --port=*) mysql_tcp_port="$val" ;; --socket=*) mysql_unix_port="$val" ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --core-file-size=*) core_file_size="$val" ;; --ledir=*) ledir="$val" ;; --malloc-lib=*) set_malloc_lib "$val" ;; --mysqld=*) MYSQLD="$val" ;; --mysqld-version=*) if test -n "$val" then MYSQLD="mysqld-$val" PLUGIN_VARIANT="/$val" else MYSQLD="mysqld" fi ;; --nice=*) niceness="$val" ;; --open-files-limit=*) open_files="$val" ;; --open_files_limit=*) open_files="$val" ;; --skip-kill-mysqld*) KILL_MYSQLD=0 ;; --syslog) want_syslog=1 ;; --skip-syslog) want_syslog=0 ;; --syslog-tag=*) syslog_tag="$val" ;; --timezone=*) TZ="$val"; export TZ; ;; --wsrep[-_]urls=*) wsrep_urls="$val"; ;; --wsrep[-_]provider=*) if test -n "$val" && test "$val" != "none" then wsrep_restart=1 fi ;; --help) usage ;; *) if test -n "$pick_args" then append_arg_to_args "$arg" fi ;; esac done } # Add a single shared library to the list of libraries which will be added to # LD_PRELOAD for mysqld # # Since LD_PRELOAD is a space-separated value (for historical reasons), if a # shared lib's path contains spaces, that path will be prepended to # LD_LIBRARY_PATH and stripped from the lib value. add_mysqld_ld_preload() { lib_to_add="$1" log_notice "Adding '$lib_to_add' to LD_PRELOAD for mysqld" case "$lib_to_add" in *' '*) # Must strip path from lib, and add it to LD_LIBRARY_PATH lib_file=`basename "$lib_to_add"` case "$lib_file" in *' '*) # The lib file itself has a space in its name, and can't # be used in LD_PRELOAD log_error "library name '$lib_to_add' contains spaces and can not be used with LD_PRELOAD" exit 1 ;; esac lib_path=`dirname "$lib_to_add"` lib_to_add="$lib_file" [ -n "$mysqld_ld_library_path" ] && mysqld_ld_library_path="$mysqld_ld_library_path:" mysqld_ld_library_path="$mysqld_ld_library_path$lib_path" ;; esac # LD_PRELOAD is a space-separated [ -n "$mysqld_ld_preload" ] && mysqld_ld_preload="$mysqld_ld_preload " mysqld_ld_preload="${mysqld_ld_preload}$lib_to_add" } # Returns LD_PRELOAD (and LD_LIBRARY_PATH, if needed) text, quoted to be # suitable for use in the eval that calls mysqld. # # All values in mysqld_ld_preload are prepended to LD_PRELOAD. mysqld_ld_preload_text() { text= if [ -n "$mysqld_ld_preload" ]; then new_text="$mysqld_ld_preload" [ -n "$LD_PRELOAD" ] && new_text="$new_text $LD_PRELOAD" text="${text}LD_PRELOAD="`shell_quote_string "$new_text"`' ' fi if [ -n "$mysqld_ld_library_path" ]; then new_text="$mysqld_ld_library_path" [ -n "$LD_LIBRARY_PATH" ] && new_text="$new_text:$LD_LIBRARY_PATH" text="${text}LD_LIBRARY_PATH="`shell_quote_string "$new_text"`' ' fi echo "$text" } mysql_config= get_mysql_config() { if [ -z "$mysql_config" ]; then mysql_config=`echo "$0" | sed 's,/[^/][^/]*$,/mysql_config,'` if [ ! -x "$mysql_config" ]; then log_error "Can not run mysql_config $@ from '$mysql_config'" exit 1 fi fi "$mysql_config" "$@" } # set_malloc_lib LIB # - If LIB is empty, do nothing and return # - If LIB is 'tcmalloc', look for tcmalloc shared library in /usr/lib # then pkglibdir. tcmalloc is part of the Google perftools project. # - If LIB is an absolute path, assume it is a malloc shared library # # Put LIB in mysqld_ld_preload, which will be added to LD_PRELOAD when # running mysqld. See ld.so for details. set_malloc_lib() { malloc_lib="$1" if [ "$malloc_lib" = tcmalloc ]; then pkglibdir=`get_mysql_config --variable=pkglibdir` malloc_lib= # This list is kept intentionally simple. Simply set --malloc-lib # to a full path if another location is desired. for libdir in /usr/lib "$pkglibdir" "$pkglibdir/mysql"; do for flavor in _minimal '' _and_profiler _debug; do tmp="$libdir/libtcmalloc$flavor.so" #log_notice "DEBUG: Checking for malloc lib '$tmp'" [ -r "$tmp" ] || continue malloc_lib="$tmp" break 2 done done if [ -z "$malloc_lib" ]; then log_error "no shared library for --malloc-lib=tcmalloc found in /usr/lib or $pkglibdir" exit 1 fi fi # Allow --malloc-lib='' to override other settings [ -z "$malloc_lib" ] && return case "$malloc_lib" in /*) if [ ! -r "$malloc_lib" ]; then log_error "--malloc-lib '$malloc_lib' can not be read and will not be used" exit 1 fi ;; *) log_error "--malloc-lib must be an absolute path or 'tcmalloc'; " \ "ignoring value '$malloc_lib'" exit 1 ;; esac add_mysqld_ld_preload "$malloc_lib" } # # First, try to find BASEDIR and ledir (where mysqld is) # if echo '/usr/share/mysql' | grep '^/usr' > /dev/null then relpkgdata=`echo '/usr/share/mysql' | sed -e 's,^/usr,,' -e 's,^/,,' -e 's,^,./,'` else # pkgdatadir is not relative to prefix relpkgdata='/usr/share/mysql' fi MY_PWD=`pwd` # Check for the directories we would expect from a binary release install if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION" then # BASEDIR is already overridden on command line. Do not re-set. # Use BASEDIR to discover le. if test -x "$MY_BASEDIR_VERSION/libexec/mysqld" then ledir="$MY_BASEDIR_VERSION/libexec" elif test -x "$MY_BASEDIR_VERSION/sbin/mysqld" then ledir="$MY_BASEDIR_VERSION/sbin" else ledir="$MY_BASEDIR_VERSION/bin" fi elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/bin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where bin, share and data are ledir="$MY_PWD/bin" # Where mysqld is # Check for the directories we would expect from a source install elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/libexec/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where libexec, share and var are ledir="$MY_PWD/libexec" # Where mysqld is elif test -f "$relpkgdata"/english/errmsg.sys -a -x "$MY_PWD/sbin/mysqld" then MY_BASEDIR_VERSION="$MY_PWD" # Where sbin, share and var are ledir="$MY_PWD/sbin" # Where mysqld is # Since we didn't find anything, used the compiled-in defaults else MY_BASEDIR_VERSION='/usr' ledir='/usr/sbin' fi # # Second, try to find the data directory # # Try where the binary installs put it if test -d $MY_BASEDIR_VERSION/data/mysql then DATADIR=$MY_BASEDIR_VERSION/data if test -z "$defaults" -a -r "$DATADIR/my.cnf" then defaults="--defaults-extra-file=$DATADIR/my.cnf" fi # Next try where the source installs put it elif test -d $MY_BASEDIR_VERSION/var/mysql then DATADIR=$MY_BASEDIR_VERSION/var # Or just give up and use our compiled-in default else DATADIR=/var/lib/mysql fi # # Try to find the plugin directory # # Use user-supplied argument if [ -n "${PLUGIN_DIR}" ]; then plugin_dir="${PLUGIN_DIR}" else # Try to find plugin dir relative to basedir for dir in lib/mysql/plugin lib/plugin do if [ -d "${MY_BASEDIR_VERSION}/${dir}" ]; then plugin_dir="${MY_BASEDIR_VERSION}/${dir}" break fi done # Give up and use compiled-in default if [ -z "${plugin_dir}" ]; then plugin_dir='/usr/lib/mysql/plugin' fi fi plugin_dir="${plugin_dir}${PLUGIN_VARIANT}" if test -z "$MYSQL_HOME" then if test -r "$MY_BASEDIR_VERSION/my.cnf" && test -r "$DATADIR/my.cnf" then log_error "WARNING: Found two instances of my.cnf - $MY_BASEDIR_VERSION/my.cnf and $DATADIR/my.cnf IGNORING $DATADIR/my.cnf" MYSQL_HOME=$MY_BASEDIR_VERSION elif test -r "$DATADIR/my.cnf" then log_error "WARNING: Found $DATADIR/my.cnf The data directory is a deprecated location for my.cnf, please move it to $MY_BASEDIR_VERSION/my.cnf" MYSQL_HOME=$DATADIR else MYSQL_HOME=$MY_BASEDIR_VERSION fi fi export MYSQL_HOME # Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] # and then merge with the command line arguments if test -x "$MY_BASEDIR_VERSION/bin/my_print_defaults" then print_defaults="$MY_BASEDIR_VERSION/bin/my_print_defaults" elif test -x `dirname $0`/my_print_defaults then print_defaults="`dirname $0`/my_print_defaults" elif test -x ./bin/my_print_defaults then print_defaults="./bin/my_print_defaults" elif test -x /usr/bin/my_print_defaults then print_defaults="/usr/bin/my_print_defaults" elif test -x /usr/bin/mysql_print_defaults then print_defaults="/usr/bin/mysql_print_defaults" else print_defaults="my_print_defaults" fi append_arg_to_args () { args="$args "`shell_quote_string "$1"` } args= SET_USER=2 parse_arguments `$print_defaults $defaults --loose-verbose mysqld server` if test $SET_USER -eq 2 then SET_USER=0 fi parse_arguments `$print_defaults $defaults --loose-verbose mysqld_safe safe_mysqld` parse_arguments PICK-ARGS-FROM-ARGV "$@" # Determine what logging facility to use # Ensure that 'logger' exists, if it's requested if [ $want_syslog -eq 1 ] then my_which logger > /dev/null 2>&1 if [ $? -ne 0 ] then log_error "--syslog requested, but no 'logger' program found. Please ensure that 'logger' is in your PATH, or do not specify the --syslog option to mysqld_safe." exit 1 fi fi if [ -n "$err_log" -o $want_syslog -eq 0 ] then if [ -n "$err_log" ] then # mysqld adds ".err" if there is no extension on the --log-error # argument; must match that here, or mysqld_safe will write to a # different log file than mysqld # mysqld does not add ".err" to "--log-error=foo."; it considers a # trailing "." as an extension if expr "$err_log" : '.*\.[^/]*$' > /dev/null then : else err_log="$err_log".err fi case "$err_log" in /* ) ;; * ) err_log="$DATADIR/$err_log" ;; esac else err_log=$DATADIR/`hostname`.err fi append_arg_to_args "--log-error=$err_log" if [ $want_syslog -eq 1 ] then # User explicitly asked for syslog, so warn that it isn't used log_error "Can't log to error log and syslog at the same time. Remove all --log-error configuration options for --syslog to take effect." fi # Log to err_log file log_notice "Logging to '$err_log'." logging=file else if [ -n "$syslog_tag" ] then # Sanitize the syslog tag syslog_tag=`echo "$syslog_tag" | sed -e 's/[^a-zA-Z0-9_-]/_/g'` syslog_tag_mysqld_safe="${syslog_tag_mysqld_safe}-$syslog_tag" syslog_tag_mysqld="${syslog_tag_mysqld}-$syslog_tag" fi log_notice "Logging to syslog." logging=syslog fi USER_OPTION="" if test -w / -o "$USER" = "root" then if test "$user" != "root" -o $SET_USER = 1 then USER_OPTION="--user=$user" fi # Change the err log to the right user, if it is in use if [ $want_syslog -eq 0 ]; then touch "$err_log" chown $user "$err_log" fi if test -n "$open_files" then ulimit -n $open_files fi fi if test -n "$open_files" then append_arg_to_args "--open-files-limit=$open_files" fi safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-/var/run/mysqld/mysqld.sock}} # Make sure that directory for $safe_mysql_unix_port exists mysql_unix_port_dir=`dirname $safe_mysql_unix_port` if [ ! -d $mysql_unix_port_dir ] then mkdir $mysql_unix_port_dir chown $user $mysql_unix_port_dir chmod 755 $mysql_unix_port_dir fi # If the user doesn't specify a binary, we assume name "mysqld" if test -z "$MYSQLD" then MYSQLD=mysqld fi if test ! -x "$ledir/$MYSQLD" then log_error "The file $ledir/$MYSQLD does not exist or is not executable. Please cd to the mysql installation directory and restart this script from there as follows: ./bin/mysqld_safe& See http://dev.mysql.com/doc/mysql/en/mysqld-safe.html for more information" exit 1 fi if test -z "$pid_file" then pid_file="$DATADIR/`hostname`.pid" else case "$pid_file" in /* ) ;; * ) pid_file="$DATADIR/$pid_file" ;; esac fi append_arg_to_args "--pid-file=$pid_file" if test -n "$mysql_unix_port" then append_arg_to_args "--socket=$mysql_unix_port" fi if test -n "$mysql_tcp_port" then append_arg_to_args "--port=$mysql_tcp_port" fi if test $niceness -eq 0 then NOHUP_NICENESS="nohup" else NOHUP_NICENESS="nohup nice -$niceness" fi # Using nice with no args to get the niceness level is GNU-specific. # This check could be extended for other operating systems (e.g., # BSD could use "nohup sh -c 'ps -o nice -p $$' | tail -1"). # But, it also seems that GNU nohup is the only one which messes # with the priority, so this is okay. if nohup nice > /dev/null 2>&1 then normal_niceness=`nice` nohup_niceness=`nohup nice 2>/dev/null` numeric_nice_values=1 for val in $normal_niceness $nohup_niceness do case "$val" in -[0-9] | -[0-9][0-9] | -[0-9][0-9][0-9] | \ [0-9] | [0-9][0-9] | [0-9][0-9][0-9] ) ;; * ) numeric_nice_values=0 ;; esac done if test $numeric_nice_values -eq 1 then nice_value_diff=`expr $nohup_niceness - $normal_niceness` if test $? -eq 0 && test $nice_value_diff -gt 0 && \ nice --$nice_value_diff echo testing > /dev/null 2>&1 then # nohup increases the priority (bad), and we are permitted # to lower the priority with respect to the value the user # might have been given niceness=`expr $niceness - $nice_value_diff` NOHUP_NICENESS="nice -$niceness nohup" fi fi else if nohup echo testing > /dev/null 2>&1 then : else # nohup doesn't work on this system NOHUP_NICENESS="" fi fi # Try to set the core file size (even if we aren't root) because many systems # don't specify a hard limit on core file size. if test -n "$core_file_size" then ulimit -c $core_file_size fi # # If there exists an old pid file, check if the daemon is already running # Note: The switches to 'ps' may depend on your operating system if test -f "$pid_file" then PID=`cat "$pid_file"` if kill -0 $PID > /dev/null 2> /dev/null then if ps wwwp $PID | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null then # The pid contains a mysqld process log_error "A mysqld process already exists" exit 1 fi fi rm -f "$pid_file" if test -f "$pid_file" then log_error "Fatal error: Can't remove the pid file: $pid_file Please remove it manually and start $0 again; mysqld daemon not started" exit 1 fi fi # # From now on, we catch signals to do a proper shutdown of mysqld # when signalled to do so. # trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh & wait' 1 # HUP trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM # # Uncomment the following lines if you want all tables to be automatically # checked and repaired during startup. You should add sensible key_buffer # and sort_buffer values to my.cnf to improve check performance or require # less disk space. # Alternatively, you can start mysqld with the "myisam-recover" option. See # the manual for details. # # echo "Checking tables in $DATADIR" # $MY_BASEDIR_VERSION/bin/myisamchk --silent --force --fast --medium-check $DATADIR/*/*.MYI # $MY_BASEDIR_VERSION/bin/isamchk --silent --force $DATADIR/*/*.ISM # Does this work on all systems? #if type ulimit | grep "shell builtin" > /dev/null #then # ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems #fi cmd="`mysqld_ld_preload_text`$NOHUP_NICENESS" for i in "$ledir/$MYSQLD" "$defaults" "--basedir=$MY_BASEDIR_VERSION" \ "--datadir=$DATADIR" "--plugin-dir=$plugin_dir" "$USER_OPTION" do cmd="$cmd "`shell_quote_string "$i"` done cmd="$cmd $args" # Avoid 'nohup: ignoring input' warning nohup_redir="" test -n "$NOHUP_NICENESS" && nohup_redir=" < /dev/null" log_notice "Starting $MYSQLD daemon with databases from $DATADIR" # variable to track the current number of "fast" (a.k.a. subsecond) restarts fast_restart=0 # maximum number of restarts before trottling kicks in max_fast_restarts=5 # flag whether a usable sleep command exists have_sleep=1 # maximum number of wsrep restarts max_wsrep_restarts=0 while true do rm -f $safe_mysql_unix_port "$pid_file" # Some extra safety start_time=`date +%M%S` # this sets wsrep_start_position_opt wsrep_recover_position "$cmd" [ $? -ne 0 ] && exit 1 # [ -n "$wsrep_urls" ] && url=`wsrep_pick_url $wsrep_urls` # check connect address if [ -z "$url" ] then eval_log_error "$cmd $wsrep_start_position_opt $nohup_redir" else eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir" fi end_time=`date +%M%S` if test ! -f "$pid_file" # This is removed if normal shutdown then break fi # sanity check if time reading is sane and there's sleep if test $end_time -gt 0 -a $have_sleep -gt 0 then # throttle down the fast restarts if test $end_time -eq $start_time then fast_restart=`expr $fast_restart + 1` if test $fast_restart -ge $max_fast_restarts then log_notice "The server is respawning too fast. Sleeping for 1 second." sleep 1 sleep_state=$? if test $sleep_state -gt 0 then log_notice "The server is respawning too fast and no working sleep command. Turning off trottling." have_sleep=0 fi fast_restart=0 fi else fast_restart=0 fi fi if true && test $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) # but should work for the rest of the servers. # The only thing is ps x => redhat 5 gives warnings when using ps -x. # kill -9 is used or the process won't react on the kill. numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` log_notice "Number of processes running now: $numofproces" I=1 while test "$I" -le "$numofproces" do PROC=`ps xaww | grep "$ledir/$MYSQLD\>" | grep -v "grep" | grep "pid-file=$pid_file" | sed -n '$p'` for T in $PROC do break done # echo "TEST $I - $T **" if kill -9 $T then log_error "$MYSQLD process hanging, pid $T - killed" else break fi I=`expr $I + 1` done fi if [ -n "$wsrep_restart" ] then if [ $wsrep_restart -le $max_wsrep_restarts ] then wsrep_restart=`expr $wsrep_restart + 1` log_notice "WSREP: sleeping 15 seconds before restart" sleep 15 else log_notice "WSREP: not restarting wsrep node automatically" break fi fi log_notice "mysqld restarted" done log_notice "mysqld from pid file $pid_file ended" percona-galera-3-3.8-3390/scripts/mysql/freebsd.sh000077500000000000000000000054631244131713600216170ustar00rootroot00000000000000#!/bin/bash -eu if [ $# -ne 2 ] then echo "Usage: $0 " exit 1 fi MYSQL_VER=$1 RELEASE=$2 MAJORMINOR=$(echo $MYSQL_VER | awk -F . '{print $1$2}') # Absolute path of this script folder SCRIPT_ROOT=$(cd $(dirname $0); pwd -P) PBR="$SCRIPT_ROOT/dist/mysql/usr/local" install -d "$PBR"/{etc/rc.d,libdata/ldconfig} install -m 555 "$SCRIPT_ROOT/freebsd/mysql-server.sh" "$PBR/etc/rc.d/mysql-server" install -m 444 "$SCRIPT_ROOT/freebsd/client-ldconfig" "$PBR/libdata/ldconfig/mysql${MAJORMINOR}-client" shopt -s nullglob for i in {1..9}; do for f in "$PBR/man/man$i/"*.$i; do gzip -c $f > $f.gz done done shopt -u nullglob install -m 644 "$SCRIPT_ROOT/freebsd/server-"{plist,descr,comment,message} "$PBR" sed -e "s!%{SRCDIR}!$PBR!" -e "s!%{RELEASE}!$RELEASE!" -e "s!%{MYSQL_VER}!$MYSQL_VER!" \ -e "s!%{MAJORMINOR}!$MAJORMINOR!" -i "" "$PBR/server-"{plist,descr,comment,message} \ "$PBR/share/licenses/mysql-client-${MYSQL_VER}_wsrep_${RELEASE}/catalog.mk" for pkg in $(grep '^@comment DEPORIGIN:' "$PBR/server-plist" | cut -d : -f 2); do if [[ "$pkg" != *_wsrep* ]]; then pkgdep=$(/usr/sbin/pkg_info -q -O "$pkg") if [ -z "$pkgdep" ]; then echo "ERROR: failed to find dependency package '$pkg'" >&2 exit 1 fi sed -e "s!^@comment DEPORIGIN:$pkg!@pkgdep $pkgdep"$'\\\n&!' -i "" "$PBR/server-plist" fi done /usr/sbin/pkg_create -c "$PBR/server-comment" \ -d "$PBR/server-descr" \ -D "$PBR/server-message" \ -f "$PBR/server-plist" \ -m "$SCRIPT_ROOT/freebsd/server-mtree" \ -v "mysql-server-${MYSQL_VER}_wsrep_${RELEASE}-$(uname -m).tbz" install -m 644 "$SCRIPT_ROOT/freebsd/client-"{plist,descr,comment,message} "$PBR/" sed -e "s!%{SRCDIR}!$PBR!" -e "s!%{RELEASE}!$RELEASE!" -e "s!%{MYSQL_VER}!$MYSQL_VER!" \ -e "s!%{MAJORMINOR}!$MAJORMINOR!" -i "" "$PBR/client-"{plist,descr,comment,message} \ "$PBR/share/licenses/mysql-client-${MYSQL_VER}_wsrep_${RELEASE}/catalog.mk" for pkg in $(grep '^@comment DEPORIGIN:' "$PBR/client-plist" | cut -d : -f 2); do if [[ "$pkg" != *_wsrep* ]]; then pkgdep=$(/usr/sbin/pkg_info -q -O "$pkg") if [ -z "$pkgdep" ]; then echo "ERROR: failed to find dependency package '$pkg'" >&2 exit 1 fi sed -e "s!^@comment DEPORIGIN:$pkg!@pkgdep $pkgdep"$'\\\n&!' -i "" "$PBR/client-plist" fi done /usr/sbin/pkg_create -c "$PBR/client-comment" \ -d "$PBR/client-descr" \ -D "$PBR/client-message" \ -f "$PBR/client-plist" \ -m "$SCRIPT_ROOT/freebsd/client-mtree" \ -v "mysql-client-${MYSQL_VER}_wsrep_${RELEASE}-$(uname -m).tbz" exit 0 percona-galera-3-3.8-3390/scripts/mysql/freebsd/000077500000000000000000000000001244131713600212505ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/freebsd/LICENSE000066400000000000000000000001211244131713600222470ustar00rootroot00000000000000This package has a single license: GPLv3 (GNU General Public License version 3). percona-galera-3-3.8-3390/scripts/mysql/freebsd/catalog.mk000066400000000000000000000003721244131713600232150ustar00rootroot00000000000000_LICENSE=GPLv3 _LICENSE_NAME=GNU General Public License version 3 _LICENSE_PERMS=dist-mirror dist-sell pkg-mirror pkg-sell auto-accept _LICENSE_GROUPS=FSF GPL OSI _LICENSE_DISTFILES=mysql-%{MYSQL_VER}.tar.gz mysql-${MYSQL_VER}_wsrep_${RELEASE}.patch percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-comment000066400000000000000000000000621244131713600241070ustar00rootroot00000000000000wsrep-enabled multithreaded SQL database (client) percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-descr000066400000000000000000000003151244131713600235460ustar00rootroot00000000000000MySQL is a very fast, multi-threaded, multi-user and robust SQL (Structured Query Language) database server. WWW: http://www.mysql.com/ Built with wsrep patch %{RELEASE}. WWW: http://www.codership.com/ percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-ldconfig000066400000000000000000000000251244131713600242310ustar00rootroot00000000000000/usr/local/lib/mysql percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-message000066400000000000000000000000001244131713600240610ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-mtree000066400000000000000000000422301244131713600235640ustar00rootroot00000000000000# $FreeBSD: /tmp/pcvs/ports/Templates/BSD.local.dist,v 1.3 2010-11-12 20:57:14 pav Exp $ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin .. etc devd .. man.d .. pam.d .. rc.d .. .. include X11 .. .. info .. lib X11 app-defaults .. fonts local .. .. .. .. libdata ldconfig .. ldconfig32 .. pkgconfig .. .. libexec .. man /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. de.ISO8859-1 uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. en.ISO8859-1 /set uname=man cat1 .. cat1aout .. cat2 .. cat3 .. cat4 i386 .. .. cat5 .. cat6 .. cat7 .. cat8 i386 .. .. cat9 i386 .. .. catn .. .. ja uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. ru.KOI8-R /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. .. sbin .. share aclocal .. dict .. doc ja .. .. emacs site-lisp .. .. examples .. java classes .. .. locale af LC_MESSAGES .. .. am LC_MESSAGES .. .. ar LC_MESSAGES .. .. az LC_MESSAGES .. .. be LC_MESSAGES .. .. bg LC_MESSAGES .. .. bn LC_MESSAGES .. .. br LC_MESSAGES .. .. bs LC_MESSAGES .. .. ca LC_MESSAGES .. .. cs LC_MESSAGES .. .. cy LC_MESSAGES .. .. da LC_MESSAGES .. .. de LC_MESSAGES .. .. de_AT LC_MESSAGES .. .. dk LC_MESSAGES .. .. ee LC_MESSAGES .. .. el LC_MESSAGES .. .. en LC_MESSAGES .. .. en_AU LC_MESSAGES .. .. en_CA LC_MESSAGES .. .. en_GB LC_MESSAGES .. .. eo LC_MESSAGES .. .. es LC_MESSAGES .. .. es_ES LC_MESSAGES .. .. es_MX LC_MESSAGES .. .. et LC_MESSAGES .. .. eu LC_MESSAGES .. .. fa LC_MESSAGES .. .. fa_IR LC_MESSAGES .. .. fi LC_MESSAGES .. .. fr LC_MESSAGES .. .. fr_FR LC_MESSAGES .. .. ga LC_MESSAGES .. .. gl LC_MESSAGES .. .. gu LC_MESSAGES .. .. he LC_MESSAGES .. .. hi LC_MESSAGES .. .. hr LC_MESSAGES .. .. hu LC_MESSAGES .. .. id LC_MESSAGES .. .. is LC_MESSAGES .. .. it LC_MESSAGES .. .. ja LC_MESSAGES .. .. ka LC_MESSAGES .. .. kn LC_MESSAGES .. .. ko LC_MESSAGES .. .. li LC_MESSAGES .. .. lt LC_MESSAGES .. .. lv LC_MESSAGES .. .. mk LC_MESSAGES .. .. ml LC_MESSAGES .. .. mn LC_MESSAGES .. .. ms LC_MESSAGES .. .. mt LC_MESSAGES .. .. nb LC_MESSAGES .. .. ne LC_MESSAGES .. .. nl LC_MESSAGES .. .. nn LC_MESSAGES .. .. no LC_MESSAGES .. .. or LC_MESSAGES .. .. pa LC_MESSAGES .. .. pl LC_MESSAGES .. .. pt LC_MESSAGES .. .. pt_BR LC_MESSAGES .. .. pt_PT LC_MESSAGES .. .. ro LC_MESSAGES .. .. ru LC_MESSAGES .. .. sk LC_MESSAGES .. .. sl LC_MESSAGES .. .. sq LC_MESSAGES .. .. sr LC_MESSAGES .. .. sr@Latn LC_MESSAGES .. .. sv LC_MESSAGES .. .. ta LC_MESSAGES .. .. tg LC_MESSAGES .. .. th LC_MESSAGES .. .. tk LC_MESSAGES .. .. tr LC_MESSAGES .. .. uk LC_MESSAGES .. .. uz LC_MESSAGES .. .. vi LC_MESSAGES .. .. wa LC_MESSAGES .. .. zh LC_MESSAGES .. .. zh_CN LC_MESSAGES .. .. zh_CN.GB2312 LC_MESSAGES .. .. zh_TW LC_MESSAGES .. .. zh_TW.Big5 LC_MESSAGES .. .. .. misc .. nls C .. af_ZA.ISO8859-1 .. af_ZA.ISO8859-15 .. af_ZA.UTF-8 .. am_ET.UTF-8 .. be_BY.CP1131 .. be_BY.CP1251 .. be_BY.ISO8859-5 .. be_BY.UTF-8 .. bg_BG.CP1251 .. bg_BG.UTF-8 .. ca_ES.ISO8859-1 .. ca_ES.ISO8859-15 .. ca_ES.UTF-8 .. cs_CZ.ISO8859-2 .. cs_CZ.UTF-8 .. da_DK.ISO8859-1 .. da_DK.ISO8859-15 .. da_DK.UTF-8 .. de_AT.ISO8859-1 .. de_AT.ISO8859-15 .. de_AT.UTF-8 .. de_CH.ISO8859-1 .. de_CH.ISO8859-15 .. de_CH.UTF-8 .. de_DE.ISO8859-1 .. de_DE.ISO8859-15 .. de_DE.UTF-8 .. el_GR.ISO8859-7 .. el_GR.UTF-8 .. en_AU.ISO8859-1 .. en_AU.ISO8859-15 .. en_AU.US-ASCII .. en_AU.UTF-8 .. en_CA.ISO8859-1 .. en_CA.ISO8859-15 .. en_CA.US-ASCII .. en_CA.UTF-8 .. en_GB.ISO8859-1 .. en_GB.ISO8859-15 .. en_GB.US-ASCII .. en_GB.UTF-8 .. en_IE.UTF-8 .. en_NZ.ISO8859-1 .. en_NZ.ISO8859-15 .. en_NZ.US-ASCII .. en_NZ.UTF-8 .. en_US.ISO8859-1 .. en_US.ISO8859-15 .. en_US.UTF-8 .. es_ES.ISO8859-1 .. es_ES.ISO8859-15 .. es_ES.UTF-8 .. et_EE.ISO8859-15 .. et_EE.UTF-8 .. fi_FI.ISO8859-1 .. fi_FI.ISO8859-15 .. fi_FI.UTF-8 .. fr_BE.ISO8859-1 .. fr_BE.ISO8859-15 .. fr_BE.UTF-8 .. fr_CA.ISO8859-1 .. fr_CA.ISO8859-15 .. fr_CA.UTF-8 .. fr_CH.ISO8859-1 .. fr_CH.ISO8859-15 .. fr_CH.UTF-8 .. fr_FR.ISO8859-1 .. fr_FR.ISO8859-15 .. fr_FR.UTF-8 .. he_IL.UTF-8 .. hi_IN.ISCII-DEV .. hr_HR.ISO8859-2 .. hr_HR.UTF-8 .. hu_HU.ISO8859-2 .. hu_HU.UTF-8 .. hy_AM.ARMSCII-8 .. hy_AM.UTF-8 .. is_IS.ISO8859-1 .. is_IS.ISO8859-15 .. is_IS.UTF-8 .. it_CH.ISO8859-1 .. it_CH.ISO8859-15 .. it_CH.UTF-8 .. it_IT.ISO8859-1 .. it_IT.ISO8859-15 .. it_IT.UTF-8 .. ja_JP.SJIS .. ja_JP.UTF-8 .. ja_JP.eucJP .. kk_KZ.PT154 .. kk_KZ.UTF-8 .. ko_KR.CP949 .. ko_KR.UTF-8 .. ko_KR.eucKR .. la_LN.ISO8859-1 .. la_LN.ISO8859-15 .. la_LN.ISO8859-2 .. la_LN.ISO8859-4 .. la_LN.US-ASCII .. lt_LT.ISO8859-13 .. lt_LT.ISO8859-4 .. lt_LT.UTF-8 .. nl_BE.ISO8859-1 .. nl_BE.ISO8859-15 .. nl_BE.UTF-8 .. nl_NL.ISO8859-1 .. nl_NL.ISO8859-15 .. nl_NL.UTF-8 .. no_NO.ISO8859-1 .. no_NO.ISO8859-15 .. no_NO.UTF-8 .. pl_PL.ISO8859-2 .. pl_PL.UTF-8 .. pt_BR.ISO8859-1 .. pt_BR.UTF-8 .. pt_PT.ISO8859-1 .. pt_PT.ISO8859-15 .. pt_PT.UTF-8 .. ro_RO.ISO8859-2 .. ro_RO.UTF-8 .. ru_RU.CP1251 .. ru_RU.CP866 .. ru_RU.ISO8859-5 .. ru_RU.KOI8-R .. ru_RU.UTF-8 .. sk_SK.ISO8859-2 .. sk_SK.UTF-8 .. sl_SI.ISO8859-2 .. sl_SI.UTF-8 .. sr_YU.ISO8859-2 .. sr_YU.ISO8859-5 .. sr_YU.UTF-8 .. sv_SE.ISO8859-1 .. sv_SE.ISO8859-15 .. sv_SE.UTF-8 .. tr_TR.ISO8859-9 .. tr_TR.UTF-8 .. uk_UA.ISO8859-5 .. uk_UA.KOI8-U .. uk_UA.UTF-8 .. zh_CN.GB18030 .. zh_CN.GB2312 .. zh_CN.GBK .. zh_CN.UTF-8 .. zh_CN.eucCN .. zh_HK.Big5HKSCS .. zh_HK.UTF-8 .. zh_TW.Big5 .. zh_TW.UTF-8 .. .. pixmaps .. sgml .. skel .. xml .. .. www .. .. percona-galera-3-3.8-3390/scripts/mysql/freebsd/client-plist000066400000000000000000000110701244131713600236010ustar00rootroot00000000000000@comment PKG_FORMAT_REVISION:1.1 @name mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE} @comment ORIGIN:databases/mysql%{MAJORMINOR}-client_wsrep @cwd /usr/local @srcdir %{SRCDIR} @comment "=== dependencies ===" @comment "require /usr/local/lib/gcc48/libstdc++.so" @comment // @pkgdep gcc-4.8.2.s20130808 @comment DEPORIGIN:lang/gcc48 @comment // @pkgdep openssl-1.0.1_8 @comment DEPORIGIN:security/openssl @comment // @pkgdep libexecinfo-1.1_3 @comment DEPORIGIN:devel/libexecinfo @conflicts mysql-client-[34].* @conflicts mysql-client-5.[0-57-9].* @conflicts mariadb-client-5.* @conflicts percona-client-5.* @comment "=== preinstall stage ===" @exec echo "===> Linking /usr/local/bin/bash to /bin/bash" @exec [ -x /bin/bash ] && echo "Using existing /bin/bash." || ln -s ../usr/local/bin/bash /bin/bash @comment "=== file section ===" @owner root @group wheel @mode 0444 share/licenses/mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE}/catalog.mk share/licenses/mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE}/LICENSE share/licenses/mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE}/GPLv3 man/man1/comp_err.1.gz man/man1/msql2mysql.1.gz man/man1/mysql.1.gz man/man1/mysql_config.1.gz man/man1/mysql_config_editor.1.gz man/man1/mysql_find_rows.1.gz man/man1/mysql_waitpid.1.gz man/man1/mysqlaccess.1.gz man/man1/mysqladmin.1.gz man/man1/mysqlbinlog.1.gz man/man1/mysqlcheck.1.gz man/man1/mysqldump.1.gz man/man1/mysqlimport.1.gz man/man1/mysqlshow.1.gz man/man1/mysqlslap.1.gz @mode 0555 bin/msql2mysql bin/mysql bin/mysql_config bin/mysql_config_editor bin/mysql_find_rows bin/mysql_waitpid bin/mysqlaccess bin/mysqlaccess.conf bin/mysqladmin bin/mysqlbinlog bin/mysqlcheck bin/mysqldump bin/mysqlimport bin/mysqlshow bin/mysqlslap @mode 0444 include/mysql/big_endian.h include/mysql/byte_order_generic.h include/mysql/byte_order_generic_x86.h include/mysql/byte_order_generic_x86_64.h include/mysql/decimal.h include/mysql/errmsg.h include/mysql/keycache.h include/mysql/little_endian.h include/mysql/m_ctype.h include/mysql/m_string.h include/mysql/my_alloc.h include/mysql/my_attribute.h include/mysql/my_byteorder.h include/mysql/my_compiler.h include/mysql/my_config.h include/mysql/my_dbug.h include/mysql/my_dir.h include/mysql/my_getopt.h include/mysql/my_global.h include/mysql/my_list.h include/mysql/my_net.h include/mysql/my_pthread.h include/mysql/my_sys.h include/mysql/my_xml.h include/mysql/mysql.h include/mysql/mysql/client_authentication.h include/mysql/mysql/client_plugin.h include/mysql/mysql/client_plugin.h.pp include/mysql/mysql/get_password.h include/mysql/mysql/innodb_priv.h include/mysql/mysql/plugin.h include/mysql/mysql/plugin_audit.h include/mysql/mysql/plugin_audit.h.pp include/mysql/mysql/plugin_auth.h include/mysql/mysql/plugin_auth.h.pp include/mysql/mysql/plugin_auth_common.h include/mysql/mysql/plugin_ftparser.h include/mysql/mysql/plugin_ftparser.h.pp include/mysql/mysql/plugin_validate_password.h include/mysql/mysql/psi/mysql_file.h include/mysql/mysql/psi/mysql_idle.h include/mysql/mysql/psi/mysql_socket.h include/mysql/mysql/psi/mysql_stage.h include/mysql/mysql/psi/mysql_statement.h include/mysql/mysql/psi/mysql_table.h include/mysql/mysql/psi/mysql_thread.h include/mysql/mysql/psi/psi.h include/mysql/mysql/service_my_plugin_log.h include/mysql/mysql/service_my_snprintf.h include/mysql/mysql/service_mysql_string.h include/mysql/mysql/service_thd_alloc.h include/mysql/mysql/service_thd_wait.h include/mysql/mysql/service_thread_scheduler.h include/mysql/mysql/services.h include/mysql/mysql/thread_pool_priv.h include/mysql/mysql_com.h include/mysql/mysql_com_server.h include/mysql/mysql_embed.h include/mysql/mysql_time.h include/mysql/mysql_version.h include/mysql/mysqld_ername.h include/mysql/mysqld_error.h include/mysql/plugin.h include/mysql/plugin_audit.h include/mysql/plugin_ftparser.h include/mysql/plugin_validate_password.h include/mysql/sql_common.h include/mysql/sql_state.h include/mysql/sslopt-case.h include/mysql/sslopt-longopts.h include/mysql/sslopt-vars.h include/mysql/typelib.h lib/mysql/libmysqlclient.a lib/mysql/libmysqlclient.so lib/mysql/libmysqlclient.so.18 lib/mysql/libmysqlclient_r.a lib/mysql/libmysqlclient_r.so lib/mysql/libmysqlclient_r.so.18 lib/mysql/libmysqlservices.a share/aclocal/mysql.m4 libdata/ldconfig/mysql%{MAJORMINOR}-client @comment "=== postinstall stage ===" @exec /sbin/ldconfig -m /usr/local/lib/mysql @comment "=== postremove stage ===" @dirrm share/licenses/mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE} @dirrm include/mysql/mysql/psi @dirrm include/mysql/mysql @dirrm include/mysql @unexec rmdir "%D/lib/mysql" 2>/dev/null || true @unexec service ldconfig start >/dev/null percona-galera-3-3.8-3390/scripts/mysql/freebsd/mysql-server.sh000077500000000000000000000052131244131713600242610ustar00rootroot00000000000000#!/bin/sh # # $FreeBSD: tags/RELEASE_9_1_0/databases/mysql55-server/files/mysql-server.in 302141 2012-08-05 23:19:36Z dougb $ # # PROVIDE: mysql # REQUIRE: LOGIN # KEYWORD: shutdown # # Add the following line to /etc/rc.conf to enable mysql: # mysql_enable (bool): Set to "NO" by default. # Set it to "YES" to enable MySQL. # mysql_limits (bool): Set to "NO" by default. # Set it to yes to run `limits -e -U mysql` # just before mysql starts. # mysql_dbdir (str): Default to "/var/db/mysql" # Base database directory. # mysql_pidfile (str): Custum PID file path and name. # Default to "${mysql_dbdir}/${hostname}.pid". # mysql_args (str): Custom additional arguments to be passed # to mysqld_safe (default empty). # . /etc/rc.subr name="mysql" rcvar=mysql_enable load_rc_config $name : ${mysql_enable="NO"} : ${mysql_limits="NO"} : ${mysql_dbdir="/var/db/mysql"} mysql_user="mysql" mysql_limits_args="-e -U ${mysql_user}" pidfile=${mysql_pidfile:-"${mysql_dbdir}/`/bin/hostname`.pid"} command="/usr/sbin/daemon" command_args="-c -f /usr/local/bin/mysqld_safe --defaults-extra-file=${mysql_dbdir}/my.cnf --user=${mysql_user} --datadir=${mysql_dbdir} --pid-file=${pidfile} ${mysql_args}" procname="/usr/local/libexec/mysqld" start_precmd="${name}_prestart" start_postcmd="${name}_poststart" mysql_install_db="/usr/local/bin/mysql_install_db" mysql_install_db_args="--basedir=/usr/local --datadir=${mysql_dbdir} --force" service_startup_timeout=900 startup_sleep=1 sst_progress_file=${mysql_dbdir}/sst_in_progress extra_commands="bootstrap" bootstrap_cmd="mysql_bootstrap" for gcc in gcc44 gcc48 do gcc_dir=/usr/local/lib/${gcc} [ -d "${gcc_dir}" ] && export LD_LIBRARY_PATH="${gcc_dir}:$LD_LIBRARY_PATH" done mysql_bootstrap() { # Bootstrap the cluster, start the first node that initiate the cluster check_startmsgs && echo "Bootstrapping cluster" shift $0 start $rc_extra_args --wsrep-new-cluster } mysql_create_auth_tables() { eval $mysql_install_db $mysql_install_db_args >/dev/null 2>/dev/null [ $? -eq 0 ] && chown -R ${mysql_user}:${mysql_user} ${mysql_dbdir} } mysql_prestart() { if [ ! -d "${mysql_dbdir}/mysql/." ]; then mysql_create_auth_tables || return 1 fi if checkyesno mysql_limits; then eval `/usr/bin/limits ${mysql_limits_args}` 2>/dev/null else return 0 fi } mysql_poststart() { local timeout=${service_startup_timeout} while [ ! -f "${pidfile}" -a ${timeout} -gt 0 ]; do if test -e $sst_progress_file && [ $startup_sleep -ne 100 ]; then check_startmsgs && echo "SST in progress, setting sleep higher" startup_sleep=100 fi timeout=$(( timeout - 1 )) sleep $startup_sleep done return 0 } run_rc_command "$1" percona-galera-3-3.8-3390/scripts/mysql/freebsd/server-comment000066400000000000000000000000621244131713600241370ustar00rootroot00000000000000wsrep-enabled multithreaded SQL database (server) percona-galera-3-3.8-3390/scripts/mysql/freebsd/server-descr000066400000000000000000000003151244131713600235760ustar00rootroot00000000000000MySQL is a very fast, multi-threaded, multi-user and robust SQL (Structured Query Language) database server. WWW: http://www.mysql.com/ Built with wsrep patch %{RELEASE}. WWW: http://www.codership.com/ percona-galera-3-3.8-3390/scripts/mysql/freebsd/server-message000066400000000000000000000004061244131713600241230ustar00rootroot00000000000000************************************************************************ Remember to run mysql_upgrade the first time you start the MySQL server after an upgrade from an earlier version. ************************************************************************ percona-galera-3-3.8-3390/scripts/mysql/freebsd/server-mtree000066400000000000000000000422301244131713600236140ustar00rootroot00000000000000# $FreeBSD: /tmp/pcvs/ports/Templates/BSD.local.dist,v 1.3 2010-11-12 20:57:14 pav Exp $ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin .. etc devd .. man.d .. pam.d .. rc.d .. .. include X11 .. .. info .. lib X11 app-defaults .. fonts local .. .. .. .. libdata ldconfig .. ldconfig32 .. pkgconfig .. .. libexec .. man /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. de.ISO8859-1 uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. en.ISO8859-1 /set uname=man cat1 .. cat1aout .. cat2 .. cat3 .. cat4 i386 .. .. cat5 .. cat6 .. cat7 .. cat8 i386 .. .. cat9 i386 .. .. catn .. .. ja uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. ru.KOI8-R /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. .. sbin .. share aclocal .. dict .. doc ja .. .. emacs site-lisp .. .. examples .. java classes .. .. locale af LC_MESSAGES .. .. am LC_MESSAGES .. .. ar LC_MESSAGES .. .. az LC_MESSAGES .. .. be LC_MESSAGES .. .. bg LC_MESSAGES .. .. bn LC_MESSAGES .. .. br LC_MESSAGES .. .. bs LC_MESSAGES .. .. ca LC_MESSAGES .. .. cs LC_MESSAGES .. .. cy LC_MESSAGES .. .. da LC_MESSAGES .. .. de LC_MESSAGES .. .. de_AT LC_MESSAGES .. .. dk LC_MESSAGES .. .. ee LC_MESSAGES .. .. el LC_MESSAGES .. .. en LC_MESSAGES .. .. en_AU LC_MESSAGES .. .. en_CA LC_MESSAGES .. .. en_GB LC_MESSAGES .. .. eo LC_MESSAGES .. .. es LC_MESSAGES .. .. es_ES LC_MESSAGES .. .. es_MX LC_MESSAGES .. .. et LC_MESSAGES .. .. eu LC_MESSAGES .. .. fa LC_MESSAGES .. .. fa_IR LC_MESSAGES .. .. fi LC_MESSAGES .. .. fr LC_MESSAGES .. .. fr_FR LC_MESSAGES .. .. ga LC_MESSAGES .. .. gl LC_MESSAGES .. .. gu LC_MESSAGES .. .. he LC_MESSAGES .. .. hi LC_MESSAGES .. .. hr LC_MESSAGES .. .. hu LC_MESSAGES .. .. id LC_MESSAGES .. .. is LC_MESSAGES .. .. it LC_MESSAGES .. .. ja LC_MESSAGES .. .. ka LC_MESSAGES .. .. kn LC_MESSAGES .. .. ko LC_MESSAGES .. .. li LC_MESSAGES .. .. lt LC_MESSAGES .. .. lv LC_MESSAGES .. .. mk LC_MESSAGES .. .. ml LC_MESSAGES .. .. mn LC_MESSAGES .. .. ms LC_MESSAGES .. .. mt LC_MESSAGES .. .. nb LC_MESSAGES .. .. ne LC_MESSAGES .. .. nl LC_MESSAGES .. .. nn LC_MESSAGES .. .. no LC_MESSAGES .. .. or LC_MESSAGES .. .. pa LC_MESSAGES .. .. pl LC_MESSAGES .. .. pt LC_MESSAGES .. .. pt_BR LC_MESSAGES .. .. pt_PT LC_MESSAGES .. .. ro LC_MESSAGES .. .. ru LC_MESSAGES .. .. sk LC_MESSAGES .. .. sl LC_MESSAGES .. .. sq LC_MESSAGES .. .. sr LC_MESSAGES .. .. sr@Latn LC_MESSAGES .. .. sv LC_MESSAGES .. .. ta LC_MESSAGES .. .. tg LC_MESSAGES .. .. th LC_MESSAGES .. .. tk LC_MESSAGES .. .. tr LC_MESSAGES .. .. uk LC_MESSAGES .. .. uz LC_MESSAGES .. .. vi LC_MESSAGES .. .. wa LC_MESSAGES .. .. zh LC_MESSAGES .. .. zh_CN LC_MESSAGES .. .. zh_CN.GB2312 LC_MESSAGES .. .. zh_TW LC_MESSAGES .. .. zh_TW.Big5 LC_MESSAGES .. .. .. misc .. nls C .. af_ZA.ISO8859-1 .. af_ZA.ISO8859-15 .. af_ZA.UTF-8 .. am_ET.UTF-8 .. be_BY.CP1131 .. be_BY.CP1251 .. be_BY.ISO8859-5 .. be_BY.UTF-8 .. bg_BG.CP1251 .. bg_BG.UTF-8 .. ca_ES.ISO8859-1 .. ca_ES.ISO8859-15 .. ca_ES.UTF-8 .. cs_CZ.ISO8859-2 .. cs_CZ.UTF-8 .. da_DK.ISO8859-1 .. da_DK.ISO8859-15 .. da_DK.UTF-8 .. de_AT.ISO8859-1 .. de_AT.ISO8859-15 .. de_AT.UTF-8 .. de_CH.ISO8859-1 .. de_CH.ISO8859-15 .. de_CH.UTF-8 .. de_DE.ISO8859-1 .. de_DE.ISO8859-15 .. de_DE.UTF-8 .. el_GR.ISO8859-7 .. el_GR.UTF-8 .. en_AU.ISO8859-1 .. en_AU.ISO8859-15 .. en_AU.US-ASCII .. en_AU.UTF-8 .. en_CA.ISO8859-1 .. en_CA.ISO8859-15 .. en_CA.US-ASCII .. en_CA.UTF-8 .. en_GB.ISO8859-1 .. en_GB.ISO8859-15 .. en_GB.US-ASCII .. en_GB.UTF-8 .. en_IE.UTF-8 .. en_NZ.ISO8859-1 .. en_NZ.ISO8859-15 .. en_NZ.US-ASCII .. en_NZ.UTF-8 .. en_US.ISO8859-1 .. en_US.ISO8859-15 .. en_US.UTF-8 .. es_ES.ISO8859-1 .. es_ES.ISO8859-15 .. es_ES.UTF-8 .. et_EE.ISO8859-15 .. et_EE.UTF-8 .. fi_FI.ISO8859-1 .. fi_FI.ISO8859-15 .. fi_FI.UTF-8 .. fr_BE.ISO8859-1 .. fr_BE.ISO8859-15 .. fr_BE.UTF-8 .. fr_CA.ISO8859-1 .. fr_CA.ISO8859-15 .. fr_CA.UTF-8 .. fr_CH.ISO8859-1 .. fr_CH.ISO8859-15 .. fr_CH.UTF-8 .. fr_FR.ISO8859-1 .. fr_FR.ISO8859-15 .. fr_FR.UTF-8 .. he_IL.UTF-8 .. hi_IN.ISCII-DEV .. hr_HR.ISO8859-2 .. hr_HR.UTF-8 .. hu_HU.ISO8859-2 .. hu_HU.UTF-8 .. hy_AM.ARMSCII-8 .. hy_AM.UTF-8 .. is_IS.ISO8859-1 .. is_IS.ISO8859-15 .. is_IS.UTF-8 .. it_CH.ISO8859-1 .. it_CH.ISO8859-15 .. it_CH.UTF-8 .. it_IT.ISO8859-1 .. it_IT.ISO8859-15 .. it_IT.UTF-8 .. ja_JP.SJIS .. ja_JP.UTF-8 .. ja_JP.eucJP .. kk_KZ.PT154 .. kk_KZ.UTF-8 .. ko_KR.CP949 .. ko_KR.UTF-8 .. ko_KR.eucKR .. la_LN.ISO8859-1 .. la_LN.ISO8859-15 .. la_LN.ISO8859-2 .. la_LN.ISO8859-4 .. la_LN.US-ASCII .. lt_LT.ISO8859-13 .. lt_LT.ISO8859-4 .. lt_LT.UTF-8 .. nl_BE.ISO8859-1 .. nl_BE.ISO8859-15 .. nl_BE.UTF-8 .. nl_NL.ISO8859-1 .. nl_NL.ISO8859-15 .. nl_NL.UTF-8 .. no_NO.ISO8859-1 .. no_NO.ISO8859-15 .. no_NO.UTF-8 .. pl_PL.ISO8859-2 .. pl_PL.UTF-8 .. pt_BR.ISO8859-1 .. pt_BR.UTF-8 .. pt_PT.ISO8859-1 .. pt_PT.ISO8859-15 .. pt_PT.UTF-8 .. ro_RO.ISO8859-2 .. ro_RO.UTF-8 .. ru_RU.CP1251 .. ru_RU.CP866 .. ru_RU.ISO8859-5 .. ru_RU.KOI8-R .. ru_RU.UTF-8 .. sk_SK.ISO8859-2 .. sk_SK.UTF-8 .. sl_SI.ISO8859-2 .. sl_SI.UTF-8 .. sr_YU.ISO8859-2 .. sr_YU.ISO8859-5 .. sr_YU.UTF-8 .. sv_SE.ISO8859-1 .. sv_SE.ISO8859-15 .. sv_SE.UTF-8 .. tr_TR.ISO8859-9 .. tr_TR.UTF-8 .. uk_UA.ISO8859-5 .. uk_UA.KOI8-U .. uk_UA.UTF-8 .. zh_CN.GB18030 .. zh_CN.GB2312 .. zh_CN.GBK .. zh_CN.UTF-8 .. zh_CN.eucCN .. zh_HK.Big5HKSCS .. zh_HK.UTF-8 .. zh_TW.Big5 .. zh_TW.UTF-8 .. .. pixmaps .. sgml .. skel .. xml .. .. www .. .. percona-galera-3-3.8-3390/scripts/mysql/freebsd/server-plist000066400000000000000000000165311244131713600236400ustar00rootroot00000000000000@comment PKG_FORMAT_REVISION:1.1 @name mysql-server-%{MYSQL_VER}_wsrep_%{RELEASE} @comment ORIGIN:databases/mysql%{MAJORMINOR}-server_wsrep @cwd /usr/local @srcdir %{SRCDIR} @comment "=== dependencies ===" @comment "require /usr/local/lib/gcc48/libstdc++.so" @comment // @pkgdep gcc-4.8.2.s20130808 @comment DEPORIGIN:lang/gcc48 @comment // @pkgdep openssl-1.0.1_8 @comment DEPORIGIN:security/openssl @comment // @pkgdep libexecinfo-1.1_3 @comment DEPORIGIN:devel/libexecinfo @comment // @pkgdep lsof-4.88.d,8 @comment DEPORIGIN:sysutils/lsof @comment // @pkgdep sudo-1.8.7_1 @comment DEPORIGIN:security/sudo @comment // @pkgdep rsync-3.0.9_3 @comment DEPORIGIN:net/rsync @comment // @pkgdep perl-5.14.4 @comment DEPORIGIN:lang/perl5.14 @pkgdep mysql-client-%{MYSQL_VER}_wsrep_%{RELEASE} @comment DEPORIGIN:databases/mysql%{MAJORMINOR}-client_wsrep @conflicts mysql-server-[34].* @conflicts mysql-server-5.[0-57-9].* @conflicts mariadb-server-5.* @conflicts percona-server-5.* @comment "=== preinstall stage ===" @exec echo "===> Linking /usr/local/bin/bash to /bin/bash" @exec [ -x /bin/bash ] && echo "Using existing /bin/bash." || ln -s ../usr/local/bin/bash /bin/bash @exec echo "===> Creating users and/or groups." @exec if ! /usr/sbin/pw groupshow mysql >/dev/null 2>&1; then echo "Creating group 'mysql' with gid '88'."; /usr/sbin/pw groupadd mysql -g 88; else echo "Using existing group 'mysql'."; fi @exec if ! /usr/sbin/pw usershow mysql >/dev/null 2>&1; then echo "Creating user 'mysql' with uid '88'."; /usr/sbin/pw useradd mysql -u 88 -g 88 -c "MySQL Daemon" -d /var/db/mysql -s /usr/sbin/nologin; else echo "Using existing user 'mysql'."; fi @exec install -d -g 88 -o 88 /var/db/mysql @comment "=== preremove stage ===" @unexec %D/etc/rc.d/mysql-server forcestop 2>/dev/null || true @comment "=== file section ===" @owner root @group wheel @mode 0444 share/licenses/mysql-server-%{MYSQL_VER}_wsrep_%{RELEASE}/catalog.mk share/licenses/mysql-server-%{MYSQL_VER}_wsrep_%{RELEASE}/LICENSE share/licenses/mysql-server-%{MYSQL_VER}_wsrep_%{RELEASE}/GPLv3 @comment "added: man/man1/innochecksum.1.gz" man/man1/innochecksum.1.gz man/man1/my_print_defaults.1.gz man/man1/myisam_ftdump.1.gz man/man1/myisamchk.1.gz man/man1/myisamlog.1.gz man/man1/myisampack.1.gz man/man1/mysql.server.1.gz man/man1/mysql_convert_table_format.1.gz man/man1/mysql_fix_extensions.1.gz man/man1/mysql_install_db.1.gz man/man1/mysql_plugin.1.gz man/man1/mysql_secure_installation.1.gz man/man1/mysql_setpermission.1.gz man/man1/mysql_tzinfo_to_sql.1.gz man/man1/mysql_upgrade.1.gz man/man1/mysql_zap.1.gz man/man1/mysqlbug.1.gz man/man1/mysqld_multi.1.gz man/man1/mysqld_safe.1.gz man/man1/mysqldumpslow.1.gz man/man1/mysqlhotcopy.1.gz man/man1/mysqlman.1.gz man/man1/mysqltest.1.gz man/man1/perror.1.gz man/man1/replace.1.gz man/man1/resolve_stack_dump.1.gz man/man1/resolveip.1.gz man/man8/mysqld.8.gz @mode 0555 bin/innochecksum bin/my_print_defaults bin/myisam_ftdump bin/myisamchk bin/myisamlog bin/myisampack bin/mysql_convert_table_format bin/mysql_fix_extensions bin/mysql_install_db bin/mysql_plugin bin/mysql_secure_installation bin/mysql_setpermission bin/mysql_tzinfo_to_sql bin/mysql_upgrade bin/mysql_zap bin/mysqlbug bin/mysqld_multi bin/mysqld_safe bin/mysqldumpslow bin/mysqlhotcopy bin/mysqltest bin/perror bin/replace bin/resolve_stack_dump bin/resolveip @mode 0444 @ignore lib/mysql/libmysqld.a lib/mysql/plugin/adt_null.so lib/mysql/plugin/auth.so lib/mysql/plugin/auth_test_plugin.so lib/mysql/plugin/daemon_example.ini lib/mysql/plugin/libdaemon_example.so lib/mysql/plugin/mypluglib.so lib/mysql/plugin/qa_auth_client.so lib/mysql/plugin/qa_auth_interface.so lib/mysql/plugin/qa_auth_server.so lib/mysql/plugin/semisync_master.so lib/mysql/plugin/semisync_slave.so lib/mysql/plugin/validate_password.so @mode 0555 libexec/mysqld share/mysql/binary-configure @mode 0444 share/mysql/bulgarian/errmsg.sys share/mysql/charsets/Index.xml share/mysql/charsets/README share/mysql/charsets/armscii8.xml share/mysql/charsets/ascii.xml share/mysql/charsets/cp1250.xml share/mysql/charsets/cp1251.xml share/mysql/charsets/cp1256.xml share/mysql/charsets/cp1257.xml share/mysql/charsets/cp850.xml share/mysql/charsets/cp852.xml share/mysql/charsets/cp866.xml share/mysql/charsets/dec8.xml share/mysql/charsets/geostd8.xml share/mysql/charsets/greek.xml share/mysql/charsets/hebrew.xml share/mysql/charsets/hp8.xml share/mysql/charsets/keybcs2.xml share/mysql/charsets/koi8r.xml share/mysql/charsets/koi8u.xml share/mysql/charsets/latin1.xml share/mysql/charsets/latin2.xml share/mysql/charsets/latin5.xml share/mysql/charsets/latin7.xml share/mysql/charsets/macce.xml share/mysql/charsets/macroman.xml share/mysql/charsets/swe7.xml share/mysql/czech/errmsg.sys share/mysql/danish/errmsg.sys share/mysql/dictionary.txt share/mysql/dutch/errmsg.sys share/mysql/english/errmsg.sys share/mysql/errmsg-utf8.txt share/mysql/estonian/errmsg.sys share/mysql/fill_help_tables.sql share/mysql/french/errmsg.sys share/mysql/german/errmsg.sys share/mysql/greek/errmsg.sys share/mysql/hungarian/errmsg.sys share/mysql/innodb_memcached_config.sql share/mysql/italian/errmsg.sys share/mysql/japanese/errmsg.sys share/mysql/korean/errmsg.sys share/mysql/magic share/mysql/my-default.cnf share/mysql/mysql-log-rotate share/mysql/mysql.server share/mysql/mysql_security_commands.sql share/mysql/mysql_system_tables.sql share/mysql/mysql_system_tables_data.sql share/mysql/mysql_test_data_timezone.sql share/mysql/mysqld_multi.server share/mysql/norwegian-ny/errmsg.sys share/mysql/norwegian/errmsg.sys share/mysql/polish/errmsg.sys share/mysql/portuguese/errmsg.sys share/mysql/romanian/errmsg.sys share/mysql/russian/errmsg.sys share/mysql/serbian/errmsg.sys share/mysql/slovak/errmsg.sys share/mysql/spanish/errmsg.sys share/mysql/swedish/errmsg.sys share/mysql/ukrainian/errmsg.sys @comment "wsrep specific @mode 0555 bin/wsrep_sst_common bin/wsrep_sst_mysqldump bin/wsrep_sst_rsync bin/wsrep_sst_rsync_wan bin/wsrep_sst_xtrabackup @mode 0444 share/mysql/my_wsrep.cnf share/mysql/wsrep_notify share/doc/mysql%{MAJORMINOR}-server_wsrep/README share/doc/mysql%{MAJORMINOR}-server_wsrep/QUICK_START @mode 0555 etc/rc.d/mysql-server @comment "=== postinstall stage ===" @comment "=== postremove stage ===" @dirrm share/licenses/mysql-server-%{MYSQL_VER}_wsrep_%{RELEASE} @dirrm lib/mysql/plugin @unexec rmdir "%D/lib/mysql" 2>/dev/null || true @dirrm share/mysql/bulgarian @dirrm share/mysql/charsets @dirrm share/mysql/czech @dirrm share/mysql/danish @dirrm share/mysql/dutch @dirrm share/mysql/english @dirrm share/mysql/estonian @dirrm share/mysql/french @dirrm share/mysql/german @dirrm share/mysql/greek @dirrm share/mysql/hungarian @dirrm share/mysql/italian @dirrm share/mysql/japanese @dirrm share/mysql/korean @dirrm share/mysql/norwegian @dirrm share/mysql/norwegian-ny @dirrm share/mysql/polish @dirrm share/mysql/portuguese @dirrm share/mysql/romanian @dirrm share/mysql/russian @dirrm share/mysql/serbian @dirrm share/mysql/slovak @dirrm share/mysql/spanish @dirrm share/mysql/swedish @dirrm share/mysql/ukrainian @dirrm share/mysql @unexec if [ -f %D/info/dir ]; then if sed -e '1,/Menu:/d' %D/info/dir | grep -q '^[*] '; then true; else rm %D/info/dir; fi; fi @unexec if /usr/sbin/pw user show mysql >/dev/null 2>&1; then echo "==> You should manually remove the \"mysql\" user. "; fi @unexec if /usr/sbin/pw group show mysql >/dev/null 2>&1; then echo "==> You should manually remove the \"mysql\" group. "; fi percona-galera-3-3.8-3390/scripts/mysql/get_patch.sh000077500000000000000000000035431244131713600221400ustar00rootroot00000000000000#!/bin/bash -u set -x usage() { echo -e "Usage: $0 " } if [ $# -lt 2 ] then usage exit -1 fi #set -x set -e OS=$(uname -s) function MD5SUM() { if [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ]; then md5 -q $1 else md5sum $1 | awk '{ print $1 }' fi } # Source paths are either absolute or relative to script, get absolute THIS_DIR=$(pwd -P) cd $2 WSREP_REV=$(bzr revno -q --tree) WSREP_PATCH_SPEC=$1-$WSREP_REV # Check existing file # This is done to not to depend on LP operation, however it looks like # any changes uncommitted locally might go unnoticed as revno stays the same WSREP_PATCH_FILE=$(ls $THIS_DIR/${WSREP_PATCH_SPEC}_*_.diff 2>/dev/null || : ) if [ -r "$WSREP_PATCH_FILE" ] then WSREP_PATCH_MD5SAVE=$(basename $WSREP_PATCH_FILE | awk -F _ '{ print $2 }' ) WSREP_PATCH_MD5TEST=$(MD5SUM $WSREP_PATCH_FILE | awk '{ print $1 }') if [ $WSREP_PATCH_MD5SAVE = $WSREP_PATCH_MD5TEST ] then # to be safe we better regenerate the patch every time echo $WSREP_PATCH_FILE > /dev/null # exit 0 fi fi # Existing file either not found or corrupted, try to create a new one rm -f $WSREP_PATCH_FILE #MYSQL_BRANCH="lp:mysql-server/5.1" #MYSQL_LP_REV=$( bzr tags -d $MYSQL_BRANCH | grep -m1 "$1" | awk '{ print $2 }' ) #if [ -z "$MYSQL_LP_REV" ] #then # echo "No such tag/revision: $1" # exit -1 #fi WSREP_PATCH_TMP="$THIS_DIR/$WSREP_PATCH_SPEC.diff" # normally we expect bzr diff return 1 (changes available) bzr diff -p1 -v --diff-options " --exclude=.bzrignore " \ -r tag:$1..branch:$2 \ > "$WSREP_PATCH_TMP" || if [ $? -gt 1 ]; then exit -1; fi WSREP_PATCH_MD5SUM=$(MD5SUM $WSREP_PATCH_TMP | awk '{ print $1 }') WSREP_PATCH_FILE=$THIS_DIR/${WSREP_PATCH_SPEC}_${WSREP_PATCH_MD5SUM}_.diff mv $WSREP_PATCH_TMP $WSREP_PATCH_FILE echo $WSREP_PATCH_FILE percona-galera-3-3.8-3390/scripts/mysql/my-5.1.cnf000066400000000000000000000014571244131713600212630ustar00rootroot00000000000000# Default mysqld options [mysqld] core-file innodb_buffer_pool_size=420M innodb_log_file_size=100M innodb_flush_log_at_trx_commit=2 max_connections=1024 # # Here are options to load innodb plugin. Uncomment, if you want to # load innodb plugin during server start. # Note, mysql-galera start script has --plugin option, which sets these # plugin options on command line. Use one of these methods to load innodb # plugin, but not both # # MariaDB uses xtradb as a built-in, so no need to load any plugins ignore_builtin_innodb plugin-load=innodb=ha_innodb_plugin.so;innodb_trx=ha_innodb_plugin.so;innodb_locks=ha_innodb_plugin.so;innodb_lock_waits=ha_innodb_plugin.so;innodb_cmp=ha_innodb_plugin.so;innodb_cmp_reset=ha_innodb_plugin.so;innodb_cmpmem=ha_innodb_plugin.so;innodb_cmpmem_reset=ha_innodb_plugin.so percona-galera-3-3.8-3390/scripts/mysql/my-5.5.cnf000066400000000000000000000002321244131713600212550ustar00rootroot00000000000000# Default mysqld options [mysqld] core-file innodb_buffer_pool_size=420M innodb_log_file_size=100M innodb_flush_log_at_trx_commit=2 max_connections=1024 percona-galera-3-3.8-3390/scripts/mysql/mysql-galera000077500000000000000000000422111244131713600221620ustar00rootroot00000000000000#!/bin/bash -e SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) # Copyright (C) 2007, 2008 Codership Oy # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # WHAT IT IS: # This script starts mysqld from Galera test distribution. It may be adapted # to be run from /etc/init.d directory for automatic server startup. # # USAGE: # GCS_ADDRESS=
mysqld_galera start|stop|restart|check|create # # By default empty backend is "dummy". # # 'check' command takes options: [database [table_to_ignore] [table_to_ignore]...] # # USEFUL ENVIRONMENT VARIABLES: # # MY_CNF - specifies the configuration file # GCS_ADDRESS - overrides setting in my.cnf # MYSQL_PORT - port to listen for client connections (default: 3306) # LIBGALERA - location of the galera shared library file # # Convention: mysql pid file is stored in mysql data dir under name 'mysql.pid' # # Normally only the following parameters need to be changed: # Where mysql data directory is located (by default - inside mysql installation) # MYSQL_DATA_DIR # Where mysql installation is located (by default determined from this script location) MYSQL_BASE_DIR=${MYSQL_BASE_DIR:-"$(dirname $SELF)/mysql"} GALERA_BASE_DIR=${GALERA_BASE_DIR:-"$(dirname $SELF)/galera"} # MySQL configuration file MY_CNF=${MYSQL_CNF:-"$MYSQL_BASE_DIR/etc/my.cnf"} if test -s "$MY_CNF" then DEFAULTS_OPTION=" --defaults-file=$MY_CNF " my_cnf_datadir=$(grep ^datadir $MY_CNF | sed s/[^/]*//) else DEFAULTS_OPTION=" --no-defaults " fi # If it was not given explicitely, use the one from my.cnf MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$my_cnf_datadir"} # If it was not found in my.cnf, use distribution default MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$MYSQL_BASE_DIR/var"} MYSQLD_USER=$(whoami) #======================================================================= ## ## Tweak the following if needed ## # use mysqld server directly, better not have automatic restarting MYSQLD="$MYSQL_BASE_DIR/sbin/mysqld" [ ! -x "$MYSQLD" -a -x "${MYSQLD}-debug" ] && MYSQLD=${MYSQLD}-debug MYSQLADMIN="$MYSQL_BASE_DIR/bin/mysqladmin" # Port, socket and pid files MYSQL_PORT=${MYSQL_PORT:-3306} MYSQL_SOCKET=${MYSQL_SOCKET:-"$MYSQL_DATA_DIR/mysqld.sock"} MYSQL_PID=${MYSQL_PID:-"$MYSQL_DATA_DIR/mysqld.pid"} # Startup wait timeout. MYSQL_STARTUP_WAIT=${MYSQL_STARTUP_WAIT:-1} # Shutdown wait timeout. MYSQL_SHUTDOWN_WAIT=60 #============= Nothing servicable below ================================ # User to run as if started under superuser #if test "$MYSQLD_USER" = "root" #then # MYSQLD_USER=mysql #fi ROOT_USER=${ROOT_USER:-"-uroot"} ROOT_PSWD=${ROOT_PSWD:-"-prootpass"} # Mandatory stuff INNODB_OPTS=" --default-storage-engine=InnoDB " # --debug terribly affects performance #DEBUG_OPTS=" --debug " #DEBUG_OPTS=" --debug=d,galera,wsdb:t:i:o,$MYSQL_DATA_DIR/mysqld.trc" SKIP_RECOVERY=0 START_POSITION="" err_log="$MYSQL_DATA_DIR/mysqld.err" mysql_log="$MYSQL_DATA_DIR/mysqld.log" usage() { cat - << EOF usage: mysql-galera [options] command Options: -c|--command : command to execute (status) --data_dir : location for mysql data directories --db : name of database to check -d|--debug : enable debug output --donor : desired state transfer donor -g|--gcs_address : address of gcs server (spread://locahost:4803) --gdb : run under gdb -i|--ignore_table : table to ignore in checking -l|--log : enable mysql query log --mysql-opt : an option to the server to follow -p|--password : mysql root user password --plugin : use innodb plugin --slave_threads : number of consurrent ws appliers (1) -u|--user : mysql root user --valgrind : run under valgrind --ws_level : RBR (default) or SQL -P|--port : port for MySQL client connections -S|--socket : location of mysqld socket --skip-recovery : skip recovery phase --start-position : start position passed to server Commands: check : check cosistency of database given with --db option start : start servers stop : stop servers restart : stop and start servers status : show running servers EOF } # Checks if a process with a given PID is still running find_pid() { ps ax | grep mysqld | grep -w ^\ *$1 > /dev/null } get_status() { local stat_var=$1 set -o pipefail mysql $ROOT_USER $ROOT_PSWD --socket $MYSQL_SOCKET --skip-column-names \ --reconnect -Be "SET wsrep_on=0; SHOW STATUS LIKE '$stat_var'" | \ cut -f 2 } # Loop until wsrep_ready == ON wait_for_wsrep_ready() { echo -n "Waiting for wsrep_ready" local pid=$1 local ret=1 local ready while find_pid $pid do echo -n "." sleep 1 # mysql connection can be interrupted by SST code, # don't fail on it rigth away ready=$(get_status "wsrep_ready") && \ if [ $ret ] && [ "$ready" == "ON" ]; then ret=0; break; fi done if [ $ret ] then echo " Done" else echo " Failed" fi return $ret } check_gcs_address() { local addr="$1" if [ -n "$addr" ] then case "$addr" in "gcomm://"*) # we could be checking address here, but generally it does not # have to exist yet. ;; "dummy://"*) ;; *) echo "Cluster address should start with either 'gcomm://' or 'dummy://'. Server not started." >&2 exit 1 esac fi } wsrep_start_position_opt="" # Run mysqld with --wsrep-recover and parse recovered position from log. # Position will be stored in wsrep_start_position_opt global. wsrep_recovery() { cmd="$@" wr_logfile=$(mktemp -t wsrep.XXXXXXXXXX) echo "WSREP: Running position recovery" set +e [ "$OS" == "Darwin" ] && export LD_LIBRARY_PATH $cmd --log_error=$wr_logfile --wsrep-recover [ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH rp=$(grep "WSREP: Recovered position:" $wr_logfile) if [ -z "$rp" ]; then skipped=$(grep WSREP $wr_logfile | grep "skipping position recovery") if [ -z "$skipped" ]; then echo "WSREP: Failed to recover position: " \ `cat $wr_logfile`; else echo "WSREP: Position recovery skipped" fi else start_pos=$(echo $rp | sed 's/.*WSREP\:\ Recovered\ position://' \ | sed 's/^[ \t]*//') wsrep_start_position_opt="--wsrep_start_position=$start_pos" echo "WSREP: Recovered position $start_pos" fi set -e rm $wr_logfile } galera_start() { local failed if ! test -x $MYSQLD then echo "$MYSQLD executable not found" exit -1 fi if test -f $MYSQL_PID then echo "Found existing '$MYSQL_PID'. Please run '$0 stop'" exit -1; fi # if [ -n "$MYSQL_LOG" ] # then # LOGGING_OPTS=" --general_log=1 --log_output=FILE " # fi if [ -n "$WS_LEVEL" ] then RBR_OPTS=" --binlog_format=$WS_LEVEL " fi WSREP=${WSREP:-"$GALERA_BASE_DIR/lib/libgalera_smm.so"} if test -f $WSREP || test $WSREP == "none" then WSREP_OPTS="--wsrep_provider=$WSREP" else echo "WSREP driver '$WSREP' not found" exit -1 fi if test -n "$GCS_ADDRESS" then check_gcs_address $GCS_ADDRESS WSREP_OPTS="$WSREP_OPTS --wsrep_cluster_address=$GCS_ADDRESS" fi if test -n "$WSREP_SST_DONOR" then WSREP_OPTS="$WSREP_OPTS --wsrep_sst_donor=$WSREP_SST_DONOR" fi if test -n "$SLAVE_THREADS" then WSREP_OPTS="$WSREP_OPTS --wsrep_slave_threads=$SLAVE_THREADS" fi if test -f "$MYSQL_DATA_DIR/core" then mv "$MYSQL_DATA_DIR/core" "$MYSQL_DATA_DIR/core.old" fi echo -n "Starting mysqld instance with data dir $MYSQL_DATA_DIR and listening at port $MYSQL_PORT and socket $MYSQL_SOCKET..." ulimit -n 4096 # This is normally allowed for non-privileged users echo 0x3f > /proc/self/coredump_filter # dump mmapped memory as well if test $SKIP_RECOVERY = 0 then wsrep_recovery $MYSQLD \ $DEFAULTS_OPTION \ --user="$MYSQLD_USER" \ --basedir="$MYSQL_BASE_DIR" \ --datadir="$MYSQL_DATA_DIR" \ --plugin-dir=lib/mysql/plugin \ --pid-file="$MYSQL_PID" \ --port=$MYSQL_PORT \ --socket=$MYSQL_SOCKET \ --skip-external-locking \ --log_error=$err_log \ $MYSQLD_OPTS \ $INNODB_OPTS \ $WSREP_OPTS \ $DEBUG_OPTS \ $LOGGING_OPTS \ $RBR_OPTS \ $PLUGIN_OPTS else echo "skipping recovery" if test -n "$START_POSITION" then wsrep_start_position_opt="--wsrep-start-position=$START_POSITION" fi fi [ "$OS" == "Darwin" ] && export LD_LIBRARY_PATH if test -z $GDB then nohup $VALGRIND $MYSQLD \ $DEFAULTS_OPTION \ --user="$MYSQLD_USER" \ --basedir="$MYSQL_BASE_DIR" \ --datadir="$MYSQL_DATA_DIR" \ --plugin-dir=lib/mysql/plugin \ --pid-file="$MYSQL_PID" \ --port=$MYSQL_PORT \ --socket=$MYSQL_SOCKET \ --skip-external-locking \ --log_error=$err_log \ $INNODB_OPTS \ $WSREP_OPTS \ $DEBUG_OPTS \ $LOGGING_OPTS \ $RBR_OPTS \ $PLUGIN_OPTS \ $wsrep_start_position_opt \ $MYSQLD_OPTS \ 1>/dev/null 2>>$err_log & else $GDB --args $MYSQLD \ $DEFAULTS_OPTION \ --user="$MYSQLD_USER" \ --basedir="$MYSQL_BASE_DIR" \ --datadir="$MYSQL_DATA_DIR" \ --plugin-dir=lib/mysql/plugin \ --pid-file="$MYSQL_PID" \ --port=$MYSQL_PORT \ --socket=$MYSQL_SOCKET \ --skip-external-locking \ --log_error=$err_log \ $INNODB_OPTS \ $WSREP_OPTS \ $DEBUG_OPTS \ $LOGGING_OPTS \ $RBR_OPTS \ $PLUGIN_OPTS \ $wsrep_start_position_opt \ $MYSQLD_OPTS fi my_pid=$! [ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH # echo "Waiting for pid file" second=0 while ! test -r $MYSQL_PID do sleep 1 second=$(($second + 1)) if find_pid $my_pid then # process is alive, wait for pid file echo -n "." elif test $MYSQL_STARTUP_WAIT -lt 0 -o \ $second -lt $MYSQL_STARTUP_WAIT then # process is not yet alive, wait for it to start echo -n "." else failed="yes" break fi done if test "$failed" != "yes" then echo " Done (PID:$(cat $MYSQL_PID))" else echo " Failed (PID:$my_pid)" return 1 fi wait_for_wsrep_ready $my_pid } galera_stop() { # check pid file if test -r $MYSQL_PID then # check if corresponding mysqld is running # if ps axc | grep mysqld | grep $(cat $MYSQL_PID) >/dev/null 2>&1 local my_pid=$(cat $MYSQL_PID) if find_pid $my_pid then echo -n "Killing PID $my_pid" kill $my_pid # wait for pid file to disappear for second in $(seq 1 $MYSQL_SHUTDOWN_WAIT) do echo -n "." sleep 1 if test ! -r $MYSQL_PID then break fi done echo "" if test "$second" = "$MYSQL_SHUTDOWN_WAIT" then echo -n "Failed to stop mysqld safely. Killing with -9... " kill -9 $my_pid fi else echo -n "Removing stale PID file $MYSQL_PID... " fi rm -f $MYSQL_PID echo "Done" else echo "PID file not found: $MYSQL_PID" fi } galera_restart() { galera_stop galera_start } galera_status() { if test -f $MYSQL_PID then local my_pid=$(cat $MYSQL_PID) if find_pid $my_pid then echo "mysqld running with PID: $my_pid" else echo "Found existing '$MYSQL_PID', but mysqld is not running" fi exit 0; else echo "no PID file: '$MYSQL_PID'" fi } dump() { #local ROUTINES="--routines" # don't dump routines yet, will cause false err. #local OPTIONS="--create-options" gives false positives on AUTO_INCREMENT tbls # --flush-logs --lock-all-tables # this blocks waiting for all trx to complete # thus impossible to use with -STOP/CONT local DUMP_OPTIONS=" --skip-opt --compact --quick --order-by-primary \ $OPTIONS --set-charset --skip-comments $ROUTINES " DB=${DB:-"--all-databases"} #set -x mysqldump $DUMP_OPTIONS $ROOT_USER $ROOT_PSWD --socket $MYSQL_SOCKET \ $IGNORE_TABLES $DB #set +x } wait_for_last_committed() { local lc local new_lc lc=$(get_status "wsrep_last_committed") while [ 1 ] do sleep 1 new_lc=$(get_status "wsrep_last_committed") if [ "$lc" == "$new_lc" ]; then break; fi lc="$new_lc" done } checksum() { wait_for_last_committed set -o pipefail if [ "$OS" == "Darwin" -o "$OS" == "FreeBSD" ]; then CS=$(dump | md5)" -" || return $? else CS=$(dump | md5sum) || return $? fi echo $CS } # to use valgrind or not VALGRIND=${VALGRIND:-""} # write set level, SQL, RBR or ROW WS_LEVEL="" #DB="test" # use 'test' database if none given # in 5.6 the following tables are non-deterministic IGNORE_TABLES=\ "--ignore-table=mysql.innodb_table_stats --ignore-table=mysql.innodb_index_stats" # to use innodb plugin or not PLUGIN_OPTS="" if [ $# -eq 0 ]; then usage; exit 1; fi while [ $# -gt 0 ]; do case $1 in -h|--help) usage exit 0 ;; -d|--debug) DEBUG_OPTS=" --wsrep_debug=1 " ;; --dbug) DBUG_OPTS=" --debug=d,galera,wsdb:t:i:o" ;; -l|--log) LOGGING_OPTS=" --general_log=1 --log_output=FILE " # MYSQL_LOG="log" ;; --valgrind) VALGRIND="valgrind --log-file=$MYSQL_DATA_DIR/vg.log --leak-check=full --track-origins=yes" # to force deallocation in std::string and STL containers export GLIBCXX_FORCE_NEW=1 ;; --gdb) GDB="gdb" ;; -g|--gcs_address) GCS_ADDRESS=$2 shift ;; --donor) WSREP_SST_DONOR=$2 shift ;; --slave_threads) SLAVE_THREADS=$2 shift ;; --db) DB=$2 shift ;; -i|--ignore_table) IGNORE_TABLES=" $IGNORE_TABLES --ignore-table=$DB.$2 " shift ;; --ws_level) WS_LEVEL=$2 shift ;; -u|--user) ROOT_USER="-u$2" shift ;; -p|--password) ROOT_PSWD="-p$2" shift ;; --plugin) PLUGIN_OPTS="--ignore_builtin_innodb --plugin-load=innodb=ha_innodb_plugin.so;innodb_trx=ha_innodb_plugin.so;innodb_locks=ha_innodb_plugin.so;innodb_lock_waits=ha_innodb_plugin.so;innodb_cmp=ha_innodb_plugin.so;innodb_cmp_reset=ha_innodb_plugin.so;innodb_cmpmem=ha_innodb_plugin.so;innodb_cmpmem_reset=ha_innodb_plugin.so " ;; --data_dir) MYSQL_DATA_DIR=$2 shift ;; -c|--command) COMMAND=$2 ;; --mysql-opt) MYSQLD_OPTS="$MYSQLD_OPTS $2" shift ;; -P|--port) MYSQL_PORT="$2" shift ;; -S|--socket) MYSQL_SOCKET="$2" shift ;; --skip-recovery) SKIP_RECOVERY=1 ;; --start-position) START_POSITION="$2" shift ;; 'dump') COMMAND="dump" ;; 'check') COMMAND="checksum" ;; 'start') COMMAND=galera_start ;; 'stop') COMMAND=galera_stop ;; 'restart') COMMAND=galera_restart ;; 'status') COMMAND=galera_status ;; 'create') COMMAND="create_data_dir $2" shift ;; *) # must be command echo "error parsing: $@" usage exit 1 ;; esac shift done if [ -z "$COMMAND" ] then usage >&2 exit 1 fi OS=$(uname) export LD_LIBRARY_PATH=$MYSQL_BASE_DIR/lib/mysql:$LD_LIBRARY_PATH [ "$OS" == "FreeBSD" ] && LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/gcc48 [ "$OS" == "Darwin" ] && export -n LD_LIBRARY_PATH export PATH=$MYSQL_BASE_DIR/bin:$PATH $COMMAND # percona-galera-3-3.8-3390/scripts/mysql/mysql-plain000077500000000000000000000066041244131713600220400ustar00rootroot00000000000000#!/bin/bash SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) # Where mysql installation is located (by default determined from this script location) if test -z "$MYSQL_BASE_DIR" then echo "MYSQL_BASE_DIR is not set" exit 1 fi # MySQL configuration file MY_CNF=${MYSQL_CNF:-"$MYSQL_BASE_DIR/etc/my.cnf"} if test -s "$MY_CNF" then DEFAULTS_OPTION=" --defaults-file=$MY_CNF " my_cnf_datadir=$(grep ^datadir $MY_CNF | sed s/[^/]*//) else DEFAULTS_OPTION=" --no-defaults " fi # If it was not given explicitely, take it from my.cnf MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$my_cnf_datadir"} # If it was not found in my.cnf, use default MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$MYSQL_BASE_DIR/var"} # use mysqld server directly, better not have automatic restarting MYSQLD=${MYSQLD:-"$(dirname $SELF)/../sql/mysqld"} # Port, socket and pid files MYSQL_PORT=${MYSQL_PORT:-3307} MYSQL_SOCKET=${MYSQL_SOCKET:-"$MYSQL_DATA_DIR/mysqld.sock"} MYSQL_PID=${MYSQL_PID:-"$MYSQL_DATA_DIR/mysqld.pid"} err_log="$MYSQL_DATA_DIR/$(hostname).err" # Checks if a process with a given PID is still running find_pid() { ps axc | grep mysqld | grep -w ^\ *$1 > /dev/null } mysql_start() { local failed if ! test -x "$MYSQLD" then echo "$MYSQLD executable not found" exit -1 fi if test -f $MYSQL_PID then echo "Found existing '$MYSQL_PID'. Please run '$0 stop'" exit -1; fi echo -n "Starting mysqld instance with data dir $MYSQL_DATA_DIR and listening to port $MYSQL_PORT and socket $MYSQL_SOCKET..." set -x nohup $MYSQLD \ $DEFAULTS_OPTION \ --basedir="$MYSQL_BASE_DIR" \ --datadir="$MYSQL_DATA_DIR" \ --pid-file="$MYSQL_PID" \ --port=$MYSQL_PORT \ --socket=$MYSQL_SOCKET \ --skip-locking \ --log_error=$err_log \ 1>/dev/null 2>>$err_log & my_pid=$! set +x # echo "Waiting for pid file" while ! test -r $MYSQL_PID do sleep 1 if find_pid $my_pid then # process is alive, wait for pid file echo -n "." else failed="yes" break fi done if test "$failed" != "yes" then echo " Done (PID:$(cat $MYSQL_PID))" else echo " Failed (PID:$my_pid)" fi } mysql_stop() { # check pid file if test -r $MYSQL_PID then # check if corresponding mysqld is running # if ps axc | grep mysqld | grep $(cat $MYSQL_PID) >/dev/null 2>&1 if find_pid $(cat $MYSQL_PID) then echo -n "Killing PID $(cat $MYSQL_PID)" kill $(cat $MYSQL_PID) # wait for pid file to disappear for second in $(seq 1 $MYSQL_SHUTDOWN_WAIT) do echo -n "." sleep 1 if test ! -r $MYSQL_PID then break fi done echo "" if test "$second" = "$MYSQL_SHUTDOWN_WAIT" then echo -n "Failed to stop mysqld safely. Killing with -9... " kill -9 $(cat $MYSQL_PID; rm -rf $MYSQL_PID) fi else echo -n "Removing stale PID file $MYSQL_PID... " rm -rf $MYSQL_PID fi echo "Done" else echo "PID file not found: $MYSQL_PID" fi } mysql_restart() { mysql_stop mysql_start } case "$1" in 'start') mysql_start $2 ;; 'stop') mysql_stop ;; 'restart') mysql_restart $2 ;; 'check') shift; checksum $* ;; *) echo "Usage: $0 start|stop|restart|check" esac # percona-galera-3-3.8-3390/scripts/mysql/mysql_var_5.1.tgz000066400000000000000000004745471244131713600230110ustar00rootroot00000000000000‹èLJì]|Õ™³²\10½ =¤à]K²!!Àhwvw¬Ù™õÉ" c/ØÁ I68Õ)¤‘Þ{‡R 1¤_r$Ws\ï½p-¹—»ä.wþßû¾i%°wmÏïûýæzû¶Xû}zíëo×ú‰ê8£¨±zhˆK«‡Šü¼48È)T©T(®, ­RÅRi°XRæÐñ&Œ°srjý„iªõ»wNlØÔÞvøÏµ'&OA'»ôøOµ'§Žç$8²ñ/ ¬.•†JzüW¬*æã"@ã¿u÷ä[Žãàñ/•Žfü‡Våã"ÐÿÛ7L¶vLlÞuuc¼r,¿ƒxU±xã?´rÕ2‹Ç’ˆÃ!ÿC¿s,¿ãÉÇ¿tÈñ_=ÿ‰Àþý U(œ¥PÕOÔ|¥ *ìã·p¸ƒɳeGñmWò÷<¦?_ð‰Íi·ï€çG£Ó=Ršû‚¹?j¹þYDïÌï/ð'NR…»üWý†:E¿~»ZRØn„)½{§)H_1Ô>Ý>4ç=á~Ƹ—º…°ÃE¡ÍCçÙ¼#ùËäÈ‘#GŽ9räÈ‘#GY8¤ýçÖ‰­Çò;žÜþ³’¬½Úrûß Á~cÑ¢>¥–løn!è›y«p³Z¨T?u§úJýð{³ (+V(ežH‚säÈ‘#GŽ9räÈ‘#GŽGÂ|¥NSÕ.¢oì)PÀ^UØóp~зg—Á‘ óöÜgð+ý{n-¨E–ÁÑ20ÏmÝy\¡8 +Gmbý¶©í‡ É‘ã˜fŽÇFÖœ ¤kj¾jìvB«‘á²Î‘#GŽ9räÈq\páh8–7'¶ohoÜ9Ñ6)Pdó–ömmÙA†Z¨îQö)ôÙª ¨å÷5Õ™éû÷¨E ˯:bùyžê¯oŸœRýª¯r‹–£ûãÉö„þ­Kƒí;§6ok·¶­ßÚÖß9ó|j÷޶Z¤¦6µX-¦?2â¨%jq´yk{rjýÖj^ÿš½ª¦iì•êïs÷©‡g½0¿¿XTl¯I_X°txŸºoÖ —žwžbûÍ2eüL¿°haíqÅö›ô‹Ûk•×§NU…Ÿ_¬Ô’Å'Ÿ¬ÿ$êzu–þ…ú Q¹Äfó…ÙLÍXfØÁ /P¨Æ^9r|ÍÀ/Û•8°õ‹ö]í ;§Ú°¶Lµ'Ìô·%¿(7&tâ¿6µ·ìhÝÞÞ}çö‰Ç6ôIã¿V ¬^}Püת•«òø¯^Vk|Ç;žV…ã ÐîU÷Ã(kBz(¡0°›¶%˜ Pø`hŽå:7Yî5AÝó’‘p­²Hú Žä©DÀ|šN庖dN%ðtŠâÀ ³¦¥k`!Dd‘\LPêvà #;h…¡Û*[YSÔ°X3á•ëV5%=K4e¿ÑtmR²&§;à$fÂ’öRÍĘŒdMH/ÀÉš‰ŠéÉÔ{NœB»“_ËdMò›¶Ð%§j&/²k¶ÜM§i&ì°l5O(œ®™µÜX0&¨jLÍövŒëóµÙòU üÆØÈpÖÔ!pÆ\ÙiT+yÕñ–Öõt¯U¶ ªȬ®u[ÃN­ØaìJ úà,:ì¿™5!½gÓî4j{¢õ‰søÄö¢zÖ”ôœË‡]ÕÏš^€óhMÄM×)k)0kjºÎOíNÄ„T­h&bÏõË‚5 \ÈkÂó+RŽçCi&Æm+h Þ¢`Ò‰¯Ñ2SÖ´t \¬™hê•mR÷&ÍÄ%š ÙËZ3q)Ï$¯j \Fv§º-z(p¹f¢»nÖ„ô\‘ ³&¤àJÍÄðxÖdô<¶hV3AõqŽ‹a5ðt:ì¬ rÄʰš‰g$e‰¢à™Ì„ì•g‘X—,9i&®fÍÎ’}Ø­àØ½´­È—jG±cƬkÝ(¶­¨Õ´ǯdMÛ%Zضk‹>'V’§Hê‘ìö¼Ä¤Ÿ59݃Ą뇂g“ º-fÝPñÚ¬ éXEÆ3Ñã ™XMu[ö‰} ›lœQǵk¶P®v²dMIÀ³IìhZ‘#X|ÂsØŒÙO ™¸nÚ{W«Z~é@ÅsÉdSó|ÉÛ®×L¬ÙÀh:é¡°åHÞ7’[­ºŽ'w>ÁbÍ®N$ÖZ€a x#ß^Ù^¥:7É”IìðÝñš´ø Y@%q²”ݘôì¬Éé°É?a¹¢…qTÉg§%@¹’“f¢F#á‚“q4ur²8žˆÝ`5t-d$Ýɲ†½§–W<Ÿ0BLÄA u»VÊÜdárÚf´û¼ÐHb;86kbº<²;5+rcç4à'ÎxÑûštØÙ;Ðc!U/ÂZŽÚƯ–5-]{ŠÖÉT$R œÞbµzç{2'¢d:9RÊ ˆÉì»î°%×jƒQ>ìÒ‚-YSÓ%0F#¶TXG¢¸Ó°ÃÈjHÍÁ8ئ/"yè0ÀMdwªYŽ'¸þž7RƬ‰éx>;ãcÙî®p˜µW“l,ÀÍ´;Õ…g·XŸe¤6x!¹€½šãIubk`=I±–Wqe:¸…Mû’'“fbCR*Y0±‘ÖÄ:'{Ú&õ4ŽìuYSÒp+Çź¶%ØÍ‚ÛÈ´ïûš ¹ç6%ÅG²¦£'`3ÇÅV-ya)àE$;K®Ú¡™¸ÓqZcÙ­ÈoiiÖõ…±…kÙh-[²p+o±¡-wEh&¶%¢xd ÎÄvb"bË~Ö´t ì -V´‹E3q;ãµR$xQ`‚ƒ¶s *©ì„a,X±31•VŸËš^€IÏ(–¬íJ“ʵZ$vaàΤ6fCrÜ>îêäÙ¥ùQ­€êŸeMØÑ»“20’7'/æ…-¼\ØK:ÓIë­ª#ÐŒ—A­Õ§Ëõ²&§;àeI¼SÙ Å&<šx9+EkcG¬[3ñ 2–ã ³ÁžÙÕ"„Šxeê³Ëš^€W¥Ö±«Z¯æ…í5Ëk´ÁkÈ?!;óÀÄÝl‹µ\×—[’¯%ÐoEõÀ¶¤ÚÆñ:Ò'${X4ðzbÂiÖ%ËâxCR-"r<¹­ñFÒ±_¨üš÷$y¤®iÞÄÙ]U¹V ¼9=ìœjÖ¤t¼e¦p›Üȼ5±;5-É¥Vß–¸»"Éùýx;ËNå¬éè xG’¶™5=ï¤Z6Vài[¨rª™xW²;µL.ïf3f ØÖ¡™xO"VDׯ|/;Y<ÁÏ4ïã¸X®z&ñ°fàýœzP ìšXÛÄh:9¶[»7i&>˜äždMH/À‡h:åº#7“Ù㉉Ш5ÍÀGˆ‰ÑØ-×öj¯oÀG5#Žàˆ- |Œv'×·$×xÇÇÉSDÙ³aSìÆøe;öXÖ„ô|RM_ò-7™ŸâÃN¤~¸—Ü]AE²=ÙÄ}\/V´NdâÓ¬žV*®-7 ŸÑLÔK,|–¦“'»&#>—Ïœ†äz±÷«Î•¡äl‘ЈÏó9Q±×IÎ=ýBbÆ´õ¢Èš–®/² ¸\|`›øײµiâ4¸×·œ;Àƒd‹Õ³©aÉ |™½§VE²ô„¯ÐHxV3¬ûb'ö&'¶+ù’<Ä1€Â# N+¼K>+ðÕÄÉ2*¹p¾FkbܳŽ\70¾>·šµD!ÖÄ7x:¹®\‹fâ›”ñ8.˜ |‹¶XªdÃn`™õÑñmÒì\X°vjâ;Нø‘«ià®*4*Yþ3±9Yb±—€0ðƒÄ,:”¿Â5Ïš®åÈ=´ñ«$v8ƒ!:À¯ña'øÐÀ¯Ó9Q¾°ƒ4»p4k:z~“ N(7œ@?dÇ£ì Oø­ä°ÇØŒ9ÖjŽ/õ:8ü6‡”  ü—ЫصÀ¥ïÀïÎxв&¥{à÷ˆ ß³‚'~Ÿm±¢£çLü½u#§é;^$Ôø‡tbǒ횉?šŽíÈš’€?NêÅ:’+<áOZòü,øSòOXå±'þ¬S¤jØ™¬™øs6ž5|Á9 &þbzMvá/ÙdC— ŽÆü+Ò±?lÅ4ñ×iÝŽÀŽ#?É þ†ô ‹’6åŠø[¶ŠËUˆø;Ò'ê‚5" ü=Y;<Ñ÷Þ›ø¶;É®gÇ57Ù_œk‡¤-Öu$×¼5ñO°i…á˜È;¸ñÏ´°Ç$«Dš‰IœñÖ¸Ür±&þ• |Ê-FÀ_·Xe¹Þ"ü¸³°¥Þ¶nâߦ³€³¦¤à'jú>»¬Iéøw5}³`«aGu‘×.ቤ¬dÙªÈ üÇœs¢éKTíðÓ™¨}·ÜªúZ •Wê ÿ™¸€å–ÒÀÑ9!¸º;?K£$Mü\ñ}vNU¤;þ›Åލ,9à ÿ£æ\Ý rÅ/ØSÊÍÅÑÀÿ&¡B‘ã•£@¨+ÿ§’‹ï³&¤`?Ùbã†HÎîBRjy’oQ†–bã ”Ý ƒ˜ðËá(’”ogsIYþlôlíd­™˜gP `M¦Õ,ú ŠÚCѲÓ|šN-9õÔÄ#‘gX,Xh¤Îø¨J½Y‹ Å×µâ&]W¶šZ&¯û±¨£‹ .µº2kBz–Ðtò$—¼ÕLœdÐUp~ÙCW«YÓÓ°49ìdÄÉkveK Ãq8E3Q·-É¡&–+‹^Ú8U31lGc¶à œf2PŽ2¡Ó ®k9¢Îè¹Àr:'¬òHkÄ—º,p‰âr³Ó8“”"KèQgi&F-7\UÒÄÙ,v¿•ù‰@txÎåî*ùÂ(ç*äɽkS3q>ÉNu¡Ž‰¸@3!ü˜0q!‹-ÆÊ­h‹ *Žn­ÀÖyP–x^À4Òû±å훸˜¶XÇÓjvÖ¤t\’˜l²¦£'àRÚb¥ÞP™—Ñ+™ \n¤Ë\“5)ÝW°Ð]BW’ÝI˜ü@ài¼°Éiš5)ÝW‘“®Æ±B‰‡5O7èb™¬Éè x9Y*¶9UGjö)ž©™ ¬fS¦fÊÀ³Œ™ð¹0t[e§YÇ®6’åеFíV8â4[e?öD™ °‚¤X_xõ¹"3áËU&4PÒLŒÛ– És0°²³°›¾ÐRõàÈ3¯ØÔM ²ãÑ•m‹28b­ätA¬b3¦S«Ù2‹,°º‘5-]×Û¤LÁL\›ìN¡Frw§gϳ&§;à9‰fg·_ÍŒëÒð9=¥¼$:Y^žKŽGGritÍÄõ´ÅºqMrœ5n  -<»ëFŽÆÌšŒÞ‹Ï 7nfÃ´ÅÆ¦ä°}”ÙggÕÄr  ÇŠÛåX®/Þ„M‡ÝðÉ ´UZض#TjJ€šfB«u’ÂD½#ÅÒ®YÓÓàédYSÒ°&µÅFõÀ–zWFØÝŒJ2 ¸©>A‹Û‘šŽÓ0fÊÏ\ô(ªÎª¼œ,¯…ÏÆ3Ë -ÖM³¦§+ É†‚ñVÃñÄŠOXkð?ɦM6a,k5ÏBdŽWèI§hVf¼Äí•€8IÛ,eMH/À(O'á7Œ%!¥Rë2°ŽF©ÕåÓ`œcÅEEAÜ”J±âJÎÍžÇi›å[ð|ÂóYì,Z­5¾H³,^`p™ú8ð~s’åPµU©‹-2c†e«)5P/äœ"K¶Ø±^31b·†]½E ­?‚[XìZ=6PXDµŠ>'6&Eª$K&ÚtNHÊå?pkj‹¥Â˜Ã"ÏkÍÄmtNÐ{q`ÏìFÓ,±Žlf?v£áD‘Ø3/šŽoX®K¹›±+n‘ãvòc7kèâè[83^t‰­\}Ž*¼“58­ÊØÆÎøŠK®+¾=±ÚÁ¨\Õ;hw’†™w°Ž-Ùˆ©™˜H=EÒ<¦³I6(WíÀöDÖ' `ŠÌ˜vØÒ<ãMq‡5;IŠe³‹-€Z†@‡;éœ}×ëÅÖLÜ•Fž9žÜš؜؂+h&^L»SÕ%ë§x ŸTÅPn‚?^:>'³#/ã<;ÙZ6^Î[lÖdô¼‚¤X_Øü9ØÃµl,w<|b¿2­Û!:õàUI™z6He¯N,€M}V„B7'¯a)ÖƒÙîžIQ“»Ïâµ4Ö¨Ýô©ù³&^G‡]5k2z^ÏIåNC®wB3ñb"+§š‰7¦e%³&¤àÖì<Ÿ*meML·À›HŸ^ÍúÍœ,èÈfâ-I€ŠÜ“Noeõ´!z(ð¶d$²¦£'àíìî~N¼ƒ ‘èäS¼3uÆ{~«l•ë"ïšvKÕˆ4ðîiCÄà¿xOZ‡‚”¥*xo’{*¹"·‰÷Ñt’›'ÈÀû¹À§ÄˆŽðŪð.4´W3ñA^¡à›€5šU~8kbº>LVñXöø ü1ÑJ6>š ZÕ@nÔ>F ›ªöfMIÀÇ9¸7h8ž%Õegâ´°ÓÛ–²&¦[à“$v„r/½'àSìŒâ@îYgâ^²;y” –5)Ý÷ÍT)µ\W¨ÑŸ&±Ã ìr$·Ø>C¢x]¨Û4>›¦2ó­Q³ª|fMØÑŸãéFŽ'8Tèþ4¤´b )ý<”ý²d;‰/Ì-$Ò¶Œ/r¨'ys2ñ%’b%g”kàÍÄu×gMFoÀƒ$ /¢Œ/wjígMK×ÀW’ʽ²cÅ÷r‚8ªøcRy0ñf¢îÔê­fàø <&L‘ÚŠŸòÕóU{ß#Âü]2¾£jKê©àz·¥˜!¥¡ÚAJƒ¿ÄÁñ³èGùT<ªÈ/Ðxs~‹v`~¶¿êVû·m#8•VuöïèÓQ=“ÌRÿHë, ÚŸLëwø+žy'U‰Q&éÌX4åt åôòIU5—R4ÔøFÝä Îõ­”ÓDT¥­}ÉXÔmÄÇÓkÝœOê ü%ªÝOÅ^¯â%v(„_oáœîÂR‘ϤԋtS!¥oRñ¾H ?àÎñŽ`~œ˜ÀòÃ7󞥀D‰-îÙlŽý\ŠM«@<¯‹ÝE½~R‰TìΓÆúK§T+دã—ÛôLÇ®/34DÏ( W·£àâŠðDâPB5*Ë_[E8å \%é…1•I¢fSÍ©„Æ‹DO6AY%sj ãÂõˆ-î/¯r¡æÛ[Éí>¡©Vóý”ëÿ³Ìç˜òdT67àmÌogXa¸ÀPQ5怋Ìï`Xg¨,«À&sÀ%æ€<ë0.3<Ép…9àÌïbxŠ9àÝ̉9à3˜ÚÌŸÉðYÌ™9à³™>‡9às™>9àó™ÞÃðÌ_ÈðW˜¾ˆ9à¯2|1sÀ—0|)sÀ—1|9sÀW0|%sÀ_cø*怯fø怯eÈ«ã뙾9à™¾‰9à½ÌßÌð-ÌßÊðmÌßÎðÌßÉð]ÌßÍð=ÌßËð}ÌßÏðÌ?ÈðCÌ?Ìð#Ì?Êð>æ€cøq怿ÎðÌ?ÉðSÌ?Íð3Ì?ËðsÌ•mx?sÀÏ3|€9à˜~‘9à—˜þsÀ/3üM怿Åð·™þs„¶Òš…Ç$ ìzn 6ßI6)ÜF ÷#…»"7„àL.é‘nåö¶oBrh :|Â#pz:äHSm‚¤¿þûë¿O ~ ?Õ2c¼J\á|j~uÊÀáU6eÀ¾ÜU6k÷ô´i¢ïµ·97eJlú Ÿ¥1”ÑÊžx—ÖêÈ—`ÑЦ„¿ÝãÑT|B÷ûÔ"mšÿƈ(Ç“ÃÂ¥Ø=¶Üæu:ãÀ¡÷k룴C:§ÒSy¥èõÒ„¡¿0Ê·&ìpWÖUŠDVÉ8)CÉѤ6=É–’5ù~Äajä¤~½7‰~ˆÃ…Ò¦â8ýæ#v0 -?¤JU•yë2»;äj»ßƒ%:¦¦Äÿ´]GZFá ½d2N½Ò±å¾§ëô£Ú=}‡ŠæOáñÕ+`ŒS7æ]ëëÅv0˜U‹ÏÐÎz*þ9[nÉŒMOMf£ÊŒzÊ–—ÁU¦ýGSÁ÷×vx;+ÿm#ð/ì‹Üáù§l_WÝТ®ÚJù¢'…Æ Ü!¨çOèeGö­] CÇtõ*»««mQ i£ÒM04;%ù:Ç(êôþãÊñwôþªÞJM⮥@šMT’í.åË—÷u®²!Bå[÷ÒžŠNeÇÓ*“RTþtß=æ±÷ˆ¯ÐE>W½hÇy,Õ!ýãv×ö‰ØôhšRn5õÿ£9EƇs›µC=ί¦pÀËíÐ%|’v:{Srj:F;{ƒvx«çk'vìÇîÈ’7bÙWí°#PT {ùl;ì˜ïÅçÝYµ‡Ú&—Wü’³}"~›Bã eл5¯¦Ý;i¤ãÃ9ü„Øêù‚ ‡= VçñÊ3É)áœÛ;þÅ)‹ü Ý›» ~³û0««ïÐ`IÅãöãhDRwnh75ËüuJì&9“ÙïÃØ­f‹ÿ ’ݬ“{a nII®l«ÿ¼›ºÈTÜ™oRTYç…cT=Zœ¢Y†›=Ï8FÈÿ«¦~õw´‰[îûý äEX¿Ümùsô^I·*rvŽútªé£Nr7cK(ûì[DÏáh&E·T›½œîk¹ús­á±.©g‹ßòŠx©£Sº!d¤Mâ AâãðaêRm¢_Ï-¬ÿÿ._9à﫪¦¿?`¨Àÿ`øæ€?dø#æ€ÿÉð¿˜*,àÿ0ü_æ€?f¨ü­V½ÎÒñd"i¹ö™#”ì”ì”ì”ì”ì”ì”lJöJöJ6ú%û%û%û%û%û%û%û%û%û%û%û%û%û%û%û%û%û%kP@i2G¨ü¾€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€’ý@€-u>øÑEºpV­÷Ôà!ü w„'‘ÌçJ¯wç°~ vdXùLW¨iRp.©—Ý‹èb:ªÜäµ¼/¬T‚ M¶Jð‰@N§[8¼N3SK—Sté‘©Š$%höO;K…x޳ß/^JSjrR/éïa«€ž,ï#™d4ê,áØùM:õW±·ŒŸãÜ^a‡ÖÇ¡8h;A:¯aZ¯²*³ÿæ=œƒ*N·ÜâþX4‡< ’¢>ÇÍï„X䮿GEˆEõßEj?XË]ï±{‚%‰ÿq·ZyŸV-Ò?ƒSýšF‹Ûä”›íAmI·rhí:J"ÞXý„%&´ÅàÙØW.3/¢%1å”M¾’ŒM¤õæ·xµër±Ó·Òú:æìµþ«»Ÿt+6¨3Ž—Å]ñ'cùÞ%K%3MKî!gsþÉ®œò³XÛT]-Q©$bNˆSnɬ6Ž”¨ª¢^ÄjÊݼ\å׺ÃobÓ7‘Šë—øÒêr-…¡GPwp*"FUI^N­–ˆ³6¢ž›jéò©CJ‚¯…â©øCŠ”Ñ)`¿þˆîLŸa¥7šSêÔ½ô¦JúEï} ˜ÏªôÃÚ­/hmŸk²ó¤àËIuJª­GyL»Çȳª5IŠFÛ'8ô”GÑø „­~ŒžŒi•á}ÔpJDÙICaÌí²!·Wm‡û€ˆžI£ž¤gÇKæ¸+¡ÊŸ%ëp›ŽORH—:ÏÁ>mw…!y«|ÍîÞ®Oï“8—Óé´»wŒ“(”;˜ˆæ¦IVJjÍlˆŸ6Èq»»§mÃù.{«»áü_tÓù‚-üžÔ‚øˆÝÌj ý€mIòç8[ìmA­£Ë”½­å#(iG×}¿½õR¦H-œæí÷ÌtÌQìϤ§^~Äû3x©ÖœJJËlÏ'7&0‹iµEÞBU7´#ÏrrÇ#[ìðÅ¿‰Àá«ù³t|Uå}w=ž ZÆ~éêB_¾V…v;ñ%ö¥ÁèÓÝÛ×x_ÈÏÚ;\›×ä4î–Âì‚-á[ߤáŽïó=åêw¡ò¿6*sP™ƒ€’}A’}A’}Azv#”¬o%û‚%û‚%û‚%û‚¥ò;¼Ó,s„òæ% TUK¨}übX˜‹££1G¨-t„R¹³a@37ŽYŒ9Bɾ @57•‹ Pª¾<‰áÊ¡ZRMH„’}AÚoˆPÏi„z¹"”ì Ô®4„Ê+(¹«•\”ì ”ì ”ì T(Ù(Ù(oeŽP²/(P²/(P²/(P²/(Pò–Pò>0Pò>0Pùb%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï%ï¥Í¡ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}` ä}``kÿ.ða´~Cßì±=<-Ôÿ¯ gsÑI%q¥Ô¤-»3QþÒ_?Ãö¤²Wâ4|ÇÆ´)Y~ÄîÖÃäì AŽý^~Jlõ|wI5"ÜE7ÑHDs·öŠ}Y‡Áˆ„—Œö£•·ŸÖ|¤g‚Ø!c)ÂòÅ›.”Q)„ÃÇé“ôªgc_¢‚ií]gikÂ#ºÝ^söv§D&=êXï•Áŧ‡ƒ;Å–©L:–ˆçu8d‡ÊÃXî'És"©%ãmp…u:ßótŽžŸ!ø&ðÅÛ\-úŒ. - íÃküA=Î)dŽð¹Ív½ê´]ǧG±d¾`@ɾ`@ɾ`@ɾ`@ɾ`@ɾ`@ɾ`@ɾ`@y/s÷B–`ŽP²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/P²/˜ÂÎaÿÐz~_åÑ?O×;|z´Ói~ÿa¶¾°yyœù÷F†ößñûû÷ìóÿáBÐå–-A!vH>ü@àK­[ý8ÂÍ;|W:aH³ú‚s"›h×.çø³O>ùä“O>ùä“O>ùä“O>ùô“J€ú‰µòûµéòŠB" îW¿gï÷†ûŪþöüjµ°`­ž9MŸ|ºpÄñaú ÝM#ü‚âäŠë+æ“O>ùä“O>ùä“O>ù´ùô6ÙÚËpÚ'S;‰<*¼!¤ˆ›ø'±¾¤ 4¥6¿‚ ÛÖz\Hìð:ÒL—K",Â0šˆÐÃl_¡tƒW ßx?ÿr>~L«^cKËÿgv©Zœ<ßü<Îìÿ3´Î÷_ö íñý.­iÿMüîCÒþ#ëµÿža¿ý/éïÿ”ùû?_„ÍWЬú!ˆÓN<íßé9ëoíçséœá»?²ãz=Úà7±ö?þ^{¹u…¥“Òzßüi}ÕG¹Óª¯úÈöRÜï½R‡ÉZq|òé'Œ:æÿMõûuèÁü÷ïîœÿG†üõÿ‚P»ÿoYÆî­À•®ÿoÖ +Kßÿ×'Ÿ|òÉ'Ÿ|òÉ'Ÿ|òÉ'Ÿq$%>Øæ¸û²ÿ¯w߇»|Z}èœG/ ‰‡»?í$}'aŸ|òÉ'Ÿ|òÉ'Ÿ|òé|è«òÿ½<ß°êfÉš-W­’ ‘f¹V}$»EH“âi!bKé*(ðÉ –ÿ龜6æÿ«œ}Ã"T·š¤°KÑ-ÂÍ•EK„àðÐþ`?Î J[J|ßW} ‰º‚¶ü‚'Fwøq£¢‰žè!aö ¦´WK•U¤º*V†X-ÌÍÕ­¹Bóì†[þ?ÅZei¡Ú˜^¬—Ol®ðÆý÷îÞïûÿ\:mûo¢ð™ÛxÝöÙë·ÿ… íÿû=öÿý¼½¤È*WÚ³ôÿÝÀòñ þ¿§#'þý‚;In¬¼Á«ÛÿØO˜¿hçø ïÁk:Ÿ¢[ï@ü­Á]®Ÿð}Nî:D²›ðÇÚBðU¶¥Î8úw‘=!«ýmÔçê·ã¡¶+ýO¨íŸ|òÉ'Ÿ|òÉ'Ÿ|òÉ'Ÿ~*é4öŸ ùýáá}k¿ÿ±È·ÿ\ê<ÿwuнHøçÿ|òÉ'Ÿ|òÉ'Ÿ|òÉ'Ÿ|òéQA2¬Îÿ=!E_Ÿÿ»Oì+‡ƒ }B²wBÈ~‡ä°=ðÏn˜ñçÿ|òé¡&=VücŽ>ùä“O>ùä“O>ùôP3°‘‰±“ˆ ‘rÅš³ñRt‹gˆ…¸:øº ‹â‰ÁÖù¿gˆžî žÿ¯5š”N0>CŠL'&)­¹ÂLÅšæ³=b›ªGu¹E¹ò‚Õh…áÞCãÄà}í'ƒ÷‹{ºÂCC‚m4: {kü~ñO@϶Øý‚m6:`‹qÑEô’âz|ñ¤›Œm±ãôþ¢'ð!„C†x‡ÕøÌ*J¿Ú*úª§Ü«n¡W=%^«Y«b›«É*=Û\Í/–p1cÍZu«Z´¾¹è'‰Zþ_M´òCqüó\Îîö¿ÿqAètí¿™Ÿ9‡óŸ{üó¿†ÔùÏ€lÿ ˆ¬òüI>ÿì¸~0ò~<ëóŸÙö?>ÿ¹wºÂê# ÛDàdçS!).¦ðÛ„¨nÚùO). ñ]#¾ç¦ù­ý–.žú'ÐöœO>ùä“O>ùä“O>ùä“O~Zßþ³¹Ÿ|°óŸ»÷ïî´ÿìÝ·Ç·ÿ\j?ÿù@ ë9ÿ™_{þó€þÓ'Ÿ|òÉ'Ÿ|òÉ'Ÿ|òÉ'Ÿq ýþ¥\Îæü'\à8 Ï~«ut¬^¨6kußÁϧ HþÁZŸ|Úr•×'Ÿ|òÉ'Ÿ|òéQJÿ½¡óŸ;ø(à£èø§¢GÜ#¾"Œ‰€¸TÝi¹¿ªž—K¥3ç”V+)•EwBFëÂ[/jøEéäó*ŒzûD¹d^׺E—”ÂáñÍïÞ@3™e ùZch£Å”7ìÄ/]ÇG®_qõºìKM×êÓY œYSñj´T—f ×;¹«ÃÐÈ nF‘«]ωÆõ^ªÑ ‘½{û¯u§SÒJzGG{öxC'÷ ïÙ·»=^a¦Ø rx{’êiã)çSú ¼OìÄy«îLbj"K\%.u;©ê£'#³õÚÂ4˜f ÿt(ãºÅé=ÙV*f­X\ªk¡]ë²:š“–3Õ»í£ï«,M'ÿ~§%ya'µ} åK»Á:*z-V¡®ôU(ZN&›ÓÆ7w´±S´ÞåååVz½³wpx¹£­(ÿy¢žo»UÄÜåzh¤æ¢ÉTöñâû"¦ÖžFßÜpdnÄÓFÃ&ÕÈÍ¿å"Œ–TeXð̹aÙ`ø¤ÕJ¯^ snDM ”oÕÈ5Z¦¨Ö!;VÔ26_^„Pt˜š¼\íëß`U»o4М/4Ñ@c‘R.T¼Y4f¬æ²eUæ¬Ú‚EÕa9Í2¡² ¾.vâb(›IÆwŠ¤Ä¿}sž:fa°iÍñ\Æ•Ì}â¯ÊÉÌ´”ºZ°Ìdܱ :¿=…Ï zå)N„òÓ7ij»m‰UOŽ…F£V,šŽ´³6ÉA3Jƒ²X¨—ôû²øTªU-<½´€Ò&–ŠŒ)á>™Õs'•Ú”øäÔãÊÀbsss­Ah¿lZ\±côØ(à‰î}½媕åaÐ7lGFÌ‘þ^Z›†ûi=i`cô$ãÔÆ²0OSgO”Ë9å‘Þä¦ÊÇ‹‘.ŸXÍg2‰Tn:—œLdsÑÉ©_ŸΪ°æ&IÓA´Æ®Ç&«u¢r?$¡V]YPF²Túð†gì­ P$ÀZk:YlR‘òž‘nTOv<}R.“<˜Ï¥3Ù+Ä»h®¹©”ç5Á-+L¼4ÚV^¡Ú,ÌÔ–š<ò­MÏÆò|§çzyf‰&ašËµé±¶T§)óE€zƒéºÐÔ·£]ƒÅwCë¼:¡ZMànRl†¨µhÏmF 2Ê©,Ð]PIÁðdç´Èuçõ¼”+#=XþE3Éh*–Ø!úÜ&pÂúÖÙ6X¬-êù¯¥Pž(ÔËLËî.‚kG¨¶lU¯WU¨7Ätú‹I%˜žJ£o{¬ü0^4­B‰*Ð-áÃb‚?_x GŒàW·Æ3é)š¶3‡™'ŠO»õï 6™ÉQ3q$™ÍeÍã&L2VíQ†ýU->r°Y²fIqæ tLåú(yŸæÊ7Š50‹0$ª*âÅ4 ÞGá7SÏ4´Õk¹Lk 5G‰7zKZÄiÄ:´ ºÞEÉæ§è\GƒAUâEÞMr †rtâ¥=È6+¥Yª+æh"žÈDs‰¸Š£F¦¡ö|æ•¢SµTŸñ~–gÙÄÁ¡ÈûÌ%Þ‡2'&¦ŒX&AÉêZ>¾Ñ¹’Þc@½³Ÿã“Ay 0bP_ØÆ\4ŸçùðÛ¢m>Ôáž©P‡lt¤š©˵úífMKGÚì†I­°ÔœßÀ|fœû|¦rrÆÓ5çú¨A9&G¶ê‰l:Këáñá™È8l½‰¬ÁvÆuç.šûË %5–¬j$»‚6ÔB,TŠ?âcNÁvã °–š–T~ÄiIÈ`bç6ªÊ.ZfcÑÜUâPÀ•Y8Šìp„`$288¸¾ Ë+§Ú:m°‰! …©Ú’ç½d˜ñ +Æ|á„… 4Û˜ç~r–ua7D›,«3Ô($š«\éê[eêŒÃiµåN¥XY‚5œ&×pÒ3;ÓëH+ ûU/ÝäÚÌ.XëÊÍ6Ûr[˜÷®E¿X©-™Ëm?Q+—¸#7°öÁ€È«èb¥\¤Ù\Y´ ÃS”Þ@Mƒk¬æºÁbÑl®û>ÅZÅŒfÍØx4Óa«‚HüwšvmE­x_á›c ¸·Ã ‹Ð;¹Ý? ¸y¢ÓÀ“U§e§íIp½G¾þsÃ{wwdƒ óµ-tF¶Ó@ºd,‘žLä2GÍñ$­b™ØøQS|#<æè•jB1g ÔÆÅ )‘ÔG›Zl*ÌPÚZõ e¬ƒ´Dª0öK3|KY‡Ü41>¨ßR¹ŠÚüw§U¯ D0Àxú6šËµ‰ç,•‘Zí¨êE³6s-¦ZüµNb3=¬=>I µz s" â…¢ÖŒ½…3]ÕÙ)"«ÊO †ÔÔ*N£\ÒÏi#W¡ãI~®Y[¬UjseÒ½aa©Ô°ú÷5õ4m`~p’nYÜÁM5\®›´ BÌ\é×{q\çcíyÍÓ€òÔ*D“© ÒÏ–hÁŽ˜Ù¥úlk¨EçáX­RQ¾šz¢eºm¨ê÷V·®äAÄæ„½±ÑJëDVë®·€Ôi[*wD-èÞ€çpŸŸS¨g0q!Sýèh%«QžCű¼¸¼nA×ËzªVY™cûoÍ\[*6öJ¨…ï¤Ô;»àš.eÒÔé>í”_ ­“ðÞÐíÀ¼÷µÑ¦…‹Äo²P#Ó¬§?´ËºPõÜÑõø¥°«ñÔ«®wtöz¼ §••A•¯jBOAœê-ð.OSù•xcØÓ¤PZuç5¹#kÕ%ƒIÁS°Qq’ {ž²¢ÆÙª¶Ñ¢G9m±¶Ë¶ÊªÞiMQ!ThX;Û†³.*ÏB+:&ï/,@´x™2ž¯•\/rÝ;E!KU!<*U‡ÓªáL¹RnÂ>¦[ÙÛÀºê#ëô²ˆ·këuöŽ¡²_ç­6(~•-K'10_¦¶«çWôú6¾YI‘|*‰ÑZ²K·9šOÅrÉtê*ñ¦ +›Ñ¾$2ó˜rÿÀòN¢Ü`IBŒ~Õh¦\Ââ¾³¸§¸szŒ¡Tu›gïù7X†Ó»îÞSÜ£Quv!Š4ú<ÞvÔ+–¡Ó¦>Äò…¾Í–«ÛË‹‹¤œ¹k¨Í"¦.r«òW®æxìµ¶÷à`¨’´¶Å¨",D) ¼ò—Ñn2j3›¦íá€òÎ&HxB†NîÛÛßY¨ÓXjÎ^sz3êƒ%aé\'?sж Okð<«ue¶Ñ)Nù fÖóÈÛŸªôe§¯´·¦–±&¤u›Æ÷5‘cÁàèFGƒHf®W'%(÷ÑJ£䪤¶(a%àÝÙ*†|©M®gíDw´‹†¨µ™Bn­SÈEFû÷G†G†#×ìŽ\3éÝ¿ïì„\ýäþýƒ»é!Â5MNž÷~ØûÄÈÅУá ãòe"#nO°ìªV£uS?:o+;ž²‘ÒÌ^/TçX¸èÅga††échèÿß‹%¬÷ÉDÃ#»‡Í‘Ýö>™þïu\:\˃“¹3W”«FïQ¢ÉÉxÜ?09y ›í5•µ#bÎ,5¡,B)§©”äžÜhÒ 4k†›¦rƒç :‘Uæ­<­üAUJþF׆vë7Tµ)„8Õ {ÅØ&¥_#8õJO%R¿(žãÚNâåfê̪ÕCí!ëiÊQ(\f2¦(«´Tgs–>à4êìkÌ–­Jɵ¢ŸËbãé%‹NNº§½ÓÝö´“Óð&öìç-šŸ6f\}z2‡y'à QÚÜw£W@âm÷¨4ÓX•gmgmXSÆ[QÈ[oå”ník¨¥odˆä>½Ö¹’)“Èå3)eÚêÛ;´Ž¦'šk0G³7Òˆô^ÙÛß’/¦!8+eê€àe[®ÐÅx©›nm787§Ëõ…ùéb™rލ{Á´sY/^ô¼[Å×ÅÈ¥ð;J¦r šØ./š=Ö7ÙœtT69–Jĉ½%‘I&'&ŽëY’ˆŽg)¶¹ÓãìÚºîJw¶/yú4‚Á×É|±+<‘>œÈ\%Ò®ÎÃ}gçGåQSˆ%Ù„ç!H§¦2h¦`{Öœ3Y(·«f»a.xëJMRZOAê>ÒW\Ù;b¦l&–à!P¨ÂÚÔ.Ë©‚÷ÞœÆ3Ñ\2˜8Ú)ÍݱT(Á í]½†~Ù~³OY™ÂE¿Vg-Þ*ƒ6oyQ+Ú=µÝ@nôL¦¢™£l­:ìÁ‰ôÁ~¥K)ÿ0³bÁ­¼ÈI¶e7XÑÖvm£ÍÇl=#»W—Ê™7 ®3UvfoÊZ6Öê·÷^»n¥ 6)Zêþ“‰L޵ê *z­®u6ŽPz<¹˜§<›5úÎÙæã¼¦Rªªtµ¢¯N£W™ç”Ñfè(ç¥2Ù-G.£áyQ»ˆu¹ø@—k›à;ܻţI¸«_gÞi W;³ä³~÷qŽ·žpç^°îá\X'œSkXÞœ3S8û‘ˆÆÆÍ -‚NÔFs¡¹FBtd¿7’#s™Q‡ÕIl…,é‰ýÿ“÷'€eéyzAvÏh®¤™ñÈ­¥%·¯ØêØ  p©"««§AU5 p°q(ê¸$1l\ ª8S£Èq¼æÉ‘ìØ±cçy}qœÈN'Žcû=Ç»åx“8^“Xϱo‰mùÅkœóoçœ{/È"X¥WÓSEÞ{¶{Öÿüÿ÷¿KJQµÏ ÜÛ²YË ‰·ÿ롊Îj]‘ =üzƼÛh›‘†ÈíÔÔæjß²S+¥¼Üm{'€rC/ Z¯j™«QEá+q)H hht—²á¸^þ¤Vek»Þ€5L•¡Í·i׉×€<Ô‚Uô'Ž Cf-8h‰TMÄü2»jN†¸q¸Á²=CÜ.ë*%^•9¸G‰³TäŠlǺ:b¢å;‰߉=Oˆj ÞÁK>Ëv-¸jѵ±º<÷>Tkä¹·Á7ˆç^åÙhè[â൴¡Ú±äKµwfŠÅylCŸl7ªð Xbðw<ìwûj‚ãÖÿÄX˜šR\…2 Kó¦OÿýI…’îãþˆÌ R‚݆ZõE%ltY•¯K(  *Mx²µ³ù¢¶ \uR?P¾Âù%¼üX,L¬KvÒL!_(€ÔAnk1S¢%ÞÈa–‚¬†ûýSQz©5OgpÂÒ ¢Ø¡}×ÖÆ™í]Å‚•X}øZÕº(˜BU¬™Q¢‡îŶ0jV¤7îƒó/ɘx°Kvä°=ìLµRÃ.@¤r´•丅²b¡nØ>=CüÁmÕÒñèt<"¿ ÷à-ÏÓj´Î· ´HÛÉÓ@eŒh6ô*Ú·ŠR­`I5Þªóz'ó)öYŸ<¦Y•`n%j‹q9;‚£S.:ÍÂÜ!Ì¢Oq­¬‘­^°ƒœÑiÍ¿tn]”¶sç ·Î;P¢\lEÑ]C•Q©fÑ®*­³µN“è¹ =j‰¤üZÐ<È9—E0nlŒº—_1,]û.9“F˜åמr< q'®öó‚­Hå´Úâ,<gó¥YWm<*¹Zž\&œ‡±®×2«‡PâIÓ‡˜'§£³¬”Y]ÂRs.ð«ú7õÁJÐ@²µ ¥ëIA“¦pñÇÇýîGã€JÉGÛ¡N”l¬Á¾Ç¬òÞ‡•GÜë~À£âz+´óƪRG¼*œ©Ý¡ºíò3Ä’Qss8,—©´Uz‡‡Ñ¾XeêŒÉê¶Å}2E ¢)+íX™…¤çM„wÑ‹ÛlºY7¯Û‘o‰}É9Ÿ¡>E*•¬ow<|™à/P_’v€¡¦1.ë2 CdS€Âôý¸{t JOµà*•)¯N0tqbà©®D õËw*ü À4u`›S|œK°Hº “Ë‚a@3=2׺Öå:‰¹:;˜¸¡ÜIâ2ªCâÄN›v·`¯?ÆK×Ý(´1<6¹‘G.kŸ'8háÌ@ǃ^ǽÔüâ CÇø¦1²ÔÒ4-üèPrõ™Å‘ôÛÔúÛv™ÈÅBúÄïöˆJWèôÁ³í³¼O«Ö®Q7ßÕ ŽjG:驚 ì¹af[y§U߯֔ܳU©µ¬ zÛãÑN9ï|®L9Ü ^ì`ç.S)ôKö6u쟹—¨Ïè;ÕÊæF3i»±ð¼' ^ï“…%¹tèÊÌÔ=Š2ŒÈ5FjAf—¾•æz£ºfÉ™€ÁzÒíÑ»g·s³\s‰—¢öò¶wŸmY¦G$×6[åÖN“49ø),!ÉÅåÆLº£ï­E€b¦Õ°'ÉWð\±³Î¦~È™û6°mmÕk­{o8ÿL#ðA qÆ>µ¼î‡ã¬ƒ‡üò5`»E9K+½Mÿ¼ãÕ*òþI< ”׋U¶CE_t§³JÎTö›ÆGþlàø©/;9ƒ¹üAoÐö{jRŽ~z¡6k“ÛWHœc†õ)‚j·2¸!ñ ³(úA³±±”Y5ïMú!Ÿ_ç¤ çÕéN¬3Ùò•Fq„WzDP´xQ«”¶Ìâæš z°ª»ºãÛ;añ*ÒTdµºîÊ•óξ’Ÿ)½®Î«Ïl•›­ °4÷”«­O;?¡QC±W™ÞàˆÌåðƒºæífAJPÛÅÞ<ƒ4!‘ÜŽ —Žt ƒz½øj”†ï†=¸V(‰¼}<ô»_adtu䨙ÿnêºG³“‚‹”»yÆ0lä‰ñ) hãS¹¯Ö9¼Š’jŒ$B¬ÜSͧ=ž˜ú~KqWvU2B„‘và½ð©¯nÛ‡t¼ù'èÍ:L]½+ÕSeºo&¸:sá09FÇø™¤Ž‚Ó̹Y“(ÊgØr»Ö^uGìD†Yܨ#p·^]튷à&;‚ÖµÑhZ—¶åŠÜ2—‡à Àµ¶˜éÕsÚŽ€hA-uÛÏ¡yh*ô:Îë—hápÉF¸. ˜Ÿã-åï Æ¼A %`H·ã çŸ†Ð!òq$ /àn3$Rá–Ç·‚ÁÐíG¬ø–,ßG½ ?˜rw8Q"F ö­¾Ê^™æ¢RWý7Ssß ïÊÝÊÃí7ôVœÆôX”š_ô%õ»ënF5pYTCµ ë¤ ¯%å÷@½22y\õ/­&)„%3!NW¹apDh!C(K— â“B2IÈú…©5U”*…‰× ÿY—èˆ/.€é;ºe(?møÎuÖBãg«%yêkrZÈÆ·ž–umB¯AC•»=]N€yrGÆyÐîľZи@Oª«Å¥Xñ»cƒ'º]±¶Y?œ8„rù0F¡·kƒQð¶’˜ÿ@Ç¡Ó×½ lû§z¤ÀÈ.&ÁáÎ}©?Gàx¾ÐÎ<íø\K$óH @«±3#„ªæÍ}ioê®(ºhÍÓó—ëTíå¼¹"ÌS3fq#<‘œax_£8Ò«ùFNãÄRþ®{YzK­gߖƧOÞ:{ë­täú_p_'ÿv4C1žAuíÛ_ê¿ Ýkr©‡_úÒÛyõ|~q ¾ÉWÂó»À]˱¼d»­B¾×Ïuöâ•^Ö]èEýìÌÎüÆTé»§R½ƒú4TŸ¾å´´ëˆzN†jÜkÝ«ÔÌ} I²éf_ÙlV.™x³u®ø[·RÛðªw\¨¿ «Ow0rwÛ6É9²N†ãöȦ±úÝBÒüª“g8ÄPdû~£=\_Q=ŠA{<"1Àí’߯;_6vï K¨¶áµžÁ5EV@÷ýrjQÑo³ŸDpc²Ã´ÄÒšNµaUï¨]Yðž„5` :Ö"Ò–y(ÌÖ†®—U»‰úu0œV-Ú=Ìé:¦T‹&²:³©O¦æ~5ùþoqiè÷»îZw„'ÍÃzcuºtG‰mç(¦q,zßï/Üd EáÂ=¡I¢l´7/}¥I6ÒIÍü“Òª+>…p½ûÕʃÏ;ÿÉL„$ z»š!Œôn ÅÓöúk6*ÍV£ªZüF~½¼QÙs­ò†ÁɸìIÉȰGrü œ3 ³ie—«Ñ¨JDúuBñ5 a¨2¯탎K‚ ƒ.2dù4zP’î-rЃ3,g?˜N1+诨.uºÃ-yŒÞ¿¨,NÉS´Ëè·²¨!á®ÝJjŸ‹ÍB5¸j΢†aeãõî”r„Š«,zBªKeãaÝôÓL²’÷ÐÝ(„¢ZJpu®Õ[(‘6n$ä ª—]ýÉH/ˆ]µqxÊZµv·¹‡Ç?;’xÑÈ£2Rª‚5„£R0KûU¸Ñ,eôÒ•òͦ¾À&ÁÂPP¢¿°ux.[ö¡­û¤ÈH¨ð8TÂTñ°ˆ,0GE夨+‘ÿ_l„ûƒ±#GGÛàJ…˜ î†û‚äÙ´Šó±ÃóÜ ÈÈ òZ삳÷gJß­1ÝÛ›;w«€éþälÄôÅÏÝÈo¡±)@Ìio|a&¢¶Î~9‰+ }#X]PþCz,o6»C¸Ëk}A-[•­ººØPYåõVõ>x–7[õFùnÅ«ÔÔTlT1dÁôSe©öûƒµ©²³$›"Ëzó¾é—ËeYÛ,¯x¯¾Y¹|Ã^zùkÜÝßz„½v¹,WÊéõô2i¯€z°³‚ÎíŸÎ”æÀæ¾Ý¨l—½à¿xE–?òÀ[ÏÀfA²RR Å9c?¾À3i ’¤»‘‡¨]Gü ƒäΗuu Y!Ù20®r±+(=óƪFÖYW¢çDõ(ùx{ñrIÚ0­U•h­]t†Ôgú‰…vðKÓ äºDÇ*¼Ü5ª#U‰ª¢Dï¹ JÍlÇ ©èZÉç¾0q¶h|Pÿ UŒ0ÎÍð1ùË¥%ˆêµˆž¼L|ÒÇ´û×Ó(t¾6»]þÈXKø« 38e»{ˆ:1€hôÅ)º£‘ôvˆJÕ Û‰O²¹§ •ü.nŒzøCêc„c}Q#·Â¬Û…ø‰ Z2¡œºv¨T£cQãóÔíXsNóÈFO0ó˜#ÎèÒ@¡7•Û @€jãÅ4(@Ú;·@V$F­ÞRãÑPWO<6ßDsX¸@¾Ú¡Ïc ÅÁǹ|I Yã»Dð‚o£o’HiíÁi@šô ]#vM²åŠA•ÇŸÖrw&m­ 3„Òð0µõ´ Íz§² §Î£ö¿OÿLéM´7ëë~ƒóíŸ6”ëÞ­yAH0&î^‡nòÙ%ã¨uúw²Ò7*å oWÕXÞ¤‹êçûÛj½Qm=Úó¨*ªcjv£\æ†é'Úý!n3_ ndd÷âZ5#%TÇéxx: ˜Cí{Ì ìëB‘Ü0¹`ÍY¢êwùÂÈr<úhž!Oµ¶3Ƶ®*ëG!»bËÜÑøàY»7ÁŽá9ÉöãPÐÊBfœ€sXäÕò…KO# Œ@uÞiÀÎdÚ5²bG©NòîB¹:Zq=Þ…å7 $ê’5.Òëa¤Û5À•¹,È’‰&QJ€ÎìÜ9Æó/s‡ÆThÒŒTÕéªá”›ÈØùj…Yåü$ZHámÇÍJåšë‚÷Ù‰^äçt VÍ–áCkžì¹©PYM,Ç—†¨ï9ÅÄc~«EùØd·§­ºA~ȸ^»Á,œ‡ÔÏ®ôs¹OÓ¾*Ž–Þ IÚÀ‚i'ì ”<™q±Ê¨²æÎæNóžä-a(S šÀ})c¯çZ9 Çe¼G(þühÔÆÄz'NTàê l™Ã(—0Þé0‘ÈÒÇá©TX~ûñø4€3!@ÀU#é†,hÔûj}ŽüÐx6@j7ìû§ê ‘V¼æÙ·ß8'±¥/[ìÓ@11¨Œ1Ѳ‹ªÒ èǾQˈ‚‰$:4Á`¹;ÓW¬¶¸i ÇvÑ $,×ä#ÊðdÁ„ë;XT«½ÿh ñJ”½Â%"éK>Þ‚ÖŽ{ìÚq¦weƳ'M;U ÎcWµR{ãôE£–5Óѳ%2!­Ù,3±5iظnaÒÒ¯fýàg¢o?TŽKi,›¾ÊÒÀ̦ßÙ~ëé&æ'µŸ?»c/mü”ÈÒ¼8«%^‘ 䈱QT=çyƒH7œ»}x«½‘P'à)Í} pŸ÷e“ šµ@ݬúäWoAQã2}d³Un´¼V£\k–‘k‹x²¬2!âú±.ñ2åɾ ¨Ö aå8 zYnë­ïÅVÂÖl•¢åÆ2&Ÿuóô©(&³ÈaaäPyÏ9 (¢»;¾SS—žY¢£Öòq¹Ã€Kæ)/’µõ§©]…XQàõCdKb9ìÓnxÌ ]Ü( ;w9]Ý¿bMùY»… ¢‚BÔ¿VP{ªÉÆ~¸È„›nø¸óê‰z|žS=7·“• A²Ï}*ÃF\i©£×R[`'‚Ö–ùX³@ÅÒ6óÇÜ,`Ó‡ýKU4$FFDò)¡:Z¯‰ÑqÀßë«ðë%EóØP°NuàÕûf×~n|å÷#¢'ˆQ²·ÒÆêé•Kjv«Æç§¼ ¬/äò2ÀhÊ$-±^wÄGp¹ã>K.Óè’ÑC9‡å¡œúçD+’ËÖl¸Í¹ßñØR·o oÖêâ®Îlà¡9sö=+2Þàæ&á? ¾ [²Hƒ µ±§õ¬°¿zUËpŒF¬tZ5cí6¹Ð?T½HÖóȬíFv€PLíÀåk¸RËš½Í†„ Ôç[]8å½²äFF³ùˆBñœŽ“zåïÎ}؉ˆæáÖæ›NFÛw_ªfžôöGþð•Ÿú£c #Ÿ…cf_½›`éÁh£¡Ñ0ã/‹E‚8úG»«*qA—2>õL]"„Âa¦˜ \­–à#¦%W¨ûTÌ™º­ÂÅ=QGF¼šš[·Õ7Ú€.óÑH_Œ\>!@'‡çC`åpuÜ++tè´ð^ªæ’ֱ骇¤€/™h9 »ê,Wç«õ-vïPŒ l ¬1m] ž¥*K˜žÌD¬..ÛV<ÏLœô{þûï¼ßn·ß{÷àý÷:ï¿÷.ü߀Pïúð÷{Áû‡‡‡ï½¼Ÿž‡À3Oü^1;}Yç”UºBYç¶p…Âüw;ç”¶x~i\Æ ]’2¿t×}YŠUÏTJêÁ9Ÿ ¯èµÎ{½ÏmrŠ%JqA\(“œ³³¯,¤JoA<½FÜ]š›åû•׿¡ÍuÖc×þ…b´[˜ouôÀÂëŽhéRг8ìÞ%¼z:ldop$Êœˆ–ôªF9Šv×V2BŸð«p%š¯ÐBôçAÊ–Ëš–€?>Â+sï>¢Ç/¨žõÊd"g5yiI°‰˜LÌׂ$cZcŸ‘ Hê] Á3ŽÓ¦ï¶1°¼º-•€æõººŽRX¡ý¦©[A@R£JÖlA8D=‹Å|u5PõA¾Ì4?Ľ˜0JÌa÷8t/Òd¤=•ƒóăL-ŠÖ$6ÆGB{qBíËÔ)¶‡Ö„º@mØ\¥²ò œuYžvx4ÑpË[? ÑGü\†§¾4t;>¢×IïƒX¦DžÚ†Yu„úJVQ€ÛÀ)i÷YN-—–޽ Ô5R$­ñ­¹Æär.¶sÊ# ‡#G9§”â9Ù™S¥Ï«}ã³h‚gÜîfýnóuç§¢ñh­wô€œ+軩}W͆@KUhô8âã„=‚ jÈ **Íõ!SbÅÛöNãnÅ®/KRÞ»ÇDü¨i.Yۄ˵T§cµËubë “ÁLìß‘J—§Ä€~§ ¶ÎîW‚ ABâyUÁžnçÅ%¢ÜºQZ\YXBó·ýv™ß.,,Þœá9ZòôFm¬îÞSòáNÊî¤R?\J£i»¾ùèn½ömÎBŠƒeza1Û %n⺠™a“|ðáš„9bDš0|ã¹…ILl#7ÑŽÓ§c¨F]  ÒM(0WGP# F ¬†ç"±­*ç“°ª«E„Gø>Çh;!€N=é¢fSs3sÀnUk;­ÊοmHðI”Éq–…nÂC£*£{§Y ÀØÊµ¯nÆÙ¨mi!?ðŠ…ÕÂÒj‚aéZÐNŽ3ëü7Ni^õÓìFùÑÎÏÕ¤~ øq>鞣×ï[ÃÇ/Þø¬ó“3¥·á»¶ªo:¿Òü àŽÏ*¹.Û úêóâO&¬ì¬x¶v7’îzB½ ·3û‰_ç”Þ¼šÐ¾Vk­úëÎýO˜žG̼@BYÙ,?ªl0]äÚ³ Ê™ö€é¤a×¢D_½_ÞÜ©4U^üák^æ«x †²î”w6[_ÃÄÙ þ¶çúpÕ½R ðëÒŽÛ‰º¼—«aò7ò2Ä¢¥TâHÅè& b*iVS ³Û”À'€kKÝɑ—ýµQ)tìë¸Ã‚õµ¨®ÓÝ Æ˜æ3픋´SLg ¥‚àÖ#Æl‡½¦FïY_†3=öEL¸Œ Âíh2n9,™¸öäö‚ˆqzN:qÑyN(;ô]Þ„=‰Ÿ/¾Ð* À5.«æ¤rƒ~®3fT´œ5Í‹Éä ÚÄ„”›õ++·7A¯Ì7ItR•c_ i»x$<ØYײ!j 3fuØ[ DÆcìê¯ ¥³!µ¡iÄèì·,ÕȾq:ç&“ü:0gŸ©ƒ1 -¢EŠÝŒx®t‡Qö±0ë~Ì~>øŸbÈ)Š1Ÿ¯ªHRaÐLJûĦÓfw׉œÈÜ y[‡šZûKîTpe‘…îÝÖû‰÷ŽW”ˆpª åôn1WŠ ?T×Ë‘{LòQ‡üë™ 4Ò´%éýd>Kqn»=õˆÌ{wS K-;/"x`â`ˆƒñ©s±¯˜H;ÒÈÕ“}êKjSù¸Z¸B®Ô'~û\`O;;ÕO;¯é£ ~ÏX"˜Úñú]<Q‰n²ªás^’Ï[ž0vðwnCÍÚb¾¸ê5‚Xè&ÓºZ s^¦ 3±Ó}æ•ç½õrÅˬSÓò©ÖD„n¥ÿ¤;àˆÍ{M–-Ùq:>èuÃcÒ€º® ôîBDu˜–õöh2{qe军Ù´9À&Iòë7 ËYÙÄž>}š‡0h=?½‹e·áŸð]UŸ¯nï¶UèÀybNT_ ÛK'•.ªo‚’ ‰šÙ:)L3Å~Ƙ­§À6C¡ žY¤¦Gúùhɱ#/n[[„|BPú‘‡/ù@e‹`Ø’ÉŽÁI»½FÏ’’†UˆÏáÌ|¯ïK7Õ…k$ߪo74>Å®d@§ºèª)ä«ãº£FïDM%Žç‡þ“;Prmõ'×Qrõ‡c âXx:Qý®‹ò5A’æè'BµožœæuÖÁx¨Ö'7›‘{YAÒãaêÃaÔí˜ש”¤dà~áT¯ ú`µ?‹Yú]ÑñÏz°W)Qã ® ¸ä˜ötMs(ÖxµR©x7 %5 24¿»©¶˜æ³¦ºuÔ‡›âB5{GݪYA×C¯|c¼ÖÔ‘±æÛ°PéƒG³:+01ú”ÑVÒ\žêèà^á±úãq¾*ç°óÔ'Êš!ckÐr­ƒ*ÃîÐöñÕí¤Rg¥<Ðg67+•íO;Ÿ7úZxQ‡>žØjXš½ 8 ½Ì)òçÍŠî!!¿‰D±–´¶-5JÍ Õ6O×-µ"‡ãS4¦X|(E´W»R‚8Éx)µ© þ—àn{8àf}ì˜sfSÿZjî]ŒI^¯Õ*'Û¯n|Æù)­a‰¼ÈÄ4l–Hï¶Q€\ghy%E(ð†g®•ç˜ØöUV‘xXÐñÕÑxdC5ÂÎ5B†€S¦ä80†›’—ƾ=J\ºpãæò¥ù9ϯՙý¤;S*€n“$ý×?jˆ9œA˜¦žQ‚ ßbHÿÝ/îT×?TÿVïÖêÊ^44 éLˆ9}_ ëSêJÃ[{ÚÍú¹UmÁÅlO¢=×Ýj÷+5)â ±›{Ïv{€ß ³5=¯ô.¼ð#Hw4EC"ýsqk(žàtÍFÌ09†´OsSmVÒ¿ w'0® Kd¹W±\pÛüD‡ùÙ@E|’Ñë`D® j_1_P\ ÕWëõZËâ!ñ2¡Ö4­Ujë÷¶Ê÷擤6ë€èôæ QF&}§ÄI¿Õ"Ðj/*Ñ0Z8(>0¥’üXAe¬£zʪ‹5 ÏBΪû¦Ûw ¤Ó±îY:“¼Â´2Jõº'Ý‘Ø;M§ÓgXá‘¥‘fœLZ4Yu”((‡Œ:tù¡Ú>ÂóX߯E[Ý'($—¸F°E—u×MV¾;Xp*RâÅxŒßŤs­¯%¾aÞš`ò¤”––X|f4HTœ¾‚QlAPÓ«­V(ꕵ±rBÝUÐîšl–+wr=0ËôÈdS×!÷,òäúèã¬qmä« ò“©xe‰,G×^ŽYvÚ¢aÏL47q*ˆ À]BGX¾ˆê´cºec%zÑñ¦ÑF½ö…z{A6‚Ð+@ŽOK!Ä«™ÎÓÒô™'5óëçŠ 6Ô–´ñŠsO˃ø óp>ëñOÙ GG;Ž–³B_ox¢2 5ÌÄšu¿½#rq|¢ TIÚ¯CØ ð1å :G°ÀA_ìMc¯ ÇîÄ‘#!ÿ¢æRØûŒå- w?øÎ‚ñ–ü¡0}"ª°íä«$Mƒ@nš$?ô4dñK`w(É‘›õI75j`pA¼-_-ãìÌÁÌÜ’¯ohU·*Õ;wÞP§Œ–<‹mBúñ|t{ñr¼s°(ÆŒwLñŠ8!ô%E$¼gj( ܰyk‰ mZB;Ì K¸‡q”¸ëCš¸±óM0DB)¬Šê?~€ÿÒ¸;úgRj„±Š1ØN:ï^Ðæ:òJ «K+ê?ÉsaC(SÁÃæ¨ÿ(S)ÞÅåÕ¥›«K7ò+øçòZÓà‰Rßî”–ŠS¸0·*[³Îr@!zGIã­àÙ(óôñh7»=%›Ué¤÷1ݪÑDzüCvy˜|Ø2Æ!üÑk6ªÓe ‚TMHÌ—Û/•6õS¥€IÚiV¾Óùzù©_%z ùõZìxÚHGÏ7” 9¡¦ö÷験|†Uaó&\ËÀX€-c!„i›’Ü¡’f„‰FŠ3döÖ1e¹Á ôC}ƒA»\ø;ñ늷\­4MÂÛó‘H–·Ô<}“oq|ÕUy$l%—QºB%]ÆTSb¬Ëw§ÌáÌÎŽœ¹›¨3 ¬¾ ¼PõÆ'oÐŽYø‚æ3 h»Äæìã³=ј6{÷ÜB¬ ú8fÜ¥'{ ι®wÞirÙߢžoB¹ÆJ Æû¸{g&þlííHÛIEN ï‹ ±ÄM]„èd@"Îs`]UÓS²j¯-.«ÌÚåú‡pmǯR³0× ÑŠj :˜ð Q°.?;ˆp¤Š4VEƒô ¤í_²ôž=¤©iiàIÃÀD7|Ì>¡ªãý‚¤zQJ:ô{ᤢ0ͤ²„þz-ÙPà»nÑçÐïü{)Q>Þ®C¶Ÿi§J+jÝ}ΆíS@¹×­Å—| ÅøMŒz“ã«'!ÿ‡¶_‰[!óv,¶P¤ª ÷ïœûÆFÕßÈ÷š]–ž{k©ßßìo¬™_«HîŠ^¾v2Õ©žP‚Æ‚ªãÆ‚n‘Zí:Ðt½,f G/[ûô¸™*/¾÷_®'5ó³æVû_ÞØùí çoêK$?Š ÖòtžXuHB ŒÐ'x´°:Ñ\æCr“ Õ¤Ù˜…|föÙI¡Ý©é‰v‡&(ö¸‹=¶G X ‰O l’;cHü2t—› &‹wdfA¤ +I|äU9è½&ŒUÈ0s±GašHÑÄå^(eÕþåBn‰å€ðê !ä=oT¤Éj UÈv/à´gˆD,V2ç?ì’#2޳‡èЪ®Ž>•LË[fçqáÓaã:ŠûÎÏ›{®O°«+©ik›ôW¿4¢¿Ò/2ã~w”•“qŸNÞȯ¥(…øj¤k;0$FtÖj«¸ÆÊÖƒgo´.‰ýÚ57ÿHPGxaÇ4b‘¢l½àÈ,IÈÎiãN‚®%jÊa¸3aÈ”zjÅþót/©ÍÏ2Ü_«@ð+œ¤>ËŒ z‹eá(_@÷¶bZ~YÊ%teq“N´¨G•r3—83þRD !^R®x=çøÌw¦J·ÁV°³­îðo:Úhpàx‡Åf£’Õ?L}^±.›€6çô4‚AÞµaí¶/„Ɉ§ÿôCZµ,å àû(˜f¦}Z,-•¼ ƒWÆjó |ôY‹¡,±áé{Á—ã¢Ð½Ê÷¦]þ0Ƹ+X+‰C“iSˆ[× åeè"˜uï—ü£·¶Y_›—ÖFææfýÖNÌ"10–Üí Fd4ò ’z@庎ØT×댗zå;æÞ‡} tPû;µêCº ü2}ÓŒ¼€}êÙ¾†zÏg½‹^gé xKÄ”¼Ì£ùŒ‰UôŒñì»éGêOnk+§¡{÷V·¶V›M Ï·¶66îÝÛÚj6ócüØø¬G–o<:ú®v!-³Ã( Få=Ž7Ç ’Mi"`kÜnhä¼îRØo¿2èùøw—}¿çšùÝñxз môð¾ÞM¢;aõ?ÕŠÂݲéuÜÿ„ú_¹ôÑr–Kè "ªaÑíZ}ëаäuÓþzc«ÜúzmÔó1Stî‹+Ë‹‹…Rq%y S÷º"Š…Õ…Âjq%~ý:·$ïX%(¬X\( êÿl݈‡^Š–ºs-!t£|ë‘÷Ö†÷Ö–÷Öñê[ÝÕ·Bï­gî•7¼…‚Úœkƒ'BqèË–V°×tL}ÿLé `/ûÎÎ솯9ŸJ™ßÀçþQ©²NügÝ“ñ‰’úG#Œ0Y\ÎÞ¸q#[*.y™RiÑËyÅy5µG€WXcV VlP’&Ù‰‘¼YrI Vëï°ûŒqw–<ÄJ4Ý/ên¯´íNŠ[ÿÁËá8³3ß’šû@Õ;p?ü¤óú€¦'15LõÐèTàC—JN³yNx鲈—Èãë ¥mãÝBqµó–1ìK´˜kÔ1ÿŽ˜hÆm.ÆcµÄá1œ;§O_®Rè»…©Ò¦Ï‚0¾0áÑu¨Õýa¯TŠ(Ô¾Vz£ùºóÙ¨þ— ‚ywpx¨„¬ìžeÆtÚÐD˜øÅ(k"a¸bîâ}µÿPàÐå¸1¨DrB¸úC wen§>Å5èŽLˆ$g¤ÔL¡F<ÎY‰ä’N(»³G\B©“>ÚF K{¢;7 \}KŒ7Ó!^r¸ ŽCE @³PW뀫îÄN×V¿>°rݺ‚:˜Û9™Pçü>=³ðA×}1‹ÿˆ¿*ÀER”$ÚG'Ñý†'êÊ"|æ¤Û‡ƒ€ô/y7zQŒÆÆfûšì÷$›ˆž)¢W-âæ¸ûßú@&Q¹[iˆÔæ±c¹® <ú†úÍmC‰é,Ú?”Daþ2UÇùæ¹Õ"¶ÛþÐÞÅuB ]aܱÊGtNGoñDpÅ;|ý¬R'fãjˆvÉPŒxBqÉ€µ€‹Su™i™cE ’ñO¹‚Ç–/V¢ÊBø‘ØIA­(ÅŠø~NÉó…ì‚úÿ’úÿåùX.õjb¾ôšºÂ—Õÿ×ãA9}iéàÜšM}É™[‡Ø¢·?ç4œÛ®[ùhì÷¦Œ&zAŸýÞDPÑÛ1i7¸N¤I„.ä/™ª˜L–¨PR©cå]Cÿ~gjnlÊýJ£YyÓù5Ž¡ ÁG—ÐO Á?e „üN/sÕ76^ÒÆ´ÐŽOÀöŸ~IÝÀlêý™¹ ʦMX¬Ÿs~µîz‚²©JMÄt~m6bö¼àë×6›·ã²"µ¡øNñâ-@Ò½›)_z†¶l=Uº}H:¥×œàÐO™- ÁÔG%1˜Lë÷Ê |Gf ¼i"O¸Ü¸¢Àú¬ØPg ˜]8¥ã-ÚÛ2Z&+¦ë_«º}¾š}Œ.J©™Û¥»ª?WÄr«ìµmW^s~*ÅWP<Ü„Ä:nЏ-í5ª“8r™Âf ÷óšý€ÊƒFÐÉתÖÁ#Òf=sW%Iw³^» ¿i&KJž¤]MÚ¿ëëhHR€40ïêf 1Ö x”õèojý,Í€ßðCBT!ø4ºžØÇõ;&< JÝÑvb —í{SfÌÝ4A©€\¤€+„=è ćuÚ,³©ïqJ÷K¼žjÁÍ9ÀY˜ºš0™£ˆŽ’[g¦»zo3‹¹Ãd›”ߣ q0óÔd‚·º’¦ÅrRd {{ä÷jc%Ž„ú5—8ûÊïI•ªpñdòN³Òø”Ó×1­ÇÈìêíV7*µVõNµ²y»ÛåfóA½±±ç¥…è5½'Ñ¿.ŸƒÁb°«´ØJ ¬JL`* „Ò´;B·;7‡‰CÙ¥š K|×df¢H0&X Ø” àè,È•g#åK¶¦9ë›bòØ#E‘iC YMâþw…5#atišR£+±ËÍ 9+‹ýЕ«õÝF¹fݬo‰éœxNÒ_‡ÁYúƒ4Äíë×IZX¬\‰Lዎ‰ŠÁ½6E¬´‰bXúÈ—b'rÓo¥M¸a¤c» †‹]FÅ Ur˜u=?JT’ŠÝWɆék*bK’;åJ#“Ô%ÛE)þ%2â1m‹.Iv84QTw.3(Ö×èÙ Ðm &k‡”ޔ܅P¼>Ìu»Ìb`gL «Gcd`öO,Õ+j–WSú鸇lj--~VØŸ# \]c3ÙéS›äƒÆ0˜N­Ïé ‡æ÷‚bc»^­µ¾ÍùÅò‰džeÏ&Ù‚s¢Áã·hñ§~:ÙD”\9û½3s‚ÏÂúN£¡fê>l8Ÿq~¶g[ÏÕ®dýç·Ð åY˜rÀÁ¢“}"²Ï-!é1”‘Púcõ°?¢Ðöc0‡1Bõ£”¢ C¢5â@†ö&ø@\†Ù"0T[…øx†Pæèño`cª•ÍŠúf ÔܨܩÖ`3AXm•Ýv¢Kl N«¾Ðq}ìZSÿhƒ!³"³WÄìÍ[޾­˜B ‘È¥:„´”æÙ?~"NY„DïŽÿI·ã`6ûØémñXCì–‹JN¯XX\\õÊ4‚ˆ«GÐÜ1Ó‘ó<ëµoG‹JÀ³#ým¢Ý¸k 'QûÆ™)m¢BPáo:_ÑW]|ÀzúyÝ.ã>&}õ-Å™ÛRß2óÞíÏ9ÇúCÞ»­>@3)Á ½ê¤·bS«/zïÝöJ×®·ùäR¥Ü©)`ÐëÎ?— ¥Kð¥‡Ì¹¾ÅÛdkÛÍêG%|T2¬)_?º™µzQËuµþÅÄ.Ü:# ù­àr•P‡b)êï%¤~C…Š%š5Úm*ڤ͹.™¥Pu¼P¬\-zÙ—h_e0‹ÇÅ’ÇÅ›ÌãâÒG^†Ç…û#Éã⾘Dž³Šö ÂãâNÍãâMàq¶iä y\x¸ee@‰ÊSâ]ÃíöÓ»±‹«‰]¼¯'±‹£)‰]Z“VƒžÃ˜ñ ',S–ÿB²û7 ÔYŽZc¤¸®.¬òÄkz5ªI cÇ@}´Ök‚XtQòû‚âØ +ú~šG7:+°ÇÅTd.J¨­: å¶*»•ùü„¤íÊ|JœØí¶IVÂ@¨ëÝø2…®•L–tû• Ø¦„¼×@)Šl§FV3LçT}hëª#)AH\õ¸ÇòÛ\Ñœ½Ì.£úæ)n2Ä|‚4*ÈÛk/bR¾AczÝùº)‘MêS üùÓÐX™œTj~®jžjSû&|Îù!K¿¯«É@¼Ãç­e_ \Ÿÿ‹ “”Õ’¬WˆþЦEëITÒÈÂ…k7>ño8¥mP>£Ã øÀ!@ý-§ø‰ˆ3,laäŠí@ŸA@Ò3rÔs~Àtú ~QBëÄF?ÇØ[·RÛ@wF&ˆÃuÂÀ¶­óâ–\&ùåÛƒ¼²D£ùÍU.ÄȾ[›=ŠßõÌœ~Gtu§ 2ÉV&6|Ekǹr9B7Úê!”“‚„IE*Ûò×åЈä¦ÏO‡,vƒ9ÚM‘¨“‹u6| aRÛû hD…åÕ ¹zA›¬û"ø.JÜ«w»ÕZíÍ!ÁZlñÖáF.1ã>ÝÙ¢cæ’’ ¥Ð¸ _å½ø«náI}r::scy…4Í€”X@]Hw4f6sòÇîôD.™T»FÓ]>‹ùõéSéÛ98*¶À[«Ü­ÖpÃl=  ®>F©|Ú×q“Ù¨ <¢Ä“ç¢äÝnÔ×+;êx;ÍÌ»TÞFe}³¬ž< Š0ä{Å[Ô¡O".мÉ=¹EOÈ#^®O·¨éT,8{²ªnѯÏ!v¹C žu0ÐKîäi #{:ž" PŽöÔ–7"í-M¦½6ÖZ nGFùþHâØ38‹e“Øêf< ƈ¯rÒs( ¿•xÁНŰ@±@Kž› ‰áÔ–mz$áX;Xn$B9žx`èi_;(7i ð´Æ‹‰ô³x» ¹Bn´¢—¸Õ«gžÍ8¥/ªsègTVÖwZÖQôºó—µâO^†£“G!fÏžøC~5¿ìÑÝÔ-#¥€ês8p«k'òBÞÑ q¾ªOuU²MàP¢èŠÕ‘Š :ÖÐ@½ú^”|ïê Ö4ÐñŸ€’Ѓؼ u< ƒ |úô…<Ïñ‚ÓÈuõdñ ímÀ¾;"ÙÚðDZÓ•ªʶn§ç»“ŽÁ‹‚²Ú¢•e]Ù‡#Ãvã(Ht ¢ˆ‘¥™¾MtÕäKôœ:f†¸.Ç(Ñ%!Ž' €Žù‹.Y´Àñ¨ã&XQ=ÒE8[ŒF¦ç¬×v.è —ãûàeK_e¦Õ}Ô;©ð²\_&ÏlêË3¥`×ä短±Õøt·^jžçõ;wàß=ö•DO>Z(õšQÙî”SžýðÀ«’ìlVÆèÅK’Ÿ½§(Vœ÷#~¡‹»’ê ó®1¹XY¦æ±T…’ãâ”L]±ŒŽ3ûÍif® ŽD[åÖú=¯|·\­5[o:ÿµ«£˜á ˆS̪¿U* =„y»,ÕÉ•¨”Èè¶Qq*†CìpÜëå‚ξ¹D¡ ùÕox×.Ç“Á²¡òÄ=‰Ù?õŽ:AyïDsšeç.yÜcŽÓÐJ7>Ž·ƒ©Q¨ºWnd½ûåý0`_;óÔfi·­$òE¬—¼Ø~çˆÃÔ$°èïÆ,Ô¬Õ}ϧø¬ÐyÖ,‚0 È?9uˆzHÀ¼ôªÝ€àÝ0…Áq‰¹dÕ\…ˆ¶dÌÁ”ç·iËÔûTI}ïÍ#ÂÈŠÑCût+ÇŠu˜p3dd´*PxéÖ“=¯t@Ꜷ™ydý“ÉJòOÞ•w#Œ¦…÷–?'d:t?ÀÖ ušï#Z“yBP5¼R¶”ÅV¥‘–üU«hzòž­Ô®,Áç‹ÌS´Í1½+`<I^¢ÇŒÓœ  ;VDC‹)˜ƒ†MQLho B˜w" ]amb]Ìî²:kTZZ†qê˜bÕ?å†ô¢À1žLtÐÕ©V"#²š˜ý£±Ä6:ΩÅÈ Ú§0Úp­&ÁþœÞÓ×Ö\²1ÝÆ/‘¯yÌ«Rо.=(L¡£B¦¿4œNH”<¥5”€\ "¼úT¶Cˆ·"¨¾q8ö{yc@щÏà\88 æ ÀçÍÁšüSJˆ^ÞDçŒmíš´T„ š榾Twµz}³R®y[õŠÖfZús?6žàPÅÄ™-A=¿ä!³&OŽKÌL %¬aŽÊ¸_j&¡7ééñÐGƒjˆ”rêsZþäqLŠnÁ´de6r`) ¨£‡b©ð–¾:k ôSAáãÅ ¤¹6M3®Ðã0²y/¾µ1‚ðœN V¤ÆZ•Q+·våMo³\»»S†ØÍ‘a× ÄÙÝ$_ñÑÊTçºOeˆ`(O[;û‰ÆÁ4äÙÔJŒ¤vPÕ[Ú K£%³Ù4 zÁˆz=‡ÂèÁ™´67>±XÐ7_Øý‡¤v"»ð¸7"Ió"™œýÍjéñ`¨üÑáxPmÝó¾¸Sii'EÙ¡ÖT´¤È¥-j®£ËÙ|+@ Kdl¦[?mH²Ä7ˆÿØÀ®!AýîšT—O¦g!çZ$$Àß¼jÖÙÔ·ÎÌí~y­ùŠóUC–»ÖÌ<ŒêýƒPMú‘µN^g„£jœÀV5¡tq "H’[ˆ%Z(]G” ðqýLªtÀDÛõÍGp yðáÚÏv~¯³=èAxõkæéã=^ úÞÅ\4 À»jN†MX»Ö° /6!žßßòÒð7©v³úaåMç÷ëIƒ¶y¡VÄH rÍõòvÅKaÛ? öaoSR§>Óì É\ò‚ìW„£[@¨x¯Ü½¦’Tÿ̦æb@Üíòºêœ_¤;djL£Ð Y¯UãÄ[çÀµÀï³±õE ZŽy ÐO/ïcÿÎÜ#À–m­5ÈU¥ 7˜O8Ò©ª‰O3[$²zkÕ­´G>à²çQ“\é? zêv©Chát9àÔÂÕªnžlØ`íKÂ|*Ò›y˜}4o{AMéËAÉsa¨=M÷àd2J€R<àEË£?–˜ÀúQ%˜Ÿ¿4Ùù9•Ϧ¾o¦ô}À©/´ëõÍM yûmÎ?rîrâu% QÌÞÌQ1{tn˜ìdúü$ª4›¸OƒžÚ1©ß'ìZ(n˜Mp0ú˜G¶®Ûß:· G£¹Ï:?™2߇™]uÃnUkëê6Î\öA)³NŸ“&3 3‚ÃÌò—Þ½Ú{4|0[E(aks˜Må±Nl3úÒÝQ>F<#&au;Q_'Ò …ˆ›V[ðò¥Y÷X¢b"ÔŒI­Ý^Â}„è´AM ê§8ÏΈB‰0R.bwšv)ð4wô:ÿZl‡ G㎑æÔªÍq5só¸Âí1þCÔZr ±WwõmpŸ±+¸uùý`rûgSOfæ¾¼:o¿â´õ¹ó¶öÄaè”[Ÿq6ƒÑ„Åö‡cýµðöRª¼“׊7 ÅÅ…•›K…•śŕ›‹o'žä 1anq©xsiiayéæbiù†úïæBqi¹P*,ÝX.--'(Œ.QGŒ7å²Hês{Bí¯þ:§´§úþSúýšSyUÿŒ’ZÅ—ÈЮ–Gº¸r£@dɲ¬˜övZë°ôÒ¥ÂÅZXq «ÅÅÕ |™7$̲ü,ªòÒŠlåÄÞU¢f›îMÁé@í4™ µ°‚y`¦7uìÐÕû¼uaž\ÄAÐÖ¨5D4îªô¤ðp Ò"‹uñ‚€­`¾BO\ÂïꀖÒþgņÃüs€u.ÞIbØþ(ºÄ“ÙM¸õ‡æ’=fÆqlT—¯Ñ}—iTZÖ„¥O̵3¹òQ;(DR²J%Ù»ÃâG¾†€çJ0{\¢vËÂ׆E×,†ÙÀ·£>œ â×À•0è" ¨Ê\8â-Œ1^G[:*¬n.ê[p›æ#é>`*ØÚÒ7ç!ÞÇïu¿b®6ä¼á2mG7€ß{ÙÃÍ,/¾®—ãƒOs‰M¡~ÂÅY$,:f×Ð1³Æ†IÕ¯õûa÷… -®DÔ6­ÇkG5¤¦$ðyAÒ“~§ã½Sî6:o /›†ù"n,yîøl7>jSó§ê2Æ,f?¼…qè×…|i!ëcækˆŸ›·…±‚èÁf¬G¾Y&ÀADï^ŠyËÒe/g/*ivöŸÎ”¾îó•æþFe½ñh»õÎošÕàIó8Óžªƒ}4ÜÍ*¡~€KüF€Ï­©£zžˆ¾ Š¨Ô¨ˆyŸ#L'YE"MÑmK9¢ëÕ/•,ö˜½ÙÔê6€Áƒ jƒÃª›ÍMAŒò²8°’êNÛïÖ™¦õ]üù‘;»šÚ6Êiö´“m‰¼x×2=e `Z½Ž)TqP›œZ‘© ‘µ¹öíuûšKcì8Ð+Ù0ÌéÂ…»Œª6…©%"ÈŠœE)Ú;t>»õò3B¶ãÆÃÙŠÍci µv»ÔºØ\NmmàÄ—ƒ„.3Lìzv€-{Ñyâ'Æ!˪Ó(r„NbS N}¥¬RùP—cóyzš›á5>‹§§¶ §A|³ aµ¯(d`Ñ¥N¹p “ø.+£[pR§Ssû »ªÔ6F囜ßàTúbRé…±[q¨Ø\YA¿‰ún¢¥òÓ›ö*ÒƒC”s¹°Ò†¾å}Ð ½Û^ÚÔœ)zÅlÉ+e¼…ùô­¸‚4Ä®ú#Ꭿ#»ª²æçç“QïαʻÏ/SÜ„Hrç—‡£–{çþ¹|yÕkëtgvö?œ)ýò…•×ï1\øugoÖ8FêÇ`¬<èQ"rú‚ÈÚ‘'b¯Öp·ýöqÀèûhÂU.ŒÜYv±üçVíyƒÂßÍZ|,z~Ou«l/Jj¡@¦öÀbQ~àֈ͟q?Œ‡Ñb{—1¼%«’J¢þªÒ¢êšïÖ . =‘(°Í¶*°°Ž¨L´FûˤÑt¨NlOä‰SfrDC˜‡-ìÀ/ÔO“ÐÛ (d:ÿÄçW¯ tùQQ•Fݵ?ì«. x.a.±5êE ÙJW˶0]¶+~Û”~dª7KÓcÅr‚®î·Ìù°µX¦Qi6¿Ñj…<ËТ‡ >¸á¡”~´Ñé“Ã>’ vÃÔ–8Ç1ïuhhX`;9U‡~G®Ò•Ïíu†X*Þ¿¢佺8+NÖ ú½§@÷nJ‰FÆE^ßz…ÕïÔt¯LkN¹à”þÉ[uínë^FWÕ¨lWÊ­LÚOg‹ê控mÞ‹³)Çó§Óó/⽎eðã9ŠñXVµq9ÞÂâÒËK"³¯|S:@þaÔ#¼îü5}¬°f!Â0£ÊfùQDÕ»÷&°æ0ج֪ïYçGFøq²tF@¢¯Þ/oî(Yø¹‡?|ÍË|mnÏŧ÷k˜8›Á¿µ7<`F6v¶7«ë ïP'«>¸s¤"äáÑf1ôà <«¼=væ¿ÎoMÝN|•÷Á·¼ôhñý:5[ Œ÷@ïÂdž!{YNFšfESˆB 4“\Â5ë§0   И-¯@¬ˆê `4îuÛ]ð5&›>)R6vã¥ÕPšKåAE‡Ä½‰cË-ŠL{7lagTÛøóiwlNoøq¦£«ƒNIfbešùôÌ\lÉsã³Îç¬ ‚pÄ,Op¢ŒÍåÄè~5ۨ紙FÔ^Ø„àg‚’´ŽíÈ[¾·V½ D¢U¥«Má§Édóc“M6ùˆéFb–\`¡É¶Q=KAXóx™ÝÎmJm=ùi±ðÀvä”:Àí¯\ÛØ¬4^wÞÕòüÈl)õíJMí»å枺~¸—LÓ¨”7l߯ªëåsï}øë=üËSGÄ„°)´M¤Yóö„Žö™KÔy§Úh¶Tm5ðd|çûêŸÍ²zøµ—¯*VþË•¸¾Yþygv¸S‰UßQR`{$¬ŸpÏ!Ú±)a—ÛL®]þ¿Ûäֵ wØ~°±fn`Ó¬bÚ…+äBžñý Á¥V8Î:ÚÙ]„V<}<2x(´;UŤD1–:ª«PC³Õr$@ª5 å^ 5zI€T<*•+ªnú @2Ž¡acñ€­˜K‚/^Œ"KÂ>. (»z]7 lvæ¦æŽÀ£Q©•·ØßûóÎÆŒ Xbž›Eتƒ´²ÿXë‚|ñ%Í»ÁÖÆŠZ¬>%ð,+›øÀ'd®€÷Ià É¢p×¹à7윂w0µñÍ*•»ðý++¡–ÉáT–³…O˜_¢ÒX`öñ'².™pönTÂn‰ú“k\Í-A9Àh ŒB¨®qY¹ŽTŒ¤ Ö¯uÜÄB„¤ý ¼ b]Áf‹µzy|Êí0g›ö}~JœõÑ;òÜü~'½Þ|9^nnEç–î?˜;vû²VFõJ§»uiØm¢iÎì'_ªt ç8;!¿æôðǬx%»uÃÊ`^^òꀨ ;-¢™^Àè¤ÚŸÖ=ô{Àð^SB ¾µÀ–×-‹­Æ#Wïd Y/ ïÒê_,)}‘´[“3]¤Æ…\˜ÌKü¹0W²µÅ«´vB¦µy7_ºµ¥«´vB¦¯Kkï—&j5vÈõNX§` ¨Ù^8 ]r\tм^ȺÀOGAª‘„KÈ@Þš8Õ”ä‰OÕ-±î¹ ËX.è®Kt›Õ}É©©ýw•“‰zn—hÔ‹¿ì2eL˜Ä/ÿ]çqÉï:góxéïzéÙxA!—Û%g#ˆ2=H[ž,ÚBf1:nY¤‚Þ*1tËïj«tQ’(ªãzˆAÎPÄIbÓd—È¢Ù3Ðt‚· ´Ôwû®Ût ˆ à–q†:à£E T (‡ˆ‰YNâ˜ÃþN•\–\ÿü2œTjg® G8«?íü¸c $øH«ôb¦eq ¢s›¼4IÀ`Ô #ÃÂrœÅ¾ýL§­oâúÍîf}½¼ Ú´úþƒFµUÙoÕ÷תµÍúݽøEݺ”óÕy ‡$Y „ЩHPßÃò¼ÓA(Ѳ ¯c¨ŽåaÐîù]ZŒûØäBæÓ¹¬Ž‰¡t"¨md–üÙ$…Û¯yG±l;&r‘Ž›DÚé¦1`ÝNº_‰^Ô/Ë;!3øi®Î”NÀžºQY¯oT¾Ñù_¬sž4g uûôFƒ9'¢ 2ŽV½dh½„Ë»&¥™ËI ñÆh˜ªÔ°9×hq¿\\êï8s}8pß»ýþç,+“úÕE\w.ô’ÙO¨Á„¦ŠœøÑù|tæÿH5ïbò¶ÎC_uÝH€WqöAçsÌ.°®m…‰9P…G®? ÷/NÐ÷«¾~¬~&âþ¢þy"e¼ÛºˆÛº€Û³›¸×ÀûÿM¿:U¨ñ~m³^Þ  ³h Û*7[`QZý&#jRA)>Jè  s›"O<Ðøe:“"þ(XÙÒáªâØ@B<Á€ˆFð—È>«ÁljßqJÐíu8±ÅG¶¼áÒ–i¿RÍ‚L‹Ä®€úŽÐævg‡ùBðHà¶…”—!Â:W±žv{ðA#ò}Cj8¤ðz·žŽ; ÚÇÄŽ-²*wnÐ`"«çæ'õ¬>ýKfkÑ!@­Ø’XÑLMª}e†AÀC©ëÑårpŽ“£ýð[ØëŠH)œÇ½DÖC¡ 08ÍÀ¥‘ž<KL½˜8˜‘VGg|rŠªxøåx0jNÏÈø¬DGàJÕ'Ôv0ìѧî´ð †"7Nfc­Šo6Ö6V± b« 8}Ì®g}õ~…µñ. 9 ’nO\¡Žô-ð"”HD'Ä åvO7£ê€–ÏólBAËãp6’1ìùOÄ¿Y4ñzè\kèðŽØëÅ£ÚÐ^Ê(/Õ1}¦7xšõÈÏ«;ré£ihhãIžúš›µïŸª3LC¬ÏR_Î9]ñLr¹åU ËRšÀÑÝW2áþê&© ­gÛõ¦š;V¬E(š„Ž€íP?ðBí"Á™ãøà± ÉM‚gíÞ÷"V×*‚Ü۹Π÷6š8¢»G}µTÔ+‚çÓFp<€‡jŸ³Óƒ§CÕõ¹Îll°éAöGÃ!ZE£â“?AErÕWzO• ° fP.mÚ2¸KAðaXDð'Š~ª‡ÂXl?À Âþ+S†MÇ<¹ðL•u’Ó„ûâtÎnt›|hc!ì¯hNMLL¨Ü5±¬q³;Á-Nm_ª'Î4.×0üÚ$Ž5ëž3à¨Öæ³Íž­6QŠÆ=±™rhj§k½ ˆ? ûÖ»ìw%‹„늆önT°¤‚‰:Éäqcmd3èÏNÇ}“å©Od0òn9‘ÆDÓ¾Pz t ãõ!k6m ¨i›ØI†×Ãø ë8 tÿ‰Y¨|õœyR”º¶Þ«?Àwkåf¥ Ÿõ¸?xj¢Ì‹P¾™ŽÐXF¹àޤ³¸ú üñÛ8ƒ™ Ñb÷ò^¦wê-3ž!œ “?RO 7v‡À§‚\'4ã¿Ìß‹sÃÒuA3ëÓPA¯å ÜŒLŽ‚éôêç—á¤Rg¥S€=ÍeëuçfÊ`A@»`–Ñ>˜»ÙÈïæ‹G$á³h÷бM°©pzÁ>„ìt¸;Y:Ò½L\fus"G'ÁjU¨z‘:ìY0èA s±²îlî4ïÙ@K=y\|5-ê{cÊø"&ÏìÌÝTé#ÐÒô•@<ßéüzðMš#Zš#Íx8xc+“ô"‚‹í<¬—4]9´³±ÚÇú¨e’ rβÀ7Zö×bãqÐ;•Iͧ~tû¹X»‹H¹ÔÔoG• §?ÅÔ ÎAq9q½…^œÏOìMKo¹èÓÈ{2ÂÁM¢-™é"¾(®¾ˆKIÕ êœîƒÐüdZe4’çRaÚ,Îì'§æ†`3¸[i)¡ýÃO;ß®# Ê3pÊɲ°a¸†]ÚšÙÞ'!‹m¨R¦^*súX(DÔó®]=ù‘É&Œa¨(v*˜hHm <ÕæYV™=Ÿ„P,²ãA¡Œ¼*è,-ßÚÊ勜Â}©Î¨. 3킨SVÔWÀ;‘ø…Ç’¿ë$P×ø3Oô°3ƒ¯xÜíi#&¿sÒí»ð˜üÑ ‚ŒÅWþlÊ¢Ge^b °éµC—;`–Ú+êTÓéM|&p$°KRÍö ×ø˜›ÐdêºÎFå>,Dà¿Àò›jõ¦j§5>±† ãbiÕ~Ë·¼¡ß}Ös’Ö¤f1¸¹¾Æˆ4ü½(Ybç÷"µ[â¹kåO¸îÇ”Œeã&°LÈE£uØ=Cà—èGè]Þ«i®Kž9è λÏSˆE§v¹nÈÁ#q}¨ç¢Ãç8 0ÍǬÝsÔøTØZôØO`²N›U¨Á‚$=Ñä'¡zI¼8‚J„Ú],[8è0ºò»„;hx»‚Šn¨¦¹ËzóÞÚ˜hUŸù'An/ú³Vü£$v¸zt%p•6¨>Óó¤Ts´£ºz¤ÒàÌt‡õ2Ypt<åRgã;'Õçž|ާ#è€X¨nÛþ)CQaˆ{S÷±ªíx0èè 6q¨ÞsuwqN {šÔ ×’™qúy Y £a•Ç€Ò9 _`ß Âôï× 8øg1»ž¦ihXç/4‘W›ûw•Š•©”¾8G´ŠÒ‹«ˆìx—ª"™£Ë:ýë€M8³Î™)… 8ï@Ç7¯h3>ÈÙ‹~ž'/Æ”â"ßÙVWË©mSçM¾}$òG–FÀmˆ7(2.“uóuçU-‹&ßBßîVkžêì#œ©é=oïP§ƒPûvìÕfÝCë>ÞÌ÷\·yLqäá(f‘’]~U‰úåCGb(™Ú²¸Ñ0ý‰ÎÇ~f§á|ÚV­Ê©¢T1ÄÜ+}|Yo¢s @.×1`ï·"·ÔÙ:—á=:.Ms‹Þÿ sÝþ!gî ¼ :®º½åüHœy=ÿ îbþ‘þÄ›¢Cé©I´Y¯og=ò,¦CãÁ½ª 1Ìë"È`®3`ñtpÊwæ¦t?á)•ˆÔúÛD”ß΀gN‹ÀüÎ1ÕRÂÏ+®âhÛS°Rª¿ÜVïÀ¯£ø¿‘Î)R|ßêJ«öÃûúzï tëòœ<Ã:nA ãKääOžMýŽTé©Ç™úëÎ3+³Nn»YO{źô”ÉæÉËAœôCTY‚"zã“ðD᣿ÈÙù¬NU\1•C°V…Ÿ H• •’*iþ Ð…Eͬ*kjc‡¸˜;"}!·;vOüaW"<êénA_0º1AªTãùòáF%ýi ¾<ñòÓePëïtæžÁú[ßiñÙÎ÷Xz”‰+Å0Œ$u¨wa WßK.75÷îmm5›ù1þqI3o@TÄÀ¾u0Ì 0r½h‘ðjÊ—O%I1LñeÁ3v—Õð1žC”-Ñ̯(éü¥HÓâû^¥t_E™žK «K…ÕÒrÚ='¹ZàQ2ÎÒÂR¡´œ/àŸK -5v6õ«S¥3äÙ¹WnìÛNÕŒ³yÌò‹=Ü#ר]4Dn4Õã6À¯ìäŸyAžÓ¢©ëµy)ãßTx6y·Ä^>„[Ëèé VºZIüÆ?ºXȺèyªª´¿Ñ¤Xú8b©Ô/*} Uäîýšs#E?íf¶æ•4µSkVïÖ*êÇï«4êwª››ˆë$›\ɨ)Þ:å„ö4·R*-,Ü(–o.-Þ¸±t³p "ÉÇ7¨€q?^²&o...ßX\,ÜX¸QXYZ*.¡ëš•Fµ,ñpÑ=÷^v[—v#é<ª_Ê;­ú~µ¦ÎF ‘´S«~q§ò±œÏμ?Sú*à´P-þO\iihã>‘ü ªAló97áÍ*¯u0Fìë ê·=M&ñÜÛ½»Y_Cìg³Ò„u{òÎKÿÁd0… `|ÒIJ¿ì“U§QݽÐJ™ÀæÆr§£²Z±»!Pº§n Fƒ¬µ¦Ä»Gz)¾«[x¯côP&3Üê–pâÂéL¹§]ÚÁ(ÇÓųŽeTSgöûgæž«9ôÊz½vÿç 3†R¢v?SË‚‚bTÙÑÿ%™þ „ šÌu£§ `2ƒÀ8g44%«ì‘n’ÞG×@-‡5L÷º%È@Zln‘)ßèM£õšÉ<­2CGQeþ×¾ìP4šiÇàE"iPûáÚ!d%Ð6RU[ÒæW¢Ë›…e¼8ò@S@IzDj.á„­‘ºXU5?-mx”"Â…ß3âpWÀ‘É›cÞÜgD zË‹êöÜê»Âé#Ö_èõð'â²ÔNÜIÙX\–t±P,$„ L¿\QnfoÆ3Ü(MLŸ+ÞȪ4WŒgÈÝ›˜¾XxGUž¦¿ Ï|È×õ¤UÛ®)nLÏ)} Öxμæ|k zÔ©’†šŽ×¢G.k`ÑN#ó÷Šú“+–r Åtžìd®6¡Oï† ÛÊâ´'Â,LiQ‹šCAíGfÝ`· ŒÜMWsÖ{ÒE¤a? Ñ.Ñ¿ ¯‡n²õ³ŸÇ ŸkU¶¶ërãQÜÊ.â>(ÕýÂåK;|éâÌ—£|&†¶Ô¥˜sb} ½;bÊ€T‚œh˜ʱ¶,<¸éºš ¦ÖeñåÏFͲɇKÁ[ }Kí e«Å«ÔApÔ%ãîV&`i‘\|¬œY+¼w6ADp@:ñD–V¸“Š"h›‡‘Ž\ ‘1Å¢áÄ]ž2&ŒàÔy0r#|šBNŸ”c•ükpU®›§á‘—óæŠ‹¤­<»€ÀW'6f—³°R¡ ÛÇ~ycCåVûþÖÜY‹ì=jJ ÿpŠ NmòG&y Âï²íf±Ìë8 ×z-¾“Š òé(û%]„-·p#W°õú ÖWÏÝóssdÐx^¡¸Z(­’…nœSœPô’ŕԩw”Ò¶ªë:Tɪ¤T(,àÑSRÓÕ£·übi!nß(-\Ó½ÿwÏÌýNØó°¿c&,¨#ûzè÷F X®ôÙ[ǸäÀdÚéwŸ‘¯Žš„t¡@(X„ÂSH;#Òläà ®;„9y`FÏ鈧 Œb˜Ñ}8×;ƒ£‚­îúÜ~nÅÄ.é²ôq NüØ ¥ï?ß)ïÃûåF£ÞN_‹ÏЫ~¦ôs@oƒ‡"à„vÔqû‹^·n‹”òÒ§-%7´Z|qcÒZ ¼#XB Îva—OBm¾73Ç #rÿœx} ç„©‰œ®GTð"n¢-›GP%u*ºæº ŲDãg³“Ž­Åöa * ÿ‡ÁÙ[ésb¼É÷Ee!±³AÃp˜w.B¬ UÝ>ÁöQøÀ2Š‹+KKT¥@\4C"BH±ʨ›¥‘¡ÙFUË¥ÂbÁ*ƒ`ÔºçÞ¥›+7J7c)B«Œ…›Å…âÊòå¾…Æz™WÙÉ ƒGs6ÒËìÏo¾ ³‡óKB?èØ!ìÃëÁ@ç—ä €MôÚ¦DÙ(¥qÆã4²¨Ôu–+Ë{ä_œ0PË{µ7 N¬&Ȥ¡¸AÈÜXGÁˆ|X`Ĺsg¢)RÚƒÇE[ ]˜,ðd•ëE€Þæê6€Ñ`¦ÅbQI$üÔB%4%—v<§ÚÛ¿ùGœ¹ìÂ,F Ïë›NæõM’.½Ì³“Þ>¸g½gj¹ï3+i$Í<»ýH$èìižvO†˜²[j*ûÃÇãSWŠ&׺¾÷p[U`Y䬽 €íÝ'݉Zäàó¨ŽÂX=¤oϬ¸z^C]Ð^oúƒNÀ;:ÎÀöq·ø´ë„âÊ„ó´Ë™¨“ñ¶ ¡#æ2¡¯T9–¸ëó^iN%ë‹üCDôŸŠIê]hF•é»Dè†Ú³^¤«Óïùï¿wð~ÓÜíùï½{ðþ{ïúïïÌ»þ»it„s/ŸëTù8ˆŸ¾¸Úƨø ˜ ¸S°v:q‘³Ñ lc†Ÿ–ºœzjq±ã›Ö—&‹åÄnÊð Z}>øJÐ@Ìã°»d½É’|ÎDÍfÑO¢Úèò͘|š¬á¸ÖDS5¶{c‰väœ8‹eLæ1Ü8y¨Ãó ú)úá ´W=­þµÆ¶ [G¯Û!0€žç–(z{ìJsz”Ñjƒø°Õ¨±l÷pŽAýEî=ƒ–.þ7®‘í˜È—Àª\Wf"¢0¸ézt â.X–ëÄ;í’qNêA'ÝGL©vÇKéO}é÷n߬xÕ•d}îOHˆ>¡YP…ÆfQ °bÈidOÔƒ‹B‹¾õâBvÑ hÝŠé 1`ß6;F…5*€úÐÕá‰.d?›° ß-Üi´\¢¸©Â´\æÏåË+"¹E·hÌ \4ž=ÿâ>i_oŸ$Šû8ö‰¦áää¢Ë6ì~íÑÔ¾^f®¬sÄh·Èé¦!­è©ùkœ‘R§€âÇnR^cWêT=TøúöP‘{èíê Ø2üþèíU/&öEüèPä¢oŠÊùGrDÿÕƒÀÚäHç[7ˆœ@Cg ×]t1@!|yìMߎû¨NÞâaÚÛ§…7©+¡ù֙Ȭ1ª·Ä@·Ûm%{u:¨à¥ºÜÄvf§ÏŒ[e/MŸÝʽ0}n“yñò™Þ‚à¼F,ÝreŠ^ôOyZü§Dÿ,Ð?‹ôÏRdÊ_¢<ÕP¸˜«–ZÿÐÂÁßTç(oåÊs*5”~.\Éê›ûÛåfóA½±ñΧ 9—õœR‘Gót@t:$š‘‘婈æI“Ñ…ŒÄ¨%®,Ã@!ndwt–÷bÙw-!&ÆËðZe”Ô•[Ìç/¬sB¤%"¡F©²ØkDI÷x6¢çlMBÌDº*ظJq \¥©–ÿ5bAÄ=XP¨—Xç(öÞ ×dõ`*Û4.w쇰‹]å®ÿõdƒš}c¦ôoÀDÐÊýr£ –ηœ?5ÙˆÙ,?ܘn_Èô†ªï0\(A´DCóuE )&o¹©f¬eØVÀ»êÎç2¡ÀÐSqüewâd^ˆ5÷Ís?0‘wê­rëMç3ÚrEO2³óȨ¤„•äCbâØÍÈ–~3ûæ›øÿü›oªÃo7\Úš6\5¨ÝÕ×Hºf/ŒK'¶-u ß@p$v'«i a,HaL‡ yk3eLáëÁœþÇ1ëwK±´°PÊ«¿—–³ÞbìSÊòë¥8ˆ'š?{^ÎB!/Šä,eã˜Ê™~9ljfkîçƒ{Áóçßl!—ë¬÷ü¹ënŽ&äÕyï¸In; ДµµËNÊ [Äv}æñ§ÉP @€ c½O¨8Îa—èv-·gR ž[.•aŠ®%Ÿ›¤ä‹5ù ¼{=ê éÞïJî=.'<€qw;LR¸0I!™$ṄI,|è¨7¡º$]ߥýU&ùlêÓ3s¿@M(w­ÚÒøS»™§S âa£=莦Eq³À ±¡±š”-\̽PziÀ™§©¹_È6‰ Ôƒð@3ÎovÔÝ"€¨÷ ˆ…|:èÅ:$à÷¹jP¿°‹§‹öP«hÊ~:¥ÏâüQ$ˆ3Öx[.HinN&SP»vÁ[€XÎêÿðsa>‹ž‹^ £<—ðçâüù¡žíþˆÆgÆÞ¹|Àgs ºtÑ—V'˜²M°§‰_U…”}çzÆÎI¥~VéÔâ-i/É?îHœËéÅ’GœÒpAB+àË¿ÈQÒýX9Jξ:rJ¿Xã/››ààw¯ÞOÝŸ„Xï\wCìÉ>±#«¯· ³")´°“Ãà,¬C‹Èi¯ÀÂGR$L°ý †£Üñ ÝÆTûÖ‰z6»a—¢c¨ZÄ·lœí¿KF’3¤3 Çúò˜ L3Eïæ À¨® §xs<…·ÆQ¦ob+ôäÏ‘Gj5±ºý.ê'î©Ï%Ŷún[­‚÷ϧ.Û+®”ŠË7 Eu.z]¾/ƒzea¡° È~]D`ƒNŒñ­ÁøçSK&¤ž®%îÀ|æ*{!;"CuC{Ä®…ÑôÔ†Ý#öº@í’ÖÔ‹@ˆwØ+ä!wF©P›uŽmöÝÎmáp`Sƒ`‚¥Å¥Z‚SØ»bKì9Í0ÇsÍxq´YA{J%Ṳy†¶‚îkø‘0‘è#¡ÚÄÇi±Ôô1žuWdÉxQJPÝ=dÍŒò‚ „ô4Úo‡zFG•ÛfÖkœööáJ „¿ûJŽ}Ìá»õT]}4ß8ˆDax†^ódZA®â«ùðãá€] ôÏ>û Æ™û7Õ¾û3š­r£åµåZ³Œq¿ÁùÔ7è7þÒÛ}PmÝψfµÙg·f­¼­ö ÖžZŸèù­’ÔîAätdKÀß¼ÝrmÃÛ­Õ÷Àc±ZSðöÞsõÍ͵òú‡—M¢¸Ýq-·½¯ÂSü+aí†Ñ æå ‚Ç™r(ÂÇÃ…áOÌ9ؤ˂šBZ ZE¿~óIÃÐ 7óùEµÚ¹+N€Ø§F v¤Dër_ü ,Êô @ox ­¨ÛhQ÷MïqpêFbc—(ƒ]*߈ûBù8bôš†K ûùI¯,²#•j°Ç¨¾ó¸´-Â% 'ïÝ4šbÜÍË}†bz#cv–ÉæÇþ%«^'5)4¦4u€Ær"r 1Ñk&'Dú8À•‘N¦ ß …D(H” ÍØ =fR»QÏåw wä4™V'²°_£Ã'ÍEôï· Ñjp{n•’ÅÚE$©Žµà“€”,ÀŒW«ë©ó½áCîH5at#õ Y®™ZÀ`Ðf¥IÓ#ÆKh÷é£ÙAI~‰ßË”AœAj×ô/Y >5î3ÆÕ,F#-ØNÒAÜ]r›1Í·9·t À†G†ó°„+wQóLCM‰A(Pãõ8Ê,‘i¬!   Q¾pOóÉQ8a2ÜÚÆÚúæð‹Î[0Ú—Ÿ¬…jm8uõ7­º±}îvá–ë–qÎPyØÈX‰ H4_©µKU÷À%ÕÔ™Pq¨r*ÀOC'±+¯ ý½#®÷ðî¡kÞ’6™&çŠÆ’ u¼ã¢4À2†^Œûmpn‡}s ¨%×%geÊ Ú„“ÚîÚ)CY¨°ñÔI|Ëe¥ÁåÕÛÍ­Lè÷üáÙ<¹ƒà”Ø^°Àno¹ ޕȪ1VbéðìöåXR˜[—Žyoµ65û³æþp×^«´T*5Øo?礴õ ÍMò û°ŸøÏp10²Î;B·XŽç*‡¯Ã Ù€b|¨H*QûϲºÍ×5êPÏ” Π<]&s¶„P÷{l/ƒFãêªmÕ¼½Ñ¿.¯¥r@–<Õ½–0© Èsš`l±¥ø¼`7hj Qáw‚°=ìÐ5è²î†àpiªÁaB/‰åÈT!­&Jë®/ËJ(ƒe„JØ jtÓi>í§1Gº¾PQ\ŠÕ^˜2ý³\,Gáb·¤¤J?Œœ]·Ö·9ÿر™¹PZÌÂߥ,„:Ž©@£d§ <\}!I„DüÞ5Š<“1w{äX´Ó‹Q¡=âå^Á4 '|¯‰ º«{×U”3›ús©¹_›Ðßì“éè 绵EÇzœŸ¶,Ùñæ™ûS¨$ä9Drzƒ$æˆ@Ì€¬¤?ñÏ\Æ;é7ÆÛR‡F8V§:3ÔvUY¶ì2»-n®•íT‡ŸA‹ Ùºóú<+ħÝQàÖ¾Šÿ²ç­{Þ[½·Ž½·ªÞ[½¸ŸšJ a$½Â"ü·˜¾WC'•Z™û·À³r§õ¦óŸkC üŽôÃjÏN˜QGÀäö‹ÈÇèQl®¡ƒï™›`¢¸“ËXcãÓ‡ƒÁ?Tÿ©Î]Šõ&¾{IÛælê¯8¥ñ”q§Òxä­—×ïU¾Ã¦iPj$ÀÜGcˆ¨„êt ÂÈ=ãQ8¸ñrÌüŨ̂‰Òm¬G+ê”f ƒ ‰Á.‡ »v òŽ·‰à'–Íe (ƒ[-1D¤(×úö%Ƕ2€ÅQˆ l(ߦt¬„|úŦ3T· %‡ò4¨]o×óGÕø~3ôÆh=Ú®¼æüÜ”zIã†QLgé‡RO“Ë…ût'„ûšy¯¬yÓ8< á?ú$ycŒz²9¹—eÉ%¢!ÁÐÅ CÁÑâ’+»·éÆ{ºõˆ¨)C£%®®×U%,/ = Ð&•–”H¶Äâ“éâ:ž˜+šX¿^q=ÛÌÜ/…ÍO ÿ¯8o›X êwðÔÇkÖö§]—{¼ãç,BgÇQoIDØ'@ý˜/lg„siÞœaׂq<3EÓ €IUìh,0lVpøDñ@4Û‘9ã@Ò]'µM1Æ@=•èò+¥……Å›¥…›Ë¥ÂBœü2” ñ,Å¥›7o––‹¥¥ba1Îpå<ñË KK …¥BaAý‰óLÌq£ ÎÞÅå•Å›Ë7o&ˆŒ/Õ®kâÏù]ÎÜ/Ã9»]ÞxÓù”™³êw9°³§~' °å! Ès§„y5Ô唂r‹£Á²-ˆ²V ;A>\r¥„Ú'J¸HóôéJ+ëZ„€ƒ˜€’>KÙôââÔq÷ _øBe²'eyYyaæ3©Ò¿­Æî3L2+±o>ïünÃéH¯¾*ï€@Ë[å¯y»Õ;HÉWyXm¶š{BÏC|}o_äwß ø2éÑÙír¼r4BX‡Öîí½ÈÁå"]IÌ1«1Yä sÝØ§qT@Ø¢tÔ=ÝÈÇŸ©ò…ö¦ŠÈ YËeôîTv4pÓèØb›á$.uYÒK:Öºi¯àø-9]ÓM¼Dnµžp¦ôË·p£²þšónJý³›ÙÚÍnìG! ¡N·*êÄt®îNõae㥡 bqî/‚ˆ«æT·ÊL‡åéþ„Î}âw{dðƒ:ª‹ù¨{ÐÅ8·8ÊddÔ#Oºèi×û×—9öÔ?5SúÀ·r¿ÜØß®oÖùA½ùQ†=·íýôtp:f³êÈc>|! z:£çj®H Cw)ymг É’®§,{R*¡¹kÈM¼t»˜NРÅì9rç@yÖ¢Ôkëf´ß¶årÈaº2èo €²òáÆgAîqìS 8ÓøA£¦Ua ãÓÜAvYöös €1ýïRsÿ¬«Ê¦º×~Âðçl¶2µ¬ÚŸ‹ðW þZ`5Œ-¼„ï¬Q bH&¿–X§0+~‚jyÞ´ˆ`z[ßEKq­šgx6ð‰Ëÿjesãº"ü¼85ŽªW}b:ø2Üî_öáßcúUÝ‘ãG zwúS%,NQ7*µÖþNS=—t`üjVÔ«jë‘J*Ùž{ÕÚýú‡&!4΃͆PU»É÷á>6OIÊM&¹Ù×ÕP„Ýõrs½¼­Fî8¬+ë2[ê^"`­¶òñ|‘ˈ ‘oŠèŠAfxCÕvOÔ¶>$’7¢t–“?Gl²Ä….D¨‡÷‰ï„S×Àë¿Y^§Œvð?«¼=6˜¯·b™‰š7õm/âÝ©ðÛÄßÂJ xIæÛÐÜc†ì°E‹’'³¥W)[·È··õÌtóÄWo½3‰P‰ýMt¨4S+qb±)§\ÎU:g{—%¹etR³?\úUÂ.|ñugu6Füª ÷(hók—f¦2™ ¤‰µÈÈ­ˆ wòˆõcÙ­9â&R´! šDèÆ ¨´ r.•7€Ê–€Ê³ ¨.kEšÈ Gy0gq-š.4±6µUŒ€VºžgYwÜÇI§CÁ›ŸbceéŒÈGÁÈÕ¸Ï8I4Ys‚¡¥Ñà6q>îžâ·ja˜‘9(ï-È#:ü³¥FD~ oÒ'E¿Åµ!HyVé¯bLÎU°jzx1®^=ó¬óGSsÿ®Z©ügOkßPõ$²>ã÷^Á7AeIþoÆÿ%ïóÞF}F/íü•¬ÀIÍ|­ô«A5Ѫš­k‚ušyºÑN»>èȈŒ™ß¤Ä|RݪQë$h˨¨ Ü™ÏÉ6~Ñ.)ň Œ»‚ó³®­Hâ®øª Õ¼QÝ…dR=³´¸ÏÎÓGœ" yÍ—“sê×»ºÕ„krp;ç¢òIêt™tVýïö'ÅK7ÑÂ+¿m!)D†ŒßãÜ6Ê_yˆ1Ì/‡Ø˜þ€ s`jè‡_µ%팹 ÅVàÅ:¤6¶lŽlÑHý4PÐÜaᇠXR“$Ê‚VhbŸbS}h¥ú„u·¼]5\SSú2œ§‰9öÇĆQ­©›] ‚{Õ½‘‡Œ~ÍLq>›)©ÿ/¨Áý"š9ëf½Ö½pm6œÆ& WUocL`ü@ýZð¼þrðKœ4Ǭ¸ïø—Øc÷ñŠ2--Lxÿ"âž Õ!S±ÜUý)b|óÙ¥ó?ûëõ=¥)¾ç²ZÀógÃìlÆ™û‚ðRnVk¯8?®E1ø=ó0¦úó‡m€-¢šïaÖI]3©Ÿ¢ÄŽiÔJy¨•E®(‹ :(b3Ì1lÏušê¾)J¸ãáò¥¸¹ªT(.,ÝX)n¬âæ:Ì$úœ ãf½Á¸^0®Y¯¨î ¸^&N3攵jínÄl‚[ÔÅÐÁàâX7ÖúÜÛRÒ @‚_ôçùËÖÌ[øt”VÀa¬5÷%<ŽÚH†pçܨï¬mr,‹UÒ½lÍ×`…œMý‚Ôܯ…µæ„Wœ?¨× üžX+À(XM-©#W̃:sŠç—{ˆªi“õæ¬ÒŸ®°ýÂUòQLàÀOÉ-ÄVI.núÅdqËï¤4¥…3CñZ ³3ß™šûuÈ5^YßoÕ÷)`ËŠ¥g zªÇÆŽ8„Òÿ¹˜º¬‹Ö ([È„[z'ã7Â!b†ÄX&šE5±¸ó-¦¬w ö®ïgzúà O±Ýh¦ÆêÁ—ƒ4bÙØŒk…òõâsÄêÛÒÂxÀBauaeuáf\°LdKÄ\XY¸yMø¾Ù¿VúõöøÎf½¬.å?2‹?¨[yvã¢ux-ô2ÍÏéèHóqà‹D_*ƒ2á'äæò‹…ÒM5õ——+ï,@;µ‚òÅK‹+‹ KÅJná&î0§bÏÁ¯!–gDŸgÇõuëÆeá!“­š Y鈆±Z©T\1kqÌ+dä)ª©ôtQº £Ûø4¸êÖÛÁÈêƒá$Ð-‘‡Gƒ‘*߈Úî`úPq-io¿)‘-¼|mq~¬_}( ëîŠÕ¤„v©/´~š9˜åcÖØ¨ºÜ@¸hÂúƒ{/¬²ÓÓáà™j„w÷nxQXi<™Pka™Àýƒˆt\/ƒHB• NJÐkE-h4ÇýàÙ) ªv5ÁN Ĺ.©B]5øm6 ¢ö„´Êï}ÀÁê§1ÌLãk¿·þ '&Κ8¯ÀJöõµ`§fNæ~p.y¨UyÓ ãKO2áøP? Êz‰gYužrÄÒS°%h±u‡ÚŒ4Ò qw2ØÌ¥qYàOD&˜#QCàÍû‚Üókð.®!KºfTÁ\Ýbõƒ1Õpjrf-Có®EmñïÇÈÔ×i![ˆäù˜Úur¶g‘|é‹ÅŒsëJ Ÿo¼$§Sê‡ç~#†¾Wn4+­Ï8?ª%@~4|ÇÄ“e p&çú5^îs\Ä Kûí¸¾¶~1¡ÿá%¯ÒàœÞŽºèÜõƣÛó±RàÙye€é839ÃuÜ]—gJ¿ ¤¹³~o8ÍPÒ£ H Ùj­UiÜ/o’ƒ­Rû¤ÀÛÿ öäâêöŸ Û–ZbÂ…âŠ6Ò£”7ï&,x& Q†ÛiäÌ–: u®)U(kÙ¾†‡–”ˆQ¶òqM„® "8ݤNj-è Š*É£xÜçBáÄ,$‚+Êg]µ4×Úþ°ÿøHDïÕùm4.ØÞ€Áàéàê`(èàXÈΘhÑHÐÎ¥ö;ä˜å¢.›cQ–1Ò¶å‡À¥xwNø~uuÕÞ+ Ås¿Ý$»NaüZÄcg6õnjîÿzU5zõ;°ì ç×ëíL?ÌpX8{GS=,‹à,ð‡Ÿlañz:mvæçÏ”þ}Õgß°Y¯Ý%cßÂŒüüu¶õ-fK+‹Ù•åêß%˜À‹w×:Èã•YŒÏ-úìþLé?€õ»Qm~o]aßåüeg£~.™£bö¨dmuc,XŠæˆVÐÉkEõñìrdÒɀ×K"6¬µlæ½£Ò”}¡[Ÿƒyšƒ€%9®17 øæwÜ= slÍ1q\Wã3ŽºªR}ûÊ/™)ýÐ~XÝÜ|Ý©¿"S~‡í¯V«Ásr»ÛC¿p¿³ßí¸n…`jšS`JÐàm ›[aÎgÀ:09É ŒÞ°OÖØŠ«‘2Ûúz¥Ùܬ6#¡äÕîò¸ "¹“ ›¯[jY]ú2KšÑˆëcÕ"'C‰u¶ X˜ÓJ³)âk  g‚¤­¢Z“º„LXfó°„á Ýõ#˜#Ž&(ÍÏëÊ©Q¦8¾•DˆHbåw-Þ=U;ñ— !|—{òìÅóŒÂ wë@%†D£—x8,Ü–&Q%SÔIÞIÈB““FÒd%Õ­æÖÈ»VÈôHm2 z†Œò÷œRÜè\Ûr)‚¤:¼Úê¨Eôd¶^A5.£ÇPZ…@`3ÓmÏvÝ·ÁííU™î3“ª­¨s ±¤"N<¯×=úó¬+š#D¯JR«CÐkñBc=r ?›%=*¹C›”ªåvK8$°W±)sª3§Ü¡'„]vÚ,À[pæþCP•› Ì:ÿ½Ã¬¥GêþW|ØR?!èýCѧÃ~#nœ†Ž“ýïá<@ÎÖ$ÎaÒïLÇD»âî?`¢‘µëê˜%þ_7ÒqËûàÈ»í¥ {-RÆ]ì‚·p.Sl”Áõèİl"ãÅÔ¬1–W»i/ u}ÇÝý:öa*õ_ÎýGÈ s3ÜœÊͨ>F^†×¡âkÇU|Úgp1›þBÂið _P¯âšºˆ›áµû¦fyéÇÀm½¡¦U½Q!wüŸélhˆwä…7:è±sBVÿŒ®ƒû]Í÷îhð.0üOßítÁ8­.ê>- àcš’‹¼‘A8&æ>fP¡Bèd|0°I¹87€‡jg›Š¢»–®É A­í ä*u8V'4Ý!´&Ç–àZ‰B~„{SVMŽ[péð(Ã3‚YHÃç÷Ý RD£Q ‡`÷AcdÞû^ðœð h7:ëqw¸Ô†ž÷é`øØâ)Ù:«6ËÌ%…Êi1àDÚì ¥'ëm„ 0é@wÉÜ¡ÚËúÝŽ–ûtþpx"[7p¨â ›ßz´á¢Ý±õVzC.Mö¨¦’b¾>¤€/Ø—c 7¨JR¥WáÎ<ãâé;©gŽÉZÑ.|¼Q_ÒâO!hìb±DæŽ$(>?Á+*}ý±Ï`®¢;¢*§<}øËsXè”Ñ1’yggþÓ™Òo¾ÊúfY­ˆ=_É÷-ç¡ÖØÊKíX@‹S§…¸ ÖK²|»±äß«D ˆt\ñvÔ¶ç`D7ÎÀÝáßoÔZŒûÉ‚ -WÏ„ ·bÕçýN¢l( I„pd„ö³FÇ,_ZSºLOLª¤;4&!‘,áÏÄûôϽrmcSI¾0Ѹq"—Á¼ï4„훎Ò$@>KÒÊGJö]aÒÐy5 “ %Gxyó"fÌì(d 嫨9ÆMÎ Ò”¾”çà8©Ôß-ý6PÔïW›åíæw9ÃT]5³çŸ†Sª Œ®`À€F‡.aî„÷Bƒšº§Ï.F­ ›Qwèêg¼s!_ Î-ÀÚ¼q®š9¨ô†Ëšê.èb£95Ý ­ûþÿ}µ³å?ù¡¶³´þ%›Všßîüv§6>¹«ÓfŽÚ1ÉÏh #ƒ„ï„÷}ÐëñèÐZ;jOë4Ì%µuIçG–(F"Kµá&lIf_:"kÝ@÷@OÞ¢“ùÛ— #²ÿ‹ º\`‡KÄ\MÂiÏ)é‹×> ³©¿1SúOÔ„únŽ!¯vÏ}dõßo~XÝ&Lp¥ñºsb!×^X f-yZ=V3›e‡g@«ƒôä¡MòNQ,Z:%C¢×*ÓŸ ƒz4âÂhpe.ªˆýˆ ,Öˆ.ÆÑì²o¨Ž$Hœð¬Ycô«ç"Ê%­j>¯׋¼ürHë‡ôèèw‡}>b\wëZËÝò_pæ~;ØÓ¶êµÖ½ZЈkzLõÃIö4å#N}%3ˆY}r=ã“[,Q¯žß?jWH¶iü‰ZX¶{ ¡Óîµ÷ÁȵO~¡12m7séhEm¿§z„xı3¦uÙ¿Øàw;ví4=i ~K G”à`8öá¢v†¿Ô«{¥ÿÄWÔVnì(¬\+o>jV¾ÇyEÇ2ñû~ï, 2»'þ³}‰Ó¾›…ßÈ\µ·'¤¨쌇8Lä:­ã,¨&¾‹Þ T\¾ÝæKDu$JBâ¿`€)ß.‰ÎÖ@bËè†QL* ±JÐð²£ûÊ•¾š7z_žD¤‚Vb“õu¸ûw… ÖEåé®F|7U!¼SŒ'h階0¢!ÚMì àe„á¿´´,"Ú²lCM¡·ÚÌUGvð§¦õmë¶)¾ƒ™í6s+œyœ¸ãa(TVœõ #k´6°òà tN^>‰.õÜ,®”_àŸ G™*€“ãªõtc¸°?áeÃ|À }x†³d 6>&Ô}¡Š¹5žÞ¸r²=M+jrþÙT:UúpÑÚZkT¾¸SÞü„ó§ø®$Ó\´ÐÝícÿ­AÌL耆’Ò|Àý†s8vR×3˜tG%°I§6Ê„o¹¾XœåNDà¨\K9Nê;þ½ÒaµÖÕ ÿnÅÛÓFÃkÕ_wî|‡FŒ¼cÙo_Í7Ðušß˜(Í< õ eÜ_«Ö6àâ€WËC¿M²Bµ'œ"SA°%ß"qŒz ” É·ÙRHäh‚z ‡=m_­gûÛN÷êŽöH¥Á&ª)i[¥Üh­UÊ­ým¸qN²ÍúÝý;ÕÍ 4ƒ;¢78J6Òm×›ÞmÏJ¥6wLÓ¨l–EŠ‚q<‹•dRQA&”Ãu5››ùæyñk±Çûëe(½íïƒTl%%Ù.·îq2­J>'mû8ÝV÷— Šü°½œ~œ]Touû x»{z =¤¶›Dªûj0î<ÚWSã> $ÕOŸšœ¸6§XÿOtÀ†ƒCæ˜B\1AÒîkL­ã¾„‰Ò™H)±È–K8\6fð¸‰Ä¥Ê:†Å-5†95†ô•ÄàaV@6>á³Vwd£—uã˜W660Ùäðqq§CÀv°õÚXTÚ(È–‘ÍAþ‰FDGªf¾L^\ÅS?tɦðúr»Ú¢y5!Xqs¹0ìåàRzx&ñÕ`ŽJ8´Ë“Ì@9>ZÔ‹7£î…O>¡X~mñ´zêwGšw€;òòˆl6|˜«ÏZ.°R×8ž6Pc¤DàSPÏ…ä³bDÇ\Žz67ÄmŸœÊyzÓGÜÂ.šˆÐºlX×ûxÏ@«aó‘xÛ™ógjrljNÞËÍÔy4¨¸Ï#‰i3è fÃ3Á Iœ\·ÇW˜»ð%r3…9#§!•K|†"ËCì¹ …dWÜ&ÝAß›HH: (´jÑÁ4Ò¥3è§Å”ÊR§ê­ uƒÔ½°Çô„éXIùíàì ZÊÑWDí5eÂIIÏ÷Ÿ¬ ;åXu£+¯´y„ïàî%L †®”;C7 Lj¹ -Œ.‹QÀ1>h#¦-ƒ”POuípkÕ·)˜å-5Ç¡y¶Ž Ì¡¬J±ÍóvZ½ÐVë#}‹ƒãDʵƒù€)ÊŽìºpŠÓÅ»?Ð(ã3é˜é Ⴝãe@Òɺ0Ø£g¨‰ÕZÏ›ÝE#kFiFL(õ45jÕmà5ú¼(gdX ‚ÉÑZß~W%¥Ùl¢:ªo¶k$šK mã¢rŒË,E¡P³ˆèI!¶»Ñ,eÙi(ÎÚMÐå¥`¾ %Ã.ÝÃߟ¥‚­k`ŠÕ¬T½={°«åI¶¦ZÛˆÛËŽ“™%ŸgòÁÎ)DïdK³Î{[ÙIÇ êJÄ¢h®JjdBñD xØö7Œ‘…^œJ®`°hî3^‘A_6íoéÈQv*Ñ¡àÌ”±P^Ñ’½hfg·l¦ +'v®÷Æ8wjkÞr~!¿hMɸD,G0²½ØÊL"2±ÐùÇçžk·î8P=pn#ØOøþE_«†M}’‹°b\aShßEÕ4Í78WA¤-&è°uæã˜æ)ÑB{b’b“ç›ñ@ÀKâbieqeù†q÷æŽÕ]wðõVWE5ÁGÇ!)«(í-š…BÕô1†™IC1ïÞÓ=AÇ ÒËžÙò%jÃ5,¡Ô¹‚)YM¯äÈÀ}†@ Æcƒ€¤€âƒ¤énQS0ñ#­¦õFƒ#¼%GÅ2ˆ¢S’îZ+¢6æ(ÉÁ5ǰÕ[Øñ’U”f}ðéÎóÉœÆ{ÝŠ¸Å¾ñ‘‚Ö,FÌ›â1`GÀQ…ç¯úoÿèƒâ(ã¢Ë”-Ô0YrпóÍ%לôEÃZ4|s§ß}¦Ž ô K©ê8Œ…„¸³NmkBE($ÉÍN#xÈ‘fŸ €À1‡QÖ>¸UoæbåFÃïb kÑ¢Æù 8Je±n´JŸÎ-uÃÓ„™©b"8g{˜ÉÅb¾8N1X„ )Z(2ZJnZ-þð̃ƒ‡)j\Åý–™PW­8^C b=¢iÔH¡í6}£·„T¹¿‹ÂÞ¶Ç2ÝN§'份HÛD·GÒ ³ eÍ;»ê¸BĈöºÜdħ§9’ªïÖÅê¦5’|žhcŸÕŸzçEÇ8Dqn8î [:)‚8Ñ`j«ݘb"/ÚJ,²oʉ»šC>Ýr±7SXB˜z= ³{†7J ‡¿ŠçpTâ„ÕÍ›éƒ~8òÒpG–ðHRÕ>7†3¼²ž,ŒI5ã±ÝÅ%Åt3בø¸eIŽ!. ¦Í²­Kò¨šÁþY6"ëCQª/òqm œQT#TZxrÒhh;A AtG Eºù¸öˆ¿x8y§å«ë¡À…Õæ[¢´æk ¤‹LÌÖª k‰/ÒFlÜ$^èøpìGÝwâoà†}ÿT-…QT›ƒßi†ÈeÆa „±mpx¨*p ÿ ›] LFãKoàëȶºuºX«Wˆ«n;Þy7³}ˆöpÐßg±*ßM 5Τ;-i.|IŒèÖ¬~°å7Þ]]k5Ŭ#º‹åÎÆ0Wmö<§U×jRÛçzöiu›µ±¥üÉ.“þè3Tèd ]»¶–ýÒ\ºG!Ýí×ê¼½°PX¶ž™žçªAf!/K„Û¸õ,¢Iº],°÷Rén°$†d€©œ‰(5ì/Pg ÆXj²šnìfyQQzº#ò)ÁîÄáÉ©ö•p@6ÝÎÛ¬=ðN [ø&U³pœè삯P˜ÅP»ñù«w,ÎÚh3xOwILKë^£RÞ˜Ÿ<¢{Ìí4a.HÏJ㱌ãÙyn/JK·¦ k‚ @®g£[j.‹AŸ˜}væÉLé?Òµ›H7oœ+¼8/ÎM<Æ)Æë ƒ¾M$á³¢ù¤é>M;=lx&BÌšä)hÝ÷L¾ Úøï–h4‘J³n$M”†^¶S¾Ÿ‡ï‘‚AH®¢ÉZÍY%)#ù‚/¤Nõ½§pÎcH‹üžªuÍw3Ü"-3eøeRv {·Q®µ«;Û¾Ÿñ>f ï(" ^/#_ëjC8Řø¢ZªsY”u2¯ã¤fÆs¿SM½ÏÖZr[ÛÞz¾á "Kñ-ÅvÉzÑÅ,ü ׌\¦0Õ†’'ö÷F˜¢ä nŒ\\4õs§a=`“ÕˆT‹ª;CÛ'Ð4”ô}í|hÛu‡÷gÎLjÊu—~Ó„ø§ÔË@± Å8pɼñt„T÷åXŒiýc²ìE䯰˾|”ówKÿÛ¤‰a³R»Ûº÷¦ó+"9ö;fÊI<žŸ¼J¥Ñ¯¯‡¯èå8‰_ý}©ÒïBîAp)Æ¥ùº3|5I‚{»àµ»W2`‰‰i­7pT[zv8ÛY1àÒÝ•˜c[ª²öF1ˆxGC¿Ïl†뇖¸|,ATù¼Ô¨Ghô=}g|sûÆÖš`ed‘Ò¦‡ô—ƒC%Ëœ¥?Hkýs:quäè ÂË;h£5]&· ©¤YŸI”~+-Û6Z>ÀÌØe‘mÐ$ƒWŠlVÉä°@ç‚«Ï›o•dž0= F‘oºÖùÄ|FŠzêù@×ò"x³õçR8ç˶'dysÓÛnTï+1ìn¥éÕkÞÛù·AÒKv†‡1{(è¹Æö¸J,Aï“ØD·æ·=k´,L02º©Å5i¤Ù2àhÛëk' s]2 qÕµWö-7>EìxI¿ŽhwªWÉåCs‘i¥k4#f¹ œ7~#} A Ï€M ¬>Y'@{겞A¤ÊD`©(&F‚>q¡ótkÀ1]¦8:¬›„Í,±@4Q‰¬ @±55¸âˆP…ûŠ9TªZú/!$%³BÈ$Ýù)'²›Wnü_éPUÀ¾Q £ŽoƈKÀ¬Pe{±Pë<óÛ#]†•9Æ £r†ÄEè¢ —q+WèDSÇ”Á'åN}Ë|éw>š#VQìíòººöü™ÏÅ|š—|…9`ÅÛØÀûª—Ò¬‘ç©%à©û¾»Û¨ïlÃÝÓ`<< ÓTyØ‚åÒ¬~êÄ C£}àâfÕZµU-oš$*ÌïÙiÊ;­:–´a’ÁÝ‚BÙ)·ÊM@wZïjõ 5^öºßíp‚åj‹\¯om©†spÑØqöaÑÒk%ý¨EGÔ?R뉯‡I ¹Ê%ƒÕÍ ö;¦|MhYÑŸT{Ī“‘àA´†àd€EÀþ»õ¾•m²Xg‡llŽÙšM´xa·;ï•õùmürf„>çupf +¤ÌL/# x}Ì'Rí1#ßpÜCGOvƒ‘`ÓUNçãØí¨Ú‘¼ElÊZëêáT€OC@.½;µº¥˜Õæ ØÄ Õ­Õ d¦–ž×fçäZ¡0_y7²fL },51R6š™¢S8,·"‡UˆßÈ–@¬ÇI Ü%(‘Æš3Rºí]ŠPùfïÚìkiêÞ++Gí6àûÌ¥8Àjd! LË&ØQaý·ØC›pÈ.‘›…ÞBéCí<ÿ×ÎøViJw³`¨=¦D(쨓R¹’ ‹³ÎßB™ú€ô )~}ݦ€S’±ðy3n¡C°ŽMrõá¢øÑɘ£È‘ÅÎIR{aSŠß'd‰)ŒB¡U@}ñYuùjyñÃyÝû<Є²ë]ààñ]e·Ú;önöÆòM/£zy^üù“ ¡ó\²«³VÃÞ¾T!w=%pŠ ”…1Ó­{æ½­5h›Kò^“Y³%‰¦5ò;O”¨›¦ÿê²®0¨bBÜ¥ $ÕC´õÛgæ#) •)S²!ÏÎuެ ¶9˜'§ã‘e:F¨ ¸ü“éA  –¾9Z¾ ~µYGáÒÀ)¸ì §Ü¯Ô’Nbßš_®¸ ðE“9§ÈÀÚ‰EP°4`#™Óx9yÚܲŠ3"¦$n¢‚ŒJq  EÂ…PCfÝEù"lŸ ‰ ?Ž>†-q#’¬Ç¥esXµ×ÄÞT`­—nn¡&ár£§ž¡F…1tñœ/£íÉ€² »‹Ë”¼Iè¤5\Sp’i|ªÌ"ô BÀ.ß8fnœ¹è”$G[µ¦n[e¸¦í“ª6»yÓ0`ãÕľG•p„üç¸x°~بO©öPW×'tYƒƒõp<Ä-Á⯅_Á/ëá [²E,Á;}dÔ4|ÏlúºÒ!ÓÔ á$žy·SZšãy€0_:÷²ˆ¾Ã,f*3XÒÚœä"©VŠ“¦Î•‚2 8¾Ù"°­¹Nˆ. ÄŽMXñ¢º…mNžMj¾ª\õ¾ÚÙrÝ‘&ï’t9 :o¼¢Å»y7³6>z³´R¼¹ì‰»èÁø(´†_Î ¯²XhíE/:#X€¡w 6…yº ƒ›|RÉàf82k&ÙP{B®ŒÐ”yp0 žt}MUé÷]0íâAyâ©qÜû¹ó–¸ÜOÎòíþaÞ»KñN{g¬øV[Í ¯/·TÄÌ .;8òqRÍÃÜ¥‡G]y'sôb ‘‡ü“¾-d=¸Ð2”k\«OQ¶C±Ë ’©—*=ýMlãí9|„`ºÜܧȫ¸žÇ#¸ùÏN}¤„Š®fAY8M¾Ð½€î#|µ`†ê¤Èµ†Çº·0X‹¥lÝ™ÑáÜ1ˆ³‘ü"µZ#Á!€` ‰µ¾¹FÅ<ϾäýS[V¡uüµ·!g6zhÀ~e‘+šm!F,ƒ¹—Ýî<•ê;üÆ ËäWxÏÍg€v”¿äEêÒKÔÕ;Ú_ˆë^5ƒ·ê/ˆªEso–ômˆP7}®Å+·ƒÖYáâŠK,Ó|‰Ã¬5‰54 [Î2 ÖâíŽ \Ç%vXu élÀ:µO4a¨rª %ø.צœ9£ÐHz^!¾§Z÷½é|]'çŸù3s¿|Q,´o:@[héU†C” ã š(3–A+Á~} âÙaAÐ;,Jˆâ?"ØTKµ;D•GH¤ÕYÚU¥ƒ,5˸*YØ=X¿L'¤°„›󈊅۽PÄ#c tl·*€&'*p£$Ë2í–„ ;Û1i¯/|ë_ˆ}y$Ó_û¸„µ!b@Ö[Ìzéꈛh¿8†§Ì}q9Gîü‚$Ý% R * 6é%™åMÍý^ȵÞX_(½â,˜Åð€°@Åzr:&ö´öY»×m«íŒû_]’Éùž…ÒÕ…ˆ³ã>©É\;*[$Jo"¢š ?ÙBÍSW‡_"›„ ÆŠ34ÛÑŸ„÷åèQ$éÒ†$à׬ï8Ü».ûe<èAiieaåÆÒÒr<4 åÁ‡±<¥¥Bq¥psiáæµÄèK¥þâÜÿ[ ùìÃzã›ÿMÛUÔ¯®»98Bí—ú%¹@åH9 4McrLÐÏÁo.¿ k«†›X¬^‘V¸7P÷0£“Ä´ôsSÑEµpA|$Cä1åõèSrì e´~Ml´Šð±^ñÂ`F”¦‹˜8) ôA$vÊÄ'Ô[¼ô96ùëfgVgæþ?jpÉoØô¿ÉùÍNôFD+Ö‹\ÄÇ^ĵLQ÷lÃC&Þ!Ó’Tôà†B»Ð¹üh ~´^x¦dëK£ôeê»/I„¦%ÊK9…AÊÄ!An·RÀA§(³zm ö„Ù §ôû4$´–÷Ë*È•o9#A úÄ'þˆ]ˆW¿GŒ*»•;åMû‘D×X¦0fxô® Aæ!B`Å Þm‰k”t­¤Ô`5Pr%¦”šÙ¢‚G‡Í¬éF¹zû& 3ˆ­OñA}ŽxˆK*Þ¥âáCNºaˆLûd;Gk¥Ñê°ø²ý:2Ä󹄎ŸÃðõG<\QjD;!#\Caƒ—Puc=M‹Ùê(¾ hz =V„m5ääFíohª%®UÔ…™ž*ê>x Ò>Œ3øµ3­#ÝË…°BU͸`ÈŽ Èƒìà)Š¡Šê¨”†!‰øU³®‡³‘Ÿ/OßÔ…&mvêOO #Ô¢Ø93ñ¦ŒätA)³©7fJÿà·¶ë›à~NT÷?îlmzgzyúx´› ‡ÝÎÞ|ÖC;¼>ô'¥@J|µ„ÇmôÙR³± Åß­×xÚ‘þr2>Îf£º1-Áe7Ì©F$)à^*¿Úk>÷%§ôûAöDXͧœïÔ ‚²ÁF˜†}ÚX2D£„ô%ó{|jîfÏOB4:JõÏîààËj5aÂ=}ä~ÕµwÝ·­ßž¨*ò;c¿Ïy*Lå‘—J^÷Œ÷_ßZu‚VïV7*µVõNµ²á­=òvÅ{bÏâæ1_³›"—é]`wª6*ºœZ½VQG.ö«ÍææsïáRaåkVeÌ+ì2io·\ÛØ³ÞW›ÍxÐÈ ï›;kß wZ]ahÒ{‚¾Ì,ò}fÙµ~Áf«cÅNï6õSHk#—wüÅ¥¹v™”ÇFÆ1#ÎÃ}ÂR­4Á±tÿ^}pZãþH¿ÞÙ†Àsç¾6ñcÎ/¡iœS ¿Æ}:Ž9%ê ͉qJº¸d> P’Ä‘’ÿ˜J+o´žšßçůëd•>hpu,—pÐ éGROĺª®Æ»â1بܯX‰JÈ®Å*Vþ`7ù¥ÃàdðÄà -¸“uþQñpêqè]ÁÑZ*[‹Œ=öÚï3ØÌ, ”`"® kÿ ¦óÔã3Ô1!ƒ™Ãî𜂇xu¬í?lšY&F@È.¹Ž‚˜‚„“`K1hÛN0ò»(£G|9šäiÔ 1Aã»ð @ðj¼Ï¢ªQ‡ÍXþÂ;s‰û æ\ç€TÄòz‡jJ‚w¦ÅA“È ™ pN¸.¬ãĈ¨³kb€°¤‡‰†|= ÅuY·]s&Š- ñ® Hõ-jû§ÄþÐåY5†s|ªZÚÑVÐê„>; …øé ª®™ŒÙ8é> :¹6º±Èœpá£õD¬Â>$ÝÇ×çÆ²×&u;_²…φWc 0 Õ¨†ØK­ Z¾^ÒöX>…­PÑ=÷ø2b;ëå½ m)X‚¡°ØèO7ùÃøC(°•ÉA|(8ü¶}:y0dßGM "jóm3gY|ä²ìNOÀ¾èõÔ¿=Eë8"LkÙžèúÑxÑS×µ|!Á%ŠÖÏÑ}ƒ™íºVSÙ¸iíÌä÷ÀmïŒa8œOÝ}/©Àdë×Qʤ Èqy—¼yñ‹@ààß­¥ >øg kÑ;㙼 œlh»t½Hfù·UZ0(’°ÅËØµF¤œ4;¡Ob¢ý«“ÄûWC>5±šØ¹'gªœ«vð‹2«–Äœ}t£‡þèXXlâ_” IkÀt D,"H âïÊÈ=Óah׉ýV-ÿ>ipþu-ãË…Døü°l:–ØkÓ¡jAÚAÁ¡㺅 QE0±ï`¨“¯ù>âÍ$“…2â:æ)‘·Ý„ZCš ÕÕð©fž°–n¸Åy=øøkˆ´ç/?^ƒUNf½©Æ²æ¨QßiUkª_ؤ­<¬¬ï´*$üS›Ìçñ´8Ó`ºŽ¨µB/£/þso“OK8Ïì¬óìãEÚíÑw:²«Í¯Ü Zk„Þˆ€öLƒ±í!Hòh™´ûyJ=äö{ÒíÙ’þ !Àž4×à›"3MF-Ú§Sì¢ÜÛð¢óðBm/ ¦}=fñ㜘e*LîÌÀ[îš*5½ñ¼¢¢ Á,ÀDéjb?O¸1M«y‚‘’Ð)SçÁXÌupk*DèhªÔü„ó@b]•Àž4ÖÎlêg:¥?±9ת­ýzã³ÎÖöAz"aÛ‚tСµ®ÞÀ»\º$ú@b’Û~¯=îÉýÛ= †p˜×ò"Š3kÕ»j¤æÁá¿ÝeÐÛt3f0>Í$-K—:uN³©¿îÌý!àB‡ ö*•ßpZÚT.Ï(ŠHÖ‹üž=tìÐ"gONwOƒà1³ÉQ<tOœ·¶wSœ>ôCS{+X pzE©yŠ•1ÀËç݉ìì¯cÌšaÊNŒ×m]ªZ»Ãpdnœ@â„ ç™\«þ͘uV÷eº¸ró9ÊÇìãêÅòÒµøÌÏ:ÿØ)ýað!¯Õ[ÞZ¥¥ª®}Îù z ]‚õüI9wâ?c[WŒM 㢙”eZ¿y"¦ê†H5k_6û¹E̦ú3sÖ~µ ­þœóûõgÓï`0è¾ò×Â@%ˆ|60W$™èÐ|Í+gq«±SɺwÊ›Í ;µkõµëë•ïKûùS¸¦¬ÚèãOî}oYø¯ðò=ûí÷ÍÌýQ°lÖï ¯8?¤»dÆ·Z%åŠpªREŽŽO`Ç}x`–Ÿ(‹í(E—\!¿P(J+++KËË +7“àU•§ˆq[¬\¥‰Ér‰t™¸¨‹êß/ÏÌý1Üüb£õŠóo/bõ{¢wÃÆ£~@Td¤.ëGªô'Ô~­½ý c½ÍZ¼¸Û0M)Ög‹ùÅ¥âÂÒÊÒ¢•8º³äŠËÉ~–_¯§¿S³¹Ò«îþäFe½ºUÞ|ÍùK3üãnfk7»±7¿çíîÔšÕ»µÊ†úñû*úêææø`žúíÇJ"˜ÃoN=  % õ}ÞÛ’í•Ç"…—ÊœPMhJ©ÌÎÆæzꟕúA’‰}úÁSWg!Í J±ˆuà»8Ú <ÊuÕ¥Ü: sa¸åµfÝuÖëµõr )†¢_+«Ú?a;¹áŠ·òñÚÔø.Q\hË¥‰]’úNà=|õãÝæìTGè“liA& a–µî „ü‘Ñ6àêß5±¸%—Ñ’p©¡·c.Pý}:ÜÅN¥Á6¨Žš0®Ò] AD¼{0©ÜêÑ9UÙÅtÀpã ˆ X@„)Þ‡˜[ôZâ}Ê׋ÓÞHnu౫ê˜êêÒõÙaÅîH¹!lNܼeq:‹øíKX€¨¿ºÛøÃ^W ›-ž}7Ù,¤ZvBÓbÁL†ªÔö1â󙛨&Hç è Újò÷‰W¥e1@eIÒ–Îú=R˜‰±P¢°à^ãÅ Ô€ Õö¸ƒCƒz±]…ÈÛ|°›ÁZ0 ,hŠt,©ªñÛˆw5:ÒéùŸ`MP˜î5žm„Èòªgþ0˜ƒ¤2²,½Àºª?kŸm¨H¶Áî±îèåM²Wp5ÑS|:J–I¹Ù™_23÷_CŸŸ·sYè/צ¥èxò›·›!×#¸i”›ëÞsuÄ6×÷$T¿Ê¼Epl~u­Õ¨€[â½róDƒƒ_¿&©©ZJÿaåÑþÚf}ýCC,DgàºLáø+bØ¶Ë `Cÿà! Wv#†ˆæ‰¢¡oû’[)k„J@Hžè~¾—÷"¥'AúèÙn(™£ñÈUŸt !`vÍ Å |bð#Ÿù$w·d*ÞÚ宾!c ¢.¼jV5ïÝ¿î”þ¤š÷Ÿ¦7¤À?êȨ̂7YÙPJ3ÙïAèA‰C3õüüÂ$Œqûn£¼QÁxÕ†ÚèêGHè®;¡hšŽ‚´ßó4['î¶ÈTu sn$U<·×77q5#¡U®W"ùG:Bcá¬Æ «(TÁñ3@pLÏx*r^Pš¸1œC"QÒŠÖ9ÈNYøìÆ(„mq`ÍU̓ìEx饖™Ü2%˜À„ŒâU´lÆÎGû—/6O{Üîm>ÀGt—~¿Tv—ü¥é›hÀ %¨ˆŽÉjÇ\ä² L#1yŠP4;SÍEÃç?ñ»=”ÑšžuÙY¡Ž¤ @V¾hÏ!c_€@j.g$ÛѦ–Ì»Gvgûµ”±—{ÇN÷)ž ,ѳÎÂDÚ +‘5"•0²…dq1›±~˜Œx@o ,‰/í¢¡¾`©ËÌ8' úêV‡îr¥‹U‰Æp8Ÿ0¦ÝøùÉÊ說3\l9®‰ILj=ÈøÚHL³q¿C*;\&}¼Rjbå 2]“ø@Ÿ¥Ú _6 Š'!ï©2!ø2_ óJIüQ› =úå2'ønOÀêbfëedME¹_ãÖî÷l¯oœ7°¥Ye`£Z‘¹hÅÂÆ>&GÜ '-‡y#·*P¢Ø Á'Óbv7ƒ_@¾_O1?wkguëv ‹^Rm= —6_‚tª°ltêns% Qs%´öØ£\î´ÝÞ™ú‡K=H„@<9Èdf¦-lãÓ¬±ÂE÷  rû P(uðï¶KD`ˆ„ö­rý`<4htÀ…ÃÄ×0jÕ=mäæÉG“Ç4/:÷€ÿ¦ŸL¾,¶šèH™½UƒÐÄb?yÝO|d²˜&Ú<¤zG~©ð&wk´ŽZ2a±pMÙèꌠA=ì>Ë{;áÅ;W׊Š…àp`w1DŒEÉñ9Zœ£8gVÈbŠÄ‹-¥Õ„°òÑïý‹ 4¿¨“£XIæKC@é(ãÀƒàJLSüB^ȉþ›NÊE/€`õê™g¿™šûSJÎyï½oqžk Ø{ï¹nó¸{ˆ&\à™@® Á`Sy/8œ³rÐMúŒ½™0Ǿ÷žWв.l!YºË~e¦ô§ôeºÏ4[åÖNóuç»g"ÂöKo)t"2ýîfõà À¸JªŸ†K2è€-ÏP†Ñs‡žyK _qh¥¾ÆhzÉK2ɱUÙÚ®7ÔM€‹"¢áfy„1!!@¨]CµŠ}Ðt/—ƒ™<åƒD™FZZü.:YÁ.㲓`ÖÒy3„Ñò9@„ÿ¨}LEPOˆ(Kø=jÞtΧÖá%òˆ»¬S;‹A¦Å[f ²;|íUn’È—ŒŸÇ=5¥Oãäü`oþ¯œ¹?ä [Kßè|†©_%´µP§ï©ç@ÿ†è'<¾Ãñ‰ÆÞQJK;2+‘HØ(RGƒb[:ƒJÞqðŒm]ˆ©˜Ä¯¡Î Á†mÇ€áÌFcˆkTrÁ±÷88›²ÇÕþ=Ü×ÁJÞp~Þ£o2óY/öÑmèÕa|º×X1h õ ÒD¢Ò‘šEp' 8¯j?hnº¸r£zâí´ÖçÙ5_(cP?BIò0ÞžyEÓ?ŠaCz+;ÄŒŽ˜j/°5FçÛ¸<•/ô× YTxé©­Ì…_¡u摉 C€X9TuÄp¼j]]hÁžG:”eºC ïC…רv¦Ú¤^ä$Øû6ê‹Á‚?'¶zâ$ Û*®,/.JÅ8¹K,D乑+s ¯XX](¬WâˆC)jåZP‡pnü3÷瀷e£ü¨~g«^kÝ{Ãùûzó1Oe6"ñt€Œu/;ÆÝ±§Šš»"̃…b–ðÍp»']‚Ü+Òõ'‡ÿ¥! ôÄMùï¤hÆó=ô „Z•r#ºQëÃÕ²\Q­)å qR¥ëÁ~¦þ„3÷߯Ü\¯Vßt>¡Oo|I2½1°#º±€¨ŒìÁF%QÒ6]L‘1£¡˜çƒ“ÓÑ™wE'$jjÕ<Ë0æ"Gˆ"ázØÓžÅÆ„êM—b£°_W”®t©Téγø+^2Tê3©¹ÿd±êýWœ_mSõ¾:Åè\ÁPÙ4÷š†röÎf½Þ€$w¸‚⺰ÒT;l½|¢‹¿'ÖÅKêÂz?&”.-œ[‘“šù«¥?ðæF/îÀDð)çG´ `=­Ø>ún¶êêÁŸéb”øŽms„¥1ÅuÕ0 «„hñÐ7tÝÑ6Gì Ä.,Ú w8dí*ÉFû¯#SÇe $ˆ1Ca JÜíÖ%w[ŽðNâ’_¨fWàÚö‚x]î9ñº¼éâuÅÈK¼.oªx]îyñº¼KÆërÏ‹×eâ8NçÝåäঠÏ9û‰?0SúïôýŸC›òý¿û‰Èýß~™ ©Ò×u¾HÛ½œÂ!ܘ»„ËÖ¦H@kбj‚s# JLËäÅîîêB ’˜!-ÇèWÞ—îÚÆ`äzÙ>â¶é«18é¶½^Á‰§Øõéæ -Á«<ȃHï×óU£ÕhX5»C¾t×}ûü?^1¢ ’Dˆup½²_­ï7áSV½~wÄê<çTÀò„´çñ?[˜lÿžšÅ«ž^ç'ÜQ³bÁÜç§ÙVr骇iÖ)2Ù~€*;±€ÍÁÑþµÙ¬zGÝöñ`ÄÁp—¬ä ÕÿûVúíA¸êÝX‰×ØÀèÛÉí»K‰fš\XìÒâM7újІÚãÔ#ThÕ{„îñ/øÜ$É¢.ic°¿±¶êNzUE¶ôØkýgSµ{¿2ö«ê|A‚ÁpBþæãîéþ:¯‡Ñü•gAûÅ£aºµ ,Áªc—J±$;jè©:XµêÕÔe'ÞJ¤;?ÑPóÛùPnd³¹¹_´tÐ:ÎI±^NÖ}½­ö‹xìjsˆ¾¶_"ÉS¢ùVŠƒ3óºIêýµà¸Û—¹¿êÝt­ ÷‘w}¿‰·\ª=öuøGYÍÇsg‚•`ÂLÀ·0YÏËo'€üÓë)öÕõˆ‰üŽ“JýÕ¹¿î†ôœNŠÄ%K‘ –·Ž?ì [çš $<õñp²½ÒæF)Œiø¬R¬ÓÖXü5ï­ `9ëÆKG<‡v' ¦ðj³¼•õªýþxû‰¼_míåÆú½êýŠ+€c¢Ø8 ®\I@,qPMŒbã/E¬ÙU0DpYà²süï—¢÷ì…—0¸¥Rß\úË VÞ¬¯«í¨•»åÇh¿ÉzÑß3jšGŸà>OD{ á´h;«ÕLuúbÕÓµÄÜ~õlÿÛz½v¿Òh½éüW4Š–¡/p6áù¬g?c<êhè÷C²u£ínž1hœ’\ÚÖËMøÑøŒ`l1ß(¢0 —Æ2¤ÁµÞKH8H×vâŠ`€” àbˆHéP›µj­Üx´›©Íï!Å˽rCÿWpù†ŽùÂ3ò ƒ¸Ÿè¤„Ï$½øÙo©Nù˜ÐP¿k”§Ðl¹S¹ % x\é'OB›¸¤þ&âHÕ-Çå°+ÖHÅòjº` Œ$‘j®8¸d¹¡ªÃ;ûNjî¯Âæ[ÞØ€Íç ç—iÅ&?"F$ƒ¹_ÞD(FáT[±¤Àí¹ãŸ…M°tz›ÑÙe†¼ n<–íQÊC+ed Ï÷ÕûŒŽ‰Iô§Ú²¹³Fy ì&òª÷ŽSLEÚ‡ñEu‹\ÐÒTTÇü‹µ&„J¿bÛK1W(¥³¦‚…"hb&zm¦)Å£œH—\µ´sÆëâ±`ì'Hä`uÉÆÌ¦eÛ‘JâÀ"Ü)l®SÎ(ÇÍ){e¡xAG\‹Ñqvö÷:sÿ=¶ÕG ]õí·œÿ][½vÑ_l¿ç½Õ=Ra›ô†LÛîN­UÝd/È} ïq@ž‹Þ…èÜXФõ.ˆñÕ%𽤱Ÿ£çt%¸óÆë¢`/[f ¸")Èï=…1 úŒ«oÎÁ©ç\àÀaØÔ|ì{(<+P›Ä¢@[`uð’N´UüEá;A£®?ÚrÅ!”Ô¸¯®¿¡ku0]ƒÕg0 刵H'¹@´F@˜&aö°'¦§¿§þÌ™0ß4/?—½NÐëžtáàx÷]½#Äã x•“9-Â&g-5Q1€€üâÑMñ™º(rð|È=§ß©¿ÞñŠ·<šHê·÷=Uª™?:«z$?ª¶}‚íyõÄÑf$©™ÑÕ ]M>˜u£‹…Ba~Ú"xÁ~ðLe|Ç\+U{-7>x¢J/ÚOЍ-·"¿qÁ—µoN±ÙÔë3¥ÿ”DM%Zoª1xÍù#Žü¬D틨6Bˆ‘lÀ5¸$ pCP5s %ˆÝ õà J¤C9éd ½´°ô±bVÚÏ)ýʤ¾ºœí†º„4«õÚkÎ[©ø3Õ]Ùó: h’ñòKâÚ}J¾N¨\KÞV©º¼WAÂBTó5JÞ/7÷ïlÖÕæ Dz{!H”dª<é©„"6 ®äã4 ³3ï9s lðJò{ÓùãúlQ¿2ž¢zyÔu DÉÈÁUƤͺ6Î ±ådfµ½™²šPÄvý‰`8Bàè⮎º£1lëtk[ù¢¨Fø«Àœ™)†”kwßñ2¥~Ç<ñžA¸j|¾0Lj%%òÇ› (Ì;AÝ!8íŠ~-¨ÏÇÄhÉ$LÈKa8R³oÍý$lquiÙ¬oWæœïKUÔµ©78 2G1éùÌŒ^fk­1¯MïÚ›ž}æÉCÏ„¤‹bl9" Ó|ürÊÏ0"ñ¤0m…º—õÕ¸!‡)p -:¨ÉïrЖLf«Z{è©¿aÀáèå‡ð#&°~T rót~û¼6|çêwR1Ñ”ãu‡G¯4¿óé©blMÒÑ^©Êiœè'Ô©‡ƒÊ$%vÿ~ÿçüy™:ë×@3gB®FqPíb×cT1µ aZ}ûI7l½žßãðÊúö‹JI¥þ~é•O«¾³~¯Òü.çiª5PßLEë{TS#RXc~﨤DÞ§×"ò%’F\uw Õ¡6÷/ñ߸šø—0…úLç ¹e&òêL!‡Þt£ù†‘Ú¥TìO9RºWs0 sà|¡í–š3ø¸{æX‹š3Í” ¨?]Uͦ~Gjîo€í´Z«´öË­zíÓÎwXQšù¡0ß%¿$P Àë;÷ÑØïÄc£Û£ªp0| ºˆ H§?ƒùµ€i)Ž˜#‰ ºÌæÝ2ý„âD°˜ó· r/o¯uÅõM¦ƒÒ¥ÂJ¾T¸‘/•ó‹…8ªz©T(,o®e©:³3õÔÜߌûNm½¾¥‹fó')ã"O3Ôçû£Á¾*bp‚QAèÑ¿ØæýL‹`ºKæåû–kG&ÁÚÊÏ„µ£ãx|bæØ’ÒÔdøhÜUIŒW¹F•×µ|R¤|˜fB‘%$w_Qò^}Äñn¥jË =¤Q‡u…pØ8]ýë × Ýkú‡4 ^©—ÓóqG,ó*áN1¹€$ÅëK»j©;þ?šûŸ‘Âe§U߯ÖÖ•­ (B~­Rzô©çTS@aM؉HÌBÁdÜï~ÝŽ¼£3—h>Ÿ¢rhJ‹<Û}rþx4È©ÓthkÛþIhâ÷™ƒ“:©Ûñ¶*Õ-›1ØÑÏÉRR´« ýn¡0¯ÓòKæùê"/ÓíÌ»˜y˜\N•]7£­Ù»_ÞÜ©4=ÌIwjܲ™t«OƒþѸÛW?s‚žÿ _<=ö{þ4€ánÃp‹Åém2qM·.Í4{AÿÍÎüÍTé‹aµÙ¬nmoª‹áÏ›©†Mä²À‹¡,ñ¥]Œ+¨DÀ0÷ÇäyoQ+Z|I°c¸5FõZèpØJ ¬˜sꮂÀ࣡zœw“R\üŠl àIר>R›§Ú|“̺"š…Aï0§E<¼†ôîºj­œ©¦KOhÝ€–;`Ø%ë$tC®¨ƒ¤Ë~ÓBCdÄþ~ÊDü0¢¬¦µíž ‘£-rÐ×ö±Š* ›Eˆ,·`VÛ o1ž¶šaÂ¥7X™iðgËÂ|NÞËŽ,!vsUkÀpp¶—ÿºÝ¡¯ûjçÌ:~fîoÁ\Ï1pàç4¼&§–Ùø`ÄDÁSîPx¤|wì|XÈEaC¹ëpGQw«‚SúÛ ¤„Pú˜P¹i,pr´Ü$à%bæ ª¢è›—Œœë~l"çÎ:ÿ2Uú;pèAK7*wªµ*|Ȭócxè=PXîÃ>D¨ƒÎð2*ÙüyWútX¬ýGò&úÒ›Â' h(QûyÕŽ@Sõ””2«yóÉTéï"gáN£¡Côß|Ãù­z]ØÏ³žý@Îìß ªITà«÷ôêc9sR¯tKÂ6P@«O9ŸŸsÁ\¶ÿH% ŠLÁ‘ÙKÍ ã¦d¤ûÕÍÊ]`ꈼ=//y¸Å¢Ø¾0N/ÇÛ³bf¡ "îwg2/âLfEêΙ,νš3™u&s§v&ó’ÎdnÌ™¬eXˈ©MºŸ Û’Þ‚‘ÀÎW‰\Œ[ŽqoÁqP]ÁÙP,2ˆ#Ft)V)èH·9ä¹Ç8¬f}‘­)«Ãê0]Œ™Õ/0 3Ãx†â±{gZÓ?LBÞ}JÓgšuçLéEÀo¹ÙÚ§‹Ä~uã3Η4gfô xÑÆž°^æ: ½]±„_ŠÌX‰ó¨éÁ5œ·Y\ŽP¤. •…ò…ޝôpß±Ãq#1«ŽW¿ïÆn‰Ô•?¬ÐÎõÈœÕ&âvVfw˜«ÛÖz•3ñ-êƒÔijǃ¶2·ú>¸bºäL1¡µ1æ6&•§·¸ŠˆÕ¦¯|=*«¢_粊C< ‰KHZ‹tòp[Zcâ À´äF(ØòEbaã À¥ÇÓ5+üâñd]ŠĺÌÕ œHÚ×aÎIàËýÂhZt©m¡×÷©›(áS¹XLœCê"FxLfjªš¡L4LçšÐ!úšÆÌùÓGnžŒRBÓI{8}¥z¡‰í»‡.üŽ]Ô` Þû!ÎÒ6s—Èñk+7ÂD)0Di& LŒ˜™ÅJbÈ{Mp ³Ã­K|–2¯2*Ð@5n™xË´ˆÙ¦"Íå =€UÁnyÑ1gˆü(ÜE›(¯°b'BôÄíáEk‰:l šØVÀ‰ÖQ —*I?1€Q6DšO]»·¶SnÙ1Âíqè™{ƒ§Äc¯à™×}æb¯ý6ÁÀÍFß‹ »5e3ò}¶zç ‚ãB[ƒêÂöø;:Û™²O4dé¢Qˆ@$¶Ž‚C~cYQeDa‚d:ðÛ½Î8`Λ Õ&>z ñºÕ!@ꮸV^ÿð¥Àø¨3ƒÈGvþ 80zÜúš[dݤ£ÀG–Øiün‚ˆ1BÜà›$ $Ù:gd·ˆF\õ2:Þ&,u¹-ÌSHÎѰ{t¼¨G"ôÄ(r‚‹!Ë›V@}ªªÃ.3:JÃFˆˆRòS‡”ä±F0žJ“šƒŽT›7‹Zçσƒ"‡w«™à4ÀVQ&4 ªæ‰<Öj‰é?þ¾Ð.L@EÂ…­Ûæ%º‘zYNyJ(Û·48V²*…>×”´ÎA¤€…‰‹¶JB"wÚ9 ´¼ ÞÚzšš¯¢!µFºM‰äƒ‰ýªJÁ¯ÁÓ<9£Ÿ:åUÙº#$mX/]Ä9øBjî=ÓFùÑÎßs"R«z&üJ-ÿ1™r‹é”‹¡UáÛ†œÙ® z7ǵŒA3ãMIn¼,XºÙn_Óí\«ÂáŸÄƒûÉWÕÓÂË—â”{ò¦t3né‰ä^<77¾)­¼(7ñ­Wñ¿ÉÅs Å ‹Q ]È-ÄQhhlºÌ|êí™ÒßÛ³6ϼæü·Žþå¨[u•ïŽOra÷+6³ÝDðíÍ…›7— ¿¥ €ëjb¼(·¸|ãÆRñã†ÁMÝtæþpj!¥Ò+Î/Õ Ž8–â{j¨I›Øi%Ás„êz­1±EA-ÆõØ5Ç”.—L˜+]G4ÅÙÔw¦æþ!ô]£Õ¨n½éü;ºïðÁ>2 *KÞ1C¿ÛcB€v`ûí)ÁC Õ´›Ë9PÐåXRóÒþPý§º$¾˜éEúå ¡Îì+Ì)ý€*·7ËÕÚw:?Wk>ù‘QºuàvÇ»•‡­Jm£²á=‡(--T 7÷äˆÁ–ƒ¿„t’¬ w4">‡#¶»V¥¹Þ¨®ŸzIä<"è™ ßRºGkÙÃçfÁ %–ø'¢DUƒÎ!¹zHµIÂ'ìlÕš®õÐ˃õ¥ŽýëÇÅÙ‘ K( žÇJ*É11~äÜC¡»àŽ1ˆn­‡Â\QÅßëqpÊ0évïRUj¾t»[5ÐFóDí¼CîixöºðåvÐWe¨ðrÇ`< õätÔQQ€ÂYH+Z fq²n’3æ¤Á¥+ ª¿<èÒå¨cBN¨Cô–—ðîGþ°#z`ЇªQ‘Isæ$ÀÏ‚ØòaøYvi2J—\¨Îq7§™‚f ¡u]‰3ú¡¥<ÅWP-Pr8¢ á2ŸA8¸'ƒÞxºfÔ)ÃõŠ8D¤«X9;å‡éáû ®BRj÷‹ë.\!×lê{gæþνۨTš¯8¿ÊðÒ£ÄY©…ŇYñ%Ljyš.òª“szHÙEænœ¤“¸]ÍÄ`BÅ›qºG;­÷®c‡\)\SÜçW¿š*ýÿ ?ïåL¹ñš3ÿên ãÅ@|2~ swcÑ}¬ÈIJ|ã¨=n4R s€2Ç®ôÂÙ¹‡Jð]V,sònßµˆ:ÉEºÖeǪ,xVákº3CôT)‘ŠrñÍŸ„§À˜âW²fRRƒ‚DO/C¥’c‹‰·!qý€áˆ²f^*¢žèÆÔ£µÒàIn}‡P@°œºÍS‹¹L>5§ª Ë™%˜ïp¹·ð2«I ’Žír w‚vÏg­ ’3óWC甊ٛ‹‹Q^TÚ‹ð 꾓X«pæq1¢2á6üt@?óØQ\÷´7FNfŸÆ'ò2@ÖøÓ—sÈŽ[Ö-à¯ÆÍ'—‰•«;"7Pz”y\”‰KKzDU{휡•p§’Ýp:¨¼.¦´¢©Úq€(V3‰˜6qƒ•ŒNxM›IfL i{Šö·ªÓž¼Àfq E¡Ý]/N•äQµv7ïÉ*¶g<+MËXÌ"uM"?ÞÉŒù‚“4+¦š>ìËßÅ]±¨cËÐøàdD+rÛåÌQZ‰i#xåú>é:é òj²]Éò“n~—öœ[„“š9™ûßáê²S»Wyø¦SÓ(_ŸðÝe;‚D2Žl §U€¥NIk‰dÝ‘M‰X4÷ÔïâÚ:VûQç è¬,µØÞ {Œ%Ýf =~z#7Úv DoÆ"ÜdÀ» FÃõܸ~"Þ…ŽJ/nÜXQ{qq=~åÂWž™ —HN•`E瀂'‚!7°XZ¾‘È…_ÒO0õêÜ?†ã>§Z‰¹±r;8Jª‡l” QEw÷H_u,F›¯¢.ãw¾D]*õsæþ P:h¬«þ–óOu_ðc‰•º aV÷¬ÄûJ×û`üan\¹TNº(ÍHAœÐÔ©V“ˆH!:XÑ’%Q߇` à™ R ;C ÑËã j l`b Vƒ¼0Òt;YıáÇ>Ëžñ½7GùQÑÛ¬nU[^ñÖ¥µ^ç×9›z2Sú§àóÜlm|Öy[o}êWÁ>ØbüéàtÌ1Ãô¦jïê=HLps¸!‚>XyaDz½¼ˆ3¡á”imlTîïo×NÍR]¸î•ÇYg&õÓjkCCqŸƒÁÖ¦Éiá€ÃÁøT T‰%òþË>ÿŸšûgÐõëõ¦½¨_×§ö ì’ÛÕCỚ ôêÜàKÔuޜұ=Ú•¼5åŠ×£?üBjîŸ«Îøæ ;üίµÂJ0á‘êšÊ3KD‰Qý•0ƒ@.vj¹v†œõD ÇAõ~±”[ +Ai5ÂJrM9©ÙÛ¥0Sp•õZêÝ»•Æ·:OóJÙϽÝê¯ò°Úl5ÕÍ1lÃÀRmÍiâ^åë § 'p"^ĘÝËgý¼^(Äry1¼sRxEqM³lk&À{U §6é3‹¹”5ïE>ÍÐñ¤…| t6È­æi÷'»%›aãáLÁÇu(¤ãº¿ÉìªÁ,݃+Y­®V ì{DÙ€¡!„Ë͇bÓ-!z[Kåù Ü¨©+Ls†Ø4ùâȯÅE؛źËm§®2}® 0#=àW ”4åÚT™s2@ÓEÙNdMeœÒÿ ¨QíÊV¹©îr¯;ј2¬ç®»¡NUTyƒœÄæÞàˆ"Ýÿ¤Æðœq c#î@gpM Ö`Xº¡R(p¼O­L˜|j*%¸²ý”}•È:›jÌÌýK8¼ZåÚ+Îê.R¿&/rõýôž^ƒØ¾ ›tz?érayaiá¦ú)È—ÝÉ߉‘œóKK7 7n¨üK‹+פ Lý˜3ç¤gf»úŠó·t·B¢ªá0ú‡¼Ìi—Ùù„…Ñ¢‰ã+&:‘….›`~‚DŒ ŸàäM+Xë®èucP‚™ÃÎ0ÒM"sõ¦ «wáx}/øâ¨‹¯Ú[ŠK+ n2Ý;ÀRÿ3)siY] o®ÜXY(ªq¾¹å—ÌÌ¥Ôx¹*•ëwUÊ7œ©ÇÍ< K•€ô«ÕàqDz±oþ‘°Xx8A–^ZÈ{VñD¿H쮣îA·×ùXGpb=ZAክ#–É…ëõ‰GƲک¹Kqî›×Ÿ b"Ψ1I½û㧇â]µcsü¤ëó<‹Çˆ]x7êyVÈ/_>&â…¾g_H•fSpY¦«Q³¼µýYço;Ö}MOº·…¨ò¾àΜêýGcT (êëýrƒJ„Ùa×0ÿ¯â… ¼ôJ¯¨>üDsý^e«üçç›îÃ'™ùø½r*†pžÚ¹êë‹K¥¾»ôªú´oÚÚ¬Ö* -xðáÚÏvþ¤³,Dàk¨~Ï<}|`\·@h8Š&¤‰¹#níl¶ªP|SIѵ»|×®Õñà%}ãùgSßãÌ}BuÒ+›õ»¥Wœ´hßï–R \dr%¶h]¢ør'^3ŽoƒV9árLЈK$˜0W,& Ç®ãL›y35÷IÕOŸl«â¬Ñ Ñ#ÜcŠYøhkä©Ùð½—ÃKr%s$ ¨å$¨̘çü¸üð ?ù:OB2Õ¡Óºæýµj?/ùhŽÁ‰—ýÒÂêÒŠú/¿‚ÒÙtÑ+®ªÿ‘€û™¬¯TZ]º©þ£¬7âŠi]è Ê«®ÂKƒ~Á<º¯$§^FZu]øÂþÌÜ7¨yò-†E£²±¿Y©ÝmÝûFçêå5áuƙ쓒<Ž­#‹ ö~±ˆO8vìw­~­¸Ir}Ì#žËE3ˆÿk&í§³ …ùØMcáòrÀù"Îì«G©Ò§@Þ$-ðq|Þù®W#*ž]’};,e¶I#¬v³úgã8»ÛÀ-^}îsà>_/oTö\«Bä…¾a‰’ó(á°ˆ£a‘”Ê=v• ×m±Þó#0Sk2Ùª Öw¼ŠÔ3Àã°ªÆVT}7‚äûÇÌH&òPeƒ¶¶³!‘2‘_‰7$݇,%ÒͰ¡Ùϰ4— ZÑ‚˜'ªŒ½$Æèm‹Þáà”ãtŽŒ.5n´¼7bÃp t¬ìqÝ·«'¾ÈïÞ^%0š¨XŒöŒ|€m/OvNкÝs"Žkœ×Vi¯V°³SKH§“7e=k‚œj;ï“7–Lèñø fQyÂ4¦ºHv6åW|'òúz'vÀN/-“¡ZسVµž œ²jw3yõfžT/“4¢©Òš©«èîxDeu”ÎóÕv¸:¢š;òô‚±½ûB½8Žó:æ0,°’Y‡ÚàN  Ì'(6ðÃ.Æ/·TzYð 8㦓UX`ÖG§’ÚØNº¬ê’ˆß>â\Ë­(ËÜ⨧i½y vòJ*A1Fü^-£“Jåæ\µÕÎn×¼âü°ÑÅÔdf§y¨nêÝP\ª oŸ’&æÑu µ¸ºD5ª”!ÔãºL”‹¥*äKK×#7þJgîSÏÔ¦ŒzÝù^#AÆ_Z¸çæ±@w" b¾¢…t¤Bä£$¦ŸÇ}€Nã’ȇº&ðÑx€åÑÞØ ±DSi·Œe˜¡– ¢ñ}q§.T¹û\.Ù="‹³2u¨Y ¸G™ÐÿP}²+¯-j *\õFî:6@~Ö†`]ð*oeŠÅy­~D­ìûš àÆ!bO2Ë…hJx• ÿš÷”t¥.›·)>ßtQ 6›ú[3¥o‚»ßÆNyóuç·¤1m‚µJ bHB•ÎøääŒç™´ú^؉øÑ%Uv`㤵Ój'á—^„Àdʇ*b³]¬ÐYãaÐ;Ó†)ýô»±J©£upŠgÁ@Cã1¦dˆ8 =ØÊbLlÖQ;’º¨*(¬tBF޹€oèb°Sª>òÖøQKåús˜€ºÂvÅ•0S2?X™@_öggæ¾Y÷«Õš:ßt^·87ÕÀieÃñAÒ-EuN×v# :Òe (#ñ'§ÅÅÀôõ–ÉÍš©…N C|Ä™ù,§#sçAx}ãç7ÂÏ®É%æË ÒMè¡ôá`ÀÎ/YtƒI_|¸p®gœrÇò¼$Ã:Œë¿LÍ}åZýÁÎ{zT1Ä^L»Îr)ÔáZÑ= b ˆô#õ'·µ•ÛØðîÝ[ÝÚZm6Ó®Zyð|kkcãÞ½­­f3?Æ?¬¦È².Œ÷ áM¶‡H.ƒþýrc 5ãªZÔ£àY„}£Zj¾¡È'`Ë¿¢„íkUhœÆÆûp²~¢¸„ªÂji9®˜À\jg‹\ c±T\*-,JËlž¹.½Ã¯qJŸe'žtL4_w¶¢"Æn³¥ÄÈ»•=Iáºvzã€3!jºqº 1âo:D™¯®¯Aÿ"fšEŽ— ˆÔ0T;*;ˆ"X/h?Fwž~¬ B¿s(Ú¬7à â°·ó ‡¤NŸ§#O_·õh»B>,0‡A/¬¬¾Š¨!Ÿ6m8‘5åüչς óýÛŸsk±ùýÛ®{×ö‹„›ÎGc¿7¥5ÆÄ/Ì 0òR\XZXX*Ý\(-,/Ç=Y!K!îìzÆ÷ÙÔO9¥Ï¥Àç¾^»»¶Y_{Íùõ)ù¼hà_¹0arÔ»g1[ZYÌ®,ßPÿ.A§/Þ]ó2¥…’—óŠóì¹p¡ IT­«Fi!ÔrØ=ƒD2ŸúíÇÁˆ¼fXÔî)¹qô.mbà8@C0ËÇ·“àd0”XÙ"sëp0¢‰u!a–šû‘\‰oáëé0;s+5÷-`ÄàÖµor~—ƒÁ›k™^˜­Åt-§¾™ÂZ[á¬ÃX8kJA7ꆠãÆ< ‹_‡ ×ieê ×Í„?=·:[º|¸+8ÊEÅ]:, >[&DQñÎýsùò®/<¶“š™/ýL5}> ø4{p4¿æüx žìfJÏçÑ ï,ð Ρîèòœ7° è7f y0„“¤p%EµŸÌ£ðÓbj W E8W”@¶”uAq ‹1mya)7ÈËoâ °™&3|ûJW(M©°¼¢oŒ"ga÷pqê¶®tâ>9n.èBôpàôêf—Ýw#—Ùi|B–¯Ègîêbò¤Mæî5•4›ú©Òk ;4w¶>ëܲìª[™Ýj³U­­·ö¼IŽñ‰Ø3š–Ù÷ÁµI¹p‘õ 4CT'AO*Ðné6-€ãDQ*dšMÀ©Ánd@¤%®©ë_)s0cK`kÑZ›UKöø ”ž‘Ž!oçÐËu'CbW;$c:ȧÂòú‡äx£Ô{䬮0j’Žåïp„ ÃP;Ñ€fˆÎ7Prꉦ vÑégð”Ëą̀_Såmµž±ôçráYˆÂ[7ÌõO]2àÁFïFælPs¤×%’IÚ>ˆò,ùñ¨é "ÃC–IkøÑ$Mèm:p #DˆƒkãlšV¶;­ëïOÕ¿3;ó?;¥oWçügwj`@þúÍ%½êü茇Eßy§½1Ÿè}& ‰´‚$ª”GÜã>¿Vò½f²å¢ £.v€´ª¶ã–“éì> §òdF¼}hÎK±Jëù¦i²ÐÒ„©Ò ÚA@ŠšO_Á¥àjɃ˜ l·bäJ´›œ]µËœðÿdïOàKÓúPøÈ®^æÌÒÃÀ°4¤9ã¦Gò´ä–d»Ö©aT¶ªJ´-¹%¹–)lɶ¦dÉ­¥ª=]Š„@H€.!a „$„l@öHIÈ É—ÜpYnHB.äþÂ…Ü›ü ßûžç]Α䲪<ó ÷Ã3í:>ç¼ïy÷÷yŸåÿTW˜©””‰&”’Q³(ŠÙîÖ5¼“¦éÛï,#å˜=íóøšCL•?šÕ8PüUµ“Uó£zãšxº±oGJªÆƒþ¤–©±ÉÉòs ;ÌU˜÷æó½_ôrý+´‚%öÔö›ëýz½ªÆÁ^uP%2ÞšÝ㜫ý(¬§¬– ôðøœŠÝ”ÀL8\††Þ ¥×‰<£:2eƒ0’^òï|¿[àׯæžWmþ;^š¨á½ßrBöÈ'æ^"nw¬prëGh¼™ÎžP†"n÷‰n˰^´WM­I™dÈca|i)Рм»=ÉÚ•Ç8ÔM°ç~aâPüR(#,ŽÃÛ°¿žëpö«cÙÏ¥Xc¬ª<ï]™ ›ç®ªúŠjEý…Q#$)ì£zg­ðj>ˆÖ˜q%çݼž/çiÜ[ž¤Æ,*gµýZ2ëLYG!¡lv Ÿ¶bfÕÜ!0¡ÊÃÀ¥‹FŽmjâñªŽúì A0ß2=“ÎQLNFƃ¤Ï>wƒ}΂ê$yhmŒø4u±‚1ß¹Päj+l\ YüŒVg¨­Ç'Æu¨Ão³‘B%5œ\dÓ¥â&ÆJ^TZ÷mÛ•A—ª"6ÀqÖó]ó&“HÒ^DGoJïa]cÉ«3äápàkôú,£Fç5õ…jäˆKR(â¸Óðoò7å&)ỦY~,tœú‰H°5» ‡á¡/-ÀeåmØ“ð‹ŽŽžÇ1ÊŠ_5Ïìs™RÉbŸ93÷yØŸÖs¯æYéò¯Ì"©ï% ÊM6êGÝ]\…ÖJ ”¡IzlЪ¥º»)ú[ð±“\‹P~ 7­©€#¤¥§)¿þûÈhê§NŠ™äbÑOá[Qeî „sRÿ•U7¢Î‘lÎ.G²^¢{còfà‡¤€ESÈñy ö99=6ógæ~¶Q\‚ÒF¾œ«–Ê/zßlÔÓüˆÁeå5‹JT׫¯l›~½Eò˪” Sïi45ÿv˜g¶5ÀË™«xB—S§kú·WmÊÉ"a©ƒ©ùCŽÚtˆÓP*N¶EP5€Ô-–ŽÂq.%iõ;ñA ñÖÔ¡O7AL Ò<¼RêOE°ä¸ °iÝÔ`Mhå‘þ"=^Ãâ—‹‹-¥ÿrSÞªÓä};}b½1Õœýœ—}òÄú•réF¾¼–Û¨<í}i *Q±]?œŠ@»®9°™_?9z©¬6Ú:¼&úLÝIÎz.¿ùãéíeƒ.“·<œôªuyÖ·:ãÝhF† U«EZ½ ÄÊ #‹-¾9hÉBHCMcÂT2Ú%r¤!µ*›Ä4?;–k‡~jÄ¡8Ou;–ûó`[ÃGäO%ŸÙ3¿›û|²”6‹«€à{ŸÁÆ–[üp%) ãšo˜%Û/û^Þïƒ Ÿ}ñ¦ššDˆ…$5¡ëËüÉ;ªùö¢aB¦ÃÏ|±Ëº8å°ò°)“”†RòùQ”*ˆ½í–Z"z­ö¥3ç‘Kéœ\ټ±¶*‰ß‘]sÀ2kÝŸP<«‚4\oî×·Tî~Ìê‚8 öõmp 9† ƒÍø´.}J.õ& ‡ßAJj…¼×½ßl÷ÇF+±$kš‡ÿÒЬݯ÷ ½ÙJüvë Åß>!Їâ´!ÿ:Pa&džrrÑlˆTÙÚDb pe°àÓ"ØåÕjÐêïmU½aX·öÑBP‘×Õ[ä>­²Ño0`)¦ãa¯Ûî ·ÚÌ9,sza¤äZ«ª2Pí8hr!Uú{hb‡6K¯ (3\éÝRc¬‡¿†0=BiP¾‡ƒÝÔyB¡¾Ù öÕÎdZ}ÓGÄ™if>7íI}©jÒ$9¿BˆÕW†{/f³gÏ Y¶‡j¾ØE€ΓHMgÇ»òt¹h4®Œ§øuÕ·Ýhìõ¥ôˆ|eR¼6¬7z:t)šòµÅ³‹Ù¥'>Ç~!– ·©6­jisåz^ma[Xµ«ŽFÍOê6À'y©tžÛ]ŒžC!? ¿C5’Z Õ›ŠM"1“fû²«ß6ŠU§}ËïvšcÒšD}½i…ÓñßúëºN4ç>%·1uÆz·—}Ÿ‰ÍÍßÈ«ï÷þ~,›KwCàkAxتÍa†½jˆ!=k€°E¥lù;˜ª}‹–°;cÂijUƒÄ`\!ÒD«Y7¼`XÒ8ç0Ú˜°«Q´c¾\.•ƒÌræ\¸~;NÏ_ 6;wAçìsÚ¸-lÜ,‚fƒ´Ô㭤żPll„èÒh¯Óì{ê¬ÐëèÐÊPŒ$}©B¤xY|³Ç"¤'ˆÐ&œýŒ/‰ÍÍÁ"SåÒJ~u³œÉû;ï1ˆôŒµ^Ä‘/+)úMŽá}`øž7+êþ[¬3ù¨iËš©Äp<ÔÔÙFý¥& c£nÍs¶fO`£Á¦j.bp ùS­puÊ€uoBÊùêf¹X àuÂBá-?\­‹œ4(U¡J›ˆQ/ñïV@ïpAÌ7üp8uôE¿ùQ.PYiï5DóKáÒòëk¹âµÍܵ|À¤‚;ÅRu+XÍWóåõBîV+tÿMøõTsUd —¹P;Ê7ÉuðA°^Z-\-ä{oQø³’WýP¨ÞVùé>BýA0\–×VJëÄýhŽ}·I¹Ø7¨†ÈÐ’¶™ G§ü¾s£/—ß5‘¯i?Å$qº²ï‡:ûŒ¦FGgصa×®÷<Ú­d9ñ³«o“&VϘ用µl2ýûš¨EŠOVÒªq=‰Çeƒak`§ ªlBjé1)™Àe5ÖT»[žf2GZª™c[à-%­/¦­Z{û&b]‡ó I’|Ë7Û¤ß=)P;÷XÊôrJJ(ª^!ôÓ×Bå]'·0{©1­Ïù[jºf9(6|×ñ‡ÚºÛRV=H‰ƒÇ¿VêG% {€-*Ö™ð9šúÒ„ÔÔ‰ûÕ-¬áRK$u«ÆMÓE©ÝátWØÓ–ߺlZm@(‡€Š“¾1\bߪ w•Ø«œÁ) V3¦– Õýj¶úÓ‚Çuq‚(ñ:†çÈÜÚÚÖÂ| 6кpõê¥ÝfFÃ@º²ÞaE×á°CØl¼ïx?’ÊéÅÖö˜šüí.4­ú‘©r]¯%£% ¯>?ˆ±\x„Ö§éNi#h%éoíx­ Æ{È'G¼q„âÕÄ9«£Ñ?Z#oáÖ7‹˜£i…‡¸R'eQúÈ2-èp ~B×úl>Pwœ3y¶Þ¥0du›½ZØ}é1ðRáŹüݬ–Q·5r¾¸¹NÜŠùª‚â ·°]z¤ZcÊÝñ…üÔ-¦q‚5ŠWÛ2²KW˜˜ŠwÐÔ±ƒnód¾*7µák´¦´ÏMxï¸ó1 v|"ßê·46ªÔŽ|ê†E„$h²ii/Û…¾ÊéÑû= Úk%÷•<åHp.®.+ò¾û-–íZ®Œªzƒ§+'WI·Æ¥eÂ2|>oùu–ÚÝî¡Àh ȇz­×m çj‰Få’øÒ'áó_Ë=},ÉC¦Eˆ.‡$[VšMšn¾‚'U™°°BG‡yºS@çTà}銅§Apiˆ›—ˆ_ñ¤Ú=N”êQ¼Ÿ£¼°Ñ~½]#¡µÔWåqVnvß6Pâ®-R‡L8ge964è !GQý.©þæN¾ Fód–dNÈŒ8|j1{Z³3#éX©…ÕamgÚh’Å@}à•WLBT×%S ™ ³´gĪ¡Ô‡x¬ë?Ë9²Y¬&>0ÏL8’ŒÉp.é—Õü0ת¯MjéÕdfÏ)ã°žL8N™6æÄÿ’-=Sm‰®Ï_š.W)ü‡ë&Òq ®»‘¸³„ïdÈÁ·Å}N¾'µ=Œí,ovæ=3Ùcž÷N^ƤxÏ{?êbâàÁµÒÍÚF¹P¢#úƒàzáÚuó÷Vp‡F➇Ùr$š¨ :¿y~IÂKJ²^ÝÜX+ò†°ž67ˆðE§½ ï¾$[¾ $Y{é–×Yãõakç.ñ7©A>ÀÞ~Ä#²6y@ùŒÉ'P•ƼÚ//úº h ¡VjZfƒÄn»Q•©Œ~–YÀ#ÂèQ/¸ÜÄôT¼Ç¿|(È¡~JiÔ2GºðØiá?{3–ý5.Þv#Wfÿ÷ª›æÄú]Ú•ý(ç‘úÂrz9¡/:—=îÜ…(ב$Ü·t*}.âsnqq1›9ÏãÙØ3±l{d±„ •kù[/zßešœhIì#µÞ’½Iá!êžïƒ[Ä+DRञ¶±e{w€À¢ ~RXGå¤ÖÅÌdçÑC òÂs3¡ÞÔŒ˜Ébw8pÆ}ÑĆ…6gë†E§~‰2ƒ”u`pªlÛ ö&Ø»û¤)„°UZ½²²à»~ŠÚðjJÅʼz[œ ïÕ©yÅöuP «¨@}v[Šó-BÆE¤-ޏ†òGcûÒ˜WÛ òÞ%ÉA G•Q~›Òº©˜-éÄû¾ŽØ5Öm쑺k¢…LuuØÐc€<ξI¨öÝÙwxsPãë3\Ì`Mfó¼÷_½qðÌoêà}@ 9oéªÁj6/?®Ùx„¾Æ_˜Ð%‘o<’²ù87éß0ˆYc>C”»§©¼*_¾HÙj`e{7úñⵚÕ×ü¼ò÷-¥ÕùÖõÜæZÕ!ž‡–NjLð«ÓÊ¿³+vâÚ¤~Ÿ-yÙ—!‡’€ý’÷-n¨om7Û#yŽ,Ù|#~§…¶j,­fÝÑÄI8Yø.Ê’UXµ ¥F¾¸ŠÃ 4¶6Y?H¬•JI‰ÝLú7¯ÖòÓn`ê4p¯9Â2}é RǼÿ˜M*ûk¡øïF·kU¯Û.qÀ|Ôö~{Úz 8Ÿ?âÍ¥À#÷¾wz?æY¤áj2xŸï¯u÷(f@ý­:‘QØ{!£Ã‡(?v»L'ñ$=ú„#>ÞìuYÿ‹†!;ª ¨5õqJ6Ò"cï·dÒÇFÿà•ô±?ºÀ£Ñiá÷Þ$2Q Íè×Þ¨W"_;)îûøJÇüÔÜbÛVó+k9už¾ž+®®åË/y]9¥í«öo7{5:¯È{ÁÕRÙÆÙÖh  é¼ã/ç¦d;8ûŠ›yòÈËß*Téb³¸ZòýHvœ¢V‹ä¹µÍü, ô~‰’Û„¢é!Ÿ@!ü ?ÑWáÖ®æo­ä7` ¥Ô~5ò#ªítMí£ÅõÇb¤«íéŒåPj)1t¾„ ¶Ñ¬·}ƒ\: ›LÖOëÞwŸ‰7S’=~%7´àŠ)D„ímc‹ÚîüÄ®{€Å®q¯ÎTÖÁe6OÎO4ã9ÙcÆ#Uψn^lþuÓõº½’ŽCZÄ4c|æº@R6ŸÜ”FHV® SŒü[æK¾ãúF4´"iÍBxË­4d{RÓùî'ÉôÇÞD€Mkyo””>•.…v‚PZ:p ‚¢jaž˜&sšj¡Þ†î¨éháØW¯>úkÙïtM†F»¨ËÌCK+ ëÆ v[&gd6šQa©£¬Ó‡8SøQ®c§¬ØîÑùl(dO=Ì0>DˆZ„iúM“PÍIN'tô8!b›¤Ø2¶›Ú!4G&¤?$÷GÖ¤Cù ]ºá 25’AbüÇL‰4Þå%ÉNœ4ISð‘ÝköS5 ¦RÕ4N_ÑÄKR«;ì·o Z1Ü¥G͛Ֆ*cÄSL¿boÑGìÂGöˆ}5V0ØÿCSM]wHJKáïò‡ÓÊŬ——If-=%!u¯.hÛ.––öfU=€‹H D–T™h¹‘ ß÷뇇ÍNŸ|ê’.›ˆâð ØõwYÿTud7´ÞŸ¨Bj€ÁyÎöN£v{¶q¦ÕQñÔKéýB¤Ý™°uX(dÔI`a ÖÔ ÔûÉÃ^ëÖ höÕ½ùi-¯'3GKÉ̓n˜dv¯ç®H`2ž]¤©KxËodÕ&“¹dó໑›!C#WŸöüŠ’æÇ%Î>IâÅS±““MÜi¶Äü´9h›ø*! aŒÞdGYa óDŒä#OžÔX>v˜Æf_˾‚óÍjiS Ï÷z¿=ÃWwëÉÕù­àÎf±R¸V̯ªËäË¥«…µ5Âvî@‘ÖNúz"Êœ>Ó!¸¥ :\CÀæ´¿²ïà,§2 ç.œ;{a1³¸tþlv1³|.ÿòbú·x~ù¼ú'›Î,åSêYÛO&<§sÉølµÞ­Î޶Øý•ÇÑ4›ÔþÀXzƒ\Èçó&.šÕˆjcE:s”³'+|óڸ²À.“!¬UrßWYpÀoO%3¼jàx£Žƒ.@vM: «y!]ÕïŒ<µÑÃl5ÜQ‹K;  ©t]ÒÓ÷ ñ)yÁéq'Bn ãn$&]ÄŠG»=Òë¾&t'N±!´ÁºtxØë¾¡ŠFÁx™e[Ð6\×±úʘ#¯>³…&œ# ÙæëY…eº[lÇÚÂOÊM=9ÙX-–Mƒ{ P‘ïõÞÿ˜30 ðøá£&ž:¿xžÙjãhœ¸ýsPœ²1€âAÜ€þŽƒgs3Óaì:°â”IV<ø+îÍÆ~ٛˀtåýï§÷¿e…Ú²’Áûßoµ9ø!Žj+ˆk“uÚ±Žµ4C '0Q›Öa¸G½P:µ Y_Æ:sl™§£Çø»=FFÕ0ˆê Ƽr¼ªƒ^9‰&#=öÅÍ ê>æ£O¦Ï˜}¿7—…Nê–ï}³w+qʾ•Úé[!qé×€‘´ó ³]d©’µiÊ¢,'³Qü¤í(µó C|‰å³ ç‚åÅ…Å¥QŠ[²ˆÃÁ1Äp£—`2RD¨8ǤX=ö˜ùÎØÜ"l|$U×Ê¥›•ç¼_2Nxö.ÐÏs£Æ{bæ#,h-Ö ëêè/ÎðãÀ~«á­Ðïi+þ”Á"± ÄCL„n 0$©Î­I'êm„u°oY7;vå6®ÏÖöo<Àq *-Ÿ Ìk²¾ÝvLÌ›ã'±Wàhµ«ã8d­{ŸÑ“N#€}Sɦ+5Ûx½©}Ú£­Èô­$NÎmwŽSûycJV*ǰúh¨Š1…þ@Ø®«åtv"ÔƒÒçÐÙ†st«péÄ[öä2{³ÞÏÏd—Ãñv¥š_§°ïç¼?ä98ýú6FkèÏQߟrq9®IO¡Š^læ¿e—áî±R.U*ùÊçy_2³Òë"j ‡Úôö2FÆ¿ìeG±=Õ‹ÔÝöÑžZ[Y5'#¹Ã*È]`qÈ‹XšÝ×HD-é4©Ã ‚´8Ep§tiÍQÙÖõ³@ƒVØ T ~Dp¡Xµ±¯tl”*¯d­¦ÆÜ1(òü80+‹mk>Ww°¬Äe^ }HU•¬ëâùißÖ|éº6N¡&E´‹ ²Ægô˜ºª&)œÎSÒ )²ß:´x¶0—8ð|²>5ûö?ËžiQµ¼Y\qˆšÏ¾Ý¸<é'wèÑ–ÃÓND«[$¾&[d!Á³}”äe\up˜ï¤®¡ž#n TBç-aµ‘p$Ž›õá.L2­˜Bœ/@°z²•µz;ÜSù%óB§Ó]½¢Iëå/r™§©ųª‚hòŸ1iˆ¶Ü0^lŠWKå¼:¨‘c;›rë-ö]Ö`íÄ K‡lÆFOÈÁ–³ÙÂ¦Ž¶õþÀ¨ýSBQN°ÕëÝ´ÛSG``x9¤Ö°ƒS”¬1V•ð #ËQ:G¼‰Ë.˜տø vÛµåÂ-Âg¹ÜfµT+WÊy¡ =›O½ð2"&„p#OŠÃæ–¡r|»,W‡döÕ}R„š?Üû¾jº:ºƒ‰,ÙŒ Ñåš»6‚QÅ ìm;þëŽMÆúJ®²’[Í'ù“&èvg¿¥D¨„%Nž×ý×kjäŠH÷CCA/m7ÕÄS«u® :œP$‹g+!Ú¦H(ˆé Œè˜FêT¤æC‹â¹ÇA~ÄÑð¤©ÓQ¶r&`µÖ”<€a÷ƒ•Am;2´´œ‹"ƒ ­p`: ûæð™ûÁ‹DVØkªS¿OŽâ¶î»õV»$Ø eá£ôý&¡é­T˹‚´|¯ÖÚÞ½[Ë|ÔwÛ0ñQþF­Õøè|PÎ_UZq%_ äþGÕx4ÁóaÌrGSPM~öX¢7þÅCVX„õ«#S(¤SbI¸ózxÈj¬Ñ˺¨]o‰ŸVøfÕªùHˆ©Hr’Xo+3PüšË%Æ¢ƒŒU­äƒñ –Pˆ“Ž;7CË Ž]€d0&Ãl¼=ÕÕ^S»ùO*‰%Tã£Óg#a $%—¬UM¬ŽhVU€’cÓ#M¦¥Ûì…¡ö8¦öt²$OîÒ©*È0ꔊÞrZ¨+ ˜Öq —Pªuƒ#P²qZÄ¿ü fÿ^ØU²£FBH:/#$6€õÓtHC\9y¿à·h¸FVð-F)Hq=q:ÅÇû|0ä%*€ßúð­»"VRÖÚŒëRKp 0òm×g¥Ùb´U‡¯Í Šä†~Ó!h7fl®:(c’·†¤11C»¯†”é‘!ƒScÇѺv5Ä¥¶pšX½JÎ* qê Ň„âJ.ée3iZV8:lÃÒÞ€½¿Iü*Û}Tþ¶Ðà|]^­‚ êþ<¾‡½Ì°Q‘¼ÕIƒìŽÜ]¦›êwYòðçµ!)·™è”rG\ ¯'ÂFAÞáv|$ݦgÉAê$8˜%g!sv!H\!ðŸÿ&F8‹ÃÈ”ÇS½ûŠè¾ô8É¼ÙØgŲçp½R¨Ön•Êïö~Ò³ Ût+1† r»5 «zL¢däí³˜ ²Ê8X 5‡ÈŽzdž]J©$–•Ш?uøŸ‰eσç]cÏ1n½ Êpï'÷/è$Ü¿iÒ„_` +)Ø›D=7ôYŸbdJ±™ù¹ 0¡äÊùÜŒ÷3^NÍïÄa·}ä¢"Sìê£FÕ¸®Ï»¢‰à¥ËGN2vЬ÷‰UZàF¬A‹ÏÆ67¢˜¾6YU<".Æë¬,¦d‰D:H'ÓÁbr‘þMÏ'‰Ê8d“Yú73?†ÏMÑ £ÁÁbLÜÅ“’>‚axœnYÿ,=2íÕÓiÌÙ3_ée/’C¸÷Zî†:Ø¡ÅÔ¶·ƒ;ƒ}U×;="ÜÔþ¹%aءס»¬^fáV°Y¬ÖHS¹ž«TóåÚZéZíjA-ÕªëÚÝ=†ýLºO7JõÏ»ý“ä\ίånOÊØ> çë;µ¸J’/»DÊ~èëZw[ƒõÈ}-Plw™™„ù¶fä+ŸQx¥$©º(Ñ€4d– ‹XÑÃ˱ImF88hÚÂä\±Ÿ…r ½ÃŽ\AçOùèBàV.´ëEÙ½Î}»?ÜÙi6‚™A+èÛÖG‘í”Éiµ:IË Áõî}%Wõ´`(Ú½ÂnT)öp[Îìäýéæ.L}FSÏ#8eaOë ׄlæ³0ÒÁ!†â=;@oˆ­C:€}©Êâ6ö™!PI§‡(¼‚óá¶4‚ phDi› -¶$OH…¶Õârœ¥NÛ5n~Ú…ÎàÛš#qh€QÉtŽÜ\G´{ióI1Z»êhÑ%IIëÑ%à wÙ—¼³Ý!¹¼Fa·/¬;F\äÐwn«wš¿»åûaV¥òD¸ñ2Ã×xŽ–ì‰JÉÎõžöÙ‹€Èð(ÔR)y7ŽxÎ"e‚‰Ýo”@éß°G±@ß)™7\eÿÀºqº¶wÄà|~X«ÀSØÍÑÐjÿ`Ž¿W«ÒAk§«ÎAâÒ¼Òú°CÝB¸=€‘<‰@‘)t«·¥¯G«Ç4\ ‰y¦R۫Ét“cšÒ]Ì€×/LÒD›j/‘I»qHÿèÕìR0¶’údÈ'цfy¢ñ®£øRmrÚæ;ð¶ÚõÐp„­WN»]‚×&Ø’Æ|7²ª©J¼òʼö\¹äâ ’EûùÊx‚›ÔÜ[ÄñqK<žÇ_ eZÌ$s Ù82ì@Kë;s–Ã#[}oIx¸Ø,±DJ4Z´RM¢á˜rM¢¯¦TádEZ~¬t³±?Ë~±_W×6+ן÷¾Èšàq08+9Æh®Ý,ªùZµT»R(*Aƒá2vÛÃþ~MìÌJhrÿ„lÞœ›ÓÊmµÊôyÿaä ÀFu‡}Ëþ¸Ã>¾C^*wŠ,᳘òÇ—©d!_¸{•nC ¹Ø;à-”ù[ˈ¡×·¦%Dõ§Œ»·i¼Ø™·æ.«îx/mYÖK—·­ç½†£ ß´o<0@oÉÛ'a¬FÑÍ0NÅqtx}ŽZ©bÀŠæ- ýÝg¿ Þ’.N+h šG0‘åBˆ]ý 'NØ¢ïئÊYÒA"éàX Æq$„¾«x~B Õ áIñPÆ’NÞk1®ÑµC}°üùP|¯ÁwåáÂß'ÊS ‡u~V·%&6ú ¨ºAÕyV¥c‹.jøñ*Ïô8WÀÑ|˜ð4÷»‘o¬ êéÅ€æÒçSéÅ ³|1{áââ¹p–®{ü›æ–#•ÀzGòQÛEè›\S¸ÆûäE‰Þ…«%«¤j"«Ký°Ö¿ßTh¿¶ÓòmT±ÊX’Œ{爛 “ÇÈì™Ë~øh4D$B-<_s&´ðèX_à†s§»»«*˜gÁýé›·$ ]£Öé$~$‡¾‰§ƒ@R³Z$µ»eÓž Äx 7 %˜Ó$)Ã#&s{ŒÐ© ؈¿W dKe$=ãÒ8Öb›W§ëd—¨j}tÝ|}Øw\ ‰×YôÝ,ô.@î‘d»0Tì’Ì]2%L®Ä9Éwuæ¾ÉX3z Þ¢8«‡¾ñ‡ü#Ü Ã$/ dg¬$¥µÈ†f:¨ïî‘x›­’•-ÙeÇ÷º+ajŸå1¾ì> ‚¾ýE\8î aŠä`¬Ç’ž‡¢¤Ôˆ#Å»¤!—>üáPÊK\'ƒHÎÖœÜC¬žaÓ”î_ªÍ‡Œð[ÑAý :$<Ô0žf«ïc‡¶! æ§QÖUŸP¢E¦Žì´R œ¹#6ctîSÎ +ÁWÒ¯!KíÕ·%Øöµ{mÔÑÃØdÈгiå*Z²ô ˜ðo4­7ûÔ¡—ýBpÀ®æ++å•üçzóOé%îM}xZêò-cF£3ªG÷[톒¡ÌËÂTÖwå£ÑWâþ¥}^ø´æSxÚ¸s ÈGims½X!WH•âÊi˜2¤|÷{»BÔ‹õ);´‡²Ð'¯Yž"q5“õHÞeá»)Ñþ8ÌjWx9°ÿZAiTí°×în«eE4MTTûEùÚ’èB°VÍòA½ˆ.Ö@⻳Ô3„V(-ÎÎ{­œ+:ï¥ ¤L‹L „½æQüÃqsTŠ/hxCP¢å=ôG­Ã!ö]&Þ(êò OXýRü¥¸V<‹B®Á§âz{Ì íÆß͹ïêî¨RÙ  ~,´äiÄyh’ —©/žYpà·)ч‰Øé¦Ô½…ÓÍÆ¾:–ÍÎ]uu5£¶QÚx·÷Á˜5Mê»ã¼íJfxoÕ÷[Æ1……s±ÿú,$Ý.úÇ¿‘+S¦óó‰šðª« ØíüuPÒ²% =çk²eóm(ç|·Ìó!Øë |¿Éî½f˧­O ?‹Ø™aöŠê’÷ðjéBn=ï=>‡žžPÙŒ¦ #’Þg'ïú½z«Í~h!ÛŒÚ+˜¨ö «Ï´ºË·ê®à Ô]¾£î NOÝ"Á¶…Ú›´ /Å]Qí8Ï‚ñOÍ=ÈJ+ªÑÐ\Êìn<" ‘Íhq ‚ÔßPÓ#$(»¹hy„Êûñ¢«ÒÈM>7ýáP®ëP µå˜ì8™OЍ!ý¨A ¸Úì-¤P²DFD—EÛÏHíz½‰.ùîSÄÎ]òVâYætèÐÿH,ìüf+¡7O.GÎí£(?ºÍb·«¤üžúœÇÓR$y89ƒh’gÇ–"®oMΩR¿«¤„x2H-F²ÀíiÒ/'ƒhêÙ1•¤Ü©%ZE²‘Á“QÅ{³±C/» ŸàB%¿¾Q½=ç=+ôóð¡HìEƒRé¦ã*ybìé˜v»ÐO“ ÝÐÒ8k'ÄÊæ”ÉˬNBègâˆÌG›Ã)[?ÌС©+)œ•a©¦qyϳÜêÝEK§œc,ö9sy‚ƒU}½þ¢÷õ7°{DÎ"vA浽ݬ° 3À:ËŸÓ¦†~?Í—#¡ä\:5ìeN˜—O4"gc_Ë^Å™­PTrhE}·òyÞy\;.\Z-°i,}³Nõ…‚¨M|.ÅQÿ¿7ÜÖ›ù^ö¸¤õ’÷FÄlSÌX¸3Êœî>¿“˜—#ßuEÑwéEY¸O¼ÑÂWbaøH õRíOÙâDDŽDüi‘rZƒ¾¦¾äƒ‘ÑÊÎX½¦o˜gÕ‡ÇS_²zŠßsrZž ÛüP°›9Œk+UÅ=•—KŒ)nflÚÍ{Í6|g\bËréfí_óÖ‚€ñ°q¯À:å¼Î;@M †â¨„+An£àJ¹hÐÉb2ˆ’dJÓ  ÓéšÕµ¯ÙI¹ç,P†C qNl­Ô/‡ˆY@ýA­m•Óâ&«ÚÊ$HO›d6öa/{þåëWÊ«…ʕԺð´÷ï<üÙêŒ^¦XÐAë­Å÷_cº¡¬š¾ÎCdP뙩³ÿ$ßôšÄÉÊ2­Ö×ÌçT·c·ƒm­÷ÊŸJ>±ÙÖ\8s Þ÷.ï;Ì‚Àw ›Ú<Å85ªáA›Ä¢ÑÔjz éh®%'KÚšˆÍÁ“Ùep¡©‘…ÀHïR ´:r²KzÚÛù¶&G‹0öËôYOcŒÐ:û”Þla~Ã"±_'O…Æ4R¥‘˜ßÝ6Œ'½Ib8xZWÈ2bkSôÚî8.´çiŠ1ñ9^I-æCyÀÝUZ$&Erë$Ý廦MŠ‚uT‡–Ðê¤j%¡xS£Í´ÁãøR´ú;Ív»Þiª­b2”M‡’”v‰zr;¹3oá(“Ùäâ|2±DÒ¾´™HxY¶>ÿ²\m+aæ¤ÁSÇ•zvæçgæ¾ àF–¯ÃNjވhø©È=7Iºõ¨ð7I  Ë%n›GSȑԺüÒIׯÞÁ‡Î{MŠšè±¿ŽÌ„vsw`ε„ìàx»âõùöšû%_¥Ç}©GæÜ{ܧ|ó~ä[Ñæœ·ÈuÒ¤úp´DX3Ëñêýf½Ç rè¹…NEnþæ(S¤|ñû÷ïÛ|Õé0¾ ~Ew楉‡Äc³KEó³o<é™1û[ÙW±Ÿä‹+¥ÕüÛ½†Ù|‡õbJª«ñQ&ßÙé’w¼‘æø¡veÅßX¹É¨Ä:zÃà‹F¶J`ç#óyMÉÌühÙ!¡527ôöËšð6Öæ£É½Õß•›\>Y_ ü(\uöº]ƿꠃ⠆psãï†í¡?ÜÝmí°ÞŠ|M ³ätCÊedX”cbb±™­ìŽ`ûxÉûŒ™ Q1xLC'zA!1xŽ‹¡;„Œ/»‹ÆÉ“Œ ,E-Ýdjr¸¿ =ï‡6tò 3Q3Ýö¤xx;[œƒˆMÅ óœþ,Ö”¶}F°ÿj½i\ò‡ý!íÍDÆNU—V_2×™$1„i‘ãVùá€Ú¶\|üij3ß›[‡Ï—¦?ãecQ„§Ä­äjd‡“ÃØ­¤‹2Ó V£à´hŠUMp¢ê,+|å:Ý0ä.¹¡÷ ÷ê=Õ’«ºgŒrwÐõ9¦oUÃø:[_4Ç]GJ¼ÅªV˜té´‚TϬ£™èsõªi¹ÌB6»˜Œðš¨›Qb=ûþ… Fß!â ¿Ÿž?ÝÔ¼›}ê¸ü³Ù¤»/¥hpâÛé…ìù¨ÜQ’ìyÿÊ“7´7;û±¹"bþË[©æÖ7r««/xÅ,ŒîýİÓ$騧†@1ž¯‰ë@®!³xcx50Yû|êáDZè!ø È’‡ó®Ê—Oø0m,&5xý?zC÷“>/›²3m7B”Q~‰àj9·R«äAyà'Z÷kÂðL–.º Ö ÅM \/m–“Ájîv2¸™Ï¿ª”ŠÕëÉàµÍ\¹ ‘nϿϕÕl¸¢)¼n²âª/²K÷3j Z/"‘> ÃM}”Þ)§Žƒsì,¬Yvß!HQ Ô]Ä´dÈ c9"X0‘¦ÒA’$7Àµ—<6I“µWs·õ†\Ôª•B-dS§¢âèÇøÛ,á&ìðÔ@þL”‰ÓµÒu™$h6SéL*jní“ ¾˜Î\L§£Bg(Oêû“åx!~J˜Ïæ²%È.ðSxÞ›y–ü°òB¬c‡'¾1žPÚ÷ ø6ŒŽ£±¸9›¢4&ø ï‡lZÇnö¾Cð)|fÍäÒnð¹ÍêõR¹2Æ%¸ÓnÝmÖº½Ú}8í˜X޵µ… }|çª:­o…<—'‘sNÊ¿¨NW6«¶P¶<͸è>Ìß´bë£M:lä© Ÿƒ’rä±Ðrh¨ÇУráÚ5ÕV =úÂBþ&9b;t5*㫟/^+ó‚8Æ­ö¦ÄfÁ¹µš¿õ–4tEµPîZ~K’HcqÆ£Cr¤Ÿ¨Ý$©i&a´Š=òHŠ2¶èä¡W!+ üÛNÌÑ*ïK«WtÔ"Ý*mä‹Üü•œµMÕ’Øöêhm¢!•²+nÖò×tËJ‹QâJe­P©ò}H®n‚Å-ükk¥+4«ººšžc?Æ£L¿q‚ÊNÑ.2LOöò˜rßÈ• òµq)Næ‡R2Å[ØQŽÙ¬«œã)çaãܱϞ®\KaŠmëpRº ÖàÅ’ &Éë$E”³ÇéÆfùZÞg°u|ºVÙÒkæ•B1W¾M÷Ì õGh6I:wL0bÆõR¥º!¯øbW–H¢(*Ò ÷Ý'ÐóPâ ‘tœxš58ÒÑ1Ñ@Ž`®6ç ä`O²§^(vw)n›ñYÛ§ÉâÄÿ|àøw@¸ ôkJ< WIbYÔY¶y£G¢ÛÍì÷îï¶Õqx»Õn H·lý‡å8Îhì&8†C>™Ñ·SÚ’L’ÙØ¯xs8Ÿ^£-¤R}ÃE¬ï1Ah&Iÿd…V”ü¢aÒºc[³\ìèØÛƒû`B0¤S”KcÞ×ï ƒ±ÌÕ{Œ`Lf̰óyÐR"ÍH0Ū²"e韎H¦þÙè 0z¾4o..-¤“‹ê¿eõß¹³ç" éÖ¤Äñ+ñd<§þ[‰ +ñSàS}ڟɾÌiš f™}Þû¾§BNÆÇ­É'ñ9gïÛŠ Ëm#Á†}±…–VÌSQQ°±94(¨!êƒVÇæâü©ü–MÈãï —e=ÁÝÅxÀ|Št@(øUûh‡ã¾×iÞlH8-gA’¡@GÔ1ú:C‚@ä`{'t›6wR[Á_ŠLðˆŽ/Є‘jù—/Œ 2JO.Ϲ=êákPM¹ÉHèÄ㨓ŠoÆ€‘ñ(@­Ø@2°»R˜ƒ"{xÿÔª;f4%Å—Ó)•9@_™*<¯“ kz dfñK²ws5ù²_…™~àà9£#ÉÄ\§º®QRª±;Ù•9€Ô©Ä¤²¿„b¼¤ -#sâKªÏF9]¶nñ'5Þ Ž[Kj¢nK}ÈòES]Öï’S«)Cä( S?Û½à~UÂìu Ø/j#%²Õ›˜ªç¾Xå¦ExâµaŸƒªœ,ß4¨ûAOMU,57Ý;zœ`d»RN§™“ØcìÓ²Æ>ÍW£Ø§êÖqا9§ÿ¿ûþˆØóXsö‚÷u–y…î$ ‘‰Z¥IIÈKJ jzy r5r¾Y¾pªj®W¢fU.[<“¾˜^¾˜^Œˆ‹§¢xšýFl® gÍ\5WÌžñÒÆ ‰ÛÉ[óÉ€žÑu¸‘꽞EMk>€i©[t8¸­}ã-Z’oÆ”lþ‘¬n¯À^Ò|ƒ„zƒ}Ú9’9 nôÃb¦Àªí†ñØx |œ¥mùئršæŒn¤ß¨ÝRÙdÄ@J/œ;¿¼xá|æìââ…sKËQ„UjãBb~ÄB±°|.}îÂÙÅìÙs–.œŠm 6›Û·3hÍr…båiï1ü)aï§çv†¶ßËø&žþogE ÷PNÐ=¤V1ë$ŠÅ[ù&í$SŸåžö§B8º{™àr±©kauç1aCdÇd@1äA&ü2 ·+ÔÇ“*½šŠá»Yuª“.ITظ̃èmÎý.·ÉùùÉŒÆÃã'ýùŸŽßàlìŸÇæn@é»Ï ÞûÌÒ‡¿Çm û`YÕ[‚K¶i Bb 츘,ÙE:àÒâÛÝM5êGZ£a]nN°EæTâ‚mî:#n©KÖ*‰^¶Ÿí‡±d²‹§ºGýÞÈZG 5i‡ÊDÏÆüvö\VHH#ÇðsÙS²¥<3Ÿ½Éû=>û¼÷û=î𹞿‚ÕB¥Z(ªÂÙ˲v·¤dw®®]¯m” ¥r¡zÛÜ%j“k׫5øëÚ»¯­Õ*ë*ßZ9_Ù\«nñ-%Enl^½š/ë{nê•ÜÊõ¼@+Küç–~"¹ãd|Z%[j’('Ö˜c®¨ñ>?â³/)Rkæ,ËyݹV.mnWno:5þÀíoéÒæ*+n³E_VYª×ƒrimmscKr¼ž»þóñŸ+•WóåÇýÜ–Ö]@küæµ±zÛ^—®^Å Ìo½%iör0çÀ-VWм¼MΙ¥Í*!gÇÁðÀÀÙ(q·7Àʾ”÷;s®n®oD„ßP¢’Ø5’æZ·Œ!âÑùæWU’ r<êë¥Õü´3<±4LïÀAµ¢1¦øæ»ÎEš?(&ò‚ ©³ }$Û*Ñ—8XôÄRÒY€lŠ8°“…[ÁuÍ·ÁªÆm‚‡¯QêFåðS·oޤöÙÛš’mýáÁ:Û[÷~ý~ ½s]#£Ó``l7'LE¨r‡':Å!Që’¾‚!½¦Ô$P+Êîœ>Q,ö¾¹[j¯œ])UÏx÷,H©šˆžövºÎíÖi¡nGÄ |==?á¤N@‹Ké³êütÎM97Ýô)–fŸÊÎÌÝVôi#^Ï{¹XÓc‚KÓ—MÀ0 %²ï²L$á òµU²¹å‰ˆy…^ šµF8ö:p ‹õîáõ¶§R\“â‰råv™Ÿ’Ö—¡ ¨œôþ×φ0:ÜÆÀñoAªðÅ×üSÆ”Íß#0UÉßR”o«SÏjîöÄ÷‰ ¡bÈtŒRðr@ñ¡7rkÁY’›'f‘/B;ññJi˜#ã•:±b…á2Õ*L+z_È®ñcáFõV‡åëõ£…øÄ VKÇämI &ý¸ñ1PÔˆø­58Z êôƒ’\¹ùGTC¯Ñ&OZPÏGä@âu¸º/›TH²3}¾¸úÉE¾üDóZí)³ 3ÙÀÿôJnåUu´ ¿“Ïð~ÁøŸº÷Ÿ¤¹fÚÕíñWÕýÊ û i‡‡¯4Z½&8:ŽâjU›Â.‘56ì!ÜdæÏûÝÞ]ö„D\Evòö¨ïp*rD•ãý–N´“ˆN‰'€¾¯6üÃ:9P̲‰Ð5Ö{æ~w°Ó=< (béšuøn†ÚA½Þjš =ùœ©.ç,Ê3;™‘9ìÜ}ƒBhí„M2';ƒì3}íQ°=$Ê_²Ût€4ËÎwYÁárÒ÷îö-§ðûi”»ÂÀ”\¥-¢o©ñH [X¿½Ê¬{TNÎ^Ý,8 |ºzÍía«=ÐQ„Øy¿ë&´-b­·+Ñwí ㆈaLÓ ÕI¼Z*‹¿Þ´< ÔA)ÞxC;ÿ¸I1g>ìÍÝŽˆ§éEïkÍ„17æ@IBšf3¢&tãÍM(_ùðdÝzÂЄÖÕØ$Òg"`ý 8hÈ:‹pŸc(Ž4>ËßNË롌,ÙyúNÉßB5Z÷0öœ >¬–ß܇•¨>šÚ¡j^¢H÷Pa×VÌ05ß Ãjω\!>#mf´®å°iï4h+§*̓Îg©VS@M8«†:&Èý,¿^ÕiŒ³3Eħ‚4è½n[8.T­©37V:–U‹5ó1C¶&DÞÑ2»¨(ÂùP·l·»Ûj+j_¶£6þÊààð•ÃÖŽj–f<¼UóÁ®Õ¸œ¹ôd|1ï¿d¿ô¦Çn[ÍߪÎzß⑺ÝhßïßÜIö{­Æu ¦%5.KÕj7_­Z!C=TÊ…ÕiM­~J}}¤MOºãŽO?ûÌs±ì–ªøg{ ï&$l°?áóÞw?í.$Ñ}×yUÎ+»jOò‰<²“ötÐdhuÓFØN ]{°¸>&œa„ÜBž´0S¶p¢”áËÞ)ê8ÝÒ¬âÚÑĄޙ¡Ne‡+´[bê <ñGêMô¼M0“QÜ-ÏÑQÖ[Cœ‰¤lý`i!c'-y|nw¡7ºÙdñ …)ÙîÀ1„]ç÷ê`äöÍýNëu5†õÑæB2ÄÜü¸Ö¤ “ا¯˜…ÒÁB¥ êl4Ðb ™ä%|¨}! ¤.³ø0ß]½×n„îSìŸm"Ñ¡ ²~·ÍQŒƒ®Ï==¾Tîãë'hFƒº1<8$=¤#ñžÞ&7KKµÑìñJ½€ç…¼«W ôdõÊêEʈñãƒašÅï†ð‰æFë«®&—ô„eïðPõéMÕØºßl3ªo‚µ&”íxaÊZdºŒÒÛ|t ôǧ Ñ­7XþMaD¦¸d7<©êî˜L¼Ù™¯óæ~/Πdݪ­”|ùnïïŬ_´½¯=¤ªnèâŒ7¼Äå¶:ÕQØ7:ÂðÒI‘æÑÅx©äœ$`âãPë j¬S§÷ª–¦­¡€<¦5u¨øw´ s‹ iw’ô±—™Çø6ìÀ©F‰Ë:°óA±Ç½5ª”píqê+&álE>UÉoäÊ9u¾BóÕT½ nŠcØÇ#jãþ`ØÐפIÁO¨‘ S¬õwÔ9ï¾ÃZÎa$-ZÊÍýÒ“:¥ÍÎnxs58à@x®]-•×sÕ¼o7 xçvÖî$»QÏÓ.®. EšŽØÆZÚk8Ð#‚í.G½Óôxm&ÜînYy!•I§ÒKA6{1»ˆ`ËdéfðÒzðÒí¨3|eØGDIå¡Ê@êhlf4ûs㲿~ñ¥ÖÅ—ú#šúãòÌ\H§GòtÇ€ûi5xé(x©¼Ô^:^Ú^úXô³KjeH§Õ2: T¦™4êdÏ{D1.ŒVmr1®/Ý ^*/õ‚—ªÁK•à¥û£µW9áó™4çl¬›¼QÀ³*ЊrÍPß ^ºý‚zå|°œ}T—MáÿÜShèSñeœ}×ÌÜG™·¸r}=W~õ9¯czs“aw’f­ƒ¬~ä`yi.h†P±ÆOZR5ØFûˆq€h·d-˜ ¥‹©ˆx@­(Ñmç®zŸ%pò9è÷9{ßf/^E¼ÃG¢zû>ŒEi~Š•š¤tÈT-Þb|ǛڕB5Ȉ*0lDj}ä “P¹§4ä81#kC!î`›6“¦Ÿ¤`èQ`2ší£füQ\ò<ͦùÀ#Xã'|aŠŸcœÙ&!00º,-œ[bB—“²ñMîø…zl®7à¼àýU³ÁàoÚY"VÞ#°7ï zCÄí-Œ1}Àì *´?”9Jtª{Í»=g©P+ÉùÓñ›ýœß;“ÝÆþëDN?ï}Ú焬¹' ¨½iƒRôág,gI=rÆ1Ï`W8š Qƒ´™¤\\š‹á€?¡Â†¼YT·ê÷ÊÚ&yCûê—Ú  “1qÞ}G12¯ƒuXc2|m8‡üq㓸¢8Ñ4á"ûôÎ!6j¥E:9æEÉ ‡TÁÿTòÈW¸‰EÁ0Ư]ÓÝι›44`²¿¯Î{~£E¦î9N•_^÷ÆU(Ä÷ÒÓfgeÃÝ7…A%ò‰ÑžM#x¨Y>{"ïðà1:h=6’rÜ ÃYIE3Ìd·p̲í",¾÷&ñEÑ´n¡ÐétGÊ'§Yy¶Þí´àŠcÌjÇ’ûp"_6K2YLÛR©Û©þ¤ö8›8‚L¥¨j÷ƒš™ŠÕÁg9êŸ@^( ³41:- J£G Ýúä½>7x7åx‡çO“ËW‘üFÚñ¹(´iUF¿;ìíˆ9ã>ûME55 A^Ó Áû»ÝvêC”ÓŃæA/ìŒù‚õ'#¤aï° B© w÷jý£>'UÙ´ ×¶;Ô[¤$Ì#›3Ètc¾±O{Ÿ 2•‹~_ÛÆ ˆ%ÜîÖPf)ªr s¾Å–L• Õ X¡é®¤ÐÕ2Áõ„Cõ'!æ‚„„]ô*2Á²ðÄ"å „h(/Õ “0y¸ØêÔî×9¨ê˜ð^»»s—ÀW¡0vÜzˆ“ˆú:~:5¿·$œT$m7Z˜nÔ;N‘Lh<©ãPw"7£=ÕÁá(C·?R‡pdÃCGs/Óë¢JÄ÷ ¿³ÏД¡ú6ZlD€FŠù¦lcâ>^j²sJcØ3.N:9ùmއö;"ÖD9 ›Ò±×´‡(åü‚©ã‡I•äÞª³¦nŸ …ƒÞ‘œ¹Qʾ.؃æoxH³ˆR¶ HöO|¦9Z:)å’ &ÃFodÓžYL$ô¦Çæ_2l“Øí‘›bà Í~W4–¾ÚÕ©<Ú¢ÆU 7@ý€X¹‚0}ûó0øÒ´àîÛÿIÍ„€„¥ÙCLd¸Ò¥â<“$„Þ§PŠDéêUЍšÉ@Ô‹Ô CpÂu óÒHFÝÝ]Ì J†UÄ,ê¼–/Ú~ÂåÜŸz9]»mG…—ð¤YïÉpÄCkmdzÇäÀF ‰šwRÒá”ÝÐcô²*$„©Ëé$yšuw/g3Ù“æ\ÒJ PãIÎç%çó&ç³gÇVd\Î8LVÔ¢f?asÎHΓ󹥥©rÜæœi³gOœs¹¹“ z¡×l™³ç—u±éRçm’q9ç[•Ö4ãrÖ]ˆ É5³xöde^#ÈêðkÇ´FæÂ˜|Çç|EºýçœÛÌcs® ·Õž4Àr’œÏž?qÎ+ðN™¢5Æ6ÆøÖhw·'æ<:ž³Sºf ;˸œ—»5xy BÌË´7^Î,//=—Ô7Xhô£¥ó™ìYZéäi Ú¨qÖò^Ú¤VB{£=æ±ÍŽ­‘7ÆÖç$?ŸÈ†  Í‘…³Ñ@ÐÆAœvN‰ã$îçzƒÏξ#äj^JèÐ9ÔÑ9H¶ZÉ 7ˆUdhþ¾ÇèCÆÃäÊ €d•xß-·Gq”dŽä턪\¼/Âðõà9 O»ök©+£bÉîÆ¬Ï$>õ”&iñHÕ¼WØnxXoõ¦vö¥/ÖÛ²æÜc¦„íéG¼ì¸îйõ<Ü/*ÕwyûÆ kï&ÈcƒJ±F±³ŒnB8Ô"ü¡ñºc)€û6éf=ìp(1{êp8p×:‘ñ(B Œ]èÛ¸by¨#îͺŎ(À;d–\S&Ä*~äN)mXÌ,…ïž"¿ÐiðýÄf^Ï6à>UΡ1_Cú»¼Ï2 î}ÃìˆjiqÒÑ¡òF/ìüZ=ƒHä×òUÎOGø9)CV´ÒgBÅzFŒœ}ø„1·Å¶p^ˆÒ,áÞ¨ T%KŠÎyž-)Ž£–Ô$¤·¤Ñ´Ðýpl±„ú¬žÄ>dªŠ@bÊÃp´UÆ™™™E÷ê”íf³ã뢉QeµŽwRUf9Ý“{­¯¡NšwbøýÕÒÖ©rZʘ‹}Ú\“)[©íßã½a¬ÖrKÕž€4þPݺJH¨Å)¡ˆæ#.f™@J€Qg.i„È_!ßµ?«ÿgžï36óƒs»XJÕZs#_®ÖªyÁûÖ˜ ×ÖwAçâÚàãÉAWýFlƒ}:ÏC¤Ga†Ÿ¯1°nÁtûãˆ~ÑD ¾äªÏä£oô½‘ð#^ž¡{—e¼ªS²9´å‚ œÔÌGö}ä—([ú"ìtcÜ.#8µ­Ž*`kZrÙãÝ~l$²Ýtü¢–ؽ*Èd/‚™ OƯ­WÕïõ|u ç€y}Q^ ‚Tî/›‹ ]LþFV':‡‹X¬>·w ÄÛÖª%°X¼àý)Ïe"‘Û〗h°=†Y:Sí¶(¦›[<ëSn¼óéåó#d/n:Õœ‹..žâ-ž;§–ÙØÀ›ÛÇ ‹ÕÜí¼ï1 ,·ÆyüÜo6ïÂS¢0Åõ'H¤ƒË0׫Gj S×Õa³O &÷lpÙgßÍiQ׎oùƒHËërchžO¥³©ôb0¡Îú““žKeÔ¨>E¨:%¿ÃÏðæZXœó·6JjúUòÕ½%#"Ù» `k&»dww÷N²ß¯Zâï$­¶ o€ªØôñ:'M.IL„³BMÞ„Ü+g^Çé#ϲ×øu² Hu´´©És$’ƒI ªTUT_‡‹^hP‚Å’ M9 3´q0Ù!L¡ ™Jн¶:t{ 1ñ÷Õ ò²˜g„×Îg¦ÏuήÁùRv°o"ÿ¤/íæH”º!u5ÉŠ¬a‡·›ÚfLG&CÌ%çæYp³&^ªš©–KDî#?!ù“åõìÒ´³`BTåWE†¿3v–“ñÛjá.ªÿÔÿ–"+÷íd1©þ‹îNú³ÉxF¥LsúL:ꅛ̨ÿ¥Ýÿ=)×ùÌoîc8<äÖ˜¦¬v§÷{_i!Fû«/¥*m€6¤$[ ¸|E¨à¤j _¶±©¸Gf¢*´Y&Õøúذ?°"vøÝE–KÁ²Ð)™Á ·ØW¡¶8`f§ÛÃY¾Ë&Õ]íJ`]r4q‡hé!V–†o¼÷ÛG QGLá@§)G…õ¥„ì‡G\Ü õBß6û¦ºÄû€ĺyÒ¨ö‘oÌÆ¾36w¹„l¨ù`^ðþNhû×Á7ù7˜ŸÎÆïÚ`éÆxn1ö̉–õݹþ‰ˆøãc$„óBe²©ÅLš©ì((bÜÜ#*ŒÍ`!Ng²óÑOÉ/öé¿23ׇ¹ð_\l&”†,ò 65Ôîà›O²çeóÊÄWèàÚw!ºOš¥uú쨮ݘ¾É’Ÿ™´}M§Ù£ù^NG_ž¤3òáÑãVæíá~9óX_VÍ8òÙŒþì *œyœ Ç3UÓ39_m|Ý3¡º#å3k‰ÓŸ¶¡NRˆ@Qm0¡ºïÓ8U,Ÿ?¶)(NlúR¤T1Ò\ yE#¨Î_¸ %È,3¨n%Œ„Iû…ÅqÌÑdY¼zL….d#}»@14Ù±õrÔ¨ê'.ãºæ°ZŽ–c1ÜhþFæ”¶,o6v-–=@ŒËJ®¢N^ÿâ‚Sˆ–ç\%6%Þ‹î;¡^ƒú]òëä@h˜ñ>‡ûKƒ~®Uâ|©ÞI:°öZ£•¬|aì'ñ«3oP$8!58Rë´šËzEä¤Dc{³Þ¯yÙÅÅj˜I>^ô¾Ñ4)ZS­fö!mDY‰™n9þ€ˆÂÀkù[Ô™ùàrèFö”ŽLOvF‰}‹7×E}•X](­ÖV W¯¾à=gŽ(ÎíÄF&¹‘Ïí¬:ö Ûì÷)v¿©NŒJªiuÕ`ƒ‘66² öÒ1-9V=u²¿}{}RÇíÛ¸ZlöÎÒ±P™ %||àŸ®BìlDÜu›åÂùt6‰å&½Q¯œŽ~%6“›;$^w‹_sÇ"ÁCÕBwò••ÜF>ˆ3µK çüø–ïo·Œá“  r™É]û=:"•UÄ/8ü‰jy3?Ïo‰«¹µJžý?›-Z ¨<êá!!Cˆm``‰¼­u‹æ¼\[ ØSõVSÄÑ8oû¤3Ñ{8Ð Äbò|¼©æ˜#¢¢ñÕú½Vã}qa¢¿jñˆ¶íØ$/­¾tï¥hŠk§TàX,—}*ºõ͵jð>Ëûeo– &a8d’‡Mˆ‚ƒºùê•À¾Â…Â#¾kf%ˆzçÈГh³bݾ­wÂtaº=Oi¶ª‘žº~ZYÍz¿âÍõT#Î|èCŸî½e¶„}È÷+û­]j«v·³‡ÿ,¬Z¯Þ´{­ÑMîÅÈø[ >ô¡ =û³3þL¶^œ«ùêÊõ—¼hVº¸Ì~W°Û'#¹&ûw·IU¼}4ß Lî ÑÚ…+ƒº"³qÞã9“½{÷Xú4ûä Ø”x7Ѓà°KÇ@v8&b¶žx·–õ^] +Œ©öÂuAÃ%L‡hâ^[ƒŸlž wAgÂòÅ`½öÙäÌI-„ôÉÃC•=û,õS“ “˜š´XªÄe`“«•4×1`ÆÆ×`¡¯æWÖr弿²Y®”ÊÓZ­©Íeèd¦Nó§bseçn\{·÷iV…yãZv%J’$QUF¸´ÄZ†|B4œa/uQc…2-{íï ßtÁ¨Gyæ'`Ì÷TÇaV%úSciÆ X€W‚ÉØ+Á' ~Å‹ÅòÙ!öìèmå¿Çû¿¼ê¾ãìÐ3Ì2znï±”±à•Žxo‰˜Ó ë ô)¢ÍŽ&Ákð,¼OF\ŠðÕ$ê'ùÃÉ`·Þî7Ãk[ÿ‡{Á”Ki·ÛnÖ;)§;0ŒI›ùæîr,L…êõBñiï]1KÉtÚR­¾Kxª$R†øè´i¤¾î“@#Ê`9¹LÿË@SKIÿ„ˆ¥Ì=M+5Ö·süM攊ä<“í$ˆŒ‰ùŽüŒe’š½1!ßÓáÂø¿‘¨P|wu&t2)&[™2äʦ•ÆÍׇuòsØ+dQ×hEbÿLMµÓFšÅÌvÛÄÝõœ¥‹äK†ŒÐ«V#„EšoÒpÈÖÁM„ ¸ÏÍzogßD[µ°9€&"/¡aDǺvjå÷eÆ»’kèM¿Ñn7ê>o†¨­—xµº·ˆV“¼[µÇePÂê’Ê$˜?úVoCØÝþþÓK?–C‘úLÊ~†:šÅÅšú Ž{®Ñé9íG¶Ò, ¥tr1¹œ<>bGNâ÷›»÷wã”@]7ãI¹ƒ÷FÜNÁ/íõ¹7 &¿¶YªªÃ¹ÅÕ£âúÚ°Ët<šN~Œû®¡˜×lÕk‡@ÐðùP/ñjrbÂVÊçx-[kÈòž„ólQÉšvWåêo^Ø×¥Pá1%o𠻚î{Ab.>7ŸôÜÚo×ûûêÆÏ³²R(@Îby|…šS .Zûyšt˜¶¾;nBš‚‘#!ùçÀ 4‡wæ4yŒÏõ!··6§£QûhdüqWÆW»/ŽÞ5DêÛþ¸D(õV–'Äwþ¥ìÜ „F¹CõsÞW8¬®ö~bÞü=Ê:Í÷§l»ã@°ž¹iöÙ«3Ù£’ìnPZ_ÏW?ÇûOÏèJJkï7Û‡²öÖ¸µè؇£˜AXéØÁ&k#¥·†¤à…‘“¼XÌ}Yýí|UË+@ÖÙ¬Ÿ*gbŒ¢`Þ –V{ž&9Z¯wÔNÇ”gµI2áR$×å¡>ðM‰…V+sÖÐ\¤LUGÉz»õqÍMÌ©º‡­}¢r§Æ)dr27Q½†·Š9¤M²ÛŽI÷Ö®:†÷m€*•Åî`ŸÑ€•Lëo»7P&4ÀC\úŽ[;.jÍNÐøÔU-F²UUï«Ý7}.½DŽ“M'¥j-Ýë‚£-R:Ö¿­W½W0{éǺ¸é.s+’bŽ §£¶ÙϹB„€ñ¡xRÐ øOÂk°üxÁ-£ZVr‚#¬Æ˜:$È)2×O†jzúî®cÕ°R˜[*]ëP®ÍM„ïtÉU=3CÐr¿.œ÷•¾©ýíõ¡ ”¤¾×«î·v‚« §Nù¬©cÊ'ú ©‡ÄAl´‡{-þPEbÁóŒ­o©F/stݪ’Žw½N:ظè¦hå—z­½=UH'ÝÝ™nÃìÑö}½,@ Ó·ãÄ7Ê[‘1ÒîîõýuȲô'åDmCð‚#! ä8PœN×jGýZRIv<úG‡‰?y˜8øºˆh;€’É¿Á•B1W¾M]æž„×ë?éÍ›:g£ƒèGVƾØù¨|jèõŽdöÃjƒ”‘&Bƒ:‘`}nƒx´dqÕZÕ¦æÓ¹`¨3ÆbæR¯µôy×~†qÅ #žfÁ©Þ÷]Ÿ+Ãá(<ööš·œBU¶’\m3ê—âãf缨=Ê¡±Ów*7z}9tˆ{¬u÷XíJ?‚«àE!RÑã`4-Ç’5:³ÌgÊsÙ¥ ‹Ëïé>=+O—Îg™ótñ4¬rì2SB`“ t— oîMø…¿¶™+«aò‚÷­žÓéÖ8¿pu2í øhÿÀ˜K§jqL¡\Ð8< ¤u£?[£÷ëÙpÛ(U ðR|Ñû6ÓVú^Xf:àóùfƒQIs­´’éˆ^KâO øÇf²oAÖ,T #¯Jß»c6êÊÞ—#ÝÊ~0®òÎ õC#pÈ*bЂ•Ÿ4˜SÐ]ô»I¿5… 9ñ´-({ioÕãOX(¯ýn»aã |GGÐ #¬ÊE·a>¾g&ûûÐÞ¥µÛ–Ÿæ‡<èñÆÑÓ$Ñðˆ»fíöµRñw{j—g~56÷%„‰ž¯ÔòÅ•òíêÛ½Ï1Gç6Fáä›w›GµÎðàþUwÞBkä;;½£CÙe›6Pýìͯ^·æ5ˆGJÐH©Ü•ø ©r°°%pøZ—šˆÊĸÝmí {úØQ©vÙ~@'>kì {¤z’i¢InrÅPT@>2K,)c²ô‘È*|tt¸´žHë™ÌEô°FU38R)%ߤԋ)zQb Ø6'¹ˆ~Æ~Ðê?e¤06n7mÒêû+×såD&{^IÒJóâ-4{=µ?°õ5„º*ºž¡È_×!3$G«¥OÉË-6¶ƒÍg¯A¹ss¨wÕwI‘&ë‚«IÓwäËž“oÉ ífgo`O¶Ö§ÅÆÒŒQÇ;u”RBo§y¿¦—5§öèòå q>H sã¥àüü¼ºQóú7ªÑ"4$4Z–îù©¾£ ­:¯&#ErÓOx-4 ßÚ%!$ÂÐHdtë…` ç+hŒ¹#ÁCǨîb¾£¦÷‹ÆõMμãS®¤·H垦wè ÃÔã‡õ¦ñ&ÃñWJ­©'«¡ *eБO´J¸iq¿7ºöÅ~ðT¡»d-°J¢ÐTã඘ö@úâÕÆX½¨n¦ä.ßÉÀpz~ùW×6+×)ëWó·‰.¬¹mõñ.Âïã»”ÀžÕì¨#©é`bñ½YïŸÆ²Éo7_X;ãý>ë·«þ&úqº#Gã~¡xmj¥í±,ä§@îÅbkîKU•ž^˯U¯¿è]2B4ß1Vê•…UÄ\ ‘„­?d’n¡± r¬¦IáO'”Q÷êŽG8ö8<ª}_9^íq¬RÎvÛRƒ] n÷¡LZÔtuÞÒj#o,ŸÎ±æåÈø–ïÄJŽÿ–žð 4û^ö÷“ßsµŒˆm8É¿àý]cÑun£ -ë÷Ü"“¡QD¹,(ÖÛœHB´Ç¹ô 7׬=^>p¿n[¹N_  :ZYü–V€¹ylëí®eO…-DGÖõ“ ÓI,žÝžoóÓöÚhF$ë˜+›ˆ ¬`䑘,µÍƒõ¶û z×åJh7²£é渪µë"Ãõú£æC• ¿ž4ºñýá:èóÁtгu­wüV[m>õöñKNè#’Ù‚œÍEØšÚýîxLþÓÓ œ¦À÷{s@Í‹Ømßûfïvâ0²xÝV§²»[&*½•’bpȆÜFw‚6XE[0ª‹43e…)Ë›£>h?i׋jðaµí^âìÝ»|vá\°¼¸°¸4zÃÜN„¼iTºc¨h 7—`2ñË*Èq)VO£=fcŸË~™ê»÷Œu<ïý¸Ò(‡D\ÒL’{Ú„’Tw?Cß!´NÌ´óÒ´î›.&tßÏ=~R?À x±3_šýƒª‰Þµr=¿òjes]“Ô/œ1ÂHèÉ14õw‚×6 +¯ªÃ]þV5_\ͯ[~4¹æaªk÷|Ò£ ¡p Ã.e!ü ´#‡ÞbŸ¦ù”(t‹uéUë7ù|vµBL퇳[VUŽóvs¬aýØøXŽ…— \ÎHaÄY• zÉå—SÉ£/\ò i:†d"çd4¸ž‰|·tÃè6MŠ´ _!)5Š:‰À{ZíøG’œ*úJ\Û‘=œZÆA JU*c>K¡Ø…ZÂ;¸w;êÓ¿¨˜Ö#$eÆØÝìÛ¸ü«¤gi¶¿Ãk§®‘oˆøÛv'³øÖ‰(RÎ*Me?2Ô'`产N=Bõ¯ûvéºÍ$HP o¬E\ä7mÀbG´·|•× Ò:;ÚæäÑÝ ²×šýÈzseIÔ0`nÛ%á-&* •59Íã¦þðp¯W¥ˆC4­¤…ŸÖsKòaÎÑiƒîFÏÎlÏÌ}¹Z„Þ]Ü\§ËB©\VǛʌ÷ç½âð wþV·WTJâ°Û>š„Ö’W†U ‡h¥âÈ`ê}—2˜¼óÞù¸âõà²öä>Þ¿5™È™d&È&³ô®3ó£»ôH;Dö`´Ê rØ•O”åŒn'%‹gAœœçÕÓé#Ï›Q²Ü‡;ÈŠ3Þ¿ðÜf(ÒK#c¬˜쇇—ôF‡;A‹V‘8¶²ùáÁJS[­}£žÏœö˜üŸð1™ëÓH ·Þ˜A”Ì<&¹á4xx_o×ÌhÝbyÚi”1îU-³×šxFŠ“£Ñ¼2é 9uvØ,A!Þ¨ƒ±?ð×Nè„~%'²–ö‡gêxþcÈsöÔ/ÉÀicüáÛVMRñd mõŠn!öwWõßi3¾v‹póvÂk¤1 îÐnÚå8šf!HŒ ªÑƒ-„ËTøLd&£Fü=²[³ù3„ôžÕòJX²³hÂÜEÃÇ?+£¦vÕ‹ œ#̼§hà%5g)±¶Gr[ƒ”×é%ßPH×Þ¯ÜÝa{üàH:y«å¥+´€>—¨gZ¡¾»ËÔ8T`U×D!T}>5ë½v«I1ÂR³cdDõ1\–e(!µ&…+Hq+Š:ð=§Žs£]E¬ut“uº5€Zò¼4v)ü¸³Þ½O«DùvÏ^\´ˆ:—ü|¹\*™å̹ qý¶ÚÈæ/›»DsîñÐÇâ›Ç->*~4ålì«cÙ? Q¥ººš¿ñnïÃ1kbÀĘâîöNÆ€é4`¤S_nçyRìz¬¨Ã°D°Ÿ6Åð ZBKEýTR+M»©ƒf$c %‰”©¶QÚ }W½®¶²zcÄOæÿ‘ÇO <ëýg/û•ó®²yåðæ€vã~Ðâhét!rOGFûC±¹¯B´ ¹Òßó"°7(üs %¥5È ¸ŒfƒÀôƒMÂÆAð¯ûFÞ½~¤õ¡á[„›SmÔ¥ñ7h€ çÓ™d6:wAÝ]<%ÌEïǽ¹?˃O÷n™.x ö±ÖJ¿ T¾øäˆ/E£ /(q'³ªÖâafÄ/ûÕðk¼–/­[¿ÆŸöB'Ö_ã5 ¨=c£Ž½µ@ D ‹Ø€ã¼ýO)/ÇÙÙï™ûã˜w››…ÕZåz©\}—77k޲æn"„=×ßW²ÐV˜˜A–mdé0{v)<ça§ßÚcëê@íÔ=?Ñ«ËQµnÏ¥)ÜÌdÏSšpV&fRЕQ$ •I=æEelzÁ-2¹ƒ •«>ÎRé6W¾nÉÆË7Ð}òçeþTœPk5Œç¯œÞÁ+GB4gX?Î –ˆû‡"€Ž:ô6Îw¹‹¼m¾- Ó•¦w³ËËxã69Guâ ‰˜MÉ^ÎmИ`qÔÑXMq¯I¸Ÿ}›!­\LNn-ˆ™ìAGê£ÌÙà Õn·„±<–‡ÎðçœU÷#™GCIwôdj 9üýú\'lü-1|ðƒÁòYÿeó„¾1<$ÖZ«SÈ}¼—]šW/¶:êÈÁŒµ5ÍêûòË—NÓ÷úbTÕáÔ5´†]È.^X>w~ñüb&³|þÜù¥àÔü¶?èÍý ;— ×®W_ô¾Ï¬ÕtƒüBÚÍNDx#_° ]8ÅMB||óÎ;d ›8M!á¶µ zìkJ“ˆz&W]í‡ m—íqÌJâN&F/C¹¬JEKg£_ni…Þî°í[ÝÇj«—ˆ붤[1<Æ'?çÐ>aL5Tî)ô“ ™Zì4%/#—ž µ7;ó%±ì×Á†šq£\Zɯn–ó/yÉ™Ð4}Óº]BªÝ&ô*zUµ’›Ä еX Ç̸«}ãí¿ÑT›AO/$ìIÏ£l†· X"üMú}lµ? (RÌà2MéWD×<(i¿©Ú3×VCgLM"†jÞ?´/=öS©êN·!vn“Žp"šO›ý.Hì:®ƒ¾ÊýàHÚV-pÚtî4ŽÔ_ZôŒ”G‡¶»ìÃjæ ¡¤Òµ²Ùˆu’!ìý‘­´†zªM«>„UL¾êë¯Núš’½›íݤ¨‰ÈX¸mž.WŽ|‰kKºßlõGsvâ•2ZfªÊáÝ=U*$×1Ë<ªtÉ æÎâŒ[7Lü š3Ç,4NyqÂ*1QE>‰eN‰+ª‚z-ìtv©Ã/úþÖimù6Ó˯Öû¯ º¯ð½WLµ –͸¢ÌÄÀ÷h}Ÿ*XdGìM‡O[¾yI¤2Þ8Éê Îwh½E¨µéwßö»]Aê°›Ô9®U¾Á —ôã ¢ÁU܉¢LÊÝN$Ý÷|¶é4B“_üC¢EÁžÚîÖŒ]dÁ²BbfšˆbgÆ'sÚŠ‡p‡Éé4õ`¡·Ô`aË·hå}óP˜ÙŒ/[Õ&ºO'\5J†‡Ž!ˆ?€äkž(9è¶Bñ>ìì9\ëqþ>ê|¹:*Ìû£=Dåè¸Ö0^to|{¢&:^I|à'ÙgÌ—F"õê¡æ¥ME&H¾‹ô,>»œñI¤'vÒV;%eE±Þ|œbgº^öL@gý%Ôz}~Ï ˜÷S©þÝÖaŠÎ9r4´áòäá~C÷~‡&¢ñ`Ëé„!â§•psR»#¥;2VöI(6ƒ®6èµ¹ÖÛêd¥Y­OÓþQ¤dbNwn“XÉ~_•ý::3´yÀÐæ/y¬RTž¸hóüV€c‰Ú6Ôe½FÕZ$8 g±ÀDˆå}Ù.¯²û¢/§SÞ¨ý\žÖm‰ø'À;µêÚ0£ïà8¢ÁÀu‰Ô”Åã†Îç“î´ÇH.oJª1­2cLêÙØGf²ÿtŽDa=c?Ëû¯Ìaší~&ÙîOa_áŒp9²LŒ'ްI~G²G¨³ÎgþRöNQýÐ >ï}Ãgšðh}3¸³VºYÛ€z¡zçéRQü·ðl%·¶¥Æ ÁıÛÑ´ˆk‡¿5(ñ…kÅRYÜ÷h”…ÏÿâÖw=Wέ0ýe•l3jÿq=¯òk«s¹£^]/¡&}œÏâ H/ÜaúLµ8ßÞ òÅ•µREÞ>ó&ÓÕŒ<“Óè³/«å¾\UCqÂW+–dÈí¡CE({y’Øér›ÔÔÏ/˜ðh`Ë Ô6òNp™Ì%x,¾Ž¶ã¤S\æRlŽD=Aª¶zhÁxéUTâ›h·£] ÁPÚijsÐB4¯=õþ(WŽï¥¥q¥ ‚R‘”'kt>40J›U¼ÌÞˆ¾Ä*Ò;[ ó »vS´ãR –ÚP0I‚‡Í×ç[¤ }¸a˲ۜA´ø ¾ã½)’'H8¨]÷KÚlëb£F´·oºBíûWþ­ß††wê:C[댩™»X¾ÐÚõ)t¼ÞsÔ©ˆÅô P ÑÛU‹@«ÙÙ!@o‘¹`‹ömM}é(2أ׉ ép¤)¦ÒP©Í¶Ù¤x9J.¯Èòû¸†EÀxFd|Wmè6%úß6ƒvr¢“8æt_‡%ÊYŠÎC_3ñ`gOû­óQõáІáE¡wé)4†ø Wœ0u-•·k„6GLm×’¶úTjz¸kȘ£²ö¾°ÃÛE׊,±4þ´à¤9VÔ©üOÞÑ­Û¢OX·a–eúºÊÇñ\Å|œ{õN¦ÅhnÕÈÜaÀ—>ÏR*­Oßr¼,ƒò1W GºJ0§¤‡’¾94;€ö4B ¬Nš#ÄR£ôΠܬhµœ` öÌkTÝÚð8>RƒTU¼{[ýþäÂBÒeqIBÌ¢òò!«î,‹FLÊ”.EA¢ƒÃ_ÇRÁp²"°«UB Râó°Ì(ƒ‘I*Dä>®Ï"LŽøÒÈ8Y eÛ¼ðÑAÉ4µ»"™2rŸÚ›†ùp§Ÿt€:FÆêÙ䘄2cÅPD?D¸+½n[£†DÇŒ«sÀ—ÌÞ-lh²Q·ÈÄ(ž¾`#öi›ßîKSý¸[T'‡=hÍÚ–«ˆ6÷‹Ê)…§…Í‡Š‘ÍlDe—“ Eäm„Z$_PÙíÁ ‹¨r4K4awé<‰ˆíNsÀv’V$’¶9vJ–ØY&®AWMrŽ;ŸÆË•ÕûŠ`­óömÅ֤րص­íš6ýF³]?‚KAGõ,lÔçŠð:ƒF¥xKݘ®Â€÷ˆ>[ Ã&tg$ÓSJ–j7ï5Û„›‰<Ú¸´ž_/•o'ýõ|ùZ~ÞÖL÷‘•Â5£µkëá/õaåÑö|ëß'îçíÇÇûsßÁm9ZbÕ»=Õ't¼„îˆGv«¡Vìù¤4Ï`ŸeKŒ"5sz-U)GB3„¥[Í7Ûö¥"º©…`SfNË :iNí…¬‡6]› @ÿ@ÈBp5»¶Ó¸T¼}ê)ÉÅíFPÌÀäeTÎy½&ã“éÅŽ31£%Åú-UÚKj>݇¶GïÚãsPøhÚ©œœt©]A1Oa%_ŸR&Ú~+ñ.9ìÄåg²‹Ig^H{ÇGÃn·¯ UŸ'é±!Ã튆ä0±€JƒÌ¬ŽZhÚBÐÖ•M¯{/Ô³—Ó†¤Ù¥×9if1¨ƒ÷AóZ`•Æ7ßeJ„}v>êðpe¸÷böìrö\VÝîõf¥‡óóúԤαšîvqH‚~†Éç›ÉÊìËBÔ9#±hÔPò¤UÓ—¿ƨp7P¬ZøåüTóìõê‚ü ŽrŸLC¼ªŽÝBКÎmwØnÃUTð® [Œ±5F£/9‰µrÞÉ i-N‘FŠjòóJG¸`\M!x‰bs!Ún%1ÜvQ3RU]}Æ´–nd. \E[Nö)qÜæã’9ŒHDÙÑ+b- ‚®–ÿ͹EÎ õí¾^ÍH£¹ß!š:Ü3ôëäìFÍ(<ÝÈÅ6ïO”¶XõLsP™]˜PóÅÛÁ´c¤Ï(No4k3E¬ÛÞÀZ)€óqƒKQÖwïrµCÅ-ÆœøìÐÑÇ•4‘ÀŽtiÐÈÂ#ÖVún_³PA«¯•úôI6Ê©>XPBo Ìp‰ø%4†ß3uðu†ÁqÙ=²†N¬s˜xx7hlg¢ø¢úe™Ʊœ¤ÃÛµirÚ6PÆcÊFºõYÙhñºÇç"›mó lL-L-¶Ä8Š%Ú`éáí¬ùÎÅ1‡Ë¸.VÜUªTj¯ ¶‘³Õi@£¥çC?¬‘=W•ý>¢éˆôI½ãDaX©&“ &+ä4ç‘c¹bð4Tá@ô.„ C>FA·ÓOò~¯%E£fë_£’ض/§Q†8R› ˜}Ž™x ÏÐ9Á¢m%CçÔÉ$©Ï†#Í ¯ž€ôňIÎgµÖZÞ¢B61©ú)ïø8ΑŽ4CŠïåÇJ7ëý¦—ýÓ¬äVK#UüÏ*¹åf20—ô1°bÏ>â±ÅHk¼xK7?%ã ?ÏË~ŒYëD®m£¿~Â['¾ññ_–Vû`–»ûwºýlìWcÙ?¬Û+k¥+ïõ¾)†ï$Öç·|?àQ9éÓÕAý â6µè°g—“Ë‹ËA"›9¤€Í"¯€ºö)c YnŸº…u•Ì Ôk½!ÊQƒ²ða‘¤(sãE'ñ–¹ŽÑë¼ÖÃRo¬Ø(Ž›¢¡d3F FšÏ~ôZ9OÕÖô:0s«¥*DÑ}ŒÈÖìðòߥ`1AbV_çr¹íñ¼Ñˆì x J_ŸÛxbÞìÌ¡7÷gÑß•ë¹ÌÛ½b£¼Õßœ Ô¥fÓÐÐt$À©û©L9›¦è<[f8ÅÄX°[–¯®‹™sK°c€G ¸žÂœ¦4§$3FLœ_Ý¢Øû¶f7XJûÍ7Ôҿ׈X'¤Ûš(!>3ÆiÉuå ›fH¸H9ôÑ}pÌC*.r{ølÇx´aÐ29 O rö°ÞïS ĵ(!Ê’Ùö}qXV­>í²y òökŸEÊ?^ßÞ‰²#Ö/\¸°Ø\<»t.}ö|æ¬ÚO›Ùås™sç—Ó;Ù³;véÆù ø“jÏÆžŸÉ~3a l^©TË/zÿØb|ÒŠPSƒ±gn0Hxô.^£`6÷¦¯_%ïu“§c@ºùÉãÀt"Xn€öž™¹o!rŸ\¥r³T^}»×0óRß7#¨£m¢Y °‡mbaS‚—~ÅÀ:ÛÔ!²ˆ“Ì*èøüV È8Á^œ]xL¨ò°rÅÌ 3Sê{M­KÛÐU¥WÎúA¾<Æ÷é”fËíhp½nëøv½qx¿4Èå®,æ³ç—3KVÒ™ÅåÕåLn9›Îg.,¥WW³gWWÒéó+§0k0.f²ßJ8ô×så÷z¿»S̱‹ÌW´Më,€ µ5€–ª&åP?ñ"P›»Új›”l—~ˆzû>â)F4uÈaG´`QŒM_ŒíéB²!iŸwùµ Ñ'´¥Ê»jk°Q§¼ 0åL(±^d——i»¦;ÝØdD塳éûG›WíÕ[mÒOrIYQÍq5T:‚ñt¬eZMÛð‡²½ÑPÌ­ÖB¾Zª]U^ ä „䞈šöSi{÷fc.6÷mŽÁâÛsépAØ|2 C²‡é‹‘Z_O­®Æ-˜Æêê§6ÝÚ4:®¼Û£htÙtz1•>ŸÊ,Å“þHŸÏ,¶ÆÌ·xsç±Uuž*‚xÎûÞªz•<Ë{‘Žiu Y ^¿¢—ÇþÄžÌ$¦ÁÙÁ±¾¤2É 2´²gù è~D¦b•¦wïÀ{  \¿Röm¨Ê´ÙŒîÛ¶õ1/ÇÂýd[#ÔwÜÝ€ ™ ²óñDzd Éé>2=ÔäÉáWÍÏ48¬ÎWJ§Ü!³±ÞÌÜ·yiSmW •j¡¸R}·÷ï,# ž$ôvÁºC¨O [¡8!f•1ksìïÁ–‘NŠ„ÃFÎÜÚ§?INQìHeyŠõçYP톀+¹ôİOj ×Lö;8øªú^ï‡=õ9‘¼ 9|ðAv=|PvZvúø~ „ ÄôÏ.ñ  õ¥`Õ"ö8g‹² eù»­”u|rh“ó^öÏã ‘m3·Vù<Õ,ùׇêX–ØË$÷²ÎPË`K³·ŒÙˆö2luªÃ¥»}„à²z›ìùÙ)ëkú,‰)¥Z~]”oŠ­êÙ~ë°Ÿ`=ÛZM=ºö?YŸŠÅÞ–ýNÀxSt¬Äÿß(äo>ïýõ0Ù‚óŒÇÇ=kæe÷mÇCƒB«= ÓáQ_>¹ç”r†Ó‰O[ã’Çfêsâ‘L{wÃ҉ʽD1YÌ$‹ÙdqQü¨ËîÊS >¨çùħd4šeHIµnÝ ›Ág@º@‚ެ^ƒn‚È Eû3ôhµ¦œ¦ Ä…8i¸Ð¸ÔJVúoî»°þ(Á±FBë§{_ã„ðËÍD”J!";jôñJk‹SÖsòãÊH€½.Yö‚:šÛ?·ã™4þåÖSëø“àBz?çe¿¸¥•j¾ZÓÔˆ_ašÊ½/ú×ЭqLêòäS@³‹ýúÜ_ܽFܯTsë/x‰‚z`‘ùéÏGk†4YßD‘¢/к¢Að(Å‘ÿÅQð‰Tµ'ÐH´Øq*¤Üêÿ®.)s>}>½tªOgæþ áß»\å?hñïÃ\åI¡ ’nˆÛ™°\ÔÕ¼¹7—쯬¨£̺˜v)ÒF°TFA"׸W'”¼Í¢"àÎó–á<é;¸fŒ”­Ø\¹õ1õf³½0‡ô݆”©¸PºX0Æ Giä1‚mhÀÇ ‘ÜÐ,Ÿå…nû:]‡Z¬ßöéu! È­5¿*’4»µîe—À=Ù­Žî2[º6 cÏ%”ÅÃaïPåíD¸©›šÞ ëcl3 ~¸W¤xŽZ^à1QôZ{5{*«8,ÇžOdDÄ'7'éßÅlj%ÜóIÚÆîîƒ*öw‰½"­‡ñ@+'ùR‹ç· £ÄéÝFÓvÈç*d´èëÓ—S’07¸ÔÈ­™A"Ïœ Þƒž*}‚3¨I¯™³D>OþçÑ.kv«ÃFäG!É:NFêCÞÐ=´f!¸ö“6jl%á¯PEÖÖªL«’ì(ØLæ^s^î¸kupG踥¬N‡Ä•Pߘ5…üb!Gq, ÙQưG¾=„@ûú° åÔØÐÇØé.x¦GÞoƒ@ä6±¤d’îLbúÝd\ÛI'|v8ï§bs8Ø/Ÿñ¶Œpð2·Ä±y*™†ys0&¬9ˆì8‹/‡°ÏŸ¸B?¢äÃCoî{ ªÓAµ¦š4÷.ï_zV "75â¿>¢êVb[MæXÂà:O/óÉÐzÓèB—˜z}XýÇ8„(IÝ.Órg Ï›ÑBèÚ-.«mølfé|zä°{a!›>·Í.-,¥O~à=® ³±o›™ûk°åæVJ•3Žþ&NqWت÷ Ðô[ìºr+˜ˆãõ¤„$ìLò–šÒ·LÚvK;‹‹ôÎæÕ”ÀSÓšKQþû#­L•ÊD5+ãÞðy‘V¶1ïFú)³°|.}îÂÙÅìÙs–.œ Mº7ûÜÿ6“ýë47*¥5²¶?ë}ísFKš¯w®­•®ä 6¨ä+0ÜmÕr®XÉñAФSGù5Uâ7u©¡fÔ±´¾^¨Vó«|ŸÕÁ˜»ù{úâ}[­ƒ…ÜZá#x€{oêg›" T÷ëz'î Sï¶Úi«£ÖLßy1ìµ»Û8ó“­P¿¦¥ÿ>ã kJm1 l7ÙÚíq{5Ô-ÞDt,r¸¾[Œ ¡zÔ踇y·Æ#YoTÜ ¾ U ;`›FÐetƒ›@W”D4ívš÷h•¾AÕWhJˆ:…Ék'O‚M…Ú¦AÕklhW‚tt¼WÓ—1¥#pNR´!Åÿävfß ]?kÝ‘¶Øâ¹í„Ö‰ÀUÙñ¸4e<;Ù¥Lv˜€~{AÒ0Ï:ÌPý&³FÀ Ù²xX©A™> Qîh‘Âsodšh T€˜¸5Ь U%v›5Õ¾5%¢·»{ÑpÚ¨*¬×äõØ—:îÕM¼có Àt×bøl±‹%ÉéìÈάl ¢Û!†LŸâÑÒnRX]}'®4à‡šØ9ê7¯çËy ÉHUf¢2î‘iWž,c—ަNšÈäÔøÖLÓøÐ³{~ŠSöµæ.‘»Þj€^ß•9NÞ:«cW]£ _ÔÖlÜÎt4*Gˆô)­¥8~Ö&¦åz!À"¼ ‘‚êº[YªqÃÔ¨ö“=¨¨lFç ÂB¦ ËÝgúekÿaÔRÂé¢âÌ5Z=ŽÑh¨óti $Ά;ÜÇÈÜnÝmêȴ΂i²PƒåÔiì y+&S9¥(u$c²‹¹¨'ŒhKðÅî³µÒÊ«JxƒCk9ý|ÞíB|êjüV§Ñ|CS&U>h2EÖû¦ B@R†Æ°/Ú òTB/‡K©}ø3˜‘¶*}»Kñ};ìãkK®‰ŠÇ»ÊF³ŽPEƒ!÷Ä*gã“ÇTËDÚa§‘tëf蜤=²¦–MecK§|ÙŠ€uLᨨ¦·^¥ø˜M'v EÝ@¤>á0c8jj×@në˜ñ-’ •È KtLäsÐnhÅÊÜá~½3Pû-V³9Ѹ-­m0Ë©Lð¯(:èsGÚJ¡y+f:ÈjQHê'ÌC <.žOÖT¼Iq©4C¢ÙÒêÄ’ ÛiB5ÛÝ#; e[IaÁYä0£0™_§}tÇÎÞ¤¾$莙ÀX0…iˆ:Ñ Ñw„˜º5c„ñáÚiZ¯óèNíê‹´øG¿khGö4hU4õì À5´­$}»Ò“opzè©o—ù8`–2a>ƒ^¿GÀ]ä2/-´R¿pGŽ•±nëJûq4zžÝÁ¾æa8¥Å¢>1êÖ0â­ìë¡éÊ‚‹l ªŸu(+5!X:p¸ÍšdÝã'é´¶±æÀ•(§4‘ŽK ²ÍÌý uÎf%DÅkg ©ÜÑʘ0qÙE ¦½8Ž«iqë4õ*7¢ˆR2 Tïñ¢ßL¾šÊœŽ®$ËÏýM¸)V Å3Þ³®d…âhÓYUÀß ù÷ê–ê¢Ólºf4J•j£˜*‘²Ù¥³é³‹Ë‹çÕU3•9iÈri³¸š0©£:­ShÉXl8÷·Èÿê Þ¯8<Ÿr“ˆ>#Íz¿Ù¼ Ï!Þ v…!*Hd‚ËAEíIõ£dU×ë]¾Vó1œ .û`¥¨[|××Û‰¸€“Ý¢^7‘æJ«WV ë'”àÒÖ72ËT: ¯£¨gØiØJc±÷f¿¦RÀ Âêæ«W>ßû1žßðW&îßݶAÁÖ%|ÌãHL°Ei|åTc‚·Ÿ0&8š~væ+½ì÷‡Qòz©TÖ •êóÞòLÈaôbc¶ÜW|?šHüE NȪ퉵7$>ìH å^sàóQÔ.4¢E¡¨ÂuÒ±ÖÀƼž }Îò˜häìzã@­1ä%Óï“ÆléªÍNÑxNIF®û‘zî(X³I»žÁ=7k3Þ!!‘ì`8èʦ”Ï|©~¿ßÝiÕ]àj­¯ØagyP53·©všG‰ý#ËÞ¨•¡è‹ÚcäTƒ2é´Ëï'Ê= ÂÉN>û(®È6ÕîŒaø8>»NK?ŽÏn4ùìÌ›™û~Íßš¯–oWooäç¼wÆ4KkUqC3Ž5‰ÕË„‰—¡“±º©G¥}ä,6äÙ=¶S45+‰äeWHwº&ƘÑ•˜I8º€`NØi«oNœpâè™Ï‰DÏ„'ÛBXk™:n±,'Íxº(äÌ 'ø™2çÓŽŒQ2Oþ /û·‰ÛÉzÁ¿ß{9odHºÍ8Åêø*øÏ\œ[»4¾ëëàqR⹑®mSùÜ\«ùõ Çß’ÚÓT½Ïñ°i«mVàwª!‘é Ê/†]ükyx •þ@à•s•QwúÆMUòàÎJ®²’cb)Á¾f®$Æ™ æñ!:: NQ”‚lMÐçpÈf‡ù€Ùƒ™%ªzÛŒãDiˆ(fU Qˆ%5¢“œÊã«õÂ)êhv>gœ,+ö¥œ„í%ÒŽ¼¨Œ`㉉±bŒžD¢îü®-ÒB ‚A¤¬íæÈ­éäŠ452ѵ&Õ7r§¼â MŽYôäìÀ²)©dIl6¹³å('¤ŒÔ€í&ÀiúŒoñÕ®YÈm»@P±˜Ã…>x|xòüŽ¡šÃÐaÚ|wTwdùllÓ¦´`·§ûzµ“ì[póiÇígÄÆ-ÜÃÎe&:Åf.ùþgýB¿3}ñpÙÅ›pÓˆôV}uL®Ü6ƒ=&„!†×Y )YhM7C:MAO¾A°¢y–qÇnH°1üTu~øRÖ_ô5̨Ûoº5GPà ÖÁ¤álI¢ÝA*õ3¯©¦{ù‰?&¸,t&Gλ¶Ô‰P¬ºtLKõ›‡ ™ÃÈC„-â24^„Xàê’ùÜ|Àœ¹›ó ”ìÄ £‰ƒhê’»£+¦È¶ë:XŒÙ¢ßÓC^xT§7tПci"!êTW #Ý%™G'R»Ý6XÕa±·ÃM‚¨/Ôº:¯n ª£oæÓÂnï —óŒ9S ‰í»úžÓIë™#™"?_çŒæ'È8áò¾Ù—vô¶9Äe° àq…Z >Ú‘&ìs}xæ5°'=fÝ“>œa:Ú"IöqATí;ÞàÝa›£ihö Ä?´D¥sô™ÑeÑ1kÜØâ×{d¿&d £3Æ" 0^9¦ñ¦‘òy“4Œî:™ ¹”&fb´¨–MH(Ìj&; óíífØÛîsXI°¾ÃŒã²ÆÛÄ”9|< Ü㉼K]ò±n [ÒfQɶÔòXIÅ_/ù¹í iÓ4(– ìmÁeåì!;c?´ÿ³ÙÞ¡ÙqxÍé@;ŸDêjYlªV—3°SNä‚>é±ï/eu1* £Tx] Åj²à§ÕùKúÝqõ‰Åd°œ¶ï„ðœyªò•<“¸þg¯ž³ª[Oâ°>J&÷=£oÒ*ó¯ÿ¹ÁÉ•3| ù=8.…úY èŸå4ý›Á¿“SèQÞšÕ(ø˜3O¤ë&Ôˆ<ÉA¬:aé ƒ2ªŽôl¥ª>¹ãs1ƒMÜ ™Ö²gÜ û'ÏA  C"ϳ¯@–:hØÌß%牨# Äì…Õ#9ëHàÀÉo‰‹#\Ôœž4fy lzš¬(ú-Fþeþw½ÃäLÞŒ2¯àθÝTSS–‘l‰jÙq‰Í‘ü-„õÀù$+=yNÑöÈhÙDRáhƒô…< ÌÈGb¯Œ.—!ÜDHaiK²¿ŸVžqWæìjçÖIýP']a©œ+ß6«ˆÚOÄ ¡^…矚ÜWå(ÈÙ˲ÉRÝ~r9eÂtqdØÉ»ÚlCÊmÏ@“÷Z{0‹S|­T^U»þ•Ûì’¨&˜öŒ|Ìý´×aɘäßÕHI: &Ñ£a€ho,ýaquæ5·«}{–«,:ù1ðDW5&­&š—•"Œvn›™È|ÑËÁǸ#JªQ|óÑeH©ae\/T}M^¥;~œNðÍäSn† «.™˜IÚ­€ôªsï$¢² ¥³O_’]DÚ‰äpÒŒ®% Ž)}+¯­Õ*ëê~­œ¯l®U©T>¯¿®œcl[u6Jµ˜äŒ},òç†Ä&Šßrɘ ‡v ¼˜‹òŽüµ;÷Z½n‡´âJ¢W u0ìÞ—ÐD :ÚKYE¬…ÏPlê² 'ŽÔ¶?ïlÆ„îzÉJXz5¤Å\‚Dz!mÞ·[²Ú5^o×Êðrdút4=}zŽ 3ÝØi_¦GŽ¡Æ¹873ø&ÜNOPÒ\±R¨½¶Yªæ+Ÿ¤B«æ¥À›ã ­¿ährƒ‰š\Cp/S*bôí"t™U^ǨqCªzÙÚ-X,ˆÇ¸1q’S !¨©Å­Á‹±ÃÃôZêsjCW$Œ¸â`iºu‹“(y}Æe¶_täTKklöp&5~îïw}½Qlí½î]‰càEUN:ê`ÊÈGö°ã–Ý70ÓRT^êZÂ’‡.f¸­•³2ö÷I…€0iñGÖý"+%ö×ÇÁ¹ÂׂuÀ´íšó€ÏŠF«z­œ+:€c› ©eM–ºé ¦nÒ߈ àìrªFË2ªŠº'ø³FÅ«À´Û-aÆlgµr•ä®ó¯ÖĉîãÛš7ÝbøV{<Êû5®cµ‰ex“F±¯ß·ÝלDŽO…UÊG‘hH“ ß ž¡1£ä,ãô!c!©ƒæ˜\¦†m é!Ûä‚Pµ\©JÇãè¾Ä± –aäC N%&—Þ8©H ­=ÌÕ;‚ò£ÊÁÓc™ÎéÚ¡oóªJÇ\œb­÷ë½×sˆŒé %èLBëHt.jÁÈT6úI¸®ã[–sQÛ&¬)iõRD#È„CN ÑŽˆ£ýpBÅÔ¦¹ð²— Ï 7êYg¯Q’„OÍ@_]©N>Œí„„{k¹fhk 6”tõÈÌT2hh Bf m÷È [ƒßÒÅÍÆ|’‹âZ{MÞ¥hlßeÍ"ͩܨ œ-¿Ö@ÀÍÁ®²™S|HS¤n}Pt/¢K'ö¾ìQË"ÌÁAHwª1Ǿ ¤àM>—OecK8f6iB8UÄDO •ÏØ/›Q©Õ…Žÿ–ó9ÓtôÄîÇš µ¡µhܼm8ÉÍf«»|^:moØéG2à2ÐáÀ,ðépb[¥ ;u3ê(é@»ZÎI¹^ôn)LüÛ ~—¸¿ºÁMlÆÍòHOL *–éqJÆþ ÚÀ®ÈŸ4¸É{Ç \'"Ñö ç›ÊRd£ˆÔ"«¸©%ёҌ ‘wŽhcŒÕ׌´o¼ó`èÄ2˜>àÚÒl2|whµ¬Woä³;¦ÞfO±Ž ÑöÒ©’cǪY¨þS_ÂAÖ,ºfÖæmš?TµI9ÓÄa"4Bâýã*¯ºs³d°ˆµ›Ôî ° Yzäûf䜑m$« õ-ó“¥IÌo¡í¶Qn„­¤œãÔýÑ»‰yµ­LRHkÃÇ4ƒ…VCÉ’»‰ÁD˜ùK¾_AXp_¶|•Yàl¢j€hd+\eCF¡ÂÐ @XË©ëÃLBå›_«äÍ,Ý)®…«—ø,8©¯ Õë˜Ø"ŽA °›¾£uÏôj,b7»%ò‹lμme%Æ$D9#ëº"¼H;¥Á‡TÓùcŽiÎÀê(ø ©G†s> —¡—U ³™´­þ˜¹5*$öC:Ø{†¯Þ '<~ïŠ&˜Û‡@ÁÄn×õu„R’&ؽ‘t’í«ÛmÃdEB:%úª^ñÌùE&ˆk«Š¶~Éâà,Z'Á> O‚k…“Ž[Ã'$j1N‡%G- »ç3:Îè†EªÒ‘ºX\ù`äuÒf›jq\]ß HS~PáEŸöÔ>wñ)bòpœ„§öš©¨W‘&k×7üñÚÑpåe|O”g=rÊäb›QÁX¡A1ðOæÕgó‡<Ó¯}ê$Oߤuô%e¨q+0 2ŠhÝ…[»~§;¶â&ênùIϰҋè0ª§6±Û®t¤1üš½=X•†ä8_'«Ò —ùPZ›‰àMpúÐv);Ø×›ŠÄÇhâ¬mš¡ã´îÖ–rñ~!WKÆÙu+-ç©(ÙØ™‰“a†Q §\®wž(£9Ò_ÎHÄWé'¸çʰ >jœ“ºHD´Û #ý}W±îwãA²(µ“ªm§ÇAÙRÈ€¢/‘šÖö’^-Bö¾ñÒ 'j^Á¨ú>‹l–Ò>v.òa\ˆOé \RÒDqæ"Ÿ¢u9ÜFâòAiªò5±ÑÓ_òEÛ bIŒ®$&¾¡Ž^N º)DG¹0PÀˆú~ßwÝ9twKpŸÒ"Ûº¥ÆuóõÒ$·É1‡>Šö¡?E°VjŠZƒýIf}H?kOæ#V¿6ûQRŒ5+™÷özÍ=¬¾²6QÙ\Çw½P¤r·ðÉχ½-瑇vGÀõµris#¸r××s7 Åk¸"oA–Ïq¡Îú«qñ’%Çs àðfªܮ6üèãl¢Ú.Îéø*¡qÁf ›=~ñs@AµyGdš²O[íduœ5>cã$Y+G®€f)‚GÔÚ%Ô,œ¶Xò嫎ÄÐ ¥ºBzP¸ãÕ?v¼¯#Qb´ôxÅ`˜³f|ðDÚ³1ù⇳·Ï>ªÝNÊmHª á"í$Ý3E[»RwkàGGjH£õ©>@W¤¡È% ¹´ätŒ»A£Õß²ªŽÆ Üh¬yrfÔ±eôAÇé‘ÚbÄ+2´NFD0í·çäeäÙSž_väÏGe{VJÈZ>ºô WêAý®qû%Ì9§YæÙéºcsÜ\}»Õ†þ;±ÝĶíH›žLL;‹ç“>fx¤µû&3=2y*ôÕ<ëï¶Xüê»ÝëËVÂKø°íëêÌb7iLXPH£4ƶÝ6nÏÒN°õ»cz'h.­úÐÌGNÖ:'],ñ×—²8Ž.˜HÈTuw ô®õßÏé›:Y‹'£#óv8gBûÒ†òOì›LÄ—ÛñØÖ¡,Ȉԯö¯ òa´óâBf)³|½™àå`ÑßÜØÈ—‘ÇÍÅ༽ä'ôü™7GRsH¨«CòŸÇ6Gä㾇ÖÃǸ^j†"wÅ#d9Þ!ÄB µ°îCã´ùãï5šBV&žm“Ôøhðª©;¨½ Þ«êÄÁH‰>…Rß)þãWªío\1#èH‹ÜFæBz-w´+òþ;#,ÞcfôäåÀˆð6 ,Ìe“¨°¬0x–¼^7#—›xÌW²ò "jA ~ˆG@ HÈjT¤œU#ºeût&µÐc4¦$,˜²(@<èú8ï:V~Hqh‰ik!¬gp/ ú•v°ùŸoÙ ô¨½v3¼!Dõ}˜ù ±[6* #tÌÌ Äp³/±f;ÂT} :Ë‘NoI½— ™½Ÿ÷ ½ •ˆnè Ÿ¨Í4°.lœ™z!w›°ýÂoX‹v¯ÓîF^ r›ÕRM‰5åH™yâ:RçHà†û:'ëÏ,ÎK:ä Ê/$Йñ~!r¶fo§¡á0pâF} þ_Y~ƲŸt¶MÌÂ#©ì´´’»‘'ܶg½÷›ùfn:~¹´¶v%§äš;7KåW·‚j)¸c^Ü ½©†Q®’ÆfãGB´Ë£ì4 “ùªúœ½=æz"š]¥4<,“tVÓöDý^“ˆcô4<ûx gcggæ~rœ»Ÿó¾Çl³1ž¯“íppÆ Åh°“¨íƒÝóÖÓvÚ)kë@v>ë•Ëžýú½V£þaŠ#FAã~ ¬âÏÉþ¸Pש³ Úë{ëhá±x¯ë8QMzÁ{]ß\«x ýŽÃ{õ?+–ýQâ %XÒw¾ßûGo ópß)j«ÄéÒÕ«¸Ú î®Keu!ˆÛm K¢þ$ìšÖ¤sµï$ÇÝÞ,±ïy¼ÝtÀ©ñ´¤W—[] Ö6׋[XºkËIà?N¬„Zw®Ê•*^EeLŠ­ÑÜ“³KªÏÏ›oŠ«ù[^ÍßV P¦d[ö£| èTÒøCgNYé7¸r[ÑÚ+OÕºÓ?:Øî¶·µ[XG·úè'ð3&ëÍbáµÍ¼êh]Ó­O@M^[Íߪ>ú3Óæ\ÙÈU ¹µÓÏøøVS"N^M tRèsc?cR]mxü>´œÑÑþ&”[«ù«9ÄMkÈF“ÛÂG=W¼–·9tÛ S@¼ÕN<„§ÏžõÒjáêíÓ˜ŽœU`$7û(<ä¦;m“ÛçnŸìÞ­qŸñãB…–/õ¤B7òÅðßeuc]5_µ´E­å¬s ¶€­µZåL}Ì QãåTfJ Q½Qέ Ú¤œT{­Úe%©ªô4¼*¶’:ÍrGút+’ÃË[r¡'crR5^É•WyÙVsd%O· @‡¨FïB{E'¡o&ÁF®\-Š*a_²=ïô˜yÓ¾ÈqÜ69õÁ•¼ó ÂÒú¥òµ\±ð‘üälÆfl)ú²^«SÜí㲉½Ûñï@+·~li¤ØW6 k«|k#W(?ò¥õÒ ç{dõ ¯$¼SÚ!˜à£Æ¼Zîr•tƒjà- Ë4§Ø¬@÷ñæ•j9ýz®ÍY¾¥ßænç÷Õœ¨]²B­‚&Àc…Êi3§?I“© ðÈC Ïž5à…Ú7ÎÒgÜ÷ÙCHó3~Ðuuµ,pÁu¦X€UÖ~(ÀD{DÔ3.Èa&^O¼Ê™ûpÐë Bp]ö‹%¼i %=A;ë\_s,SY|%ú5Û»d{'c€B@ßuSñ)D> û…Ôk:~aHRl˜RÕMéÍÎ|lfîÇ”løi›°ù¬ç*覵ҵÊóÞß6ç=~ø¦<}\)Õý½‡%/Þîîqüñ¯^Éc™Æ!` ^õW©Çú»ßtˆ¦úäÆ`áj˜¨ ‡:æŠÜÖlàµzAè1ØoŒ2¡>qô£ÖÁœ (™Þ©ÙðG¾°¼d(õòxø1î ÿˆ',¶®f d*¥R§¶[š)QÞ+µ/D’S…Ãao¯™: Šzdo‰eFú“ú‰òBÒ™tü’?ú–î"ÒÒ¤—RélÍ^\:{1{V½Ò“Èørkû¿Ç²zìqj[­æßë}§GŽÐús‘Ó$a&ªz»U·^ < ìK ¢OúÃAKœ.v›`Aù”R¬ÌÎüv,ûãà:ÄÏð¾ÇðnÈý;º®æO±T»Y.TóP¸©ª«>’㟶­P¢¯I( î¼¶YXyUíJðÎ+ÑiU]ªóxíjy]íî×qx­«q¬N¹†hî˜Câ€[¡ ?ÛÒ~ËjâÛ2ÌÕ­ƒ£–º³³W v¡ë3ÅZBeÖIÄS­)mVFôq®¼r½ ¶C ÃWY0fÒÜÙÀ© I!¬'˜èDyOy¬TnØô'§#åâ§„?4Åü¡ÔqŒ%xbjö}µZ;ý{ãòYmŒß¨¨]…,¸câÙgÇáÚrÎ?nRoö©÷ÌÌý}5ž"?ƒ÷{ß2c½a¥¾×7É+8…œipßõòµš ý’Ìýv›ÝÖÈzK E`ÕɻںîÄ>/k<ƒü¹‚N1çòÇÑÖÄI Àæ+úd46Ó:ú©Ä{‡‹Ñê8VYNßkúvÛ«;öØ¥›î˜()hg 0}GHÜbqÇEâ ÈÙ/”›ñGÞÌ1-FL.¬öHÐÈjqí9ž"<[ë;wc’Q2¢° V ½ …”E»q­V.ݬ­å‹×`U]ÏÝÂßÓÔYæÕŽsÒBþÜmzÓÒ¡ŸÆO¸`f,g&Hø¢×„F §µ^WÙ$q€pµI'ÑøQ÷x÷KdÓóóêtz­PÌ_æ.ˆBuʇ³Ÿ¼‡pDU…%ݼ@Љ8L™ñ瓉8[ÓU&>Œ4;E&ÙøZ©4Aw æà‰[ḚÃwf5+QŸŸwÞÒ­A«9]N 2ÉAv^jS[ÏW¯—V/ëäÒ‰Eƒ‰ƒÌóbŸùTö' ¸}¿÷½ï sÎw Ì£VÌÞ)\¥Šço*ÕÊVXQ›àsÐ-gÜqu¯Z™¡nè”ÈPêYϾ)‹pgB¶¦-îÖT´bÑWR¸•_}°z»˜[/¬<Ðhóv¥ªæÎþ«…Ê«Öóë%uîW ‡©&×úJ¡jÕWÔX0°«¾p•Z›ÅŠê :´|$_.]-¨6¡w Kô¤/¯çW ›ë'}{Š÷ò×òå½{¥pí¤ÙªõkM¿˜l4wZJö=6ÅjiS-pÓ¥¹ºVÊU§üL~E%S¶;&ÕֱɊ›jï,¬L›l•iÕ0*ÖíE¥š[ß0ÏÍ£Ûù\Y[@Ê¡QÅãw¢&~ëxUü B•t >q~¬³ˆ {õ¾ï|†'ù­P:}Á#Ùü¹V*^3 ›×8»'¯þ鿯e?Ý<ѧ›c^×-²™$ý“åCÊcg¯^ÿæÞ‡Ö«ÞfÝüï`Ó?n;âìËù«ùr¾¸¢N Vé5nS6CAíY+×™9U BúƒL,9ûw¥°¾±–7)JEíoË!ƒóŠiŒ¾âGoé’ƒ(xÖP!Uäñ`6üR :]0|ß•„9±5Ö‰ê>¿\{½ßb»õí‘…ZžÖ9†;'|¶Ž<<©UÒŠ=•Íuzú&ø2oEs™h» ŽðØÄÀZÌS3ñ3‰F¯¹ï¨~É©æ(«÷”ìÁïÕ·ûJú4õ ¬šjIÒ ÆÊV³Ž”œÄÎi3 9Kt³Ú~Å,ŽCcÀ8vÞh5Gôv¡8î¶ÕƒØZP_\¥r³T^ma õ(¹$3‹ªƒ6Ôˆ®¨Ër~u³¸š+Vé¦üŽžA =Sï$ršÖ;älÇ£ÝÚI¯X÷—7ƒ;pGÊ•·h¡Z?}`Ÿªš‡xNwÊpI >i¾I}¡¦·)@&jMººyåt &_‹dí|R><Öà Uÿ¸ût¾Q«Ÿ?îa´yÃfhSæ;¢ys $ÙÕë¹bð¦4Ezü ð€·3®9¨,ô9`kÂz会ìb/­Ã*8o›Õt¦P“.î¼7v¦òy34«êêˆGîµîn 4î›îD;hu&¿é,Ôx7²X;/K«yóÆ{n£YÛëu‡‡µVÃy ± “zÂ#3&<ç1ÌíîtÙ‘Að»=ø=èGõSÜìâJÉ.!D ñkK›l`± ‚Á@0F·Dó[¤x£âbµ–%YvÊ­¡š-n·…ˆÔÀ/ëdC>Ûé'ß™ýXöÀA[;j‰áûÛf²‰=å›þ1é³éô…T&›ZÌÙÅ‹ËÔÿˆã7Í*}*Quž7ûÔ/{sÿA—Ö^ò~ïûc²1Òögk¯CóÂÇ„E“XHÞ!/oúá7Ãøz‘kw»wû!â ×v#¦›“»ãFÙ6N›4ùmG1ô扵9r&r4FS¥2(‹VSiÚ”jÚ”Û <<j6$@öº¡’0OÜëöŽBös%C5Â7Ì ÿ0•§Ø&½äX;ÍçðëuP(*©úÊ¥ˆŒ«DWµ*÷Tל¬0!³jâ‘ùKÔxóH(Iñ‘.“~tVãóDIOZGúÑM3]*·:Ýùã_æÓX"Z³¤SàGäàNÌãó96›Ðt•Dáaôˆäv êig'´ž“'j §Õ§©º›ìä5Õ©ÆŽã/:½•aöÙ oî§ ›ËäPòÄ|ùýÞ×<ñ<áñ²÷¬Ò@וŽù7Ë9À[)Á¶~xè¾Åh'• !ÞÏw’c˜2›Q{¿\/Uª–o#%ÁOFÉ{¡½ã[ÓøGFõ9þq¥´òj~ÒWK7‹“óET’6šj)Ôà/Þô‰]εz·c¸vjRÚ!‰P3k_ͯæËªéW#Ž‘ .v´î–‘/ÕÎPßá‚áOõÃ'ÉZFÎI;\|ßÈž&lg`„ô†–hÃÄ7¶(ðÄ¿²¨ÚÝmÕ’nÙwº‡i…RiR¸ý¹äÀB_î¼¢ªêºÂ·©³ïÖ@`×F€Î.ÙqÐW»©E€$.‡õ‚ï¼€šô[8{Á[³§„¬:½ç(#œO§ß­hmêG¾K…gã¹_vÄøLèÜðîdsZžz”?‚Òí¦NLãKÀ èVÁ/Ñ©G0Ž6ÈÍT¿IعªŠ‹Ea9uuÈ‘¹}¤õNº B”W·-gUR™;¾ÜZV¢oq3nV¯¦Î'õ—'tN¨í •?ÔåÛízçnÛѼAø¨pˆ¼û-´ËC¨ï‚"ܦ´ˆ¨á¦PŒGŽdO C ­šðEÕ ¸àuÂËŽ´*‹i~ÂW#&^!ÍåhM:,(ZÝûUPâ#2T2²æ8óB;w; Q\Ý2¼¹Î¨cWg`q?yC’Ü9ZÊø]3Ш9(k­eH.st ûše€ 6œõТÃ_aö«GÝýV»m>\µîáß÷]¯ë‰e^°äÙ!íŠ]#’Áõ.¨W·“Á¦@0$ƒz¿ÏdÆ4L¥Ïc*e•d!þ®é ìîKÙúfË¥M1^n¨ÁOòîÏ\È.dΞ_È,dÒgÕ]³±ÆUŸpª<éÁ´ ±™ÿ2÷Ópñ¿Zȯ­¾è}š‰o¡ 5ó’ê¿ ~eñK!B‡ÅJ¨UãM þr`Nô”>  Ê´èmRÞêlÒPó œfÌnwØihõÞÞEÔèà’Íó‚M+HÿBoÍé8)rÀ—×T{ôM^úɸ“V?•…÷~Kpl'-ht‡¬Ð)˜:ñQôTcgM1àvt–Ù­·ÔòÔ¤]qpä[E­(";G‚BcšAØ‚ð&ƒ¢ùókUbb:”±¯hKø»ñæÇÔPŒ_çÌuü»Ïîv»•GÖ›Õnwú¬ÒO†ÿ,¢¹ ,¢õÜ«ä§ö‚÷CVÙ%÷j‡î%Zá ™díV€ŠtZ쫽Ck–»H©IΪmÊÃ7CçTÕZç£j-]‹L6™YN.¦#/™ìÅÌòÅÅôé ;Ûå/ÎýդϬl–qˆ{ÁûϦEåÖ$pÆYµ8k o¾­~Rëë©ÕÕ86Eü¹¾¾º*¨_I"dL‚t^Ç‘bYýiûãû`;Ò¦Þ#ÐZçS鳩Ìd—I¼ DYwò¨4é³™ÅÓÁâzê~,ûOĵ–>p½ÍKäCÙSãú­Ždk«µG¿WŽÞ…2š§ôð-–mBåq)Lúê¼L1‘’ŠH'"Ý/ù–¦Yx/Mš%“3Å&¾PEæ}KÂÈÊ,&kj¯PöVÔ'“¬!Åÿ}¬ôÝá@Ê!"yøk:¡os¦=© ×Qj´-5€a_6 ¢ìñmm„VXôµeò ]ÉÖ°ïòLöÑÎ0þ Á“EÆéÕp™h©V£³¨½®~t‡}CãQÔ Ö|¦Oo²¥nêâÛ¦ùªHåzy’’k!(h1³WéÚI+¯üQ£}øÈN•jt©t–W^zÈt¨¯­÷–uþÖq^VAžœÄK1X rX&Ë7á }HÄ”B²Qà!Ê+ Pl÷8AD(D[šó¼aÏ$¯è¬}'k‡J2¾ÝÝŽÓ§ã/-´»; {Ý{qŒ¸OÍÀf×AˆùÆ53„Vô<åøa'·à²³Duš÷Ñõ%¦šƒ”3Sº Œ$õfßþ…±ìϨµ÷ÝÖù³¼ßû? ö5Ù­”—áÜêê »¼E§‚«u(‹A@ðÎB±gZë¶Øo}\ÜdîÜ̪[Ç9¥Ž(Ç멬LXo QbQ¸?£20üC£×=TBs_ðàêÈáH6¦÷”Ð[ïF» ÑçE‚0oÁ“šêbèüPUõ"ÀS„^‡]³Ê#üîx)äÀÂNšê½Löüz D§ó*Å^Þœ7*N¨æðRÓRÅžžÊ¾¸v²ÝD kPßÞ?TÝú2tÄ"®&ÃA}OUjØ ÓJHšá¡µsp´°ÓÙ]®£[›yUÁÁ6æ¯õUîÛ  O®ÑMµ™Zù~©,fSÛ-µÔ©•á@ü(´ÚÆŠóµKd5NS«Ï/][ðW†{/f/dΟ 2=¶‡êØeç=œŸÇwYß ‹(Wa’0û¨×,Ý"ïKps ˜hßÅ–!“£!³#MK¯B³Ìwfަ¡‘hÑ,!(RzöÒ/P/ÌV û¾q\¢ùÎÌtläv‚mKÓ8ÉnÎû µ ¨Mª—«›áR¦!R²K~WŸci­&-RÀ0ƒ—ªå• –í±o¡}|óšè£ñ1YcלÝ-´ØcH¬öÜZùPC:`‚‡*3ìQ]SF­p3ÚúŠ0‰«’«WÖ6§ÑA-ƒÄ ?ùqoØVRò%<[ #P4FŠâë"`,†àïï '©ùÆa½ÃìþMhËÝÀúüB#LÚî2 ž -¨Ž7ü* Þ]b³ÇcŽþHÍÖU³æÒwæ HÎ]ªÐ »M¼1®‹Q}’é¼Vª_Èý…¨¨TŠì•^(k••ëùõܪQÑZºcHÇ)Ȳ÷dÈ)Ôv*{ÈG†=:µm‡hÈ©µÒ5|½F 5Ç%ºÁ—ù[Õr.ðålEpã“ʯ_b–$Ûa”“ê8 Näqô…êí º¯;2~É95æçåcÿT7ücªAÑ R>:q]ÌσÇÿZ{¯¶1t>@û¢?Ô/ ðàYSƒwíåEõµÇH¶ôÈdYJ7õׯ&[zü&ÉÒ3%ljôBzJ0Á5›'•i ;ÞV þ¨tq&fl9kÛÂÙèZgh{w‡mŸ=ZV[ý»Á*f^AÙÅéd1˜üøS;œ2ÕP¹§¨3¥ø‰‚Æ«7ËÏ'UßMîÅbÿ%ûÏÁŒpÀ÷z>FaqŽÜ‹'ù"üГÄëùÑx=̤+¨˜œÑ!mŒÈô©„ögê È`°¹­ã‡Ì”|&[“)j`ÊŠ @`úåØH{£’RâqŸ÷iQýæ:©ÏS¦ ÖÐ Ûrryq™œ[Ï^à”R †\Hdæî†q¤ÍÇE‘f§ÕR~"¹fg^˜™ûŸá§X¸\Ý,’Ö3Þ¼ÂUrOÌ$ñ;K¿çIßC·1y@À!ÿ™àƒ‹Ÿùí?Öï*¯yQ—ô}Êï’+ ô3J¼¸zŸ-‹dt ÕÇ—¡Ò\²îž4‘mÈ’sOM¡ÎÞÝvjWm¬#ÊÉo‰('Uy3Ê&³ÉŰzrÑ}ïƒÙdü¨ÙWS«UÅÓýÑ$•jye}#ÁFª$ý“‰ÏSzÎ*’‹ºï_yòjz^l&5÷Ï¡Ú׆²ç¼ï2ãCß‹j¢õù/!:Ÿy«­™¢]ôzÇ4Øï›‘…·ÜÔ.ÅâGÝSrf ¯ÐFý·o Ñ’Œ ¶úý®Z>´¦m [§ ê*uÌv°©üz8[mf•Aj-†á|-úqèôÉQv i²ð€¡u ¨ô³ÞoIJ? ]x“þ›½bÎÿ΄›÷bÞ?Îþ Ø~7J7óå3Þ›ÆZC7·’·çEÿC¬èý#ÒÎ’d¡Þ˜Ú¾¨_ê„Ê6R—“Îüc2‰ÅnÏýKÈj¼Ïxßbªƒ¿·"¾Þƒ3gO ¦·’z° gõæ}R¾è×T+Ü:Í:ïF:•3ñ_ȤÏe–Ο˜;wa)ãI‘Š$IEÓœBÛÎÆ~Ë›ûÿ¨Æ}š—õ½§-É/ôζ ñ˜oÚý0­¹ÄO²‡^x’ªÐú9Aµ)YFÔZ£¶Ør3*©þ{ çhhôõÝÞÀ,>̹ŒÝ¶O–q⥢øM‘N´ÛÞHwø7öÐ(QI”Õ©¢ñǤ™$í_;¥zξýã3Ù¥úÿ]aÊÁç½øÛè&#¤0/(võ ñŽÒ6‘(©./2|dQUi’²P„õ4꽑Ëèéè‹5Á“¶>Ük† 3¢8ìöüN³É<÷ë­A´DµÄÀ©%`hĵCZ¾}”í9µ»{{¬nÐS ¸8T¢_·!4“½aljÒì¡OoßĉMŠìYà–K”FumV£°«p‹Óáp&.h•ïÖ¬’Q Xu5+:;â‹ÀÒ1¹¾>lÙ.·ÝÆB ‰cnG|Ûß>b8J±ºCQ‰cm‡oÔ?Ö…óX§¹Û¢å•·ÅQºJá^bŽD*®”G¾îE¬ÛÃN£M¥Ûc? »Ð€­c8sm;yÐñƒc}—@yÑ(2 §C±ûM5̉ –?­ŠnýùFKÙ«¨d}š’#ÚúµÖn¨(2Õ9$Pkirô– ]Óþc•Ð8áì#6QÆ¥¯½Û kDåÉñXJÌmM¯’ª?¢dv¿Ñl×H’¼ß—¶qSÉÿŽmΑJ³fA R°ó1‘†2l'6šV­LtF¤1A’ýf»Á9ÁrÑ<@¸Å°3hµ­!Ò 6">µÁp#Å•9®zôDnbR¥vØ!$d²tõ")EîB«º0/QÄ’¢]ó°£6*²FÄ‚!áÞ·V] ûmaˆôï²µ+˜âšøž|·}}¾Êri\¢ôŽ´7GiZ}Ž$et¶¤[æ™›¨ ‡µÕeT-¯¬åV^½^Zs ™›0>9¨ò™P/?a&Çá2«\°„ž8¯ív}çî~·=67"4˜kÂÒÙ›Z-LMYc¬j«‰)FòÀµ{ª ‘ÑðOgѧc³ƒ`³ÃÝ ,ßiõv†ØúvP"Œ}ÚòújN©U’&žD¨†‡’ÊÇA cÆšu!ë :¶èEKHó@Œ®*_–‰¡ÈÒñ‚¼N±¤o>àd›†4B4"Îm„öln¬V°"üfd[¤Â_q¨£qâmYÈl48òbVo7M#ýc%½âZ Lq| Ê:ŒæU;ޤ3qS˜S·- Mï‘y–¶í®)®)¾(dÃøˆ´Óîî"¹£¤µðbÄ3 ®C({l}l©¢(é6ÞVç϶&ýÒñ$Ùù‚ÊÙ!W¦d´ñÜk:PÔŒâ¯åoæ  ¯oˆ&kR×ôÍJ‰YU·²„ ¨o6xR»1cûRE9PrÔ®c´ä#ãF÷±Ø'{Û€²hXýi5 Ü?)Ù€å pññ{^ìé­¹­ÄïO¯\/Ý 6Ê¥•üêf9¬”VóÏ{— 8=~Ó>`”¤oÑ»j6¿,3‘~ŠHß[+á½z«Íˆß²^ø&@Éì–48·‡­ö€× Fs{Ȳ±40-¨jÔýˆ‚Dü´:JÄ.Ùì'š.ÊÒwê¡íÍFHß8 ±ÐYh5™êm*9ÏAøŸ{× 5É» Ñ/Œ)‰uºy’,•Ùã )È‹ ì>) ÁXÊâ·„½Ó3²2Ó¡Ù?¤PzUÈ·s-Q7©V˜“$¾Û|jÖU nßQø±›I M*ÑöÛMÕ/B=@O¥õ‚Nk›MÁ~Wgç’ÇÃîm«šöi­ÒnöüÑíµöèëýî°·Óœ'ç º ±©­^ `Y‡ÌǪq(&»Æ+ ÙHéöf¡xZØxX—SèÌfC-ê¨ÛЦ¨Õ¨ñjU(¬°½òJÍÜN©ÃL0äWò× EýG€ð굜zg·®Úˆâ}5<ðòò%ç58hˆxçþZ©´aÿ2»%ñ/vÊ}þ’ûf¾¸J©›ê–ªÅk°¬¥WÁ͹-¨Î13-ÆL­Y]\TuU./·Nú)Y @àÙñóóàq¾ÎÃŒ¡ùpZ5ò1_@ ìõƒàB0ꄹ ²:Ár0wloÌI‚E•àcÃC•òQ?Qé¥s´ôà>á$˜ýj,û¿C¢À¾×ûú˜‹ ûX¨§~ŽQjÅêœ9›:`²ËZ/¢® ·Æ%$C/Tà%ægß ¤%Ø©à$Úhœ¸CÄÑþXâhÞ~‡GÇb_:÷oTwϬÏxÿÚhÊ×Fõäp3©•»ÝÝ«+‘mŸlË·.…µå0¥š‘w°[Þ2}CÒ#´ˆmÂÊžN²™•,Þ-ë˜~š*ö›íìÚˆ‚=½pöÂbfé\æ|zyùÂ…å¨Ѩ~å=úÿ<“ý9èÔËùêf¹ø’÷Õ1Ë.…;dXf݊ܰ›­Ñ„ÀüÜÜ:1ê<|M ÎË=§GyœþŽì¯æÕR´ku• ’¨T"¿Qd¤ ®ÑRgdràhæ>‡ÕIYçk=¿þ(íú˜¢‡Œ §d&&Ûq>i];ÃÊGÍr†Á¨=ŠåÃH»÷1VÜR2|²Ó'ÏÍXö…®œöS^•þ¼w橜nž°/6‘Yĉ§ú29œ¡£¶x(ùçp8`±*œƒjŽö°!}VX™§e¥ïhçhÕ"'¥LKz²– ¤ ÎbõÁÎ>gÃ¥_Nq çxj3*"íVc†1Àçâ6B¯Xû‰ÈÍ>Î;Ã>÷êI=”èÒPR!¶4A+t< /†…ÛPÜʨW'óÒϼ—ÃW/yàÞTÿŠi*³»Sp<¶i%5€‡!ös¼|pØ‚JûAPQ‡"µ©LpP›¾\¯ššª©2µV ï¡DJŠyàpä2ÍþuœGÿ~SõËþHçç¯F'ÔWãóh(Yž³å‘™¦\—l´‹™P#åȺy€ÌѼjóX:w|‘rÐØ–céüTu‘<úá<.LÓ/‡¦QÝ<.,=:ÓcÓŸ¹Ì22¥"dLb%·üúÜÏ«¥uv­tíŒwÕì—êO%¹$á.›¸’¼Å_´›‰û4¶.XPšX…)hÂì@½QyÇÈ2ÁcË2URh@S"êb÷Ë Np Z×xÚŽo²ŒäoÁžn¶ØS”’nG¥$ÕŠSŠI*Å'JNŠÅþdöTŸ?‡cGåµµšú€FŸ÷>s£UGÁåàÍôƒÌ[¾¿Úê3Ä$zKèŒ-}-é¦"!Œ̆Ÿpód'/¤%•Û¼>sˆ]V7xÇFŠzÅ•dTý­w¿‰Äçf°n%İ>aùLŸ^á¶•ž¿ô©gcggæ~‡ˆ÷]~·cüP2xße²¨ò9= Ü/‹ ÔøB:‡×f<«cý%Ô ÞLGÞŒ¼~xÈÙâê0šï£ìªõkæÌÌýœ¯n^/¬å_ò~Ø å;¤š«)ù­Ù¾¸Ðs5ì`«¹)X-Q™Ìˆ"|wj NpG Gœ‡ÈŽnüd`L%ÿðÈ<”ÆK 4‰l´0à÷à.™@a%Âz×e-+Ä??dÚÉ|Z„H*µZ:S'Œ%Ìa˰ï´ÖÂÃÒ,-ØÛd‚öÚˆ¸dSÑçšãN9“”pLæD)¶ Íßçh ]z51ïk5¡ÖÞË„•ƒ—|õ›C=‚O²ô¯&ÙÃú¦ž\ƯTÁ€4}} Ý~â™<®ôj<ÆîƲÿüªsùJM³|{£úvï½fT:·[BäÝæþÕn‚öÈÉa›&½*'S²!ÙØúîîn‹¼ÛUÖ~"׸Sg#ÈwLšŠ8þÌ«üöº´³Œ>&DcŽfjöwz-óI”:_äROë®Ø4Ù/OºLÌBµ÷?Íý[€e¬æ@Û‘Á»ìø(Ó­F´1&Êó~³y·QgÛ-ó©çhÆ9^Yñ~»ÞÙ"(„6½ßQ^- ̇3uÛ†Ú±†@lÛí¼‘j|äøP³ýù‰6E»«6v5îÄ„F˜¶CŽGÞ¸4â5ÌÏ\¸p>•ΦÒËQóêþ°×W-xJ(³±¿43÷ËD ZÊ—W W k…êíç¼ï°((ÎýÏ›Š9Dît›pkazt·7´ ºOÑíú»¢Ð%naãõí¸á9!FÝÉ W‰ùãF?~é¼¾WóRößá,¡–â÷zÿÒ#Àõ‰¤wjÃbϯ‡’spŒv­=‹»ZM©TV‰ÊKçϪӡ:˜¿Î±êd؉& ¨ë¥ì…¥ gÏe/,OÙ­Órœ®ø¤-59Ù™Ïóæþ=ÖªkÌ<õïŸx×ÖHžh÷]D$HÈŒ~•R[îN‹DeщS”Ñ÷㯵V§)~0ß&…9œçØáL³¨”S6N[}Eá‡=Èaƒ£‘±ÿëvìWƒ«b\â¶t‰LIfƒlr1Xœ_Š VÝךÝÄ T›o *ŒñcM;Ð×LN<)fÑMíüdÎgÏ/eÏe²j¨Í>:uáÔšo6¶áÍýŒrnµ+VÎx?n–<¹5Æý^ü»o‘ÃÔ=ö$Íf£¹×k²º±Wo´êê3A¸gúÿô¡¾Í§‹~ Î¤: éNíX|6²"êº\HG}ô—Ï¥Ï]8»˜={NÍàÓ± ìÅæ~EµéÛŒæò9ï«Dn»‹|·Œ/Ù2t±Æ,Úñ‘]cûÊ$¯!¶j\¸ïhâN#üGíÛ÷fæþ#ÆVJ¹µ|e%ÿæ{L£5ý=/€^DÊ`¦ƒ>ÉÁz¡°[¡N3­¡â˜crs¤_¤C˜9>® ü²ù5F·s çàX¬0÷¿c鸑/Wh[>¹•AîÉ`cze±W\¡nÓv(}i˜J0ˆÂ–‘SœÑEÃÔ"úäþüÿñLL¾Ñû¯áýŒ7ã©ÿ¿/†'~›ßˆý§pŠØúmùá¿×øŸ§½oô׿ŸV¿ÎH>ÿÿûÙòìÝ^8_Ï»þ×þÏ–\ÎFþ÷“ÿì'ù3óþOå?3ó{Õ¿Ÿá¡&?xz¹Í¨œ~fäC1/¦îûøßÛ¾n}Ø~R=}NýñÞ3ÞOÆÞ'¥ÿS¨Yþ7F·ð].¯ïü‹=ó/¨_Ïâê³ñÞÛpõ9ßãy<²?÷Ô¯·ãêó~ Ùãê…ëê×;qõ¾?®~½ Wq|÷9\%W=, ê'…’~®Ë{põÊ/ª_ŸŽ«E<Åìõ–þ „«óo @¸úB”þ³pUú›ž,9¯GÑpU®ª_Ïãê6jø¹¸ÚÂÓÏÃÕö¨_¿WŸFqqÕÄ7>Wû?«~¸úJJóý`CýšÃÕ!ZòE\ q…œ¼/Cm^ÂÕWà×ûñë«ðµ8®¾-™ÀÕŸ@)çqõ5V¿>€«¯Å½—qõuÔ8øõè…®¾õW߆ÖxWß~¨~ÑFú¸—ÁÕ_F-³¸ú«è­E\ý5|=æýu´Ú2®þ&ÊqWß‹ž9‡«ïC=PZïoã»põƒh§‹¸úá/S¿.áêGñôƒ¸ú‰_V¿.ãêB’û®~ê+Ñ)¸ú§(¾íý3Œ†®þ9Úé ®þò[ÁÕ¿FYÐÂÞÿ‚Êãêß íU\ýܯ©_×põó¨F”÷‹õ‹ä˜_ú&õë‹põï¿XýzWÿyÑÖõ¿£)×qõ«U¿Š¸ú5”¨„«ß@ ПÞob¿†«ÿŽú—qõ?êWW¿q€q{'FØ&®>W7põYØCnâê³Ñè§Øóè…Û¸ú\Ô»PìóÐ[wpõ{¥Õï-\½s»T,þ-êw W/ã 厥0:ë¸Ê`´oãj ­¶ƒ«ó¨J»ˆßM\}PͲ™¢G›Ôìð‡±ºé©ÿ˜ôbŸ±ß¼åÅ0}æF!O៬=Œ½Ã儯_ë©Ú”ó˜³öÌÃØ3Ó°³ç¾ýáÌìJ#zæ›>ãáÌLC5öóßòpæ Â9ðÇ ÒWsxðÔßÿ‡gb˜å³¿ñnU±P8/òø©ð06s“æÌŸ÷Þq%·òêæ†)Ê™gÚcÏ‹~ÈåÛäáÌ3Å•ëë¹2fЙÏý¹‡3o«ÞÌç‹Å׿oõ©•Ò&7Ôÿ±öðÌÓl=ão¿þðÌL -4Óýì‡gfoÑõìŸþ9UÞµæú™Ÿ}ãáŸÉ‚€'ŠNûù%Õ¡¥ÒZžj»’|8óôfq•üí+¹•ëy&Aä9 Úe Ózö§~üáÌÛ+ù ´^&úœZ²>õ¶JUi5©ÎƨÀ¯ý¬*J¾€´gÞúJUÄBmóÔÛÆž»ž+^Ëë¹ Åëba˜ùŒ •’ºüç>ãá™§‚+·iÔ=ÕöáSÏêT|"þsϼƒÂˆj¦=f²¿¬¾ NÍ(ô¯þ´‡öYl¸¤6¿òªí‹ïúY”{sÝÞùrÕ¥gÖJ4DÕÚ­FJi}£œ¯Txþ«!Q\ÉQ _P#v¶v“ü«ÆÃY¿˜§¢Õ ´šÎ|¾÷.°1­œq+þ€e¼0óƒû*s5¸×rÈcæ©ðžÕøò(É¿þ­‡±·åË…Òj-·Jwþô³Ÿ9³Z¸Š•ùLU4†1;;«¦û‡á³ÿþ‹ÑJåÒºŒÜ3ïüå‡o›½ù*FÂSï7>CÛ;¤í¶ûâàË>+/ªeUµâ5næ¯þÃjpT ÒêgzZR0ÑfßûÆÃÙšœOý¸*ÂÓåüFަ®ÚÎ<§}—ˆŸ§ü;üaìÝ›eÛãk¥k¨ûS‡ßà=óÚf®\å¹~ø›jF–¨ÛÏ47Œ5oþÕ‡3<+~ìëÆžÊ_Ëߢ]dëõŒTyÄöÕòUYËÝ t_á½J ò³?­º®pí:uÀ·}ý¸I•S¢„ZnÖô´ý5g7rTñ¿¯ÖÓ3Õr{ë̯|»÷¶ŠÊvCFÀSÛj5Š@‡ñÝ·]G#Pýúo>œ}¶¦,Y½cÿö–ÑÐ8áéûeUF]›™ÿú¯TëT`q¨IƒÙSSŸ&uìªZSb?ò7žù=×Ôš“[#Zªl­òjaƒkÁmþ¶ßzxæÙ¹rA÷È7©11{=ùéÌ¿ÜW[¢Áõ‹ß ÞVÂõR™ä€Ïý‡O½m=l”t÷ðY8l´ÐLªö’ÒÚæ: "%µ>|Æ/ª¼¢oÎþ3ÿÂçßÅnwÎ&5{¸úðv“šYzøŽÐ&¥ädõ\žY•É;Ÿ.®]Su}ø-ÞÓW ׸kb÷~–î}ìƒÅj®À¥!¹rü3©Œd÷oÑÍç¼OËßʯl‚þÍ]^IRÂÉà…«á'$UC²÷× Ebº¥å–eXœΨ…›&vŠO(³Þ;Áˆ[*;Óä·Y5ø <Ò-B-üÏþ0={ÖÓ"Àì—ýÝyG™J²I•úÁÏSãcmóšTò`C­KUnºQ®b¡Íçiò~Ûoªõc#üù£ßŽÝš×Ñ÷¨ë·UK™U«¨oà/uÆ:£ög’w?¶ª&X¡z„œZb$ùHó»?ÿÿûCçÿ]õ_ìC8ìy´û¨ßûI\ê7tn±ÂV¿?†«W!¤ÜÅÕN阂J^P¿põNP¢B”÷¼.®ª8§ád£¶õûu\mÿ¸úÝÃUçahVcí‡ê7NmjyT¿‡¸êàÔuW]œˆîãêõoP¿ñXãüÈ#¡Iýþ¸§W¯7=ZýÕoœ…bÇiô-\ý>è&~®¾9| ®~?ÞÁ·cõýR\}9N”¿W_ùÔï?€«oÄy çAµ¨ßWßü+ê÷—ãê[ÿ«úý‡<vÕo,?±ï@ ócß ÁÁÕ_À{Wm‚“°’œÕï¯ÂÕßÁéìáêïþˆúýÕ¸úAÔ'ðØ¡n£mLýþä õûk=Úp=V Ä~}ù'qõ¡1øz\ý#œ‚ÿ®~ßEžê¢~ÿOž^.¿Wÿ)þ4]ᬊTJpT¿ÿŒG¼úýg=:x¨ßߌ«_Â"‚¿Ô>­~+®þZ÷ÛpõÑÎ#AWýFOÄþî}®þ3ÊñçqõëxúŸ;=c&ö_Ð:WÿÚù/ytÆQ¿¿ WÿÆô¼üeõßÌ,jþW<T=ï¯â꼃wÕ¶®~ÿ5\½ùýu¤=õûoàêÓ±'¡]•p¯~ÿ-\¥0î¿Wi|ãû<ÞÕoŒî™EôÇ߯ÕÔãïàê"žþ]\1²QŠ™×0ê~We”à‡pUňøa\ÝD‹£·g>òQõûGquãìÇpu€üþžG''õ¥9„Fçï㪇{?«>´_?‰«ú£vfˆZþCOoÔÿWÇÓŸÂÕCÕGIWBz?£ðX¿gÞñHƒì~Þ©þÆX:óW‹þ~„Ê·QP’Cr¢÷Ú£-*=õÌÊ#E ç"‘¸çÙºñ÷‚Êþé|¹,Éþù(‰KäùßÝÿÿ¿ì] p\Õy>÷žswWÒʘb‡G³ž¦M)´ñ L(a$KkKXòÚÚ¶!©lã{â‡*‰çPzÓ8ŒÓ¸S“0ÆmIj¦ãéÐâ˜ÂÓC\âó0eÀœ0V¿ï?÷îC6¶áó1¾ü:»{çñŸÿñÝsÜüï ð›”¶®©·F\Fé!þއBÌuº¬kbš p³ ôó;"S“¾OFÉ SVˆQvÎ ¦e MT.æ¢?§÷˜mc ¾·z¢D`Ék$”!Ñ LpÖmœèxYº3ÏSèÛ1,Ó™ÙY¨ ù(™ Ñ¥e%qè§ mº:rìÐ_8ôR¹ö®æÆyÜñ(ÆvçÌÖ¹qLð‘Õjôôl®4ÌŠƒÿäª0‡Î7¡1Ù‚f®_G.ÓÒšíàò”„B¥¥„šýpïÔî0%á (Ï0e"Ç38áT¸Š•‘Œ[¾XŽdü;¼ØT¡kZü8AW®E`"Aï”DÁÛcPc6ŒwñÊÐOPæÅ…|u+Ú‰;çÀu³ sâN•liœÙÜ&ªÄ;wQèÕeÛfešríí6rg¯ƒ}Z|±4ct¹N ìNWíCÁ›ùÁ:Å8s˜¨©,ÆÜ&–%Â.lu]¡±­-c•­’©#4AÓ§L†",d#Å=é(ʸ£É7Wï ƒ SIÃþ, }¡¨`ƒNâyqùÚßdfæ¤RzÇ0D@R OøöÊÐh+›/܆KeÛg$¦ºi'#eÑ×~¹>ô“9KÈåWß·¥öYâlú?ïGÍvMëÈ–"7þCg†º¦3Ÿm.Årpa/Qà•µYÍ9«sý»”™Ñ*—¢5“’åÑ7ùÑoÞAý—–bdÉsç ›¬{¯^»d¥…Õ3+1DdŠÑ½”þ4i¯×òIl1×ÍG“µJìÆtn`t)[ÑñÔ­)u¼À_ÕÉÄl·Ûâ/2©°NêTz4ª±jMLg¿“@à¤Íh”8òª—m“u3sÍSË“«Yùú‡M¹utî£Ý€”ØâûLà t [ÛÐ)äjŸ_&Ó•ëtñæ7¯ K”άïØÖ&òù¶V©¨`ôj\H¦cÙW^.´~wXWþ…ÿ/[$Zoÿ‚Í-cÈ*å†-a­­sï ÉjÓ ¨‰cDò׆†™ÓØ1W N +#J†Lzà ›"ÙŽ‘aÍÿû1æÝ×kó6Tz^ñ`•æ3øi”OðN6’à¨0FfK*f_µaR[hì([fzÝø0QW@CæKJëîn´fœƒmŠ{•~ø”¼nÎ2‹eÖ†aÂtÍ’£~àÑ0i"KC§ ÔWµñƒîÈåÚù¼›ÆFá¼(3c±xÆÎ©ÑŸðp|Abw[¶†‰(ô®7n k]¥.ötC9Ÿ£ÓݸCFõéâdóòÑÉô™OàbÐcq4P¯îSQJDû72ÆoS%Ïl~¡^oÀ%‡ds±Õˉ™Esq_Œå±¾ÞÜ ¬Ê‹k Tú‡Øf&‘›6/+§ÐÁÍÕ¦ZèÕÏWgeJ«^Ÿz@E9z£øÓª0§þì:\,ºÝ…’¹ç_+1¼Un°øÿ4ý¯2 ùs%)/S’¢Ãñq; ”eÂø7²1žT’ÊÃñ)‘è%=Mé&ú©ôŠü›éGéŽÇç•$qü%¥ÿ B£OâßÍëþ¯’ÄŽ/(‰rãø+;lpÜFé~^í×JR8¾Héô&Ci#Ÿß€òÆñ%J?¦¯ô2¥MôÖ^¡ôSÆ!è=ùðÓJf_S’äÄñÿ”Ø ìAQ“(E®”ÿ4¿Gv“¿™5û¦}Ž#k ºÇ·(½Ì²ß*±upd$–qr¥ø X`8î¢ôëôw¶wáø{J»æãÈÚdŠU©w•„Âq|OɨÅñ}Jﳌ>š¿‡Oý¥½Ì ïUîÇ‘|+ ë2O£Èa’މ<fo•GFºòCöè'êZø„y ºŽeä`|B¢×«GÁ3öÈÑ£ÑÃ<ò@ô‰ð*=ò@4ù"{žþF—GÌHäèÓø ò@0A¢?­3ðä=ò@4ù"y úOðy úOQ/{žfŽÜ#y ú ô!<¨ Hôõdxòy zÊmTªJR)ÈÒ§EGé|Þy º× D“šà‘= )C©ífSê3øläèvô <½°}h¨ eó캸AÙD»^Ì;%D™OÄvÒKÑ‚y š‘ɾënÞ Óï0 ±'ë¾ÕÈÑ—³vÉÑWž§¢üûWøî £/ûò~V˜ŠÂR¸æ6ØIY;…Ü=7Lê®Y æüû kó¶7E™ãQQFIŸs`×dš1í¶ÎsϼHƒ¥£iÓÏþìTè×NYx› †8eáÕo“•YSÿšUø8VýÐMa²*£û2J»·ÞŒ¯—Òc×~&L—Òîþ¹ÛÃT¢8çªrnMý¿‹SòÁ‰÷Â6ÌåmAÿÓ\NRÑ,Üyl½Ün<‹é›wÓº·óÆ¿¹<Ô‚Û_åP‹bï=U&û¬ÎÊ廸‰2O<Öo]¡©%Ó8ÉR)ØùÏÞiOÀ€›ÚQmÀy§¤ÑÕ+Ò«zW Сq_Ö­%™m[Ü? [ÛÊôtìûp¹t*W¦f`6°.ä:›Z¬k…nỈ-IØ¡°g›Éìƒ GÒ‚*P=¾^ìnÑý/Ÿ;?ªÌàùݨÁŽéRW¦áK´6uäòqª>øöîÈSPßù7TA§á7ÀÔO3Å[á€zçm-‘=`<à®rÒ(3Цڪ$•CÏŠõ•_‡®Y_Ú«.ŽŸ<=7¬ÝØ"ýUDÿ¢ù¥‹xËÑÜ£ ŽZ«’Íæû§V8=fÎnÌ!mó,Ÿ„‰!e0"Mj> 6WÈLÍ ëIIô=WjÓ/6ÖMóÆBs':bÒ¦ð˜Œrj0脳'à{Ö£ã´3•Å=Yý˜¼+ÔõÒÐQD\é¼M)w*_‚¥¬s6²r¼šl¡Ì2oö…^][sWKǦ®ö}’ªgW¯œxLk_y⑸ui¬zãö„5Õ³Ôø¥¨g;é­¯‡5¦"¼m’å–w?”"¼@t^¤ñ*ŽàyQ |Q8WQ(¼b4·m‡8êÔ0Ö1›Ä1=˜IâérŸÉ ž¤±M”¸ù ©€Q0ÕÏŸ3 ÄÐk *èŒ,ÞÒãJ´Ä¡‚ýÖÖ0°W+ìXôÎkìšúܬ:¢S’ÑK?꺹B`)é¹oïDãÏšÛi9fÁ"Œ’d¡©äA¿ÐRVQæŸï S¥2; •¾*úaW¾%'F¹5T »Š7oñq¨¨äáû±hûÆ/ïóÝîj·VÛ—™ºu×´ØÉ!xmñ!ù»¢Mõª4ÕEìøŠmc¾:žn½œÙüñÎÁ,Âw…=á´ß [Õ«ò‰m ôØý;£®¢¯E.¸þúà é*;Qg XÃÈçÀQ¹àú;[iü+1…!‘ ®o¥H.¸^GŸ‘\p}[¿²ä_};úŒ%óÞ±MY‚¯¾g>$rÁaþAjPbø@bØôˆd¢ø~šCo¤G$úfƃ‡8Z~LýÎ8p°‰£Š1Ê€aqà`3Ÿ’q`8†w ‰qàà¶ãÀÁ6FÁ†‹‰qààö¦mʾƢ<Æa`@b8xçc8xƒeŒˆ;ùlŒoñþÞfe8ØE}Ì8pð;ö ƃß󉦹£<ÆáBb8ø€#tÄÀ£Žé¤OW²¸´‹ÞÙ‘[ Ê!LU$‘õ•0¦+ùÑ.ü3"Â?~§xJ®ßO$çW“º×áX’J´N‹)O»«¶œÃl¡«±`‡É&öÅ™…œDw/ŘÊÛLp?Rñþ‚Jù Xþ¹ b¶ð}»Ð²±Ë§‡8žÜ`”¯ú¥Àéÿ7ô«Y­íó¸+æÀÏéà0¼ÈŒp|2Ÿj¤ƒ‹Û·_ÝšolξìàààààààààðÑaª_Îåu$‰d„$ò áBx°ñ¯S]¾Rùç—JgÙm£—ŠN&ü1§²Ë`Ô¨2‘¦kÉ"¨€!\æxù€û7_¶¢çj~–TéEÅÞKz–ts³K•R©âU –u/-ªe.ïYªÌ¨ÚZ%!ÜŠ§T\Ð/” ìEAâø àJÀÄÉt*Åe€G7Qj R×ë*Ô˜¡¼TŸc êŽm„gð½TÜè@t—¸E Ù(ó¿ú–,+v]³by±«¯gÁòÞ%lé.î¤ûWíóšëæ ªù_ÇO?Éñ¿†‡Öþ‡·ìAÚâþÚÂD×þÃÙÿ•o®sÿׇ•lz:Îî¢ú¡ª½zŸV3„«¾ßó`ßWoÐ߆!îû*».Vþ㊲“e"ðâ3í³ˆo÷}Åÿªö}•ŸT•û½¯êÿEŸ;k8|üp(úÿpéàãCóÖÿgåôÿ° šÿ½D–!àÿ7ò­æ/ñÿÛÁÁÁÁÁÁÁÁÁÁÁÁÁaÄû»pK–C¿Ê ýˆÿ&¬Pâ}í騮@G9uppppppppppppVœ9$þ÷É…%ËŠ’D2e’H†$‘‘JðT ®QܰèÏÔJ¥eþ÷5* ÿ]_(i„þ}B¡šNÃÒ„Jæ.½´·Ø§’*ÙÚÛÕœ/¨”ªo\¸°§xÅ’Â7õµµÊ¯ä~Ÿ€‚DEA"YWÇà 7ª•‚dRk5Êt÷ MÕ+¯÷Bõ®¼¹}ïlÀÞÖ€½§Êr O"Êü¯ÞbÏÅžÞÃf{ï‹!ó¿'L>kÊxÇÿì¯ýí½/†ÌÿfûOqí?þ·ï­þ÷Cä$8þ÷¹ß‰ úŸp¿kí'%î÷û\ÄSÇ¡ü'˜°7y–©Uùêñÿûþ?s€Ï†ûêÿ#¼ø·:8ÿ{âø³ëÿ)“ÜúßÂÁüï QúÈçøßŸxƒŸñrßÂÿf0ÒѾ45…ìààðññѾ‡‘ ÷zƒƒƒƒƒƒÃÑÇõCâŸÒ~u~v[fÚŠžâ’Ë–gò–2’é[°piñ£»ÇžªQßP&¡T˜Z*-ó¿¿¡jk†ÆÿNÛZé’U¿´¬èíƒÙ§›ª¤ªéì-öÈ')U3kAoï•+zá‚Y+zúT­JæW\òåbŸªS©9= º»‹=*­¹+—C0é¦~oϾ7^ |cEAB·õ«ðÊÉšiý\â½Tb¯Ë51j£.sÈk“-ýê'ߨKMïW×›rA:ÑÚ¯¦傊'àã4/ˆt ~Ê>â€}¾èáäÉ\éèaë.-.èîê-^²bù¢#Â:ÿ{Ê䉓ÿk8pðö?|6øÐùßS&Orë¿ ¢õ¿/>vøßª~Ð?ò¿e¾;ÐÚß^ÅÚßµñJß)µÿ;5Ä›qp8š8˜þ?lðƒð¿ÇŸ}ö>úÿ¬)g9ý?Ìÿ®/äøßŸx^¼þw‰ÿÝÔrüï#ŽA5éx€É{½¡ð¿?ÛV\бÔÞÌ’å—®èY&‹Cg eúâÅÁGOÂS¾š­>­H;­TZæÏVÚÿ{tåªÚK„^×´¢§§x‰]Ö{ô˜1J¢,8{Š,îºhohY£»úå_ùpL™ÿS¼¢¸¼ï#XýùZÿyâD·þó°`ßö?Ò«?´ý'ï¯ý'Mpí?þ¯öáÿ>AÅä©qö…‘Cäÿ¦†pµó“\úÞ¡ß“Ùbÿ©±o¯K.ðIø§ ¬`?¥¼5ƒå{ê8”_¯RÞ*//Ev-h©·huhOJâ·sürQü?£Òö¯Wì RžüïÿÙ;ø¨ª;Ÿ;IÈäMH  V#>ªÐjðÌ  3I&ƒ!!¤†“!h|4ˆ–wW]uµ´Û­«­J¥µ»]%j©EYÝ][±«UÛªìv©í®Ún={~çÞßÌI4D )ôü?Ÿ{ó½ÿsîyþï¹çNÎýßT»ñ-{±³Ž8Õ‰âµÿŒ¶ÿ¹«lÙQR]9ÄŽÊí?ËËí?½öKíT!<±%ÌFŒ1bäÏG’çGÞûû ëÿ§–M+Kžÿ•›÷¿†E’×ÿä™$2Ìú#FŒ1bĈ#FŒ1bä8Ëcûï«7Åþï§÷I„GðGL¤q?Ââî‘.Ë0É,Ô²Ž‡–AB¡zÿâ‘.Éñ+‰vc^e2bĈ#FŒ9†äíô¡¬ÿåÇ"‘ãi„GŒ›¬’,!ö§¾%RÅñÏFÖÿgêð‰VaÁÐÖÿ§´4Ãí»vò>J¤5w´\)Ò…·%²²^ܽ"+rEdźh$Ü"¯µ=éìnj «m]De׬l´µÀüŠÎHS4Ò"²EÆšŽ–V¥o9"·­©+vRk¹"kYT÷䉴H{K—êYh¢ëºD¾Èíh¯èX³¶-¢_C#2º.o «Ô"¢@eбfêYQ(²::[Wµ¶7E;:ÅX‘ó ªZdìŠÕMM+TáÂ]‘hxE[+N‰ˆÔ”¡µÐØmmúµU¢övçň4‘ÓÒŽ©¶ËDÛ…×EWÎPYTï)Î*×BŽïû'NÔ¾ïÓ¼^±Ñ* …øÃùB¤{¼%n¶â§x³ D·Ç^ÿš ß÷yYYâZ8 íû>oútqGx7ŒÖûÚ÷}n®Øès±(8¾ï3”bÂVääªDor%š›®·¹yiJñU—btºÊå•‹5ZxK~îøñâ^[‘ŘŒù[Ò¾éã=ù"õ¥(€þ<ñºfefŠÖ”øK#c3ËËźí÷ 1nì¬åb[аzSR¡ÈI+Òræ-k\ŠQ™ª ÷¥Š ×;M([š¥öᎎ˸ùÊDÛ•‰†+«•4Y™`¯Ò6V K•¶™Ê•4PéX§Œ›¦ŒÙ¥È(å@&Ýæ%c¶%…lôûêdmƒ¯®Þ_'õ e¥¯Q. 6¨Ãª@C½_.õûÉ¿"¨TªŠº Ã85;%¬O8§˜¢Zs,5¨xdŸOß9+®p¢»UöŸ•þ€o^µ_%¨Í5„ª}Kü¡ªJ8¦²².X#kêü!Ý¿:®óûªÃ¾Px~uÐW/kªjü!ª4+Ô±/ª ×6ëý!Yµ ¬SÅ®ñUøe Xn©ƒêÆðü†êêð‚º`CMx^£ 7¨óü•áPüú:_E}U0}eU]¸*®P¹ªF© †ê¨¢ÔVË ŠTí—‹C8¨œW"û.¬œ‡SùÃÁ$Âa=*âV̯òWWÆ‹USK¦ÚPZ¬k€h¾†ú`x‰¯ºA/óסç«X¤š)´0ìUøTÝe¨¾®ª¢>¬ Ù™Åt>UIG£NE¨K%jÂc}PPùTUêƒô×ÕëÂóÕVYµ¤*¤J©ÚÈ.€Ê¤² åöUÇŠh7 Ú¶N.¬Z°0Œ–VýUá¯ôtÇýU?š6T_Uß Û¶ÆW®X¨,S%¡{£ZÅR&Úÿþ_ÿÙÒ|T^þƒ¾ÿ3ujiüýŸÒ²QøV‘am‹½¾Ý)p4ö;Ù;4ÊÀ­u-‘«šyºHe±b¡"ö’÷vûÏnûOqBØÈþ1bĈ#ǘÌÖ©xPHÅl[«RzEü@ç(®òôŠtçQÞŽ1È=àÓüߪ\í¶$ñÎý±³³O”[×4â»füÕiŸqr÷.µ} ¶µ§ôxŸW[qQ·¦´Ç»Kmã§õx¯PÛ~µÍ˜®âªM”õxW«mÆ u¬¶wÔV3³ÇûÚFÏRé¨ ùáÿV÷o®õ.;×>>ï÷/ìÄöCµ½4¾ÇÛÔ²Äën¶û Ù­¶å6£»Ó«Wi«ùÒ?¡¸ú/»ÒIé}\ú)å¶®(–¾Hÿç¤ÿúéœ`ò„yÜ­£í‰XÑö¨N¿ßÇ1ó{¼Ãÿ­ï›äûæò…À©ÎaOãíªGúû¦ôx/T}ãNÿ·CL¿@àÂ@]¬X½ð+¤ÿÓÒÿpˆég9Óì)lå@ÿ·zW-ï:ø6ó+ó«ãùÿVûG q@]Ìïäôxá7ë׊ь.¯õvôô»®ŽÔx±°«Ö{Ia÷@~bGb¼@3z7Ôz#¤¸ãÅý­µÞÖÒõNHJwbB2VÂ]’r¨%0bÄȱ& ¿ÿ çObPÿO%Ó¦MOòÿ4uz©ñÿ4,’èÿé Ï®øÃ§*öýçuOxŒÿ'#FŒ1bĈ#FŒ1bä˜OªyÂ#îµðC¯þþ³%¶ OïN{ÉRJo·¥W*a=’þB1ÏP ]‘NãÊȉñ«u ˆÕ_Œã #FŒ1bĈ#F†[ÚÓ†âÿ© ²)ÚÔÜÔ)ZÛÙÚÝÚYu,}ëy ÿ§G­WÔÓÈ.k‚z(IQO%îï?_4dÿOi ;º¢"M¤T6Ãÿ~é";i‹¬ˆ†ÑnÂ+²«Ú•Þ9ÌÙ k[š¢û0SdWªÈ<ÌÙÚ‘Ž}˜-2+;;ÖÚ9"kAgS»“N®]Y錴¯ˆtÙª<‘UÕÞ¹Â>-²|mð”£òÅ8'áèšµaÕ¯mNcD~uÇŠËl•“PÈw"w·FÖÛºB‘Zݱޥ+ X뢭íN‚ãDo‚öÒ!;ŽÊñ;®‡ôùi"K»#³F‰œúÎÖU«X»Ô´ ¶ÛŸ³Ž»#¸ÚéRŒJ+.Ý.QéÙ))â[–öäÝ?y¡¸Ï¥È€â~—"Š\Š,(¶ºÙ™Jñm—"'K)t)rG+Å6—"1¾ãRŒ†â».Eþ8¥xÈ¥“¯ßs)  xØ¥(ÌSŠï»c •b»K1®@)v¸©9J±Ó¥HC9q)F!Æ.—BÂøee³ý£ Ëæ¥Ëà¥ËÚ¥ËÔ¥ËÎeÌÈeÜÂe’y˸m˸aË­Z&›´L¶g™hÌrK–ýÍXºmRÆ Rº­Q ’>ôãëÿÖ¶­[ÕÚ~4|}Šï¿O-›fÖÿ ‡ ÐÿGÜÀ ý_2@ÿ—ÿOÃ#öûÿÖEúýÿ§p/´DÈ^zˆßï÷6×'È'ÿú!~÷ÝZ9<¾ÄM¿¦¦ßr•f1¥çûeb‰<¥ß£¦r?Nøæ{ÒKu»íƒÞC,Œ##*ýÆÿ£ðÀ ëÿ‹§O)Iÿ§™õÿÃ#ÉßöÅ=¨xNí¿þß|ÿÙˆ#FŒ1bĈ#FŒ9ëpñýçÝúLgý¿ùìó‘³LÝÈa‰Y/oĈ#FŒ1bĈ‘ÓÍÖPÖÿç,¾2T[]d/9.VCXó-÷áódÆ´ñõÿsEŠgˆëÿõ—ŸÓDJK¡ïN^„Þk=áRØß×mi©ZâëVwtEÎ@?Åú_u`Öÿ ‡ôëÿ£ð°Aú¿t þŸnÖ‹8ëß×럷Ç*ûû_‡ºþ÷]”‹ÁÖÿæ:àX¼!|ïkSâ¦×E×{XË뱿÷Õ#¼ÖÕ‡ò½¯x¹¿ße¾ØeĈ#FFJ’æGå ƒùÿ/-Möÿ_Z2uŠ™ÿ ‡$¯ÿßäòÿ?ɬÿ7bĈ#FŒ1bĈ#FŽ ±<öúÿ¨¥¿xÛÏÿ¿yà‰Yÿ?b¼Î1bĈ#FŒ1bÄåÌ!ùÿŸ÷Þ.ßÿ³‹ŠG:WEZŠÖ·FWµ{_ðˆBqµU=n²2¬þþÿW¦ÿÿ¿ÿé‰~ÿ½‰~ÿ3ýþg&úýÏrûýÏNðûŸÓßïn‚ßÿ¼¿ÿ£?Îïþ~ÿÇ à÷¿ ŸßÿÂýþÐïÿ¸$?þåÂc ñ;Cõô§üÝ.7õÚÓÿúdOÿW${ú¿2ÙÓÛÓ?û_åöôïøW»=ýñÿ5nOÿˆqm²§ÿ/¹=ýñ¯ÛÓ?üøoHöôÛÓ?ûot{ú‡cÿëÝžþáØÿ·§¸íÿr²§ÿMùñÿósáløí?RâZÿi[5E[;Žìgóÿ[¦8qýß´²Róþǰˆäz?¹Ô!ùŒeò÷G[¶‡t9YØ~ÖåËza/”›õO«ŽFÃ^µK§odH¼þ¸[{rÎÊb A¥Éà¬á&µË¼¬v¹,GÌc™5`ƒM^K@:Z¨yCiòY0 k•f  Yí XA +…ýVˆ.üXfŠÂÉç|ð+áÀ©ÔdPs[LC¸p2ãÔþHØA¸‘‘û儨Ú´)ÍÀ‡jw«s¢>KíNœ¦vŸ¨û‚8™í£aéœÂ³ŠÕîTVðT¦3‘0‘§C+ïPp:5§³Ì§3¯3اN¤fáºéL.ÿÏ1ކ5}„¥ ÚB¸”ÐG¨bä½Js<‹U>›šI˼;]ÈL5<¡Â`pò1º;°° ± Ѫ´˜A‹i 6T€ `Ci8C'È8&P¯Àÿª]-¡Ž¹cl•W©2Öco«£ã%Kâ™IC0‘ðávÂÂÃ<})5è¥5c.! ßÙbPºe5±:ПK£‰JÔûRÀ ÂI„T»0[LÃ~ËÓ¨ér@áM¹d4`Ühfc®Ð vÖ~ ûT. ;¨ÉˆƒiDŒ€NYÉNYÉfYOø¢Ú­ÜG@1ZÙb§f¡™p€0™Ðg¹©ëkð2Ày„6áÀÓnMÏÒ€1ï˜Èµ„·îT‘1“Ýj‡ñW_kÙtÖ^gÐOÕîrÀ<¥é¤w²î^eÐ>jš “ }Œs=5Ajö º‰°—AQ³…šçv0‡”ÿ§v¸Ëk/`6QfºŽý®áEáÀõÔ̤f5¨yŽ€2£õ…ÖÍ v³UÑŽzXÏæ]ϳ4`Ôº€AïJn,= ºŠ‘¯à®w kz­NYi¾øÚõ çbD)õ=å:F¾ŽÛ(œë­¯¯S ˜ÜÀÜ¿ ˜e9€È›yü á\ž7²17`M›Y0 ÅÔD Kt #?zZÏ4´Ð,)œ‘䝨ƒÍf¹ð ÚÁ¸åOÔîVìoX0 Û„K©¹Ëç6À\R¾][ÚÝÁÓÿV7¯ÚÝ Àø|'O×0‘ðávÂÂ^ž~#50ã»ô&¸…AÞU»¯²`_£Eý“d ³©é£‘¿NLiþp·Ú}ƒéÜÍt4ÜFè#<ªà`5ÜE@ÇÝâÞËîþ&ÛYC€š>j.% s¿¨%PåûhÆ÷Óê4à*@MôTöö»†— ã wzèÏ­lð­jð SÅA‹ÈÝ ~ÈVð"ÜϦÛÏšî§i¨cÐlÂÙ ZNͳ„>¡}^bûhøšÒü°LÁ¿`Ë/ó¬WðŸHôDèUöà«,ák,óëü¢³î_ðÈ/Ùb¿bhøº‚_³:o°Ìo0w ¸ôÞÎhó–pF ° ã wz诬×gùOj~ÀƒÏ0¡:Èêd-²s²:Ù)Ù¹i$™2. =¹}E¸|›5}›Íû6s×°ŠqöP3ÐÆ §©yš;¨™MÍ2j.! /Þàvó3ÕÐLØC¸ÐçzWÛ³‚÷¸%½Ç ÷X÷÷ØÿÍ~‡éÈ3ü#£‰ådï3‹„38|ÈÓqñËóUÐ˜Ž†KÝÌ5e±üº$/#À–ÿHkùˆ)ã§n=†ã@=OÀ’I sð0²¥XNC¥0ùÇ• ï)p;Å8n'LdPaa/ãSÆ¥®Ÿw4ÜB@-²¡ªxཀÊ]ÀFXÄFЀ_1S˜—Ä£ÿb&`C¡¶z&dCÕè µ«¥¦ŽÄg€%žžëÙ§ L––pÖð3Bƒp] Úö{ Ò 6q!ÓÁůoµ¶ðøÖÈê4²ÊfS³/‡AÈt›å"æuñÿ³÷.ðqÕýøÜ»’¬]ù!ù•wXåi'J¢ÕÓÆ¬ÇÚV"KŠ$;v€nÖ»kkãÕ®¼»²¬„‡òàM - mZ –ÒP¥ÐR“JÛ_Û”R~´”ø•_ÿýSú¢”"ïoÎcîÞ½{W»k+zXsü‘÷~çÎãÌÜ3gfΜ;W=‚W©W«çþ3ø¼Ô4x.`öuŸÊ0¬2­„–œãŠ1¼PPD.` … añ:l .Àút.zdÈIÅ^À(4¡žN\eÕÆ±à”ªò)õ(«”„buRE)Ç,¥žiJñ<¥ò9­n¥á¦+•OFEÆ‹OÈÿ²*C˜â pF±:Ÿ’ÿ… ˜^ÎÂŒ ¨ > Šx.`Fô ª2^À.ÄkT†¯ÅT2äuȺø¼Á1uq^¯âàŻ՟ºE…°l…î‡CÿCJêð4ÄÃªî¨æ…A{^4˘¡¢ÅõpñU<†¸P¼hV!^âU!W«kÕŸºø´º1~3\Àhþ%uÐI°áÅ>2 B€ç·){;\€JþYÕò?;ÕÅÕ¬ìÀ”€šíJØðbH…DÕ<¸wÜõð⸺ø²ºõEÃòóp#Ú/¨œß¥R½ ‡$¼;^À\ý=*Ÿ÷¨|Þ«BÞ«B@G£iúc©[xK×÷©§ü~õ”ñ쿤d /îV©[ÐbP-ÿõpñâòiògêäðƒŠŸ*Å‹¿–ÿ6Á)߯À<´ÇáÌàxñVu1®.þF]t¨‹—ªTPXháÜï×Tó~.~F]ü­üïꬨœ?¢ó#*Ÿ_WM÷„ª^Àœä£k€Á…ü šs¯T ðb›ºø°º¸I]Ü£.~F]|Gþ÷›ª5>np×û¸zpx‘PïW·¾¢.` û-Åh%œÁþ¶zpxq•º¸^Ýú¶üïI¼%C>©"ÿ2/øb^]À-Ðe8«ü”*ë)UO,ÆxCÛgTÂ<»Ìïªv¶.>«ò÷”@þž* fNØß?M'ø"¥.v«‹§ÔÅyuñj• –o¿¯ØÀ‹s2äT(¬…¨´ÿÏâ»°ÿOG[ñù¯ÝíÝÚÿg)ÏÆi<ÿõ+äFÙŒ2³›ÝÞ<Ϧð<[xN«òkþnùÒv‚c³íùý®‹wîkMyˆ¼Ž?ðð'ëÜ×r®) ÓF ¸ ÉÞW`Ð>,ÏH+Q½®¯ŠÙÓ¤iiÈóo|Q0N÷Xa þ‘Éߢ„ôgü¢þ»Q-!ãýˆê8dÑ:!ä%d¼Q=ßÿD>¡˜ ›ŽP^O÷_E´ïSÌM„8Ï›ú›È9íÛmæØ‹h çDGn%Äí²ÓÒ›Ûù*Šè F¯Ct!.ïræ€êw!ã{ˆ®$Œ)DW3Ôž×2:ŽèFßGôæî"?sG­ÔLÜ1××1?^D71ºÑ-ŒFÝʈN¯¾Ñ ˆn`4¨…Ayî`ÔŒèFFûµ2z ¢Û½ ÑÍŒÞh'£/"ºƒÑsˆ®çVÌ" P{ DmÜŠÿ¨[˜Ú¬ƒÛ”òìäV¼Qµ?£]ŒEÔÍèˈvS{sy/åö¦<÷p{_‡èeŒ¨Íör8•÷rBüT^Aá\Â>jaã=ˆzQ }Œ(f/·0Éuq¢ýŒ¨FýŒ~ÑAF”Ëìÿ7YR¨|%iêu'#š Ž2B4Ȉx;DˆëÄ~šÆÏ aDÚ`˜¥»›q.p;,4Έz ôÃVÛƒ+Ú-V.÷0¢tàUœBtŒÑŸ!z%!æåUŒ(ݽŒHÛZ‹UxÝfÕêLœÝGȸ8ŠÝaÕ=ÌmIýd1`µn”—cDy‚ãÈ3iå F¤ßâ„X¿`DéÀ&’ÿ1D÷âÀ!«ƒï“3V‡PZ Ü® WP{Â$¸Ë*ý4£nDSŒ>‡(ÅáT£4#’ #*z,ô­ßC4͈ʛaôDàš´Ûªí,!Ö)0:†èAFÔà¥}ò!z !–pJÚc•ºùeÖÓ÷¤½VmçQaDZäaBœî!F$K2¢ÀUéåV»¼™÷ê71¢y5ØÜAШÚqŸPzø­Œ¨Fo#Ä%ÀAU#p<@O¼@[AôBÆ×¥¹ß’‰ŸÆ#¬ºM)Àfa<øx)¦5lã¸OåÛ@ýƒ;øÞ<†Axœ4ŒéP[|¾Ž*0°S‚{1¶¤q\úÕJ&hrâ·¨*›Ð)pdü2 ÂthPœ°›È°Õ 5.y`‡¡Ýx‡zxlÑ•çŠðà\¢Š—!5iZõ„㿜=ÓÁßp¿5«‡Ù(ÒŒÐ×`öp¢÷0"½®‡0K qî}„Œ/ zŒÑÓˆÀ§ðN+æû ±NB˜æÿ !ÖîàU8hÇà-xÈŠù8!Ž „Ê#žœþàŠ”Ö‡±ÿ5F4vBÿ‡Ù ͹?ʈÒ=AȸÑGQ.à8biJyaVó#Dൺœô2¸îYuø8óÿ "ÐC0«¡µÈ'q ‚c(¬ÍˆždDÏèw 4ïü£½ˆ>ÈæìzÏ\–͹?Íè7}’Ñ7Á“‚44 Áø s£W#ú<£Ï ‚Z³FÄßgDÏìîj=õ’s1ã ˆþµà9A3³D_$ ^W #zšø0¨]`„Y×ÕˆþˆÑ.D_f4‚,O0O£gûÇŒ>è+„h,C‡:@Ï#9¹O"OpFyŸÕºÐ:0Û£ÙÎ_2nGôçTÏ,a%±¤à/9 ­ þ†­ÊþŠIù×Ñû*#Z£}¯ÃžgDs&p§‹Y|~C âØÿaIr÷MB,wзaFI–°o1¢'.p0/½Ñß3zÑ·ÍR©'ý##*ñ{Œ¨ÿÀè½ÀˆæêßeDëÜÿCˆ¥‰ßO`‰ùñÁ÷À› æºÔ¾ÿLˆæ è×vÊš{ý£¯ úÿ9 ¥û]qžàSêÿ?dDkõeôNDÿÎè<"h]9›6~¸^ÀŒù ¢ÿäèéþ£D?&ÄíGŒþ¬oaNþ׈À,­Úœµ¡î3êaË£Dúæ§Œpkx¡ëÑ3šgô$Þó2¢g”#dô"úF(i`*E„ÚÀð1ÂöÄÃ&ÓêùµŒPõŒþQ£¿Ç Ua]A¹€]Ö¯E´‘ŽHØG³\Oal D}΀IŒw»mcô¢ËQé—3úD[‘v5¶3¢Ú61¢¶Þ̈Zì3ðÌQƒWâ–¸ŠµX@P&Œkáèa\Cˆd¸š¥+¬hî´nÂGŽZÖMˆ`œ°Íرÿ¿ÆÊçjMZËâh÷:«µaÜ—k%ƒ¸µÿœ ™Æj?ÒÄXp¶ÒÝʈfÿ`izĪ=Ø PK£¶„ZÚ»ŒhCAŽÞhÕ¢•ñRD°¦~“•K;#ÊÖÍo¶xÔoQzÙ€/´&®ÒŒÝŒÐn`t3BK–óVëYw1Â‘ÔØÃGDÔ3oµZ 8‚>…£ Ža€pŒ0^AˆæZ(So·žÙ>Ak:Ë  Î’^èkï°ž¬ó@ó|Øz`­öLjÀ*3ºßBt×}?#ªÑFT£F´„ƒÙÚ»˜{a 2¢t0[{·Å ÌÈ`^HýtÐ{­Ò!>hA’FóB4‡Áïçý¢ÕËŽ0¢òF¡Ñ8Êõ”q˜ÎaŒ»áÆ€þô˜¥‹Àzð>«t˜•¼ß*ᕌ(&ÌC`Vú¯ˆà Àª-Ì'`ŽºQ˜=÷!–òãŒÐ†iÜ'pþÊ÷¢Œ(OXâÂüí7Ø„43Æ ¾¢N" ªgDyÞψʃqfº8§@²-ϱÿKl ]Æ€qóC–L‚èÃV[@¿€™/õ–)F4Ò¤ ±üœf„60#ˈxí 3f’óiF”ç £»Æ|Âj{Ðn0'§\`D:e–[ ç)Æë=€è!FÔ†sŒ¨¼–¯#ĺïAFh5Àšr…¶ ãaF$?0¢\@Éy>˜Ío?nÉè¯ß²Zâ­ŒèÉ¿…åù&F8c4@ÁŠà>Dog„ó ãg ÑÊÄí«#~Ž—ÁNc<¤†yþûý!Ž DJë0°OYé ¯=%T¯~/#œ¿¡¾xÊÒ0ïaD’½檤]ßOˆ¹~#Ò `DR½ï3–dAû]«­™™ è7ŸµÚóqk|ª´Oµ!MñkŒpƒk‰ÏYé`…(WÆ3ˆ@Âå:ÆÀõ² ëœAO0¢yÃo2¢YÒÇ$É¿ÁˆzÈ-̯i´ú-F4Z}œÚ’k OùœP}å·ÑXò$!Ž Oò‹V›A9O ÕWàÙ=c=?xZ6[œ ù|‰ZNÐÁ—,9€ZÙ*bÀª ç¨/`ÞLã?´&ô)\ŸgDåÍ~þ€÷?dDm+FÿŸ ‚ºþ©ó‹”×ðF”îi~–4kú!ž'=ˈrør5F¦BjóVBmž³Ú÷ѼúÏ‘žúF¤ûþ#šùý)!æV~iµÌ)aÝFý ÒÀ dò«Œp=‡¶Ú¿JBÿš΄ñWŒèAî_J}žζ…³Ö¯sKÒV†à¬™ÆÅç­gûMF4–ý=#´Bßbt¢`DOó;„¸ÿ#ü̯ñmFÄçÿfD-ñ#z~Л¿a=¿ïâç«ÀÿÍZA° ,4CZšËšðï¬`(9ǵ…0`¥µ"iýgB´ 4`Møm«%`u\‡è_q Ï@ѶcüíA0J½`=Û#Ä’kBYÔW¾gµî2¢öü!®¬ eYŸÂšjL²ûSF4ÊgD¼Ì3¢Qîñ¸öߌh\û ö݆Õ†‚ìT¬ˆÿ¯jOüö?±VÀ7¨ÐA÷à¦lE²¼š°‡vCm`®c„ýßô1Â63ëÑšÛ¬a„­kÖ2Bíc60™õŒ°Ï™°ŽÿÅ èxNØÿÍ«D´•®>ÌËázü‚®–ÍFBd…270j@´‘Q¢íŒˆë-Œ°W›W3ÂÙ€y #´š°ªÿ‰Å5¬ûä“Á•”0Û¡¼˜íŒpjºï§Ö=X÷ÁóÅY„¹‹®)…ÙÅè"XžWR`â¡6‚G9ó¥$î4¿1eËõ…Ö&ì.šü´… û‚ð|q6a« žJ¹ù î_8›3{ñîÖ>A6’‰~F”®ê}ó #ìæ!nùýŒpueáXbÒþÿ¿¨Þb61Â^mnfD³ZËLèA?´¸¹–?O?#ÍfF¸R1¯gDåÝÀˆJ¸Ž®[L°iü«uFàW1æÍ„XÒv2¢˜;QË€Õâß-‰Zÿ‡%0¶KÝ– a‚-âGV.`}º­Âíñc‹kÐÿmÉÈÍÚ“I\Ç›w1Ú†è#Ò"#ŒÐ{ļ“ŽñæÝ/¾d3"‰d„~æ(#\󚽌è¹1" »<묧 {7õŸã,$°[zí”ææ‘j+Ÿ°ay™G¡?Ž ;$ )I_Iˆc¾ŠR;‚“eö=6Y\K‰«&®Ø… ;Гߎè>Av¹"Ø•°m©Ãø˜z<ìRlµr…=ùd r€]ð&£ýyØ%€±€úÇ#êñrÜ€6ÚŠ„ vz'hô;ý•VÀú.GÀÞÚç æ#œËšYF$wg¡÷“ù£+½Žî~˜1¢ö}#´üšoa„;MfŠZüÌ·3Âõ£yš®õÌ3Œp†j¾–®¤ÍGázÊüYF$i“Œh´œa„¶eó5„X²3Œp§Éœf„Þ]æëá,Û|3#’ú72BÛ™ùVFh¹3߯ˆæ IF$i³Œp½j>ȈzË#z¶3B˶™fD²üsŒHß<Êèï½I›äîá*Ô|'!ÖÃï`DzñçÚÁY"ÁòXàýaø­{R.ÑÖMÏャЂj¾®¹ÍÇášÛT–Gôk5?HÈ ö~F$É¿Ä÷aL°‚çÍ‹À†£õ¹_!„–ia>.p…D³GóW¹¦h6Áöv³• ØÞ`ü¢^õ#jù_g„óoócŒÐÛÑü0!Úµ4?ʈZð#,+$Ÿ¿IˆŸûo`ÿ×mxQmȽïˆÀÚ%Ó¨÷ F$õ`ÑŸB[À2³ š7Às€YÚÌORMÉg‚-fäàô£ DŸ¢⺃ݬÍÊìfàÿG«°”Áœã4¢ß#„–Ta‚ÝLÎ@xTkhdÒ§Ÿ'ĵkX·U#°jIy@‹³0¿Àˆêv,г4Ã8'h…8û"Isý4÷hÊóú‹Ë{–l_b9¢˜°6…=ZAÁjtÈ*áÛœ•ÎëO²À™°â±J‡5&ÌG(&¬1G­{°Ž³ÚÖ‘0¢ãîƒ +ÀÃÖS‘+@Ü« 5Ó?1ú:¢ÿY4Ìÿˈòüg–1šßü€ßûFÔ7aí;¸Æ6až ú™fzÿÁˆÒý'!~*?bD¥ÿ+#Ü%1ÿæÿè<°º€gŽóZÏBT#¬ lž±ØÿãJ =ô¸|x;å”zJž-„hþïÙÌòˆêÙJˆF|¬&­¶€5CÒJïrÀ®Œ<—"ÉöÀ»SV;Á*á´U:¬ÒVL˜WZ~ ž—âò®e„ëGÌ$aíð D~Aö6*]Ît`—‘fÙ˜•ÌX-³Xe| ÌC`—GKÌCà W&ž›qûÂ<ö‡ÐNáÙIˆ[ûFÄÌ.`_×>xóàµVé0K€•åy#ªßí„ðé O+#ô^óÀœáõVº#ªm#\s{ÚQžm„p>"<0˜ìaè±Ö=8ñt¢>çÑV8÷€/þ#Ös[Ä£–„ì!DÚÕ¶°èáÍã;¬\ÐëÌãìR›õ2Â9¨§ŸµnÕo?#ªß>F¸Ÿâ9@ˆŸC#*½‡ÑWÁxk*’,°>À*W«9@+Q¯V§¨O=ì©Jo;yQ‡QåmV»€…f¸Ôsa€U"Ú§=0À* ×vžQFô4ïfDœÁ;ºh!òŒ3Â)Ï=Œ¨„£Œp¤önðØÿaܤž{/#œ-{^IˆK|5#ªÅ«‘,ƒþyëhLØQÆÕ€4滬ï´‡Œ³sÏqFT^˜y[z"¤3¸ô#´>z@¾×ºw’•zæ/è7è‰â{ ù³Ð)FTÐ{0¿Çù¿´èy’úIB,õ Í`_÷=)Fhð¤ ñˆqšõ$°h|À’ÐiaíuK4È´ÝYB´ª÷œaDraD²º vÅéÞ,!Ö 2¢úŽ‚îßzÀÞ+,´ûx@ó<.Ø¿ÑózF8/ò<ˆzÙCŒptöÌ1B†çaBÜÇeD1AGýªPc'Øa`mBèû²$äMŒÐJê¾+3¡/~Äâåm„¸„·2"™ûͯ[åA{ÂjÝwb)€>«=\‘z@¦aæH¹€L“O4 _`ôJDï"„þƒÂóFhÃð°×è1FT£÷1¢þønFèÑì)†ÕåwÄ}Ü’È2¢ð— ±æý#ªí¯0¢gûKŒ¨çÀ±½ó»»86R}a%ýÛV‰¿Îm`ž"+”ç#ŒHîà Á öÛˆ mÁ#b~”åŸÚé7áû£žß$ĹÀzüSú8#´y`íü”Å'¬«¡ßÞx’·6pž 8{õÀJ¬S¤ ?Eˆeä)F$ÀÇg­{Xí¨ÿ†÷Hó9‹OH£/=ùÏ1B £ç÷¡×‹çóŒ¨íÿ€z {¾@ˆv½<ȈÆ(|#Ðâï9Gˆ¹†•4øTœC+é/X÷`%­í€´íª„íªÔù/'ÒèTµ(TîûO]]]Žó_º­íúü—¥ ó†×ë¡£J[áà9oþ–y ¼¥‰¾Í* N¦ûógl¯IÞq½¯I“&Mš4iÒ¤I“&Mš4iZ¹ÁtÐ"ï8W'Ä•ûj„1gÒEndtàPÏè%ý ô%![Ö‰C³c=‡–Mš4iÒ¤I“&Mš4iÒ´Öè3F5Go?›I¥£·eSSñˆ_y‹¼xì½èdSŒã¼6?†>V =¦¹u§¿B5b#:Ò`…âQQ+1€[‚j6ú|í+²pB¯m”u¶€\A9G‹i‹Éûÿd㓱ЩdìöCÇúË'¬‚öÿAr~ÿ©µ»Uûÿ,¹?ÿÅûöP™çïöý¯Önýý¯%!þþ×+ñû_Ïâ×~øû_¢¤š)ü^W5µÚéšÏE~ÿ˨’8MB}…þ@ù«oœSј(ï4Õ€©\þ«àK_†3½&M+‘Üôÿbúþ•õÿíîpêÿ¶Ž.­ÿ—‚œþ¿uù[f³öÿÕ¤I“&Mš4iÒ¤I“&Mš. ‹'øÿÖйÁèö+´Ûïⶤ©5iÒ¤I“&Mš4iÒ¤IÓ²ÐïWåÿëOÆüà$r©¸Bÿ/|€§Nø%ò KØÅøÿnWŽ4äþÛt8 %bá©P&I%£Q³ýÅ&öÿmò`¹õF£0þ üíyäœäDîXnhqL3yÿŸ©t*²è®¿H úÿº:­ìÿÓèêjïòfkw›öÿYjøn¡ÿeÃwgÍúh,?KφiúE<š‘‚èoñK EÂét<–æÀOÔ Ñ<00äóÉ>Ðìì R‡HMgC޶Çõn* O¦¦“Ù¢(ÞìäT(ê–ï¤øŽ?;žNdý­{°ü±à¸ßJ¹× Ð™‰x"–™¼Ñêï†[yÖó‰!ó½*G öû“)¼Aa²èa+.í>äOÆfB©t4–¦°{%Ç2å ñ£³g¨B™K‹±D|2žULËBö[Eø_îoõSèøÁàUN¿dm<è(Ú¯îZ¥§òåॊàWŒ8Ø+ºï`T>…'…Zb먧¯‘Id0SÈ ƒ»Â¼9ï–æìðHl›ÂáHð^§L/9o¡D<+à/R]0é#Óét,™ “¦TX“SÎçëà#±0›‰òOwìð¡ù®z ¤9=NfãÙÙEÏÜŠXüà ªúâsÏ­‘j>5©º$µq$ßÄY¥½Î€[ý–|I~yûx8NFbU]ßê^aªY„ørvâ;²`­"Å•¢Ays`ÿ‡¾rª‘[• ‘Ñ÷ð¯dj`0¸Ç'/ë²RŒöݸ¿îwŸ¨ƒ¹’&ú efbÑxf"‰‡he¯•½VöZÙke¿Z”½'/œóg¥M¯¥@`–ÿ-d—ŸæçÉÞ,N²+íjÒD. M*N$B‰T$œÀ¤åãË¡¡¦ÒrdЏd-PešÌôÔTb[¯Ú¤ª_U›Øl»p6«MªØ¬6°Ù~álV›T±Ym:`³ãÂÙ¬6©b³ÚtÀfç…³YmRÅfµé€Í® g³Ú¤ŠÍjÓ›ÝÎfµI›Õ¦6w]8›Õ&UlV›ØÜ}álV›T±Ym:Tï­¡ß«Mk)øj"§3]ðPt!cQà"£ªÓZœ^Èp¸ˆñ¨ê´§2".bHª:­Åé… J‹•ªNkqÚYv('ãþtDNº³-·ÛÌÊ´@sõH:•Ëð#=£}{Fw´uvîÜc‹sÉx(žŒ•‰ gÃ%£PQ‰pÆY#›Â¶QÆG ÕÎÛPH4”ŒÍZ“b6U¸ãFÆ‘«#Û™P6|Ö?ì,.°Ô¹¬‰g"¸†tÞ&V¦Òq¹ªr»—_}ºÝͦ²aG{Ñö*Fc‘D8óÇÎÊG<NF±´ÿD*íÏœNÈÅu6æ¿O ¹ÙŸ‰¡¬(#,¶Ò‘½­àe« À…2¶ŠÏ¶V¸ž‘O¤¦3°¦5âL~å6£–yœ6c‹ßöøìùò]ÇVÉfÎʦÌRß¡¢¢!GaØO`µé\>îå¥sA]÷: Û¼ÄVrt»Ìí-@riZ=Göf±ÉP‹Ÿ:üRŸõ˜žTÄ[gk)è㪽lµv/ÅZÑÒÜvÇ (¦†Æ‚£ãÄTÞ>·ƒMr-Ê´Ö¢lp`M9Ò3x88æßáhî«Ä‹«E…µK&Æx*wʼ…­tðKfÁºÔâóºªI›= bÓ®¬%w•œ¶Xíb+²È°Õâ:<8ØR°\oq.öwZRYÔõóF[ËtÊk~Ë|ŠÖS"Tq¶ÔðصÇqÛ¡‚÷:Ç+—ø–êÜ[0@íÉ—ŒÂ̯ÅOã ü Á‘,³-?ô´ØÆŽŽ’ÏÆ&“$ÇóR·’T)›7/S ym•±מàgUeÎ^ùty9µí(|üy‘ˆ£ ¸‰ž×™oKAøü^¯·D;@†p×U­z”œx]v‹?Ðâ Aü¼%¤¯  %Êfç¼.Ñ€MD’ж*%Ô-¾»„¶i ½h ]H@/B<ý®âÙV­xÝz±ÛV>m¯RZÝâ»KkûÊ–ÖåS»È¬Im_^Im¯@R;ª”T·øî’Ú¡%u•(ÔŽåÓŽ Ä´³J1u‹ï.¦ZLWBí\^Ií,?OíªRPÝâ» j×*Tõì–M^W”^íZ^ií*/­ÝUJ«[|wií^Òº\juE i÷ò iwy!ÝU¥ºÅwÒ]«@HÕ³»YUI—j"PÑ]x­(‹*ûÜdØÙp/º(ï*/Ê»«e·øî¢¼[‹òâ‰ò‚É–R°w/±`—ìÝå%;ÐZí‚[‚{­ ·•JwµsŠâ ¬4¡´.ÕŒ¢Ô–BkâZõŽW[^+|Ïky¥uEM~Uou-¶¬*Õj÷¾\”Õ¾ûEs! 5ÿE,Ô g²+EV—lß«”¬¶U «Õî|¹&(!««aïë‚dõR³)–lã«”¨¶W ªÕn}¹&(!ª—êæ×¥¸©X²ý¯RÒZÉX Ú-0×%Äu5l‚-“f]YŠuÉ6À.ò yíj®]͵«¹v5×®æ.¤]Í«™ÆhWsíj®]͵„jWsíj¾b\x Df%Hªv5×’º ªv5×bº:ªv5_Ù‚ªžv5×®æ+_Zµ«¹v5_ñBªžÝŠ÷ÏÕ®æÚÕüå“iWsíj¾ÈÒ­]͵«ùZ‘Ö5ùÕ®æ+|÷K»škWsíj¾Úl ÚÕüRÝüº7´«¹v5/-¯+K±.©«¹Û¾¦¾½I¿o9*›Ðl°µ'|¢ç›†ýCœîî•~øÀP´‚8,îD³ûj/U‰ÇÐáCÁѾ…£¢ûxðh™ÑÚP.Z*a¹ —‰ÆÏ§¾|ÖÉéÉã±tÙéýt&=Hk¡ü—½ÖKì\î% ÿg‡¿#Bñ»>¯ìÝJöúyñãõ²ÖÉØ:j à%(¯×rtÎ8z#E¶®)6ªL69%霌RªyACÛø2g”ea–Ê#88,`¸­†ÛVÃí0ܾ’᎕Äpg w®$†»*`¸k%1Ü]ÃÝ+‰á]0¼k%1¼»†w¯$†•‰w!ŽÁ½|«i xŽAõåÎùË­¶úðËEªp˜Ùeì³v¸Í‘ÏÅ´îÅ•,k°;°Må|©?ÓéßÁó¨X²DÕÅŒº  N‹Z'•œ9?ïCÙYß7m±/ˆÊM•0/žÁc6 pñä‰ÔNŸW½!”Ÿ¶(ÉmQÕn)˜œµØZÊÆ~ÑlO½*TØø «…•>/Þ;/öÛÊz¨'z¨'z¨'+†a= Ô“@= ¬r(D·_}k~Ï͆³Ós=µv˜u2OëƒèùÆp6-Æ*k¤he-À Ïóêö«ÔijðPñ4ÇØã¸3F1d"œÞѶÓy÷x8NæmÁ…·ó‡f†æp»ËÇ ä'¹»v:£¤¬ï½;î¡}ß#nÝrÞ±¶oÜ’,JÔÕ.ö˜/þ:{Q„xÉ;ŠC÷»Ä`[ ¶UÊ`{IÝïX¯Õ.À`{ ¶WÊ`GIÝïXoS.ôŒ;*à°£R;K‹aç‚,–HH,vVÀbg¥,v•f±kAK$$»*`±«R»K³Ø½ ‹%‹Ý°Ø])‹»J³¸kAK$$wUÀâ®JYÜ]šÅÝ ²X"!±¸»wWÊ"}>½„Ún]Xo—HÊŠ»µÍÝZ1Ÿ /eÆ—…˜ŠF˜Š‡útz >eJ%e>+h4ôáô|.<Ø”JÊ|V2Þ*p%FŽxþ^I>t•Œ:ЇÀãN`á§TRæ³’¡'à{|ÞÂy£šú9‚]βSóXuè}å]ÂáéDÖŸ•!%§BeRt&¯eÕJÀm½’Ÿô—]¡¸¬R¬:/œ—¿ùØÂ‘iÍÇ 2ZØÑ’ ƒ°äJ­<¶¦æînM›’-•œŽUqì"¯²Só!gNkC„–´¶Ã×d4e7°NWSëáHqÓ¨åp¤¸úù[(a{ó«"ykx´?8êï=æWË ž±>">Ïÿj%u²ØÚ«êQ°Ô¶*‚ÙÀ‘r´x²2Ç &Ÿ½žݾÞr;oÎJêh‘R "›o&)8qNÕÌV uü[á1nêÐ7ëD7[M8…c§Bò)mk8® 9§ª’r{/ʨ›dóGM|ùçŠbÝ´?UK°SS±¤?b 8ËF&Bǩȩ—Z´döÄñ£"JèÕ7EÜR¤_K*šBEÛâ¢Wó Ñ?,;Kä–ˆ…ÏÄìÕ°%‰%£2Ùžò5is«I[QMÚ*«I›KMÚ–¨&ín5i/ªI{e5iw©Iûդí&E5騬&.5éX¢štºÕ¤³¨&•Õ¤Ó¥&KT“.·štÕ¤«²št¹Ô¤k‰jÒíV“tWV“n—št/QMv¹ÕdWQMvUV“].5ÙµD5ÙíV“ÝE5Ù]YMv»Ôd÷ÕöÜÖúÅcck…ƒc«ÛèØºTÕqé]†úJÇz×Á~©Fû€ëp(ïø·?°TC~ÀuÌú Gý€Û°Xªq?à:ðŠGþ@…CÀmì,ÕàpýÅàÂñ?à6È¿­ƒœð¬nD©L 'ÿçÍ¥7Õô¦šÞTÓ›j)½©¦7Õô¦šË´\oªéM5½©¦7ÕJSJoªéM5½©Æ«0½©fÓ«zS͵&zSMoª¬{õ¦škMô¦šÞT+X“ëMµR•Ñ›j‹Y½©¶puô¦Ú"VgenªÁûp×}TuF¿/øÍuSáÙI¹t·âöÃά×Qˆ‚™B˜ýͽJ~ûûoÊèÚ‰É'Ô1a2ƒo5:d ö˜)üHw Õfâ™l:ˆl¶ÃÒ‘ÚŒ·>. VňOY·wƒ…¨à~´\e¢•T&ZIe¢…•qÏeÁÊDËTF Fð@ptó™l¼(ïÀ–,Þi6+ª@¤’¶ŠTÒV‘rm)×V‘¢¶rÜžšH%c ¶G&;ήfPŤã“ö¥b„ñIÿþ£ÁþmpÌrqDÇ'ÜwKn«Ôö#P:[]šk6 ±ŠÉ‹ˆÏ&@ð/ ʦ½ º-afáeÒ—Imi§‚(>g¤‚Æà(JõY”§“4óªÊvÝ×´Ó²~ )NV.–%JåS¨ö¸­Å¦ÌjÙ¦ÄZò ËŠSô}{¢‚¯Ü[o¸çkɯØ'„—íg@d:ú½Õ®öËàhÅ(×>j«yÔVë(·bTU0êÞŠQ[+F­u´b´T+Fí­-nEx?=8똷ó9ì×`ì‹"PÔÆEÙBG¹‰£e›¸êâm¸Y¹ý²Û¼÷ ,àEw ¿Î»%ãΈ%íÂ¥"ÎÑ6£«XhM/nqWÛº•È~ˆrAó-`iÏËkÄ&«79õû#JJq|‚‡0- 7˜Ç —¤ùÁ¢©ÃfíÇ`þd»#­MÿwÀŠ·¬º÷¿ˆ££rØGë–üÈÜb…Ýs£æ°£-Eƒj‹côtÍÉjœüXÙR<*j‹"Á¯@àË ºû>ˆ½?L+öúoîí»yÁ~]²÷¨ã³ Ü‘<¿`X(ƒhÙ,\{¾-‡™29¸*+}¹ò.Ý1tå“ÛäA¶u$•Œ„³;T›µÜ쿹%_œ±Ã‚{pg§KY<îO¤`¹ yƒøM¦e¢ñûÕ*ˆÔ’õ©Dz9ÈgŸ´«[¾%kvΘÕdµp>ŠÜÒDÕ>‹µ—†£òŽ[vª¢,ö}E¯ñ´Ðyé-nåºN’ݦȎ›Ô) ¤ãƒ n²wÔw¹9£n¥´ìþ²‚§ëÌŸLopüž`pÈ¿ÃùÈnó·µî,) …K’À΋>Ò@Ë“–§"yšV- §ï˜œÍœNÜ1•NEn?tl`ñËh•ÔÕÚ ¿îNüm tt௼‚ÿD ÐÚÙÑèêêìòfkW»ð·.>+Å$'‹á´ß/³ÓéÈD,Y:^,Y †––Ο_g¹A<)¢âkÂ#„!šM¸³;çˆZWøû‚Ÿ~9øûý…¿nÔ¶Yþw#ç ®·büä¿ÅU\^ˆ g> Síú—¿žxØ*ÿ¶É?³®NfeŠšza¼Ó™ÊcˆM2üMÂk¼Å£ qN•n43'òE¸4›óÜÙ9¥Hê§0ЪŒËOðÑÏzÛ!þ‘¢ÔØ~<ôctŸA?&ýÔPòJÛK“&Mš4] ¤Æ^»9‡ÿüEgç„K4×@— â£¯n0 ¸1 ÿSÙz<Ü3¼ÝÅwŸˆ~òõà çdºÙþSÑ=c‰‘äÁþ¡ƒÓÇzô ÞuÿŒ8“®Ÿ’qÞ|å0h~y}¹=yÿ2 äsPþâý—äïCù8ÄÊòp^2}ÿÑ’åef“§"ç†öÉ|G¦Ó±Þ‰àþ±±ƒgǧ&G{¸·øªŸËóõY¾vÌ_Ï‚|Éò¯¾H¼dyb§Gg'ïÿ¶Ìóy™_ï©ÁÄD¸oú@0rüpßÔxv*z<6 |=nãkd®˜¯sÌ×óåø’å!_÷Nõ•,o8vläìÑ#gn˜’ùžÈ¤Od²'c±tâàøpßl:ß{×Ôðµë¡<_ßwáëèCÄä³ _²<ä+x÷]%Ë›=¾kàì±Æ‡‡êe¾'œ¼;}wü®3‘hÿÉéôÝÃ'ÒCG゙³ñ5÷P1_?d¾ Ÿù’å!_w-Y^41väì‘éJ¾—ù=rb8y×áøÔþÙ#Óé;LOõO Œ_çùºüáb¾Þü0ñõx9¾dyÈ×ýãá’åÅÆ î{d¸a—Ì7™M $ãýã÷œî?=›=söx:6~jøäùzÒ…/ÿ#Ää³ _²<äëd¤·dyÙžéÞèÀ‰çežÏÉü‚£ÙCƒÇÂ3§±àባ£g{'fŸ¾³ñuð‘b¾>Ë|=WŽ/Yòud,R²¼‰é‰álïԣà 2ßÙÔþdÿ™ll_ìxæî÷ eûN¾ZÍóõm¾F%¾ Ÿù’å!_#w –,/}êhüpöîú7È<·Tòø©;{g‡SÇgÞ>td;OÆÒò×GÒ±p6MÂ;™ŠJVäõfá…¢%މ-2JjÞb—M² >AŽÈòC™X6IÄ!|› O%à¥ÐT2I%“±\ÊÆÚ=²n‰½Â4ªk40šÎžØ%j<ƒç„ÉZçÇ„¨­½óœxšŸ×ùf¹¨½ê*f©Faü— X·±çœxÄÈǨ÷z½¢ÏõF£0!†·±½]ôS€|M2Fj  aã¶mb?ÔBÀú†úzqÀMý[…øé+„ØP/î6Å52àdÀÆZðjÐÏ›êü£ˆ›yÖë7n#ñrq™äRfÚä•ã (`³wÿûkzÄåf“¨û± ØRàœx•'ŸÇÖm/½O\]#Œ9د±lßÐ{Ÿø[[@O2ö²ZqÅ£ÌX.z<r—ÁɈbNÉaÎ!„9§æ Ä/——½ ^bŽE.Çò–S–S’–c1˹ÉXÎMÀrvéÊY¢’¹ý‡‡úƆ‡r#£Ã}ÁþãA8v÷ ü¿oxh¼g`h,phFƒ=ýêïïÉîØ?´…ˆÜ±à˜Œ-/†Ž ßÍõ÷ É_©C=c¡ýƒÃ=㹑™RBYPŸÄ=Cc¡»Ë  Cc#=}A™ÛxèðX°?7<4x,´ÿðà`èÀèðá‘Pï1àë°Lw`(Ø;Ü;>ÚCÕ‘áý£¡¡PŸ,u<˜?0„J ËHƒÁÜ¡1ý½m¹C=Gû{!É]Ác¡áÈêïé Úd]û­€CÇdímítÑÑŠ5€h=‡Ç‡CxìBhx(toptB{{úîì; ŽõõÈºçÆÆGúÆC’iÙÊX˜Ö#+É!2)duã9,Œ@6rÏà@?‚±\pttx4´_þõ“\Ê6"d!ýÀwÏ Å"5 ´íhîàÀƒ!hé‘Ñ „à6|(8t@>ð M¤2YY¾Î†O‰uÂ'oœ‘÷$¨À':œŒ’g¿WxÃé“Óè‹_Ó°q#8ƒ[.äµàÜ]+ŸxÿÜá} ð¯Ú'ùõ€;<lµÔoè=‡§±BÀ&p‡÷Ê<¾aË#—g:gqœ³ØÍY¼æìŒæ—kÌ~t QÞÿ û퇎½_s*çÿ×Õç¿¶µv´vtµ¶uÑ÷´ÿß’G 7ÿǸ±&JeoißÕÚÚh»Û;ƒý@_o_ûþ¶öÞ¶ž¶``w_W{_°µ7Øg.@9Gù÷yú1¶fEÙ<[ ¿$ž7JÜ™#~ö¶ÖÖÛºúoëé„“NܡҨ<ÊUZ¶£íßÖ»¥µ5ØÖÑÝÓ×¹wÏþ¶®ž`k`wGoG vwíîm»{Úv—cãŧ¢þ¿äßÿ’Ýýý_Ÿÿ¼$ÄßÿšÄï}…Þ»Ñ3­ï©Cg<üË'D[éWWn|€/¾Vº´CÏÊÿ6«ôS#ýôB¾ûeåUGéO\'<Æ«}óëf‘ÿæ—GæôCg*©†6Éð’Uþgë›_OYyŽ1' ¶OñõSù ù³³€ÙÕÿc}‚Ìþã)øèXá¦G×ü Î ÁàÒ8h… o" '`Q`‹ÛÓ™îQŠ/4iÒ´bÈ1ÿ[Žït´w´}ÿ£M¯ÿ–„œßÿ8š_v˜·XïÿŒ©0ýýMš4iÒ¤I“&Mš4iÒ¤i’aÒ÷?¾‹Û<ÆœA»æÜ§ißBöc‘¨R¢5A‹ºï­? I“&Mš4iÒ¤I“&MÐwê«yÿçªÃàá'£þ“‰ÔñpÂ?•ŽŸ‰'b'Wë—@<âfáõœ“‹Î£FiŠzqµ Í¿ÿ󲪿ÿQ{^ö©µÐVrqê g23©4¼ó³~,–ˆE²!h5YÔú¤ŒÃÐ+ÖžŠ†³1‚>±¾_FV°A¬ïÃ*\/|ýéÔ býh,‘ G nÇ&¦³ÑÔL’6‰ øÁ–L†p£ðí—ÏŒ@“h8'™‰Í¢q4v"–Ž%et Ú"’ÑØYB[ECO>Ù€h›Ø06‘š EÞ.Ʀ§ÔÝ7TÝvÛ¹ŽÙÉ©P6|\ñX+šS‘SÄlÕ‰ Á³±È´j‘uÀùT"”I„ÏÄT7a}YBµr—q&›QM½ k‘i[9V:5'­VßB•/Ý`e‰oNñ3hž± •`<?yRÝmÞL&AïzÉö‡ëH|jBŠËf±þlgëîP<“™–p‹Ø€03}ü~)7²õ7N†Ï†NOÇ2ð)ŒŒ|ë!`'#Û¿`þËq°êo±lá*ö|jjï|JŸeimŸ¶ÔywîßSw±n½Ç#6øIüNK=l²x! Ñàƒ€&[@l¶¬÷É€-¶€ c«-`ãF°Í°iƒ Øn h„<.³45È€Ëm›eÀ¶€-ãJ[ÀV¸Ê° J¹Ú°b\c ¨Ù.®µÔ6É€—Øê ¿-`ðÑloBHr½ !àz{n’7Ø›p« ¸ÑÞ„[dÀMö&„[… zÛc¹iþ%âž»z—›‹‹#±Ü ¬uš÷Û–Ù Ãp¶z´P³XfÖ<Í7ã°±dvuIŽôùDËMó×åWg«ÊNm#±Ü ¬uš¿^ðëB«oFͤ'ÖËMó7ˆU+=LÍb™Xó4#úXÇ¢þQ:šuõ‰R³XfÖ<ÍßD{gý±ñd|îœi!Z~ZæÃk5]4•>ÿy`ÑÊXøüg¸ÕZtþs{·>ÿy)èüùu†0w‰'ET<5á{’v«£Óor$¹)ÇDp=yyùÒvÖ ø^'ÑÍôSð^æ+ÄÁOþ[œ/=ìFÿÙò,Gf°ðOl•µp§®ÖT9=WT!Œ`Xþ«í£ÏçòÝMòî—Å:ñGF3sNÕ!Ï#åw!4æ*d\“¦E!£MÉ# ¤Árjr'òPˆúm­”k :)ý@ë„ë…½¢}¬Äü]/6âï± 7òw§6‰&üm›ñ·IlÁßÍØ…DÛðw+’i›¸ ·‹Ëñ÷2qþ^Nß‘è*ü½?ä$$º¯×âï5â%ø{­ðãïKõQ¿¸›Åõø{¸¯7âï ¬oš4]2䛋öÃ[õsƆ] ½\l(x­egu{aï5Í™u´ƒÐ?W³¹øá- ¸~Î{C%‡`äM—ßá¤öœóy­­N xÉœgsñ xkûœ×—ߎÀ æ9¯×òëæê·¹ºÙãÝËÄ6׃?ðæF±¹ØŸï\=glu;þ o6ÌÎcðÆzá9Ô;Š—µsÆv÷SkðöÑTt ;‰›XÇGk#¬™369ÄpïœÙèüžÞs+ÇñÜ8WÓ`3‡aØ sæÆBs=_'šŠÞèÄ[æŒÛ1©¶NÊ.½s…p›XÇ®¢¯ž{îêÅËkçLc¯L±ª¨ÔúïDzrÑÊXxý×ÖÚÝÝáXÿuZÛõúo)è¼áõÊ _£œÊæ~Ú æå×ì†)ÎþšUØÓòöŸ?#òß ½ãÁ)Mš4iÒ¤I“&Mš4iÒ¤IÓJ%Øw„ “¶Oç$ܼϔð˜s° ´ïœÈŒê=–K†'cú£ÚšV åVÿû«¿«`óéÐìÀXÏ¡ågMš4iÒ¤I“&Mš^Dú©‘ßË/O›ÀIÄÏN"Ê'gU“!jD\Üi 4ï°BGÄvv‹‹ÚsëΊ×5¢©À‘&ŠZQ V¹ÄØ2NÇ’Ù‚»ëDÍt:!jšjkZ_d©f³µµwžC\8/ê¶ÈÏÊsc]Í]sÆ—m1r΢ÉZS\hN–HFœ¼ÿO6> =JÆBèöCÇú«Ë¼ÿÑZüþGWkw«öÿY Zàù/Ú @ež›ëó×ïÿ, ñû?¯Ä÷ž¥gðû?¢¤•·ð=JßµÚéšÏïýìFU¾ó#¾äøƒ÷ ð‡ºZCåäöÎû[=êí þ=W%3š4-'•Ôÿ‹è\Îÿ·«½Ë©ÿÛäm­ÿ—€ ýãÆ—ò·ä³Èÿ7nhÿ_Mš4iÒ¤I“&Mš4iÒ¤iÕ‘aÀ!ÊÝý Ü}—›¿K†r/–ëâRUC»IjÒ¤I“&Mš4iÒ¤IÓê¤_®ÎÿW'?8‰\þ†0ÅAñ'\Á¶Z¡#|ج÷ÿE8¸úó»Ûå~þK@xþ¯0Îâù¿_7VÝù¿V¼*xirümU‰mg_îLdÂá›áŸ÷´SaŸ ©ì5YÄW}•\jÒô"Sý¿(¾àåÎÿíîtžÿÛÝÙ¦õÿ’óüߦü-ó}þ¯&Mš4iÒ¤I“&Mš4iÒtIaÂù¿B¬ÇÃiðüß+÷Õs®Nˆ¾}õú àÅ"—ÔgéjÒ¤I“&Mš4iÒ¤I“¦¥¢Tuþï¶üù¿y'‘Uíaˆ‹ÜÀڬмÿw\Ôxªóÿ.<÷·V4Ž[-EÎÞub‹=hvІó€MÛyÀµ[· ´ÂÈ€zpÓÞ"cl´Ÿ\pX°£˜\qn6œ¼ÿO2zøþ®ƒuuX}Wß_ƒ|7¿›§¯A>½òíå–c´Ð&M+Ðÿ‹vt¹óŸ6§þïlëÔú)è¼á+ðÿmÍÀl¶Î¶T–öÿÕ¤I“&Mš4iÒ¤I“&MšV!ùÿÖ£Õ3ç5D¯vûÕ´H»GkÒ¤I“&Mš4iÒ¤IÓ"Òf5þ¿—bxPÌ€ûƒ±Ë Íûÿ>(ê×UçÿëI‘Û­¨µûã pø­‹M¥"²¨z:}8#êEýôT4œe„WÔGc‰\ú„/™ˆM†SSQãݺ¬2½û$õp[í9pÉ 3–e@]Œޱ®^4Ùê!à [€šm>Ÿ Øi È)þsÀ|9çC“ÿ_;vLÃ0 ôø«{ªaØa#ÈI›Óà\­QðÛàÿˆ–percona-galera-3-3.8-3390/scripts/mysql/mysql_var_5.5.tgz000066400000000000000000001630621244131713600230000ustar00rootroot00000000000000‹)ENì]yŒçu3¼¹‡v­ÕaÉIV±[¸©cí))©c‹KrWŒwIŠäÚÞ¶ Å%G»ñÊp¸ÖºiJµÝªE#4E‘¦\Ô6ÐETÀv‹Àhiù¨a´…ä5Ðp¡¦q¢p1vú3ÙYî.×ÞC²ÞXÍÌû~ó¾÷¾sæÓã|K9å(l3†ŽÓãðññ!ëÑ >~l††‡ŽÁàøvFQ¯©9epjRµZY‡·QúuŠ%Rÿ¥åÚW‹ÛØ :­RëCCc#¤þG†Æ†±þw­ú¯*•ó²TËVyéΙ¹ØÖåA+øØØÐõO*{Uý‡Á¡­3amÜàõ¿²â@þ.AÞ€i‘¦œÐtŠè¸EÔtðË]ìùÊÆ¹Ýú2ù§[¿øÁ¯_öæ€qW|ðžeýÔå¸v¦;mZ2?tñyûsÝìõˆº&áŠó.·{ˆüŸ!(|OHë¶>gx©K Múy›„rþÝɾÅNèuüøà]SçU"ÃâÁsü0ÔîJ§\Õ­ì° ñ±ÇŠ•|®¸X©©n¥RQÍ_UVçëÅ¢U*쎑@ ¶79®q†G n´Ök’²$)µ;Ï*¥-ÎcýõߑᑡcŽõß±‘Ñq\ÿÝ ¬€  O`+†²àñšIâºìé¡§G ™Lx§_ø´!8z`p' F @ ±iä…>"4Ù¯Ð`NMÐ’©ØL(5§mp;¢ShƒâºíÄ»mâú€f–céÐ ŸœÿùŠ@ ±ýx\„¾ÎÙ‡g–Ó§§'+Š$/”ÓÌÖ$…¥ø!ÌÕjV”1Á“¬(*Á—®äÏI*tÿ~%W­J tƒ7ñ`™œ¸»ÃMón+GˆÅž/6á²EàuM7á¡%ð&›0!¶~*]-AÀãvÃe¦}§šðš…ÑåŸjÂãî– Ûk¤§%Ð,kÔ]-2¯Žj†—uQãþiºsó ™v¶ßÿæõ_ÿnq؆ñ_ã£Îø¯ã£cÿµ°Ç]S.3Iü²ÿ•6d—Eÿe„aü@ @ ×>D/ý_h$‘¾è³ø/úM*±ñ=i‚«±$°oR¹ÏÒ…Å&xgE„ö-**ò6Drrµ46¥äÊj×õ; ¬Cl;„Ý6`‡ ÷){”Rÿ.õl@ ÄÖã/7ÿ5T*y©PW¤A("¥©¶}ÆíðÃxÃrEAŒBÂeÿ ø7ÿž<,àË E´ö¤*uU.KY=øË¼V—«À¯¯™@‚´Y tA0#—¤šš+UÁíùâs ê_h[Ixh¸× ×34l½Føz&šð¬% Ìßsø0°õ›>~JÿÔU`ë7ú-Á`ô4Ä]àûA|ŸÆ÷î%EwâÐO^¸­!^šÕ/Íꔹ dº£™¾h MÎÆÃ™X"®%S‰p42›Šaô¼”¯«’*ª’2¨kãŠp1i[ЊÿZ”ŠÕ¬"sª\)oiØñ_CÇŽ9¿ÿ5>64‚ñ_;ç÷¿­$ñ3kÿë°!Àø/@ @ ®}"ýþÝÓþJTlxtó@0z‚Û"X Ð]ѵ;ö @ â†Â Âfâ¿öŸ“–é·œ>«Vªr~ЈÙ>ó¶ˆr°Ä1´â¿2à7ÿÕËiXeåx  ô’£"wo~rþÍ-Ox-ͦCs(ØÊµ˜VüÏÙz9çÌ\d •ëX?þ‡Áÿ3:::Œñ?;Ë÷¿Šõyk¿tlÿ5<âüþ=`ýïV„ -þ+,šIâ2&bü@ @ ×?¶ÿãíæþìw ¸ÿ#q #@ ćÇoo*þ«‡ïÿÈCE®ïé ñ_wÃI ,Mi+þëîMÇyô]…"ýd_X¡Øs„}²«!\¶4öݬBq·ZZñ?ª\’²UôOyÝ93Ûª<6ˆÿYÿ5>züÆÿìVV|¤ ¿— ¯Ð¶*ÀÞb×l’š~åÞDn·¾ÜN]@|ðžóú©à¸na“v¼êø£ÁŸl×C¯G04½¹*öùkàƒx8” š­Ücs“Æ » ûþ¯[9ê·°þø?:Ö.þw|Çÿÿ]bÿ¿OÇA2þ³ÐÏ9ÇÿgìÇwOð£~9i;¶ÅaúyÁýBh?þûMöFó@<,ÔOŸÕÿ0Gb?t÷Eþ~ƒÛ@çƒ}@·ÆñU"xü |Ãy—‹ÌDþ„ßøö¸–ù@Ÿ!&y‰žŠF-a¶zÅIÆÁ.4isp³ï6Ð Ç-º ÷Êrpñƒ~ƒgx)ùÁÍoï´¼ññÁA8™÷ΪÅéÊ›\Þ=Q>+¯’5Ày$×±²¬M‚·4œwÎw‚iS:R³uÙm­{òvZ×ÖZßií”õîÚŠí¸ql)mkª 3ÖG«™NjXØén”ä5[Åë&ndp§&o¨§35›ª¾­µ¶pé€"±ãw‰üSR-VK+ùi¹,e–«RR©,%”‚¤Ð Fû»S 8Èij%.\)UsååXá¾\QæåõÒ÷ðIΨW«E%¦–’Šœ—Â¥ª÷Ñt3ã1Yô|5RÉÇ ä3³7þ£‡[”Xy©B¥+u%/Qé_ú Ãm$…è"ÿ˜º~HŠË—l½Ò(ãÝ›Ìõ½Y14M„âìíð;w5`_KžPB…BâÁ²¤°ä¿_l@+9™ËŸË-ðLG2 °h¤{…0ùqâû~»Ü¦òr±·ØÓ'rås¡|¾¬¶X¯~³vVbþ+R^e©¯¿N Ï’ª#957Y¡9)R­Æ ùüí<£x½XLIgåˆT”TI§„ ¦êG꺬©(cýç]벦CŒõcÒÎn&¬d]YÂ=Uª1·jŒòΓ\‘NÑ=¯Ô˪•õ¿–Øb…+e5—·2D8hËŠµTb˜¤Hå¼Ä)RЇZZ„5zÉës[Í!­LVÙg8çÀiô‡4\Y~ˆ%;ò»ù)‹I³µ6Þ‹·]²x?[kï½8¤· %)ŽŒî¾Íbôl­­Ñ1hÀM„“ª¥m$£aÄhÀ’6[–Ë55W,†H_–óìnvó̼ÕSÍŽ{§ICèÖ“H÷’ù ódì;DúiH‘XƒœÈ)áJ 1䪮[½ø N¸¦ÆÔ¤’g$NùÝWøðb¡”È¥Ðñ ©¨ËDÈx/u;xjI™(,¨NÞ›ª£Ív9^QÙ“Ì)¹ãýÛ[|˜1y5Zžy§ºŸüÀ®.Qo¯neÀÉS#t`sèsõ’zÜgáéiz¹~î ]Mê<1J/«š£\Mô¼\SkáÅi|e5–¸ÄZžlXìh遼™IbÃ?“ù iFD>%‘Ê’J“¹’\\ÖGÙ‡Þ7g½*éD°zÎøõ79C¯N‰™2ì¼GsÏ¥ªß|§Ÿb{M®Òu!Iú'¶ªrëÈy€³ˆomòûÃ÷y³æ:ÝyGR–ˆ£æÜó'' ›ìÍaUnO‘ƸŸÍzžT*%zÁÒÿú„a3«è|{-ÏßbÎÀdþ]»4ÿæczµLùnžiûð\À1à ñ7~jgR‘f«…œ*‘®Y%½ÓRo´Kyÿâ=vW75$Y©©aE"dÒ–êRÁhN”èIq"yøâfwÄæè‹]»:võͼÐëwO¬ñðÿ!žî;zò^ïákg+ìÝØ»±wo¾wÃúè£ëÿ×÷#¾õÝ) —J5ëë•+ö]•ÞªVYôko:yF5çu×wᄃG[ iRUÉîÂw# ØCxü†Z,ámbPŸ™Ì-—¤2[½p½ó:ï| AWœX6”SŽÛý5îñ*¾¥÷•5Ô¨Ì<ÆÙßäÖqNË:÷áßá OO¨1µ¬©™0Ú­}ëÒôBuÿ¢>4¯Aã. ý7/N²ˆû—Þ²:Ë+×QÓß°⤘e2÷\{M–"™ÿG›¦j±½ç‹ƒëÒ Ï«o[=_EãÆ/ òqG'Ñ–äpïái>f¶e˜Þ}óŶz,Î=s‡©G^"Ý6-©¡]_!'i5§ûvéÒöN´·ð‰–Œ†uZÇ,1A\1WXܯ%ùBX|’Ô}•y¯rÿŸ§ëktº®“TÛ¦õÁ©kuZ?ÔšÖeIiuÓ\¿xö?vÍNýÔô™œš_¤•v¿¬.Ú§QÏÑæúô ŽdþÇ.]»üǧËÒ¾ÞVn³’ç AGër¼aµHí×=çžjÀ€˜’ò’\eqžóä)}puê’dxjêùúÛ-=üaƪç"é {§Ø*åêL¾]äeHùíý~fÑI3ܶÒÔßLÚŽÿë o&u›ª÷ž4säk«m óö9ií ó~iÑ4lƒ•ZÓ0Î[e˜÷GOò& —bÛNìQù‹WÒzQðMêc…5=]JÔbcÅŸZͲ9ÆXÒßòqÉʲԭïk'yÙèéÆÿ~9þ£Ñwñ=­^S+%I™¨¸GuNûV‘¡fŽO§UþìíûÓ3¼9ÏŽÿ©Á‡o½ÆÈ@â üp‘O^-—XÚÊ‹ü½‡§YÞ{üݼfœ5WÖÇ>F‰XÝ0³Unø µ}àóÿítþÇv‚í„·“VÌ–cŒ¶ã¿xŸƒ V<‹89/ßfæhH --ðÉ6Ïxtd<ÔŽÇT±‚ ¸škè"ŽXtnýY§«xUæ,£}îÓÉXÙú`Fj·Åš¹bÖ¨e±k~Ì´+a~íªžh•—­géÏ7ŒótŸ™cÉî;/šîÙ)öRøÞ›î9i–B¸ú€a“ÃtK†?»cõ¨ÑIÎV8 á(tŒBŽßnÃîîÿ1:6<æüýçø0îÿ±#X¶ý?.¶~¹.Ž®½ÿÇg îÿ@ @ ĵÁE÷ÿáazBCäß—ij\Gð‡Üä#Bëô¢ˆí°Û|T‚(nÜÎvÛÊ íü‡†½´ì»É|â# n@ ˆëݾÍìÿÑŸV+ŠTL*•¼T¨+Òu¿ˆ O.º¯'âaˆ‹IÝÿƒBŒ {7·ÿ‡«0}/xÔåª>è­U¥¼|VγÝ5Àb®¼PÏ-H€¾ÚW‹ÙBNÍesìçî„~¹–-Hª¤”ä²\Så)#Ð7: .pQA°Ÿ0¢\ং®Þ}û`’ Év/ÍåW]z¶DÇÀ¾ÏŸ³.ºÒ}TðšE°¿gâ ü¼»%p‰ŽÇÝpócºaZažo4CŽfkŠšÑ5G#Ôœ-P³5?­Õö4½ái´5½Éiz{ӌƦ-MÓ›™Ö®ií˜fm]šÙT4Ð&gãáL,×’©D8™ME‰0}zšüNÄ3¡X<¥—ñ;¤¢¡d#¡LH›IDb“±¨EÚ\4MØä$¿/qo4¥E¢“±89½{:Jg'§¡Œ–Œ%Éä’d&סx:–==›È±©x"ͦ“¡p”hËdgÓш–ˆOÏe'g§§³S©Äl2;1Gíš%÷MÅ£‘lzv"“ qwˆ<Kecñl˜äš‰jÉD:3•ŠR'„4ÕfÒô"21¢Í„ˆLÐ[îÎeIª€úÍ„&¦£Vñu:b f戂ёQ~26Ä< ´Ðl&‘½/4=KnŽg9šJPéD(|oz:”>•¦Ã!⻖ΤbáL–MJ™efÊBÄI]Bn¥*¨/ê‰qÍ.H!‡¦cv‘Ö¢©T"•$‘Ø}±4±’”7€d‰Q»CÓ¦‰¼hhÙ¦´S±©SYZÒÉT”4„hœ|6Ÿ"•G‹6‰efyS E²áS¡T–¨`µ1MX™S7æÂv+þSZ"Ýo[@7Šÿ<>~Üÿy|ã?wÎøÏ+–øÏϬÿyÔ`ü'@ @ ×>‘Ç6è  —ÿÉvjnbØçVAÃÐ]†µ6vÛ–¦Z¨ |J†úžKg¢3»mÉÇövc#ýÔ‡@ ;„Ÿl*þÓ¥A"×}Ч"ì‡'„»º®¸¯‚¾?iüg¥ú£Æ²HL_+Ó]Òy)_W¥lN…ì‘˪¤,åŠÙ%úùf’mKrV–ŠèjÅnv[b7{ ·˜«©Y][zÁGcYHõìT.ÔHÍR‰Z¯A?ô²ˆºRµ(±Í5#?»*м —sjE}Tå’”}¨R–H‰´ •ÀíÚ\ µ"õ8‚H½«‚B]ΠЗõJäA¡~?5ƒ1}4ó÷„Ö-þ®½{aI„3 "èöötuÁ×E8L.ºçØ1xDÿÃz`iß|TlÅovÓøÍ'ÄVüfO/\°(íõÁï[{#² P7 jŸ[Kº‚A]pè¤nú¾àÉ“PréåArÙO£DÿÊ%ꦂK”¨‡†–,ïÿ³w-±m$鹚¤$>ô´dÏîhvÒó\kF£è-ÏÈž˜&i‹c½F¤üH(Ù–zM‘œî¦d/‚À IÙÃrN.ƒÅr˜ƒ3§¢L2›Á$‡rØ‹L6XA’Ã"¸R~T7›/K¦dûÿ©»þztÕÿÿõWuõÏ*ê6úw~n£.ÇNG}±[w±[qk=@]úй²bª©˜«)véh­Ã¨£šØÖËãð"½Šoà7ãÙÔ^Y[Í.ádü6^ZÛ$Áôêf6…o¦R×q&•X[MRbcͼ§Y·ì,[, ½1³Ñ[3%²ÈìÞ.’¬Ïë”oærfr‘Ä/.©Uê~I $¯æì&³¿‘ʤ“©-›„prcm¯o¤2©)pq}þ\\ÿO»GmZ®¤«´—L¬ÜN}ŒmìÿÉàñÿœŸŸÿÏNÀOþÔä§#pÿßÉù™yüçæfg@þ€×ÿ÷ '*𠙬Öñÿµàÿ Àé‡$qÿßCömíÿŠ.ƒÛïñã©wÿåÍp;ûÅNŒh*µãÿ;U÷™:‰ÈÔIäp–P-¡“»/ЈM¥þ¿K(hÏ»µk•zþv¡¾¬íP£Pˆú«²ÅÄýU»ú¢Qº«©íÁ‰i>,fêÄâ‹ãÿSÕíDΞŸôúÿÌÌÍ€ÿWGàõÿyÝ9bFØÿ/cÑ,ÿŸ„EÿN?¬ýÿ~Šøþìà‡(ðà3z3 Ž@Ç…GOÒ7穃Ôíqö¤ÛrTˆmq»WÍ“îÁDÚñÿÝÔM—s¥‚¼S,oçŠrES÷Õ¢²ó´úÑ[èjð½x/@aôâþ?ÜâbÛûÿu-•uƒîHyE^è"ë9]?(kÔƒz3JQÉ[”käQ½éIc#¨w³RÈ FQo’$¶‚1Ô›`Û©ñ`/Š&µr…úPï†R,ç <Øú3»U£P>(qÂêcvë:¢èU"3B±kZ®dVâ ÜPî(šR"É9iÅÒ¥‚r‡FP,^¤›­±ÐYÔ—Ù-l¶yøŠeª+ö»móîœÙFc¯²eä¶­:v¡¡årþ.'™ÕêF})s#:î¡5¯·ôbn_±<ÄH|O8‹ËCæ3öUåÀbõk…C‰¡3•V®jÉæú0o¼‹ÚgI]¨,ÄØV™¶²šº³cÅ¢¬†²Ury[]/òó½Ï ½Ï«•]¢Hè÷ÞÜä»[ª®WIpõ± ^ÝþÑ("‰þ½Ü½­ªŠN7îÒ‰(z)¡ÊTJG¿‹ºBíÉbfwvÏÓ‰βi#Ez7ê©«;j‰Èà\®jì’v«y¾ûžnhji‡z¿=ôœé=9‰>Ý‘±1ô¯áWêé Ñ€Ä6Ed{1†)aP D(aH D)áŒ@ˆQ°@èˆ@è£)Î „þ~B8'úá0HËøš@ŠÂ×™ABxQ Ó£a„^géS¾!ÎÑ/ „Ð9BøÐ5D²@è¦e¼"zh=^YH³¼&²^Y8@oˆ,!„7EÂ7EÒ2΋,¤Uó²ð-‘…/ÂÛ" #££h\r¶Ä¼M#Ø@!RÒÖä’Сÿ;iòÏ%þ“˜ zh=ݤP§„þB¬—Ä™1ä2æªó3s ñ#3Ü— —‰ïEB‡OéüèÐa|Io„´rÙ éÂ"ï;<ð=|ï½);ÒìðÅjOE5¶«Å¢C»`ß‹ì*…IÁ>Ñi#ð…3ÿ#Ó¿}EÓŸÀ°ý÷ÿÙÉ…y˜ÿulþ¾ûü¼ÿww¹ÿØÜ/Êc¾ÿXïÿ?!ÈÞÿ-gUózØüjtMÎÿ9–ý šÿ²0çÝÿaPÁþwÞý†œ(òb\÷ü——,ìÿÀéßÿ¡^gÿ‡/‡PàA7B‰ËaØÿá¸àÃ@÷ý{;[6äµX$ݯðbèy0á<˜®Á‘ÄVa!Lß=LRô‹'Ƹ‹ñ<×>Ão Gðÿ,–¶Šåã?¦‰ÿÏÔìtÿçÌüøÿt¤èãÿ3ˆæ»í¨@Ø>ÿÅöÿ¡¶‚úÿØðÿàé@ þO=hˆ JdnðÛ‘“­  ƒíøÿ„3Åò\,ï<¹ uŠ¡ÏÑ^7BóݺMsü>G½±öübÔ¡Äà®>](Êv‰ß¥GÂt£ØGUE»Ï£zP´Èvا0Šjå}KWJŠ ~PîåöÔ’R@Q,l“zsº±¥òÔ=Æ ô¡(ßÁúQDÿ¨¸e(÷ Š ÓÝ©ÞG/ ÔCwt‰†ÃÔ­c‰žœð¿Ô±(R-¸u™48FRôD aX „£±eÉ(%P×£=láE .£î—I€èÁ$…Üí¤è¥e¼.úèSÎw;þLýR±ñn§bØa%¶ùˆ&b›ƒØfvñ¶±›kع³ù…-f=ë`Žÿ×®R¬lÝUîÓ#-Ž×¬ÙþOó³³ÿ¯¹éYØÿ¹#pïÿôyà '*°P»ÿÓçîÿ5jÀÿ €Óy¡@tSzº½³ÿ:d¶º|èìUÊí)Ïß2àÔ‚)c«ëó§ÞÍÀb'ÈPðŒâ“¶öê£N"²é$òTïûdABtý˜Ü}Aý£L8þ_×Q0Оÿ× èH÷€ê¢‹&(4èÝá©ëƒCÄÖWÈß#êïäÉÚÅÇÿçNµ”?‘óß}Îÿœ™™…óß:óüOU<ÿ3óLŸÿH¸ÿØï•˜—SËçZg¿¢zçòôÀœ6þŸeÝ ö?yüÏhbÿ'ýìÿÜ ØÿN ñù¯lçÈ#+Eûò_X˜œùw‚üsÛEEߪhêþ1oÚlÿÏ™…¯ÿ÷ä<ôÿŽÀëÿ ÚQMÛÿ;cÑ,ÿoØÿ€§ò~P!@¿Ÿ0ÿo =DŸÑ›C|°/‘›Izð}‰SÐWìƒF׃;ró•ã~MË•Œ²Þá€?9¯lโݩܿF:™ž 8~ü2ÐŽÿ÷`–:‰ÈÔGD-*;ÊÓï.¡0úýK¡L0hý!Z :þߣH¸=ÿï®%ºÙg &·É4ºkSW4ÔƒbŒs[Ì<ŒÂæR Š (=ÄW7r{µRQþ¢êM”‹Õ½†º>xˆ¦/é£ B]ÁåCô™@èîšœDlµÆ$ôÄ’‡èû!¾öb«6&!&ÍuöÆ’oJÑ``I¿ Ûxö&~“°… !@ ˜6'·1mvZe¯þØíÁNc°ÐŒpF)*y§ÙNœx³RÈ N"¹$4……´r…‰7”;Ц”òŠNr”{8^4È£yBù†ªàÌnù@Þ§wYMÝÙ!±u"”uÊv áøU´r¾óþŸÓ³Ó“s~þŸóàÿÕèö¿þ0Q.í“>£hRß•œ®8AI |É¥êÞ¶¢ÉWÒ×Ò«Yys5“¾¶šJŽËÛ$­œY‰//Sú[ˆ)W~7§Ÿž›“KñL*+W;äÄÚòr<›b­mµ¤“t%E ŒR+šL%–ã)™fÖYÆóóÆùj|s9+¿:95=3;7¿páÝÜv¾ ÜÙÙU¿u·¸W*W>Òt£ºpïþ·ãW$ýµ¥ô×—WV×Ö?ÜÈd7oܼuû×ß{gqb|ëÕE×£tƒ˜“=þ¬™iáYžtš¢Ë¤y‹QF½¹”^NY y_ž”“kQk( m¥©/Yño0-º˜Qvšdú†O*³r—ÛVñìù•tòEžæ¢Oê^’Ó³ìôU×åìRjÕª)‰)GNé«G©ÓÚéZukÆc'’YS9¾š´«DpÞ'»°ôŽP<ÙüžµiMRö~Eaùh>¹YF—î¤3òêæò²+Ó˜XÛh«þ½{¼vLOSCä-q•î×®šŠ]|ŸpØ•ÍSfkí#ÅLO޵ÂW{í «™mô‡iŸþ`FÑ.{l£ ذ`;ž7ÛP÷ŸXï'ü:|1WºK¦3´`afó5RŸ+¾1dγò˜sž¦štÖ( -ôö~1êL“øx_ëT›`ÂMm`¤|ò¶h§|r’. Pín>×bv¿~>æc˜Z}2é€õhw<#6tèÏ`ç cÑ õÞͯç–s¥›eíîMÕØ-W óÁlLJøÆ1éeDG˜õ\þnnG©3Èl«tó]g©Û˜Z²¨fji>Ü«ŒyÂb¤SIõ³S›7TrŒ»n©×O9ÝŠxÔ“ÎÔqš.`y,'ýaך›ñë×25÷,G™Êïžš-¢h¢\¢‡°5[`j8»ÞžÀŽ<Öð¶¨5‚´éÖ(Ãâéûƒ+²öÝä’ìˆ:Ùé73Ÿ¤_ÂL3{ÄáìIL@(Ç*„BYk¼á×ÿû©^.oÔt4/•t´éöß„þõEÇEÉšP+IN>9œõhßù›;r¡ԙ·ÕÉâ?}9…S{P‡gDêúGfJ$é{ܦ¼öÏ%ê¿Aßò©AÊ/‚X–ËbšÎ¦k(¿×á×DZ!¯ÀíèZDï¯>äºQ.*ú¸wÙRoTc+ׄóšgYž×¾ˆÏÃ&Ì–mƛԷ®'Õ_7OÍÀêWw¢E»`_qÐñ—¿!º|’fTTùÄU™ÖÀos[þr˜_ß¼xOÕ =µ’S‹R?5åB˜Xðae÷²å¹379&,@ü=¡·aÚÎÔy°K%6××Sç]Ѭzc„[<’OߺÁóÀ)ª__Zs>wè¾X-åyGqfçH½®úÐéÆÊ~3aJÐÛáé¥]Me²é~/ŽNäSò:\­yŸþs®¿+¿àúüΧúrN7â…=µD ¤–3ÊÓã´èñ%•ý¦¾þË –xf‹Æ_6iÊm[6VtêV:+/Æ-§6ä«kræÃåÔ­Dj=›^ãüpÄÍ›O_¶9ã/TÎb*X¹õ¾¥½µåŸ·£VÆú©ía^œÕÉçÖ;U¯¯wS'Ú›Aež#•!†"ô ·Qc|ÃséÎQ“”©Vm_Õ‰=¶í”@#u4núéÓ80R 2m©ÐÿpÛô—æ÷À…%ýF®¨̯Ò3Q.1P— gß(â•JQÍ7·QCí­À´ÿá–)…P›Çÿ’+&®iá%¹†Ô(»h¥Oëq2ÉÞW LÚµ ÅöM´ZW¦kä~X«Ó÷nªªU£Z~ÂmÝ4ÿ6+}^äŽ]¶Ö–ÂÄÚ¢&ž¥Ü½ô¤°ÜÌ2ÞÄnNÛQ2媖W¤³×=UK&ïŠò€_¿ã1æO®Ûÿ…ÿ`q;xBŸúéM#•"p5Ðõ;âç#‘}ôΚŒ¯UJÕ 2'z¡Ý_-Ö{œ©ˆþI¸ÖÙRˆŠ“™:9’~Ä@&¤µí›>bûÒº^U éÒ~YÍ×6ÍÛ¤UžÄÙ ™#6hCÉ+jŨiŠEoÒ;Yóê7Ÿõtýz?»xº(tQè¢O¨‹Ò1¹ç;|l^3Çèßú':…aÊÂ+¿¬–iÔ¨}"Ép­ZÃ5%ø Ê$mÎ#Žà‹'eZ2 &'¼«,Q»îb–Ø(“m{"¾ºl-•xVk<Úœ¨êFyOÑ®T ;ŠAK·–LÍöI#*9oo4âQt¿\ uÞ^¸jÚîéãk÷šVP´ÆÍv’´Ñj!S ¶zz£UÎÚ¾î“Wèé'FXù9¾1:!tBè„Ý zI¶ÞùûòÖÙ8›1Êù»R¿=îò0jÿ ÑÁ”µzmÚPöêD­k劢÷oäŠUeª•DÓmÐÃl€Þ¡Ë't§ÎjIWwJJÁè³ EIJ¼ù»µ…¸÷CO³&Q•ËÐ߉ðYœlNO©ʺd­{Sº^q§~6Ù´¢Ò!ò¼Íæq—™Ÿ”‰ÚÔ+Ó²‘: ˜ÞãjeíÐjêvŒ¬x÷i‹+¬»°^èðÉù,m§ŠÚŸ®œŒ‚²]’@ÔþåJjê绯“°^[I>Ý8yÃNN2p[Úâ36XQžo‹¦Äœâ×Ë`Úåû6Ðó ßVÕùÜD”~²lG˜­KÓJùÿíý t\Ùuˆž*€ ªÈn²ÕìV$¹º-‹€ÍŠ¿n±Ñ"€lÈlÀnµc..ɲ (¤ªÀ&eÇabYÖŠœy¬dæÅÉybçã8Ž’×r<Ï{´¬x”L2K3Ëó–óÆ3c¯h½ü–'öK49Ÿ{î=ß{Ͻuëì-±/êü?ûì³÷>ûì3Q ¸DOï¬iL”0=éq…LfؼrÍ+[›Ý¼×DVe,(ïS!¾óÃóÈ‚øÎT‡€Ny¤ß…ú”Lci£@<ñDQšTE5D@šhB¥‚¥¥LW2hƒXLŒ-eR2áz,‰!p]Ûú(05M±”?p“.øæ2¦±yX‘­Ü'd+wÙ"Ëì.²¹ †”ÇJs£gG+#éä»à^òvj$+¦™ÊPľ«šuí(¤7Þ@zé ¤7Þ€ôvjÞL?AzSG$"¤7 @zé­Sé ¡üo³sÁïûÆýSßôÚdg¼ZÙ®Õq#sïÃ\SÂFòùWPÔY`š¼}£³Ø[~f!0Ò‚d³¢±qÈr†ÒYæ}`¬Ïæ[æd$5 Èh ó O9Kkr%Îo@–Â4 $ñãÿ:ÃçÏø¾Lü©Ö| cñj‹ÛA9Ô;GîƒT–·Fcl›ŠWê^k]ãJr2îhpö¼Ñ£RP©µE‚‘”« ”îHNÔÜ\¡›ç‹b…Ô–”¨a¬0hº©V}Ä”ªÃÜJýB±LR8x f¦È¿{$¦’'Æà¦—¶Ï€k€kñ¸F.³ýç Ø÷'¾éäv`ó4¿½Êq:j‰ïŒm å78dìY&/é´tmùæļÁç Ø÷ «Œ™Qöý§):£0&ÿÅä«®j*àV½fËü‚Ÿ#¶Ÿ5’ê[r³¢ét+lˆ¹™;wZ­ -¢f$šJÛá4 Êã˜r5äø {ÕkìÖ=C妱0ÑlV€‰hûEKT›Ï²qÕù2mã,õ™OääK|~›ó ìû'ZK;ÜÐ[ã ¾‹’Úˆ˜à>ˆdÈXì§æ»ôBtÀ›t@“oŒ¦Ø?Ť¼1 “‡|•ÓJòË|ç j'çú.Æ®œÐ°]9Ÿ±óÖô0ˆ/ez¼.YÔ µÕ|‰"œí¸þñ¤}ÔæCígP†Ú×°ð`M-#Ê7zúÅ{«O»vK@=ì7¡­k‡-WŒ=×QË6âE óX¨÷(Ìݰ`D®»¢G$ÓHˆ¯Ð4Zj5±±azI}dï<yòä)sò„Pþ›\ffßÿô—Z˜q»[ÕX¶0žÎ º Ðõ:r™Ë'ìûW_–ŠeÈúþkÜØS×ý‰X±$-Ї‚xÍ}KO,† »söÚúZvˆ1à²wM£îC öllsÓóŒ¼ÊùöýrÛlŸ{& ¡z\VÌÀKF—{aÖ}lCLgù $ 69ö;%jñ¡w·~à³/µZt¢Ôc>ñÀc¤=ùuÎs°ïß{¹µ²£#H€WÑg#WQï}(}Ãè(?"Bv-’0•„â2”Í\e‚𴤂“sá‰:bK¬$¥á³ Å8ÖÐYîbÓ’wiKövsÐt5–nGgÖ†1&=<«« hĸÁ1z\®Y!„¬ò¤™ü÷hÁ|¾ÄéŒLéw(L—Ì÷ï §À`mPq°`o¶!•¹é#y[›¹']eT.‰£Â¾¾µ°ì“Ýÿ8O+[ËÂ4ó€Ú.54jNM ¢\*EÌh”[¥ø ¥¹æSY•öùdEÚ§Ó¯Rm>™Æ)ôÿäKŸÿ ‰AbýŸy*­¬©¢éS?µMÀGpÀGÁpsôí“oq½û~õ«üÝÕfc›üÈ=I5zøH>_A¢KH‹ZBº™×6¢ý"‡ìK6õ‹!rIíVõQrd°Ÿ)}U4TJ&yè¤üqY´\vgà}8“€ÙëÏì…gþé)G¿óúÚ=r¨¯« Ù™¿-ÎüáÌ¿ÿ#ÜiÂxÌðú¿z¸¾[ìfô;MöxÀiÀéþ æÃ>Ïpùøööÿ¯×[ëÍ*—˜è@[ŸemŽÄèü¼øØ†ùüGÀÛMaWæc~}iyqsãíÕÅÍÕµ•7—×6WÖðMÚ =ÏÂâõ¥7×ÞÞÄî¢) ÙÛmUÌÎè)¤gËt%)\ª%)\|æR|SÞYkÔÒh}MEÁRC7–LT×'ŠÊC?Å÷öýõß—y¿•î#t±}P]‰rtâµøC0Åê+”Å3Õý™Â ^›ï…ôsä±ÏRO9Š çSlbð¼‘ú9 G¾ï¡Qª¥:žm8œ(\-ÝèÍ@ªVásX.…Ññ‹ ŒÔØ@ _¥ â »äL~LÀ4çËœÖ0ÚóOþ€Ý-i.µ·™s¡í]U¸´Æcô)äpµµCôÏ̘—ìX2AË|çÉvÙIA¿à®“‚‘Wµ!Í»F-Zzô¨Ïå7}Ý×??Ù¢´fñÞîB£º´…ÿC…æüÄ…©ÒTÄ¿ö¶½ƒÅ%I8S­Y¡€û [Ú’þ…±ï©«ÿñ§¹ãC½[¤Wêì[Rø`ƒòÞöHú´aºÙA±}襇„]».vŸ¾+{Wxi7H!¿P{W}n7Ä¡TéµÚ»®îDŽ’>Râh©#ç8zåÎFOy¥X;ÓCÅ‘#—ä±ânŒ›Ã˜ílÌæͦWmcôˆ=[R‡q´fTL<—Õ¨:¬h{âD#ÛÿU}(ªî£Ü˜¬`!¸™ñY°±™&66ØØ`cƒ 6¶>llßáú+öý½{Lô;ªòýódK$–/£˜‹‡ N¸~}Äm«,¤9TIq¬Rˆ?Uq9W1Z…‡ÄŸ¹D];{­Þ½tËΜ°áÊV–²£øš´GIêòFjR(D8ò“Äz’í™ùªKy°ÙK;»{í¯ŽIR3¸(ì7=l¹9•¥õÒ#áR&ÒøèÄL–\3 @ †œ t q=4;7{é¡ÌJ4«K[ø?‚½Œ5šé¥chLJ‡zé?2:[Œß³’ÜýÑÎ#Œ‰Â ó˜d"µÛÆ»c™Ýt,H”왉¿7äë-cï4†Jî†{[ö!Œ"m#hqóØK9Þ>~Jñ+{m;‰•Ñ’Òi$my{?œÝà䀀 ôP„rÌN¼ð§è·ø‡K[¹±eï^›½³ø2°¦¥õv¥i°¼°¼¬ø9éfŒß‚ ^ÆGJÓ÷f®–^}µtþ•ÉÉÒ–&&pð %<{4îìÕH¢™‹“äµË5–0SÖJ˜¾‡3Nf¹a Nzt—ÏÛ¾Û¹±íúuüÍçÿ"šoì´ñtÎU‰Â»ôæÜÚüëskç§'§$2€ŸsÁkU›µ])ûÌ´{þ¹[·¼jÛÛZk¼Óâ×d‰øB7ÖÉ·ƒÝWÞ~½Ö^Ý¿U;)«D?µ´Qz¯¬ëX¢¾º²VZÿäõÅOÍ/®n,­°) 'G_xÔÄ;º¬A _^_\Û`dâ¦|Û­ÒÄFmÛô½Óm¼†I¦¥­øt+ÍÛ•ÚgèI„KúµFÝsIÐø¤sDiPunÁj¥úéÊm§F\ÝÛ©:Ë3®À㊰mÒœô͹ë7×KË+oMÄañå=<™qiÂDÆ¥mâIŒKSe—¬N^\Ò]6qqÉnù““N")niÝ'Ð@5&M+vmå­M¶ÍOÊ{Kq);z$ H(9 ¨ŒHqðKLýô»ìû¿Y÷ÚÞÜÖNÖʟĘŠ%‡0„°u/¢âÒrɤ5^¹±¡é.Šÿ—Ùw‰€5ÞÁä0àÖ.;¤n¤qs×ÔÍQwÂDã©èF),^…‘L\Ó#Ï„AÌœ]ÐøÕD«ÜEVŸXb€Uæ'œ‘«0ôU ) ÇÆÂOœf8=U:­âÁ‹¯‰uâ¼üÉnY r4´ê$Z•Ë}‘–u¥²óé¹*Í–?Ô „¦ ZOjl#Ó+ ŠŽqægäPWÌcsΙ[ÀcÍÕë耀®ø'TDqP¬¸Ô ð ðËFæžì;“}?4NŠ$Œ_¥Úx2?x2>ùþ€˜QOŽ<†$ÜLƒŸÁ&ÎKV6U!¦Ë»©_ Å4^%ðd€F]G#„Ž–ú{ )÷È÷{Tð½ëq åÉ®©¡ä|g-A²\ÙöJw+ÍêJs¢L ù’Ô%š5Ò飆¬tËšEÆIËa{öXIÑOè ™N†+Å+ød˜RtR*n†%Ó‘œÕÆVx2³¤”}†â¹—Pi{¥Z+0_´fXj±)e§ñzJ±¡gø£PŸ¢^‹+Á±}r­bÍäá*^- ›xݬŠ’È3O6» Ö7æ°huzfæÜôôii±½±¸¾>wmqscñS¸„ÓË+› ss›´®•æ+;¥F»DÜóI/UhCK·Í0lÏ^€o¼kÛ\\[[^!ýÀÕWI½òB™0*Kª ,8§‡PáÃl_ó÷Ç'´çêõ^LÁþø„¿?ÊÁdƒügtƒô5¾ìxCgðÃÁñCT¢˜½VIe“(–Z<…ßlœŒpU,v±Ùl`b+¬€œÙ¿e&7Öié™—°ð¢*)”pH›«dc#¤ñ¿–DÖ‹O<3`13FÒbRR|ÎLÑvméû,6‘nãçZ»¢ ‘íJáúR Pˆ‘©|eg S«“#SAþÍ óå–QF‘Yk”b&JÎðk£¾;SZâIáÑ"Z¦–H¼©[ªlÌ=Y²< ÓgAÌÇšRÅ'DkßÁr&1)ÂHÎ~ˆ¶C %3qS P4S[lXϰža=ÀzFhd”ëWØ÷¹oxíkõÆÍ µQ]÷ÚxíÞnåŸbŒ„C˜‰ Õ$æ=þ#9ãŠïÒZåm;ãÿñ½Þý)k$}˯›ûH Y\p¦$"®0ix›EDU«¾Ölìíì ±§³¤°0Þ®ãM¼Ìùgö=Ú"­%oúT$ÿA¶,Ñd1\Cñì°ÏðFóÞ“yã6"3õy«d}®y†=LÜ(zŒxŠì—¡l“aÙ¶{wƒE×ÅN–na$)ùö× É·Æ È£—%Ù””sF9L7§8ÏÀ¾SS:e$¤6ÿŒ™j’8Éž!FAM/O!òŠ=ROY#1Vʨ`­\¨Qì%ðàRK@8@8gZ9ö»œ·dß³Ç=~T„‘GA=[ÏT=§_ýÿ›yPõ1º §*‰õ2¶‚¦Ä³š(\W*O¥´qê ++ˆŠ<\rQÞ äräŠ¢î …J–,¡C»„Ȇ6v™ËìûÊužÛæ‹ls#“íÇ“íl6‰€ÅFnù{žÙøëçÌ«µiL<§~O„Óqqq6ÃåÐçSV V¦û)˜+ý!…XŠy…è#CMW—t7Ÿ©ê+;[|e$\[Á›É,7&@u@õGu¢ƒÿ.±ïÇÏíàŠˆÊÈ¥+•V­JÏ¡–L1ä2ß«®{‹ñnߟKzµ4«0?wý:¹^´´Sk“+FÓSz¦J;{õºí¿z^f"ø"z®ª–/â㤸096«ªƒ)…Ÿ%Ï#±ƒV‚­—e¦ÖtÆÿƒø¤K$.½ƒå½v9Ìx1lnaÁ¿fDPz;Ì6#òm±ì¨?à4àôàà4•>Ååö]ü)Z0Ù*ÉÖÀ¨ü“A…R8¡ñç\Î 4Úþe FþÈ% ±%±È`5®6q5L•æ›!·”Œkƒ:£#úC VÁ{ªDb™–’”?²Äø¥åÄÚ¹¯ÊhÅD–kJBqº¢¤ îÖÖK–ÄY×¹ÜÀ¾oü1/ˆ[±­å©)Žl/­¸íÅYyE î ž=?iÙ¾b~–¨¯K1nM2Ã*Mˆöa¢9Xð‹ZhM•¢Úa]˜­ïVX¤5š% k…iYDårh­i‰›ŠÌzõHˆ® ¬¬ RôÕ¢4PSÕ m7Žiò&ŒaVˆþ¡]k×=¦¢0ZîIX'ƒÅºÙáxe¶ Ãʇ•+¸V>BO}‘ˮ̘cr´Õ®ÔëÂñ õM€ëP‚ ‡ñ–ÕãX`6¼í5«µJ}¾IÌmg÷<†!äýºùÅ…k‹óÿÁs†[¬PLN®Îݸ¾Á¯ *„'Ð÷KqÚi€ËП0ˆÑÇØ’qÞNIA@JÍbÉÅ®6[{UÃãJ2·Óx3ëÇÒH wYµ­ÒüµõŸ‹†©ÒDRöÙÏq&ü×ÄÍà£r°A*0=\EWbÀ¦Y3–úçºÙøš£ø\Vµì?Z5ó+ËKË7¥ªÈMz(¡lZÿÓ—ÄPÕèÿHLI|ФÐz„ÜáŒÉÁ©δØB•ÑÑ BpÄôä%±5&k ré¡YñgWi,Ý{ »PxÑÂXK ”¹¶%îAM\«òÑot!ÃTsT~Mªl)ÖÊ¿+«‹ËÁôÇKð[›õFc÷c¥ë++«4¬puqcþõpµÒFîò¹ô3’g))–…ïf®/ν¹ÉZèů°s‰ÖOµÞ¬Ôk[ü5ºÇH³¥ r翤¸kÊ–ÿ4·Ñ¡]Ÿ¯µmnýp,ÞqîÖvªQù 6­®Pä¶9xDþ½#½rqª4Íà·Tóy:dýL¹‹þâ”^ÛÃFPbGûeÝ?gÊÔ^*ã§ µàRø4FìÓåj—1‡>?·1M®0Ëåéòù„¸¨7ãCLËl8py5ãX°ˆ` X½]„éW’ ‚° 2^¦i,‚¸`8ÂtmHf¦áE@A²C Z¤;x\ˆ ¼Ýç‘éî•V£;ျ‚7àÊÕ>pBìÜ”<ùSáÒZ† ¶øÎ‹ËAômìhfj/Ø*`«€­¶ Ø*ðV…žãþÛ¶·>Ͼ.KõÒWçØ½"=œHC{T¢?írŒŸ)BXZˆõûèK—7kóŠÿŸ#–SÒE·³, V½­½¦G­Íßœ[›}nmâì´’¬]¹Y7$ O¢÷¼Bج‚$$SõŒû“‚ì ¾èû~ùò—ùÚÙiWªm;@ w¶/ð3e¨Ÿƒó£!—¯”Pe+1J0>P¨+2•ˆÙò”1Y'²”©@ˆêŒŸ@~Fù ì `€ýöØ`°è×ý+\À¾÷U&›,î´kíûÄÖ:*”XÂP"¯üêîÌ6/C2˜7U%&;>Æo~X‹iòwDÇ–Dü‹ÂÊ.M§!O¤¯ÄŒ¤jÛ:ÃÑU WÐW–ÅžNI]ž2õsÊÔ¹® CÄò͓͢2¦gFÂÍ(D;`@ 9sDaBŠ<‰F­ÞG´µ‡)õµÅO­ò?ýƒg^8=¥ÏÉTéô‡¹#3"Óîì…pØ¥a—†]Z!è°KÃ. »4ìÒìÒäžÈ(?¿fæË,ÓJóvpGä‰Pe wÇŠý}`GôÁnƒÄ±aPoÀØZîvL0Ü¿ø:[ ÿèK¾“¾–× `.†wg ¯–^Ü:ôóHbztÛ ÆÚe¬É")ýßSØó±‰pU¬Üüa¯ÚíÃPòœõ÷äŠþ!Šw¯m~¬fßGE¿Ü¦$žÙˆM³ýTÖWÞ¤Tþë*QÏU„ãàðbÅžptC.Ųy3©†h-ox­îJ yyYÕÎÔ–úÈï‰1Iµ²óV£ùé·jí;=>ÄÆ” i^¯6Û´ÞH#=¯AËÖ‘JI4„i³¸h·$ âMžŠÏO‡žŠƒ4|~p2:µÖÎéÓm"@Õîzg„ÔâLWël5v<¢î*ùþé¨ER¼òÇFq+4Ä*X4fAxÅC:RUá=+ÍßX[_ñKºÓ‡)” ù˜hÏòÕÁê¾1Ã{Obq˜pâÆßX”Š$ÞÕ•˜H’AGž)ˆhÖ•ÕÅåp@x¨l×&»is3ËfM¯²µYo4v?Vº¾²²Êxö«‹ó¯ ãÍ®Š°Ÿ~¾ÞUi£D ’y< Šô%i3ÆS~}/~ËÔC5Eâª÷[äó-íN¬>xáŸ/”ÖVÞÚdF“q½`±zãψå…g'ÓÃLm ÃJ¦ŒMþüõ•õE #(ã3¡•5Ég¬`ÜØYÇð®}zi™z­\_ñ5+u¡QAÎ¥WG {}=' N@œ€8eLœ“Uüçé7žb¥‹—}¶ëaÝzlzÎë’7±úäîf˜[§r¦TqTNhŽ@éô12_ í9½+¤#vJèÄaq¡u†©r!xÒèSš'„dL÷ôÉÐIŸyÂ䉟Û¨RÁä3^è„ jW’ ב CkŸ=FMj»¬¤QÁ¡€: íŒDêƒNcÅ`F(M5KÔ2;^È; w@îžÜ!TØàz8Æê¬ÿ… Î>¶@ŽIÏ.$'’¼êä²ÊrFG?Eaô› Ey<´<–Æ@QC>.”P™* 3¥€þ/;õ+¤ ~òÀë„Ï41|Rgy“Tbç>›:^•Bäxð±™ qSȬ)0Fº%Å1¢& ›œ ½´š¥"gò°ÒÄȘZA€BX6 F@€5ê”&êØS\ÏÆ¾§>KK§“²æÝòšÞNÕ“Ž8•(ÂT½ßvH{þH2JUÝkâRÛô¹2ù=;5Iðð™%™œí’Nð7Ê +|qK~Œ£˜4~1—’¾¶Çf<$  9êà(€ÓšËþx­_ë“^Ì Ö ¥fÒ@ÅS'y\‰&sJ›·)—½oA±¦hO»1:Uð cCÁ–K€ßxúJá«f"½9=¥ô0|ÒM 7?ÜV õ†Ï‘móWά­ð³„ïžmOž 4Tì68ñbcJ-£ ÖM[ò²Ûé©¥­©ÓSjÅìm·BâÞÊ}5"žd­›¯‰v‰q¤•{سR·_3wV §Ó<9¥5eRi³¾[ø¹ºÔ2cüùò äÈoBò‹á/r#û¾ÿk õ2FÚË,~[ùgÂÆ«qéõ¿‹L>Ö²pøíH&€þI¡øOZ_ E?Stœ §ÈqŠn:³-î0ŒEÀŸâòû>ýeç–vîÖÚÌuª†B\z|ü_º6Êу,4Þ4ÈBtGƒœ6üq¢:ƒ“œ&²ï‡¿‚ÑM¼‰!(>ÄÑÑ©=˜:˜ì«4ÃÏÃâîÿJ‡¡;¼«v8’56#‚y¥³×ã×óŒ™V[ûÁ°š‰Úp+ €êÕª T¨®«®àØÆe2ö~¤ºÑ²ÞÔ¢Ì ºKjŠMÉnÌBì…Òüƒx˸˜“bB}Bq~°ojÅm ‡þ¢VÔU­¸]#š$²3ŽÞK”å¬í']·¨ÝE¥/ò£fñwÕ/«‰®/ÓÍ]ºùcm”7ºNnʉ˜OÿîûÕ9Ó&Ôÿ›Â°ŸÁ~ûìg°ŸÁ~ÖßýŒø ú~Ö¾KˆÖã5Û£'ÃúÅðH›£gæé7á?õö—Ü¡?ö&ãÐsï`„#Ï»ÍõGx³b;;ñŽítÆGÞÖNöãÌ[&aÃma4h,ÐX ±@cÍöD£ŸâçÌ'ÿÒ§Xëìw=ô¸”g¿™ÓH³B3³VJ˜5 ”|Jb]Ä=Ë5‡`™±?x#p+#2¬4kx벹܋ ˆäļ6JKæbÄ%µu4N Ĺ›2¾eo°øpPðÓ‘S¿Ëé û^µ¶ÓjWêuáY”üûIÉ;z!(/Z¤f 19YDˆ`Ä&íѵÅ^ù4±~b¼?V>XŠSªÔb™©(¹‰çÝÆ|ˆ-cÝêj RRÅ*8Ònï[{Ô5Nt2þtLt23gi¤„»¬Z£Ž›^ýÚöšÕZ¥>ßÀôá6½§èç8þ-9i²ç˜*)–ÒÄçL3ðÀƒ7` ¢¡èêÕxºîlu˜3È5ú8s Ÿ cÖäL+3ÏÞ4òê:‚«Ñ!b“©“$…få.äQAðU~÷U#ithE³”ÓácD~!I­³­>ØH¤ 9ÌŸ ޼¸à¤fèMô—#m´˜jŽªÑ¯Iî…_« |ùkÄAîâËŸ6m—ÏajéŠþ`Ò¨á¤L"bЪƒŸ\­ÈÊ~?<• ,: «aËÙX°Ô¸ýB=Úƒ´tÅ—NAîáÚvÁ'¶©Yïpk‹EA=é%È’™ô¨eŠ«)ø›ˆ?A!þ߶宇)§,»XŠ÷°¬TÊmØzÁ¸¹ aµ¥ðyNÿ†¿”:KâàTFŽ'ëd´‚ŒCïž]å&3²àpÆçÏ>1Ó"å–~vi~¥v²I êœ Û‰ÿŽ–X0§’¡Œ[ÀQ¾ˆÒ®ÌÄà,³Î8Kà,í5g œ%p–ÀYj3}@9K„Æ~žë5ÙùÉßÁÕà†ÖvòÇývÐ_¹‘|~4·´\Z|£R«GÅç§'íï23ÀyV+­Ö;æVí¹ØlD;N¬¦XäCI0ˆZJ?Dôâ¦xÜâ6žyÓ™Ác(,K¿5ÂdEa¸4ËpÊšJ\ÞB•zúÖ™â˜öC8møÃ”t©5Wm×îRÁSzÄŠ;²Pi{tsÃg@Lœ å715XÏ3DVQ~Äd—Ð+`ìèérD²™n\jjj#ôá?`{ÓÍ—Ù÷ÏÝ£™®T°Ä¹å­6ñ¯=âVôš×škãÈöõÏèIN³Ôö¶Mۋżî®×lß§gÓ•-éDÏÆ@¤ÒZþVÃR,6› Ú™ÒÝJ³z§Òœ˜™žž,þúc}N0‹nëwåje»V7´PN¸¼·}Ók®Üò›Zc6JÆyo ÃgMkB…ÐÜ«µÚ†ÙagêÑ)ËJÊŽ(˜€·Ê´xΓ…s7[:½¸¶6Í`fúô¥(‚(-D[U3¡@ªæ´’ߢ„Ê´ºx¼Bh 728º©|ÇŸ¸TŸ*¨—/Ĩ3!˜ˆn–Ê.Š™d¡ÒϘ¬1ƒ‘$«0Næ»!%xõ5•f'@l;r— rŸ?ZNËt2­ SHjÑɥ݃áQ€ŽFüȦS3tͦê”ú7ýµd‹‡5?¤¨B—ä%4¥ÐÕ)…vNè3߬y…|s\ Æ`B)4F$RëLœãvâ<.õè]Í"m\b#þÄæ PI!!Šáexú´Œ²Ø/.”**+á|VJ9G*gã€7ñ8Bį5ùCí@7m»ìŒ#Q0Lh&4‡TZÎvBË.êÜu¿,ŽýrÒ x&f¯:-l¡´ü½|B|lxJ†ØÚg½¨¸æ*[«±ÉÏpî´ž>z‹Õ=èx9aÇ Ë™¸ç.«Y…¢nÄ_‚ˆÔDo]Ð2–ä嫤H´Š šZ¼TJ¶˜Í%¤'Ò–SïÉ’4ƒn"¤Ù zYô²P:'¹aÁ¢‡Ñ ù^¸P™bk½ˆ¡GÆôQBŒ–ÁL‘¤dâž †Ù.e§·U¨‚ŒÕ€*hàùaP*TAny@ª Pæ U¨‚@t°´  U¨‚:û:·Áeß_?î3éó-,Z¯6«Ôš©•Zàßå(bæôo¸™Óz¥îµÖ*mÃm¦©e õ»Oú+µú‹§\jùÓC'4dƒ¡!c]’f†m*-áת^‘ÆOÈ+ªäP ¦©Z%v“Î4ÓxOãŒ0ñ¢­Ø¸¾) ç÷ZíÆ¶×$HÇÚ$3é‰Ü¥§ eº$!Ïïš¹|1Ó¬Bî'U»Ôcfª;Q½~¼ï›CC ɵ£æf$Ô“:2ÓW@cšX9Ò9p’±m›FÌxƒ®t½ä÷0ézô†7ûÝ„û†¥ívÜî™Þ{ˆ‘»Ü9rÃÀ°œ¼rÎ]¡ ‹6à6ÕJ¤Ì%9¦$i]#Ü5²f¨ËWJëmÈ–¼jHGâ,Mít7M§»éL0âp([$´œBLq; 26,þŒ(LáéÐ+Ãd( '%pRWœ”ÀI ÈÖJåƒ/\ÃI œ”ÀI œ”˜NJऔÉpRÈ}ð‘NJà¤NJ@I}À•ÔpRHØw$„“úR‚Љ;ÜO0û~³^–Ù^in5¯×v<_ÄÏèšt™F'7j¾e}Âó Ý¢ù·c.ïCÁ¹PÒs¡?êä<¨Xèü HgýudR@:*}:æÜ¸‡Bãzc¯Yõ¢Ožy´÷wmé»(…~Û Ø8Ŷ¼Æm{¾¸Î¦¢ÕP²ƒÁ”«¬Ê¡fU ²ôŸÂrôŸJ&KÃ6 Û,l³°ÍÂ6ëSYØfa›•5Oþ!?;fú€ïy*øÛ „ÔØîkâÏ)ò?(c‘˜±(ðdëíFÓÛ2c‚–,%¢3À „…Ñæ`Ö·Cˆ10?ÑiÊBš ™(îU“›]Lq¼zí®× ˜'Á ªDû¢3Dn ²â¶ú9©ÇbqH¥"Í#—$,ú‹µ·‹¥b@#ZO6(“{]µ¥ŽpšêÄÈ|þ,À0qtºÈrÆbÝ“ñŠ”¼PiW&Ò0f$fœ Qæ²||×½#@¸: ,?°üŠåÏF³ 00ÀÀ 00À 00ÀÀ¬A_tÞ…ïpÛ7ö}é”6#ù'ŒE4ܧrŠÚAOmSQg­ò¶sÊÝÖˆ¿0ê"(íãåÜ|·¹N™w´´F=ÃMÎ`RdMüÖhDƒ,/ðVÄQø˜‡ 3¬Ù€¯¾f+%»íPß²KoTÚÕ;d¡¿UkßIO™)$$ÏjždìQj¦,饎þR莈 : €èh`ºÿðÌp;ö]úŽÏä­Ý[Ú¹ë?ôf²w0Änð£Q b¯$8ÝC80Vþ¸ ¹µð«…Å$«{dn[ž„åÑ¥êYÌx¯¶…6"ÌZêÁÑR«zê5¯êÕîâ6ïÜmÔªqJj[ê8 µS>uW²å“Lm“e`èÛ]%¸”Ä´èbHmäªtS¿=º±ëf%º1©“]"&Í!Cd1Õ¬qÌœ¡FhªðSšªaQkdLÍRò›Ìí.„MH3¨V!©‘Uê—µ&¹\Ƥ,kKî~œìŠ|ʾU#-î‡Jæïp@Žún b ˆ5 Ö€XÃÄk@¬±Äk@¬±¦/~¾f~‹Û6±ï|ÓŸ“õÕùímÜsVvþiaºä(rºõ>nëd]ܨÖ+u<Ø^³ÕØþS¬SOYÄ=2ç}ýápIƒÚà žX41¥h#åïLüŠ’7CþKH„w§è­I/Å}Kõ‡ÇÉ€˜Tì³ÎƽÕÐ0*_Í¯Ü 8=ÉD ¾l‚T”¹/)„·q»ÖjÕ;­ !ãñK&‚i ,±bö w!"±¹ g´bLELbΣƒÆqÞ¤ÃΆÅ©Nš*L<ÈЦí…ZPV-•ÛéP›múᎬLÞ_gõ-7Qnâ–E‘‰ô ô$¤è"³켯¾¦Ê5:gÓÉ~rá•Tlº‹Ht}}QìÎA<@ê8€RùÍ™ƒ·ðâ;}ZÆÕì.)‘¾qÀG1p|„qH“1³&ªa*–éÿpN%O¦fFlÒâLôfÔ”Üúèe‚ƽzy8èe¹kôÒPr–ô²ìB/}qaݤV‰Ù2¯·Pà5FèÃDº±C–6#–FXd¹'mí›_ˆ:bŸ–Ö&ɾ¬È}̬:ëƒ&ËÒn–õÉŠì,QÆôVmT97®ÏªônﳘBê9ùAÐéRvÆdpº§ pº§ Àå&ëp¹“Ë…Ópº§ IóÀéœ.‘¤ÀGL>Nàtè¥Üj —© ôNàtA78]èÚé¹Äqâ÷Yƾ_x™_Ü`^ª­oµâÏ[mÿv žª€G`ûóì =v Nîá (\Ìs0Ô¥Ù#ÀÖ ['l°uÂÖ [gLžƒ³u"ôÒqî3}ÿ«…@ŽÆË}©½½Ú¬ú“ÓRäl-žÈÙÿq?{8AÍkt‘û¿~øà’?_‘ëÐå-/Xåµ*ÙóÅ-?\áS¥Ètß“8:¾Ú1 1Ñ™¸Î*ÄÖrPb,F?MsÏžÂ¶ÍØ†¤vmñ…”Ó²ÔºRiyÂÂò±£öo3ç/ôÊþ xSwÞ^¬‰‡¬^¬¡e ‰ÅÛa"ÛÖ£q7Zn4ö±6¸wW¢„t<¥é é²5¤ëéÊ]A:³FÇH×û µÞ±Ej¢I| Ê7˜th—¡ÎQf– 3çÏwn©t¼'6.T‚¥¡o—k´I*9R²¥;2tH…\ KH“d°á9t¡£M2MÎ[¦ šUŸ\š[/É%Yø=@EÇÂí[gš:œ7RœQ±¬%d¨!w”yÀ—3ž <Ú‹¿‡sH¸Iñ,® ñ›‘c0…uá.?¨ÁA jpPƒƒh jpPƒƒÜ  ×ÔàC@¶A jðáG:PƒƒÔà {Ý#¨ÁA ~ÐÕà¡þ*¿kξßú·uo7ªŸ–û#ÛÂëñÄþÛ-8#ÖY‘ÊZäñ “»ϲ¤Pñu%Uë›3„—Ö™PÏGûŽƒ[”IòŒ[”ä7§”C¡¶N¢jÕ…Ú)mR¥»ô–¢ümC•l•í‡U¢UåIPe(½õ©õJ5ùÌ€«É SÂ蕦#k[veH@TP2ÌÆ([sé$AŒLDÄŒ>¸†ÈlqäÁy¨5Æ}GI\š}W159©)šçPk‘>“Z’dóiê¶ÖuÛ¬ÆgŽ[[ö(­yîÛAÊ2탵@uÎ;ÔèêHå¨ãÕò%ñ“ÊÓGÉ“Z‹³T1I”^WWìfcß ÚMÐnÆUÚMÐnté ´› @» Úͨ< Ýí&h7A»9¨ÚM©^Ðnrí&h7A» ÚÍ$e‚v³ŸÚMb¨zôŸrßÍìûío4½JÛ›¿SiÞöò'ðÔÌ ¹Ñ|þvÔkH1¢Á8ÖvÚDiº;‚ '-JR¯µW÷U¤˜a·ö¶·ïoê*Ô‚¤dYoì5«ÞÆý]ƒi->9WR­bœPœø½zÝŸ2?ž,ÖVºlÔf·?K63½?~#(E Q›­¡xº6BfÌW]ñX…Ò‹MÆKÄ0®'R¨VêuRî‚W¯Ý]n´×½öÜ6™)üÇz£Øééÿù¹……ç§J—åy #¶ZˆZ—Z­¥»ZÕë^½g õ®yU¯¶›AgY±v¢Qž>wÚ"‘LÁ²˜UÖ‰Àqgvà+V.¬ÜÞ®\¼y¿ÿ]~÷„~GG”nÝ«•ûÛÞN;2ØÌý²›‹ß3ñÖp¿oííl•nÖÚôÖF»ƒ£Ù¸Y6ÿ°”pxc²¡-myÕÚv¥>1svª<éxÙ$Ž—xsnmþõ¹µ‰2f%¾ç˜ÍÃT@ƒ"tILUÛŠI²ÑhWê”ó³&¡x¤/9~“Ôå¨Ù®aŒ½—ܧ½þ`uè*Ê›“N ƒ(aô¤Kyì¥(a4™cº„‹÷’( ¦)$“¯”êÑÔ…‚©1j>\›I/­!~@Ci¹|c Tå®·å“´Ö™pL¦ŒñáPY…îb%žïj9$2Ø>´J1LYæL<ò·-W„ JÆ\œ€¶¡Q¤( =„/–Ô ‰etEÓü&%F:ðÛ$°ÛÀn» tØm`·K)Øm„Нósw¦³ôë^Ýk{W*´ˆ+ÜPú~þvcŠ#züÏp=¾í†ÐTIñõdQâ'W¼ÿò¨Ûq_WxàLÕñ"RŽÎü1j•n¬/-_Cbl˜s!ÙŠÃîm/^»œ3.[°–” 幚Uæ.¶1b}ßqЫX{¢×¸xËsaH‰S¢‘¤œM½×Äe?d¬Â¸‘ ;ÁZ:! £ÅÌ*Ü3ÔÀJšî¨ìeCöIJi#JÌÐøü¨ƒ ¦¤Éâø˜N0%ò,'R)4[Ø>…¶P>J«yËdÊL7‡ìT@ãJrí@ãD4®4¡£Íû>ùP-ÞíÍ?mªˆF.òŠv+Ú=rÏÑd 諆ž¾é¸f»–5x´ƒ.éÞ±G°|Krí°|aù–z°|éfÿO¹îˆ}Ÿý)­8:zf‹#»ÿ"“;ðìöøÿ=7°D"þ†(1ʈÆäALÚØÞm,€3‡ g°óY.¿°ïwŸ$… ×ÑXé}¸ŽöÆ¡»ÔâGÃz̓áx_®µtPuG7[êe%'¹Ü’ñË–%,Ë —%Bã_ærû¾ð¶ç¶ÚÁ»T\FÉ0Ü’ ÑýÕ)~}ð”ó{­vc[|à+TOèqS6ÿ>Dj*¢³–¬ªŠ¸|)u±Í¡`qKb€ µúÀ§Ô[8ä¬Á0—å¤Ë0dí£ `¢ ÌÆFkfW%I ‘Ô¨ÁPP„Ž\æºöþ7æ¢ñGñ'8ºZÏR~èNÚEà¤Ör^ ® ®ÇiÜö~ìp€i€iñÔ¡â·¹\Ǿ—~Ç\øýü³öšûnuü žEðsÑÐ~.Á¸¶zÎÃÉìÜœG1ÎZ¯ ã–Þ^o9ßk¾'Ý÷ûÁ"ÑŒ š6¢ Dsøˆ&B'ßå:ö½þEZ°èoA !\m[õ‰·UʈiòQ÷;Gcfðk°•›uÏ÷Ð'º¨°8çÓ’˜ó]²øæ`uÅ;èˆN7$^:úrœ«»Á`cÉÜF›¼rH׋g.ñä©SÊh#”ÀñE òoÏ“Àt@”#j¿s˜äø-™’B…ûöAo›þm8˦'ÝR_§ Ã:U ‹ Qx^¡röC¸ÚÌ„r.¤Œ¹Áœ‰§†Eš ¿»‚¹“ÚUs¹³æûÜÁ%n¹¿ onÓ麪!&w/À”­Õ ³|É_v¦§a´åªÖãk-IÕªènHB/¾“«ÐÅ@„§¡³¦ùÓÃtg2çàêA€ö>®©‹+²¹2'E³£WâsŸÙ pÀ%—\p À%—\ÂÁ㈒â‘ós9ö}û]ZàúêüövKp ÞåV£ú}6W85óz¥Ž{ê5[Ü›íZ«Ukìªfsè¢P7•] …b8§þÀ¼ªo‰t¼mƒÍ±S7ù©;{>!¹?âñé;Cè½F_<‰§RH0<ñf)‰qiôŽÛí¿¤gé.5ñ$Í`U˜Aÿ‘ÏTwMƒå°½fŽ”²¾†v)×M³ÓL_ |)ð¥À—š|)ð¥À—_ |)ð¥ øR„ÐK¿Êô²?øÛLOûïǽöB£ºG_¤'zÝ ZªŸ½f‹%úÙbÞ·•ÀQM›Dp&wg#P¨»¤+[Ò}r¯²Ó®µïS>í¤öf¥YcôSˆ¤MߊêKÑ–À©†¤¶ž°¤¦þÄ[,µx>v€‰QÅgôy<-£ùa"娹­­eï:Ûz>v(°RßR⋟!Âo®®­Ì/.ÜX[üãwCùd‰"ÂÆý]ãçâŸÜ«Ô7pÖ½æÝ¦h88F Ò1¬?ú 3j³6ö’©M¦â²fð5ˆ¼q_âiÝ@Ìa치ÀÔeÏ(( 5‡#Ž¡c†©M!>² }N/$â‹“ÒÊã!Ãs}qîM6-!ÒÉìP<_áꓚòú7=¸éG½úš’VØxµa™¹Ähc)Ä™ÆlæR¢ÞEÍ(Õ jiKˆœL¤#ðK|ȬX"÷;/g²k´ˆ¶ÛuUÍøÄpÉú6¢b‹ž#MPqôê䙸\û*ñ‹Æq–MH_NÚæ£”U`KâÅÄÏ´!‹Ixi¶U‹:—„ܦuâ8‡´Ÿ×U§@$Fæ‰a¹9ëËÊ¡«3fÈu ?X¬\Rð„ÙÌÀRŸÉ(¹lËP&f.¾qB:Et¯¬œ´²RY€)ßoe0}"SØÄ›$,S /Ö¢8ÛÖé6ìDÖ•kŠšE¬(U¸Š¿ÉQ0ÄŠôh!àE§ˆ‘!f(¨Qˆ¸?4BÜ7ü˜é7~ÌNüð)I¸×( À@ÉgäŠÙŽì¬ªÿ[f@R‚©fËfßñv-‰óž›„Í ×b–¬ÎmOÊŽ™fÓÕw¸B·XŸBOy^[O™Ÿ4¬§6™ƒ@Æ ~tqåxòþ1AA úÎu€"‚tŒ!Y¢ˆŠ#!/(ºTÚwn¨ˆ¢Ò‘C…(œ¸y$Æð”üÌÌo@£ mÐhƒF4Ú Ñ6h´A£ mÐh@£ mÐhƒF4Ú ÑöÀ(*A£ mÐh>¢¤Óh#4v™Ùëÿæ*³ßÿÌ{mö†?¶5¯•’Yì«á¹‘|þo9½[oZ.̲ÑÈ]Ic´n'i–÷¶ozÍ•[a+ù…ÕâŸÍ›ó¸ZþDÜÐN…&—<\"Ka®øÑR‹ÿŽ«¨µÉ†ß:swo3ÒV—bØíps‰êw!X¨ÑH Z£ÛgËÐîî.:RÝ"‡Bh½‘ãŽ:Ó_mÎ3SÇÀ.»8ìâ.«vqØÅa‡]<Û]œ(Iž®s[öýô—⸷ƒ*U˜<+×#Emɶ„ùˆÐ€Öúþ ‚¤lãqV˜ôX1ò×Å>D:c}cåŵÍ+7®a´RJÇŒÇÕ¹×7è›|Zž•µ̆ز”…, ‹×—Þ\\{{’ÅMÜâÕöºÎʬÒü^«ÝØöšWö¶n{m2ê›Këøÿë7p[çÌe,Ôï6ÉZXÙ Z~sei>¢¨²rEÄØk# Uí¯:Ôü£DWÜ™ÇB\[RqŽñ\c@þ 1A0”·ª,©ðVgZ8“R5vfÅ£2¿6Õ„,j_9T‘6OEŒXæ<ëe‰ +èOlpd”v}&H*ÿ‰-ÛdÏj´XÈ*8ÑÒÉ!5t–ƒ¹]r¡À\ÍÉ4Ë_Þ…BàO/“çÝäêefâB×9á(¸û5!µ•“/ÌL•BÊÅH—šˆ­}Ù2Ð- µf%L+†—d‚ärÇf厚2D_¥a")]‘1#!U CÚŽ® @‰‚i½DGA1ǰ.*Aœµ,©Ìø9 \@¸€páê!áÂÌÞ³_âz6ö}ø¦Çkú3#d¥Y¢ ?øS”LgW–½UÕ¹Gºà“Ûj;wIMf±ÀÓÒÅYÓEg0˜Õé-‰%EÎc3“SÇq~¿—–WollÊØ7Þ^]ÔQÒóöÊzŸOeƒöp¡—?AÎvO!†£•!Jä¸4eK|Q“ Žˆ°§¶ŸåŠœù ¹9ƒP`8j®ýû3%9#¯±±lò“-¼À/Òu{¦À·ƒm¸‚ó%ûhÉZëpQõ€©98§ •˜¼ÔVö[‚;6—ülJ$–n~~o°N‰>€uˆ„+×Wݤ+)ÛÆ\¬ïóà-9Yq#Vt bì80‹¥b÷›Ý6úc6&´qíf¿0®†„ñ™\˜þÈýÛ:\QCe6$ÔÇJwób´#ä59¼ìóЊ@‘!NZuÍjYmY£äÖˆê¬ïd9Ñ=6þ/E†|vÙíÑe ±Ó?´<€V…½—`áIAº-I:-›4‚dßCùÊ‚'•á’G)»c2@Ê)¤ 2@Ê)¤ 2@Ê)¤Œð…V„žþ›üýŽ=:ÍwM鵎üÓâ†*E ÞéÊ\FækÙ<ãé²ôKTÉĨÎ|B š@Sl&™‰¦)p’Š.õ_Z㌶ѳ•˶¥Žc±òøëXg 3˜Ùic&›»câ ¸¾Fá4Àî<#Ú Fß)XîÝ.ØÖ;û«Y@ô”]û¤që¼éqÌzŠ.fkÌÆJìæSˆÁ8¥}‰0áûrÄ–Îjg7ig4»þX¡»páZbž)t5€ë\ÈXŠèìeB;jdû2¡ü0a÷Þ%ìⳄf:åbŒfäF2;‚QDE@QDE@QD  Š€(¢H¼(BfV^æ÷`Ø9ÍÜizxX*ïY¢Éy̓\ìy‰Ãw9αŠ<6N*0¦3Ac‚×Ý)‚•A¤ž ì`ÉÆáÓHúB¼!<î¥OVjmç¶/zM•”#ª»²øš3ÓÓ“Å/|Ä&©…Œò–hX`’\”ä6NI/šEe0ŠfJeܵx )‚O/o²¤n²ï’6ÑŠøæWoE0cc]½¡‡²ì½c-iÊÜB¨9àu0º°îµhnk —EGÜ’‚vsþNeç¶·eŠ÷m®ê[öBxKÞ¬4kl{ÕºMûL»&²u>Ÿø´¬ád•„&®A$o´uÊÄéîÛS”¡ì,®øYºç_R" |l²²¬¦‘ïÛ ’ .G…’€V_ÿ†(…ä)Xqµ„õÉËD g ƒ)D|_Áò0¹ }ÅX} ±Ø¢t%9DÃ0¯ ¡•X…Å’ÌäÃQ4¿¢­è9,L€Ï]°›ÝªüIpCA}Yí<Õ¸¬qXå^®Av8âÁtTí kLàY^Q_ cù„¾á^(¹zÁð[ŠÊî-Ób5 Õ‰¤L*ÔLÆâ’¨c,S0CTÜÀ©”ÎØu@LÔLÑD †'}’=nÙ0üò«>u~L\÷b»æw+bè¬uí¤ê\Â䪦d#çAÎq9ÊÎèS6L[§”3ùÂöÛ¶§È†˜÷–QhGX’Ü>i¦Ë¦ßmƒr íPÊ”FFŒ‰ÄÙ¨ºe+±6YeA" ù±Ñ¡Qµˆ¦aVÛÒ5Ũ°”UV‰ÿyɸ ŒC( £tt½3þ¸dÁ;[íR1*ÙñGV¬s !l¸ ±”÷Õ¹æéš×^hT÷¶½6¼@É$¢«±´Às0kB#”Õ‚Ù¶!4X°r´D·MQ¦¶Ú¶ã˜4Z‹Õ YŒ“´wRŒÿVˆÒ©'sýj¬Æø+޶L¬ÿ ?°)Ä=j"Zu¶h“à€^âlº•oœÊYˉ²Ù-‡Üf”ŽËuznaá´SJ õâ2žß i“ÕýË|‚浈7úÕ釀¤&éuF¾bAÓIJœð‚O*DNŽÉIQ¹\î™;ÄfÇì2ŒËszóè䎣Sj–Æå0–°péd†w@UM(<–¼ÇdÏf‰ ÄarØp÷Á ã6y5AîÃÓe”‰Ó–“èÀ•åðSÖn”É \IsÊ‹"inëQÞ‰"0;‚¦êÌv;l\){77+/4c¯¶AÂr¤ÿ3ÓoâŸ5â*VÁ¬žuÍšš²ÆiyS2L4•!WÒlž ª+jž¾h'8ñÈŸÑ¡x)1V=x qÙ!™4vµ¡%Fʆ{¦ÔÝHUÏØ}~ãÖLèúc\ø4é§I›Jã&I¬\mDI‘.[ÙpT˜*—×&e~üE…zðÇÇ'Ö-XaŠ{ ¬ôsªnNbõâøèÎ+`|´÷~ÐT¬58ømˆsõ¡¯‹ƒ|á ž~ÃU-k–¤S8ï°×Ec ín¨šÄÇGhT4t vâ\e>ô‡…–šÙm'0j£60j£6À¨ ŒÚÀ¨ ŒÚÀ¨ ŒÚÀ¨ ŒÚÀ¨ ŒÚÀ¨ ŒÚŒ À¨ ŒÚÌè%Φ[ù`Ô&µQµQ[,XåÕ¹S›^8ÈÄiË& 0j+9ì`ÔFm`ÔæžŒÚ€ ‚QµQµuk|À¨ ŒÚ˨8Ê{ã§ø»Fìû‹È R_ÿSÜæ©ÑÄmÞÒAq›×#§xþïþ‡ï‰5œ¿±¾±òÆâÚæ• ×0z(Å—¯Îݸ¾A7,-ÏÊÚÂâš5KYÈ"¿0Éž´f<+Öµ×j7¶½æ•½­Û^›àÈæÒ:þÿú œÁVÀ9Ù¼Ž—±P¿Û$½²´üæÊÒ|DQåKš]¥„µ‡Â°ÒÍÞP>©´âhO(iRÙfcOèwËÝ>›tË›«‘Y¥L¦Än‡aª±4T–ŒÙ–°ïöˆª¡\œÑ¡fPØ5+A«*Ûx…ëAƒàtBë?uƒæs¾ñŸù%e³áŸ1m¬Ñ_|.“ÁŸžËjìg2E½tèÁéA2Û‹â› ˆìc`Æfy<ê‘o‹užž0þù >‹yÎyRQ½ ñ”qŽê”ã{ý¶ÀËÄÒ̸é 3³~˜˜¥Ö²¹¢OBD³uÂæðÕ׌²øHDLÈÀ„Œ3ë…8 2–ª$·bºŠ°j7¾ñ3ÅàŒ¾IÇçIšö‰MŸ?‘ZÍ´á'ËkYîîÅèû•{^~°ë˜\AqÇ\Æ“ŸBг4š/‚!§ñ¢–1|¤¥Pˆ5Uó“8š%d´N¤Y+Ò¬—°¾ôkÆRF2ut©³µæ·®š&ÙZ{‚vÖq r¥[Kœ &t!¾‡¦rѦúòéÀ2Î*ºgNk½á s¦,f —SÒÒR[…¤6´ëÈ,$Î*¤_»¯2².z÷buǬ@“í”×&o]á#3¥ÚºÌ2G Ú*KR”(Å&ܱ’±}z°]H¢ŽÞº¯ã¾,lû:Æùƒµ1¤²<ˆ»‚Ö„Pg{ŠRûC5¤EÝ4«ð ¹ ¡zX?f§:b9˜«oñ.E´ÅÊi¥ßÑBkŒ eòüâØT¯ =Ç€d¡à+XMyã5È…ÂÕ…¹ Cí­°þž·’@’õv¥½×ba©à×lë7×ù”ä3öØ©·÷áŒ/̸CDY'Í’,L”¦1--\lK#^A€ÄÃa4\1¯¡•½¶Í‡…•p-YÊÖÖ“­ ®kÊ–?ÙºÒK1¬-C"2TbKbXc–<ÚR3Õã¶ÜL9“,9™¸Nx¶ƒ÷ÌÜÈm؆m؆m؆m؆mX¶aë`¶a`¶a`¶afÐ7i° 3çÛ0° Û0° s° SÀ*ºgN{øï s¦,f —SÒÒÀ6 lÃ,™Rm]`&؆%° ;؆m؆m؆m؆%³ Cèµ/1l?p‡}ÿåçy¾ ÉÁÜå?$–«Çwl§²;¶ÔžÕêÎ#¬ M‰âMˆ®½™|*aèd2L6‹3Gã.AƾkØ,·Œ W~;³gÆ]Im¸’?ð©SýCcÇÁ”™¹"2ÄYt¹f5˜uÙ²Úl»lé£lµ"šÇQ#R/–Å ƒ¯hs®ÈŽ›ˆ…bÉŸ»qçšqTz^< ýÓØ~Yùùx&;bììýÆ`Ý2ö¤4ï ¤R2ªc¬á2Æ*øXãþÔãŠÌr™ L ‡ü©Gù<Ã1›áÄmÈ_‡ìÓË5 Þ†t·«rÅû䈟ó;EýÈü¸oÍï€üÆ¼îØ¯謩)PzMÒÖ— "Ñ`h(>aQ( Ü#’Ûf$‡G#gQ¤kúp¿8Yλú¾£dö¶¤y­‰V$Ž{C?Þ–¤#™$ã o"ê{”¦âå$–}Êhû#cl’âÑ)ªf¤·JêÄ,)»¤A¿¤íî˜\âc–ð€¥£Rô«•Aç“eÙE˜‘dPž°”Œ¥ëÁ¾ý(&;·/pp ×pp ×pp ×pp ×pp ×pp]‚ƒk’®áà®áà:8¸†ƒë>s€ƒk8¸ŽË×pp ×Ar8¸VààÚpp=„ä®áàzЮzýÛì.ú/þ!ý-·yε{Â=öüÓb¡R¹‰¾|Pn¢“ÆìíîÖk^3Á]õÕ&‹Ò–W­mWê3g§ÊÞaÿ³ßíh °æU½ÚÝö¬‰Ãs%†— ˆNsΟô ¿Wošl4Ú•:íY˜ÈÖEÆã’ÙªJma]¦'T’>¹’ì­ÕAŒ[j­î‘EÔR(9FÍ»5Lù)ù'Áˆ¸äÆSW¡Ä3"§Ñ’CLâlaÑC# v˜ %Tƒ9vàL1,Ö<”fëÐ] ƒE”å3­pÉÄÿ#í釯\CY1¶¶Ôq†Nù VÆ|6 câ(ûŒ˜ f‹ c&а®ÖÈÎðXmh{•±~u,,ÔV±y0 —bô`Q³-‡1i¼‘_†"ÒØq¨ED÷G²à° —¥ƒq4¶ E6¼°ŒBÂ’äÐð÷Náp™Žð,Iö}*1·Ö›U1Q@Ó~0B6y)¶.™6Ô³P¢íµðašHa3IñÓµ}Ӛτ`=£¤9ˆÖ3[l5"(Å€6q¼ñŒirÈ Ö3=²ž1â}IGüÁ¶žéùÓb'èï˜W&´qy$ó™ä+ Ñ(øæ3$__Mfâ±¹f2¤¿;ç®Ñs‚¶·ÌÊ„IRïCb%“8ã@oª™L>©GÛ„š&ŽbƒuÌa£Ò`Ó=óÿ}2wÒŒ¬µ²ý½ÝÝΟ¹,QŒ’B1¬•ûú&SÕñÕðµw„²³Ú1McGwÀ”Lú½ìë’"X¶|Us b#—1ݤ…«ÍêDHd„ÏBÈ\¦d†34=rF“ÙE™Ž;¥ÈÌ­Øò€-Øò€-Øò€-Øò€-Øò8h5m K- Øò€-Øò€-Øò€-ØòD¥[°å ³‚-ØòØA'>q9À–'./Øò€-Øò€-Øò„Ém`Ëc°å±fMM«Á–lyÀ–lyÀ–ç ØòçFù:ú—Ÿg¾Ž®¾\õj»mÌ7Ím7övÈëm\^þY~(aˆ$îŽ<áî(Â㎠””‚ßIæ ¨Ùx§JjâÅ›„B Ð’Ã\¶lu²µ·½}3(†ÆÓ’Uæ›·½%ÜÁ[{;f –„­Â8#––‘jÀ"¦óÇ“%ߊOÏj§'éœË¦³dn³”iµÒl×*õú}¿IlØ#!Çemã”Ið]kÕlél¨ÏË>RÎÀY‚Ö™`z鹞<åÊÁžŸ%(,<Ó 3KòXå°Îþ6ÏàϽÐ2Ò³vùé-Í Ð^h ës}Ü'ªM•.Ë80)í]Æ”c°Ôjíf÷ÝhÀÙ˜øK½“ªYáfÛð2±Ÿ>wÚb‰-P2¹øðü';<,xXðC±à cñþ§ø!ûz¿j›Çü¢f™p ÷úÅsÇ2':vMS!Fke¤[š^I©(IZ»ÊX¨Eù$ôÕªvR»FtŒÒ*œœ”&Ñê’.ÐÌ´`=Õ4éŠ0³Þ¦gãfzÅÞ j2¬"¥Å†‚”Ö›ªb×;Í’»)}Òq7•!¬o5DŸ;ÆûÄ9>+²­PˆöÆû™Ñ §SQ˜(å¬1ôEw}Sªâ^0'h• A7¤àŽOúÅ® ‚cRì­y…‰; µ\‰L†B Ÿq’4zÆ‘˜éýH¼˜ÙH˜qL ³â1X+¦rmš=Z ÚD»nV)±‘¦|rrµ…¡¦ÏDc¥_<‘6Ž¡¤þ3•ƒù“~8:lº¯Ôz$ª㉞ LFÊ;Ržf£ê÷Yjª"44KÖ–ø®’™ü¬4°ÒÀJ+ ¬4°ÒÀJ+ ¬4°Ò‡Ž•FèÉÏóswöýÑ˶ãM/.ÅöW/þ«E`æ{ËÌ7Ü|oÆM"3)y¹ ¥ÍJQ\®’4é+Ù2í½îD ¸tàÒK?Ø\ºBT=’îÆóæJv5Ä•%¤k7îL™»ÄˆKõSF\nQ·ÕÙÀ 0pÀÀ pÊ’€8`l÷†&Šç'ÞåvÙìûÓ¨[™çŸ¼f´>ï¯îy8oà¼ó>œwÔ¥ÿxž;¸6,·S¾ÃkaQoúG4Yokìïî4´\4pÑÀEl.:‘‹„8Î9ÚCB$·l¡Y®ºÏ!û5G8E(qšž™^¸SàN;î¸SàN;î¸SàN³àN©’ö·fßÿG×jo¯4·š×wðÂðšÞNÕkå?Öfˆ&ÜëTƒKö½V»±í?zá¿§aÒÛJ#¤$(^AH~âcŒÑêwoù.¼m·×_/±·éÅÇS"r^ -ßÃBO.¤ ¢´:¶À<#Ei›Mפ²[!‘¯G†_:v0Œ¼ï0è†L$Ô?Êqîøj]F:i;ʱÙ#‡739Ö#¬GXY¬G¼Ñþ!?#eߟû!º¯úM½²·uÛó9qÛ5D“m·¦n»,AÊ}7ÒGæ]+ µ3ôõ#¹)FMSÖd#`˜$'d§Íú ©y”™ó‹f⬹4I #‹˜2ŽKFXCµ³æ‰c.÷”ȈgÊd/0:w$ÎÆW‰ðÔ#°eD¥÷´H%/rÓÓç§§gfüÉ´<ûæc‚ïüW¦`Jweò¥Ž…$e‡5w6õøg¸‡Ãú…õ ë·ë¡©—±Ù÷Ÿ=võ€?ùd»}?ÿ!m×—âɶ¿’‹°—R{2ÿEV[´ÿf¢%V}™Ð)]Ù’.xa“Ä\˜”‚G.ÅÈx6fÉD½1ãüýO8GË]RÓ™ÇNK7ˆÑ £©ePFVˆ_bóQÒŽù–ZH.)±þ”›#µ‰vHV’Â4ÁŒÎ–¦ýe*i„#=8dÑ+£ôcu´ð+$zwÛÆ Žøô¥L7 ®Ð(oÆ!T>ÖqnUÂ–è¬ %Ãto Ú²*~¶*‹Â²²HmçòË5Š»ú!¥œ)zßèG(&ëO[ÓF¾ß햫씋ã¦Îšk^šqIԆȫ2jõ‰y.N0zþ\x·pUó'­µW‘S®Ø„kƒ¿|Ík/4ª{ÛÞN›’˜àE’‰k‰ŠP±ÀÁòh|D|Y‰\7†ïn‹±Òz6ÄZiÃÀè$j[Õ'â…(ùw!Â@Æ•xqãP¢ä­C‰Ô6ÉÍ›Ç HxGÞØiyÍ»lÜhYê8:!‡0!ñéí’*oÙ5¯³â³±çØ’ª˜ŸCæ*ÜòHï†]5p(” …´Dßjg84&¯-äêÊ]F…NÊE…N G…JwBçòƒËq2;–– X6`Ù€e– X6`Ù€e–­‹,BÜà÷ÿÙ÷½_£Êµ¼@+Y­Ü'ÎDó'ƒù!D—úUþ µ†GÔªñôS´Ö¼[{;Ü¡µ;·M;¿åUkû'fÎN•]5›*û¥Ôü±G-ìk!4û‘Z´Q¹Y÷äf]²%õ¶wKÖ¤6Çg[òp©é}Ço®VjÑ.ÊY¢f»V©×ïÇ%'Ñ.=å³ÇRiÇÙËé&›$% yX="‘Êæw÷·¸PvöêuîáÛ€¡³n܇‘Â,‡l^«ÊJÇ\t.޲P^5ˆ' êb“>[:{I”pb¶T6ÞJ÷û‡Iªß˜))”5\ãÍ“Cÿöe¯¤îN†}ª¢°Ê¼B…[ûÁ—€R)LsÒáedqÔ2­²“k^Õ«gr;wµª×:Îø”1^@2!Ôé/å?eL™ðKåFÕ2ÕmR«“v‘¯ºaj©#‡†gŽê Õá*Û†k¾ÑlzÕ6®/nà"Rf0„öÒÕÁŒhGä°FäK8À…€åÒ7QÝüPÝ‚UƒR43¤<œL„fJ2Ói¡ajÈ †õ,ðÈ"síX⋦}ú L)è‹?>Æáì®,D}ÖØüÐ}¤-—Zý*B‹ÃÔs_0§—ç§p±É‡·ßo_!4‡-¤œm±0±ë·‡mƒßÍDÁŸXµÀWEÎ@~€s¦Mš”ÌðÍ”’Åæ3¶í çå. e D0.éa¤ú½£s¤%S’]Xôö§u²}ªÔÑFňC!^Ô+ø#î"åù˜Be<µ5²¸Wg+b{”¦+vK &.bkI1…N[rüdºî“Ú´¦Ü(»>ÁövÙ¦º ¨²;†9äXcAŽ•ˆ&ȱ Ç‚ r,ȱ Ç‚ r,ȱ ÇvMŽE•/óû7ì»õYZÏÚ=¿¬ë;ëÍ*yV3ÿlÐ=’œ&oæî ›RÒÀØL 0&º±ÓôÇ·¿—yžÊÅl“[ïĹ¢X¢óDº½î5ïÖü¥¯ ÓgΆÝ40ÚpIìO€:ËNIƒŠÍšTˆ3ÙT²<&Cƒ(×lj“ý©:ÆÑiÂÁ<‹Õéì,VCŠ©]­8 H‹‚¨¥-!RxO¢p>âSÚ\æL¯†S£Ö6#`+2&HÛ•Äkù¦ÝH¿˜¯ªú**ÿ—a“Yhù”q)&²fµ &±nµ¦µ caÈ’Íå©PÅGÇ›ˆ ÉÀÕ‡èÙ1Û«®-˜¾&‘-±ZÌdö--ËÏ4¶ÙØèv½úZtui,ª5É}¢´Çñ“xTøXYËr\>“xý¨ˆoÄSWc)æâ•PQÄ"~\!“ZŒ‚+1÷#C»2*nÔKi~§”,z|&#©žŽ_.C7w‡¹Ê}A.u›P!ƒ'z|2B.T²$cÝøœhE$›oTKÞF•(E7ÑÆ8îÝšwL£xÌΜ-³r¨<˜÷uùÉØÑTAëRta¢ÔoU.Äj»u!ëëŠqºÇèÅnŒQL¡¶1ºØ…{c¼<&Èqõ¤ÊÈZÆÌî80<šàü¢raaIg-UñüÆ{ aÃÃj’Ü– ¨•Óõ´ ¡Ã™€®Ž§Ç¬UÊeµ‚X¸íº6¹ò`Ç]ûÓ5vž‹€–QŽºhcq=(ñ¯i~òúã"Îà¬Îà¬Îà¬aTtpÖ0 g ) g pÖg pÖg V,䂳†œ5ÀYœ5ÀYœ5ÀYœ5ÀYƒÉñàÔ—¹¿AöýéÓÒ×÷vwë5¯¹ÒÜòš¤Ÿl·ïç?ôÐOn‘¬Ä¼ï"eL}Ë$úŠJ¦wP>¹WÙi×Ú÷©Öþ¤öf¥YcäKˆt¹9}iän¥Y½SiNÌLOOßzÂv’#¸iÀƒµe²Kj:óØiÉâ1:ƒñiT%ƒ2²’ƒ ѵƒ¦¥Ïëc£×6%¢ÕÌß©ìÜ62·µµì½C«²”À^UZ©oi‰ºxx“ا¸0ù³‚^4Œ ”¦HƒT›¬,$+„i‚½Pèê{!&œ1‹21b”>#b¬Ž~…„znéúý‚:â¾Z_?_ \ÏôôyÂöø\O!ѹ Ÿ!á4IRNM§iU–ê8‘ Kj2î=D*E³*¢†RnÀ ÉT_>”Lñ¼‘¥d”xS"‡dM«¢Š\e§\7ý”Â8šk^šqIԆȫ2ji£æ’õaÉ÷¨1,a¼÷“ ëšO8'i-ë`'\0ós¸ܤk^{¡QÝ£þgÝ ä¡ÒÈG€€ŸFÝhd|Y‰ç“l ø)VZä†C+mhDm«Œ–R”ô(¡a íJ¼¸›(Qò~¢Dj;ʤ(¦šv”à|š£‹4ˆ,êH:¡‡0%ñéíS’*oÙ5¯·â³Q=‘[RâsÈ̆[ž€lCÈü¢Ð•Ø&?=xîÅ7ý‡Á_Œá6ø‹1à/üÅð€¿ðþb2ñ¸þbìí1hý¨ˆþb ¤üÅDŒø‹±þbÀ_L’ùv@µäm1à/üÅ€¿˜ƒé/Æ€à0Æ}¨;æó“É<œ6Àiœ6Àiœ6ÀiÃ(éà´a@&NR6Nà´Nà´N¬0Xȧ %8m€Ó8m€Ó8m€Ó8m€Óóý™-î—ž}ÿðó¬-¯)]þxFèG®~¼¯~°vÂe_.~üßG1d³¹p:ˆ‰Kq~’#qøl0Ö4ƱJG/pô’|8Úl?x1¢aöÇ.ñªJe/1**…Uç-Ý8o¦I€³–”…³–®œµ ×Ús–¸8g‰8g±ç,pÎr¸ÎYHFËQ‹(«-ânÈjôcYZ2tñY¤²è’½EuYœíØà\ïVbÇåÅlÇ%²8Û¸œïÿqŠ*”wz˜"»©š¡=HQp¡ßÇ(²Bφ±Ãt„bà;@ÉæºœÀœÀœÀœÀœÀœÀœÀÁ@.8#(ÁœÀœÀœÀÁá:#@èÄËüm ú-Œ<ÜZÚYðê÷—m<9w÷6iöj³šÿëž-žÜµøŠ¿k75p® Hu{»»õš×\inyMÒŸ‚~'ÌRþwŸ°q%…XÁt‡é Dkv|®<’n”8WmïqJn²ôUk MÇ•(¨‹ÝJMÂÇÑôIy¹än¯YŒ.ݼcK¥š“öÉLSeMe;Kqª¥lÆù5ÛaZ˰â‰lc™ÀŸ¶8k‰ümË1¤ ª;’P†²zûn0Ú¹£³‰HS%Zèˆ3$I&D˜Ò0‘½Žvºâw<ÉéªYÒR›5¥D©-õÔ´0¦ìîñÒ [id­@6‰=˜•Ø+ãêÓÖ~ÈÒ_ŠÈnDiûÅCs67ge\³+7ï'ÈL …‹ƒròXÿ+æäæ'¬Ó¡±%“b)Åô›ï¯÷}"Aï7äKj©AÜGÄ\ð¤\pŠáRݾ8 WÌ,w6\ån W¹ßÕ0 s›ãÏe¸Ðs˜Ñc2¬ÖNÊ"9D’•«Íñšmë•î e+bÀeËnˆÛC†Y¢v0Ú~æ)VØÁ8øPÛnârYËœ/!_° Œ7ÖZ¯Ú⦨µwé, ˜EÀ,Æ­1`Yf˜E`=€YfQ¬Ý K=õKüŽû¾ñÛ†ºwé¡Aþƒ–¦±h¢Iý‹h ¯1ýÃŽ¹Y'GèÉl¯í«üÜl‘´XQñQÜ ˜t_ëâŒØ¸k{2‡›ëíJ{¯åƘ‡¹–Ö7×ç—Þ\\H‘uàÒÜõ˜"zÆäv›¥ ‰m×ìN½ž-•/Eg’žUâjÒ#RûD^æœαUºS¾Õa›VÅ‹æ:è}û †*Ø~”­'LpfÕÛÙªíÜhÓ¬cº•FZd.¡UbÉ¥eçr»ìXȨíV!V¨Y öXIn•£TÙT‘þŒS)„¢i¸DÃ9: l¤f&ÅóÄôTY§‘4]ã3«hý>>| cz\W¬uÿ˜u£yþº&·÷;)V)N%ERI&ôibMÐ'Kh_ÔÜ+¼+Ÿù¨¹reÜ£×¾-æ+UHû2Qb]Y$[©“—šJ˜@` &˜@` ŒË L 0Å"„N}?·÷dß›çp-K­ÖÒÎÝ*©d~¯ÕfšÊð6˜bC_Êë½fÕë»zò//gZÅƒÚØÎ€3÷ rçL¥Μ©ž S‡¥õõq|©1#§VQ 6WªL Ì•F VÀ`Z*ƒ0¯À‘z-mÀÔ­FO`æHÒÅp¤†Ø>$Ge2äILJjèLJjVCe>ÔŹ3Û<ôrtJ!dÎ}¦éŸ>ž¸æaL×ãøÌYqŸÖ=bÖ…dYxϤ…J…Ù9O)o$9ЧHà—2{çµO|Í4 Ÿ}ês²‡ÉcŸü^iZ}Z)A"ËÓ¿i|õé¯þöÀSŸ'/ט4BA‰…´(j\þ óÄៀICìîO|±¼t1ÖÓŸ–í øùë™9‡ÇÅÝŠ°¸s*j¨üûõÌcìÔ¸á05à×/3¿~Ú>v ü©;ºé©6>Û’'ì…zc,bܬ**qW€w\pBëi‚Ök ÉDÅ­®³†º„‡í @_*±0Ñ1¿óbHº Ĥñohe}˜×ˆÊPÛˆ q¢×JÂõb'‡‚CõT|0NN(ƒúæi{åŠHð$á~'l´JÏ(/sVBH§|r‡ž5­U¬cÆ.9˜ hp@ƒÐà€48 Á)E®\Ðà€'ùÔ€48 Á hp@ƒÑÚ ¡|›ß¡dߟ?¹µ²×¯l†·)ý'4lñÄðéºÝ§Äñ"Èšè€m¾“m¾šøÊÞÖm¯mJm/»3+þu‚ÌémøWqö¥åkIzg¯Õ˜i“år«a“62¦ä>^'p°îŒ½J ½äÃÄ>ÇÆ«ʌ̖Îjç3@ùk-rÅow™PÆDš“{GËJ¿fÕJè>R Ž¸Õ íé…¹¨K †*"¯5(Œy7ï5(<¼‹é¾ª¼Hz±A؞ݮ4¨ ·û ¢ÞÊañ?ãÂèØûàƒØ»àCÝrºÉÐQOrï2„‹ÓpƒAZ‹i¯0ø4•/Xr‰¡£r×éná¾ú£W~º+ Q3n¾Ã9?¬mÇ ¸x'ôþBÈÛÓÝÉAÈwßÃü]ÔßĈÊ_%g,…¶ 9SHjEÓbÕÅ/”ªilL5ÈšÄ\1HQ(èϲëj(%^ ÖËŒLL?¬×FÐÜO‡>f„ö}À{\i AK ˜uH„ Z{!H„ ‚D!H„ ‚D!H„Fœ‰p$B„Žý÷éÀ¾÷×v·ÖîùƤÚÖ‚ü3¬Q¦8rÈùŽÛ!gö”o±‹£vaT ·¼zí®×¼¿¹ƒ;dJ¹´³K烦"½6‹}ÖäÔÊò›+KófGY äÞ^È:2ºË£Ãø*Eõr¶Lq/± ®`ý©OÃlúiÌ;EeÊb©_'¢2i±d‹¦0¥äî½bG_bMJ‘5X|EW2£TBwVâi~‰Ãµà–T¯1Ŷ‡ÓJRƒŽhdSýÂísëÏ«uìóë0·¥Èõ$ïÒ¤9m&ªL· ½©âV!5ƒî™i ,Y² dÈrFd3çÏÿ.·Gdßÿá¯(U¬SKGî‡ÍE8õï?x~ØÈ^rï¤mß;P·p¥4ë .Ë6½ªWËüº¬[©Y_˜•2&ã¼-ë™]—å%vtaV9å]’—^Žwk[¾V”nÖÚÚ„Ë][-Òß¶5”$³Ì{º·úL;ß¹Õw3·û¶Aä!¹&+M“墬鞬„ý¿)›ö¢¬Ô ©Ÿ±—eY{q]¶«·e{v%S¥FÚcÖD"¬¤ª'·f»}i¶g÷™fÈ}¢f¨'—gÚÝYÓ¥R¾¥Nån ö…YS׬×dåùeÈàÊØ±v¶Ö›U1M?¡ÊT“Ù.åÒ~&iÂLpéÕñ®Î6èp•Ë·É.Þ:\º•Ê·/›Rê…[•И)P„+‘x‰-Lxß6bmé]·ó ¦î ËL‚H¦"éb3öß骭yý%S ­»]R5âåiñ073µ=¨/@}ê P_€úÔ ¾õ¨/@}ê P_€úÔ ¾õE×ÔÄ åÔ¯qtöýýO©îí’aYmVó4µ'ˆ&v.ßBN†,™Zª‘ØÛÝ­×L·‚i ƒäÞ‘½É_éøíl O6wiû,ŠÞ5:È8]ÜÍg-[2ŠÞ¢k²¹Eúd*µudYNYbÞ _öå*}0¦,VlõÒûFCõ!‹dC!™Æl>ÎÊø)fŸ”Âùiqø²œš7@["‘©ÍÍMV£CB;J“b)+k ú̽ŽvÚï‰=Ÿ5µF)“w%Á`‹•‡¦”b¤Ê‰G*zv;©rwFªÜß‘J–ãÕ׆e˜rxñb2žTÇ›*cI€q¯Ù6VÉJ\`é-ÎÝ[ö<Üú3̵O1|}k+ìd xƒML‹n¯-¤OÆØŒ$cnµ–ŠŒnØ^iöÇrÀå—\pyÀå Ân\^fC \py€ËCèñßâwòØ÷?Ni•í²>`nÊnð^ÀÜ\iôæ>Û›sž}óöØò'´co3¬Þí©ý7ê¹–Ö7×ç—Þ4_LÉÊ^Ù‹è5Cîî6Q™89•[o%¿‰ÑcK}'fjFd½á§P¢(Ñe[ï„G9)ÔÊ×7Á‘œyÓˆóPèNóPhÞk"ñ™7g?|ñè¦o0º8)ûÔS(„I‚”£T)Qû¾Žˆhu'û%ú¸%ì¼Cú ì…LÌ…è–? aªpˆ.e§4ƒÑ5.v¸[i¾´}¿õ'ë/Ýñê»›x ¼Ûæý3o¼½”Y˜=¾pnš|g.ž—¾ûŠff.”§/â¿Î•ÑôÌùòÙ2*MgÖ‚À¬M¥Y*¡–·»ÛˆH?¤ðÞ{Gs(Ÿûô´…¾‰òÿÿ¹Ú·åÙ÷ýMPÛwÿ†©xüréãþžŽF”ß&Èùÿ´)¿(ÿC§ð¿#$fìHž—ôM­¢Êáðqò¿ñÓ ËdäXí8öŽýMtý7¹çüÖ?ä}ÛÈʧ1äý™{àØp€L ¤ÿTi¶0åÏzW‹¡ÿÓ:ý?7}á"Ðÿ^€²ÿ·»µj¦›?J³ÿŸ;ö,Ì/€îÿ#¹¿|H÷ÿïcÿpùùü"¶ÿ‘rÆÆò¤´|Äþ_$ÿ+ðýTˆ5ïÿ£þߣ¬±Ù¯àÚ¦ÑßfÿÐSšÕKö÷ã#cc9*£ÜÕ\x8Ã?‡ÆsŸÏ­Ó &á1îs~KHÈ×x–0ˆFÑqöë÷Yã9úeƒŸc›„¿UŒúIÆÙç$û”Ä.çXY¸ô]fŸºÌ>Øïf¤y^À!Eÿÿiïþ;æV¶l`Šóÿ™éàÿzþùÿONý?úGÊ¿S¼.‡ó]ÿ}þoÖ D†¿ÃäÖß÷—ÖçÞ`HõH?1 [ð:éžú1)ùF"5¯Õ½võ ȨúD¡ÅüKAè*zÒ7ݪ¡#£ùS“ÎrÄ(zL2¤Ù¬m¡#èÑš`ãñÝJÓÛiK±GÑè^³ŽF;rQí ®5ÿBGŽ|â!µ#ïေÇqНãüGG¿÷Aî7…ûjÕL[£WºkdJ‹ÿŸL]@¥ðÿt¾|ìz‚ÿ‡Êͺ×ÚÜmÖîfŒ)æÿâ Üÿí ë¿ÑêÎõï4÷¿Ï^€õßðïÿü‘xÿ{ýÐÜÿÎý¤üÚ?Ab¸ø¸Á'§ÿû3h<÷£Áýïwyí~»ƒýU¹]ï²ÏC)°O€Ã !ÿGüùwÁù/ŠçÿÉß*ÿwøÿ^ÁË2ß•o´Q> |âOï—SwÈõ2¯Óÿþ¼c][¼ÞÖ˜çT^2,‰Šn/GåAkùÿxâ½Ü÷Œ6öGϾ<=½0svqñâÙó‹ çffæ¯ÌŸ½Z>{¥‰¾ —?Sszÿ—Á'ÑH>Ùýß“ÁóÙ›dDÐtl¾ÑlzU„FOž:…¨–—>Nîù;vŒ¨`ž%#ä¯RÀ~˜;{uLhÿ³ÛlÜ«ñ  Yºÿ³ÿ™™9§¿ÿrüÿ÷Tÿÿ_üÿßìÖy÷ÿ_â`ÿ0øÇòýûP}#GŸ-}@½‹ò~…ü1Füo,dôÁ_αôûÔVhìÁK~?´ºÖ¬ì´M°è!ì'÷ö0ˆ€úÝ€C[Ù0Á @zø¡|Þó‰-¯Y"–"÷KÄN¤V÷n“µ9t}ýF¡¯æçý°¿Ÿí>‡Æ&³ÿ9òz£Õ&>ÿÉXa6ÿ‘UjX³µIlãÚ‚ßÄá"GÇÞªµïlÞ&ºT@ã¾Qq£¶íµÚ•í]4zäï2ßÌÞ['LO£_ƹò.úß„€£àTeãŒËåÐ?ɱ»FÄIqaüÚï£ÿVHQ,>þ8îéǾ؉}±ûaóPÐpP :„ö_;[77oÖvêÛ›µ-ï^v¾àcü•uÿ_ç/\œû¯^õÿžË½Cý¿Ђg#ý¿&¨-Úÿ;Oè÷=—¬¹iöÒÓ2b>ß’ˆ±1Ú}RÒSZ.“˜©Ä€¿VÀ6 +ÐNdÿûØ<59 ¶¿ˆýïŸF_Aè£#¯â_GÐóè##¡ýïŸNmÿ;²p 2Ì ø(:¶Q¹Y÷6w*ÛGÇÙ8²ŸÑÒ·Ä‘16þŽ\(þKໂïÑc Ñ_ Ï?DTgãˆïGFB;ßâñùÀýGãùÇPîŸã†¿ 7™íoØô}¡Ý‚•¯Ðâ}´¿îÕ½j{içmïßØÝª´½ý5ï–×ôvª^ ÔEƒ¦÷_Û‚ÿÉû»^džÀÉí/^œûßžµÿE¹ÏQûßo0RóÜpÙÿé´å#Ê?bÌ¿ ~þûÏl¿Qšù?wÞè DØgöHìû3eeþ/L—áþ_Oà½\Q²ÿïåŸCßþ7x²ÞÿBÈå¸ý/üGrèÊåq0ûè;À+Â'Ùÿ< ïüz‡˜?ä^BCûßIüþGaµÁljÑtäj­îaAvÌÛmTïàªÆkôUŒGã{ôeŒ* ñ-¯î‘?‹¨ØªÞñ¶+Ý-œ:E´2W.ãvŒWlG>±OL2 8ÆÆp ª±ñSÇ ã$ài! @žŠE0)ìóöï“ÆïÓ–ïûÍÞ÷Û¼ï7x?h-(ІBû¯­›™þùcÿ7sþ‚jÿW¾xìÿzûßãJÚ0åi÷» ½„<…\Þ‡þkhçíû7‡±åéÀ0oý^ï*˜üÿÖ½ÊîfË«6v¶:~û‰@ ý7¼ÿtáâYðÿÜðßúôý§¯vsèÞJúöÓ#Ê?òöÓ‰ˆzû)'¼ýTä/=‡µóïxÂÆôÌï?evõƒBüýýý‡¸ÿÑx/W|,¼ÿqý‹0*?Üÿü¿]¹ÿñ÷?†òvUïÁ„4¿þ&ûóDtJ€¯'ºÿqì3)Õ·»×¦^B¡?ƒþÿõ/Ð\Þÿø3èèX²ûǼ»ÞN{“˜S¢#¨¸×òš›w­6®¨Ø¾Óô*[ÄüQTÄwqþ1Ž©6¶·+;[Ô;* B¥y{o—ƒF=þ81.{ ½ŸÜï@èHq|œXe¼¾p ¡ÿ@ÜÀ#“øìeä»/‹Äª-p?þÈ•‡Ô¤œÀ….㟠eì‡ÞZ¼4w?hë¾ØÐ}ÞÊC¦?:@ÚUõ½íÖæn³v7³ß¢í¿fLþ¿gÀÿoo€ÚÿæsÿŠÚÿ~›Ð•ZgÖ«Žö¿I®FÛÿÚ€§Oh¬B.Y{G>*ÿ£vÂÔ¼—Û ŸD#/«¹pÔ‰“$ý±‘—rë¬ ô.¯ÝÉ¡‡ø¿_•B0²çöÔ4¹_PCòžÜ›wÙç!ûLK¿üϨ”àPB¨ÿ¹µ·SÍøâŸ1÷ÿ¦/žQô?gÏOÏ€þ§ð^® ½ÿ4z(È?GÔôþß:ãï?}Àý?€Á‡}ÿ)Rû€Üƒ<³3€÷Ÿ²†ýn9™ì ~7à°CN}ë‘þb4ÀÁ?Ï%¹Àñä–×,my·j;ÞV‰XŒ‡‚ZÝk^×!‡FÑèûóÍçÉ=»ôßzMvÿïÈN…ÞümzäÎßÈVEGè½¾Ñ#ŸxˆòþUŒ÷Ö.;—C_Cèm ¹þ ÷BŠ£Gž}7 ÏD¹?"7õHñû¸ìý­ú>½„‡öùDìWnßnz·+mÏYoÿþCçOżÿ`¸ÿuábù,Øÿô óŸ¹Xœý×…‹ç”ù?wþÜy˜ÿ^€jÿ5F ö_ÿwnÿõ,û/€Á‡µÿ"Nbû¯gð°ÿÊèHæUžcýlÀá_KdÿUܨm{%b$2Ì6_"ä°L¾AoÒŒ¡µÿ"¡ý×É'³ÿzd#0¤ªm¡#è±-ɤª…F)’+wèòúñÏ~ä±ZïxŽy‰eì«ì£ý·÷—³QÍ„ö?»ÍƽšøÿîÜì+€û¯òùóeÍÿ7Øÿôöëj¥N¼ý§¸‘Ö/h6ÃÔÜž@®ß èÜÿxiy·Ö¾¹W¯÷»-‰V‡Ã„´ý¦ôf÷ÿ­›Ýñþkÿ‹÷ÿ ªÿÇüý¿ Ûÿ~-ÿ«á3ù%Ýÿã×òÌþ÷%ö¿ƒùQ„N <úùÜ ü?¾‹ò~…9‚yp7G_§Áÿˆn L„‰O°è ½cÍÃ9TSøïê/Ø9’Äþ÷ñ…J»r³ÒòJÄJ´V÷n»!p=‰þËÜÿŒ¥‘_Í=ÓíÿDîÔã ý?¾ÞhµÑ4²p—u„hGÐQt|Ý«{Õ6µ®EãèøÒ÷Ðñ»[•¶Ç~Ññœ˜ÿ<†ŽÏ7½ ö8*.4»ìÇ#èØµfeÇ/çQtrÍ»å5½ªoÇ‹N cK;[Þ=öë$:6Wo{Möë1ô¤_p{{wÏkݯâ}è±ëê§Y_Ðãè1?ñÝš÷ ;…N¬ßi¼#„޾*Œ>‚~E8BÚñ„€1’âW…€}‚üû 7™RPÀù}á÷lßP}_ÀóýÉ÷C ßWÐ{?Äíý±÷X½¯¢ô¾ŠÏû22ï0y_Gã}'÷C„ܱqí/ï¤3…ÐþïŽWÇãÕØ­eþ tŒýßÌÌ´jÿî°ÿï ¨öß'¼ÿ|ïLŠÿOnÿ(ëÀþ`ð!Ÿ'ö¡ÿOüßg.Bçùÿ²ð 4}~¨¿m!¹AÚ`ÁÁìÕ°ƒj¡x¢Wè Ð%¸’ObÿwŒ‰”¨‘ÈÛýqÈaÿÇÐf¡ïË¿„†ö?†ŽŽ%3R{44¤a@ÙƒÐcè1Q­´½Ûæ}wßòZÕfm—¼ÞŒÆÑ¸w¯²½[÷Pî5ëhôÑbQ• ò=…’¤©Jÿ{X`=väúG½äŸ#Flããè¿AèäÂ)„¾CŒØ0 ÿ^(Œ~ïƒÜÿ$”±/µ˜ixÔ¶î Ý÷[¹›ª áÉÿk5ðþº”eÑö_3†÷¿Ï¿þßzï½w4‡òù÷£¯ -ôoˆñs­Ð(ëÒÞ÷ýJ°} ïþ S9qÀÓ/—>~ÏÿsDùí¡g;ç6¬Éÿ&¡Ä(Ž3C¹ã(¯µáHÀáŸFÇòܺßÞwy ür¹¡¯J!ás{ôÏçÂ4¹_ æ¹ >\FÞ£äУ£ýÿð.ò¯‚Z~ÇÞ’ûû.ûô»¡ÃðLQ þÕ¡ö+zIôþÓ yÞExûéR©ô†×¼ím•Þ©µï”¶†ïu¨<:…þZî±\ø“¹BNÿ©ÚáûOÒ»OGåwŸÆåwŸ ò»OEùݧcâ»OÇ¥wŸÑß}zTz÷é„ôîÓIÛ»OÞ}zŸáݧǵwŸN™ß}zÂøîÓ“Ê;N—Q>—ð¨¤/=‘G™î ÏÑ—žÞQ_zº§¾ôt_}éé3âKOäa§_z"¯#ý¨øÒyØéO‰/=‘?¦¾ôô§Å—žÈÃNÄ—žÈ;NF}ééÏŠ/=‘‡~\|é‰<ìôYñ¥'ò°ÓOˆ/=‘g›>§¾ôô“¦wœßNÃñnSV ÜÿÇ5ã )ü\ûÏÞ€ïÿ#Gï|›XûHÿi|¬ËÿÜ|Œ2ß?ŒŠù”¾?„4Ì÷GÎæéÓ{åéÃwñá_OÉKù>„úŸ­›™;þð!FÿcðÿQ¾xñ,èz¾þg‘ê~—èòhª^æz—¼’%/ëeNùÁ#»ñµQýϸÿÃ×>ðŸ']üõ>ø÷}C[sáïqä¹_•ÿÑνŸÄpÏ8 —`$‡Nàð_D…ÜßI©óaž è(º”Ä¢h On>CÏ£Ü÷Œ¶½VÛÿý%¿¾ó{Øo ïdsØíXÞÿÊÔhrÿçÎ_ÿŸ=2ÿ»^óV£¹]Ù©z›­êo»òR¦u ÆS›hþ§Ï¢ÒùL[a˜Óü7ß©[ëÚb«Ý‘cÐÿŸ3ÓÿŸåéóàÿ·7ð^®øÐÿçIô3‚ÿÏqbîJý>Ç÷HüNòðÿ 0®úä»îC ïC«‹kWWÖÞ˜[ž_Ü\Ÿ}ñ9óH0,p!ŸÈ׃EŸC+‡ÐÏ䮡Äÿ'3„ø:2šÐÿçòÜ‹èzråÊ'ç76—–×7¨Ü~eñÚÒ2Cϼµ¶´±¸y}eþ{6¯¼½¹ñúÚâÜÂæÒ:Šž †qó+7–7ˆ‹Ëô–Ëøß‰ç:òä©SÄÇã< ÇcÏ;†~*‡ž}€Fˆ‹Ë'ŠEôÅzæ²°OÚµolÔ¾µEû¦æ€Žèà€Åþk{¯íÝËÈü+Îþkúâùsªý×¹sðþsO@µÿú nö_<쿆Àþk€Ánûu¼¿ &øvî°Û ;è?Ï!ôr3AhhÿuŽdlÿuÊdùå`áuJ±ðŠ2è2™rûo±ÿ©6v¶²2ÿ‰µÿ¹paZµÿ)ÏœûŸ^€jÿóçÜìNó°ÿȃÕÏ@‚ÝôçX0tð•Coÿ“GŸD_Ê!ôçr B‰ýƒO¢‘|¦ö?ÔЇY\F‚¡Ï †>Qv=™÷ßbÿãÝõvÚ­Íw*5üßê^³‰¦¶бÿ)OO«þfÎ],ƒýO/@µÿy­DEÙÿO3‚ýÀp€äÿL€Ýfùéþ6 @‚ÑÑÃnÿs=ûÙ"B¯ÿaJìØ›§sLfÿS úA…Å7—7Èßcèû›šEG×Wn¬Í/¢qt|céŵÍõ¹µ TÀùéÏÅåTDÇØ·æ–6pƒÆÖW—–×Ñqô¨oäﯠã~-üÑàçÆÛ«‹è„Íé$zlyq}ciùÚfÐÌÇPqïàsK+Ëx3?¹|ã+¸+W7¯¼½±¸ŽGcW¯Ï][G£ÅcÇÐBÏ^FÌё©S¸_è  ‹Ž-<È@¡¥ÓÑ£¯?D?Cè0~gYË£+ü,…"ø>! x ÜŽ‹è‡óè™~µÇ{ˆvòa¡ŸGc/„Ÿˆf aÀ bqõï ¡ÅÕÉÇpÀ(„µþ§ê›ÿ¹úæãßÝ…½Ô‡Á;ÃŽï?ÖvZmŸÊ X¬ý—æÿ«\¾pì¿zªý×Ï ¢¢ì¿^à`ÿ0ö_Ãv«ßýmÀÀç½ý×ú9ôÍ£ýüÑJ*ÚKhÿuuéúbðü£Éþ‹¾ðxT~ r<â1ÈBäcE\²üäƒÜȘbÿõGû/ò:äŸÆÉëQ(×!ÿª°t Þ‰±8¿Á÷×GÐq?€þhðsãíÕEt=éÿÄ™7è¾|eñÚÒ2îùcË‹ëKË×6ƒf>†Š+xŸ£ïR¾T̵Ðãhìêõ¹këÌïØˆèw¬pêîWh36F ÑÈ}@ ÑŽ}ý!úéBü€qbˆ¶–GWøY Eð}B@‘خݎ‹è‡óè™~µÇ{ˆvòa¡ŸGc/„Ÿˆf aÀ‰'q¡ÿ®€æyKO’·4ÿC!¬å±âô4Êæ¿<¿y¶¦xœ´ãR1l‡æMöŒÆf{_˜êý`ž÷×gt†÷¥éÝæv_˜Ø}ã¬î«SºÌç¾2™ût&Aáw˜!ÉûŸ·ë›•zÂÇ?Q¼ÿ·™óêûŸç/–/‚ý_/@µÿûE·÷?ÁÿÀøN/@®°þßЗзrýbn# ý¿})±ÿ7ÑÌïˆôäç˜öäçQíÉÏqíÉÏ‚þä'1¬“]¾:…~\xsŒ<×ùõÉÏŸQŸüüYõÉÏ¿&¾ð ïz°Øµ¼öÞîfµ±ÓÚÛöš­TÏ~cÿ5}áìyÅþkúÜ…³`ÿÕ Pí¿¾FEÙæ`ÿ0p ì¿rQvQÇúÛ6€>Á_Ívû¯<šGÿÿõ5tÿ!6‚ý×<É'³ÿ:â[~/.Ï]¹¾¸€F|â!’ÌµÆ bh1>wåþˆ˜Z±‡5Yú}´ÿöâúþòJO”2 ÞLm”üýÇ™ó33`ÿÓ €÷ÀûiÞ€÷áýGxÿÞ8œéÿ«¶Ój7÷¶‰)`'Àbý]TýÍLŸ;ö½Õþï³nï?Nð°ÿ8Pþ¿†r‘ÌŽ÷·qC ÿõ¡÷ÿ5‚®£ÿËÜŸÍ=aðÿuŽtèÿk /êLy·‘8ûñ\èll |6gó F‹ÉÖ?˜Åþ§}§éU¶:|÷CœýÏÅ™²lÿ3sáÂyxÿ¯' Úÿ|ì$Hþ¿úØÀ  #ø'`ÿƒÞB)‡Ðr¥ ”Øÿ0Cˆ·ÛÿHþ¿N¬®­Ì/®¯__Z÷½€1ó ê=+/zÏ:ÆpÀ?`Œ ‘ÇØHвƒ)¹Pf#”²ÿ‘þÚµm¯Ù¹PrûŸ‹ÁÿOo@µÿùZeÿsš€ýÀpÀòÿé=çXÛÐ'ûŸ<ºŠ~ÿõ5ô>ükŒ˜Aþ®¢‘|:ÿ?þÓ}ÌÜçÈ'"Éóϱçž#¶Š£Ÿ0Ë>ÚŸ{þú"_^Y_œ_Y^Øci~-üûúõ%ÿï¥ùïÍØþçV­îÑç¿H`§@ñö?”÷¿¦Ë3àÿ§' Úÿ|þhþ(û€¡pþÐøï½ýÏzý¹£}þèóAhhÿóvrÿ?W—®/nr# Å7—7د1tleuqys~åÆò-âÙ$háAnd, ;V,¢Ÿ8Šž!Ä%Ð~Pò~Xì~Xf-ŽÅþgëæ™Æn»³¡ ÚþÃÅóŠÿŸóÊàÿ§'°åݪìÕÛ/VïTš•jÛk¾ØòÚ³{í[/ƒ¨F½^i×;4xó¶·ã5+õÍj­ØïÆt dý·½Vû¥.ÖÁ–øyûúŸžVÖÿ }ÿï|ÛÀ!_ÿÃÿ7E–8à¨percona-galera-3-3.8-3390/scripts/mysql/mysql_var_5.6.tgz000066400000000000000000002244301244131713600227760ustar00rootroot00000000000000‹3LÔQìÝ[lWðofwöæcÇÎ¥´E“–FIÍú²»”K›ÄN—¤$q¢ª´Õj½;¶GÝÝÎÌ:]ª…P*¼ñÄ/H}¨B(TH}Àê¾!T‰@Bð€TH (Ã9gfgf×ëË{ãÿ/òîÌ7·3gΜµ7gÎY*š§i›e˜|6+ÞÇò9ñ>žÉ‹wå²™‰ÌXnœ2c™üÄ©ÙíNװ좩ªTmZ/UÖYo£å»Ô»þ¶fÙÛY6uýÙ…ÏäÙÔ$¿þcùL׿øõ§¶`ó÷ÿd.“Ͱë?>–ÁýßÁõ·õªVørÍÐ ¶Y4,ÝÖkÆ£ófõîÁ/pn2³ÆõgSÙ\ÇýŸÏdÙõÏÜý¡7¶Ç¯ÿ)™Œ Iì2éÒp°H>I "…OmÅt¶ÞÕw‰hN³zCícz w’L”bïi’ùÜ2{ýØ™(ÉË1¢©3 r®\›¹|öÚ³ÎN't·ë’1ºÜœ™={ÙK÷7=°§üY¢¡Í¯}ðº^ÕTÞHD ‰XÛ—ºí'Q„t:Φ†iÜ^¡CÞ”Nш¯€$:*‰Ek~åëxܹhG{øínûißÑÓê/{“RÇüZ¤Ór¬ãg”ø×±üE‘Z{:Ò¹‘,‘Äâƒü_ò :#)6i‹(]ÓÕþæ-[u€¾éVÿW´b½`i¥šQ¾ëºŸë½þÏåsYÔÿýàÕÿωúÿ^'íºú¿×º_ǯû#|Ázu¿ªûS­š>½õžè11;)¨ÿKµJ£jX…º©/mÍs-¢þÏ­ùü«ú'½çÆóùü«ÿ³“9ÔÿýÐùüÇɈ¿H>ï?ÿ1ÛŠñç?n¿zäÏÜû$…?ÿ!Ó'"ü}ñü‡D·I^~ƒO¬PdyIbŠ.¿&‰ˆ²0½B¯…‰ôÔ ‰ïl¼@252ÂN’§ÃlõQ*=õ;JÈÃ$ý“?YÂÏÁ™žsxê éN(ÝŽŸh'”b‡œY­¢•lgÆ`ÛÚÎz¹hkÎ5m^35£¤Yøºè^´ÿbWkI3­-iñÛ®÷ö¿“cchÿÕ¢ý¯,}kï´ÿ)í?¢ýoÊ]â·ÿýŪƒH´ŸÅßcUùÏ%·;ä­Ðªö¿+¿E×YÐWAý_žÛ†ª_X¿ýïØxÐÿ«ýïD&;Žú¿Üú_>/êÿßñºI¦YÞ=ÖªåŽMäöúzÔ GêíÁç(ø>¿ý‰ ^ëóàê¯Nÿ»uŽùõHÁdbíµÚ7ùiû8¹Ã|IL‘½=‰x›ûl`ñ×))ý@šõÒy»•/"‰*þ'mVÀ¥†˜”he}Ž}ºäý=øKƒs¹í¾­¸o™¶e;û»ÌC$=å#€yóËçsÏqçQ¿üÿiÿß?|Úì!¡ÿÿ«—´BµhÙšYÐùÚ–u±Aÿ“ù‰|èûßIÞÿÏÄdßÿöÃ)™÷ÿ°|È')©vÿ“÷ÿà_ôÿpïsÇÿ”éÑÌ+º|ŸÛR)¾ü‘;(:yØ"Î9¸MOÒ÷M_3q3b4cµés£i¸wü6ÙKÿ.‹æ!êŒ1_3«E>Dàö%­/d:L?–¾*-Hûý¶¼ÿ‡4ÝŒ‘FGzëÿaèéFuN3 µùBE74‹êf[¡R[p»|ˆÑþP¨^³(îõ‘ ïs¡Õ3Ä ˜©-ëfÍ,SŠ”+5Ó¦œª†V² ¦f›M–ØôyƒwÓP.XV…öQ|ÖªJE¤wª^´i?%ÅœÆö1ä-Ñ닚IÔàs/jM:@‡ùä’fêóÍ‚Û-€»É¥.jEÓžÓŠ6’rN7ÊtFfŒšÉí®«—-–ʆ^&“”hoù—¾ÆÏ¨Pª5 Þ†HVɬ°I±ý££ì„é_#‘8Mq婺ÏïTãJ¤Ø&¿f›|]lrŠ’ƒ,ð{?ðIJ)ì(ùG9Mƒ,ðW?ð%J§%‰þN4ÀR"Gûâlÿð÷ñy`vP/ðiÚŸd”x„†ø£~ Kà ø¸xfG9.µŽr‚FRé4èá DÙþG¶É§üM.ÒÁÈû:Ä×8ëS4Í2è R+ƒ'…vÖ_#O±4 ¼à£ø!–Ž?Éé¸ œŽ{Ài¿ÜGü¢ï´•{‡z§­Ä;¡âî¸%Ü ºÓ*åNPį|;Ý ·ã—l‡kgu™vxvB¥ÓñÊ£*—N×Bé›jm^¹¡ê†j/jê¼^ѽÎ&øIó¥<è¶ÁSçt£h6U–Aj©aššaWšêœ¦ ª©Ëê¼Y«†Ö»ñ6åÛ´ŽÝÚk…-r7ԖؾÄê‹,Ó»Z,k°3w—±©²j×Ô’{ødǺ­ µ‰U Ífk¾È’gÚ›Ù3»Pµ²zœå—;"¡u‚­R´Åz¢É¢zS¯TÔ›EÝf™Ã>–øÐÔMžIlg¦Ö}Ï3FY/mvn.j,nº»—Zµuž8K½ÔJæZ¤‡_07ÙìPb«)Vxôy±;õlÃ^¬™ºÝTO=¡–‚E^6Ù‹­”ln3kUበmÛµ¹%ž2–T?¥íçÓuÏìþp÷øL+_jª{¯„s(|^ÓºU¯›<'õÒ";$ËßùbISuKÕªõJ­ÉòŠå²áÚ½4|w—›³W/y;©ñoï@3Ó_wŽíͽO±“©Tj7Ù>çÜ$Kv£X mº ¼`ƒÝ·7`P(Š¶Í’h[§Ú‹Ç©VAZЗxjõM\úkÚR­$~#R/éì®:>uíÒ ÿ¢û›m¸‰8Œµº€>yg†(ësÁ-ÉëBÝÏî=m­ª6üýguÿ?[:ô›°~ÿ?ãcã™\gÿ?ãy´ÿí‹Îñß”˜¿H>êÿÖÖþ÷ê»ü©QÚÿÜû$Émÿ»"þóCŒÿFÛm`ü7€]ŒßÄ;ØÝ:‡6<°sŸG°gÝêiü·ûÝ;j¦¦/ê¬ÛdDµy“·íKãv’(I¯R4F¤ÄÎùÑ`ü·W)•ì±ýª›+n ^ÅkÖÃÁÅ)ÉÛ5zƒÀ%¯´šõ&½f½)ŠÏÖJ/j¼oâ³X¯k&¥)öÅ››ˆòqÜZƒqÜ9ÊRÌ›­¾ Äøàp_“‚@þ[v<—Eû¯~ãÿô’ÿç}w¨É£»kü7½Ò’ìøáãüˆ:/4Ü‘Îd‰$äÿ’OˆÐqHQ¶E:F…‹ö˜<€þèìÿ—·Íoõÿ«Ï•·äëöÿ;!^CýÿfEÿ¿Ôÿ}ñ•Ï4þµ*xä³mÈ4Åûáxûà3Þ´¨ÏÜšÛ¯¿Ýï{ÁkÇr.²Æv2ó_©Ë:òëk|bìNß>û›[ü9ÿ¾Mß§ ¿ב7Wüçý9…`œ|þ½7ùsþÏÝ0¾Ëfå¶…G>0)šW†È}õø=t.[o^ùPÿ% Eœä%[þ_Ó¿3©lÅÕ€{EæŸ=ÆŸó7þðÇ¿Pè‰|±ÅÏÿ,´²B2½¼,ûsÝô–Èô7j\b/ûtc^¯6ª$ёը›ŸØëêTúæŸ>lòçüw:)°yÿÿÿìÝÏoÜèyðçåüâp$dË›µÝ ‚E³bÏhF]Yëí®6Ñbײi3¡4”Dì 9KÎÈÖŠ Ú¦‡zk È!(zÈ¡RgO=Þ¸-’CrÈ5·bÝÿ @»ó¾$‡äŒF’g3¢dëûYH"¾$_’eq>/œž];ÙÜs>hÜtÚ®^{`ÙïëvÍ0·¬s,û(q‹‹%ïkyiÑû:_Zò¾ò©ùRy‘ÊóåÅ…ÒüÒÒR•ø|¥:Oji,{?AÇik¶ª’wŽiwÒòçÔËO¤ˆ¦¿LDûv´Hš£¼J19׋¼Ý£'D¯ô7o© öFÇøô ÿš&&æºüóµå4¹ïÞY]»uç¾{Öýƒg”¥UÓ´n¯øsWζ3pÞL¥iúÙ[_ú¦—¢®š[–ÝÔÚ†ež^×Áh‚¾Âþ‰O}›þ7Œ¾K/S_a“Òì«ê3¢4¥V딡⽡íÕÖvÍÔš:ÿó|*Š´,‡r4½¦9mÝŽÚÈTŒ…D£<]{}Gß|¿ef»f÷oR¡«CŠ t=¶¬9°£‰¾Í6û÷9I3±…Žþiѽ‹mÛV§UsŒu*Òˇlí¦Ö¢tJQÈ{œÄOcJ&ÊeY¤“ÌÜž%út(;5;Ë·@+¢_F¹iþùs±r‘·˜‹µÈ_ãŸ_µP®ò•X‹Âuþù«±×x‹7b-&gxÇÖb›z‰Þ‹Š/óv÷zÛxÈ]­»ýÔí»šîÀ¥tû¯£{äE¾d`•ËwÄ¢•¼ ç½j‡£þ%Ãþ‹'ÊÿkM½ö¡eêcËûëñòÿªGæÿ•—ªT./òŸ­ÎS©\],•ÿ—„–ÏÇóÿ²Ñ"iŽÄ][Löåÿ½÷„èz/€ü?€óo0ÿO"ºFÈÿ?ïLJ"OomouýÖš-œe—àâø6JþŸr×hêªHqN¯K‰büoò»4Iâs•Ï¥Hd@Dùw)%–ÿ7y·—HS3D&àÌ=G¯5t­UsôMˬ;”žTò´‰RsD™™”·_™Mû=¸ñm¸ƒpɽï¾3žG3QþO«ÑÙ6Ìk÷oeÃ1Ç×ÿòÄêU¨T®,-Tÿ“„èú›õÚ†aŠTBìëÇ—vBý·r¥4?Xÿ­\ZÀõOÂSúò¿J,\$U(äɽX¯þÛzäœ,åçÍŸ T7ÏheY&¹;ǼBpùî+~a¬þL¹ËgÛ€çÝci”ü¯#…~LDúûFò¿~Le´ü¯ü»–cx•ñ2”ùK£!j¿eõ–µ¹C9’ ÓÑí¶C2ÉV]kë¢È›\׺˜THq6wô¦fµD ·¢eÛ5¾Â®’±NTð"þÖ&)½½iP:?;+^Þ[Y&¿¾Y&ó¶+27HŠ<ÍòÞƒ ENVšaQÁ3Y®Äy¸ (}>(y`.˜(ð½¼ÛËdš·ør¬…Û;3®8-®wnpBÜàl¸Á©pÃóàöŸ7:.?|<ŽúãDù_;z£U{_ß{`Ùõñ–;±þWu°þ×Bõ¿’Ñ_ÿë±ô$Z$-®ÿÅ] þÀóFâЩ¿þ×rš$Ú÷RW¼»¼¥y#œmŸ"Þ7ã³>Ÿ?¯PNÝ¿ŒTÿkR$‰¨A’È QLÔÿúý’O=#O¢ü¯¯\ÿk:žHã—Ëx£n¦§ƒ²_Ë”ýʼ½ï•Qök`Õ¶Dù?~†•s ÀŽÏÿ êõÿWžŸGþO¢ë¿­›º­5ÄX¢cò¤ú_åò`ý·…Òê¿%â€)3Qþ×4=IrXÿ+Ìÿ¿+Dý¯?éÿð|è&t¥èõõà…ßâÙöàÔ½5Rý¯Â›~’ˆÚ°¶O¯OIb”¥ï’ĈžÒ­0å}—rÙÑò¿ ú®n¶km£©S†”Ž£ÛµËió)í[×¼¤°)Q]/™&7­fS3ëµö^K§<å5{»ÓäÛ¡táòeñ*Þ÷EzÚŒ(ȣȲÈÊxëö,ÑÿÍe•+WÄE\Yæý•y 'ju½L±ò^“+û^ʆy‹|žoãw±m¸Q§Ý°ÇnØ]7*¿ï¨Ûëå|~ô‚8¢þ×ÚýÕñíã„ü¿ùÃù åJù_I88È1~ûû{ú)Õé7"=UUý„#¨Ý€?—ao_øxØvõ–¿£¾ö0˜L ÌÂQúôdàc¶·¯lFêmé7‡vĈ¥Å°ü¿ük^hÙÛ% –ùÌò[ü±¹ ÷ûdÒêãþ³v`übã?ÛÖCCwj-ÛØM´þc¹\=tÿ¯ÌcüßD Öü¹.’î…õ×{±^ýGµ@þ/Àù'ñ¿ï/‘Dÿͼ˜¢þ#£G$u?%Ju?ñ#é§Þ#Ìl÷W"ð4* ù¦­™mËÆÿ ‚¹£W[„óˆÎº ñ¿mûë}^è1Ø 9ß)ÿ÷Ê=G·U‘)²§Š<£¡oëÏuHF9ú},ý\z=ˆýLŠò¿Grn´üßÌ["Ù7Cq®ø?ó'ßõkê~p.šy¶$Sá›F{§¶-žˆ¡€ƒ‡("·ì®ÑÔ¶ÖlQ:óö#’‚Ô±ƒuQ:²T¢bìäÊ#ú$ÈMòÞ#› £_2h¶.Æø}ó)ý*ÖBQ._æO!RsbÀ^q(®87~nüܨûá °ãxtÞEù_"÷»ö¡eêãMþ¥Ï’ÿ[­VÊÈÿJ‚—ÿKì[^þï/Ľ€Yþo/ËóeóÃŒšó+*îæ‚¯â#–óËX°¥C¿ù’™£s~õ‚ ®pÅê?7´]½fë mOÔ®æ–5ž<àêÿΗcõ«üþ¿ÄàþŸ„–Ÿˆò VIs”Wêÿ̯ÿÿ pþ‰'ž õÆ—»eü÷0§÷¬ûwÁeiÕ4­Û+þÜÌÙvž_»é‘òïˆôõëÖ¶ºjnYvSk–yz½;}ŒdúwÒøT•¢T?ÿ÷ßñeyyÄñßßé47t»fmÕ†©;”¡â0«Æ >KSQ¤e9”£é5ÍióµÂ62c!Ñ(OÊúZ]¬I ]ŠöóÀ²ß×m‡ ”Z­ûã̳°üï]ÊýŠÁ3¢Úï§ëFÙ©ÙY1êÑŠh!Ë󔛿->¶øk’‹¼Å\Ø¢By¥P W‰®û]&åßË—cE† )(‡2¹'Âí? nß)pŽßí?x7ÿ/Èÿóÿ*T*Wªå%äÿ%!¨ÿlÄó¿×O-ÿûóß¶Áüï÷~{óÿƒI60?̈ùßâ5Ÿø‡—ÿíe9f3¬·¥a5Ÿ£ªÎ~9T¿ªó@þ÷~|Žuû–œ7õÿÛVËûoÑîÿ"ÿ»ºX®àþŸïþŸb?H¦þÿñ÷ÿ!¿> &SóÃ|–úÿÿ|H|Ÿÿ»@¼IJYïuËÔHõÿ{K‡×ÿOÓi¿³ûþœä÷W9üàÔE÷Ã4­úFÿi§?¬ñ›bÛ×(Çßÿ+åùCïÿ,.”ñþg"˜Ò{ÿgY¼Þs= [úóðýŸ°þÿÐ÷¹Nð™ù2¿HޓΠþÿò>IÝý‰T÷ï˜7‘é®JÞ^ úLpºàÂC™ €ÓôÑHãÿ½xDýŸÐW‹D׋õ0*êø¯’ýdäúSu­­mhŽî×ñÈPÁ«,Ñ«üQð_°ñær4!Ê1Ô:-¾Ž(ù¡ˆ÷nüey*x3»Z££“BŽÖlñÍ8Ƈ:hÆ[X×MÛhyEXÒS·ö½1—y·‹bŒÀÂí}ú8ÈŠ€—Îr—/Ó}ß«ý!ÉÊûäåy-ò…ÙYRR½: DÊ\ân(ÌM\KE«¸}ÇïFïFGîÆÛ ÙØ­;x¨H¥Ÿèý¯–mm:51ªçµû·Ç¹Þÿ-®ÿP]¬âýßD ÿÑûYç;à£ÿ¸€ñÔÿ¸Hã?>øˆÿØÛÒñõ?âou¯ÿ1ÊI83‡Þÿöÿ½–àûßóexÿ»ºTÂý? ±÷¿½ñÕ*’¾tôûßÚ `üG€óIþûß]1A¬Ëzï?&¼í Gÿ+Åã<þæÂçgé‡ôkFô#öWaÔÿQø!å²cÍÿîËøÎQά‰± I¦+›ŽMO¯÷Æ`™Þyºêtšb´C«½£Û±EŽŸñÍ3¾Ç3¾E‚÷ß²(Á;—›¥`Q>·|…þ1È_厎ÎçŽ'qû‡á;÷¨À3¥³Ëÿ6HSâWà¤ü¯ÊRe ÿ{¡\GþWX>å=–ÖSá"é¿+ ä=–†Œÿ¡&Ùa™Äÿ¾¿DÕ¥hüzDR÷#ŒâTw—ñ‰¥»ÿÊü=õ^vÍt·$>ñ4J{ÓÖ̶eã±$È}Ögóp¬ð‡*Kk{«ë·Öü9dxaüÿÿìÝOlYÀñß›±çO·©Z–J¥+ç@¥ÝCëq¨‰ãBV›6[¤°%M¦^¯;øO·å°ä€€ÕJˆNˆ à¡p¥Úâ„„àÈ©‡\©(Ã{3c{â4ÿÇnÚïGŠgÞ{3oÞx<íÌóÏo*þk↠‰›‘RÙ):õ£kXŸ˜ñ?ß•¿GD vN,9-ß“E»ÿõî¡ÇÿŒ~¹ZoHTìùÛú2:z³îÔdXÆnt‚Àb ºJdDFo”Özce}CF[K™÷WÆd Î)¿žU¿àiñßó/|ÁüÎÿ£êï,¡_ä{…:?ÿÛÐÂJ,¹·ÙúÅ|ô‰žLKþÝžK™O”*wJëÍu7&RonÔ“ày·!«}æ%ó;ÿA7€§Áݕڥõûõo–/ÝiVV/Þ©­÷~ -›MxÓätÖ›¦ÓÞÔ›K'%™Jf§©ééé´$’é)½x<Ñû¦ìÔ¬7Vjñ¸xoÂËíW~Lm©‘[dBéÃ$RR9«]dMJL$jf ­¼’^îÁïDη2.]‰÷³ÁàД¾¡KŠ2©M}û¯tÂ]Z^Xœ]~Ýtûžnü˜“A7ày§OÐ!Y¼¿P˜]ô?R'û‰pÌüMÉÄÁ—~ñfÝ©Åל;¥Š³7#RµR?ºæ9%Y”¯Y"9ë´NÙò)»$/å‹Xg^>è=š®-ZYYw$*‘šÓÐ7löZY†%Ú¸¿áH$úêCñzX´­‚躕’÷EƼ¦Äô žýÚ¦ú ´ÄpôÜ9Ý4‰ÍNˆúxRÄ5Õ»ºnw­ìšZ]q[Â])kNq¥á¸ß¦ÿSt*Nm¥|«\-^Ì{øïÿ£eÒ]ñ?™étšøŸ~ØRƒn©sþ7Vn—ú­ZéîÅÅ×z¸½Ïÿ¤yÙqþOOqþ÷ÃÖÖ°ËRò+Y“˜h?K ¶)‰ïúˆðS‡¸|ó_Õ/g‚„r¨µöõ?_zÌÚ]éîòn¡åÚ^»°ýÏk÷ˆ)ŠúA’ãbÝë^+¢ä¤ÎKF­Š*m}ÐjAc¾aùõ¶ýaWÍîeÔϼY%/DDþ©¯#þÕ®ó‘>RÎö½{àOú“Ķԣ yþÄÚ¶àÙ×éÿqî:•F{~|ûôÿfvöÿ¤³º˜þŸ>ðúl+êõÿüÑÿrbÒï8`ÿOì[óúvÔs€þÕ•Þ:\›"õÿäì·ýíš>žOë?{hH™^+&ê‡ÝkYJNêüïJL}¿ÝóP‚n5´Ää¼ßZ¥“ÕšDdÜO=ò+ˆ)oñß|å÷Ôý5‘`‘˜?™ð'ñð.+‘Hh íÔeòËþdÓŸ(ï˯q‹n xu®ÿÞ¬ÖÍåß|ï·á]ÿeöøþß\ÿ%³:Ë\ ¦Ìõ_&‘åú¯Bßÿ–Ö[ߪVœ[ÚJ¥^2%·L€Éÿý¡8üñ×w|ÿÛã߬;µ#<ÿ÷ˆÿIeÃ÷ïüÏd8þý`KA=>¹¥>©U«WÒŸK$æ“é|^Ÿ€ùùL2™›Ë¥¯¤Òs©ÙT>9“˦sùÄ\>gíEyqt­zN½ñJ"‘Oe¦gsSWff¯¤²³ùDr&3—Iæ“ùéìÌ|>ŸÌ¤ffS3¡Jž\/z«sþo”›ÅRå(FÛoü¯l2Õÿ£“œÿý°¥F÷ÿk$ÿk²•×ÿë\+ƒñ¿àxúÿÿìÝ[lÙyðo†ñ"êbI^g·iè¤MAw£»Ò›×´HËÌR¤LRN˜¥È±–XŠ£%)KNsÑÞj´yhƒ¾IZ Øä¡äÁ5PìCÕK€¢@›¢Š<åuIƒ EŠðé9s爲Dƒ"-ûÿÛ•8óqnœ9¢¨ão¾OI¯ÿõ¼]ÿKïaCý/€ÇP{ý¯è`Θ?íªþWlõNáz&n¤Šœå²_6‰dºD—õú_;êÔÿºD>ùÑê‰Â_zÁ/+iiô"Q@Ô÷úWÀ(çU© ª£Å•ÿ«Ö¶•r©¥nj;=M<¶þ×´7ÿoanõ¿ú¢SþoM-m+Mµ¬Õ+=iÝçÿ..- ÿ»/œë_¯l(ÕzMÛTªõŠº×»·€Gøù_âÍ׿<ã¿$ÿ»Ãý¿ó3ÿµ/:¼ÿ÷¼tÿþ???‹Ÿÿ¾ðÜÿuzã?yýggçç½÷-,âó__xǾëÜb!¬óøÏ׿Kô‚@þ7ÀãO’ñŸ[bÂÿùÉû÷1tOùñŸÏ"éoõÛ*úæ£nò¿g®iÍV\ Z­©›jówâñUµ±©Vâ»ÕÖ«ñJ©UÚ(5U×§wä½!Ó$½+}‹ÿ]xW K¢neÜùßeir¢ËüoqŽDþwrƒok¸ ÖÔrKV•†h8]oª s6DÃëÛüœ©Æl˜†“|ak6BÃË Õ~6J‘dCÛ6f†)ºÒ(ÕÍíÄh,¯ÞRj½làJ#M‹$Ncn”¢‰ZKmsctÞÜpkk[ч}5ž§ñŒV~MqKçhÜ\øvUÝ5b4ZxUÛuE&iÒ\ª¡í´ªusƒS4aì·-zžb©=µ¼c½²Ë$KÝâX±QÝÜ´^?ðÉ{í£jû2tßû|t[¢d¢=$»®@Hö\°Üq""ðW á?r†£<ðYW 6ÆŸsFÄŸwFEà ®ÀØyØwÆÇyà Wàœ¼é LŒòÀ[®Àä$¼í LMðÀ;®Àùü±+à»®˜%7˜«ù2WÛe®†Ë\­–¹š,³Û+s+ó´Tæ4Sæ´QÖ±2oëdÞ¦ÉÚÛ%ëÐ(ÙáÉÜÍ‘¹Û#–eOtß§çþ–¶]íyp÷ùßó‹Ó¨ÿÜžëÿšzgWkôæ¶[÷ù¿ 3³¨ÿÞÎõoÖø[gMÛì}ðÃþggæ—ÿ>¿€üß¾x EÆüß1º´Ÿ’C‡ë?‹¿Dýç[äÿœ òÑC}ïëÿÃGË…ÆäÔ`:ù„¯›üßP¡¦íÆkÚæéPŸI4Lߣ7ƒD—‚Ÿ³£Nþï÷(6Ü]rjT$”´QN‘Ùiª EÔÖ£ E_ßQwŒ§†(RÓÓÅLˆ" m·©4Õz‹Â4¢Ï¨{¥­j]­P„|• ŠÒh­Ôl)U# ³ZáGqfbá“·ùÎøÌ…›¯×”–º×¢QŠ´^m¨¥Šx˜y±_¤gˆÆEy·H($r<®%'‰þï"Q0‰ˆ&ñåËüÕOð%†"<0á „"Ѩ8?ω€Â#<ð¬+ññíü*ŸQå::Ê—ˆ%†Å6~͈‰½<¤g­ÀH˜ØoLMÑR®ˆ%B"GÕ9ÑÌ>ËÌ9ÅÌ>¿Ì>¹¬í̲Êk?§Ì™²Ï&³N%³Ïã““êäU6N§úë±ùŸ3 ‹‡ê¿N£þs°_?é[Ûc¤¥6[ƒ>†~’u’l’øÔ™½n¨œÅ#4®Û Þ½Ž«ÿß‹dàcêÿê¿Úó¿—ff—ðþßÞú¿1ç)ù¢]ÿ×Îÿµêÿ>gÿ ðø“$Qÿ—ø_ú¢ZŠ^ÿwùre{Îs&Û«ÐFû<ðTùŽÔMþïodÔÒvÜH iÆ«õ[Zc«Ôªjõ8ŸŠ‹ ’¸È yì«þ:$’é:}ˆOÅ\cÁ8ù¿×É'w—ÿ;Vl”êͪ8+VptYk4Ô²‘lr’ô^2ÒXÑhTtÁ©°"¯Õ³æ¬ÝûîOýdžZÓ¯gO‹Ÿÿãÿ{a~õû›ÿvžrÿü€³Ìÿ[äÿˆ[Óäý ѳ—ýF"˜@"P¸N r ßîw•ÿsÞô}œØ¸•-rz‡wêDþO‘&ùTØ•Çàäÿ»ÎÿqÒ÷4æYU/Â7‰Þ¿BFÆO`Œ‚®kÛól —}1NþÏvC+Ã*¿¸z3ÝÃ]SÿmÆ3þ¯>þçâ òúáÁƒ!þ# ?Cß¡ ýL4B™ >ñLüÈfÆLÆ\oôÁ?à߬-‰µöõïü—æ¤Ï3ï}¾É™<é1ûòí_æ ¥¼†IÞó®h”Ç_£¨¬IóxïYG`F$:àßÿ¦-¼´£O^t–‘¾)&å‚ó*dUŸhÄOô¢ŸÚ{yŸ?{«ýõÞ3Œ‡é¶9s‘÷Ûæü'93p¶´÷ÿôºçÇpòþŸ¹éé…iQÿ~zý?ý ÷ÿøä˜Þÿó}ѯ"ÑE½kã·¼ý?rû£ôOÆ£Õ—âÿFûc'zÿµB°s?OÈ^ÚÕŸ#yæFònçáü_2¾è™/Ç úxÄØ…r0(:[("éϽkù$åñ»–þÄî}9°öîî¿¡¿“²u ^zÃ}¤ÆBÖC{Ð~1üzÞv=HV_Žßõà3Ì$zE2dãÁo¬~ÒóOëwoíÂn©QׇÐRZ¥šªÔµººµÝº£ÿº—žô@Ï8ý?êmµÞ:•! ÿ±CþÏÜÂÆì Wý'þÑïûÿެÿ4=¯_ÿ¶úOsó3ÿ­/Œü/ézÿß¿‹¾=‰ Fß ó¿ºé7úÈ?vÚÎQù^ÙøKVn•ä™?J—}ÒÝö/»ï‚ÉÜ’´ï]K6úþ>C!é³'ÉïrŽ«=ëè¾½~<ÀÓÌûù¿—u?-ÿü?;·´°äýü¿´ˆüÿ¾ðÖÿü“ý-L¤º®ÿyï»D·¨ÿ ðø3êÊ´/éÙÀû>ã_.ä}ý_jPÿ³W;i 8î«1ècé“®Z¨$= gF¼†ÂÍB1µ:è#yrµ·›örÆz¤wGè“ÿꦀ_0%’DÎÐð¾Ç’é<Ý•~7Jôÿûä§ß£ËoÉ¢þ§~³4}Xšœè®þ§¯²A ÔK[*ÿhØÐ*whˆBõVµ®6(DQuO-ï´T¥Ô¢0Vë-µq»TSø×ŽÊwëDnUÕZ…¢*7ÔRK­Ð0…·´J•Ç+£‘Z©ÙRÌ­Uh„†D. ¿<£Pë•&¿²"ÒÚiÒ8hu¥¬mm×T½bë9 7_¯)|k*Mðh[[üÊÒ$EµFu³Z/µ´MQD @¬ˆ1ù™*¿Zj”Êüà”¦ÚRʵªXE%¿¯»34UÖjFáX~Dõº90r€b• Å~ŠŸ»ˆ8wÊNëÖ'ø.2FqîA(øäYÙÄ.Š„ÝPˆÞ’èÉI¢_¾D4ZyŸþLrV E'&è¶L¯ìó€¸Ý=<ÒçezN|<]\¤7e ½1FÒ/øF£!¾Ê[2]¢gÄùja¸+db#<ðE×FG†xà/\Ñ|Õâ{y—ïE#Yìe|äÂú†ð‰À¹ðÕ¯¾)ÓyœüÿË¡•úkÙy-“ÑH„ª>³b,ßèTäòeÚò™çƒÎOýö+ômŸ‘¾,Vñ‹@Ìï±+¯Ð–+ŒðSø¯~úÀÛæ)d• &Ú1‚™-˜9Í—µ·]ÖÞp™Ùj™ÕdY[{eFce¢¥2£™²¶6ʬÊÌÖÉœ¦ÉìvÉ:5JÖ©…1wóbvÛbÄn¦yv}=‘/¦òl5—-^cÉÄMv-·ÎgÓÙõbŠ}*•z™R˹l’‡–ó9sZ¬ªØ«(ú*bÂ\MLšKЧ¬°>moM„¬9c]gûæZNÀ\Ü2ÚBÄRÙÄ•LŠoÿi®O2‰©B:™Rì±d>·ÆÖò©B*#Åçó©DFI”«™\¢ÈÖÒk©‚˜åÛ\æó‰l!­\_ÏS–^Éæòü°×Ë)–Í•õßb.›¹©\]Ïd”•|n}M¹r“?§¬óõV²©¤RX¿RÌ'–‹é\Vē鼒Î*Ë|¯ü¤¬å Å~(×3,ÇʤØjAÌ$¯Ì²ÕÄï'¯ˆU^NÝTrkb1[/ĸšNe’v`õ&ßÀÜìœ11?­¿±Xb½˜Sn$2ë|å¬òéT>'¢WË/óÓT¸¦¤ Ë þÚY¡˜O/~ÐÙ‚±3;–à/ÒŒðUÅ&ÄkIŠWbÍë3é,ßO:©ÏX*ŸÏå•«ü+™¾‘.ð£äçÈ8¾“dZw"c¢qjĹͳké•kŠ8Óüz-§’©¬~â•Tv%M‰S[(¦‹ëú¹]K$•åk¼eòMèW#×âMôðï?'ÿÓþ‰RZöøó½¹è˜ûfßÿ³¸4=‡üÏ~Ðïÿ!iO¿ÿçŸû.wˆœðþŸnÊ?üþ+þè÷ýœøXÆ=_“ÖÊÖ}?|æ‚w%™˜àñsâ¿ðKzè²¾–¾JÄŠˆ›+ÔåQœ2çý¿YÓv•š¶ùâraµ·û8öþßù9oýÿ¹éY¼ÿ÷ÃÜ øTk«ÿ¸WUí@zXà¸Ï ³žÏ ü3!~þûÕ´r©&îý¤ Œ†¦¥Ãí iÐÐ'w^ŠgÙvµµ±S« úXº‚F{ØÓÔhýNß™óûS­«RÍüàF÷Ñ}ýŸù¥¹üþï÷ߥ۪²UjŠ®ôjý–öbu£Ò“}<ôúÏy¯ÿ‚èÿ›]DýŸ¾ø•ÿù·ƒCÁ ï½ÓVBÇON§UD—'£çÎî¿3þžü+ç»çyÁwÄz2}ÔþN–‘¿uD!ÀÙôÞÆ·â>ÿûÁVŽì:•¦ ï¾mW°P°àT¼÷é¿ýqŸÿ×~ø—_ç³rÛ“Þ{‡|®y?㈌ï&»b€÷¹‡Íþ³ú<äcd¶ü¨Ç?˜£vôâêÀãâKK?zAÜç¿6uÿ¿ÉuG¾þ$§þε°ŸdÚÛ·î˜tÜाœ¸¯þçöԬĿŪõ[Õ­-’(JÔÜÙn¨bâÿÿÿì[Œ×yÇ¿’Kr﫽X–â˜j"ɲ-÷î$u,jÉÝeµË]‘\ÇŠÛN¸äh5.—\󢋟Ô4ÈSQÔ-úТÈKÓ[Ò‹ÛÚ® ôa«ÚNh^ ô!­" о´@žsfHÎÌr/´(J²þ?‰;<ß9sîüHžùs€ˆmÊþVü_Jâwþ÷»*ÀƒÀÕLi|ëFùÕüøv¾ºiή\Š·»Œ0gv6,s³ò8ž“Gù4¦‰É‰Ù™ðäÜÜÜ…'¦æf')nwEšQ-W2¥Pˆd'ì“î ø‡”;wü y”4½A9z—âÿO(2Šíu³0CÞJ{âåfù8ó#ºøáøO­§Š+Ü ¥µz¨óüOøÿE~1Ÿuu)µœ>ØUˆBg¸ý}òÓwNÈ2´SÐßɃòµCÖ€›ÿ/¯zYÛ.WÛû. ýÿô^þÂôÿ³ÜÄŸMOrÿ?31ÿߤÿW•ÿ‘þÿGä®0%½ás5¬ºNQþzÄ2û^9¸´Ïü=ÿÓk,¿°‚ƒ{¾$B/ܰžz\aw¼»®Jàá¾å|ÈÊ“»|ª•“òC÷Y^…¸ýŸ¨[ù’²êúf­•–E!1¥ßrXDšw§Q~[>U¨Ÿ¿çüÏùI=ϸý{¶ÖqÞ4áf!+ÉGV-Ù>ñ„)˜/f3ù+ÅrÅ[*+õÿ¶QÙ¨æóv«r* €¶rÄÆ;< õßr¾xMË7ÏΧ^lo\ÿ ï¾þ7=žÆúo'hŒÅØÒµ×Š]+d¶ô³+—¢í*cÿõküëÿÓ“Xÿïñ¯–õÒ½¸úàëÚùúŸ×ÿ§§g0þÀ¼þ¯þº¼þóâZ‰B)ùðó‡¼þS¿®òÆÁ¥ÉëÿOZúuû&×ÿoÛÓØÂ{Ѫà¤ù SäUŸ!óϳ"BjTòòœþ{×Y pûò&ÿø0×xê1æ53†Î8êü‰9x©{÷ÁcŽIÓƒB;Š™Rµg:ɤœ´­ðÞ$oE/›—îcµ÷žÆç¿l1_Ý*Ü3ýÏžŸÿ&š|ÿ›™ Oáó_'°ô??‘Ÿÿ~,ô?üóŸù1êúÏÁJÛ_ÿ¹µô-êBÝ(­Õ×ó´óa×)VNžçÜgñ¨A‘¾Ç3¾ÏgÄr뀄ê§êN£ü¾Û¢êÎÖXjŸóv„¬ƒ×q€G’ÆúO!·¡m…|qS3 9ýzûÖ€Zûý¯¸þ7373õŸN ×å¹þóâ÷U îÿï[½þWO{øú(aó!Ûò‰¾âßç‚k™rùZ±”#?õ¦ô¼ž­Èߨò¢zãžÆ ©w};—©èf°›z£½ÂP•SªL¿!î^ßÒX ŠÓ³ÅBg/sôѨÌQ4Ònï"¿¹wƒ±Lµr…·ÛÈfD¤V®”ŒÂ¦‰mëU é×·’ž#¯ïçÞ4ï7ù“"òùÂazÛfè ž9CÿQ3Œù{=ÕARþ÷Q@m† 0 Ù ÝÂpÄfè†a›¡·›Fl†>‘bÔfèïç†1›a ³EGm†¡nxÜf82È Çl†a‘â¸Í0" Ÿ²FE)OØ c"ŧmï7Æ ÏØ»0xü8=kTÙ…=}N¡¡èÑíxörÜÍ0ÒÇ ›a´¿§‡.(tLºúïÂ^nXµ¼ƒÜ²|£Üðe›¡Ë¿´C/+¤Ü´¦¥Œ—r\¥¡¯‹RRVžTUgâ-€ ÿÏjΟÙF7ÌEÁöh[–0RªØ&ñ¡Cñ¸—ðÐÒñ=xì¹ÿoµ€ûïÿ;žšuïÿ;3‡ûv÷ý?ßkD©'êú¿5›¸ÿçEžæxÍýðà#t8âþŸ;rTêÿèÜnûÙvz™šÙ §f«ç¾u'€Öø¦ÒŠþo mlé!! ‘ÈC®ý(¤Ò}?{OnmÒÐÿ-‘GmQÿ—à=C>êK×5†¼ÛᎼ¥è9þ¸#´T}ÝÝt‹è˜0x„tJœÇì'ubñ¥¡ÿÉóÕ­‚©:»r)zð¹‡å€ýßÃÎýßÅý¿f&æf ÿéñ¿¢ç·µl¦¢oK7øˆ·­ŒÆÒ9þbÿ癩‰IŒ'¸sǯGùMzƒrôðPª¸_¨`O÷Ã,ÌP+»Ñ?ñr³|ÜÔâ/~8~Ûzêq…›¡XVêô}ëáágþ3?Š·¡xSºº¤vXá9}°« Óÿ/HÓ9sû,+v€Ç¾O~ú®rªýN­ µTóþÒŠŒ!EV»û° 4ÓÿVJ™BÙ÷%wE½k)ðú߉ðÌ´Sÿ;žOÃÿw·þ÷T#J}zoýï§kè€E%¹è00…þ÷Ø9/©7»Ì'· gî-²u lû;_QŸDžU[Ñÿkè"‘‰<¬R`…|ô}?;EÏ×­ ýïk-ï›îÔýúh8í”ÓkùW/_.ëò“?^Ö¢©4¨/²±QÒ¯rK`ò °jû†¹¡Ëfèò÷ôˆÅy36aðû=±d UdB{è;z”¬¦Õ±S_¼»f̬3ëÄì Ð'‘†þk»TÌÞ› ØÿyjzbÚ½ÿóÌöîný×ë é¬:EÁfú/±ÿóçjè¿€±í³XfüeûþÏ;¤Þ¼%bÅþÏ_S(Q »Kúû?>ì(÷»w‹¢¨êÁóì~ײC<ÒÿØ8{Ë)5}â.œxXèõ·¢ÿJUŠ%=Z+³z®Zzhe_uT¡’ò­n¢×½?䟈'(¡®y„þËBÌ´¼ÿ³'·A>ò‰ûcŠýŸ…°ŠüÔ_ÞÖ³Æe#+wW¥ó™Âf5³©S˯æµ\¦’Ñ2Ù¬^.S7 e-§WôÒ–Q0Ê#K=<=[-•R­E½Ô³)e¶´ŸÖx¥y/ËÂê¶o¤eá§Š,D[¢¢%µ° ðNŽ,Ç£2b±dr5©-ðG4þb<ÅkÉûȬ/$õŽ,׫hvèÛ$[Š/.i¢§×’1>b ÙñZ,±ÈOtm*O¯›S%Õæ—"Ig!Gc™§J/=š Û{ÝÿµBÐôŸaqÏW×ý_§gqÿ׎àÔÞR¿ßˆRçvë?o©¦þ³¾Xý'ðà#$eââjcÿï#çÔú†àêMqľ!¸\3¾¿u {øeÎ9ey}ïPÀ'”Û­íÿ-D"!K$b<üêO¡2ô’A? ± ìxÝ*ôŸ¦œÐ Ÿ·5)ãCHcÞ°¦ÞΔôBÅë'oµ”'ïÏGrõ…—ª,Ù£\}!Kö8ÌS¼ËSÜ´Rø½½O4(¥‚âî~î¢Í՚݅2^¢¹ˆãºÿ[[÷ý®qÐþÏ“ÓnýÏÔôöÿîÊ»Î}—•wŸ*[ŽÍ§Có«ë‰ôSOŸ -$WWBFár±´ej3ËÙ+úVæl%³‘×Ë¡//Å’± HMih9~!:}¥X®œEQ+Ê<ÉŠ”ýi¢R+î|$ Iùàé3_ì…â ¡sW2WuMä¨Éä¡/…¡ôR,Ñ-^v©Xš§¨Gj…bAß򨆯£%²ì³"½Ì>Æë_¨´;^ï˜ßuïOýjþèµL© 59CÝ3FüŠ×Ç_ççc‹qQy³êÎÆ=þb÷>²ÅÊó¸7ø·Zju\¥..§Ò‘4ïÎð•–g¬ÄR©ÈbLKÇ^J?:-{²Ñ!£*+!YÌÙP\rúvI¾#Êr¡kF>ÚÐC%}«x•ÛŒB(º\­TK–×3eýìi{¯òcW©X¬œ;y{üËâáâÝñGÛÔ z)“ײÆP÷&´ò5=g”¯pK›{©q¦÷®ém/,¾˜ˆåB³GŸk¿OuÍc¸ÿc}Ê…f—ðû?ÖpÿÇù” Í7Âï¹áþ—û” Í?Âï…áþ÷)š}Ù¿ÿþc¿ü?oOa{Zï…¾ÿä5&Æ™§2Îä8SâL“üV¬éqªâ̈33ά8³ã̉37μ8ÕqæÇYgaœš8‹âÔÆ©‹³8Î’8õqâ,Õ쉆?Ëþß;>fO2ô/÷)š]iè_áS.4{²¡?ãS.4{Š¡?ëS.4{ª¡¿Ñ§\hö4C“O¹Ðìé†þ•>åB³« ýÍ>åB³gús>åB³gú[|Ê…fÏ2ô¯ò)š=Ûпڧ\höCÿŸr¡Ùs ý­>åB³çú×ú” Í®6ô¯ó)š=ßпާ\höC›K¸Òì…†þÝ>åB³k ý¯ù” Í^dèݧ\hv­¡ÿ Ÿr¡Ùu†þ7}Ê…f/6ô¿åS.4{‰¡O¹ÐìzCÿÛ>åB³ ý{}Ê…f/5ô¿ãS.4{™¡ÿ]Ÿr¡ÙË ýïù” Í^aèß§\hvÆÐÿO¹Ð쬡ÿCŸr¡Ù†þ}>åB³› ýù” Í^ièÿا\hv³¡ßõg¨š3ôâS.4»ÅÐÀ§\hö*CÿAŸr¡Ù« ý‡|Ê…f¯1ôêS.4»ÕÐÿ™O¹Ð쵆þÏ}Ê…f¯3ôö)š½ÞÐÿ…O¹Ðì6CÿŸr¡Ù ý_ú” ÍÞhèÿʧ\höå†þ£.áJ³¯0ôíS.4ûJCÿ7>åB³Û ýßú” ;ÊÐ̧\höÕ†þã>åB³¯1ôçS.4{“¡ÿ{Ÿr¡Ù×úð)š}¡ÿ„O¹Ðìë ý'}Ê…fß`èÿѧ\höfCÿO>åB³o4ôŸò)š}“¡ÿgŸr¡Ù7úOû” ;ÅÐÿ‹O¹Ðì[ ýg|Ê…fßfèÿÕ§\höí†þ³>åBª^9òìÁdÿÜÖƒÉJ†«ýChx¹o}ðyêûi€ ç/ÿÿìÝ{pTÕðsîÝÝlÞ›QyDäÞ!<$’HÂNg–…,²’ì†Ý Š3¶(øø£VqëŒN§3¨c‡¡/|GT”ÖW‹VÔ¶¾ÚJ«¶‹o¥÷ìýÝ»¿½›þ¨£­ßÏ þ6Ù{¾{νwsƒÃï.üïyªîƒºÏ®õ„|¹w˜ú³–Gs67Ä•ôIªì“ÏmÙQù÷>J}kt,¾)ÖÛß+ ¥šB¤úû’Qý5À·YZD×l¬¯Ð}þßûèUŸðöôW_P" ò‡™ÎC§GªÓ©Î :“jÕYTë©Î¦:‡ê\ªó¨6Pm¤:ŸêyTϧº€êBªP]Du€êcTP}œêTŸ¤zêSTŸ¦zˆê¯©þ†ê3TŸ¥úÕ穾@õ·TGõ0Õ©¾Dõ÷T_¦z„ê+T_¥úÕ?Pý#Õ?Q}êTߤúÕ·©þ™ê_¨þ•ê;TRýÕ¿S}—ê{Tß§úªÿ¤zŒê¿¨:çÍ¿©ž ú!Õ¨~LõªŸRýŒêçT¿ ú%Uºï„¤/%=tï I§°ôQ¥ó^Òy,鬗Aª…T‹¨S-¡ZJµŒj9ÕÕ ª•TÕ3¨VQAu$ÕjªgR=‹êÙTGQMu Õ±Tk¨žCuÕs©Ž§:êDª“¨ÖRLu Õ©T§€o-ðÍeí{òá°õ¨Éú³ƒ?¾´#uÏ×9µáÝZ»ê%ÝçâÝ_éâ@ΓÕÍ£r¿sòäÉ/Ùã“Ή!÷ !§­ ‰ð•ûŠÿwÀ·Ò‡=çë>ÿ‡Ç¤ï°¾,Èy²úà+ž;ØèSÐ}Š¹ÐŸ^î§ïëOL/¤ÇúSÒKØ8ÃHþ§ðãªí8 ûük¿sìëË`ÎçøU|ÐòhÎæ¦ya¦«_˜¥™Žÿ¼@IÕ0»êƒÖwMÅ7Åzû{Ea@M!Rý}ɨþºñçsêjÇ×TWXÑ¡*ñRçºÎpëªÕ-íËVf^Kì°r§Ëê øØK¹Þ?îôÉF°¶¬®’ãXNxɪå,Ìp— ¶`ãœiµãGU•ûDM•QªÃºš/oéìh^ÒbgÉ«¬õîÄJ3ùƒd÷ËyõS&Ž;KY[ÔV‰tÖÒæ®æÖöå¹I·Ð€2½ßKjy¬yáÜYÓ'Œ©¢®Ê¸¿w{jkÏÌX<žèÞNG6ôDét$Ê„W[ sÝé•[+xBõs’‡6VÉý9¡±xwôrjî´FÌsCC;ì{>xCe/YÔ0{椚³„hª2KíÐTOd[4œŒöD¶‡{—Xé›™Xß.+£Á­"Ö\:д`NÝ´ñ£G ÑVelà±½‘T:šÌfú¯±ÝÌJ+sä ™>žÙQ%Ò<ó²Dr Ï \kÌw3Õûòfú½`hi9NDC=Q¬ûüoÝ {Ï sûÿåíÿ—Ùýÿòaˆ ÓÿoÜ-œÆgßtùöeúÿÅ5Cõÿ« !¿¸“³¾ýjë©j¿ §J¼-ý#­çküâuzÞÛ¥_ô‰Z¿øœž.Ëi¼¯±ÆÖùåxz²|¨^z½]£_.§íBCµÇ³¶kòËm´]ÅÐïc­-ÛüÖ>´UÑÄ®7ëð‹4m¦†éK€ÿYiñºˆßtb@÷ùÿøÑ ­ïåöÿ¼ÐÓÿ_Yù©hËyÂ9öÈj%l¤ä#­¯l^Ñ2Ìø%[Ùxƒ_±º¥uÐñ3õÔõxŸ¨Uroòñì›Xßq¦˜I`ë®SòzªÄ³nãÌüuO«_3ÊÙ¨ä'l$_·1£cUÞ‹ÎÕk¶‡6)c!Ê—l,ѻ̚ô Ëv3|¢MW± ¾lc­ÞmCe̘2qÜ{Êp_ê.^Z±²^NÊÜÈÁ»}ØFÛƒ×*ãS6XòÁ NñÂë•ÙÀÆ|ì…­Ë›—åí=w°OlV¦sg†2ï¬ï>Õ¬û”¹— Ιõ#Í]mÞYÏ«·^Ú{¹2OÐwËÝ6®¶Ì•uÝ‘tdC$ Ç#½ÑÌAé”z«½Õl}¾Ú!;”¯…HÒbßüb°„9uÖ©g¯ÿz廂%<áâžH*îï³f£#Lô8«qß3Bܤ|ûY„É#ñp2qYÊÞ‡ÖÆBÿ ç['Ÿ=z·òûØh½kcO¿¾F´Û¹CG슨7«Y‡ÙYw*Ëòó¬ÛRý½áĦp"½9sÇ '.onî1ò‰=Êå…Ücdî´òæþ1Ú«ü¯±ÉC†9F,a¿ Œf O¸Ø^ɰGÙúZÖ³“'$†9ÊzWŒ³÷ÅÓ*p‹ðñˆ]úÎ)§ZÅ *ð6 ðó€Û2Û"=ýy‡—­âˆ*˜È<á§©HoŸ¾×‹{†Ü}²M¶#ÞPqQÀ#ÏL¢;šÚ˜Œõ¥c‰¸½˜Šrç§y£ž‹½7Žª‚_PN…{fø¬K‡lõ+û{7Xç˜u²õÄâî f:{­Aï{:ÇTÁg,Fò˜e«Ý»ÍОõ[{Vß§HoÆ~”|¬‚M,Åà)ßͦô%òÎuwEÖK«àu,Ää![WØ·³j.îŠ|2¨‚ϲ¹–Å 2÷d2¤ ËXŠŸ§ÜÞ¹µÇ:J֪쿻cÏÓûĨV…±€Ø›=>öýwòŽPö’.kTáÍ,¨€=ÙÞí™=Ed­*ÀrŠXŽ!YÎ%ÉDÿ[›Ö´À:Ïì°F•½9¢p.'6"/lC,ÝéËì´E~w§|¤Co–*(}°äÞâ=EwÞ¼® Xïïò5˜ ÆBÙ*¢÷¼öÃ.Ýço©ÿÕvqnÿÿóIOÿ¿in£–™ÅÂEÙýìT`ÒyT°ÏÛÿÌíÿÏ4øŒ²ûÿŸ£qż:ô—µ/ ·¯túáéÅäŒL;‡P­d…'¡„'üD7¶g#ˆœÉ"j”ìòD”òˆÃº¯=?¢Î]Gæn·òWN¯µÆ÷ºë0Ø:feþ¿=‰:%ßá/.œþ êßÔ¹®3ÜÕ¼xyK¦×¼3ì´œó3;óåíÀFeÌãSN¿ÖK›»š[Û—7‡í¤&elçóN uMìXݾ¢yõ:¶ÄL‹hSÆC|&Â颶ÚcÙEžˆeœä¯.œ"j´<žpbz"Ö*“÷ÿh¼…Èœ’¿Ÿ'b}n‚f·Q/Â’üYø³»à«ðÿÿìÝMˆMaàsÎ ãæú+å'+Ù£¬Œ°˜‘š©™…b¡PRÊbDY(fg”šÙ 5;Y(‘ßl(v¦HþvÜ3ç»÷œs³°º’çYÓ÷Þsïâlßûÿ”‰t<9ºñÌÔ£¼çÿêÙݹÑâzÿÿÁ‰Žþÿüž‘دH²¤Q.·µ¹³ÞÏí«-Eÿ²Ýÿ_PïÿÇI#$7ãgÚÿ+ЪÜO ï)&D“U!yû:S3y·?ß|Ùõ!m °/îÌÎæ%þ<»ºØeÞÒÖ0è’ŽlvaxϚ≛C:VI¥ÕÔÕÑ‘±8,¿=¤gc¬œh=ûssÍúÜÒéxÞè ÎÎã øPH_Äór6:VíßÔÅãhöhÈæU>PxÿRއÇ!èý!ÛÓåäpQÃÏz÷øC!«®áV·É³uåã‹ÝÖäXÈ.WÒÕòlk¹C^Ì¢&'C6SIW7dz¡ö`x|kN…ì} —s™Eû? ÃGÖÆ¹ûÐÓz[V´S±à¿;Ÿ޹ÉÐ|³Ë\u3¹g>ò¿u*´ÿ+ÛÏ‹mÿƒs#d";œN§ ’£®}|™÷üÞÌÉ×cwvü•_ÿ™Kï?Ï{þaïõoI±i_¡ÿÝÐ÷d0É{þ_ÜøÞ¼è¯Ÿêÿ@7\|ýéGÞóß½oÃÂæm£~ªÿݰvו§yÏÿ~ã|oóviýTÿºáÖåŸÇóžÿã·S‹š·Ëê§úÿÐ ý§Æóžÿ¦{_CóvyýTÿþE¿ÿÿìÛ?J`Æa„F…ì¯ÒµÕÐ ˆJWh:‡ÐM£n MmmÑÒê.Òä$¦ßçö]àáy¶—÷ ?`ý .~ç±óo¿u‹aþr~Lbç_yù.…¹›¾úÈaT¿ÇÎÿ¯þùæ^úêÿ ‡“ñb#vþ¯æ"ÌýôÕÿ@wçO±ó¿ïo†YI_ý?äðSkܬúÿ³ër˜é«ÿ€®ú­jìüg·§[a¦¯þrè4^Ÿcç9-m‡y”¾úXGKÿÿìÛ½JPÇa\ÂI#ˆìC]‚š… ڢͩ¡Ulh5Ê º‡.À ¨ÝAAhs($‚n Ü"pjíœñÜÀ éy¶?ïòÞÀ˜?ý‡¯ãØùŸ–›KaVÒ«þr¸¹Ïbçÿ1­tÂ\K¯ÃÞŸ<ÿLý¨ð;ÿ­ÆÛy˜ëéUÿ9œ<ŽVbç_*^·ÃÜH¯úÈaáì»;ÿýÏí‹07Ó«þrxÝ{Þÿáûâe˜Õôªÿ€~JƒØùß.wºaÖÒ«þrxiMj±ó_½?¸ ³ž^õÿ0~ÿÿìÛ¯JƒQÆá6,(˜ÆDƒûœÄì‚aÁpÍ´4D,c ¨ø'[¼1«Õ´2›0ƒÍ"–] XôœxnàÀÏÓ^Þkøås<ÿ­ÅÎiõó<ÌõôÕÿ@/㟅Øùï¯,_„ÙL_ý?äpøþÑ‹ÿÞ f‘¾úÈáû±×ˆÿÙ´{æFúêÿ ‡Êßî}ìü_®Âl¥¯þrhO¾Þbç?^<¸s3}õÿCg­¨ÆÎÿùéä&Ì­ôÕÿ@³á,vþw£úm˜Ûé«ÿ€2úÿÿìÛ1KqÀñÿ9¸”:G[ƒ8T–OTàkpâ!ê 4ºUƒ$"„ƒBê ".. ½ƒ¦–¦¶†âYÏÿ‚7ô÷Ðû|†ã~÷ãÞÀ¾ÀÕÓûúr¶ìü­½ã½êVÿ—a÷ÃøBÙù¯ö¿¬Äñ~e™?†/~(ŠâäÂ{qþ<3tc>„¬S×Zâs´Òbþjºìü÷ûa2Ž“•eÞïÖëÿovBÈ7 É%>W@+-ýœ™+;ÿµ•¿âø ²Ìߌ×ìÿ!dO €äŸ+ •&îì •ÿÝwÇ‹q|XYæ«¿ëõÿ#{!dO €äŸ+ •þ}¼}«ìü¿ÿXߎãTe™îÖëÿGçCȺ@r‰ÏÐJ/¦ÆÊÎtóÓA;•e~ðº^ÿ?ÿϦ €äÒ^+ –{½õ²óß8|¿ÇG•e6øV³ÿ4—"ñ¹øNÿÿìÛ­K^qÇa8‚E˜Ó§8XR,rÔùò´iP †EÁ"ZA°Ïfì2\QLCV£o Ñ?@_Ë`çO<à9‡q®«ÝÜÿÁ>Àÿgrw}-tþãñEorö§žÑçÙlýÿ‡ÃRã 9ÏPIÇ'C¡ó_œîúÎÔ3šxÍÖÿ·®”…Èy®€Jšù½‡ÎÿÓòÜ|r~I=£ÕílýÿÇ¸Ôø(DÎsTÒC÷ËAèü7çÏÉ9˜zF?Ç2öÿO¥Æ@!rž+ ’W{Í¡ó÷o7“s(õŒNï²õÿm‡¥Æ@!rž+ ’Žê-ßBçÿcékGr§žÑÛV¶þ¿}¥Ôø(DÎsTÒÆýèhèüwšþþJΑԳÖ9œ­ÿ¯Ç¥Æ@!rž+ ’Î6zCçßúýº/9©gmê2cÿÿTj|"ç¹xÿÿÿìÜOˆMQð{î}3f\ŒIx³´R¤läïbŠ¥ØÈÄÃdf )Q“š ›)& ¥,$Y)ÊìQÊk+ 6¸×¼÷Ìñg1š7óùÔ9÷œó»çvß[žú^àß³ãæÛö2ç?º½ûQ1ݳs§g–ÿ_q¯¥á`N4ù¸楽£/ž–9ÿËïŽï/¦›£bv«gfùÿ•ƒ- s¢ÉÇ0/yѽ»Ìùï¾4ù±˜n‰ŠÙ³'3ËÿW×·4|̉&WÀ¼4~wß•2çÿiçþ÷ÅtkTÌ>¿šaþ²¥á`N4ù¸æ¥ oºî—9ÿ‡=Ã׋邨XxçÿkÖ®Ëj×åEk«­w­³6΋¶hÚ¾4œÅW€ÿÆÅk—9ÿî=«‹iˆŠÕþ«ßrýuq˜%#»úW•9ÿç{FýT¬žïM:¦ÍCòýíEÛVWÊîK¡Þ7îÿÞÿP/e¿Ù—&«}ò‹{ÒÛ_büóà¯Ð¶1MËœ_ÇúÉ$ ¢bõüÎ$VBXšvFiü4ÙW«½ß0˜|ËïOYSïKY:}ã ]MùA³$¬Ë“P=qvèTÿÚ£'Oî;8|¨¯ÿÈÁ¡áCÃCaièÍCZÿ6BWejK8§ñb½a ÏâÅ4#y%^ÌÂ@ËÛâÅJ wòöx±-Œ…ù‚ÅSÏ¿&òŽ%SãáuÞ™5n®ºÃDø/¬4æS¯û:íÌóx1„³ñçÐr_ÿÿìÝyl\Åð™·‡×^kæ˜Ã!‡“`C“b“8$U€„rجã Ybï:Þu JÈÁÑr¶Ð(4iUÄ!B¥ PÚ Ô ZþJU!•Vˆ”rCßì̾ýí󮉘¢iÄ÷#%±½ï÷Ýï;ì5Èó ž7ïúè!¹ÎÚÌóŽ÷`ËXŽEÊ ¹îÞ£ß9AþUrW¦Vùó¯z«{Ü™’žû±ÞÎaÓ½¿åûûòo©¿Y1Û› Üë£7k(nÇþåþ VÚ.ÿ÷3ÞÖ•¶Sîô¶«ô¼þ}wJ·úàS0¡k^e\çßó‰+˜\sOÉõÿúß:wéë•›èýПR¿s?ôïO-ÒµÏ4èÿ޿Ю}–AÿÿØi®èÚgô×NsE×>Ç ÿ{vš+ºö7 ú¿o§¹¢kŸkÐÿ;Í]û<ƒþÚi®èÚçôÿÈNsE׎ôÿØNsE×^kÐÿ;Í];aÐßNqM×îÿüý¹Õе×ôçvš+ºö€AÇNsE×NôØi®èÚë úí4Wtí ú‡ì4Wtí ýÃvš+ºvÊ •抮}¡AÿˆæŠ®½Ñ µæŠ®=hпÆNsE×2èµÓ\ѵÓýkí4WtíŒAÿ:;Í]{Ø ½æŠ®½É ƒæŠ®=bÐ?f§¹¢kg ú7Úi®èÚ9ƒþMvš+ºö¨Aa§¹¢ko6è抮}‘Aÿf;Í]ûbƒþ“ì4Wtí-ý¶Ó\ѵ/1èßb§¹¢kÓ ÿ!vš+ºö¥ýµÓ\ѵ/3è˜æŠ®ý-ƒþ‡Ûi®èÚ—ôŸl§¹¢ko5è„抮}…Aÿ#­×tímý[í4Wtííý²Ó\ѵwôŸb§¹¢kï4è´æŠ®}¥Aÿ©vš+ºöUý§Ùi®èÚWôŸn§¹¢k_cІ抮ýmƒþmvš+ºöw úÏ´Ó\ѵ¯5èŒæŠ®}AÿYvš+ºöõýgÛi®èÚ7ôŸc§¹¢kßhЮ抮}Óçío§u‘®ý]ƒãßn§¹¢kï?þ7ÿ;Í]û–üøßàøk§¹¢kÿà?þ» Ž§æŠ®}«Aÿyvš+ºömøõs»ÁñŸo§¹¢kÿð?þwÿvš+ºöý³Ó\ѵdпËNsE×ÞmпÛNsE×ÞcÐÿx;ÍpÀrÎü.¹Îÿ±Ml®ûîÜ’[6u³0ý€û²÷ y»äõY†ÕvÚþ®¾x_ðÿ®øRºöÏ Ï”ëüÛ¾öÖoÜw#%?Çß2¶¯ï‰’ÍÓY4ÿF ¹ÿT äú_'ð¶÷VgÄýh€§Séõ©¡Ñ!Vf‘cÙÑᑤ|¿ûgó;Ú¦¶¶4ºÑ±föÇÕg¯Ž/=mUßò“OÍ?—ü%|é@Y HžÊ³è‘ãÌ™9mò$wË–f>…äÄŸ¶b5 s õ•Âîíž?»mêáÍ AÖÚìÔɰ5½'­è[½²wqŸÊâWÈ»èyÅêòùe²NøùqÇLŸr¨p·hkf×ɬ%½kz—._QšT¸›e½±k^ûŒÖCëiÔ©Ðì`bs2>’Ll‰f.pÓ×ç_ ¸CÞPË‹m¬X2Ö³p~Çì©“flY³ÓOc‡Ù\r¤˜Ú)oråe6¹™—É ÒÌ•Í,G3/ÊŒl¤™á+å§¼L±U]BþÌÿÄT–ãSX2væ/£rÿu±ëäÚóêÒõÿOî_ÿÏ¡Öÿó;˜Ã"…õÿ°·Eaá³)¼|(¿þŸí¬´þ_D‹…Øn=%ëö[܇ZBlL?Të_Ò°ûxkˆ½¢÷¯ÒoŽY[ˆ}¤®/YxßêÎv„øTý`C¥µôr»î_¡·‹UZ?ÅÝ®'Ä7ëí+¯x?ÒÝrYÈ=†JS…Eìr³•!–Ó›‰ Ö¥À+Ç^aÉèïŒÉuþ?ybÚ3îÇjJ×ÿ?sºoýSÓlYþG™ÃúØÒq©NáßðÛÞ[jýÿµÞúÿªÒõÿ³f}äa‡4ÕÊÛöŒž‹"l+c|?zù¦~Óz°ðбsfN;JM¶&“œNv/=mUüÔÞSú&˜o|)™wèü)«ú––o—Õå|µ ¾ƒÌè|¿ºYû‘BÅ|ÙïÁ×ÕúöÛ9dü~Ïn›Úz¸šìü}2I÷Û™»ò´qOº@î³íÎ"2JwÙY,™[ºìn{A¶L8W ºÛÎYò°Uʘ{Ìô)G¨+…SØù:oç¹Ë;ùŒüü;!OÛd5|–p> Ü/üŒ'^+]dÖ¡³§/]Ñ{ò¸£ç Ù(Ü™¡ÞßúžÏj=,’á’Ö¯ì]³Ìßú¸N÷©ÕìÅ"ðŽþhƒ÷ÄÎ6w`ïHäý‰l2žN %ó'e5—[É­æÉëU…lÁ.ÂiHŸºùE¹„ùöÿj¼„$84áœÁD6vÛȈ‹„ª {ã}Î0v£î%‘IÇG2eÕ1¬r7fò[t¼{ñ©é]"$ÓA:½cÝ਼Fr p‡ŽÔ%IV¯ SY»Eh É Ñ¬[³£CñÌúx&·!ÇBܸnÞ9 ²»EèVóÎQ`»›wÜþŸ£EèeÂiÈçˆ$ìáÉ$Á¡ ç¨=™ð,»ï‹ðZ’  ™ β<SÔ±xV„÷ˆ Ø!ïœòY{ñ‚¿NB4àÖ|ÀæÄàè¸ÓKöâ%Q5$„iÂÙÄа¼×‹w…„½y±ÍT¯Šª4‰¨¢OçK $³ëFRùT&­v¦±¡ðÕ¼[vQGã Qõ°Îiô®Œ ûÒÁ»xç©£Cýî5æ^lƒ©´w G­KUç-Qõ!‰á4æäUÞÝfô‘ ¹GVÞ§FnF¾”¼'"=$Å¡)çS†3ã®uoܧ‘«HH€†l:EÝΦRo‚<""¿%1As%‰)Sƻ؉êz’¢)·¯Þ4èž%w¯T@È;°'Èc¢ZDõ™$ L,žuÿqg¨ø’Î[EõM$¨Šýjù€²x‰ð6Qý’žlò.‘ÐNw²›·Æ%BÎK‡¨9’Äp³dÏ‹»±¨I’‡Æœ=ñy)¾àñQ³‡¤hJzY&+_JëÜŸ0ýù_ü—‰š¿’Ù Ý~FÖ}þâ.°2—9_)¢3H@ˆìÊ '²Y÷”øCÈœ%¢ëHH˜†Ü¿23’óŸ R`­ˆÞMf«èìS‹3étr].>’Ìlñ‡_pùý ‰ÐûÒòõ` žÍªˆ/œóâ .µ3ID5xsuv0¾.á?ůÃübQ»‘L×i‡«éáDnƒ?¡øM6ß*jï# Qš0)ŸÌÇò ‚üjQûO2_KçgåçSÃî‹´?AÃVÕàFQ7›$ÔÑ„™°1¹Å?~âWÜO5¾KÔ]BÆëéør|sr$µ~Kܽ¦Ü· »Sr:ȫݢî1’Ö@Ó.\–LŒäú“‰œ:QùïuJ¿ ò»EÝ»$ F.?É}÷ïŠÜ“YêÉõ½d¶‘ÎÞ¼ü‚tF~ó¤÷#5õ'‘ÏŒ½¢þ2’ÔD“î9c45®Eñ•™‰ú12+èìã«ägD|]f4]øäò¾´x§4ÈŸõŸ’ˆƒhÄïóÅÈà ^ '‘ñf:þ†/wYU¾h¨ˆ—Dà $bø¸ð™™ÍeäÉ”þ¡ä¢ ¯¯Š†çt˜Ðÿ²@øJwÃãyûø× ò ú†ˆ5IN'—ìï÷ü-[CRšröþ~OðžˆÝNB4$½ß¯=±×HLÆlŸøµç$y~òÇʼnˆÆN’¢)»oH®Û8œI¥sä&}åjÿkÁ‰‰Æm$0Lï/X¦àbùeE嵈Æ?¼*š÷ÉšøÀy»ÌœVÑ4$Fhâ‹åËT,~ûë´‰¦!XMß$Ùä¦tÆ?UœÑô(É©!9'9ŒdF‡éµya= ÝëL…u‹âÍYáåD‡MÖŸÊ %†óíÄwÐþäb¯5ó­ÿÿ›oÜ@«nPÍç3ß þ^,w 9:WÝ šËß)Yr€#JGÉ=ŠsÕãoÐU:Gn çþgg¾Dþ ÿÿìÝ_h•uÇñßï÷œýó·ÍÓŽÖ‰tiÖfmmkH”lº#;䟱p’Í鎴p›mÇš$¦d!8o" ºvS Ô7aFÙAŠI7Ý”Õetzþüžçüž³%Š•ïìœçùý¾Ï÷ùÃs5øü€ÿ˜¼È½}ì—^Îßùöï'çu<ÿÿÝDIþßq^5þÆ¡Ä"¡çõtÌ·ªœ·*>òÿïEùÿÊxþ¿µéñÕ«–ߟ¬"™ÌqÚþvÄ!äòõl×`vk—Ö 0'“O¶5¯m|4èNÉûJ:TÛf6mëµZ²Éj±"%ûKZÔØ-.öf6-Т9º„hLÉ÷í³»j­j4ºeÝÇSÖ?ÓÞ\DsJþlŸÜµØï º•-roß@ß`ç†Í™¾žÎ™¾Aÿ«äÁ´v<»®­9h¸.¥ÚíKf±†°áE¯aWgç¦ìæ›´k³RGJ´¯Ëå?÷p醯{z³[:{¬[ô[Y-ºSê ûJ\u~ ³ˆÃb‹„i¡JZô¤TÁ>»+å·0Ë9Ì[„7â”´Øžr_fëì®%~ ³¬Ãšù7’(i±+å¯êݵÔoaVxØ8ÿ*ÊŠÀ=//ûE®ñé ^ÎÿÊ¥3cîXu<ÿÿÍhIþ¿ÌÙfòÕmB‰d”¹.J˜oU5mµùÿãQþ¿<žÿèÁºj/û¯ÅisL´®@¹ŸÎv­ ªÒZüh&«K«ÎzÙþ­[2¦v…–妤¦´öšâ÷jý³'D£–kMImI­z'Ûµ,èØ¬eŸU%íª{¶õÕeë´™7uǵûfë¤]·½g|"oÎ:­£ÄÿÒ¨ŸIû¿˜ð7åÕ9#ËEnöãë?x9ÿê†B½0ÁìHúp&öå2X ZÀ 7Jçþj¿ìòÈ÷îS¸‹Ìe«[½þ»sÕE·ã5ü[ü¾¼ö9/ç?;~þa%òýIw<ó¥U,…SGÂÄ|Ù‚ ÃßšWb.Újñ¬Û;2z`ÔÓBLØ?‘óö¸×í{f—½Ôãåü?}÷ÄJäõ‹Ò‡ÆRþJ€;àÒ¡‡•—ó_3°>3o2}R‰Jk_‰âåî_‡ÙNxWø)•>*~–Ì{œ›§DCô)¨QŸânùöøWøìù™3^Î`ÑêóBÈöØdúdU”÷H™T;ci|%^0s¿¶·?¿ïvY~zÇ>Þ¬ DòŽÜÐm"›µéу“¯îkÞ=826œ›œÌå'eRf´TáÚÉDpˆÜ¡U|PÊŒ×N|PÉò˜NÄ9.Oé²ø`B“§uy|°Lž’çtE|°\ž–Wte|°Bž“WuUMpÒ+ò†^Tl_UUZ;Qq¸Q'o¨z]ˆöýSUªU×Ä¥ªWݺ6>¨T«Ú©ÇÕýO<Ü£*^ù*ëåüOM_Ÿuw›b“é·åö@¡PøÃÚ.®PÕs^î¿þ×îð¿+ÜÿÿìÜ?h]UðsÎ}/­½F[‹ð(q±¢‚ÒAG;XJ¡88B)‰ÿ3ï>þ[‘‰µzkéx­Ë?{¨§€=cêo¾/ûü—Þ>õÅ=ÅÖòpØßg¡÷€âs|mÞ(‡N¡Cõ&Ozã†zµßf×¥ðÌú6Y“>ïÔmùö`WXxíçeŸÿï¯>5B|¥Vl-Ÿ ©–‰ñ`ªuã§ðæZí—WÂjÿ~±Ë ÕXÊýׯ½ „C䆶I<–‡xdòüÜÌÄ‹s§ß›8}~tâì[£í©ñ³ñ`<™ÇT½áP£{QÉS=ãÉ8“gõdŠ#q1oÔ“Yœ‰—òf=Ùˆ‹ñJ>PO6ã¥x-ßWOÄ+ñf¾¿žÜ¯ÅÛù#ƒÝýoÆ•üÀcÝùí”çy¶¾¸šŽ+i(´±¯ÞXÊÿÝ· À?ùî£ËYÙçÿüÂ_‹ð¥Z±õá­0Пèt:wûæ½·t¥Á¯Ë¾ÿð¿ö€ÿ]{Ò»Åsï?{·ìóÿéâ⡯#µXäO\í[œ…Î]¨:æ››nxxu]ÙW¿²>;‹a°=5ÞžœŸ 1ä!ÌÍOÏŽ•°íþÿÿìÜAˆÔUð÷Þv]}ë:•xì •ØE‰ ÚÁCÔÅÐÔDaÅÝlW£@00o]‰ÊKvè Ä’‰E‡ yëÐIÂKe—À¦™ÝÝyºv05ÓÏæñÞ÷÷þÃÿÏÌi˜ßþgö‡]Wm^Ûêó?Û}à¹f‹zýä[E—í®Þ<0&_üüÛVŸÿÊ?¾;C±>y4ôt¬kaî €îæk¸#¦öÚ' œ˜¯«·T7¹.…GgÇ0ÏžtºQºÕ§€{ÃäËgºZ}þO|±ãç↢XŸ|;¤"‰±¿-ºñSxa¦öûúÏÂTÿ~ó]k-UWçõ3'„0pGè6‰ksˆ+FߘxußÚ‰};_Û½}tçÄÝãÛGÆö¼ûã¦Sûh„Úôq[Neã¦8–«2Lq[<’keXűxÿ¯/¾÷Is¹®(Ö?Þº;ƒF£ñWÇ|î€i©o¼Õ÷ßîkwøç x }´cÝ’VŸÿû?}ðas™Šb}òh¨:ÖµéøÿóíÉõµZwý8òC3ªî~œ™ÛN·zÿÿÍ]ϹŸ>÷ŠwÖÿòx«Ïÿùåg¯†ŽŽü©b3æËŽÍµÂëo¶;æ»æ}ÃÁ©}­¾úßfgOÆæÐ;2¶gdôàhˆ!‡0qpÿøîÖ tûîw7_oõùúU8ÙLbQ¯Ož/ºüçïøþ¥Õ/}3Ùêó?ôÔÁ?o(Ö¿=ë®0w@wó5<3¯µ†FS{ í“NÌ×Õ[ª›\—£³c˜gO:Ý(ÝòãÀ}éoÿÿìÝMheðyßÍJÛ€žý B%­èEZ=yð¢P(*)›m³iªñT(Eô\¡~œ{уK/ mmoE´‚TèÁC×™d7ÙWDÉîªûû†÷yžÙev÷ö2ÿYà¿ç§¿=Wæü¿;õò³YžH†ÓWV²˜tB˜Š‹I?f/vf¿hf«ùýâ]íK•Zïë;OȲ}ù@[$ì˳°gaeiñø¾¥ã/ž;úÚ‰æ«sÍ£óc'ÂT8”‡Ø}4ÂαµW„ÃyL›! ¼’6c8Îæci³á|^M›cál¸˜×Òf5œ—ózÚ¬…‹áf>ž6ëár¸•oK›ãáf ùö´¹-ÜŠ»óÿ½ùäƒeοñý¿f=‰üÕaÑ拞“«YÌ^?׫¿²«3‰ÙíõÕL(ócó Ë YÈò,[Z>Ùœ++u'³WÞúéÆJ™óþÚ/çŠÎÕd^ûNVëm´Ûí»=ëv÷ØšÀßCÖç Iòû2çäž+ÊkɰþÙW›Ìÿßjøˆ>oWÀHšû|Ï×eÎÿ©÷.„¢¼ž ë?¿¿¹üÿÃ3{ FŸ·+`$Uδ~,sþŸ¶Þø²(¿I†ã÷/o.ÿÿHs¨á` ú¼]l?ÿÿìÛ½+EÇayɽ×"d“E¯e’"YˆÉª,wcd“M)’Y$¹f€]Þ-e¼Y âœñŒ§œsÒyží×ï?øÖøÎÚç¾Ãξôsœw‘gaf:^ÿß3”i|¤"á¹ri|·'ìüë×¶ÊÁyyÖ:cöÿÕLã  ÏK{“ÍÕ°óoY·ȳpú¯ÿï­d©Hx®€\º|kÝ ;ÿ‰òèwp>Fž…§›xýßR¦ñŠ„ç ȥͦîí°óxï½ Î§È³X:Ž×ÿ÷e©Hx®€\újØï ;ÿ¶ó¦Õà|Ž<‹#Ë1ûÿj¦ñŠ„ç È¥“š°ó_h™ Ηȳ¸8¯ÿ¨d©Hx®€\꫽¾;ÿÛƒ•ºà|<‹‡ñúÿÁ¥Lã  ÏÀøÿÿìÛ?+EÇñ²Ý#e”,J„ן”M11™Ä¢d±Ý²[ JQÊbQf%¼”Iòï^в°Ý’œ3žñ”sN:ŸÏöô¼ƒ_}€ÿgi¦m+êü?çWÏÂó!ö,W“õÿýå\ã )ÏPH?»=Qç_oß ÏÇØ³T?IØÿå™Hy®€BÚïèëŒ:ÿËÉщð|Š=ƒîdýÿÀQ®ñ‰t× (¦éžæ±¨ó?Ý™l ÏçØ3˜]HÖÿ—+¹Æ@&Rž+ jß7SQç¿vÕûžÕØ3XIÖÿ–s€L¤2‘ò\…Ô¸¢Î°~T ÏçØ³|ÿ¬ÿï\Î5>2‘ò\…ÔÛÚ˜‹:ÿ¾¦þŸð|‰=ƒæ›dýW%×øÈDÊsÒùèüDÔù_mîž„çkìÔööÿ¹Æ@&Rž+ îJ¯kQç_êhß Ï·Ø3˜]IÖÿwç™Hy®€Bª.¿D×Ôâdx¾ÇžÁöP²þ¿g9×øÈDÊsð~ÿÿìݹ•UÀáDQÜQqGE Äÿ€Xàî¨à®(% ••ÆÄFbLÔXY© *« ïÍy¸…&ãëÜ7“yžjÎwšßœÜâËÉ}g€‘gõgtçü¿Z´xFg¹£gsÒç3†6ÿ?gvéðÐÃ|]£ÒSß­ÜÜó¿n×'?v–¿ôlNÚ»oˆóÿ;K‡€¾æë •>ýiÝ—Ý9ÿõƒ[·t–¿ölÎübhóÿ×l->úb˜¯+`TZ²cáþîœÿŠéS—v–¿õlÎÿhhóÿsW•}1Ì×0*M»zóÄîœÿé?lßÐYîìÙ|þÛ¡Íÿ_;»tøè‹a¾®€QiÕÚßwçüÇÎúf[g¹»gsðãñCšÿß5`þFa¾®€QiÓÜ5›ºsþWX>o ;Á¸)+Œ;üAû†Ï÷üçÿÓÞ¿­Ç½|{çÑîþÏ'Ù ý{jÊ›È^˜èß[SÞDöõ‰þ}5åMdßèÿ½¦¼‰ìýûkʛȾ)Ñ ¦¼‰ì›ýÔ”7‘}K¢ÿÏšò&²oMôÿUSÞDö¢DÿÁšò&²oKôׄ‡È^üßûÇ”þ‘½$Ñ?¦¦¼‰ì¥‰þ±5åMdßžèWSÞDö‰þ#jʛȾ3Ñ?¾¦¼‰ìe‰þ#kÊ›È^žè?ª¦¼‰ì»ýjʛȾ;ÑtMyÙ+ýÇÔ”7‘½2Ñ?±¦¼‰ì{ý“jʛȾ7Ñ?XSÞDö}‰þÉ5åMdߟè?¶¦¼‰ìU‰þãjÊ›È^è?¾¦¼‰ìý'Ô”7‘ý`¢ÿÄšò&²JôŸTSÞDöÉþ“kÊ›È~$ÑJMyÙ&úO­)o"û±Dÿ”šò&²×$úO«)o"ûñDÿé5åMd?‘è?£¦¼‰ì'ýSkÊ›È^›èŸVSÞDöºDÿ™5åMd?•è?«$W@)µ/·]…Îÿtnp;_Ëh¼?]ÿ߸Xh|ä"ãs”ÒÝØÖdèüg:÷âñ-±ŒV†ÒõÿMÕBã Ÿ+ ”Ÿ7gBç¿ôP߉Ç÷Ä2:©¦ìÿŸ €\d|®€RªM¯‡Î¿oær??Ëè¶–®ÿo>+4>r‘ñ¹J饽¹+tþs»ñø™XV:FÓõÿ-‹…Æ@.2>W@)5þì†Î¿»þµ_‰e¥6‘®ÿo­¹Èø\¥t3r:ÿÕó…•xüN,+óS)ûÿ§Bã Ÿ+€?ð ÿÿìܽ+EqÇñßñ‡«î)LF%Åd•ü ŠUÝA ’AŠQLʪ”A20“AÝEw’?Àr'3y8ãO:ç¤ózm¿¾ÿÁ§ó>ÀÿÓŒkIç¿7¿½ùûüJëÇlýÏe©ñPˆœç ¨¤öUí1éüOΦۿÏô÷ûõû‡lýïF©ñPˆœç ¨¤Ù§»î¤óŸy8m„¥õÏÅlýßT©ñPˆœç ¨¤ó‘‹ƒ¤ó_ !Jÿ ž\ÎØÿ¿–…È{¯€*Z8ZßI:ÿïæÇRQGê/®gëÿû/K€Bä½W@ µ[/Içßÿ>±BÔ™:Æ[ÙúÿÚF©ñPˆ¼÷ ¨¢•ë›Û¤óŸ>]!êJãæN¶þ`ªÔø(DÞ{TÑóá[+éüw{[s!DÝ©cü´Ÿ±ÿ-5> ‘÷^üÝÿÿìÛ=KVqÆñß_H­|:7.Qm֦ডbƒÔkht ‡^ƒƒC‚‹‚‹.º“Ñ ®‚DÜ“8ÅÏxˆsr>Ÿõz|€ûçznìEÞùÏÌN,F¤BíÙ³ÍrýÿàQ£ñP‹ªÿ h£žÑõ˼óŸ9ý2‘ú cöv»\ÿ?´Òh|Ô¢ê¿ÚèïâÒhÞùŸý¹}‘ú c¶±W®ÿžl4>jQõ_m´ºÿ`*ïü¿-¤×éaaÌKöÿÝFã UÿÐFï?^üÈ;ÿ_/—_E¤G…1û}\®ÿ9j4>jQõ_môdçê]Þù/ÜÌG¤Ç…±3ð¹\ÿŸ­4µ¨ú¯€6ú¾öi7ïü?l­?H…±3}^®ÿïL6µ¨ú¯€6š>éý™wþKÝ»§i°0v–¿–ìÿ»Æ@-ªþ+€ÿ÷ÿÿìÛ1KqÆáÿI%à`Ó\’¦ƒ””â¤" NºuÒIÈæf‡B6ÍÔ¥ “:¹è(8 uÓ¡ÐOP'É)–Ö¶ÜxãQîŽrϳ¾ßà…ðÿ¼Þ$ÿŸÕ½ç!Dó©±qò-[ÿŸ—…Èû¯€*úòãh;éüwÎv—Cˆ¦ÆÆ×Q¶þ¿9(5> ‘÷_UôáõæÇ¤ó?~Ö] !ª§ÆÆ¯q¶þ¿Õ+5> ‘÷_U4»~ßI:ÿ•«ËnÑ£Ô/M3öÿ“Rã yÿPE/¶Æí¤óÿüöz.„¨‘ãþïlýû¼Ôø(DÞTÑû7«Iç¿öîÁLQœãýZ¶þÿñ Ôø(DÞTQíÕ÷aÒùŸ~þ !j¦Æø¢ž­ÿïôJ€BäýW@-lŽ’Î¿÷tBÔJñ퓌ýÿ¤Ôø(DÞðïþÿÿìÛ?KUaÇñç%‡s½Þ‚4„‚¡A%Z‡%p)pEñM88º‡bwi’^B[[A Ô!H(g<ã!žsóù¬¿wðƒ/ððl÷6>äÿÇGw!ĉ˜ ¦ÊõÿQ­ñP‰Ô4ÑìߋӼóúª{BlÆìõórýw¯Öø¨D꿚èr£=“wþ›'/cq²0f‡óåúÿÞ°Öø¨D꿚è¸ûëYÞù/~i߆;…1;[*Ùÿ_וHýW@í.l­æÿã¯W!Äna̾-—ëÿû£Zã ©ÿ h¢ƒwŸçòÎÿüÑ›ï!Ä^al­•ëÿ{µÆ@%RÿÐD+Ó«ûyçÿâ÷ÌÏb¿0¶–Þ–ëÿŸ k€J¤þ+ ‰6?­gyçÿg|ùGqP[;ïKöÿ×µÆ@%RÿÀÿ»ÿÿìÛ!KqÇá»7 AN‚ÛÊšAQ“i˜-ÂÞƒ‚­V“*‚(ˆ"¬ E´Ì¥Y±jlŠÞÅ‹ »cÜó´ßòÏøÃçc÷r9éüw®zAN¦Æètµ¿þ¿|k|dbÐÿPDÝÎI-éü§›ÇÝ Ë©1êlö×ÿW6r€L ú¿Šè}¢ÝI:ÿúOôa%5F¿[ýõÿÕ™\ã ý¬€‚j\Œö’οþ´ta55ŽOm÷Ùÿå™ôÑsé{$éüç[áY|Þ¦×ÇR.€‚ùœkT’Îýem/>[éUÿY8?:l'ÿÂØì~|Þ¥Wý?dámq¤™tþ+µ¿ƒø¼O¯úFÿÿÿìÛ¿.CqÆá¶9qj(% I¯Áf¯AâH ¬Da¨ˆ?‹IlF -•ˆÅ˜:0ˆè8ÎIHzÆ&zúRÑãç HkÛ»AÜù¯¿ÛѼMƒúQ—ý»¯ñŠ?W¿à ÿÿìÛ=+EÇñŹu™ä±,†;Ü«X(‹,2È¢¤W’õÿg¹Æ@&Rž+ Væ—_£Î¿Zß ÏÛØ3èKÖÿw®æ™Hy®€B:Ù:ÿòèáTxÞÅžÁd{²þ¿«–k|d"å¹ i¶1²uþÕ¶—rxÖcÏ`ã#aÿÿ•k|d"å¹ ipmh!êü/–Wáy{§çÉúÿî³\ã )ÏPH×mǨóŸnyÞ Ï‡Ø3xßNÖÿ÷¬æ™Hy®€Bª n}GÿQ¥o&<cÏRó\²þ¿·–k|d"å¹ ©õ`o'êüæ/»Ãó)ö, $ìÿ¿r€L¤r‘ñ\¥tp:;:ÿ޽“ïø¼M<+õtý_£ÐøÈEÆs”Rÿáþcèü£Ðþß%ž•Úhºþ¿­ÐøÈEÆs”R÷ÛÐbèügÞ6âó>ñ¬l}¦ëÿÆ €\dÏÊÙEÊþ¿Yh|ä"ã¹ø¿ÿÿìÛ=+EÇñ„œË¢ˆÁ`‘<.&‰’Eñ”EydðPîdSŠévÃL &³”ѳÍBÙnƒ8g<ã)çœt>Ÿíßÿüê ü?‹—7Qç?^=¨ ÏÛØ³éã0Yÿßw–g{d#å¹ ©¾\y:ÿ‹ÊÚUxÞÅžA×J²þ¿)×øÈDÊsÒqÇÜwÔùÏ7ÿTÃó>ö fg’õÿ#¹Æ@&Rž+ &w†·£Î¿a½¼ž±g°Þ°ÿ¯å™Hy®€BÚn­EÓØÆhx>ÆžÁÑg²þð,×øÈDÊsÒékÛfÔùO-L|‡çSì<_'ëÿ‡–r€L¤Çž¥æýdýÿðH®ñ‰”ç (¤¯Æ½ž¨óo?iY ϗس4¶œ°ÿ¯å™Hy®þÀ/ÿÿìÛ½+EÇa1Ý+%£””—.®’R620È$‹b¼‹IY JQwð2Y”MY0øPF\/›MIÎÏxÊ9'çÙ~ýþƒo}€ÿçx­î=ìü—[fÆ‚ó!ò,¬LÆëÿK§™Æ@*ž+ —úê/OÂÎÿ~µ!8#ÏÂA{¼þ¿¿’i|¤"á¹rii¶m'ìü?Ö/‚ó)ò,\½ÆëÿÊ™Æ@*ž+ —~®÷zÂÎÿñ«c;8k‘gáë,fÿÿ™i|¤"á¹ré°³Ôvþ7#ãÁùy»·âõÿƒ§™Æ@*’]+ Ÿ¦{šGÃÎÿ|w¢58_"ÏâÜb¼þ¿\É4>R‘ð\¹ôö}7vþ·½µà|<‹›Ãñúÿ¡r¦ñŠ„ç È¥ãjS[ØùßTç‚ó-ò,^4Æìÿ?3€T$Äž/÷ÉúÿŽƒ\ã )ÏPH Õ»¨óß¼mÏÇØ3h:JÖÿwÎç™Hy®€Bj[=‹:ÿ湑Ïð|Š=ƒÁ•dýW9×øÈDÊsÒäÑð^ÔùŸV¿ÎÂó9ö 'öÿ¹Æ@&Rž+ vj¯ÊQç¿1u¼ž/±g°Û‘¬ÿ¯ä™Hy®€BZ».EÿÐÄ~%<«±gpó¬ÿïžÏ5>2‘ò\…ÔÛ²6uþýu?áù{–ê/“õÿ=å\ã )ÏPH'£³ãQç¾¾užo±g©²°ÿÿÈ5>2‘ò\ü_ÿÿìÛMË”eÇáÌÇÒœéUK¢ \´ $¢÷>ÐJMóÝ2KK­¬å¦ p›m[¹h<Ÿ %hSR-ŒV­²²ÒÒìEº‡ó„ºÓÅÌIÌql†k®Ío¶óþ>›ûæÑÎîž»ÞîŽßö.»·ÿ¿¡t|LÅ„Ÿ+`&Ý}`Ó™ÑÎÿ¾-û7wÇïz—ƒckÇÛÿ?0_:>¦bÂÏ0“~°týhçÿé¶«»ãÙÞåàÃÕãíÿ\S:>¦bÂÏ0“Ž|±ïøhçÿèù_wÇï{—ƒ ÇÜÿŸ+S1áç ˜I'ϼöñhçÿæpá½îøCïrxçGãíÿZ(S1áç ˜I;Ïn¸4Úùï½ã¶]ÝñÇÞåpÝ;ãíÿž/S1áç ˜I·ß{|ùhçëW§ŽvÇs½Ëáë§ÇÛÿ?²¦t|LÅ„Ÿ+`&Í¿úÖ—£ÿ»Ÿl?ÒÏ÷.W½èŠÅÿ"þáßûŸÿººû·ó’Ï÷œê¾úiúû„¿döú†þŸkÊCfohè¿PS2û±†þ‹5å!³76ôÿRS2{SCÿ¥šòÙ7ôÿZS2{sCÿo5å!³·4ôÿ^S2{kCÿ5å!³·5ô_®)™½½¡¿&ÜÐsMyÈì—úo©)™ýrCÿªšòÙ¯ÄÇŸÿÿìÝMˆ•UÀñiRIÂÛJdKÍü¬,;0Z .\»J” p¯­Ò´µ²ü,Ë›eº‰ B\ -qÙ:Z´láNÒ¾ z_Îú.¯Ç{.÷÷[Í™³ùó0p™ÏÌ=õÏ䔑½¯¢ÿÑœò"²ß©èŸÍ)/"{Eÿâœò"²Tô?–S^Dö»ý甑ý^Eÿ’”ðÙïWô/Í)/"ûƒŠþe9åEd¬è"§¼ˆìCýËsÊ‹È>\ÑÿdNyÙVô¯È)/"û£Šþ•9åEd\Ñ¿*§¼ˆì#ý«sÊ‹Èþ¤¢MNyÙŸVô¯Í)/"ûhEÿS9åEd«è:§¼ˆìãýÏ䔑}¢¢]NyÙ'ïµ?§úŽÈ>U1ÿgsÊ‹ÈþlÌçÿyÅüŸË)/"ûô˜Ïÿ‹Šù¯Ï)/"ûË1Ÿÿ™Šù§þ·ÆÈîWô?ŸS^DöWcþós¶bþsÊ‹ÈþzÌçÿMÅü_È)/"û\Eÿ‹9åEd[ÑÿRNyÙç+ú_Î)/"ûBEÿ+9åÅŒ­é?}×îùO¯ûårsü£s¹àÊÜ©yw£ùØûﮯ;ŸÏSí_Hý!?WÀDê¿¶·ßîùïyóÕ‹ÍñVçrÁÞ€ûÿ7S—€‘òsL¤™ïÿÜîù/ë]ë7ÇÛËÞì¢Áöÿ¸”º|ŒÄŸ+`"Íû¡ëížÿ»VjŽv.{[—¶ÿ?½;uù‰!?WÀDúm˱mížÿçžmŽu.{{× ¶ÿÿà†Ôå`$†ü\鯭£;Û=ÿ·~ýtsü»sÙûaÀûÿ7S—€‘òsL¤MÛ¯o÷ü—ì¼v®9þÓ¹ìýºi°ýÿ9—R—€‘òsL¤Ûóç,j÷üw¹z¦9þÛ¹|äá̓íÿÏݺ|ŒÄŸ+€ûàÿÿìÜ?+EqÇñsÉß;œ[d—b²J…²¸e]%E1ÕPŠ0‘U“<©;L2ÜÅàúsÏxÆ“Î9é¼^Û¯ï3øtÞøÚ~ŽÏ¢Îp¾¹×z6cÇpb:Yÿß9žk|d"å¹ éyòõ*êüwîÖ¶[ϯØ1\™KØÿ7r€L¤2‘ò\…4õöÐuþ“O§ APŠÃf5Yÿß3žk|d"å¹ ébèò êü‡F–ƒ ÿ@el)aÿßÈ5>2‘ö^E4{XÛ:ÿŸÛÏÅ (µÅŽ•j-Yÿß{k|d"í½Ѝ¿~ÿuþ½£«APj+›Éúÿòz®ñ‰´÷ àï~ÿÿìÛ±KqÆñÏ7’Ô4'.‚N.å¦Ð$F‰ ¢ààf: .Ñ n®BSPKࢋP¡NBM84´ âŽrã‡Ür¯×úü¼€ûçÍ×ï‡yç?õyl9"=,Œƒrýßd£ñP‹ªÿ h£Ëÿóγûx1"uÆÎÅVÉþÿºÑø¨EÕ´Ñù«Ñgyç?ýrb."jÿÈF¶ËõÿýûÆ@-ªþ+  ½û•wþÓ'3éQaÌ>–ëÿŸ¬5µ¨ú¯€6ºš[Ê;ÿ£7ó©»0fï¿”ëÿ&€ZTýW@­ït=Ï;ÿÓÙô:"õÆlw¯dÿÝh|Ô¢ê¿ÚèíÆÏßyç6¾ú""õÆìÏ·rýg¿Ñø¨EÕ´Ñð§¿Kyç?{1ó4"=.Œƒ}?ÊõÿÙZ£ñP‹ªÿ àînÿÿìÛ!KqÇñÿ u0œswS¦GĤ"AöL6ÁfSAx‚èÀ™,ƒÙ4È’¾Á0‹QAÁ"ˆÁ¥a5=`p8'/rwÈ}>õ÷~ð^Ÿ«ÕÝý´ó_ÙùÚ!êÌŒñÔY¾þ?¯4>JQô_u4uÔqvþ‹­¿ý!Dï3c¼t™³ÿoU¥(ú¯€:j~Ùø“vþÿǾ †ueÆøçM¾þ?9¬4>JQô_utþ°½vþk{ë#!D2c|q›¯ÿÿÔ¬4>JQô_ut0=û+íüwC!DÝ™1~¼Ë×ÿ÷ŒW¥(ú¯€:jŸù÷9íüGOO!D3c2|Ÿ³ÿoU¥(ú¯€:š˜¿ëM;ÿãåßïBˆâ̘Ì=åëÿ{+€RýW@}_ÛJ;ÿÉͶ7!DIfL~¼Í×ÿ÷5+€RýW/÷ ÿÿìÛ¡J%a†áÿbGç.– â‚bSƒ‚A, Û6fåÜ„a£æEQ›A¼›M‹˲ ¸"ÊĉÃ23ÈJQô_u´·}5•vþ'=ëw!Ävfê[Ë×ÿwv+€RýWÿïÿÿìÛ/K]qÇáßï LÃÎEPï?ÑfÐ2‹å†…Yd"Œã‹cE¬&q`+ƒ•…1n¹U dÞd³ “‹¢˜T'žxçäJQèY5µòeä<íü{ÇKƒb'36fwröÿוÆ@)Šþ+ Ž~ŽÝ>I;ÿ…W?BˆÝÌØxû1_ÿßíW¥(ú¯€:ÚŸ{÷+íü×ï>œ„§2ccï _ÿ?µYi|”¢è¿øÿÿÿìÛ1Ja†áÿ?€.³c ‚…»ëj·]n"z-bJA¶RDO S¤I‘"KjbaÐ&`a“T!p;›íaÊ)‡03„yžö»Á/ðÿiJQô_uÔxøáiÚùOÏî‡ç3c²sž¯ÿïô*€RýW@=»YL;ÿÝ'¯CˆÝ̘¼¿ÌÙÿ+€RýW@½˜ú=H;ÿ·£ëƒâBfL~~Ï×ÿÏ+€RýW@}{yŸvþgÎ÷Bˆ‹™qzâW¾þ¿Û¯4>JQô_ü»¿ÿÿìÝOŒ]UðóÝû¦é™™>X˜©+I:ýä&@RË€$@…!M ‹É4¼1g¦ðæµ %ñO£‰Ñ.è ucX ÑFcŒP\¹aCRc‰+c4±;˜¸¢¾ûþ1—ÚE…b”ßoñî9ßù¾sï}ËÉûÎÿ{ÞüãOªúü±yå{)Ålmq澿^_ÿÿsÿÕæà#q£ÿ^GúÙ}T}þ¯þhùÝ”b_mqæéƒ©¨E"šÅ+ýßù~í_¤cƒµ­;.W½]f‡Ÿ•²V_eôäñ>–øTN‘žZX|ðèó?ôX4ãPŽb|°žý¬x4õ`Ä¡8‘Ëz°ˆGãTnÔƒeœˆ³y¬Gƒ8/å÷Ýìl\È;¯ÎžŒ—âbeOö³/Ä¥Î:©õƒüÎÙªÏÿ/þnJq ÞÿÿØžëîÿŸ\·ö]æôÿÀ5uR«ýÆ'~_õùßzë›?N)ÖûÿŽ]wÿÿÔàºu =í?¯ÿ®©“ZxçÝ_U}þ·üò‡¯¥wÖûÿŸ¾ýºûÿ§×­ƒ—G£9ýÿpMÔúõý¯þ£êóïüíòñ”b®¶>³º8êöï‹hÑ?`pJ@‘Ž Ö¶î<_eôv™~VÊØ^Ÿ†³©òN’øtN±{á©…Å'î‘ù…/>2¿͸7G1>È™jô3ãñ\Ôƒ÷Ær.ëÁ"çs£‡ƒÝ±/䱯hÞß÷ùx9ê8üäáî>F¼òÎѾÓýÌ—ãb¯#.Ä¥<1ºÙôpÐŒ‹Eä]£›5û[\ú _Èý_+Sõù¿ñÓÓßI)îº2Ð[œùÝ÷ç_¯¥q.í¬±’ŠÔHcWm¸{pݺkx–ÀÖ\{sb±³tbµµ¸ÑYêlTIƒº™œþY=[¯®üF·î3ñV­neý™ÖWÞ«;°·WwKîwPöêßìÖÝo÷ë6V—¾ÜZl·V—N/®žübwƒå“UÚìm½ÊÛr÷ýSêµÎ—cßêV*oÞ^¹¶´Ñiµß_v0§NwÖûÒÊgºeŸ-ön/;u²ý¥meðúÿÿìÜ_h•eÀñ÷÷¼›Û»Ç½¶y²v¸ØlÚ΄"aš Ý*S\±576G%D^hvDà…îŠ/2èÆHHSºóbâ "6í"Hhç<ç¼=ÏÎ{(é ¿Ÿ }ü½{¦ï™·ß€ÿ™ioøëW>ÚZìüïÿöÍsž'ëõÿW«úÿ“åþ¬Fÿ–°n¶rZ;oúÿOkõÿ½&ÿªóÿó=½µôŒìÝg.æïwoQÿ{ÑEk@ñâ‹f@ ë¼E îT.f­(^í1‚…O`Ñ€.÷ªµà¯{k‚ê÷žµ x¯n?mÀÕ´7üÉ‘Ÿ?/vþ{›ûæ‹Å½ó<ÿñ¦ªO‰„*0ûÊ[”÷VùÙƒ—¦¼R¾¿ð]^¨üZä+û¾ ü´-É;Õ‰¬ÑžäkíP6iQÍå/nk0Wd§VîPd“Lhß*Ù)Gtƒ;ôeBNèFwØ GdF/s‡rBÎë¦VóýgäŠnΙóy¹©?ýâÊ!’+òP·4¤6ÿÜ›*ÐÚŠ<¬Ç‡xl÷Nÿ1[ìüw´<ÿ£çI¿ó0ÿEÑÿïªÕÿ÷÷y¦ÿï/õÿýiÿïÛ÷Óþ?\’ª“Œþd|ßð‡™ý˜Õÿ‡Yý˜Õÿ‡Yý˜Õÿ‡•þÿ’nr‡ËdF®ëfwØ$—ä¶ZÍ_z]îë–œ9ß.¶ÿ馀°rˆå¾êÒËÓ¥qéÅT ÖêVw(ªKmÑ9w¨ÔZµK·¹C_myœžPM£?¼^ìüyõÙ)Ï“‚ó0ÿÕ›ýÿªšýÿ¼gúÿB©ÿ/¤ýƒ}?íÿ£%y¡:‘>íÉJÓÿÛóþðî©á±=wM¼»{dü e³µ 2údÈÚ™ ›eÒÚ™HŽZ"³`RNY"³ਜ³6DfÀ)¹lmˆÌ€srÃÚ™ —åNy€/7d¾¼À—;J[¢Ê!‘yµÊÚ˜ úß}š€¿óý‰Ó~±óïùîí[ž'ÎÃü·ŸU÷ÿþþZýaÖ3ýÿ@©ÿHûÿFû~ÚÿÇKòBu"½Ú“vÿ¿Ïéá©Jü¿ÑŠÿcÿ÷Ê+þMü¿QÆ­ø?6ñÿ9lÅÿ± òÇå¸ÿÇ&þ?,g­ø?6ñÿq¹hÅÿ±‰ÿÏÊ5+þMüQîéÀ6Ë5%ºÅrOují[”¨n½ÜjÕ©6èVw¸\u«m:ç[Õ5ªÛÜaNmS‡tèÛÔ¨:¦#wªCꌎÝa¤Ž© :q‡±:£æt»;LÔuWw¸Ãv5§éNwØ¡îú±^á;Õ#¿KçK{üØ_­ŸÊ™s—?¨W¦{âÊ¡Ý_ío×O§{ÚKÿ'üA¿~ÆŠ¿Ý€j/ÿºu®ØùßšÞûšçÉzçaþêÁêþ_MÖêÿ¦<Óÿ¯/õÿëÓþ™}?íÿ“%y¡:©îÿ?˜˜z/»ÿO²úÿ$«ÿO²úÿ$«ÿO²úÿ$«ÿO²úÿ$«ÿO²úÿ$«ÿO²úÿ¤Òÿtk)ŒoTÝjPçræ\PCº- ã“Ê¡C ªI¦ |GéÃRCÿìÇOŒ“?}YêüÔÍŸÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÁ!€ ÿ¯M¾ÿÿìÝËnWÇñ¿'ñ=!7«• R“]‘Úb'NÜM%Ìd ¦±Mm‡’c.USÛe”J]öº`ÙG–R•]¡ËJ}„îr:ãëØ®É¥Äøû‘g~3öœ9ƒ"~:Àp{š¯\yR¬<(WJùíBѬKù+ïôaK,®¿Fb+õ×Åp¬þÚ$‘ÅÈÊrx1‹-I8]^ Ëüò;Å;ÕZ¾2?/¥Ýê[o9ï°ãCjÀówFµÇ¥b¥úåƒJé„×°ðÊʠ翉Dzž¿-/Ë|øÞé#þü\þOÆD¦]Öc²^äbçæŸˆÛÞ\heÓÖŸ—û"—[ÁëGÅüé œ&ª½­\ƒÏ›•[Fæz:“Œ§tÃÌêkF2Þ82ùžGþ5­þú#Ë%ãòLîZ[åkkÏc× ä–|$cõãÏÄ=®….Ï‘õiÁ\"idÌT¤ùÄ?¨ÿÕ.ˆÒÿ`8tõ¿Îpyƒ+†sg;0vŸŽzÿ+ ûò·&ò\Û­·Á>–FÿË[?¾/ÁÀñú_ÜZƈ¯š‰Uq‹ß¸m¤rö¶G&ÔªÙÞ÷J°±]/ŠùÄ›ModtCü2ÑèbesñLÎ] ±k½Y‚­rÙwñDN&d&eds‰ÔΧNÊ\w–Û¼eÈx ²Ûd×®J£æö[AÀx&­`Ö öš7¸ºç²²Ï˜²Ÿwí¼p‰ì5ÿ„õ–»Zç-û*EG ZAÉLصG09wé’]9ñýج¹©öä©Ö=)紩Μ©Æ„)Çl©öT©Î<©ÞIRý3¤DY3’V`oÝ0Tý­§ö×ðÌ©ÿUÝ)•ò•]óÞ®ù¨\­Ù¯õÌí|©xx+ì°þ×b$ÚÓÿZYŠÆè†Þþ—y´þ×ç­€þá«ÿuÔßtž'g7u8®Á ¯‘þxß~ùõ¿¼òB~ÑDLm³Úý¯ÆBè/Äç=^ÿ˽–ÎæÄÝUïòHPOoX{vMÉ^î+»‘4U.ŸL%)gâ—©øíÎ$`¿ãLÆÝ7_Úµ.מ5Ѓ¬ˆÛ.m½–NiËc7°¾Ò:=¯ú"aWÏÖßn9‚€ÜqʾAg«skªû¾T÷M©î;RÝ·3e«sh@ÿ«|ïûb¡Öi~=Ü*ßËoÙůÚî“#T¾ºÖÿZêë-Õ¿ÿ“þ×û×ÛÿÚ:Zÿë‹V@ÿ €áÀú_8ƒË`3g;0øàü1òý/Ÿ¼’_5‘-­ÜN;ßÿøJü¾ãõ¿&Ò×nzså-·\hî6ÿqëi¯ü]Å0__1ÌßW ôÂýŰ ý] k¯Õå¾#¿;}ÆOŽÕ¼¼vSÌè-†%{‹a½Å°»Ž 8Õ\¬(ÇT¨®yPŽI ?v†ô¿ìe¾ª'ý¾Ç^‡ô¿Â±hOÿ+².Óÿ: .Wÿk¿sHóY?ô¿>kô¿àú_ƒ‹E§3§œ'¹F½ÿ5&÷åO±¿é±½¨cý¯û2>v²õ¿BúF&c¯‘¥§S)CÏ%Ò©¬xd6—ÎÅ×»Âþu¼B¡¼ѯJóëg­à7GÐXƒë?® ú>þí½¨ýŸj±Z}\Þ6ó…Byg»fÊÛÛÅBÍÌ×j•c÷‚[ÿ)Ü¿þSt1Bÿç4ô­ÿÔùý˜cý§l+kõ.·ú? ÖFÿÿÿì]l#×}Åÿ¤ø1œ’⇴ËI¤hm%íJr‘¤Ý9’¸Kq”Ê–S4³Ú²»À®d¯´›l£2ê‡náñC4EÐä!0R (Œ íKTAœ¾ÔÈS§ hÓ èC¤Ø"|sï ɹ3%qíMóü{9çÎÇ{g®¼ôÑù–Þ6ýì`;ÀH |þS‚ž¡»:ÑM}¡£ ÿ_ëJ&úóÿä×l«b:N½æ4ÝZ•’¤ͦÝ)èm¢ýÔsƒ!ßÿ•óÚWcåRþ/µ¹b›FÕ·~eÌ'D@ÿœ¢¬Ù¨ºí4iþgϦPÚ±ÖíŠIÒýšv¢ž(÷§ú›ü`ÒH“ªüé”rÖj ‡²Ñ"ƒ¹p‘ÁÕ4>–©¥º±ìPB-—E]ÅÅ äÇX%3\Ð$!•åB‰ û-!­U÷cS|Cì! *é•ú²T¹0£óC>QÅU>% š¨m¸- zJUénœÂ²¢>â_ƃ“ætÞ—B^«ÐG30.*(¾) …I~•ï¨Á½ \ø¾\¶Tšš¢WIynœb÷¹PÖ¾×Õàæ&Æù!3UÚ‡LŠžþ‰ô”už.Öž&?W,x¨˜ÿD1éqbg‰I…½§èˆúŒÁÃsXAÇðcÃ¢Ï ë~`Xçia‘G…yÏ #ÆOÙ4WùâÓ²ÉPàñ!q´ÿowosoë–÷ñúݽÛ÷ÄxŒÿïüùsQÿßìüùYøÿNƒ¨ÿoVé4åÿ[m ðÿÃAØÿ‡¯Ùp<½]O3ƒíå½™ÑöÿÑéýcÏeˆf•Gã²ÿ¯èµ_z'ûÿÔºU¹ä ‰²”q>Vw›æF“r”®Ö–M§IyÒýO~Ã8åÛ%#[ÿ•V›‹Q'a)ì$,÷2 N¾ú”è€iÛ KŒžm6×í†Yu¹ê¹¹èÙ¾‡2»j:ޱlú½ORšŸÝ²EÍÌ“†Ý¨5–>Ž9ÛzÒq¥%Þ/³Ê‡Rõ‡ß&M¿ÕÜ0Vk¼7|<ÏVøôðÝæêš[­9|źéðÑ-ÉM-U§‚cÖÅ-/­×ëîE‹ßm–ÎÈšm4x½–e[-žÈ' $o»|T+—„³¥:£Á'¡èXvÓå3ËwY3‡_·Hš'úç)‘êoñ›~KoÃ;x‚r Ëõ-zë¿ÃI*qaÙ²ª²úq‹÷7øÝîÏä¡îOÏÔ™ˆš:õ¨©³5uŠßˆ{tL5uºQS絨©sG6uŠ=>.›Í( ýUœÎ>ϯý†0u¦W.Ó ’Ë3¯ó=þGÚc<á€þ_Ú£ \žÿ,ù@‹žS4%±Ç‡“P>Ðß$ƒŽMèšF‰T+žQ˜:‹ù<)©àDvq?vV’i~Ž/¦¥!cú’ÎqáeIPÄíÿ“$dÄÿ" êY.¼* Z‰ ÿ& ºp¬þP²g¸ðcIȉ©üIÈ‹sü\ÆÅÌýR ¢ví¯%¡(f.®BIt]•„²Š’0!îåI˜—}¿$$D×S‚QO ³í¬˜m†s¶³þ²öâËüõ–IË. ¯¹‡yh1ÝYÖµÂ2y¹dþZÉÚ % ­’¬³D²ÐúÈz,ެ{edÑe‘¾&2ydÝ«!“–BÖµ²`du–?ZûX÷Âw"?òûO’ÿù¬¿ÿ9?= ÿïi€üO`4@þ'ò?Ãò?‘ÿ‰üOä"ÿs496ÿóÚÿãέ[›·ï¹×nî\Ù¼é^¹çzíîöæ­­¸ñÿÍÌÌÍGüó3ççàÿ; ¢þ¿—c¦£üÐàÿ†Ùÿ†‡Þÿ·9?ØŽxDZuÿ_Š^¢ÿŒ½kvTáÿóy‰Ò©þü²­/IZÅZÑoMÃæWÊ;ë«®dáKS~µÖ…òÆ˲’áû²’ž8áÓ¸@­¸@apûë˜d£ËsáIH áó’ áK’ÂW%Av’7ÁÂwÀÂÝgá¾³pÇñ-Ó;þ¯Ý­ÝÝ;ÛîÕíí­«{îæÞÞíÝ €;Îÿ5=s>šÿ¶0 ÿשõÝÔ;M’ÿËikmÿׇÚü_ÀpÊ`?ïfzÿCv°`$ÐGÞÿ• gè®NtS_è¨Âÿ÷>=CÉDþ¯üšmULǩלVÕ\Õh6mß–"ÍÛx¨¯›”¦‚eWk £î®YNÍËOKä5M\{ê¿ú˜C”!a)ÞS!ä¹Òø´]ãÂ~KHø!7ôVY.°pXçú,¸8‹^ßüŒ"'©ÿùã¿$ÿ‹ÿ×i€ü/`4@þ×p‚ü/'ù_ÈÿBþ×èrlýǽ­[þÇ– ìÊ=÷“7®míî< ìÿ×¹¹ù¨ÿëü<ÿþ¯S êÿº2ÿ×b[€ÿ ÿŽ0“ýÞ`;àíànz´ý_qz/½ÿ£1¢û±w¼Âÿ5æ}úR¬\êÏÿ¥ûwnÀÒÕÚ²é4)EºÿÉmšÂù%;Ô.gX¦Ë¦v9ô.g˜N9qžºU¹äÉ”%M¦m[¶C9ÊŠ­' »Qk,;”§¢Ø¶­'×XZ2+M³Ê‡\GtÌF“ Ò^æ†Á»Å÷*Ò£B¬Ø¦Ár›«knµæð«‹uÓ¡‰6·ZÊ4!Z³Î/ç.­×ëîE«Ö  šŠê¶ÑX6ýÖI*H­^ýŠ4µ¿©9=‡Ë§ªr‰ÏÒ¸ÔâTŒŸ®IO²ì¦Ë‡—ïºf8ïÚŸ*¯Áï‡â˜¯ðAâsÞÉT–[kTÍ wÝá#¨ùÝáâ²eUå´¥šÍŸÇ4| ÕºÑÞHè•/™nŸZÖ¿ôÊeú®$¤tE¡ßÑÙçËDoëŸ0NG­G­$AŠ$hBX“=Ç… IÈŠ«\–„\– ×%!_äÂÓ’0.ÎñI(ˆ=ö%¡ø(>+ ¥3\øœ$”'¸ðI˜˜âÂW$a²À…¯KBBœã›’ç·e÷ä$¢îÉ×ä!]]B!üHBq/?‘‡P\ögòj¥ý"F/ˆe¦ ð!T¹ð+I`ÒJÂüŃIkÈÛåÊ ­,X.˜¼V°®…‚…V ÖµD°#Ö‡®6IŽ® ]b°,°èûÜ%ø/8‹¼ÝìÐW›…ßkz©Yèf]¯3;ü]fÁ‹Ì:oñ;é;ö~òÿ®Üs7¯^ݹ³½×_àqù³s³Ñü¿ù…ø?Oƒ¨ÿóÅx§é(ÿç¶ø?€á äÿ<é×éÃÌà†ôKo_ja°€áâå‘ÏÿSèkôZœèÅø':jPÿõk”Qú3&×Ó¦$%W,Ïö)ç>×g"9=-ºë„}S”ŒM^|…f%!%JAb g ¼˜ŸŽGLŸ‰GLûñˆ)ð³’ÀÄ3qÛÈzø¿v·öî<í^ÝÙÞ½skëöîɳþãÿ×ôü¹¹ˆÿkzîü,ü_§AÔÿõjÐt”ÿë÷Ûü_Àpð®ªÿ;Ê2¤ ¶oÀ€ørlÔý_qªÐø§W)Ï·Æ„çAªÿZ¡±xŸþ¯VðŸb6D¨U•É‹*תd2Âh¡ã»/ŒSžQªµ?#ö”é°†u*_Ê0ØŽÀÛÃ/S£íÿ‰Ó#t%^NÝ+TÿÓßøjßõ?ýܧd(÷)Ê}Jwå>)]¹O™®Ü'µ+÷I‹VûÔCÕ>³‘jŸ¹Ãª}æ£Õ>Ç«öY8ºÚg±gµÏRjŸå#«}NRís²gõÎï’îoŠºª}&{UûLuUûLG«}*ÑjŸ™Ãª}ª=«}&DXW(½K„u}‹¿XJ„u=Ô£¼MïZ‰¦w­EÓ»6äô.Q±òr\®G‰Ëf#‘`¹b$,Ÿ‹D‚#‘`QÁós’Pe0¿ %QÁó+’P<¿. ¢‚ç7%aRœãÛ’<$!)*x¾& )qû¯ËCè씇P?‘‡PÜËÏä!—ý…œwö¢ÎPó!äìç‡ÃÐÃÿ¹wýöÖæ'ßbî[›ãê.ÌÏ„ýŸ3ó çàÿ< ¢þÏÇ’¦£üŸçÚüŸÀpòâ 28š#s&Ï ¶oôàÇFÛÿ£½'æ$‰Kþk(ÿMõÚßËçú3ªÍÛ4ªn­*Š€¶ìŸÉæSkÂ;˜_³­Šé8õšÓ{(T¯th&¬yvR5|du‘4*ËJÅZå ©’>س…f©(kNÓhšü¶C;ÖKå¹fØÂÎÜÃ8%m«nR²µ†Ó´×Wy»°-ªå2-És—¼¸ûBðl‹É÷½þ6&&¼oÄhq¿uˆR˜ž¦Wøû­=2…?}…þKÔü…úb<´2?äÏÇAîÀ¿£Jû¤ÙâGè%i\AQh=AgŸ/½!l‹âÍDÐq‘Ðw#RÈf2 $ôuÄÏêÓÉÂsɢɢ³ÈÂSÈ™?<Ö5s,:m,:gLL“g«w¦à±ù×¶vÝë7v÷vnßsoîl_{KØqþ¯óç"ù³ sð Qÿ׳'Ëÿûã¶ÿ0„ü_ìyz[jJƒí ;¿3òþ/•¾Gÿ'z6~o%¼ßÝþ¯´×þ=ÒÔ·àÿÊøé`üsвf£êv¶Ó¡€@…ÒŽµnWLÊîG‰1aüRýM~0i¤Iñ:¦Ó¬5–ƒ³f©Ö<ß™çÕŠË^­ TIH‰¬·"–¨´¡{„ó–’^9 ¿“½Z:?ä/âÁ!ª¸Ê–$h"Qî–$x^­;’-MM ˉò\·Ïª}OL69mÍ0&ë “âÔ¢ƒÄºGˆó¼U«^pZÓX6™wè©=†£‡ÿkóêÕ;Û{oOØqþ/þO$ÿkaffþ¯ÓàÍX&äÿú¿ )®ðe©‡ÿëCmþ/`8úú¯ýÒ=½}GÙÓ™xØüÿÿìmŒc×YÇ¿¿Ží±=3›m•&ˆT¤ó²;[”ñØwf½ë¹|=Ù]PëN¶ÓdéÎn43Kê¶Í‡HÉ ªhA”~©¨Pè  ®$PŠDEùä P)B!D„Héá<÷ھϽמ—Lv&ÿvìÿ9¾÷Üë{¿}mÂáQ÷¿¢tƒ²!¢ÿ¦¹~Êþ—SçÅ¢\ÿÕ.âë®§ru­e×gª6MÓ¨¶ëMÓ¢ÛÍv¥á £±™ïJ ¼4èœâår™Þ ª>F]M‹©ü(»ò”]mjÀ~U`§# 8]ØWý¯íÛ››ë[Ïvžx¶s{{c‹Ú:7×77öVÄöò¿æfÏúê-ÌŸƒÿu$øë½Þ_{×ú_é𿀓Á¡ü¯ã68(Ã-·‘þ7^yÿ+A_¥r˜èõÐÕ~Êþ—#B|•’‰wæÉò^qÊT›k¦½‚_‹—´ÖV:¢”W’ò+uS&)ÊW_–IZ÷©\‘IÐã¢]l±=FÝ%¹×·Bn/{ Æ?A’ƒ¿AŠƒ¿Ašƒ¿£˜‰B\î¡)ïq)ïA)ï)ïáÀD;†ø_Û;·Ÿî\¿¹½³u{sã…Àöð¿fΟóù_³³só𿎿ÿõÜþü¯÷ø_ÀÉ ŒUßC„B»‰ZÙã€ÊŸ‡FÝÿŠPƒ~Cæ~.4a?K‘ã94(9 ÿe_1Jfe±aðÊq¶œj]¼ÃŸîûzV,™JÑB”¬t—?ŒÇuðœ”-Xu·d/jXS¤®–2›ïÊ—6CüŸO]¿±!Ë>¤ÜS€=üŸù™@ý§¹……sðŽ¿ÿ3î7íæÿ<Ú àÿ'ø?à0 ·•î?ÖqpÉÆGÛÿ ÓEÃÍ…×ûµO\ÿçÅP¹t0ÿGÖ}Šyê>ÅuŸºOÉ@ݧT îSº·Õ–Q©QFnÕN²r«v2&·j'9¹U;ÉÓ}¼smeQGÍ¥ÎâÕ¶a9mÊ:{¼Üª· §‚8;*RA‰•¨ Ŏʺ—{,v4A§íÖiœìéJݪÒg¼£83öbòÌØI\ž;IÈ3c'Q.«åñ¶¸¬ÖDI¬8×ÈzÁ_gë‹þ:[_ñ×Ùúº¬³Åý¦2ÜãDåàeŒqðªr|Gùûtð½»>d!«ƒ×Eñ‚¾/‚"?A‰ƒ7EPæàmLœÖA$ìîe’%v{Dy`%Ä8˜ûNáƒaß)|X÷ ä˜;”w)ïRÞÙ£¼SG ›7JLå›1Ê7]”o®(ßD¸§Å"Ê{½+ïÅ®¼Wºò^æøxÙsýÏMç¡+ƒî<µµ±þÉýk¡{ùŸóçýþçùsçPÿíHðûŸ÷çþl/€ÿ œ à‚{Áp/ôÁ㌠?yÿó4=Þ‰] ¿<ÀÿüÆýÏtû»_zíHÍPŽ·ÓhV/Ù1e)ÃÑj5[Ñ?»\i™usÙ¢ùy«yÙêT––ŒjÛ`õ3×-=^}I¸½Œ+=,ÝkœÎpXÕG§_Ôi¯¬vjuKï•‹ÓYúÓþ”¿¹ÛR¢ n±Œ†Þ]gi­Ñè\lÖM*Ó´?oUÌeÃi qÑj7èweÊŸuªŒê%úö×i-ˆ-YÕŠ©ß­I;j¶Ú}zõ¦W+–¥Çßõvíg ç„9‰>Iú½s{c)ç šÍNݬW:k–>ƒigø:\n6k²%š.—yÅÙÅǨëG²sÊ¥9è/åzXÅ4ïWLs~Å4ãWLÇüŠiѯ˜æÅ´Š~ÅôŒ_1ò+¦~ÅtÚ¯˜Ž;Ši?˜œò+¦¿b:¹§bšó)¦IæEâcyDiÞmUZ©ýé~üTÏÌVî´VrN«À„VžÙ¬SYí2m"öÏà@èN_埧À™¸Ê7 ÕÀ)¨¼óOy&ŸòÌ<˜vjðœÃwÞÌîþç3ë×õŸO]ßÞ¹µõlçÆ­›O¾“u€÷ð?çæÎù×ÿ[˜=ÿó(ðûŸfúM»ùŸíð?€“ô?¾`Ÿ ÿ/gŽw`ࢣ톨D+¡W3DfÞÐÏ¢4EŽÿ™³ÛWç¦'¬Î«f­Óžð¸¡IJX͵VÕ eŒå1>ÓÎSýbÊPF˜ŸYŠ[«u“Ï\sñ¢cPÙ¿qr”íöÆó”q´'ûY¡ßؾºÊµ<'»Oõ¦Úöï­Ec¹nêßeã¦aµëæ²;蕼™½‰2¥›ú÷^¥]o²¶YðU)Ôç2¾Ô¨,[Žå‘–cŠ%>ÄY7,éàN7H°9M®™L\¸K¿"ºÓ R\Ñòãa÷%iÞ˧Da©ñ¦²ñtš~)L§9ˆ°å˜«Ü¥_»ÍeõX‰¸A>S»K?rƒB¶z—~$‚qÖ ¿–#+‹™vw[*MOÓߤ)ù¹îêÎå´ñ únÚ=¸ vg3Tí½d’GúSw¤ÝˆëJJˆÎ¥Äå¤ú×’’–!_EÊs )qý(÷âQâÊQ/å¿fTð‚Qý«Eù.e_'Š”ÞdÛX±åÅveÙPö8ïÍ`´ÙwýÇCH€{øgÏÎûý¿ù……YøGA`ýïd¿i7ÿo¥ÀÿN^ÿ_³`o†[O³Ç;0 ä©Ñöÿ"ôaz ò¹Ñ\òLXúE»ýÒ{ÙÿK»UÇ(eý\£Ó6®´)G‰Z}Ù°Ú”§¬óÈi(P¾ºÖjñ^»K÷Ê€E¿IXòš„åa²àeW®òŒVËlòÙkíµ–iÔ::µm.ú՟ʱò*ˆ3ú%ºE-ã”ê´LPÎ[Ì2Ii·eªÛÚ/b™¦Sà Xf¨4 xe–Æ…+ÇhjHÑÊy Væ©4 Xe²²ðä8ƒE'‹”'K”v‹M–»OìOPÎ[dr’J LþA/Ë3ŸÕ=þ]ô(ä»Ko‰ãlyþ‰ð@‹¶)uƒ÷x$æeö@s6‘Íd(§iØáœ,æó”Œ»/‰Ž-Þ A,¡·ñ[ q ùœþ^ÂWºò÷EäÃI)îñ§"HŸÒÁ+"È”tðš²l¬þ­ƸÚå?Š Ço忈 ÏÛø7Ø Ìÿ—ƹ„æÿŠ Èï\8)ªòÐÓ"(sPÁËiLònA”‡þI÷¬ÇX¶Kº²í½0gEmÎîÍW9÷[%n»Ê{ÏäÐnÛµâ&«wX%o—ª[)´_%Ô[!Ô­ê­ :¬*è Š j C*zª€¨*«+ŠªŸnÅÏ~µOo¥ÏU>÷ã#°o¼oÿ÷Úí­-ýàÔÿàÿÎ-Ìaý÷#þ/0ÀÿÀAÿ œ,àÿÂÿ…ÿ ÿþ/ü_ø¿ðáÿÂÿÝ\ÿÉíÛOwv®onlm¿å×ÃþïÌùÙ9Ÿÿ«Sø¿G‚ßÿ}ÅmÚÍÿ}¨ÀÿNÒÿ=ñ„vó‘2Ç;6à˜x-4ÚþoˆÂ´Dÿ¬½BEý,΄íÿ:,Ø›ŒÙ¦l¬§êÚÏ¢±‹wù›‰¾ðË|èCìZ$+=;Í–¾Ü—(RÕ«Õ†¡s³iÕ¦YS+õjË}ÜhÔ»Ûõê¥wú Îÿç©[Û;këúɡ퟽ëÿÍ/Ì{ýŸÙóggàÿ~ÿçóÑ~ÓnþÏb/€ÿœ ¤ÿó?Ç8À! ÷ÏpïÇw`œpÞL޶ÿ¦P=òZŒèóÑ/…CaçÁö"vû©ðA‹ÖEꫣ؅¦Õ¦8åùgçñJ£^ãúI” ’µ¶Ò©6M“‹u Ú%étµ¹f¶;vïE.+eÔz)ºßid/¨n.5;íVÅ´ê\¾¨Û%è¢?AéO¢K†ÊNûƒU?Îö^Y©ÕZƒ7>èØx®¿ñj«fZ½8O“â°*ÕF¯¡@gºãmv*kí ÕÆÚrÝì5Ó}Ý=ÛŠ4ÕÝfŬY*—Œ^K‰N9-«­æ•«\ý©Õk*÷ö'šÄp&zͼ?}Xõj¥]oöw9IãN³eõ_2ʤv]<àlc¥rÅÙ÷Ðû韯=¼K'}Öõ‰\ëTœ>èô®K•µ†þYiW+Vÿ„$zWUݬ·ƒ—\ÉiÔ[¥á^kNºf^2›—M÷Ë,Õ[úM´ ÃÔ×RºQé=ÉÒ¸Ódwu²1*ØD4îêÙ&¸ØÅÿ ¿JºÃEϧRôJÄuâ\äíÕUù%v»Ó:øŽR÷ëà{"Hsðº2e|_YîñŒqð¦rü’·EçŠ~‘¨Îè #‚ñûtPA‘ çM‹ ÄÅ÷A™·ñ°&8˜Á$—´{DÑtPAìa\Aüƒ:°Dà3ö "Hò9½&‚Ô„>-‚t¦T¢í(½À·¿ñ¤>…i<#‚ì¸~EwºÁXAŸª¯*žóÊ{÷SÁ[ŸzßS{Üôüíþ›’p»S{Üëüíö)ïrjà-NírSÃnnjðM ¹­óÀþÞДÿn¦ö¼5íÖÃw_R»Þ”ÔÐ;’ ÞŽÔ {‘roDªRþ[òÝ©«†¥Ìæûè¿:¿ì¹þ÷“úÇíÍÍõ­g;O<ÛÙyjkcý“üÈîÒ¹¹¾¹§"¼‡ÿ;;7·à«ÿ·°pö,üߣÀïÿ¾äþûÁnþïGzü_àdð¾ªÿ7‚ ÷%GúŸv~3<ÚC” ¯Ñ[!¢—Bï§ný¿¯Q2qˆõ¿åßqÊtÅ«v¥¥w›gN¬ç¤üJÝ”IŠò•Ç—e’Ö}*Wdb/¿’Ë/óâÊ,1sÀ¢eœ×Û}!$ÖÎëà‹"Hrð¤8øºÒ|SÕtí¢…îñ)ïÁ)ï‘)ïa)ï1áÛ¨£cOÿkgcÓyè:`ë׮ݺ}sgߨþ×üÙ¹Ÿÿ¥ÿœÿuøý¯‡"ý¦Ýü¯Çzü/àd ý/µßo:O2ÇwªÁû…áÒÝïÀ`0…Ähû_aš¦_ ×¢DE^î×¾aÿ+l?úõÐAë?Ƹ@–¨)°„GK°T@K°L@ËRŽ·ÃÕÓì˜Æ(ÃA¿8ã?»\i™us™«2ùy«yÙêT––Œ*×¥,8Û°CK—ÆE/ãJEK÷*Ò»„[ËàrnöÊj§V·ô^+‹ ƒ+0Nù›»-ešàËhpÁ¯¥µF£s±Y7i‚¦ýy«b.Në$‹V»þRɃ½!Sþmtô‡õê%ýD‹U­˜úÝš´£f«ÝѧWw]­X–aõl=»ÁGÒ9aN¢O’~ïÜÀÞXÚ9ƒf³S7k†]8­¦ß½©n¸ÜlÖdK463Ã]ñG–] ñ[4'‚8›}okö%Øì{*ìùžûD¾Ï„}"ßd8x^Ùœ~Mc¼—/‹ 7¦ƒßA¾¨ƒoˆ ÀÛøCŒs?A‘«ÞA‰+&þ•Ê\˜ð»"˜˜ÖÁß‹À.øO"ˆò6þU±‚þSq.åøVØçBRDœBzR) "Hó±œA†w{¿ßœˆï¾é™êÊçJNr˜áÊ3½U`n«]&v MÄþ)Ýù¬ü183Sù¦¥8'•wB*ÏlTž©¨óP ž„£gžñ?·o]ûôÆNçúÍ펷µ ø^õÿfæ|þçÌÂüyøŸGßÿüX¸ß„úÀûÿyŒãïoB(UÇÆêÿÑó¬»ÑÇÂñúß9rüOG}þÀõÿ¤ï£ÉæâEö˜ê¦Õ¶?ó.Ëu E™À¥-^ù¶ÍO’öâ)Š­6[¬ÆõëÚEÙýó,ŸÌ&Ûs¢"_œ ¾¨ƒ;Ý ‘ÎdèK!šæVÛx æ/‡Üm¤bºÇÕ°Û#/Yé/Á,ýµG"êöWÿåÑ+{èŠT½Ö0T¥Ú®?nàû¥÷®ÿ÷ä[O¬ß8а{Õÿ›Ÿ;ë¯ÿ7söü¯£Àï-îÏÿú™^ÿ 8`ýWðn2\òzàxü?ÿÿì]l[gÇŸøÛNì|8%é&>Æl+Kœ&™FÍÇi›.‰;ÛU˜4õÖ°,©b‡n“2EC4$ÊÚ¸€•ÝlˆIÛ$¤««ÂÕ`\ nˆ‹Á^Îû<çulÇmâÔõÿw³úœsÞsìWZ³ßþ }xËÛÞþ—AôyãËD“Ưý6¿h¸ÿÏéñ¾?oEߟ¯¢ïÏ_Ñ÷¨èû ê}!Gß_Xëûëܪï¯Kïû‹lÕ÷­Ý÷×]µï¯§Jß_o;¿¾-úþbUûûú+ûûž#Ÿ·±O«Jߟ§¢ïÏ«÷ýùô¾?ÿV}ê}Òè“߸ÃT0údÏÞÜè‹ìÀàÞ.mpoH^åy„e›ß‹,è”ýv¯° Kžãu¨¾¿7Y•m~WXÐ-+ñÞfAló{—½²Íï=ôÉ6¿÷Y“çèà}²Í/Äûþ¤ÙËûþäíïç}ré·ð¾?ÜÎ+彌ðÊDyÙϰ~èð»a©âž9ýéµsùºFmÿÓb|”ùŸqŠÃÿlg²,n¬ä,]\_\Êg×ä²ù{6òÜ,Z[YYÌ/¯­ª8ó`v5»¾¸’YZîõâÁ5S»ÿ“ }/V^Eh=ÿ{xX÷¿ããqìÿ¦ ûßwoÏÿ¾§ÀÿZøß`'¨î}´öØufÛÞÿþÝlÌvÝmœßÂÿ~úýïªýŸ\ ÷Uˆáþ 1¶=ÿóÎbÿh 0ÿ\'TWH{÷vaÐê|¸£½ýOé5ú›Aô˜ñ¨õÊMûÈö?}êøk 6&²Áî Ø&šõg/ušóÓ™ÒkŸCõ“/•8™œ2)@aÛ©’rš”<ƒöK뇥ßÉlÏ0uÏ›©ôÌüÑòY;©×™¥N˜ä–£á­[œû ö´DéQ &ééIT>!Aö¬ú9U«šž8j õ£Mûîµý¯ó‹ËlôûéG3g×rù†f¿Kêù_ñŠþ¿±ø0ü¯¦ û_™íù_wø_@kàð¿¶û›Î뉽{t Qª^mýß!`·¹h´÷ß»\ä£Kôƒ(c,”RéÙe€—ÈïkÌÿòK¤Òrò;Ó»v§îÏí9~Yj]®Mk¡¤äñéM× T–¶TýÜ]zwÚa½;혡ÕÏ0´ú¹ûy»š¼Á]ŠÝŒhÔíÿÊg¶ÿX–À6rÙõF$°zó_GÆâšÿ5‡ÿÕ tÿ+·=ÿësÅþÐ\“ÿµwË7 Õ°[övapãð϶Ÿÿ:H§ïtåŒó_íÏ4<ÿÕs2e&›â…¨Kžg61u¯Š)L!˜Éd"™¢NꔯNM$çg榨‹zäëdâT*3qäˆ9•6å¸×®R˜²Ök}Êï2–eÊ1¯7Ép*iNX?”IÏÈLϤ¬«NLΚ)ëïïûôÃ…#½“GRæ¬Âyääìlæxbfžúh¿ž''æšöÑu³£ê€õìÓ³ÌÔ1sê^ú]Ê^”)551/çôª(‘Lg¬ÇkúÄD*e­ßkTꀽŸýÀìÄzHÖgWÔÉöœOdfæ§Íû3Ö÷aÚúôö£‰Ä4?âö UZ|qÒ,¾ËúÙ—ô!²¯êCdßЇȾŇÈvYÁŸøYy•¿ð!²²îï|ˆlü‹‘•çø/"+ßáf®`÷MVfAÏ>+ècAoÌ nbAß~+ø8 b²5î>DVžã "+ÇÌâCdåÞi}ˆì,!åÒÓ\„”Á¸)ïå !åeW¸)wú.ˆŽM-Ê;Zðí,*ö²pldQ±‹E-\qŒÅúæ­Ë;Wè[´"°÷¬Ð6 Ør÷ çÖŽ}'›NTì8±õvƒeꤊÿ™Ëæ7Îe—òk빫ûZ¢Žÿ946ª÷ÿÉþg3øÀpøŸ±Ò¿IÿÓ_Íÿüd1€ÿ ´ÿóÖFÐë€F×ÜèûkŠá½ùÌ€FxÎÕÞþ§‹:èõ¹ˆb®îR*ýO›cäþ?Ûõ’'™˜5Ë]}ò¤Êò“Úß ,ðÊàØ={Ê1“§Øs©ŠÿóÀòJ–W¾-¯æòòøU¹@õú߆Çtÿ'>2:ÿ§èýo‡ü¥Cµúß>[ àÿ­÷£º&û±½]ù¶ï ÛŒÙÑ!ÿãŽþ7›¯7Üÿ<23kÚµoz \bò¸¬<š™O¥Õ¿!MšGgæÉçh‡óW´Ã*Úá‚íp¡Šv¸pñ¬Isbš:ùYUÒÅϪ’?«J¢ü¬*é¦U¬trnÒŠG2“ i3eë¡°}ÅSÉ™´I½vÏZaI*ê£(»Å(ÊnEEýÖ»Ê÷¢¢gÈçmìcÜj™öÉ<Å'37“š*V¼ÙWS‰?•øù“QI€?•¸ƒD^ù :Lvm›êqëð²7ÙJö¤•Éʵoû´·ïû´·ù´·Ÿ° $ƒŸû´·ß° S¾ã·,è’Ák,ˆÈà,ˆÊà,è°‚?ûhªô„­à¯ì½²ƒí,è“Á¿Y“ÁÿXÐ/Ÿõ¸ ZA§¿|¼—˜_ëq»™ª ïV¿öøµG8ÊQÚ ¼»mË­¹Snå(œ»P8· pî?áÜ|¢ÚÎlÛ mÏ mà m· m«myûHyÓçŽÎí"œ{E87 ~×|=QÅÿ\?¿²¶ôPIû¼¶¸:þç°uPïÿÙ tÿóiGÿ[UÿóSÅþ'Ð8úßöp Õ՚ν]€V`ÌhoÿÓEnº@¿v=íš-¥åù¿Èãn°ÿ­ ~V‘=½4¨l*5áÓœÎL.dÒǤĕ™™&ÅÔËÇ”s%Ûã6]1·Pª„_c“W½R»h›…À é{.”ïèÚ[ Í­êŠÄVËÁïˆnªø_Ù¯fWó¹L.¿ø`6Ç‹—–Ö6Vóòê=™ÕŇëµÖó¿â£qÍÿÁüϦ û_O¥Cµü¯ÅþÐ8ü¯íþ¦³•Ù»G ¥º÷Ö]ûp~Úöþ—Ÿž¥ßDO_*¥Òÿ²Eˆg)àoÐÿRs?=…9 ^Gàî4ý¹åäP9[t“гE_¦8 ¼²Šî*ûcªyզ3´Ú´G ­ynÓКç¾Á{V©šZÊŠÕv¨Bm÷¿ mImÿëüârÞ¡mä²ë ¹_’ºþ×°>ÿu,>< ÿ«èþוíõÝQ à­Á5ù_{·lÐ(Õ]ª¶þoÐ\l{ÿËG—¨Ï ºâZ(¥åþ¯Kä÷]ÿåýʽ/_…÷å¯ð¾ÞWpÞ—Ô¼âÄ&ŽJÍë²K—ù’Kó¾^uiÞ×.ÍûzË¥k^0¼nªø_Kk«gvhúc]ÿK+û_q9ÿ1>ŽùMA÷¿¾¹=ÿëÅþИúx]R]× íí´¿tµ»ÿeÐ}rN"}Óus)•þ—Í}ÔaìèüG5ÊQJ‡‰r|‚ûU55îøýWñrÙüƹÌÚé¯d—òתÿÔí×úŸ††GÂÿiºÿsa{þÏmÅþÐpÿç—ëÖ=\ÊNÐú7àªåþtííâ´$w¶}ÿ“‡rôcëoÜ\cdX¯äXùrÿS޼žÆüŸpÁÜI/œPWáeá¯ðÞÒñÂ@@¿9?19kN“Ÿ¼² išÜáHDÖ:ù]QrýGB]/S‡µ˜M*Ô:…§^¦W w ÆùùzÒ¥~Ä?â÷ZÁ¶*áX’`ë…ŵA"-_Zÿ\0Sb>ÿM솣šÿµ¶ôP6Ï'ÿ54ñÏIÿkd¨bþßH|d þW3Ðý¯¸Q:TËÿ:T à­úŸÀµPÝUûÈž® @™°·½ý/ƒö‘Û¸«ƒ(n,–ºoÊýO]}½ù_|îŸÇ1÷Ï[1÷ÏW1÷Ï_1÷/P1÷/XÜ¿p}j¡ƒÎY·…%ç,ÚkG¿V¥½Æ¡ôk5ÚkM¿Vw>§¨_»Ø÷yVýnœ]j,̹gÙ°êvPJÓ°êuPÊаêtPÊ:Ÿ ÷9(åhX\ŠÍÉÙÙùg¼K)OûÔe*hŸºDCå"íS—k¨\r>¾tCåÚ/»55?7ufaM»ÞP—é îœ¹Q…ê.šYtPwÔÜhÐiIu×ÜhÈ?œ­ ¦³“çÓΙ6¬»ê—jòp†Kuy8Ã¥;1«Òßi6¬;ï7•ò¯ê–Ì ¸ªÒòªŽ¨gäUQÏÊ«:¢ž“WuD=OC²oÞ¼Y =ºW^¥H{t¼J‰öèžx•ç3ª^¥ìÏ)-5¸`*rNQ5KÎ)ª6(çU’sŠª%y…^^Jó:y¯ ð¾!µ†ïcm!ÞùF\½2p*®^8#„< ÏÅÕ++B(r£«qõÊÀF\½2ðŠÊ,ÜB……Ÿ Áâw^‹«WÞˆ«WÞŽ«Wn ¡ÆÂïä+ƒŽð¾|e€sÑ?¯ °ð¡|e€…ä+,|,‡pÄ>‘CxÀîÈ!dáS9„,|.‡…TB !¿SQÂï¥&„2 #B¨°ðE!X,<.„Áš#Laˆ÷ò„ª,4„Pcá”ê,œB²Êç‡RÃ|~!ͪ2,l!ËÂ+BȱpCù}|~¡ÀÂkB(²ð†BÞ–C¸ŸÏ9„ùüCÈÂûrYø@! Ê!ä¯ÿ‘BîúÇrYøD! wä²ð©BäÏåò¡L%ŲP‚{Ö„sÏ!䇸üBaŸB(²0!„ Oa€…†Ê|JBÅ=?„`±ðœYX‚{® a“ëˆ?\ïçÜÏ×pŒç;ò¡ÃŽ|â°#7ìÈg »Ûƒ†Þ©¹A¯G Ý•ˆz<\Øž,tçÂÅnϺSê“]ž&ì¨G óÐø…Næ >ÑáñÁŽxÐû ôOz¯íí£ïÿí7ÿúäÕºÜöë“>ü¹Î7üv×»}£7æ=ïóžE´Ñëߎ¸½7úæënì~ÛGߢÛîχŠÝîÌ.„?ÙåžÜ6oÈn³VH޾7vš¸ÂwÄÆ#® Uètãmì6(è—ïÿm¬­\[ë;è¡=òWù£GÆÇ‘ÿ°-ÜåBù“íRùí¶ü¨Ÿþ¯Õõ•—îWlÏü׉qÿ:1Šõ·íÿº¹9ÿò_€Ö|ÈA €{ä_È¥Kô›ÑÍØh ²ÿ«e„¸ÔwþkÊ‹~­{ ‘ÍÌ-.¹ÏíÇOÎÌQšª³óSO5¦›ÇÏ5ÛV±dê›×c¼¬Þ1ò–Õ«W«¼ŠÞqÜ5᪎ðSG¸î v+þ5j/vÄ.¢ÿg§ïü×ËWί¼ÔÜX[¾¸éØ^ù¯ccÊÿ31::ÿÏv ý?#É ÔÍÿ3ë ðÿ;ø› ³m[þ³p/,äv·ÿ'A_¢ùÄSD#ÉÙPþk˱¾åù¯3sÓ³­ß²¡¢rÆ Qyc…¨‚±BTÑX!ªJƒ0Ò`ËFlÅHƒµŒ4ØÁpì™[5Ó`kflÝLƒýEÿc.ÓcSflÚLƒÍ˜i°Y3 6§Ò`ói°…ˆ4ØbDl)" v@¥Á–#Ò`+i°VDì`DìJƒ­F¤ÁÖ"Ò`ëi°ÓõwXîSzìôŸ9=6²¼žY:¡V+H¨ÕÊêBpÓc÷ ¡ÈÂc2ú”=$£Oy‹#2ú”…oÈèSNÈèSædô)'¿>-£O9Æõy}ÊÂ}ÊÂ}Ê‹BHr£ß‚›û#!¸é±?‚›ûº²,¼)‡CZß‘Cȉ«ïÊ!dá÷rYø“Bþ*‡½­Ócÿ¦Ócÿ®Ócÿ)‡…Ë!äFÿ£ÓcïêôØtR¥Ç!ÉB]›Œ“mOÕH–E²ì#‘,Ûgþ«¿"`_ öÌÐù¯ã£ðÿn ÈvÈÝÙ ÿ@/ÞEþ+Ýòò_¿¨íü×[}ç¿ÊÈ×.«nI,G¿²ã‰E Ü’,X‘½!raVØÿåZ›šß¹xmùüJóò• Wïï>\ÿ×ø¸ç÷:¬ÿåªð9ÛŽ;¿l³ÿëÚÕ«ëݶëUß¡L:rhtìA÷lÿ}”|/HÕpercona-galera-3-3.8-3390/scripts/mysql/rpm.sh000077500000000000000000000156221244131713600210010ustar00rootroot00000000000000#!/bin/bash -e if test -z "$MYSQL_SRC" then echo "MYSQL_SRC variable pointing at MySQL/wsrep sources is not set. Can't continue." exit -1 fi usage() { echo -e "Usage: $0 [patch file] [spec file]" } # Parse command line if test $# -lt 1 then usage exit 1 fi set -e # Absolute path of this script folder SCRIPT_ROOT=$(cd $(dirname $0); pwd -P) THIS_DIR=$(pwd -P) set -x MYSQL_DIST_TARBALL=$(cd $(dirname "$1"); pwd -P)/$(basename "$1") ###################################### ## ## ## Prepare patch ## ## ## ###################################### # Source paths are either absolute or relative to script, get absolute MYSQL_SRC=$(cd $MYSQL_SRC; pwd -P; cd $THIS_DIR) pushd $MYSQL_SRC export WSREP_REV=$(bzr revno) export WSPATCH_REVNO=$WSREP_REV if [ -r "VERSION" ] then . "VERSION" WSREP_API=$(grep WSREP_INTERFACE_VERSION wsrep/wsrep_api.h | cut -d '"' -f 2) WSREP_PATCH=$(grep SET\(WSREP_PATCH_VERSION cmake/wsrep.cmake | cut -d '"' -f 2) export MYSQL_VER=$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH else MYSQL_VERSION_MINOR=1 WSREP_API=$(grep WSREP_API= config/ac-macros/wsrep.m4 | cut -d '=' -f 2) WSREP_PATCH=$(grep WSREP_PATCH= config/ac-macros/wsrep.m4 | cut -d '=' -f 2) export MYSQL_VER=`grep AC_INIT configure.in | awk -F '[' '{ print $3 }'| awk -F ']' '{ print $1 }'` fi if test -z "$MYSQL_VER" then echo "Could not determine mysql version." exit -1 fi MYSQL_VERSION_EXTRA="_wsrep_$WSREP_API.$WSREP_PATCH" MYSQL_VERSION_FINAL=${MYSQL_VER}${MYSQL_VERSION_EXTRA} popd #MYSQL_SRC RPM_BUILD_ROOT=$(pwd)/redhat rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT pushd $RPM_BUILD_ROOT mkdir -p BUILD RPMS SOURCES SPECS SRPMS pushd RPMS mkdir -p athlon i386 i486 i586 i686 noarch x86_64 popd; popd ###################################### ## ## ## Prepare patched source ## ## ## ###################################### #FIXME: fix spec file to make rpmbuild do it MYSQL_DIST=$(tar -tzf $MYSQL_DIST_TARBALL | head -n1 | sed 's/\/$//') rm -rf $MYSQL_DIST; tar -xzf $MYSQL_DIST_TARBALL # rename according to MYSQL_VERSION_FINAL test "$MYSQL_DIST" != "mysql-$MYSQL_VERSION_FINAL" && \ rm -rf "mysql-$MYSQL_VERSION_FINAL" && \ mv "$MYSQL_DIST" "mysql-$MYSQL_VERSION_FINAL" && \ MYSQL_DIST="mysql-$MYSQL_VERSION_FINAL" pushd $MYSQL_DIST if test -r "$2" # check if patch name was supplied then # patch as a file WSREP_PATCH=$(cd $(dirname "$2"); pwd -P)/$(basename "$2") else # generate patch for this particular MySQL version from LP WSREP_PATCH=$($SCRIPT_ROOT/get_patch.sh mysql-$MYSQL_VER $MYSQL_SRC) fi # patch freaks out on .bzrignore which doesn't exist in source dist and # returns error code patch -p1 -f < $WSREP_PATCH || : # need to fix permissions on 5.1 [ $MYSQL_VERSION_MINOR -eq 1 ] && chmod a+x ./BUILD/*wsrep # update configure script for 5.1 test $MYSQL_VERSION_MINOR -le 5 && ./BUILD/autorun.sh time tar -C .. -czf $RPM_BUILD_ROOT/SOURCES/"$MYSQL_DIST.tar.gz" \ "$MYSQL_DIST" ###################################### ## ## ## Create spec file ## ## ## ###################################### export MAKE="make -j $(cat /proc/cpuinfo | grep -c ^processor)" LIB_TYPE="bundled" # bundled or system [ "$MYSQL_VERSION_MAJOR$MYSQL_VERSION_MINOR" -ge "56" ] \ && MEMCACHED_OPT="-DWITH_LIBEVENT=$LIB_TYPE -DWITH_INNODB_MEMCACHED=ON" \ || MEMCACHED_OPT="" if [ $MYSQL_VERSION_MINOR -eq 1 ] then ./configure --with-wsrep > /dev/null pushd support-files && rm -rf *.spec && make > /dev/null && popd else cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBUILD_CONFIG=mysql_release \ -DWITH_WSREP=1 \ -DWITH_EXTRA_CHARSETS=all \ -DWITH_SSL=$LIB_TYPE \ -DWITH_ZLIB=$LIB_TYPE \ $MEMCACHED_OPT $MYSQL_SRC \ && make -S fi ###################################### ## ## ## Build binary tar.gz ## ## ## ###################################### [ $MYSQL_VERSION_MINOR -eq 1 ] && make bin-dist || make package # Fix the name of the binary package to contain wsrep suffix OLD_BIN_NAME=$(ls mysql-$MYSQL_VER-linux-*.tar.gz | sed s/\.tar\.gz//) NEW_BIN_NAME=$(echo $OLD_BIN_NAME | sed s/-linux/$MYSQL_VERSION_EXTRA-linux/) echo "Repacking $OLD_BIN_NAME -> $NEW_BIN_NAME" tar -xzf $OLD_BIN_NAME.tar.gz && rm $OLD_BIN_NAME.tar.gz mv $OLD_BIN_NAME $NEW_BIN_NAME tar -czf $NEW_BIN_NAME.tar.gz $NEW_BIN_NAME && rm -rf $NEW_BIN_NAME popd # MYSQL_DIST WSREP_SPEC=${WSREP_SPEC:-"$MYSQL_DIST/support-files/mysql.spec"} mv $WSREP_SPEC $RPM_BUILD_ROOT/SPECS/$MYSQL_DIST.spec WSREP_SPEC=$RPM_BUILD_ROOT/SPECS/$MYSQL_DIST.spec mv $WSREP_PATCH ./$MYSQL_DIST.patch mv $MYSQL_DIST/$MYSQL_DIST-linux-*.tar.gz ./ #cleaning intermedieate sources: rm -rf $MYSQL_DIST if [ -n "$TAR_ONLY" ] || ! which rpmbuild >/dev/null 2>&1 then echo "Not building RPMs" exit 0 fi ###################################### ## ## ## Build RPM ## ## ## ###################################### if [ $MYSQL_VERSION_MINOR == 1 ] then # cflags vars might be obsolete with 5.5 wsrep_cflags="-DWSREP_PROC_INFO -DMYSQL_MAX_VARIABLE_VALUE_LEN=2048" fast_cflags="-O3 -fno-omit-frame-pointer" uname -m | grep -q i686 && \ cpu_cflags="-mtune=i686" || cpu_cflags="-mtune=core2" RPM_OPT_FLAGS="$fast_cflags $cpu_cflags $wsrep_cflags" fi RPMBUILD() { if [ $MYSQL_VERSION_MINOR -lt 5 ] then WSREP_RPM_OPTIONS=(--with wsrep --with yassl \ --define "optflags $RPM_OPT_FLAGS") else export MEMCACHED_OPT="-DWITH_LIBEVENT=system -DWITH_INNODB_MEMCACHED=ON" \ WSREP_RPM_OPTIONS=(--define='with_wsrep 1' \ --define='distro_specific 1' \ --define='runselftest 0' \ --define='with_ssl system' \ --define='mysql_packager Codership Oy ') fi $(which rpmbuild) --rmsource --define "_topdir $RPM_BUILD_ROOT" \ "${WSREP_RPM_OPTIONS[@]}" -ba $WSREP_SPEC } pushd "$RPM_BUILD_ROOT" if [ "$(whoami)" == "root" ] then chown -R mysql $RPM_BUILD_ROOT su mysql -c RPMBUILD else RPMBUILD fi popd ###################################### ## ## ## Copy required files here ## ## ## ###################################### mv $WSREP_SPEC ./ uname -m | grep -q i686 && ARCH=i386 || ARCH=x86_64 mv $RPM_BUILD_ROOT/RPMS/$ARCH/MySQL-server-*.rpm ./ # remove the patch file if is was automatically generated if test ! -r "$2"; then rm -rf $WSREP_PATCH; fi rm -rf $RPM_BUILD_ROOT exit 0 percona-galera-3-3.8-3390/scripts/mysql/rpm_wc.sh000077500000000000000000000070151244131713600214670ustar00rootroot00000000000000#!/bin/bash # This script tries to build RPMs from MySQL/wsrep working copy # probably will never work due to lack of essential files (manpages, etc.) if test -z "$MYSQL_SRC" then echo "MYSQL_SRC variable pointing at MySQL/wsrep sources is not set. Can't continue." exit -1 fi usage() { echo -e "Usage: build.sh [OPTIONS] \n" \ "Options: \n" \ " -r|--release configure build with debug disabled (implies -c)\n"\ " -d|--debug configure build with debug enabled (implies -c)\n"\ " --no-strip prevent stripping of release binaries\n"\ "\n -s and -b options affect only Galera build.\n" } # Parse command line while test $# -gt 0 do case $1 in -r|--release) RELEASE=yes # Compile without debug ;; -d|--debug) DEBUG=yes # Compile with debug NO_STRIP=yes # Don't strip the binaries ;; --no-strip) NO_STRIP=yes # Don't strip the binaries ;; --help) usage exit 0 ;; *) usage exit 1 ;; esac shift done set -x set -e # Absolute path of this script folder BUILD_ROOT=$(cd $(dirname $0); pwd -P) #GALERA_SRC=${GALERA_SRC:-$BUILD_ROOT/../../} # Source paths are either absolute or relative to script, get absolute MYSQL_SRC=$(cd $MYSQL_SRC; pwd -P; cd $BUILD_ROOT) ###################################### ## ## ## Build MySQL ## ## ## ###################################### # Obtain MySQL version and revision of Galera patch pushd $MYSQL_SRC # make dist if test -f Makefile then time make maintainer-clean > /dev/null # make distclean fi #if ! test -f configure #then time BUILD/autorun.sh #fi WSREP_REV=$(bzr revno); export WSREP_REV time ./configure --with-wsrep > /dev/null # MySQL has a mindblowing make system that requires extra/comp_err to be built # for 'make dist'. comp_err requires prebuilt mysys and dbug but they are not # built automatically by make dist. pushd include; make > /dev/null; popd pushd strings; make > /dev/null; popd pushd mysys; make > /dev/null; popd pushd dbug; make > /dev/null; popd pushd support-files; rm -rf *.spec; make > /dev/null; popd pushd libmysql; make link_sources > /dev/null; popd pushd libmysql_r; make link_sources > /dev/null; popd pushd libmysqld; make link_sources > /dev/null; popd pushd client; make link_sources > /dev/null; popd time make dist > /dev/null MYSQL_VER=$(grep 'MYSQL_NO_DASH_VERSION' $MYSQL_SRC/Makefile | cut -d ' ' -f 3) #if test -d /usr/src/redhat #then #export RPM_BUILD_ROOT=/usr/src/redhat #else RPM_BUILD_ROOT=/tmp/redhat #fi mkdir -p $RPM_BUILD_ROOT pushd $RPM_BUILD_ROOT mkdir -p BUILD RPMS SOURCES SPECS SRPMS pushd RPMS mkdir -p athlon i386 i486 i586 i686 noarch popd; popd mv mysql-$MYSQL_VER.tar.gz $RPM_BUILD_ROOT/SOURCES/ MYSQL_SPEC=$MYSQL_SRC/support-files/mysql-$MYSQL_VER.spec mv $MYSQL_SPEC $RPM_BUILD_ROOT/SPECS MYSQL_SPEC=$RPM_BUILD_ROOT/SPECS/mysql-$MYSQL_VER.spec i686_cflags="-march=i686 -mtune=i686" amd64_cflags="-m64 -mtune=opteron" fast_cflags="-O3 -fno-omit-frame-pointer" uname -m | grep -q i686 && \ export RPM_OPT_FLAGS="$i686_cflags $fast_cflags" || \ export RPM_OPT_FLAGS="$amd64_cflags $fast_cflags" RPMBUILD="rpmbuild --clean --rmsource \ --define \"_topdir $RPM_BUILD_ROOT\" \ --define \"optflags $RPM_OPT_FLAGS\" \ --with wsrep -ba $MYSQL_SPEC \ 2>&1 > $RPM_BUILD_ROOT/rpmbuild.log" chown -R mysql $RPM_BUILD_ROOT su mysql -c "$RPMBUILD" exit 0 percona-galera-3-3.8-3390/scripts/openrep/000077500000000000000000000000001244131713600201415ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/common000066400000000000000000000002421244131713600213520ustar00rootroot00000000000000set -x MYSQL_BIN=${MYSQL_BIN:-"$MYSQL_ROOT/libexec/mysqld"} MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$MYSQL_ROOT/var"} MYSQL_CNF=${MYSQL_CNF:-"$MYSQL_ROOT/etc/my.cnf"} percona-galera-3-3.8-3390/scripts/openrep/configure000077700000000000000000000000001244131713600237472redundantustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/demote000077700000000000000000000000001244131713600232432redundantustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/flush000077700000000000000000000000001244131713600240302not_supportedustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/halt000077700000000000000000000000001244131713600223722serviceustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/kill000077700000000000000000000000001244131713600223752serviceustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/not_supported000077500000000000000000000002111244131713600227660ustar00rootroot00000000000000#!/bin/sh # Copuright (C) 2009 Codership Oy echo "Operation not supported: $(basename $0 | sed s/\.sh//)" exit 0 percona-galera-3-3.8-3390/scripts/openrep/offline000077700000000000000000000000001244131713600230642serviceustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/online000077700000000000000000000000001244131713600227262serviceustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/plugin.cnf000066400000000000000000000012211244131713600221230ustar00rootroot00000000000000MYSQL_BASE_DIR= # MYSQLD= # MYSQL_DATA_DIR= # MYSQL_CNF= MYSQL_ROOT_USER=root MYSQL_ROOT_PSWD=rootpass WSREP_PROVIDER= WSREP_CLUSTER_ADDRESS="dummy://" # WSREP_CLUSTER_NAME= # WSREP_NODE_NAME= # WSREP_NODE_INCOMING_ADDRESS= WSREP_SST_METHOD=mysqldump WSREP_SST_AUTH=$MYSQL_ROOT_USER:$MYSQL_ROOT_PSWD # WSREP_SST_ADDRESS= # WSREP_SST_DONOR="" # # Parameters below rarely require changing # WSREP_SLAVE_THREADS=1 WSREP_LOCAL_CACHE_SIZE=20971520 WSREP_START_POSITION= WSREP_DEBUG=0 WSREP_AUTO_INCREMENT_CONTROL=1 WSREP_RETRY_AUTOCOMMIT=1 WSREP_CONVERT_LOCK_TO_TRX=1 WSREP_DRUPAL_282555_WORKAROUND=1 WSREP_WS_PERSISTENCY=0 # WSREP_DBUG= # WSREP_DATA_HOME_DIR= percona-galera-3-3.8-3390/scripts/openrep/prepare000077700000000000000000000000001244131713600234242redundantustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/promote000077700000000000000000000000001244131713600234532redundantustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/provision000077700000000000000000000000001244131713600247372not_supportedustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/redundant000077500000000000000000000002101244131713600220440ustar00rootroot00000000000000#!/bin/sh # Copuright (C) 2009 Codership Oy echo "Operation is redundant: $(basename $0 | sed s/\.sh//)" exit 0 percona-galera-3-3.8-3390/scripts/openrep/release000077700000000000000000000000001244131713600243272not_supportedustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/service000077500000000000000000000144671244131713600215430ustar00rootroot00000000000000#!/bin/bash -x # Copyright (C) 2009 Codership Oy PLUGIN_BASE_DIR=$(cd $(dirname $0); pwd -P) SELF=$PLUGIN_BASE_DIR/$(basename $0) WSREP_CLUSTER_NAME=${1:-"tor_galera_cluster"} WSREP_NODE_NAME=${2:-"$(hostname)"} PLUGIN_CONF=${3:-"$PLUGIN_BASE_DIR/plugin.cnf"} . $PLUGIN_CONF #=============== Fall back to reasonable defaults ======================= # MySQL configuration file MYSQL_CNF=${MYSQL_CNF:-"$MYSQL_BASE_DIR/etc/my.cnf"} if test -s "$MYSQL_CNF" then DEFAULTS_OPTION=" --defaults-file=$MYSQL_CNF " my_cnf_datadir=$(grep ^datadir $MYSQL_CNF | sed s/[^/]*//) else DEFAULTS_OPTION=" --no-defaults " fi # If it was not given explicitely, use the one from my.cnf MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$my_cnf_datadir"} # If it was not found in my.cnf, use distribution default MYSQL_DATA_DIR=${MYSQL_DATA_DIR:-"$MYSQL_BASE_DIR/var"} # use mysqld server directly, better not have automatic restarting MYSQLD=${MYSQLD:-"$MYSQL_BASE_DIR/libexec/mysqld"} MYSQLADMIN=${MYSQLADMIN:-"$MYSQL_BASE_DIR/bin/mysqladmin"} # Port, socket and pid files MYSQL_PORT=${MYSQL_PORT:-3306} MYSQL_SOCKET=${MYSQL_SOCKET:-"$MYSQL_DATA_DIR/mysqld.sock"} MYSQL_PID=${MYSQL_PID:-"$MYSQL_DATA_DIR/mysqld.pid"} # Shutdown wait timeout. MYSQL_SHUTDOWN_WAIT=60 #============= Nothing servicable below ================================ # User to run as if started under superuser MYSQLD_USER=$(whoami) if test "$MYSQLD_USER" = "root" then MYSQLD_USER=mysql fi #ROOT_USER=${ROOT_USER:-"-uroot"} #ROOT_PSWD=${ROOT_PSWD:-"-prootpass"} #mysql_log="$MYSQL_DATA_DIR/$(hostname).log" usage() { cat - << EOF usage: service Commands: check : check cosistency either locally or through network start : start servers stop : stop servers restart : stop and start servers status : show running servers EOF } # Checks if a process with a given PID is still running find_pid() { ps axc | grep mysqld | grep -w ^\ *$1 > /dev/null } galera_start() { local failed if ! test -x $MYSQLD then echo "$MYSQLD executable not found" exit -1 fi if test -f $MYSQL_PID then echo "Found existing '$MYSQL_PID'. Please run '$0 stop'" exit -1; fi if test -f $WSREP_PROVIDER || test $WSREP_PROVIDER == "none" then WSREP_OPTS="$WSREP_OPTS --wsrep_provider=$WSREP_PROVIDER" else echo "WSREP provider '$WSREP_PROVIDER' not found" exit -1 fi WSREP_OPTS="$WSREP_OPTS \ --wsrep_cluster_name=$WSREP_CLUSTER_NAME \ --wsrep_cluster_address=$WSREP_CLUSTER_ADDRESS \ --wsrep_sst_method=$WSREP_SST_METHOD \ --wsrep_local_cache_size=$WSREP_LOCAL_CACHE_SIZE \ --wsrep_start_position=$WSREP_START_POSITION \ --wsrep_debug=$WSREP_DEBUG \ --wsrep_auto_increment_control=$WSREP_AUTO_INCREMENT_CONTROL \ --wsrep_retry_autocommit=$WSREP_RETRY_AUTOCOMMIT \ --wsrep_convert_LOCK_to_trx=$WSREP_CONVERT_LOCK_TO_TRX \ --wsrep_drupal_282555_workaround=$WSREP_DRUPAL_282555_WORKAROUND \ --wsrep_ws_persistency=$WSREP_WS_PERSISTENCY \ --wsrep_slave_threads=$WSREP_SLAVE_THREADS " MYSQLD_OPTS=" --user=$MYSQLD_USER \ --basedir=$MYSQL_BASE_DIR \ --datadir=$MYSQL_DATA_DIR \ --pid-file=$MYSQL_PID \ --port=$MYSQL_PORT \ --socket=$MYSQL_SOCKET \ --skip-locking \ --binlog_format=ROW \ --default-storage-engine=InnoDB " INNODB_OPTS=" --innodb_autoinc_lock_mode=2 \ --innodb_flush_log_at_trx_commit=0 \ --innodb_doublewrite=0" err_log="$MYSQL_DATA_DIR/$(hostname).err" echo -n "Starting mysqld instance with data dir $MYSQL_DATA_DIR and listening at port $MYSQL_PORT and socket $MYSQL_SOCKET..." LD_LIBRARY_PATH=$(cd $(dirname $WSREP_PROVIDER) && pwd -P) export LD_LIBRARY_PATH export PATH=$MYSQL_BASE_DIR/bin:$PATH nohup $MYSQLD $DEFAULTS_OPTION $MYSQLD_OPTS $INNODB_OPTS $WSREP_OPTS \ 1>/dev/null 2>>$err_log & my_pid=$! # echo "Waiting for pid file" while ! test -r $MYSQL_PID do sleep 1 if find_pid $my_pid then # process is alive, wait for pid file echo -n "." else failed="yes" break fi done if test "$failed" != "yes" then echo " Done (PID:$(cat $MYSQL_PID))" else echo " Failed (PID:$my_pid)" fi } galera_stop() { # check pid file if test -r $MYSQL_PID then # check if corresponding mysqld is running # if ps axc | grep mysqld | grep $(cat $MYSQL_PID) >/dev/null 2>&1 local my_pid=$(cat $MYSQL_PID) if find_pid $my_pid then echo -n "Killing PID $my_pid" kill $my_pid # wait for pid file to disappear for second in $(seq 1 $MYSQL_SHUTDOWN_WAIT) do echo -n "." sleep 1 if test ! -r $MYSQL_PID then break fi done echo "" if test "$second" = "$MYSQL_SHUTDOWN_WAIT" then echo -n "Failed to stop mysqld safely. Killing with -9... " kill -9 $my_pid fi else echo -n "Removing stale PID file $MYSQL_PID... " fi rm -rf $MYSQL_PID echo "Done" else echo "PID file not found: $MYSQL_PID" fi } galera_restart() { galera_stop galera_start } dump() { #local ROUTINES="--routines" # don't dump routines yet, will cause false err. local DUMP_OPTIONS=" --skip-opt --compact --flush-logs --lock-all-tables \ --quick --create-options --set-charset --skip-comments $ROUTINES " DB=${DB:-"--all-databases"} #set -x mysqldump $DUMP_OPTIONS $ROOT_USER $ROOT_PSWD -h127.0.0.1 -P$MYSQL_PORT \ $IGNORE_TABLES $DB #set +x } checksum() { CS=`dump | md5sum` echo $CS } # write set level, SQL, RBR or ROW WS_LEVEL="RBR" #DB="test" # use 'test' database if none given IGNORE_TABLES="" case $(basename $0) in 'dump') COMMAND="dump" ;; 'check') COMMAND="checksum" ;; 'online') COMMAND=galera_start ;; 'stop'|'halt'|'kill'|'offline') COMMAND=galera_stop ;; 'restart') COMMAND=galera_restart ;; 'status') COMMAND=status ;; *) echo $0 # must be command usage exit 1 ;; esac $COMMAND # percona-galera-3-3.8-3390/scripts/openrep/status000077700000000000000000000000001244131713600242322not_supportedustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/stop000077700000000000000000000000001244131713600224272serviceustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/openrep/waitevent000077700000000000000000000000001244131713600247152not_supportedustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/packages/000077500000000000000000000000001244131713600202475ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/packages/deb.sh000077500000000000000000000030571244131713600213450ustar00rootroot00000000000000#!/bin/bash -eu # # Script to build Galera library debian package # # Source of information: # - https://wiki.debian.org/IntroDebianPackaging # - https://wiki.debian.org/HowToPackageForDebian # SCRIPT_ROOT=$(cd $(dirname $0); pwd -P) JOBS=${JOBS:-3} function build_deb { # Create upstream tar.gz package local version="$1" local debian_version="$(lsb_release -sc)" galera_dir="galera-$version" source_tar="galera-$version.tar.gz" orig_tar="galera_$version.orig.tar.gz" pushd "$SCRIPT_ROOT" test -d "$galera_dir" && rm -rf "$galera_dir" test -f "$source_tar" && rm -r "$source_tar" test -f "$orig_tar" && rm -r "$orig_tar" # Create source tarball (cd ../../ && git checkout-index -a -f --prefix="$SCRIPT_ROOT/$galera_dir/") tar zcf "$galera_dir.tar.gz" "$galera_dir" # Copy to orig.tar.gz cp "$source_tar" "$orig_tar" tar zxf "$orig_tar" cp -r debian "$galera_dir" cd "$galera_dir" dch -m -D "$debian_version" --force-distribution -v "$version-$debian_version" "Version upgrade" DEB_BUILD_OPTIONS="parallel=$JOBS" dpkg-buildpackage -us -uc test -d "$galera_dir" && rm -rf "$galera_dir" test -f "$source_tar" && rm -r "$source_tar" test -f "$orig_tar" && rm -r "$orig_tar" popd cp "$SCRIPT_ROOT"/galera_"$version"*.deb ./ cp "$SCRIPT_ROOT"/galera-dbg_"$version"*.deb ./ } function usage { cat - < EOF } function main { set -x test $# -eq 1 || (usage && exit 1) local version="$1" build_deb "$version" } main $@ percona-galera-3-3.8-3390/scripts/packages/debian000077700000000000000000000000001244131713600232022../../debianustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/packages/empty000066400000000000000000000000001244131713600213160ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/packages/freebsd.sh000077500000000000000000000045331244131713600222250ustar00rootroot00000000000000#!/bin/bash -eu if [ $# -ne 1 ] then echo "Usage: $0 " exit 1 fi RELEASE=$1 # Absolute path of this script folder SCRIPT_ROOT=$(cd $(dirname $0); pwd -P) PBR="$SCRIPT_ROOT/pkg_top_dir" PBD="$SCRIPT_ROOT/../.." GALERA_LICENSE_DIR="$PBR/share/licenses/galera-$RELEASE" rm -rf "$PBR" mkdir -p "$PBR" install -d "$PBR/"{bin,lib/galera,share/doc/galera,etc/rc.d,libdata/ldconfig} install -m 555 "$PBD/garb/files/freebsd/garb.sh" "$PBR/etc/rc.d/garb" install -m 555 "$PBD/garb/garbd" "$PBR/bin/garbd" install -m 444 "$PBD/libgalera_smm.so" "$PBR/lib/galera/libgalera_smm.so" install -m 444 "$SCRIPT_ROOT/freebsd/galera-ldconfig" "$PBR/libdata/ldconfig/galera" install -m 444 "$PBD/scripts/packages/README" "$PBR/share/doc/galera/" install -m 444 "$PBD/scripts/packages/README-MySQL" "$PBR/share/doc/galera/" install -m 755 -d "$GALERA_LICENSE_DIR" install -m 444 "$PBD/LICENSE" "$GALERA_LICENSE_DIR/GPLv2" install -m 444 "$PBD/scripts/packages/freebsd/LICENSE" "$GALERA_LICENSE_DIR" install -m 444 "$PBD/asio/LICENSE_1_0.txt" "$GALERA_LICENSE_DIR/LICENSE.asio" install -m 444 "$PBD/www.evanjones.ca/LICENSE" "$GALERA_LICENSE_DIR/LICENSE.crc32c" install -m 444 "$PBD/chromium/LICENSE" "$GALERA_LICENSE_DIR/LICENSE.chromium" install -m 444 "$PBD/scripts/packages/freebsd/catalog.mk" "$GALERA_LICENSE_DIR" install -m 644 "$SCRIPT_ROOT/freebsd/galera-"{plist,descr,comment,message} "$PBR" sed -e "s!%{SRCDIR}!$PBR!" -e "s!%{RELEASE}!$RELEASE!" -i "" "$PBR/galera-"{plist,descr,comment,message} \ "$GALERA_LICENSE_DIR/catalog.mk" for pkg in $(grep '^@comment DEPORIGIN:' "$PBR/galera-plist" | cut -d : -f 2); do pkgdep=$(/usr/sbin/pkg_info -q -O "$pkg") if [ -z "$pkgdep" ]; then echo "ERROR: failed to find dependency package '$pkg'" >&2 exit 1 fi sed -e "s!^@comment DEPORIGIN:$pkg!@pkgdep $pkgdep"$'\\\n&!' -i "" "$PBR/galera-plist" done /usr/sbin/pkg_create -c "$SCRIPT_ROOT/freebsd/galera-comment" \ -d "$SCRIPT_ROOT/freebsd/galera-descr" \ -m "$SCRIPT_ROOT/freebsd/galera-mtree" \ -D "$SCRIPT_ROOT/freebsd/galera-message" \ -f "$PBR/galera-plist" \ -v "galera-$1-$(uname -m).tbz" rm -rf "$PBR" exit 0 percona-galera-3-3.8-3390/scripts/packages/freebsd/000077500000000000000000000000001244131713600216615ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/packages/freebsd/LICENSE000066400000000000000000000001211244131713600226600ustar00rootroot00000000000000This package has a single license: GPLv2 (GNU General Public License version 2). percona-galera-3-3.8-3390/scripts/packages/freebsd/catalog.mk000066400000000000000000000003231244131713600236220ustar00rootroot00000000000000_LICENSE=GPLv2 _LICENSE_NAME=GNU General Public License version 2 _LICENSE_PERMS=dist-mirror dist-sell pkg-mirror pkg-sell auto-accept _LICENSE_GROUPS=FSF GPL OSI _LICENSE_DISTFILES=galera-%{RELEASE}-src.tar.gz percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-comment000066400000000000000000000001071244131713600244750ustar00rootroot00000000000000Galera: a synchronous multi-master wsrep provider (replication engine) percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-descr000066400000000000000000000004651244131713600241420ustar00rootroot00000000000000Galera is a fast synchronous multimaster wsrep provider (replication engine) for transactional databases and similar applications. For more information about wsrep API see http://launchpad.net/wsrep. For a description of Galera replication engine see http://www.codership.com. WWW: http://www.codership.com/ percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-ldconfig000066400000000000000000000000261244131713600246200ustar00rootroot00000000000000/usr/local/lib/galera percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-message000066400000000000000000000007571244131713600244720ustar00rootroot00000000000000************************************************************************ If you want to run Galera Arbitrator Daemon (garbd), remember to configure garb service in /etc/rc.conf, e.g.: garb_enable="YES" garb_galera_nodes="1.1.1.1:4567" garb_galera_group="wsrep_cluster_name" garb_galera_options="gmcast.listen_addr=tcp://2.2.2.2:4567" garb_log_file="/tmp/garb.log" To start garbd, use command: sudo service garb start ************************************************************************ percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-mtree000066400000000000000000000422301244131713600241520ustar00rootroot00000000000000# $FreeBSD: /tmp/pcvs/ports/Templates/BSD.local.dist,v 1.3 2010-11-12 20:57:14 pav Exp $ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin .. etc devd .. man.d .. pam.d .. rc.d .. .. include X11 .. .. info .. lib X11 app-defaults .. fonts local .. .. .. .. libdata ldconfig .. ldconfig32 .. pkgconfig .. .. libexec .. man /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. de.ISO8859-1 uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. en.ISO8859-1 /set uname=man cat1 .. cat1aout .. cat2 .. cat3 .. cat4 i386 .. .. cat5 .. cat6 .. cat7 .. cat8 i386 .. .. cat9 i386 .. .. catn .. .. ja uname=root cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. ru.KOI8-R /set uname=man cat1 .. cat2 .. cat3 .. cat4 .. cat5 .. cat6 .. cat7 .. cat8 .. cat9 .. catl .. catn .. /set uname=root man1 .. man2 .. man3 .. man4 .. man5 .. man6 .. man7 .. man8 .. man9 .. manl .. mann .. .. .. sbin .. share aclocal .. dict .. doc ja .. .. emacs site-lisp .. .. examples .. java classes .. .. locale af LC_MESSAGES .. .. am LC_MESSAGES .. .. ar LC_MESSAGES .. .. az LC_MESSAGES .. .. be LC_MESSAGES .. .. bg LC_MESSAGES .. .. bn LC_MESSAGES .. .. br LC_MESSAGES .. .. bs LC_MESSAGES .. .. ca LC_MESSAGES .. .. cs LC_MESSAGES .. .. cy LC_MESSAGES .. .. da LC_MESSAGES .. .. de LC_MESSAGES .. .. de_AT LC_MESSAGES .. .. dk LC_MESSAGES .. .. ee LC_MESSAGES .. .. el LC_MESSAGES .. .. en LC_MESSAGES .. .. en_AU LC_MESSAGES .. .. en_CA LC_MESSAGES .. .. en_GB LC_MESSAGES .. .. eo LC_MESSAGES .. .. es LC_MESSAGES .. .. es_ES LC_MESSAGES .. .. es_MX LC_MESSAGES .. .. et LC_MESSAGES .. .. eu LC_MESSAGES .. .. fa LC_MESSAGES .. .. fa_IR LC_MESSAGES .. .. fi LC_MESSAGES .. .. fr LC_MESSAGES .. .. fr_FR LC_MESSAGES .. .. ga LC_MESSAGES .. .. gl LC_MESSAGES .. .. gu LC_MESSAGES .. .. he LC_MESSAGES .. .. hi LC_MESSAGES .. .. hr LC_MESSAGES .. .. hu LC_MESSAGES .. .. id LC_MESSAGES .. .. is LC_MESSAGES .. .. it LC_MESSAGES .. .. ja LC_MESSAGES .. .. ka LC_MESSAGES .. .. kn LC_MESSAGES .. .. ko LC_MESSAGES .. .. li LC_MESSAGES .. .. lt LC_MESSAGES .. .. lv LC_MESSAGES .. .. mk LC_MESSAGES .. .. ml LC_MESSAGES .. .. mn LC_MESSAGES .. .. ms LC_MESSAGES .. .. mt LC_MESSAGES .. .. nb LC_MESSAGES .. .. ne LC_MESSAGES .. .. nl LC_MESSAGES .. .. nn LC_MESSAGES .. .. no LC_MESSAGES .. .. or LC_MESSAGES .. .. pa LC_MESSAGES .. .. pl LC_MESSAGES .. .. pt LC_MESSAGES .. .. pt_BR LC_MESSAGES .. .. pt_PT LC_MESSAGES .. .. ro LC_MESSAGES .. .. ru LC_MESSAGES .. .. sk LC_MESSAGES .. .. sl LC_MESSAGES .. .. sq LC_MESSAGES .. .. sr LC_MESSAGES .. .. sr@Latn LC_MESSAGES .. .. sv LC_MESSAGES .. .. ta LC_MESSAGES .. .. tg LC_MESSAGES .. .. th LC_MESSAGES .. .. tk LC_MESSAGES .. .. tr LC_MESSAGES .. .. uk LC_MESSAGES .. .. uz LC_MESSAGES .. .. vi LC_MESSAGES .. .. wa LC_MESSAGES .. .. zh LC_MESSAGES .. .. zh_CN LC_MESSAGES .. .. zh_CN.GB2312 LC_MESSAGES .. .. zh_TW LC_MESSAGES .. .. zh_TW.Big5 LC_MESSAGES .. .. .. misc .. nls C .. af_ZA.ISO8859-1 .. af_ZA.ISO8859-15 .. af_ZA.UTF-8 .. am_ET.UTF-8 .. be_BY.CP1131 .. be_BY.CP1251 .. be_BY.ISO8859-5 .. be_BY.UTF-8 .. bg_BG.CP1251 .. bg_BG.UTF-8 .. ca_ES.ISO8859-1 .. ca_ES.ISO8859-15 .. ca_ES.UTF-8 .. cs_CZ.ISO8859-2 .. cs_CZ.UTF-8 .. da_DK.ISO8859-1 .. da_DK.ISO8859-15 .. da_DK.UTF-8 .. de_AT.ISO8859-1 .. de_AT.ISO8859-15 .. de_AT.UTF-8 .. de_CH.ISO8859-1 .. de_CH.ISO8859-15 .. de_CH.UTF-8 .. de_DE.ISO8859-1 .. de_DE.ISO8859-15 .. de_DE.UTF-8 .. el_GR.ISO8859-7 .. el_GR.UTF-8 .. en_AU.ISO8859-1 .. en_AU.ISO8859-15 .. en_AU.US-ASCII .. en_AU.UTF-8 .. en_CA.ISO8859-1 .. en_CA.ISO8859-15 .. en_CA.US-ASCII .. en_CA.UTF-8 .. en_GB.ISO8859-1 .. en_GB.ISO8859-15 .. en_GB.US-ASCII .. en_GB.UTF-8 .. en_IE.UTF-8 .. en_NZ.ISO8859-1 .. en_NZ.ISO8859-15 .. en_NZ.US-ASCII .. en_NZ.UTF-8 .. en_US.ISO8859-1 .. en_US.ISO8859-15 .. en_US.UTF-8 .. es_ES.ISO8859-1 .. es_ES.ISO8859-15 .. es_ES.UTF-8 .. et_EE.ISO8859-15 .. et_EE.UTF-8 .. fi_FI.ISO8859-1 .. fi_FI.ISO8859-15 .. fi_FI.UTF-8 .. fr_BE.ISO8859-1 .. fr_BE.ISO8859-15 .. fr_BE.UTF-8 .. fr_CA.ISO8859-1 .. fr_CA.ISO8859-15 .. fr_CA.UTF-8 .. fr_CH.ISO8859-1 .. fr_CH.ISO8859-15 .. fr_CH.UTF-8 .. fr_FR.ISO8859-1 .. fr_FR.ISO8859-15 .. fr_FR.UTF-8 .. he_IL.UTF-8 .. hi_IN.ISCII-DEV .. hr_HR.ISO8859-2 .. hr_HR.UTF-8 .. hu_HU.ISO8859-2 .. hu_HU.UTF-8 .. hy_AM.ARMSCII-8 .. hy_AM.UTF-8 .. is_IS.ISO8859-1 .. is_IS.ISO8859-15 .. is_IS.UTF-8 .. it_CH.ISO8859-1 .. it_CH.ISO8859-15 .. it_CH.UTF-8 .. it_IT.ISO8859-1 .. it_IT.ISO8859-15 .. it_IT.UTF-8 .. ja_JP.SJIS .. ja_JP.UTF-8 .. ja_JP.eucJP .. kk_KZ.PT154 .. kk_KZ.UTF-8 .. ko_KR.CP949 .. ko_KR.UTF-8 .. ko_KR.eucKR .. la_LN.ISO8859-1 .. la_LN.ISO8859-15 .. la_LN.ISO8859-2 .. la_LN.ISO8859-4 .. la_LN.US-ASCII .. lt_LT.ISO8859-13 .. lt_LT.ISO8859-4 .. lt_LT.UTF-8 .. nl_BE.ISO8859-1 .. nl_BE.ISO8859-15 .. nl_BE.UTF-8 .. nl_NL.ISO8859-1 .. nl_NL.ISO8859-15 .. nl_NL.UTF-8 .. no_NO.ISO8859-1 .. no_NO.ISO8859-15 .. no_NO.UTF-8 .. pl_PL.ISO8859-2 .. pl_PL.UTF-8 .. pt_BR.ISO8859-1 .. pt_BR.UTF-8 .. pt_PT.ISO8859-1 .. pt_PT.ISO8859-15 .. pt_PT.UTF-8 .. ro_RO.ISO8859-2 .. ro_RO.UTF-8 .. ru_RU.CP1251 .. ru_RU.CP866 .. ru_RU.ISO8859-5 .. ru_RU.KOI8-R .. ru_RU.UTF-8 .. sk_SK.ISO8859-2 .. sk_SK.UTF-8 .. sl_SI.ISO8859-2 .. sl_SI.UTF-8 .. sr_YU.ISO8859-2 .. sr_YU.ISO8859-5 .. sr_YU.UTF-8 .. sv_SE.ISO8859-1 .. sv_SE.ISO8859-15 .. sv_SE.UTF-8 .. tr_TR.ISO8859-9 .. tr_TR.UTF-8 .. uk_UA.ISO8859-5 .. uk_UA.KOI8-U .. uk_UA.UTF-8 .. zh_CN.GB18030 .. zh_CN.GB2312 .. zh_CN.GBK .. zh_CN.UTF-8 .. zh_CN.eucCN .. zh_HK.Big5HKSCS .. zh_HK.UTF-8 .. zh_TW.Big5 .. zh_TW.UTF-8 .. .. pixmaps .. sgml .. skel .. xml .. .. www .. .. percona-galera-3-3.8-3390/scripts/packages/freebsd/galera-plist000066400000000000000000000026511244131713600241740ustar00rootroot00000000000000@comment PKG_FORMAT_REVISION:1.1 @name galera-%{RELEASE} @comment ORIGIN:databases/galera @cwd /usr/local @srcdir %{SRCDIR} @comment "=== dependencies ===" @comment "require /usr/local/lib/gcc48/libstdc++.so" @comment // @pkgdep gcc-4.8.2.s20130808 @comment DEPORIGIN:lang/gcc48 @comment // @pkgdep openssl-1.0.1_8 @comment DEPORIGIN:security/openssl @comment // @pkgdep libexecinfo-1.1_3 @comment DEPORIGIN:devel/libexecinfo @comment "=== preinstall stage ===" @exec echo "===> Linking /usr/local/bin/bash to /bin/bash" @exec [ -x /bin/bash ] && echo "Using existing /bin/bash." || ln -s ../usr/local/bin/bash /bin/bash @comment "=== file section ===" @owner root @group wheel @mode 0444 share/licenses/galera-%{RELEASE}/catalog.mk share/licenses/galera-%{RELEASE}/LICENSE share/licenses/galera-%{RELEASE}/GPLv2 share/licenses/galera-%{RELEASE}/LICENSE.asio share/licenses/galera-%{RELEASE}/LICENSE.crc32c share/licenses/galera-%{RELEASE}/LICENSE.chromium @mode 0555 etc/rc.d/garb bin/garbd @mode 0444 lib/galera/libgalera_smm.so share/doc/galera/README share/doc/galera/README-MySQL libdata/ldconfig/galera @comment "=== postinstall stage ===" @exec /sbin/ldconfig -m /usr/local/lib/galera @comment "=== postremove stage ===" @dirrm share/licenses/galera-%{RELEASE} @dirrm share/doc/galera @comment // @unexec rm -f $(find /usr/local/lib/galera -type l)" @dirrm lib/galera @comment // @unexec ldconfig -R @unexec service ldconfig start >/dev/null percona-galera-3-3.8-3390/scripts/packages/galera-common.inc000066400000000000000000000020631244131713600234640ustar00rootroot00000000000000# This is Galera package description for ESP package manager %product Galera Replication Framework %copyright 2007-2013 by Codership Oy, All Rights Reserved %vendor Codership Oy %license COPYING %readme README %description Replication framework for transactional applications. Implements wsrep interface. %version ${GALERA_VER} %provides wsrep %provides galera %format deb %replaces galera %requires libc6 2.4 %requires libstdc++6 4.1.1 %requires libgcc1 4.1.1 %requires libssl${OPENSSL_SHLIB_VERSION_NUMBER} %format rpm %requires glibc 2.4 %requires libstdc++ 4.1.2 %requires libgcc 4.1.2 %requires libssl.so.6 %format all $prefix=/usr %format !rpm $CONF_DEST=/etc/default $LIBS_DEST=${prefix}/lib/galera %format rpm $CONF_DEST=/etc/sysconfig %if x86_64 $LIBS_DEST=${prefix}/lib64/galera %else $LIBS_DEST=${prefix}/lib/galera %endif %format all $INIT_DEST=/etc/init.d $INCS_DEST=${prefix}/include/galera $SBIN_DEST=${prefix}/sbin $BINS_DEST=${prefix}/bin $DOCS_DEST=${prefix}/share/doc/galera # percona-galera-3-3.8-3390/scripts/packages/galera-dev.list000066400000000000000000000026161244131713600231600ustar00rootroot00000000000000# This is Galera development package description for ESP package manager %include galera-common.inc d 755 root root $INCS_DEST - f 644 root root $INCS_DEST/gcs.h $BUILD_BASE/gcs/src/gcs.h f 644 root root $INCS_DEST/wsdb_api.h $BUILD_BASE/wsdb/src/wsdb_api.h f 644 root root $INCS_DEST/wsrep_api.h $BUILD_BASE/galera/src/wsrep_api.h d 755 root root $LIBS_DEST - f 755 root root $LIBS_DEST/libgalerautils.a $BUILD_BASE/galerautils/src/.libs/libgalerautils.a f 755 root root $LIBS_DEST/libgalerautils++.a $BUILD_BASE/galerautils/src/.libs/libgalerautils++.a %ifdef GCOMM #f 755 root root $LIBS_DEST/libgcomm.a $BUILD_BASE//gcomm/src/.libs/libgcomm.a %endif %ifdef VSBES f 755 root root $LIBS_DEST/libgcommcommonpp.a $BUILD_BASE/galeracomm/common/src/.libs/libgcommcommonpp.a f 755 root root $LIBS_DEST/libgcommtransportpp.a $BUILD_BASE/galeracomm/transport/src/.libs/libgcommtransportpp.a f 755 root root $LIBS_DEST/libgcommvspp.a $BUILD_BASE/galeracomm/vs/src/.libs/libgcommvspp.a %endif f 755 root root $LIBS_DEST/libgcs.a $BUILD_BASE/gcs/src/.libs/libgcs.a f 755 root root $LIBS_DEST/libwsdb.a $BUILD_BASE/wsdb/src/.libs/libwsdb.a f 755 root root $LIBS_DEST/libmmgalera.a $BUILD_BASE/galera/src/.libs/libmmgalera.a %format deb # Debian packages come with bad file ownership %postinstall <. # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License or later. # # 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; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston # MA 02110-1301 USA. %{!?name: %define name galera} %{!?version: %define version 3.x} %{!?release: %define release 1} %define copyright Copyright 2007-2014 Codership Oy. All rights reserved. Use is subject to license terms under GPLv2 license. %define libs %{_libdir}/%{name} %define docs /usr/share/doc/%{name} %dump Name: %{name} Summary: Galera: a synchronous multi-master wsrep provider (replication engine) Group: System Environment/Libraries Version: %{version} Release: %{release} License: GPL-2.0 Source: %{name}-%{version}.tar.gz URL: http://www.codership.com/ Packager: Codership Oy Vendor: Codership Oy BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: boost-devel BuildRequires: check-devel BuildRequires: glibc-devel BuildRequires: openssl-devel BuildRequires: scons %if 0%{?suse_version} == 1110 # On SLES11 SPx use the linked gcc47 to build instead of default gcc43 BuildRequires: gcc47 gcc47-c++ # On SLES11 SP2 the libgfortran.3.so provider must be explicitly defined BuildRequires: libgfortran3 # On SLES11 we got error "conflict for provider of libgcc_s1 >= 4.7.4_20140612-2.1 # needed by gcc47, (provider libgcc_s1 conflicts with installed libgcc43), # conflict for provider of libgomp1 >= 4.7.4_20140612-2.1 needed by gcc47, # (provider libgomp1 conflicts with installed libgomp43), conflict for provider # of libstdc++6 >= 4.7.4_20140612-2.1 needed by libstdc++47-devel, # (provider libstdc++6 conflicts with installed libstdc++43) # therefore: BuildRequires: libgcc_s1 BuildRequires: libgomp1 BuildRequires: libstdc++6 #!BuildIgnore: libgcc43 %else BuildRequires: gcc-c++ %endif %if %{defined fedora} BuildRequires: python %endif # Systemd %if 0%{?suse_version} >= 1220 || 0%{?centos} >= 7 || 0%{?rhel} >= 7 %define systemd 1 BuildRequires: systemd %else %define systemd 0 %endif Requires: openssl nmap Provides: wsrep, %{name} = %{version}-%{release} %description Galera is a fast synchronous multimaster wsrep provider (replication engine) for transactional databases and similar applications. For more information about wsrep API see http://launchpad.net/wsrep. For a description of Galera replication engine see http://www.codership.com. %{copyright} This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPLv2 license. %prep %setup -q %build # Debug info: echo "suse_version: %{suse_version}" # 1110 = SLE-11 SPx %if 0%{?suse_version} == 1110 export CC=gcc-4.7 export CXX=g++-4.7 %endif %if 0%{?suse_version} == 1120 export CC=gcc-4.6 export CXX=g++-4.6 %endif %if 0%{?suse_version} == 1130 export CC=gcc-4.7 export CXX=g++-4.7 %endif scons -j$(echo ${NUM_JOBS:-"1"}) %install RBR=$RPM_BUILD_ROOT # eg. rpmbuild/BUILDROOT/galera-3.x-17.1.x86_64 RBD=$RPM_BUILD_DIR/%{name}-%{version} # eg. rpmbuild/BUILD/galera-3.x # Clean up the BuildRoot first [ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; mkdir -p $RBR %if 0%{?systemd} install -D -m 644 $RBD/garb/files/garb.service $RBR%{_unitdir}/garb.service install -D -m 755 $RBD/garb/files/garb-systemd $RBR%{_bindir}/garb-systemd %else install -d $RBR%{_sysconfdir}/init.d install -m 755 $RBD/garb/files/garb.sh $RBR%{_sysconfdir}/init.d/garb # Symlink required by SUSE policy %if 0%{?suse_version} install -d $RBR/usr/sbin ln -sf /etc/init.d/garb $RBR/usr/sbin/rcgarb %endif %endif %if 0%{?suse_version} install -d $RBR/var/adm/fillup-templates/ install -m 644 $RBD/garb/files/garb.cnf $RBR/var/adm/fillup-templates/sysconfig.%{name} %else install -d $RBR%{_sysconfdir}/sysconfig install -m 644 $RBD/garb/files/garb.cnf $RBR%{_sysconfdir}/sysconfig/garb %endif install -d $RBR%{_bindir} install -m 755 $RBD/garb/garbd $RBR%{_bindir}/garbd install -d $RBR%{libs} install -m 755 $RBD/libgalera_smm.so $RBR%{libs}/libgalera_smm.so install -d $RBR%{docs} install -m 644 $RBD/COPYING $RBR%{docs}/COPYING install -m 644 $RBD/asio/LICENSE_1_0.txt $RBR%{docs}/LICENSE.asio install -m 644 $RBD/www.evanjones.ca/LICENSE $RBR%{docs}/LICENSE.crc32c install -m 644 $RBD/chromium/LICENSE $RBR%{docs}/LICENSE.chromium install -m 644 $RBD/scripts/packages/README $RBR%{docs}/README install -m 644 $RBD/scripts/packages/README-MySQL $RBR%{docs}/README-MySQL install -d $RBR%{_mandir}/man1 install -m 644 $RBD/garb/files/garbd.troff $RBR%{_mandir}/man1/garbd.1 %post %fillup_and_insserv %preun %stop_on_removal rm -f $(find %{libs} -type l) %postun %restart_on_update %insserv_cleanup %files %defattr(-,root,root,0755) %if 0%{?suse_version} %config(noreplace,missingok) /var/adm/fillup-templates/sysconfig.%{name} %else %config(noreplace,missingok) %{_sysconfdir}/sysconfig/garb %endif %if 0%{?systemd} %attr(0644,root,root) %{_unitdir}/garb.service %attr(0755,root,root) %{_bindir}/garb-systemd %else %attr(0755,root,root) %{_sysconfdir}/init.d/garb # Symlink required by SUSE policy %if 0%{?suse_version} %attr(0755,root,root) /usr/sbin/rcgarb %endif %endif %attr(0755,root,root) %{_bindir}/garbd %attr(0755,root,root) %dir %{libs} %attr(0755,root,root) %{libs}/libgalera_smm.so %attr(0755,root,root) %dir %{docs} %doc %attr(0644,root,root) %{docs}/COPYING %doc %attr(0644,root,root) %{docs}/LICENSE.asio %doc %attr(0644,root,root) %{docs}/LICENSE.crc32c %doc %attr(0644,root,root) %{docs}/LICENSE.chromium %doc %attr(0644,root,root) %{docs}/README %doc %attr(0644,root,root) %{docs}/README-MySQL %doc %attr(644, root, man) %{_mandir}/man1/garbd.1* %clean [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; %changelog * Tue Sep 30 2014 Otto Kekäläinen - 3.x - Initial OBS packaging created percona-galera-3-3.8-3390/scripts/packages/galera.list000066400000000000000000000027601244131713600224040ustar00rootroot00000000000000# This is Galera package description for ESP package manager %include galera-common.inc # this line is required by rpmbuild #d 755 root root /usr d 755 root root $CONF_DEST - c 644 root root $CONF_DEST/garb $BUILD_BASE/garb/files/garb.cnf # i 755 root sys foo foo.sh - this creates links in rc*.d, we dont want it d 755 root root $INIT_DEST - f 755 root root $INIT_DEST/garb $BUILD_BASE/garb/files/garb.sh d 755 root root $BINS_DEST - f 755 root root $BINS_DEST/garbd $BUILD_BASE/garb/garbd d 755 root root $LIBS_DEST - f 755 root root $LIBS_DEST/libgalera_smm.so $BUILD_BASE/libgalera_smm.so d 755 root root $DOCS_DEST - f 644 root root $DOCS_DEST/COPYING $BUILD_BASE/LICENSE f 644 root root $DOCS_DEST/LICENSE.asio $BUILD_BASE/asio/LICENSE_1_0.txt f 644 root root $DOCS_DEST/LICENSE.crc32c $BUILD_BASE/www.evanjones.ca/LICENSE f 644 root root $DOCS_DEST/LICENSE.chromium $BUILD_BASE/chromium/LICENSE f 644 root root $DOCS_DEST/README README f 644 root root $DOCS_DEST/README-MySQL README-MySQL $LD_SO_CONF_D=/etc/ld.so.conf.d d 755 root root $LD_SO_CONF_D - # the reason we don't create this file in postinstall script is to have it # in the package database f 644 root root $LD_SO_CONF_D/galera.conf empty %postinstall < $LD_SO_CONF_D/galera.conf ldconfig $LIBS_DEST EOF_POSTINSTALL %preremove <. # All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License or later. # # 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; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston # MA 02110-1301 USA. %define name galera # use "rpmbuild --define 'version xxxx'" to define version %{!?version: %define version 3.x} %{!?release: %define release 1} %define copyright Copyright 2007-2014 Codership Oy. All rights reserved. Use is subject to license terms under GPLv2 license. %define libs %{_libdir}/%{name} %define docs /usr/share/doc/%{name} Name: %{name} Summary: Galera: a synchronous multi-master wsrep provider (replication engine) Group: System Environment/Libraries Version: %{version} Release: %{release} License: GPLv2 Source: http://www.codership.com/downloads/download-mysqlgalera/ URL: http://www.codership.com/ Packager: Codership Oy Vendor: Codership Oy Provides: %{name} wsrep Obsoletes: %{name} Requires: chkconfig #Requires: boost-program-options # BuildRequires: scons check boost-devel # This will be rm -rf BuildRoot: %{_tmppath}/%{name}-%{version} %description Galera is a fast synchronous multimaster wsrep provider (replication engine) for transactional databases and similar applications. For more information about wsrep API see http://launchpad.net/wsrep. For a description of Galera replication engine see http://www.codership.com. %{copyright} This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPLv2 license. %prep #%setup -T -a 0 -c -n galera-%{version} %build Build() { CFLAGS=${CFLAGS:-$RPM_OPT_FLAGS} CXXFLAGS=${CXXFLAGS:-$RPM_OPT_FLAGS} # We assume that Galera is built already by the top build.sh script } %install RBR=$RPM_BUILD_ROOT RBD=$RPM_BUILD_DIR # Clean up the BuildRoot first [ "$RBR" != "/" ] && [ -d $RBR ] && rm -rf $RBR; mkdir -p $RBR install -d $RBR%{_sysconfdir}/{init.d,sysconfig} install -m 644 $RBD/garb/files/garb.cnf $RBR%{_sysconfdir}/sysconfig/garb install -m 755 $RBD/garb/files/garb.sh $RBR%{_sysconfdir}/init.d/garb install -d $RBR%{_bindir} install -m 755 $RBD/garb/garbd $RBR%{_bindir}/garbd install -d $RBR%{libs} install -m 755 $RBD/libgalera_smm.so $RBR%{libs}/libgalera_smm.so install -d $RBR%{docs} install -m 644 $RBD/COPYING $RBR%{docs}/COPYING install -m 644 $RBD/asio/LICENSE_1_0.txt $RBR%{docs}/LICENSE.asio install -m 644 $RBD/www.evanjones.ca/LICENSE $RBR%{docs}/LICENSE.crc32c install -m 644 $RBD/chromium/LICENSE $RBR%{docs}/LICENSE.chromium install -m 644 $RBD/scripts/packages/README $RBR%{docs}/README install -m 644 $RBD/scripts/packages/README-MySQL $RBR%{docs}/README-MySQL install -d $RBR%{_mandir} install -m 644 $RBD/garb/files/garbd.troff $RBR%{_mandir}/man1/garbd.1 %pre %post %preun rm -f $(find %{libs} -type l) %files %defattr(-,root,root,0755) %config(noreplace,missingok) %{_sysconfdir}/sysconfig/garb %attr(0755,root,root) %{_sysconfdir}/init.d/garb %attr(0755,root,root) %{_bindir}/garbd %attr(0755,root,root) %dir %{libs} %attr(0755,root,root) %{libs}/libgalera_smm.so %attr(0755,root,root) %dir %{docs} %doc %attr(0644,root,root) %{docs}/COPYING %doc %attr(0644,root,root) %{docs}/LICENSE.asio %doc %attr(0644,root,root) %{docs}/LICENSE.crc32c %doc %attr(0644,root,root) %{docs}/LICENSE.chromium %doc %attr(0644,root,root) %{docs}/README %doc %attr(0644,root,root) %{docs}/README-MySQL %doc %attr(644, root, man) %{_mandir}/man1/garbd.1* %clean [ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; percona-galera-3-3.8-3390/scripts/packages/rpm.sh000077500000000000000000000025051244131713600214060ustar00rootroot00000000000000#!/bin/bash -eu if [ $# -ne 1 ] then echo "Usage: $0 " exit 1 fi set -x # Absolute path of this script folder SCRIPT_ROOT=$(cd $(dirname $0); pwd -P) THIS_DIR=$(pwd -P) RPM_TOP_DIR=$SCRIPT_ROOT/rpm_top_dir rm -rf $RPM_TOP_DIR mkdir -p $RPM_TOP_DIR/RPMS ln -s ../../../ $RPM_TOP_DIR/BUILD fast_cflags="-O3 -fno-omit-frame-pointer" uname -m | grep -q i686 && \ cpu_cflags="-mtune=i686" || cpu_cflags="-mtune=core2" RPM_OPT_FLAGS="$fast_cflags $cpu_cflags" GALERA_SPEC=$SCRIPT_ROOT/galera.spec RELEASE=${RELEASE:-"1"} if [ -r /etc/fedora-release ] then DISTRO_VERSION=fc$(rpm -qf --qf '%{version}\n' /etc/fedora-release) elif [ -r /etc/redhat-release ] then DISTRO_VERSION=rhel$(rpm -qf --qf '%{version}\n' /etc/redhat-release) elif [ -r /etc/SuSE-release ] then DISTRO_VERSION=sles$(rpm -qf --qf '%{version}\n' /etc/SuSE-release | cut -d. -f1) else DISTRO_VERSION= fi [ -n "$DISTRO_VERSION" ] && RELEASE=$RELEASE.$DISTRO_VERSION $(which rpmbuild) --clean --define "_topdir $RPM_TOP_DIR" \ --define "optflags $RPM_OPT_FLAGS" \ --define "version $1" \ --define "release $RELEASE" \ -bb --short-circuit -bi $GALERA_SPEC RPM_ARCH=$(uname -m | sed s/i686/i386/) mv $RPM_TOP_DIR/RPMS/$RPM_ARCH/galera-*.rpm ./ rm -rf $RPM_TOP_DIR exit 0 percona-galera-3-3.8-3390/scripts/source/000077500000000000000000000000001244131713600177715ustar00rootroot00000000000000percona-galera-3-3.8-3390/scripts/source/COPYING000066400000000000000000000432541244131713600210340ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. percona-galera-3-3.8-3390/scripts/source/README000066400000000000000000000004601244131713600206510ustar00rootroot00000000000000This is release 0.7 of Galera - Codership's implementation of wsrep interface (https://launchpad.net/wsrep) For details see http://www.codership.com. Build order: 1. libgalerautils 2. libgcomm 3. libgcs 4. libwsdb 5. libgalera Building unit tests requires check library (http://check.sourceforge.net) percona-galera-3-3.8-3390/scripts/source/build.sh000077500000000000000000000035471244131713600214400ustar00rootroot00000000000000#!/bin/bash -eu # $Id: build.sh 1323 2009-11-22 23:48:22Z alex $ usage() { echo -e "Usage: build.sh [script options] [configure options]\n"\ "Script options:\n"\ " -h|--help this help message\n"\ " -i|--install install libraries system-wide\n" } INSTALL="no" CONFIGURE="no" LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""} CPPFLAGS=${CPPFLAGS:-""} LDFLAGS=${LDFLAGS:-""} if ccache -V > /dev/null 2>&1 then CC=${CC:-"gcc"} CXX=${CXX:-"g++"} echo "$CC" | grep "ccache" > /dev/null || CC="ccache $CC" echo "$CXX" | grep "ccache" > /dev/null || CXX="ccache $CXX" export CC CXX fi while test $# -gt 0 do case $1 in -i|--install) INSTALL="yes" shift ;; -h|--help) usage exit 1 ;; *) # what's left is the arguments for configure CONFIGURE="yes" break ;; esac done # Build process base directory build_base=$(cd $(dirname $0); pwd -P) # Updates build flags for the next stage build_flags() { local build_dir=$1 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$build_dir/src/.libs CPPFLAGS="$CPPFLAGS -I$build_dir/src " LDFLAGS="$LDFLAGS -L$build_dir/src/.libs" } # Function to build single project build() { local build_dir=$1 shift echo "Building: $build_dir ($@)" pushd $build_dir export LD_LIBRARY_PATH export CPPFLAGS export LDFLAGS local SCRATCH=no if [ ! -s "Makefile" ]; then CONFIGURE=yes; fi if [ "$CONFIGURE" == "yes" ]; then rm -rf config.status; ./configure $@; SCRATCH=yes ; fi if [ "$SCRATCH" == "yes" ]; then make clean ; fi make || return 1 if [ "$INSTALL" == "yes" ] then make install || return 1 else build_flags $(pwd -P) || return 1 fi popd } build "libgalerautils*" $@ build "libgcomm*" $@ build "libgcs*" $@ build "libwsdb*" $@ build "libgalera*" $@ percona-galera-3-3.8-3390/scripts/source/package.sh000077500000000000000000000044311244131713600217250ustar00rootroot00000000000000#!/bin/bash -eu # $Id: build.sh 1323 2009-11-22 23:48:22Z alex $ usage() { echo -e "Usage: build.sh [script options] [configure options] \n" \ "Script options:\n" \ " -h|--help this help message\n"\ " -r|--release release number to put in the tarball\n"\ " name: galera-source-XXX.tgz" } RELEASE="" CONFIGURE="no" LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""} CPPFLAGS=${CPPFLAGS:-""} LDFLAGS=${LDFLAGS:-""} while test $# -gt 0 do case $1 in -r|--release) RELEASE=$2 shift shift ;; -h|--help) usage exit 1 ;; *) # what's left is the arguments for configure break ;; esac done # Build process base directory BUILD_BASE=$(cd $(dirname $0)/../../; pwd -P) # Updates build flags for the next stage build_flags() { local build_dir=$1 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$build_dir/src/.libs CPPFLAGS="$CPPFLAGS -I$build_dir/src " LDFLAGS="$LDFLAGS -L$build_dir/src/.libs" } # Function to build single project build() { local module=$1 shift local build_dir=$BUILD_BASE/$module echo "Building: $build_dir ($@)" pushd $build_dir export LD_LIBRARY_PATH export CPPFLAGS export LDFLAGS if [ ! -x "configure" ]; then ./bootstrap.sh; fi if [ ! -s "Makefile" ]; then ./configure $@; fi local src_base_name="lib${module}-" rm -rf "${src_base_name}"*.tar.gz make dist || return 1 build_flags $build_dir || return 1 local ret=$(ls "${src_base_name}"*.tar.gz) popd echo $build_dir/$ret } build_sources() { local module local srcs="" for module in "galerautils" "gcomm" "gcs" "wsdb" "galera" do src=$(build $module $@ | tail -n 1) || return 1 srcs="$srcs $src" done if [ -z "$RELEASE" ] then pushd "$BUILD_BASE" RELEASE="r$(svnversion | sed s/\:/,/g)" popd fi local dist_dir="galera-source-$RELEASE" rm -rf $dist_dir mkdir -p $dist_dir for src in $srcs do tar -C $dist_dir -xzf $src done cp "README" "COPYING" "build.sh" $dist_dir/ tar -czf $dist_dir.tgz $dist_dir # return absolute path for scripts echo $PWD/$dist_dir.tgz } pushd $(dirname $0) build_sources $@ percona-galera-3-3.8-3390/tests/000077500000000000000000000000001244131713600161445ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/conf/000077500000000000000000000000001244131713600170715ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/conf/cluster.conf.tmpl000066400000000000000000000030561244131713600224000ustar00rootroot00000000000000# # Cluster resources configuration. # # DBMS that will be used for tests export DBMS=${DBMS:-"MYSQL"} # DBMS superuser username and password for administrative purposes export DBMS_ROOT_USER=${DBMS_ROOT_USER:-"root"} export DBMS_ROOT_PSWD=${DBMS_ROOT_PSWD:-"rootpass"} # DBMS test use username and password export DBMS_TEST_USER=${DBMS_TEST_USER:-"test"} export DBMS_TEST_PSWD=${DBMS_TEST_PSWD:-"testpass"} # DBMS schema to use for tests export DBMS_TEST_SCHEMA=${DBMS_TEST_SCHEMA:-"test"} # Host for clients to connect to export DBMS_HOST=${DBMS_HOST:-"127.0.0.1"} # Port for MySQL specific tests export MYSQL_PORT=${MYSQL_PORT:-"3306"} # Port for PostgreSQL specific tests export PGSQL_PORT=${PGSQL_PORT:-"5432"} # Port for crossplatform tests case "$DBMS" in "MYSQL") export DBMS_PORT=${DBMS_PORT:-"$MYSQL_PORT"} ;; "PGSQL") export DBMS_PORT=${DBMS_PORT:-"$PGSQL_PORT"} ;; esac # How many concurrent clients to use export DBMS_CLIENTS=${DBMS_CLIENTS:-"16"} # Type of GCS backend export GCS_TYPE=${GCS_TYPE:-"gcomm"} case "$GCS_TYPE" in "gcomm") ;; "vsbes") if [ -z "$VSBES_ADDRESS" ]; then echo "VSBES_ADDRESS is not set"; exit 1; fi ;; *) echo "Urecognized GCS_TYPE: '$GCS_TYPE'" ; exit 1 ;; esac # Extra parameters passed to gcomm backend. # # export GCOMM_EXTRA_PARAMS=${GCOMM_EXTRA_PARAMS:-"gmcast.mcast_addr=239.192.0.11"} # default replication port export GCS_PORT=4567 # common part of my.cnf export COMMON_MY_CNF=$BASE_CONF/common_my.cnf # libglb.so location if not standard (/usr/lib|/usr/local/lib) #GLB_LIB= . $BASE_CONF/nodes.conf # end percona-galera-3-3.8-3390/tests/conf/dummy.conf000066400000000000000000000000771244131713600210770ustar00rootroot00000000000000# Script arguments t/dummy.sh arg1 arg2 t/dummy.sh arg3 arg4 percona-galera-3-3.8-3390/tests/conf/galera_cert.pem000066400000000000000000000021771244131713600220530ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDJDCCAo2gAwIBAgIJAL6/ZXC+Xx/xMA0GCSqGSIb3DQEBBQUAMGoxCzAJBgNV BAYTAkZJMRMwEQYDVQQIEwpTb21lLVN0YXRlMRUwEwYDVQQKEwxDb2RlcnNoaXAg T3kxDDAKBgNVBAsUA1ImRDEhMB8GCSqGSIb3DQEJARYSaW5mb0Bjb2RlcnNoaXAu Y29tMCAXDTExMDgxNTA5NTU1OFoYDzMwMTAxMjE2MDk1NTU4WjBqMQswCQYDVQQG EwJGSTETMBEGA1UECBMKU29tZS1TdGF0ZTEVMBMGA1UEChMMQ29kZXJzaGlwIE95 MQwwCgYDVQQLFANSJkQxITAfBgkqhkiG9w0BCQEWEmluZm9AY29kZXJzaGlwLmNv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LBFNowDw6d8njjguINZc2Xy 7puA0J8Jy6xCsnI/JtgxCMFI7ytvwm6VWfkpJd5aKiNhSV1Nr6Gmzqp8rzboZLWf Abptdnn8k2wE00YpXhVcrw0atcTEugOddBrS60m77Y2gLN9Dj00z49ZPBu4TW5rc QCX5E+PZXeQqZ6QqS1ECAwEAAaOBzzCBzDAdBgNVHQ4EFgQUXhvWGncIUO/lqGkO Rqdm5AEMsBQwgZwGA1UdIwSBlDCBkYAUXhvWGncIUO/lqGkORqdm5AEMsBShbqRs MGoxCzAJBgNVBAYTAkZJMRMwEQYDVQQIEwpTb21lLVN0YXRlMRUwEwYDVQQKEwxD b2RlcnNoaXAgT3kxDDAKBgNVBAsUA1ImRDEhMB8GCSqGSIb3DQEJARYSaW5mb0Bj b2RlcnNoaXAuY29tggkAvr9lcL5fH/EwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B AQUFAAOBgQCIIp+/5+sa7o/VqAwk/SlctQOVJRrv5Ciy1qYVL6UcsTPFIE3w0ttP NUmD/+ck40U4NXhWaQPrUsT08QkoHqBe4LQbuURN/iscbX2THvawkKFxuHTES6p0 vntTDjqBuvVmrwy+ttOwa7hbUOTkE5VOEJYbx6Ejsjb7dNQCSLMcdg== -----END CERTIFICATE----- percona-galera-3-3.8-3390/tests/conf/galera_key.pem000066400000000000000000000015671244131713600217100ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDQsEU2jAPDp3yeOOC4g1lzZfLum4DQnwnLrEKycj8m2DEIwUjv K2/CbpVZ+Skl3loqI2FJXU2voabOqnyvNuhktZ8Bum12efyTbATTRileFVyvDRq1 xMS6A510GtLrSbvtjaAs30OPTTPj1k8G7hNbmtxAJfkT49ld5CpnpCpLUQIDAQAB AoGATP/M+dxdgzJoG6UW3V2xgo+qO/nqZI9ZuOmdTmQzAu0f4oAWnhCj0tSkjKcP VKafFA8r1Tr08AmwF272RFv5EI0Vr76CyRUmw1Jq3gl4I5s6hqkYEnNiA3KuMcev ea+1briHm2ezLvC+YhQ02NP9hLkiipmN5Bi9Oh5EID0tg7ECQQDnuhOvbtqhPZxo 5jphwqwAYr+QtDadTLX8nKSj61wjyaB5owafA98CBvvcxg405MBFYauU9a2eWGDl dsxDrkF1AkEA5oxnlpOESqltIKIyfixEIkWfMxF6jf9OeiY1ctjZoprm/V83QsBq 60FfUwluhlG8pMriW4CU8S/c6WCMRuCq7QJBALtFYktRJ1dP12vfRCdlkGPvaimj us99A0ZXwabHuvshI5Op8Nvp4PxecIWHeku84rYvrN8BfYKOoiBP1dyMo1ECQQDc HyBkf1JnKt77soF9QGyJQGohC0Y1P5dBPyv3DJ63BykWr4uGm0s6dT87fBzf+Dii Kuf2r40Fv0owNTOaFLZ9AkACDW9483PlXdbmCxLwl5tqY0EExlwuRVVTga4ViNjp dMxjA9lS4sVvPKSkysq3RkCdkxuYtQcxl9NQOaW23KHn -----END RSA PRIVATE KEY----- percona-galera-3-3.8-3390/tests/conf/main.conf000066400000000000000000000024031244131713600206630ustar00rootroot00000000000000#declare -r BASE_LOG="$TEST_BASE/log" declare -r BASE_OUT="$TEST_BASE/out" mkdir -p "$BASE_OUT" declare -r BASE_RUN="$TEST_BASE/run" mkdir -p "$BASE_RUN" declare -r BASE_CONF="$TEST_BASE/conf" . ${CLUSTER_CONF:-"$BASE_CONF/cluster.conf"} if [ "$(uname -s)" == "Darwin" ]; then GLB_PRELOAD=${DYLD_INSERT_LIBRARIES:-""} else GLB_PRELOAD=${LD_PRELOAD:-""} fi export GLB_PRELOAD # The code below tries to find available libglb.so and if found, export # necessary variables for client side load balancing GLB_LIB=${GLB_LIB:-""} if [ -z "$GLB_LIB" ] then if [ -r /usr/local/lib/libglb.so ] then GLB_LIB="/usr/local/lib/libglb.so" elif [ -r /usr/lib/libglb.so ] then GLB_LIB="/usr/lib/libglb.so" fi fi if [ -r "$GLB_LIB" ] then if [ -n "$GLB_PRELOAD" ] then export GLB_PRELOAD="$GLB_LIB:$GLB_PRELOAD" else export GLB_PRELOAD="$GLB_LIB" fi export GLB_BIND=$DBMS_HOST:$DBMS_PORT GLB_TARGETS="" for node in $NODE_LIST do target=${NODE_INCOMING_HOST[$node]}:${NODE_INCOMING_PORT[$node]} if [ $node -ne $NODE_MAX ] then GLB_TARGETS="$GLB_TARGETS$target," else GLB_TARGETS="$GLB_TARGETS$target" fi done export GLB_TARGETS fi percona-galera-3-3.8-3390/tests/conf/nodes.conf.tmpl000066400000000000000000000035761244131713600220360ustar00rootroot00000000000000# # Nodes specific configuration # # Symbolic node ID - for output, for future use shoudl be unique declare -a NODE_ID # Location of the node. "local" - means this machine, anything else # is interpreted as SSH arguments declare -a NODE_LOCATION # Absolute path to where to unpack the distribution declare -a NODE_TEST_DIR # Address for incoming requests declare -a NODE_INCOMING_HOST declare -a NODE_INCOMING_PORT # Address for group communicaiton declare -a NODE_GCS_HOST declare -a NODE_GCS_PORT # Optional server configuration file to be copied to node declare -a NODE_MY_CNF declare -a NODE_PG_CNF # 1st node idx=0 NODE_ID[$idx]="home" NODE_INCOMING_HOST[$idx]=127.0.0.1 NODE_INCOMING_PORT[$idx]=$(( $DBMS_PORT - 1 )) NODE_GCS_HOST[$idx]=192.168.0.1 NODE_GCS_PORT[$idx]=$GCS_PORT NODE_LOCATION[$idx]="local" NODE_TEST_DIR[$idx]=/tmp/galera NODE_MY_CNF[$idx]="$TEST_BASE/conf/my.cnf" # 2nd node idx=$(( $idx + 1 )) NODE_ID[$idx]="bernhard" NODE_INCOMING_HOST[$idx]=192.168.0.3 NODE_INCOMING_PORT[$idx]=$DBMS_PORT NODE_GCS_HOST[$idx]=${NODE_INCOMING_HOST[$idx]} NODE_GCS_PORT[$idx]=$GCS_PORT NODE_LOCATION[$idx]="alex@${NODE_INCOMING_HOST[$idx]}" NODE_TEST_DIR[$idx]=/home/alex/codership/galera NODE_MY_CNF[$idx]="$TEST_BASE/conf/my.cnf" # 3rd node #idx=$(( $idx + 1 )) #NODE_ID[$idx]="bulldog" #NODE_INCOMING_HOST[$idx]=192.168.0.12 #NODE_INCOMING_PORT[$idx]=$DBMS_PORT #NODE_GCS_HOST[$idx]=${NODE_INCOMING_HOST[$idx]} #NODE_GCS_PORT[$idx]=$GCS_PORT #NODE_LOCATION[$idx]="alex@${NODE_INCOMING_HOST[$idx]}" #NODE_TEST_DIR[$idx]=/home/alex/codership/galera #NODE_MY_CNF[$idx]="$TEST_BASE/conf/my.cnf" declare -xr NODE_MAX=$idx declare -xr NODE_LIST=$(seq 0 $NODE_MAX) declare -xr NODE_ID declare -xr NODE_LOCATION declare -xr NODE_TEST_DIR declare -xr NODE_INCOMING_HOST declare -xr NODE_INCOMING_PORT declare -xr NODE_GCS_HOST declare -xr NODE_GCS_PORT declare -xr NODE_MY_CNF declare -xr NODE_PG_CNF # percona-galera-3-3.8-3390/tests/conf/sqlgen.conf000066400000000000000000000001701244131713600212270ustar00rootroot00000000000000# Script test_sqlgen/run.sh --create 1 --rows 500 --duration 10 test_sqlgen/run.sh --create 1 --rows 1000 --duration 10 percona-galera-3-3.8-3390/tests/regressions/000077500000000000000000000000001244131713600205075ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1003929/000077500000000000000000000000001244131713600216725ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1003929/run.sh000077500000000000000000000063551244131713600230460ustar00rootroot00000000000000#!/bin/bash -e ## # # lp:1003929 # https://bugs.launchpad.net/codership-mysql/+bug/1003929 # # BUG BACKGRPOUND: # # Table which ahs no primary key but has one or more unique keys # defined may cause a crash in slave configured for parallel applying. # This is due to the probölem that for such tables we generate only # full row hash as key value - the individual unique keys are not appended # in write set. # # If bug is present, slave appliers can easily conflict and cause crash. # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - a table with no PK but one UK is created # - test load runs inserts/delete load for the table so that # inserted rows are different but unoque key values match # # SUCCESS CRITERIA # # If bug is present, slave will crash for DUPKEY error, PA control # allow two subsequent inserts to happen in parallel, althoug they # try to insert same unique key # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1003929" echo "##################################################################" echo "stopping cluster" $SCRIPTS/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD -Dtest " declare -r port_0=$(( DBMS_PORT )) declare -r port_1=$(( DBMS_PORT + 1)) declare -r node_0="-h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]}" declare -r node_1="-h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]}" inserter() { local node="$@" for i in {1..10000}; do $MYSQL $node -e " DELETE FROM test.lp1003929; INSERT INTO test.lp1003929 VALUES('a',1,1); DELETE FROM test.lp1003929; INSERT INTO test.lp1003929 VALUES('a',1,2); " 2>&1 done } createdb() { $MYSQL $node_0 -e " DROP TABLE IF EXISTS test.lp1003929;" $MYSQL $node_0 -e ' CREATE TABLE test.lp1003929 ( a varchar(20), i INT, j INT, UNIQUE KEY(a,i) )' } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL $node_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] && echo "enough slaves" echo "Creating database..." createdb echo "Starting inserter..." inserter $node_0 & declare inserter_pid=$! echo "Waiting load to end ($inserter_pid)" wait $MYSQL $node_0 -e 'SHOW PROCESSLIST' echo $MYSQL $node_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 $SCRIPTS/command.sh check if test $? != 0 then echo "Consistency check failed" exit 1 fi echo echo "Done!" echo ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1013978/000077500000000000000000000000001244131713600216775ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1013978/run.sh000077500000000000000000000220271244131713600230450ustar00rootroot00000000000000#!/bin/bash ## # # lp:1013978 # https://bugs.launchpad.net/codership-mysql/+bug/1013978 # # BUG BACKGRPOUND: # # Foreign key constraint on non-unique index in parent table can cause # a crash in slave configured for parallel applying. # Current wsrep patch does not populate any key information for non-unique # keys and dependencies for parent row existence are not respected in PA # control. # # There are five scenarios how foreign key problems can surface: # A. FK has ON UPDATE CASCADE option # 1. Parent table has two rows with same fk key value # 2. One transaction issues update on one parent row, which triggers # corresponding update on depending child table row(s) # 3. Another transaction deletes the other parent table row. # This is now safe because child references have been changed to # point to the first parent row # => These WSs don't have mutual dependency and in slave side it may # happen that DELETE will be processed first, and it will fail for # FK violation # # B. shared reference to non-UK column in parent row with inserts # 1. one transaction does insert on parent table # 2. another transaction does insert on child table referencing the # inserted row # => These WSs don't have mutual dependency and in slave side it may # happen that child INSERT will be processed first, and it will fail for # FK violation # # C. shared reference to non-UK column in parent row with deletes # 1. one transaction deletes a row from child table # 2. another transaction deletes corresponding row in parent table # => These WSs don't have mutual dependency and in slave side it may # happen that parent delete will be processed first, and it will fail for # FK violation # # D. delete with FK on PK # * same as phase C, but with tables where FK constraint is on # primary key column # # E. shared reference to non-UK column in parent row with insert + delete # 1. one transaction first inserts a row in parent table # 2. second transaction inserts referencing row in child table # 3. third transaction deletes the row from child table # 4. fourths transaction deletes the row from parent table # => either insert or delete transactions can get applied in wrong order # in slave due to missing dependency # # If bug is present, slave appliers can easily conflict and cause crash. # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - parent and child tables are creted and populated # - Test phases A, B and C will be run subsequently # # SUCCESS CRITERIA # # If bug is present, slave will crash for FK violation # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1013978" echo "##################################################################" echo "stopping cluster..." stop echo echo "starting node0, node1..." start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} ROUNDS=1000 SUCCESS=0 create_FK_parent_PK() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1013978p ( i int NOT NULL, j int DEFAULT NULL, PRIMARY KEY (i) ) ENGINE=InnoDB ' } create_FK_child_PK() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1013978c ( i int NOT NULL, f int DEFAULT NULL, PRIMARY KEY (i), FOREIGN KEY (i) REFERENCES test.lp1013978p (i) ) ENGINE=InnoDB ' } create_FK_parent_NON_UNIQ() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1013978p ( i int NOT NULL, j int DEFAULT NULL, PRIMARY KEY (i), KEY j (j) ) ENGINE=InnoDB ' } create_FK_child_NON_UNIQ() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1013978c ( i int NOT NULL, f int DEFAULT NULL, PRIMARY KEY (i), KEY fk (f), FOREIGN KEY (f) REFERENCES test.lp1013978p (j) ) ENGINE=InnoDB ' } create_FK_child_NON_UNIQ_ON_UPDATE_CASCADE() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1013978c ( i int NOT NULL, f int DEFAULT NULL, PRIMARY KEY (i), KEY fk (f), FOREIGN KEY (f) REFERENCES test.lp1013978p (j) ON UPDATE CASCADE ) ENGINE=InnoDB ' } create_DB_PK() { create_FK_parent_PK create_FK_child_PK } create_DB_NON_UNIQ() { create_FK_parent_NON_UNIQ create_FK_child_NON_UNIQ } create_DB_NON_UNIQ_ON_UPDATE_CASCADE() { create_FK_parent_NON_UNIQ create_FK_child_NON_UNIQ_ON_UPDATE_CASCADE } # # Test A procedures # A_cleanup() { $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1013978c; " $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1013978p; " } A_createdb() { A_cleanup create_DB_NON_UNIQ_ON_UPDATE_CASCADE $MYSQL --port=$port_0 -e " INSERT INTO test.lp1013978p VALUES (1,1); INSERT INTO test.lp1013978c VALUES (100,1); " } A_inserter() { local port=$1 for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " INSERT INTO test.lp1013978p values (2, $i); UPDATE test.lp1013978p SET j=$(($i + 1)) where i=1; DELETE FROM test.lp1013978p WHERE i=2; " 2>&1 done } # # Test phase B procedures # B_cleanup() { A_cleanup } B_createdb() { B_cleanup create_DB_NON_UNIQ_ON_UPDATE_CASCADE } B_inserter() { local port=$1 for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " INSERT INTO test.lp1013978p values ($i, $i); INSERT INTO test.lp1013978c values ($i, $i); " 2>&1 done } # # Test phase C procedures # C_cleanup() { A_cleanup } C_createdb() { # # we can re-use tables from test phase B # C_cleanup create_DB_NON_UNIQ_ON_UPDATE_CASCADE B_inserter $port_0 } C_deleter() { local port=$1 for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " DELETE FROM test.lp1013978c WHERE i=$i; DELETE FROM test.lp1013978p WHERE i=$i; " 2>&1 done } # # Test phase D procedures, FK by PK # D_cleanup() { A_cleanup } D_createdb() { D_cleanup create_DB_PK # populate by phase B inserts B_inserter $port_0 } D_deleter() { C_deleter $port_0 } # # Test phase E procedures # E_cleanup() { A_cleanup } E_createdb() { E_cleanup create_DB_NON_UNIQ_ON_UPDATE_CASCADE } E_inserter() { local port=$1 for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " INSERT INTO test.lp1013978p values ($i, $i); INSERT INTO test.lp1013978c values ($i, $i); DELETE FROM test.lp1013978c WHERE i=$i; DELETE FROM test.lp1013978p WHERE i=$i; " 2>&1 done } run_test() { phase=$1 create=$2 process=$3 cleanup=$4 echo "##################################################################" echo "## test phase $phase" echo "##################################################################" echo echo "Creating database..." eval $create echo "Starting test process..." eval $process $port_0 & pid=$! echo "Waiting load to end ($pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 #$SCRIPTS/command.sh check echo "consistency checking..." check0=$(check_node 0) check1=$(check_node 1) cs0=$(echo $check0 | cut -d" " -f 11) cs1=$(echo $check1 | cut -d" " -f 11) echo "node 0: $cs0" echo "node 1: $cs1" if test "$cs0" != "$cs1" then echo "Consistency check failed" echo "$check0 $cs0" echo "$check1 $cs1" exit 1 fi if test $? != 0 then echo "Consistency check failed" exit 1 fi eval $cleanup echo echo "looks good so far..." echo } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] && echo "enough slaves" run_test A A_createdb A_inserter A_cleanup run_test B B_createdb B_inserter B_cleanup run_test C C_createdb C_deleter C_cleanup run_test D D_createdb D_deleter D_cleanup run_test E E_createdb E_inserter E_cleanup echo echo "Done!" echo stop_node 0 stop_node 1 exit $SUCCESS percona-galera-3-3.8-3390/tests/regressions/lp1019473/000077500000000000000000000000001244131713600216735ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1019473/run.sh000077500000000000000000000062301244131713600230370ustar00rootroot00000000000000#!/bin/bash -eu ## # # lp:1019473 # https://bugs.launchpad.net/codership-mysql/+bug/1019473 # # BUG BACKGROUND: # # wsrep generates certification keys for tables with no PK nor UK, by # taking a MD5 digest over the whole row. This makes it possible to replicate # and control PA for key-less tables. Unfortunately this implementation # had a bug which caused such row key hashing to be non deterministic, if row # contains certain binary types (blob or text at least are vulnerable) # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - parent and child tables are created and populated # - test load runs one connection, which issues a large detete for child # table and one row delete for parent table. We try to make the applying # of child table delete to last so long that parent table delete gets to # apply in parallel. # # SUCCESS CRITERIA # # If bug is present, slave will crash for not being able to delete a rowk # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1019473" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start "-d --slave_threads 4" declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " ROUNDS=1000 ROWS=5 USERS=3 echo "rounds=$ROUNDS" echo "rows=$ROWS" echo "users=$USERS" insert() { PORT=$1 for r in $(seq 1 $ROUNDS); do for i in $(seq 1 $ROWS); do $MYSQL --port=$PORT -e " DELETE FROM lp1019473 WHERE fid=$i AND uid=$i; INSERT INTO lp1019473 VALUES ($i,$i,'C-$1')" || true done; done } createdb() { $MYSQL -P $port_0 -e "drop table if exists lp1019473;"; $MYSQL -P $port_0 -e "CREATE TABLE lp1019473 ( fid int(10) unsigned DEFAULT 0, uid int(10) unsigned DEFAULT 0, value text, KEY uid (uid), KEY fid (fid) ) ENGINE=InnoDB DEFAULT CHARSET=utf8" } cleandb() { PORT=$1 $MYSQL --port $PORT -e " DROP TABLE IF EXISTS test.lp1019473;" } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] || { echo "NOT ENOUGH SLAVES"; exit 1; } INITIAL_SIZE=`$MYSQL -P $port_0 -e "SHOW STATUS LIKE 'wsrep_cluster_size';" | cut -f 2` echo "Initial cluster size: $INITIAL_SIZE" createdb for u in $(seq 0 $USERS); do insert $port_0 & insert $port_1 & done wait ../../scripts/command.sh check cleandb $port_0 echo echo "Done!" echo ../../scripts/command.sh stop exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1026181/000077500000000000000000000000001244131713600216655ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1026181/run.sh000077500000000000000000000114351244131713600230340ustar00rootroot00000000000000#!/bin/bash -ue ## # # lp:1026181 # https://bugs.launchpad.net/codership-mysql/+bug/1026181 # # BUG BACKGRPOUND: # # RSU method for DDL has been observed to cause intermittent hanging of # the client issueing the DDL. Original problem was that thread running # under TO isolation could not always abort victims. If there was a MDL # conflict with local DML processor it could happen that DDL query just kept # on waiting for the DML to end, and DML was waiting for commit monitor. # # Test scenarios: # A. DDL on same node as DML # # B. DDL on applier node # # # TEST SETUP: # - Cluster will be started # - sqlgen is run against one node in the cluster # - Connection to run the DDL is opened to one of the nodes # # SUCCESS CRITERIA # # If bug is present, DDL execution will hang # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh declare sqlgen=$DIST_BASE/bin/sqlgen echo "##################################################################" echo "## regression test for lp1026181:" echo "##################################################################" echo "stopping cluster..." stop echo echo "starting node0, node1..." start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD test " declare -r host_0=${NODE_INCOMING_HOST[0]} declare -r host_1=${NODE_INCOMING_HOST[1]} declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} MYSQL_0="$MYSQL --host=$host_0 --port=$port_0 -e" MYSQL_1="$MYSQL --host=$host_1 --port=$port_1 -e" $MYSQL_0 "SET GLOBAL wsrep_osu_method=TOI" 2>&1 $MYSQL_1 "SET GLOBAL wsrep_osu_method=TOI" 2>&1 echo -n "Populating test database... " $sqlgen --user=root --password=rootpass --host=$host_0 --port=$port_0 \ --create=1 --tables=4 --rows=20000 --users=1 --duration=0 > /dev/null echo "done" ROUNDS=50 SUCCESS=0 dml() { local host=$1 local port=$2 local users=$3 $sqlgen --user=root --password=rootpass --host=$host --port=$port \ --create=0 --users=$users --duration=600 > /dev/null 2>&1 & echo $! } alter() { local host=$1 local port=$2 local mysql_="$MYSQL --host=$host --port=$port -e" echo "running DDL for $host:$port..." for (( i=1; i<=$ROUNDS; i++ )); do echo "DDL round: $i" $mysql_ 'CREATE INDEX keyx ON test.comm00(x)' 2>&1 || : sleep 0.1 # this reduces the number of desync collisions $mysql_ 'DROP INDEX keyx ON test.comm00' 2>&1 || : sleep 0.1 done echo "... DDL over" } consistency_check() { #$SCRIPTS/command.sh check echo "consistency checking..." check0=$(check_node 0) check1=$(check_node 1) cs0=$(echo $check0 | cut -d" " -f 11) cs1=$(echo $check1 | cut -d" " -f 11) echo "node 0: $cs0" echo "node 1: $cs1" if test "$cs0" != "$cs1" then echo "Consistency check failed" echo "$check0 $cs0" echo "$check1 $cs1" exit 1 fi if test $? != 0 then echo "Consistency check failed" exit 1 fi echo echo "looks good so far..." echo } run_test() { local phase=$1 local dml_host=${NODE_INCOMING_HOST[$2]} local ddl_host=${NODE_INCOMING_HOST[$3]} local dml_port=${NODE_INCOMING_PORT[$2]} local ddl_port=${NODE_INCOMING_PORT[$3]} local users=$4 echo "##################################################################" echo "## test phase $phase" echo "##################################################################" echo echo "Starting sqlgen..." dml_pid=$(dml $dml_host $dml_port $users) sleep 3 $MYSQL --host=$ddl_host --port=$ddl_port -e " SET GLOBAL wsrep_osu_method=RSU " 2>&1 alter $ddl_host $ddl_port & alter_pid=$! echo "Waiting alter load to end (alter: $alter_pid, dml: $dml_pid)" wait $alter_pid echo "stopping dml load ($dml_pid)" kill $dml_pid echo "Waiting remaining load to end..." wait $MYSQL_0 'SHOW PROCESSLIST' && \ echo && \ $MYSQL_1 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 || : # eval $cleanup # what is this supposed to mean? } ######################################################### # # Test begins here # ######################################################### run_test A 0 1 1 run_test B 0 0 1 consistency_check run_test C 0 1 4 run_test D 0 0 4 consistency_check echo echo "Done!" echo # Automatic cleanup at the end of the test - bad parctice: who knows what # you may want to check afterwards? #stop_node 0 #stop_node 1 exit $SUCCESS percona-galera-3-3.8-3390/tests/regressions/lp1055961/000077500000000000000000000000001244131713600216755ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1055961/run.sh000077500000000000000000000106351244131713600230450ustar00rootroot00000000000000#!/bin/bash ## # # lp:lp1055961 # https://bugs.launchpad.net/codership-mysql/+bug/lp1055961 # # BUG BACKGRPOUND: # # autocommit query retrying was effective only for statements which were # really BF aborted. Autocommit statements, which tried to commit but # failed in certification, were never retried, they were immune to # wsrep_retry_autocommit setting. # # # TEST SETUP: # - two nodes to be started, wsrep_retry_autocommit set to 100 # - sqlgen is run against one node in the cluster # - sending autocommit updates on one sqlgen table to the other node # and checking that deadlock error should never come as result # # SUCCESS CRITERIA # # If bug is present, deadlock error will be observed # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh declare sqlgen=$DIST_BASE/bin/sqlgen echo "##################################################################" echo "## regression test for lp1055961:" echo "##################################################################" echo "stopping cluster..." stop echo #echo "starting nodes..." #start echo "starting node0, node1..." start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1)" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} $MYSQL --port=$port_0 -e " SET GLOBAL wsrep_retry_autocommit=100 " 2>&1 ROUNDS=10 SUCCESS=0 sqlgen_load() { local port=$1 echo "running sqlgen..." $sqlgen --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD \ --host=${NODE_INCOMING_HOST[0]} --port=$port \ --create=1 --tables=1 --rows=20 --users=1 --selects=0 --inserts=0 \ --updates=100 --ac-frac=100 --duration=600 > /dev/null } deadlock_test() { local port=$1 echo "running AC updates for $port..." for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " UPDATE test.comm00 SET z=99 WHERE p=0; " 2>&1 ret=$? if [ "$ret" != "0" ]; then echo "DEADLOCK ERROR"; SUCCESS=1; fi done echo "... Deadlock test over" } non_effective_update() { local port=$1 echo "running AC updates for $port..." for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " UPDATE test.comm00 SET z=z WHERE p=0; " 2>&1 ret=$? if [ "$ret" != "0" ]; then echo "DEADLOCK ERROR FOR NON-EFFECTIVE UPDATE"; exit_code=1; fi done echo "... Non effective update test over" } run_test() { echo "##################################################################" echo "## test phase deadlock" echo "##################################################################" echo echo "Starting sqlgen..." sqlgen_load $port_1 & echo "sqlgen $sqlgen_pid" sleep 3 deadlock_test $port_0 echo "##################################################################" echo "## test phase non effective updates" echo "##################################################################" echo non_effective_update $port_0 echo echo "stopping sqlgen load ($sqlgen_pid)" kill $(pidof sqlgen) echo "Waiting remaining load to end..." wait $(pidof sqlgen) $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 #$SCRIPTS/command.sh check echo "consistency checking..." check0=$(check_node 0) check1=$(check_node 1) cs0=$(echo $check0 | cut -d" " -f 11) cs1=$(echo $check1 | cut -d" " -f 11) echo "node 0: $cs0" echo "node 1: $cs1" if test "$cs0" != "$cs1" then echo "Consistency check failed" echo "$check0 $cs0" echo "$check1 $cs1" exit 1 fi if test $? != 0 then echo "Consistency check failed" exit 1 fi eval $cleanup echo echo "looks good so far..." echo } ######################################################### # # Test begins here # ######################################################### run_test echo echo "Done!" echo stop_node 0 stop_node 1 exit $SUCCESS percona-galera-3-3.8-3390/tests/regressions/lp1073220/000077500000000000000000000000001244131713600216615ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1073220/run.sh000077500000000000000000000027601244131713600230310ustar00rootroot00000000000000#!/bin/bash -e # # lp:1073220 # https://bugs.launchpad.net/codership-mysql/+bug/1073220 # # TEST SETUP # # This test starts two nodes and runs mixed DML/DDL load described in # # https://bugs.launchpad.net/codership-mysql/+bug/861212/comments/2 # # for some time. # # PARAMETERS # # Number of test rounds ROUNDS=${ROUNDS:-"100"} # Duration of single iteration DURATION=${DURATION:-"3"} # # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1073220" echo "##################################################################" echo "restarting cluster to clean state" restart echo "starting load for $DURATION" seconds SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} round=0 while test $round -lt $ROUNDS do LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration $DURATION \ --stat-interval 30 --rows 1000 --ac-frac 10 --rollbacks 0.1 \ --alters 1 wait_sync $NODE_LIST echo "checking consistency" check || (sleep 5 && check) round=$(($round + 1)) done echo "stopping cluster" stop percona-galera-3-3.8-3390/tests/regressions/lp1089490/000077500000000000000000000000001244131713600217015ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1089490/run.sh000077500000000000000000000103001244131713600230360ustar00rootroot00000000000000#!/bin/bash ## # # lp:1089490 # https://bugs.launchpad.net/codership-mysql/+bug/1089490 # # BUG BACKGRPOUND: # # Foreign keys can cause slave crash if following conditions are met: # 1. foreign key constraint has been defined with CASCADE ON DELETE option # 2. foreign key constraint has mixed NULL options in referencing columns # (i.e. client column defined with NOT NULL option and parent column # with NULL option) # 3. slave is configured with multiple slave threads (wsrep_slave_threads > 1) # 4. work load has conflicting DELETE operations for parent and child table # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - parent and child tables are created and populated # - test load runs two separate connections, where other session deletes # rows from parent table and other sessions delete rows from child table, # one by one # Due to the cascade on delete, option, the delete from parent table will issue # delete for the child table, and this cascaded delete may conflict with the # direct delete on child table # # SUCCESS CRITERIA # # If bug is present, slave will crash for not being able to delete a row from # child table # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1089490" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start "-d --slave_threads 4" MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} inserter() { local port=$1 for i in {1..1000}; do $MYSQL --port=$port -e " INSERT INTO test.lp1089490_parent(pk, j) VALUES($i, $i); INSERT INTO test.lp1089490_child(i,fk) VALUES ($i, $i); " 2>&1 done } delete_parent() { local port=$1 for i in {1..1000}; do $MYSQL --port=$port -e " DELETE FROM test.lp1089490_parent WHERE pk=$i; " 2>&1 done } delete_child() { local port=$1 for i in {1..1000}; do $MYSQL --port=$port -e " DELETE FROM test.lp1089490_child WHERE i=$i; " 2>&1 done } createdb() { $MYSQL --port=$port_0 -e "reset master;" $MYSQL --port=$port_1 -e "reset master;" $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1089490_child;" $MYSQL --port=$port_0 -e ' DROP TABLE IF EXISTS test.lp1089490_parent;' $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1089490_parent ( pk INT PRIMARY KEY AUTO_INCREMENT, j int )' $MYSQL --port=$port_0 -e " CREATE TABLE test.lp1089490_child ( i INT PRIMARY KEY AUTO_INCREMENT, fk int, CONSTRAINT FOREIGN KEY (fk) REFERENCES test.lp1089490_parent(pk) ON DELETE CASCADE )" } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] || { echo "NOT ENOUGH SLAVES"; exit 1; } echo "Creating database..." createdb for i in {1..200}; do echo echo "### round $i ###" echo "populating database..." inserter $port_0 echo "starting delete for parent table" delete_parent $port_0 & declare parent_pid=$! echo "starting delete for child table" delete_child $port_0 & declare child_pid=$! echo "waiting load to end ($parent_pid $child_pid)" wait done $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 $SCRIPTS/command.sh check echo echo "Done!" echo ../../scripts/command.sh stop exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1100496/000077500000000000000000000000001244131713600216675ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1100496/run.sh000077500000000000000000000106501244131713600230340ustar00rootroot00000000000000#!/bin/bash ## # # lp:1100496 # https://bugs.launchpad.net/codership-mysql/+bug/1100496 # # BUG BACKGROUND: # # Foreign keys can cause slave crash if following conditions are met: # 1. foreign key column in child table and referenced column in parent # table have mixed types of CHAR and VARCHAR # 2. slave uses parallel applying # 3. work load contains concurrent direct deletes on parent table and deletes # on child table # Crash happens because, wsrep appends shared parent key (through FK processing) # and exclusive key (due to direct parent row delete) in different formats. # => certification does not detect the conflict and lets write sets to apply # in parallel. # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - parent and child tables are created and populated # - test load runs one connection, which issues a large detete for child # table and one row delete for parent table. We try to make the applying # of child table delete to last so long that parent table delete gets to # apply in parallel. # # SUCCESS CRITERIA # # If bug is present, slave will crash for not being able to delete a row from # child table # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1100496" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start "-d --slave_threads 4" declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST --port=$port_0 test " populate() { local rows=$1 $MYSQL -e "INSERT INTO test.lp1100496_parent(pk) VALUES('Parent');" for ((i=1; i<$rows; i++)); do $MYSQL -e "$I1K" 2>&1 done } run_deletes() { $MYSQL -e "DELETE FROM test.lp1100496_child; DELETE FROM test.lp1100496_parent;" } check_cluster() { local original_size=$1 size=`$MYSQL -e "SHOW STATUS LIKE 'wsrep_cluster_size';" | cut -f 2` if [ "$size" != "$original_size" ]; then echo "cluster broken; $size $original_size" exit 1 fi } cleandb() { $MYSQL --port=$port_0 -e "reset master;" $MYSQL --port=$port_1 -e "reset master;" $MYSQL -e " DROP TABLE IF EXISTS test.lp1100496_child;" $MYSQL -e ' DROP TABLE IF EXISTS test.lp1100496_parent;' } createdb() { local charset=$1 cleandb $MYSQL --port=$port_0 -e " CREATE TABLE test.lp1100496_parent ( pk VARCHAR(30) PRIMARY KEY ) CHARACTER SET = $charset ENGINE=innodb" $MYSQL --port=$port_0 -e " CREATE TABLE test.lp1100496_child ( i INT PRIMARY KEY AUTO_INCREMENT, fk CHAR(20), CONSTRAINT FOREIGN KEY (fk) REFERENCES test.lp1100496_parent(pk) ) CHARACTER SET = $charset, ENGINE=innodb" } run_test() { local charset=$1 echo echo "## Testing character set: $charset" echo createdb $charset for i in 10 20 30 40 50 60; do echo echo "populating database, ${i}K rows..." populate $i echo "testing..." run_deletes check_cluster $INITIAL_SIZE done echo echo "## Consistency checks" echo $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 wait_sync $NODE_LIST $SCRIPTS/command.sh check } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] || { echo "NOT ENOUGH SLAVES"; exit 1; } INITIAL_SIZE=`$MYSQL -e "SHOW STATUS LIKE 'wsrep_cluster_size';" | cut -f 2` echo "Initial cluster size: $INITIAL_SIZE" I1K="INSERT INTO test.lp1100496_child(fk) VALUES ('Parent')" for ((i=1; i<1000; i++)); do I1K="$I1K,('Parent')" done run_test latin1 run_test utf8 echo echo "Done!" echo ../../scripts/command.sh stop exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1130888/000077500000000000000000000000001244131713600216775ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1130888/run.sh000077500000000000000000000101131244131713600230360ustar00rootroot00000000000000#!/bin/bash ## # # lp:1130888 # https://bugs.launchpad.net/codership-mysql/+bug/1130888 # # BUG BACKGROUND: # # wsrep appends shared key for FK parent references, when child table # is beign modified. This FK parent reference requires a read in parent table, # and essentially new shared lock on paretn table row. Now this extra lock can # enter in deadlock, and bad news is that existing code is note prepared to see # deadlocks at this point. This unresolved deadlock left the server in hanging # state. # # TEST SETUP: # - Two nodes are used in multi-master mode # - child/parent tables are created with cascading delete option # - node1 will get transactions modifying parent table # - node2 will get transactions modifying child table # # SUCCESS CRITERIA # # If bug is present, one node will hang # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1130888" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start "-d --slave_threads 4" declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " ROUNDS=1000 ROWS=5 echo "rounds=$ROUNDS" echo "rows=$ROWS" insert() { k PORT=$1 for j in $(seq 1 $ROWS); do $MYSQL --port=$PORT -e "INSERT INTO TRANSACTION(ID) VALUES ('$j')"; $MYSQL --port=$PORT -e "INSERT INTO TRANSACTIONLOG(IDTRANSACTION,IDMESSAGE) VALUES ('$j','$j')"; done } trxlog() { PORT=$1 for i in $(seq 1 $ROUNDS); do for j in $(seq 1 $ROWS); do $MYSQL --port=$PORT -e "DELETE FROM TRANSACTIONLOG WHERE IDTRANSACTION = '$j'; INSERT INTO TRANSACTIONLOG(IDTRANSACTION,IDMESSAGE) VALUES ('$j','$j')"; done done } trx() { PORT=$1 for i in $(seq 1 $ROUNDS); do for j in $(seq 1 $ROWS); do $MYSQL --port=$PORT -e "DELETE FROM TRANSACTION WHERE ID = '$j'; INSERT INTO TRANSACTION(ID) VALUES ('$j'); INSERT INTO TRANSACTIONLOG(IDTRANSACTION,IDMESSAGE) VALUES ('$j','$j')"; done done } createdb() { PORT=$1 $MYSQL --port=$PORT -e "CREATE TABLE IF NOT EXISTS TRANSACTION ( ID varchar(25) NOT NULL, MARCA datetime DEFAULT NULL, TIMEOUT int(11) DEFAULT NULL, DESCRIPCION varchar(255) DEFAULT NULL, PRIMARY KEY (ID) ) ENGINE=InnoDB DEFAULT CHARSET=latin1"; $MYSQL --port=$PORT -e "CREATE TABLE IF NOT EXISTS TRANSACTIONLOG ( IDTRANSACTION varchar(25) NOT NULL, IDMESSAGE varchar(25) NOT NULL, TIPO int(11) DEFAULT NULL, FECHA datetime DEFAULT NULL, PRIMARY KEY (IDTRANSACTION,IDMESSAGE), UNIQUE KEY IX_EBITRANSACTIONLOG (IDMESSAGE), CONSTRAINT FK_EBITRANSACTIONLOG_EBITRAN FOREIGN KEY (IDTRANSACTION) REFERENCES TRANSACTION (ID) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1"; $MYSQL --port=$PORT -e "TRUNCATE TRANSACTIONLOG"; $MYSQL --port=$PORT -e "TRUNCATE TRANSACTION"; } cleandb() { PORT=$1 $MYSQL --port=$PORT -e " DROP TABLE IF EXISTS test.TRANSACTION; DROP TABLE IF EXISTS test.TRANSACTIONLOG" } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] || { echo "NOT ENOUGH SLAVES"; exit 1; } INITIAL_SIZE=`$MYSQL -P $port_0 -e "SHOW STATUS LIKE 'wsrep_cluster_size';" | cut -f 2` echo "Initial cluster size: $INITIAL_SIZE" createdb insert $port_0 trxlog $port_0 & trx $port_1 & wait ../../scripts/command.sh check cleandb $port_0 echo echo "Done!" echo ../../scripts/command.sh stop exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1179361/000077500000000000000000000000001244131713600216765ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1179361/run.sh000077500000000000000000000063611244131713600230470ustar00rootroot00000000000000#!/bin/bash -ue ## # # lp:1179361 # https://bugs.launchpad.net/codership-mysql/+bug/ 1179361 # # BUG BACKGROUND: # # # TEST SETUP: # - N nodes are used in master-slave mode # - master gets INSERTs and DELETEs from two concurrent threads # # SUCCESS CRITERIA # # In case of success all nodes should stay alive # # If bug is present, one node will hang # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1179361" echo "##################################################################" echo "Restarting cluster" ../../scripts/command.sh restart "--slave_threads 16" MYSQL="mysql --batch --skip-column-names --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD" MYSQL0="$MYSQL --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]}" TABLE="test.lp1179361" cat << EOF | $MYSQL0 DROP TABLE IF EXISTS $TABLE; CREATE TABLE $TABLE ( obj_type varchar(16) NOT NULL DEFAULT '' COMMENT 'obj_type', obj_id varchar(20) NOT NULL COMMENT 'obj_type編號', tag varchar(255) NOT NULL, msno bigint(20) NOT NULL DEFAULT '0' COMMENT 'user id', terr_id int(11) NOT NULL COMMENT '地å€ç·¨è™Ÿ', PRIMARY KEY (obj_type,obj_id,msno,tag), KEY obj_id (obj_id), KEY tag (tag), KEY msno (msno) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED; EOF ROUNDS=100000 echo "Rounds: $ROUNDS" # Checking that all nodes are alive check_nodes() { for N in $NODE_LIST do MYSQLN="$MYSQL --host=${NODE_INCOMING_HOST[$N]} --port=${NODE_INCOMING_PORT[$N]}" if ! $MYSQLN -e 'SELECT COUNT(*) FROM '$TABLE > /dev/null then echo "Node $N is dead, test failed" >&2 return 1 fi done } thread_insert() { local obj_type=0 local tag="'中文測試'" local terr_id=0 for i in $(seq 1 $ROUNDS) do local obj_id=$(( $RANDOM % 100 + 1 )) local msno=$(( $RANDOM % 100 + 1 )) echo "INSERT INTO $TABLE (obj_type, obj_id, tag, msno, terr_id)" \ "VALUES ($obj_type, $obj_id, $tag, $msno, $terr_id)" \ "ON DUPLICATE KEY UPDATE obj_type = obj_type;" if [ $(( $i % 1000 )) -eq 0 ] then echo "Insert thread: inserted $i" >&2 check_nodes || return 1 fi done } thread_delete() { for i in $(seq 1 $ROUNDS) do local count=`$MYSQL0 -e 'SELECT COUNT(*) FROM '$TABLE` if [ $count -gt 2000 ] then local limit=$(( $count / 2 )) $MYSQL0 -e \ "DELETE FROM $TABLE ORDER BY obj_type, obj_id, tag, msno LIMIT $limit;" echo "Delete thread: deleted $limit" >&2 fi sleep 0.5 done } thread_delete & delete_pid=$! trap "kill $delete_pid >/dev/null 2>&1 || true" TERM EXIT thread_insert | $MYSQL0 FAILED=${PIPESTATUS[0]} echo "Terminating delete thread..." kill $delete_pid && wait %% > /dev/null 2>&1 || : [ $FAILED -eq 0 ] && check_nodes || exit 1 check || (sleep 2; check) || (sleep 3; check) || exit 1 exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1184034/000077500000000000000000000000001244131713600216675ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1184034/run.sh000077500000000000000000000014161244131713600230340ustar00rootroot00000000000000#!/bin/bash -ue # # https://bugs.launchpad.net/galera/+bug/1184034 # # BUG BACKGROUND # # Running # # nmap -sT -p # # causes uncaught exception in gcomm asio code # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1184034" echo "##################################################################" echo "Restarting cluster" ../../scripts/command.sh restart for ii in `seq 1 100` do nmap -sT -p ${NODE_GCS_PORT[0]} ${NODE_GCS_HOST[0]} done check_node 0 percona-galera-3-3.8-3390/tests/regressions/lp1206129/000077500000000000000000000000001244131713600216675ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1206129/run.sh000077500000000000000000000036751244131713600230450ustar00rootroot00000000000000#!/bin/bash -e # # lp:1206129 # # Verify that LOAD DATA INFILE is executed and data is replicated # over cluster. # # This test assumes that if the LOAD DATA would be processed by single # 500k row commit, it would take several seconds process that on slaves. # On the other hand it is assumed that if LOAD DATA splitting works as # expected, Galera flow control limits master load rate and final 10k # batches are committed nearly synchronously. # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1089490" echo "##################################################################" echo "restarting cluster" ../../scripts/command.sh restart MYSQL="mysql --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]} -Dtest" rm -f /tmp/lp1206129.dat $MYSQL -e "DROP TABLE IF EXISTS lp1206129; DROP PROCEDURE IF EXISTS populate; CREATE TABLE lp1206129 (a INT PRIMARY KEY); DELIMITER ;; CREATE PROCEDURE populate() BEGIN DECLARE i INT DEFAULT 0; WHILE i < 500000 DO INSERT INTO lp1206129 VALUES (i); SET i = i + 1; END WHILE; END;; DELIMITER ; BEGIN; CALL populate(); SELECT * FROM lp1206129 INTO OUTFILE '/tmp/lp1206129.dat'; COMMIT; SELECT SLEEP(0); TRUNCATE lp1206129; SELECT SLEEP(0); LOAD DATA INFILE '/tmp/lp1206129.dat' INTO TABLE lp1206129;" rm /tmp/lp1206129.dat sleep 2 ../../scripts/command.sh check $MYSQL -e "DROP TABLE lp1206129; DROP PROCEDURE populate;"percona-galera-3-3.8-3390/tests/regressions/lp1208493/000077500000000000000000000000001244131713600216755ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1208493/run.sh000077500000000000000000000065431244131713600230500ustar00rootroot00000000000000#!/bin/bash ## # # lp:1208493 # https://bugs.launchpad.net/codership-mysql/+bug/1208493 # # BUG BACKGRPOUND: # # When wsrep_provider or wsrep_cluster_address is changed, wsrep will # close all client connections to mysqld. # During the client connection closing phase, wsrep used to hold a # lock on global variable access. Now, some of the closing connections # may be accessing global variables, and refuse to die if cannot grab the # variable protecting lock. # The fix for this issue, will release global variable lock for the duration # of conneciton closing, and all client connections should be able to close # gracefully # # If bug is present, mysqld will hang after wsrep_provider or # wsrep_cluster_address change # # TEST SETUP: # - Two nodes are started # - Client test load is started just to constantly change a global variable # - One node is dropped and joined by changing wsrep_provider # and wsrep_cluster_address # # SUCCESS CRITERIA # # If bug is present, the test will hang # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1208493" echo "##################################################################" echo "stopping cluster" $SCRIPTS/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 declare -r port_0=$(( DBMS_PORT )) declare -r port_1=$(( DBMS_PORT + 1)) declare -r node_0="-h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]}" declare -r node_1="-h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]}" SET_ROUNDS=20000 DROP_ROUNDS=30 MYSQL="mysql --batch --silent $node_0 --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD -Dtest " read_param() { var=$1 local varname="$2" value=`$MYSQL -e"SHOW VARIABLES LIKE '$varname'" | awk '{ print $2 }'` eval "$1=$value" # return $value } set_vars() { trap "echo trap" SIGHUP for (( i=1; i<$SET_ROUNDS; i++ )) do $MYSQL -e "set global thread_cache_size=11; set global thread_cache_size=10"; [ "$?" != "0" ] && echo "SET query failed" done echo "Setters done" } dropper() { for (( i=1; i<$DROP_ROUNDS; i++ )) do $MYSQL -e "set global wsrep_provider=none;"; $MYSQL -w -e "set global wsrep_provider='$provider'"; $MYSQL -e "set global wsrep_cluster_address='$address'"; done } ######################################################### # # Test begins here # ######################################################### #[ "$threads" = "wsrep_slave_threads 4" ] && echo "enough slaves" read_param provider wsrep_provider echo "wsrep_provider = $provider" read_param address wsrep_cluster_address echo "wsrep_cluster_address = $address" echo "starting variable setters..." set_vars& declare setter_pid=$! echo "dropping and joining node..." dropper echo "Dropper Done" echo "Waiting load to end ($setter_pid)" wait $MYSQL -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 check echo echo "Done!" echo ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit 0 percona-galera-3-3.8-3390/tests/regressions/lp1255964/000077500000000000000000000000001244131713600217025ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1255964/run.sh000077500000000000000000000034151244131713600230500ustar00rootroot00000000000000#!/bin/bash -eu # This test measures master replication overhead by running a number of # autocommit queries with wsrep_on set to 0 and 1. # # NOTES: # - The load was deliberately chosen to produce maximum replication overhead. # - SQL commands are first dumped into a text file in order to minimize client # overhead when benchmarking. declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh declare -r TABLE_NAME="memory" declare -r TABLE="$DBMS_TEST_SCHEMA.$TABLE_NAME" declare -r TABLE_DEFINITION="(c1 INT AUTO_INCREMENT PRIMARY KEY, c2 CHAR(255))" MYSQL="mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD" MYSQL="$MYSQL -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} -B" prepare() { stop start_node -g gcomm:// --mysql-opt --wsrep-new-cluster 0 echo -n "Preparing... " $MYSQL -e "DROP TABLE IF EXISTS $TABLE; CREATE TABLE $TABLE $TABLE_DEFINITION; INSERT INTO $TABLE(c2) VALUES('abc');" # make sure the latest writeset protocol is used $MYSQL -e "SET GLOBAL wsrep_provider_options='repl.proto_max=10'" echo "done" } # load() will progressively generate larger and larger writesets in geometric # progression, by inserting table onto itself. At some point it will have to # spill to disk and trigger the bug. load() { echo -e "Rows\tSeconds\tRSS" for rows in $(seq 0 20) do echo -en "$(( 1 << $rows ))\t" begin=$SECONDS $MYSQL -e "INSERT INTO $TABLE(c2) SELECT c2 FROM $TABLE;" seconds=$(( $SECONDS - $begin )) echo -en "$seconds\t"; ps --no-headers -C mysqld -o rss || ps --no-headers -C mysqld-debug -o rss done } prepare load 1 percona-galera-3-3.8-3390/tests/regressions/lp1274199/000077500000000000000000000000001244131713600217035ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1274199/run.sh000077500000000000000000000022511244131713600230460ustar00rootroot00000000000000#!/bin/bash -eu # # This sript starts cluster, disables flow control on node 1, locks node1 for # a certain duration while loading node 0, and then waits for node1 to catch up # # Triggering the bug requires sufficinetly long SLEEP_DURATION or suffcinetly # small cache settings in order to trigger ring buffer overflow. # # For 10 duration gcache.size=1M;gcache.page_size=1M would wor best # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r NODE0="--host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]}" declare -r NODE1="--host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]}" declare -r MYSQL1="mysql -uroot -prootpass $NODE1" declare -r SCRIPTS="$DIST_BASE/scripts" SLEEP_DURATION=10 $SCRIPTS/command.sh restart $MYSQL1 -e "set global wsrep_desync=1" for ii in `seq 1 4` do $MYSQL1 -e "FLUSH TABLES WITH READ LOCK; SELECT SLEEP($SLEEP_DURATION)" & $TEST_BASE/bin/sqlgen $NODE0 --users 16 --duration $SLEEP_DURATION echo "`date` waiting sync" $SCRIPTS/command.sh wait_sync $NODE_LIST echo "`date` round $ii finished" done $MYSQL1 -e "set global wsrep_desync=0" percona-galera-3-3.8-3390/tests/regressions/lp1284803/000077500000000000000000000000001244131713600216745ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1284803/run.sh000077500000000000000000000046321244131713600230440ustar00rootroot00000000000000#!/bin/bash -eu # # https://bugs.launchpad.net/galera/+bug/1284803 # # BUG BACKGROUND: # ============== # # Big writesets in IST stream caused replicator to launch background # threads for write set checksumming. One responsibility of this thread # is also to assign certain write set data structures. In IST codepath # there was no synchronization point for this thread before write set # was applied so sometimes uninitialized write sets caused skip in # applying and the assertion mentioned in bug report. # test -n "${DEBUG:-}" && set -x declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1284803" echo "##################################################################" MYSQL="mysql --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]} -Dtest" MYSQL_SLAVE="mysql --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=${NODE_INCOMING_HOST[1]} --port=${NODE_INCOMING_PORT[1]} -Dtest" function ins { while true do for ii in {1..100} do # Insert long string of chars to generate big write set $MYSQL -e "INSERT INTO lp1284803 VALUES ($ii, REPEAT('a', 1115693))" || : done $MYSQL -e "TRUNCATE TABLE lp1284803" done } # Restart nodes to bring nodes into sync echo echo "restarting cluster" echo restart stop_node 2 node_list="0 1" echo echo "initializing table" echo # Create test table to store long string of chars $MYSQL -e "DROP TABLE IF EXISTS lp1284803; CREATE TABLE lp1284803 (a INT PRIMARY KEY, b MEDIUMTEXT)" ins & inspid=$! trap "{ kill $inspid || : ; }" EXIT for ii in {1..10} do echo "-- Stopping node" # Stop node 1 stop_node 1 SLEEPTIME=1 echo "-- Pausing for $SLEEPTIME secs" sleep $SLEEPTIME # Pause load for IST kill -STOP $inspid echo "-- Starting node" # Start node 1 which will attempt IST start_node "-g $(gcs_address 1)" 1 echo "-- Waiting sync" # Stop load and wait nodes to sync wait_sync $node_list kill -CONT $inspid done kill $inspid || : $MYSQL -e "DROP TABLE IF EXISTS lp1284803" # Success exit 0percona-galera-3-3.8-3390/tests/regressions/lp1299116/000077500000000000000000000000001244131713600216775ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1299116/run.sh000077500000000000000000000046501244131713600230470ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" NODE0="--host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]}" NODE1="--host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]}" MYSQL="mysql -utest -ptestpass -hgw -Dtest" MYSQL0="$MYSQL $NODE0" MYSQL1="$MYSQL $NODE1" $SCRIPTS/command.sh restart test_1() { echo echo "Test 1 starting..."; echo $MYSQL0 -e "drop table if exists uniq;" $MYSQL0 -e "create table uniq (u varchar(10), unique key unique_key(u));" for i in $(seq 1 10) do $MYSQL0 -e "insert into uniq (u) values ('const');" & $MYSQL1 -e "insert into uniq (u) values ('const');" & wait done echo echo "Test 1 done" echo "****************************************************" } test_2_load() { local node="${@:1}" echo "load 2 for $node starting..."; for i in {1..10000}; do $MYSQL $node -e"insert into uniq(u) values('keys'); delete from uniq;"; done } test_2() { $MYSQL0 -e "drop table if exists uniq;" $MYSQL0 -e "create table uniq ( u varchar(10), i int auto_increment, key(i), unique key unique_key(u));" test_2_load "$NODE0" & test_2_load "$NODE1" & echo "test 2 loads started" wait echo echo "Test 2 done" echo "****************************************************" } test_3_load() { echo "test load 3"; for i in $(seq 1 1000) do #echo "round: $i" $MYSQL0 -e "insert into uniq (u) values ('const');" & $MYSQL1 -e "insert into uniq (u) values ('const');" & wait val0=$($MYSQL0 -N -s -e "select count(*) from uniq;") val1=$($MYSQL1 -N -s -e "select count(*) from uniq;") #sleep 1 [ "$val0" != "1" ] && echo "0 $val0 $val1" && exit [ "$val1" != "1" ] && echo "1 $val0 $val1" && exit # echo "truncing" $MYSQL0 -e "truncate uniq;" done } test_3() { echo echo "Test 3 starting..."; echo $MYSQL0 -e "drop table if exists uniq;" $MYSQL0 -e "create table uniq (u varchar(10), unique key unique_key(u));" test_3_load echo echo "Test 3 done" echo "****************************************************" } test_1 test_2 test_3 $SCRIPTS/command.sh wait_sync 0 1 $SCRIPTS/command.sh check | wc -l $SCRIPTS/command.sh stop percona-galera-3-3.8-3390/tests/regressions/lp1314854/000077500000000000000000000000001244131713600216745ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp1314854/run.sh000077500000000000000000000123041244131713600230370ustar00rootroot00000000000000#!/bin/bash ## # # lp:1314854 # https://bugs.launchpad.net/codership-mysql/+bug/1314854 # # BUG BACKGRPOUND: # # Keys for varchar columns using multi-byte caharacter codes were truncated # in the write set, and this caused excessive certification failures. # # If bug is present, slave will crash for FK violation # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1314854" echo "##################################################################" echo "stopping cluster..." stop echo echo "starting node0, node1..." start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} ROUNDS=10000 SUCCESS=0 create_FK_parent_PK() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1314854p ( k varchar(10) NOT NULL, j int NOT NULL, PRIMARY KEY (k,j) ) ENGINE=InnoDB character set = utf8 ' } create_FK_child_PK() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1314854c ( i int NOT NULL, k varchar(10), j int DEFAULT NULL, PRIMARY KEY (i), FOREIGN KEY (k,j) REFERENCES test.lp1314854p (k,j) ) ENGINE=InnoDB character set = utf8 ' } create_utf8_table() { $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp1314854 ( k varchar(30) NOT NULL, f int DEFAULT NULL, PRIMARY KEY (k), KEY fk (f) ) ENGINE=InnoDB character set = utf8 ' } # # Test A procedures # A_cleanup() { $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1314854c; " $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1314854p; " } A_createdb() { create_FK_parent_PK create_FK_child_PK } A_init() { A_cleanup A_createdb } A_inserter() { local port=$1 $MYSQL --port=$port -e " INSERT INTO test.lp1314854p values ('A«B', 1); INSERT INTO test.lp1314854c values (1, 'A«B', 1); " 2>&1 } A_test() { echo "A test good" } # # Test phase B procedures # B_cleanup() { $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp1314854; " } B_createdb() { create_utf8_table } B_init() { B_cleanup B_createdb } B_inserter() { local port=$1 local prefix=$2 for (( i=1; i<=$ROUNDS; i++ )); do $MYSQL --port=$port -e " INSERT INTO test.lp1314854 values ('${prefix}$i', $i) " 2>&1 done } B_test() { local port=$1 rows=`$MYSQL --port=$port -e " SELECT COUNT(*) FROM test.lp1314854; "` if [ "$rows" != "$(( $ROUNDS * 2 ))" ]; then echo "B failure"; exit 1; fi echo "B rows = $rows" } wait_for_load() { local pid=$1 echo "Waiting load to end ($pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 #$SCRIPTS/command.sh check echo "consistency checking..." check0=$(check_node 0) check1=$(check_node 1) cs0=$(echo $check0 | cut -d" " -f 11) cs1=$(echo $check1 | cut -d" " -f 11) echo "node 0: $cs0" echo "node 1: $cs1" if test "$cs0" != "$cs1" then echo "Consistency check failed" echo "$check0 $cs0" echo "$check1 $cs1" exit 1 fi if test $? != 0 then echo "Consistency check failed" exit 1 fi } run_test() { echo "##################################################################" echo "## test phase A - FK constraint" echo "##################################################################" echo echo "Creating database..." A_init echo "Starting test process..." A_inserter $port_0 & pid=$! wait_for_load $pid A_cleanup echo echo "looks good so far..." echo echo "##################################################################" echo "## test phase B - concurrent varchar key inserts" echo "##################################################################" echo echo "Creating database..." B_init echo "Starting test process..." B_inserter $port_0 "AA" & pid1=$! B_inserter $port_1 "BB" & pid2=$! wait_for_load $pid1 B_test $port_0 B_test $port_1 B_cleanup echo echo "looks good so far..." echo } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] && echo "enough slaves" run_test echo echo "Done!" echo stop_node 0 stop_node 1 exit $SUCCESS percona-galera-3-3.8-3390/tests/regressions/lp518749/000077500000000000000000000000001244131713600216245ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp518749/mysqlfs.sql000066400000000000000000000062361244131713600240520ustar00rootroot00000000000000-- MySQL dump 10.11 -- -- Host: vs1 Database: -- ------------------------------------------------------ -- Server version 5.1.42-debug /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Current Database: `mysqlfs` -- DROP DATABASE IF EXISTS mysqlfs; CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqlfs` /*!40100 DEFAULT CHARACTER SET latin1 */; USE `mysqlfs`; -- -- Table structure for table `data_blocks` -- SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `data_blocks` ( `inode` bigint(20) NOT NULL, `seq` int(10) unsigned NOT NULL, `data` blob, PRIMARY KEY (`inode`,`seq`) ) ENGINE=InnoDB; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `data_blocks` -- INSERT INTO `data_blocks` VALUES (3,0,'1\n2\n3\n4\n'); -- -- Table structure for table `inodes` -- SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `inodes` ( `inode` bigint(20) NOT NULL, `inuse` int(11) NOT NULL DEFAULT '0', `deleted` tinyint(4) NOT NULL DEFAULT '0', `mode` int(11) NOT NULL DEFAULT '0', `uid` int(10) unsigned NOT NULL DEFAULT '0', `gid` int(10) unsigned NOT NULL DEFAULT '0', `atime` int(10) unsigned NOT NULL DEFAULT '0', `mtime` int(10) unsigned NOT NULL DEFAULT '0', `ctime` int(10) unsigned NOT NULL DEFAULT '0', `size` bigint(20) NOT NULL DEFAULT '0', PRIMARY KEY (`inode`), KEY `inode` (`inode`,`inuse`,`deleted`) ) ENGINE=InnoDB; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `inodes` -- INSERT INTO `inodes` VALUES (1,0,0,16877,0,0,1265561793,1265561793,1265561793,0); INSERT INTO `inodes` VALUES (3,0,0,33188,1000,1000,1265561852,1265561852,1265561852,8); /*!50003 SET @SAVE_SQL_MODE=@@SQL_MODE*/; DELIMITER ;; /*!50003 SET SESSION SQL_MODE="" */;; /*!50003 CREATE */ /*!50017 DEFINER=`root`@`localhost` */ /*!50003 TRIGGER `drop_data` AFTER DELETE ON `inodes` FOR EACH ROW BEGIN DELETE FROM data_blocks WHERE inode=OLD.inode; END */;; DELIMITER ; /*!50003 SET SESSION SQL_MODE=@SAVE_SQL_MODE*/; -- -- Table structure for table `tree` -- SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; CREATE TABLE `tree` ( `inode` int(10) unsigned NOT NULL, `parent` int(10) unsigned DEFAULT NULL, `name` varchar(255) NOT NULL, UNIQUE KEY `name` (`name`,`parent`), KEY `inode` (`inode`), KEY `parent` (`parent`) ) ENGINE=InnoDB; SET character_set_client = @saved_cs_client; -- -- Dumping data for table `tree` -- INSERT INTO `tree` VALUES (1,NULL,'/'); INSERT INTO `tree` VALUES (3,1,'foo'); UPDATE inodes SET inuse = inuse + 1 WHERE inode=3; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; percona-galera-3-3.8-3390/tests/regressions/lp518749/run.sh000077500000000000000000000013611244131713600227700ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "regression test for lp:518749" echo "restarting cluster" $SCRIPTS/command.sh restart mysql --user=$DBMS_ROOT_USER --password=$DBMS_ROOT_PSWD --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]} < mysqlfs.sql; check; ret=$?; if test $ret != 0 then echo "checksum failed"; exit 1; fi # Cleanup mysql --user=$DBMS_ROOT_USER --password=$DBMS_ROOT_PSWD --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]} -e "DROP DATABASE mysqlfs"; $SCRIPTS/command.sh stoppercona-galera-3-3.8-3390/tests/regressions/lp587170/000077500000000000000000000000001244131713600216165ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp587170/run.sh000077500000000000000000000020241244131713600227570ustar00rootroot00000000000000#!/bin/bash -e # # lp:587170 # # Verify that ALTER TABLE ... AUTO_INCREMENT produces consistent results. # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:1089490" echo "##################################################################" echo "restarting cluster" ../../scripts/command.sh restart MYSQL="mysql --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=${NODE_INCOMING_HOST[0]} --port=${NODE_INCOMING_PORT[0]} -Dtest" $MYSQL -e "DROP TABLE IF EXISTS lp587170; CREATE TABLE lp587170 (i INT); INSERT INTO lp587170 VALUES (1),(2),(3),(4),(5); ALTER TABLE lp587170 ADD id INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;" ../../scripts/command.sh check $MYSQL -e "DROP TABLE lp587170" percona-galera-3-3.8-3390/tests/regressions/lp847353/000077500000000000000000000000001244131713600216205ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp847353/run.sh000077500000000000000000000055451244131713600227740ustar00rootroot00000000000000#!/bin/bash # lp:847353 # https://bugs.launchpad.net/codership-mysql/+bug/847353 # # BUG BACKGRPOUND: # # FTWRL needs to pause replicator from committing. FTWRL will take global read # lock and this can cause a deadlock between applying trasnactions and FTWRL # execution. When FTWRL has called wsrep->pause(), all earlier applying tasks # must be able to complete. # # TEST SETUP: # # This test starts two nodes to play with. # It uses sqlgen to run load against both nodes and one process running # FTWRL agains one node only. # # TEST PROCESSES: # # Test creates two sqlgen processes # sqlgen: regular sqlgen load. First sqlgen process will create # the tables, latyter one just sends DML load in. # FTWRL: FTWRL keeps on sending FLUSTE TABLES WITH READ LOCK # statements agains other cluster node # # SUCCESS CRITERIA # # If bug is present, either one node may hang # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:847353" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1)" 1 # Start load SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host ${NODE_INCOMING_HOST[0]} \ --port ${NODE_INCOMING_PORT[0]} --users 1 --duration 300 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 \ >/dev/null 2>$BASE_RUN/lp.err & declare -r sqlgen1_pid=$! sleep 0.2 # this connects strictly to one node so no libglb preloading $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host ${NODE_INCOMING_HOST[1]} \ --port ${NODE_INCOMING_PORT[1]} --users 1 --duration 300 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --create 0 \ >/dev/null 2>$BASE_RUN/lp.err & declare -r sqlgen2_pid=$! for i in {1..150}; do mysql --show-warnings --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=${NODE_INCOMING_HOST[1]} --port=${NODE_INCOMING_PORT[1]} test -e 'FLUSH TABLES WITH READ LOCK'; sleep 0.5; done echo "waiting sqlgens ($sqlgen1_pid $sqlgen2_pid) to complete" wait echo "waiting for nodes to process all transactions" ../../scripts/command.sh wait_sync 0 1 echo "Done!" ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit percona-galera-3-3.8-3390/tests/regressions/lp861212/000077500000000000000000000000001244131713600216065ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp861212/run.sh000077500000000000000000000025131244131713600227520ustar00rootroot00000000000000#!/bin/bash -e # # lp:861212 # https://bugs.launchpad.net/codership-mysql/+bug/861212 # # TEST SETUP # # This test starts two nodes and runs mixed DML/DDL load described in # # https://bugs.launchpad.net/codership-mysql/+bug/861212/comments/2 # # for some time. # # PARAMETERS # # Duration of test run DURATION=${DURATION:-"300"} # # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:861212" echo "##################################################################" echo "restarting cluster to clean state" restart echo "starting load for $DURATION" seconds SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration $DURATION \ --stat-interval 30 --rows 1000 --ac-frac 10 --rollbacks 0.1 \ --alters 0.001 wait_sync $NODE_LIST echo "checking consistency" check || (sleep 5 && check) echo "stopping cluster" stop percona-galera-3-3.8-3390/tests/regressions/lp900816/000077500000000000000000000000001244131713600216125ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp900816/run.sh000077500000000000000000000021611244131713600227550ustar00rootroot00000000000000#!/bin/bash -ue declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:900816" echo "##################################################################" echo "restarting cluster" $SCRIPTS/command.sh restart PORT=${NODE_INCOMING_PORT[0]} HOST=${NODE_INCOMING_HOST[0]} USER=$DBMS_TEST_USER PSWD=$DBMS_TEST_PSWD DB=test TABLE=nopk TRIES=1000 MYSQL="mysql -u$USER -p$PSWD -h$HOST -P$PORT $DB" CREATE=" DROP TABLE IF EXISTS $DB.$TABLE; CREATE TABLE $DB.$TABLE (i INT, j INT);" INSERT="INSERT INTO $DB.$TABLE VALUES (1, 0),(2,0);" UPDATE="UPDATE $DB.$TABLE SET j=j+1;" DELETE="DELETE FROM $DB.$TABLE;" echo $CREATE | $MYSQL for i in $(seq 1 $TRIES) do echo $INSERT | $MYSQL echo $UPDATE | $MYSQL >> update.log 2>&1 & echo $DELETE | $MYSQL done echo "$i tries passed" $SCRIPTS/command.sh check $SCRIPTS/command.sh stoppercona-galera-3-3.8-3390/tests/regressions/lp909155/000077500000000000000000000000001244131713600216175ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp909155/run.sh000077500000000000000000000102431244131713600227620ustar00rootroot00000000000000#!/bin/bash ## # # lp:909155 # https://bugs.launchpad.net/codership-mysql/+bug/909155 # # BUG BACKGRPOUND: # # under certain situations, DROP TABLE processing may be postponed to happen # in background thread. This can be fatal for galera processing, as DROP # needs to be processed under total order isolation and has strict requirements # for when the processing begins and ends. # # TEST SETUP: # # This test starts two nodes to play with. # It creates one table with AC primary key: test.t # # TEST PROCESSES: # # Test creates one db dropper process and two inserter process: # inserter: keeps on insertting rows in the test table # the two inserters target separate cluster nodes # This way the dropper will conflict both with local state # and slave inserts # dropper: dropper process runs drop table; create table sequences # for the test table. When table is dropped, local inserts # keep on failing until the table is re-created again. # There is small sleep after CREATE # # SUCCESS CRITERIA # # If bug is present, either one node can crash. When DROP processing happens in # background, the drop can happen in unpredictable time, and slave applier # may fail to apply an insert => this will crash the slave # It is a good idea to check mysql logs as well. Backgrounded DROP will cause # the following CREATE TABLE to fail. galera apply processor tolerates failures # for DDL, and this type of error does not cause crash. However, there is # slave error in the log. This latter symptom is much more probable than # actual crash. # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:909155" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1)" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " #declare -r port_0=$(( DBMS_PORT )) #declare -r port_1=$(( DBMS_PORT + 1)) declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} inserter() { local port=$1 for i in {1..10000}; do $MYSQL --port=$port -e "INSERT INTO test.t(j) VALUES($i)" 2>&1 | grep -v "ERROR 1146"; done } createdb() { $MYSQL --port=$port_0 -e 'DROP TABLE IF EXISTS test.t; CREATE TABLE test.t(i INT PRIMARY KEY AUTO_INCREMENT, j int)' } dropper() { for i in {1..200}; do createdb; sleep 0.2; done } echo "Creating database..." createdb echo echo "### Phase 1, DML & DDL => node0 ###" echo echo "starting inserter for port $port_0" inserter $port_0 & declare inserter1_pid=$! echo "starting dropper" dropper & declare dropper_pid=$! echo "waiting phase 1 load to end ($dropper_pid $inserter1_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' echo echo "### Phase 2, DML => node1 DDL => node0 ###" echo echo "starting inserter for port $port_1" inserter $port_1 & declare inserter2_pid=$! echo "starting dropper" dropper & dropper_pid=$! echo "waiting phase 2 load to end ($dropper_pid $inserter2_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' echo echo "### Phase 3, DML => node0, node1 DDL => node0 ###" echo echo "starting inserter for port $port_0" inserter $port_0 & inserter1_pid=$! echo "starting inserter for port $port_1" inserter $port_1 & inserter2_pid=$! echo "starting dropper" dropper & dropper_pid=$! echo "waiting phase 3 load to end ($dropper_pid $inserter1_pid $inserter2_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' echo echo "Done!" echo ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit percona-galera-3-3.8-3390/tests/regressions/lp917416/000077500000000000000000000000001244131713600216165ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp917416/run.sh000077500000000000000000000112661244131713600227670ustar00rootroot00000000000000#!/bin/bash ## # # lp:917416 # https://bugs.launchpad.net/codership-mysql/+bug/917416 # # BUG BACKGROUND: # # BF processing can kill local transactins doing only reads. One situation # where this happens very probably is when DDL is run under TO isolation # and some local transaction tries to read from mysql database. # Native MySQL uses thr locks to serialize such access and reads are not # aborted, so we have a transaparency issue here. And there are use cases # especially related to SP's and functions where proc table is consulted # for available routines SELECT ROUTINE_TYPE FROM INFORMATION_SCHEMA.ROUTINES # WHERE SPECIFIC_NAME = '' etc... # # TEST SETUP: # # This test starts two nodes to play with # # # TEST PROCESSES: # # Test creates one DDL process and one mysql schema reader process: # reader: keeps on reading mysql.user table # the two inserters target separate cluster nodes # This way the dropper will conflict both with local state # and slave inserts # DDL: DDL process creates and drops one user to cause locking # needs for mysql.user table # # SUCCESS CRITERIA # # If bug is present, the select process will encounter many deadlocks # due to BF aborting # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:917416" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1)" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} declare -r ROUNDS=10000 declare -r ERROR_LIMIT=10 declare errors=0 declare success=0 ####################### # Processes ######################## send_sql() { local port=$1 local type=$2 local rounds=$3 local sleep=$4 local SQL=$5 for (( i=1; i<$rounds; i++ )); do $MYSQL --port=$port -e "$SQL" 2>&1 > /tmp/lp917416.out ret=$? [ $ret -ne 0 ] && \ echo "SELECT failed ($ret $i) " && \ cat /tmp/lp917416.out && \ success=1 && \ errors=$(( $errors + 1 )) [ $errors -gt $ERROR_LIMIT ] && echo "$type STOPPED" && exit 1 sleep $sleep done } reader_m() { local port=$1 send_sql $port "SELECT-M" $ROUNDS 0 \ 'select user,host from mysql.user limit 1' echo "mysql reader complete `date`" } ddl_m() { send_sql $port_0 "DDL-M" $ROUNDS 0 \ 'CREATE USER seppo; DROP USER seppo; FLUSH PRIVILEGES' echo "mysql DDL complete `date`" } # # InnODB reader and DDL # reader_i() { local port=$1 send_sql $port "SELECT-I" $ROUNDS 0 'select i from test.t917416 limit 1' echo "innodb reader complete `date`" } ddl_i() { send_sql $port_0 "DDL-I" $(( $ROUNDS / 20 )) 0.1 \ 'ALTER TABLE t917416 ADD COLUMN (j int); ALTER TABLE t917416 DROP COLUMN j' echo "innodb DDL complete `date`" } ####################### # Main, init ######################## echo "Creating database..." $MYSQL --port=$port_0 -e 'DROP USER seppo; FLUSH PRIVILEGES' 2>&1 > /dev/null $MYSQL --port=$port_0 -e 'DROP TABLE IF EXISTS test.t917416' $MYSQL --port=$port_0 -e 'CREATE TABLE test.t917416(i int) engine=innodb' ####################### # Phase 1 ######################## echo echo "### Phase 1, SELECT & DDL => node0 ###" echo echo "starting reader for port $port_0" reader_m $port_0 & declare reader_pid=$! echo "starting ddl" ddl_m & declare ddl_pid=$! echo "waiting phase 1 load to end (PIDs: $ddl_pid $reader_pid)" wait echo echo "Processlist now:" $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo ####################### # Phase 2 ######################## echo echo "### Phase 2, InnoDB SELECT & ALTER => node0 ###" echo errors=0 echo "starting reader for port $port_0" reader_i $port_0 & reader_pid=$! echo "starting ddl" ddl_i & ddl_pid=$! echo "waiting phase 2 load to end (PIDs: $ddl_pid $reader_pid)" wait echo echo "Processlist now:" $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo ####################### # Cleanup ######################## $MYSQL --port=$port_0 -e 'DROP TABLE t917416' ; ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit $successpercona-galera-3-3.8-3390/tests/regressions/lp922757/000077500000000000000000000000001244131713600216225ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp922757/run.sh000077500000000000000000000133201244131713600227640ustar00rootroot00000000000000#!/bin/bash ## # # lp:922757 # https://bugs.launchpad.net/codership-mysql/+bug/922757 # # BUG BACKGROUND: # # Foreign key constrainst were taken in consideration so that both parent # and child key were populated in cert index, i.e. they were recorded as # write access for both tables. # This caused major performance issues due to unnecessary cert failures. # A general use case has it that one parent table is referenced from many # child tables. Transactions updating such separate child rows had conflciting # write sets in the parent reference and caused a big number of certification # aborts. # # TEST SETUP: # # This test starts two nodes to play with. # A child table - parent table pair is created and populated with rows # so that we have only one parent row and several child rows referencing # the parent. # # # TEST PROCESSES: # # Test creates several update processes updating separate child table rows # updater: keeps on updating same child table with altering values # # SUCCESS CRITERIA # # If bug is present, the update process will encounter many deadlocks # due to cert failures # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:922757" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop #echo "stopping node0, node1..." #../../scripts/command.sh stop_node 0 #../../scripts/command.sh stop_node 1 echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1)" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD -Dtest " declare -r host_0=${NODE_INCOMING_HOST[0]} declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r host_1=${NODE_INCOMING_HOST[1]} declare -r port_1=${NODE_INCOMING_PORT[1]} declare -r ROUNDS=1000 declare -r ERROR_LIMIT=10 declare success=0 declare err_cnt=0 declare ok_cnt=0 ####################### # Processes ######################## updater() { local key=$1 local host=$2 local port=$3 local errors=0 echo "updater, key: $key, port: $port starting" for (( i=1; i<$ROUNDS; i++ )); do fk=$(( $i % 2 )) $MYSQL --host=$host --port=$port -e "UPDATE test.lp922757child set fk=$fk WHERE pk=$key" 2>&1 > /tmp/lp922757.out ret=$? if (( $ret != 0 )); then echo "UPDATE failed, ret=$ret key=$key round=$i " cat /tmp/lp922757.out success=1 errors=$(( $errors + 1 )) err_cnt=$(( $err_cnt + 1 )) else ok_cnt=$(( $ok_cnt + 1 )) fi [ $errors -gt $ERROR_LIMIT ] && echo "update STOPPED, key=$key" && exit 1 done echo "updater, key: $key, port: $port ending" } ####################### # Main, init ######################## echo "Creating database..." $MYSQL --host=$host_0 --port=$port_0 -e 'DROP TABLE IF EXISTS test.lp922757child' $MYSQL --host=$host_0 --port=$port_0 -e 'DROP TABLE IF EXISTS test.lp922757parent' $MYSQL --host=$host_0 --port=$port_0 -e 'CREATE TABLE test.lp922757parent(pk int primary key) engine=innodb' $MYSQL --host=$host_0 --port=$port_0 -e 'CREATE TABLE test.lp922757child(pk int primary key, fk int, v int, foreign key (fk) references test.lp922757parent(pk)) engine=innodb' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757parent(pk) VALUES (0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757parent(pk) VALUES (1)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (1,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (2,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (3,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (4,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (5,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (6,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (7,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (8,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (9,1,0)' $MYSQL --host=$host_0 --port=$port_0 -e 'INSERT INTO test.lp922757child(pk,fk,v) VALUES (10,1,0)' ####################### # Phase 1 ######################## echo echo "### Phase 1, launch updaters" echo updater 1 $host_0 $port_0 & declare p1=$! updater 2 $host_1 $port_1 & declare p2=$! updater 3 $host_0 $port_0 & declare p3=$! updater 4 $host_1 $port_1 & declare p4=$! updater 5 $host_0 $port_0 & declare p5=$! updater 6 $host_1 $port_1 & declare p6=$! updater 7 $host_0 $port_0 & declare p7=$! updater 8 $host_1 $port_1 & declare p8=$! updater 9 $host_0 $port_0 & declare p9=$! updater 10 $host_1 $port_1 & declare p10=$! echo "waiting load to end (PIDs $p1 $p2 $p3 $p4 $p5 $p6 $p7 $p8 $p9 $p10)" wait echo echo "total failed : $err_cnt" echo "total succeeded: $ok_cnt" echo echo echo "Processlist now:" $MYSQL --host=$host_0 --port=$port_0 -e 'SHOW PROCESSLIST' echo ####################### # Cleanup ######################## $MYSQL --host=$host_0 --port=$port_0 -e 'DROP TABLE test.lp922757child' $MYSQL --host=$host_0 --port=$port_0 -e 'DROP TABLE test.lp922757parent' ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit $successpercona-galera-3-3.8-3390/tests/regressions/lp928150/000077500000000000000000000000001244131713600216135ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp928150/run.sh000077500000000000000000000023131244131713600227550ustar00rootroot00000000000000#!/bin/bash # # lp:928150 # https://bugs.launchpad.net/codership-mysql/+bug/928150 # # TEST SETUP # # This test starts the cluster and runs 100% autocommit load. # # PARAMETERS # # Duration of test run DURATION=${DURATION:-"600"} # # set -e declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:928150" echo "##################################################################" echo "restarting cluster to clean state" restart echo "starting load for $DURATION" seconds SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration $DURATION \ --stat-interval 30 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --ac-frac 100 echo "checking consistency" check echo "stopping cluster" stop percona-galera-3-3.8-3390/tests/regressions/lp930221/000077500000000000000000000000001244131713600216035ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp930221/run.sh000077500000000000000000000034231244131713600227500ustar00rootroot00000000000000#!/bin/bash # # lp:930221 # https://bugs.launchpad.net/codership-mysql/+bug/930221 # # TEST # # This test starts two nodes, runs sqlgen against the first and # FTWRL against the second. Finally consistency is checked. # # TEST OUTCOME # # If bug is present, test will hang. # # PARAMETERS # # How many rounds to run FTWRL ROUNDS=${ROUNDS:-10000} # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:930221" echo "##################################################################" echo "starting two nodes" stop start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1)" 1 echo "starting sqlgen load for $DURATION" seconds SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD \ --host ${NODE_INCOMING_HOST[0]} \ --port ${NODE_INCOMING_PORT[0]} \ --users $DBMS_CLIENTS --duration 99999999 \ --stat-interval 30 --sess-min 999999 --sess-max 999999 \ --rows 1000 --ac-frac 100 & sqlgen_pid=$! trap "kill $sqlgen_pid" EXIT echo "waiting 10 seconds for sqlgen to start)" sleep 10 echo "starting FTWRL load" cnt=$ROUNDS while test $cnt != 0 do mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]} \ -e "FLUSH TABLES WITH READ LOCK" cnt=$(($cnt - 1)) done kill $sqlgen_pid || true echo "checking consistency" check echo "stopping cluster" stop percona-galera-3-3.8-3390/tests/regressions/lp959512/000077500000000000000000000000001244131713600216215ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp959512/run.sh000077500000000000000000000033731244131713600227720ustar00rootroot00000000000000#!/bin/bash ## # lp:959512 # https://bugs.launchpad.net/codership-mysql/+bug/959512 # # Description: # # Running the statements described below caused slave nodes to crash. # The reson was that multi statement transaction produced empty write # set, which caused IO cache not to be reset at transaction cleanup. # Following INSERT INTO foo failed then to replicate because IO cache # remained in read mode, following slave crashes on final UPDATE foo # because row to be updated could not be found. # ## set -e declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" # . $SCRIPTS/jobs.sh # . $SCRIPTS/action.sh # . $SCRIPTS/kill.sh # . $SCRIPTS/misc.sh # restart the cluster $SCRIPTS/command.sh restart STMTS="DROP TABLE IF EXISTS variable; DROP TABLE IF EXISTS foo; CREATE TABLE variable ( name varchar(128) NOT NULL DEFAULT '' COMMENT 'The name of the variable.', value longblob NOT NULL COMMENT 'The value of the variable.', PRIMARY KEY (name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Named variable/value pairs created by Drupal core or any...'; CREATE TABLE foo (a int); INSERT INTO variable (name, value) VALUES ('menu_expanded', 'a:0:{}'); START TRANSACTION; SELECT 1 AS expression FROM variable variable WHERE ( (name = 'menu_expanded') ) FOR UPDATE; UPDATE variable SET value='a:0:{}' WHERE ( (name = 'menu_expanded') ); COMMIT; INSERT INTO foo VALUES (1); UPDATE foo SET a = 2 WHERE a = 1;" MYSQL="mysql --batch --silent -uroot -prootpass -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]}" $MYSQL -Dtest -e "$STMTS" $SCRIPTS/command.sh check if test $? != 0 then echo "test failed" exit 1 fi $SCRIPTS/command.sh stop percona-galera-3-3.8-3390/tests/regressions/lp963734/000077500000000000000000000000001244131713600216225ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp963734/run.sh000077500000000000000000000042371244131713600227730ustar00rootroot00000000000000#!/bin/bash # # Regression test for lp:963734 # https://bugs.launchpad.net/codership-mysql/+bug/963734 # # TEST DESCRIPTION: # # This test runs create table, table rename, insert into in single # session. If alter table rename is missing table keys for both table names, # slave will eventually crash on insert because replicator allows parallel # applying of insert when alter is still running. # # Table renaming is tested with both ALTER TABLE ... RENAME and # RENAME TABLE ... TO. # set -e declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" TABLE_BASENAME="lp963734" ALTER_STMTS="DROP TABLE IF EXISTS ${TABLE_BASENAME}_a, ${TABLE_BASENAME}_b; CREATE TABLE ${TABLE_BASENAME}_a (a int); ALTER TABLE ${TABLE_BASENAME}_a RENAME ${TABLE_BASENAME}_b; INSERT INTO ${TABLE_BASENAME}_b VALUES (1); DROP TABLE ${TABLE_BASENAME}_b;" RENAME_STMTS="DROP TABLE IF EXISTS ${TABLE_BASENAME}_a, ${TABLE_BASENAME}_b; CREATE TABLE ${TABLE_BASENAME}_a (a int); RENAME TABLE ${TABLE_BASENAME}_a TO ${TABLE_BASENAME}_b; INSERT INTO ${TABLE_BASENAME}_b VALUES (1); DROP TABLE ${TABLE_BASENAME}_b;" ROUNDS=${ROUNDS:-1000} cnt=$ROUNDS $SCRIPTS/command.sh restart while test $cnt != 0 do mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} \ -P${NODE_INCOMING_PORT[0]} \ -Dtest \ -e "$ALTER_STMTS" cnt=$(($cnt - 1)) done while test $cnt != 0 do mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} \ -P${NODE_INCOMING_PORT[0]} \ -Dtest \ -e "$RENAME_STMTS" cnt=$(($cnt - 1)) done $SCRIPTS/command.sh check ret=$? if test $ret != 0 then echo "Test failed" exit 1 fi node_cnt=0 for node in $NODE_LIST do node_cnt=$(($node_cnt + 1)) done for node in $NODE_LIST do cs=$($SCRIPTS/command.sh cluster_status $node) if test $cs != "Primary:$node_cnt" then echo "invalid cluster status for $node: $cs" echo "test failed" exit 1 fi done $SCRIPTS/command.sh stop percona-galera-3-3.8-3390/tests/regressions/lp966950/000077500000000000000000000000001244131713600216255ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp966950/run.sh000077500000000000000000000023441244131713600227730ustar00rootroot00000000000000#!/bin/bash # # DESCRIPTION: # # Regression test to reproduce lp:966950 # See https://bugs.launchpad.net/codership-mysql/+bug/966950 # set -e declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" $SCRIPTS/command.sh restart MYSQL="mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} -Dtest" TABLE_PREFIX="lp966950_" PARENT_TABLE="${TABLE_PREFIX}parent" CHILD_TABLE="${TABLE_PREFIX}child" $MYSQL -e "DROP TABLE IF EXISTS $CHILD_TABLE, $PARENT_TABLE; CREATE TABLE $PARENT_TABLE ( a INT PRIMARY KEY, b INT, INDEX idx_b(b) ) ENGINE=InnoDB; CREATE TABLE $CHILD_TABLE ( c INT, d INT, INDEX idx_d(d), FOREIGN KEY (d) REFERENCES $PARENT_TABLE(b) ON DELETE CASCADE ) ENGINE=InnoDB; INSERT INTO $PARENT_TABLE VALUES (1, 1); INSERT INTO $CHILD_TABLE VALUES (101, 1);" $SCRIPTS/command.sh check if test $? != 0 then echo "Consistency check failed" exit 1 fi percona-galera-3-3.8-3390/tests/regressions/lp967134/000077500000000000000000000000001244131713600216205ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp967134/run.sh000077500000000000000000000035411244131713600227660ustar00rootroot00000000000000#!/bin/bash # # DESCRIPTION: # # Test for lp:967134 # https://bugs.launchpad.net/codership-mysql/+bug/967134 # # This test script may not be able to crash nodes or generate inconsistency. # However, some error messages may be generated in error log if the # fix is not effective. # set -e declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" $SCRIPTS/command.sh restart MYSQL="mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} -Dtest" TABLE_PREFIX="" PARENT_TABLE="${TABLE_PREFIX}parent" CHILD_TABLE="${TABLE_PREFIX}child" rounds=10 while test $rounds != 0 do PARENT_TABLE_CREATE="CREATE TABLE $PARENT_TABLE (a INT PRIMARY KEY" echo "-- generating $((100 - $rounds)) columns for parent" for ii in `seq 0 $((100 - $rounds))` do PARENT_TABLE_CREATE="$PARENT_TABLE_CREATE, a$ii INT DEFAULT $ii" done PARENT_TABLE_CREATE="$PARENT_TABLE_CREATE) ENGINE=InnoDB" # echo $PARENT_TABLE_CREATE $MYSQL -e "DROP TABLE IF EXISTS $CHILD_TABLE, $PARENT_TABLE; $PARENT_TABLE_CREATE; CREATE TABLE $CHILD_TABLE ( c INT, d INT, INDEX idx_c(c), FOREIGN KEY (c) REFERENCES $PARENT_TABLE(a) ON DELETE CASCADE ) ENGINE=InnoDB;" ROWS=${ROWS:-1000} ii=0 echo "-- Filling parent table" while test $ii != $ROWS do $MYSQL -e "INSERT INTO $PARENT_TABLE (a) VALUES ($ii)" ii=$(($ii + 1)) done echo "-- Filling child table" ii=0 while test $ii != $ROWS do $MYSQL -e "INSERT INTO $CHILD_TABLE VALUES (1, 1)" ii=$(($ii + 1)) done rounds=$(($rounds - 1)) done $SCRIPTS/command.sh checkpercona-galera-3-3.8-3390/tests/regressions/lp970714/000077500000000000000000000000001244131713600216165ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp970714/lp.sql000066400000000000000000002157001244131713600227570ustar00rootroot00000000000000LOCK TABLE test.lp WRITE; INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); INSERT INTO test.lp(who) VALUES ('loader'); UNLOCK TABLES;percona-galera-3-3.8-3390/tests/regressions/lp970714/run.sh000077500000000000000000000104411244131713600227610ustar00rootroot00000000000000#!/bin/bash # # lp:970714 # https://bugs.launchpad.net/codership-mysql/+bug/970714 # # BACKGROUND: # For locking session support we can say that: # 1. they cannot be supported in multi-master case # 2. they muist be supported in master-slave case (for tansparency) # # Detecting MS and MM use cases is difficult from within a node, so we # must detect locking sessions conflicts between appliers and # local locking sessions and abort the locking sessions. # # TEST # # This test starts two nodes and runs two client sessions against each node: # applier: this load is simple autoinc insert load which will cause conflicts # in the other node's applying # loader: this load runs a locking session with a big number of inserts within # # The idea is that in the second node, loader will run a locking session and # applier load from the first node will conflict with the locking session. # mysqld should be able to abort loader transaction and break the locking # session # # TEST OUTCOME # # If bug is present, second node will either crash or hang due to unresolved # conflicts, applier will be blocked # # PARAMETERS # # How many rounds to run load ROUNDS=${ROUNDS:-100} # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh applier() { for (( i=1; i<$ROUNDS; i++ )); do mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]} \ -e "INSERT INTO test.lp(who) VALUES ('applier')" [ $? != 0 ] && echo "applier aborted: $? at $cnt" done } loader() { for (( i=1; i<$ROUNDS; i++ )); do mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]} \ < ./lp.sql [ $? != 0 ] && echo "load aborted: $? at $cnt" done } run_test() { echo "starting loader" loader& loader_pid=$! echo "starting applier" applier& applier_pid=$! echo "waiting for loader ($loader_pid) and applier ($applier_pid)" wait trap "kill $applier_pid" EXIT trap "kill $loader_pid" EXIT echo "checking consistency" check } echo "##################################################################" echo "## regression test for lp:970714" echo "##################################################################" echo "starting two nodes" stop start_node "-d -g gcomm://$(extra_params 0)" 0 start_node "-d -g $(gcs_address 1)" 1 echo "creating database" mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]} \ -e "DROP TABLE IF EXISTS test.lp" mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]} \ -e "CREATE TABLE test.lp(pk INT PRIMARY KEY AUTO_INCREMENT, who VARCHAR(10))" [ $? != "0" ] && echo "table create failed" && exit 1 echo "##" echo "## wsrep_convert_LOCK_to_trx=1" echo "##" echo "setting wsrep_convert_LOCK_to_trx=1" mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]} \ -e "SET GLOBAL wsrep_convert_LOCK_to_trx=1" [ $? != "0" ] && echo "SET failed" && exit 1 mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]} \ -e "SET GLOBAL wsrep_convert_LOCK_to_trx=1" [ $? != "0" ] && echo "SET failed" && exit 1 run_test echo "##" echo "## wsrep_convert_LOCK_to_trx=0" echo "##" echo "setting wsrep_convert_LOCK_to_trx=0" mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[0]} --port ${NODE_INCOMING_PORT[0]} \ -e "SET GLOBAL wsrep_convert_LOCK_to_trx=0" [ $? != "0" ] && echo "SET failed" && exit 1 mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ --host ${NODE_INCOMING_HOST[1]} --port ${NODE_INCOMING_PORT[1]} \ -e "SET GLOBAL wsrep_convert_LOCK_to_trx=0" [ $? != "0" ] && echo "SET failed" && exit 1 run_test echo "stopping cluster" stop percona-galera-3-3.8-3390/tests/regressions/lp994579/000077500000000000000000000000001244131713600216355ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/lp994579/run.sh000077500000000000000000000140451244131713600230040ustar00rootroot00000000000000#!/bin/bash ## # # lp:994579 # https://bugs.launchpad.net/codership-mysql/+bug/994579 # # BUG BACKGRPOUND: # # Foreign keys are not yet safe with parallel applying. This is due to # a bug in populating of shared keys. # If bug is present, slave appliers can easily conflict and cause crash. # # TEST SETUP: # - Two nodes are used in master slave mode. # - Slave is configured with 4 applier threads # - parent and child tables are created # - test load runs inserts for parent and child table, each parent # insert is followed by corresponding child insert # # # SUCCESS CRITERIA # # If bug is present, slave will crash for FK constraint failure. This is # because slave applied inserts in wrong order - child row was added before # corresponding parent row. # declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh echo "##################################################################" echo "## regression test for lp:994579" echo "##################################################################" echo "stopping cluster" ../../scripts/command.sh stop #echo "stopping node0, node1..." #../../scripts/command.sh stop_node 0 #../../scripts/command.sh stop_node 1 echo echo "starting node0, node1..." ../../scripts/command.sh start_node "-d -g gcomm://$(extra_params 0)" 0 ../../scripts/command.sh start_node "-d -g $(gcs_address 1) --slave_threads 4" 1 MYSQL="mysql --batch --silent --user=$DBMS_TEST_USER --password=$DBMS_TEST_PSWD --host=$DBMS_HOST test " declare -r port_0=${NODE_INCOMING_PORT[0]} declare -r port_1=${NODE_INCOMING_PORT[1]} inserter_int_trx() { local port=$1 for i in {1..10000}; do $MYSQL --port=$port -e " BEGIN; INSERT INTO test.lp994579_parent(pk, j) VALUES($i, $i); INSERT INTO test.lp994579_child(i,fk) VALUES ($i, $i); COMMIT;" 2>&1 done } inserter_int_ac() { local port=$1 for i in {1..10000}; do $MYSQL --port=$port -e " INSERT INTO test.lp994579_parent(pk, j) VALUES($i, $i); INSERT INTO test.lp994579_child(i,fk) VALUES ($i, $i); " 2>&1 done } createdb_int() { $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp994579_child;" $MYSQL --port=$port_0 -e ' DROP TABLE IF EXISTS test.lp994579_parent;' $MYSQL --port=$port_0 -e ' CREATE TABLE test.lp994579_parent ( pk INT PRIMARY KEY AUTO_INCREMENT, j int )' $MYSQL --port=$port_0 -e " CREATE TABLE test.lp994579_child ( i INT PRIMARY KEY AUTO_INCREMENT, fk int, CONSTRAINT FOREIGN KEY (fk) REFERENCES test.lp994579_parent(pk) )" } createdb_varchar() { local charset=$1 $MYSQL --port=$port_0 -e " DROP TABLE IF EXISTS test.lp994579_child;" $MYSQL --port=$port_0 -e ' DROP TABLE IF EXISTS test.lp994579_parent;' $MYSQL --port=$port_0 -e " CREATE TABLE test.lp994579_parent ( pk VARCHAR(20) PRIMARY KEY, j int ) CHARACTER SET '$charset' " $MYSQL --port=$port_0 -e " CREATE TABLE test.lp994579_child ( i INT PRIMARY KEY AUTO_INCREMENT, fk VARCHAR(20), CONSTRAINT FOREIGN KEY (fk) REFERENCES test.lp994579_parent(pk) ) CHARACTER SET '$charset'" } inserter_varchar_ac() { local port=$1 for i in {1..10000}; do $MYSQL --port=$port -e " INSERT INTO test.lp994579_parent(pk, j) VALUES('key-$i', $i); INSERT INTO test.lp994579_child(i,fk) VALUES ($i, 'key-$i'); " 2>&1 done } ######################################################### # # Test begins here # ######################################################### threads=$($MYSQL --port=$port_1 -e "SHOW VARIABLES LIKE 'wsrep_slave_threads'") echo "applier check: $threads" [ "$threads" = "wsrep_slave_threads 4" ] && echo "enough slaves" echo "Creating database..." createdb_int echo echo echo "#############################################" echo "### Phase 1, FK by int column, autocommit ###" echo echo "starting inserter for int keys, autocommit" inserter_int_ac $port_0 & declare inserter1_pid=$! echo "waiting phase 1 load to end ($inserter1_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 createdb_int echo echo echo "###############################################" echo "### Phase 2, FK by int column, transactions ###" echo echo "starting inserter for int keys, transactions" inserter_int_trx $port_0 & declare inserter2_pid=$! echo "waiting phase 2 load to end ($inserter2_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 echo echo echo "#############################################" echo "### Phase 3, FK by varchar column, latin1 ###" echo createdb_varchar latin1 echo "starting inserter for VARCHAR keys, autocommit" inserter_varchar_ac $port_0 & declare inserter3_pid=$! echo "waiting phase 3 load to end ($inserter3_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 echo echo echo "###########################################" echo "### Phase 4, FK by varchar column, utf8 ###" echo createdb_varchar utf8 echo "starting inserter for VARCHAR keys, autocommit" inserter_varchar_ac $port_0 & declare inserter4_pid=$! echo "waiting phase 4 load to end ($inserter4_pid)" wait $MYSQL --port=$port_0 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 echo $MYSQL --port=$port_1 -e 'SHOW PROCESSLIST' [ "$?" != "0" ] && echo "failed!" && exit 1 $SCRIPTS/command.sh check if test $? != 0 then echo "Consistency check failed" exit 1 fi echo echo "Done!" echo ../../scripts/command.sh stop_node 0 ../../scripts/command.sh stop_node 1 exit 0 percona-galera-3-3.8-3390/tests/regressions/run-all.sh000077500000000000000000000022711244131713600224220ustar00rootroot00000000000000#!/bin/bash tests="lp1100496 lp1179361 lp1184034 lp1089490 lp1073220 lp1003929 lp1013978 lp1026181 lp1055961 lp994579 lp970714 lp967134 lp966950 lp963734 lp959512 lp930221 lp928150 lp922757 lp909155 lp861212 lp847353 lp518749 t285 t281" skipped_tests="lp900816 lp917416" # old way was to run just ~50% of available tests # tests ignored # # lp900816 - does not work out of the box # lp917416 - hangs # #for ii in $tests #do # echo "running test $ii" # ( cd $ii && ./run.sh ) # if test $? != 0 # then # echo "test $ii failed" # exit 1 # fi #done # new way to run all tests in directory, # but skipping those which were declared to be skipped for ii in `ls -d ./lp*` do skip=0 for skipped in { "$skipped_tests" } do if [ "$ii" == "$skipped" ] then echo "skipping test: $ii"; skip=1; fi done if [ "$skip" == "0" ] then echo "running test $ii" ( cd $ii && ./run.sh ) if test $? != 0 then echo "test $ii failed" exit 1 fi fi done percona-galera-3-3.8-3390/tests/regressions/t281/000077500000000000000000000000001244131713600212055ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/t281/run.sh000077500000000000000000000026151244131713600223540ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/signal.sh . $SCRIPTS/misc.sh function get_status { cmd=$(echo "show status like '$2'") echo $(mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD -h${NODE_INCOMING_HOST[$1]} -P${NODE_INCOMING_PORT[$1]} -e "$cmd" | awk '{print $2;}'); } echo "regression test for #281" echo "restarting cluster" $SCRIPTS/command.sh restart mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]} test \ -e "DROP TABLE IF EXISTS t281"; signal_node STOP 1 pause 20 1 signal_node CONT 1 pause 10 1 status=$(get_status 1 "wsrep_cluster_status"); ready=$(get_status 1 "wsrep_ready"); echo $status $ready if test $status=="Primary" && test $ready=="ON" then mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]} test \ -e "CREATE TABLE t281 (a int)"; if test $? != 0; then echo "Failed to execute command"; exit 1; fi else echo "Wrong state"; exit 1; fi mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]} test \ -e "DROP TABLE IF EXISTS t281"; $SCRIPTS/command.sh stop exit 0; percona-galera-3-3.8-3390/tests/regressions/t285/000077500000000000000000000000001244131713600212115ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/regressions/t285/run.sh000077500000000000000000000025631244131713600223620ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/../..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/signal.sh . $SCRIPTS/misc.sh echo "regression test for #285" echo "restarting cluster" $SCRIPTS/command.sh restart mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} test \ -e "DROP TABLE IF EXISTS t285"; mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} test \ -e "CREATE TABLE t285 (a INT PRIMARY KEY)"; stmt=$( echo "BEGIN;"; for i in `seq 1 $((1 << 16))` do echo "INSERT INTO t285 VALUES ($i);"; done echo "COMMIT;"; ) echo $stmt | mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} test if test $? != 0 then echo "query failed"; exit 1; else mysql -s -s -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD \ -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} test \ -e "DROP TABLE IF EXISTS t285"; if test $? != 0 then echo "cleanup failed, check server status"; exit 1; fi fi $SCRIPTS/command.sh check if test $? != 0 then echo "checksum failed" exit 1 fi $SCRIPTS/command.sh stop exit 0;percona-galera-3-3.8-3390/tests/run.sh000077500000000000000000000026321244131713600173120ustar00rootroot00000000000000#!/bin/bash set -e # This script assumes that galera cluster is alredy installed and configured # This is location of this script. _HOME suffix preferred to _ROOT to avoid # confusion THIS_HOME=$(cd $(dirname $0); pwd -P) # Optional configuration file if test -n "$GALERA_TEST_CONFIG" then . "$GALERA_TEST_CONFIG" fi GALERA_TESTS_HOME=${GALERA_TESTS_HOME:-$THIS_HOME} GALERA_RESULTS_HOME=${GALERA_RESULTS_HOME:-$GALERA_TESTS_HOME/results} # Incoming cluster address (load balancer) export GALERA_CLUSTER_IP=${GALERA_CLUSTER_IP:-"127.0.0.1"} export GALERA_CLUSTER_PORT=${GALERA_CLUSTER_PORT:-3306} # List of tests to run GALERA_TESTS=${GALERA_TESTS:-"sqlgen dbt2 dots"} # This is needed for native load balancing and consistency checking export GALERA_NODES_IPS=${GALERA_NODE_IPS:?"GALERA_NODE_IPS not set"} export GALERA_NODES_PORTS=${GALERA_NODE_PORTS:?"GALERA_NODE_PORTS not set"} # Create a results directory for this run GALERA_DATE=$(date +%Y-%m-%d_%H:%M:%S) mkdir -p $GALERA_RESULTS_HOME/$GALERA_DATE declare TESTS_FAILED TESTS_FAILED=0 for TEST in $GALERA_TESTS do export GALERA_RESULT_DIR=$GALERA_RESULTS_HOME/$GALERA_DATE/$TEST mkdir -p $GALERA_RESULT_DIR echo -n "Running $TEST... " $GALERA_TESTS_HOME/test_$TEST/run.sh && echo "passed" \ || { TESTS_FAILED=$[ $TESTS_FAILED + 1 ]; echo "failed"; } done if [ $TESTS_FAILED != "0" ] then echo "Tests failed: $TESTS_FAILED" exit 1 fi # percona-galera-3-3.8-3390/tests/run_test_set.sh000077500000000000000000000006421244131713600212230ustar00rootroot00000000000000#!/bin/sh # # This is a wrapper script for ./tap/run_test_set.pl # BASE_DIR=$(cd $(dirname $0); pwd -P) cd $BASE_DIR res=$? if test $res != 0 then echo "Failed to change directory to $BASE_DIR" exit 1 fi export TEST_BASE_DIR=$BASE_DIR . $BASE_DIR/conf/cluster.conf $BASE_DIR/tap/run_test_set.pl $@ res=$? if test $res != 0 then echo "Failed to run test set, exit code: $res" exit 1 fi exit 0 percona-galera-3-3.8-3390/tests/scripts/000077500000000000000000000000001244131713600176335ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/scripts/README000066400000000000000000000033741244131713600205220ustar00rootroot00000000000000THIS DIRECTORY This directory contains a library of cluster manipulation scripts. The main idea is facilitation of parallel operations and minimizaiton of code duplicaiton. Executable file is command.sh. It sources the configuration and the rest of the scripts which implement different funcitons: jobs.sh - the main file which defines generic command execution framework. It implements parallel and per-node command execution routines and enables unified logging behaviour. Other scripts just have to define the actual command functions following certain conventions, so far there is only one: node index is appended to the list of command line parameters, then everything is passed to the function. install.sh - implements a cluster-wide 'install' command which takes a name of the distribution file as the first argument remove.sh - implements a cluster-wide "remove" command. action.sh - usual start/stop/restart/check commands, both cluster-wide and per node. kill.sh - a per-node kill -9 command Assumed convention: cluster-wide commands are just commnads, per-node commands have _node suffix. E.g. ./command.sh start starts all nodes, ./command.sh stop_node 1 stops only node number 1. Numbering is 0-based. It is intended that each command should implement its own help. SPECIAL FILES AND DIRECTORIES: ../conf directory contains configuration files. Each command creates at least 4 files named _. where is: out - standard output of the command err - standard error of the command pid - pid of the porcess executing command ret - return code of the command "out" files are placed into $BASE_OUT directory, other files are placed in $BASE_RUN. The reason to separate is unclear. percona-galera-3-3.8-3390/tests/scripts/action.sh000066400000000000000000000154241244131713600214520ustar00rootroot00000000000000# Helper to get status variable value cluster_status() { local node=$1 case "$DBMS" in "MYSQL") local res=$(mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ -h${NODE_INCOMING_HOST[$node]} -P${NODE_INCOMING_PORT[$node]} \ --skip-column-names -ss \ -e "SET wsrep_on=0; SHOW STATUS WHERE Variable_name LIKE 'wsrep_cluster_status' OR Variable_name LIKE 'wsrep_cluster_size'" 2>/dev/null) echo -n $res | awk '{ print $4 ":" $2; }' ;; "PGSQL"|*) return -1 esac } mysql_query() { local node=$1 local query=$2 mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ -h${NODE_INCOMING_HOST[$node]} -P${NODE_INCOMING_PORT[$node]} \ --skip-column-names -ss -e "$query" 2>/dev/null } wait_node_state() { local node=$1 local state=$2 while true do local res="-1" case "$DBMS" in "MYSQL") res=$(mysql_query $node "SHOW STATUS LIKE 'wsrep_local_state'" \ | awk '{ print $2 }') ;; "PGSQL"|*) return -1 esac if [ "$res" = "$state" ]; then break; fi sleep 1 done } # # Routines to start|stop|check cluster nodes # action_cmd() { local cmd=$1 local node=${@:$#} local nargs=$(( $# - 2 )) # minus cmd and node local args="${@:2:$nargs}" # arguments range from 2 to n-1 local dir="${NODE_TEST_DIR[$node]}" case "$DBMS" in "MYSQL") echo -n "MYSQL_PORT=${NODE_INCOMING_PORT[$node]} "\ "\"$dir/mysql-galera\" $args $cmd" ;; "PGSQL"|*) return -1 ;; esac } # By convention node index is the last in the arguments list. # So we prepend command to the argument list otherwise it'll go after node # index here. start_cmd() { action_cmd "start" "$@" } stop_cmd() { action_cmd "stop" "$@" } restart_cmd() { action_cmd "restart" "$@" } check_cmd() { action_cmd "check" "$@" } dump_cmd() { action_cmd "dump" "$@" } action() { start_jobs "$@" wait_jobs } stop() { action "stop_cmd" "$@" } dump() { action "dump_cmd" "$@" } check() { wait_sync $NODE_LIST || true cmd="check_cmd" ! action "$cmd" "$@" # ! - to ignore possible connection error local -r prefix="$BASE_OUT/$cmd" local node local prev="" local fail="" for node in $NODE_LIST do local node_id="${NODE_ID[$node]}" local out="${prefix}_${node_id}.out" chk=$(cat "$out") # no need to check if file exists: # should be created even if command fails # echo "$node_id: ${chk%% -}" if [ -n "$chk" ] # skip 0-length checksum: the node was down then echo "$chk" | sed s/-/${node_id}/ if [ -z "$prev" ] then prev="$chk" else if [ "$prev" != "$chk" ] then fail="yes" fi fi fi done if [ -z "$fail" ] && [ -n "$prev" ]; then return 0; fi echo "Checksum failed." # for node in $NODE_LIST # do # local node_id="${NODE_ID[$node]}" # echo -n "$node_id: " # cat "${prefix}_$node_id.out" # done return 1 } # Query each node with causal reads on to make sure that slave # queue has been fully processed. # Arguments: list of nodes wait_sync() { local nodes=${@:-$NODE_LIST} local node for node in $nodes do mysql_query "$node" "set wsrep_causal_reads=1; select 0;" 1>/dev/null done } start_node() { node_job "start_cmd" "$@" } stop_node() { node_job "stop_cmd" "$@" } restart_node() { node_job "restart_cmd" "$@" } dump_node() { node_job "dump_cmd" "$@" } # unlike bulk check this one returns error when the node could not be checked check_node() { local cmd="check_cmd" node_job "$cmd" "$@" local node_id="${NODE_ID[$1]}" cat "${BASE_OUT}/${cmd}_${node_id}.out" | sed s/-/${node_id}/ return $(cat $BASE_RUN/check_cmd_$node_id.ret) } extra_params() { local node=$1 local extra_params [ -z "$GCOMM_EXTRA_PARAMS" ] && extra_params="?" || extra_params="?${GCOMM_EXTRA_PARAMS}&" # echo "${extra_params}gmcast.listen_addr=tcp://${NODE_GCS_HOST[$node]}:${NODE_GCS_PORT[$node]}" echo "${extra_params}gmcast.listen_addr=tcp://0.0.0.0:${NODE_GCS_PORT[$node]}" } # return GCS address at which node N should connect to group gcs_address() { local node=$1 case "$GCS_TYPE" in "gcomm") local peer=$(( $node - 1 )) # select previous node as connection peer # local peer=0 # use the first node as a connection handle if [ $peer -lt 0 ]; then peer=$NODE_MAX; fi # rollover echo "'gcomm://${NODE_GCS_HOST[$peer]}:${NODE_GCS_PORT[$peer]}$(extra_params $node)'" ;; "vsbes") echo "'vsbes://$VSBES_ADDRESS'" ;; *) return 1 ;; esac } # start/restart nodes in group mode. _cluster_up() { local -r cmd=$1 shift SECONDS=0 # for wait_jobs for node in $NODE_LIST do echo "Starting ${NODE_ID[$node]}" if [ $node -eq 0 ] then # must make sure 1st node completely operational case "$GCS_TYPE" in # "gcomm") $cmd "-g 'gcomm://:${NODE_GCS_PORT[$node]}$(extra_params $node)'" "$@" 0 ;; "gcomm") $cmd "-g $(gcs_address $node) --mysql-opt --wsrep-new-cluster" "$@" 0 ;; "vsbes") $cmd "-g 'vsbes://$VSBES_ADDRESS'" "$@" 0 ;; esac else $cmd "-g $(gcs_address $node)" "$@" $node & fi done wait_jobs } # start/restart nodes in group mode. bootstrap() { SECONDS=0 # for wait_jobs local cnt=0 for node in $NODE_LIST do echo "Starting ${NODE_ID[$node]}" start_node "-g $(gcs_address $node)" "$@" $node & cnt=$(($cnt + 1)) done # TODO: Poll until all have reached non-prim for node in 0 # only one node is sufficient do while true do st=$(cluster_status $node) if test "x$st" = "xnon-Primary:$cnt" then break; fi sleep 1 done done # TODO: Figure out how to do this in DBMS indepent way case "$DBMS" in "MYSQL") mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD \ -h${NODE_INCOMING_HOST[0]} \ -P${NODE_INCOMING_PORT[0]} \ -e "SET GLOBAL wsrep_provider_options='pc.bootstrap=1'" ;; "PGSQL"|*) return -1 ;; esac # Jobs will finish when nodes reach primary wait_jobs } start() { _cluster_up start_node "$@" } restart() { stop _cluster_up start_node "$@" } percona-galera-3-3.8-3390/tests/scripts/command.sh000077500000000000000000000013771244131713600216200ustar00rootroot00000000000000#!/bin/bash -eu help() { echo "Usage: $0 [args]" echo "Cluster commands: install, remove, start, stop, check" echo "Node commands: start_node, stop_node, restart_node, check_node," echo " kill_node" echo "Command help: $0 help" } if [ $# -eq 0 ]; then help >&2; exit 1; fi declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) declare -r DIST_SCRIPTS="$DIST_BASE/scripts" # later create config.sh to read config from command line options declare -r TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . "$TEST_BASE/conf/main.conf" . $DIST_SCRIPTS/jobs.sh . $DIST_SCRIPTS/install.sh . $DIST_SCRIPTS/remove.sh . $DIST_SCRIPTS/action.sh . $DIST_SCRIPTS/kill.sh . $DIST_SCRIPTS/signal.sh command=$1 shift $command "$@" percona-galera-3-3.8-3390/tests/scripts/install.sh000066400000000000000000000044021244131713600216350ustar00rootroot00000000000000# # Routines to install distribution on nodes # untar_cmd() { local node=${@:$#} local path="${NODE_TEST_DIR[$node]}" local hst=$(hostname -s) echo -n "mkdir -p \"$path\" && tar --strip 1 -C \"$path\" -xzf - && > \"$path/mysql/var/mysqld.err\" && exit 0" } copy_config() { local -r node=$1 local cnf local cnf_dir local key_src="$BASE_CONF/galera_key.pem" local key_dst local cert_src="$BASE_CONF/galera_cert.pem" local cert_dst case $DBMS in MYSQL) common_cnf="$COMMON_MY_CNF" cnf_src="${NODE_MY_CNF[$node]}" cnf_dst="${NODE_TEST_DIR[$node]}/mysql/etc/my.cnf" key_dst="${NODE_TEST_DIR[$node]}/mysql/var/galera_key.pem" cert_dst="${NODE_TEST_DIR[$node]}/mysql/var/galera_cert.pem" ;; PGSQL|*) echo "Unsupported DBMS: '$DBMS'" >&2 return 1 ;; esac if [ -n "$common_cnf" ] || [ -n "$cnf_src" ] then if [ "${NODE_LOCATION[$node]}" = "local" ] then ([ -n "$common_cnf" ] && cat "$common_cnf" && \ [ -n "$cnf_src" ] && cat "$cnf_src") > "$cnf_dst" cat "$key_src" > "$key_dst" cat "$cert_src" > "$cert_dst" else local remote="${NODE_LOCATION[$node]}" ([ -n "$common_cnf" ] && cat "$common_cnf" && \ [ -n "$cnf_src" ] && cat "$cnf_src") | \ ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$remote" "cat > $cnf_dst" cat "$key_src" | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$remote" "cat > $key_dst" cat "$cert_src" | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$remote" "cat > $cert_dst" fi fi } copy_file_node() { set -x local -r src_file="$1" local -r dst_file="$2" local -r node="$3" cat "$src_file" | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${NODE_LOCATION[$node]}" "cat - > ${NODE_TEST_DIR[$node]}/$dst_file" } copy_file() { local -r src_file="$1" local -r dst_file="$2" start_jobs copy_file_node "$src_file" "$dst_file" } install_node() { local dist=$1 node_job untar_cmd "$@" } install() { local dist=$1 start_jobs untar_cmd $dist wait_jobs } percona-galera-3-3.8-3390/tests/scripts/jobs.sh000066400000000000000000000053021244131713600211240ustar00rootroot00000000000000# # Routines pertaining to parallel execution # # xxxx_job() functions assume node index as last parameter # # Logging must happen on different layers. # e.g. logging of stderr must happen on the same level as recording of return # code. While stdout log should record only the output of command. #_local_job() #{ # local cmd="$1" # eval "$($@)" # eval $cmd #} #_ssh_job() #{ # local node=${@:$#} # last argument # local cmd="$($@)" # local cmd="$1" # # ssh -ax ${NODE_LOCATION[$node]} "$cmd" #} _date() { echo -n $(date +'%y%m%d %T.%N' | cut -c 1-19) } virtual_job() { local node=${@:$#} # last argument local out="$BASE_OUT/${1}_${NODE_ID[$node]}.out" local cmd="$($@)" if [ "${NODE_LOCATION[$node]}" = "local" ] then # local_job "$cmd" 1>"$out" eval "$cmd" 1>"$out" else # ssh_job "$cmd" 1>"$out" ssh -ax -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${NODE_LOCATION[$node]} "$cmd" 1>"$out" fi } # This function tries to add a bit of polymorphism by treating untar cmd # specially. The speciality comes from that it not only excutes command, # but also transfers data # # Usage: node_job cmd opt1 opt2 ... optN node # node_job() { local cmd=$1 shift local node=${@:$#} # last argument local node_id="${NODE_ID[$node]}" local prefix="$BASE_RUN/${cmd}_${node_id}" local rcode=0 local start=$SECONDS case $cmd in "untar_cmd") local dist="$1" shift cat "$dist" | virtual_job "$cmd" "$@" 2>"$prefix.err" && \ copy_config $node 2>"$prefix.err" || rcode=$? ;; *) virtual_job "$cmd" "$@" 2>"$prefix.err" || rcode=$? ;; esac echo $rcode > "$prefix.ret" echo -n "$(_date) Job '$cmd' on '$node_id'" if [ $rcode -eq 0 ] then echo " complete in $(($SECONDS - $start)) seconds, " else echo " failed with code: $rcode, " echo "FAILED COMMAND: $($cmd $@)" echo "REASON: $(cat "$prefix.err")" fi return $rcode } start_jobs() { SECONDS=0 local node for node in $NODE_LIST do local node_id="${NODE_ID[$node]}" local prefix="$BASE_RUN/${1}_$node_id" node_job "$@" $node & echo $! > "$prefix.pid" echo "$(_date) Job '$1' on '$node_id' started" done echo "All jobs started" } wait_jobs() { local err=0 local node for node in $NODE_LIST do wait %% 2>$BASE_RUN/wait.err || err=$?; # 127 - no more jobs if [ $err -eq 127 ]; then err=0; break; fi if [ $err -gt 128 ]; then err=0; fi # ignore signals done echo "$(_date) All jobs complete in $SECONDS seconds" return $err } percona-galera-3-3.8-3390/tests/scripts/kill.sh000066400000000000000000000011431244131713600211210ustar00rootroot00000000000000# # Ungracefully kills the process # kill_cmd() { local node=${@:$#} local dir="${NODE_TEST_DIR[$node]}" case $DBMS in "MYSQL") echo -n "kill -9 \$(cat $dir/mysql/var/mysqld.pid)" ;; "PGSQL"|*) echo "Not supported" >&2 return 1 ;; esac } kill_node() { local node=${@:$#} local dir="${NODE_TEST_DIR[$node]}" local pid=$(cat $dir/mysql/var/mysqld.pid) node_job kill_cmd "$@" # wait process to disappear. while find_mysqld_pid $pid do sleep 0.1 done } kill_all() { start_jobs kill_cmd wait_jobs } percona-galera-3-3.8-3390/tests/scripts/misc.sh000066400000000000000000000012331244131713600211210ustar00rootroot00000000000000# # Miscellaneous functions # # Sleeps variable amount of seconds (by default 1-10) pause() #min_sleep #var_sleep { local min_sleep=${1:-"1"} local var_sleep=${2:-"10"} local p=$(( $RANDOM % var_sleep + min_sleep )) echo "Sleeping for $p sec." sleep $p } # Pauses given processes (load) to perform consistency check consistency_check() #pids { local ret=0 local pids="$@" kill -STOP $pids sleep 1 check || (sleep 2; check) || (sleep 3; check) || ret=$? kill -CONT $pids # processes will receive SIGHUP in case of script exit return $ret } find_mysqld_pid() { ps ax | grep mysqld | grep -w ^\ *$1 > /dev/null } percona-galera-3-3.8-3390/tests/scripts/remove.sh000066400000000000000000000003411244131713600214620ustar00rootroot00000000000000# # Routines to remove test distribution from nodes # remove_cmd() { local node=${@:$#} local dirn="${NODE_TEST_DIR[$node]}" echo -n 'rm -rf '"$dirn"'/*' } remove() { start_jobs remove_cmd wait_jobs } percona-galera-3-3.8-3390/tests/scripts/signal.sh000066400000000000000000000005601244131713600214450ustar00rootroot00000000000000# # Sends signal to process # signal_cmd() { local sig=$1 local node=$2 local dir="${NODE_TEST_DIR[$node]}" echo $sig $node case $DBMS in "MYSQL") echo -n "kill -$sig \$(cat $dir/mysql/var/mysqld.pid)" ;; "PGSQL"|*) echo "Not supported" >&2 return 1 ;; esac } signal_node() { node_job signal_cmd "$@" } percona-galera-3-3.8-3390/tests/t/000077500000000000000000000000001244131713600164075ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/t/dummy.sh000077500000000000000000000011651244131713600201040ustar00rootroot00000000000000#!/bin/bash BASE_DIR=$(cd $(dirname $0); pwd -P) . $BASE_DIR/../tap/tap-functions REPORT_DIR="$TEST_REPORT_DIR/dummy" if ! test -d $REPORT_DIR then mkdir $REPORT_DIR fi DUMMY_LOG=$REPORT_DIR/dummy.log echo "args: " $@ >> $DUMMY_LOG echo "pwd: " `pwd` >> $DUMMY_LOG echo "output: " $REPORT_DIR >> $DUMMY_LOG echo "nodes :" $CLUSTER_NODES >> $DUMMY_LOG echo "n_nodes: " $CLUSTER_N_NODES >> $DUMMY_LOG plan_tests 7 ok 0 "first" okx test 1 -eq 1 is 1 1 "third" isnt 1 2 "fourth" skip ok "maybe not ok but skip" TODO="not implemented yet" ok 0 "test not implemented yet" unset TODO diag "some message" ok 0 "final"percona-galera-3-3.8-3390/tests/tap/000077500000000000000000000000001244131713600167305ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/tap/README000066400000000000000000000002771244131713600176160ustar00rootroot00000000000000 Required packages to run run_test_set.pl - TAP::Parser perl module + + Ubuntu package: libtap-parser-perl + CentOS: ? + Directly from CPAN: http://search.cpan.org/dist/TAP-Parser/percona-galera-3-3.8-3390/tests/tap/run_test_set.pl000077500000000000000000000064741244131713600220210ustar00rootroot00000000000000#!/usr/bin/perl -w # # Initially shamelessly stolen from # http://testanything.org/wiki/index.php/TAP::Parser_Cookbook # # Name: run_test_set.pl # Purpose: A test scheduler and runner # # Usage: # # run_test_set.pl [-q|-v] []* [" [test args]"]* # # Options: # -q Quiet mode (default) # -v Verbose mode, prints report output also to STDOUT # use strict; use warnings; use POSIX qw/strftime/; use TAP::Parser qw/all/; use TAP::Parser::Aggregator qw/all/; sub usage { printf STDERR "Usage: $0 \n"; } my $out_file; my $quiet = 1; sub printlog { if ($quiet == 0) { print @_; } printf $out_file @_; } sub read_tests { my @res = (); my $file = shift; open IN, "<", $file or die "Could not open file " . $file . ": " . $! . "\n"; while () { my $line; chomp($line = $_); unless ($line =~ /^#/) { push @res, $line; } } close IN; return @res; } # Find out if script is run from correct working directory my $cwd; chomp($cwd = `pwd`); my $self = $cwd . "/scripts/run_test_set.pl"; die "run_test_set.pl must be run from test root" unless system(("test", "-f", $self)) == 0; # Export some helpful environment variables # Count number of nodes for test scripts my @nvec = split(' ', $ENV{CLUSTER_NODES}); $ENV{CLUSTER_N_NODES} = scalar(@nvec); # Report directory and test result log definitions # Report dir is r/yymmdd.i where yy is year, mm month, dd day and # i running index, starting from 0. my $fmt_str = "%y%m%d"; my $i = 0; my $report_dir = $cwd . "/r/" . strftime($fmt_str, localtime); while (-d $report_dir . "." . $i) { $i++; } $report_dir = $report_dir . "." . $i; mkdir($report_dir, 0777) or die "Could not create report dir " . $report_dir . ": " . $! . "\n"; my $result_log = $report_dir . "/result.log"; # Open result log open $out_file, ">>", $result_log or die "Cannot open outfile. $!\n"; printlog sprintf("\n---\nReport %s\n---\n", strftime("%y%m%d-%H:%M", localtime)); # Scan given arguments for test definitions my @args = @ARGV; while ($args[0] =~ /^-(\w)/) { my $opt = $1; # print $opt . "\n"; if ($opt eq "q") { $quiet = 1; } elsif ($opt eq "v") { $quiet = 0; } else { usage; die $0 . ": Unknown option: -" . $opt . "\n"; } shift @args; } my @tests = (); if (scalar(@args) == 0) { printlog "No tests to be run\n"; exit 0; } foreach my $arg (@args) { if ($arg =~ /.conf/) { push @tests, read_tests($arg); } else { push(@tests, $arg); } } foreach my $test (@tests) { printlog "\n---\nRunning test: " . $test . "\n---\n"; my @line = split(' ', $test); my $file = $line[0]; shift(@line); $ENV{TEST_REPORT_DIR} = $report_dir; my $parser = TAP::Parser->new( { source => $file, test_args => \@line } ); while ( my $result = $parser->next ) { printlog $result->as_string . "\n"; } my $aggregate = TAP::Parser::Aggregator->new; $aggregate->add( 'testcases', $parser ); printlog sprintf("\nPassed: %s\nFailed: %s\n", scalar $aggregate->passed, scalar $aggregate->failed); } percona-galera-3-3.8-3390/tests/tap/tap-functions000077500000000000000000000165211244131713600214550ustar00rootroot00000000000000#!/bin/bash # # Taken from: http://svn.solucorp.qc.ca/repos/solucorp/JTap/ # _version='1.01' _plan_set=0 _no_plan=0 _skip_all=0 _test_died=0 _expected_tests=0 _executed_tests=0 _failed_tests=0 TODO= usage(){ cat <<'USAGE' tap-functions: A TAP-producing BASH library PLAN: plan_no_plan plan_skip_all [REASON] plan_tests NB_TESTS TEST: ok RESULT [NAME] okx COMMAND is RESULT EXPECTED [NAME] isnt RESULT EXPECTED [NAME] like RESULT PATTERN [NAME] unlike RESULT PATTERN [NAME] pass [NAME] fail [NAME] SKIP: skip [CONDITION] [REASON] [NB_TESTS=1] skip $feature_not_present "feature not present" 2 || { is $a "a" is $b "b" } TODO: Specify TODO mode by setting $TODO: TODO="not implemented yet" ok $result "some not implemented test" unset TODO OTHER: diag MSG EXAMPLE: #!/bin/bash . tap-functions plan_tests 7 me=$USER is $USER $me "I am myself" like $HOME $me "My home is mine" like "`id`" $me "My id matches myself" /bin/ls $HOME 1>&2 ok $? "/bin/ls $HOME" # Same thing using okx shortcut okx /bin/ls $HOME [[ "`id -u`" != "0" ]] i_am_not_root=$? skip $i_am_not_root "Must be root" || { okx ls /root } TODO="figure out how to become root..." okx [ "$HOME" == "/root" ] unset TODO USAGE exit } # # Commented out option parsing, it messes things if commandline switches # are given for the script that sources this file # #opt= #set_u= #while getopts ":sx" opt ; do # case $_opt in # u) set_u=1 ;; # *) usage ;; # esac #done #shift $(( OPTIND - 1 )) # Don't allow uninitialized variables if requested #[[ -n "$set_u" ]] && set -u #unset opt set_u # Used to call _cleanup on shell exit trap _exit EXIT plan_no_plan(){ (( _plan_set != 0 )) && "You tried to plan twice!" _plan_set=1 _no_plan=1 return 0 } plan_skip_all(){ local reason=${1:-''} (( _plan_set != 0 )) && _die "You tried to plan twice!" _print_plan 0 "Skip $reason" _skip_all=1 _plan_set=1 _exit 0 return 0 } plan_tests(){ local tests=${1:?} (( _plan_set != 0 )) && _die "You tried to plan twice!" (( tests == 0 )) && _die "You said to run 0 tests! You've got to run something." _print_plan $tests _expected_tests=$tests _plan_set=1 return $tests } _print_plan(){ local tests=${1:?} local directive=${2:-''} echo -n "1..$tests" [[ -n "$directive" ]] && echo -n " # $directive" echo } pass(){ local name=$1 ok 0 "$name" } fail(){ local name=$1 ok 1 "$name" } # This is the workhorse method that actually # prints the tests result. ok(){ local result=${1:?} local name=${2:-''} (( _plan_set == 0 )) && _die "You tried to run a test without a plan! Gotta have a plan." _executed_tests=$(( $_executed_tests + 1 )) if [[ -n "$name" ]] ; then if _matches "$name" "^[0-9]+$" ; then diag " You named your test '$name'. You shouldn't use numbers for your test names." diag " Very confusing." fi fi if (( result != 0 )) ; then echo -n "not " _failed_tests=$(( _failed_tests + 1 )) fi echo -n "ok $_executed_tests" if [[ -n "$name" ]] ; then local ename=${name//\#/\\#} echo -n " - $ename" fi if [[ -n "$TODO" ]] ; then echo -n " # TODO $TODO" ; if (( result != 0 )) ; then _failed_tests=$(( _failed_tests - 1 )) fi fi echo if (( result != 0 )) ; then local file='tap-functions' local func= local line= local i=0 local bt=$(caller $i) while _matches "$bt" "tap-functions$" ; do i=$(( $i + 1 )) bt=$(caller $i) done local backtrace= eval $(caller $i | (read line func file ; echo "backtrace=\"$file:$func() at line $line.\"")) local t= [[ -n "$TODO" ]] && t="(TODO) " if [[ -n "$name" ]] ; then diag " Failed ${t}test '$name'" diag " in $backtrace" else diag " Failed ${t}test in $backtrace" fi fi return $result } okx(){ local command="$@" local line= diag "Output of '$command':" $command | while read line ; do diag "$line" done ok ${PIPESTATUS[0]} "$command" } _equals(){ local result=${1:?} local expected=${2:?} if [[ "$result" == "$expected" ]] ; then return 0 else return 1 fi } # Thanks to Aaron Kangas for the patch to allow regexp matching # under bash < 3. _bash_major_version=${BASH_VERSION%%.*} _matches(){ local result=${1:?} local pattern=${2:?} if [[ -z "$result" || -z "$pattern" ]] ; then return 1 else if (( _bash_major_version >= 3 )) ; then [[ "$result" =~ "$pattern" ]] else echo "$result" | egrep -q "$pattern" fi fi } _is_diag(){ local result=${1:?} local expected=${2:?} diag " got: '$result'" diag " expected: '$expected'" } is(){ local result=${1:?} local expected=${2:?} local name=${3:-''} _equals "$result" "$expected" (( $? == 0 )) ok $? "$name" local r=$? (( r != 0 )) && _is_diag "$result" "$expected" return $r } isnt(){ local result=${1:?} local expected=${2:?} local name=${3:-''} _equals "$result" "$expected" (( $? != 0 )) ok $? "$name" local r=$? (( r != 0 )) && _is_diag "$result" "$expected" return $r } like(){ local result=${1:?} local pattern=${2:?} local name=${3:-''} _matches "$result" "$pattern" (( $? == 0 )) ok $? "$name" local r=$? (( r != 0 )) && diag " '$result' doesn't match '$pattern'" return $r } unlike(){ local result=${1:?} local pattern=${2:?} local name=${3:-''} _matches "$result" "$pattern" (( $? != 0 )) ok $? "$name" local r=$? (( r != 0 )) && diag " '$result' matches '$pattern'" return $r } skip(){ local condition=${1:?} local reason=${2:-''} local n=${3:-1} if (( condition == 0 )) ; then local i= for (( i=0 ; i<$n ; i++ )) ; do _executed_tests=$(( _executed_tests + 1 )) echo "ok $_executed_tests # skip: $reason" done return 0 else return fi } diag(){ local msg=${1:?} if [[ -n "$msg" ]] ; then echo "# $msg" fi return 1 } _die(){ local reason=${1:-''} echo "$reason" >&2 _test_died=1 _exit 255 } BAIL_OUT(){ local reason=${1:-''} echo "Bail out! $reason" >&2 _exit 255 } _cleanup(){ local rc=0 if (( _plan_set == 0 )) ; then diag "Looks like your test died before it could output anything." return $rc fi if (( _test_died != 0 )) ; then diag "Looks like your test died just after $_executed_tests." return $rc fi if (( _skip_all == 0 && _no_plan != 0 )) ; then _print_plan $_executed_tests fi local s= if (( _no_plan == 0 && _expected_tests < _executed_tests )) ; then s= ; (( _expected_tests > 1 )) && s=s local extra=$(( _executed_tests - _expected_tests )) diag "Looks like you planned $_expected_tests test$s but ran $extra extra." rc=-1 ; fi if (( _no_plan == 0 && _expected_tests > _executed_tests )) ; then s= ; (( _expected_tests > 1 )) && s=s diag "Looks like you planned $_expected_tests test$s but only ran $_executed_tests." fi if (( _failed_tests > 0 )) ; then s= ; (( _failed_tests > 1 )) && s=s diag "Looks like you failed $_failed_tests test$s of $_executed_tests." fi return $rc } _exit_status(){ if (( _no_plan != 0 || _plan_set == 0 )) ; then return $_failed_tests fi if (( _expected_tests < _executed_tests )) ; then return $(( _executed_tests - _expected_tests )) fi return $(( _failed_tests + ( _expected_tests - _executed_tests ))) } _exit(){ local rc=${1:-''} if [[ -z "$rc" ]] ; then _exit_status rc=$? fi _cleanup local alt_rc=$? (( alt_rc != 0 )) && rc=$alt_rc trap - EXIT exit $rc } percona-galera-3-3.8-3390/tests/test_causal/000077500000000000000000000000001244131713600204535ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_causal/SConstruct000066400000000000000000000004001244131713600224770ustar00rootroot00000000000000Program('causal.cpp', CXXFLAGS='-O2 -std=c++0x', CPPFLAGS='-I../../galerautils/src -I/usr/include/mysql++ -I/usr/include/mysql', LIBS=['mysqlpp', 'boost_program_options', 'galerautils++'], LIBPATH=['../../galerautils/src']) percona-galera-3-3.8-3390/tests/test_causal/causal.cpp000066400000000000000000000273461244131713600224430ustar00rootroot00000000000000// // Copyright (C) 2012 Codership Oy // // // Small utility program to test cluster causality. // // For commandling options, run with --help. // // Build requirements: // * C++11 capable compiler // * gu_utils.hpp from galerautils // * libmysql++ (libmysql++-dev on Ubuntu) // * Boost program options // // Example build command with g++ 4.6: // // g++ -std=c++0x -g -O3 -Wextra -Wall -I../../galerautils/src // -I/usr/include/mysql++ -I/usr/include/mysql causal.cpp // -lboost_program_options -lmysqlpp -L../../galerautils/src -lgalerautils++ // -o causal // #include "gu_utils.hpp" #include "gu_string_utils.hpp" #include #include #include #include #include #include #include #include #include #include namespace po = boost::program_options; namespace causal { // Commandline parsing and configuration class Config { public: Config(int argc, char* argv[]) : db_ ("test"), read_hosts_ (), write_host_ ("localhost"), user_ ("test"), password_ ("testpass"), transactional_(false), duration_ (10), readers_ (1), disable_causal_reads_(false), compact_ (false), write_delay_ (0) { po::options_description other("Other options"); other.add_options() ("help,h", "Show help message") ("dry-run", "Print config and exit"); std::string read_hosts_str("localhost"); po::options_description config("Configuration"); config.add_options() ("db", po::value(&db_), "Database") ("read-host", po::value(&read_hosts_str), "Read host (:)") ("write-host", po::value(&write_host_), "Write host (:)") ("user" , po::value(&user_), "User") ("password", po::value(&password_), "Password") ("transactional", po::value(&transactional_), "Transactional") ("duration", po::value(&duration_), "Test duration in seconds") ("readers", po::value(&readers_), "Number of reader threads") ("disable-causal-reads", "Disable causal reads for reader connections") ("compact", po::value(&compact_), "Print output in one line") ("write-delay", po::value(&write_delay_), "Delay between write operations in milliseconds"); po::options_description opts; opts.add(config).add(other); po::variables_map vm; store(po::command_line_parser(argc, argv).options(opts).run(), vm); notify(vm); if (vm.count("disable-causal-reads")) { disable_causal_reads_ = true; } if (vm.count("help")) { std::cerr << "\nUsage: " << argv[0] << "\n" << opts << std::endl; exit(EXIT_SUCCESS); } if (vm.count("dry-run")) { std::cerr << "Config: " << "db : " << db_ << "\n" << "read-host : " << read_hosts_str << "\n" << "write-host : " << write_host_ << "\n" << "user : " << user_ << "\n" << "password : " << password_ << "\n" << "transactional : " << transactional_ << "\n" << "duration : " << duration_ << "\n" << "readers : " << readers_ << "\n" << "disable-causal-reads: " << disable_causal_reads_ << "\n" << "compact : " << compact_ << std::endl; exit(EXIT_SUCCESS); } read_hosts_ = gu::strsplit(read_hosts_str, ','); } const char* db() const { return db_.c_str(); } const char* read_host(size_t idx) const { return read_hosts_[idx % read_hosts_.size()].c_str(); } const char* write_host() const { return write_host_.c_str(); } const char* user() const { return user_.c_str(); } const char* password() const { return password_.c_str(); } bool transactional() const { return transactional_; } time_t duration() const { return duration_; } size_t readers() const { return readers_; } bool disable_causal_reads() const { return disable_causal_reads_; } bool compact() const { return compact_; } time_t write_delay() const { return write_delay_; } private: std::string db_; std::vector read_hosts_; std::string write_host_; std::string user_; std::string password_; bool transactional_; time_t duration_; size_t readers_; bool disable_causal_reads_; bool compact_; time_t write_delay_; }; // Global state class Global { public: static std::atomic_llong violations_; static std::atomic_llong value_; static std::atomic_llong written_value_; static std::atomic_llong reads_; static std::atomic_llong failures_; }; std::atomic_llong Global::violations_(0); std::atomic_llong Global::value_(0); std::atomic_llong Global::written_value_(0); std::atomic_llong Global::reads_(0); std::atomic_llong Global::failures_(0); // Reader class class Reader { public: Reader(const Config& config, size_t idx) : config_(config), conn_(config_.db(), config_.read_host(idx), config_.user(), config_.password()) { if (config.disable_causal_reads() == false) { (void)conn_.query("SET wsrep_causal_reads=1").execute(); } } ~Reader() { conn_.disconnect(); } Reader(const Reader&) = delete; void operator=(const Reader&) = delete; long long value() { long long ret(-1); if (config_.transactional()) { (void)conn_.query("START TRANSACTION").execute(); } mysqlpp::StoreQueryResult result( conn_.query("SELECT value FROM causal_test").store()); if (result.num_rows()) { ret = gu::from_string(result[0]["value"].c_str()); } else { throw std::runtime_error("select didn't result any value"); } if (config_.transactional()) { (void)conn_.query("COMMIT").execute(); } return ret; } private: const Config& config_; mysqlpp::Connection conn_; }; // Writer class class Writer { public: Writer(const Config& config) : config_(config), conn_(config_.db(), config_.write_host(), config_.user(), config_.password()) { } ~Writer() { conn_.disconnect(); } Writer(const Writer&) = delete; void operator=(const Writer&) = delete; void store_value(long long val) { std::ostringstream os; os << "UPDATE causal_test SET value = " << val; mysqlpp::Query query(conn_.query(os.str())); mysqlpp::SimpleResult result(query.execute()); if (!result) { throw std::runtime_error("failed to store value"); } } private: const Config& config_; mysqlpp::Connection conn_; }; void init(const char* db, const char* server, const char* user, const char* password) { mysqlpp::Connection conn(db, server, user, password); (void)conn.query("DROP TABLE IF EXISTS causal_test").execute(); (void)conn.query( "CREATE TABLE causal_test (value BIGINT PRIMARY KEY)") .execute(); std::ostringstream os; os << "INSERT INTO causal_test VALUES (" << Global::value_.fetch_add(1LL) << ")"; (void)conn.query(os.str()).execute(); conn.disconnect(); } } void writer_func(std::shared_ptr w, const causal::Config& config) { std::chrono::system_clock::time_point until( std::chrono::system_clock::now() + std::chrono::seconds(config.duration())); while (std::chrono::system_clock::now() < until) { long long val(causal::Global::value_.load()); w->store_value(val); causal::Global::written_value_.store(val); ++causal::Global::value_; std::this_thread::sleep_for(std::chrono::milliseconds(config.write_delay())); } } void reader_func(std::shared_ptr r, const causal::Config& config) { std::chrono::system_clock::time_point until( std::chrono::system_clock::now() + std::chrono::seconds(config.duration())); try { while (std::chrono::system_clock::now() < until) { long long expected(causal::Global::written_value_.load()); long long val(r->value()); if (val < expected) { ++causal::Global::violations_; } ++causal::Global::reads_; } } catch (...) { std::cerr << "reader failed" << std::endl; ++causal::Global::failures_; } } int main(int argc, char* argv[]) { causal::Config config(argc, argv); causal::init(config.db(), config.write_host(), config.user(), config.password()); std::thread writer_thd( std::bind( writer_func, std::shared_ptr(new causal::Writer(config)), config)); std::list reader_thds; for (size_t i(0); i < config.readers(); ++i) { reader_thds.push_back( std::thread( std::bind( reader_func, std::shared_ptr( new causal::Reader(config, i)), config))); } writer_thd.join(); std::for_each(reader_thds.begin(), reader_thds.end(), [](std::thread& thd) { thd.join(); }); long long reads(causal::Global::reads_.load()); long long violations(causal::Global::violations_.load()); if (config.compact() == true) { std::cout << "Reads " << reads << " Violations " << violations << " Writes " << causal::Global::value_.load() << " Failures " << causal::Global::failures_.load() << std::endl; } else { std::cout << "Reads : " << reads << "\n" << "Causal violations: " << violations << "\n" << "Fraction : " << (double)violations/(reads == 0 ? 1 : reads) << std::endl; } exit(EXIT_SUCCESS); } percona-galera-3-3.8-3390/tests/test_causal/causal.sh000077500000000000000000000021001244131713600222530ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf #declare -r SCRIPTS="$DIST_BASE/scripts" #. $SCRIPTS/jobs.sh #. $SCRIPTS/action.sh #. $SCRIPTS/kill.sh #. $SCRIPTS/misc.sh SCHEMA="test" TABLE="causal" USER="test" PSWD="testpass" for i in 0 1 2 do NODE[$i]="-h${NODE_INCOMING_HOST[$i]} -P${NODE_INCOMING_PORT[$i]}" done MYSQL="mysql -u$USER -p$PSWD" DROP_TABLE="DROP TABLE IF EXISTS $SCHEMA.$TABLE;" echo $DROP_TABLE | $MYSQL ${NODE[2]} CREATE_TABLE=\ "CREATE TABLE $SCHEMA.$TABLE (c1 INT AUTO_INCREMENT PRIMARY KEY, c2 INT)" echo $CREATE_TABLE | $MYSQL ${NODE[2]} sleep 1 echo "INSERT INTO $SCHEMA.$TABLE VALUES (1, 0)" | $MYSQL ${NODE[1]} failure=0 for (( i=1; i<=10000; i++ )) do echo "UPDATE $SCHEMA.$TABLE SET c2 = $i WHERE c1 = 1;" \ | $MYSQL ${NODE[1]} echo "SELECT c2 FROM $SCHEMA.$TABLE WHERE c1 = 1;" \ | $MYSQL ${NODE[0]} | grep ^$i >/dev/null || failure=$(( $failure + 1 )) done #[ $failure -ne 0 ] && echo "Causal failures: $failure" exit $failure # percona-galera-3-3.8-3390/tests/test_causal/hard_causal.sh000077500000000000000000000123621244131713600232640ustar00rootroot00000000000000#!/bin/bash -eu # # The purpose of this test is to test correctness of hard causal semantics # as described in trac #688. # # Test outline: # * Start cluster # * Increase suspect timeout for second node in order to generate situation # where second node will still be forming new group after partitioning # while other nodes are already operating in new group # * Run causal test (shell script test doesnt't seem to be enough to # generate causal inconsistency in cluster running in ram and communicating # through loopback interface) # * Isolate second node by setting gmcast.isolate=true # # Test script will run three scenarios: # 1) Verify that causal test generates causal violations with # --disable-causal-reads and no causal violations occur # without --disable-causal-reads # 2) Verify that isolating second node from group generates causal violations # if evs.hard_causal=false # 3) Run test outlined above several times in order to ensure that # causal violations won't happen if evs.hard_causal=true # CAUSAL="$(dirname $0)/causal" if ! test -x $CAUSAL then echo "causal test executable required" exit 1 fi declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh . $SCRIPTS/signal.sh SCHEMA="test" TABLE="hard_causal" USER="test" PSWD="testpass" echo "restart cluster" $SCRIPTS/command.sh restart WRITE_HOST="${NODE_INCOMING_HOST[0]}:${NODE_INCOMING_PORT[0]}" READ_HOST="${NODE_INCOMING_HOST[1]}:${NODE_INCOMING_PORT[1]}" READ_MYSQL_CTRL="mysql -u$USER -p$PSWD -h${NODE_INCOMING_HOST[1]} -P${NODE_INCOMING_PORT[1]}" function causal { $CAUSAL --compact true --write-host $WRITE_HOST --read-host $READ_HOST --db $SCHEMA --readers 8 $@ 2>$BASE_RUN/hard_causal.err } function wait_prim_synced { cnt=100 while test $cnt -gt 0 do status=`$READ_MYSQL_CTRL -ss -e "show status like 'wsrep_cluster_status'" | awk '{ print $2; }'` state=`$READ_MYSQL_CTRL -ss -e "show status like 'wsrep_local_state'" | awk '{ print $2; }'` if test "$status" = "Primary" && test "$state" = "4" then return fi sleep 1 cnt=$(($cnt - 1)) done if test $cnt = 0 then echo "failed to reach prim synced in 100 seconds" exit 1 fi } # # Stage 1 # echo "stage 1: check that causal violations can be produced" str=`causal --disable-causal-reads --duration 10` echo "causal: $str" if test `echo $str | awk '{print $4; }'` == 0 then echo "causal test failed to produce attempted causal violations" echo "output: $str" exit 1 fi echo "stage 1: check that causal violations are not produced if not attempted" str=`causal --duration 10` echo "causal: $str" if test `echo $str | awk '{ print $4 }'` != 0 then echo "causal violations" echo "causal: $str" exit 1 fi # # Stage 2 # echo "stage 2: check that causal violations are generated in view change if evs.causal_keepalive_period is high enough" $READ_MYSQL_CTRL -e "set global wsrep_provider_options='evs.causal_keepalive_period=PT100S'" round=10 violations=0 while test $round -gt 0 && test $violations == 0 do $READ_MYSQL_CTRL -e "set global wsrep_provider_options='evs.suspect_timeout=PT9S; evs.keepalive_period=PT100S'" echo "round $round" f=`mktemp` ( causal --duration 15 > $f ) & pid=$! echo "started causal with pid $pid" sleep 1 echo "isolating second node" $READ_MYSQL_CTRL -e "set global wsrep_provider_options='gmcast.isolate=true'" echo "waiting for causal test to finish" wait $pid str=`cat $f` rm $f echo "causal: $str" violations=`echo $str | awk '{ print $4; }'` $READ_MYSQL_CTRL -e "set global wsrep_provider_options='gmcast.isolate=false'" wait_prim_synced round=$(($round - 1)) done # if test $violations == 0 then echo "stage 2 failed to generate violations" exit 1 fi # # Stage 3 # echo "stage 3: check that causal violations don't happen if evs.causal_keepalive_period is short enough" $READ_MYSQL_CTRL -e "set global wsrep_provider_options='evs.causal_keepalive_period=PT0.5S'" round=1000 violations=0 echo "running $round rounds, reader is isolated" while test $round -gt 0 && test $violations == 0 do $READ_MYSQL_CTRL -e "set global wsrep_provider_options='evs.suspect_timeout=PT9S; evs.keepalive_period=PT100S'" echo "round: $round" f=`mktemp` ( causal --duration 15 > $f ) & pid=$! echo "started causal with pid $pid" sleep 1 if test $(($round % 2)) == 0 then echo "isolating second node" $READ_MYSQL_CTRL -e "set global wsrep_provider_options='gmcast.isolate=true'" sleep 9 $READ_MYSQL_CTRL -e "set global wsrep_provider_options='gmcast.isolate=false'" else echo "signalling node 1 to stop" signal_node STOP 1 sleep 9 signal_node CONT 1 fi echo "waiting for causal test to finish" wait $pid str=`cat $f` rm $f echo "output: $str" violations=`echo $str | awk '{ print $4; }'` wait_prim_synced round=$(($round - 1)) done if test $violations != 0 then echo "stage 3 generated violations" exit 1 fipercona-galera-3-3.8-3390/tests/test_cppcheck/000077500000000000000000000000001244131713600207635ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_cppcheck/run.sh000077500000000000000000000010401244131713600221210ustar00rootroot00000000000000#!/bin/sh -eu OS=$(uname) [ $OS = "Linux" ] && JOBS=$(grep -c ^processor /proc/cpuinfo) || JOBS=1 TEST_ROOT=$(cd $(dirname $0); pwd -P) GALERA_SRC=$TEST_ROOT/../../ LOGFILE=cppcheck.log # --xml output provides us with error ID in case we need to add suppression cppcheck --quiet -j $JOBS --force --inline-suppr --xml --inconclusive \ $GALERA_SRC 2>$LOGFILE RCODE=$(grep -c '^ $GALERA_RESULT_DIR/out exit 1 percona-galera-3-3.8-3390/tests/test_dots/000077500000000000000000000000001244131713600201545ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_dots/run.sh000066400000000000000000000001021244131713600213050ustar00rootroot00000000000000#!/bin/sh echo "Not implemented" > $GALERA_RESULT_DIR/out exit 1 percona-galera-3-3.8-3390/tests/test_drupal/000077500000000000000000000000001244131713600204725ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_drupal/README000066400000000000000000000070031244131713600213520ustar00rootroot00000000000000FILES IN THIS DIRECTORY: Drupal 5 files (obsolete): drupaldb.sql.gz -- dump of drupal 5 MySQL database drupal.jmx -- jmeter configuration file drupal5.diff -- patch to make drupal replay transactions Drupal 6 files: drupal6.10.tgz -- Drupal 6 installation configured for drupal:password login. Unpack it into webserver root (/var/www) drupal6.sql.gz -- dump of drupal 6 MySQL database drupal6_8080.jmx -- jmeter test file for drupal6, verified to work with 127.0.0.1:8080 address drupal6.jmx -- attempt to make universal test file out of drupal6_8080.jmx work in progress loaddb.sh -- script to create drupal databases and grant permissions. SETTING UP THE NODES: First, running the test requires nodes to be set up: Drupal installed and Apache configured. This script cannot do it automatically. How to do it is described below. It needs to be done only once. Second, the address of Drupal site is hardcoded into the Jmeter test script: http://127.0.0.8080/drupal6. This requires glbd be listening on the client host at port 8080, and Drupal files be installed under /drupal6 (e.g. /var/www/drupal6 on Ubuntu) 1. Install Drupal 6 in each cluster node so that it can be found at http://
/drupal6 path. Configure it to use user 'drupal' and password 'password' to connect to 'drupal6' database. For that edit $db_url setting in sites/default/settings.php Alternatively you can just unpack the provided drupal6.10.tgz package in the webserver root directory and grant webserver rw permissions to it 2. Fix Apache to use clean URLs by adding the following to Apache config (in Ubuntu it is normally /etc/apache2/sites-enabled/000-default): Options -Indexes FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all RUNNING THE TEST: 1. Initialize drupal database by running loaddb.sh. See the script for the configuration options. Galera distribution does not come prepared with Drupal user privileges, and currently does not support GRANT command replication. That means that GRANT command must be manually repeated on every node to create drupal user privileges. Alternatively you can run loaddb.sh against each node in turn. After that you need to run it olny one when you want to reset the test. 2. After database initialization, Drupal needs yet another action to run properly: You need to login to your Drupal site as root:rootpass, say, using links, and then go to the following link: Administration->Reports->Status Report->run manually (cron jobs) Without doing that, some of the pages for some reason become inaccessible (no idea why) and you'll get false error positives. This procedure needs to be performed every time drupal databse is reloaded. I don't know how to fix that or how to make it automatic. 3. Start glbd on a client machine like that: ./glbd -t 2 8080 node1:80 node2:80 node3:80 4. Start jmeter: $ jmeter --testfile drupal6_8080.jmx Hit Ctrl-R to start the test. NOTE1: During the first few runs it will stop with error about unable to find requested JavaScript file. But after 2-3 runs this file will mysteriously appear on all cluster nodes and it won't be a problem after that. One solution would be to keep Drupal files directory on a shared disk. NOTE2: It is essential to run jmeter in GUI mode to be able to catch and analyze errors. percona-galera-3-3.8-3390/tests/test_drupal/drupal.jmx000066400000000000000000004451271244131713600225160ustar00rootroot00000000000000 false false 127.0.0.1 true 1000 300.0 false -1 10 10 1233463594000 1233463594000 true stopthread 600 0 true rfc2109 1000 300.0 http /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_id user_login_block = http /drupal/node?destination=node POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/comment/reply/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject malo sexa = true true comment titek net! = true false form_token ${form_token} = true false form_id comment_form = true true op Preview comment = true http utf-8 /drupal/comment/reply/2 POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/comment/reply/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject malo sexa = true true comment titek net! = true false form_token ${form_token} = true false form_id comment_form = true true op Post comment = true http utf-8 /drupal/comment/reply/2 POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/comment/reply/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/comment/reply/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/logout GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 20 20 1233457549000 1233457549000 true stopthread 600 0 false rfc2109 300 false name test = true false pass testpass = true false op Log+in = true false form_id user_login_block = true http /drupal/node?destination=node POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/user/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/add GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/user/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/add/story GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/logout GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 5 5 1233457451000 1233457451000 true continue 600 0 continue after errors - trying to access forbidden location - it's ok false rfc2109 300 100.0 http utf-8 /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_id user_login_block = http /drupal/node?destination=node POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/add GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/add/page GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true title test page = true false changed = true true body test content = true false form_token cc69ea143915e2247edd27d40223a3af = false form_id page_node_form = false op Submit = false = true http utf-8 /drupal/node/add/page POST true false true false true false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add/page Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/node/1 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add/page Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/1 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal/user/2 GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/node/add GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/user/2 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 http /drupal/logout GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal/ GET true false true false true false Accept-Language en-us,en;q=0.7,ru;q=0.3 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2008121621 Ubuntu/8.04 (hardy) Firefox/3.0.5 Referer http://127.0.0.1/drupal/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true percona-galera-3-3.8-3390/tests/test_drupal/drupal5.diff000066400000000000000000000154011244131713600227010ustar00rootroot00000000000000Index: includes/database.mysql.inc =================================================================== --- includes/database.mysql.inc (revision 5) +++ includes/database.mysql.inc (revision 8) @@ -167,11 +167,13 @@ print '

query: '. $query .'
error:'. mysql_error($active_db) .'

'; } - if (!mysql_errno($active_db)) { + $my_err = mysql_errno($active_db); + if (!$my_err) { return $result; } else { - trigger_error(check_plain(mysql_error($active_db) ."\nquery: ". $query), E_USER_WARNING); + if ($my_err != 1213) // don't warn on deadlock + trigger_error(check_plain(mysql_error($active_db) ."\nquery: ". $query), E_USER_WARNING); return FALSE; } } @@ -261,11 +263,21 @@ * with table prefixes. For example, db_next_id('{node}_nid'); */ function db_next_id($name) { + global $active_db; $name = db_prefix_tables($name); + db_query('LOCK TABLES {sequences} WRITE'); - $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1; - db_query("REPLACE INTO {sequences} VALUES ('%s', %d)", $name, $id); - db_query('UNLOCK TABLES'); + do { + $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s' FOR UPDATE", $name)) + 1; + if (mysql_errno($active_db)) continue; + if ($id > 1) { // exitsting row + db_query("UPDATE {sequences} SET id = %d WHERE name = '%s'", $id, $name); + } else { // new row + db_query("INSERT INTO {sequences} VALUES ('%s', %d)", $name, $id); + } + if (mysql_errno($active_db)) continue; + db_query('UNLOCK TABLES'); + } while (mysql_errno($active_db) == 1213); // ER_LOCK_DEADLOCK return $id; } Index: includes/bootstrap.inc =================================================================== --- includes/bootstrap.inc (revision 5) +++ includes/bootstrap.inc (revision 8) @@ -466,9 +466,13 @@ global $conf; db_lock_table('variable'); - db_query("DELETE FROM {variable} WHERE name = '%s'", $name); - db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, serialize($value)); - db_unlock_tables(); + do { + db_query("DELETE FROM {variable} WHERE name = '%s'", $name); + if (db_error()) continue; + db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", $name, serialize($value)); + if (db_error()) continue; + db_unlock_tables(); + } while (db_error() == 1213); cache_clear_all('variables', 'cache'); Index: includes/database.mysqli.inc =================================================================== --- includes/database.mysqli.inc (revision 5) +++ includes/database.mysqli.inc (revision 8) @@ -149,11 +149,13 @@ print '

query: '. $query .'
error:'. mysqli_error($active_db) .'

'; } - if (!mysqli_errno($active_db)) { + $my_err = mysqli_errno($active_db); + if (!$my_err) { return $result; } else { - trigger_error(check_plain(mysqli_error($active_db) ."\nquery: ". $query), E_USER_WARNING); + if ($my_err != 1213) + trigger_error(check_plain(mysqli_error($active_db) ."\nquery: ". $query), E_USER_WARNING); return FALSE; } } @@ -244,11 +246,21 @@ * with table prefixes. For example, db_next_id('{node}_nid'); */ function db_next_id($name) { + global $active_db; $name = db_prefix_tables($name); + db_query('LOCK TABLES {sequences} WRITE'); - $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s'", $name)) + 1; - db_query("REPLACE INTO {sequences} VALUES ('%s', %d)", $name, $id); - db_query('UNLOCK TABLES'); + do { + $id = db_result(db_query("SELECT id FROM {sequences} WHERE name = '%s' FOR UPDATE", $name)) + 1; + if (mysqli_errno($active_db)) continue; + if ($id > 1) { // exitsting row + db_query("UPDATE {sequences} SET id = %d WHERE name = '%s'", $id, $name); + } else { // new row + db_query("INSERT INTO {sequences} VALUES ('%s', %d)", $name, $id); + } + if (mysqli_errno($active_db)) continue; + db_query('UNLOCK TABLES'); + } while (mysqli_errno($active_db) == 1213); // ER_LOCK_DEADLOCK return $id; } Index: includes/cache.inc =================================================================== --- includes/cache.inc (revision 5) +++ includes/cache.inc (revision 8) @@ -93,11 +93,15 @@ */ function cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $headers = NULL) { db_lock_table($table); - db_query("UPDATE {". $table. "} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid); - if (!db_affected_rows()) { - @db_query("INSERT INTO {". $table. "} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $cid, $data, time(), $expire, $headers); - } - db_unlock_tables(); + do { + db_query("UPDATE {". $table. "} SET data = %b, created = %d, expire = %d, headers = '%s' WHERE cid = '%s'", $data, time(), $expire, $headers, $cid); + if (db_error()) continue; + if (!db_affected_rows()) { + @db_query("INSERT INTO {". $table. "} (cid, data, created, expire, headers) VALUES ('%s', %b, %d, %d, '%s')", $cid, $data, time(), $expire, $headers); + } + if (db_error()) continue; + db_unlock_tables(); + } while (db_error() == 1213); // deadlock } /** Index: modules/block/block.module =================================================================== --- modules/block/block.module (revision 5) +++ modules/block/block.module (revision 8) @@ -188,14 +188,19 @@ } db_lock_table('blocks'); - // Remove all blocks from table. - db_query("DELETE FROM {blocks} WHERE theme = '%s'", $theme_key); + do { + // Remove all blocks from table. + db_query("DELETE FROM {blocks} WHERE theme = '%s'", $theme_key); + if (db_error()) continue; - // Reinsert new set of blocks into table. - foreach ($blocks as $block) { - db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, title) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, '%s')", $block['module'], $block['delta'], $theme_key, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['title']); - } - db_unlock_tables(); + // Reinsert new set of blocks into table. + foreach ($blocks as $block) { + db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, title) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, '%s')", $block['module'], $block['delta'], $theme_key, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['title']); + if (db_error()) break; + } + if (db_error()) continue; + db_unlock_tables(); + } while (db_error() == 1213); // replay on deadlock return $blocks; } percona-galera-3-3.8-3390/tests/test_drupal/drupal6.10.tgz000066400000000000000000051663751244131713600230430ustar00rootroot00000000000000‹M¸Iì<ûsâFšó3EŸ3µØ9,Œíd&É.3ff¨óØ^°“KeS.ÐZHŠÆä*ÿû}¯nµ0ØÉn’Ý« 5)ƒÔýõ×ßûÑ +S?:i¿ø ?ð9=>¦¿ÝNý/^t:ãÎÑQçäôðÅAç°{rôBÿ–H™O™~¦Ô‹år¹ø…¿mÜsïÿ~áš%Ó0Òùo!¿œÿÝ£ƒ“?øÿ{|ñ?ÐS¿ŒŠ_S~9ÿOÿàÿïñÙÊùëÉ‹f dðI·»…ÿîÁQçEçàô¨Ó=9=:9yqpâÒ}¡~­M>õùÎÿ/þœÎÓF»­^‚Wjé­{ÕñÕ!èo»sØîœªÎá«îÑ«£®š%c_õRõ²ÑhúiC}ª†º(³Xùð/Ëü•J¦ª˜kµH‚$K‰k¥cé@-ç:†×a®d1_øÁkà!È¿d¿*Õs;@"Îh7¦e<)Â$6;¹à·2~wOýOC©L0Eh»ÍI%Y³¥àËb¡ã¿Îu”â_ø]âßÂHâd±ÂïÁ8JfͽןmÖÍ'Y˜²³¿i’Ñï0‹ÐÌf} ³´ŽŸÞö2,æêN¯rÕŒý…n¥À¦Z±)ËÃxV£m‹!áø„FÂòÍÈg¥?8@Ää^gYhÂмQ¹Ž4ÓgæÝ~žêI8 'füºðÃh#à·2{úò+Õ<#£ÔlñóÚñõˆ°ª ••' ­Æ~˜1ePò£°Xp“‚~_h¯ kmæhæ±ÒÏï@ÞæþÚÊy™¦IVä›y‡üi¯B Tb± £H¥: /TPfÀ;ž‹ƒ¦!² äd¦=u ˆý"XF*`>(V™Ã:a\è ¦D+aùrNÔÑ÷~T‚˜áA˜§‘¸éð=ÌÏ`¾ˆ(ë¡ð‘&:<Ãbw‹ãˆÉ-¯dw~¼’ÕdŸiÂêQÖÐóÚÅÌ*ý‹ªÚÿJEÉÄ·<Ëôe˜iÔî£%ÑøÝ@EöÇ~1™Ë<%*˯ðù$‰§á¬Ì´3Àû00žÕ À~Ã|dÆU“Xón[LiØm’:ƒŸSµJJÑ,T¸H#ÂaÐ(Kr˜ã²u" ¦ëãò ŠZ|–yîßkâC\.Æ@ÏdŠÓ'à“…ÎÄŠ£?qB»(»ëg¡¢ñQ4 þdÂöæ:#m\úÑ]%WÇ’\Hà©waªU„ ¶Oõ Ì4pjB΀ ßK’Â\½)û„PŸaw´ t=Á½O…i™™lk¼ÂÉ„6ƒ‚DJzÝÄù`ÿ`_ÓPgÀ Ò'?-#½í˜'ÉÝ&™Gþ,©§¾r/€¨Ê¿OB¶7™BÜ£¾:8…–fÑ»5c*˜J‹¬³Tg”]~m é8ÐÐðÖ`ßWêÃõõé‚ÔvQãͶ3ÑyÔiÁ÷ÙKk…1Žq½TN4ÏÁiÄ{ª„¡B@4âã– —ö4 å3L(“°nŽ AΊ,óäOî «úžêƒˆ™­§èžd®ø’X뀥7KîÑ•ù „+|€pøÔ-0Ö™j7ž—ãEG‘¹ï˜ù<)#vŠbç®\„…x<„ጓˆZ@^TGM¹ê̯*üIŸê¡Ó9·MÚZ¸”“úÁòKU¦FDëN+Y³êÆÖƒrOý‰5"C@ŠŒ‚89Ñ]ã1È»53%>Ë4Ò"AжD‚Ú Ê““n©E8›À…˜” ÊBt /\·fZ”ˆ\HÑ\+WBŒj»b &”›ŠbÉr ñI„öÔH˜Y¹]AJü H™/Ò¨µ'~Í^߃QšŸd:w2)(vz×;õÙm€y¤ÓÈKk³ IZA’¡É7²X'I ât—П9â‰ði¿ì³kÖ 6¨Yꌭ&…E@¼-\%l’(Ö∡!ï ë…Óº•†6@©W…‚*iüíƒ!18ç†,c4p‹í[™Kc7è–kXD‹ u«•Hçà›m@•ú™¿¨x«($˜”Y†*Ķ\""Ù•ÊW`\žú“ŒG ”³”)”’)ù ¶“-6£ðϺÏE Ì"ž÷6A"ZÝ Ï%­!o1µD‰i5"€ìs ˆDg ²l¬XùWÈ|08èrå:Ëu2›Î>‰ÇÛrè¸þx~:’wÂ>O]Æ ·ANYU˜d…Ó {Ɇ;A‘[†9Åb—àgÄ„ùîŸd>ÒcCˆ¶!çİxa#qDeŸ h bÔb•jÔdÁÕDm:¥'†flžy+ Cùì\h›2=e²"ÈjHïjÀp‚dR¢uf—çƒìÏ‹"}Õnûièq½ÄK²þlè÷ÎÚfïm’4„x‹Nd£|é&:ÎWÈnp§5(’ó¸ÙØúæ¾Ú³ï8™åY¸\5k=W‚É;=õ…^|…пhÃ0<áDÁ>É(ÊñÌV2(D'™“«R q‹7>‡~`D”ð§%û3¶p–gFÁxÞXým§7NJä÷ßvÀžNL² þZó°þ¾Y©h nÈó °@&qRˆºÜ‡0ñãžC”GLe^ãq‰fnóð9&ŒÞÛ©H̺J4¼Þô]Òc€<~YÀq7ø rÚqFÁn­º60)oŒ?ùNœ}ëG r_‰kzhßë%3 ’ Y•Û¯E½d¬°\FÁ(6U ÄÂø>™Ð JX^ÒêTÐ0ž#MÒ2B˱%ÈqðýMo¹PÌ0`UÐj×ktÚ]Õ9yÕ9~uüY­ëÇSïûæÓh\eaBÉU™Î2? Â̪*é8Ç¢9ƯR:Ë$]w5_ &TË“>„rP-ÊE½ŒïSña‰)ÚBIÒœÍí™:À©ÄX¦”u@ˆHE& 6ï±*DÕ¦ÝO:ä‚Ô[v¶úDid`o¬u ©ŽÆØ‹aÈLÁKˆ°žF^ö—²»ð¬òmTÂÀ26Ùd²^£q®  ãXÏÂø?ާÔ¦€­¯Q;“®¸ VûJS³"^¿ƒÎ%ß!Tã‚.îËÏ&•êºcFïMqQ84„'ŠÉТþ„KžÄV¼Í ÓÙ‘;’>qWFPorg;šeŠåL¤551±âNUþMÀˆÊss¼àä³Þ¼ð'XƒD,³dœ€¬¡I«Ã–ÇJVÈRœ¹ÔQä5èù„´¯¤|„Õ³ˆÃ,6–iëq]O™†9¾Ù1Ñ™—ÎSæ ½Æ¶EÊ«Žv¸ã¹«h"P÷ !h–T¾š@>Ò™¤+Â’4 )£”–ä1È>ˆsDõÙ–k¨JL»ªm%j{f ÀnŸåEVN0ãR”êqqDÀúUCòší»­ 0µNЯíƒòrìý#=PÙy}4 ÿˆ%P7€[(³F€ÁÅèºw~ŽÂT= IŠç!„ï-9£*cîî!Û¥oƒ3Õi‰à‹ÔpáDS?f³$ɦAŽÝLPT´½@v«+2ÜS7êzw€•¯–#‹z””2d\0ø©ú¤s@ò‡UaøOŒ U7‘Í(Ïo¥8¾ŒMK¢Ú¼Ý®)Åð“õm«`Ù¶@°oUë±Ã@SS¯"¢mž˜ì\N§ûQë4 šJ¶‘.jJÙl®²2&6@z$;\ìka úÜtJ%ð:Éä\K@Û±ý~.aZC°8¡¥šDa¼D)5qýó_­$¶)]BÖ:Æ^ÚÍtJ]›Ï"$mÀªä ž$HH<(¡Òˆ;¸¥F—å’zUÉ›¼Øš» бOŽ–?¡r.…üNÌë{?‹èØJ¦Þ@æ²€t5FÞÃ:gœð“Ÿ<é¥a LR‡‚Æ'‘|)U±sÀ²Ñ4Ãf[ü`í¨‚õ"ñ ÞÄ)õ*±’¬—[ Úúõs?ó°·Š“­œ…ñaX\omx‘³KTÎMB.Fx“/#0•?o•i¡rø#öJ2ȺÉb˜C^•w4/ ¹!¦ç"ȼ*Ëþæ` öáßéØÑv Éç@’¯ufÚHä ®°€¹Š‚K걡"g¸ízM¢gJéX£ñŠëŽˆÍ5rFU¡mW— ¬Þª5•JӾɢ–U…ÔÂZ–‚Ûn¦}ôذT-¬Øh1å ÙâN÷Õeª%ÞªRM-4ˆ‡°pëUsجS!âŽ8Æ!þ*W/yÑÛi¦õ­àáT¤øó–úÈK@vó ¬{¾v㮓Éé¼ §tƒ{lJ7:&DÃ5CJEÂ9ª~ó)”§otÀíô«‡Ï]9Âÿ¼¥9Æ#F0‘ˤ­1''82e”Ó[ø‡¿üÐR Ñ´{ãÄ{hÙEéEšéû0)ó c’D)¼š,DH…è˺kã©\‹þ;ïÖ\€¬ÜâLgCò–f V“Û2ÐòÇœ¢4ä ¾bÚÙƒ+Î&á::µ” Ú}ä~Œ ï³]9µÈ8élåì‰%˜fUëÖô­;4IË õ¾_|F<øÁ~V3aÆ…ŠÑØbÍ„àÊGž9çh#œuÑ'¬vň°Ëæì°«ÄCò»²é]{¦I*šáäÜ?,ÔìûÚÚïY¶?Ê»ŸB÷´ 2 þ!4h<'¼…†H ‹O]þxÔÏ¿.žÄã3£æ(UÅXlç2®Â]9Ù“ÙVµÙ ,ºŠ¯žêåÛäl…³Ú.½ÉåTƒŽ® ?4çÍþ}\Je7$q¶ÞÅ”i8ñ¾'ɳoq¢þÜMý×É.õ5ž®ÿtN^t:GLJ§ãS®ÿžþQÿý=>¦þëðŸê¿'ïÐëJ ø´}ð¹ê|N5àÏk5à·—×ý‹ë‘º|§®? FêÝà¼_ÕƒÝOƒV%Yü}i)ek/Ž6âoQ¥ua*ªáÖæ’ùÛÍéˆ×G[Yy»~,Ž 1ƒJ‡aÿ¯7ƒa›¼£FsY]Ìù¤Š¢³ºYK]}¸R]µÛõ޼cô^3J‹²=üŽïŽ»Žõ¢[¬‹6~Ô!¥cW£¿ž+wØb•ÿ‘‰c8I^\UÆq(Ú’=.çõ )…?Ž´¯Q•zÁ@‚DMî@¯%1\›d‡ÃÀ1x ÎïLÂ8Žcñ¶ÂΩaCšZ˜Hâ ,º@¦@§1é\ç„UËzÊ®×ñ:Šˆè*, ZNa€9ÑžûSÌ’˜Î óÑJŸºöº cÂIª3>sÃ)=‡ˆÍNÎñ’‚IuåûÁ³m0Â'‡OlçòêzpyÑ;W×½ÑëŠÙŸöýïçûȇ€'N­¿‰’Ù Ðé] ëáh»ˆ©#`%¹Ìi€m× PY’(‚á>¿ý­¨ýÁwÌܳR¶«´ó–ªÙ7Ãó|Çœä¡2büXƒZuLÊT=n3½ÌÐÂHØoª§Îñ\”îˆ8i6¼£BK…‡¹M„h€r ïnHSœQµÀ{¬öocâÑgÇÝ'X¸¯¾!ÂtÏÜ’bäF ª Ö1 rÞšîÀÚIµ(¬ öÜSâ| è JƹḢýr{8hSbä °ªR6Äæ|‹kfw.ç¦2ê±&õ&†äã0 éj¨õ¥tµ9ÚT S,®&qýÞß ãITòE¸l!>CC¶#‡^øÈÐŽaø.gãA²Œ±‘”?¶/¦ŠvMeئ\ß¡Zp¼ªn@nËþ¦M¶×Z—3¬‚¿ïCŸ*6ƒ³ì[ÒuFEü)öV[\âc›îh™dwûL44F]APôPå×ü"VÙ/¿¹8¿ì©³áÍX„ÞÅ™2æáü[ÕS×ÃÞÅHfc,þ­ØídŒM%¹oHÏša:ôÇE‰ÇÂ- 5Í9ŸBqåAçÍ~TLzÎ}a¼pú®aR˜ƒé@K>l—â C.¨$QŽG 9 -V)6.ÔM>Ðá2„… ] 2U±%^¯yŒß¡–´1—7ûÞƒàÇ“1âÜÿñá~ªÀ¤dk¤ÂêS!¨jaVÓÚ¦;GL†F›-}êÅhŸ{{S  F:UeQ-,|ªXûnÏ NH9ÅX•E L‰»Ì*K’5”/¨•ã(œðás ÇPoqïnáS÷Ge"Ûàå0ÈiÏ‹EDå2Ô’ZªÜL8àp/töãYæóê~ ÇtŽ‹â„Sks¡µ»b`³$ à¹g…Õ\,ð¹'SÕ\+‘ãt0µ€hç-U–sMã|#à˜SNîð$ —Å”½yè+hõLÙ^‘\+ n;a˲²”$b¬äaáALOšÒà‚N%RkÎ1vÛèZ¢°JÃ,YŠ„{”o‡ýÞuRƒ¾‚TáÝàýÍ,å d+Þƒy¸Vß 0ìª?ü8àýˆøm äBç¦Ú¼µUm¯Ù¸Ý_fµmÔï’Ré‰=KÈ)ò‡æsáC”ÏT–ì¡L]u/äb3‘Â\=so¨ÙßI÷ áÎ<ÎBÔF÷áC3†”r‘ydN0ÓÕ¢’{=5´œ›‡ÖtºXÇT½óOCñ´jîAA¼´ðï¤s‡}(ÌôÞ5g½5]Z¤ÅJÉeæbÎòƒˆ£À®Ô„gkÕ6|ص*Öò>‡y{\¬sT~ƒ0T/¶àÆòLÒµãA‰/hrZ°Nžã½†V…¢­ã"Dþ‘óE7sðeí†Ù·&Ýà ô_´U!%ØõÿI‚â›4|öaxsAr(U£·ÃÁÕµ¡JÄã™ù„æb·9"šD¨ã%ÃdjI‚òOüÑÞÌkm©‹ ·ì&@¤geø¿ì½`ÕÕ6Œé,1%ô„A’Ù]uÉ ƒ,˶l5´’ ÆÈ«Ý‘4öjgÙÙ•,JB !@B%!”Pâ„@è„ÞL ´ÐC1`j€Cè%ü÷”{çÎì®$Hþïûâ÷ `iæÎ­çžòœçÄ5 ¼áÑ„r±g(É9›òÌCPŸ »§!ˆð40.HOra Ña¼¤ÍFòˆ•Üœ‰À®F3pg<»ža €5ëÓ®h†CJ›#úsQoÔF Úò!WñòËC¸AbÈ8ÎDî¬ä„³’h­âLQ²Ò0_¬INÕÕ7˜úÌ'XBÀ-e¦9ÑÕvq¢Ñ0F¨•70/¼3ú  ¸ ö}ÿ8¡BçHæXúù„»•Q ürÑD¾ ùF¢GƸú؃ØNb{ɵ—ÈÑ‘nZ:':¨<Ä×Aؘc™ÒÃCSﮜ\†ÜÎ äJ`Çs¡íF‹†F¼µGzR7‰P7¢ÎÊ”K)C ¾Ô ìh XcN1ŧ¶/J† M«€8UXPÚÄ­ÂïS¶·Ü&îæ¥Ï’E"aœQÈò̦ÁM‘¶œåâ:L$Žõ㜣+ëyÕ$‚»ž² ŒˆO/à“lqã¸04gY>X¿ éxÛ(ø…€‰È=¦8v„8“&ŒÔ3p‘UÎvv²±yZ†5)LûÀeÝ)Z`&À¾AÜ®›)¨¿‚NRÂÀræ “™ü÷0¤LºYâòPÈDD/f b²àjí¢‹ž“U_(Vî/}Xª3Ø&xQl*±$V ^qO@‹ÐDŠÄQBR3@”„)MÆ‹ù42(~ùÜIÊhcÜHÝÙtBe­i@{°—óƒq~à!«Ï1pÑúò$ä4‰¼åØÇlÝ)³¢N¦avêÆpu£WDlVoN!n×ìÅÀ9„0ÇBË+o._Ø=Y6à $þÿ}?°brmMm);ç75. [9²(ÒÙØbD:Û:êg‹¿6vv6µÎŽ  øçÎ<Ò^ª÷2._-ÑÀ*Ñ ­oäà[®_Oz!óA fÇŒ ðÛº<ÔùYa_J„h²¾—R])ô¬¤’9âã-³`=ýóö Oîìa1À›;#÷pÒ›z B_Ò•øy¤å¥>¾%¸TBÍê•2}¢†œ;Æ¥FÉÒcG‘Bü5‡´1³ Ñ/äLÐ\0)×K¤e냕í¸Ëï°Hsž;J·]4º„N¬ÖÔä ˆ°ÓŠa3Q¾ä¶V£¥¾ `mõ­ Œp[ >ÏKãÉþß·Dçb:E,†`z ôhÄ…”ߨPHÄ,Ê#Ømô29KUðL\ƒ<’P4ˆ4äICB*Ø—Zr#õ£ˆáyr ˜ƒØY³ia˜+„ü‚¡*&E¡ÐFxTÅ™rán¦lt[3KBzdÇÄP 1lDm ±ê³ÈÎ'©A1µÕ"ì z>”¨”RJ6„òœiSB@­y“1ùvêpM6M¢²Õïÿßj3BFè#”1*F›:·O\ÐÁÞø·¼“¨Àn™‰ñJJ‘¡T£b‡í(ˆjì’ÑÈ3Eîà’Å¡÷€øËR³hmÒ¯Ë<‰xË2³¥©µ)ÒÙ‘‹}Ñ@0õx<Ù½d%ù'HÂJŽq¯&†¡1ºy½¢5\LÓ“õ¢EépG~,¸«aÏuqŠ« Ë—›sBh¨P>z4Vì‰Ùfc©ŽUŒPެàj¤Ï¶ð8 +¦(â`ƒO—T?;‰a ïÒ“àÎÁåv͒𽊿7°Øjˆ^™®?\çï2“J%ƒéÜ¡4 @td ·E¤3Â甓“Íkä099ú•§'#@Œ«9§&ß²‹mÑ t !I3áB¹D„%óż§ šëŠt¶µ4ÚÔ:ÛXÔÖÕ¡®–Æ’Hiþ£AÇ£É,£™Ü, Äö’æ©9I%1«Ê55(dcËg@ù€ñ”#Xtε‘0„/Î1H\¥ð¶Ä½˜¤kÜá‰ÑEˆìP~WdUî6“”AO<³ ‘ˆ8BÌÇÊî÷€„Q Y#TïŒèŠÔí…´T0Œ!ÖBÑÝ”ÎhÙBÀêÈ] )þʼ}RXðµ€È…Q‹1µt5w6E[ãßZ/fìÊ—«Œâ‘¥©§‡B){UT ‚¤h¢3ɆÀ£·­xÖï‰=Ô"ãyÈ!p9u¯e¶GO|&XN*ò]9Å íƒ|ÑÚä•1L±î1.f B9¹²ñôòŸR “ÆÃMòL³ƒÇ;$Ĺ²ýˆiAÅ|)çÒhr;ø¤xØÓ€«%Ý ×“D‰_,„xŸ«ø˜¸A»:š©ï9”inTL2ûŠ).™3£Ø(I*kª*¸ÌÀb‹f2Ä-K„HÔNW˜ëPt¥Žþ•R<™0‹ì­$¼Ÿ-—ѧ”±åbö¸ŒMØø;Ðúö¨`¼ÙqŒ>h’Ö4¯ô ÝO"Z©âṖ)m£*ícëý(¬&†ŸØãåÛv 5Ž5Â?‚D,À‚2bDqTö“11Ÿäg=Á±û€G S6‰b¹ÉQJ4Ï'æéåØÒ ÌÆÁÛ‚%âIòó(sÙÕŸ¹Ü‚ŠÝ˜ÚK¼’AAêhs™§?ù»ó’g!Fz,ï„|åuõü²&—J€/¶Ò¢è~Â[.*,P°w(˜ƒ–Ç@ J|ÉÖ¸)Nƒ“qO¨W-`sL™T>©¼ÌOt£PÒQïá°ßR!±§wÈÍW'ærPÔÒtMÛv€B=ªê@ElÀ-~“ÃØƒÆEÐX7 žNÀûFwˆ]L¹'@è÷&沪oåÑÛ¬d@Þ6är´ ¼¦l¹.Ììpé jĽ†à,™üŸ¶YBF^1³ÃnPÃm[<$›xÑD×7tíÚöˆ_«7àÛÐHîáKvÆì _þ=Eué"ƒ]9g¨hŽ xâ7WºZº ð¯)ÃT ±³rÖ r åé¯B=nël$ê¯kƒŒgB´Ò€ùE L®„î_v$è1 ò¤!{ßÑL8ÊÏqÙc„ÕÅPxõ%ò b¬¹–k£¥´­r³Ú:Zòk£„\®"åñ…R«®/Ïùððžô§YLÖO¤ñÊMí㘖*Šä} HòšLªÑͶB tÈtß“¿¯ Ñ×ðï"e‚SÂQÇÇ„?˜óžP#ËÝGÚNPýâ\Ð ÎFe=ð‡!~šÆô%!õÀ§gé/ S9«J½ø[ΘÑ|³?¬ x¤I Á££Œg€†iŒÃ{ˆÿU4Ϲ#âÃEú]ÑH] GÂÿàÊüÿ榆ÆÖȃÿµºª’êV•×UTVÔV@þe]íÿòÿÿdþ¿¶þ˜ÿ_®W@úÿd¤€­5*ê¦TÖM©¨ÒÓÿ·Ú r³[»ŒÙ­õÍF{× Ñ’l0 £•AcnVìŠÉ“+Ä dgèÃ4JJÅ'M⯌Yiq`#voftMˆ±äoJÆÂÁ€QÏD“Ë…ø7"B«4…¾9Ëê÷Ñ,qu †¸%áù–z£¼²¢¢<$öW…Ñ©à†ŽÅ°Û ò(ÂK¥ Ø[.Ûñi°†S8¥m.µ–°bfÒq#µ„ŠÉð¶¥°EX ɶ¢ùh*ӠׄÒâ–Ö@–#¦)¬/ÉAÌwf% UÜÆÂ ˆ{!ß¡&É+©FÖÇq±Ø½ÛŽ¡É@3aÍ•fß—$ÃdÇòHŸ‚ßdŸC!*Vr8 ÃÊ¢ (toÐsÑ#¦¤Ç€·k†ìZ4•J0ÑÎ#þ=»$àî’bG›Á$%ý%eäJÜy}PÎgue"è§h,’È4ÄÙ+Á`=½VhGz(Æúr²›‰ù ÀÀ@U7£ñp©› c&â³€,õ%Õ¶1¾„õfF±öNªì&2B‡°Ð,ûÃë8L •ßlËꙓ³õô%%on@¥^j›C;:tbrú'´!Ú:é>Ü >SŽJ\ækŽü[rʃ2Y6©÷X$“ÝFBgÖýTZšØVÊ"Vpó\!]2å… 7=Ò·Å+X}˪­¦m/Pµ†[q·X|ì<¹L¨oƒ“@Æð_V: âuâ ›ùv çÈ Ù„Ñžb”T”âµD·¤wÖÁ™YRY*毗 åy/&rfÃQnjÂì‹&4°„¼ñ‚ú ‹6Ëì´îŠ–ßÃ^× %èBVHz;r(³ÚŠц—ÁœmÞpœpS^Ân|DU×eæÈ$TMÃ%4ì¦>{îš°¨ëRXâ‚J'$8|ÅL8’ÇËqòý °´pô$ºËK&:3$7;fèJ×a_P;„†wŒ ‡”·x6FÝÀ;D#T¢ËÕ2:^¶àë¨L¯l†Ó.ð$I†6¬¡«‰'Bp£&Ià ˜KpáèùnLE1•;ŒûN¢¶ÜÚ¤qŽ\÷Jòv°‰{8J“®.N„ÑPQ9ÐG”:ƒ( T²M5C‘ 3ƒèXšbO$ å&ãDãªæq‚Ùð7MÅ[«˜µ òâÇ0ïê¹(êea©‚¥`ýÕÉå,9v.§†1N©&‡÷z@O‘aG3ªz£¨Æ€ciìh!C[ëÌ&p…DŒYmâ¯í‹šZg™>hšÑ…)óð`KÛ̦YM ŠM£œýy%Þ8×bÌîd§—ûðQDö@~%0äÅ%\ו:ýv"Ž)TìØ2þÞñ@V]?4…RKί]„iÖ‹Ú©EAʲ PeQÝÇ[Aô>Èξ" å—ò)’­LqÍIj-í7˜]šR 4@e@Èc+ÔywÀ‰èД€ ÉÂý…ƒGÏjtþ–Ñ5ÌAc¡¸Ê‚°™’ÝË•ÌW㨠ö J\ HFPGçÁ(ä@/æri¤¤ºsÌ›éÆÅV -ÿ:+ƒÔ׋@ñDo4 ʯŠÇ…ÜôEâê(‚8- RH?°y^¹@Þcá$ê’ wºú1íÞSI¢R–Í8Vœ<àŽh]n€°Ú½ TÕ§že²Tt€›Z’0‰Ö„uc üJ@SÕ1€oõâãJQ€QšrÙõ_.ÑÃyPÊ’ ³ŒrKŒ3OKÓ“H›,5™–AfòÚQƒ„r‡(­*\Þ†1˜«RUãfŠ]áh¥ð€ÖŒ)sÖ[Ù LæuÕ_pï:)+–µ³çyiAiñÄ»:*WCvR*àž4–<<ˆX"j p2 _üSå&ó‹CËHå.@¯9òÂRõPÒ¤1ŽÃgÕo ÝëèMGTÅàFû²l¼=y¤£hÆ)œB… Ç”õòzÊè¸k0Žâoìlв¹ídY! íBÔ…qq#ÀÞ)‘Lñ=ÃÜ+NZŠ kY~ؕԥòš˜Ÿ8&L4à~ÂwF‚l£³ ×E–rÇÝ›±ð»aE8¿YÆãÑ·Yw²#¶—cAV@4iR¨ˆÂâécµÒ•ú=h£!õÌt†œïÚk|óç,"hÞrc8{óÏ…%Eåê*èŒÊ!|¨‘¶‡…•0BòãiŽÒ媉b¡ãÛi B2å¹ÖÅ(RÈJ÷"Ç{ìxÄWu2e¯D¡ÃLI蔑uˆý–ͲDs€×¾T‹ŠÌ¿Åð"06½ <;°/Åol^†”•¦ZÝìdr´"³”•F0Y^ ¢)(á m„Ÿpyü0È!6"ÂQ·–vbbÀ»J¼®ÈÕ—ƒ±(Ÿ ì^*Mc—×!ê{6ÇŽ I©¡éø¢-ÙdÚ²…¢ kÄá-ZÒ¹ë>õêÓ!&ナ£/-!žOÉv1z°y¶CÎØÝpMÂp¾)ð…Ȇ€Å–j¾|ÅDöÎ|½É—ŽA¸¥ò\Ö@÷t ª>A ‰_êpôÎs‚}:µ¢…2§¨çz0~´w×fÍP]*©‹¹QfÞ÷¹Bçu*¦oØ&2'€×r1: íÌ)p‡á¼ûj9p_.ÞgGxºñì¥Ã&jX±N w}ø#™ÜãI™¡–ì[™ìôCÀ(@Î׈z¥äIbØÍrjm3Ôw@u§E¸þacFcC}W„*µ´w´Íî¨o1š";Ó˜ÕÑØ•dæÔwÌn Âs)ñ´Y­ñTþ½q!T¢%ìÎNÑÚŒEF}{»h¼~Fs£Ñ\¿@Ìfã†ÆöNcÁœÆÖ@4¿ Iô'ÒY/4µb*`7¢‚Uí‹:šfÏé4æ´5Ïlì@¨n™ø:¾h´×wt65F¢ó›fzUTÝ.24uÎiëêT‡ÁÕ·.2æ5µÎ MØPãÂöŽÆˆ@´ÝÔ"zÜ(~ÙÔÚÐÜ5QÀ3D ­mbžÄÈD?;Û‚Td„ž•­‹Îˆö-ÀíØY?£©¹I|’Â;[Å'\\O=oèj®ƒèêho‹4‚û¦P4"&¼£)2ϨxbéªW ‰ÙÅ´m`FÄ’¿ž…„á1ÜbÜÍ3á€|&ªÑ˜Ù8«±¡³i¾X^ñ¤øL¤«E‹tâ57­ ¢¿õ‹ŒHcÇü¦˜‡@Gc{}“˜~Hwt@+m­$[*ðxb—4·=ÐÕÚ £å‚¾yv´Q?[ì6˜LmÝ šš›q…ü‹ÄWÄ/ÜÅ_$¶Q›ÑR¿ˆPÙ‹x{ˆn*ضwWˆMáîÎúm03Dš°[¢#0!°D3ë[êg7F‚µ ðÓŒ$‘öƆ&øñ{±õÄZ7Ó¬ˆStH¬"Ö@ÂFŒz±œ04؇¼dpa¯µÊ="¾í?—%î·}ûöEs[k>C¡%{,þ=£žîhló…Ç©¾¡§ðcð†èM¤K¶¦V\”ŒOsSÇLyžpžYõMÍPgÁ·ÇÄ—ÛÄB“¸×Ô‚ÈM) â0šf‰O5ÌáÕ3<§v‘1G,ÅŒFñXýÌùM yè;q"M<'mÜÏ£Âô‹SBÏçAï‹gà‰9‘ªG[”ü«xý‹b9©V¡ëð%‡<Ñ|1ÆÅ½š°SÌ®’¡TAJVa„ß•T'ÙÉdýTâ×eE Õ;¶·5¢*›ƒÄmÁw¼‚¬LÀ{Шru°‚îÚÔ’@U¤X:e2œtÈf2QŽ7¹š‘òJÅ‘œ’šj;‹¡AÕÛòaÄö)b[° =…L¥ä ý`Ð怕ÐÝ%² 4FüŽâÈeæb™âP?ªðEJ(âz[h"=á©2"4K!Lldn@NƒùÄ÷%\@›€bÇ-XŠÙkˆ?JH¢(îD„OǶ¼iÔÓ†0]|Aÿ’Î3¾Kt®éçYï©*±Ñ³Ê¤üºya„žÌä‡zæË1vQÙŽGmTH½Âz’›DA äò#Ín( [)ñ"¤KsÕçpþ Ðã°’ƒ =žg©s‰c%–“(ùÁž‘w;È y¿OUÙ'Dçná‚ÎI4φÿš“;†[:¢x,Œ‘¦YÑÉpmJ:¸Õõ}í¢(< ‘‘Ö"c„½¥¦;—S¹àÊ5`•É/þ|õd~HLÐ8 –UÇÔØØB_Ffý´c¢lÀ²€"s ›LÚÞÐЩA)!eR ð”#—oÅ@ô£xåU Izp®âÉ:³“BÇ$å^nñÚÉA߉†mxOsÎÛZ‘Ôú‘¶f¡|4/Ò穸+d±Ò̰ØâK1qu¨8ì ¿Dpo¼¨@qÃx¶ÀyTÊ}$-²©úçbÅzG„[éN‡Q.ñ-û‡}Poó–I·žÌY0÷¬­+ q¿'«B «ü1"ÑB3  ZâSÞ®qùéQô˜[4Љ,G¿†[Å!Y޶´“µ2Ì…˜RŽxí¸"22‘ñ µ‡Åk%2é]a‘ùí3]*K1°àéHšBÍDçúæÜô›"7KEj Vo@+ebÌa”z”¹W§„ ßmJ¹‹ìa;> u³ñ¤cp¯gX}ˆÀAnð„€ŽÂB˜?.ZªíóbYoN£CÙ¼XL¢`œRåS› ½1æDc˹lä4‘@Þ·Ø%Ãâ¤ÙÉéA£Bhki+$ ¶Ð/‚ÀÕáX2¿k¾ØAì×- •›…ãF®‹C•TKi΀–«øT-­‹¢(„h%_zÂêòJÊGàpÌÎÄ2Hx[ĵ=j\²D—ü¢æWw(%ÀK …!‰•ÝqÛ­äËsÈÏs‘ëÚüoóßü¿þGò?唀ý¿12ÿSyeymÕFåu••5uUåU••WÔT×Vüÿé?ñGò?å¬?²@ÕT]YEEYe­QQ;¥ªvJu¥ÇPQ@´âËn±`·sAbpÅ®×`Qåz%\R?£pêꜚd”t åMhP¥†)„+Äx„`¯PU å—Á¡ÑÁ…ðÀ’ Bˡ؎[íM›’Ån¥@fÆl'®‰‹°|€„QÞ°.e9qa‚ñŽ/÷rÀ {Ï yÐ*¯ UÖ¸úÏÕZ>'/“lÐ(i¶Áü§â½Iå£MÊj_¥AäZ6H}¨¡­£1D+¯RmB¥¯nàÕ-)œB÷Zf"NEÐPÏŸ„¢àuÂâõ¦ÀÈ‹4³2D‹6Öú YL^9ÈñŸEê75“å?\{4Mœ~+Ž&š.Ö Æt %iSºwÅ`‹L•×|OÂŽ-‡‘ šúÒQ†Ú.;$ ¢M(4áZø];¥S#ÌØ¢ï HÞGª&$=.µ„wÒxÂEOŠs3õqhC,¬ûæ$¡hyÒ‚ 8â¸'ž!Oý;ܨÔ*oMe7¨6®J0q/!ž2ER-H" þ¸q²æãЪ,i….Ô麢 TÝUÝà¥UýÕKY%\-׬•zÓž¥Ã*u¼»pÈ™/~wzo::`!™,AÌ/‡·b'pJОpãjÞâÐÐA2«B)ÑÐ^tÛò=GK‰½ïêh6uL•^¨~ä+‚ ×K,mšx­73‹¦Ê5ÑÿÜ• . ‚ÛAÑà$Ì^ॷéä‰GUsP‰d.§' ÕöøiaÂB>˜ÈiA>—o\Ð6X)ÅŽz=œ§ïŠ¢}T+H+»„ /²dÞH“SXä‡ç\>VïÉI…ì`s IùÝ‚OÔßå¹ÑÁh·¯Fð µ1â·¢|†‹j6àt7ŠržÃ­…šEWViAq_! Žkd%•å KÉo>«H’a¸·%|âÎírH–ûI)3J‘€M!^¹t}¤õº|Ã\>LÅ®~3 ÌØò‰°µÉ¨M˜¢S°ïåQóæ£üp§W6 -Ð|¥ÝÂFGh³ÄĸB»È-"R%.[ {Za »U‡ ¥5”$nDò/8Z'MLGˆ&íäðå˜ `Ò+Ì—6mX-üðù £‘z.oÜ &iD@Œ%d&ÑT|¡ì‡›¨ó)¯„˜}¸úä©„w°:svMw äQÄÄÂÛÊ­ƒÆƒ“ÅPWžø€ܘl˜\̪£ŒŸ4¶´·uFºÄˆl4·5Ìã¿Êu’W¦äžçO '£¼_Ð‹ãÆ„5“}™~™¬Òk1ªÊ]#qVÅe d6P„b0„¶zÐ`#EU9ÍoRòÿ ¹ý@Ž"å‘(ÈÛ“Ê+é£Õl 7ú«¸t“Ä`Þo!ô\8iL ·W #Æ•?wæþ·¦,xLgU'Ÿ‚ÝÈI´²(/ÉYªŠÈKºÜæ<~Â>h¸1Ò}½S‰høþ #q%,¦RšÈùhÆÝoi:A ²|:–¢¼µ@ÜNdGqªµ‰w^d|Gæmj¦Éþ%Ž)•'a[“mV@)æß™HÈýäè±2}*XÑAó”¥82ggÌ>ª­ žæqã"SUGq7Å|æ:šbxWÈ\H×ùâ“"jøÕ$é–´²ZEÓIY×½—¿0©˜CŠv:›ü–AØnÎ!W47Ç‹j˜ç ó#ï ¶xnˆJ¬2øfËbƒN7½ mÕÇA(ÄUZ—ïKÌáV¨ƒÝQ~Ýë7%5ØÔåãB5ŸªTtÁ·ZåÎ6Ù{ Û¡‹Ÿ/Ü- ™¤k‹‰Ÿ#-*OÔÎå·…í#•ZO-Š–áÈ!Íz,‘ÇÌ wtÇÑ ù˜rVEô=ÊÛ £¤ðtÂ–èæ—Kõn؉¸t;ðžófd? d•_ŸJ[Ä]Q^AÉö†TþE °B¬îÁï{sËûóÚð ×#Z®¨ù÷âÑ*Ô¼¡æo.\5ò„IMRþ[h]±å&gbÔ{XšPh#¹n^mi€ÆŽ@o-Bê¢ØüUZ«µ.Ž€ÝûÊkZZàïI•ìIy¨b„òWî {sUÒ$C>ç†}ª¬¡ W`bt"n˜ÄiE]PN“º[±9–Æ9´g»`c`ÌsCÇvž ÑÉ# Z\z,#›ts¹ÙIŸ³°úíVÉ ·À§@â÷0˜ik%¥ÆrâK«A€®fâ…þ;ûg)4–Y‚m9–fòk_ÐÀ$ýÒ—Ó"Dù¨÷QÎ×<ÛÏÿxU¬—»©A40Ý;²ÑB˜oooö”Õï. ËSAéÜd5*0‰þÒ¸Š:ˆÅˆ&‰ÙÌû¦8@J$`vBHǰ‹Ó}qì Ø:­JLIôÑœö2´&Ë @9b••;dö„(–«y|©²f4)½0´Ëq¬§³ÉÒ¬éu†òÆ;‰X‰‰LU,Ç{ƒÎ&ƒ. CÀ±5Š}¨ §Ø_ðD~·‰£¸úwÄSÙõ©†ì{í ˜€µÂbF€‰Æ fˆ~[GŠU“ó„ù0 ñð8ÂÕ1;a§5 ^fšc¡˜ŸA(°é žË]BÙ‘ÇW! Êpµ d ¬J;öú6þ`e°iu[â¶vý}”匀ä·CëL{Œ/SØx”ÀR¯;Ö±á0© `@„”Ñø˜ejËEÑe Çñxùø ¾6‘¥§MÝ™B‘$ ÃZäŸwÛ.Øl’?kžÏ#çB ''Ìw¡º$ãNÞ‡ÝxMúÓÊDÃEª;ÃyƒêyZ›2¤JPÀ9uÄU5·~a)¯jZíýên²0Ò ;>móL‰ ¬ådaƒPJ„ý‹áº!iÓ¨²+DB½ ûÚ‘¦$·•î;=Ô¦(†©ŸƒëCÒ<;…äº[”¬;^aWì åìúbrÀôØ+˜X†8Zù[â>÷ŠW<ìªá2š òz]Ü#&fy±x¨Â¢‘(< Ài©E ™.Wl”•Y!+'§Œ•A€¾&ϱ¸Š ÐQì ˆoi-Ò Š)…Õ!Pp!þ‘xaÄU|ÇÒƒ*ÃÀ‹^h^5µ\¶|ÁE¿쀈T±²(l¨}†¡lUýDö§-¥"Ni`Ê]Ú˜)^@cÐÖ§#¼n‚Ï8¼„3èF‹‰6¼‡K k 4%ŸŽëÝ•¿ÖœFZ¹°X::”à@ûLyÅÑ÷‰žnÜTÝæ Ñ)§ý¥àg{Â73ÅòÇâÛFqÿÄŒ[™b %Àß¼»¤ËµŒ¼ŸF­’B7 tø:ï ó”R•.–5J$šÍ{¾ ú¡p¸ùPAf§ $þ×~N»ÑÉpÃLöYI½þ '`S•ááAyS™/9õfù<*5ê׌9CtRkD3ý9¯ð.-ôá‚<§(F&F• Êy™/¶Je” ì0ùÉr<ûàã%ì#°p¡gß;Ûž kÆP™’"Û¿“†#žÖýÍT_I*5â¤ÓÑa§@hX u阑¶Ï ¿Ém™R” ˜4àµr.«ô|áÕ|ò$¥mb”j@ #;%º¥rJ.ݰôDÓ Ä“Œ â:¨.¯6Äp£}T])ÉŠ§NB! í]Fl8&ƒÜ=âCVÜÝ,|©$b b‹ šÅ2X ` +6ì¿€"-äͺؖ¦-!æîêòý$·.Y¼žÄ08â–c%öxpÀÊ·ñø®vRQ–“§\)IßGMAMù&Þ”TL¯ç"w[ˆ!Ô–C‚ìü\~ÐQDbܲ ZÅßMž¤#Ÿy)­‚ÜØ4\æ½!dGמéX"êh†^u¸Îu£äÂóúYþ/wÒᬔÁO§ÏÊWqµÁ‡&ÁÙ6âäÕ››´aþ´oÂ]öµú¶þ=7ÌHÝQ#ø\F"#8tàµcpéü;Ný[5î·FÞKù»y£ÅnýOÏ´sŸ®ôt‡üȵ¸Û ÆçÆÞZÞYùŸnˆtÌÊy¼¦àã ò™{’¼.ï9ªÅ]¨¬ŠG†¹E_ËÈ*¼µR~~5úÄA"¾<Vr½ç ån&«’U¢#ùŸ4öÀ:JKÙÝšPe!TA¾î¢ìÊ÷ýš€žFyOY¾àÓf¯tÑ ˆÿC7ËÝnŽ<« ÈöCaÌöi¨&ÚB,„Nt£~d\1rÚÏiWz?gIû÷\þðàÂŒ×/™á= <’ËæŠŒ$¯ÐßQú¦¬÷!›¼Ó=MèUÍïj’Àv(• ¥¢‘O1Wéu2Ãê&VplN›HŸYßÉÐAƒ<(ë®KD¸«F7ðÉwÊôI,BÃ\n'×5€É>&¦C˜)3c!+ \ ’ß’VöAE&H‘ÇCí«Ã³¥%ª±ÐîwÏ{0ÀÅI^.¶—%î„Jv!¬íI€ø åŸ3t˜² [Aõàr éR ÒVéôd=- AÌ>Ó)>ƒÝX6IÈ…aæ£õ`Õµ*§ù’œ´uJa) Ó—¿yæу|('¯Çç(É@ŒœŽ™k!"}D§/ÛGLXÛÔî”A*:R˜† x $-„”{Úä´É0U¯ÔmØ‚k³ S,;xÌ·FGÜæ{E‡ àsåÕy‡î,liu´7¸»K1ñÝC¿SáÀïÊÌh;ip”ÐÇŠX&†ŲÌP¿Õ×KÔ‹îSKsX))¢£Û©Ú"'jžÖ _yò§)oZùšs<Ì(ž!dʸЄU«±Ø!S¿g8£^v}y_©ï ;G$¬bxŽÛ„œøÞÍN›6‡º™ á¤eººFÔãs¸h`ldŸvˆÏHõ§±N•‚™p8커ÿšJB›ú{£H KlÅÎÀÛâl*`5 ~Ðöæ²T<‰Bñ,çºé !£ÅMº/|Ì`²ÒNÜÕÑŒK{HÖÌš¾ù’ßGMB^ð Z°ÊyWø’Û)aI»1n-w·(¿»:šÒDñÚ Ñ™¶‘óœs±¢èžR×Bk¥Ãe43í?e§)²®ÿû 5I¿õj’òé¿i¨é½©ûúí0½ùZÙ|ÕT·y0À‚æE8zµ;¿>¾ï!7F ‚¦Ç°hð™)«†?1†™òÖ1BéýDµüDE¨ª°Ï³àHªÆ8’*þ `xÇàñ&ê©(ª`f7òº…ŠÈÖ¿\)¿\;ŠÛ)ÿ—¡ŽØ|Û7ì ÷ãc9# › ª:rÚ?Ðrù­êQ¦n\­N´ºf½· k)L²Ôƒ4ßB[‚!»/jL 2ý…ž¤Úo±ÂžeG3™Ö?U uˆ(I<šß_Ôꜣéš)W=¡ÿ†ž',¦ˆÀKA„–fÓPÈrÿS4œ%¹G—ÎNiNéA,›'³Ð£–V†Ëó(²Ja•:POÂg~kYdbA (¸BÁHØ$[û aå¸ K˜*²œ¿9£~A×9O¿´ü1åï‡ÇÂek"[­!><Ï;®‰3ÒcŠxg¤‡T×y=½(ðNTOgHiÔ¾çd¤5^Oí`7ìé‰#Í‚B¦€G ‰8þ¾K U!i~…bËàfËg‚;œ2Ê'AdýTëì_âáÑ*Á¸Ñeñ;ØËÄ჊(hó„Ýô `¤!ä”»Iã–Êꂾ%û°oqµB͘ä$S?2K…# -úÔW Ù¡cC°Œì—?;X\ª ·Áè--ÉÝho¬ïp=CüqAIž –£ä')®î³ùØI”…£˜‚CÁRmô·ÐÔð£¿ÖÚb3u qN7±.˜œmq¡ˆ§ËfÚ+†…˜“&ÏUXãê‡_Me›¢!s@¾A•Ifz|Ã*SRþþÓ*SÒ ÿ *S«)~ã*S«ŽîÎÙ,Q#šL$ÏŠ»NR iz¿Mªa5†»Ç8Πݨåò£Y³­*N0’PWS9ŸE Šña’¿ OÌsý ÉÈ Ùüop- *Úëgö£?}ñ Ħ>…]êþ!Ðj ¯6=U`„’8Óï|Á_Šf^P-8 ñÍnñÜÞ‚ðež ·ø²Ç½ŸÏ æíIÂ6'y¥ëÎç\V‰!W¹Æ![¸‹d©Ãû2¿Ä1J˜Ä¡šàIÄå0ZsÌë¥ßn#M3ù4½OçÕís¿:0(è!/#¡¸ö8s=#Þ$¤¥¿¬ÊÇÚ7ƒs!¼Ê_'µÁñî¥Õ¸d|Йâ´ã„W $Šs®ä8×üvXÃ)¤rŒ°Õõdˆ¤é%:BMÅuRJ5…«sùµP§)¤(I@!˜@³›f¡"ÙÞ:;çKf%×&+ _@Wû KŠÌ°†¯îJ¸Ú£v º®)˜8Qéx>÷ø€)ƒuývÆ døB9ÅPý1™Q*L±Wßâ‡\3¬Øµ2’ ˜ƒë͉™B±78b„¾Ç} Á?‘™#F<'HÌLkß‘VJá͸ײ]³Ô¼óhüX(û\óÈò"ù½ÄbÌ%D×¢éœ> ³“‡CØGééi†YQöƒ‡?™ ‡D 2¥&‰ªÇìS€¸K"«Œöbl€¾‹ï82´ îêò*£D<Òc‰¯&K½Œæ±é†€·FÖ–iµc¤‚þv7E¦¹žµìá±TVpàò‚q ìFˆXO9§ÁC嘅}ƒup°Poá@¼¸KCȈ&3.²;ˆÆv¶¯ßÛ;¸\štr,÷ú8®žNœ%ésÝdº¸4UÓyêWÁU—øT™¹BòÆöQ¹"c„Sœ€¤©MÕÿA ´š5ÐjÌ»ƒŸzõÀj¥hŽŠõùꟊ&üÿàD¾@±Ñbf¢ L„†äTh±Aªwå“KE¥cŽP;Ëç*ʉòŠ1—¾:©ü…n®t„¸Ü$(|+\ïn”¹ðYÕ˜ÒŒÙ^yÖÖÞÒÌÁçl¢¢Bürá˜ê4Ô¬¦i©lÐ ð?ã±)qõŸ˜ã4…“±ôa$#>G©~(9ê§o˜r)n-yÏB‰TzmÐ2¹âº¢ÑÜ<ÉR‘ôñÊŸ7ÓË£¥{’Ae¿$Œƒx¦±èn¿Ð‡‰­nÛ#þÍ‘[Ë{µ¢EdØÀbÛ™”ŽyQ¢É£CõóiWØGö.ë^(®íŽž÷bb³,öNÚ¿µLlô8Ø[,΋E‡É=G ô‚½Ô9Êë»éýòøÉ¶§îULd’gf.õ&åÁ(T›Ò" Å îW쪔."C4UÜ•l7ÃÌb0´Š…>: ÌR;Yðñ–(l1zº]!üŠGȦ„ ¾xL¨G=ºŠh¬Ä¶hœÜìBt…^ï7©¼M¨îl( ¨hïB±‚†AÆý(ÉÓ©ºs>ôT±V¬ûˆ,dÆu÷¥bÆFy±žWãvF÷²;PM¯Í«ÊøÉ¶LJü3Äé dâV¾ÉšfC$"¿7[\ä)©š .2AÛ®xÙÚff:ç´MK˜BcŠOÇDJß®¿Œö˜ þ2¢ëmæhxÕBÃCå÷Œ]Í«vÕ<Ï%Ò«koºr nò„«¸’†ÈÿƒL»#ÉWNð††í4V-Nrê<¿,ióÓã•Ó½´«\Õ£âÒ ªXõ¨úæ|\U¬zT3vCUOæœÐä±²ÄÐÍÇ)v‰ìÀÈ1|–¤ƒ Pº- ÀÅ ù¬èC¡ †;—x¡vS˜c3,3ù±T°ó/³-"û´’I±—ð¯…ïûs(m3Ÿ‚¼Úû¡DûrÓLÑý7™6x ‹º’X kÁ@‹ëÕ"–ÒI ·éªX²J61̧éÖO˜¤š×áÁ¹î½<¶·‡þU½YÈaå=êøÀ –®a® sbÙîE?HÒMYœ¦Íî#Ñ¡ ^m3þD\ÕXŒ¢ð•‹ìÅøÍ†Àzs*xëa-•¨ÌÐvŠÙÝéq4¸9è˜OÜzꢯbŸ'<­¸§ºRjLÆÛÀS- èT§âÒ“ Õ#Ú}ÃN¯ÄT9®Iá[°‹"M ÍF(¾æKÆ=:‘HYÇÌYWU6BS†P`Ù¶'Œ¤¢û\(Lz¯Dº¢3QEíõOä›Õ¼;Ö]>(È"oZ÷¦Ë»Ò9Š-)­…¥%/ºŒ,1â/€Õ%QŽ­‡ 'Tÿ@|sf±$g†eõ»¶ŽbÓyaî`¸ðÝ P¤¹ó‰|' šCÒ ‰}…•…<î~ßüK”뺢/Ÿ´e"j‰)ŠcB2»5‡˜+*AU Øë£êOÄÕ˜âllj¿ö¹É ˸—G)ÈÞÚÒ}Üc"7âÃÎ=BC 709,· ľê òÅA#Ë‹jFRau É7.&¾.å1¨žŠ}×¨½€ÒÜ ¤d10… CܳïÝ}’ì[PY#ßJqb-všýö€‘T4¹ er N¾}%옢ٶÝ;\û¨HÙHEAIIwz<-ŽaR²ê{SÅ‹ý©¿Â.]ßcH™©fA£Ð¿OuÖØ®ÀMÓk€  Œµ [Ö ±W¡g_s\rã9TfR²Nök2Z²±T;ÒÈ´]æNýH J\W½“ò¹Båñ¦È¿¹ßR$õœ¹¯I¸ afbúÈÆò ð§Ø#õÕ?ß68_`Üp ÙòKDž-”°Ñ?!+tÀQDùÐka½RÑBTˆô ÇîÍ A?\§'”4ƒ¯'„¶ÊUc<^>Øñ¤óØZV ‰æÓÚMçøs]r¦Ï}Â72Øc0DÈKD€yÀ9ÁÁ…õšé4ÈD¸âN‚;±«¬ [(Ÿ:ô•×€ç˜B©)Ô M™z‘#!ߨ¬%: Þ²AÂæ}TV‰ÒKôz,h@efTüµ>¾Âª¡“só¯/Äš\ô쇘sðª¸ÐE¡úTHÜ^tw"÷ yÀäÇea:ï·YÂÂk˜¶¦˜9ÉGÔç‡Ì©ö¢\J¦@b¢zNÉÄ!tËÅ¡¶JÞ]î´£ê ý€Àp¡˜°h;Ü産F•eÿ(¤ìÅ$’$_®Ø—ÄÛÀº…c­§´TDû…ɄѰ ÓËCÙ”.ŽËYaÃ(ÀÞA„Ë‘¥8ÑD¯À‹ð^] ñ¦%EOt ©'lŠ“‹;¹Ô]Yïr¹ø9ËÑPµÚœ±H3‡”d9|“šÚT™²”^çi½ï@)çÃÁqm8™¹‚Ò§ßׄ2ez-FOÔAÒºøIK¶›M±™“knJß(ñܰËÈ{’òæõDZ:Û9óÌ2õž$UÔU…GT©.}-pÑbÕ¹:GP&°)3×Ídÿ•ÜÇžZF ÿ1…˜ôZ©IJE,å^Ç’Lv…¬¥±Û>le´ÄåÀÀ%§Ìý.t!¢Íà³)Àe:wŠÝ8~‹Šœ£D`e HC˜ŠKÊ AÒDégPݦ§ý 5 ‹-ý¼ÆØWì Z£ˆK;ÈJø+©i÷¼ê·… g«sàßèÚà+ }A<Ë=y´²¼4ƒGÿ2âT,M~—Ð*%W«3'zP†Z5èÊÈEʳžçU~HÌ… •ì  ìC`o„m¯ßÝLcïíz9bÉc­ÁöWßc¾…’a{¥Dn5§YËÐÊáìÀ\;P ’ÐJc@¹•[Æ]Wiß躞ÇÓÜãú“t­ ì° •„‚%le®—:×ï·ËT† …å($¤óIR·¢t†L쨧˜;þ&—&‚~zäÓK9L& R"ŒÝâþP©ÕuRW‹Å&0I㜋#€†ü j^¨"²2J¼œ"òã´YØàqh°€…0ØäQ,Àae¤CÃP ï±’é'ðyB¸|‰_tQ¬ª'¬¸±–*gßø0òîÈWJHù9¼›'Ÿ›™ü M3Ñ›N0Ý—KdùW(âa9ñ÷´_Yß‹“d*`ÝUîyõéXÂÎ2ŸÖ“´–2”Ìcµä–¤Ì•ek³‘ÏëåÄØi—LA7É=ihA¥ ¬qz.( Þ®&44JÃÿ¾±*5²*¡‘Q(¤±¸#jdöG^™þ^GÍÈrÝugƒ;ÈŠ[t“£øäÒsÌ+UéÜM!mÇÛërîuùäQzÝ‚YPHÛÍ&d¼îJ¸ÎÀFM ¹$TB¡Ñ*3GT¨,Ç56PsœÂ¦F½`ÆÌT& ˆòž A…Ü/"# ˆJ3&±L¯âÛEa­ïlÚyB±é`µ4Ìw‘±ê‡™~”GB]“{@I+,.ÌÅÒ e·84R5F­:Øè!,!&LUÚ}ûU9õ4ר.YI€CûÓB1‚?»÷š´fÕB¼“úÞ“ŸÀiö~·ETL¡{©éõD=¯Z®KßÊðˬnȧ„A ¬l4+‹ÔŽõüسÀn )…‚ Þ¸0 ‘¶W«´ŒéˆÚg®(E!z¡ŠZÙ\× @O&Ö{–Ërv½5ÕÊZιÜZî²jº{JÔï˜GWûÐT¢b¥–wÝÖf•phyíTYÙ^×¼Ø2–R1€Rò@}ÂÌ”ô+9áè]7–5hÅáÜäĘ{§PÇÁjòuRYMÙ¤tôD`;`4‹ùW ›mtR¾kYê—ª> Ý} y—¦—ç|äºSýÁA±€_Fjû€°É°Àð¿L¥¯a%M‡¼Ãq= ˜É€8K÷k/OµFvˆZ‘?,ÔIh>áØÔ§ú>å}Â’Ó‰JNž‚R [¼¬) H¨æÄ=·4r}òrpœâª˜á¥ Ê¿¬°\|–߀§bó€­¢²J3Ãcéß}äýÕ ƒ}ÈÀYŒ‰ÅFI 6„ŒÒSXTTžV7|AGÑ|As%‹›E“\ìèwkÎÙÌô¡Ñ9æ(•wÆmYÐæYrÕ¨ùF_?B^Âñ˜Ïã &øG£/Š´NúýŽê7,ÆsXm÷ahûk´º+uûµjû5B p¤ŠìFiÇh).P 1>½dU ËEÓ08/  “tmèWá>…ÞÝoÇr¥`ö0Ú ~' Ÿk• Çe94ŸT©¢)¶DÌ"ÓܵwõçódŠÂ}¦9œƒF< ˜¨»÷5†DÉÀ¢Â¥D%ë\Á¢"xÔ“<-~0&1îkD¡MɃ+`!em¤#ÒNhï ï‡A•Õ,%0Ì”ÜsVZyüM±Ø@>ª¢Ér| !Ó²Ú0E°¡oè\ƒf²Â î7´x¦Èƒ}‘ÂQ #nc0¥¿lÑ]€ mB&íÌtT}(AK¡`³…^r§FÏpàâQŒ8!I,¿ ž¼æð†!AQ¿)âÀ4ãk(|ª·E˜’鵙툓ì& ºu“äB/Ò&YXêQݺA—£’ú=z?Sý€aªÅLtð¦…n€žaörÀœÊö„´¯»›±¯l’ÆB‹q„á Ž±H‘DÔéoG[˜`ó¢BTB;‘˜m§ÄZìe¶¦ðIq.´Fq›C$BVqéQq=숸 'f Ά%I?]¯·Ôo ó͈2E¤w[ñ'õ¦£ªÒÏy8ÃŒEAÿAð×àB!™°‰&èÕH¨ ™=Ä¥ ´-rr$%©ØÂh°œ~*®ÒMÓQ¦Â!0ÉA”{JU )"öRV¹†­ò=Xð^Bu€ ŒÃæW2O½¸Ä?,æÿ®2:¦p­.ð¯ˆIÁZ*õ…¢(°Ç¯µÁ¸«Zºêc~-Õ +¢à—Z ð*ù™V"L¯]MOàè¤óP®·­uÆ÷^ŽBåÝ1øqi ëˆË"¿(Fu³Hœ Q,ÕbvL”1(£]z%29R}⹪G¦?ÐâÆâ´Ø¢ÿwq+šW£›‰?7“ä¢òöÈ߆ò%æ6ãæš)¬°ôVà(â²qEFÇÌYe€D`1ÇÕsãN\k/ïH\Ghþ ÆM:e! Ѥ­^d”›B‘¸üÅ\Õ÷™E¥#íQ ;²õÏÅó„L¥ŸyñœîïňyÙÐÑ8³©3Bõ$AO$]Ô£s*•³BW9Gã”iJ }0šQÏÀFÿûóÿ“?Tn¨¶ ý1©þÔ7ñrñ§¶ºÿ]^]áý7ügyíFåÕµµUåuuu•WTWÔ”od”ñÿÉBª©al444„¥8 =7Úïÿý3í ±è²2cBS|Š!wApPœïªZd1++ŸTV>Ù(¯›R]9¥¦P×B¸7®H²‰B~L%h's¢£±’Â^Bn * AY‹j3½2–i®ÈÖÁêÉIc™Ýh:cbY À¤;Ý5ŠÃe’„§¬Ç¶3 ”Sañ£â©ÚÉÝêÇ%3;ºÚë›»g´µuF:;êÛ»gu57—ªáKÝél²Dü追 ÿ½?òü#Ü㣜ÿŠºÊjqþ몪«+*«êÊáü Ið¿óÿŸøã=ÿj ˜\”åe•e•µFù¤)ÕµSª',:©Ô  Ç‚•îJÔˆTm7õ¾lJØ L20HXô]eŸ®®åˆsŒtc…b„Æ›ÀÉyš9Lñ{`ùJp8„‰-…ÒŠ3-¼=»µË˜Íà±v¨;3š­˜™t°#"L½†¶öEM³çtbqT°9š›[#ðwkœ‡ò5еÀ&@8껉yÐì&I7Ï H;Xn¢Ü§BèàÚÇä&A£ZXjSJ’£\ã °zËé–ðWKK£„2éû_̺ú)þЦ€Ð¡[[»º[Û:»gµuµÎ”ª2/igº1W:H¿ÁÂÂS}ï×744F"Ý3[›ým×7“–9Z;‘¦ÎÆî¶Y³š›Z}Í€}Ü͵‚ò´rLà˜€™pLšafû¦@Ln;a€;@@)¯¡À1™†VœÊRÃ\`£U,"ÆåÅFS ñÁD¨&AI1rä ù±©¢rsÀ¯ºƒÖwCο”ÿ` ”}C2„|]MMAýOüÙ¨¢¢¢¦¢ªª¢¶Nü¼¢J(€5ßP<þ—ÿžõÇý¥G¿ÞoŒ¦ÿ×TÕˆû¿¶ª²®ª¶²ªJ¬Me]õÿîÿÿÄŸ²‰tó«¥Ç›¿–.~¡üW”ÃÅ_SšŸÝ¥{¯0L‰7M÷YÉ)F…91àLBÚNÂNO1öíííy•éÇç1:šp$28L5D/š;; UÃïˆ=ƒ­a¤(Ôcg2ö€øFj…A¡ã}c±6šÛñ86œçËñxœ¾’BOÉþQ3©h<ލ†šÔ øñ¾Hø ¿q¶§=¦ßƒ1g&Žù?Á¬ðœøKòédß×÷QÎ]0ö+Ê+ë*jjk„ ÎmEUíÿÎÿâÏÉí­³Çv‡­:¾iÎÌñï…âñ-7ÿÜ8ôÑkâ_[dšZ·xz‹v·Óö3^\,~´yϼÙ37úþï¢;.=Süd«ÔœEâÞÿ,üoÜŒ’óVl´Ñ¶Ù¦™õ+ž_{Áp{gß·W]ØÉ!Žu]Åeºn{®sY¬öì–eg>ôæš';Ÿùþ«Ó_oÿÕ¬ß7á¥YÉö[^ŸµicµñîÆÛÛ›nÛ9­½sÇiíõoì8ùõ;/¾é³=úv=íÃUÿÜ|Ö9W½}Pæœ_ÔÝõ·g»‡¾÷âË©ó¯:õ†ïmÓ·÷§;_ºËÚwÙâ-úî¼õ×wO=´­¡ÿÚm÷øì Ç&­øÛM«}:íÉM¶?ô3v^1áðïï}cß&u5{Þüà¿nz¿ýûg=8®o›øN ™Y©SÏ<îú­fŽŸûÌ ÛÏ}xþ ;wÕÕ?ÿâÄŠWO:îú÷6{´vÒÌmgÇ>ÚnÙ‡·ü½Öxð»íÅ›7ߺÞH½ùËUÏ´ðoûX;þò“î랸ôXç¡Ý—¾õäY­ܵv“Gïÿøì²?ŸÐáqÔßÿš}ü¥'îÞ¨»aë½îü|NñÒ­âÿ|zÓáËö:gÙUÑ{çìqáÿaÙé¼´Ü\òêÜÌÝã>¨eúðõ{íyõÍCk_ÿð‚›öŸ68~Bׯ,?¨âÒ¡Uß¾0±¶x›WóýñO7œeß²ÿcÏ}òûâ%ß3N|aÍ3ã^¨œ÷ê’—«Þ7ï¬×âן}å[•‡½_~Û¡kK~¿jñÞá¾uËtÜü“ÝþóÄo_sÚ#Û,x¦,rEâoK~üÁ©öû©µ3¾»ÇÀ_^ÜùŒ3~¼õ¹»&Ž™7uå›Ó¿¦ªq}lMv×ë&üâ ¥'?úòøóOÜåo»ýû+ïÞbð¡çÿúø2ç®V>:`•ó·?ýý¥[ïóþïÏ<¬ó;W]ñè‹¥­ÍÁ;–?¾Ù#{í™h8úþÕGÞ½·uÓEu·ÚQ¼Ù?†Šº«Vu<{íÞ÷ÜÒ>·ýÜò×Vµ¿x÷{¯ÖNoÙ:ÖV¿hIÕ;¤·ÿöªdéЉã‚OtÔ³ù/úñ’©/(Ö[Kß,_~á§‹öè¸èšË·?ëÁ7.9´ô»î°oï|MâóÄ];/¼à¹pü‰3wÿÎí÷-ºº´úÝyß?oÛeÇý䬧o8øãçŠ6öï«\ñæGû>?.xÃ[îxÐ&KŠ瀶6¾1YÒ·Cêí÷0®¾}›¼}qøÀ¥©†'¯¼óççO<àwÿ|íØªVý¨¼ÿwW}¶è¶WŸy)tÀG‡ÿ³·y)µ¸|Ö gÐþöîwþäÖ5C©_ïöê>so±þºò”ʹKœ-ö}wþmï>xJÿá«Æu­·Ë ßY0åÕçùÁ>ÇŒ_0¿ïË­ÎÿéÖ;ýtMf³uG5§wLJÝ?8m›³WÏh‰œ÷TèôGO¹mÜæó:>ÝöªÄ1÷é…)—Ïmk.º¹ì°Å7Û­k¿«/ùéÓ»MH]ycüâÅsži¹ùÛ_Tœ»óAÍ75üàƒÍÖœó`ýg+ÿ¸ÛO®~~›“œ‰+—6´_u×Ê–šÙûö?þ°“/»ó¸Úg|ÿ‹çOxòÊ=ïL_zû¸Kºõû¯ü~ãËׯ9s“‡:½ë.™³¸"ylvý¸þÈÝ™=*6wƵ‡>ùÆëV,þå´›¿ýë»7{ꪋþöݺßý幫®zúŒyå§ÞyÉâŸè‘ oÿÕÀé_œºçð£c­ WÔ»¾eÏ[_YüÌN+>›V:÷Ô_>píVû,éƒÉé¹í{÷…æÞ}ã%¿yáÂ?ï÷yQ÷òíf]9iJꕹËv9ë‡?ÜóÔ››æÔÝoÿØzêÜößìªãŽ~ïì×Íl±ß’+ÿCË®MøìPs³£ÏÛèÚß•§O[ðì;ßýì¾¶èG¯>o»÷OžÞ~»õ¿®œ¶ë]o>¼jÓ~wcýk—¾zÊà£O}1ïéqç]¸ù€qm±ë/øòÁÏ÷Zúâïü¡îœ×¶¹ùƒ»~ýHd«¥'ïtÞÍ¡C¶YèÚ㦥õÓ¿^pÚÝ»DwYU>q‡é¹'Uã­óžÜdíåο:÷¾jå–UN9攇ï:ô7—ï~Uÿ›«ë^—7?vOkô•ÊUÛ\¹çâµï/Ýû'¯ì¿~Þ‰Ÿl’œ½ê¥/Þ‹þ¶xõÄ7Á—ÎÛd\ñº»O{x‹Ó3×ïù‡Çv<ö/w¿P¾S]gñÌøû×.Þn»ðe[ž9~Ó5—NÿxÞš¿œzǘ¸ýÈ×uÕþáܧŽZß”ºõÃÄzÿøÛo½óÅ‹_¹aøïg[÷Ê5÷_~GÙªïîš:mÑo÷?ãöñ/ìxuÔ!ßþͪ=†މ}w½¿yñØgn|tþu—ºÿÂß¿±é·®]»SjëE©ß .©ܼ׿JÿùÆ¢ï{ð‰Çžýå³GŸÑ?ñ® ¯Ý²Ûò}Þ|={b¤ó§÷_wäŒ'×>^ôìÊ+'}<|ìôŸ}´åï÷{b—S–^ñ§#>xòåuÇŒO?Uû¾1íŠä+ÙØáÑì‡Í ¿¶ýGó.y%5{é_:yÍÜÇoì|mÒ9û…vûy—ZŸ~χo–ý4õJú—ËÎ~äÊõŸ?\þ\É%gœVöpÜžxÍâÞöÞFŸv . øó%‘‡~/7ï¦O^[½ÃêŸÿÍ3Ù‡Ÿ[ñú—ÿcÞ ?üûSwº÷‹íJK^é|ùØm÷öF5/žÿÜQï-ýÝíE¾tÝ®“ŽºmᯖÏyèö·¼Ððçsÿò\hßíÖ,xü”§~qá=ëËŸØåšµ§Ž_ñÏÕoîVQsÎ'õîÔÛþúƒ\2÷¹#×ÿe¸oë¶»gÔÌÝ1S?ñíóî® 6•®ylÍ÷¼xÒÓÇßa/‰ÌëÛãìËîß´béî;í´ôâ=ŽÛ¢ÿñúô­~¾îg¸÷é‡&¼õeÇÕ[ÛßúãOÞž°ýÌ­ûÞøâ㋦·jÇg¶Y¹ÏÒ­÷üó“]Ö€}ÒïÏ/š3é{{{sÕŽžþå—°ô¼UǬy¿äǽ<ñwÏþmÛ ºÙýW½±üƒû¶Ç?ºõ¥Öðn—Z“nº½þ¯~K÷æûÿë¨U«®ª:ê¨#ç–_œûë[–ßùÞ;æy¿ÃQïlãû—=?é“£¿{ãÇxÆ1{OwºnÿàŸŸ>¶Ç¦ãŸ(9¾¼|pÝÁ­¿êöWïyðÜààIɳ>˜ºzZf“ÞqŸ¿pþ–ïÝ0#úÌië_o˜œyߥ/wœ_»üó©?°Þ;ü„;7JO=zå¦ûžtDä˜òtê¦öc^;üõ·ß[vîŸ.¸úùMϘwFjë—N¸üÈsîúd×S»wZ˜^{Ãú²³;¥ù§ŸÚðî¼5g{åúO2—~wí·çE­·/Ø-zãÛÝ[ÞrAèÈ÷ï{ê¾ÉΙß»í”Óùö•ïmóü½÷¿§íž{ÎuÃÝóŸª=~ùç»ýzéI¯|爕Ë/.½í¢ó׆›ß{nü—÷ÎøtÁ^S£GÞ]}Ì«7>uâ;?ö'çg׺ã–iG®zé¶’åËïúÅf´X1˜½ÿá• ¯nÝ¥húúÕ7^jÕ{è–ÍK~~oGçô_DZØïãµû“=?®{yímç¼pËìÏnúæqŸíø¯;îù°úo/Ÿù“ù~úþºïxìà3ç]ôÑQG½ºÿ/Ÿpòmw¼¹Å¾»M¾ôº½jÇÍ_öv袢&\¸é5«6Y×{ÅAßúÁ'¯ÿÉ~߻慎§ŸýÕ_ç6ì÷#óìE+ã/¯}ýÇ3><ÿf禧> V/±ÿqë’sμôữ=¸Ýé§_Ù¸ñ[Ÿý)¶ú‚úC6¾%pçcŸýýêC®˜þù£=5Gšf5D^Ù{Û߯?rgûäŽÚ‰—ÇN?©müºÛ>ÚwߪÌoï›úén¯¶}YõÁŠ­º?ÿiøÐô…wï4ù™WÞü¼ç§Þõäê7²‰àU±ª-OØ*|Ìá 'Z}Ý]Ö—›Î¿¾+öøoüÊÞk»õ%óþé¢)“¯_svìÓuߊnýØÅýô=·ìòÐ˧¼ûΚßþêô¯n³ñŸz訅›¯=éè+¬×Ïê|è¡.®øÅ•{¾pÐý?ŠÌøþ»†yôÆßûøé]w{ ·å©=g\pÚ¹w®»þãÝÚß<ëðËÞÿ ´õO‡þõÚ5ûþõ̇Ïù´«yÍÃç|ï’õ¯:õÆ•úË•¼pâÇ»î·ÑÑoßÕùÎÛTM¹éã믘ðÜUóî¹òÃ#jÌüdÇC×;“ÿöhÛç\½û‰/Üô³žØªyã~sóÏ^[Üøô-Ûý£ën:Ê|úЇw-^Vrñοyòí#?¼yÍôXó¥¥g¯{ûÛÓØoÇWz><-ù¯…'_vÒfá-²zÓ»Vþàâ‹¿ûßïtÆU[F.þÕÊxÙon=kÜàƒ{^öó»¿xü’—öñË[¾sÞ±û¬¸ø¸5M*žuÑféÝì²5ߺþ‰¡Ž›&Üýϵo]üáe̾ú?ùø„®wžwÊv».üù„Ã8üèë¾[þÐCGMøôÚñýO|Ðsê‡;<5ûK³uÓuïþHðó¿Ÿ=õÖÜ7cÚÚôí·MØý¤ÎÚ.»÷“SCó__}ÚÒm—ÏÿçÍ®]¿û)ýÿØ»¸&޶¿D/DQAt$’,9H¸­\" Q¤TBŽ$æàP¡¢xßWÕzÕRµ***X¯ª€Šw=𨢭·¥j‘j¬úîÌÙP©o¿ÏÏï÷¾?—Éf÷™™çyfvvæ™ÿ<ϪqÛc—Ç¥Ún}5ØáþÉQU]gç:'Ø=8Q;Á^2÷“³ùî…,êº{¦-Ç¢1}÷äÖÖôÞÒŽïq:¨Ôºö«N¶[ç>vɬ’5„äù}# ¿°ëË‚„e«Â~à|ex1³ç/sÂ+öVO:oÛ˜¹zzš|Õƒ$¯ù·³/¯›ãüjyIGß áþ¡<]¦²xhìµÎ>wn*ªëÕW{_$(óE_·¶.OÜ>É%ÌïÃC‡„l JšØÒüßÌþì\¸ÕG«W¦¼3#ÐÛì¿")Xÿʤ™ÌKì?^BOÉûÏû8Þ`ÿi þY–øç«‡çá_ÖQ±¡¯_¿ÆO‡Už/À¿X†¡Cbþw/§â?º@#Ï ET’0©4©”•liÝ iËfE² Ï€2ÞÖ?ÿ‡ÙóO9¼ÄÒßé Ð[ž±§Tðž/±Ìï ðA&ôúðü¿ƒB~0ª®‰Å` ÈÛC(òy¡"_‰ÈW*c,Q@PŒòþ©Çh×Ã4ŸKz™!–Æ]¹ºR¯ vÑúª5.V@n^S¦ð8|ÊG »O¸t¦¬g>0[£Jޥ鄔V –é]¹†4•ž‡©ô\U<8gÎãQ¥ Td‰Ty¦^釢ðj>üÌ»+LbSÉSR‚A, Si¦¬9 ¸<Ü©üIj*@é jcf¦Ÿ %Òp°4G'×j)ˆOx¢…ð~9\½X‚ðPrÍ †ÛAüėʇtÍ—.×kåjè™O¥¨ÔiJøOéx:Ø…) ' € Ì4¹žØ€ 3£ÄLq9þ)ªl"TF›®E%(»Ÿ?(¯Ÿ¿ù…S÷ãðHMbZ9ØÂÅU¤•ðª1Ëo´N…‹­dÓé0àVN ÂDpaL|4G* hŸL•ÏÁÓ`ä• Ù¦Êä% 8IƒÁÈk¡‰¡pÓQp@ÜÔÀê®J1¤¡*3< æ êÎÑærH~¨ŠÒ¬r•¦VÔ¬Òév˜¦%ãZ€*1刧0'4‰4%V®>ø¨Ki`Š+—h“Ê;¹d˜¨.â²QËÅ/ø½©]“­Ú\F6LQšó)7¤ájÌåJÄÍ·;%®)¨êN²Ë,˜)¬Q ¼3pÙ´Ðl>j&¶Q‹ßn®€–,âùÑy>€Úü×BDÍÞÿÐñ€€Vù—€ßŠÿ‰šÿeRÙüÇ{9Þ0þïþÛ€ñ?WÐ1ÿr7„Ž0SŽ6bUYJ$[‡Š¼Ñt£ÆUÁ?|¥_±uâ¹ÓåYB-×XwîâÖ§øz%XI&‰{U€V•*do5:02A¶ÍµýSÞ ÿÍÓHÖøiyyù¥K—V¯^}ëÖ-¥R9AðIH9þ™kkD:iœ¿, i6‘‹Î‰s;DÛXÅoP–¿zý}û¤i{N“¸}{”ÞØøvÈ–ª¬’òüßój粨ü¾µ_ÿ3;–ÎO]2µ¯uÊ4]ñš ë,)û¹H|hسê.vŽeÓÖ¦µîÿÒàâ±o¥³áÐqPàøäÆìùOàÚw<øGÞ>þ{yñ¿Pæ%JeR0þJ¥žÿ÷qPãªêáàŸÂ} =Ä"ü9÷•úø Efcöh0È¡‹)B³é`0Šf4ðxß‚Ãñ¾4©L3Ô|Ê€óÝ&ÓÙÊ©"“óÐð> í©'övÞ'!¢bËIp79à¸Pìe2GäpqÇ¥GüÄЄûÂY ”9'1 òÿšŸÙ|¥',`À ¶Ô+u`ˆËåG_6êTø5R=´7I¢Zð{&B•Zeˆ$|ù´˜€AcJ·¾-%“È4%‰1Bhµ/ –Þ÷oÌ~0“pk°<3ÀìÌê•Ò!ŸÄ㣵dÓÈTÝ^Pü=bº‰â¤ø`]£Ô¨¡#)õh2Esðaž&ƒÑ@Q@›î76 l%NÃë„¢&æmùŒùÍ3ø”`¢@ï‡Ä÷n¡Ä¼‰Ëњƶ`g4CÀîþ”Ëà0†ìªl–fÈÊä2ÎÓ­Ÿ»è`Z˜Àt—ã’#Wðv–¦J¡1êL™Lšdx½Ä¨«Ar—CÔ£a›WeG} ÍLýeÑÞ|¢Ès®@Äg¶N’Ô$ 9å£Ó’3οd &OŒŠ¦ë2E†æBHÿß=*‡9þx¨T¦ ×Q·w®Dô.¦oyÿ{ ½Äÿ)• =e‰Øÿ=%ìïåhÿÙŽÿcšÎ!4þ³U¶]{mø>j ‚X41:‚ðCBóüƒŒ>þ©W†»(ÅÅ%Á‘=ÔÑ1¶#{¨Daõ±†5(‰.bY’TV[Û›{ûÁ}û*\\½z%99%té1ÌÞ>¦}çÈví¢ml#,­#ÁȰéHüdädøniVQâ”vI NÝŒ(‹—øÚë÷‘ô’^¢Tÿ ßmê¡Z¦Z¹O2ö›ÂÍÕS—v3le9ÅXØ„<ù£qÁ‚-ñ “ïßxüÄ¥¡17oÕ}±d›N·ø·ú'HÖ¶±þñÎðe쬻Îüôé¢ã¾>àÄNìÃW¦«^½zkÿþSmc; ÌGÆìDô»gü¹mâBõWû7ý1"kž“K²KßÌ“§®$)f 6ƒ>’dÙß_z¢ÖÓÙ)¡}—蛫Ξ»Îjï:VÖ_×!¢(xÉÉñ{'MëŠ~æÄK}ðàq|Ò¬ÊC5ƒ¢'²ì"0M貓µu +Ö|?c^éÅË·;³•v½”k7T öÑ{ÕÞ]{ä [¢wrÏÔä|ÕÝ-ÃÞUeë¤hãÔÆa”]ä”o¸·îôÝ®«_]ωu¿?¿×ð|Øš³{dz½szŠôŽ˜¶ /«šj騰pHê;ãð¹» ËÞ¹ù艽ò Ÿðñi%Ö>ZzäVGv¢‹OÞG^¹]øcl]ÒÛöN³ì•ÖK–Û«ñ‰(d )r©» ¾QEˆ[2â7‘v‚¸"ˆ?‚xà­¢÷„?Ú‚øôO˜ƒðUHmpâÂäÅHÐd„oI]nÃÿ,aVÉðY%HØôª–î#GLZuøÈ‘’]Ÿ¯)ÿnß²ý•cW툚²áãä%>‰ócò¿út]MgocàXvøD—șܨÙnQ³Ã§9†NéTdׯ°½ÿŸ‚6^ù–žcûíDñ‰ë}0ÓX]~q܈c÷ƒ X²Oaâµ»QÑÏר¥š·¢Ëââðö|ϲ¸ifZ(>ó¥jÂÒ¬¼_Õ…¡ë²'—n?±«ÄöÚ…s .©c8ÿâUÁ½ÌlîëçJ¿+_>λþòtž,e{ÌÅ5Á/>þ˜ã„”\{ª_ýLj_5as_8ûošÔ´°ifÓòº‡_¶~ÑíÅÜ0íVõ Íœžìý-¬UÓEûv6×øÇ/í¦Ÿ*Þ+ȯCŸ”?]¶¿©)éìúÂWÇ‹k—v+°=¿F]')zÖû~ÏìúŸï…Žz2éæ+«žŠ„ì2îf‚ÚËïÌÙÌŠI܆®¨m»W‡Ö<âEÖ}>ò`ØhŽ•€;©Ûë¨bÞ/]Û™¾uÖí¾õÓ?>­·²¶™z¿ÿ+¯¯¾[õå©›Z䣥!ÈÎö†?ÛÜèXãlYUxpj›œcýµƒK:ͳ˜é)ZâÝæZER§úðz¿ºƒ¨vn±½²¶WÎ5;EÃZïõÞÛÚø¤~oaàØŽ×N' /½Z©f­Yí‡Æ {Vh¾˜v5P}o)ÿ]h§!3n? }þ´f˽lûw.8ûD¼©üé°»#7Î;û™Í…ëû—\˜X¯?ß:{¡wÉзŸÙ]­¹R3ƒ[n™‘1nFçèØeWƒV"¿®Ì¾ú¨[΀=»mŸ“±kCÔ›~è–º{ožþrֽ̒6Ã'ïL¾·ãàÕòYCôóœ÷Ú%=ëµøÙ±+k÷»õž¹©àÀêâØ—çkfE¤[V¬ýúÅå[hùËé Än*7ôÉÿ%pì§Vµ~³½~ûÏN!Oê]â2FZZï_'Øú4w|¿¹ÕÁ÷6]l|¹œ;EU¤þqñ×=J 7º>ï÷›tëËòñÅeû~ŠŽŽ™‰UL¨Ûø´þ [Û-[?>}ÍÚ®Þ±àé#Ög¥q#O?ë|rc+.¶ebŸ-ÆF­Æ¹Æ«&°ªiü„=áq?‡ÅÏU°øhœxWS¶õOvÇ®¤¦&lv?¼ÐoòŒ/Åw¿°{0ÒjÓ –à VúqÖD´éÆ–†½Ý†Uõõ˜°cû‚ª…Sø§ä rÛ½'f^~¹wÞÊ”o#Ç_¶¾žµëSGn{Z²Oe×çÜ)ï_ë‚,íþÀàÛvΣ>·<æ5(sÀ–ò'ë-÷p¸“`U|ZÉÙyò³û°ªÎSQšÚÁívÕfbñÊýõdrý¼îž¬¨¬¬lÜqtw]ú¦r®¢¢æÉcÛèÒ }ëº ©gžã’‹Ý*íþtdûå—¶œM[Ì_y:ià™««k÷ÙmªÝ#ÝbüSeË©;¬Î.÷7£Ìq\Á9Cuˆ‹º(À*ø/å‹Â‰=ÖÙu¹¹Ž/Éi<íºÚ™£Si‡4Ý.+ãÅüpÊÛ#ÜY4üŠ|Љe³Ø u›²`ŽpOôY]Þ×ì¸>|ÕûÚ»­X¦‹«»?½Ê~Ñ PöÚ%Aîíã'ª’.m'¯M]4õÈ‘ÉßùªjnÙ/²yÔÁ©ݤª†î‡£î¨¶­¯Þ»q—dʆ©öNº¶q¥KÚzI¿d€lY%öÒ°rÏkéëÖ6nÎÞ|F-#†ÿpƒ×‡Ãì0·ÿËuÉ9°ÿ¿Ó­Àÿ|ÿ¯T Æÿöÿþß-Õ¿éôoþûùŸX$ËðúJðkBO ~]Œÿ}Øÿ÷^ÊþkVß„c""óKQ¡¯ÄÓWäÅ4ãÉÐ)lÄÆ&=Ú¨Ôåa©jÌ”§¹}—2%˜\bç£ ¦­‰\&&Œ¥ÀÄEåßBæÒ' #b뮜A8 hú­4p…Ìâè{ÌrÆgäoÎ0²‘ŒbÈó&nxfbŒú§rk¬V6%Ô$§+RÈÔdÚ¶L‡«õJà:O®Ë0j¡=›!9´AšA0Lù²û1¯Ã½Ò0ƒy#'M©Ì|Ó à]2Sž÷¦[i~’<ï7‘è3[ !‘!~¤¼$ôƒQ¤‘ž¥&cI’ž›1®°àÍTOÆÂÓêä)*#0¥z{’¹éÇ«h¥¦ €8üŠ'¥øª\Æfs4jHt*#%H·Ê0Æ‘Ó0µƒëŠ&²ÄO1zeg¿/ι²Å"cPý˜Â¨¸—ˆq1ñžìÿ µF­ä0ìpy!‹Xxk&óû¿Ó“ ¿'\)ŸH†‘Qº¨˜aЧ;–abE9Í2äø’Rð™DD üØ”U)¾!# u,pé à!X¤J¡Ó€Ð¾X`¦6MïFhä)J— Í`Е|úç6º©ÀÓhñK:E‡º“b»£lMŸÏk¶Ð@X«a‹kfÀÛb„JA- ®GIK8àÓÑ<\U>ðöœòÇjþ¦#…Mn„¼˜ÂÌÁˆ4øgá“1½Ü·¢ûà0Q6 GÃÉPæµxëÃokqÀ» •¡xªÀØ]x“(vhXP¬f`L— e¶B÷!„O|.Ïïokë-ÚŠ‰a¡´ pe‚øLŸ‰Íˆ™jÃy¥D¥9Ç?ýlÌDÄOð„±\ ˜‚¾Mi?…6´%1ß,àÿä0ÓÌP%ð<œM…6€.êå",£³Í†žÉa0dÂ?7$WWßD>$9þJÇ,³^˜¸ ²Ö·üĀƗËGókï@«çx ³!~ãïr ÙDãµ+!€¼w©¾3œ`‘€¢šâÐR‘])ÀFÐ.Å@·¦0Çø¨Ê`BGSÁ‘ãØóÑ)9ð©ÿ+Y|s2óõr …uuå2eç‘©¹ûI?ÍÊ'Ç|x@\Ç ¿ 7$ˆ7KoJ`Ðh™ý¢ÔÓÊc6èx¾–4YY0ª ‰‚bÓâºÔý84×לg¼Æ}›1•ÏÀPP¡á™åµ9rД˜ñ©˜e‚ž*µ ^ÕrÒ@¤7&:VI }òp±\?óëñäõ<ê:$BÝñ,I†#Ú…”Ì›±”&Q‚ ŒÉhóAÀ¿Øû¸¦’¶q UzB! Uzï½w zïUé ÒU,PQÀ‚"Mi"*HGXÐ{N®»û~ßÿ½ûý~÷îÙ5œ3å™§Ï3sæÌèƒÇCmžÁ½büÛ}paû–ÎBómƶEé–ü´Œ-•³…g9ŠÐŸýŽ#Ûºü-æðîPÙíÝkž¬b[´ÅF(4ògm*ù³À¶½75ºçÏ8½ æÍlBÄžu?åg‹ÙT[Õÿ•ÙâÉoÔæy‹”Y¨3~Ëtp×Î,èËÀù=]]7¶YßèðrŒ˜¹5†ƒbðbü%‘ å_:CƒÍÏ67þÜî­·¾øsW ª† ÀŸõ…/½åy·–ù¸aÝÝñ{5þn:!¾ÛZƒNˆñ¶wäoF€?W ýÚ8–†¿rT }{OOˆV<]Ày…Ÿ]þÀ´Ÿnœp\F`Á7À#w”[|ÝÙzàƒl;ƒÀ8Œ€Š ¨¸#³}HÖ‡¢àøª€s@o  ‘ÌΦ7;´ÃÖ-ÆÁaGH‰mÇ&²]ì¨ AûzúÁ€ÀQ”€€Ó–œÁ8’ð-­ø„úþ-È¿² ÄQ n¶Ãï¢â¿ÔœÐ€?Õ k»Öì4»üÁüæC“?7r¹¿®ò{»ÿÕÿm„¯ñ½%a2lã¸)p’%x;¥;¢í?£×€bKñ±ø³* [Zü©ŠàŒÙætaêiû¬ É¤ŽŸ–!ø`@ðPAoñsMd‡?ßü"hsîˆÔv@Åß»øÿç Ú²i­ æ[³ˆÿê?'ö„¡0¤$¡û!ØüˆûŸ‚Âü)¨¸ƒž<‚¿ UL?0)|êÒ¿Œ‚â=ÚOâ¶Í©mäl™m á¶[~œ(é‡okœ¢b‰Í ™í³R[®î?MÚpš?¿3ÂmLŠþœ&úôÓÎÉ¿_è’Ý{þœúsÙÊ pè¥Â JP!~ %•nÜÜÜ„6óMz7:Wü¨Ú‡@8~Ââ÷hýþSÔ-¦ü&Jðªó³ÌÏ"?#ÊØmØþâÎÿB=I†¿¨BüDés3['úÌÐOÂÉŒ[§znúœÍI–-WŽÿ·„ƒ6»‚i¹ƒ‘ÜüˆÿçK¡ÿXÊù¥0;KmôBüB€]Á‚€þ-ªAþB µƒB3Â44Z HØ& (Ìýw5Üÿª†óïj8ï¨ñÓ¥oMEýùÔ(V|ÂæÜ8 Pé?|Œl‡?I\xŽŠi%Tù9ص8Œ*Þü´‘¿«%Ž€JþÏkI" 7j9üVO%HâEßú€f“ ÿ“J$6*9üjÛ¼èŸM£Šê `ë 4„€º# Î?5؃0½Fˆs6îÁ¸mcÚ PgBY_ ø-²T^tbp@½|À¾ìùÐp@Í|€›` _ñÞøˆÄ TðÁGç¢@íÖ`‡w2@¨Hðþ›Èyˆ âàÿÉ›?)ù÷%D7a9ìÐöÍ‚;˜õìË@®À<Á®ð Ð’ArÁ$Q|’ǶÉ[0N¾I'ÀÀè}ñ@ƒ¾ÈΘ50;sÅ\̟áRà$xÀÂÞ*¾ƒôÍÉß¿rŽ@¿° \q>!X€%€ZÚ°m.œÁûLÞI<#ï þoCþž~[±8~m‹ÅA ÜŒ¹¶¶‡ì[Å€ûíÅðØ€GI`Á±9„ j) lIÌÁ[d?ûíhscës¡ß>]‘´‰9Q–O¡ÐôyÂsÔÊÈfÑz þ鑌‡ìt oœCiÑÒ˜X%²”,{Z£~NFs8ýØ+—TF˜õ>=ÍÞ•Ð66‡##×¾œ{AšTqÛV´&ßÎ$@0{×õ…¢k‘\dq —tö ¾ÓMÖæOgªb· ùÔžß])¤Le±/*/©zåÍ—ª\¦”–ìûÎ]ݳ?¹šZœ#Û-Äs€h3Õpvžh‘¼PøÎ>µx!Ä->~ª&±WضŒî6–Ýuµ®o…9²ïÏÐØ,ühS/Ž¥P!’©Ò&gO!å?\õ=(«ç%Zøðâ´÷õN²ð.ÒšŒ}û¨š³Ÿ‚&Á©äoº•íüÌ{öç]Kåĺé çÂë"v#¾%©Äæ™Æ ÊÈò˜éÔ‘›ÊC:©g/ºê¨_ʲ)x@IÛµF¥Œ9Wä&Ï죹A"Œ¸€+$iͬý˜Aµ…iƒªØé¹ðü.u]e(÷쮱ܘéJ7³4Í*ut¸ù¡»—]h½uè i‚j;Oy_ä½DÅ^kH>ÄŸ¤D`.¦Ê Ñ3°2£ó®˜Ò–ñåÑ@¸z¹²Ùùl³péWR–°˜¢cé¼1 ËOµõ(ªQºX Ö¤Mé¦a«WY?ÄзðCž ãͪ.ñx2æÙu0Á}9BÿŽëGöC!ü‡?VÏ}9³›˜ Ú3}ð1¿lcÏÙ¼x¼¨‰…“ sƒå¬eswÎ Áo*ǪøoÍËY(Ü2ΊÂH ïÉæÖ=Þÿâá …aÖñ“öoÖ¿ž^f®£R©ÍyUöñ¶ê~ôêøãéÉÙÀ4¡¶<¡+‘¼B&çP($[ÍŽE/r¯¼É ÓÊpÿžl™üT›WÈY'ÔbVxšóÕ‘Ù`L’Að—6K¨ä-ö ÊpÒ*Üÿå][©<§ý6Ï*Žg1wí¯Œþ|®[ùÙƒ¬c(øPYß¶fƲå?BÅmíŽÒYH5SŽçk & ?èªîØÙs“Íöcï?¥P/Îaaa[ פUyó4ƒFè#O­zq!;-4ÜÆëÕÖÄÎæ!³¢Eâć¼{ï)ê ¦ 7i'îûÊ’£ž›@ÒÑop—]y-–úÇy½#oí>>$ÀÂã\`Ÿİ.Mz7J·Ã«¡úÊhºøâYv¶Û1Qº'œ÷.ÞN*ü|„õöëÓ_`˜7NºTêVD÷ã:/,Ýøö?ÆLýÉÚq¢7w¼WÝ/ÜX§‰ç¿øãFíèLúSëó™¼dÉW}F÷zg¸›ò½8KåöÄŠã1‘E‰ÅÌóÈéÎ%þómQ)е]Ø>^!jë]ž:P±å_Y®ƹ“½5ÿ”ÄÍZøÌÛ%î1»b×Q*1Ì®=¦£®Ž‘ºò/YgG£tqÓ"#F™cDò—›_¼~y•/Æ|äÚû¥Öqèç·õ'÷LïÖ¢’_ vzQAþJF8ÆÞßõ¹ûæ¦òÄÕ‘ w¦ïû¡RäÛ ßR›úôb¿=Øü×' žÑò}©ógñþ¥ü)ü›õÿRÒÉ_ã?q©×ÿÿ#×oâ?pï¦6|ü§tè|%d{ü‡e™ú$zxë`Ÿ‚½·–Y:ª’àA£NUf‰:Ë ¨:¯ÄúHs»—€ˆIµò;Ùt+„ÆÕŒÝó,Nn;´¢¸H›¥|Qw¡äTnŠÏíå-¢ŒâœC35\×øÐxeâJãnrèÅ»Ÿ|®¯æQ´wkŸQ[aI¿Ï ¯Û|ö[æñ²/çqp¬GѲÈÚ _•>rñ=eÐ(¹¶ª€Uæ_¢æ å/K{Xºsåãf³IŸ'¾Ä~7÷ÊeJII>Ô‡®¦Î­34Þž¦¾1)äGŒí$N+!i/Î}?)e‘a7/<Ãj95AF܈Þ+óиY¥ LX"n “'J)‹ ⋤ìòÏ}ÞÉùvÒo8ßéjRpZDçÆ­®¥ú‰Dvލõ›%[œ WcTþJ, büÛ[:öêZ@̈́ɛR£»ÊŽ*ó6àJ ¯3ZO³fe žÆQÀÆå‘H¨¯ݧÜ7©{°Ó›ìÿžæ^šž®’ ³LÒ[¤¢‹”2U'e„èÔ¼[fP -9†MÄ,"Œö†ÍdˆYþzµ }Š»òœ­mqWâÆÏ=}¤Ï3&@1Ø#¸‹FQ1IŒ]*ž^ÞiîGUéîþêéž\²dv†SCT¾»ˆÜãÆÇöR> ‰Ï>{Êü± ©bE¬e0ÜÆ®Z5€’hb·û;]ʶš§ø$!”{‚"W]PªF¬mìiµ’ú ‡Í!4:q®èóƒ|ú—ŸÜ >á¼Fî}ÓáºØÔ šÙ5eg¦|†ö]64RZ™ñÄ?/>T€+Ø×é‡ß~‰Åô×þÝ:·ioÓÛÁ"¨‰Ž<ͰëÙÿÆ÷²ÖqM®ŽëÚ°}ÿjÜgçÕùÁÜï!ë稡¯wO >½ö÷þüI-`زÂ{ßë0,»CJðT_ä®H…ν×TrÜÛø¾EÞ=K™ Àr’–­ Fz ¤Uáå®ij¬Çeÿ~òW{é[x”’ž ¢n ¹ór€în«ŠÝ¦©<2áí0ÓŠ”6š¤KÒ§Åèa²]k? ÃÁZý»,³ç¡FBê›,sh©½tHå¥ÅY6Ç|;fÇ]ÃðI~ó›Ýß’Úzˆ˜RT¡h”¾CHÃÖ`Ú…~l]4#-ŸöjHÖî×þzs©¯‹&¡8Œú‘ß…ºë:â Ï›íöß·¿w°å›7÷Ò}îüAíýdoßð±g½©±þ¥”¥û)«/ùú{{}}wÙ¶çñz¨FÎ £Š®xjRªÙX¸ßž<1ñ”U’ÏghÛX’ŠýˆœyÕµ¬Á2Î7)}~5ÿ‚XKíæ[ÉŒê¯yíé£DÕ»¡QÜ­'x¿ %UA£H>pÎ-TŸé‹*QU¡Jv¥!š1Érb"2£(Ðl¦a9Yê¡6`¨œ É}Ú”s¾©ìîÕ¼K.†åoV];Z_?|iç$†­‰xx¹D,ÑCúÆò×È DýÊB6¡.'zHª)¯Aç„J¾FöëM¾Hpæi(ìöIu•eu+‹Ø•~¶@·ÙšXø–ÜÛk«û^`ö‘ }“ö¾iÌeäN™(g+€}•½CóÁr¾µXK|V§jnŒ&é4Ã¥¸¹ƒýá*kÕ‡ô—;xoûeìo×g‘;û”¹ý;¬¼”]+Nwˆó4O¢Mù’ñ ŒöIS!¤UzìäqËNdù±Leþ‰'è”ï)?º8Pç³2 ›æ7ÇÖß_ˆñy­×Ó¢‚¯ŒÆS‹æÉ·´Ç“™ˆt'év',2¾m&I¨Õ OéK§gJ©&F!]Ÿ¨XÝbÐà치³°¼}\ së«*ˆú å¦É—™~ÖçˆZìÝÊd ]öÄaZèø6ˆøñ˜õ]£Ñ…sJ†”’&ÏN+Ÿy:‹E=—$—í%u}ÈÏàÚ¥YŸP¢r%iÎâJJ–™ô%l IžËÓÖYêz€nÑÂu †c»)8)‰´¯¾{bÀFÞ¶8SúUU<§´\î.Î]nÊIá8Â[Y¨ò¤5¥ŠÔJ¡…Bì¥u:EÍäTÜôiÝY¯\¸ÕÂHªÃÇ\Áô›û±j’e†4{)näï¿ÞS† «½á–¦¬´k×z|2ï…s{ÏÙäK‰ÓGHßq­{tõ“ÎûOáe¾£A<îbåX”ÓJ‰¦>­” /&8Q‘¶D'‘7Ò”iÔ|Ç´h\©9¼;˜˜Upå €Ð>ÓÅBcnÔ9’N"­t…›î÷ÚœÖÉÌÉò|¸¿øÒر¸E$ÁÅúáEdîdôÄzqŸN挚çT•v˜Öãvk)ÖG{ΆS’Š•ˆ…ÍŒ3R'NIŸÅ~Xm>…b€ÌÅy6ËS=I¸Ëxï™û·F–¯ÇÜ?JvˆÇgóíç貋ŽnØß²+IšÏ[(2Þ¥ÆO—⥤ºf€ºðawIJ5œ„ËÍa‘u˜ºäý‰ñ6Ó!qùþâ$íÄÄYêgd^™ž¹K.G¡ðÕèQk‹3[_&;{¥B7Ï7®‚¥Dº7 âDæ$éf{²×½Œ1ëçMë‚›Ž\¬‰¿ëU^‘2¿”ÝzAKöJØÉ47Kp;]õÓ9l…ድô 79{ \uÎQÐÌXˆ~øâOêžÿš•eÑç.b»FNt¿„ýÅã¾…2óãºéÓŠÅSŒŽˆž”›o†6/¯ù1ˆ¦xTO’¨›Þ·{J9@[bÄ|ÊZ¶óa?Ó¥–.bÑŸ Ö4^[£ål…ÊœÀB¾”ð§³°g8sšjÏAÚ(«Cµ»(ÜÕç%û'⮞ z~¼lôž{ôþ¥’d¦i¦dj– _NêíaˆI÷½¥™öòƒJÚËøe'¹ Ò/ŠSŸ’yEr‰ÖÙ“0ÄL_65ßE™VU¨Oí^*C§açœeÊÍ@N'êpx–á*+½ÄL”k°2ŠIð å¬ü×ã3ÂyWäißó UØŸóeáö‰½×p‡FòŸ¨½pÿF⹂ŒI¡—_êk=:‡-ゼ«[ˆÀ´Ú'ÿ6ÝÊŒ)áÝì@ÂÙbÑö`Џ5¾=k"ÔŒ§’fÝ/7å® Jègî#kÏ,Å==©“rÞ.áuâ†ç±óm=9CŸ¥2ö,ÁÚƒØ nRäñœ}*eRò¾@gýáù´¸>T–†ÆKT—³ еâµ—ePœMÎb]e?H(wHì-R,»ça›ŒYí3ÎT™ˆ»÷%O²n3l{ªµÈn¬uû΢éP«áø5¶SÈ‚¦»,-Xò{ߟgNy°dŸuV¾Uû°üûâ< 1•2ÐÖ«ùÌ9]år Áæ‹ ^ž;xíeë?N©í QºÍw“®K_ ,ž{.þtÀú&Õä%VF?Öö8'bëØý.‹ ìF e¤?xˆƒ‘wb,xÐåol¸ùÈ&å¡êKè÷%ÞÉW°r9Í›çï[¨?¸ëÄšþLUBѧÊ>þ 5·'ΩdùÂþ‡Š½µ”*h^ßå+x$ט†.÷–±ÿÁ°þÉøà859ä=ê«Ù”—€Ýì‚]ÀþÁz+þf 6½Ò=)æì4þ>ä Š¨ÑÑd¥#a5-Ló^ ¡¯V¿fjIuTï½ç½›ì?ùç,'îüˆæ€±k•Þ$m¿Ù`¡±î,œõÙ>s.úq‰$ׄðÍ N';‘Ãil‘óÓº$êô›…,… _¨¿h·ø‘\cËDWq2H bYÕ(tk/+™f%goÓ¡è]|b¶XÅñfŠ´Ñ»=©0£þýÍ09vî9ãlìãȬ<}~Qìcº>H*UXÌÈ—¯ÕÎ ¼Œ‰¾*¾’úúU½G?ï“»F³)S€³?ò¨¨™$6‰Û·$¹öðz/ûš­£»íì®Òæ%ÙÚ)Ð.y]‰BËxEÍåëv§´œÀ(ö¤ð„b™÷ ¬¾úŒÌ%'‰³é’i¸IÔòõ«F|ÿ#w&ڜʆõ,7#¦o¾ÆØ¹.Ä”`ɬՕõ/hxèÇâUÿd¡k#Õ/\š4ÑÖúeÕ Cwq~ÄþFÚ/jq¾éÐÌU¼/×£;L5ðˆáûŒÂíÓè—w3F }ÞŽâm»ëä'öa¾»OLTï½^".šáGãî)ó8΋”TϽõ GÂדe–ÍŽÄŸB=“¿È>[*¨ â}]§®t©†hè ٢ͅÈ7½ýƒîŒ­Õ ù/Þ'¼ìY]5Ð=mtÖ±:ÌÂPøírŠšÄ›…=ÑH›±·¡ï®Ó£ÍÚ$B'½žPXC*R[q²‡GîÎÉuÇÙÓˆJ¿L_–Bžó$~Mm9¸ô*^ÅõÛÁÑhæQ#Y¿ÄŽˆ}ZV^ë1O™¶æœšó\ 7õIxR¹±y ŠÞã:ÉK$j“Ov¥ñÙk×̳߉W´ÝÜÇ ìN–.Š ‹`ˆL“¤o¿?X¬}Ëo¢ªï‡å’rÕ›>ÆÇDO8eL­ìîß[¾¸‹´ñ~<õ¸ ÌE㇠­H†iƒ ý~–Ø+ÄD¶¼l/ˆxË9®QÅZò~`EñÈ\»»ÊÚQ€P85#‘z+§úoÚ0{o†Ó!Ú£òª_šú~í|”ò(ŒáŽ väö”õ„äõÌ]õO¬¤›é9ofí·ûáv½,Òî9âÇ¥»†/¿e0â˜àЉ" C ì.dÙ—Qö.“êÌè"ëTǤ"¸ˆìs?ñÜqn=m±Ë½ QÅ+t©žÃB2“n*o m÷ž$^_jæñÔP».×C…†Ú‘Áʳ6¯ÄÕ®~´µ]ÐO‘}’ò‚5Uüt•ÇÚÝ”ãŠÝF_6áÅöNƒ8…ãn‰Œ}Í‰éº ±A7Ÿ }#Ŷb;~Ò=ã³Mâõ£Ó°ŠúûÉ-ÊNÕ>‰º"šÝ×ßG…F -ó(Œ´”3v–sxY*.=7XŽPsŽäÚxà<ê´þ¡Væ=RË*–añÜ×g_fFÞß©¾12ËâÈüµQóK9Õ{žá¶l‘eækIæ‡ãUÌÄÇgCÜ%\5PVjU}˜xY•ØöKŽ›ç⢟œvÑo=Ö·VdZÚ®ôXc¿ô¼›ùh‹iÏù›”,J–%Ìj~ìNб-xê˜ðTêGTâƒK4šòTï˸z¯x“óO6ÀÓpdÍ n4z/=×cíÞŸ[êÏ’=ÉÖÏ>Úíë ¼rר¹‰×ŰžËã}š|ûÞ9ÕûyÔ7•Û´$2z§Pô%7?}Þ{=Á!~WpË2Åæ3Ptþ…뎭FÔ þc3“™TM=“ôçŸ/4<{:—.þ ]“jôг8TE¤™þùÍüF­<’\AÊ“OIÌýØùdô•Û¥?øP·@3Ôäc€}IQ)Æ28sÓð³Ïà­VÞsžRYÝ(}ä0e/]Òáx†ÝÍÎ…1¿¯˜¢" –0猇º=‰íd7 <ï.Ð씟˜qvþ8ʇ‰1Ú¶4^ƒ¸”zˆÆÆn‰O £vDŒY÷n.Y2öyÔášÅs*T ­Óü÷^¡_ôðÞñq²å†ÔícóqêØ[£°"ÈÎdÂøffTðüåñÎêh¾+DÒlm âO—C1ü uËŒ9DÁ2 W׈ɣ{Ïe„^k(€(‚¤2‹¦“^¿V[2#–âÍ's¼å=Ü›ó}qj½;—Ð(:ULª9öýJ¸ò“Iê“\.'ÎÜw½uýMwÉ"ÿÚÊêJ¿Ç·°î6Tþ}–',Ɇ§—„wµÉ_+˜—öZË‹7¹[žÃ_gKßßœ\è”6+S§3@a}Õ¿oòõ݉k:å†#5t¹ø0å}ÌÊ5ûÈôÈÝúôR=YüïO»åRÇÉ º!Yé:L#kã ðL\û~ðí¥Tk· jû瘝_g»äÅß–Gí3þð@vŒlä³DBl÷»ÀÅÀjÇŠPU¡B‘~ÑR£=,7îg 1¸jÏ"ì]è—ĩݜa ó¹mZ5…ú¡÷ï{Gì^vc?H²Èö^§õÆXlꉆˆð{#XH¢¶Ç‹Ú¡[§؉,Q º÷ò#:©àv7LûzJìn†ŽÁ‘Û >{ƒ’óâ&«†:dך•žŽî!'Šöð&šôÆ<ÖÊ•x>Ôqöä4ט¦íÁ'Ñ»)ZŸŒÚÆú@FJ÷ú¨ú;­4ô« zLo(D^AM1à*º@zâÿø{¹q‘šÂkö¼V²ãw¦(Ç&>~&7!II^ìcaW”,ºÎßǯ÷EÃö¦éu/í ¢Që£gVlCF%ß<½0s>Rr·‡1‰÷ùT°øàÂk¿aÇëˆáæÒ¢q_ïÏGL¿ÑrçwÜË÷0çñ·•î¼D±²-ƒWƒ3gnPß´u¡Ì‰Êó¥-©ó ™€¹=ºðñɲÉý'’Ñûr ìë?ÓË'2r†]-Ô´˜~·ðíªÎêEû¹ ŸùÅ›y™!z¶wÅD\L³>Á@„ö¹u4MìÎ(÷Nex+ý¸;9#p”X³þèIS¬5Ëíªý:$Iоé¤÷Y˜J“”$S½EšPÁSTÁ®PWwÇç³]x&øæ#1÷*ÏtŸCyA ›ôÕâb†]ÝÃÔ 0(„‹®ï;q>‰xžm,}¦ñƒ»'ËÕÙ°ZáÌê´ãU”_}Iš­Hpê|=›~lxôÆ‹ÕÈPÑÎcCƒ£=óyo$/IÞðL€ Þ½àiLk<àWŠ@Ë“,%K«¦àʾ~²Û7y0tì¦=wÓ¥¢¹V(à‰°5OZî&UâC¾Yy±?„¡Snd™éôˆîºvþõæ§"=Æç"“gRd – T{n„¡çQìOg¤w93Ñ„ŽL/…®ïS#RËû|TcÍá`ÜÃSyÜw㻵jT :Ŭ¸!ÒÀ—ÍâP³—–'/Öpb½»JÉÈ¿ÝbpC¢:Å_—Ó z„<ѦC”’ÌËX~½ƒÈ–ÛK*×Y{ÔsNSR“â:™£ƒñOíé]ã…=†·•<5[«™IY.qœÉªìÝ“Âb;z=åRÜîÓ(?ùäbR%ɵ‡nùµ!û“†¬Öºx—møÔÆz§uúÙu8U:&k4Ž/¬êD˜_yqÂä …ÅÀiÿ>Žùd}ÇŽ<Š›òðøY­«BgSêyü û‚m•Ô¸EsÛ¿yÞ“NkË9Çás7þAÿ—¯š¹5MôÄJÞVašõ¨ÆÌ½œb{šY„h8¥‚%yM8ÔBÞmjðŽ#fp_ebñ‰sŒÓ÷kȱ§æW,ìo¸|ÿ„ÔË‘sIÑ'Ÿ½k„}I <|én Öù…Ui½lºŽßüéðA7]ŽˆÆ.TÈîI¡YtnÌ·¤:Ùb›/,Ó¡Šn¹:4Š O“‰·!!?V“Ôÿ¼ˆ7 ¾BTg£ eËsšsêtá|A™[^›Xv3]8F– Ü%3²7ÅJ ¦]Ýûe›£èÂìós1#Ń:( ö™÷ûZg"hËIMdôÌŠwfµ^0ŒüBó ÈÞ&ëk+Cø‹„ò éÂ4›Æ@½§RÑZƒ“Å*ÔWSjt£ZsÊ÷záôóÜ1-BõÊnwõå!×ç«©¦œ«aB4&¾h¦'§D'·¤ç‡_YvÏdfûY—áñâžÔ÷†I?%ÓI–ÇžÔO¬3âuµw8¤ÖäÐ{®=¦L$b]ÊE“­/kR¨ñ+{ôQ˜ÜIµ¹W—üГUaÊ•w&ö…ås’ÉþPcõÐÐv1*ï9†ã=ÏßP óŸ8wUãS®‡µ“‡ÄÜöØ,OšléõÇ· h:H^™ž5Ÿ¾gB%¢Ü„‰â2¶$Ñrë+=GÜ„p‡US¤¯?ž`xì)œ‰nxÐ H%5üT*@pœ“zÐ=+í>‡ýáF©x¦ý !ƒù·á¼fSžœŒ$ -ä|^Óá÷cS²ˆ›ìLõ*G:»K2Þ‹9Q(12»§jJØ;¯çœ1 Ù[üˆÖ<)#ˇV¦ØÌ¶~‹câör‡T?St›:q¼: e’ÀÂ@÷ÉbÂåÚÈToëÝ—¢Ä×–üóZuŒ z(J€»'ˆá ;¹¥ UÃ÷L–ŸæêJ‚G6¢HàyÂ[©KÚï8ûòxÞ¢ïù¾cÌ?_1H6 £z <ÎPÅ6o“±/·Wl|j‘ú\­sFXÀU\Ey¦Ìó¦Ý¡v³[à¯9×§HDz•ÚA¯“1]áq±¡ *¹ú9é`s´ÙØ¢ ¾ˆËŠŒíî_üGŸ/Ô¯C“nàáDô•¹'Ü–€*Wœ,ú¾ÿBŸòåí†o£oP÷×w‘ݹ“‡ó¬‹\§Ã–-õ,__]é•}A¢Vär ë¥DôÆZñÁ5 [Ò7 ª¶IÏ%»U{r”_!"ö3¦PäÏöC µiÞkJÞ}|͇ɒ©V‚´ƒ™\åËEâ3‹Ý¿ÿ6ææ]HsWÍgôm æžm~¿Nt2ÐÙó¢ŠjÙ‡Ú¤V–gÊüÌŠØ´÷PT•ŠÆ)x¼í‰ÂqLõ“FÔ) –}y¿ÌAhH$Ú×h¶™ÍañZ< ÓX¾ò‚YToüšX ¶»S<Dj|Ó/rM—ï~ε_½HïßI­íֲͿ³/!œÚcÅZ. Ž<`¨°Ÿ81äÛÉõzӣöó‡žFþ¸&Ô€øŒ¸rÙ–ÝцQÊ&óqc˜â}Béž·]£í‹2Wš£»ïÛæs}WehùuFüíØö‚D¯d¬¨|Eé# +ÎÃù¢ýËwßuåïó~Æ:ÎÚÂÆøÝ¶ùE÷p×…P¸›Ͷ îAn¥Þ{Qr¨³Ý÷íòû’è5ûó¥Ñ}äZ«mÆ¡eŸý^VŠ”èóøÛ` ´uÛžwæ]¬ïtÕ—»³B%Šˆœb*KÞ–·å”×ÀòÔ;Êí7Þ@n{L½¦>×屸>Ö—ö™è\k Ó[Zïùç²Éh²º[n»tœÈ¾…PÔhc d† ‡èÎ<§½që`eÛ§Æ¥sÏxæž·fqzÏã ¶|ÀÒV@‘u˜‰ü½€ä=:ÑÒÛ“ŸzPq(Æo‚ÔY…/,êËpÔµ˜ç8áK¤v¸À…Ù÷Ïš3™ˆ·B8ý†û/)¨Zsȯ¹µø½˜Aê%Ì $¸v«ì[b0²kãjc|«s€ »F‚ º«©Z™¯$©Û¶ò‚YìÈ#õ„𔜞¡}Þ-óÑŒø×y¥Ûí5Ûh÷aÉãÚÃØbâߢ/Âmã³/©ÏÛcU§ïSü¹°7óZSWh›!{&w3ú|&õ¼¥Gg+ä%SówøÄÕ”EZ®Âá9õ¼tSQêï2>]D}cÍ×Z¶+î4!ÖÕ xnÞóòÅŒ˜Þ¡ðø>M”b×PX—½ª³£ÇäHÝħ´гSt”\nØ,\'ýÞó 7Ÿ åpKZFÓò]2{B–v=1hI|Ù•Õ\U#“t"¶.ÑÈôÀbÁP@«@Ôyöcç_ŠÄè´Í"HBcZ¿ò"®á.¾LÀîw>Rš µÜerÍþ©9íD{ ‚=løªáõºÀž3±N"OZ3©|ùau9­DÄ@ÃS‰b!6ÕèºË¸n› mñÕææ{ò3n¦œsÞ?àµÆìgâ„$†AŽ1ÑDsÏ“9%˜ K=.£#…ÁTž83œ,xµíRíä‡õ݃|IYNXRÇGŒ¡Lœt&¸ÞÁòJVAå{J4_¡òñ2Vç(©‰[iºÒffGt&ñ+Í·q!!8—[üÙÇÍ6N×aç]ÌD\šˆöZPLÛ„I$8š~ÑPCÅ¥5`K/##ÞjT|"UoÓ'= vtMjß%Ô§Êër0 úæfÉ™ö¸Ã5ôCho4QÒ»}–+$[ÚwÓ ­‘R=*üØCz$$Y}…ÒvÍ ¾ï$1ÅŒòëUeƒ9z•Áažô¤™7 ?V(/H‘’¤½EÊ¥{¦Ö2Œ¢Õªy34WöŽèß*oëüÄLšñEÌø‡©CÙÃó¬Çf,>†/Ô¨û½NŠ®ý~É^°ëìbŽÛ­8eëË·žk½ÑR—o*nÚ=œ÷ž8R€ƒ"I—¨Œ*Yc¼µ¢’µL%žH=œÔÝ›B!X-ê@f½Ýïݰ,'¾â+§òϳ^/¤l‰,é ‚`v1ĹúR¬¾øì}ëôc‹€hÒ¦wd¥V{n^¾q(–šè:9QwžCÚõë,2Éée³¥±›Äñ!ˆ(¶¤­y>²Nà#…dLãAZ™Ý$uñ!EÚGÕ‰{ÝEjÕàü­FÐ5ÁN’/ßHç|x|^¥ñ` ÕBœâè"ø’Þ;Ð…\I<²—*œŸ•×ý´U~ÞÓ%¼ |?ã%ôøíДKfçÏ;Ý=zþ@©1»rm€#©Þ)ÁÜȦ·‡~`¥Î~f¬íyjZ)5|íuLÎäñËaŠËë* ëÜ´^De?L¯'ÒÄE8´ÁzCʤ–‰œ&csµIOµI<²¤î(g¯UªXRC!ŸzIš©]º¡ú*”V/HÅŠ r‚_æún×'U\ ËžœÞý'Òj#ìCŽ›^GÇ-_Y"Z ît4X/Zjæé•CÀ1ŠU½–q¯‘Ä—pjÝXÞμf§wÆÜúF¡Agæ13„i u`'J߉û‡Þø†9VãIy—l¯_{òx\ú~º.EÑ¥»Ú"Cþ¯OµqöŠJÞ ›Š O¼ËÕ3ªB½jŒ:Z¶×~¤lõ£Ÿu ,¡¾ž\?Ùò`´‹aé铿T\o•ÛÈ” ÓMŸZÐ ž"ùÿ²`žRé}ç}óôD†KOZw¾x˜j\ã«Ý—w;§ç14ØD'®7“y[C žÜF”¤FOt&Ê®é"ÿ»/4² sâ51&ü¥C‚ŸiBq§­³f^ŸRxC¥$޹˜­jªD,jߺëÁÁ´ÒdÈá¯è qý¥b±7ú#ç\ž´¾«J'-Ý_T.pT†µK:W{É#OUú|I2ývLŠ]{íyWº›!ª™&ȉ´!úÇWü_8(&¾c„¬‡§Ñ©#¢ÏÏéy:óòt>˜0Ëø`ü²rÞWAš¼ûkÄM áÇ™d­¡\ C6 Ü»ÊE#Ý.ÁÚM>a -U#(¦?ï* Üÿð!ÕØs}o–ÛnéÐÏqNÒÅŽjïh'Mý`üɦ̖âæRKVS´?奡| ëðˆ…¢²‡g[≜ôj÷1ÑH–(r¨{ ýìð4¹ð©ŽÓ<ç‡Øh[(Y'Ï:±)×9H†pFR5‰1,Ш¿je¾ÀOq2Ôó!ÿSMÄBйÎY£}ñ9ß ¥î;[÷¬¼œ ÒÍ…žºÉj~tA5çQå³ ™•‘Wè*¼Kƒ,ÅUعöÏ÷MkßÍ®í„Ó‹æî+ð“mTi¶`ïr^1…?ÌôHDóÊîý0ª¢·*Ϫ85$±hüC±aWý½6‘¢ØÂD™¼ó‚vi“S ê³ ñŸâ±N ©š+¤ydò­b·ì’·¸Gú($ò"šãçõ2r¼ÑnëåŸúÙ³?wŒ ja(y¶°G•¥¸kVîÜ>¹ò*«Oøn1¶„¯]^³ƒ¿ðdˆñ•¯;Èò¡‹¡±þŠô~_×bVùA§þ8ò=/ù¾¿ëwrx7™>ãÙ.zŸsŽˆ/EÁ5‚Èx'„÷¾‰gøVÂ*K—qygÃ!/F1”¦HÞt»Ö&–²9…›vàÁª1×Äks÷n£å¬ Ö}‡)Öv¥{çÚwž>œKßÒ>£ÂM5@Y²Z±ÿ>ߘ€®ø‰AÙçö{}0¨ûP¿Ûá~]ý}zuʼnS>BÃ)/ßïLn›ä4g)ɽ“5NjŸùÒð{¶µxB]\Òb8q°@Ò{•¾¸Švÿú»òßUMaõü™(²UŸyRzG¡Í%ïò˜ÜÌ~Ö®‹0aÚ ¸srƒë¯ßÄ…0-˧ÛyL±ÙÞ*nkoȤ‡~ó áLÙS„ïR â+¼ =–Ý”³§«AtàjÚÉb®;É·êÑ1ó‚{B¹1'ã‡ßXL e  çüÉÛeYĨYýÚ–¡©‡-ÚvÇÝ&¦˜ ‹NT$. ?CZúÎn×ýðö:„[žo’]ˆ¸Ïb:;À+ÛSî/‘—¸Ÿ¢ »þn˜BQaP… êi×O­)”Îjér •Ϙ üÄ¡*Óã@”qšòu8Q£z°²Q¢‡=k\uwºûÅ-ÙQ‰¹#Í1{Ûö´i|Iye_žzÒÑ>ÅùÆxíñ¶CÚôW¸¼öP\—uxÄéϰLJD`ê ®«=¶h“Å`r5áÇ›'¹¹StQÑD_Æü覬ӄ×É$ïE£cN°} éýB—ÆÖܽ›÷í[.Cgé¡O ÷|Z`le2 ÎÁýýCŠ\|™cæãxµIUt’Cë—p°3’Oä~;g/iå8MªnnM?ÆZR_D7&y}¤Rœ»U‡Á0>€S]:B²'iQ²e÷z²¬M[EäÖ2\ÿúþ¹»´jÏÕý"ú‚b <Ý%„x÷ïmŸ{.ÎðRÊs¤ÙÌ›”²Ù|ή­N>;r‹ÑôH‘™H‰äR¥“:¥êb0¢ê@›ÂƒÑ×\ë—xìׇXoL©µN}yö¶…éÕ=bE柴¿v8Ù·ÿãɪ[ŒëãÔ% %´-¤gã›­$úéÊΧ¶î~–õÙ3ø$Ó`tI¡‰ùžêÜ)¹S*ìßQçP¾ƒ‚~µJ żýûDæoug\›¢Ž{-Gmõt…GŒ*!-D›0Þà®Ò›xÁPþÖëæ‘‘ñå^+|)FüŸ%¬Ìî'Qô‘‹ô¿ïÌÉ®> €‹®–¹vPë{%Ù{¤RÜZ=˜a÷xÆÍè³Ú''njÆ;ðÊÞ:VLüz“MeîüÅä] ž¶G¡BÕ_Z ç)˜>’x'ð÷Ð?O£¥¤ë„Óí" ó]ñޤŸûWèïF ~ØéèïéÎ’j2å*°¤òxP6›CÕcúÂKK\<| zhŸj Sk7¶ŒŸ1Á€$E6RЩ3T 2öe…þɬöœÔ±m¦9\õ>­AeÂA2Uö`òÚ7ÁÚOíådjþè„÷ì}2tü“̰O‹{±¯N¾ðÒû‘ÆÊš"ÁS¯-ØäÄ¡®´+pŸü-ÒÀ—‚ÒÏF©Ônà ³\¹ÓùMîPîy¡æúîjÉž·ðþœ“–´¬'Ôø³ÂôrèÉk°c¨¡·õ›uÝL¦&r¸ì÷Ø›wÉ“œ‘½¸Ççslytd/)<áãð8Ñûá¬%I¥X½Ú~ÎTgŸò´|ÍíQAÓ&wÊ;UÀQÙFoãæúœüRߎ:=vA5EÃ^îƲë¼b¹~¾ÕG ÖäMòì"Ì–Šˆ‘|ñ5tO·Êý@£ÓÛø9ìÓÚZŸu=ö¢‹ûIõPœgUó±º|È!ÛúçØÞë3o¼ÈZÁÅÜÿ‹£9þƒýÿ]‚ÿø›ï?Ñðü”JZJ<Üÿ_\ óïúÿâþÃþÿ€¼ñˆNEIˆ¡Å¡(iYqqYŒ8Ô5ÈLØý܆jû>øàwÝþÁžàN²[û®ÉQÅî(%üK9¬s°¿Oh~ß+—Р`pp{î`¬gÐ/•Ðí6vuÁá·S’…¢÷Kà÷k$L¿•°ƒƒvÂÚØ­ ¿“„4aŸ¨Í§Í†Pè_"$üÒÐOî_$ òm}`‡úù‹‚§|bCäþÇ„lGú×6?áÞÑÀ/õ7vØßÎAé_ÚÝxJº{Ò• ˆ€¢€ÿÀ0DÁÍÇ?\êáéêŠÃoñGTÀf~ƒÌ¿xþ_þýÿ¦ÄþßÛø›óÐô¾ÿ—Gýëÿÿ‰ë7ß1‚ÿðßÉùj}þˆ„hX‡¨‡ƒ;ؘ{úâ aAP´Ô+Ôì#¤ hqYq4Ø;ˆ Ð(÷;5Pk¶>£†îK+œª’(´m€`Éþ#ªœËIÝU T «ÙÔß°dÑ,áÛ²KGûô„MXî/¹ O;1iS1ñ~H á¥xW¦!rV4)G*þt¤óý:ýHpÀ aUšÈ[Ù«l&*|¢Ä-i™RÂëû—¢ç©Ôd)âéƒ_=ý$úî+— †ÁÆ•okâGÊDV“öyçÞj[P ”J¨ÍK(Uöú$¶t¿¯X`Ê¢!|¢»ÚñЏM¾ ŒÅY±8›'šè¾“÷¤å49}Q¹ÉUësN¨µ žúåjU£¦Ãnï™)*z(˜5°gMa2¦"ÂB5tëmŽa¥±%оå¬+Fç´a*µB|Ž£kVt¿W}çÒêjŽ.{"îªuoÐ-.ÊâOøà~ÎÍùN>ü´þ™yIÚå*ûáɽ..Ή7L*{U?y=––ÏÙŽ«·]¼âþï©ÛQŽ…üdzMôT€Ìo 1S"/.7à ïw ;’!ïrVÿ²deäp¥Rø¼)\õG­¶£õûùìãºÉ÷ oc|Þ-zHÀ¸³½Ýj?³ÌÓÖ4ß?t‚zöýçƒî7ó¾™Ü#NÿÆ3²(…«µI×<;û1 Î@a,x”7Ù,äéÑò4 deÌC‚ýN’wM«&Ý%bE“Î÷F'yÖȸøÉî2ý ª5r¼tûØý4Pÿ=Qîÿîú«óŸQhÉàügŒ”´øÏþ÷ûßäúÿ7þÑãÏVß}³²íüg$GiÝ„øÞÆùψ1 –d¯‘x\3—w‘`àˆóiR_aL(\4HÀ/ì å÷Ú õØÃãÁ±×•Ó™’ÖNLeFÃlÇÀr€„Ú–d—5„ÌŒ˜Ób—k‘S .!åõâäÅ1ïqüþýûØØK‰.Äó"ķƼ uvñÝâÊÇ£7ûª:G’kº:G^ªî–Š@‡P1›3šC( ¾|ýÆÌlBÄä@& º?ÜþõÛúǵ/޹º‡/+Ze ËÅ0ó»¼{ÿ)-«ššÃÎÈ2éå«Åûú1BBöZZÁG^ö÷?º´ô>äÚ³ñùe£Œ«ÅÍC9'ê½"ö(èÆ>ž¾}»[N.€ôáÓg„Rœ€t›ˆ'̀ш¾ßý”„ÃÎÎ1]H‹8ÒÑ9þF+õRË“&•aµ…hNtà.~Wq•ð —îõ Œç·OG_%ið:Ó(ª›Ì†ò¡¹-¼yG¹Ï…_6åaæt¤©cXÍ"™ˆ×ëÃçoן¼æ÷?õôÅ¢iÖ5QÝ4¸vŠ f²€jÜn‰À®¾1LpQŽsK©'n<}Á"ƈ £ 8{¹ÓÜ«T0€HÀÂïGÕ¨pìÞ©^hR+Ä¿b ¡XX/mlø>•P¤Nô™ÊVŸ¸ {¢÷*Æq)Ær(IJËŰÊD1JF0J„ÑK„Ób¨!”¢ÁŸ;©pÛI^ƸŸCÖÖä)¤9×DÞ'YÛ1W>–FÁ«®.pÅ'Úä5Y\›Ž"©–é.É2a5IûYB¹0f`;ÙãI³¸+Ž÷K;…È&K¯…å¹ßEÚÈ;Zjá²bE†.|× šþ|ŠÃàUOËsÙ©ä>ž›²V{ÆÞ‰ô5’3&?ËìßOͳª'vaoã‡>­1‰z^ïùcUlÁÎ$YœümôªQía´¦ avÖû{£ï¥ä2ZÕ¼FÔ¬µ»ìšõi]JôƒùÅ˯VJ Ý|ævŠ>L®éìqÖ ÑM×Û%ý9Ì#¼8C!aîdŸ$ëQZ {¤2I|“.™yøü£YÃêÉɽw: ,†´þ¤Í—cêý‘Ù¯µqy\*X¨W¸Ô~þæ¡ôŽeóCjѺƒÆïú§˜W÷§&·pÒŒYsE/_r-Ìô .˜÷þxU>ÆÏãSìëòkæ®=ËEógÆ;â—jNSwËñÝxž5ÈÕ}æíá®Ü£‡Jë¼-zkpqÿ K÷ÊúÆÁÛwäk3'Â$Þ—Ý¿ª×^¨ßíCì£éµ?±GR .t›E¸¿ {±ÔFj´³§A³¯.+]ÒöЕ°‰7ED&%œ&Î\«6¹4÷AZv‡Á4È⪓—šœu\’´¬ŸÒÜ4)( %ò}—¾îz:'.T£ÿj¸ô'ý(N-.!ùúIiÌúqé÷ûG®ßôÿ©À?a|ÿùöM ȶþŸ’˜w|ð—_Àþè™uΨ—«œR(ê—Íï?ú‘Ù.t›Åó4•í³ˆe:Ä&r bw”Öµ-òª@J«@ú=Xö‘¼T~?¦è±hÁcáãø>‚fpåîÉêgNÈ”ÒE•ÜM“ÖK–Ø­Wñ\õÜs¹Â^®Ð‹×2&ßRÎä6ñÓ#Lƒdq4‡˜\óu_ö+mŠ¿t?ùJWxy«û©Û&™WaÁÅÏJz¯’½iÄwHbZµËïK¸¡Wq½âÅòÇü†~‰èó¬!Õ4qmÀzˆO-ÄÿæÃñ¹ÊûÏŠÓk»¯=|>8ýúÃç¯"áç!ØSÔØcR%ÏEŠFrz÷é~>ÿîÈíçèŒ6N¯B l¡tÌUO®æ:x‹9ñ[Ú}HpĽ‘|ÛþDUôˆs•\éóÅ÷Ÿv‡ÝD¥Ýኾ¶ÿ̳•OŸ»gWFqUï-^}¼ w¢kæí‡Ù•Ï{_²ÄÜ ®ºóìõ£—ïXs‡eb˟̪}jQØU÷ìö“…€Ò&Û£õÏç–ÊZ«”O²Ä5Eß­x‹¾™w³÷æÀD\ýc“’‡‡ó{ŽðùŸN»rß(ïž÷å§Íó¦ô’ÊÕ*g['–ß|øbSù”»`lôÕ[û‹ÃÇÛ¦l³/ñgvŸì~u²÷ßÍÂ1þ“S—Íï <“RÓ5¾ü™7äÜ£·—ºFt/½P½4/{~æÜÐrëôGÔ™I‘3“w'?<[\«}Þ<ŸßûVâܬî•9ùŠ—ˆ²Ù ]ã5¯vjv¬›5¸º W9/YñZ³f]>87¯’ß-w¨Â´îí(éOÉÂÞ3óÐâùs_ZÜXÖ¿þN±æƒù!*Ó2“"ý(ˆN¸XÅ[‰ìά–I‹›ï8“%ªWd/¯¨ô0Û'ÛÝ~o}c‘Ê<Þææ[§»¹œRTk?ržc°Š£³Kqnùds÷Ë>×tÇÃ7Ö\ھص|AúdCS¹qÙš7×ÄrQ¾9">9ž9ú·¿x´³jþbv÷‹L¤ BF Ömó£íÍVY›¯¨š>am¢Jé|^YùLozèzdݰ&åáã·[Rn²V4˜>¼,Ö^?–èWäé%—ã—pzt…$bd/ _õ &n K±¨ó¾2Ö\Ü×ûyý­ÁÛÆª¯U:×Ç&–^Ý=ü6«(¶vA•’úÜ'šCk<¼t&š•¶Së¦;Ãþ~J‡hÕw vÍË\»q¸#çÞÌ飙³…µ_Œ˜XïÂÄD£ŠV×øWâbŽÉÄZ4»Ì½a€¾{kº¼&W(tÓô&[l=WÄu ?¨Ê²²áÇO¹/ÓÜ÷E}DPÈG}¥MèŸQ¿4·ß~}ôil¢cÍyéA’ çgSü ¹.Z §Þ•§ÝPÿ–µý€g\Þ°9âT€î…—[És5Ü ÃƒëÒoN9UœŒâòd 6Ï2öêºÒ®&uH2P‘éuÿà…éî]ƒnñ÷ωsM{ú.ʇ½yêî½—Õ6”è¾\…íó™Ï”ò¼Ü‹#pë˜ý¾¼¯8¦ó¬íÞë²[Ø2GÝÑ,áÜ«lõdJ-3™Upÿ5åøð)½¥JØ.]Êó§Ki›2Fݵýú:ª´ËÛyddD6)D£hêÔË—i÷\¼§wß]:Žø¦{ÙšaáÍÛ·4_µ}h˜åx™#‚Äô–U«€\ªÓVx{rvtŸk™"\ÕŸTÜiá¡8Q4‡[S•AQâõëT‹‹‹¹ùÄ2õ%S,‡Õ¹%'È>A>Ûw+ïmÃíJEºTÞ½~o{ßK¾;ƒ-h+DÒQZ)9F¡zßMUï:·áãÇõw´Ó"ß8–Pð¼ŸþëSÎ6®0ˆç¼1ê«›Rn‰{{èÅc¯—NÑ_«ê ièÕl>´öÑ˪¥¶=Ìí£ãIRŠš;!JK&+óØxõÔ½™ Ì^ÕQ‡oó0 ÞÞrd¬:áe<@\,'nöL‚GöñY¾B¹ óÖëÕÕ4v&ç§kç{<=§ü+U=ÚƒE©bïq3œïÅ­N¯½Ë~eAvX3õˆ$ø(FIéÑb[ϤÛ.¿ˆ¢âšS¿‡ÓÑ¡¡Ì)‘*—Æ›”Ú\t±š½ª EíÜñ^5>´jùèϦÖÖ N¥~o|“—g•¼UË-JUñ¸Â©]²éÙ)ºÐG ¡gx)£35Å}D“Cû¹¿» pÞž¼Ûâ'<^›|ñ`ؾtù޽k*²ÇÈ4^WEПP%[¿*ÍçÙüú}$v(J^¦à¡9M¦æŒâ÷>;Ä=5žÕš@¾ ÛêFJ5¥XjóPê˜üøþw'Å+›I(_ŠÔ)• Ÿ õìMœÕ¨joq;û9®æ±[7IÀãC?t®%LÔÏ-pRÔô•¿È‡ÜzýäÒ´€¥Rý)Å—7PÞÍ*Øy®*£‡ÞŽžÏJœ-ÿ†êYßYš÷{Å;hÖä¹§±õÎQoÂл¦¥Õú,-î¶ä:øõšêZdö³nØËoO§ï?Yytº÷þ|/Rh¯Þ“E§G¼{[¾@§Mo¸Üè:}ÕYŽræ·âk5š÷Gw›ÞÉŒè¡UhA­>ý–“*R,`÷h˜&v/‘¥«_:Ïìºå ‰ßщÃó““ò2Ü#tN/)Ößçy×v/ÑøvÛTDÒèÄä²wûѲ;÷­˜hC2o'sεŒqUz¿¥$Õæ=ei”?â=Þ@›eîÿ£hŒœûñrRe£ÿ®¡Ö•´k‹_¥UÕzŸw èÙ©¨e²geÑ©íºrúDi@ r·ý¥ò¸‡n⻈‰Ö¬E2—ûÉ¿IÜw"ÝÜ2¦Ý/¼@Ô­©±Œ©¢9V‹ŒF3–ˆ˜û‘Šëu×Ó•;߆o?ýXQj>{;bòíù‡U!¢%Jõý§lC-¯ÛRó®8“q1œ½ÖúvÙ¡y¶}IY¡é™s’s‘ÊÎHý“gî -¦tô_ÅŽ¿«582,súòjmx‡Ä;x¡î]y“1Ü¡–ù#WÖZ<óÊöºêä”FƒNK6¼òD%BÜ–=„œÿ`›±vÜÒlœöD oçžÑ—o-^—ôöOU½âà~à@Q*çç;$¦ä|6ÜÄÚ“™ö—ÈiYÓâ(Kæ2Ý^¥È•Ð8ý¸ÁÝJB~ú®±?”BÞR`ß…´…ëµ ‹oªÖ±3ûö½y8ß¿‡j\™È•X—5OˆT¡çˆœ\$GkÄC¢h=I3wÍQÊ&­RQ\£Ë9*îkkúNNã;Z¦qäÄó€¶Ái\÷‹[ûÞìÖÿ2˜“JW05¯ÄTØ‚ï<‡ÿCš†–¨±zbéG4U—â««Pø|Ã1j³û’û}·<ß½~?x8%áDšÍ27_æ™âLº…f÷De*ÆÝ-uì5F¹óÐûÄÝz‰YãõŠì‘ÅÁ‹öuÆ0ærUQh×4 ¬_HÖ‡…»¢z;éóe%’†‘D·àGøPþ5.Ü1þ ÂáDýCBü}ÿ[{ƒ×ß­ÿÆ€ë?¤ÑR’Œ$8þ“úwü÷]2ÿk‚ÿþp€ïÿÌüÝB±A8ˆŠ«¿3Š?2݇u ìÂÉC $pD799™œœìææuðàÁC‡…††xxx¸»»ûûûGDDx{{ÇÆÆFFFúùùyyyÅÄÄ< ËÌ̼páB___qqñÝ»wüø±wï^nnn(ÊËËËÇÇÇÏÏ/ °oß>AAA!!! ‡Ã………EDD„¨¨(‰µ Æ`0âââ’’’RRRÒÒÒ222û÷ï—•••“““——WPPPTTTRRRVVVQQQUUUSSSWW×ÐÐÐÔÔÔÒÒÒÖÖÖÑÑÑÕÕÕÓÓÓ××700044422266611155533377·°°°´´´²²²¶¶¶±±±µµµ³³³··wppptt>>!!!111)) DJJJjjjZZÚáÇÓÓÓ9’‘‘p8+++;;;'''777//ïèѣǎ;~üx~~þ‰' ‹ŠŠNžìíí4¤¿¿÷ >zôhhhèñãÇÃÃÃOž>>11(çÔÔÔôôôÌÌ ~¾xñâåË—¯^½š›››ŸŸ_XXxýúõ›7oß¾}»´´ŒDVVVÞ½{÷þýû>|üøñÓ§O«««kkkŸ?þòåËׯ_¿}û¶¾¾þýûw@Qvר³7ÄÔÐìÇ_\›”W^@A«î7=h"”†¤†ªð©Âš&éº6©€]þiáRÀõS%«–¯a#*¥Ì `ZöeÀâHïðûz[Üíø;)¸Ãÿ{†â‚"‘nþA¾H¯ÿÇEÛ®¿öÿh Œ´èÿ1(Œ$`› ÿÇü»þÄÄëÿvŠ¿þCXÿ‡F‹¡÷CÑ(Y”¤¬„ ÔÝßKXþGE%&L†z™€U¡š@U¨±O¨»§˜† Æ/ïà Qh( G‹á`®r.0Ô3¼Y; Dƒ§ ‚§“%ÀBXßðTîY¨GHH€¬˜˜/Ö'84éâﻡ­àa‚¾b`qõP¬ÔÇÓçŒsÅŸXL8}Ú@ÇZ¦–±þfv°,Xº -Ò?Èð rÁ!ýƒÜÅ6 †"ºñ€ ðøC=w¿ÐÜ|!¾>TàòH\Öçça,ÂáÀ!‚àÑ8…­tx4áô˜‹,\Q\R‰p®<@[ͤæïŠƒ¹ˆ`öÃe]~ž:'.‡ÇÊyºÁx…„A¸¬ &æ(† äÃáÑøÃ a.¢¢ð ;à/ÜAÁÛÎÅ!&¼—óV°ÛB·‰(èë · õÍ,!{ûp¡X9t¬ÜOÈ@û Px€BÀà鹦8w@‡`@-g!°Aü-BÈ]ŽÀ×Ûh2 &“„ À£ÒH´—‚$ÌCýì…$í…àþ Ñú²þ±rþ HŒ,í!+´†Ù a<ܘ´ŠW‡Á:›9îøàf¿½P,Â?&&:.' PˆŽ•@ B¦HŒ1£o/„°“@ø#¤0°$Ú.• c$è(˜?æø#-áÑÚ0q¨T< >a‘j°è(Y?„Š,ðhçç ËadÁ_†á‡äφõâR`»øl9 ÃšÕAŠ£ap 5ðh$ÚCDþAblxJ@ª¢ ø#h/$Kx ”pRP•QU )H ,ìð@ÑAp }IPÂÀ Kh í¿=Ý#ÈÀ…–€G‹CCü‘ú11`¡X9Bq,(4€_†p¾ >´ ap¤:,Ö‡ËÉ@7 `B€Z›éëd  úøöÁ¿ú€:`ξ{* š H-9OyM9O¸…§˜Ø[,@`˜‚À ô~Yñ0€¹@ hC =\ACी’ó’x•1°0;/x¸‚9žpŒ ‚D¬÷DŠûãEˆ… Å}À\,í"ö˜É€¢î©Û†*âå(‰/ °ËU!Èå â¶¡Á± þ~@5€4@®â€š‹ô‰ÆŠˆÈÄ‚´ÈcÜ ââ |@¶‡ˆ½4jÛ½˜" g9,Oxo<î”  h(¤8 —ß/·AÚ:&Æî…ÄØ€ªd%«!‡Gb,`||p9{!9 ¢,c (Æ #܉b$€[´éæ-ÞŠ|¢meUhgà£'‹B`t|?1,XK[¯Œææá”»‚£ ä.(È eÈÀB>L¨iî[Ïá|;„›Ø¢/ 9Àð€_´^7dÃ@Yû,˜¦§þ€)º ¾¸,@g0ø¬ƒFhÀñíŠDkæÖÆ & [¢„÷h x–õ@`Ü2âj Už²n€¹Ô»Úa@‰©Š™ŠZµ10 C ¾– Lh  !|ªœ+RF€H€Ž²Ð(8¨@1@Û|H`ü•ÀŸˆ«ü‘s9ñ( ž\<ÈÓÂàŒ0’3Rêû@üèp|ðÁ¸C‡Ëù mŒh?%ð‰6U’ÐÎ@Æ[ ü‘5""ƒ÷3^öB11›OâÁ ×‡º€ÔAŒ–ÀA•sVpQrAªÈЩ ‚ñYB |"Îx›GŠœ 6¾U΄ë¬"úgAA¯‚*ÜYã îòø|ÛØXñ°ŸÂ– €òƒ¹!|g€58ÐéîÇ ©sõA!nS$qßMEŠÝžê½¥^mõq+Û ¯€¶JÃÁ˜«„‡-KhþSÅ=㹩‹w\‘$À?÷‰ %J˜c€T)€{â®Hq)î °A!p‹…ƒìÁ*À€‚â2À€). Ø­"†g•œ +(ˆEb0„_$Ç ŠÔZ%¬¬*0L”Ûr"€©€÷V x× ¸#$èDuDû‚>ÄðÖ¡ øB§³qbf8(`å`|²zÀŸÚðὩ-  :êÍ’XôV%°c”:”¡ë4¨2Q»PÞ6 ¸10më`°‰F+€O@A´p‡±Æë‡1O…ÅfÿÀs¼!ˆ d¡š¥¨3mºYm_o•x |a› Cåð-o²ë GÀ ÐdÀÃkA+lpÓ®h¬¾ø`ƒÍ¿r,…¶‹ýd&: €áLhßAK µP@8€• O‚àà]œ{ÃÛ 0À Ä€¯+¾àÏ>Òu[ ÀÄ)¸%ÞâQ`?8: ø Xœ ÒDP ˆÏ†/À+W|º‚n+Ä:$ào€Hh‹ØL‹ÜL“|#:,ß ƒý.aP˜ `í¢ €v'tâ@Œ@›)à;ay´¾'ÞG]òF(Æ«  *(h µÜ  w{9|¨ÅK ¤ÑMÏ>ô~ÀprÂm''€þg“îxNø–ïŽ'Ø}ƒ¤»ÿH°¡F›&‡áð!$¾!gŒá9oªˆÄ¦d¤ä¶˜(„>¿c"¶°m´í`¡çß²hlƒ‰ ¦n›ª(IÀlÇ@AhLb'#A•Ä3rS>X b]Õ˜ ABƒ11°MÔNÃAÍÛLR|9pÚapYg±08ÀFg <ÎkœlC€_Zøƒ4T6g à±A˜ >ŒsXr‰ 3ÑÒ ø[Œ!BràV2Z¨`T ØÌÖÛʵÁg:#Mñ?H^g`È!f5˜ˆŽTPEÃ#›­,Bäf©®ò(|>Að´7Ñ‘m“Р®(GçÜ`8%W´,Ú`׆.ƒI²@Üà)ïöS—ÑÞ  €î ‰Ás*La#Έµìì…Tì…â!p%@ËUdÝ‘*@y€J˜–Àq¼ælGªlÈßïζû/0¦Fè"Ànô`˜Ø–ãÂàý#Fý—J`P%A˜Ä6ø­²Å\ñpð–À2|T!TnTßß D`þOVK€BEo¹Ó _ÐU(#½Ñ¥RþùŒQÅÈ >"Å#á ,émª,p– @§å ¨ÙO°@QW^çͲºQtƒ!rE•3žª-~á3 Š„%t€˜(`‚óÆÝá—ÐÃn(йa"a•‘º0 x,к(8Ç‚ž BI!„ÁH#4<Ýb°A1àÁß1›#ÿÂø<ÆÍ/<ä=æÏ/?¬/¨ïŠ‹ñ õñ‰  öˆÁa]ƒ\ß05_, u—¬«+¾”¾g0PÐp‰ þ»¿l@€ˆ¹?A7ñ87€ÈAUÛÀùzãîãïŒÚà Ø°h(Á â›âCqÁ!Ú8¬+ÐŽ;˜@°šÐ>=CCpÁ`¦ŠÏÎüà Q°B°!¡ÁxÛ%ÜЃ<±>žQ€BCB¼ñæk¶• *ïϧ€ \Ìæ÷ç1›Ÿ¤Ç¸€¾fCƒcƒ!ž >™™ÇlNeÇ^!ƒ|S…SÙ!Ïç©Nö˜ü–DÒ^¦îèls—åó:Þ÷ »#‹“CöÚ¿Š¿8'%\T/QÕzpW0Åëõ¸;ýjl‡ãˆH*‰ž·å!Åñ`†®Ï•·¬—’ɉø¥3a’ù9Ó+G3\=®<ÓY*BÎL¹©•vETC8–ÿ'ɤC¿€ân6pщôN8½Pärª²ôi ¿Ž{Í™èõ¤"V?˜Úpº‚&Ño‘¢Éâ`ZÌŸŽÖ<©!Þ6†e4å7¶tY8U}ÝÙùM찷ݵùa¡ï[ ¨‘žNµÊcªn%¿EJ*#þ"ïË |ÑÈš‰2þ¸‘ÝQ®Z±Ê…g¦o^Ͷº¬}ö½ïÁƒ¨‹–JÖÕ2Õ¢*O_íÅ=AM|KÚ/½n¦{‰`•ÁñeU\t„×yi#¯h#©—Þå{;DÈ e‡¹«ü[ú$2xJºy# H銞i¯ò3ôd`·¥œË¬¨pö”kìô:ƒ” :7óÍálaÏ$Ãìí’„ªßJOÒŠ—dóÂ÷ŽŒtØ2¥˜·™K«v/¨´¿ƒ•Ø_ëû=þúåÉÆƒ ìýB·ÓÔô‰ rÿ¤þß^;ü?64Ä3~ý/.ù›õ’ÒàþÒâÒhi”èÿ¥$¤ÿýþû¹6×ü"zÂüP2b(´JŠFËJŠËbп¬Á¯ÔPÁÖpÁøõÛAAqØ0Oÿ hˆ?ŒC7Ö}¸Bñay0~‘„:^‘›Eƒ‘; (@7§ 0üÈ&"Žß°( ÖÅÕ(açî:$ÂÅwÔ—‚`ØŽQ Ì#\œ+\݉g$`?›"´Ah%4Èhœþ@âç1äð9žnP/ˆ€ï°Y ÝJê€k6ÈSQSW…ÉpBíØ-èxœ²úüBPB;ž®H`¤C!¶R³$PQ(Z~ ­!Á±Lh;UBFšš„Wpøb0cÀÁI˜B€mൽ&a´ºá6ܽ‚UÔ ?ɃoÂу#ᣚñïÄå'³…ðåcßX¹-Å1ÂÏéÄ ®j0G: —Á¼àPww`Äú þ¡PÏ`(¸f„®îÁ®ƒÿ¤l¸Îêê öGnWº?R¿CáRÝXŠ hŸÿTiðó5HOWœ1ˆlƒ~d00ðJ*(@Q;x¡âU oÈ „¡óvdA1ì@oC$®ÎÛ-bCUÁÖг¡_ø¿[©x»qušß!¡ A¯Þ¸HW€€m´á´³É ¬ Òßo³X%‘ˆÜÐý›uÜß×tö ÚÉW°Îv^‚Ï®ÎH¬Ÿ Ά¯ вs] VᵂoW>Bc¿ò (jˆ?8#ò“¬ßñG`5Þøq›ò½a‚ ‰Ž—4ð/8Ü1„ƒ¬×imVpÁã (Y(àñ-aqvø†Iã…A˜R™»ah[zˆŸ6•û G\Ðó?bðW0\qnX`䇺h€[APáàUÀUaÃåЀÿÇÆÿßå0Z OU°‡§[ȶTi|ªKH϶D™ l+ˆ!È õñwñÞÆrq|8ð}[ºÄÏtP®Ûr$ñ98?×miô<ü}qÛ Ø˜Ûäù§‚&dìÇg[öýš÷gZ¶Cª?‹Àâ!Xçm¼ßÀ¿6s‹;DqÁ.Û5î§þ‰ÜŸ6ù·ºj¡ïÂ÷¼›] "µÙn´ :zpñè6_‹×@ÍwüüEÓC7º)—Ð p¢Ó'êðÛä9ÏüìtG ;ˆ„ðÏ_XÁTw„ß–>ÿôÏ>€¡¹£û²$„&Ûs?â~@œ³ Ï¿ÅEýWøÓ0·9€vAAèŽ$Ø’™§³¸Ðt{—¸Å0ØŸ—ß´lPrÛb0 ¿ÇÇH>žBˆŸ"€ÿ Æ|@„ÎÔ­€ì—¦Ábî¸ ¾-‹ý ¾AЧhðÿ„wÿ;Îm¶õ?áÞ¯uþè¤ÒƒýψØjêOôñ”l"*ðK2’0Ñ»n& mIY€t[ô¸³ÌNv´~‡Ž[øyü© õû;ú6Ñú ìÅl£GÝÁv×ß ‰¶…§) 7µCÀa¹l! øL3‚Óð ÁùnFÊ„N(.§÷ÔGx ǃª Æâ¦‹°ÍÀ‡Í[^¨„Ô/ 2¿ž! 9ö!ŠÝ ë‰ûÿöýY b†_S°Ã†Ë Äl>·§m Ž„œq€ç’݉ò†Oùì€oÆ Mh Yg@Q½·î…S IøÅ;RðÆþ'ÍíbþªÅØ¿šŽRdž`UÁ¶þ8/Nmî`8ÍùsÜB˜>~zD¸i½T…ÚJsg´èØ*.œ»K| W|ŠŽºþЃ‚¸ì"X`§ñIŸÁmÍ›áçÃv¸íí值í›]€G»€Á èˆ<€Ë‡óÛ( Ns>ŠÐ…l7<%vÛ!:üâ8·Í âEûçõ¶Û­Ž|nîüùÙ4¸è*hKUÁe9«Ð¶gïˆ ðIxl.Xƒm˜}éF×÷Óh`ß騩xa# Zæø—@÷†gÎ6…ÚAíE‚ëP`[Ã7@޲P> "b#)4ÈGlÔ,!1ÀUoH¿” gaªª-Ы®~‡¸7l.Þ¼¸¤Jh3}c¥¡ìŸuš„ ÏLüÊí.Bˆà„Ày]¡­eˆB`TüÇ2@ÄŒÚÏÀßàúFe¹meVZâ‚<Ý"7B~À&Á.ˆ||ð=õfÞ=GúãçØÁ€· HÇVp²©è;5}'–ÛMÐÊMælG/–ê7Å·éÁUm«²Y!vS x÷¶]¾>à'·Û‘Áúà‚~¾ÃðÀzàW*m–Dlh|«B#¡¤ÿðß¿~cÿø7©®ÿÅ  þÎþÅѨ_í_#ñ¯ýÿ×bÿì ýƒk×ïþ˜ úòåKD¨€#<‚šmà(ä/à¸Í @Y’¦¼Ù!CdÚõrËQªA¨8"!§C<¯Ä>ÜKã­Ðš}.lÃòQ7l¯‡|k‰¿JXûCúØ^~*#ïE>§pGfvÙ¾sqŽÏé[µãW_Múr/Ü(/˜ñÿ×%ü¿]qþÇmð¿Ûÿ[…þuÿoI”ô¿öÿO\ÿ³ý¿™¡Š) ›»½A uuïýû]0;aa ^sV´-…¢7Ä0b’±H‡XgBìŽB«GR‰Ù²òêòñéñ󛊈ØíÞ­KM­JI©@M-ML,ˆkiq ­!®e$¡´Bæ\\fL¸]½.uüaWï‹Ô0K; e_ÂfÞß¿ñö=a?o"Ýhz>#„_I)ˆYûÇý¼?~þîçí{‚=µKÜåçµÑÑñ´´ü=øm¼iœŽvò¦ÛÙÃt°?Ñ ¨§á6@˜_¿^ܽ[ wææuxûvå^û£wï>RQéápQíí=µµwŒŒlff^ÎÌÌWUÕ³³K…†¦66¶‰‹kÃá2½½ÃˆšLlùÐИ……Ktt.aïñùå²ÖÇ̱/6 ‰¾Xþ˜w³wñý'ÂÞ$žÌ,æµµm€Œ A·‚®>åó?MÁkÍÊneeKD¬çwec?oèÓüû\9¹ì­¬Âè¢G_½¥D»ŒOÌ8vìX…[Õcë´ 0/*³¬Ü«8\Ú¥Á9Â~Þäp, ƒåè謴t@QQ}˸±7«mº¥eêÝ»ׯw3±Ú¦¥U>z4yáb+ íKDfììœsáBKçԲݡÊÊVfN‡Š¾W‡Çø`n·o÷XÚ¤qr;]è?{îÎ>Ö½N4Ì6 #ÎøfN;/%µH"*³íÓ‚IwÉaöÂqä Vóï×¢®îCùªäw‹ft<Ÿ[’;TÁ‹%¢³ö¯y “âð ãÄ3Ùí>Ô|îáË=ÂÎßü)mû$‚0Y÷Õ z`2aÄì`òQ\hbÅ@ýa{Ä‚ lXFQo¢=®”(˜Z,×þP½ ­ˆ»€J,¿B%»„F’ˆ×H;œ’S™œ]‘ˆYŽDÀ“LÞ‡íÓˆã’ä eÆÓŠP û’Ã|Õâtˆ›U븸± xA´=‹W³• óÓDÙ›rá´rŰ\Cœ·g:§W‘{y§ç˪‘˜Õkw`ÈÌר|wÜS;Sx÷µ9^]sב6ÄÐ Ÿ~÷¹so°ôÝ ÒM…±{S}˜ÿ:æv¨ûmÌ’´¸Üm!Š»ýü( ùrÞÙ­·LÀÓa8ã”B²¾K¬ fù|2° °â<÷üÿÊI~Ú]ôGS¦L&¬ùËïO1¬1£_±Òï$R¶êXˆ üPÁh^R×Or[ƒå熻S š)¡Ìâ‡ßœ§í¨•¬eBœ¹{§Ã£? ›iHYšjÅ}Ë­PÍY5;²þÕîen¯Ä½sþa¦Ù _ü]ìÇV (,jÙ΢‡ ¾~|Ûz,#¡AaRGýžžw¤Ãž,Æøýç˜o3^¶os½Ÿ(ÜýæA5ôöì<ô½Ý…CIOîD©_ùbýZ?Á/öÁ°ØÝ5*ÃZ×.ó–ÇÔ‡û:øú.r« 4ÝhoË£o V¶&»®¡¡(al;‰îìgˆ6¡`øa9jOd ETÁ5§ÊÜ2¾±³å培çiѼ)©' öE]¨‰YF¼k‘¯4æO¹ÿ©ïzÌÝ×2œÎÓ# c£^Þ75³Ë—%Uré"† &ÜÅožªÃžÄ6ˆ„]Ƚúô­LþýQšìKlÙ‹}̉{÷è‹'ÓT±5Ç'ï¥É~(§¤8LÛNcܶ»r$½@ẟ[âÐÒŸV:¹#{ouÀWŸZ~¸/)éOò&È®J'[ÚQ![z­ƒÛîš‹÷¸¤˜°Âø£é¥#pï*+3)«»_ˆ–‹:lhvDÍúÒª]«,+K€›Òf°s[ùóevÔâ)m»,ÝÚ÷ “ýðøñ׎/^¾<üúÅ A±’ººFòUÕ½{–#ï9?YFÍBá³=‘Õž•ožv×zxîÈ«Z?x/ý—·’Þ> ÝÒu§š!(LRÒpô~!Í‹3ëBˆðkîl)ìUš·¶Î»^¯EÈ—D’ª®ÿö=‡Ó¨“ýÐìa­3h·ž®¥>ŒF™Í!œ¡ž/_ïIdsË+ÔæÜ›y÷|fÓ›ï.æ—î2HkŸ‰/àTà™]}+ŸLHMøìFÿøÓr·ª`oÏó %æ˜HÛ$U²owZSÕJ5î|O¦4¦˜d¼qóBm‡ˆ Qê# ù·êÛØGHdÙ †Ô¦Õ1ÑàTÛÕ‚œó•Q?ÖWèvó«¸ÿ馸Ðß…×Ž< ‡6ÉdsËÌ‘´4/%ŠÔÚëÅÐ8Ç£5¸’ìáz×ÞŸi7Ó4#QÁr\}9Z&áÖ«Æuæª]—ÍÓÄôžÉ]~ô×Þ•)$|—Pí |NòõL4EÂ÷5YÛü¥~¤ÿGãþGž;_Ÿ —òD™¾j¾ 7ö:]«¡guöU`Aê,}ñw;Ê[ä£IWï߇²¸Hp 3$‰Pr`¾S±•ÚqÈÏ%ìâvŠÌQôP6BŽ}{†QJý@VLÇr˜ S²äwêõÐ`î‰ãK÷è–wÉ=1HÒ¯¨;H1I±´[#^¤9ʨªwXôÎP›“Ç ŽÓntýaî¸>×ãÏžUsIM.8¦h:æïRp½¡$ù–ÓCs’©sF·3Ä}´«ßjnŠA £ºwáóe÷¤Ä°[DÝî“|3¯ìY¼¥Ã/o3À}ê¢3ô¶ƒ_ä5¶Ó)ÜIz,8Ù+ôäÙðg–ÙŸéù~²ÿ ;J¾¸[ºé1[Ç`þ]ûVÕ Ïy¨0{^u±½Ù3%“˜š™ÃYÃ]‰ó‡ŒnqUZe´ÁÏEÞ“¶ØoÅõBÿ¡î£.ÝІåz¶ ?œ, GÔÐN¶÷l£•ŒI̸ÞÇä»ÓïÜ5žÆï҅ͽ!ž4¶ÿÖùIg@aðqƒR]_ûtÉó{&ܵš¶l!v/µëboèùx¤£ÁŽé5â±5vøÔZ5ID¦Ûv6Ü>f„Ã2·´æéýÑ=ãWýÃ>i’˜iF˜>B(«žê¿~r:áåi§„}iÚϳ 8GP¾F_m”$7/{hiôÔ¤M2¯DÆ~9sèàÄÁu,Ň=¨€~²^ÚååˆSä/÷¢œ;U{'yßD·q?™1¼Óª`[Ÿ~䈬f™Í9-#¾S‘ÃÏ {ËËGlR'EEXõK"é7s.DPòQ®Éí ÙMf«î—èO<üÔÐ×=ßÕìÒ¡Á-䵟QŸ¾ÌØ| ÛÊŠµ`‚Ì\ÇYìÆlÏݓޞžA¯5ËcJ( êt´½äõŽ—Û°së·å{ ¦§w^³{‚:ÉÎ9TÏJb`[<$È;pUh´ýØQ£À¸dZÑþ6·Öœ€€S&ýa£ èÁ–Ûå…J^ëZߨ;§Dp.˜?‚ï¿Güõ‡ý¿ÿ›o\¿ÿ·ø/ûÿ÷ýG®÷ÿþwÿï÷ÿþ¿Úÿ[ycÿï'hFІä*n-ö‰;j·dQ .½ÿqœ2”‚”8^yRµÿ$~ã©y¢ÙNÔ(Žb˜ ]ŠMùÿýü‡pðm®«¿»¨¿÷?xþƒÎÿIHKJKKáÓÑRâÿÎÿý#×rþûÆ©íÔÌà?"HÑ)v„ÊÐSMÍØØÃ?Ä?ØÃ?ª£¦ ò÷ý€@"F.ˆ´ÏðÞsÿP_OÝ“cúç5Õ«ØÔ=N³ wUÔåzºUb‹8k5áúºbÔ›»<âxáÔµ»¥yjÇö™—%³gEC —xúܼjüÞpækðØj¨ÒÄRì!Å>’¹@&^2åšwO^Ù]"rY]˜$$òTK]Ý%*F\„ ‰¦v¸ê—0¢:|=zL)ØŸAnY¥tŒ×¨@ 4UGg„dI ¾þÊç-J#Ä錻‰aŠÜ¦0Žä›÷ñJkUÎj0܈?%8aÃaN U.½XQééá5ßúñCª8M¦fAAQa¶s·xØóo;¹è]ZB¯u(×=­ØöpìQ÷É3¯”‚-•Œ—OåÜzYŠz°±Ì… ‘ñâ^`ä·µ$õ–é}­¹Ö×Ì‹z:ùùwcÚø[â\/;¾_ }-íó¼îómÑ# ¾_³ªOOüXž¹üflô§·£«Kë»è¸e¿ó+­;þáÕ·—ûYÅ2‘ æ°Ù}¹¢âælŒç|ò¤£°Èí˜ów¦{?ñ7·¿z»²²á¥¡ïâXtèÇ´™«KJ^~~ž±O‡ÇV*Þ¯½àÐwFáÐÀºw_·UÐç×Ò±þ_',N>zÕGe\!Áj!Jk ê»·áò8j}ІDí,c‡`¹¿ZT3›Ã{ÿøƒ‘Žáƒ ‰gÝÓ!°E*6ådê…ÒÝ÷­tœ?ùç ØÖÉhòR˜RóîûÇ}Û›;#dxFþ<©©½}ЙÙÀϺ‘íõ¯¥…ýÇ,Ì‚/|zÛØð%¥ã+}Q‘Ïõú£,ÇhŽ‘jCl!ß3ân1µÜ\±–ºö‰™‹ëô)*òðpz#1ÿü<ÒÃ|†öRÑŽÖÖkßÒÒ:+ææ È¨ww §¦oÊs+)òòš@­ï¨Ãô™ßË;¯w¾«ëÚ±cC8OÏùnLcu‰í»êm™3×äÜûÆye<¥Éƒï?5uBgõàŠãm“ȪÊ/†‹_R¾ˆ^òÝ{Ú¨áLøê¨±¯ŸÆRãû¨âî|…”,¿Áµ^ z/op©y­;ËÍPF’Ôà|›Žef :ø2AÂòÎO…UÕÊ.ÓÂì³|•X.7›*DY%ƒOž‚îjÖZaï¸IÁ1嘌º¢ÇUOk¿0«½h!ÁZ´G49,á“j»í>•}VçõkZœ‹Ò U~h%ªwÉlÌ"öö3ÚðLŸLLJ ]€øI¯N¸Þ·î†GwèË×öevµsÅ¡É Qµ¤ðXV,;tóý²s ýÙ§Üøç‰¹·Î3vHÌ5>ºZ>qÒUÅ —t/(æiÇ- ôD™´öd_æ®õ¬~òt5ßÌà}£¦W< ö?˪ñ®+¨iÁæž½}ô⣸àG÷Ž¥Ów\â;Í$.Ùù8´h1äÇ‚ŸÄ ÅÕÝÜF £œKWbÞ~‘ú*ù9¼÷Ø.¨1¿Ç¬Ï…ÉœýÓ9¾Á}WíT-Zí[“ßg«×iب µŸ²[V ë-#9åèsÜÇ+u5æj[Þ)P“¢µÇ¦¹uvùÇo øb#‡uOú cÊÄ'.}>¸ø!tïŒô3¿ç×"«^_×’ûô&c-þûÌ¥7ûß4¾ü:²º›«G†+ôoxÄøýbÖçòç]æk“ï÷±±9 .Âc#qüb7Žßjx¥þ"É®èÕ‰ç]·NÚÜ÷]nò$qÇf`dÌr,°T|µ«©A½ïUhôêÓÆÁü¦ƒfÂ/ÿ˜üš‘[üœ… BZÑŸÀ‹@“Õ¶Ü÷z£ÅÁÍl{Ï5AÍGèAšbºh²Ö3#Ïò"—‹©û$6¸„f/ìŸcåìà´¼Ô¤Üä!Ø—ëߌñ@ëKc0²r|Î÷âVTŽ =jt«íÏìÏæ>/W™ð9³åÈ“³FY¡\_;Þ=¿i1³^ý¡ºèRöȹQò§…Ϻ¯ÈLæ¼e)1`3ñùá½ö£ô7} ®…xe¼®ö4»`÷x¡áЇ¹oV¢zÞE¾]Z]*¾HáJjÓFóéTÝaw÷‡Ýô—(¼é­Ô ´¢ÔËž´ÏŠU8¬å¶euOž™¬o-´&t™…ù]ò°¬€ßYÛFŠÂÑ… ×.·Z¨Þ>xTUÁ-Ô²¹K{ Ú¹±££û¤è]»Æ–?|Éä>ÔZ¾yóíªÄhØê…‘hñO߈)Y7šjà>TÙ;V´;¦Nø_K㌉Ј!¥aÒ>Ô²êiùs!Ÿ’?é~0w"¸»QØöò¥›X{› à÷—æFÓÚ‰½^¬~ú*Õ¹´äOåÇý¤ÚCáqÇkÔAó÷3fW.›8ô¹mmïø©ûÈDõ›ÌÅ÷o­Y½çuûñl^äGÓÕ}o¹ìüšóQ)T1ãcýïèÛÜMý"A…£ù:÷ÏaÅ<ÃSï;½0ðúÙÌX;ÈC€ƒôý I£{±}-½|—4¾9¿Û=„¼6[£SÜtC§AÿöÕçN/F˜_KJ-ëœPtä£s%é'O“¿ ó XoŠL”´Šä*V†¸ALšäsY««eBk&Io2¨Q Ï1L’ßÌI a,ð a¶×æUƸNBÉ›þà9u8ësV×®fsË]ç;Sçºu]Wo¶¼ª|dLÙ-·Û«duIØ3Ó8|ü|¼Êš&b¿òiF{V`³ø¹8ïXßÞ{zu0±Wõ± ‡§ØZ¿»åࡊ¶¥>z Yg!}Ù læuTóR`ºò%¶aܺI³ÝóãAö3¯-Ïh®H粋¬÷ªnÊ5Õ…{+ËÁD?ÞVZgkêô‰ÆÊ²j=Ô}¯¿LR°LY¹OÀõÝ/Ò &:o#l©>‘U9Mb¸øº…̸úSÚNyþОoõÓc67ŠúœüÈz•ËïU†ó ŸT-«7føø¤ïÄy!LJN^µˆuJ;‡†³œjªíª¾÷j ¿³ŠUž$º4?Ÿäö¦…Xчì]0äŽÙ|µ¯WçQp òï|ìÿÉõËþž~!¢A!>àG5ÿ½6þnýZ ÜÿOJ#-.…ǯÿCI‹ÿ;þÿ'.1aÂþO;Dßý M8þ %%†FAQ2²’’ÀÿÛ6ÀSûã·»záð‹Ýe¡9ªXªÂ@¸ˆQ¬§;˜~§æý_Sýïµyí°_œ_¨¨ëöß} ô·ëQüþŸàñâ„ý߀ÄíÿŸ¸~3ÿ· ü‡ÿó>ãÂd+ ~:ddügïƒ ôàû æææ¦¦¦#G€P òãÇ‹¶$àŽlszòõ:#DmÎNñr66777†‡=÷šïÑ”q°s´H0óÐM…ÄAH ŒG!%zcs¬ æÿ ÿkçû_ü·¡¸ vÿ_Œ„4¸þ#!!-–”¿ÿ•þwýÿ?söÿ¥‡À ÷ðÏÁ4ÑìÑ\I’94OõÚ–=ò¾òôHÓT}}}Iï«úá¥Fà_êèèèíí0ý~øÕêøÒê+à~W,×êUðú±JxçüÉžÂà«ü¦­ ²(”¸Åf´‚xϹ;bÇ*íÎJ¸“y¡!›£‹ç§:`‚> KiîåK‡ ˜Ä±R¨Z™í ªg!Næà{XÞ¹è§XDýI¿RW(:¬oéë¸ø„ƒ,”ԬѬäD™™»8EX‰‰ˆI‰Np g±RQ2Ÿ àg9¾›»„’›93BMDÁ]YZŸAÃGqãz5÷J¾’:nš]47‰ ˆ/Ö×_&ªœf`&©>šIN‘Q$²{:‹â± uêáÄ¥å•wïxwÆ¡þƒi¤=ʃŒT\æ“v$e`Ñâe›_TGÝ6âs HCV¥ë{Ÿb(KÔm°†œ‹£n• ÒwEä6‹§‡Ú¼¬¢­¡ÓÊ™õd%þl%öëL—ÃéÂé.•½2h•!j™ÛŸ|¦™_¶&ƒˆ˜vŸv?Ì"ž¬ó×K¬Ðt¹æ£mÛ^KÇw0ÒßÁÔ`š'dÀŒÏ—¥PA2ØùZʯk·W¼2ˆ‹£ –aêLÊ ÔM;ï‰SGÓ=m '!N){l@Fž!vÁò6ŸÓAPý¸Î/̸o}Îçà‹8þ·•ÔÓÓ+,QBI‚Ú^GÈJÈŸ’'uá3ÛOE0#“+áxdi]¤™C€mòoY­¼äÆÏèfHI¯##ÊH*ÉÓž©SNRñV. ë2)£tIi²ªJf"*u]d™Ld#Y~Ëc (KÜN~X·†OñiµÆ;Ÿb⛫Ð'fâ†dšpî#îס¶¸%(H‚Ìfèd”9KM½¢vܰʄâw5ÈÌ9¿e±ÕÜi†2N&c;DAcD(èqœªÓeCYKÏÌÊ%çgjèî={ãT˜E~+D•?åDâœ9É=ãS¤}äüË g9tXPÆqû—5 œB+Ø|ΡÑG`¨ù?—ÞUCšÁƒ2¥,2Î0s‚Söª:¤ydœžœ^ɼd‚}\Õ I1Ëo¨a¸<ôVí÷ÒÓþ£n¸ô¤Ÿàb?–›xÂN!¶‚ÈRôRÆ1ô³BÃâÚ‹Ô44+´4,Mî~çÝëÇïö»œ_ýpÎÙ{íµ_k­½÷ÚÿÕòÇjU¬Þ*]œ/ÐôyZíÿÉÖËu›œ-˸0"ùTú_Q “|÷Ñû¦LŸ8ìý·>Zôó¶ê×½NŽÿiöF¿Ã>ƒ³/õÜ1öÎ'ûŠÆý°?6~ƒºiÔÊ¥¿höß´#ízšÿõÜ=†ùgó_«|{dJdÎw'ŸRý°nöÎÐqúì/ûö3‡%Ú €•ìZ*´úñßst9w÷yÚžÿšóC£ŽÐ†©µj8ÿÃÂ#ºìÿNyXüwÜõhç/B‚wÿ"ƒÕ!Á ¥ ‹ ‰‚~O¶[ Îalbìô á…£-ͼ"HÊd™ƒññXlWDœpq@ Ô ±€ „[1Zr œF6g"JaH­¡°Å3lºüœ™° üªÐ‘°ì3¡;ø›o2Ò*ˆÔFó•<ê…ì"“˜A3Ã8wET&DqÓç9 –oÛU¯³éF¤ˆðK¤áûØ~ˆqŽßò«!@QçA÷Ãt<èb?lƒ`K™GÊdaP{hÕ åæc‰ù#Lü‘8ýHJŽð!å Þ+ ©g1d?Re@ª3 <ÄÌç#(nV»ç]ÁÇ¡qËD^ðФ8ÎHëðõádDéF‰ƒ® ä1ɶ‡q_Ô,­àÚ¢a€á»„ ø¢Nk…t4Ÿàâ2”ÀCH~†:¤á£µvA©ZíRi™olb„.Iµ€O3×X„O¥R2ߨÄ{žT:ðšMBæ&„ÖÝà––|çØÌʘÎî|¢/lB"í$â/~& Ñ%•”ùÆ&&À¯IÉ— ¨bj!],ÖÃs ÁÅ ªBd¾¦RrøKÍ}…{ÜWø‹ÿ¦N³Ȩ\.€y–*¢´¶U8ü>ÑÒzñåµUè<¼lÚ½(>g@M±fgç[-¸ÝÔ­q'WªQoµ¸x8ð#Ò”8©ˆ£@Ë™ÆÃX‘X#8P€P(Ú‘¬A¹c(@2U8J#‚á²›yЭðç,RX ÊÌDAïÄ)1/”ø8¥Ñ¢‡Ÿ…IÉKy ‡¤‡e ìÈÆà¡²âI…s@½.‡ÅÈauM0è$VŠ´Ôƒ0…o²ÐPÿY³Ä9!ÅÊŒ´†¯˜„1dL ¼9d"ôX` ’wx2á×ü¨Ÿ‚™µÂI¥Ý«’)Ó+LŒ DžG²£„ˆÀ<¹Ú)˜ µJJ]‰»Bg1åQ(†,Æ/ÄAi›Íjϧ¸ý(ã<ùæ2Oƒ–“ƒF‘[ðØ$ÃRI1…Ò”ÝÐZÁµ„ŽÈ$C°e -cåÅL‘ãdr¾fpŠEÑL¤yUÁ ›˜´{»Ú‘ )Ô‘†„üÓ>4†Aì„—÷’ TTŽ5ô•W3 ÅÀvܨtÇ5ÄŠrUÁ3“.Îd1´6Ë(bç2)VØ9v+\`¸\‰Ï0«R ‡×6%‘˜Rq*„cÜ h½'àÆFØ«:{˜*(*-éÌ´êìaˆ†Z)VT—­#Ö’ÅDô`9* 9m„­e·:²s8B8ºÀ…FhÓ”Q•­‚ëÒ±¢ ŒV‘Ž4 “–³G™¸:Ü4ŒÃÎP±òÊŸU¸'Iè 85¡üÁ×VѤZéb¤£{”c[1dæ͸”ð:ËÍlåá.òå¤ðUJfŠd.l2 [0èѸ` ¶1&$XС…Ÿ›bå¬qÆ bb~Ãñ‹ÔûB‰bŒ°Úo"˜Ú@°23¡ ²Sìq,ßט¬ÑhCH€4œ…¶¤ø£“NþŸi!4¦Xj¤X0 ¹-Ϋ -uðŽ—h¥t[nI¯¬ÆJ¬¬”nÉ©(œc¼Çv`Öa’N’²Û²-}dvƒð´æ6%f&3jD¡Iܦ¢8J‰;%S"±@Ìf ^€nGaÍ F·ú> €32Wa,¼ÉA :š·qâÏì1Õà•¶L Éj7›,`­.²ƒâ€àæ`z¡w /h™OÌ2l¯¡ÄJ´o©±QKxuPQãy«Y(Buù$j„’1&0~çá=tŠSÃu&õ¥à♊S{Å0¡¬¢1©#À@ È·ãMkÀGá#@ÉoŠ@~Ì2©¦â¢aT3TibÊòÖ)³®ý\\ߴƤÐ^½2Db&7BÐöW+ÖFGP©“ Š8P„Á9ÜÁ»Öc&+o¬ P'`ƒf5šåȃ‡Ah5g€ãƒ7ÅÉÉ Èµ*¶~@i`<ˆOu@¦Lf' 2zøÍÌêS¨€ðq¡Âh{T«8¦Òs›¤uXÄ¢çϘÈvoËÒ@ Z±3Ø` ­@ö S2öз^ÝJ›&Ü&ã(p¾© ÖÄJB6ÊMÏ.¤8¾þŠ0>Õb°"ÑÎk(ÆÂãMmTÅ ²]Â[ K5¯›Þì¨Úl'(A×Ói„ÿ×]õý‚O{þ_!Ú±ÿ—ZÞåÿÑOGü¿ú’ø-7hÖÛëÛŽ;2‘·×$ì{²wBJ¯«"ë<<»-{þ쟯=tï·¦½þÝ_øGFðËù>fȯÿ¾ê?ãÝ›½·43.奲w'DZúâ²ú2}¹ù—cÝœûþnþ×÷ïA6»<¸þM`þìºìl(«;wþkCµ"ü¿puX×ý¯Ny$æ_ð¿ÍÿÓ)®fð§7qŠ··÷—ç&Ÿ?åû]vøðáÒÒR»Ý~ñâņ††«W¯®X±Â××wÍš5ׯ_/..^»víí­ž‹ i! š¬¥e‡ý·ïd,´T¯«ð¸ía¯€—Ã÷Ë’tz°ƒ‹Sj<0H ­ö\šJšýÓž)Ø~dx ýôª9/ö÷ ž þêüþû&ö:<ý]¯€€ª¼‡’?ó\Zš6³ú½‡»‡-ì¶ø…þÉoôW¼ÛoFï¸ÿzdîÐÀ°5ç {xù)ôE÷;7Üä¥SK—åTž÷<ïåóáŒÔi¯,òñêá{*ýà;Þ#<§=}ª*q±ÇœÚ€ùûsCevÛ£ô˶6ê_HZ‰õ¿¹Óý?á7tÿ;"DªVk ÿ']ó¿3Æÿ“t½àæ÷¨`M¥‰Œ "ðýtsû3;òòMØK+óãøÂ…¸Àag ya«í:ƒ ,±w’ÉÏQ9Êhmn·æá¥ˆœ_(!e±æ+¤˜áœãÉ.=ïÀ¥Íô`ƒÏü¤ÜÿÄ\ Ãà(T‰ tà 'Ç&ƒŠvdÒ`A¤…Qˆf²qd!/h¡„<.ø‡ƒø´ôߺXr¿ÿmœg 컪]ümˆÛýð.ýß)Ok÷¿= þ¿SþÏUàOÿ üsêáÓ¢G`ößG´ïÍcÉGf¢ÊzÈú¿ãqäë½Kø )Ãÿ‡ÿ…ì&Ý] ù¯ƒó?"4"L¡FøÚðÐ.ýß)£ÿy]l€5¹¢ V‡QM”64*D#u$Vè¶‚÷!I$â<Ó|£ÛBŸm*0µnPQIÄ“{èÒH?9‰BÇåÀþ7Ь˕„Ûsƒœá›Ü&4¾ÏN‹l8Œ4úoœ°WBò­T6ö=EWF˜-]X´•¯¢ûF;@ Ýr ]S4r÷²eO‹¹(™û‰ŽcÁúžë™YLðaÞ82]aËäûp»íB—n“zé`—œqįFI±.8psyÍòÛÜâ\› #²‰s1g}ÑÉ?,Àuçå%ÂÐÞ‚œ÷;Ÿè…ÎÿÎNEw V½µ‰Þnð¸ƒ\À;Íæ\”„|3ï‘çÆ$èz ],IË!kñþ5:î¸{€núŸdÁc4ŒøŒd-7Ñ# †œƒ¼GþTFÖç„ïò"Ù°w0ØBбq.e\S˜Þ Uµ2®„ï™+m\YJJàa*xŒŒ‰¡Ôðô“÷jt ,<Þ!$¨’ ·-ã|ÀöŠÚä…&C~øÄ£1R>\Ξ>"ÜG7"¨k¥2ãó”ÔA:/ß—Œ=ŠtÁIŒð“T[ábÜ}Ò ÛefOm8!„®ÎÍÑÍëHŸ }×ýæ°›”8"<昋} çüË»c‚óÙnâ]˱’ÉY’€i«íÏ3ÿ°JÀ2f´­x×è¼)ˆOYy¬àVHÜFñ‘«IäÀIzHXc‹#/OP¿T¢ØzA݉U`ìØ<ÂM'Q3qdo<Úª¯àH=R•霾ÁŠïMÚ¬èê#ª’*²:Ð ÊbµÁz£ª©¨ÉPËš ¿C)Ê0j=üou8¥@ê<Öo ‚f7Ì¢zÀO>\øØ Æh BOVä¼­`ÖÌØ§i˜¨ïè’S=æ%¾f!—ó»;¸KÜq X7K¾s3öóµÁ¡˜¥Ù/H†1F磯æç¦@K« 8?>»fs_1.%ö€æÞ,äó0 ŠêÅ£Îwpe‰ó…I+ή„pèƒ#º2Ì Ž>uôŒP 3Ìø»˜v¾S •¨ÂHr°^ÜL‹£öã·÷bc»¯+P·?ë%,:)KK!T3mÛÿÂý_ã]ûÍ<í¬ÿ4`áñÿ´aááZu¸ÅŸ»Öð´vþ‹â ù¥Ö—àÿí<áõìeYÇðÿµ7þ•T’í×c­ß¹‰ã—f~wLr»¨*a݆ç'„”þ\¿ÆÙýfè·¾Ô´Œ¬ï¿áhÝæ{ÒtÛÞ˜`îõÀ3ªÍ7/éÝ|Ä÷örµÕ¸æL°÷ªþO~–yáÄàŸw9øÇÍþ™E”é=¯œõrÞð9’÷ÃÃ~U¼|èÝ…¦A_O.ݧ»}凳3^Õ¾Ðò}øû'O&f~óÂñ´ÏáïTmþ¾îqçÆ}G~ÝûöÚ¥·nŽ>z}Y¸:j‡ÇÖ_WŸ)ôôÜqʹxÎêÃá{Þêg:IÍ/ðý¹OlÄ­´ÅË{û.9V5}­÷+Ýí–Á¿=óÖÙ• KvgF÷ùå&epÜßë¤uGóð…#|÷_r#Egîóóï÷å.÷BFÕõÝ8•j>¿ãMEî•úLc@®[mý'ÑËÊýº[/•4g=ºæ·ç_]¿þxRYÜwæw¦qÏc“‡*=Ò·Ï™÷Ä7ž{nù.T{ë±ßë'Ð/ØuÕ¬¼” ™Ò¿çô½º’¾ÙÃý>¿íüiÏ«ë?ýæý÷žÒG‡ŠØ<×;`ÕjÕÆ¦±Tõ§Ο¿}eæCåMúŠ”A[wOª]X4Ð9.«6n@í‚YÏy…›\K:]¾Ø2cuÝ–ÃK/¯ë™qé‹á™Ú¹öÆÌ¾¾«zßÔ~Ý> ù>ÇGEßVoÉùvø´Ø7›WŸHêsÝè–fËR´iQ—Ç|׎$÷äfž5»óå?÷bü'­ZÛÿ©S ùïÿ÷„ûÿ#Úþôdöÿ³Ö‚_[rK7€?C¸3÷Ž|zJí= 4s<5`qfzïèä Yvï>§ŸLèñc»&ÜÿÝG¸ÿo-„—\ƒ2óÆ Hõ<ö®Hƒö쿈pÿ3D ¬¾ðÐPèÿªQwÍÿÎxZ‰ÿÙá?ÇÜëîÉŸ˜”pÏg^ƒ¼£»?õà‰ƒ2™G" ÍÍÍMMM®úïô2Yz™_nùz£wnEUmC`Ù‰À’šáËùÿÃ5¸ä„_I_±Ë¯Äå[|È›®’é+¼s+½‹]Þ´KF»j®øç–§®ªª©oÔ”ÕúWùÒU M²ÜJYn• ¤Ï­H-¯iljnjn^媫¬m(®¬­¨©×8ë|s+}s+|éJo}E3Réå2=ø¯ñNw&–UŽrÖúÑ•~tUºÓÕÜÜRÓДXæV¸#±¬Ê骧·Öø–Ô˜wž)wÕkÊjœ5 úŠZíÒ}‰NÀKSzyM\yý(g}ÜÊ#®úÆÊÚFÿ•§ýÊjWŸÉ-w%VÔ§–×–ÕWÕ7É@Y ÎšÆ†ÆæÊú¦úÆæôŠú@g}bymjEèòzÍ+_ÄU4Ä•7445§W6¦V‚— ¹åU©•#oÍûØÌ)P¦F>W¹æÚ´ºäþÇ>PLö /Ï[¶¹Ï›{ú>¨´L÷È¥)Գ˔¡i¯‡´´ÌÚßd^Üxtòú1ÙÅMª]'r}¹¨¥ö·óÝ÷ ºU:dèÃÿ‡Ý²ìùço†gE¾?pUò†³¡~zÿò×½ºÔ³î«†[_½ ¾VmýqIIìW7¯ù?Q=ÖÞ{azõ’Û…š\št¤úèúuC‡è¯¦]‰~´q÷Ч®ô;mùÅrü"îÿÖ§XûìØø"×@eUÑžÁ%³fmëùéÅ´ríþcfž«ÚõûçÝw¸¾SqcèÚßÃÏî¹rhÑ0ǹè_’+«÷:}¯:íÒý£ýïKL8À<ÚøÒÙ^ù™5 ûwoèá<~ö¹Eƒ÷5pëºËþ[•wÁ¹—âê¼¶œ \Sùèc{â­âñ'ût»üÊ©6ÔÕÔDõ|~|œáïš½'Ÿ±D~=ëžÇ‡m{ÂÃõÈà„¿½´ü—¨×ænêû͌ʜŸOzúžÓ´>R÷ê±È]ûN-yüGeʶZùpÕ®ª™G¶†È#/dÐÎÌOO{Ù£7ÙŸ5–—Ê?jœfœ˜˜¹íí¦u[~tùè?Œ{óÀÆMYÔõپήX¶"cÜCK¯•ôªz7Ty+¬:nhøÖˆ çã/,1ì•0³úÞ÷R•/&žëÞsãçëfg„†ýøßì]{xTÕµ? ^{½½jmûõóöV'GLÎqNNrΙ3“Ìp˜+ $!$„„Âd¢çÌL’!!„ïŽÒ–< õ³pïó¿9+˜Ñ(‡é“¿µ××<ÿOu°ßÿpiÍéRu¬ÿt翞ÿù=½†qù /ÄwWw6Ç¥BèƒÞ?ý·BŸÀ± Ø8Ö?ÔW¬˜ûÙüÉ\ç-S¸gà}Ï↔ýÍv¾q[õù÷ÜPÊñƒÑÂü¼+¸]·VrÛª»|ä•Ç#äé[JÈK´‘®¨óмr®s Ú›*¸œ[§p'n:œ<8+ü&ê¢<î\H–_%¹¿E ‹§ýœ,0Ï' B÷ⱨš³?âþ¶z&GÞ[{]òC«ÿ÷ñ;dãäÉyãȺ%Aò`›D¾Ø³ìßûÁÉemJv‚þÁ ·b] G°ú|G¿ßþ=|ðKòöÆ¥äøÑ¿'ûÖ/kx>A¿|·;AÿþÚk{Ñ⯠ïþcy,¢’ן»x°g«o^yÃÎý“ ÜÉý†Žóȶ'êÈïm^×—o°ÑþU°·ÅWA ÿy©«•Üi]ôU‚~e=w"A?X[ÓÌ‘…~f°ÕîýãuÜgC¡ÇöL#Gncô«ô¸ C¥ÇvïÕ™;‰›› ¿«ŠûéöU¿<¹ûww—®ûù×Ò/¹ŠûâÚ>ð‚â;ÚGŽø„¼õðd˜7l@Ú§aýà/Mùàê[ >þÓ©G’ëoèG‹vÙÓ‹»«¸K^_ѶçàÞmä•yi”î¹ÿüÓ"?—1mÏ×Òí;žŸMV„¹Ã÷TsÆPéz¾–·_¶ì­6çÄ¥wàŽÛu.Çm‚ òša7Ût.›{hNÌá¸S„ጠÚÿpƒã û ùÐÚu¹¼ëK¹{+~íh=‰; }û®)á>š3Û-zíDîÇß„ï`­­€<ç€_î¸y2‹‘ží¾™©dý½5dÃÒ:²~i-銸ȼŠa€õ^r&²Þûú0°ŸÜ‡fÉäãw6‘}»ß&ï¾úòÚ³óÉ›ë’[×’}½E6¯˜CnšrÖAÐMÛ?"èª]Æí¼ï'ÛÒé6òÛùÅŽÝ^u`|ÅeÀ¼V€M†ÙSaÏGâ=`ƒÜпXò÷<Šlð'dï¿m*ÃDÀ ²0xÍo¬¾ƒ¼õ½4g,k‘ä¿â†²}ócdÙŒËÈÕ?€ñyá¾úäø#¬^h’y•?œÿ5ö>÷ΩÜ.ÄÒµÍ [6Íù9üåî~¹_;ß\Mºf«l ×&¿û2Ùÿé{dÇ–•dÁÕ?¤ýkÈñcGèüw7/?þ$œN>àÐskš{cÛž?Þ? ìÄ óØöW%KêÑOÿÿ»êö~óWÜXºy Ù@3üÑ:îX_lE¼Ê sð–ßÎ%´^A×ò—ß/pÞ¶W= ¾øß}åßåã®Á:¡¯ü¯ö¼9$ù½tròäiÇþúù.v¾®¯ü¥&·m ¼´óÅ›‡,wïû[ÈšEW“'owÚýŸ¶ÇýåCü¿ÝW>Ôg[¾+ùˆå=}ä/î+»}æ»ZÔ™T6Ö€?Ù}åc[r·ÿEˆ÷—®½ø[—52•²· $;®ƒ‰~¢žìùÃbòÁšyíîQd]ëðoEþS ΠG ÿ¹O'ÛšùW~ˆ8qôÐçäËëÉûkbäÕx½~&í‰i4î–&øÉE¾zïI\¾Ž>@>{óQòv×ÐÅYÿ°üû,î¯PÛüç×ÉÛÁùN$Öpêäqòå{ÈŽgšÉÆÈùß|ïõÜqØWùPd÷XƒðúíÇNêÎ¥‡öþ™ì|a.yñ—?²lÀÕ#PÇ èïC±ÅS×{Þ?¸w{r Gî%®»ŽlhÿÁ rWöBNÿ쎩gv Øhþûô×VÌ>†y__íyƒ¼yÉ€r±†y0À…µß¦rû¶®–«>}g59ôÙ6²my°—Ü5 ÷¡ w ä>í¬o[v¿¸|sWÃßÃyþ…Îó“Ø6^µ°Š;÷»’Ûk UÜ/vþ¡ë$ÖO1ÙK¾¹=Ûúe»7ΕQv×÷-Û«Ï[´èª³Ÿ:c^. dÓ0¸âÈ)Žóžà¸KpÜ íâ¸s±m⸳¾®%æˆÓK—xÎAÞTÆ.p#—BÁê…6Šýgyõúÿüщßö7Àÿÿ¿Ë¡;NQ25è߯ÿÿ«®}ÿë{y%¾ÿ•4=û¸*«²ÿ˜3CÕm™Ùn-Ë­e÷üpüL.~$7þ0Ohœ¶t[q¨Ý6Ùœêñ=ñïJåÌhšÍ¾ç-DÊÝ6nF]#>ë+\kºŸÜ)ÒOú¶™ ¶†p ÔØ ÚÚƒ!öe–¢‚I6þ¤/ÈS\6Fníh¥ø˜¼’ñ6þôLpiIþ`‰OqǤgêéªáHUÝŠË–žéÈÌ´ ef«dƒþ"s6&²ïÌrÛtg–N?hLqœüôt“dJ©^ IÍb$dtÿþaŸ#MoZš;$Ч¾4¶ SE» ŒÀå¦8JÓ½eìøø=ƒœ:³ŸÐ-ìj¶èÈ­3ب 9E1æ ×)iirüY‘BFu†ÄÆE1BI¤§‹Í>xýF½/àFñÚSoøºŸžXž &úc~O¥'†ÒªªÚíi1OÀPbžnÎ ™ŠMFSrø¸ÒP-¸‡TVšÚ饔V›&J”ÂÙÒ„|3ÎÖn(–ì(’´é#ðj„gœ-—uÑ[#_0%KŒØÔѶ\YqÉú4Úƒ‰mFFµ¯z¤ÿ a¤ G«ªZDû(ÑW=Êňhõe®^‘!9U˜'ûªÝ—UUùªªdÎÕƒìŒ\Ùá0"ú4w¾DAA#–yò„ ¬8ň˗é7‚—\h(ž›+–'(ÓlAÃàUÇõŒ6YÍ‚"RS…€Ou§X`‹]š’jUÖZéM\*Î#K4í»T`c.§›ºŠÒ,ø\~ÜŽÈ,¨w&V„ÒD°° 2ñ!´Z6‘Õ†x›`}e48°ÒûÄ7ÊŠ®Ü7zVe§˜¶a•0&;'G½=´‘U:à¤ä¸6+éªÚdAɖФ‰R> Ü^„¡òøtçØ~Ó‹˜ž ÞèµSš1}h&&DÀ”`|2©Ïì7³¨ßLYÍg+oHNÖ£Ñ\Á:—Ô™ —J€>]R|ÿ¹áèZ1¼já«¶òÛèß YQ€\MVê^–yqTºêhàupy³wy×€Ùã¶¢pY“šš“A»qÊÎB‘(éu€L°Tfñ¢G¯cʤÁˆ Ž|¿æ§P§Š¡\3 €UKâ]¾1þŒH¼0Êcx!ˆÑ"Ð}?‚p·m4±ÀÃ3ôÂkí° R‹!ñÒ¢—€J°“e%$}a?&dèòYþÄ»<ž©±âm Óx\§<-Ó\YËaÚ—Â8 z­§×1P2 Öb p:*áauCŽSeö“lTZl³Œ$¯–\1tTºs;'ˆ1sÓKÐ872ÓíJ1, :¡î¡¢Àä0¯#¾I%À“B‘V•æÅÔá¦ðúáØ8uJŠIw]KýY.•“\“ºYkcÁ­x»‰!Jn™"+µP!óZDzU% 2¯^ÉS Ùéœ$-IÑáNÑ%µÞ'`ê¼2]­àÑ  låÔªaC­ð† ù¨5ôÊ®¸].ô„Gª5ž°ÝΠ^ÑÁÀ4;«“Åê5áÍAÙl•ÕÙlôBênvÃŒ˜¨V€ËãÔ Áb€öN }W` Ö¹üO™!dTU5gÔJps5–0°c¼hÙAŸUižnXJ€ª>š˜¨6¥¦fè¢úx.y‚îgÌŒ ,9ÊÈD‡¢šƒu 0ººuhÔn_s>»”G+1áÀirO¦f/¦J3ëi ¥˜`)S¤TØ6Îgn¤öÎñT^ªG¾»’}2ù ¸¬n×Ðg•¬*ög»iÐR—iÂRØ® ›µ$á|”•Z +”ltDµ¡O &ЯwüQD4 $B˜#ˆBçøDÕ†Ú«—¢ËB=•–¼ÔƒáÂÍ£»Y¬0`~+ë9 ÖN6nçSxÉgÂæi90XL¢—Çñ+ZG%Æ( ! n•àÚÖ—«dùÆch†«¦iÁê—ðdÍ¢µž õRTÂi\Á’F)’ÖÑËS´1¢u°B³“N'n£NÔ:äì`&@JHÑyB †<õ2e/²­È;Æ‚ÛÁ,YËxUå㡞@üG~4'`·È0ó-:´)Q„¼,[φ”€Õš+ Pì(Ó2€8ÂtRLË]–€ã½àä0IŠ;–è ¢Ð~AÎI¨’˜'~ Àº/=ù6ç$!,ÅKhÖnZ¥QL7ÞIšâž()ÜÈ=†–+ëm(¼95eçüëȧ(à¡‹ Š&Mß.ôû|›Ò‰ng‡ãGÖ¸l0XÙÔ`°m[†’MU‰IaC‘à -JŽÄêIpÈ*#Ðgyè|…Î÷æÅz~ñë|Lò„BÃ#й<ééáX©xXHá*NVàö‹X-"†ÒâUÑ™5,,VÕv„Ì€?îýj»è,‚kGGjªÚNÅÁŒ¸ìµÏ¿;%ƒ+µf.6_mдðP6¸ñvT›ä„3€¤7ÃN$gž‘Ñ™îÕÃѬÑéÞ¬+£Êì¨st4kVºW™š–´¬;J¨Z¨ðHV z „ã!=&±“a;Ö# s{æ2Ì{)ô\[1åJQÐ| ƒåj8øµøüÞ| ͦQ^r4&!PVr(•@P§!±ÚI»À÷•P|9ËZ=:1=¶¡”јq¶Çc¦ ˜IÊôDžïQ¦Câã•æ G+ïIÖ`"t+͆ ê„+´2,ê!Q{,¬•é’…U)Þ¹àœ_ªL8!+ñhT)«Í‚h@Õï ”J°EÆE™ÄØÉòêÍî­>P†ÑÌ ²kÃnwbN¥5¡RÉÊ)úÎ|Ðb†Ž÷ù‚~pã[ÐÛÝá6ãPL¢¯?©„ˆZnK0°üÑ¥-èS”)¸LK¤%m¬8¢”#ò‹)XÝâÉOoñ0FŒu3±sf«A ™A÷@ÊB–J…;ôÑðo‡2„§D—‰°ÀõxÔuCüõšq:^õŒWH·^ Ñm‚X:cꨈuaP¨z¢ÇìvìÖ+A0j˜ÙŽ¢aÌñS?¸ =nQbz|cNEKjjK-£Á™‡^½àøê­¥ŒuGh%I-†@ŽÇGZ •b)ÔbÏØã¸`XÍd¬¬Mž±0&â»Ý ·^ÞÆC¢í&­/”ó$9lX)ì_ Poã}oy4š2ØñGv¶ÀYÖàd“º€Ö;¦„;B0 ;<8é 4g² .ú²SD$DýY®€7{w úcL­bϹña¤ˆŸýƒ`[êJ!Ôuâ…2•þkÈ’´)FDËtóz/鵂òxIÉróZnE7âT^¯‡x‰wÖó~7\çáu˜÷CjÓ-Ñ?11(gÕ@e›Å jå#“eafa8ákA¬¥LX¯»x;=‚D£™5§×˜šcöÿgï?à›®ºÇq¼**¢âÞˆo"„¦i3Ú´ ¡–¶Ì–Õ–Õx'y§M›EF¤(¨**î¸׃Ü¢¸Š}DTˆ{óèïœsï{¥-à÷ó¼ü|ÿÿ¯™fä˜d-tÂbÕA»ƒD$Å…v“ÁQi€ÍË?ÚFðvPra$t¾ä%[ÍT >Çá ¬ ¥›Á-uqRk=t(Õ,605bªµ°Àƒ¼†Á5CpM3°ŸìÃjeÛÊ™Íao'Ò Ö¡C§ÂÿëÃfÉ‹Äi´8} ƒ3dð„½aR*Lõey3ͨXä ¶Áörtš˜ÅæĹ’ép@%h6£ê“3;a*PöJü+zƒHÂ!=°Í¡0° Úý³½ÒZÔŒ¿‰RÁ/YD€RöJ”Ìó›àÃK?¬S­¶búÕKø(y9„†mªÇ&H5­+5ØGÜ8>>,3R è‡Þ¤t…í£¢ii׌V&kC–Ë ÕÙ„ëÑÌaÕЇF[–b ô1¶fFû4Ðg2ô¥™xXþ¬††@®É>Ý\:8?„TN2#»‡§ùìvÐ n+³AE…ðÕÃ?©Müï½îX_«XMt’=mQ !9–@ph¼[š±íVXO³·™YAi¶Oö?{ƒÑ /È^×Læ»fÅ|G›6L–Èù )’Yã pSon ’ƒH5œ·ÉÖ]jnhÈA0ó1fJ !ä,“8>ã f\•qtÆY›q•eÄ‘G4#Îˈ±Í @3—úÜÀF Ï7äúáÓ@Öœ s a-¶6o³jB2:(H–§áb‰z›Å0Ü^&¸ÚaÜ®öã aÃóíe# h—Ë&”²®6V?iIiÀÃMâ܌ݞ#±5#†Ìùry[-+ŸšQkvVb¸ÝÎûµPŠš”Þƒ³f, hPÕ¡V…ÖXuøÔ·!WrUfwÇʹæòÙÌUë(¦ ¿­m¸ÏØÆf\_`1Ào ò¶6P@€«€ÂÈ•êíhK•UòòÌwx]X«‰*ÈbjÿêÙð‚R¨`ùž>¬Ž”[ "öPJ#›kñ6á¶÷´Œ€½—×bfê[S} è‡Xˆþ€* Ó7¦(áW¤b¸ï’ùLÖ0cÓ%¦filuáå°|”‘ŸÈÞ`62Î@J*:Yà äSŽ©Ô-ÿE¶¶SÐ1‚ÂY)˜É@O…æV´õUµzÉ2Ö ›Œ €­Üy•ÚÏöÕAk£ü¥ØŒæ†ãd" ˜-ίŸ„`‹-(ÛœðéƒÏB%¡ùEÓ4¦PxK\nÅæ¬! b7PI¡úÜ!Âs`Åö1ôÆÖý3ŒoŠgf·ÅjOÏ~ÎËOSŸ¶‘I˜ꢖâ©Ù¯:Ð?2Y}JÖÎâ:èÚÖâZÔ`Šk¬5ÜC\®ËB¦Tºm.´©Îtf§X³rÉO”H¢â $¿(à*'bÙf°OvŠ` %ðY ¿áyá\øœ ê3°î}ÚîYï¶M¹çMZÁ6 lH¹@宋'0û@w>3¦ª.ÖÂ09Š«•r£ÈŒÏ€Z¥yj·ÉOÇ«Oëe‹¾Ćh&¡CŸŠÚùÒ£M‹ä.Ð,èÔ¶&ÐMU.Fôž`ª~õ…3@ƒ;£ì.â®\ªqáZ9™;ÚÁAë4 hä0vQ9‚.™U\EWPºŸ™ù’l„½ÜcZ*º™%Š 2F°Ê\V$=É‘`v æ:±T]+ Å8¡Ü«Ì™JÁ÷‘æáÅcJ @AZ‚b4ÌÉkÌ4ðV3`‹ò®¡¡xTü©ìVÈRT嵜m&ìø,9ÌdÈ-Ï5ä‚|a)§¼”ŸšN6k ŒU ÔŸlm,å/‡ÁKND‹Æ±4Û Y"8ÝHû°Tà LŒ-ø0Úp²®˜ˆÂ•ÁÞ†f,Ü÷üâ m¡ÐðH½£1¯¶N¹îùù¹CÔ÷O½ÞwâõôÂs+9M°¹(Æ»ÑÓ* @+4e‡Ø©tQ¹îŒÛËs¦ ZbOÆóad;÷C‡"5Ú"Œšc¹ÂZ‹ÑhV®xž¦Ü ]9…öëøJßÎTžý.îÔÌÜ$ûƒŠ;0BC4cpŒ™ tÍ&„ J”ÐJ o-zƒ€DN$±¾‰øT±ÁŒnˆQõYa=ƒÂ ŒÖÔE³ýDÚÆJ]/ÕUŸa]/¯[Ü®ŽÞ1cŠ:;üí§þvލ™½}µ9žøß4%ôˆ$ÁFÒe)œ(?+œ¨<«RžU)Ïâʳ¸üÌ!³Aƒc²R.¦”‹ÉÏŠÊägEeʳyʳyò3{R~fOª" Ð#‡+ä;k3ö²LQgÆždV Ñ:ÃÌ­Å ^SH .":Ç4Srõf4iê'5ØWŽÑ-ÜY DÎg­íÂжÜá®ÏŸejh¨7 ÃN)Ei­=¤5a˜©~аÁ³xAÓ€ ÆR+kœ¨7ù¨è6+U@ó1”B9, â(AæÒúY&´ñÐ;ÒŠT*ã¶ž Í«4¨Ñâh¢ ûydœÅ–BC³†yhB¹u‡¸$–ôˆ ÷¤•e˜…ôtâáPßWê‡× 7)Ò¶”¾S€DŠG/¥,1½–bÞ7óØúª6±¡Cc,FBþR¯=1o `h†­‘^B²£Æ2Ç™²^3È›Âá'pìŽoÊ“bƨŠÑaïd‹£Å[Te‰x-{™BÎ +<h£­‘Ô4Yl÷ „N¢ ¹G½ø£Óüô:Ûǘ5® Ó N‰ýŠOm†Ùœ Áì x0 ‚’£…Ë7)R4ÜŸèW {«»&̇ÁÁÊÖÈ]Ðh&&‚Éœ‚ &uÈä³OSD"¨F3ˆ´³áGh*Ü(S`q„HûhîyZ˜úõF`¸ `¸ø™k(  9Æ>ÆMŸ0Å)&OÔõFÙ,£\#ãªYQ51thk}“ìm›‘ÉD5óŸ/2cPÃQ´Õ°~Ñ¡ÕÅ€ÃÖH…™%aQ…IÒ5½+á•Áºøîk&K b•l3B–a„àå³*˜è³¦x¹³µ€í åÆ öp¬5˜Ú"„|‘\øëÑÛÔÐ äÒLl£°4“PX GûС>+0ÆÏLfŒ™1ÈtAñˆ0|æLp˜â´:åA<«°uX"J×q¥ëˆ¿k·©8a†½âé×q×ÂÈ"l×ó…rºDêœëÉ åJ δ¯ #C0%ÌVç öšüa½ LMûºÞ`–[½XY±±™K¶ dNAe„•ežW¬'K+¶×ˆ 0ðyd.ãÆVû´|6\À óÊì  F÷Ôe™¯¬ËСQP̲P0VH03Ç4/ . ÂT›,¦”½,AÙËâÑ£­Î±H›£ÉjwšñÆ­;aÑG›¤A){€?êƒ8sF_‘à ŒÙ‰-V¢ãÓéÔ–R QßV¥T`R²­Š‡¯Ðšˆêòˆ°Øó^?ôS:z•dž2…ÇeD àqº*‚Ûf>ÀEÊŽ3!r³³ˆaåÜ "ƒ·šŽ‚àÒcöüâ˜;ÐEr½¡8*G„â°PÜ*Ø“Bq‹àt …¡¨E(¬ŠCB•PÜ,7 Îñ‚½S(…¡XŠ}Ba±PŠE¡¸Xp¶ Å.¡¸H(v EÁ>Np– E~a¢PlŠm‚£Ð@` ²…‚œ“žP^†Q£Æú }zhÈÕ8#»—ñ¤|5ØDÖâXOš°úz¾G¯]3ùᵳ܋`-çÂÙÇ™ñÐ=–o‹Œ`MJˆ2ã‘¿:³§ÙŠT®Éi…( XőҘ]V×XQ£±êqÕ°I.A%1Œ’'À°Šc`Í»Ìê m< [>¦€ü‡}3™|òD2w¢Ë:(^¾-‘±Î8&Ë'búÖ“²!HD6I'¨sËÇŠK)0È§Øæ;œ /8œ{‡[„©¹µ|]˜w!nRN ®1×h‹k”ÅUaq•[\# :q!ŠzÕŸ!öH/ÉŽŒŽRjd„"Ã9~€ÏÅ¡P]GG@påq½',€XtPô¦¹EÄ?r'±R{ŒFë³ÔYø1Qx[ÁŽiÞÓ/XŒyô¾|—c CSÊ #{D™a†6Š (˜¨¨ÀX[8ÓZ8!Õ>{­»Àâšç68§äwä‰yŽ©yb»Áâê€2ü©r×Y gÀÇdøãœ "Þ*nŸ`l ø0à±k<ˆ[Áq³#Ê8S‹ƒµî˜GÅñ‰-AeĤÁâlw†å3 pÚhx0ižŸd§5«-I ÿ/i>I:­Ûd±Ïôæ{JMC3ƒñt…-m©²Lô&A«#wãhSÒZ5thÒêê üâ¾\øÆ¶7|aålhÎvN¢p^:ÌϾ‚7"†2ÚgšÍø=×k’åC×ùæRÃPƒÛPŠ1½I«sR&cp¥á‡Á[ÊNƒ@ U òÃ_µ™*l¤ªþË¥Ú=UöИ5º”ñÁØ|Rr{™ŒvŒæùM4Ü‘d`ÄùÉýåò^ûL‹ÁkÈmÊ5àÉìGô²&zz‡<#͇ŽRB¬*¯è±MÃp1ÔÉØ ›ÝÃÎ0ÒOY?G»YcÉšÉeÅgÍáøm3€˜és2[‚^²(àGs'íQt%Ë#Ì7Ø3CÍŽˆC hé-†Áb†ÝöËSjÍ5™Z½TÏ\Ú뢠¨ˆkÐÅñEé7ë …=Û:ªh/b~Ô‰PÈ$R Qä¢çí¹ntf@Cù¦úYð·ôdŒõèAÃû:4Šd•Æßíì;¹;a‹aÆítÇt)Ž]sB·Ùê ¨W øØâÅod‘ÆÂ~xŠÆ0±‰+݃Âè ú¤³òè HùŽy~M2 (ëÜÂ3¿ÍHðmö.ôfO&k„Ígu%Kí#WÒd%«è7˜ÝøSÞª…3Ì~kÑÓD þ8l|ŠßȪ˜ýÖŒ8ÇpÜouŽ„V}y¢h€w®y¼ÉùMI^á”<±Å*ç¼zl¢v›è²b‘  ¢S(œà¦ÿ "â«7=¯df^É à*®„ò°döa›ˆX윌Ml,U¿æ,R47>²:ÛÍêv€‘Eˆ E€ô'¹-•á¢N^ôà ³œÌ±JE¦‘K=ÔjdYiäÐPhtÑÊ€:Žo{-®O„Äu`}.4«“-Ü–öò÷è,«EWY…ÕÕbò£ ¤D¤%…58W3Žá 0˜kjŠKЉ6f<´ŒT´h:+‰ SR#OŠ ÇpÛ«5@ ðÈè·Ž…5Á¢tàÁÎñd´¼F^æ91#žuQ’à  ÆÚÒí°’³-ÔuuÉ?ÈÛå ¼Ôæ`%ìµ# Ì x3ìö£Ñ•ÀL¾â€‰  ÂpêàuÉ$Â+>6¥ß:”#‰¨C?FyâÐ mÓšM3UÑè²W¯\^=L¾0N®2«Œ3ù{¬2JYp…Àäå!ž¨EF¸Ã½­ŸITŒ™_ (™ñ‰=êÖxæðÞ*a`¦s" <üæOq„é¡CÌ” 9*Œ»Э–áuIt;=¼d‚à q}]~ù[ÉxMü.{d€/1¢µÅÕìæ*ôÄ´ 6xHÛåM‚ÄH¸  î±Ñ¢éº1Þfɸ¼‰ Ú'xéÔøDxØ-:Pƒ™?&+ÀRåµO(­%cIÒXÙ' Z…Jª½ÅKˆŒ‡“àm‚æ*¯ÙÏSª¡¥ìUò”çªÈ}j2äVÑI˜VÈ6QùðH’oˆ\¦3ÁíflER•’¨ü;Ò”MC.ý°w ŒíagíÉæ,Ò1˜–FLÝ‚!RÔk¸iÛjQâ­tÃàãÁ·RükÝàø“td}(?4Ä^€:J®Kä\‹³MÏÇZ¢NÙÏf‚´‡Bb3û´uÒg­–›2CÜ6@e%³uY +èT.‰ÂM”ÞE‰$•óô†r¡àüiUE€Û6à,Þˆˆ5©ž½:ôŒ5àRO {D–öUŒ0e›¨Ö$¤Ð΢šÏ¢šÏ¢f!ëÌ•ü@¹2‹Â >íðåá”þ\ÅL÷µG˜ÝJI#HÙ¸ƒÅgÆüvÅŠÍÉ-jFf°‘á'Ž >»²Œ€°êõ¤ŽÑÑw„w).Í*xÚd´:oÝÚ±YBQ=¨V TöT€Fà Tt+ЩÇš.ô6@¹ˆÈð©ËbÇhÑVK :é™oØ™ËÄ~£¾\ßlu!ï-5L‚é;Š`úYÙ¯èà~i ó1¢Á·ØF{õà³8‹¼.ÏS÷a+Öo­c0 ŽÑ™Œü{úÛm£¡Ý {2æ!>ÆYV…L&Î!˜ç5tè´:^ć™)þDG{BÔPÄY¨ µ•©Ç­ä¥ç¹!(ɨ½Øä,²p7`¾=’±MÈØªYâ³Yª'Á b(µVÑÂ-6šZÙ‘}$Ó,Á®ÏÍkôš)48›‡G¹LÖaæÁù@l}^ÉjK™ª)?Ãh'ÈŽ€É‡1K{µ×G8tHm5*eÓaòÎ"ëT<ºc `4N®½Úm™Ø¯|Þ¦y˜Ýç‘ Ú}P3𱄤&úÓÈóJóln›yXšñy$«úñYÐ9Šòo‘Ý1c<V©¾÷ëÉÙG€®¢… ãL öbÔËð`މe¦ãz(Y^;$"jíãj:5s·}\é«™%qXðŸ˜uÅìchÒEûrº6‚· °ÀŠ(c•þ|“HÇC¦‡.8vLÒZ ,•I?ø@ TÏ5…,6† à‘¦2“bb'”y•#´dAùû¹äi†·¹¸ƒ¨¹ÀÆÌúç9K°é¹r–«2/Ï9$òÖT0a» ž¹²‡y®u¼y.ú¸@Ìr*%—Ë­$ ÷'º·ÆbA©Ï=ß6ÎígüžŸb}{Úí³8mnöB”*•¤à[—'`µ§ñ¯=B‚=ÍS”âwŒ/¶ޝÇ`C¿­.'Ô+¬FOû8<¬q^‘_—e+“Ù&,n6ã_>+eÄaÍw¡õ3n‰Ê–"_®8,Þ$Ýc“)Ï^b-I˜âÃðs®9ßnÎ-°š‡‰¹>tdMD§€³Ø]g±«©b€Âzý€0µ ZÃÀZz«c¦ÿ ™‰ø9L S;+Ü i,´Úg˜ù'ÚZ‹ FçaþGհϨÇ69d ¨?ŒÖQ_œÜñïHñ  M¶‹-%;Äàkkú_©ûíå9dùkFrQ$šlD˜Þ±81thbD^I¼4á–sÄÈ%Xr‹c4·ÉˆaOeöà)>’#LP’ Gg5§Z8kŒâ¢—5ðÍ96|T˜˜a󷥘e]0`0d @½£y"nøÃ':˜QÀ/ ³ÈÇi«~ Qqj ¢Ýk6³Í›—Û×Ãó!¢¢‡íàòAku ã@½†„2¶ö°ÄŒìT#•ÄC¯m@kt!},ÀÇ)“Y³x” H]H³vU %ú;­µ@Î&(BÔöZ-÷Êú´ Ÿ! Ë)/wóÃ~M`˜ÎÅõ¢æq)aÍRØä¥ ¢ÎBÞ7ÆÇ`€$y6mæØí,¤d/ÞjäâSðÞVLΆ¬ÄqN‚½¼”"ª–i…U=–ËVkžC)òœ€ŒkAeqíP5ð‹[dÐÆQ)õ±½Éå X²"L S©<„–‡ Íçd\±Õ³æmä´Y '• Q6r9 æFôLÂS`±YxU³ºrM¨¤„óð»y6iæàïB¶Ê‰5ÒËüÂñîù%awI‹¥$ävI—Ó]ÒD+=ßÎó¿Š07»„rûa<å>§íÅ@î²ÀÁ]ßœ~¯~i|”ð V‡^€#/èrû¨°Ç%jò¼öBâŒ%Î#{V¦<Gá3'¡2>óÁ³¢:ùY™úl*>ãbÍR%ìµH廨‡•yQº_D3:!hÊB,L„iVN±6Ц¶*A3K=˜ôðû äãí ÆB©Á¥ G7e':nÝ£³³Á˜ë󨙘e– :íY”P–p]xò(<R·ù¬%vÓ P©èæÞr à­ùéþëv±„þf·|njóSî΢úP)€tlƒÑ ã`l({¹lüŒ¼r<žŸŒÇPú^Nìóé„J1kŸ›Òõ9ƒø³Ó_… l‚tß§ä¨÷Ñ™*Hriy);Ÿ_ûÃd;T-)àUyÞ–R³÷ù){Ÿö‰3È™ÄRö´¨FÓþ€>ܤ*a¼ˆÑRd·•XŒö/ÕJfvÿ/ÌÈ—…dØ•™61‘ KѦTs/Ëɤi)#…“R&Õ‡o¢¿9ñw0–ÈbþtDЦ „ÉDÓáp&™ê C¹6|š‰ÆÒ1"á¤d*ƒwÀCQ „K_"Öž”™X»ORÑZì"ÍBÉx›%š¨ùd&gÚCÑ@¬=ã‹:3q1Ï'@Œd"É”ñ'“("uL fâ‰XœF fü" KêHIÑ@†ÝfÅ2üÆ“LÂ’ˆ{úN1`K35‡ÜH…´ 7_ {°ELò¹±õÕˆ~GªaOĉJÁûØ#1ØÇ8- °IÄ»Hl^(3°<,—Šý…­W» 1¿`Šg,"_ "8Ûa¬Ãi´ç¹œÈv^2áÄ%Œõ%°E|WCdÛóêD8ÑJ†Š$¤0, –¡?be !ï¾Ó€ò&§WWÁVËàî^'Š>é1n@U \! -Ê¥b '2쾩ÌlN+¬(#!ÄêX  DS’˜@íO‘ Ådj  ,7ϤãÄ_)‚ dÆ\ä3t÷¬ê˜Úê*la,¢ …äo…æñÎ.Ë'¤#>h—]ŒFÄÈ0Ðî6†Šqøá—â)Z\@o†? ^4ž¦=ˆ”j‘—ø¡@+ã‹5Í’„Ü,JË¥h‚µŒî6H%†h„ÚÀH’RS‰¬±7@ðn˜T€­.'£<ì1Xò@€}6IÓ¥ÄñRg¦Uê$ŒúÓÆaÔ"…C0é風È-iíCadjÀSbwñVø‹<†q£**ˆ‰¥q¸2‘¡d2í‹@½ òE1ˆ/7'rDËÂÁ9N%.L’ã»V.#ú’±0ë‰h{BŒ—ÁX#ƒ–$®Û™„l·ûS‰0‚€‘3\s1$®$"Ø„¸ÅV#²#‘Àw¤@’¡Œ/Ö­g 2 1Še’í´#R0£àl(¨|Å¥f›’ñ<;ã HÈø–ű°o´°Ø ¢ö0~N¡€TÔH©ô“ÔP¶‘°ùC°'Q``,0©0¶é(Û$ˆ,‰$µ?›°ÿÀè*&V—ÃR#ùcØzàØ7ª’ŠÉ;¨ˆü× ÑlFfÒÄšZÀn¶ÑGÆRH€Yí™)$në®ë§“¸—€–þf"ºlUiINéIq²ŽÜ-1à@,R*K„/iÈ/ ؈œ¹‘,¤OÄ Ä Ä`Êób0ªX€q›ŒqHÀUÆpl0©#žþ ;·1š}[‘I£dÄžÓRâöEýÆ0q {äpä„¿6F…ˆ±ÁfŽ‚¨“h‚áãkdÒ€šQköá­¥Þ y¤â´_`*Lü)̆d¨µŸ>ª|€—øF˜±w$+ ×Í´K¾V؈H›M!ŒÎÌæ²—47cC|fÂñ´ôî(pâ3vx%†ãÍb¦Š˜ hBL¥ÏZZK ‰j¸è‰¬%¡Ð\æ˜â°¯!ÁÆÛQécˆÐÍ„+¤0@¦ %š†ñl$›0H˜B­üsº,ÐrÓXI™@ÊÏZE¹&Ã\|`Ôï˜2Š R;/JïÊ“ 8©E?¤¡°,§ðvØ,HËñÑT’¤%‘p‡_ÊÅ0]'4€&e©LA” $(\E ñXEc°‰ƒn¶y@deB±*ÆÕ_„=m°Í(Cu€x‚™tÍ^œ!È9m. ‰1’°ðúR®îÈ‹F2<}Æ­}XÆ´?ÚÈï˜`_ä–“ä†2îNcŠ2ÿ¥¨?¡`ÁCB€Rf¯IZ-lÛK¼5 |Rç㊞GÂPÈÏ©², £"81RsÀ• × nŒÄ|’>Lò‡…v;*ˆUÌÞ߸åý‰V'Ñ"¨‹?‚HsŠà É VÀm A¡F6ŠÔ$$`PhÒX@’ÓEdí°ŒÉ°à/ˆkmH èòܲ&WTl b %`âø16Šê þ$rIßëâì³w)Hñ²ðK^ƒŒÍnwd&ˆ¨‘‰ Û9`ˆ$Ö#ýHÔJªÌ*Bj¾¬…%“ ï³At™dPRc2Dª9q„·œ.Â6ÉŒ®®%EÅÈŒ­ÄUO l™Úæt¦&û(36˜!z'3.¤µµµ“€gªC°îɲ~Ð/¢¤‚‘8ÌéTŒ‰²~Ä>™üÉ’‹• Æ@Ä%]ˆ];Ò6ÚE–@: ‹Œ“³y#‡f²wM>LQ„zííbãÍ YBÒ„•f”ÇÕLœ€Ÿœ£2ì$‘%i"…’ð’Ä®‘dÌ¿‹>P…2‰ƒ‚Lö £•Œ*&cÆh¶`Î óÿö…ÏYÿt÷ÇQa–yÀ¤¼ââ‡Í6ýûØõýßð­À–c+°8‹{NÍå(püsÿ÷ßñoé¤ £îw|?øzðØ1Sàs:üwRß}àoíÑ¿½û§ÆVWîÿæ¾Ç°·³ýÌ·ääìýÛ¤ªÚÊ?þøcìMïV\÷VÅÊ×=W½QrñsöeO;óáÁ î91}ËÁKlûúÇ_ÿö§_ßݶãæõ›j/Y»Wðƃ—Ûñ/óyœýü±gm˜rLJBò&÷‚[^ú÷ç·<5þìÕ“Ï»»íæ'|õ߯où2oÁêßJûÕïZ®|÷¸‘Y{ÔëÆ®sÖ¶K7>÷ùKž9áŒ'6ùÃág>?ü¢§sZî8"~cÉÊwŸñðQ÷V]¿±ìÒ營¶ªüŒÛo]ÑzÍ#Žy7.¼óÙ—“¾«äú÷¯|z³eÉ#-·¾ôùw?¿üÑW×nøè«êV<Ýqï9‘»çÝþüSï|2íÂûEW4\ü@æÖõöåÏäžó”ëŠWV<÷qû]¯T\ùBÍu/úo}uüëko|cäeÏÕº2gî9ɇÎ}üÃèµÞ¶áÀ•k'}ÇàÓî;åÆ=?áÚWjoÛ|× ›=7m­ZñÂê7¶½ñéwÂe›ßºcㆾm¼õ­‘·}2üÖOWmÜñå¿^þÂçï}õËê·¿ž¾zë[_þ^óÑÉW~pòU[ênÝôÜæOozæÝ…O|â¸ñã¼ë>Î]ùá€ôm«^ÙvóËŸ~üí/å7m{Ç'cþõYù_8oþìñÍ;.fëø»¿ôÜöyáª/fÞ±yÒ};FÝõ•xï–}N‘r*ã9…µkSƒgγøÙÃçÚ¢Ës[κ`póù†ày‡Uús<³pO?ij‡qöi–¦¥¹á Ýÿú¶uÝ'ErF¶:æ^ìä Ÿ3lV¦8~þˆ»¾‹=ñ͈èÙ–K©õ?ŒL,3NMì?v®­é¬’Ô%yñKÊïû©}ÃÏmË×<½mÉÔô’âÀ©W%û–L­\óKæÅßGw\T;÷ôË.¿üÜå—„.ýÐ/ãæ]b¿âŠ+ª×þÞpóÆÙîð?öcóúþ§vÖ?±súc;kÙùJäƒ3rrú|=¶¢¬vÌÒû7v6¼! xüÛ|—!Ü÷¼È€­›Ÿ¾ oä~£^Û0dÍ ¦K/YÞ¼÷éƒÏ_õ¢xóÒñ3.’ê;³ù¬“çL°œÝç çï»Ñþð«wݳvÖêG_ùÞóÓ gýùë;_ÿ¼neÓºŽïwÜ/gÓ[¶lIÞâº}î¥u?Îéò¶O¿þ}ë+5Ÿúýžú9ÿSßZpÃa¿\6~Û©'>4/ýñóŸXßx{ÞÄûg{ìŠkG\õè}£¶Œ?æ÷ü? é³ÙúàК։óŸ-¾çNsÅØÒ“wþ¸þÞtp×ïïÿ¼õÚ_¤š/ùOŽé)á‘oóܨÑö‚c_Þ0æë“æÎݱsÛ#‘Æ­_ýMKäÌ?4íÓuðáwòàû?ãóÙŽûeÒ§žùÍ-M¥'sSÁ)ùOF¾*(ÈézõÙ¯ž{ú;U£¯?ô¼%W=î»;³èœ7šæWß|þa;>?«ÿÀ¢#^¯×YðСŸlYy@ãsŸ2•ϽÿÜw"W¾sNxù{Mköm:úÀ}®ÙÙ÷˜¯W\ylÑœüÍï'eÞuëUG—CW_}äˆÿÜ‘ûÕûE›í«W{É¡_Ü‹¿¹ê5ÿŸ›Wé<ä˜[Ê«óbËg6Çî=1è~>}î×ïÆo½üÌòÜíWÍ|ûʱgýzÞ»«F¿Ýß°sQÎ?λûáÞgÛá÷]ûbõÇÞôäÜvÇYEçŸÿݧOì÷â~E÷ª©6ãSà ss®}ú¥÷ß|çÛI5ŽgwÜì²$>¸ªÏO¾÷_ô}8ìƒI5÷ž2ø;‹ñÏ泆ÝWvÂC?ý¾×/_5mí²Ÿµ.zäŠCŸ«ž–ÿú ©Qßýò̸œmg·¬ªùê'n*Ÿ2ÅûˈÓGO,ÿã;Wn{}¯_Nè—ô=_Ü$æ–¬~ø «ß<î¹­Ç&ÞçÊ~§Õ=xÄCN9ð‚{\y÷Š{:GäÜ}þE}Wœ´rüù##é5wÞtÍ¿íijÛøE¿ç®8ú­½7ÞÖRVÓçÃEkŽ®óΪ¼öGo˜°Ï†Óš>‰mþ!gùI¿ýôÞË·•O>$üdôº5ÇÖºýƒn.päýGM]¼÷‘Çå4%gÚ_k]|Ô–œÃO;7çð…垬|í¡›nºéö§g$W¹¯È&~°}ƒýâ7'2*¿æó%õ—Ÿ1zΪ;ý~è¥ã ïú×ñ÷¼šxô¤·Ž|j^Æ1ñàŽ¾â±Ž‡=]?Ü5$Ù/j¼è¸öãÛ¦ ¸ôý£>½óbkÕÈâ.Z~Ò³fÝhüælߤÕëN />ãß5‹Núó“ÎÛ-§Vž6²ìÃmýKÖØ¿»üé‡Vž3x„ýŒ‹šíÇlšôÈ£sßüò7º.>ü&{͇1lìØçžšòÆ”ï§Ü{T¿£ûß}ͧáKžú4qï’÷ž~m嬚KÞ=sØmCÆßŸ¿ïÝR§––Úy6xú™àÈ©ãf6„ç´Íœ9³mN[[Û“iÉÀÊ%WŸ~Ñ÷/­pÈšWqRiû¬‘íÜ÷éKžÏÔÕyî“DéˆßZÏ?¶ºfú¾‘Å}ÄßC¶¼›óù’ã–·¼ºùØtÍ}7O;wÊm—Ü^ûhUbá }Â1Ç;¸ÿ è™?Ú¸íÕ±yïwô9O­[7äÁÙ­~üÄûÃ/—ŽŸã¹ð‘}ž·þë¢ÍC×®ßqmþO+>úÄ[÷QyCtõð/'~ùBç¥E_¾õç“wä>óÛ‘lCÁal儊œ³èQvùçßÿüŸNþ%'úWXŒ'A H¤Â‡ü_`/°ƒü_d/r8v‡åÿ"»ëùÿïø×ƒü¿?þ·Êÿ¬X|3#™“Óÿ)üo¯gc«ðp?ÔþüóOøZ÷ä àcïÔ” 59Ö/7Ü¿ŽDÙèØ7üι`Î]sVåøدNß¡{™/˜zª{þ‡€üßðO·ÿÙkKò¿ÛÇ®÷¿ÝQ`ýßVà(pڋ๭Ðî°ý³ÿÿŽùùÂà±· ,½¥M°aH³ÝêìÅùEùöB¡ Ä]Pä.t M1Ÿ(TvÄ…Áýúµä*¨¢à•¿d2Â|Á˜ä^F£[˜ßeŒ>©Yl ÅʃT³‘”_è¡ KôKèòôë—?lX?a˜P#¥((@?!4 Ã1%„¢t™KI!Ɖm"3Ú JB²9–à@þu)å÷«§Xɬñ0f9ÆÊÚS˜‡0t¨Z@ÅÒÃÙ!¬{•Â¥{§w¿ªs.#·¤ †ÃBBjBÿeB hæ–Š ¢€¶G[%­P +ŽTŠˆ x‰¾Š<ÅÑ.ˆd»N22×'6¥m(i¤h³EÛ:6È*„h,š7N‰ºêÆ&­YiŠÒŠqX+ÃÆöXx‰ &… ˆ±ö¤Ÿž‚6Züÿ²k)ßh9¼‚m(˜ÌÂ|^G¬V+ÿ¨ƒ-JÑoòFÙœÕq‡`èÆ‚°Àq³ˆ ìÔ †‚ ɶ”H¡wŒaªðÐ~m* läÐ0:òžF¡lLÙ˜ü²qeÓ9`B lˆh98¦ŠádL@¿£€¡—ê<)ÖAˆJí¬/>IŠb[Ìÿn‚’„®HìGŒÊKŠÓ‚]ÀÝ–X ^“{˜ðHA5lH‡b ì–÷ØÇøÀÓIØcyTä¥Ç%A»pyJ÷زM¦´àXX.GËAÃRè®?~‰!{SÖAÁvÁTÃy&±)ÜÇI¹­„Ä;Â×± ¾ 7½ ±ApQWBÌï1òð=¥”¡‰,‚ÇEB*}á•á‹»1‘ ùÓa †ò(Í`§PxcGŠ¡i™nyø"h¡oÆq×Iš……F$Ó¹:kʠת¥qÙÈ®n m y\ð^þä[î6RXS6ÝdUXGe‡äO§$¢Vq$êVzÇö‘ã}MÙ»Ú¢FnJ ¼WÆæ¡‡]ôÙÕOÃ*É£#ððM]F@Øh×Eq!ДGó`ŽYDF‡#áÁà- (gVÓÂ*³‘Áx΢Fè)޹w¨ÂK`vCq‡Š‘¸Ç¼Ì@¿æ¦c)ú9œ~†Ùô£ ~­¢á™°=e&8Þ¸ Ö_“Ô½áždo&¥ ´Ûdä0c†¿VÞˆ‰jZä6ë•Zº‚À¼øXÉ£…umBŒ&Ñ;Ïa©ÐFöÄhS¿à~à[M~&S‹IÒá-!q<’R¢MJä%C°ž)@…æ!L‚锥#ç}ÒªßM0¾“äeæÞtüŠmWF›Â¡d³üÇ-OƪiGL4%•-ɹŒŽƒŠ¨L6Ä("†'sz,7£…­ ü2 ±âMAb´Sh•:AD†aœQRÓ]™4T,Á¾D¼)öŠs³‘b’("ª«ÁDèÅÂ%$¨ˆ¤@JúÅ8òûh IbVÀÍùcž0H¥Ü À¢È •§¨%X[lW ´«¸…š n³ÒÀn PUd£4춪_jŽ…‘ኣã<…ù¥H^cdAæx&ÍFÍ•Y:5g2jš2ši§0”f­Ôx”åpœÐTÖÞ·f°íDn””ò³Å"154ZáÑ‚ 2Ëj &j­òîá¯ÇõðÙ(ïu¶{/Çö,ïG%“6,q_åàƒÀB¤øZóí¡ éᘪm Æ “6ÁK+ x1˜Õ׌øsTCv­<^* ÆSŒnå‰@M×CKêÔÔå4)o9 ÃtÐÀ£ílHyÓ•njÎêl®³îU+Õ-¡E»¬V†hZá’ïnæÐúY„žf“5¨.ÆÝh5mçìºvM¦GÁ‚£Hß)Á,–ŽM¹&¢ÑZŒÉ2®¨ÈŒÄ$N'8Âò§ÂV‚> éfÔƒ¢ÝAœîÔ˰F9±iRLéiQ “§î) › ¥þ2 f³!ÿ5~BPR‰ŠC†Â¥-ß@¥=µŠFÚ qñ„ZVaRXBSáÂ$@ˆB°dú+W´¤Œ•4¼F0IÖ&+‰Ü—Î#îï@áÂ^Ìœ‹TÄêXé6'.¦+cT ¢+¯i½1—Ã#רHpÕσñcv¯ÇW=w®°w¹4(l=uhî®ïŽÆÃ bŠ-%Ûídæ’ZV(ʶWFådîVF&D éLʸŒ ÄÒ©x:%DÒ@sšP¥#¡Jϵò¥©CD<ÒX¨1Úì ŒíM"µçZ¡Ç(Q  )>Rm[ ýx 6o.‚LšÀ½ UÛ‰‹0àè bèŠu›!VÓ:ÑCž7 & =–ˆÂª$BR"8fFNÊ ‘š­¡5&2DXäÖw)óQÑ,™G¨rP<†#o¬¤˜áO˹ƒfY @G:aiU‘^ b\·íÖhT ˜z/z+—´2²èWLçœ5ÄaãÜ0#‹% ˜æ æ©Zõ¢¡xø…mSE÷Á{›E&rõx2\«•tÃÓÜ\³fÃZñX­I)†×h*Š߃&í(ê±ëF¤ŸÚ§Vå\${o¶ÒÑln…`h6ã$ŒO†9c¬° Gi«25î<ºJ|:Dâ&›J3ðXÈX¢#$%ÙÉp#ÐFÜVF\$#Ypñxˆ‘’InQQKg“Æ%cQE+2!a¤ŸV倂©À‚$rW0Î7šQí½@½ÑœELç lnJa=7ýå«t0Ë­Ò=c]T‰ÚfN»²ìMx€Éd4ãSý\Áhöõ •¤y’–xxÎ\`‡ÏAN @¡B‘t„?2“(Ir?ͤ£Q Ãb¢SHÇÛÅD )° (–µ7KQ Eøµbb5ˆ‚ÑP<ÍÀ¤ž•ÓhØé“îÞyú騶œI1BmZ“Ρd2Â[fÃl‚¯f«?™4±EÏu»£|„Ñh¡7©XÄ;øoL {@'æá‰My ä†^ŒH#ëÈÈ͸Bf´'LÆP›Kž\€P®ËN¨Ñ€uËVÇAÀLüê‚i©Sà„nNÎêÝÊŽ´˜ô½MKà8˜G#ÀÓPÔo$˜Ú ?éDX Ó¸È¾4¹·LÀÍB€ƒÓ™t¶rlõÚ¨0iÌ$³º>× • tbs€/ðÿí‘aZñˆ'×Q³ñ Ý›¤fÌŠÜ?Ä>*¿ #Ÿ-€Lâ ]+ÏXa2–Îõi瑨Em»éCÛNµ3Ä^h/2ê:p(/Ú ð?Ö5¾•µ=Gsÿ,³¸ÓQbÊh‹—ÏNê ‡',”bZ¸q†JÀXò ù¹UiœNÄ1B¥CÖFWU)§µ‹i¨‡ò^µ¬ã9›vg*eø‚%LÜ£T±CV×H³CÜJ!è”M“# æa­ˆÃµòIXt+ÓWªOˆµ X B:é4’€„˜MBýˆ+ŸNc­ë:JJ©Êh`–4+ñ ü]ÍÆ­ï­€ldôd‘Õ MLIé.iU`ÀÞzåžhŽœäÉpÑú4•U—åä¬ÞàÚ÷ìÏá÷q©Ê驚X0š´”S†G󅱘…2Í}NžÃãÃ×®]ûçŸvÜuî9<>üÏœOÖŒËáñáïúæ<¾Ï±s÷ÙïøÏöé[sȤ×E¯ßЇNÿ‰ÿ[þéö;fû ÄšòHú¯‘Ýì›Óá‚ýosÁÿ]6vþ£ ¨àŸýÿwüëaÿŽÿõÝþN}ù¼i9Êùï½öÛë OÔŽí [ù ܽÅ/,»èñ'L>vý÷Û/jÞì:|ߣöñÕD·3uôþ+Ÿ}ûícÚoŸŸ]>üí7÷ŠÆÆcÍ7VÍÍ[3uñ—×>ݶÕ`ÜÿwçIÇï»ë‰Ó.yõ´Ûמð³ûÄu÷ßÿà·-ºeÝ€Më×?8Ìôø™£N¿æw~Y¹|áùί?ÿ¼sÖ;Ÿ~:´á‡-×Ý}؈΃÷Û|ñÅÞvס—=ôЃ;¾:걫o¹ù£ò©Gÿ0Ï[±äýè¶·Þzë›W7ö‰uyw¦7n:ë…uÃ8#d·t˸!ï¾ûîµSníØ«âÑcÛG®œ½îä“/¬lr8.|èê?æ›/Û:xÐ^Enë³sû?¹AºýöÛ‹·o¿ø—¶=Z°m\öÓG}xÞ²õm ûŸÙgÜò¼üü§ê§µö‹–ŽaÃ*f¿lrÁßÎÝ2fþ·ßÆØpÔQû_jýìÈ>¯?w饗>½nóÅ—~töÖ-¯\{±Ñµð¼nØrÐ!ÏzÎÜû’#Û뾻yhMWç·4&÷ºCûò´¶œ½äñÉͦY·ÖnxñÅTßkz¨$ÚÒ2îÅs›U3 ê¾æ57U~·À8¸ÏYO<±JÈ=²ß¾ùOìW|sEæák× ?s{ͯFgÓÀôí÷äÔªƒÆm˜xÝño½tRÛù#^ë_º±åòçö© þÉœkÉ1»m•Ô¢&Þôñ-Snýø¤²ÇÖïèðö ßÙ ý2êNouÕ‘ß%ªÖþžébîÉ¥o¼ñƯ þuû™¯ðîkÕ+ï^w×-gî˜^XyãŠÄÑw]xÊ”Ûß\7õöô}¤þìšøéç/¿háÂ…]K/8¹áTïi«xåƒßvþçÓ¯¸ôáW™[ršo=º~q(sVWWWggçäÄY}¦œöҟݾá+yýœû^¼ç¥Í¯mùâ—ßvÛWåDîίv7-Ú¹sçW_}õÄO,¿ô óœ…Ç….¯»àÞƒæ\tàœ ¯~ìŸÛYvÆíÇ5,>íì _pé‘SO•®ZÛ¹ê©>õ矾ê¶gß™}Ùƒ9ñûûÕ/K,<'‘Hœ¹üòþµ§î×xqä´süñÇt:}ö%+ú×–:ó‚_ýõÓO?]¿~ýý÷ßÿÑG½ýöÛß|óÍ›o¾ùþûïöÙgþ+.îºù”E·õk8Ѳ‹y䑸u…¯ytæE÷ç·_¿÷Ìó?øü›ëŸ|óÇ_Ë™y^ßÅyón=lþÚc—^zÕÊ/¾ø"gΕ¼úïÿüñÇ…¾lN]ëêºyû÷?ο)tõºÿùãÁ×þýíO¿žvÿ›EM‹z衜ă9ɇw¿mŸw£!võŽ~ž·êé%«Ÿ .8?ºúí}–?ñÖÖG7~”¸áñš3oøøãûÏ{$sëÓÌZþÞ¶ãg¿øâ‹ÁÛßœsÁí+®»ñ¹çž»óõφÌ]¹äîçßôI]çùO¼¿ãpéÒ£š.û×óï i½øµ×^>¸aË7w½°yÆet,»rÕ+Û–>òþˆØ¹o~¼ý“ßßòÜÏZ~üÂÇ/XyËeë?zÆ£-K®õê”Ç'4Ÿ;eÜxŸéâ{¦=~ÐþcüMw¿ØòTKóôƒ÷:ó‘~âq}/þêâG~þàÆpËOOú`~û=×}ôÝÄSOªtþ…;º¾~­ç¹EwÝóÙw‰ÖìõÛ-­¹á΂ÛN¼ãùO:ö)¹ô?oºo¹á§?oªæŠÞòåþ¯ùÏÒÎÛyó¥·?ðç¤+\tðë'åÝùHdsù«¿•^ùTÝÀѯbaÀ%‹mßmJ•Æ®uÿÒ)'w艿^VõâŽÜ }ÆÉ¾µÆ~ÉS[Îë÷Ùeµ5¹[WoìƒÑ¹æ°þûìóMÙ·žòìQ[>;nùú‚;Z?o:xc“}ŸWǼµðñá,}oßA_¾gÿßl>âKæ;Ž}fb×çC/{*b¿Ì/¼×ôÄ1ûÎ^š¼ïâç^«ùü©‚ÅΛë›\ýÚ^³'v½ü¾`iìW¹@xhˆ»àõ¼Gž{ì÷?Î:é@Ûßø}Áp«óË1©Ço¹Iʽ(øüÖ_¶ßðJè•_?zaõÙ‡<ÿÈìS·&æTÔϼþôø¡±y/Ýxv|ÝwË×üžîÚ¹®ýúónùì€s>|ñú³ÚzQà¤Cš~ÑôñÜnº|ç€Ø#WÞ{Hûc>¼6zמÖ)Æ«y¼`DÕOßžwã·Žü1oô²’aO~ûÖöÆECb÷VRõä応×zꦎüw.¶Ìf2¼üÄ's×}ײ冱o¶®^{œûËÿº£sîú«_nØoõ–ïÆ$žzý³¹ë¦ÿ0(ôÜø£Î°µüë•_¾YrYãy<»Ð8î‚‹?^rßúã ûxeÚQ§Îl=ÉqÄwßoðÞ¢³¹°øžWg¾~ï3SÞ)výq–áÚ÷ù¹ø¹¾5—n}ùÂW–ÕM,½¨©ó§ÏqƒÚŸ+®­|ï‹îòy–_?ðó©ðƒožç;åÒ­Kí+›¯Éô+ÞpÎÉ#ëê&}cºèù¶Õ·.P¿¨~ˆçÿXó-_Þ›V¶ÎÛþmqqŸsNxãÈSk›oÛysÛË 1 ÷‡ø¹™ÜÛ6æ¾öc§ï“÷Ýî9ó§ew·|õÃ?¹gÜ·5Üÿí{žYt`g¿[ß:ãå>55…GsðÚðŒ âG·îçÈɯ:l}à臧.3©èåÛWteÁÖíû†KzÀýçÞÇŸ}`þ+ß–=³øÀµÖë~Ûëý‘oÞt™èþ8qJ\:j`ºò£¾«ÂÛÓýº.;ʰzhÃ;G;¿¥òôJÓùþƒó÷ï?°tÇÅ5=ÿ9hÖÕž¯œS/ßôò›ï}yĶͿ>1ï‚1mx.:Ä5£ÇÜóšÝ–MKM4ß¼ßù×–Û7ÿžDá,iß¼9‹ú\ÔxÞF?$µó€ußWüä¹cÇ™ï}ppåÏÏÜ3õ“Ö…Û=ù̧Þ9xÃ}–M³N¸gä/÷LºýÖ³ïxu…ûÓ·/:ŸÚ¾q>þð÷ÈS+F½qãæÖk;úl=`z‘¯:Ñwëa­‹cç„ö=ýºâ?ÖÚú¦0p¯·/z7õ@îi“G|´á‰…µOL;ϘüCŸeñ>_í¿åœߌÿ~ý}#·L2ôïCŸ>yê샿~¢ãêõ”ß~÷€E?׸z¿-‹Œ_¯ùóøNë!Åß\»â·'ÎÐòâ*Ïöx_ök'_rÔKO¯i[qi0çˆ#Žîwâ•oî]–{ƯF\fzøŒ@áa}ž¯-ÛxíoŒ{³à¥9;¾~à÷o¬qì+nóþ”j½wÔW…óúàˆ›¿¾wõYO”¾Ùpæ ÇTMoÜ$¼8©`ìÂSýþbÓ±Í>è€ÎMK14Œª¨o:}À…^6ÐѶ}ÔÖgbÃïK<9ôªèÔ%×Åo­\ÿÔþ›¿){íÞ²ïæ¼ö̹.Hüæþ²ÿq³ŠÇ}ÇšGoýòÈØ+¡¾/å_zXñ%g?¼ízï’mWŸëøùÛn?xÆûW /Ï]|pcòÎûÍû/½>ܿϗïU:Ê|Þ%åî]·~É©?ß`AÉôÿìõ_ïúßß—ÿ±Àîê–ÿÑ^øþ÷wüûkù÷7žWµjžFÿSt>Ðä/^¼`ÁЮbñ¹İmFbÀÔ΃ëö©=}¯ÚÅ{לy@Ý¢c¦:lF[ùôàlÑ'IRKKK<okk;ãŒ3@µïô3ÎX´hÑi§–Éd@§ FSõm˜D4ÈÆK@ÿ2sþä?ì QÞÙÖ™±ÏêÈk»~Å£o¼÷Ù× “Ú÷õ¿¼»mÇ-ϼ]{ÉÚ>Ò5ƒë3õbôTrh?J H÷‚[XÈuolÙ¸u{ÁÂ{ûú®;;’J¥@¯­.U¯ ã†1gÝ™¼Ñ3+ ªX]|*²Í«@sõ´¥k)Kûx\èŠK×¾ªd~<÷ñËϼã€Y²tM+ÖE–]»ðüËË< ÚÕÆ-_ÌŽÏÛ¶m[ÑÜËÊ/{±ë¶õg\:è57ÞÒ§éæÊ+^ü÷ß,¸ã¹ÎSOt2ÐÌvìØÚgäì nxïÓëžý 6q&¨že+YòÇ£Z¯¹yý&[èœAñë,zt²ºë^Ëñ_óëï;Ÿsè²…n0/]ÿú§ß]µáãÞßúÜ‘Á˘±tßôÚæ;Þz|óŽmßýò᎟.f«åœõgÞQñGH—¾ôÒKû7ÝpÀ´Å7n<Ä35g¸˜ãš™cwˆ}ôÌ™3ý~ÿ ‘Ósœ5'•Œ›5k–gb}ŽgNŽgöl)”Sùä˜ÓÆÍðíí™m˜ØrbUh¿RÿÀŠ™UÁ¶ñÁ6Û´Ø#G»ÆO÷‡ª|ñ¶®…³çf¬S£SfήœæËœºpþi‹bóGùÓ'ŒoÎq7:ÆÔîܹsñ-kùí÷w¿üqÅsŸ6ܼqß¶µÅ×óJ}Ÿœœ>OR Ègï¿tÿŽ#¤cO{lsjÎú²Dû©z†\û’ùõaç­šÿ䎑yKO¸?tβ‘w›|kÑkïÛ~õçwµlþhÕüWZ–M~zéƒ_~pÄÏOýüçeã§Í<©cà³ýýÑñ¬ùóOã+íûß5pƉ×üþì5|ùõ©D޹éÔGnÿâ£Û7=÷åãKw®º­ô?;_X}Å–?­ýÚF¤¿ZríšçWŸúãý?_ûýÑß×,Ùþsó¥;[GXÿæÃß…fÿ»éšS'Ÿrv¬éžÙïõêA¿tf¶ ë+;þ‚qSþ0̯ó¿6èÔo¶Œ>阕y.i‘gIpΩaÁó¥{ å®äˆ}Ž÷Lj8lA©ãð_~wd~þ~3ö›ßw–¯ì™\ç»gm¿øžÆ©s&ÿ¾ãùåë¯x±ß‘m[\°`àwG_Zšµ½aò‘ÒQg¿÷Á¼ùG~ë™Ñçñ¯8«laÁ¨Ç/÷<~ÀAÆÓç¼½´òë/¯˜<½l}l]É¿Š8.~仓6ÿñéƒi«\¿ÑúÂû+';WŠƒ'mÞé{aÉÆiû™ò¯xnÇÊ* ¯yVü´÷?üpmqÑ÷®[h¸ì’;ž;ø¸ ɽVuÌšõÃ/GLQ÷ÝŽW>}~ß¿oþ>¿Ï3«/*îzlkׇek;ÞûÎxàšwV]ýCÁã'Ÿ?â™3/¼{Ç­xØ 9-SÚ?]מ÷ÂÏ7IíkRïÑ·jÝÎY3«9ßuÃçe§ï_?àõÏSÃ. Núö¥’oóö©ÿàÎ5ûî--k[ðû‰WV}÷róÌg=É’7þ¶tj¹óŠqC.ªÍtó½uéA-7<>ý„ØõŽ ïÀÇ ŽxuÅ÷o¿>Ø÷l ïã©§ŸË]íûèöýÛ?_\¹©øóû7…_è·Ï)¼ªà½™×=²åöþ#¯¾óí禗-üðÁUÒÀöë~ýñÇ'4_ûîo;Ènpnýø¹[®íœûFè–ÞžóåW—/lÝoüõ¿úÕÔ‚ÂA“÷_×yüàˇŸõ¶oÓ[ßyý…C®hûLt–ìì{Ðè—Ÿˆo|íÙ ·}ê{ÁQ]~ßûôÇ‘gzÃñ--%Çê 6­>ñÀIÇÔÜѱì™äðtÇŸ¿Þÿž—žZµÂû G,{꓇L‹^š~â’;Žxâ¤þ¹gŸ÷‘¯Ä”{ß³æ‡?Z^YvC}ÅúýŒÛ¯q]6±ýž}ú¯(HN½{ûQ/KO}»hLßÜË­>¢¢nHÅ“W]uãá¯ãª¯«ýÏCߪs=MvÜóûå+¢ç¿î½eBnîU#ü«ùùöÇ>ºëšæð¦c‡¯žœ0¶šyBø×)‡.YÖ|ͤs=gùªßþnxoxè¬ç†ÜäÙá”¶5¶½ÿÒ‰ëŽt8÷tHݪ o<»¢b{ÓQ«7móO<à‡gŸxkUìþßþãΕs¯Š|»øÆùŸ?yVß±oþÞ~â÷ƒ¶wúÏþÞ>ñB×Ûñ–=žrßço¿Tôoß s£ç/ºè‰Õ¾ N¼i•{ÔìÇ^5ëÔ‰W¶æœjþäµÓú\:Å„îÿÇþéä1‘ˆµç‰Iÿ7hwñ?¶¢"ÿ Š EE.úÿ‹ Îäÿ¿ã_òÿÁøå3¤­4GMõ¸fÍšÖ)CÖ“½(Õã)Ÿ¾„)’g…Î)ûþxÒ±ÛO*ØpÒœcsæ4Í™³¨ß>9ãçõÙoÌ齂½ýC^þoû§ÛÿÁX"ÉkŽ¥þÞýïpvÛÿ…ÿèÿË¿öÿ¡ø_Üÿ_½ÿ>ˆûÿîþ·Üÿý›6mÚºu+Ђ 6¼þúë6› ´x(rô«WÝ”“EÒŒ.ä=oëzÁ¡¯…Ì5Ô83?Q90º÷õkî{¨ìâþÛû„b/œöÝíknØ÷Õuu³ç<¶âõƒV4}Ñw¥À¬Þpõðº÷9gùÖ9«þ}AÍô-¥Ÿ5²íÞõG|°tã?{ýˆ3Oïø#|“tÈþk;~íÌCÆFMëÞXüi Nîr³ÛºýO÷þ²+¬þ›I`w³ÿ]ö"æuÙÐŒö¿ÝVôÏþÿ;þÉù_õKOI`mEV»ÕÆ’ÀÚ ò à«Ãí(p;ŠtI`åÓØ»ò²‚_§=Õíd_÷j£¬šÙë5ÊõŒY'Cz(nÒ¤Mè–@TS^wÞP—‘Ά’,KK%íL5ãYÑ0;M*F…±•‚Ë*Lb‡Š1ïK¤£QMæ/~f‹_NnÅ{Åñx¢|—qö{žEÌ"Ø ÌÂpÁ¥?¼¡i‡ñ—¤8&ñ·R€-Ýw`ë&°…KÊI=øOv¤¾;KK­ÉTÈßÚ™ÇÏ÷t“–;K™´Rvš93¤™%sÌ>¥K£+DZ°Æ0/'¦Š6K‰P*©žNä™UùUb!Is– —5â…±Òq+MЄÈ›­ÚÛ¨éµU½ÁÝlÅ‹çLÆá ”‹ÔkàeMF g´m„ÑÌkš´G¬u‡¬évk~\Z{Æš,cÙK„ncÖü6×ð| ò²Pºm ÞžMa~66&¶˜*\Ø„Tˆð‘³¥4fwC-[å:ô©ðŠb>Dž¸vb6«¤Lœ#±ÀLJô4\;•§žã`æ#òÈÅh¸j©q˨œè’óÖå¤5bÔß¼ˆ…yÞ¤„ŒÙt× {ëŒF¹n-í Í\èܪz 1VW3nðJ ®Û$]}Jp ¬Þh©Tïí<•¥àå4‰T­x^÷Ö£œò”¬š¶y5=©‡:ue´EÀ F~Á½QþÐ ¤¨Q¦æóYBŽ< ¹º}G‹oÑ@ЭŒ¢Kà ÊñÄ&ËÞ´/K'eòk’”(V»¤d?cSURÚ%b ¤Èy̸x'·,goàÉTxz"¾i¡ef-¦ã}Ö²ä=J`n¡ò8ý޳гäU¬5A¾iZÀÛÖ“²X9HM¹"ßÓÜ+S•aªÉÒ²'|+´ÓÅ¿2 zÐeÁ^©ÑûÑò=k£KÇ¿•”<8ïÞþîj… `É^ÅTU²QN“+)Æõb]UÍGAbXˆòXEÓá°šþ›\÷¤5Œ‰PFU%3Õ÷I©v PA ´€ÆÉ²[){K¨ãT¥%ùçká[,êq~ÙB>ƒˆqa²a,á—4ÌYI‰ñ$tëÄu§õY-sbR½œw7 ªPÞ"Ø äÑâ#ƒ¶‰}° 4ÿÛjóÿßüënÿ $Ħÿî@»´ÿØlŽBgÚŠœ6‡ÓQˆößB4ÿcÿùþéì?|é™õÇaµ[ü  ’|›K(p¹ KÜŽõ‡§â¨€š$-@¿çÂ9X’»`H t‰Õä´yuI9g?Ï¿Ìj¶2Mg åÝe S›íD‡ÐÀÀmº¡EâyÛšCñ¤|ÕGÈ ¨¾˜ËÚlb ÑÍ!V¡<NG¢I}Öl.6‡ °«Ô),´Å= OXÉŠiǤ½˜ãV:âR"Äó‚Ð Ë)‡7Ô˜0Y³ˆ)…•Æ,UMÌ‹h.ñuÒí9,/¦ .k,ŠYØ—X¾¼áGM»·ÐRðcA„ˆ”jŽ(C %Õö`Óš„Õ&ñ±”™d_ °©©é'åeå+Q”éèR®dÞhº½Ý=¢$ôa6è’6U¾:JmB› E¡“1¡ ÕÊŒV[4"ÆjE¬#+CU©áý¨Ù€º÷\½4raœ¥¤“û6[ƒ¡0¬»É¨±Ÿé‡aÎæ½Ù¬—á†rÙNw±2ÄîR%å6,mK˜ûïTb”x’]Õš‚ßOL¦½)I:ù?­ˆ¥Î–ß2’ý’§ÅÔNÇë{„Q–왵LºlMšä[å°ƒS‰´?K(Ê‹ > aK›Ôè*½žš'ŇYv0×#ÏÄ©ëƒß™DTC!Öì6d°¶\Ò·Ä.˜j ‰Zê†mÒk“>³`;†fC]I”ÂA´õÁÊÈ"ìÌjˆqñ©ÉÈBÒ& qÝ,„êSÍ–ÐýVJáØ'²†¹è†}Ê7Ñ^§Oäå‹aªX%û^€–/Ž)¹pI­êÞ¨²ºJyÝfÆÓ/0k:Ÿk—¯ZÓ´4ž`¦@½­Þž¦TŸAR­vF%—6¨¿x•P¬=*B žÁ\€Þ@]c˜a3ö) ú›1·&» Šá¤DíNk–h*þ¾³ñ¶°„Œ5x»¯¬4;*¤8™•Ø«ÅR.˜:αvèqC®¿0ø¦ÂŠYgRfš8´  Q(òl˜§›º©Pæ*g/f»!ìÓ`¨ uºQ€ig •»gÏ5¸5ŸÚ-8ñB2q›v …€èìÂ:·à*`Z€¦…±¼¤Fkм!«$ôŒ©Z]¥ŸÎšâTØTÆ«±§àI”ÒŸæõrE(ÊS›±²¤ÓÁ`ÈÌ¿ÓX‘h *øµ{=º¹ S,qI¶†â˜ÇŸl7¬±¬‚šÄ>•m•CÔŠÈ×Ñ…ˆ¥+jÙ”ÙCõnC†u2£mJÄ…ݺ“^$Úíu=ÕjÔÛqz*Qm¬7jÄ’¾øtvžÇŠ^žl+Ì.û¢Ù “jîx¥qÍ^Ù]}}ŸrÖ@ê¹Û0å~4oÊiïyù^©áB1¯\¡"À2QóÈ¢=®BÃOÙ3Cn¸ìzœâ¡O™9A!1,¸Ø$¢˜ ´4Rò‹XBe?˜^]‹T,é& ™(Lk;²0<¤†€º¦IÞeé}»~H!íªD tÙ"Un‰„²ÕQwL5.“Hõö‚ >½ºÂ ǪËÂÉoRRë0HX•a¸Ù°RöÅÈY§Ù tŸr³»ýöd/mY„¯-t`ÕÌŸÒ½³ÞÍdÖ·ÉæH²fçí¶|¶¼lGë½J2òK˜Û®Í~¬ZΪÑÊ+Q¾Å8e¡åk¡]²¡¤‚¥›xJ2…U‡«Ü¬£qÕÁˆþT§` ÝB%ß¼¨P(Pž$®p™”¶ÊŽÚ¾]“¢ˆ«Šq‘]Bƒ²Žr,^*#Ò•’”Ÿ5|“yçyÂèçWƒ4£͘]–HÜMªì§ÏS‰c2i|{£æîBê !&_Ì„€CƒÂ^Zè‡\¯í¦ã{Ðj,Þs«¡™…]:Ómatë ˆ%!õö€¤F|e·3ÈŒM¯ô(®ª6µ ¬3ÒêÔ=•u“;56T….² Í{ù.jªr.J¯Þs“ÝX–e­±½ºJ¯ÕêÀ+RÈʑـ¶©’U–òhµÌuNtíºeî6jÌöƒ°ç\²ß}u®²ŸF6Æ€Qý’)bo·¬É,P^€,tÒ_±ˆ7…PûŠ^· SÆþë 寲¤IùTOÐOÛ¾·Û“<GõÈÊî­ †‘âÅtÁ6R$^ ÃÄ]d{ÍÕ\Ím‘¼1Sή¬ÈGx¤X¸Ó¬ŸKO¨ kJ;NW»‘‹LwzYê,·U7£”‘? K—I˜f9¢Õ; qÏ¢–&s©]óL(­Qì§ÊlK5÷d³-MEÏ HᔸG¬Bq*d¡Û5·ÁV5¬P_bl ””9©Ú YGà§0qQ6Þ)RZs<,=LÐÉìC*ýRØ~t—så×n&MÛ  îɬ£Yj¢’\[ÓT/8SK× FÙmˆ"ð¹,UÕ Æý±H–Õq—È£“ÓµèCˆìÊN¨1=³‘(±£ô‹aÙpQÀ»J¼†“ r\¥jÆe #†ãÅ6ü­ülhÔ—Œ{†çëÃóE »d—ʤB)R?Ô«‚H¤[ºòèbz¢„ôŽ‚>5Cä4ê´QSˆnd4Ë¡ƒUQGÐ*Un4ÓAÇìfjÈÄZÍv ù/P.]ëI©åkNˆkw ‹Ih×›ªÅT3Z&LÝ•=6$6K·º=]Z§™¤R_Vhù¤´:" WÍè?V¬Ä¶éWž£RÝÝŠj#›i™Èn/±žÉ£6H“e«]W7Àï¾ FÜÿB/:“Ý„4M¸»ƒƒRÒÔM1“q„o ‘È“fà dÊÊvY´¸j·ö<Ûˆ\V+ïV㸔X8*äVó”_@Ä»›vÊc1¼‹·Q™´ÕqSip2ËÖSóXŒ:˜SZï½ÿìxıÜüjDùƒ$º|Y…ì­A«;¿Õ‹,r„è¢CZZC½+]°ŒhÍÆ"#ß~Jy«|1ÕN'LæìÁê@uc ^i}Œßᣠ!ª‹¢ó{HíÊC¾ˆÌ<`Ô‘~‹l¦a–N PµQå"¿îPæÌ2ß+C`¿S±ø >É!Š&µˆÙÚéɮ勥R±ˆRQÓT®ö ³vÉËòqOÓ[ŒLäévI§=§/²)x¥<5jAãe[ ö.›M ‰üéD]=i»sq =ÔÉë°MçˆÒb\oõT»G™‡ÊØ ÛÆ O€Å%±`Ì`8„WI¨èçèðtâX˜¶ ;oÿlr…=*¶…šDP§­¸PÖ„†6å2±êš±•B‘U½PL³mXÃYJì®$í&0>›–1¼ö–Ÿ¨¡«â`“É‚ÛæÀ㔓 x F®'ˆáv±3)4…Ú€L´òÏ#.™¤Àä42€¡3ïÈQ(»f$Å 4»Vœ&ÊþÆ“6rˆþVcõªM¹‘! .#*^•MÒÌXåˆæÛ’ŽÄq¼iÕB‹+×÷²› e&åÇÅïά{ï¸& ¡‚"ï7 ¸MS‘íHv!¢fG†8lúðÞéI÷Þÿê†Í^Ù¤Žz W'Õñ°QÂb¾0¿¿ìƒµ7›’ŽÌ¬š¡-ï™±ÿ%a#kß«ä|èPý¼ºqË̹ª¡“[XJ¼o<™ŽS轎Zjfev-±ŒÅ›‚ÕAÊÊv§„7ý†’ò%Þte;¾àüÙ¬J6¨Qì«Ý™@Jp¶ƒzc³{Äçd>þ—X†² Ú‚#"Ÿ¹Öó ý³Ë±ôÃV‡‡Wz —ÁCþ·Uû¶Èaw8ÝŒ©’‘"Ü­œ ë]ëËÌŸš)ÏÊ!{• ÷f‘eƒ+v3¤—¡ÙµCKdz&Ÿ™B†2…Û{q°Ù'e¢:®öæì;“¶%XõÁÚf2pèѬ·_eAWoýªæù¨\K×|ÏTœâ˜ˆÅF‘;2JeüaIŒÊ>„WJòð Æt\sL§§åÎ2èÉbÙETò‘ˆÅRÙ a”¹]Œ3Ǭ.Fh^P7L‘Þ¦¸Rz ÈÞÕše«ŸºµÈŽ–ûŸ. û§gn·ê:¼á·Äk d Úv»t¿v‰"=¬p²úèPi²'@wd*~tºDä $-0îP’ãˆ`mb8ðHfV[,4…G­ŒìDßnž@æÞ§ØÍ*«°.{ŒBRíº{‹N ÐÚ¥Ëdz¾Æ1ü52S:J'¤u9˜ ݲ™tTé3˾ûºHÝm·`¡]”%¢œ·=-”r’›.ÖÕb¦YW[»Tœ?s· “›Ì<2 c8˜pÅEVŠó̺…ÚÚ=ìS”+˜B»¬gfQ¨e‰îÿ:#Ûc>æ,p3zŒÖ—çÐ.Э£xQ©#Õ £=¤‰Ê%ƒŸÙŠ5vÍÕä6‰:ò»äfÚA(åwÑž‹É5þ^†ý;yÎ’»úMòåë!Œ)Ò05¼TÛÒŠ×!S¯ÐÛèé<ˆjÉÎ>"/>.T†›üHŽ™ÕMSËÐ4e­ÚÊÄШrGSEv[#åmʆy÷µeõê£6ñÝE#÷Ó®¦ÚPDL´2J0uמ5(Äì[:º—³v¼¹i"©°F³œu³Œb%µ¡@žm2[ƒb@5“áX»6ªZ?„Îvf›vY¦N™éøŒÉ”³È!U×µ÷_Àaµ5xÕ½V·° nÍôhwPÛÔ¢Œº8@ ]päÚÿ(=9ŒKþP0äg68 .ÖzÔ fÑÁÁ:“¯×+zP§Ð=w€Ü«ê¦¬Èžh2Eþÿ¡)ÊÀÒk 9;Ÿ6‚³´pÔñuÊYZ`iù)uf(T¨/øR i÷Qäš?æ[ç…Ô—Hn‘§ÃÀŽåßšóÇYg9E­h˜høQS1ÃWž³ù‘’¦„èSŠåtLs~€¼‰¿'¦è¤"panÁâ&¥ÑóYã€C@qÛ$«?ÉØ7åÛ ŠòS’¿9ŠZ?Ë~•‡á6l°è¨ð¥›òBѼ$͉ï9s„nJ@j•CA’²½å¢êÐIÅùôq†òFæÎ(}ã“haù™0‚¿€Ò¥¾z˜V¤‡µ±¸§—‘iûQˆ õÔk?ÔKÏ}ôS„Îùnl´M7”ïòô„ÚLÄöÇHÈ–™TC{™¬i"¯?À*[I‹˜c)ÙKí Ñ*ËV(¿iÄðºéhP*†uVš²89MÙ.?µ0Õ”k°¼¯Ó…Ü^Ó‚¨Ūà+–ºS×ÔŒ^šÂ ¨½4¯úQv=íb„(^R>Õ$cVá+Ä…ñ&ݲ±U—WL¤ô[2Fµ¨?0MÉMŠ«ÊÞ“*U£šØ|åñž,},¼&c³Ÿh¬Á$ÕÇüŽ.È~´aάŠY¦k5vå“è12^ňˆªùåñ~¬hfQ_tª/:õÐW•%¸w—«IÙ¸Œ Y©•e¨WÃ+¢tÀ’Áìe,S^˜—Ü'ÉÌ,•Œ6RK\„ L‡f Ê”•¯qT‰;fKÉ–7гÌÚŒHjcÿÇír½»²´KN6-e¥ÉH =Ö•ƒ«§žóx„èp|n Sr_ø™›«UÔEÔÈGÁº™M •³¿`¨ƒ²ÉìÛ5™™#‘ñ¤ã,Ê€fô„ÇXUå4JȾRIqª+þE} ½§1ß®1խίcå Ec±ÛÍØöt@½ŒB†,g´Kr8ÓSf´h³!s"¥Ér, >­îmB#½‰§ŽÈLg÷áÝpþ.Wû.+N¯‰bøxå”CbJ±YᦠÁŸ-ÎdïYþO“ G—1‹»ÿ»”î©wôªGJÕœ–e{°{RG{š–âDáÔG$ÏI¥5ÎÊZ(9íÞè®'$ÑÕì>.­õ|šDVD2Ÿ¹Q0›’’Õ…§ ABʤÍþ¬¶ÖýÀ:Ïi@´A¨i Åhí"Êð>FTCÊ$ˆê™M%SµÅpán0Ûú  ;JdÅQö}”à ÙôñݪjµŒ,ÀjØQ™Àk|ŠÁGM.Ä-=½æéG&N9·ž’(KÏ…¸•èy¯9ùØr–µ‹I¶š|L»åZÛ—. ¥ÒiV"Ê=ËLR‰ÉvXQûDE(M)–4r1j¬LnD„‘Û"€ÅÒ˜€™ØÖ¡d>I‰²ÞIazO#Ò–ÔIh I]i1E³¯†u+ª_PÙ˜ÀS>¨ýß\B¹š„*G()i¤Ax`n6H6$‹JˆùAVú+ØÐ32ÈpÔ Ú„ˆœle[5ؤœ³‘T/Ì8„/†09S6ÁìÒ‰FòHþ›%ùv ™˜|¤ŽLVLÈÅå ÓŒÐÜ!‰ÉN æÒÜ.PÂ¥ˆË+¡Æ»1kX7šì¨q ¬z£]ÙAžÚ*½„XîzÞr0ã.£žåÈxMV]ù0¿öaÏ??‹®µOölÐ롤fâYnVÍT5Íu÷}ÊŸY^ÕÝÔWSáiV>+.v7 SÊþ×À¦´ø?oêÿ\YuõYñd˶d±X+»1C"\7q‘1”»å´Â›9bt”DG;¹u/I¤¤‡D|²¥‹{¶[³3îùfesï~¶„¯õ1áGx³EYÙ‡©_?"mgÙãQtPÁ„AQ•À²Ž†tCÌ^ö„rÖ^j1õ£ %̼­S˜§]sàšcL…d)îäÖD¾¶”8QM­EÙBï=ùa62Oœ¡ðé0–¹Vsú‚T3h”ÍÕ‚ÉFH"öÔ<8šbZ“Ú˜Oê¡ÛìÔlì™$ü‡H'1™  ¶Ä“U¢àM‡29·°öÿ3:v“pɉ¡Öê†LR÷ÐQ}'=jH==”6O°5ª)¥æS+ù¤p¬½ÇJ<ÍœQ‡÷¡N5÷t2HÓ~/'€Ôa«Ì¼‡S»=œö!¶léBjìânÐAwxEèvù)¬Ÿ›å<Þ£œQÀÓáQ"Iqñ̼Ђ‰Ó0:#ìxVa-´Kì {aã¾*TÉÑlD&Ùõ÷r“„âHsV¢ÃXŒêÉt+ýäàÓ{²‚jü,N‡µbNS3û›Õ<+¥¶¯©•Ý/ªö@=ê\Ÿ5©´OÍê&”¡çšRl³ëøä¬t”Mä®ú¦P4É<¿Ì–µk©†î¾€½9cÿúˆTß &ßóÁh¯d“3³´—ÜÙGùirI‰pdªx·Øoa-S•úûÓpNhgE/]É&ŸVgЖ›dWª ²ßHµ˜ÏP‘Àâ+Xœ¯P¢5ežâi7µèܬù&/²bi®F q§“’ÞVoe7ŠáìP­„æ)GŠÔYðœšyt»ã+뤟ÊÖ| Úel—’ú!#DE–øRÌÎÂÉ[„ïh©F{#QÑÝ€µ'IÍ…ì[즰 ‚pi,zˆZ5‡:h†D]Ô°U¹%üНµ—·¬ H«tÿ‰a»H¤Àd`ŽCŠ‰Ôžpj 4Žò÷!×Ä e$h€"?a r9m¸$ŸJöÖÓ˰䩧ka5’o‘'iQ°§<"÷ôòÔ”¾,C F¿’àÉO´ ÏòJ>Ñô؇ˆä¶Š{LèCžh¸cdǤ´Åt…ÅtâÂRâžgdÄ¥ñåäsb…,Ý@’¹Çl•É,˜I½<Âh…¥¹ÜÏŒqˆ®h±^ú$ÃÎá”é²q¢P±x,!7¾#†¬AØ÷*Q6HþUØ ·v9õq e|Êœ@˜1±Øu»1j~&ÌÕüe¾Z¯® eæw‚ šˆŠE×<‚ˆ‰÷µ"¿ÚëtF+_EèjàwÃZ¸ÄT¢÷É ç醉"»+{Ú,cî8_+?7žÁ¨š‘€}‹å<âzå"§ÕÝ1‘ëbý…ÅÞÒRSLžHß‹r;0zsëA¦Î!3MƒãVÉ ¹ËÄ6*¶òKB5ða¤{a­ºZõjØÕðÇLYîƒ>Á’Zak/1´+T,Zk“}›Áq ›h w®¹ÒÂb éþýä‰ïWðʆKgZ• “ÚL‰Ù*)Åli’aû½‹´+­A”°FÙ.©htSyÆ–ŒVŽB ö*DKó^°F¸N%;Ü^´‚”ŒˆûõŠ‘(^‘¡Ï|Hà4óÎÒd‰HÎKQµYP°93£ë­ü‹6ñÕ5>è:†÷8À—„çþdajƒ4dP 8«¥Rlj“ ÁIˆUJû"D—v€„䬼tx”DóJ¥ê¦G2Ø4æ»H4b„R‹¶0„0†¼‹£"ÜÅ6ÅÅéý`ÒýþŠ µ¿RFºì+ f3ÀY"O UÂ#aÌ!ОÊSæÉ¾v'3åBÀ¾è©&6踡IJßáùŠp1ý`£©çceâ¤çäŠ[:@œ¨î™'ÁiÔAކÈ:ÒÃè¹ûNv*dë ÀPEžÆ€. ù!­h½ÀIuÎ(ƧõpQT'ÅÅjŠ½ê’ JªÐ”K˲pבŽJÔJ§æÏË„’ù¦5/¸q2€ (AN>Àå(”l”85è Á¨ž±¸9•”§[¯ÊÝ¥˜ÿ&‚2àÄA®ìß<âЋE^ ×0_­…aK§âÚÅa'üÃ^^<üìÌj-T–I’MzÕP™­Æ_qÊÚ°£+;+ Ú³ò'ºÙ9 TÄíÊÎÎq¸Ð §Ý ØOYú¸@hTI¨«C#÷„=ñÊõ÷ü'zýºxÎU#‡];tdáÌi%𠉃Ðÿ3¹r2úR<{þôH$ò /T•üò%t'1\2g^BÁ¡ÊÑË §M™_ß\¶¬`ðì#ŽŽñ#Güu蘣—Ùß½ù–äA és“†¸<ü š+œ>gÚ¶+—5þhã=sÉ—ÿeµ&¤ÚnÊ6ú·ÃíF📕“mw¹œè>ºPÂø? â£Ò ½¹Š°ôÖ•ŠÃæÈQœvû„L»#Óy…â°çº'ä:ÝJE`¹G™^_£¤qk~ ÇQ¶bIˆ@¶OcD!.”ˆ”BÕDT#:Ò£%‘W¸šì ˆbµèiú=¢¬a½÷Jê©)„pÀ„‘§@``9á)é ë‘ ²1,ý`–ò¸ë…Ó•åµô„há©›3¢¼ù@&R®J™ÄÈ#$%iÕ4·|/äC7!û™3¯ÞÚ ‘+&Hc²2NßKƒî"†Tõù}Æ\çélrÑEc½šÇ먻Ø݆[h•ö°ß$®ù%C:1P¼òùÀû>!ô©ó±%QÚ«ÐaåqÏZYæoò¯ÂbѺ §†û´`­*Uí³6Y•š=\IC†4P'°ƒO# SW¶¨Î/š=QÂPhÀÞíw*fBS•çQ*ƒjù¤Ôqˆ¥O'µ¤#†Ú“o²Øp¯cû×Ç\9Áƒ=cn<¾Ô´D¬'ÃPÊò…µ m´j0­§V ð%àhÒ9$ê¹bL¨Ì™ò1(ý|+ÚºP2—}bs)<ƒ‚t„U˜‹[£Só©hB̼PÌMƒ ’]c‘#‹ÐjÔ¹¢Ã•µZþÁÅ ÿ´—ÄÿaaEE§ì‡ÿ˱ç8ÿsÚ99g–ÿ¸]gø¿Óq1þO^zÌN0'ÓáÈt Йëpç:²%0êܦ1s}$ÉKG7¶ Æq•žBÓ6Òt†Çç£xF¨ª¯Ó[ΓÒ1ª£z¤»N³ôê ÿQRiAÔ‹T¢ß\¨—w?õ%ÀVŬˆý‡¥/¡g~ØKÂÐä²’T9#²ä;Áí¢YÔ,Pñ†ƒÒF´°c)ôô†Èwˆ-P4¦ƒ×cöÒ8'ÄCú`ºoÅÆ³SIŒè¯sb~Ñ ÐÀOS|>S®.27éóEfE’š›,VöÞœ€_•^œF÷ZÜW•Õ¬$pï<Ö¾¤^ £'‚BRÚG1fžØÇ‹ÏÃÝqÂá ªK c÷v܆2™Í†M’k¸‰z'³SlQ&‘Z$Š™ær›¡¼pe>ÝV8ðš>+^U垨!Áƒx ’Ñ1×|qô3Ã, HX$PºLJeo§rRÁe†~7è-ãtGE‘Iy˜ ¼%4ÏÙG0©ËÚ@¨Ð` ¶¢R&[HcúkAº:<ô8ßR¼bR‚ç¤åõô¥É°tbßÙm‰jŒits=½?*õ¼T–{pz&,,$Ȉ½žò®ŒŽn±ÜÕÉŠ‰Qb8˰À˜”R»Mäùu29^lžš%NW…^@ÔkÊD¦G-œÁ⋵“uL¹õ´ð˜ª¼ã¹qOŠÜ°õúaÖŠõ»P´ÎÂÑ×'e¼¨D̶3Ü`¤B]ˆXNJÐoÚ¸tÔ¢qtW¹:rÈ!¿n¶GÓg²(€¦§1õˆ±ì=$£=”x[6f4Ùh9èâQ¢[ߨ$žÜ,u¸- §‘ñg ‚H†IDœ±@¥iÀô]y†Hf´ù%$¥)Ž JzR=Á²J!m4ÁP{qÌ%,,æ!l¤Ð¹XÔxp ,«ÅU6iVi…TáPÀ‘Û„ƒ?X‰Í OŒ­Ãøt“1ÁÔ, CÝö#M¸-˜ÓšL<ª·°3£éì‹Ãº&‰¸˜úZ2.1¦Wl,RЗÎ+¡éuB0Šô0ç´ß䋦ø>tîð^Uþ›¥¡b;,ŒŒ°ÂoLÂOlÔ„¯üú¯ÉÄ  ìÓ¨ ,†|°Sǣ̒ŽÍz˜µ9EÓP­a‚Ž›¬j´åÅЋ҉Š6ßÒÈoó¡ø<‘^Õãã\X@ÁÌÜ­ÎGDÀŸë™Ñ7õ÷DZÔÜÕˆ`5„IIvrÇ]ZÑaU´øÔ`ߟ´Âlj$tD‘cdJh6»±Ã}þ¢Àʆ'MfJF&32òÑò8i·É‰Yä`NA¤D E‹¥1ö|ßAw”•n…~¶85"1 ô€UBrñcvõÛTüÓ‘µ*6diK,üNÎÅïŠæ 2,NŒßÂg/‹†Á‹§B+Óý•qD´¯eA3˃ñ „5äu 2›M6LL³§Œü'¿D@Ì·rFE™—鳨”R C¦ ½÷‚rí'P«-.`û©TÔ©Å@´"u‚g÷ŒÎ?ã%Éê«}§Ôñ‹^ýùe;² þ_Y9®¬3òŸÓqÅðÿJC£’Áÿ«æðœoÐÇÃØÿ릴ƒ×'+ÙóìGþ´Ïw=spÍÔîçÖ~\šôõ³½‡÷Gм eTbä‘‘{¾Ø¹)ò|ã;AWïþwŸ2è­ŠqÇ|çGþ¼#r软Þßù·iï]—yý7×&jpu·múæxϧu¶Hy¾ǂ‘Ï?þì©Æc;6­vµ³8éßÝ>ù¢Äý[¿Y?/r{ÖqïàÈ—ÇÞõœy*tl[ã”¶VÔÉmÄ íÁwj´Ÿ“´¬øï‘kŽYÍ/Ö[/¿:rçsúùˆÜ]—ô雿YXñàóåÝMOº·N~gТûvN›¹ƺ„òÅ:½zéÇíŸ??áºMwU½¾ëœ”î’Ô©s”O[°qÙCi%õ7~3Ø¢¼øÀ”‡ÆÙ3®üKòmê?^á:’zö­/Oÿ—]+no¼mÝ‘I‡¦NMþ¯»¯OÙPÑݲKÝû¹kÃ3wí~êÙ'z.|üÑÅ®G»bë® o¬€5ø1â$ø¯ƒÔuÞ@Eu¨=EÈ ?øw;]þ9è€ÿ×ÿ¯ÓsÅ€ÿsá/yúbõUÿCÃ…EÓ‡¾—8$qxÎî­WýGBBâP€¶ o–-Û>hËÜÇO\¶fì냕·¶Þ»*²ô¹+{o‡ßüìȯ¿X{nÓ¦;¾ºïîžš‰¼¬&pÏ:>³näë÷½’9&òþCö»Šî¯Ú¾íƒ¡á×ÎÛµ¾iÙˆåO/,hD÷ê·'µn8ïàE¿O_™XºâΟ5]²{ìŽ1íK]w&¿ˈ¯ën{ï%»Çì³pÄÓUCš»}ÙwAù„•v5©ÌûL«ëøŠ—†½{ønó‹ù·ý¬iÏkÏüý,*XÐìIöô£¯¹—-øEÅŽí£f4-k*?÷·¿G"öáCVÚ½Ie¾`Õ·k— Êö¶î‹D¾]X¸³ªa¤}ç¡É0tÒ-«_uDÂG+n®¾ùð0•?IßV þkuÏ8£"èY•1Á^ïpŸ Ðü;бàßévÛ³²].'†çýÏi¹bÀ1ú;ŸÿÓ.|±-Ãÿà±É-¿¶NÛ÷¨KxoooOOO[gWò¢¦„EMcªš-¡ÍÉU›[;ºšššÖ¬YÓÐÐ …ÊÊÊ:ººSªšKšZSBÍíÝëÖ­«ªªêîîN mN¨j)inïîéíéí]×ÖÑÒѵ¦µcs{gCK{B¨ÍÒÔž¼hÝÕM-mmm]]]›7oNµ†Z»ºº{šÛ:›››;::¡×ºz®\ÓÒÖÙÒк®½»·7ÒÐÚUÕÜ–\ÕÒÚÙ“°h]{{{gggKKKrCÛë:®nîHYÓžPÕjihu„š5·'”5W5·^5Ê¿!¸]ÁÝÓr½ç¼Ö3dýÎüåã7Œ)¼ éÃÊ ©ãk~ù²}‘q«*ØbY?ùxýÜŽ£>çoîî8+R:ù1ßž¹-7\>ïoÞЙzìÃÑ×?ÙzâÞWGÞˆ|ººíòš W?‘õÄú·J7Þ§$ÙRg¬¿äà­o/’ײ`û×\nu´Ýž’ælLô}öü¶cGî?ñҼý‹*þôÅŠ¥ž?&U öÜìc//sÞ}g’ùÈ–e‡sî-ØûÄØ»¬íýãï|°y߆aÞøý‘¢ñöÑoœÕúÕ’Û÷,+¿¸jc^ï–óÆvïœøù'>ùä5ÜñÌ‘·V\~cáåÝ6í~¶x…+É–ôÕM«ï9tÕŠ'GoØ~ËØóÚþrkøÚÆ;6¬»xÖ¿·–äýgÅÔý7ýîíÑŸÿÙSAÅ–ßnþùVåO…wTmwµÞôðø¤ Kævf<õÀs{öΞûÙ¥ íŸÝT²÷¿J»ÎuÕ|~Wм+«åÁà 7¯?85{QÑ—Ç?Ýs`ê¢_,´ñmKÏ’Ç&^ø÷%GÞØ›7wúóuï¬ ,ØVº~ÏÑ{Z/ýèý#çœ;æì?·Ÿ¸~ÄÚÆò÷×Ô÷„ö=’rÎĵ3—¼ÔtüÄ­ÿÝv4ãŠÇ·¤¿zGÞ‰kƾûeæ+‰¥ëKnÛQa‚Ýþ“DÑ?èÅð?bý‚5e¶šÊšSßF¿ô_–áWVv¶Óƒ?Äÿ¹ö3øÿt\y“Ñ’cVú. fn0pg:œ™»â¸"×™›•£xƒš2Ø”k>™·xf±ž²ØGW"¨ejør]Ñ쌒â©JP]Q«†X&:âK-†Q òÒ„Š3Ù2ÿŸ½g[N$ÉnëÛ8ì· ¿f»QA7jÔ¡i1Ýr¨[m]vgVÐDÔ6TÑU…$F-ÿ…#ü ÿƒ#ü þñ³Ÿ|.™EUR÷®F³«RH‚¼œ¼<çdÖ¹Èï¾ÑuÝÀ° è<Äc¥„QLë†a]™èOD‡B1d1ö´ñ/áY¹ÿÇsçê÷¹T\Úÿ[ò߃<«÷¿D€ÏÝÿÆÌ÷ ÖŽeÛÖ»Âè[Ån)ïþ¦ôH ~¢giÿ»}«àsX°éøžÚ¸}ÿƒàWFûÿíêv±²U®ÿÇíêãý߃<°ÿÕæZÈÅ/CBÅ>VØ#@ŽƒÛ¢TªWŠõÒ³8)@¼wn¿^?óá¸Cß_Y; êõC€/sðýhÊÞõwRÑÌzý¥ë ì!êkäÒÝÓ¨)4™‹_C9Ñ9!Òè;-»¢Èο´¾Õ µ0k؃ܓEK¹V—¥±ú§Z¬.‘:S·_žárëÊ(´É.†E×àÄ×u}Kkìb”›TjuÑâ¦(È¢øµœÐ,ôàš×Ȇ(K-£Öep?Ц- ´r¢#‰Ì`lѸ‘ <}{ˆÑrØv‹½ cÏÍÙ©ç1ÎÃgÖ¢£¿x±›Êx–Ù—^~à/£<ß•î\oØÈvPSÄ7Z­ó´Ö6Œ!~Í ë&Œ°O~sp©ŽÒ%ûÏñ/÷R×u ÝôÁBõØë²¿(Gz¨stmÐÞ$H6H“œ„{?çïëm}Ã0vÖÛØ0Pc'8Cvod©ÊúFk£e„CXS\}4¡…YÃê¾4X,MÄ3|CލÝD×qþFM«8îë\Xi'RUÌ72a1î&BzÞ•Ž@Z JRëÅîªBÅ^FX΀´˜Ó]ÓKë°¾n./tú&ü¹˜Wa·réó÷éöFúþËo¨¯ù–~þ^´ O( ø¸ÒZ+­k¢°+ðƒÐÒª—0qwÀö¿jéw Ø ÐŸ9´u=€!¥Û-=ìÈí}Ð[iî~¸st6ŒísÁ‹•ð3â[ô¿Ewo¶‡8?v9Ö‹9Œ4ÿ¼ëíöPLf ð ]C,õ»•=nþËYóä´sv|°  Œô¯)‡6Ì0‡l¿=9ÖÕt좸ÐMtÐrézpOœìyØ™y6,´ˆØr—Ò‘¦Z韲S‘Àó±(=D²ögÃ!݇š¢;B©¬y ªfë–.xÚ£ un¾oŸ¿ßm#Šì¶[ÆÊuD6ÒzZ-|­^†â„{v` íZ mq)z ¾MM¸KET <×·¢b€Úšæ1ŒÎ`—V*GƒÉçÎ÷ ¿oç$ Çû Y 2œPØË…éÙ¤€î@—ýMZŒÁçqQ\°ÎRkÏÏ[̶õMàîR‹¼T}kb¢Él_jp„]ØÀ›Ë¨IžÕs‡Žý½Åú·Ÿ„H&âHˆÌ®M1°.eœ3i2o¢&´E…œÔ‰²Iß$T34@Û6ÀÖݹ;£áÛƒX 1Ï ’¾+rî1]¼Sw\'ô ÓŒh'ݼ¤ÂF>P%¢=yI‚Œl‰˜ùé‰Ò Fÿ´H!Æã@ø#w6FÿBÕÐÈù;™(ÏIFî=>ÀÂ…œ=ø„á?ð™û„»Ãì>ù0HøÇÆW˜šoå–ÖRË1òC{ ¼W¸pþ~çú¦Þò[Nð¹åldc(ŸŸïÏ[þM{CõE!hfÑ -lòA N-ebÔèÀêËdÏšÜË›VË¡oKh{þþúÖ~ÒŽLöqÑ ¹ ±éÍ5êt[îxÅ–låZçí¼¸ÛdK‚û-­à 'Àä[íöÀ·w-e”µBFxˆä¦ÛŒIøÇùZlG÷Ùùùû , l´÷ä &žhe—Óác²K4Ýç-l´•noÂGnX,ÆG¯CÛ6Ò[÷ ¼÷j½?Î\ H ŽñEîÛ K»XJÞÔñsá…(ð~B cŠõ)ÅÍᢙýæÉËãƒw§GoS©#ÏÚù‹B12°8'›¼ˆœ<¼s¿u˜XÙ…YöÏöG4Z]°)¿ÚAØ'•ÌgÕ€®›ðNmùе¸éÌ)?eO ê;¯‰:gAØÙœ†¡ƒ}=Ð…¦^_±˜$3›ßî½ywØÄ\=~A*tÔè[Wô>+ÕèÍ‚ŸÙMvòþW.Óý½üùÅ]ïÿKÅrýT+år±†Ÿ‹¥íZíñýïƒ<Ñû_@á¸:Pˆ tý«nñX”*õJ©¾µZHn}„Áé¬+ ¶]ŽI ø Ųá§ËpJD–QÀSÉïÈ¿¼%4€›» '½¹™äêÁHŸ $q‹mto›yÒ«Š’ Åóq€ø«Câqá0>R6zPŽ®ïŽgÆÿ†£/Ç…t=26»=‚þÜG9¦«æ8¯G â‚{ô‰Í0V)Bùúôô h=‡ ìŠõŸ²)N¬Œ„Īå!EreØ;ÚÝK}A¶àÎ’sêN[M_±íaŠ”â¦$ó¨D÷C=釯 ³šȰw]¥ž)*¦¨ `uÒÐqÕ2¥IIJ³Š¶0„.ê¡\’áTËIÝÇã ¾¯¤ð{>@-[©PñÙÞ}¼h!Fj;©WA&Öy}trªµåD4;&ZØ;|>ü&,‡Õ@›oŽN›½ýýcYÊ–Ê5½?¥XQþß99úæôw{ÇM(EQ”xyx€Éwûoš§¯ö,|Õ<‚"ÇßuNNÞ¾â–ÙSÑíÃXnV›{b ¶0ºÆåiІN謒àØêÅòZ¦íÈ"él”Éܤ·‰K%¤‹^aLðjðªÇHr\õÆ7˲KCÜ.nP[|}¦ê„á‚ñÆ]c\Öêr »"öܲĖÕ}•;ÚU®$hâüÀÈQ½˜w«Þh‘¾¦ÒQ=69ñh-$¥{—ý0ÀsàÖArA07-'½€tG tÔršÇÇGÇ!âÄdµzˉ€S@¤wMú&7O=2XvÂ"gzU Ê8æY‹Ž£ò ¼D›9÷ÒQ9,±2Ž{b!¦Hºf¨E¢ÜÎÌ«µßIE+#='Ή‚kllÃÛ˜smäúAˆLa+ KCÄêD#ÙðGr†Ä//Ö·M¥niêìP¯Óè"™BúÑ äÐÅ[ï°åM€‚út>¾kê¼K»/o>ÙðÅ’¡“¯'Æ®®ù4Þ‡ãøUÙYQOzt¦Ë<5R<ØÖÄ™oõéµÉ Ó©èL‹†\_U;o$Öãl‘^Ÿ:ÎyÿÓÅ‹GîŒ*J‚Nßôú’ØÂ>Éýu.¥èÝÍeOµ2 &ã°Ö”#G­‚ã_]"}öÁ@MXº——° ªÇSgè·ÖÕÅFê%¢@¡oÁi«.JE¹/¯‘@IíÛ>©§ÔÅÂl?šHþb d¶/4õ\~SMT’q, Q.–Ó8Á$˜„Ízùzïí«æáÑ+ZŽHFhI;x{rºwx¨OæþÇq²‚ÊœWdÊ àu¥^6ßž4“ÉoöÞžÂoóø$™ÅÑ£’àÏÞ½:ÞÛ_‚³p$3‚gM_]YœúùhQ³?46/¬aà»Ýy"«ÄÒÆîð8–„¯Ln?¾fð+–4Cßèž5´1ŽÎrÎÔôýK×ë/ç@›ØçphŽ+ÖŒîÅÇÆò!qý)sy˜¼b¤òýÐÒ`!}Åx!uýÀTæÊùP™rà?5×z|îëQòŸ¤_?J_îÿc«¶]|ôÿñObýáHü¦yÏÇ€»ìÿ«µ-ŠÿT­lU·¶«¨ÿU©=Úÿ>ÈCRkLmÄZ”oû¤7Ñs9ðä„mC}T5ñw"(Ï <»‹/ØSŒ>ÝqÒÊêËÈ£¶'ðu”?ëÆe8ª!JRÀf$¦j,µÎÆM'è nzßoÍEX®‰qLc-š±–R¨½ë)™íÿáõÏBùMy XäÐáeÄo°b§‘TÎÒ‡:T!6"rçuþIî'ŽI'‡@ÚÒX¦oç2ú¦z‹CËSšJ…â9kÝú,4‹eÍYâõ¥ZµXÙJÝNìË¢éÊýò/§ÿÛ•â#ýgÍúƒàX€ß€±:.|ùú×jxÿó¸þ?þóëù¬sþ¶q×ûŸÊ6úÿ­AZµVEÿÿå­JåÑÿ÷ƒfÉüê‚ØÁØZטá5½xúôé¢ÅL/tƒaN XØL¦ßb|êÁJyÛ¹NŒ‹J¤xgRœÖ9¾`îŽÝÞ_â`Ÿð#C¦HXÞ¨×ÅÓ⯱j­-ODF)Ûå.ë59ÖuÌ‹1š1%zQÔŸr™ÙXG@µž/š•ÂØušžššÈPcuönp™TÇu¬È0_º“ ZÁY½±ÉGöxG¡-9þ*ˆ¢ ü;d½.ßùmò”À?÷JXA'EÇBçÐÍIì¬õðg'9ÔgŒ)ƒ±k phëV-b¸V±AËÖóÊuÜÉüË_Ú®!L<ˆà©„½X&€ìºÁ(‚âjQÖtŠWã::ÂPþ«——ª)7y×·nÉÄö[½åtZ¨È)@ßw‚úÓ«ÕsÖŠ }ý®”˜I(Îèé\¬[ÛØd>F"BäÜÃ×Î6Ú·ñ9 ·$QyÚ…}ûB§Ó…©éXc¡÷-VtÀ²Ñõöì]ª°†ÎWðgeÑÖ:Ò%§"AÉ¢Oáw›ç|Õ`ß6‡²çíEª±ŸˆXÌÆŠàWvâP°'d׌¼©;­€ØM47…Îᇕ „Fpó3<Þ%ÿ­á×_ÔÆò_¥ZFùßúŸj ïÿªþæYÿ Cþýß_cü¯ïÿûÕ?¿_Íoƒ—žÅ„äÔžX¿ø›ÿùûøÕ“Êýò-F ãaôOûË»yùôwÓ×ßÁ™!õ¿øûW_ÿgåß!±ˆQÃ~øá‡ÿgï-à¢Úºþñ¨ b0`RC·ˆJˆ€(Ý)ÍÐ¥(ŠH‰% )#Ý HÒÝ0¨twƒüÏÌ‚â½÷}žç½ïûþwfÎÞûì\{µÏ^ë»7þr¸9­Xxmhÿžã!нôB×o騽ëÌ3'ÏSA³8­äMÕ‡X´žzµ{@çWéZ‰/§ËT®,rJ]Y[åûÜãÃÓásÊß%Þ­.é.͉gâÕÍZuެGN1ðK˜‰nÄÖ»N1 ެ§Š%Á¬hWN|™@VG{#®~=É{Üù%òÅÁúb8RtŽpê£æPÔëNz‡ãùÙvÇ?]­÷í'Í},Úón‘–æñ$ÿê¤LÝ h1N½m¶Š¤¿KßÉ•ùÎ}2NiåjõtZÁô)Ç+1s8žù_O:Lg/mèÕìÖëdä ¿æØ|¯y¨yÐ¥¢àî\ÄÒ­nOŸa…éÕ+eV KÕŒ„Qw>½¿Å%Ì,%e‡·ÿÓÙœOO{˜yßi2zB4¬8ü§ =Ù0 ‘–ž~:ú «û¬ï#äuïÛE$E^›ÎŸ8<•¯ºANq'çžÐt€Ë»’‘ìçß.’¿V½>Zý¡µ àeÍ üvH H€^-ÒÛ}Nka1.fIøª^­ÅiFŽÕ8ƒÉZï¼»Î8s4U¡ÃœW>lO?6|WGZ*5̞儇û‡öƒ *µcúmÔÐ!uéi¢õc¨ÿp?ܹ«§z¾VcVfºÃjÌIílÙy)!toT¾ß21: ^æ4ꮰݰ-5=_Ïœ æpÊè/[›W(õ’…]¿?«ÄåM0g šdó„̸½Ïo<¿"rb"âåȵ¯Õ‚¢ó+ótOàÊ_™V`Í! ÖïW¯Ôz{»XûÎÝwz›sIZZªÇ[êÝËèÙ9—ÀÅ7}tÖª¿ôBCqŒÄìáõ)ò·”¥t yâsF)Csüø°Š‘œa‰†°·÷ìî-\»woX}åå÷¨{ÃAÃ= `Ò†Ù\õÕ³­ú5ª ÄlM+5ãNq}a{!º³qµG?“ùÆ}¨@ªÙìe,õÈGÂ9DÄbm[Ëtó2±=zë‰Y*˜·YÖ‰w?;~é-ßL?=RÛÚþAâK*6×ìóy1Ñö/ Kfý Ifëú‰ÏJZvÁª{ÛùdŠ‘‘‡>2¨eIýp}~²¸UŸ>”4Eäµd· Ý -Ò“Ë5UÝš1Ŷ•Ði0pÅÛo¼íÐËÎú#ÝÈYùäøÜòªµ™¥!"µ/Ê羋_¦¼dÇ}hØ Æö 9OôÉ—]® ߯Ïö ö“ÀùbŸ¼®‹ e‡Do›ÒˆÙþjÒi©Dí/ ‹õQL69&~ Ng¦ÆÅ&\f}1ÈP²º[å$Å„yñ#/Ï/gî¥ìž»ZW\-e~ê´4Óðù¯Ê¥k$xÏ­9 ^ø.²Æeù<=¨-t¿f.¹ÑŠÛA OèJwDwž·^ËÔų5VCòµ$rSF×#”cÔ;Ü̽BØ$´M®™ddBò@‰8°ÿÒÕÃ]ét6ì&jË1“—ÚÈ¥\çJÇ}2©|ª¼k6+Ë´äå7ºo4žÊlŒ’ËT†OÂŽIøÝ (Èè¾(Õòæj] ÇcõŽ’"%Â{^è¾À¼‰ËÁžºž©ÎG¡¼A]‰ ¦Š¢1ÕOvö)—±Ñ Ý[J×I~dGBÖª:ü‘‡æj“w®ä7ðcŵòvÒ1–¦¬m‡Ëfe”Þ­dkêŽê¿Åd¥£t马2öº\ý•1êXTùiÙ ˜‹;£•B[ÛxÞq“S½Î"f÷ >rOöt:Ø*'„ÿ)yÙac kÓ·+¡¶Þü‡?%ij³ÈmèÜ¥dùHy¦ûhsAÿšû‘Çjé³õEÅÖ7H('IC´VŽ<ÈÖ Î8'’÷Qïjp²Š?Å=‘âSÔ{f~×;§?®ÍèP4]8{Âqá¶Xü£ä{…9}7/HÓÄâÜ4À¡$v¡áT±"FBhù–I{[|Á9T¯ŸwáQÀJ è×/ånÍf!j¾£±ùåµÖWÒ+Ö‰MX^¨¼ W×’s‘'~w+ûÉ⻎:k•¢N?Æ+n¬ÏCÏS¨2Í\aÎ,± ¼‹ÌÛÊ>é5_m±leôò…]_ÿ%©/O%XF«‚„ ‡j®+nðà5‡’…”µFöÏ(ËR]ŠP»;0u§ñZÖÜZ¢ž¤€Ê&˜‰÷ä~•{ö)h»°.]¤÷(ŠzD§+¯šüž,ee5\ç=‰xiG¿:êbºÿ|qÖ\§¶(úܰI½þã¶EæT4ßU»Ä‹¿3‰)%œŠ‘!FJ˜¨Z|?—3õwõÑâL"-ž_ÁR’ª]ÏjºçxQç³³1‰ ®õù•Û_+ÍbŸ †µª–‡X»+sÂørF>!?0úžÓù³hCòȨ¼ÏõYwÞÀ«ƒ~”7“†û¯ä0YãHýòÐÔ|ª9\B;ûÙDoH—¡)‚ë¿]w éÚ¼q¡ä³Ë¸šP"?õºš*¢BÝ(½wuLªuÎ+ÓÇ ™Nê§Úû ®jÛeÙ„r—¤^¡˜høÆ¤s€åBË\ÀWN麙}’'²cÈܯ̓ów©úd%éQZs‘ÍW©bëz°JaR;Ç`ÅEÛè¼]ê=—gF=§)“<íZ"‚ç¤S·ã§|låËüÙ Ê$SÉÜÞbµ÷Ö«XÙîdb‡ÞâVêW²Ëõ5}@Ñýh|"8Šc¢ÉÅγÀ?BiEøœìø`çX9íõ×nu œð†f–µÝè €ž¦š»y©(f8s:Y '|¹›œ+cÊûË¡9ÄË©‡!܃ØãKÃöýÓƒq¢ú·.å;NK¾{QMÐù&<ê¶´NK†³O7WãŠ}kàó˜çÌ£¥†M9mh5b¹æj•õ5ë/K±¼ÁAŒ©tgÙÍê:;„••—ƒÊ¹Ènp*‚E v2Èñ7FÊ×Rî««*?_Õê+zîä×O|È+²ä>aϹׄ¹ƒ ¹àá>?x.éØc!K=¹ZmeR[ÄÜÑyÖ5ÿ°™¡†¸è»¼å1µð¬ Ò:Ÿuè› Bó x±9ôÏ^ð®â»*ÁgoS)ùºQLSÜÖHO7÷~õב!Ô4¥¼ÐçùwNgèŠ(3ÝÖqQMbxJSüƧé±a{†ÖmÉ×þÃSÆJ¸Õ…ŒH`–ÏoWÆ(—dVá eÅAH~E­ÁíZѼ?Û(ŽˆkF€ `ý[Ř>û’¬ÛF/ÑÑh&s$‰Ú=¡¼•„ _ÛÑ„Rm̹ ªa½þÙÅXÝv“פÅxMžfÀ»„£áu^$&° “ ¸}Ñë»ÝwõÞÐ¥½o¼M’IêÝy¼ÙR—$/…½95£+ÈøV«yàépz™óÇ… 5¯Ô\#8Crú¨¥D2‰üKÍÍ€{§ L \Dœ]4’ KûÊ ¤›­úºÒ<ËgÜ > ÖÞPdªöÔÓv!KåY¢»Ô³¶Øäøª-(û’øC÷ÏfOóp¿'õzY$¶g`ý>§°nAä*^Ò:ïçk–™ÌM3s>0û]›Þ3û»X£®. .)i»ûÓrW ¯c „Ü‹_¿¹+×d"Ûuóð“63ÑáÒ3”lùSH¨ 1ÉsóÂÜn‰4s¥tõÜm_¿´…æÉùÌŸïű5/_¡>6¨ãtr¼ïaò©r•;qýˆ*i²„l/5óZ¶òó4ËK yÅÕê'ÕHϾ]W{ ›póÌ'-ðfæÉ 礤u˜ã·”Èž$„X«!ß@I'ªß¼¸|΋GqÖ”‹òÌ>j3›“/ ì#m|[_ÃX'æ}m¾MóḚ̈\‘¼ñ”æéõOן–O[ÆðËQÄ=I§ÆrîW }Ι`+Õžy˜˜ú[ð1š‰ D_ñèJ!nÙ±˜.®ã4—ºÄ)£Ëœýœ(Î…%5÷]¬x@ •¿Çfœ!ÛÈÔ•Oö?V‹êþîmÒ^ËeîÅ=rʰ0Á¢I bÿ¨¸?ÛȤ'¿Âz´ôUgÒ¾·¬ ÖqnÎe^Øôó7ÈS8ÌÖ›LfxïJ«æØ™ån¨Æñ%­ðQe•Wq¾ç©ê(žmŽU$©I¶qÎféM®§áeNR[^³Ô*¸ºªš°L‘Un¬`ë8õÝë 2>Ç™å6»ÞX ´÷ËÛÅý- œ•ßîLßP)éy÷^ðÑÛû$“¨Q ¬ÐUl£&úÆ––Y|]/èÀ¥¸õãëöãß_•{â-0IߢvšÖ†C[¾Ï0 Šùo´` ›dÔ¥×ðØ:"í«ŽöÊD®MqŠ$KûD9úÕb°± aípó´S'.ÞP?^éT™@þÝ™aY'a"—»EΖhY îå Ó“T~mVÑÌJ&ãËmÒ¬§Ýqřݨz¸Uq¶1Tº­væx?ÑõkÁ –N¸c´<ëCOùLsˆÿX4WSΙ·´w+ÃÙðÓDúe¸Þ]e4éI,Àâuþ©©Q]ò¡zQÄ«.O©ˆû®5ÅÛ/‹]zš(›Í—ë{wÆBë›B„õŽÂ…âÚ¡Ov C8§¬žu„ŠwâS“‹.XØ·hð{[ʘ~ìó+zNS޽Ò÷ö3~]h¡R’Ø9ü3í÷9§è’r'—ÆJí®0ç!Y|ÔQW[Â4?êæ֔!§ÿ>%H¾û®\©®Rz¬“öFEñ…|ßžV™àBŽùøæ](®&SÒ†\QûÖ}+h‰*k95EÍD#›ÕÑ8D2C—ïýŒ¢2òt¥ž¢˜ÿÞº×/±N&_𩇾­-zy`^ ­ríÕ­"j‚KrFÀÉWãí±2ìæì˜t=¤–ƒ.ª•0øXiaºß޹>qä¨rA˜ßç:œÁ¨ð‰Á’Ë ‘%çGioºX¹w´ÎG¾ršRïó¸wŠÁ¤õO0àPjO&{ä –èØƒŠò$ gàá:Ÿm圣€ T|8nÑÿ¤ˆ}@ \S‡D~d"èXê¹”ŽEã·Ã/Þ ßÐi9EŽ»ÒöÉ™l_¨ kI¦’®ÑKÃkâwÃŒXZr¡a­‡gÌsi:¾¦¤w‡fÒ_ÈO xt$ùBÅ1§47ÃkÑõù'¼k œ2Æ"æTyÅÊD_{äMšçôuÅ›dßíÒÉhRÕÎÑLŽÿ€ ¹ýeÙþè~;^ê'Âêükמ~¶pÆLË*øÐ’ëpÐ}ˆ¸¤ôÅÓù&ªï«ó™`P˜oÜ—ú@òcµ¾i{E¥©î¢[u—1W¼<þÃé7zŽ·™:4ùÖãÛïÒ.yö2?ðâ§{œõø€ýÕ|Ù¾ú!µ³<ŒÅE~‡éÈ^×WkõœŠ¿ou-òV»òÉ›ðèš›žMét*—/¯¯ $OˆÝéwYÄ'¶]¯S5£…)“.ÉØ…†K-]ï*è8tÕCÜ9Â+T"gúZ±d!aa¶‹ë›¡ÄÈùÝDd}õ.Dò¹Äñ(¬Q†¬º2šÅ/Ũ¥ÆD´”¼¾pS‘$|²Ê#xwàöÛøK¼Ê§à&ǯø5Ó¾vØz̲AO]×6¼V—,Áj"›[ƒù^Ðè9àæ­XsøNªU–L«*ß`?åGK"}êàkç ÙG¼‹®Ó·d¦¶xk¾ïÛ¹ó²>7U/²|ôÆz-©*`TÑÞU0/9.ÀL¸ÚÃ,¯.`~’Ä?à¹m±Ê­+…O|[ÕtÆæ½l¯à_Œ-îv†Aüsbè97…B¡ïPî¶Qò‘²âO¬ &?YhÌÝU\³z+ŸZ7Ïzè}EÇ!'òEâ2*&+D,¥€éÙr¼ÈWÜbçé.?–Œ‹u¿}!ã2öRÉEÉœWîaß¡ë¬Éþ«”‘(9÷ïßYýß¶ÿûq&ö¯×ñ'û?6´ÿG”Ö'+Zÿ‡•åû¯¿%ì±ÿÃE}Ðç?œNâ_€íãü$ǘc‚Ûο١wÀm¸áw{ñxG‘úUxï>+Ùrà% D7^ŸÇ÷h³èipj€äâ¡Á)«£¡qûØ‚°@Žiì^=Á§ž¨žü³Âÿ•ð/œÿ2ZZÿ—Ÿÿr±ü¬ÿÇŽR ügýÿ áwç¿x¨D¸ûþ¯ÀoÎr1L¡õÀ¾Cûy­z/´€Ùt·Žhs» Oø:A7°Ö•óŽÌ—ï ›>AVyù„bÕ ú5•}kË §Ú÷Hï¯ã>AÞ47&k”Çeä‹Ï¯)?^³-Ä"¾Ü¿5Â0¸À0ÃjÓºYmÙ[4W:ÿ» Û¢Û‘ükŸ)µ9Tw:óFÝU*óÍûjÍÍ£8'¨Ý½£ssŸ?,·µ¡s¸ö½ccVhFÚûÎÉ•îåÑD v÷ˇóðÙâò&j 4ÖR-ÛGr¹y^©œB’Ÿ+ꀕG™"Ïu¼(461ƒKþ¬R©jÁ¡¤ÔùÖ¶÷›ð‚üƒ‰×އûžL0õ5í_>P¡fk2äül0(—¯Œã¾àçÙ “7,à”3 å¹7ªU5fjîä0Ï—çÊ©ŒŽjêÚæg‹¨GèK"÷ ~`³D6fkój?"¢³±]â’¶jiÌ­yÙm/ø¡’f|XÅ,2p騕2"Ç$ÖvÕɾáAÀái÷¼t¨Èd{Ùù6ÕZW)7dúÐA®ûC ƒeíÝxlCÝžº¶"O(ÆËskrÙ4¥E)ò_ȽÄÅ¥ mËþtˆÔ·XÐÔí³ wŽŸ|ŒÐ¼Ll­w·÷±öêÃ*͆’ÍÆ/éPJÏCëE<)“ÎJÈÍÇ­¦°øþXã÷wÑš„Ñ…Ò)k¿ÅúLËÍ··ÄŒsŽXäµ Š—žó¬§Y4]c•§´ÿ… i[ÑaCÒ§³ à¼7nE#ÕƒTßP…õ+*}E Í-ã®Í³êá<°–‡Pñ.w®!Ìî«\¸g ƒ³á3*wC¸ñ+õô©âŠõâ*‰ß.#ìæÆcÙÎ6ç+Ë}*¡!QÓR˜?\O,ˆ{õÖ]Å9ÛúW©¥bSGYè6V–S£ÒÚl)ŽÊàØ¥`V ÷쬪¡mŠ#Çö«×Γ8¦ÒIç’{ÐÉõ`\;]·_óó΃ê-6Äxx‡D Ò¬²e^Ä|«¤½³âxBUò3Ö%ë‚;3¾>_%ÇGÛF½Äj) K9§©Ä±bW¾È¿•¹b/*E8õx—?ÿ|$qMlxºÖÿM|¬Mcl¦Ã Á#Ø~9Oúu&°FȇúÈSru®ÕøÔg©©”÷ç= ¡»¸ª&ÑÖÀ(XÐ6⽺m#N–§(­¢7¯ãNr”v\ Ë­Ë4ÇdvÞ{}…#‹4ÞÔñÿÌ,ÙŽ³ÇØñ¬ÔO-åå ¡J*îKiI¶ùà j#ŒW>š œ2æ¹õ ÷€™zãgJÏó„…2ÕFûÅD©Ûô½©Aê·7Æk³ÙÝOÐ==Hø]™Ÿì9^®åÝ´”mèL~ïþr‚ÃUűg)iÃÝDÊ’?­Tð•lemÆM]ì|^&èJ~˜ü4ç¼óQWc˰¹¯ŒÂ’75妯¹É°ï<Š8†@â. M*ž£.I Z5ËWòZlYÔˆÞÏÏõ^ܘ2ÿº2MNg×Å$‰œ÷yúH\öÕñ£ÞþÒŠHl8Ch• ­h‹ã5MàD–XsåfI·=‹„¶Áô²½¶^;ÇE’\gm¤r"Cš#Sè–Þf?•‡xé¿OôÁ|œÍË`|˜#_¥žOŠ·ãI/ߘë?hiøäiCÌÓÂCÔ#·äο󴿜_'À20¡çÕëå½=àï?À‡•`§|½¾‘hê íÊ£„%õ0¿.’äþkúŒFÑU–‰zk¼„ö;IÑå'ë E]{¾6¢Ñë˜N€Ãèìöá0C®O_ÈØ„ÙïB –W癉#H“b8‡ßÙ0F-Jœø¨_þâã|oÁ­³Òœ.n&ý'ß9 ’Ò­w6!_¾ô€³¥‹Ë+¥»zŸ¬FؔɺyS´âVÿ¶e4Ñ4£‹ðBZŠ&–‹žkÁeÎ~y©“¹Jl}qÝÞØ÷Š™è힪wú)¾˜‹]–zÿüÀ§Lei#=iºAåLuÕ"eâŽ, ÚÔ ;¤ †Cª¼â³»ó¨–ãž@<žz¾K³ýíà«ê-5Î^E~·ÈKSšx1¹ =*X¼ ͵~¸¶>󕌱÷ ç² d²òb±È!-8Ç|¹º“íCø…‹‰Rs]ŒyeóÃEL¿Ī#–>]¼ïi¦Š†N<÷ªíXl¿P-aSűü6Šd½`·R‰•bŸ7 Lr6 IR×8íøÖZ(žJp 7(#•}1>–øzÒƒï}û—ÏÏ.³0e¢µv%ñ¬¤µç‹¨GN>ü}zÊ»­zý%ݲ#뛜ë¯Ï(ô&ÑØ4Ëñiµ’Ëö½¥´i ¯x{Úæù«ÚêùÂçï9.Q´5÷uŠÎ¶Ï÷…]ˆI%}F)wªrÙþ’¨Ë;·Æ'8ÏVía“Ðæ‡%ãrOW¶]I½\Šsg¦ÑyÔ†ú½&ÙåË2ý‚#Á‘z4ô<Þ†WÆNÕÄ”© [ÈL–÷õ=H9zÆztõìÃ(Oø¾;uø¾7ï!C¹dßÑ>ÒªÃR»Õ7¶ µ¢ÐUšlÜpR¼ñÌÙ÷Ì9fÃðЩ‹n†1$Cï†ÞЕrˆP–åZ„ž¯QßÝÔ&7”c)-ñôë‘NãË>¾ë³<>ÜNn¦X¹‡íß•eö/Ësr,§‚é¥%Í)xï7Ç«*rt´dJ¢sâwõò|7ua_¢”FmèáÄxéi‹ù™)½úŠÔ!qwÕãM!2Ë©‚䩪z²túêìŽ5—i¼ûi¤n#îR®óôþHñ©‡ƒõÃÓMÖrd¾Df'âĘh\Ï© ûö:ßLmÁrø„Kª|ÉC“Ç„^ØLÃD—4wjñ†Š¬$#LÕë;¹]¾Rg¶Àñ/D+_Ä甿>„´ÓÖ÷¿~<Ç•'æí¢tWž$×Äðîø[õ=ñžcœ¹Ô¹Ûîbj)IA/dçŒÔßÕ Sò×Ië´Á'D&¿”³ôX‚°{‰àÁd¬w®ùWwë_,á \(e?ï(áBH.z,éÁ ²ÞõoLþ³•c"‰9Öõ›7)<9­>tîêyGJÞ_9óÅ6laèÒ*ÓÁeQÔƒÐkðváËý®X(íßßóü™üœú÷vÿ[òÿoí¿ØÙÙ¸Pößl,¬,윬 üÏÂÉÁñüÿw„=ä(øáAŸÿÆa¿N¢Î9åÌô¬l5-uË:fZºë(µiY]M{‹r]~ÀP›Ý8Ñ«¦ÎÞÆ¯£¹È§(À¡p®Èíœn=:ªì!ã•ìö:)àC1 òÜ"<K7þ±0zïŸVÕÝ7Xå̯¬gTv9f÷HÁ‚W×Ö¼ËñI)vŠœ˜™œ^ÀÖ f÷ù Üz \v.ªlš˜9k 褈¼¬ò,ê}WÜ(úèø%]´ KýÔ\ÛÕgá—À?¶¤¡½ŸÒ0 (=+ÿ6sÌ!_îÁ;@ùƒÜËL#º©ýÛYLabûEÏ2@Ô º_VÛ¶_Æ£²íËáÞ×ïEߨ€%´¤~®ƒ=ȬïñˆDÖ+䳑°ù2ëÿåÈ-➀}q˜—ZKÒôééå¯Çûl TÏ$%§œ8'u5~qäEϵ†dÍŒ’ùÛsCך߳Ïêy©çµ êÖŒ˜ýxí‚õ‚œƒ¡•.X¹îÆçðr^B EZ-Ô+¦ê%'sJ~.Lù$d¾0Ö®{$cDˆ0u,Õ97äWSXþñ`¬ËàáúF½Ë÷ciVƒC÷©ð~‡¯l`á‹k:3FK;¥c{)ì¡ÔÕ|¬Yã'„pÏ ™Ïè=(I®N!Òäi±TÂ]uµž¥ùÂÙ÷HŽÏj>1áé÷w±ÉÇdàÀ]CíKKûåÝ+ ŸH}tt€h¶žã¾°÷º^ Ñ—Øý¶#š¡Í"Æ<¡OÞc¿Ëç6 w‹p8u›PˆÑ˜‚ÜWÑ¥ª_Î+ §p¬˜Ú¡WÝüp˜{FÃä„{ú@'¯;{ðˆ+/ÿóìËÖ N…–w¨iÍK½íØ«*æXBrñ#zƒ>):0ra© 'RÍ€©‡÷ti†ã[„þ×;‡›’ƒ^˜]d¾vÕ;w¡H(mcóäÒµ2žPQƒWýÃP®+Af#|o}<ÇÁˆÞ¸qp“'’X‘ñGNÞ602KFˆ³®»=Îà|{¢£ÃÉKˆ\ØØÍšÈ=øN›ü¦;Ÿ¦¯~òAóh!+slk;ˆ}Z‡Œ¨¨(^K+½äñà÷ð£øMPR)÷XD”CˆXÝSFk¢ÀF ’ûìSèq.XÒÆû\gc0‘*¢»½q–OùÖñ1Cé·/–¼øt-+½Eän®A¯«v›rž)Q yÆy f‚¼_Ü1;ø²Ö*Ÿ¯Mq‘8»â.çQâÕ(ÓìûðPßÔYEW(¬*ŒhÄ$c_{ãsk]HãïóêéTÄ;–œCÐTˆßø•˜û4ypέÓÁP™2&ó+Gc{…6°ÏܾÀl¹ØŽrùâÆŠ˜‘–œml¨Ò;¶ï¶¤ùl¤FüØxñ­ä8s‘³)äý_ø—Ò(Ïœ5\À";•FÆÆúÀöuÕœb-‘~_Û bd¯Ê(>…òº' ~C`†:ºZš–Û‰hŽ…J•EýØN¶Ñµ„aj¹}EVîºô |4”®„“Éå0}³FÈ6-ããóA®ït|¡£ƒAÁû¬ 2@m#M}Þ¦c^08<Œ,¬Œ¬;j¥æd‚²Pã›[šÝÕÕF9i§Æ”B‚÷‰ÉÄ eeãààád…rSÿ¯†ûíúÿO?m†?ÅbáÚ­ÿåâàúÇÿÏßöÆâú7ðŸ4 ô%Ô÷€Jÿ7™W§vÙ­fÜÿ°y7í¿‘HD”Fá¿¥¥¥¦¦cîå奭­åææ†@ `0Xpppzzº¸¸¸££#WRR.--]\\¬AÀáþ0¸¿#î_š÷‚ÃdýÄeee[JÓýa²éÁn^FÂnJPdKi°£’¿‘ð ²ÅK[˜ŒŒ¬5ØR³89Y ®A¤#[j`ÂÄ‹àõààdKÍ$²eqppqrpccq¬iéO •xM°&Û÷,M†QÂÄpYº(q*/b ÝHxYSêe”n$Þå•®-Ü’\ã‹&‹';œ®ÍƒD¤—ºi×ø;Ö;• QnÚFõ³]\fS½r{CCR–Oe30WlJ¦MºÚVÆt­½Œý£`î’¥¼Ž'I‘˜3=NÊ™.êô±Ê.–Û)…Níø-m³‚ˆOF”/‘Nö½ -“©fõAÌL\Öù<š‘ãL³2>Wix/š--y}l·£¢Ô×V}ñâr¼j/# W —Ø…ø öÞ–»ÇSšä¹Ò ]ÔB#Ålïs]O2y¨±¾Á¤¤ð~,EBÒ˜˜æ)ÕFñ'ÊEåµ±qý8ÛyoØwò—)÷i"s_^»2Ìlb?ÑM9Ƀ?3cëïÀg›žž™Ÿž*ko߬`éÊshXrŸÖuÂÛòCÄ]¬#f>»rÞ‘bÍÉßD»ÞÛ¿}@Iez¯,àµìÕ ‚µØTW=†DŠ÷GÔuCxlYkn ¦„¶<ãx-ÜwCzaÑ»ÏÐaIÞCG„8M%seØxÂià•7æ‹ßMãœ#™X­­Ìh½ãE?øZšýÏÕ+>‡x‘2ò¶5ÐY–A#“¡èÓfϯÙ’a O¨©£Äæ`ª„x´Ô˜©~ Ó©¶(fÿ"ânOØ!~)Í_.=—°nÜáàíj-& ¬ˆRlE’ˆ6…ЉÐ4ÑØ·~bö[ŽRØX Ĺ¹–˜¼BP=ÿž½¸›/+)×(O-¬]Íáƒa·ÈEÒþ”‰Öºæ£¯Ú‹ä]rU6šµ²›²Ÿ¨e¸W—¿ºÒpVžºX–’oÐÚU«ù½²àû"À/ïðm¼wp¹;qkñM榆ñ·ô“õ’38ç ÓÛ}fjœ˜(±¼Íí²~z”kÃ*}8ìÞÒ¨¼&üŠ1\ãµB–÷BÝÍÈi›„ÅÀN—vy¦ ‘~Êž€QÏ+áuô\Z»ý²%¾¯­«¯uW®9wòÁ ÒZN¿¯p"3¸Û4Ö™ä²ð"ªÀÅlÙ,zc¡{±ßA;ŠŽI›Ë1¯öQžÓ Mƒý`·­ËÊ„úz¸‚Üá'Ö‹’iÆtQþŒã'àk*éɆýõ–e¯WZd¯êÆËºôeP&b†ž•+Ï¥Ÿ¸¡ {Ć€{¥³åÎÂÙÌl­C?OÌ=N×½xlxIñMùË7¶¾aÝ@tö’®°à#iXÍåèk¦| ×"?gÀs§L}% áŠ*ì™"¢û;f,Œ¡¸Eueܼûµµ™ÏÚä± ~ù˜j!ÂÝa£ªì(ʧzSQ¿:‰áÄ7á‰SQSÚ÷…Ýàõã„ßåw%Å+kqûì!O–MíMxývøë+v‚V‚ÊëøùÓÔÚ½Í$ÏÒŽããçBÖÏ}Z<‹&j >@y0¿PzQóÕóè’w%t‚>W¨=äžµ…-òj2Ý/|Qœ¸ñe5ØÁ¹oè}ÙŠÝtÉû^ó¾†ÏÈHiÁÉ´¤/ßN;ÞX8ã4“þÇý𙵾¾N‹Þú¸a|SCbw 6Ü_éõDíSà2³ŠRY&ª¨e­98§”8#îúùÊc–¦Pʶ[éñŠYnÉ&S^ë=Ý{çã•xè·NúTù:··ß>Wò5Øh´0 a¹po¿¿]89=»&äš·™×é2…“ý§{%»ç½é÷özôJÌ/+AӵüwÒÁ:ñCTiugY-t»èMþ„›sÿAD­#†ròYv—ÏÉû|‹ObûŽƒµ¦ÛóæQžÂ:üÐÇ/®~…fù–CÌÝÅìæŒh®†: (ôLº†ë;„:NxKÐÜ@$#_+°±p¯7Š8û’;!&ãz½Îš¯y$†}§`&"$¤°Ÿï[Tã˜+ Ç-ÊQ?öêƒéÄÒŘÂé‘Sßñ˜¾Û÷”Ë=ìqy³ÎLÈï¼ÂWÜCž@韤 *ò”ñ9/Ôy;à\Qr÷g[™ƒdÖK^øfÉuÔ¦/%¾.Á6â†ge×3OÙzúáª[é©y x™“ü_ÉŽ•6¼~¨2r²÷@ÑÜã7Û?ŠBX \‰`Gè}dÄböŦÈ-†\ó]£ö[q{£ÁQ*½Q§éÁé«£jÀ‰ºùûY¤I¼¨‘lj“%_K/ä\;Ö™ìG‹sãÅ5?“<õÞû½_–å㎇61É›|aNÆz»•4†;òþ¹|U—–†òˆ¤d•UM•Ê«‘×_„+qH)F.Ë2bEGçΨV#ªMÆ+ûáµÒj¼©º Ågg {)áùZ{õ©S=ÙÇÃ:™W‘4œäúb§C™ÃÆ”m!“3fd+—Jè“ÔΜrððëu|ì[¨ùøÆTÙÙ¹µƒÌ!keîËÄÄZ<¥6®=”z/ù\ÔÕ‡˜úu¶¡Õ·Î–Ž×ßòÞ]:å´möÑ/ßïÅêáEBòþÏ®ùrÎ1¸7±Ž¼oÃ++œ]coz+|LØíN<­ëÑ ÅÜÔÆÐ2""r'có¥ºÞõ3ŸeòmÆ–¿y°Þ]ÿ9T°­³ÀLã-åB1àèøÖ×¥­§ÖåÙ3îkžìûÝE¾ˆÎÀáŒK›òHf4QNPÉÐË1 oO_ÕÔîF˜Ø¥Åe!ô¯ú%Nµ·¬ )œãÊ™Ë}­æËœTôqÕÆóÁàS†¬c¶ö¡€«!ª¸³35¥·5záé-ù¬r›F–»+G†J*çð#–Šjƒ¸´*±¸£']Äòî¨Y¡gXÊl;szFùÍ𯭣®. >_˜—ç>hXW¢ùê‚…W¯K0¾?Ž[Ñ1è930³Uß<€Ü’•¿² ®S˜y+zÓŸ¢±¦©¾5ê\Er´ðeI9eš­HUFÁ­ßhG‰ÛÌú·Ù両: „BcleIÇ¿é#Óe}]+u˜®ª«´4VfúúÆà0hÚ ”>i¶fnŽ˜OÝÀÊÄXÅiiøÑ>š,u¨ÁŽYZi[[AP÷QC ,uõ¨i˜ÀñÑÕ6RGèïQÛŽj˜h¨!¨é F+0Û1b b¤¡ÃøæD»‡DŸzm{†D†Ž¢¥Cw \Wu·ÏݵtõPŠE[.2wø·ÂPdó™B+®i£)‡>°b€È¡Oµ tu­`¨Cm&:T½˜Õѧó‚ÜœZZT$¦[Ù0ñ?çCÇÒ`zÎÌÚÊ,”¢?•¨´È-Å›W ¨‘…Ü”–¼.Q¡fdf¾Ã&ÂÌ,zK¢€VÒ€2±€Í³4Ô¶bf¾rC…Ì´éaåÏÜ– íaü–,³ª (êÆÍŸŒ0ô]L:V:*Ô‚*¦ho§[m`Bµ]µ‰±)L`¯BQx«˜²ÀZQDæÚ&X0 ¼“whQ1Û”ø»ÊÁiØ+ž\Aj&íæÔ_‚ ºb®n¥©ÛŒi‡â3Ù Ô:´ŒÑDFK:BVG)¹Q3@¨1îR©éÀ5ðWrýA‰˜#}TnjÙRó3cùkûwé5C÷ûL ØöGÉwM+GݯCŠêöRCˆ¡j–ÑÄN õ6C8‡2Þ&Ü]K•òƒì*¯‰Yï*Ôà¡–:j\ÀéG &ÖŠ–æš™‰. &E%ÆÁ,µÑô– fWå^YAÀϬ)¸éŸ÷Ïøj"ÛJ(F•¬­œV€D·5LcÚ]ÓM³M4 ÌDÐСç=íпÚ* Éü¶]¨ÙÕ0L~L£öhÒfq`£h0- ØjÊ/ôJCÓ*eS@WÇÈô›ó Î-ê,¥š ¾+-ݶÓ^t i ‚íü4†:˜ˆMmšM'¾Û¢ýVôS®¿XÕݘÍÚPCo‡œvw÷è NNÍ„ŸªÚk"hvÎõÖ¾‡ZíPújÙ*jWa»ó`Jpþ¹œß5jwI?åÚYÖîuýc¦÷ “¢}þ¡þ¦ˆ²73éÑÊr›bÐLa§ sá„ ”ç¬@qhÇ3ñ7” ¥ƒ©r§zXïÎ{Aþ©óûvï(¥<·Õæ­¦m>~©CoÔZ– Ó¶´6ÑùõVú#žCD??X1Eƒ«œuÇÒÂÔ©©µƒ¤Ñ¤ ö,ÙJÒê^c¾gw)»Áßö€ÜÛXYö3î”…~Ék klþ“|êŠ)?##( R9dËØ„‘qÉß^ÿ ÒÓÕÕÙã1´Yj+ðs[ýÕ33CI]{14L†¡íII?Z˜¬(Âüú²Ég›¼þ9£¥´¿LÏèÜ;}ý' &[îýhfF/ÒìúGâæYÛØ fm©ûë€÷þ0(|lºå“ãw{”í9Œ¶ç9+]MzêXÐ{(ô…5B? ²;d¨{Qr-ºFA %Ó¡6#h5RFkSsk-‘èê ·&¨‡˜;»¡¶‘=&;æ÷v&ꟸºQ{Žëv‹v<éi·út |èoVˆNŸî¨+æÍ8SC´ÈˆÙÄ€»XCÓ]Ù7@Güžñ8ï6GÁ4$Æ­ÂÑ{1’é[‡®1LwÇs“E{²¢É¿iðn‘aÛN™u§úö5êž‚"õ–$†ÊŒ²FQßj3¸¹£FÍ'æ!n zÑvP¼¶‡PiZ[I¸]BYcPoË›)˜¼~g ŽÁ¦x†® hÐw¡3a¬EÔQ×[c¢ÒIÑÕ³ÁL4AaŽŽŽÓÔAß…ÙónÖºÉLQ†(–¿‰™7´~¥:ú=¸¿Û2õÛÁönÜJB?ÃÁ!Ú2 D§So5ÿÇ|l‰Mè Aæo‰z³°=ò ›ÿ,þ`:ù“„³gQèHÈ®;vвÚfÖ¦V›Ùö–vÊJ[‚ÓÏRÞV5¿‘ê †¦(å[ºBìïVÑnšük,lSõFfS[}‹ŸíÚÍþí$ôÍ;~¢õßÑ-ÍtKóWév³ª? ÝÍ(Žc‚±NúSúýõÃn&„.dƒ4pÒÎaó¶ú eÛ‹‡ïh8P([*°?êW¯ÜR¦± QÝ=KM}T.tó¶*güq¯6ŠÇnòQ¶ßoYe¡`v”‚ù±µ"¶ê0C}S°w–ºeï…ön̈~’cvſȅ(*üvß±þ$®oUˆÏ=2 Ÿÿ»Hýäøßš†1ƒðÓªû-ÏØZÍ?-¶w¡¤NZÌè¢f¨kæÐr1êÁ€Qñß̶5 ›Eïâ#¨h6‚)‚‰Ó~KÔK@Ì`9ÿ¯6Åû rþû1ü3ügÖŸíÿ¸ ÿøÿú[Âîóßí³_(ëƒàž†[¿1ÐAþUã›í#è½ý¦³ýb+µå½U£Áfƒ Ll˜ã^4 ·°÷‡; d0†-†VšÆ†h{=Ì ‘ßWŠ9yÞ6Ò636Ö4‡é¢ó Uˆ6Z¢0·Dô«!ί ›\»àÀ˽Ì^0f9?›mõÑÊ1`?là‡üp€ν<Ý3±rlÝò«íÖVi¬¿5ëÚ´¶Ù•´Ù½ŸêÝ£ÿ¿`üÈвܴ:Ú1ƒ,Lœ»,˜þИróðf³nÛ›ÿÖ‚îìNÜ ô£EÒV¿˜c2@ö°°ée7j¼e fef¾‹z [†Û&Ÿ»¡=6Íÿö÷øMá`Y›ïPþ¢0†CËæjÚ`WQ[Æÿ´”¶h»¦šõÊαޛ¶ì™0»‚ßLÛ/+~‹¶wÎmÚÖB¹7§€iû¸u·š Ó&[Ùn¦1?`\¶U0ò±ã6/Øe`ɦɆ*dËä } Þ¤kiifÉ€–äQÆvàf”¡0Ñ¿)ÊRWgGI諟'ËTÓÆPsbŽÙÄ`€ÌЧó´³–58[ÒÀ殆6ØÃ Ûü^£c³Ý÷]FÚ?-ŸT}v1–]¤Í»{D.yE _í"ÿza›Ã%‰:ÆBœBnn¢wïä?©¡!yvuxW¬[úD¿T¸“ ý4Fj„ùƒ8P UÓR÷×ÁÜdUšúú–ºàă´Ã„zË3³¶ÔÖý !a,Ö!?=cþÿ­õÿnø­ü¿AáߪãÏô?Ù ?ûÿwÿàü-aûO ðc…·üÏ}[üø… ¾~ ‹åû[ðÊeh§P<ÞZNxŸ…@T¦á^䟛۾ØBK{§ ‡2?ÕõÛµö7ŒeL¹§£äL©U„\În¥Ã ™Ñ¸I^£ñáí?™ò6ÌÿÎ '‘èO§u.ÛsÑRs_Žþs¹ŒÉn;‹èÙþ~ƒ›zRc8¯Ih>?°|Ì@[õíð´Aoï¸D Ê]ðÿ2mêÿ{á/èþ[Ø_¨ðgëŸ µÿß…ÿÅÂñÏþÿï |?+~þþA!¬l¼¬\¼lÐjŸ›`"Û0[»AÀ¤ MA!± ÌÖÐÊ”?Q[!´°úoâéé¢_˜Â”QI(e Ý1›:‚»#Q-߃QŠÁ‡ýÐÞSÖ46VŤmA#íüãÍÉc“ýï!ûíúÿO8~Ø ˜õÿþ88wû€r±qþãÿño ÿYÿcnF4õÏ,¿oíšÈëkèê×÷Køë¼€%Ï?õ9ŕؤw>‰/J«ëºõ$^Ô)òJ@encp÷=pëàð °Ê,ÒG'¦il¢üÒªEå*~gtžJœ"²[ǼI+©èy‘\Äc8}D];ûÇy™Å5R{pÙEíEFd~c5r°ý{“(ú`ßd3{õ´¨÷ÛÔüÙGÅs+ëÉ•]‡,sò*ZÝò8lL|ãÌ£?µ"ûJ¾Ëkß?uôW´~TýËì…ïD*€AzËðmZ5褗÷šÉïU§ïòøWR;ž‘%-€’Ôþ«gé9ã€K åǵ_˜y…ŸÑ|ÁnÞ5<õ $íY8baiÐK¤ž®oljI€qæ·ñYÄV@ÑëMB> æ#ô bäš÷0Ïžœž?¤ø„J'ÐÄÝîÅvÅK+« +€~4pÍ5³}p*¥±4½Ã@ Žòù úPò>ì€L“qõ#í0”×…-oØJ¾‡ ÞܶýcSTfa‰yÍÓß7`aYZÌß›G~™ærŒ Í*ªyS\ùÑó8©¼°å[Zëx~×$ ŸÜr6 ÎÅ•÷´(˜zUÞòé›IrpõÉÚÚºsNyLQµ5¼UþeÑ>i÷¬$‹Sâôò*©Ê³¹å5˜÷Ûö¡Ék>“2ën†Õ—|™zù.åEBÀlÁííøiª¶o ©{P ÀUp·*¤rÊ(iìŠ/©¿ø ÐÚ?°Ë¬òSߤOÍ,w"¤<“•wµµ]$ú¯:Æ—Ï<+è,Áž~ÿXÚ\RÝQƒ(%6MŽÌ)׉iÒ‹oݯäcÓh–ØÎlèÍh]7‚'ÿ¸ñ «w0*®,0«viuý5¢áË䜺_’î«L79|v‘€Y8zLfÆöÿø@‡-ÿYÿþö*zdeùJ¨ÓA"#{öˆð3(ñIâÈ Ù#>Ð×Ó}»©I}-;zŸŠ>é9éîþ®j¦Á®¯œ¶9Ù!Æ5äù‡¹bø>±†Gí¯˜LÌ“vé©EÖzÎ-7丵击-ݹàû=’WùÄy¢uïù=8?,áãdä<˜Å~Gß6b‚š§¡{ÚÒKpÈí¦ ŸÓLlñ†dípUì)œ K·¹¦Ån^JVŸ“æ9E¶ ýt˜Ÿ‰à¼Qg"Ó·ö;—‚HÏØ}ùb©iPhî5Þ›©•á”$õÀÓ^+_WÓ®¥UNÚw8EêU¬d§Ï{ºyë=#š ¥ªÍrjîìÒþ3£ÔÖWÜE©±bæ4u4¡‡mœÏ…»}y™`BÿËÏùšKÐ=QføÙ“b1¼®nßÒÔÝ”è¢5>~8íwÏ ŠòþDÉqÜÿ½ë€jbÛÚøD°" hA:I DŠ(pED¥X•„"U"ElØ#< X –(¢AÔÅ+AEpmc¹ j,H¬DEáͤO è»>ÿ÷þë°kÖäœ=§î³Ï™oûJþÜkÙï\]@éª{v|ô¾ÿÜÂg§ñÝO:'Ï–üXü2aÉ ÚBƒ¼0žçýÕ³÷  ›‹ŒÓËǦç¶ÎO6ì»É]«©¢áö ý›É·ô¬ŒöÄNÉ0Q ·|Ùž¼éòð“|íNVzQƒý?º£ì, ,†ëÙF_¿òþØ«YÛH¡“fPÞºæëÞl±8vS\æ k4ÁءߋÃïê2Þn¡aùán)ã¹AùCÛŽß¹f•ØV….¬h8©®{¥ußÀÂË“¯«Îlšàiñ¬ô”ú;ý˜ÃÜu&7¸¡§^¦=™u|Á¸¡ îÅI£7ù—¶qÈ>Ÿ:\µûÏÇ^ØÈ5»|2½yvíVÓ–ß0yÙ–C<½n{bÎéwWîh]Ö®g¹zo‰§½jWëDwüZÊÝ+Mo:ìVœòóæåÕ`Û—cšûèuÿ¶A3ïVÃ`Ȧ_òÂl/n}Òˆ½ÓdÀ(b!½s; ´ϨyÃŽ?¼Ì.oT~v³Î’»»[ã/0Wî8úì×¹ûçì ™ž`f05ÒzÖÊ…GBÔMõNnXË?á8Is’#ã}{Ñ­[QûçìvnÔ:äÆŸy“½·ö»6»þ4&ªÜÈýøŸ÷{ìÀŠ9i³œCÅ5,Úöç<ÎêK×ð*.»ùðÐݪƒs›OVQûç9÷½x?ÛîVU€¶vKåñk“‹5瘟š}åV¸Uü—]ñC4ç²Ó‚œ™L™[}¸~Ð ];5BÓ,½™ßÞŒ!Û蔜R«/º@×3Î1€ÐöÖí!§ãc䆛MÏöº¯¼î¿àÓé;?Œ7[R1—Uön÷5µÜ>cüµëÑ4B,ÕÎÌìQÒaÇÐ] •DW]5“@{ö±Ž|›ƒ¦äwuÅŸ—/¼°©Ùºèys`C·ÅãÎÎ “)#Ô Ô––Vì›a˜ŸYIÿOzæÿý.îß½ïÿ±(¹øHGçŸç?äRÿÁñ›â?Àˆz…d½ÂχÍùDÂNènˆ!‰?9 âp áô¹ Ý(ß\b¸¿&"R"„Ž‚v̂㒽Г³7î[¹(JIm¿‚··`b91$D¸ú 4«*j+ÏG*û%W>BÔÿró?".•KŽI :|¿1&<ãS¹ÿ‡.øùÊ ñc¾_T_óù¯ºÿ¥·õ¸7ýAËŸÿB«ÁOýÿ#.Ñù¯\g[ /If¹#à HQÛAAˆøÔ¸”•Ÿ {ŒC³ Ö)Zx(Œ á¾ü=©Š¨&Àxþ;ÏYÿ[/Õóÿû€èÿí$àÿp5ø#À:ýäÿø!—òøh±ñ‡v@ÆÆœþH—¯„öÇDÊžöŽR2nû6gqE`ÍsÄÑ<…Ñ¦Š£/Ø"H¸’‰˜)€f&Û'ˆ‚-¼% ØGJÑ[ß‚ƒ”p ý»8H…(ÃDÊB…X<¤IªPé;N9BV)Ͻt akÔ™²Ð3¼ê°ŽÎ.ò\X¾Þº‘1Ä8‰˜¢ ‡Çãe¯Ê†ƒÕ ëA¬o&‡îE¡…íJÞC àà]pøÇãb‰k¦ÊN‚øHpÈ2¸ç eèñ!¬K\%ÊÃEã”b°¤­…F£¹¤ ú=Pñ+f“1  n°=§ûzx¬-†sc#‘Hs79ôš’.sŽ(3+„2Ôk| G”í*¤4Ã7@ìÄ­—"‰” iOô_4±`"{ РºüàËTÜPgbQ…Š”ƒIŠà#aRe}òðy˜ºT þ!ePøV{'Åw+CËÊ—GFøWI”ëkc@É¿:Öˆt§kF"â’ñÑáD„zB\Ë>z1©Dà:»Èëqt)N£Y-3J!;aÆ+â5ñ1$’8Î…’I$*žŒ)%¦Sì|±,pI”Þ+U肾Q±8ØKéM`«8„®À®—sù =0!b_Ø#e…U–NÉ‚#l•~# ¡sT«UÑ¢Bˆ![‡tW¡„º¥•ƒ;€¨h:)^È¢&‚bßà â;#.CDñ¸T1m2–ƒëMj’@¡ ÇŠèl ‘ÚãÉi1`B¸®“:»lUXP[„BE? 4ÿ{pqpQjpH"ÈHØ/”º‹ˆõ0ؼê]•1 j¯P yT¼ß»7†’Ò é‚ç,,À´S¿Æqãk,£BC}7ß [·$kZ$4 i¸è$7Êm%…û 8µ"#‰É`î¸tÁ+pR({.Y ,7$*>T\"9j-Áñ@b˜:J‚šÜ'A-E$q€Œ4{¡$pÀC%”*H”™B Kðú°»py ½ÔõÄVîIõš¦híKµ‹…é .5%ÑM0ZÀ&N†ÈÀ›H\j\Š(‘°¹£Ý—yˆÞ,re€ –‹J¤¬?eì<¹I¢_TÖHìò…˜J\&g*@•ȵîk!õ’Í4ÉT”ÎÞˆˆ™á(³]Á*ßÇ ìá>8 î@Šžh‚"« '‹p,»~‰Ì>´¢‰€Þ÷½^—°ÚPˆw_§‘åŠ%i%Ÿ{ îaò¦­DnR ^à^®Â©=;.ÌJ„y;Áö*$â"àÊ\Ån%'MqFÊÙfªÂ·I$Ó¾}(©Po³]ÒªÛ¾ÜHKÐK[‹ZæÚºWŸ ž=}þÊŒ‚;»IbƒÃÞ69I¸¶ÇãRˆQ‰ÐQ1¸âʦHî!´U9Е^rï`ÒT*¤²ÃE"—UÙCq*Pm§Æ#¤ÇòbÑï §Mx~‚½àlɃ¤DRJ϶’lv°P1x’l~péKâšÆÉƒ›4²B mš«ª- Ñ©Œ²8Xa0xBÈ颿…—QìN«7Ø÷Â(ì¶” KÁâ"ÛÎö’mŠdì8ãå’(8,ŠÖ°J,%ñ€ ˆÍœÅ¢Á;d]ôþ u'š8ª^!­Œâê [$í„•ƒTy ü?U1Ò úû¶ÀŠÎÂ3¿U`Åÿ‘«‡ï¿‰ËìS’âì“¢“þâ;zõÿÃ@øgŒ3Å¢þ…Åüüþó#.8ÿ»LŸËb€ öw,9ÞÕÑÅÕÑYÖh¢‡6ŒÉ”` =ŸB’á<›ˆ‰RJ=!”©‡0]8æRD ÝnP:ˆOøÓrÄD‘D™÷ˆLi¹ìbJˆþG[Ĉô¿öYö‡]ªç¿ÈŽý: —ùB£Ð‚ï¿X Òë„à?0?çÿ¹äâ?Àû\ÿAþbrqE;¹¢{Ô")²3S–+šŠ:B´[S|‰&´è)dÔ€”M®Wõáè!#Ú Ž™ h!h²HØš‰irbÀ'B!P²ž´äÄFN€ä¹¬&R¥Á¿ Té1Ù_…´R:WÉÏpÁR":±pa)ùœä)¬Ðò9©X™Ô´ÄBL¤¤\*ª&ât´HÆ-IMtƒ¿EÈC-Û,¢›ÿë™ð÷¼zÀÿ|·à½àŽH'ÿO” þæ'þï‡\_ÿûëý?2iÆ ÓéFA¹¡›OY‡oÅPÙ9T¦i¯cäŽÈMKKHF&•Kfä”/¤³P„mYÔÚ ×¹}ìÃûa¢Ýñ›˜løRǘRß”½3“·Ð1q{¬Â SÙ.±¥!kh¾™´}Ìk&ÓRÕ]_´¾:$‡AayÅ•„díæ¿Ñ,¤ õéK ±¨«ëKww7‡Ãñ˨ÀSÙ1%—ÍV:DYfs¹\6›Í…B`|>ŸL&S©TÆãñÈ, …Âb±Ø“É„B•SØ999\‡Áx\ƒÁÈÌÌäq¹$)66OaJšÉ4&Á¢0bqÇ%1 às9TÉðx<•Î"7³€ÅøÝÝ|7–Lg.^ à…Ð___›Ãæòñ9ô›ÎspØl –Á‰e9L€PÂx|<|Ì!3L ƒÃãÓ…Τ2XL;“Éñ3²99tü‘ΊØàŸ pð ° l0ƒÍ¥°¹d(k7“Ã#19\~7X”°,n& ³¸±t ›Ç ‹¥0hï›Êä„ÐÙ 6àåååKBÈ,<™Áçw³¸<¯–/,À8$‡Ê`³@É4 , V8”Ç`ÅÆPØ`û2¬5XZ@gqél.‹Ë÷Íay‘¨^T6µæÚÔÅ»jÀF`eÒ€îîO¯_¿~û®€É¦099 €Ì"²ËÁnáñø—O¦±¢Š›ÆGNŒ¡·72nhlB‹ÓÝͳ Ý”š»¯­­mîjú?«[2é!™ô÷ïƒÖÕå³î@ßõN 7tó¸ÝÖ˜Æä·]BÌÝòøõ—[Û¨líVVV^4¶gt^‹kYÎ{ó®éêí·Ÿ¢7VF÷ØN¤¡Ïã£Íð¡>úÁýÕ“V†O3¦ÁJkZûL*ú1’ÙX5çrÕØÐ!í¬»áqq¼Ç+ùNML{ÆäsªøœLžùØöí‹Ku‡XY²Ò°G§œ:vìö‰`M¾yÓ<n¦Ä§Û½–pb¯^ÐìËMúŒˆœ½â }µõ&ã;†Ÿë x„–®ˆÔ¿Q€ës°e^T×ýÚUóêî={ì­»óHýŠñoöï§vcî[ñ¼ke¦‰õ¼ùø-Ôþ>£=¿™¶Ÿ>}òÓsC‡¦eO; ˶Pνէ¯;toùþƒg\DåÃÍþ^«ƒ)}Â4JªVk^ØoðÍZÃ:Ý$>¹9é\£·ö‹Ï;ÉÅÙù¿‡¹t Üdmšì÷I­)û£†åš§ÊÛ&×ìg&ÔdþÞ€ù|©¢ð¢þ¢±³·ØÕ}190qýÈ¥ÓæÑˆ/«µœy«ÍJp#üÖ{ˆm»ydϾÑ_^)œéúeûæÍöÂú½LÂÔoÊ2ªë¿óîÀæW³ž•67;¶¯aê­õâÑ)Û¨ÎO¸‡M2ï̾8|Á,#+o¬­žó¥A÷&ä'Ÿ Ñ·2qÇQæ1X-;ëáúºN=ƒ¼j ̓뫊]ƒp)ƒ¡Vœ~Ú:º“søþΙgjvc/6½ù}ÖžKõF.ÏgF©Q3¯G}µqÅc]SÓ•ÁNë,öéÈŠ gŸ~ÚxnLpTàCÊÕ¼ OÚ¦«åJ\äï~­ºCkC~Ô‚Ï7@=F6ö¨|‚0œçäG_‘ŽÊ:Sþx[PS1&v_Ü1ë­]½yLó&tlá÷{yäw·âÚÄ]Óuëš-³XiÞ+e÷‹n3´ÚÒ$·ºbÐ/´£ùuö‹æéÝ?x¦ºbú†âjÛ–!ø\dMÔewÜ 7×VŽÍ¾-§ö|a9 ¿¢‘v@WkúøÊZ-WÎ6 úÏÌè*˜6ÔbÂ’Ö«kê£"#§å¹T>_œ]W]5©hÁ?^.Š^¿€OútZÎì¶|\SýB“QeS?ez­Ÿ±Òàæî³÷^m 5¨Ú3Û<Ä+b$^»ÝäS íK¹]õüqüuLjð·ŽGüz¶×r>7ë¶V2OÔVV`ËNt«å߬Ì/žëöâ· ýë¶U ³^6ïðÛ7n«žíˆºeÚú ÏZœõ©Ws«Á…z“õ‘šqm}·»ºxž'ø OÙaÄÑèó'kkälvê¡„%v.»í未 W_üñ¡NúÙ+}ü†"kÕ°ÁEëÐg‹Bs¦e.sZ屨Y`¿j0kÆ þìëÌy~Qç«ÃîË‘ùAG¢†¾? ˜æž‰]žüdžý1oÐå(FsƤ±ÃZª<è«ùjðjóI>óÎ÷Ÿ­œl[ܺæ½ÅÌ ½#Y4ÓÇ{>hS=u™:¶3j24 &³êþÝ@ãY˜ænUûUKçÃÞ!Nfþš:éQ³ŒiêmÓM/캿¦}9}rz¢/…u)ýõ§@b`Vµ…]]N\ØgÂ`xÿ®ÑÞd¿V] ¯g-I\v~Y;39ËzXöØåÏmžÙ\|¤¾9²dʽèæòc—X—–<)«¼›¡õ‚ƒº7ê˜ó\V ¶¶ŠöÞì€y8±èÓåÛëÖÕFÍýætœãu/u©ëb3ÿXdµéMÿýSÎØ|Ü>äМWX³zш–'ç[êWjŽÉk_?yä” ñ&eü‚ßúy\Žvæ!,7Ú”×¾q&ÜËcäž8±wô\Ó93•î±)ޜڢÆ=égÑdŸ0ÿ©xª“õŒ×Z¨Û•´ŽJ¹®>aƒÇòjÊ»tF¼wàš‚S£®9k~õÓ=Ñ‘«ÇhÚYP„ #²_ÔŽœ[¥sùNxÌØé¯Îni¿zÏÉ¿uêǶ¥öô{C½Øpw^ ÝñjxHÚóß´èÛÖyÓub÷[­÷÷Tß\1ËÜÃÕŸ°ö²Ï‡惞їîìü‚H›·¦~¯Fâ`Œæ(´Æ»ÎƒÐCw§FøÚGùdòçÀó?#.‡…£L µ•†Ç÷ž:¬õckÚç¸K­>Û~]´$¤³/Ï狟n(ÃzVDýB,~ÒçÜ¿Ø;óx¨¾ÿ“¢²†¤"Ó4(û2cÉQˆìÛØ3vÆ:–„ÔÈN‘¥$²”$”}ß÷O"”dI$“Hù¨”¾fÁŸÏ÷ñyôû>~Î?ópï9çÞsϹç÷ýz¿Ÿ¾n{ÕòÉ.‚†™Æ4eíõtôÊÌÛRyÛ²¤µt´Š¬_„ ÷¸‡Þ+M¯N @ÈQg‘Dž¹\LKWiÞýxFUúC„ÄÍχï¨ô|€™ƒDLù2^ O·‘ÌÌBÇu¤CÕT¡GòôH¤þY‚Éšt,ù2ÞŸ“ïI8%õäí´Ý‚%OÑ)–\{ß랣ÖÀsr3ƒ¦ð^ dÆÓ¯%{_2ûT†g_†+êéñhu?LÍ(ªäÍëŸ,œ8œ.IîñtV¨´Žì\î=ùùc7å´ÍÑÜÏNE¿~’ͤï$©ô²™´—ÔH݇‚ýVs—«¤0ÍVcŽ·Oïý‹Üò,dž|Co!ÃI#”ëÜöЬ8šv|•’näÛÅ_°…œç¤¤®Ý}]kç9°Žê ÿÔzYRZ Ť ç2G¯ŠgA[1MGÆ|Žëñð½}{¨[”‡ÓA´åÃúûûK ïëɹƒЬÈ~GQȤöy›Š^ßvŠ?ÜYÈc×2•ÓG¡"É>GçÝ»èWÜ¿Üeäß¶#CUE޳v,C!@ÂûÚìÓÆÜ=S“šB­‰á ¹T‡ýòº³O EؾÏiõÁûÏÞ¼M† ÄG¤»¶m×Ú}±LéÛ"&|{ë(³²Å7ÎL)E8óŠE¯[j^7óÕ(cÁ3‚o ­NP$ao%“©Ù_£Î¦ ]píSœµ€”ÅdÆ~hT0xNÍËKûÁ Î4˜”eàC©ÖI®q3£nˆEP°Üe âíLë§ÒÞ  ½—ßp‘‰kBzÏÄZƒx²­Á —DñìVo‘ÃMeÎY’î¨Ñøp(Íá!;ètá۪Ʃ[õT%ZÝlMÄ {ʸ¯7Š^ÒºÝwÖ ¬`×’ë3ÐUq‹¯®«GÉ6‡çLÉô—(ÅÄBdàרëèéx3 ºC|ïÀ$e¨2餅ãɦW³Ô­Üq"õZ”|ld<Â#;¿ØY?¸ÂÍc:aŸ³‹Æº´EÊ âÈ93éX[´þ€ØéHPŸ{\B%åéZ³Ìôh§²]MXgP•kÒ¼–t屺à(¨Ký%É¢w,Ŷ¨Y0+-£øPzÉ+¯86ô{¬SÚ«»èboF¥ùfV?«ÜRTvå¹ê÷l(ó"[Z7˜Ra>kX«hˆçÛB៧¼Lm¿ =;!) Mé AoÒ™Ž~©é¯Ê>XèéIýRãý9£G­Òí ¸ê‘÷BmÒ½}Cä´(‘éÓúqNC%_3Ò1°…RóCU‹Ró¨Ú:‰Ò7Ù©˜ýîweUÝ”E¦Mb1«Ø“L)ͪöº”¯«i•C7LZ¶íX¤5ÏÐi/«@¥ùít4(º;õç.À5+²’¥ËÔh&e+H õ¦»eÐï•Ð0ìõ{óC¶Ü'·øƒ®W0›ÀeÆ+†•óÆ óR5»=·Õ•eŒ2¿7cö™e I±&n>#Ñâ\Z²=”±(p—³o€YB¢2å xdç«Ûnùyö¢ôJ ;³çRærü ÌÉtšwÄöGOh/^Ì,Ý>ùÄX;»ÑCù’~Ç…KvcÍœVÏlŠ-¬ 虺Á*Â’,×r˜z˜kÄ¿ihý½;·ÙM «e—wEvÇâ‰c?Nc†¶Q‘ÜÆx :p`¿]üÿÊðëÒæßÿ°ÊŒǼ…ý,"$HÄÿãâ?,ýüþþ÷ ÒZûqŸãÅ6€ ­µþlL Þ@ üsü0kZe ÿ%j˜@®µ>è«8l¬1j@ü·rc¹Ä›e\:‡7oíÆs‰±ö <áwMì9S“Xz™¼{A› oiYk§Áéý6:“÷,Ÿ!¸6ã©ØX$¿-̆?ºl®âç¨ÂáXi7'ÌÃÉÆpÚë„í„è8â.#ˆVm±úv.þ¥ê’üøz–º^j.Ž ¸ô‹WÇáµQR@ ÀnoOÐú¬ü튄Y,ÿmc)E  ñË…`QÂãXw°C‘! {œ`Î#„×v ÂeéÎq\u\¯áqÂk²¬²‚±]¶B^×·Xo4lXÄðæÅ ¤áuÆÂu–;xY ±Læ\ñxáü·Ú²Ö°G¸.n¬Á¤qðá-oïAC¸ÕUã'‘{ ç×!8Þ,Û÷ÖO±pË5½‹uÓÛ w7§Üb«&n÷:jܺÿœ ¼Rÿ†Ïf3Šïwµ&ÿ?„"o~CËÏç{fŠUů{Ì8XèúwÊ ûú9J…€¸Žýyf¢-—ûoMMËŒÑÿö5'¶y¯ÞÑ+¥ã&ax;ï7l=.îq»×¹¥šsš$”ÞÜÁàÿº#ÿË´ùûÿï@ðïÿ¦ñ?…E„×ê?E!àßúÏ_’6Ðb»(Nÿéû\œšäŸè?…ƒ ƒ4Îß“sL8ªæ!e‹Hh´Œ{ÿþýQ óXa››gÝiúU÷Aòîò›EÓ:ÏgÁ®ìÄ©†â‡Å°«¸ ZÆ YݶNâPõ)9ò›E Á¹tüÁ¶Éá÷³+»Ü«y~DÑ! £m`t‚KÛÏ4ªš×(Ì1¡þNU_yÇ fP¹˜kŽÊ…ˆÓÃòV'ÏNbÞÕw {Ül,my·ú—^ ò…÷䦾¡7÷ëžO`´ó v)ÀÓ6"È»\úsúÝnu½“ð,8ŸÖ ¾^Ù3­wpüj~§vp¥˜yØqËHIËpÿôVˆYˆˆY°(,´êA^_óšøõüôC*ÔÎg?~sÒ![Ûv¥žMÆ\Å3=4û©©) ¿ìœºç"f!¢f!'¬¯ÈØÆX^k¶¼ÖrÜ2JeVn^¡.¸^ÔeÛônjêÕøÛÑñ·X¸¸[Þi×›.75ýs´ ¯7HÛÄ@ƒKRÊzÎzeœð.”wJà5@ó B`Ñ5¦Ñµ&U¹§LÕHH¶ïÇê?›b{áç^ˆ1S ;b8 ˆÂQè1áIÄ µc{¹ÅàˆGûJÊOJSº ~ûãêý¡ù| ”ï@4¯Âw ^H~á ÏA–Ïé1(õá.ê½ùP‰±Þ¯˜­­asÈ¥–“æedØé4ʘ$92w¡Ú Õž½ÀâLb#}¾)Ò«æ^‡Ü3ÆÁ³¤$€+Œ™a`ºgse¡9—èg†IýIÞÊùñàç,~?ò¤˜¥R»·6Pþ“ªú']‘§o²]˜w-ÖÝ‘41 =&G²‹«+4;–éþ(-ÎO6ð5>ûJ,êзOCç:ioh âúb—¾=x€ Cã5ë3õø$··|› Ó“/Ž\Å ûX?÷:c‹}>tÍLò.u_«Ë"¿ô _XŒÝMë"ß<¥4óì[sûl4åôôŸGœ‰} jÎØ9øÇïéÊ^4¯#ÈUFÄ<Ó¾.|48”ËB&ßÝ@óÙI¸ÅÕ«õý<ŠŒ«0¹(SYlÎx˜(á{Ë‚ƒü©=•Ç>Ê¥¦2_@ `ȳ㉔(ºOÌöO ¾ù‡Ý¥"¯UbfQb¨^ÛEy‡Y¥…2Šf§Œ§"9¹ßËôžîk;»*.h©u ‘ϧ‘Fe³%EÈW:I&Þ¢y< «6CZìV¯Š ÖçöýTZb^¾o_ªŽ $²jX÷Úá®ä€aÀ) ¯=?ÊOÏRz¨ùˆº¢¨KëÃð J¢åâÚü6‡7†Gíu5•SàHËÙ]o¨Ùšhæƒ4 ž½7H;¾?ü8™ãÜÕݲ ü£Ñ,™×2‚&{;mÆÀ—¡‡º: €{œ+S|Öó{´ÎÂB܃&?쌇¦Rþ<ŸÛc5ÅV/Ьu¹°/4k[©ÑrB”/cºÚD¿Ë÷(ÒÛ_šõTÆÒˆ96Ø©Ÿs7ø~2'ãžU«MX«¦Ú ^'“O~c†nc>c=U¥„¤36,/ÌŒ“ž'xc&'i¯>h…Œ÷Æ áf’Ð:$nN…Éh7ñTt˜ã©!9ò䬩£íÔ„OÑb›Ü~´l YåµôŽ+õt)äb•º=ŽšnÕ/½t&_øÐf]„ÍpXꋚ4ưÂù9¡>2"p´úÙ±'Ÿ>ÂîhœɵѷujW—ܼ³Û6rþö"§zS0û6 Æé»/=óÏÊ×¼|ÿ>jÎ?<Áj e_w°ª¾dMÍ„ÑÙב´¦;}jÆ¡ÐÈ—®pƒ[)9|jªH‹ž,Î÷Ϊl‹ygvFosM½ú}i³—Ëkq–TšÁö‰êÔõG:ÏÏ<£B“½‡šZ^¶=Ò û±·Õ>ì÷¢*—6›TÈzæDOß{Ðü0è=véýŸ/lÿ÷_@lõýO ^ÿWH"ü›ÿøKÒæüÈß¼"ÂÒÆeéŸ*\¾¥:6â‰ró÷£sîÞ˜]pdã—¸¸Uø—„Y[„Ãü{Wåúö•u„Ó¦SŠiõ;Ç2KbF¥“:ŠJ‘#41–,Ã,–±LÚE¨&Ù*?I–lÙ™–S9¶!1ö ih˜1Ƙa0ï}ELÛΖ˜ ¦òfÕéh‰ðƒç蛢ÎÚb/ˆÈ÷/Í_†žÉžOÚ ‹@àó«›·=“ÿ9{„ ½[|PpOO ®éOSÐôSpt³@‰ç˜ié… 5aëTí‘(ÿH¤tyáç¦Îƒ,¬tN÷=‘h—©€Z¦'P›Š3ç¡Ó˜ƒW-šk! í§`nšâs »ùVð¼œö?Õ™^N =pl,\>þU±Ù°áÂðí w@úÌêÞì ú-týjú ÿ/Æ¿+ üÏã?-]oñß?‘œOÂÛáó¿¿öþGG[Gÿikjhh æ]Sˆÿ¢þÿéIŸâ¿™©F€@¨ÖPkê ìüN Ý ¬‡À. Ìïì tXä©€ˆ !©Úh€½Aà€ÚÙÅÁá1å¬|U?Î=#ðÓOo™~u$ÕÖÓ™‚v>] ÂÌ#N(¸ƒË4õ' ?Fºa1ˆÏ\¨è‹ðóʯÞÜ44EÀü8U„ïNæÜúfx>ªk‡H‰¨ZQ?¦ªÔQÿZZs뜖OUNÍy ò#£6ý ˆCs½¹¨æ/çL= ÚGÏ Mÿ/âÇØ;1ãS„]XCW}†¶kNsDu®è{é¾+ngÏÊÎ\OÓ¤œ· ¿κ||y=õæÞï2‚{í¾Þg’‚ûR®Øg×7[­\«=èýapѼ×Å0 êÆ_¢þ÷…µáceŒœ<‰5Î,²Ús_b|ÙŠþ§{‡»ð&ß·øob*/ªŸ=›°ù=•5zðÇW¹òŽïá‹ &Ž]tÓ±~¸ú¹1-H¨=(ZLi-¦¸aCÕ©…qDÝç|Á¤t—ÜSVa[í£VÊ}š1>¢Ö›í(D÷•ƒlTùXØ|X3ÞV(E/åt€}¼½a÷¡¥Ë&ÖÎÜC(n„±ÂhÄñT‹ô:Cwr¨*J*äÙ”ø2m,Û‹°©Ú€_-Ôï5ûÞˆ÷’áŠT¾º&Ÿ\ÂNGNÔ$lÇš«ctíþMxÝ%Eº£íîÇúP: ýدšªu)Cn?ç›`;Ô@ÏOMuýµpMŸ%#€ªO4ï6w™â`þµînë“aê{}|dLd^CŽ|¡89yB˜ æ>gQI†cç¤Ô¸×.±%ÙĘál½å]âY x_"5ΧêÇâýs)ðA4XD0E¯F™éÇÁ9ìì`ÿ‰QÆûc•Y[šZc’¸$Ù4nìwy8ý€RÜ0v‚ѳZ%ÁŒÃ­»qïžÖqÇäßq„y“K³ãqnp¤ŠöŸ5ì 6}¼“7µ/¨gkÚ‹SÎÓ ºÃÌÀ' ¿ŸàóûzüÌ ì·?]V â&“3lx™“ø‹¶&M•¤MvÝ5¡·êy6–•ÀXeå¸8í<ûºµY!û6²±²e²… ”Ó†¿¼õ¸žÏHD¨‘ÆŸJÂ<ƒ/yʈoØ™–EPmBæ­×T_{]ø9º¥•.“½ÍJgáy­”²Ø¿yÓZLÝ2ˆƒW2*¥y7o6Zã!¡|s4 EDÖóJïÆó–·DƒQætÚEæºÎ$k³ëÉæfІ=Çóš6zá”Fh¿T»úÕô2ìy”ù1uË{™¼üfIî&íÀš—ZW¿Îovë»q Ü@¾øÄðx‰oʶ ³óƒ˜í&ÐM¹ôµ€™zG–«¯^NIÄgŒÀ®ú/ Ãìëm7”›@ÝÙ?_êw·å†šFL²"™0%[G× ¿›à·bß (°Ñ÷ßRŒÍk÷Çßµÿ8,•tÝÉ_¸WÕ™£µGxO’eœ§ÃëH£0=>&C¿R¨~Uœîê¥%´°K9Þ¥dÀw)FŒ´ØûDØÈLÜ_-a'?Þ®ìÏÝ%Ë/û ;»–€õ™×ÛäOºÔ(¬kî¹ËXˆrÓ›ª¬îEé^µŒ÷Ëë„¿š:z÷¸”•ßPqŸ´‰ïw!@h<~;¯dL„“`´L$¾¿ªx~‰UV’ópØc¥:®wƒUÀ býeW¹Pÿ©ûút›×±˜ç^–$ÌùŒ“ÅäàS‰Âfõf«k×¼#Ým&Õ$±•¶¤ñ¬X¯Ž%¨!ꊡeÀÐÜvnT©ôS¾P ª_G¶eò;°Wh‘Š”¬}0|ÃQ«â'fâA7:UßËöÞoß;bØYš}*!¦ç­lé!o8Ó›q!Á!MÛsvo´&&r¸/ÂpÖ–Ó PNn¢ì |=‚¨Öªã#SþFÚ²-¶v7r1ÑÄ!çFÛxƒBaÝhËÄtF⌽ûÉÛ_g‡d}èÇ]ÚàÝÒ¼~è¿™©¤ŒûÙ?£?^Æ1 z×@äù|ÊpWÔïXõ|l¬q#ã:/¾eÅx<9Œi­Ðº•@É·ÐA*vÛò¶6¡h9´ô›U†0 ~Íà?—ø©.”ò|E¾:jdžõ “}\´OP ÷Kåíè&UOX§æ;º…riGòÎ[~ îµ¡„pcSK;^&l8%–»·€\o¨QPÔc߈’±*K2SÃg>t%f8í’Èå”Ý%ð,QÊ ;¥ðÇäN½æ*îe^¯}Ì1Ù”q+¸Ðîa‰ÁØø¶÷ùûŸ‚×)ZÀNX|O˜lb`;c{#¥ñûú]ÿÀÍ©=üsK“úá"éÞ;¢ÅÒÐÒYgÒ_sY(;ZïÈŦ¤ºÃj‹;&pir6%M,“5g”ÓGïšâHûû³êÝøu¾57;Èñ9 ÿ,^hyà ±ƒÃž†Ã…Þã1>„_xñ¥­]¿D’¨=!Õ~阾?Ã&KÚˆŽ1ã£ÒÙnµ<¯uaæ}‡ß­½ K®†ÅsR¡©àOm–HÆ®3|èË7QÙ±vߦ“ òån6úÏMj–-öÖ,ßåË´ö4¾j+éoWãÚÓu Öµ:j¤"/õñ@§VÒ¯3"”ÃÍsnÄ9ÆbÑ䤣ﰌ-–ð„ W¢l¯m*lËŽ¬å²Vå-ïmR· ¶¸F é`ZZ”?þB€Ø*U2!²6~ käŽ_Ï„ë{?^M„ª¾dO'¶•½µe ;ȹ£YdigxZ ~5›É­wŒS2`§Øzž„Æ1i²¾‰ëû_x&xíAlô%YƒÑ‘rI• x„W5X”¬:¾ÔÕ~ ½‡Ã©Õº¥ÛÆg'´ì :ȇmË Jg«çÒm”-Ò¸aÉìN–5™LæåpttôJº]ý‹ g‹èÐâðCË8^óû×a•ÏÝá„C‡Zd˜×[Ö•­}p‰ –Ñ“äK‘ ±­‘ÐCd/£‚ ùÆ4+VÝ {Õ”Ýä°d®=uåžR^ü55ÓroBµG^U¾¿šôjHϲ£ëÑæÌÂ!K&Çhá!ƒÄnûJÂ|œk vOB«Z»U6~ØœOSɵ­?::)mVn§pLK߯n¢n?]À¹dš[-»|ÂÃ,ÅõÕ2T?-ÌGŸP"÷# 겸,§»0xóR[$®>f¤€G/¦”žix„tï(] }K!(=¯ŒjÍG÷Ét…(Õ”r»BeQ2yM ¿gÝ¿ùöÖ8æøZ~Äu(JÜ´¯CÇ< ¹›ÐÖ=ßVíåÇ¢GrRZ{Ä«;Sª"ËIym/PJs‹fçS‚xRq§v–æä°®ô†i÷S¨%¯®é`~m„,¿% $¤ø\¢ð2Ðõ%Åéç;tx’ z´ö— x9eœìž¡WúŒÖÛûÃì+|ˆ¼v£ç=Í/×ïê,‹0YÊ©ãñ¿ßzòº`|¨2\:ÎcÓˆÚ¤æ õ>ù+½‘葉ȾfÌ?Œï ãÄŸ6a<«mÇŽ.m=¹ÑÙpõ{÷€Ò‰ÜS ÑOíåÖHò†5Õ‡‹¥úÞ¾¨|kŸþ¦3êáŒíã°Þôñ!1à•S»ìe(Ö8ínq1ï‡âªh#mÝØ:†ÔÔÚ2ü€¼Óùƒ¶âÆOÛÌŸ¹:_d½2Vy'yï@¾Ï±÷PMß»hQ¥+Ò{ï¢"  ‚TéÐ[ UE@¥K—¦R"½'é½CB• ÔHB^‚¿^þ÷®õÞzë½µn¢)'3ßìÙ³÷7{Î9ÌVWØ –„7‰î€P¹Í’Ë`|iêc[}ßí^bÄœs÷;ôð§ü9¢ÇPµ°âñËÒ†–ÃfrÚFU Jêl‰³)‘×gö莑:Ö~ž@5ÚfÆì¾E.m]&`Y¼tÚšf@굌­Mq?5„õý6WѧmèÊamPZÃFs³² sqC›S(¶i·‹Ogsuu‚ÃØ9V"[} dìˆÉE¢IK(ðµ,Oý‡±_ãhUvQÈT1;Ö•F8møtNríË…ß–v«žãïŠ{ y׆T“³€UÜŸ³ªM¢B›ÐñSý¥kBï9ú&œìt<Ÿ_©îx’A\ºQÍÃCu1ª´ û-A˜YLÖìvB$zWánÛâçŽ\J¥ÕµaàUí·æu.ÓÕ¬7·$œ›è n¿Ö>‰Xµ«l±€Ø‰¿xÛ&Ð'¿×“ëT—CóÀØ}ðƒKœÙÊxÓ–·—¸×'‰Ç_¡˜–™ÜÂ#wËÆ?ë|ÃØ20õM=òûZn€”Fñ6|žÖ^ÛÜÜtƒ ÌÛeÌ/b¢T¤™(f4“øýc6ææ^z™f]ŠÑ´EH®ï†{ö+Œ? Žz!(õ©_æø[Îkxò`í±ýã ²o¸ÿÊ&>^ïdMÚW ¼ÄÅ-«A½‚7[‚ëÁ_Ö¹] UúˆÈ•Qñ\—¬Ïd ûß*'5€µÕ4ñ-öâmMúÞïW‘ÓHÏ™;RcïT³ãvÆß ·T/ͼ2õ™´žñõç-?Öá >ûj·×¯$ ^&.ªŒêû¥nÇ\w¹ŸH·Ɔ› œ0ÿœ¬{àQn¦=ÔM £/¤æãí­€p¹Ãì7÷Šs~§“;ëÅðÚdË*r—m8ʬÌc¹Kó™¢v§ô‰Q…íu&[“jgÿÚ.P¾Ÿ ËCÝ¡ZZòà(ºaíG½RÜCêßb36Þi›‚mª–Ÿm —8…Œ*§]2Ö ÁY{é+8AÇ;ð`žöÝ‚§  ­*ì– õ«¡å8ÔLÝæc`¬ÊÖ÷6ši9úmƒŽê[M\ëeÀUOàñL¼ÍÔ Š¡ë׳ߨªä¤ã­rQ»ÑYõÇei½FB'kT,’Ä#WkÝ’My6Émê"$pOÑ®¬*®N¼ûîQSœ„fÁ³UÏ /Ló?¦]•Sn¸.û1 Ó-g9‘*ë½¾qxFéx0Ž5á§‚¨é¾cÑó¬JÅÁ'1s?†‚Гv÷—Ù‡äeج_*…†¦zÝ!€/Y¬åb÷ú\ó^mTjG- 9Û@âwKŸÿ´lÖ‘·™±ÿjÃéôiTEzÍË–Pga¤Pñ@ÌNIÈ`lÈÓ¼&^GÑÿÔ[ºg]ûóuû€ÒÉN\TÖÉ~!ä™1¼=Η<Ós'á—ðá÷,gÄ’ýÐsѱD«Å¦n#¥—6¥fÜÚ¸n²ÊmÈaf7vm¬ƒ0yØ7ÉWµx»S¼3Ó"2E1^YÓZi¬‰óž¬\©Ê¾°î5O™‰¦]¶£_%Çmg2©ÛÖ¼Ñù¡{ ÷™êÈþ0Kê lÆ&ãæ´:Ä 'ñ.9{ß*–m5 9ª¸,©L‘Ô½©´õþ[öÕî·YR;ï+”èy%z*íäâ· ÅLJ¸yZ”Rð ÎC5s&ŒmÒDpy1¶KAÝS/ÑÆPÕ'õI/¾ãk]JXi <ÚÊßO5Ùü£¼¡g1NÉuÐóZ‚=´½yc²B³¯èhqRýP£Ÿåãˆÿ0#ìR•ÛF÷/hÿ§"NZª€Æ½°’ ôö jƒ´`×-x¨^êôf#`;“qgÃöΦٷU«ìS$k‹¹2èÈëѯ#Æt×!ÂÖyUƒ`þtúJƦýˆîýŽ{Ê\ôŸ3ïûöøy ÇŽÿòiSÖä*õE-¿qgÄtv¥Ì¢-Rͺ3Þ„xƒ¼A)dÑ´@¦Äʼ':sQaNü}£ßvLI¼É±ÛÃÆÏ+ôÅçßÒaUkW¥”(ï¬ÖîJÌŸT4n¼2^¬~«a°µYÕ:ÌÑ·×ßõëy4]N4êsi¶MÇ  ÄÅ3ð³É3ø_䲪 ,ÍH:›ôDFÛ“;§‚¥úB…M‡±ïuí“YÄN¬oc}¨©ðy÷C@ùú«ÁÄ€3Ǧ,Œ€5œPfs«îÏÞ«˜_)Žùô¼Ï%,É ÚØñòMbûå^J¼ß+÷JÁ¾)+äž<êmÆ•¢hõ^óeä!ïCºÜ‚)ÿ¢Že1¹™ZåG»Ùb>ô¬mD`5BçTSÊráøM¨…,˔ߤ9a/{X$œñŒ¿˜o툥ËÅRÔp:0;9€Ø×Ö0"}LÙÌ$ÓW}\=otùÈÞj2$ˆv›ÀËX›û‡yÙ•FÜ_ìfSüºŒŸ¿ lû tMé€wã¤U\¿IŠŸ°&íTÔ£œ¼kÜ<Ư­³D9Yù²Ò iØìÞRàLgVvVsãà<ù‰A3{4Ï ãŠè2Óôȕ߽,ÊÆNŠÌx‘¦Yø¡Àya…ƒ½óš5„Ñ5+\®¦PÓþ¤¨¼¹rà®püÚc…ùÙzE¥!ïZ áµÙIN2òt‚¹ð@÷à¬N ­LÐ:&N.P•ü䛡ì%‚îä \ÆöÍ “ìäÖf[¤¶;l8^†¡î`¼j¡+ÎÆÏÙwäý§Ï6R:º… Œ+ðœà`=!´ìLQÛã5 •¨¤áàĬ³£¤h€ÜíÞ<Æcåw140-~r*­CLrÇ›U,Ôè ¾¯¥Þé×w‚ED Ë*rzʱÛCÆ>Âø«ƒJ:°ó¶J+EèqËj…ÚøNTµŽÒ^j`\C“ÙÞ'5ÄfÐÞw(E·’&ƒo_¹©m5Ÿ™+ë×’šÝ÷qi&Î\?–q›žªròC ÷54;ž¥Ýl>d%ÈnæSÙt_ê/‹w ¬4÷]Œï¾;|݆úÕL%¹õÒ*EÞ@+.¯K&ŠÙã×ëg)ŒÇB£2RáóAE è¾ó©/QžOÒ|8Ïuþ›^jljí2jãó à—÷¸©ï½C?•þF“®þÀhó%ó'2lÇQ‚¯ïeRH3íàK€AÈÉì8²Zc­æÂS¿"‡&zÁ~–7$Å ^¸ÿìÜY>(2_çoÂ×.Æ‚‚qÖj|ßlXâë°ã«,o=²hÄÞFÎ?ƯéÓò)|ú}0Ïf ÜŸcˆòXÅ]à\üÊæ¿ôAΦ3ÚôÈ&~u¡†–Iö§ÙI2t?¿£vÜ $<Ã$qãÛç|SZ¯äa +àÄù €­öÁ²M¼O 7°·À“~µƒ+2i¹&´Ó„ Ö%ÐpïÄ·6™.(FÜk¡Þ¸9»b¶²¬™õ™ÎzR¦é6ôíÄÿU¦”çÛáïÆ¹9ÇŽ+M›ý‡Ãj‹2L0Á×+ö¾¶T¡zªïjŸé•ø¸E§êð>.zíøæâøØ»!xœ€*¥~5^æ3—Ù ,Ú*ë)@XòhB Î!+‹Eýá…]çÃRÃÚw +Û§º±¢‘Ž(1”«F-D‰YbÊÚÞÏÅÖ™« ÖÎ…""Zà¿KÔ$éXØÄ2õ` žª>ßaòƒÄ*½ßGs”J7‚X©µxr¸1[î}2+/V#©×ƒk–ø³‹ÝNÞ‰ËÏŽKî( óÓÇ£æßÐÊÚ1æÄprÀîÖ kokš~é·édŽ%»™ùîëD¯jUÁ¨mìC[Ó 5©ûªÉ“üÒ/R’7>3W.{JÛs†_-2øµ}¸E3Kûn“ÜÉÚïRÀ¾´éñ‘œRµBЎñHÓÎÇ1Úz®UÒGCqÁ¸ÅÅÊ¥•ñÖŠ •à’wjhª$1eÒ½ð’œH, A导·[(ÚÑ/Qµè)'¶Ç¥-àįŒ­­¬ú~¼ŠUÑ€‚bá½à¾ãcܬ‹µë2ïs·üÖ«11ˆÂ¶ïº”Yͺ“»÷¾ñšz;gL õ¨a^ñ$eªYZû,(-A{÷`Ñ×mÍð¨ 3·äâñÙ/l³äóœˆðó/-àŽ³Àix¹oá ÉÔK…¸@íé¹ä„„‘fÿ‡d%žÃý`tE¾Å÷VäÉvsúEÚŸ—¬fõmÍë‘eì3È TB¢RçwGÚuíæõ‘ú•þ¡Ü&ÌŠ=äÄ ŒS@§dÀgsâ$n#ÝbL2¶Çóo¨‡!G¯ íØÏß­öǶF¢à^J²þîó’^÷6Ä7%Я9bK–Õ ›ˆ“^–õAQ…à Ҍ–lñó7ÚºÅo²é]ÝïÖà«ÒAL QJ¸–’T3çpG«²%&6êßÚ˜Ko¼…0,[Uí Z£¬'vkyJæRKeÓ‘kÃ…0SÕÕ4ðÉ^Á—_’´¨?d0ó›ûQé\fƒvF-f¾(Rít÷¾ùøüaË€(u—/dàöP£nGt ¤pÖGÏ^ýc9÷ÌÝ’5kìâv÷£öƒvY {Ñ«AEœ¢´SÒ² ›ŒAÚvkV™6Y&[Þ²é›gÕ¥°‚€w( ü4±x(K6ËQ¬ÄÈ®Î9Ü¢jW'S*²ê5Ÿ7+ô¤zQ¸§œˆ<(¶SpÚ¨™)_&®+Tê ×t%J Â1duiªåËŽc¿Q?÷›3'ʵ.{²=ްp›Ï¼ƒGò“ß-ä˜o¹ôàÔ™~"^™2Ý`X®³ ÓÂäØ{”ò“±5KGøVF ÕJX¨Åkû3$ÀýZYw? ¼'§÷éÆmѬõÐÌ´g{tÄ›,ø–|ÐÜkT»ŸL–:;l—w>AY¹½ü²…ŠÏ`ÎPvЖ¬ÚLX7sæ»VRÉPmò°MkÇØ´/Ýv‡Ô\òþ\‘ÑÎ9¯K(üUìü (ß XñÎñu9ycSsùÉnra-ÝÚ –«{ Úž¥¬)5‘óÖý‡øUÑéYv}Û»jÊ:z¸NÚàÃ6§ƒéHî6S˜*yÏgÃþyFîCoÇþ…7Åɒת£ucîÛų\‘vök™b;é½ë†#EŒÛñúMmTYží¼ŽOoÛö°!èÔÏÃG&èøEËíJ¬–gšJ ‚óñ}Œ(Ûï­òuÍ>aUeSú0K2ü‚ì– ½ &€i÷²†™óÆ4Ï?ÿËQõûa}x›ògºÏb²g—²f#?S«ÎYHÇœñTéï¼ëXýaMûèhsuº”£5Øk8´B=•\E``|É“Îz¹È³~&#Д¸D1(cÛ]Ù• Öˆ½™»Š+dv©-vò‹79ņiOðÍqPþûÔ³æô§ã“ÃO— LÖ>¦éÔwK¯ðZËLn`²ÍoÌúú?FVÃ÷¤Xî+z¶Ÿ”c¿¾‰XÝJ¦Éd{qrý|rä~tÒËç%ªŠõ±äòV…j›»sþ%Ê­¶†.Ôw¿“ ÄÿÞÓÜç]ãzm˜õïJíµA3œ&t¾‡w²N‹¾x .»a`µr‹,øÚèÁËuseî–º~™”Bøådsð³|9ê¶Á‘Õ—Eñ3Ð_è^ÐÉÍ”.B¿$TDú¨´t¶êñ„‰L(Z¼™ \Iì#S<_Ĩ¨qì·k+ÞøKn9A÷S¹Ù”æñþ¡hÀмP›Û³ ÿw;XÔ¬>‡ÝRe|_´j ‚Õœ(Gö½ú¾’4ìVÍž£òTó‹ÎÃ$oPß¹ © †ô/¾¢CFú§ç2dvné'Ú7›¯‰¿ö8fìÐUáö ª|UÝj’ ×Wwøù‰}ްĭÄs33WõéÖkxwPc›GÑSŽ6[ý  Hï$:C®p£ÉÎûË£N§Â[þþo#ä—È”nxä"6Ò»ªQïHbO\šMÍT¢ô+²é,2æÄ 7—¦Š,©ž‚údã÷ãËVÒÇ1ëû†¹èmðç.õA©ëf8O ¹Ëà+P¥€ôHå|ªnÀËÀTà½]|Uð‡þ#ñMSØvqÛ²@¿ñÇc[ìÚ@ÆEó ×[«?=¶òi;{ããhÖ><ÞQGÖ!rtϹ+ŠËw\\Œ¦ð5Ù  *<ñæþUì û¶f}ký½TºÛkçÙA!~+qÌÔ9êtÂN¨]z®álfüÁÎnPfdXáóú¶Õ;r¯š§Ô`Ï„¾Ž»Z õ+`f¾dBg}£à+‡xûë©”3ß š6)¹Â7$fL¤'ö÷½N¯2²;±@}E³+‘ùŸ¨Æ±+Á'+³ ãÈíPc–•ál×ëÒ¿S¬~'8ñ©Í3i Åf%Y¬òR¿rJo×,Ô»¹³ù†ÆÎøVÕÁ¬nðM/Í@Ž6vMJÈHàgêàeÃ"Uê˜s¦ý¡h?äB’BL˜tŸ¸Ç"¥±àLöúò+H¶g‘M¶ÇA™ÍîIQûµBêáA $…Ç–‘TòD…{¢&NñxuÖÒûmBò˜ªN¶Àdì}»è†w™Hw{gš…TÑ4êÜÒ¶Moÿǰhà³ÅKÇ.÷Ô'õ‹ 1å?`È7ócµ™>÷{ßá  »‰>­Å6=Öy^×°²EsÂyR’b_at“1”ánNL¥°Éoê®ÒÊ—Ð%æ9ÁÜ•þ‹ã<ŒŒöYþÐL/óÝÇ\«¯4”O#W4Ï3fM‰¸ûÝ Ó ïÔ¼S2¨Ÿ5>/:¹_³ËY¤ö6«qÙÍÿèJôzÀÜʆ˜Z©ÒŠ‘ÇI[<¡6 5r÷UN6[º|[\ÚÁåºÍ¯9qÇ//<àU@ï!MËÖ2ø/A]pÌ´¶âã>ÎǨާ¡ÄI§j‘á¡ÔˆÇØpÞK€>kC{°ÐXÐM0£?34}ÉKò1tà¸ÁPl壃ȡƒu¹Åx^”ÔÅÌxöã-b¦«Jl¹‹m*5:^{€Ì‡’i@¨êH2Îóܲt¨Ò›Œ²f™_BhÀ¸f”ØýyqåXû{È ,Ás‹û¼(0;‰b[J^²¦‘ßn¾suóM“@µö‰h³ênÎÓª{C<äÀPâS æ7l2•ï¬;¿§ÁpËBãíLUƒÈÜ[GÙOú8©1‡Âv©=Ù[ƒ`KÞ˜ˆ8¦ ¹÷™¬)§1šN qçNn!’¹Öà%˜ÎæØ PÏÓ«aì@¿vËT©¦Ü:‹g =¥ƒÏäËÏÕzâÙ^xÖÌÔ{Åð§KhõÉ£þËî”v‚&Ó,¶Þø™Ð TÂÐ=æQ!æ—tŒåŽc©rƒ½Q ¶tàx#3¯H7«¡ñL®)ë{5Ú ¦Š3a&¸0°ÉvìêË@+ º]Ùàè’èወ¿; §-2æçN®Š›a/º¡-®œt·mòÞ>èó7UŽù}é:ÄäQ·Ä¼˜vv/é$T€.oD–w5¡=u£^9Ò©G{F¿ÞTñ’ým_5F¨ÌÝLß9¨ö|uvZ°ÛæÇÖ´‚ùÝ‚Pm‘9î(x\‰ê ·âΛa˘–ѲqÎEI=—”¤±u¡-Ê-b·)êqþÉ“B3_¿/[ÇMÁ„¸/=ÇwÉÎæ.~_©K,ygt¢Eon©Ç±6<Šše^r*0,ÛÚ5b§~ð­ŠïÈ$;Oûy‡[è™Õy/Ji8ßÐòÆ#Í¥4Ÿ¡Ìžm òÂÍ–-÷ÜCjæ9Ù¨šËHƒ<ÖUöÔ\~ÒÀ] é„±x&hVoÔ/â•Jðð·(ˬ¢ôÜ’}ÚÌvž»žÇ‚Òƒ¥`³„À3³‡÷S:O¡BçòfåµåuG]c¹;—fÙNîR³Å -ê}£Ê„ óâîÎß웑ۇŸ†åuñ×o˜–±¬9gqr»¯SýÀr‹ßùœsæ§ÛUT†Îº·Î§]–»Qrl7#ºjiÎhǦõ‚ì#ü±k› ã4”ãÒèS”~´Ü.ÆÕâvz*…ygb)úžÏãd“ï¢;ÌV®¨Ê+mùlÏ ÛØ×ûJ±;z.òÐNÓÎïSϪ.È&Ì,VHû®w0&gèϵå(`áL[›&¼ ÁóŽ< ÕO\ýY<<ý[Ëz³…­07ÆÎ;7>0þ䛟Àc³^úÜõ4¬¬ýAuÇ9üÃK€v®I,”Mî„Þzø­‰u÷§Íç Ô‘K'ͳ¹õ±ø©_†ù›XÊ=oDÇÐu‡f¶‚ÝèíLµt— ŸfÃØ.Õ –Õj*íçКæ Ïfm ZSj–è¹ÈL HÓ—©ûyÎþFïäév}‘74õ7‘œïh±ƒ7VìûiÅ•…†ÞcbÐ÷ ¨»ÿ ¹ÎæaUYk¢jòå€îJY²l³ÜÀ¾¿e—á˜Ñ2¶ù&šª.Fõ>k@ùÆã›Û¹úðï~çÒ¿u†ìÉ.gD~|ä 0{åº_eÎÞû êÆpag Ç%´Ê˺ÏJŒˆ‚yN¾Õð¶ŽÏßT§sñÍfJ.¯{G3—3WÑ…™ë‚ÆG«ä;ƒptïG¨Ac›–ÎorlöpˆNÞõ\ÁsæL:H¶Ø…~™~ ª #øµ<ÿ;þzOëÞ¾ñÏquX èn5ŠSŸ@•Ìçì–M&Ì*[:¬ÛÿÍmiC%@]¸i¨‡yaÎäÁxC±ÜògE’.É(Óߣޒ¸_»ÓÖék»} ¬·Ø¤ï–|N…¶.?¸P鑈®ØœŒ \c€J”h¼‘3Q‰¹û®wV0pÜaâóýj净$òà ã¯4iÒöô¿¢#ŽOÀ ¬„×lª›v½Ó×|d]`ÅðÑ÷¡×;6•…(©ž5ƒ-Î[=kd¾ Tè¼Ì”òM3BY« ¶M,År~Ub Dváì‚0sÒþÇÙ+Üe‘M[®)d%»ž !Ù¦yjàa¸ö“} dñ¯õ…ŽäÁ÷Ç/Y€y¡{Sjª.ŸOó¾ø¾ì¡þÔºÂäáÀ»ïWô¿æ<ÛA€h¼‰qðÅØ0 ¢{àaíGU/euû_ùA2ïà#5w~Ðñ¥w°>Uáf.¸ÞûCöú2ƒƒM¡X[GJõONÙÆM×8²¨SÚßX™+Ó‘ê#FÝfXæ m *©ƒ®4 Ô¿$A¿Ÿ‡ÆýÁ€Ã®§  ìåsgƒÕÇò~|ó9XǸ:ÓÚô‹»:©Þ*²K€\¦]P ¦} ”¬Å‡ÿ˜jI·1r ëãPÐrOôÓÔc¿Ž¡Ó.ìŠGÚhBf`aé{³EK=߯Î[kšAÁRpL8Žä>.X¾3Ü é—ÈÉç1X›ØöìŽÀ9–6lÕƒ¬ý dÑlÖ}Ú¥7<°3o'”"Ë:nt€ŒÚæoà©È”vÂõâØewF›J“#[µžÞÐøö.·ßi8wPix©ìw¢|m+ì`èx)YozËÀ<è€M­ò“”ëÌ|ÕËCͯ/aZt>•Î_¥N½Y¼£õ‚¹€.8£õ¥éæ‹ÐòÚ(gêz_Âû†w±2„¥0ZÅCwê(XÙCÇ¡ Ž‚Œä¬òf©où÷PÞŒ¶Ç½}r^wÇeê!XÒ FýûÓ…É\æÓwð?¬9)#„¿Çžß°ØôÃTQm™èdÓ¶ñ úY<µÓ>—2='Ç•{JJ%6J% ð½ÈHì'dN€çæÇç³³™`I@»ØÃÛÄ(-ünšâ-r¹6ã}õ7ýÃ4ßÉê€Õ%?Ì·‚ži/ýÜUÌHq< gq‘3…MŒ‰&[* 3¦ E­¾½ó˜ZóðID‡%÷}`®›'¹ãˆî+ ©áý3e4‡óã#ƒO¨åü¦SÖ]²¸àp&c·ªäX§Äâ³û]ÛrïÑ æP÷Y¥ÃZÖºÝ.>BÅŒ‹ø%œpïIëóŸ9lÆ<‹7wøÒB)­­QîÛ• ñ¿ÃŸ?ý,L¨›ƒ†U…c³;ôùæœfW\ºÚ‚xáŠ34[5·ñŒ[¥ÞÉe@ÛÊÇK7]Þj)þÌUÕ’¬í—89^s Œ«:X[<áéx[¹ƒ1vR¾gÅi:‹¬b8i §xö)ì<Ò)æð;ë·Hºçñë¾L2ón5·™2Ñ'!r¢œ)LÑ/3 “Üè7íƒ~:â6+åþ>M…k dD"9Ò5G­Gl;Ë`tEÖ,Óc²æ nì|„¼|Àš@‘7óIpg^º[ÿFPÉâ6“ôœÒV^(Ùm;P“Yƒ%0±5•hÄö=ã“ÝRtš‡k£Gß”lèwƒ6Ú„È·H6ÓÛ¤•Ó½EˆÝG­Fûžˆð{¼#óK_м5ñéušPýêgì¾ò‘ŠÂξóf"¶ýA‡ŒA–Á&½“M}&ÏAÓÓfÊßãÝÛ1ö ©›²KË–%„ºï­Ú×Ü€#"Í+Ç£输9v J…¼ÞûRæKÓ+Žö 'ÈÕU¦·—hMã>’7¢ýJÝYš´ !Ù¦  šÄ`]=¼šô,fL ýYÌÄ?'üö_Éð-¼œ;ÀVª—yçKZ2³U¼N…¥y½Ø­I¯†þŒ½€á%ã²×«‡ÄC]ÍŒÊB£<0ª[NtéÚŠGKYÈ: ܳo2údVÒ‹b~æ—aÝ1E&ÏFͬ¨‡2‚¢N‚{I—ÛuÚÉ;a((¶Tv9AWqñ¤Wã]A`©«¿ôJ‹-:FêåÓ·/ÖÎY àh‘lêÐbûÓeY]Â|¾ †8s7ÌäS¿¾ŸÞñ9ÀR°Cùö<Ìÿ5£¸qiëËïâDÈ3EÄ#»$¬/Óc_µ!²•Ž0ˆÎvnÖ¡l%=[ѯÜÁÚ`_Œ®~HË[aN¿Ä…Pg>{§#ku4Ÿµ•áϲGHWõIF5¼ê”àì˜,}Ýf´]gJFËgÔýp¨ 2kêÑo¥Ó u{S<9£‹>#a¿Tã`…۫愼& ù=TÐl£­ddeu Y[—È”úk•å¤m»2ÇØKY7„’oôVOÑE†|¹Ÿ7;¦íZ ßú*ú¢º“:–áËÈ8xè*¸a¯Ð¸-²é^®”;)['&öB‘›׿)ØB•\âÝ©Ö>©Ÿ1/Ú4¿¸/Ý}¿&WýB¼@á"‹zœÃ¸Ða^Ö¿¯ÚÇ)T-¦œ¥/hó.Ý×[çZêЕ¯üŠöU—KÕ’7¤"²Ùd¦!Bóþ MMĵ–ßFYÇÉÝK¥ƒïÚäUa,æ>JJŒ¨ Ñç³9½É-ør²ùÉm!¸KþàØ»ž•!­àS¨Ø‡µBú¨òßBXõÇÅEºNÞ· iT-ê4<ß·*E)ó?Ë¿ºî–×@º°¨õ }p/‚"HíPz˜¬g(ÌèŒ{w¡µõ½QiÜo§6Lú0ÀçR?˜¶Ø¬ýk¬<Vûû“S’êÍÉvô4:ýi`ß¶m«ƒ×º·q飦ö8áS¼[__¼GÄ1‹ºø0_Kn:3é[2¬3Sf|,8 µžð(’Oé5{@<à¦S—‰ëïõó±Ïû6Ê»É|ѽ^Q©i¢â/ òžr7¬o%Àøã–½g pIj´RÓ øè˜Í59ª2Ù´À‡B#w…FÒ-· ±|sȵ76¸éûn÷µWÀ­€×W†¬âõmDU 'b´3ÏÁ„1›Áâ!GEsüfoù~çóݦhðŽ,¡ÏÜé3p!‚šë~³/2Þ7\¥‹úû Árªa3›W€Ö,.;ÅKÝ!ÃûÃN¤¨v³èX¾p~>rÛŒ'cRÏ2Nâ'U+ùó$­³0í´åôOZ6»Â=i3?|¥[ÐÌòÌüµˆmwYº±Îø¡ÎÛ†«qˆñìýÌÔG¢?i+rV¤3Äõ}dÙhŽ]•æÄ/åR˜ ¾(ž,0Zñ¦çQ`³P~Ø`ÚeÌû°y¹ £Õ ž‚cº‹P£Üy·­šAÏŽ¦„Æcóë¶¡Ø HêÁ´CÀ~€¯ÍFk5ÍuQ[”iÀ ßD>ú‰\gÞO«C½QY99ΰù8Öd ê XdÞë)ѵÝ5UÜ‹µš7RÝó]í0*Ûĸ¬{`uEý;<ÑI:J4³AÖ.8E³½æ·Ô»i&¬IÑ™¿^0mû¸ïR(6E,_UPq…Óc}“„€ï¾~±Ý!·´•È”oµÎŸ2Æ”]v;Ú/ÊÈj<¤8j2;^»A}¤¶ºQð_¹¸ü¥‰áQ¸Œ­W[ŠF½g°´ã¦:«ugå,ò”kÙ:BPn ^2+W#&œ‹) êÃMµâ|ù×ED˦±eì›’ÌÊ’\%éÛgè?KÇÄÇJ³&„y—&O¥{3*¸ÎùŒ+ ÏÒùÖ}¤»•a3{Ð/Ýßw.ðÃгĭEí Ù›v ¾íŒúþ…9ÒO¸¶¹f§¸g§iÛÑQ<Úç{Ûï}1·0©Ç\ f®![(Õ±kÅÞ9‘+[1.é±olÇ][qÿLaXr¸;X£rއ…QrUü¼¨ö"Ô3!ËîP[Ûϳ(~Ha™qn ¹…VwëO …vŒök·Ï“ß@…(•ëz÷çÒw·pãŸÙòKß9¸;˜}9ÏomˆÎJ`N(u¶„Ã/R‘Ty¡¯¼ÊdùƒDÚXnðjø$MὸÈ}Ú,ÿôtBûJ—÷¯>˜ÓAzˆ€]‘Šr×#fܨ"_Íl÷H3’*µ_;™Îݨ6¬Ö™~^?®x?- ?YòV Ž/†ú–¼c–ÕBáý(qá,ý.õƒñ4 çÔwD¡tNÅÜúæAÅb6Œ ;Â[ŠI?ZÓ˜ÀHS!%´Ÿú«†÷—5f¿›=2$ˆOwE7 t&Ðt° öÙñ¯—&ùâSÑè«N/mm–¤ž€[X?ümX¹Í2EL¸…Ð7À­‹y%ŸéRe‘69e¡z~Îêe.iGéøð‡&CVír¯!õÜa /É_†FàæsdÕÒÝSøý§~ŠZÜîôÑ/ŽrÃ)^Ídœ“:Ìë¹”!Ÿ¦×f–.¡•Û÷'½0£s+çVJ¥¶zÜfb]¯½¢Ý×íô;èÀp:uêÜlj4䶺g…?ÜÛÞÿ¥t|½£ë3¹àǵ=[JîYÉÝü\‰3¡:÷!w–L„š¼¼`¦âi%A/~{ÌKQåX¨^¬‚þ’-q¨ðŽ—G×Ôü2M†o„ƒ0gMˆÝ³lÖ)³ÚåÍþð>käûn‘xÁz]Pþrþã_ý”ùXóO-ì Ò(+ÑäÐçiPå­QÅLÉ ãŸk “~x ¦«zR!¾DxT¿ÒC‰¡Û=8;ÉÃÂ"ûÍVXZEêFd¼>bà«‘Úz –’tÿ]ÖoŒƒ1­Å–Ùm'ï­'™Þ²t(¹åXüGTà3ÆøZ@Õb-Yö¦êɰ¶Â%\ã.æcŸƒjÓš6¬’Œ0ýý‹­TÇ?r2ȆÀúW¶=r{â{º½½ö6‹Å—x};“c|—MnÏÐÿHÛ E„Œ!qJ œ¾¡¯×c@5J·»]ÁY¸ÅÝàGý óÐDrÒŸ‡~¢ß]| -kƒáøÝ­Âmú%Ñ;“[×.`Áføà·Óƒô6‰<ÂbæÄÉFXôõaîmvkß§9”ò€ÑPÎ+pg±C¹¡B)rΣËÔ%‚JÊÌhÚÌ‚ßA4XåŽõŽ÷Ôí¼ u6ÁPúÏÕ'w¸šðpØUrÏБþˆðòÅ£§:`à 0¸¡çŶ¨÷óÚcýÓ*fiá»ý2/ßžpÿò¤ Z•¤GÔì9krCF=O0B˜®sãBÉÜ5«¢xcÛ »6ÞÉÊ¥åz^œ~ƒ súyç\#Êr²ƒ›=“~±êÂc#‚ÝŸp ·ÿžþœ¹e/Ԕظ¥¢¹”ІùÈ(ÿ´gû(9¶£æŠlS@ùæïÍ ò:»Bô$™‰ÕŒCJõ¡W¿WBp6m0 Â?Ó‡cUëPŸ¢,[à%²jµ§;ÈþàÛÍ}Z¥Ev£J6Ï©ÝahRAUV|Õî3=þƒM8Ù¾oÂŒHeKCù3ùŽ2áŠEˆK^öT=¡}k]ð'ËvjÊý„–b5QIóuê»ÏŒ?§¸é4ë4Y‘Bè•¿3ò/EâÓoÉL¢jM+m¡èßýùS¾{yyŸ“X¯˜tCOç=ZŽ’èÛ—íÿš¹î›Åí;׫E-â^H*ú‡Ío^¸9i–å’uc!­xhtòÓÇL9¯·”n÷8ïˆZ©$÷L{ðË,ÉÈ>$XSG9 ˜ëöù 0ZTrJ½|xü.„-˯| u¶ùéÅãTù8ó!ígë¡ ùžN‹÷Ì Î€óY*g§ŒÚº» Ç%l„:ïBÞTÇZ•Q*3Íâ¿|xOöÒ¹-hÎ÷hy²îf–B½Lõ~ê"ÿ^s²($ ÝÝ”ÙÈž{wü-ÖΙÒË$Ë,BŸH1$ƒ]¾¾£éezY[=‚ÚuÛ !ƒÈàidïÌÈsðЫ‹œz ´ ï»vœªoWI\`ÀÜZ"Ï·61mìQ1Hù]¥IcÞ·º…ˆ[Î÷ûŽùÖ˜ä 1—Avÿš*e}q̳r6¨¦ØÓ7¶ç†oÖs;â¦Ï….|²n¡ÔUÕ›®Õ\?£@›œ‡×Õª()¾ Þg¿‹Â¾Ú^ðéúåïF3G7vœ€ŽH¶ŸÐ6ûR@ž7ôMÕkã*õàš^z_~mk¢½wsN¦µOȃºñ¹ ï°5y6À¸‡ÊM7ÇŸ×jAss­Æ·o°"÷úʲÜhóÞ;´xÇÆµô¯QÞƒ ·³BôW":ö¿¼¤X$Ûdܦã²uÓ´þ}XO©~ú~éÞÍðÀìŒ3Pº­Å[JÄðçž;s.-`œÀÒ}ÂJÝ›ƒaM9Kfn½TÙ5¨@äG{Zè“ߌ)zdêãÛù£g!èó‡;2D Š:z3_L/Ûþœœ®Pœ´ ªs”\.ÕÄb>êp["â*8Ä=;—¡QØá9qyëE¥*Jʦ°£ˆð9 e‹ÔIú³êë)P²«ÄÓö/Þ™¯¹9v N§÷g#’’  Y„%%ÅÃø6~JÿÛËxÛ›À@¹çº´ y¯ -‘6æRh.osŸP†Pè}ëDž”Ly•ÏCKslƒª¦ êayË3V@œ¡V-åùÃ@vb}[ZI2åæ8áÉë§û«ÁØ{|(ÊrÙm4öOäžî=!mJaÝqßxy;§‚xØd´¥æöác½«Ëlžlºfµ~µC4 É5¢—5[YµÕåkh×uäY²û|ùL$eéò?ºÐ=å£Üù 5x‚NÌb L )æq+¬Õ{´¹,Ôh1Rèu/ÖÖxBˆ1[ŽlÊËáÝtK3>1C>ÉØö[•ëðÄß™íDŸÃRFP€û©ûv.gx™Vèñ[¥CӀØMæ!ÒÊœq„æýÅ[9073’¬Ò½sõ¸]‘½˜R)«ds¦Â€g©j£÷üñ(ã ¢ç|‡ä«A3aq÷‚ü2V˜ír#ðáný¯®~áœC2}+zÚ”!4“¬Ýä‘üÕ§l lnn®OVÏŽÃlH]]â›­žê7Ur¯ì:Q//'}õÊr`åˆï¬íX^`–Dûâƒ}Öõä*);0dM¯>õˆ%·øA”BÂC É×¶]‚ ø-·ÙB‡æ~ûæ~#Zhı½Ÿöµíøöqƒ ˉ'ú©â1¡¤ÔPŸXö‘Ô‹[ý5EhŒ†OaS¬¦¦6»6¿£ ÔÖt8)¼M{á¹OˆYðÃè³8çZhÆÓï´ãAaYL7nüš T•ŽºphÆñ :„ª:)yV˽A`¤Þ_n ,Q>)IZž…©½R¼„iy>†rRË`éøÙÉuóæ Léþl ûƒf”뇶¦–Ü™áVï,WhMÔ8ÁÖ¸&°¤f…ü åÝlÐÏuŸC;t¦Ù_S´*²SoÁÆàG·šÆ`…TÇômó²-—Y°0¼+‹í‰×MÆOt6!Î)dç•?Í¿“9äÄ»Ä+V~Þ Ùbõ¦€ŒJ&|MR€w*ͨÀõ¯…åº?ôõi§*®^Äž[!äfÁ ƒ/ÙÌáEn H+äÍŸ†F9 º÷Ðë¸Ù"w9®•;Þ®ñÝ~Ô[´CsNw$¶t€H‰ÚQ ˆ*¶AüÈ?@•Ò‰ª² ”ñ˜&ÊZ‰B^mrK@YœÇªÍK²xª¹)Æ«R§+n¢ÆfRª,™å­ÿÊ—Íý.ßo9yJ¶{…ÇGG9ë^æZ(åæ˜hg¬‘+/·I*E¶déÉðDµ¹€òõòº¯9)>d©ûo4úŒØ´óõõ½|˜;Tê>KO#í‘s£0$«×ö9¸¬p&ªÅí’cì7ˆòYÛÜ<ðÙ˜¸Å$åÊÏ„;°D^Óí_ìëhUBÌ“¦¤“È­nlS2ð¾gaf®d:®¸Œgí»créÄbÓ6 ä ›¢>([>(”²jwßž˜7ëн¥¬ì˜ Ë-ÿ„³²Ú¡¤ lؘ©«x©êÛÚ¬tï.šÁDòøkÌ9`w’@‹hèâ¡ÑM£¯šõÒÜa6¢ Ð3w·Y¼ÞűaÉòÎ:,s޹Z¼è·Ûª ¢ç¨r‚~÷¤Ê~æf ÞüZ½ŠzÃ=yKéС{ò ;iFÊeÛصtVJŠwDN®"Žpr[4Lc¹Ýç’…·)cÎPŒñ‘¶øbÞÚZSBKûÜa®óí`ÿã¨;ƈ%.kØŒÐx°=í=¶YÄy—4gŸø~ÏŒ‚ä~xÒÿCÑŒ3¾A\ÂßήD¸|L ÈòýÔiòMËrYÂÝ$nü´;@Ês¡ÐVcŒ*š ׯÚË•|^·9³¡ñp¬pÊ;·*k¤¼$/Ò%ç:´s¬0KG-s•y㇭®èp`_æ» ÷³Eu7ç%: á¯9Ÿ)Þ>û‚)pN•*À(–ä* ûnͤìNoîK–»ÎÖßk%ËÏ|oŽÚ=ÐfÕí^”òͱuÉòXdl¢Èò­ÚùX¥½5ºZÍZ„ÿl?ä—»m,……®g4—Üìwšk’a´òoâ Ò‘µ²W¤õ5-§†*5‰LÅ¥‰Uá§œÜðM²5Ï›èpþZý «}(Ùûg¥êÀ»E²-¤Tžg DZ ((HíÚI÷L;WßúðᩬµÝ€kË´dª˜v”$ýî³å;&Øjvylûb1²»œa*·P+”n}1o¬˜׈þE©pèó±8ãEƒã(oðâQbß'ûïlÓù¢X0ÝøÅ?›UÑmêd™ ˜ö‡ÖÓ4PuÙ*ž.ÞŲ̈qp–ë>‹Ï–(m ¸óí+P)ÿÄ}@dPw~ÊOÙ©Ü“4ëni}Zi’Ë÷ÍAËÚ‚,&ËmTLA.€%ÛþL—îëÝ6ëTÕFû]ã92çL™}†Én²ö jêß´ï‚k§Ç܃ür‚@^c ¨ðXîÊvë!Í@GALIVóð[:³µƒeÞk iKoE‰S %dFÄüFíȵí4eò†Œ»iÓõÞEwÈà]VñFFêÓðcà·R,ôÖm’&­é´: ñ7c$Ñ4Ž|m´·²RÌós|Žõ¬ÿÅcÉv¸à¼³Ò'üXýbññäeFœf+ÉË‚¢i_†ž ¤R 0­zú”1bô:—¦Æõå=—<å1V·„ÎÀ?÷P¶jÚwß ùî9œ-,‡¿ÙÎcò~~]&BV)å£vér80õ½e™iÕà9 rm‹¤Î¤î\C¡ØŽsc›jà ìW«½ëi¥ øQRÀ¹t˜©ÿk-p£¬#o䯷8qGߤڙJ;ozAVö7\»¶×Þg¹=þ0ß ¥ÿjÇ Î]íp|gUçþ©ª8óy¼¹^? # keUê=¯ù Šüä•ÐñãXBQ÷ÁVîÝïEIM¤¾ l÷ÙFü3%u,t‡ h^QW€h2Åí}]Rd\lâÛ\É•V¶ÏI-z;¶¯$½kqßgj–¦ÄÍèê(Øx£\Z¿eŸ4ÉY<דéÐ.­ aKêÚ¯J(¸Oßf›±üü`Òï÷ƒÅ]$õ‘hW zÑ7>W@­¨ýi´èÆiÙœ­Ój”ͶWt­)wÙH†Ÿ èm_é´‡®t,H°ö|Ù—ïØõ¯™º3–«ãÒxo{IQXƒ vø%¦sÇû#/2¬='DŒu 3@ZÍ"Âi_]¡3}€ F ÄŘüXT¼•èWÎ'VÍÀ1¦²Ë½O˜b«úï[ ZaÓ÷ ô‡6K^Øâ´‹Í Ó{§ÁEà°Hº‰NcŸµÓìºO’Ë­K¸›…füÉ7iO"±ß‹IóŠr3Hw^~ÚÂÅÃÜD]FÒØL³¼rE[‚Ÿ¤ôÒB:_/Jä… ÞIÅg¼p£hÚFޕěúLþÜ’Jì6¯¯[.jl)mYQ%Ò šê˜µ# [±WVUÂ)$àòrÒÑѱýö|,qKõ`‡´D«|ÒÜ€Fw+®šÖæ/ŠŠÖK¼#(# iÄ9R¤xÜ|ùÍ¡/㟯ê­LlTµ8WOųüÌRùDQ“ÂɆ9 ãñZº—Nç™ÚÊHòÇÇc‰Â×’oÉ*ÇÁxÄ'°CÎÛ•ÑEŹcÆÌ:vR®37ÛÛ¼B0ž™:ÿk 5¶”Ø?@ûø„n„H áX2Ä™ bíËK›– hý®![µ]5x¼ì¸åquš¤ËÛ®h¡¾¾ ¹ñäc¾µÓ9qÔŽÂýF  †ûtF$¶r'mÛ(B̸Lð“=D(äØÖ¬Ñ{n\0´="U F8°v íÕh ÓÑG ‚½›‹Ý# ZßjŒ«5§¼·_!ýiªÌ’÷Óƒ÷¬-cƒKÐf‚ÇëiëÆ5#l†g 0æŸVô+âþY±àbLu¢+‡ ÚÙ"yÊÑÿôÙ–ùA TrOzhêô\î 10rs;íÊÊ*JØå¾L³æ^÷\Ú3º¨Ovä¨@¸ÅÅÍ©`ñ-E3^±5òWO~'¥¢‰I_Ñ9¨(ŒîÚˆ5^´èï'!È¡5…j¤¨&úìÀªGï„Z#—éÊèѱVø{!ï­63rìûd#H$óp ?¼I1XqZØК¢\Ÿ,5£FŽ÷ã޹WÆrˆ^Àj  rsÂ@Ò3»­È]ÙNËwnÂzˆM:NõY:å àÍO„»Ìï§5ÆMóÑíÓµÁЇvÅãíÚÄß=ÖO·+M»²UE -‚@tŠ/\Jn|—Üòø:ŽÉù%©f¼ìœǵ•ʳ0â4ÿ’¿‘¦³ìjJfÒ¯ž/¹Î¬‡hT:ͱ?=çÈ!’ÄO̎¾'ÖU}Bá·¶¶²i ‰Í•p‹œŸñ™á8—Ž(¨Ý¼yìÜIúóQ÷Öà;B‹º”Yb‡¯¼PtóMgÜo.÷ßбÏQ–¸¤mti¬F%Àö[9[¥nI|fô‚/R£K bÛ ùKl”ñc øb] õFt¯ccÌÁqìøbÌè¢~zÌuº6'Ð}ÀH{Ø{ø½Ó‘3=ÐK¬ìªö³Yì—ßAû¶Õ²Ú_{58+g>¦ö:ÅRK–á«×JV6µBW4…L°®bÀô±q§½•5­|N¢Ùð‚»bϵÀß \Áë{Mœ[ç.Ò¿»ûêæ,Nª[óXcñBä)dgÀ×zòLÜÆ3O¾Ÿµ-£€ÒtvnÍÔ G®]ã?l°0Óiï5ŒƒÂÛOLœ¼3vNÖéñ(”õÅv$Àû—øø‚…hpNPÖÓåZ¥À“…šx[lU2Ì@çKºœo©”çïçvYzóŽeìp¡fÿþ ™ƒëÑcb¼É¸ú…üS¶‘Õö¾?Æ-—âôš ¬ÏàeÄ­ÎQ7þF†ÊŘPH*­ô ²§€ß¸ò.÷rÑê˜NÏŽ§CCÄ¥ŸB(”!Ó¾C^J9æÓX$_(ÌQ†¾±„ Jó³Scù–rXýiC 4EuŽÌ”ðvF©›é&±ë_t*ÚçV¼i•v g"§!/êÊ¿[w~L×òâ\-…uÉÉòsÕôš(2}ËU*™ÿ©øI"íÇë!ˆâ'/RD¬Š|I[îNÆ{ÙiüfÂ+¿bŒÞô€¨W—ៃ‚š®aÕ§0©ËùCHs‡Y§É¸áF»î&V¸TØçyCLÖ‚‚þæAMšŸ`qiçÀ@ôÆ$‹l^Ýnt¾HÉÎå˜ÁE>y¢1] Z!9Xli¥?+ëÍ™F9÷Ĉ£/vˆPhÆe$퇉Ÿ‘û#4v?—I›ìËO oÍÊîHg’#;ZGè¡Fr’ó0-ÃÏIááü¾Ãe"vzÏ5¸BÊ«dv§l^¶’t9m9¼¿fWY÷ ¸®n£“PuÓ)·cÎ%¡ G5pÜvK,W84îž¹]E:eÞ“¼ô,•ÄZN^QÉy¢)[ˆ·VHïp»v55é¡ñáR qm(?ÔÔ¿ÊüòóÙ@мœ÷aŒ 5·Ù™a&iq6¶¶Seà3\ uRï Mª‰í¨Ñ¾Bð®Nü¤Âß>… é÷–E몫…CP€=Ã¥ŽsŒ—µü9ÖßTJBá5t6%Kùøà•¾Œ“ß½i¹C)™fl#°šèsà‹«²ŠJ¾yow^þ³B²=Xd›«2{<)šâºMÛí@Á€Ÿ›×ºYø´„ž{fõË®™•t*±'øÜÍÙ^[<Ðöþ/Á¨…GûS€ïÆG$¤uÚC­ÔÎjéŸÅåêÖÝdIÿçÂó‰øJ‚Z¼gÙôêÁ×nëg| Ä%õëJ."Èâ‘ )b_ɸérq­«Ù#,ÀÝiĸ/ÖÔÔÕ ´‘ØÞ”ó*µ½)w®žöÈ—$)Hïé$ᆵ‘•± ˜£…‰ÓtûÉ:ÛüèÄa¸`y¥'•C̶ç®bµ–W•U B»uIyçgJ€Ëyá-V@ˆ qmX `¤ÔAÕ«xÅ´-¨%rÂ5ýÝ—‘v1,èÅåãª@[}¦s2£ï"‡cw aঠk“-Ÿ–ÅZóqª6/¢ÖÕ¶và [䆥]‰òTîÛÏ´ŒU‰@=6 |"iãíÍsÅF¢hÁ±yy¨ä%þU;?:RæˆEæmbˆ:P_o_RŠ'2!ÿ’I3D¼–ÝØ‹®©È‘ý“J"Ú©“¥¨pþ÷TÛÈó2Ë*Q³V^¿žÁ–nqŽ Qû§×3F ‰!wXz)¢ËÊÖ…šáå´¸Sã:»œ,ÿ™&ãi« aØ,¡MŠa¼!Ka^í2mÛMÙt8ŸÝ a#ú@£cnø)ÉD¸¿r^¥ù.¶°F íÕvj™\0Tï±§7xãÀ½LÁýû¡€7SœN3å³é=éâ;$ËÌ}7ì+÷ÔÔýá_š†.ÜÇp »-@cc]9œ˜ÿ Ð#rõ¼ù$`@³Œoé Àæ ¸d#oÒQ¬×ØmD8«,:¦»f^ZR¯#`ûàÙFNÍñQýãOàuok{ËâÆëÄ^¸?¦l—ž[q^A÷a-~ éùsPt¹k¶;¼±[èΫ…¼ 2Ó VuHÖ £têh‘Átg…åu⊠5~Ô#…Ü&´®Pá€Eö>÷—t«6Ïta6éd©rüð•-›yƒ)ܳ“!#¢zè†_kÓX+¯3dq­¾¾~ãÇTqDÐE¼EçcDÞE§Õö¦¢ËkZ!À¥­Ë–!n¯õF`viH–þCr°ð´ó1…¦û-òG,ߺšÏ4=(‹NìÉ2Ó{Úq–Ø[Yvð±$‚@fFºÀõrŸ:Z!dØ,¥¿ðìÛ~­Ióx¦¥§º¥•q£ä~RÞc,û@Ó‘bYŒ¸¦ý}~¬çK\VÊÆ®5ß À…€]lGÝB»¤ª©6A’ .÷¤ãöðp8|õìÌ=jL7%ÉçÎâF¬¶s[Üè»r'íùf †°1Ù ïÆ¦çˆâ¶†¼ºŸËSé‡\Œ×·Q©×ìL߯]9¡!²¸êÐ )æWŒgÀ½üß§ý‹ â#©{˶Kw‰«9+à àæTÕ¹‹G’úæ ü††´Ig’uÉZ;v ‚¬Tä77ÛÜ1? ]—™5qaè`dí§ßStÀ¦ãÊ!RÑãÑûÏl‹Ïíff²¦Wu»0• É‘vAÉv³0×hFš›_×Lškæ•l’âWÃçeÄÏ=›–Àoà¬^Ó<±kÖé+­¯Îí7ì@ ͸–F¥iÕq ‰tKÇ}~-Úw9ãUÙ†"’'ÜŠ{s/šNIŒÀž¦+Q*92~ÎÍ ƒû]<”<ÏÖ{Ó¯¸¾ÕJÈTÊî¦Mºx8ïÆï!]™4¤,²cKꨜ—UÁû§}­Öø%äð¡£­)³ØIá°å;òg ÊÑu]—‚te8^ÉÜÜ,‘*fGÚi3r {‰nô«ìø9©ÉQú Ç~¥:’,‚ÿ 4ò8t¬’ÖqÚD|m7Ëoʼ­>#|ú EPÒºø[Òyâ}YýáÓë,Ø›IƒwNSÜx)¤,˜¼§3ü5þ„50‘È’æª vM¸c©´ Ö¡O®/1ÕΓ·Mj\«nº_ øè*>ÓÁÕVN¡ò*ù ¤óÍÞNÈÕ¡ÊhºŒçokñ>\”±ÔJÕÅ9ŠîêŽe‘»Ú“ú&¸]8±‡R›‡OÙ·)“¶Ãl–n@)Î=7>­‡®¢ª(Iì\Ô§n­7ufnjRq){½1^+ZÀ×ÕJ¼z7&+\Òµ¡]Ç~6‚Dº‡’¼”²¨ðÔ iøàòj¦½gÚy³ªÆ#Ù§ÜÅýqЈªº}ѼiÍEŸ oo š„cÝ>ò™‰\Nëv‡4ÂëdJ–9/UfC¡è1;þ¥é¥çÆgÄîæßÔöx~ ?¶ùoH»f1h“’špÝoŽ;«pL´Gî>}Ƈ‹Ü/ì{‰úŒÝl>{ñp ÄÕúFxO:ÑqHõ*kQžtj9ßÖ£³æŒÅÅ,: ÑÙ~.N¼éaýò´€qèM h^z„eÞ{Õye›¾M:  :åFûx(¤Ÿéô²èW›Ž9“Z»KŠD‰òÜ¡°!e2yùùå3Í—)qöí/ˆ“8ë ðÅÇ»¤9c*šÍgžnŸì4ýÀ¡%Þ9FrËe÷"ϵ ƒo¤/M²µ~è”çK±}¡>Mh ^@ûó‘nÞɦ>£h>M¤b[ª,+9á:rðkÒ·Ç”ìòñ›n0¿ÛDW·Ú™\'yï|zwÐI¸Óúž71špñxlW"4ŸçKôW+YåfàÏ$!&R Áõ'‹‰áné 3Xk´Á±º€à·L:°U?Q+b§öy/÷›‚ð}ÊÓ«c:ﹸ¸gÎ\¥«É©×nÉJj ¥õîò=LOu¡IËÒ8¾AºÁ‡¸Àå~ˆT\#¶<0$‹R¶2þöØöžÏ\k1ñXåÓVZM›H˜® §³H}Ã’Þ¿ÇBš“ïVçQÿÉÅTy…tßUsxË›ªEÂÕïTÆæ ûsžIó0ÙùSÝxH fzI¢Æå”JÅQlø­á'd€l¿+Åv 6W¢êðï^à%‡QVÜB±O8ˆ88;Ð;³8çбŽúÓPO;úøNB'³ùþ\ Ùú©\òòAÛ³Ž²$K·}w›â÷“Ë> C›F:£Å¾?CFíø•50`ƒ¸†KÿR,æ“öIK™4ïÞ(y¢a%có~ùúO¶ª©Ï”YMâ€11LžØ?1ÙŸ#ÝvkïÕ)ÂÂ>u#—X«Ã ЪN:p£Ýà®K¶ h›t–$DRç3òUý’ßÞ©•¿–TJË>xÊEœQöÓalÚ`>â·ì7W¢‰cð×›¬\Ây‰‚^„!(ˆÍ#0§}¢Ûvp!Žšd¨U€_)Kˆ:óiŠ«óV§ÉYÞ=½rU^‰|xe»Ã€+þC bÑy€rš…ä´{ÅÒ ÿ%Wé^@,þ¯é{`÷¢e¯„ÓÝ#‘<óð«NæÉ Õœÿ8ÒBö/™€LΦm\ ]ÅD`x¢©£O#­lüE«`%éFM~¯)²x…¹¨xSC¢.Ф{ß6þ!aÐi6•wŽÂù^zP®/ž˸õPr©ŸÆ?§£ñ·ü`V¼ÅdŸ^òw£ û¥ÁÓîÒ]VõüEÒÓ»çþŸJ6%(ʳ˜’Ëé?€þç׿*e2@Nû‡kJÞ?‰­ã÷gÌïÑ*þ ôôõK»àl î\þY@vÓhR× òx‘9]nb|n-#Ìp=©ôç©™²ÿ{Æ4ܾ¼v ‘ˆŒñOb·æPüq˜?£¢ Ø%â°•,b‚<^쿞¾Æ Ή•HüƒñÎ|Vüû‘ÚSÍ=¼(6~æO%úm‡µS>!åZk&™ûßÛ`ÿ÷öpîÍwˆár%g,ªÙšú0ðéè&Ó+¥3ýs?äIõW¸8®FÒy˜©»¤khUJVåæUÀŸ[)O3ux…„è8±R꿎^öu‘û”ìs”Ò·(ÿÔøK¶:¥ÒÞ.(©ÔÔéíåû½ßi(òo íþr#Tù¹@®Ÿ¤*Æ sºt§îrCtNGOø?*;ä“{&Ë_Mls y…d ±kûSäÿ¤P¢&Cþ7ÒÖg…C«Ï|§”`ÒïìKv¦s§P› Ûk?)IÄwû›¥¨¹Çˆ$Q-ÝN2¼Gß’wãÏDôõáôî~=GäŠ~I✥ø77þ%ç¾ùT÷_ëÿéÛv*îÌMRB¹bÓÑ?ÕÁQ½V!°’]™"û‡Êÿ>^/o›\â¬$}•¼p*ˆÆòÔ’ÿ@<-QXæá¦€ê3Ûòs§–ü½ýý5Dýê6O"ñÓ¥î2ªg&ÕÎ^½"#Nå ØJ6µºW‚©ÊÊÊZ9_&õRyÏèKMô¹Àw'ÕÕïuT/„ o¯“Ù_¶Ú~%ÚBçìD´‡+ ‡Ê£EªË'ùº­Ø?[1œÀC…9+çj)’AŸSµ#-ÄÏ@ñy”Á#ˆ†ŸfŠDD`Ï“ÓÈIBè¥õb˨.E!õùc3÷L\Ð/J’b^Ž´r½¢#iáÕŸîŸ ¸9H™ -eø9„E¥,¬$ù9DŤ%¬Dù9$,,%llø9ÄeHÏÓz^w¹ï9{Û°?¶°]ÙïÞ·±µðvöâáæáÿ ˜¸¤¸´8LÔV\DÒ–øn!j)jM³–”’’ùW0Oû¿W•°¶!¶ûÇ8‰ïÒb’¤wa)q~IÒóoUݽ-\,<ˆý;‚µ„¥°¸4±¤•¸¨0Qr11’Œ”ˆ”°è¿õÄÆÙÎÁ•]ÕHÔ–…×?‰Ù’ž$II¢Ô’2ÒV–ÿ#â?ªäßD¶²”± 6-"%-,ÆÏackm#,B|—´=ÕÇ?‹¢êàåáíÉ~ÏÙÂÓëï¶Dµ"–·•&½[ˈØ¥±‘’øW)TÎÖì÷-üÿ^ßJÆJ\FŠXÎJÊâT¡b2’"DµHYÚœ*øŸePó°±qµ´±pù;€­­¨QX Qabgl­$­EHßÅ„mÅÿMŸZ6Ö^6DËrþBJZZ‚$ƒ˜­”¨ô)”…µ%±/Öâ¤'QaÒóïVÞÿÐ K [ ✾%¶“ ¶,ck!m-ñ¯h­¼¼=\-œÿ¡}kK"¥GÎBFF„XÁRÂZB”ô×ã"2Dmþ @ÇÙÁÇÁâïµED‰”HoKb)bi[1’‹[X’ø]ZFZXúoÒ?qpubBC«¿cX•oIlÑJêY[ˆˆ‹‹‘”)*Bä^b×DH"ýC×ÞÁÕŸ]èbáõZ‘–& „Q $Å‹‰KII1$D-meˆ˜¢Ö¤ç_1ôl,œ‰nê_þЃº‹…'»Hnþì¤Ä÷§Ä@úöo¬àpZXÈÅÆÕ[€èÎnž6Ö‚v¶ÜüÿC/çÿVÈÆÏ8Áýwg Û¿ýö7¡UuuÙmœ‰rßµñ³rö¶vpµcWvpqzxñúâaãëA4;v_/{vWßb¾?ýóüwÒóôòw¶$ýòϭĈ\àÉ´e·ó°°v°qõb¿ëÇÏîÏOlÃÚËžŸÝÞÆÁÎÞ‹çü¯Eþ¡a~v1)~v)"w±‹ˆŠü8I0 ‹ÓA öÊù&ýüob[ZxÚüsKÂiHBRú¯ÖâL4Ã(D22vâÏÏ..ÂÏ.*Æó?õØ‚(1"a?JØ=¬HšÿOBþ©~ªubaÓQrµ Ö"vÏ›h ì®§P§ªö´·±ñú3 bþ7{³Zû º¹Úq³ÿÇÇ¿ê˜Ô!iaž¶&K;K ÿŠò7 ¢o“sªA"”ø„ðµ'Z×ûaÉÿãeaù¿–æ?Ó?Á¸Zø8ØYx9]ÿí_M‚¤žG°ºzm•èj¶^ÿŠñ7q’ÙŠ„!)YBô¿Ãx á_pþ#!ò¿‹óuówõçß?8ÄİèÒ‹q¨\þ îo0b¢±Òÿÿ Ë¿€ØŸÒ㨿÷Iüù+8¸ºÚü»ùý DRœh&b¤Ñ! %.úÇIŽ ´þÆÿo@¢$Ã#‹$Q,©¿Œ§i"÷´þgÅþƒ!uIœ85±‹Š ÿ3;<³±µñ°qµ²ù «žúµ-ñƒ%Ñ×IT,È®eáE¤ZÏSW'ÑÓi£žÊÿ Dê>%úÓ:nŽ˜ŸêöO¥?+£¿üpÚ ÿ?–ü+ËÿK¹?ÿ§™{DñNÛ8íÂ)4» q°þ8Õ…¿ì¿7ú·~ñ_à‘»ðÿLüÿ?®ÿþ¡—ÿwÚøŸ×b"bRÄõŸ1—’%­ÿ$¥$ÿÏúïÿÇ›'ÚjÔIÖD­þèþ3àŒ@æyž‚xäp2™tE‡ÝêÑ3-À%ðŒsÀ«-À?è¢Ĉ:aö¥å¨ž«ßWÑó›ÚÌ ¬½£æ*²û ï-Ò2¶¹õ ð!ü—ÊÙü¯:ËD)îûÝ¿öJRr~ò†°Šhõ¼BØc ºp•WÖ;ÊgÂ/g7v;\×7v3"dšž{:­û`¼ú{š|Ð,ô„ËËÛ×ÛÛ{¦“!{ý§;΄t–`ª›{žô~Yôzž—ôz–´» ôÂß_¼¯š”bIú´ÊÊÿ_JªœûÛñË—­\?Ü™g¹Þ~öËA“nè»øíÕågǓΒ¹Û0ñ¹§*ãtîߎ0R=rî/éÍ©™™¥F;ººdyÕùųqà ½Mð:Ï*sì«+zÚ3_ž¶ˆIHûkÿ¹3¬0ÁîÛFI£ [B·`ÃGnnîøkN~±¶§â··S¬âÐ,i’.õ¦'S<ÑÑÏÒ«¤$¢¯µS'ý÷ h°¤.¦D ›Æ/U$¾šW;O–¯>‡ŒÚA÷2P8üX‰IÂr¤ð»é{8Uåd´Ûɬ|¿_?Í÷ºâbùcß)ÔÂÏhë{~³H3LêÌG×õäè·)~¼M:®[Émr+uñ›ÀàÜÒKt“š­…Yàãšû̦œJ¨6E×ã_m«Ï¢H}“ml–Þ‰õÝ-?U”‘}2báœ"ôm=gyñÇev£ØÃNðî·Âšº zcr%Ù­ó#§î¨?úûp1ŽŽk|š4]²=ÉÑ09-1îÓñïÒeeµ]ÀíõL[ð¤¢=ôâ7ãŸN)Žå-—Ç/?™_‚â‘ã%0AÉ(Ó£ƒÅW~3Å*ÖŸá ¯S#nw›¶Xb.ÐÜò-ÑäÆÎ¾°=ó[aÂïŒCF®æÑç””Ïøw Ô¼ðr(̸u‹ÆŒ†° Õè6{Ô¿f=(ª¾VÁ¾¼)uE£Ñ)xjRÅÏ?¥ûñiÉwpÓmœ0„F€÷²8ÊLÿß©0ÿe>ó#ÓŠñ€¼nÉ ß³p=³‰(lPÕfßõAØ-´ë-ÛÊ£Ò»Ó¤7ªG{ÚÒóg¯+Èîº6LN³êßÙüè$8&ä¥xúä«Dç6j`vßn®-ðüÙÍÏLz– q~ËŸŠN5t)={÷‡Ž‚¡Þ%‰’C›ûý/6IÖørîl"7¸•ìú×CìŒÖÔžÜSúÙ÷çÀW8'ñð7 É&¡*?!µÏþåÿ+Çoè1^Ìxu÷-EÓ»Û(±]0_YÍ ToøÊo‚Á'RÍ(|ÜÿI×­®CæÍ‚Œo=¼¤ß0û+Ñ¯ê ¾ èrúµÇ¸wþ^‡Ýx&µ©ßTÀ?Œ®0*£èIôõsý Uà ~nŸ>ä®bÍL.™E÷¾\«b.W™¬7»˜´]_Çy¡òþõ¯Nà§õ»Çn·—•VÒ}ÍÕÌfãBñuXF‘s€0Ž/Åï5@¯G\—y{eì{ê]?Z8׿UƒíydiXæð_-œ§Ø«/Œz"×/ Øß ýP6¬¹mBï òݲ0ÚçË’‚ÍvÏFÂâjg¤_X·Ö{–`/Ác)§ÍC¸«æ×;Nì'=50Ø[HçääòsÀ“Z• Ý[6?õzé8£mŒx»E’ºË³Lõ'À •Ȥ‰Hè‡aé¾äãF§ñÒŠÇÁ…ü¾«+ûûûÔ»„ÏìÁÏ[€ÙônT‚g}w&â÷ÎÎΟ—ëIùS]‰Ö†ÌbbL ›@£j~¯ºBåËoCŸ‚„øËº-uFžÛš^zqºè]ÿÆéß[Ó@>ã•´6Ý:½ÕJêÙý„àþz›2nG\%5&X2M¸ TÚóïcAž$ ˜hcJ1IYø »8šûô€æV*Þ~Þe¥æøÈ­ë¿ŸóÁ‡mlðïÃ:ÀÙúƒ´ÝË FIi{}rÁwiëú^ÃZ…A¤´”S Ú^ßÜ­]-Òæ >8iï´°ÞÁ<²ÏåkúôÓ–:—]Æ>¶Æ¹ñ ÎÛ^ø¯4~&—ŒzC×r¤x¯)ì¨xò‹îL·ššÛºÿºŠÃË?½ëÀ´ÛÀ ¿©ð_õJÿÅ ë4VìŸ{¶•*'OvÃfÔ®£½w¿3 q‚®á>ûù‹Õ ì S(˜.޾ m"ÅÈcé¸öãÇNÁÖERvJ+—›‚ ÈÒE…Ž•šeg"gk?p;Vm!¦ˆøÌý<§c¯&²—l–Úõ¸g?ôv%O>Ä.&»á^*”x8º;I”-Xdˆ»:jùeMN7 +ÄÙ,šŒ‰4錽¾d)ÃßIµ„¼¥ÿ–÷áã®b»9}5º±ƒ÷e†õÒçäÆ%NÊqÇ*|ׯœnÖñȨ6»µ±, 5 ¼WÞþüɧ_,-»\ã½W6ä9¤Î­PÞ9Tåßj—Y7lºÂ;üÙQp¾ì ªÞºXG;V™Ñlvå˸ecHUÁÁçÛŸ7ZNºHÛ#¬Ìð¹N?°²²â8¹°ÖÇZÕ‘õ½5w‹_›”Ÿ¶<õõ+OëLÏ¡çX&¥ÂªJÿÁ°YÀZ¾’÷½’Aûže™»pùÊ–æ ÃràgãV´)*`<äoôã{Ÿ Œ]îÍOª_º„cæI×uwçàî3îx·W¬®.PsJV¿¹+¡š‚uKŒb /ËÄûχAVlr’/ü'm’gmmã”™üÜï~nêB×õmY=Èâè¦*—ž´hãÿ™?.qy‚%(Í2Ø2ÚM3"Ó€Ð#´â…®±U)ÿ–ÚVswdI ¸bÎ} ÷Mté¤Ëðj—éHŒ†“ÉZ’(µüŒÓ:ÎÎî³C+÷øp•Ïl£RS%“}=3÷ÒÉiöâqX •Ž_«oÆ]ØÂ[¾Òô6O×½\º‹sSù¼¦ÑR[“+ ®Yµâ÷QòK¿”ŸÌÒ'Ü¢Y|¦çÞÒ)Û¨G–b™üÛðñÅ?nW 6áv»…ÛüÝÔ}çüï²ñsÔ:ëÙÒ6æ»ýoÝx¼­¼¯v9??N¬/w´–ߨÜúyÊÜEóÃÖç¶>¯£êú’E–-ä/wxãïÄN` ˜&»7?I{ÑP`Ù–"ó%Ž5 7!ï)|‹7ʺkíò·Õì%3RÞ»ÎVoÝsHj9LT”ZûGß^ ½º³sq4~‚E׎áaGi°£rƒþŠVæû'Þ uݬz˜Oh³ú]€ˆfàÉ †Øþ¥P\ÕzßnÒ¾ð§‹÷È›yu~Óú}vÇu¥Ø›)Í ã±ÇØv¤+¶B [q¼Ɔ%£dv3ÌꟄ wV¬¬æÆø&?<›hü19uRQãã– 83ë¦Ê>„D?(+yüFëÀ“ë˳b]M’ÈDqye`oãcÏ~L·¥«’ë†/(&Ý=f– ¾‰Ï:Ù/„P1¶›=¹š“t[²Uúi{Ï3-:ÎRU¶%5Vÿ¥\.š­³´Õ=&å&"nbÚ¶w=mr'qM™ôˆ©ÀÓ§Å”š?ôÑ­TÚª[1[¬\mkÇŒ¿÷ôí² ü: ˪Lz›cL{ëφ±ð݆í'«Ê†fó‰EEÓã"‘B¥/iíhÉNoU8œCä$Î>94­ì|$³–y /E¯[‰éœ^.HÚmغ˜WÃobLk\Mõ¾;‡PÑˬGJ-¤ð¶¢ç±É)G'Ò$$³Ã$å*¼©hï¥é Ïø-Ƭ·UݾìüæÐ¸Êñyšù’PðQ÷´Vªj«l©Aq‹8Ó 'Ó«TÜÝ NQ†‡ûª3 wäåÔ+ƒ·ªcfî³S|-_õ1jwùôf.Çä"ëê–Ö$æÈ&ü0qcijXABLlÄ$£šÝ¿¸Õ€‚¶W¸bK{’A†j¡?DA†óøQsüè«L7ǨòKSüZÖÉWã8ý UU¶€×ÒoƒŸ ½?à`êQ¸è¸_ ¤E˜<¼çòBXþñ<¯þÛ°m¦;Jæïå_N›st£lŽ&[(Ùp 5'÷’bÉÊ´9C5>}ߟÿ¦U}²Q­ÿm^Þá´_Ï9 Ù­©i-ŽúqtP:ùðî4KQÆ¢å)ë‰:Á‹L¿×´œW\O‘»øMÔ²î½ó#Añ&y|›±ô-ù’Ê‹F܈U0º]áYQÍ+3þ¢ø\twïãm%nš¤iºxÜ[é zåz¶Löé/¨(Åk(–ÒàÝø,Ü¥+º÷¥›[Jþ_N4†·H¹v,Ž+ú±‹Ç–@LÍÔï/¨âÉNœÒàÖ¢ðä _ÛÁ.Á*Ïýø{–›BŸšÒñ ·z}•-þÅîÕ<Ëa¾PКÿС9+Ã’“9ö“1}rÒ¢”h×·F†'šl*ái¸½÷‚“ý]^zÚ GÛ®¡Íñ<B´9îÞmd*G¿ûH>_ 3ýåäuÄÀ ~—>g¦”q~3áTì@{ÑÀpˆü©ƒ´Ú%ÌWŸ—w“y°dr`Ï=€¤]ï-TÈz`ë3þ³:“™Ó߯Vâå/à«UPF¦ÃÌ»ýy:†Ž ͤ„²:hdáˆÄÓ³ȉ:ãâÚ£2\£[lßÑ4#‹î¦­i³~Ê7&-ê'²W´Æ£ý¦R«JÎ×wïOWÿ0º…ݹdcañõdHçâó¢)eëSèÂýx­ù:ksl·²»ç°2\QÉaÇÓ8‰ç„×ùÊ~1m (Ml¹¡´TòÇÍ“m]…ƒKˆ{·ZW}?™Õ_¦¹8ܽ ‰y5êì.utU)±a£ÍÿM£…Õx0É7;‰nþF£f,³/-0 ·´ Õ‘”ßùZlÆ\µs|ùÌðŒß‰‰ïe†¨J-þÕ=ã+þ6 ü A~AëhR&{Ûv%»ûë-e*,µ³=‡—ëùésÖgË£¶‹oG[¿h®î°äë?kò&ñ7)S ÷-vèjÇ#Ù”uCfžOY*z`4Ôy{°=È4ì,„D-PÊÏ‘õ»!ï[oM'8ð¹F×Ácþ¾þ}¢žë4źm4r¿ÀY/²G¥€Ý3^¢$È«äß—z Œ/Èû–üà!¸)•Å&ÔúvÏ ¶SÞØ©BއYG®²!¦`—[y¯‚õS”bM·I9îdùò*lZÏ3¡É– >¹Â„¨a÷wBiñ5ÁØ¡ä+ç‡"|ËÆ³cÞr.tZ0–igðrüHÂfÝÚ¨}×w– +~|ð"জœ¢íeò:ˆ´…s²bÅ…XgÝíÁÑ:`?¼|·Çï¯-ν¨ÙŠíx ê$hÒí:)7®4W“ã(#ű_¼ö뫤 ÙªžžÇA¢ŒŠÞ]÷aìô7¾NP´}Õ}Øë½ìÚý;/6¢eßìÝ làM~}°*²ˆ?G¨ÿúäýÖ| 9'1´ [(2ǯ¨Îv¹Ô"LÛoÚÍ\5üf’»öÃȸiÊï ûÐø8ÿü·¼"ãð΋¸ë lŸ|__¤Wx1U«g"xMãØv‡=j3“‚\’<¼X§c&4ûÊÜSþXZ¶ÄíÇçCU™ÂäNó‚~à /¢û_‹Þ¢œÿ–) Ç±»ý‰“÷EŒ$oլ̓¸·öµÒ)\y.Æ—Ëæ˜ímË› uû:¨”ÎÓw¼ët#ƒ ùÉ…’mƾÜskj1±RYmßÝrÓÈŒ¿5¹pä|Øîl¨tƳæò ìLÛ«jß+úpEÍ%IS]LëwpñƒÛÕ`!ÊMiÌÀåƒPßÌúË+YYeŠøuÿ~üëǬäÎìW¾êªÉ0xì6²ý–‚˙ۚ å^69ÔVHÖî5Ý´¾-Î}Ñ]ÓYS½¿+ç ¿gdÆðúÛÃÚ¦óÝ| ƒ3ï)JÌ4}7]¸lbˬ+)9o¹¼:çd?>pQ=°A‡h¾c8‹‰ œ ´¸Õºå|Å…ëÆuhnâŸȀRGØËÈÇŸTÒmrD79è‚Tª #ÌV!ñ†fJ×/ê¥eôX±æ.xìãQÁÕ;‚#xù¢Y"ñNöËÚyÕh öáÈ2²=b†EKFŸò8ÌÜÕY‘’r1¿o{ä÷Ö7(ÒÁ¼§^V¾$r+tëqpSBR¶”ã {óH˜ž×bl„ÁÔkð:×*Å“[ :ºW>?-ÎüTÑNZt½"¿¾fÙ J™ÉE{oS£XÓÊ â¦ôѶ±mãEÍùÚ Å D8ê';HMGÚÝg|G*µ8Ýé£OÏÑ‚ÞOÙÜÿùú>ŸÒ^¦¼´‡:“¹h’—ÁŒ|[ùµ+(ÎÙ[Ý¢/s{ÆU’¶<3vðrí×Õg6á;o¿& ¼Îãða FLoÝp'å6ß ×¿¾ÛÞSK’ÄLEXÛvèhìÞé¦A¯«Ü­_¿Ýh2þÓ‡¯Žì¬ÄÚ³€¡ž*ÍoHµ’)åiq ™Å©-&ªùlð¬µ÷™\ÕÎg¯_(kT–‡“œª˜Æ~µì¤™èP šÎ_W°„h¡1&làU¯ŒüŠºPïëÎkìYúo|ÅÙI;A;ÂÏÌi. $ê”]m†Å>:™†’0»(åIذ Õ@þ¾V'‘'2£ô 9ñæŒù8þ^‰ê."/ËìþàëwµÓæg‚kf4Æ1u-ÑÃé=znžn}ÃAZ³Û®•Xw¹ NÁ Yº»­h PðÆn¸Yˆ> z‘×\ÏÆ›#²­ŽÃÿ†’40ªçÛ§¡ìY“Çû.;G W+‡µ=wнåýUó`ë„éDðâÝ±Úø @e41E›‰ñ™I Šê¿â^ñ´Þ@ü%BÕZÿ¸ÚPÒçÎÑ·‚Úç}ïž™£³zÄô‘S4 ÿ´%m_›jüû¨³“èÛÕl7sÂ6-aû:Ö§~Vò¼ºû8-Íp”™úÔÁ;×=ÎYŽÒ2‰¡—ýë[tˆ¯„•Mni³½OãÌ7 *DÊÞ¹è9вÍò_¹›*ÿSÙýÏm4½n`¸¹‰ÎŽèY—Ý÷¸ò¾7”ªGØÞ}¶b|¢+ÊL#|JØGw½j^Õ {‹É8tép<ø³^é€ÛAƒ¶µØíпÛDÐ'¦®ñŠR6íÑ7Í0'¥1B›Ì×ZušiüÖW–ö½ƒ+æÅFc‚þ„üñ Nÿ«NCøV¯…,ï:©Vç—CnW¾˜w~­cêÊMÚ·.>—¾§ÃÿXʤ®2>¼²>ëþq%Ãû¸øën•d _ì“ÖœU~ôë5ìÚÝC>s/õšÑ[¯–·k´ë§KKÞxæ.§‡ùÃÕ@ÌZ¢; ®Ž/«æ›®C³?6²®p':!¼C»z¼â¸V£#ÏcÔ@÷p”c7g³Ž²-ú‘D¢×ŸÔ/~.3[ yA!pˆù„4‹kEÚà«?½æ¤ð©Œþ¦åØÄºädËž.²ñ±Áªim@]ZJ"‚Ôc n…l'ÛQŸ˜ê×áFI·×'V•îrâÃLÉç%©³òR—ß Òvfù û<>$Ä„‹Ú#ûtí< )c¥·ÊgYº#¼˜XÓoÏŠ‹éšß¹­Ê¯\qýµÄoÞþòøõ6Û©•cM\Fž(<+»û ø·%”w6ˆãjoÐ}&{o¯¾]ƒáG³¢ß4pzwIú3èö\WyEUIÇ4"þ/öÞ®ÉeiÇ‚±"bW"(H š € ½W¥ˆH€ÐBI@º"¨€Ø(Šô^AŠtE,€ RÄB‘&(MDþÏó$žûÞûÞïûÿ¾ÇdËììîÌìÌììî×$¡TôµïVFÑvþÛúé?ì2H®¼aÉìÒ~ý»Uø%ÄöOõCnø{øgbÏÔ][Ê™¶ ÒòžÒµÚþ€ScÕËô…jÛ¾}å.˜îQ<²FÄÚ£_AŸ‹ï‚< 7JlÃýåeªÞ:âêlx•YwØ"ò•=Ûñ[ .Ô¨ÎèÝÄuáÆæá!.¡ ?š¾´ºéÙ·ßñì¼²¹ñuîÖµ!¼.ô§È7“´/ù!"ϯüìoJ~â¶uàÒdÊÆ ¾ŽÏ0xÝÐ/B%M y>e—PxÈ-UÞzãž5-r¿æ4Ç´ÿú g1Ä–uʶÉ)<&'v÷Ï÷)/õ±ãþ×U$¨?Þû¥jýÕç T:É> —û™g䯶K½NJ{Ldç‡Gy›J8Ér›º8þáÖ)®UQIxg•b%º©Û¤Þõú£:ÂÆ_ïœúÆÊI›'øÔ)ÞumC\Ù9˰(9ßk5òWŒ8Rx:ê€"K%»—«1ååÿ¦ø]û©Ç†Ø»ößÞñ$ìýfQ^òìÎwiÞÙ\/› Oã½ù9›ä¿%ájäôú¹ƒ·!)ñØÜ¯±‚{–kKi/¸$EÛ§DÄÜ˽8Ûöæ¯dÜÌì¥J«z®3ßÕv^Ë9ˆýaó4ò°à›È=Nö·=blß™íø8Ûñ´çàÜW¾@‘ÛpQãìíµôýçX/©ß;ל{ËôömAâ§ >»+F„ '›Û?*ÇúÛ9ž|­:ÁQ›¼C× cuìðX‚âÑ+—PtÓ5‚N>Æïôp–®¯üïDFá`í2Ê¢r9¤Än.·èâú"ôã³OÉÃ"ÿ¯t’åûX¼Jm~¶)mä1™eòd²x£Æúk”[é3÷ª€žb ¼õTý§5ò>päUøÏµº$u<) 9[ô½,úv~ȤËÑÞn±6‹o<‡tjî³±æúF³^yÿ²ÙnÛ «\‘Ù¹Zš¾b_Îþ FcÿÁß¼¿;­ÃÊ:Ã)«wv(D*˜EâÔݰ˜`Å5ìM¥ b3÷‰ºî4Õ y똑ø›Aö ç@=5§Â!õ£Ÿ}Ö Q_ +~]J½Ö”¯±ã/œ1LÕ…W%õåÕæokû ;<>Ó•‹5wÎè{ÉzÃz/-÷ÈCÛIô°¯Ë¶ MRÊû#-ò:˜$¤-K?åÌÓ¾Œínj¢=Áõ܇ý/Kne¾&R£.¢øýYKÍ¥ïë‘{ŽUWëogK¸5cSí9ÌZ—6g(wçpÃó>)¾À’ª³="Q&’GžVt•G²ux°Ð™O*& Š[5ël™jû”y‘Î[ód>¿­Ûš;$'«pN±¾cCoïÄÖŽ×ß)ßvsÄ£M5Õ>µB…>ÑS,pïCž³‘sñq.ÝæÎ¢®_©W“T¦Þú>üòéaœˆú®/¶¼¿m Ö*O2¾“73n¼Ù7×i¹¿ûpäýÙ=f£Iá¶EÏ ®û°þ².ÀrÕä]Ƚy+™½Õ4c+Òó*îNùÓ‚»ïä~oÓ®;Xz8íPÉ !ŒßW‹ÒìÇ–ïr'•övÖxÔùî<{>ÃÜÑ2€Ø ÿsb*¢ýWƒ´—¸‹ý1ÀŸj¸×‹xT²}ˆÃèÒn—¬ê` M)ôñ !zÎÊ)ު펡)•ê^Ó Êµ*"µpLQawÎÒzõòÿe>ÈZ£`õS'• ûsع|)!’è9Ä÷lMv¾þºû'î¾iý•m®íÐL調Ži 7DßýñÖ^µÜº÷s„@Öè:*7®8UbœÑñ_`ìLóSÍ+€1܉UûࡼÛžfš+%£µ?Û÷TËÃÄÉýû%ænÝ9å?½ŒÍ¼ê󤼙27ú_ÅîT+Ú1öZ¿ýåÓIåœÚ&Žt#EÄí^ŽÐ\Ú¬U_©ÕC)<-ç…­j¹|`4D®}”«¢ ²oúf’ÃR©ïª~…r†¦ÈºÕh•¢“¶s? Êg³3ŽWýr2¯z07X1÷qvØy.6`ks&¦M¾¡‡Çsú]ðNm?Yi¹¾¼€ÆB㻿†Ÿ¾²ýyª|=FÅëk²fM¼Ï¦ó¡¼o?Ýä¹§¿¨¨]²åût•PYcºr—Ã{ì;±féÊ: »,®nñ*Õ ËTbHͨjh›Ý›™?ñÞ¢e½±NÛ°ãÇÇðíÏè¿0í£|[z¿V;+uÐýÂYú…üÄòÞ\ż%{GÚ¡íÒwÙìD¶ϕòEªÈã1°³«h¾TJ÷Ìh¦ö½)xyß<ÊåKÏè9×ðº=¼ØÈÍS9Ò®ÿNDµ4€–o¹Ì^~#)ø›jýÒ3þ•Óö¯ê[ûŒ·òJ—N˜\Ï1Ä·Z£=,‡Ô«Ú‡¥8N…íUy“÷¹Ž5b¯Ú‡>ìˆÌ=æÑ½ànÕGµ¼Ù†Á˜%ó71ý¹{Js½Ü_>ÁmÆ(¬^\™úÓmn”wnT­öŠ2Wó… •¼ÝÉ£ú öÅŽ£:!ëXF~ão[årôïŒk¯9w5}ÖªË'MÅm\w=n*$72…q259ÊõÞÕ±AïÙŸ–m[²c[ô*k"ϵñ”cç*Ù%F>hœ;Šjl+DÈÖ}œšÃ¼ôóîøXi®Êúâ ïF“‹øƒ2Ï×pu$Ð=è<>vð²}Ù¯.‘Y±cõ¾¯Ï{åidü¼ÂC¯Æ€+_—wÏxƒz9üÑ\WnIx¡¨òÑÕ42³ã©Áï¤Óíß•¥V\õ1Óº§ÉÜ,Âãéç1ø½IøÌüÁ58CüºSVuÛ®µ8=êzõÀñ·è-ñüyÔÔ­ff_j„¿ùy]Sýø`¦ÅÃFDàéw+a›V÷)mdcIΞ<ÌóW¯"LàÇæÐRb½AÝæM6g¢BÛŽËžÕŸáw‰ û04då,·FôH£ÍîC½âÂØ†w§N²®ž=°ûÉOÚ¬_ϵëXÝú9;X´?¹?¡§ÝÉÿѨ‹Éd¶(ëç—ãSƒnÃ…; ‡)É&ýš2™ÔOÊÎCÍšU½3cãû’²¯·VJâõø€V·±ÈÈ~±:<­Õ§S _wÖXˆ0íÊv̰/ÑÑS˜ür˜=W_(\ž™)âx6Fî«}hM./»?m/òöËчŽö¢³Ü{¸¼¬¿]‰D–u'ö6ݶ|¾«aÕÆmlVˆ°Ÿrߢîò H0j»Òûõ#sóþ'ÅZl‚žIzw¶ènˆP¹õtëôü$mtíjÞˆªkTT~xØË¯÷æz8\æ¼Ãv‡Ý£S‹¨_uNÂÌlQ)|¦ìœ]Ò¤,%éxú…o[÷ºmzbÒp ÷åÝÖ“w­¢bF>¢XÕû¦âÌ_¹±:c?ýÎÞáRašs²-nêÞèZåíÁÊÖ7¾8v=ü >µöFtÝ·(L[×µ¤nŽÑŒ«Ù˜r‘9Y Û7Üé¬ùÜ¡ïv㟯}&jÖvR}{«g=c§Ú9ë"ôÙ°æÒAk•bÉ0ÉÒZŸ‚²Ní/™žÅµ¼3ê•óÇWŸ°`yÐyÝù\îIÍu·õï<ÔÏó šžípìÉ=þˆùù+•w~1%9‘Ž?&ö”O'öJEÅ}Úe_mï}tàëÖÑÚkwÂøJ«Dó94òg÷}$™s½?Z]¼ç¬r¶mi\ñš/²´Õ^wå9 «\.Ü ¶‰Ûx¿ªU½y:CO³š£î¨Y«{Ïýɱ=Ý’÷¥^+wßµW;ð—¢Æ”tn¨ÃÚGŽb»ÂJ©åIçÄ«¶5câ$mn÷íMŒí ×|^((P'Î¥Žyq‘Vã(,Ú‹òS,f¯÷±¸ÿtÃ=)UKèÓV{¤Ó”^M<¸×ykV‡uô¨«i%¦NŽjy\‡;ºÙ‡ÜrOôžé.ëIÕ«Üšù0øÒÐ<=Ŧ©²Ð,Š-LS1Ý¥ÎYѰŸ†&±ñéËÖj±Ä¿â8TOLã.Ï(÷Ìž>«+ºAwëÁ_ÜŒ4àkFëNjø^Ì7mÿrZNOWI-côÚ?÷=‡ÒO>F&÷ »|Ü7èßxUQ0‘bŒ­¢á›4©ŽN°bó‘ÑÛT”’·E÷HÌ/—É_gŠRVÓÐìÂIõ¨»„ä?Âûi¢oÊê¢×ê>GÕ¨)ø”{f~°ÐqãïÙÚüìÞÅ1™%Åõí©¨‡‡57î†íÜõ`”GŒ)½kbYí©ÖöM?è.kÊ=•@×ÞŒŠaðÁ ½óRLþ©ŠÅ?ån ÿ…ø$‘¢»M§ìd£ŽßÝ¢/÷¬>àÞ!¯”f¼µøÊÞ‘Îó¹ÛKdèaówɵ®Ìn;y­$]æÐûêŽf•” zعlnUïC»oc2ïÊø¤égúã¶¼ö§=!¢NŽ<£?námâáu…ûhëX4ä»àu ÁGæJú{\Ÿ™yûwnžLæp¹!BÍšT3Ã×­ßéR×3;ü%ÌàKÔN=4õ¤þ는+niÌý9ÃêÚŸ\_[™¹žÿ7:$+éß1ÙßßÜ býc,ÛpkåuÃŽêh]®këÎÐ*â¾y÷îÝ”ÃðMǰùŠíêÃ^Ÿ]'a‹3lF³þ8BCóªu¯Ô›|ó¼ —þúü*Cc³öŒ¹D›} ]/§evìg—|1ÔY´*y’Yå³V¼üå+ÜT ý_ßÚòÙÜ®¢b›•vÚvy&ÏFkï6h÷Áüš«¯FœÛ§“õút6Ü<¼ÿÖ­[—lf$ÐíÓ˜¬!f=. ¦ÞÑ ){V±m”Ð ë²çØí=wj·dŸ]Zð…(Ï—>Ïù^­ï‘X¯$ñÀ:FV7„[ÇÉ SkæX?­Å Ù·ùgÚp-M§S5§ub´kûØwpÒÐ\ø fÚ覣›®ÖÝÃ\Píc»õi±Ÿduã+h‡w:™ÄjsbÍ~T~˜ÓÊifš-¿/Ìç¿`ŠLë/>ÆQƒêsð'n¼„7¹¢ ê äªäË·Yš(a6V ½A†®‘| ^qÑm•–fVòŠÃoÃcó-u‚D¹ÏÆÕôÜ[’×X-î:H‰áÝäøYP×öN6ĉ6bÞœ³«SÚjü>ϵp¬øXƒ#t¼˜MtAy.γ}o~ÓeMÏÄß9·!tÖN‚³V÷† ªo\*ˆ۵ѽ6\O|Ù¿Ú H{ »èkù$ëñE¦§s·Õg%yê|÷6Î=µ©ÏWmßLCsަýyT—€?ïàݧqQšàM¹'¯C±Æzziï{vʪ\Q•R½ªi!·±¸ïýd.^¿Ãùs>¦Ã}½ Û›õ M_h†mnœÔñ§!SåÖ-Ñ6[L³å5j¯Ü]«»ýì.½[¼:Òooçg~œ+üæYV_Ï tó‹’ž±éø›dýåòÄýמæë· Î? %ô— çv]¡R˜e콨¨ëˆµJÁìiþt žtéjÞ Ú±>:»´Eæ ?ªÉ´âoµÔUÚûßÝóórÎAöX¤•fKåP»CÐÙF¡}q–Nîî%pï4Õ¾¡ég}´?äGJÔÐñDR¸U-«qê^‰ÇQ¹û§ÆÚ{NmTœ5öl¹Ãý6Ió‘ýörí·Ì“AÞ:9ªœ\io¥±â—;Æᓉ,)–,){,cµzŠf"b”ÆnT3J¹Ìõ$r°T䬯«)÷Õ-èdx|Ô¦XmÎ|H’Nv{±¬×k×óT †fròµšî?¾‡X#F¯A[íïO—VTû-…QKø[Í}ß4~QQý† È™s‘1þ® .k~ßaOÚzš†æMú…êmêhɀߧÙJçÊ5N©N¯”f @Ê´Ûwa‚î…õÇÞ{Àbu޶)ÇŸŽótLf:6µvÆIÍÔÔ4ÐÏÏ/᦮NaYki¶D;NäZíÐãÅ)4h·›4Í‘Vm=*£Ù:@ÇŤ•?ÃÛ?ÚðqÚhÓ¡fé¼÷_‡Æ9Y/q§Œ_cSõhhàô¼!{ ÃíEg“Òv3ë(iÝ’VsoÜ— ßhžVæ69|ëäfÑnŽ>£ÛÖt44ª <Ƈ†fsjÃEŒ ,ÞÆU¹–Jðxê6ÊÅs<JʳØt($ ضö¢ŸJä½{i…ë!ŽJñ­Î›ÐõkÒK·CÊîÏÓìÚ#•8rØPìYà{fÜš,ÎQ¨Ê¨M^™&ifœ»î—‹Ñ§Ýë©Ë…®2»ôþËé:éÄCŽø7L\@>®åÃ`ÜÁ[¿æ¶êxy÷½¯•Üp÷¹«>:}ÌF´]Š÷|á2BáD>Çtî¬oO:]§§•îZeØ‹ã™X7±àîzÁ\Õ7Ä[¿B˜J]Pï½/÷‘ ¼½ÜíjÍ)¸äNUPB\¾Äi™Ví«úÀ(]ó{ûìéø=«i^©‡›Ó®qlh.(ÕXÿqSGë_ÚšsçöHд¹ ¸_„< ãÜDzf~1çæFý’C½=ˆÏžÝ‡òÿ1t,YiNà½ü>÷×;3Õ wö|e­yò°ÁéùvçÍ"NŸaÁÊŽÞu­æÁzE^oÅ”'¡JùhÇ‚î”Y´!zuÍÉ_A¸ø9\g y'üÍY¤WÕž1Ó\"¯z1‡¶îMÛ·’™‡Ö‘¯¸–”0Me½8ÿvv»‹'®(?ééò>qçìÒª—ÑWâáߺâ^·°ôÆÆÝ~Ý\âfjAÛÔ·ßù½¦q®Å­Ýû÷†Â,WÛ7{¾.5ð;ë«sW¢ºøÏ«Q¶-nngGæ+y#ÏJ¡ñçÕ’jUJŒzÌ*7Z^g¨Ëº¾*‹|£ì!â!ñ:å"ãQÖ2=b}ä¡M«˜þøïë®G$µG]qÚ™ÁÆ­æJan,üY³Ü¯=ß· 3 ¯˜«5{vzÛx¦Õc£š·Ò:iuZŒt>KzkÑ(s¦IvX9T†ó‘Æp×ÈqzžðN¤sŸhCè“ΣP•´ ¾WuûØ { ó¹ôÔPýæ—ßÜKú Þ¦3áÚq5ÆRß[G¯uÊé¶~L‡³ÑóçÏã:ŠÃy óQô<úèãȦq‰bÃJ VŠpˆMM}ZêìäÇr !¡•lÖhÕÉUú¡m™ o¡ýéx:®8í·tºv*Cÿ:¨R]à\ŸÆÂ‚ÒâV²u@î˜T¦” wûñcy:F„Ieï)‹¼ªƒ²²íù6Êõ/p¦ ˜ýP¨8b3Ñô=~5ض¢ápRDj}£º‚M%ü±eB§ü¯xËœkÃï 8h˜¹Ng¨peɯܖpë[j]¿­·él#®-<ܦqØ5Ò•-Ÿ…k3³zÄë¼tõâ¡îòõL†QqûÞÚJ+Þá>uî0‹ŠŒNÁt'oJ›†}B™æ^î€Ð£±ò9ϰiðß:›²-UÓi•[Re•åî1™¸w;Z»c_ÙÍfUØÓ”ÊßӯΚ;ón‹yüÒ°`†'Ç(¹ËI»yL—·º»8ú"|Æ~=ÙÄqÁ<¬HàôEñ‡Õ…yíK»“Š ÓØÑÕÕÁGžÆM&ó—JjÏàmüß¿@{ÿ­õºõ)·TÂË5õ’ úM–¹nùàhI}Vªù½=ßÄ2Ò%Cv(ˆÇÒáTÞ—^%dÕ,ØèŸØ^%l6ö¥¶6xšM6Ó¶—zBD=%/±ÿHwÏ™NŒ?ðºXÛ˹õ\Riè„{S€'íç€/Ÿ &ÝŒ;Öe ½˜’îø9€a¢__SøD÷™¨+ƧÐÕúfw×j‹ËÛ5«Mˆ ðÏiÞA7ÙœèJ¹1é.¨>YûxCZÊ–€ç)ZÈÖqÅÃEÊ´o¯2éê·[ļ±)°¼Šæjµ}q}¿™‰I\ƒ9nðþŽMO}Áï*y«=^UÂ3›£¡ðŒ#[#U»P,Û–›úÅ/ûKºýÎ[¯°Ó¨ØéÙeÅpP—WÕà1.+á8Å)$”êèºMîóó½Ø ¿5E—™k·žòK ²•î21èOîÿð ÔŠÒ”Ñí£žb‰êŠ“}â“ïx®÷f×M°›¤¹ÌN´°Û'ÊØ ºoØoð™±ò`)\J´ÀÊÒµ=°Eù@ßð®0ZÙmU³UTÓã u-íëû-¼z:\ï+¾çÜi¥”¡—í4–z·~NðqrÆë=R·˜™ Ú`µåXíVÚÜ uM®Ï µUÝœ(¨k5g×hÆXÜæ0×Ùè×Ãyê`O\zºiQåƒú,•ˆî!±üÍèh2edÆÆÿh¼£ä£Å¡£W˜jn=yö+PºP1Ã0-#©è8Ò=-»\S·êì`’m0¹hÙÇŸ„ëŽ~ž’ÄY\è*øÆ<¡î«ÓínE&”чõ«žì¸[H¿«èÍTš´‹–Ã<Êù’~z þÇžwŽÆ÷‘çÔ#êè9Ù'wìK;°=J,ÕjçÇó[h«èÊ?|¤Ûá03õá,ä¯@–ž3‰n¦Æiê@}9Çó‘— 3·¨ž{ý|_Äú$ƒ“Âvw´|ÍaI—¿ü×@C|³þLùý-m³™tf·k+;V—ð;_6©>©5ì90.XOkqÙ#sŠ=œI¾ãʲoìøå½¶W{ößxß }¯ñ¨ýŸÙ%´bνÓá‰=§<§Lìðêø©9±GY6òpºµæKiŸÏíR5­¬A³ú>µ ÞÐŽç¨î¼>ŸH4›î°SÅ"(-iÈ ~½àÞûwªÇ2ñ"“µgT.¿¯ˆ Ü:r&R=lÆþ ?:0ufú¯Ú-º’™Ú’Q†f2ʳ&%8Rö8¿·¿ò<²ž&Rñ‡ä‰ä½­Éu}œ)Ö}>zÒ\»& +OåÔ®úkŸ†q±Óý±ôS:a¢ò?¾ðs}ÿúŒËûÚ„8YŸawk`‘9С¦·ï¢æèòÞS“ [ÚXcqa¸µð|Ô«qIæ–óð±[ÎQc.tÇb9­tvmÿì½E÷sgÀá#Éabïõxb£÷¼kø"_kX,Íô®A¿<œha‘7!¼ëçã¿FlÇG*Ãá«‹&BÒDíM”y4ö¼Ó~Êž¢«ô”ÝçØÛóºâjâà‚¯¡/Õ´í¤%æ¶B¿¥°VÖx“žºM~»tº!?ú©ôPFÿqOE‘HºøÊ©÷úéï§s>ÍÁ Ä€I/S@·Û¿ÏIpUå–hÙnó¡¤Õ/ÏõÊЯÇQb9Ø Ï×âgåöqV‚vÓwºt%žÙѾ¨Ð­t~wµØG9 $bÓ–`bYé9ŽM4öNãÞ¡ÌZéšˈÓêÌ*ÿðrmU|Žgv«U6=kÊ$ã¾TP¨&öŽ^y¼»õ‘½©ö%GÞµóoßYô›¤*ujÝ7ȳ”ñ9•‹ë× Œ–—ßRn~«e23.XÞ~´&ñѯHF…g¨¨íÞpÎ4€¹dd[ÜoÉ(ß(°n½½ö»ÎÅÄ e™ÓFåéheS½ªE\x…è5Ð^Ôí ÑZÅtí«²OÜòVý›u{öwÈ)ª—dénã˜r¶Ÿ »´Y,¥Ì¬öÞ;œd=tÅæmoK%“]Šý«‹viÃï2±?›€ÛÏñîÅØ†^Æm Õ's£õÝû?Þžöyê±SôTĈñÙ¨€(õæ"–öäÚÁ“ýmN†pÙ±­w3_þèˆ8ÙŠÇôFó¾‡MóâŠvú7ËÁ±²}ù¨;ïÛÄo.5tôÎ¤×øœ¾ÙwCù.íw¯í¿s~ÝöB¹Òˆx½ò"—²÷÷;‡[y»%‡Ï¤hy§1¯6SâÖQÝ»»cèµhLË/š¨²7ôÎ&<H¯TãwuXΑ7EV¡?ì3ü dÝ’zo(Zó5¹oŸƒì— .ǯ&wNôÊ?SÝÛ‚›MaÕŒn–5:[.µU7©Flß„Æÿ:Í]!ï¼å'ÕË¿e§ÔXm›°—hºh[-Äy«ÜS|Ò­ªëL«ÙæÕ° l—mÇ×G ±ùµLú·êeÏäÅ%WÝr»¾å x«pJIŒ%í7g~e\È«ÉäÍI’·À›ôi8¹Rpã:GFìã‘ ¯Tè|ø¸¥Æ6ÅǬ4`©¦- õ7oÒe«ˆýD(,sõJš‡Îï&Ûƒ÷ßÜór;{òËmÙµ×äóäp­—ÒÕZ‰O'uuJ¬[sm¹,£aÕ4ÜQ̺ÞokñM:“Rk¿7Z›ÞhzE½sxä2ûevzwÜý5Û Õ7NÒÓ Õî“4å”ÿ螢£€±SÇsžéö=yÕzcšpl"W î>zvzBH_ÐX{æe  óSƒÉ¦pçƒunkî]Äg›¸”k¼ÏêrÚ(a~ßpÇòb}šç™÷E×Ãó‘ŒZò‰Ï"ø“Ï|îWä—þp³:7Õ|ZS3Þ%ÓZÖë[CZ¹wïþ¡5½Ê^3ßC[¥UG6M¹È­Ñ`Né•4m_ã57^+Ý#Ìh^§Öîõâ Ž´)ÇïýR´åx^Ík?&%̽ øS²ÊÌ_úa•öfôYÐѬ–F“DíwwGãçv´ƒ^…Ùƒ?reÑÓs–mê Ïo#X‚¯ÉÈ9WÈùÞ ÿz^:CÏ´ó‘ÄaÇ Y@%´Vý•\¦Óyš‰×¸ìø¶Š í@›8­v°ÞÌé;îQuÜ] ÿª.òØDÖ­k¹œ¡lÏXšÎØv(Ø`‘‡N¥+TÀûœY^ŒOëħƒþŽ»‡3Þw Ñ›6‹½­AWe!Á$¶'H©èÇ[¹²½R½Z¦A^Z&m’‘K¥I¶mƒ<¤‚N÷œâ1:È-Y“T¡üÆûÚŽwß<¹ɨ!Jrë”DŒò#›Ïë´M˜÷þÖz º/ޏC‡ÉÔËŽ;|-8p¯ÈóôÓY™ƒ)’\7ï™å{«Ý­9SÛÚÎÔúj«ŠbA\l:h0êU9|Ûm!ÕěԘzFnª)¡=“#Žs÷3ðyæ‡øÁf…‒s°ùˆWÚîÀÛ|ìÇ(½¼iŸöϽ0Ñl?m½çÄÇz{8¸Tƒsnäv9µN¾`oÿäWÂ~Ét•œa¡w=µï¼–óR+,•ü«'Ò8¹H{\LÞ¨9(ç S@£›vLsQ”luî‘[|]ø¶~bÝíÝŽaE‘xU1£â’Y|Q™æEW­q‰±ã†£™^g?Ô4v±LZ7Oqøìá„ocƒÛÝÀy&miÉ}™í†Ùè0RU(éŸ_lÏ1;-9ì i¿_|gÔÃÉá§³ú¹Ç;%ö±Çx!~ÜÊÕ¥ùNª©}ôðkÛºÄ;æ†Y6oÅ´”Û¶wœ”œ´„pµâ©Ê'%l^ª#·üñuLJ{H]r+zÙ×iœ¿¯¸6ÞÜ›Öþ`=n=½éÒ<¶ê*7Ô϶¼YÓ¦ÎñÀA»ñ'[…ÅP[ž¢@$ëu1UhQnbô¯™K‰­÷<ŠçÆ<éæ­Ý¨)”?z‹±Øcjjší4Û¿¶jº[kQ‚Ÿ V‘ÞCAº¾íxС‘&£)¥[þ5§ÆdèzÃyí6Ýäh±{ê¯T¯¿QÚðhvšçÃá¡öÄpÁÒ‰ð/¢F sïœ6ŽO-0>Ù'|µµX'ë$4‹úrh}O¼óñ4Z{é.hÄqw\CeDÅÔ3¸qw–î*ÐÓlJã¿ilò rp¦Ü®ºoîmÞ*¾e“ïùX!›¢€ÛàõïÎy§)ˆ´ŽOO 6}KÍôV0Qy–s¨™“AE1"Õs=Ÿ©KülÜFÍžÃcñ)ÓƒA'f©=xXÏ´žó.¾„/ZvMmÏ~.›f'YoÝ/´_qu²—Fñô·Û8Þ·šÊÑ^¿uçF ÿ¼û¯©Κ «ÐTìZâ.® 5½Es[¿…®‡U¹’S[l¬zel7çLÿhwHJºýE« Óž‘u wM¤Î\a‘²ªùpIó"^6j:ªÕžtX•ÇŽì¡ü¶ûCͬ™ÊÔ‰JÙÕ};Riú¹å¥d9¶­­|ŠŒÍQF\ÓôQW}vÃù¶ƒA‘ê–í©1;EF:¬¬¬l˜©œ‘õN´»Y+§}]i°æ[DÿÄ]ÍS}:fÁèäA­üãq·[xröÅÈ<ÉÛRðPôë6=gÛø¬”iBCrFÓk¿%T¿eH¼}hDuËäÉFSNƒš[zÏä¾;0(ÕØcïæ"wÚ@#q}†°ŒEêKD)O 6º·ŸëÃjÆ+€ü<—Bç}Ù@£¶íõõýÇþJŒ{ù5ð°P}bЬrñ\Š(ðdu‘QÝ´ëy ªåGÎñK£ì2Â.Ò5¶ ‚´,‰Å]´ƒ5'Þƒ–ʪJ«®+ÕWÒX*Ïž©ßb{ò0, Üá Púqj"=q¶ä|öÛï™Øû£µºõؤlÇíç@#à—NóMþ“Œ5ðZtMhn<Ê‘óc.&ˆASÈÒ¬ˆ©×:û÷øÄå:…ot ¦›zvÞ?SˆØ–èàÇó]fM€õüÈ/dFlB¥îÈ…ŒóÊ‘&#ÁS¼6ï¥0/·$ú^<²çôKÔWV®2µ6 Õ+ŽÂl’ù×ù[³:#º˜üFtQ3¶&ÑÛýbCÂÞI¹|÷¯Äø+8×ÛìrPÞÿ¹="é ÷Qí¿å ÿÖÒù^öMøºžNÌÙç‡åÞ#%#‡%µíÚYú$6ø¿ˆ4)Áû·n))W½è–Þ' ÉùÝZ6ê¢lME¸n‚ç¶;÷U µ$ˆ›22§qv»“†}÷@ê¾N¶ŠOĵñ ø‰ýOvb[s×£Ÿù3 éßQ¼m[Øoö«ß|ÃyMÌݬƒ¯´Ò¢ßœûËžñaJûO1ÙICá³Ê"=µ?4·àS˜Ñ-6î©q=ÍÊî)9x{/@F2ó‡Ô¢™e_éê÷™qbê·€GŠvésô`‹cbx¯œÈÔpÞÜŒ—ÈëH[Se<£ÀýpS§êI»×=-ëó”¦v°îÕ®¾úXK~â|o]äžÝFéÚ¯¯ö¥|ÔEL\Ëk—þztâšÚÅK²ÐVŸ¢ÆÄÓ¨¤Õв:(ÚŒUqJ²Aá&r²!××½/óp³Ø=¥N{ ¨Šc0Sﺬ™¦çè‘íOìâ¼ì4¦¦Î_Ö1§h? zx&õAŽvm®ê±®ßAðŠLúWrF¯Ã‹Ag',á+MAu^ïì6m£´°¿OÝžkÔ4ò ˆòóó“™³‰Áê×ÏåÒÔÜ ÷–TÑwŽNé0 áNß1ŽóS¹ì«ÀWÜeqž–ýQ#ƈG?_¾‘Ë—ÒŒÏþ븒MWñxCZ™ŸRq‚¯ì÷9«)9¿ºª‘ Cêì¹Iµò ­á«¡m/Tê<½ãŠÒ¥óJÎQ’¼ý¶îd2&ºŒ:³|ñMß {£Î}©õËiÄX4&+ÝWç|€ó‰†G½D$ÿÔ¾¯éQtžuöZì ¤¼3—ŸJí*œ–6 —ypëød”¸[ç}Â"õ·2Ô;ÕûãV+ÓÞúyZ4»§o×ÎøO œÆ“‚ˤceÒ C2¸Ç¢Ÿr PÓï*Ë2./+›û=~;Îß\B4<¤ãÇsÓy­†#sjÿžóóÞö$1; ÚäeK™ÞÆQÊTqæ ,ZxŸ÷ºA•ÕîÉ¿ëÂÞõ‹‚n¸¢ “ C΂±a··ŠÃ;U4&z_ݤ©y¨ïP•¶˜fÎÎKœÛº{÷î z“ü<¦Þ¦ñhb´0_JxÙeèNwÝ Z¨YÔ'£øs­×s `U âhNöKT¾£–u¶´-P£ðÖ›¾ºMëE6£g8>1®ØPÎŒ7rÓ=ï$´øžá¢öño2Çœ‡=Dõl,Ê•V-™6}N–/´œZŒœ{lDj~™C~¡]rfy“—Êu÷pìÖÛÃÇòö)¦øèÉö—•,ë®:TðÑÓ/æöð==îŠêhƭЭ@ýá1·á%¥ôªuB™Iªá::©1Õc –þ7µ¬t­Ž MŸ]ëËŽ¤÷÷ÔÜa—VÈÐUTI3´-Läè8ïzáa‹AgðνO«¡Ýô¥q.ké¸ Ì#Ÿ¢£Iìjêy3?ηçÛ¼­áÚ›ó¡v¢Wn¤ U½ç¡é‹ÍªÌ.ÚUݾª|IWèGhò”Ñ?§âöÈç¢í·½>ާé¦tždÂè­ÍÓIM©‰f¹g ®ˆL9_¯¾):¦L›³ì íÄ3„ŒHµôo±R‰Ò)qil›¿\ÑbNÕ‹N×Èqœl.å«kñ&êûZ#·ézqB›”:ªí>¡W9û?¤ô¤ÆŽýð;œ†ñ ÊŽ_¹ÿõúäÊà³Ú=üMI¥sÒfø©Ý¿îƒ"Ý?øæúç‘w¢ÅœýQ™Ò¥JmÕéõÃâCÓÚBÔ¤º¶Y¢pŠAzI¸Êhޝã 'bÝPCŸvÙ©Ço‚#?.­õseŽ35réjs… í.³T/˜h¥tƒÞºæµÛ«FÖ^ï â@ l;pÐ*í®·&k}Ïk_†%Ôû~„ÌDžçÛ·Ü:¢®²Gž•‹‹èâ“åL:´£éÃc-7ö§äÇ‹ü¹˜ô…}¤¿òD®=¾%d¸A- ôî=•BFb¢=Ÿß=8›Ö_ùbOí{ÿx…ì>õÊ2õ©4Ú«YáÞ~_?º»Á‹3Gðš÷´Ÿv‘ÿ}Åmàú!¼•º…t58öŒ>Æ=8’³ícê!×Ûz>Á—U®NÖoÓGxE«‰ùhë•{z0$O ›ì¼1wÄçàÌ·ÊøÜ³DÖ+ÅôµU†“uL7E¯L˜ùͲ€«ñ¹'´ºHfΖ°T–—²Ç^·–1IJoRèäÔVÖMÑçN²ïÚ)'%{ërXÁ\‹Ã¯8^Þû¦|3A†¾µÃÊágR”æÅ„ß:N÷î^·8íiࣷo»®7ÒYXW'5+D/õUºæjèfÈÛyJN^tŽCÖWýíÐý:ƒÉ­í‰ÉôVJ^éxÎ[Q&­ôƒ™àÚ £¢!K»s“¦#2¡á©L±ÓÐÀ£R§ŽÖáâY_Õ ½<”RiC}üë¶_7”9Á·ýM±P¾Œ®~5nêÂD]~ú0;ÇN”èÓªŠ›Kræ&šMHˆ®Þ¦“?óæÓ°3º Á1õ組ÏH#B®=÷ªWèÛ/£Þ¹ñYðÑ‚t_Αx-®ƒ'JÊú ¯o¤ÍTUß'Èí­„É™ƒ løNÏÉ ©êÇR bÔéÀisw¦$1²"{ö5?¼Þþhf¸ØjÏêÀÑõ½§VA7y…ĆÕ±LÔúŒkJMÙÆ|÷ .J‚Añ–Av·ä¦nŒu ­1 Ü’h/À¶\T¬yíÄlù]éœ*tÚ–)êΦ3èT¥”5¥Ÿn‘9!ëö㫟Ñdtxz†ZÕ{w“l%z9Ú;' kN}­ Ž›ÙzÐ ºãl®;˜x•áx6ÛDöPE œ?õÞžRÏnÁþêQ÷ÌÐŽ´ÌÓII o²]ò³ž ûGƒv³‚—¶]¾|jƶ÷ëþŸ?ÊÞ>Íwõ®ÒA´•²ŸâØäS×Ï}ÄÜc´ÉÌ¢ºAtþºd«Ü3$¼R© 3€´DFκGǼ½â‘Bg™Æ§…Ldx­«ƒy ùMý$×»˜(ž[‰ÍCmºTO^2÷°”êûºÊ¶„èÝk|{<Ë®¦Yë>hû”½Íùr.zlÏÇë~WÑB ;Çj«OíSg#êwÊäÞ ®º½éz?ÈßÒé‘rAJ¹#yJ¡‚à;#3—‹ÒÂ÷Þ^T.ÍG×êœâ×ÅHéæyƒŽ¢Ï‰9:œIßcÁÐ$1Î~V£®"pºc4š`BvèÀYŽP6þ¥‹ï•º|{üx«!£n“tcŒˆíÞiic¿ATìrûCuôâçïãCéØwNe5¼¾ûƒ’®öïû$ÚYŸâ.xÐB+Áã2î;Pó:ÜšÚH#̵T­ \_YJú wKzøVÓsž²?>쨀íLWvšÓZZé‘ê ¨@låàÄšt§ù¨Ç€KåF»ñKi›÷îò=-Fˆ|F,ŒöCVŠiíD†Œ;˜x¤ù•yÞ]šËv=0.Íd5§œ È¥ìºÖí#±ó0o•z·–žª¬ߣÁYÓº¨•* a±n}ѯ/{¸Á(£¶K™« )xãŸR­—Nº|³h5vùª’ðÔÕUyÃ[A“ë‚ð~¨ºœ\)}_À±Mkln9b ³ùø‚–ì“æ6áÏ Ý?š2M×IQñ²´Æ3þuœ¾ô'gA>JQͺ—%häIhü?)hè Âøä  YuB¯³€ƒö®e-“#h¬5Ô‰z! ‚}À»“WŽö–8ˆ÷š¤(¨ÜN©…оs)•Š÷OÚJ§žBQÙñJû3U[S F›ÎJÕ$®oÞ>eǺ½ïƒ¦, ð¥ü~=hbÈ®(½PZ‘à-%ÎÅ•’¶ išËµŒ(/.ܱgoárÒ¦€¤N-0‹xYi^Ì›èù.‚ ²‹M¼½õHjF ´=ñá…ýáv׿qÛ)eº®(¡‡:÷)QšX3 2‡ES·gn Í“{Ï\…¿‚¿ÿyèÿ'Ÿeà?ÑÆÊ÷? óóïÿ!øB""Â4|ü"!Ä?÷?ÿ7>¼œ„—æ'zùGà(çï¹?Êˇàå‚ñ‰Š!DÄÂdÏÿÀ8yééy99éaœ0yÝpCWšË@4†Ÿ³´qh3¤-L iŽC›#‘ÖÜ0Œ6ØJÇã3DaqF0[kbI'´-ì4‡CÛ:ræVXR4îP,¥hsÁâÁ;àaH˜)0}XŒë¢§†¸¡"6@&ÌM¼[ Ãà`H3Ú„bƒEaÌ\ÀW

e$„ ãhg„½‰5ÖÔŠDÔ[PœF™eÒ¼.#4@'cÉŒÁqHG+Í-å Jû—©ÌƒþڀĄôm I,ªM.5ÿÆlÍWŸf!Ÿ(`¢„€%gŶP@(ä³€¨ÀŸøçþ³Á8šò:ƒOí °æ‘ú t‰Ž|–Ô »ˆAxH(’ôì–+iffF*†r@š¯PÌÌŒ¼$ôï¸|Ê0Š:SÏ—Gú”™Î¬ƒ6ã7!N°meŒ¬Ø3xk4ô|Ï ˆRÂ/Àò1Ç:¸Sk'F XÒD@£²„²ø(ËD%b¶˜³æ{"L£Ù ñ ‹¬@vbf@´šZ`¬¡±šïË’œù®-É!ïéÒLê'‘ang lV@‚Ùã1‹(ßÌ ‰æ#+éˆ7±­S€ á(´£©ÆT‡ký|pQ¢šNtTüZR‘Ò8"X,DÉH𠂆ºD´£#¸.XŸì¢´*ˆÚí<ŒÖ%®R”`–è§„lh˜óÚÔÊ{jŒ0pH;ÿk!Ÿ˜ê}”EÉ2 bÄ‚ùÃj ¬<€9%_*æ… i– Hµ%5C˜% ؈ù•˜ b)5+ XVÌy Ê  9,nzֳ̟ÅyŽÀÊdjÕ_œeè>‹Òæ5JÜ%/Ç Ð&H‡E¥%“J–Ê¢äiT††8»ÀœQçyÁNô‹¨ ]°xä a%€«¬K¨ T'e±Ql( ÁÈU™%/JrÀʤJ,,‹Zƒ4jú$ùòL"nªµÉ1_ ߟ,Öñ ,°fBV±Ú ŠoÈd…,ßüð-B€“²Q‚ò»ÔUAj‚8+˜ÔäqŠ 7 A |q~ÁB‚°¬˜9`™ou&x¾À¡Ç/ÁGW RiÞá>œªŠuź;ÌÄëìˆvp„S™vb5ŠîÌ«8‹ÊÚqÃ¥”#Š.7hDÅìRÑü×XÒª5Òm½4³üÊþ½…~:; íìˆî*@ Š'>.»ˆÐù(±Î/n‹BâqØE‚à±AžŸ× "Pâ2 ‰=‡@“ˆíèß©À ¾ÊcfEâˆÕ¨i( xú@@÷áÊùóJé‹‘+¬”¼Cêìéʃ¬Ô󀄃ômðy]`7…,°Ñ¿Ñ ¨,,þK´œ?Ô&Ñ>q&‰j™0kb"Ñ6‚:Ca²Bs ÍÙEôü8 >ˆ,* xЕNÔnkм ÁÂÙ° Ù†ÃÂжŽxèÑeàÿGà7on³À:`\Aü­aÐÁIžpÒä8/ú‰Ä'J"%&ˆ¿…ÉQ‘%Ð!ƒF‘ ÊâVEæ lMpÿ£Ðf Wr—:ŠtÂbP„§bAÛÄ IC,f‹t$´‰a Z›h;œ 0 RJ>jóITTÜM #@K s0” ¨yRåpz¯š4¶ÐCé6vÀä€{Ô‡ /‚Ÿ8&T†J-"±Q¯æH¥(}Jƒ=”²EÁÒ–Q¤­•#40$FhÙŽƒ^ §Þ/G{<íŠ^Ú±ûE¥‰‹–é×ÒXå§$¨þXÀé>-öÀÔcj©ZxGžˆf9º™WàÈÛ9‘F\ô‰ôCDc yQJ0jRn´ ;.èPä ~²mVŠ !«@î‚°ž_>(§ƒzBGÁšDõ*'©#T4Ë¢C¡.¬Ý H-Ò¨¡G’”0–Všï­—Ì—F¾ÁúmPHG 4…y í´ ­1æv›·¢‰[JŸ3*Õiá/_“Zuœg5`ÒçÕ´™ kAé’Ñp䆃 lÁ ÞnGÈá§ßñáö†ÈwÑôÊ” i ²¹?oÒ,c¬¸{C­h§‘J2‘ì©ç‘Óú=Hä>S¢7•ïØR&ù{²}až 'èbñ¾à  Ž8ÄËôŠZôÅ¿ƒÔØò)P`N[ut$åý‘ ùT¶•‰‘¸ìüdº£ÿ5B¥ÒT©e,+ÕÜÿ(¹š¢Ðfü+ê©Ë÷€Œ©eS#Á¿×ÉÃŒ5EZÃÀ-cÇErŒœèI&ó(Pþš# ŠÕe\w+Ì:(Êq€žÁCîÚ#_¯…ÁUn±‡† úo–ßJC‹¢Í»eÔuc²>RM¤j*æ …yB1n+kjTHúo N>(Xg¥± „®ý²@À18 pP—¸K(P 3Á—:x©D-ÐåZ@n°8š ¥à4núÅô„\Bb”À) Sc“¥¬¼,}.2çû,¸0Òä6;G1L$Ÿä0^FZqÿ‚‡Ÿ “þ­!O_²îRd’Æw™ùX<ìË1•ö¨g“·Hm’–ؘ”k"@°‹¬[>q›vQTÁ2ôl—Vð…¡…v„±.À…0d¸-J-def%øuˆÌ _¼LÈ%ˆ/W‘d:4n”áY‹b©–?äÒ”zÄÕ"ÿö¢ØŸWVB÷ èqƒ>#hhˆ Ã2nEG#Ë„¹yÐûÍfQê¿:ËÐüF¼Æ‡w@“£3y@.9ÿ5íhI[‹…6°8øa™Ð*d»Ôwb4Gd ¤¡·¾qS«ãðIÃä+qÛ› Öÿ®­ÆJâàEžŒeDîÿµ…S”«0Éɺ€°S C®ÖQì?cDTœW‹}æ`xè³ÂØÚ’l2‰IpEÿ©YþùvdEøÒÒñÁƒº¾-‰M(· ¨¸qIÈXP×[ÉŽ<eÑ/GΚÔ}ÖÂó>k¢$—27w@¦ÖÑDðì ç“—ìƒåy¸"Xf8 Ž=øw+5¸ü‘j-’ܱ.¶(Œ)!T¨'ŽP4ñaCؾ5>RTݲޘ?D"Š%<èØq½6%G/¿·@>Â$M• …†µœCî?¤Lz¡·xG`=°SyæÃ‰©íVz,-JŒ„þƒ=IlX¨ ³sÀ‚‡‰áÄ%ðs©nGÚ›/A<ºH£ìÉ¿¨æâ-”™d‹ÑÒí»ÅÚÒ2JÕ¢ TÊCoÄþR$.® .î(Åš…NÍ32iDÙÓ'¬](Œ &ò<ˆ¶æ^œ@)€—æ‚»°dÉd_ {ø }Q¤¬vÀAŽnBúü‰FnzÂ9Ç7ÀãC”í­ÌuDýEð(¤_,ÆìLEYyÉPü'ÔUr]ìì9®T¦…úÌ/S‘]/)C¹YýoÓ1é€õ"$áÂóœ@îèâY8$ïÊd¬nÑù¬ùÓ1ÄCN \[¤åÁItÀiÞœÀ-ù½Üù@ðh7ÒT˜Š+’žÀÂ)¯ÅÉóÎÑ%9T b²¾ÅqÈóX[¬ èÚá!?z²ØYZ˜H ј§&÷É-W‘P’¼î¼_……‹å yƦÖHGÇ#‡gäA®®==ˆñ¸6ŒМa0½äç^Y`q²VX–)Úá4ž 8„6 Ñ‹Í"A™<8M½zÒhQbÅBE²òC§äùðZ°£1¦,Æ _Yƒçç?‡@+×˜àŠ…‰ÃH` ÈJy„PÊ`Hh§^ßЀÝt` LÆ–¼9DªÐÞ mÿð‰—kPˆ@øâ0 @%Xú;Œ›ø2}&f®„ˆûqðЫ;|Iœý8/!oe !9³2‚‹1çæîNÞÅŘ(•ý¸¿Äq$ÌÂm&Î IEзuÈéˆ6¶Câ,8TY`¨ ùÀ9”ø“a°¸É…FÁ“¼Ž¦‹[$TCZã¨55OÜ,0ÞÅÍzPéÙ‚£Øèï2ã-IÆ(d\KúI//ñÈ( (¤¡×€XᣀDbIòÃ3óüML$cQ p„{2Áu Á"Ö$œÿ#¸ý!]t‘Z¨:/„ùàt–…&cgé âB1¤€HáÏb¶¶[)Ÿä&Z\†¬[”rœœN) ‘œ”pÈÇŸb° ç¢MÕÈ>^(Èt@àN´ ´Á­-Ò¦‘ 2bÀÙY ³Ä…ø8¨]¬ô¿Dó—o!q8¤©Hʤ»—ð€úDÙ9`ÍÞQåDÚ šk"ÜU@~!`fC(B”AàH`€ñok ‚HÆ ¯X ‘%DCyÓ£ÙÿIìÿÉÏ2ë?1¸ùßrûÎþ°þó ñ €ë¿€ðø ®ÿÿ¬ÿÿ•¥ÿwÑ´Cj?߼ߗOÆ/*†þ#÷ûZ)…q@B®ã9DLä‘°E;sìb @°hŽ‘L d(C{+”i®hä1‚~e‹„Üê$YPÛ!Ƽ‚NÊ_lr’Ò ~/ȵAOU!'kŒ²ŸÔ²(›"0¡1Þе¶€æƒ›&7‰þl)‚%$://²)‡Ÿš ðJ†E‡¹7<³EFäv:˜µhþ G¼ÈÌÌÅ-3þO³ð¿õYFþÁþ3m€B^DHh9ù~høùóO@€_XAÃÇ/,Œ¢ ýgš_ùóÿ¸ü_yþ—\Îú?jãë?¨ë¿‚Ÿ!("Œ÷ù„ÿYÿÿ? 5ùMô{@!¶IQA|Ñ|{ø0øÌs¤˜Á«(#¥s4дdü«ÀšÍ2ß?3^øÞ7ù’üð¯ ØƒÎ¶W_Fzü²×«‰ŒÍÚGcÁŒœàøt¢ „ÿÏCpÿwVæÊ#wÈcö¯¶ñ'þGCï¿‚!Àúÿ€ ÿðÿã#¯(wTIOCOSICSXXXQQ13332ñ³¾±©îÍÛæææÏݽUUUùùùïÚ;j_¿ùüùsKkûøøø—¡ÎÎα±±Wuoz†sssçææÆ&gVhìàÔÚU44;h¸Á`›4´<1‡¯7X¨)kÜ]³ŠIˆÓï NöyÃõšÐȧw…, âRh/‘ßâWÛãKCsì¿4,ÿÏ|þ…õþ²ªµ?ñ¿ˆ°ð¢õ_€Ôÿþáÿÿý•õ|Æv#´þoÒGC³ª\ÿh‡Ü·Bn÷}]8Yö±WÕëMþŽ#b}lÞbk¥]Ú /ºzéÒvœ=ב¾CÞÃÞ'™4oÑûÃpWêc¥÷F¾ÒˆµÁ=ØTèãk¼Â_öc¯z?uyÕ1í7¦.^sÿåÙâyÍuÇJ½KÞ=—ãÅy/jÐíÃ'}a;Ú¹›{þþÜÚªžþQØsN<%ð4<*¥)«ì• Å=…m*òqÎL~žßG•M~nK|Z[»y½ó˜Ý×Çï&f˜Ã 7%ß^·î¡Æþ#¦™%1uf³uóïU¨¹u·OÊB’s©6öGþ'žzþwhìú¿ˆÐ"þçáû‡ÿÿ*ü¯üÝ ñ?=Úf/ð Èÿ Ê=«6]ÐØxòIOåËcù;˜{ÎL2FO¯úê#½“õ˜„Ã3óæ‘Ý¥×Õot6¤ÿŒÐt¯KÿymßÜ‘ ß¶ÿPláýcüßóùú?é™ÄÿqÔÿ…Dñ??¿ÿ?üÿßøôÿõ€Ñ_¹¦´´´  ÐäàÅËêç/^~ììîëëËËÏ ¯_¿~êê©|ö¼¤¤äç®ÙÙÙgÏ_ üQó'|úÿv‚þ¶ICË ;|ýPâÖõ±×®\:quìê-þeÖuOÅ¥ÖßÛ”¿æ¶ßZ>F~zïÕñ2›Vý£þÿÇ?Xÿ‰OÕü{müiÿO€±ÿ!,ðÿÿ7>TÖZ@åß­ÿ{é'ihVß×½§!ªûe6ú”ïHÓ¸I{løùþ É/iõNpÂßs tYk}ª>~zª©äí5ƒž@kGñ1Þòƒ¯&¿Eez¹öÊŸ8çýйü¯Ç°®kÌekZCQÇNì:ø fë6ï”ô”†#‰³´SmY—.➪®YûœãsOV×Õ¯z³UUæ •-OŽ»á£KÖû(X±nm™]­P1@c­CÈ‘­J,:ÜUü¤óœxcGxÖkò¹žVò¡Âx3 áX¯¥õ}-Œ!Ò“îM§ÅÏ7l/? n—ü”ÓÞ_:ðüÌø³Óôô{²2˜nén?qˆýâá-^‚òÅ5 w¯sûu1?f"^£J.ᇴ2g‰-mã ,k_Ÿl¹hÞj¯ ÎA¾»nŒÝ•,´žcƒ‹óÚ¹Zì\êd‹Ú¶#‡ZN3lÛ›úúû® ¾I´M¿mÚ,ºò´×» rzÿ.n\·½áÕES›u#BS޵ƒo™ÐÓ‰nN£n‡;< _\Q³‘S*zÛó´÷`¯gýS­7òÒkœÖvã,í;5 k_Hr…ýÞ] °óC³@Ò©Ý~¯5=Çv°\ws?3æì¹~ûé!;u¥ÛV>æQgƦ¢ØÅ_{ymõ«îxZòšÇ0w>î/ßîu|Ïä#Œ‡Sb¿¤ýÄš MÙØ¨þÑ3—Êû &mn:†O¸ÿôýâhWò Œ…éè Iæô‰kèžêîߺ¥ü€@]PH¹ÇÏYO¯KÉѯ[RgJg~9¶Lu‹þþ1uc2½%KäroÈë99_w^ƒoŽ3ƒÆÝnº^eB³Š$çæ<ÝõÞ(ø!Q&è5—79~ê³²ûÜ&åCÑoêe<AúýG•ü÷>´ÿ–<ªñ¯·ñù/Ì|_´ÿ#Äÿý÷_ùP‘ÿ@þŸƒä¿“ui& ÍÆ# ü?ß6dd訊ApìU˜Ôê~Cç7ŠãÉÚôk·õqop£¹xBrõî‡mC™¸ùø³¥‘ú¥š‚ºSãv""^2(¦¹ñ;^«WÓѬ=´uëM‰¬9­­oK*8>Ó#³ªë~úõÀ§äzÔÒk,ÍYJD­…]ÍÈäôþüåó¶Ï,Ÿ™aÒ°ƒëÏí1Þ~Y [!—€ˆfÞÍ»n맯«œß§ºUÁûÔ¥Sï£äé}ã\»fa'vW=|Ï<á['e6[;<²cí§Õ4—öå& åÜT±«b–ïºà÷,Ôçëµmtë¶‹9Q±uüdÀ›U©çR§Æ÷ Ý>ÄM³uîÔ‰§«Oè²1EV^ºdG«´Á¤êœðͧN"›YéÖ|ibq`щ»~(‰1¾u÷Ðö¯rë×=­|ʺú%ߪ'ö¬lƒøëŒñÜ‹SøÕ©KCdZÊ4>(9½³¦¹ìô.qº{A|ñÅêr«7×W\eýÊ}íÊ=/W¶X:ÔÚ‰˜¸ËÞ51請¦Xî¾Z/¥·ú2R.èÉÑšWlkÌVóaXÏ÷v÷%ñ?'d!+brh7Ûí*ÛÍžTväŽX½-Áâî‘pQUöÚ nïZØ~6N=}Ÿ'Þ-¿&Û9Š-¤•\Œçî?ZÝ¡]”u4¦â/šŸ½=̽fÛ'%_=TH “»Ç”swn¦Š{§‘¤ÃÖCÝ"MgS:ïÿJ“ˆ:›Gu¤‹ýiôÜÏ™rÏɦ>aU;úækv;o$?:ñ¸a×%Æi9Ä ûxÿÈ~­"éÍÒJ§ÕÖ0ú6xKþ²=»C…±C(Œc«Uœß§H´ÞÔ/÷‡®Á.ïó[‡÷ø|Z1oRì\eËz)ömkw¯N½x«†#ù¬äË:üµÃ{bbÄ$Ê­ñ´÷·l>yÛT–ÌåÛ*ãcØrAÑÛšÝiùŒá&ZpÄ,ãÓk–‹ykÖË5¿ãF_ÊY¢¼K1€¥ûD#mÓÞÂSñß k.pDZü…>ÛÿÞnÀ9¦§©­1G¼‡&^f+è~æ—-O¯Ãæ×ïùêmÊ‘;[»[ùÂä-àtÛ?©°ô—Ÿˆ W1eÛ੤uôV(£ïÆ^8žCÀ2îÓ§};&˜ð”Ä µšô­_÷ÖûÎq«!–O³Ÿ^^]¶/ñ̳ék·Ö«<¹íøà4:f3«N«­ý(º;CUQF}{–¿ÛžrÁ“Ò:ÒXÝû]Ã\½5ºž¯™vÚ”Hqéžv÷¿kW]Ñ©œaŤ$ÜtÃUkÏ^ýõ¹¢üöößß%+`^kkp¸%ÐÕáeú™‚7Ûʾ¿m˜©0ô¿¢O[^9âOûh·pÒË j—c””²pïðág{uÚNãVD§-ÃõŒ}¦2zº>ãä²³¾øš§¤ç¸‡I8m“‚jXvN·Ó‡°m7ÏëŸó`Iã:*o¸5T)cû¨€†î.mÑÙ‹9ªJ—ó\³¶Dôûòrža¢ÕcÿôEóÔÏÀ“ªrŒ]M„ö‹Êß§ÃoŠ0*`ëšþÁùãÄ>¥g¯¾|±¬-ÅwÖÖÑ׋rÑÁ¬{7R¹këÍ•«ÓÕ—5ºÆ-E/Š»ú•íÚÚ¢¯|#;êGdpŒèZ#‘÷}rëY¥IÚp D•‘"ÝÓ^·øœ™0îÿœ´Sû]ºyIˆ‘bèe5o ÌÁ‰~©§ØLAÖBÖ¿D’E®È2±wšWhlhÞ]Ò•s¶Ø¼¿šv÷þ¢jD…üÓ½å 3¯õåÖª¨ZH+SÉcõår~²uµšiqðÑ)ú  Ök¦Ô·Ÿ¡ÏÊo;£û ±ÎÉ:ÀP·öèér'<“Ëq…ÞËÏF\89ð*/ù¯ÉIjëQ`Ü{8;‡ë-àtŠN Hˆskx…³´‹ti•c^ˆ–™ÃÙÐ3mwNì\«t?£ñ•¦µ 'GžØa¿´ŒÆ£®ÁiÃQÇÔ$á¯+eÜ┃Š_ŵ™I>ÓÑü,xæ1åA~œó‰*ÿëZš¾Oj}:ðÚî0âËUíŒNë­QsÎ÷>%½vàÉT}vÍJ"²âÑ ÝCZÚ-_¸ü"\ŽËØ[%û&È»_ÿ ²îp­‚ÖððkãÈ >ÉÏ’«†÷²ùâÃÀ8Ї陒W"M÷yeçJ3g Øf]glQ¬ü ŽÜSLŽ[³¿ùÿØ;ï ¨²m7Ir’ÐØd›%ç,AÉ -9@$I’$ÉI2-Ehr–œƒˆÝä%ö罪¹3SW'”ï¾*¾ªS§«û}NŸúÖY{ïßÚ{·‰w ƒ »ìG%$þ6'}ÒhL²"G*¬»‚é$ÝQ}ƒs$¾ÃëøÉÑñcäYÏ‚ú]&¯C¾‹³jdlñŽ9©4ÓÕÆ!/cê½èÜXC½âïÖp]7Æ£XÏO{4ªÂœ6™Ï…Ü|µ+¦(0›6š¾‘î nÕ„ê¹Cpa¥»Ö–3r¯EA7oq5âUWNñ±G/?G[èRKßyÁ7Ézb1WžæØÓVla0&ʧF·YÈvèÀ·0™^­7[›®`/Yg}ÕµûÞb¡zT-²ž¼k~ÂLè.eá½?¯ß²ÔRZ>ôAœoµ€*ŠM¸óŒØl–O–‚?×èÍå VÅH.ÕÞ[ydf),§§;ÌsŒ•»RûlZ/óø©ÉÊLBÕš‡Kõm±Çx¯K †È]ÈŽj9­§Û·Ý‰Ñ•îyé'qÎ:ŒÕàõVQ–³ WÂvhzR“ŽöI’†ú¼mÕíô“èÄIR—C*¾„ûn¶–ÞóRÈhð•Ý|–3H$Í}6~¦^[N8{­qú5mt@²É½z.ul¢-ÀElÊ=Fny/(ò·°Ø¥4Dïn‹áSV-›ë†y+—®MmKx£”ˆ@`ˈºiÜõ{¿^¯þ…-Ð~À;h¡Åÿl¸Ö¹ØûÈmò=[ðɹY‹¥NDæ·Ã®=1—kH Æ—E0n8¦Žm&Œ ¨¨Ußf^·hÁ¾#0MÏDM5ÛÖ tZ«®Xa§Í¯Ž¢.ìU{âU²ÇO²LO(YTÐË(€™¦>Å|´(ª++­ñ„ò,ò9¸ ¡'Ôy.l ÈêÃZ…à’;¶ðxÍÑûbÜœþž *7Œ…5^;\Ý™2ð#ˆ Èþ¬¡Ä¼ûqŠe¼ºéƒñDƒ±‚F$›¬0¦ÉtB±N‰np¸ªÍD2ûÖxB?éÅžÇYuñÏU}‰õ¢•õ¹g®+! i–©¸f.*ƒum.ª¾0/1¬ÙÔ[„¾£Xó-g-ºûÀ/ÂÅu*¥2óÛ¡¦£y}•œ>‹îw…oQ—·ˆœž ¸eÊS_(ÔíI ÀNH¶L5¸¾t&¢’¯åįeÕ"Ñ& jCÓuâ¤U1õYœ·è3NK†“r¯a7rå8;º ÌL̃ÜWÛB£¦ß06˜X§®?z1Ë[:H9öÒ8…zP‹âfè=ùïMmÃIÊH?ñjž7Î5:5s°Ã'siÚüïÌ÷¢Vš,÷™ Úëš>Ý—æÇ‰•ËêTN½3|ƯŸÆRKø(ˇ5WÔXth|(•q¸ÈIpçP4“ø±ý»-×àžXf]­Xý÷vcÛŸ| ¯ëÂõêÂ!È-?ÂÞ§†x­)½Ÿµ†Ý®\%trý†‚]Àqõ@˜z”¥½/Jë¼e÷•.‰ =ÖS–’ªOÃÐ@"•Ÿ6Ä:GݳiÆ–1íh5ÀÔè[ÄÍs}#hÏãÇ 4"¯•«Áa#7¨ˆ²¶«Uò} ˜$¶`Õ§®%®?Û#xz¼Ç4cnV%5¹‡ ]¦ ùuÉoåKcã¬^a\sbÝÎ}-M~j£ä¢NTBÍn‹«/š‚@bCøÝòè€"`”~d=ßÞÊ6ˆ¿™ "®×ºUuà÷ÍyÞð*m™KãÿÓúæøÿÿl~öwÚø&ÿ%Àû;þKà²þó‡èÆÿÙΟ¾ŽÿoË)?=? å¿‚ï黬ßl‚¡Ä¡¼u:Ò\Q€Ò•{ ¹ "7Hb»Óôz4ÛÓú(»Ó~]ÉòšÆ Ð¥>L颩ËÁ¡¾wþïïÄ€oòß|¿å?¹ù¸.ù¯¢?ð?æùÑþÕÿ…áv¥èþc-ö–Ã$ѳzËî‚6¬>8ÎMÞ¡Â] #‹~{’æ¨/5/½XBØeäæ_Êg%È„FÜ›¹H\¼Ñõ°À¡rB¦x&DÞ$QÑ;Y1RÂ(²æóæn>Y"Ì „ì¸)è÷ÅÝÕht=¼˜"–h<[[3 ©$â-éw%ô¡®žÔý(݃ÃÜž'šÀ°µfCš—äú 4ƒøíDó–ÚÓd6µuCPYáÏPÀ§ÃRZT'ø(íŽèÈ0É3=nZžL ¨g¶^cúü"½2«‡ïD–s8 vÙŸ6qØSWÉ*ÇR_Éܨgêßûp`ÝΤh„Ên+’–îÅ·yæ.â×±¦1 eYËËﱄêÇ©+dôž×A°1å)7›Z×Qâ]Öã2ò@Á3¹á» ;î>-³=Óoë’̧{2}ª îz‹Wœ©îèë²M­´¼¦]©‰®‚ÎkòÍ¯Š‡>Ö¸} y¥CÖúj ê0ô¾•,62S–‘]·b¼P³f]<™×p=Éè"±H,–©°ÛÐ,*Í¡àrŸx¸ßqÿ³ÿ/6aþºÅÅßJ¾™ÿs}Íÿ¹Ï¿æ½ð?ßeÿÿ‡èüu~à`]¹ø±ÎpÑG¸¨ÿˆº÷‰”@ïžE ¶ò⡲\ј`š>zFÓG6§å­±ˆ¡¤àCè‚!ÝÜÞöSq…F1já°œ·2:Â#×/RŠËdà¿DÿÙÿ¿ß毴ñMÿÿ®þƒ‡‡ï²þë‡èü±ÚÛ×÷?<^1ìüäá«™µÑ|]RrµÞjBËÚ$°½¥«†î“s…©ø†`6‡û²dFÿ3‚°8‹W°öÀˆÚDÁí~éxelçX±HibF>ÀëÊù×”ó]H—™ˆ©8H5¥×4¤å2äÓ4¶ì¶ã¹¶½I–Yž`g¸Xf„ž&f{í¡˜¡€™Sm3‰‟~zqÑ—ÁãÓŸ­ÿdÿºaúŸ‹ßò¿€àoù?¾ $ðÒÿ?@ßSÿéýõýOÙsÃ_“´uClaêØ«[äsŽ|RV`?¤èY,¾¹)ó6fh(CŽNiäu›YÒmqéCœbÊÏÕÅzAϪZ ÃTSMÙÀû@këù™ºžíj2ócí$ÇÑ{Jêø¾اè³ÝâÔõ2injYà Y©’:ù1bËIwÝŒ –±îÄã\¥K~z/vð]Fu)\&-¬ ã!£lÛ"Û¸Z"+P2 R«õÑç=Cùz´À1Åf'%?wÛÿyù~‚‡Ïľ³Ùk<‹7Â^Š&²>VM}D2¯YÃÐTË,ºH°V»?ññëeÝI`Æ=mX0^ƒMøeÏ=ÁðöWT4k†(êªg¡¾Â)nÈù¢FÉ͘²$j"º€Ê€AD².)bä¹¥#Jú‚&óº‰Tûhþùlÿ‘B=JÎæ¦A<05ÙË«0±®Ã¬"ñÀYb¿íSf©Ö«¦j“l4oUÀbd°å¢/ ‡_§T31 à*zë¤]çÁZŒS¦P^Ìîô3×hÒ(ÍMˆ €¨ÔÜßãã}m Ü¯³Ô-'µa2 5Z÷!•ìçÌwî„°O,ò‹Úd’%åVgJq÷Uû͆ *Ñ™ð Æ²3M¯’Œ°HGËVÿMäÛõ©ÁèAÄGéòö9ñhqÍAgË”2´ššÆn…‚ 1ÅŸCžJÑ·ûÅ ·ÑX´XeIÇmÅ:"÷à±r™aùN ’._ì> Å0¾À‰$B`v<›ujãÒxê]WŽÛô¤kk¬]+£nw+X†*f†ã"³?yÒK“ÐKúb²XéïÆKx}9Ì#¤ó²µϱ ˜NIž¼Yˆ OŒI _„Óä®™Þãz-5I +ÁõٓТîF'9³¨'ùDô7X÷ÛHìÞÄ:(ôcaI=x"‰utºáµ¤ÉŒ•‡Tf’ûnèaÁ¯Ù1(<$¢ØC#ç\Õñ%jøËÍ(Ç´#|Uîë±M¢ðXÌ´N¼x²Üb”¸Ï…8¶¶W_˜Òõe\*¶>ކo¾¤¨Ö÷VPÛ.Ï|9?4RËú‘ü)»qÇ™®:—/ƒR×'Bßê&£@¹w$‰vÞ‰˜Ô›ÜÛªçŸÜ¶ª7·,Õ †„Í¡ ½¸Òç/÷ã…Ü̱î˹ÁÕUI¡V“;àSà4a ˆì&]…ð£Æí¤àiyæm.âí’Øÿ<Ì £8LdÏD7csóÌÔßëvÅ™g~ª„Óà(jV°n´J§€_w–R\2€fg%™ÙPnÌ”•“oì01ŒfëðŸÉ¦ßn­áqLÃχk:D„¥ «˜W.ú¾˜ïîïa?Œ¢9´ ;Ø54Ø&N‰³ îvæ¹nJ!ü6¯è£â‡nsCJ…TÁ§l¯aÍIØùd5ýdrüúº—à¹Pä8ÇÜÝ’®­ä…Žêô¶å[BN,*_vÓξ-Ë®BË%>b¡IxÔ™³aÚ ª½«0ÃÀç£{ÝCDzv+ªW³Žû©öCŽœÌ÷wʇV0H?Y°ÂÇ’ª 9ûD9¨!©WI¯±Ì¿»éÀ "É]÷Þ˜L~­}5²Sù#/Ž­¤z"Ãܾh´‚È|Òýèé¤TÇŸêqÂuNœÉG÷#Pã-C–lZƒíñå}m$%…z…tF´^®ÆÄ†½{é)MfwýJ¡LÜ}•¾¡‚7ÎLåÛýr‚w•JÉouc³Ÿê+±$š«§½'M~ÙRÿ{ÿÕTÓõ ã¡+EP)ÒT@¤)U:X@º‚Ò«ÔÐBo!¥©4¥Ji*½×$é½½‡N„À^×]Ÿû~Þç-ßûý×ú?g­œ$gföÞ³göoöœsfv&YOØ·1ÜGå^uÞÜ— x › ]îµÚ>ZußB¿÷ª8‹ÉæÌ ±±ú`¬+¬ƒÌAÌu½(õq‘6á.ø†‚ÄÀ‡»ÉBŸ=&ýJ;–=º:îÎð3E ÖitWX¤ïv6˜óÛý‡¯7¢\ižéžØ˜!ìiWóëÀÈs;¦|tÍýiéë‹‚áéÜ ¨ŒE{Œ‚tŽÖÙŸ&M»¦Z£¯p&ýˆh¹ ¼ß9?EóâpdLì±ýw¤n赊[«Ü¸"gÖ Ávš˜Ã‘D^ŠÝ¡½Ÿ§^Älžéó/Û"tá÷| ï¦gêÈšý(Œ­ý^sKcœ#a7Ù-7lO‹4õ4Ø-G5¬&^Ù'ë>!N€,Òˆ‘ïÑ-7©ãY•GPÊÎ"‚‡lÕó¯o›%,êþº;è«t_¢òžùÆto¼q>¿Õ+NGnîØu N#è9Iи–H““m;¯£ò[ЗNÌÔp/ûÖ­ä"äšÙ9*Î2[—>Jhöìè|°RÒJåNáž0=sy¯ÃZRostýJZóîÕÎ6¢[³ßÌŸ‡¿!¯ÿM,mT"ó†,RßÍKAà©ÐÈã÷ÜxÚà¯T55GßF´®_1­B>kIB`üΰ~wRˆz'+§GôÆqÛ«–Gëi§Û«ôÆt~`ݑʟêüÇ$©Š¬ö­›~TT¶ñ;~O™.^®[KWb@‰M1‰úå¤Ã\ÁWtêçiŒc´îL.²øJRšUdˆ"éãß]yü °áéáDu» 4ùú;»6Ç .£ðo¢!u‘Þo3À~˜Oõ]Þ»»Éùuo<õ¨Ùë¬'Ö’si7êÍA¶ºÎ5étáé—6•ɽ #FU*]ß^[޹}¼6Сë¢ÎùuéY7aœ¶mG›QÈëÒÉÎîgé½;u3°7Mí@ñÂkŽ53 ŸÚ©#ó4 †­wª0±:˜y¤oäïVk™eÒÞoë]röQm/Ô›]÷{óc‘€#}ÏçëCÕ›½:N…bú½ÍB™WÕW|nAi~€&WQˬ ºQÁ>i•AÖÕ›Gkø륖—ª!Ò9MSÃ=±;åÒwn¼¡Kúf%¼ùÍLÍør¤…¾Ó•ÙGŠ]uõ‡÷ð{§Š‡~«ym©Zvq!å|TʸÜíjZ߉]‘èû]ÅHá 1T¥×ë]jk£Ú"ŸwÒwyeVíí‚ì*:Éã«¢n>ܬ؛Èî0iotŸ´éÎ#_ø4ÅFôP´2›ÊÁnXRäM[y| šaö]/ÝÇ[å"»ô äèwË;#]eËË#ï ð¢›bƒÑtD©é?tßøÝ¼ÍíÐa` i¤ÃÓ be¨gñMý.#-XÝÖ+ݽHVôëÅW8`>\ÕYSs Xýˆe³}6©Jãm~â£ð3/Õ;ï³°} B­-ø¦¶6é&iÏîót­âçÑ”yçQ öCÀÀó– Ê´£còžE±O#ù¾›Ë|oBEf;&9ÞSUñÆÁ_úZp´ͱ۬›ºYE–ø¼¦2!Å)cCö­gø;¬;¹òLJÍü…Éûl¼²÷œÏôi…êØRså?uŒMAÅxˈ>Lå´œ%m»Í¢´µ§Î"PŒózRñšBlSß»[X=TMÜaã•¡2ÿd&f›«‡"î—î&±üT³`–ÿlºz×=rŽZž&³“,-£Ÿë/­ íµ|¯bà§üišÊ`ÃUkÚ'Dú’C|†øªŽ„§Å ôP¨†¬eüñ2uÿáØ7å¡Ws°b{äÚå¯2ª­| СˆîoÄ%šo¾ÓêP†Ý)˜õê æ¸„,÷œ eÕ?f=¿Z—@ %«ià¬=ªáj¢+YÚÔóÉ»Í}XÌcpè3œVèRÿðÖAep%ÍËt9N1^ã¼MP|ÇâÁb¸æ¼¶ ÑÄH„(E©Añ˜=)ŒzŒcF y`ˆz¯‡\‘)SòNP7è¼ÁÁçˆ<5nœ«\ì>*Êóí N‹’4MB{ŠeYšOÐ9ˆF±ìÿä¥ÝxQ"ìÐå!(¥õAŒ6©ß´ÐTWg:5ÀY5’áýÒƳ|Ï>Pu“Fk³Œ1´ÝLj…‰{Žä¨Má×j`¯Öxªª[”hŠÒÇãýâ‹Ø °ßÖXîëÞu¸ÄqåÍF|vËK5¨k;,šyF´ÐAM—v¤*òÃÊ)Rð$2¸¶-ÐRtfD´øÚ2ù¸']ÖD­E–Oîs×÷ç\c}×Â]Ðfz.Ã4TÀØñN&ÖÆ rtyÝ»xÉ¥qÝ,|”1‘ºSHQºúv„š4/ÿnÄ80U¹^6ž5B½FüÖÚ@(À ›j“xB}+¤r:‰«ÇÚúDa'ÚÀ•¿Ü8ç_ü~ÍÚã¸Ð,í²é‘TÌ™yýq‚l¶OÚ÷Ÿ—íøÉe)F&OhòõŽTue/å'¡wcF^<;>²Ž¡’„Ýé ¿Û£0 x^§-ºÜrÎ|a¨–þ¹Øävc¤NƒVS:4¢Ï|tbFÆGÏhG^Q¾œœ¾˜Âü÷ÝÀÿ㿲ÿŸ§ ÐÍòýàÿðý‘Þÿí¡èƒÿ¾ÿÿåø¯ìÿ$òûýŸ6ôÈË6JB¹L/bÔ|Yd¦‘¬Æ_JŽŽ-è)½ÚizO@áùÜÎ%v¦’‡mÏQ¥MÚ\þÛDÿõø7öïjîbiéèjúß{òÿÇñŸÛÿCa1Áÿ°ÿËïÿüçøöwþÑÿmÿÃJ|†’?ïÿAì>ÝuŸÇNC»ÁXÿͱÅwÄ—iˆå®f=¿/Ì1À«iv]‹ZèF4ùœâ¸Òx©á÷˜”Wܲs÷ãoI*Õä³Bc-8îXp—>î´L(œn1@È{õ.ÍX ¡. N—˜²: ã’=~(-YJRLÓº/ZIŠrCm®n"±“®ð½)äáQŒ`ŸXNMK¦(/tãåô ºþó—ÿÃÝ©È0w¿¹SÉ«ŸßÃwúYŒå3GvÍ ž‰¿„k2hz°ªÃOöÛd 1N§' 7§ùw|M^ùáGÀ’`WÏHÔ®˜ßÙ4ºNu¤ ‚»øå¿¾—ï–Y3ËèþÍ :ôôû`tbÜ×Wa´JÇöévÒŠ3±…ŸœGœZ+¾2«‹ë ˜;H}åË™ø6˜Gã‰YgªÍKå±ëRÙuÍ)Ü/äŠÒéäÞ_3}Àæ ÊêÉó3\„qˆ2nÝ™€øMiJ ¯Ñ¾¿vJ_¢œ€À¿ õ³Êv3G›i+qöJv¤ôuA'UþcÕÃÞÑùgm8è'¹å§bvo‹~ŽYê =š,Ük$ÚY®±|.¶ÿÂÃ…ÏñõlœdY…ýëóÂJj;Œ×½“+€Ë½¹Ãb\}{Þö¿hvl§x5‰³ÛŒ+#3Lê"ŸŸ>­T8âD…ûû_Ð<¨æ¸ôô¥e(©XàWÂYù÷rWÙØJRØ5Y~‰Öt?°xOyµ„€í„øvTá÷5ØäêMõ+Ì/dƒ®&Éù´»¦MÄB67ùwSVtÑUDr1 XkÌ Yáô·Qáeµs¬„ZƈM,E®Æ#|b’BïÝ嚺ºVÊç÷©åÞM²½Û½BÕˆM¥W‘|óyÿ3û§„b|ú]†…†¨hê§ªÞø`å·vŸ³•4¡nƒrÏ·V§Æ©©VÒï>–»uçž·§€Ÿè-@ýÛ¤ªâmëÄQöÛŸ-ðÛS-E2eËI²àÞ*èé´¬¦P^Ëh–Ò?ÐDÖw Óæy£½¬èØíC0ïA(uØdTN1¹X%àûlÌ B¼ÝbòhNà–ÏÎòþÃçWiÅgSwè†ß­ívœí§´ÜL­Ë3ˆ–/{¶8$î™faÎ ñ¿ ëžÂËž$–·»Ê@7ƒ–1áYw7SùOFfñu®»(Öµ³ãÞ ŽQ…ô™Œª_2ç¢03°¡¨Ný¯õDבGN%b“õ ‹’¸të<Ôî&èà@h á WGÇÕ ±i’XÐjиuBÛ³§€À_×I¬‚b6DïÙ}œ_¶ 8&º}›Dî=eSQàû§¹_ôÄáïÞÇÜF^Nžý¹!(H+¦:£¼¸õËàµ-ëW‘ï–“¤*ÆÊÐMÔ°ÐuM_ú99¡«29àÓÊØø¸ìîÆbb·*ÑsîE»R™”£èQõ@íçí±úT÷Šê%hd`~‘üºäÅj-ØÁÆä.VÝèzzÎRÍ¥«€ëÜ'©ùÞ.µÄ©Ç‘“œJøžåö2Å:­\~¾wQr÷ákL‹=4GÓZU‹Ôá˜úÓÍ”×éÖ}ÓÛ7eîäߢyD ç¡~Šý8ú&¤åg¯Ó¿pˆo?"kO'ñæR9ïº$8_×Ýi»rÅ’/<ͨjë9{$ÆåY‚:Ï zbtW÷=§Mô£] óRš×:ާ_¶íá<#Fµ`µ}ϹgÅ…ÚOd*ëd« äTüðr¤4ÌZª`6ƒñÒ,è2Y SãËOêÝäbàWµæßëzâ#}w$eúfÚ°TÌ+B›ôk¥n%|<ÐåƒPÆ›²2PkÏ>'ë8»=÷&LܹãLéÕïã–­$æaÎ…RŒèv՞ط+ß‘u»q˜óA Uj5vtZ ÜU$ ¶éíäâg÷Û1AoIúžý:[Û*‚@5›]…‡] asö-±ïpü‡ºJ¼ÍŸeSj¥­Ù’ÛO|WªêèŸUQOƒýÀs‡“²Õ{íÒDx§¹†•ÚJ]×:µ.ƒã–(­"¬þ—‡½RN¸ÏØ¿CÌìŽã.~»LiSµî wçpOj×Ï®ÝgI ‰v;±ˆ#;j6^&ë‡Jõ¾LmÝYbçX¿tvûkô {JrcÛ1ÅMåγ½¢ˆêëö£²:?¤„“kÈ<à'!gͬ]¼Úê&Æû±Ÿù)®¦ÉºœäúáHôL¥ÚGo§qg=b¨G‡5Þp)ûàsgE².GïåS¹c¹ò &tgø•ëðcÐ&.Zc óS—Ñ\.àé“Ó%ޱR7ÖšíòΧléûªfbûiýÁ©Ûª\&”:ü4~eMó[ÿÕ¾š°¨oÄn~ë*ƒ RGNØf–hžH ~‡ÿêB Ïq*sQÊãm/¿‘baèÒ›Õ’6ìè&Ot6I%n’øÅh)ØÝÍ–=¡À;?›tý§ÛÙ¬§g2»SóZÍ$RÖe'‰ïZÙlD4îÕRž¢3­YUó]‹Ù1ù2Ð噟]s£‘F'+›WŸ&'çe¹õ§<䲎ƒoßl³Íb†Vƒ[v–âòÒü|‹ÐG&Ç›u°ä`ÜCg+Nó÷-ûGšG‹B*ó°©÷^fpû ÜÊæ©«ë"⑌¤T©­¯-¼C„–â+ý"®wƒÛ¾Óöm5@„àÏrMóQP« Ü} ½gXÅÙñôt3졸wNøù·ÞÁŌ֓'¦2±¢åí AÍÔ[âîÀÙØ²e}žë/P--‰d—oÑ0̧j0h]P/j6ë÷§M^–ƒ¾=˜Ð9œ3a^VX‹+ŒáYÜxs´‰:Àcð6ÆŒG©%Ò²_’çÅ%^–ÀžY~p³òe“4ùŽ8ìI~¹!`5˜ý‘ù8,éjLYåõCÛ[jwËœß:e}¹†WUB‘® ì1ØûDo_&€j×kRrm~ËzçãR;ºšÏŒèÞøûÙ7À½/ŠêçêïÙq àC$ý°Ñž~ËS*È2<ƒ–¬´Õc¶£ª})W§•~é'OÝ€5§3…·¿¹Nu<Ì岃¹[SPsÏ’…Ⱥžñ?­/…ÔVÍvs¶*ì¨“Öøk ݸœ¿äeŽ?êÝ@aºBÚfN4S.óÌÝ¢q›_tu__V_™,¦7—ʧ4¥ù’½t+g¹Ža4Æ¥yþJè†gú§7”ÙËW ¶ೃB*¿ˆŽ\³-©éÙèƒw7¸0öLkÊiܯkúÌraJ_c2xš@W=]“~'ÍNÐ--Æ·Ë==|* €ªë #i5 a;[ë›¶ï‹aŸj««ß’OR¤¢ãé^®0,xrz»^É)Q‹úXñ0ë}˜Á¸Ì#‡ËüÖØ8®FqËI ñê{Z¢'gü¢­Pˆ#óá̼áŠù@=¥í ôM÷M!:ñ†ñj/ÿÐÓûØePª7¦Ñ±?Ý?ÝP¤æ•tÑ9‡‚œÎ+æöåb¡ïoއƆ! ¸D½õþv³ç-Y°÷7IIèd1õ0Špg‚µÄã/rll")…§ïžLÎüzq5Ü-7/¢jåë·öm¸&®+¶ïV)sã×Âö>ov |Œë€ïœvån2¯w|i6>M6vùò‹X¶›ž)sºµ¿(®A /ŸÛ·èŠ×èUE€ŠÂÜrÏ6»òã:XĽWCZ77áÙwkBq¼Žl( ³Ê0tÕ–Ÿ0‘*[YT¶ÛùPú#@&î3gî<ÅO7 ÛPsqQB‚† ÙW /ïGªÚo3f ’ö(8Á‹õ™Öäþ¼ºÑbcyËlŒ½^UØìsf¼—ŸÁ$ï•”œCÀÓ£Ù&†}›µ§gڹͳl+Â×H ¸ é4òñºën_+ˆÎ}ÞBZ³~„J{y;%þ`-Ú|äCBì e¬æ.DèéþfÐÀi º(µ™îÙÜkÿ^zý~:VX˜y3/ÞÒð‰Œ¬!®õY› f,ùþÉŠŽzQÇD›aZTê®á‹k4 }„ ¢G,J²›!Ÿ)4ÉŸíûì%£D —ñ9jnò&ù½ÿu—·aÜ(¢Û9«¿ªw!QÆn0Î3>uywàºS¾_¥þTU(ðE×œí«›Ãb »û/‘…wYdþªBrJ«Ywo %ä(Þp÷¾L 74¯URæ.ºB¬ZESÙ§£â³óu %“Ñ·M1 ª.ÖDì-~ŽÞýLÁ)ÌÙ•ÎaP]IÊÿ©x¶ß5‘ÿð®%ý¥j[µP®Ðëjsè¥Âݹ{—¨Þ²}޶»­Ÿ˜¡6´GÍàjt¼FÞ•w²¶ö¶ÉOwÙ>ñö½*uNMBÞÔÌ[!+Î1Š”b#DšF¾5uŸÍSÍ¿SX—³Qp&âÍGŸöz›’«ð -WšŸ SäËX`R~ÆUvÅu« ‰/j×®¼2q»÷^¶Õóîm¶Q1·5“\C %+¯îÕt°·iL7´Ù Õç,Ð:bhC‘Ï„‹*£/S |º6+'¿¬t[ Çƒ³C.Ée½YÞܺáI½uý5{å~ÒØÐûª9®åBO$É*&'’ª©fÉn(^Ÿ¸«d¸Îç}Ó¦yï«q]yÏÞ’`dóãÅ{ßã¥_ÄŸoC” úÞÆª}.MHoü¬y}Ò\ó~ûë èuÜ%/@4³wL¢F”YF½ ³\Ê£tßä'É’÷Ìi*d+Üð #Qþð”úCßЧ’š'“éeåöïØ[Oê!éÁÄ×ïW|qJø^r³r¾YôÑm «…Ën‡ÛôŸéǻՊEê©ñQÕ³×^d}jÑîÃöÔ^Ç›I\h­˜]}h6³ˆøÝ>œx­ãS­)¹Ró—(òX» %ß)Ž7QßÖiúÚ‰»‡Én˜õÒ×~÷Ío€Ýþºb§i±,>ŸÛ?×SÍ« ÜáÓcN—û~õéU**‰V¨ÆÓtF͆{ˆ·|¼Gú¦±fˆÕôÁ„†Oš¸§Zv¶Ü6šY1šÊÇÎô7}ýлÉòóÆÛZ3µª85Ì󩎹×…¾×-’ŽóHѯ]½‹Ð}ãElÞ °˜=s.p$¹™dtvÜÓõzêÕbÜaƒ¥kQ““díøOÛókÇá~TËVy¤ ¹Wnj…»Ë}#öpSy×÷öò½¨˜Fãå@ýòÈÜìX:>øŠ±.ýlKÊkûDéuÝ^@ÖÝŸûŒf¯¼3Þ)l³S—ž/œI\+þtfùöðWÔ\ÓËl‚«/ï©]Þgÿœu7ݱš8RIX{o)`¦êö·âÛtA\îö¼s½º6/˜2Àc+×9$Ù0ø2V«SÅý‘ž·ÒÞ²'&¦üüž¾5_L˜ƒŸ°_»«F˜Œù)«MÚ[‰€ât‘74ßxޝÇfVC¿‹ø†)&æÔ&9ççGzê±å‰V•­Í8P™„ ‹—oVŸò;}s·ÜÝ©ÊãwÀÏ>tè­l¿Cµ"Àve¤«kv™]˜=0ç²Ú“ÿ—Ro¦ªWY^A_$ƒˆhýI >:\J'žæ'*ż.èe°¯§ÎvNu0‹µñ.Pãë’­”vᑤ{f‹nw¼ê:lhÓòæ¥òªwê¼;òʸéÏl3z…û´ÝÇÅ?°„ä‰_@? åòæuÈm¹«®‰avœ£ò£0ÛŠÄ^O%nÊÓh QÍIù”+ýSľ[ä­šD×’ÿ˜”'ÍU35ú½á÷ÊJÜ7\Ôæ;ð +ß¶!³\ûÀÈfs'—§Í ¤ù*XݑޢföºÓŸÎ¯g´•~ž÷ÌA¼G9,8Ø­ÆDÀ4.=ýð6h 8zmÞpt1ûªÀ•N°€ƒffóÕäÞ˸’׸˜ÓMkùàøCVY"‰é]î«6¤;WJ˜:%{ˆ(a €jÉk­<îämI¢„¢¥àz¥§ÓVÓÄ_UE;éó´tª¨\jŠë¶ø*w÷‹On÷ÓIôŸÜ¯#‚i”×%hß‹Ž=%ù¤lÃI{ÿhùWÅÒ•Oº Ÿç–¬*Kæ›""ÐÑ·*D1gÀ5™C¶Šº13˜S~ð_¼ª`^Úü~1k”pUbÓòNJÁ£á(ù£T£*w#2bÖ©­¼Z›ÊãÁE(fÿˆÑ,âN创´iKP7¡ÿ¥ë÷±´—ìi•3i¤’:[(«¢oý ì–'Ö|ÌÿëGÈ„‘PµÙL0aØk½”KÄv¥™r€ÆW$Ã.¢ñ\r„ ŒvÕ«—n”<#UVúH?bGbæÛ÷){Ú·ï%× áSaº¯³ªÏW¹9> KfiÞQd%hõïä7(̵g´Ñ½Òð2+·vœí–\ vÏ߆Ùí®0L÷ž2Gl <¾…«DƒEM^Шé·û¶ GÝ4m«ÉR²\¿û©Ð዆é‹UlV|žÿÉÜH¦¿Þ*Nûî=¥œ[6[b ™ôÃUØ3ýã©÷<‘ÐcçwÏCK_Îßׯë’;,<*a·}飥T$,Ö&NûøR†sør˜k×ÜøOÒ½!zøõ]àÓ<aߌ¥¶ô“ÑÊ»âejê75…ãîŽX §aÜßÍìLyÍ.‰ pÞzre²”wPØW6«†@n´Â^=÷)‰ }˜µšgUázðkHá°_½ü©}›Ù­rë “G59=?ÃټÙÁ× ‡´5¿¿JnÖ°ÚÏH¸V¥BJË’ˆ‹›Q¸;ú©„†‚cíe¨ý³b\ÖÜÔA^¶v]“¥z‘~Ö¦%qá²n—•H¸r¢I|ñ{F£âËó+µ, öªgí×÷Ét=éXámˆZ£¢³êùp¹àެAnÍç[jƒü™•ßw?ðºCôÔñyúœŸF…Y’(?¥í:[Sô³m#k Ù[ŠŒËA4‰VôV)òOŸeÝûúš6¼ú…Õ{â†Û‡"D§|6ˆýg‰sj$iÞyÛ'Ìgrïç›ÐZ‡hMÀO†åwL9À/Ü OïßxëÏX‹_Hÿ°N¢øYó®Üšê' ë/fz/‡ïe?Wþ³ Aa!½ªó×m̳TÌ7EÉ?eL¢õå…»MŸBPnþÌíÁ×µ©Ù{Ýo.©Hà  ä#­·î4µ¾°5ýP/}µØ´¡ÆV~ž“¦« IîJšWI¶CáÇ×d›h¥§]QŸŸÕ Ð6&Ò H¼q~„$¦ -«ã¸Jß?*cȾò\É/ãáÓÖªš—øs’´¿ØÛŠ•Ì. b™cí×öïÿ|½Ë%w[PõN¬² ûîSÓç§_èÊ“(ðÁß^KpóoÞ·Ÿ3¸`°~šu9ƒ)øÙ]H‘æ÷Äà«vCcqýYA/¿Q]Öã¸ý&™¢'>žNž[n!1µTY™Tv­$¥FœÔPáxíP±\ï¡E`ûö”÷lIݯï/jÕo¾sÞôN&R¼mˆªH"yÓùiZê‰2•²Œö‡={Gõëc…ëÜÙ¼¥šßME+œîÍÄq Ù"…NÙåjê2hX?¹Z¼ì“aWû6ìûO©r‡uPç˜w°ðgžš ÁW»|¹”Æ+µŠÊʺ÷®S6ËÙþ¢©¢¶•7ym°ßvê!Òj§ š924æÖ+B—räÓFçXsi¬)$Å— çH>%7ž£é“Ñ SAÚ°iã‰MéI–Õn½SÙׂ æMóÿ…ÅRÿæùŸ“™µåÿ™àï€ÿáó±‡b¿ã? ‹>o‚¿Ëñ;˜ýï\Žf–Ülà¿KûÇòFçÌm,ÍíLΛèø÷Åþž"ä_Rw=¯™ãÿý? þ;dú£ãK³Ï{ ÈÂòï?ÿ7uþ3ñ?“êÁ…X\R®NfŽ2\üÿ!ŸKJà´ÿ\Âß8óŸ øÏ^´?›¯ïßWñŸ%ý£§rIÙ<”‘2c³q±´’¾}.äZtw±¿w×Êå¼?š\`1÷¹¬·Ù~“ùéï5wžòø;þ™ç߸¬Ù\]Ìÿ™å….˜™Ù»ý+VíÝ·Ùþ™-ä_Ôïï4x¡n³s{<¯ð¿Q¸ìßYÊß™íïÿ¿­û¢b@WWK·{wÏÉ;˜¹x›Øí\¹¹Ù$þ¾ô?"ÚoŸæ×ïœM÷Eyÿ´,®ßÏÅ&-ÃöGN¶?³ñýQì?2Ûo ”ü×ÿNLWËsP±ø_ôŸ ÿ{Qÿšñ¿$ì_`ì·Š lÀÏoØ%ÿçªükîû¯@ç ´°¼x5ô"Ë_QóÏ‹·ÿc=ÿ0ßsL5·9¼~ýMëÏ’¿‘–í÷™ï·6þ ×ÿVô¯ÐþïšâŸF ÿEûÏ5ô×ÁÒñ7ÿ­ÚÎî––>–·ÿAøßƒŸ9ÈÅñ¯yÿL¹`þׄ'á—ó60wqwxó/ëñ[uçÝê|<×Û_ ù/ý™rû7Ðýùç·É]T“Kò?QÐoÂnfo\ÿÕ‹Ë|-ÿå ø_ ýýþFÛFð\Ä?8²É²qý…ª'ÐÍæb—A×Û\ç6ÂÅuC¿+óì9GÁÿùš¸Ûÿ…Áo†õjú}å‚°»½ÌÿŒ¢ÿ=ý¿Zâß8þ…Åÿ˜¸« ÈÓä|þåzñÖ5'çyKþùç¯ÿzå?#öW/ÈÞéŸÓÿ®Wþ£sÃÆöo¨ü¹òûŸèü½ùü‡"V––&Àó‚®ÿ‚ûE¿²þ0¨(õûâ_êÏÆÿ—+óâþž÷<ÿ eügm¼çÿÞ,ÏÿßùÓv/~þa×ÿõþðMÿsØû翈{ì`ÐE«þ‚€¿eýŸƒÀÐë_½ã¿8çÿ#Ñþon;ù?÷{«»‹åœ¥~Ç’y($ôPTLðâþÏËý_EþO0ÿÿ~ÿçÔþæ {Ëÿf/øŸnÁBëþ»ýÿß?þkíÿÆÌõÿµõ_b‚"ÝÿMXPèü÷Á‡bÿ½ÿÛÿã?®ÿ <<ÿ<ú½ÿ#kGŠÎù›ùsM5Àá à f€·›€w(ÐA ëä–'5oPõ¹6éÿ\+2E–|÷u v'·Ü´ioìa¦çråÚ+9‚¤ïf¿¾§ñ´Æj{-Ï´Öª‹¾Ñíàý#¡7Oß-Ôÿ4XJ¶jîrÅI‰¼–εûQ—׸y‘M›NH),Ü,<”ÍUO™?‚ûE^TÀ†‚Žàü[®ì¯çQ.ÇÛz”ÿÁ餬U˜!úë™þeyãE®‰K"‡Xÿåù‹Óʳ‹l6w†~#öüÓyÕ)šïü«OáÛoz—~SûçßÔäÖ¿&],¬K@}þM³Mð/Ï„2ç'ÿÇÚö}*ï@$uùÈ\Ääü¢i=é‰óÕ ´uÆ‹í9?ò) ˜3z‡‡d÷s¢Àïšk\ÝÝ;ò夜g XÀ€¥Þ+LB<Mâ{E>{ç7 NE‘ º2RÒRÆ_eðõ®)6ÇFƒ€j’m_~±Ã~4¨ïŽôü(~äÿ¡Ä$b_È-áà­´aÅx™œ®D»v [ÓÓÓ£Xž1§ÞðfÖçßßn¦öëÈV‰_O]oΩbôDLú.w'U)VP—ÙÿÈ~½DqN0Ìn„%Û3ŒŠÀ—z ' ÷z$·˜tŒÜ‡ÛF‹Lü‚dXB5¤ ÇûSV½©øà²^-cÓhHÚÔ»CÈB^wU]]]Þ$ÙªÈg0 þÒ~N²¡šú0©u_Àzñà©uQÍR¢"b7¶èdnj Šý¬¯r&ç;Çì16û¾“¿nC‡q„uè¬p°íøÁ{lÛ;¯9_øáœkäS§BªÛ÷¼%ü»WÜ"wpìæQ2V+æ©2˜C$êÔcv§á±>R óŒV=QxÕrÔÄŸO«!µÓyŒj;(‘¢œ38xÈ üу͊V÷Q8yr²—vVϳø›îóvÛ1‹ƒ¨˜_ ù(ãÑׯ¿æ!ð™®Ë=øÌÓ3“ãGÀ–7z¥÷ûžÈÖº,v„œ…”è7é{à¯1.KJ&ª/×ýˆ;ºX¤5¯guË—4½*Ñ%ï¡IQdlèMc¯þg7 ôáÊgˆxWï%’›†N ÁNvñÍábDͤ;ïÞuó ªêwúTrF*ëÔls:MÃqW§E&Þ­ Ö·ÜZnèLzlÖ,óT¬cÆØ¤')_­-•uø¢Ò÷`ù©¿e >Yc—­}8Òt8´ÝŸ)öë´;7ù û¤Oåø½€nëü¸©Ä¾ë­¶ðßæ€p¡©šÀÜ 3ðŒóØåRzxÕl+%©×§r>åÄA²~wšíÁ û ³Ùzšà¹Ì8Í=’ß&µÚäu2[éóøðy÷ÍßF=J×AÔM‰úK¿0¯t  /á_ÿýdzª°øj4üœK¾œPª»›v–eQ¯ñ>~|,‹=Û×nºôõ7r´ïE{ŽCz)$8Õj ɽãÈ~Ûó|šÉRÆ1©‡ìzu³ä«ÛøqnhàNôo“§ßªŸ”…6FËB§£U7«—¥â»XêÐ÷KÓâšxH¢ßR½Ù"¶6O=ñl »’fµ÷9åÊ¡‰÷iW[Ñ̤';ËP¾MÆ^;Zµ.‚’Öèg“ ¨ê-á…´§¿¸.@*]ÄË姇̮^ˆ/bÍ’„”yñ©…©’ªrzç@™Bʽwå$<ød”f÷ò’F@÷^r±xî‹ pc5dªk][,ºwÄdáÆwóJúK»í~¡VýYÆç±v¬Þ4áäB8ˆ²§](ÑÇêèk²ç®$ ¿9šr:* Åt“Õ8Í¢;£Gycb™ªì"ëƒN шÐ_ð6˜ÚÒ†{tòn¡Ø¯‘p­Kk_ÓtžsJìå# q öÞG»Q½°Å0Zué7~5`½¢×~=D… ]áêðýÙ@rŠ#æ©ÛuÒæ¬ 0œ§E7íVl8/ÞÀ¿¦'ÄÍ”7Žï·Î2['öÅ-Ú¼]Qƚܴ=k–´õÕMÊT ›M‹ëq«„¡ÏŸ¬ÕãHTÄ8C|W8-1§¥0ì|)tgBýŠ;ˆWªœ'}'ó›ê‡ù%iëÍ{Ò Ÿ#¥e£íÒy®î4é‚…Uw}WŸÉ'®QÇØ <2$JçZ¸ òa»ÏD¯äÆŽ2ÕqѧØÐ˜‚uYN¿£‰L— 0!¤,•Vy±æ’öÎ!3þ¸Pµ7Ÿ¢W­wÓof¸7 6Z¯×œ³Ú‹ÛÍÃiwþ˜–©Ù¨m[d/h`´›•.@÷ÚHïúWN™­øèU¬4»tß HLß:›uͧü=’¬]ñUNÝ«l¦–uê-2<®Š<Ú†\Ëí¼é{ÔüÄβ½Uæè`ªs¡[p½?ÕÑk¾1áûkìÇǤSÿút+Có»¹I›ðn¦žEiÔï -#œl‡zdzl7Ï,f¡Zi'ó³Ã»eÈ8[óÍ.Ó3lx‡í¯­Ñ‰“ÜM¹>ƒSŸ#ÆúO%VãžYMð›YŽoùà)"îI¢—ÐÞG™Á8Ò…àgv‹mU¼t¨Ú–ýÄ1lÊÞnÏÀ·×E¯b›÷¨ÓR,˜!íòÅP/7ìä7ÆâŠ•8$“=[aê‘™íƒu¨ã†ŽÑ»£Š£í¢Ì%˜"}׳NÉ8*Œ÷–÷ÆòöÑ#=—3½¾PáÔ_LG³X,¤¾Ø¼G&älÛ3Í»“'bÿÈG0½;ÄYcÞÎÙŸƒu©ÐÎ7©3µãmcj§§ßM«ñúíbA“¬Ð[‰¿Gñ¼“ëEƒêˆ¤ßÉ rÚ«K¾ŽK½ÎÖq2_rÐØK…<®Pê¹Vã×ÞÚêø­@dÁ :¥ äýÓÔ;íó—6G}Ò¸P”ÿ³%s”Û†·xš£Hb¶/Š‹´œªçÝ ˜KÛ@wi‚-©’êhˈ}TÀPR7iú33^Ã.À|¼AWÈSÆèŠøÁcªC“J„²n4õEÇjø©zPM•š·ÔZF—m‰™`¿Ò†âM¦Yô`Ï6MJ8¥‹nÌ‹ÉVªCýΔõÞ1vèhÝgì«ÏíB2÷ÛÒü ±)d¼ H¯tˆ "øè¡Ú-ã& Ï€msY„›Ìþ`ôÀ4¸•`•ø£Ó! ót4—`Ú†”©ëņ÷ðÀÁ.ª&QõG€V“êQ¤¶å’ã–øb ËþP0zG†{Eë`T#Ó7÷ÏJÕvsIòv†'¤¸’pN¬Ìèb  rä~ïqØélvÿNÜ'ÙBhS» ·/î2׬rQtਂàls¨š‹1qRFŠ×ög*?…É-&µ4«D=G%¤Fŵ§4+U/äÒ‚½.¯å~âdš’3£[¸=µRZx€Ó–÷é.¶,Åßäg"¢O›…núlÔÔuD€Mª;ë™9Òz;i×÷&³¹ ŽwKM8ÍvýXó[¹(J(Wï##uŸ¼ƒ®^“‹_$ ¡ á$ý‡—¥ÎÏŠ¬>njõI‹ÐýR<>x8S_ɇ±^Æy®?Ð/$š½ÃªžD•æ™û!N¥1s´“ïûv´Ú½Ã" ;FˆÅx*ý‘ñ8nÊÕ²2Ô&å¸Ä)Môn|’(ܤv¯÷îF34èñ“ K£^¬Z¥kÏIiµË²â/²,½~ ¢X„†eð´Ü´&¹«:^ì.Çb\¡ú:Å›'æH·nm}b›á·[Ñ–&…³š¸ë9Õ 5IëºähßÿAs4nå “n{ù¶ÙÙVDÊ—©‰²ˆmo¬;ÆUù¢g¬½Z…5:žÏÃÍWÁ¿¶¾^·wŠÛ’EzG† [§/î\߬ƒÁ~™ÈeH~qÚñ+Eü³ýç‰V/«)ëšÓÐ¥““ 7í©g1o=û‚‘ÀYáèæ­[|´Ø~fGи3œ÷# gà(þzô€’_™Ö/àW´Ç,X2j‘¹wšâz9CfBŒK’ÚÓÄ#·[|/<'| µØ•›ú‡RÐnEFu˜R'cŒ.xÊ}”ùðÃ%]ìùl¾[æ)©˜TóËA‚½|VúÁÓîF’étÚ®3·Ùn¸Î?œˆM,áÈüªŠ†¤ycò"Üy¢¥&ö"BýYƒúf,j|Ö:›œjž²j¬š—àQ﬽÷*ù\hØÎ7¿:R-¬{çF¸Ù3ùZjC¦þÆfnªÏÚ¼$º|Ð@(¡k?""b ƒò;ë ™Í¸Ñ¤WÐ9×ÒMšj†¸ì-uS$7E“äpßÈ)±ÜûI«QÞéâJ!]ÞPú`ÒØéý˜5²E#°w\˜T=¬õµé›c™IYºMËA΃°ˆeÂÈåMÉ2«îû ¡†£;·%Þ¤!ª¥ùŒj÷osÝ-rÇ”ÂǺAнt§Úט±RËÐ:¶f¼Ï#…Á ðÉ)áçÐY·•ôy ïrB`´Â+v3”gé¦G³4‹ßÉNd¹Þ3ÑŽ£Æ`k}™E+YyÞôSæ3øbu‹µrƒFªØˆ€0ÐJQ—NQM„ÂcDã>"?ôx‡^ÝÜ”‘~===5ä}^›aÚÁrËŬFÌ«U(Õ9‰vm­÷Þ3^UÏäZú¦©{ÓÀ?Wë<ÚÔX[[»Ï¨nÇÏ7ÀxÒ¾þ%}ûIÅðÔÞr¯lU\Ó@­1~MgËž$Nßj»Eºói¼U»^¸w1§Y3]îóÞ€ã6YÂZvêÖÉYo½É°—ñê<×m•ž|š^…+`³Æ°„N½ßsSƒïã\vîG;ªäê6>Lô˜o ƒm Òó¯‹ çúšT%˜ôˆWŸ/E9jIåZlP¶ŒbÀ<94e©oJ«LÐ}So àf6Þ7rõ³S³èa?jßiRzñÈelU²F6°€k |EödûMxþÈ®tÍÇ]¿£N“›·sQN*% •” ÍðïAcħM|ö±÷&9¸XÓDѾä—ͤW—YüD%–ISvE0åÄ É•nŸÌ‰eˆ ~tŠp·ØÐÅ埄‡‰Ñ½Ë&y GòÙ9ö$‹“ÕjÀ—¥·j8NŒ“JºG#Z伎WsÏ&ë°Ò‘,{÷z«ÉÐ=: 7 ÙY-’:•óEªÜŸ±|C‘.&à [{]t¿Æ§Äkg.ä¹=4¿ØÂi}í4ÍWw>I…xŽ™…¸t§M&Bq0p¯4Ö÷­d£|7õ“üõ5þuÕÃñ|ÀHÚ‹xÈ.$å€ahàl7!5ž¢P¤?. Ð2'yo:ÕûåaæBj¬ßÕÙ¼r/u Óü>Ð:Wÿ–&¢R+uïÛNuyOnÕŽJ¥BT‰— ȳX»ÜÙC¶YHà'Ïkb&LUòT›ý`¬‡«4ôÃxÚíû,|VœØ¢h¢Í…UØõÓIM‰ÉˆXvÄ(mJ•c2ïŽò"QÇÉ€‘­ä•º»Þþ|ÁØ3fX¥,ÝéäöÜð£4è²Pk|42ÒóºÕ×Ñ:<¨Žý~.Vtcêí ¿÷>&‚êS¿¥XoŠ(ÙW˜nÿ«ÿ5¾ªÓ}%`·‡Ý­•¦¦ÈÊöiŸÇÈ(j pR“â«mW»™îWo¸ªû»ÆC†<êØ²ç/jJ,Éù2/™ {B¬Ík×¥X)°ãc뙊C|+¯¦üRéx^ |ÎØáŒÂ0ùmë&qáS1Âv—‚=qÉÛ^žûÌ…StÇÃÍ?^8Ÿ25lLcáXÝjÈ$Ê®áhœ«Ý\8뮟®·V/ªk­ß¿íæ™ õ* ôˆLô$÷öZÔ ®Ys 1¸æÞ›-§;4ºl Dô-ÊaªiUI#3½ ïVkt+|†Ü‹[L—WÝlf-Mð½=Þ À›{—º.IlùŒÖyŒæ\ÓúÊU>ÞÕìÁ0¢k£âønEÌ8KMãcãk*½ÛÝCéïfƒ¤^AÎ?Ugk°ù¸ÚˆÕS¼×sý,>ÄÈÒ˜æ>¢W·Ž²6tiç±Aâ5lÁó[*Orqy…µkô õìE<'öòé—ê®êµùÎMQ)T|’79›èÜ—ôÕl^1ir”·Õ 0±‹® ”ÿ‰Ž—ò ì¾ý‘²ß/™<ÃØx()µû‹YýÛN9çÞܘKb”Ø`^.uäÝ žæÅ’â×¢ð5h6E1†±8F§˜Ö¬ z=eÅ®Ï;Lì¥ØHê# xÏ&ô¯‘3[£iKåçRuX+\Ô¡æNrkm aÝ›–X ä‹>‘¬ Ö|l”¯ˆ!j¿~ /bTðF"§+Ë(x¶…Z˜tXª¦<<"ÂH©Óü"‹õ—~g±ÆhŸÏuN…0̉¦Dz2+5Vðѧ÷&V~ü›i>ÙËa+—Xì:T™*Ü”6&»ç&HñÙš5ô‘ávsŠèñàÒÔ×J;ÆõúALœAMrë x®)o®öƒdòýª f0MgDYšçÊpšµDP¸¢­pÜgðˆ©€ÇoCn®«W­שŽû~g (LŽŠ{S;¤ e[&.u—ã}Ø!èèžÑç=Xyy61o„.Éý¶±5ÔX- “î†Ë"=á*îÄ'”«ShDäÌ¿¿á彟œú´ÊS–{ªæ[=Õ ØSàúBüöÍÚÐ÷Öœ‰UÛ­{m­²+ç>ah2i„ØE#n½G=ø–¶Z~¶ò¬ ºéšnvÓhÿý#ýC/cé½£¦›ðí7·KÙèò?¸gšõ›Óv¼×=%–Ò®H(Br¿ó‚¥¤ðN…À篙p¯Æ{Iúͺ£¾ÆG:ÆlO*[ ¸ƒ‡ÏŠ|rOÖñŽÙ€îlEeäKT$5MÍ åÍJa)W|=?hdŠõó;ÇåÒÝV®}0¼UýJ9‰¡BOaìîŠgJS¥­8ùÈĉëu×+«.| 3Ï)t`ýviG]ÖÆ–°†§½«•>+•ª°ä Ö#l6Ú´kÒ A[×òÐfo2l-ACõ0y*%ÝN;1ä×ð×¼Ë"ù”éžvøRjCß?¢·M·Œ>WN«Ð[}»¯ß4þ'!\òP û–Œåзj»ë(õ¥8,àÝ:™ÌöÛÁ7Øþue»­²ºÍÚõÔ˵Y¡Ýúˆ"ÑÕ:•d+µ‘;¯ª)?î“« w€ µ¯ž£îé­sX{µb€‘Ë´9¿$”fÉ+“ú÷Kb-K]ï. ¹)|.1÷=q÷;ü%Æ~E÷K|sÔF¥Î÷º ¶—¨ê˜ú³ÕiVyu…Ìד™œÚF²÷L_E÷}Ðûo_l§1¦TÈ|öˆ®‹îG…‚K ¥È“ö—n×9ƒ¤gOïèy´wKhëGòMèSŠ+–¶S³2Ib¾y«õ<ÙJç§Ù¬Hê'Ž=í÷)W8¼£ß Σ}I?C¤Û²œšõåšñä8HϬˆ¬zD ›9k>&§qÞ! ð¦1%®”ò'¾5À½é¯‹o¨à#µq¾ ªÂȃR Á ;îI¦$ë v‹*s 3-Õ>x<9¾ƒ=ŠGœ, Œ° •{ä}VS6]}b?4@ô>ugXÏêuŠŒH[<™ˆ\Ÿ‚|˹9ažâ 0fìU\§Ê–ujã+Þ>†ca[a£sái£øýsÏÖ‘WX ÚMúöQ¼ ôh.JöZRÅ8U‰qV4UA#Þú³Ú£cL èF•H\þ¦ ¸zÐ&:wQÐÍÒ. ¾¤WEûëŸÀ†rÇŸ'–U%Œí³KWÖ«`»ÅìöRÒž£oïùge®oêãÕ—WÀ©™ÈŸáçV lpçœËM]vÆ{‰¹-ñIî±÷Ú§Ür¦HçÈÒ„Obüò<>QØn‹TÇ–›Gˆ/%L¸ö±Ô²»¥`VK»ì„g2Hº*|²ç_þJ“ôtle3š®zfùlãwìç‰teõYɨ„ãû#¡ûDŽfJ¨-IŸ'¶¯¾týQj }ȹəl¿»Yo‚ŒEÞxFŠW<€F l´Š„’rz¹)úøOªº‰"ëÁ›–ìYáF5X(ŸþZШ^Û(:M*ës½ƒø$¿RÄ/—ÌGÆbVŠ› ±žòÝë^wÓ»5³‰›èZ­=;J;ûàXîhÚÓ ¾œìšK)2Ú9²9àܽ7ƒ A>5N²GG?PÊÔ²Óå £®{ó-(qËcÌÌäƒL݃¾ï¶G8+Ê@Òtéf˜;jX÷Y3^¤º7qš£HÚQÌ{gpéÔl’zeµëJzZƒoß •ŒïØÒcgÚunÚQ–y(7"|€ Vi†¤±hC–õJ—“» ‰j¥6«úLµ¯"¿%¬H_ÜIé!½h†¶ƒeMÕ‘xH~¶-_9•¾5WÁû‚ŸN2¹åæv3Xµ-•©&'=EãËWŠ9&*¦>~kÈhô]>Üóø`Ü<®“Q”Ùý,)ü… ’ûÍ3-YÔ:Õà+‘LÓ÷½byË=m(q¬>S»/‡íý8¤lzò®1pNzåQ'9hÜ‹ZB¿®fò²sBV¯>ö* §RD·1?)½SKP6QM°XY÷f°Ø«WQÊD{3ˆÑ¿u`ò”À$~Ü×9y |ïAGæBbÏì"¥1ÅúýÅÑ¢²ÞUÁSoÀ.y–#ÉÐ{èî€M‘ ɱ½),¾ËZfO„ ËÔ´°ùÈÝXëZ%Ì4Ŷqïxü£‘Ÿ¾Öu#ˆÉ%"Û’QV>¶˜ë·Î'Òdwkð°ç.EšObŦ,&¬·+rã«‘õü!!îÊ£ü Õú¯ øûÕ‰ªHÜ©85 ¶ÝÊtJUÑy g€M`Ó¨|QPëDýׂ‚#3—ˆ  GˆÇÕ&ã±ÑÞ;xƒfüMËoËÙWÐ.{JžŒËÆA¼\¬€L–} "»õM–A[t椢7U€Ub2îŠÉúÙ¾´ïÖñl“FjúìlAÅl‡ ¾)È~â£Sù¸º÷Šh[‰(–Ü›¢©·¬Û¨BÞªY Ë\ÈϤþŒ–ÌÖ±Û)ª=¸ê½^U«FwÊ·‚k)L„1òPsÕ«Š rY´…öÓ–Ï´!gÖÝB Ô²§ë½—È媙È|×0q½r ’lK1NCÞ-aô-@ß¹¾È%{¤4”:6hu5¤-m” Ýš{&÷|CÅñĽ8I£ÓéÛ$ÚÐ2ýlÿ~«PEñ ÍÎü w(Eoyzê^&+~%ÿÐw?ç§bfï›Æÿ†|nÖÖ¶ ôJµšWN ê‰~Z £OŸÒ £ˆí;aq_Ýv°rBòU+šã[áãz²”GùF‡Ø«äÊCÇî2:Ö+ÍoLè_œ8˜Í–='šqJ?ˆ‡ïß™õ Ù¯:›\–ñÌÁ±ö {´(‚fŒW®Û’{ –Ó]sÉ,Q€ýRp§âRošøîÜlF;˜^²Í¬¨yÞ~zmºHóûõš·Õ¼3d:£Ð½$Tò,¿ÕŽÇ `Òi¬¶îV‹ÃÒÊpöüWDبñlôVÀÁ"ÿzqèèÜ¥±‰WK“>ð"º˜478h[‹‚œ0òK–.³¦Ä͸Ü0˜GÎqtîÊžéBµé‘סÁ7*Ÿè iŸ|MÐ!lâiÉ; àå[÷uê1}¥³2ެµ®Gñ“¤Lüê€ ¹¡ßÄâö‘$í¾ô ñà]Þªr1 ÎaCR‚³òAu\iðÁüÚxD9àÙ¶»à«N¸f&€š_¯’±4ĸ€úõB­@r[WØô¥S‹\g,o™“œˆç6÷‡¸È‘7&™"{E®¹£§K~n³A7§ï>¬#±Åà—Ê>Ñ>ƒIÓûüàÜcŸìEÏ ™3Y°µ$Þž‰1==Áß˪%!YçÈ >`<ã3¨ä -<ÑÅqx·:ÎPLûQ”é)ÛnWøÇ æ1p`›}Ïp¨³PJªdº Í°iaãr”c°T®àŠ}Vm²§¨LšKžÛm#Ÿ³ ÔJõk;ôõqÏÈzqÕC`â¾¹À&× 4ÂoœÏn©u:4T4O‘V¥35 §g; oh‘HÓ¢N¾sóÔå­¡µù¥¥}§jçö9í—Ñ·|¢ûE@Ãú8 øÚ£„þÁ×Îp#f=qTŠålÙÆÒäp îØ"ñQ[Ã@ggZ¯œ»3@SâvÞSöÇÈç7í² ôÂ0afNx=hoà |:x÷bVoý3ÉÂf "œ¨°× Ýñtpª’x+P4ˆfMSGV(ÝöQêÍM‰ÄúÒ¸Nç ´g.ù†åw–™L¸ËÚ”d— ívÝ—ŒåµsÐß{^Ο´ ŽŴÉ6KÓqðÒrë<*† Qø¯ ´ÉCóâöáH6­Úµ xõõD¡àP+i©kpé«ï©±îAPCÒ6sÏ¡ ¯ª—‚ÍCV7:ù#ätíòsZ²=MÖ7ÎÐãtïG0îW½¸Ç¡:r3~@íQkŸ¿P¦Eÿìmy–òúñK;܈xFî¯Ä,›¾éçyñx?:µ\®T3 nkÐb˜hû£G2j^A„ÄQ3]Z~GÁ_­l `û^ÑÓ<‘¹¾ûÒ•M<:Vsn©|»Ž+߆&ãbƒ?ÝÐïóÖMr™Ìa_j}°ñ¬"›¡`ÖW!0‹‰ UÕÊ&cÖˆGç]bÜŽŽ9œcy)üâìUÒ²ÛU# Z¡»XŒNI?ÞG#X¤¿ÝîÁÖhº$i4ÎâÖÄù*©éÅi÷ îV÷ýÈ«xbºR9å-ì%òb}𙄼™”ÜÌ4½Mèàã’B9LIFB]UP3eòUºZÆJ-h®ý­téõÄÝe˜<ÊõB¡b*Å‘ª<¢ëø}Œ1äÞý‡3•ãž>1ÜžÑ-DÙbÌóce±"´ƒ`’¯ÓNw¡œýŽwU§NæYÏóʺTtG uÒ«Ò\ÔÏŽ¨* Ù÷bã.9ím£yt¼Ê˜çùÚ°’A_†ùaœ$¿»§ø[úšì&fU9Ô›WmpŒ¬dL¼¯„xw -·op3wSEë'ÍÞܰf5€»¢¥]:›=-Ä÷Æqí‘Ó&®ãV_†{­±töS^!1?ß¾¤×¤ƒ«-of’H¦ÿ¬™¹ ö „ÅMJÉ:¿Ÿ®U‰8ñVŒN‡–Í/Šs> ðy&úÊÇH†ò²ykk$'âæè®hr·Ø›ä}"ö#¹ÑjzÉ6î éy u÷׋›­ °Éë Ó“5ı¬wŽO‰õiRŠ”bZu ]ôùj7âÙ„êÔ|ß›a­‘ãsÄÄȓܵÑÚÕ.½b¦\ïMÅÐ5L_–H_o(šlóÆûÇÃÑOí½×o„OUÌ¼Þ ×{‡—)l­Cψ&-‹tb]rzëÖ¹§"èœ>fjÕ‘ÌHÀAJoy¡¾NqJìÆ¯ž©^¼z«ÿAd^)Q½*úÀ}S Ч[Ùƒ0=QÙ@JÜ4(lWxȬ5ÔÅMC®âLÉ6K }¦Û©z­ñ¢&õÏüŽ«OJæyÚÆbûŸæ."½ø~`^•>Mö(2ccV°;. }‰eÚ„ÝýÅ9üeý}õK‡ôÜî;¥KÍ›'´¾'œmÛ S3÷œ ùF²‚+¢žM„Í|Ñý5EwÖ)asžûÀ¥jBð›ž9H¹®Ä©F-1Ý‹*TR|SMh®Üv5xjÛÃ#ý•‰kJt×û{Þo( ‡WŒÒî—áÚõ/•-äꎳöºEüfÔÞ¹4“Ù0&ô7l¨/;ÝXhfÍ„à¨å!!CíýùÈó¤MTY*8e±\)ØçÍÄý':Œ'ä8ç½=Ù—EÚ±“Økyzꃤˆ@¦Í‚í¬à‰ž2è _L’qÒ䉌ÙÄܲúŠ|nß“ýò¬Mý³ªiŸõ¨±Ë_½¶^4{*""bÇo$“ K±YS¾_µ-bÁ‹Iy#Óëá…Zå~8ü2&lÅzcðq«&zb3ÁJÑñgøÍp{¯¶ì8mñ…½jð$­¾?mÊ$»³îM­¼îÐ,FêP›.6Z¿Oá“i£¤æ>æm°Ç= ~xåÚÍØÑ<ÒºÙH×ÌB›^þð.ëÚëïB¦W°Å’á˜AYE»^¾ÆO˜ºÌº6Ö{‚Þg…8 ú¾bN¥s ¶$ª g-Ç^‡ŸÏk¾ç~ËJq!=éVỏógu@4brQ¸™1‰Ú©ñ%ÒŽëÆ×Àî%œš='…÷+B’Uš{ õ]q![PlŸ“IîÔSø+å:Üõ*¹Üy‰[_Åì=;_”EËä¾@ \V³¼êX§ ó{G9²ižúõŽøÖ ëÙëÍŸ7ÃFª‹âÝD:_Û=+ÿ`$ULýŠ¼ì¦‘[ÿëž}Žn×Þõ9¬c–¯Ð–¨;0ƒA!&Åo(NEøqæ’eG‘ ÆÚë${Âz¾›x Ò–‡™K!Zc¡jÞF5aÓ?>SW¸MYýÒ(Š·†cÉ\úêà\g~²ŸŠNN=øt†²5w¬u–…̘v=q锨(¸Ç¨jŸÞ¸e éŠ:Û¹xÄ ÃÀýõÎ1¬ë˜u$&·Ëº—Âa› Ìòª²FC´èô{¾Á\|Øõ$Ó<Ññ*E!ªë仲ÓÜŠ†nA¾'\gQ¸TC>¦rV‰ÊÈ/?È£ø^™Nûñ4úû²g3^à ci•> k‘œD]U—~Xï¨f™üžl^¨ß‘Í£„…gŽHeµûuHÈD@Ͼ ÚËwÀ¨‰m»¨ ÝmXf¥‡*—æí„òYÎlœçfø‘AEŸVtJ!­Yà7¥ /ûJ“4tW )q†¼üÚôþÛKvžÃz®d§¦¡Cƒj§Y´£“JÝñŠØ—BÌU|ÞŠi”[•}EÎ8¦CÞÞò˜Àu¯Þ{ú3¾÷| ?t¯ƒÂpõ˜*hBåråÄŒšþ|.yúäÈ…kfù uǤ®wýWgîêëd‡^¶ë•°<#à35ÊÓðS¨:¢H°fék/Ø\”ÆŒíU4ì˜ÃA5Çky~_±Òõwá/šfI³*OÓë†`Š·¼¦Jw#è«¶…ÃoÓ”§ò—*ñ÷§ó4Æ"$Ó”Ó¦ V—ˆL…‰ ^§F˜ªRh;í¢Â—>}©î.á7ž“yï7‰ÍJ>ÌàYD£N¢y‘é¹+ÏlÑKšùosS{rÔ£ò}_¨ãöZ¶Ot_ò>ðl_{ͳµÍ Ûd}¨NÝñfëÎk¤¶í˜“V]ù°¯½lÁJ,»þ°%¥µ©ôR^ò˜CX5ß³é™qÝ6ÓIiÌA¿T9¬{§Œ§¨~—…ÛTó=6õé4WÓ*cbï×g¡,‘$ÓéáµÆ7cHÃý^óÝ ¦´xüxHñ°Xœo÷ìƒHÒ7Áðƒa„Éc9ý$šÒAf3åÉŠ2-™lÍuôù"“dÈÔ‘âx^?¿Ê­›Ò/}§€Eüt“¾L :ñ£!“•xŸ½EOn«)ëd`\Q;)¸²ï^Aö€ïD/‘><¥oZ=ÒšX$ØGO ðËåàv±•áéE¾|^hÎ'bpäreÉèÕÂæÛ舃XŸ åî—i¢+úùþǦTëe^ £>"ŒÛ,õs׬w½! 7Ç»+¶¼Ú$ #Õ vOw, p°x žˆõP.%F~Däc_3ž¢ŠCé´%{}§K,È-Š(žÙh‘¦»—ú)péÍΪÛÏ °9 7€þÈBV·fItáS˜À ÇáÙ¼ƒíØ‚>¿•ÍgÓÝ*L§”¡Úùñ{p ™÷f”_Lê›ûוˆMž‰M»ÙiGÌðÛ‚3º]ÐP÷SàGð .M—ƒI[Jçûä¸Ò>Rç´ŸÒÅúð®Í`dmúÈŒ,{¶˜˜ã )8~Äj$0ïgPwë$nÄ ªø]ì‡C¢d„NI}VOV> µÁ*—!RÉm¢Ò [´ÔÉÚ­?RYÊæS¨¢K· W\í2,/ŒrTÉÄ¡œ÷.V÷pLÈB&n 8ô/U7nÊ;=‰ºáS.×›=^€® |@ôlÇójvåreèrŽçñ!ƒOÕL£ Ÿëކ ×+·7J6±#[õCzü‹¶Û¡!’žSãǰÙ`¦‘±u·§3åþ:¼åkÒ7¨íF?ŸñàWɨ×ç^­œÜIl%'špØk¶dØÌB®Å—#‡Ïœ‘ñmÀȇ*n/ÊU2› «S@£Œ;‹&§»ñ²×©a-³x,2Ý€ÕõŒŽîk'{XÊ3ýÄ,ó¤•"Äç`Y‚¡öò,-Ë„‚˜ÃóŪç‰sµ@]çtQy~ D3ØñÝô×3ÐŽNÖ@÷ÑqMAY`Ç;5õÙ>Oð A ýýÇ ÐgvcÖ£ó ?\HôÙ{¨¾û\[µú#2;ŸÆGº-4Õ :ê…pë Ã*'##PõK\åÙOǘLþã ß3ìóƦú‘aéåt£Eƒ­GjŽGCvÙEñ²ÃÓ-Ëå„ SÓ:upíât›ö/ £l^”Ç©É!ÂïדHiwÐl¿ßé3»-\ЮÖ;üzp¹‘ïCÊÔ#‘)íAqñ|†ÎÎ`ûª¼6¥Ù;L…Å2¹Á³–D8’A­ Vv^sÝ[ãÌ)®)¸ëN¦oôôR/#žHág}ëš{'iÕ·$åëe“5tW¾9ˈ MûæQ†'NÜ€V¥n_uçIø‰,Д¸o[¾QÛŒ¢¢ZÀlKK6{«G¨•q` œ!²'8«eÉyTÁCúª¾½5Pô^©šc›÷ÑSÿ 7²©O¡º!s¼Âú®Õ®Ö_2zª³¯_Ç~t8yö]­HíAÏ([|øñÞhåʨí!ø®aUËÁw5ÙÔïgôu?LjÝV™õCÏÄÖ»k–VPõû Z¡³žØ‚u…¼‡#ÙûOîÜQ\/k/ÊYnSø>.g/qoíL2f¬÷¹dm¦“Ä5å½”`m<=w·&X|½§ÖÏo 1̸™»¾Û©‡®Ÿ> j–SíD™š¼Ÿ!_O–w1¹Õ2Ûw­#MŠ´OTÉÖ}înößGyGFY2æò¼A.g‘‹ê4&|ígÊ€Ï]5ÊÞvm?óôôDAòP¶ì¼µ½9OF÷hÉ6™AFñQ™³˜ÀÞS"†µË÷Ç@ߌÜŸuØ^XÅŽ\MM;èвÌÅù\1=í×ÑW„FEÆ s²r4ÉêÖVc¶àǦâè†ñïÓ hR«I•ü¤¹À^`¯”"Ÿ†K‘ØÒ@,yycUHqÂ+Ãz¹)’0./$²Bö„VæDkµB>O0!]ûìÞ3Qwö}89æÔ;\Ð<¹! Žõkø¡£\¨àÆ<åŸæþΤM!è¶ {Tj}èB»=O4¾Ð´-®|<ÑÓÙ÷Úÿ­j­ù å#yöÚüóõ‘’Ÿ^«]÷Èìš’ùƒY5îô=Î.>vØÇ×6+¾òzO7ÛšØ× Ò%÷ ÎNJ¬xÊä]§&|Òé \»Ä‹|½øˆòa¹N•<Þ/w/å+aR27aØd'Ô#úÂ)§S"(áĵhbœ”HiÒË¥tÏX•DnxXKï·ŒYXã:8†B˨÷Ń$<%ÕÈwÐÎʇâ®%Mž¯ž{"ö²œŽù­ B}^º$!•,ÑA(Hž–© 6Û^$ÉZUŒdæß{ü/šKëŠqÆ ÕÄ&ô—†ë• ©sĬ“÷ÌrUQÀ·œ—r-×&]³¬[M¶úšu …òû±ß\êb¸N<ÄÏÄÁA¹ÒO®L»{¡‘ÞÝD¡£¿Š¡º…'£D»ßNYÊ‹¶~‘ì}f×9 ]ŒÉÝâFÀ®ÖlPWuJ«Œtˆ:ü²vɭ߬ éPì•Pq[K'Bñ[‘¿ÐUSüb“£X£½pê5±A²=}ró%l&ÓöÔ€yÏåá–$bK/O×qÝîçù.ËYIÎK‹Æ‚Ødl—Dã#Ö¤HœÌ‘®RŸ«íÛ©wrìf‰>KÑñcjJœVù‹ yg–Í;Õߘ R…l ëYC7—Ýí\{<]( š³ÁÎŒÛe=•Ü%˜uË8Ä£õüfï$&Yý²õçá¸&¾÷Þ˜Õ_b9}•g²µJ kåVe×~ï¤çB±ã} ²ˆ£™ÃÄï±@Ë—}z )‹lE<™öŽÌ²dF)Þ­”Y?‚;ÊOàÕ7o”žê6ŠßD²g•xYÙd-yi\„=ã;íwÀZwEiœÔ¨¦¸¾ Ù¦8ZÈô{A%É6åcžOrr$äSNÒ;“Q¬nÔ+wÉ”*õMY¨Ú§š~€œÝïËdÇOY³ðÅÃ1ÄGÕ¢ãçS©&$¹ƒNw—¨²uMYdòYlI;Y|Ñ€%E‰%íY-µ/µKªôveƒ'©'8 ®ÎM†<§, 4ŒªyWs¢ACf¼1Ë•\½´8Í·Ù6]6ÙŽâÙÓ#¿Ìþ'$˜VwtýÍ`mZ§kŽVz×®Q³ÈscDžÝŒ‹Ÿ„Ò"kÛý·ø#“ˤ惲²¶^­VDN2Îûæ7$:“Û8fÜgå¹ga¾µØ2¢Qcl*XÒdïk;¦QõB§àfÊa;»NÎöÃOÅ[–æÕ“8å×·¢J?o­s]DO—Ñä¹mkúæ|DÒs±Ìoí†$®Ýò8f<êt 1{ÄØ[÷©Ãya;¢—6ïU7~~(äµg?à­Ÿ;e×¶ZÚ!´Ðëɢ?Üû3‰pÑ2ž9h‰P±ØÕ’ê\/'VT¹Ü‚Ä9Ö/÷ÅËi’Üh}yå°§•ã²ü#èµ²P¯/Q/b…¸iáw[pÕ{;]¹†4?¬e”2~ª&ìKß'ü^jÏ£¦µ‰;¶ŒÛóºr8GÜ ÚäÉÿjÌc2ÝÄyð£KȲ˜Óù3GmBüƈg†ïe¤Ù@ýÉý·«Ò?+¶6^{¡\:õ¯‘B£áE¯Õ5sø.÷r \¶:W>Z¬ƒƒNîcìÇ< jUá†å圈÷•ÇT<FŸeŽOÌ>Œ§(ºµ@–DÕ=,#« L#…1¶›ŸAa“ÞÃjš‡æÎNEæ4ÛmfÌ®Ÿ7%+õL,9^ÄWG¯ ¥C÷N­X¬1™8âêÎMµ4^·K<€ÀbÖÛTjR;ÕÛÚÉèÉ|«Ü^”õËÄKu$û)5¡ìÝ’ÄA /L¾2/ó‰Á0%±Ø i·ÓÀ„ŒÏÈìÄÒ©¼Ãf™Cݶ}â¬1_ú©¶-ê–çvwZ¬€¿ ÛɲS%”Ñ™!ø_¥<Ò´ô?ècµý…z"ÁE=’“‹v×´›ÁNsN6çâ;S­láeÖŸµéÒ²ØÅÑŠt_.Ò‘Úáй¢[⾑5»p¡4>i[ÖqóÙPÜ>Þºkø³\Ù¼Cëçgb0£ÍSüT”¡«F5hñ÷‚Óœ ߪšÓ¢:–Ê€[Ns‹e=J‚ÀD.cQ#8æ½ë·àý:„“ã¶É:é¶Š/fÅðÖ~q™ï¼öxyì7â>9Y¿c‹„\J)¾;ùÄ#>“Â3¨jûùfú®c*&@p«ž ëƒ?PíD~gï¥<Ö¯1È|•žMý-„î/O0Á­ݲ›á  ëišj¢Œ–D³YàņSïèÞbt‘Œºú#¯ÑY _Ôf³®]&uæ7Éo„‘ª‘Ï]tòƺ‡"îúDš7¦:ý^˜)÷ñÓæž(ý>Üã;Ž^eªÜ ?þU^y$ ÌΑÔWMY¤:5øzof€™Õ«Ër•«*Ûªè$ûVȃ¤ªÎãéý2„~¡ŸWÍäþ«¢üªé½ãÞÖØ$Kä9rDáàXÜ Þ±:ØàÕÍß뾟_Ý !Ã?Ñ•ó˜Ä¡¤^­n$ÜgfÜê§*?ÝN„àüL¼2 *[]k‘ªÛØúŠºªD_ “´a"æ +ù6‚ÉrŸ{=œÞÙPï&oósFÉóIÇ\Š@0!”I°! ®»ÚýxgçãäÃÇ.¥½ý’À´#ý$Yôâ€ÈªÜêÊæ•ão½VÍý èÛ±¬`N¯·ºÉÑÄ|„=j’¶¾9¼ôH6¶BÃX€â´V7xt¤n~«oøÂþ½ÆÄñ¥# lÏÞdÏ >ñ*KYYž1_KvL€á„üú\ËÃOÛ÷©ûÓe5B’Ñýò?$„7À-l Ø‚EiÜ.ŽC¶X´’/ ó´ ÇW”ž£µe7-“%z® D.Møçyë§U—´úůœsBù³²º•,l7\¥8NЉ”•ú.ø.¹mr}rÞLFàrÀµRãˇ±¢}.wL|hÍ€¹í”Z›—AiÎÂqd埧"/3Ä&qÆò÷#ªá6>w¿tLïýyʃ£r¨’Ñc¿soô#ÒÚžÈM%Í8H“  7!8'w÷ iÔ•‚¨ø·Ž‚ÄQÌ õlí±Y@—W5ï&Šy>¶$'@¨~/›´Ì>l†ÿVPÓ)η©™*5°™“ ¯û kîÍͲ»¿.Ø­A³Íc a˜®² ¡tÇǸ¾ƒ ž÷÷VëêHÝÇŠ‘iUÄ-WX7·”Ô”`׋nJ ÆgáƒÞÕò²Ó†ç]7 ’‚;ÝžÕîhIòv¢\!ƒ>–$ð{ÕûI¥Ùdõ^ø\u±èmyÁ¥fÕcø{µˆBh $Kwˆ¼öÃà#ŸXš²6uX¹„_Þ‹‘ XŒ JÛ®9L6Øzõ*Èdfé*VÔW¥} ~üެž§¢Ç@³pÝv=sÚòõ*¤Ó!z1NåÎzg|?_î5F㻳Q®·±&‹bV¾[£ò*Q¦Û¹pàl]±V ™ná~”“"ôýnŽåáeÞ²±¬\Æü­‚Oôí–y‚öõÏR9W Š©“Ö‰ÕÜ6Î0u¯Ç‚Dµ,Šê1¥f¤l3DÀwe›¦øÇbHNæò¯_bËsK«ûtÍ(ˆš‚Ð1ß„8Ë¢ñ´‡n|5 òÀ㨇EßtîTÚ¯~‘õ;M­Ç®Y õ²€rNéxÏÕ#¸õÅÛuµµÇeãöÆÈÅe×Cyž=r³pYÿûúŽw‘Û»F/ÂXéé=52'øcLEûkRKÞø_¦ÙžJgEÔ±žÓRk¨Úqø(αÆ@-ç>ò4÷µÇ—tÅd'/} ,ƒY ä9–<œ±nJrHüzEèÑ2Ñj¹!|xÌ`0ù››Æ–sº´FÙUüÅS›Lÿ´¡6× Ÿ¤àp}c;ú2¬ØPDs ;ˆ8ï§6FYñ”IÓ¯¤¾´ÓövŠooåÑüãâÊ\}¼±+ÜÔß\m‡©Y˜¶ï×â‚ç. †çG9QŸè+m¸Çù7AÄÀj£ÚéÍ Ú½÷æ,ò4Î,–°aÅâAFçã°®øáà*ã ðí+ÑC0€^Lžr&™:Lía~_ñ˜Um„Ý ¬5S?iÅíW_x Ѭ¹”‡yt¥ƒ[ôœ µ,\³<×Ë%½üú‹b ÓȘú]|·#ôãÖâèöø€okÖÁK`ÍëD“ l¾¨ÉwçºO1i¹ûÀÜ‚EpöÑ ¢/ª3 ©g46X=;ðí.â«2Q Ç}ËÒ¥‹šs©%íŸ)㬠Ù–Ú«eÙG|[&@& É4á¶HÛuí·Ö7i¡ÌEñ‚išöÍÆ)8ç‰y»ÄE-`ÝŽ­T¥ö„ L³aK·ÌJÍñhwQ$ëºÔµQï½ç2nï*Oµüú’ç ð‚"/ lœÙ(#Ó™=0:»«&a¶€&:XÌÚÉTž³¸rÇÖ]wþh—A/*Gê‰(ƪÜò¢Æ“ÁÇëŸÑF‰'Ò0ÆøÑHC[°¾±Áºh‚džQª9üͺf¤ìÄV:g¨TË :bÅßkµ1Z‘/Vt¹-ÙeoG+u@˜}fYxæ&§Fª}€r{ŸA}…ݨÕRW‚yÅqBÅM«õ”Äþ”””ÔSt ÃE°Û¹CûC ÑoÃ""®ø d)É©dÛÚ—Oc>ïß ±bvz¯ÑúriÔÔTJÿ¨Å†'ß-¯ãºs§Ÿüôý­ÂÞs,q¸=íÐ[#»µL'~###ø)*qkìÁ਀5ß$FægPå˜b#Ÿ®¿]åÇ»ûÞ,œ=‰'Åe2o[÷¦¦ §VV¥»å¹SÛNó}3(€Ë('vê6`ÉHØQ[:ä§’›Õæê(.òã[ôû[1Aù¤{ö59|Ô†ò[¡½[•HGfí.Y‡ì“‰ÍÛ:iس²˜¶šmW}‘0lÀ…V[Óͨ——˜&f‰ÎÅxçêíåÙ³³ã*ë¡­$²ÁôqJ¼|Ð[éÒhb·¡òØ;ßHö‚éUòÃÍ *+v øî1l!x¼¼1mø÷X¦ÞÐ;ÁN¥¦²Ô]Ík±Ú 5X¿¢åÏIêç (ÐÏF—M½îm1¦Ú³Ã€G$h^Lôê8|JðAx&6ü z³(â¬9âñ²sÙq©A£ûp³¢'oÂ_»Â^òŽHßëšEÞÉN|¸oªmoø‡fgicœÙ^+kÇܶlD-_'¿a‹?’ÚÙíþÕ2¯ëo80°ÍèdÎNW1Ùà:ÖGV¤qßÅ¢"‡béýoט¥râ° %ÓÇÝú2WJ‡W|“vàÓ—ì©»'øEî…‹}Ä=†íýðTYùš½up¸û8p4ËüY§÷Céµ)DR…ŸOfµ##óƒN»í=°šOS6–éƒùY›7 îŸ*f¥—L¨eëåGʬDe1ÅŒ>à· } D.åéâB±Ñ`O”×E ÛPôOU4÷àšÔ*åÔdÃëGÈâÞ=e¥õJ ?9°Òw~‡¸IêGÁB8ÙG‘OÉ~o“–›ìhº9Y#ê0ò¸vІ lŽ%“žæ9ìMÉ{‚kŒ—x,#¶Jøg¤ßž"(b®5Ü®Q-{‡8h‡Ìä¶dK^ÀÚ¡¿‰Æ½ˆ‰ž›-ïü†Ô ßl{’~'?Ø*Ï+’è‹Tˆt¢È­ïu¤ì‰ž‹ŠÐËÏëšhlWOö]˜™©!t@NÇQà‘Å逗ìáÅfÏ DôAþiuçžùĺZö4(ñÚ S€Á¼jCÁvˆkdZ¤çym‰]ŽTx‡¨@ô–Ùþ¶ÊÃózO ´ªâˆý¬ÓóôŸ@3§,#´™Ú\ÐÂvøPc¢´Š\]ïÑœï˜SàDUŽwxÌQ¾RÑ÷*µ|“f¬Ž×ü*Úÿá cüÑAó‡=Ë„hœRÉu(Èò}K«*s ãqX¾3÷Íš˜3—™¯æÈ,ÞL„Á ÂÜâ3ÞfõŸnv’œ=dYé`jÆî0&GŽÎX0ú¦ a[gDŒ:›ó\¼Ü¡¹Ÿ}QVßËDJ|æmÒ˜?Ì·?ßÜË,‰PÜu}uœšy3( ‚ÄÎs<$e¥Ïð7é½rãÀ_+†æ$ íÆ»³â„¡¾X˜Àyåiq…Y™½PI_òG©*Ý™ä$9S­y[¨Ëq±QãáåCºé²Ùf×ÇgÅy$~ õ‚/åt”t.vÙBö:–÷˜;ãøöÀ`p@¢7.“ôp¥uü^}ÈI÷æÍ4Ïso‚¿g^.š*äÁ©Ñ Yþú,”|‚zô…À‰ÍöÁV©U7ãx¥ƒãéÉÆ9ýøÑåÞ:IH6t[üÐ'#š7¤bÝNLÎÓ!»3e[-8Rr˜RCö÷³Ÿc3_¾Qh^ÅœR¤±xHmŒ]ÞªžÐCG BX.æT‰Ã$jV8 Zt äYgÐ0ú6OPôQ „âð¸ÅûÈ+^=ðö[ú~ºÔ„'%gþIH¯pæ'KL×SsËg=©§ze)Vß“,.”‡ ›²Yël gÚÓ¯I/êªA’¶ÆÔªG02²æ­aWà´”=²ÏìvܪMê©n5=®ÇcÖ—ìÎÝ<ƒOd×çž’}“”ø™¸8V­Í؇Ö‰ƒ£&æìø 4? .Gï·M‹ÄæH³‰ º©A=Ù®à c¤$‚6:æ‹h«ÁVƊŬó­Pä#Ë“Š‰§miU„·‹œùD𑞛Oj§„팬‚Ù¦"Çtt(ÇœpX•×}KP¯¤šc";ð’½@‹klN‘¥.Z!‘jXâ)8Ûl`ð ÞxýÁÐdK˜ð çXÁoE½¼)²íSôvÆXéWÔáB_DbW|vçehÙ3þˆ·ÏÂÈC`zëy®)^TùE=£^î¼£ÊHhEï²Èjõlö#‘Z?QpÝ·ƒäu3YÂ!VªI¢çS¡±.…Tß]%¿Üµ!N y*x¸f^¯^®Ä¦:H^6½к?ëÿÚ8öÁ\Ð$∛šÑüê.“¸S…Ý/ÐHcýçO¨°íi[vD$ðSÚ&½ü/VÜ'Tþ¢D;¢~Ý‹êè`C1€ ›AŽÈÚ,!xÕ_Îèë`%d*½<¦ncd©o<úÉD·ÔBÉj0G j"b¤ß‰ªp[Õìµ=ÈD„¨AN8™_]ÀÈåì„;ãWTÓd`Oìf :»Þ¹‡+Ž<´ F6È2Pœ¥I67Œ“Kô¡h‘¶‰Mœ¨Ã+‰ÑÇïð]€P Õa#àõÚRÝnCèÜ¥/©ÄоÞΚ2µËOˆ3íhç¨&\Ûϧ•Œ²Mº®^ù½ƒ'gÈŠ#¼„ÍëJX/$A’—í J¦"kº,5wت “ÍÔ䇦¼Íê½îÞÈ­nPωúDqîÒ¾ÍÂ`Göu¾ý"Ò$;ùÜW$²7bÁ•k&k]q41=]ÛW>íþ.ðó]‡(RxB¯o¶mxÝK'Ë×„Ìø 5µÑæÌ(¤›Ø­ã*¸ÕݲXô¬ OKŒµPo Ÿö¶gUÀ±ºüv‰oÊÈA™xï¶5¼Â:$ï3âØYñÑ¿XQ@EzbÅjÏÛ`ýFÒkÿ^ |Zì;¶æ%”òy“Î1ËöžB&SÙ}ž9µOØ[ëôè²®ú‡ÇõÆI~ [öÔåê¡ËGÛ2ÒârሄF™:«îİÊ:lÅzg£¬­Ð-Ö“r‚¢òöˆŸ„ÜÅPèïL³-ÍTƒÙicÅV¤@Ñ ŠgLbŽûöér#_¯ìkúù Êyåþš?'ɉՆªSƒrÒœnÑ£×u%¥Ÿ¶H¡æ(Ÿ±Ïæ^ÌøÎ¼Ãî¤GLÌ>À&2}+HlâaÕ ÅÐH„±÷¢ˆvœªð¯Ø ?»æ2ÇÀÈo²'ïeQ˜ à~té°ñy]O6ôÜŽ@ó#_?,è†Å`ü£ÃÉü€õ¤©>§oHáæ|ÂøÎJD›¢è­´9lé×v¡ Ê]â³o@õŒ®å‰Ë?“–Îu‡yY(Îï]P-QCžZ"ÿñ:o#Þþã‘Á§HŸî’Ó\ /AMºx·/tZ§3ï¼ò(6G)1DgÖÝ8vë·ŒIEo²GBLR®N³§ Ì)ª¤ü+£Š&*£=¤GëR†ô½4ù‹l‘õY¾~‹`•ŽÅÙáCã‹F[µXÍ|Z¥ˆÒGHÝ´ßn¼÷³Á}¾6å4XZWssÐ8]62ï—‘ìÞ©œx¨­Éb²®— œ®û¼÷f‹Á•èX‚¿Œ)|"k=o@»$ÜŒ}AM|A]¿‘í^ÒꯊÌî¢ísùMæÝ ß=ÏF-ÍêxÕxY.éuJuÀ&f Ê –1˜ºx0BxPÇ€tXÆ${KÇ©T—º>¥~³Å}î2TÊ 8Þ†wêk:nA™‘¯Æµt×8 ‹JeµÁÔJ% w¼ÑÄ>0ißî‘«ã û¶(—4 }ÚÁ­u| î³É¼óÃîc»V µ½é þxŸœ­Í6h,:;Õœ‰Ù @e«/–À¸ö Üßn?^ʪ8’{mÖÿõY‚¸ë’›Ía¶$ñøq Ù÷Ïß .Æë Á±;×—éŒ ¿£Š´õ¶Äåã ÍeÅ’ƒÌ—h3DϧMIö‹{,êdZ &Is”+ÍeLöÙ'þÚ²2´ëOdí]ÉþF_Í©óºÇ3µ‹2¶hS5(°f ¹û8;İ­˜©§òæ°Šñ,Pÿÿaï-ªêºÑ Ò!! H)Ý Ò!ÝÝÒ%ÝJ#ÒÝHwH ÒÒÝÝÍ] Ÿç}Ÿ7ÿçžçÞg£¬ÍÞkŽ9æ˜#~c®¹Ö¸Ï{Ýüñïìz‡ÅÍlŸ»Nì`´åP!SòS÷’™í¨9ú;Î[¦ùÒ¸sv˺‰ºRʉqF^´–&g@àƒeåQÁšñó…FÑìÁÅÏêN Æêâ±ëÔÅvÓ9J— ©v·ÊSo†iºÍSó‡y7rg¬²zË‹+[$b÷µ-ïékèn©æU ŠÅëJF^|ÎjãÕ¼S²Ô-6!´?aKô»ÆC•ï5¸´¨Z¢õl´u0ž‘´b9ìµyá—"™XÂU·qä»ñé°±«i”¹pDÔª´o`î(gÑ:¡cƒ8¾Z\æµz_ÞŽúúé¸yê9hÅÜ(7*šô\Ê'\5q-è]ué8`9 ýVÙéÆÎŠ)§Ý«áðúo• „ÍsV_iÕTã΋Æèu9L_”Ž|vHBóª[H½x6óØs27sìqòú£4룛JD êý_ýe?QJT a¿^ëïsàeŠŽäŒ]hªÆŸil³ÏÃ5#~ôG¸sM>¹÷Ð'uân³âù83ÎBñmãø€f¿ûΜ`Ã4Z3¡“!Þ>b…ÂA͇vÀ›A™ºº½¦ùtSPN£¦í2,Ÿ+h/ÚÏ G<<< ¬òðh^óFŸµËÇñdFŸz¢5ßòñFûò4ÙL-ñÒ~—v’ ›@è2NSѽË9ž}±g±J/”²?o£2‹ yM¾Ü;ña%56sŽ?Å‚n»;¹F¸<¡øNŪ—$Õó¤h.ž y½e(BO»]tŸzÜ\¨ƒ¶wó /œÅ(@1-Éç^9ÑÀ@Ä0FŽ,OÔ)u+ö~W+N™ÖàLF_µ–*ÁÝœýVn~ù®HˆxÐëo±`¼¼’8ĤúÝ/ýÌž¸¼×cãùÄÙ·js+ߣwFð<¥ŠCžaC’0,o‡ݵa$NA6C¡æëKiLi=ߪ£l MèÀGוînò &* ÊhàÏçyåðsÓ2q‘«'sžç$êk‘Jê0˜"Éy·–VM·ûœå,Ka£ÍàÃó´ÐYÖüZƒgRçuº5–&+äå¤ãî2:O®zk6“›D‡×©(‰Ô,[¢§Ü1¬ÂŸ7óM-À8>ºqS‡´¢Wš˜:ÿ1^¬é‰t]o áœ8®ë%Ç\ʳqáS<¾arJ6õ.!M¶˜à„Áªåå†EÞ Åôõ''Ç„ª´Ëi¶Âþ[¢ ÍÐæÓ¸ ¯Û«´5]‹“Š)cbä+?w¾zŧ€³äØ“ ’p·`=ÝM-›Môø¯ô«®pNN÷3tsd’͵õמ#\-Â;ƒÎ!«™íÂLrÞuWœÜ­¸ÿ)û†¦ìk•ÂÒݳղ?'¾¦&3IÔ# Ìãõž y®Œÿ:p"njTWý¢!Ú(ú¨Ý: ,A>n±ÊôòãÝ“L<»v§«3o¼^«ÊX×ãµÕ¶ÈwKí ­çO¼p¼k~š±ö<Î=;=…õœ×üâr¢ÂlÍz)0È ØwÎkœK ÚG.Ï6©0fyÌ ¹M+FB?à`TEgçp‘ÖÆ«çàʃá*Ê!Ö|íóÅ&Éo+5ŽÏ®› ïÚÏØ‚R¿§”{a&®ÛüBÌ{A„Sð7¦éå>òª\†šó2Üò+÷Q6ÞÍ{ñEí/‡Â‹|³‡ÏÇ>ÀUÝ2EkÑR ÝøXCÍÕ §b/óí·kֱ̫8Þµþ†R3 “Lþ\ÌD?  Ôl¥ºPìœDÑ8-‹t=þ’üæË¾¯Ë¹sd×õ7iÀËÁeØ×kg›˜§Sÿd»ßÍ&t|ŸO: 'mÕf£kóç5 ¨¨Ð^¢ù§7í)Ÿ¦V5{­ڪ¤-J+¬˜Š¤v·uôõR©?‰´¦ò¸WÏB})[°˜3߬zLÐð“þBà§‹¤.æçìV3ÛãÅHægí_l?¶–.ò¹ø·ð/<†¼]ZZÓxëãåónÎ*f Ã<$ó‡™éy¥»Ôü¬‹L ¯†H6Äkœ½Ìé\ÖÛ¹DV‹›EçÉ&*¢UUЭ óð ¸ÞòY4>¤·3Ñi¡ºž·1%åEájM«.ò5Îí¨(ûëÍ’ÿ Û£äyUDDqØk&4p­3xÝ9–wÝ=íÌg>ºæ˜~m±¿úUÕüB8\WùæÌ5étÜöc>ó+@Ðd¦[¹—¨ P-Zôdv@:Ž;ç_ãø2w/>¦YK»³\<®ºÙi|XÍE¾ˆ…ö–ë³–vÛ!Ö£mó¤/Ê–ÕV–}&÷mu¦É>º´'?êsz˾‡ÿX øƒÊÇ|Äö)Í‘/–Ëâw”/Ü1âêáÀõîÁ€X—¤å÷Ï4ìׇ Àâ»öÉÞ´ÊN.Ö9<·˜¸¥Ú I ù †„Ì®3½ð¹ÿd©²%ðØ–î;>pFjÀ"Foå$ß~x|c—9@¤qácMà/ Ò¹ùŠ˜š†ö{Ç…Òœ¡E¥õG]±t¹@«Žt0@[’xEÓV]ò[þYÞi¹ôë`Á#ˆ=—üÅ‚é»îôVÿñ º%@h! •_Ãååtº ×á| “«¥Ì1˜< ö_¿‹äØªŽ®Û”ídL²Ü||èÓ7ÐãoµîŒâ)Dã{ôï6*;"äµ:ô‹î£´t[<äúƒœ/ƒ­A0½€gèK;áÑ$dì3€ò[qÔÀ ˜o’qËÐé/Ç‚˜’ˆUã~ì$1õdùùûJôr¦Cê 0¦f/ÖÓiǤÏã¿}”ß>Ëô%tŠ}v'ãœ2NP$ ú±e„[°O¢¶±(6~PĽZ†c»¥z‹QÙì”ÿmNó÷®œ‡­6 ¾ÏoØLúPõªÒÅk’Ðë¤AVâS½Ø9x‰Û°>>Šó->ùZŒ°^tÊïŸúñt`× áBýQqxíî›ô§€0¤ I¯MfÀµ  ¡ýæA£n~Wà£2\Ê_¥Ã»Tí‘å×û¯ðàr•`?ÁPZ\Á·Ü®€¥8¾±–¯€¸Oн•?Fº‰ú["Sbš£ ö «þ&ž¼W%‚–*ñaÿœ4íÈæØÈ<&š1D&ŒXKÐ †Vóãà+n 1·™]Éã­(ƒu€¤i Z/íÌ?Š}U¾Cñ⸀Íþò!{C~ޤ•“À”ô$©<ë…e­ùgjÛØؠR‡É!åÈ 8Ÿ‚Šo}(™â3ôPŒHÈ[àaÓ(^º”÷;#¦gß׋D.3…%8Ò|}¸¸eb³÷øÏRdØ'?C‰fСûUjå/å¬àÍ«$C&–¨ß ¦H¦Á-Oi<Ͳ5ñ­Âh¿?¦_QyhÎqë…`6ÃO/ŽIìP+˜¢%¼zñOõÌZá0áê ÉŒ[s½µ÷7pÙúáŸ+¤A ¼•ü<J­Ý°]¾˜y¾…—vx¸*tÇ!ŒIð'¿€ŠýQ‡ífMßÜ:¾´ý>èù?WRûO¿ÿ¬gÍ× ŽÑ6ì1™é_*È6‚?qø°'‹ÿ_ª»]Ð@ûøX#>`,ê Õ_Ï·$pWßa!iM6V€ÈcöÀR_Nÿf¿óñ„OïƉª×_Ù"tÞ€O1Íüíx`xYÁŪMÎdê³ÖäÿDüÝê‹tlnrƒ¢üA/`ƒÀ.›_p¿0ºßàiñ»c6¤ pIIuÐÌ¿ÖÊûëï?EÎØJ„ pôj`\&Á+Äùœ¡<°äû¾ò{Ý¿/»õg¥»ntð%ðÿu:4Ñ‚=úƒ+„è¡ØPœ-êôðÛT0[ø («¨‡é”ø 7+KyOÿÀÎoÁOq/\+#€ô?Ý“ªôL·Mð>ö¸êx( H±€ ÊÇíß ;ÍxÆäñ*æõë@=F7g²†û¥Çú¡y_yþÅþO:HèŽìû0i»èÏvQÿ2û·Ð¼U¿=Ï?!¼ÉYìÒXÅYwòç7>>ó$¸X0ŸïšƒTDms(Èñ^üäoÇò ™¿T¤pjÝ¿éñ/¿- žÝ@ÿ…KOÞªËhsc(Àž`Ïø°Geð?)†&²¶éßT‰é­ú~žFú`ÎÜml·8è!ÈC"ÿoôîvü fq£ 0 Ùlï&‰noo(°:Î)ùÂl ´™>988ôœlލ½½_«³FCºÀ½4²$Ný€É]„‚2¢ø{¦o˜4à¥T Ö þÆÑBé7å¿hXû2‰Ì3 Ð&í ÷‚C;(>h/„©m½—ÐÍ·YpÞç³ú´¼ÖBÚÖæéëÃwÅ×ü TSªBéœÛÛ D!¨", ˜{¢|+0àôõ¢[@UãǃõxÕƒràÚŸ€Áí*¹Zµ˜¬cÆç¿ê%{Å4ã»1o¹F¦E•úä£ûjðE¦M>©ì@O{ÈGa€à©b¨V]²¤t@ÎãH'Öµã:Ï)Ð š÷=a?ƒ ª¤Þɪ]a¤Û‡,I‘ÓÒÎNˆuMNìÃò·ŠJ{ “¤=ú=,‚_>p ÑÊÁÒJùKƒÇ]é¼`>@bþ2lP€fx!¿‡ù0F(BÜ€‡jœÀ̱_U ƒˆ)áèBMtÈo{8þ7 öó¯àÚ€™Óãädè³²2„þüœ‘æßȾ3s2Óû{kF&&`¾õ³€³™9A”› ø›ƒ“ƒãoÜË™YYÉshfðwú€ðõ Ø«µ# 3(L&FÀ÷CcYú“†¢©™•+‘’µ¥žÃ_¤ÈÈÁÊN# PðÌ,ìì¬ V&}cN€&“!øó' %#½w ›ßí_¿Ýƒ¸¥ž‰‘=‘ƒ5àl\‰¬Œìø×¿x::z³‡óé-¬iy§gcodHgbfLNóßÏ¡µsx÷_Î3r±"Ý%õÎHÏøo_ÿmBŠŠDÆfï€1P¹¼s44³2!â7³´±¶s Çegäl¨ ‘³™ƒ)‘•‘ó?xÁßcµÿWômïàúΈüò;´¶¶:\ƒ=‘µ1‘‰ž¡™‘•… ‘+ Сƒ) ‘©‘™‰©åý?OùK' 4DÌì4Dì€+#bdbü q7=;#½‡9öî¿¿þÎõõìþ±'†?:beãøSyÞZù—“@#â=  # 3å±ÀPˆ@ ‘ý;3PøÿŽÉßÍœlf÷0QVz@+`xŽ€R™Y=zµ½©‘‘Ãï¨ô@󿨟¾µ¡+• 9Ñ¿}ý³˜Á1q0Pþ‹Zé›ÐêëÙýGB#<(ž9ÔXþ%ZgS@Óþ ½¢ÄÀö_)9èéÿÏ<ýÛ)ûgJVzNf&zfÖVÿJðŸ5Õ¿%b`måh/`ÆÿLæoDX@EfYeÎÊô_)ÙÚñO¤þF‰•ñÿ©+§¿KÓ¿Iÿôô?Ȉ˜<Ë ø7JÌLhøÿßsôOthM|éoj˧󧫠ÿ¿jæßè°±êà ª##À Óoc-ÛÚÄú¿˜Æ¿£Åê$ DlsìS${0öÛ›Zÿ{!ÿ{EÇÆ4"&†t" FÆFvFVFøßó7Þè.tÚtDÒz€S¶ð {è×þ÷ù¿áêùº@Š`bôÛ›‚p|‘Óüî:™Nþ!$<´±ùý‰îƒ„7úFýñÅC/4=óÏxÎË?žú;üîIà𡛇Qƒ;)lÄÔí!$Lð?$1 \0}d" -LnŸâcˆ)HC –ñˆ}2¿¼ßƒ@\C ^ !3 8|g4¿ZD«_\X@Éej§É= _9ùî>©`kk¯Î(êû-œï£vV„@(z¢†¥ŒÚ4š%*y59µË‚<Š Û1l öZ ¸ƒ6’àú¢ t_1A11}è:Y¦ï†dÑRkã³ÊŽ^ÞRʃ›‰[{[}/“×oÝÆ,¢JsŠ·¸O9×=Â"Jû¢ ÂSâ…ŠðÃoDþó"ïည ù®OôÐŽP#ï¯_ýÛ<,6xèYÔ­•ŽPV(ÅìiǦ? ¤Ê{㥀Ømë{_CIꑘó]Ú4kéØô™ã‡^LŽjK‹’‹ŸøÝ ‹OyS0Å(³3·ëÅN>)5‚çg¾‘s]ê²Å_ä3V³š®Þã[C V¾Ø¨ß3M\Û¨·Âëz;ì¨íÜxLJðеº „ø·‡Q+¥AÛ´é5¶ ¡¦éÍÔÚbê¸ïVíÇç\Ö/sÀ¸bÒKI¸öÞ\óµXL”ÌBÜ È–o^jŠ9Rœõjúg{³ …b¿Yig€œ¼0ˆ…òñ¼>ëä; ’½9_çóÚ¾»½&œiñ¾Çñ^`4èúñÎÌìr%û³ŽÛt‰vÃYƒÙ>TôÛ§!ì‘bǯ^&Ë€UTeï#]@v¡aǾµ»x£ðÿÀ¦½R”å9íÒvž=Ý@aŸ±©±kâ;¸8\žo4ý™¡Ëww±ìýxöm µï"&î~(ûœ‹k³ïŒçù¬Þrõ‡Dpü8g‡¼„b‰‡^Øà»¿œh:NÞŸ™˜Ÿ¿¯}Ê åµq¹žJx¾çÜr} ©†žÜELõ‚àÀ¬w]§œ7®+y“€µÝ”‰—“¤3E=Or ö °P€ñ9„äȦòzîcS7óÚ.uðA.¨}Îw~U¬')Êp®nïîîâAUBoøXˆD)L½êš^ò›®0œSøÍà!óóê[S„­î4£¼¦ª*Ç‘§- –Ów>êqFÚ7¿½œäÝݯq »ð&TX¥(8#£ÞÀÏà¼|Ìø¼‘ žx”¸ž·’"ô,±BW¿áû˜Ðã`5Üûf¹¥3í4¦ ¹¤µ±Î“âÉ>9ðÕ7‘ÕIP)˜¶ÅR{5­ˆCB÷äïGeoGÜk"—4nw-ØhñÁ¬$ý¡Ç=¦XJÐB…ÇK¸I4ÖúC°BžÂÍEB-ø–‘„þ©¢2r”K¢çÏáÖ™mÉo<Ëÿ=µo’Ó:Âï#¶äÃþöY‡é8z <´VóÔoñþ6"øô4’ÿx ÆRúÏßÁÿù '‡ñèˆTÿùð¿â/þùP!¦ #Y(M¤Ü¼Æ»äR¼C\½×yaÄ¡¯7-VM5Ê÷ýŸH¶Irm‚g±Ú‚q]$¥vÔä½nºo„i´ŽŒ€¾(\ã ¢v€Ë9zó×0»QAÑ¥ÕÁ¾Ò½»ÓƒuU_dÅÊ’¼S²exXÛF¾uSt£ëßtSeÞ¯ÓJÕùb0\>j¢PðÊŽqä¼DÁRÚ»–ð¬vXñ¨¾VU”vÔ”ä Û½ï½øk/½ùÓ­¾€ªNOØýjÎ ù&›2¤ï)ïÖ ˜·µ—¡u÷g½c GH5ÜȺ¸¥Zø¯>©Íå}èÈyATy Ýzx{[eëÛnŠ>U?Ìv³+X<’Éñ’¢è¾.¦×>–»½ÜG Is|u¥&>m8ƤÓý³‹™Â²}V jª` ¡å#݃¹J„´ü¤>dçy#šàÇJÛãÝušJ0ø?â¥nº_vBVUUyŽTïöo:\ÅVYLèÌ!éå§õÆÉZ[ïïgÅì*ôò(ô:MW×Ô-è±5ÅÛÜKÔå'ëãó'Oë$B>}·g©ÓÛšáv7ÊxPÓ´™ÙHSîªÛìqy“¬Ð‹Ji´x¾–´cíLêÁ¾Á7>G)ý\«r©F¬EéÛ~§KáÔ‡1ŠÀ€Ø¥¦Åw¦k¬#ñTbìæ£^IÎ-aªû¢Û‰=нZߨØP[qZ{ó:+¦`®©©©Å^7ÍPâ LÄŶî½Û{êG£ÛSY1Ôª%Üóžzn*‰a¯­’¹]ZÌÙÈpBú=À(©{}\ˆÉzùFÐyŽ·¦§†²²ƒ\"EdP,XðŠÓÀ§MT)XLJMU7}·¤zœÎŠÑôìf;×úSî¹9œ½î¾Ô’™¹Ü ´ÚÒz®Ñõ8wvÀ›I*÷õrW¨{…›@Ä}†·ùÄdzðáÍyQž½ÌkÞlËç3öƒVµM ½Mžžž[;O™À¦/Š)?¾¿Û¿ŸÓÐSÿ¥‹ò­ýãTÚ{ yö™›ñÍz^ÉÐ}°úù6ë™Þø ø´`˜<Ù—OŽ?B1=kŸ°-¤_ô–彬÷`ç8UÔUy‹@ÄhÔž§ç mívô|På‘fü%‹ü×V—TÏ»s ¡œöçš~š¤üTa;˜•ŒÑrªRÒ"mfT†Ñë—Ñgé1K)J }÷yw~ðÖ#ÞŸÃÃvÏ ¦‰lky™aõß'8Ô$8uxÊÌÇ x >‰Æœœž&l±ˆë6ó|“¿k%F‹¤¬aŸ~'Oåæfã¤ÍÉÙ¹å"üþ"üËLù!¬YËV%”«nÞº?ª´´´µ"/ÿøã@f0*ÉéXšÒ}@mmÜÈ!›˜˜HEÇrúÏ8§jŽøñs¡É·åj¬tÀqp•h× ñ/Ù–¾ã§o<ÔDQÏMó¿K»×ܯ¼‡y|5ÃäÙ+­Îm¢ÌÎîúÙž*öÇh:õ¬-…Ð{ÙS>ÍQÈï~á^ô”_jâ4.Iì±_ÂfõÈÏwéGŸ8v&£G£UµÇü¹On/žáâæ“»¹»K³Ï›•ò¸’ÌÒ·Ñö d3p й§`Êr˜O²ZŒßt¢Xàù3–ü(GÖÂPØòàzkª³z÷Ú"¿á° /\yyªÁyÿ/!×Kß!AV’d¯›aIzž*1µ}‹ŸrÍ>Ѫ:®«-« iMMžÙG~ ž‹¢Ùe7¯h™uÛ.ž–×Ü{Rn¯C&›âQÉ× >ພ„F@#ÏpŒÇ ”ñÆì¦ë·—Yå¬8ï& ÂyDx\ïoÏç‰}kåàm›Ñ—Þw4ø¡› ÏQùªEˆ½œ[w*²»½:ݵpÞ›¹¤nü\EúŒÙ¸„¤œÇe b"{d3)œZõm§ÇxrG}óc;Ãó±¯AÂúþúß,ÚÈ¥SyoõE\¸0{oÏ©iÖXy&€³Îi¿5^ªë½Ùìy󫺩ª¥åþ>…Ô8Éãè{÷Å#å/¥7µmáèLG8Tó’4l&IÑ!¾ª1pDw úDxÂKž8¾ÂÜt±ÍïbÿþÎ:3?ßl*Gú‹ÎXÞ_åÂE7ÍO'ðNYŒi!i¾‰Ÿò°Zï¸.ð !¦'Κ)áÝ™(XhÉJ®m3H˜D×û)ÖÅGȈZ››'VõŵÌ:ŒH‡%R“VìÒá„„žªïÁl8‡Çè'È©ŠH@®^}Ö:j§;[<š¬ˆþ`¥¹¥‰ˆ×ŒêÅ™‚–/óx`/ E²‘u,¢uò^ï ,lîíYQ—°B® K›ëm¿}€ý…YÒzDó:¥“’Ñýlçü©¹¤Ä*øßý¸r ,md^ Xì]êð¾·ú¼Çq?ŸèbKšJ´®#Ç=õµóž§NüÝÝò©Ò2 ¤cm Ù]?-b§W~âIªbŠC6?ü3Ød!FûµÌ£Ñ N»æÉ\ŽæN2ƒ&¼Ç ™8´£ÅY¤^Ó–5žJž%Uæ§Ö••oÖ×EÛðÝah2дnÖóðäjf@!¹gW7l÷\uåv/(ˆÈ[æî«Þ²-t‡<¯.WëѶù¯­ ãþÞg㽆L<’Ÿévö2 ÜwÊôÎ I–LRäûú¡‡¶1 ä/¨Õßðéµù.Eƒ…ˆ?7\nA1¤­Hko¥îúÜ/Þ-¢Yi…iâ„ÙéPLL6‡é‹zôB,4"îé½§‘žŒ&Ê.$بöyždö— TUW[Á£÷ [#”[j"]´” fáYÕê Øø%· ކ€)Þ ŒSÅfBÛùv€\1®j-§˜ðcûýZúÐål™A÷›l^iHøäâŠ1@{g}¿)·¼ bHüòÅ~ ŸN³ú{Ì¢H©‹Çn7† œ† €rö KÓ*©q…¡™™2Öǃ|÷[€šDyê%{]mŽ@Ùë*AóëïÍÔ ÔTUíšššŠØžœŸ;¯—%qà&í/:º<[í|.úUHþýâs£só€Ê.pСa ËUŸøiæ²ã‹¹Ó‚{¼ª¦­ííÜ‚„ý‚ºæºJJóø°°0v‚ b—Õ8[XáçßxCÞT¤õj w…¸'9gÔÔ8×P— ÕWÞ6"‹(™KäÇ5Õ@÷ ”ðÑi¥êÞqUzf¨[Ï>eë ˆ:ð.º LùØUg¿ž²rø+ˆØÛZ`0ôDzÄ΋o3+z ÚEC<·Îf±M2X ¾"ãä1ßÅ·›œœœã÷ó=Õ. ïiq™7Wûîr0vHi¼455)'¶ KÌ&Ziþ¿jm—y‘ëû¾b¿7„dee•Vlç=h…qg¬õ!]Îyµ[˜[äMEì+$/ÒÂ}¸ ù4è¹g/Ú©_·ß?"qÖ þ’£ œê£&¾)c?Ð:Ë®N6G`¸àÇ~¦5t‡•ŠQêF+”Ä(”y¯ÂyVLƒöŠ;„îoï=°|Ö¦­[nW,§«= Þ¾]°VèÕVè­r8Z¯›Ãîù°oǶ얶ǽò£3¦¥Cz¾óærLÈV õ’+¬OÎÎî¾;b–64\³™bÓ”ça¡×{dˆÿëQ«@¦– Åàz{:¡J•8 øèÐf;ÍäîD Øí8~>8tçã ÌÍÍi—¬fV)œRp=¢`ÜØ8s¤\Õ \M„yŒ:³_•y{}>¿_éDiÔgÝxh–úò²´~«ÀlÓÁ-ϸ@X)<îÍi•é/}®ÀªÒggg„µ§³TÙ3¿¦§¯¥,,¶wÁŠ»JÈ—Ž ÓŸÒÕŒ·t½.WÃwæš®ØË;FÁ*N¡y8wûòx½E—6)7ÕËàÁFAœè¦7›§àÈ£ˆx`Eæ‚vœ×¶ûS{1t%ãh.“Irð! V}WU{{{©»¨¼’J7w‡@êÕ0qw¾?¯H¹ZRHú!IßtbL¹:Ÿƒg9­SȽ^†€I–”XÁš›âfÞ‡Dßhcdb².;{] Äì–ªšúúµD‹œoëÒ6ô¯ô²b”9±$‡8 ݼ€ Sܶòs =O~δðœMèÂ0 µ"@ÖhÎP‘O˜×‘†»›Îç®9!Ý0ñPoŸûd‚Œe<Ï©¨8~!‡â¸+ë~¡¹Óú •1Yôf”ZœãÂëùˈFë(yªÇQ°ÝÒ%˜)Ë@–9LÚ59•÷ãFN]š%G²Yh}ÿt¦Qš»u§3ä©wáš÷Eû9„Ʀo-+õf…|â²û°Óš£Ÿvù|wºFЧÅz¾Ù5´ädèV5-ÎßïàA\¤·ãÑx]Šs×S½ïD­ð¾¼0I!³ ˆR­”qÛH S(Õ<ðùì·Ug0vMÞ:WÊ#¤V‡sŽÔгJ9;Ÿ+@D¡â—^0;ïLÚZ§_Éd+L8¢7zæ,ý Ëša3RôEÝAë{úžLk™•‡íÊ€¸D­#O‘4­fõ΋š™¹G ¯$ã<yî»ù€É…:çDhEØ÷d6/&%duA¸æG˜ëÂûǼY:-^·W¯!?RcÏ)È[Lê¿Qêµ5 NØBd¯¶ éUÙµ˜á¹,ÙÝÝõì/¾.³"xVBñíwX£A¿¿¤§llnnþtœUñþÂdÔë°¿}>=wv7Òd_¨Zêu €¼”µ–o½±ÔÎþ‹ONOO91ÅêëÜUÞ§¤¤øò…|?';Ž«ëž•ª 96m–÷Ñ]šNõ²¡¡¡/x”ð²Ç›ZYªLŠugªjÛP÷¥thKss7añæ:”¬Uš_µ“]¬|Yÿ8#i­É¿BCC9éhëœ/ýi3ùl&È“ÐWrÚ÷zðêC(qâ/€ævø\/8lÒ&Î*GdÜgÊ‹>ÎÕ#9¶®]ôÇÔJ9kyvöªÇ~£‘úcúº•(¼ÙÚhÈ–óîÔéìæH®÷”Iö®ü½uâÚ'ke<]{XË0¿“ô€nÓOuo¾n‘Ç?é^F© žàá²I}Dô™^·™ÙäfÆVÉäsÐr8ß]Ó\ÕØùæÁž´O%ÝË^Uºƒþ7º©Ž©Œ]ŒPFÅ%g´œ-–––…£zà ­3Šx•,s^]]]bfm­[hí*»ÕM¦j7Mk ™T¼Í'³ÄÓË­‚’’½ŽXjU¯'u2ÒÄøG…ÝqÉ¢L]ŸF<M+rÌÂö³wÕ«ž^ ÐÅ®F“I?'ÓßLTÅH­ãþæ˜ü¶ðkܲßî%Ú¸f¯ÁÒ5\û°@ŒHxÆn•Ä®õ‘ñF»%333×/L†ë(hcÖS•›q”Š97²{¿€HoqDZö#¡BCé0 ÛKU×óÔΑ¢@`ñ}¥MgÖ:ëç)ç&-3SÓÓΤ÷sΙMî”èýÕ¾ÏÖòÓ +¯t†Y¡:¾è€ëGUùBÁ !µo]‚fþÚ´y« PÆåøË¼G“›ÕáR§®;¨¹kGFªfj2zµ·µå¶<ðz¿ñ;KŸ0烅Ɏööǯcª?CäZ\—j@„£]t…2Ýä~N­{5ü¹ÄÂÔ´v˜¥ŸÚë²O÷n’\a ݪ3§ñz¯AÓ3n{ǼÀ˜nq\ÏÀ"ñnP‡äF¾v– d·šùÙL¼=+WݪÞèrø,{mâ–¨gÍùæâpBÛeѯ¦Po¼DûzøÓ3æf.³á¬ÁªÊJ-Ç«Í\¾%OC¶ÛD4éOd•¥Wûº`7ÂB?¨2ÒV]¾bnŠßÏ}ñTô'ØÙ'?2q™ØšÇÖ3´áÕ£˜Rþ›OÌñ6£ò¢MÝ×· ß>wK½Â¸ê¢Ejqë0Æ/벃ÁØÔl®›¸·©°isîâ)¤ºgó¼:Ñ´n:¿?è^X=âªtQTùa·$þòÉHÄv÷%èfr«._¼€Xà579y±Úïø0×!n ŸºwÜÒ‡ ©0ä¥MÓ½$oki“E …2½?¢¿·‹â+.m¾*ØÊ,ȺTÔçЈ‡iW‹›"^UË#“NŒ¡l¾Ýµæ³ÜÎNU+ÓïdÝ/nð¼Sê|¹QßS MÍ–¯~ÍÏ0_ê⌗éݧ}ì\ì^„Ç»—2×Â<V¢É[rÓkÕa–v¡°Ï0lgEËÔë`+®';Ï}]6¤P’ãÐÏ@ –mf[®jₜ‚Æb¥ÚÙ än÷ F½1ô×Óó:¿Å†À|a·žËÎ)­¨`6¬G.—#vVN§Ê{Fý€Q{°"¨.r{†’I’md d#zÌÄûúlWÒ Ð7×蟘7·Fž—«Ÿ[ Ð펦þ\D(ØÉº£.©ÕwâǵîÌepâóòWïP-Õ¹ÍwK” U!bÞ›’ºnCçïÜÚ{¸`±‰EÙÆ¾DTÉñ\,|Ü—“ÅçvùJÀŸSXX¨y;;[Nâ5"Ížœ)óÖ{)ˆÜëqk"¯§à¿Ù(¢  6º ½o¾§.u÷ð‘0ÍJ÷—ãã㬹Iv½h3ŸKœúhkŠ/×¾|[s ä‘n8ïÕF$­¹Ùë¨@¹Ð*žÛõz,Øn-Á„×—my L¾ü¶<[N‹­o'úè[< B/z’¯®®ü}ªM`"ÅÛCAAQWE½­ Ç¢ï~ý¢ªCKkwͰ ïݪ‰qRç ïß“´+§Y²xÈÊL=_Zõ%ଗ‹kæIy"Ó†%é‹kW¢$éŽxB¼å‹«ÏbËÏ™óZ®öƦµ<{õÉqÊ,—`»B®ØV¹/u™WÕÔÊ*eÉ»y½ÿË9r1rè-cO½xk¤ZcFâ;$¨\ßëdîµî°§ 1¼±ÏRÏׄüK£Š²žŸÏ5¹’÷nר[.¹!m¾˜£›Wió‚±b/ýQ,ooÖùÎ×>îøÇyª÷J¤èè¥Ä©Š×·Ïkʸn–yÉÆ”‡µöå…©v-æÔ¾ˆ‚Èï]÷×CèêMÛÚÑønï\Àƒ½±rtbBVe°ŽúÆÎã|E}1uÚnM”ïê§SÌ×6úVå7Ze£z6.Åăé¨Mù…¸’†wØ^Êz:Ÿ+ÝýÀôY¢ªÈÁÑÑÒáõz%5<¹VŸ¯¯Ñõx@Þï˜ØhÎ81@Z¹Ö“ì»^Øÿ`¼_ñ¼KÿÙ(I†A:-˹cßÄPR³¿3g…#uŸsY·ŸÖ¬q?l¤©÷ÀñÒ; ËÊçÁCŠwÓãPÞç óÚYq›®Äjå§Áé»à Ó?^Lep?Û©P*ÜÈþ¬s…e·.‹IÔ/é ßAEqgwß÷}êÒÆrí殺­V@Ry žT]?áNÍÃÃg zׯìæftïõíÐê›RÍÒË)bb_œ‚-Ä@ú+*3ŽÁƒ0ÝéAwÛV‚P4å—lV3µ@ô¸† &[ýa&Ÿtæªo3‰.kb’;¡þtñŽ™™Çë|÷—Og>›ÃñïÐZ»öM ^^uó26!âB:êÖSÜß߯dˆ„”Ü,¢yo|"xí$($ÔžE$_ýîW¹Dÿg†HîõàùɉCa\ˆ‡ÛÏvð§ò(6žÉHb âªê^! ÆÌ¢® üµU×§gŠù1Vêqqß ÏÔhÖpý_F‹÷•…Õ4Ÿ÷;ˆì•B ñ•…¯"XÍ7{î^R—Uš3¤“Fz$IÆø™¿ù“ ™€¹f9ßzßt{'mPÛçd«}Q˜Ðqß-Ç)+Ç3k?È3oSœ™òQb€ÿ23­Ou=Y!SÒì³3 &)œ×ªßB ®ïóH.ƒ¨Š×‘ÃööêÔÛælÔ»ˆêö;“eœ‚×sîû(¤0}—µËašç­n ¿¸<à»i¬ ÕßIê^E]•a^}n¹¡Söhr‹3l yÞ#ÈnØë½ƒëÞ£G±àú^S âeÕ,åíîÍûÇ/&w‚ Jà =Û¥-^õ÷~«óå,Ô—¸¼÷FRïNÖŒ6N'tïç86±×Tâ‡ÊP­\ýŒJ¡óKhX7š¼Šêêê~1ùå€/zÝú˜—AèvR½Éí”P‹˜DµD+Á ½œ¦/žÝZgÀ£ œëÝ‘©&»bj¿öãû³‚íííמ?Rx®/¨VØ¿&7èÙ%ÙÖëU)Êò°’K[L”x8ë¾ÿÖtg'œ´ÎJÅ; OŒñUΈ<Ë{Ï>õuo‹Ûž]6\?¹Å)`à µ°5³°Ð<&Ïî5Äu9”}Ñ[U7Î$ÕÓ©Â;ÐdºÚÒÚEo­ÿ‹sª3ªßĦ8ä pos+hÎ ÖAð\„l/&˜b‚)…A£S¤w@i\QÙC»ººôèžK¨-®CZA}/šqÚ›©ƒò#gxú„•Ë'^W4vÚ¼>`þlÅjsJpUw˜à°ÝØŸÓvd¡Zû«> ÉŸ¶ÛHC˜îMã…@ÃsS›öš ÕÒ·ã‚âPB>/«ø›óÓÓ*Zíú“uý”rÿ„nMâvµ“q¿ÜåÛ*Ž—ÌÿpÄ…×½äÎé_.ŠÞ—çæ’‹Êyn)¦ö^N^–Þ_•ÎS™…ä¯õTÚÚmD3-Š|æûL°ß $M:…›3·hVºi1¥¥å×úBÓ¾§uÅ"æ æ2åS­÷g_åÈ$sѦ%s`)ûF˜£^nâj…¥.ç¤åæš ™eC¥!Wßd™9 ;» y ßÕFf¸Ë"ÐHƒð-J߯­UÂëÉ ;†½qÌ'>ñ zmX÷—ƒ^gôTãPü/£¿ëé¸,ÂZ»ÈWVVJѲƒ(çVÛóûÓÄå‘‘‘Šu ÿvŸššbk¾rÀÅ­ÕíIaåÿÂã~–Ïû­zú^YÇÐ/õb²›—í‡D5%SX+¦ÃÇëæ(äO¶¶òÿ°ÅﯶìצÅ1üS_òÚ_oòÐ…ûxÊ¢”G׸¡¯¡m Š'ð›+ƒyw‰ÕÓL˜V0!å:rGSÍKƒŽÛf6uÏÙdÍ5æÑwY¯£FðQËAú—C _¨cdrÝÁëú"#,äÉ2Îû’••=?Z훘·ë£µˆlØ’ê^øªrvu{}Þ²WQbtNt³ð˜/~¹P\ý0ÎZ q¬,F! HÃÅÖ48ï{)Òœ9ÏEq ˜A>ër?ûe’*ßËÝýñ~4_Ñ~ks1€pÝPžŠ´…sð½7¼‚Áõ¶ãÑÊwÎÁP¶U=³ˆÝ´Ë‘½êè<Ë—2ðϲ?H$óa¿^‹7°ó§¨¶ž¿ >¸tº ¢Êqss;Óò¾=¥¯ÓëÌÏMáúh3¦¬J«ª/@=$@ÓkM.·…NZz‘*\<<…¸f³5=?œqÛ.ÞFôlâ=›4h¹wíp*…îÊÜŠñ¾¦†ÆÚ™åj_RnÑAß¶5ø””b 뾄Ÿîî;$ÈœŒ¬78ß}¶o¬î”-"hÊvaw'JÕò®°äK÷7 è¡¡¡ê?“¾º¥¸ïqZcë8•Ÿ y|„B­f ªDO§ý7àßS\×`z’iR%¢µTá:WCoM¯ÑUƒR„»Š£ÀÏèíÛ´nk?[Z‘µ ò—’}N5·¡”¦é ÞILF½ò‡.×-åŽRu¥‰÷uæ¿ß7FOµhY•rC}G¯»§n›îe9µãÍGa´4â¡–˜â}wéy€‚çç¾W·~Fª¡ÉŠ!ø&мè¨/!b¯æ xå—<Æ©‚ÛU1È{x$bº^§f_ï d,gÍN‡Ë&ÑX½Þ ¤rpª:ë7(šq÷ ïe·Þn Í7ŸïòÊ3ú¤7­Ò{¬Ïî{9GÏ·.ܦâ>)QÃ@}cÕ|¹VÏ.ŒE‘3Ã\»¹'O#ä‡jQÆÕM¹ãÿCïì ¯dàAYMÓq­ä "6<ìBä©6‹Ùb›ßü)BVQÍ͸Íq?{j®Z“?mfii©,ÕéLär1Ö®*YyëqÜ©~3˜;ºÁªÉ´ýHïÀVäááqc‰ó‡ºhúðœ7”^Å&*à3•8[ iuss7»ÖÞÓ›˜<¿êR¡NKÝâÏçbÝRlÂìÀݽr B¨<˜Ã·ôõc…ª÷u˜‘€Y·Ü:9¶&pÚ‡½êr4HóR7wU¹à„ÄÕ4fÇ_@ »WÛ¥„Õ¡!LeÖžÛšÔA¹Ò®Œš¢³³³Póøœœ (_쀙e&˜Žjâ™×ÐpݽÅC×rs¤'”´‡Ø²óù[U‹ñ‡¹jb‹?]–¬ÜiEž±zpÚÑT)ËR0µÌÉØOÄì~u×ý…‚ŠêêêP‰2Ÿžóû†zÛs,w€ù.ùèöÚ`ê½ÀJ½·UZ®lª×‘Ynr\냊Æe`ÑÛ@™Ó4^À𤏿ÔëøøòyoñÝŽðyŽë2HÆÑ XpRšchÕÙeë©ûu´ƒ[ºc8Û=]{¹¾ìT³¦ß^j xÌ}jÌ)í·¿䊫/&C}&×’iˆRžJ‹B·[Ñȃ&pƒn­šÐ¹Žš*3bJ°òŽŬ÷«Üh7‘…ïN‚jôtãîÒ‹•¨V9 :V?ëÞåp/‘®S;ÝÝ\¶“)XÏ7ßžšwŒLMÕcÔö*ìÍDá`¬–yr¯³bdÅ)S>_/bnŸœ¼8ë y:x®sCžì0üµN¶™ç:@ ¤ø@2[á15º’Îz*å[O.7è"&œ6´d¬™v@åöù1B4Ï Z[¶ŠjjÎÓô“%Š4ª¶¦(ž\¨F1]Út65?ãu½K­[•Âá5Bà<Ã8Ø$‰p?ß›]¨Èòh3ј–¶Ü]a¶wÏaÇ3öºûeˆC7º gì“Îg½çZ¨ßo_ÓìøžåMÕÙ¯o ¼Ÿsƒá¥ÎXF<Ä/Ö<_ ¡ož ›ódÒUo(¤¬˜ë§þa¦v68=á};ñ ÷a}w·Oñ¾Ýî8kn]C°€(ÏŽÛðZµ·Vw}볋àAÔ7Ñ“¬¨M`¶÷«Âäã•‘àâÿ3WAÙ|X{ ^Ç;wœ"1åd˜Vÿúö[€!›ÜÏQ;¡#á"ê· ãÞh^|ÚÊÜüùzñ¸Þ•0lö>’WáØw›hx~»Zm6’ƒm.úLaˆÿòù¹ÿíh¿^8‹?½ÁçWÕ-zí-%C?ÈŸØw|ò^ß+d¯]×wžs]ÿ^ÞÕ;>@zF•ÅÄœ  "ÞJƒž o¾’äíˆzž°o]‚ÿ`bû¥jeú‹àμ;é/lž¯b%h€]^¢O¶+†i*7ê›Ýž? s¦Ñª2k¡×¬ÞÙš¿;«áãâúÛC”'=4JaÔèþ/'œ£5TÙ ÝØKœ7«ôÞ—ûêN£n½!ìUÀ˜>ò×±µБ—'VtçË º¥q§ÚåÏK¹T/ò±$Ì¿g¤‘ø~( Ê@¼Ãfxí´sñåÈNF¬sùðÓàóÊ0U?‹ù:b*¶QËS ßi¾,Š}ÐÐü|Ë|HfY™í$Õ7Ý›¥§…‘¯‹V.Të  ¾˜¨¼LéÿÂn}Šð â .F±×XÍ^MèÃZ¨›mpvçuóç¤ÜÙÞ¶øh›#†{ÝK]ÊM—&4õ”È\ØÞ6¦Õ6Ï^Vbꨋ|Ñl8+éH·ÖfQù\+°eï…×Åâ)dÈ_Ÿ-o ¸Ø·Á­w‡O›üÖ7x®[?¢ñ^Tºí~zÆ<мð)‘»pÈÂN¶€)ôN÷Op–YnŠÛVx*>Âbë/Aé~$lpž5<[ãzq®Çkž+Ÿ˜j{ím‡~þ,ûu.ppþd‹ù5šÌÄ©^»K‰È_ê ôÛ:Þx¥¾½A5æÁë¶µ™yÝqÀÑS ¾Ù¢Ö½”Ⱦ<Ž­ò¼>ûu­Eå8Ê6°—ñæÓ[]Œ –S•¿¼l€¼nv‚r¥]‹d@^…²É\Ž2u‡3.ˡ֕_ºSÀ•Æ×áœkñô·;&| žÇký’#›¥S”–€A}gä>N½?@»·Yl¹n)¶Õ|v/§ííí]XzÜ{q«U§×H\åÑi9˜Â³µV%WyÇ:{{Û±íLÕ#¸º˜çh¨A¶äg'è¯ÞGÑ©*³dŒÅäÚ.J…Lî ñÝø›41øë±Ì(jß± 6 ÜfåÜ|Іħ°þøò.îdír×k†oj¢S 6:?o¹¿-½ñ²Hsº;¾SöóÌW¡¼yï @BÙy¸÷†GB!p£—>íÕQn‹~O½üy[ Ó˽?3ÍXiš¶@Êâ—-¿*ëôO¼g,=nMc3Òa§@¾šþ̆™Ö3»dÑÈžjóÒß5PbM‘¸Ñèò^ÿxà·ï™õ×LGk#y’÷Ñ{é ôi•G°;®gg>’µƒHË–›éÔçR.û"ðȉÇËVá-ÓÒáë.Œ‹9us(ô؋˜ñŸD‹:\àXtÅfGYÃÒ›v¶WŒùW3 ëtjšÊ%kïVpZíéÌõMùY¥Réù÷tk[Î)\üb̓ž'ÀQôÎAÓ6Løtê£ÍÇÀ€­ìÀ5{Z]ÓdYF/Ëï1q×àlimm}^¸Ô…þªë¾[åg´™ÂW &§²ô•Ž5V§®€Å¤8«›4iã´uÞª:ú€DwÁì¯eþ²©¾lólÞw7Ë3}€c,Ñ\YuÃ~ó5 ²ëÜùs·*Šó¼çùkîõ2ð’ݘv.u†LCLùîo²ៅw3ƒ{çVÁ«Z—râëei.ƒÖOøÛ ÂyΚ3øÌ¸’ÙX¤£Àâ²»LxÁ\ÂZ"j&$ €íuVŽÙ2A÷Oi{«úÍQðzU;ŽIþ )Ò¹¹ MðFc¯¨z’ECº ¦Wc¥^Žßb(s¶ë÷^> :)õ¾ÝžŸÔnŽûû¤Ei““%ЇÙVW„É®¿O%}×Ä$$z0Sa¹Íà<…Î÷‰›×ï»·{ôôzï˜í—´~ÏDh±Z~6©ØE›Zoȯ/”çòänzܶ‹ÙÝ Í%ïµR%²;¢ö䂞ªÌ s¤²ÊÊåc6Ž4—+¶sIhЈ^lefaïÚfÏÐ ×™÷l׿ÅB¤’þ.9Lë­ø]‘пô…R)+tÉX ÛÅ¢ƒˆêÅoI¥P$ù§ é4ÇÎ'F”Ž,iðDUÛ1gFÔâÓ¸aÌD„ wYÄä.§ >~‘i?/[öÄÊw•©_\–ÐaJa#ò1ý‹#Í2ñWI™Zëù”-ùd.éÂõ$£lj¥ËGqg×û¯WŠ(x6™–Ë¿tlocqKƤÃó±šÿr%!ÂzV¨ÇÝ—¶(Yjn[Ã/ÈJÒ·(JF’Fp±FHì2‰Ðì&C‰#’Þ±ð\úrV°äü÷k,‰ëž‹ÞL¹nß–¦üv%U˜0’GJŒ9Õ¯m}°ÑÑÕýå¦üOÜ• cÎXÓ²˜w-އÏé>WÝ?{T=ÿ‰äjáúí‡cºWÞEj@Zu4ýîå.¸2U„ÔçMê¬÷q›¡Í¹Ç糡œÖ“ºèÏ"ü&ëá¢+â!ËJÜ uªrn’A݇~Ê#¯b.ôÖ¿Ë6‰¼ç²nË;Wô$„€}æ‡CUÅœÍ}›ÁB!ëW"¯ÙZ,éḯk™se>⹺OÑFd›˜¸—V8¯«,üTs•܃ðÍ‹2Xn÷úA·ÏûÍðò²^OacWT¯R¾{œ+g>æž0£šì★‡UÎ&È8hJIùœr/²·ßˆ>ÛéÇL 8#*ºD®Û­(Ã-ì.H@c™ÎpyD}slŠ£$Ç¥EK4(ó¾:±ÐÃR+ˆ™"Ìc‘Ew2Íi +žvÁàÔ.zþǽt­àUu¬Zëæò7­c‹¼ä‰d{Žßô988MQÇÖYÚ j,¾à›ô´#¤Á%8Ë9}øuÁzjéBÒæ¯‡}Ü* Çò[¬c½¥ðê|$†<ë(¢Œ"à–öå‡ èÿ}ÿºù‰Q0ó,±oDµ)užG¥¿¼Ø4SKûŠVBÚîCïºØè=û<'Øè“ŽÀª3Sò±;–¯rÖ#å¥;—ÜÔ!¤jrAºP™ÄÚ™´¡È¶¶†ÓòUÍQĤô9£MœH»'D¢ yÁÀh(¬SÚÏ/^G‰€ûò™¦`cë;•‡0hSHHó ;b¨²n¼£ßƒÛä ‚(•Å~¹¢*«‰#l!RµD0A:*…šÒ“¦>Å=Ü )¥¾7ÿéÚZò’Ö¢,#­ %M¡3&=R‘SIo•ðŽôáš§J^Œ±¶á•î†X¶«ê…Y1ÀwÒ’sm;GÊŸÐõ¾zÆl¬e…Û…Ki¤Â‘ÿfîôŽ`û£SÝy[wKfõåÞ3§Ükóƒî ¦ýæò¨Í(×á‚9M’_{y?a‚X;kõ4:ÄÎÈR+‘g®¨Ó]è$„bx±F+˜¯b¼Óíò³š_¢îŠFÒydtÔ£Ú¿ ž'¥8v&žM?Л³÷»Óx]cR0ɬ.×{N‡…Í­8ÿyÿR8ð\žu»q¿|S¥‘P|¾ÚrßÚÂÂý`#3\' žzPcõ-Úµˆ´œYp|0T Œ222·ÉôÙ J£.gi9nXïãÔó;Ýz ¬«ÐfQ`â?M>}_j=81ññ©ƒtúq¶Ö—}gbá Ÿ‚]n €¶¼)Nc"3´™’Ý „ skë}6åb$bôœc6w÷ouÒ K佑…-ÁGý©ÌQÐU=1Y¦ö®`ºEÓJךÚó>¯ Ú ãÌœVÁ7¥Ñó$Rðva‚ųÍ9芞Ã|Óm6˜9µíL€¹ÍR±AoüúN)¤€B=ïƒp,j« >ùò@xÓ†˜0† iز‹g¤F6!+FÔ "-¨ñb–D5¢òU[ð¯n+¥@u®z•wÓî‘©£ô ƒÎ¦êk…ûËHñÍHÁèüqquŸ3ÝÎ>gñû í_Ÿ†[Sµ £"Ÿ(ò[ª9¿9e’µßÇFÐ7²SÍ<;áØí°”6И‚¾æ›·±ª@À»4&sÿ¼ „ ßüAC«~æâU© l5{ÀBc£€Š(pø‘Þ.\§›ã÷`;#”y¨ù%Ô‡Èý¯4ËlÀQHSÆ=ñxƒÝÐ,ç!°8Ú<1¯ú±ð&ϼÇÅnål½Š$oc&ú÷m*ØKD‚sJà7QOKŽð`±ù©îyAåtØ»ûùˆV)  Ž]ùäîíPHD*¥ÑYÒyÃ}bšÅÇÐFÞèÍ«:f-õ9jèÊ*{ÞC/Uæ÷=)v.AG©¨”Ù˨Y1mÖoNÐ~ºÞ£r}¶¾ð¶úªïRÅAL€£Õ(k\Ú"ÌÁ¯íÎÙ7:[C©Ó„Ùá¹i\X‚JmºŒaËðÊy"’Cuæ÷k·šÒªrn&ä€7Ph+À/]¸/y£vï‡><Ïþ:ŒúÊ ±]ÑK>8k™ã«¥æ EFD"iDqQ0ÐçŠ B¾ÌêÍÚí<¦ügúI…ÎÛgD9oñ€Ñ)HË+œæGPPž3´IÀÏ.ò!ð#ƒ}Øâ/jä=gàÍ}®¬Ÿ©.‡@i‡‘˜ôbT¬ñP T‹—SCxFÁ‰‡b”ŸE³"ü–9ÚΪ-i“eðª-·===Ë€ôœ€Ôw6Bßþ%0"I- õù¹¹fÊá&Ú5eñ–¸þ™f‰Ë•o^EÇì%ÂÀBÔâ²]Kž<܈Ƕ|™ü©ô m›íM!ÚçÌ«-Mƒkì¼+õ‰¸Jfa!‹õ|O$P0¤eA Éø aOž+ÉÈñqvúÖpôì2²BNœRO=n-âg‰h[ :ÞôÙÂdÑòÅJ™lM1ˆã÷ÞÎQ\·`ûçOî.Ê3¤˜ÊÓ;@GXP>¢¶€}?ѶJ}Ái„så ô l z6ß}1Êì隊â•ð"øC΋ãBÛpÐÐ¥D¾´öê<ΑiO'RÙYaΤ+/^·œé2ƒ'È„™ˆÜÜ®ðÆVEØb¤ Ê‚,ð9+!ñα¼;f]~åƒéö,¢?û‡ûI³G‰[pýÉÊ5÷ŸþåG0}N¦\à}k+6ßrœ|œŠÆEŽØiýÁ¤lÛç ZÈ(Ðãû“a²PSù¼ÄNÕ”Î%‘ ]hâE ɯÙ+ÔRWíÜhÙY"Xµá‹S‚÷ôä©z%ýçZ™&XĽÐÄGXl÷~)ƒ Ó†éLÔ1Õ -±v÷‚–Üï¸õæ;·pDæNõRÔ»N{¢y}MÛ3~¬sì\³J]b™³gt8[¤›dæÀ*UTŒL6¹×8à‹†¼VIe2 Nßv#„̆öÙ" C•¢EÏ8 x [òvé©‘/ʵûä¶Ä÷ŠãùŒ;áîôLߟ¾Qš|!§GÞq†u¦!¯wÅ(x*'î.{L)Aƒ&¿jRü|ß_¡„¶JÚß³Yv5àÉvf’mî„gnÌ‘T âˆFÿQQ—½¶DSU£ýQ'© /ØJoLLrUUÉýÐ7¶·1¯ÏvGȤâÑaÒ,§*Å-Þ½uÐ0KÌ(+ûI%Z¦ÏIú²’ãY2èÁ#Ñ•HpB¾2QBñO8Rð¦9ô•ïÀ'Hf­NøuS†âiµ¥äZì2ƒ´"³4æwCviEàŒAjÝôu©7Î&…Ayð ^µ~ å-š •’¨Á ò…À±ÆÜgm?'–3Uƒ1EP5EaTÚW¥NÈë÷}ºrê˜ä2, ÀJ‘-4R./*@(¶]îêÔFÎ?o)ËéO½C³Lo‹€‘Åï®ráÞ»d*xUIÓ×»þ‘Šÿì·ëa(­¢;ò>‚§µNªHRpŽˆSœptÔQ’ïNéÅ¥îĬ§p3/!ëÆ$3á“àW…øé«2a=·öAÇrœ)©n*K›¦Ûñ=dDAd)á…‰ØJ][c…ɆLꦎ:ʾ*°ÂSÄ“zÆYøþoªdÐŒ\¿Î–']6ã%idH¸¿È·œÝŸ¬X#ÏÎ,)‘yîOÜgóQ®`ˆªFPÌH÷QÀñ•Á¾)šS0Í:ž¨‚;Õ˜|.î7·‚Õj¯Î3_³Äa–~½Âcn=eØôWBXõÞLõ !~ ày_xvÚìå=ŠXÀ°ÂqvR:€ÄA…¡SÀŽ,öpCµÛ£±Ž Lǘ ¸tüôlŽ3e%å-ÞE¹Pùu<zÖ]=ö˜"‡h…S-Î/ožNs׌ZDë±ïÐ)®Ú±Ñ)Ž¥Õ¾Yjˈ©T.wµJ¯§[¯{ÔAí*£HÇô"ÿ&æ()¼Ã#Yp×ãåúãÐQüóQEÖ9MŽGŽª»W%Ò~ÄÝ)y£óJ¼éŽñîÁí.„òzܤuâfœ_‚ý1ê–žËë¹Æ4èUQ0Ë’ºÎ›ËKLQ™}ÖÇâ© =ä}öÝäNnôP,'SŽͨ9“- @)³ÍƒNt¿"²éüqá©Æsˆ<¿)JH%~wJbÎ{P¡XEªK'›ð¿¹¨=RfE8J{ñ²²Ò#Œç—ÿChe- ÍcAæZÅÆÞ”f©iƒ§EÖh–°Ûyf¸û{î3Ò,VUUõ}nN'á»áKHDz­uFyœ’JÕ­ÂO?è‡MÂCÙô<0Ž/_Ø­¿'M’€|µÄKNNÆÅÅeÈ‘þB1„^ÈnGä(ű#æSÂRaú.<5Fvs³Uff¦ ˇµ£,(s½¼”ÙŸ:õ7ö÷Ïv§sÃñØeôMÅ7vvX¸¸¸ ¹’ãO:L.“”—Bþð€S%‹ ¤8‰ì,³D… GÓDÿúz.ÚH`þé—á> òiñn9 áОÀé440ÈÜÙÜŒÄä–ɇš!u~Tè @Èn6iE1JF§µYi<ˆÔK}Cƒe;Ã[uœ«ëë*C¦|›½˜Ù™|<\\tÈJk+dx³Ò81G.O`/ý¢v‰Y%İu4EžoE••\fŽ!5F!>yÀ¯÷e´xþv=º`+rÀð~³÷‹§­iU½É?dÖ$<ö„N†ûÅc›ù²kº1Ö½œó$1ç›­?í–½~Y¼Í`Ÿk6Å( D jg(ÏȤ8UM`/kHÄtèM‡)ë÷O¤à4”f¥¨‹h ÿ®Y¾ÍÑoO·ØÒ¡÷W/‰T"õlÛ›Œ7JeV}´ŸÍ­‰¨j›£,%$~±‰aQü¼"&•¸ðf­æ@ä¢ä6!=½‰­xœg—Дš—Æ+’0ÈÔ[%7M×lnòR°1œÊ“muœçrŽ3–W42]Ã>/)''GMT4À!`÷«çµ§ë‘!s‚ÔÔ¡‹–=¾èV=]vŒ9±äÓÝ ŸÛiãÌt[ÖL†¯På•Å…ò•å•‹rŸÈ+£”a±Ê+÷2 ÊcïÈ;^ˆ(WõžÚHÌ—f*+Åã£8í ÁÅ9‹WY¦wê«ÑŒÌ—ŸûÅgAø: k“õä©og—ú@ˆ¬¦<&J´I’eLØåœPWá¹o2© +O¶¦A×§ qÊ*%ªU °ços)äÇìll€´ ß -, ã¾200,Æ‘ ö²œùj{k 2ßÕ÷@C48- R´¶f¼¼ðí£†®nªAb˧oš¦SiŒRŽ€Uá?Âÿ[\ÿ“±‰ ì@Êzi¢ï©4†Eü„?§¬Œ1NŠ,P“·o[åÉÂøìý!Ù1¬™Šg4h ÈþnÿbDSÕ‹9 ¢m&DøD¾W¾ÐÕ)‡ÑŒÈíÏ™?ýœœ4=9=嬶l/§1›vrjŽ)Ùnc@Ž”"ó3KL‰çzwúØM“üå{h^j߯-Ï¥VÞ0X!eši䤧«ðE€Ô?é:l#í»'¾æ#œ3]½¶‰cÕ~2ö¤/€«)`Û+`«¹S%sBã™êÉâjÉExVZÓê®ONž3G‰ •j,Δ[Îseü¥.œ³{ÑÊ­ð·Íºa5V %´¼Â¡ëŠŸ>œ¡gsõŸïqoËßß(fà ½~ýº H·dr{:FнLÛ®gÆ =@ 9zd¦Æ‰Éj‚ézÇB $Ê«î©Ç•È9Âð‡-–¸a!¡%f‰@câ 9jëÛÄêæÛç£ÖPÆ‚Dƈ_¯­Ëóe<Š-3|Aék³µ½ f§¥º×8TÙ1@®Wë ¤ó6 ünŒ”!h"2Ù”"ÀU `ª€lpÚžd˜¿Ô4db\Q;C0EŒ‚ ¶dõÝôÙÙå:÷#\–œ‚°ö‚t X[ï´ Ý/²P*ãÛ€ôÎÊ®®7ýö[€¦àï«åëë‰jËÍËÌ£¯4!ÍÙŽœ³€R{„žx# ÷µS$ÂßÂÐz œãÒ¡‘[A¤XÍø¼®‡dŒŸº—ŸCºËiŒ™³]ož- OÉoê*䉊¸#\l–èþ …š7y2qŠ%9]¸_šïÏ5=ºËCÔ HWö|†¬QEc’ÿÖ éjû¾†‚Q+‘‹ŒU~Kþe8|d³¾ª&ÙåÖ«žùÛ6_z¸ÎaU ïÎ)™I7ºšä˜«2"Á8Õ2¶ðˆó§Äû¡«Äáðòs«ãMðòäð¿šÑ—~ÑÑËSª—9K¦ÛÑÄœ)L1 òŽdð_ӜޮýB=n¦= é9·àt|¾6{¢×1XF1¬#áY#2.¦@+`ÄÎÆ†Hì;äHp{{;P¢ÝÀ‚¬ÑzÒϧ¾Pz?_ÞaÃä{@ ò­¾PïaûÛ6î‰hóu´Q ·ÛþåÞS22&ЏfÁKêq§¶qûº]aÿFrD_JB½é@š²"Œò¦>¦)ÖàÊX}ÛÏSÕF‘ëe“<ïqÄ}tïšpÌ£Ë}…Ó+?‡a%ÄÁN™pî»=;âŒzÕü´}T—u‹åG“$íg»¶^€sša^×»÷êc3d'ç礑b¦@n ˜µþ/U˜dÏñðP&ž¬Æü¢x# ®ø*IË) ùâË0%Ä䘙ûëõ“3%|zgaѾ7Û bo_ŒïR«âiØ Sìi7pš¾Tç ŸãÊ;Ìðn#œ>7VǦl¤v@ãÊ4w¦kd¹Â`ˆ}‡C)¶Q_0…{肟cý1®yŒA‚cbK¶SV)CrÌFX¬ ù69P•d7›šš%‚JJè6¹Î:V¾GŸÆÅáX—»‰ã5<,mhˆ OŠ;W=Šå1êÅš=&•í @߇Ôgü}n Z¿¬sS–ä `U[fJÉw4Ý€Ù“)©‡çe“¿žš¿^  ·NÏ{“°¡#Q}õ¸uûàØV1•R2•b/¹³Ýu†™gŠMÅMg¢4<ò‰R€~<Ü»gþÄÐE)î~d:Q0=qhÇ´(‚³È{*)‚}1›í/KêSù’™dï$êLš¿^–(–~gWÙ Z¯ P(ñó-£PÉkÌžSô­Mwèá6 à6ò#YGSo®"ié‹8UÍ õ¥ìÖ7£:AîØ…é­:&¹¤;»Y/”TÙB¡ ¯>¡7/Iq õù˜Û]¥ÏN$Ð^o%»qPÒÕšÔ ƒ‰P/¥]ÿZ"…˵æóQšæüÏÜ´ž8Øaõà+‰årÊcÊpzÏ…äVƒ™Ú•—ÞWfÏ(ÆØjs¦|’S=v¼E]à2h×pˆ£k®ŽSøY¡O(FÍ;ã‡ö¨Ð«SMó¦ ¦”/_•·Ž©{]ª…aw+žïæj ¾¥\ïõ4îkâ£ry!ì·KùÎ5ñH«dýÖîšIÞ¯ZI¦E~䃚\tIZ’ùÜ'¯¼‡5’àãüBÊ<˜åˆ0"AŠL“H &X¤ pq²jß#±4Üw€‚œr{é»i¶Ëi2Ú¾(=CZÑ8£ô††×Ûî½¶ø¸þÄò îôU7¹Çþl’¨hþîâôݾÈ"=?;ÀÜúS ï]`¢PvMM$±oE&æ¬"wæ7çpw§T["ÉšRòæu™¨AÃîqʺïÊÁÈ›·x&”mÄôìYxw¶Vø0¶Ê0=Hô™A´¦õðN@&ëK @.ÈÂÂbšRÛ»(bгΫC8ЉRò^¹wg Ÿo#›ÔÅ×ý ƒúŒ„ÖlAOR­}]ªÛšEIaÚã¬'y©¥Z°ºè5)=¥ó1NÂú·‚)Ôó ÞGN%FÁ˜éGŒõ=ovDã½ÉúXxÚÁ2“ºãܶ Mªî}QÎ;n9}îÕ¬lüT‘Õ« <ëü;^Ê}»’§Ø•éæ1ÚuwÙmqš¯îÒ%,¿d´]ôŠ«²zP!NËg{uP.’Üܤ#Z(´¼s+9ž£ Ÿ­þbçM¿Þ¤Xboç‘k?¨¿¶bªX…ÏÑc†ØmKäÛ:×äþÊÿF[1/Œ: 2¬×ƒþAÈý!mPþ ¡´€‡Ä³Ä’íŒÒR4KKK.¦ÐqeKÅl¬ï–5xj>Šðh˜¹zÞ O Hü€&‡l×G»±¹É¨¥—M ]RÐóM}SIL:übb.rPD>\¦OÕÙçRBï^ä:‹Ùtxô¢OÜõéY&y´8Àx§ ú¯©ä‹š½J}}#ú°:$¬./â0šož2 dE€š ¤ms= 2µqM7UÕÏëêA.Ü%¯¢ÅMÉ¢¾¿”òd~„”aŒÈìi„Pá¯Û¾òôyJ¶‡«¸°sœ7êé¤G|—93^‡}@%GéùþÌÐb«q7ñ‹öË¢wí @OÖo‹_ÜÒ¢{vz*.=’¥‡K‚Bý½æ1j ÑŸ33` $3HZdû{Tù]ãÌO|€¬B[W·ðUM@kTdd1b_€©}Fµ¸Wh/¸)DŸ˜˜XYfн•cÆUòµ@LJÜÚøõ´”é—•@û˜i–¨ÐÓdg´´Ìcª0 ®¯®¾zß{±°±.wãÅÂSO|¤zðzØJ¤Œd”P“@’.j³10@”ÕêÜ/ˆc%ôßmjn> `éS¸ {EWmfäÍ5¹uo "*_ ñ1Ú aîÝ1”ŠÈŠæ/ö’BU.ȧå—÷tu(/&«C¸PˆÁÁÁ{âƒ%È^H!@üÔ©Ï”,Cý~„e“ëýTOÚ”KK49Eí9..’5bŒ9AjÜ5·F±òÚ:ßìyV 0nÓÄœ`Æú=ËøÐyØqx(J£!Âîl<ÅïÂÍʵ’k9ùUÀ­­‹>ÞHu<~?õþHù"Å\ô©µ>°HOUK?˜’Âët•GØR#@LÚbŠˆÎ7ÇzP$ï¯0 8úQÁJʈ‡ë‚¨pB¾±ô7~ Ä 1êŒ*Ù~XÔÚgÏ$;ç_õÊS‹¥²pº™˜#R`_:EÅ×W!‘µþ上 +Å‘qõÛŠå‡×zHØ#àŸ|²¦œ­@¹)­Qc‰§ ñ‘b/+…IÞ³tÑ-ò`öaøcÃÃPCï¦ßPÅF…-=\7Y´RÚ)î8F5›f£é¼u}}=³»jK¾|xà_JÅWPH¤Ÿó¸¶éDä\1»,8Ćñüe’èïb}ååÐ}úÏü#±UÖ[_oVîìï?MNN†ø¸p‡Õ×s5åç#ä˜i`Ѿ'RTi]DµüTj<*Ë,1°{ø—ÑܬCÄ” ¥¢`ÉM™ñ‰ýo¨ÊQñ9 ľ6´z26ýöà¤g9õœíï¥4e6·”Žg98V¥À´N—Òw¯"Ð bPøàGfo×ÿXèÅ“/ìö`”¿9´YÛ[ýÌüTb„Ï#H­ m¬Ä·r3uœwÓqaË>x¡Ì7à@§ ÕBô"<Ä…;¥ È^iQ+™*bÁâ‚3©)\fÍŽz|k_äQð«çrµa-8àêù(ÿÛÐ+¯æ(ñMR*¤›žQé¨_w ô‰¦ÞD‹j¼”Ll÷xCz Éðº«B+þÑC0âÿž”/†T‡Íò?ÿä  *õÿÀälÿ$’FÙg±Žã=<’IÞq‰ÀL v°ðÁ’2Ä•rå"‚á(‘6¦ò¨/öï˰b~ÂV õÀ‘Ò/ÇÌ¿ûKí›ðóÐ…Ô˜°Ø´>†ô@‰æÏ­%±Ê[{àžŽÑ¸Œà·ó:Ô8Té$_²‘lSzŠu“—€û^^]8 =JŠ‘ùýdÑØfÖ†fsEmÉcÑ•ägÏþØŸ"*#÷ó¹ÈßOñœ4¸ðDúÃ-Ky&F·æìz˜˜m,áƒSŠ„þãZr$M‡+ó9I~ÕˆjË L8²ñ€ á/ÇýÇ^|Ja¹ü^Öà…‡é¬ ׿AYƒµ÷äD@vóÁÈ(©Œ Vòje"ÿrµúb¬[‚JI±à¸¾Êæþ~‚kÕ»ÝD3ÒŽ8O?ùz#>lÙÙ^;>½ÄR {ûǦ?L¹(ý‡Ð 1YcúWâæðõÒoAWÄ^>Î}6…FåKÄ€›‡K1‰ óbB!àU';C¦)VÈïYzVLBÅ4Nõ·g¼¢Â‚ÐUøåkÇߟœBó?\€+ný½¹†X”$[ íA;Pœž>Gúò°h:ÜæÏÂ*7»­ ;üæ]#˜|çÉõ‡0”ò^½BQúý(Û,ºÓRy²áSZf¨—ÿöÑ´Õ£ÁÖ´OX­7•^þæ$1miÎóaBE°®¼þx8u˜¡@öE^š‰,8Ÿl ãÌpýÈͧ´Í0‹Ä;Ëü=œÃ°ØÉîàè«>Æ0EÑEå½ùãñµp°´…Qy°î‰£‹M²»ßóò‘Aú7SÞ“Æ”¦8؃X@q•KôpÍåì²òß?w—ÀJK÷OÞbM©T^ýÃósQ©›4@ø7éÖþȇg‡I‘PçmÐ>¨1OVLäζYú~ZðÿðÐàÈ<à¶Ê©—æžÜ´ÿôå˜7øöÚáCË;ºGƒâÂçv‘ QSÿÿQe·ÿµ×ÿôüÿ?߀…þwûøê¿1°²3õßX™˜XÙÙÁúoŒ`I€ÿûüÿÿ/zªß•ßþ:ÏÅߘé˜èÁ&ô Lô ¬D œ\Lì\Ll)GDEˆHOE…HDE$ýš‡âÂjEÄFç~§è`d¬gE$£gâ`d¢§÷ކÈL¬¿c¨djfO¤ihí Mdõî3Œ¬ˆTÍŒ¬ìiˆô ,¬ÿ<ÁÈñ¡C°©³ž‘)X—EÏÌ xëŽHô»+ƒËkDÏßgÓÙ›éëÙÙÿOÍ89þ]³‡:4ÿ®)Í?žöPdæê‚ý.þ¿žù߯ÿÉþÿ±&Ëÿ^ÿÝþYÿ¨ÿÁÄÂÎÆÖÿ``eø¿öÿâõ¯õ? qÀ x°Àï˜8‡òlèw¹Ž]O‹ü Ç9Îó9¯~w'ç³÷Ð !°ðÐà1bˆ¢˜^©GQ&d½Ô¤§ëB‰SÈ·Ó¢{¬$“%ñ}@HYå¹Ñk§wâØ…1OHƒq BbòäÊ/°( .´8áúºÌ¯÷7›ÏSn6Ræ j[éQ«B‹¿Õ0Ï69_ðœ'í{œ³ÝíM¤| ¶zĺ€&óAÏ"£²ÿþ®»”Ηts®)ó¾ÝyGD˜äª÷ÜËÎ¥äC›Oÿ.ÊL‡P)Ž®5áðé‘d)Ï]äùœú‰ÍæLþãpš£“4ë6Qow$Ÿ¹¾ÚO;§ò=ö>ÿ šÆÀN¿g.¸Ø1=‹Bo 4’0зLžk2sµú™þÙítü&Ú¬ÓóÌ‚ïfD¶éžY×[ÁäM¨"úÄt^Ú+y–#æRÉýE&«¶ò òXlí{å5jœÉ …*}ä¦çj?ÄI ¾Ì.…îùÕVË|ôïT€¡óáG>gÆúÐYñB®ûú‹æŠ<<¤ñ\ÔcÄŽ}Ô÷]ÅöMÑI[¿åˆï—iGbÿ¥õSáŸßʬÉГwÖìÒ8qôÑ˵Ø8µì‡Ž× ±.¬¸†Ygcä«—rØÛ~·ƒË>[ä@NŒ×°®šËTnçÆ€•W4÷ª‹Á˜ñÃAî~A£b”—iâ^Q‰©zã@CKûøôÝô38ˆ@ ïóN¡}¡ .Ç è‘zÒÐÃ>µ[Åî=èÏHôñ $$fœo{ˆÛ%ÐÄ`69Ü„ü_›Räðáí§~šêoqõg…!âyž9ßhùV—o"t 暉°Ž3olúqçëîwQ: â—ŠËQƒºÒL‘ƒÞ´DlŒÙåèOÁø°¦>ö=âµ³?*n'3õ ü´’–MÃÿHã ‰öet±Â¾ÄÆ)Ÿ|䟞7~7*¿7 ¶®—Wì0DÐj <_érÃaÌfjCYï[·ÎÑáŸÇÞŸ^^žhz¿ ËBÒÙo´ß®á;o¹š|a®dÕ{08[qÌŽŠiצ;'ñŸ‰Ïs½šwŽáy¶·ëùE²¦AAãM'Úîêþsöü÷6ʹ°1§ôs Ë‘Þ^=÷—m<˜5†›é²3në*xß}zÒ¯øÜ§7\ Å$![Oç&^LºOä! KòßÎ_»;‡FL…NÎ0ßíÏ×xN4_n_ó5¾&˜éÏj|ýf7œ÷¨ÀHáÅw8S„¬ò™ÛâÔéÁ§bU;õP|Ê^hkDÏ¥tdYº(dK•²Å=q–EaávÕ˧˜íúñáæj¤û~ÿö%TF„GK/ä=ÙüqÄ=Ÿ—:a` ‹{{B?¤5?Drz8‰8%©f³Åk)V°ß¡ÅºØr$Ë`õÕz¯íÍRnÏÄ/¨Ì»ïã/¦seðÔ!)ÂK>ðYAð‘P$f(üð¸,²Ñg¨/w'Œ??›‚W*UÎ^a­Tu_—NÐîÔj+«´5͸×õ¾ÍïŒíHá=üñý•ðãH1 ; E!“§*æ§SÍß:žîM7 ðhO3%1só6Àg  \{Ÿ×û2?‚hìâ‰iïwÔIªwnÝ:ï$iÿXþ~©)’ŒÂªy4ÇI ÓÝ||´ãî„]¾?8ñÊód|¦ÓÃÑ-ÿÈ^æiH(ù€RëW±úeqë³ i^/s g’ÏZ4cqÔsÉŠêÂܼ5LIâ¸þŒÌªËþ»î«Œ­QÂ<Žøì`g0ã VHðQ?‰JºÅÉfáò¸Su­Ðz6±Öèåå¢kþÉt÷“éò¤uIÑÏZ pŠ{´œÇqé?£õMâ ˆC˜²Å1³i¬v?^ŸjË2ŒZí67T\Ù›E“zvú§”šcvÏ MczæTy[œ‰v¯Wçö˾xÞÿªèÚº—×îm9ŸŽ¥Ë´Â’û)¡n³¦h»F ¶{žïÌ¡ññ\ÿ¼ýø:`„p2öÙà+K¡É‹)Òú›«Ýš§½·â¹ôz¤Kä÷ëHÝGc¯ß$ó5z‡+Qé}‰”¹ïÄ, ÍJ¾Ô/&; ûö£Ÿ&nŽiêœÞËkФùr˜Úhv„G‹^~º"lagG!èÅN¦·Éz#®ò6tÝdŽ'anÖäæûr7¯÷`ñ¼÷ª`Sí ¡×f«ð8oCíQënßa ½NAm‹çÄFS ²÷~n®õ|U­¯Oð#X±Ä¥ÅÌUSËì)NP)‘ùÏÑï¸îôÔ•/í'>wÙOY û±/6Lx{D‹ä7üë²ÍT÷¨c¦0ÌçgL•RQm¨[•F>. ÊÝ/´ZTÊ|žÝ-77"²¤˜Û¨&n¡ð›4™FŽýê;q.‚>ÑlÔ‰@j#J?¨(”IÌ&kªMñF|}tŸz•Ür…JF&œamb0Îw9ˆv×®#ì‰kœ~v}¾su'I>œÐâq:só­Ì!ѵ=á"Á/ãeüs‰R%¼ÏÁ§ùZI9ëHïN!°Qß-.øÒ ™àÙ†£ë80nsÃ_\} ß½m?·T®^á¿YÉÆ½ùÂÇëx¾·èí¼ŸRD­{5°¨;ÇÇ=¶3åí¹"9ï¥Bd˜p„Yv}z3 êuPgÝär2³”‰m¬ÖÃAB%X”uþíVSFW‹ËÎéãäë.æÌ_BôÚoÛâñé>;4\¢í¸¹ßaz_v¤òÝ1A¤è•Ã镨Q.gò%½ïV~dÏ0ÆèÐy-¾¸aOYC ˜Œ¨ÍùL:Ãf[D×!+Ë•¤~ÞltPšT•„K2ðÔBÌûsbsŒ³T¤dg ãõÒ«ó½dNGKm9«¦ÿÅZ¸lœHoP'Æáà]5íæo“µÇ^ªç[IÝ-on[3Μxuš×þ“‰¡ôX¬²Ò+Q‰_¬Mkðr²ob5™4£Þ0Bò$.ŽBBP¦¹ ^9¯DØ_ÞŸmÈÖbSS§`1ÄÛÇQµ‰ß-çwÎ4D ý’½=Eã6žußVË¿8qG›i2™ª‹Å¬l¹M™LªuqWß|O  §¯³à߉ CdØH<&6ìqÿþðþÈ;…\î#Ú,/({ÖJiÆñ§Þ{;w‘£o·Î =²íØ-eY¸YUã´â—?nvë&3+z²Õ‘þºø8ˆ_šø+()40d•kéÔ6KØÍ½Kjr­,„úµh9B7GÕ©âýmYÍ>>qÆ¥éSv…0NÝ$\)ÌŸ’ëGÜq‰¸{0> K+oß`Þ:Twì^tÈ%Çõ:ï-0Ÿâ Щ†ÿÀIåV¬õžÇ!᪒“PÓgXmdàA 4ð òÓ/.I˜‡I¼ÌP9¾Tp6›QwQÈøÅDŒAÉ9Gè})x÷K²7™_²[~ ‰I5Þ'Mãô) ·O¶3Œñ^G± — ·’á/¼î<ò .¥5ËÃyœÞ¿‚RDËÖ 12ÆíÁxÓÌz>{Mž•A˜<0ÏÈÊŽ’Åw_œ Oޱ®Cg&;Xºó| Æ|oó¹~Ù­&óçà±_­6)ε?[ƒž÷µ”aʾѸƒ±9H~p}§_"sߤ­ÜýdÁhª–럈1xFßOÓX=ŠÛK¶]B3ÚxxÇIªWŠ>iÝìdbò:«?0Æ‘TlO0ooP:£ù愜cr¼Z°´G ‘+è3‘éG;Ïõ[Ý™‹‚õAÊŽ¬Lvø¡xLÐד„tü8éP¥w9çôâ×U;9ZjGùÙÁ÷­efÇ'8E±}ò3i‘R7' ç_¾óêqxÚ’ÄÓ*‘G]¸Ÿïxnä“z"\Ï6š·¿¶5[-Lñ4®þ†©n¥‰ý²2Îë5m:Ì6@3QËø‹I(ÿäìÛŽsxu”H3‚I¾–÷žGЗq~)ÃåñüK&cĘ_Ys¼mï';«JôX `Z;±Å,¥5…TÏ"KÒWê:3º-'iKŸMç>}ò^åú óS¤ØX}(Tc3:ÜÝEgZ\º–µÏQMÐwìN‡F ?pxºlH>ÕÚÕå +«âh=—à´íãð°ê |•Ú çºÖ1ãiݰy'Ô€„}ÞP:`M(V«Ð»Z¼L)Ì]¡DÐûr˜q{Ç.G‡Cœ¹ VŽI‹w#ÍÚÎ–ÙøÈÞî)™AÞûêónj”R¥|Ï;¡ÇtE7‡¢5(ë{Ó-§Ó¢Æ÷{ á³U&v’V/¿\\„Ü_wnEwÓ{ …ÝÜN_-)«ÒM`/{½Še$S) ƒâö¸ø€!Y‚EÂ{vä:(ßU}Þ YðP/;¦~¾!ë½ji+9ù!yP5᫊ðõ>ß_·Ì»A.eÙ5<_øékL“¸Þ¶¯7MU1©÷GA¨˜½nF¢3Š )tÌ!òг+­ýâ(©Z?…lyß¶ùiÐé¿»›BGoÑ t|—^íLQ‚öô'GŸ=…ÿ£ØÕ ,ƒÀ§Ôõy¡³·d0\qmyWZ¾ .›ñªþt[ɱgý™'µy”¬™ìÍ­HóåYÊêø9٬ׂæ¯Gaùw&¹ŸM¨YbYÐr›ù´ðBa„ÆM»¨]KqÔñÂT h„K“t=úÂ~&º;u Ú{|•5±<ÛØ ̆SÛÊ;nߌŠ0\vò<÷¹Ý5è ¬¥i€[î _–I(ʤþ4s•LJ‚YÓâ]_[1ÿB*1<5Ÿx}ΜVé¹hˆà¤­û˜ÿþeï÷°‚&ɧxˆO¥`”œäÓÀ$"i (»Ô !½´{J“ŒÉ2F¤'³”ðè°Eò7þ.1ê{µ¡ÄÊ B†ö“ ‘ªññ ˜ ¢Í †Z=ÒŒq‰ÇáÞÊH$,8ñÏ•Æm «câ+¾°! ¹—8m?òõéyÆüŽLJø%DA¡Ž•¨ù1çDŠdùû¶iþ)‹ˆ¨_!ò Ž´<©ÔoÛÞú‹hXÔ¼áÿôEÿ"àŽY‰ûøÉš_äØS—gŒ´j¥Qhå¼JIÚ–UòîJT ‰]ú¯È/ãÍücáY\¨ü_õgw“[øXZhȇזì2Éëïî;Ç-×öRù¢ë}t¨ù¦†›³ðzôélյξQ²¯ç<¶œ6§ÎN•¸îIî;uö×w™NUpjÛdfC4¦r×:~C¼Ž£‡VYþoX ‰}U§Š2·‹R‚Ò®H2ÒÆ&¼ˆ0 Þ«d±²bV9Z†ø•¶Í#ütlÔd3õPË$Ýݹ+=.b1ÍŸñ?ÛÒpK;MœÙPþпk^pö®XèѰð”ý|æcû,ì*©ÀäuxÄù³¾/SÏH¢B§«‘¥V£šgé!=_oݶsׯ¾DŒOª¢fåf¿ëRپٲšLûÊa°Ý¿t`Äÿ(Tºø-}bOEÆw§Pi½ELÁ‘ä'Ž/5à}ßãch[FëbQhãÈa™Œ‘ˆà>jªÁÿxf‘ä¤õÒYÝeM¤‡{(6¬êSͳÜFÆ0,¡£ã¹ çO.bLJB‡žµÈ]S쬵ÿH04NáïÈíê Óš…u—·  ÕŸN“¶CŠôÛåçý6iÔXUù‰„­3ˆ„÷Z‚ÈÉd_•Dúë+Is1ÜEÜ‹œKÜ;Çâ7Z]"„Òꮲ28™ØÚ{œZ4P3Htð‡K1ÞyõkœµQÕÜÃä°¡ó ZU‰oì/‘—RpÞOí¸= ì—¯øÂß‚¿a³ÃŽ/œLyJ@yJ2’&úþû¾BVÕ¸Æw¢P‹7nU%ÓƒÔïÕ{¾XYááGÖgß(32ÈÛ‡ôéôç©Öò]¶Ó—” ù"t%’’‘Xܪ92×MÚ`Þ4ÖçiL•[ÍrGIt¾#!ÉÀùìO+.Éleyoñ˜ý N#*~_×”²UªÜá­3Í¡âã6È…’ É.Ëéô0½ÔD¿ãÓð](sjÌíHpÔ)‘Ži&üݳᬾ¼ì•w~ÉÛÒ7ØHˆ”îC^¾•¾³w,ˆȰäú¨'5k´~Ž÷,s8Iûñuôø£Q<´›×ƒiÂ_/´Õº»4nž!ùr‘Gæ@žî5mŠÂPIfG„L/»¬@üÆß’½ î`xÛ¤§¼Øö96©o+ëã†4³œäØô Qƙ֕־ÅÞÖ¦9ýJ`Êbÿ>:çÔ'´› B"§X÷Tšˆ‹l‚A1hÁòÜßlJY…Ö£–+ˆÿ(wâ²*¯ä—ý4úáV×-;ämZo0 zz'ŽæÏ„¨NýŸ ÂuJRĉqÚZß§«-Õd*^¾of# äe}¥ùs•õ£±×P\öœ z~—ÔšêÜwÙÇ>èðï¥FzŒ¯£¾g­×=z;]}’(@éÿn¢€óÿaïM¡üºÇñ±¯e )õÊ:Ã[”%di³T”J³a˜E³$$IÙ¢¢¨©¤d)Ù³Q mRT*¡EÊïyžBõéý¼ß÷÷ùÿ·yæ.çœ{î½çžsŸsî89R}º[yÔñ/æ × ¶þtRå9oäÙ„œÂÅnFåæ²DÇSöxƒC9–Ú1ëí×ä—ÐÞGñøvºw_á¾uu;#õ#—¯{+œc­·V[ÎwÀÄJû¹|Â)"òN{ºÂ²å‚»¥²Ì¿¼ŽåW8žÑÒñ8ÐÑæP{—¨í… Í$©sÎæ1pƒWcÃW‰FŠ_×]¶ÔÝuø°éPÒ6E'µ[꥽[ĺeS¬ë•_þb±Ï­y"¬™ç’‹Wü³ºµõþÔîB4¡þ’võ}׳§²yfæw]fßm[T\6ãÙ6$½õœ@«Fjœêùª¾ 3^}sw}²`dErŠˆIèš³ŽµØê¨Ó' ~üu[:n¬ÊÞ"ÊŽB΋n41 ¸ª'·;¤Bz÷½*Û¿cYS½gÿíú¾ŒŠÛÒïÍ+¾’>ä–kÝwg{ǾÒõ‹ÝÊEÄxïuÔmV;1´ƒTš^qg5ÿh²ëóY køob-ÏžT½ õ‚#ŸY§Y8 ¨q#ðÞvÉìâð9ÛÜ’vJ'xý×Iú³­0Ø/ÅÁ¶8ÛkŠ7º®s{Ó-!v,;LÌ3’¿lÃ;_AÙ] ;nÍÊ]ûr/ Z«»j3éTOî¼Öëδ<Žò4[ÎF汿<³—éæ¹sÂîÌ<‹èù—°–Ê"û2Ú õºË«·f¿Ä;òRY䬶%·2Wç…61IrÁ×y–Ç“Mœ_%=>þünÇñ¹I>qéO+ò©jq”« æoBßåPê=$ýø„Q2E€Åú¬ùç/à]^ñ¬NÊ%y½* ‘ë¼NKc^.#€â‚½=oú Å*wöópþ»çky¤no|º§G„_^X5AÙžÍÓùO)á³×eDO,šž«z±UtqÆ—ÈÝ‹k(€d[nÜiáèÝ;ÉI‰¤ÍÊÆ]µ[ËÜtCÖét»u“ùØÉNÒ Ös„[Zˆùü§bLó{Ôf”KŽÔ®[F>}ƒgSÄ}³$ß̯1¤êzž‚^1"MŒ‘vSŸ ö¾f8§÷á²bI½*«)Ñ…"—æ…,®ôÉàEœ‘}Þà±G]¼óåÆŸ¬B^VjrR¹ŸÝa±ëCEm²î½Úe†¦qvšó2œ76S8k%ÜŽZôˆ•§‡ÓmU’Ú%YrÕ±™bê|×ÁI¨@ðÊk»øÅ£g²j#y< íø2f·+tÅ`vëÚ¬Z”6¯èµý¨J†á¼>ã½EÆþ§©æØù‘vîr÷?žtжãPsÔKHLu=×¼°‘3Of3î°u‰ûXìkrérÛÀÎÙçïzÏ:E>|êcQà…ü£: QW¨¦¨r´³{8H†J“XØÕˆÿi*Ê»¨îyë.¬×\}óQôp09xÞQs%ð\—f‡ªþ…r}ÌÄÃ÷c”ùv¯×n²òmÛØ8§uÒÈóKˆx“ÁÍ+”¡@ÿÏy,üIÿÉô/ûižôÇoý?ô  ƃÅb  ÷¿Cƒ?þÿH2âþ 3ìÿaù~é`ôttõÁGc}ý ¾¢4•,÷û%’˜ÙE¦ÓÀìU8<…D!1™ÚƒD Sè (C ²),2 Ì`SiÚ€'y+‰ÈñŒàˆÝBb09 ÖØ8»Ø¯\!J 3 D/ Ç$q*‚ܹ*Ê„\I˜Þ$‹éŽ£P6¸o 'ú³ˆŠšö`¿TLŽH±âÎäGÓ^€Žà‹ó"Ó¼N/°È€(]=”žÁª†hŒ.RÔA÷!XP Rœ$p2Qý LŒÖÀ`¡Æ)ú¿ÄÕã§éwëŸB÷¢ÿûžœôÿ=}=£)þ`uìŸõÿO¤ŸøX€¿ö°ÿ/%!ûòÿð~rË=`Æjöh ³´¯¸õk Ç©k™Aù©»=e­oÇ;iKEeˆßɹ© K¨:•´^N‹D6ŒµOßÏkâ±t˜Ç&^W¶LÛÔ´hQ±ioë×ÁOÁŸRGÞ_ÈÊœéi¡ê±|ù@PßµO©ÌƾóŸÖ?ü›)µLªŸ…-vz‘Ö¥„”õˆ¼¿´”¨§X¦Tè§Î"„îjW‘Qùè"§ÄlyåvŸ–?•$õì¬5"RõXð.b'B×M6?šª¾DV@Õ…2Kýðž"žÆÊÆ{5û$yž$!ì¶áO¼)gX[#B…ùß«óŠ ÑyžÇ-áßj¾3²ÖÝ@ÁáÛ¿ùÑÞ"ÕNÀôQ¾òäÝ»2µ^´Þt¢|²CH/¾•è´ìÞ.ã–Ž´];—Çd+›ñ(^Ÿ©ºS«Ê;¦±ëÎJ³‹ENªkvtXDKwé bk,ߨ!ÖÊ Ô9L{{:Ê7Ù ƒÿK0¿‹ò(”æË·Ü¡ÐÓ}™6Ïÿ³£«¯KÍÃ[ß]*nM³éàÉI3åÉ®Øoå³AÆFвÃÌQ#ÙÞ˶ïÛóªCG‹É3=¬=!Ô%³wŸÇ‘íldĮР‘·§»½¾5BÁµg}1L#=°o$íÿ¬8“¿ îÁtÂöé¨U²Ö’NÚ~bì o¯ÒëLVwÊÔ¸ôy‹Ë\¶W"žo¡+ÍY[¤¸Îôäü¢·fù&7f§ÉâcCfFK¬ë+Îé<­’8ZAZWv¹†Ñ¸¯+æ©mPæœvs¾=í²ÊGcZÚøTTÂ’)¦Í·yy6ï¾+¼ìÀ.‡’Ã2I©ø«åò½_Fšk\Ì“ýS^¦Tåô{Õ|ŠÕI9ß’ª/Ak-«MNn¸SsIÇÄ,.¼-‘MOï2¶«Ÿ­8òeŸÇ»Þ Ý\×÷?vë}q†W8kÙóÞ6l*jUÈ{*š* †m?™·—~åu>}keQîF~¢½ã«¨Øˆ«WÔän§t­}öébÜצÝ]jæÕ<‡9u»÷ëL sŌ▶ø¥—m=6äávØÈíg®vÖ>uìàÓ!¬ÔNïVTã쯕¨Ò®å ç^Y1«‚›ªÖ󿮵]“èK¾ñ²}g¬ùÆégªo®ßJi;.÷Ù0’Àïµ»‚劖Z&ÑSú¡ÂŽûù…ÛŽ½ñ>‚2Þ+E ¶{ï|½¬ÂPß^wFbÕÕ7ÕÅ9›kvKÎÜT¡]¦ƒ’z±L¹l¿KíçšÁ‹6¬ë>±öBdôêâÍOýaGT°’O4ëÏ«òFòl½ä¸.)…Ò»UQ™~K缺M²I%‚½´ýÄ—Lô“û…n ‰†—GjQ –MžÝr/ß±ºÁˆýÑÏÅÖó%o1~¥Ebcäçò‹îèúCëÏûlí­a^ï—´àÙsmÎõ}wnïõ ùÁÀáN]*^Z‹·~=ÃeŠo&ÖÜà¥!«\ÁM¼*[!Ýœ–ÑÄWjWf\ÙëÚm…405DVKÆx\ØX-«ƒÒÖ&Æùìô.ꑺ¹TRfÛª¥K—®Èà'ì|Y^"$‡$hî®Úy–ûmî~‰Në>voFh÷«WÉYÓ;Ì´ÏEZ$êa[ßx-£÷]q–[¡ñ¡éØÒ1¢]É_£.»f6?R5¾¥|dºDÌ“—=·ynÀjõç±[6-V}^üìÁÊš3ׇæàç п0›N'îÝG=wñŒœ2i“uÑCu)kagÔ‹sD¾[\²×UÜ­w8«^qv}=&†_€úò˜¦J.סøÖgåp—êïå–Z©;³5»˜[úH‰Ú¡uèC¢ÙÒtµí‘8}=Ý_Õ%¼Ç•W"u«ë’hc ›EïÊÜÉ*3ðŸÍ‡¢ï ÄÔŠŸXs¤aÆÆsk´uæŠhGúë}]b´Q쬢œA†ŒÒÀ–‡žÈ¤›®^9$ËŽçEWJ?]Wï*»t¸ªÙoùrÀêü†Öä;û³]ôï|å"¸A*¸°  3¨e㵠̺³,Û‡+Ôu=ƒ1è¶ÑŠ{|A™‡«OÞ‹b<¯L×»~Zùæ:wmA!ÕÊ«É{¾??'ñƒCð:ß>»€ßíÛU©8’š#{%®sCpçµ@z©gø`!É|Ë)×”'››_+y”bÆèÂ.ž‹[¥õè¨Ô©+¤´@)Y-÷–-Û_[uµù•[¸wܲýs·UÚÕþ÷ë›wgŒÔš«ãΰ[·Ë·™•¹ê°Îš8ŸèŠ}­'ŸÜö]¢x\¾š÷Ĭ|u`ðKã«"âÒG¡¯+î³x47æÙ‹7ó‘ò:Y«¦ò9”Ù÷µ"OþhKr2Öµ>ˆ_±¨è O=Ú[2@Ôð´‰~uUwž ûùAR4ò¸xIPÓZ£´ö ø»…§KÙ­Ô®Îë|ËåN¼>¦˜†Ö Çð`b9nmÃïÒ6Žö¬Üز>m½á>ÆËj%¿XgM“»äc¥eöŸ_É4NrlI jîÎ÷O‰/q[ÂX;z±1môÉ-ªúÕÓ‰þ¥.€ ÔÍé¾ý$Jú”^}ÿ†9ìzT™|NÌ0+üÊTʼ•į6/ŠxWNh]ZíLߦ¦Ÿ¼}*ÅìÉ+.xïUêÿÅàë4±ë‡SB Žg;ÔT÷¦mï ïÛö&'‘õÿz‰{:»ðR\¤°¸'òÃÁÖË2\¢r\¬;ò:¯žjc=œõÖè-JûTVñhî¬ü‚њΠ4¥¤uÍëC¾^Ëßö|g“t‹=qÛÍð‹††2Z˜„4é5·ß}˜ºvÅY‘aƒnwø”èOºRŸ´¾¿åŽ^Ðìô 'ûÕ0KÔ°÷°?~>¯ŒQÿّǾ´Ò¸ðÜà‡g?ÒUi§}°q7V·¹Ô. ¯>år†¨Ù¦*”a#'|Iºå‹[å0=êctµ>yó‡åòóçË}¼¿GÂ,èÕýõ òž5¹RJ’˜Ÿηo³ß·rYn^AœóIÙâ1Yç+¬Ãv^º(¯¦v›ŒvØ«±àå´½ŠÌ.‚NÛû§ØM{ìܲ·n^È|Tj6XYw¿-ðV”Áç×Á¶7ìÜý%.WÕo¼‹¯Óò’Ò"ˆkШ}±{¦H¯Â_•<mãÕN¤mð}3Íq´Rë„ÇÕ®™Ÿb‘äÊ‘dä¤[$B6é%~;t±›ê»õÂ3ómoª7“é=›ª*Ÿ¿š§¨‚Ñ"Í{ÓtÎõ¾Wý`ÞqÅÇyA«ìÍõRŠ_<Ú·>ðKðʹ Žìg>6üTÇóeÍÞçoySZ²Í¬´CüËÞôË¥Ó¨)”µ•rvöYÖ~h¼~X@n“Û™†T™RMôŠô3bKZk•É_½û>^Lßý‰FY4óî!‡fú¢ æ<•¥Í^¸01ôÂ&wÝSäö Gy®½÷ß…µE”ôצwö¿8ûhmÚ•×w/ë÷yñ$³d{{Ó饋K9Á„O¥Û†£™†,¹õ#ý:Ó{hO×_õ­3\q²Ö!;çëKɬãŒmV–k[#¥P hyÎõ}Áƒ7v:eÇ×iÙð+ë8¥èìuþõ+ª½Jà˜#{o½6¸önWiJ¯9¸[V+„õU ½hs—Ç“Ñ:óÒ.{ÿ¨§>ÆÃ­íE>—üz”$>‹K:nN°ù¼hh¸ùõ¾úW¯Ú“¼½‰Z<‘Úºq8ù‘^åR=! +Ù©ÐÝùüòå ´ S>™®ÙvNŠgT–îÀ»Õdè<üèo@ã3ôºßv“»Á‚¤s_L’bâ¢(fšV‘¡Ǩü3;•äi™Óôsó$lªC:;j>Q°s}l½SN?R£º$·¥zFfRJJà‹Ý^mD•ƒ_‡*ôžtÜòyXvÇu@ƒ¢À‡•‰Ù>XÏJfQÏG¨$Qœ§8'JL¿ß—ñÎÌïÞLñ¯Ï9;hä¿MlHÅú¥»öûi©ÝÌ;$tÁ„¬i­‘Ú‘pæÓÖ¦—o§mÐHNßpÏ×ìY?;?#°ºìÔËt¾v޶³è²ú9EÄÅ„¡Ó—ê˜Ó*ëÏ—®5tßÂôú´·_ç,6áØÆw3÷3Ú’Wò¹ÀÈìcÍ\“`ö,Ѳšê¦©CŸüöE‡9ÏØ­§Ùð Ûõk£¼ù•/YæOœÒ,g¬kÝÄÈN=Ú×™ÇÈIؤUN‘ÑŠDª{_ÿøuG{‰âG“¯§¢;.Y.{8Èl~ÿMÞ¿±+ÇÎ`罨§DÕ”lÁÀGàÏ“jÏõÆi=&º†Æ‰GÖi¾¸¹7ò~âêÅ>2õþ¥’þ»ØÖ”‚«™Žšíƒ׿Ÿ–ÑHúš²üu,ß™aOzß‘ó·_ öTìÌÖè9Û7-¢Ø-Ïö‚ ‰|8ãN‡q5»:Bbš„k•hÔA‰Ç3æÖ{/íSšÒØ€m¹·íÂ4þü–›i—üZe²¶yµ^ºcæ3ÿÌÒîÖçÛŽQfQ8×GG^G¿_½©p8U*ÊÕ¡b NE³±3s£xÑ]ãùô¹÷M±F^oMÜnl2ßÛyòmÙS¡@E¾_ó”Š{bÏìªÚ•sâòC¾£âìä 7OïakD í9››]˜y9“¾Ájé,­= k6UÕ_B¬ë(~òá\ßÌ÷öÓ+;F¥gGîñŽŒ”Â\×Î CìÈ•¬†[·®R®¯œ·èL\TfåF’fº,Ö:WÊ›/ç˜s¶Œî¼kñݽo^m¼\r)#6Y7¯ÛsûøôÛŸ/ì}uSh-nô„cÙö—Ó³,Óì¢vî ¬q8(MH2]CõõÕ‘»Üyâ€L͇Œ"œ˜&OÒF Èà­>Uv³Tïxƒ¹œ8pþµo vm{­Æ}Ó|z'ú £™ŒûFª3SÍ>ê3ÏÔ(åÈ‘u7Q«5W£tïL+SÈÆÏ¯:˜³ÊÅÅÅÖË•”™#}3?eŽôœ^})vŸÒŸ]d+¶‹ýÀºÕ£ÃO&ë3á)á¼i©õÁH9‡k F[.<°úq‘"½wQ¶7f¶êgE‰Úù@BFdÙÛ‚%ñ kfwcÅ.öZË{…õf‡îöA‹WÝÛiQñl·¬ô¨ÝòÈ>‹˜AûðìÈÊ{IøânD亃j£ž^À.çû2}bÀÚív’lo!ólÿÛ={lw.½ÿÕ–¨Ê„Šî2ÕÁ‘#Öüˈüõ¼e[íú;gf±¥-¯n};WÑåCüb*o.ˇ:&d´üé9eUŸØØ^Ï€yw³ËcÕ‹%ûÐÓt–…žíŒëP*×p²lJi*{É.2°)˜$Ët¸*T˜a÷)%–*3œˆ˜>*”•z÷øê ¬tú_÷6ôçÿ4:‘„fùQÐ~Þ~ÿc¿yÿ‡1Ð3€â¿u±X# œ12Äü9ÿÿGÒBsp„Eut8¯';üЀûPWƒ"À 0&z &¾47]H$oÈÄEH¨5 ø1È4  ç˜ÑÈDSÀÜ (8&“SSì ¨«2Yd‚o€Äm¥prÔL`°Ù÷šÊ`U‹ÍœXÆÀ¦ù±ñ2Ó›Dä6Bš‰ŠN¢ÄL`±$°h¬Æí‡ó"‹º&P,ôÖ3[ˆ¼A3vò‡¾x°¸',2‹BšR΃qÿ4{¡üÁsñ“hD²§)Lˆv;Øx*þN# ,eúáhcÜ/Ÿ‚g<ßF51‡<4`\hPŒ: lN p žB'ø"¹H'«Æá‘àGH?B˜PJ%±p“Ã}eá¶ÒitjÀ÷®NnÅ"1¨Ì©ü„òà.ÂT|‡ÈéãËÆiœ„B¦ù2… .œ‚ Î3ý5ºÉáþýÿzQÿô ùÏýû?ñúøž~çÿ ûIþ ü×7ø#ÿÿ‰Äõÿ˜8Þ?ôƒô°ÐÕX½Ÿ¸Ør0þ-ï ›<ÉûP'’P.ࢥ@"”Œ©h0v:(Š<Á›ÞdPŽÑL‡ _^Šf”‹†(ûÀ%g1‰€c3I! °¹Nð…ž©dÊ›5ÖüITƒóÀ1pÜq< ©[HÒ8¥&€¾îØ]Kžd…ñ‘‹ÉšNScbçàA,^ D&$kÇj22 °·Ñ†p€Ä:ÝXPì€mˆhªï­!Ó†F‚±±Aë†A¦âãóh y+Ø &š,º–2žÂÎ$CÛ ÷bâ@‚OP @m@¢šrÇÌud@S™5`O 0½Éž,¿78Ñ Þ8¼™€"çÇ·ÈÀ!ÁÔ{³¨´sš[‰ n¤0á?¡L”K Rò+ ¢ ±ººP+NQx:‹E§šÜæ¢,œÐl‘Ì„öoâÃVƒƒìI†„À]¤°rqÁtp‹$³¸k ®cÎ?oœ:·h‘®ÆO–Ùÿ­i6¡/cÖ 2!P~à‘Iþ0Þߊc±po”7´Ì(8< ”a*l? G7x/Pž0PïyÅdB tlZáˆÐà‚z$¸S€{ÏZŽØ²ä-›)Lœéì»›0˜Ð(X«2T<áôo_(ö‹ý6ãþS@¿õÿ6€öCCP0ÂèBû¿‘ÑŸû¿þ‘4ùügÒ°s®äÚ `è›`˜` u7Ÿ|ÄÉ2£Ò‰lPn¡ÕPjèñL"‰ÂÂM:šp†Løÿ¯@N<ë‰@s€ >V‹ÉÆC¸Æ¤óŸ@ãÖƒ ý©g4¿<5AþÔ÷³îqÀÿæS_¬ÿ1£êŸ8ÿÕ7ÒçÚÿzàúÇÂç¿Fý?ëÿŸH“×ÿÄa‡—?ÆpÌXzc¢od‚5š(ƬHÑv6HKG±p^œõ€û'ƒŒgƒpÁZPEK"¨Ï©M¼^SMûûgXU@Kb,‹©ÆnœàvO·K žl6×'œx@è=àêªpm@†©oÍœƒ@èJOåE€š0>·˜ó™S T9´/š@¤*ƒ¿$ “Ä­5ØXãŸ4çtÓ.þÞö'˜֘ÓףּE¹=õVKÓ@c ÂØé8W\A2—­†äö"x|ÔœI,6Ô 8g0DêÑDƒMÅ,ŽL4 ?GÅÜx9” –`[p­ X†&Áw8ð)*ÂÃÆç¬ûþªhÔù±Y5ÌãuÕ'õ}Ç·‚ïec âR¡6Q¨¯†49F±Ð‰$u5 cG!ÎÏI8Ðj©þ7¹†&ÈJHe`“ ê¨Ã‚Ö Ø]*¬ þE·¸U<¸ÖšúØá»6çÄ„þËoÛ6ö®…à¿ÐP q6Uí§ý…¶ê1:எÙҫI3ý/@€›ê÷q\–ºš÷³‡eàÖúø¾sq%h¿2 ud“Ä`ŽvŽ«¸,¶àdˆ½R *ÐešSöWœU~Pa'€j¶ôâG}¾*ˆÉáüè®ÆÂá™zjphùx0I ©DÐVô÷vŃ…cú2ÕA³Rñu;Èì„I€Õq4G'áçƒi+™Ébª«Á5ÔÆg ü¦Ã6^Ô9Äü|urÄ*ÔGH p‰ÂÄ01h`XÂ=7…'-lnpÎ09 ˜hFÂæ2ØAô‰  Ïô£Y0†ñþr-}pƒf‡GD@œÿ5“a¾MâÜcîôK¹ö÷TžBGµ ÆßpAKΚœmÊÐé*‹L%kö   ZZ èœZMf9,¥Ô¹"Ví{)°ÈŒÓ1uµï-€qÚã-Æ Ã-8'ÅPÞ8=àú‹áã] ¸•Æ_t ~¡8¡Oß÷ÿ¥Áþ•ÞpD wÐkHí‰=;ï#ÑH hµA&-høs$<|ú€*$à¼jh,Ó¼Øà ÿ«EéEbyAFÀÇóÜÉâE•  :Ö^oªd³).„°¨ƒ^neé€ùHèdòû)?œkD2n»Hî ]Pö@!¤àªcyƒ¨ÐôàÁ¢{p¸ɨ GßH@‡#™8›<—Ðn!3Hœ~€‚v™å ÛÕ–¶6`ÇU¥hˆT˜ h@š™¸hé €ûÔ¡, L¡éBÁ˜ý>y84üö\àúÿ"ìs<ýíøOŒ‘.öþÿ¤?ñŸâ?ÿÄþ‰ÿüÿù'þóOüçŸøÏ?ñŸâ?ÿÄþ‰ÿüÿù'þóOüçŸøÏ?ñŸâ?ÿÄþ‰ÿüÿùÿÏô‹óø¥ÂØ[†ÿ)Žßœÿct ó#,ÆæCßÿ«ûçüÿJcþÿ“vý1¿c` Lt L0ºSÝÿ!cø¥×ø;1òëB2aÜ~8îÆÿ“vt }0ú×áx'CNÖú$*yZsuǺ¡·ÊÚšÌ"QQ2“5žÜ µBérOnVžÚvRsØqg²£4ƒã[¬Ëõ-žH1ô‡zž Ê¡ÑÎs yƒï=ƒŸÇ(ü›ýpDÈé ÅpA0õ8À&;ó8ÓÇ€|0Ø Š:’ E0u`ooÚ‹ì‰ÔhtƒäG±peÎ`.~ïñ¿Ä#=n ˜X4i«(^¸žäÿ2Ec­~GÇd'÷Éx3xüšL£@1h\6L`<ô3Î'4äÞÀ¯iJýØì ðÀÂã ?ýÈö†ÿ¸<o ½öØóF~[nhÌTp,Êï0 Ñ:à•Ì$èøãXo"Ý E÷Šæð¯ðLèËüšÂÔ1v§Š˜Wcã2¬D„†ûHœÜdl }_hÈO…g³XP`çÇ…cRKxp8hÐcSfJ¸ƒ·Þ\§Íx¤ÎTÖªˆžž¸I³þr™à|å°—âŸýpH¼1™ê5qvMbëX‡¯zp¸xRè8ð#\‘ƒaÒפ£9^Ђ:¦tÑ€õ£2ùkÓÿªÔÐ…~¹ °‚î…€r¼'„ A>(PìëxPÓ›Œn=¥ÂÜÌ&‘œÒP˜Åd¦{¡¸°ÿëÑ'GñàðL:…ÍúÅÃáLÜÑÁrKQdP,n3&n¸ŽÜè&n Ù öƒ·ÜïqO(޳NÐ÷Á„ÔD9ßPoÄ]‚?ÔçÊ¡ÆÜùwÌuìGÄãne¿B p. ûÈA?µÕ¯˜Ñ5µ|"$¸žÎò6©7ÞÈ[íOfy£ w¹Ÿ@:«¿ïr㤀Ôâà­û{Ƙ›šàL¼¡ˆ½³·ÁéA"jOîÄ8è‰Y“O®<ü”.‚© ZkДã°oI8Ï 1ŠPèÜP…ó¤oô`—/<Û‹¬Ä]&@Ž1gl aR~ºƒN”â?K†üÓ,Ps}︜ȶŸ é¤vÀ$b¦Â˜P‹¢9wNLÊý‘¸)$/[3÷ú‘‰˜Æ=ÿ~Ò{]Óß,Ÿ#‡û8Ò6±5TÀéÃO‹ )B›< þB¡à¡H!y‘hD÷«ÎM!_û‰"÷ojcšÃ_ÄΦûSêŽmùS%É¿ºõB;Ê$xc{÷Ôñœ\ =¶ýDÊr©_F‡^'Ð ¹¢(P. ÒqÆ ¢Ÿ¯+(öG¤‚à¸áŸ é •8þÏ(çJ”•ঠŠ1{CØ“ÔÞÆàj,œË"~µ‹s+ý::–³ÃÁø[åHòDÁraNj=i_†ök݉ {Aâ¨"ñ(Àš~¤ÑYp|ƒ/î< L<ƒîÏä¸gëp¢†Çˆ£Šy«29q¾·­zòfþÿà>ó}l pg2aâÐsæ4êðT"Pèl*9Þ„Ã8ž‚Žêpÿgsô aö¿ª2I7ýµž6i[ ñó£@¼Ìeœ{  éI!ÀF àXs°÷‡ˆ€ƒNBV€ü挄`©3I$À›Åò3ÑÑñ÷÷G3q¬@жÿGI'1Q‡NóÕ-šç4$þ4Æ'ÄÑh ©Åp.b'Ô˜æ«=þ4åJxk§\óþí˜ã?éOšrþëÇfzs¬[ÿè”×ÈÀà—ñß`šrÿ“!Æ‹ þs$ü:ý—Ÿÿþzüq p{‚oI@q…÷¿ð»ø=C=FWkˆ52ÄèaºzzúîÿúgÒOüÿ¡gIa>ð…ô9 èã²U65É´û…GG†Ï„uÝ+o¾| ÿÍÓÑÑQóŠ`a–ó —QNB< +^ æYBq 0ÒeºÂ|å×ç? y[zc—Ø®2Ó«{Îíˆh©C âUUfÚójGd[kÔ{],¿î)íó®6yJàÝ}oŸî ˆÒÿºWsÿHúõú‡Õ_XŸCûøý¾ÿí—òß@«;eýC—ýYÿÿD½?ú!é°Ä~ ‚‡œà?Äè[„”5›à€àAðƒuÁ¬^ÄtK"OBËÀžÑGˆ]ÞñÄýòóAÿ ðCI@PN‚‚BBÂBB‚""¢¢""ⓟ¿€ˆ  È41±iÓÁ$!—qÿˆKˆÿE-CH #Ìûùx¤¼R<|R<£•ˆs/Ï÷Nò ð "DÀ<^¨h¼€—‡!È/ $," >óò ñ óñ‹ÁE<¼|~)eŒeœ´ ÒYw‰!ƒ½Ì6ܬ2CO6×(tqü]+—°MÖ¥ @<‚ü¼B‚Bnk)>~KeŒ“´€n³žL¨`\:Ò9+{é#ÞjU9~'A^Xaô!Bœ¤IŠO ìÅåÊø š‘ê¯'r[Ï;9ö›ôHDÛ›×S_žó^=³J5É´§è¶÷%ÌAgû}ùý«sõ«1vÃ`f3u&ÆÙ<¶ iÚ4Ì.Ú7Ã'Þú&Õ}¦¯É1*þïSÜŸfѾaK¬–…HµÛ¤÷ÛŠlƒåôcž¨”„)ŠÇ&Wúß&»çù^飢ä:ì&Óš`EéçÁÒœ°ùkèR편]¶•!ÞÃÝôÛÍl‰è0…T‚»âL›ÓŽ+…üÕ”KâøcÕQ½:(Æ—¥É_´ûî­ëXy‰Úõ:ËíC•ÑæçõT…š½wCæÇšÈÍœ9H™1ç로Ӟoî¤x­,¸UtâˆMB?ëÓ‚—ñ_’ï÷aŒZ®Ì‘#Å]{ëêcf’=Û`Èñò5¦sï¹{i:²ïóÕeQ±Z¦Ëª+X…9%Qhš`|>®6=.âXX,+~¹ ¶`ÏòÕÓ:U‡9‡I®ó‘™¿®üÀËpé¹R_Ot_(µZ}ÏLSœ` 2Í›$—n+ް:§¦¨ñ­Øó€Û‡ekü0Í}WT–`E'C–"›¯¼¹¬YËŠÜSW u_¼ûòËa¹ ÷~ƒkƒtÅqvkâ\JÛ¡´U¾º$#®ÇòFKÜòB*í¨\ _Ù¥Þåóòã/öœÚ}ù¥AP¨RýRq´Ÿ=ZÄåèß¡ RɺÆAæÛêæ¨Â%äüg×_¬¾rc^]ÉÁ¶Þ6z®LÍõO›Ñ×áÏ©ç2š³Bb×ßêk_ÜjM,+•€èai='öJæÂ UUwÎê3Dè/ ßÔrŽ’c%Âë©n¼cåôòpSßòoô>¥†¨–Œ0q¶ÖšÇ«Q—7k˜-Ÿ!Ól’—Þ=Š@m©VrͨA»¥-7â±ŠŠ¦n ghtx"°Ó]ÜÀ¼QhyxV^]¿­…P©½ŠT{nzÌE“w*›‚%BÙÍå½ W><‡ 4\Ä®H)Ž­;´`:iQÆ%Õ´,û{ø Å%ˆ-¸Ulaç[Ì\ÓfŒu°Ý´ Ö@#p*Ý"žt~¦É=œòû¹Í }4Ø`Õq¬»‡´¦:ÜÉGVáv58ëµ­NcŽïé—,±°ü@<*l«É^þþKN+óÑ’¯û»Ò sn44¬±vN{÷UèΛ‹ûòŠïkÔd²gº*½ÝÕþ±hî—°Ïþ[ÚÊ{>¼Ñ\{Å)c ßÉãÞ{®ªbÚvË[}vÆ;oZΩh9Ц¡±­îza¦úQÄñù­>_ù¨MlVtaHþ¶Þj ÙãApgèP_çH{ÝçCŽ_L—ä„DD_>Ø·ÈüöÈ-œûü[IG¼ØòÅ¡ªunzìÓºVæ¹Áì‚W>…U–1^r7/ÄŠ¿§ŽIq×Ìw Ç8lä_ÎíÙvàMØó®„À´¸+3RäˆP®_±»4fåðæÕksœÜÛH£öøR®Úê¾xåðÍ÷•´A(`FÇZ¥÷Cm7,ƒrì›’t×gU1íMNæ¥Þ¸¶ßyûcŸ‚&Y&óKÂúЩ!ø9Xå‘ûk-Ö¹òú»6„˜½ü8{$«™•`Ì,- 99E‡ÊÈ`Ǫ§6_ÆŽ"¼¬žcþzxÏ®!×ûG‰/4ƒ¬Öl²÷»ÿ9xàäÑ-äk"4˜x´] ÃTkšJgö õcF®Dt–¢}¾ê”4†¾ÛN1b±ítpJ½ÇZóëUkïûÖ¦¦½Ú·°e‹ðߟs™Ý‰KÍ|k{Ø”pÛèÎâWéàF1ë.žgâAÏ…gÌõ®½?¿bnÝ'SR"ƃ±ÊT:±qý¬ó§Ènšv½gã­*ý©’«¨w žíõêÔºäãp‰|ªhæa×¶«óSÙ++›¬©ãѪŽöå~B¢C £ˆ¯!¯sŽÕ£U£Þ®ÚsüÙ†„L™Ç(ÿC&‡-¨‚å/¬~jW÷Í-=£ÚÊ·Ñ'Fæ›Bü™CxwpÝz†P%^î_¿0ÅSuIü›µR+Ps„ðzŸ‘å¹Lȫɾ鴫I®¸æšûhù-ºfmŸ\p#F»BÏ'z5-UÿkZç•[f$“Є—q¤Ç 7dt»µmÿ’²Rl3Ò!òNäm»Nüu/šqðŒ0ÒÙ[#’õ…ilj^dêÕ[q´ÊŸ=sïF\I2&ÊmSo”¸Û°Â·@Å+Wû_^µ9u=a÷t÷ížQ{¯ˆ¿±á'²˜VµCu?¿¡·°³½ÁÞyÖç£{¨…›¯RG ß)Ü¢€sšDÏžÕ]ðFˆ¾™uæaú.–Âþ¿½æ­„ßä+ïb †Ûâ\%AÕYJrú³”õgTØOd¹M8úàŸÒÿÛÓoì?ÎY?üìß7sþÝûÿF_«ÕÓÃýñÿüGÒDû4Œ8öß#„hÑð@?cž”ùùù@#GúÍ;Ñi¢¢bA&$2]bšøtè5‡Z?âÂBÂeÊýo6ã&ô4ð„…D`¡™$´Å@ƒO”_.-9~„€ ÆRHXYDéä¼9NFv†ÖÇ`_R1ι¼ØÆ%ô@ùÁ;Mp <óñ‚ð… ÌX)Èк«AÀHI/–Á:m”UFêYÊ©àâÞé;§—?»3ÙÄ{Ý´W+w›ï6ýùÙ®ÞŸï}8hÑý25¾È''\¸?º¦ÅÌ@ߢì¤qúˆmuBæ^¾€ª- vM5$¡“¿œ=m¯U]OVåݼ“X±vÔíóã$ÕŒ7h.þü±µƒ,ÅËÜ}÷ä‚[‹ >'mÉ52v×´:èû„ ¹gžsxôè‰X±ðÙÜÈR7ŸÀ×9ê[‡ö´u''¿3Mr–]ümÉi]Ûœ3a¼Û$f«­y¼´€P—ëUrÏÍqݪˆ'~O÷ŒÏ˜»ƒOq‰ÁÍ·DÞÜ£yÍy"²ôQ^]mÏ!–G îþ9ÿÚjë…Ö¯¯å®±W}µ ×½) 9÷fΊæúØ{°¦®¥ƒ -QQqá"`ECÌB¦U°RQQ¥ ¶z“Ü@$$˜„M«¢âRqqmÝ R¬ â^´VµˆúÜjŸ Ö]«¾ªÕwÏ]’».õÿÞ÷™4˜ÞœeΙ9sf朙éþÂõZÅó+A¢ÞPvx¡c~ ©lÏqïóG®ìr£SϾÙ³á¿D›ewim›+‚ 領û—Ëögöý¹.íÜD¯´˜‹{nlÛ]zn¡(îà¹>Ç}ç_ýî놉ݺŸ©8¶1ßcÓÜå½þuüY›Bí¢*ÑíŠ;Ç´å}W„ý9ðPÅ7“÷ÏßZáZÿ»ä‡Ð\õ…enSrg(Ÿìîž¡…±q®ëןüÚ¥ÃÏ9Ä«®,v^=ÓcOtwq³ò«]NÎwÖ6ˆó~Lñ‰°ì™œ\ª-™ÓôàÑØÈ‚É‚/¶kÜÆ}é~«‡éÑFƒEæ›ßuÚ‹9CGÏC¢Ú7ú»['ÿ⯠ÛTõ;{é’“Z´ê™\i'hÁÂ\òhq&jqzŽ¶ëƒ‡ó–Oi»~Ãɋg-{šÛ\ýdüâÔÓ?m¹Zò÷*¯õ'² 2¿>çÒêÊ©êaÑ-ç¦{þ1Ø/%ý^Åü8UÕâÆ;£ÝÝ[toYåþs٥Ǣ·né²@¯m¥ 7îê™=|ÿ‹îýlÜÕóøáÊqíg_ï¸iU’<½ ²ÙÚêGGCœ Š5^ÞýåÎÏ%Ö<Ý7+Èxñ~Ðö¤v._zu¨Q—žæ1Å?cPzî™ù¡Ó¯U<É+Ê^ÔdìgO_ ¦ðéc^­½£Çõã:ÓýÜÖ+ãËöÜQKÍ•÷ê¨H‚+srò-¸Ýjáèf«¿ìŸÔýö§Qz©ïú¬=Ë&¼ß÷LÍ¡KÓŸÍÚÛ¢×/w[±¯^èÿѓȳÃý/v^›*òk´Ì~q“±–âñë\³ ®éÎ7™¶U‘Ÿ`pPž'ú¸ÁÞÝ“$Ï«n6¿ø;³yUÃîŸõ¸6fj£ñÝ–ÅH>¹9ôáá!×G= J›¸¥7\^ù«ßñkð­çù5®üklÚmYï¾Ã‡'½„øV‰Z·»¼´°´qµCduér‡þms¾^ïo7²tγ҉ã;ºnxöÅËñK¢ï¶ß²¦Æ={âIÞ¡ÝØïE*÷†93_Þ¼Ì=¦(é§AnCv=|%hÒmxwä‘zÔ…›/—Ü{<þT[]nª¡båá+ÕUºE…œÒ$®Y(ûelù½oúqø&ëÚÊó‹¶)m{ìÀW‰»Ÿ;ôÄØA†¯>áÚéä‘.-ñΔ>¡¼w94M¾éÌÉ’…ÅÊ­‚)(+`fçíBtZ6€i¹üLËÆ‹í{/˜fN]}uû8sô¬ƒ¡ÝDYÅÛ%ÿlúþA?äf Óçå÷'5l3lÚŠ<›ïÛ!—ÒKç”o»¾Í!ª ãî··ËkVi•µZ%½AÆLo×?—µV´ec‹åÕ›ÖV(>›»ôÀ剦ڭÍUZ —÷¦­(1ÿR=yf£ÛӆܹØ&èÀ­éwÎÿ9̸ô‡ŒÊ¿}´¯óc÷Ýøò‹2ɾq þ3í•`³ Øç• épYŠcLªº‡·§ûÁ+gœ×øwðWÏþÝ’ÉË+C{×dÌ4»-”ŒñË.%´t-ñTˆŽ—¬L‚u}3»Úm;¥(zÍÆ®Wgô)xíÑ„9Ý&ªƒ¶,]{5Íçù†M–çL9wgâ²Ì¢àÿY]š;ùvMëf›Výv¢4£åB­£òÐ2—ÙÛÛ 8»kÁê®»¾ ýnÕŽ8ùˆÐéÿÖ­‹ÜŸÙýÂöGÍ÷Šç?n³3ã¬_ €c÷éQ²f[`÷¢OÏwB®-º²?2:Gâ =€f Ù0®Ubú½ðÛ#Ž–æŸOkìsÞE].'=âöÍ<çEÕ[œKšJÝGX¶ÏŠ^ÚsöÊè.ë6~®ªþB¾µ×öXÑZ¹D™Y&j¦r:•Ó0¡átAÃʲ]?*s6ìßznÐ'-¾’´/fw¿WÑÊçë’‰+Äv™˜/+5–&Fä….°ÙóÔ¥Öî7ܺÆv[ÖìÙãÍÈ©É5åå—¦ßk>¦bÛ’’ëã¦Úå5~°=ä·Üê¼u PòÇ`× ;Me®ŽÙ{#šD.)žuÊQ9=qè›ÐÇa€³½ÔL`S³øwÓÛî2MŸ-ï'8š?°EÜäþ¯–œ'÷ŽJ8ÚÁíÞQŸá]ÇôȰØqT—¥ù.WnŽxéëÕfà/§JÚ4Ñ&ö?yQ”—×-Æ©ñøÔ—ðÓ‚ªNßÐÜþ·^uè” o«ÿñžÿI•J%ãüOê§ðû ÿ½W}ÎÿzòœÿÙƒƒ¾F¨.dï`~š|loÿqGT pÎɱYs§æÍ[¶lÕªeËíÛ·ïàf}Ù¡zdSǦmœÚº¶nÑÚÕíu_¸z˜ÂPGM–ªÀ¡ÜGíìOÑá6¶wŸ6¤ Ž•¹G8· 7 š¦ËݹQ|ûTχ°çƒV a¢ áš–ý%[rbå8xvÝâà%Ôh‰pó¬ÍK—Äßþ¡f‘ó»Ð¬œý]²N»ûNmâí5? Ê É†r"íËÜÐvC»¥ÓÇý¶k®îC“ï·Éãã}n†ï—ÅT¾óÕ¾lì* o·ºßìêÜÁ b-‰Ý?h;Ìý›Ì\»hi´\îøxoJ‡ªƒa¿w=™Óèä²5¿t™#ž[<ûGhœÄ,q´V·VË%'âÎFTŠj·ÿÉë7æÿ ®ÿÉ2ÌÿÛ÷Cþß÷ò¢ù[}¿e¾Vço™ KÿèË™ûMØ­ÔXø ›s7Õ·›LQ„"™îÜAM^D󥢸>·ªAc"(YY4"ÂoHqo,u›NÒé3¡hĤ °êèS‹N~ 6é@¾93l0û˜“K“” A 2ô#G?¾èG~”ì;3!ªub£:‹0?öT[£”n¢R Q ‹H$>E›D6X¨=Ó† À Í‘\$¤e£“Š•¸OÅ$6?GtЯXŠ< ÍióoÇËÂXhl«¯†QM0~qÏ€Fô‘F\ãVõš Z­¿Z"Á›¢ÞÙ³ÖÔJ¼)Â/¤8òÖ‡¯'VÏ) ¦=ðMÓrÇ©Œ& HãÜ×ÌF½NƒB ÆÜ ’Yž¨R0eœ¼`Ʀ-¥MÂÇ×Ö°2@QRÁÑ}ï M«?0p`•‚„wøWpè¡U&Ç­ o¦["3 ƒPï)0'¶ûù8IüÃDά‰é-k]Ý‚ЧWìgõÁf;éÆF¡F£áÎÖ úÕM ÷”ʼnŸRËÒÆ^`h[ø1ž™»öU(û“Ü8» 2¼)'1R1C= °Ï0ÎçA:ÌbÑ(ÔCú“¡|YTpï®)“ ­Ê6Ö”|r:å¡ðÐ;³°}Å™nø„ÿ9 49oܽoð]¦g¨´h<ŒIu;÷s¨‰Dã •bm-¼J—¸;ùŒd:¤s[}ãï—ÝÍkË×_“äQÊq§:[דªÇÖ»±oÖ/Ý»Z1¼­ñÙáxLåÊLâf–ÅGÄÚ‹™ÄÃá^BR1pmuäåT(ÀS­ýƒºö²º Èm; ÞµŒd‡Œ)ó°9™¿ñ¢%¸F+–éÐŽ"—éânÅ:û.¼#¾H¢âj›ù„¸UûŽÊœnç}.Éô¦m†NÈ4¦àa€S©ÑNøê‚¹¦W4§¨lu©ž>4gsž`ü0jyku&³%AZ×äSÊ,àh¢ ™†Vl ,@Êx ÛoŒ¨,¢$¿Ñ·Xô-Çd ¦€‘–€RºŒÕ€8¾â2ƒE$þm"M'Ùœb1²„ È£ç ~c\ƒ" Ñ™“Ñí4£ð¥9’ÚÆ(ä‰Óšð1jµx”™ºx”mr !¬/eL#—½á)SF ûŠM!­iæüÑéÙxâ´±0V ÄT&4¦!&5læ›2«Ÿ.;˜ ŠÊ$^kŽH‡}Þ%É`7<è¤p'n½ÖJ¸ôJsô õ[R"Š ƒÈyÓá›c­¼Ùò s¦·4ç²`wÅ 9UR¢£’I³|`q}µ%ƒ^‹Žð4æ¡)^ð°´b4Å™8¾pWÜ0ê bí›|íˆä¦r˜pqòuÁ %×…5Ο­ÅV ˜½ê,k‰ÁǬqôHUŽ‚-:2 UêÉ"I:FOJ°I@„ÒÍ€}•úŒ^‹C9äר¨¡¿ˆð<ìΨq¸ Qz·iÖ„¼ã%'¢Uñ[·Øª=AD˜îJa¤5x×¾›ÚÊÐÖÍØ‘“&¬‘¢þaËM“—R´û4'Ó X­Î 5òM›J£‘#0CÖÆ¢³RÕ5¶VÞƒ…CŒA ’è1E_)IX”"6 žòˆKv'wGj9.‘·Çñrs²3ª“Â᜸± 0ˆ‘ª ‹• '%«I‡T–¯dùÙí”Ç%ãñoðH,< 'Ï$MgFl]n%Eù)±1•KŠ)ã…d¨ &7ÄÖÒ\€éÓ W±åÜ€ºÂ‰04Aa•Ñ…¤ ÍâprFÿ —5ŠC<`”5ÿª-x•×2Ìn¾X ˆ>™Œ*c².oÒ|Å Ç(Er1@UT‡ÙÏÊ6ó„˜LFCº]˜Ü"‡*?ŒÝ!YM ¬ô5A~ë&%/?‚bþ!ú$ì²è?E£`nW(£f)¡¡¡Á¡ì!Rg‹ŒÖGÑ*àM«d›š*Z{%¬' Ø2š!#äQXJ%³b9Õj_¶m¨L3Ö2çšxG{hFtÙû$O'6©Í¨Žñì+¯0@…g&Ô½†aÌÈÅÖ)Ý„m×L«NfŸÚ,Fl3­oæ)‚cx~¤,B­È4-Ò~$7(ÆÃÚÍKŒÂojZâ7úÕö»¬ŽßY&?)Óägnʹ©Qé Wãðâ!»Ô :½ÆšpÞ¨…Àâ‘©»E¸Ùýǘ.‚‹Z Ú ÓBÆ( 6€èU –qS5¨:§Õ"`Óg`]À9Që´:5„ï}"Ë4 @õ)ð® %d4 5AXS¼%À‰¨Q:ÄìÞD™»¨ƒƒ* A(›~Þuo@™' rE‹…dÜ,[Äx@¨~Lk3Y¨G™„lm«"£UQø«XUü˜Uä´*Äâ¢UQ0«øÒªø«V9³Š‚V%@©Vj•l—ì‰ÄÑZ+€­”–oÏfGe»?Â|G¤@N0¦3¶]k¨b OÖ¾Œ•!Úà Î&0'±OÌ<¿RBà¢ð§°.æ‘/Ý`Ý‘å,{S ’)ØQ#YÑ­QÄú`£©§jmE,t$´g`5q+snôuŠ¢Zl=¤˜ªElš™NãÃÜ´Æu4E6|ðFèLœyõÿíºòáõ^üþ_¶¯bpZÿ}Ôÿ[!ñ¥Ç—Ieâÿ¾ŸWîþÅ@6æFø€I”=$þD¨*ü!I‡˜q'0!ƃzAC­•…TÑ¿4 l…””¢·è|ðlرNqUúËôn§T£@ë#f±•sÌxõè~‘QaC Ñýt£§ C>]€Dæ#SPúì¬K%…É&ãDmðV: Qä#(­$%ƒ‡R™\¡Pʤþ…ÿÓŒý—C±ØooøŸxÕµþý°øß´øoù‡õÿ^^ñÿA´ýîÛ£gtR…þc¯øùg‚Wà½joa.úÄ!¹,ð î}B&~ ¦&Ç“õ^ÝË#;È~þî©ÕƒÙ ¦ýûÑ„IN<µ£§n¾Ü§ãWs£l¿ÌJÕ*×Â;¿ûSö7vj6µ}ûÜÑ ?¹0jUF“ËçÒW¤WyßðäÑMufXÑÅ׌öskžúÊXö[ák²*´Û‰ÍÑŒWûŽúTóøz¶ãý¹ûÂÿnº¢øÂòQóŽûQ6wë}çÊþú|vÔÊ)7ô®>Nž”ögÀ¾=ÇÏ»¼&k]Òñ´é3&MÊñ¼|bãgM]²Ÿ{=|"."djå_Çç{NrsY“¥\“%{?ÿ ¹‘æõ}úžóÑ™ì‚"qŽÜO ©”›w{ð!¯M1œQM™û\nÜE?$~´0Vv-Ô°÷—×ý¥äÌ3¥¡‡kËòu²fÊÔ-êX³–¢;Ôû^òt)MO)Á07zWÎBsâe«Xu8õõ}RÓZ eÉR¶)!CÀ¥ðuY–nt˜Ê”£*}6j­KËo­E\lpÊš†5vâ®ÇN;¤ïŠÿòà¿ÿó ‹îöÿ;büo¶Ž½ÿ©Ù_„Ñäôò&̼ÃŒaÈç3öâ6gË"†@ùï6Ü ‚¿Ç£áš J òöƳaÃS¤ôס§ÖòCR±|à6&æç·j°âJ Éw46^Y—Éf]Ô ­*óBCM„ñêý@m^ÞðwÿKš‘°sΖW.{q}rm³4Ç–ïø°ùž€"É“Î|çŒpüïñÿhÿZÿ¦\ùœí±Â·²ÿÉ6¶Õ¿ðfÿ/,‚Å ü!"»ÏÿvĤd°×‚@l¥}uÍ7S€¿¤‰!¢0¤˜„ ¸„à×Ó@CdC¤Ì­/m½,-͆ý=Ûa ¶Y+Ìú,ìÇfÂ8·Lfs»•À¯E7·³Þ*iïhmç Û*‹-)…°ø½ ;së³’_*øª±/ùøßÔñk–>®laìþm~üoŸçÿVûîøÿ'€mïÿ…þÌÿ@îŽÿíˆým÷ÿM[÷ÿyÏå ~0/“ ã(4{Ûu úHƒ’ùHAÍý¦ó‘öï*š‡›ÅU@[ùàGöð3‘ÏRμ$™6¥¾q¹žUÜÜÚõÞµ­3‹Ëk¤€°GˆÐìøéBRå‘Ò‡²Ü´—“K^(è4Bë±HpßÊÀƒ‰ðI7¿ý ¿N¼E€½·—v“ÿJÃ.€ÀÖ(9éí}½ eÁA` ¾FÌâ °`bAûF‡uQh™c 5NÒd5rOCí'„-w0Fa‹\øÝi‡ JüÒnX ÝòŽ=”é9Ç:ÚÕ *v½öRÃ.Ï‹¦yƒ ”ó{3†í!¼,æÑw¨‡«?æ>{ëØ§5’“I¿N!ÜØžVÒ3®®ênöøi°Ýi—¸z1þ)•èÉÁ*W½iîŠH%SŠt?åúÁùÑäûÏ,õçô0@wúÜCO ÷<»#ÔÄgífK-Hé>”ª ^ã›°êk ׃Œ‹Ý–œg“ö¿8ÐXÎ0†¾|ÉÚ–­ýq{[éù4ñÉä#7Ýb&!•¶ ÊÑöAüÏ3s±h­8Ï;…•4½,õ¸G÷A—?ó‰µI›5B`z·ÔGJñ¢ží!I±ò:Õƒ(éúîûÒ‚Ž"ØOPšŠËãPˆ,ÒÖÊ5–¥í_ LDøÉP•Ç&š9Áþ#}‰äšÒ¨ ëmwðà0ôT›ôe° zS4OQ¦¬= ÂÛÎ=lžzS™š.Öí H:_àV¸$cùÈÅV†OòD¾ÞÝåÓàwÍÊ”™tIOîÞvªá’w(:Óª™ÊzÆý…­aw°k=ÇÇ…Þ§‹!÷ ž_nç,Z”/YÌ…=&™ï§)Ф6çDiÈßìKû(!6áS "hæO¬8ðìÚ¬P|QÁS·øä„·’<ù÷{¬ûí@oä\Ð3N¦vµŠg²’F/úÚ(3ƒ>߸ßcÆnƒs¥'ˆ'Ž¥ppλÂͶ‡B¬c ={N‰r‡B|¹…BœPyKQg7†•Hðg‰°s-|N,¯ÒÝW8æâÆõ"Ý3Ž”.:Yn®µEt>×¶ý´QçØ^Þg@Måže¯¬•Z5zêÊ­i:‡ÀŽk7Y¢näc€þ¸îùÄÊ <³YàÞÍõªÃÅð\âæûSž ·º*I•‰-¬“gý ¸„׌87’7òW0@öFfê†v'Òa#hýFÄS ¼zUÿBªÄç¬ÊÑÙúŒöŠö&ìiP­Nñ”ŒÒÔ)Fý…l ǹ°3@è¡®Œt/—AEÒc_x2KÎs÷àŽy•r‹†ÙSß& ßZË•A· ž/Ÿþåšdãz²Óíñ…e;õ畎ÄË ŸUÎé3Q6}œ­†¼F”_}÷‚Ð<‘ü«øî#⤜Ê¥xg^WÝrë^Q˜gzäöBTà Ð<”Õ¼>ó+ÖðÒ§ôIçÕªî3èW –Þ³˜ý£ð©«÷˜‹'=žPE‹Y—QX·k¸¨ öúþ’ëý)Þ>¬’È%ö^·”»956<”\n{€Pl)ÌëžË9ß~tÆlõdºC¢ÚÓušTÚV2ÝxûËDНí¡`¾á5uÔÄgyOx ͧ‚pÇè°¼3óYÏUÇ¡Gùhw…â¤ÓjˆL­ÄZoáG+26á~Ï ³Æ ¥Ù'õtzDf'ãrO'[æÇh¦M+NŒi±›ëžBôu©:ð¦^B½!ÏjÇÄõcÔ“²Z¦R¡ÊT=|䂉¿Ö‹a«½)PDÔ™ô©ýyw *~Êí̶k¯Ò÷F' —f²”÷Ä—hSók˜sÚ> ¬&ôßçÃû …g² Ãp}OPz~ ZÍéÜ‚WÑûÇúGÇôúü²»+û-%Ê8ÔÃè‹%V'ù@ŽVxØ7`áZQ›®Ï1 vl¼ŸÅµÏ6ÂsäŸ Äöˇá  3=‹ˆ¥cM¹¦\úäaÙjä¯vÅ$ó~(3ì±íè3à* wPöã~Q+ï¨Ü®c³q ûç]Iõ4ªñÂZÿà(­åj²9–¹ÄÙ8Á‡çPþúá-÷XÕëL‘ Æò'Ÿa£ê¹$Ú ÏoïÎ#¼Ø²nëiQÉÞ§/š(~4œ.þÒÐû×É’.q±·Imc,Ñ‘w™R%9yÛÚe­¤pês u“\”l¾ÖÙ1ŒÆJîèm[‚(•fÆâxÓ׺-š7û].´½'xð>¿¶‡G™ô\éX¾ þ=p—³fŸøAŠ–¤¼¿¶€Kî¤65÷y%tPÇÏx¸G:mv—¡ÉRç"‚£t˜?ªäº·Ø@3ÓøMãËÓŠsº"ÏÔ†ÒËåÛÜ;´Å&æùßhöÅÈk{gpðª•^œ,|t×ÀùÅ`\§iÑ+n›Ô{ßq}¶€¸—PWí“Éã¼£ºK§ýÛæ&\xÁ×uõy4¸È×K:¶é ^„ß,ö(Ö Ë OšÎ¦[•¯éüuíåÏ 4—䙋{óN4R:Wà…ige¶‘ýôøkÒË'LµÓ¨opÌxóôä&ž¿â<•!ÌLVi}\;¥Þ:€Iá`‘ºFN"‰†€ü2ÎæøÓ‘î¡éçÞ*QÞ*;s4 Ö¤/¨‡ „›ßÍÖþ–0"ödwAH4ŒË‚”僌šž/.4>ÑŒWu2è‚1ƒP¨)ž{_ûM‚êäì:®B‚ˆ T) oÿ D´ò2£ýñ¬ÃSz+šGöóÅ^Ï  k{oÒåå9Uƒ,Í®×¶Ç>Ùô_ÄýŽüï¯æ)ù±6¶ÏÿþÓû»ù_;cßÿݘ`÷²ìöúê§ŽÿaﺣšØ¶>E   (5€†*ÞBÒ¥ ˆ€‚(j@QŠHT.½‰” (MzSŠt 5@¤w %H{Är-O¿{׺ïÝ÷}ï»{­ùcö™ÙsΞµçœ³ç·~;Ëgª§¶· 3;º··G”ìÀû9þ[êþ[£©@XKT»:òüpª‹{E,båå¹m–Q²<^wio·)`-¯!׋ô»ƒl÷æo¨÷Wž’&ð;1CìŒëäæ?&ÿýoþÿ+ü“üØßÿþùþÿ}ùÿÙYI¯Cé?¶aË®F¦S‚¯Šè¦{û<}šw:¸ït–ÞC’#ÞÁ³º¶ç·ZØ3Ihq ù°;ūۻ±–DR¶ðrI¦%Xã„|ë@qùÚso¢hü"SR¤–Á¤}s}1ôÖ7NË$É> …¾+¹ò<éí,"éÄ<ƒè òK÷J¸ôØÒ-—Ê«´#¾NPù•Ÿm̶ê~tÂ#]åQf7ráüe{['Õ¨$Õ8×ü¿øêü:þ¿-øçžñ»ø/1þæ~!á¿ñ_‰üWÔ—6Àû±Ô;.; ø'å¾öåÇêïß)©X~Rüêû´íj„³Di ^&^k¶_r{¦fÍÛÔX Ý"kÁèç„r½toäÖTš@–@’“LÉ8ŸX"´Ïãq%ßá%àNƒšîñ¸€ïý%×)ü;æ„ zbÂÇÓ‘—MüTnqÝâª:’#EÆEpÉŸ`ô A2A2á¿nSñëøÿBmûç1 ¿ÿ8ØçÇúßb"ü¸7ÿ ü]ÿû¯‘ïñ?¼óQDœ_€_$ ñ±¸ðÿ€ùlã[PÆ Ð‰S v7–³#Èñ#Fä3M17è3LäKãgHÇcÙ_`B,…þ ¨DèGÉoôí?Üó•Ö]Væ›~~¯ ÜÂåSg¥Ìà_¬íkYe@'¿³„£yÆ=wÌ}ÿ PùªåŸýðÚòMÛÇŽ9ZÁàf]ø›°jkavý:ë—öOWÈ ïDüÖ‘Ïêï\ñÅô7†¿^þ“·ñÛ XxyAPEeUMè/ïƒý¨g•á¼nvÍÙ^òûºç[/á î¯É¾5÷¹ñ?Eÿwå×ßÿ¯ÌùÿîýŸÈGþoñÿ"‚¯ÿþùÉþ¸0|âÿÀkÇ)¾âÿÉØ/œÅ¥„þþOè#oÀÞ^Cÿü­'o®Æ´®onß/è÷Éy[Ð:éÔÑ9²Ô?¹òn~=«U:TÑ=3ÙL®9nÂË´;>.¥„'7Ùwuÿäù§Í¥s˜á‘W Õ†…`éžÕT–ûìªrá4ÁY-¸„<¿û`|y üR¦uU¯ÃûÃ~T‘ôÙi?å&VÒFƒDµgèªüID *ű¶Æ÷g‹:ëµÒº’­b|\[Ÿ<1ŒäG™Löï׿K:îXë¿—÷J˜><œÌÍA¿÷RÝ“n_®5‹ËM¶(I²'/Ì8 wù<Ús3ŽÇ‹ä{»Û<Ý=ÌÛq†Y{á¼ü¿w+ùëøw¼rÝÂîhiïô'é¿~'þDEEÄÿñ‹þ½þûKä'ñµpÛ“^UqW¼/ñß8J-§x‰ íŸÆ?‡T¸nñ‰†OÏÊn·h¿¿d™9Ãp‹Ha  DX"(ó ðóaëÄÃc>ò™"ì©^¼bbã‹¥¶ÅÁ„açøqÎLRèL!$·‘ÞÙY &NïhÉyE¸q\tRó ˆTµI¾z硃éØ!—–¡Îxr ÇuRá¶aºÎU-D^¬¿\ƒ Uá\ǚ¾¾ 2oW¿zï}Ñ0†‘¯åÌDãÞìfÏ”ÉP¯ÛéÔÔÜà¶ë‚¢{|‚*#\À§ÚÈ Cn U×­%Û7¸¹ù,ì úÆ6–­C¦D±ÏoÏç%Zò? ËôtM#Óº=IÔÔ5ù\$ñm …ékw»A½T|›êe¾c!žjt$¹ô Ãbåì»›ÚÈë¬Æ6&éðá]DÕ#Ì«5j!êh­¦Ü¶ Å¥6Â'k˜@«¯2èúÄCí®•©Ì»oð³*žÂU;r0UaüOÙ/QHÇ]“èÅ]x_çñ¢„³D‘¦Õtâ†× lÑö­É\¦²ˆÝ!W{Ð,ƒAÅî¼£ïˆôÞõRõ¥šš¬‡ÉsR‰ÚÛ˜z«àÉhÉÓÄé+j³·«°<æ^4¹Í(¼åΓb¦IEï·õsùìVìBwV‡uŸ^¯J ­µŠÔò˜¤‰60Fê´»ú{ùìK+Æ.¸Ÿ ½îè]¨»ÙÐ~‡OZ7˜Ø¼W¸t÷ [Éišç yì0f;NŽ^÷C Õí¿»óЋ*Ô°—}¦dCa Vºï½›?{11‹Xôlœ+iñC+Ë\³(ôDÓ/ÐêhEÛ/‡Íöi#˜ÓtÕE“´úƥĿèÙ¬ V›5ÂÇxëÃCv'¼]Ü_+MÝÄ þÝ]W´®Öüm>»õ%ŽvœGšiwåmKË<[âÅ¥}³ØUˆkÓŽ•gÓ󚜭èrMÛy¦˜=TÕ(â‚fFwíFUµìx)9 ¢Œ*ÀòøXVÁM29ï2« ÷l|Špi$§0.ØÂhÀ’zúj Ôtd æãPÆ%Ó®CÓÀ≉A ÍU²(ˆ]k™nÕ½pËúJ‰ə­ð.$„úèåಂ´æÛJòøî«áëôyiÌv”íÏQŸèí3Kï[‰o¿’scÏlÜïÂíñ£/ŽcÚ-wÌÌó…ÂÊš$Õ?\i¹ákéÉe¨p†m¼1z¾izô0[Ü¡uÑ[âr(£¯(ÀŽrT(oéÓù­b[GÁòô¹Œ¾Ž¡ádÄÙòúÕj½ùJÃZç”öµÐîäs’Ø@’¥îzõõèxpýZˆ¦¢ñŽuæBWM[¨¼w(þå‘ÈÒÉ¥öó9lœ"@O†óŽ‚¹^ͬ:G ¤åtØœâŠäÅï„G#²º}(qJ}.|•À‰T–5£…ÁhÁ!ÑÀz ï]¤7E4Ÿ>Õ÷þùQö—L…/™Ö_= ’I•ôßB[±IQ—ɨ}:;4Ç_ç#êIê6}²«ôáR5”1õn×ÂùŒZ  ´Ì¦3”òwgn<“*ÖÌt‡wù>zBR˜á#ÄL(HÊPIîÙ#ë°! Ú N¶ôy¦—ïÙå¼aC›Ä=à^úFà?1‹è›Poë±ñнu7ôPRB’íððR÷„˜‹:W®Õöè%•Kjï—Š·Ø^uÉ>·|m"1±&9|t8 “yº(’<×¹æÒÞöÀI¯èÀYqÈMî´µ³Wç¢åEÔÛi™sº-?œ+‹zGB‘å6ž°â1Û?ˆÀFËŠ¿t¹Åɼ¦Ž°§•¯Ó#T+§£+$ »‡Œ¿k®æõ!Nrçž5ûJ; )gá)/‰¢±övyg- Ôc†ñ3(Y+ 5g¯ƒ[ËŽÍð„CÃ?\̸œpƒ¿Bn>®ëHü ²V+„­>Yzsˆ4—¯‘óÆâ=U"}‚ù‡½uQŽf”§«‡u§ú§ÈúëKÜ—ÕJt<°×cÍJø¸ÒõX:¸&¦ô™LpÀ­hQî9ÌC°»X\§|λLø3™™J]œw%Rf¬ŸR ®{‘þÌL=Ao 7ÞÏ ëUDèÎ2FKDGе€cÇ+8oYl+%ló6Ö’‘rðÝ/¸óäújdþ¹fS'jQB—vÃjçTçÄ›Ó*…°GëNî-ätRºœîb}}X¾ôg\±qv¦šHœªn>Ø;Fbü¦R_Ы؀â>,ÆZËÿò=E ›eŒaqµQœ>ÛÄ3l-bc1é¾Y)¡ü©ÅE¸MY´Ú[ø>ÿtÀ+óôí¹¢sy‹vU‹Yã0pv7,ÉëAfÆê¬)²ÛBM*m޽5Wã úŸè6Æ­îxìTúø8òm¯•>x®RI¶H\ƒßwœèé(§o‹G¶:-¿+’HìxÀ'ºCÚL-7q*¾vœ­×8aô- …¾l3!*¾Ê®£ o(Û‡l‰åË Üwp5HE]aæÅ3Øÿìöíé0ÏGg„-+Z4Œ™hx>60×vY›p4‘ÓܲNH•G÷EYíø‚“9=ý’ÃélèÏ¢nQgšéÁwRù¶÷ eyD«Í2°W§‡M¬tç0Ö¯&žRû ƒ…U]a(tqs³ƒÖsY¹î5ó‰Ûlð¨’x©‹Û=v¦ ˜ÖõÉæ¨O?Àm»¨lèä<ý°þ˜<-ÏÎGhìz¬du¹&I#•b sªµÄå>qóêzc×K{¯'[ɪ£G9îb“<ù’pL“ŒÔp} ]Y^lÌ’C:>“I㫇…C/®‡*îðú9 g‚sm©Nïφذ <³!RâÜ‚*™æ*‰~¢’v^@‡õ±å6ó‰[êÏêÊIoh-˜¬è‹—{`¯¼pY?Ð_éÚ'™_ð2Ætàz?ãôÄD¼Øj:öF2³rjG($w›”>µL'_³¤°… rݺ´7íîvØ‚Þø‚îdžS½ö¯dõ8W¹›¢ÞP,ªª³p…¶¬¨Œ³º@ò&ºøƒ§)±Lþáq/“¥EÒ¬H<ô`06B%«9p¶úˆžß¼' ŸÞ@:> "Žc;M¬Î§,¢v6º2JŸãÕ’1ñÆ[uØDR—U²­ 31.ØCf¡õêÍæš¦$Õ!´’Ô»fi;ôô³í ¸9õžî%Á˜6q¿I{-Ey¡ÇIRôT7D«#šy᯷sÑ’8®Èâîb¯bc©ˆÐ{Ž>QÔF—ˆô8ÒbÙl¨RrF ³:NiJÔ€i1ÃlýÆl­¡Ñ¾>Ñ¢ê½k.°—LË€OÚðQèq¼UtOŸ;Ò¼BXNt×¶»›>›'~ÛÈ^¡X¼™©_l²A9µùàJP|tÈj €ŠÛk};X%æˆM$¨àÔµô–ï²Óy¯aÌÖ5í§ °§¾}Òeï\wx7Zª,R¬ÀiŠ%·]‡ó\dÊ& YVØè3u 0÷P…‚¡:Q1ȉ%–ò‘cgN)UœlšÜ3Óâ'à ¥÷i=ösì½ß5ìw­õ®µ÷ú½ëw½<³b‰wôHyLOÀt É™ÐOAfþko{¤¯Þ_£lëvQQ°ïÅsžâr¢è”l¶f·k'«%D%ÝŸên«ß("#±–\êÊŽ‰YÑ£•_.–ËA( ÷ªÇuªwÇNðƒ-ùñàèä¦N]î6gô­û®|•èèw £NðÓ³Sÿ`Þ.(yÅöQ³TÛ)™Š;dù½•ÀôFrÒì³7èÈz†yø?ä–4JÝïðVæ†'ßþ”OÛ|4ðƯu0בôWÞV½„&/Û{Dä¶„‡®DL2cjÄË<‰Eç½¼¦34—WnYÙè¡åcwëjã»Zºº*L‚_”É©¨>¬4ÖÐÔT’ààâŠz2sÙfhþäÉ•GÁ Dn1Ï£RÎihŒŒŽ* ÆK÷©Ñ& "& 20 zÍÒª©ñ8.¦þ ›Í¤sÐÂØsM8’>át½·Ï„¿Ô³W ¾îfh9:“/ßQÞkÕ?eŠQ·Á&I&ùTÆ¿ÿ‚‰Ö\¨$aPÍèDÁíšÏE2èÁá A<µg! %Z¬³ÑMÇK@p9Ï8Ù“· è¦ÑÆ>M°¡ÿð4¨­“ŠÅ„3Y{µ³ëö‘ê{T=w²VÑžûÜËjúéÞò´7?‚©&¥óˆòd{MèhÉ—àyWäùÍüŒã¹…L¸š°é F·œfù±é€â¢"µ6Ëu8XG(+Ü"&M©©©Ÿ\?ñafj*fµ¶¶&)YRØ|Kÿ>ÃâVe_|cÿ0›cQª©µgç-+HsJÛtIÃÄ/*õD–óFd¶ºT‚Ùåé"tÑçŸ>}ÚŒ?󦺾eøAƒ¶xèµyƼ…tásøðë9WÆb'‰€U'œ¯YI.'x\™Ïñ˜*Ë\õ¡z Sž/Ðõ¾ê¾j†…²‹M OMP÷Ö}‰ ©I5þãÂÃÃë¯EvÚ‹_ÖW‹ŠŠ–/o>/8?[5uJ¸zyÀ³¬´œá½Ô/ÁéòQýõ>¹cF~åêü©¶ÅçlE6<Œ´”RÉ^Ç/õÓË/J=¶ÃHo±J°o±ÈLévùô!+b˜‘žã¢<žÉJÚ6³8'ÿXÕ ¯Ê¡#båFu¾X'.†ëÈÏÖP½«ñZ+¼žrùË*cŠÛ£ÁÁÁöv[«'v Øu2{Â;ËçôE^œ,´Ž’-¸M]ÆrrüÝ*bÅ ÿ’×OÀó_„ÏM­ê‰VPP CX¿(¬sÙü²aÞžôªÂöéµkך›{ü/̼®Ô•àÏ3ëÒÆ~üAߥ™ãÕ;¼J5iC}ß«s2¡PöR)Ö)D1‘`¡~¦ÚDtYäÊhsXH³³§s!÷Ý•ó²æ4ÒŸ]#G#š³ƒeÃènbõWÉè4’19Äepþ<Ÿßa º„m_ÿ«}}}£LüÇ¥‰jîîÇ>(Í~PJ.­P™O|c ësB¢nÜYx¦iKö"ÒZ—¥ÍÑZáa–ˆ<ù Κ¥y#RVMîeËÈGÉL‘ë Q%ãAZ湊òêuÌù䳩ŒJtëðϹ“@9mÉhÍÇa²ÝMï¯Êéü æ€ï;OqmãZÙù·Š|9ý$¾,×»bÛ¦ž2Ó,Œ_Û1>‚:Nˆzž¥q÷ d Ò¨ÀO]“Í;Fà`ææ~„YDùÁeq«²º„‡Šp=#ùô6oÄ.,GùúÝ3Q¿£mÎz+ëi)Û#«ÏVd9á,cJˆ+ÉDm²4‘‚& ³MfN¬lW%¯`äÓjJºgôÔ›rþ=eÒ]§mI©ÊÃIòZƒ|.{G=‚Qøß{&È…¨{æh ùËêÎ(½bË‚Ø_—`ã‘L6-nV»[NF}ŸG—<1`ÌÔÿ+²‚9ó’‚.SS§¢· vbb¢ø‡Ú£Œœ_òÚœ“£k.Y—ê¨ù^Æ£©®®Vof,²;y®ÇÌeŽp.¥øÖy^¯‘´›ÞÔ$Ç¿ ŽH¸£N:ñrÒârŒ™ž8UÈÓ´(U§8ÊMR ·½%:Þ.¡¥§ÇÕ\Ø4¿z*âc­ !4ÃY´º£ÃD4t.K-+'p4W¬(//ïÖ-3\âVb²âââ²2' ìôµÀFº¸öü© ›íš¶<’ÐÏ4°Gâ¡ÃÙ'lÖ ýpŸ‹·—ÑNek>z¬1Y­'»Wšæ55£}ÿî'‘ø¡ u‹­<¨¿«!C²š˜(BÂîЉÈQÒÈr_ÇvbÇUñÈ2?çØðâÁȶÌ9(ÙDÿ"þõM°>œnézôCg"µ—º4•_o&§¤EØE„“’P¤5`4çÏc¶IZ?´hìI¸Œ&"´A²¹H¥’tÄZÑ¡0i%æ ÌÎK÷ÁŒ~†›DÊË„ ž3«˜i%^„h.-.¢!Ρ¿}Å/›¬ÉÌà—2V}+$5KS“ÞÅ[Å€Ú»ŠÁñäFD©¡^ÑÈó33©e5'ì"SÃè&ÏÈÈèèè0H®ÌIp_ks`ö èÐV,½«âf%œW•Ë=‘9†`$gn°ôÇá/§ª«{» *L® _×óð6µ£)¥$\´ñ¶¨4ÆÊõ]–Ä‘mW~êÖÒ>s²ŠÓÃJ¶ÑÃñ¹«Nz ¬JSþ·dî•"såã≙™Vw:&홌gT0=ª©i!9ŸB®‡Id'&0Ñx¿sÖ›Õ(wÑ [R`*_©ÇÈg>Ç€<ëÄàN›.̼Xc¨Q”«L595ÿ, ¯"‡dm0ál’bA+_|Μ œ'“òv´0ú‚!¡à†'M¹Ñ©4˜T–a7mš‰ôiÇ\yQ}­‰SNÿ¸¨%Cž3ý©M)žðÒng&ü^y>y+pÅRÑM¯Q«e]ù¾1g%èçÏ~F™§š…ÐèªEfN\ÝP¶¹›_À0X26ÃZþî+3 Óˆl+D™Š¯J'LÖ2ŒA_¸=¨éE¤íz“)c–R^<±?CÛ¿ZT,ÆÅ0+ÁE?Ç62¼,¨Y²ŽI6^®«k¦¡¯ðè(}’‹®]ÉÇâeËFæÜl’^l¥˜ÒrÅ5"šþz=½cx©âÓ ¥¼Ï¹{ÐsñC0sG¤ßYdG,(ÑzYYÒs¤u2Sä6¹û)YÉÑ'L`ÁëEØøÒ-<Ë&îj›7™<ôൠ‡ ñLTù/ªž©²x0“V"ðBS²RXžiàË©âiL•q†)$ž62tåÜX¦Û$-ØÈ 3²á¦³·$ðµvÙâqߎ‚Ó |||,e©>71â´··N§ùS ]À½u¦ñcØj‘³¶Ê®ØJ‡äá×úÏÂ’ F'k“_²e­ÖÍÍ ϩɦ˜kjÁ©ŸR ¥½8?×'ùvNBÝÎÄ༧ǻA×è;Ìè7ÕÄ[Uùg®z踉RØÝ˱LÀ¯YMTÖÓׂÅóæ¾+ûI×Ù<„Ѝèg©ÚrúBmàTgÆ™A)6{‰èwOžwvˆÂˆ–¦_9m|^¬­¥?‚ƒã+‰#˜µ8Ügé¢aFí9ÝxÂÁÁAEf^ÜÏÏï„×§ÎÕ…±³)–ú"WP z}æÆD›4ʱ¸®;ζ’oo÷7]»ž:ÕÖ¯A rôˆ¡Ô…_'ÎDéKø›Q\­ºZ¥®ZËv¯ï”Ÿò+Ú&2Í{ÃS%P²AÜÊܲã§OŸvû’Æ€œfÜ"R¥o]½*?åÓ~[³J]M-Í?Í~iZ»•5íM1¬>O=G‹ë­OAHÈa:Š^¹Èäøø& î—ÅZ"†^‹Ç‹Ÿ57û ¡Å¼H0ÞòÆ;ï2ÒFôßųõ+Ôâ¸Òo—bMì+³˜à1òªÚ®5¤Ú­{NF†âÂhI#·©’ Ö\"ƒ¼PösñHhà¨E¿>ŸM%e¨¼°ñ5‹éáá2‹NÓÅ|0žüU)<ܬ Ú ‘Ï.`æ)æ1****j[÷:Ü)ô{Z|­–¸ÉTbÆZXXWWVVrs™œýC©…ÝÂï˜+›½¾Iè@ý’@£3úþ}ú{,c‹×­J2#ôfÕOt^ï¥OÓÌ?&$n•¦•ÕyÕÄ/7Oj‡š´IÙͱ)EGY½¬”­¬øh†=/w½P®…¾ Ž9Ñ^Æxìpa;CÒE1ìèÌ{‡sTuð_×… ?’ºjÿ‘y5ïåi,éâ RAÐÃ7®^à·ÛÈ|~´ðÌVïá rlž'ŰYç­üåuê ¢9®y›EUnH”7ÊÜ(’ÆNÊ÷ ð¤z¤D!êêX~OB‹âÂm+’Ç”è±il'ò×ïrráùeú\ø ƺ{a>­?zz&kΚ_dEZ\-pˆ-uPÿî*Ïb,žXD¡ÆÒ,=>Ù8)¿Ç ßù"BþöޚܶV3VxÔMA9U‡kÇ¾e=ûaç´pÙê'""’’’²ºº Æê?¼$Ò}"22²ö(¬X†²øþ}!룳 lì— ò4ãÞKk6ñ‹Ð9ï€zˆ\ßT¹€ù‹C3è5äð•ñ{‚®Ý«k"z³ÂXshº;]bÎ¥±‘â›ÈD̉°ëU0?ÙøáŸ©yRôqI¥B4ÞP«[a”eðÃÿè#РQºôÖ_e-MÛ°Ò£»­g=Ï÷ 0«3ª$=Q{[玌°Z 0Ü ;](Kª2=”}î)Ëí4öèc£šwK-ôØõ«L×ÐÙO)³ƒ!ä ‡%ŽŠ?~”752b£hJÇ¥'Ç Ç’\¯\¬ó ÛÁªLÓG}FÜÁ4ñ3ååÜ¡GÁ4uã‡ÝÒb‹cňX0½JL¸Žë%º½ãšïcÅåŒï£M]¼”t-çGNPÛ£[¨…LÖŽò"k÷°ÿ\åå(³À†/ 9%%%÷Ž2ºM^ÂøÊÊ`þkFâf9¡íØĈŽÝ<%¶LF¯]aOjú’MÜ\«‰\™–˜ÁïSŸõíw%ð1•Ùe®@Áí§_Ž‘Æ,.-ɾäu(äìÕS¤p²°…â¥)8ø;Ôì›´_#Äæâj‚››gxÏbJÕ9#ðu [CÙ½=¢©•t£GWaÔj¢a‚Ђãá,ÉhÊQôµ#D•*º,† ÄCÐMhRésœ“·81K!Î׿fK{²ÐüD(.º²°1¯³µ±)NÇ$ŒCÕ˜ÁŸÛç"çÔK¥‹€ ‚³ ôñ–°…Z¿”îÄu¸Ò1Y{ržˆ@%³€ÄW;ëÆ¹Z#t3‹CQ|=BÎX%­Œd%ÏK¼÷˜gV!Åç¸Âƒv£‘Ïg]‹uúŜƣj  †ŠñÀ·,`¿ðìK§J6pΧa3ûÛw"€Dê€ r[,¢·&£³Ac'¦B^93J*áFVøšP¦DxJ2´WÄ¢ñ‚4©«–7úWY¤I”i„Ó´ G_ü¢ô™ ‚}àu,Ëü¨w‰+ݳt´—/ô‡nM€Q+´ÿYìÀOð?»€À„ø©ÿßAÿ/N¾?ü_¿%|gýŸ y€A(üO¤#ò‡mdz¾¾Ž—––>}úôñãǹ¹¹™™™/_¾lll¬­­-///..ÎÎÎ~øðAòDI9à‚§fk™?ÉÄÈÛ[Àa 6¢ã–?ðócÄSáhôÄ®s½¢R7!k<›rX ´0P}X3Äیѻ!~ ºÀ÷F»æò A|Ýá^ hhvÀwÂ}–º¾4~°½ÛcÖ Hó½ RF>Â@ ‚¦Š±K«=]’s¯ï›ãasÈvpÐ@ðA`Ö/3ÉÀH0¿ ÿÇqB?)ÊÃГçëê¬d‰f=¯b¦œ52’"ñtðI'ÑŸ>Ôá~ɸ®6`½Þ~Û8Þ®¥´ÿ^8Ï¿þ†ÿfÿ÷lø“þÏÇËÉ àØrãáæââCùpsþéÿ¿%ìÇï­ó-ð7'Ï)ÎS;pvN0— § Ï~¸0ÔYI mi°…³ ¬¢)¡(' †°±³Ÿç’dg—ÒkÉj()"“„‚5P,Í–( ÁÎ.­ C,œíÙÙ‘J>åÊ…bìd×PcwC¥Åмó/›óž˜§LM!¢8Â[ºÙ lD¾“ ‡€€Àvl³5ì#/¹ šMt÷?<•œà¯K›Z:þPyoð.Œò§Ú‚1oÒ÷ãÍQ÷ ÿªoK dmàÎ00ê©Øà.–D ’Ûp6ugwœMÃÝïàÂE (~rv''˜ý/¨üž,ö"èwáݨtœ¾wc‹'uëŽ0ûvÙq„íLÝQ¿{ Ü–¦(Ä=²”Žp3í.~¼õûõâÌĨnmi¶…]°4ßB‰12#38ÃLLàNNÖpwç~,þâ³ÃDOí ¿q„·9×-ME ÈH60Gw6ä¬Åvr±A‰@”¿ÆÃpÔ”Æ ™ë6ѶŠÔ!ØaÉþzîd3Ù=ߢ´ (í·½œwðΦ[[ØÙÀ÷ˆÑ…Ùï飶TÛãä°uwWqû”oæˆÔ¢¡ýnû¾*e‘9né©0Ѽ“£É>™ÝüP)Àί"Ø·T»¯ì{áý(€¿3ª-ì}vÔþl(Þ௠àü¾P‚†(ÖàƒZø«A1n%†’aý7)g¯Jö”`»íó}Øû¼§T~'¤Za¶?{‚m)Æïä¾ÿôOóÞVõ®¦w:Ün ßöØU8RáÈZ¶4·lÜCÀvÎm,MMQn1û2ÚÑjØgbÜJ‹‘L·“¸áÖV0ÌÑæÎĸ•3#XDüU’ÑÒtû²_",œ™™ÁJüuD­Î¹¿—:Á‘fÂô·÷Ó]¯Ÿ¯¹Ð!R‡ÿ%~Mÿ_P£“‹ñ5¹]úÝ®Åóÿªid©`Ž&†Ævn߯¨ƒº²CéÕvÛ£šé7£ Üñkþ…*ÿ:.ü¨29xþ•ÚÜcTáfÎ`0ò—óÓ_†Én sdCÉ|_+[±¿U÷»÷5Ñ]E;ÛÙϾÙX:mñˆ(ÎŽy@•hG‿Ùn¼¿1 _‹±71˜¥í^w®».[ŒoߨY‘&Ž.6Æ„,8~ѧŽãk±fìôýì÷CÉLõ€.þF?½±m»-ì\ ‘ï8NÈà ÌÀ€ÔúîÉÏõôUôôAuÿ}¦p„ýß*akꀂì_ÈxßhàGíå‡zq£ZÄî|pÇßî›gÙ¹->ýÝÛfp¸©!êãÓ^ TÈŒ¿Í`ŸOà–Ø–ÈnÞûÔ–V-Í-~Úg·„¾ßi·ãÿ´×þ­=2³³CšÎß;þüŠÕþKMH›GÎö ÉÌû¦ÿ|$ï›Mìz¾7ó;X´ݯîWGHð¡úgüÑ0ôWÓÛ®ö];¾x¼si§ì_;å×ö±%ø=wÜIÚ½"tú«_êÁBîï‡;'Gø¶øö›Òž"ßT§?ë/ñ¿üÃÀþûqóüñÿü-á—ùßÿÿûi¶ËÀ¸À:ŽS«›×õƒžæÕ@‹ žU¡Ñ§îŸ‡RSG3Þk¹‰ÁV`ÏÍ$n·RÙ]ª|¡¿xÅË"µÛÐÿÒ÷Öÿ¶ðÓýLþ©÷ç/ð¿@¹¾Ýÿçÿóo ßéÿ`Ô±åÿ¹Nú!ð—ÿ'ou @ øêÿy†:ÐrOçX¾ëÿyÁÌ ýËÿÊ-È! ÈÁ±íÿ‰3ȯ…І2²A&/=W+Ôçbd‡ê@­êþ£Á 蟜Ì~½µ;Ï«ðo?îÿfvÈ×­i×xÿ®­õßýû?üáú=á;ýŸynÿž¬)(”¿ö c‰ê=RøEþG/Ô¼Ë솀U’Æå¼›÷ZŸ¿ŸœŸz?>555Ý7øþœwžˆM y‚¾áàðØ—ÕÅÕO+‹—?}\^ü8?7;333?7óéãœ}äfÃhõK¹kË ïÇ&Kš\ã*\ã+ÜoTzܨ´‹,/¯ï^˜Ÿû¼´_ü„Q?:ínËèø„a@­n$“A4³a X+\Þ5c`hôaëKN³PÓøç¯‡7V>Å5ÐêDBMã„I­=ë+ ².,F±“SÓK óˆëeÑ… ÓÓÓæ¡%Ö×ËNÆdÜkÙ\[ªyÚ›~·¥òÉsXìÍ{-Ož³Âb3+Zï6ôX‡•eÜkµ /Ë©j»ó¸»§(þv#»I‡i|Û‹ÍÏ‹©åO“ËŸŽOL™ߦÓdԊȼ¸0otû¤QŒÊÅœþwï/%Ý÷Bþ%Vù¥UYýtëa''ü¯E‚–O^ÿÛ÷«‹«‹«š^#’O™Ä X'%•6wö½›˜šš˜š~ÜÑïŸþPÌ>MÝK*p`~i‡¦ÏˆélAnai&Ph)¡OГ(ÜPE+Z3½‹> ÎÔe9ÑåBvƒL,<æKJÔTÜUV*|’Ô4t´ H¹æ!漦.Xö»>{e)S çÐ#¥åÉ^ŧ|sŽ Q[…œ¤~;Y‰µ’./VXŽ[rXÎëë~ÓB¡Ù‡!§ÓÕöF’P‰/ò •RrR„ˆ­±•YØ[m-í…WàU=I1uÝ3„8΋Ÿð2ñ®…¾ëR»ØÅYꈾ–››Yx3?ûHÜè»÷Ã$øD„˜@˜Jap`p8éIÓãÖG8ˆi1=M™¤×¡èYçåÍëîÜZÊþ3r| ¿†ÿùg#ÀÏì?j³”ýçãàA½ú¡Þÿ ìÿï ?ÂÿlíÿjT$ˆ’ùµý_Ѻwöñˆ›ŽâªcuûÁ¦ 0XÚÂÑv´5òÄ#©±G^dÄͽÜäå!¾%ñÚ–±iÒ¦1˜:ÖüciÑ7ÙDljU¤2-ÉËmî“M¦Þ‘I•ã|¢€úƒ55a§2žEªáhÇŠ[W“ªUãÄ“ijúÜ Á‚ˆkÇJÄ_än|kÏ/f]MÎàï=µ(¨[¯cM$]Â2R·°*ÌMHÓÂ)¥ZžWl÷|¹ºÇEäU2·¬ÈkÜPÿTÜ!½”±³>èÞLÁLÏœBŸ5òÏè‹™Q“&9»•¿I¢xï®Ê–_›×NX¸?F 797¨® -Å-Š~ã‰]q/ZçÄL–w"ñ¢­÷Ñ·Xso'j¾½ö…;mù ìÌ‚Z­C’;õùÉeLoý^ñ ”ŠCü)bøÜmoâ£p=f—‡Ð :çÝ’œ{<Ëm„ç5²uôÖÖèßyM×üx€» ¡wüÉ|-2•|¯ÁYLË"zët3Î Ñ/ëKºIý˜‚/ %'.!u×ýé>¦¬Tm«Zìû¿55z9à%šáU)fi÷;«æå‘šéy‹¢h5¦`cìÃVV›þ›³k†"7νÐYG‡“n&;ë7¡šÁ«ù?~Æÿøˆw¿Žÿ„rCÿìÿô[ÂwìÿòÚ²ÿÒXï¿Èÿ8¸cýŸ—ò†Iw"Þ2…½Å3# ï{ªª'fOw- ? |¢Ýç|Öš½œ|Œ»HciÙ4gÙÒù'÷7¨SÃ]¹¬] Tâ¸2OvÔZ6Ub?ÆYYóâëõvC›µ«Í°{íÕ @Cb‚pQ6)>u€P‡X­··8ò@C |W¨xç¾ß¶Ìîým™ƒ‰øyû@ÑÆø†xÀ±˜åI<'+LXQJû²„¿²ÿÿvÿ7Ô÷¾oöƒþ™ÿý–ðËßÿ7_dmN´o†6«Ì7³7Wæ6£ð777k'P¯˜ßûþ/ºýý_¤X Ư‡Fe¬lžžKTÊPyn^\{=•SMŽ>fš®ßñT¯œïÉZ&×ö~(T¯2»ˆz ;æ^8ƒ*æÿPûï ?ÿÿé׿Ÿ÷>(ÇAþ^Þ?ýÿw„_ÿñýëë @µ^ 90'÷V£Ì=ŽP¯¥çt£i0˜ì™g„ž` ç³DÆW#í¶î¸oãMï)Ö÷¿‡qµO­Ý¹¼ägºf"ÊÚ=O—hm‡¹n“ÔÛOwVîÂXÎ'Þ3`døÁ£@Ò“mwH€_ìnÄ]ÄZ/xˆnÔªŒ;Wb“ú/ýûœy‘NàyÔEÈ¥R¤!{fY·>'Åæ³òšs­JŠgñä•ó@ö$Œž[¸yJ¨Šû7YÄ_Zÿßbþ½ü_œ<úÿï¿>þK6CŒ6?Ím¾éØ´€n^VÙ¬JCö#Ó>(™yý?aký?*bgý¿ÿ&FQîîúTˆò…—:@ï™uT!ÿŒþÿ±ðãþokgú{ü¿88¶æÿ¼<¼PN>>è¶ÿ×þ¿ßöûí­ó-ÿ/nÔº=;Êû‹ åääâýòT{1·Î–&ÖîÌ`Ï̼}"öÚG­A³Ã²W•›‹­½‹1ÂÒÉnºiyÈùA¶iEP°<0tÈô[\ów}LPyº8":ì…>ÃvàÏ?À"îeù%ž‘mŽœoñÑnv¶v6îËw´9’þ.ÈD¾áðØÆÒoÁ8ÿÒÖÿ—ªã[•ü!êøï ?Åÿ§ùß8¸³½oð_\Þÿ~Kø_àŠìã»Ñ÷q½!Ÿ „‰…@ÿ–„Ñ@hè Æöm4 : !H\v̉áC+‘^§ÆEtœ`‹Eí/694  :¡¸ê1l?IÜšâ“f, ¹øðÉ×Ç'б–F„Zhá˜JÞ|tËølsjãy·Ž·ðdõçe_hŸð¼Ôãf§¤ª·…©j$Ë+¬ÃçM„2䟅"ÎŽºæç=é)©7Š©è÷Þ£,·™î¦U¯ë7C8xzép¶Yçv¾˜PÛ®´[e_ßøò|*Sc?-:ú‚(GÒ âÍža{7yø îdÆ1ë¨Tõ U›€Ï7y&Ü—jæ…"H4u©ÙU§%²”B—£ßÝb.©aƒæPQ hF»C{†õ¦ ÜäD Éî –Ëi/û,Måeea™M›“¡ž›×XÈŸgº%¢ÙL¶F¤ÙÔÅÎCnø¢%‡¸¹ÇÀjú޲ÿÓa¦Æwâšd”ä?_ñ+j¾ÅÀWœÓ *òB?WlqÈfÉ áQƒVÚ%é²aËÝ*Yšs*àiŒx°XÿìJטK/C)â¼–Cþ=®Ç"Å2‘¿1Û @ÐÒjRhÜ€ì7AÞdmý lS€ Ú@ \ëƒí ˜üRrµç.«åÝã‘eï7ùÌÞæqûN­,÷½¬¾¦ÂJÅÔlšõE“œçúe-‰SÊyT'DJ>ßÝâM¢p¹NÒÉy²¢*³[8°KŒÎ[ª7°®$R¤¸K j”Ä®{iJÐôM¢v–Ñ8¥÷)Žø@€ ”ÎNåÿØû ¸J–$Q>¸»[ãîîîîîÚÜé¦qwwwwwwwëÆè†F›î½;;;»ûfv÷ÿæ}¿÷n@fEUfFUJDeÖɈxí<_#$½$‘'TªSó…1ÆdZNY6—ñ%LÇêÂ%ëGº® Cy¬ˆ€j³®§{ìîÊÆå¡¦©G©踰? úXþâäµiÙwÅ;¦/uMõ]™ÝνùhÅm:l¡ø‡IóìƒkÃXµmÒ-îLK÷Õ×µ7ÊUI%hÎBÊ¢Þ[Õfn áÝÚ5ï–4153îÍ2»„ŽŒÜÍÑ"ªw†Q†²·Ô{–«ö! KK|ÚVfù2£Eru%Ë£ï X¨gOµ5iÁ6õ–5{œ>ºœÜrW :-' j¥Uà žÃZîê½®¯dO«µÕæÐ©cKI—h0v;ÑêZúã²Z4¥FÜhº²KÇ×÷W.¥…r»'k°Õs°[Å§Í sr@;Ù³ ík„ä•Npeejé±:aÁWFø !Qà(÷Äp3mImÉb¿Ù‚1…!y•>q ‡³å¬ÿÒ_!PHdhÏ·#ô(@Ý»{4®ö)™}${ÚÚÌQ¦\ŠÙjxÍ~§ã^båvÜ;£cªΠƒ¸œE?€´ð ý¥tÑâj¶?+•øÜÌØyhuYSÇ ÒK›¦PkçKÿÑΆ:Å|”æ™õp½ýoƒŒ€¡YÏíC´ô¸„+¦MDÃ\a«t¼Td^+jq)&ƒÊ|­ÌAaÜj1XëeörRÔ­Ì-]¥Î•4Ê÷ `ûÞb‘5--œü̱ę»]Œ¹©¶´Õ·´ÌÜ>éÃ×ùºf½&æ/wG÷¯ÒO}uðáWƒiÜ3m§ñ·‡ L.ôGµ¯FÓr õM¼N·œÓ¿B½j—}z2 ''7¨±¦ëJY}_3¨vJ,Kü±r Ÿs™Ô o!‹AÅ|h-v,Ë%CƒÐß­:]OžÍ\§ û¢ZŽëhò$kˆv’^’’¿…ÃåÀuº’ÕçG•ðÎüÑr8Nª¶ ¼ °Àæ+m„*DV Bî+/ªå/žôŠ:(ç³ØÅ0—q|‰þVD¾Dà¾ÄBP= Ö5ZN ²£1çfg{GsuI‘Ž´üZƒË½×æU<­nkË”Úïù;lÏ5cl¸§þ$¥ó²½÷áÆŸHìÄמeÔR·)ÈÂT9燩Ùõ1ìÌÓ\Þ6¼ªòÎ>µåÚSÕ¤Ðìî›[W…deãÝØhh°‹Š¼ì?ç«Ý¹¶Ö6o¦ÿ¨Òd ÂœX™…\-³£Qþ—ÎX"oPvà˜ÄÎfÖ•}_gß8-·ø”¼Ðdûu'Bc®iËf4pYM­´†yÏõ«ñŠJ­ÆÈtø1% ¡'LÖ²iÕ©™Óñ‘ç!©]ש8kµ ƒbxy¢ Ù'µ§–SI§*ŒDýW›¥gE]4m¶l«á_hw£Ù?Z ê,Z‡<î wéÛø+/ò÷q}æÙïOàÊ#Õ „«8f¨bËÑRYçv%說øPJ—R;,Û4J3¬ÏGžƒ Ê%5Ç «ô4if¦šiß\À7âî4.¦,ÍeHøZ‚^ß-¾¯âJú…‚ÀeeS];“Nyã ×®eÃ~K­lYRþºh2ºÒ™ TÏÂÒ¦´nž[œÿ^o±n#º¸ðé¹™¾¹ýÚd^GßqTÝêÐ";-nÊ¡¸x´ö˜M›n~¿~`_FM5——ÿdOKÌLB¡`Á=Z^€Âûê×zÚ²­Qj'´ݼ,34ÉßëÏu îÚ<û,6žmO^=Ù65Çuqׯy¯%g˜ä…ãi(Ï ª{7šºæ35'vyöïûÄÍVÒu†N^{daŸŠO:­¬WÜu5To”7ûÓ«EØŠ¿â5Ô›|*q|t^Ð)£v7–‰¬žšîŸ?áº&7á·øX hy"\'ÑsÜsšŽçF©—³¡ÝÛRŸf†_WU›Ç:yéG7È÷X›…Ç=UU¹ŒîøÐbœ ömÛ#,oª ³›0˜[Œ>L`>y/é=,F(¿†-Nc}n³Ÿ*è=~©ûi¨¯°PäDŠï g#ñÔêñ¿¯‚úTvüQÒ~ÚËá™yðŽ]³ò‘±®xˆ, îï½õ—Žë‘ˆ˜,šÚQ-„L£ÐA€9Hi8¨ªPßG€%¨ ¿¡»298Ÿ1Ûa¤Áb8ï³²Vs´(€»Æöµè8k!_ ·çòœ&hÍï1+Ö–-:CZ/çy¯í–ä4]ïÔ‰M´ÏìÆýW?àSN=í’–*œ®Ãyñ#V6éNž´;Oh£RÓæjthT?¥ÂB®ôáà&¹6T. ¬8.œ¾¯œS”Åœ&à^Ö\Kg!×Dó™xä:ÌVÍß÷äþU?6U¿ÆóµÑäN7½º¯´šìP_£~ðɺœz*»I]&Cþ£TYÈ ÄAÞ žEzLÚõ€àyZ¸ày½/­*õÄñ ù°D[çOñNU•Eî'ò£c]™þ òyo-ÏÀX%6²c£•fBÐÝ)\`ãþ á:~ñ«h)Ýdyåèþ¹{Yp~û«¦œ}ä¼Ü׺šýpTŠ*x€ ž‰Í÷·eš¨›/"(›…¤漉HV+ÿgÔ WÄlX¶èÈÈ×lR F—D±9úa/]ÿïžÅ ò±³ø •§ÀD/鯅‡ëEZ½µÍ!Ð76jûÐ× ¸3ÆÁ­Ë]re‹«ôÚMìdæëÚ]ìòind 7Ù\ÍÕKͦ4á' íüq2Ú<ËnYÎaß·»(æË2œt12et&Ãb¥Ñ}ß%¹z ™Úõ~±–=‰pýnïÍwwVTm(J›Ž'/3ø(SÝ4Ô;~Žþã¼¼ôSÈ K2Ÿ`ï4c²x󼪬¶Ty£Fê‡Ò 9;KâxÔB1gáb a}ô/T-Éùr¸°ãÅÀA—›V>M M¢ MMUjLBæC’=¶y’=GW' I´þ¢Ï" žêuë*õ'Ìë õrêº(*ÅaçR„²Ÿ-ó qˆüáH‘ßZÔ—>Ÿ"uç„TФŒO¬ë‹î ÿÚ´Ð=–Òüw2­îEljÓ&évzÂ5-#]yËùÓÍòÜÀŒó¥<9!$_P_2KÈÁÍöbìýló”kòÜUÔ$O£yùjš„¬G*}ØíÖŽÕü/é“Úš¯âv&­¶YRòö ÿõ|ÓG§MûªJ¡^ñ‘>|zNMO«Ts¦ª8´ à±ß¨ó:YUµÿT8z†“Û ¯¹mÖ7±üSO›çñy?I[_Ue}£-¤º­(NsRPÂ»Ý®Æ 6ñœŒ6aá•.µÊçia}£ª°×öd&”K‰.–“=Nü씩•E[\9ز¶GñYD“mdkÎ ¶bQÌG¿Ædo²#°_g \¦"V©BÕ#¯P<ŒQe_>Œ!¤F›«Íû(U $V»pö*4ÛŸà’8øéÌO¸:>¥Ùf¼³ÆýÁ4Ý´þcÐTkº°œ˜æ;£ ö:þØB&R¢‹äd‚ädXLX)H_Gaÿqâk{íS ºº²²ï¥ÇŸ<}i…[ŠyKBe„é R”´ÓÔo´L•5íçJõAõX¥E æ )¿M8!!F75Pš"Û™zzPXð# 1~1¿¿á„ Š@†/4£4/\=¿s<׳jk–@©b¶”My}²çç4ÖJâé°Î¸E¡çŸ•ÞB)´$Å6²é®©¸Y¿ÎHóü–ä#½=êAÀà¼ããÁÕ¿æ"²ó`µ®bƒR–4‹³2ÇPU°ÈrØÓ¥ Š Ìüð¾t/åa¡K\3^c«¼JLî6Ú½¨æ ‘ÚΪ½æþ[}ÃÏ(–+à pÉšfm%­¤›Ð„ÍL¯ è>-)¡¸oX$ç¾牫½Ð¥ÏwQSÂý[·3ÂMwÈ%a3¯d’¿l–¥)7zÂ%ÆaDˆÈL(ÎDðºž9N K4·SD*·Ž7ikj•®yhje#õ}XtsRW7Ù¥©Ì-¨aÁÄø¾v©ê[Ç áƒ[Naƒ°€ó¥8˜™lŸ&è TT‰1jÐæ:°‘"¿.†wpüî•%†ÔùkãÆg2Í .mI¯Ó‹nÛ«ãv„MW žL`ú€‚Í×’ž!0dy³CgØàu惣N¨¤n °0¦T¼’þùuPP2BQL\X˜.ájó¼4_ÝZ<‰g®€_‰ŸÆj¹oÍ ?î-¥­S¾ r|$ }`dÆKƒ R–”N¼óÀì‡ÛÅxb<5S•–Pi6³B/ Êa…žøüS@Æ‘žHÄ€¦ÊUHߘԴTe5¿Ž9[û\ÜE EA/zU~b&”ð ;&Ó±ã;¦£-Ä(¤á‡ª€cG®`(I´¨Ü™ï%‹)¾LàØBÐàY" d0+.ã´r\zDâ­)«O¯Ú(Dñ`wa3uê<<‰} ¨ŽÈ&òî!~¥¼ ŽÉ6€mçSB ,Òä Â}Yý'|ìþþü#þßÿwïÿeãàøÛß8ÿ´ÿúÏÄÿû¿øq_=¸Z=ûÝwûÙ÷ûß½¶T,uÌ,š›ùúÍ"u"§ûëï^ÞwÏnël¬ÿ¡÷ ×ÙYÔdxˆ¢Æ° ——µN*uëo¢ÖìÂj¨Ulƒ'£ Ž­¡ Û:)8²ö“!ôòwr:øN“ÚD¥ÏÉ…äXH<Êtè)ßL·©à.q¥…åU^4ÓÙ+ôUdUëHü·²ý ¶’ͶÀmb?N³ƒÚnêgâe ~àƒÈ~C˜/BùƒßÖ²Âw*+ÊKÌóÇó¶–QþÜ”T^9às76ªksæË·Öú¿o#ÒßÛÿk÷?WÿùûüÏÂô·üÏÂú§þÏ?þþÛòKûÿ×Ütoþ°ÿÎj‘Ê`õ*˜Í’È4Ü[hô>_ßÜ ÚgvÌQéúM¬ìË},Ôö¯vÏסñg~-ˆôW›ÿeoàÂFJ.àÔ)2x–_ÎgCQðàµýž00ÝzLkˆlée¿X;y¾™é[$¯Õðw<ÅUÓþÄç7¼ÿØ;¦0—ðwà›º3àù&,žýú­þïãì þ‘ý¿ÿûõþÿ‡?õþIðïÿ¼4½œÌ¼iþä1½Ô(½,¼íÿ%‡°òüý¿µ=Lð`½Ñæ§?¿r‰“á»B€Äü€ƒÊg çˆrŒ0µ¡,cŽØ Œ‹0û÷åç¹áú;Pߟ›?£ÞòÿUæü'À?bÿç3ÿ3³2ý­þ'ÇŸö¿þ)ðØÿù‹Ÿçû›ÙµíüæqÓ䔚áÆy"­›èú×—†A•ÞíGÇoÖgÔ|Þ,Ô<Ü~7 «Èéä¶ÎpOnI¬|y¸ièŸ·Žª_XßYÜÜ-n›ü~uÉdöf‡Å"5½v¤uxÑ>®L7Î!®qíëþÝÍõÄÂ˴Ϲݾoöƒ¨ h i“¾î&T >ßÿøuóòxËk“Ág“yuùÑ4™T'îçkö÷iǧ§'§gÙ c9MãT ï#jµüJ Z&fÖ?¦¶î6 .Ü|¿òJo;8:>:9Uõ.¡ÔOXßÞ-¸¿¹6 ­ž\úÂm•qvv–×<~qq‘ß<ážÒBgœ$ãžÿëþ‡utýâÆîÕå…CŽþç ¯ŒvóÔýÃ㌺Ñ̆±¶‘¥ªîÙÓӳܦñ®±åDZ£¤/;Owߟï~ðÛfy¤¶2™¥¤T*y· /ÚÆÔ“êÆÝ~¿úysM©Om˜(åšÿøóûŒÓàoVRwÿâOGÂ1mªŠ£CÈÈt2A&‚d´Ç$Mç=Y$ä/刧(Ü‘ºP r†¹È» ¡˜žÌ^ÕCÝ0ºL‚žã‹bU[$1¾ ꑹÛ&?§;qÇ.²:ÄôÚ~]U`Á¶¾FÀÖ‰Œ‘/±¬sŽt2Np ce±e†Ÿ¤å|Š6”4®øÚb®¯é6Hqw…JזּP:‘6AÈ)ê¸é²ñH³êY?ÐGXEQÞ–¤r߈ã\Ùhp*²ÅãOý™…}8xVa£4ã4D5j¬lsÑÍþc˜–¥EímI -I„ý8 ‘ÁèîBÔN×eoÃ÷Ï7Ãÿþýï±ÿúßÕý»ë?V–¿ÑÿdeaýSÿãŸÿéüïMÿ“ÑçBðêÚþ0,v÷tÒûò6ýE°Ûéòm>ˆã`\$IÉÉút÷#m»÷ªžÓ}úyÚŒ‰Øù‹`ÇgUæø6]T0¨l*áA¹ ½ˆ6qp Ö×5r>ö…„HÎË‹¤ëÔW￲ ÔBIŠŒp"N¬!!!ƒ¾¢!f1VþꮫE÷Ëéx𹉀Xü¤j4 †ÚÄèH$PÀÀÀȪ`¨û.áÄÛšìãíýìcºŒï?  ÔOîô`t{k‘ÿ·DÊÎÿ&ƦÖïì]íþÛvŸÿþÿ³q0ÿûõËŸöŸÿ)ðïù$æ5ÄýæÿOP;ìÇëï_ýÿ=<<ÜÝÝýÅçßýýýÏŸ?ÍÊ`ÿvvCôûìä|SÞOr {¯‡CD=jy×”*ãs>ªÈe¬’x˜©€ï‘Ž¿çÀYVväRœíèZêñÅqÖÌsVgý÷“Yïë*ýï=×ý„óÇ?Ž×¾SMÄïÖLÒkâtÂ&_X*gTîÖ$Ù7PŠM,¹{BËK k~úì øI%AŽãÓçš|~ZOoü”¶ƒ)ýt¨’o”A“[x彜˒µï¶Õ>YµœI†l< ’Æ/`Ž;B™[Q®K<™ =}4‹™j4Û:0c‡ZûpàÑ&Éüh\$Õ’Ë/jÄò­ùÂj9éw¹"éaet½8Ï9uŸ¯.ßr)ÕªhAl€YÂ7…Jé š¹÷EüÒR×Ã|kñŸ÷U ewÀUÌ$?%ùtl3šˆøûtϵÀ¸ƒ.>¥ÝÛ„±94C´F°9ûa·ÜËŠã¶4|B±¾"YÚ¯ × ÇªÅd4¡7ÐéiüðŸ%ÂW|æ~PÇy¤u”’Ô(ºvJuþ§™ÿ+ =$Ó‡©‘¯'+Xb=þû¦wÇ777;§‡÷@äÐW»¸õ+”6ä #BEC°>>óEÇ ^_žŽ&µçëlBcáð{q?»e˜xL/iÚy\¦w’ v, ÝšDË<{ºnžªÊ Í’LÿÒ! ½ÎúX×êý“Ú˜œu”DÓð¤WÓÃÚR¼ç—0§Q,AлïéùŒP?Ý Ë ©Ïýšå¸6?cµ mÓ²Š7AaŶ ¼”ör.iï_Íä„ö$I‘¢dç›I¿É~ kî®åE§A}´k·;ÿÜÀ~y« )O¢jÖ@ˆ >!àè0î(€‘4h |á>}p@Öørƒ)Œ3 òÈê è:kÊçVhè=›Lƒ‘ÚwÈdâFDĹÝi}ÒÂ{„ò \æNÀÈéA!R£¡ž²~(~ó›ŒÞB"1й¼]+Þ"ù¿—#ø\ O6Q×­^ )Ö§ŽÈÒ³!{‰!ì;aGBB„ÚEƒì NDf#ÎD´B‚ŒÚDB…lƒ€ÑDÁ‡n‚öý\H–3¥"Ò§ƒª´+ ZD"…ìK£ˆB'Õ³‘GGºMíÒþÕ܉ŒN|†ˆÀ¤2ÑLJ+,GØbæ³¶t8‡T4.YG°7CWŒM„ ›Ô‹¤êÔìQ’1÷ö!÷Š’ñd~±tþPÇ/ ! ?¥ãz‚¤0ˆ}d+î4ËÄõHüvFxÓóòÎ%Ææ³ ¬ÔK+èbd¹tL¤z®o†W˜Ô²‹:ÿ”•OÅó¡ñ=M/ÉfWBï~QH­K†Çõ­ÚHô a.¡‘ûEbÒ‹€¦Ò7eÆ4EÆöÌjÅÞ9k—âÓqH|Í&¿m0ÕŽ•,hå3´‘k±‡wŒË#a‹¹ðtîÓ— ‰CÇÈõÓã;km‘”– ›êQÌd‘SQù ÉÒŽï_bvãÌÑG$-Œ‚;²Ö˜ûÙà3t7°(’YL„±Ð'-ÂÐÚ'õGLßÞ'ùGL×Ù'ñGLÛÝ'þGLÓÛ'öGLÝß'úGLÕ‡Ø'ò{ìÏHèþ#f íú#¦'WQø#¦#T‘û#¦%V‘ù#¦!U‘ú#¦&W‘x‹EžŽ¼¤ý©HE>U˜þ†¨ˆ2ª€|7ø ét…€4G¶E"¦ ŠêKCA6C’(tDVsþe 47¾'¬£R„³ô5öÃà^¥ŒôŽž §–G5á3Fб°!k£Ê„ÝJ•-I¼†#¢&)X!›Ø_-jÐZ1H“àäDiêŒ8dZ²}")l!›_-"cZ¡>°<Å>ðב'ßù òdû _Lžtìk€Ë“ì{­Ë{£ ‡äþv®3"²3"2P"ž×@CFB„û`ÉDˆn¤? •Ňø-P €•ʽ¶L²rM(•”<ªrLYÑÔgá²Ø€¨R±×¦@”†ˆ¡!S²ŠQ)RË*@ á’fGÆYõ‘a›IÓø‡Ä©AÄ’•Š<ƒª Ñìab³„`K»"SljÁ±¼2"Ô×J&CôôÎȬˆ6^ÃYQÇk¨ +#Êx dcDž¯Á†ì„Hï5È‘A }‚÷­‰Il1ƒô ™€dìé{c¹ªÈ˜@$ ÀKQ‡İ Š™“% ÉHÉù%Ĭ¼v6Xn¼Xn\ÊkXËÅÏÝA*Gæ ½M ¬…ñ§d†õ§¬…õ'g†ó'¯…ó'e†÷'­…÷'fFð'®E¥dF¥¬E%gF%¯E%À%æ@¡?À CKã}Œ“º&«ôÝ“Jm‹£B“ÉÏ¡J…PÇ€K/cJ=ÑÎQ«Y°¬˜ñÓ{6Ñ›ì¬}Ð#¤ªËç§VáX–ù˜ÏOnòNÿ£ûæl2·nù‹ûêæ\–‚°ç´rãÐZ<õøÑê鱋ÇG­‚/ ¢œ‘;lÞ&aÿ—ï÷_‡7[þ¿€ùo‚ú{ë–¿±ÿÎÊÄþçï¿ÿøÖÿèoá·õd(à¯í¿£ãº;¬þAûïÄ|0}ÑǹöS ó2!C!® ‡6áÑŒA#”îrã Åp?#2øâƒ°Ý‘¢ÅÉïá?ÎDrNwü~€Â‹BBaQ ç_7ÛsôOaÀ¿ ì]RÕ ~·`yr ©O½041Ò™ š?%‚E¶Æî_F‚ŸxLÚReè 3Æg/WýnûM:h³[Ž©¢÷n˜:®ß÷.] æC|Ž_Ez1 (¡å]tìÝ('2ø ea?Âsu‰dCîÓT|QaHo¢ÁÁü(OÀ>ºƒ´ðÈŒaÏÊ/(¶˜û= OF¥v)ßÄàC*Ú.¢ªõI#èpt¨’åQxL›ˆ‘<¥oeTx]€Ëª6ÀâÊ6™×gò­'þÏ¿÷ûÏ›Åc ÝÜÿß3ð¿æNö¿µÿÍÁüçï¿ÿøký?ôÿw൤EE •T%¤åÄoŠîðRr@;{PdÀÖÎÅIER„HK[‡j €@˜cSgyU µ7ªÒâ¢Dί™þêF¯4n—¿©ÌÏÓK)½¶ø PLœ\^É(½â¬fæÎ¦¯øçWÜÆÝÅáíú›Õ:të7ôÍhºÓë¾âØoøûßqºßòüŽ ½áf¶v¯õ}{f3[³7|àqs5ÅÁä^ñ 7 ¹û+¾ðŠ“Ù¸Ú_ñ»·²¶æÆ¯þíº‹¹©å+þ6`áÔTD_q>þý_á&…¿9ê~«”¨½ÃÇßR™R1sssI™»Û˜»¸Ð+›Z;™‰ÚÛ:Û}|åÔßêü ¾µ-Ñk#s0sspг00ÿUCý/ÿAxëÛß±ïÊ¿õæÄ¿^ûòÙç\7¯mó¯×LR€æ@{í_¯‘åH¯ýÖ4ýWõÁ|/å»hnÊ`jùW÷ù»þø«û1¼‘ûKó‰™[»Ú¸½µ›©½½«Ñ›KGs"ú¿Äÿí‚ÿñsЩ˜[˜;™Û½–Ðxe@»÷¯Ýmgö›ƒ{" ÝÖ‰ÿÍb¿ëW@+ø@7d O£ÀÎ'àhp0½¬×¿ô›Œàó4 ÷¿È¿§ ý9ßÿVNTEÈÔÕÉí÷´7¶@`H¯s À;)€ @`pxBq€ @ ÐL–[€Àà ðÂ1€D@ P(TêÍ€@/`0˜,Ö[€}À)àp x|dP  h 8 „ ä ´ , \  â r * Ú F ïAì@\AÌ#, ,%,?¬¬¬l lì ììw8888n8e8 œ/\ \ ÜÜ6Ü=<*< ¼(¼¼+||1|ü*üw !„(„R„~„/wˆhˆ ˆÒˆfˆ>ˆéˆMˆsˆH0HäHÂHHHIHõHÓHgÈ0ÈÈ¢ÈÆÈÞÈéÈ­ÈËÈ7(h(Ì(Š(¶((e(£(G¨P¨¨â¨f¨ŸQóQûQwÑÀÐHÑDÑLÑÐ ÐÑöÑ!Ñ)ѥѭÐÃÑ+ѧÐ/1P1Ø040>`¤ctbla‚aR`JcÚ`FcÖa.a>`` c™c…bUaÍaýÄÆÃÂ6ÇîÆ^Ä~À!ÂDZƉÅiÆÙÄÇ¥ÁUÆuÇÍÂÄ=ÃCÇãÅ3ŠëÃ[ÃŧÁWÁÿ„Ÿ?CðŽ@’À • Ÿàìæ;¡wVïÞu½;&D# &vža Ù¥ ]ãK»çO?’P’¨“ø“T“l’Â’r‘Z&ö‘^’’É“y’•“­‘Ãs‘[’'““ÿ¤ ¤Ð¤¦h¦8¢Ä¦”¦ô ,§Ü B ¤r¤Ê£Z †¤æ¢¶¦Î¤ž¡¥a§±¤I§™¦¥å ÒfÒÎÒAÐqÓÙÑåÑ-ÓÃÓ Ó»Ñ—Óo3`2È1ø343\0’1ê0Æ23þbbg²a*`ZgFe–aögnc¾f¡a1eIgY`E`•`õama½b£e3gËb[aGc—gfïcæàäpâ¨â8æ$ã4âÌà\æBçRâŠàá†àáöáîà¾çáàqá©ãùÆKÏkÍ[Æ{ÄGÉgÎWÀ·ËOÂoÌŸË¿%@$`$#°%H,h,˜'¸#D*d&T$t(L-l%\!|!Â$â$Ò(òS”GÔK´G LLR,LlJU\] $ =RŸšbšqš[ZŒZ^ZãÚ¸Ú@í( "]qÝDÝ}=v½ ½%}Jýú£¸6†H†Æ†õFFšFeFOÆŠÆyÆ7&Ò&&—¦¢¦É¦§fBf fÇæüæqæ‡üqGïùßÇ¿?¶´L²<ŠÓ€WVRVÙV?­­‹­_l4mªm¡ml[íPí¬íìßÙ°Ÿu urØräqLt¼t’u*rqÖwnqALM¸R¹ºn» ¸¥»Ý¹k¸×@ù`÷aâ#ÍÇЇ…ŸÀ?™~êó$öôóÜööÊõñ6ñîó!õùì³ï+é[âëgí7éÏäçÿ#@3 í3ÁgßÏ»’åAˆANAËÁ¼ÁÙ!à!À©PÖÐÔÐ_afacáLáIáO¦c‘Ì‘)‘/QQSÑÑY11v1K±‚±%q(qq»ñòñM D a ? G“Ø’²“a“]“·RäRZRÉRcRŸÒ,ÓÓEÒ«3ð3B3~fšeÎe eUed‡g?äsVr%s›ò(ò’ò!óÝò 4 † ¹ K‹p‹Â‹ž‹íŠ·JTJJ9KKËðË¢ËAË]Ë+ô*f*Å*[ªè«r«1«Ãk5®5'µFµKu²u}õ\õU ä haM M›.›-›·Z´[f[eZûÚxÛÛÚ‹;ˆ;Ò;1:£»`»>w½t{tßô8ôœõ¾ïÝí3ì[ï×ê_P˜”’êîáéåmãkçoš`ŸhœdŸlœâ˜jšæœn™áži›å›íšœë›Z^_TXœ]R_ZYÖ[ÞZ1[9ZµY½Zs[{\÷Ý€ØÛDÞLú‚ÿ%ï+õ×ê-Ž­Îm±í‰Õõ]ÓÝÓ=ç½§ýÏI‡„‡¥G,GÇÇ3'º'û§§gAç(çT ß„¾M\j]î_9]½\G|Çù^üƒíGßÒÍ—[ÛÛÇŸaw8w%÷\÷Ú‡îOPO)ÏÔÏm¿dm¼Ø¾¼¼¬D  oÿØ@‚ƒƒA@A¾¾®^4  44,4,,,ÜÛ¯õP0ˆHðˆoø‘·âo¥^ÿá¡¡ áÿËð»é°$ôc:Œàuû›ñ°¿ÌgÀÀ!@!A^Ÿðš,„üæzòíYÁ ~›‚£@@¢3 C¡‘°(C;ÆÎ¢ûÅÁ²Šäb`ª˜8ù_b©Ö’‰öö]½RÀûÛaÿ:cúÍ$Ôk"å듼VëæÛÿï‰(`̨ÄÂà$hèÊ,"¤~±ÿÖÆØÓ®4™íäWÚòTl¿Œ>Œ%cÑ#×R“›5¡Ê0þrª¤Ê#ý¨6|>k÷É(“!Ý{"[ÜÅÀlö¢z|Tü¬Ä-¥ §bÁû‘œóÀ-v‰ž]ÄbךdsÑý0–iÁHgÒ÷FðJ.¦¦"m軬ÏM[@L£¼YÓ  ¶ˆ7Z™Õ>Ë9[vE™rH†O™í À‡ñ”zAÚ ½´"³â[ñó>;vxü¥ü]ÁycQòMÂÝ@Ò×âÃyT{¶å€öc^­È¢VÅ`öpJöMv,&½¼ ®;’ó”VvŽœKsjö Ø­-]³÷BA,ø|Ü­­9D¶X8HyÌöµ¢xˆlt¬V'R仜àu fŒæÚµÔgŠ>œ‚»‚®z&˜0w{>ïì—¼CRC(›¯žß_4(‡´Z¿š¨ñÙß ý²®ÎR˜Î«^QéèeSptp84IÍèÞ.Ö©µIðoﱓ›/KîFI C@康-ZîäN•p:’•…#gÔøz»õ,;:-/ðÚ&Õ²zÉÈ)´âÑä³= W–Zþ/’.KhI‡£ÙáÌ“wÞY–Dc{@c^×§(i,C% 'SÅlàÈñpÚ‘¯ yÇCÒçA²ÃÔXݲw]Éˬƒ’@¹ÊD¾(0°Ê„šº÷@mÕ3˜I2°’K`g§›@e¢lù9ŸŒL Ê?&ÊÁþ¼Ô*ã—´¬¯ªCl ·:¢K~Ö{½¨ÍhD«&6xpR2ö4‚6ƒu¯âëôV.QÆ,[£ŽÁ¢xòCý:öÂÌ®âÏVCê0½èŠÑwTgÀ˲Æ3n˜Ý¼Kyܭȵ6$PX˜£FâM|ŃðC¹Ô,d¡âè­ãû€Êô«®‚þÆ@»q±ä‚f‘Æ©e@k[se™ð³T2¬®Ÿ:Zü!&¹µÊ#§~†®Ôåg* mlcgƒ ËAîª *š³‰èe2Èð¿+mnG™&ç—Å‚Rê?7M,çËHÏù6Ðî*c ^¡[£ãCï‡?yÝD ½v,ÍZ̹åÀî¾ëŠ:ñS€ÿ¾³".þG1ZT·D2œ¾5¦Ål‚úŽ~dõIc=E¼ŽïÚö{J¹–xVRqB†T„æ™}õÕEŒ„›ïšw ¼®Íží,'m4BËA2?QÆ‹ ì:žæN¢PºhÍÕ8ÍÄqHàK».ˆõˆ¸ÑP⪢Îán!/ú–²³öÌHÉ„Ù碩¤’,¾ã}̹A¾™óE„±z«|6¾Só¥€þbiyœ€VãõD#︊¤Çˆ‚dÕfy› ü8¸³Š £C+uT2˜ƒž22ÓO9ŠB†c–0|ªÄ)ˆ2&üÚWX«ûP©Q(㤾5'2Oß8xò¿Õ*¬Öz2Þھà ãðHúájEÒSUäfþcjñ]A:ë¬qŠ+¥ËsrÝmkAi–JøåÉäy¸4fJ†ôº(IW˜#Ð͆>¯ÐÁ™Ô"ŽƒC÷ƒóˆH;\1Äp»Å¯ÑÂY2>I˜ÂWÙü5o–††¬, Ú €V“hVÉ– Oµí•R‹nÌŽèm`J\Ò{â)ˆéu†UÓ•ÔTòýøW¹>ûÅAÝ€¬Ò¼w®eW®`VHJ²­ª"±µ6©0Å2¦â#x ÷\yÚ>ìâgãR9ª,HÄsA¨|sÍ­NEéÙôÎLíÔÕ„Tcæ¢-~¬™,ÚSøÁYC§tYË4ž¸ËpÛOºìù¼2Ö'µ’УôÛ®&³á«xH9«¦5u³GÙ’“Lf¼!ZMúhޏÈœ"1Ê$ ¼Å#T*6T¼á¿¤öÐiЊž~9Eª.«ZÈÐK &HŸ¤ZWÑAU¸6”#6â3 Nìsíf`ä´+_ìÒXAuôµI,H£˜«ôœ ðØì¼lRNš< #Ȥ2 !ó®þK Ô°E¢Lø ^y)®‹ØŸð%›á?\ $²–ó u£Œa»Ü2›‹óÑ3ÆH:°Ù»~®½zŽÔ=ºœ´sångíÂÙäŽ\4=>0BŒNf O¿£f­ïB¸”ÁÎ/vÙ´ÖujÿÞV~n÷À/œr‰É+1ü“«±™ÇƒÑM)œ¯›T? ¾‚G>™ÌÙ,?ŠÜ‡î³£ÂXÍÏÍWÙÿ£®{'”e”D-3c¦ßq3:O0Š*{/¦ 4´èy\fÖ‘4!%Ò@©0lKµÙÜ­MqÎs…̯ÖW·p±ÔEDß¿"Mj—ßs+)Y¢>ÌxótcwTGÂu‘ x®­Ö£„¹@ðíF»pV¤%PUì½Ë‚˜XZgt)qÑ-õ"@”h¶-½$¶éUâÛDÞ´ÊÁÔ ª†Høo7r2—Â?…pfY;À£”àé~áéô²YȦˆÔ`Ål¡ÍÀŽÁéMúVטgÐÛa—Š Âjó-m•á—ž¿¥ØÒÐcʘ²¤‰#nê¸OñÛ`»NÕ ÏÏÙ¡–…I]üøüÒšùõ›óîÿ9»¼æ/¦Ã?ÛÜ1=Èxv+³«îØ2‰‚έã…W«w}ßi?,[2õÊßq¬èÅPý‘ìaµþ í¹±9™ÿe û*ßíl^@6î''9Þ ôt0UÒ•ùšÌÿIQ‰Îý£2ÁÚôkE§¥×¬ÌzþdòĽ‹Âx7æ„·µï6‰íT>YÖzY…¡ ~yŒân\d½¤õyúíAËÃn­ýE×õ§X¯â÷”0À\ÈCØÝí’hUëJSòíôpýú`S&îÏÁlÍ+z6zñçqŽ|nÓVè£d’Ñ"o9í÷uCœÉM¸"Ü9¨”ÑbßµÕñ¢¹iÈ–¸8w]””&¸8?L¦ ÌÈdkc{ºWpH]µýÜüLºKˆ-ºÔé½óÂŒœ%ýñÁù+öƦÙj„z0Ð2 xaŽcKpvTìhfÓ·à’«í1Ûò‰‘Øy+i{‰Cˆ)QësË”ë­UªÇI•ìRøRü³±V~!JM¦y¿|–!a ¥å#ç-O‘›yÌzÐÞòܨª2+е‰ËgÛb7>—’½}»iL·ÜUðÔ÷\ËKMüEd†&Š”/¸áñàˆÖwCtËè‘]Õ—¶›zììû®ÖKøe²~žé»K¥nŸ¬@ŸæKœ-0Vè¹µŽ³˜¸™lª3ç íÎ«ÎÆ¢œå®£:» n‡b’‘¢Œ˜ZÙÃÂ$÷è^L;ç~kòÕ¸´®‹7³_U‰~&®1Š;uœ û™ÜÎ8×6¯ÀµuÕeHU‚%GèÞJKTïªè™§2I:•K´wŒo1¬gÝš¡Y…?YÎIî Äái4T¶¤µ™Ü?îÇ”rˆ§ŽŽtÔ¾MÁ—ÑÂí­D…¦8úÎ;v ÍÕÆ­ÔÂ<–ÞÒÝ÷N­,¦<¤ ‘² aýêl¾`º5`y˰b™i±!ƒDÝâM³ªHU–Hâ ³¹ S6A'¨¹°c³f=ú³0Œuò3°ê³úÄR0è =–²° a£M£ùLŠkc=èé ³h§Ø”öÜEלtæ4Ô9†22-â¾<œÏ]"iÈ0<´¯ Y0ñnŠœ™PÛߊ_“xá¼:Qåý¢#¥ºp/ôáÌ­±ª<1­’Wsì|˜©Ôf)½!ŽCë`Øj²v*óϹLä½F\B2§nȇU ÖùÁµúŠÓfÛ¶½Èêó±ƒí‘cmª Æà2-–)A¨]ÜMüÙCqVÓ‚'M™ïËò §´UXátÀmÛ!:º/ €ÒdÑ0ÍX63µr<òÊÌ%6â]ᔸGˉåäÒŸ9$ÎÑl¯u$(lCÆj£6}uWu|3¢p‚Äì·…[z˜R8²ƒ·³>Ðï$Ù†¨Ïׄk«‡dª¢á^0Ô×`±3ÝnÃÏÂj$Mºsm

X»J[§l[¿ÃŒù–~kïì)²›b`àʧÎÓÚ#ýå×xóc+:0£î~×+».{’×_aUëzç‹p+fÓ©ž ÙÎ…ó}î¯ô«dC6á:Uèµs¸F¯Òsüé=k9VÊ÷•X±àÚ¶„ee¬>ln¬òëâ ÔÎlU›šj,ÂóÃäµî·Ò»EBâ÷”‰uI惕E ‹€öBu=BßÒ¥ÝÏi¢pC“%(bœ«&ÃD>°˜Š»ïï¸%{ò%C8Ÿ6®“ßùñÒîó´yœ6~3•¤¬: "˜æùc惘ĶZ!· h/F,’ÄÃV„©n±¨™¨„µ {-À •6ƒ´t§«fe5¢ÕG BäÄIò–€Î%×1 #ó}KxôL ± ¼lGs±´ÌbHï):PkS¦øuY Ћl²Q*¬¥ÎIïlÌÇ›mÏÔ_ 5ž×“¼ÝÇ-œ˜\dÖÖ•$Jl}íCd0ˆ-LD¯àNÐ9¼é©¢±ML¹Øí&Ñd²3ÃDM¥Ž3”dæ—&§ƒw“ö_ÞŽ5Ô`‘çâTÂ{˜$Ë/twGÓ¥¤e÷¥ez>ý_“-R¥Ã’¸PZ´‹tC%á<[Eu¾oãÓç®&äÙ¨ý®Â\áá1” vÅNS3*L|ERçÚ3O,âèv8D¨èä#$µn–ÌŽ? 3ßPÜÎo3mbG¤Ã2ü±\Çýuî™|t…_ŸjMl÷{a㙡/á*ø¯Ë³¦(Ø¡æÝT*rÚ0›˜º’Ÿ,‰û¯'åèæK6èãeͤTl`sn('?UhèÁª\ÔéUxŠï÷vC¹p#ˆD#Æe9ØìÇ›æfX….º |Uõò«VÛFeN&:«dÂt&À«°KCã¦ë±€ºô5ŽÈmƒï‘‡3sõ·,o÷mk§òäE˪êB‚,´Ó²ÖjçÓ«#×ðÀæX°„kC²¼Ng)þ21×¾í7ýÑh6/I‘ÜÁÒÍQk˜X=)ÿÁ;í€Ù­ZË’}žà_ë»h¾ê“·úê×<:ˆËuw%¹>;TÖ1·‘!úªãp’lŽÇYÈÏü!Ã+Ó– j /€àÁ£M Šve abðâ‡nE,¿Ó§)ٛؾn᪠Ibή­*qCIÝØæm5!ý-dÆÆd=gùôw2ε){^ãØ§í{m—Œ›ø÷„’uûžê«NI2Ÿ,ÍŒtg½p Ëø¸Ï#G¹˜eÔTPÊèFQÍ–d+èèâU6ŠŸõ@X*kWÎ GóX,ÓÕVì„VµÃf".Bâ->3‡* ½¾51(¹L‘ägäôîBªB¤*C 5” JÌ{çÖ+ÈWVh²Ô¤c ràÃé³L$ }JŽ:§QJèfŽÅ\Zç.0Uä¥H¶i« …)V7RPR° þ1þêbŸ€4Ÿ@,Ÿ¤ )«¼}Ô‰êž4¬ÿÚ G‹^š˜ª‹œ„óå9-d#*ø ›À'jòÌçλñyBñ×P#gŸÀ§^>çýóÀC©NÖs;~tU’5ŸG¤³]ØÇ_A6˜T‡Ùày~û³PØø W&ºÏêŒY²–Š|™©ý‰Ž:VCɃª(ÀÚ¤ýgŒËäGçÐ#Ÿ ÉH£.‘ùÃW¹ü£þURï—–__Ù ò_¤SèzíâëõP– ßX9hõÃÕÅ>¥Ux7×úßZ_x[”q2¬gŠ0Æz ÏÔ 9ÞÛš¢ÇÄ»LD彊o¿&y%8Œå Ê>á)°ºÓÆ—‡“–uùFwvÆRºPØœ È0×¶ªB¦oWÔzbçxʨN ‹¸Ó'[”9Ö*Z ~æ¤ü4÷—)îJªŒöM(Èð.V[Äx¢¾m­IX ªðëjöhÌì„o ê§2ʶ¿Ì”Þµ¢Š 6”»Ø¾ÍIG±.ªžÓÿ`uÑø“0n‰Í•7lÌâ+Š#oE|àÀ÷>ÚÙ*À踡åk€&nÔ”§­È/Î0P@ÉmîZ=5L%p¿ ¢Ênèä#¼ ‚FƒNlcj* ô[³†XìGRØ“ëK‘oüL1Þgÿ²¤P»Ô¡ÃÔãHòhÖlBP0Ýö… uO­jqôãýÄ3Œ1¨|3¿w*LêŒ_T؃¸Ch­ç*£‹%ňäÄúr2OÞÆR:AN”&Ζ‡©˜·f ÍQŸy"ÉûCW&/ÜeP‘mvT?Òº}h¥1ªs=ò[[‡ËW ‰9ðšy˜y|áÍõªÓ¤î’u;,Ir/ìZm³v²v©Îx¥èÙ¡s0y€š» ›[…〲³ï?°Ìls‚Œ‹­?å]®59hûОÏü’ÍæÀþÊfNZEw\1Mj’¥©Ú,U‹wm?ªW÷PéF`lu.A}¼OâZ¶Yk£ß§“‘ÑY⮞Ï]Fì¬Ð4€Q宫Š,f»- ÕdIKÃíd°Oñ;ÿ˜9·:ŠOS™2žuEã•©u;2CÇÑLûAqÕftWsf’ˆ,å"عnZ86¯rŽB5ÆxËU6Á–ž„¥õm//Þj…^0YxF…Ër“§À½áÊPðÉhŸ`œQ a†„rž†ÞaþÈÌÚBÃåÛÑRø)'ƼNæF6÷v1Þ=-ŒbÖ®D¦'ßÿ=, éQÒ=A2®˜Qœh;ê0 ¦¡e‡¹ ¥Ð¦öÄ× öÓÖÒÓbŒÑa(§k’œŽºØ$ªSIpíGÏãÜðÑY-Ö×96…Ñ-Ħ€tÈCÐÙ$=)|‚ššÚóHdÛ7DRõÍ–•¸íábõ«rFÁÝj1‹'«!Ú´cyr)KËÀ5RS?„ñæøùs½óСØÐ¬*ÀˆüE$GV„Çb)pĠɯYá*¬…¢?îô4&f‡åîäTX(¥–¾Vv5 7mjÔØZ¦–ë'S8—¥Ëòh4~KŒþ4UŒüÑýéó*!õsœ´ÒQ!#â':üŸÒv  až6®fvƒtÁØÐ-õ°áyVw‹‡É<Ð „bÑÆ/Ì‚ÑÆ‘ÅË‹ZוڰáÇ(H+’oWûˆÕh7ù5ž•@î½ÙDà­éynà`ÉãuÇFX¡Ô·p×Õ<“V7mü¹£ 2À—ƒ'ûù½¤> MC“„¥;è¡R¬‰aÿõÓë®î.ÞÇhBñ<&ÓÕxÐr„¹UÓ9úZʳ¶bjƒ0ãV ®äüù™ìºùw¡)ª l6wÃÑ«®ÔWLq’Ç©[ì’Ã¥ôè­Ø7[°ˆ9—wÁÞ£¾wR/€ð‡ç¶x µ]»kÆÒGÒnØßñäOG/ÅUÌa!Âä2˜ïƒ7‚f™ËF0÷9Ñ;â7‚æ#§½ƒeOÉï‚f ~ãª-Ùø‚ª·ÒM¾û¥k³ïYoElãI©. F1¦[)¤/&E}²JÉV” ÌÛâvÝû_ ët˜)þ¢ò.>+ï–Kí¿îØ3Ô{%&…—dE_¿ý]W’Úàø¼˜9´}ù¬¸ªé:Æ Võ¾÷µ¸^J[•_;õBÐýÖkF½TT&•>BÕ[M›øÿ’)ÝxÿÿÿÀ àßÙÿÏÆÉö·þÿX˜˜ÿÔÿÿ§À?âÿOéO•€?UþT øS%ð§JÀŸ*ªü©ð§JÀŸ*ªü©ðÿ…JÀäYô/öÀÁÞ"ð7€€„ø ßô   a``aa`þfw?8 $$  â+ !ý–öÇé¿®ý¿PøO7öÿ¦3þú8Ð`à°`€ßuPÀ‰™Q!„Ñ •ýHÐcç rgYDâHY1T1¡kMœØz·¯TòêDɰ°/ýÕP^É‚¾ù(ÿM;à7Ú( ¨`ÄÌÊÂhàèÆ$Ž~±,ÿV1à{OKVw5厠γÅÈS? \ê ”€â€wC-uЦÈÓ=ë àóåsº«ãPE5„U®îÀù £8 R1Ð’}7çMR4ò1Ïùð×kf â=­‹÷à@ê_¤7…&×›^ïD¼¹‚“,.<qÙ¯7Ô ©Ûqú¶ä³C5À7?‘ä©Èÿyš¼?˜TüýrfÐRûí²•#å*Ûס×Ë=ãúŠ8P„ßÐMàK†Àv¸±ù"ìö¶i7ÏÁb*Ú2HÞGÿä™T :pÕ6¼ ãùXVg6…ÞQ®q‘ÀöÎtЧCm#íX‚ÜKògúVêBAÔâ/’p$šÚq&ì‘ãÒ8ø¬¨_r7‚}Ml–|ôk¯Ãöu•dl–B„þAæ/×\㛌®\&Ê[æ&s’  Ÿ‚-ÈiÕK6n³›¶wŠÊÙ…“j‹ªŽ4zÓ¶ åùÄd]áõU &P뉉ÒDð¿H[éIÈyHžs?”¯o$cWtÑs2ïtz\âä Z©mM…©…pG å²*ÑÊ[ÑàÚãælûÉñªYÑPqy³ qØ>ƒÅpå©c…”l*A w{A†Yµû`ŒpL#Uýd` ­„¾ ±ÉÑöâ ÌŠ­jk ÀVâÏ3æ6¹¹„©™×$ÈŒü$̉">Í÷Ùªî…åƒ~R b" éK4ý@€ªÒgË]¼†})”µNžI€Œ/aE³Íå0‘^Ü7âé[ã9ÝRT 4ž¬dËUnäÆlj™ÑÚ‘g’“¬Ö²|úpéRiË< ÅÏ}ÓäÁé=s&K9ñ¡Z§ÃOÂ’Y'ÌÁíR)7©Ø~öY®W¡n„™Õ6ø ¹œTÔš’£xT Uj­g#Ø9"È(àLk['‡f W(I8I²d_(E9Ô¿C ©¶²Ä° 8€õë•úXРIw$!DSýÑ›¯T”ÖA¼Õžɬl„²ìУcp ¦ž!ÔÚ¸1èHÿA@§´ÉXE¯É‚ ?.Ñeb6S^`á˜zøAƹrËàLh4óté»de% ywšS‘•ÃG¦¥I„ï Bç¯yt=ü©èõ¹€Ž¹”„çÊ K†· { Öó’?f½†ž™ðR® … !ù¬g¥å¨Ä}ˆðqªÄqêJ!xüïlåQÔ&x 0 ˜‡{YÙ†ÔBÔþ w¸JùQ• %PDIŽ89„‘ C% É„V -䉩„à`yï»üöò¡â/>sþ:¾ÑàfÛA˜ »"ºõLŸ¬Š&ðÃóÆH˜Må!ÁÃJGW¬æ ׯÈB€ó~–=¸ù½ë –dJW°\ ãpå¥lÇ~9ñ·ˆ¤¦x[ñJ‚…à ûšëRšZ4Z¢`Œd\›Ðj£èÓ‚qUÃÂ1ht[ü%Ø—íLËc´#?²2VL ŒIc.9'ø=5Å~ |ýZ:éeÏzÎÀ ¸º8þÐñnc8ìÁã¾–Uœ‹ÔVÇx”~#çd+n½—¦„—Œ$3L‚…ûËÔõ}Îz),ˆ’ÙP‘‚+ deîLÖyð$_ KôÎôGv˜Ó²šã$RxíO-ÚA:‚|ê)yZäË$EÈVË,EÈ-ër?]Ä9µ¯"׼;Æ1þˆD´ë3‘ÁE•1¡“Ö¾äâSÌÉFM< »êYš†YÛï(7Ô‡\º+èØßЪ“fëÒ–K,‡M-ŽøØo2ä9@’u#Ye©]T¶}õˆâˆgÍõ˜ µcaàyàdà`Ç)Ì%Óe1O§< jt¶hlH¹ö\p왩Rx¾<9ž/½­N}9J’Ù…DSÙåòv–ǹ¯}ù14ýxµÿë0z½ÈÓ2›¤à±J«SÑ …% D"˜P™„P@¢,Õ¼!È…Óå•*‡BEŒ±ÁÈJa¡ÄR3­Ó ¹‰¨Ö!ùpÙ&“€\ ƒDjcp¡vÄ@@d2™®YK>ˆÝ”[Sâx˜þíªQ “ƒ²ñWi6#µwš%âÏX‹BW\•\M婦ÖS’DõÍpÁýヨEýKD2âylbô;Ø85À øœÜÒMµÉÙMd¼?ßzÐê:YiÁH['Ý6õS­G;¥Ã˜àY»ùrÛþïÊ)Úføj±é4´)d¢j‡k}5Ûue9gŠhIžÇÝ¡¾TpÓØYtÞ$£·”Œ‰«ÊR‘‘÷СÉèá¡K?Qá`3MÂ’(sÝ4q$_O°ý”ëü”>±ÿËžSCÏEõó ûy8P÷•• Ù&Ñ·²)x­Åq‚âdÐIuœ¤•ÜJËÐÙ¶b{׿erE«{iD¡³6¬Õ¡àvøsY™`ø”àÅIW$¨ À«”â"@ò›ª¨ Wߟ+RØ4E¢Ä̇ â`ë­™$IàÈBo9æUÊ9‘ÙôžU{ä=ðššÊrZ 1iÙž¨f@û1\‡‘’ZF?6(Ç,³Œås"åñ‹|$ ðŸú†ÅV¬É­®?ã^Àúî9Û®j%4ˆ}K÷ÍZz©Öö•ëhîÈ«Ø`¼ö½òwä"À%›¦™/úÂì?>'.nªvÊ›PD[{šhœ :OiG´ÜÝtùÙNç<Û°Š»Œ¿]ÝàkpBT~c Š©Æ,vÛÈLwµf48Çš³k·¶3Ã0MÅÛXîtûèh"ƒÐ,¯e§9Ë¿‡úÑ– AŸ¼ìà›â }·Ñ6íì÷Üôwuwk¯~k=øÛH TÖŽg™Jdê_ dPÿÀ7S*á•ÊÃôØÌíË÷W‹Â¾_ËÙ&r¼¶’cËÁ í‡Ý ÁØrþd£9)äLæ—ߪƪ?tÎÆç(:n†Þÿn¯†”"Yl -kä s-RJÝ<Æ“²â[¢T‰ «ªVu˜ÓViJÓ¸{† â9µ™r´iý‡!ȰB‡jJÒãGÂm$“prîFn$Y­‘í½ÂO zÄßË]†V†”¤ñeôHZç13yMŽËG‘­¥ÛP<ÏKíî猡WµixR#`ˆ;ùmr´U` ±pïò91·¬"/ŠdÎ^óKs/ÍÊ.ƒ/®›ÍçK(§©1PrgB€ ½ÝöŽC¦Ý‹ ëÙOŠ2ÞëÒ äQ’[Ò–lè·U•?mšU­œuåZÜ”5¤¯Ø[£1N5£(Ñ eü£`1$,¤P²òKF¤œ¤†¬§0dÊçõÐ…Óuˆ%r?¥C¡&’ÚgI6Þ©’CÁµÃ;ËMÔFQAáà…äé¶5*RXqôƒ‡ 'UÏë$˜Ê£­)P„íËcÎI2¯Y§‚«)L×ÕÐóXI• lhòWºFÏõ­„ч˜G £õÒŠòB@(û%–Ø‘ÎûÉBŠà­¤]Â¥ñƺâ'uúõC‡`?-ñ$O Å®‰ðÃöÔ¸2,¢õ$džì Sv K›#þŽTÌ1Î9²¹³8§ôK× ¢/sµâçŲöyQ¦®­{eúÁÔ´+Z&Æ:¡¼NÙÿ8‚­aR»‹ÖÂCûrWx¢5#S¼¨œHs—!‚G[Í÷Û«2/wÉÜë÷Öë³9~¿gª/«zç›B«ïð<Í"$–ç:š–•죬«¯oª G³W¿²z¤1Ä?FöŒ£‹·îqñFØÒ²mŸx¹¬—tù^µëßJö´ù ËŠ:\æ«ëÊ'ž×ÇDŸðí½½Ñ+ÅíŒ1LÖr2üÔhƹPã Q"UÕxÅ©¸¨FˆE"`Õ‚È…ûc€iŸ•LãX¬èBàû´‰W Z™€¾D8¨•yZ\ÉW¤Q‰†9¡ƒg®\Ÿ¯•×’xÓñ¬†F1›ÙæÅ']¯—lB[ ÇYOñÀp&Móz¬kÅpíM-€±Euä~ûoƒT˜îV©ív•@Ëñ ìƒúö³*¦Œô ‹Ãà&Q%‡ ­ó®I×%¬t‡¯_<ã€|.ëli'©dºO{ÑÊT‹YZç•äKÈñEîíÍß->~<§¥]nò²‡x)Î$¯Û@Êú> Y±Sò-ñwbJdzÕµ…­íx•ý¨áŸ ØÈS}ÂBï°®º^ç„’ƒÐ¯hG‰†hj¦»h±åà@Üð9_YûN5g¨¾+»Á/zíS°Þ ÝX½·1™X EÚèæâzÅð|¯it#9^n#p-¹ |§òÓ à˜K\%ðêÐyÿ jŸŸmø¡­Å\.‰°÷× çw;ÓA/rÏS6Uxô”Ä2vè’ Ð€ }‰ffÕ^r.Ó juá4 XuH ´R%½LlIÖ왒Ó³Ø *kífW>$m36õm,ÈgEÌ–WèVôCÐqO> ýÀy ›&f8ˆæ€V­¯³›‰$óX©lTVÈZFˆÖòLF"+ŒÃÈ2£ _Î}³Ìhº(äyÃ+Œ.,1¸0d »®­!aBC~B É?ŠfôÈv×úi6j“Fc³îeš÷½3 Ÿλ˜vYû1 ¢Þ¯êÆÑ É7W lL’‚“²þp™¾í‘ÚàùTj?WÁ$DùÙ0Y‘!ÓG"‘PéžâU’ÿ¤í·s§`GÕ3›±£š'¥d ’°Ñú\Ú_«»P¢üEÊ’`¤Ê./Y¾À( Ù}2RûS|)‘çg#u^]ÎPÐt‘ÁþwGýâ2J”pܬ¹šT=çµ aJ[åätµéVQâŽç?)R}£”yÙR‚cÕ9Ì?ö\ý˜Ük,ÑþÒ½¯ê Ô>J}ŸZñMóº»õ /xa®³c”¯L` [õqxÿÞä£ðlWØ=0ÖíÉg_µ{±ý›âÆÙ|kÝЩ/xx}Õ©¾þ§±E{â ½¡-IÂBçs¼Ó}ˆe§°PD¶^Skmðu ¤”†´¥Ä¦3î=†‘ñÈ[ý)©µ+£5!D¢–GÞ­kg»O™R·õ:`ºI`Ï\ «zà“K‡ØùÎú¤.ßÄÉègzy7¡'ÉÞ¯ÕWšpÙŹt¥E‘v Ö—)-ñc†=ŸhtÕ Foø4[ H_å3'³:%|S¶Ž 6ŠXìògªþwLƒ4P7|a‰ÃˆÎ5[ÆÉ¥l9½O%¨2àN3zB8 Ônk‹¹¾í,y3Åèr–…È2(ÇgØäÂ1ºþñlCu©à`µ×Ûﶸ ©f€°¡ÄN0ªY y(‹–ßTf ¾ õ°™øVc¦ˆA`öCR‘â†gÀ:RŲÏe5 :> ÷ÍrâÅâÜ÷pùÅ›§âL wi`µªó|Ó®HtFŠ„¶\׉m&µ# ¢”ç+²æßWyùÐ}½¼ßÙ­àÒµØÊ\åõeÿ=Âbï+ظd]ùÂÉW};Ò©³¥óƒÂûIƒ¸£Ñ‚†MûÏîŽ Á¤Qê:ß¾6y¸œwK~{,*J­IíÚ—>X‹Ìûõ…ÇûÜâ**d ÂYŸ/áEßøÕªÚ[Þ[*ˆ1xu¯œ-_ZW¸GŸ2Ü_À×­¯Œ±Ín-å¤í^è­ûÔµ^áYßAg?ú,tt½§Ð,™ONj£'|&H~à)àdÞéÚébN£%§ ªOÆø,…å2c€Cæ¸]ŠsM–i¹w&}·Q,–_YëU¬„ïMeˆ°ÍÊTöè`)ÈÊÉÜ&`ÊR¿ŒÌE(c  É±‹ÇBzKû™Ï/% 5è÷1° ¯5ͶTßq“û<šÍ‡+ä9)‚.ã½¾ 'Mé7{¿Ïá[[G“j§g6#,y݈†¹Šº6p{´hoœGÁ=¡A°³D´wÚGÈ?YY"`‡è žot¾]–ˆALžw°ÜA°÷¿ß/ïëÞ¹56k¸F~Ùlqµ¸Ø¬¶‹Žo´ž\iË—$Êd+âÃܸí:eÀUT>P(wêêjñ)iist?‘:ì®ÇBíøµj{{>7ŠÛ{¼yrìkû“ë#)‚±«ôv0PÛ¡±˜ôz¾Â4×^ák*î…Þ¤ c‰Ã„ùFñÙù¥Ï'Ãø¤¯¤]&z\™”Þðι -G¡wí_ }“_U„LÝû>ôzU>¼ûy Óµš'nžXgÇ×ëë¯kÙ;ÐX‘FŒÎ’r–¥@pãHh5‹­1Õ0 °uer.«œÊ@ܨ5m\ƒ•Q ±¦ÐÚl 2:XO¯t"”?À7ΗU4s˜ deEÈY'ˆ©q\I·&ˆ›PÛw(,{omtîÐyÑ»žɮ¯Ízíxz¸GöM ÂQ\Ú rƒö?¿†üàÕQÙm½ÞÔN ºÊðU‡Ii–ºó˃‹OBR?éQË™ÝÆtÅržºyÄM¨òöØÊU·@¡Ô1C͉4§ôøëŒó mÜR€6¾Ý³ÍÃãrцpʨ´úUo~¿ñ޽Y€rLˆë¨ÚÔÊ­ú¸šºZ˜G\µ;†÷E£F7õÔ0¬nú•¦pîzûÍàó¯ŒÛçŒ~çŽ Ä rºòœ åG[H>—¸6n8}Á›ýè÷ûçÍ¡›ï¯ëóϤº5éã*‰È{‚=øÀ Üžì7‹ôÌŽCJë,Î6ÄÁŒOD×÷<¶?[6mrÖ¦o#‘Àa“ZgO„aÂò§JÈ8”eáNç^WÙÛºÝê17ÕëÆ–ðý*f ͆àÿ¨ÐÒµöžç“$ó÷¡ŸâØî:ÂÕ–cá¼XTÁ…ó¹ V³¯ËFè{Ÿ™:Ή¦þð£ÓØ‹¼Š~ï1ÿ|«9¦cƒ¸]¢->TUX5’Ñ25›æt]k aöö !öE4LÒu_ÄîñMÖÒ} аãƒDÆÍtçŠD­&LP¶ë(¾æÍr•’þÀšö»?,rƒ¬\‚M¨öblÁŽ~“ 6{d¤OspËá Óʧ„ü ´›¦ŽiäË¥…”,…²6Âp –•tTóЄ‹&ÿÆy~cš¹¬ƒK%ÆT·þI°_Þ%aéª{Ãέ§ËVÞW‹i¸)Œó+³ŽuØé½"SG7.¾ÈÞíÉÒ»uöÚ)k3ÿÀb_åœÊ€íÚfGº|ÓdÀâÆhQñ™ßàa ¼Ìšõx¿€Öõ ’üÇ:ùgLóE|R®ŽŒÉ U©õ(ÓvöIG½…½……ŸÃüV²X$~r…¬¸JSƒr¸eM{„sS·¨$“×$VÍMB©›Ù¯±UMòÕã ä×mÍÝgC™‰ŽèÆ€]=Lnk¢Œl5x»$`s”†ÜlGr‡U²k|Y“†ƒ©]º}G”õ§,ONŽÈ(Z¬ž)k]Ú¬k½Ÿ\ ¶ÌeÑïì4§‹ 22õº•§pKåq-ÇS%(Y'wî]HÌ}&/|zºü÷·êQX_óX­/P¾2Ä•¼âû”çé;ÔÖw6rÍ(Ù—¥‚ˆÜrUœohAËt"à„¤¢é/ôÈ;IB¸×¼ÊûJTÖŽ„¯4`Ó?X˜K>xƒ¼žIÐî`ôm§}0z•~ýÉò ¤?·%ã-HÍõ³Ÿ¨ýÀMºp.|ú|©"|^¯PùZ 'Ö·C=Ñt¤œGlK¯¾Þë##$ÞåÓí§ÌËœl»þï«î}©¸ð=*>ƒ—9°ZO‚ìùðÞË}‰Í[`.ŽÙ -ÖB1Ë‹Q“Æ\»îü­+|+F/€±ÚÖé Z•÷Íó°ÁOÔnfV1òã¸äPü”“Éðk­:'øtFô‹¬„<§%Æ·åâéRy ‰­Æd¿ÌÁJ'KD=«šV±íöì¶ñ×jï+HÁ+±ùZîôàëYʳ ëp½’ZÝèË¡èÏÁ9–»­¦Þ9$§pGYTÒåî&¡÷âéŵì‰çU#|d"d×'w@9§Þðµ×õ¶­ê¤ý1MV gUjc¢2!ý¸ ýE&Ãi »g]›~Fh[ðÜãëC…E &Tš˜KK((Ñ|oÆía£ïËg{U; ÷3V³MÈ ‹,4)?:m•î¹\lÙdžYÓ`³›ÍžrhEfm)\(™þ ´ØÝ½÷¾¡û±æcÓxcž§s#bf`!babâddâbdâ$bââaåæaå zoobL$þÁˆ VP–Ï èFdjcììÌOò="'  Éoä~'JOöûAÀÖÞÌÕÆœ„HP€„höø›¬953·q1&á}+)KDô×wuº¼Òà³døkzÿRÒÙÕÄÊÜÔåµ$ã[Æ×¢KâMÑÍÜÎ…ä?$ðGâo~+ûûáÿtçýÿ9ÿÛØ¿·§76uº™ÿtÿÞàwþgÿÏýÿþ;ý?fæW1ð'ÿÿàÕÿûÿã]º‚€˜³K7ý7›tà`ÐP0¿y8ú·) `p(dèÛv]H(Hp¨ß^Ïo†½ßìz+Ç¢’¨@;Ö:¡±º²Ö£cpø©Æ7ˆÔÍÍ'ˆs¾Þ  ö/DAP^I C0+;ú¡²\£±Ææön“¨Ì¢ÿÍÝÕiÒç]¯üËKD9žS\ÁƒdÙvõÊ T;qò™·§l¸dræèqF¼çKVA)CÔ„ï½Ú&%fæ±IïÖ+f,¤îWÍÚ93;„xÝ73¾óØßvù]ñDB\ì~±. çááu‡ÜÌZJqpÚ£œæ (§x1猬vHVpü~ÊFÔ`Ñã­G©ñš«Âw4ñõò©º˜çðÏè¦Ê{ ½þœ!Öð@‰¡ e;tì™! <2Qìæ¼Oáãz]s¿n]›êëCZ[œýóˆCo`‘ÃýÑÄy–<yÒn®ÏYé‡äù²açxåÄ÷‡(!èI~&4Cˆq-·evÔ•L†ó9/§½' Oæ[ŸHÐÇOæˆiyÔd Ù;^«—ªà¼BÏ´’e#”ÉRýîr1ÂøØýucýˆÞœþƒÆŽï©ñðVÑ_4wd>öí9å]œÍz­qlv0ˆÎÍQIÄ«ŠÔ$§Çlf©es¶OßÉ¥½ÎÜSÒOõÌSÍì1v¢£Î ,ò«ß“°lýk°+Ší³Qžák»g©o˜°¡”-§=ŠÛ™;` ÅÃÁö€æZF5›à¹nXPúÂoÉNÅ Q´-´Ê²Ÿi-.õwÛ/_ñû)[Ú°Øà{0Œgƒ_´Ÿü9LQiÇ$¯Ìt’6%œhƒaÄßé6D&vgqíMu<óÒ%éñ2Q©1le×éúñŽ(ñ;K–pD(Ω‡Ñ ï_$äã×ö“{Ú ­E@›Ìòrj59À7O|.jÊwî‹T§°Àmÿ/ò¸¦„ý8®n<xŒØUÔª&¢ÈÏÈÖõ ûx§ÒNqÂ…;S…“Y_nŸÍ>a+ƒ„‚2 ‘ ªA™~,㪺”ý ÷_sµýq£’­æø ÑñcÖì½ÇþªFcC³+˜[«·åàî˜ÌîŠ÷Gsâ°7¸{ &éŠf5°„:2p?š§e’Ûí–“Ao;á6i Î{–R9ôˆ 2(\" û%ôÌ"’ËÎ|2Ž‚,hNC»"­¦3gêf书~ZJêîëÚÑ­õŠÓ—êÅ($Vσw©§oŽÂ.oÓ×zµÖ,ì9žlNÿ!Šª»*ÏR‚:ñN ¾ÇÖnjƒù¨¬bžk›•.\3›[ÉêûwNû8Á“QÉ'  ãMѳò­÷Ç÷ñë“]Êï­ÙB4x£æ»²¯ ¸@%á­ÉçÈqÒ9n¤×zIS ̹ýbÍ×h©Úe—jÛž.\ùè×ÄQò£gV¤ÎkûÛ‡ñé1Ùt"¾Åêv”eïDïW+n˜e´†]œ°â·=Ø ‘@Ã’1›ãY]^T£CROÈd»K¢à¹d] P @Ö±CGˆ§7]j0 žðùðhõ5V}B€ޔ땫,Í1·…#áM¶•ëĘÃpá™ÅùTzù¬ÙXIÉf¹à+*˜h„W„ѱÃ*«>B¥õ» ç%2VP˜¼ò¥‰¤s†=†®‘«òƒÈ8onæÛ”>'Ö¯Sû‰ÝOZ…ÛÚ›–‡½;‡Ûø¬ÄÅh\Ó¿¨ÒzÌ?à…ymëÜXUõ«ðëC¹¾‹g—ăÕ}–ëÔiƒ5°‚]ïrŠUœv{… …Éâlû´ÒuV7â¨ìgºdò;Ýzëöu›iCó{3:²gXn°iÇ ™º³ Ë[²ߪù?í%­wüPª·ò Üo £" ƒ&Õ2sð¥)+éU©ÐÆl(”aK ‡BB5lPáQèôÆWZö…"¥üºº]ì&)OñTÃrt(Y™£ï ÀÅ~„f!¦lLQù&Ø’B–<ðÆW3&µ³¦Âµ3¦Â£¯Ä$Åÿ†`ÿɘÇþÞ÷?;ó.ôn@g ‹¹Ù×ðß]ÿÿæÿ““‰™•å-ËëáÏïÿÿø¾ÿ½áÈ¿}ÿgô¹z=@šÈJŠ^Þþr:‹ãqÿ ú-HŒZ¿-…ÿp÷{÷ò"Æðô4ÖûÂé6yÿrx¸üñòòò¾Òî"ëñå¹_ö·Ù»'j¼Ügô^sØÞ„—2†‰jÁ®á@)ÍôˆXIËâgtæ·áÑÙâ’CR‘eldd´µ‡5ˆl7ÓdŠž°,ŠÒÑ‘½ý­Úþ…YNÍ]^BùiwÞ~С†z(DäòÖšù •IîòQ˜ã{kN$¼ÿ—ÁEQxš¨Zx}Fß‹×ÔÕ[cü?øñ?çKsc3s'z“ÿãß?àÍÿ¯}ÌÊñ7þ¿™™Yÿüþ÷O¿ñÿ+õÆÒ¿yé‚|]¸CÂ@CA¿®Üá0‘àáðÐ11‰HHˆ ɨØèÈ(˜) éùé™Ù9yxxHiŹDÙ¸y8óÒ ‹€‹„„ËINHÎù_†ßø® ü` $ÿºÀ'|]bC€ümÛ?tm¡a`á^34¾-çÁ~Óº…Mõúc9ÿæ¦ MÙŠÄÅ/6šT¤¶Ceö’ŒÕÄÉ —œ‚’Šš†ƒ“‹›GTL\BRJZFUM]CSK[ÇÔÌÜâ½%ÐÊÙÅÕÍýÃG€ÏAÁ!¡aqñ ‰IÉ)©iyù…EÅ%¥euõ MÍ-­m}ýƒCÃ#£csó ‹KË+«kÛ;»{û‡GÇ'W×ßÜÜþ¼»x«×¿èÿkÍþ¦^(oŸ)ÀÁÁÀ¡Þêêþ–‚˜UXÊØ„Å]$6·¶†”UåÃÄi“Œm›üê­j¿Õ쫘ÿ«f©Ø¿Öëß|ñ¸ÅåÎgŸ1âñ“ŸdŠü¤ÓäfÀ"ÑS &¿]³‘ÿý$..Ì}8”b‰GfžVi)«Ih‹(Åž{ŽršÍz¦"nJ91™×ª> ç§$Ó³H™øÓµ8h7­PaÈ{¶6^p2 yÁ® c®”«’>7ó† îÊ&»\ÉÃ<¨¢!Ò¹2Ãrüe‘K‡q\'Ý^È«§Y×tPJ,¤Éu¡2ÈÑ7ᾋ“£š`î[\ÓŒ".ñõP^G¤õ]mÒÀ2¼EZ«©ü:Ì ¡b]H¾©oÞ#w¡7ŸÇ5Äb-ž›µ‹ŒY*¤Üótt☡úé»Ô'Tuçù´ ´Æ®DíHôP£Çƒ¬ÃëI–Tyi¢ûZÑ k>‹‚fa²±ÊùN¦›îrLëd2×ÞBÊœFÒ–ðñÔ—syã&¬Ÿ=åî–ŽxY0Øì*»!èrús42“‰¸q sC$a|óÀ¾xpníÿN Ž¤à‡xyÃ.i“{wX…ejƒmÊJª•Ý4€²¸TL»ÛNy[É8þ7É‚.M« ð©ªg5L‰“M! G`Nš ‚´<…%[B‹%Ù¬p¨ELšŽ ÀMž"cXTN6ïJÂ]ÍgKÍg‡€Kc•NãΘÄ)8¸YNrDÌ€ÕK[óÓz³i2¬Bˆ iæàWâ¾*@V¥Ž”¢‚Ö²}ʔڈ…Ëae!VMeZj^ÜA=wXšŠÉv’ÂÔ»ž²Ã¨†¼¶0Å\ÑàA© ü»¸,ÈYÝÎ̽àBE>¥3©­+‘ˆ0Ôšõvã¤R,?) B a²lo¶uTÅ\í„vT*æØ¥†íùÛèÌ2ûº!ÙŠX«ˆÔðsáÇÆbþsæ´ÉX7Guj4.® ‰F2ÑCôœR5£Å:öþ§”Š_÷lÃìHD”nü)5E ¶­½ƒüšìÆp¶õö œ¶þËÔ4q_Í/sLÒªxa¥¡)Òýgá÷2æÞ§é/¥GßXäøtªf‘°ëOOЉ“,æÜkͯ˜Íšu·Q~) ×n.ÍÓA†àH´Xß‹’$”ÀÂÿYŒæÐSpƒ;N¸ íå$¯Üï r¬2Ή§Q–Ö"1  ‰ *(¬„&£:•¡f'|èÕŒu‚æGP~¶¬Ÿ|¯4AmÊÜÜ(mÀ›^¨•&È̺¡ŠâV‚Á·,º_OÎx<—"Í+ªjR…“† \‰”`+©r@ÄÑ}eDØæ…ìæ^ƒ(®-×¼%˜F˜ ,j˜Uažï_#2Q9Ó°%l³ô‰û|³ IVxé Õ:Â=ìy;©›L¼M³Rù–%úu‹ãí<ÞèàÜìpY\‘+ ä©¿8Š bù*zÙv*6>°³²–›¬„@€kÖÐ(–&59u+GWjEco|MÔ£ƒ`.,8‘N£¡†—ÕJ8´Sì”éd¢ÁLÊeuVµøÉ¦$Õ0‡¤Y𳬒žiT-GãóÙ¯¢ÒM@?Ûõ zdÆR­†;ª¥:«ŸR‡ Šd˜ uK9æloz³Œü POë…–ø=U¤·£ ":,épê´Lx²±6h ÷ÆPåæX'f)n›µˆ¿<9‚+^Vê8+¿ÈÇÂÞ| %Àl)”ÌâbHYCcµ6UÀðP6D@ü èœ{]»ÞáB„Ó[RWþ ÃX/ßìU¤“®ts [Rß=YvB@Z3èyØRÙi ³&ɾðM!Ç™½ãJ!¾Êœ†x°á»Ðwc'?ùY»¯P”yÀLUÄ\ta.LQÇ)bib ä{X„šŸ·U³Öä‰=B:Ê UÎ:+ºIf³ÐÛ—…€°lzƒï{UI0\`CQ\J§°ÐÊVùwq¬™Æ®†NŽÞ’P–xe;œ¼%U©F>ú•t"ª9ÛÓ•Ré µÕÔPI²+©´ë<ܼ2UlAÉêq`i`Ù‚Èn¸ªtš„U…¬ihQüë¤mQK= Ȇ+cÖ>/3§J\CÏÖ°f«#ãÆÄ*—4ô³¸ZY9J^ªE”e#ËŽt´LŠ•^§Õ±¶°1ÕŸ´_±¥ SÔÏŽÆm—@†(jÁmGÃ7IRÊž·2yÒƒ }A3¶^ê;bþ.;Â9¸p"Ø‚Œºåû\%R‚1:¬ u#PkÉv3ÃŒ9ôfRb Í%(oREÄÆqë„”‚ðhIh™³8¨/l*¼çg%? ˱_Qšãñ$ñA=Z%9õH{6A ˆ E "²z¨ïèp¥zë.h^<=ì¼4ê¾&zƒš †Éì­E7œA}J–y¹TlE13 &1ss¸[ª¼øBøš”<[#/Ä EŠ"fQ|š2®¨¤‡¨`¤ÓƒeVD7©ouà Sj¸¤îêÑIhÄÛÊ7E6蹑¬K7¿†ðÀ¦9?›œJÚ„˜1kv¾Ò"–4ËÈ´yZXcö<¡´WV˜CS‹¥¾Î¨¨WÒÃ%€ôâ‚B¶„6\tÔ¡9ÕÛxùorIgÜX ¶2Zó Zf ²¥ôGRPV5ƒìY© ò£ø úÔZÙèÔ»a…y ™«89f A*ÂçòC¼¾TßÞ-øg@Èb¯bûE\ÉM±†¹§íí”ÚP¶: ¶PãÏÔœµ+'¡3¾Ë±UÊóóŸŠY ô°òw³òÍ‹˜5¦ª=.EªÔáÄį¨ÏqU”ñË×$¤æÕSÉ „QÄ¥À{7*líŸì¾“WJØ­$zÏëPæpªƒ“/±a !ã±àðÜ«¢Éºq¬ m™³“Þ¢‚½+-ǯ ßpF´ ,(²c»w2Yè»y®h¢×LçeúRå…A#Ð0SS¿ö„S̬¸™%Ué ,U©9ñ z º²Š’-º-º²8‘ò«4#È祩)‹ÃDø‹aó©sœŠct€ÍáRU˜àÊPI54( õ½R §ä…Á˜A®rç…I‰Ðà|´³Ì+ã»Å¦Í +&VÜ0UÑüÿ±÷ü1rTçm[G Æ>ˆk yÆ„½ƒ»Ù_·{çu!¶ñlŠœmL£þ8ÞμÝ<;³Ì›½ó†  D±5í? E-8(iÔ ´´´R«¨Qõ‡Ò&M“¦ª‰6Q¤jiU!µé÷}ï½Ùٽݻ3˜KÃÝÞÌ›ï}ïûý}ï›ÙócŸ}µöÈá/þû‡Òo¦ž»øléüØsµ§øœ<¸áÂüì}þµo|>óÊè™Ã_}zø;ßz%ûÍ+Ïß~è®;œÿñ©ùÓOˆ¿¹n§}æã£gvü÷Çÿþß}ò×ÜÏ¿2zúÉìÑ©ù{¶¼ð“».~ç™±ï™ÏÞûÒ|å}¬üBnúåÑ3×Hÿ±ÊÜo|é÷_½÷…Ÿ*;ß=?öü#óß>?>42?;úc[aå|vôDæ…©ùÃå“`Î?úvמÇþX¹ÿç­÷þâ±JÿO&;5ÝÙÿ“†ƒúßz=êÿàÿnÀn–ÂÿÕà×&êÿýá?ýÅþ þÜ€­¾Cûÿá[øc;ýŸµïß9üÉûGŸ|t÷ÐÐ/mxús_Á „÷bEýuô×µ¬6 ¹/<ÄžÞfèé½.Žû\ã àjPg¡h®ÀFΞZP«B£ÎÙö³fGA£T^ò\ÿ,sëÕ Ö>§·ÞñôÚæU»‰9{ÍDÏó­& ï ²“Ò–ù W"×Jõr/ùÁdbš¦g)žÛC–²mYªTfìL¦8!¾>_ô\­ (_Ü»Ù,·M0@¯såú¤và;ÉÓ«a_é?©…d&¦"P î8®_-± èÊÃÿ´üšÐЭœ¨ïc æss¬̘`RVñ".¼` õ˜j¾˜ŒoZÃ-À€ýeêiÆÉ f ¤µ‚æÜçžuÂqyJ²“§ïa„¿[oxàiüˆÓW ³.ö³=ÁÃ’Òã‡õ¤Yb•½Ò} £õ á;1.dž–Ñ  ñer‰t'T¼V*¦Ñ¥@Æ"£©X”øAÌl/ÍǬ¶Xú¤f~YÛKK©q/dA2ÈúkÅUOh k‡Œåºä¾—´!å´ÝèDi¿æ",í™››;0G²Ÿ˜*d2Ðbè”^’Ý +fŒøvˆc.—ù@?0Z¥ºõ ÃV0½Á¬*êQèâaƒ8Y:¨Þ¹4í´Ôêúc`¸¾6Dü•qè?MO6ö™¥múW›l¹€‡ºœ2’^áâŽ`–y’¦{\ÛyÃ:ˆ5UOYôü«å{HU>cH_P ¸’GraÊIõÌÏZ–¬×Ôpí¨*¶i«Ô^v¼…ãr³{ñGÎHþªèi€kC0žÝK4w§ùÉuØ$¥&™®;W\xA¦]³…­‚&Šé\æ4i$ý«-3Ñy/§ì¹Æ^(˜ éraÑÕÿx‰Ø´µíràÒ¥käŠÅþ¬iÿXU"n-ò× ‡þ¼ysh,ãÍ¥¡Ó9o™K°–Å> §£Ú*1!ÇËœYb„ã8lLÛwkl{L7 D%~bôGCéa  `ÿh¤ëÛÛ!= èòˆ¾pÞ‰QŽÌ7zÎ\f-|P( {×ÄÌR¬ˆ¡¢ã.N@»2‚Ò‹ÃRŒå0þЇƒ ^ÊöŒÛ’wö çW“>¹ïiĈ®´cƒf§‰­šÿ¯òüçò,öMÔV©ÿäàjWÿw®0èÿ\Ÿ£«ÿS=ÿ‰ýŸWlÚ„ÿ᳜ÃW o¾jóæ+¯Ü|õÈÈ–«¶]}íµÛ®ÞvÍöÑ]×oß±sÇ5Û®ÿûvÞpÃM7Ýtíõìæ÷ßxó®oº‘ú?‡‡‡7_¹yëæÍ[oܾmû—|èþÏ®úÌØÆÏËïïùÃSOüóo£2~aêâ®Ý[oßøç›œÝ/ú¯ƒWe?óâÓwþÂpññ½>ü“y²öÜÈþÅ Oý˱=/ýé‡~åSû¿öDí±©Ï^uËÖ ÿõŽW·Lüɧ~ïУ£ßÞ•úêì¿xàÈÅGnÿæ¿´ïå™§¾4@ÿíAÿË»¦†ùÊ¯ïø»->2ÿ™<ö±ßýÇÃ>]ªýê±ælñÙ¼þúèÈ?zmÿu_ùßüÏGoyêŸþ­}°ÏûÞ=ŒÿÇ Z¦ßž9h“§ÐÿŽ¡l6[ÈæóÙâtn(“ͳ¹!Vx{Ðé<Þãþ¿“ÿÜóÞ¸tþOå‹þ¯Ë±œÿ'g::kEêë¨/DZÚóŸ…"¾ÿ±€Á1Ÿ›þ3ÅAÿǺæÍOm®Óæo7‹él.˳l¡”/” Yæ„®ú½O#§k®ÔÛ¾dŸ²4=‡•kJá@ÆÏ~ïµ,ù^À8Ç}‡Ù@ï ÎÔ«äžR©'[ª¹vA:ϰôøä‘‘dZŒ¦[rᜠ–X+hˆ‘z7.]¯Åš ``‡H¤ \©¸žºYHa&e‰IÖ#€5aëàweËfÙ, —kÃ|p¡ÇÍ\²J€ÈÈÒÈcm2«KžS÷¬ž¯óÑ©ÿŽúöòËìHÇ×`ÿóù\¡Hú_ÈÁåý_‡£7ÿõoKŠ(rýª|k¯\Ùþç²y|þüËåŠXÿÉæòƒ÷­ËÑùþ¿^|'0c嬬nšIgó,S,rø*ÀŸ¾í¶vÛf?hSŒÂ5)Âv+® †Ù¯¸Õf¨:p¨cqø‘£'ŽŸ<}àØivìøéÙž"³cX·X/ p1Œ´Àª2 w&Œ¹…fÙÌèúÀVÏ£)L# ª!¯[ìH…ÍÀ§qú´W ø AÀûî O|º•јr›-VquA„p…¾jµ•Ú ÐaÍD'²9Š`¤Spß¹®Ôk<^3÷d{ü[ÊÀv¹ÚI C®Ìne™pH#ë`«b#)TwŸÂ©éG®§lò’+‰î¡x° âÙ¶ ÒX¨~#P½ùv¥]B’Q•ØµŠÆ pÌNþV[îU­ŸZàI¸QZ´¤*޲¶DQ)±2õ Ü/öQùh©.(Ã"÷š@Ûƒí(%κNŒQ½-€ŸLÀ°&­Ž{ ˆ;šuB,„Ž ¼ŒÂtÕx1³xŠ7BôS¬;`ê €0ÁD”‰z#R~ÖJYm©¡@©ƒ\D(Ù™ "'ÈÄ)!HmO\¿ƒ¥ê W ©}íI ÊQT†Ä qe¢„}”f!]Qù»‹Ò";wàžS³Tˆc§OÞKŸ G ÅìÊb(9ª *µö2 ór:« A¸IÚÉVÛÓӜ؂¢P lv+¦*â,TB!ÀÐfÑA#ØcƹŒ[ËY"ÎAf悃G„!AkÇ«ê."Ÿê¨Æ’4݉hÆót‘’ééÆ,³¬Àª?n\AFicƒP`­ý¤#é4ë*ÛBç½Ä}ŠŸ@m BigUðã¾Æž å)¡0²j‘¦œN»0•%»§ Ab>mü¤± ¨ F©ᬎr±w4ÖßÕ‡–fคñ:Ðï{‡ì3Eò>’ãT%ª(+EQŽ{Ë\J¤üÚgx¡êÏh)#’ X¥Bí=k# „‹ivìx× »c¡…øzYŽa 0m Ãôäu’ßF¾¢Œù§ëÛ^“„ %Âð£…Ñ•²äŠDˆqY£DaMàXnuàêØ8 l»Êñ *­œÀŒx¿ØÍöƒ&±B°Q–/¢tŸ€xvþÆçdŒ°Gös0^ÁY¦“Ž.9ŒÌbq;Ó/.¥>É…«¸]µ2­/€ç… ßaäÁõž²¸L÷;͆‡•s#&"œt…/Àa"mc mR<¬ÂÈÐÈZA3j4£Ô„ò··‹÷¥À¯Æ£ë¼êÚ ôü›\ÐkУ3}ÇÉÊÖ9NÇ–ÍÁØ.€Õ‚PÌQ!µÿ`Ï­ƒ Õè>‘ê9˜ââèŠ0È*È=AWí…:?—¼Ôj »ã4TÔ¸°€1ó‚BH Ù~㨠tAºŽ‚Ú19hâB(¨úZ¯JCW˜'Ž“c¥Ü2höl Ó«ÂÀhŒ6ÁÜ»µ0=/Sh©LM€"3SÆP•8ÿa¾PibNÖ—îˆKdiâ¬N{Ðf×§A‹P?$Γ¨¤&²U—´";*þ¨´£~r—HÄØê•q\€N¬x í¾t85Ì•µC½5ù!\r)«T%-×8v( ƒ†:…ž^ªÂ‚òGà ‘Q š'ŠB°a0Y´„¥]r~˜db MÓ%6±ZF5AÁÎvúÃÒ3¦€åÌ’”¤-5çÚ¹ ,šÊØÚ §LŠ›ÒYr™Â¢¿¶DŠÜÊþ C6 žø©(޼T=#Áñ9 ½“éRØA>ˆ½+¡XP\ĸ”*¦` Æ™kû®l{²˜™,BD©N'd}]•f;WK hÁ(]à0TìÀ>=¢ßvÁ³(¡@šlÐ5QZÜÍ–’EÖ•sEaƒtrí˜ñv±‡»Âíx·àä ÁÙtˆáËjsA‹Ž_i§j{(Ïv.P¤OYÒÑVRÏ Y¢A´s»§t”й¾/<Ï5C8ØÔVäU]>ƒÏ$`èâdÁ_–¡.Ê’, P¥2I*×àU##¼ÞŠvÆu½Úظö•ér ÆÔBJŠjaЬªêL!q' ÉQ4}ÝFî4É£¡ ÃkqQõòÜhîÛ`–q)LèU±Âↇ›ó$×Ú/SìZæ¡Q¸;0Àè~K‡h˜œÑ3оDKé VZ¶$ÀM'æ$êéﯢzÉkIÑÓH¾èÄ ÜÂ%vd`T“Q­.¶=¬ç»ÄA3< ðàž@)ε(OjDèIÊ$î@B¥L&ºöuF•À‘ê•nùJÄí $ä !†KAEmö€(¹°A\0ùhQ½xŽM;š‡ü÷JŒ•ûéɹ \â¡#üÄÔãØª˜ÒçÅ]X'ÒñºÀlÍ•u’c`ø®J §U¨¥$.ɸnIi¡’nèÄÀQ,bi]6±D²S6!(SU̸{cÒ/¿A¡@îéÇÅ^á×KªòviëR&,g;FÌÃHTR'Æã.#É¥1gjG‰2@ ¦}mÿõfúß[”a‚4û€F’¼<1´WŽé/…*,˜N7)&:¥¡Ý\£lšƒN–Œ° ÊgÚ’‘dº‹-, t=Äy…OJÆÑ Фý>- 4.’’Y0®­£CôöhÃØ}ÌMÔ7|SÒçe;V1ŠGj§s¬®qÆkÈ£] 7±úA¤†ðÝ0ð å~tÒFQW+œ„w¨&é/–VÓ\]²DáiÓYÙRa MÍ1ЬWw¸ªüØ©·è;½³¡gQÛÔç\lXšsÕTN2Bp'v¹z“ƒXQé \;I–£Cpð"êRìÃ'”œéUèò=&‡X¨sK¢¬Qyq€Ö– h{mÇÍ~€ª¼k£¥v»TˆãµŒµÐ»ÆD§Ä<²S`ZÁŽõbùBÌûo½kUi0î>ç>çÞûÜ›ÝK5תUk®Òˆ$’ K¡;²‹l÷2ÄWºñHbI"ñk{G†EÖö÷ž={È—Ö¦>µ—ï÷ ‹þ2u+©È²BóÇÖ6jk~ÕðªMßoz cm£º±aX‡!é”~@Ò5ŠÙ"èühµúf%™˜uKK\ÖÄ ®sáÄÎÔ¾ƒ4½kßNcÒ°èéq¸]*5c‹#›öFs«»Ú¶]¶¬nÐýWh?©Ô¶Eœt!,?#ÍæÙ8Š­nÙß²›]w>–\«R·íE«ß³VJ%wó͵ÖúëŽäÛöíÕm`«»¶fOÛôkŸíîI’à¹u´ÓáÅzx%ô°¨V§TF‡e~tJ§%Ûá-Õåda•¬WÔÏkã*ð:nõÀ© ÃÓo­×Æ®$ñkðÊ Ž}»gøO]×k¸µsNYPÁË`ýöOY-79>žÙå'vû''~Kþø§…ÑÛ¿­;uŸÊ¹í?šÿ<>n»”½îx~ Í»nµÜÖΛ¯¬EA”$‡­—Väzuû¶ÑÞ8 ¢VÃ}x­=£±xiyçF¦_11þnpéú»VdS•îêªÕm{î•­ÅK~±#ôqfµñrB]´ÞRµ08t먜 fˆÒ¡ëÿX 8iÏØµl×ÿŽvñÚ‹(hŸ,o ¼vT½¾´hèŸëÚm’ߨ6ý†Ù4«óDi¸õoTÖPváÔ®š&ï[ÓÙ|ÙÄZ È›…ó¦¹áT&”") Ïßæj »Ùh‡' Çߣ܎ͳÀXZ¡[ ê#\8õoRÛhù¯ëM\ïÊj8!cá¼o¦«ºë¾GÔ©õ³v×mêvßꬮvÜÚÕv‡V¢ÙqTÐ{C»\‹ GA°w½ïAP«Ûǃ&x`ñVWwÛ$1½7$8]¬@Ü.Zád.0ñ÷„Ž}ûö£Õ5¼‘ÙÅ7Vg»á~n6h{ÓkŸÆ‰ NÇéSö9ň^=«Ç%ÿ츔$üèý~\²WW+ãñ†Ò˜xÐ0ÝôCMLeÒŒW•À¬n™4ã•à&àVŸT~X–Ì]ÿ'a¨íÖ^P=»h™f €¤y6,%CÕ­Ìùå%=zõ•`ÓËe|vß<ÙX8£¬éÊ B+³bKÄé”™²ò ½¬%h«¾E6ý“ñ)ºn½êÔ+Ä´¯Fo^Íñ?Óï;°Î5ÿ³ , º¸g|âUíþç혘ßã§²×ôjî›Vÿ±ßkõËe!õ^˜¹³ÿž\56Gn8wýk7mëž6©Ä5ô?SV½B\ˆæ° j_¯w-!j×Äÿ¼±µ~|<]?uèÊxþB/pußî” žÇ¥VF–4QõGuA²ºº^{—Ôöyw6Üw6axõu`É2Rg´’O‚ 'Tª’62†¯ñ×]ËÜúhb•¤sjéK¾Ñ°Ð¨7•›7ÚJH+EÛ´J,•¦ò‚Fþ›"gxl3Pª¯šŸˆÙ§Ì8Ðèd¨QûNO®ïYHßjò¦e”™Y}§_ö€f³”ÜŽŠP™‰àmýÁÒFÔÔ¯¸ÿ˜‚šuÓi›ƒˆRâ¾–Ú-Zõ@Y’GHÒ ðg›1˜š&Э#‚à­[{F`ý)ùesÅtÚ!MžÅ±n {X®è$–£t·ß ,Ô"Š«è¡÷žZ½\nÕéœèÅj†Q3[èÜaxn¥Ã²g¡ìS§çœQ缯hHO<§r]Àŕʵ}[¹AóLç'¦qfW®Ý­1-QJbÑ/­¶øç¨ìÿä$Â}¯KH d¹r$fµ pÈ{¦~¥öÌ!5æxC-Gæ·¼!1>Ó›®Wçf+•ÁlJö¦AHà¤'Úh‡ê‰Q·:½¡ÓTŠ·½ò;ß´Â ù ªÑ7ןZv@R7~ (ßh•˜2v™ÊÜÒþ¢uêlצÍ.K]Ø3Øò”Ëõ7à©,zßDœâ_ÁÁŽ,´JkG'„Æ{F´%4CEʺ¿ê±£äOîáÖÿdè:'´-ˆD´X ÓE¼¯fÇf’H"íâí­÷ õÐÞÂû éš_m`ãõÜ^d.DÏŒ 2é¤Ý¹A»3r1×.j¾vðÑŠEéãíE2d -‘¶ËÑuµë²|Ú…µu!mÅ~ m"ˆNÔ0#*h]Ÿ€G þÐB^¹LûòJD‹Ú—u'U´N ´~BV·¸2«o‚ôZVW»µBì†úK`}doâû_M¬–÷¢yË’$¯9ÔG…>Bš•×m"슮v…V ‚¼p+GHyAy6~Ë¿n›†IŒÖ.‡,_xºñ´::+bR yïÅþx7ë>Dýqë3‹Z¶©iB²£l°¼: °/H¢‚´rÍA#",¨³ŽE …ƒJþ‘h·1ã³û™~ZòCè,¬v¾¬ÊF ¥ûG´¶ŒJ1`}f& ¼ßÙ4Ôq*_ƒÛÊFÓ¬]›Ní”XÐKÓñ6›feS©ªÖv۬ŦcÖ/Ì“&=¿ÄsßM»BûCrí")¿f¼24AZ¶\öÜê)ÖãLÁêøx F[+5v„­Ù°OSq}’ðÃó°õ?Ž£²åµ·[ïƒÊÅ6Ø=¥®Ë:8§÷vœzÚ¨×è±¥~¹M¼#?ˆ±Oh}Ýð€é¤¤ž§…ëu㘇3Âës†¶/hmZgÁ™XI9#¶Ïö?ÿ¸dSÛëÎØ|w–šïxÓ˜À29_‰X‘Œ´Æ)³hnŽ ä©‹q›mÝÛöññú†YG˜))ŒXᛤÚKÏ“ðeR=J;Iø4©Œ’ðgÞ$ᛀfowšÄž<^7Ë]ú5ÙšÓ1'„u¼ÁYf]é±åéqx E¢í9æcÇh\ѸWÇ¥'Dïû;OL˜ÃuÙiZ¶ñCJà——”üØ ¿'¾Ÿ„Ã$¼H¾½®Ë{GR¿¹¡µP _J<ö}Õ¯ÿ$-j¥½÷L;7–ˆ(U­dU©5©N¿Å6t¥Æóåî¤\㻚Í÷¬NjšÀø½=5cOfÜÞpLz'*ïý „¸ )ŒQ9nû'°¥Æ„*kk6Á²kG9¡‘©‚¨qêêÙãmªà‘|Ï?neÞDË„A Â{ÊR Â`°¹óàÛ¾uþ„ööÚÚ¹-êÛiûœôCT "…ªBŠ1?‰¢„GP1ì»ÙºÈ6šÞ²Î ÒF²º”ùh22ð‰í­‘Ø8x`8$œ‘”´±º Öð |ªò™»Uol‘Ç €sZ0I¨§š}[OVu°eì‚6/”ó "•º+ûŽëÀÚ¨6m˜ÇÙDÙNu#è²ìx=msjõ‚˜-h_Û=`°X¥Îe}Ök’j”|f`ô›6ñ͹ˆçE^½Š,‰>¾UuQã)J:M°ÊKZvcb¾3ŠzÇ¥¹±õÙØúd¶"FÐ]Èš¥‹ÜFl…ÄHyr°2¢0TÏ÷Šž¨4¸7±ÒÈ%fºudÂSÂc‰Ü­ĨL¢ØûgªvJòH•ÆéøvSžc"~Ä6<¿y¦:è ý×£I? <è÷Ï`ÆóÌ×è[í?ì“GÇÇö:Lqe«ƒvÄšÙÚ'ÎNBf£gy7çQƒH—Í&;4ÅðyÎŽ|˜Á¶-’z$•pR¥¢,pέ7BiÒe؆±fµÃµŸ”¹õêF$ a`k@:• ¥IZa6à{nÉòoÊ®èøQæâjŸˆjõ ¯}Ø„é½O°c£þGü­îñó… )]¤'>µúô¶¶F̼öÊ._KÅbI…ž²íTsçÜ?:´ÆýÖÉÅŽÿQ{á¤Æ‘ãr¥¥¡ÞŽÐ ©;ÔÆ‘v#µýCJ Ž<ž´Dš.~¤êT`YBÌ’7éo÷‘é]6§õ™–¬øcÒ IMÄOpÐêbSsæb¡t¿.;ïH7¯àÎcjæb­ ؉°y–{Áf|ê~.Õ÷tê›,µ­-È"ÄšÅpèsQ_-=lZ,w‘näÀ©íNá¦Ú…‹Þô˜™á¿p_˜ îBÙÌ]•TÓÀZUÅLm<‘F`†€Æã—c,XhVÁp ®Ð\Xm³þ¤cž°øßbÒMéBôN;DÊél§jì¡ëuÛfmN¼O˘>i§^‡g’˜mO.þ,+ž¯Ü”¶·E}—¿R zƒŽÔ•¢3¹~?W@^l»©ýHî ÷T|&[|Ic¯ò˜n‡M±D1T^~MsÙõ¤ÊTìâ:qˆ®m°âµñ,HçÌ¥è¹öÔ~¼ùjÛ$ JÔ’£G•áÚIr¬þ¹6aKšw|¼ùbþ<¿SÈ©ïþS£úÃ2ÿx‚´Ù#Ë,?+›e’/œúë4S§Zÿ´óö²íº'Û*óe*"ZEÄÒd¶Ûw†˜î¤}ZªG¦ˆ±¡ƒÂhóŸ…b!„+Óÿ3JP¦Ù¼ÝÜÍê?¶+'k´užÒŸèôJXì©AÐWN¼û2*ãfê‘#ÑmꢈwãÔ)”¢‚»¹²ÿò¹týY!Æ]¯U/Í<±gãù#¶ÄЩÈa¾ˆPs”«9žÐh)·ù3Wn¥P.¥ý¾r­¶3——÷Í›ÜÌ-íÚ¼F„Fh#8ÆVÝ™¸@¢¤VÎU+°è­‰|Çbý)ó©Mӆ⅙¥ÕN9 “þñ2Wfûw¼Óº×ÍÒP7Pu7¯²ÑW>Òb|Ìf‡÷êëì½úšcnöþnó ó¿/i葌d*#Y8µw:­ö.MÛOÓöÓ´Iš6ÑiÍÍʇ´Ü8-7ÖiõVßIÓ~¦i?uš?Óiþ,ƒ3XJ€ÿF‡+¬W'©ß$þL¬@¡ûÍVÖâ¯9¤‹'ã‚æ\W?ƒ¹(Wos–þgˆæxç(g5¹Ž{´@°-_7ÛëXÇÇmÛxôïmHkWk$­¬öÊ£ßþø¯€4 z9.m›D\6ÖT RoN֪شÓ*¤ù˜ÛT…¨Aüdo·ÿ°`ãá<ÖŠ2*ÓtÿIÍg4èÄ©œò„»*2Îñæašµº®LH¡²î0—DÉVHzÏe£–M8~ºÈ(·•B®ö\; 6Ï Ö­5’'Hlyd,RnŽËÉš½Í ë@Jà.5eú#Þô’òLRÊ¥­Nì®§‹L›ßI–‚ÃI¤–çÁ9ŸÒ=Û^Ûp¢€^¡(üjùÎeù¼(8'ÉÜ!RÞã±…c%nû?NÄÐæq#£€--÷ñ­‘[ýtËåW"¶‚]÷Z¡ál-?G Ú50a%'¬Eö¿¸‘Qõ¾^øT V½çj nE6ª¿j3÷ÿ[OÂ^ÐkkÌSÉwzAýÒ2?$Iªê˜å^Ùl-L›‰&IÓ,°±—jO Ú‹ÅÞí´9uæÍ9Œ ‡ª  Äß^ªàYðˆ.²´5Wp 1xoÎ’š7§¢bVš^,’` ϦÇ—¸á7Æyœ4ouµ\Ž‚ 9C´‰t*t/[–Ût]VWG¤þØZ(Ø3¦bæøHpI¦zêp˜NO{YzÚËÒÊ£÷ÜêÒë1N]¿jãâÖ«´è/­xEEnž§­SD)'ËYVJ}ŸºûÄ/€yÀ´ž„ƒyê1lÞ+í½ÊeÓ‹:2AË» Í7™éqkìùâz¯Ð·åVöÝ#Õ)¥=6ïô‹ñ,]ÚI£S;Ì4Ðw£ÊËrŽ(ößÊ‹^qÏþœÞ1DõèV'MéI<C¶òÆÆš^9„Ú’p2·ñÇ2«c³Œ,¶¨ ¸ž¹½:ÛÖi½àÉóÕ¦çøuıI-vÎHAt‹^»8];ly@-;Þ¾SƒˆËñûgâ™co¸–|ÎÜ͉µa `qün¯>xÔÌiÙ:cU[¢CÏÜwömBÛ ¼ë¤ºgEèv´¡>Ìbƒ®D¤÷9È >)ÿ“—v3o!úŠn\€`,'¶¤Ä âÓùÔVZ ¨ïí§DJööUø ¯I˜-OH˳ƒå‰Óå‰ÝúÄÆÚ b@:½N”3BöHÖ©PÆ^xûÁ§– )œö"Ln$À \-ˆ:$áQM¶mª%J_PÊ«‡ø¸3"=Ú£}¸SØJÍ^¿3ÔW؃fßb*3kÃYóäćž„Áᘟãðb«íuœÃ‘Ðgp~¼½wó‹‹µ¼áSxÞ®Õ£v’ä“í| VºIÉ?nŧ}¡ñ!Èåö]óÌñ_7{NÅgË,»×ê¡ú¬‰°SÄ S=D6,¸…wÁGkòK}H¤_ƒ¬—Y'`—MOüžÚ¡0¤îžs\ ù0°¹ú™zm^¯³“Ü£®ÎK/üé I|,kF²Ah—¶ˆ}KëÚ—ÒxK»M8Œø<Ñž}Xxûp¡6VWOÈÇÂð³òШnD§hvÞ§[“@!޲ł3>pŒ.‚Ô ðW6ZÏ©[*’9*×ô:î»UÙ$êõ.£_ÎÊ&6eБ°Z/X©lò–ú°UâpBzf!½v›j)}Ø[ʾ­I[¥)×zP»iïU6íÛíù Ký쓎¾ßòð£)<–@Àqº}†•l³a‰Å‘²¯- ·œE¤çV€ ÁÁÒ# ûvsÜŒ,×››#cshlŒÍ ß›çFµaÔ"£~nÔž›}cߨ<36Oêÿ1j¡QÛ26cc³cÔ6zÏØ ÍM£zal6ŒÍº±Y5ê‘á¿6ªÏŒz×xglúƦgTj&ƒÑ0µ…‚“­þÚ¨¡ñ~¿-òfä“"z´#™hännÐzò„³ì×È~ÍÙß ù)»ú,ÀZËŸŒ„´Dþk(½®ÎºâU¹R9x¤xõaÆÕ76ÑØ›€ lSýnïÜBm“™ÏjFʧ3®ˆ„îâëY"Õ¢2[£\BI—„š.?nØk°¿vðDeë=Œï\—ífe»iÙO d¥F¢Ú`¿yQ$ö6žh„µŽÞJ-ÐùµP¦VÛâ?·ñˆ±=o¥­ÑgR à™­zÛ^SžüíŠzªnûÍ ÛV¾ãÊö¨w »„úzÄ_%̈ŸyÞ¼õÍÛê„iW­F‹³GlGN¹u®ì¦¹™Gq’|ÆÂg™µŠéÛq+D¹o0Œƒ´{*Uã+ù7Ú…ö‚σQ¥ƒVˆ õÊ®ÙÊK>"hÑøÞþéø¼¬«·y|÷WúÅøÞÞ;>}P~ÿ]v^˜ð˜Õ¯æ6-Çg•Úl伂ì—$¹4v§CÈÇqüÏrÔHÅ’3$”p±#QËz$tÓ9ÃÎË¥ù>ªŽ’%D㪱FžbIñ‡ªÓḆӉ|Ïé ç@­=+•“й‚ð¬}àc×þ0;ƒêmá Ôþc"M¶š&M[Bðy®Æ×ü| ]ŽK•ÝãŸÿá—·ôÂÃS‘¼E€4þ›c³]‰F®ì@ýPG&‘Ó ¹h#ŒšœÊN‘( …€+ÜØ-þ²6ˆ¦$O޵CO67SÙ!!gìùè˜ß`) òÐ5qúWH^“p|ÍÍ’H.ólÄ«eÖ·€ß~â_Nÿñp²òÐNÏèÒ¸öÀÆAAÝÆgËôvLææbç•§¢8 h B•6Xè¬Ð¢6!õºÕ/iì.^ب÷ñÆs£õ9–;l‡Ê³í‘ÆTßd¯3?{¯ÍåöÒÓù¸:ÀüìvãSÐ8I0#©[$(ÊÉ_>‰\oX§­{ª]Ð¥Y¦"œBª'Õ ¦ÂSyÛ úµè]X3Hpd£¸é¿7YBÎ.› e!jE´p•m DI’iÖOÍ”ôF+=…wê¼#i'ðü7¦³ßŒïµÞû|*Íô¾˜|g‚Ù „!ïÕßÞEpëõ'¦œ@u«ŸØ„ùت«>à[÷†OÄ Ébômùûd·Î\P¹6^ˆd‡'¼B| A¸¯Ž‘ò˜ncÏbj´—WXº”D¥ºÃ _Ñš/ìì„6ŽðÒ§Ÿ$à°o’¬³'R܉ ÷Q¼uošx/“Êø×GHOiˆÜ†3ÙdàSS+ÞæÀ NjCº­TI_¨TÿºÒÔšù„Î÷.L¬4àÄl¼r/Æ §±ë4ž9§fÅÇ ÅÇ@ñ^JǤú b? Xv:ÊWƒ€†‚sê=ÎÅA¨þÄG@°òXï÷¦CÑ¢“¢÷¥ ºàNáóü1mÇùä¨c¢”»+G‡rùüF‹ñ“óŸýr |h*aäCƒØI#ŒÔF}ƒƒ‰êM`míw·öÆGÍÄ?jn8ŸM³úqýz-¼^«|^ ¯L§qMe*ýÙo~rjßèOåý©~ ï-÷ß:†7¥Ç®q[Á6åH cP™êÜt*Òzå'GŠ7å2áÌtªWMóÑú#vŸ°ÑTppfßÎä´æ3sÔeò|f|Z÷ÔñÖƒããmk5ù §+¼KgßyÌH«cwãKkæî¯®ÎÜÆ5{¬èMùréI¶7=H9æìê{çåÃüò¸B9!BýßmÏåÀÒIëÔõº½m®šMs1½3·ú>IÌÆ%½˜Á¶œ¡öIå§¿Y3ûhd›þ_æÚ÷Unñ˜€‹t|ôBûQMJ·—$ù1Ú·§<òS60b~º¿²ŠàõwÌÀ,Ÿ–MœÜA?a MÜ—‡žC³åuà(eÄÚ–÷ábÐÉ$Ãó[r†‘_µ~»Y±dgì²R³ æ0~ï‘›?È| Ø‚æNÞ£p%ë®[ödÕ® „ðÒ;æoᄆ}NÃöõ”.Ê–up={ûÁE3©ªˆ5X(|Iûÿ“õ¦Â-ÀöWôëâG}‡€B‘H‰D±ÿuÏ9œWå&œÔкÕþƒþnÿ1°­"hTÿ««#U?žý]yfw'íãp Ü®pL—ãØs'tÏÜjÄ à>sâCáy€'¶H£…ŸRa O•Ò½2€ƒ–èÏÊÃ%@Pú ȾÀ$“âAºÎ‹>Îüžà{þÞìlð:nc¶í?53Ë c7ìšv¯z«Ö¾Ù]·þÑzç`Àô§â9HÅ[—smàœàx×­>¥V;kahR^ã§jòPçl­Õ>®…›«ª?Ûhâ„v[ØpŒ°n„5#¬µ·MþÏCRïëÚÖïk[߈«4¦iâÖôá½W? ±w'ÛÙcÙt P´&’Üê•mÙ ÒHÿLÙRw€:kkÔCcÀÌòƒÂª ™žšN›jÈ­4:4”Úã ºxeH‡ÃÛ?Âú Y\'Ö×€YmáÞe òá,;‚«l×mœ[]øÈHJ-©b03ŒPp îšúq‰š`ÑÆÆ¡ePÑúW)‰…Ù:Ô“¥bfíµ‰mŸÕ  Å"c×­íÑŒNiQÌxÐ9NFë5 ÄsbÏ|ÉñRc½K…v¨TÁm Ÿ ýÂÞ®êñR¯"%ü£'6 Þ‚Ý]]Ìì+Ž,1 ¤á|¢ì­÷ŒWjli¿Ÿ G2Q§~" Qžc¡÷Ô싵ϣ[^½gzõpùÂk]å5ª¼¶º÷Vy‘.xJ`ÖÖ€'Y‘—¦r¸×`ýœA1¿ 0¶ñÇ’¤;ïââ­13«ï ¨ð?š?Ç^®®™Ù9ªMš„p«]> 1Ǿ|¼õÖFX!Ö·ÑÕO[orñ»’Dd@-1ÐÚiœ5•JA=‰V‘Æk»ªI’ AÁ÷6ZÿZSmn½^{Gò ÿ6àSãoð´[">Pƒ›?Þ²+ÀÙü·Û¡»µÇ’6ÁÊ»ºº%Õ?‘q8‰~`´÷ƒ-rW]©Â„–oߨ×)çöÙ}j™å}>ÉCÓÚ'Ùf¤Ì$x#T²0Ÿ ¾²!؆¬*Í üW.ù6f™_ükÈØ-9kÏ6çÁœŸàê„HqsÒ¸åÛ:ÏR­ÜÍ‘ø8ø¶¿éxÁøg|d}Uú—¿¥l*‰\iqÞ[}>žÐ:å)¥ýNÒ„Ä3ùõnøwÁ«Õ䛡̦G¨œ^Äçlnm—Oå²(|Ê×»¤‘¤úž>ó±Y¦^ˆó¬UÕ ·=â,-ÕHˆš\¯¯§Iì”p+”k b ø¶‰ƒÜ…ùY¨Y¨YÐ,´Îü\(OgQÛUsÈ_ cHûklŠîëÅn•^#È·!(KÇÆýv›©Í©æFæedøÅÈèw±d¤Uo³:ÆGßïm,ÏNœ6y™Í»°v2K*ðâÞYç÷àѨ»w Ü»8¸·@®‹¢ P ŸŽhÑ çNzñ­;kXò}¹}æVêà½Ûæ{š~¥NÓ_ºýŠî÷D¹EDƒ3q¼—A|Nµ4Z­ öáê_´'F¡Á’Âñ2Iôû[øÛ½—ÔnÈ=ó€¹U!I&r‚}ÛjÐ¥çV*p¦R3Å+’ÂÔT¤ZK‡z!êñ{éÕÝ|ɨ¿iUëŽr®ûÃÄ{›xrqŒmÇm †æ¶÷2C‹fxb]È‘}i¹‰‚`·Ëk'Í¡ÁQy G¹,÷‘ýÛ:ÛN»ÞÜ:àû^ZŠ W"«ƒ˜%Ç?:ˆÃgщÔ@)ûJ“¯ÖÝÏ8ºcEˆÆ)û-jË’·uÕ¦ýÈï´tA¿C…p£™\HjñMc-0·×¼¦g?Ѝ™N+v+ÔOlj¨sˆú=” ;1Æ#°ºžYpÔÞ×Ó·]…… q&¦¿ ½ s,¹™NÝÐ×åíÈ!‘0oÏ®S³w”í›àʶ\âF°P¯¸uÅîš,x_~ÍGÐ p›KÌ¡Î7VÏ7…|ܹ0=¸à䘤{D,U¤¼(‰ê5FVßñÀ‘¦+51¿6v‚ôŽ^H¶ aî”÷=Í”[Æâ¾³‹é޾¥Øôw}ËÕN î Uk˜Ð®@¡õ]{˜¿»oìïðq @l}•R£ÑL/`÷'Ü[€q¸±ÝiÞz¯›]á÷r|JnDì8þe³ãT½¦d„úB¥­9=-Z‘ë_⯠!Á¿TWlãÑâ›níM/'`Ãïn£Jõjð´¿Æàœó²Î~]¹AlG³w-·müU³jñ84¬Û¬Ÿg¤-ErøhBÞûB²e­ù[îÖÔš<Âïw{Ý·ËnÍ~–;pd½ƒS ºÙüäø›ÙU1DájA—æˆDkz!lá¥w+¿Ûø3ósš®®î6SÒXsýo¶úåQ»G¸`ô'î´¸†ÿ­6Od¨©?Bë¸/EîÔ3(µ‘»­ÃñæÚ!FÒÖ ü¯\LÞu‡¬Ên!’‹o€Ñ”áz`ñtuuúdmk²=mê;bt ¹Æ©¼T6¹ˆög±7Oé0*†‘¬ˆŠjaÖˆââÌCzª¾¥ÍF?»–¦qÛ\,ë1Ás9õ ò;lø¹àBfhô@:‹>¶È{<ók„©Sc…w¯mËæ][£íÛR÷!BÑC;X>jí‚a*ÐkX(“µ§%V`”S€«¤ÅÙÞ[Ò Hž[vnñø* l!íüª˜[CþN÷ˆÈÙÛTˆú‹½è^¥Og|ü›–çróÓ~? ¼,c½¸y,Ee[ O/­ÖT߈A€$ƒ<[eÛ »«5¾ì%8PA.ï½Mvþ ²2?Æœ*­{U©TT%,Ë «E,×äÒ©T+Mg c-8 l’j~Gƒvr¥´#{SÉ´lEx˧*æk€V‹¡3ZWˆ®xmiÞãÈ ªçÖÞo›5ÈFŠiŸÀð–φã9ªªm²%e°†gûš´ø`«ŠXƒ8·µ7ÍÛ­AsëÜÙê7±Ó¨6·Ny¥o}uÿkHsócÈí?)£›KìªDï&w,7dPà"Ãü ]ö*«ó¹òÊ#«LBþÁ"UVü~zÓ!ÍëWð­¯Nå;-Ä‘ŽÙ1(œåa¾Õ08r¼^fŽ÷~ýŸNíS mâ¼æ.çí@ÅHîrhƒ`—ÐSµ—¦Ã>ÑjbèùÆ¢ÙáÂ-ŸJ®~„¸ãÒVõ¸$i;iZøiUFe¤u(­þI§ídiŸ‘¦$Ír%ô'-rù…Lp8_÷ 4ã‚Öbá"L;=Åz\ªlP?¸Új f¹zpÖRß'ÐÇÛKµø¸D¥k/K'Ú‰Ž­{\ªÞ—ÊVvó€Xf¢{°gñÕ€ZÂmàä;QxR÷:î–o­ô·Ã¦ò–ÇïÜk—øo³!úÛM}nžj«SîÕz»¿M Ý;.5éç5 ²WÃSgäÓãñêdSEI™——oçëæ_ª=Ø©êÖ†ªªnPm¥uq{_—oï˧T{*É ·%µ~˜ë/ÔGsƒU%Ä‹”œºïÔë[N)‘ø®\òçÿú½D,$‘Oz$?Âi2ˆG§ó³ËIæÓË8‰³8™ßLè)ìž%½ï½ñ4Ñ_–OðyÄdt9$³ùÍ€Êý@j2GñÛpcHñlžà0ü•÷$éLÇW³xšŒùãš3.z„.z£$êÏ&\l6=åægÉåt\õGÑø*錣›dN)ý-ÕIÂ(J†³~œtg³„ŠÄ×ïzÉd:žðˆÇ½ßüNâëy<Šùš KÔO’Éåì,éÒh¦ø3 ôzžŒ{½Y<Ͻ$ÝËi‚/f^Îhd?þ²lÒëOgóggýADS»ýù MáŠ`×›'ü•8ÏåÓ‘IöB»×ÌiîÝA8›1|ÎúQùÎz2 ç] ¿žÓ çó)Ö¥âdvFÝ`mZóiÿô4æ•Hhýy2ÇÌñ½>Ê»¡É£©Ù%á“€‡ Z>9‹ñ!Ÿ$™ò×ÿ’9ÃU>ã—œ^ö#ZÎar:w• )³w„„g‡‡ÉtˆŽƒ#êt^Ä;øîŸJÛ(†áuŽú4£˜0¢ÚZâ)Ï|öÂiŸÊѨǧ§4lšË(N¤%B–ˆÒ?M&ñôYHX×¹œÏ €üEFX¤¾|Ðx»ãÉMÂßUp$äºÅÓ]¤3ÂÒî<Å@¢iDùñuÜÅ<º´xÔ)” \Ïûü GFC.@³=Å̇ÂÞåˆ~M Œóåó#Zä «aL¥“Éx–ÌûÃx|9O¢˜ÝÈ@hL®©÷x’œÏ¦\¸Ïs g7£.¡0o¢]ù¢W‚Qö´ôø¤50Œ–õûeL“•TDæl¼îhwÍŸÆ´MãdDp—b»ØÔ½þ5:ÇgŒ^ Æ!m_|ZV™&K£äo׿PXJéóXcñØ´&ØPÿA3áP¶CMãUž%ú+IÉ oJº6ìŒêué÷Óǽg„á*C{ ­ñŒgLMpãýñ•Zöó“(ß~†•œ)°žÒFNðyî8ñhÇš ‘?ù0%†¤†>{zs¤®3ÓŠRþä=ŠðTpˆ(És ]Ä#´E”#Žþ´¨ô1ˆCìê{JÄ@–æsŸjB;ùŠ*Ñ_¥Mho¶„357Y|Еð{x@{bÂTŠòÏiŒicZDagÀ»áøg0Zžåæc¦¿´õvh7ƒˆ°©LÉxöˆuÎà²Ã¤Ã/¼ç„\¾“7›v qc;S´ˆ¼C&Û]|À:é1NàûÉ "Ó÷ŽŽý•}‚„Þj§å}=ا­–`w/™0Eß=Æ6!T%ÊÕ'Špž~TLp"‘ïM%ú+ìVZQ!! Äþ’ŒUPc{¥YÀ ’ÝÞO3¬ ‹à\‚ÄÏ™ž·dõr1!› ‰$¾G3A™Îø­'É4ŒúãdvÅ;b÷’gû½ôK-›Rxž/„LmYŒEžx%h±§Líñ©]¡PD*å{سe{zC›¿O{ƒ°ÀYÊdd N/G²I€,Ó·ÿÆBü¡Ñí¾;xFK ò' ²’¸ˆeÛî@d£Q "¤°8ƒ½Aœ£a0ÒpŸŽI#!„zÆ8úM©µbášàv¡ö ‘Ôlð,ô‚ÈoÏRiÅ „ËËÈñ”„ÕþO%Ýj˜Ažà‹åx`Þ&ŸùR©$Î 2&œ¤Gò,‰òÖJ\30H‚©Ä¯IÂ8þÙgÌ3ˆzBJGÝxðô²#¼JŸ Â53Ø™h¦€ðlM$M&Aë›úýª¥^n++ üÒ*äšþ((ñA¨›Ú+4eˆ ñ•*Êy‚ò,¾?ƒèÑh9Eµ#³`-§ÃS™±–Äž Ã]BB“y²1RE©(Q"˜§%¢MÜ#pËæIä è‘°*áêÂiOH¼’õÆà`T‡ˆ÷ ú—\nxþf«z "‰c–°ðùR¥îèEcžŸ‰qçwDûã ~'‚ýNOqXEbÀ 5î~EY½¥êO¿7xXè"Pjö:ãÕBËhcy14 ¤¢øxªç±0Ôï**ö€Â4*†“*šV†VhpÝŽÆ8$ ‰3•Xó}(ˆûbo 'ey€ ÿ`­2-¢ºxéæÔ)…e R+hŽiPÐÈ^°ú £Bï÷3EYMµoÂ2‘;hÐ_×~€pxîÎ)À5 ôI1 †{„4qüì Îà•É%?šÈï.v)IñZø#Š¥× ñ|¿’¼ ßr#ïH¶«ÐY¬ý˜1ÌKªba5_ka³™àc6‰î¤"³ ÊjL¤ZGÊUt‘¶Iòòàˆ ˆ‘‰·ÕØH^Sꆗ]&‡}ÚGÉ^/az§híÑÑ{"ÁÉAŸÖ}6ë'ýbÄ*‹ÃŠNE”íû4ù%’M$‡kÞ“ˆËº:»+ Òûµ =ˆI:„ÂÉeÞàÄÌIöŽ`òE‘ê]]%ÌÆÏ¦Zi$Â¥™åׇïÞâWqTÁNYúÃSV(/YLQzKÆê9ì*”’édB 2Û/J.U¬RR² Ü9a·ô—åËÛú‹ËUïž/.oÔ›µFî‹ËÿøÇpjìrE#ÐIbÜ¥™’ëJMãvá¥N|F8ž¦ 5RîõdÂAÌoÆ¢…/9ó‡‘ 4üeê§MH/áÜ ‚%%žýÕYÀd¤}³³ñå ¢ƒ5š8âO$ïê)>úGcÖV-÷>ÅÚX]Í ì÷äh¼µd4+äÞlÎ;,Äõi| ‰‘4“ÜÜæc#4°Ú†Âýé§iÂ.ƒyÎZªÚ!S‹™@P„M4•ohæñˆ6¨T*¬1Ö²gŸöfîRg¹öG¼b Öé°Ñž(ôF83zD|ÇW³&Rÿ]ú·\+}âå mß5,Û¸Uu Ãu]õL¨ƒ‰©FùëÚÒ¨Ì9wŸ†E Z `q«‡3eòw¼gc´DjÇÌ Þ¡5ÒÞàb¸Æ.•€,QÃO£±ójçÕúÎë¯ 0ý)bÕ—Caj8˜ HzŒÝÙæ×¼<á—SzaZÅóÐ^:LD5®#ýÆ×Ô[î“öij÷´¤`&¦¿®jÄ⚎n³Ö:QÐ5 Ñ›P©•‡õÑ4Í )X¦tAÈ L—xÀ~P[M§ijqǼe³Âƒä’p×f$ksB„”æ&½Ë)•¡¥cuiæwGí$½ÌJÁ#Ú~>:ôgg:ãÖ“qsíX5K·¤âN4:*¦4Ù¾PD8„=ÖÑhi«¿ŒH¶‹USÔ@8º1H‚ÂEY1Jn:2 <òP»ã©ˆØL¼ÙÚ¥¸ÙÓp&Љ*<9,Q@¤^%!QE‚xFÒ+øý(Z'@²˜5\3V´(Õ4DõBQ0ôĿ³Ò–ì*ƒwÁ[(¥ Ùö±Óþu§® 6Ê£A¼U»ñÙxV„‡ª²&†Õ9ËkB4dzrµ¬Y:7g•rM•lÇ¿¥¥•#Oºü‘‰˜/í}‡1C¶¹ñ¼+‹Åb*‰Ô‘¡ì³)2ëFóS„ZWïþîÍhÓï‰Þë².'{Võ“’ÇÉ–¹oêj6Ä(¥ÖZm!WHIÂÔ|c4BPš´E™®˜¬ ;Ëâ¯P ì:M'^¥—šiŠÁM·©¥“ljÙrZi®"aøÇ®ÝV¾³÷$a¬ÁŠvyz¶ÔÙJ¡³»UŸg["vK­ü+׊’|ÿd÷ ŸcÜ7›¥A-4ŒïÐjÞÎË-,~M¦_ЂC¤¿‡’`6¾1M#¹f˜’Ñ£‚Œ)™Ò 2d1™ .§ á™Nuçƒ×`5;‘n¡ì_$qú¦(Ã:B9ÑÉ4sQ:HZ ,d¯e{*Çfúó¿ÍCz ‡ÿÈÿ?a(eİR£¡(é!Ï7 `BÚËªä¤ —*À¨åï1P,ƒ “!6" °4ýÕ–”Q)Çk +vO]¹MOIçCÀÄÄþž4É2mÅEvÇ uTú·ÌI‰éé3‚¨ç'0|pv’ý7æ¦j8Òâ=3sO…ñ‰l¥9[‡YÕÈ0ÿ[±fæÿÏÝÿ?ÀÝ ãíx®lA7ãK" ŒâÐè˜vŒØéU@w½L®FjJÈ!@‹8#¼œ‡°-»¹áïˆ;"\]z/Mô0ÆèlÇ«M’cÄàÎx£jüÓ« Ì"J2ÁÒ ko—¢¯»Û …†ý‘ÐMösk„RÁ\Õ¾ä/‹R¬…Æflÿ*×*Æ6š†e-00<›šÙ LØš’_Tß±¡% ÅãRÞ’A‡¡¢5„ð[ðj¡ÕB})Ÿi»TVð(—N®Åy?–Ч{³î﹜ÃK¢9§PéX¨*rm¢|s#¾G9 7Æ›} oÊ Ô^i…ávy¢ s5Ò|[‚~Ê륚‚©SØ»Tõ˜xHó!Ž>e†ž ¨{ Hô»KMD=oBLúd3¥U™öãD&pbFžiH°ÈBÍþ'Gk,6D8ºõ_Ê|\tI¦À3ŠÀ½ —f0Ã_žs¥Í(â :ZÚL¤Ï¨±Òmï4z•"¦ÿË}#r3WÈb75+ÖÀ¦8x‡`ÆK˜óuó2­Š{ÉQ<<È6Mu>å{Ž&rí“¥<ÎæêŠ RËe;·a]2Zi1þR¢VŒÔ´ò£h£ëÐÏ|ª›F¢I¾ír0¬…ŒÜf|ÍÞCûÅ2™ûÁ‚̧û,nØ\ZÀã°±$FXJ(I,n‰h#¶U ‹Tb .òÆ0žÍ”E%,Gƒ¼žG‹8* Œ@ùÕM]ÂÖ†¹¥Û’ Uôáí’½DLo dÓ R¨×ä¿juˆ®3f53ºWú4Jýd2êt±doBȈU²JÄñ¹~Ù(Ù­Rä/¦qü3Α½†„û’<3ˆBõ‡—C•d³(Ér€ 9E3—£Q Ãp8½1.'Wá4šâ†Xvuˆáq÷݉‚£þäRÀY‘•óhÄßס§9Ê—³R“aÔÿ‘÷8JV‰rņ÷›E¶ÛÍ,YIÛ4J:h¬äpÎ|<¡ÄɵzG¸v!c”)ÅKSJMê¥@–¤£’$—l¬ ëñÔ*õ#0*™Ëš. #Ôu%&ˆ\X¶O bâÏ,Ì"˜î'uóÏ¥Þ] "°Š½}™bâш"ÄŸp¿ÃqôŸi|5%ýÁ¸œ ö¿b‘;—ìÞ²ˆ›õ cÑÅúŸÔQ ½vd¼õÞ.àÀÝpßÂС¬8Ô]_æ@”¿D{tà›‹ :6®C³ Œ»Mr3v*7¬ÿ˱~J‹±.  Iµëª3Viû{P⠼Ƣ·ÝäŸ|;unç_~ͯ— TÒŒJ>ã˜þ']#ëÅÒö|©ü³bqç=fʰÅëhµôàÓN‹åá¦<“ã:ÝMç$!T#k-¼ªi¹¼],G=Òü̲Ï¿—ß™iµG?¢„¥¬1iŸªH]7º”°Ù´u*ÓdÇ !^©è‡tì!ÇéôÓêoÇWŠC¸oJ„$Q‚¾Ø$²B\$­:šÅóç£è=JZ¥ç­¡?´«eÜÅÞ®HÄvH'‹­þifJiw37…äº'ž£âk.¹Ä xh,PÕË–L9O‰K–šRƒ‘êÓZYf(¹Â÷£MV{9û¹4—Cí§—}øe—ø°°j#< Ï @æw£ޤËË=×Ãbsd®R]a­ÐaüTBåBÃáë·´x>Ûf¸YvÎ0 ë±f†JËÜÑwy+D®q<ú7 ˆþ¢Ó1nKx'èÐ_h(H¦·û:V®9mÊÌ©Sÿ­X#hí¢(³×ûGØçp8ÛýŒkIÑûŸ¤÷oµ˃¼gJpËF¢ª.–kªWB/®uã%Ç„oúƒ²²++ÐcÄ~=I»»^ÿF#,O<ŽBü[çY¥ó™°jšž•g=*‘|?¾èÇ”‘É-œB ,…³ÿœÏ¯EúÈü,X/©r,Y$Ga$`0atcÝñßï¾f‰\ j ¥2·R‘x¢» H&äÃW +©å|&Ü *I<œÐœØ­}ÆÚ­œZ³ú#¶6‡4p™$ªóþI#s>)Ûš ¸ae^jÛUõ´ª–U’°)qu ËªŠ¯ÓßÜš÷ø­SÜ+=އOJ™Q-çwáÂ$t?^G‘ÔôF„ñ±»hžê 0¯âúnU…m­{ c£Ñ¬m5+[… 0µ8»T“¹G4O¤1§$Eíá`您­©O3íÅU!éÒ±ä û[b¥anSÂVgP²$r“cvb%ÉŸõ'3ü1 #XÆ`ݧ6O%´ŒcI\ãIØÃѬèGáá¢94 áŒl!¤¶ä°££LR¼ÏaÆ…ÕÓˆ¯I6í+Lá>c©"’L0ß#8 Š¨–‰Éá¯\ˆHç†ã©ÄR¢ÁåŽGhÌ‘‡1ñ—àM/‡WáÄá¥P 8DA²Ã0žŸ#Þ3ìfá“%3ZmÞ `}bDaS$SË zB$“N§° 3 M÷¡h”Ô,РŸÒt0aÖDžO®@QŠs-Bh7Å–,òˆ„Ý•‹n-ñL®¢£düánÏmôrÂ&LüË÷m»rÖ*5Gã¹uß0l’­9&枦‚iøÕ]qÃðG\ ³Kã#ó-AB”1fS„ïÍŒCþµÙ(5Û¨šrg«âN–3•¡¤ºÔë¹°€QÆsî[¦ÿΉcϲ3Í©Y>Žš†ñ^̈3E€òE¬ç8ö•‘ö¯l3…>TS”`¸ËmhH[).[’Ãý0OÝÐ&g[E]óÞÉËPOÝ8JI¥±2 BÄQ÷𩦦‘…y2 J?¨…ßV!5·% ïi)Œ]â³%—ƒA }j 8TQ´ëŒaR tGqЍC ¹xÚ´ú7ªµQ˜Q”zW.'à48ÍBÒÂTé´¬àlœÁçGX‡KTÑîXM\:Àí~9‹y/£2¿‰Q!~tª±ñžªrÚØ0¼Þ'ÄôÂk6„…CíôçýOý 7T*ß9|Q¿YÙB+CP:“’ •¤DKƶ±æÁsÃÝì¦sÕölÙ ‚l8hÒ?…˜}Ìlc3R*ª»—ônݪQ7*BTå\UÓ¨m¢KsÓhlˆÆ—kAŸÀÒk[Ì•ÅÓirD3µ6mèíñ ‘8?x&¥Y:^¬÷,fOÖ(f'¯sI®è¤±¬Wܽ^¿ æãVLO² ± zË¥›ˆËì¢?g—úºŠ¥±ˆV!skΧ!óŒ´ýŸLŒZC Üg–žÚ,eÊ’˜E» ÖiFË'ÑÝî’Udt'»ÍµN2®Å¶š{J´G'íRHâ, øJy¶wïXqUÇrÀÌ/ûâ]êäIæMLÏí•?«_ìSë‘Üóaê~r9Ïxïj¯±Pl…å .B,“ EÐÁnŽŸã~Ñ_úr=Eñ¬‡j‘‘ñ …§8Ã5O[zwC”ÈØny¤3 ™¦ó9‚‡ÜQ×K–wÅàkøÅ!õóQ ™DMtÙÑcÕ-±ÐÁ§TØ­ç“&‘™?š!Xt¸¥¬p/블3ÉáB–gñ@¨Zi>uÓa4eXóHJŠuÚ®:nfIwÞ[ËK»3TkK¸¹ù³Pz·aà´<ÛÍÎ=kZ~#_^ºýU¾þ?oWÞ/æÄ>X—ãüj- ¢Ë2”2°ÜOY¦p ¸ªr-äQ§¯ wïQz=>·-§t,~J¡pŒR¸¬´­(R¨{ò‘Ç©BÂ’ ë¤Gƒfò!vŒJSÄ7凾ÙA‹œAˆf·$ß‘*—,“UJO‡–rÑìÜ ¦Cõ8€˜¤Ét8MAîÁv/'¡ÕñäþVsB3/Š„!ÝY˜ÂzãiÔÏüɳœø*þzÍØŠÚȽâjfsÉ/p^ˆµ ê^ƉîÈ93~JeC‹`¯£{¸ 7ã\ìp»¿É;, e¥5ÙÛÐU¬ÖŽˆWÈí9ÄlHÛÌÈJ&Kµr ‹[V:'\¿nY¬ ¥“< Ãø$]Iö^½U¨ÜÂ(#Q‡ZiûkŠøPÜ­fz–ЩtØn?ÕËÕiÊ追q¢µ¤É¶’òåŒGqN(PTÀ:Ž/U”R<“}?šŸ­ñ¹_åÍ‘ÓCë—‘ÃÛ{C^ÜÜ Ë ÷T¸È0‰eÛâM³8Q(3,d^+׌©.4ÃÚ~S¦kÿÝ6™±g™1”\‹îvq¥Ï#ÖaéÑcÐ\FÝRåæî"²–šÐá`V®­€Ok†¤œ“&Ÿ3ÔTÝW«wŽð¢, DÊêr^JÕg“p4Ë ¶>Óm-Cb”ß‚d#ã±tPÌ2T¯k’Û¨§Cê)Ý€úý‰¦ÒÖ h;ùøíEú¼È,‹@[: ½å Ó)5SÌå¨ùe”ìü”fÕ–)޳8C‚2ÇU!f½qä¥) ‡“N2F—ÝXªâøòíwRÖ2-B`Éß“FÈóbvùóÙx‡ƒ…DLÑÊ,cd+57w~@5fò­2©À >bÈÁïÁ]œË}¨JkÊ;N HÀÕ;¤ÇÑtç¥Î™²ô{Á(•r$á| …iñd§±g¡¥i.õkžI¥sªqŠý\ÙA[™¹g™måʤz^„[0þ+C(¦Âº_s´šc…­”î èÏ4'Í´ þ£ˆ3@ÙÉ6&RysV&°FŠ}(£_)Ûýr®jàùÍ”k›4Á¿2ëÑ’š˜º[rM=€3Gh>’ø àDH|nIFÕñè|æ´;.Y‰<9=>Rò+;aÎô,#Ñ!Âò&Xö84½˜ÿ4åÔo`ff\)h>yŒP'•«ÓVGÙ¤õx²ž<^Ÿ”t˜Ñ¼?gõ# c “ã6×ø¨² Œ½ã öÜUÈ~Aµú£oëÓX¿e¢Ž‘Wªš0ÓQÇkà YÒ겋æ?¾‰M6û}J}¨_˜çw‚Å,´M¸}– 뮲'C’A8wêÞÆœ›dZ_+´jRyÂߣ£îH­ÔÙÊ«'.u×]‘ª6ÚL+8"»J2¹×Î/m®q›%Ðdmµ[Üs&øÏ»ÈÝ3ó×z)¨˜#¦.$úS8¤%­;Š™ÆµB&O¹“’©•«3u1CÞ&îÞ?Û{ˆÜR÷`\rïÂjP‚Èm.U…¤É`ÿ¤gã1B#U;Ã,ÉÊWǦÊáä’1ì¾æQŒ;x?N[¸M95\÷”ùµù›1G«ÐÞXÝÕ‰™Î8œFŽ9úúÞ½œ¹Å¡§†lØ´…Bw‹Jjû¥å]ªåâÎ*Ë^l 27ð*ï£~‡S($!f‹Rð{ÄWi¢ZD1” $AßÑf±t:l@Õ>8Ä£…*^‡“.™ïÓ!Èû|<ù–ç÷ª’•±Ý›Ör­_’—VÌ5UΧäïÍÊFˆ=ÉL#Nm1šÈóy§¿N_´)Mø´<Š–ò QQŒéõ Ô»6›2u/§3¸z.ï"qq…@Ø;°­àˆÊcÜ=¹Eª¦Ü£â¡*ÝÁ¶Wð ·öž×åT®ùº€ATŠôsøA<7‹hË´ƒp$œÊär {zG”›Þ•…—î=7ênbšÛ6Òð’û+Iûž ¼p1æ¡$p[‚‡i“iÁH¶9ñ8åÉâÒzF8¸ o侌ÈÄ…ÚùBû”¤ rÀà AÔTJÙs›`öâ§è:uš¤û›¯ºP ÅsnÙá ÝŒDdh"¡dÄÔ “±£÷¹‡£î˜É@<ßóËáã½Ì,”ãIz KÎh&ÅWêÝeÖw|Øö¡ èýÆ"²)B0ÕW»pˆ|nGöl}Tïœr·÷¿»a—@{‚²QTêd6%-&ã‹øýµ2ÌŸuaYYsCgZ~?cÿ[ÂÆÒ¾ÏÈùêjq^w¸å=æÜL(È-ᔚ]à ÔÙåd2žÎ‹Ô27+u ãÃËÎŽeƒÔÊöMŒ³_ý™>Öɇx‘¡øØlF6¸QWÝÅ ê°…Ù®<ÄfÿŸÓ|üo±ºeQ÷ÈʼnyÏgv³AaØÙðø2€J£ ð°ÿ†Áíæsë¿Rm Se#ÅàN9£Ð{Þ—¹ 55kÍýPœ5Áf#€2Œ–ì¢ýjy…z¿è73Ï÷òµ ÍßOÅ9~A@ÅîÈ—áÛµáÞ•Ê¢<£t9)å­Fw—{É §Å¶‹däc:Ï—A#”ù*œdçÈÓ¢ýkÜ5ÆQÑ–ºRòAù­Ù²úYX‹åh¹ÿéÊ¿ü8ËwªðFÎX óí. o¿D‘{V÷2“LÇw¦,Áay|j"õ£sX-Ë19H:4îþLá‰`?ÂAGþcw©- MQQ+OoàÛ]ËÈ~xŠw¬²)ëQ²÷ÓqÔg°ë"öN"Ðù¥K’û€Ÿs ÿ ä„Ff]Žð¦ÄCXnlær”ö¹dßýï.ÒB{'Xèe™(/ãí} ¥¿ Áû»€™övå”?+·ŒÈM¶ŠLC ‡Wú> Äy.Kt÷pŠ-f|WùÌ¢–gÓ»ÿ>#ûË|¬ºÑz ë˽ƒ«äÝ)'ö>ÀÇxå¢rÙàg»¨ñk®¦Ûdê¨^~ÉÍòƒHËÿ¢Ÿ"Ó5þw9ú¿ÉÃ0Kåê·ôqÜ>bŠrLhƒý7™š}É­.‰’ ª[šd@/m|½JÜÑ]6ò[–©‘®à¹ä#­wXžè÷ñ: ?Í‘’Åþ“v˜G»Â–Ñþ~F|/qeÂCÐÊwò¿ÍSºšç„‡þt,P“¿Žÿ›ØÌÿ¹ŒÒµ~¡íf3MCŸ…´äÍG™ç$ÿÏlhÿ}+Zî"¶;õiñ0¬V¾À4ÆU “øH"õ yECOfÞú¸dnâè^ > 7㻤²ë ²{ 2 ;%ÌÙ´—M:ˆ‚gê¦x¹ÂVÛq õ`/Ñ_lÈàrtŽø6£üP`.xÎ’šbÈW}„v_Jõì6iÌÅQ… Ôõ‘¼™4¦ ÇC#r ªl®¯_]]¹8Áp1’¦îާ§ëç³u*6sq(®`îàšØ;þçŠÿ¯4ï?‘µv~µ”9·ñŽ7,úŠ Äø°Lб‘æ!V‰yßpÞì”P^òÒÜrêøÆ_t¥&™]ên}÷ÆXû3—ö8 ©ë_4uýšºÎ™tSÖÅÑDòÙà Tÿ[3»DÌïÙ•7P¥4éøö« sÝO²ÄëE#†Ÿ7'd¨BkÉùŒó4ê9U<€œRPÌ#w¾ 6›…Q¾=‘ŠY ÀEÒg+•¯X®YJÁ^a—Fyz×Bf†QøjŽ4Z<Ç‘oî™úQŽ´¨Jl0ÂØ‘^h(‡MRxë^—ó|BRÉ]•['-C9.Ô|üjÒJ湓̒?åÀÌ5—ãCÙ´÷rBÉKAC2@<å¨]ž,dö‹)®´ìËSA²²Ýy(ø%N‡Ê§g`s¾vŒ›»Í*å'r—Íß²{t˜‡¤©¬›‚Á[@ùwG’ûµ1à/µù+n¾óšs䉃“:B–ÎÝü¹wœ‰×n¿×ûÛ,ïEýÊvžr`Ê…(wOŒö ¾ 6Û­AöÀ´òh#ÕÕ 9N…¿Ÿdɸ×óZ”Ú÷èü¯i· Ç²7Ây öò…"Ú­½ÞÒÍüê®Ö¬Y*>Ep'NO”‡Sa‚z~&©Z{¿üM7?xMuÓ£¤û+þg´œåà^˜F—°À Zλ§ EÒ;žÀ;2éÑEÂ0Øâð`IDp©¾ªpí±ú 2Êxòg2 Ä)\-Ì*FŸ…òÍ”ù• »Ì kØI‡=ÓñaKºËŠèmù˜HŒfG9*zÇWÒÒãHáz?½áXó'±®ÉÕ¶³1¨<‡HOc¹AWGèÞCgTžŠ²| Nw§ßܬ|Sô—µ²™eǵµ_P…aŠ'PÝ À§yÒH&‰rS1§Ò®\xtgmG¥ê°©7ŽòÇ6î;’Y²—σè¥)Æ…j¸é$3[˜fž¡åʺùÊÌиòGËŽEÞY#‰ò^6-ÃüîÚJ½öèÄ‘‰ÿY4ò?ò«™54 §BI"ë®öœC!±oèÎک澄¬Â–ø,Cú¹¶B(³-Û•ŠY%|Í,U]Â=g;—M ¿Š,˦,:¾0™g9”©à…öþ/À‘Ú9¼º[ëNXÐfîµ;dmæ ñ…8À‚ ]8*íÿE‘ÊUŒ]±Á!¸8Oè d0€¸D+˜|Óà¸!ðp„D6…»wè®TXÕ=0•"E“ÐùÿE1R|˃w`èÛöò|¹O=unô--´´ê”º Sê ß|ÿyy.ä¯ÀƒÕÁ¼@}Y€Ty><@ìX¿çÎ/å˜Æµ’7bòíUéAb8âËuº4¨Ž”œNÃNæPäO׿ϰ7q–~,ŽoÆW,eR:»ãŽ;!"Šû#v»ãá:ÁþtÝߨ¨¯ãs€#hýëÜõÂmd°pTt.O×ú£5ùê±Ú;úæˆÂ”ò÷ZÇéöÖE³¡³Šªéc†z#+gT±ñ÷¼°êLÃ߀tY,”$æ¹§ÄÑxÒz`dù~R¢Â==Ø÷rÿÈ®ç»n¢Ò6›T~qïE’"bwÇ,äó'þÒÐ^‘5-özé¯(‹"kñ”¯éÿ?ì½kSÛH·0ú|ž_!4y@ŠeI¶el¿I „! $Æ8Uò ÌÅ&¶ ìýÛßuénµd›dž½w:uNjK­¾÷êÕëÞK"¨è)¡UFV(…_ŒéRE”$¯JГŒJË‹ƒÓòÎE(¤’²„¸¨ãßJÊñžÀdÂy<ý)¹¼šÃ¹>¤ª:YRÕ1.ÏâªàÓF&ôá]æK¯& !ä¬"VHãg©eãU—+Sø-ukÛ1òÌ¢Ýu…ð÷\]=¸6N°š¸J@T*“e¥mᵈ9,?ѤÁDÕÛhŽnH‡ÝÌ™‹¨Ð½×‰í:Ç“XhŸ@ÄuÂùåE;.ŠY’ɇ‡ôì+§²‘Ðî ¶s,…x7¥"\wb^1 Kž?’SðE Já…÷´ºÒ‚ù,‰—.‚Ý'áÊïµ-(1«Xã²;…Ãp8‘’7à³l="ÒCRÙÃ\Ù“ë='ÈJ…ÜD™–Zièn]Y»\½Ä,Z¯ƒMLWñÇIüñÄ—,j¤+ØœØd]±„âøëõï)šÌï»–­hŽQÆâ)u²¨,‚c,šœ4Êd_RJu¥_L—Hk ¾NþÂÈSzW(™` Oôíw;´¤²’θëJ#pæSÄíWN‚q†I‘½,·-÷¶PHoQ§óIlšþ`lŠo9ý[&ÎÒ@1¢¿2äÝ·”ìa2ê0ÚYr&»gÅ?-@O*b–PÿÏyJ/ÊEîŽQâRšü¸,«Á^ÄŽ.–R¢ì“ RĤ҅ó+™®õÇ_Pîêz’”¯æ|¿téù×.II|ÞBÁ,&%©‹‚ˆ”©Í¾2Nj›wX1 7G—ý£Ü”‡ïý+5ÄLFœølj’ÌD#ˆ»g¼ ÒF dv4ÊØQ.µ> l´½Ç¼£ªÎed&V;Ž^*ë±€‚ãSŸ$¸ô,%ò‰8el=(+sK Ÿ/ÉÇË Pvy5EŸ~yf貯TJÕh&åïE&ÙÆ`;œUA_¬ˆÒ‰’¤‘ŠQ“29Bˆ#ë¢ ÞŽÚB¶Mqi±þq—¢Þu¯„é=õH,%ƒÐI³´˜1ÝGt•ZÑô‚Ja‚XLé¨ý?¹„²„v ™”óñLñÀjî$`ÌV ½ùŸ@Ãb`ó¨z@D¶²ÒF š”ŸM7Ñ‚à…\Hð¢)Ó™Ró¤4…¤‘ü2KÒí01}”ôL2&¤âj]шèÚðxüàc.e‹¥4—¢S^™?Ýc®8Õ›¬Õ¸6WËpWÖÈS/²ÄÄòéqKcÆ'­ž¥e¼U!•Ÿ)Ãrð _tÝÖ~¼ØØgoANmà5«6T­ºyݧüÍhUQ> …§­|Æ.öS§òþM›ªñ¿?e¢ªÿhº2eÓQéÚRжäWÃá% æè¸gŽ\`4†4à\L+Œ÷>$W =xÒ½1_‡8ˆOJÚ¹ñ{»5˜ñ÷7+}Þ·D^ñk‘ñE”%e¥SM~ºGzcÙþ(… *˜Œ ,ã2˜KöpŒ‹x »>³w$(aœm’bM»æpM„1†Âíqˆ;Y[,Ö–'&¡µ(ZˆÒÞ‹[&cy¦ÌùôŒ#×jÞtð´Ž@¥Åø< |Ì3A’hÄØ<¤ ê55c:nÕéÍÿ˜DÚ¸+–’û»îÚ¨Ký—´s²9cÓÈX’fB]r§žuDx¡døÛdA§ ’Q²Ý¥ˆ2¡jjs9Ù¥yB•}>ÄŸ“‹‹$¹ýà3K+ŸšIt¤­ç$¹B£/Ï9º®ÖØ<¹¼Ïü=K}é½Öjp’—Þ)ÒDW¯9N]ç$oëî ¯†vc7‘2ŒEúUÈ–F>Ò nSƒtùnÝEQ]eŸ•b8 8’8HÒ ñ0ïè´vèÒÕÌ6ä­ÀOö.ÕN}²Iœ”4Ik" ý9Ôˆ‡dôÉÏXK<ËÀQ~B±™¡¯ÄzĤI%Ee» ëB'N²ûôÞqªpây‰—õZ)KX»@¡jSÝX~£WNÍÑ•‘4nJH[Y¤ÞHâß!.Ý•hˆ¿–í‡á _›¥–T‘crÞÝÔhR»XfùÕX´h8B;=â ²éúöjK°*Ù¼0{Ü?ãn\‹øð R‰ýœk¤šÀ…Nv.¸!©šI5I. ÈÞ$½jYÜž9™ºxæ—ס¯Õv¢,a<¾½¦P<ðƒwÇö7·=Li²Þwsrç%+ }E—h`Æ×kÿýEM ÿnS3§årË@v‰wÎÜp"mJ"î$œ¯ »£È ‹µq&F0RXO"ׂœ"ÐSªjÇç<–HyÝ—didÏÅ×¥@…Ê|nî`JÓ§âM3ž G‰Ï~Ô?öÂÞÆ-¼ UÄ*ÕìøN¤§TC.)Ôê^ ïaæR€º¹ B]"^ä¤Õ¿Ä(évr˜/ðÚ]àíCDz³ú‰íâ/À!å¼¢ƒ„²Œ¯rÌ3àè«CŠ…·“ÿèŽÆdÏâ… œ†Ö·x¼ÓÙO—s x, ™>xBW…,9Š­ÉŒí%7I$&Ž4æÄú²–x¦»ô*¦/mìÉûYŽÈêbLS›ÿfªç\IýZ©l"kÒµ˜R}Mn[IT7ã%j®)Ä6_Ç'£ÒQl´X¨êÏúƒ1k~Y–õ4UÃnÃó ¸LûÏ{”èø~«3ÛßïŒ~%›ŒXÌa/…²…7yWY82+>w›Ò ;U)¬Hߟ6⛊IËGW²IoužmY%_m˜TÈXg¨[$°}ÛùÛ}2iIBF ”»©7RWp;ò&/’biW#P¿oÇÝ´¬^ÜS£C¶öºÿ3¹p^BÄ¤ÐÆ1wÇWÆÓK ikѽB íÝqºË8£1¾Œ³Q8E¼¢·C·\ •Ô X¿ÔÜÈÞb÷‰/Â¥qÒ3êI<Ž¤Ó „]³UYSM~k‰šUú™$„å ²¨Î#¯ŠZp , I}Þì&ÓåÍzÏ’¶4)ÒaöÂû°RïÉX“‹­ä£ú– ö²–¹»MžêðÿÇ¿RÉi_Æ¿=Gj–Ø×EÒÀ(vz-oGЖY+"í,+ðJV’è¤ë´•¹RFh‚À$&÷¢‹bDix—DRÿ"Û¿EPòDï$scÐLâygêxòväVÔ´ÁP”ÌÍýµÖ2(õÿÙž±Ò|,»ÚÿÙM\_¢]ð%áD€›dŽRNÍBm#ðAÚ½b‘fFV2b›ÐŒ°‘ª§A N¡ÖLšÌpð¢ªt§ç!As©N]sR*I  œ£–@àôþXZ&ÚËL³/æçOšcÑD€Dv$M:†‚-]•–]!þ÷ôÐÒr.Î÷þözÞQÌqdxdV©rbÒü0²³e×å›Uòsw¥Å‡òΖ'šû­-oGq¥IcO®ÐoŒ,¹ûqé%s~ìª+²Œ„ÐHï& Ηmyb¸„£ÄZZ÷Ó¯[H_~cÍïöÞqC×á8l[­U*t­ ç…ã[ɾ%Žã¹º=óµ¤(‘¼JÏñ®º%•/ù–ó|:ú…-Ÿ¡@qáåð#A×I#؈25óWcޤqâÓç³´Û Ú*e¢Ê=¶A”e-¦„&Ýüjô„ÝÕxKêû•…jÒÈH7NU$‡’]Hyy¿ÃУÙqkN€_“¨Ký‡Õ "¤§dliDƒH;\ßL´ˆÇ©¹×}D¾™´X»jI€!ÙÑü®P[60nùäÍÄbCô]\ŒZ 6m^ãªSK£~²•·fYLæÄtMyv3QâÍÇ HvÛ,h;ëC6.‰t¼—Û,³™¤KÏ<Û4æmÒ‚Ó=ˆ ã¸!”ïŒ<”'¹pJþàŽ, ·(övâƒSòÛw2éâ¸ÌÞ”#ÒngâinÈ/Mr]Ä6HCŽü7P¶ï©‰ÞRwOÿ fuÜ£–gLŸyÝ(»@¼~ñþ¨Šîcs¤—Õ‚¼t] b@V^zÓ)¯!±oŸl8 W÷ëvé"îåÍþƒ_€n40æQ¢ja½¸ñ´ü(¥úý±óú1™Â ÃÑ ªu³ñ U‰"]‹“¥Í²F’ÕD¡ o Ï4MþgSl`¼þEèϤßý$ð˳3ÜÑTš1#W5A’üÎÜr”4p†7±£E<ë½ãqÖsF?<_ùbƒD}ªrÒBø“2qM†}Õ{*X§—°žûx‡4rfº¾]ÒÌŽ¦ÄY™#E²ðÉÑ¡÷™ÍþÀR‰NF7¬,šOqP¶9¤ËâÔ»VÕ@u *…Ùº(*4$z«˜>ba¯ºg°+(Ì8{»ŒŽ^7¹D°•„.’± ñäÕq^þ7”"3‰ ,¾=ëáþƒ`k}Ág[¸IŠúåIÓõ”Lô º1ÊÓŸrM:'ÆiµFÿ)9'×/ÃQ¸!Èæ·1; ù‰ýˆûW´‘ÿ•"¡H§ÀÒ›y )¦S{Ú©õ»q”ÿ;äš~C_ :ÈO[£ŒÜ#}mxJ>•Ó`ôôé½ß‹µp²ä[ŸåIý¹½·$?{I~á* §w ¡ß”àÉ#Á“h"nSѨtᓸþƒ|ˆøn«…±Ç´>lê†;Yv,um±Xaý:qm)©çùüR?}ùœ^¡¼‚îw.s_ت”YH“úôç–úÎU~fêXBtÍ‹õrQreÆ]Ön\(TϾHˆ§ŒïØu„pßeeCÊ¿Š ro[ÂÇi”•ñï‡ÉÄ’ë4¹1öR˜Û´¯n;‰‚Všßi6h:*Ö]ó³‚òµbßíXö;Óï=0]üî¤?¹E1•nÀýO„G‰a¢Îî¦=í2Œ wНM_CYï"¹ÛXÆ*jÐ%¬s¶‹,oj3ÛRÖÊQ‹Á~ qÊ`^íÒßu9`ÇPÒëV)#â_ú@-¸(ÞHï5óKv‚r 9œ•ɲH®#P˜°Y0Èœ™†$ézG}“Ñæ0>Ððú檋tÄ{Š PK¢îþ”ajG"dP[œMŽÒTÇÙI Q‰æ$$+}Ñ¢‚§ …Òš8>dþÔáñiîœ7λWÈô¤ 6³ƒùO$ B©Í[dBdCÞ-Q€iî›bèâô_dÒý_ec õW¹²õ´¯4šÍ g 4^|‰Øc ½®º2/ík÷O¦\ Ø7?ÕlƒN EÆÓáù([r°‰«çe:ŠsïŠ×[1DœP‹òÌÓŽÐ5ê(G²Ž{8?wÿ‘ ƒÎoª¤§q˜ˆBþ7­h4½À?ê\VŒ/êQ"¢¹Nê‹­Õ´xÕS2¨T…k›¸´òî;áhÌ­´ùâùfs¾Xû½æÓîÒÆµÀ5”¾ü7[LG¡üÍFÅ€ÍHýÞþAÕ“¡g·LÎN·®r—’þ›°ËG¹rŒ¾yìÐK"/”†÷‰Ž¿îO¤Mª]v Ž«g»*WwÞ…FîÅØùax®Wv}×3üõõJÁ[/¬ÃcP Ö«AÙ8¶bcûþÆx–6|Kl ç­D5¥Lë°gÍ;p1;ŠÖd9uÊ-Ïni_äjuÏc8oGc=jÉð”:\I>H:CÔùË(]"F²½Ým#tÕ©}a8º „»(Žíâ#Ú2º"‘{=îwQÙ¡¼92ßñ´&y½xmÓÓz]±‡4Õd„1$Q8…æWÃÒ[¼pc)†¯0âF“XýgÞ\`”Ú—ù®0è™`NÖ¿h3•ðÇ‹‘€öD,¦jÁ]B’ày}áÊÐ>³’W8£‰„³í¬R4:ÉÏð6éy•t—+In$¢ZiX|}EÂ~&c˜r|wg¸w#Œ¾¾)BòÎåªÍ›DñÅš4|²8ì¥Ò é|ÕXëõïñè‘R€á ¤­ßܯ1½$•yÙ>kï¶òΖËBÔ—žC»õ ™eœLMËÎÊl‹fDôœ—r-Û Õ¬L½èW7FêÏ ¼}¢_ýDÈæBjàÊ癀¬;ZÔ]a>¦ë¿Å4OÅüÒ›v³°%ˆå(ºÕíIÉ£¸|o4Æ®Â\HÈFÊ÷%%s2Qö˜v†6¾6£?WÏ`q¹r„] ‚é^r½|'žÄÉJüèw7’eN*Â:ñ,YQ¿-’"<ºZÝ+‘ÖRBß§òèYjI-Nê3«+MØ;`CcæbRàü®TìNª~_P`†È™v„ÉS.hä&‚ê b¸ˆ ˆ"¼C‡僘Ø[½NÈÅs@:²C²R•¾Èºç^çF%íÉž;‘V½Ûý.²sÄ[êŠnÂò‡{ô•b»Ýí0-Ð*ð‹o'ÃL`î%-£`Z6­ùåÖ¯,âÅLúé$u'æ5Úüt3¹µEÕG;w7o„I킬g‚EÍ¥èŽÀŧ·˜@çêôÿÅN¡Ø¢KöI;–öŸ §iý¢NtœZR%9QåõÍ¢5ÐMPr -ÈÆ„†|ÝLöêÜÖhè€õðÞMâ?1縉ªF^NH.µïhñm«ª3í€r¸®‰ïfR G¾ÌK _„›Œ´„ ñ®z¡5ä¬y'€P¨ÊĦMî›5RÐTâ“Íw:z‰ÀÈ€¾®†mŸÇãL|Ô'Ì»¶–Ý·béEFÉ=®å2ÕfÑM8Bwû¼ï炃_A•ng.>FêI5=o7sˆÁÌãÉc£©éo½g Ì„``ø‚2圯$}JñTã+2ÞÇÚŒëÛ«Iÿ#Ÿõ¯“Ð+I,rèÅÓ‡ª&E~ëÆì:$'j…. {UbÙfüÝ:f©ó;uSÓr‚ž­0–õr647gyîj­)rŽâëÝáé%zAdXŸae°G’Úó7Ïò!Â6~׬‚ÊKc$Vù’+³¦v‡YC­”é÷ƒYÃÓðv²p|Y"Ÿgdí‰aÚpˆáB’ò=wõ"«Ou2Dó9_0³úáÄbè½¼Q'3«äŽæ—Öå‚èðȳmñæ[)V½äX}dVÂç¼2$À©VKAŠYUwÌPlD*,uTô"ùêĽ{F4£ŠkH:ÖãóKUsbc“Ã黃‰ 0œ8ºËlèœRg`˜nÙOlØÜh,Éu´P¤Å“¤…ÉP}™•û%0 +ëß•bÓ¬ÃП<‰8/é|4:˜3×ôCEŸM*&}4ÿP*äXɸð€Z(çR!ÉôQ,‡RÿSQ—PlcŸ¸BKh“ü*ŒðRŠã®ñ¢à³®:KÅø(h´ F ˆüAG]$Jú}Òÿ¦éXɈ…›ìG9†§dH›ÝëÄqÞͼcØ£ ²ÁÙEWXÌ –ô L-4:o.ò Të,‚·Ê[ƒ(ê-êP®ü2WAÃH]éÁ>È×âu)ꆬÑ\X®l¬[—[΋õ×ÌðA€_¥²é·kN›'‰˜ ªÖ$Øôƒâ­Y«ñÍhæð¿ý\tŽ“lÙI ?rÒó‚c¬=ó×´%#Žª[AxçEê¦'¥WËñA–UË_ÿI}x%>+Zý©8‹§FoUNÐâ‰ÑhÔmjxùSs”h²N™€ÐI¹”ž']vIjT:q6—Sk*9jµIXÔïo4¤å\Ø>"4“ZI 3©owBÚ1EqƒÅ9š>8Ÿ†=–KÒ±ý)ùw¤“](iÂ}K®ä–¨—]ŠÏFèF(cEwS¦ Iäý´\.K‡cQ‰Ê¯ Œô#,¹€šO}ØIO•ga{8BͰœ[’³pÄy-ȯQø[Rn9v›Ï 9GZ'/$qË»ã] pyÀ¸G9œ ‹ð§Ž}Þ…iÅv¸š»ª] é°Qæ*tZËÁ-ÆòTaX§n*Õ+Læ;u-RŒ©S ,X·%·ŠÉ‰Òެeׇ‹q-Éø[÷ˆ'[2ÛÏìå^ÉÀ–Œkñ­¤Ë¿ðη_ö –ZQòùÅEeúg©-q0ì 9XŠJdÿ ¶áPÖŠAa¨»€—‘‚:TÿBÉWÕsÀ@ÞÞk×RhN¾çox´R\æ"ÁøÈ-%W¶FzWçÙÄ/W“üÛ[ÅwS7$*å¸0§¢ ÅÍê-¹U%LV…ìׄ×Ü ˆ“ßÀ¶è3K æåS1ÐPÄ%ÙÅØ9ˆaî`X×Lb cAè–ºö“îœû!"Ú'>Š 74xf×}Q%8äùW§wóhÉué`áýÇÉ‹X»íáµà€Ìžfþ¼Ø™*ñŸHeNV§ÂêÉœ)„#àçFLÇD©kÚà©©Úä:hA½çÏQýïvUdŸï¦6† #?”.üëÿÿ÷ÿåâ›Ë…qÒ:Ý^|{5)ôúWðv ¥õ S º^»¸Þ-ƒv»e£X®ôü Ý‹ñ¯ÛX‡år‘~׋^ú×óðüËó¼RøÅ „|~Pô×ÿe¬ÿïÿ_ÿºOàÄ1þuww—GMè²|¿úþÿÒR¸È¡©”=ŒïúnÀö0ëå‚_2Ö7ªA¥lh"FeŒ(Äö”)yã=P·_Qò.þÛ@]M„àbò¥ÌVÛ¦ÚwÃó)QÏ KôP¦MΗ@ØûÔîÆ$¨é/ăÝcÂ?ùýÝ×Ûï¶Ý 0EXiÞû†Re-Ê Ðb•:_/åý¢á«¾_õB#¿^\_7¬£xâ~?P6›­CTR¹R"ñc7ÉíÆ‰¶sét‘ýØñ£ýÈ¢.«½××Öª]K™È´ ±mÛ9ËjGíÇö‹ T?btpæ"Ùdæèõ°ÓµÚ9î¶ÝÉ¿ZAÙ¶gµ~ÏZY[K$ß ·íG2z·Úù¼=jÀ¯ÝŒ.íætŠÏµË¨‘0‡²{dlΚ5­ëòÓÚéé]nmVkGÞ¬–Ô íc¥öMt£:Œ l”j­å°Á=:kgk¶C%j¢É›™µf½…vÞw‘×r‹Npý ŸžÕÞ[œD¯Ñ[+vZöã®á¿2¶\/tK”2ƒŒ·Qá[ãÛfó¹µi¹ÓÓÓ±{a7¾½h>6ýö§…½·Ÿœ²ùÜÆ·êŸ§§ÓS>ϯauÑ–[,F¥‹ê[«ƒ u¢ÎtzTÛ±:®W¶Càð¢N-t÷"¯¶k„³Ë»0:Qdú‰ýoG·®¿eul(Ò^]µÚ ¦{¥k±C/vÛ8·øÒ„&jï¡X¹e2M,cîØõ¬D”´klY¶ëÇzñ9¶g¨ÑœÍÞøÚßàuÇ‚a`ûTæÈnÐ$ùaÝôC³j³É•„nùòúÌ;sJwU“ö­éTvª¸˜eoæìU×àRbLŠ£ÈóëT,´«a#nξ¶lö¥»¥ABñÌ)ŸpQœ±õšÓëz7®wg…NLý˜9ªjU·ÜøÔ)õ“zó8ÛÐì¾ÕZ]m¹¥»z V¢ÚrBÈèíAÆ6•‚̨sïzߣ¨T¶a#ì4Ì.ÞêêV£5šÞL&8m\Nô8«u&£x†ÿàØ·?YmÃfqÏjÕC÷K5„í ¯}è'pZNê°gØ‘3ì±C«gµ¢ètÍ??]›NéÑûûtÍ^] :0›ëv }¢eÀŠ¡ï¦›XňMpÕZ‰Ì↠#^‰>ãÜâ6ÀAðòx,ø×õ„Úné ”³k8[¦YÉ„q†.%ͪLèe½òJT±ã\Ä ,,W T¼‘Õ›8›W°ôSö[³a…Ñ,´ù€ÝÙà/®%6q «ï½öîaœøCUQÏC±è• S<ÛÐKøæ–?B¥Ÿá0•O 3©ïÁªÁWËÛpœÎ[Þ>84Xx>}ÙËoæ²,ȾÐbß©Ìv¦ÌGÙdéˆÌ”³ô}.çÁ\N×Ë=¿R™KƒétËjÀœ;þw òmÀ0Ÿ¡#Æ¿…;AkÆ›×ßµ o¹Mƒþ\σ‚j®wn™®kÚ/òlÔâoµÝ{€º»Xw–]¬¡ Ø‘½ÕÕÈ<€Ù è–‡Öí”Î3P¥÷ôk¥sžLÚŒˆÄ ¡ø¶‰fy„ŠD©‚a'êaŸÍç&,XVõƒh1ll7WpGâCôy†¯ {ôæ~®@?Y›ÀÞ­ñÄìü˜Átè“Å-Ú¶ñ±E€•`Ã~u½®Õiô›x CR£Õ”¿î>OcöÛ6ϸ˜SBž-ئ[nðšgßéãW˜×KzžÁ$ÃÇ3܈8‹'r{´”Söy=lU-p`‡¾7Z‘ªökË݃=Þ€Ÿ¼SsËÕ•Al[ *q0`xns½®D-B:ÝdPS°äïîøËvĄЂӵ:UBßHq ¾¥WVbõÁ³»÷b}æ„ÇIÕÁ+3ã–èª!f¥Úc¨ELPC¨:Œlú/M‚§nÔvËE§À¡åx%xóJŽÿ~ñè|™÷¿˜€wÏ´ªýÈÿRïÂáã÷è)çU½’»Wëoú½Z?—cTï•`étö¿Ú8¯š;nŸ9=ç§}]zá9Á} W‚{û1¸gBó Ÿ8Œs;¸w7†°L€)áˆÞ±z¸å ʼcÓæ—à;hߨA.7xk™¾o"Žzñ?ÖGg&ÛŒ“ñü"¢#¸w$ЭóiýGRk¡@ @ìx×P²x ‹ÇÉ{"wù©äÉ€e×:t·¡¡ò1Nɬ&¸¤Ûñ±öÖ([}GÐE¤Ý‚ëÑ‹«øæ^õ£ãV±ön´-·t‹¦ÓØ-âßâ[Â5êTÇŽéøîßÞO»°•w3hð*b²é*âa·"oƒ¦êqæô#ÏFaÃÝsŠ÷4[RÈ¡²k?BZ«Fù=Ê_œ7K~âù­ Kv¬½(ê#¢ kù|öÉ|¸Gè(N@¬PW¿i#µˆ8”ˆW¯Ä«ÑBbÕ¿C”Ùn è÷ïìò<ïWWý;jrˆ¶Wü;äy°Žñ r9ñtjAò´Po4«3ªdtåßÑÉÅùý;@š-dʶ¡¶3‡Óæ”pJ#‰SÞ‰ ?óõRZy•¯W^N½‡iùÕ´ò#_÷þ.ôàÒhZ¨ñÇÊ-o b=$6‰9Ã;¤Gà$ÜÒÏ2<÷Vˆ/ƒ¡Äî lQ˜ùFË߀ñ7šõ·„šãby§8P(Ðõ^S)¯ðà_`aÿ'%ì{m@@¢;ˆ–ƒKbbÛŽhÏ”ïÄž9‚ÊïZÒQù5ï>ÓŠ³¦h0’½QÃtÂl´#$êá ®µzô®R¥øÂ¿s"Ä'ȸþȲ# ºñ&åV‰0c›°Ì#ì/X§V½4ª¶‰úhF'ƒÍÏQ.WÞÃ3•hBï„É)úelñB‹´F§ `¼ktêIB5¨¬ýT‹-AR þgCVÐj¶ýÉ"‚NfñþÂn¶lB‰@ÒÎÞ?zŸ±Ö7ó¾ u‹œ_éÊÆ?Ö¶=K*1ŸÙAjP'ìÎuØÇÚÆ’{||²ºÌôÑö¿²‹\"l—ÐÀëb×%ßaÿ¥r,«ë’ëê:ø“ªÁ-<°bTÄu}˜<˜ê5ü–ËÁÆ~Dz¥‹ÚçuV´'àúTˆÝ¢Âľ1Ð#ѲºÚFR+ÆÝPÞA¨ïØu|ÿ/WË{S}$J’V 9²D }BRhœ+Ø€Ø^m3®fyãǘò¾Ùø›‹èµn&´v.&ú“•«â”9j­°Hèm|O·G»Y¶Áì[[P³ U'€èØAû!È@«9"€‚2ñX0s1Ÿ Ò8ÿæ"»Ïîø©ñ€k§9ãiµõ¼â3–¼Ö–@©‹s}nN§øàýM¢¡–ü=ëU³to:¥38‚vLÇ«TÍ`‡RŠD©zÃ,uMÇ,_šÍ*<ïàsßlÂÑVjYˆýeÆŽ[ée[ám´òëhOáÂÀᤥbèšY ͱ ÓézÍú濆o9³Ø2E8[ùÈßp+àGÿµ 'Ê•ˆ¨/àüÆÎÐZþU9¥”ñ{Ö:R4´(±˜€æ¨ç\9—¼¿‹øFl3.X!Dè_‰þ‘F|pKEX¬ÏPïJŒ¨¸ä[f°mÂæåß±®pzL¤\…>v#’Õ|q0»ƒseÖMϬvgÕú;««T²b2ñÅ-­×ðOd®á‰~5ùµƒm¸0ÛÅ~¡oÛWÑâ ËÕÕ/ð_ãªiw#ü¡z‹ãH—0‹}³v]Sa5^æÿnÚÈXäŸy°½ £‚$µ‡c%Ñá ÌJ϶‘u‚A_±œð (ÿÆQQd ¶9d†#ˆvÇö·Ýò9¾¦‚7I"@.)ûñ ~"zq¿¸^¥–b¹®Ç=¤ø ¸€÷^:å2ÔQ.ÁcMüRøŽß£.îX_7> <É©*s¹Œè¸ „Ã9Àõ•sŽu_ÂÚÔΣs–rÇ>ÉÿüÓ5>¼îœÄwçJ|G›öŠ,¡ó•1’ÉqvÇ™7wÉA Údá6ɺëöéiáÍY‹;`R ¿YñÞ´Ø›†ÛÓxgZ<ž†/§ñ«i0˜Æ?§ñÃ4þaäÙõVÎ…›3׆_“¤9=&s: °Ž÷#:OÄBˆFWz$yÚŒo‘‘hx޹é¿4Â;èwxwºöpØfÁùÂDq¸Ì;RyÜiI©Ã›Vü}êûÓøz_Nã¾]ù½cοZȵ@Ÿslú¾hס²Zªõžik}éFƒ¢ARjãâð›®C ·³Íq¾ð»Í÷¤ŒM`ÿ½›ž±Ç#n¬;&¼–÷~§ 0Œ\·á7Q–ÚPÉçm˜wø\:ÖˆF ²CÌÆ‰dÏ6×ëPÀúž~Ü`RÅš‚h ä…ÁxÌ]Dg¸ík/`oçó6³og à± )|"ÀÓ3JøˆX ÷ݸÀ´†UoXçHÒvxuáãóÒÈO$oí°Œƒzg@%­¯®âÑp‚çTð…šo$ႊ $pžUÆéZ*Ù—(ëéàQu‘dì6 /…ò ,u›÷•Ai£|¨Ø(þa'iÇvŠëQ›ˆ`ÇëI™S­uI‚öW£‡ÌR© ^ŸBéã´Ø™~¡ÉèáÜôp•'œyœ¼r?Éøç{U\Ç¿XâÐd&X¤¥ÆRvxcq`ÄÞéÚÄØøbl|6kèFÔžñš©™ë¸a #ùÉ Qʈ™‘õìQ«ØäÆÓŽÒŽ ‡éƱ‰šêKÇÝø• ø÷þy$Š=R„~:¾]å'œc@~plx~õ\4Ðcü/ƒ~yÈßoGÛ‰.ìžZovóùé©]@Q\Î P CdÕlìÃÉDfس¼‡úó<Ôe“È«¢ùÙ&Çï(«[@õp*À ¤r€YP9Wc®©ËؼՈó?áãÆÛO M¶œH'¸œ¤'£AxÏ¡Z2÷LÈ¿“¨¸Mf­>ãkeÂðÞ‡¹#¡þ'ü[Ü¥çKeHÀtŸøÊêÃ[>‡y WRÙøû’*fI*ò91ÉNåéãéE-Xã~mèbÇÿ$µp\âØñ¨†i µclبãXª‘þ¤DÇ3êÊ¡ÒYTñœ ­ƒDÌ)oàßw‘é-§õ —¬øCà MÄŸè ÖÆMMg3ÁûµIy¼yðZ(;\ÀgÜJ;5+•h%¶Ú¨'j­…µ¶©I”_°T²ã¨nkõt²½YÛзå:¶Ð¬ vÊ ;È+6OœÑ‰ú#Úxån¼d§8z,½ªZ?.ÝœU¯nýj¡èkŸ¬ñ4,Ù"e7·ÕÍpˆÛÌ7…0&ôª+â 8ÂuØŒå¿M`ªæ'Ⱥ1€Ãlãž¼7ð$põÁ }ü3„?ç¥g:]øíÀo ~7Lœ¤„Ë_5Q 0¼aU)ŠG$AìàÚ(%éA épûoé‹7ÿ¥x…_*gëâ•¿²é"ÿ×$½ôƒD‚pX!/êT¾d?Ý£~äc’JÒÎÊgxm·rŒLåÈ=*:åf‰féöB”%Êt–“-A‹e‚ò‹¥)VÚ@ÒûžLá`,˜NåcÕ,Ãð» ï^ú¿‡° -“›oéÍsëÞ†&S^¼I·x†´H*›®¼ç  ãÕù,LMT¬¥+R"TT¾7$ÆçIÝ×R}O¦î%© )ÀOÀ‘xf]TèSV_,=Ê´ˆîÞÈA¥¶;B5ÕªQ{‚-&bø¯ÔŽîŒÙC:]UâZY u¼àJP:)ŒCÊGP0“GÍkÌóÊÚB•‡œ¬†Y~¤e6‰üo32i+¼"¾“J¦rZuÅÆ¹^»a–&pöIÓîÔkA☓íIÙ_'ÙõÂU®û¨Îì;ÿå ÅÌàpY~<£eðûZ~±íªÔ#¹{ØÝ3Ö™´lÖ%y½BcZ«,‰¢Yykø%yÊÆÄ'#–S°êÄ9¼¶N2ŠwÆëH™rÁs镽Yy[7ƒ¶ÆèypoNOÅ?×hQßNO+oòðg{.“SÞüWFñ‡e~{iãç–™{3s@_8åwê£Lµþ´õ »I†ÆŸn³.>>‡‰–ß²4éØí;×8Ük öa©ž›LÆÆ&D›¦²ÅH\™þƒ`ÈP5«•-=Sóº4óë°u^§Ò_Èô N·©QÔJ¼E‚aUiä€4Á:ŽdV´w£Ô2 €·´¼ÿö)wùu* ú óÅ[SGö$<N²ótÈr¤galŽùJÇŽÇ8šóU~jùVRùîO+÷b;S~~¯¨r±Æ1¶ èÎ-œ¤(¡– Q JôVEYFçTÅ´Q ñÆLÒJg”™ÿØÑÊ¢Øþ¶±*QÙ$ ËF¢lå.é}ð ãS2:|/¾KÞ‹ï1j£÷¿R{tþ}U¦GÜ“÷dæ”eZéP¥í«´}•v£ÒndZ A3ø¨ò U¾¡L+¿”iå—*í§Jû)Óü±LóÇÉLÑ ¨¿‘æ …âñÔ9-?Lý1Kb÷ÄÒb×dRƒ‹ˆJÆ=˜Í‰,~Žâ"­\e¬Aßk´æ8t„²\Ë=ža([¾¯6 ߬ÓÓ†m<ÿ?u¤Öîò@­Ï­ÆÊógßþ+N^N×ê& —„5EØ›fÁ‚U[ÎǬC>Ìâ0Av½ñÍB}#®(Á2U÷O¨>ÁAM'8£·…eœãM†EÓ¬ÕÕx%ê )Ò:%1g-¾g¢X–çñét†CùV½ ŸGUb¤½‰Ïd 1ÖKg(¬×&¬}³wdm†««C¶‘ð©YFC€¡¶1$¾ˆäàÈ9Á~N­­DìþûE“Ú„…Q$£¯¢Np•÷ë(¸@ÛË žÜ°Â'€½&±i’l¯!…N¤ ©G#|Eë´v µÎþ[[SmX'·•NíĶGÄ ØµN4‚nÐ,‚¾™£iàþ\G½êUt0{ÿƒ•m¼ÈýWÓ¦CO$»Ð‡VÒeÒÙ>ÒQ†¬Ñ ¡vîþ5 EeÖ OÜÇÅfЯ]0û1ˆ®¡»ÿÝÅßœYï 8Æ[¥_â'«6¨ ¢r H1N ›5 I£*VW/gRÛv2´ñ?ÊL6æ6Œæc€²nZ3ž^£d†lšÈ ‹ºrEäϘc’uì0"˜Ýq‹c3Á˜?D xx@µ0Á¹‰[þayŠfïIb\~óvÒÕ®£Æ: írœÂ&d‡Ì»5•uFg.M5ËœÑ"E§Ñ!É7VÈb³?Qf†b³²'mæz$T¾Aa²gщk«Ø#A«uCDüëÿˆ„bú†l|©ÌM´x¡ñà£yº–ôÜéšÙ<]sz÷f5ºAQކQß ±ÂM³ÚÀÁÍ:ÑòZß±@ÿT1¶(‚ µ¨%ynV±áYÍÂÛê*m‘¢FÙ0˜3˜°"´<#‡ro‰ùPÓäš6f(]C9%ª¬xK¸éÚHövÇÂÇ yƒJ¦êúk6Šº`3±ûÎI’‚P%e€È&@ŒÐ|µ\‰-w"òuXÖÒ<ôÈíþN¬k@j0”\ð]çào--HF@@,£‘xo07Ó H,¢}uµdÚøÙ$Æ‘ƒDdÝgeBGàÀ‰ÀÕ“ÂÙ–[¾w®UÓ7ªéëŸõ-€“TY¸À°WjKaw-ôìšw½X¨* Q¤Å\O6k$«Ó<Ó¾AŽ‚5²Ýâ &}ØP€¡éŸ¦-[‡V2@s#â6Í)Pƹr~Fqƒ$­X_~ ã?I\&„­þ×w Èþ b‡^§S¡M±ÐþUâ+?§S|Žàå'‚]©É +”²¢¥|£(ó“©ÀÖ‡žÑDM?ià˜sYµô<29ëE(ŒM*@û¼oçö µl€ñ³™6EÚB1¹Rsíдy^T°ò@OÙòÜXÀÜœžæ¦y»N œXd· *ÓЦç”ל’ó m`b« >T¾-Á‡’€ˆ,ÏCåþøîÙv~ÝéDðŠŒÂSËwÁËçu¢  Ì@uxöx$áXé6üM´yTÉ "IË¢skà¿Gí\®F…àXÁ]÷jîE$-¿À°kZxÃTRB¾cÿ›rï…`ˆ“ÙPÊ"×àB¬Á#ÓFå· :=XÿÖˆ°õòD2Ò;½¨|k™§SÅ꘹^άÍL›&P£Ä°±§¸§lŒÙl÷qT9“ê… Glª ÄH¿¡ybЂxረ­‰˜—;ïMˆRó&•‚Óë2%ØEͦG«QoŒþ8Êou5—ëDQÑ; ¡ý€å #Æ{ɲ<ªuY]ûcK¢`×±˜ãkÄÆ%=ê™Cf:=©eéI-KM3Fï¹Å]˜H¯…€qæúEÿ Ýz}Çê®ËÍóè¬v†VŠp°ˆå\™•BÛgî>œyi=6ÇÃS¾8hÃæ½•Ÿ½·Úgx.°¼[ȱù&ú_ÝÒ%©G¾ºÞ[lÎÛpƒ}÷X4 iÇQÄ;ý´=K[Z§¶”uj+B±tôlTiY.Њ´Àü†WÔ²?wì¢xt‹7hšÒc{"šÙ`ÏÆ?(hzë|dl ÄÉÄÆ?–Yš9üÐÖià¼6a©¾2ÉÖa½è3ÐóŪçøe´#‘Z×9R­[äÚuÕÚá–ÇYëò ;Þ¾SB—ì÷ÏY3GÚpIùœ»•kÝæóÈñ3T{õÑ ÀƒjÎrÖ9±ÚlzîÚ=$ÚP»ü Îîyzv[RP'¶¿Q›-Òûdd†:)ÿ³/޼†ÖW¤p£ 0Çì±Å9šhŸN^[ª‚¾·¯ 0•ìí óZ“8Yž–ç%.OW-O×-ߨø6¤˜1:¹Nðe€Ÿ¼N©<öÌÛ>×D_€á´gª3ZO‚´RHê…s %I¶)–H½`d^=´;у=ÚGu I©IëwN„ú iÐìG\€`l­;yxè±<Ñ9º ‘‡×µ^Ë9jÚh }ŽÊ÷ 7?«X[7ä…çmY=¨g:ýl;_£•6YRÒøÐ¡¯Ð?4ry<¬ž;þ»jÏ |’̲{'Н«hvŠöÂP-fTÃatNÖšôR¾Ô/§¬§MY+"•Mõž0µ!€0RÝ=çt-&g.„æâ2è5h½Î›Ú£,NKÏçÓW øˆÖˆ$ÐlûֵϹ[¨-mWQaDþ\€{ö…amäí£ 5\]=C³@r ß•e½z OÁè¼Ï8™0¬(›ÍèÃG²ÑD ”8ýAÅ)õœâuMX2GÊå+4ôZîW»T{&ø ¦3¨à&ƒð(¬Ô‹V‚ ù°”¯kÅktNP>;hÒk7 ”àgz‹×¼o‹×À­ÂK=d»aïû±{>jC;ûÀ£ï×<ü‘—'Ýéöi®x›µJ,²”}g!p³/â•ò[A`ˆÈ—Ͱ+ÃjgFt½Y•k£reT. lT.Œbh”:FùÂ(m•¾±oTÎÊ™QÜ3ü£¥ £Ò5*-£T1Ê=£•ŠQ¼4*¡Q)•¢Qîþ;£øÚ(·C£âÏJ&M£aJ )'ký|ͨ‘ãþ„~kÔå‘ñ™ÔG»Ãí¸•uXOpòù~~GŸÃ¿øásñu„`-Âùïlüéeá늯ÂåJ|Á÷g/^¢™qqÏÆG¬l/¢ u(ß®â;ÕPª “¯fGè´ÑÇ-¡Ûø‹ëYB@*ur$r}$JÚ@Ô´éqÝΣüµ…O·ÜÃþ]ȼí$o[åñiF J@áA/Š!éÍC´"±ëø=,Ũè J‘ü^Šyh¥ êð¶Ø·íšª †8æR8=ãU¯îUùɯâ©X÷«ë¶-tÇÁÔ¨·v‰ålÿ b†õÌ“ê£V‹7„»J%Xœ]À`/Ù˰s°¥¾&y´“$ ÿÐ2Kéð±ã€¹°ªŽ…ŠÝ¥…ü©B{Cþ`Pè £Ñz°eÖtʇ -èßû_öÏKšzÿÛý[\è‰þ½_Ø?é(‚zÿ0ñ&³ø—Y‡åø"R«¡¦$½$ÐmÀ±;->rÄñ¿°«‘°%' $(Àb‹­–å€è†.Ó[§KuÑYÉ QÅ®žtNÖ‡ o!:±Õ@R~ ôÐ9YK¯SYÙZˈšµäví_'>¨Þú° »ÑßÔd‹a°Ùă†Qüb©táîZü;²ð/nÈ÷aaIÁ\70Jª©˜N?’?Wø—>^—Óµ`ëtüèå=¼P÷„%mÿ£M¶ÙGÎ[#/‘ý.“ø%„/<åÌ |¬~t‚—U´D ®Peø—¸A¬ŠmáñÉaW;lɦj‚—@$£=¹Žù!QQHÝÃIÿÖÀB¥÷@ßSuG@’³Å<‰ñÕ2Ëß~ˆäŸÆÿxèYyd+]è×.ãˆAÝð‹ez/M:Í8΃WÌ8ëˆ4°6$z,Uaª±TR„Ôß"¬Â(ÐY9dÏ}e1 ÿÀ3»„"{þ’'r9´ÎØZ÷Lª*—&šá ©z`½PTxÆo뀿fí¨Ò I(núL¢“`À,tjØJ¶ZIi–ÏÌ2éaMyá9‡@­£ž¿g:ûՎ㽓{Ÿ¼ÒLï«I1Ì8¾=«_ßBãÖ…&{ ºÅÏ$ÂÜô®E¨T¼ë,Ф€}]þ>Ûµs±\_eÇMZ!ŠBï 7Rês膻a£ÝÄ]õÊ’9ÈQÍ(E 7~ k>³mtá…-?Ÿ€þ@gßé´@šHV'†î `¼‚7šz;Óà£L<ÄðÜ’2áh]B›Ä|®J·â:µ” é1(¿ÿ¾ÃЪzBk†qn,epb†opÇ ß8á–¾vÂWf ććâ=…‡Àú3`¿ŠˆvdÓ”ê@ä²N¼TFWPGyŒ‰ÊëU„ÚÒßné# C1ÿ¸ºî„?«fñSá>ßçƒ/ùøÎtÂ{Èxðg¿úÙ)ÀŸà#ü)~ï=e÷ß;†7‚ݮѷ‚w]e—@Ç€<ʼné\{ð“²cŠ7¢<ñØtŠwUóyṉrŸ(£ Ðpl?ŽÙ[óÀ;â>ÒxÆä­{æøG…èô´n­NŸ¡w…wëì;‡Ñ¸:R7îXcwuuì†÷¤±‚7¡Ë…'ÞÞðÀù<g?9/9óóã |‰Ñ”ÑÿÛ¶ñ9Y2©M캹jVÍ:ÚôŽÝâ‡éÔ oáÅŒêì 5ìË“jö±’ý:üŸ£Ò‹ רO3Õ?xý(%ë›Nõ>Úg4ŽÜ+0âød{9aÁëÿ협™;˙蹃íÄW±è:x^›5¯…ŠR¬ý(®y_Ñ\ y2þàù5öa¤WÉŸ£Ü¬¶d礲£€ê°ÿÞ  ›~?òœD$PÓâNÚ£¨J–=,X0íÓU;¸ŽÐ¤€–Þ1ŸÅ7Ðí è¶/‡t™³¬ËˆÊÙõ¥‹fB=P×`&àEµÿ‹õ†Ì5œÛÏTÐ/³õ ™"Eú×jÎQ™q—«¢2*Âx×ð·þ'ÚÀÖÒS#Ú_] Z¥þ㳿ÅϤî„}_ñi—rÓ%;vÍC÷Ü-vh ¨pçP|áI¤±†+˜~HEaX|&˜î•+TÐþ<ª€RÏHÙW(’Qp ÖyÖGŸßsDøž?CmöG’Fx-7×ýWF8¶Ì¸ëÆmÓ®â«Üª¥»í–?Y‡vþžƒ©øDRÅìWaŽa¼í_A­­|›ð-ü)ª<’_6ò¥Où¸‚dUñg«hÂn‹CLjËF\2â¢Qz_¥ÿŒaˆËý•ßø;¿q§J8R‰_± ø+;lÖ“ÇœéˆÑª˜äïìd;@Ï® !]ê Y*ÂN>-„WtX~P•Ó+Ói@©&G¥‘¦¡P袕vÞþ1®Ï5‘ëpô…(V'Y¸w‰ï¨,;FUÙ–^XmÔ‘•ˆ¸¤t„ ϱ‡ {HÀ`¬©¯H.ADÚØè´ŒX´üçÄ…Ù8’ƒ…lfé‰Û>)AHƶ[Ú…Á¢˜©éÁÆÑ3Z®QÄšálFAàl6Ö»`‡…Œ¶ðy6“/¤í*îÂYêœÃ?~±náÍÐÝF¡+M3éŠ;M@˜ºó>o| ¸}Sí~F:’:´ƒ!“ߨ5‚Bï+b³¯Ö>õ.»z¯åêað…w²È;,òÎj/,òF-¸B0ù<ÂI’eÇ ÷J?Çȳ^ :صñÅIs•oa 8[»h˜Y"¯ñ÷ð°[:äPƒ‘?Þ“*ÀÙü÷õØÝØ%JæÊ¿ººLª £sü LÐÞZ°ÈmR…-Eߨ—)HÏí“úÔ2sûäÉÃÚÚf GÆl¼ Z˜|‚ïl$lcb•ÆÈü·M 3G/þ=ÒØ5öµ'™sLn0M Ý‚&RTW„nz]IE¢–ù/쀎ouükï/Øÿ1¹¬¯ 7 ûëÈ£äLA‘ .Î{/ýã,‘§<ƒ´¿ÚC"ñœ½úÑjU)2”Yõ”U ò³ ÝÒyå)|Fá]”%©ŒÓgnš9hN~ƒ¸ª2À¶'KMTcI*WC­¥qaâ%\‹9ì²Wmâ@ H¡â@Œâ@ŒâF!yæmáP®FQÚcл/;†}Pí…æ}ýk–[©0‚ A(XZ6Æ·«(™S5Özæ_sÏð{¿³ŒV½Aì¹¾ã|×qh¨TAo“dÜ©µãQB†7 3$¶e Þˆ [sÒM,Ì 5‘–Ê,1ÃÓÌñÑZôÒ¹@%=ëÖá8 -~G~¹qîe<{ëæ~P†ág¢_‘ã~9G´hpno'JOŸS,Gaí“uƒûðË_6nÐ: ÇÎt*ßߣ¾ÝÛz{€îI˜‡ðxÃQ¦Ó„`?ö4RàÒsƒ B˜ ôr‰=•èÞæŽåŒ \Ä€c˜?`Ë^ge>vy|*‘’¼Jo˜ÞtHý:ÁU|ë«]ýFqjS^ÉrŠm¾µÀ?µÝ/±í¾§_ï‡]?óÕ¡Mœ×ÜÁ…G[;¬ˆàà:Ž¥x]íùDDÕ Eµ‡á>uš·²B'xÒ"ÜÙ+É©T÷=[ ‘l'±lúz²þµ§¿ö,._–ôF×ÖO6«Ñ—S§þÙ¦?Ÿø ¯tc¤âï'¾Wöný¹0w¶“0¹´ÔíCôÝ»"މ®nÔÏ,ïʃïT±}e@où®YÔÝã6ákëO··VÅn-h¹q›°Hïn¼"@ØÇÕ„Èx¯U¾u„]\[î4÷Ôy¤«à"L/ËBCà{º ’£Zåó‰°ÉàG)pÏM³N2ŬbûÍÀ¬)ìõ›ƒ®CÙP_4z{À™~b¼U{øøËaû刭ªßü;÷¤åžØî¹^jÀC#g…íBã#.3³Ó×3¾Û n¤ÈÙ RIK>ÑßH&n…à}¡OÕo¹m#ÕJK EøLñ|÷9OÊFz—M³„žj=}hº|á&@¯òʪÕåÌmrœ”}¯NJÜyq§v^”´½4-xŽ´“2Òº”Ö8Ói{YÚG¤)Iµ\íIœ%$NûÅ×ý‚Ìø„ y°p¦•žb=/V+Ô®¶ÚÁ³\=·U|}¼ý¼X΋”»þâ¼x¡Ñ1uÏ‹µÛób©ÛÎnÏ,côþ,¾Pk¸Mœ|'Cên×ÙñÌánÐR«åá;÷Ú#ùÛjÊ…þVKŸ›§Òê”{­ÑîJÏ‹-úyE°A÷jºêŒ|z<^ŒÇVú_œØWÝîâÖ¾_×Wëãµë/ÂtÏãwÓ{:]>SEI‰‡—oçëå_j}QØ©èNEU·¨ºÒ²¸½¯Ç·÷åSj}•d»’Ú8ɵj£UaS ûEŠvó»˜È?›Jþý¿a?ÑÁB é‘|æÉ(š — ‚å$˜ ÚU‚Å ¢°%ýïýé<Ñ¡Ô>K;‰·#ʇ€gI2™†Âp¤(^$ˆÓN"R.»ˆlÍ“é ÍÇœõMô'I8Œg#\l6põq²œ ± R|"a,ßP™$Ãd£¤Ç e‰nÞö“Ù|:cˆ§ý±Ž“èfMÂD¢ÙP¶DE "‰„6\$ ôñÔèÛ-uUÅË"õÒ£à+¥õ.©I4™$’,Y0^c@“ –Æsœ FÓn0¢<}ìß$ÇáãÙÉ P2_£ÓÑè”_£½ùœÆMÒŽ€Šqp““!õ(J8d»B-8àžÇA?˜)A= lêË$J¤&"–ÒÏf³hþ, ª“xÎ ‡±&ÀÂ圃¿'oo:»M8ЧÂ#×õ$šïk"•°…É$ÍCúÝD=ô£÷•R3A‚Ès'Ãî˜yœpêíc°ˆ~¼å„~C ]Àùâà”ùãjQîd6Ÿ.Iñ`¢„fÁì†ZfÉU<çÌCîKßNzÉL¢îKD¯„ÆhÞÑÐO€5¢0Öoˈ:«bÊ1)â#/L$ºêÓˆ¦i”Lï’m“º?¼Aãcô|4 húÎçÓ¹Œ2u– S“ÃçŠJ)}i*žƒ@vãê/TŒe:$@Ð<Š©pœè(IIŒàMIðaÂÆT®G¿gŸ…>(žSmÜ㘹 !nz4½VÃ~3‹"øŽ†1FrqªÐ: ‰œŒ§Ë8¢¢€v:¢®û“`èI?½=UDDZ, õÓÙ;bÁ@hˆ8É@Ñuçˆ"0“›[ic˜+Ôöœ˜ ÍÇ!ÔŒfò5x&_˜ÐÜ&j bÕ71Ñ÷ø˜æÄŒ¹}¿¢92¥yŒn‡E0HjíÇp4 ž0ICÆcêíÑlcS¦žCbDÅQÍ0iðÏ9a—oeæÅó.SlwŽñí„ÙvúG܉iâû0‚‹Ì#ŽAx*ä¯ãœêù¡fqÞøóñMµ³“dÉŒ9ú!ø1¦ ‘*q®!q„«4¨˜ÐD"ñ¦’¿: ­4¢ÂB‰0uH]DÁñ+Qÿ‡ˆjŒ/‰$h €"Üñ,‘ ¸ ÇT$*ÅðïûßÀœ Q}yz|„A.Ä.VJÕ#f—¦ò7Ëq—ê•ÀhÌü‰ ïþ.¤8£—^4[ðày ý„C"¼ÉlÉs`†0©§%x^äâÉeAšMxX'ÓwðTøQ3¡4BcÒ& 4KZÜ~d¶&_ˆà&u*”‘Ãp ç‘b4äa(¿ƒè3±£Eð:ºM¾F·L1TþÓKbÌá ÒhHþœ0dž´ä±Ž Ô´:b6°l¥¿1"uiÂU2³HSŒ´"EIuÇTa /ª¤9³#„’8˜Xј„•K‚n<I`¢×ó`¶G°†‘°AB "«jØ^j0 e¶÷óP ì #Ãê$—ñ3ÁhKFO3²¹°H’;Q Ét§7¨=©T’y§I|Í3bõ“”f‡ýôC-“Rdž'ŒLMYÀ"O<4Øsæö¿âPÄ*N¢Å‚Ú‰sœíé-Mþ!ÍI( "ãTÈÈœ/'2I@,ó˜ëÿ‹©ºý·ÇÏŸœØŸ$Èx$yâ"‹©ž!ÄEô#Æ dö%y÷ö䔨[&úÓé XJI>°ºA¢‡¤no´Œ1—B"ËÞ%3]U¡©uVŒÈ´‰ —\MIƒ#µ(-1½,»¤¿b(áÆº±¾’˜©!$”L ªi(Ò&銄$Z ؆èf6'ùJ3—c²Êãá~²„f$é<”˜à ‘ßKQ§Ð¢Â£bü§SÎÄ‚&ó„Tù€ÀÈ'ÂE!T ·–Wà;ϽIóXÌx¾PWDý -Ì nÝãŸc è¿#(Ä"ÞÁVH¯'›\Gݯ4Á›…§0E')Ý+ú–¸ gQŽ? ©õj¥†&} F³Ë 9báF½™fü9Ïky ‘áD©ž-ó”çÔÇ…Âý +æ3Ö˜K ЋK² Îó)I’./©:Å÷“=fÆŸ5{a<"à"†b» •MâgS «3˜*d5£‘À}:%‹„êÓèT¥ÆŠ•kÂÛW5çD~P½Á³ð ßž¥Ú:²A —Ö‘£9)«ÃJ=&¾?Ö8#†L¤G5ÒË6‰Î.¬~©4þ@lL$ öN´[ÐC¨@ÓJ%yMƉÈÏîx¸d™AÜZr0éE£§Ë®Èv}B×TÍh?f¾C£™7"³Á6 Hê0MŠÖõûYk<Ü +àüR+ôšá$)õA¸›š+Ôe¨ ѵÊÊß„äY|w Õ‘u?‡˜3xevÉÏg3ùÝÇ,%-^+ıô$®çU“7Á®ä-évU‘Õzð˜9`^S¯›ùÚ ‹c¡;¦lRÝÉDf”͘„YµbŽôUñEš&É‹ãS64 F&îN³’¼¢ÔŠ›œ^.““!ͣ䰟0¿Ó‚ ¼öôô±àäxHãO!úɾ˜° Æê°âSSQe{ >Í~‰eË¡ÁZô§¤â²­ÎÌî@ºQ½Ñ£ˆ´ÓQ ’\ú Iœtï.1©ÜõuÂbür®U °Fb 0šYQ~uòö ~•Dêd•e8°AÉtÉjвƒX3VÏA—L¡”M'32ÙQtØ©b“¢eWpç„ÕÖ—%ò¶Ž¸\sˆ¸\i´êÍ\Äåÿú¯ïÁÜØç‚†¯’ĸ3бÒëŠ-ãneÅntI8§ „52îõtÂQÄoˆÿ_[802¡†c,S;CLBz 1)QŒ˜õˆê,h2Ò6Œørº…”`°E…"y_wñ@øÁ¬½ZÎC†µ±¹™eXó<ðE«àkŸî9ÍÖ¾­+¼YŸ÷X4Hêóh‘,“\ßS#00Ú†¢Eúiš…¨Ë`™SNM#`n EÙDUùŠbÛˆ&4ÀÍP¡2aÉtR΂gg‡±s¯± Ã ˜Âu 6êƒÞb£OÌwz·ú;fèßýRé‡ohÿ®aZÆ*cŽã¨g"ÔH HUÊѵ¥Rés÷@CF-Á\n<œ9ƒàãxÇSÔDfGlPë°in òÀ1cŸòŽÀ–¨b¨NÀ'¡ÑØ{¹÷rkïÕÞg…˜á±éÇá(5ÅSšžgwÖO¶. ıæ¶6H• °£ ê‹Ç6ú¤ù¢Ej'˜è!E·h(EÙè3+äLG)©¡¢5.ЬjñgS€“„!rd¦‡^!#?på´yÔMâ圙u>‡rA@ÒŸ^$Ä> Ý8í‘c˜ûSô3FU˜Ç±®‹ÔiŸ§ýõrDÜìf4ÆÁ-P2!tqSÆ´× `k½Ç³á"-Ÿ` ÉÞÏ`@5~1ç¤D,GÄ 5”–BØïìP4Þ,„L÷Ö†G BûŽqØÇ¬‹€î…ÍiÞ¡‹Ku”Zµ“çq÷‰=›:¦…'†‹¾ë'bߺšLà°æ}¾)E ƒDÇÁMÔ#IÇÜŠ0¦îð7™GVXÌû³Ú΀ÑUL÷)lmN\ñïê¿rá€e¨¡æ„416žu p™û!ª0ˆÑP 0`™³ª J†“',Kßt©Ù§”k5=Æ\ e=ŠRó•D Ôi“>:âb0+VöY˜¿"5ˆë4did/¶Òƒ«îPMYײá4ӝЅá/í¶ó½# £ /Úrpy¯±µÆ~.zM‰<ÙÝ«å_¹Z”æûoúðùÙÆC½¹ÔJãø'^ÍÓù~ «¿gÓÏiÀ¡Ò?À I1›.'ÌÓH¯§lôtMÇ…LY1ƒ™ÌF˹"xæS½ÅèÖ1ØÌN‘@¬[¸¯/’:}»®ÃÚÂ9Ñé4 1:H[ F¬d—³9•3ÃÅ,CúŒ‡¿äÿLž0–2f\)Ì(J{ÈË (˜Ðö²"9mƒáR˜´ãÝ(‰ex e’0ÄNdA–濺 Íš2 ådaFÎÀa•»à*í| œ0¿„MàE>,%Eö§Œuú]ú¤ÔôÆŒ!êþ Ù;ùüôM•°¥Æzægkð‰n¥9›EÕÄ(üž±âÂÿ“îÿHwÃx3](_ÐítI¬IóŽ /z­‘»&G5%ä¨Å>#X.¦cx„‰—Ý>Hð?©{ÿF¹¾ôNªX³Ã˜¢³¯&INC:ãŠñ\kl6°ˆ(J‹l½-Å^#q· ‡᛼έ Ju 9ª~ù~_åŒ-›±ûw_Íu`,£e˜æ}}õ¨š }tI¬)ýEµí­Y(—Ê– ;Œm±` ßz î¯jXÃêZyÉŸ‡´S,)|”ŠŒ×õ~ˆ<–­O~z¸ñT¼ëÜd°=Ô õ³½ûËÅÁB†Rf;»9¢8/ í{.§¥Û»Ù‰kZFÓåb¶\ã%ñœL:VªÖ¥6q¾…Ý £œƒ…+ãÉ>ÇjJ n¯¬Â`¿<ñ†…‚4_—ŸZõRÕ!Ô© Ì]*úB< þDŸ³@O”ÃÞ½ª×TÝo"L}6ŠXŽÒ¨Ì‡ÑwA"38q#Ǭ²PµåxÉŽ[×þ·:g½§SÂL‚bマ„÷z°Ç_^r¥ͽ0äMt4´™JŸ)PSeÛþTé\Š„Ö_‚@òÅŽ°Å^ê:W¢1&ŒMIð.áŒ=–P0æ›åeV·’ãxxišÚCúîÚšÉu.Ú”ò8ë«#Kh”Z*Y¹ ë`#£™fãH‰Ú0RsÐÌCÑAÓàŸùT'݉&ß-‡7Ú˜)ÃÈMÆwX¢>cuÆÐëb™NùÍ‚,§‡¬nÙœ[Ðc³³$UFXK(Ê^Ü"ñFL«"©È\,Èã(Ž•G%E,ïyO'kq1ò«“. ›,rÃ7ŠwE ¦è¯3tŠÖ=fzg-ƒr¡\‹ÿªÑ!¾Î”ÕÊø^ñl’®“IG¨ÑÕ=¶Œ˜E³HŸË—Œ¢Õ.®£üù<Š~Dyæa`g¯!Û}ÉŽ âPÃñr¬’,V%YP[NQÍr2‰àæ·ÆrvÌÃØ%`¨e×—Ñ„X÷ß“*8Ζ¢Æë¢œ¡‘õþŸW#t÷—“|>3u†Ãïù§µ%³H_Ň÷›I–Ó‹cSAï¤mE½i¬hó—ÅtF‰•ÙzÇvíµÞ£L)nš"XjQ+E ²( %¹ha„,xçfqBPI_Ê:ƒ@¨ËÊž xmØÎ ÄÅŸ X™ëhzÔÌ?ïµîÈ&s½µOsÀ!+aˆý'Üîxþ5®çd?ËùÈàõW rwÉË[&I³!Ñ`$²,€þ•.Ô®ï^¾³Öhàçí¾k ÃX±©¹¡ôè3þïÑßlªcç:,ßø¹J®ÆJõ†­yÏ·4[2šÅQ½Ž:#`w¿ùEžÀeVµ¸îÿäëip=ÿòê^£¸Ö@5ýPÍ8§ÿIÓøôüÞô|¡ÖgÅãÎ[ôX(ïw«­akÚi¶<ÞÔŠFÆÀ七NwÒÊy’0ª ok-®­ª¦ùò~±÷H¿gžu¬ü»ù™™æQsôr˜Ê“ñ¨ˆ”uÂ¥l›M3Q£ÒM^&dUD : áS½÷ Çi÷Óâo¦×²‘@XŽÇ·E"’8ÁP|Ù ®Þ$µ¯5G‹ƒIø9Íâ¶ÖКÕ÷zkׄ$;¤‹`%‹½þ„iJis±“â@¾úº%e—\b†ñ‹í($¿Õæ<³x‹h¡ªéY­¬‡EÒï§_‡}ÈôN!/ƒø¯«ØwÛd,.ý­¢ª ·ƒ%Ûɱ LÞš?­?¼|͹`Õ,>Jun½IEöýl€dJ>Öja pa#õœÇ"½`’Dãõ‰}ÑzÍX/+§Þ¬á„½Í ŽAf‰ªÆüú¤‘->)ßš¸af«Ô–£ÊiS-+$™áSââ&†Ueߢ¿9Z¬[§´W|Ÿ3§ZnÝ…3“Òýx YR×Cº#Œ½Dj?˜ æÔܪìl¹žán·¼VÕ[Û öÓÖÞ¥, Vdá:SL)yoÍå&D›³bȧ 9)'Ñ«™=ˆ¤Ç yóªªZ“éÂ|˜lWŠÅz¯aä¦Ãßæ‡ÒÌû¦ßŸ¡à#4-îD‡Ý¸~¡Xb_‹3 •ýeÖi Š… ‡ÀÂ:¸:ÍÃ|eS 7L|:R6ú¦£Õp<²í-·²U¡Çj«ZiU W §CöÕNëŸ*§’ý\ìíDŠY¾_ÔåŠ÷¦ôÙÍœ¿ë'òÉå_S×¶¯°rGæ6/¯ÉÉ-á–”ü‘˜$ÀŒ¦c¼k+–ás² sK¶Jتs¼ŽàB¯ÔÇþîWË¿d3“È~l4×g]ê‹ ø^GÑ âÞWöÔnùhH(ãfÈÀÅÚ«^Åò_BÔœ‘„˰÷õ¶¬³Á›N…¶s˜ÊÓ´­·ôX² ç¾yÅÐ=,R6Taífr‘Égj¥Ú§vÝ£œ(àJ%>ÁÊ|ÚášL°Nþà&v²ÃΖƒ=Úfñ± ‚7‘ùÕQ©ºðäñ}B“NJšyÛxÍ:惠ÊÎÍÇ¢ˆÛÙø æÜ;_Á›Ë¤üLùª(ø ,¬ L2˜^¤CFä2”ÅûÍpÍŽ.ÿ©fþ|8ÁFµãð([ ¥WDl‘Eó‡À%8DÊ8œB³‚¨­³1¸Y®i«˜ò!½àÐ׫ Á¤wI|‚I¼æš²y[¾|%Õ¡¨ËžòÌÈõ… ŽìÄŠg®RÕÃ(GÁ'Iùòì™JG‡?Rï!G|A*_nœßÅÚ×vªžGN®n2G³·L¬åÉgigÞ)Ø™\XŽ!Z'2&ƒª–¸ü7àÊU/ÇàeœŽœ`S0•‰UtnÂæ>£I CV€SâKRs_ )Sõ³ˆåÕ%1 ®4M¿Ç†dé&¿£„·ÁQe|f†j̪w¢o*»x«”bÚ„Ú‰ˆãz½ÿð é¤_1Z¹Š‰ü°ÌWÌ·müªåáT7͈“<¥"ñ•¬ýUú”òÀ N;«;y•ÃOt/wnPó½M-›Ô­ÁS‡&Ôð¶|ŒÖfŸd~ôúHo6Uö<ʽ)¦Øy*ýÿÍLÁa‚_Í“£”þxþÉ‘ªò—fˆ“^ºð«*é“E¤š›,¹†1òG º±'FÂ[¿>Îæ> «ŽR›¡e8˜kµr#ó•ë#¿ª§9÷úÿD£€?׈z@C׊}Zâ×>ÿY«5ù®¥ ß¿Vø6+ŒT‹©¦fšMêH÷†¯«|ªSAÁjØ q“O¶o›ÜÏ« "Dx+\º¤Äå»Ñâ:"R«e¼eÉt!Gg¦ýk’Td7|<Ø¿ûJ¾`¤ø7Ýp:ïE9áœúneXýc¥{M ©d3íÌæ…“hà6¸“CÆ:V)¿mxõŠ<= ¶MùQvë?þîŸ,Â4¶ˆÓFñ–òílᢅxë*ÞªGn£ö·wêÞv¯_é÷û½z£_qwè±»„dÿmõü*ÿVjîú¯ë5kÕÚ?\×­W«^ÃEºWskÍ•_õÿþ¿%<؆ñëëë24Ù_åûwßÿý§rIFêÏð8XÝnUwrþ nAx•½ŠŒ ’1o¢k㌄ì›Z²6ÝŠÉìY\»ñjz9a%x`˜ †ÞtÌ»Îö—¤báXÿë˸ûKdóñá©aÒŸòÑ᳃7'΂Ln€~ñîÈ0éÏÚG]Kº ¨[ @¹R/{5íµ<¯å6r¥V©æI° 9V3Žƒ[ÎÆõˆ¾·Œzc»Î>O^MO¹ë ×*Û_íÈž#Òz¶é̺&eö»Åb+2SGo+°,«dš=¿÷¯ÀzR­ïÊÁ“gêz³Wòv¬VÏÑ×W˜Õ†e­Úþ¹Q,f ‡nÙòݲîø1³W.[óýZþW¾ÚÏí¯~'/Òà”ñbuÑή?ˆ§¸j÷|wÕÎj¦öQ©5óg)¹Ã2Tª[,¡Á?Ú82cs‰¶jr¶2‹êßk„»©ÛÕñoxú­ýÊØ—$~õÓ+þùjv܉}Å)ˆL·ô·þìüùøâ‘ùX…+=±:>¹xô[òç?M@oý¶e7<Êçtþlýóü¼s~îÐç-Ûõøª=\êZóïêWQ á×ULÜÐqÖ_¶›ÎkßåÛ¾9Ê^(·˜Ë=€K 9¢ÂËp4qÜnŽÄåºujãÒìàåB.3—ظ —2T9h ߃8Þ÷ Ÿ“p§"‡´ -}¿bèw.V«7^»êÇÍÒ!ùðáÄêÈ­Í]¨l!>â…TÒt_L¾cI’}D# ©ô-‹½ËA›¶êÿ>f8‡ñÉëš[?KO. þËÑ(ºBK#<ã¬'e—&jmNŒ·Õx¸ý9’OiXË\ÈYÄ`› À  Ó˜šÇ–]O£¢}/Xíú¥ “'#˜%Ô^^À­Ê¬H•ZI¤­>`æÀ¥õži¥ášƒ \ìjáÁ?ã ‘ÛÛ?fcSµÛ‚˜4–<ßH`ŠöøÆï.?W²TLذ3¼€@¦¤N÷Bÿ">úЧùv W8M£ì;Õg‚}±ipP <¯8zAu€iÆYû’•ÏXNÓñ°Òj¥în¿AtO]Ï×®óšæx§‹ð¸GÝÅeÒT]C„Ž.ì2lŸ{\i57ü.3(›#Ü 9åû€?3-[¢lHØ]ˆŽ–Ž,ð«ÏUé€{=`zv^?©¬ìæiV5‚·8…‡ÄŒÒ.3gåz-T NÀ—¹!Ž\ðö –DRé9šÝ¨’вGÁqë¶÷‘~9fß^Ùûˆk½#⋇ƙº¾ßû¸‘ðñúüTr[n—ù?öú|£?³z7ϳtö>!ÄHFÍ¡,ïÆ &»$ºç-Êqƒ )©…n»Q•Ð!¸¹QíšÂÔn8I5ŸÏ%˜ìŠòé®YÝá󼸤$€ÓΖlnnÕß&õ£­4Ì+BÂú¦ #5F#ùįpЇ#ŽX%  Áa3Ã!Bи‘|Ý7 ; %0Éû”¯4X«ÔK‚µJãÐ4­‘H¥n#¿‘÷z]Æ3>v)µ—­3„CÒÂ4Ðìf¤Qÿf"L·Ë™vZ¡q\Å2ngy¿V»{a¥ÑÚ8ö»„i¯vxNµËºþÄñûö%ânp¼ š©®]½Y£ÅêuW½Es¡Ãa/­ê³3¥aâÛÊãSž©Ì=-XòR½€…Ús";ÜiŽ ™žÇA29ŽåˆìË$[“9šôŒê­•€hW¤õ-‰hkMÅT`_Beƒ@ãˆn,€Uê>â´aYóUà á$ß™S DGƹ‚ÞŽÇöK£qjm¥B× »©ÈÓxCdÞ÷}šj_IÀøúÏJ®ñk/™ H˜¹áåCé øîø »™Û¯VˆÐà« âÓ¨î£êne}×&CaÇym×n|j¶ž2‡íCëŽÒŸ˜ò»œ¿M§žØþÖòn}˜l?-ïnï%îmÒxšl/ïºl íê;èï-´h{©¢, $óÍ$± ¯¡$ÜÏË2Ƚ ]*p¾èpEÌ–ÿ$Ã/î\ì¾”0^ˆðK¢|’²@Ç}Æ¥\ψ ô÷'í»ˆ©Àáˆ3_AÄ/$æJw=°,_#ÿÌvÇùè²îØAx`ŽéÜNu0‹’ݹ:é‰&Ú ”zDäéB{tÇvZ)Þšô†5_ráöÐEúÃ!œ}ÒºñKHù‚ØÐGl!1oì!¤£ÛÝ­Ï[=Ö>z¤†±d°äÙ/•¯!SY't¿ˆ:Å¿Bƒ]h•Ö lôÐw³Ä”cVÖû»u¸0n1uÝ šÄ¢?˜¬Ðé,îg€‰(§ÄI¥EtŽŒúTPKX~õ‘…?æµÊ*]‰ê¨WÍÎ ÍÎÐA_9nøkÌHŒ>žþפCF°9æ¬ûy…’<ë²ï4ÿÖrüª®¯RWdãg­BMÕ‰*fB¯ChÁjã[©D›C™‡4¨CÀ‹2…¹¨kbnqa6ßt¶ÚÑæ&Gò 0/8NˆµK„ï}.`´Üç­;Ö$yÄÀÈa>²*ôªP\Ú’ððà˜yµÈs§zŠ”ç…ߒϯ»CBt¬_¸ºò´8gö»âR }ïëíñlÖmˆùÃÁ4‚EU‘æÇ“¾Ø`°ÏɲTÔ½´:XDDoYP/HP"ià?+â.bzv>ÒO[~ˆ\Ë• ÕÊçUŸQBÙþ!-“R¤ƒ>E*âƒ]ýì#Šb¢ØõA 1mw»%¼ªu_•Úí ’„ø­”@‰ mõ® î¯3†ÎvŸ4Ûm™V¤+?ó+"…ë,…ÉÂ×ñ»B *Á&‚xÏÖ¾!^D“ÃE¨ $»eßÛq¶«Ä½g”¿’DqDh À°m|£*ªŸízD'1[*ÐhxP…¢€pÔ·GöW™ÉDüH½ª/ØP¡jUÉÀ¯¾sê5¬3ª!§î™…êÇœA<¨Ð{[à $ÌBï"‰”%¡pUØ-¸…V´R¬Ö{±¹É%· bF|tê•6þø…ŠÑüb4?ä1oF¹±6ÜZÖÈ¿úº¹ù‘þëŒ.¬ÈÇK@†ýX/Q¨ í‘?’ ì½ò ‹2"ÅsV¡¤¯}ô•]‡„•¾eÁt¢NÄO8€åàoà÷Áˆ Û4Í)3‰ žý¡å8K¼3§¢7­"P.ï‚u7 Ÿ_8V;{”X[‘¯0´¹9è  6MÏvp«øXGšý`J¸µAÚÔ€C‚Y¹z‘”3ê {.ûNMÅ)¬ §-•:»"Ö,ø§);¡>Iøá’eØÖŸ«izŸ­]´&² î)uKÞÐÀ ¸»g7TG£NmõËuâßýó„Æ× Ž™OJêUš¹Ñ;ŽHq@`æ‘}‰º¿">ñ¥)^cRB.Iì³ÿÏ;/ZÝ%»ï.S÷OÚ3Xfç!’¡¶8Ceq®»›9,ˆê±8·Ù×½kŸo=aœ©d¤¨à£Áë¤ÖOšIð"©&ͽ$xšT'Ið#A˜”ï[eív[$ž<Þâ˜2O ìÍ鋚 ÁÚîwÿ2s nôÙóô8XÂè¸vá±·g4¯ îæõyñ ñ°Ç[ÞÞ“Üá:ï<ÍÛü.9ðËCÊ?6ƒo‰ç%Á8 ¾&ÁÐÚÒùÝSÉß\°Z(‡'9{žj×{’f5ÓÖû+KHŠV³¢T›§ßõ:t¡æÁýæ$_ó›êÍ·¬Lêšüî÷Ç®ê±+=îTì½—w¿“BR… ưu¼ øR#"•rÙ"¼ÓçúiNid® 3N½À<{\Ù¥.é÷üãT­Hb½2 ÈK9ˆ‚9L¶?à€¨WˆZ._Yb¾ ›m?bRx¡"dó“Jxä`¹4ïâ-Ñ5,T½c^B¥ etéã£-èÈ 'ö·†âã`( pBDtõ+E…–šì#7«ÞØ7"3E"&ñ'-¹Hæ!šӨᫌÄ_@U«à/J¼-ˆ‘N¬ñP£B¬¿5‚ª¸çÅ…±óÑØ9+´CÃï­dÌRÌ…Ns±Bj¤<9Mx‘¦gŸ[EK”›ãh¿¦^0Ý9-Hd‚%tvÞ“ * –TìZ>R#8mÏjÉpLÌĆëµ.U}áÿºcÔé§¾ ûþác݃Ì×쟟›?­‹GççÖ\q%³ ‡v ̪Ù9"ÉŽh‹}Ó½õ žGÍ€£ÆCM¦ª?Láø7Ø®IZ¤ Rª4@œ‹s[Í@*‡vÙ'q0Êf'(ÿ ;/D‚F¶F¤]ýª,IÞÔ½½—°,YúMùm/Ì–¸8¬=/ôÜÁûÙe»dH¸c§þü­òóW >$2ºÈN|jé­\&aÞ…xå%ïHkÅ**Ù95õ *K—ÆxØ>$½Øö>èU8)qj{'\(Çi¨µS4C掅 Œj©ãPŠºbxÒiº¬#Õæ:*i•˜)4o²ß‘ é}v§ ™—lxS² ÉLÄÜîaRóÇÕJÙ~=^¼#Û¼ª‡RâgÒJo ᆿ˜=¬¶ÖE­=nþ ñJ†v v®žð>´¬6 -=޽µEã œf[±;QBD÷wž:;{¢Åþ]ýiËüÎté”ÌÝÖÎm²s“ì\';ß­ õ–qÁaÃ4|‹˜[ç4k{_[[Íú– œé½hmy/ô›Ûom¹}õ†H‘Ù§š×Úªy¹OæNœ4ë–JïæVó¶ÝBsŠiæti·µ¡¾ÁÁѬÐdlüQ # uWø@Yw&$ÌvÏ}Ž`yÃBëÖnzø3¥?;—”¥_°w"ú é·K¿;bï®ñ)çŠ!ƒw§ÙJÂj'ìA 1vêYzQI{/ù‹ûó—Ú_¶ÿ¸_—”Øþ|?]åÿ”¥×¿³K„lQ{ûãýO7XyŸ¥²·sû¬@¶¶³} fûÄ9QK0,åVp>ä°¬* b7õ÷ÃÎ{ ºâ Tš_ ‚t5×}.­c"Ö¬Û•‘ÆROOÛ2Íž/ÜÒ‘1Å|—¿’¡v‹ ¶”•™U2xÃ\y±¬–^Gr^ïJlg^ø°d-ÉeêU+¦»AK>¢Š‰6^³,°ØÚctwLÚ> Õ£‚¨±¢èÂ?ײP® Þw¸Aƒ2´ ­»íý|¦áãq§zQ®ÐÔy¶–þD§Wƒõ¶‘êûCµˆ÷Ї괕®È‘j‚:NtVìwãÔ9Œâ‚û¹¼ÿò8wãÙZÁ]–kËBžÙ³óüûÎ}è”å$ŸE¸9òÕOmWx´äÛþ‘Ë·±–/åýkråFMgÎ/ïÛ·¹ž›z=hû;4 ›c,¥Ð]šÀ 4JªåJÕޱȷi”\ö1mp˜ò,­>à4ÊLöÇ‹\Y¸íßò4NËJ ô, e}Uvû:ƒ¾úãCÖ;¼×^eïµWÄs½÷>q¯Yþ}J· $sde×ßê´úÛ4í(M;JÓfiÚL§Uµ,Tß§ù¦i¾©Nkìé´Æ^šö#Mû¡Ó¼X§yq†)°”€õ½]a«všx{Iã6ñbºø‹¥¼Å)]ó– "_6ºø%ÜE¹rÛqŽúža7Ç[[-V“ë:§+TßòM«³õ§y~Þ±ŒG¿ïB[».“¶f<2;~ûó¿}²4è弸[ †à°³¦fys±eSÁ–•!˧°Kù‰*ÄAÖnçO>þÆVQÆeZÎ?©úŒ]ØÕw¸§vÆÙî:¬Dw6ü.¤@ywXJ"g; »g‘š,l¶ÓY†Sùîn>Ï[lH» ›žyƒÄBí^ZØSµ{m!«oÖagÓfº¹9•=úa‡>]´§þ0¸a;S¶ HI®žØ_ç‚ØúɆ¿øsÀ^=ñí…8£P£Gþ{»zå7Žì±_½ÂÞË$7ðâî›iZmoCCgÕ…—G}¼bwZ¯Ug凌[Ú0¿(NÜK×Ô¾XÖœ DDŸŒ¥ê•Òolh˜Ÿ¬«ŽüãÕ›;ŽF¶ó¤ôß H$kkHÌ d^³½ã.‡H¦Ñfíþ˜»¢œ2»:dëãêquؾócâ Üÿ&pñ[*ì†pÇx/[üK]ü`¶'í‰?‘^N”*ÆÎ ˜YFW±¹ùµ3Ыm_’d’ëÿÎd!™aŒ |5Ò.´V‚£ C#„rÒ nŒX=ŒÙÞ;õy Ì ZŒxèSqÖxShÀsŸÉƒª%—Nã»éÚp;­Þ°Ç¸ñŠð6†w5#€±ß©°µy–…”2¶Ó¬+–¹Œjñ9“¡ÅÖ9O‹°²çŠÛìŸð™ÁmÖpõž¹>;•gp&»&KlŒmj)]l¬+ñ3Çûî«…éïñå23ŸøBçwúX8/–V:/.΋vŸÏ-Vý\aè°¾÷ \avÑê s?:ëò9ØQ`ZH¤) ’aY‹U’G…nó®YzÛÜä)ò…µQÙ@ÆG¡:)ЈððÌmÎQ}ÉÆGŠ&§`!C}L4JR(dá-³¦Ûs í ÷Ô,êtN¬ëójîG °•š}—ìIUiŸ1²)#Œ¯®“Rb×Y¨|¡øZBâCGr‡†7%‰5&¦F}€`ÌÄ7.Ñßöº? ë.P➸ϑ[ô( ¼Ð¾¹Ù%µ{ü,vcÌÙÁ® ÞHàËbB¨xàBñêEt¶ï4nìqÚô,mzìã9?€¤í¹‰¦¹Òþ%­cÖdc™õj ZL.¬‘Ö¾`|ø?€5ý ¦„s]·ôÈ/HÖÿöáŒÍ*Àþ¼?/­;µ,¢ñÁ*‡¢Ü@T(¹zåÚf´¹®¿e–IŸ µå‘51ɸ9?/%ek—¶@@,ŒÀ}ªªàMxÒKÊ3I)¹”¶A4±¿•2}ØþFº„0N"À7]‹øñ(ݵ¬rÅ}z…¡ðwÃw%Ãç†þiæ6±:È—=QÇû~!Ž6—+™øìiyHnMœÚ7¿W*µ¹‰̺÷T ç³·ü 9hÖt!„ •œP­qb£ê}«:ò)¼,z ®Ô܉nÔxÙaé!ëo}Åû~¿£)O%Cßéû¥YxŸ$©©S(õK…öª`1Ó$ ržmlì§ÖÓŠ&Æjux7oÍíEkgÉlUÐbèoØ^®à[p‰/œ°¶µPx ¼»`MÍ]PVq+K/M0ÂʦË—,cÝçqÒMx››¥RèûØÀFû‰øAçÂ÷²a¹KÇessB楕‚Cc.nŽO¾l.éSW6oÓéëU–¾^eiç6£÷Ú!!Òí‚0ŽW³ðûÖk4è/ÌhCíܼôív)“$Ëeº­”Ú8G$/@y ´¾l‡ðÔ/ˆÅg»/õg÷eî3½¨#4¼û°Ø¼ ýONý+/|rÜ—hÎÝqªGΩj”ÒNý>»w†ëûYzzwj7ÝÚõáÖ @ßòU–+lâUà;y‘Wܲ· w€¨Ú [Sú²Ÿˆ1[}máM/í÷ÂmI9YXøcjÓB ŸˆÚÂðzAHäúì[§ôý3Òçk-×öØ?Æ.µÈ¾$U»[ôØEéØaÊk‘`Øvì:T\Þ¿)+s¼®5ŸKg{fV,‘¬Ž°ì5Ä!—ª”ÌK6µewè¥óÖºëCi»Åê:ÙƒÀîå:v»ÚQd{ýžìHò&3¬Iyg^:}ô¼ÝW¼àÆÇrbKr\`:ŸÚJ ôÝ£´€hÉî‘Ú¾ÂcdÃÐðìax¢tx"§1³ð‡&¤ÂˆN}™àóDÆi-µrü³¶‚… Nk•“ƒ”+U‡4œS*ɾM5Dé òÀxu±?î’XDŸæèË)ì¥æU¿KVÔ7xͺÃTc³b—]9Àp å¡/Ûà‰ˆ.qLˆÏq¸‘Ùq»öÉ……ЗXüxóàä—%Ö.è†Oá¹ûfŸêI’3Ëþäoôx'%ÿ8UúDða“ËÝÛÖ¥í½jõíªÇžYbv¯ÔCíY ÛN±_˜ÊagãñŠkxë_ònM~iŒ‰õk”õs(ëú¼dÓ—uOBm“HZwß>/|˜ Ô\ûÈú¯Ë‹Ü£.ÎC/òéi|¬kE²ChŸ¦ˆuGã:”Ü]¬–öZX0âó\Ä{ŽÔÆZß=Âjsss€m|, ?¿‚ê®I|ŠzçžÝ™„ Y([­øÃ{Þ£KŒ ]„ú«Ûv½oׯmµ“Ù)7FØèvOV»ºMÜëmÆ¿ÕmL2ú@ÄÂê}£ºÍgXãvmŒÃ é™léµ:TJÙ³ ÞÚXæmmLÖ*u¹Þ‡ÙMs¯ºmÝuiÎû=jçˆlô£¶‹Íá1Œ@ŽÓ1®dšu‰JLÞ)ûÊqËYÄQznÄàóQ =¶aßmO[áŠõúÂöÄØÛ#cû«áÅÆö•QkõÐh\õc{hÛ—ÆöÀ¨½6¼[£õc;2¶»F}ÛhôíÀØÞ6j_í¦±Ý0¶kF#4¼WFí™ÑèomÏØvj½Àh4 ÚCÁ‹“ía¹ŒmÔ°xÈ>áß6ƒ|Œy¾È¤­P::ÛOîpöù>¿âÏÍ?ˆøésí™?4–?˜iˆ¼WþPzCuÅ«:r¥¾à=”쵯Øf\{mᕽö9Ã.•ïµðÎ5Ô·‰ù¬f¨Ö´qÆ;¡{øÅxÖAHõ°ÄÞ(ǃRÒ#¥¦Ç« ÿkO”·Ñ|W:o/ËÛKóxZ1Õ:ixE­ÉëæMì"±vñDÖ,ôVë¾þ^¤kõøÀÂ#`;h§µQc)ôÄ›î®Û’'o·ªžj»^«bYjí¸z¬WÔ»Ð]ý-â¯RfdyѺ󚭻ڌyW½NƒsHlON¹w®î§_³yì“ä3Þ[³P¯l;N•8÷-À8Nëx P-úe!ïV/¡=çó`Tè¸`Ózu¿ÐÎk>¢h|oþ-|nÖÔ›ÿ1|úøÞ<Ÿ>(‚uïmv^˜ðjŸ »4Uj«™[äuIÒÛÈb·»D||Çû(GÔ^r摤‚-veײî)Ý2°òziþ€jƒwÉ¡qµHÏzNYU§…Xb§Y«ð§7íc•µþl-«œ„ÎeÄÊÚ{>ví³3¨îΰÀÜ>&Öd©nR·e‹w£öÑLÓÕq×Ú¾‰¿˜ÿÒÀ0“"\wJ%ST$É{>ÏÕüœï/‘Ëy±º^äó?üò†^<µ€§ˆÆ{oñÞì{_v#W÷`~¨#“øÒ¤/‚r±F˜Þ·ÞÛÕ½v¢4npewøËÖ ª’½ðx²å¨Z²¸šê)É8cÏGǼ&kQЇnHÒ¿4 UzCÊñ WwB*¹ì˜gw ^ÍBcôí5¡þåì'+O¬ôŒ.Áu1ê4?šw¯ÀÒ¼Jâ¼úT컦ڠô˜i…k­Õ¨]HÃÇ'NíSºw/ìÔûð‹ÊsÐz¼—;h¯ƒÊ½í“ÅÔØæUg~v_î×—žÎÇÕ…¶ÑÜë4ÏüæÉ)¯Û Ž¿îæJÍ Ò3q¿£ÓbóÀ,4?ØÍ÷v­jo×íÚ­]ûl×>ÚÍwv¡Th¾µ›oìí»^µë®Ý<¶½=¤×§vóÈn¾¶·C»É¸¨yu^¯çgKòÁ.“+L÷ëªý=Ïù® µœ¬Ä4ê²ÒÖ³h(»°C=†]¿mŒ¬ bTÔa™Ä—lµÝ@iÓ'ÌU„;k4åä>õ²Våó¡lf$s‹E9ùË'‘Ms »uz©¶4ëô „´z2½à*È[…ø×ªç÷àÍ Å‘âï]5äì² 2ÂvHóW)ÐÔÀ.I2" Aa#½ÙNOá ì·¤­ãž÷º`µBÛ}¥ç>ŸJ+¸Ÿ |gB¡ICßks¸»Í­ß·žäªS;cæcw¬®úÀòØ–;~"M¾cháÈߙվtÀå:x!–\ðñ-Á‘:FÊ07æ¡ÉÜè0;®:2u>(‰m”ê 'xIc¾²²Ú8ÂKSœ~>þþI²Å+‘²œØt¾ÇÛrç‰û"©¾×‰oq}„´”n‘Û"f›lœµô±â]ÞÔM}HwÕÙ ÕšíÝ´êZ+ŸÐ]áÞ…™™n8)4_ÚÍvó¹ÝÜ·›ÏìæÓ‰O‰OAâý”OÉôÂ~ê³î(|”¯ „æÔzœ‹ƒR}ÆG@0òïw› ¤A'CïS+ô ‚ƒü1‚¶kŸÙê˜(}Ý—£C¹ïüFƒñƒ¿?û[øÐT Q䯀ØKw¨ŽF…75*-Pmý§þÎc[õÄ;mUìæV¡öaë¦Ü”«ËÁuÁnÞPžªKŽZgvý ý©¾§?µ÷¤â½áìÞÛpçôSÀ±kœÄTpÇ-9h”§¶(ØU©½úƒ³#Åsž .صëVáÑÖ£ü„?ࣩâ0`lÝÅrZóØŽmõ@¹?1ŸÖØÞþ–~¾kn&¿át…»´ì·~LV/7¾0cçhs3vš7¼bEoj-—ždzÓƒäsáή½ãí¼|˜_7èK€­ŒÞ–…ç’oê¤-jzËÚ-lZ…]ìéÚ»$)4—ôRðwå4ÕpD&?ýͪ9B%G»ôÿ—~¨p›ai¬Røè…æ£ê”®/Iò0ZwîGé);Ñ?Ý^Iíàõþ° ~¡4(prí¾TñÐ7ðÚn ¥LXG~Ðv?a»l2ùàzm9ÃȯÚ>‡ßlˆ½d—¼d¥zAÕ~÷ ±‹ßË|ñÙ¢îNž£XJÖn™„ödÓªŽ}l)à¡· ¿3ûŠÀöt—¾–Ló«Ïå¬Ý_Zê¡‚ƒ•¢—´ý3Þ”¹ ÜžqA¯!ë¨o±¡P4RbQ¼þ:ÁÊ93®K-,fPE[fçOú»ûOìm¯£Fµ¿¹9[eøñìíË3/wÒ<F"íÖŽéò>öÜ ÝK§2 ¸æ‚äPpåã‰=Ò¨aDè§T8Â2º7FX %þßç³òX (}†dÝà’Ié çÕg~/Áð]o…Õì÷ìp»N3ÞõžÍØ,‘ô V ¯zªÖ¿X=§ñÁ|k`úSum¤â‰½Š÷¿Z 9¡ñžS{JµvËAP oͪÊýe§\ÿP¶¡VÕ~tPÅͶ iAÃêFP3êoZüŸ€†¤ÜçòÎå/$Ušó4qçÚpß‚ŠkïQÙÛ‹Ýì±T° p´’œÚµ•M‚lÌ iL¬?V¾T¡N¹L-4G,,ß+ªÊˆéiÁîP© ¹•Fo ¥úø‚.2DZàíb|Ƭ®“èk­ξpwé«ïX,;ÅRÙ¾Ó¼2{X##-¼¤~`š—€Ph îšúu‰ª`ÕÆÂ¡epÑÆgɉÙ9Ñ¥l…ú«¦}V‚‚6«Œ=§~H=РÖЃÆq2Z‘/+'èlÅ—l 3Ö]*²C¡*n[8[­ô ¯vÕI–ºUÉá>©X¤x u÷àte4óZqh2ÂH!#sFŸwÞ1])ØÒvÏ G2S§vB»<S¡û Üì“yÄÐݽgzôpùÂ+]äм2{yžxÊ`ÊeÐI–åEA-¸×áýŒa˺YøcJÒO•ïã’­6fÖÞB PÛÿ¨ÿ¼p¹¹Ilfì¨>k`YmùÄoF|{ùxç…m…ßfO?í¼Îíß•$bjˆAÖvó²¥L jI¬Š5´ÙÚUU’ÆÈ´°¶)øÁJŸ×¶ˆ©:w^•ß’>è½ñùÔø<Í–Ôàæ7¼`ùÞ›ÝÀÙ9dM›på½ÙÜ<‚‘ê]ùLÈ8œD?ð ZG~—¹§®TaFË·oéèsG¼|jJG|’‡ºuDºÍD‰eóF ta>|mA± ØTŠaüW—|›‚B‰_¼èØm9kÏ>ç€Á\]àêl‘âê¤"pË×u•U¤jùù‹ÀÇÁ·]ü5ÉöÀ àùÈú¦:ô/¯¥TP¹²âÜ7ú|<‘%lÊ¥ýAÚ”ÄKùuoùwÅ£Õ⛡ -—H9½ˆÏÙ6ú>ŸÊeUxÀ×»¤;Iõ=}…Ç…µB’ß`«ªA´í’di«J”ärm¬êpšTÐÌN ·¹ö&ƈo›8Î]H‘ïűêűêÅ1õBÛÌê@yÚ‹ú¾êC| `HÛkn‹íëÅo•^#È·!¨–®…ûí¶SŸS+ÈAæ2ü2ú]ÝsÒ¨wØã£ïÀ÷.†{Eœ6y‘õ{m줗”áùƒ޳ e`hT†ýŸ2Ü®7qü`†\ë>@%zZÙv‹~µ¯°H/kë$Κ¦¼Ã^î\:Õdïnáu¿Ú îß»ýŠî÷ŹÎ{f»/üuôÙµ†ßl0g˜‡_Qþkg†Í(,/’D¿¿Áz»û‚êí»ggèq&·*$ÉL.B°îú 5ré;Õªš©V!LñŠ…Iá Ô”¥VOAý*æñW^¥WwCð%£Þ¶YkØjpË'î›Ä=–‹c,+ê°b0.ìº/2²hæW9²6-7QðìN©|á[¼58,•q”ËtY¿m³íú‘ã.Ìc¾Ÿá…©r54»Ø³d{Ç~—7âðYtbµÇ0Ê>Sçk ç#Žî˜!v㔼ã6ÕeÊÛ–ªÓzäuÛ:£×¥L¸ÑL.$5ùºQö »e·åZBª¦ÛŽœ*µÓµCjj„~dÓ8ã±±º‘ypÔ܃ÔÓ·_…‡ ûL Þ6ì2Ì1åf:uC_–·'‡D‚¼<»NÍÚS¾oÂ+?Zr‰áB½âÖ«+d²âyù9¿ƒ·±$|cÕúù¦€;±MKprLÒ9%‘*Ú^ •Äõšsh»ŒlÀ‘¦=3u1¿2öüôŽHö ¡ïôí¯4Ó×fWðʵžnë[úHLÓ·\íùêΡ@Õ–¡ õ Úßô ó7çµõ kÜ‚K_¥Ôl¶ÒËxùË[ÀqPÙí¶îÜW­žÈ{9>%7"vmoÙêÚ5·%}¡Ò΂žVíÐñ–8Àë-¡$xKuuÁ.ž±[|Û©¿îàå‚7Øð»Ó¬Q¹ú1VÚ_ápnñ²ÁëºrƒØžvfï›ÈnYø«zÕæq¬»&¼Ÿ3{¢=EÝRðhFÞ»µdÓ,{;ÎÎÜœ=Âï7k˳J§n= J],d½Å¢@m»uf{ÛÙU1Äáê~æ”Tkz!já¡wªXø7Ësê®®í·RÖXw¼/–úe¨S\0ú÷?š\ÂûÒA 3”ÌáuÜ–bwêêÈÝÖa» ½ F¤® ¬¿r6y÷Õ²ês;¹ø0M×û€Šç››ó'åÙî¼¥ïˆÑ9är»úBùäBØÅß@2¥ËHªŽKIJB^è6â(î¡©bÖI¦˜Ul¿˜µ …½~S€`Ðuè/ê‹Fo8ÓOŒ·j9l¿±Uõ›çž´ÜÛÝÃ"×Kƒ@ xh䬰]h|ÄefvúzÆw›Á™#{A*iÉ'ú©ÓÄm¢¼/ôéâC£ú-·m¤Zii!£Ÿ)žï>çé@ÙHï²i‚`–ÐS­ç¯M—/|¢Ñè@^Yµºœ¹íQŽ“²ïÕI‰;/îÔ΋’¶—¦Ï‘VcRFZ—Òg:m/Kûˆ4… ©– ¡=©‘󯤃DÃi¿øº_Ÿ4ï.´ÒS¬çÅj…ÚÁÕV;X`–«ã¶ŠO ·ŸëÑy‘r×_œ/ô":¦îy±v{^,uÛÙÍâ™eŒŸÅWj ·‰“ïÄáqHÝí:;ž¹1Ü Zjµ<"|ç^{$[M¹ÐßjésóTZr¯5:Ã]Béáy±E?¯6è^MW‘OÇ«“ñØJÿ‹ûª;Ã]ÜÚ×âëúj}¼6pýEcXòyünz@§ËgªH#)ñðòí|½üK­/ ;Ý©¨¢êUWZ·÷õøö¾|J­¯’Ì`WR'¹6ðBm´*l*a¿HÑnxv£±cù‡àDÉ¿ÿ7ì':XH"!=’ïÁ<‘¨ò ‚å$ˆIš &x‚X¶ Â+%ýïýé<Ñ¡°ÏNß(‰·#ʇȱI2™†Ñ›`¤(^$ˆƒÈ—¤\ª¸°É”CÆœõMô'‰ %óW'Ëù(‘I "}%YHÔ$ÃÁg“^'xðm?AèÕD¢ï&:–D7‹h&͆²%*âI‚x¥I  ž"hq‚°‰D]{Ç­$½å<‘HåÙ÷$˜ÍF·I8Ï.‡£ºô†‹[êÂu‚0x ÇXIîÅ K†ñsìþp´ ¾süVÆÕK.ƒIH%ÇÁ¢ Æ³Q´ .sŒrEI|IÍ`l[‹ùp0ˆx$BÚp‘,ÐsÄÆ¢o·ÔyT/{€–pÔ_Jë]R“Ü*¡ŠÇÓï”™ñsšd°†4œãdÀAÓŽ=žôo’〃ðñìä(™/’4Ò\‚ |{ó9[Öo’`2¤E ‡ÜR¨%Üó8èó!å#¨§ƒM}™D‰ÔDÄRúÙlÍŸDuÕšºõ†X¸œsð®„àíMg· ŒVx$⺞ ›"R‰/L"Ñ<¤ïÑMÔC?z_ið¨QÄë (ÃÍâdØEt6&Î@½` ãÑ€·œÂo(¡ 8_œÒ `\#Ê̦q²0fIñ`¢„fÁì†ZfÉU<çÌ-1 âÛI/™Iøå}‰è•ÐÍû#ú °FFÃúmQge…ñ1ž®óa„“ á]²ícRsØß„Ã=Mš¾óùt.£ÌAŽÍ÷\Q)¥/"MÅsPÈnœ`Bý•pw™ 4b*':JR#xSÒ|˜°1•ëÑïÙ‡ÃgDá„ÊCs µqcæ&„¸éÑôZ ûUÌ,Šà;ÆI.ÐDNÆÓe!º ðò‰ðAÑFÕ­åøÎsoÒ<3ž/ÔQ?H sÁˆ[÷øçè#ºÄï ±ˆw°Òë‰Á&×Q÷+MDðfá)LÑÉ_J÷о%.èY”ãOCj½Z©¡D‰GŸ‚Ñì2HŽX¸@o¦ÎóZHd8Qª'DË<å¹õq¡pŠùŒµæ’ôâ’,ˆóÁ|JÒ„¤ËKªNñýd™ñgÍ^¸ˆa†ØîBe#¨F!Rt¨áDEf4¸O§d‘A=cý€ªÔX±rMxûªæÈª7x~AòÛ³T[G6(áòÀ:r4'euøC©ÇÄ÷Çgĉô¨Fz`ÙFB}2P¬~©4þ@lL$IŸôYRåGl•ºb•DK†¼& CÂS.àá’eqOhÉÁ¤ž.»"Ûaô !\S5£ýhD˜AìÛd܈ÌÛ”ˆ´À4)Z_Ôïg­ðp3¬lL€óK­Ðk†“`¤Ôánj®P—¡&D×*+’gEðÝ%T?ðˆáHë)ªé[9]îJÌV+wxx&X F »B1"“½ER™(††¢L”0‘@Â4D4‰û„n™<¤²ŠRÇ¢J¤ºÈEšÓ²¯¥Gý)$•!æýœþ%ËŠëm'Œ¹šÛ$–8e áK•¹£ux~Ö1¬s²UOHÈ;Qì÷úJÂ*i¨i÷“Êê-5†ý9ÐÃJ¡R‹×˜G 5£ŽC–Ű€BZˆ’ã©ÇÊа§¸Ä2TŒ'aUÔŒ â,ŸÀ6‚Ãi7 HABb¬ëžQÍãIy è#ØxRc^DeñÒÏiP ëdVP]² `‘=gó*@F™ÞbÅY‘M­o¢2Ñ;hÐ_R×¾ƒpdîÞèš߇dPÅ}" ê8~'0gðÊì’ŸÏfò»YJZ¼Vþˆcé1H\Ï«&o‚7\É[Òíª"«õà1sÀ¼¦*^6óµÇBwLÙ¤º“‰Ì:(›1 ³jÅé«â‹4M’ǧlh@LÜf%yE©79½\&'CšGÉa?a~§xíéé;bÁÉñÆ=žBô“}1aŒÕaŧ¦¢Êö@}šýË&–CƒµèOIÅe[™Ý5€tÿ¢z!¢Gi§£@$¹ô’„9éÞ!\>b(R¹ëë„Åøå\«@`Ä`4³¢üêäíü*‰*ÔÉ*Ëp<`ƒ’é’Õe±f¬žƒ.™B)›Nfd ³ÿ¢è°SÅ,&EË®àÎ «­#.Kämq¹æ>q¹ÒhÕ›¹ˆËÿõ_ˆ¨.áÞ _?$‰qgc¥×[ÆÝÊ6ŠÝè’(p:OkdÜë7è„£ˆß8¨ûÖ#Œ|‚Ðã—"·1 é%XÄ`¤D1B°#ª³ ÉHÛ0âËérR‚ÁMrˆä}ÝÅá³öj9ÖÆæf–aÍoðÀ­‚¯}ºç4[û¶®ðf}ÞcEÐ ©oÌ£4F²Lr}[LÀÀhŠté§i¢.ƒeN95mŒ€¹E,eUå+Šm#šÐD7C…Ê„5&ÓI9 žmœÆÎ½Ær€'1ßéuÜBêï˜x ÷K¥O<¾¡ý»†iwªŒa8Ž£ž~žj$¤*åèÚR©ô9ƒ{H ‡!£–`.· ΜApÈq¼ã)j"³#6¨uX4·yàޱOyG`KT1T'à“Ðhì½Ü{¹µ÷jï³BÌpŽŠØôãáP”Œâ©MÏ€³;ë'[—âXs[ФJØÑu‰Åc}Ò|Ñ"µLô¢[4 ”¢ˆlô™r¦£”ÔPщhVµø3)ÀIÂ9² ÓC¯‘¸rÚß”¢†A¢ãà&ꑤcnESwø›Ì#+,æýYmgÀèª ¦û¶6'®øwõ_9pÀ2ÔPsBšϺ ¸ÌýUÄh¨0¸ËÖžw(–ÇÈèÒU {¤"H=¥ÂÒGv›$¸Š›ÁxÖ.’,+ðÛ·åtÁ¯ùu$/Oøe@/Ì«<õ¥=AGTå9ÒÞ º¡Ör!íÓ"Tï ¨p&Ó_GUbrI[×ÙIK](ì†ØM(ÔÎãútLbØC —)_¶G Ó˜jªé4Í-N¢hnÙí£èÄ ý„4ÜrLº¦± BHypÒ_Î) ›K±³>›5“ô0+û¨û`2 ãKýpëÎ8¹zH­ŠÓ)©¤A§PÅ\ƒ:;Žˆ!Åue-MU’—!év‘ªŠ*&·™ƒÂÁØ`(+AÉU‡”Gµ7‹ŠÍÌ›½]Jš= baPÌT±"‘£…DjÅV+ˆbÒ^!ï'á!’Õ¬°¥äcÙØÐªTËÓ Y! Ó¿g9¤.™UÏ*¦Pʲéc¥üë§ ¸(Ä(Cƒöxªö¢Ëé¢#S¥,ŽÕëk´Ä3sµ¤E:WgsU-†ãw!i©å”Г¨hb ,îÍ}›)C¦1¹çÑ¢'ƒÅj*©Ô¡¡ü³)1ëJó S”ZGÏRþüÐ¡ß =×eþþ:ŸÌYÕN%ÃÉ–¥oºÔlˆSJµšc.²E©ùÊ"Pê´Iq1˜+û,Ì_‘ÄušN²42Š¿[iŠÁUw¨¦‹¬kÙpšéWÅÂð—vÛùÆÞ‘†Q†m9¸¼×ØÆZc?=ȦDžìîÕò¯\-Jóý7}x€ülã¡ÞÜj¥qü¯æé|¿†Õß³éç4àPé`…¤˜M—æi¤×ŒS6zº¦cŠB¦,ƒŒ˜ÁLf£å\<ó©Þbtëlf§H Ö-܃×I¾]×amáœhƒtš…¤-#V²Ëٜʉ™áâ?–!}ÆÃ_ò&OK³®æ¥=äåLh{Y‘œ¶Áp© LZŽñnÄ2<2Ib'² Kó_]ÐfM…r²Æ0#gà°Ê]p•v>N ˜ß Â&ð"Ÿ –’"ûSÆ: ý.}Rjz cÆuÿ‡¿ì|þú¦JØRã=sŒ³5øD·Rƒœ ‡Í¢jb~ÏXqáÿI÷ÿ ¤»a¼™.”/èvº$ÖÀ$‹ŽyÇ„½ÖÈ]“£‰šr„ÔbŸŽ,Ó1<ÂÄËn$øŸÔ‹½£\_z'U¬ÙaLÑÙŒW“$'ˆ!ñFÅø®56XD¥ƒÅ ¶Þ–b¯‘¸Ûˆ„ÆÃ‰ðM^çÖ¥:U¿|¿¯rHFˆ‚ÍØý»¯æ:0–Ñ2Ló>€¾áZTM…>º$Ö”þ¢ÚöŠÖ,”ŒKeK†ÆŠ¶X°…o½÷W5¬au­¼äÏCÚ)–>JÅ Æëz?DËÖ§?=Üx*Þun2ØjÐúÙÞ}åâ`!C)³ÝQœ…ö½ —ÓÒm]ˆìD5-£‚ér1[.Œñ’xÎ&+UëR›8߈nÐQÎÁ•ñdŸc5%·WVa0ƒ_žxÃBAš¯KÈO­z©êÆêTæ.ý!PH¢ÏY § Ê€‰aï^Õkª‡î7&ƒ>E,GiTæÃè» ‘œ¸‘c VY¨Ú¿r¼ÆdG„­kÿ[³ÞÓ)a&A±ñAOÂ{=Xˆã//¹R‡æ^ò&:ÚL¥Ï¨©²mªô.EB ë/A ùbGØb/u+ÑÀƦ$x—pÆK(˜@óMŽò2«Š[Éq<<È4Mm!}wmÍä:mJyœõÕ‘%4J-•¬Ü„u°‘ÑL³q¤Dm©9hæ¡è é ðÏ|ª“îD“ï–ÛaML„”aä&ã;¬QŸ±:cèu±L§ÆüÀfA–ÓCV7lÎ-è±ÙY’*#¬%e/n‘x#¦UƒTd.äqÇÊ£’"–wƒ¼Š§“58 ŽÀùÕI—„ÍŠ ¹áÅ»¢Sô×:Eë3½3È–A¹P®ÅÕè_gÊje|¯x6I×ɤ#Ôèêž¿ [FÌ¢Y$‰ÏåKFÑj×Qþ|E?¢<ó0°³×í¾dÇq¨áx9VI«’¬¨-§¨f9™Dp ó[c9»æalÈ0Ô²ëËhB¬ûoIœ gKQãuQÎÐÈzÿÏ«ºûËI>Ÿ™º Ãá÷üŠÓÚ‚’Y¤¯âÃûͤGËéű)ƒ wÒ¶Œ¢Þ4V´ùËb:£ÄÊìF½c»öZïQ¦7M,µ¨•"Y”†Š’\´0B¼Çs³8 !¨¤/eA ÔeeO¼6lg ââÏ,Ìu4=€NjæŸ÷Zwd¹ÞÚ§9à0Äþnw< ÿšG×s²Œå|dðú+¹»äå-“¤Ùh0 Y@ÿJja×NŒw/ßYk4ðóvß5Ða¬ØÔÜPú@ô‰÷èo6Õ±s–oü\%Wc¥zÃÖ¿¼ç[Œ-Íâ¨^G0‹»ßü"Oà2«Z\w‹òõ4¸žyu¯Q\k š~¨æ?œÓÿ¤i|z~oz¾Pë³âqç-z,”á‹×»ÕÖ°‡5í4[ojE#c`rÜA§;iå¼IÕ„·µ×VUÓ|y¿XŽ{¤ß3Ï:VþÝüÌLó¨9ú9LåI‹xTDÊ:áR¶Í¦™¨Qé&/Œ²*"Ðð©Þ{ˆ…ã´ûiñ7ÓkÙH ,ÇãÛ"IHœ`(>‰ì…Wï’Ú׊£ÅÁ$|‡œfñ[kèÍj{½µkB‰ÒE°’Å^Â4 ¥´¹ØIq _}Ý÷QɃ²ÆK.1C*óUñÒ/s¦’§È9‹-)A„Håé µÜ(¹Ì“MVúþç©.GÚO—C¬ËޓöUÁep¹¦dënô…wÒåõž›ñ{sl®R­°a¼Jj!ƒZBÃáó·4{~3¶Åx3­œcÖ°fŽJ³°§;2íñTã|ò;DQIÁ6îŠx'ìÐ_X(H¦·‡VKsÚ•™3§þ— 0'°ÚÅPæUïïÁ·ÃYÎÿ\÷ ½¿ Ûƒp¿«á¸äp(Å-ƒD]Ý_XS­yum/xO¸ñz8)/»ò=ÆÞ¯'éâ^ÿƒJXŸøÅv’ßjsžY¼ŠE´PÕô¬VÖÃ"é÷ӯÈ>dz § ‹—Aü×Uì»m²G—þVQUÛÁ’íäXƒ&oÍŸÖ^¾f\°j ¥:·Þ¤"û‰~6@2%kµ0¸°‘zÎc‘^0I¢ñŒúľh½f¬—•SoÖpÂÞæÀ€Ç ³DUc~}ÒÈŸ”oMÜ0³UjËQå´©–’Ìð)qqê²oÑßH­Ö­SÚ+>ŽÆOŠ™S-·î™Ié~¼…,©ë!Ý– pµ'ÌóÔ~0wËmîN«ê¶êµý`?íßÑuür)yi;¼)—]‹“éÂLËfÛG,]º´l-ø‰€@~ß§Ã7-åöÀãМ*’¹¥àI5ÜT3Ê­²®zJ‡—Êt¤Fˆa—§^;L³°Ù¦ÎêRÇ*ŽWOWóŒ6ÝÆn’‰„Qet9jG¾Iç„öCt­¨z½#¹jò]¹;ÎÖo̪w¸KºOÌ}UÿAã Ü|ÃùÎÊA@³všÄöZ·×2,gÛ¸€_!ØÍkb¥œ²7‚©‚ŠS{ÔœÒÛ1ÜJ«¾ÝòêkœRK0Þy-k<é)5qéêãÆ’÷³Åã锨N¶öÃ3±&鸚çºDÞç¦Ò2½ó·, ܯèhèÃÌï.*牨ÍÉfÏŒ«ÆäÝ"aG]/À#ƒN,ˆml©IvœŽx—Ö"'±e9È3Щ¦Yzqˆ§ñ@"ŒYv²B¤i+ž”õ,wÁ,æz(9õ®FA7便»ßÍ”Äô¹ì–QĶ}åJ1 9ÝJ©r$)M×gÝ[mtK• •n9œ,¦8{Ë<ÅÉnÈm#¸÷ÅQ´@Äáç猠‚Ÿ *)îÍ´Ò•r¢hö paÌ2ˆj©R™ƒSgkþ7û%R3Sšs*û¯{‘¸ÿVuÌÁTcùP§û Úœüþ‰šþÇ#óÀ†F…Y½ƒîgìb=u¼„:Ãȧ˜×w0>ˆî5ç ÎÇe+Š—0¿£Qß‘Äâ~Ëmû¼o&8ræ1˘úÿ ùî¬hwçTK5n+wTáoÛJ/`ø©¡µ/i+„’/<êÜG%‡I—XLg:K²ÉW¯ë ­\¨d ˆ“?ÃEi’ù !©¤z7É.A93²‘SÀ)¤ð©£)-9Öíä_d~®2Ãð­¸ ¤ŸtnMk$p_éÖ„¦sƒ¬¨3£h@Q掮ç?Ò¿á™úy"¥>'„ð- yQlÉ¡Øà±²±rºz‘¢;üÙÎD´z/޼­Ït2å²'Ùú²‘~ý7b•êÞ§PIxóãFf&¶¼{_ùL ÎU²› º°Úõ!'dõŠŸnSWÉF%$+$D¢y&Ø×Œ(…@`zÖ¿½Æ¡hp5Àºîð/#Âù“bIj)‘‘@uf¨µ_ŽœÖ”ãŒbZ¼Y¥˜iΪSûÄ¢ª‘¡Ï¨8§§ù0œé¤l2GnˆòlW÷äwÔ=¨ù˜÷4‚L¾àßÏê%Xrj‡ðîŸûÖ‡®°|-‹ …ŸÌ…ùlB©‰f‘§‘Pµ.ެ\«?É•¼]˜ú0l7׾˷}s”½Pn1—{—8rD „—áhâ¸Ý7ˆËuëÔÆ¥ÙÁË…\f.±q.e¨rо1p¼ï>'áNEiZú~ÅÐï\¬Vo ¼vÕ7Ž›¥CòáÉՑ;[›»PÙB|Ä ©¤é4¾˜|ÇxˆˆwõëVçmÁÞ~‘¿{½²_·*6y“h‡ˆ¢ÂßáZÅàbe{‡iüh°´§>ñ›m‰¹¬î"Æ*moFèuÜ™„bT¾wùÀ ït|S»>Ìê-»ÔÕ;âŠNýzWi¶ºv÷%¿ÎâàÒÙpÏ××Va2zÚé"&ÏkB_[ÛÄþݪÊu‘úNõ!®…ïááPnF@‹-ƒ¥×!"¶R»k#fŸÄcè /LD2¶ßÛé=èˆ`íâ®ÿ3•½ñü§ìÇdßAHaÀÎeî•y¯› ,¡Ê,!v¿ý”óø§œŽ÷R ¥™ë“$ÙG4šJ߲ػä±i«þïc†s™¼Þ¡¹Õù³ôäÂà¿¢k!´4Âó8NÁzRvi¢ÖæÄx[=€‡ÛŸ#‰ñ”†µÌ…œE ¶ ÜÈ:©ylÙõ4*Ú÷‚Õ®_ 2y2‚‰QBíå,fEªÔJ"mõ3.­÷L+ çÐì\àbW þ‡Pˆ|ÜÞü¹À0›ªuØĤ±äùFòS´Ç7~wù‘¸’¥b†á2%uºúñ©Ð‡>Í·Á¸Âií`ß©>ìsˆMƒƒJàyÅÑ ªL0ÎÚ—4¨|ÆržŒ‡•V+pÿpû ¢{êx¾v×4Ç;]„ŸÀ=ê..“¦ê ttÑ`—9`“øÜãJ«¹áw™éDÙá¦hÈ)ßÌø™iÙeC¢ÀîBt´td €_}®JolÜëÓ³óúIee7O³ª¼Å)”8$f”v™9+Ðk¡Zp¾Ìý qä‚·W°$’JÏiÔìF•„–8 Ž[·½ôË1ûöÊÞG\ë_<4ÎÔõýÞÇ݈„×ç§’Ûrë¸Ìÿ±×çý™Õ»¸yž¥³÷ !F2j`áx7dÉî’èž·(Ç ‚¦|¤ºíFUB‡àäF´k S»Aà$ Ôt~>—`²+ȧ¸vduK„ÏóâZ’4N; X²¹¹U›Ô¶Ò0¯ ë›2ŒÔä¿ÂAŽ8b•$€F‡Í ‡m@ãFòuß,ì|(`”tÀ$ïS¾Ò`­Rw. Ö*w@Ó´F"•ºüBFÞëuÏøØe¤Ô^¶ÎI Ð@³›‘Fý›‰0Ý.dÚiñ¤e’‰Í¡=,¹ ³8 ¨{hŠPÓˆLhto"jî·>ÿ˜‚›õÒ <˜(%i­ Ø 9ª-1Âv€à6ø³ËL-ŽÕÅ@è–ƒxïüï¥Â¢¼Qç/Th2ž“ rÅ 9°¥¿qýMú„RÄq?DȸåýZíî…•Fk?âØï¦½ÚýIà9Õ.ëJüùÇwîÛ—ˆ»Áñ2h¦ºvõf7ª7Ö]õFÍ„‡u¼´ª7ÎΔ†‰o+GŒCLy¦2÷´`ÉKõjωìp§9‚dzÉä8–g ²,l Oæh:Ð3ª7¶V¢]‘Ö·$ ­5cP} •= ^Œ#º±V©ûˆÓV„e!8ÌW€+„“|g6Nç z;Û/Æ©9´• ]ƒî¦"Oã ‘yßsôiª}%ãëK4>G(¹Æ[ü­½d. aæB„—¤3à»ã€ìJd~l¿Z!Bƒ¯.ˆO£"¸;Œª»•=ô]› …çµ]»ñ©Ùzʶ­;JC|bÊïrþ6ñ¼Õºâ§ž_,Ä1¦Ò¯}F×l—ËÃÕ“ø¡pbc¥º†´EðPV^ݺŒFʪw –Ù»PÔï][ ĺ¬Ýlnz×ÜåPmox×°yPN‚dÕˆµ$‰Iɯ©…ÝÎEëneQ•®¼k–\’ß»F4seTÛq¡´Ù ²ìúœzb7^ø[?Ê»õa²ý´¼»½—¸·Iãi²ý½¼ëþ±5´«ï w¼c´HÐ¢í¥Š²3ÌC6“Ä2¼†>B’p?/Ë ÷6tt©Àù¢Ã1[þ“ ¿¸s±ûRÂx!Â/‰òIÊ÷—r9<#‚,ÐßœD´ï"n¤‡#Î|¿˜+ÝõÀ²|ü3Ûç£Ëºcá9¦s;ÕÁ,Jvç~@è¤'šh'Pê‘§ íÑÛ]h¥xkÒÔ|É…ÛCé‡pöIëÆ/!å bC±…ﱇŽnw·>oõXûè‘Æ’Á’g¿Tj¼†LeÐý"êÿ ve UZ'D°ÑC#ÜÍSŽYYïïZÔá¸Ä@Öt/hZ‹þ`²B§³¸Ÿ&¢œK$•Ñ98v2êSA-aùÕGþ˜Ö*«t%vf¨£^E4;+4;C}å¸á¯E|0#1úxú_“ÁJ䘳îçBHò¬Ë¾Óü[Ëñ«º¾J]‘Ÿµ A6!T'ª˜ ¼¡«o¥MleÒ u/Ê梮‰¹Å…Ù|ÓØjG››É3Àlh¼à8!Ö.¾÷¹€ÑrŸ·îX“ä#‡ùȪШBqiKÂÂcæÕB Ïê)Rž#x~K>¿î Ѱ~áêÊÓâœÙïnˆKôm¼¯·Ç³Y·!æÓ4 UMDvšOúN`ƒÁ>'CÈRQ÷Òê`4¾eA½ A‰¤ÿP¬ˆ»ˆéÙùH?mù!r /V‚V+ŸW}F eû‡4¶LJ‘ú©ˆO` võ³("ˆ‰b×-Ä ´Ýí–DðªÖ}Uj·ƒH6âG\´:Pa$.H´Õ»&¸¿Î:Û}Òl·eZ‘®ü̯ˆ®³& _Çï %¨› vâ=[û†xM¡2lì–}oÇÙ®ôž!PüJÅ¡a,ôñª¨~¶ë]Äl©@£áA ZˆÂQßÙ_e~$ñ#õªz ¼`C…ªUa$¿úΩ×h°Î¨^„ œºgªsñ F@ïmƒ’0 ½‹$R–„68ÀUa·àZÑJ±ZïÅæ&—Ü.ˆñÑ©WÚøã*Fó‹ÑüTWļqäÆÚpkhY#ÿ<èëææGú¯3º°"?,Zôc½D¡6,´GþH‚°wöÊ\X0,ʈÏA@X…’¾öÑWvnVú–Ó‰:=?á”w€¿ß #‚lÓ4§Ì$‚xö‡–wà4.ñΜŠÞ´Š@¹¼hÖÝ€~|~á@ZíìQbmE¾ÂÐææ ƒ*Ø4=ÛEÀ­àS`Yiöƒ)áÖiS vfåêER~Ìxd¨ƒ46ì¹ì;5wt¤ °2œ¶@Vê ìŠX³àŸ¦ì„ú$á‡K–a["¬¦é}¶vUКȂ¸§Ô-yCW4àîžÝhP:=¶Õ/׉w|÷#Ì_'8f>)©WiæFì8"Å™Gö%êþŠøÄ—þ¥xI ¹$±Ïþ?ï¼h!X<üu—ì¾»LÝw{ƾÒ$càWµxrx_žw\ÞFý°mÁý#4Î.Òвk¿ÇJ°íöµÏ©Ý÷#ö }îôAÁ╺’ñÙª¿Ojaò‘‘Ñnú˜ÄŸ´ä"™‡kN£†O¬2~U­‚¿(ñ¶ F:u°ÆCR±þÖªFàžÆÎGcç¬Ð ¿·’1K1:Í!Ä ©‘òä4áeDf˜ž}n-QnŽ£ýšzAÂtç´  –ÐÙyO‚ª€XRm°kUl@úHà´=«%OÀ11?®×ºT ô…ÿëŽQ§Ÿú.ìû„u2\³~nvþ´.Ÿ[[pÅ•Ì*Ú%0Cªfçˆ$;¢-öM÷Ö'x5Ž5™ªbü0…ã;Ü`»&i=’J4H©Òq,Îm5©ÚeŸÄÀ(› üƒ>î¼|@ JÙ‘võ«²$xS÷ô^²dé7åW´½0[ââ°ö¼Ðsïg—í’!áŽúð·vÈÏ_-øÈè";ñ©9¤·r™„yâ•—l¼#­«@¨dçp ÔÔW€X¨4.]ãaûôbÛû Wá¤Ä©íp¡§¡ÖNÑ ™;‚0ªe¤ŽwB)þéŠáIs¤é²ŽT›ë¨¤=Vb¦Ð¼É~{D6¤÷Ù6d^²áMÉ.$3?þq»‡IÍW+eûõxñŽlóªtJ=ŠŸI+½5Dl„þF`ö°N@ÚZµö¸Iø/Ä+Ú)عzÂûвÚ0´ô8ö:Ô €rš!lÅìD ýÝßyêìì‰ûwõ§-ó;Ó¥S2w[;·ÉÎM²sì|·:$Ô[Ƈ GÐð-bn Ьí}mm5ë[*p¦÷¢µå½Ðon¿µåöÕ"EfŸj^k«æå>™;qÒ¬[*¾›[ÍÛv Í)¦™WФÝÖ†úG³B“±ñGŒ€Ö]áeÝ™0ÛA<÷9‚å ­[»éáÏ”þì\R–~ÁÞ‰è7¤ß.ýîtˆ½»Æ§œ+† Þf+]«°1ÄÚ©géUDy$Qì½ä/îÏ_j#|Ùþã~]Rbûóýt•ÿS–^ÿÎ.AV°Eíí÷?Ý`}ä}–ÊÞÎí³ÙÚÎö),˜íçD-Á°”[qÀùòª0ˆÝÔß8ï%èŠ/Pi~^@ ÒÕ@^÷A¸ð…ïȰü^°·ß· ƒêýÐ;¥×¿Ñï[ÐnAšïæ›—ÖÝœOùáIº/&¤„×Mo¿ÉšmJ´øv~‰µ>âE„íã4ßsvã Rr©ž«S_g©íÀ'²H\Y„}Îê¹:ö†0'ÛÈÆ¢¶3Ç2Õ>–±z‚37ü'n =€Ã]8{“¥«ÒjRÞ®Ér0ÕñD*w /79SÁJ‹ ÆkÆ}ĺ<–<~M²'̤—ò…f'ùQâXî¦f,Ǩ,Ô$û´Ž‰X³nWbDJK==UlË4{¾pKGÆó]þJ†Ú-2ØRV^tdVÉà säŲZzÉy½+±yáÃ’µ$—©W­˜î-ñD1V^^]KÙ€í¤ê\ÅtåÓUEh}e<óÓ>s.zF<áí—»â Ä-É0zT—/’sõϱˆZÒoççÛÏËôçà§LvãÈ÷žµïfáÏ'H‹™…Ò³R¡Dú…Ýx•~Ô©æ?­|†Ã,CçŸÎÅ®úøˆ>*&ÚxI̲ÀbwhÑÝ1iû4T ¢Æ6ˆ¢ ÿ\Ë@¹*xßáAÊÐ*´î¶÷ó™†ÇêE¹BSçÙZú^ ÖÛFªïÕ"ÞCªÓVº"Gª ê8ÑY±ßSç0ˆ îçòþËãÜgkiwuZ®- yfÏÎóGì;÷I S–“|áæÈW?µ]áÑ’oûG.߯Z¾”÷¯É•59¿¼oßæznêõ íìÐ,lޱ”Bwi/Ð(©–+U &ðÕH»XÐZ rdŒ2 YŒÊIƒº1bõL0fxwìÔç%0+tj1â¡OÅYãM¡Ï}&ª–\Z8ï¦kÃí´zÃãÆ+ÂÛÞÕŒÆ~§ÂÔæY^PvÊ|ØN³®Xæ2ªÅçL†[ç<-ÂNÈžoT(n³Âg·YÃÕ{æúìTžÁ™ìš,±1¶©y¤t5²±f¬ÄÏﻯ¦g¼Ç—ËÌü}â ßécá¼XBZé¼X¸8/Ú}>òCXõgp…¡7ÂúfÜ3p…ÙE«ƒÎýDè¬Ëç`G]üi!‘¦(H†e-VIZh¸Í»féms“§ÈÖFec…ê¤@#ÂÃ3·9Gõ%)šœ‚… õ1eÐ(I¡…·ÌšnÏ5´/L<ÞSo°¨ÓA:±®Ï«¹ÀVjö]²'T¥}ÄȤŒ0¾ºNJ‰]g¡ò…âk ‰ýÉÞ”$Ö˜˜õ>€1߸DÛëþ€¬ ¸@‰{â>GnÑ ,ðBûæf—Ô ìñ³Ø1g7».x?"/‹ ¡â Å«mÐÙ¾Ó¸±ÇiÓ³´é±çü’¶ç&˜æJû—´ŽYKeÖ«j1¹°FZû‚ñ”mLr»ŒgžWsRÈ!̹åÔ¾Èg^û)P×òŸ;K/l½õQ8õ±››³µIl.%eàÊþáö´¢¾ 0ýà?Ø]¦œ­Þ§-—(Èúá+e‡_“D­¦˜Øˆ%ñI‚gŸ^~€ìê’°Á)¹”?9…Êü-°Žúðá7þÖôƒ˜>Îu]ÜÒ#¿ YÿÛ‡36«ûóþ¼´ìÔ²ˆÆ«ŠrQ  äê•k›Ñæºþ–Y&}‚Ô–GÖÄ$ãæü¼””­]NØA±0÷©ª‚7áI/)Ï$¥äRÚÑÄþV:ÈôaûéÂp8‰Lßt],NàÇ£tײÊ;ôé†Âß ß• ŸúW¤™ÛÄê {\öplDïû…8Ú\®dâ³§å!¹5qjßü^©ÔæB$V0ëÞS-žÏÞò+ä YÓ…&TrB9´þÅ9ˆª÷­êȧlð²è1¸Rcp'ºQãe‡¥‡¬¿õ#ìûýަ<• }§ï7–fá}’¤¦N¡Ô/Ú«‚ÅL“4Èy¶±±ŸZO+š«Õáݼ5·­œ '²UA;ˆ¡¿a{¸‚KlÁ%¾pÂÚÖBá%ðî‚55wAYÅ!¬,½H4Á+›.k\²|ŒucœÇI7ámn–J¡ïG`rí'â ߈å.—ÍÍ ™?–V ¹¸9>ù²¹¤O]ؼM§¯WYúz•¥ÛŒÞwj‡„H· Â8^ÍÂì[¯Ñ ¿0£ µsóÒ´Ø¥xL’@\,—é¶Rj{à‘¼åÒú²mÂS¿ Ÿí¾ÔŸÝ—¹Ïô¢ŽLÐðîÃbó ,ô?9õ¯¼<òÉq_¢9wÇ©9§ªQJ;õûìÞ®ïgééÝ©Ýtwjׇ[ƒ}Ë{TyX®°ŠWïäE6^qËÞ‚Þ¢ztj3lMéË~"Ælõµ…?p4½´ß ·%ådaáY¨M %|"j ;Àë!‘ëk°ozÐ÷ÏHŸ¯µ\Ûk`ÿ»Ô"û’TìnÑc¥c‡)¬E‚aÛ=²ëPqyÿþ¥¬Ìñj¸Ö|.í™Y±D>°:>À²×‡\ªfP2/ÙÔ–Ý¡—Î[뮥í«ëd»—ëØíjG}íýõ{²#}ț̰&åxéôÑó6v_ñ‚g ˉ-Éqýé|j+-ÒwÒ¢%»Gjû I O@ó‡á‰ÒቜÆÌš c :=Nôe‚ϧµ<ÖÊ=òÏÚ 28­U LPP®TÒpN©$û6Õ¥/ÈãÕÅþ¸Kb}š£C,§°—šWý.YQßà4ëPÍŠ]våÃ1”‡¾lƒ'"ºÄ1!>ÇáFfÇíÚ'vB_bñã̓“_–X» >…çî›}ª'IÎ,û“¿Ñã”üãT=èÁ‡M.wo[—¶÷ªÕ·«{f‰Ù½Rµg-l;Å~a*‡Ç+®á­É»5ù¥1&Ö¯QÖÏ¡¬ëó’M_Ö= µM"ahÝ}û¼ða.Psí#oèwx¼./rº8½È§O¤ñ±®IÉ¡}š"ÖëPrw±ZÚkaÁˆÏsï9Rk}÷K¨ÍÍͶò±0ülü ª»&ñ)ê{vd*d¡lµâïy.1‚tè¯nÛõ¾]·ÕNf¤Üa; Ûu>Yíê6q¯·ÿ"tV·1Éè= «÷ýê6ŸaiŒÛµ1'¤gv°¥×êP)eÏ‚zkc™·µ1Y«Ôåzf7ͽê¶u×¥9ï÷¨#²ÑÚ.~4‡Ç0 8Nwĸ’iÖ%*1y§ì+Ä-gG鹃ÌGA0ô؆}·=m…+Öë Ûc{llŒí¯†ÛWF­iÔC£qeÔŒí¡qdl_Û£öÚðnz`ÔwŒíÈØîõm£Ñ7¶c{Û¨}5¶›ÆvÃØ®Ðð^µgF£g¼5¶=cÛ5ªõ£Ñ(h/N¶‡å2¶QÃâ!û„Û ò1zäù"“Bz´BéhèlWh<¹ÃÙçWøüŠ?7ÿ â§Ïµg>þÐXþ`"¤!ò^YøCé uÖ¯êÈ•ú‚÷P²×¾b›qíµ…GTöÚç »T¾×Â;×Pß&B泚¡ZÓÆWì„îáãY!ÕÃ{£JI”š?V¬2ü¯]ÀS¨}.ìÒp|T©­fnU×%Io#‹ÝîññAï£5R{É™G’ J´Ø•]˺¤tÈüÁÊë¥ù>ª Þ%K„Æ Ô"M<ë9e=Tb‰vd­ÂwœÞ´UÖú³µ¬r:—+kïùص7ÎΠº;8Ãscø˜X“¥ºIÝ–-ÜÚG3MWÇ]kø&þbBþkHÃLŠpÝA*•LQ‘$ïùÚFs¯Ó<ó›'¤<¾n (8nüº›+5ƒHÏÄýŒN‹Í³Ðü`7ßÛµª½]·k·ví³]ûh7ßÙ…R¡ùÖn¾±·wìzÕ®»vóØöö^ŸÚÍ#»ùÚÞíj$ à¢æÕy½žŸ-É»L®0=Z|ܯ«ö÷<ç»*Ôr~@²Ó¨ËJ[Ï¢¡ì õvý´1²6ˆQQW„e_²Õv¥MŸ0WTì¬Ñ”“ûÔËZ•φ²™‘Ì-Råä/ŸDn4ÍìÖè¥ ØÒ¬ÓƒÐêÉô‚«p oâ_«žßƒ7ƒGvмwÖ³Ë&ÈXÛ!Í\¥@S»$Ɉ,4…Œôf;=…7°ß’¶ŽxÞë‚}Ô m÷•žû|*­à~*ð …& Y|¯Íáî>6·~ßzR¨NíŒ]˜Ý±ºêËc[îø‰84ùBŒ¡…#gVûÒ—ëà…XvpÁ#Ä·Gê)ÃÜtš‡&s£Ãì¸êÈÔ9ø $¶Qª 0œà%ùÊÊNhã/Mqúù@úû&ɯDÊrbÓùBoË'ú^'¾ÅõÒRºDnCˆ˜m²MpÖÒÇŠwycP7õ!ÝUkd/Tk¶wÓ ¨k­|Bw…{ffºá¤Ð|i7_ØÍçvsßn>³›O k$>U$>‰÷S~<%Ó_û©Ïº£ðQ¾‚0šSèq.JõÁÈc¼ßl"€ ½O­TЃt òÇxÚ®}f«c¢ôu_Žå¾ó ÆþþìoaàCS)D‘¿b/Ýa4¢:ÞLÔ¨´@µõ?œú{8CŽmÕï´U±›?Z…Ú‡­›rpS®~,×»yCyª.ý9jÙõ/ô§úžþÔÞ“Š÷†³{olÃÓOÇ®qSÁ·äH mPžÚ¢`W¥öêÎŽwÎy‚¸`×®[…G[ ðþ€¦ŠÃ€±uËiÍc;¶Õ}äþÄ|Zw`{ø[þùù®¹™ü†ÓîÒ>²ßú1Yu¼ÜøÂŒ£ÍÍØiÞðŠ½©µ\z’éM’Ï…;»öŽ·óòa~yÜ /¶2zXžK¾©“¶¨é-k·°Yhv±§7vjï’¤Ð\ÒKÁß•Ó TÙüô7«æ•íÒÿK\ú¡Âm† ¤±JᣚªSº¾$ÉÃhÝ ¸¥§ì`Dÿt{%µƒ×ûÃ.ø…Ò TÀÉ´øRÅCßpÀs\h»],”2aùAÛý„íb°Éäƒëµå #¿jû~³!ö’]ò’•êUøÝ/Ä,þ}/CðÅg?@Š~¸;yŽb)YC¸eÚ“M«:ö±¥€‡Þ.üÌì+ÛÓ]úZ2ͯ>—³v9hª‡ b VŠ^ÒöÿÍxSæ6p{ƽ†¬£¾Å†BÑH‰Eñúë+çX̸.µ°˜Am™?éïî?±¶½ŽÕþææl•ádz·/ϼÜIó8‰´[;¦ËûØs't/ZÈ(à6š ’CÁ•'öH£†¡ŸRá ÊèÞa–øŸÏÊcI€4 ôu7‚K&¥ƒtœWCœù½Ãw½V³ß³7Âí:Íx×{j4c³DNÐ+X-¼ê©ZÿbõœÆó­ €éOÕµ‘Š'ö*Þÿjæ„Æ{Ní)ÕÚ-A¾5¨*Oô—rýC9؆ZUûÑA4Û‚¦m #¨Aͨ¿iñF’rŸË;”w¾TiÎÓÄOhÃ} *®½Geo/v³ÇRÁ6ÀÑZHrj×V6²13¤1±þXùR…v@:å2µÐ±°|¯¨*#¦§»C¥.äV½5”êã ºxdÈÇ‚·wŠñ³ºN¢¯ ·:ûÂÝ¥¯¾c±ìKeûNóÊìaŒ´Dð’ú €i^B¡=(0¸kêÔ%ª‚U ‡–ÁEŸ%'fçDw–²ê¯ ˜öY RÚ¬2öœú!õh@ƒRXCÇÉh=F¾¬œX ³_r@²ÌXw©È…ª¸málµÒ/¼ÚU;$YêV%‡wú¤b‘â-Ô݃ӕÑÌkÅ¡É#„ŒÎ}ÞyÇt¥`KÛ=ƒÉLÚ MìòhL…î'p³OæCwôžéÑÃå ¯t‘W(òÊì=Xäy:à)ƒ)—A'Y–µà^‡÷3†a,ëR`dá)I?U¾;Âåæ&±™°£ú¬E€eµå¿ñqìåã7¶b|›=ý´ó:·W’ˆ ¨!YÛÍË–2)¨%±*rÔÐfkWUI#ÓÂÚ¦à+m|^Û"¦êÜyU~Kú ÷ÆçSão@ð4[B>Pƒ›?ÞðR€}ä{ovgç5m•÷fsóFªwå3!ãpýÀ'hù]䞺R…-ß¾q¤S Ïñò©Y(ñIêÖé6}x$–ÍÒ…ùLðµÅ6`S)†ñ_]òm:P %~ñn c·å¬=ûœ>su«[°EŠ«“ŠpÀ-_×UV‘ªåç/rßvñ×$Û/€?æ#ë›êп¼ l”RAiäÊŠsßèóñD–°)”öi{P/å×½åßV‹o†*´\"åô" >gÛtêû|*—Uá_ï’î$Õ÷ôJÔ I~ƒ­ªѶK’¥­* P’˵±ªÃiRA3;%ÜäÚ˜#¾mâ8w!E¾ǪǪÇÔ m3¨åi/êûªyð5`€!m¯¹-¶¯7¿Uz ߆ Xºî·ÛN}N­ ™7Èð ÈèwuÏ H£ÞasŒ¾ß»îUpÚäEÖïµ±“^R†çf8Î2<”¡QöÊp»ÞÄñƒrM¬ûu–@èie{Ø-úÕ¾Â"½¬­“8kšò{¹séT½»…wÔýjƒºïö+>¸ß ä;ì™í¾ð×Ñg×~³ýÁœa~Eù¯6£°dp¼Hýþëíî ª·Oìžy Ç™Üª$3¹Áºëƒ4ÖÈ¥ïT«>h¦Z…0Å+"$…7PS–Z=õ«˜Ç_y•^Ý Á—ŒzÛf­a«eÀ-oœ¸o÷X.ޱ¬¨ÃŠÁ¸°ë¾ÈÈ¢\˜_åÈ>Ø´ÜDÁG°;¥ò…oñÖà°TÆQ.Óydý¶E̶ëGŽ»0ù~†¦bÈÕÐìbÏ’íû]ÞˆÃgщÕÃ(ûL¯5œ8ºc†ØSòŽÛT—)o[ªNë‘×mëŒ^—2áF3¹ÔäêFÙ/ì–Ý–k= ©šn;rªÔNשq¨ú=MwâŒÇÆêFæÁQsROß>B|.ì3)xÛ°Ëp0Ç”›éÔ =|YÞž òþñì:5kOù¾ ¯ühÉ%n„ õŠ[W¬®ÉŠçåçülÜfÄ’phðUëç›>î<Ä6=,ÁÉ1Iç”Dªh?x%T×kNÌ¡í2 °eGšöÌÔÅüÊØóÓ;Fx Ùƒ†¾Ó·o¼ÒL_K˜A\Á7cÖzº­oé#1ýMßrµç«;‡U[†&Ô+XhÓ+Ìßœ×Ö7¬q B,}•R³ÙJ/àåO,oÇAe·Ûºs_µz"ïåø”ÜˆØµ½e«k×Ü–|ô…J; zZµCÇ[⯷„’à-ÕÕ»xÆnñm§þºƒ— Þ`ÃïN³FåêÇXi…#À¹Å˯ëÊ b{Ú™½o"»eá¯êU›oÄ!°îšð~Îì‰öuKÁ£ixïÖ’M³ìí8;ssö¿ß¬-Ï*Uœºõ((u±õ‹µíÖ™ímgWŇ«û="˜SR­é…¨…‡Þ©þaáÜL,Ï©c¸B¸¶ßJYcÝñ¾Xê—¡vNqÁèÜÿhr ïKu^(ÌP62„×q[ŠÝ©gp<ª#w[‡í.ô‚}º6°þÊÙäÝWwȪÏmìäâ`À4"\ï*žonΟ”wf»ó–¾#FçËaìê å“ Y`É”.#©:b,Ë y¡óXq-ô»¸øã =ÕÞÐd£Ÿ}SÓ¸¿m!žõˆÐ€Í B9µò[Lø…ÐB ̰0èl}l‘çx¶®¤‹<{-K&o¹LÓ·­îC„¡‡z0|TÛ6ÃTa×°R&cOC¬Ð(§WAH›?»oÈjl‚?VŒgÙàñU@Ù@ZùQ)ìŒ XïtN‰½I•¨ÿa«ÇºUiÓ®@ŽÑÊòÂWËü4_O„—%ŒW¡¨ŽrCáê¡à¬µºjûc°A’Ñ ™­>[Šºku¾ìÅ?V›\º)ݻۼø/ÄÊò}ª¶SêU¹RU•¨,¯¬®S¹®ô8—N¹Úi:#cÁÊfyPsø›Ùµ³ ¥]™›J¿ q`/Â>U±([mÆÎdKaP0F´âv¤z—wÕ\§þn·P‡nÔ¬¬ ¬¼!ÆS±][µ²)P2a¤ŒÊx¶¡JK¡±ª˜5ø}WݺÛµv®ìa«ÙÍZkgÀ#}ç©û_ê›AoÿAz¹ÄžJtosÇrF.bÀ1̰e¯³2;<>•HÉ?^¥ÆŠ7Lo:¤~ાõÕ®~£8µ‚)/ Šd9Å6ßZàŸÚnŒ—ØvßÓ¯÷îŸùêÐ&Îkî࣭@VDppÇR¼À®ö|" "Šj…‰¢ÚÃpŸ:Í[Y¡Æ4]¾ð‰F WyeÕêræ¶G9NʾW'%S;/JÚ^š>Þ~^¬GçEÊ]q^¼Ð‹è˜ºçÅÚíy±Ômg7ˆg–1z_ ¨5Ü&N¾‡Ç!u·ëìxæÆp7h©Õòˆð{í‘üm5åB«¥ÏÍSiuʽÖè w ¥‡çÅý¼"Ø {5]uF>=¯NÆc+ý/Nì«î wqk_‹¯ë«õñÚÀõaA:Èçñ»é=.Ÿ©"¤ÄÃË·óõò/µ¾(ìTt§¢Šª[T]iYÜÞ×ãÛûò)µ¾J2ƒ]ImœäÚÀ µÑª°©„ý"E»áÙÆŽ]LäQ%ÿþß°Ÿè`!‰„ôH¾óD¢Ê'–“ ˆT‚(l B'a–p8¨¤?':]‚¸· "ð& 6‰¾#5A\¶7Á8HQ¼H¦?œD¤\vçÓë8š'ÓÇæä¬§h¢?IT(é$˜¸ú8YÎG‰„Kß.É£%A&ãx%½8N(Któ¶ŸÌæÓC<í'½€ÀŠnÑ$L$š eKTÄ“d¶Œ/“A@=í-¨Oÿ•H,¹wÜJÒ[ΉTN}O‚Ùlt›pL¯gˆ\•¨§Ô…kÂ]‘pŒ•ä^ ¾d?×ÈîÜ3áˆYŒŸËaF“ä2˜„Tr,zJbb&Áb1Çø W” % ck1DBH.’zŽ0kôí–:ªâeñ±éQð•Òz—Ô$ÊK‰ê–,¯1 IËaHÃ9N4=áØãIÿ&AŒZàãÙÉIÂñy“4È Aý5Ú›ÏiÜ$í¨7‰ŠpFRiA-8àžÇA?˜)AÍ‘ÉêË$J¤&"–ÒÏHìY@T'±O©«QoH€é8£ ÁÛ›În‰~GD°‚G"®ëI4ß×D*Qï’I"š‡ô=º‰zèGï+ 5:¥fÊp³8vGÀÈã„3PoƒÅxDô#à-'„ðJ@ŒÜäÅÁ) òÆÕ8¢ÜÉl'ç6].’0âÁD3Í‚ÙM‚0¢ÉU<çÌCîKßNzDÂ<‰ö%¢WBc4ïhè'ÀQ ë·eDUaù˜ñ1ž®‡š]‹§MÓ(™Þ%Û>&uxƒÆÆèùhÐôE @eê,AÉÁèž+*¥ôE¤©xjÙL¨¿à.Ó!‚æQL…ãDGIJboJ8È&lLåzô{öáðQ8áƒòHH8a1sBÜôhz­†ý*fEð cŒäâT¡u@9áàĈ.OÐNGÔb½e¼˜Ž’=~z{ªˆ®;šÒˆÒ÷Ù;bÁ@hˆ8É@Ñuçˆ"0“›[ic˜+Ôöœ˜ ‚‡Roãøšˆ ¼ “/Lhnµ±ê›Œâ*}iN̘KÑ÷+š#SšÇèV"r©µÃÑ(HhxBä[L™ÿÒÔÛ£Ù "ƦL <‡ÄˆºW p™aÒ ØVìR‚‰&ñ¼—HTgâ¨ßN˜m÷¨Ę&8ºòä5¢áO…üA•C„žj¦ç?ÑTK0;I–̘£‚cš©çG¸JƒŠ M$o*ùK¡“ÐJ#*,„‘x< ‡ý!ats1Gý"ª1^¼$’ ˆpdzd9 A¿䑨ÿGìsH|sBÅ„D ‡ bEÔûJÕ#f—¦ò7Ëq—ê•ÀhÌü‰ ïþ.¤8£—^4[ðày ý„C"<„ÝÄ ÂŽ£SÈŽ )rñä2Š Í&<¬“é‚;(!­¢fDEBcÒ& 4KZÜ~d¶&_ˆà&u*”‘Ãp ç‘b4äa(¿ƒè3±£Eð:ºM¾F·L1TþÓKbÌá G¤ýœ0dž´Ì"k'i(k‘­ô2F¤!M¸J†biŠq€VÞ IJäjÈ=Â#¢F*iÎ숇E¡$Î&V4&aå’ OGÒ˜(ÂKî¬a$lÐcl/µ…2Û{‹ù(v†‘aõ’Kˆø€™à´%£§ˆ‹Ù\X$É(Œ…dºÓÔžT*É<‡Ó$¾æ1úIJ³Ã~úˆ¡–I)2Ï F¦¦,`‘' ì9s{‚_q(b'Ñ>ãg{zK“Hs ƒˆÀ822çˉLË<æúÿb*Ä‚nÿíñ3 Âz$ 2Iž¸Èbªgqýˆ±âhÅÉ»·'§DÝ2ÑŸN`ÀRúKòÕ =$u{£eŒ¹Yö.™éʨòM­³âøšEÜWSÒàH-J GL/Ë.é/¤ØJ¸%:î-&$1/RCH(ÿ˜TÓP¤MÒ I´*° ÑÍlNò•f.Ç•ÇÃýd ÍHÒy(1=†"?‰;Ì-*<*Æ:Mtt[èRuæ Ÿm„P-ÜZ^ï<÷&Íc1ãùB]õƒ´0l€¸uŽ>¢KüŽ ‹x—`ëWÉuÔýJ¼Yx Stò—Ò½¢o‰ zåøÓZ¯VjèQ`âѧ`4» ’#nЛiÆŸó¼–N”ê Ñ2Oyn@}\(ÜŸ°b>c-¹¤½¸$ â|0Ÿ’4!éò’ªS|?ÙcfüY³Æ#.b˜!¶»PÙt„ÙDÇÖMT XF#ûtJ Ô3¦Ñ¨J+׈S¬æÈª7x~AòÛ³T[G6(áòÀ:r4'euøC©ÇÄ÷Çgĉô¨Fz`ÙFB}2P¬~©4þ@lL$IŸôYRåGl•ºbhB©$¯IÃØæ” x¸d™AÜZr0éE£§Ë®Èv}B×TÍh?fE=™7"³Á6 Hê0MŠÖõûYk<Ü +àüR+ôšá$)õ!£]†š]«¬üMHžÁw—PýÀ#†#­§¨z¤låt¹+1[I¬Üáá™`11ìÅhˆLöIe¢Š2QBf„«É”&qŸÐ-“‡TVQêXT‰T¹HszBÖàµô¨?…£2ļŸÓ¿dYq½í„1Ws›Ä§¬a!|©2wô ¥¡µß8'[õ„„¼Å~¯¯$¬b1†šv?‰¡¬ÞRógØŸ=:Ú²¯1jF‡,‹a!…´%ÇS;•¡aOq1ˆd&¨O*öuÂ#C#4:m ‡Ón‚„ÄX%Ö=â‘øèIy è¿ZkÌ‹¨,^úà9 JaƒÌ ê£K,²çl¾@ˆÀÀ(Ó»CB@¬ø"+²©õMT&zMúKêÚw0NƒÌÝ]“àû ª¸O$AÇÏáæ ^™]òóÙL~÷1KI‹×Êq,=‰ëyÕäMð†+yKº]•@dµü#f˜×TÅ+Âf¾¶ÂâXèŽ)›Tw2‘Ye3&aV­˜#}U|‘¦Iòâø” ¨‘‰»Ó¬$¯(µâ&§—ËädHó(9ì'Ìï´à¯==}G,89Ò¸ÇSˆ~²/&l‚±:¬øÔTTÙ¨O³_bÙÄrh°ý)©¸l«3³»î_T/Dô("ítˆ$—~CB’0'Ý;„ËG E*w}°¿œk¬‘ŒfV”_¼}ƒ_%Q…:YeŽlP2]²š¢ì ÖŒÕsÐ%S(eÓÉŒ dö_vª˜Å¤hÙÜ9aµuÄe‰¼­#.×Ü".W­z3qù¿þ 1ã%»áë‡$1îŒb¬ôºb˸[ÙF±]NçiaŒ{ýpñ›±j#’3F&ÔpŒejgˆIH/Á †#%ŠNQMFÚ†_N—£ ¶h¢C$ïë.ÿ#˜µWËyȰ667³ k~ƒ¾h|íÓ=§ÙÚ·u…7ëó+‚I}c  1’e’ëÛbjFÛPt £H?M³u,sÊ©icHèùX0(Ê&ªÊWÛF4¡‰n† • kL¦“r<Û8;Œ{åNxÄ®S°QŸôF}b¾Ó븅Ôß1+ð@ÿî—JŸx8|Cûw Ó2îTÃpG=é Fb@ªRŽ®-•JŸ3¸‡z2j àp«àá̇Ç;ž¢&2;bƒZ‡ÕHsKŽáû”w¶DCu> ÆÞ˽—[{¯ö>+Ä ç¨ˆM?E©Á(žÐô 8»³~²ui Ž5·¥°AªMP—X<¶Ñ'Í-R;ÁD)ºE³@)ŠÈFŸY!g:JI ­‘pfU‹?Ó˜œ$ ‘#Ë0=ôð ù+§Í£æh/ç<àȬóñp08” ’þô"!öéÆiÃÜŸ¢Ÿ1ªÂ<Žu]¤>HCø<í¯—#âf7£1n’ ¡‹›2¦½^[›è=ž )hø ÃhHö~«ªñ‹Ù8'%b9"n¨¡´Â~g‡¢ ñf!dº·6f]¬p/l†Hó]\ª£<Ъ<»OìÙÔ1(<4\ô]?ûÖÍÐd‡5ïóM)j$:n¢I:æV„q0u‡¿É-BõŠ g0ýuT%&—´u´Ô…®aˆÝ„Bí<®OçÁ$†=¤p™òa{¤0-ñ€ù ¦šNÓÜâ$ŠÖè–Ý>ŠN ÒOHÃ-Ǥk "„”ç'ýåœòÐб¹;볉àQ3I³²_ðˆº&ƒÑ0¾Ô_·îŒ“«‡Ôª8’J:t UÌ5¨³CáˆXRüXWFÐÒT%y’n©ª¨‚`rk9( Œ †²”\uh@ydP{Ó¹¨ØÌ¼ÙÛ¥¤ÙÓ ÅL+9*QH¤Vl¥!QA°‚(&íò~n"YÍ [J>– ­Jµ 1½Â0Íñ{–Cê’Yeð¬"<` ¥VZÁ¿~ª€‹BŒ24h§j/ºœŽ Š0â0UÊâX]°¾&lAK<37QKZ¤suf1WUÑb8~’–ZN =éð‡Š&Ö˜ÀâÞÜ·™2dú“{-z2X¬¦’JÊ?›³®4Ï0E©uôì!åïÁú½Ðs]æï¯óÉœUídP2œÐ3Ç8[ƒOt+5ÈÙpØ,ª&Fá÷܈åðþŸtÿ¿@ºÆ›éBù‚n§Kb Lâ°è˜wLxÑkÜõ09š¨)!G@-öéÁr1Ã#L¼ìöA‚ÿI½Øû7Ê…ð¥wRÅšÆÍx5Ir‚ÒoTŒàZc³EDQ:X¼`ëm)ö‰»ýˆHh<œßäunMPª#ÉQõË÷û*‡d„h!،ݿûj®c-Ã4ïè®EÕTè£KbMé/ªmߨhÍBɸT¶dØa¬h‹[øÖkpUÃV×ÊKþ<¤bIá£T¼`¼®÷Cä±l}zðÓçâ]ç&ƒí¡­ŸíÝX.2”2ÛÙÍÅyQhß«p9-ÝöØ…ÈNôXÓ2*˜.³åÂ/‰ç `Ò±Rµ.µ‰ó-Œè&å,\Oö9VSbp{e3øå‰7,¤ùº„üÔª—ªn ¡NU`îRÑïâõ‡$úœzª@ ì˜öîU½¦zè~a2è³QÄr”Fe>Œ¾ ™Á‰9Ö˜`•…ªý+ÇkLvDغö¿Õù8ë=fô$¼×ƒ…8þò’+uhî…!o¢£¡ÍTúLš*Ûö§JàR$´°þò’/v„-öR×¹ Œ1alJ‚w g채‚ 4ßä(/³ª¸•ÇÃLÓÔöÒw×ÖL®sѦ”ÇY_YB£ÔRÉÊMXÍ4GJÔ†‘šƒfŠš¾ÿ̧:éN4ùn9¼ÖÄDHFn2¾ÃŠõ«3†^ËtjÌld9=duÈæÜ‚›%©2ÂZBQöâ‰7bZ1HEöàbAÞGq¬<*)by7È«x:Y󈣠àŒ‘_tIجØ`‘¾Q¼+Z0E¡S´î1Ó;C€l” åZüWñu¦¬VÆ÷Šg“tL:B®îù›°eÄ,šE’ø\¾d­vqåÏçQô#Ê3;{ ÙîKpl‡Ž—c•d±*Éz€ÚrŠj–“IÇp0¿5–³ë`Ɔ,C-»¾Œ&ÄŠð¸ÿö˜TÁÉp¶0^å ¬÷ÿ¼¡»¿œäó™©Ë0~ϯ8­-(™Eú*>¼ßLz´œ^›2z'mË(êMcE›¿,¦3J¬ÌnÔ;¶k¯%ðeJqÓÁR‹Z)‘Ei¨(ÉE #dÁ{<7‹Ã‚JúRÖB]Vö1ÀkÃv¦P .þlÀòÈ\GÓè¤fþy¯uG6˜ë­}šYÑCì?ávÇÓð¯yt='ûÁXÎG¯¿b»K^Þ2Iš ‰#±eô¯t¡víÄx÷òµF?o÷]ÆŠMÍ ¥ô@Ÿñ—xÞøæ`S;×aÙøÆÏUr5Vª7lýË{¾5 ÁØ’Ð,ŽêuÔ³¸ûÍ/ò.³ªÅu·ø'_Oƒëù—W÷ŵªé‡jþÃ9ýOšÆ§ç÷¦ç µ>+wÞ¢ÇB¾x½[m {XÓN³åñ¦V42&Çtº“VÎ{„QMx[kqmU5Í—÷‹å¸Gú=ó¬cåßÍÏÌ4š£ÃTÞ˜´ˆGE¤¬.eÛlš‰•nòÂ0!«"RÐ Ÿê½‡X8N»Ÿ3½6Âr<¾-‘„Ä †â“È^ˆpõ~ ©}­¡8ZLÂwÈi°µ†þЬ¸×[»&$‘Ø!]+Yìõ'L³PJ›‹òÕ×-q•<(k¼ä3ä¡2_/ý2g*yŠœ³Ø’DˆTžÞPË}’Ëü0Ùd¥ï>êr¤ýt9ĺì=9l`[µ\—k @¶îF_x']^ï¹°w0Ç@à*ÕÑ Æ«¤v2¨%4N0K³ç7c[Œ7ÓÊ9fa kæ¨4 {º#ÓO…Ð1Î'¿@ô•l㮈wÂý……‚dz{¨aµ4§]™9sê s«] e^õþ y;œåüoÀuÏÐû¸°=H÷»Žû@>‡RÜ2HTÑÕý…5Õ*‘Q×–ñ‚÷„¯‡£‘ò²+/Ðcìýz’.îþzéõ?¨„õ‰_lG!ù­6ç™Å«XD UMÏje=,’~?ý:ŒèC¦·p ¡°xÄ]žÛ&{dqéoU¹,ÙNŽ5H `‚ðÖüiøáåkÖÈ«–`ñQªsëM*²Ÿèg$Sò±V  ©ç<é“$ϨOì‹ÖkÆzY9õf 'ìm Xàp 2KT5æ×'lñIùÖ„À 3[¥¶UN›jY!É Ÿ71¬*ûýÍÔz`Ý:¥½âãhü¤˜9Õrë.œ™”îÇ[È’ºÒaì%RûÁ\0§æVegËõ w»åí´ªÞÚV°Ÿ¶îð.ea°" ×™bJÉ{k.7) ÜœC>`ÈI9Ž\ÍìA$=^È«˜oTUÕšLæCÀd»R,Ö{ #7þ6?”fÞ/ø3ýþ ¡iq':ìÆõ ÅûZœa¨ì/³NQ,\(8ÖÁÕiøæË(›4LÿøÿÇ¢„7¶Èâ‰â-5··pÐ&ÞºŠ·a¥¿SÙ®õ½¨_mõF¯»Ó¬n{ÕÞvXé¹þû6°¡¶Ñ¨ño¥æ®ÿºU·RmþÃuÝz£âzn³ñŠWmzî?ŒÊÿ÷ÝÿÇ?–Ð` ã×××eXÅ¿Ê÷ï¾ÿúOó9$•rïݨÕíVu'Ç‚ ˆHµ…;X¤‹¾‰®OiÒÙFå²y6Ý 1{×n¼š^NŒQ<üÿØ{ó¶¶‘­_tÿý~ ¡î¥X–‘<ÛQÜ$„2A¦6d?²%ƒÁØÄ6SßÏ~×o­*I&¤{ï3Üç9÷:mI5תUkªa‘ü%mLÏyÕaë’ø-ŽuL`_ÀÙo±ïìíý”vwžm¿ÙßvDב’ó‹w»†E?+‘º”tèÛÜ€ÒF­äW ¯Úöý¶×0JÕ ÃÚIv¥ð=âHHÆåˆ¯ÚF­Þ¬1ÏckJJ.p­–sæÄð‡Ù¢ƒ}'ŒÁ<»…B;¶ôÉVkPI’,ZÖ ü3´ŸTj]ÙøäBè}¦ŽgZƒ¢ß²ÛW_²*uÛ^vFCk­PÈÇoeGâmûŽO[ƒRÉžõèig|µÞ;gA/m^¬›gP£åQ'×tUÀEÌ…egxËNV2ÕBí‹à"mDn³åêЍ°È¯¶L9œ££ª¼XZuÓ5®;®î9•óßñö{畱%Aü¤W<òÕ|¸í”Cà™à2(ë}{|ôÈz¬œŸØ½oOŽýž|û ~—‹öïe§îS:·÷­ýÛáaïðÐ¥è²ãù|Õ.õ©wµS¹Qî÷”O¤Èõêö_uîk¾pÛ{Yˆ”çG¾âN³GK¾^˜½Éáv;Ü '×íQ'VGr™øFª{” Â—Öò=!ûæ Ü©Á. Ø--߯'¶ËåŸ}Ç÷¦k— ˆØ·{rgO£ %møÇ8’Bný«ÅwÌEðxP»n›µöl§–ÞŠeÚÚ‰“'#ˆT_á}&E*×RnZ¢Í츦6°ìô:ÏFoûˆÝ·â%øÈWhÆnküœa”M…ÝŒ‚œ/A¾‘.Äðo}~…_Nå¾ÉÁẳ¤Ÿ¸Ÿ}*Ûú>Ü+½í’Ýô627½|©(Þ—|{eåÓ„³ú5u*˜‘q”ÍWšªb%îŸê¼a/媄Ž8ƒ}Ms¼×gWóìì‘}'zu!Ú»LØe Ø :÷x£ÝX úLtâlŽpU4äìżÁn_¹eU¼uÁ:ÚúfQ4¿ò\å^ƒ[rnðÙ}ýdcé4²¢qy¯kÙ%Jœv™)+ÐkÁÚ†x[…³œÑ´MÓ–›tn½êÔ+ìĸŽ5Çÿ°GJUò?áZ·˜èâŽñQ]ßèêÆÄ|ü!¿½¶WcwÒþP»“Ž72wö?ãŠÙ ›#Òã\ÿÆ ']bݳ6¥¸Á¥¹ŸØéc½"WÇâ¬z¸k Q»aŸ³Ê=úLœ -Ù!ƒàê®Ý/ì?<Imzr'»°v}½\{›ÔvË©›¸‚7L #UF#ù$ØàK?wùÆr O°Êá†a(îX‰¿nYf냉QÒfûŸó…†+…z3 °—é}—4M«ÄR©ÛH/hä¿^åñ .¥ú²ý×akæhô3Ô¨}·à¦Íã ¹[mž´Œ2sk䌊Ðlž9TÚ±D ¨ÌÓ¹QÿøÞDÔÔouþ15¤ÂyQ ÜÕR e>€q¹1~ºŒÁôÒæËÑû"Þ²·Ö‰/šk¸åŸ:¤®¦ç9 ,Wô’ËQ:ŽËoPrÅUô.Z—÷KuúGvê­o—}ÿ‰›¾Jÿ'†/½ Gñ»ÏìßkèœàÞU¾/•fªçTnVpq­rcßUnDÐ<Óa·'våÆmMi˜ø¶:ø¸À”g,óL[>*7h Y}Nh‡;íà$Å÷ÙI û1ù$ûÁ<Á¶Ðd¾MrFåÆÑB@Ün}K,ÒZC娉@9Àà…âáY¹ס[ìˆÅQˆ¦„ÌáÏ—*ª$úfäSÈíxí¼4êÖÈQ"t²›ò<†/xfzÏÞǨô¥8 ¬]¢ò\ Ôßâ·ú’©€¸ˆà^0‚“–ïü´+’úÑ|µÄ º 0½“½æÂË-|':¤(´Ü×Nõ& jk)qhîØwÖ/»§ïÍ[® ~êý¥i÷Åøë Ð5:¥ÒhùÁ"z¨/¸µˆ°RY£#Ò"h( ¯^My‡°ê_ƒdŽöû×v¾Nª7ëëþ5WG)TÝkþ5tä“KÒ«DZ’Ä¢à×TC·wÔ†ït*ƒÉ•­Üóã×ì[˜pc›JÛ3‹›S'À©Í¨'NýEPþQêÖFIói©ÛÜL¼Û¤þ4i^•ºÞŸå‘Sy¹ãƒE.­n^*/PI=d5I4ÃkÈ#Ä ·ò¼ |oMß.º_õuÕL–¿‘â7ïu_Ê5îððD¬|’’@×{ƹ¤GïÜéC*ÅWƒ¾pAñל»t‘~Ø…WO³3¾Lø+|ƒí²†Ä´q—^¿[›µ,} H cÎ`Ë{P,Öáz1g•_Eœâ§à`_Z…õ"8›Ù1¢nŸLÊU£¾.žk€,]@ÿˆ¦‘è t:‰x8‡—"‰$ÒâvVö…ò”Sh~µ±kÛ^f….EÏŒô­ç1ÍÎ š»™d¿q¯…|°bQúxú_“ i'ÞÞ—%\ˆð¬Ëâá 5ŸâWeIY±ƒÇJ@›¢̈ Z‡«%q zqÅ"MlveÑ Žôî”(Êݺ/êgfõMßÀ_Ý]_gO.!fCýßkw ñý/&FË{Þ¾cIr >.ßYPMqI¢Ð¼X÷€¡À˜iµ Ès·r€ç¸<ÏbÀŸ]Óm!Ëž.<ÍΉƒþš˜HÞÆ÷j}<›u¢þ°3ô©hB²ƒ¼ã@’wBö9»Û¯ iqЈ êß³KÝÁA ¥ÿH´ˆ»˜ñÙýDŽ<]££¥€ÕΧUÑÈ¡tvá‹ÆúÒïXÝø ÂàT¾¸Ewâ:µã6|P8^³-7¸WjÊÕíá&Q÷‡µ{|¡(®=‚SÙ¾ê¯FnsH’mS¦ÉÊÏ‚ áÂ5æÂ¤áëûÛ#¹T”U\vë?[‰Ã}¡ ¾.T% ÞØ/~ËmVˆ>úÏpQ6ìJâÅWÛh 3Ðúw*¢òÅ©õtrgï$”P…p $ ±s&3𩈟¨W•m¡kÚ£¬¸ ƒÊ;·V…3H*.#B·æ[fe›ïÆ}àc€÷ÖäKi™„ÞÅrSº\mæVf×ôÌv¼L⮯sΦ)jÄ'·¶ÑÁO`n¯Fã³)Ÿ¸óxÌž;ª£òȶÇÁ-hÐÙúú'ú×Ùq€s@n-ú±šÃ¬ŽÌÎ8‹¾ÞféÏ#8]4KðÈ—À²%}¢¯l:\#¨ mªuz,vÂc(Pþ6~Ã`FÙ¡iN‰‰ñìlÛ­Ÿà›)}iRùÛì»czüÁ©w²W¹k=„Ö×{(‚UÓ]\¸ÞFûT³lö4ôÁ’ëöÓªŽùJøv®\åÇŒG†:HcÖˡ[U~gÆJ+Áh `¥¾°5öiJN O~9aVþ·*–ÿÅîªK‹cìžBËò%Þ©=›N½NeÔkôÚQO.߈à…žêùä†{L'%ô4M\¯ƒÇ$8À1ר9AÙgðOuœˆÕ˜„bûlÿó 6œÂ^wÂæ»“Ô|Ç“vÌ–ÉùZÄŠd¤5ÎHiœ«æf¾–HõXŒÛlëîÚ‡‡å' 3å⃔å|&|T‡Ic; _$Õƒ¤±™„O“Ê$ $¸&÷ ×–ÛÝ~›øÂ“Çe¾Sø‰ÉÖœ¡ˆ9‘ ¬ã]'™YdtmÈ–§Çá%‰žç˜ýM£qMín\ž {\ö7Ÿ˜0‡ë´³4mãJRàÉCÊ ~l…ßßOÂó$Á®"GÍ‘¸_f±ƒ¿Ø6"3Enøöç4a’PM5û ¶ž¬ê,`ËØM26ž©ÅƒˆÝ;ñ¼ã<°6ê—¦ óà8›H#Û©n‚o¨mNa³íKo «Ô©ŒO¹ö>©FÉ'ư;Pÿ³æ\Äópþ[¯"ŠEF¢€/ZUÝÀ/r¼5EI§Vy¨‘ .öÞaŽÃÂÂh}2ZÍNDÍK³r‘Û­)onVF$†ê9äZQ¥f?j¯©ÄL[¦8À¢¶Dnë=1*w‰³ßT•í˜ä‘*µÓñí¶¼ÆDüˆmx~ûDU0ú¯;F~xÐï·á>ÈÛÎ,páá¡Õûf=:<„³Z\e^A»bHÅ´v‰³ÃÛÆÐònjÏ£FÈ^!&SQ ŸmÆpÄà ֵHê‘PÂA • ˆ²`q®Ü¥pH—CbhFÉê…¥Ùzù#0°5 Ê™Ò$áxE÷ø^IJdñweWtü([âb·†¼ÐÃÞiû¬—ŒvlÔÿ€ß꿟ٰ!‘ÒEzâSkD_¥1ó>Ø+/Ùø»Z*VŽpHÏaG8©­¾ph\ú4Æ£ÎÉÅŽÿA¯ÂIŽÇßçL9JCµ Rwl8áPËH=ŸB‚ƒ%·'M‘†Ë:Ru¦½Ò Xˆ™Bò&ýíá&Št6§˜–¬ùSÒ IMÄ#Øë 0©9r¹Tºß€ïH7¯hGw‘”£è™Ô2XÄZ´¬…Öë$­õQꀫ„ýB¬’‘“6;WNt¿µ¡¬6Œl=ŽƒÕEã‚F¹ºbz¢¸» ZOÝÖ¦€qpW{Ú¶®/Ý¢Õm·n“ÖMÒºNZWv˜zÛ8b·qpW&âÖ;Î:þY»Ü¨••ãÿE»ì¿Ð_Þ°]ö†ê žB²¨ªß.Wý\”Õš'š­B`»¹Õ´­k6¦˜f¾©=ˆyí5GcŽŽÿ4I hß™(ikB̬Þs8K™í[§áãgJ?­J24VLψž}z¶Líbá®þ9gŠ!…·Õh§ aÕ}¶ F˜@­Z^—bÅþKŽñ~Ž©ŽÓüó~Y’£ùå~¸Jÿ9 ¯]±I˜{Tl~ºuƒõ‘÷Y([;›MÒµÝæ4˜æ¾»¯–`˜Ë-Ùá`Äny”Œ~jï‡ œ÷ôŨ$¿P/ …éj ¯ûÀ]\ Âw¤X^™Nó}Û¬ÓTZôܦo ¯}§ç[о)Õ÷óÕKí^+gS~x’nɤ )îåtÕÍ79GC ñØÉ/±ÖƼˆÐÜKÓ=g3¾u7ê{:ôuÚÓD‘FâÍb,èsRßÓ¾ÐÖÄéFµÝ–©¶°ÄˆÕÔ˜™á?s]è îBÙÌ]•T—‚NU–ƒ©Œ'R¬ÓÐxÁ¸Áé –šU0\ÃÔïÖå±äñ+o"!&ƒ”.4zyÏâǤ›ª±ì£Ä¬-ˆ÷å]ýz}ñ"nLôôT¾MÒäùÌmíEÔwù•Õ[$p$¯|hÏ<’Àåȇm·õ:’ûº+¾½xáÖµ$±W­˜vöX¢*/ ¿¦¹lÈzRe¦|úp ðé£<ô¼2žiŸ9½ÃŸTóe×$ JÔ’£G•óÒQr¨þ\›°%;/ÑÏöO‰œú.üV¯,óÛ„ÍYfñYÑ,’|áÔ_¥‘:ÔúÍÎ'ØÉô~sº*ò| ­¿$bi2Û9çèî9Iû4TLcC„Ñæo+ÉBW¦3RP‚¶Ù¾knåŸ÷*G¥ š:ÏVŸèðJ¸Z7Bƒ`¤ñЍLÛ銉&(c_'Å~7Ai *¸•KûOŸSן­„Q»+ÓRõÒÌ{6ž?bÛy@ ’ìç“5GºÚã –t͹tk+éRÚ¿ÂWnÔtæôòݼÍõÜÒëAÍìЀ»Qù”@wb.(©å|½5"‘oS/IlcZc7uYXí˜Ã(1é/rya¶«Ü‡yGxYò*oó:k}å Ƈ¬wø®¾Ê¾«¯ˆ0æzïæ2_3ÿûœn=’–̤%K§öV‡ÕÞ¦a»iØnv‘†]è°Šfƒfå}šnš¦›ê°ú¦«o¦a?Ò°:ÌŸë0žAŠ,`ýFoW(W3©ß&þ\»®új+kqŠ×¼¥ƒÈžc š ýæ¢\¾æ<‡}ϰ›ã­£«‰Èõ݃% €mù¦Ý+³{¶ñèvò{]"iÍxdõÖýþí¿Ò4èã°Ð5»pü cMÕ õæ¨ìPƶf!ÍÇìR:$¢ñ %Èîö¾Y°ñpkE•i»¿Qñ :r*Çí¼swÇ[@†ï^áZÁ„j‡ÍÛ*e'$½g‘ª,ÖÓ™‡Sþ~w@ѳ6+ÒÞ¡wÞ ±P»—ÎTí^[È꛽Ó[@µ™®¯Oe„~iQÔQgLaƒ¶7e½€„äʾóí\Yß_ hþ m¯ì‹ÎBŒQ ˆÑãà½S9 ê»ÎyP9ÅÞKöJ#ü•h£wÄjZê:‹.¼<à»Ó¬:û/íÜÒ†õUQâAº¦öÕ¶g¬ À#ÞŒšÁPªœ*ùfÁЦù¹uÕq°·|sGƒÛç'Åÿ>²™‰€#Ùåe°²&óšíw6DR¾2i—æŸsW”QféŒXû8}\uNEý˜çÔÜÿ¦æâY4»Ì1þË6?©‹¬Î¤3 &ÒˉÅØ85kÂ@ã"Ö×ÏzÇzµík’Lrý¿Ó‰l¤!5Œá1­FêÅ‚ÖR€#c”AÈf€PJÔµ1‹g1ÇäݱӀ—ÀìHÜ"0ŽùSHÀ³€ÑƒŠ%nýÊò˜ØOçIPEp;‡u5C€ó ·ÁÔáYQrJ¼ÓI“.™ç2¨ÅæLŠkç<-¢^Ä–o(f³ß`3ƒÙ¬îé=sC6*_À˜ìY̱1¶©z¤d5Ò±.Xˆ¿pý+íöú‚÷ørž‹`‹èBïŠ4 E„ æÑaÁ‚å‚ ˜ÂÎÙ 8Hß÷ Táâ¨ÝCç~Bt–åsmG†.~Ú¤) ”a^‹U’Gfwx×,}­¯óùÊÒ¨l åìLLž™Ã)*/YùHÁäš6ÔÎ)IÚ YxË´éÎL·ö……×{â uz'Òõe9 b ØR;qENX¥mDÈ$Œ0¼únЉ}w¡ÒEbk‰ˆýÊíþ”8Ö95êlçŒ|çEúí¬Ú²p#@ŠÜï9R‹¼aÚ××ûì?{­o³cÆf 6]ð~Dj¾,&DŠ.­^t€g[nýÆ9O«¾H«>ðžŸRsfa€i®t~‰ë˜µÔ²s™õj ÚŒ.,‘V¿bÌöþÙ‘>âMfX“ò?øè Ñóv_ñ‚' ˉ-Iq„ýé|j+ÍÔ÷vÓ "%{»jû I˜ OHó‰á‰Óá‰Ýú…š b@:=N3AôDÆi%½ôvƒÕ¸d_¦Éµ”ËQ‡$œÊɶM5DéÒ@yõ°?î„HÄæèË)l¥æU¿Ô×x;ÃTæÖ†Sòäć¡lƒ'$:Á1!>ÇáÅVÏë;ûG6vBŸ`ñã̓“_–XûÀ>…çmYC*'I>ÚÎç`mÀ;)ùáV|jÐgj6¹Ü½mŸ8þ«öЩøl™%b÷J½TŸµ±íû…áÁy¨Í%¼ Nx·&Ôωôk s ë¼d3”uOmƒPR÷¾¸ù0°¹ú‰7 {<^'G¹W‡^øÓg’øXÖ$ŒdƒÐMûŽÆu$©ûX-´±`Ä繈ö쪵·‹%ÔÆúú1¶ò±0<Ö~Õª»Ñ)ê÷ñÀ$PÈBÙrÉïy.‚tà¯4ÚЩžwÔNæ¨\c; ×w?ÛJ“¨×ÛŒ~8+ML2Š "aµa°Viò–úy§zŽÃ é™léµ{”Ké³ÀÞê¹ÌÛê9i«ÔåÚj7ͽJÓ¾ëÓœTÏ.éè»Má1ŒŽÓí2¬dšõ K,Þ)ûÊrËYÄqznÈìñQ =¶aß5§íhÉr½ÙœÍs£96šg†?7š§FµaÔ"£~jÔ¶æÈØ5š'F󨍾6ü[£µ–ÑŒfߨ5úÐh†F³iTÏŒfÃhÖfÕ¨G†ÿʨ>3êã­Ñô¦gTj&ƒÑ0µ…‚';£R Û¨¡ñ~ÂÏ7y=òáI½Ú‘t4r›4žÜá,ú¢_qtãOB~Š®> ðCcùƒ‘†Èeã‡Âëê¬+>Õ‘+ƒïH’Wϰ͸úÚÆ+ {p‚.å´ñÍ%Ôš„È|V3RkÚ8ãŠÐ<1ž5 R-*²5Êõ!” H¨ðë†]‚ýµ7J[¢}§:í K;HÓ†x[r#+5’ð¨Õ¯›7°‹ÄîâZX ±Ð[©:¾J×j-nð¶W´m»“–F]œK.€g¾îu½¶¼ùÝŠz«výö†m«µãÊž^QïCv õjįfdyѾóí»êÓ®Zg‡(ئœr!ê\ÙJc³yì“ä3þ[ˬULGØŽ[!Ê}‹fì¥e<©ÿ2“«—Оóy0Ê´× ±i½²evò’ZÔ¾7Û>/«êͿݾ‡3ýEûÞ<Ø>}Pë.þÛì¼0à1«_Ì. Ç'ÚnäVy]’ä6ÒØ>!Äñ?ÉQ#µ—œi$‰ „‹}Ùµ¬;@B75™#ì¼\š?à£êà]²„h\A5ÖȳšRÖCÕi!æØiGV |Çá gO%­=[I*'¡s ±²öž]ûçÙT¯…3,P7F‰4Ùª›ÔmÙâÁݨ~²Òpuܵúg`áòŸ#&RëB)g Š$yÏç¹_òý%t9,T¶ |þ‡?ÞÐ7Oíà)¤ñßÛ¼7{ßÙ’ÝÈ•M¨êÈ$b# m„qà}û½SÙlc'JC!àv‡_ÖQ”ì…Ç›#GíP“ÍÅT6IHÆ{>:æ7XŠ‚‰\oXDz[÷X/U@—f™ˆp ©žT/˜ åkƒè×r `Í Á‘â¦ÿÎd 9»l‚”…¨Ñ|ÀU 45°K’”H³~l.¡¤7:é)¼cç-Ië8ç¿6Ýväx¯ôÜçSi¦÷Ùä;Ì! i|¯­Qw ›[¯ÊOL9êV?² ó±w®®úÀòXÙ;"M¾cdãÈßG»sâ‚ÊõðA$;<ââ[Â]uŒ”ÛÜp;S£ì¸êØÒ)ø $¶Qª 0Üð%ùÒÎNhã/Mqz| ù‡}“¤Ì+‘²œØp¿Å+{³Ä{‘TÞëÀ·¸>BjJ7€Èm1“MÖ >¶õ±â.o ê§6¤»J•ô…JÕñoÚ!u­è/qïÂ…•n81/Æ §ñÜil9gN㩹‚âS…âS ø0¥ÇSRý±Ÿ,; å«AÀCÁ9u€çâ Tä# yŒ÷;Ó!ˆhÐIÑûÜp§p;Œ‡ZÛw>:ê˜(ÅnÉÑ¡\<Ñ`üàøgÙ>4•6‚0òWØLw©Œúo&ªo´µµ?ÝÚ{CöÕÿ ½á4~´Íê‡òM)¼)U>•ÂkÓiÜPšŠG?»íNí+ýTÞÓOõ=‰xo8¹ÿÆ1¼=L»Æ9@Lï¼-GƒÒT¦S‘Ò+?89B¼§ ç¦S½n›ÊLØ ÀFSÁaÀ¹}7—Óš{ÎÜQ/Éý™óiÝcÇÿ3(‡‡]k=ù§+¼Kg×yÌI«ãåÆÖÜÝ]_Ÿ»^±¢/µ–Ko2½éEÒy0gWßñv^>Ì/¯kb+£ÿ§mã½X:¨LU—í®¹n¶Í.öôÎÝê»$1—ôa]9 B%ì’ÊO¿Y1»(d·Kÿ9÷C™;Ü& Æ2m}Ð|TÒå%I¾öÝ1÷£ø” ŒèŸ®¯¨vðú:f`‹&Nî ž0"ŠÃÏs³ãõ±Pʈµ„ï3¶‹A'“ÏïÈFþÔú9ìf#ì%;á%+Õ *í÷¾9°ùù^†àkÀv€ü0wòÅR²naÙ"°'ëvå<À–zÇü=¼ fŸR³}Ý¥³¢eœÏîþrÐL*‡2b – _Òúÿf¼)q°ýÈýº¬£¾Å†B‘H‰Dñúë+çX̸.¶±˜A•­Þ7úíþ†=°UШú××' «Ü~¼û[òÎË4ñp»•cº¼=wB÷Ä­F ®£± >žxc‹4Jø)ưðX)Ýkc,ÐýòYy, ”¾C²ïÆ0ɤxŽór„3¿' øž¿Äjö{¶Fx}·1ïúOÆÜ2ÃØ ¦ÝƧžªµ¯öÀ­°Þ:h0ýT<¡xc«âýX8'8>p«O©Ô~) MŠküPEîë˜V©ö¡6!VUôPÄͶ°áaÝkFX5joÚüÏC’ïK©õg©õ•¸Jc–¶>£ï-°¸ú…½=êf¯EÓ1@ÑÚr«×v6¨eçLΉôÏ•-Up¨S*Q 13Ë÷ «2dzj:=Êu$·Òè­¡T_ÐÅ#Cê8¼ýŒÏ9‹ëÄú0«³-Ü» T<˰T¶å6N­ÖÈHJ-©í£1´Pp îšú q‰Š`ÑÆÆ¡ePÑúI‰iíëÎR2³öÊÄ´Ïr@Ða‘qàÖv¨GÇ4(æ xP9NFë1 dåÄž-ù’â ¤Æz— í©‚Û>.—úƒW»ª;ÄK½Š¤ðžlØ$x v`te0óZqd1Àˆ!!5ç#E·Þ1^©¶¥õ~„ÉDê‰,ìòDÓ ½Ï fŸ­]nÝýÑ{¦G—/¼ÒY^!Ë+kð`–ç逧¦TždI^˜jÁ½ëçб¬KQc?–ýTøîð Þccfõ-„µýúÏû/×׉̴@ŽjmÂ,«]> 1Ǿ|Üzcc[!Æ·1Ðo­×¹ý»Dd@ 1ÐÚiœ´•JA5‰V‘Æk»ªH’V6?XhýËÊ1UfëUé-Ƀþ›€O¿ÂÓl‰ø@ nþxÃKÎnà¿é†nk‡%m‚•ÿf}}Jª0"ãp=`´wƒ> ò@]©Â„–oߨÕ!çvyùÔ2‹»|’‡ºµK²ÍD™ËæPÉÂ|&øÚ†`²ª4‡ò_¹äÛt ˜Eþðo cwä¬=ÛœC>sz„«[°EŠ‹“‚pÀ-_ÖiV*åç9€ƒo]üZ¤{àíŸó‘õuu èŸþt”¢©$r¥ÅyoôùxBKè”Çö'I{OäéÝòsÉ£Õæ›¡Ì¶G¨œ^Äçlnm‹Oå²(|Ì×»¤;Iõ=}æc³Hµç7X«ªn{ÄY:ª99_«:&4²SÂP®ýŠ1æÛ&örRä{±§z±§z±G½Ð:ó¶:Pžö¢¶¥úo¾nÚÖ×hŠî럋Ý*½FoCP ,}÷Û5S›S;̵Ì?—–ቖÑsyÏH£ÞcuŒ¾Þ] ÷‹*8mò"ë÷ÊØI/)Áóìe ¶JÀ­Q ¶~Jp»ZÅÞƒ rU¬Úu’PðiéøØ-zæœb‘^ÖÖ‰5,ù†¾Ü;q+uðÞ®ùŽº_©S÷ïÝ~Å÷‡¢ÜaGƒsáx/‚Uð9ÕzÐè|°.0Ïÿ¬wÍ(ÔXR8^$‰þ~ƒõvï•;$rÏÆ<àã…ܪ$r‚}7j¬ ËЭTàL¥fŠO,DHo ¦$ÕZÚÔ3QÏx•^Ý Á—ŒúM«ZwÔ2`Ù?O¼7‰·'ÇØvÜcÁàÜìz/2´h‡GÖ™Ù™–›(øv¯X: lÞK8Êe¹ìßËDlûAìz kïgxa)‚\‰¬>ö,9þ^Ðç8|H픲/ÔùjÝý„£;V„Ý8E¯CeYòUVeÚü~G'ôû”7šÉ…¤¿P7JÙ-ymÏ~Q1ýNìV¨ž¾Qå#ôw(›îÄÕõÌ‚£æ¸ž¾}„è*,\ØgbúMèe8˜cÉÍtꆾ,oS‰„yûxvš½©lßW~µå7‚…úÄ­+v_ÐdÉóòK~ 6n3`‰9ÔùƪÕóM!wa›–à䘤{@,U¤|(‰ê5&ÖÈñØ2€#M›Vjb~elé#²ÞbQ ÚltüfvU Q¸Z0 „9 Ñš>[xèÝÊŸ6~`fb~NÃÂÕ­vJk®ÿÕVOnµ{€ FàþG‹sø_{(óHA†’‘ú#´ŽëRäN½ƒâQ¹Û:o¡Ä(BÊZÃú+'“ï@Ý!«¢;ØÉÅ7À€hJ‹p½°x¶¾>{Rj]tgm}GŒN!—Ã8•Ê&1Ãþ$öâ)}ReÌP"’ñB瞢Zè5vqqä>½UßÐd£Ç–%†iÜß¶ËzL`ÀfÈœj‡ù-&üBp¡ŠfhôB:‹>¶Ès<[×ÓE5ž½¶-“·T¢éÛQ÷!BÑC9>*í#6ÃT ×°P&cOC¬À(§WH‡£½7¤56@7 ß0ÙàñU@Ù@ÚùQ1[ç&Ö;Ý"goR!ê߬uO×*u:àã_µ°¼Ô2?Í×ÅÁÀË"Æ‹‹ÇPTƹ¡ðôPpÒjMÕý1Ø É`ÏVѶÂîj/{ öÔ&—~Š÷^“ÿY™£O•Nн*U*ª–å…ÕU,×…îåÂ)U' g c,xCÙE¾©9ø]8´GPJû27•|AãÀV„7|ªbQ´: IYAP F¸âõ¤xwU=·ö®kÖ 5*¦}„€7Dx6ÏQYíl -()ãÞíG(ÒVà_‚­*b zàÜÕ^·ïZãvëÔiÚØiTÛ­cé;_ÝÿRßürûŠä*лÍË ¸ˆÇ0@—½Îò|ê…<òˆ*’¿·L•”ÞtHýÚÇU|ë«SùNq`‡S^Îr€m¾Õ08p¼9>æŽ÷žžþ§ö1P‡6q^³… Ê­PVDppÇRüЩ B BŠÊ#Ee€á>p·²B7XÒbÜÙ,Ê©Tï=k ±ƒl'±ŠÝ_èØÍùK^ï;ú-Äf5Š9pk_úùÌ}½¹@oŽPü~æ; peoùÛÂj5“(9±ÕíCïŸÅDW×jmÿòƒîT°}嘾ò]³©»{‚Wù›7X)¢[ ÛÞ¼CP¤oo¾¤†°2Ž« ×:ñ_« |뛸ÊßZõÄ;p颎q¦—m£Ç`„ß¨Tø|"t2jp„£¸g„¦ŠU#žbU°ýæØª†iÛk7&ƒ.CǬ© Þ`¦ßn•"9l¿±eå{pçí·½}ÇÛÄ"×KƒšòÐÈYaǬÂefNúù‘ï6ƒ)¶ÆÎ‚DÒb@ø7V§‰;„!ø^èÓÅ;Få{nÛHe£­™ŒB|Æx¾ûœ§%#¹Ë¡ ‚YBoÕA°:4}¾ð‰FMß@Ë7–í>'îø”b¿ø5â ­êaAÂ6Ó°ð9ªŒÊëSXý£ÛÌÂ>!LHŠåL¨OJäôKé ápÚ/¾îhÆ'­{ˆ…‹0íôëa¡²Aõàj«˜åêÁyGù'ÐÇÛ µø°@©k/ GzS÷°P½=,ûìæ±Ì2Dw`Ï⫵„ÛÀÉw¢ð8¤îõÝ–o­ºa[­–ÇïÜç€øo»!úÛm}nžr«SîÕzoÔ%îÚôxEmƒìÕðÔùôx¼:­ô¿8±¯º3êâÖ¾6_×WⳎë/ê#S:Èçñûé=½>Ÿ©"‰¤ÈÃË·ó òÕ¡씵µ¡²ª[TYi^ÜÞ7àÛûò!Õ¡ ²Â®„Ö÷suàƒêho°ª„ý"§î;õzË)$ògIÉßÿ†‰v’ˆKä*œ%âU0³œN”ø„Kà,‰ÃÁI2 ñ=œÎí,ó´dr9'óÅí˜ÒÁl’L¦Qü&<Ѥx¾Hàf8šÄ$\ögÓëyŽy$Úh‘,Ðsø¢£¸[ê<Šš_àˆ‹€‡g68¡*ÙCl’ˆƒØdÁpׯÉñå(¢á¦fS_&q"%²DþÞjŸ…„uâÕ,a_ÉÔ°èrÆjï`zq›°Ã0GB®ëI<ÛÒH*þÅ’I $šEßÄôcpFƒG•N©šÜ,öG}x:fôØçÔÛcŒÁâ|Lø#Í»œÀo( v¾Ø> AþÀ°:)ur1'‹Ñy<½\$Q̃‰j¤!4 .n¨öø"9Ï81{-NÂùíd(gÌ[âÑ+“÷ᘆŽÑa4¬ß/cê¬   ""çÀëÑ„f×âiLÓ4N&wI¶…I=Ý r¸1z>ž†4}áÉQF™:K­dlÏ–æÝ.'3`Ðî<Á„úWÂüd:$¸ôž'ÚKR2‡ó¦d€öaÂΓŸ½÷&âYÈÆœ© nº;½VÃ~:gEíÛÍ1’‹ÖcšÈÉùôrû µv:¦®ù\ÎÓs4I5}þôö@!]<¥¥ø‹wD(ÂcÁ!¢$Ûhªˆ'(‹(Gƒ˜ÜÜJã8Ä\¡ºgD dh>¡à_þš ´‹A&4· [¹ꛌ<~ŸïÁc6S)Š?¥9—´èQØ9ðî|úc4‡ O”¤1õ6i6ƒˆ°)SÒž"Dì%]Í0©ð3Ï9!—oeæÍgB\ÆØþ,Qn~÷™l¨D'®Fó¨È,†oÛè@ÐX9"Hèù¡fQÞù—½]šj f'ñ’ ¦è; Ç˜&„ªD¹FDNS§b‚‰ø›Jþ¥ÀI`¥Â@Ü›Fì(s8#À利Äùâ%¡ @ˆ{~‘\^DÀßøü‚2‘Mjó&‘ÏÑ Ì Õ—{»(aèBä"QøìÒXþ†%'â‰?‘a¢ÝW‚Šô1ˆ/<¸ìÈøñà¼0É{X% ŽÙÀû'q n6áaLÜÁ¡{„ÍÒXQ›8Ð $iqû‰ÉšÄ!@&u*’‘Ãp åb4äQ$Ïãø ‘£Eø:¾MÎâ[ÆÊÿù%æhŸi<¢NI˜bƒ[òØÆ`jpŽ0˜·Ò/xŒpšP• ÄÌÒᮼ”œ_öÏ)Ü&á‘ÂÍ™ñ°¨F(޳™+·r‰våN)AD¯gáÅ&µ5Š… XæÕ¶—šŒ#™íƒÅl 9ÃȰøÎ%HÌ^ˆ™jôr1!› ‰$¾GsA™þô¥' ;«Læ×<#fñ0Iqv4L_1Ô2)…çùÂAAÈÔ”E[äG‚{ÆÔ^»AgR±/TÏš¼/tP¤µPkù¼óÔ;Çdž/Ô?H ó@ˆZø±ð^â9†@,ìd…äz"°ÉuÜ?£‰Ú,4…1:ù—’½âï‰|áøóˆj¯lTÑÂÀħ¨p|q&»ÌܨAo¦}ÎÓZH$ØW¢'XË,¥¹!õq¡`¿Ï‚ùK L%¥Ñ‹ÒÀÎgSâ&Ä]^RqŠî'›LŒ¿hòÂp„ÃE 3Øv"µj!„ÅÌ å‘–ÁHÍ}:%„êãè¥ÆŠ…k‚Û™šsÔD~Q½Á»Ð j =K¥u$ƒ./,#Ç3VG?”xLtÿ\ÃŒ2¡•H/ÌÛÄO®úK%Ùp‘1á$C’gI”³VBàšƒ©@ÒL%~MƾðÏþp8ažAÔRr8Äã§—}áíPú®©˜ñV<&È\A¢™6³A6©‘Ô@š­¯êùEK<ÜÜVV&@ù¥TÈ5£I8VâƒP75W¨Ëâk•”ãåY|wÑ4b4ÖrŠ*GzÁZNŸ»2g-‰…;¼<(†cn»n„"4„&›‹dc¢ŠRQ"&«É”&ñÀ-“'QÞ½…U W¾HszBÚàµôh8£™\òûÇ yna–’¯…?¢Xz Ï÷+É›ð ò–d» 5‘ÅzÐ9SÀ¼¤*VVóµ6Ÿ Þ1f“èN*2Ë ¬Æ$Lªq¤XEiš$/öXÑ€™x­ÆFòŠB7¼äàä2ÙѲgSÇRMá ¤ÛEñúÈ·®†&(¬uŸnJVà ֱ}ˆÓ1µ"ˆƒ¨»'óÈÅ ‹uV;YctQã}Ú¶.ù¹ü¯CØfj(ƒ¹&M„gÝ\â~ˆ( d4Ô Ìe+€bÛÇ;dËÈ2KËè…•£{„¢EàzJ„¥Hbvëĸ ëáùE§@¼Ìä¯ï—Ó>æÏ±|<ácú`ZÅͳP^ÚtD®#õÇ7T[Î¥}š…Ê=.(˜Iƒé×U…XœÓÑeöÒ\G º†!z2uò°>˜…“9ô!Ë”.Ù#é/˜jªé0M-öãxoÙì£ðÄ ù„$ÜÒœdMcAˆÒ<Àdx9£44t¬.ÍÝÕÙDíQ3I³Ò_ðŠ²·'ÇãÑüDǢݺ3n®«æé”T܉Z§@ÅTƒ:;Šˆ!EuaÔZšªÄ/#’íbUNn R… ‚°AQVŒ’‹Ž ÜÔÁt&"6o¶v)nö4œ b¢Š‰–( R-Ž’(#HA<'éü~• ,fEmÅKÆš¥Ú†¨^H f˜¦ø#K!eɬ2xV0…RšM;-àŸ?ÀYÁF¹5¨§ê >™ŽÁŠ0âPUJbX]°¼&dAs<+7Q‹š¥sqV!WTÁævü!(-¥xÒáN¬޹ï0fÈô#"÷<^ d°XL%‘:2”}6Ef]hž`ŠPëêÙCÂ߃=zé¹.ó÷×édΪz²Vr;yÂ2÷M—š 1J©±VÓãœ3¤¤Gaj¾0j!(uÚ¢HWL Ö†E ñW¨v†/Â…vbpÑ=*é(ëZ6œV«Hþxi·“¯ìI%XÑ.OîU¶¶RÙÏY·³)‘G»{¥ü3WŠ’|ÿ¦ Ÿc<Ô›{ZjÿD«y:ß/aù×dú9 8DúH! fÓË Ó4’kÎS2z°"cŠ@¦4ƒ ™AL.Æ—3…ðL§‹ñ­k°šH·P^_$qúvU†u„r¢’i¢t´ŽYÈ.es*ÇfF‹ÿ˜‡ ÿ’&ÿgü„¡” ÀJAŽš¢¤‡<߀€ i/Ë’“6¸]*£–k¼Ç@± $L„؈,ÀÒôWgtXRF¦¯1¬Ø=vYä6=%Ÿ&&æ÷‚  ¸H”i+.²5e¨#ÓÒ'%¦§mÌ¢îŸÀ𗽓èÿ o*‡#%>Ð3×ø¸Ò>‘­Ô gÃá0«šæ¹ËÁanþ_îþÿîno¦ e º^i`‡FÇ´c‹^+讇ÉÕHM9Dh±OÇ/ÓsX„‰–Ý>ˆð?‰›#\]z'E¬èaŒÑÙŒW“$LjÁñEÙøÓ« Ì" ÒÁÂko—¢¯»ÛŠ …ÎG¡›¼Î­JuMrUù_ä„`-Ô6£ûW±Öjcl£mXÖý†gS1é[Sò‹ª;06´d¡x\Ê[2è0T´Æ‚-|«%x¿*aª+ù%}¾¥½BQÁ£X8b¸®öCø±l}z0êáÊSö®S“ÂöP…öÏúî ,‡ J™ílæˆçyVjÛ«P9ÍÝ6Ù„ÈFô¹Æe0½\\\.ŒóK¢9ÇPéX¨ZåÚDùF|r.Œ'û «)sP{¥†°ËmX¨–æËôS«^ª¸s0u*s—²^‰‡Ôâè3f詼ǀÄhp¯èÑC÷›“›~1Ž™Ò¨ÌFñ•‘ œ˜‘ç,²P±ÿÊÑ‹ Ž.ý/e>NzO¦@ 3ŠzÞëÁB yΕ47£ˆ7ÑÑÐf"}&@M•nûS¡P)bZXy¨’nî Y¤¦sÅbBØïÌØb `¾Éa^¦Uq-9Ї™¦©î1¢xÏÑD®wÔ¡ÇY_]YB£ÐbÑÎMX­4{JÔŠ‘šƒV¾=T}ú™uÓho»¼ÖÂDH Fn2¾ÃŠõ«3†^ËdjÌld>=bqÀæÔ‡%©0ÂRBAöâˆ6bZ0H¶àbAÞ8çseQIË»A^ͧ“‹82 Œ@ùÓM—„­ $r-0 wªè¯ô ö=bzgH#Û¥B¾6ÿªÑ!ºÎ˜ÕÎè^áã$]'“ŽP¥Ë{ö&l± V8>ç/»SXùóYÿˆóÄÃÀÎ^C¶û’<7ˆBÎ/ÏUÍ¢$ËjË)йœLb†ÃÙ­qyq΢¹!KÀË®Oâ ‘"¼n½Ý#Qp2º¸p¾Êʹ5²Þÿój„îþå$ŸÎJM†Ñè*¿â´² d(Vlx¿[ôj»ƒùÜ’AÐ;iÛFAo+8³˜^PàÆÅúÆví•Þ£L!^"PjS-² $¸`c„lXgVaQI_J:´Pç•=AÜà•aû¨@ &þlÀòÀ\Óà¤j~»W»+›¬ÕÚ>ÏÐYш"ì?ázϧѿfñõŒôãr66xýƒÜ¿äå-‹¸Ùˆp0 Y@ÿ•.ÔB¯ï^¾³Wpàçí¾+M‡²âPu#é½P4~‰öèo.6Õ±qšM`ü\$c§rCùŸþóò1 FY@“8*×Ug¬B÷{Pà \bQ‹Ënó#_NËù§_óë…• *iD%qHÿIÕˆz~oz¾Pë³bqç-zÌ”a‹×»ÕV ‡5í4YnjE##`rÜA‡»iá¼IÕ„·µVVUÓty»XŽz¤ñ™e+ÿ^~f¦iÔý€–²Æ¤Y|Ê"yÝèR¶Í¦‰¨Ré&/Œ²*"]àðÞ{ˆ…ã´ûiö7ÓkɈ!\žŸßI"¢#±Id„¸z?”¾RÑ<^lO¢wHi¶±µ†~hVK»Wk»& Û!Y+Ylõ'H3SJ«›») $6Ð5q?(i¸ä3à¡°@e/þ2eÊy œ²Ð–„ˆ”Ÿ¾PÊ}†’Kü0Úd¹ïGoKq9Ô~z9ºì=>l`[µž„'+@¶îF1¼“./÷Üœ±w0G€à*ÔÖ ÆßHõ $PKh8œ`ýž&Ïoƶn–3̺­™¡Ò27uG¦ž ‘kNþ Ñ/ 1㮀o‚ýBCA0}=T±ZšÓ¦Ìœ:õ?Ôk­]e^õ¾ G¼Îvÿ'ÚuOÑû‹va{jÜj8î7òv(Á-k‰Êº¼¿°¦j%ô"ì*/xO¸ñz4++»²=ÆÞ¯'éâ^ÿƒBXžøÅvâßjsžU8 k¡¢é]­¬G’ï§g£˜"2¹…C„…“pþ¯ÓyàuHYœå‚* ·ƒ%ÛɱÒ0˜0ºµ~Z~xùš%rª-P|”ÊÜz“Šì'úYÉ„|¬ÕBAàÌFj9Ÿ ÷‚JŸ_PŸØ­×Œõ²rjÍMØÚÐÀad’¨J̯OÙ⓲­ ‚V¶Jm»*ŸVÕ²L’6%ÎnaXUò2ýæšÔ~`Ý:ŽÂãøüI!3ªåÖ]81 ÝËH’šÒaóÛ9„µ# ··¹žÚæ—7†×lû•veceG˜Þ ž´¢æ¢nã’·glž†7 r|FÇøøawÎ܇ÔN…z Ÿy·ŒÚKÆ Ï¯aŒæÚÊÍ¢ÿU< o!سFC‹Ø¬.ƒ­’ Æ·ºÖüÉ—s"£>®ðŒ»ò«],sŒæ÷7ŒÄsXv¶ì]õÛ\HE²Ùe:Q;»\5 bÏÏFÔuÌ-žòî˜û1½˜âztu;w$4󚈄!§B¤`6¦[eôªåï–ùP"ØMßJ¹ÍC¹xÕÓv1a¬{*£¦€ º½S‚«ÇÒí‡óø‘ £h†épeSNë W´ß#×8ÃbÙŒ†±Ÿ_„j&ˆUx -k&NèRqæ“B1§—Hh\×%±¹h>.SÎ'¦ýse(|)áîw{6•jFÑíL¬×;`©´rÙ,æäýé²¥%LŸwmƒÖN'J5SÇZÛ?)BJHSƒI£­R/Ç®Š^m1ÛbÃs‰Ïò˜J¥3õq>âf|ì9]£ü{ð*UOÌû½szv¼_§—3µ(—îQ˵–Ð}Á;z1Gç—ÓÙB™IξœÅ?…nœÎüPŠ ä˜u·ÚU”‚mHOïÿ‰î^‡³ÉÏ(%}fZ‰õŒáèXâͬ›™y°ÓLï‡ÔÂÀ„(Ñ.—Õ~Üé츌ã-e¯V©×Ì'˜Æ}âÀ² ‡*y–bòãrø„¡fVÃÅlz‰-r'ÓéB6¦RÖ ëÿÒ;²V g楈ˆÆ=ñ)cÈ“ÁÿùÂÃT6¸íû·)Äÿ6"™Çh`ø“¿¢“iõº£®J”âËã2òµÌñ–L%GÁ1ùà¢ù "ú müe~uðÖt ï)Yýy4TÿÏ¢”?waÃÀÿûDè3 ¾¡Áê@"†#Þ¹2½Ä,#R dѨƔ‰…¿“¥#–¨Æ£³Ÿñæ ÞRUYä'B§–_y:ÄÙ^M‹.¦bgQÄŒ'øˆ„rœÒ1âÒ9'µg¦ ²* öÉ>*c5ù¯¤ØéÅísô‚O¨­˜ßVÄ×tufN¬mïð¦þŸ†q¥°œµMÛÇÔ^òâ3n |‚V´Í WËíé&¨VÈ©k0 b¥­#†³•¸Ž’œÎ¾Qc¥›ª½›Q´ºÆFÎݯ6|ÇÓµôÙèë «§‹´‰ÛO}ã†YKSÏ%sqÖÝ* äƒ£sãá<#ohÐÌ'Ž#Q+-(fé{\ÄêÞ4¶¶f¹Ü+Þ>‚_X-Þ0î'N» ï•—ÿuÿmù`×ssö¯†/oÒÉ:™^—A ¹Cë×óXuQ e ÇÅV$˜$HCì¥ÜýªæˆÏ/òéµÇŠí‹…yºó"\QI2¶I ±Ü´YßíB†³®œQûÙfò»˜GrÐ| $šê4#8Ý•T–Þ†n­RJ´ô+Ÿ §«IÑÔD¦Ñ5L\ãcmÃTpµ6Ö¬X„øˆ¬ÒDyž­‚Y«²„Ϫvü'`ú;0p#~†¢ì…Án€@C4³Y?¬ÂjTqÇ$SÇŠÖߤpù*$«|Øý”±Hc®Kφ]WØ™(øÐÚC†‡A5ñwW´ Fex›- +®Ê#Ÿ…;J¦ü BE•æÌ+1Òá ÎøjK¼w΂^Ú¼X7Ï „GË£N®é:ªG\…egxËNV2ÕBí‹à"mDî°åêЍ°È¯ŽÌ9œ££ª¼XZu÷5Ü]U÷œÊùïxû½óÊØ’ þ RìšwâŸr_µ‰K«Á]íT< ÚwQ |bG®W·ïøúШÓp_ßöÏ^6#ñb ÷€^ÂáXÄmà^ªçÁq}Ÿ/䈻ªãÄêáãHœˆoìºG *ì´ˆïA ]ÿj-à Ü©Ê.-#[߯½£åòϾŠc¿yÚ%'"öížÜÙÜèÂAmþQ¤†[ÿj±/k×m“ç­é4_¤Î/_/×í ‡<Š·SøRî/q­jx´tüÔ|€¶tB·6 ñ¹®î"Ä6:þ×õ.ÄK¨œp¾Ë;ny§ý;µQVnÉc§Îþ.{Puk×]\¥Ûî; Ü—þ:ók‚K§€=»¨ÕíÔÃlêõ¸×‡O®×¾¶z€ˆ‚»e'’ëbµO…ÜB p‡x$·‡Ã¡Í§6œAÓç›)ƒÓwà³Sü1k,/,x2=,ø'‡öÆtXðþ<,Øëë8ux¼‡õ> †C ?„/Ko¦}Ô^õq sËdŸ±rwuÛb¨–ô…ïëõ†Úní9|^v-Óä‹jqÝ­¸TÝÊÂÉ;kiÚa1P~[à§.žt¼™Õk¡;¶Œ`í‡nßËK#ì¨j©Î[4§%1ÚU*_$ÌW»ÞÜ |ÃEqËjЛ_5Nåýì¸õ÷Tbí‡%n¶›L”ÆW®RT­|¶¼–³ç¼wR?ð`ïÁ×ÇG•¼þü§ä{$oÁ¥8ÚÎy¶ïåy¯« $‘J,.¶¿ÿ”rï§”®ÿRZ>N×&I²o$4•¾g¾·ÙÉkÃQýß g7>2yý«ÜûV|rdð/{£éÛp-÷\®kÚOJMÔêŒo{€æáö÷X|¼¥nms.§áƒqW2€n}jíÙN-õŠxeÚÚ‰“'#ˆT_Á"“"•k)žö†h3;.® ,;uçÒèmábg/ÁGv¡ðÐø9Ã(›Š½ÓÀì²#Þkj®ù1E|ãŸ_‰*ÙÊ'tÔ!SP¯¤ŸðO‡> i¾m ÄLSo'[nå™@Ÿ]ììTïKö^R9Æ4á¬~ÕÓ£Ÿ‘œº/ãa§ÅJÜ?Þyᄎž¯}÷5Íñ^îgàGÁÃeòT\]„ö.v™6ˆÎ=Þh7Ö‚>8›#\ 9¥û€aÙŽxÙ/Ð]°Ž¶ö,ƒæWž«Ükk!÷ú˜ñÙ}ýdcé4²¢á¼É5‹ì7N»Ì”•Gèµ`-(;søJÙô7M[<) ÜzÕ©Wˆi9ð£âz5ÇÿDOöÙ¹Yò?áZÿ˜èâŽñQ¹ïð?ucb>þߊ^Û«Á™ÇcÈ=˜Ô{ð<ÁÜÙÿ C6Gn¸pý7œt‰uÏÚ”âN“>Q ýN½"®ƒpz½ܵ„¨ÝÀqš8j;<œ‰3é%;äÔ\ݵûE‚çaaÅIQê«“9,Z_/×Þ&µÝrêæ.¡K†‘*£‘|l°Ó—]öX'Àa#ƒ!\›Ð¸ݲÌÖ£¤¦ùŸó…†+…z3 °—©¿š¦Ub©Ôm¤4ò_¯òx†G—R}Ùþwhšùý 5jßéMÁ9V›'-£ÌÜ9£¢4›gµw,*óÔ#êß›ˆšú­Î?¦€ fƒ´@šæ ¢¸«¥6@+b¯ÖD;!œ[á§ËL/mvŽ×Á@ðÖ­=#°þø¢¹/Ôù#åšç$°\ÑH,Gé8.¿AQÈEWÑC¸Œl]Þ/ÕééÁj†V3[èÿÄðÜJŸe%ŽþÌþ݇Πüî°¿š©žS¹YÁŵÊ}W¹AóL‡ÝºžØ•·5¥aboðqŠ)ÏX昶|TnÐ@³úœÐ> à$×÷ÙI.û±ý$ûÁ<Á¶Ðdö¦9£rãh! î ·¾%–i­¡ƒrìM `ðB`ìÑ‘° ÝbG¼ŽB,Ρ΄.áNöU?H´g¬SÈíxí¼4êÖÈQ"t²›ò$†1g°å=(ë¯ÁSY&ô¾Š8ÅOÁÁ¾ ´ ëEp6¼cDÝ,>%™” þªFí.k€t]@ÿˆ¦‘è t:‰÷Í„—c"‰$ÒÂ;ûNGyÊ©-4¿ÚØÆµm/³B—¢gFÚë]L³sƒfg䢯ä|-ìàƒ‹ÒÇÓÿšdÈZ"ûœö¾,áB–g]Oóo%ůÊ:“²b•6D'*˜´®E௃¸b‘&ö䕈u¤øQ¢(çuQÔ-ÎÌê›öÀXÝ]_gO¾!fCýû ²»„øþ£å=oß±$É#Bõ‘E¡…æÅ²ÍÞNB1ÓjAçnå!Ïá<ÏbÀŸ]Ó0á¾²|áéÂÓìœ8诉Iäm|¯ÖdzY×!ê;Ó5L›Š&$;È&Ë;¡ûœ![yÝL‹ƒFDXPÿž9õ%”ü#Ñ"îbÆg÷=:ò tŽ–V;ŸVE#‡Òý#[F¥X;}‹•Ç7§ò%€!øDrjÇmø u¼f[<øUjÊÕíÁ“Œÿ1Gí;”™#bmµ¾ê¯FnsH’mS¦ÉÊÏ‚ áÂ5æÂ¤ákÿ}‘8•aÎŽüg+qðÓ`w1*ñÆ~)ð[n³BôÑGi°+‰W¸†²Ñf õïTDå‹SëéÄgÓ$”P…p $ ±s&3𩈟¨W•m¡kÊUµr#•wn­Jƒõ‘Ê…ËÐЭù–YÙfŸSð7xoMvJÄ$ô.OyâÚ Í¬Ì®é™íx©H­ÿb}s6MQ#>¹µ~sÃh|5ŸMù„Ï«1{n­ŽÊ#Û· AgëëŸè_o|dÇ̹µèÇj³:2;ã`ÌJ…ÕÛ,ýydC±(ýîÑô‚ ¡¤¯Cô•M‡k•¡mCu¢NÅNx Ê߯o AÂ!;4Í)1± žý‘ío»õ|3¥¢/-"P*‚}wL€?Ø‘^'{_{q  ´¾~ÜC¬š~ìÂá^íSͲÙÓôKÜ-§U³KÀv®\åÇŒG†:HcÖˡ[U~‡ÇJ+Áh `¥¾°5öiJN O~9aVþ·º–ÿÅî*§U± vO¡eùB§4àÞ¦S¯Sõ½vÔ“ËÄ7âƒó„Æ× ÷˜NJèiš¸^9ŽIp€cö±s‚²ÏàŸü$8«1 !'ÄöÙþçlŠ`{Ý ›ïNRóOÚ1X&çk+’‘Ö8#¥q®š›Ù-ê±·ÙÖݵËOfÊÅ+))Êùpø:©“Æv¾HªIc3 Ÿ&•IþHà&é nëìn¿M|áÉã2û”zb²5g(bN$ëxWÁIf]²åéqx E¢ç9æcÓh\S»ׇ…'D×ýÍ'&Ìá:í,MÛ¸’xòrƒ[á÷Ä÷“ð< Ï’pd—uzï@Òã™+Z ¥ð%ÅcßWõúOÒ¤VZûдsm‰ˆ¢QÖJ–•J“ìô\-Cgjl߯NÒ5¾«Þ|Ïò¤¦ ´ß»zì©{ÒãÞ†cÒ7QyïŠâ*¤0FŸçÁ–ª”J6Á¢k9¡‘©‚n¨qêêÙã.eðH¾ç‡[Y´cñõÌ | -¥ ›; ŽÙ!ò)"—J§¶¨oǽSÒ‘ˆ>( )Æü&Š^ÙY6Í»yYd E·¬ˆ´‘Œ.E>*CF>±½5· '‚Gç`®èP3\~âjÕÛFd¦ˆ‡7pN& ÕT³Ï`ë‰ÀªÎ¶ŒÑ$cà™Z<ˆØ½7Ï;Îk£~iÚ0ÿ޳‰4²êF0`!Øñ†ÚæÔ1[оô†À`±JÊø”kï“j”|b` ›!&ñg͹ˆçÁâ[¯"ŠEF¢€/ZUÝÀ/r¼5EI§Vy¨‘Ën\˜o°b„Þaaa´>­f'¢fƒ¥ŒY ¹ÈmŒÀVHŒ”7·+#Cõr­¨‰Rƒ{+à'´u`ŠtjKä¶Þ£2áK®r­²“âs›0}vlÔÿ€ß꿟ٰ!‘ÒEzâSkD_¥1ó>Ø+/Ùø»Z*VŽIÏaGÈ©­¾i\ú4Æ£ÎÉÅŽÿA¯ÂIŽÇßçL9JCµ Rwl8aUËH=ŸB‚ƒ%·'M‘†Ë:Ru¦½Xˆ™Bò&ýíá&²"½Åæ´Ó’5Jz!©‰x{&5G.—J÷ðâéæ•gjA0’r=“Z+€X‹Ö‚µÐ`€¤µ>Jp•°_ˆU2rÒfçʉî·6”Õ†‘­ÇqУºh\Ð(·AWìAOñWAë©ÛÚ îjOÛÖã¥[´ºíÖmÒºIZ×IëÊîSoG=#÷¨HèJ,ã8ëøgír£VVŽsýí²ÿByÃvÙª/xŠÍ¢ª~»\õsQVkž4j¶ íæVÓ¶®Ù˜bšù¦ö ïµ×T  šŒõ?MRÚwæJÚš3kÁ¦÷Î2GfûÖiøø™ÒOë„’ M§Ó3¢gŸž-S»Ø¼«ΙbHám5ÚéBXuŸ-ˆ&P«–…Wàå•X±ÿ’c¼ŸcªcÄ4ÿ¼_–äh~¹®ÒÎÂkWl$f]Ôi~ºuƒõ‘÷Y([;›MÒµÝæ4˜æ¾»¯–`˜Ë-6Ͱ[f嵟Úûaç½}±*É/Ô HaºÈë>¤€g |GŠå•é4ß·Í:A¥EÏmú¦ðÚwz¾¥í›R}?_½Ôîµr6å‡'é–L@š/ꪛorަ±œ/ÆÔl‰µ6æE„æ^šî9›ñ¨»¹PßÓ¡¯³Ðž¶ Š4h†Í¯’ÔWC›Ë]¤9XÔvgX¦ÚÂ#VOPcf†ÿÌu¡0¸ eo0wURMcU•å`*ã‰ë44^0np:Æ‚¥f ×0õûŠuy,yüÊ›ì@ˆÉ ¥ ^Þó«ø±í¦j,û¨5k â}ZÆ„¯i¯/>bÅ­žžÊ·mš<Ÿ¹­=ãŠú.¿’ z‹Žä•í™Yø£\ù°í¶^Gr_wÅ·;/|ز–ä1öªÓnØKCå¥á×4— YOªÌ”Og.>•‡æWƳ í3§¢wøo¾ìšDA‰Z’bô¨r^:JÕŸk¶¤q‡‡Íç%úÙþ)‘Sß ü§FõÊ2¿=AØü‘eŸÍ"ÉNýU©C­ßì|‚,Aï7÷¨«"Q¤"¢õ—D,Mf»#çÝ='iŸ†ê‘)blè €0Úüm%YáÊô¯`A JÐ6ÛwÍ­|¢Ñãó^娴ASçÙJø^ WëFhŒÔ"ÞC•i;]‘#Ñeìë¤ØïÆ¡3( D·riÿésêú³•0jweZª^šybÏÆóGl;ˆ¡S’ý|¡æHW;p<¡Ñ’®ù#—nm%]JûWøÊšÎœ^¾›·¹ž[z=¨yƒ¡Í1¶èN,À%•rªJEoHäÛÔK6Û˜° ñÜÌÂjÇF‰Iÿx‘Ë ³ý[žÆiÞ€ófaȨ¼Íë¬õ•4²Þá»ú*û®¾"˜ë½ÿ™Ë|ÍüïsºõHZ2“–,Ú[V{›†í¦a»iØEv¡Ã*š š•÷iºišnªÃê›:¬¾™†ýHÃ~è0®Ãüy)f°€õ½]¡\=Hüͤ~›øsíºü«­¬Å)^ó– "_4:û ÌE¹|Íyûža7Ç[G-V‘ë»KÛòM»WþfölãÑ]Hk×%’ÖŒGVoíÑïßþ; Mƒ> ]“‚ËÆšªAêÍQÙ¡Œm;ÍBšÙ¥tHDâAJÝí}³`ãá8ÖŠ2*Óv£â3täT޹õ3ÎñaÅ»{¸D0!…ʺÃ\);!é=‹Teyä°žÎ<œò÷»ŠžµY‘ö½ó‰…Ú½´p¦j÷ÚBVßìÞªÍt}}*{$ôK‹¢Ž:Ó` ̰½)ë$$Wö¯hç‚ÈúþZ°@ógh{e?XtbŒZ@ŒïÊiPßu΃Ê)ö^.À¹i„¿môŽXMÓb{:‹.¼<à»Ó¬:û/íÜÒ†õUQâAº¦öÕ¶g¬ Ø(˜Q3J•S%ß,XÑ40?7°®:ö–oî¨q4²½'Åÿ>²™‰€#Ùåe°²&óšíw6DR¾2i—æŸsW”QféŒXû8}\uNEý˜çÔÜÿ¦æâY4»Ì1þË6?©‹¬Î¤3 &ÒˉÅØ85kÂ@ã"Ö×ÏzÇzµík’Lrý¿Ó‰l¤!5Œá1­FêÅ‚ÖR€#c”AÈf€PJÔµ1‹g1ÇäݱӀ—ÀìȭΩτŒcþð,`ôèàÀŽY\¸õ+Ës`vZ¾a‹qýÁíÖÕ ΃ÞsP‡g9@xDÉ)ñN'MºdžË ›3)Z¬ó´ˆz[¾Q ˜Í~ƒÍ f³º§÷Ì Ù¨|c²g1ÇÆØ¦ê‘’ÕHǺ`!þÂõ¯µ0}Á{|9ÏE°Et¡÷Eš‡…"Їóè°à Á rÁLaè¾ î¨ÂÅQ»‡Îý„è,ËçÚŽ ]ü´HS(ü«$Ì6*îð®YúZ_ç)ò•¥QÙ@ʇY™˜4"<<3‡ST^²ò‘‚É5m$¨S ’´²ð–iÓ™ní ¯÷Ä,êôN¤ëËrÄ@°¥š}'lIVi›² # ¯¾›bbß]¨t‘ØZ"¢C…r;†?%ŽuNDúÀ9#ßy‘~;«ö€¬ÜP"÷Ä{ŽÔ"/@Xà…öõõ>‰Øãg³cÆf 6]ð~Dj¾,&DŠ.­^t€g[nýÆ9O«¾H«>ðžŸRsfa€i®t~‰ë˜µÔ²s™õj ÚŒ.,‘V¿bdã×ì/èMT¯nõ[S†²Ÿˆ![ymㆦ—Î{¡¶$œ,lüXfujEØõ×#"—WgÛ:õ`|$y¾Úö¿ŽýclR‹E°»E]œŽ¦<  „oשAÄåýû'²2Ç«áZò9q›Ö†-üÅñc,{pÀ£bŽ‹Ö «Ú²;ôÄ}kß !´ÝbuôA@÷dº}m¨³½¿Á@v¤x“Ö¤ü>zCô¼ƒÝW¼àÆ ÆrbKRa:ŸÚJ3õ½Ý4ƒHÉÞ®Ú¾ÂcfÃÒðlbxâtxb·~aã‡&¤‚NÅL=‘qZIc/½ÝàcGµ…N{™6&×`P.D’p('Û6Õ¥HåÕÃþ¸"Cš£#,§°•šWýNXP_ã4ûP™[NÉ“ {†² žèÇ„ø‡[=¯ïìÙØ }‚Å7N~Ybíoøž·e ©œ$ùh;Ÿƒµï¤ä‡[ñ©AŸ©}Øär÷¶}âø¯ÚC§â³e–ˆÝ+õR}ÖÆ¶Sì¦|ØÙ¸·äÞ'¼[“?êçDú5Ȇ9õ^²ʺ'¶A( ©{èB>Ìl®~âÃ×ÉQîUgç¡þô™$>–5 #Ù ´ESľ£qIê>VKm,ñy.¢=»jcmàíb µ±¾~Œm|, µ_µê®AtŠzç}¼0 ²P¶\rÄ{Þ£K„ ]„ø+M§6tªçµ“9*×ÇØèõÝÏv§Ò$êõ6£_ÎJ“Œ"è…HXm¬Uš|†¥~Þ©žãpBzf[zíåRú,°·z.ó¶zNÚ*u¹6„ÚMs¯Ò´ïú4çƒÕ³K:únÇÃCSx #€€ãt» +™f}‹wʾ²€Ürqœž[2{|CmØwÍi;Z²\o6'FóÜhŽæ™áÏæ©QmµÈ¨Ÿµm£92væ‰Ñ<6ª¯ ÿÖ¨…F­e4c£Ù7jM£>4š¡ÑlÕ3£Ù0šu£Y5ê‘á¿2ªÏŒúÀxk4}£é•šÉ`4Lm¡àÅÉΨTÂ6jh<¤Ÿð³ÃMÞCü@xRD¯v$Üæ'w8‹~…èWÝø“Ÿ¢«ÏüÐXþ`$¤!ò_Ùø¡ðº:ëŠOuäJÅà;’äÕ3l3®¾¶ñŠÂ^œ Kùm|s µ&!2ŸÕŒÔš6θb'ôOŒg ˆT‹Šlr}%jüºa—`íãÒÖ‡hß©N;ÈÒÒ´!Þ–ÜÈJ$‰ä²cžÍø´Ìz øí7 þåô'+÷íôŒ.µklÔm|²LoÓdn^!v^y*ú‡³¢Ò ôXi+•­”¨MH£ÇûnõsºwlÔûð‹Âs­õy/wØYm*÷vHS½É«Îüî½2ï——žÎÇÕæ'ÇhlöƒÆþ ¯;Ò7 ÝÍ¥šA$gâ~§Íêe6>8÷Nµâ4kNõÖ©~qªŸœÆ;Ç,š·NãÓl9µŠSóœÆžão"¼6u»NãµÓŒœJ, `¢æÕy½žŸ-ɇ]FW¨m>î×Wû{žó]j9?$^‰iÔg¡m`ÓPö¡Fz ûÁÒiD¨¨+B2‰.9j»’¦÷™ª*rVoÈÉ}êeµÂç#ÙÌHê Šrò—O"×Ö±ìÖ=ÖKÐ¥Y¦"Cª'Õ ¦ÂcùÚ úµX3Hpd£¸é¿3YBÎ.› e!êD4p•M ì’$%Ò¬›K(éNz ïØyKÒ:Nàù¯Mg·9Þ+=÷ùTšé}6ùγACßkkÔÝÂæÖ«òSN ºÕlÂ|ì««>°(‰m”ê 7|Ic¾´³Ú8ÂKSœHþÀaß$)óJ¤,'6ܯDñÊÞ,ñ^$•÷:ð-®šÒ rBÌd“u‚m}¬¸Ëƒú© é®R%}¡Ruü›vH]kçúKÜ»pa¥NÌÆK§ñÂiLéñ”TAì§ËŽBGùj0ÂPpN Ç¹8ÕùFãýÎt"tRô>·C`ÁÜ)ÜÎã¡ÖöŽ:&J±[rt(Ï_4?8þÙ_¶M¥ ŒüU#6ÓFc*£¾Á›‰êm`míO·öÆ=GõÄ?ho8m³ú¡|S oJ•O¥ðÚt7”¦âÑÏnû£SûJ?•÷ôS}O"ÞNî¿q oFÇ®qSÁ;oË‘@Ç 4Õ…éT¤ôÊNŽoÆi¹éT¯Ûæ£ò#v°ÑTppnßÍå´æž3wÔ Eræ|Z÷Øñÿ ÊÁáa×ZO~Çé ïÒÙuÞsÒêx¹ñ…5ww××çnã†W¬èK­åÒ›Loz‘tÌÙÕw¼—óËëÅ„ØÊèÿiÛx/–*SÕe»k®›m³‹=½s·ú.IÌÆ%}˜AWNƒP »¤òÓoVÌ. ÙíÒÿEÎýPæ· ¨±LÛG4U§tyI’o£}wÌý(>e#ú§ë+ª¼þŸŽ˜Å㢉“;¨' ¤ˆ‡âpÀóÜìx},”2bíaÇûŒíbÐÉ$Âó;r†‘?µ~»Ù{ÉNxÉJõ‚ŠCû½¯Dl~¾—!ø° ?ÌC\¢"X´±qhT´þERb`Zûº³”̬½21í³$tXd¸µêÑ1 йTŽ“ÑzŒY9±gK¾ä€x©±Þ¥B;dªà¶…Ë¥þàÕ®êñR¯")üƒ'6 Þ‚Ý]̼VY 0b@HHÍùHÑ­wŒWªmi½!G2Q§z" »<Ñ4ÆBï3¨Ùgk—[wôžéÑÃå ¯t–WÈòÊ<˜åy:à))•€'Y’¦Zp¯Áú9‡b,ëRÔÀØÆ%A?¾…;<ˆ·ÆØ˜Y} !@mÿ£þó>ÂËõu"3-£ÚE›0Ëj—O‚FÌDZ/·ÞØØVˆñm ô[ëunÿ®PC ´v'm¥RPM¢Uä°¡ÃÚ®*’$FÆ…•MÁZÿ²²EL•ÙzUzKò ÿ&àSão€ð4[">Pƒ›?ÞðR€³øoº¡ÛÚaI›`å¿Y_ß…’ꟌÈ8œDØíÝ OƒµÌâ.Ÿä¡ní’l3чGæ²y#T²0Ÿ ¾¶!؆¬*Í¡üW.ù6f‘?üÈØ9kÏ6çÁœáêl‘â⤠pË—uš¤Jù9Fàãà[¿éø@ûç|d}]ú§¿¥h*‰\iqÞ}>žÐ:å1…ýIÒ„Äyz·ü\òhµùf(³í*§ñ9Û†[ÛâS¹, óõ.éNR}OŸùØ,R-Äù Öªê„Ûq–Ž*$DNÎ×Áª‡Iì”p'”k bŒù¶‰½Ü…ù^ì©^ì©^ìQ/´Î¼­”§½¨m©>䛯†6¤õ5š¢ûúçb·J¯äÛÔK߯ývÍÔæÔs-óÏ¥ex¢eô\Þ3Ò¨÷Xã£ï€wÃÀ½À¢ N›¼Èú½2vÒKJðüÁ{Y‚í‡pkT‚­ŸÜ®V±÷`‚\«6@$|Z:>v‹ž9§X¤—µubg K¾¡/÷NÜJ¼·k¾£îWêÔý{·_ñÁý¡h wØÑà\8Þ‹`|Nµ4:¬ ÌÃ3ä?ë]`3 5–ŽI¢¿ß`½Ý{Aå‰Ü³1øx!·*$É…\„`ß +è2t+•8S©€™â ¨)Iµ–6õLÔã3^¥WwCð%£~ÓªÖµ XöÏïMâíÉÅ1¶÷X087»Þ‹ -Úá‘u&GöA¦å& >‚Ý+–Ž›·GÅŽrYî#û÷2Û~»ÞÂÚãû^XŠ W"«=KŽ¿ôy#ŸE'R»¥ì u¾Zw?áèŽa7NÑßëPY–|•U™ö#¿ßÑ ý>%Âfr!©Å/ÔR`vK^Û³ETL¿»ª§ïDT9Äýʦ;1Æccu=³à¨¹®§o!º ö™˜~zæXr3º¡‡/ËÛ”C"aÞ>ž]§fo*Û7Á•_m¹Ä`¡>qëŠÝ4Yò¼ü’ßAƒÛ Xbu¾±jõ|SÈÇGئ‡%89&éKéŸJ¢z‰5r<¶ àHÓ¦•š˜_›AzÇ$[ÐÐwŠûÎ+Í[Ä â¾³WÃ}K±éïú–«Í@Ý9ªÒ20¡\Bç»^aþî¾¶¿c[bë«”vz9/by 07ºýö÷ª=~/ǧäFľã_¶ûNÕkKD¨/Tj-èmÙ‰\ÿxýK þ¥ºº ‹wìoºµ×=|ñþvUÊWÛÃJû+Î-^Öy]WnÛÔÆì- Ém¿ªW¾‡šu×€õó™hKQ¿>º ïÝJ°e•ü–ÛšYðün—}»¸áÖìGa±…¬·X¨6Û¿™]C® aH´¦Âz·ò§˜™˜ŸSÇp…pu«’ÆšëµÕ“[íà‚ѸÿÑâþ×ÊóA_on#Л#¿Ÿù\Ù[þ¶°ZÍ$JNluûÅû§D1ÑÕµÚGÛ†ü ;l_9¦¯|×lêî^‡àUþæ VŠèVö7ïéÛ›/©!¬ŒãjÂ5¤Nü×*ß:Â&®ò·V=ñÜGº¨c\‚éeÛèqáw » )*>ŸŒá(î¡©bÕˆ§Xl¿9¶ªaÚöÚ Æ ËÐ1k*Fƒw˜é7†[e€È_Û/GlYùÜyûmoßñ6±ÈõÒ ¦†<4rVØ1ëŸp™™“~~ä»Í`FŠ­±³ ‘´þÕiâa¾útñŽQùžÛ6RÙhk&£Ÿ1žï>çé@ÉHîrh‚`–Ð[u¬MŸ/|¢ÑDÓ7Ðòe»Ï‰;>¥Ø/~„¸ÃB«zX°Í4,|ް*£2ÂúVÿ¨Ã6³°OS’b9ê“9ýR:H8œö‹¯ûšñ Aëbá"L;=ÅzX¨lP=¸Úª…f¹zpÞQþ ôñöÃB->,PêڋÑ^DÇÔ=,To Å~'»y@,³ Ñسøj@-á6pò(<©{}·å[k£nØV«åð2—ûÿm7äB»­ÏÍSnuʽZïºÒÃB›¯¨m½ž:#ŸW'㱕þ'öUwF]ÜÚ׿ëúªC|ÖqýE}dJù<~?½ ×ç3U$‘yxùv¾Aþ£:²¶6TVu €*+Í‹Ûû|{_>¤:TAVØ•Ðú~®|Pí V•°_¤àÔ}§^o9…DþàŒ+ùû¿Ñ0ÑÎBqé‘\…³dOŽ' œå$‹ÙeœÄãyœÀ!|‡ƒ“„}&Ãé,ÑÞé)E|žL.Çãd¾¸S:ø¸Jøá}žÇhR<_$ð3Mb.û³éõ<ž%Sö«5ç¤ðbš '‰rš„³c.~ž\ÎÆÉõhM¯“þ4ºMÄóÖÊ“„Q”œÏGq2˜ÏJß¼&³é·x:L!5+¾YÄ“(o6”,QO’‹ËùI2 PO êÜi%Óáp/Þq-ÉàrFÝ —sjÙUÂþ.“áh6_<ƒ 8êB8-n© ×»á"a+)p¶ 6(f4®=ÔwöýÉð9EQ@2[¢Óñø€*=ÏâÍÙŒÆMÂvŠóð& '#êQLQn-5ñ˜{>‡álDé¨ÕÓãcj6õe'R!KDá/.âÙ³°®¹Xçñ`D ‹”çè„Ú ˆ » Tp$亞ij-¤â@-™Ä@¢YDññM<@?g4xT锪 )ÁÍbÔ@}N žxz#ü‘æ]Nà7—”É‹íä «ó˜R'ÓywzÓËEÅ<˜¨FB³àâ†j/’ÓùŒ³ê$œßN„Â<‰¶Ä£WBc4Žiè'€a ë÷˘:+(¨ˆÈùðz4¡ÙµxÓ4“ Á]’maRG7¨nŒž§!M_8¹•Q¦ÎR+Ï©ÊÑs…¥¾ˆ5Ï€ @»óê_(&<—é@³xN™ç‰ö’”Ìá¼)ao‰˜°óäg}‰¸Ä²1gjB€›îN¯Õ°Ã±±´ow4ÇH.Xi"'çÓËyO¸µÓ1u…ÈŸ8BD“TÓçOoÒ±ceýôâŠðXpˆ(É6€*â Ê‚ÚÄäæVêÇ!æ Õ=#b CóiDuA3ùš*ÑN‘šÛ„-á\õMÆ~û¿Ï÷hN\0•¢øSš#SšÇèQX8õ¦Ú~ŒÆã0¡á‰v‚Íô—¦Þ&Í&`6å`JÚ³C„¨ —&~æ9'äò­Ì¼ùl@ˆËÛŸ%Êq÷>“mvœ '®Fó¨È,†ÏÝè@ÐX9"Hèù¡fQÞù—½]šj f'ñ’ ¦è; Ç˜&„ªD¹FDNS§b‚‰ø›Jþ¥ÀI`¥Â@Ü›F£áˆ ºˆÃq.ÿCL%Î/ %h BÜó‹DüÐ&ñùd"›ÔæM"Ÿ#¢˜4ª/övQûU'r‘(7Ô |vi,syÞ§rÅ1"ÃD»¯/èc_,xp ½¢!¼7bbÏãð’%8¾¸ÇàfÖÉtÁ<ºGØL ѵ‰Í@’·ìÚWÅ!@&u*’‘Ãp åb4äQ$Ïãø ‘£Eø:¾MÎâ[ÆÊÿù%æhŸi<¢NI˜bƒ[òØÆ`j©CSá­ô #\‡€&T%1³4E8€+o%ç—ýsÊ·„I8D¤ps&G<,ªŠãlc`æ ÇÄ­\öçÓ±Ô"z= /6©­Q,dÀ2Ç(¨¶½Ô,`Él,fc€@ÈF†Åp.Aâm&‚ÇÀ-=…\LÈfB"‰ïÄÑ\P¦?½AéÉÆFÂ~Í“ù5ψYA„k*f¼gçDþI¢™6³A6©‘Ô@š­¯êùEK<ÜÜVV&@ù¥TÈ5£I8VâƒP75Wد4Äq•”ãåY|wÑ4b4ÖrŠ*GzÁZNŸ»2g-‰…;¼<(†cn»n„"4„&›‹dc¢ŠRQ"&«É”&ñÀ-“‡DVê˜U W¾HszBÚàµôh8£tc8šöã$ÎU`Í÷¡ ޔå‚þ[€µÊ´ˆòâcšS§–1H­ >z¤AA#{Îê D€Œ½Û!Ì]dA6Õ¾ ËDî  @¿$®]pxîæ1À5 ¯F¤PÁCB ê8;¨3ødrÉï/ä¹…YJR¼þˆbé1H<߯$oÂ7\È[’í*ÔDëA?æLó’ªXEXÍ×ZØ|.xǘM¢;©È,ƒ²“0©VÄ‘b]¤i’¼Ø;`EbdâµÉ+ Ý𒃓ËdDó(Ù&Lï4ã­=8xG$8ÙѸϧ`ý¤_LXcqXÑ©©ˆ²`Ÿ&¿D²‰äÐ`-†SqYWgbwFzÿ¢rÁ¢Ç1I§ãP8¹ô’˜9ÉÞL>¢(R¾ëë„ÙøÉL‹@ D 4³  _îx*Ž*ØÉ"Ëèü˜JÆKS”Ä’±zû¤ ¥d:¹ ™í—*V!)ØÎ;Úã²xÞÖ—«Þ—7êíZ#çqù¿þë*œ)GõF _’ĸ3 s%×ÚÆÝÒ1 ýø„0p:Kj¤Üë/Ȅ㘿ŒežœÙ12†},S=#LBú()ñ~åáÕYÀd¤uÀýå8¢ƒ5š8bÉ[º‹ÛBÿ¨ÍÚªå>¤XëëY‚»Á1Z_‰ºg4[‰[x³>o² h×7fñ1$FÒLr}[LÐÀh ´é§iÂ.ƒyN)UmŒ©Å\ (Â&ŠÊ4wŒxBÔ *Ö˜L'¥Ìy¶ñqgîÞ«,×ÐÑ„GLÁ:m6Ê…ÞçÆˆïôzÞFè˜x¡¿û¹Ò7ŽÀÐö]ò;•Ç0\×Uï„:(‘*”½kK¡Òç¬Ý#jz1h©-€Ú­œ‡3e²ïù%‘Ú17¨vh4·x ®±EiÇ KT0D'À“Àhl¾Ü|YÞ|µùEf4CA¬úñp(L Çó©IÏ€±;ë'k—üXs]Š$JP³ã ÊÇ1†$ù¢Fª'œè!E·h(AÉ(šrÆ£ÕPÐ Š¨VÕø3Ž©†‡!td¦‡V!#?p¥´z”Oæ—3p$Öéx8¸9” ’~± û1ÉÆi\ÃÚš¢Ÿs…y<×e‘ø !z:\ÍGÈÍfFã<¼H&.®Ê˜!tmÂ÷ùÅh‘6-›Ú0‘¾ŸµUªá‹Ù8#!ârLÔP·ÒVûƒ ŠÆ›… éæÊð¨AÈCß5v†˜u1 Â½p¸EšvèìR¥TíæiÜ}dÏ¦Ž¥šÂH·‹âõ‘o] M&PXë>Ý”¬†A¬cû&§cjEQw9Næ‘‹ëþ¬v²Æè¢ Æû´m\òsù_9†°Í<ÔPsLšϺ  ¸ÄýQÈh¨˜ËVŶwÈ–‡e––Ñ …+G÷E‹Àõ”K‘ÄìÖ‰qÖÃó‹Nx™É_ß/§ þ|ÌŸcùxÂÇôÁ´Š›g¡¼´'èˆ*\Gê;Žo¨¶œKû4 •{\P0“Ó¯« ±8§£Ë쥹Žt Cô&dêäa}0 'sèC –)]²GÓ%^0ÔTÓašZìÇñ Þ²ÙGá‰Aò I¸¥9ɚƂ!¥y€ÉðrFihèX]𻫳‰Ú£f’f¥¿àeoOŽÇ£ù‰ŽE»ugÜ\9$VÍÓ)©¸µNŠ©uv$ BŠ먵4U‰_F$ÛŪ(* œÜ¤ Aaƒ¢¬%¹©ƒéLDl&ÞlíRÜìi8ÅD+9,Q@¤Z%!QF‚xNÒ+øý$* YÌŠÚŠ?–Œ5-Jµ Q½Ì0MñG–BÊ’Yeð¬"8` ¥4!›>vZÀ?*€³‚rkPOÕA|2ƒaÄ¡ª”ݺ`yMÈ‚æxVn¢5Kçâ¬B®¨‚ÍíøCPZJ9 ð¤Ã)œX!‹{sßaÌéGDîy¼È`±˜J"ud(ûlŠÌºÐ<Á¡ÖÕ³‡„¿#zô<Òs]æï¯ÓÉœUõd­ävò„eî›.5b”Rc­¦Ç9gHIÂÔ|aÔBPê´E‘®˜¬ ;‹â¯P ì: '^…? í4Äà¢{TÒQÖµl8­4V‘0üñÒn'_Ù;’0J°¢]ŸÜ«lm¥²Ÿ³ngS"v÷Jùg®%ùþM@?Çx¨7÷µÔ0þ‰Vót¾_Âò¯ÉôspˆôB̦—¦i$ל§dô`EÆLi2ƒ˜\Œ/g á™N ã[×`5;‘n¡¼¾Hâôíª ëåD$Ó,Dé i1³]ÊæTŽÍŒÿ12þ%MþÏø C)#€•‚5EIy¾Ò^–%'mp»TF-×x7ŽbH˜$±Y€¥é¯Îè°¤ŒL9^cX±{ì²ÈmzJ:?LLÌïAp‘(ÓV\dkÊPG¦?¤OJLOÛ˜DÝ?á/{'ÑÿAßTGJ| g®ñq¥}"[©AΆÃaV51Ì?r#–ƒÃÜü¿ÜýÿÜÝ0ÞLÊt;½$ÒÀ(ŽiÇ„½VÐ]“«‘šrˆÐbŸŽ^.¦ç°-»}á/6ÿF¸ºôNŠXÑ㳯&IŽƒ;㋲ñ¦5V˜E¤ƒ…#ÖÞ.E_#v· &B7y[#”êšäªò%þ¾È! ÁZ¨mF÷¯b­ÕÆØFÛ°¬û Ϧb6(Ò#¶¦äUw`lhÉBñ¸”·dÐa¨h[øVKð~U TWòKú|K{…¢‚G±pÄp]í‡ðcÙúô`ÔÕ§ì]§&…í¡ íŸõÝX.2”2ÛÙÌÏó¬0Ô¶W¡rš»m² ‘èsË(`z¹¸¸\ç—DsŽ¡Ò±PµÊµ‰ò-Œø&å ,\OöVSæ öJ+ /`—'Ú°P-Í—%è§V½Tqç`êTæ.e½©?ÄÑgÌÐSy‰Ñà^Ñ+¢‡î7!&7ýb3¥Q™â+"81#Ï5$Xd¡bÿ•£5"]ú_Ê|œôžLfô$¼×ƒ…þòœ+5hnFo¢£¡ÍDúL€š*Ýö§B RÄ´°þòP $Ýܲ8HMçŠ50Ä„°)Þ'˜±Å&À|“üL«âZr/2MSÝcDñž£‰\ï¨C!³¾º²„F¡Å¢›°.62Zi2ö”¨#5­|+z¨úô3ê¦;Ñ$Þvy3¬…‰ŒÜd|‡!ê3Vg ½.–ÉÔ˜Ø,È|zÄâ&€Í©<KRa„¥„‚ìÅ-mÄ´*` lÁÅ‚¼qÏçÊ¢’–wƒ¼šO'+qd0ò§›. [HäZ`î 6TÑ_'èì{ÄôÎF¶ J…|mþU£Ct1«Ñ½ÂÇIºN&¡J—÷ìMØ2b¬q|Î_4 v§° òç³8þ片½†l÷% xn…_ž« ›EI–Ô–Ss9™Ä0 ‡³[ãòâ:œEsC–€!–]ŸÄ"ExÝz»G¢àdtq)à|••skd½ÿçÕÝýËI>•š £ÑU~ÅieAÉ*P¬Øð~·èÕvó¹%ƒ wÒ¶‚Þ4Vp8f1½ À‹õíÚ+¼G™B¼4D Ô¦Z dA**HpÁÆÙ°ϬÂ(£’¾”ti¡Î+{‚¸Á+ÃöQ@LüÙ€å¹ ¦ÀIÕüv¯vW6X«µ}ž¡²¢EØÂõžO£ÍâëéÆållðú+¹ÉË[q³á`,²,€þ+]¨…^;1Þ½|g¯àÀÏÛ}WšeÅ¡êFÒz¡hüíÑß\lªcã:4›Àø¹H.ÆNå†ò?ýçåcŒ² €&qT®«ÎX…î÷ À¸Ä¢—ÝæG¾œ:—óO¿æ× +TÒˆJ>âþ“ªõüÞô|¡ÖgÅâÎ[ô˜)ïw«­@kÚi²<ÜÔŠFFÀ七wÓÂy’ª ok-¬¬ª¦éòv±õHã3Ë:Vþ½üÌLÓ¨9ú),eI³ø”EòºÑ¥l›MQ¥ÒM^$dUD2ºÀá½÷ Çi÷Óìo¦×’C¸qõ~ )}¥¢y¼ØžDïÒ*lck ýЬ–v¯ÖvM@"¶C²V²ØêOf¦”V7wSHl kâ>*~PÒpÉfÀCaÊ^üeÊ”ó8e¡-9)?}¡”û %—øa´ÉrßÞ–âr¨ýôr„uÙ{|ØÀ¶j#< OV€lÝbx']^î¹9cï`Ž,ÁU¨+¬:Œ¿‘êAH –Ðp8Áú=MžßŒm3Ü,;g˜„u[3C¥enêŽL<"×8œüA ¢_b:Æ]ßú…†‚`úz¨bµ4§M™9uê¨ÖZ»(ʼê}Žx;œíþO´ëž¢÷íÂö Õ¸?ÔpÜoäíP‚[Ö•uyaMÕJèEØU6^ðžpãõh²8 ÊU@nK¶“c¥%`0atký´üðò5KäU[ ø(•¹õ&ÙOô³’ ùX«…‚À™Ôr>î•$>¿ >±-Z¯ëeåÔš5š°µ94 Ã0È$Q•˜_Ÿ4²Å'e[7¬l•ÚvU>­ªe™$1lJœÝ°ªäeúÍ5©ýÀºuŠ{…Çñù“BfTË­»pbº—‘$5=¤;Â` Ó§öô¾0_ï óÊUÃóÚµJÛ÷Vö„­lcŠEË•m£€¼¦L#l’ ÎùÌÐg¥„¼à°² fƒ¨/º¤È|†e%{2]X+!Ù›¸£.Rv/ÜK¥쀗.g;)Ù^Cz”Qå4H­à«îm>Ûz !n…˜ŠQf‰€E` ×3Š”º]M‡¤,׫À8ÊJ~Ïw’üÛç$¾á’QNö»%€žÙ®˜f5¹ÉçÜçÕÂ\ÛOç›Ï¤'ëž­Ëæ ›#/»Í霖-jÛ<ÛKÄ[U@dH¢~~F(TEm‚8 ¿ø™†ò¼‰úlž•!”„‚W®ÚÓŸëÕ£¡ÜéD'+Š$éP'ÓB¨ß¡óRìÃ9qD`®È“‡%¾£¾+»é-ÎJ}ÉS¢Jíú¦j«ihKÁ \3Ö‘uë!XÇ™P·–nÚ•’Sa.®e½°»êôšÎÀ«ÐÕ68(×’@r­¦4†H«Ø˜­õŒù{'+§ÒärÏQÊÇ‹¿*C¯£ ÞÚÅÖ,jð|5 ÎÓÿd³~Ê—ÿ&Œ©Åÿ{!ìÕ¹W|$ÚàPœªË6r } Ax1‡>–y…cxsÔåE.¼š…c\s15Ž!•$&Í;™žÇ¹@iÌ;¹ñüå@KD‹#fl\¹÷+,[Õ,9•„ä‹°ŸƒMEµ}¡6Rt¤¡ñ|ǸlŽfCÒùe•‹{²îÞ%멊>164Tõ‚ÐC“ÍÑZÆBóÕ„ÿvïaú»KŦ”ua|kœ¼Ç€9S¦C„V¯’äåxþbFÈT]™“Ÿ3ú,p€hA‘+ì듈&ùÉ©Û7W[|a¸IÛù·mÙºOs›Œ¸Pß×ו7w Á KLfý:ýËvàkãÑ\d¤ñ¨àdC~agÂØE s}’­2þT5’ǼÅ)¯?þnúàø»ÿc»wHýß‚Þý[~ì°Ój¤%Ê;92´*ƒ=cb»bèYÕÞîþÉzßpOgfˆØù)žƒŽ¢övçIûWÓõ!’U(tVù8Š1ÓË{žŸ-ïµ Ïo{íêƒË{€’:ºÌ†^.']ÛÓ»"±QŸ¦%ßëÂGçùâ¹ÊAíZ]³ÍVüT‰¿:¹ÌûzˆÆ2§âS!¯§\­F•ë5$ìNæÅ£Ùåd’;ŸW~½µ]vq‡«•Þ‹âR†h:»·õ1¥¤¿›Ôš¤e²Š(ïÿÎúáÊòaÚ¹Ÿ—Êî—˜'—{ؤòêæè#~ØfçÈÖlfîÔyÞõ}^bSÀµl’Ë6ðð¶<µÄ˜K}m‡êWO-3ê…=9©,·Åý]Þg*]V†+÷éX÷ cówKl»úRµx[Ð;Uêö·Á k´ó‹làÀ¶¥ýGnv¹®rÑóL‹ã„©à/©ó*1Gd»µ±'àSd—WºoîÛá¼ÈûæV6ÓÍ‹¿«@-oê‘}5Mµ-™HáàLïíF{ÝÕfàʸIÒÜz&2¡±·vå¼&‚PÕƒ|ªbápv8Áÿ4šŸ¦¶ï“K9Q Ý1NdË>ï–Psš‹Õ\:mè)ta¿kÀ«¡Õb¡:}·N­QÈU—)‹Mš’'·eã°ݬžfèR¶Ky·áƒ??ÇÆàpò>Ç^å|qlršCEå“ 2<W³ò3ìT¬| ϧ³vŒˆ’M ¹›CO+½#;‰Ést4ÏŠJOafWzrÄQ¯Ë¶4³ÌùC>ÿË(GYQ|ï‘R \S4[áqºa"¢èžþ¯œ±ÆT†Ã%ü4sdsS‡)þ/æ ßôóÄAJà)_F—ïsÌmW}`«¥²®æá&Y^—í{ù$êÖlž)B£¶c‚k^ÎÕ™AfÅ©Uc>=ÁÞ箾§¦yÜýålKi•Ë—cÛ·,CoÝï_帗œšö+N£ð®ÐÜœÿ7¦õßOg^Úþë ý—󙉨šÎ«“˜­¿šÄ¸c¾ÕÈ­jþ„£b†ø7PU½ý„­›Q$ƒPÆ|4ÄŸcÊb—gÖ ““ܬ˜J(è’âåæ“Ç²‘2f`J¤ù`¸WÔ¶ªŒ[ê“’)'_Ýg¤Ž…ü´ÕÈÇPy3“™ Èiú¢X­4%'Îlß,pàõ—“—K$V¸Æ[,_æ±rt›Ñ3ìò3øý4­ôg×J%K¥'4<~n0¿u»ps«„¿žRù)ÿËY¿vÿÃËÏ …QŽB…¿AqW®]´rò€³BäþÊdö7Uýš;êZó9y™Ä~ˆ¾ _ü%ó{ésáŽZ?³‰…OïBâ=qJ0å¥rY ‘Y…ñ¹éð? x(Á+±"ÐŒæ–Uà­r%«ÅùÊ+ùíØ¿,\K`™tº2RlHZ¤e­O›á5®ÐûCãÓQÁ^1«Þ'´yé„¡«¶ßå4²²å3Ó ½†áµÚ¯]«¯è„¿᯴·¼:•ª„¿éßêT ¬WÓQÄwÕå®ãÞÏÝ<Ô˜oð€þ› ]~ñ¦sÕP¹jn¾â|gÅÿƒe¦6c¥Û+ ./LǸ€_ØË‘eM)ÿñÿþwýÉ!ÌzyN„i^V[Ëp´0/ŸÎËþF£ÖêWB¿:hU7ú‘׊ãJÜïWêQ³÷#âY_.T®×«üܨz«O¯ÒبÔÿáy^­Rñë^­þ ¿ºQÛø‡±ñ¿¿ûÿøÇ%†aüãúúº„‰_¥û»øÿCÿ´"N22³ô·WšíJ+'†°MÃæ¬TcÜ`\'Jú&¾6>‡W±‘]a«ŒÓϦ·²5ÊØ\ºñjz2!w>:6,Õb—|ëÌÖ% bЊ',°œ#æ’½âŸÒîγí7ûÛîâfaë#/Þíý¬DêRÒk¨pz›PÚ¨•üªáUÛ¾ß&q«´QÝØ0¬ýpA:K•„à[NÆå“*Þ6jõfíç|š>•‹.àVÙ9sbgfßÅA&„ÙwBm­Áã°[(´cK{6²åD¢e ‚Á?CûI¥Ö•eJÙ3åžÇý–ݸÚ}…U©Ûö²3Zk…BÎZvÔr‘}ÇĬA©dÏzô´‚3vm‡÷ÎYÐK›ëæ”ðhyÔÉ5]G¯‹…egxËNV2ÕBí‹à"mDî²LÊÕ/Qa‘_\™épŽŽªòbi”ßëÀë»Õ=§rþ;Þ~ï¼2¶$ˆ?åf|Ç`×ìð‰}Ê!KJx”¿õ¾=>zd=¶ÜäðpnŸØ½oOŽýž|ûÍBëíßËNݧtnï[û·ÃÃÞá¡KÑeÇóÙÕœºVƒ»Úiû¥¡¢Œ÷;ðHíÕí;vuîëÀcoß/àÅ</æâðÒõ·à3ó…5X_·¤‰& ¼›Ãƒ¸¸[§:N¬>ŽÄ™9\/î»uTŽØ]/R‡®µp|*Ú®ÿå*ÿŠQÐ;Z.ßøì«8úÔ^²mγo÷Ägk£kú ³mV+æ‘Òpë_-ö1Ni—Níºmò¼5æ‹¶òQè¾^:¯ÛN墭\†<2r¶Ü*†GKÇß—lå}îØC·6 ð߸têÊ1 ¶Ññ/¼®wáz×⪠tÞµÓQ…EññNMeå–mªv×b_åµë.\i¶ûNþ’_³/êP<1FÁ°g÷ãµ:œ¸h4\_S–õõ­^?ILï5‚ÝÖ0Qp·ìDâ.RûTÁ-ü>„#ñÜï6ÜOíMoúQ;‘Áé;#IÑcñ«ŽÑ³úðŒéŸ’„_½? öúzNÝoØ!µ‰‡SÛM?4QÄL:ÍxÕ‡Ö–I=^S¾»«Û„•+Ë’¾°¿Nÿa¨íÖžS>8ÑÓdG•pwé`(ªneá¤ÉëkAÓ‹¼zÔ±F½-žNgV¯q„îØ2‚µºEì—“FØQÕRØ+TiIŒëS/Ü v!êz7âô†‹â–7Ô 7¿jœÒþ=ÙÕ{ý=•Xû 'h4?<˜(¯\¥¨Zùly-gÏyï¤~н: ¼MQUòúóŸ’ï=¼EØØ@Û9Ïö½<ïu”$R‰9eíûO)÷~Jéú/¥åã4qm’$[Vïž»¿k”ÀýñØj8ªÿ[˜á@­¥L^Ç*÷¾Ÿü[fï²6¡šëX¦ëšö“’Gµ:#ÂÛ yðþ£ì!üÓÊX1¹ 9\__£Ä‚®@·>µöl§vB”©BEzW¦Ý©0y2‚ˆQ@õå42&E*×hC´Ù|dÒ€ hTß©½í#8vµñ|\‚àż‡7~Î0ÊÆ¦bït0»p_Z¹¦ÁÍwˆ):`ß}~%ªDö³ëÅVÔ!SP¯¤Ÿî®€qHóm[ ®`ÊijÏNn+Ïúα}øÇûÒ†ŸØÊ1¦gõ«žýŒäÔ};-V2ÀÿpçÑÒx¾öÝ×4Ç{ô(yð£îÁ™4W±m ª„]¦€ ¢s7Úµ ÏD'ÎæWECNé>`Æ_X¶Ct$dRT9,tÁ:ÚL¾!qŸ«Ükk!÷ú˜ñÙ}ýdcé4²¢+Ï ­Ìbˆ)§]fÊÊ#ôZ°”€¹%Šlú›&ãS ÜzÕ©Wˆi9^¾¼šã¢ç[°ÎÍ’ÿ n½c¢‹;ÆGñ3øŸº11ÈoE¯íÕÜ×ÑcØÁ¥TLê=xžgîì¶ïWÍ‘.\ÿÆ ']bݳ6¥¸¡„þ'ª¡ß©Wˆ Qà¹^îZBÔnˆ7þyS«|x8+;ôEi<©¸ºk÷‹ÏÃB'#Kš¨z„£:¡±¾^®½Mj»<;î[›0¼ú*°d©2É'ÁŠ*U Ž  Ã€Çøë–e¶>˜%å™:Ÿ/4\)Ô›I€Ím-¤‘¢iZ%–JÝFzA#ÿõ*gxt(Õ—íÄìSæhô3Ô¨}§7×÷,„·Ú„Uÿ$sp¤°ß¿¶ë{ô^½Y_÷¯¹:J¡ê^ó¯¡ó ú8¦TN˜$¿¦º½£öÝÒ¦"…\ù×̹$½MD³¥l›JÛ3‹›S'À©Í¨'NýEPþQêÖFIói©ÛÜL¼Û¤þ4i^•ºÞŸå‘Sy¹ãƒ…+¿k^ÊÔ`5ÔCV“D3¼†Ï™úµš3ð'ïxçZŽ"ÌïxçÄøLoV®.ÌN*ƒÙìÍ‚ÀIo4Ñö!Ô£îô!=zçNR)¾ôEÈï|Õ (äW¨F_]fÙIÝxP¾Ò(1e0•¹£ùEãÔïÖfíKØ3Øò‹õ×à©,z_Eœâ§à`_Z…õ¢#Bã#êfíP‘²Á_ÕØWò'×pç4tý#šD¢?X,Ðé$Þ4³o3I$‘vùæÎûˆ|(oé}‚t ͯ6¶ñcmÛˬХ虤A&4;7hvF.ú:@Î×Â>X±(}<ý¯I†Œ¡%ÒtyOM º®f]Oóo%ůÊ:“²b•6D'*˜´nDÀ#P¿ï ®X¤‰}y%¢Aɸ“*:'PZ?¡ «[œ™Õ7Az-ëëˆZ!fCý°>²»„øþ£å=oß±$É#Bõ‘E¡…æÅ²M„]ÑÕÐjAçnå!Ï)ÎÆ³ðg×4Lb´v1dùÂÓ…§Ù9qÐ_“ÉÛø^­g³®CÔ·>·¨d›Š&$;È&Ë;¡ûœ!JH W4"‚:ëX¹P8(¡4à‰q3>»ŸèÑ‘¡kt´°Úù´*9”îÑØ2*Å€õ‰™$xñþdÓPß©| î*m³vc:µcbA/LÇk¶ÍʺR T®nϬŦcÖÏÌ£6½¿ÀûÈ<"ÖVë[ þ:aä6‡$Ù6eZ‘¬ü,Ø.\c.L~%‚,RÓÌZÃ,² ’$ÿÙJœÿŒâŠfµoªÄû¥Ào¹Í ÑGÿ™Mœ v%VÚÕSâßh 3Ðúw*¢òÅ©õt”ÇZhxPBÂ`4tÆÎ™ÌÀO¤"~¢^U¶…¬1!ôÏHDÏ=ª¼skU¬TîZR\ó-³²mÒä¡áaÞ[’‹Ð»8`[Í'áh`evMÏlÇKEjýë뜳iŠñÉ­mtð˜Fã«ÑølÊg„:\”íê¨<²íqp t¶¾þ‰þõÆGvàÁ[‹~¬æ0«#³3ƬTX½ÍÒŸG6‹ÒïM¯Ê­%"”ôuˆ¾²ép 2´m¨NÔ鱨 ¡@ùÛø ƒ!H!d‡¦9%&ij?²ým·~‚o¦Tô¥EJåoCB°ïŽéð‡ûÉõšì5`|Œ¡õõãŠ`Õôc×ôŸ›m´O5Ë• ŠÐ”Ñãã´*”9$W.‚òcÆ#C¤±aËåЭc<,?a˜õ…Ù‘’ÂùÍ _'ÕaÒØNÂIõ il&áÓ¤2IÂIx›„W6ÍîöÛÄž<.›Å=M¶æ Ẻaï*8ÉÌB £kC¶<=/¡Hô<Ç|ìokjwãú°ð„hØã²¿ùÄ„9\§¥iW’ORnðc+üžø~ž'áYŽì²NïHz–RƒÍǘöÓ'4·K¥S[Ô·ãÞ)é‡È@D ”…c~E ¯ b˜wó²È6ŠnY'i#]Š|T†Œ |b{k$6n g$%m¬¯ƒ5|Ÿª|âjÕÛFd¦`a† À9M˜$TSÍ>ƒ­'«: Ø2vF“Œ €gjñ "•z óŽóÀÚ¨_š6Ì?‚ãl"l§º Xv¼¡¶9u†AÌ´/½!0X¬R§2>åÚû¤%ŸCÀfˆIüYs.ây€W¯"ŠEF¢€/ZUÝÀ/r¼5EI§Vy¨‘Ën\˜o°b„Þaaa´>­f'¢fƒ¥ŒY ¹ÈmŒÀVHŒ”7·+#Cõr­¨‰Rƒ{+\b¦­+%Ü–Èm½'Fe}ÀÜ? T¶c’GªÔNÇ·Ûòñ#¶áùíUÁPè¿îuúiàA¿ß€Û™®1<<´zßì£G‡‡v¦¸¢UA»bHÅ´v‰³“ÙZÞm@íyÔ Òe³ÉE1|¶Ã3X×"©GB )T* ʂŹr#”Â!]‰ %«–~PdëåŒH@ÂÀÖ€t*gJ“´Â¬7À÷"–%ù( kœ~”-qõŽDµúˆÏlÂô="رQÿ~«;ü~fÆDJé‰O­}•JÄÌû`¯¼dãïj©X,©ÐsB¶jî‚ûAŸÆxÔÙ!¹Øñ?èU8Éqàøûœ)Gi¨¶TCê•q —‘zþ>…KnOš" —u¤êL`YBÌ’7éo7‘é-6§˜–¬ùSÒ IMÄ#Øë 0©9r¹Tºß€ïH7¯~¦ôÓ:¡$CÓiÅôŒèÙ§gËd ÝÕ?çL1¤ð¶ít!¬ºÏĨUËÂ+!…+ö_rŒ÷sLuŒ˜æŸ÷Ë’Í/÷ÃUúÏYxíŠM‚Ĭ ‹:ÍO÷£n°>ò> ekgó£Iº¶Û<€ÓÜw÷Õ s¹¥Ã¦(Ý^¶³l1]l༗ /¶@%ù…z)LWy݇ð „ïH±¼2æû¶Y§1¨´è¹Mß^ûNÏ·4 }Sªïç«—Ú½VΦüð$Ý’ HÒâ%P]uó€Ù–óŘš-±ÖƼˆÐÜKÓ=g3¾u7ê{:ôuÚÓD‘FâÍb,èsR_ =lZ,w‘nä`QÛa™j KŒX=A™þ3×…Àà.”½ÁÜUI5 ŒUU–ƒ©Œ'R¬ÓÐxÁ¸Áé –šU0\C«´% ¬žYƒ Ò7Xü1¤t¡z§DÊéwS5vßõ=³¶ Þ§eLŸ´S¯Os ̦''–%ÏgnKÙû]QßåWTo‘À‘¼òAt&—Àåȇm·õ:’ûÍ=–5“¾-kIc¯Z1í†m±D1T^~MsÙõ¤ÊLì²tâì]Û`Å+ãYö™SÑ{í©ý¸ù²k%jIŠÑ£Êyé(9T®MØ’Æ6Ÿ—ègû§DN}7ðŸÕ+ËüöaóG–Y|V4‹$_8õWi¤µ~³ó v²½ßÜ£®Š|D‘ŠˆÖ_±4™íþ?ì}i{ÛH®î|ž_Asº-2¢i“ÔbKaÜî8‹/Iì$–ÝýPeËÑQŠí˜:¿ýâªHÊK÷Ì=Ïùp—Ì´EkA(U…*ô!º;$kŸHõÄ36r@mþk)[ãÊô¿c9(CÃlÜnî3õŸ[ÁÙÚ çKéÏtz-·Ô0ì«M¼‡>ãF¶#G¦ ê8ÖYáïÆ©SLH îòþìsîÚó¥4‚;¯UæfQØóâù^;I¡S–ãb‘æÈW=q<‘Ñ’oóG!ßÊR¾Lö/é•k5œ9¿¼oÞznéý ÍkxhD6œcleÐ]XÀ ,JªåRÕ‚½‘GlÖŸ³žÚ4mlC¼4ó´ê9§Qfš¼*”Ųýã¬lÈeó4” UÙÍ«úàãCÞ;¼WÞäï•7$ ½÷?soYÿ}Î\’©@²pªG:­z”¥ígiûYÚ$K›è´@«A3xŸågùÆ:­¶£Ój;YÚ,í‡Nóæ'9¦XÁRöo´»Âzå$õwÒÚMê'² ¹_lµZœñ5»Ô€ˆØd|KØœéâX.*”ÛL Ü÷ÞGŽÚ¬&!×vO¨kË×ÖúÖéiË6žü² kíj¬5ã‰ÕZyòÓÿÒLƒ^NKÛ& —k*MoÎÖ*ذ³"4ó1·)2Q…ø¡I½ÝúÃÂãYQ.eú\9Á9w¸£<ão®Y««ÑJØÅR¤VwXK"g3¢yÏ,›²-™g§%§Ç§¦«áKa舾 ÷ RarÖh¡s÷mùì(°? $Ò˰®Å.ɳ†›ì5Ko««~6/cLyƒ—.Ø‘À—Í„®’3%«gMðÙ®[»v†YÓ“¬éaˆçâ’6§Lc¥ù(¯cÔdCõŠP f¶H+_@Oqkd–Ûf<󸚒A…`Mm·òE>ó~Ø#¬@]+~n™¶ÞØ: Q8[c!17åÙ&‰¹Œ•+çGµx¥õé‡ÿÁËej±Õÿ¼.àÙ?BeìðkšªÝ þ‡Ø_ù‘¦xé娮z& +œ²RHùƒS¨Ì±«¨~âM?Hhàá\×Å-= MÉú_!có àŸ÷Ç…}΋Z6ñøù¢€¢!‚F®Þ¹vmž®[kdOÙòÄY4¹9=-§kö6'¬ƒ!€XLw©*Óñ —”ç’Rö(m…xbw=#2}ØüF¶„N¢)@hy6'ðãSºgÛkN7¤WLþŠ|—B>¯^’eîñx…c%nùßÏd¡ÍãJF!¯´<¤·Fnå[Ø)—›\ˆÔ FÝ{ª…À yµü9hÔ´¡„ •œ°Öµæ$FÕûz0ò)VY4 . nÅ6ª½n±öý·ž„½°×Òœ§’aïôÂÚÜ2ß§i6Õ1˽²Ù\˜6 M² §¹cc/›=-h`,{·ÓÆÔ™5fXl8W½@ û îU ‰äÂ1[[3…—À{3¶Ô¼e•a5Ó‹ÅŒ±³é±Å%ÛÇØ7ÆyœÌ ouµ\î†a q ‡àh?’uЩȽœ,·]VWG4ý±µQ°gLe™ãs(Î%=êê¹Ãn:=½ËÒÓ»,Í‚3zÏ­ì"½6ãÜõ+6þÀo½BDeÅ+Êsó"Ê}ÃŽx¤÷ÙÉ {RþG/­zÞ„÷o¸q±œØ’gðOçS[Y!°¾·Ÿ+ÙÛWî+L“('ODäÙyâŒ<±[›ØøCRa L§éD_Fø<:-å±Þ~ø±©`¡ §½È€)@*”‚©CÎ •äµME¢ìy0yõàwA"¢Gc´í^¥æ]¿ 6ÔWx;‚ÄÚpÖ<9Àpã¡'nðÄD8&Äç8¼ØjymçøÌ†'ô6?ü²ÅÚßð)‡+ö¤ä7ð  Ïœ\nŽÿ¦ÑsŸWfIؽQ•ç ¸Â_˜ÊÁ³ñ`Á5…ì­É/µ!‰~²^eí·lz²ïI¨­ Ãêî9§¥ˆs›+ŸØq ×bz]œuq&½è§Ïdñ±­IÉ B»4Dì[¢k_r·±[Úi`ÈÏs‘ìÙW޵¡·-Ôúêê9ÜùX~Vƒê¶NrŠzç}¼2 ²Q¶Xð‡÷ì£K‚ Û„úƒM§Ús*æòdÁʵܽ¶ûÙn›$½ŽrùEè 61Èè=«ö•`“ϰԆÍʇ²3;péµ[TJÍgÁ½•¡ŒÛÊf«ÔåjÓn{Á¦}Û¦1v¨}š£ï7=üh 2 8N·Ï¸’aÖ&.±ØSöæ–³ˆƒìÜ ˜!<࣠=ܰo7Çî‚ízssdlͱùÕðcóÒ¨Ôjר]ÕÆfߨ76/ŒÍs£òÖðoŒjdT·ŒÍØØlÕM£Ö36#csÓ¨|56ëÆfÍØ¬µ®á¿1*ÏZÇ826}cÓ3‚ªÉh4L½BÁ›“ÍþÚܨ1ã¡ù ÿ6äôÈE'uéÑîJG»îæÑ“;œ~ƒÏoøsýwb~ú\yâÑò3!‘Ècã¥×ÔYW¼ª#Wê Þ»’½ònÆ•·6QÙÛ3lSùNï\Cu“™ÏjvÕž6θºƒ_г Fªv˼åú0J:dÔtøqÃ^ÃúkO”·Ö|—:o'ÏÛÉòFxZ0A•,<‚¢Rç}ó:¼Hìm<„Õ½A5Ôß«‘t­ºÅ¿°ñØ^4³Ú¨‹‰”z’UoÛkÈ“¿¨§Ê¶ßØÀ½<®‚½£Þ†íé?h•1#û̳ƭ_oÜV&,»ªU"ÎI°9åBÒ9ØÍ¾æ;òð“ä3þ‘eVÓµã$¹oÆAVÇ…*ñ£…ü½…ö’σQ¡ƒf§õ`×l-1´¾Ã¿…ÏË›:ü·á{¸Ð_Àwø |ú ö]ü£ü¼0à1+¿™ÛDŽO*µQ/ì ò¾$Ùm4cwÚÄ||Çÿ$G”/9ËH2A‰Û⵬;@F7Ìì¢]Z<à£Ú`/Yb4n kæYÎ)û¡ê´kì¬#K¾ãôºs ²VŸ/e•“Ð…ŒØY{ÏÇ®ýa~ÕÛÂL7úOI4Ùª›ÔmqñànT>YYº:îZù=´ðòç>†…ẅT*™¡"Mßóy®úoÅþ»œ–‚ÝÓŸÿá—Czað”'0ÿÞfßìcgW¼‘ƒL?Ô‘I|©ÓA¹ÌF˜Þ7Þ;ÁNž(uÅ€+\Ù-þòlU‰/<ž9j‡–l®&Ø!#gìùè˜_g+ öÐ5iúפJ¯É8¾æêŽÉ$y^Ä«eÖ¶Àß~æ_aþãádå±Ñ%¸ö Æ!AÝú'ËôvLÖæ©óàW™8¨ F•U¸ÔØRz ©ÿôØ­|Î|wñ‹z©¼­Ï¾ÜQsTîmfLµMÞuægïy·¾ìt>®0?9F}§UÿÖÏÈx|ÛPpÜ(z¼› 5‚ÈÎÄýŒN›§–YÿàÔß;•ÀÙ¬:•§ò›SùäÔß9fÙ¬9õCgsË©NÕsꎿƒôêØ©ï;õ·Îf× b9%jÞ×ûùù–|´Í슩Gƒûµ•ÏK¾«BmçG¤+1ŒÚl´ul"esÀ®¦a;ìÀ£Ù *ꊈL’KŽr7PÖô1Ka@%Îju9¹O½¬|>°+ÎŒ4Ý"CQNþòIäZÝ:oÝs½U¹4Ûô`„sXõ4õÂRá¹¼müZtÂV3ÈpäEqÓg²…œ_6A“…n³KãW)ÐЀ—$M"ÍÚ¹¹À$½ÞÌNá;Gd­ãžÿÖtö]Ç{£Ç>ŸJ3½Ï&ß™`Ö‰ahÆ÷Öêoï¹õûú3SN º•¼„ùÔª«>°=¶î ŸÉ‚&_ˆÑ·qäï£Ý¼p!åZx!‘1…ø‚h_#e˜ën}Ïbi´—WX:”„¥ºÃ^Ív~BGxiˆÓϲ?pØ7M×y'R¶ëî’xëÞ4õ^¥Á{x„ë#¤¥ÌDnCˆYlòœàcC+ÞfÇ v¶†tTh¾TÿºQ×Å„ö÷.L¬ÌáĬ¿vꯜúK§¾ëÔŸ;õ_Í%+ƒÅ{™<ÓÔ_û×mG‘£|5a$<§Ðã\Œê|”½ß™1@—ˆN½Ï\ÐvŠ^ñ´mç££Ž‰Ò×]9:TøÎoDŒüýù_ÂÀ‡¦2 ˆ#b'ó0Pµ v&ªm4ÀµÕßÝê{,†8ª'þIcéÿh˜•ë×kÑõZði-º2ú5å <ú³ßøèT¿ÐŸà=ý©¼'ï³û‡ŽáMéÇıkœÄPð† 9è”§23@j~pv¤xSÎ%¦S¹j˜OÖŸ˜X'ü5š‡û6‘ÓšNâ¨úÈýIø´î¹ãÿ®‡§§ÛÖjúNWxsgß9 šÕñvã++q÷WW·~Í;Vô¦öréI†7=H>ËÙ•wìΡùåq…¾Dpeô·m<—CK'­SÓëö¶¹j6Ìmøô&nå]ššõ9½˜á¶œ¡öiÊOójöQÉþ6ýWæÒn2L`E½ÐxTÒõ¥iFûöœûQþ•Ñ?Ý^Yyðú¿;fh–ÏË&Nî (”*ú†žC³éµ±QÊŒµFMï3ÜÅ0'“žß”3ŒüªççX7ë×삷¬T/¨:Àï}!q`óï{!Á—×2ôc¹“Ç(¶’5„ë¡=]µƒa—&½cþMìKÛ×]úZ¶¬¯!—³·%šIõPAÐ`¡ø%kÿoèM™›ÀíG.è×dõ…b‘’ˆâý×vα™qUn`3ƒ*Z·ZÐßíÁ¶¹ŒÕþêêb•ádz¿+ϼÝIã8ˆ¶[:¦Ë~ì…ºn¥Ë(à6ê3ÒCÑeˆ'^‘F B?¥b1,:W“î•6hIþ÷ø¬<¶ÈÊžaÙ·,Éd|ÑyÑÇ™ß |Ï_`7û=¯Fxm·žlû¿õÄ2£Ø:¦ÝÀ«ªÕ/vÇ­}°ŽLÏA*žxUñîW<'<Þq+¿R­íµ(2é[ý‡ªòXÙZ«~X‹6aVU~´PŶ¨îQ͈ªFT1ª‡ þ¿‡¤Üok[¿¯m}!­RŸf‰[ŸÑ†w.®¼GeGgÛùcÙt H´’ÜÊ•‚lÈiH¢?Qk©Â;`µ5j¡>`eù^qUÎL¿šN‹JÉ­4Ú5”êã º˜24dž·ú Ù\'ÕWDz:¯…{óP}ÇfÙ ¶ÊvÝú¥ÕÁY‰%ÕcS¿„Â{0`p×Ôg˜KT›66-CŠÖ~“œ ÌÖ±î,e3«oL û¼M6;nuztND1—ЃÆq2ZÓ(”|¶àKH7Ð4Ö›+¶C¡·-|\,ô ïvUöH—zäðOžmØdx ww°èÊhæ½â®Å#„ŒÎGú¼õŽùJÁ–µûv$ uj§kÁË 1zŸ!Í>[û Ý]ê=×ÔÃå ot‘7(òÆêŽ=ºuhíô­wôÓÖÛ‚ÿ®$‘P$[;õ‹†šRPK2«(pC“g»ªJ²™–œ‚¬´öÛ’‹˜ªsëÍÚÙƒþaȧÆÁð4Zº| 7òV€³ú‡Û‘»µÇ–6áÊ?\]ÝÇ$Õ¿ ™‘q8‰~°&hï‡m"rG]©Â‚–oߨ×)°çöyûÔ2Ëû|’‡ºµO¶ÍHIÄy#R¶0Ÿ ¾²aØFžØsÊsJû¬=‰òëÝðï‚©Õà›¡Ì†G¬œ]Äçlënu—Oå²)|Î×»dž¤úž>ó©Y¦VHó<«ªo{¤Yšª’%¹\»:œ&ÔóSÂÍH®ýÁcÀ·M.¤(öâ@õâ@õâ€z¡çÌ/Ôò¬Õ]Õ‡"ø0ÀµWß”¹¯?”u«ìA¾ Am°´mÜo·™­95¢dþP Ã/ £ßÅE@¢z‹§c|ôøÞ¸ØTÁi“Wy¿—h'½¤ /ÌpgxñP†Feؽ—áf¹‰ƒ3šX^ÔY"á§…ãÃ[ô«s‰MzÙ['uV·äóåÖ…Ô {·ÍwÔý FÝ¿sûÜïÉ ä ÎÄñ^…Ëès*µ°Þü`M0¿¢ü×ÖÎ(,M8^¥©~?Ä~»÷Šê푸çÅ<ðãDnUHÓ‰\„`ßöÀKìÒsƒ Ï”)^±!)ì@MY*Õ Ô¯2=þÊ»ôên¾dÔß´*5Gm®ûÃÔ;L½¹8ƶãCsÛ{•³E#:³¾Ê‘}ˆi¹‰‚`·Êkg¡Í®ÁÝòŽrYîû§u¶í0v½™uÀ÷3¼²”@ºV>KŽ¶Ù‡Ï¢“¨=À¤ì7ê|¥æ~ÂÑ« oœ²Фº,y[WuÚOüvSgôÛ” 7šÉ…¤?P7ÖBs{Íkxö“.UÓnÆn@í´.53B¿Gât'‹ñp¬®å+8jìAëéÛGH®b… ~&¦¿‰yæXr3º¡‡/ËÛ‘C"Qq}<¿NÍÞQkß„W~´å7Â…zÅ­+v[ØdÁãò·¢ ·±¤j|cÕòù¦ˆ;÷ᦇ-89&éžJ믄J’zõ‘Õw%7"¶Þh;¯!"}¡ÒÖŒžÍ®ëÏq€×ŸÃHðçêê‚m<Ã[|Ó­¾máåŒløÝ­W¨\õ;íop¸°yYã}]¹AlG/fïZÈnÛø«zÕäq¬Û:V?'ÎH¯µËÑ“ Yxï–’-kÍßr·¦Öä ~¿Ùë¾]Þp«ö“¨ÜÆFÖ6*›Ž¿™_C®vˆaNÈ´¦â&½ünã–™XŸSÇp…pe·‘‰Æªë±Õ/Cížà‚ѸÿÑâþ—ê7áÉÅ7À@h D¸Þ\<]]>[ÛšlOúŽC.‡q‚WjM®Ë û“¬7Ni3’‚c‰DV—7:”ÔB¯áÅÅé©rHƒ~v-Y˜Æým3YY p†œÊ©u¬ aÀÏ„*Ø`Æ ƒh΢-òÏ÷5¢lSc…G¯mËà][£áÛT÷!b¢‡z@>ªí#œaÌkØ(Ú‰åT#ð*iògïfuÈÇ $#ÔEN<¾ ('¤]¤Š¹54±ßéž8;ÌŒ¨³Õݪ´él@ÑÆò,TÛü4^gÏ„çeЋ«)‚Až&g­TUÛðƒ$£:[}¶wWª|ÙKx œ\Úß{›¼ù/ÌÊú} š÷ª\™©J\V4V—¹\WzPH§\Í,‘ Z°CÙ¤jG£vr†Ii[Ʀ²/ˆ¼Špȧ*fkÀV“±3ZWŒ¯x-©ÞcÏ ŠçVßm›UØFõÀ´Ï°pH‚gÃñUÔ·@ÙÂ$e°†gû ª´úP«JXC8·Õ·Û­AcëÒÙê7ê±S¯4¶Î™Ò·¾ºÿ5¢¾ù1ìöô¡SHì¨Dï¦p,7bTà"Ãü¹ìU^æS+bÊãS™ŒüƒE6YñûÙM‡Ô¯c\À·¾:Á7"ĉycP4Ë Ü|+Qxâx ^Ç{O¿þ§ú1T‡6q^s ­oE²#‚ƒë8–âGNÐ ‰-ˆ)‚ fŠ rŸ¸õÙ¡ÆVÒbÜÙ)Ë©Tï=Ï@cp'±úz¼üµ£¿vl.¿&éµ¶£Ÿ"8«Ñ—·ú›C>óA_/±‘è%HÅßÏ|®ì]ÿcfmm¦ÝôÂV·Ñwÿ’$&ººRýhûÏQr'€ûÊ9½»fSwš„¯õ?¼ÎRÛ•¨á%MÂ"½{É‚áÉ8®&\AîÔ« ð­#¼ÄµþÇV-õNÜ'ºªs\‚áeÛèq8Âߎî‚ä>Ÿˆ9ÜÅQ Ü3BCŪ’N±¸ßœ[•(ƒ½zmB1è:ô—õE£·œé'Æ[ÐÁÇGÉö(ÅÁ·ðÖ;nxÇŽ·ƒM®×1i䬰cÖ>á23'{ýÈw›a)¶ÎŒLÒrHü7P§‰›Ä!xŸéÓÅ{Fð­à6l4´’QŒÏÏwŸóp ldw94@0Jè©Ò —IÓæ Ÿˆš}o,mÎÜô)ÇñZèWɈ;-mUNK’¶“¥E/‘VaVFZ›ÒjuÚNžö i AR-B{R#ç_H‰‡³~ñu¿`3>!hÝa,\„ig§XOKÁµƒ«­¶°Á,W&MŸ@o?-UãÓ宾:-éMt ÝÓRåæ´Tn7ó›de–1º‡õ,¾P[¸uœ|' Cê^ÛÝò­•þvÔP»å1á»ðÚ!ýۨ˅þvCŸ›§Òê”{¥ÖêoJ÷NK úyC°Áöª{êŒ|v<^Œ‡+ý#'öUwúÛ¸µ¯Á×õUzx­áú‹Zß”òyüvv@«ÍgªÈ")3yùv¾Nñ¥ÒƒŠnm¨¢êUWV·÷uøö¾bJ¥§’¬h[RkÇ…6ðBm46xª‘’SóZmË)¥òá¶Ò¿ÿ×ï¥:XH*!=ÒïÑ4•ÈŽ)‚夈,˜" bŠ™)bÉ¥v*í§©(•"ZŠPl)‡K9˜xšŽÆÝø0Æ)Nf)bÀô„2MÛÓñUOÓñÍ'œõMôFi·ŸL¸ØlzÎÕ'é|:H¯ú£îø*EìÈ4˜FÝn:LúqÚI’”²Ä×G½1 âq/íDV|=‹GÝT¢ÙP¶TEP1Œ®ÓhÔ§ÅDÀ.•ÔˆçÜó$êEÓ>å#¨9Ffš"2e*5³t)ý#‚·>ˆë$ð&u5îô °î|1F ÞÎxr“rDQ…Gb®«Q<ÝÕL*Á…ÓQ &švé{|wÐÎW"5ŠÀ—e¸ž÷Û`ìq̨·ç Ál8 þðæ#Bø5% XZúêÅ ùãjSît2NR„Ïgi7fb¢„FÁäšZ'ée2åÌ}îK”ÜŒ:ÄÂ<ˆv%¢WJ4šöDú°FFdý6©³B@aE|L&àëþˆF×ìWŽ#›Žï’mƒº×¿Fãcôr0ŽhøN§ã©Pù±>Ó!5Ù©¸”Òg±æâ)¸l7L1 þD5ÑP†C Mã„ '©Ž’”r`䔃˜bÀ&T®C¿?ì=''|P‰h(b#aiBˆï¯Ù/Qß~?%g' ­ç4SŽRGEíx@]!ñ×™'³ñ )Г_oNÓµc¢(}Ÿ¼#A ‘$yÐDé‚ãá„2‰M‚y‡ÄgŸäÆQõõÉÁ>jØ»¸HUÝ1»4—ÎÜ=•Àh,üI “ìþ.¬8¡—N<™1q‰½…º}baðP§ºB9S$Ä#’w»ò{ÿFâh½oÒ¯ñ s •ÿüšs÷˜iЧNÿ–²Ä†¶Ì£çB5΢>FëÖvµÖ!¤‰TÉQÌ*M ðÊ‘°d2o©Â¦QE›³8b²( ”ÆyÂ$ŠÇ$¬\µ“ñ@Ú€E@Õ‚µ‹$´$ ‚‚íµVƒ®ŒöÎl: Dœ2l>@s ¿`!xÞê)æbA6Iz'î&©ÑŒÚÓtuûã4¹â1{iƳý^öRË ç‹… SC°ÈS‚ˆ=eiOð+ E¢â8žÍ¨¤ Ù~½¡Áß§1 ƒAT`’)‚ÓùH ˜ešpý2âA·{tðƒIüI‚Ð É™õ!)¢A+ŽSš¾;:>!î–þëx,¥¿¤#ª‡´ng0O0–ºÄ– ºBU&‰ðÔ²(N®Ø@PÌÀÙ0‹²Â1ó Ç`'Ã&RÊ-Õ1J1 Ix‘BJùǘ wEÛ¤i¼*èšc²ÓïdJú•F.#–ǽÝtËHÒ™”ý±ßk1§Ð¢Â£ü'cÎÄŠó(•¹ ò±ÈA±FÕ"­åø.Jï1‰y¼PWÄü +̃ iÝ០ø¿Ä¢Þ!VÈ®'›^Åí¯4!›E¦0G§*Û+þ–zàg1Ž?÷©õ`£‚¦>}Š“‹(ÝgåFŽsù\”µLHd8V¦'TË4“¹õq¦p̆ù„­–’ôì‚fPççÓ1iÒ.¯©:%÷ÓÆ¿iñÂxDÀEj» “ t‘Âæ ƆŠ$Íh$pE,hb¨çÌ£P•¢ׄ·¯j̈ü zƒg‘ ¿=Ϭudƒ.l#ÇS2Vû?”yLr¨qF™Xj¤Öm¤ÔGçJÔÏ•eÃHŒ‰&é‘=K¦ü€g%„®J–†p*ék²0ŽE¶ÀÃë ’ž°’£Q'ü:o‹nǤOኪìÆÂÌwX4'[t6Ä&G«Ži2´¾¨ßß´uÀä΂ ³ä—Za×ôGÑ@™"ÝÔX¡.ÃLˆ¯TÖ<4´‚ï.`úAFôÚNQõH/x–Óæ®$€2D¡Á1æÆ@pwÜŽ#2˜¨Äªïc‚¸/ë ô¤V`è­–ET/=Èœ¥°AÓ ê£G3(ÌÈ^òô&@ F™Þí%ÙÍfßÄebwР¿d®}‡0à4èÜs k}ïÓÄ€*îKPÇñ³7Ât¯,.ùùãD~w1JÉŠ×ÆI,MƒÔóý =Œ¹’#²í‘ÍzÈ„%`ÑR•UžæëYX’ß1g“éNSd¶Ay“²¨V‘¾*¹HÃ$}up ˜‘©·UßHßPꆗž\ÌÓã>£t¯—²¼ÓŠ ²öää‰àô OtOÆPý4¿ñŒÍa%§ÆbÊvÀ}Zü’È&‘CÄšõÆdâò\…Ý€ôþ¤z¡¢1Y§ƒH4¹ô’”9ÙÞ],ùÈD‘Ê]]¥¬Æ/¦Ú‚h$Á€I3ÊoŽñ«4ªp'›,ýá9O(™/ÙLQó ¶ŒÕsÔ¦©P&¦Ó Myý¢äò¢ŠUJK¶³;'즎¸,‘·uÄåŠ÷@ÄåZ£Z/D\þç?¿GSc— ¡~HSãÖ(%Ê®+5ŒÛ…c”Úñqàxš%Öhr¯ß`b~3MDræÀÈ„ޱLíô1é%š$0I‰£ßã¨Î‚&#kÃH.ÆóA— žÑÄ]‘¼«»øBäÁ¬WµÜ‡&ÖÆêjžaiÝà/Ú_útgÑléÛ²Á›÷y‡ Aƒ´¾1Ïa1ÒÌ¤Ð·ÙØˆ PÛP| £Hÿše!î2Xç¬eS#bi‘ÅØDUÅŠLjG4 ÍP¡šÂ£ñh-žm|ÜKÜ;í˜b ×بO&ôF”=¾ã«¤Ô_0*ð@ÿî–Êž˜¡¡×w Ë6nUÃp]W=ë F@ªRŽ®-•JŸs¸ûz·Ë¨%X€ À­‚‡³drïdŒšhÚ‘Ô:f4¶y®±KyKT1L'à“Ðhì¼Þy½¾ófç7…˜þñÔÉ¡85$c–žÅ<»4ÇšÛRØ S‚ÀŽG¨Kf<ŽÑ#Ë-R;ÑH“Ý¢Q  Ed£Ïl3e¬†Š–X ¸@³ªÅû<¦' CìÈ:L“«BF‘pkYó¨9%ó)™u>&ƒC¹  éO'f?'Û8ë‘kX»cô3AUlj®‹ÌiŸÇ½årÄܼÌh £ dDè⦌q§a®MüžLú³ ´HÖ Ã OóýVTã£qJFÄ|@ÒPCi+„ýÂ Š‚Æë™°éÎyŠØw½F] ¬p/†HË]\ª£<°ªÝ¢Œ»Ëìùб(<€4\ô]?‘øÖÍÐ`‚„µîÊM)j¤:^\ÇÒt,­ãê.“qäb‡Åº;ª]•Á|ŸÁÖäÄÿ.þYP/X‡jÁÜ€’&ÁÆ£nB@¯q?Ä3j‚ËeKˆâµw(VÄÈèÒU {¤"h=eÂÒGRv«¤¸J«ÑpÒ,‘.3ùíÛ|<ã×§ü:—gürN/,«< õe=AGTå9ÒÞy|M­BÚgE¨Þó’™L]U‰Å%]g++u¦°k2oB¡f×'Óh”`>¤p™É{d0Íñ€ñ †šNÓÒâ8Ž—ø–—}ŸdŸ…»–­ï2™œôæSÊC¤ãéRâ.&‚G$Mf5Á#ê~1:ô“ ýpëθ…zȬJ²!©´A§PÅRƒ:Û‰ˆ !%ue- UÒ—]²íbUUn šŠ@„`ÃDY)J®ºkÀxdP;㩘Ø,¼yµKi³_£D UìH¸D!‘Zq”…D! ℬWèûQwÉfV·¡ôãš±¢M©†!S/d…2Ìrü’çºdT<ªB™LȇUðó½ ¸(Ô(Cƒöx¨vâ‹ñªÇTeMVgl¯‰XÐÏ* Ô²Vé\U*TU²Ž_„¥¥–BOFþ®â‰%!0»3öæ ~$ä^ƳŽ‹ÍT2©»†ZŸÍ˜YWZ˜bÔºzôñ÷à‡ýžé±.ã÷ñ|2fU;9” 'XÖ¾ÙV³!‹RŠÖjx ¹@&z§+#8ˆA©Ó}te‰ÁÚ°óÏ"ü«A]gé¤Kc£ôK©‘¥\u‹j:Ë»–“Óʾ*†¼µÛ,6öŽ,Œ5¬¢ÍÏ/î4¶²ÔØý¢/ò!Qd»;µü\¨EY¾Ó‡ØÏ1êÍ Ç÷d5ç»5,þZL¿$‚ä@’a6žX¦‘]3ÌÄèÉ’)™šäÌ a2̧ŠáYNufƒ×àiv†Ý"=x‘Ìé›eÖɉ6Ȧ™É¤ƒ¬ÅhÀFöZ>¦ j¦?ûuHñð§€üŸéÆR.,€+…9EYE½Ö^^¤`m0\*³–k¼Ä`±dL†xY¥å¯.è°¥ŒB]cX±{î²ÉmzÊ:'&Æ÷Œ° ¼È'ÓVZdwÌXG¡_¤OÊLÏ`Ì¢îŸàðÑÞÉçÿ oª„#5>Ð3×ø¸ŸØVŠÈ99VU#Ãü¥@±óÿk÷ÿ´»aŽgj-èf<'ÑÀ,ŽËŽoz-±»&“«™š ŒÔÂOLjæ³ñ+Â$Ëndø{æÅÎß"—ÞIKó0æè|Ä«ARPÄÐÎx£büƒ¥5ž6°Š(IKg<{›Ë|ÔÝnL,4ìDnò>·f(Õ€äªúåû]“C2BµlÆö_}µ–±†aYw Ϧj6è£GjMÙ/ªíÐØÐ–…Òq™nɱÃXÑ3¸ð-×à=VÃV—ÊKþ"¤­RYá£\:c¼.÷Cô±¸>=øéáÆ3õ®sÓ„í¡íûóÝWØ.ŽfBJí¼Ì'EUéµW‘rZ»íð"/¢'š—QÁx>›ÌgÆpN2çS:6ª–µ6I¾™_Gà£Â Wƃ}ŠÝ”Ò^Í £ ÖåI6̤ź„ýÔ®—ªn¥NU`ìRÑïPâõ‡4ú”zf@ ì90ÑïÜ©zÉôÐý&ÆdÐ'ƒ˜õ(QeÚ¿ YÀÉ2r¢1Á& UûgAÖX¼áèÚÿÒæã¬wl @˜kP8>èAx§3Yø+j®lAs§Ûe':"mnÒçÔXÍmïUú€”"¥…ý—‡ |‰+b±“-+ÕÀÁ¦4x›pÆ+–00æëçå³*n¥ ñð Ã4›{ôé»çh!×:kRÊÓ¼¯®l¡Qj¹l¬ GF+ËÆ‘õÄHA«E MŸA~SÝÌM¾Û.;ÃZ™À( ÆwØ¢>cwÆÐûb¹MñgAÖÓ}67lÎ-èqx±$3FØJ(‰/n‰d#†U D*ñ .6äaœ$jE%C,{ƒ¼IÆ£¥qA0ò«›m [DäJh”nK6¦¢gh•ì;ÂôÖ åB¹ÿUÔ!¹ÎœÕÈå^éã(Û'“ŽP£‹;ëMp±JV‰4>—/%»YZFùËiÿˆ‹ÂÀg¯!î¾4N ’Pýá|¨’l6%ÙP.§¨f>ÅXަ7Æ|rM»‰![À0Ë®.â‰"<î)8êOæb&˪œ¡‘ýþû»ºûóQ1Ÿ•-vûß‹;NKJV‰¾ÊÞO=Ún'I,!‚ö¤m%í4VrøËl<¡Äɵz‡»öRû(SŠ—¥–ÔJ ˆ,IC%I.Ù Õã©Uêw¡¨¤/k:ƒ@¨ËŠO¼D¶ ²ÄŸ¬ˆÌe4=€Njæ_wZwʼnÀZníópÈŽF· ÿnw8îþ9¯¦40æÓÁû¯ r{ÎÛ[i³>ñ`,3dÙý3ۨżvd¼{ýÎ^âûî¾K c²âPs}é=Ðgü%Ù£ß\8Õñâ:f6¡q¿J®ÆÎì†õŸý—ëçDŒu!€qT¯«ÎX¥íoa‰ð›Z\wƒŠõÔ¸žŸýª_+-5d‚â‡SúŸ4O/ï ÏWjVVÜÙE•2Öâµ·Úö°§e+âMíhäLŽ;èt7«œ}DPØ­µ´´«šå+®‹¤Gö=_YÇοW™Y5F? ‡¥Vc²">‘²nw.n³Y&jTºÉ#À„ìŠHA<|¢}±qœu?+~8¾2Â|8¼)“tIôeM"!ÆÕþ@RûRCI<{1ê¾CN«ô®5ô‡FµÀ½ÜÚ!‰ÔÙ"ØÉâUÂ4+¥¬¹ÄÍp _CÝ÷Qéƒ5—Bbއ2ÜrHTÑÅÝ5Õ*±q׺ñŠ}·ýÁ@­²«U §ðýz–mî>¾õúTÂöÄ#î(¤¿•sžUºLDµPÕô¬vÖ»%²ïÇ_û1}ÈíN!–.¢äÏË$ôš4™]„ë%UAÁƒ%÷äX‚ &êÞX÷öÞ¾f‹\°j Ÿd6·vR¢ûÜÈÇ^-&\ØÈVÎÑ^˜’Äà õ‰×¢õž±ÞVÎV³ú#^mŽ ÌÀ±0È"QÕXÜŸ4òÍ'µ¶& nXù.µíªrzª–’ÌXSââȪ²¯ÓßHö­3Þ+=‡ÏJù¢Zaß…3“ÑýtY²¥‡Ì#ŒW‰”?˜áT_ߨZ÷|ÃÛlø[À_r»çºÃ^Ê"`E. ÅŒ“w––ܤ€pS6 ù4‚!'å„…šy‘ìxa¯R±QUUc4žY“{¥Øl÷Fa8üe~Íì/xŸïCÁGh܉/ã†f©Ìk-n¿«æ_V•Q2Ï Ûàê4Ö¦ó82ñéHiLSkS¨åyëÞ–áù ¯ÚðjM-®EÙ,E»lÉ[„úÆÛ‹œ¹AC…¦Ò¡kD=[p]¨ªˆcG»˜ØK^!…Üʶ¼ÿáA¾QD3b 37·LCŸgÅ4<æÅyÒ18¤+³n%μ–¸9¥š©Ÿ³®¢œÎ @ ¹ÅýUËl‚€{Ǭ w¾f«>¨_û å&†"1ZÑ %jgKü'õ2-'<ÈÚD¾cÈA®CÏ4õFZ(ž˜ÀÌÎ`P*NÐ æ)cE¯’s;%ÛÑåi>²TpWñÚ£EÅ,rzíX·¿¼ÉN_4ú€î"=€y1˜osB3³þŒàpxÍ"¦™Â†›wÈhÜI$è²íZšš(¡Ô²äÔT4~ÙgŠ Œ§³‹gŠ­Ø.ï‰ÃT•­YÄ@½\H÷NI®%ä=V.ñàȧŒš,4uiSš MŒËµ:îö˜ÄŽ`äåõ’¢ ú“$¹rZØvû$ï§`{NöÇãI¶ \ì& 4ö£” cª¨£V/ ,•U,9\Uw^Ï£\ptEØuò²c€¬ÒA„ŒábÅ®ìz3AÛŽ:\ê‡é¹Ì•êQbÚྒÝZuÛ(iÕS"Þ,ÎO”Œ3«¤Á)eLºÈž¨yœ‰”±õfÜc  ¼3D­‡PV4©íŒùa.ÁÊ+Ö.tÆH( U´Uø‰Waù»°ÆØÏÕº ;šv.”»UaÒP0dņ¤W&¹ „-á¦u‡H^î¡ ñcã @Ö»"nk¤9KŠ JÁP޽¡³ñØ1Æàì+2¯02tKïS« Õ¢Kˆq•'Û®ÜÊa•Ú†´UV»À™÷í %my‰™ÓRÛ¤5œ™Ñš‚¥Gí<&ÛÒŽÑt<ÄžRæ™í÷ó¾â.÷€ô¸}ïà¥áÿÄá:(«7ŽcmXq‰¿¸dÎðùbã2do4äï\À#¿p±FI‹Å“iÄǶ ›ªð´áLŽ©²A·´ý…–[€›_MNêË{AòÜí$wÄM¾G²‰ûCûºç£³ïê«h0þ¼|à飾w™ú¿/c…-î Ø>IRm’ýgêî§{F‡cô·ÿÚ€Ë0CÖ¨YG4ªµ0› Kªk,€ÀŒã‰>ŒdŒ¾Ù¸hŠ<àð·Èä·Ã@2Fè(ÂÙ_‘r $0¥/Õ©­›/´Ö³lŽ=Pwª‡xIŽÅ½>=9#šMôk®/³ýÍuoc}ƒƒF°Ñœ?rr±À®:¤{®VXÍ¿_ìh$Åì0,ér¥;«Ad· ®Ïe%ÿãsYÞ )Ì’ã#¥t²ƒŒ½FÝ5ÞÉF"|X€Lç£QÁÛWÑB]åâö&¨>}cÌÝïÊsØ1<š?>5êÿî$’U nèªÉ .›!ªWÙFÿ§šU°ý•ÌÈÖ¸YSkzŸW,LÕS5U¿»3ÇÐ=,RÎâÀíoD’£?Kò ušJØìÇ…ýW* 3ÕÁ´x­Ã-ÞùßÝüž,ÛÅñ^š *Ô$HuTª6Ÿ=]篘 II«¸­º´±Êw©-Òâ¾ê²Ø¸ s᣷2)…bŽ\ëÏà“­,œÌF^žè/[¤Š”¥»ÍpÍn¶8€ßlS‡æ§8¡«ýgK¡¬ã™ ÅLF‚äp ±Ës­®Ð¬ Ò2úAÝ—·JÙ–ZÄá ÔĈLÒ8XÓ_É©æl>Ñ-_C£TÔµ42 }aÍž_öš6ó²Q=,N'ŽIW/•g§†Œ¸7 Ûœ~l Ý7•¯pxÊŶ÷Ò×fÁd.ÔMj9Ë÷Ržb–fžá‚ÙE±íÊÍÄëÄÆÆšQÉ \üMøªßW–¥¡rºrù‰‚iØFaú¯TÐ,Æë$ p@^Ü­1™¤ÌÕÏcÖ¼üQrt3ÙÔ6K¿«ëyÏ»¨mùUÆ×-PyõnüMeG%ŸG«Cl8y®]Å÷^Ôó9<¨U¨˜Ø¢¥bÛÆc-“”5͈“<åÉ•¼ýEö”ÉÀN'¯û©?‘ðNîQ‹½½7s‘¡Cªÿ§K£€/ÁP& ;ëMÆj+ 8ËCL‰óLûÿÍHÁ9ôÇÆÉ~Æ<þä4;Uùè–›Ý×÷X•ôÉ&V- –Bý„ï‡C º±gÆ”·~}š8U”Ô5bl¶Ê-‡%-ÿÎoÅ gM#¤¼4î˜øNƒ ŠEAAð,Kî´J´Y¹’»YéÛpUª…•tí™õïèa›Ë4¢°ÐµaŸ•x|;ùß«c±¤¿37<ôûqƒÿþ´ÂÈ °äQ35·l²ä{Ëø_¤ `3¬Ï¾«¸VogÈA8ª‰áST™7"—odz+¬£EÝËy2»33GŽÎÜú×,© È/‡|°w|ÁHé/0¢—o;qA9gn?â<¬þ±Ñ½d†lä#íÌÞY—þór?®sÔÔXÆ*åw ¿º¡ RäGÁ¶%?jËóÿÿßÿåÿÄ ³¶Nê2NÖ•oÇ:.ZLÖ/“õ ¨FA-èEžqÇëu‚j;¨Õ¢JäuÛ‘ï^&ß.TªÕ*ü»Qñ–½ æÕêÿð<¯ZÛðüÊ¥Óßê?Œÿùîÿãsx°Æ?®®®Ö0y,ßß}ÿ?ôŸ^™’K2³E)ÿÛˆ‚ÍF°UX”2௠µè€Œjd(ÆWÆgÌôò+l”ËþóñäF|L¬ŽÍµoÆ#žÉœ–‚¡3ò©³Ý9ÙɸÖo„…OÜý-ÖÁÞ‰aÑŸµý½ç/_¸³ë€õêݾaÑŸ¥º–ì*.Pk0kÕ5¿bx•†ï7¼º±¶A¼gXÇÑŒeÅ8ˆn8×ÿ!þÞ0ªµÍ*û<±7}¦"'«ä|ubgj߯a~è̾McužFÛ¥R#¶²uªÎzdÛvÙ²:aççÈ~T·åâ «^ÏÕõ¼V§ìoÙŽ«¯¯´‚šm/šýžµR*åŽÃ¬;òݶoùq«³¶fO[ôkŸ…_ùj{<7¿†­ÂfŸÏ Œg‹³ftý©„@¼¥E³z‹f^3µJíI8É€(\–A¥Ú¥2,ó£ƒ+3.ÑTMNVIð¹B¸ÛÊ ÂÓOÍ7Æ®$ñk˜…øãÐlˆ‰uÉ)ˆL?×ÿhýñôì‰õT…/?³[<;{òSúÇ¿,@oÿ´îÔ|Êç¶þhüëô´uzêÒçuÇóùª}u©„·ÕK‰(nßvÀèÑî]¯fßrø€n³î¾ =Žöõ Q̺ÅLâÌp¸Ë-^¶åºÝ Ä$ܵqaµðr&ÁÌzáØ­y”!à ¥!rýï+!'!¦‡´ïÚ:¾B7l-‡^ÛêÇÍ–(Y6—9¶[³¥¾múu³aVóL*©»µ/Çë"â}õªaò¸5ÍW ÍþíÂyÛØp8È;‡ˆ?t›‹ÕV!:[8þ¢d鸒m„G«ŽÂ:â7,œšŠEŒm4ý ¡×õ&ŠQ¼-œwÅÀïTŒ7©Ÿ×»lS³ûÇ*«^m#”F£íÔ/ém×Ag:À=‡«ÖÄ-Ð}EEVWw[mÄä}Kˆà°5P Þ.š] ¡cªõ®ƒB]‰„€–ŸuÞôÚ'8QÀi;}IȹŽÀøÊ²ÚˆŒá_œ–8ëiÉûý´d¯®êötÃŽúM¡bÔó#IJ÷¦Òiæ«6‚°l™Ô㻫ò‚ø ønYÒŽ×áÿ µÝêKļo[¦É*î‚ã˜2VÝ`æƒ5nÚQ9Tq³&‘4½©ÕªŸ¡;¶P°úCCÄq9ˆÂŽj–Ú¼8[òÅõY®:‡q½k‰ rÍU1äuEôÍ/š§Šq6ÝÚ{ª±úNØØüð`¦ì{ð=cÕà³åm9Î{'‹ƒæÕ°Ž¨Ú’½öò^öƒ²o7Ö;—yq§Ì{ÝeéªÌœ³úí^΃{9]ÿµ@>È2WGiº‹h„4”¾i–ï üÑÀª;ªÿ»áÆS¯¿g­·þ(?;3ø/G£lÛÄjž×uMûÙšGµ2%ÁÛè5úУñöB0®pšE;Üuƒç‚}§Ï± Ï Ž^œc@pV¾èáÑÎENÍzØYµRñ‡š‡F;ÌjàñÚvßÒoµ~qÔ<“¢êj" ^XÂ*Ñ6KÀ:ɹ§úJØf¡çc„›"’S¾ñËv$Ê&‰¢à´´ ÕÑБ%~ðR•^Y‰¸×çÌÏîÛg §~’Wà­®YFÙZœu™%+Sè­p-$sûBÙôwL["©vÜZÅ©¤´ÄQt½ªã¢_ÉöwÖüOë“\Ü3>ªð}þ§í˜”ßã§²×ðªæ÷ÔïqD?õ"ϱvö?#ÄhÎÍ]7š¹þµ¶IuO”ãAS?Q íf-СˆT À»–µkN–@ͧ§Sjæ@ឿЮìÛí2áó´´¤4‹€ÛÌ–®®®WÒê>κ{d‡WÞ„–‘#J> 78èã>G¬–ðˆà°žã¡ ‰n¤_w-sëƒ *é€Éþçb¥ÑR¥ÞTìEï†i…T*uù…ü·Ë:žñ±ÍH©¼n|D8d­|ÀõvÎÕoô$ úVƒ-³Lbõ~Ù›%™¸#3 H²ˆÌhpg jé·<þXBšu² i˜CˆRâ¾¶Ú€-¢ú°,Ù#n‹?ÛÌÁôÐààØm1 „oÝêsBëù^6Wå:¦B“ó˜—+ùËí(ýë¯Ó'”"‰«ä!BÆoÍïÖê´Ï4ñDšjV í{ Ï Úl+ñçÏôùÜé9ˆ»Éñ2i¤zNp½Ä‹+Áµ}\‹¡y¥óݸ°ƒkwkLdâhe”ÒÃg.óNL[^‚khV^Û!¦YðÚ2}ß„ŒGxE’ÿ¨u’m‘ÉMvFpíh# Þm}C*ÖZ] 2vúPÙñ"`ѰJ%&§LŽb,Áa¿Š$>îPCµ DGƽ„ÝŽÇæk£vbõeBW`»_¬[/Bˆú®x÷Žwô¿Øû÷®¶•ä_Ÿ¿çUÍ,Ų@ò; ›„Ü!$rÙ†½—lË`â[,;@¿¯ý©OU·$sÉž9çwÖú=ë<™ÙXjõµººn]ÝÕDíÊ#ÐSã3„’¯àoåS 3ß³Cfßuàý+5o^Iýh¼Y"Bc Ä¥Q½-ÕÍÒžCŠÂ–ûÖ©\Ôl5%×ö ¥uZœßãü-¢yËUÁO=¿2i*(ÃKëm @èê­Ri°üh=ÔN-"¬T×àÔ†´Ê«W•Ùè@Xõ/A2»§ ûýK»¶ÐWëëþ%7G9TÛkþ%t”“ Ù"-IbQò[ja»}Ú¼YÚT¥+ÿ’9—ä÷/‰hv ”=§ÚöÍ"ÀæÔHpª3‰S{lü,mWIãii»±“x×IíiÒøQÚöþØ8å÷;Þ3X$hqc!KƒÕ@RYMÍðòqÂݯúŒJ÷ïÑÜ2*E:ès¤">ƒ08å/¢ˆ"&ªS=#ôÒt¼FS"x—«*µÝF$Iñ#O›m(‰0’§ÄÚª Ô_gì¹>I¶ YV$+? 6… W™ “†¯ãw÷$¨$« vê?[ù†x‘u©2oì”Ëm”‰>úÏ(v%Vš k£3Ì@kß©Šò§ÚÒIÌÖMH4<)¡ á@H0ê;C盬ÀO¤"~¢Q•Ÿ -XcBè#ý¨üÞ­Vh²Ž©Þ5Äœw«¾e–ŸsÌYă¼×&%ezI¤l mŒîVæ¶é™Íh©H­ÿr}K6LQ#>¹ÕÍþæ¦QÿjÔ?›òŠ˜·C×#e»2ØØö0¸ ú¶¾þ‰þßžÚQ€æ€Ü[Œcµ„Y˜­a0d¥Âjï”þ8µ¡X”~óhy!(‹P2Ö>ÆÊ¦Ã5‚Jß¶¡:Ñ ‡b'<ƒå?Çß0胄B¶h™SfbA¼ú{¶ÿÜ­ã)½irùÏ!!Ø7gôð Ònek; „Ö×ÏÚ¨‚UÓãmÜn¢ª[6¨5$áÖÏÒ¦Î8$ø±«Iù9㙡Òܰå²ïVÎ0ç V''%m¬Ô@ضfÃ>MÙ ôIÂçÌÃ6þ<9é-ÿ‹½­‚ÖF6Ø=¥nȸ  ÷vœZê¨Ué±¥~¹N¼ã{aÐüºá>ÓII½H3×j Ç ç„×Cçu£¹içb5&!äœØ>Ûÿü“‚MØ^wÎæ»óÔ|Ç‹vÈ–ÉùZÉžÖ8{Jã\57sXf Õc1n³­{Û>9ÙxÂ0ë³#%…òO+|›TúIýy¾L*GI}' Ÿ&åqþL&õÂVÛÛ&ñ…'78¦ì“­9}sz‚°Ž÷#8ÏÌB £k}¶<=P$Úžc>öwŒú%õ»~yRxB4ìñ†¿óÄ„9\ç¥yë?$~yJ¹Ã­ð{âûI8JÂoI8°7t~ïHòã7W#´ÊáKŽÇ¾¯ÚõŸ¤Y­´õ¾içúÒ#ŠFEËYQªMŠÓïjºPýùíæ$_ý»Í÷¬Ljš@ÿ½=5bOFÜÞtLz'*ïý „¸ )Œ½bÔöOaKUJ%›àNŸ«G9¡‘©‚î¨qêêÙãÍm*à‘|Ï?nyÞDÍ„A Â{òRÂ`°¹‹à ˾uñ„Öv©ta‹úvÖ¾ ýˆHá…ŠbÌO¢(áT ë.ÞYÃFÕ[Ö9DÚžÌ.}|´øÄöÖžØ8¸`8$œ‘”´‰PÔh¡É?q³êm#²R$³8§“„ZªÚß`ëéU} Ø2ö¿©Íƒ©Ô]Yw\ÖFýаaþgiÏv*›A—…`Çëk›S«DlAûÒîƒÅ*u!ó³QýTzÉ'F°écÖœ‹x"¬»µ >±ÈHôðE¯*›ø‹¦(é4À O5JÙõ©y`„e#ôN sc등ul¶zÔ »”9K!×së°#åÉ­ÃʈÌP=ûÜ*Z¢ÜàÞÄJ{.1Ó­#Ó‘(ñ›ÔÓ­ĨLÄ’n\«bg$T¨ŸŽo7å 0&âGlÃó›çª¾Ð=0ôÓÀƒ~ÿ<f<Ï,põþɉÕþÓ>}trboÀW´Ê0hA ©š­=âì$dÖû–wPÕ‰tÙl²CU ŸçŒáø3ضER¤Rª4@”›sõP*‡tÙ'v€n”¬vXúI·^ÝÈ$ l H§üMi’V˜ø^Ķdñ7eWtü^¶ÅÕ>Õê¯Ø„é}@°c£þGü­¼æço6lH¤t‘žøÔÐ[©D̼öÊ[6þž–ŠÅ’ ='dÛ©æÎ!¸thŽ­×$;þG½ '%Žÿ å( µv„fHÝ¡:Žô6RÛ?¤”àhÉýIs¤é²T™ L ë@ˆ™@ò&ýíþ.²"½Ëæ´Ó’5Bz!©‰ø ö[],jþ¸\*ݯ˛w¤›—Ÿ© ÁžÔ£è™´Ò]ÄZo-X ­.ö HZë Ö.7 û…X%{NÚí\=½Û½ e·a`ëyì¶©-štÊ­÷ +¶¡'.™£þ¶žº[;"ÄÁMõiÓúÁxé­íæÖu²u•l]&[?ì61õ¦qjÑoÏ=-ºË8Î:þ·æF½Ê”å‡íø/›þKýæõ›^_½9É}ªøÍŠŸûdmÅI½j«Øn®5mÛ6ë,3ßTƘº×\Sß`à¨oÒb¬ýa’м1?RÖ­11³­oôä½ '›×NÝÇŸ ýÙ:§,}ÓÙŠè·G¿úÝ2HB7µÏ9S )¼[õfºV9d b h«š¥—CJ'Vì¿â/ÞÝ/•!¾4þ¸]—”h|¹®òÎÒ«?Ø$HÌ º¨ÓøtûÓöG>d©líl›¤k»#h0C÷PmÁ0—[:lšÒíÕa;Ë6ÓÅξ±*É/ÔHaºÈû>¤€g |OŠåÓi|hš5šƒòý>§wJ¯~§ßšÐŽ)ÍwòÍKëÞVΦ|ÿ"Ý•H Òâ-PÝtã€Ù¶óŘšm±V‡¼‰ÐØOó½`3¾u/—ê{:õm–ÚÖ|"ÄšEØÐ笾šzØ´Xî"ÝÈÁ¦¶;Ã6Õ.¶±{‚33ügn #€Á]({¹«’jꘫŠlSO¤X§! ñ†qó1,5«`¸†Wh[Xm³ö ¤cž²øßbÒMéBôNo ˆ”ÓÙNÕØC×ë¶ÍêœxŸ–1}ÒN½%Æ’˜-OÎþ,Ëž/Ü”º·E}—¿’¡r Ž”•¢3¹ þ —A^l»©÷‘Ü·èî™ì™tlÙKò{ÕŽévØKCå•áW5— YO*ÏÄN!['Î>ѵM¶Q¼1žé˜9=WŸÚ¯¶M¢ D-I1zT•N“õϵ [Òo''%úóüN&§¶øOÊËüó ÒâG–Y|V4‹$_8µ7éGjýËÎgxehÿË=ÝVÑGEDk¯ˆXšÌvÎÑ´OSõÈ16t@mþk%[áÊôÀ ‚”¡i6o»ùLƒÇ£vù´´IKçÙJú^WÛFj Ô&Þ}Ê“fº#G¢ ê8ÔYáïÆ©3( DwsyÿísîÚ³•4êwyRª,Ì<±gãù#¶ÄÐ)Ëa>‹Psä«9žÐhÉ×ø™Ë·¶’/¥ý+|åJ-gÎ/ïëÜÈ-½Ô¸‚‡FhÃ9ÆVݹ¸@¢¤Z.T-°è­‰<`±þŒùTô± ñÂÌÒªgœF™Iÿx™+ ³ý/ã´lÀe³4” TÙÆeÖûòGšŒÙèð^y“½WÞaÌÞÿÌu¾eþ÷9u=’žÌ¤'K§z ÓªiÚ^š¶—¦MÓ´©N+k6h–?¤ù&i¾‰N«íè´ÚNšö3Mû©ÓüX§ùq)f°”€ýí®°Q9Jü¤vø±XB÷«­¬Å)^³K &›Œo šs]üæ¢\¹FœÃ¾gðæ8pÔf5¹Ž{´D°-_5ÛZ''mÛxôû6¤µËIkÆ#«½öè·?ÿ' Mƒ^N Û&—5ƒÔ›Ó ‡ 6í´i>æ6åC&ª?¤ÙÛí?-ØxøkE•iºÿ¢ê3tê”ÏxÀ]åçxsȰpÍZ_ׂLH¡²î0—DÎVHzÏs}6*OaLö,æØ˜ÛT=R²éXSâ§®ÿ#PÓSöñå2Ó`—èBûwúhžŠH+žÌÓ“‚ÓçÃçÕ` SF#¤oÊ#U˜ž6ÛÜDgY>×wØÆŸ&i‰e˜×b—ä‘ÙDÃ-öš¥·õu^"_YÇR>Ìòؤáé™9œ£üŠ•L®i#CuD4HÒ^ÈÆ[¦M·fº·/-<Þo°©ÓF:‘®/ËYÁ–jõ³%X¥mDÈæ$Œ0¼:nЉw®òõÄÖÒ#:ô+”{møâX#"j4ØFŒ|£"ým­Ú²p'@Š<ïr‹¼a7Ú××;$VÀÇÏf3ÆŒÍlº`Dê¾l&ô œ+Z=oÏvÝÚ•3J›ž¦M<ç—€Ô˜Y˜`Z+­q«–z6’U¯&ªÉèÂiå+æSÜå¶μ®f$ƒ!X3Û­|•ϼö*ÐÐòŸÛ¦­7¶Nm,Dæf¬m™KQ°r~a›-­¨ïL?ÔñŸl.SÆVÿó†t—0Èþ(a‡_“Dí¦Xð?Ä–øÚÏ$Ás@/?vÕSIX㔵\ÊŸœBe~ŠXE}øðiúIDæº.néQ`JÖÿ `ŒÍ*€ÞŸçöµlÂñ³eD¹‰(‡rõεÃ`ó¼`Ã*‘¶õÚ€ë)‘뫱mFÐŽIž¯4=ǯÁŒMj‘sN¢¼[ôÜEéÜaÉj‘@Øñöœ*D\öß?—9Þ ×’Ï¹Û˜Z›¶ðÇϰí5À!ª9+Zç¬j‹wè¹{`ßô!´]cwôA@÷|ºm¨3ßß +év2Þ”là¥ÝÇÈ[ð¾â 7Î@0–[’ãþé|j+-Ô÷öÒ"%{{Ê}…ç$̦'¤éÙÁôDéôDnmjã-H1 ž'ú2Æç±ÌÓJ{éíÇ-ÕR8íeÚ™\O€A¹RuHÂ9¢’lÛTS”¾ ”WþqçD"ú´FØNa+5ïú³ ¾Æ;hö & [›NÉ“ ûúâOHtŽcB|ŽÃ‹¬¶×qOmxBŸcóãݽ‹_¶X;À>…çíZ}ª'IŽmçs°ÖeOJþqË>uè3õN.7ÍsÇÓì;eŸ-³DìÞ¨‡Ê³&ÜNá/LåàÙ¸¿ä‚söÖä—ÚˆH¿Y?²NÀ[6}Ù÷$ÐÖ …!u÷“Bȇ¹€Í•Oì8Ðoó|ŸæuqžzáOŸIâcY“0’ B»´Dìš×äî`·´ÛĆŸç"Ú³§ko[¨õõõ3¸ò±0ü¬=Ô«›:Ñ)w|`(d£l¹äØG—Aº ð—NµïTF-åÉ•kC¸z÷³Ý*7ˆzdô‹ÀYn`‘Ñz VíkåŸa©Z•'¤gvàÒk·©”Òg½•‘¬Ûʈ´Urµµ›Ö^¹aßthÍ]jgtô½–‡Má1ŽÓí1¬d™uK,ö”}c¹å,â0=·döù(¦nØ7I³·d¹ÞlŒÆÈh Æ7ÃÆ…Q©ÕžQ»0ªÏÆÀØ3çFą̃¼5ük£Õ-£ŽQmµ¾ÑFè|3u£Q3£Ö3ü7Få™QëFÃ7žQ®š FÃÔ Þœl J%¸QCã!ý„[Üå}ŒÈ„'õèÑîÉ@{nc“擜}~ƒÏoøsýB~ú\yàÍåOFBš"ÿ?”^Sg]ñªŽ\©/xïIöÊ7¸WÞÚxDeoΰMå»M¼s Õ!2ŸÕì©=mœq…'t¿˜Ï*©Ú+²5Êõ!”tI¨éòã¦]‚ýµƒ'Ê[ë£:o7ËÛMó†xZr'ËU’ð¨•:ï›×áEboã‰zX ±Ñ[®ú{5”¡U·¸ÃÏm<¢oÏ[im4ÄXJ<ñº·í5åÉß.«§Ê¶ßÜ´mµw\Þ×;êÈ.¡þƒñW 3²ÏF…ö[!œÖË»f+/ùˆ Eý{÷·ýó²¦ÞýÇý»¿Ð/ú÷îÞþéƒ"Øwñ²óÂ|€Ç¬|1·i:>©Ôf=·+Èû’$·‘Æîtùø ŽÿIŽ)_r¦‘$‚.vÄkY€„nê2°óriþ€jƒ½d ѸJ¤‘g5§ì‡ªÓḆӬTøžÓëξÊZ}¶’UNBç2bgí»öGÙTo gX n i²Õ0iØââÁè|²ÒtuܵòG`á/ä¿41L¤Öm¤RÉIòÏsÕ¿äÇKèrR(ïžøü¿¼£îžòà%¤ñ?Øì›}èìŠ7ryê‡:2‰/uú" m„qàCóƒSÞiÂ¥®p+»Á_ÖQ•øÂãÉ‘£vhÉæjÊ;$$ãŒ=óë,EAº"NÿÊ@©Ò+ޝ¸ºCÉÅcžÍxµÌÚðÛ¯CüËé?NVÚé]ê×k°qPP·þÉ2½“¹y™Øyù©èÎ&ˆjƒÐc¥®4¶R£6! º•Ï©ï.^ب÷ñÊs½õÙ—;l­v•GÛ'©Öà]g~öÞ˜·ëKOçãêó“cÔwÚõã ~xJÂãÛ–tLJ‡¹T+ˆäLÜoÀà´Y=°ÌúG§þÁ©”FÕ©\;•/Nå“Sï˜E³~àÔß9-§ZvªžSßwü¤W'N}Ï©¿u=§É˜¨yw^ïçg[òá6£+T&÷ë(ÿž|W…ÚΉWbuXhëÚ4•è€==‡  iŒ´ "T4!™D—ån ¤éC¦*‚€ŠœÕêrrŸFY)óùÀž83’ºE‚¢œüå“ȵºu&Þºgz«º4Ëô@„3Hõ¤zÁTx&o›D¿–Ý  k Žl7ý÷&KÈÙe¤,ôZ=Z¸J–¼$I‰4kgæJz½•žÂ;sHZÇ <ÿ­éì5{Ž÷F¯}>•fzŸM¾3Á¬ÂÆ÷Ölï¹õÇÆSN º•c6a>öFêªlmx£'bÐä 16ŽüÛ­sT®"Ùá)ÏßBî©c¤Üçº[m15zWZ:”„¥ºÃ _Ñœ/íì„6ŽðÒ§Ÿ$à°o’lðN¤l'ÖݯDñ6¼Yâ½LÊtâ®–R¹ !b²É:ÁqS+ÞfÇ NjCº)WH_(WÿªÒКù„Î÷.L­ÔáĬ¿rê/ú §¾ëÔŸ9õ§æ ŠOŠO€âý”OHõÄ~°ì(t”¯# çÔzœ‹ƒP}ÌG@0ó˜ï÷¦CУI'Eïs3tÁÂçùc<ÔÛŽsì¨c¢ôuWŽå¾óMÆOþþì—}àCSi'#êÄNêa4¤:j›ìLTÛlk«¸Õ0†ì;j$þQsÓ©ÿlš•W¥ðªTþT /M§~EyÊýÙk;Õ¯ô§üþT>ˆ÷޳ûïÛщc×8ˆ¥àšr$Ð1(Oen:e©½ü“³#Å›qž06ÊeÓ|´ñÈ„ð'l4eŒí›XNkî;±£è#'æÓºgŽÿG°œœl[ëÉo8]á-œ=ç ˆI«ãíÆ—Vìî­¯ÇnýŠw¬èMíåÒ“,oz|ÌÙ•÷ìΡùåq¾„peôÿ°m<K'mPÓö¶¹n6ÍmøôÆnå}’˜õ½˜Á¶œ¡öHå§¿Y5{¨do›þ+réû ·¸O@eÚ?z¡õ¨¥ëK’|í›3Gñ)1>Ý^Qyðú8f`ÏŠ&Nî 0*îû†ž#³åu°Qʈµ„-ï3ÜÅ “ÉÏoÉF~Õú9ìfø’ó–•U‡þ{_‰ØüûA¦àkÀv€ü0wòÅV²îá†E`OÖíò(€KO½cþN©ÛÔm_é[Ѳ¾\ÎÞ~pÒLª‡ b– _Òöÿf¾)s °=æ‚~MöQàP()‘(Þcç›—Å&63¨¢ «ý'ýÝþ|`[« Qí¯¯AV¹ÿxöwå™·;i‡Cáv+ÇtÙ=wB÷Ü­ôÜF}N|(¼ðÄiÔ0$ðS*Œaá™Rº×†Ø %úßç³òØ (}†dß a’Iñ çåg~ÏAð=‰Ýìlð:n=ÞöŸõØ2ÃÈ »¦ÝÄ«^ªÕ¯v×­}´t˜þ”=©xb«âí¯6pNp¼ëVžR­Ršô­þSUy¨¿l•ªKabUågUœÒj ëŽÖŒ°j„£ú®Éÿ7Bà”ûRÚú£´õ•¸J}–&n}FÞ°¸ò•œngEÓ1@ÑšHr+—v¶¨g#&H#"ý±²¥ îuJ%j¡>dfùAaU†LOM§M¥NåVíJõñ]<3¤ŽcÃÛ?ÂüŒX\'ÖW‡YmáÞ"Pß±Yv„­²]·~au±GFR"hIõ©Ÿ£‡‚{`p×ÔgˆKT‹66-ƒŠÖ¾HNLÌÖ¡,e3«oL,û¬ -»nõ5èŒ&Å\ÇÉh=GìœØÀ³%_r@¼ÔXo¡Ð…ʸmáx¹Ô/¼ÛUyM¼Ô+KÿèɦM‚·`wFW3ï÷,1 d¤îÓç­÷ŒWªoi»Ç#™¨S;= ^žèc¡÷Ô쳵ǽ»={Ïôìáò…7ºÈycuï-ò"ð”À”JÀ“,ËKSm¸WaýŒ¡˾u0²ñÇ’¤;•ïââ­3+”ûŸýëëDf¶@ŽªÓ&a¶ÕO‚zÄDZ·ÞÙp+ÄüÖ»úiëmÎW’ˆ ¨)Z;õó¦R)¨%Ñ*rØÐbmWUI#ãŠSð½•Ö¾¬¸ˆ©:·Þ”Hôß|jüžVKÔàæw¼àìþ»íÐÝzÍ’6ÁÊ·¾¾%Õ¿‘q8‰~`´÷‚MrW]©Â„–oߨÓ)çöxûÔ2‹{|’‡†µG²ÍX‰Åy#T²0Ÿ ¾´!؆¬*ÅPþË ¾MYäÿ 2vKÎÚ³Í9äc0§¸º.R\T„nùº.²ŠT-w¿È||ÛÆ_‹t¼ ÿ1Y_WÇ€þíoBG)šJ"WZœ÷NŸ'´„NyFi´!ñ\~½kþ]òl5ùf(³é*§ñ9Ûº[ÝåS¹, Ÿñõ.©'©¾§Ï|l©âükU5Âm8KKU¢$—kaW‡Ó¤‚zvJ¸ʵ?P1†|ÛÄ~îBŠü(öÕ(öÕ(öiZg~®”§£¨îª1仯;†>¤íÕ¢ûú#±[¥×òmjƒ¥cã~»Fjsj†¹žù#é~Ñ3ú]Þ2Ò¬·Yã£ï€÷6¦GMœ6y™{eîd””áŽö³ ÏïËÀ½Qvïd¸^mbÿÞ ¹&Vm€:K(ø´t|x‹~s.°I/{ëÄÎê–¼C_nŸ»åxï¶ùž†_®ÑðoÝ~Å÷û¢ÜÀ£Á™:ÞË`|N¥Ô[­)Öá7”ÿ֞…:K ÇË$Ñïï°ßzûDîÙ˜|œÊ­ I2•‹ì›>Pc]ún¹gÊe0S¼b#BRØš²TªiW¿‰züwéÕÝ|ɨ߰*5Gmnø£Ä{—xûrqŒmGm Fæ¶÷2C‹fxj}“#û ÓrÁnK§Í®Á½b G¹,÷‘ýÛÛN¹ÞÜÚçû^ZŠ —{V>KŽ¿t؇Ϣ©Ý‡Rö…_©¹ŸptÇêÁ§èï·¨.KÞ6Tö#¿ÓÒýeÂfr!©Å4ŒR`n—¼¦g?êQ5Vä–©ŽÓ£Æ!Fè÷PœîÄÇêZfÁQk\Oß>Bt.ø™˜~zæXr3º¡‡/ËÛ‘C"aÞ>ž]§fï(Û7Á•m¹Ä`¡^qëŠÝ4Yòºü’÷ ã6–˜Co¬Z=ßòqçÜô°'Ç$Ý#b©"ýà•@IT¯>¶ŽÇ €ËŽ4íX©‰ù±¤wŒðD² c§oßy§™¾±‚¸‚ïÄÆìÕtGßÒGlú»¾åj'Pw…ª¶ L¨W Ðú®w˜¿»oíïØã€Øú*¥z½™^ÀÛŸØÞŒÃÍíNóÆ{Óì ¿—ãSr#bÇñÍŽSñšò!Ô*mÍéiÙê¹þxý„¡®.ØÆ3¼Ånõm/§ì`Ãïn½BåªûØiƒ#À¹ÍËïëÊ b;Ú˜½k!»mã¯U‹oÄ¡nÝÔaýœ:cm)êÃGS’ðÞ¯$[VÉßr·fÖô~¿Û¾]Üt«ö£°ØÁFÖ6*æ±ã7²«bˆÂUƒ.!̉ÖôBØÂSï–ÿ°ñf&æç40\!\Ùm¦¤±êú_mõ˽vpÁèOÜÿhq ÿkuž*ÈP6R„Öq[ŠÜ©gP<ª#w[‡ãÍõ†}ºÖ°ÿÊÙä=PwȪÏ-xrñ 0 šÒ#\ï,ž­¯Ïž”¶¦Û³¦¾#FçËaœòKe“ë1Ãþ$öâ)RyÈP"’ÕãÎ}Eµ0jxqñÇCzª¼£ÅF?»–¦qÛ\,ëÎs9µ òü\p¡‚ fhô@:‹>¶Èk<Û×ÓM5^½¶-‹·T¢åÛR÷!BÑC=˜>ªíÎ0eè5,”ÉÜÓ+0Ê©FÀUÒâÏÞ;Òë ›Hž[vnòø* l"íü¬˜[#ûw©õ¶º¯[•6Mðñ¯ZXžj›ŸÖëü‰`࢈ùâê1åan*<=œµRUmÃ?’ VðlõÙVØ]©òe/Á¾rré¤xï5xó_•ù1ÆTn¥Ø«r¥¢*aY^X]År]é~.rµÒt2æ‚ʦù®æà7u4h§§PJ;²6•|AóÀV„w|ªb^´Z ñ†‚ @ŒpÅkKõ{U<·ú~Û¬B6ª—Mû;ïˆðl:ž£ŠÚÙ(ZPR†%<ÛP¥­À¿[UÄôÀ¹©¾mÞl ›[ÎÖ Yœz¥¹uÆ3}ã«û_C›AnÿIº¹Ä®Jô®sÇrC.bÀ1ÌŸÐe/³2ŸÚ!Ï<>IÈß_¦ÊŠ?Ho:¤q⪾õÕ)§‰8²Ã o g9‚›o% Ž/ÆKìxè×ÿéTuhç5·páÑÆV(;"8¸Žc)~è”»¡!Ey“‘¢ÜÅt¹õkÙ¡Æ,iîìåTª÷5ÐÈÁÜIl‡¾®~íê¯]›Ë—$½ÖqôSg5úräV¿8ôç3ôõb‰^ŒTüýÌw@àÊÞ?çÖV#é%綺}ˆ¾ûD11Ôµê±í?CyÐ2ÜWÎè-?4›†»ß"xmüéuWªØ®„M/néÝ‹—ÔVÆq5ár'þ[U€oaׯŸ[µÄ;réªÎp–—mcÄ=À»z’£\æó‰ÐɨÃ=¥À=#´T¬*ñ« ÷›3«¦}¯^™` ºýeM}Ñàífú‰áVîâãƒÓöàŒ-Ë߃ï°é:Þ6¹^ÔÕ§FÎ ;fí.3sÒ×c¾Û f¤È:sI‹áßP&n†à}®O¿6Êßsn#åͦf2 ñãùîs^”ä.‡V =UºÁêÔtøÂ'šMt}=ß\6;œ¹åSŽÃRàWIˆ;)lUN ’¶“¦…/VaTFZ‡ÒjÇ:m'Kû„4 ©– ¡=©‘ó/e€„Ã鏸º_ Ÿ´n!.´ÓS¬'…ò&µƒ«­¶°Á,WÆ-Ÿ@o?)T£“宾<)œêMt,Ý“Båú¤Pì´²›Ä2Ë} {_ ¨%Ü:N¾…Ç!u¯ãnùÖÚ`;lªÝòˆà{íÿmÖåB»©ÏÍSiuʽRk¶ ¤¯O MúyC}ƒìU÷Ôùôx¼:WúNì«á ¶qk_“¯ë«ôñZÃõµ)äóøô€v‡ÏT‘DRäéåÛùºù—J_v*ºµ©Šª[T]iYÜÞ×åÛûò)•¾J²ÂmI­æÚÀ µÑÜdU þ"§æ;µÚ–SHä"L%ÿoÐOt°DBz$?ÂY"‘ËIX6Aå‰ÄÈJú!Þû“Y¢ã™%£ HUϯ‡”á“á¢ß…£]Šây‚0_JÂ¥ î›L8ŽdœèÈÒIœôñtˆ‹Ífg\}œ,fÃDâ\%×–dqm“°×KA8éÆqÂÑ#ú âç&B9Aä¸$ºšGã^"Ñl([¢"ž$:›t©4ÒîœÆ„(¾‰„Î{Ï­$ÝÅ,ALìEL=û‘„Óéð:éfˆí>öhaw0¿¦!\&ˆe˜pŒ•äV°·d¿ÐÀ–(Ô áeøHdÄä<÷¨ä(œwÑ©ÑtÍi„óù óƒ\QŸS3˜†Ö|68;‹x&Ú`žÌ1r8£o×4xT/ºˆb—pèfJëžS“¡,I$–x2g¸Æ€&9[ z4£äl8é„CÊÒÇþU²b<ž$³y’† LIqg6£yËbSRâUŽ4¢(á¸i ´ÔÅ3yöÃÙ€òQ¯'ggÔmË8J¤&B–¥O§ÑìYHX×YÌçÀxuÔ±ÞbÆØêow2½&ü  ¹.Ç¥§T¢¤'ãH„÷„Qãè~£É£Ft9Lraê=9ƒiO%‘ðGº·À¯(¡ƒ~¾|~D“ü‘a5Š(w2ÄÉ\bÑ%½ˆ'ÍèpíÉôŠZ¦ÉE<ãÌò2 ãëq7™J í]‰è•ÐÍúCšú1 FFÓú}Ñ`U0xFE|Œ§Àë|,èdLp—l»XÔ»9á0F/†“–ïl6™É,sdÍ„,¾PXJéóHcñ Ø´%XP¡šp$Ë!€fQL…ãDGIJboJºèlLåºô{üñõ3Âp‚å¡5…ÚxÄ1SÜdor©¦ý"fEýÛĘIâ/9£…œŒ&‹8¢¢èídHC!ò×]ÄóÉ]R]Ÿ^)¤ë '4£JÿžEx&8D”ä9:€&¢1êBÌÉÄäêZÚF!Ö ô1©ù4 „šÒJ¾$¤íâ á ­m–0Vc“ù¡Ù~öiML™JÑ÷ Z#Ža…w£ÉÏÁp&4==ä›O˜þÒÒÛ¡Õ "¦LI^!ê\Áe…Iƒ W‘K‰ÐšÄ³.!.clg†ñíÉv—ÆGÔ‰qBnM8¸mÔ;ô×ÑUõúP+(oüe–Z‚ÕI¼dÊý5è1– ¡*Q®Q„‹4¨˜àD"ñ¦’¿8 ¬4£BBˆû“Þ ? ˆÎ£pF€ëÿQñ\B^2qGÓd1í£Ñ”2‘Mêó‘ÏÑ ¬ šÕWGû{¨á5Ð…Èõ"ê~£ê³Kcù»Å¨CõJ`4&þD†»ˆñ˨8¥D@æÉ%ôüé ñÆÓ¯Bì8:/éR†oÂÏ£ÜlÌÓ:žÌy€GB÷› ¤‘ £6q ‰ý‰Éš|!B€OX<4¨žÌ¦S(Ä£)ïõä÷,úBäh¾®“oÑ5c •ÿüŠs-I˜bƒ[fÑvÁçá«yk‚àèšëЄªd f–¦på@P2^tFTa “°ÂÍ™ñ´¨N(Žó+“°rI؉'CiDáìw¨¯½HÈ %Æ,¨¾½Ò,`Ø“ÕÞφ3Ì ‹à\‚ÄÏ™ž·dör1!› ‰$¾õbA™Îä µ'››É,ì &I|É+bõ“gýôS-‹Rxž/„L-YôEžx&h²gLíup]&‡Ñ|NíÄ9Êöôšÿ€Ö$aqÊdd ÎcY$@–YÌõÿÅXˆ?Ի݃ýg4Õ ’ ó.É™Oô !*¢1W@³¯ÉûƒÃ#ÂnYèO's`)ý5ùÈâ±âºÝá"ÆZêEˆóËDWf•§Dpj•Ç—, (侘'A‚¥pÄø²èü’  «LËrDúB,H"^$†Sþ9¡^MzÂm’ŽpHÂUá@èõ!ºšÎˆ¿ÒÊå Àòøz7Y@2’tžJ,Á˜ÐO¾r‹ ŽŠðM836ZÌcufgÔ}tùPè H#j¡Öò xç©7Ió)¯Šˆ$…y D­»ü³ð^âwXØ;È ÉõD`“˨ó"h³ÐÆèä/%{Eßø,Âñçµ^Þ¬`„‰OŸÂáôɳ$ÊY+!pÅ`*‰Žx ~M†Ä€¦\€Ã9ó ¢ž’Ãq7>]t„·CéD¸¤j†»Ñ ƒÆÉ °ž ²)a…i´¾ªß/Z:àéæ¾²2Ê/µB®ŒÃ¡„º©µBC†˜]ª¬üMPžÁ÷çý@#C-§¨zd¬åtx(1kI,Üáá™@1rßu'¡!4Ù™'›cE0@P”ŠÒK$4M-â>[‰¬"Ô1«®.|‘Öô˜´ÁKQFeˆx¿ ÉbÓó C®âÕ‰$NXÂBøR¥îèIcžŸu òoÕ üNû¾â°ŠÄ€jÜý,вzKÕŸAð°ÐE Ôì5æÙBͨã5óbh@H!)DññTÏcahÐUT 왩W '!U4Ì ‚eB7€{“N’€„ÄX%V} âžØèIY è#b|RaZDeñÒÍ©Q ˤVÐ=Ò  ‘½`õ"@F™Þ¿&ÄŠ.² ›jß„e"wР¿$®ý1à4ðÜ3€kþb@÷ %hàøy=†:ƒW&—ü|<•ß]¬R’âµðGKÏAâù~9y¾ãJH¶+SY¬ýˆ™æ%U±Š°š¯µ°8¼cÌ&ÑTd–AYI˜T+âH_]¤e’¼Ü?bEbdâmÕ7“7”ºé%Gç‹äp@ë(yÝO˜ÞiÆZ{tôžHp²? y'`ý¤_ŒYcqXÑ©‰ˆ²]`Ÿ&¿D²‰äÐdÍûqYWgbw‰NzQ½`ÑȤÓa(œ\Æ IÌœdïL>¢(R¹ËË„ÙøùL‹@ D 4³ üæðà~Gìd‘e0:c…’ñ’Å¥±d¬žÃ©B)™N¦¤ ³ý¢à²QÅ*$ÛÙÄvKG\–ÈÛ:ârÅ»'âòf­Y­ç".ÿóŸ?™±Ë@?$‰qcb%ךÆÍÒ1 èœ0p2Kj¤Üë7ȄÈßþŸ80ò!âÇŸGµ3À"¤—pnA€’ÅÆ ÏQLFÚ†ŸOÃ%¬ÑD=‘¼«‡ø\èõY[µÜûkc}=˰b7¸ç‹ÁW>Ý2š­|[x³1ï° h×7fÑ$FÒLrc›OŒÐÀl té§iÂ.ƒyN)UmŒ©E,aUå+Š#ÓB5C…J…5Æ“q) žm¿ŽÝ[å::óŒ)X§ÝF}¢Ðalô‰øN.ã&RǪÀý»]*}âé mß5,Û¸Qe Ãu]õL¨ƒ‰©J9º¶T*cÎú= ®÷z Zê `~«àáL†Ç;ž &R;bƒZ‡ÖHkK€Šá»”w²DCt< ŒÆÎ«W;ov¾(À f¨ˆU?ž…©á0žô »³q²vi Ž5·¥°A¢u;£.Ñx£O’/Z¤v±žR ‹V‘>³@Îx”¢*ZA1Àͪïâ˜ê8qBGæazêa2òWJ›GÍÑ8^Ìx‘YçãéàîP.0HúÓÙÏH6NGäÖîãŒQÖq¬ë"ñAÂçIµ!7›Qx Œ \Ü”1évCèÚ„ïñt0O»ŠÍ}HßÏú*ÕðÅjœ‘±5Ô½´À~gƒ¢€ñj.hº³2=jòÐw×}¬ºPáQ8Ü#M;tq©Žò@ªvó4î6²gKÇR]á¤ûEßõ‘oÝ -&PXë6Ý”¢†A¬ãùUÔ%NÇÔŠ ¢îò7YG.vX¬Û«ÚÉ:£«2ïÓ¾µ8qÉ¿ËæÂs框2˜`ÒDØxÕ1`À%‡ˆÂ@FCmÀ€ðÀ\¶(¶}¼G±<Œ¨°ôŒ(]ºG*z®§DXúHÌnWa=M[âe&¿}_Læüú˜_‡òò„_Îè…iwÏB}éH0U¹Ž´w]Qk¹öiª÷¬ `&¦¿®ªÄâ’Ž®³–:UÐ5 Ñ›P¨•‡õÑ,ÇЇ,Sº d¦°ÔRÓišZFÑ Þ²ÙGá‰Aò I¸¥˜dMcNˆÒ<À¤¿˜Qš:V—bwu5QÔJÒÓ¬ô<¢îçã³á >×_Ño=7W‰Uqº$w¢Þ)P1Õ Á„"bCHÑc]õ––*ñËÉv‘ªŠ*ÇשƒBAØ (+FÉU÷ ÜÕîd&"6o¶v)nö4Œ…@1QÅŽDK©GIHT¤ ŠIz¿÷6,fõšŠ?–Œ5-J5 Q½Ì0Íñ{–Cê’Ueðª"8` ¥4![>vZÁ¿ïTÀEÁF¹7h—j7:Ÿ ÁŠ0ãPUJbX³¼&dAs<+·P‹š¥suV!WUÁæ~ü.(-µxÒéï)œX!ó[kßaÌåGDîE4ïÊd±˜J"uÏPöÙ™u¥y‚)B­«W ÷~hÓï©^ë²~Î'kVµ“õ’ûÉ –¹oºÕlˆQJ͵Z#.’…©ùʨ„ 4h‹>ºbb°6íì³…j`×i:ñÒÈ(ü^h¦)WݦšN³¡eÓi¥_ Ã?ÞÚmå{OF V´ÅÙù­ÆÖV»[ôy¶$òhw«–çjQ’ïߌáôsŒûFs«SK ã;´š—óí–¿&Ó/hÂ!ÒßC I0›,ÆLÓH®¥dôhEÆLi2ƒ˜L‡‹™Bx¦SÝùðÚ5XÍN@¤[¨ï/’8}½*Ã:B9ÑÉ4sQ:HZ ‡,d—²5•c3ƒùÍCú ‡¿¤Ëÿ?a(eİR£®(é!Ï7 `BÚËŠä¤ î—ÊÀ¨åï‡P,ƒ “!6" °4ýÕ–”Q(Çk +rÏ\¹MOIç#ÀÄÄúž4ùdÚŠ‹ìNê(ô»ŒI‰éi3‚¨Ç'0|ptòù¿›*áH÷ŒÌ5ŽWú'²•šäl:fUcÃü=7c98ÄæÿÇÝÿ/àî†ñn2W¶ ëÉ‚H£84:¦cÞôZAw=M®FjJÈ!@ ?#\Ì'#X„‰–]ß‹ðwÄ‹¿.„.½—*Vô0ÆèlÅ«E’cÄàÎx£büÓ« Ì" 2ÀÂ)ko Ñ׈ÝíF„B£ÁXè&ïsk„RA—\U¿|¿-rHF°ê›±ý«¯Öjgl£iXÖí†gS5›ôÑ#¶¦äÕv`ljÉBñ¸”·dÐa¨h.|«5xÕ°Õ•ò’?ßÓv¡¨àQ,œ2\WÇ!üX\Ÿîýtã){×¹Ia»¯Aû®¾ûÛÅá\¦RV;›9¢8Ï Cm{*§¹Û›Ùˆk\F“Å|º˜£Ñœ3¨t,T­rm¢|s#º G9 WÆ‹}†Ý”Ô^i…ávy¢ sÕÓ|]‚~j×KU7S§*°v©è0ñÆC}Æ = Pö toU½"zèqbrקÈù(ÍÊlý 23r¬!Á" UûWŽÖXlˆptí¿”ù8ë-™=Ì8(ô"¼5‚¹þòœ+5hîôzìDGS›‰ô™5QºíJï¡RÄ´°ÿr_$_ì Y즦sÅbBØïÌØb `¾Êa^¦Uq+9ЇY¦©î1 ïž£‰\û´E)³±º²…F©Å¢[°.­4GJÔŠ‘ZƒV¾m4} ú™OuSO4ùn»ì ka!¤#·ßcGˆÆŒÝCï‹e25Öœ™OXܰ9·€ÇacI*Œ°”P_ÜÑF,«&©À\lÈ£(Ž•E%,{ƒ¼‰'ã‹8 Œ@ùÕM·„­M$r-0 7ªèÃÚû1½1¤“Mƒr¡\“ÿªÙ!ºÎ˜ÕÌè^áxœî“É@¨Ñå-{\F¬‚U ŽÏå‹FÁnVAþbE?£<ñ0àÙkˆ»/iÀ±Aj0ZŒT’Í¢$ËÊåÕ,Æã†ápvm,¦—ᬲ ±ìò<)ÂãîÁ>‰‚ãÁt!`¼Êʹ7²ßw7B1Îç³R“aoð#¿ã´²¡dè«Øð~³èÑv»qlÉ$hOÚ¦QÐNc‡¿Ì'SJÜœ^©w¸k¯$°2¥xiŠ@©I­È‚4T䂲a=žY…AŒJÆRÒ¤‡º¬øq‡W¦íX@LüÙ„å¹ ¦{ÀIÍüëVë®8X«­}ž¡²£ÑëÁÿ„ÛMzÍ¢ËéÆb64xÿ“ÜYðö–EÜl@8‰†, ¥µÐkÇÆûWïí¸ëî»Òu(+571Ð}Æ_¢=ÚñÍ…SסÙÆÝ*¹;•6þí¿Ø8£ÉØ Ð$ŽêuÕ«°ý=(ð.±¨Åu7ù'_Oëù·_õk…•Êé‡rþà ýO𩈚–çKµ?+wvÑc¦ [¼öV[ö´Óly¸©Œ€Éq³’ª1»µVvUÓ|y»XŽz¤ß3Ë:vþ½üÊLó¨5ú9,eI‹øTDʺ½…¸Í¦™¨Q&oŒ²+"]àð‘ö=ÄÆq:ü´ø»É¥lÄ£Ñu¤G”` 6‰ì…WûIí+ ÅÑüù¸÷9­Âs¸ÖÐZÕÒïÕÖ. HÄvHÁN[ý ÒÌ”Òæb7…| tKv'R»…5@£êž·ámžßôªM¯¶âvǃ‡kQÌ0ÏðWÜHÔã}+Îܤ9 WĹDhd7Ç“¹•¯*s)±‰éºVÜ r¹•Ðr÷CžJ§KKYÌimÐ,›7 }Päú]ÄV_"^8ý)êœÎ¥î0Üœ¢ù4Î9\¤¦‹ySç„ýèíñ¨wÍa©jK{ES»ßRsê×Î-YcCba¬¶LÄ1OÛÿ¸8ÁA”Þ¬ûŽ!'<¸­Âèš@\ü™á°×ürrCE›_¹‚íèrïHÐ])¸«píÁ¢ÂïÑ 9u¨Û_ݽ¥/|wî¼pÆ›{œR~Ê£¢ù`NýpXŽHÄVÐp³Í[‰Ô»tU¹zR©eÅÑ¥¥æøÅ€glh<žŸ?QhÅVÙHžU±ñ‹vŒz¹PÜUd#V¾ÖÀÈÇ $20uiSš L¬ËR–ºñ¤p·GLJ%|û3ˆ²"ž—m~“$WŽ¡Úî€XЭÉÉ 5“½ÉdšZ*óä…Æz¢‰ fjv”Y,‡RiÅ’ÃUugõ<ˆw¦.ßw¼ºã,æ |wX’ÏúƒíTžÐN~H:®Võý󹊕Ê=fbÖ䤂Ý^íê¶QÐ,¾@¸YÈ9æŒS« »SH‘t™>Ñ0Žy •Ádë]ž‡ºšëå­%jݲ¼¬f§È> ñ!_»Ì3VBž¨¢­ÜçÀxˆ¼ Ê߯ɼÛÿ±ùú?3WºßlW—-VHp¸ÅàQ:Ðæô~Øùàì|È6)¸ Ï4sÊ©ŒÜ`ÓÍvrÙJ~)L.ìμ'ÆÝe?ƒ ò0ÙS¸2àˆ®O|3¦¤ÝVSÖ„Á±~W7¥‘«ë@ÃÏq£Û¯k´"5%ÉÓŒÏo{籨€-_6}äÍý‰1Y(…ž&;œuÏ•ONÍ b ê•R®ÜÄp…·CSžëÜ}¢‡ÖAnZo“¸Y¤æ¬ÌP”c †òÕO&Ž1f_bì&“è‚[Æx{™Z9r¨´ùë*K¶]¹îÁ*4UMÄ$«ÃÌ»r €’vmu‘ä'3›K-ïçØpª®Ü+ ”óxÚV¶"HÇÞbæ©ì÷ E~ûtH|Ø>‚ÛéÊòÇâIM³¨ãD V\"à/.‰3|pÕx‚ é-ù['Ðyåçnl(h²x4 ùÇO5fÕ»Ñw•]vй+™­NGáH³öA~ý¼žéð˜­\Å„~p=,äÛ6j™„ ´iœä)ˆ®dí/Ó§”fýt²ºïQýi oåÎMj~´w4Y:´ ?á†>\Y|»‚IØ«•Po:Q{Œ0à¬.1EÎSîÿ7+œZ'{)þñú“cÒTåƒ[#nzÜCUÒ'›P5·Xr b¾x -èÆž›`Þúõq¶°[_P÷S±Ø*×ç4ýS0¿HqeÝñä;96Ó^,s ‚µ,qUЇ&4'qÄ2`Ît CMý£gR´S¬ïtÍÚ@yæ(¹V-Zá#<ÍRãbªŒ#¸AfZEŽ"ùÊ&Â8'z"ãÊ'ö(Ü^·jêUFm*oU{›¬1ÀÏs¾;)ÍÀì;6bˆñ§X`­¶“-'- ä™ÌJÓyéY8®‰ÈΖš;$ïñiX‡ þÃGšÅRj3ôE1.KеX¹–ùïèkVdª9KºvùùOø0 È•XP÷HèZ°OK<¼OùŸÕ±\áß©Æý°ÀW­0R,~PLÍ$›tkòŽ_ºÁ7ͨ^°6`§HÜ.ª·3ä2š{< „‰ðñœÔÍËw¢ù%ìhaïbÏoiæÈ‘õ3“þ5Jªd·Þ;¾ÛB¾@¤ð ˆhóm7Ê1çÔŸD¼RÕ?ºWÄÍl¥ÝÙ[vé›ûqO žU¨R~Çð«›zBòø(жäG,F­üÿþÿãŸ8áÕ6ˆ«Eñ†ÚÛßÀE{ñÆE¼Q+Gýh«^#ßßêT»•j­Úñ+½~Xo46=÷"þû6p¡N­VáßÍŠ·úëU+¿üÏóªå²_õ+›ÿØôËuJ26ÿÏÿÿXÀƒÉ0þqyyY‚ÖðP¾¿ûþÿÒÚ€$—$¦¶#ÿžÛhÊfy+g;2à¯eÀ 65âçï¢Kã3²ì å²ýl2½ž‰q׿Ú7“ó1+g†¥úÐŒøÔÑî‚ÄY\ë6†}w?‹´ÿúȰèOiïõ³çó«9€¸óòýžaÑŸ•º–ô".ÐjrJ›Õ’_1¼JÓ÷›^Ý(mV67 ë0œ=«ûá5gãú?F?šFµÖ¨²Ï {S§œlа:Î7'rföMd‡ŽìaV÷q¸](4#+5'u7BÛ¶‹–Õ ºÿí'åê¶\|àÂ8õL]Ïju‹þ–ÝìºúúB«\³íekÐ·Ö …ÌqôÏ G¾Ûö ß muK%{Ö¦_û4øÆW›ã¹õ-hçöäT÷ Êxºú-ùó_zoÿ¶áÔ|Êç¶ÿlþëä¤}râÒç Çóùªuõ¨7Õ ‰(mßôÀæÑÎ]¯fßðõñ½VÝ}x퉣¬÷$Š•Ü¿@ÀÙG4DxѶGàFt+D’p[ÔÆ¹ÕÆË©³ÂÕû‡nÍ£ eZÉ÷à‡®ÿc-à$Ü©Ï!Í{¶¾_¿´O—Ëw^;êÇMÖ!ÙñáÐnKÌŽú¶é×ͦY)›§RIÝ­}µ8ÆTÏ«—M“×­é4^¦ÁÏß.·ÍM‡ƒ|K´{ÄTáÏq­~xºt|Kï踂„ÇªŽƒ:îï_:5‹ÛlùS¯ëM%_¨‚°¿Ïî{¯b|Q—Y½%@›šÝ³8VUõr¡š§Žx9o³¸v:Òì9üTµ† ^:ÐGTd}}·ÝALÖ·[ÒÅ ô‚›e«'átL­‚uC¦'ÑcÐðS³NË›^ÔOp:b¶s@ïLGà{i!’ýIÁ??)p4Γ‚÷ÇIÁ^_/#¨×ãM;Dèg4…ŠPÍËܛɠ¯:±eÒˆ×Tì¦ÊsƒòË’±p¼ÿ'a¨íV_ æy Ð2MT€pÇ’¡ê–çN>X_ËŠÛ‡øˆ5‰¤èͬvýñe«?u8.Ͱ£š¥6¯Ñ-ù"ìU !ázW⊫âž×Õ¤7¾jœÊÇYtk¨ÆêO`8A£ññÞLé÷òUËŸ-oËÙw>8i,¯†ppuDU–ìµw²ïß“}‹°±Ž¾s™ç·Ê|ÐMP–žÊÌ9«ßïäÜ¿“Óõ_Iχiæê8IvŽ–Òwò]„¿ZuG+œÃ8Êâõ_[í?‹ON þËÑ;6¡‡gu]Ó~Ròh¡VfDx›]tÑ"‰ñ[×sÅä‚Vd_bpàT&ЭM¬}Û©¦Q±˜v«z.ÀäÅ"F •W§0a3)R¥–i¹>›Lš°®e§áüêíç§ìaã!8æzQ€èQõ»ÙÜ”í×-ÌÂW”/©Cób‰v9âS‡‰*I¸ÞÈêµ§`È”Ôîœê_Ä'Æú´Þž ÄLÓhw»nù™@ßp,9ĆÂó’£×•ϰ @8+_õòèd$§æË|ØiµRñgZïŒNÖÀëµã¾¥5Þî ü âhy&DÕÕ„@<·UÂm¦€u¢s7›õµ ÃD'ÊÖ7ESNù>bÅO-Û‘(‹DŠÊ'…m°Ž¦Ž,ˆî—_¨Òkk!úŒñÙ}ûdséÔ²ª¼Ó5‹ˆ#Z‹Ò!3eåz+X JÀÁ¼¾E6ýÓ–Hš]·VqjebZâè¹^Õñ?Ñ/Çlß)ùŸÖ)"ºøÚ8VáÛüOÛ1¿ÏOE¯éUÌí±ßçˆnLê=DcîìFˆÉ ›{n8wý+7oëž5)Ç‚f~¢:­ZYBG"N­ ܵ„¨]!p®ê=9™!P/Šöü¥žàÊžÝ)Àz'Cêwz’@ÀN}«É‹–Q&¶ΠèÍâ”ÜŽŠPŽÓˆ¼hxk!jê·ºþ˜‚šuÓ i™ƒˆRâž–Ú-šõ@Y’Gܶƒé¡ÉÁ‘;"ÞºÕgÖŸò½h®!Ê7 þT…¦æ5 ,Wô’ËQú×_§O(EWÑC„ ßZÜ®ÕéœêÉj†^3[èÜaxn¹Ã²þLŸÏœ¾sޏ‹/‘Vªç”¯Vpq­|eß”¯DÐ<Óù‰aœÛå+wkBÓÄѪãKž±Ì;2my)_¡ƒfå¡bZ•_Y¦ï› ñ¯Gôõ1O@²-4™£©BÎ(_9Zˆ¶…[_K€´VW„„„þ&Pv1y!0ŽèÍ X¥’S&G!–à ß„w©¡Ú@¢#£^@nÇcë•Q;²Ž¡+ÝÊ_­/DˆòžSöšï ‰Ú9”7G §Æg%^;ÀßÊ+¦f¼g‡Ì¾ëÀûW*Þ¼.’úÑx³D„¾@K£ây[ ª›¥3<‡…-÷­S¹ ¨ÙjJ¯íJë´8¿Çù[Dó–«‚Ÿz~eÒTP†—ÖÛ €ÐÕ[¥Ò`ùÑ"z¨\ZDX©®Á© i4”…W¯*³Ñ°ê_‚dvOöû—vm¡ß®Ö×ýKnŽr¨¶×üKè<('A’+DZ’Ä¢ä·ÔÂvû´y³´©J!Wþ%s.Éï_Ñì@){Nµí›E€Í©‘àTg4§ö2ØøYÚ®’ÆÓÒvc'ñ®“ÚÓ¤ñ£´íý±1pÊï!w¼g°HÐÚÆB–«¤²š$šá%äâ„»y^¾·¦£ ‡îW®–ÉòŸ¤øÅíÓíWƹ*ïTÆ) t½g\Êëdþþä$Â}¯KHu‡#Ž~¿”˜›tœÖLíR­Äs¼‘–£ó[ÞˆŸéÍ6*s¥\˦do„Nz¢…v¡Y;½‘ÓTŠ·:½!@é×\¸u ‘þ¸þ̲’ºñK@ùJ³Ä”±ËT¡ˆ m»:kvYúè’ÆœÁ–ç X¬½Oe™Ðû*âÿ vd¢UZ»wJhüÚèmg ˆ)Τ¬û«u¸hnáÆ?6tSZD¢?Z,Ðé,Þt³c3I$‘ÑQõ-½On¡ùU‡6þXÏíeVéRôÌžŽzÑêܤÕÙs1Ö.J¾vðÑŠDéãåI2d-qÏ© D×ժ˾Óú[ÉñP]ߤ®ÈÁÏJ…@›D'ª˜´¡å¹…oÅ"-ìÈ+=šÔàL™z¹¨Û¢nqaVßtîÊÞúz¢VˆÕP{Éq"ímB|ÿ‹‰Ùò^4oX’ä!‡úÈ¢ÐGˆBqqÃæhw¡À˜iµ È ·|„”ŒßbÀ¯Û¦a£µ‹!Ëž®<-ΙƒÎš˜HÞÆûj{¼šu¢þ¸µØ¢šmªšì([,ï„ì R„lu=­aAí{Ô”Pðï‰q1>»Ÿè§%?„®½Ó¥€ÕÎçUŸQBéþ=š[F¥HýTÄ_§ü%@IÄÄtªgMÄ w¼FS"8—«*µÝF$AñO›m(ˆ0‚§ÄÚª Ô_gì¹>I¶ YV$+? 6… W™ “†¯ã7÷$¨ « vé?[ù†xu¨2oì”Ëm”‰>úÏ(v%Vš j£3Ì@kß©Šò§ÚÒIÌÎMH4<)¡ á@H0ê;C盬ÀO¤"~¢Q•Ÿ -XcBè#ý¨üÞ­Vh²Ž©^„Œݪo™åçsñ€‡ïµÉA)™„ÞD)YBÛ¢;€•¹mzf3Z*Rë¿\_ç’ SÔˆOnu³…?¹iÔ¿õϦ¼"æéÐõHÙ® 6¶= ®Aƒ¾­¯¢ÿ·‡§và‡9 ÷ãX-aVfk Y©°Ú;¥?Nm(¥ß±½µ'6î g$%m"1ZFhêOܬzcÛˆ¬‰ðëÎiÆ$¡–ªö7Øzz`Uß¶Œ}£EÆÀojó G*uWÖ—µQ?4l˜ÇÙDÚ³ÊfÐe!ØñúÚæÔê[о´ûÀ`±J]ÈülT?$•^ò‰ÑlúXÄŸ5ç"ž‡Ûn­‚O,2}|Ñ«Ê&þ¢Ä)J: °ÂSRv}jaÙ½“ÂÜØúdl›­u#è.eÎRÈõÜúl…ÄHyrë°2"3TÏ>·Š–(7¸7±ÒâÄo™ŽD ߤžn} Fe"–p äZ;#y¤Být|»)O€1?bžß±t£dµÃÒOú¸õêF$ a`k@:åoJ“´Âl4À÷"¶%‹¿)»¢ã÷²-®ö©¨VÇxÀ&Lï‚õ?âoå5?³aC"¥‹ôħրÞJ%bæ°WÞ²ñ÷´T,–Tè9!ÛN5wÁýƒ Cs¤€g |OŠåÓi|hš5šƒòý>§wJ¯~§ßšÐŽ)ÍwòÍKëÞVΦ|ÿ"Ý•H Òâ-PÝtã€Ù¶óŘšm±V‡¼‰ÐØOó½`3¾u/—ê{:õm–ÚÖ|"ÄšEØÐ笾šzØ´Xî"ÝÈÁ¦¶;Ã6Õ.¶±{‚33ügn #€Á]({¹«’jꘫŠlSO¤X§! ñ†qó1,5«`¸†Wh[Xm³ö ¤cž²øßbÒMéBôNo ˆ”ÓÙNÕØC×ë¶ÍêœxŸ–1}ÒN½%Æ’˜-OÎþ,Ëž/Ü”º·E}—¿’¡r Ž”•¢3¹ þ —A^l»©÷‘Ü·èî™ì™tlÙKò{ÕŽévØKCå•áW5— YO*ÏÄN!['Î>ѵM¶Q¼1žé˜9=WŸÚ¯¶M¢ D-I1zT•N“õϵ [Òo''%úóüN&§¶øOÊËüó ÒâG–Y|V4‹$_8µ7éGjýËÎgxehÿË=ÝVÑGEDk¯ˆXšÌvÎÑ´OSõÈ16t@mþk%[áÊôÀ ‚”¡i6o»ùLƒÇ£vù´´IKçÙJú^WÛFj Ô&Þ}Ê“fº#G¢ ê8ÔYáïÆ©3( DwsyÿísîÚ³•4êwyRª,Ì<±gãù#¶ÄÐ)Ëa>‹Psä«9žÐhÉ×ø™Ë·¶’/¥ý+|åJ-gÎ/ïëÜÈ-½Ô¸‚‡FhÃ9ÆVݹ¸@¢¤Z.T-°è­‰<`±þŒùTô± ñÂÌÒªgœF™Iÿx™+ ³ý/ã´lÀe³4” TÙÆeÖûòGšŒÙèð^y“½WÞaÌÞÿÌu¾eþ÷9u=’žÌ¤'K§z ÓªiÚ^š¶—¦MÓ´©N+k6h–?¤ù&i¾‰N«íè´ÚNšö3Mû©ÓüX§ùq)f°”€ýí®°Q9Jü¤vø±XB÷«­¬Å)^³K &›Œo šs]üæ¢\¹FœÃ¾gðæ8pÔf5¹Ž{´D°-_5ÛZ''mÛxôû6¤µËIkÆ#«½öè·?ÿ' Mƒ^N Û&—5ƒÔ›Ó ‡ 6í´i>æ6åC&ª?¤ÙÛí?-ØxøkE•iºÿ¢ê3tê”ÏxÀ]åçxsȰpÍZ_ׂLH¡²î0—DÎVHzÏs}6*OaLö,æØ˜ÛT=R²éXSâ§®ÿ#PÓSöñå2Ó`—èBûwúhžŠH+žÌÓ“‚Óç3âÕ` SF#¤oÊ#U˜ž6ÛÜDgY>×wØÆŸ&i‰e˜×b—ä‘ÙDÃ-öš¥·õu^"_YÇR>Ìòؤáé™9œ£üŠ•L®i#CuD4HÒ^ÈÆ[¦M·fº·/-<Þo°©ÓF:‘®/ËYÁ–jõ³%X¥mDÈæ$Œ0¼:nЉw®òõÄÖÒ#:ô+”{møâX#"j4ØFŒ|£"ým­Ú²p'@Š<ïr‹¼a7Ú××;$VÀÇÏf3ÆŒÍlº`Dê¾l&ô œ+Z=oÏvÝÚ•3J›ž¦M<ç—€Ô˜Y˜`Z+­q«–z6’U¯&ªÉèÂiå+æSÜå¶μ®f$ƒ!X3Û­|•ϼö*ÐÐòŸÛ¦­7¶Nm,Dæf¬m™KQ°r~a›-­¨ïL?ÔñŸl.SÆVÿó†t—0Èþ(a‡_“Dí¦Xð?Ä–øÚÏ$Ás@/?vÕSIX㔵\ÊŸœBe~ŠXE}øðiúIDæº.néQ`JÖÿ `ŒÍ*€ÞŸçöµlÂñ³eD¹‰(‡rõεÃ`ó¼`Ã*‘Ó‹:2AÓ» Í7™év«ßx{ä³ë½BsÞ–[ÞsT£”vôÙ¼3XõgéjïÔNêÚ `֠ް*OË\ xøF^ÄñŠ[öçôŽ.ªG·2…kJ_ü‰²å·6þÀÐôÊù Ô–„“¹?–Y™˜E|"lëµ×S"×WcÛ: “<_izŽ_ƒÿ›Ô"çœDx·è¹‹Ò¹Ã’Ô"°ãí9Uˆ¸ì¿.;s¼®%Ÿs·1µ6má,ŽŸaÛk€CUsV´ÎYÕïÐs÷À¾éCh»Æî:郀îù*t;ÚPf¾¿AW<Òìd†=)ÿØÀK»‘·à}Ånœ`,'¶$Ç)üÓùÔVZ¨ïí¥DJöö”û ÏI˜MOHÓ³ƒé‰Òé‰ÜÚÔÆZ b@:=OôeŒÏc™§•<öÒÛ Ž[ª/¤pÚË´3¹žƒr¥ ê„sD%Ù¶©¦(}A(¯üãΉDôi°ÂVjÞõ;gA}wÐìL@9¶6’'ö!<ôÅ žèÇ„ø‡Ym¯ãžÚð„>ÇæÇ»{¿l±v€7| ÏÛµúTO’ÛÎç`­Ëž”üã–}êÐgêœ\nšçŽÿ¦ÙwÊ>[f‰Ø½Q•gM¸Â_˜ÊÁ³qÉ5çì­É/µ‘~ ²~d€·lú²ïI ­ Cêî;'…s›+ŸØq ßæù:?Í=êâ<õŸ>“ÄDz&a$„vi‰Ø74¯ÉÝÁni·‰ #>ÏE´gO9ÖÞ¶Pëëëgp äcaøY{¨W7u¢S4:ïøÀ$PÈFÙrÉ>°.‚tà/7œjß©ŒZÊ“9*׆pô:îg»Unõ:Èè³ÜÀ"£ô@$¬ÚÖÊ >ÃRµ*#NHÏìÀ¥×nS)¥Ï{+#Y·•i«4äjj7­½rþéКºÔÎéè{-?šÂc§ÛcXÉ2ë–Xì)ûÆrËYÄaznÈìóQL=ܰo“foÉr½Ù‘Ño† £R7ª=£vaTŸ±g4ÎÆ™Qykø×F54ª[F#2£Ú0j}£†Qùf4êF£f4*F­gøoŒÊ3£Ö5Œ†o4<£\5Œ†©-¼9Ù”Jp£†ÆCú ÿ¶¸Ëû‘OêѣݓöÜÆ&Í'8ûüŸßðçú„üô¹ò,ÀšËŸŒ„4Eþ(½¦ÎºâU¹R_ðÞ“ì•op3®¼µñˆÊÞœa›Êw›xçª Bd>«ÙS{Ú8ã Oè.~1ŸU RµWdk”ëC(é’PÓåÇM»ûkO”·ÖGÿ.tÞn–·›æ ñ´äN–«$áQ/*uÞ7¯Ã‹ÄÞÆõ°b£·\ ô÷j(C«nq‡ŸÛxDßž·ÒÚhˆ±”xâuoÛkÊ“¿]VO•m¿¹iÛj︼¯wÔ;]Bý-â¯fdŸyÞ¼ñë͛ʔiWµJ“óš(ØŽœr!ê\ÞM¿f;òð“ä3þeV˦#lÇ-å¾F7öÓ:î)T‰,ä_ë-´|Œ í·B8­—wÍV^òA‹ú÷îoûçeM½ûûw¡_ôïݽýÓE°ïâdç…ùYùbnÓt|R©ÍznW÷%In#ÝéòñAÿ“5R¾äL#I%\ìˆ×² ÝÔeþ`çåÒüÕ{É¢q•H#ÏjNÙU§…˜c§Y©ð=§×}•µúl%«œ„ÎeÄÎÚ>ví²3¨Þΰ@Ý<&Òd«aÒ°ÅчQùd¥éê¸kåÀÂ_,Èhb˜H¬ÛH¥’)(’äŸçªÉ—Ðå¤PÞ=)ðù~yG/Ü=å ÀKHã°Ù7ûÐÙoäòÔud_êôE@.ÚãÀ‡æ§¼Ó„'J]!àWvƒ¿¬ ¢*ñ…Ç“#GíÐ’ÍÕ”wHHÆ{>:æ×YŠ‚t+ŸSß]¼°Qïã•çzë³/wØZí*¶OS­Á»Îüì½1o×—žÎÇÕæ'Ǩï´ëÇAýð”„Ç·-é Ž…s©VÉ™¸ß€Ái³z`™õNýƒS);ªS¹v*_œÊ'§þÞ1‹fýÀ©¿s[NµìT=§¾ïø;H¯NœúžSë4zN9’0Qóî¼ÞÏ϶äÃmFW¨M>î×Qþ=/ø® µ¯Ä2ê°ÐÖµi*;Ð{z;AÒiD¨h(B2‰.9ÊÝ@IÓ‡LU9«Õåä>²Ræó=qf$u‹E9ùË'‘kuëL¼uÏôVti–égêIõ‚©ðLÞ6‰~-»AÖ Ù(núïM–³Ë&HYèµz´p•- xI’iÖÎÌ%”ôz+=…wæ´Žxþ[ÓÙköï^û|*Íô>›|g‚Y'„!ï­5ØÞ…së'¦œ@u+ÇlÂ|ìÔUØÛðFOÄ Éb lù;¶[ç.¨\/D²ÃSž!¾… ÜSÇH¹Ïu·þÚbjô:;®:´t>( 7Ju†¾¢9_ÚÙ má¥%N?IþÀaß$ÙàHÙN¬»_‰âmx³Ä{™”?èÄ\!-¥ rBÄd“u‚ã¦>V¼ÍŽAÔ†tS®¾P®8þU3¤¡5ó %î]˜Z©Ã‰YåÔ_:õN}ש?sêOÍŸ(ŸÅû)=žê/ˆý4`ÙQè(_ F Ωô8¡ú˜€`æ1ßïM‡ G“NŠÞçf,è‚;…ÏóÇx¨·çØQÇDéë®Ê}ç7šŒŸüýÙ/ûÀ‡¦ÒNF>Ô‰ÔÃhHuÔ6Ù™¨¶ÙÖVÿp«` ÙwÔHü£æ¦SÿÙ4+7®JáU©ü©^šNýŠò”=ú³×Ú7g<ŽâS60b|º½¢òàõÿpÌÀ,žMœÜA;a UÜ÷ <‹óF¨da>|iC° YUŠ¡ü—|›³È/þdì–œµg›sÈÇ`.Nqu \¤¸:©Üòu]d©Zî~‘ø8ø¶¿éxAÿc>²¾®ŽýÛß„ŽR4•D®´8ï>Oh òŒÒþ iBâ¹üz×ü»äÙjòÍPfÓ#TN/âs¶u·ºË§rY>ãë]ROR}OŸùØ,R+Äù Öªj„Ûq––ª$DI.×®§Iõì”p+”k b ù¶‰ýÜ…ùQì«Qì«QìÓ(´Îü\(OGQÝUcÈw_w }HÛ«7D÷õGb·J¯äÛÔKÇÆývÔæÔ s=óGÒ3ü¢gô»¼e¤Yo³:ÆGßïmL›*8mò2÷ÊÜÉ()Ë{3ìgžß—{£2ìÞÉp½ÚÄþ½rM¬Úu–Pðiéøðýæ\`“^öÖ‰Õ-y‡¾Ü>wË5ðÞmó= ¿\£áߺýŠî÷E¹Gƒ3u¼—Á*øœJ-¨·>ZS¬Ão(ÿ­=…3 u–Ž—I¢ßßa¿Ý{Iõö‰Ü³1ø8•[’d*!Ø7} Æ ºôÝr9ΔË`¦xÅF„¤°5e©TÓ®~õøïÒ«»!ø’Q¿aUjŽÚÜðG‰÷.ñöåâÛŽÚ,ŒÌmïe†ÍðÔú&GöA¦å& >‚Ý.–N›]ƒ{ÅŽrYî#û· "¶ r½¹µÏ÷3¼´A.÷¬|–?è°#ŸE'R»¥ì ¾Rs?áèŽÕƒ7NÑßoQ]–¼m¨:íG~§¥3úÊ„ÍäBR‹h¥ÀÜ.yMÏ~Ô£j:­È-S;§GCŒÐï¡8݉1ŽÕµÌ‚£Ö¸ž¾}„è*,\ð31ýô2̱äf:uC_–·#‡D¼}<»NÍÞQ¶o‚+?Úr‰ÁB½âÖ»#h²äuù%ïAÇm,1‡ßXµz¾)äãθéa NŽIºGÄREúÁ+’¨^}l A—iÚ±Róc'Hïá‰d ÆNß¾óN3}-bq߉٫鎾¥Øôw}ËÕN î Um˜P¯@¡õ]ï0wßÚß±Ç-±õUJõz3½€·?±½‡›Ûæ÷¦Ù~/ǧäFÄŽã/š§â5åC¨/TÚšÓÓ²Õsýðú  þB]]°gx‹7ÜêÛ6^NÙÁ†ßÝz…ÊU÷±ÓþG€s›—5ÞוÄv´1{×BvÛÆ_5ª߈Cݺ©Ãú9uÆÚRÔ)†¦$á½_I¶¬’¿ånͬé#ü~·7|»¸éVíGa±ƒ¬l TÍcÇodWÅ…«]B˜#­é…°…§Þ-ÿaãÌLÌÏi`¸B¸²ÛLIcÕõ¿Úê—{íá‚ÑŸ¸ÿÑâþ×6êts‰]•è]çŽå† \Ä€c˜?¡Ë^fe>µCžy|*’¿¿L•ÞtHã:ÄU|ë«SþNqd‡ÞÎr7ßJ9^Œ—Øñ>ЯÿÓ©êÐ&ÎknᣭPvDppÇRüÐ)wB BŠò&#E¹‹é>rëײC'XÒ"ÜÙ)Ê©Tïk ‘ƒ¸“Ø}=\ýÚÕ_»6—/Iz­ãè§ÎjôåÈ­~qèÏg>èëÅ6½©øû™ï€À•½έ­FÒKÎmuû}÷/ˆbb¨kÕcÛ†ò ;e¸¯œÑ[~h6 w¿EðÚøÓë®T±] ›^Ü"(Ò»/©#¬ŒãjÂ5äNü·ªß:Â&®?·j‰wä>ÒUá",/ÛÆˆ{€þvõ$G¹Ìç¡“Q‡{8J{Fh©XUâ)Vî7gV%Lû^½2ÁtúËšú¢ÁÛÌôíÜÅǧíÁ[–¿7ÞaÓ;t¼lr½2¨«!OœvÌÚ'\f椯Ç|·ÌH‘5tæ$’¿¡:MÜ" Áû\Ÿ.~m”¿çÜFÊ›MÍdâ3ÆóÝç¼(É]-¬zªtƒÕ©éð…O4›èú&z¾¹lv8s˧‡¥À¯’wRتœ$m'M _ ­Â¨Œ´¥ÕŽuÚN–ö i @R-B{R#ç_Ê ‡Óqñu¿@3>!hÝB,\„i§§XO åMjW[maƒY®Œ[*>>Þ~R¨F'Ê]}yR8Õ›èXº'…ÊõI¡Øie7ˆe–!úö,¾PK¸uœ|' Cê^ÇÝò­µÁvØT»åÁ;÷Ú%þ۬˅þvSŸ›§Òê”{¥ÖlH_Ÿšôó†úÙ«î©3òéñxu2®ôœØWÃlãÖ¾&_×Wé㵆ë/jSÈçñ;é=ퟩ"‰¤ÈÓË·óuó/•¾ìTtkSU·¨ºÒ²¸½¯Ë·÷åS*}•d…Û’Z;̵j£¹ÉªüE NÍwjµ-§È?‚Jþþß Ÿè`!‰„ôH~„³D'–“ þk‚XÇ â'e•ôC¼÷'³D‡Kí:A,©$ž_)¢ô& ¢:¿ GºÅó1`e”„Kƒ7™p¸Ç8Ñ “þ8é âé›Íθú8Y̆‰„£JU-ÉÂÏ&a¯— ÐoÒ㄃<ô„¹M$Òq‚oIt5ƽD¢ÙP¶DE§f07 ­ùlpvñL$´Á<™cäˆCFß®ið¨*^tl.áË”Ö=§&9X’HÈïdÎp9Mr¶ôh:GÉÙpÒ ‡”'¤ý«d?$Ä x<;<Hfó$ê— àáÎlF󖅤ī$hDQÂáÍh©‹g<ò8쇳å£^OÎΨÛ4–q”HM„,=J?žN£Ù³°®³˜Ï €ñ4ê¨c½ÅŒ¥%ÔßîdzMø;$„8r]ŽñN!©3OÆqè +¢.ÆÑýF“G"6r˜ä¢É3zr‰¥ž ˜!áto1&€_QBý|ùüˆ&ù#ÃjQîd:‰“¹„ŒKzO&šÑQÕ“éµM“‹xÆ™92eÆ×ãn2•P×»Ñ+¡9šõ‡4õc@0Œ¦õû"¢Áª˜íŒŠøO×ùÍɘà.Ùv±¨9ÄrÂaŒ^ '!-ßÙl2“Yæ˜ ÇA|¡°”Òç‘Æâ°h7J° þB5áH–CÍ¢˜ Ç‰Ž’”ÄÞ”tÑ?,ؘÊué÷øãëg„áÊCk µñˆc¦&¸ÉÞäRMûEÌ$Šú·7ˆ1“:_rF 9MqDEÑÛɆB䯻ˆç“º¤º?½>RH×NhF;þ=ŠðLpˆ(ÉstMDcԅЈÉÕµ´1ŒB¬ÄÑ#b Sói@5¥•|IHÚű½ZÛ„-a¬Æ&óC³1"üíÓš˜2•¢ï´F§Ã" ïF“Ÿƒá0LhzzÈ7Ÿ0ý¥¥·C« D„M˜’þ¼&BÔ¹‚Ë “9`­"—H5‰g]B\ÆØÎ 5âÛ!“í.¨ㄊ¯šp Ú¨w$诃 êõ¡VQÞøËþ-µ«“xÉ”)úkÐc,BU¢\¢iP1Á‰DâM%)pXiF…„0÷'½A@GáŒ8×ÿ1¢ã¹D¦d⎦ÉbÚþF£)d"›Ôç"Ÿ¢X4«¯Žö÷PÃk  ‘ êEÔýFÕ#f—Æòw‹Q‡ê•ÀhLü‰ wŠ—QqJ/TÌ“Kè-øÓâ§ ^„Øqt^Ò¥ ß„/žG¸Ù˜§u<™ó„î6H#A4Fmâ@®ýú“5ùB„Ÿ°xhP=™9L§P‰!FSÞëÉïYô…ÈÑ<|]'ߢkÆ*ÿùæÞ!#ÇDþ’0Å·Ì‚â‚5ÎÃVóÖ1Ì5×!  UÉ@Ì,MàÊ d¼èŒ¨Â&a…›39âiQPç9&&V8&aå’°O†Òˆ(¢ÎïP_{‘AKŒYP}{¥YÀ°'«½;Ÿ !g˜À¹‰Ÿ3<nÉì)äbB6I|'êÅ‚2ÉjO67“YØL’ø’WÄ,ê')Îúé#¦Z¥ð<_8(™Z²è‹<ñLÐdϘÚë¸L*£ùœÚ‰s”íé5-þ­I Âã”ÉÈœ-ƲH€,³˜ëÿ‹±¨w»ûÏhªAþ$Aæ]’'.2ŸèBTD?b®€f_“÷‡G„ݲПNæ ÀRúkò‘Å b=Äu»ÃEŒµÔ‹Ž—‰®Ì*O‰àÔ*)Ž/Y@PÈ}1! NbùJáˆñeÑ!ù%AÜU™4–åˆô…XD¼H !¦üsB½šô„Û$á„«ÂÐ7êCt5¥•˱{åñõn²€d$é<•Xƒ1¡ŸÄeåá?šp&fl´˜Ç$êÌΨûèò¡ÐA‘FÔB­åðÎSo’<æS^/4?H ó@ˆZwùgà#¼Äï±°w’ë‰À&—Qç-DÐf¡)ŒÑÉ_Jöо'ðY„ãÏj½¼YÁŸ>…Ãéy˜ì1s£½›dô9Oky"‘áP‰ž`-³”æ†4ƹ‚ý! æS–˜JJ§çç¤!€ŸÍ&ÄMˆ»¼¢êÝOv˜Ñä…ሀ‹˜f°íD6êÕ°‡Ö9QQ—ŒÔݧÒH¡ž1Ž~DUj®X¸&¸}SkŽºÈj4xzAä·g©´ŽlÂåeähFÂê৉î4̈ êQôÀ¼˜úøL‘ú…’lø‘1á$}’gI”²VBàŠÁT˜üš$ ÕL¹‡sæD=!%‡ãn4|ºèo‡Ò'ˆpIÕ w£!Aq†“`#<dS¢ÿÒ$h}U¿_´tÀÓÍ}ee”_j…\3‡C%>uSk…† 1!ºTYù› < ‚ïÏ!úF †ZNQõÈ(XËéðPbÖ’X¸ÃÃ3b8ä¾ëN(BCh²3O6ÇŠ`€ (¥—HÐfš"ZÄ}·,YE¨cV%\]ø"­é1iƒ—2¢þŒÊñ~Aÿ’Ŧç7†\Å«Iœ°„…ð¥JÝÑ“Æ2„n ÷&($ ‰±J¬ú>Ä=±7Г²<@ÐG`÷¤Â´ˆÊ⥚S£–1H­ 1z¤AA#{Áê D€Œ2½Mˆ]dA6Õ¾ ËDî @I\ûbÀià¹;g×8ü1 Å€*îJÐÀñóz u¯L.ùùx*¿»X¥$Åká(–žƒÄóýrò.|Ç•lW¦.²Xú3ÌKªba5_kaq,xǘM¢;©È,ƒ²“0©VÄ‘¾*ºHË$y¹ÄŠÄÈÄÛªo&o(uÓKŽÎÉá€ÖQòºŸ0½ÓŒ ´öèè=‘àd@óOÀúI¿³ Æâ°¢Se»À>M~‰dɡɚ÷'$â²®ÎÄîôþ¢zÁ¢‡I§ÃP8¹Œ’˜9ÉÞ=˜|DQ¤r—— ³ñó™@‰0@ifAùÍáÁ;ü*Ž*ØÉ"Ë`tÆ %ã%‹)JbÉX=‡R…R2LIAfûEÁe£ŠUH ¶³‰;'ì–Ž¸,‘·uÄåŠwOÄåÍZ³ZÏE\þç?½~— ~HãÆ(ÄJ®+4›¥c:Ñ9aàd–&ÔH¹×o ‡¿!^û?7q`äC„y? jg€EH/áÜ ‚%%ŠîQLFÚ†ŸOÃ%¬ÑD=‘¼«‡ø\èõY[µÜûkc}=˰b7¸ç‹ÁW>Ý2š­|[x³1ï° h×7fÑ$FÒLrc›OŒÐÀl té§iÂ.ƒyN)UmŒ©E,aUå+Š#ÓB5C…J…5Æ“q) žm¿ŽÝ[å::óŒ)X§ÝF}¢Ðalô‰øN.ã&RǪÀý»]*}âé mß5,Û¸Qe Ãu]õL¨ƒ‰©J9º¶T*cÎú= ®÷z Zê `~«àáL†Ç;ž &R;bƒZ‡ÖHkK€Šá»”w²DCt< ŒÆÎ«W;ov¾(À f¨ˆU?ž…©á0žô »³q²vi Ž5·¥°A¢u;£.Ñx£O’/Z¤v±žR ‹V‘>³@Îx”¢*ZA1Àͪïâ˜ê8qBGæazêa2òWJ›GÍÑ8^Ìx‘YçãéàîP.0HúÓÙÏH6NGäÖîãŒQÖq¬ë"ñAÂçIµ!7›Qx Œ \Ü”1évCèÚ„ïñt0O»ŠÍ}HßÏú*ÕðÅjœ‘±5Ô½´À~gƒ¢€ñj.hº³2=jòÐw×}¬ºPáQ8Ü#M;tq©Žò@ªvó4î6²gKÇR]á¤ûEßõ‘oÝ -&PXë6Ý”¢†A¬ãùUÔ%NÇÔŠ ¢îò7YG.vX¬Û«ÚÉ:£«2ïÓ¾µ8qÉ¿ËæÂs框2˜`ÒDØxÕ1`À%‡ˆÂ@FCmÀ€ðÀ\¶(¶}¼G±<Œ¨°ôŒ(]ºG*z®§DXúHÌnWa=M[âe&¿}_Læüú˜_‡òò„_Îè…iwÏB}éH0U¹Ž´w]Qk¹öiª÷¬ `&¦¿®ªÄâ’Ž®³–:UÐ5 Ñ›P¨•‡õÑ,ÇЇ,Sº d¦°ÔRÓišZFÑ Þ²ÙGá‰Aò I¸¥˜dMcNˆÒ<À¤¿˜Qš:V—bwu5QÔJÒÓ¬ô<¢îçã³á >×_Ño=7W‰Uqº$w¢Þ)P1Õ Á„"bCHÑc]õ––*ñËÉv‘ªŠ*ÇשƒBAØ (+FÉU÷ ÜÕîd&"6o¶v)nö4Œ…@1QÅŽDK©GIHT¤ ŠIz¿÷6,fõšŠ?–Œ5-J5 Q½Ì0Íñ{–Cê’Ueðª"8` ¥4![>vZÁ¿ïTÀEÁF¹7h—j7:Ÿ ÁŠ0ãPUJbX³¼&dAs<+·P‹š¥suV!WUÁæ~ü.(-µxÒéï)œX!ó[kßaÌåGDîE4ïÊd±˜J"uÏPöÙ™u¥y‚)B­«W ÷~hÓï©^ë²~Î'kVµ“õ’ûÉ –¹oºÕlˆQJ͵Z#.’…©ùʨ„ 4h‹>ºbb°6íì³…j`×i:ñÒÈ(ü^h¦)WݦšN³¡eÓi¥_ Ã?ÞÚmå{OF V´ÅÙù­ÆÖV»[ôy¶$òhw«–çjQ’ïߌáôsŒûFs«SK ã;´š—óí–¿&Ó/hÂ!ÒßC I0›,ÆLÓH®¥dôhEÆLi2ƒ˜L‡‹™Bx¦SÝùðÚ5XÍN@¤[¨ï/’8}½*Ã:B9ÑÉ4sQ:HZ ‡,d—²5•c3ƒùÍCú ‡¿¤Ëÿ?a(eİR£®(é!Ï7 `BÚËŠä¤ î—ÊÀ¨åï‡P,ƒ “!6" °4ýÕ–”Q(Çk +rÏ\¹MOIç#ÀÄÄúž4ùdÚŠ‹ìNê(ô»ŒI‰éi3‚¨Ç'0|ptòù¿›*áH÷ŒÌ5ŽWú'²•šäl:fUcÃü=7c98ÄæÿÇÝÿ/àî†ñn2W¶ ëÉ‚H£84:¦cÞôZAw=M®FjJÈ!@ ?#\Ì'#X„‰–]ß‹ðwÄ‹¿.„.½—*Vô0ÆèlÅ«E’cÄàÎx£büÓ« Ì" 2ÀÂ)ko Ñ׈ÝíF„B£ÁXè&ïsk„RA—\U¿|¿-rHF°ê›±ý«¯Öjgl£iXÖí†gS5›ôÑ#¶¦äÕv`ljÉBñ¸”·dÐa¨h.|«5xÕ°Õ•ò’?ßÓv¡¨àQ,œ2\WÇ!üX\Ÿîýtã){×¹Ia»¯Aû®¾ûÛÅá\¦RV;›9¢8Ï Cm{*§¹Û›Ùˆk\F“Å|º˜£Ñœ3¨t,T­rm¢|s#º G9 WÆ‹}†Ý”Ô^i…ávy¢ sÕÓ|]‚~j×KU7S§*°v©è0ñÆC}Æ = Pö toU½"zèqbrקÈù(ÍÊlý 23r¬!Á" UûWŽÖXlˆptí¿”ù8ë-™=Ì8(ô"¼5‚¹þòœ+5hîôzìDGS›‰ô™5QºíJï¡RÄ´°ÿr_$_ì Y즦sÅbBØïÌØb `¾Êa^¦Uq+9ЇY¦©î1 ïž£‰\û´E)³±º²…F©Å¢[°.­4GJÔŠ‘ZƒV¾m4} ú™OuSO4ùn»ì ka!¤#·ßcGˆÆŒÝCï‹e25Öœ™OXܰ9·€ÇacI*Œ°”P_ÜÑF,«&©À\lÈ£(Ž•E%,{ƒ¼‰'ã‹8 Œ@ùÕM·„­M$r-0 7ªèÃÚû1½1¤“Mƒr¡\“ÿªÙ!ºÎ˜ÕÌè^áxœî“É@¨Ñå-{\F¬‚U ŽÏå‹FÁnVAþbE?£<ñ0àÙkˆ»/iÀ±Aj0ZŒT’Í¢$ËÊåÕ,Æã†ápvm,¦—ᬲ ±ìò<)ÂãîÁ>‰‚ãÁt!`¼Êʹ7²ßw7B1Îç³R“aoð#¿ã´²¡dè«Øð~³èÑv»qlÉ$hOÚ¦QÐNc‡¿Ì'SJÜœ^©w¸k¯$°2¥xiŠ@©I­È‚4T䂲a=žY…AŒJÆRÒ¤‡º¬øq‡W¦íX@LüÙ„å¹ ¦{ÀIÍüëVë®8X«­}ž¡²£ÑëÁÿ„ÛMzÍ¢ËéÆb64xÿ“ÜYðö–EÜl@8‰†, ¥µÐkÇÆûWïí¸ëî»Òu(+571Ð}Æ_¢=ÚñÍ…SסÙÆÝ*¹;•6þí¿Ø8£ÉØ Ð$ŽêuÕ«°ý=(ð.±¨Åu7ù'_Oëù·_õk…•Êé‡rþà ýO𩈚–çKµ?+wvÑc¦ [¼öV[ö´Óly¸©Œ€Éq³’ª1»µVvUÓ|y»XŽz¤ß3Ë:vþ½üÊLó¨5ú9,eI‹øTDʺ½…¸Í¦™¨Q&oŒ²+"]àð‘ö=ÄÆq:ü´ø»É¥lÄ£Ñu¤G”` 6‰ì…WûIí+ ÅÑüù¸÷9­Âs¸ÖÐZÕÒïÕÖ. HÄvHÁN[ý ÒÌ”Òæb7…| tK…·BLÅ(³DÀ"0&Ûô”º]M§¤,×+Ã8Êÿ”üž $ùƒ$¾á’QÎö›%€žÙ®˜f5¹É—<ä/ª‡¹¾_Ä;Ϥ 'ž­ëæ›#/÷»­éœ–-j[œù1ÏUÆcÞ˜R›?‹³³(7ªédº˜²Eg*^Q[ºÃI¬ðnÞœÒOVyøÑߣœ¨å… ZóƒHÃÆ'8]|}NXjü.hå„%tÄ›v¨ví¯ «ÎŒ;ÏV™’^'¿"ª¢5A…_ü›¦òºéuØ<+S(¯\åÓŸOµ£¡vÝÉXg+ŠdiÑ ÓJhÜ÷T¡ËÒ×ûKâˆÀ*\Q&K¼÷:®xÓ[\”Æ’§:E•ÚõMÕWÓЖ‚¸f¬#Ö}°Ž2¡n-uÚ•’Sa.W®e½±¹êôš.À»Ð•Í&8(·’@r©–4O†H«pÌÖzFЇ|ˆ½•ÕSnp=„çÔr<ýUzÿu°k[³¨Ãñjœ§¿c³¾Ê‹écêñÿY{5ŸÉ¥Ö9§êr‰ €\F_&¨Ncèóßr /óvŽZLsé•,óšûRå/¤’äÒ¤{ç“Q”K”ÞÁ¼“›Ï'Z>lñ‡Wn}{ËVf5ËN5!û<ìä`SV}Ÿ+G Žt4Š»yŒËÖh6%­›ü[Ü“}ð.ÙOU,ð‰±© j„šlŽÖ2Þš¯fü;x Óß/›RÖ…áµqNðæØ L™Z½K’—cXàùÅŠ¥º² Æ)>gôYàÑ‚>®°¯O"šä§î_¬\|a¸Iûù·}Ù½Ms›Œ¸ÐØ×ו7w Á KLf=œÿžm;ðµá i8(8Ù”OíL¢Ja®O²]Æ;M#ÛYÄ.Nyýña¸éƒãÿ 쎧ÿk»uHý?‚Þí2w‰t6žð?DÚÔøxg$º£¿ÝJvsÇì‚N.¤³ü›Tš“Wó¬‚K°þ–õùü¿ÝbüwãÓÝúEïo÷LqÔ°÷îS‰râé/g@‘©•Áê¦Ì lÿU’²0ø¬À’…srñˆqÆØ„OÆý¸héð¢×£R»•иõî×m½×tÿVðv•n­âî=Lƒø‰¯dÛ©‚G¶úµ×º‚|£:/nöÑŠŠärÕA6«€cy…Uõ,Wºû³ñüýœ¿Wû7i"|¾æIFÖ(œuÏ+Lí‚ 8Ÿ\¦@J'u¿åÓr»*¿Ó-0þíNV–›4UŒV4¥[9X5Êé)«=ÌvÃÒ“šÍ<&åOâÅÂí 0ëNV>˜KjsÅÎgWVŸ¦QÀé‹Â?õ„mÈŸZk…áäw'éj•êÎÀtºd´n/‡[ûŸ°ïÝ­Àb÷¾h|¿R¦n4øqû¬Û òôq ziTáwøà‰ö7§›;,©8ÚÓ —6 ä©Ó’ùí¡(Éì–E*E¦¥)ü8h«Ç¡öbø [ é¶êŠvËŽÊ9oehZbøE¥$E¤ö‹á 5¦ÀðfV?)u¥â \,<Þàô4szÀý®¦*ëI™2µV«‹Àéå>å6ÏÝï)EëN¡'ˊɸ†ƒ»Ä•BcÑã^ ÓMÝáÀÎÏRFTó L=aე© Øõ…Iyy=•ÇVW;ßwc¥=A§€rÖŠleÓáj‘ÝúBËYn$+,S±þ–ÜGì{H›ªíšÜ»¿:0¤”Ï|šö0ïDD¹R/óUš’ ;pÇêtHh+¤ÍyKMbâPUI’xYäSx±?ÐÜŠó«—¿2GáŒ9üXï±KÁ´¹¤tï‹»‘î‹g1‚¹=0Ê››i_í³ýêÖÜûh» ØeW ‚…rкîpPôee‘au9IŽyev3¶‡­í|>lbæ^5 €¿:‹]¤œ€飚*3ÌÜD£„…ä ¤¯ñôáÌYyj.—_·¯ù¬ê<ºŸ¬i¾p+EU8n«ëÈòŸWdNbè›ËînåhÖ—-K­[iúØ*º¯Œ—ÏR×B'G£ôFýo.NÊ[©úFóØ4L*h:*i16Ñ&0«XØ(¤;÷xW¬L·®@_BØÄØd\Ðéê¶ÁæCLSþe. )‹Ðž]ìþZH/‹,@*¾›g-ÈÓCÀ{&— ® ·ry ”Ÿ¢Ù ­D~ø©Í°…?à#Å)såg8c“è¯| ã(ÊU„q¤Â‰FôUL_íen¢+5pòÝ[þóžì9¼R•+¢ ,õ,0yËÏÚtÍw&F³lCïÄgÛï‚vÚŒ4¢Dy'G†Ve°gLlW =«Ú›ÂÝ_¡×yŸ€[:3CÄÎ/ñtµ·[÷,Ú_-×ûHV¡ÐZÙäëN†Ãp§|^=Ýàó· o³Ym4ýê}|riˆOHY­x#뛊Óxe4™°¬:ýýWîy¡KäÝEUZªß²4w@€quï{™Ë"ˆŠ üíÒûÞäž‚ì z ™“Èâ‡Á»!ŽÇp×_?÷0©I.Kòãyn³Y6£ ¥Eë]ÊÌ9FŸk`ëÔôDí9ŠkL=-ye#[á͹*@ȇìbÝJK/n±ÒU¡¯%ª&ª­^O|1#¥ÊmZizºGzßít^÷Jîez=žOpm¤’ÁÒËlsëùÖWá£dnßA@ R*©0GpçèÝ?æ.ªS6 ÉØ‹k¡þ7ǵB@þ¹"’><ŠüÄý—¸âªzî5SÜ’„³ÞædË;ØôÏÌ=gñdõáï»ÐÅQ Ñž 0uÄ|çêáû{Áý€ý °:g™cØwåîKQ÷s7Üöpq庾,c꺊+ÆoÜÔ*¥˜t[¹[v~ÙVzwð†V¾¤­H¾ò¬‹]Q%­g>™ê,ýE½•ªÕ̪E…Šbé_5z¨ÌOHE5‚¼v·åÌÐFm¤éžÂÅMi½hUÛz ó½ý*q¸o)Y™—‡Fˆ‡=<®Ñtn  f‘²(kG×óŸøu¬¸uô3>tw!µ4[ FCD­™ˆZ, ÄÊ=(…zêŸÌ)V½‹Q@ÞVWú=›éÀÍ!–©t}$jC¤`#+·µ ºßø:%\ ÈÊ.KSårG}XE·©«d(pVö—"&Í2Æž‚QÝ)¢4NuMmk…BÝÑò TC®Ñù/¶®6–ð üÔÑ뻳öàÌÙjêâ cš|Î2磵K$z®†A¢²º^Ñ€$§ùØÄ•NAJ&W¥á»ß†Ù"ÇßRf³*ùX·$‚Œ¿àßÝ-zäÌáW‚,ô1SWXºÿxóÉmk•‚|¶ ÔezV—‘`½ÊŽì\«wøÊ®=©´9ÇÁßY*kú™3Éš~“ÄÍÍʽÎd$n—ÔE9ìVÀõä/Άc¡¤ò-‚|Q_ó(‡©…·ê!˜QUãC÷ä°9iôlá3Èo'c\äKk%œ…cW¥Ùb<Îݱñv÷ù†‹ˆVz ŸKz“Ù­ƒ6©ÞN3™R é™L‚<ÿ×T-Ü]ǬÛ5æ•ó}øŸ«²º;úB 07G21¢ÁóÃQ‰7žÊe1Qm©j®/‰Sãj+§¶Ó¼t¤î&þ»²ÏT¾¬µü­Û•ñŽÆo–®ØÎa=“ê‚>ÿ¢rpšKØhæ×spn+\úO¬>cZ°Çȳ=Θ ý’;¿Ã²³ðýΰ0G Øa>=¥ñçI\äS+G7ââo*ñ6cx3Imû²Âî7}’ýuW» Šÿ’¬9ºËª¨,hœäZ¹„+AªA>W±p2;ã?Ðx|OsÛ·•sa·`Žq.DÙ7W­i®V ²éèmÅB!Çrðjjõµöp‹LŸí»¹5 ݼӜÔ9¹›Õ†hèfð2ò3q‡¸{‘TÇÑÇÐH±ì.f1NÆå«ã N­œêéѸšÕŸao^Ûj&³.ü“Åä- ¹ N/+½‰ÍHïýà5:ˆ³ªÒ;?rг\¨¡ý1ÅRº¹ÁåC¾m†Q&êeUñ-›vJ1p)ælÅ¢¢;&1=Òÿ_®X㿪ÃáÄÜÒaŠÿÀºáÛ6ï.äžòÕÇÙÜñ©šÜá¨{ŽLYªèjîR•uy79ŸEÉcÙ:S„Fþ×S͹:w¤ñd±äê[;‹³íW[J«\‘¥€{–¡·÷C%ne§®}$ÆŠ³Ï|)·æÿƒeý÷Ë™ %¿^п\ÏLDÕr^]ļWöÐ"ÆUlñ8†*›mЪ„Üœ¦ŠÕJWrâÌó«9®WypñòV&Ä`ãjÝå Ž£ëŒžáLi”ÁïβÒ÷ë>^+•XT,•žÐôø9´üA9œùÊù¤=¼¤òKþÁU„(Êÿ Ã˯ …QŽB…¿Aq¥²X9yÀY!r¿Ú ý›¦掺Õ|CN^&±ï£ïÂÿWÉü~z‘pG-Œ_ļ¡ÇwÅ@â…g¸“"å¥r5uÞ ÎŒÏM§ÿÅC Öðûf[Vf”ôW-þË[^Èþ{°r-Ý1f,S¾Æ†;¹Ö6ë}ÎŽ¡ñ v÷öïŸN öŠéñ6¡ÍK' Ý»a Y9`”é„^Ýð¶še¯Y­­è„ƒð!í-¯N¥*áà ý[ ”õÇdÐ㛑s—Ûòèc75æ<¡ÿ¡B—ŸÏ­ß0r3¦©ö}zÝíql¦fóA÷@›7ÅNé3D9&öúM¹Ù‰jqŒËÉì=²ÿP8Æ6‰8bA&p ìz7u=Ølknl\„ñ4»ÝÉhc•c"©¤öJRŽ8ÅY‰Q\ßÏ["._¢Å5 ¯'‹ù?ó|ZåPé,¦+„ØÚ#¾£~VM)Fæ¬M¹úÎfv”™Hrž<,MíÎÂ3[3@_•nS¿J ìYµ?‘R“Ú›T—#]¸‰ÊçÔÒWÔTe ø¹Êkí¶¾˜vÕŠ2,º5é)ž«û)¨‘HŒÜ鞀ÎÂwC¨€€4°Mׯæˆmvš3•aMÅ7ƒÁ媰œZ÷áužò¦ÉU“Êí¾#€ñÊ*û·»¨ÇÄG TÿE㪻ù†óƒ•hc–™ÚtŒ•a¯dXLMǸ €‡ìåȲ¦”ÿø¿éŸ\ÂQÛˆ‰TÄj»u¶â‹xc3ôª›õ-³±¹µåuêýòV£ÜktürÍß }Ÿ¸Èß·€µZ…7+Þê¯W®øUÿžçUk›ž_.Wÿ±é—ýŠÿcóÿüðÿñ–°aüãòò²”‡òýÝ÷ÿ—þÓbIË Å÷D£(7šå­œ``ÀZ +°RVÁ¢F´í]ti|DFÂ@™‹ŸM¦×âoum®Ýx39“ÖÎ Kõß:¸» Ñzê¼5ÿŒì'Aµ#ÛF\¨IÏ”{FkPô›vkàj÷eVP³íe{4´6 …œI²ì¨íBö{µ¥’=ëÒÓî…çìÚïíó°›5/ÑÍ3(aoÙkçš®£ ÇÇ×Ų=½e{U2ÕBíËð2kDî²tÊÕ/Qa‘_\™îp޶ªòri,ñA}z}·ràâíÏö+cG‚ø.ápyÏðŸì™»zÆ!KJx–¿u¿=î=²[nz|<·‹Oìî·'½G¦ßþ°ÐzûϲSó)ÛýÖúãø¸{|ìRtÙñ|vµJxW=k½´bT‡qš¶_X±ëÕì;v·ëîëÐkïõå Ë;3â04ýÀ?ÐW®¿Ÿé/¬Áæ¦5 Ý0M7úìvŒ:N­.>zTEû »Þ>tk%zÈÉ~°#×ÿ±r|jÛ®ÿå*ÿÚqØí-—o |öU}¾°¨¨ŸóÚ]’_ï˜~Ýl™•ÀìI!u·öžÒc¤]:Õë–ÉóÖt/ZÊGµûzé¼nm9ÁeK¹žŽBxäælu¸ÕŽzKÇߣؾ8G[Ú‘[„uøï^:µ¯’Ûjû—^×»t½k«îDÜŽ¥ó®•*ükSÔ©ŽVå–mªvßêonöÝêu®Ô[}§N ½×”pÀ¹(q{×û†ÕšMp Ñh~³·z››;Ý~ššÞkœF ï–íXÜ…£ãð8>²ï>XÛ±MP|mõ;u÷S«NÓ›>GÔNdpúÎÈCz4ä-vxô¬><£û§Ç…4åWïïソ¹ÄŽÇ[vDmâa@ÁÔvÓL1“N3^õ7B³Ò4©ÇáGtÀ­ì?,KúÂþÚýŸ„¡¶[}Nùì6 ešì¨îÎ %CÕ üñ‚^½ÚFذ£b(¯u¬^k‰§û™Õ­÷Ð[F°úS·ˆý²Ó;ªZª«ÈASb\leŽäÙ…¼ë݈Wø.Š[^WƒÞøªqJûwß¡8·öžJ¬þ†4L”Å?2T >[^Ó9pÞ;Ê<ºFoSÔG•¼öü—ä$o6ÖÑvγ{/Ï{]%‰UbNYýþKʃ_RºþKiù8K\¤éŽÕ%˜;þwò¢Ϻ£ú¿ƒÔZÊäõ÷¬r÷[ñIÏàß²ëy”‘PÍõN-ÓuMûIÉ£‰Z™ám м[*;AÙCv5VL.hF777(ñ„ «ЭM­Û©že ¨Hï‡i·«§LžŒ bPyÙƒŽÄ¤HåZ ãpˆ6›L°ê;Uc½»ÛÛÀŒÄKøq ‚—Ð= Øÿ’a´›ÀÞk `öá¾>¸¦}°¨±˜¢¯}~%ªDö³ë%VÜõÀ)¨Ûïé§»/`Ò|Ûˆ+˜2ñìÓ4Ýqƒg}g„X‚ë9¿/ Èy‚iÂYùª§GErj¾Œ‡+œš¡oŒ~˜•Àóµï¾¦9Þ¥GÉ#Ðlh8¨¸šˆ]KP%ê0¬{¼Õªo„}&:ÉjŽpU4ä”îfü¥e;DG"&EÁq¡ÖÑbò ‰xø\åÞØˆ¸×'ŒÏîë'[K§~´*:xNhe#L‰$ë2SV¡×‚µ m`ÕW¢È¦¿m2>%áÀ­UœZ@LËñªôåUÿ=ß‚un—üO&°€èâžñ‘GuúŸ: 1ÈoE¯åUÝ×íÑcØÆ¥¤Lê½* 0sgÿ³}¸jlŽÝháú7n4éëžµ(Å %ô?Q ýv- .D}Xµ¯À]KˆÚ ñÂ?oj•g凾(ç/õWöí~‘ày\h¯È’&ªá¨Nè_nn–«oÓê>ÏκûÖ& ¯¼ -FªŒFòI¸„†"Àa}Ã(äq#þºc™Í&FI*§’>ç Ö õf`óDÛˆh¤hšVˆ¥R·‘^ÐȽÎãJåeë#1ûŒùêýjT¿Ó›ë{›-ž´Œ2sk䌊Ðlž‘;ÂQ‚¹ˆ^ˆèïMDMýÖçS@P³AV MsQ Ü×R E£þ(KòIZ!~:ŒÁôÒ2n} oÝê3ëO‰/š¦Ó¨ó,Ž B™“ÀrE 9°¥ã¸ü:E!Q\E½wTêÕýR~OžP3´šÙBÿ†ç}–•8ú3EŸ8Cç”*çyEMzâ9ÁÍ.n7ö]p#‚æ ˜ÎOtãÔnÜæ”†‰(%±èÖSž±Ì;2mùnÐ@³òœÐŽR¹ÁKËô}4žä ДÇ<Á¶Ðdð/:‚G IG¸õ-±HkuEHØñ.(çt ;yÃâ®0`JHN‰…Xv;0$<PEµ#€dÙVZäv¼¶_µ#kä(ºÙ-øjÝyQ _NàµÞ;ÞÛJ_b¢í¸Õ+T>KÓÈ­½Åoå%S67*¶#fßuàýKÃû ´+’úÑxµ¤ Ç¡ˆMãPºÝ½&ƒênéŒBÏ!E¡é¾v*7!U[͈CcϾ£°~›Ó{œ¾M4o¹.ø©÷—& %xa½Ã]½]*–,¢‡¯™’ÄI„•ÊõlH‹ ¡,¼zU>„Uÿ$sÐSØï_Ûµz¯Ülnú×\¥Puoø×Ðy}S*'JS‹‚_S n¯u·´©H!Wþ5s.Iï_ÑìC)Û¥ÒÌ"ÀæÔHpª3ê‰S{––:ÕQÚxZê4¶Sï6­=M?JïïòÈ ÞAîxÇ`áÊïW25X $õÕ$Ñ ¯!'ÜÉó2ð½ Ö˨+‘û•¦(A~CÈò7RüæÝ^ç%“æ¨*ïT& t½gœËü3dörá¾7 ¤š²œ‰Ymòœ©]«9sH…9Þ…–£óÛÞ1>Ó›•+ ³É`6{³0"pÒM´CõĨÛ}HÞ…Ó‡TН:}ò;_µÂ ùªÑWןYvHR7ž”¯4JLLeîh~Ñ8õ;ÕYkÀÒÇ€Ä0æ ¶¼‡Åbí5x*Ë„ÞW§ø)8Ø—VaݸGh¼gÄU@+R¤lðïjì+ù“k¸ó?º€~¦‘è t:‰÷ÍìÛLI¤]¾¹ó>"Ê[zŸ ÝBó«ŽmüX»örUèRôÌÒ “Nš[4;c} çka¬D”>žþ×$C&Ðiº¼§&]W³nOóo-ÅïÊ:—²µ61D'*˜´nDÀ#P¿o#®X¤‰}y%¦Aɸ“*:'PZ?¡ «[œ™Õ7Az-››ˆZfCí°>¶;„øþ£å=oݱ$É#Bõ‘E¡…æÅ²M„]ÑÕÐjAçnp„çgãY ù³c&1Z»±|áé³ìœ8ìoˆIäm|¯×dzY×!ê[›[T²ME’­&Ë;‘ûœ!JH W4"‚ëX¹H8(¡4à‹q—0>»ŸèÑ–¡kÜ[ Xí|ZJ÷il•ÀúÔLS¼x³i¨ï_»`«eVoL§zB,è…éx–ì¡+ÕPåêtÍjb:fíÜìµèýÞGfX[µoú넱Û’dÛiE²ò³pK¸p•¹0iøA Y*¢¦™ÕºYd$M·Úþ³µ8ÿÅÍJßT ˆ7öK¡ßtÑGÿ™Mœ v%VZ•3âßh 3ÐÚw*"øâTû@:Êã­-H4<(‘ á@D0:cç\fà'R?Q¯‚]¡LýsÑßs‚wnµBƒõ‘Ê݈@Š«¾e»&MþÖà½5!¹ ½KB¶Õ|rŽæVfÇôÌV²T¤Ö±¹É9¦¨ŸÜêV?¡¹eÔ¿õϦ|ƨÃõHÙ®ŒÊ#Û‡· Aç››Ÿè_wܳ“æ€ÜZôc=‡Y™íq8f¥Âên—þîÙP,Jz4½‚[KD(éë}eÓáAehÛP¨Óc±ž@òwñ…C0BÈ6MsJL,ˆglû»níßL©èK‹”Êß…„`ßÐ#ä÷“ë5Ú«×ñ1 „67Oº(‚UÓÓn¶Ð>Õ,T‚*BSFO²ªP>ä\¹Ê uƆ-—C·r‚ñ8U°:>.Áh `e¾°5öiJN OS~9eVþv|-ÿ‹Ýù³<•Kl°{ -Ë*8£÷¶ZʨUéµ­ž\&¾&˜'4¾ntÀtRBϲĵÈqB‚Ã)áõØ9EÙç46íÓðT¬Æ$„œÛgûŸ\°)‚íu§l¾;ÍÌw ž=ÞêPä{~¸Á¢…’ ƒ„¤¥„Á`sgá ¦}ûì ÍíRéÌõí¤{Fú!2‘Âe!ŘßDQÂ+¨æÝ¼,²†¢›Ö)DÚXF—"•!#ŸØÞ‹ƒ[†CÂII[››` _Á§‚O\­úbÛˆÌ,Ì 8g Ó”jªÚç°õÄ`Uç![ÆÎi’±ð\-ĤRdÞqXõKÆùGpœM¤±íT¶Â ÁŽ7Ô6§ö0LØ‚ö¥;‹UêLƧ\}ŸVâôcØ 1‰?kÎE=›& Iè®ö9gŠ!…·Yoe a•C¶ Ƙ@Íê*<ˆ(œX±ÿ’c¼_c*cÄ4þ¾_–äh|¹®Ò^…W°I˜tQ§ñé~Ô ÖGÞ¯BÙÚÙøh’®í6Ž Á4ÝCµÃ\né°iJ·W‡ílµ˜.6pÞKÐ[ ’ü"½€e«¼îC ø „ïH±üa:÷-³Fc4é¹Kß^ýNÏ·4 }Sªïç«—Ú½fΦüð$Ý‘ HÒâ%P]uã€Ù–óŘºZb­Žy¡q¥{Îf|ê~.Ô÷tèëUhW[E‰4K° ÏI}5ô°i±ÜEº‘ƒEmw†eª,1bõ5®ÌðŸ¹.ôw¡ìuæ®Jª©c¬*²Le<‘B`†€Æ ÆuNÇX°Ô¬‚á \ },yh`uÍÚL¾Ùcñ ÄdÑ…:è^)§ßÉÔØC×tÍê‚xŸ–1}ÒN½>Î%p5=9ù³Uò|æ–”}Øõ]~%Aå É+Dgr üQ.|ØvK¯#¹¯ÑÜY3éÛ²–ä1öªÓNÔKCå¥áW5—XO fb§¥ç€èÚÛ(^ϬϜŠÞ«OíÇ—“((QKRŒ¥^z¬þ\›°%‹;>nŽ “‚ËÆšŠAêM¯ìPÆ–e!ÍÇìP:$¢ñ %Èît¿Y°ñpkE+*Órÿ âW4¨ç'ÜáÚçx Ȱؚµ¹m„1LH‘²î0—DÊvDzÏ"SY9¬§3§üý΀¢g-V¤½…Cï¼Ab¡v/-œ©Ú½¶Õ7{¯»€j3ÝÜœÊ ýÒ¤¨^{Naƒ¶;e½€„äàÐùŠv.ˆ¬n„ 4†¶‡á¢½cÔbô8|ïgamß¹ƒ3ì½\€sÓ%ÚèõXMÓb{:‹.¼<â»Óm¬:û/íÜÒ†õUQâA¶¦öÕ¶g¬ Øí8œQ3JÁ™’o¬h˜Ÿ[XW‡Ë7wÔ8Ùî“â÷lf"àHvyD¬U“yÍöŽ»"©F_™´Kó/¸+Ê(³å#Ö>Σö™¨“ð‚šûßÔ\<‹f'†9ÆÙâ'uñƒÕž´'áDz9Q¢' fMh\Äææy÷D¯¶}MÓI®ÿw:‘4¤†1<&°ÕH½XÐZ pdŒV² ”’ucÌâ™@Ì1ywì4ä%0;v+8›MˆÀ8æO!ÏBF*–\\¸µ–çÀì´|ÃãÚ+‚Û¬«+¸»[ÌAžåa’Sâ½v–tÉ<—A-6gR´X;çiwc¶|£@1›ý›Ìf5OQùÆdÏbޱÍÔ#%«‘ŽuÉBü¥ëÿÕÂô%ïñå<—áÑ…î_iŠ+ÌÞqÁò9&‚jx Sz#¤ï’{ªpÙkuѹ_eù\Û‘¡ƒŸiŠe˜×b•ä‘ÙBÅmÞ5K_››Sû°ÉåîmëÔñ_µ†Nà³e–ˆÝ+õRyÖ¶Sì¦|ØÙx°äÞ†§¼[“?jDú5Ȇ9õC^²ʺ'¶N( ©{è">Ìl®|âÃ.×i/÷ª³óÐ úLËš„‘lÚ¡)bßѸŽ$u«¥ƒŒø<Ñž}µ±6ôö±„ZßÜ<Á¶@>†ÇÆïZuW':E½ó>Þ˜ Y([.9â=ïÑ%B-BüAéÊE[ídʵ1¶z}÷³ÝD½Þ®è3h`’Q½ «àÁgXjíÊ'dgv°¥×îR.¥Ï{+2o+¤­R—«C¨Ý4÷‚†}×§9¨ž}ÒÑ÷ÛšÂc§ÛgXÉ4ë–X¼Sö•ä–³ˆãìÜ !<࣠zlþkL[ñ’åz³11Fcl4Î n4ÎŒJݨÆFį́o4NƉQymø·F52ªM£‘¾Qmµ¡ÑˆŒF蜺ѨŠQ‹ ÿ•QyfÔÆ[£á Ϫ&ƒÑ0µ…‚'Û£R Û¨¡ñ~ÂÏ67ù=òCáI1½Ú±t4v[4žÜáUô+D¿âèúß„ü]yâ‡Æò'#! ‘ÿÊÆ…×ÔYW|ª#W*ß±$¯œc›qåµWö:äÊ?há›K¨6‘ù¬f¬Ö´qÆ;¡xb<«@¤j\dk”ëC(P3à×-»ûko”¶6DûÎtÚÁ*í KámÉ ª$áQ+*u^7¯c‰ÝÁµ°a¡7¨†:¾IתMnð®W´m·•F]œK.€g¾éu¼–¼ù@½U:~k 7)ò¼ ôŠz²K¤P#~•0#ëÌ‹Ö_oÝU.™vU«48{DÁ¶å” Qç`'‹]­ÈcŸ$Ÿ±ðßZf50a;n@”ûÍ8ÈÊx S%ùm&ÿV/¡=çó`”é aÓz°c¶ó’ZÔ¾7ÿ±}Þªª7ÿãö=œéß´ï̓íÓE°îâ¿]æõ²ðùÀX63’ºE‚¢œüå“ȵºu"»uOôRti–é'êIõ‚©ðD¾¶ˆ~-áÖ Ù(núïL–W—M²·cš¸J¦vI’iÖNÌ%”ôz;;…wâ¼%i'ðüצ³ßŠû|*Íô>›|g‚Y'„!ïµ5êì`sëòSN º•lÂ|ì]¨«>°(‰m”ê 7zIc¾´W'´q„—¦8=>üþiZæ•HYN¬»_‰â•½Yê½Hƒ÷:ð-®š² rBÂd“u‚-}¬¸Ãƒú™ é.¨¾Tÿ¦Q×Zù€þ÷.\ZÙ†³þÒ©¿pêÏúŽSæÔŸšk(>U(>Š3z<%Õ_ûiȲ£ÐQ¾Œ0œSèq.BõG>‚‘Çx¿3B€˜½Ï­X0wŠvóÇx¨µ}ç££Ž‰RìŽÊÅó ÆOŽöoÛÀ‡¦²FFþ®ÛÙ£1•QÛâÍDµ­°¶ú·[}cÈ£zâµ¶œúÏ–YùP¾)E7¥àS)º6ú ¥ <úÙo}tª_é'xO?•÷$â½áäþÇðfô0qìç1¼‹– t JSY˜N ¥?99B¼§‰æ¦S¹n™ÊLØ ÂFà0àܾ›ËiÍgäþÌù´î‰ãÿ–Ãã㎵™þ‰ÓÞ•³ï¼ ç¤Õñrã kîîonÎÝú ¯XÑ—ZË¥7™Þô"é<˜³+ïx;/æ—× Š‰°•ÑÿÛ¶ñ^ -T¦ªËvÇÜ4[f{zçnå]ššõ+ú0ÃŽœ¡öIå§ßU1û(d¿Cÿ9÷C™ÛÜ& Æ2k}Ð|TÒå¥i¾öÝ ÷£ø” ŒèŸ®¯¨vðú;fhOŠ&Nî ž(”"ŠÃÏ ³íõ±PʈµFmï3¶‹A'“ÏoËFþÔú9ìf#ì%;å%+Õ *í÷¾9°ùù^†àkÈv€ ü0wòÅR²naÙ"°§›vpbK½cþ]R³Ï¨Ù¾îÒyѲÎCÎgw~;h&•C1K…/Yýÿa¼)q°ýÈý𬣾ņB‘H‰Dñúë+çX̸.¶°˜A•­î7úíü=°íuШú77' «Ü~¼û;òÎË4£±p»µcº¼=wB÷Ô­Ä ®£¾ >…xc‹4Jø)ưèD)Ýc,ÐýòYy, ”½C²ïÆ0Édxór„3¿§ øž¿Äjö{¶Fx}·>ïøOúÜ2£Ä¦Ý§žªÕ¯öÀ­}°Þ:h0ýžƒP¼±Uñ~¬ œ¸•§Tj¿E&ÅÕª"uL³TýPŠ«*?»(¢G³-ª;FT3¢ªUŒê›ÿ3"àäûRjþ]j~%®RŸeÍϨÃ{ ,®¼Gao{ÕkÑt P´‚Üʵ½šÔ² &HDúçÊ–*¸Ô)•¨†ú˜™å{…U+dzj:]ÊÕ“[iôÖP*/èâ‘!u ÞþÆç‚Åub}u˜ÕÙî]…*‹eGX*ÛqëgÖkd$%‚–Tјú)Z(¸wM}†¸DE°hcãÐ2¨h틤ÄÀ4ug)™Y}ebÚ¯r@Ðf‘qàV÷¨G'4(æxP9NFë1 eåÄž-ù’â ¤ÆzW í)Àm —KýÁ«]•=â¥^ )ü£'[6 Þ‚Ý]̼V[ 0b@HHÍùHÑÍwŒWªmY½!G2Q§zb »<Ñ4ÆBï3¨ÙgkŸ[wôžéÑÃå ¯t–WÈòÊ<˜åy6à)•€'«$/Lµà^…õsÅXÖ¥¨‰K‚~)|wxoM°1³òB€ÚþGýç}„W››Dfš GÕËa–Õ®ž„õ„c_=n¾±±­ã[è·æëÜþ] "2 †híÔO[J¥ šD«ÈaC›µ]U$IŒŒ k›‚,´öem‹˜*³ùªô–äAÿMȧÆßái¶Ä| 7¼á¥g?ôßt"·¹Ç’6Áʳ¹¹%Õ? ‘q8‰° ÚûaŸy ®TaBË·oìëÈsû¼|j™Å}>ÉCÝÚ'Ùf¢ÌeóF¤da>|mC°XUšCù®ø6f‘?üÈØm9kÏ6çˆÁœõpu ¶HqqR¸åË:[¤Jù5Fàãà[¿éø@ûç|d}Sú§¿¥h*‰\iqÞ}>žÐ:å …ýMÒ„ÄSyz·ü\òhµøf(³å*gñ9Ûº[ÝáS¹, Ÿðõ.ÙNR}OŸùØ,R-Äù Öªj„Ûq–¶*$BNÎׯª‡IõÕ)áv$×þ@Åóm¹ )ò½8P½8P½8 ^hyW(ÏzQÝQ}È7_7 mÈê«7D÷õ/Än•]#È·!¨–¾ûí™Í©åZæ_HËðDËè¹¼g¤Qï²:ÆGßï†{Eœ6y±ê÷ÚØI/)Áó¬ì>”€[£ìü’àv½ŠƒäªX·ê$‘àÓÒñ±[ôÜ9Ã"½¬­;«[ò }¹{ê5ðÞŽùŽºÔ¨û÷n¿âƒûCÑ@î°£Á¹t¼á:øœJ-¬·?X—˜‡çÈÞ½Äfj,)/ÒT¿Áz»÷‚ʹgcðñRnUHÓK¹Á¾5ÖÐeèAœ 0S|b!BBx5%©T³¦ž‹z|Ϋôên¾dÔoX•š£–ËþEê½I½¹8ƶ“. fÇ{±B‹VÔ³ÎåÈ>È´ÜDÁG°»ÅR/´ykp\,á(—å>²ÿ,±í‡‰ë-¬¾Ÿá…¥r[}ìYrüƒ°Ïqø,:‘Ú(e_¨ó•šû Gw¬»qŠþA›Ê²ä«¬Ê´ùý¶Nè÷)n4“ I-~¡n”B³SòZžý(¦búíÄ ¨ž¾Så#ôw$›îÄÕµ•GÍ=p=}ûÑUX¸°ÏÄôÐËp0Ç’›éÔ =|YÞ¶‰òöñÕujö¶²}\ùÕ–KÜê·®Ø}A“%ÏË/ù4ظ̀%æPã«ÖÏ7E|Üy„mzX‚“c’î±T‘~ðI $ªWŸX#Çc`ËŽ4m[™‰ù•±fwŒð@² }§¸ï¼ÒL±EÌ .à;±1{=ÜÑ·ô›þ®o¹ÚÕC‘*m&”+Ph×+ÌßÝ×öw¬q @l}•R½ÞÊ.àåO,oÆÑV§ßºó^µÂïåø”ÜˆØwü«Vß©x-‰ˆô…Jͽ-Û±ë_á¯!Á¿RWtðŽÝâ ·úº‹o°áo·^¡|Õ¬´¿ÂàÜâe×uå±mmÌޱܶñ«zÕæq¨YwuX?/‰¶õ‹Ñ£K’ðÞ­[VÉoºÍ™uùÏïvÙ·‹[nÕ~ûXÈz‹EJ£õÑñ««bˆÂUÃ!̉ÖôAØÂCïÛø™‰ù9u WWvZi¬ºþW[=¹Õî.ý‰û-Îáí¢Ìž‚ %#õGh×¥ÈzÅ£2r·u8ÞB/ˆQ„”µõWN&ß¡ºCVE·±“‹o€Ñ”áz`ñlssö¤Ô¼ìÌZúŽB.‡q‚Ê&3Ãþ$öâ)}R0f(ÉŠy¡ó@Q-ô»¸8òÞ*oh²ÑcÇÃ4îo[ˆe=!0`3ä‚@NµÃ‚ü~!¸PÁ34 z!E[ä9¾Z׈²E ž½¶-“·T¢éÛV÷!BÑC9>*í#6ÃÐkX(“±§!V`”S€«¤ÍÑÞÒë [†ó‰ÕàñU@«´ó£b6/L¬wºGDÎÞdBÔÿ°Ö]«ÔélÕÂò"TËü4_O¯Š/.CŒsCáé¡à¤•ªªûc°A’Á ž­¢m…Ý•*_ö¨M.ý ï½/þ ²2?FŸ‚v†½*U&ª–å…Õu,×…äÂ)U; g c,xCÙe¾©9ø]:´—=(¥}™›J¾ q`+Â>U±(Zm†Î¤¬ (#\ñºR¼Ç;ƒ*ž[}×1«êi÷°ð†Ï–ã9*«½šE Jʸ„wûŠ´ø—`«ŠXƒ8wÕ×­»æ¸Õu#yDIÈ?XfÊŠ?Ên:¤~⪾õÕ ¾Ó@ÙÑ”…³a›o% oŽ¹ã½§§ÿÓ©~ Õ¡Mœ×lâ£r3’\DZ?r‚AHhAHl1R ÷‘[¿•j¼Á’–ààÎvQN¥zïYM¼`;‰íPìázì@ÇlÎ_’ðZßÑo6«QÌ‘[ýâÐÏg>èëÍmzs„â÷3ß+{ËßV³‘Æé©­n¢xÿŒ(&ººQýhûÏt'Àö•úÊwͦî´ ^åoÞ`­ˆN%jyó6A‘¾½ù’ÂÊ8®&Ü@êÔ­2ð­#lâ*kÖRïÈ}¤‹:ÁE ˜^¶Ç€~º ’"ø|"t2jpŒ£¸g„¦ŠU%žbØ~sbU¢¬íÕŒA—¡c6TŒï0Óo ·`€ÈßÛoGl|ï¼Ã–wèxÛXäziPS#9+옵O¸ÌÌÉ>?òÝf0#%ÖØYHZ ÿÆê4q›0ß }ºxϾç¶[-Ídâ3ÆóÝç<(É]MÌz« Âõ¡éó…O4šhúZ¾µlõ9qÛ§‡¥Ð¯’w\hVŽ ¶…EÏVaTFXŸÂjuØö*쀤X΄ú¤DN¿”gýâë~f|Bк‡X¸ÓÎN±‚-ªW[5±À,WÎÛÊ?>Þ~\¨&ÇJ]}q\èéEtLÝãBåö¸Pì·W7ˆe–!º{_ ¨%Ü:N¾…Ç!u¯ï6}kcÔ‰ZjµÄ[u¹Ðßnésó”[r¯Ôº£tï¸Ð¢Ç+jd¯º§ÎÈgÇãÕÉxl¥ÿ͉}ÕQ·öµøº¾ÊŸ5\Q™ÒA>ßÏîèöùLI$E^¾oÿ¨ E`§¬Í-•UÝ ÊÊòâö¾ßÞ—© Uu$´v˜«TGk‹U%ì)85ߩ՚N!•?8ÀJÿóßh˜jg!©¸ôHD³T|-¦p–“Â×_ ¿„)œX¦ðî–²#¨t8¥ÚÅS —d)œ£¥ì¨+e÷Þi:™ÆÉ›è"A“’ù"…˜!ÜB¦i6½ž'³tz‰êçœôU 'i<š_Žq±Ùì„‹Ÿ§W³qz=šÄÓëÞÓ•[¾4Šãôb>JÒÁ|žR’äæí0…WAnñt˜"jVr³H&q*Þl(Yª<ž¤—WóÓt@- žÔ'xšJÅqØ;®%\ÍRq²K-û‘F——ãÛt8šÍÏà+1UÞ¨¨ ×»á"e+pvÅ][:š?×ÀŽÆ ê;»Rcøˆëáô4šÄ”ó"Z Ш‹Ëq² .3ŒR%)\œòØ0´³ÑÉIÂ#‘²»ÇtžÃÑÅÝRçQÔüj—v){ؤ°Á)UÉÁÒT¢J/¢ód{6£q“°}€â"ºI£Éˆz”ÐÆ”[@KM<ážÏ£a4Q:j5{­LSøŠL¥$B–˜Â?Â곈°N\aRW“Áˆ_Í"†(µw0½¼MÙǧ‚#!×õ$™íh$w¿é$ÍbŠOn’ú18§Á£JáŠ2¢7‹ÃQ H=9õöc°¸þHó®&ð €û²ôÅî ò†ÕEB©ÓËé<…CàéÕ"LT# ¡YpyCµ'—éÙ|ƉGÜ—h~; ó$Ú^)Ñl8¦¡Ÿj„a4¬ß¯ê¬   ""ç—ÀëÑ„f×â){vM'wI¶ƒI=Ý r¸1z>žF4}g³éLFùÞ7Ó ªrô\a)…/Å3`Ðî"Å„úЉ.d:¤Ð,™Sæyª½$¥ìª8e·¢˜°sÊ7 çÇ{Ïà ”F| Ù˜35!ÀM÷§×jØÏæL¢¨}û£9Frq¤ÀzB9e¿q”­Ž©+DþWóÅôMRMŸ?½=RH×OiD)þòŠèDpˆ(É.€*’ Ê"Ê‘$ &7·RÇ8‰0W¨îšO#B¨KšÉׄT©öó™ÒÜ&l‰æªo2>pyGø}q@sâ’©ÅŸÑ™ÒôVŽz~¨™F”wþå`Ÿ¦ZŠÙI¼ä’)úè1¦ ¡*Q®Q„³Ì©˜àD*þ¦Ò)pXiD…„0¦ñh8"ˆ.’hÿ’(ÿCB%Î/ %h BÜ‹Ëôê2þ&—D‰lR›·‰|Žˆn`NШ¾<:ØG {@"©rl›Âg—Æò7Wp·žŠc4&þD†‰vÿT¼¤Ar¹àÁ%ôü‰G„xð™‹9@ˆ=OŽÀK”à\øâái’€›MxX'ÓwðHèa34DcÔ&ÄÞq·Ÿ˜¬I DaòP§b9 §Pñ!FCÇò¸%L£!"…›39âaQPg3W8&nåÒ¨?ŸŽ¥Q¸8ݦ¶Æ‰AË£ ÚöR³€q,³}°˜!gÀ¹‰w™ž·dôr1!› ‰$¾“ÄóT;MFééÖV:‹âÑ4_óŒ˜%Ã4ÃÙÑ0{ÅPˤžç !SSm‘7 ìS{j¿¢PD*“Å‚ê™ç(ÛÓ[šü#š“„Î3&#Spv5‘Id™Í¹ü1â‡Z·óöà|øù“4IÞ8ËbªgQýбbϡ黷‡G„Ý2ÑŸN À’ûkÊ^[ÁzˆëÆWsÌ¥˜ÐrpÊDWF•‡DpjϯY@PÈ WÖ‹²Ì ã {E'Á&RÌ-Õ^C1!‰x‘BLùç”Z5…Û¤âû¸*膽¤ÓórFü•f.»–×½ô ’‘„óPbzŒ&„~/EœB ŽŠðM936šÌ“TœØr“…Š4B j-Ÿ€wžz§ðÌó…º"âIaÈQë?>ÂK<Lj…½ƒ¬\O6½Núç4A›…¦0F§ÿR²Wò=õ€Ï"QíÁV L}ŠŠÆ—§QºÏÌôfº¢ÏyZˉ‡Jôk™e47¢>.ìY0¿d)©¤4zqJØùÉlJÜ„¸ËK*NÑýt›‰ñM^Žp¸ˆaÛîCd£Vc„°8ƒ¹¡|;3©¹Oá™êãè¥ÆŠ…k‚Û¹šsÔD~Q½Á»Ð j =ˤu$ƒ./,#'3VG?•xLtÿBÃŒ2¡•H/ÌÛˆ©ON©¿R’ GN2$y–Dù1k%®9˜ $ ÁTâ×$a ÿì‡SæD=!%G“A2~zÕÞ¥Oᚊï$c‚ÌH4ì¹Zx6È&ûNi´¾ªç-ðpgî}™òK©kF“h¬Ä¡nj®P—!&$×*éÊY³‚ïN!úFŒÆZNQåH/XËésWæ¬%±p‡—gÅhÌm×P„†Ðd{‘nMÁAQ*JÌă`5™Ò$¸eòÈ*B³*áêÂiNOH¼– §à`”‡ˆ÷súK¯¶<¿‘2ä*^Hâ”%,¸/UêŽ4–áù]»$ÏñV=!ÁïD°ß*«H ¸¡ÆÝÏ¢(«¯Lý g ]JÍ^çæÏ±|<áú`ZÅͳP^ÖtD®#õ$7T[Î¥}–…Ê=)(˜Iƒé×U…XœÓÑev³\=]ý ™ÚyXÍ¢Éú‚eF„ì‘Àt…Ì5Õt˜¦‡I²†·löQxb|BniN²¦± DÈh`2¼šQ:V—æîúl¢ö¨™¤‡Yé/xEÙ»““ñh~ªcÑnÝ7W‰UólJ*îD­S bªA EÄ‚¢Çº0j-MUâ—1Év‰*Š ˆ&·©ƒBAØ (+FÉEÇ„Gnê`:›‰7[»7{Í…@1QÅŠDK©GIH”¤ ™“ô ~?‰ËH³â–â%cC‹R-CT/$3ÌRüµJ!eɬ2xV0…2š°š>vVÀ?)€³‚rkPOÕAr:ƒaÄ¡ª”ݺ`yMÈ‚æxVn¢5Kçâ¬B®¨‚ÍíøKPZJ9"ðdÃ+œX#‹{sßaÌéGDîy²È`±˜J"ul(ûl†ÌºÐ<Á¡ÖÕ³‡„¿#ºôìé¹.ó÷÷édΪzV­ävò„eî›-5b”Rc­¦ÇgÈHÂÔ|aÔBPê´E‘®˜¬-{-Ä_¡ØuN¼41 ZYˆÁEw©¤Þªk«á´²XEÂðÇK»í|eïHÂ(ÁŠvurz¯²µÊ~ͺ»šy´»WÊ?s¥(É÷?ôáôsŒ‡zs¯QK ã_h5Oçû%,ÿ=™~N‘þRH‚ÙôjÂ4äš‹ŒŒ­É˜")Í`…Ì &—ã«™Bx¦SƒÅøÖ5XÍ΀@¤[¨¯/’8}».Ã:B9QÉ4 Q:HZŒÆ,d—Vs*ÇfF‹ÿ52þ%Mþßñ†ÒŠXV rÔ%=äùLH{«,9iƒÛ¥0j¹Æ»q[Á„I‚‘XšþêŒKÊÈ”ã5†•¸'.‹Ü¦§¤ó ÀÄÄü^4‰2mÅEv¦ udúKú¤Äô¬+‚¨û'0ümï$úÑ7•Ñè™k|\kŸÈVjWÃá0«šæ_¹ËÁanþîþÿîno¦ e º^i`‡FÇ´c‹^k讇ÉÕHM9Dh±OLj®Ó X„‰–Ý>ˆð¿ˆÛÿA¸ºôNŠXÓãW3^M’#wÆeãLk¬60‹(H =ÖÞ®D_#v·“ ]Œ&B7y[#”êšäªò%þ¾È! ÁZ¨mFçßÅZë±–aY÷žMÅlQ¤GlMÉ/ªîÐØÒ’…âqoYA‡¡¢5lá[/Áû] kP]Ë/éó-íŠ ÅBáºÞáDzõéÁ¨‡+ÏØ»NM ÛCÚ¿ê»/°\-d(e¶³™#™çYa¤m¯Bå4wÛf"Ñç—QÀôjqyµ0.®ˆæœ@¥c¡jkå[ÉM<ÊX¸0žì3¬¦ÌAí•V]Â.O´a¡Zš/KÐO­z©â.ÀÔ©Ì]ÊúL<¢þGŸ1CÏä=$Fƒ{E¯‰ºß„˜ÜôËqÂ|”Fe6J~™À‰y®!Á" û¯­±ØáèÒÿ­ÌÇIïÉhኃbマ„÷z°Ã_žseÍí8æMt4´+‘~%@M•nûK¡P)bZXy¨’nî Yd¦sÅbBØïÌØb `¾ÉaÞJ«âZr/2M3ÝcDñž£‰\·×¦Ç«¾º²„F¡Å¢›°.62ZY2ö”¨#5­|+º¨ºú™u³ho»¼ÖÂDÈFn2¾ÃŠõ«3†^[ÉÔ˜Ø,È|zÄâ&€Í©<K2a„¥„‚ìÅ-mÄ´*` lÁÅ‚¼q‘ÌçÊ¢’–wƒ¼šO'kqd0ò§›- [[HäFhî 6TÑß'èì{ÄôÎF¶ J…|-þU£Ct1«µ¢{…“lL:B•.ïÙ›°eÄ*Xâøœ¿hìvaäÏgIò3É;{ ÙîKðÜ 5º¸ºPA6‹’,¨-§(æj2I`Žf·ÆÕåu4‹ç†,C,»>M&DŠðºóö€DÁÉèòJÀù:+çÖÈzÿ¯«ºûW“|:+3Æ£ù§µ%«@±bÃûÓ¢WÛÌç– ‚ÞIÛ2 zÓXÁá˜Åô’·.oÔ7¶k¯ðe ñ²R‹j)©¨ Á#dÃz<³ £ŒJúRÒ ¤…:¯ì ⯠ÛG1ñ¯,Ìu0=Nªæ{µ»²‰ÀZ¯íó í8Æþ®÷bÿk–\ÏH0®fcƒ×_1Èý+^Þ²ˆ›Ñeô_ÙB-ôÚ‰ñîå;{ ~Ýî»Öt(+U7’>Ð Eã—hÞøæbSסلƯEr1v&7”ÿé?/ŸÐ`”e4‰£r]uFÀ*t¾‡žÀ%µ¸ì?òåÔ¸œúU¿VX« È"‚|Ä1ý'U#êù½éùB­ÏŠÅ·è1S†-^ïV[ƒÖ´³dy¸©“ã:ÜÍ ç=HB¨&¼­µ°¶ªš¥ËÛÅrÔ#‹_YÖ±òïågf–FÍÑHa)kL–ŧ,’ׯdÛl–ˆ*•nò !«"’Ñ齇X8κŸe3½6ŒÂÕÅÅm$&J0›ÄêƒWï’Ò×*š'‹ÝIü)­Â.¶ÖÐÍji÷zm×$b;$‹`%‹­þifJYus7ƒÄ†º&î£â% —\à x(,TÙ‹¿M™qž§,´$!"å§/”rŸ¡ä?Œ6«Ü÷£w¥¸j?½a]ö6°­ÚˆN£Ó5`µîF1¼“./÷Ü\Œ±w0G€à*ÔÖ ÆßÊô $PKh8œ`ý™%Ïoƶn–3̺­+C¥enëŽL<b×8žüE ¢_b:Æ]ßú…†‚`úz¨bµ4§M™9uêÿR ¬ ´vQ”yÕûG4âíp¶û£]÷½Ó.lRûK ÇýF>Ð%¸­Z¢².ï/¬©Z ½»ÊÆ Þn¼ÇÊÊ®¬@±÷ëI¶¸ûû¥×ÿE!,Oüf; ñoµ9Ï*œÍ…µPÑô®VÖãÉ÷ÓóQB+¹…C„…Óhþ¯³yèµIYœ†å‚* ·ƒeµ“c­%`0Q|ký²üðò5KäU[ ø(“¹õ&ÙOô«²ò±V 3™å|.Ü *IrqI}b[´^3ÖËÊ™5k4aksd@‡aI¢*1¿>i¬Ÿ”mMܰV«Ô¶«òiUm•IæÄÙ- «J^¦ß\“Z¬[g¸Wxœ\<)¬Œj¹uNLB÷ã2’d¦‡lG»“¤z[˜Ws}דmaÞVy‹^ƒV°Õ jkÛÂ4üQ€;ØQ[xódñ^ÿk¶·Éf‡aAç+ÜÕ’[9CÊ/[Šré×$µ},5Çë6²¹`rKXHÒãXäKâ {»FÝ5Þ‰šK3‡)¹µ@EÅÕQg;!°èód÷ãÕº")cÄ õõáÌ”\jßë$¹„éqpÎ& ‚-Ÿ9ˆeÜ ¸¹6ó©OQ²ÿK¤kNHTk48¿-©oðnÆÖdº°òZmá±I|Р’í÷åvnÝ3´E ÃN, LH#ÑtËäµ×Jmç%9éBš+…„ÔV&.wÐÂ!^ÛÍŸähwuŠÖv±ù×*<Pðî¤ÐT•¢Í'Ëû„¤]Éiå•®5µ‹O**¯u «{¦ñK›sß|·k.‘2`äS¨B 9.°b+m’Á\ÁE:´‚ˆj¹ eá~5\²«óð3ùž“Úv)ºìx>_µŒKý+á]õL<ÊÚw1XÂÛ±ëÕì;¾>:n×ÝסÇÞ^ØËr,^läè+8œŒÙ£Ü v=7¼ÛÀƒŒ¸Û¡:N­.>zâÌWoº5ì´ŽïÁŽ\ÿÇFÈA¸S›]Ƕ¾_;»½åòϾŠc¿©Ú%3"í®ÜÙ_ïÀAy þ±{RHÝ­}µØÇL ÇÕë–ÉóÖt/2çǯ—ÎëÖ–ÃN~ÅÛ5üÇ)÷ǸV;ê-O;Œ‡_±>ÜãT'a÷w/šòEˆmµýK¯ë]Š+®H9a~—wÜõNû·wª£U¹%@›ªÝgÚnõºƒ«Ô[}§¯W~­àt`سû™jÍÎ<Œg^ï»}ød|M€`·Œ@Þ-Û±\®}êŒàh±x€C³O­:MoúQ;‘Áé;ðÙÌ^À¼íë…OÖÇÿô¸ÀÞøŽ ÞßÇ{s3€SŸÇ[vׯ¨ á’Á—±7“N3^õq ÓdŸá⻥²k±lKúÂ÷µû? Cm·ú>Û€–iòEå¸î\܇ªn°pòκvT •ß.øG«‰'5ofuë=tÇ–¬þÔ-â{Ùi„U-Õ ‘;hJŒv•ÍÉóò®w#·ÂßpQÜòºôÆWSy?kní=•Xý 'h4><˜(‹~d¨|¶¼¦sà¼w2?8^ î êðª*ÉkÏI~ð@ò&acmç<»÷ò¼×UP’X%æ”Õ¦<ø%¥ë¿”–³ÄÕIšîÀM¥ïå!;ù®;ªÿ;˜áìÆM&¯¿g•»ßŠOzÿ²7²¾M¨Æî]×´Ÿ”<š¨•ÞÖ̓÷D||fnÍ™\ÐŒŠÞ ʺµ©u`;ÕÌ+îÓnWO˜<AÄ( ò²ˆI‘ʵO«C´™×W–¹óªww{¸ØßÆKø‘]h%!¼ÇÔÍ0ZM`ïµ0ûìˆýš7/¦è€=¾ôù•¨’¸ëL¬¸;ê!SP·ßÓOø'E†4ßvâ ¦™·«7x&Ðgë;Ãû’½W'˜ œ•¯zzôW$‡äa;+V2ÀÿDû ¼»ëx¾öÝ×4Ç»}¸ƒÎD¨¸ší]>ê0¬{¼Õªo„}&:ÉjŽpU4ä”îfü¥e;âeHQp\è€u´´g14?x®rolDÜëÆg÷õ“­¥S?Z ç}®Yd—èIÖe¦¬Â¦f>Àz…Õïô&Ž@z³Å“–QfnœQÑšÍ3rG8*b@0ÏNs¦v­æ ü 9Þ…–£óÛÞ1>Ó›•+ å¥\˦`oFNz£‰v¡û½ §©_uú‚ƒÂ¯9wËè"ý¸þ̲C’ºñ$ |¥QbÊ8`*W¤p…Ô©ÎZ–>$†1g°å=,k¯ÁSY&ô¾Š8ÅOÁÁ¾ ´ ëÆp6¿gÄU| 3)ü»µ»X®áÎÿhèú=šD¢?X,Ðé$Þ4^î‰$’H ïl‘å)§æÐüªc?Ö®½\º=3Ö^Oš[4;c} çka¬D”>žþ×$C&Ðá÷˜š°„ qžu«xšk)~WÖ¹”•8x¬´‰!:QÁŒ¨ up-'¨mÄ‹4±ï ¯Ä4¨#íÀ•Å9¯»¢nqfVß´ÞÊþæ&{r0j/ØOœÝ!Ä÷¿˜-ïyëŽ%I1r¨, }€(4/–möv Œ™V ‚'EÈV^—³â Ô¾¯œº‚ƒJþ±hw ã³û‰myºÆ½¥€ÕΧUÑÈ¡tÿ˜Æ–Q)ÑN?åñ„Á ¾„ð"ŸxNõ¤ÔŽ×h‰× ª\.<‰9ðÖkuÙ¡܈õˆµUû¨¿N»!I¶ ™V$+? ·„ W™ “†¯ý·ÆâTŒU8»óŸ­ÅÁ_XÝ…©Äû¥Ðoº€è£ÿ Ž2aW/Þp h£1Ì@kß©ˆà‹SíéÄgß$”H…p " ±s.3𩈟¨WÁ®Ð‚ &„þ¹r#…Á;·Z¡ÁúHåÂetäV}Ë vÙç üŽÞ[“Ò1 ½KÄSª¸¶Ds+³czf+Y*Rë¿ØÜäœ SÔˆOnu«ŸÐÜ2ê_úgS>áópÌž»+£òȶÇá-hÐùææ'ú×÷ì$ă9 ·ýXÏaVFf{ŽY©°ºÛ¥¿{6‹ÒŸM/8cJú:D_Ùt¸APÚ6T'êôXì„'P ü]üFá$Œ²MÓœ âÙÛþ®[;Å7S*úÒ"¥òw!!Øw'ôùƒ©¶W¯âk5 „67Oº(‚UÓ8\m¡}ªY6¨U$îvO²ªNØ%ìG;W.‚òcÆ#C¤±aËåЭ(¿óc¥€•`´°2a_Øš û4%'Ч)¿œ2+ƒ[uËÿbw”ÓÂÄ»§Ð²|¡‚3poÛ©Õ¨ŒZ•^ÛêÉeâña‚yBãëFL'%ô,K\«'$8œ^S”}NcÓ> OÅjLBÈ)±}¶ÿùÇ›"Ø^wÊæ»ÓÌ|Ç“vÌ–ÉùFÌŠd¬5ÎXiœëæfvË ¤z,Æm¶uwìããò†™rñMJŠr>½N+ô¾›F/ÒÊQZßN£§i0I£Ÿ)Üäý€ÛR»Óo_xò¸Ì>Ÿ˜lÍŠ˜ Â:ÞðteݲåéqtE¢ë9æcÛ¨_S»ë×Ç…'D×ýí'&Ìá:í,K[ÿ!)ðä!å?¶¢ï©ï§ÑE§ÑÈ.ëôÞ‘¤Ç3W"´JáKŠÇ¾¯êõŸdI­¬ö¡içÚE£¬Á*+•&Ùé¹^†ÎTß½_¤«W½ù¾Ê“™&Ð~ïÇcOõØ“w·“¾‰Ê{?H!®B c\Lº~¶Ô„P¥T² î]=Ê LtƒDSPÏou(ƒGò=?Ü`ÑBÉ„A ÂÒR Â`°¹³ðÓ¾}ö„æv©tf‹úvÒ=#ýˆHჲbÌo¢(áT ón^YÃFÑMë"m,£K‘Ê‘OloÅÆÁ­Ã!ጤ¤-¸"EÍpMû‰«U_l‘™">}À9K˜¦TSÕ>‡­'«:Ù2vN“Œ €çjñ &•z óŽóÀÚ¨_6Ì?‚ãl"m§²Xv¼¡¶9µ‡a´/Ý!0X¬Rg2>åêû´§ŸCÀfˆIüYs.âyð°ëÖ*ˆb‘‘è#à‹VU¶ð‹oMQÒ©ƒjä²ë—æ[# ŒÈ;.,Œæ'£ùÑlÇÔŒp°”1Ë »õØ ‰‘òæÖaeDb¨žC®5Qjpob¥1üD7LG¼oQK›ï‰Q™ð%Ú¹VÙNH©P;ßnÉ`LÄØ†ç·NUC¡ÿºcÔé§¡ý~7fì®,põáñ±Õýf÷Ûe˜âŠVƒvÄŠiîg‡·í¡å݆ԞGu"]6›ìPÃg—1ñ0ƒu,’z$”pB¥¢,Xœ+×#)ÒåØšQ²ºQé'E6_>Àˆ$ l H'8Wš$¯ëÞß‹X–,þ©ìŠŽ¯–¸º=Q­>âs›0}vlÔÿ€ßÊ¿ŸÛ°!‘ÒEzâSkD_¥1ó>Ø+/ÙøûZ*K*ôœˆm§š;Gàþaا1µ÷H.vüzNr9þ!gÊQªíÕºcà ·ZFêú‡-¹=YŠ,\Ö‘*3í•~ÀBÌ’7éo7‘é6§˜–løSÒ IMÄ#ò~ÊÖÎÆG“tm·q ¦qèª%ærK‡M3Pºµì~fï‡ œ÷ôŨ$¿H/ EÙj ¯û¾á;R,˜Nã}ˬÑMzîÒ7…W¿Óó- hß”êûùê¥v¯™³)?Ð`|Xõß•W«ïÊ+"Œ¹ÞûŸ¹Ì×Ìÿ>g[¤%3iÉÒ©¾ÕaÕ·YØ~¶Ÿ…]fa—:,ÐlÐ Þgé¦Yº©«më°Úvö3 û©Ãü¹óç+H1ƒ¥¬ßèí åÊQêo§µÛÔŸ‹(r¿ÚÊZœá5o©Á b‘ñ5As¡³ŸÂ\”Ëטç°ïvs¼uÔb5¹¾{´D°-ß´ºåoÖñq×6ýÕ´v]"iÍxdu7ýùí¿CÒ4èã¸Ð1‰ ¸l¬©¤ÞôÊelÙYÒ|Ì¥C"*R‚ìN÷›DZV´¢2-÷*~EƒzNp¨qŽ·€ ‹­Y››ÑFÄ)ësI¤lG¤÷,2•å‘Ãz:ópÊßï (zÖbEÚ[8ôÎ$j÷Ò™ªÝk Y}³÷º ¨6ÓÍÍ©ì‘Ð/MŠêµ§á0˜a»SÖ HH¯hç‚ÈúáF¸@ógh{p.Ú 1F- FÃ÷NpÖö‹08ÃÞË87ðW¢^Õ4-¶·!¡³èÂË£!>±;mÐÆª³ÿÒÎ-mX_%dkj_m{Æ ‚ÝŽÃ5ƒ¡œ)ùfÁЦù¹…uÕqx°|sG£‘í>)þwÏf&Žd—G”ÁZ5™×l︋°!’jô•I»4ÿ‚»¢Œ2[N0bíãìq0jŸ‰ú1 /¨¹ÿMÍųhvb˜cü—-~R?XíI{N¤—%бqjÖ„ÆElnžwOôjÛ×4äú§ÙHCjÃc[Ô‹­¥GÆh!›B)iP7Æ,ž Ä“wÇNC^³c·2§>"0ŽùSHÀ³ÑƒŠ%ní‡å90;-߰ŸöŠàvëê .ÂîsP‡g9@Ø£ä”x¯%]2ÏeP‹Í™-ÖÎyZÄݘ-ß(PÌfÀf³YÍÓ{æ†lT¾„1Ù³˜ccl3õHÉj¤c]²éú?Bµ0}É{|9Ïe¸Ct¡ûEšÇ…"ŠÇ³w\p†|Ȉ ^†Þé»äž*\öZ]tîDgY>×vdèà§…@š¢@æµX%yd¶Pq›wÍÒ׿&O‘¯,ÊÆR>Ì`bÒˆððÌN¼då#“kÚHP½ $Y+dám¥M·gºµ/,¼Þo°¨ÓE8‘®/ËY˜Á–jö²%X¥mDÈ$Œ0¼ún†‰}w¡ÒÅbk‰‰ý;”Û3ü)q¬ "jÔØ.ù.ŠôÛ^·¬zÀ(rO¼çH-ò„^hßÜì“X=~6›1flÆ`ÓïG¤æËbB¬hàBÑêEx¶ãÖnœ‹¬êˬê‹ïù) 5f˜æJû·¸ŽYK-»Y¯ªÅèÂiå+ÆS¶52ÊuÎ<¯f$ƒ!X3Û­|•h^û *P×òÑ]ÓÖ [oCdÎl,Dæf¬m™ËP°r~†Q—-­(¯¦5ü'›Ë”±Õÿ\–æÙ?C%ìðgšªÕ û±$¾ñ3MñÒÇO ]µ'²‘ ùÆ!”ç§HU”‡ˆ?9¤é' DÌuY\ӣД¤ÿ»*ûó¾Ú'lÔ² ÇO–9å"ˆ äê•k‡ÁæyaÙ*‘ƺ1Îãd›ð67‹Å8 9€ö±ƒÎ„î­†å.—ÍÍ ©?¶ öŒ™˜9>‡²¹dH]=qx›ÎP¯² õ*K;·}èVö^ˆqâú?Ø·^¡Aa%jçæixÒ>Á.Åâbb9Ͷ•RÝ'î>ñ `0m(ÛÆÁ<õ|1;ÞKí½ÌEÓ‡:2AûÍ7™év«ç¼<òÙõ^¢:¯éû”ÂŽÂ!›wFëûYzwj?ÛÚaÖ †¾å=ª<,gØÅ«Àwò!¯¸fAßh¢zu+—Øš2”ýD Ù൚^:ï…Ú’p²°ñc™•©YDa[Ü\{D.¯Æ¶uêÁ0üHò|¥å9~ ûÇØ¤–8§$Š`w‹»$;Ly@-;Þ¾S…ˆËû÷OeeŽWõäsê6.­-[ø‹ã'Xöá€GÅœ­SVµewè©ûÖ¾Bh»Åê:郀îé:tûÚP­öþ†Ù‘>âMfX“ò?øèÑó6v_ñ‚' ˉ-IÑÃþt>µ•eê{ûY‘’½}µ}…Ç$Z ODóáI²áIÜÚ¥š b@:=N3AôDÆi-½ôöÃmÕR8íeÖ˜\K€A¹\uHÂ9¢œlÛTC”} ”WûãN‰D iŽŽ°œÂVj^õ;eA}ƒWÐì; @0·¶œ’' < elr¹{Û:uüW­¡øl™%b÷J½Tžµ°íû…)v6,¹„·á)ïÖäÚ‘~ ²adý—l†²îI ­ Cê:Ç…ˆs›+ŸxãÀ°ËãuÚ˽êì<ôŸ>“ÄDz&a$„vhŠØw4®#IÝÇjé …#>ÏE´g_m¬ ½},¡Ö77O°-…á±ñ»VÝÕ‰NQï¼w&BÊ–KŽxÏ{t‰d‹ÐpªC§rÑV;™C rmŒí€^ßýl·ƒQ¯·+úEà ˜dA/DªÃp#hð–ÚE»rà ٙléµ»”Ké³ÀÞÊ…ÌÛÊi«Ôåêj7ͽ aßõi·ªgŸtôý¶‡‡¦ðFÇéöV2Íú„%ï”}e¹å,â8;·dø(†Û°ïÓV¼d¹ÞlLŒÆ…Ñsß3£R7ª±Q;3ª»FcdìS£qbT^þ­QŒjÓh$F£oTFmh4"£Ñ0*çF£n4jF£bÔbÃeTžµñÖhøFÃ3‚ªÉ`4Lm¡àÅÉö¨TÂ6jh<¤Ÿð³ÍM>@üPxRL¯v,ÝÆ'wxý ѯ8ºþ7!?EWž…ø¡±üÉHHC俲ñCá5uÖŸêÈ•ŠÁw,É+çØf\ymã…½9A‡òZøæª Bd>««5mœqÅNèžÏ*©ÙåúJ$Ô øuË.ÁþÚÇ¥­ Ѿ3v°J;ÈÒFx[r#ƒ*IxÔŠJ×ÍëØEbwðF-¬FXè ª¡Ž¯FÒµj“¼kãmÛmg¥Qç’ à™oz¯%o~'Po•ŽßÚ²mµvèõ>d—Hÿ Fü*aFÖ™­;¿Þº«\2íªVipöˆ‚mË)¢ÎÁN»Z‘Ç>I>c῵Ìj`:ÂvÜ€(÷-šq•ñ@¦JòÛLþ­^B{ÎçÁ(ÓA;¦õ`Çlç%´¨}oþcû¼UUoþÇí{8Ó¿iߛۧŠ`ÝÅ»:/ÌxÌʳCÃñI…¶ê¹UA^—$¹4v§OÈÇqüOrÔHí%gI"(áb_v-ëÐMMæ;/—æø¨:x—,!WPI4ò¬§”õPuZˆ9vÖ‘µßqxÝ9PI«ÏÖ’ÊIè\B¬¬½çc×þÅê ª×Ĩ£ÇDšlÕMê¶lñànT>YY¸:îZù;´ð‹ ùÏ )‚u¡”3Eš¾çó\õ/ùþº‚ãŸÿá7ôÁÍS;xŠiü÷6ïÍ>tvd7r° õC™DLbä¢0¼o½w‚ív¢ÔnpawøemEÉ^x¼9rÔ5Ù\L°MB2ÎØóÑ1¿ÎRä¡âô/ 4 ½!áø†‹;$‘\v̳9Ÿ–Yk¿ý:Ä¿œþãádå¡Ñ¥v탂ºõO–ém›ÌÍbçÁSÑ?œ- ”¡ÇÊ \«l­DmB=>t+Ÿ³½»ø`£Þ‡ßžk­Ï{¹£özS¹·CÒ˜j ^uæwï•y¿¼ìt>®0?9F}»[ÿÖ{$<¾nKSpÜ(ú}7—j‘œ‰û œ6«–YÿàÔß;•ÀiTÊ­SùâT>9õwŽY4ëoú§ÑtªSõœúão#¼:uêûNýµÓˆ ‘0Qóê¼^Ï_-ÉGFW¨->î×Wû{žó]j9?"^‰iÔg¡m`ÓPö¡Æz ûáÒiD¨¨+B2‰.9j»’¦™ª*rV«ËÉ}êe%àó±lf$u‹E9ùË'‘kuëDvëžè¥ èÒ,ÓN Õ“êSá‰|mýZ¬$8²QÜôß™,!¯.› e!nÇ4p•M ì’$%Ò¬˜K(éõvv ïÄyKÒ:Nàù¯Mg¿;Þ+=÷ùTšé}6ùγNCßkkÔÙÁæÖå'¦œ@u+Ù„ùØ»PW}`y¬ì]<ƒ&_ˆ1²qäï£Ý>uAåºø ’õx„ø‚h_#å6×ÝúžÅÔhou\ulé|PÛ(Õnô’Æ|i¯Nhã/Mqz| ù‡}Ó´Ì+‘²œXw¿Å+{³Ô{‘ïuà[\!5e@ä6„„É&ë[úXq‡7õ3Ò]P!}!¨8þM+¢®µòý%î]¸´² 'fý¥SáÔŸ;õ§þÌ©?5×P|ªP| fôxJª¿ öÓeG¡£|5a$8§Ðã\„ê|#ñ~g:„1 :)zŸ[°`îíæñPkûÎGG¥Ø9:”‹ç/ŒŸÿìß¶Me Œü]#¶³Fc*£¶Å›‰j[-`mõo·úÆGõÄ?jm9õŸ-³ò¡|SŠnJÁ§Rtm:õJxô³ßúèT¿ÒOðž~*ïIÄ{ÃÉý7ŽáÍèaâØ5Îb*x-9蔦²0@J~rr„x3NÍM§rÝ2•™°þ„&ÀaÀ¹}7—ÓšÎÜQ/Éý™óiÝÇÿ;,‡ÇÇk3ý§+¼+gßyÎI«ãåÆÖÜÝßÜœ»õ^±¢/µ–Ko2½éEÒy0gWÞñv^>Ì/¯a+£ÿ·mã½Z:¨LU—펹i¶ÌöôÎÝÊ»45ëWôa†9 B%ì“ÊO¿«böQÈ~‡þ/rî‡2·¹M@eÖ>ú ù¨:¥ËKÓ|í»îGñ)Ñ?]_QíàõÿvÌÐ,žMœÜA=Q(E<‡žfÛëc¡”k?ŒÚÞglƒN&žß–3Œü©õsØÍFØKvÊKVªTÚï}%r`óó½ Á×íøaîä9Š¥dݲE`O7íà"Ä–zÇü3º¤fŸQ³}Ý¥ó¢e‡œÏîüvÐL*‡2b – _²úÿÃxSâ6`û‘3ú5YG}‹ …"‘‰âõ× Vα˜q]la1ƒ *[ÝoôÛù{`Ûë QõonN@V¹ýx÷wä—;iGcávkÇty{î„î©[‰\G}A|(: ñÆi”0&ðS(ŒaщRº7ÆX %ú?ä³òX ({‡dßa’Éð çåg~OAð=‰Õì÷lðún}ÞñŸõ¹eF‰ L»…O=U«_í[û`½uÐ`ú <¡xc«âýX8'8>p+O©Ô~)ŠLŠ«ÿTEê˜f©ú¡5 VU~vQDf[TwŒ¨fDU#ªÕ7-þgDÀ!É÷¥Ôü»ÔüJ\¥>Ë›ŸQ‡÷X\yÂÞö:«×¢é h-¹•k{5¨eL.ˆôÏ•-Up¨S*Q õ13Ë÷ «VÈôÔtº”«'·Òè­¡T_ÐÅ#Cê8¼ý#ŒÏ‹ëÄúê0«³-Ü» U<ËŽ°T¶ãÖϬÖÈHJ-©¢1õS´Pp îšú q‰Š`ÑÆÆ¡ePÑÚI‰iêÎR2³úÊÄ´_å  Í"ãÀ­îQNhPÌ5ð rœŒÖcÊʉ <[ò%ÄHõ®Ú!S€Û>.—úƒW»*{ÄK½@RøGO¶l¼»0º2˜y­8¶`Ä€šó‘¢›ï¯TÛ²z?BŽd¢NõÄvy¢iŒ…ÞgP³ÏÖ>·îþè=Ó£‡Ë^é,¯å•5x0ËólÀ3S*OVI^˜jÁ½ ëçб¬KQ?–ýRøîð Þš`cfå-„µýúÏû¯67‰Ì4AŽª—-Â,«]= ë ǾzÜ|cc[!Æ·>ÐoÍ×¹ý»Dd@ 1ÐÚ©Ÿ¶”JA5‰V‘Æ6k»ªH’Ö6?XhíËÚ1UfóUé-Ƀþ›O¿ÂÓl‰ù@ nþxÃKÎ~è¿éDns%m‚•ÿfssJª2"ãp=`´÷Ã> ò@]©Â„–oߨ×!çöyùÔ2‹û|’‡ºµO²ÍD™ËæHÉÂ|&øÚ†`±ª4‡ò\ñm:Ì"ø7±ÛrÖžm΃9ëáêl‘â⤠pË—u¶*H•òkŒÀÇÁ·~-Ò=ðöÏùÈú¦:ôO :JÑT¹Òâ¼7ú|<¡%tÊ û›¤=‰§òônù¹äÑjñÍPfË#TÎ.âs¶u·ºÃ§rY>áë]²¤úž>ó±Y¤Zˆó¬UÕ·=â,mUH„œœ¯U“ê«SÂíH®ýŠ1æÛ&rRä{q zq zq@½Ð:ó®:Pžõ¢º£úo¾nÚÕWoˆîë_ˆÝ*»FoCP ,}÷Û52›S+ʵ̿–ቖÑsyÏH£ÞeuŒ¾Þ ÷‹*8mòbÕïµ±“^R‚ç&8X%Ø}(·F%Øù%Áíz&ÈU±nÔI"Á§¥ãc·è¹s†EzY['vV·äúr÷Ô jà½óu?¨Q÷ïÝ~Å÷‡¢ÜaGƒséx/Âuð9•ZXo°.1Ï‘ÿ¼{‰Í(ÔXR8^¤©þ~ƒõvï•;$rÏÆ<àã¥Üª¦—r‚}7j¬¡ËÐ ‚8`¦øÄB„„ðjJR©fM=õøœWéÕÝ|ɨ߰*5G-–ý‹Ô{“zrqŒm'] .ÌŽ÷b…­¨gË‘}i¹‰‚`w‹¥^hóÖà¸XÂQ.Ë}dÿY&bÛ×[X|?à Kä ¶úسäøaŸ7âðYt"µPʾPç+5÷ŽîX1vãýƒ6•eÉWY•i?òûmÐïS"Üh&’ZüBÝ(…f§äµ<ûQLÅôÛ‰P=}'¦Ê!FèïH6݉1«k+ Žš{àzúö¢«°paŸ‰é7 —á`Ž%7Ó©zø²¼m9$åíã«ëÔìmeû&¸ò«-—¸,Ô'n]±û‚&Kž—_ò;h°q›KÌ¡Æ7V­ŸoŠø¸óÛô°'Ç$Ý#b©"ýà“@IT¯>±FŽÇ À–iÚ¶2ó+c;Ìîád úNqßy¥™b‹˜A\Àwbcöz¸£oé#6ý]ßrµª;‡"UÚ L(W Ðþ®W˜¿»¯íïXã€Øú*¥z½•]ÀËŸXÞŒ£­N¿uç½j „ßËñ)¹±ïøW­¾SñZé •š z[¶c׿Â^ÿ B‚¥®.èà»Ånõu=Þ`Ãßn½BùªXi…#À¹Å˯ëÊ bÛÚ˜½c!¹mãWõªÍ7âP³îê°~^:m)ê£G—$á½[ ¶¬’ßt›3ëòžßí²o·Üªý(*ö±õ‹•Fë£ã7VWÅ…«†B˜#­éƒ°…‡Þ þ¶ñ3ósê®®ì´2ÒXuý¯¶zr«Ý#\0ú÷?ZœÃÿÚE™=JFêÐ:®K‘;õŠGeänëp¼…^£)k믜L¾Cu‡¬Šnc'ߢ)-Âõ>ÀâÙææìI©yÙ™µô1:…\ã/”M.f†ýIì ÄSú ¤`ÌP"’óBç¢Zè5vqqä!½UÞÐd£ÇŽ%†iÜß¶ËzB`ÀfÈœj‡ù-&üBp¡‚fhôB:‹>¶Ès|µ®e‹<{m[&o©DÓ·­îC„¢‡r0|TÚGl†  ×°P&cOC¬À(§WH›£½7¤5ÖA· ßð«Áã«€ViçGÅl^˜Xïtˆœ½É„¨ÿa­ºV©ÓÙÿª…åE¨–ùi¾.ž^1^\<†"ç†ÂÓCÁI+UU7öÇ`ƒ$ƒ<[EÛ »+U¾ì%í {UªLT%,Ë «ëX® =È…SªvÎ@ÆXð†²Ë|Ssð»t4h/{PJû27•|AãÀV„7|ªbQ´Ú IYAP F¸âu¥xwU<·ú®cV!ÕÓîaà ž-ÇsTV{5Š””q ïö#i+ð/ÁV±=p[wÍq«yæ4G­zâÔ+­æ ô¯î¨o~¹ý'E rèÝæŽåF \Ä€c˜?¡Ë^¯ò|êF<òˆ*’°Ì””ÝtHý:ÄU|ë«|§8²£)/ g9Â6ßJ9ÞsÇ{OOÿ§SýªC›8¯ÙÄ…Gåf$+"8¸Žc)~äƒÐ‚"Øb¤î#·~++Ôxƒ%-ÁÁí¢œJõÞ³š8xÁvÛ¡ØÃõØŽØœ¿$áµ¾£ß"lV£˜#·úÅ¡ŸÏ|Ð×›ÛôæÅïg¾Wö–¿-¬f#ÓS[Ý>DñþQLtu£úÑöŸ!?èN€í+'ô•ïšMÝ=h¼Êß¼ÁZJÔòæm‚"}{ó%5„•q\M¸Ô©ÿZeà[GØÄUþÖ¬¥Þ‘ûHu‚‹@0½l=Ž#üt$EðùDèdÔàG)pÏM«J<Å °ýæÄªDYÛ«7&ƒ.CÇl¨ Þ`¦ßnÁ‘¿¶ßŽØ2øÞy‡-ïÐñ¶±ÈõÒ ¦F<4rVØ1kŸp™™“}~ä»Í`FJ¬±³ ‘´þÕiâ6a¾útñž|Ïm ¶ZšÉ(ÄgŒç»Ïy:P2’»š ˜%ôV„ëCÓç Ÿh4Ñô-´|kÙêsâ¶O)K¡_%!î¸Ð¬$l; ‹ž#¬Â¨Œ°>…Õ>ê°íUØ'„)I±œ õI‰œ~)$ÎúÅ×ýÍø„ u±p¦b=.[T®¶jbY®œ·•}¼ý¸PMŽ ”ºúâ¸ÐӋ蘺DžÊíq¡Øo¯nË,Ctö,¾PK¸uœ|' Cê^ßmúÖÆ¨µÔjyBðÎ}ˆÿ¶êr¡¿ÝÒçæ)·:å^©uGéÞq¡EWÔ6È^uO‘ÏŽÇ«“ñØJÿ›ûª;£níkñu}•!>k¸þ¢62¥ƒ|¿ŸÝÐíó™*’HŠ<¼|;ß ÿQŠÀNY›[*«º@••åÅí}¾½/Rª +êHhí0W>¨ŽÖ«JØ/Rpj¾S«5B*p}•þç¿Ñ0ÕÎBRqé‘þˆfé˜ý3§p–“ÂmU ¿oéâö’Þ¢ÁiʨÒát–jïw”"¹Há†4/nÇ”îBSx‚{]$hR2_¤ðõ$\ögÓëy2K§ì)|ÎIPÅp’Æ£ùå›ÍN¸øyz5§âp.…G½tå-â8½˜’t0Ÿ§ìüí0½œM/¹ÅÓa ßÀir³H&q*Þl(Yª<ž¤—WóÓt@- žÔ'8KÅ{Ý;®%\ͨ[ÑâjN-û‘F——ãÛ”½ˆ=ƒ¯,êB4-n© ×)¼U§ìc%½ç0ÍŸk`Gp'š².†ø¾NO£IL9/¢Å/œi´XÌ0>H•¤p€ÉcÃÐZÌF'' DJ@-ÒzÇnwKGQó«z{¤®?žÒˆRüå;"щàQ’]4U$”¯â ˆÉÍ­Ô1N"̸`&b Cw¥ÔÛùüš ´ “/Nin¶DsÕ7 Â—L¥(þŒæÈ”æ1º•ŠO^ªíçh<ŽRžéS¦¿4õ¶i6ƒˆ°)SÒž="Dý3 ¸Ì0©ð3Ï9!—â¾4Ï„¸Œ±ýJDÜ!“íõ¨ãûs½Æ4üñ‘ ?°rDÐóCÍ4¢¼ó/û4ÕRÌNâ%—LÑ÷@1MU‰rˆ"œeNÅ'Rñ7•þK“ÀJ#*$„x0GÃAt‘D3â\þ‡„Jœ/Ä©9€÷â2½ºŒ¿ìV’°ÿMäsDtsBy¡D {@"ÔŠdpNÅÃg—Æò7W}*W£1ñ'2L´û‡ â%} ’Ë.¡·àO<"ă£OÌBìyr^Â>+…/ž& ¸Ù„‡u2]pʼnvJØ ?Ì‚hŒÚÄf I‹ÛOLÖ$†¢0y¨S±Œ†S(ø£!cyž$_ˆ-¢×ÉmzžÜ2ÆPþÏ/‰0LJŒHì÷KÊÜråË;Íœg o¥_ðá:4¡*+3KS„¸òVPR|eƒïá§Rqs&G<,ªŠãìb`æ ÇÄ­\õçÓ±Ô" ‡–ÛÔÖ82H`™cTÛ^j0Že¶³1@ ä #Ãâ8— ñ.Áà–ŒžB.&d3!‘Äw’x.(ÓŸÞ ôtk+EñhšÎ¯yFÌ’ašáìh˜½b¨eR Ï󅃂©)‹¶È öŒ©=µ_Q("‡É.Eç9Êöô–&ÿˆæ$aóŒÉÈœ]Md’Yfs.ÿ_Œ…ø¡Öí¼=x&n_÷%@ÆM’7β˜êBTD¿b¬Ø?rúîíáa·Lô§Ó°äþš~`qƒXqÝÁøj޹ZN™èʨòN­“âù5  ¹Ï¦$Á‘X”eN_®ú$¿`)æ–jO»˜D¼H !¦üsJ­šÆÂmÒ¾pHÂUá@hµ!¹¹œ¥™ËÞMåuo'½‚d$á<”˜£ ¡Ÿx:æá?š¦ÚŸ.ä‹ ‰:³j>š|(tP¤µPkù¼óÔ›$Å%Ïꊈ$…y D­ü8ø/ñC ö.îÝÁ¯Òë¤N´Yh ctú/%{%ßSø,ÂñçÕlUÐÂÀÔ§¨h|y¥ûÌܨAo¦+úœ§µD6íÓ6ÕÞ|Såš–ÁHÍ}:%„êãè¥ÆŠ…kxFVsŽšÈ/ª7xzA ä¯g™´ŽdÂå…eädFÂê觉î_h˜A&Ô£é…y1õɉ"õWJ²á"cÂI†$Ï’(?f­„À5S¤!˜Jüš$ ñ¦N©‡SæD=!%G“A2~zÕÞ¥Oᚊï$c‚ ü¶§3ÀFx6È&5’:H“ õU=¿h逇›ÛÊÊ(¿” ¹f4‰ÆJ|È{G—!&$×*)Ç Ê³ øî¢hÄh¬åUŽô‚µœ>weÎZ wxy&PŒÆÜvÝEhM¶éÖD ¥¢ÄL<V“)Mâ![&‰¬"Ô1«®.|‘æô„´ÁkéÑp Fyˆx?§¿ôjËó)C®âÕ‰$NY‚ûR¥îèAËœy§Ú£rŽ·ê ~'‚ýöPqXEbÀ 5î~EY}eêÏh8x´gÍ^çz¤AA#{Îê D€Œ½Û#Ì]dA6Ó¾ ËDî  @¿$®ý1à0ðÜí€ký‘b@ %¨ãxìM Îà“É%¿¼”çf)IñZø#Š¥Ç õ|?HßDo¸·$ÛÔDëA?æLó’ªXEXÍ×ZØ|.xǘM¢;©È,ƒ²“2©VÄ‘b]¤i’¾88bEbdê5ë[é+ ÝòÒ£Ó«ôpDó(ݦLï4ã­=:zG$8=Ѹϧ`ý¤_LXcqXÑ©©ˆ²`Ÿ&¿D²‰äÐ`-†SqYWgbwFzÿ¢rÁ¢Ç I§ãH8¹ô’˜9ÉÞ1L>¢(R¾ëë”ÙøéL‹@ D 4³ üêðí<Gìd‘etq %ã%‹)JbÉX½G}R…22^’‚Ìö‹‚ËF«lg wNØmíqYßÒn¡¨àQ,ô®ëý~,[ŸŒz¸òŒ½ëÔ¤°=T¡ý«¾ûËÅÑB†Rf;›9’yžFÚö*TNs·m6!²}®qL¯—W ãâŠhÎ T:ªÖ¹6Q¾…‘ÜDÀ£œ… ãÉ>ÃjÊÔ^i…Ñ%ìòDª¥ù²ýÔª—*îLŠÀÜ¥¬?ÀÄ#êqô3ôL€@Þ@b4¸Wôšè¡ûMˆÉM¿'ÌGiTf£ä‡‘ œ˜‘ç,²P±ÿÊÑ‹ Ž.ýßÊ|œôžL®8(6>èIx¯ 1üå9WfÐÜŽcÞDGC»éWÔTé¶¿ú•"¦…õ—‡Z éæ®ÅAf:W¬!&„Mqð>ÁŒ-–0æ›æ­´*®%Gñð"Ó4Ó=Fï9šÈu{m y¼ê«+KhZ,Ú¹ ëb#£•%cO‰Z1RsÐÊ·¢‹ª{ ŸùP7Û‰&ñ¶Ë›a-L„Œ`ä&ã;¬QŸ±:cèu±•Lù̧͂G,nØœZÀã°±$FXJ(È^ÜÑFL«©À\,ÈÉ|®,*`y7È«ùt²fGF#ºÙ’°µå€Dn„Fá®`Cý}‚nÁ¾GLï idË TÈ×â_5:D׳Z+ºWø8ÉÖɤ#Téòž½ [F¬‚U ŽÏù‹FÁnÖAþ|–$?“<ñ0°³×í¾¤Ï ¢P£‹« d³(Ér€ÚrŠb®&“†áhvk\]^G³xnÈ0IJëÓdB¤¯;oHœŒ.¯Dœ¯³rn¬÷ÿº¡»5ɧ³2“a<ú‘_qZ[P² +6¼?-zµÝÁ|nÉ è´-£ 7ŽYL/)pëòF}c»öZïQ¦/ (µ¨–YŠ \°1B6¬Ç3«0ŠÁ¨¤/%@Z¨óÊž nðÚ°}T ÿjÀòÀ\Óà¤jþ¸W»+›¬õÚ>ÏÐYшcì?áz/¦ñ¿fÉõŒôãj66xýƒÜ¿âå-‹¸Ùˆp0 Y@ÿ•-ÔB¯ï^¾³×pà×í¾kM‡²âPu#é½P4~‰öèo.6Õ±qšMhüZ$cgrCùŸþóò FY@“8*×Ug¬Bç{Xà \bQ‹Ënñ#_NËù§_õk…µ ‚,"ÈGÓR5¢žß›ž/Ôú¬XÜy‹3eØâõnµ5èaM;K–‡›ZÑX09î ÃݬpÞƒ$„jÂÛZ k«ªYº¼],G=²ø•e+ÿ^~ffiÔý€–²ÆdY|Ê"yÝøJ¶Íf‰¨Ré&/Œ²*"]àð‘Þ{ˆ…ã¬ûYö7ÓkɈ!\]\ÜIb¢#±I¬>qõ~ )}­¢y²ØÄïÒ*ìbk ýЬ–v¯×vM@"¶C²V²ØêOf¦”U7w3Hl¨kâ>*~PÒpÉ®€‡ÂB•½øÛ”ç)pÊBKr"R~úB)÷J.ñÃh³Ê}?zWŠË¡öÓ«ÖeïñaÛªè4:]VënÃ;éòrÏÍÅ{sd®B]a­Ðaü­LBµ„†Ã ÖŸYòüfl›áfÙ9Ã, ¬Ûº2TZæ¶îÈtÀS!vãÉ_Ô úE!¦cÜðMС_h(¦¯‡*VKsÚ”™S§þ/µÀš@kE™W½D#Þg»ÿ7ÚuOÑû7íÂö Õ¸¿ÔpÜoäíP‚Ûª%*ëòþšª•Ћ°«l¼à=áÆëÑx¬¬ìÊ ô{¿žd‹»¿_zý_ÂòÄo¶£ÿV›ó¬ÂÙ\X Mïje=.|?=%±’[8„@X8æÿ:›‡^›ô‘ÅiX.¨r;XV;9ÖZÅ·Ö/ëÀ/_³D.PµŠ2™[oR‘ýD¿* +!kµP8³‘YÎç½ ’$—Ô'¶Eë5c½¬œY³F¶6G4p™$ªóë“ÆjñIÙÖÁ kµJm»*ŸVÕV™$1lJœÝ°ªäeúÍ5©õÀºu†{…ÇÉÅ“Âʨ–[wáÄ$t?.#IfzÈv„e \í ó}µÌ+{uÃk¶¯U­­íûeÿŽ.ã·HÈËêáM¹lZœLV–wµ}Ä&Ö¥sËÖ‚_è÷c:ŠyÓRnß ,Î3ž0±þœrGs+×I¦«Ç{¾ò‹æ—I7Ó‹ò()&¤ª’œ—$_‰ò•€~%½u¦DB@‰fMˆéÕ‚ ÓÝB£¬Âcè6¼ (4³Q,鎚O£¾'ËêA©Ÿ°®?WvÙZ™6ñçzy'³u;1³|n¶‹Übv¿3‹Nl[ ÐW9øÐ«\@Ø£›­ëäKW9£Jãò&tW ñAi&–ŽÌmê&)G†Ó깚SR·T{2 7kª•äVY×=ÃÃS¥:R%DÀ°ËS¯fIXmSgu©c[®_ÍVó„6ÛÆn‘Š„Qep¹jG¾Eç€öCx­°z½#¹bò]¹ßvœ­%0ÞX¹‹ºOL}Tÿ‹ÊUsóç;+-3ë4±íµn¯%¸º4ã>~`//YˆÔþÇÿùûÿóŸ(áµòœèѼ¬x{íæå³yÙ ê[C߯5½J¥Ò¯[ÕæV¥Z«&•j¥Ñ6‰Uýç:°¡¾V«ðs«â­?½ Bzî?<Ï«_ jÕlùç×þalý?ßýüã tÂ0þq}}]‚UìwéþSüÿKÿ´ì!‡$µäáùìF­ ™“> ˆ… Õ^ì`¯}“\Ÿ#Ò¤W[˜•ÉöÙôòv&vÄÍ¥¯¦§ãq°Ò¿¤ Ä%yÕqçŠämëš@ ÀÝbß=Ø;2,ú)íï=Û}s¸ë.H:AhÎ/Þíý¬EêR²m8@Óâ”¶ª%¿bx•–ï·HÊ*mU¶¶ ë0"Ý•ÂH"E2.ÿCò£eTk*˼lMÍÄ¡K\«çœ;‰3ƒ§Í•ìeß ‘µ£N¡Ð"¶ N¶[ƒrDNѲáàŸ‘ý$¨vd㣠¥÷™:žm Š~Ón \}|Ñ j¶½l†ÖF¡°2}+;oÛw|ƒ„5(•ìY—žv/<ç«MðÞ>»YóÝ<ƒö–½v®é:ª€‹Ø Ëö ô–íUÉT? µ/Ãˬ¹Í’”«_(¢Â"¿:Ø2ép޶ªòriÔn׸î¼ràâíÏö+cG‚ø3Ì®xå«9q'â‡À3ÉUXþÖýö¸÷Èz¬œ‚ŸØÝoOzþL¿ý¿ëEûϲSó)ÛýÖúãø¸{|ìRtÙñ|¾j—zU»ê™x”€ûMå-v½š}Ç×ÇÄíºûš”/ÜöÈ^Vbåù•ï¹Â…óìÑ–¯go’¸Ý7HÊu›TÇ©ÕÅGO.³ßh5|i5߃±opÂ:ìÒ„ÝRóý:pb½\¾1ðÙWqì7A»dAġݕ;»ê8(jÁ?NO ©»µ¯ß1ÃãIõºeò¼5Æ‹ÌùÉë¥óºµå°“ñvƒû£•û\«õ–Ž¿—ù Ñ–väV'a]ÇÖÔ]t€ØVÛ¿$ðºÞ¥\Å)',ïò÷¾Óþ­œêhUnÉc§^þ>{Ðq«×\¥Ôê;uÜ—÷zu¯-.ö|ýdµfg†2¯WÝ>îdM€àkËVc¹.Hß©9µ Ü!Ëíq¸ÐøS ÎÀès]”Áé;ðÙ"þ¸Nô ¼/,x²9.ø§Ç¾û¸àýÍÎ\êùx  }Œ Uý¾L¼™öQHxÕß`GÃì3Hîn¬ìZìÇ’¾ð}MþOÂPÛ­>g‘€–iòEE¸îHܪn°pò—õ6쨪{{q?rMnRöfV·ÞCwlåú÷§nßËD#ì¨j©Î[4§)1ÚU_$ÅWH¹ÞÜ uÃEqËëjÐ_5NåïYvkï©ÄêOKܬ5><˜(‹~d¨|¶¼¦sà¼w²{0Å%r^$yíù/ÉHÞ„K9´óìÞËó^WAIb•X\¬}ÿ%åÁ/)á/™[>ÎW'iºƒÛhi*}_ù^c'?uGõ3œ¯q–ÉëïYåî·â“žÁ¿|q߆kA\Ïý¤äÑD­Ìˆð¶hnÿKäŽÿÌ­QÎå|pLpÁ¹  [›Z¶Sͼbü0ívõT€É“DŒ*/{PĘ©\Kñ´0D›ÙqUu`ÙÙu¾õînÝ7ã%üÈWè&!n¬ÿša´›€Ý œ/Q¾‘2Âð}~…_^å,†»qbÈpÝÛïé'ü Cšo»qÓì¶[vÓ]_¹éæK…ñ¾äÛkƒLÎÊ×Ì©èŠäÔ|;+V2àþ¹öxwÒ%´ÅôkšãÝ>®î±³WöêÕ„@hïRQ‡)`èÜã­V}#ì3ÑIVs„«¢!§t0ã/-Û‘[–Å X¬£¥oFóƒç*÷ÆFĽ>a|v_?ÙZ:õ£UѸ¼Û5‹ì)ɺ̔•Gèµ`m]¼-ÃYÖ€hÚ¶iËMÚ·Vqj;1¯ÂkÕñ?…ìã•R•üO¸Ö1!º¸g|T×·úŸ: 1ÈoE¯åUÙ¼?ÔîäãÐÃÍ£Ìýϸbz…ͱ-\ÿÆ&bݳ¥¸Á¥ÙŸØék-«£q^-îZBÔnØç4_Ô|<gbKvÈ¢¸²o÷‹ÏãÂÚ%ÕÙ èíÕ…Õ››åêÛ´º_ÎÜ|Á%¼áb©2É'á_ú»Ï $@gwÛâu%+aAíûÊ©8(¡4à‹q—0>»ŸèÑ–¡kÜ[ Xí|ZJ÷gÞèa¢/ýOÔÿ Nð%Ä-Ò¸Û©ž´àƒÆñ-ñàTC•«ÓÅMÂî|¡0®îÁ©tßõ× c·1$ɶ!ÓŠdågá–pá*saÒðµÿ†X.f—]ûÏÖâp_p¯ V ˆ7öK¡ßtÑGÿ.ʇ]I¼øàjpaZûNE_œjH'wvoA¢áA‰X"‚ÑÐ;ç2?‘Šø‰zì -ØÐ¥ÅPïÜjÎ`©\¸Œ‰Üªo™Á.ß9c€÷ÖäK©™„Þ%â)A®¶Gs+³czf+Yf±779gÃ5â“[Ýjã'4·ŒúW£þÙ”OÜy>fÏ=•QydÛãð4è|sóýëŽ{vâÁ[‹~¬ç0+#³=Çℳ»]ú»§«f žBùh¡¤¯Cô•M‡•¡mCu¢NÅNxÊßÅoAÂ!Û4Í)1± žý±íﺵS|3¥¢/-"P*‚}wB?Ø‘B{õ*¾’PAhsó¤‹"X5ýØÃ…Ú§še³§±–¸Û8ɪ:a—í\¹Ê uƆ-—C·¢üN•V‚ÑÀÊ „}ak6ìÓ”œ@Ÿ¦ürÊ<¬ü n•,ÿ‹ÝQ—–'6Ø=…–åK¼£R{¶ZʨUéµ­ž\&¾&˜'4¾ntÀtRBϲĵÈqB‚óS”}ÿt§á©XI9%¶Ïö?ÿ¸`ÃY(ìu§l¾;ÍÌw( )Æü&Š^ÙYÍ»yYd E7­Sˆ´±Œ.E>*CF>±½5· '†G¯p ®Ps,î×Yìà/¶ÈL‘þ}À9K˜¦TSÕ>‡­'«:Ù2vN“Œ €çjñ f÷n<ï8¬ú¥aÃü#8Î&ÒØv*[စ`Çj›S{&lAûÒƒÅ*u&ãS®¾O+qú‰1làØÿ¬9ñ»Œáˆ‡¬c‘Ô#¡„ƒ*eÁâ\¹Iá.‡ÄÐŒ’ÕJ?)²ùòF$ a`k@:Á¹Ò$áxI÷ø^IJdñOeWtüxµÄÅnMy¡‡½S÷Y/ìØ¨ÿ¿•=~?·aC"¥‹ôħֈ¾J%bæ}°W^²ñ÷µT¬a‘žÃް2[|aѸôiŒGí=’‹ÿƒ^…“GŽÈ™r”†j;B5¤îØp£–‘ºþ!…„GKnO–" —u¤ÊL{¥°3…äMúÛÃMdEz‡Íi#¦%þ”ôBRñÚLjŽ\.•î7àÅ;ÒÍíè2–r=“Zk€Øˆ7ÂÈ`€¤µ>Jp•°_ˆU2v²fçʉï·6’Õ†‘­ÇqÐ¥ºh\Ð(·CWìBO?ÂæS·¹- @ÞUŸ¶¬Œ—nÑê´š·ió&m^§Ív—˜zËè±ÛH8,qëö€³ŽÞ*׫eå8ÉÑ*û/ô—7l•½¡ú‚§ UTÅo•+~.ÊjÎÓzÕV!°ÝÜjÚÖ1ëSL3ßÔ½Ö†Šƒ£¾G盤´îÌ”´9!fÖ„ï9œ¥ŒÌÖ­S÷ñ3¥Ÿæ)%šN3¡gLÏ>=›¦v±rWûœ3ÅÂÛ¬·²…°Ê![cL fuÀ˱bÿ%Çx¿ÆTƈiü}¿,ÉÑør?\¥ÿ¼ ¯þ`“ 1+ö¨Úøt?êë#ïW¡líl|4I×vGÐ`‡î¡Z‚a.·d‡£1»åRnpú™½6pÞKÐ[ ’ü"½€e«¼îw‘ß‘bùÃtï[fÆ hÒs—¾)¼úžoi@û¦TßÏW/µ{ÍœMùáIº#&¤¸—ÔU7ÞäÕÅ[h;¿ÄZó"Bã K÷œÍøÔý\¨ïéÐ׫Ю¶ Š4h–`AŸ“úžö…¸!,I7r°¨íΰLµƒ%F¬ž Æ•þ3×…Àà.”½ÎÜUI5p)êTd9˜Êx"…À: ŒëœŽ±`©YÃ5Êüþ`]K¿ó&4b2ÈèB½›÷ü#~Œ:™Ë>ŠÌê‚x_ÞÕ·×AâÆHOOåÛ(KžÏÜÒž‘D}—_IP¹EGòʇöÌ% üQ.|ØvK¯#¹¯;âÛ>lYKò{ÕŠi'j‰%Š¡òÒð«šËF¬'3åÓ‹K€O/å¡ë•ñ,ÌúÌ©èþä/;&QP¢–¤= .J½ôXý¹6aKw|Üx^¢ŸÝ_9µ}øÿ­ü°ÌoO6d™ÅgE³Hò…S{•EêPë;Ÿ`o• û‡Ûë¨ÈGði.D´ö’ˆ¥Élwä\ »$íÓP=2EŒF›¬%‹ \™þ˜A‚´ÌÖ]c'Ÿhôø¢ôJ[4už­…?ÑáA´^7BÃp¤ñЦ­lEŽD”q¨“b¿‡Î 4ÜÉ¥ý§Ï©kÏÖ¨ÝÁ´T¹2óÄžçØvC§$‡ù$BÍ‘®zäxB£%]ãg.ÝÆZºŒö¯ñ•59½|7ns=·ôzPã;4àn˜D>%ÐZ€ $J*åL•‹Þ‘È·™—4¶1m°›ÊUXõ„Ã(1é/rya¶«ÜžGyG˜«0ä UÞÆõªõÁŒ«Þá»òjõ]yE„1×{ÿ3—ùšùßçlë‘´d&-Y:Õ·:¬ú6 ÛÏÂö³°Ë,ìR‡š šÁû,Ý4K7ÕaµmVÛÎÂ~fa?u˜?×aþ|)f°€õ½]¡\9Jýí´v›úsíºî«­¬Å^ó– "{Ž&h.töS˜‹rùóö=ÃnŽ·ŽZ¬&"×w–(¶å›V·üÍ:>îÚÆ£¿ØÉ÷u‰¤5ã‘ÕÝxôç·ÿIÓ ãBÇìÀñ7Œ5ƒÔ›^Ù¡Œ-;ËBšÙ¡tHDâAJÝé~³`ãá8ÖŠVT¦åþAůhPÏ N¸Ãµ3ÎñaÅ»_´Æ0!EÚaû®JÙŽHïYd*Ë#‡õtæá”¿ßPô¬ÅŠ´·pè7H,Ô3U»×²úfïuPm¦››SÙ#¡_šÕkOÃ) `0Ãv§¬:_ÑΑõÃpæÏÐöà0\´bŒZ@Œ‡ïà,¬í;ap†½—ì˜Fø+ÑF¯ÇjZæ:‹.¼<â»Óm¬:û/íÜÒ†õUQâA¶¦öÕ¶g¬ À#挚ÁP Δ|³`EÓÀüܺê8Σö™¨“ð‚šûßÔ\<‹f'†9ÆÙâ'uñƒÕž´'áDz9Q¢' fMh\Äææy÷D¯¶}MÓI®ÿw:‘4¤†1<&°ÕH½XÐZ pdŒV² ”’ucÌâ™@Ì1ywì4ä%0;÷儌cþð,dô b ÀÅ…[ûayÌNì§÷4¬½"¸]ÀººB€‹°»ÅÔáYö(9%ÞkgI—ÌsÔbs&E‹µsžq7fË7 ³Ù°™ÁlVóôž¹!•/aLö,æØÛL=R²éX—,Ä_ºþíöþ’÷øržËp‡èB÷/Š4 E„ fï¸à ù°A5¼„) ½ÒwÉ=U¸ìµºèÜ/ˆÎ²|®íÈÐÁO 4E2Ìk±JòÈl¡â6¯ÍMž"_Y•¤|˜ÁĤáá™9œ"xÉÊG&×´‘ zA 4H²VÈÂÛJ›nÏtk_Xx½'Þ`Q§‹p"]_–³0‚-Õì;eK °JÛ ˆ-HaxõÝ ûîB¥‹ÅÖúw(·gøSâXDÔ¨°\0ò]é·½nXõ€*PäžxÏ‘Zä ¼Ð¾¹Ù'±{ül6cÌØŒÁ¦ ÞHÍ—Å„XÑÀ…¢Õ‹6ðlÇ­Ý8YÕ—YÕ!ÞóS@jÌ, 0Í•öoq³–Zv!³^ T‹Ñ…%ÒÊWŒ§lkd”ë0œy^ÍH C°f¶[ù*ѼöT ®å£»¦­¶Þ†ÈœÙXˆÌÍXÛ$2—¡2`åü £.[ZQ^LjøO6—)c«ÿ¹,Í% ²†JØáÏ4U«)öbI|ãgšâ=¤Ÿ@»jO68d#òC(ÏO‘«(rHÓO"ˆ ˜ë²¸¦G¡)Iÿ;„1vUöç};µOبeŽŸ,s Ê DAÈÕ+׃Íó²U"y‚Ä–GöÄ"åæø¸˜–ì”,”À*Êô'<é%䙄= Û œØ)gƒLï$KÁá RBËó°8‡Oážm—¶œ8¤O( ÿnøÎdø¼8<ƒcp"uà=[86’®ÿ£'†6 ™„liyˆoMÜÊ÷pP,¶9±Ì:¸ž§æ…l-?C š5}0a%”bûŸœ‚Ȩú.Sîí_X}=gj îD6ª½ì2÷õ·¡"„ÃpØÕ˜§‚!ï ÃÚ•e¾OÓLÕ1‹Ã¢Ù^š6M’ g«ÃL{ZÒÄX.÷îf­™³h-`l8”­ Ú@ ù Û«Ø 9‘èÂ!K[ —÷,©y 8-fÛ«Òô‘¬lz,qÉò1Öq'Û„·¹Y,Æa˜€È!l´Ÿˆt&to5,wÙ¸lnþÿØ{ïî¶‘$^tÿÞOqgDÀ!LiZ#[Î ¶%9Œ¬™`™L–d÷³¿úUu#(Ì̾{ß;çž{½³"€NÕÕÕ•:Ô„ÌK+¯¹¸9>µesIºÚ·y›NO¯²ôô*K+³½çT_"Ý£ïxU °o½JƒþÒ ×ÔÎÍA»ßêc—âIq± ’m¥ÔvßÙ'yÊ¥õdÛ8„§~A,Û}¥“ÝW™dzQG&hx÷`±yúŸœÚ7^ù丯М»íTöÕ(};i÷ؽ3ÌïgéêÝ©dwj§ ·zÄ{TyX.°ŠWoäE6^qËÞ‚Þ¢ztª3lMéÉ~"Ælå­…?p4½²ß ·%ådaáY¨N H"j ΀×sB"×Wgß:õ ×>%}¾Útm¯ŽýcìR í©"ØÝ¢Ç.LÆSX ö»o× âòþý¬Ìñj¸Ö|ÎÖÌ,["XïcÙkˆC.UÓß0ljËîÐsdÝô ´]cuìA`wÇnG;êýtïo»+;Ò‡¼É kRÞ©—³zÞÂî+^pã „c9±%9α?Om%…@úî~R@´dw_m_á1ñÓáñixv1|ØärsÔØÞ›fÏ®xì™%f÷F=TŸ5±íû…Áý9H›k8jx·&¿ÔÇÄú5Êz”uÚ¼dÓ“uOBmƒHZwÏþZôù0¨¹ú‘7ôÎx¼ç™G]œ‡^äÓ'ÒøX×$Šd‡ÐMë†Æu(¹;X-í6±`Ä繈÷쫵mwK¨õõ>¶ò±0ü¬=ÕMƒøõÎ=½2 ²P¶ZqÂ{Þ£KŒ Y„ú+[v­gWÇ-µ“¹ R®°Ðí8Ÿ¬Ve‹¸×QÊ¿•-L2J baµ^{­²ÅgXêãVuŒÃ É™léµÎ¨”²gA½Õ±ÌÛ꘬Uêr­³›æ^e˺éМow©}²Ñ÷[.~4‡Ç0 8N·Ï¸’iÖ!*1y§ìÄ-gGɹCû€‚`è± ûfkÚ V¬×¶&ÆÖØØ[ß /2¶.ŒjèFý¨=7¶†Æ¾±50¶úFõ­á]5ߨm[¡±Õ1j[F½glùÆÖ–Qýfl5Œ­º±U5êá½1ªÏŒz×82¶I>cá™…Z¥`‹Øq*Ĺ¯ÆARÇ=…ªáƒ…¼k½„ö‚σQ¡ƒ–M땽B+«ùˆ¢Eðþ-|nÚÔá?†ïþBßá½ðéƒ"XwñŽÒóÂ|€§Pý\Ø¡áø¨¾6™UA^—$½,v»CÄÇq¼rÔHí%gI*(ÑbGv-ëÒM s‚•ÕK³|T¼K–¨†šxò9e=Tb‰t$Wá;þÞ°TÖÚ³\V9 Ɉ•µ÷|ìÚ§gPÝmœa¹1|L¬ÉRݤnËîFõ£™|WÇ]«¿·MüÅ„üuHÃLŠp}†¯T2AE¿çó\ÏÙþ¹|-Vö¾ùü¿Ò ƒ§vðÑxï-Þ›}lïÉnäÊ.Ìud) J”‹5Â4ð¾ùÞ®ì6±¥¡p+»Á_¶Q•ì…Ç“-GíÐ’ÅÕTvIIÆ{>:æ5X‹‚>tE’þ•©Ò+Rޝ¸ºcRÉeÇ<»ñjêÛ o¯õ/cÿ¸8Yyl%gt ®×ãà Nã£Ypw ,Í+$Î+OÅþ°Ë`¨ J™T˜k,W£v! ;ÕOÉÞ]¼°SïÕg õx/·ßʃʽí‘ÅTßâUg~vßn×—œÎÇÕ…¶ÑØ=kœ¶Çç¤<¾m (8nä?ÜÍ•šA¤gâ~F§ÅæYh|°ïíjÅÞªÙÕk»úÙ®~´ïìÂF¡qd7í­m»V±k®Ý8°½]|¯MíÆ¾Ýxkov%”pQóê¼^ÏO—äý&W˜M>î×Qû{^ð]j9ß'Y‰iÔa¥­kÑPv`z ;í.´1²6ˆQQW„e_²Õv¥M3WTì¬Þ“ûÔËj…ϲ™‘Ì-Råä/ŸD®7̾ìÖíë¥ ØÒ¬ÓƒúÐêÉô‚«°/oeâ_«n» o)Žì/xï ¬!§—M±´š¸J¦vI’Y¨÷ +éVr ¯o‘¶ŽxÞÛ‚½ß l÷žû|*­à~*ð … Y|oÍáÎ6·þØ|R¨Nõ”]˜Ý±ºêËc›îø‰84ùBŒ¡…#§Vkà€Ëá…X¶Î#Ä·øûê)ÃÜp¯MæF¯Óãª#Sçàƒ’ØF©.ÀpüW4æ++=¡#¼4Åéçé8ìÇ›¼)ˉ ç q¼Mw»/ãÊ{ýñ×GHKɹ !d¶É6ÁiS+ÞáAćtS©’½P©ÚÞUÓ§®5³:+Ü»03“ '…Æ+»ñÒn¼°{vã™ÝxZÈ‘øT‘ø$ÞKøñ”L!ì§mÖ…òÕ „¾Ðœ:@sqPªOùFãý®`4èdè}jú ‚.¤“ÿ<{Œ‡ íا¶:&J©{rt(“Îo4?9ýÙ_ÂÀ‡¦ ˆ"b7Ùa4¢:êeÞLT/7AµµßÚ{8ClÕï¤Y¶?›…ê‡Í«’Uª|,ù—»qEy*.ýÙožÚµ/ô§òžþTß“ŠwÈÙ½CÛpçôSÀ±kœÄTpÇM9h”§º(Ø©½ò“³ã‹;ç<~T°«—Í£ÍGø ÂGSÁaÀȺ‰ä´æÙê¹?ŸÖíÛÞïíÍöׯ;æzü NW¸K{ß>jGdÕñrãK3rö××#§qÅ+Vô¦ÖréI¦7=H>îìê;ÞΡùåqR|leô~·, J!‡4Ž“ÑzŒÚ²rbÎV|ÉÉ2cÝ¥";ªà¶…ÓÕJ¿ðjWõ5ÉR·"9¼“'e‹o¡î.œ®Œf^+LF d$pN)yûÓ•‚-i÷z$3uj'0±Ë 1ºŸÀÍ>™û ÝíÑ{¦G—/¼ÑEޠȳ{o‘É€' ¦T¤Y^Ô‚{ Þφ±¬K€¡…?¦|ºSùîð ÙbcfõJ€ÚþGýç}„Ëõub3Û`GµY“(ËjË'íFÈDZ—·-l+Äø6ºúiûmfÿ®|"6 †dm7MeRPKbUd¨¡ÅÖ®ª’4F¦…ܦà{+­ÎmSun¿)‘>è¶ùÔø!žfKÀjpóÇ!/ØûmïpÇw¶_³¦M¸ò××÷a¤zm&dN¢ø­ýv‡¹«®TaFË·oìë/ÐçöyùÔ,lìóIêÖ>é6}x$’;҅ùLð¥ÅÖgS)‚ñ_Yòm:P üâ]AÇnÉY{ö9û| æâW·`‹W'á€[¶®‹´"UËÝ9€ƒo;øk’íÀñ‘õuu èW¯ e£ 4reʇú|<‘%lÊ>}û´=(‰ùu¯ùwÅ£Õ䛡 M—H9¹ˆÏÙ6œÚŸÊeU¸Ï×»$;Iõ=}…Ç… j…$¿ÁVUhÛ%ÉÒR•ø(ÉåZXÕáoRA#=%ÜòåÚ˜#¾mâ s!E¶ªªÔ m3?WÊ“^ÔöT²àkÀCÒ^cKl_o,~«äA¾ A-°t,Üo·•øœš~2o,áÑïê–FýŒÍ1>ú|ï`¸XTÁi“—i¿sc'½¤ /îÍpfx~_†FeØ»“á:ßÄÁ½2Mä}€:‹/ô´²=ìýf_`‘^ÖÖIœ5Ly‡½|6p*uÈÞÂ;ê~¥NÝ¿uûÜï‰rƒ öÌv_¶ó賫õv£õÁœa~Cùog3lF!`ÉàxÇúýëíîKª·Gìžy Ç™ÜªÇ3¹Áºé4räÒs*•6h¦R0Å+"ä o ¦,ÕZê71¿ñ*½º‚/õ¶ÌjÝVË€›Þ8vc÷@.ޱ¬ðŒƒqaÇ}™’EÓ?7¿É‘}°i¹‰‚`Ÿm”ÎÛo 6J8Êe:¬_6‰ÙvÚ¡ã.̾Ÿá¥©r%0;سd{íoÄá³èÄj`”}¦ÎWëÎGÝ1ìÆÙðZT—)o›ªNë‘×iéŒ^‡2áF3¹ÔäêF©]Ø)¹M×zP5VèT¨ŽPãP#ô»/›îÄÕõÔƒ£æ¤ž¾}„ø*<\ØgRð¶`—á`Ž)7Ó©zø²¼]9$âgýãéujÖ®ò}^ùÑ’KÜê·®X!“ÏËÏÙ4ظ͈%áPç«òç›|>î<Ä6=,ÁÉ1Iç„Dªh?x%T×kLÌ¡í2 °eGšvÍÄÅüÆØm'wŒð@² }§´ï¼ÒL©˜A\ÁwcVþ»­oé#1ý]ßrµÛVwùª¶M¨W°Ðú®W˜¿;o­ïXã„Xú*¥F£™\ÀËŸXÞŽýòN§yã¾ivEÞËñ)¹±c{ËfÇ®ºMIðõ…JÛ zZµÇ[⯷„’à-ÕÕ;xÆnñ-§öö /ç¼Á†ßF•ÊÕ°ÒþG€3‹—u^וÄvµ3{ÏDvËÂ_Õ«߈C`Ý4àýœÙí)êløf¤á½Ë}6Í’·ílÏÍÙ#ü~·6=k£ìÔ¬GþF YGX¨n5Omo+½*†8\­Ý%‚9!Õš^ˆZxèÊïþÀÍÄòœ:†+„«{Í„5Öï‹¥~jçŒþÄý&—𾜡Îs…ÊFæð:nK±;õ ŽGudnë°Ý…^£©k 믜MÞÛêY•ÜÂN.¾LS Âõ> âùúúüIi{¶3oê;bt¹Æ®¼T>¹€öGñ7Lé0’*#Ʊ¬€:×B¯±‹‹é©zH“~öLqLãþ¶…xÖCB6C.åÔ:<ÈG˜ð ¡…*˜aaÐÙ,úØ"Ïñt]ÃO5ÖxöZ–LÞR‰¦oK݇Cõ`ø¨¶Sl†©À®a¥LÆž†X¡QN5¯‚'»‡d56ÀËøŒéàñU@é@ZÙQ)l XïtNˆ&JÔ?lõ@·*mÚeÈñ/ZY^´Õ2?Í×Å¡À寋«ÇPTF™¡põPpÖjMµý1Ø Éh…ÌVÉ–¢îj/{i¨M.„îÝ-^übeyŒ>UZ õª\‰ªJT–UVóT®+=È|§\­ä;#cÁÊfYP3ø›Ùµ³s¥™›J¿ q`/Â!ŸªX”€­cg²©0(#ZqϤz—wU]§ön§PƒnÔ¨¬s¬ã)Û®­ŠZéØ0a¤ŒJx¶¡JK¡±ª˜5ø}S{Û¼Ù5·/ìía³Újs»Ï#}ã©û_}ê›BoÿI ÝÌÇ®úè^gŽåúŒ \Ä€c˜?aË^¦e>žù<òHÚ %ÿ`•+Þ0¹éúuŒ«øÖW»òâÄò§¼0(’åÛ|«~ûÄv#¼D¶ûž~½Ÿví´­mâ¼æ6.<ÚÜöeE×q,ÅóíJ·MdADQ)3QTºî§q-+Ôx‚'-ÄÁÝ 9•ê¾g 4´ñ€í$–M©ÇùÔ®NíZ\¾$ßë[?ùجF)'Ní³M>ñA_7²ðÑð?ñ¸²wó…¹½ñÀR·QºwA]]«ZÞ3”ß©`ûJŸÞ²]³¨»-Â׿n7WÅNÕoºQ‹°Hïn´"@ØÇÕ„kÈ{oU¾u„]\›l×c÷Äy¤«êã"L/ËB໺ ’£Ráó‰°ÉàG)pÏM³F2Ŭ`ûM߬ú 쵫ƒ®C§¬©Þ.p¦Ÿo•.¶GlUùÞ¾q›î±íîb‘ë•A ú<4rVØ.Ô?â23;y=å»ÍàF Í‘½ •t£Mô7R§‰[D!x_èÓůÊ÷̶‘J¹©…Œ"|¦x¾ûœ§e#½Ë¦ ‚YBOÕn;?4¾ð‰F —yyÕìpæ–G9ŽKm¯FJÜ×âvõkQ¾í&ßüøVeRÆ·}«Ÿêo»é·ø¦$Õr!´'5rþ•th8é_÷ 2ã‚æ-ÂÂE˜VrŠõk±R¦vpµÕ6˜åêÁ¨¥âèãí_‹µðk‘r×^~-žëEtLݯÅêõ×âF§•Þ< žYÆèkø³øj@­á6pò8<©»gÛ3׆;~S­–‡„ïÌk—äo³!ú[M}nžJ«SîÕúÙp‡Púúk±I?o6è^ W‘OŽÇ«“ñØJÿÀ‰}Õáníkòu}Õ^ë¸þ¢>,Hù<~'¹à¬ÃgªH#ÙàáåÛùºÙ—jOv*º]VEÕ-ª®¤,nïëòí}Ù/Õžúdú;òµ~œi/ÔF³Ì¦ö‹íºg×ëÛv1–ˆ²ÿý¿a/ÖÁBb éÿðç±D,'^Ì—aŒ˜1Æ!s´©¸7Ç:ŽTŒ¸g1"°Å ,æ8Òq<™á¡?R-bÄ€é '!)—ùô2 çñtÆQ£9ë šèMbJ0N•ÇËù(¾N‚éeŒàȱD#;¤2±ñ8†q7ŠbÛ7žÍ§³XâÆˆ‡W‹pÄ͆²Å*âIŒ¸èq—  žvÔ'„³Š%:Ù;n%î.ç±Dª$È~Äò<î çÑâÙ`8 bòŠºp# tÌ1Vâ[±#ãaôB#»7-¨ï¯ñ3A8‰þ$ ’cÑP¿ .sŒr…q4 f06Œ­Å|Øï‡<1!m¸ˆè9¢ÉQÚ5uUEË.âæÒCÿ}ë¨IŽ:Ç :^0^%´yÜ_ÎqÜç ™1ÇžŒ{W1b”ÏŽcŽÏKPðjtì wçs7ù¶TŒý«ØŸ ©Ga̱µj Ä>÷<ò{þ|Hùêi¿O`S_&a,5±ôýѪŸùDuåbAäXéX°œsÔ˜àíNg×D¿#"XÁ#×å$œïi"•صñ$ÍJ¯Â.úÑýFƒGN©Ÿ2\-އD:gò8æ ÔÛ>Æ`1ýxË !üŠ> FZüòù òÆÕ8¤ÜñlÅ‹á8œ.qò`¢„fÁìŠZgñE4ç̵<ö£ëI7VÁØ÷$¢WLc4ïhè'ÀQ ë÷eH•RDb4]'4»OCš¦a‰ f4“/‰¨À»8lLs›¨ÅTßd|Wè{|@sbÆ\ŠÒ/hŽ $5ºE6ݧ?‡£‘ÓðqSo—f(ˆ› 0%ð¼&FÔ¹Ë “9À¢b—M0ŽæÝX¢ú?ˆU˜ïcfÛ]êq'¦‰Ãh.2Û:8òU z~¨™Fœ7ú|°OS-Æì$Y2cŽþüÓ„H•8×8ÂETLh"–xSñŸ „VQa!ŒÄƒi0ì £‹ÐŸ#ˆ%êÿRÑâ‘ @„;žÅËYú Ç3bÈÄ6 æ]bŸCâ˜4ª¯NöQÃk ±‹˜¼RõˆÙ¥©ü¥Ç™?±aâÝ?„gôÒ g \dú †Dx“Ù’ç@a™:db#ÂÒlÂÃ:™.¸ƒ'Â÷ˆš ¥¡“6I 9XÒâú#³5I!F€$LêT #‡áÎ#1Ähȃ@~ûágbG ÿmx ¯™b¨ü§WĘƒc&¤Ñ:ý9fŽ iÉc?A¨!z¬?Äl`ÙJ!cDêÒ„«¤(f‘¦håHH2ZvÆTa c¿‡D‘æÌŽxXJâ<ÇÀDŠÆ$¬\ìw¢éHÚEÕ]‚5… Z"Œ‚‚í•£@f{w1ÂÎ02¬>@r sr`æƒ=E\ÌÈæÂ"Iî„A$$Ó™^¡ö¸\Žç~0œÆÑ%ψyØ‹šö’G µLJ‘yžHP025e‹<ñHÐ`Ï™ÛüŠC«8 j'Êp¶§×4ù‡4'¡0ˆŒ!#Sp¾œÈ$±Ì#®ÿO¦Bü!èöŽž!P0±?ù ã䉋,¦z†Ñ+O¿;:>!ê–‰þtº–Ò_b ÑCR·;ZF˜KAˆ¨ÕÌteTyH„¦ò¬8ºdA÷Å”48 y-…C¦—e‡ôRl|%Übš’˜©!$”N ªi Ò&$Z ؆ðj6'ùJ3—cËãë½x ÍH¾óPbz 'D~¯DB‹ ŠñŸL9 6šÌ“X"å2ÈÇÂE!T ·–Wà;˽c„"æùB]õƒ´0l€¸u—€>¢KüŽ ‹x[!½žl|v¾ÑDožÂÿ©t¯ð{삞E9þ4¤Ö+å*:@{”äf?ÞgáFNSþœåµ<Èp¬TOˆ–yÂs}êãBáþ˜ók Ì%èÅ€,ˆóþ|JÒ„¤Ë+ªNñýx—™ñgÍ^¸ˆa†Øî@e#¨F¾°:ƒ¹¡H3 ܧMõŒiôªRcÅÊ5á훚s"?¨ÞàYøÈoÏmÙ „ËëÈ᜔ÕáO¥ßkœC&Ò£ée õI_±ú¥Òl8ؘH’é³¤ÊØ*!tE*Ð4„RI^“†q,ò³3,3ˆ{BKö'ÝpôtÙÙ£Oá’ªí…#ÂÌh4[d6Ø&©iR´¾¨ßÏZ;àáNb3ç—Z¡× 'þH©ÂÝÔ\¡.CM/UÖ4"´(‚ïPýÀ#†#­§¨z¤låt¸+[I¬Üáá™`Ñ1ìÅhˆLvqy¢Š2Qf„«É”&qÐ-“‡TVQêXT‰T¹HszBÖà¥ô¨7…£2ļ_пxYv½­˜1Wuħ¬a!|©2wô ±ÏÏ:îyF¶ê y'ŠýnOIXÅb 5í~CY½%æÏ°7zXé"Tjññh¡fÔñše1, |!-DÉñÄ΋%2µâbÈLP1ž„UQ024B£cØÆ@p0í„>)Hø©5σ¸/þzRž(úG@k•y•ÅK<§N_XÇ ³‚úè’‹ì›/PB00Êôî5! R|‘ÙÄú&*½ƒ&ý%u혃ÌÝí]ÿÇ ª¸G$AÇÏë ̼2»äçÓ™üîa–’¯•?âXz b×ó*ñ¡È•‘nW!Y­ÿˆ˜f5Uñа™¯­°(ºcÊ&ÕLdÖAÙŒ‰™U+æH©Š/Ò4‰_œ°¡52v·åø }-»ñÉ`iů{1ó;-¸ÀkONÞ Ž†4îÑ¢Ÿì‹ ›`¬+>5U¶ êÓì—X6±¬EoJ*.ÛêÌì.¤û'Õ = I;ù"É¥ß$ÌI÷àòC‘Ê]^Æ,Æs­5c€ÑÌŠò›ã£Cü*‰*ÔÉ*ËpÜgƒ’é’Õe±f¬žý™B ›Žgd ³ÿ¢è°SÅ,ÆEË.ãÎ «¥#.Kämq¹êÞq¹\oÖ™ˆËÿþ÷nìqA£­âظ1Š‘ÒëŠMãfeÅN8 œÎ“„52îõtÂQÈoƪ…HΙPÃ1–©!&!½ø ƒŒ”02†=Žê,h2’6Œh0]Žú`°E"yOwñ¹ð?‚Y{µœû kc}=ÍóÜ“¢Uð\Ò-§Y.-¯ð¦}ÞeEÐ ©oÌÃ>4F²L2}[L ßÀhŠté§I¢.ƒeN)1m Ÿ¹E$eUe+Šl#œÐD7C…Ê„5&ÓI) žmœ¾Žœ[eNxÄ®°QŸô†=b¾Ó˨‰¯¿aVàþÝ.•<ñp´ íß5L˸Qe ÃqõL¤ƒ‰©J9º¶T*}NáèAÀ¨%X€ À­‚‡3grïhŠšÈìˆ jV#Í-A8†cìQÞØU Õ ø$4»¯v_mî¾Ùý¬3œ£"6ýx8¥ú£hj@Ó3àìNûÉÖ¥8ÖÜ–bÀ©v8A]bñØF4_´Híø=¤èÍ¥("%³BÎt”*Ê‘pfU‹wiLN†È‘e˜zx…ŒìÀ•’æQs8‰–spdÖùx8ÊIº¡{Ÿtã¤GŽaîMÑÏUaGº.R¤!$O{ùrDÜìf4Æþ5P2!tqSÆ´Ûõak½G³á"ÍŸ` ÉÞOa@5~1ç¤D,GÄ 5”–BØoìP4^-„Lwsã!‹}ÇxÝì î…ÍiÞ¡‹Ku”Zµ“åq·‰=:¦…'†‹Òõ±oÝ M&pXó6ß”¢†A¢ãùUØ%IÇÜŠ0¦îpšÌ#+,æíYm§Àèª ¦û¶\ñïêßðœe¨¡æ„416žu p‰û!ª0ˆÑP 0`¨©¦¿inq†9ºe·¢ƒôÒpKéšÆ‚!áyÀIo9§<4tl.EN~6èIx« qüe%WâÐÜ ÞDGC›ªô©5U¶íJïáR$´°þr’/r„-v×¹ Œ1alJ‚wg채‚ 4_e(/µª¸• ÇÃLÓÄöRºkk&wvÞ¢/Ó¾:²„F_76¬Ì„u°‘ÑL²q¤Dm©9hf¡8CÓçàŸÙ¯N²MÒ-‡7Ú˜ ÃÈLÆwX¢>cuÆÐëb©NùÍ‚,§‡¬nÙœ[Ðc³³$QFXK(Ê^Ü"ñFL«"©È\,Èã0Š”G%A,ïyM'98 ŽÀùÕI–„Ͳ ¹Ö6Š7E ¦èÃΊÖ-fzcMƒr¡\“ÿªÑ!¾Î”ÕLù^ñt’¬“IG¨ÑÕ-¶Œ˜E³HŸËoE«UÌ£üÅ< †Yæa`g¯!Û}ÉŽ âPÃñr¬>Y¬J² ¶œ¢šådÂ1ìϯåìÒŸ‘!KÀPË.á„X÷ŽHœ gKQ£¼(ghd½ÿîj„îþr’Íg&.Ã`ø#»â”[P2‹”*>¼_Lz´œn™2z'mÓ(êMcE›SÓ},Ï®Ô;¶kç>ðeúâ&_KMj¥D¥¡¢|.Z! Þã¹YTÒ—’Î ê²²'ˆÎ Û©B¸øÓË"3¦{ÐIÍüçVëŽl"0ó­}šYÑì?ávÇÓàÏyx9'ûÁXÎG¯¿b;K^Þ2Iš ‰C±eôÏd¡víÄx÷ê•£»Û}s ÃX±©¹¡ô(‰÷èo6Õ±s–MÛ¸[%Wc%zÃæ¯Þ‹Í> Ʀ €fqT¯£Î˜Åïí"Oà«Z\w“²õÔ¹ž_½šW/æ¨$ •lÂWúŸ4¤·¦çKµ>+wÞ¢ÇB¾x½[-‡=¬i'Ù²xS+)“ãú»“TÎ{„QMx[k1·ªšäËúÅ2Ü#IO=ëXùw³33É£æèä0•7&)âQ)ëKÙ6›d¢F¥›¼0LȪˆt@Ã'zï!Ž“î'ŧ—²‘@XŽÇ×E"’€8ÁP|é ®Þ$µçŠÂÅóIð9Íâsl­¡?4«î|k—„$;¤‹`%‹½þ„iJIs‘“à@RÛº%%—ÌÇy¨¬­Šo<˜3‘±/Z¯ëeåÄ›5œ°·Ù7`Ã1È,QÕ˜]Ÿ4ÒÅ'å[7Ìt•ÚrT9mª¥…$3|J\Üݪì›ô7Róžuë„öŠÃñ“bêTˬ»pfRºo"KâzHv„uI=ögÄàÔž0·¡öƒ¹›Þ¶á–›µ­¦WËíÓãÂû Ås™œ½G…ÞÄl,y—F4žNIbȆUèÛ¹ñãj^èYKR}K¹é/é7gHôìhèƒÔšiŠºU<9 "[˜Ò=*QˆQ\„#ìéúðœ3诟‹æ(5É>ªï=XdèPœœ†œìKè?•›ÚåÙ†~û4'Ó…éÈþ,‹„sÒaeÙže6ÖšÅL%§Þ«ƒƒ•æ­oÉžN3aÔú´!ÙØŒª Ã3[ôU6Ú'ßõ Îæ}Û7’©«¡’-Û¯'‹)N”ñ vÒs®™Å±[)Ž¢"pœÍM³þÂf’BUSŽ‘šI¥+ 2Ž#>.T4Q9à‘‘’35°cü²_"W÷yîEvàþKZqÔæ]Så}þå´p‡šþñÈܳMGaVï ¹‹]¬Œ—ì[>›—ß—s/ºs&N}¤~ò”ÊpÔsäXœ•™ÍL·…Ÿ#'yÒŒ‰U‹Ûn'–µ/Ûúu[™ ¸ÙVr¬øNC¹”¤BÉuî£#š¤îMg:Ko°"S«émZ\hÃ@'{2¾Iæ'„¤ Õƒ¬¢y·åLÉFζ%ÂS„¦´¦•×þÈ|/\%†‡aË©m ¤;;A5AäH ·—ðª MçYQgFaŸô~™;ºžtS"æ‘®H6¬Ý™;ŒðTÝH‰%E‚Ó]½óP¶âB³Œ”æ`Àåã•'Û©½¬ÞÅ6‘·üL'… {’®šIêßHvŠM 倷´0ndfb#ç°ûwZã´8G¡Ö2åÜ—öcë6u•¬*A²²*EB$œ§‚=A£ÚnÈLN°¶rŠF^ÍÄ¿D¨zìðš nï“â†Ô²Aª‹ÿ.,@}wÔ9K ]”RL“—`yNæöŽì‹^¨n„†>yeàôa”äÃp®%C°É,™!ʲQ\H‘Ý'r¯æcÞÒRù‚JÑˉÊJùŸÃkÚŒAVz@í‚®°t)®³Â“Ç›”ü¤˜̧J³1‹<„j¬¼8²2­Þ‘+é|+¦š|FÛäKä¼R¢pÖÏqEétˤw^¥Y)7+õœÒ©q† äëž:0–Uïx–î;šH1«Ý.êrÅ[–É=ÙÍŒü»Ã¶2ùæ\ì£F²KH¶²N®‰P‰DFâÍô'P?ŽñNœÚXwcWÄ|9™dvž)ŸºŽÄÁM"péÛ n§«]l6ió–ñØhä‡dI…à{†3,tw¿±2L¸å®Œ›!éEeõ*K:ÿÞÌÉF¦©z]Rö¥Ágg„Š2˜ú'¼Ù03jý3À"•a_8¶ LˆýÁ¬´wLíìW‡‡†aÆ—%àJ%)àš˜¡dRd«EaÑT¨)¦:*Uc~q*¸•”4³.þœ“Ÿï³H´îÔÇŸ([üpæÌ{ÊÄô°ðrY6G+Ç ì˜d0S¼H‡nsM5”ÅÛÍpÍŽ.ÿ‰X|1œ`?®:8ñ”-…’Ž+"6„ȈeÝ.Á!^¡”½(4+ˆ´Å$হ”ý[í›èéMþ¤; !ûZöíÌ5eóéBImÅ¢.{Â3#Ó©ñ‹â銯êa˜¡àcÿG˜+Ï lÉH@gNJþFͼG÷…¾™Km%jHèdê^kgZJÅW.O6K+ÍðNÁÎä¢È ¯¹’¾WM þ¦Ö²2ÕË©J,–Hμ†^"VÖ¹ ›øx¯&1VȈà°¦,‰©¹¯†”©úYÈòŒj@LG”j&êûm‘×_nkh‰þRiõNø]e—E7¥håôçW8©·-¾~Þp’TŒV¦b"?ìV*浌ZîNuÓŒ8ɳQ$¾rŸR‘ðÀN;­;µr3ø oåÎ j¶·w5Qž:4¡†?á‘åfÈþõ6Þlª–% Ò姘bç‰ôÿ›™‚3‘Í“ý„þxþi»ïAojÞ”»¯JJ²ˆT3“%ÓÀ0⻊ЂnŒ4|oýú8Xà+ª+mŠÉ¹q«¨ùŸÂù,—4B6róŽßÎ`°™@±ÊˆgðÊî1u[Žf4&QÈû°.Ãd÷]¤œ*jKå|JJŠÞG§Ô;]³^=T‹ùʬP“Vä³Ô¸œ)ŸÛ;§œ„e82±¯tÕ26,2æ’x±x{Þª¡W;ÈÞÈW{›­1™åþ„g`ôm¾[ü ˜ùvn9Œ¼É55“Eòàdyæ<§ÔÜ!}ÐÙ|†Ýø¤lž’ÚnY8Z­\K—üõÍ  U+usé]ÿD£€84¢îÑеbŸ”xxiãŸÕ±ÊÉïdKúý°Â׬0,zPMM5›d5#ñåÕ¾œBAÁjØ÷QáBBíý‘û+îÙ4!B„wô';c¸|'\\†D ~p±Œ²»*™Cȑ™jÿš$éEe÷öï¶’/)þFD7œÎ»aF8'Kв‘Mýc¥;§†”Ó™vf³ÂI4p\-¦G#Ux ¯VÖ’¥GÁ¶)?Êný×ÿý÷ÿÁ?Ù„Sß$F›jMemE›Ñf/ð·ýšT+ÛõízÝo„ae«Öí5zõ°Ñ¨—‹èïÛÀ…õz•ËU7ÿëzr£ú/×uk• ‘C¥ò¯²WiT+ÿ2Êÿßwÿ_ÿZbƒaüëòò²à¡|—þ¿é?í ’KÒGwÏm•­fe;ã2°ú€Åeèã‹: çÃðÒøë*½Â@mÙ|6]Ïea×âÚ7ÓÁ„­‡¾a*ºÓ1Ÿ:Ø[’nŠk&X$Äݯ¢Ô¼>1LúSÚýìùáñsgqµàÐ]^¾Û7Lú“KÔµ$ÇpN“(•k%¯j¸Õ¦ç5݆Q*WËeÃ<öÄœªÆÍÙ¸þá¦Q«oÕxÝ„wS&bi†°ö7;´çÖMØNX7ÂÝÍîc§Xl†fâênú–em˜f·ÝýÕ·žTj;rð٧険žÑìnxÛV³ëèëËÌJݲV­aÏ\+ÓclÚ’nY7|ƒ¬Ù-•¬ùýZçío|µ1ž[ßÚg x¡Ï Œç«óVtTD ÆâªÕm»«VZ3µJ­Y{–‘9,M¥:Å 4¸Á6ŽLÛ\¢¥šœ­Ì¢ àp‰p‡Õ»2þO¿´Þ{ò‰_ÛIˆ'̓˜(ü‘‰—íÍ?Îþx|þÈ|¬‚o<±Îþxrþè—øÿ˜€ÞúeÓ®{”Ï9û£ùŸ¯_Ͼ~u(yÓv=¾j—úWÛ7µ ‰(kÝ`qŒhÇŽ[·nøúè ÕpÞ¶]ŽöÂQ–‰b#÷@/p2àˆf/xæºÝd$ܵ10Ïðr.Álpõö±Sw)C…ƒÖñ=ؾãýXkó'Ü©Í!K߯´ÏÎW«C¯•ÆqSuHf$[grgcÊ›ˆ}.•4œú“c̈x\»lxÞì­—Iðã·+ûm³ls_‰vøq*ü1®ÕöÏW¶÷ZŒG\±ÂãÔ&íîï^Ùu‹+·¼¡×qgŠËWA˜ßew½ÓñííÚ0­·lS³ûAÛ©]îà*õfÇn ^ÆÛ4®‚t{?S«[I„ñ$êýY1ß"8lA#´oV­@® ×1u† ÔE ‰@¢G  ÙÇfƒ¦7½ N°;6b6s0·¯#p½4ÉúkÑ|-r4¾¯E÷÷¯Ek}½‚ >˖Яh # ’ç#–±;—N3]up ÿvc†Kì–ês“`›Ò¾¯ÝûIj9µˆyܶ ¾¨×Køp`Õ©,ìl°®-Ëßh«¸]ˆV—HjîÜ“°æÌ.hFö$ïeúÔ<°ìZ÷GÁjÕ‚LžŒ`bô¡úêþhfEªÔJ"­ö3®¯uM+ çÕ8{~Ž‹ý-<´O9„VØFô˜ÆÝÃtl*Öë– fŸ±_@óâcŠv9âK‡‰+I¸ÎРΆçÈôé¬s®Ÿ}èÑ|{.W8M¢]í9•g‚}±npP1<¯8zU¥iÆYý¢§G'e9uOÆÃJª•ˆ?Ñ:Dtw]Ï×Žó–æøYáÇGÇE0ª®. BG—÷w˜6ˆÏ=.7kí30#Ü 9åû€?3-[¢¬+ª|-î@t4ud1€_y¡J¯­ùÜë>Ó³óöIye7NÒª¼Ï)lpHô0é2sV¡·BµàÌç qä‚·[°$’^שWíz…„–8ZŽ[³½ôË1›wKÞG„u ‰/¾6NUø&ïãNHÂÇëñÓ†ÛtkæôØëqD'fõ."±tö>!Ä\JÍã/ïÊñ';$ºçMÊq… y©…N«^‘ÐqˆQ¯€vMajWœ):¿~#P'Šu½•àê¾ÕÙ |~-æ‚Ô%[iÀºõõÍÚQ\ÛçÙÙpŽ,¢ðê›¶)ÃHÑH>i—9è×>G,• Áa#Å!B[Ѹ‘|Ý3 Û %0Óû”­ÔÏUêÎ僵Jâ]Ñ4­’H¥n#¿‘÷6/ã;Œ”ê«æ)ÂajáhtRÒ¨}§' j7¶›G(áúþV_10Ãå³øn€î_¨vózƒÌ­7+Dèj«AIT,w›Qu³²‡m×&CaÛykW¯ÚÔl-a[¯­úÖiq~—ó·ˆç­òŠŸz~U ¡¸Aœî·íöŒ®Ñ*•†«&ñCàÎ$ÆJu Ï-h‹à¡¬¼º5”Uï,³{®¨ß»´êˆu^½Z_÷.¹9Ê¡Ú^ó.aó œI­k‰c“>¿¥vÎΛ7+‹ªvå]²ä’üÞ%1ÍŒ²çTÛAah³ëdص9õÄ®¿loþ,íÔ†ñÖÓÒÎÖnì^Çõ§ñÖÒŽûûæÐ®¼ƒÞñŽÑ"A+·–*Ê6Ì@2ÙLËðúI½¬,ƒÜ[ÓÑE}ç‹WÉlù2ü¢³óWÆu\Þ®Nè¸Ï¸”Ëá¹d‹þþäODû.â†+p8âà7ñK‰¹×à4gê—jÎ ží޵E”ßrÇ$ø î|³ºPQš!µ,úìÎÛ>¡“žh¢C©GDÆ´Gwlw •â­AoPø%n]¤?Ž77­6iÝø%¤|¡QbÎØe.ƒP¤…´S›7»¬}tI cÉ`És{c£þ2•uB÷‹¨Sü+4Ø‘VßΛm;éÄfVÖý«u¸XnáÆ;5tsšÄ¢?˜¬Ðé,îg€‰(÷ÄI¥Et¶S”C}*¨9,¿ÚÈÂó¹µJ+]‰訧!ÍÎ2ÍÎÀA_»(ùVÄÁ3£§ÿ%é!¬DÄ=&V!γ.M§ù—ËñP]ߤ®ÐÆO®BMÕ‰*fB¯Ch)Am!mcƒ&ö ô•€u¨¸R¦ uWÌ-.Ìæ›ŽÀ[Ý__çHî>fCý%lj³vˆð½ÏŒ–û¢yÚ$9ÌGV…>@Š66-Žvå Ž™W ¼p*'øòÁCñ»Ñæ×‚Q Akmø¬_¸ºò¤8gnwÖÄ¥@ú6ÞóíñlÖmˆùÃÁÔ‚EU‘¤€õ߃}A†¥¢.'ÕÁ""*¨OƒºB‚IÿX7!Ó³ó‘~ZòC䜯­V6¯JF eû4¶LJ¡úªˆŸ` våsQäÏ®õ›ˆAm»[M‰àZ©µU©3D³?ì¼yÆÅFìœD[­c‚û댳Õ#ÍvK¦éÊÏÚe‘Â5–Âdáëø­cÁî¼g¹4Ä kp¸0•dc§Ôö¶­ ñGïe¯$Q¼Ð0,@ëß©ŠÊg»ÖÑI̾24_¡…hÀ'õì‘ýMfàG2?R¯*Ï…¬1#ô¾©0â~»òΩUi°N©^„Œöšg*Ï9æ ⎀Þë¥czJ¤T m p€«ÂNÁ-4ÕbµÞËõu.¹U3â£S+·ð§](/FãSA^ópÄ‘»«ÃÍ¡eÚ×àAßÖ×?Òg£s+lã‡% C‹~äKªÃBkÔ±Qaží–~?·`X”~qiz!«PÒ×úÊ®Ã5ÂJϲ`:Q§Gâ'ìÀòžã¯ßî…A¶hšSfA<ûË{îÔxgNEoZE \ÞshÖMŸ~ÚüÂT[é£ÄZ Û Cëëý3TÁ¦éé®6ŸË— †$Ün?iªÏ!aO­L½ø”3ê {.{NUÅ)¬§-•8;"Ö,ø§);¡>ŽùaÀ2ló„U7½ÏÖŽ ZZ÷ôuSÞÐÀ ¸»k×ëTG½F-õËuâéíó„Æ×ñ˜OÊ׋$s½v’â0 ºÙÔýƦ5hÄkLJÈ€Ä>ûÿ¼¯E‹Ø_7`÷Ý qßñ¤1ƒev¾°!h‹3PgÞÝÌa9ATŹ;îëë×Í'Œ3⛌|ÞW{qãy쿌«'qc7öŸÆ•IìÿŒ&ï–Z;&É…'79¦à“{sz¢æB°¶û£=HÝB`£k=ö<=ö—0$Î\»ðØÛ5—wãòkñ ñ°Ç›Þî“Üá:ï<ÉÛø!9ðËCÊ?6ýï±çÅþ8ö¿ÅþÐÚÔùÝÉßL°Z(‡'9{žj×{’d5“Ö{+K@ŠVÒ¢T›§ß|ºPãùíæ$_ã»êÍ÷´LâšüîÇ®ê±+=>+Ûz'.ïþ „¤ ŒÁFxæÃ—©”Já’k'¥‘¹‚HÌ8õóìqy‡ ¸¤ßóSY4Q3Q£ðž¼”ƒ(bî¢ÝÇ´o]<¡¹]*]Xb¾õÏ.È>DbRx¡"dó“Jxü‹6E×°Põ¶9€JÈèRâ£MèÈ 'ö·âã`( pH9#-©ŒP¤h¡i?r³ê}#2S$§<'ã˜ZªYßàë ª¾µÙ3ö&;¿©Åƒ€Lê®Ì;.o£~زàþgi`ÙÕr»ËJ°íö´Ï©Õk‡ìAû|Ö‹WêBÆg³ö>®ñGFF¸éaÒ’‹d"ì:õ*’Xe$þüªjQ⨠F:u°ÊCRVcV82üŠá»_‹ cû£±}ZhF»»’1K08!Ä ©‘òä4àeDf˜ž=n-QnHo¥âDoŸl‰\&H·ß“ * –h ìZë“>R%8mÏjÊpLÌĆë5ªžðÝ1êôÓ¶ ûþy”ñ<õÀ5z_¿šgXç¾~µ6áŠÛ0+pho€R5Ûû$Ùm»gº×m‚çQƒX—Å.;TÅøyÎŽt¸ÁvLÒzä+Ñ }•ˆ³`qn³áKåÐ.{$FÉ<óK?)qûÕ=‚HPÂÈÖˆ´+ß”%‰Àëº7 ÷ ,Knü¢üж¤K\gçbZâuŸ0½ wìÔÿ€¿Õ×üüÍ‚‰Œ.²ŸšCz+•H˜w ^yÉÆÛ×Z±xRaçøì;ÕÒÙ‡ôo·;4ÆÃÖkÒ‹mïƒ^…“'¶wÌ…2œ†Z;A3dîX­–‘μcúÒ>Y1ßþ®òJ¿×~°K„lQ{ëãí¤+¬¼O¿²·së´@¶¶³u fëØ9VK0,åV6»f`të0ØÄß8ï%èˆ/Pi~¾^@ò“Õ@^÷!ÛI•¹ø)déÄ> ¾VfÅãY;é3ç¢çÚSëñÖ«qPâ–d=ªŒKçñWõϱˆZ’´¯_·^”èÏó;™ìú~Û{jT˜…?žà[ôÈ,l<Û(l~a×ß$‰ú«ù+›áušáì?ÎùŽJ|D‰Š‰Ö_³,°ØÚctwLÚ> Õ£‚¨±¾DÑ…ÿä²ùP® Þ¸Aƒ24 Í›­½l¦áãñYå¼T¦©ó,÷ý‰þ^ñómãk»=T‹x÷%T¦ÍdEŽTÔq¬³b¿Ãh .¸—Éû«Ç¹ëÏrßîÊ´T]²ÌžçØwÞ&NY޳Y„›#_íÄv…GK¾­Ÿ™|k¹| ïÏÉ•+59¿¼o]gznêõ ­+ìÐð-lޱ”B70h”TË…ª½5b‘G¬Ö÷YNm,,C¼(¤ßj}þF™Éþx™) ·ýOã¤l›Ë¦ßP¶­Ên]¦ÐW>Ð`|H{‡÷ê›ô½ú†c¦÷Þ'®ó-Ë¿OÉÖ#d.¬ìÚ‘þV;J¾í'ßö“o³äÛL«h1X¨¼OòM“|Sý­¾«¿Õw“o?“o?õ7/Òß¼(Å Xú€õ½]a³z{»qý:ö"ñùÎKy‹ºæ-5D,2¾%l.tñÜE™r[Q†úža7Ç‘­«‰Éuœ“*€oùªy¶ù‡ùõë™e<úmÚÚe‰´5ã‘y¶öè—?þG›, zùZÜ)CpØYS5ȼ9ß´©`ÓJŠåSØ¡|ÈD⇌ kçì>Nc«(å2Mç?T}ʃÎíJŸ;ÜU;ãlw[³Ö×ýµv’¯¼;,%‘³å“ݳHL–G6Ûé,é|g§KÉó&Òî¦gÞ ±P»—öTí^[Èê›õúlÓfº¾>•=úa›’Î[Óö0¸aϦl’\9¶¿Î±õãµöàÏ{帽h-ĵ€=j¿·+íú¾=nW.°÷rÉM#ü…x£{ÎfšVÛ[ÐÐYuáåÑ6^±;­Ûª³÷ÊÊ,m˜_'î&kj_,kÎ‚Õ Úsƒ±T¹PúÍ‚ Mó³ŒuÕQû`uxCÀÑÈž=Ùøç H$ksHÌd^³½á.‡H¦Ñfíþ˜»¢œ2e»2dëãâqeغócÒ¸ÿƒÀÅïFa'€;Æ{Õä_êâ³5iMÚéåD©b윀™5a¤qëëßÎúzµíKO2ý¿Ñ™,ä!3Œñ1¯FÚÅ‚ÖJ#c”bÈb„PNÔµ«g‚1»À»c§m^³§QŸ‰˜Æ¼)4ày›Éƒª%o,œúÓµávZ²Ç¸þ†ð6†w5%€qû¬ÌÔæYžSvÊüº•d]±ÌeT‹Ï™ -¶ÎyZg{¾Q¡¸ÍþŸÜfuWï™ë±Syg²k²ÄÆØ&æ‘ÒÕÈÆš±?s¼mµ0=ã=¾\fÖÞ#¾pö%¾7ðmãk±pþµh÷øÀ7aµ=ƒ+ ½Ö7ãž+ÌΛgèÜBg]>; ìàOiŠ‚dXÖb•äQ¡‰†[¼k–ÞÖ×yŠ|amT6ñQ¨L 4"<$ü `M?‰i p®ëâ–µ ’õ´áŒM+Àþ¼?VŸZÑx•AQf *>”\½rm3Ú\·½i–HŸ µå‘51ɸùúu#.Y;üaÄÂÜ£ª Þ„'½|y&_6\ú¶F4±·™ 2%l}']B" mº.'ðãÑwײJe;hÓ+ …¿¾ >7h_fn«ƒìqÙñžy?ÎÅÑær%“6{Zî“[§ú½ÝÝØhq!+˜u﩯ÍÞò ä YÓ&Tò‡R`ýÊ9ˆª÷ÍÊȧlð²è1¸Pcp#ºQýÕKYë)FØk÷Î4å©ÏÐwzíúÒ,¼ãÄÔ)lô6 ­UÁb¦Iä<ÝØØK¬§MŒÕêõͼ9·Íœ DzUA;ˆ¡¿a{¸‚KlÁ%¾pÌÚÖBáÅðî‚55wAYÅ!¬,½P4Á+›.k\²|ŒucœÇI6á­¯olívv ‡°Ñ~"~йð½tXn’qY_Ÿùci¥àµ17ǧ¶l.éQWû6oÓééU–ž^eie6£÷œêkB¤Ûaô¯jáö­WiÐ_šášÚ¹9h÷[}ìR< I .–A²­”Úî;û$/@y ´žl‡ðÔ/ˆÅl»¯t²û*“L/êÈ ï,6¯ÀBÿ“SûÆË#Ÿ÷šs·Ê¾s¢¥o'í»w†ùý,]½;µ“ìNí´áÖ @x*˶@ñ*ð¼ÈÆ+nÙ[Ð;@TNu†­)=ÙOĘ­¼µðަWö{ᶤœ,,ü1 ÕiaIDmÁðzNHäúêì[§ôÚ§¤ÏW›®íÕ±Œ]j¡= U»[ôØ…ÉØaÊk¡`Øv÷íT\Þ¿?•9^ ךÏÀÙš™eKä«ã},{ qÀ¥júæ€MmÙ:pެ›”¶k¬®“=ìòØíhG½ŸîýmweGú7™aMÊ;5ðrÖCÏ[Ø}Å nœp,'¶$Ç9ö§ó©­¤HßÝO ˆ–ìî«í+<&~:<> Ï.†'L†'tê3 hB*Œèô8QÊɧ\kåî·O[ 28­ULPP¦TÒpN¨$û6Õ%/ÈãÕÅþ¸±ˆÍÑ!–SØKÍ«~VÔ×xͺÁT"³l—\9Àpå¡'Ûà‰ˆ8&Äç8ÜÐkbÛ)ö S9ìlæ5W?òÆÞ×à<ó¨‹óЋ|úDëšD‘ìÚ£)bÝи%w«¥Ý&Œø<ñž}µ±¶íîc µ±¾ÞǶ@>†Ÿµ‡ ºiŸ¢Þ¹§7@&¡BÊV+NxÏ{t‰$‹@eË®õì긥v2·AÊõ¶ºç“Õªl÷:Jù¡³²…IF ô@,¬Ök¯U¶ø K}ܪŽq8!9³ƒ-½Ö•Rö,¨·:–y[“µJ]®õ`vÓÜ«lY7šóí.µ³O6ú~ËÅæðF ÇéöW2Í:D%&ï”}c‚¸å,â(9·bhðQ =¶aßlM›ÁŠõúÂÖÄØ[#cë›áEÆÖ…QmµÀ¨_µçÆÖÐØ7¶ÆVߨ¾5¼k£æµmc+4¶:Fm˨÷Œ-ߨÚ2ªßŒ­†±U7¶ªF=0¼7Fõ™QïGÆ–gl¹F¥V`4í¡àÅÉÖ°TÂ6jX@¼¶È¤€­@:8[eOîpšüÉo8¹ñ;?%WŸµñ‡Æò'! ‘÷ÆÂú^Wg]ñªŽ\©¼’½ú ÛŒ«o-<¢²·mΰCå»M¼s µ-"d>«¨5mœqÅNè.~1ž5R-Ø`o”ãA)é’RÓåDzU‚ÿµƒ'Ê[ï¾ ·›æí&y}<­ÈJ4<‚¢Úàuóv‘X;x"k>z+µ¶N¯ùÒµÚ6üÜÂ#`{ÞJj£.FR è‰ÖÝ·)OÞNE=Uw¼fÙ²ÔÚqå@¯¨w »øúZÄ_¥ÌÈ:ó¢yã5š7Õó®Zç5q°]9åBܹ²—¤¦+òØ'Ég,¼#³P«l;N…8÷5À8H긧P5|°w­—Ð^ðy0*tÐò±i½²Whe5Q´¾Ã¿…ÏM›:üÇðÝ_è/à;¼>}Pë.ÞQz^˜ðªŸ ;4Õ×f#³*Èë’¤·‘Ånwˆøø Ž÷QŽ©½äÌ#I%ZìÈ®eÝRº dN°²ziö€jƒwÉ¡qÕPO>§¬‡ªÓB,±“Žä*|ÇßöÊZ{–Ë*'¡3±²öž]{ãô ª»3,07†‰5Yª›ÔmÙâÁݨ~4“ïê¸kõ÷¶‰¿˜¿i`˜I®Ïð•J&¨ˆã÷|ž«ñ9Û_"—¯ÅÊÞ×"Ÿÿá—CzaðÔNž" ï½Å{³í=Ù\Ù…ù¡ŽL"¥A)‚r±F˜Þ7ßÛ•Ý&v¢4®qe7øËÖ ª’½ðx²å¨Z²¸šÊ.)É8cÏGǼkQЇ®HÒ¿2 UzEÊñWwL*¹ì˜gw ^ÍB}ôí5 þeì'+­äŒ.ÁõbÔi|4 în¥y…Äy婨vLµAé1“ såjÔ.¤áãc§ú)Ù»‹vê}x ò ´ïåö[yP¹·=²˜ê[¼êÌÏî›Âíú’Óù¸: ðÑ6»gÓvãøœ”Ç·-Çü‡»¹R3ˆôLÜoÀè´Ø<0 vã½]­Ø[5»zmW?ÛÕvã]Ø(4ŽìÆ¡½µm×*v͵¶·‹ïµ©ÝØ·oí­À®„r.j^×ëùé’¼¿Ãä Ó£ÉÇý:jÏ ¾«B-çû$+1:¬´u-ÊlÀ@a§Ý…6FÖ1*ꊰLâK¶Ún ´écæ*B€ŠÕrrŸzY­ðùÀ@63’¹EŠ¢œüå“Èõ†Ù—ݺ}½T[šuzBZ=™^pöå­LükÕmwáÍ Å‘âï]5äô² 2‚V@óW)ÐÔÀ.I2" õ~a#½ÑJNáõí#ÒÖqÏ{[°÷›í¾ÑsŸO¥ÜO¾3¡Ð ‚!‹ï­9ÜÙÃæÖ›O rÕ©ž² ó±;VW}`ylÓ?‡&_ˆ1´päïÔj p¹3¼ËöÏy„ø_#e˜NãµÉÜèuz\udê|PÛ(ÕŽÿŠÆ|e¥'´q„—¦8ý| ý‡}ãx“W"e9±á|!Ž·éÎc÷e\y¯?áúi)Ù"·!„Ì6Ù&8mêcÅ;¼1¨“øn*U²*UÛ»júÔµföCg…{ff²á¤Ðxe7^ÚvcÏn<³O 9Ÿ*Ÿ‚Ä{ ?ž’é/„ý´Íº£ðQ¾‚КSèq.Jõ)ÁÈc¼ßl"€€ ½OMTÐ…tòŸgñ´ûÔVÇD)uOŽeÒùã'§?ûKøÐTQäC@ì&;ŒFTG½Ì›‰êå&¨¶ö»S{gÈ­zâ4Ëvãg³Pý°yUò¯J•%ÿ²`7®(OÅ¥?ûÍS»ö…þTÞÓŸê{Rñ9»whîœ~ 8vs€˜ î¸)GmƒòT»"µW~rv|qçœÇ võ²Yx´ù¨?áOøh*8 Y7‘œÖ<°#[=P"÷'âÓº}Ûû½½ÙþúuÇ\Áé wiïÛG투:^n|iFÎþúzä4®xÅŠÞÔZ.=Éô¦ÉçÂ]}ÇÛyù0¿<®QŠ­ŒÞï–…ç¶©?mRÓ›ÖNa½Ð,ì`OoäTßÅq¡±¤—B{GNƒP ûdòÓß´š}T²¿CÿßàÒ÷n1L U½Ð|TÒõÅqFë¦ÏýØxÊFôO··¡vðz¿Û…va£¿QÀÉ´ã·¥ŠûÒpÀs\h¹,”2aí·ý–û ÛÅ`“I‚ëµä #¿jû~³!ö’ xÉJõ‚ªüîbÿ¾—!øÒf?@‚~¸;yŽb)YC¸iÚãu«2ncK½]øÅŸØ¶§»ômÃ4¿µ¹œµóà ¨*ˆ1X)zIÚÿ›ñ¦Ì-àö” zuYG=†BÑH‰Eñúë+çX̸Ühb1ƒ*Ú4Ïþ ¿;ÿÁØV5ªýõõ Ø*ÃgoOžy¹“æ±?i—;¦ËûØ3'tN5`pÉ!ÿ¢'öH£†¡Ÿ¾Âæ÷•ѽ6Â-ñÿŸ•Ç’i@É34 ëf—LBÉ8¯†8ó;Ãw½V³ß³7Âí8hÇ{j4"³à‡Žß-XM¼ê©ZûbuúóÈÀô§âÚøŠ'ö*ÞNµ@sBã]§ú”jí”|¿@iŸªÊc²]ª}(ù[P«ª?ÏPÅ9Í6¿a~Ýðk†_5j‡MþÏðACRîsiû÷Òö’*yòqûÚp@ÅÕ÷¨ìè|'}Ü(Ø8ZŸœê¥•N‚lÌ iL¬?R¾T¡N©D-4F,,ß+ªJ‰éiÁ>£Rçr+ÞJõñ]<2dŽcÁÛ;ÁøŒY]'Ñ×€[}áî²­Ò±Xv‚¥²=§qav±FFZ"xIíÀ4€Ph îšúu‰ª`ÕÆÂ¡epÑúgɉÙ>Ö¥l…Ú›¦}Z‚‚«Œ]§öšzÔ§A)äЃÆq2ZQ[VN,ÐÙŠ/9 Ù@f¬»Td‡BܶpºZé^íª¾&YêV$‡wò¤l‘â-ÔÝ…Ó•ÑÌkÅÉ#„ŒÎ)%o¿cºR°%ížBd¦Ní&vy4¦B÷¸Ù'sŸ¡»=zÏôèáò…7ºÈycvï-ò"ð„Á”J “4ËË‚Zp¯ÁûÁ0–u)0´ðÇ”Ow*ßÃ$[Cl̬A PÛÿ¨ÿ¼p¹¾Nlfì¨6k`Ymù¤Ýù8öòñö¡…m…ßFW?m¿Íìß•OÄÔƒ¬íÆ ©L jI¬Š 5´ØÚUU’ÆÈ´Û|o¥õϹ-bªÎí7¥#Ò½Ã6Ÿ?ÁÓl ø@ nþ8ä¥{¿íîøÎökÖ´ WÞáúú>ŒTï¢Í„ŒÃIôŸ µßîÐ wÕ•*Ìhùö}ýúÜ>/Ÿš…}>ÉCÝÚ'Ýf¢D²yÃWº0Ÿ ¾´ Øúl*E0þ+K¾M Aaƒ_¼+èØ-9kÏ>gŸÁ\œãêl‘âê¤"pËÖu‘V¤j¹›"ðqðmM²=ðø#>²¾®Žýê•a£l”F®¬8÷PŸ'²„MÙ§o¿“¶%q ¿î5ÿ®x´š|3T¡é)'ñ9Û†SÛãS¹¬ ÷ùz—d'©¾§¯ð¸°A­ä7تªm»$YZª%¹\ «:üM*h¤§„[¾\ûcÄ·Md.¤Èöâ@õâ@õâ€z¡mæçê@yÒ‹ÚžêC| `HÚkl‰íëÅo•\#È·!¨–Ž…ûí¶ŸSÓÏ@æ2ü2ú]ÝrÒ¨Ÿ±9ÆGßï ÷‹*8mò2íwn줗”áŽÒ ÏïËÀШ {w2\ç›8¸7C¦‰¼Pgñ…žV¶‡Ý¢ßì ,ÒËÚ:‰³†)ï°—ÏN¥Ù»SxGݯԩû·n¿âƒû=±@n°£ÁžÙîËv}vµÞn´>˜3ÌÃo(ÿíl†Í(,/ãX¿b½Ý}IõöˆÝ³3ô8“[âx&!X7=FŽ\zN¥ÒÍT*¦xÅB„|á Ô”¥ZK@ý&æñ7^¥WwCð%£Þ–Y­ÛjpÓÇîaìÈÅ1–ž±b0.ì¸/S²húçæ79²6-7Qðì³ÒyÛâ­ÁÁF G¹Lç‘õË&1ÛN;tÜ…yÀ÷3¼4C®f{–lï Ýá8|X팲ÏÔùjÝùˆ£;f€Ý8ÞA‹ê2åmSÕi=ò:-ÑëP&Üh&’šü@Ý(µ ;%·éZª¦Ó µÓ±jj„~÷eÓ8ã±±ºžzpÔ܃ÔÓ·_…‡ ûL Þì2Ì1åf:uC_–·+‡Dü¬<½NÍÚU¾oÂ+?Zr‰áB½âÖ«#d²âyù9»ƒ·±$ê|cUþ|“ÏLJئ‡%89&éœHí¯„Jâz‰9´]F¶ àHÓ®™¸˜ß»íäŽHö ¡ï”öWš)u3ˆ+øNbÌÊ·õ-}$¦¿ë[®vÛêÎ!_Õ–¢ õ Zßõ ówç­õkÜ‚K_¥Ôh4“ËxùË[À±_Þé4oÜ7Í®È{9>%7"vloÙìØU·) ¾¾Pi{AO«VàxKàõ–P¼¥ºº`ÏØ-¾åÔÞžáåœ7Øð»Ó¨R¹ÚVÚßàpfñ²ÎëºrƒØ®vfï™ÈnYø«zÕâq¬›¼Ÿ3{¢=E ÿÑŒ4¼w¹Ï¦Yò¶í¹9{„ßïÖ¦gm”šõÈßè`!ë‹Õ­æ©ím¥WŇ«µ»D0'¤ZÓ Q ½Sùݸ™XžSÇp…pu¯™°Æšã}±Ô/Cíœà‚ÑŸ¸ÿÑäÞ—3Ôy®0CÙÈü^Çm)v§žÁñ¨ŽÌm¶»Ð b” u­aý•³É{[Ý!«’[ØÉÅ7À€i D¸ÞT<__Ÿ?)mÏvæM}GŒÎ!—ÃØ•—Ê'°Àþ(þ’)FReÄX"–ðBçâZè5vqqâ1=Ui²ÑÏž)ŽiÜß¶ÏzHhÀfÈ¡œZ‡ù~!´PÅ3, z ›E[ä9ž®køÉ¢ÆÏ^Ë’É[*Ñôm©ûaè¡ ÕvŠÍ0Ø5¬”ÉØÓ+4Ê©FàUÒâd÷¬ÆøcŸ><¾ (H+;*…íqëÎ ±³ÃD‰ú‡­èV¥M» 9þE+Ë‹¶Zæ§ùºx"¸ÜÀxqõŠÊ(3® ÎZ­©¶±?$­Ù*ÙRÔ]­ñe/íµÉ¥“н»Å‹ÿB¬,ѧJ+¡^•+QU‰Ê²ÊjžÊu¥™ï”«•|g$c,xCÙ, j3[£vv£´#sSé4ìE8äS‹°ÕbìL6cD+î™TïòΠªëÔÞíjЕ‚uŽ€CbèëF>º¾âï'¾Wönþ±0··â Xêö!J÷.ˆc¢«kµSË{†òà;l_éÓ[¶ku÷ EøÚüÃíæªØ©úM7jéÝV㸚p ¹cï­*À·Ž°‹kóízìž8tU}\‚éeYèqáoWwArT*|>6à(î¡©bÖH¦˜l¿é›U?½vU€`Ðuè”5•¢ÑÛÎôã­ÒEâƒÃöàˆ­*ßÛ7îqÓ=¶Ý],r½2TŸ‡FÎ Û…úG\ff'¯§|·ÜH¡9²¤’n´‰þFê4q‹(ï }ºøµQùžÙ6R)7µQ„ÏÏwŸót l¤wÙ4A0Kè©Úm燦Ã>Ñhô2 /¯šÎÜò(Çq©íÕH‰ûZÜ®~-Ê·Ýä›ÿߪLÊøÖ¡oõSým7ýöß‚¤Z.„ö¤Fο’ 'ýâë~Af|BмEX¸ÓJN±~-VÊÔ®¶ÚƳ\=µT|}¼ýk±~-RîÚ˯Ås½ˆŽ©ûµX½þZÜè´Ò›Ä3Ë} _ ¨5ÜN¾‡Ç!u·ãl{æÚpÇoªÕòðyí’üm6äB«©ÏÍSiuʽZ?îJ_-6éç ÁÝ«áª3òÉñxu2[é8±¯º3ÜÁ­}M¾®¯ÚÃk×_Ô‡é ŸÇï$÷œuøLi$<¼|;_7ûRí‰ÂNE·Ëª¨º@Õ•”Åí}]¾½/û¥ÚSŸLG¾Ö3mà…Úh–ÙTÂ~‘¢]÷ìz}Û.ÆòQâ¿ÿ7ìÅ:XH,!=âþ<qļÁrbs¯%ö®âŸƒðñìø(™/â$D_Œè…»ó9[’>^Å*x̱Êj Ä>÷<ò{þ|HùjŽáS_&a,5±ôý!·ŸùDuåbAŒfawH€Ë9G=‹ ÞîtvMô;"‚<q]N¾N©Ä‡'!ˆhPzxvÑî7ŸÎe”9šeÌA _(*¥ï‹PSñÔ²ǘP¢,Ó!‚æaD…£XGIŠ#oŠ9:&lDåºô{úáõ3¢pÂå‘àéÂ6"æ&„¸éþôR ûEÄ,ŠàÛFIV/îÓDŽÇÓeRQ@;QWˆýu—Ñb:H ôèéõ‰"ºÎhJ#Jé³wÄ(ü¾Ðq’çM„Ô…8!˜ÉÕµ´1 }ÌÅ#f CóqH5£™|IDÞźcšÛD-~¤ú&ãC£1&úМ˜1—¢ô š#ºn‡@wãéÏáhäÇ4<ò-¦ÌiêíÒlcS¦ž×Ĉ: p™aÒ GŸUìR¢¢ÆÑ¼K„ËÛ™£F¤3ÛîRÿˆ;1M¨`©1” ƒ!ÑTÏ5ÓˆóFŸöiªÅ˜$KfÌÑ_ƒcš©çG¸H‚Š MÄo*þS¡“ÐJ#*,„‘x0 †½!atús’\ÿ‡jŒf’@„;žÅËYú Ç3bÈÄ6 æ]bŸCâ˜4ª¯NöQÃk ± ‚"ì~£ê³KSùárÜ¡z%03bÃ]ÄÕeRœÑ ¢óày ýC"¼ÉlÉs€; O Kº”á›ÈÅãABšMxX'ÓwðDøQ3¡4BcÒ& $±×¯?2[“bHÂä¡N2rNá<CŒ†<ä·~&v´ð߆×ñ·ðš)†ÊzEŒ98fBâÇŸcæØ–i„[ˆÆ…?Äl`Ù# ¹–:„4á*)ŠY¤)ÆZ9’Œ–1•CXÂØï!Q¤9³#„’8Ï10‘¢1 +ûh:’6ÀDB~—` Baƒ„–£ `{¥EÀ(ÙÞ]ÌG@°3Œ «\BÄÏ™ öA[2zЏ˜‘Í…E’Ü ƒHH¦3½Bíq¹Ïý`8£Kžó°'4;ì%j™”"ó<‘ `djÊyâ‘ Áž3·×m™U‡‹µe8ÛÓkšüCš“PDF‰‘)8_Nd’€Xæ×ÿ'S!þt{GÏh¨Áþ䃌@’'.²˜êB\D?b¬@f_âwGÇ'DÝ2ÑŸN`ÀRúKüÕ =$u»£e„¹„ˆ­ËLWF•‡Dh*ÏŠ£KVq_LIƒ“À¼R8dzYvH‰DUu9b}>&$1/RCH(ÿœTÓ@¤MÜ I´*° áÕlNò•f.â•Ç×{ñš‘|ç¡ÄôNˆü$È*·¨ð¨ÿÉ”3±`£É.îY1Ÿ±–À\R€^ ÈB€8ïϧ$MHº¼¢êßw™Öì…ñˆ€‹fˆíT6‚jà‹ŽÑ«ÊŒF÷é”,"¨gL£P•+V® oßÔœ#ùAõÏÂ/@~{–hëÈ%\XG礬*õ˜øþXãŒ2‘ÕH,ÛH¨OúŠÕ/•fÃ ÄÆD’ôHŸ%U~ÄV ¡+‚P‰u”iÈkÒ0$î2å,3ˆ{BKö'ÝpôtÙÙ£Oá’ªí…# ‚ÇsàFd6ئ„ò¦IÑú¢~?k퀇›aecœ_j…^3œø#¥>wSs…º 5!¼TY9MHžÁw¨~àÑÖST=Ò ¶r:Ü•ˆ­$VîððL°èv „b4D&»‹¸`d ú¶1L;¡O >FêcÍó` î‹¿ž”çŠ>¢´ÇUæET/=ðœ:}aƒÌ ê£K,²l¾@ÁÀ(ӻׄ€HñEVd뛨Lôšô—Ôµ`ü 2w·tMüC2 ¨â‘u?¯'0gðÊì’ŸOgò»‡YJZ¼Vþˆcé1ˆ]ϫćþ!WrDº]…@dµü#b˜ÕTÅ+Âf¾¶Â¢HèŽ)›Tw2‘Ye3&fV­˜#¥*¾HÓ$~yp†ÔÈØÝn”ã7ôµìÆ'ƒe|<¤y¿îÅÌï´à¯=9yG,8>Ò¸GSˆ~²/&l‚±:¬øÔTTÙ.¨O³_bÙÄrh°½)©¸l«3³»îŸT/Dô($ítä‹$—~CB’0'Ý;€ËG E*wy³̵ ÖHŒF3+ÊoŽñ«$ªP'«,ÃqŸ J¦KVS”Äš±zö;d %l:ž‘Ìþ‹¢ÃN³-»Œ;'¬–ޏ,‘·uÄåª{OÄår½Ykd".ÿûßE¿Ç¶~ˆcãÆ(FJ¯+6›•m;á€(p:O>Öȸ×oÐ G!¿!øú¿7q`äcÄl„y?Ä$¤aC€‘Fˆ]¨Î‚&#iÈÓå( [4aÀ!’÷tŸ ÿ#˜µW˹ϰ6Ö×Ó 9¿Á=)ZÏ%ÝršåÒò oÚç]V ’úÆ<ìCc$Ë$Ó·ÅÔ𠌶¡è@G‘~šd!ê2Xæ”ÓÆð™[D‚AQ6QU¶¢È6 Mp3T¨LXc2”ÒàÙÆéëȹÕXÐá„GLá:õ‰Aoø‘Ñ#æ;½ŒšøúfèßíRÉGÛÐþ]ôŒUÆ0ÇQÏD:¨‘ª”£kK¥Òçî!ŒZ‚¸Ü*x8sÁ!Çñަ¨‰ÌŽÈ Öa5ÒÜäc8Æå-QÅP€OB£±ûj÷Õæî›ÝÏ 1Ã9*bÓ‡CQª?Ц4=Îî´Ÿl]ˆcÍm)l*A`‡Ô%môHóE‹ÔŽ?ÑCŠnÑ,PŠ"²Q2+äLG ©¡¢‰hVµx—Æà$aˆY†é¡‡WÈÈ\)i5‡“h9çGf‡ƒÁ¡\ô§ ±÷I7NzäæÞýŒPæq¤ë"õABò´—/GÄÍnFcì_%B7eL»]¶6Ñ{4.Ð|ñ†ÑìýVTã³qNJÄrDÜPCi)„ýÆEAãÕBÈt77™û“öÂe„푴Ä惚jú›æÇa˜£[vû(:1H?! ·‘®i,ˆžœô–sÊCCÇæRäägÁ£f’fe¿àu?ŸôGÃh S·îŒ“©‡Ôª(™’J:t UÌ5¨³CáˆXRüXWFÐÒT%ynªª¨rm9( Œ †²”\u`@ydP»Ó¹¨ØÌ¼ÙÛ¥¤ÙS?ÅL+*QH¤Vl¥!QA°‚0"íò~l"YÍ šJ>–Œ5­J5 1½Â0Éñ[šCê’Yeð¬"<` %VRÁ¯w*ࢣ Úã©Ú ÓDF¦JI« Öׄ-h‰gf&ê†é\YÌTU´Žß„¤¥–BO2ü¢‰XÜšû6S†L?br/ÂEW‹ÕTR©CùgbÖ•f¦(µŽž=¤üÝ›pF¿çz®Ëü}8ŸÌYÕN %ÃÉ–¥o²ÔlˆSJµšc.°E©ÙÊ"Pê´I‰Ž¸̲•& óW¤q|'YÅߊÍä‹ÁUŸQMçi×Òá4“TÅÂð—v[ÙÆÞ‘†Q‚mÙÜjl-×ØÝ¢ÏÓ)‘%»[µüš©Ei¾Ó‡{ÈÏ6îëÍ- VÇwx5OçÛ5¬þšM¿ ‡J+$Ålºœ0O#½fœ°Ñ“œŽ) ™² Rb3™–sEð̧º‹Ñµc°™ X·p^_$uú:¯ÃÚÂ9Ñé4 1:H[ôG¬d—Ò9•3ÃÅ-CzŒ‡?äÿNž0–Rf\)Ì(J{ÈÊ (˜ÐöÒ"mƒáR˜´ãÝ(‰¥x e’0ÄNdA–濺 Íš2 eda†Nßa•»à*í| œ0¿„MàE’ –’"{SÆ: ý&}RjzcÊuÿ‡öN’ÿ‹¾©¶ÔxOÏã4ŸèVjÓá°YTMŒÂo™Ëà!*ü_éþ€t7ŒÃéBù‚®§Kb Lâ°è˜wLxÑ+Gîz˜MÔô!C@-öéþr1Ã#L¼ìú^‚¿£^ìþr!|éT‘³Ã˜¢Ó¯&IFC:ãŠñ\kl6°ˆ(J‹çl½-Å^#q· ‡᛼έ Ju 9ª~I¿­rHFˆ‚ÍØù«T3Œe4 Ó¼ `Ûp-ª¦L‰.‰5¥¿¨¶ÛFYkJÆ%²%ÅcE[,ØÂ—¯Á}¨†Vså%Ò³â†ÂÇFñœñšï‡ÈcÙútoÒý'â]ç&ƒí¾­»öîK,û J™íìæ£¬(ôµïU¸œ–n»ìBd'z¤iL—‹ÙraŒ—Äsú0éX©ÊKmâ| #¼òAG WÆ“}ŽÕ”Ü^Y…þ ~yâ i¶.!?µê¥ªC¨S˜»Tô„¸Oý!‰>gž((Û&†Ý[UçTÝo"L}6 YŽÒ¨Ì‡áA"38q#G¬²PµfxÉŽ[×þ—:g½¥SÂT‚bマ„·z°Ç_Vr%ÍÝ àMt4´©JŸ*PSeÛÞ©ô.EB ë/÷A ù"GØb7q+ÑÀƦ$x‡pÆK(˜@óU†òR«Š[Ép<<È4Ml!¥»¶frgç-úò8í«#KhôucÃÊLXÍ$GJÔ†‘šƒfŠ34}þ™ýê$;Ñ$Ýrx3¬‰‰0ŒÌd|‡!ê3Vg ½.–êÔ˜Ø,ÈrzÈê&͹=6;Ke„µ„¢ìÅ-oÄ´*bŠìÁÅ‚¼1£HyTÄòn7Ñt’󈣠àŒ‘_dIØ,Û`‘km£xS´`Š>œá¬hÝb¦7†Ù4(Ê5ù¯âëLYÍ”ïO'É:™t„]Ýò7aˈY4‹$ñ¹ü†Q´ZÅ<Ê_ÌÃðg˜evö²Ý—,àÈ 5/Çê“Ū$ëjË)ªYN&!ÃþüÚXÎ.ýy² µìrNˆáqïè€TÁÉp¶0Ê‹r†FÖûï®Fèî/'Ù|fâ2 †?²+N¹%³H©âÃûŤGËéF‘)ƒ wÒ6¢Þ4V´9e1ÑÇòìJ½c»vîïQ¦/nòE°Ô¤VŠ@dQ*Ê碅²à=ž›ÅaA%})é ¡.+{‚àܰ*ˆ‹?°,2óhºÔÌnµîÈ&3ßÚ§9à Àþnw< þœ‡—s²Œå|dðú+¹³äå-“¤Ùh0 Y@ÿLja×NŒw¯ÞY9¸»Ý7:Œ›šJè’ñ—xÞøæ`S;×aÙ´»Ur5V¢7lþê½ØìÓ`lÊhGõ:ꌀYÜùÞ.ò.±ªÅu7ù'[OëùÕ«yõb®J’PÉ&|¥ÿIÓHzqkz¾Të³âqç-z,”á‹×»ÕrØÃšv’-‹7µ¢‘209î ¿;Iå¼IÕ„·µs«ªI¾¬_,Ã=’ôÔ³Ž•7;3“ÇÖúC³ZàηvIH"±CºV²ØëO˜f¡”49 $µ­[â>*yPÒxÉ|L‘‡ÊÚªøÆƒ9ÉSäœÅ¦” B¤òô†Zn ”LæûÉ&-};ù¹T—!í§Ë!ÖeoÉaÛª àr @ºîF)¼“.«÷\GØ;˜a põÕÑ Æ+'v2¨%4N0I²g7c[Œ7ÓÊ8fa kê¨4 »º#Ó.O…À1¾N~#€è/*)ØÆMï„ú Ÿéí¾†ÕÒœvefÌ©ÿW˜Xíb(óª÷ÈÛá,ç®[†Þ_À…íA ¸ßÔpÜò8”â–B¢Š®n/¬©V‰¼ˆº6—¼'Üx;”—]ycïדdq÷á¥×ÿ¢Ö'ØŽBò[mÎ3‹‘ˆªšžÕÊzP$ý~úmRBª·ðBaqàG^Dm·EöÈbÐÞ,ª 2;XÒ9H `üàÚ¼³|ÿò5kä‚UK°ø(ѹõ&ÙOt×I•|¬ÕÂ@àÂFâ9DzÁ$ Ç3êû¢õš±^VN¼Yà {›}8ƒÌUÙõI#]|R¾5!pÃLW©-G•Ó¦ZZH2çÄÅM «Ê¾I3 5ïY·Nh¯ø8?)¦NµÌº g&¥ûñ&²$®‡dG»“¤z[˜[w<Ç•many³L•f¥Ü¬ÔsÛÂ4þQ;ØS[x³lñެ¿[ìh"Ŭv»¨ËoÑÊ=ÙÍŒ#åΖ¢Lþœ’ÛÁZÙq¼n#› &×D…¤=ŽD¿$Éðú¹ÑpŒwbfÀÂÂaNÆFf-Pqqu@ÔÁÙN(,ú<Ùítµ®HÆÉ‚ÇF#?œ‰‘Kð½ Ã\Ýoì"Üò™ƒ@ÆÍ‹´›O½Š‘ýoÑ®9#q­a÷ÛuIÍxƒw36'Ó…™ÅTº…Ç"õA£J¶wÜÖÛºg€E*ÃN, LÈ"ÒtKôµ×Jmç†íBÀ•JÚ+3‡;hâ¯ådOr²“ž¢µlþ5‹¼;©]P•ª OorêÒv¥¤™5ºrfŸ0TTÖêQ#þLãÌ™w¾Û5“I90²9T%ÐX±˜d0S¼H‡RŒ(Èe(‹·›áš]†•ï™ÍÑ@oeû Ê–BIÇBdáü>p ‘Ó©$QhVµt67Íu/m¯=Ù=íÆö'Ýqhp8ÕÃ0CÁÇ>ißÙòìòHF§ Óõ! 눓AåËl­r`çR[‰Þ:™ºÉÎIßR5/—'›¥•fx§`grQd`9r.hȘ4õjZ`ð7à]ÈT/ûÜa¾JNGŽF)˜JÄÀÊ:7aó¸Ð$†¡+ÀöyqR¨¹¯†”©úYÈòŒj@LG¤+M¾ßbC²&ݪÀû«¨2>ŒA5¦Õ;áw•]Ü J1iBmqþt½üúyÃIR1Z™Š‰ü°~T̶m<Ô2YÂIÓŒ8ɳQ$¾’¶¿Jž˜Âi§u' ¯2ø oåÎ j¶·‰ÊœØË%%E¯l*õN׬ý9ʽª,Ô¤9ÂÃ,5.gj7ùkYNÂÀ2™ØWêõò£A:51—Ä.âíy«†^eTì (nܪö6[c„2Ø„g`ômÚ4 þ„ Ì|;étÒÊ@VÈäšÎÚ›"ypÖ'³Ã^jî¾Ç[šmÞUŽî?¼/]–³¤6CŸö3pâ5ÒjåZê„Õg媧¿í?‘Ã( çš5¢îÑеbŸ”xØØügu¬rò;qÒ£ß+üwÍ #QÀ¢ÕÔT³IìËdÓq^àã‚ VƼ²…+bÒ Á,àEˆð«d­‚ËwÂÅeH¤àËh!ë]ÉBŽÎTû×$© H¯Ž¸··•|ÁHñ/0"ºátÞ 3Â9q ÊÒ¢úÇJwN )§3íÌf…“hà6¸ìAF«”ß6¼ZYH–Û¦üˆOºõ¯ÿûïû²Sß$F›Ê·³‰‹¢M’Ÿ›ÿ+ÚÀÊF£Æ¿åª›ÿ•ÿr]·V/»úï_e·ázÚÿŠÆÿîßlÃø×ååe ÇCùþ.ýÓ7þž[«n×®Û¨÷üÆ–W¯ôÊåí†ø½®× ÊP²þ® p½^}`üë^µÞÐãïU«”Ï« üË(ÿÿ€ÿÃÇßÁU¥åd¶ìàGÜàêƒ>ŸÞ/ñeHÍÿôz½j¯ÚZ9¬ý†—º?c/ô[«ÿp¥~@Ò·$w•ËÑ Õ¿(ñ•%ø›8oÕR÷Ì4Ë-9sK²†NÖì¯ùšäî®è†ïj²qLÊ—*±–_vjᘾñVØæœ­óÕ"p5||%µ&™0w©gÜ ïäçíƒì+¾Q.é&_£ÀÚ®ýšÏž\pS’3ì÷U )ªX¬ù*ˆ'?nðÎt1ÈeÐ »ÿ  ô¬\dè,ÎãùJVö.F øÛ¯‚áG°?ó'áè&$=nµÙ•ÿ»êáNà B9ÇJ#”'³®B™u-æ/¤ÑÜ­:ôMB(F•²¡ÀV®5¡o¡›‡Ä`WJ–pwÕÆ¯­,¹D>ÙRLBª˜ÓrüùNÁð Ö.¹Áè•üѰ?Qu$D›–%{GA/ߪ_ÉѪßo²³"—’Gð_dSžn㹬Á6G‹yÝßNºÃ0²ÓÏØ„HE‚\OQ‚þG3m› V³žXvkÑXéjÔf7*}«\Î¥+Ç·N.oå“ÇC>Oª“{(­têëhŽK²êG`±d1¸‘ oJ¾0¨éið]%ƺÝîß”µÿ*uîð5|%˜ÝAB_L)•r:B‚•òGܳÁóO=µ2i‰Û›g[J åz:Mtë×öÜ‘µÕ<|}Qs9™›Zê®»›—¸ã1˜öK\È™MúÖßUéÏÕÑ¿ÿªUì51ýößÖ>ý¦*–uÈ’¾¡ôÀäßþõnÖgü}™e8r\[õ‰o·‰ÓÅÍ]6¡jÁò»1ðt5´å|úL'ƒ†ÛéJ‰È¹Ñ·:ŠP@¸‹·s*©„ÍI]¥¡¶h¤_ì;9äjÄ ÜÞ­ïNîÇ£ÖÛæ@ü+8Šœ‹èn9cäwHe|uâñk­)—Ç%°­¥k+àà®#$ æ7jŸq–ð“ #éÏýëÖj8î+VÓÔ,I³âU#…Mý@éƒ,çWÚJžË çÏs¯Ê-îåð –XX7ù¸Ì:ÃÑ,8…[Â\õ¡ÜÊä=øÊÖyKâ—”V°ùÈx5$¹"+¬¯Ÿ—Æ~×øúˆ>c|Œ\ s¿>P³ª’½ÀÁÜ'ξœGÄÚ±Û xräfDø½­€•á4>BpŸn†aë/ù2Ê¡Û(;uUÇܯÂöÊIŽ’vøÞ›5`õRÀ¿'CH}ÝŸM}ÕÏYâèòÕ£”•ÕVcn‹2ÞÙù÷ÿW Väƒî|9îÜÜ’C˜T¬>`YEŽP ˆù¨ ÃiP;jÚ•ÊN•ÇÁ£¿êE~Rèh¬ªH&-Q=ð¨F–ϠݱÙ_H•UéïŠäcÙ`$Øp5ù|e%\µø÷5*4ü7§K<ÿ=À¥\Å"áµ’ÖjÒ–|½ÃÀþ4™ ¶Öò– ·ªÏ+—³º95§DwÒ`y»ì*]]'ÝmµWî–½|.;Õn™aAÒ¸w»ñé·DY$m±¬j¤¯w›,—}?ÍÀ|ã[®¡ m¨|§!ÈÇìTÛխֽY GÊîôî1<³•-† ¬?ËUoÄ›GA.Ïr”5ŽÊN£ÂÏ ©\fc4Ì熫,à´Tjt7‰·Ò|žÂŸ}“zFCͽîí^ÁM¦rVÌ®„?g´ [qîÛzÏå€ò”øòiÒ“±„k 7Ú¹7ÒÈo¸ÅKÂ‰ÊÆÚp ¥ÒŸ,25.gv^¿Ï¿2løÞŠÒn|g¯šX™ÏÉvì;)¢aå窗0YZ¹êsæ]ÖÛb&“S¤¼Øý«q•Ž\w[ôf N°5n¤‹jFF¢|àëk#MŽ,fïæÍÒF¶ØCÂ"á‘ð·•C_¿…£‰ušµñt>`~«ÄA8šIŽ;8½§ˆPäÍ}Dšç¸¨ež5î‘òwòc*ß±sr®5$í@WªL<]÷ ÿb8‹þz*fÍÏòmã³ÜºíX#‡×L…® p:ö=ß²p_²< È=<¡ã¼…-Ó¤þ¢üÕûÛ÷ïiÀÏRšߺ¯ôânټˑõäT·©ěԋi¸¢ÀÜ©?D¾ŽÄ.YÝõ)’4³ï~ÍÏw­2/GÎlND4¿~Ø:IiøŸ¨÷ÐvFx0­)k©nÇvg!ŠU<¨ v:,ˆ ý‡;@©†ÿ€bö _P­ú¢(#±ãT¤}ùË7}ñc®9[½|[”2šx>aw*q#-yˆµ9sàd[ܵ.³À+„!£‘七’&ßÈû×Öú>/3YQoD÷ùúa£ðåØŒ‘jL ¹zîÒ<U;smoçÌ\M~êõ}ó™ì‰)–ëI5mb{{»µú[GG¹IÜoú¨ßj%^e@ÿ,ñ>2xYoÕ–ÕâZ÷*av¾PŽÿ ‘$ên^1"k´¥¬gµTw·.GßÜž«´\nxíV†O‹è/Ì–r˜ù¾7œdït¹Óö¬Öëð„—Ú`Å;ŠÔš·n•*¹[ÙrÚähܯ jÚ'¿ýé1ùx[&j^ ‰ñp«Æ£„ôe ÿ"ë(쇓඗ä¡Øæ¦Š¤Ó"çCûKƒrN–¥ðjæábYÂÝܨýšZ˜ÿÚ#ü²5òß̧“ltQ¸lt/ yŠX908æ-Ú%7˜ ×ÕPSPdSùŒR~­ÁÄ`|Ø4 æíõŸò5Ì?Xxý™˜‡Y6Hòˆ­ >ëBÅ!ÐO8þ”^–øŒ< 4Í0ãŠ"¨2'2êŠÒÅ\°ãn(Íq¥¬’΋;[~[Ý%¤%}Ó0þ°¦Ð…5{ñÂÚ‹]IÞ¥Z‰ya< -ÁîV¨#ï 5í¸®fQ«ª˜ÄÊ‚>ýg•fä8äÿY””„dÑïEk–~TT…Ë5ü ˆBÊñ–|Ïzév®Õ¨-dfÎÙÈÂîÒ—+Àß%и—EŠ­“&~Ù¶KŒô’ÍÃÁßa¤ðÅ0Îß.0Ÿôä ÃOÈá¢BÎe>‰ƒ¨©é×9ˆÚÔµÇÉh7X_* â̱ µ•‚mDJדö¦³I2·Üä}|s¹}ƒùß•ì&Eaìûð®à“]e1rôƒ ¹:rZ¨8·dÙ?ß9©êÝM¸×7ïo|ý9™ôãQÜÎÃZÃì9Nïu÷kü?¹ºþi>ÛXê3e¿ÛƤ Ü[ª‚ËÍöåVûr»}y·}¹Ó¾¼W5ÀŠ{ÌÚ.~Hï6mïc^ ÛÔoöÎ<Ú² ›Z}s›ÊlÛ2wéÑ]ûˆKíØG[ôèž}´‰fƒ6fLHÚ…Õ.¸Píê^»£ í¢­ÀÞñK¼‹Ä·ï"05n[÷÷ŸÜ›£¶U ¶»%îmí—U¼˜î{Â4>Þå{¥]¼`v¾úzç,!®ª=hØëàe¶æÎÖ×w{›8~¨|¹m†ÍLû;:;ÅBp µCó¼(ø_&¹´«íÿm¹]+´žë =ÃTð$Ô®!ûʱæË¶*Ð;#|•í]Ú C}3F@…à‘?m' O]Åi?9‹'aÙÂS)ËöÏ  }Ž— -…¹…«‡×øü…gk°·[@¶—¹JÏ.Ö$k.ÂÐ Ç×Û]n‘HüAËQ§*ØÀ Ðs¾ÐžÏùÐû¹„vec0{+VLJÙÎzŽycË?¼b}|ˆ‹ô°Ì¸]x€wkàWYÕS‡d´b™íbÕäVz˜UU+¤ëj£+« –Ú.PRÞ%¾âè³bÔtŠÌéFE¿A:zÕÀonÝ'UxE‘ŒT™_ÝT0ú ÈE¶Fºø¬ìi´ðãËÍöâ×ʺÜXJÙš`ûѸ˻Y}›¶*²ohª¤Þ]èâ¯p‡]òÈ+u6To2¨¹œèxCð²Ø×$V´ƒ'ç翺¿`1ù)29*5ä>°2ÍÚÖf¹[Ô‰bqpUù¼P” îÕr'ò¿ÏÉ=èÅ‚NŠË´Wv",ŠGhsîäégZøÞÙ’I }kæÖoÀ ¿›EMèMP¥òü,˜)hdR±pÑ(‰)•åp€¹:‘W…ª›u7¦#’75^ú¢Ü-â̾álÄJU‰¡¬ÔðÁ±Îe=½Ñ’~dÑùðûb¡[ÂÜ›_óWô%w‚ö„ãö¡ÆÉ(¼\>R´÷½âõ(EzmÌé[vn¢(a?£@;­ Içe‹Üä`Kmï,é›pãx°­*ÏŸ€fmV_æ¥aûînÌïy–y Jwÿ µ˜³ÿÕvY©$6N±tÓ:PŽÞgI%5Û•T:½,‹/¤âAQCÅ_nÀè*,´*ùeÜÏ®v?Û¼·óuÜ#ºƒ7:—YÒ°3—4ØvùºÝ´ % ÷¦/*§Á¼bg@Øú:î߃ æÙ ]ìÁŸl$;çg*¤Lﹿ6×Â]pQ›Ë“Ý-W7G]X@çèî*ª"}oÅSÞYÕ¯t;-ÀœVà¾z ØÉü-äÌ‹‹¤(R4ª;Nû±zPÓ§î&ûRÎ﬋h˜·eбŒ]‰‚cÍÚ7ï£B+¿m'•+ã½TõÜí¦Ê—¿e?õúÉöùæ<Îg^?ýN¨z[Ø 77!Û©Äìµ·‹á2Uâfû ª)ÜjνÕ\"÷<[‰;ÂGó5¦É×ÉùùvseBÈBc Ì]Cˆª¯uÝ=7tÄ{^6Àœñ(„ÃåVÓ¹!ìy¥Çw>J¡ùÔ†R…Ëäb·Ú³ªˆ«ÒSÙ¬Å-ìýbÅaÑŠíž„ªÝa7î®ÌWà ·IœŽr«¼«ÕZk›Üuã ¹ÇÅ«"xg¦«zr—š²r[Õoç.N)|nw92[­ žlÑÍZbæOVe'«œ¼\oÉÃÂ"®–ŽÕÁó"ÖE®lC»két0Î*[‰R}'Ð("nÕâ”.Zþ.á’¥#ÛÙ—öÝ?º.x¶Ôx*ÇÇÖ ñÇ2í:›Ë?^¶åªFÉUÁˆSâbK‹z¾ÓðJÞð‚±íÿ”þ¶Å{»â*¥D5AM¿|÷i¹ßÏ4OxE•#0»ÕI_boR„¸¦"¸\³æzÜ1xƒ|4 Òô²ÊŠ 4>¡ŽFÊÆŠÀÜÔþ¼æ7]ûrf«1dü¿¾NÒ¶7ÛmÔËí¯¢ÞlrºDö7{»¤·º'z«øâb’ÇšþÿlLñï¢Îy’ô™¥5'‹<ت¿þXj·½I3w¿Lî¶éÆšÓG1Á¦I^%PV3L¦ñÖÏ`·$@#¬=² ‡&\Qª¾2V÷Síʸ¼¯“XL÷¡Gv6Ž{è¾TÂúÌsÛžãž°Ì'4 bò¼1ˆiîUŒŠ2P̶à Âÿ ½/ˆ-"ÖÈô„/ᮽº¿ßïõ–ïX©Kl(–$ÎÉì)Ñ(…„â¼-P‘7Ðý67Ð ŽU± þ%”ïŽu{ø’°â\C°Âc¢ù\—vN g-h'z8m·-E݆þÞU*pš’àí(*xÃ-jLØç™~S ò\WÁÅ`."J}|ÌùV÷[†ƒ^è¹ñyÀ?.‚¾t³ó!¥ÝÏØŽB8ÊhDÊ kdá td“kê£N5`·ð­»‡+â–‰£ðeÐɦÌ\k<‚½ÊÃP…rPAÑa3(Þ|yLU]GéE(hŸ¡Ø4þ²áõJ™kêÕWäÃR°©È)r!n»ó>¤ä‚˜ÓÏ(ÝêgOž<1Ž‚ËÃ&}ÃÙñ2qÕ‡½ó^òU•Ⱥ“ì|uÎ[‹×ÙydoÇÛÛÛE¥ûç[½¯*4¥D¼¹,*Dæï¾{ÂãûHÀÀ ¢·³…•ÚÑ{øìÙK~‰xTÏÁ×ÉN¡ÜB§Ýó³óÞ¹ùBï§Š¢ þ_¹èâúwðÿÌGe@PWŒä^¹èâúûç[}Û©"Ö©hr7¹[,xÃÜôáÿÌ'ˆ·ùî_(ÖvÏ%J÷´ Þõ÷ïÏ­Â7?§²9Ä£w?Iz÷—†¿õ¾ <Þm¦^áh$gg5v9àø:P /oÜÔ ]HÎnF“¿¡ÉܼRÌRkgØÚ¿;mË'û¹)ÿOcg£ÿÕNòuü5Hú°û·û½ÞæÝÞV²ýUòuï«ßžÿgçþÝÍÍ0ÿÓÖÝí»uþŸßã§ÎÿSçÿYÿ§N­P§V¨S+Ô©êÔ uj…:µBZ¡N­P§V¨S+Ô©êÔ uj…:µBZ¡N­P§V¨S+Ô©êÔ uj…:µBZ¡N­P§V¨S+Ô©êÔ uj…:µBZ¡N­P§V¨S+üÚÔ Ë~~´ï–ƦÎwߪ3:ÔêŒuF‡:£CÑ¡ÎèPgt¨3:ÔêŒuF‡:£CÑ¡ÎèPgt¨3:ÔêŒuF*\gt¨3:ÔêŒuF‡:£CÑ¡ÎèPgt¨3:ÔêŒuF‡:£CÑ¡ÎèPgt¨3:ÔêŒuF‡:£CÑ¡ÎèPgt¨3:ÔêŒ!øTÑ¡ÎèPgt¨3:ÔêŒuF‡:£CÑáwú¹9ÿÃW[;›[wïŸ}ýõÎý¯ÏÎïõ{››_ÅÛñÆf|/Þüíùîmݽw_ó?lmß»‡ù6îo×ù~Ÿ:ÿCÿaAþ‡¢ÈQtÈ‘ UoòËR¢Y2·ú|‹¼¶9„ªRp3º&´Šâ_­…ª°'e L¤ªû.XÆ›yÊc¥ïLü]µ¼XFIv›ÖÝB}©øzöý"7ÑröM8Á нO&9ÇGL@œ@ÍÜ`:±ÓÝAí½4Éøì˜ŠèÄj”¸{W¢™¤U«Hç¢ø}2 ^o|¾&¯-‡~ rcʆEßÞÀCóP[¶½áWhn·>³SCí’u—Þ»©íj†o B¥“f9¦ïcÏ–j¢Ä¾ÝX»ÄÐ"IC݇CY›sø¿þ¼\t*,2°¥Ú2¦Þ$IFùeæÂ  ™Z0<ÔGéXÐ)ó~l5|ø8d͇À„@–ÜQ†%çcΔ ²¶Á?i—Jô€g"´cíF wcé€â²ß®Btuqé;Áä®Äª“ÕIŠê$Eu’¢:IQ¤¨NRT')ª“ÕIŠê$Eu’¢:IQ¤¨NRT')ª“ÕIŠê$Eu’¢:IQ¤¨NRT')ª“ÕIŠê$Eu’¢:IQ¤¨NRT')ª“ÕIŠê$E¿6IQ-¨ÎTg ª³ÕÙ‚êlAu¶ :[P-¨ÎTg ª³ÕÙ‚êlAu¶ :[P-¨ÎTg ª³Qá:[P-¨ÎTg ª³ÕÙ‚êlAu¶ :[P-¨ÎTg ª³ÕÙ‚êlAu¶ :[P-¨ÎTg ª³ÕÙ‚êlAu¶ :[P-¨ÎTg Q êlAu¶ :[P-¨ÎTg ª³ÕÙ‚êlA¿úç¦ü?ÉVïîYÿnrïÞÆÝ³­­þæÎÆÝþÖÙ&ܳ›g÷>uþŸ»Ûw1ÿÏæÖý:ÿÏïñSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿv±ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?–¤ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸÂ×ùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÿ§ÎÿSçÿ©óÿÔùêü?uþŸ:ÿOÅÏMù¶6ï÷6¾ÞÙù*ÞÜØŠïoèx–lnnžÝ‹{Ûqoë·çÿÙØÜß5ÿÏö½{˜ÿgëî½:ÿÏïñCl.]HíbÔ¬ á/¹îÍæÖÓ‚c°óH/ø/¾1ÆI3™ë¶IåÞÝyþ,"U|^ù*¯þ p¥¬¬«ê]…¤wX¹É3¥ÚG:·´7Ùò%¿³êÏØ_ia•nÀNƒ6í=KÌÜ(~2IV;†Íõ_à“½¹ýo𤲾R<~ñï>à7üÜDÿï&÷·“þW_oõã»gÛÛç_ß‹“»›ñW_õõ½þW¿þïÜßÚÚòùߘþoßÝ©éÿïñSç«ó¿-ÈÿV§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZç¢N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:uj:µNZ§N­S§Ö©SëÔ©uêÔ:õÏr?‹ò?t.§|:~c7äÿÙØÜÞqù¶67þ”xsënÿá÷ø9N¦?îÐ$zJ[¡{œôf`TºO³î‹lÚ=JÖ Ãÿö»@ˆîuá·^Ë™G/€=q|ùƒÙÕñõðš þ݃«nüÑóŸŽzƒÈëÿ‚6ðŒßßÙ™{þá‡Îÿæööæ½ûð|óîÖý?D;ÿ‚¾”~þ—ŸÿÒúãÏâ<é ¯ó¿£=³÷›Û úwýߺ·½qï›÷ïÞƒ[bkû¬ÿýû›uþŸßåçáãñåøÖúz´zØßÊ‹ß~mv¾ú:ºÿÕúÆæúÖÝhsc÷î½Ý»ÑEvGÆÑê­[ëwîÜŠîDß ç€¿<•š@"qõ<î%¢!`ÈXôüúøž¹¶"™Þ'“¼Ÿ­ûŠ€InqìŠÑÃJ™õè÷kt>õøîÉ/AÂëGgÉô*IF ‚«K;·$þ¯› 3μ-¿†6¼l„ƒo?|qøüõóîó¿B[ÑÃhƒg¢8¼ÓFž¼GèñkêÑÁÿ¼><:x~ðâ¤{ptôòèAå7FñEŸá\ü5›éö:¦]¥y4Ͳ(ô;ÂàD²ò(FÃAœOå‹Ï¥ÿF[¦»¡h+GÕÂÎý‚S2I¦³Éˆ»ùàÖ/fçàsèÆeéŠgçôgáD-?¸†SÍ`CÂ÷´ï¥î§…òR]iº½DÓêQ·8-˜©äÃxg±ÙXƒ‘Ò|vq_r¥] —nò¸tHò­Õá(¦ñ ýGÅ~½l4J¨å“!ïš«³É@NüÝÍ“']Ô™Ò+Ú_pŸ`Œ*n4^|6¦ :†ÅCELÒ«^Én¼­mu“0à¼É;E›m´tïu¡/$†wQ9Ðl¼Q˜æ4çe)Ч³¤‡¯’ÓdD ‰ä ú€½eØ#êK`³q÷¯qC>DÊ÷è,Дôá:ý…íåI]fWX(êÅ£(ឤÓNÃo+˜‰§ ‘N˜œµd„¿ö#\$…MG¼™ÎÌô#t!PP™äÓ*¦è”À_}ª®i_PsÐÒI§fÓWˆ¬±Îu\ø„êLó<™6íC$/Å–ôÍnÔh\}ZÓƒŽŽk+&1б'Ï‘2÷òõ‹§Ý£—?ï*À F³áP& p¤qÓºšCØHú­h’]åm:,añøüœuëX€6™ÙÍ{Ñ7á¤Øi{¼ìÎ6-G;Ú¢DtÂÖûóÏÑm®˜Uû@šùì O°·ÚÑfËí Ï1žZVåÁ„ÜFƒ™\¥È¦”I ·@š­àd—M€y}òÝÚW8d.ø÷Y2»çøà$z±ÿüà8Z™MÏ¿ZZmºÐgÿØ’è’šÝ Æ#ãê[ÝuoVéh¬ŸœÍ.`êåÖ¾»7ˆVY? å¡M“ç&ßsñ$ER†×J.ê÷\5Œ`ÃM#ßJðY¾†ÿS„SÚ›dȬȜ!M \“,s-ú:úÒý =Ð%:"Çj ˆu d¸÷ád0±í·ñ6“ñ;Rç-wºpP#y@ÝÄᣱ ç§2ý$gô}û…€-ìêðIØ9[¥°pw°ùu`‹áÚisAÝN¼'€+^¿!I§J: ¼¡:8§[Àfêrå‡#CïèKwW™ pöívçȘÖG×½ªž¬¼­Ø~üºó”O³ñÇiµŸžŸcG¨üšœC3‰@N½â |æÉŽ›iŠŽp §e5ŽÑ»~jaªžM¢õGD4ñ¾µ4ÔÌ(\?j­Üv…G™-¬í*ÙäeãO£(¿ãHü᨟¢S#îKÖ‘E¿méOéTºa©”ìÊ>ý–%˜_`rð"â9*qqœ6†°Xº°gÓQsî(a½eŽÜ²ÃŽ>è¾>>8êþ¸ôâðÅ÷²ª2ºïöŸðØü•ð]·p„)zdËNUÂ<¤HQÀHˆ%²}p³áAt’ñ:uø$ŠöýàùC­;Éûí%m¬‰{×;µ^C*ßHuÚ&úC0§¯$oŒ7uYä'n¨T†‹”(Û&øl6Mr® Ã"I­ÈáÇŒÎÂÎP‘³ìŸ]ÓK¥«æç¯Ë5exWÑî¶ÜBðšV~ù –‡ŽÜï»:ÀXe½4æ( lþW,W†«õ.Aޏz‰ çZÇ¢õâê„îàeMÂ6j@rW}©ÏÉ ›æf¢ç­¶µ_ìàÃvDú‚îþññË'¥…g®g:"ÇŽé)¨kÜï9»@Wþåhp-ò+ Ê :JŒ¼Ä]ÅUA3â"txöµ•a=ÅÍÞŠ˜{´CkýŽûîÄí"âÁh v7…+Ç%ç.ZôŲR tQàðEy- ÄЬ]S:ÚÐ¥PHÒAÁ‚q’Ç`B²+­ ß é7ˆ›¡ç%nD×'˜wæ>_ó6€9zú툇Ӟ\(|ÜöŠ] Š¿ß¨ôéÆ[½á›Áï¾§ØÙ!†-§Š;¡ŠÜ¤ãÕ®0ç"ßTË FZ™s9Ww(”q¥¢ÜÀžRC7{ zÊÍ£Ù*Xò:/Û¿ð«9ý<šðî¤Cô[›`ÇdºD)#ÁhNÃ,浞TR­Ä™NáÆ*Èh,9p`Ò…J¨Ø„m„Õé1êHÝ“5Ô– С%ž\Ì8vGäþ:¿ÌfT'^‡JØ—<ÁÍ;µ*¬2Ï”ÝI®IS…ßM2.°$y/£ëL2EbAȾS:úwy‘TP7”R°Ü œþ m`5nIõ»N§£)mun°W—)ܤHúýäâ í$pE¬ !Vôf<¿†>|`FBîYW©Œ<õ™Ì¿©>™¨ÿKâ¾ôñÏ1ú–}Ž8R Xº‹v£ÏA^þÏÏÏágQó,aè"î‘6ˆ`$ I\´Óh´è^ûüsÈ(zñòä`W•9¸™¸ï@@èk>^¼~öŒ>£#¯wr´I/ÂØhKï¡ é­ÊE6‹+‡¤ÚÓdr¸·ì |ÊÛÑ.Ûj/›¦þ«aü!Άöh»òbûqã­¢—Ò{¿ßQ…Fóú!éáVàÚz٨܎eªAŸuéD‹@#:kØ9P`,KZsü›¥l¤ŠAÝq6nRi~I7\õ;~–_¦çS÷ô–¡;@åÎÓ]âríª´D‘‰_µç’æÊècè?ÞC}Ø~Oóæ.4dé]CÕïõqŠ¢.*DPÑÀM°¦Çª‡^_¨<Pô?¯ŽþÚ=:øþà/¯@0/×ÙhGf*‚¨=;|~x‚’bNl‹§-6î ­‚¡çEÍV?>xvðäD >²r–«bšg•ŒÇ“„­ŒÑ$Íßaõx•æbký·^“nK_•4¢´ý5W¢½Yšõ¿ñYOñ"xrt°r<õòhÿè¯ÑÉþ·ÏH¹è›í4¢ƒÑˆ{?ì¿’_Ï»kÿ÷\¶K]›âÓ{rÏöh$)ßòá}M¢—ß’F‡QñØà冎 x4ؼ]ÚÏbõÆ*OzÛ=™®IuÞ,ã­4VT¥fÜlÏ.› ÿóÆÍ•Æ­Ò?>±]~5ÁKœZ'CìÃŒ|´¬[ÔhbAR:÷æ.,D8‹87ËŠÛU«€ßÌ'~4Ï4ö\XØ åÜä3Ïýp[ºñìå“?1]8ŽþÙè˜Þ‡_u¿D?ž4‚Ö_ÎO„¿húãŠ9™|_Tûà»ñú…éHØ„s‘A2ÇWѽU§;Z™àæY– Z%…žëÄ Y"e.žþ (å?WÌÈÊ/•Ö¼®Â4ޤ¯ªAÆi4o©ø‹°ÿdéÆÇ¿b O^>{ýüÅqôÝÑËçÑ ‘áVÒöñà‡£ýqóÒ¸X# çe"¼8zzx|røâÉI³Å¼“ÆÁ£˜Ðïw‹õ‘ñ˜ù;Ê,ÂuûÀMx¹d¨A&(P*à 5Ã1qýÜk×sÓGbtQ/ÈñZä‹t¤= ´ÍßÐ ÛêµíÄíL‘цM•ùn‰’<Ðÿ¡ÿ¢<ùÃS©~rŽOö¦|7Pý"ŸM(I;\ZÌ ‚ S’Ÿ]zï÷*ýéîPæ}èYwš‰c Z™Ý~pœ—þÁÑi´â‡Õ|üð6“O2.Ž<¥A–½[;K.SØ M`UHš$W“tÊ«Äëû¥D ¯m£f]ÏS‡jò&ìÜi5ïÚ.¾éüü&oa—´–7ÍŸañ–S³s‡Žbk}ÿuNüÙ›ÍÈ03_nYNÄŸ¸o~ Gb¥è¼Â«ôïö¢þïý¹Áÿ?ý7ùÿïìl“ÿÿνMŒÃø¯­Úÿÿ÷øYäÿŸº€»>`;ÚøzwçëÝ­¯?q€“ÛÅä–F½B$ÀµxÂ%ÐµŽ¾@¯ Þ°}ñŽvÐ $ñ‹tUÆèš³Ê(¹uñûïãQíoIŒ¨tdeænÝílv>´£ÎFçUt–\g#¹n!u~÷ã{Ë5Áeˆ uDЋ]*|9Žw××aûtÐx”LׇñhÖô·?שÆe¨ƒêà‡:øá“?TŠžKDD¤¥ëH¶dpD¾ 8"Tz ]C.œpí€tKÔÍþóŠ“W®(EP¤¿6„"…ñ§S8 _|Ýv¡ cÇ@~µÌGÇW¤ ,Òß5ÂbqJ|±\ð…l¡ƒ*ø!Ô„šx¿³¿Ùv¬/þFžšÈíuÿM;Z> `Ž;è_›º'N[‡ÝR̃¿¤gÒñk ܈ª¢‚– HUkG]àŽÕu`À¿>0àVð1qîÊuðÒŠ HÿkC*ÇYÇü÷ŬJƒŽ4Ìp‹&œAOëØýdëYüg„~Þé‚x‚CPPÜ)Tž6 W7gŸÔ±ÿžØƒtùàƒô?0ú ýo?¨àþÍñðšªõö¢°nX¬³8‚:B¡ŽP¨Ý1ë…:Bá?Ài²ŽP¨#ê…:Bá?õJ¬#ê…ÿg.ÛO¡ðQžú¿„BZéom\ãLJ(|ThÆÿö…›—*«cê…:F¡ŽQ¨cê…0Fá?3H¡äÿï€?Y ýÿ·ïݽ¿åò?lÜßr›÷(ÿCíÿÿ¯ÿ ýÿýâ“Ûÿý{­ÎÝûèüÿõúÆÖúÖN´µ¹»±µ»}o¡óÿªÇø§³“+êGÄ™½¯r‘)‰ Eϱ£¤¿ +Aþ°„$Ù€®ý8p]"DeÒe¡ /9c¢Ê¥#1)Ÿ¨"ý‘AŠY×Á>î.FWÒžœÜÐRÊþáÄ™æ1Ö-Š‹tô>¼‡Zz@Ó¦¢I®"Ì@ÇõAl;ÞÿóÁÓèyøà£ˆGÑlÜ”XXr_›ÓÔëWOAà|Ú` ä%›ë'˜v±¿TO.sÛ¦ã„Ü–I…ÕÇQ>Nz¨VéÃZ_OhoŽ`Ÿn<^á*ñºý´&RbæéňÖ=Pâ{±å‰&Ë£Ùn W%;îÀ‹®ÔÛ”ÆÅ5Uä*ù‹oLœ©´Gn•T¹:6yÿ­Û hfƒVÆNÓî!‰@ÎÊ/ÕœJÙ·ä*%BQ`2Õ’öÂùž8™y¿h6÷KssC\ª]£:HòøQrà’rLUíprnê62NªæÎY2™šq@ë‹ véªébá"i»È¾D amü U,tQS"K¥ëbÞWˆ–ÓëRJ¯µ ïŠ1dG;ßÍvyÝÅnþKÙÛ ÁÞdEì´ØE÷×j Q·Í´]îü¬ØèMþýåÞêK[5ô2AR€‡ø ù½Þd6<‹€È¦g ð¢ÍÅ}ì?’½L›x-„ÏÏÛx.'Džˆ•^¹Ì†É Ý ãIÖKØ: îÅÙTÂÝ‘{!ªì@5±ð]išnUR ¶˜˜/*¨„éÉBé;rõ4µ„´¡¢™J|Ô´WŸ>3j9`AïªçÇSÅ…Ã jÂ$ά‰eÅJX]!بzÈû}`ÃgST‰áà¯øi|¡ë'ÏŸû,”FÅb à 2‘¿°"± š É­Þ)˜n½‹_4ç_$²vÔÁ= Í(íðʰtä²`§ß9ÛK´‚ }˜æ§Æ R#ˆX×ÌÝ8eÕ{ÄW¶ˆ´°­<&ÐMŒ„\Ãð³÷{oVä~X;¹'oVô‚(R®c]ÐÓf3¹7›ž¯}…ÖÉ8uŒÒB§zÚ úà\Ž‚Ì½³D1³s™¡' 9Ä Rʈ1D¼oûœ¥²<”^¾‹Ñ$]â1U‹ÆoQ$žéu³q•Ž“P†´öÜ''¯Pq2† W÷ÚBòˆÉÝèGærYKGvb¥’¶&!J5dnd$ƒÒ4Ë|€Â(Á¼Ÿ±¨2È8šK^H ¡yÔL: Q¹ýåø¸5b„úÐ\•ÙcbǤíuΧØÜÅ ¨> "›2ê#Š !â„ ÃßÝ-¥™O^:gB{p=²»^ 7ʇÚJÎ bºïhCpu0«9¯‹ýñ$RÄ0¹5F9\5ž&Q€ÔŠÓŸ–¹E3ÉH§ÆòpÆŒO¾©yEþ£pôõGªÐ.~תºªv^þ‘W„|Õ Ô¡åmÐ*’êxPX‘×GÏ–bf“ò³§Ÿ`;JaÂÞàI*1ÓÂåÄý~ß6%&PxLþz ºä¿è+²P" ÐLˆ¹,}}ŠEÞ–ˆ}±4£‚ìEoR  Ž^Ó®rë‘~¯¡/°y)¦·¦?3MmÇ–H"äÔÑöÈ‘c}’ç_~nøÔDk㯠_‚üÏeqªZsn4?U[Y7Óüí»@hÙ÷…”½0Ø)Õ˜Gg%Ó²ßúT¢H"xöTËJßï•¶˜5e:¶› [©&T2’a˜éÆšÿJÈÑw^O’y£'Ǥ„'¼jñÞž“¿EŒfA ú3$Plá÷Žd›ï%BQJÊÙÛ¯¨€nŒÕî÷'ÁIM>Ð¥Tüúì4Þ6Tâõ÷HeV(â‡fVdÓÑ,)êÄ]î¸éîÊEóIßùFÛ‘K·F&«•í5:SÄý±Ò}ùÈ7¾h´µÆV•1<¢„Ê7vŸ³;ÆÇ{ÙðLËЙQú”M3,ñ:g]i?EwÊ¡…JK¤„¥êYMŠîg$0HD©‰Žt¾õˆ+–Òâζ?T)…£l¯X“óö.»ÍÊ^ûMPã~å³Þe»P/œ6ªQÔñmˆ¦Hè> Èûy#8@0Ks ¼i¢é:äï"dÇÁñ rh1ö.ëmßân1Ûd^ Õá‡H÷ˆŠFij+2Ët¸Ù$½H1¥ œa‰ Eãí orVuÚø;ãø¿T€uó]p†ðCò÷FËÒþþ¶§I¾è1û¸F¬þ²ä¼a¥T*lj˜ icÓUæÅøP’ý)~šÃiFk9Z)åÂäƒÒ ’Ü1ŸI,˜–bg4ÙüÞÙ(ðMãC8ƒkäºð­~ˆî›ÓÉŒIà•QN4rö‹¡]îÓ>F?dWˆ"Cn¦˽Ç3܇ճä2†ã5Á˜Xs>ÆXEp¾àX¦.üÆmÊ5¾Ž›i'éà÷äºXÜ•¡/ç†qHñZA%§ ç´ñ¶PVîqt™öû a Ù0ß Âå‘-í 3=‹Éb+`\>oK)ì›33 bq` QN¬`×5Ö¨z4fз—l1Aüèc6ò VXAPàËtÔX;#rdÊaiÎâIa_Í£8X“ð:—É`©Fî"ì"Ýg²ÙIuŸŒd»¢%û ÜÁð=‚fy!M^5Ùi"ó°&` ‹…´Mx'¡%šŒôÊ0H.”žÔ-ÑlÝáÕÚ6±ù(åÀ7Ú4šÄ²‘3•p‘{p 4-(‰‘éç• `Pƒ©ß`‘OEŠ¡¬¾£@…È6uRšÎ_µÿs°Ýqoe#hºMn*£Àåyõ|_ “¹¬‘¾‹`Oƒ^ÆQY{´µõ.³I+¨ õf]åÝ»HúnOeƒŠÕ›bøæ ^h+ÈÔá8úîI´uoóªp¨›mrkæŠÖ¢íÍèy†¦ÅW Эã05yYý™Wj‹šfSÃK›·|=[pÀfèù¡Œ¬‹Ì4n©W?¼j“Ò‘r„˜ãáãBãIOÖˆr‚µml‘OXÕãÞEu ‚¼¶ûþù]˜¯&Ù‡kÿð¾ W8’QDM‡‘Ó‡½²ƒ-áeð4»b”B~KF·"b%uÆ ³y”¢uúÛd}À—Ðn¢ò™)² d5®O@šTa™” ºPÁ¯ +£W|Ã9«xe†Û}îIyƒÁ;XJ¼«?Ž×I> ¸È´é±” ^ÐÜCF§²9¾>~c³s*)!AΠçg„ƒ„#‘½:üTÿB0¹³<̦¬õ 'hx:J†pÆÐ'`€;ÚÇUãÕïô¬¢'­rfÕ–áLX×·òf²¢€&ÊSb«ËqŒqÏ™Gö[rjP!ÄJÌõ”³ˆ*:[‰x¸ŠG‚tÒ.0ØŠeÃÞ x¨j09ÍÆóýÃ'/ö_<9è>ùôXŸŽŠO‰[äjÏÈè¢Ä»¤ $¾ÙAbêGë”ÈQDû‹K½½ºä~Ö¥f‹¯¦ ”™°•nåËÙ´OG]ÎT;º’lØäd‚ñà*¼á,Ì\e?h‰TUý,cÝžBÓWWQ·¸ÈB¬è—+º}rºWc×õò Ó-ý%·'èòޏ:Òh÷È"AAÄx\M²ÑE[à€fþw„Ѳy¨ê³·±?X[ _ѵŒjøÜ…oÀN¡0g™(rAépÚ,(ªG FwÑ*!EÎÎÏ×ð)33Çü€ E±dh‘zBÞe¦‚¶OY_ÝÀIZßìlFt É„©Ùȹ5Š’ž³9m6ŽmGE ØÛ biÚ¨õ‚ Ùýç]â= €@v@ʬ‰Þ~CSƒkæ á*†Í`êàéõ1tÄAß”O`+Å#BԣˎØ)„ , IÍu«è²1è@Éw>ŒºÕjÍ]Ê»pksõôÜò€´éD#Ç Ì9úz(Ó¥<óáêV®ß]aˆ?œ´+ÌJßÏ.˜¥¤&©:ÅÞ12²Ãý¸ò䇧/¿7;¼ãÿ”$cDÜdÆçÑzµ y7ݦó  ÚÉõÈ_^rçncóØîX±V0#¸T :Äu|ñ…TvÛ6d€)Ô™C°PÁJ:¨8·6; †”ÆÆeŠè‘‚«é¾Ì º‹È…í²š‚\rï €­™ŸàµHC ^BR´¸€1Z%°~SRÁÏéöqUíEÏ^¼î¾x)`U/÷Ÿ 4[÷éÁ‹Ãƒ§:+UàU¸§Z¥~C™¿ëÕ1±gÒô©E«DŠŸ‘–±I£'¯^3H1üç*í#Ï’ Sqú@“ø†²ôÔÖn´9ÊnÁÝ®>£ÈI0Ësíi=Ôý×:J“åÎè6 èg¤ àAû#Ê•E\Ùÿ–ºý;žÐÿut?ØQ•çó¯p²lõp”“ô2ΓD ņ“c·PÅŸLHßå?œ‹‰QM¢jb<ƒ“´xßÍü`¤£9!´;ÑÕ:ÊJ1⤢}õòÿûú„A¯yɃ B‘¿ò2þC|UX8*S®£¿Ï⻜¾>: •ì.àìg¬ ñUŒãs¨}Çé$¨i˜Àªô }!iC;ìЇxŽ×pÕXú©Î3éÈ’Á "TÄ_»!!Ïu‘LB@3‡À ÑÞ_‡”U**TÕãVÑU¦GÁ9+7ƒ–Ùn{'dÖÛî9×Åê½Q¿(4TÓvI¨¦x”\]Úº>¨Œ€í×ݪÛ2g¨ok¥ÃÌD×ù|Ú2ˆó¼éˆ7«Uh&„{'Œ\%Ä8ŠÉ›|½àŽÆ"9§s@ž‰¬Òë=¹ •ºs_ÖlG0sXÖTö¡‚^YàÈÂeMœ6¨G‰½BJ ¡<©Â¨ó‹ëϯÒ)YqÃÊ¥nÚE \¨Æ®³º ¸NN3á¶ú¿£Ýè« õô]EdeByÅ‚ÝÁ뫃[è« ø¼A1Yô­GÎOxõÑD¿9ÏÉÆèñdªióh~EL.þŽa;ÚÜq5 «ç»…AånT°1D‡vû«lò.wÀáw;Û¤«M;ÁKèÂññ³Î¯™’»w·—ž(û1“ÒÈóÁîú:‹þKLÏÖFÕôˆÞÕ­wi{¥#víàí¹ætóhsvå¿ÐGg ƒ‹§!é;ÇÇIÁ0 _ò#Ã…’).’0–Yý+PÙ¾€>–PPBò  ޝuõ€2\úèI"xFË‘wÂó%zÍ5žÇÕ‡¨?ð0<ÃêEE#†ÎzXW%«çqJHôtQ“Eð[1ÔˆŽE5r•œiUœR ·º î1!–ͦžûà&f: áÇ ƒú 5I*9ÁæÁzÌl1å\”ÔÈù5Èîý uÈðã8ÏœP‡Ëô½‹#EÀfuXD’0ñ€Ú0ÇÈ Ö:·Jh>a $ïO#Îï"Hs!^ƒÞ³JÖÐÑМlË]ÃØ¬¤Èn¡ÃuéÔ©ö~7Z¡qx ·KJÜ—ÆHZ§ZÁßv™”­Hò‚aÚ¿Pݶù{WM9Í/%­ ï•N6¹Xo‰"ª¡ÈϒѬ!Õ>#ý¦:¿’ƒû-Í­ÂíDW8͇O‚À}" SÄsQ^dß<íwŽL+B+vŒd[pF—ü´±/Œ½—ÞÂG»Ñ·Ôôõ»÷î:¯S1’þÛ"¹ÈÖl +»+È>ä›À =ÞË…äѪg} .Y®çRÄøGké /z*ÉÚs Y§AåøØ¬D"ƒo¼™ˆ“½û¤³g\Š'ìT¬=hKR‰Ê:$°í–¡º¦Sjý¥Ù }ß„›£í^¸ÝÁ°ÆÊÇv¤:fj÷Äe…ÍÛçIvÞ¤ æÞålôÑ~&”µonlÝ 81®{K¥U ;gm=V2¢¶ ´NN£m?FF=ñë~‚Ú¾EŽËD—_r9¨ú£¹²Ž¥ÆÿŸ¬“C7>æ~p“pçN³^6 P-r_ã¸üÎ;Ýml×Ôâ M³.ÕënÐòºãgz•tñ{ó›“;hX‚nkÓÑ]”°6’B¤^ÐA·ÿyõ¼À68N¦kO²ì]š#¥æ›_ï2¤…+UŠ»@Žq’æ‚G1ÍÞÙÁâ¾*þp· ‡—U`hëå\ñšÂÑõ/Ø2” áã—éÓÜ1 ó†E×YN)³%Ew¢[âÜjöæTರ[px÷mnl8Ò~—«¼±IŽIêÀËè•l½\ˆÿ–|ôòOk,ÅùÎíÓ“-z‚Š—±>Ú¦G/àr¢;eæïЧ١rw¥œ†¸ÐÃzÈÑ=öù=zþ ãá¾ro¨“ÛÒÉçêøä2K{ ò7ÛÒå’3½ãÎ'‚mé¹sF gÚKï‹@wô*eWzvŸž•=¤›w¥›ßÆ}xET>»+=|=òê(z¼%#¾&ãþsyüj[ú­ŠÕ6C´Ÿ:ž»ÒÉç|?à«}ÞÙôòžû€WŒ_ø‚‡AÊöƒK8ìÅW²TLóO€]ž—^}­;í|öèÑ&ý{86ô'šÙ‡ ÚM÷„à¯Sjö;âËéívÐèt Xî“,c ,*r×Y{}tXx/K7ržÑsX¨8Â+*pÏV€áÕ„²Li¼`òóT§j“§êàÃV9ºJ+¾#+~8"G”æq;@é*Ø‘µÇE8T… tG–÷Ê÷pØ®âkzª;”Í–¯ÙßòÈ¥¼]‘Ù Ä&ÿYò¶™¼dÐ&sl‹ÌÞXÙeÁ :B{:+*Q&‹†3ò,‚D49=ʤ“{«±¤KsʶtBÂ^^TÏ;ÊuJß[ZOÂÞù Ãlô×:R´Vtÿ)ëOȤnÕ&@Év)¢ìOþœî]Ñ5DCçiT© BBE™Œ=!±E¶LE(LÃ"÷qÄîÏ,THþ;J@òÑO(¸9¼i"Ôí-¨Øëüœ¦O4|íhmMZzPl9?&uêmHéaxyÕWìãFï†÷zâ‘,h VµE!÷— ÀŸ GÑ~Ük9ˆ¥7^adÞOidÊpöXšz4ÀüT99ç­E@l%h­1PíP`snFãÊ¢¼7I’Qµ7È\Ót:&ñ- à(Æ£tlGø+nž—×¾m’ˆ‰xÉ .ÇG°3Ьá9×&‡ìPÀ{¯GÑ!ÌFg'×,Úг_ø¾ÙB~o#t¶Ô¯<¦è‹¨yÐÝö,ú[t€æ£Ã'ž\0®²?Ld!ºLX¯â ªÖ‘ŠÓ߬ÿÕ2|µ*‹|ß=äõ´Èö–æ+»wWž’~ÒÞÜú*xî?ØÚáºIÖâ;r ÒC_¥ÿÜõ8)®m½©ù.b®/S¸x8I ì¦4eTbèGf6b ž¸„%‰¬uX§ì¸t–|×mVñªQ ƒk ÙmÓõã!?[¢l ÛòT+Y°‹U—÷Ì¡¹¢Ê–°YÊ‹ÖrÔzõL¸wBtEÖSEoCÃ(Ú¤¿ÓÄñô$á¿ÓÍÕÐ! amƒÿgˆêwL7àL=ŸÓ/©œ¤^âmðçBG›~:*øSV¥Šc²H7J!UÜDã8rJwÙ=>8úóÁÑiãøÉÑá«“.fÄÙoøºfæ+‚xÚJIÿO*¨ }®sÝÿœÎ¿NÃçø_›g˜ëã a;½¦~ën¥Õ(®·î‚jPÍük'" >Xȧ·D å‹q¯;Œ/Ò^ó‹Uôb°1^ºwé¹Î“«xðŽ_ hqP‘÷0":e÷Ýtœ£õÑ›©âbS1E'ðÃW‘|ƪâÕîw‡ˆˆš¿KÇc Áy/á;Óá˜\ñ(t–%RLüö° ç܃VÆûºjaãÑb¡Z|>~„“ƒ)/ØzàÜ\.e1ÞáA] š'® úâr tMÀÞÁf×fcL+Œ›ñ³»[[_m„ƒ¿‡¹¦=~q…š’žÁÒ­p`Ÿ`OHNä¸*7t¸½CøÆnßóiÁÄ`Gèj”2qá‘sÓX[£ò p`åA(d”eJ>yùòO‡Ë•W¬å ÓÁ¹auÝi~F»l'pGçˆ".#.M…@‰Œ.f(&¸­úLÐ38k¨Œf§2ò¡è,`k•—š¯t4wR5ÃŽ¼XÙ9ßÃ÷òy'Ë­ûÀ ùÆÂÅ7>–ˆW[ãÁ¿6\nq)¸£œÀ.N¹Õ '¸ËgÍìÖÈc€³°â/ˆ¡Ïì.…Ó|‡O„dG4÷ùìl˜r–hUHrÓÏ<…jûw¤Þ¤—Sô¥¿€ ÜhÉ{në›dÔ—AãŸû臃Ó.³:%uÎÁ!%’çKÖš¤8Ìø+)ÀÐÒ¦Á‡ló«tš (*®þ1¢ñc­×¸²fÑ ñƈGüéJ$xè,È¥¨ê_AK{XK!y‚ä¶Ž-Ö¯L^ò,È çw$†”ò %h…lÑÿÛÄHlà±Äå໣%€ :W8ÅÙl*Vk$ÂçFº¦Œè¢Ô,îV-Å[MܽÛ;° (wðj}þ>ÍSZ»l²nëhyÚ<<£Ýñ`6‰ÍÕi6ŨþœtM2C"ƒó Xé…ÛfX—6WUÙõQÍ0£`¡ÍèBôºZ—h´Z•;ÖN:Úô§×Îjiw¨nëÞj;QÎ\›«/ƒPà€ã|-Í].N²VãÖàr¸Š~ÿJ¢¢…ƒô‰µaœ:ü±Y¾Èqr¡0m®rFI33n$&ÖÓCÛ‹ëÊ9‘îVÙŽ¤ 1ͰÜÓèöl2è¬8æÿ¤…@Ÿ¯\¬õU±S²j_²"nËQ¨Â*¬Eß|üÔòÌ•ÿå6a—¸;C­!<’Œív©›ÎÕaS Û ¡†,¿*ÜQˆu/.AÉÖ¡ÁzÐL#Gò ?Cü”Øk7…”7{þ<}¾Ä< Éò3E3 É™àsÝ—éÅåþ7U7.ò¯íš}Oé«„îÇ:St³øfÄ2S“á#¥/ã-'×áÏE;”iÌç8Ì5"}èÈñ߾˻ÜÈ3®°€¹\è(¢È—•ÓX=‹ä3%aåèQ9eT6ÜhjÁtIhþ>—Ì`ÌH.—©^yÜ}Æ/Hás˜ŘóWeG…·À„¾OQg/šRÑg”…«"mÀU6é³û<¾ëðÒ ãÉ;˜|½T=m÷]Ë5n€‚bI@qËOax»žc0~žrz±KÂþIƉŠ5 Ø$a0ýC—1nc’>ÈË]/ ®:ßâ;¨Výz1Vª€rôƒd6" dºà‚@Å>Ö°6ÄéãTÏ»ª:´Ž}Ÿ)£ø yìö¦„(Сdåþ¨Ùw´Wè°.O#€oGú`ÞuQÝsÜtÉ;hнÆ>£ºÙð=GˆÕµ·tså‘íÞÃõøQgÑ€ Ûþ›„íeF"cx„’H,PèêI¬1оn¿Èw‡ºF‹—åi6zOoöÞECñä/uâÉU­<¥+ÌÕ´RYÓ· Éu´)ZÆw©ÚÈþµ†ÚUw¢ÛÄâ (öŽómy’·5ÔCÿ…š2:²ÛèRMo’7ω 耙^MÓg˜2ê&RîÄ‚èq×sUÀ „Êbè× •(¶ÞŽ,º·(ˆõaN……õ\¹‹&áÂo#íÌ_~OÝû#ë†:î¸!t¸B6mê§­@VÚ®ØÇì¤àΩèWk~ÇŒnln¯´ÌÆ’AÏÈä&µÒÉÈlž<>OÂÆ­bDAà …%˜­«¸˜º®dëÕ}£‚nyODÍŒ°\rp¿ô-ҷБ÷ël–Û.Ð}Hhvµa.Eöɰå$šMbÄH}T`•¢`LzT¿PD±h ž|ƒ²Sh‰Y¶¼³òk¸•yÉ:24˜‚¼06 E ‡GýÙpxÍ'‚Ú£yÍŒf’ ’÷È[û>y Àœ e’ѽŽ+CWtpÐ]>g·NœåÛÅMLeyH-šñâf'ƒ>ùxÍÂxv6@ÅÔ5úQLú”l¼ñWýC¥/7ͤÌI6çýNŒŠðï £t(„ŸÆN¡Óhcá—.˽xù|o™Î8›~Ðì¨/qP7ü¾‹ï›F¡²ªÓ[TwPT·¿2éºôP†éŸ·Ü¼ë‚š´9œ cýðÔEœõƒavæÏÙ €¤t¡¼µ$u[P_ùË”v&ŒìãEb-æTT\QB:£&¥†2^-ÌeŒ”O„Û­YM¯±ÔÚ#ÚQÕ¬” l‘ç1§Â€´£ܪpQP]J&yÆS"LšöˆñØò‚r¦âRŽžR8@ÎÐÇN¿ÈWåÅxß³–A}Öö–’£¢âÞ%Ï«}qÙ=dõ:*r(¾¸è£~»•‚ZEÄ9ÿ “'}§Eàô(tb8ù ㆉŠºí4€ZNs1k`Kd¶IŒïxÀª •Í& áTR$QE¨žèûlHòÓµ vªú:°‡Fƒ4¿$yœMßH}¥'gœ¡pÄË­º¾¶Ü….ÊBÙ®¬|;KÓµ”£'ç Ó®°sI‰p‚/ä0ÈhÒ ¹uÂé x%zÄÔ‰Œ®²nMwtaú´ºjVíšfXÓÃ1Íð]u‚>†É ú„‚1Aã1r2¤2'jÃ4¦1ý@›€X7¾G£>ć4›’Ϙ‚ €¸$dDÅ3(¶ü§‹sm°aæS¶äœ ®ñÛj©ë7v;XsærÞÜÊMKmuöÁL>v|\3´p s•ØIgüô$=Ó¹ÂyP©Ë,{×åæˆ÷ÁOg$;X{&×`æNÑpÙuƒÅHŒ3Vf Y—6kë—kÃÞËcÉÍB¤`z8“ðNŒŽ®¬0N?†\ Ðþz$!¹¼=xQ«¢{±)9ÙúÖè£Ã8aÌk+5aÎñ<륬Û5‰€2¹´åØÅ@V<Á‰Øo½Dê#xÆZ—Œ›ë$´0®Ôk½XnG×Ç>k`1+†¨èQñì< –Šª•'€]–±€¶Œ®m¡‡I_Àá¬y×ê‡=A7êÐ]ÕbÒy BÆj¡¦9I-÷éç¥OY×Ä(žì[í¶¢Þbªx´¹$ÐQä„HÛTôeYSزˊÔÚÓ„—¤a‚éLx2ÉYüUÔ›ø¨£…yôŠÄ bÓ‰íSÑ9üúÔM±udžWV)ôbZÞ ?è’Ï‘|£Ê8¸‡ƒaþՉ䖋cV¢8Ͳ6§ÓƒžËõ$B(ê„Ò{ÐבÝ4°SÙÄA–Z†½cu_™~{û;‘ÅBÏΣdä:†ú윞%Mä+SÖàè!·¿ÑkÑgJ”ÛÒŸCw>´_¼„RÂ0 åË × øtì$ç­mHÉØÌûã5˜‹ßn|Üá=%„÷ÞuKÿ‹£—®È}€ ¡ŽyÅÉß±Ü~þŽ -âñ«+´õ¹i«à¢]hœ N<ÉžßÅYñe.´ìæÝ.þÜìkÂbi£‰Î`)Ñ­. É%7®o`ˆÌÀSÌ=3:‡Ä·úT”A )`³¡‡®åN&é9_+ù504„Ìl—B>½±Šwgá@–*’Ñ@Šéøjk‹hA?™¢ñµƒuÌç¬âª.î½£× +%…DØÒül>/\…ôª›`Ý]ù¬Iš08ħñÚ?ö×þÏÆÚ×Ý7ko:o¾|ó·ÛŸ½Yýü‹;_¾Y³÷æñ›ÿûæç7ÿ|óËÿ÷¦ñöKŠ]ígd‚¯›wáÿ}o6¿û_߬½½c^´Þt·¤®tüþ.õ_üs³½ýKóMÇÿÑúçö/®à=-¯ï¯}‡%îBñÝâ£Ö?ïÿ¾£6Cò½/›+룱ӔaüÜ|sÚ¤nüLm´ÞÝ]¥ Rš.‹EtÃn2¸Ò!~³°í¤;Vç‘Ìc&¸ã§m‡º˜Ð! a·™»ˆšg Ș#—v0fD ñWz¼B>+­Åû^ª]nÏ+pMÛw4 @kÈõQ_nÎMo÷‹P·õ¿E¿êç³è/FbÇ÷ó!;yiNÒùtü3¡¶‡–QÕžò¥¬ÀEõfVH*ŽUt<Ì‘Ï;¼tárŸ,·Rä*«½ôeéúÒÃøC:œ õdªí¸Ð/m9jâo2uU×íd–èDÓ„è Ñ¡Hb±6hóà:Ñw1ž9g€®ÜZGÀ3Û”e÷Ó#̨ a7‘6ý¶;>xvðä$zòòõ‹“æVôÝÑËçnÿýøÃÁÑ u¶X´ÿâ©ÛŽö™Û˜Ñ#Ø…‹7!&@¸·±Ñ²ùçšÚ͇v}3£²kb}–\’þÐ’Ðt!8AîG˜õ/«Ns¥) %£@>†`?¬ÇÁ„b*"à‡¨ÃQÜ“bÌwMx¥4è”Á×>‹û]­ V!áz޹2t À¼>ó3ïI9žOÊM-¾;dnkGÉ´ÒM®‘|´ŽŽÉ¯u” ô4í;ÆWs¤«¢ 0.ÝL¤z€‚Zº¸oÙy -‰ã'Ç÷¾#lŸ¼óÌÚ²wäecI 9_çh?õ¿/§Q´I„¥¿šØú¨Ei è¨h%8fÔYy¸Î*¿ÅqûOißà#þŽ^Òg·Ü>®ÓVg#ZAŠ´âL«êÛ*.¼&c˜ïÌÌúT ×…p ôÙ4ÆÍByÊ%ØL8H("è)Êþ†ÖfÅÛãêT‘/9¿ÈÔ¤îùÑHÎ0 ~=ÀÿQ$m8!¦ŸÅ)å¬]t<¦IÞ¤Þw±ÓM»qÈŸfÏÖT=÷²Ú¥¥óºgZ-V®Dvô‡á «G¤éµ1Öý‰¶rá!Ôì«[ÅìÒ–ðQ¥9‡û+ý+ƒ+/<©UçÑž¬âßvx>b‹ûh‰]´ô€šü,³ÐA?t©²ÈÞˆB­dâà-RË’eÙ!ÿƒÊ‘€67¶ëÆ.SSÔ·¢½Eœã¨ù>¢'×ñW—i¿d~$v2§åjºƒr øª±ë÷L½äˆ)ÿZìg¹)â®ßÊU=ÝÀ\Ig΀R×5iÍ¥D…SDîVªBŰ’©{+®nš=·‹¼Ü²¨õ–¬µÓ<œÿ0"$ö¢ýlÎ.o‹'…1ä¬~,±óìO ~2I{œÕëØI!CåOi)õ{x$jŸ”ôºkcY‘fUü¬µP¢Qï›Uœ~W¸ú{ôJKóÒ¾-æx,z1_«û­Œ•«T,¶[azð¯Ù‘¼8™@G”tè@ô· |·Ðã•h½ú3kãKkÊb«†¾xÄÕ•‹kõ=ûåV˜*{ÑÕUÖΑgÓ`C¼‹yúñ·¶ƒ.ÝÜFf]Ÿì2:fBr¹%¾µNi+nÙ„¦Î 0`dìõݬÉXÜR'ç.(XˆÃÃTŽ…‡™í„H£ñ䉉Ǔ'yuL€ÄÓŠ¸ÏøcÀ[£òÒXî’àÆ  ´Nò‹ëµÉé*‰üD¶5zSøù(¹¢?:åj’Ñbuù’õi¸“–ã&T£®=‚g]|FOò©}Ïèýœ¸½d©S^-@—ªàÚ:¿Š@‘€ ÖlU‚I•L»V Ð¥„q° ZýdŸ´<ž¨7,×¥r¨åÑ0Þ]MJnŽ’ëÊ&9=ʶY±^ŽüJ Qô”1{ñ#™}\½#ˆÏ`I{eîðøõG N¾h;o•âÐ8þÐwл ÂAc£hå³ff"ò•ÿW*®è[éR»R-t¥â4˜|7p /mm•`5BÁns]—ŽîerukîŽâÙ4Ãw²ÀTîó/×`º–óåÚ¿Ñ“«@õåø¬z#‡|iG/v‡ ‹“ѯ éÁ"PÁ$ˆNe¾Y¬¦ìÕš…ï%¡L<£>YÏÕ‹dª‘–C¨” ‚ 5×ó†R q)ò8*=öÓãõ»ÑÚæîÕ·qïÝU<éç„× »„1õÕI:ð°ˆ‡ãæ¸Ê—Çpu΃†êóì-y¬l¬x£ÚÒóê?߬ü|a÷ð§ä<3‘€î‹½hßœ"cʳÓi¼-ì™B_ÄÓE{ä:gŠ_Y'âJÏé}‡a¥'åìzšð¥R”¹1dÛ9œÀïM,’ÀÓ› °Žœ©¼šÙ¢ãCþéál”Ê•ÏÎÏÓroµ£í?µ£çß"zÞ÷¶„ª¼>ÖÁ›š(xN:ƒ/š49µÜrv¹ASº)Xúïø¯­»ò`(î~µsÿ^Ï¡üÝ¡¸È…¹¿}ÿîæWðe¡”/첊3bc½)Õ7ù滟‡?_´7Ï7qF··ÖÓF›—‚ÜHà›’›==Ý| -¹QžjÐ"ì¦ M&“¦”ÛzÛz[tœÒ t^`)̶^½eR.ÿ‹®_ë\qm,¿ÁäFñ;lÞMAD‘¦á!c߇ W¸™¸&ŠpÂŒHDóçB»[7Ono/šPžNþ‹÷£‡x—]¯úv~Ývö‚1,×R¡­ç Û þ8Á*Tù W$Dý‡H72eZ„ŸÑïÓT!s8FÀGé¹TŸ!òv ^+|Ë[ݽt0`¼låÖµ^D8 ¸ì𘺹Š4YY?=§ ‰S"œAÎÀÔ†‚ÿçóbs•NMõÁÒ·M?Çí`º`3mÍåÎxÊþçft ò×Ïr–ðwF ÚÞÜA»ì¸«$y§Eðw.rȾèÇ×ú~å×_Ý»+oÑš­¯ñwiáž¼¦#} ¿JÕô¶…¾_ù" Ôèeõ(o®z”Ÿú?7ªÏgc¾Þ+¹/…ZS5àÿ(‰JÔ)-Áüöu®k•ÜðéÆ[ùeó킳™}¾gªÐ;³økkJ-üˆ‚½að‰¸Ñj­ZFå·]$:´szZABúÎ'ÞßpÖÏÓ‹Ù$QïBö²’ØUy‚žˆ[&¹7ä!Z5ÿ<`î¹³‡;ý^Í|_²®¨p:Ưƀpõ¹—ü±†qxû}Ä/wå¨6Øhäs°f0„%(bòJúBmø³6s¯_þÅ{R¤ UU¾™/É$=a‹Å y¥­ðxWpŽWh¸+^n¥4²\c8‡çÑ iisy!5Èò˜ J¯¾ÎHÐa.¦TQ L3#ÄTrFq¯ †ôí{Oƒ‘ãù Jˆ: 7A´¥„Aj°‚)cˆð„Ô̼I¹6¿rÁ²ýd™q¼ÿÁyæÏ Üß^ð°e¬¸h;÷žFÎ×(}#÷Å2·×÷ ’…ä¢Ég`!x´`Á•DêÚ=wâÚn¿ Ùnû™õNsÙDQÒO“¯.8Õž†‡±HºÇé‰Ö301ÆÚ0$Ö,%˜QMÆKíEA· ¥,ŸšaÌ7aßHÇ.Ò³ëtm#NoôÿË=_რo)±ƒt›Lù\Þ·½P¾ý³KÂý;\ï¯ÿ5Z‹~ØM}žÈRêK¦ ÓÀ #x÷HïßE?µ£›Û`æ×TÈ=G7;ó¾–íÇ_1,Ñ_·}OÛQiRxq†ñFÙ¥½Ã2§BçÉð)¨·¿7DðïCúýòKd‡‹«8]Mßú] Õ³¼ÙØŸžãêµ¢ÛÅ4±Ú$áH\ ùTöÚfÿ´n”1hï²®ŽòW}¦­R°PÊš2TßZ\Öh˜àªG»~¾=G† ‘ rMÑ uxÀ¶á3Z¹ Á¼S°º·±¯kÔÜ5×èD‹§ªô «šÁVÏ¡®Ú·ý‹ï/Hz6åÇÓ“×W?þõúK,cuϭפQQM5™†­ìhIÛ4Þëýè9NØé»yôÒìe÷Í˪~ä”ü}•?ߨêãÿ nOÚQAŠ,õ±Ô_âÇg¹y¿Î£ÅÇŸócx}oca¯þOU¯VçÒpóå›7•ŸÊYýòKwZ«®W¼W ìÊpcÀÛ³Âß›*øºõy­¢½4.E2u¢F)g›¶FzÜ *0­ø¥ç5Š'œÓ³¿AŸ*€Û>ÒˆØóu1Ù¬£q{¥Íéݹ&Û c³®”x®tĤ(ÄÆw¤ñF8š>j;›â³hԄТW^”TSÂ9IvÀ~±Bö󟱥Kù¶jÁÛ;*É÷êLXÀfq¨…vˆÇãdÔטv£+©ó'Pñ:I|¾6vµœ¦¢;¤Ï'ñ9 ØFõa„†É)²ï\2!:‹–ÁÜ÷­êÞt|=bVÛ–h|Öð µï„G®m*Ú)S6_™ d£»»ÇÕ)ŽlÆW>´Pœ ñm¾.Ú9-² +0ApFsÀË¡™<íû}ÁûÖ×džcq>O„Yç‘ Ò8_fXNÒ¥ƒÂˆ—ô±ú‘ø:¢¬±d5ÒL÷1Õ¢£]ø‘·5xYáì'“i²h¡Ïfé ïÿàÍ5!ÉzÛ+á ~-‹Œ¸íd4*Gš½Ác†®—¦3”]|¹ÿƒkr] ¼e,›èé$Ü>+àôÜ—‰šññ‹‰°RiæÛa5×2MïÜV±1__±Õ‚ UåÏ$S.§ÒYB=" *¥¦´ÿ §5áv`ÿ˜B]N ÿq“LâIƒèýÚ*Èjä+ù®Eæ‚VôÕÅ–®`)W|ñÏ|ȹ¨˜¨¸,ߥŠÜ|‡1çÁ‡cJ霳¡AûÜ)ʘºë>kTÊ&’éY¦sÐïjEAöäÏPfàBÞàe¼‡Ãq¯.Z…›WÂT§­YÇXý¾°8šÝÍ»<«žsç¤ä{¥Éyl'E–/HdyLf€R…®%ˆg7dxèÈKÜØ‚}uË+½ô¦ÅХı t;(•äÇ–0¾˜Ú«äL²Û瞇?<<¦üyŒI‹JÍh…œ)…Xóã _kUŽÙöeÿ}ï<ËB‡C}†€ £kÊÍÀ\ZJÉXü"!¢‘Dîwd&ß§£»Ç/¿;ùqÿˆÓ‡ñ· ¤LnÓ¸n±™&80¥{Äñ/Á=r", eû"ò?¥Q Òrއ€v„NÈ] £·ºŽ«¢5ÎçWTIè+¤„“÷Â%K*B•ÁXù7'[K f)Ñ•kžv”³•¦„kÎ$6ŒY\z©jc>(\ížÿÒÑ1iPç×CÝ"º oý·ÅJ„’ï<éR1=yÅsì/yíW=÷|l§ v@énè'swtAl8£ÌÔvO<7ÐÎÄ~EZLfóìšÓ$·E ª.ÞOíÂZu#ñÊ{f¤Ž©zL€Ù\Æ:n~z‚µ5Y=ÉìRm»D£ çhw5 †gl½^oåW\_°|3Ô‡ò­% u¸H˨‚ª~Ä#ê14´Lö(o?Á÷ª¨¸™t+Q¥ùê(q ]AŸÝJ…NuÝ7ÔQÚúQ2G¶ê‡gîUÁÁ‰2W•ûˆrÙ4þ¾×è(ððÌåJJ•-¼ÐhXW±ý”/—aÛTÑš¿(BâeY¸’߸7¬AÙN=òñbF?ÃNÑŒ†3/Šº± Ä,š¯= Ç+§ö%¸Ü9…Äýk›ØHÓiIÊy“mÄ”ÿ½(Ò…ü¨/g2;ò„œù»­Jˆ¾ß[é4VŠ”RßT84­Nç¹!œè®úGÕ7Ü*Źˆ1Ùç|7bÒss"s{ó8Ýx.™VÜƒŠ„1fK¬TN [PtãD…T_äw¬Ï­•M*‡ÙeŠn„[„ÛäDÓ8±Ž (ë Ëmø+ót›|j®ó-ðz\=íÔ’^ 2’JKa/Iæ@S”"ÔuÕÏ©šƒ4’UJ®ŠÊäËéoØe¶ªß-Áw÷Jœ°µ`;œãS`ÛЗš©$V¤ë@!çlêGe‹In\ÒAÓ>œ?ÇMQ“>+jìTr^‘íw:³f| æû4®èMk~³qÄ<9È=8Í9n4Îø,#SžÈY®#¿‡N½(;—¡¼¢å\ë|Œ4ñ;+î?Ruÿ/ÑÛÿ¿¬¹§±]N‡ƒ%U÷œyNîZWJLN·ØÒß % õ{¿s¸ÞÔI+*Ç·ÍE ‰9]T=±2x*iÌxܦ—fÃhv'X®OkŽ8’8äH}¶%H¡BÛ0&è Så@óÔÌeˆ–[­{Žª€¼‰ú7èk^ýP³ÜÒ¦D)„©¦€vP&v½´Kù„õ9á矫¤`k…‹v‘kh¶H¡*=iÙn+ºBÅ7È®{{UØ4޳º5'šÈùÓ.äò—äÈqž›Æ\þû¦J ŽRªÞ8J†Lí gð*BADqQ[ö4ËÓtÌï,ɧÇšUèG‰ ×IéXþ>ôg¢6j¡ByÀ/078Üæ³|œö(^öLR üÂ9K>Œ1åðû¤¥;bñôj"q$#}Õ⢠æ>¬Ò±Þð™¦ô¬›ºãÂk7\ʼ*ŇŒŽœùõN• QÙhKÁük:|¤— æµ#€Ï%!Æt{&‹—øÜþZv¾&^ˆ°/òwsP`irçç £ãVÀ;xŠ{¡ôˆ÷UŠiÖè˦_VH7½ÏÞ%ˆ×l`ç%—l¢ü%FIf#Ž'>¶<¿˜­ÜäAbs0çø¨æ&ÂÖœõDÌ´FFJff‚ïÀ vÅÓ™fP:ºhG†ÙÖ¬%±6ι¦š¤„ýˆZ„I§†f£";ÇFøb9Í;7»„sä@hXé¤ùÒä§vís×Hï½§§4áÞ_ZêׂXÒ·l9Y$2rQ›”mßðŒÎçÅ«7ð0w©¨ δ}¯æ:ç:yÃ1n»¨Àª³)*øËS~Nê'ñ*¸hQç\Têþ‹{§µ‡Øóó;êÏå~ÂJãØck?‡”Yâj‚ü>îÒ3CÁÜSÔ"h먫"b†~‘"³9EØtÇdz‡½Rh{ôÉC±·¯Gœ1›j¥ëUÜœ3úa8PH>|Œ*?¢›û%ü%þa„sª%Ñ¡2ÖAŸfzNŠÊ$ŽV, öñ@üíq4óþýZ Ë0»£Îú•à`tþ 1€¦¢‘¬®WñuîìÍ0Îõ°ŒÅÒbõûg/¿‰IŒœX<ÊWUœäë”NQ#ÕÛÅ*jqUಸ[=—\|•Ý&ƒæ%“p—>&I®>y„7fc§³R{²Ëç(øÕÙÎîS~x†¯ÄûSœò“çÑûOçX~úý.~ØsNܧeF ¬{ ìh³AMTËs¶‚Ž@Í;‰ÈT¯¥œVŠ8ìé5Ü™— Eس’ÛL>ƒâÎv•N’ø0fn«ÉòÃ)î\tj]¤·õ~ò>ð;=ŸZ&rÖy1ÀÈN;ôTލŠéÄu!÷jhnƒ«c k“€kWκØçØv4‰}0áI^Gî%I(Cµ"‚Ôq‚[”›YÃd¨÷=± Ρ‹zLŅLj«ãQ‘h𠯹CéÅûƒq^‰õ€eH9ö¹âAE4u¨“V…4fÜ1´ÆX¢$ I§9K¨a<ùŠäö”‘&¨]oZ§ÌBê‡F·µi¶6HΧQó‡äl’\ÉïOâ³´'”»Ê]W.’a  9Pï{òÌï#’óI³ÇÕ¥S¯!ÏEðô4¥\üJöÊ%iˆFQcm2¥]Õd™!«ÿ5B@X/EåÚø±«+â®úä¥Ü»6¥ #¹Å!`WyN³ÉµÄ(kÃ\—ô]“Ôø…ÂéñV¹„¼Y·Ê„¶™Õù4ç>°ŠìÏárU!ÞùµpÖõr5ÄB]¿ØI“ã‚r´µvƒÃ§›5h óâÊÖè ·é ö\ÃBFPln3ÓÓŽòÞ$IF¡Õ±²¥ù(4qÌs7µk@¶‹ HÈ`MÈPÒssXÏ“˜$±ËŸÀ³ †þÙ˜£–)¿I˜óIzìÎØ8uôÍ}àôFDlb*E°_~‚)*|Búé/ëõÏàtÑež#>ŠiP‡ß¦9g‰ÇP+ŸÓ]²fÛ¡’ÏÓ0£<ܨ™ äì£$›Éèaû¡“Å8î%žhœsçr#“É…Š@ž¦$Ø¢Ö³–¤$Gf¤‹B{?ìS±J0ÑÕÕU§Ÿ&Q2]Ì×I…†i(Öv˯<ƒ°* ƒ›6]Ò@µŸÎè.Rõ#«Kʧ‹3qÆy*ü!$S6Ç.¦$tL¯²ˆBq‘QãåÞœtVÜDHbï6ÙƒäŒÞùãŽYLÌÂ0‘Dãq®Öê%ævé—'I6SŒwj a õ5¢ÊlpÍÚDA»®/heú+f´à³Ã©¬]<ÅþÄ ÀŠÉé²±+>:A\ a ÍóÄÕ0E¿Ì† ÿE&æ˜â<§n££ æÐR|…tKÇ?e„ma´µ9vìš:ŸNíFãôI8_ý”sŽã†Ã9b¥cb¯x99gtéõ&™RoˆdàB‡¬oHUÁÍÇ™‡Ý®žÏÖõò¼«á"ê‰4¢€È”í+pQXT´023è2­æw²yö·'”=°hûƒH3„:2Kg9Õ*çÒ¦—ô}ÿsÕ¡kŸëWîn’]q¹h.O„çÀåČ¿Þh ŒˆŠ~ÔŽÄÔ=°ÞüiÞEs%ýƼéXªé¿ÕÜ Z¦øª0$n'»Ã!>;è>}ùã‹g/÷Ÿw_½þöÙኬ~ãfŽyö1#S⹚óÁ QEÐ} ¿”Z‰pà8¸•€ÂÇŽŸ²Á®uŸÜ&åô^µz¸iЕ]B, FØ?åA`Ÿ„:Pæ&Ï™·Aâ^C ¤ðy˜Ì Ctx^-ëeççdt˧dðkõÕs± oÝwþ˜èà|‘¹kMcÌoÍN¦ …‡w—rÝâr ®ê)e¢‚3þìäˆqr“ ‚±ù+—œˆ×HÂÔ°žÊŽúIÆ9"ôg»…4x¢G¹Xõô¶Uj0jfpë;å û@kpÈûS«``ÛU;¥îX lƶOGÍÑfƒÑ°së¿k8/¶3_Î^Àpó#¦+ÔJ‹p ÝnB£…·Z¡Ý`qÀ IÚ”³ÄQˆ¥Ó²á²³ô#ò*wrâÖÓß!å-zÇð¢Ü™fã;íb㸓þ@ÔY ‘PE”2â>ï”æG¼ˆÐȉ®d#ÐOò!»ÆB {+èI±s¶‚½¿h+,5“ïõNcÅûãY{WGŽx§pÃàë• P¸u~ýú0±ø¸å9˦Ólø©WÈ0Í_&¦ÂÕ«Tbçþ#©”ñ‰ºo7ý‡õø—97•Eœ½Žx­‚r~p/û;MÌ|NNMås }DOQ"ñÚ?[5_‡Êÿ¸ 6'þ’\c;²™_ŸÉ.v±<Ï%F5ñ=­Üß±VmÌ 8D¸p#C= Œ:TÍ%ËùÞÎTá0‘—•™ÌÃ*Â&ÛXØ®"fŽV±ý[¨BCè)KVí_áëÔ”…Ñâ7¶dY½yï°`J9Mèõ¦¤¥Ëóubx‚¹=§<5$4@Q¨ÑmM(@²mPNà(u~EÓnYšú©ˆdOŽöOÐ_øèàÉÉË£¿úèêÛ  b,xÇŒÅHß"Tå„FóÙv Ã!“JSi)5CëŸ »ùÃL6™§i³†Û’*øc}ƒÔ|míu¢È!XÛI6´Æ×‡ÇØ9U;E“h[î–¶})š{¬ªØÑW슀ÊGŠNõ›Åô®ß‹QFäÙ٦ȶ­AVôiÐ{Ú”@ËùG˜ä.Ú¦I¹ÙXŸMoš§o+o7ß>×þñöËݟ߬Ùjžþ ·Þ~Ùâ×o8¿F£zlâ F+5W~ùÅ)¯_‰eóÇí'NíÆì30ÆfwµM€'Gë°×`¶ÖY štБå³xº–ÇÙdÚÖš¿á¿£ £1P´–ä•GQ„ÝPUÉP(¦“ée–;?à/%ðf-ù0ÆS½.ŸþíÁÛ/ÀTð =¢ùÚËmžxMC’è”(°«á¿! d,Q(Î#¢Óðžn¼¥ë‹x›€¡8…ÊG?ß'ˆù7µwsˆ€’ƒ¿Ÿw^=ÛràTgFµ^õ±½x~H¨·<¬æPÕ–WBa¨°Ï9ñ<Ê=çüéäµÝ©özEµŠuñ̓[Æ£•в{'9OT¤‚ЏSDv¡Ck6`.8,’ƒ© žå ‡@5:õF”'œfމ– wèR}ÇïŒMFßĹג^]"™âí=~ëz(E 8„ÖlÔÆÿmþíçõЉ77u¤ë@Öé¯ÿ‹´au3°ø˜ÝÒÀ€" €-Ó Â{ž9«‰hy6€²½§Ðý;Ú˜¸/–!þë¸ü-u;/}gsìÉÝbâH¨,^¸­(Å '$ôàEt˜¬ç++¼CƯ#7æïiï¾'‰u™pþÆ7B=Hx/phÛµ|’„Û‹ýiB¡ãEÎÙËÑÞ&‘Äåk5¡ÐTQÑîy3æ±^þÊ:úˆ´)¢f)T|è²"=%=¹Ó.ºùò¦83kd“Ÿ–9½'áúR£¨¶Ë-{aÝÊìàîÃõ¾šªèÛ€²kC“L%÷a%™áձׯîêA–óÒÖ 2Ý[µa!Ãdy³Ê|½Œ€üdÈI 3ã±=ÑMŠC0tµ–ÎŒÔhî.‡ánÍÚ¾ÎF(‹PýW}¨j…_T_Û»D;GÈŸ™VŽn& ìAe·ŠôÙ©Çé`]’G!zmC_1.Á“QIèø3uì(ÌÇ<~Lº…ÎïsÖz\dÏ„5ƒW†9{ü`Ýrg…]ZÁžùpÛ!FÙ¡‡ " æ³ŸôèõåœC)Çe3¤ä‰ÖDª$ž¦ÇñyÂb7›Ûæ—â%ÂT8™|ñ|–â]}åûßš•í©âËœ7ü•›¤*¡ð(¤O5 i3]µdß <)Ĝ͊ˆ‰ p(Iª w)ƒ«0Sê:3‡-]*°úÀh¿ ¬œ¥¶÷”evÊd“Ä$ãQ1|áæ”bh$<»ÂxysãæSZ×ñ«\8íDÈDÌl•YŒÑÙdž`ÿ$mÖ¶ À!ê— &ái‚ÔO12ÞàYGù¦­ B+Á²R/%Ë¥ Ú˜îøt{2:ÑŸüù˜^³Ýœ:Öp*Šb¬Çã÷ñ1#Ÿ13t‘Ôq¦D'Ôeþ)¸!Oy–\ÆïÓlâÝ×Ý8 _7WÇLÇbäšp›Ôq;ïÄÙÈè 6‹.E±c¦»¦Gí(II¸ŽÅ³E°BÜý‹Â…!ZÜØØ‚ï¡~âß>=‚™Â ]x³Qš‘ª£êšÌ(5‚Ù~&”R­†m$Vq–@–°»Å f¾øR” Á9¼I4í%ö½g0 ä9÷¯,ìÙyJw®NÝÂÈ¿+žª¢ÖQ}ö—Àa—¬‘'øD¼˜ƒ›¶äúBŸ`\ŽDÀ·1íM‹,¹l Ñ_ë‚¢ÚØ÷ÛØƒ Îû«³q4£×?Búe(°$˜99ÌüZÜ1zF¡/í ªxÐb+Aì³£UvSYÑŠ7•6Åyà}Ú3bd<0…?Öì8 ý^\êï î‘0ŠFØ1ÜÃŽëBAlCuPÉMìðœ!}lùAaÅ®#+>ßEñàaâ=ÞлÑ+êU ó2jÖŽ«Mvá. ·¸ß þ™þN&QÞƒùòÕé‚îzÃ…p’Œ à ÅyNöÄx²«œÛξÅ™'×{Æ ¾B|ÔHOâ1ù§›Y {ä6 A[±&S=Ь“$ ¤3?Ah¦ëG¾iÆòÁ;ö(xÈÚ&>ÐûÎ <îöâ>qnÒm·èL³uÉhúniÔ\;ºÔ V"_Kì>4@’B—¶¤ážKå=ì âP¦,}憶Såä ,¬ZEP^²ÎÎa3b˜S ¢Ð+O †•$=ƒÇ4(¢„• xŸÆí¡Š8!¹@éªki—r3YØ©å”)2"Y$cgªŠ$€e⊗¾ƒLÈ@¡y¨ ®ž_rŒ‚ï â™0s€–ÞÄï6BàäÊ}s;ËH_ÔŸâÅžæ$ uî ç3èÉsbÃhcHU.À‡ÔCf3Ã-ƒ3#YU(@†Ôtæ<¹=˜—ùŒ_töÇʘ³OdêÓÕ r‚v»`lÛ*L1Fš;×6êä\HhÒyÌú.>TϽë„M/'IÀÁâ1¡FåÞH99ñcyPåÜøšŸò¦Z[æ†×p÷ÜÙlË)ш©¶lD ¶¹9ç'˜(‡iïœCM™ƒð3•º‘9ù‰üÄA,’(ë'vKÕ´S‰—¦ÛVNM[œVÙ÷•§ó‘ò>ÌÃcÁA˜Né"`u¾Ï6 Æ?=ÕÙñá0N« ܯ‹€1vÊÆ0Í{ën\¦@cážÕMºAð‹Œ¿µ+×j—jwóôIk7¿VÅýø—¥øóN©ZåÜHOu1©a“æôE¯Ïr{¡"Çì5ÚàŒÉ/O̺òÛ·sV]Þú¨ÂR·Ú•³S5+U³ÑjW hî@Ø üÛ—˜8e.ŸúÛ|„¥•©W]òUe:ÝͯŸ1ÖÙ´«¥M*S­RÙâektKÓçi+°ÙòLÐZsZ-äKU—BÁÖËõÀô3Ìbh] Ö}C_©_¶ÃîŒ2­èrù˜6o 5~,ñ¬»gt1¥né8škÞ,<ªß,š •)ŸöR ϧ\s7¬ÖVÔVœ4ÞJê*y&Xš¢Âc±®cWõÐ(Ö唢ÀH(·V¥êƒ_M¨R³xÍG _ï=jó¥o…iv ѱôÔ`m…!Žc2c|bÁ<1\qÉMµŸæêå}g9逈ûÇtabJÎ’€k‰B¶Y/Ù€_ôÛc~Ä—cŽJC·Õ—¾J,î¢|Æ|Ul:çÑ@>Æ$à€h†b†[¾!: Y¶ –,`ªBlÂß{E™ÐJ™ÇÐø™t¹ óÐN5¹Ç*߸N¾VÁ[…à VfT…]e¢T;ŸcSŸ Ÿü¨UgHeÒÂâž¶xÙ7á=ßhW¼$Ûá žðµ~±?-©û©Ž¨û_Q}—’0 %ï³Dm<”“ <­Ö-ÉEÆN“â²Âùawž6c0~ý$¡.ê(¹Ž1§ï"ÀEx4ñ7ó9 :ö>.öþ/Œ@¯´;Wšª‘\‡ÖZ ÆÆ¤{úÉÓý“}XØ 1êEqŠÖÛ+gÙ~´QX]TÝ]ŠÔ¨A1@p/9b­k¬Þ‰V“áY‚)"%“ÔÊ›ÑÃÛkkëëkkÞ>¥²§ëëð¡8¼Ë'Œ©ÄŸHñ·oQ™[Ö•ØÄ Pe˳ݖG>¤êW1é6@WÆøÞ¬O£r:å{’`Þ.?Ü_ª>Gžù㯠 ¥f­;ÇòQ´ü)nÚʦ—‹¢³dìÇù¨jíøðŒቒÜ.;zÜÀÅ«3P1y‰]ñ1›¢å“^eL §[ÓšX^$”ù€Xï2±æq ߬<ªÞ0aSEP³0¡[®þ¾L‚û„½ØðG ˜…)°Ö HK^Vž:0ïC«~¢Ø8Ѝmjõ£hÃ1–óƒ­¤pU°ÕOkuS¤ÕO.XF®÷b UÈ`Þ¼Qæ.}9œÊ¯©ªÒ©ÿúb1tê½³s?é”*'÷ž8gÛ+‰¹ÅÀH²»åêy%0ÁÏñB%Ä!\R¹ÌáZÿã±³{Di —$¯kB}‰éÙ^˜ø& ˜€ãË §¯åcÃn€ÎÝÏqÄ$Â÷',í¦§“øÂÊnÎÅ„ìf¢d ’*þâl‰äQzA–í8è„„ÀñH‘Û"Êò“05Â.Ñ×fK¢¾ebðþCn°TF”ïÈN¹U\FD€Œv6p¡ehïÆ£t<hˆ›´Ñ¡›RKˆMcŽúéû´ÏÖØÁl8ò^fÙ—fcÊÆ'6X´¦õqòX3ŸqvÙð‡1¯ ~_fm@ ŽìƒmKÅÜ!¢.i8û Š­¶êe:Î  K>!¬JV‡è¤gÌÍs'©¤‚Z¦}›ì0a»âL}Ø9¦…Ý„H2áA™õ.Éîÿzuø=Kß7TnS–Òá” œ×TÚgápx½&hCüÉfwJÛ›‚ ­áŸ‡i-Œ5Ñéi{ü9Nê㹩„'Vf÷‚ØË3v@;Z¹€‹| ³´Â“Óì‚‚™;¾G1ÂÁÍÄíþRíá ââ]À•yÈ œû7ç ­Q ÔéÄâé±ûOúNšiÕ$´ +ƒƒ;…‰îêfo ¶5L»…¹b>›—¹gÖH?]ãò+U+r€\,²Êxfç‘ÍYPPy)0t_ÏñŠÃÌbÉŒÏO+qJ+ ÛR}B§ÓáCÛìÔ¢P+Õ@ÞˆUÇð^¬‡2FÚ‡®/ zÙªà¨Åœ¢E28zc îUÀž®2›ÝNÖ‘Ô¢4)ØØÚ ‰ÏÕ9Í=œdÙ´!þoLB õ UlÜ’¼ËNKGˆ{å|ØK•óTCm(<Óôƒ˜[ðY熤'¶†³DÃØ€;ú”]é!x"Œlîê„ËûJLØÉˆÅTN]IQ*k(Ñ ¦hãà/èU!òvyË6*—”Îì0›(TØŒÚñ„ù/1XI¢äŠ“”0DMÉ™)Ä3:d½wˆ{@žDâÁi)‰OZç¨chR´Õ|vF ð¬cuþðXªåüs}ÎæLé÷Ž¡'Q üDO2'#œˆÀgðº}Ou™Rzw¹¢mdgŒûF,æ„òj9 Zô eVGi`äƒ5ɨ±†{[¯{Wp>ë2×ÃÕ³”îºkë6j‡„°-°m8nç+{ÁýÍ3ã}^iZàÏ‚¯kÞå Yœet¯{£šés`×M{Ç#%‡Õ$›ª±VÝK€wn È̽OsÔ¬ÓÕ ‡b†§AóWIBu#‹@Ìžs)”J[hep-ìÊÌ‘]ÓÍ”~BóüjWëåòböØO ¡Ç~ú5Èc?}4ðØ«qÇÄq¾•“md%gWs¾G‚ÂÏ9+4°"Œ¬òu£n‚Fó«¦A·JØ BÇÑ?pˆaEp,³r\â¤u¶£9sºÇɆª?^YýÇ%«ú5qÕ?ýú°êÈ1æ˜éªræC¨³Z¹*Ãl†O²\¢è“H¹bwOTÁ<ŒÃ †g«Ãh ¬ &^‰Ì2 ŸƒÔœ40˜ÀU2¡¯>æ¶©³Ì^€Ø·kžõ³ʽ<0¥­‰nû©x>>¥Dò¸™fåÍd¥.@øß‡øŸGøŸ/VZ!šlùGöÊRŒ½Ñ?l÷äß„ÿݺ׸¹¢~?Vù2Éuº1ë½&5å„OÿÇã—/PGÞ`ã’u:+J©Aàf_ Ÿ‘Rwl,¬o4š Ï€.QÒrJÓÊ‚l­6Cõª“M°®õ1ÈÚ.à¾Cœ¦fÇMŒOœ»è©Ž¡œÜAÙ?ÿYðsz¶··‘]¶¹Ñ¦ÜUÙ¹¼Y‹6Ä.Î$8[v,%Ø®t1"®§pL*€ý;šá­ä°üm­Š\IÞÈ/ãkO%Û];:)¾\ÒÛgn¾üò´qn°ŽÙüÄí¹c/üÝaï+f®†cFÅ;’‹Ñ•Rå°@(ãrÎBÎn/ðeÉ}bÍN2AÀtJp®¨_aÄ2i¬vò|wã®x^3 ¥Ñ”4>ßú®!öÛaÖ‡Û”SØÏFÜt}¾&ÅCÌ늠@m¼d.5s¬ôާTîܘv6ñà2µua'Ä%`‰%¬Ø0öÐ)êì9(ò6ÉU›¤Gu™bFB¹ ÜãÈrÑÑbc fh×^K&eã„Ó@fì^['K=Ôëë A„ ¨œmsyS&4(:ìIÉ$‡(P“7‚ØÈÊ'ÜŸúÒÇœ\±çXXÁ e~ˆÖ·Ë|ÿÙÆ`óÙùpËïè‡;ò)þöÝ‚Ï'ñUq0U9æ+z¬}Å–ç×â‰È§è£(® 0Õ°m¹ðôVMJ„§?{‡€{ 0ଔ#Ý×5?xH !7Óô‹u®Óc@ÂU“ïÌ70–ÒáÐr6Jÿžö›Ãi£>9MNÚ‹^ó…J/•­bS% ^xfÅ™ïu¾bž1Ÿ8z•”´íÀ2Bð99º‹£qaþ«>÷ o™gå¯À·°‰‚Zæs[½T¢Éu’âB”fÀžç)­Ù?~v_¥tÓ>»…r­ ¶@æû³ ­øÔ“DÕùíȵ³Nã9BØÓ_9«ÞRð.wãQ6ººÄº¢ÝÆÝEÖ6ÌØÃKÔCÎ}GcÌ+ôUX•äO¹âóD åéȼë°wTe¿EgWÖOÌ œÆ›ò²Ÿ%Üó9,ï'j]w”tÐì¬v±3ª…æ-§yO±³¯šÍâWèb…ÖÍ`°{¤äÁHšÄ‹öâDA+ÔM¨eNÚHJa$ó/ÏŸ­½z¢aIͼUÜ„@|ýŽRtx «­£ÖŒúã,ee‘ÿÉg¯,vñ†èK´þa8˜Œ{Î&Á­v:R ²EØ_韫 ÏÃ0™^f}VÚ¸ÜØ~vÑvr1´KŽJå¯M3»TÚÊ£&§†ìД$Z®}«&×ú ø2òWôO¤c’#;ž"¼¡C&N­QG8wX,.ÎEpÖæÍ›ØéKgF³sqÛ(VÍõ‹,Ë ­£U€D#¦.‡Ò&f‹—²›L&£LXdÿ(›t‡ù…Ã⪜ñÊé$9FËÔò_|Æ%ð,‘ñä.Ê8r=Ó™“‘±o ç…½ñ[ xTPë:Óú’àŒ¡!ü²‰g†éˆ]òðjtÖ5LYw=üÍá°°°„mŒ‘ZxCáßÁÕTÍÕåz,á|ÞËØõY6ö*w1ƲYÈÝL3â$9ù;d'•M—ÐÑÍ‹FGFE7¸¹ÅÐÉgrs14NÞ\нö³Éô梤¿±pXÏ~cÁtˆÈ7·Šæ×› {íæR‚ié r®BÚ¸"Óöfù4F¼µÙÓ™d~öù4ÊCwO Øz FhÁ¤uÈÎ?œœ¼íÈòºÌ´Q¡E –ž‚Ø›ªÛõƒ¼éàÞ¼w´l:jêW¯G} B½€­ü÷ÊÓdøÐ½€CJ]I¾E¬¸ô‚‡o%'¡×bî ÷ &À9csÄ_â,A­[„›3â{"@9’æ”3"Æ3€ÊîœG¡Œ¡Y¿ a€O¯Œ x*à*hd öÙk9 DÞò©ä€§þ(#Å”£çôQ]ü#¥¸`‘¯õ.á¯XQ!Ù¹ù ¤þAzF€¿#úª)üNÁ(™ÂAÍâÁz2ZŸ$ç,Œ³Ã×Ç+òí¹kË×¢YÜ…ð'«B±Ž‹°LI*ñÈF{µÜ>¸È&pÉ ó]%k}’sôê°*½3~ÂB× Ž“Ž—¼‹WÇô˜ˆ£L@Gβé¥t|ØÑ½œq6¨5õêtFß73bpæÙŸ¸éÅBUñ-õ×Ä÷â8HØci[•SŽÃ3áî¸ÜrpÃ+^à©¶ö7ËæJ”.ºö{3­an‘Õíýùàè´qtð?¯ŽOºÏN~xùÁa×~pBi8©­ ×ÙâŒ-—v]üx!ãÐ)´ÇŸ3R¨ å>ù0Ä#uڋ䪘¶ì,´«Zà& æJð²2†Ú5G ‰•@ºñ­‚õØS‰ÜGÕ]öTn£Sƒ[Œ€cÜVôµÐ,è—˜œ(Å/~䇵ÉàqgtÉ4H@ ©»ÑMˆs½áo4qÉç×m&W¯¬…NŽæúº}÷òHÜ÷ÿçðU¥‘††œ˜ØWš*ôfÃMße£úæëŒæö{‹5Y@ð¬!.*V8HÎI†ÅAœrGùR—ZV{; Ä .!WxëŒÏGFgAá´ô¦ë²ýÐAO.îl’¢vG¶¸4n8ØdOöŸüpÐ=9xþêåÑþÑ_ÛVÇÁ‡9wØfaø°Ñy æÞ<ÜH¢¿%^¯ Y(<noØ$v¢ò–×Õ6|¨· õ6µ‚Ä“¿xƒ ݸ¡a<ÀÎLÝéêõ–PÉ9¢8)H7£”VÐ éî’:¹¹uwû* JF2Ì$q[g| +z‹\§ä’îŽFá^;àÏ9»wÚ |* !k¶æGÑö½ ¿ÍbQ†úãð-•98Wi}zINìÑ%µ*Бé½Tvçb˜ 3Á¨ÅDúâôtï^¡ÿe?»à’gÄGt‚°—rx‘O)„HM>õÞu¼ƒD;úqÿäÉO_~ß=8:zy¤ù7$oG5”Üü÷“Aiþ ÈY!®žü^˜`C€a„ö=vÚŸ3ôý)†(÷$YÃÓ@}cv}û”^H½ÕcýqÿèÅá‹ïçc±Ñè/0N|ôz6Eg¯á‹_wõuWO–cÚiRÈ07Lršg V1©¡b¸´¥ÐÀ×s8…¹š¯/=ŽxO¢òàYê¶.IDzŽV¦Öî<>”f<ȦFŸkÁ^Ìë-†ºÛŽ.ØÂ´v€‡zÒÊEzñòäðÉAйûñ¦Ýè« (dži<‚3?£û±¨’f»,ö4¤¢‘ü½#ªa×u»!ÊÔgÙ sœ©ÌnñÄÕ¢õð4Êt$f #T5ITʶ`]’˜G‘“ƒ1r,{û"=AòŸQóMGë,[¥÷AlôO"Üq² Ò9®K4Åm9•OÛŽ†\TVžN“µ«TÂRjX“\½äˆ­K¨<œ˜5,Ÿ â·ôbЬ¾O²‚[«Xi±eM•é_b]Ü:׈Ì5þæ«í„yç}Þ%×&¡ í.Ò¢k±!Þ@ü›ó×DŒk¢ÏäÌ:qE$Žƒût ¾ßÎñ–’À¥(‚¥ÿ@» "Cä°™ˆM…DŒ58„:è”Mé1’õ6npÉ÷ ¹€‘$žPe$ÁÉÝ2š¥Y0Ém–òÜÐX•ÊÏ:£¢í)”‡qþÎ[…à’˜áPAÄQ±Õ¡1jÛ(´kÎÕä³3?ŽêpIÖyŽ~öWt\‹ õå ±ÁÃla¤—L—n"ŸŸyÎ. : ;Èw·“¬·xdd•ž aÐ0…wåÅ=¾¹Jz„3e¶ßùDı™3ø–­Ãû7x¿ëñÐWc¦+Ý'³iÒ²¶ÍÚ´ÕÜÀå „­:TÀ†’¸œuÒ%sª(ƒ¿8ÔAÑDq(K!©•¨uû3R½¹$¨+BÇAD¸ƒ±f !Ã×7-ø K?Ƚ¦‘k,mÆÛ™jIú|·d“[ƒFÁ5êPáîDû¬…ã›/ +Ñ\rªóäÍML7uÑÆÙæ¥;…7Ë$RÜÉŽ\yˆÒ bÇBBžÐØ"bï§Ã¿(©Û›ùuŒECæ¨+ïŒOŒT«álõ«|²`Ÿ8G@I; „ŠyK’o‘MTN¦¿7îÑÞeW™£´K.„ ÿ=úz»hcxbz5 uô84Úú¶5H„=‚UQþ’(…l²!»çg“‹xDdžì|ý4çÀYŠ3–4®Z׺`±”Øʼn…‚]ù€ÍêC!÷*ö âXðëé¥Iœ²gÐ (FvF7+#D<ìg¨›xÜ:·Ê‰1Wt¶Öu¬ûi]ñ›'\‡Å_9±·Ô˜‰¥š¨(kåéï1Ÿ#Eað%ãšê·-:¨Â¿€˜Û®ŒMèTª<~ÜŽ„`Îõìßhk QK=[^ ~/ÔÏ”$5FÎQ¼²2§LxÙ9¦ú›ÌzènçÈ›€É2 D?¸Úï€ÐCÙ-4¹Š$‘Ä-›óé_kWÌk0/‡`&ÇÊ’ æCÈjQ‘dñà”Ð4ó s‰H.U_Ew¾? ¿LÏaÀ…/–+°h.Êåí®z<—"ŒigÔið`„޽ÊÅüõ®TwO_áÈ4†k`T…£Ëª?™«n¿Øûú(Aô0ûg}K\qû Ü…SÞø¼À)«9sÖÐ`3d¥àmu!F HM‘ ¹•B™‚g„`áx$t6vI÷ü¸P{Nª oÂ!ÊH×1Ææ7KþyI­­òÎ-à¹ð=“qbœµ¤ÂŒU ü–FZ}ƒr8ŽÚ ã-‡Ò¿AÇÂCëi,-fÕ©|SpnÇÀ—Bl¾Ñïhò;Þ¡P. ƒKf IÕv±9ãŒo`/m8Ó)i%ïr Øo5^\Ä„š·%›‚ùÏ ±ý)ÌΊ"¬uñïÊâÆNíÐ-¾ „-V0Ë"¥¢ ).ÎAȺN’¸µ°¡ÃmÞÝdD5bÝÏú¡¦€Q ¹î…Ó‹X¸’ÛÒÈTQúµÓ$‡Ì²ê »‹îCÚ›OÙŠf·xÑcNI"Và2ˆõ.Zí}± ¤ÎMûž¯Èìø*Ëë-×í²ax YŠœLÈO¼obÄ(–?! ùòž3ËÅ~ÆÑg Œ´`;3T¨™µYŒ|™v´¢_¬x=„Ýs"…}6M§’°ƒA=ð0pð˜@PÔÚƒùÒaXÎÇmª=œ®>*Í6YIR"ÞÜ×´iñ*ÜaG}½OH¹?TR¨SÅÉ%øŒ/i¼­:…"ΓDËi†å1:µDÖPRãó¿0š=ýÊÀõrcˆ‚ݦÚÊ)¾yëqD\/é9ቄ¢]Glý>Vš{en‡H+ßKv¦+ÑásÔ€¿RœõÙd—Ñeª>attQ*¶³öª®n?å¹{ëœý¬LY)Yc'Pw,vݱ7ì2µ˜o‰éDO”Ô88nŽŠFîAKãn*SCøÊÓüU¤ßPÄçP¶ÁÐŒ&_£ŠksþyíšÖ#¡«>¦ƒ»ÕÀ•EØêóÔé·æÞ+ã,Ÿ–y–y\‹-<‡mùÆ%Ø †s‘‡ååµÓU—Ÿ§’)cRXØMúœ’qÈîq9{*8¥¨…jô¹©FÕ¹>Ë‹;ÿÚDÑàÿ 43Q:0ÿC^~øoQ˜¢ÈdÇUY‰ÈrI O£bAâã®àïY-P Ša@ šÜ¢‘Ú'0Ä ’ÜÏ*k:³5•j:«¨‰Ö|¿ö|ÕYk£"j¾zh?z­mB囎º¹LÅz‹ú94´“É´R«Ó§¯›ž–›èÔÓ vþ¬Æ©NµZQÇVÈþÒ@'zåKž%hæFk?T¹¸G)¸ȳ _¬Gá3ß4Ð&ü{ËmZD*Ž2D+«ž0ºæôÞ•§Jïž1¾IeönWÎÁÁTÏ¡5ë­C,´$,±SNŽ#mõ_§µ%5—…ÿͳJ5†SúJ€ž™ágº‰ZUÓbo’åy„ñ4 Á¨²áH+ßžåÞ6õ–pñOô A*ïKI+çen¸˜>›L//.QQ ´'góe«Q ŽÈòËìªKð> µ>"„ÓER‘º¡ÊœØ€ýƒn¡‰ÙºQOÜ“ÿÍ]4ýY«è®äÑü=×%mÊõC[…*§qþŽ‘€(Ÿmƒ¿hgøÓ>Ö¬èÚæ`j²:ÝýYè|q‘L¿jÞ^À¬qýÞd6<[¶K…/*¦Ï—¬­¸Ì³3Œ_ûuKRÚ’gƒ¥çY’ìšyCFüÆÕnQDA—TÑ.§E’ˆn/ ~ݹ Ò.ù€Üš-MÁóéõ`îù:Ë>,}5jdˆ³0xº×˜G±ÝBOÌ.½]a3¦r#Tªx;L–n…¤MüûùþÑŸº/~,žhu›ûxâç·QiZ]«Ù`Îñ.ô£!ºxøºx0–í BöÌ©ðÃpÐM{²¿­ªó$éÿêºJÓS5ð_;æråAݽA†î0ËÖL»ÿÞ(ž0Ï>,Q9@ãEk$ù`.Y›ÀöÍ© ¸æ ôÔížÅK`³{…3/wó¼VLš‚¥)–Þ[›a]˜‹—.\ßó¡Ëó³ñEñzˆçÍ ÏÃób¶)ÝÑíwŹÄ>tÉ)æWqÖA7äÁoèˆêNÿe}!·°÷1Ÿ¦ÍëÜHûOë…ôü¬ÞÇP´b?(x”\ÍëŠ+VÕ›¹ìNõ9ÊŒxÉw ì¿;ŒG±Ý©}é“O>€Õ„DU¹0_€ÜÃËO~0÷NÁQÕ°ô hÙy•¹Ö–älí:]ƹSO„DW¸åF£ªIZ‰. g¿¶a#–q,ÕÂV–%4ÕKª€$" ˼l¿‹{»È~Pj’äSU7‰ûiö)ëZšBßPºw]e“~—¤'Kï·ªí+/ýÛ«ú˜SpCUµø’Ë’Õ-¯^¸¡B”fÓOµå€O—gnZÔAt?i•&sÆo¯Œ@ç>U]p3ÒñÿT¤$ûdÇ »O’øU'¶ÐOKI>^^³Ätm™_Q%Ülì½PÕF ¯ÿ&qœèÃ0ŽÇ)=ý'éã­Å‚¨LDHIä¶Ê& Ix,i {ïÀø%nZ¥:òX‘àK²-³>rˆ8™†){8Å&ŠG+;B;ÇXEà ÕÑ·2W ÷¶´Ai’j[`2ȵmG,PC’©ÜñRÒ‘§7N’/ÓŽ”Ü@±à”BôÕŸP÷€!MÞÛ<’ª…•딜P>«“t"ÄÉTð9éG©f|‚ø=Û¯¤" Ä8TèeiGEÖÎF H¤ý Î<²'Ø+ #B[Pß;ù`íî"‹;ýk¦/¦{RÅÈù…•a±øH^Lev–zQð˺Šç - ºqH8 ¶"e$qZñÏo7a.ß4BÛ ášR­'Rƒw1Ðà‰ ׊“iF"ГËa€>ãâ¶ÖÍö:O 8î wÝu6#<Æ´—âÖåÈ?ô¤œ¤êA¨*;{¦^osu:%Œ Hå¬ãÚÂqƒô"³Áy…(!Ýà9¥º¬<Ššržù—¾Æ†æÁQè–“C ÞL2w1ëX»Hbd4=…òÜn´…yHG¥ÑQj’tª©8·„M1‘ÿšèA&¦˜|B%†<¨ÚÅ‘ ÀÔª‘ÕEK\æ˜ç9‘ƤzjOˆ U3Ÿ‚Ä1D8 4;覣éªê Äo“ÂæPCè|RêéÑEíþkd87 N&«ÍÕ„¹E²V±Ñ_ÌU-TÌ‘)¬r°Pµ¾w}Kó²f¿5WqÉ]¢¹r3sÜ š‘* Ð:\Âw\¾Ø‹šòFIÜŸd¦n÷>옿”VaGп²mö; w ýj?*àø¾÷aý(¨©€Ë6`Šã¨ÝN!@4bbá;ÇÓANÜ© D‡Ó–¸0sú›2›õw’%‹À›hmã¸åH0ÑK)œr{âžpè2ÆÚNT½ç¯àø{Ùl4-í´ˆb:š9ÆK»‚Ç‹§!÷ˆf :æ]˜²È¥0Ýcê—8B=£zó#þHØ-#šðX1` Ãz"Aà0…‹c9™`Jâ´øäÚèRL0Ð~˜¨Æ¢átaK̳eryW3Ãý4§Ã‹ÆËÒ§›8Ü}t3t¢×#Éi¢®.<¾0£ÅqK[[Ô„.) ¿ÙÃÂ[_úƒ×5œÂ «×ÐŒ˜ë­pp,9öe§èšá¤zó™!a\€g ]g߆ÈÜ{n?ìåMÀæKWûœ¹-a‹¸Y}(K±îTÁèT?WråðÅñÁÑItøâäeôÏ•Žj:+¿DÍ•RÎožkÌùÝŠþ¼ÿìõÁqÔ,g·óNe5úW¨ÿž¿ò«hq8Š9L|Êt¬ÀËÓ)¡ïƒ%â;{Ø»2.„{+çºÓÀÆ;…ý-†çÛwKnMÅ%0‚ňՑ*[0Î/LkåF,’lF,0[sц£Œ®¦w~…™*.îñÁ‰–ùñ‡ƒ£ƒÈ.v´ÿâ)­¤A«z …G³W¹$±—†Ì*{nU³mzè6É­Aô(È™^ öÏô)¢,Ø£>ßD1ÓQÉí®ç ‰¯Š”C÷°.·™8P;ÿ†ûÖMM‰»a•³ä")KY²¶¦†(y=ß }R)ç³ BÖ&ür¢SÉÜJï#Ï ë Ÿj’?ã…óKt0"?•’?ÎJ'ðÅy…¹Üì «H±ˆ,wìR+G ‚¨K8:>|ùbÎáRí”æáðÚ7ÎÁbB*Ó‰ö)•`ndL’ŸaÔ•hjh ¡®†“¤‰VC…~[Jíaœ„°ÂXp‹®‚·-¬¹ÿ¦h;RPDà%Ý}$ÿó(«<ž$Ý!€sæ"ªõ›¿½ÉïDó>C¥ –ù„¤¥(uq‚¹¸ÏîˆWµÑl>Þæâôo{Þœ¾yûöçêÆþ”pÒBYFÙWÔYQò÷&F€¦(E¢¸œÐéáÝ1`;%Ó\£yßœžþÚºóæmU[³lx"±×´AÎâ‚,¸œyyª­õåcï„ÙÚ[4c4ë"ÂÄ>Á-:eË– H:wWž?à–ü¤5Wà÷Ó¿­¼ý¹ùøáÞøi­´î¬´~–Ÿf38»k”6¶/ÊË¶æ Œ]¢‚(ðr Ž}ŒYN9Ëì:=L4`óMƒÚzÓ0½i´îÀÿ~ÆÍ@àxŸ¦)heòfôöÎãVå<¾ÈFa;¼0ù«sgŸ÷k6Ö튡‚˜Ð½r·Â¥–*¶ë7Ñè$Qá*D@utð}ÄŠîË£§GèœR’ýHñ÷€Ë÷Éú©rj;8¤ p˜7”/"çÁ‡ õ@ßt¿m¹ß¶Å‰.Ý@À’Šºvúå—«)CQñßð— 2Ò#÷rú9–%l÷"w¥‘’k›0%Ŷl1~´m½y™çÛ•ù?íúìEDÀàbO§ÍÆú›·ßœ®ÃÐ'Ðà°É¹o>Mä*ÉTjogc*äÀVáL²_ïBT}_ÄÇTÙ<âXKu«¬DâœC¨? ]ƒ¤µàT¦ Ò®P1Å6D”^¯(ÞÚ²ïÊÚ¶5;ö«’§1£ª÷áæ XZ£žÐtϼª$NèCßi¡ªfYŽ{S$—"ßøùåÅ-N°®yõüþ®ü)•~ë´ÞèðÂ52eà6¨Ì ±o0Ld/ÇÄhÀÀ/V2ÌÎ84AæbÍ.òú´«uu¹®¹pM>9åóƒ£ïñÉÞ£NJB^ä£ÞµFzº‚ûÏP3æ Æ OK…žž>Ù&…z˜ž¬‡*ÙB9J‰iZÅÔœ¥B’ðN ]Åä%JÅ8›¡« îâ´—”J¾øîeä[Äe*•yzðík3ýäl&͵‚,)H3İaÂÞH²»ø"g gcfª`ú®¡‹åQµr‘;³•d¿€"qÑ{•²šD€hl<›îÞ.Ìç¶‚)"ÐÉ*‘ z+ð o•,°²]µ³Îä]Ïϳ 8´¤¬J“pF>‡Kýo?·ßDwZÈLßÝÙ(ýû,q7ãé¦( Wm©¢W¨©‡=C/Œ!ç/rš&†V#Ž0‡UÔ$—Á!Iö©I0»;j\à0a8¸„Ö 1iœ úç/ U¶ÓTòa$Ò V²+rr>Éc)GÝqÈßÎB$zYæ)J…¬ØÃQ¢ð„Wt¾;IHsÚl¬¬àíŽÿ¡µpÏ×ÿ¶ÒìÜi­¬âØxƒÜÍ”^D#±ÒÛ{°KŒ5ç•U«ðÛЇe,Å;Êé0¯9Æ^^á—?¬>«œ;Ü0¥­P½ Pû³Ž”YKRÄ":Çm ~”½†³Æ¡z¡ç@´©!TíÃ]r[ózã=¾^±¯Ã)ÅC¶Ò îǬ-ÝŠ.MÔ'¡ÛÎA°(Ƶ¹`{°Ÿ‡ßa²nr’¨0 Õ$:Ï&& «çüã]Ì—¸ø'£™¼'a9˜&lÕªØíO:ç¹<**¤!QwÄQS·NXÃ…î*Õ;‡²SUûD¯OÈ– ik¼ùP»õò|ý§ÜG™%¨]êaÏ)´Nú(-înÐ|Ýý)\±£ô†úÀû3x÷“yå”áêaMÆ\¶žtÆ—c¢&äF„â¥:0\*¨cj”a¬ã •|H$hš«»I>£XGˆ(™7Ó—Õù(OÖx¾øâäàÅþ‹'Ýç/Ÿ4È2\|J|wÏqWšæ‘Qà±KMç„oŒsKùy“&edWÉÑ'\)ÀO(c]ás˜—§dG eÐ6œ¿h ¦dMÁ‰ˆFGQ/Ê,ònóN’ú¼œ0`5l^ªJ³‹ Šl]šnɘuÆ+F|fì@÷W{œi]5ú¬á²Ü ˜þÉX þoÂSä;”ˆ[yX‘{Zö-ÌG½(РÆR¤¿åLUÞi¨ã5g+%þ!ŒM¾3jœz¤>ö)w4\Á¦Ùñ¤cŽ¿sH¹Ä•樫ã)¦æäÂl«?)ÜŠ?²)a„]?º½b §oyïú¹òŸõ€ê\\¦?½ GÙøï0_³÷W®ÿ±ÿí“§ß}ÿÃáÿôìù‹—¯þçèøäõŸüË_ÿÏÆæÖöÝ{÷¿úšîINUïîè°Õv¡_Ws¹ã¾‹§Ãiw·Xs£—öÑ{ýÛ‘Í–sÌ/¤o¯œÀBcHuÅnCƒ›_·èêþÃGþð¢ß[WÎu]B:ã‹üï„ÀùØË?¸î÷îÞ¥7în†ÿnlnonÜÿüoãþæÝû÷ÿ°±yçÞÝ?D¿½é›fh犢?\]]­áå2¯ÜMïÿK>Jp s öw£Òâ·ßG›{@Ö6î¯on¬omE›;»[[»Û_ÃÕ‹H¹Ñê-¬àU–Oá~Do}gÎsñ4šv± çm>Crõ>Nä3zÚ“f/u:Ž!å¢ÞvQ¥_‡"îc|Fb:UcŒkŽc.„4Öwócz&$ĉi—zÙ\ªM#ÜiR‚UÂE/JA2UÜa aÍêËì´³çq‚Ɉ¹µa€³æä5ú¼6¡[¨%3üNýþ&Ah’8 «”ðåÖD€¨à6£þ™Î"ÛcE1m¼Ô ‚S‚‘,¤ãp¢1Ø{ Aé>5~¨dµX/:a/¬W±eªê–çÕ} 3¿°n,PU¯|8¿ÏÓË…õöÏP(ÅšåB(wœj€[a~#°QO ¨œþкêœ`ªS]e 2]åu%šêð›¶eŸûÊ”¿á  =³fæ´Rt§9á&™¼Çœ&æ0c0¤¢þLšØ>§ÃÓy8FLñ@Ï/ÔП§¶4âãÂh \š¿ìÒ“¦ÔsÓ-dN À¨DÔAvœÌF7FŠ@:SØŸ³?ó':¥\3&i§Ìî|^Šêæ«i7í@êÄ{?2• cþŸ< ´t@ÔùÔÞ3˃ˆÊZO=¤l<ÃQ~Á ö¼ŠõÆžsN¼ãõæ¿ù„ˆ;n,†zQvÔq!}êLû&ø@+œs”h;•N“}œhPî0ýæÍ ?/~(Xm^ÅF‰­`gépÅÅ;»j±ÑEÝÜ£­ï:«{»[çß°Ê<ô߿ȼpåE~öòÉŸÂ%þöàûÃèEå:¾ˆŽØ?:ˆŽ^þüåɳ×LJ>ˆHÿüo]xTËþ†µÆÏy©ùãÿڥƕ«8Í/ð¹zwsÚÇ$½kRcÕ›Î=‰Gy,9±FäÁë‡òI/Ÿ??<ù¤‹þÇ|ô×›+øbÅymËkþ.ø"çgÑwG/ŸWïÓjöBœQ2«p¿ri©¶ÿ'È6¯VÅʽ|UXWx2_dùw-ë½7í:ÒÊ~ÄJBãO|Fÿ= Ëã—Q§waœ9jjYžØE¢–¥4·ûË¿[]ÿüÊŸ’ý‡Qy?‰ÝGn°ÿìÜ¿»öŸ»÷ïmÜ¿w÷Þ66ïmìܯí?¿ÇOhÿq‹OvŸÍûhøùj}cs}ëëhsswûÞîÆ½è";‹ÝÇb#²?ŽÃÄc¬MN)†¹Þè)¾( ÍB»”|{t’3E£SMîã»ÙïˆÌÚ”Z(ÎQHÆÛ»/9¬“»ØçºÕÓKû>‡3çæÜ©x,vÔ"€;¾$^=÷¦’h›kIGèÏÐ+LÒíP‰Sðá€G~HYUB·òÙ‡ pmU@äÉkPð¤¾.°®ƒhõc†#žœ‘Ï \^¢"õÚ2Š*d(¾‡é(Î_<¤çÀÿ`è”ú gAÙyÀ¿ƒ¡mø›ß~ôÅ…_VÖ¢mREÑýÿVÁ8ú%¹€´iQ:&ýäõÁa¦*Ü´0 d0ígWd̺Lâ÷׌§ž§Ó™ƒ†ŒJ¶üŠñ0Ï}ÁúyÙ o¼Ø˜“ÑpïË‚Ð9ò<ù0ÆÎÛ{Ñç}Š<—ñÁJ;z²ÿ䇃£çû/^œ´ƒ%0Ø4Ü å>Ç`’.Ÿy¾Âú¹ˆ#W$¸¶qöȼ-í¶íaßë©fŸç•6¼–[m±MQK¾ºèús”“r6á!~`Ò@—¥ö"Õ'ŽWB0¦zð¡‰ì\{$“»·WœW œ¸q#ZÜ4?>žu¶­¡;×Y8z 0°ýð“¢É•òW]£ÍQÏs{óĵ‘^¥}çmVCë$ùÁ5õ Zäš|– ÿ»>³ê׆1 ¿ª§wuQãP’¸ 4¨[j!ÿFè\ÝñjãS?OHmßÈÃʰü¤cˆ¼?þ9kÒ§Šé’ˆ B*! ׄUw1˜oGÚÞ—i há°žµGÜà#·R2»ˆêÓo[Í,ˈP°Ç쌱výôÎr‰=ƒAL;®.›žÞ/uKåã7ã2Ûñã7¤ï¡Ýš:¿(80oX¯cºg厭æ<\`zùáNbX4ó8GÁP¥AþcÄNÜ’Lt}Kn"q¿oQ”À'µionBLìv.!ÐX%Qpµlt=Ìf„RÊ®ÅΡÜÈej‰ÏÏaz|Sãb*±ôPšŽ×˜“¼c4>ÐA¡›Änìò”æŽ0RKcŒÙ¶ˆúÔ ×Úâ@…‹quðß8¼9¬AŠ;v6R+,Nšõ…Sn ‹ŸÆ¦èsCíM8òÝ7 -~S™ötøÐ>NÆÔºI”Žf=œéËø=Ñ ˆrKGLYœ‹Èž+@ÂZ” SÄÃ×bÎÑCóÄ1³)x\ü᪘¹˜M©4{¸bÛ² „’>„ÅAv˜ÓÀ0/˜1Ê>ê2ÒsBxœºM‰#JhðGiœKX¼kÍb×¼x ÄÖ• ôÈØÙOówб?W²ÒØÏɵô ¸§„¨…´#ϯÿçY#hzã¯á»éL7sKú]PÎÝ,mØ—4öù™“|ð¯¾J=ò‡)J6(DâY•ì#3êä©U•£Vde#’󎃾ë½ßÅ0¯ ÿÆkJ-kA¤Ó¸XöÎ×ÑqBpäø?yÒo‰H÷у+†ƒHìlª<]!ÇÊ+Ïàòhš=„Zå\fa(‰Lñ6‘5&®tgA'0+†¯ï.gBêØÌg.|Îõ‡H0Ž·_˜ÆŠ¤¿î[57‡m·xƒˆù G׉ž#¬-Fðw:E¸pÄõ&ÓbK0Sý^< ‰U£–ŸÕ§rbÂ8&7TÖ Pt®²20ÞGÄrJ áÌ]P!®N/.§äæÄUÐ+ZëÆaz‰ÁF´ÇJã×5N(±˜¢x§¬òi”4|…¬|: QûQRY4<‘Z™Þ à )¢Œành{ñ† ˆŠ$e—ö;ŽD?c­FŸE“Ïò^qd’QÒ‰ q\XÒÇ‹©Œ˜‰Õ“46zð#40˜Ãä`‘¢äN¾ÜyÍNJ§ëÑWæ8±ø½ÜE$W©âìševâm1ßÍÔúÈד§C…‘•{\îäÿQY–”4×´,Ïb Bq•q˜ðΪáoÐ/¥ïÿʃ¼ü)ùx_í¿ûèýGü”è?Aht†1a цùÍwÀbú¿uos{›üîmìÜ»·½õ‡­í{;5ýÿ=~Bú_¹øì ´á}îF_ïÞÝÚÝÙ¨º¾Á 9±µ ‘bQ®-_¥U9:^2ÍQÈUàC»)ã&F’«"oKpEîSÀ(‘X‘0)Æù9a‹£.¡ÜPd­ˆÇãi„ô+wÅ t7*EŸ?OG£d0HIƒ|èS¯É èâÜ9j‹Ìäž@Cót·1„‘ G­8¤k˜ÿFð¾b&‹mVßu1Ò0V‡™çÆŠ ƒF؃žB°Kfâyu«Q?Jm6Cµ=kË¿]ÊœpKÝVk(wieHG²ÔlȽ ¡+n-ÊQg1égx£_JfãB5pŠFB.òn†ƒjt<í"|eø«ñ`Q)ž†‹¡o/÷—›R´šß\ÏÅÍ¥Hù å\tµ–”~t{b` £Ê[“ ͸ªÅsfÅÐJbìÓ¹›%ÁŸš•èOš$Õû ᡜ²Ÿ÷& sبpqÖ® hçi/G Ì‚ÅF^\±–€ãiWàÉNLjo1#\S’KI ™¯ó{ù§#i5TT$F¹¹ñ{ù'¬ÈÔÓdu+1-îÛyrtÑy¥©É>1©,fq!驪™ÜT‡ª—UÀOÝb?2 Û£Tž\4÷{ðØ©ý`¦˜½xB+#n•" Ï'J︚» qËh­ß¥èÓ [ý5°‹ÈX+hßÏx SøI越禫#6(«®ß–à ò/}â+nìÔ½z»öÈ×í÷±ƈ|ˆëôÁU´°BÎ-÷rÞzZ(‡­õ°©·~ÐÅ?A7ÓXkAT£lÇp§â•êàÕL;ESClüã§ä3tIšøò~Ѩ;ü ©õðb˜p9Öº4߯\±É‡éúåt8x@øƒPpo6=_ûÊ“ûý3M87¾[„ÂÎlC~ÚÇœ&\þxpK £ØøÂ~‰$žpÄžc€¦§SÅtí™Ïlt°-áð5æ/§ö\ì_J¡Ø9IT[gW`’ô®{x›è‚V´výtÄsêºá™F#ö@ð¾9ÔO»ˆÝ×ߣ½ªÀÅ¢;¼–>•˜?Ø4M§ƒÄÃÒ—KF¢M8( yRŽ?”ÜÓä•gƒ÷ÞD‰¨!~FÉFKzZ]¸AvçUÿ)jnÇ,¸Yk:¢—Ût–y*:݇ëøä¦ï˜j Gã,÷û§XY¹§©Ýñ#Âen6^¡w¢Ž"nŽ$\pâBöËíÙd°òo¦øöa¹øðO|KžblìÎ&)E® ‘{5³ ô½Ýn•[I!ò—ÙL¾ìÜí,ž”Ï#\øBNÙ #¿jXØe =ôJÇ\ââxNB&®]豄þû|öÉTu†}uå4bñ§cûØä ]q<Üù ¾X–\ÌÆ…CüâçŠWlç·°t¿é.Ða9>KÑ|eÅ„ÃjQŽZTáÇÖ÷r/×´û_@»OŒW¦ _ÃóÆÎ¼Ã”h$ާâìÑykyzÿ ƒy) Ålĺ>8˜¿M•L0œÒÁm9›¥Ç SŸÂÞ“©.­”‰[> I@f[´ðwR_r`˜Ñb’1öâЋ“·¢&}D>¤2\Æ Å ÑÅé]-—NóŠ\èׯ¶LÊG¸Í.1‰³Hpä³.NÕt)IŒÚ½xî–ͯ¨$Ý‘X‘"¬¦s¨— ¹öZ]êL¾Åù-“tlÞV*\mËã/ÌÞÓ›m¿ßÎã÷i=…Ø”–Uœ¢R€Ý]\ ’®”kTáGw`5D£w˜Òao…\{zÈšÂw+"±…"ÑŽ±+Z3Ít+c¶·’aëÖ¸¢õG†$GZ®µ#A–p¶oÔFzD²Ý©]š¯‚; ”@bTæåRY•/œ­€Þ©öí†6¤Pã­~H¸e~áîü<‘ŒÐf>åéBzI4ÛäMí'’ä?Œk¼°Ò1Gò»î1ÙñSmÏß¶&G­¶¥«øÊõ׉¼æ$•åÇxś٭,X*ˆƒ@€ÇÑ ¾Æà;{±ñk6ŽP—é¢{ÄÙÞ–Mΰî9ÕP1ÕÌ©Š-n®«Yý\ÁùkœeÓKâ¸N;O(_Ú¬ÇÌmD·¼šŽý¢Ñc»D^`]eX-B©?9ÑWŇ킹]²ºG þ€­ª”BUM-[UUè•ÎÙE<Âò ùà›"ãß †îÎv|= —{xϧòŠ~¦\^¾T«Èg“¹ƒ¡á#_{Ú,€Î½Élxf[d…»-w SÉ]~C¹ $º‰²m\vOÄ»à øôª©å/b o•zŠ£n22ôÁýŠoãò·åÞ»t1sýÖr«ß?{ù-tʾŸÿåÚ£~:Yð%½ 8a“逨`:)w'»ÈÊÝ®¸¤¨`iÔ†¯¶£Y –=žÇ}·œ&h€Ñ³ƒ.VMëxæäº‹W±ö&4ÊÛ>QÜFX|AáxÒ»ìžeoKÔí¹XÀ]PY$K š›r×̱»L“RvN£–€T7ˆ¶ÝbÆò½¢Í¸ÜÍéõ )|^»•_õ€fOóÂÊ›¯~ªø˜ÝR««@Ë•ËÝPš€A† 3ÛQo¬á™öØYoÉ^¨ÞâèÛp‘Ir  G¾¦º8Ëú×p¿·6{˜Àƒ®ÖîPûŠaÓÑšá€#Pâ^ý3ÊÃÔ·q¸è½ºŸ”Z쟩 ð s/}ºêÔ7½ÊÖÐýý,žäÖÂZ‰íYPëhN¥ó¿€ õ“Hþ]kt*™góµž©Ø »âÝj_·|œ¸ï„5‰5&µXÁ„Až3Ø5×ÎÑßI‹ñI¸Tˆ(Bd`BŠBõ¼ó±Ÿ"·:–Ü €O½oì±S© %[ñi›#ÚÊRÕþõÿ?süÿ?üÏ­Í­?lnnîlnooÜßÞ üÏÚÿÿ÷ù©òÿWŸÿ»›;­Îæ×èùÿõúÆÖúÖN´µ¹»±µ»Y‰j=ÿÕŸ“´ øŽ4k’ ÄŠM+pÓ2¯dUöcÍoŽZ×°tè]HNŸú9VÆUètG“ V72²Ï5‡o³þó÷+7"J#†’øÔw‚·òÍ?)<€°æŽ¸HG9y' FÊ4+Bª:äå+Ïì§mûõ‡ý­ÑÝúèOÝ£ƒý§pÁÆú¯^üÈo(óWðŠQNðÃ-x¥ãû%:ÂÖJa+a€Æ!:ÀL=•ÌöÃbªKÏ´"ÊÀøŸV‡àÒ`+­WÁ'ï·´«¢ n-l ¬åH œ6n>=zýjÿY÷Û—/OŽOŽö_ua^÷¿Ý?>hyýü\Oè—#›Pž2R“¿MŠ =“óNígS7+*þü†öNܪ÷a\]úò|*.Àæ=ˆž,בj̼y"”8D‹È³(s¨ñÁ ‰‹Q„¼Ñ–²O:†+“9á À︲¹³á&BûÕSl)œ7xû¥Û°änÁÙ¼vaÿ¯ta,W‹ˆ˜àËIqx 3‹Á ±klö¦þÔ×­&F2匲À’#›¿„ðÃû] öGŠ;ê² Xwס]EÓHý›ý:XÔç¯cƒN½æ‘bìâ?%Š­Bç,å´Ùub+¤’þÖl!ª¬{OÑ23uò“H ®z"Õ8—Ź8E­¢ç|u¦6²W X¾ÒAý¢266ˆIÜx™ºB‘‚¥Ó׆ö+WÆQ(Î ‹–óCTͽÎvuTòœÈ_õG|…á¤ÓËI6»¸äÛTó-œë¨­ïWà•[=q… #âø)|KE0VÝÂÑ“õ³$5¦Ñ»6‡lÓÆZ¤r@9K4¡¸H¸Ýy‘¶êãÜ˶*\*XZ±’¥JÛ²=t¾¿F<Dôæ¿1°\œ_a'qŽY¾kÓMÓ²¸4Klm%\×]¥O8®•¶_+œªôHöÜÙsÖ 2ÝDXòµË!óÉBè}=…_›/Z¾…'ÏÑwþq€À&§úˆßÐ/š7pwâU÷ô»l"`²Þ:5IxþË[éÓhoªm¬ˆô‰ªU§%²¡ÈÇbiC'z,GýkèP!‚˜ôI„.¶ý>åöÆ1ä Í ¢ô´޼igÆÃñ5ÂR.üBAJvZ^)r"¢í^Vÿ}Öc¥Tp®)6×õØk&3&PÎàZØí‡5Ѝ¢&ÅðXemÁxÁì(φ£˜M¦¨s³Ê`¡¥ =¹ê2 ¡ï2!)õ ïè9DÅ2ü>ù0†F)ú-=€º 1ëÕ£ócè 5Ý­÷0™\$UyÅ,¡ƒëœŒ(³DsJÁkÌjKªìlrOúí(Ÿƒ¨â¡:ÿ‡±2´}LÔƒÓê`Ø—†¾)DYElVÞat—~2uÆ.Ç`ôƒ(Üil©eÎU“Q89¶ïUã0ed<šúx’RžÜ6.àCn Ê#t‘:Ë 1QÓîBÐPôä p檆FÓ>™ª‰ŒF9¸ÃóŪ`j“Ì׿½­ôþEµž3‘dÉÖÄãØñ²#ªJç:V’{ô½5¤f÷®éºUÕ‘¼¼4! $AËD` pFŒ„ËENéýÛÓVËñ}øÛƒy¥hÄOy[ײltãÇ…!çÓÑ+ íraRṼ0é#¿bµg#„8óIC@‹P¯'õ™ ^j/Œ3}Õp|1r«'2¶ç ÁèæËÛ=}Ýr":ÏkQvä;º#óø‰ßÔ¡ žâ{³ˆŒ7¥ˆg„¼\‚.×°$Õ¯ò ²îÞœE;½Ê&÷¿ÚýñöSÖÿO …PÞX]¨ÐVô£ÿ³×‹‹˜H´"žúXãeZ5ú·`Àš8*&¤ÓðäMõcŸGz­`žÉÃm.Þ6v;÷h>d½6Ðz5 R/½7bè·Àå‰u‰2xÀYžx»—úmë<§°§ÔT©ŸvÑ›œŒ ¶”Šå]jÆìgs¬šÒ¨X“\·ŒçØíØ:ìµ¶¸zëA;uÉb ŃcdžÉ0ãÖ‚ùøØÙ(N„1È·çûÅ=ÿ.%ÛB[èh ÷,,}28Ç®/×C7‘n—î™çdœ­rÙá–÷àÄw†wî T=¤ØI%4Á¿ ·½`õÆØºp;&–J¾åÌØ &Aü§åýÖÈ)®_vW"òêÍRú‘~Ay ¯¨SÅ[ÄV é—% ÖI¢þon,Bä«ÿ†g¥|•%ÛœY0ÔÝÆxj×¢ Ý ú¿Q§B·j:ò‘3ËË•“pS åm jð™TÉõ¦å9aôJVÐF[vôÛ}Ô¤)Ò¹à\JÒ5bQE ¦ýþ@’\^48ÿŒ²è]8-æD“íH ²J•ŒÊHr]šÜãƒgONÐ׆å²ÑRSä2«®9r­‡3þhdäT¼À ÒódÚ»ì2¡Œr‰CÆzÛS²ƒòZbyPÚŸ°ßtÓ¾2,±[Â…êÃEùQoÉ6a Ð]—ó‹xW ª³g¸M4ZЉzÿwÖÒ¯UŽÕfÈŠ0D¡ÀšþÆ@ò‡ß{7ŠâJTŒø‡%·ƒ²ªkÞpô‘w¹¯ìKi Q9½Õþe‰Þ•=ð¹{rO´R¤äL~STÌkÄ0V·S5\õm… î˜Q¸‰Þˆí`ÑC6$“,zf¢L÷µáf÷_çÄEºÚdxpFÒ^RiSsÛŠè«-â{ÑFIõB™ã,{P<óÎO]/rü¢MÝñ+}ÇpþZt¹R^ ç\åÄJÕq‘9_æqbAѦŠUò$6„ª"í|ƒ¹8Ó©:"ÆcŒ˜ 7uQ®.gf œÔÑi ïvý@± 6' !å<ÒÀ¤+¢È0&G:DäònAYAcù–Bmä²ç ø|÷%’Þ Uì˜ëÄÓ6º0¹¾d”¸ò¦ú Ntè_Çþf(¬ñÐc¬¨Ò«vEbP8Ú‡Ü@‚Àq©â ãZ'_§;N o‡F±&ú9 …©‡í8,dk s1ç6äÝ¥j è0uƒ{PÕm1dú4>,pÓãd¥ìªª¼Æ®ÌåZJp ¬r8;@á$«muüÙ¹Ál¦ ܈ä¬:µ‚¯BgQ£Ý^¾üÓ¼–SÁM&µA`†Öu!ìŸ Rëà&sî½\›ëQiA%H\}Þ-Æèõ³ƒ%&È9Ÿr§Šó‘Û¨ Ì:Ò‰v’½[ãÙ4.4@ZšMÆKy:„U$f¼jõZ z~Ó,Sa…a×6‚gɈìþlYg›s°ø\nmT1É+¨T1¶œ<ôÖVž6»ÉJ•šëZ9ϲêƒ['Ÿ­æ³³a:Åç.£Uà˺‚È>+|Уʰw¡z;9ø pÈb‰vJôŒý0›"×–ˆvÅĞȴ¼øþðÅËKì×¥ÂÞ(ïVcz£ÄÓpM.I½ðtŽl1ʇÔy¢/îò2ÇÒ†¼ªO˜!õ”†fÊÑþ\ˆ3zyÏ”útóüÐ(Ùdzi@†ˆ ‘Aìuˆ>Bgrzš5UþB’)+ÞÙ¨×û•0¦îpýlÀ‹MŽ9î¬FÔä/~"é_èYMŽÕ¡Êüãtœrkoa`¼…Tg‚èÝ—_»Î¢Êœ[- GL>L“Qî—Oò¯™Mg« ³iê;÷=–tÉØ¸¶f#£¨-8»»I Õ…“³éÛ†r¬"[Mò!6Œ"!œmqY­# ¤HEU!Êt¾Ž8ê§ç=õóÄj ó†'†\p‰."$½]²ðOqú‹¶—òºÝXE•Ö_Ï…U¹R¦’Êa”«+vÜn ŠâUžwÁþ.ÓÎeœb—tTÿm9ÃêªÖãx N¾ç#éuÃûJªh¡3\ ßÂ=3ÂR[œõæÑ›9þr¡"˜›÷›v\Õ7áZUSôŠï,Q_°t’·ÍÄé‰^­(åÈý©dàæGë¥`ølá‚ ¨˜Äù Çîo­€¤O–ÒØ˜À¢TóÝá³—mfÞ­IƒÞ‹ O+ÁÌêÓÀ˜Ä"Y oq®Ð%vð¡»Å¼ä…k-¸£ÂÚ}ð7·3·¶øÏÿìAñ¬ÚM•¡(ë2äôÓ¼‡>!hU€e;èRÛБV©}Eâ²íµt¤HÊ},pÇ´£;½ÌŸ«ŸjE˜ñ M…Ì]P¸’±wœWñ2(Œ¶)•¿'3!ùð2—µYG-nØZxŸðQc›g˜eµ½*‹s?m0/ryNIB¶7GTG¤ØÆO”ÕÞócz36]X/!þ¢Ò£Ä–MoÒ{Ìì)u5ÔLÅÞ¤ÚæïÆ€GªæU6‡äY–óûÎb"ksÐÓЩï^:GàJ¢âÑÆíù#±Œk-•£ÇTÂx°˜ŠÉcÄý]šiÞV9ÖÈhò%¼Mô€ØØ{_{p w–îQ{jªft<> 0Á5”U>}ÛÓÙ`Ä¢¬º8GCLjªyÎeévåÃíKš’À¸ÇÎnœ6˜{Å 6á˜ýלˆ…%qRìÿÿìýëzDZ0Œæ·®bÌЃàA–P¢lZ¢m­¥Ó’è8Ù”‚oH ɉ ‚D1‰ïåûö¿} ûß~olw»º§$%ÛIÖc=kÅÄLOõ©ººÎUÌ ÊGU&·´ ¤[ÚJOE_âø\¢Ó¥÷é¯ãåðùüÄ-Êó·â<¬øutF£ÒZf­`1áéB[·$:Ö±þ¡y<5Ò½áL3 ü¡bõP"ñ2Y· ²‡Ð¤|´•@kàûP ;IÀ(5u&ª,òQEG[¯† #›|NyÒp¡¹ø™3(ĆšËö CÐwêëå˜p&J¸]³Ãе5@9ôÝ ÆºîOUínØ©¸øÎÕÊïA¢ž–³ŸÔàýŠšåÔô›Ò¹&ŽLbAí¹Øk•ÕL†½ÔŸéÊk@›~à5 `~® @¹0 L˜_cwõT7;¼HÜíèAFrÓ̸¡ß ÜÓoD˜­.IÇoq}Õ1x"&¦ÆÖ«°ÑFDìÂJ½,¨r´[Ø0õJtPóMO%˜kku ‘óì¼,æ°—È‚n$?=…2Ì7@éKÐàÒÔx XÿnÈìõÀ¼‹üÐÞOÜÖø6Y‘)ìó¨¥ùëð…¨ÆÃø#~ŬIÂñÈÕ}èÅ è†0Ýõ—Ç4»DÁyÅBÎqó«a(³4tÒHÉ-é¬byÙ~ÈJ…›ÏÜTø…ÃÖööÜði9l`WÄlÕÌ]¤™ÀÀêéÖê”Kêé¥QeùLò|içâcvv¾@¥©¿<(?ʨ/N~sˆÜrÍÜÔÄÇ­Y_@I‚XL€%*q§O 7xHj†´—²rºð ëØ®ª&œÅö.òsyµL]À7ÀgŽ YÌíg[€+UÝ‹Öó<ÑkhÆ%ûÃuÉÀ¥z¡]RÝGGÆ·! »mÕ˜áïÎýÿ3ïàFŽ«³qØ1ÖÑÕ™ë®Áoz¥)b»væPu7÷R }„Ò6^¯Ÿ–½š5”ãj^ôJ>´=ýM‚½ŠmÅä¬ QÓ»æMqÉ£¾¡tz=±3Àê!`µ¬•Û… ƒÓå¸Hàóu1ÚOÍ£u4(DlDñžæ+\)3<~eåô–m“x¯-ïŠ^Sȉ @„Îð$2Vf„|K.É :ô×+éî: Ö‡ý0ôI’Æ…£é‰×<Šñ ’½@‰B‹,pü(l>àÍ|8éüáÍäïëHß+¬’ôÿ+4­œnvu]”TÐ4]pKòˆJJ)­J¾úªtd/Õ «ùV9åÂ,!<ÐÑ3È…áø@f†°y_¦ ¨yã£úJ½©¶ä‚UŸê¦¿=–ZÈÖ¡î+¦b¦pçb$EØ‘G'—ØF;E5‡4bÆY8x€í¼!Z[©…<­Ûà!•€@{3Ï‘x¿G±ß¤dy€vH€Xk/…‚PaëÄ7‚ •t,1»EBù¦(x²‰¹4ÞqªÒì{#ÿ $2z[kÚèÀשh¯/²®;ÜÎÄ];¨þIÿsçØBjË †ãê¬J|m·¹)4ÒY¿6ØÓümyÒŠËMÚ `¹žªã̧oêfc ¶.ÐQkcÛtQA†Òô¤š¶L+Õ……ëA¥Koõ´¤©lžØahº6mÆÔX¡Ò;ú€ÌʇÈ2ðÔ“jG­Ñ:Ñ´mÓ’+Þ4mê“Up& Vœv`覿-ÎNxi©ª“0Ü''>ÃÉq: Ön%TÂgpGn‡*‰u%u‘€/àúÉšåòU§/¢vÏdâpG]]LÛà{BÀ$ïÍŽðEÔ+ÌÈÈ ãÐ FàsÑ`yø <á˜ËŽ«w0,_7>V<¤ìŽiø|4)9‰óiîMard%ÍEênh×}+ºød.P¹†2ÌÐJ¬Ý_ÜñP qFñ²  ظÚSémÒÙmT‡lo±ÆExx.g%º Ù‹¾ëã­¦<F.säÄuqt‰ÂL)&s6s¬‰\ïa¦›Æ-È^œçóú™ElÜq‘kÿ*‡OD±‚òªu­³ùÁŸ_ _þ÷£ç½»Aîµ…õ¹FK(„îCZ PLχâVÇCwCΡ|C–üGéæ ™ßñ¸F*q%å–Ö›áÀ×îêÇA­_ëPz ã_9„ûÒ îVyBãaGsdG¤)#ƒfà‹N“³@móÈ• `TÍç#ÃhJ  ã ¥™9c_¹C…feÚTôdz¤ˆ<\ñ£ Û€‡*©9©¬¬<;“ÝçbšSOeÊP~Š A‚G³ãü’\åݱ/ÏÎpÔL$ÞL!1BnÂ8~1 Eû‚c»Üšäo´˜U²CÛ%í—Æß—J¿`¿q"¦ñ"úº{ðò¥zfR.{‚Ó7QH:vNk¡g 8j‡ÜŸuÝ ´Ž+- óœã ª)¬x×÷…~:è”Þ»àøfcg£<.ÔiÙ@ó|^8ñ`üjuêçß™\HjFêe]ÖçŽí¡¬H>í¸úÖVÍìg&ºhÌÛ27ÞŸÝžà<l ˜ˆÉr@ð6›ªY~\±Á… ¼>Z€àd^ût&þ< 'Ö+‹Šƒ U§ú"”Ò¾VU­¦Ö `SMlàK-¹ËoŒl–jg%O¦;¾4õ$å &;i;4¯RjFÍ:B§1‹:Ôí²Ó§Í)Mv0©ß~ÉÛŠu mYòê6­ “L°Þ€Ñ@Aöµ]¾Yý¡‹¼ßpõ£¥È5mV€àKÏŠ.|(€folÜ´1—­±¦4i>JÀb;î™WÑÔå&®©Ñ ¯ E5ççB¡µÛ…õ%0T®’·¼™·„[ú²¼:T±àåÄ1}—B —Q>¦ ;¼ßAG\McP0=“ö(ëj©M8–~‰(á¡aZÀ¸|>SVYÒnÓÇ\éñÚ[fBy™s`ßtŸC×fCÉo[$³L_©>]ÚšmVÀ |©5¤ÏúzLp'ÆpX7Nö6Œa³‚`¢PÈZ]A#ЍNq`é&˜@ü–²DÙ«ÄO\,¢)ÚSHž¤n¨¼™žFDAÚwe‰Q#æ[p%vѸp 74ûÝ" s©!7X4ý$(LæM£:ÁH5¹ÕßbLúïâŒLö˜Ðšhõ^H爬ÁEÊò–/<fÜšµx:ç £­7_#™½Ç KO÷Ÿ0áù†nFe¬`Mòí~›ÏÇn|½p“`ÜÂ×°©œÌÊ̓Ä<¸ÚƒÃ¯Ý~º¾Ï¨y4û™ÓFÑÅâä‡tïÆ é9^‡µ_q“~Îûè¬.e-èË‹J)á4 ú j€¾ÍËÜäXV!…>^ç”G5°EƒÀÑ ÚÙ4’þ¶¨2ºút#ž¸ï(¤Ð­›^Pàpò£[ÃKLЖ¡Aæœ\|¹X&@P$3@ö=¦q x5W{ÕÊ»…×)`ÏœŽÊ­V×uTN7ài¯™‘U0ØÓ6§ÝóÅdÜKj̘»Ø+)XîÜ+&÷;r«b·Òjй· /ï6ï4$Žs£r2bötÇ”sÙREœ1 Ô_ˆìš'öäxuxÕi¾ÝjF‚T/{Yà2u¨Ã t»ë [Ë{…ÞÚ#ÒU8×¶ŸÀÆ/¹"çAjYiCiÓ•!‡Æ}ø%ݹš4Me’„Ⱦ)ïÕTÁ0{ÙÚ½Qù6;;wïÕšN¿}µvÿÕtÍûb¼l×@»Ÿm¿šÝ[Žý·³”nb­ã Ô­J'ËîKÀ,i˜ ÖîmºGòÉÞ7m÷‰dô¦µŽèh+ˆ—ÖhÓ-’´ÞCÍ èìF3vŒ¡ø°EňïXh#P†Ò[GÅ–‹VeØàJ\uäx9•Œ’ÉNÝÀ\|Ó¥ ôíhÔ¥ƒ(…ÎY²á÷BÛ»AΖnÝï6püV€mø1 ÚVŒ½®µC3‡RuDGÑ5#"t_rÕ¬O—<ä.²°Õ­$»~è<@McÑõæ>mM“+o©.’½ŸR]¤qιÉ98?áXÉó"\sŒ)Ƴ¬’d§ó Å; sÏž=ì±a½òúUhƒƒM`{||Ô9w÷:'] a'Ão:s¿þùÏÄûνӹÿûøœw°¬‡øp8sˆnÆh±%Ä¢O7îËß8ùá÷ÚfO;Ô˜¿%MŽ0%¯ü·`aûRF;ŸÃÊ)Í ñ®±ºOZ−hœ|Má5?ܱt³(`égA·ü3YÈ2ðÿ €Äƒ} ¥”ù¤Ì ŸÿÓ¡¶íÂq˜ó|Æ”›Ü½z–Oï“/Ýh„'t@ZkÜKË2¿€Á €yiFõ†#oY”p6)Kä: mP·N” )ØEß²9”&¨ÙJ€IŽËb"ÆT Q€pƒx €!Ãõ6Ø-è]úäbáågo\nŒnÛNÃçê»±œ¸S_Š>*ð€$¤…VRÌŽ4:UwçŘœ*á¢ôÙé‘N—NhüþÅãðæžYôB8wøcƒÄÀcPBñ5l7¬¥á»[ñk/ˆ-†Ôµ¡CæPz’´QÃa™U³%$§OöÒ¸á.¤Á-Ϭrêª{*'î0åg\Ç/ÖšXùÑ)•B¯Ð¡¨ï‡ ‚e9‘dhî8cý!–šÜ1…¿@1Zœo:btüX @[ØcZbƒËÀ·]޶‚Ãó×çÁ™¾¹¯“dG):‰ä»"oàN‚ëÆ¡×¹Á«Ó¯ã¼Ð3ë7 åka@CË[ìe_9ˆø¼ÆÚI”"Â;°]uâ 0fA–ó±kÚuÿ‘ííI@ë—œe7ëF¦´žŠe°ýõüdoM…3êþ®£5À~óŽ©b>^Ð[\äæ{|L-Ü+®n¬Ì—ÍårǤA°*ƒN¶)Ô£T@¦ÓÑÉ|99†|ðå8¦þý­0-E„pŽr·š"oÁRóQ{‚Ú¡oÕ5Ã1¸Ç÷•y¦\u;æe±5ßl è8èr äB'ûÿý3,hºªʕˈL% eM¡–5›æ9PB®VþN]2o¡AoÔf1–À › l@›ZƤXò¥œw}#[ƒRXk»xuz DÑÅ#=©ÆËÉt ß–ÅxÄj©8|èkêú«ÏÂ>U×d<†àÁ Õø1e-«¡ÎDÅ‘)ôuÏÞºìû0lŽÖI#¦}®åõÉ,Óè×<˜ýé%¥ÃöTÐ[UÖÜçÀ ­õѾ<›/55¦ÌNŠñ8¸Ø‰h".­¼s[Žöa÷7Z–L#€©Þã-%p7Û×ÜkNNIbÒ:~AùŒ0@‹Y‘ô'DMIU^Yí­A,Y}ü޶Ä}ùh:rô†œr ÉgL->ÂÎ Úwާìà~²QÑgö•Û÷c·ú‰¯L¨ÐïT‚#S£{-Ã&YÖy3Ú ükGÿºÝ‘V½¾ùÂ!.»¹ñ¥Ö…{…FÊŠ|jÀ„3híöǤxö£áßúÞŒŽïôzðÄk¦-séGNï[¶b:2+·’97HíkËÆlùIŽ’½°Ë rË…Vä¾Çíï{@+î7jŽë%Ò¸ÎȦzá¤5|½¾ŽÚ(¬o©Þ«^”'o.塺UZÞMBDXG”>y4þµî’k/ŒÑ_kñKç¾:ÔÙ tXq®¸ñ@)‰›ù¯—.Å‘ÀkƒLœ‹|~²¹Djr`ñœ #CVÿˆq TÌõ%^ܸãì“€›5õ1:V!JF¾«u¢¬Ú¿ŧςDŽ”/ì˜ì;èãå¹ªÇ È ÖàlÝŒhhNö>‘Q6Žr-¬XŠqÅeWp]IABÙ&ñú…š"•¤í@÷,dHV¯ØjÜj¸ÿÁ5r8äVh Ÿ¹¿SÖQ.£V„ãТv›´‚!Vx5×ú鸜yc££àVÿào|#¢»˜èi¼ÁxíbÍ'´¹í°{f6:Ee­9áb#bagn9f¥ V<… Ò#z̾£›ÿ™CîÑMê(ƒÆŒÙ Õ™œˆš|ÖHò‡w9å/MZV«ÈL{„„úx}TxG Ù—¸y¥lŒØ,VjÃåâöz6”.•Øb°G¸rD?Mf8³ä)⩇“4ŒHnáÁõBeÒ—P‚ä×Ë„(E–È ëÈÕulú}ikhÙFp3šDNw* t–ZY2×GmuXœüJ‚w•*iQøœ²ä"¸„ù=ô-ï¯Òˆ{$dòL| ]8îÂduà»,œG.ÕðÒ|Ü>áû‚–‚–¼•â/˜Ãòcou©á† ´\¡‹ƒ²"=vˆ]e— õ†;"RóÀTÓeü*VŸ“Hë™S½¦‡ ت9n7Z+Jôàè ò‘šŠ\€:¤+ïg´€n‘ª‹ ×£ôÖíè8À·]~»N´p”»ÓKÝpWwK³ºhu²B»Z½kø…FŽzI¨PCxé…]|{~ÐÖòlþHú­eÞä›À r}«|¹JQ[½c5v_GÞ—1Áí I¥: ï›{ç;¢ËÃI1IŠ+ÐÜïÜ¿‡Ú»B 5–×7ŒMòù tNâƒZ¦záÁü 3 „¢Ï ¨º?q_ ¼œñþ=%v£!R/èÓdôêêödÿÅŸüЧ¿¾þpÿðà!ÿzq°ÿðúNPØQr/àU—•´ÇÐQuwåPÂûËrdÓSñ÷1s–:de–ý£áºóâ–´ÓkXF×P³^Œ›õÃ{ÖÒתó)Î!XÑ1Þh|ØTCPõGÒnzå7+±¨ Ê£ÓŒËD²«9î«o˜‰mšè¥ emëÆ7Z¡q!ÖNR¢Ͳ‚ó¥Uà"«‡søm}<æy×NÎï2/¦Ú# y¢H°¹;D˜t`ÌÙ`å ´oÉDî§\×:¯V4R[%`µ•Ø|9HVl{IYﱌ‡Et胳A¶¶¯õ³µj¼Ö[¥‘Bë¶2Õ`ÞFÁ¨¯sŽ Û k)É2»„”ªHl¶l¡å#ßYŽ“6Ü&õ5¦¾ý¬Ñ²yYÑ:™Ô_œßŽ öm㵤¹ƒÁ§ÅD÷Ú ¸aôµ’Õ`IƒàÇâ!5θ¤,hî÷•²¡0΂ìWa1J„™ú‘?\ꃧ×úX2þ„égö/$en°T«Irà´è öšÇE>éÛ㜋Þ]Š-F㥡_‰a“_Øó{é&Ép•J’Z4Ç"WCÂìÈañ½†„މ«F„ ºŽë^ãdÃ.PH÷7ì¾ú‡îQ׿kŠn BÊ“’C ; ðÎXŠÓŒ”kƒutìd'6[44Þ€ÆOø“£{N §{k_Ñcíw0ÜÛÌï¿ö–l‚`äXÒ[mÆŽçç.õ?=yȇßT¾Äк@oG›— ԻDž£ õrµEF&’}xZ£!À3ñÉaßÚÛÓÜ_›à€Ã54O.÷»É˜Àø…&¤G‡¦½´ðæ>òRLÀ³Ðæ6="d[ZÜxxSô É%4ØŠ¼Õ_"±0„¤´~Õ ¥øž}޶™‘倸³ÄÊú‚>…q¸î#\]ã——lõ™Åà{®2tp³e^q¨;èWBì°[€ãquÒŒh[yRÑçZ«†LµB¯}÷¿oÜ8^€ÑÓJV”¢„»ÑJY,Q‰hŠx•}Å"4´Çµ»š²¸-¦¯8Á4ïb’Ú¼+N!§p­ÓªZs¨w/æËiƦ‚bªQ“°–”–ÜQ`Œà)JØhùPUÆèRŒ®våq;|˜ífK‹Ü¦(P³ÉÉIÉV.ŠësäN Ç`rþ8œ®ÆÏ7v&´œ]´ò ëô)¸jQâ>*D6tpºzG5yJ*¹(9ˆØ›ií¸,0L¶å#”@ÉÈÒÚBŽ“¡#åoór¬Užìê ™ŸÎk“~ äï4¡0·Ýõ—VTcB½{¨¯´^ ›vy8©è-!a(Hílæù£f™ lkùrü*ȼ-lô½ò>mܽÍòþÐýãE?šlSO†î„Õª#n©l¢Ñr§œ".*» ™T0”Ê >=ÁD;ƒÒPÁ*ž¼úrĦñ2m¢ ®^œIO$A»&*¡'É y)!±a76Ù:…i$å&ï$ÑÁ£.Ô³ÈرqqC5a“BŽ4€={ä㢬 “ŸY¦Mé=hìI„”†]^öÏ@”¬nËrŽÏúÛ¦B— ój¾`ÍöyáÕB‹ªÊÆù[I?ðJ}㮦é%[0||ÁŒÅ|\L»Q‡÷³#°pUuE&Μn?ÁêÛw€þ;î´©³‹A¡ 0¶ )ý—°f6¯¨–®ÍѯgÚÝL4,”†+ͺê•fâ9Œó’¿ËÜ5ùDz¸z„\ð½^û´t sv¢RŽ×`¶mq5ö¢–b«êñ&gsq¤ö¬¨ÀÈ|q^‚L`€áßÙO Ð8×öNcí•»;ÐdMª$d/´Äs~væ` »¤'YwÆX†<_ü8­Ò:ã*Ñ ³[>í0WàUäY¨é‘%9wk0 C‚]1¯ñÙ;=/Æd3›VäyØy­ v¯5'ë²NÛmˆcù03 *œ{”/…vfͧÕôrR-kb£÷õ§I |}k†Ãh·±5¸Œ4®n'¿†#~`8"ù<2؇½*Û¬>‘|…Ùp¥Ó\T)CP¨lŒ@>_»oPº 5ʆ°·†q,»èBÀ£q˜ð±û9f£˜hëÀï‰;Ê5¾æy¯…!ܶ/åñJäz@ZrŸ†£œŽ4¯ƒ0 ü À°æ9'ð›Ce¹B+´ÆB=cÖ’ °R<üÚ爹o`¿M«Ì}ƒî:‡,m·þ;"Žìú]w­e÷hðð÷§Ÿ&5ÞVeîûY»ÿÉô¸žÝ b)V-ùW?bND·kÍä…k4-?¯Vo3qp Ò0‡jmÃ#{5ºnèüX+‹î:3AÈ‘}€áF¬…ç¾ÿ}I5Êr9mBM¼‰¾º2ÆKObò+ ehX"Äå±A§×î-ÎM÷xÏyÝc’¾»ïF©ïFòÝJ pB@mÒ€±tšA·¦>m(–SóiUM6žiXæ]®õŠK²¸ \#áPXz‡ shâr§cJê’]{}&¤(#Nœ7©ë.³ É>‡Gwfìk¤@‘ 8~PÝOlNU*Ïš´YKBqª4ߨ?y8‡R> ð¥èQì;ç|‡’ëïÅñœì³3®…Œ[Qdk‰Ñ‘ Úí­ñ’Iú9âÅ€>uliS9Šò‰Gë }ɉ1O1XÒÑrÚxñeôý.ÕI°Yyq6¨í?Î>ÎvPËÞ•»ÆÒ~]ŽØ¥Í| ‘˼¤à@.R¦ú¨”C§´zàZ¿ í£« ÚzT&\ ƒ£’¯A$¦ ìÜ Jq/@Ö ó¿ëÄü3©ž£Æ¨ ºVãqå„ÉÑ0m#]±>†| œëëošNh‡-þˆ$u;Oö==Гµ &Üé¨?²·Vƒ‚êdIk)N¢7Ó Fº_Μ°„¦œÍwdܘt/ë6jëÂiÅä XßtL—'«Béå¿¡îU£¬íE@=†ôª¨V¥6T­ÙÔ_Ϫ¶•¹;ÊûeÐLYà&]dãâ”r‘•CƈzOJ‹ ØÂ*oÔôu nt2©j)Ý,5²­_S^ q«tÜ=tßáÒ)ú‡b¬ž뢵Œ +©AáÄmºý´Ó‰nˆ}\MUWC†{þ[ÆÏ³"nÇOŠ;%Ö¦ùsˆq·»Éú^ñ‰9 'GóKÈñd‡Üøš*§8¾µPw'Q`Ù¶°º>®  6Y¡íÉ•°ºéçÒ ²rÇTsÛ•}Ž—€kòÁý)ʼ‘9ÀUÇ)¢d„h °ßÕÌ2¤€”¤ ]=?¾3È–j{Ç bðØô $i(ÞmÄà#£>„0©Ô‡q0¬¹Ãµ¤;œ×3éžê꺠h‰Ö\Aký˜3è»:j©d? UÎ-<Ï—î5 øV½˜¯Õ<'†¯ ʯÄxô°=ÂMЄ­94lS¡:þeßZ«Lž^³sñ^¨-Dó54¨ƒFÛ¨$r¤o¨œØµË’V¥–6 ¢ù{5ñíxÖü–×_6>ñù×ì'ëß>~öµŸ}ßþåÆ}'Œ­øßÄŠ83_Œ‘ÂŒó†°ÈÕ—R3)6lÌFrCF³‰o<ÓìKYž(¹§£†¢Ž :ÐÚX¶¾ƒø%^‚4=­Tñ³%¸û¶~S7ç]>Í>ù^fnüùƘ|Ý\ƒÞ _׊zˆ¹¥"Ehƒ (e ±/ ô3±òæšÃ³Š¡/3þ¹á~Êý;ÎùYw«gË­XE8i³u´¤–Ĭ8±’̧h4‡P 2ÏÃvöI1×çâQ´—X˜ûmUŽ28 gPæ<‡Êa`æç "œeŸ`ÒÆÍ‹Iõ+V@æ!*Ô6*kÄ´b4È~(´Ð %èäïPdPÂH©ã"Ë#…)ŒhX9uš“ÉΆ&òm1Ÿ@NãÉØmOÝÄEÜŠ™“Ð|‰ÜŽþ’Ÿ€…ë¼üë›ñdZÍþ6¯Ë·ï.ÿ¾µñ‡áëO?ª‘’ö¡ÖýY±Ñ 3Õ–#ã㲨`Žó.mÛû¡ÄÙ)l„5¹]y[Ž–Pc ûŒ¸ÐºŒR¶qßÒ ¨‰o>Þ¸+YiL›m@›æ$Z¡‰HÂx˜.œã § ó:ÎI +ŸieÄc]\T,pcX åå•+Úþ…(ŸÈä`õR#0KõˆdŠXÃRzu|Ø®ä{ù}óÌk5EPо¿X±YŒÂÊyx:)C4bƒDgϦ|¬¼NˆV)FK¦ ‹RÄY)†Ú-ÏÎ ŠÛx¬ŸÐÁÑ>qTŸïð䂚¿P°Á+búaí|±˜ínn^\\ øÅचl>nno#-æE.°BƒTçÏ 3lnÒc<¼x×q†ï¶[^4›'>óÁºYÖ="èyt%^`E’øâ¬‹Y|.Q|nëz³ƒV÷~õ ÿw |Ü)1êüL,Ô¦Kº„ÌØDb×Úë >r'ï'Çjì§n^áÇ¢¸†Æ&‘T+{c¸i™b”‚j’œïÂ|r=›H¸±7°‰ØobAL¶¿¿EäƒL0þsQ8VoÎ?8²@­Ñ]a €ÖMk€ð¿ÍFôšQÅøEþ®šV“ËN’CÖ·¯1iý h}©Œ&¨;†Ž’Zµ6ˆqŽ¡ø¶¡å"=7Bw×$>JUP”¡—Æñ}Æ=5ÊŸœz´½bzö«Ž?dUØm¤ˆ3{ì*=a¹Yê†ÜŸFMÅO |¥2}ÃùMU7Bmû™}­>”qáw Ü @”òÃJç*z‰çs°ï1Öu¾$å >B^Ô´lΑpéuØ—N&‰GטÖ*5öï%ÄaEé-1}/ÔEÅ1*;5»áRŽÔˆçô:ï¨2]$½uâÿͱ•NjÌÓŠ<Ñ+Ï‹+³ª¬Þ  ,<@ú¥Fæ2…å3·„ EtÂi½‚cw8R‹•' ÎW)§À=AÚD žKOІ+NZ8ruCk‡ ˆ$—ùÛcNɨ6­({q}uýb.2¾ £®õÝ+oC´WE×ásGÝ¥ÜQûʸ•˜!ë_`•?–àºÑôæËGUdß'(î6™9+Éöî­ûÈø~7ä+Áý<¥Å;­ÜÚQŠ{S/˜©ä¦܈@¼‡[Dðý¿ˆ À1Øë>Æ€+î{r9k\øâÿF‘Nè±… ‘H,èu7I8F½EÐWê§!Xªâ…tqHWãä„X1äz¡ðÚßd{䯯gôeÎ5žy 0Cëïvƒ.¯å GðÄ'îúÐÙcîjúÆbn­yOÞŠŸ’È5©‡Tð7¿þû7üG’ãç›RÙvSÝ)'—õ߯TPŠ5¾[îßçŸ}†ÿÝúl;üïÖí;Û;;¿ÙÞúâÎÎ;wv>ÿü7[;Û;[;¿É¶~ºi¶ÿ[:Â9ϲß\\\lÀÜÛÚ]õþ?ôß½/áÒÈÖG£Ý¬uóûo³íÁöƒÁv¶³µõûÍ­Í­/²í­Ýí/vw>ÏΪã<;x7ËÖ},Ð "5…Ys,‡^,. §v‚NRøWék pdx`§%¦ot Ü=÷·%hÌXÅuÞŒ'°¸/Î7ê%ÛdL1qb¢„7>1‹i« "D­,p¿R Ê[Jµ£‹3çÄ'ÖÉñéE}’ϸZ=*ð_þÏcî¯d?HXľ™wG²2ì a+š5HJ-eQŒNØÏ××xÅðÎr±¤ê v™fn‹S­+ëx;_ó8OuE+©rZ³Ëj‰ÕÇÑEs†ÕÅ2€?.BŽIü"(>íþó±[Ì7ÜmQvsÔwîf;AöcÇf~|êþÿ8ë—˜H° Ÿ*TˆSÌ(@pÜ΂iîã=ø§ÏvyêègÊåt1Êöj B¦ ü ?„%‡˜È⤜äãl‹§ mÀe:Ñd;*£™#çiú¬cuÿ©–ó“+EP¯ÜLÍ.Šºù‚R0ŒÜ‚ÎÁYcç)ñ³.ašÄÍÏ@8…VT+Æý&F‘äÕú¼<] N’2hÑÇä½u†ËwœÝSÀŠfIRñº¶^Ó‚û #yìFü]XR« BŸ2‚tx'T%‹)€ù{a‡2¹!„¾»ãE]˜œÛ:pk…òÍ~=üŸï^üyøâàÛƒ?=ïg&LHý$9|g¯kÊåÐ ã·ê'Õäù¬Ä§ÿHÚ·"gÁùöEÑsÌ=I©µÑc4—šÞŒŠ)—œ? % ÉúO”kƒR/QTä2w‚‘/©ýçøßíK²‚fC„©€0R(±õ¥Þ“ÕÜ*R ɤû7 ö¦™`zÖuáã£^ÃzyêpÑúP&_ChÖæï>úlk{k+{xðÍþ÷³ßí¿Øpxð"{yp˜}øÍïÝÐL¦a¸ Üw^ìd‡û_?>Èþ±6àX÷ÁÚYW’û³©f,—¦P;øËHIoäÆ>ÅøcHÁô÷ù§Wå»AÞe¿hÔÍÙÇ"2âs~ ŽØký,*! º pqÎ>A¡ð«=ðQÐ#<¡i{äÜsR6xÝ‹¬™K°ë>MåX² [°+0!9Õ‹ÞÀo‹$+p¿0GÁÆmøjÚËhG¤ï4>4s.C{:Ã>Ä25k0í1 åűÁfÖÑZªÓ,®ÅRø–„¬ç/=Ùñçì¿þŒQåa¯¾ÓTlÞìw9-]Â=5ýzäK´ ÒŸV{”ñ÷O9š‰É¾tZÇ.€d¸¡ñ*4£ÞŠk Êà¿®þ„#¥æï1V,wš„€Oܧ¡.ÆOŠÚù“oÓíú[SήNÎA$û"¾q¢1̉o¿Žf»ï‡ß‡»ec'F,‚#ô˜{Ù ŽÝ‡9}â)UeâÜVøPî*0¦™´*Mx ì8Áõiuå"¬N–qÝ+­Ð_'¢Ñ¢5ë@·=¡ÁcÒðÎ/×p­§ÄÈ{µ¯¼°n&QßDœ Á$ŸÃ/†î—Í¥>ƒÝtMŽä?tv=^ðd^‡¦¶ðpé/zN†K‘/ÕÐɃs¼Ú‚Áàˆ0R5“ LùrDÇ`FXÌÕ·à#ØJhþÙ¹ey¾¦Pf,PJb@àƒ‚JƒW‘Ç&8,!ç?Ƨ±úœ†\ΚÔkç·²§†ÙRl÷ÙpÃCi ÈóBDŸ±ÿ› ÂÖ)RbIêIgNóÌ@™»Šy™ÿ˰/ÿW¶6Ș¬ZLŠ«Q‹±Cih\îDxÂFD( pŽ?)É%›ƒœÍK'J•¯S]®·~æßð×f -$…}¥úÉôå bN—ãq€“+Qr\ >O 0Q“X°dl 1@ø ¡ÓÖÞ,ËâW€'þùÀ=¶wЦpÔæWÁÛÖc ¯˜O³·p}…ú¸f–ö Ï­#Œ €@ËScrÇOÇjÊÊ}¦HIGs–°ª„húF@ÓÅw0i<Á–èÌçŽ0íÒ Bœm]ù2Éæ¿™¿eOW¿¡ÔÍ “Ác*tÌ\d¨^XäuɦIÒÔ•²†D<ôœÝWÙ‡JÕ hDÎ@¶%²ÈGmË|õHa@÷¯ó\ùó9Ï¡“¡…ýû/@ˆêô©MØ £6Ü€Z€có^Ò{jqøèéŸþt(`°Q=’'W4š£r9ñ}=9xøèû'fÇå™ô‡Í?{úm£Qbu8ŽÆØj$kN:XPIú6íÑ¡U4ƒ[:t6ŸÃHMU\ªJ,ð-j"‚Æ…3?q‹Š¨ïÁz‰ å*‚Du?éh¢…¡=‘¹R” A ­Î1Ç)Õ›4>e)Ú.ÊG[šKP/ÆÂ{<^.ž„Lˆ¦U£²2p\K¦Ø0Ü3s‡"Ó(úØôÉ÷/¹ŸKHn=.€›³…›?<­¨i"»:&¨[h"Ò¢“÷o˜»„„7fèd0Å»Ù8Îô æD¹3? Kæ(¤”ôÍí`òV,†Ü°•êó{SÌC@ïÙ²_YæŸg£M‰²gj£NÒ.¾ÌÖ:ò«U¥å‡·£ÞAèÕƒg¿ò4¤I@¤¬ªIãQ+cMWÏåÐòÿG QÛæO«Õûÿ~§²}Ññ¼òª§dc•üwXW®Ë÷ ÖD¦ŒÙd£$)‡k^Öú=×Õq ‘…OÕUÖǦؙ˜Æ/¿Ö‰ ¢uå>àz0+–B9oµþc\»Ã -‰›Öa†Ž|'®fĤ¹&ñ’­<Šž9ŸH>k?®e'O)Hþs6(ÐW¬ø µxLpm­)£Q!úßfÅttŽÔêZø|]©Ð;yÜwï^%Řý³G ¼n_ô@ép݃{€â“2cM·ÅGOž?{q¸ÿô½p+,¶†Z35U<›—ãrqI äè Šý»Ù2,m^ˆû¤[c¬6_2Ê\™&o8üúܱ|qˆiQŠ|ÊŸØ~±Èô’Ÿž' Ëj(¾@é`dåÿaîȾ'/}lÿc·'‰ÙÁás·D²'UH:¬ü,™‚i·0Ý>ùY‹ŽÐ¯wÍ5 ˆN3:!ñ¿Í(ÛÛñ79`SH¾Ám’¬†¹}u¡îë¤5Ŭ{&Ò›0W•qZ¿…žƒA$Ÿ|@Ó€&‡`éW‰¢£/}ÚcGìÀQθØu7Îb:’¡Â2Â$.ò)j]iîŽ}¬…„Ž"êI%ØÇt9¬Ùó«kù3:œâDé8N ­Q¸H)6ŠŽ(. 5­ŒÀ}Z/ù«1ã•cEfrñÂoV­]¯±ptXÀԓטâVê·a5ð¥dJr¨å &4‰Ã¹ÄùaÆé¦Ž¹Î&ËzA)sreJ¨˜UÁ æþªš2RÞ}Ö°;üû³Cè“|JiŸÙàú½’é6Ζs<à¬t0U{+ ‹î”í§y9F[;C“±AµðycÆžÏLí>’,9–¬¯.$-MêúšôË´ð&°£fäô|\,Œ‚þ®»PlˆÁò¹e9ƒ'5ÛÀô! 7HÉ@ö)3 œ˜Ÿíê—´ÁÝÈêFg ù‰7=ͽômט»Ä´Ã:ˆ’l4£jÚYÄzÁüOï†f>é\ Ç/kàRêö³›¸n…Uƒâ‹¤Mƒ¨›v ÛVpоÛúíA¨VjêAš± Ðýû›pÄ_ìg2àh¼@T…XcÊ©;àî? ­uÄí7ãtÝékÕ[¥>´Ÿƒ» z zÄ…ÜÀcº„ö=IÐëhGWÍ:—f÷_=}yðÂýça—l-?þçýõ¯ÿ}œ/NÎ?,Þ;þ·:þ{çóÛw¶!þûöÎgw>Ûùlë7[ÛŸoݹókü÷/ñ/ŒÿÖͧxïÏ Öû‹ÍíÍ­l{{÷λî¶XïìkøZ<èájƒBªTFNõTz ì»crÇ‹ê›~wxøÜQG[êEñýbè6(+.Ô”øìó ¤î8î‹ÎñØHнàeEŸí}BßcgM¾ô‚‹W 1”ÓÏà—( ŒŽ£t¡ÃÿóýÁËCªšE¹B¹è\‚†®1 %ˆß¼xö$ûþýcöÃw/²ãrä¾üx”í?}èV üÜ=öqÝØ¹°¯ e>6mŒ¦g±Ðì±Ìðžåß‹.4•°/ã¥!ËDh½(G×"Å:R½&¿/¼Nè‹a}¾\Œª‹éP¶¨Ûá=’7œÅy½šùüì~>ÕŒë†|Â2-ÄÖLxR;î#­ª™¬pÐäŸ/:»·È/Ó(ã×o“Q½å»·Ì÷£J?vkò_/7£™ã÷ÿkÿO™„¸ CU«A§Õ_k ÷i5Ýø¯—¾$ªTêHŽYë¢B+µª7§ëóbÔ¾Ò¢åÊB†Ð ƒE±ø¤&Ï(¯·¸Ë?8¯Hì¤dÆ-ðÞSZ^mN¬í–ŸŠSbhR?@ÝÁÅIÕtd‘ÏózèVÙ gÕ›’üì@áˆÇhðךA>"Ž óLʺ׼-kP÷L/a0Ò!¥^bLúç€Wžû¨.°’€äY-Èן²ÇSÄÄäÁ³gÿýèàHÊô$ñ88§I$Hí+ðÆº²4È;N…™ÿÊßæ/1lOüZÈpcdINQdßæ ÁF°W´ŒùGJúm©!å­§#V…£+Pùwvìt‹ùì¸T:0™˺G|óV”Ǣ,öö;Í$h›‚öÀM Oœljiå¿b^kÈ*ÿåú¦}qs¢Ê"Dÿ–ó1'L¤õ9ê`EMsè=¢ø#õè=Å­™ò#Qük-Ùø¢˜lh`I‹ëô„k¤ Ô`ºøÚÔPtîÏ7±ú0÷µè `Ø“v¸ð6ñ‘;ZÔØ­=ì©Ë{¸Úf¦}P¬á_Öm!†çú{²ª¢´­òÜNV¨ÆC=½»%)w‡`'åù¦¨¤›LH(ç·ôÄÉdºK©¾ìäH)0kd\[Õ\?Ba‘ózþìå!²_åR瑯ÐÐ u`ãç”XÙûÝá“Ǻx—¸WPƒª†Œ±œ`T;™ç *]’OÒqáÖ×mÏ û³Í£5…MOåô-&µ‚.ú^Ó{!¹ÈsˆÁ8P`>M; K‘ª•%y|sDŸÙ¬ÈÝuq ¨yoê݇É]ä|nˆ6Êz=:jDï}´±'°pmÜ·ËλiÁüS¿ú+©ñ é1¡‹©£œô½l{kË„-{2¤¢ŒD'ëàð„óîNš“ç>ÁŒ¢í²b½C!*Òar’ÿ$ü˜»)œ´ŠOiìÌ µ_‹ë3lÀúvoíEqê¨ÿùšàÀÞÚÖÝìû÷à¤Á5.§êy>Yzu±8½#«™—}ªXÔÔ¼²Q‘±¬ëU>¸ÊçÕX¾q[Z¢¡Š3˜!Ï:"bnÜÖx¦h#s$m"u¦‰žá0ò‚qê³fG/ù›ÜŸ´Šë°=bâ•ÛBX&Þd3 /žÁqΤ´ M™SD1®JñQH[%2âµ¹@Q4ïP´k^@™"J*F±"*5•AU"ÄX>ÄÈ Ú"aÚj¬»äi"*ú`¿d­kdœMþôÚ%ó9‚ùHMÙgÓ ü¹geõ°r¸˜nPu!’ZS„Õo†ž_´á0æ.Iž •÷¨VA~¼Í×ë^°§OåÀ èx)yÌ膫×Ó­Ç|M´Ýä4y\ðé@,Xd£úunO-0Áê5l!1³Â\˜«%uãºÑm;GªyÙf÷‡4L¤*´M¦·+ot7ôo‰ãW½¼©Ñæç÷¢Q΀ëôcߘsËŠ_“娇¤Bƒt2TýJ2Sa­Ã{'5ËQDÅæiŸ •pDÜfèþ¸!¾¬2,7‚¦-qŠé.§Úg$ß›]ëÑÅhhês3v\GÊé’uÉN×£™’POgö2vù¸ý[T PÇ+>1ô ÂßD‡ÐÎG¤3î5†ÏääÊ¡k»ë [Ç/å;a‹ä®Í°Ò2u¶aÇù©¿¶î&Ô.üÉ—Ù鸪æºÙ¦¼ù‰k»ðÀ‰‘÷"uóWÚ)¥QñƒPðW4wúMð·ͽK®–pL=ßn…Ûˆ¶Ã¯)T™tÀâíË|zªðˆ>¥ì£E¾Œ~ïfO¦Çõ¬Ãât˜´UDkj¨”’‚P•¤¦1¡ât9Èy7­.v$IC Ã ÀëÉs¡þr8.09­¿»i=ý eµOR—×jMT¦ÐÈU¼>’Ÿ&:ô#}RÂ%ûÂkÙSИô û‚L²,è2 \Ë0b["®¥»8_ÖR+ö’²{ZaÊs--¬¿ûW/ˆ1^cMܹÞ~yDM fÉÍ 3„P ƒ‚§´ZÊûè4c"Ûl|Maꔲj9ç‚’A\´h”SŽ\'ø TûÁÅx‚t¶ÔƒÒ ¿>㤨H£M÷¼½¸2ÈZb¡ó×ýÌþ¦~lj™W<{d=`#f¬kÁØè<~nmøêp€¦QT ºÓçVc¢*gX Üúâ&™æÇoE‹YPH"™jL®ö¥90Rlr˜š;¸ê}fÜ•ƒÌÄì0P,ÂL‡þˆ2€;¢çÀM-n ìhj9Úûnj5š¯ý°b­F³­\ú?š~ÇãªÙgYºIð¥Š#ý µ‘ùíã$ïòcÈPK±µåÌà4ûD;$g$2埫cM¢RkBÜ#VòäÞ¹êáÁãƒÃƒUnUkýÐL®n¾CqE ×w ’³CÑ-fìé¤À°¦EAÞôl<½Bp€zöôˆÕvõÚP8p“8«U7L o­—ìM©w×.qF†þ¢{*VdX ›åõD¦K«„ Ú|u¤ùñåìš4 '¯&é–ÔTLµ!Ý‹|Þ¯M2n¼XÉt˜¤ì¿†%´ükøÿ¿›Œç³“ú§Œ¸Âÿggëöo¶··¶îÜÞÙº³õøÿæ^ÿêÿÿ ü ýÿÍæcÀÎg¦âÛg›;¿‡Šo[ŸíÞÙq$ Ä«0 |5Am“9n~Iúd$0zòxãÅó›¿gR™À†0¢wܪKÀ¤XœWœW‚Ô…h4ò’„ÀBæj ˜2„‰¦6Ä,Û ’OX ^;Ú‚ÓÅè”’Öê©ùw4Ð]ˆ‹ 7ÍÔ¨nùtYM5•¡àµt’sv'è{è_÷”†€=¾,ÏÜ-ƒ“å} › ëF;¶R™-p”Äœ^¯&“P¶\rzP]Žcч°àŠA¬$F’Ÿ-–‡Uhƒî­˜’»ä3ÊóàP«mJpùž¤Ú©ßKHÍ„ë(Ä3‘M ¢*kñÂÿ(°ýá®1°?Ái·Îšðî4f@›²b+`]ßæåïeBÁ¦f”«Hß|WŒgW ιmâPe%Ò„uYl¹…Ï–ë–V£w‹µ®Äû!ÇÎw<Ïþñ%gí—m”CÉiò™6@Šì´’)Â@1@R¾Òô³óªzÃÞÿ_Ë)—†€‚Ê-μ‰LªºŠÀú,Ç¿ŸI±wCm¬ãDý°T8/ t#_ X2_HÛ¡iXrè«•Yx©ö|\1ß[½q_wÄß½>ÜnýPÉJË—;­_^¥¿¹½B¢j·›~æ:#æoÄbÓ6Ȩ™j4$¸ ”3D”È#«îvܺ»é8ªÙrÑQõìGd% oYt;JyèÒÉONŠ™»4Ô#nJôåt¼‚"¤·Qð qÂö1]Ø{øÖ óÚµISL izpv7nï|±µÕÏÝÎsB~£ƒì ÍÅSOOÐç;ÌÀšîRÿÀ œÌ 9@ÏÙ¹b8Ÿóp^Ò2òx±‡%/² d׫ º°£ {A™:xD®`ší6lµï·íüàœWmðB­}m9îzã¾;û8×UËÃur –Bâ¾ÄkLNê¦ãg‚Bpð!(ï|Z · Œ‡p,nÝ£I¼(ê™»6‹ûîÝ=²ÿó>ŽïB¾ÏQÿ¶7cÇ*Á¶ŸaØG‚Y·PÁÅÑJËA½ðp hTUj Þ&™ûJ”HßjÁíE.²ÿ¸9Mšaääå%\½P",ëÌdÈTˆö(ÄuŸí;s›}‡y¯À5&ÁK¸p²Î̆e N/|!ñUü1LÙë¸C|3\Év‚+á#ª¢Oö•Iîð"AA;šóši³†rÃÕüDÏd®ñÂÀµ&FžîÂ('>k²ýüÝ-ë?ʽ‚“ ”QãOúreÂKèÁ;s¨[sŠ.i{+®ªo+nBK#$:™ÔSG1G!M˜~ Y ãnüì3ó(Þ7×C/ûç?ñˆ—¼”IÚo¥ñµ¥?š¿§¦ï²O|þYc@¬›ˆõ‘É_ÿ“Ž¢ªÀ¼ÝèYËX`¿Fó¢8YÎÑç”V’tDðt³=.G£bßqâšÞ›i[QUsâÁ¯T (žÙLÅü¯ƒ:ÝN·%оµQ«—tùíT€ÿsN?¶šG/3ÑñŠP MsUÁ‹`¯äý­¥¢ë%ñë<ëËŒÉÛYë@6KO#²µOŘ³yµœÕƒËü¼ªÄàÜ7Ü86yS6w~ÿ‡/V-Blt EM›O…¾K$TÆþû9[üÒäšxƒ üú#i9ð£m|Ñ“ò¤havª˜sDñÕýQ_Ŭóˆ;†gÅ`Z,°ïzs~z2@ÈC@ëz0;Ÿµhgkk{ëÎöçÁ¸’ίDú"¸îÚ”lMòÞîPª{ÒÈ¡Ý\Ãq 4œÍØ‚³µünz·ðt_…Í‘·›Wi$ÿ.ƒ†+„’þú,¹ö+]Q"Q‹º·Õ¨8ô¼À²ÔÞJƒbu}¯Gõ ¾9ж<=JqϽ:åì¶vîàcÔ°Okå»rÅ9k£Nëí½”„ ý`Çò®Yã›»ÿ(BRQ ²ó{דú†Yxôú°ù-9Äé6^Òóˆ×›6²V<®mx«8Íu} Â꾛ЄÐ0kÞàh@s•bÞçú_iûý5að¿ø_Ãÿo9-áîÿåüÿ>ÛþâÎg˜ÿ×ñ;_ÜÙAÿ¿Û¿æÿýEþ…þfóÉÿï>ðï³íÝ­Ý;[Iß¿GPH#_ЕL†CΈé=Y wf9#nçû§<{x0±”äuÂW5'!ü>^Þ)Lœ\á%ˆ‡ÂÐ9ùby¬~ç£d(3rlž—µ”»âÊWö€™K\/ T-ë¬ÿ€‹)kFÂ6…u tUÀik\åðÑ€’¢oÎ&'H¢ ¸Wàð lKYSrWTÌ”“rœÏ¥ÆMÒ7€­q?œ” J5á€Àg²º±ß*9ù;¹’X¥Fhj+Ñ{ƒ’‘Ìói=fWE*‹ŠP¨s–Ôñ• '8nÄm3¦†ö¡yReWÏЃl\96•ªjQ˜ “w?ÛùàÑ£ tOàÅ•Bpæp³ ¯» þù9dK|ÐÑÞ(p+>B›ôó/fÏóùå-Ns ¦s›„èûOvL»9Vûp·² øÏö€²ò-À€$L?èïÀ þ`¼³µDg9‰æl8Ëo·³yôþïÿóÿ¼Þ\‚ˆñþߘ™%1 JP(£Û)ÆNÆx Á§@xýs‘bdÒ<^“úa6¯ŠMjJS¢QšrÄó¦>}ƹ ±—Ï··ÁŽyîè½&jt•æ¾ÂY0V8(ã’¤Aöª ‡xJx _ÜsŒ¢{°·öÕr>^»="À±óÞf~_ Ö 0”WïÀ÷ QßÝ9¨u˜Ì‹Ž²ì1¶4‰i›–½3L…à¸qÅzJOùLck”¶a·d²–‹ÞçŽ0Ô‹âôÎõqîΘ ø¸¥W­9 ]µrââü"šzÝÕÐéÔŽÝA>-Ï–4O^ÁrZ"£Þ‘VTõ ¥ì ¡sëºÇá‰Ü)Ù ÒË7Æg¹—oÉo\¼ñ„ÜŒ‰æéšÝ+&÷Óã¼·é^ÉEsmDÖ•ùi‘¹¹mk-WØÐñ]r¼Òì]öÓ,wj¨ÿ¡«Ù+]LÁŸ®óï¶à~”ÿÉËL¬ÕO²ÎM.í'\hþo¾Òžg³nh1YwW Z¦“Om·³\œnüžœ'P÷iz¶ïðŽc/; #M·!8¾(¬îL!zc)OÙ²}†ý¸è¯p³&„6?)S»N#)ãÜBÍ‹Ÿ\aº—F~”–Æü¥1ì÷Ùï¹ÉãÏåNc®yê×kHËL¶«k Âö½8xrðôpøÃþ‹§îåŠ1ÚÖÏþ»eT¶8Ɉ¼™}`Så´HzT¿—GnÒ‰L§œ7\%ÂYÀ:{S+ÝÈ#Ðk'šoƒÁ©ö59Ìm )ÈÚ<ÐÓÕþ9ïÙ%}ëwÐí®-ƒbá’´sôò…¸Â?=yœa†úJzñ<»åýw“1Åj̹H;4¤ÒuìäÜ‘¿šS^ÓyÇnR@º¡oÌËzmS‚ëwŽÊ}øÍÆïYFÑs[ŸC0‹Ä裱È1Ãvbp}µÐ ŒÒ©ÍdÑgÅj€v¢´™®QH¹¨‹ñé [{ ÙreJíN?ùÊÝPõÈì &u ,ËŒ¹½Õ¥Ÿ¨7(ÌFlYÑâ Öâ]C¢zLN°œú8AULh•M®ý‰—‘xÁúû'ñú\D»XD™.MîDN¶G¹ý$è5RD|‚ßz/cŶð°p;F”ÀÞZÕhöŒ|Éã ‚”Ž ¹ÿŸ˜ 'Š—c2Â3F¨çN:.n*¤”ÇÕÄûºÄR!~œ!‡PÍGè0Ÿ¿ÉºCî$ÑMôHå¢'J€!ŸžLf$ÕÏÖ^½;øæÕ»¯¿vÿÿÍZ?»m’cáPŒ‡)‡}ÕK¸ Àí T¡2ÅQq2Î9Ÿ«4p°ój\a™*ûúÙŒô8…ï£ÅA@òyánô¿Ü{G¹ÿúS¾·Ö=úËÚëO{k؛ƴŽZÌáך^qdŸŒúû$*›¶î9%ä˜*µ€Ír|ËЩ)†i;ÿPÖÕÆïçÛðkYoäõIYšÀ¸rÊ&GȲWA.{2á@:‡ ãû‹ÉÍyŒÃE5t=ÿ^6ÆÃ1ÎNð¡údçŸ46Ú]‡p<ÌlœŸ8ê/ÝÄVô‚½è¼zµ½·†Àpk\×í®?°+£ê #áã ÊMž^x’>®=ÝöÌåÇ”¯Ù®àû‡¾{øì[a$Ô©Œï­-ëaÄ>>ÙdÞ‹Žy¸ªæ=è3©Fs×Àèð‡Ïž>zötx¸ÿâÛÇ:_ác¿›ºLCÂL“IÀN¦a ”f7‰F2xßa€R«;¥=ª˜u¼ö³ËÁ`ÅüH㠦Ȣ;y*%Š`²çØúuÍcŠÌyXÿ(,Áh*4‘Œs·T æt66¸8¢ÎO‹ñ%§Ö¸¸JÕ¤ÁÑB9«êRtØ|aMÊ\¥˜Øîá<9¦'Ö¡©Oœ‡¹Í.œ`ÅÕÐ%éF‹³’Ô×äFB>/ý_‘èÆ±  ¨µ}íïjæàœª—ȈP?%I »³g\Í2À ô¹ž8dKåÔîîky0—T( ¾Ä«æÀi»áZq— ó/FZv7 ·^Ž;÷Ö"·£—\Öž«»3ïÐ^:¦A4#ORx† ‰à hиðœÛ…‡q i*«©ÉÔá‘`Œ±ŽM¾zø£´ƒ"i5DÌéòxû8O„$’Þö²{{¦ ýÃ×V¥Ôul|vŸ¼vg[ï~¿…^ש×÷÷Üû[±î_˜4àQzãŒíð›Õÿ÷moïQçÙ?~4wX{ßz^vÈ_qÂ…[ $ùfœÁ™Ä2èõÌñKhöd:bzˆ”€ÌŒ^þB®u>@UTŽI÷¶¨[Aܽ¯ézµhÝ÷sɤOc³ÁÕŒÀRÌçæ@U°^k€›{Ùga޵¥]Rޏ!ùoï.0üîþz[`E3TU*ZyFËÄÓæal$q °“áÝ  ¨ ÝÏX±˜KS¹EÕ[dKxihr„Úå ùkNµgÙÚÆ ´l ƒ8a! Æå,kSú¢[uöäÑ“ƒMtD ÀñŒ³¢ã=ļXö íî}¾j™8W’’€o —î»òÚôÝ5=)†š8.'¬,þÏÿ§^ ï@)/Öòµ½/ô—_9zòlvrû–£ïη¾Ü[°Q¬Îüôd£•‹j>¨ægà.ÿ¿³õÙ9­öfH`߯1wñ†»‘U£©­5=÷h¦îÛ ›ÚÜÁ9Y.6ˆ89_Nß°?Np”{_qPüˆ* Ó'}‡å™X…=¥„Jyâîça|·þ«i–sÝ‚j¾|Ë!Ù¡‘¿âš†äèI=MÄsYÊ1ªêq¿^Í]Ú«yDª;¬tF.àÐÕá/¯Þílm¼z÷ÅÁëM`€¹µ¢3N`X—‡³þÙH!(‡~÷‹;nÂLÍ Ê84qŸÿ.Û|qGRæ±NyDùî*{εSY®æë—.ßÌÖu£ÕÜ»’áðƒ6qRÔ žK?ØÎ £HQ].ü¶— Ö¾Ü{5]ÓÏOÌø©ÉÝ+ ×ú‰oÄÔzýÄ’/É–6/'] 2!íäâA%iªš[ÞŽ£‚æH?U÷ *‚!ê®PBÜ:¨IœrÔ  .ZÈz»–ù¬†Z¥Û $Õ 3`R¶—ÍŒ’d(¾ï÷^}Ù=úË—¯?í¹?þçŸ_÷ä÷?Ý_~´×sö^ÕŸv¿ÜsM{€¥asV€¼<¯»·Ø2†eçh^¾z… |T± %9n^þôµ†ê÷œ»‹¹ ˜¨›¹ƒ¥vÏvá+_gÅ»YF1O»ôl{7{ 4 üó(z^íìfNb›ÁZ±Çx÷€Ú|Ý£·wùÆ"õÄ-¯Ó¾v^cÐà×H5Ì',ßÑí×PÄá·W ;È?ô³¿-ݽ0bmI°Û¦>VU¡UÊûí×ddf-’3èª$>ŽÐ"HBB=ˆúXÂbЖ×%×é’bù‹9Ø €«rû‚>€gKðôZkºÈblöF€š†F¥\á~[vA«á³îÚ'îz¿;^Ü]#KYðÖ>Ÿ}Äïµ{k½X 2Ãþ‚'¥õ}–ÓP§õ]Á›QAþ.fƒ3°w?ÚAÀ‹p\é<îÁ®ÿ³Ö‘;9?=-ÀŒuì¨"ç/F¿”2ÌX%-¼íâ\û:zÞ¦­A$cºñg—ánÍz¸›Ÿ²Gó·eyò&ªjj£}°¥­nümEYl€-œ š€K‚ŠÓq9ëžIéOcb».@<=|tøèॄËriÓ3ÇÕÑäÑËg¬fϹ/ ôªõšúF¿“|†zúßó}äŠ&£]ì;Y+w,üb^ÍuÿôäqÏ€:ê|oï¢yt­³&‡Š›†}ÊÓS^*¿Iê! ZŸÎ Ð/ˆ.ÆÁÑîŠN§âo«rDh@‚`ú@-.JÔ.¥½£ïŸtûîËž£éûÿ¯|ãï[p¤þî&‚Æ8¶¶¾íÛÚúþIá2B¥ÁU4+Qü‚»‘Ÿ–ï€ÛpϹVÛ:§÷±¾"ä‰\ O=~KÞ\¢€í¬B~ÝÌoÒhÒ*ª©¢’[†äïq„ÂÍ´œ€xxæ5Eï™ß¾ó$^—sŠ×…Pù®] íÏÝÿoÙ˜°‡-½áõRÎ@,F„ú{1¯jhpتðâväOg/’)íx",ûËÖ§È#tìî%’òyym¯ Y ÿ^b^…ªbçón¾jÒß§€.+ûgÐøþýìó^·ÔýpÃßÇ ?qPoÓ»²g¨À—îûAfaçÛ;í½7Æ©ƒhû§×öÎV븿IŽû÷×·›â•oNõ=æÚ˜l`°fÊ12wý-qôÓ4L‹¹¡v±:ËžôHëb$zkE¨Ã„y&øgÈnàÌÒÜ©@?¦Ê±9ÈÉ©øÔ g¯=41 _EZ“-‚’k¥ÔŸÑ0u;Ò'@ˆNXÑ2¨?zW®‚TͶ‡"™ÀŒiz\ QÊN-„e­2 ÈËÚæÑ+·Ýà¼ðzsÉ Õº×ù{P¼bjžh=Û–gQ¡®ög[¢~z™€;x°Á*€¥&e)b®„Ê'sö ®ì1ÔçpܤÝÅB¾ãbÁøîµ‰…¯Þ=¸íV}Wýs÷ÿ¿‡?HµÒñîr®3èËpÁ-êÅô¤››m D?ÛYø7ß ±L¨¹A1àŸaƒðXüÁmÐ`ƒþðlPŠ‘Ãý2ÊŽxñàlÓ¤02è Åíï?}°µñý§ÐáÓøñÍC|`ü­±`<ÜHô—áŠ4»õÚý_h®2/@\þKv{'`Nä³rETL5yZíÀÖ»—'ø•EC êšV& ÆISošLù‘7ÉM¤–'Ùn B#{nbÉ·Ûá”– ¶ÏÊâ„MÖ<`1žÇkwKô,H'‹ä¸1Tbµ¸SÖ\\œçoKðìªÑo¸Î ÄŽtã }˜?‡Žš,Ù°Û­³7S£ÃÙ$€lËKvŸË¼CÞ^7ê~ zö1›Ÿù;¸ÑRåf&K'«Ÿæ5»û%ÈH°ë¨ 'ÈÙB Ÿý¤¤EAïðìK¤6‰a€æ¨å•Ž0E•Öé¦4ÊÜÌ|SryÅZüLÉ£ðôÔÉ@oßL˵SÝch*«fá.A`Í+Ü×U¦ïÉ)BŠ0£³ŸÆ} X0ží» ùÎçüƒß‹6šÝÓ€œƒÔúž®©Œ] J¹O|p$°bGÔÀöI„%°È»b€ò÷Q·¶äçó™ó,³M¿÷Þ‹[`%ÁK›×]Y‚æúR÷{¶ÕÝxíyQÍl¥×ÿ>ù\¹òÿº•_/eÊÔÕÝ[Óá–4u6È:žac¾‰V+Ûȶ âÏEcŠwáî{xˆJt>Ͷ­YT£S¼vÁ¡þ *™ —Ac6´\Wï}ËÙcbõorøblÙšŸû4Ê¢4£Þ>¶]ÛD»úPîŧ2±'¿À4x,aé¢Cyñ=XòE8ÉßuÁe¿ÜЃ ®^L&Úiä)'P°ð'Ìþreý·­Ûwv ÿËg_ÜþâóϾ¸ù_ܯ_ó¿üÿÂü/ºù\ý+¿mcö—Ïw·îìn‘90JþòTÁ?öŸ?"/|ZÎ pi3@eû~1*NÑPIo³Gø¿‹ª¿)Éáë«  ñ³Ss3i昷%Øã¦@0 ë¢æ— œaÕŒÉ|Wñ3ž„ŽKȘà„F4âŸÌ+Î(•É•¼¤h*‚.Nçêê9{<„CV%|b(ׄ$ÀÏ Ç¢ñmÔQ‰:,×í¸ö¼æF¨­¹@G’š½]«šd3 ¸¡¢Sc>©«5©ƒ’PÐyƾ}¨ßASŽÊ©Á­Ð½â5%7_tfvã/¿þƒì'5áåÇ¥Ã={’Ÿ•'&âk’áRÀÝ0/%É>J®·‹jþ¦Ö AY=AçiÄ~vì¤6ò§-9±Î8ŸC%ØÀÚ8Õ¸)¢\VAN Ø¢´g“j~ ¨óœ3Êûq¾ÑuÐüÉõòô”ê5𖵸ìÐxJS¡½|NÙiÞf½|Õpôð­Nù\½šCìæRò)–2›]–œ«ƒÎà!µË œG*E‘7á¡]¦ú³8{´ôò–bPôù¸)¡¦AÄdÛ”T=Dý7äs¬™ËS@Ÿ-àv~y\°¥äXˆÎÅŒ%yx:Ü^Öçá²›4v¬÷"owi‰Ìqõ¼„År±hŒÃÅ쬊|CYeF̉Ê7^h‹¹ãªQm•Í8Ä9Ǩذ؞ÀV;{8ç“ ò”0¡áÞ}_ô¼¼ "6ÄWO„Òî)úpÑ1ð¶êÆw;‚ tð^ ¿{سιx¼ V2õ¡ÇÏ:[G„è]zª†BS¥>[lbCvŸZ×ùì…îÔº¡– mܧ ›ƒÎ|;^Än$P—6¯6|’¼ëzƦx„MŽ:S̃Á»ô€Â‘Á2ާ˜…!A-š)çWDÖw9ŸÓyõdÓˆñRó°H…–˜ž"Ó×P PSi=ª$Âð'ÝÈÏžjÕ°â}”ßni ³b&r ÈüöílÔ>~:$äÈ:ƒ˜oì <`÷ý5[+öeˆãÄ‘e§-t³ÛÆbÉ…¼2heF¬>ÒÖµøãç%T°A×ðG“îmõ†/p½ê&×’GŒxWW¥îÜ}`„% Þλk~ulç¡=öÄj0÷Çò\Šd)œÓ%îHÙǪr6¡erx-ýv]j[z¡³m‰¾È/k¬»æ×ˆç>rK>•t˜aä –ƒð®ÂH€f¹[XáP±¡@ŸWÔ®wNBÕú¹i•€[hü”i´ø´Nù„öºñ =n|bŠÐ¹\(j f6&Iî@IT Ýö]º¼\ý`ö}žG_ÇbË*1Ý$,—!|×ô¸%Û‰…þkëßð!ÍÕÜ÷˜4¨Û ¿t³æ6xˆ=c‡¾ºl|%PƒÏdFôÙS×™#IVn¤m­ÒCìÇsÓ7½ø2I÷ûãû» 'íesÓâ@¾š®$F$ 4ˆ $E«s"HHƒVe`û@Ç2ÁäA”AwЉÐ[þ×SýœêŸü0£_ä¢Ã³œI¼ìû{1òƒEŠÑÅ¿Ôý’…âÛ¬ñUƒ|¨ŸqÏ’& ÌÑ0÷ÀåsÑ›”Ó®.EQ8 Ã퉖0ŒßÉ“á‡Ø‘ltŠÀÅ#ãžü,‚®n]A'®I¥šÄÁª†M(ÝhϦÕÜ}:÷Xÿ͇õ§8­sfõop\v #‘Á€ãKƒ>aè8›Ñ¿×†ó ü÷~¼Ý“quò$枌--4ÛPpà?q6'?«£Î$¡RÑžtþjëð_Axf…ÙVÁ¼Ã/rhùžQb/r™s»šoÎQƒìr³l½#ë2‚:»~8mëÝééÖÖé)›)Ï o+ à ü“º9‹â§¹fhÝZŒW¸o×\x×ÁdìàJLNuâóƒ9 1!=…S>=µ€”b ]ü{!ø;C™*ë9ýÙF5Á7…!P}Õéãüɺï²ÜÉð¤íp/?îe+Ü{vi¥èÓÂM_¼!Ã~3èò~õcv0ż¤k¡oÁÍæ_íiñïù¯áÿ#)¢B Õþ?ÛîÝöo¶··¡öÓÎíÏÀÿçÎí_ý~‰¡ÿÝ|tÚþl°3Ø7 ?€ÐÖN¶s{÷ö»Ÿý>YJý€žˆÏ‹@ôÆ ¡*ù¸\D–÷ì9ºäþ3Q}ÏÜC§ôý´8«%Ýbꋨ—´u$§tM!Ì¡z³/1Ñä-vp¤´ê®®~™PÀ±}C×á†õT;3säíñþÓo¿ßÿö`øôàÛg‡ö1æÓgO$‡ÆŒ«Ç¸j4ä¡×õ—ëUûÁÔÝþ€ÔÒACÿƒó½‚‘ø¢\PAìj¤ ¤0ˆ¥uœR·i¹vÏÎDœ|”‡Ïžì?z*p¼×,¸ȯÀ%s†™yö(±ïp9û¯6î*ЮDš“ÙÂÝ'ø¥$«Ei'iwׇ/^üñàÅQ20 ¿{öò°ƒI,¢Æ¡3§.p¿ínµï¿BÏ÷¿><øfÿûLJ»×h+k §wøíÁáQçon&”9š­bÞu“‘B$'˜j–nù*= „òó%”QU[OÀqU-À=m–ÍÎÝÕQ Ãr„¬/:"0xïfcLC…¹‡Ì«]ëŠB›ÍÑÞlN©ÏËS‹Îëx_ùÜ¡7æÔrÉcsSl³èã±L¢åAW?%ä Âéuœ/Šãe9eëº?Z/N×s^L  ÐÀ|iö´Mvñ‚•¸jR ’­½«QÐÎÅÍäÑ)Ö[+ÉâJæÖ-.3IQ`ýýäVœp´XûAµ9f8÷W”(´€xoÜ_ºq¡¥qÏÓ<~-õjW4µ]=¯. wˆEœ-6tÎ@‘LJ…f)4Øo†Ç ÛÚ¿ííð‰<¦`»ˆÐ¤B½l?#eÚ)ËL~‹Ôºÿ•$;8½4¬¸­îGS³ùéÜÆ»Û¬í^ '(±/ci–7{[æ$ùSóNÍýf¥_¾ÅšÊêÝlí|Ùwç{cYßýÛÞÖàóÏáþyû6dãp¯ýÛ;kp rXôÄø–ÄVâð:ØðààùáP‡¹ádg¢¶Ö‡L WÁ!ô~¦»^bŒBæþ{ »ô¼üôÓ ôâÐ6¸«ÀÕ¡(Ñ17Ï$å0ÿ…T&ÏÀFIl–@ùÍ p„G”&$Tâæ¿Ã±l9^ÖoÊÙÌ“&"° ÚLJL‹ÓçOòº^NÈÚ]@¾‹²ñ™(^|ó``’IS·öQ÷(ßøûÆëO{]·‘Ý£­?¼z5p?{_~äÖ˜ò§…+u´^¾†$ñ§¤Î¢k,Q ǽF 2m>=»wT÷t\åNdÕ‡îrÚlEtéGsNŸaý „/\‡è¼.· çQ]ÍÍÆâ(ÔDp8Ǽ®§hE1·3¬947W˜ fº6ÿço»ðȇ†ø¿%²¿xzØÙî¼>ÒRi`ZÛFÎBª0¿˜ƒƒû÷/wjqï–Ë9{º?Ùsï·–Ï ¿E¿a°kÃåºàÃÀÛ‰r­†sê¾ûÉ:0;'‡æêPð™7¼rÜ¥ Ts^@ìÀÛ,à«ßƒ¹hmÉàzT@%&²ßÜâ³£4Ž {àjM´&Ò·èZ€ä–C†Ñ™0¸õÂìSÚ¥4 X×Ôk+ÈFáD,ø@‰Æ÷~=‘‚#Å=.ŒŠY1…‹Š¸Òœ3bî` 7,€Ñ?Ç£¶-ƒg„˜•¸rX¡Œ"å"š UêˆÙ½ýZ äÇu5^º²CPD$¼se®O»’q·|õ‘¸™¡M]1ÐT Úu¥)–à „'Ù[ÁÊ­ZAÏ*í)0ÿ4\Yeã9À…4…µ¨PpuZqÍ0(U2¸ÞäÂýÞ?9hæò£@?mJ¯Wì ÇʯØyÄógÖÿ4ôóñ“†ÿ­Öÿí|þÅçŸí€þïÎÖííÏoþ›­í;_|öù¯ú¿_â_¨ÿ“ͧð¿Ïï€òï¬ýÛÙÜÙɶ¿»½³ûÙçÉ @U»˜Ò@N2”~M¾Ú÷Æá`¤ÉÉ&žêg[ ¦ðÀlŠ6.i߉Jb&ù(©Ò² %zÍ$†Áì)ß)ˆ†ŽéŸyŠ¿àÈ¡AÅ Œ%z븽Ù€Gœ;¡p>ß Å¼úª.Š—{©‹ñe?õ¥ùÌ— óý!›˜šL؉ɾ)(`ä *=¹§‡¼`X†"«¨p:¸S±S$ÛKJøÉ^…8EÌŽBnÓ¸£êÝåx>Øj˜»¼K¯¾r-=nÐ#7&ßåP„J¡7^Óu½ÛDÂ܃°×ÚM±âz>+ 1ÝP‹¹ZY±2‰”ÏšûwkTÖ³1X(:ªuŸÝÝÝÀq©@B·PsòJõÕÕO.eqoî =}ö'«A%ÄvtJK !«Åhy"–uŸF ‡' €I•T]Ë“" x!HN7Ášâ”Æ9bÀÙ Fh˜m®¬Vƒ<AR(ú ôe¼^8'×Ö±vsÉ‹Šs¦´ñt„ƒB~2 *}ÅÙ‘ÑÑŠwBÕ N–¤ÈYv›G2aâÞâÉtÁè«bŽâ“ëÁ ‘;A¬@j,;þs«paîE—êÌ -¾!°|qIcÃÂ…ÐÇ ñpŠwÅÉk;Æ „`þ6,õAô@Íè‹ùòd±œKLC-!i 7*§Ô¼FÿÌ9)oÉ˲‚:LȧRâPnÖuRñE臜ü¯ÆåôTpçi@³ÀŠîç&Ø€6GÉÇ´¹¨få ñ5¿¡R´ä»5Ö`Ë@a(Øu|)%ÂÙ²tÒƒíj³ëu8 1A7–ãYÅ%®<ÍE9Mug'îXCÞ €¢d ù¦`úBwŽß–Õ²FSÖT/§X]l[Ö§ŠaME8ð#8P¨Œ§ÃÎÇÉò1€"‚4æ:ÖW©_9òÎŽöÿmé«Y³bP1³¨K?áˆ^™:`5vÎ1®ñ :  Ö…;ou]ÄOŽPÍïµ,G%·À¬`~"…ÇѵK!Z]“°¨Å¨ðÝ×hÀð¿aS)ÀŒžXGÁ` ^U—&ÒÜ­æ^µ¤%am%”Ç׋çD‚§yª1Iïg>‰ùÂãFûT NPtcZ1cñˆCÇmÜ<†‡OQG‰E½úƒ@•S*. Õ¾$Jø® S’GÿI:©™ÎN¶“]xñW®l\iÀAB­ä2êg¥ìøJü³>›¹0#¶ç]ІW¤œ÷Ú—/ •Í/_:¹D÷o? ƨmPKۑʯn–ã-å7™dÀò »þ˜9>M åc'SŽ. ·æÊ¸ fšçÇ„ÜU½Ø B»Fx^X5µ—П֊ò´ Åy1 o´,^ý•ËAb0«wV®[¹Ø+ªbWXžõáóg/%ÞOhü ”ÃH˜Þq²„V&8DÛOYµ>»”K’èöÔ].àªÇßõXBRÐȘ€‹˜ )ñ2/"¢¡¹°ò;ÿÑT¸;B²ˆš2Õ–YF*ñL7•Þ1P Cf4—örÁŠ}GÐqŠnDŒè‰*Ü,&Ãjuøl±q½ñ•;BN]Q®Øv²¡â±G…S†ÛÐöaß"V/PjzLÐÅ9.)¿0P£Q9_}Š¼à‹ºÂ1nI¨@!º…‹êv䜋êz‰£ )òÁÊŽ§…³ð ½DžÕ's@è¦^€ÆëAó;êÌÐC,‡1‹S"ýM%æ·6×E˜¢§šZ þÐ ˆ3€ ?î6Þ@jѽì3iCözw`½Å¿è+ôTÛ(Û›Œ«î0ÄÅÓ.¦oé½D€èox°Ñd“Ñ.\cå¨;Y çn/P¨/‹^øõQç·‘²½¤4å!ͨ{x±ðSHHFL,2nËrª´Øãน`_H¯F¹gÊü–(”T÷vØ£Ï8äåÆêìímeuÌLs›„·Ëâ5QpýiuAƒwgœj8¢¼BžäÒq'¢Ë:àu ßÚ˜ÉÉkÀTíK:Diü¨®³‘ø‚¨ éþ^’®E€}r9ÁÏ•z½ˆÅØ&¹LÝÝ+‡·$™L„­„$BDV±Z¶k>1`¼t+À-\ˆkã%¢Ó=4Ô•wßTó+Ž• ±¡z‹Ôàªø­ì$V®õê ½)Œ}ƒìëKJ§Ä#•.âˆñ2¤: p‘yŸx&ŒØkã¹3Á²ÒLÿ£;;Äð>%¢ŒÒy¸>žTP÷ª$Fî´q±W$k*åèÛB °‡˜8cƒ ¤ö©ç˜vŠ>Ô;4òƒÏô¦"6Ø]ÙÜp¡ûHXeÊêUÈßf Iéù?£KÞrD'!3!uiˆsÍúcBcѱšnª…n˜É¯B÷‡^ÌtS”jÈÞû©É!$2Øiâ¸T¬¡ú¶Å…fº†½Ÿ‚ÖɵçŠÏ·˜pNÑÉí2–„ö:<,šy§$ݤq‹Ò‘€äÀ{©´Oµ^VHð–4‘Ë»ÖDuù4Ã¥äkÐkPm€“qý,Š TøP¨¾ùܲâCÖ÷£$|X‘Bxþ¶ Ì%ßXä%éÓ>çù+Ç­ƒÙÍF‡Õ¯çÙþwûß)i€·`-Ì2¡*Z]Ž—‹' Ÿúo–~ŽDDĨòú›¼ÆýбÔ,´ÕT$ò³n‘:ÂësŽÌÑn-žË4n}Ìþ—º¼ ` à•zª§p JR4Õ"ƒ,V#€ ª§p«áð`¦99_1VÖÃk›íY:—'oŠÑ&Öyí®eâ“t¬8:„º•;/Æ3,.NAÈG þßuö«2ï2Ï +õÚò!ž³Ýæâ SÃʳ dUBIzä¶ûJ`^'Jýsëgãe¦X /=ô -Ü›)&]%EРï3r ó† @̨Ê#ê;F,Š£¼œ ùåq8p@`Ю‰TxÙ;¥!Ÿ­%yl0X:ö4‰7XxTjÈ*ˆâJRÊEpG`(4ê€Ðà5¤s S¬X ® ÄaÒñÁÀO'R"3tâO—e'uÙ¢euw2°„hÃhW´¶pŸ4Ù~S^÷™ãÑY•‹^"èË= üÁ…¤õ,h]/aéë,¯ƒ  •n6ÒüÑF ²§ìf ¹ÅmEÝ>ÇEä ‡ÜË…ìDp^¢.N+MÀ_̰œC܆”%Р|ˆòÄ;?[5“îG¨&2Nœ™î˜¨¹à¡)w£TÉhyÛ´2ªŽQÅí5õ0¹%šˆ>8F4e»©W‹’üC+7Bþ|Ni›Œh'X×ÛBdQld ¢è8ÐpŒ½$ÒÄJ‚[KYP? Ô‘Ô‚Òªr°ÌWIÆíËñ¸PLš q ¿á’¡Àª±Òšùn«6…!ˆX„šÐ[»e‰|Ycn(£sAÙååtš6âp¬ï ðòÖ±(ãöȦ5?¿ Š¿ Šï)( .9±Iýç„&KÏ.Xe”4´[·56O/1â`¦vš_ÀÝE½ìþݽ]¾i:=¢î“œ™#‡µŒ´Mô»ôÞJJ|`ÊçÕqµ{²ªý$/Ǿ=4ÿŠ7p¾òS˜2} ]TóÑÊæÕ »+âåC…yBø £yìšmeä¾Ùàëdí­Ü”ýGÛWŽœQ‡à£7äÀ,¯9€ákùïÌ;5m}Jù X Ót·x]]vVî W%€•zr‰\¹PÇÕè’Z‹XŒê÷4ƒÂP­üø¦ûïwåeþ¶hÙœãPi]'2téôpBS °ÒvÞZá{õ!BqÊšZ÷”BßK(I1))o_"7äé l %åuͯÌÀ/Ê ü ×÷.FÒNiÄ}úbã X˜oqÁÇ•B XÍ ºP¸‘3C‹š¬´­.í6•j÷D»+*>[6Hw¬Ž¶ŒÕ%p•ÓBÕ¡0è$£€™§òÍôd”­&Íø œŠTµ©< YI±¤ N@0?^ƒ¢ólÇ3È£TEÞŠ:…]T«œš Ê‘Èæi` ÏDù›Î[“´ÁN®8&¾ ¾"ˆ7S§>y1>E‹7+Ó¹4B¨¤Í66ØoR½:Ê ïTiYޤwA©´—=»”o>lìΊ“W\ °È£!7P¶t^ãÚhöPdÐô7?úý¤¥`çÑ Ã%Ä{³Sʉ¤rdŽ‚*´ÕH..Ÿ¨²d· 1éÔ&Æ·\É\X‚AZ–fyêÉjy¡TZëv:S¯¤S Ùçä¿V@QµqëN±¿(Rje3`;ûŠÄídÙu™Ò,)¯1lEǦHƒQÒè>`0F¥í5Àâ:†/§!àdñ`R’$Dsˆ³“ ®PÁy„&è}ÂeQ9èljþosðõʺûBÞØM…<‚F#@*„×á‹\`m:ê#Œa‰ü”[à 2§³ÊÞ~QÚã×n)ûô‹9ø^´D/+V”sW\•’uÝÀi‚jøÒa›Qq?{Á¦u¨©gü¡ùûAf¦ÅüR )õ‚y Fþ¦]¢&ûäH¸á+ GœùvJ-9„°FT¬Õo@ (OÆ!rPäxÃÜŸéÍk×,ðŸuÔª§'4ôgf*D„dRÌÏŠkIø: »WÈ{éÚO"×¹¤-J}ìZM[JÊ|· e½4óàÌ{RÀaŽˆ€X1 Sp,´‚bf+Aå[pp•LÀë'#„ 0~¸» „ñw7Bc¶ŒF7®i¾ÏÉDÈ¥d€t-Ôœ´¤\;HA°?´ûšŒ)Þ%èAk(=ŽÙ/Œ3¯ Y“[N¹¾(ß³ º@N3c,¿¥þéÄœŒ¼{ê±P¥A1tÂCC×-±WOÒ ¿gïâUö–¸h ¡‚Íà¸ûÏ™À9wóq”©±5Æ΀gŸ—0L¼éú>fóå#aÙc.áŸ骓’²Æ$9o…láú2= h˜µ¤^|1s.„$/2Ö°slIå–Æôf( à{Éb3®°R¼»iæãr}/ŠYMªf5©·jÒàö=ûn4‡}ª4K’ +(ŒC F–AÐp‰õlÕ—{¤nMî½E ÿ„Åð„Ú!©% 3Š ­9U‹F1¿Z/ ù…fPºQ©-ªÿ ,nf|2’ˆòÖ¨z%?vrÆ-1‰vÛܼh4Š|Ç}·Þµ095C ½‰cƒÚ_Û ¡ž¯óbÍTn½®kï÷ñQàm9umÝý"X€Ó"²¬2÷ùè!wÈ}º0¬¬z€ ZŽ–6Ö ”†Ø7I&à d+‹EÀß±ß ±#×Q ^}xY1/©ÁHB±â¸€#D9ÇŹ$ÃïIØÍÏÜ,åÈÊ÷œŒ-ûîðÏiâr—Ú…Òqµõ˜“Æ…+IÁ‘,"‹Ý@µÒi% ˜ ñ-ˆhdþêâÓ•Ê-ñOƧ<ˆÄð‡Xõ07ñ.¥³ g$ê"Õ=B­ý£HL'EVï–È<6( D%Drjdø_Mè+§TµZ:I ìcPLàìÜ&Î ÓtQ°G?{°ÿໃáÃG/÷¿~|ð°g+|Š45¾ž„ÅQyb•Ç%ò ¶7å^+2ñÞm‡Û°¿'èÍþ:Žô˜IሻpTÙ©££‚P 2Dy‚þè’£auyì7‡»Ρ6í£ßxŠ0ª00Rò-DlÅQxhäT›X]€éĺå©üj‰U¸¯Ið1hjßz]Öéû½Ob K¦ÞøØ tA€çE´÷œƒ’à,ÉÌíŽÄÅÔœŽu=Ö¼rŠ.T m†ºd„á—c²€õ„ˆdêKλ†#Eàñâv«Æþnò½„ ‡zýf[¼õÀñý-5þ(uš´r¸¼O6ë™›ãN´r ZdÔ#œRNoÓÇMØo¿qM‘;sœÌœäBHPó„qŠL&nÈBÕ€òy˜EÔ€'Bwäï‘Û} Ç‹WÔ›½Âé“6­âCEÚ^Ûî©ì/á[­äÞ?t:ÎÏð§¼×貿0ç•¢” cêÉçDËâ£PlYX?¥Ä,ìGúȺxëRØOÂ:uzq€W Ž»{ñÆ£BžÚ¯›¦ks-øØ'¸µ S+)Ž`@ãBn¯qtß+Î=í±®ÎöÐÒÒ‹ö×P’䩸ò.oiÐtü‚*ÌÒæÞ¯ßÆ $ó´zÉò9ÙëPÕæ-hD­PŽ:&“Š[6ä„/¢Ô9L¯0<÷Òk/b‘PUJqc,’c½(£±G­úPQô?±—‹|2¿ÇvÉtÿ ¹çtêæPŒòžÞ‡|âƒjÛfó!×>OxVˆV%š™»ñàHb¢ÐQk•©§ÅÎÛ.,6ŠJÈiA€×â Ý ¬Îö iýPЊS‰ð۟Ư"þHåU>&< tQ8/G‰:}}…\W÷ûñ­ÊÑ•MÐÛû‡C-+Êþ) Séƒ=ïK‡¥RÕzŸÃ#ƒ$$x)´| þÅ ”ÖÈǪf]X1ÖLÜt4ÄTÔÑH¯¶ôJ6¯¯gèñeÕœCþ‹"ƒæŽIÌ M°¸%²éYÅSÉ õΗ>7sôÎ1õœ_s“ß=ÞÂG))^É«‰ï7ýYýrPºÞ¢“÷fÇ ƒDôαá¿ål®CE ïâÆl­æ™`ÖÆ¸1Cš‘ çò:ŠÝýÀå ßmœ•xr1ž‡¢p [*ž¸± :ðçÁéõ×Hß¼ÇJÅ''¶ŸÜ‡’8r«d D¯…mZwŽLƒjý–ÂÖ©é´IÐøt/ò-M¥X;"ý¥{eRt¾ÚL¥nKUÿÔ‰µ8]Úô§‘]%12ÖQ\\üA˜Ýáj…ñ¶7¡4Á›Ðóíñ’S‘Þš¹žºFä<ÑÚÈS£‘†™®Ý•j;¶ò|' mðeϱôÔ›Õ ÜWëì¯Å8èãËyqš©©a}_«Jˆópha /!ù p} Œ#[NúÓ4¬"Ö=É/ J%—N½2—ä^ 1DɘÀzÜ&kZÁ8©BöÕ¢U»>8®D«2çým.¨ð+Ü]yrÔIÎßìpÀ½?5P¤ÛÁݸj K/¯Þ0¢Z‰¶ÓgPô¹‘Èòä8-žØ­nj*vMl›8:À0?é<;<¹ ÖÎá¸È䳌É5çÏà“pEB*y¦x¡),¼…÷ÈÄ––L~nfäÒ×ê¬n·Km#¤µ 3$˜xV¸gu#¹71ni”V×Êþýåì× !½&ò=-‚a>±îÜgåpcƒWÞ úì° ­K#‰®'ú2iXØq¢ò€Ä)qL |œ³ãoÏ ÛJ<§Ë16ÌÒ¨<—kÅúHŒfÅq©+Êe‰kL¤Jinõ fö[ÿ’(¯O†I]3G* dì­ú1ÍŽiQî KR»óž–É_¡½–PÔ0á­B†ï(- Π á“œsÁ©|¼ (C{}¡>;ºK5í|s!à¯/r|Ô%Ö¢ˆgý˜ãù“—…¤ÍA Ì@¤‹Äjtž`AŒ¼Ûˆ[ká©Å†Ôµ}÷ÁGýQd( úø¡dÆê6íŸÍÞµ¶DZsB÷ JoùhŠCH+]Í^̱ÔüåM'ŽßnEMÄf¿Y%Þ¢¶ÒübœRûùmaSìË4¢Ï£ÕH¹ï¦²Ñù×dÑX y`æn™²ß"T8%CÙZƒ¬ÎBÝ.££_Ù£5-`Å^°Î9Ë/!È^ ì'¥•9´òªÝÎ÷Ûwi9ÑiQ8ñ¤õÑ¡†!NŠÎ\ ¨<‡B7’1IåÖVÐÀΟ’‹u°ÂE,]À1ÀPÕ–Ù* A€‹-Ø2¦”„5®i'HáXJu­Ö›ùbý¬rÝxKv°×ÔÞKÉÜVßXñš^~¤Ê!_‘±ÂhËMR‚;4&o¨¯àî°Ã€à²fï»øe¶:pZ‡Ž_Åa¾¶Ê‡%¸¦ÝÔô¿A+_4 .FVÃâp$¸š‡…ÞߢXTûåÆ@Iê8Gj~;Éß‹éÙ-iÀÓïN0tƒˆj]ŒÉÄÇE„È\]jš,©,¯)æ‡í°†œ·Š„&ä€EÎàyTó:>‹2_¹ú_¹ú[®þ߃¯1ä>fþÔf'@eš¥ü"`i’þ†}ðh\Ö~9¸V¨Èœ4€Õ¨ÀL Èr†Ú¸WPsÜUÍ‹Âä­ç€ùèóur^ŽGî,q*)jTyé§ÒÃÊ‘îà&h¼´9‚÷œ<~&¤¹m©¨]:‡7ý¿›‡è_J%UbÎKÁzý¬f»l}Ù>±Îo1eàУN,ÔG£:[È6ïÎU>êGYïÉI‡ï'NjŸóÙò®N4šPB ßhª*+½òíJÊÜÉ] û×¾ 7eYðn·@¦›8îµg— Ã&Ú ÿÛV/`4ËH|4§uÝ aks§çÁìÈGjÏ´½qøv¯—ô:ûc1‡Ú¡HôX H( NÓ$๻~M|Ôfa>^‹äR…ã \a¸n°#ÔvÔ;hr(Ù—DMÉX?fL2màû䪲ƒHbm!<Ã<Öô™²›Ú~Ö¡56ËLšð߯ô¶bS;œÞ#æÌx‡’”i;½Ä§Eö²1„tÝI±–ñÏá)–m›¶ŒÇ{©ùº“€NBI ùû+æJZeu`¦ì YÇí=E"¹{¢îÒŸŽAÃR²Ÿ!øù]Ó¹Þz< ¸àÞ†ãK—Ù]ÏcõÉql´£áÅ„MžWÀ"©P<*Èä²ç7S<ù ðUgjÂè< ;û˜ÿë8:Ã<:sø¸ “·ÄÏr{ýì‡ýÃß=|öíðàÅ‹g/¢¹üx+õwˆ¡Éýhîs¼AÿŠÍ¹ÉÆ||iNˆ×/½S?Þ²ÿõV߈™Èq¡.›‘8I¶MTÃp"ÇX`á—b´æám°âåÄ3y(ŠÁ±üs#” À¨*Z¶Òe¢5†@mùýÌbQƒeÍ"nÞ8ëb#«¦ç³DÑסnüã €ü‰€"¤P³¨?/Í›Gøü„+„¥‹+¿@z)"P|…5¤a/ oyÑM¯h?ZʈˆàÒ¼½)nb;û˜r;¬¢J~Þ{ÇÁ8T Zñ‘K‹ü΋ô§XÊä^ɾƌß~O}Á‡¤x¹‘Ï"fÇô”³¨ôÃ×STã``*WÝÚ £¥Ú€H•רc„_pÒ¸µ™ã óx »DÊd\>—cìÈI‰ËJ_j}Èÿƒ0Û×$_VfÜý|\•‰Ú)÷'¡ÇPFYº Œq&Æ{T+Õ¾0…¯ÅCê¨D(bšÊàÆ­ŒDdqNË˵$®8BHà¸#°­ÊWǦ9J|#:àˆœ°®\Cà› m+ ,ÑÞäpÅ›ÅÓ"tdçÚ$Ùkœ"rԌ陘 ‰C_^bµI†; õqZ{…Ãtaœ8Èõ9{epApy^;[‘ œ¤ABHXrälæ†-µ(Q£* 0iθ~€0Μ„ ¼0èø'Ëx…ÊÝPò†ñ³ñ­Ça_tJ=bs3¹ÉÐ ŠÇœ­ºêc›šø˜ N5Ç9Ad³lŸ|%$B˜#Nó´@ö«]xÚ&¡’g!‹–‰Îq>§ÿüÝIi ®“Ù ) —î6¿ h@rݯ×GîkøŸ¿wj"o|€jÿ1b…£D.ÁtˆbbýÛš¨ ¨íø£3³ZÔ ?æ …º˜.+Chzsã£ï_p¬¬3e;ee§&Ö ¹O± ‹x0¨¶*H‘OùþÃ|4©L_ Ö´ÈGm ›Y0@äØã⟲à«ßéóÔ„æ6ó:…´ É ~çë \@¸¡÷ I'>Ždé!W¤·ËO¸D£áæÉï´‘ÃUœz§—>¤‰’С1u·CwáÑF´åLÖ _¨½…߆dŠèÈwÆÇùýØÞ¢¹§XåZè…³Ò:jÒ……]9xeS¯žh´ ç ^‰k›uå©©Ò+Á† úâ ÒR¾>2‰í'•Õêš½ª qu@r˜ºäÄgÉS’¯Á…øDF(ê=ZµkÌǃ ²#þߨu#`-­ŸL_‚»@ÞÅ.|δ¾¤ÄjÈpèd1uåV#ûKá¾–<øðš“ªUø·#ÎOÍ¥O‘ÆLQón!©$E03•­}4?kÊåH¬;Û%!’’Ê/3LÅ>*hü—d-ÓD#lžjN®·¦úhw' „Ú>§0׬IйÛô¿£RÒ” ’ëÈCo}¥i®+,‚[[’Ò¶ö8=¬iÇSÄMMî¸góôa~hQ}¼µÈ.(éÕ• ¢—Ü ÙÒX óèœÀÅfú–1éöD»f =–Éýg‰Úñ,Xæ§j–ƒÒ@ᨰ ªþÓ¯| hT @×wÓ{AÛ‹>q`ß1-g ò9^{áPãü¤8¯0åîEQž/T„–šVÅ !-+„ ¬8MÒk†qÙÜÞÚÚ²ù@§AŽù˜z”Ø”©@ß“ëØ»¸(˜@ÿ<0Ìœ'¸à ¡LTׯÁ_‘T¬Ý{†æùé§6ÚDûߢ“.Á£ÌœxãYYœTõi~ñvË$¡°ˆô]¿;‡|O>wªhçȦsÌáY¥º|ºâEÛÿæRx@×ï´XdïœT4w‹M|í²³˜î+Ÿ—,mÈ1””Biºœ¥§çoùój9rY1#­!‚M‘Cš’ƒ=:ÀlXÓl93¹ß1ûæó<©Î¦˜’O½õ¢=¯}[“|þF±Èðà.l³;}IJßâ¤.œÑŒŽÜyáZËLIÉ9åîy=Ôø–t¼ò%sµþ¹3¢f\ÎÐ_ŠÒûÀs«A¹3%T‡Cq±LLjÀ‰òíÊØF „É£ÖŒm„‹jÆIñÐäŠ#§oÕoËM¤%2èj¾Ûø· ÐF@73°Ãµë™žK(ª0Ù;É·˜IÂJëŽDíQšL(‡úP^^ ©U5 ke_ }@ö´Ô½Ø0[ËbAÙß0¼A-yFÛÜp½&ïž²ð4¸w\ÇDL UððëÌºË GyÌ^ôî{¢E@ðc£BLlr9.:çuXQ†3wØ‹¼.ɢȔl}øÍ£Ç/A:€åô„r©ÁŸå6¯º³‹< ØYÝásÌÛäs¨q¸1å,Ò &R" î‹ ä# fö¯ט €•`×ÄÆ:6CmëàGš¬€FQ’å&cHêáT8†H‘×Σ I+t”ÉA†é%"Â4*kÈ;˜êÔ˜yé¨'ú†°ú+„ÝHРΩӗØõä½”l÷ÝË)ÜË¢ÁâC“ÛpÅñ;Çs@¡Cÿ¡Á>”ÒaYtüI+ Ð{5žš—¤L†–@èJæýÉ®›`µõm”_Õ#0Ö®JËÅ 6ËóûÀbѯ Fƒ—÷눛±’}âÖÚfîã`{~1·hrlE_Ü'Ú" Ÿz’«¬Æ¡ŸJ€›I.ÇÔæ¹ÇÛ¦”ìZµùÀ°'úüu-F6>¥JÛ¼í#çë0rL<·\3哞óúï¸ñ?®òQ µ\¹~¡: F°ð`[‡PÆ×)Á ? EÉ‚ü;Z Ö®ÐõäJiXÁ!Í#ʸ'ä/@ 0dHD} ºШ.Á@ £‹Ä#·’µßVPueÖaë»ÄJŸóІ¯³|~ ðã^Ÿ …czJȰÍEÍáMÌŠKn,Q®©Û1=$ËN$ò(†)ÿàæ‚†ÃÄIU^Qï4ñM˜ú‡ç}yS®N/{Á‡a[ˆTq¬{MyCŸ?56ʆ˜¤‰eàSQb€çÕ”ü9°½J0‰&äû¯8 äF¨¹|òÆ×ò³°Û†,Ù©Ï)Vmz6.6xÚ0’Ú&N©Çý½î óÓ5» •(ëçààfŒ9¹)8 CâUêg£òm9Ò²SNl.§õ®"Ÿ+reNüHe‹¤÷šV´1¢¹¸½±‚º’wPvõ„º©‘Ã/ú¼cxì†$ydû ¯–}”̉ÍÞ ï"3øJKDë+Ãs´OË&Ã~äÄu( ÎU.|ºsõ¾ó-¢x·Ï'ù´$áÍC4挈’¯ºVkŸº@AA>ƒ²¦RWp¡SˆqȨXü©:4PÊpZBMe²ôV÷ÅŸó6ñÎuâ­m¹i›Î·ÍQQºïŽˆ!¤X¨+r‹µ Qº'ù:EC9Pq\]?’ˆâèb:ÃWQ­oó^¾ÅàlRFeU3åóñDA^K+%XT-Æ(Úª*ÔO‰‡¥_aˆzã—VŃ5’äÏÌZvNX^æt¯çÚ847')Q¢Shu~6P Tz]Ëw‘t¨„ÛÜ ë Ç>½­ÆK8\ãê¬<ñDu-¨”¤€ b/¸;ã»§+üìéã?ãÕ* ½™¦Ÿí?}(îÇÀÛ±õˆná>$›ö\>•¾ ¨pûbåIž¢Ÿê ÷uˆɆ ÉŽMu„[5­½EP —ü"”3€ÂÊtwæ§åxœwdQðS€£")…û¬G 7Æ|>R΢Ò*Tµ&ìýØ]Öĺ)ì–ÃxB„ÎwfÕG«äæÆG—AŠ'ÇýÅjipȰ* êämÉl‰qà\-Õ| U[’{;›^Ä®zb¤I¾O Ç Bß ô‘”=uÀðaáæ€ÉF·~Zˆ¾TܨK{úìÐ×ïíñÁ:w¸´pz”‹ºLújå¹c!—ó‚ ûÔðTÕ|‰L|‰ :•¬ –#6Átð¸K‡¼‰oqºušÌ“ïÝB#§É~JÑöÑ)%ò ‘Ê"/ÇÐù-¹§Ë¹Ý0I·~ì¦z6­Ø°ªQ]W MvÓ¾‰ÅÈKÒ鬨C~Ä&kOjô)C»;'×"S ïE¦(oøR k‡»TÒêöy¤VÆûAK÷Ñ@|Y2JËã^QR¶'yÈTp/$ò"p—1B`ÙÛ´–*ç9_@0މ9B†\yÁÉo —Ôẘ—x`&Åj5zÓ Õt«rèö?K@v­¾iëo@Þÿ||‘_)ª(Âc¡Ag’˜ŸÉ (™sض ¯ãO‰@7pG"»‘íÕ,·.PÌgZÌECiML€‡È-£™ÌXÏÙæh•ö{5ȾçÇ^n’r¥˜ÅJw±\ˆœÈ»Ô•×Ã\aPËZ*Ëx¨£œh¤H4nÚÊ=Œ]{m2–ÂG'[/6¼t<Èr¦õŽÌ×'!-%Ò)¤}`³ô@|e‡s¢Î‚ìhÚ4ÛÊÐ’¢F›ßØ5øq^.êÔrõŽÑÂ9/“ÐÓ’E ßÈ(©šH‹L¥_©ÊB¹‘\E[ûûJvÖ³,^r’–‡·÷Ê(!b™¯:èƒ-@« Ôœëöž޲ x(ª!ò$8ÀXÛg0$ÍYèþï,ï,m:u¨47®ÞlF]r.]F}¸YòÙ ê_±j*¹§F_£!4>|(5œJ¥LdÊ—µ·¸/Â>‡r L¥L€Ç>™Mb)qÑ¡z]h2Ü  )Ã8)P–=©þì7Äå<ƒ:K}n4^ž¼¹„ÂĸDŠ&Wáëñ-•ô$iƒ|= Ùe  ëHM”ó=hÒáç08i¿¤ïb-–Àí,PÇBîÀ@‡TB6nÑáw^j]‹`’ †ë ‘‡ÊEÅI­ië}1ò UÌŸˆwñ¯²?‡,é”% òU †¯.ÃvJÕí¬ŠgÊqM –¢\Í”,-ŸÛjZ’< žzV U£Ôç¨á;¯ BxWšÁpºW֪˖x”oÄ7•byãÔɹiÀ¥ÆõZTº—äéócÝ®>ÒdHcÞØÆD6×qÛÌM!ýõ°†£¤u æ}|gR0W³1XGß5²|\ ÏeX¬…Ð6Ð-KŒ9V‡]óœ½ïE¢z«_ïŸ;DöäCï+ý½‚›Æ£Bts T»Ëi„¨‘ë'ÄT²ÿŠ«ÿ^¸ZÔ7ÀÖ½[5›Rà×MjêO}µžf½nÏ4æ±15Š´ŽÕSyÛ¢·`´ú^ØT¥\„¡²‘²ï‰í 9»p<ÈÐÉÁNܨ2âW´ÿw@ûx{>ùoŠæ«Imö©‚AnS}$;üóÓò¹ýJ†ÿ}ð‘väC†PC-†ÏHUhG—¿M GtñK âŸä³!ì “Åð¬à(¼ßØñ“KÉ1ÅÛ¼ÕMùÔ…zÅ[ÂRRƒ… ÞPwJ®8‚È äûØ¿qω£ÃyÞß”¸±»öj¾ÖÏÖ^M×z}J¯¡¾“¨o¯¹rŠøÃýŠ“ÿBœ„ø|jHÙzJÀ,‚<8ϧgE\¼“=îLF$|l"\žŒA¾¯¹¢šÅ³‚ìcšÔ•ÖÄÅaöcŸ‘ßd‰›cRn_vO*ÌDié3MZQ cÒœWÍ\èØÌà¥ÃÃÖ=ε~*Äðcá§l.Ñöy#¨N%¨B^sÈÓœs:@‹K «›…+ˆú’} È]ÏÝŠnä¥OMk5*ê“yyÌŒŽçù ÞŸ@õ°çÕå ³ýYñÑŠË>ed¥V.mªè`ŒßQgqQ¹á¹:P\B.ŠÎH²ó{Y) À…`=TTªŒfÀ¦³„8˜¹Bt3yóÉ@UJµ_€ÿ†, `€ÞÕPLhÈÖ2û0Kà ÖTäÙ#¢É°¶Ôêt:zv–‘ë4U/¬sY™DäPBùL6+‚ÃGÓÒÅnMïdˆ.kŸ™2$“_5JHÀ’8 ¬t¶’›ËzQ 6ü€ÙÕç˜%”úëšÊË¡Ñ Xk 9¦¸NZ‚w¦­úeB…*#\ä¢àêäf…Á×V¡€nsÃJïGþ‰x\Í–H°P…’'qV‚(lÛjî"ÖªÉã@àãÞ|DÉ^BÓ`A6Kbômù¶ ;Ál§&úôŠÕˆ¯5wëÎËâmpÑÚ°G9IâB..Þx“ÂL.”[r}^œÎ‹ú<]‡B3Ѭçuy2ÔÔŸAå`˜Rcf”‡ÑÁ‘ß™0#yË[wÂáÌ“Ðx*‡Ê€ºÅU…í¦Rè)z9óa³Áª¢kR–¨)¥WënGÜT;dØ¡6lJ¼\÷2ùzúÖ±<]n ©Õ„˜#ÉxÙ§)Θ:š£§äŽ¡†*åÛ‚çmR'IѰTþ½¨Nã]«ñ£ž¬)‹ÜáïSvžæ¨Ž‚†¯ÛâRŸáµÄdˆÐÊ]pæP÷*$îd÷œæK“õoEˆÝ’TRxÏ0IŸf¥lÏCJw«@)_º§hš¿:þ«c¬9³|œXº1llµqŸž÷™ nHôaný@n…¨ØLóN)pƒíHdäD¿Èêá¨æOq¸°vÒÑ']gHZØ´ãê]KÁ©[×NGFÁi@0žû÷ÄaJó¾˜åy…ú™¡^¾C¿(eúAv¸¨ÞàÂW”Ìm±CfZ7â^:^FÀˆÄ/aà¬rŒýñ¥lj'åÕYüû]ŽøN»o”SÚb’×ýgéD¥5Äc>.àë©Ëq~ìC]ÐX¨a*Ç¢3,åÙuYû¦EWΛulqEÖ…îq˜Ö:Pª0w"<¡˜› þÜ[ƒÐÜÆëAg­£Á^þj>çàŸ¯¹M®Û )«A95N!èÜkëîúã€óᄹ"¼{*ì.€{<+0IÇãÕÈs÷¸ë{uÓ;zM3èádâ·Š£{kò×Z¦hMk½~»¦O˜ гr C…]¿<ÆMty%Q=Ê›l¶pй·I/ïwz :Ýò!@`yƒ:`D‚+Þ›üúuP’„½³qã=7«&îzFäm«Ÿ¥)s L±¸£ Cã ?V+Ó2öƒo¹XªÚ‹h.¼šHè0ò)«‚Ûeuïz˜BýlÄ2Èø…/ÞB‡ÁÜñ¼„ö£gÑ%Æð;ÃülHwpÏý0ă À:,º¯1—ö“k¡D/õ¥C3éí~2aƒ¹yWŽúZC yŽIyXUEe’e!sa1k]ÅûU¿Õ@=°qaXk³ùi9•-rú äí… Ì×µ¤äPQþ±·&­E!²Íß@£q-àüãH)ÐÆ=œÝ]N͘¾y Dj‚v‚—ÚzÑn¼Í!Ã[æäpž;ÁjlóJV&|)Š[89¦—|ë‘ ì®VHS†ƒŠ;¸Ñ‹jÔ¨¯0ͨxWԙؕÛÿ0P0ú"‹%f×´AŽ:Q°Â_ÿ稰ÃËXr#•Ó(ëù] ½¥F·Oª·E&‡®|.î„•ÇUÝæH¢‹2ª«TC‚ŠË=äS  éy­gX©{Ì&¨%$ašë•;Çá.òwÕ´š\òVPÖ`È#ÃÙ#Ç—6ð ã¯PÓª·ßyYÌÁËïRA¡RK¨¿°$ ÈŸxÜ3»9Dê¾dGðËñJš_÷Ù¢E¥ü(ru,ff¢¶åYaÿŸ-ˆp„»ÀR!¸žßäoÀÂuzZž8Ȉn6„–GêSÚ¿6ò’.¸t Ý i|UEm³çdBF1/@”“¾º¹¶Rdâæú¶ﱯ+lDCmDYÚø”]QW¬aIÚdÖN³Ì²é8i¬™Pa©·­†Œ/éòàÀä ¦èáá4 ŽúK©¶W/a¹Kⱘ .‰ê°É÷ÃGøó5Zê5·9EÈ”'€š¸åäØPSš¼ “àöÈfìÃq_J4¾/1‹8e 4’Ô âé?8éÑ- —\¶ÀÀÕ½ƒÕÄkôVÉV°ê!¤ô(p¢Eì›âÒ¨ çÀ‘GAÓò´¿’úš¹ŽDsŸ4ºT…  z l{ÄZÇŒ/‚MiÍë„Î’µ'nuuYZÇãù§qÍ#ËU"§D8tc^)Œ1KKô­,‹Ñ…,I”Ã]xÎÙ‰CM逴S™Í^ìÈ•_µÐ(©`¹õÔ«øÛ LÿŒò¾—rú‘ìˆü’>¸VÐ|†Â·þø0É 5¸+…ÿ†lL‰ÐŠX:¢=Ͱ3ª€£Ñð¯Nœ˜”õɦÌiðWÔE6”ái boò:JwvESòƒù•_³h·ÀäÕjsœ”û&}pv«sO–¿sC9ú>Jéþ=ÑqýÞ¸8+¦£û¡”- €«•*Âw»bíayåø%v9*ßf8ó½5ór-CøŒÄ}g‡‘X}>2aEÁàÅŠY¨ÜûeJÌæïÖîmÊ.Ü5]KRÌáãaò"šÁ~fݺ•Æ$¨YéQÁåŠ(Êõ4cø¥(ƪåm‚hG)7A)¿·†mÖ²ŽmÇm•j)n»R?–hïeJóAädŸú°ˆ– ÌÜÛk‡ØCí×ìÛ[ã?X÷Öèêfz¸Mj™&§Ëñ8AO¼ÌìŠr܉9X|i[}¤2ÎN¶‚.àû>O#gÈmŽêQ<Ö`±qGОî÷pkäÀýf&˜ãkn;cÎÂ{Óã]ÇútDˆŒãÐé ׊c7¼ö^¢!¾$¿lú~Ø /(€Çà 7?ìÚ‘[LfšÀm°·^­4᪗>3ûu1=9ü„S‚ºç&ÚÇnzTa âMó¯<+å¨o.G­ õA÷ÝÍŽB¼,Ñ¡øÀ­óûp@Y­Rá%è­©êÀ/7ðžHL¥¼XW Ø„bàô„.˜pcTG=)ßáÝ¢Ûy.oÕÃGE4Λ¹ð$à¿ñR‡”té.QIºÒ5„‰G0• \M2ñ Ázì|Àz<àýšý<ë²óó® cKreR…šÕ1oCb(ZwFËö$/²ºú›"FXo˜Ýkî^ú%?S¾#"öþ‘Gß<‡†p™S×:ýö¼2ë87@·7‰éð“³7+±b ¿,8á¾¶¨×öøÓ¸09"¤1;lFÕž–0”YÖ’1ìZœ^´9b3k¦ñs¸ø|Ÿ&§^sBd„ Ö¾~NÇ$ßÜÌ¢–âS )æŠ9ºqƒ§i4T’ð¨ó¥á—¤8˜þŒ/‘³|>Cú~òkWlwµH&ᔫž§dÍ }¢lùhçfõ›9ÂBIÿÀsïIû–üo棩ë}z}Æ€Îøû0³ÊkWÌ7ÊéØý7V©~T9Ñ€qxQAò-ÊGM©²pnijÅ<Ô?¤€ìB¨•B—ö¿ÊÙö¯3qËu~PÓ+A]ùü:þl ÍÊë,ÈúŒæV(0‡`„8ö~viBhjÇvj°ü9ä¤S7':¹9ˆä’p ˆw0ú>¯æ€]ÉæhóÏÙFöÝnÉ/” øè7Æ=ÉߣÀ¬â,£9à&°-Yãé_EcChZaL’0ž„0pùD£áŸi9´ëbkÖájîy—ZßÒâ?#T7Ôv FlÉÈìM2 Œ0Àß ×å_Û‡ŽqÝv½mÄ;Ã4)çàF×uDùövON²ìØuþæn“Vò†P·wCá}¾º \èõð‡­­~¶³ug«eð? "åâReuïÈþ«z7$ë‹o—»³\7ûÒõõ•g§¼2Áó#¸EÑàÛ‹ËU„o{7akË ³3˜E!ÿ(½—oŠì›âx¾Ìç—Ùm\í­Ï#ZÇ<ä&éu…þ•øt6òõòÉO<§³¸š BœÄNq„ž[—²ÄbÍh±Ž‘QËz•_qZxÇ.Š"=øÄ»ÿ¯%äg“É$æ[˜§h Š<ýÝqè_l…Dþ‰ûŸ­à^}„Æã0lkRÞ'®ÐÇÖo䨘ÂV4bj„³øm\]{ .‚ã¯Õ¹\"]PóÛ­x£šéö¬M?Ç$èªK¥Ð/ Òó~EêÈŽ–Þ4ó‘T.šÊH cy/»ïv§‘{»Í¬žv@LÛ'›Fow‘|[L)H ÙY ‘¢3/ÁwßÃÅRQ(£ViD/ÜãD·åˆÜ©`葵I(3÷wûý<ƒÂž Ööô´:œ]L\cK&™~øV5¼ŠáëÀŒ­ŽxaûfÞŒ„A²Yx£õ­¤>:¹©§olPr…ƒÖåHÆ+K_…›Ù‹$?ÏÏÓë€oâéÓÃÆ¬“¡.+ï§ýÑ(Ûÿnÿ»D¡óÐùO‹ÏÁ^ ‹ÒÄa2ø(!ý`Íßæ$¢a:Žòh–/Î_ ¥à*XöÉÊøzœàؽ#ŸEíú¼ÈGTŽŠæáœÁqáÎZYÍëAö²pgÎu>ø+űMª9ûhé$ÿ>#n@CtïÓß°2üçÅBéçú ‰¨¥OOOÝÕÒpŸVÓb)«ˆÉ›iaýâñºñPq)‘\ŒÀ£#åîÄ´Qj zúk=¤ª6Œ@íhtíFÁ'r‡’S<ÇŸ“sÖÔðQêõùA=²8Šº6a'æîTŽÞnœd9äî9±ínð3Ćm"QÃXCMÎc0© rɸ…¢*&O§…7YŠ{ö@L@þÛ2ǤàzϚܴ³3ð§Í Õ´jAå,ÑGÕaCS'LBŠOÀ£Õ¼I+ V7gç®ívŸN*øÉz, w_œ_m¿K(Žé¡p©M¤C´z,¬‰[€ã ªàÌVŽÖ5Ål¤ENÊJª»w\s¡$ž;2Ÿ[ñjå‚—óÎÊÐev#™Ü¢Ç,]·o îJ÷n WeatCOcC¤Ý™ šc„.K@ !1x Ë>$_J7ÇÂaLB=˜€ë7N º¡¤í¶¬€Í>é˜ÉÌM¨Ã•ÄÁ’¡cG¦=ØfW»¿ýÕ±tóËœ]ö€kkÉ÷’:É­#q?v 2L?–{—óq‡þt¼û±b¦*³Ò¬ø›öYk{=I‹Tóà¤SÍvÚßnleÒê øÚLÁ‹fgõøµyÙü6ẒìÏçoâN¶z>ÜŠºƒ«­“î@Ú)xwõŸW£«Às+Ï™Zz¦ÚÖ»¼rǵöÁš[/&@V™ãc·½t¯þsí—ïHšYãT®(ë¦ý7½·’j’‰î—³åÉþƒ²-F•0—ʃ}Mê6%hêË}«+65è‡7X1ã9ÚÖÆ«ÃuQÛáYMLƒ"s¥A4€är¬6á(…..th% ×ò$9Ò¢+AnºÌ J3`ÎKÍŽ^aÁŒì8Ÿ‹ÖÇO`E?¦†ûÔd­N‘^Ós'ZØšwEe²êQ±Ûh»z AâÑS÷Öë$`?¬geó„§æ»¦GË/&Û¬r‚üu~Ywøâƒ]tÔßóƒ<ÇÒ‰ÂËýË÷,ô4Nîà{n]cŠ×Ú9ùê½¼Š•Cf“æN÷®Åðx’·±µ…ònFTéÓ•œ) ËA–––¼Ï蛦××­i~N¤„ÄsÇH)mK¾6u¿¢¡^$!é7ÕÌñ‚¿ÉÍ`íÞ?Aï±ÃG¥F[ŠYšÎqRÀÉqdÈ~]ÅG³‚slÉx’ Áœgé&¼Ýšãí¢¸ÈÛlA»JcÆRò+æýd˜‡Ëº¶:`'Á÷˜ûºÛ¹!jõ„#Bà+¥A j¹&̬žŸ Ôã¼.ÐjÚ…è_ó™kpå$…ë‡#˜«f¨M"þ¸vkŠmÎdìk“¤2Ãy9\mIÿ û’oþ=ÄŠöY\‹ Ðçék0Äqjy%’ÿ44síÕZ¶öÁD3TÌa®ú›­~²’G Uiãtj¯ü—k™½DáôÁex\LÏÀ« ýꢃ•”ŒÆÓÿž¨Ú\„ëm‚|ÖH'Ié#„†ã•ôª¿*•$ŠAº)ˆú2«Ocئ¹ï@du«%ƒ©IT$'õ©1}ð·WòXÜ·„âyÜÛ%y¨•æ¾Æåô µŠÙû&˜ÞJ+«ýÀ(ñirGþ&µí:¢aç*]aÅ€m»›Vj²~“0ŽÄÆÚæ\Ue™×ÕØáº e° @²¤àÞšüµ&qü?®Ô…ÒŠôڃꨒ‹;!§¥­¥i3 Ü«gùTV ÛoPû8$%„E‰:ݧ÷3¯ƒ àZ²(ˆKì€c´Þ›È›Œ¢7ã‘ošŽ%P¶¬.&k[Ý,±¼ôAzy˜_ÞNÌ^73òNpZ/«sÜ ] dªSœˆžê,G7L‘T5¤Áv9­¦—àá”ZøÝÔ§—ÙŸ°{ÊÙ–OO0°d&ÆBÐ3ÒËÓßÍH´µlå]Ë!S˜Â=9œÌONŠÙbãä<Ÿ;„Ü[ûþð›ß¯ñš6n v ¸úD݈ rL¨]ﯵF­­¹¨<½· shåšÄ™ê_šÂª‹xÕinåx“`®×fMà«6½||×£kšFG-~Qä5í!G¿¬‹a²'hð¸&D¶–‡ônµ%Ì" Wä£FæÒv#xZ-Š]›¼=ÛÁ‹O@@–=¢7HÀß ü@ô«íõñ UÁ £Í÷WtxÃŽÒð-ãÂíl3쮿nR“Ó6®óF‰«ôf0º¥y(OGs Vãñ®Ò?¤˜òÀ3&KpÚ¶P÷Œ_¿¿,ø>Ù×®æ"îéÂF1¹LÓ@E;w°)ú ÊààæT¥Ô½xÀu=ËGoáb¡Òc_²wÚšVÚ„-C,4åÕ5ÙñYÚÉDSþûš+ÍR]Ac¢H¥¥æ÷L—øîÚ¦ÂäÕ&nÅÿ2Åχ å¿+&+Õ"|7%ê«k7f*»[$è/o j+蕳)‚¯Ì~'KðôÎJX"$½_ ¹HÄÆY8X’›ÖägId,Ž>a‹å>‰Ðˆhw¸ìîÆ¶ØlÇ‹,á™{o/ñ Þ|ú©ÊfÔA}´>Å€Êi»À›s÷´}lÄfDõÆÞ—2“ÀÒ-  ´tXLKÀØû5e—ôâ[9†"}ã*o¡.xôéÐB/9âœJÙ¼Ô×ú)àšÿ²„؈ä€Çt_aJøS Ï"p1À;¡îÔ£µ‡iÖÛ’jÓ jò3ÊÝÒ…#AÆœ©Àé £˜ Û8ŸBXæ%eÉ2Åù)\’ ÇBf]Þ²ì‡s,Žƒí—µäçuâ5oNù=èã•êIÞk¸ÊzLEOc€¡#˜¦¾w´½ x¤ýç;[oËåÞ‡¦ƒrz’¬§/ßË>dòvmæÐÒ>øþ*º%ƵT ‰÷Íx=ñïYEMWÝ/`:@K@˜”…s¯ ØÈÊè€þbâmpëÛÄzöD…6í¸¡ˆp¾ÈS¸þÁ%«’*Á+|˜ºhN`æ9וrÐ ¤Uî°@5€>ÄÏmÀ¸±x®ö õ5pï‚´¹è’€locãF†X ÔbÍgSmÄå¨Mé×®Pæ°–5UîšïÖHG’y²ä†ÕìÖ'×B+A¨`ÄÜÀ5×1•ÔqH$ÔB_¹ß‰¾Ñó6-z€Øã„œ·!™ó«+MõºZé(êæôö´›}¤«¢”é#ïåDÂÒð] ^úìðˆê…YõäWH““)oKºnOsÜÿº±ÅJø5>9بuCCŸÅ´û½¯‘‡Øœyk¸j`©êËÒ0ÄD‰´_JÕµ>ÆhTƒjCøÐF$tĽDêd•‹OB™,¦„-LÒ¾Ô¬€òÄ4*LaÂ5<$Œ1]î–nÕO © µz=[Û.OÊ…œM*{PÛIÍ¡÷œyÀƒ©ûÐMŠØCÌfÑÇ™aBž1Ê¥È0C€Dwò¡£%—V‚®¤æÕc¢1þ×K&œ04íÄórUÊ./òK‡å ‡M« Ç<õa¢hCe=$÷:Ëgö¹h£¡—‚Gn; uDL€ÿu !U­3Í>ý4å\4‘²ºAV²rdiáW?:´Áüî¾>%ÎÏA>+×è|hSmpŒu–¾Æÿa‚êba› DªÕ¦Üq­.˜žº½cŠ€ü?^zõlŽé/Ü^aÁùÈA>Æ-HpE9:…-ΗuV†“ô/DÚˆZp ðµNÌ[übkÎeÏ¿{žAî/×+nø¸ðãT‘u'`Í©ã ð ŠI -‹XÕô #Výjx>Ê×Xnw^Nòy …Å  [tx`¤g˜MjZž@Ú à((qD6¿¨æoNÇ€]€×û…šcÖ´8‰}ZM7¾žˆµª³.¦‘[Î0¹áì|ÖÃñÏ1Ó†D;câ ¬ÆÂl€þL›!ƒÃÞKíÅñý°úãËžÌî€jñíâÞÃ1?Ö ?|HPÞN ûà×?Ã4œøÞ/±¥Ñ;ɸݙ\…Z·•K^‡"«ËébãþäÖÔr»ìôròëýZÛéHN0]Ÿ37_ñ‚ŽM|ÿŽÃ1þIOÈ#þ‘²ÙVÖåH§Ùë_“žìzpŒÖ]ö•£´¼¸ÈçRýÃãèü…›dœö3âºÅ† tùx7c-Õˆž*–†îÄöÐ8É'׳«ß]ÇÅÆ|ŠÅ´Å;Òý.cñ»Èä9ë*ÎrPœÕ°fìh¼×âë¶ ¨í¬‹ü §®®k µRÝ)ž8.¸¿ÎP+DÓ0€¸n{«qÃe…9Ÿzã!HëHö( @ Ó»äœzDmLf ÌÀKä1S*s¤Gõ5 •oãþY(ÐW äÞF¯åD™o}Ãy´šXá¹ ínò¨dLp½ˆŽ•9¦uìo‹V»ÓmÒT“g[‡,§ÙFºð¯£L#[wW¶eB4„_§ý$‡ÍFÇCÚ®û s u;/<8Ì<ûþéa÷ᣗ‡žºŸnOzÙ7/ž=ÉþüØÑÍü‘we\Â帗ݑm"ÈÔ ÂRBâ5î¶Ù@Ì~øîàÅ>½Ÿ}<Êž½xxð"ûúÏødÿ僵þuæN¹aq,2@:óÝuGh0§ÜÙÌŒÐ(ƒÝh 7|zÔ™‚’R²ù£Ÿob‘ß¡¯D”n²ý¾ßć+Oî' ÄWà%TŸhE¯$~+]Åί¿¹ºìíL—!ä †|—fbä@Ë¢ü£ô–'@û‚Ìð—¿Uƒƒ.mí´åbß“\ƳñÒ‰KÍ0A7…²¡€†dÐß»Ç_aK|SÛWÑÙ‰²Ñ­cÝ¿áÉœ’s>·¶±î’?ï i U9ÛBé n{¹±÷„¶],-r†ÚŠQ…Ióüyvî¯s¾Ñ|°µ0a`Í'ÑLËÃâAryLFQ<œ#¼âýcú,':¢O2†#h·õ°¢ÜÝMá“—©ŸÍ j„mévÑâÃ[jûCnʉáÞÚG_¥88æ·ÐÆ' `…¬Ý P¹¢-`µ¨¤]cÀ3RKgüÏŠ|üO‘Ÿÿ…²Ûu¸ùÙ¶‘×®Úà‹!”5Á?vÂ{vl~Ùñ÷¾»‡‘­A >‰ n®ÀíûO>ùXgLë|Ñí‰pP‡y¿kÅ[FðZ¿f©—¬Ú.ŇÃ?.±ëÕm”™êô éf 'ªÐæ$ýPR³†·/à@u. ƒQé ³K,3¸Ó œîmàx:9?ÞÈ8¯î ûîU;Ï ZÖí{>åXAžY¬I !Š6l’£2ˆ”TÊÞ]%à§ãÄÈlŽTÜ JJ©¼†õ²ñÐÜDYÕ§ß )¸ttP¥KùìÔ))rz šH¢)‰C¾›@³„f>‡Ë’Ö$ƒ£_ªÇÆ%Ü:3ð„"MWóò §ÐLªÑ® t›AjŒ#ö‹=/Ƥ‚QÕ£‹1÷Y–ZÚ]"{ ¥Ò7^ðô…\ϼ`ކ-L¼ŒÖK¾W@¨s’ó×ú7YP­Š+†ÖÎí$kTñ»õèGšWQÓ"lGÿH‘µ@E$€•§§j2Ü=¶¨½„êà:fÅu½‰;8/3Z:Çæð…¥\ ŽGœ•øÐ‘ÍaÑ)å%Æsô–õÉ'n£‰+Af)ü ;ÈéÕuý0žFJ-}™Á±€dÌß?RÞgŽL¬zQ‡zj5!ly#f7PR/Ëg ž‘<Ú xÆÆG†ÁKKõÁzk@VD‡¨óŸS÷ôœÊ¸}¹Ämç¼NƼ+*‡þÐãqúU¦JÝO”ò¡zk]¾3"+iG'G¬&–ó +btÀš&ÌѸl$ÈUeTós¯ÆK¼cfß…™By†»›‚P)‡ú1Áÿ|!.EhX ð”ЇŸŒä.ˆ‡m¸ÍèÞ××¾´ŒnëFFׯWÞŽ>«mp9Ê÷m×W°\ëŠjÈÃ>}š50 žÉ‚ø„¬‡`t³“ÅåÖ$ÑÇÕbQM‚Äõ§àœè&U§û»¹aÊv蠎µ|Ma¨ÇóÍûŸLëÙÝN<‹£®²õ,j™wæzym2Ë>: Õ‚dÀö‡¼ *6x9°çªîÆ´§¨ e¡}€×Øv¸9kI¡†GÝðªCžœ¯8/Þ»go¨Ö±¤w µâ]Y/ɤ¾^»/¶µ þTèx|Yo’êÐíû¶fZ"P;W€ºœà‹¸6 W…Ý"äh)~4S² –o…ï#ž¨+ÒW/{Î Ÿ4€¿/΋i´vr³ÆJw¿œ#ÐÙ†0WhŸ>.OÕí‹5e@Ͳï_<òÓÐy‹<׸vÅ §3ö¾%nŒüƒƒYÒ7í­æIÖ£ëS)#Þ{Q2ê‚?u?0H îBždIHž„W„Æ%eOÜ[ë†6Ì$G9ë}j¶d÷þ®–N¾ÎôÎ~{pxÔù›É.+(Êú•¸€ |"˜gÏç#PÂcð0]¾p¢‹Hîö¬¡Ed“!<8vJA9 ‰¼;¨˜ïQ½¡;£¢v?pÛ:$y:³€¢ríáÙŒ«ê )!J­vapeøâà¾?xé–Ñö¥äõZ©kùø®~ÉI+Û:‘†?ò¥pclu‹Ð}È“@VŒ5Ý©³_oâ´qãõŒjÉ)—ðt{@ÎQ|Û;aû‡‚j}€MZ#sÉ‚ÏU^/P·Ì±õ:Tè"E^ŽÝIé`ÖŸ„Æ.'Z L­+kž¾/N÷Ö¾¢O9Z»nØ%×{›ù}¯öí:Z|Ãý¾Çý°eÔÅri¶Êr+Q™°ÿìjîŸ,– ù±EÜ“T®ˆ¹·XW•CH Ã9j¢Ê÷Ïî(–¼<8d(Žýý¸v3 ~±õì}Ð>9„1ÚÎDef]ÝŽ¡(·S?˜»Ÿ£!] ëàòì¡dûI9ÚãVÀ’€ECœnZ]Gs!^Œ(ùy5ör4ˆÑâWeçt$ª5»žàbHUßeaÙ}zˆ®‡Áf9=/!Ù$–ÏýÔb:æWOÖd_Ž o‹€WþѰŸÆ ðE %ê H_]åù‡Øíï7?ë?ÂÏý¢½›Œç³XµŸ¬-÷ïóÏ>Ãÿn}¶þwëögw>¿ý›íííÛî¯;·w¶~³µýùí­íßd[?ÙVü[šgÙo...0þ¨­ÝUïÿCÿÝûÒ1Ô·Üq[4ÚÍüæ÷ßfۃϾì î@ÑÛ?lnmon–ílïÞþ|wûóì¬:Î!’3[÷ˆ JWøã!âTö§'7^<à.–ãy>¿­'pøì¹ùèO/œ€Þ÷S¤Úþ1µwo»'=}ûx1‚ìl¸ÿ¹½ü± 2VÛƒ/²îq±È{î‹—åÄ=ú¡ËâçvnÏGÙÇ7ÊW/KÈm’eç‹Ålws“% ˜1ô28©&|6¡õ“|ºW½«[O°%H'*Ù½åº?'9xª¹e9±’àÛ§ßgß>ìæ|R¸>°I¾ J]o±…)âÍãx”¥»šæÅgWÇ…ølY¡k×ÉGÇgÄ24%I v!m…7òñ¡–ÏDzC/EvûwƒXO‡>ñET“VŒ+íâ‡ì¾úõ¯ÛvൖÅèàPd¾m±qg°GCÑ À B¸ôb¿_Ò“åŠ8ÃÛnT¶G]1-”’ =„s\ÅŽ qûØâɶJ6^åwfhû!)ÃÛÔÓµùËMÌ%N¶Ù\s”‡[à§êsm‡3ÂAê„(¼¿o$·sõʸfç_f÷\+øÃ‡õ· ¯l.Ý,­\®¶±½cŸä3ò6çßBjàw|,, Ââ?採‚sëØ–š …{ÃÐüB¡å¶Ø'-¨]]0h&,îr0íš‘ßÖ1s(µØvvbÌý$D] ¾5]8ê4˜‹MǰÀ»ÙSŒúY’Jô4$‰\9R„fq4 ^;ŠŒîœ}vð¯¡÷·1É ‡ÇU5Nb… dMƒ†E>B؆£jy‹OŸQ n"ô·M5‰¾¡X¹ÛmõWœ;wn÷ÜÙ,¸¢¤~)ã-%Z ºbV.Ò‹æûû°E›+O;V”X¬³ŸÖBÏ0é[¤%š†{1O/ÅÝ£¢¥UInmÀ8dIÖ$wç¿iOýØéUt'&&ù³:Aá´Q˜µ{ÐMP-¸Û¼Ùd™¹¶.ŸÍÝhéïñ ,ÚÒŠZÛˆV[\›E?ÌÔ6墽ÓE³'÷—; Pñu+D¦  ô|\iÑ š·_@k꼋‚²Âq þàç7¯fçèâ¤Pè©ÞÇãê ½†Ïž>zötø`ÿåÁð›g>zúmŸu:éшž¹gèR2î±óʾ;:¸ ¹cŽÔ«“±“ã)wŸô¥DàŠÉߣËÔ¼ LûMbª~JWyEW­³ WÌöA¨g+xÙ˜oçùqæínÞ“ àÉK š¨º"ZI.´ê”)º7šS¹ºŠØj¼E2Tm½>ê(is (6í^QFŸê†——²Bš4Gh„dɳK¹±â5â»ßq¢ŽwÇœ1%5z&½–›¹R0käA˜.Ä 9JPávéký>.b°ŠoÞÀõlîÿ:+Ú’J8{kµÊ[ÎB~ÌŽº·‚œô÷âQ‹yóÒ†·­—< ˆX›"'ÃYjãÖh¨‡Á j8?»kÅl÷;”«)ÑÿG™)µ_õÌÃ"xE'F%Œ•L1Ãî¤?,œìˆÖdOÐ+\´UŽ9`æ'äÇóönÌe¥"‘ðîµ¾;jT&ˆuí‘UÎåÇë’÷(‹7…Á׳T…òÓ'bùÐqëÍžµœäËÓq~&ŸÕÅ«„ø·—┢u]£^š½J-ŒwW #yÓRi¨Gò]Ó‹Ÿ¹÷HÕ¤½_«Ã÷™­c!Á…¾¬«ß¾µÝìÙHä-Œmrî:y°9ë,\/÷ŠЧT÷}‰òÃuÜ#H÷B¶ Œ»a†©ÉDò¸fAH>ú¡ ™5cèbKA¨ë7¦¹U\}ròXÝé€ _üîZïTîZñy(šp/ôÎSĤ‰õn„"«Ö[”<ì½×>ôv%L¤Köcå7?ó)Š”@Ú=ëœDù ß›¯5ˆ¼|Ó· Ì.±Y5k=ÔÄ蘯û]¥ï³Þ¤(Ô±®è0¡NiG#L2ÝÊ$@Q¨ùÍQ+1!àΞ®ìŸÚ°BèC:U;¼_pkn m›m˱«ƒ:á „Þ‘–Ò(ºúµ¸«ë ±gcûuÊ9 J‡ãIÑê¹]«û z>º’´€K¡¦ƒù:€,} |"íôìÿ”³kJÚEó¿ I~>ÂÀÔܦMŠ¥ã¸ë(òQ9k9 _ô÷®µ~¶Fc…¿ˆ¬ù ëf×M¸ï÷ÐÄs’Æ"޳Å%œ”¤ðŽãÀ)'ªý4ŸŸÕQÒˆêÔ¯8¿BN1 -%€mŽTI ŸGÝ]—}ØmÈ•s›•z{n#ô‹TÒðW²ôMà¿Éî·{ïÞ½ƒgoÝ©8Äí­m¶Ö¾¼ëžõÖûÿhÓ`zÒV·îjÞ¿uËõƒhØÔÂá‚UÍýã^0d4\!\±•IHÎÛ†kÀº»T‹E튯Œ¥F¢ ¹W z“WCÖ—Õ†‰>ÅSÒÀ&Î6Íz7ŽŒòB?  ÇÉ4¼Žè‘˜× “OêÆbFmÐDZ{®#j# Cøo²AÚâ"é[ñæÃÙµV EãÅsNˆÐ²›ñi þ’ã*î»÷PùƒnààÄ´L?Ø,Ë„œìÁªe°¼d׉$–ðGòªD$ø›¶ƒöÞH}šîýâ.y'~TGƒUoúI›f÷6y…ÿýêyHl ʮ뀒Kx¾’VBum2è2-€“ >Ç- µÈgM³G/ŸAƒŽ!»tðPbÌ£Î.! n/;›à ;{6¿›hÌÐühËd´W¿S_ÖPWS¦ÂX…ÝÕCY`ñœ6ƒFæšÿ„±«X5ŠjÊÔˆ£®ÄÎRè&>ór§_.ž_ØS’èëŒÓë˜à­=¿ß"báæød¨M nXþ˜ºö€ÄÙÃËY±ÓZƒ ˜@´ó}þìå¡q"± ¾7ªSoÌæ~´aM²à!oj–ËûÄrÒJ&=LÚì7¢zÃqÀ1Ú‚² ;î¼-²³ ¢%!M¿º8X‰½b N:°9ŸÛ;_l¹Ûbˆ±?Jv þ¶”‚œò#vz+æö€:ðmÊÉêKYÝkú*„+ðXð"Sè|°zpOxTXÄÐ1ÏþÛ馳B³ŽMÔðªÒ ‡böé ×I%‚k0­„‰¨ÌÓ±v¹ÉG$a¥]#~í’ƒÁ͸ʑÊ볟`”²ÿ‰b¶‰sðÍæÅÛ²‚.ˆkÉQtÇ ‡Äå ±ð?s@ï ÿ5â9Ö`rYÿmüÓ„¯ŽÿÝÞþâ³­ßlo}ñÙÏ·á÷o¶¶¿¸óÅí_ã‰aüocó1 øpÍü"€wng[ؽó‡Ý?„ÀŽz]¾üŸÇœÊ¯<Ñ4lÞ¯OO¸§½¥/ ,¤Ʀ¸/86›H*ÈC‹#_‡žDš¬sfÕÀ>pÜù” ÷þØçÈàF žÅAÞd\Ì`¾iì’™€O‚<Òt3¦æ —L"os ·ßwÏe©%ò‚MácÌÿ&ÕàZïÏQâM<”Z¾ê!ZA!±Æñ0Ç­ŽŽe™à¡7"ì£TqÀ¬î[Uí åk:3­§i‰ä!ÅßË-ŽOÏ«z‘ìŽ^ÝaQðfKz¡‹°¯u7 žd#åJŽKëUŽ"î¹­ªŽ-øÉ²£ùLwÜÕý”奤š ŽÑ>æDzëfõ÷²¯ì&ß¶¤,{Ÿ«Ùíx‡T÷ Tü…Jø©çådfZ%SÍuþ2€Òãyó­¹ð¬¤ÊfÀ»ÙÇtÛÞ[Žïß—÷÷çÀ̰¢üAÉ|ε~2 A› fÁå¢ì_ÞÛt7`8•‡âØ»QK‡ K@WÁ±;ÂsÄz(Ë)Dhð—›nP +¤㙯ö¬™o8rƒ–yPÍÏ6!úæÎ߯ÝDt”kò@®ªÙÙ<ÇLíç˜b³zéqÐï†Gçp@WÊÏ ‹ieø W®ÍTpššã56û4i„‰ †f\µI·ž¼‚éä{M5:Í„Ôù)‰^ˆü6±^ îû´zÛ¿ösnÞœ©(|êÚGBš±¢„Ã«å˜ ÒØ“ÂÜ‹?*8=(¼Û¼³bPhÔ8µÛIÛÔi\ö”ì.ÜRN€—ÚMH†‡©îv~±¤Ä²f#ßoÌú.ÒÎ4wñ¡;Åñ.Ò3ªô•ØÊ_lÿFÔÕÐe?W“÷ÛAôŸ¾ƒ´+‰|ñìy´îI;OñËmß¼š…û…;x½sßÎhÇèÓÛ±͆¹mðÛ% ÚÚéþ‡…}ŠÅ1òºQ~K°âUú¿†þ¬Ÿ4ûã•úß/vnþ›mPqû³mx¾}ç‹Û¿ê‘¡þW6Õ¾Ûì ¶I÷»½µ¹}²?n}¾ûÙ¶;wv¦%ý£¯:îN7R#`ä«)7d?#|£TíP¾n\æ’4ž(¯«Êcä…AÑ9¦Zq —;ÉOι.]M27W°!í äÑHpÁSž² ôî¸l©"Õ3ÜO~á'h~'?ñJé>×Òñu!Ö˜¦9Ž}Q/æù¬ûðÅ÷Ï÷¿~öìðåá‹ýçÃçû‡ßõîF…Û£â,>¥º»n8Ã+ú(w›ñ|‚•™qæY%Ø¥” òZeΦн>Òw¸g³S7‡â|²÷¬³ÉFÕ˜ˆ]˜L ƒÿ:u¹(†Ž¶O˜UÞÆ²–ݤÐÂ$YXZÝaE_H”ñáԢ䴀Ü”!!0)0ò-7h¦-ª¨V/ÀÃ@â;‡‡°g’{‹ÚYRGqçZ "ËžùRÀþ~¡¨1.Ö·áî)H¿Çœ ¦„N¤>Û•~e=‚ÚàázàQê+ÒSh”Ñ_ÁA§ÍÕ$ØþH&¡É¤¡™÷‹—Ò`åô-$q?C8§ “WL<í²àPæA»­`‡ã|z¶ô©E$í¨<¦V¨ÛËç'ç¾60ƒ°Ö›”§‘oyE¨.̼è@Ý úX²éPúwÈ/Ý• Ê’ÂÝ9ƒ¾ª%×̰ÐD%V9ÌûÕ×Eb\ïêB$C»Zr§Õr:JS(?°œÑÑcŒìÓrbE?ZÚ̧9WÇnXëòJ|Y'ù u˜½€ì•~9û” Ä¥(6‡ùS0.ÉY2Þdu9™/ùjÄ"¬.ï®O€©¿k”gžùªÌËùxˆÀTR)|bÎæ·‘@P|2`]™%×ön8$ë×®žðôò~¶Á¨„IÙ$5ñ(pœ&¶ËÈÜŽÂýyM¿ÃÚêïÒÚü.·•h+È]R5³dœ–TʃE—S·ið³ÌP©\DG>¼™'4ä´Fo“[$õ­G®—xo8M?­0æíßúЕGO»”ÚÖN `ëë‡T›Î8ocÚ¾(Š‘¶²Žæ!-TTAs· ;wÊiÁOd-òåÊÇó"A­[Ð;"qÛ×¼xe ù ùÚÀפu-ù~ÅvŠS]èJêrÉ¡A])®ÛÇÀ»I¥Ø×õ`.3‰°r²ˆ¼Eš Â×ÄcÂÕºëæì éèÊv¥¾ ú§EQ)KZ¦Ð MGèÝø£©q²º1½Ê}W[ÿ¨E¡“ïXóæ¿AKÛôsµ‘Êi$ÕÄÄ›((pù´È…à0û®”ï Ý´BqÁ‚ÁïQâp{ö¸×X~ ÞbæÒ¿ä%3s˜z`Wg%žGaÕ~~ŒN·áÏ6Þ m •§ÆªÀJ™÷-SH¸ñ]Ç—ô`4)NÐY\šÜOÃ¾ŠµsŸU­Ü\Èp+{W¶xh‡,”È-;~ yª T¬4“›ûZ –|¥ÃÔMžÃUyí™â;Q@¹bšlß ­gL.xY ¼ ³ ×‰ý7¬}°éºs´.&F¶Q6Àì¸Ýgú‹ìöacÀ:ZÊ:¨hÜÜwZ{ÜxRŒiG+à¾/0íNì?_‰7@¦‹Ýð{;YÖ‹jn^˜ƒ^NaŽë|ý„•'PZ:KKn)¡Ñ´HÇPŸë Ÿp-¨ö>Äo¼mBWcî ±‚¶;ÕPR3LQøè(Qø¶,.H9Œò»ìàÖ¨mr„ù&¦(X£ÚÓÅ»*uƒ ø¬»…±#hcå!Ò§kô~»½dˆkT‚šì„MÞõ'ƒÝGáC“BÛ¢xEqmoSÍL¥ƒáõužiX/§ÐqÍП/ óÜB”``ÇA-'Wï˜$÷Ç2‘…q½$Ó6i¾fn¿Ôû>Á šST ]°‡Ù ,VÃa&í1¦%xÛC W³©æíîó*`À‰GÈÜÃ…"ñÐç ª"X]7² ·(õ8¯Ï¹ž7A­ fõ€[Å›‘{ßʺ/æU¯•øøOÙß•F@ÓAšƒçäÛøïô¶#EpsžºfI¾™½O×W«S C Ÿx¢Á¼êÎùDÅLwã¨>”M!Y½LœHœ®²Ï~Ù2˜#õúJXÒ°¡[d> =Ç„„jCZÊÚáü¥+"ú1‰g}}œÏÛQÄ€ìÔôAû‚¯%°€ïYË¿Ý×tÍ3Õ@÷ý©ä:²lÐùJ´äÜ ïØ¬f8Ú,|†é§š>Ô®ŠNsÏß4.èÐm òä7]£Ê-ÄA‚ÍŸi¯˜øðÜý"' Õü8¾Â‘‚¦abÉSd“ÝK8’Lz¸H„#:Nrx[ÔÁ i,nUÏ¡‚Ǩ{È%aÔ>ó4*yTÑh J:äÕm½n§mJÒøMxc‡ðNõñØC‘ ƒ)@gÓX‡¯)#íÅ®&оš ÀÔäÑ-據ìXæ¶«Ù¢÷ë†}…w¤¶fµ5Ç– ’©–DÐb8Qñ,+{ú;±— Ìò3ˇÛY»Ã"Á„‹Gcà° ó)y†cÒ|¶B°6€‰K´íðû[-ùì…—û«i?{5‡C÷jþ*-¬À—p†ÒE?Î0žF’ •ŒŒØ}cx°æÅ™»›w0??ÒÏ^[6>~ÒÃæ_ºA˜vœý6»0ÿ/ÿùjÚì㛯àßïèïî_þùêŸ=xp·þºß]‡‡›Â0þ ¿ƒÿ}µ-ýümY-Šk"³AçÕü0ßë4ØnèÚôÖ7;ÉÀpYS‹ãùˆ³P¹ÿ•ÿþdDÿë~æþïÔÿüìó϶vîì@ýÏ;¿ÖÿüEþ…þ~óÉdûޏ€üaskgsûól{k÷öÎîöÖÊ ûÏ!gÞRcõ,9…}àÍÉR;;m„ž݇Z/1pë@½ìqá¤{Žy6Mª ‰#´¡‚`£: |Ñk yíXÜ.…CqZ+Hi@/#g6€ä˜a|r7Še ÈÀ1æ2GËÁË|4fC*vOßâ,PÍÁÖV’fÒ)X`£»./ú^þ1ʧä{Z[Hï BÅ‚ ¬æ„ª1FÒäÀÂÔ¥n†ì“#™=$ék6{ùD}/ÆèMó¶\˜ÍGmƒ6ü‹ØŒyq:/jæ4~8/Мî 7Ç“Â` ŒòñÁÕ"¥HºäÝá÷”U[*Ðm£"€Ys‹Sî´¼t¸A½ªãŒ—'37‚ʼdnÓ× ¼,ÖDú7%(K]ÍÙ áëK)S××ÞÀB]ÍGÅœx©‹¢<;_P!w`iÓeޤ"-At¢SaWXJưüÀc;-ß9ñ¾b I„­^öìm1Ÿƒ o ²ÖäåâÑd.Ëé¢û=œïHíDŸ ®°¥™KŒu]”9È£âÙ€¥=Á£†k´æ¬1‚IÕ!¾¬€z583$+}ƒ9<Ä>m iá×,)ÂÁ þˆ›)Ó©ÝýóŸŒv†ú@Æ€6Øô/f¤AѲnÚ ²‹ ¥¡L{èÁQGšh¹yý6E+"üº$2žâ$tÉ£:j’»%¶ÒhüñXœÏ«HÁdP% ÖT®¸ “A“*lÕŒ<ÛøÓnù¶·¬òQÜùÀw¿Özá´†Ñ_hèï1Ћs÷r©ÐqÆž BIQz`.FÃ…ûNMüõÆ}é+2.c”:{$„ ™,Osj;ÒÉ‚ J‹÷† ™*K™rZƒÇèsNa–U6*!È\|ä£tByÊÉCµ£Ù¾Ù€GÖÐÈ9Rʽ_‹ÀP¬3ÚËü²èÃO>ÉB™MÞ ÇÅÛbìÖe€¾k`raln®ì•çT†œW³Qw`|bíGxríû…÷ø±q®56+ë$‚¶!c_"ê¶Nä’Þ½wá‡ÖWFU\–ІÚ/zf­UÇËr< £kÉ@ïO1J“ùêÓ æ¤ïäîà îŒK>Ó“²¨}*²n¯¾^¤_Ö'ó™|Ûéð ÎsŒÑtC …þÿìýësY–ÖgþÎ(0="L’™ÅW&H‚™èâ«°²«AV˜#Âx"Â=*Ü ²HYk5¶#ÓÃvÇv52idk’¶{Z£µú¥Uwk%™MIk6û¡­jÆzÔÚý’-Óì®íþ{ÏëÞsý̪êV²*Ɉðë÷yî¹çœ{Îï°³ø£ÍÇ›ž=ê?ýì) ‘èƒE·œ–Þ«ðEÝÚz>P0Vœä ö l1üÕ.&a~Ào8ÙmÃËp‡sa»ƒ^¸ô36ß {ð¯ÍúQ2ñõ3ÊU+ P¾g÷);¦»n©]Ê9%pÔ»vÈîðSa’jðqÆÌš òd×9¾aÔjt…v>ôì\vôáÆ¶™gG1 0‰â´áå8åIéTnœWÕF‰nŸIeæQ²j¹‚(­=»dä“ AÊ=­mRƒ¡êCØmX͵\3RË Ù"\δ ÷Ýcå=a4¶Ð$jée•VÀª}ÖÇÊXÁ„Ͼ(s$xÐVTÕ岞\æIKîxPÙܹ c{FQœN¸ñ|q¢M7,5ò¡A]!q¡£3³ÐƒÌpO·)À ¶ú;øÄ–÷Ð8ìÕŠ`ëJÔH^wœ3‚¾¸mÏ?èY¹4d®TªšÜ”‚Lª»‰w]7ðÀïºVPºuÃõŽÈrrA䌴TSQíf´²æêÍæBJ²Åܬêøp;µm m rµDL:ÉXM­‹$g?ÈÊß—†ò_§UšÈEf^IRåi_Åÿ+UE»ö©c¹Ï[‰Žv}‚¹CÑ (ø‹–P$)„ºº·ðÎÅEós<ÃÀˆØª€T‘e"¾lZ©fKç ;ße±k©G÷`S¦eG—d„Ñ:—âžÜ·–d¯C„ØÖÈ85Ù^¡{‡g±’ú’«psßÿ"„âÑ>ÿPr`íÉt0ES7…§]<úBðš±3Ê Ÿ€…: È?Ô¬®nYj[¦!›•ÆÜ î²S*>f1]ïc¥XUR„4†³ŸÆP>5; Ûv}”gp/)kéU&á3IõùØ žåbÑ#KH´—Ó@ðD+¿î$Ý»8³rå{C$Ëw óVÅç¡y\¸J‰Ô‡^w1ã1yE“ÉÈŠUóñÙû à0‹á|®Ø©†Æ8§€'îÏHäV„ûá·eu ‰d˜½<=0;K‰¿æÉÝnp¯ã±`Ó£÷*J»Ã{' PÀ®/(¿À“ÐÁ Ï)¨Ïuìõ/à„¸ÉëkKuÝ!SÙ^ZyFm±T¸}‡ÉØ.ª›9)½ñ¢SV‘}aTË#¶‹•f­LeöD½¼EëxJCGÊSfÔ’j Eª-+ÕK16U^¶ðœ¸b ‘™ÅËs bi ÌsÎ%ËÁî)ÓªúãH謆:&>^ÿ!úѶp7˜Kú·o{‰Oü?2ŒÔYsV|\yƒ­¤m O»ˆu ˆ‡J¤ îècÇ{T%#?ŒQ勎lÂÂREµg;RU÷“%(Õ]o3ݬoå>Ådˆ£V¡ÓËOñÈW!Â+™îŠµÍ¿ùÒ]œ·tð§ngËŸ×5¿Õ [FtãC›$vÔƒ°‡éa@OvÙp'äûlŒü52‚Š9ÑP…Xpå ‘)`#z¢bþÈ*q8j5?ùÜ$_1ðüás§G¹²àjf”e–ïêªSc³bŽÙ»­»\W‹¼= PÇqœÖWÂk<õÎûZâ­Ï~¬Mó¤Ì!-Jfɰ\›_×ëÚc£ãƒûŒ)†ç›!*À|¯èùß{ö­7Xs¼?èù‚3­Ÿð¥fä]ÄI||I¤£‡Nó¥Ñ‹m iC㇭Íß`0ëÔtÊ‹Ëmª½ ƒCÄîÛEpkÍ þ­»Ù²=Ø»WÓB æ(>-½Ý¥7=g:rWàªÂ\ºFºšEæx$pa¿w`Ú´‚mçU þ7 ãä¿Óž„½*ž·ù°Öü¶±T;äRž3CÃø¤)±4ú>µFÕÖþü®$8AÃeÞóTÖ¼„¸ECú¤M¥J óeévtç»õŽŒŠF^ø§ Õ”! I‹®"2À`¡ ´¹«G3¸DFG$l”q—·ÊêYˆ¤$¿jÝ¢ET7‹öÊh5Þ'A¯µ‚uõ°/-åÛK¦^bÎqþ‡³dʃtôw#úP™(R=0€4oßÏñÝrq÷™òÜÎyeª—¤Ùšíí$Hk®­¸ù,¼À™ ˜å—ee¾–c*ß&R‰w ìƒf±­«áñ'h»î»iP÷ýå p—÷þ$,!߃#·z‡[5&;Þ¼+f 6ö­•U:î(ßé‚3ÞÖÙlç±Ñª¡°Îüjí—†ê¦\ÙWç÷~ Mvõž`Øø™þb8Óþrí¾ð¹ŠîÕø>þK:”o‹]@jÜ¢d³$ê‰ÝˆZÖoò‡»)õ? §«LyXÑÆHKôˆ­dïûÃkÁ>ËÛ€NÂÎ/œ'ƒG쨵DÓ»–ʹã:¤1†®ÿÖ÷Ü™ûr‰ÂÀs±41¢½ BÇ×ä²ÍqTE}¬Bn^Ûºø—j¢ÂfF 4iþVî„<ÄBHòÔß“Ã1`ÐüïÜjc@û¢ú~q^ÿÍsïîÆÎ+¾t0À ¡ÔúæºìÊ E+‘3É=Æéû˽c¾9¤Æ¾.Æ©n»J‚§g×;7òö—kµàjÙ{¶ÅXnÓFäy6¼yõ Þü3äºñKÇuy†Š¶Ñx.ذäh!` pÐ0£‰UÖª\ÇP%p‹ncÛ•`¨a†èQ–f'üaS:ôša”h[‹ºJ[YYfûdïL³Ù„¯Ã?ƒ¿ñÁèº2XA6³žìÎK•]Ùf‚„UÑO¡5ú²| Ê«¸—ñUõ žàÒµ°õVn¬psJ µY†rt’s$÷~–õ÷¢)àdÑFËüÒ’ˆ¸ZýÜ\±F¹sÀÂ`_ɲžð1P¨[¦âÚª s½`8!öóB™#‹žf¹lšs …WqÐì¼û×>f¤-B¤3p4 ƒmÙu7©#éÏ p’€ÕÝ.Þ‡‹>³n¸XÇëÝ̺ñJvé®-¹$|›ÁR;X¡éÜ€‚@™Á5Jñ>Ñ—¢XÛqU$…‚µtZ;“P”k âÜ_b଩ðiˆR*ÍÜdûîòíØèÀhøÊ3»ëÉþÆá¬HZ-ÑfÑ >À°2Àn3oîCʽ÷5¡8Ò nÒâ&Œ ð@Ã$øÖÔ“\ÝqrÁžp ¼üE¯ÀÐ'‘ŠJ$×9Œ°‡D+fÞàZ¹?z¤Î~%¶ Ë7„€¾&#W'´S­ gµ÷zfyÌ Z` oA°tëØÁºp$¼„ªÑóœ¤zžë%%_ŠP^= I¶Äë·öÁy Ë7Yõv²·}£‹óºÅy›Ùüs)á¹À³Ø4ˆ ’ŽNoÔǾÔ¥õŽ, ïüÀ$ö\°þ;]ªl/ ˜’ðRÜÅDq54»î¡FzaÚ4D”P¡œ]!‚š(' YTc(Jq~Eib*áÖRžÁRè÷¦') æ…ÿæ.vS…þÖ?¯ÄfÔ˜©•ÐÆÃ®dåmPMj\ñüÍí¹áÕ÷°*(ûNÚøŠž²d@pN^¹â­h69eJGF¯u—`˜?YPبž¦i‚­—‚ ¾» A¼†4ˆù(…#²®ŠFùÑ;ã¼ ÔW˜=ÓÇöÐøH‘TÞÔƒ êà¡v*GU†Áæi2™¬”n}Rœj²½Î%×ÚœðÙØîEPôiÂèLí]`Ÿg€¹Ê³€³Îœœœô¾4"ToWàÃJ4-VLKË(;÷&‡…,@W¨† Ö\›=a#'óàµfB×™îüøù£;l:©_êõéwÝ&ìÿ²m©Þ§ˆ§Œ`AtÃÕ—kXéÁgçùæ)¸HRmüÛ‘ßÖð7¾ìãR]ûŒª±íÛmªÏã›f$¸ú þÇÏâÿáŸð?>¼Ú»Òûñ?ÖVV¯k×n|pýƵµ¹øæ0u¸ hx³‰\[ц‡ dÚi‡ŸÜ[¸Ñÿ¥íþöÎÖæãOµ?¾aþÿþE¸£ðÕ/:ï›O-þ±e~k™ŸZø!ÿùeóWçãÎe WãîL£4gð|œ¢õÃÈÇñPK)AÅ(°7ß…{-(£ub6¼˜cýüæ+åál>zúdk§ÿä{[ŸomîlH˜äý:ŠcÌnUÛÔcNÃå„þ‘Ù/Ÿ×•ïnl< !îÍ;8-вMžó`ªÁC¸µ¿ÈÊF£¤8µFswŠ=Ëc¶cìGƒØÞžŽ*åƒi—%hêˆE‹ÍûR¼±("ÙÇæ4–Ϥ)‡ò5´wðmJÊüT¹’Í'tŠxøíÂô +í5‰R´mÛ Á7De/L‹qkzI¢·»k˽PHôh~pù*XVV2ÿBB‡Ô Å–ÒüfTÔk˜1NhLR¼k±U¬Òoè eù•Ʋb¡ VÉÏ´®ÍðÛ®& ©j%‡¨R}€Îñ5Âë¥:)pBsϬV×e_ƒ»¥‡ë?}¶þéFkçaðq`hl „€_ï!¤¦7?>4Ÿñº'·ãR(qWx1}:³k‚ƒÚË^B`õZ¦Zþ"ÏjVLìÀx¸Y„tãâ mCJÚìMÛµÛ©Ø©ôe¶7NšzÁ ÷W‹bªÛ2Iô‹Œ³¢p¥ß6Ü6Ö|îAÞÖ Öü¢¥ô¨¦UAY«©F‹<Û%gLÍÁðçþ| [gfƧY™Ìe‰õè}‡Üç(>¥µ'MMÝM³>‚1Ãkèç>Íït603 ÷Ðì/ÈZ•­ÈèZü¹?8„KThËwg!]Ëêe@2œ®M³€–Á”ýÛå^\û:ЈnÛIqY|<;eiGíÂk/ )D…9÷f:h‹÷m9÷Í7a‚j—3€Ç1¡Q‘­¾•ãi»¾àuoNÆÀÍË4ìtm¥÷‚9uÂ[fq²ôàŽóþôÛŽ‹ EûÖŠ¼à*ixQX+õq~ii.ò‚Ïc{ÇY¥Ò#ˆ§ˆ‡†à\"j»ÜÀ¬5¬@„+€) zA›HrÅ)æ—‘ïu¤ôqæelŠR²ÍmŒŠ¸ænâw¸³{GpÁ*ÄT¦!ÓàSLÇtêÇ÷ºµöÙFz`¤œC´‹5•yL WóŠÜ· ÜT€×²áñç1ŸqµOŸLbâÓ¹œ‚KÙ¬˜Ì€Ã!sl‡èô:4[]Úƒ^ÙÞí:ºéx,œŠj&þ”®ªXx€g å€ïºôÍVضÜú\BiŸN.ê`-ñÇ¡ÍWiÈgr¶÷%u×ꉤ–ɺî†dñvY–”̉Øb•}äñކõY‘Aà8üNÙ\{4ØKëRÆ#ÀQÆ;HÏ!/M¦ñq’ÍrSe[%î±1S„îªPé¡ ªD<± g/UlíŒ(Þ®eÇ5-‚ϙк׫Ò=-êåËÖK­¢”›ôBµj‹¯zJBY–ÇÐÚ×(TSÕoÏҹ/¡Û·c=÷tªòÖ«v¼[íjWØM4%¥ÊËd¯Ô»§I„öXž´°Z`Ë;1ìzM/²…^Ì«W*õÈÀ¢ÝPJ Á·“g=’ñ$‚HùB〮 ÔŒaòýä°Â+ƒQŸé×IE-Ö£˜Ætî“´Ôp†.^ꦻúQî&CB˳4¢ápÎvgx`JÎ.C²Ù¼­ÂVº˜ÂïSI±@ØMƒ§d_ÕA Ûb7&ÒB޹95p²÷ö¼Pó¨ÆÌ´è0óÆYêª Öý `$ü–ùqMcýŽ:Ò𸭳¶Ø^AáUp?‰GCÓk«’RÖ –/j†(vøíA6EŒo¶œ²Zêý|¤I3·¾3–LIÞjÖ“àØVÙ©Õ¶ÝsW‘9 1v‡Óãt0J3z+ßYºÇ·VÌ8»wÁö3Ê’Åî!‰•JŠÕÌœq§ÙlZm΂“D“‰á8äaÆ&½NÕP™ù7²è!1ïnRêKÃrû~‘Ý ¶ì„F²ø ½a—:{6Q«gF̨{Õ1ÈÆã,í³- o7u~îÈjVMFSY:~PY¾r¥é3ºÕsúvÊåYæO•ª«¾¦ŸœÅó¬©H:¾[o-*±?ìCmlâ.Å ×a_˜G¦|¬Ñcsr[©¾ì-!Œ‹®`,/B‘'ÇÎD% “2Àx¥ÿP†H^+2ݲ ïÙ®‰|ŸC•Ü8W2Ħœï\uã-LßJpóÃõd<‡+¤Œ¶IˆËFò³HÎN·&¶s›{ß#´2©Uâ|Yè0¼»ÉȪA÷p.Å ˜Wè©^.Ó†R~2¿ñ!Ð4â‚Âj&ѧ:´¡%@E€‡9{ŸôÊï’KºÛ)‚Gª§ñ³éä½2¡Tâ¸/&¹…3®æfT¯ÑmÜðÞ(Êó¶½P®%NÅ©ÖãNI ÿ>ÎóÉ3AÏ ÷ V4P—®éL ׈G5]¡ZÏÝJ‰.››ÔmñËÏÒs=O¾¤BkWÜãèå(NŠC|r}Õ=ßšÒ±[/â}R3PU^ìÏxÙ4‡táïVNãýÛ­O¦ûƒ«×¯^oÝÙzp/€O·V¢;˜pp”D©2±$€a8ÓžD >ÛhàÈ(âjzŠO)  S€ Q@ÝOûi|@ùÓP½5͸ˆ’ä#›ßZ1dÍ4/?ÛnQŒÑ—‡ËŸ™â­J˜ÍF†Cë«Ü[“¸ØïeÓƒS`… õŠ—h}ô©È¿Y„læÉò ˲¹Õ b%B¹Ú,îkZÀ(‚ s ªv­+ïG·š¶[½àsŽ4pF¨èjßrÃt†ÍªL.wo2clké‰{ûÙ‚:ßå|yß÷bôù8£šÉ0ÒÛ~òòÍ&ã)äã Þr¨–9C-‰zSJi&b51Hf7L¾%™xÉ›X ™n»Œ²"aëaÁžVcCÖ§•‡'^mûœ‹36ØÈ'Ëæo¶Z£¼vBh¡q k&c®ËZgÝþ½Ñ8lY_†(Ó‹ûi<G)Wbr_ìO Y-à¡Q\ç x î”vÁ0ƒà·d¢\IÃNX»òÑb[ªY`+,s´é&¡Kë`¦¾ÈŒ†¼ •ßǶØë\¨œP‚ÎCµ¦}N!\|Û€²+´öö$»£J™ýo?";| ¥+lè"ȱ! ³ãŸ‡±&-$Ó‘¿üù‚tš×4E$JbCmƒT¢ÑaéáÔ E—»ºÓ^ÄÆ#iu]ú&Ç’}.¡`ÿT‰G“VožÑÛRs1‘Æh—îlɆñ•º¾ƒ•)y8YÑdÀø+Ÿ *âØž­>{ƽ*Ýt6]h9=Âü gû[°Ù‚¨²j°¸÷äÙãöû7²[€ãÅ$ ®ÅEáÛ®S]˜ê=c—ì§ö%2¶D#Hò~*| ÿÑÚ²vü$ ’96hµ1¶®Ô†1ΫIÃ_Ô_5Œˆ"9@íÍBšÕÝ”2™Û"úþÔKI5gZ7S$ ×5x$W}Î_C©žžéQ4´rš™“=ÅX‘$pК|c& }K5O)Â.[aÄ¡¡y_)§†ón±…ß`>”ô‚TT¶Ð‹ÉÖΠܽÉÓ¶íQ÷,Šo|LÚNcuP4—aù¨±€¨LlõWÑ Àë2o0%|{B¡´ß‘2{Á£l{ýR°Fœ±€¯Y1Pþüͦf°4ò”³VѰ]1¾3›ŽÚ|y ¿qp 8ÕY{¾&.2—rþܯI-_„о7Z 6°˜XÚ¡6is¢, ¹HOã“Ñ)iÑTZ’2‚®é-ðúÌŸ¥=ÐàÀÕ‰ ¿ö÷Nk÷xØ÷JI‘> “ä‡èCÇ”DóàG7º·vr˜/ãx–o:@†”ͳéê‘Si,t ³€¤±ªæ³+B~›[Ô2®&Ù… àËê,ô¤¬¨ç¢³³/hYQáBã ONã×çEYˆ›÷d× A”£ª5°˜}㢓îÞð,p'd§qV¹+r‡Ú—èC9 ‚EBÉ1"×ɶåÍ8¸Ö9â¡ë|Yœ´ó«-ÓÞj-FG°XvÛÖ„P&¥3&½Ñ¢EÈö  HÔ:#G'ÈÚŒñK†ŠÄ‰º±ç£\o2Þ-år§Þˆr¥[oE¹zbwè.:Ô¾DÞr¹Ö9”ë:Ê=C®ö„þÅÅêòn3¯>ÓÒKÿE²ªýêq©®¿ôÝ@…,Íõºüš¤æE%â·’»A.ä7ÍÙ`êÜ–Ïl@î#'S€Z+… *y/eZèRzoág‡ðq2šM£æƒg£K »wÛG\o+¸>ª}Žøñ󄜥rÉ~7+ò¼Qųøq3ô÷Ù>³üÑ¿¥ûz}NŇtQŸS ïpw£ø]1¿©—©­Ã×D+XÌå”:u¦'ÎíEˆ¶U370ÂØ”ãéõ/Óñ½Bj”"[‘:+%Ž {:t¶qhÍŠ¬Ý¸¨¾íi®ˆPfÐÜÓºSýõ”PYù®Í.U78‰¦)è€S3€|Ÿ£,§ŒUâÒ» œDj£@J68[¶ÎôÕä»óŽì´Qu×Pš²€ «øE<ô×Î ™k0o¦°oÈ™M»ÊÛ—€‘|¬z䤬×ÖY…çDg±.‚D0vîB®í¦ñ8;ŽñÜíT?ª>ϳA‚j=^%¹>L²¼Èk®yøÒïöôõw<35ß,¢íÈÏ,U–‚Öãzó—{=v6Ë)Už¢b™ÎÁKÞ:X©Æ“©1Âß 7—Ä[CZ9ã™;!龂IJ/Ž*ï$Ç™c…_Hv¨‰” n`ä3ª 1ŒiæŠoðˆswwüKÑq´M®4¥ID~±{H:ï/ò&å¢2.5ÁjëÍŸÚî6l½*áÂ% ·ºÖð­[ZÙC f—ؼåy-BžÌgÎaĆœaÖxJŒë˜3'`‘fBcÀpߤ:}½I€¤BþE :§°–/ë»û‡Žóº%j䬱m›:MÈ4sj8+<€CÉâJ„€ tè«jküåë½ÏÔ+ö"x!´Ï7ÓÞê>ÞøôÉÎæúÎæ“ÇýÇOoˆ·ŸEóŠ?]ßù¬ãÁú³‡;U/'ô‘X¤ŠšWëý„Ϊìþ“Gë›å^½ä­Ñ³.u÷æVS9ð4=ÙÝæ9ë4ßï·T<Î8†<ðI>¶)l-Þ8EЀ#Hh¯ú‰Ú,‹nrBâMF> è…DÒÌ ¿[O¤VÙèí=Ð;^8Dx¦Á¶ÞѼ=¥Ê3ãw¼ z¦äÓ Ëú2ç(©îwnýiR˹ÍÁ©_?'ö8ëÜØÂa9 (hUñTæÁOü"eÇÕ†µµíº|?,³Yx­†2åqT*k˜ÛTg5• mpî]ÌJMØ9í3Ø‘\™ÙjýJŸòP)B‘ÃR –eÄ=ª­ã"‚ù^-ŸÇ†R ¥šÍ cˆSW..¿ô:öÁ¼‘“±¹ÁÃe}[Þî¢{­µ/vS+¯ƒO·ž<{Üý¾+ØÒSIM©0IGIuVMÞØ;akÙ¥Ëwl;åÍ?rwý+Ì"0-XÚ£Ä:œœL4µ]ÃüŒ¶ ¬“â@h¹©Î R4¥rdv&à¡ËÔaOYÝ·j!˜)±¹´A(–“´ÃXS­ŠÕIzLJó×)DS¿c<áÐÁ¦¥+ö \,QËKöðUª¿š÷V´&h¯^êˆâ¤ÄÚI¥UFH|û|'f‘¬37IË’:0Xò´¨3(]•5ÔÞs×yï,ÚσÍÇ7¶‚_zb„ŠBZO›JÀéè6Tlþ­n–®eK-o{ Í¨fw葹]‚',”\<©Ù†šô®á['úU1é;°ƒCS:l·«VæVúþÚêj¯\r`´ &(**£|Q}¶qµ;½ñuæ´ôZ×Å/uZvë³8Q,“;h™9G`õ8[øüËãøÈ;û(Aõœ“o›œó+åævÐJA¿¶t{Q”R#ðì,Œ³wþ¦Sê“aŸÆ…³Ò…lZ2‰ùaåœ÷å>>îùŽÆõ ƒíŒÀÖ^ØÓõ)IäxH÷(£b0Cà²ñФý@6Ӹ̅Î@D  {£ˆñmzµ ´ÇUšO¸(oæÊÏ”Êæóù^É8T×Þ<‡ý¯ØÍJ ž»ÑZNHŽa SÊcDTd´ŸA”Ã×Ô¨NÉq\³ãkE¼’Â"撘ș‹q’ 2(Ù— ôqpÍZlúrJXÎ[о"NôRàÜ);:F«2¦šæ6å1s¤× nÝ>2ÖåáHe‰ÎÜ ŠyK`Ï^ 7xW~…F!t-EUXŲÁ¯·'"§Åvu­Ðb”ÍãdHàå”­«ƒR®š‡æ•T'Ã8ìo3ñ¤ç™/¯I=e~_Μ5o¦î¢#‰5B,íLô8‰îg ¥†®*õ¥u5^ùúúÕdŸWé©Y|ø+ó0Ÿ7w‘g}¸I½2Ò‹·£d ÈѲæÅVËUßÈ”™µ^ê©òœu»ÆF²€èÎÂb ;fÖÀP7 . Ç~1¯Žyg?~“ÓŸ²JóäÇ—ô©÷­Ì›ña5ž?_ïÈsF!’Ë“ý‚H®Ÿæú¨½°Õz–\¤Sr¡¢ƒFñ^«Øå]WÚiRpóx S ïQé3ǃõ,>*ž:ßß¶VС#Ag“‰+®œRý.ä¸hFàÅg.bËK,`ÀµÕ92Í:.2’§¦hyxBmˆ­ëM2ŒKëÐß¼¾Ÿqa?‹Š' ’ÊÔóBGbsp¤%E^ó`ïfY^ºÙ×7ÿã¬QE†)s À€^ÔWôò˜8BÍÑŠƒ©:墽)VÛÍÙ›žF;–óÏ;ˆBëÍT3¥ ¡sæ’Ö î ´ Ã:%1‚Ôœ¶»sgcÜL=ó&ã‘Bʨ›†j6³¯ ês!xê… M ÅtL‰ÍˆéJÝy–ÂYè*ðÉIÝêÆ¨ÒAI¥!JxùÈœ)]Ê(§(èz‰6Ïó ´Þ%!À‡­ŽÍ õ ql!ØÝ(‹ùHæÃ˜{Ž­d's±g{µÖÏg^˜ƒ{#E ‰ ÁÀ^XHYÖ •š`Â3ø§7}*Ð&Îܱ©EVá¼u)o:3‰Ù„vMõà\ÀèÿqmçpÎzƒp¥Å–Þ2dé"Š:.\Rå1¤Xf1Oñø*ˆ/'×Ô&*&©IFd \/ÖÆìoÓðØ*·½¤Ÿ¸ uþ!’Ô•]ËÍ·å;òÛó\#ëYÜÖìGɨâµê18ˇ¶&7©¾|¾¾sï³ûO>íolm=ÙjŽo­ÖØ.À ¶:öÂJÇϼƒD_¥ËBV˜Wj7ÂÅòJ•-zYÖqV‰â—•ˆz+•¨RÇ<žK…}KïÏP)ÒfeJRc²¿Oë†d6x”žz$½‰›q½nu&rne:&™¥»}±e'opæ CW÷ûê2MŠ—©N‘Œ4 †Š}•· ž—²{8Í‘öF¢òo¤xm¼¬W¼ÅÚ•¦¿]OµQ:ðY¨¹v®ÝòtQ£{kp7Ò?êH}ÏßH¤%9ˆW³Õ"O0Q2Oþ~Ö„Ò¸{o¼€wèh^ªÕúÉßéfà–è­¡ÅO9»Ñ„›¨nGF#äW(‚s9L²Î²¥]$Pö¢¼Îâð ¹òùF˜†¿ËIm5$ÌW‹n‰JW«ÅsmbÍç@n¬b!aÑú"ï pU!ÖŽÞmçPk4WÜÜw{1qIlçÖ±Ñç 9F¹¨‚½Z 68;DµÎŽZÀà·t./q‘;DŸ±sãtÂnõ¡Jh»Ï)r ïe]ê ­§³¨[µ²¸( —à>Ç~YHtìbb0;ð;gY#èt2´tõc|o7´ L²9/ùºÑã9¡Õ!ûQÉ®çšcú…¬wÿህ„²œ„Ü=s‘Ÿ¢Æ—êóô¬š¨´²fÅWQ^D˜K²ir,+®«åE6!ÿàl :¬r‚ÒAÓ•L÷᥯ªuO˜-rÛy@ÄOt§êˆuV´“l:<™F“6ÏçòYªU‹ùʇ‰™ÿ3ú5•8z•YBxó*¥Ãަüî2}½}R“g£döËðrsƒk*H×$9à¶¢#–êÁ6ô”DÀ¨(©=h)@Î{¶à"°ùR&„M•Ÿø¸@7DWCAÇÃzðN—zJhˆ öŒç {’ÁíóíšuB?G‘TÀ3nÔ伪u%jcÅ/m‚¶çŸ‘[öîÄh‘/“±Àˤ³ñž™FÃÌÑ ÕldLŸ˜zC‡Þ›Uˆ´»ªaíAœŒÚ†Aöa'õY ÷÷R'X Ö®γ¶ú®­u#]0­ô½g”=\"·'íø4Ž; =€h}ˆT²*ï'QQòÖ•4ɈXçazs{gó±ù๗ZâœÂÈJ#|‡)Ð%Úõ\Fµ¤Wã9J}-cË—K}×N›åùD§M¯¬úâÛôÞ&ͫ׻32»À‰A»=i,PÑ~Ìa¹tyf¸["wlQI@‹ÍÝ®å˜ÔÆÏpôŽQÆXÂ8 ö"ï¢Î¹¬m}ÕÁÙŽ— `ÛÀkj@÷5SôÛMÓ"^>EØp—â÷©r21¬çûÐiSÜh‘†Ÿæ„E|¶óèa¸"GO㘃O‹’¹ÎjÀï„ZÀ^<˜¡cÈúò+™NcLqµ ²©‘Eàöß{•º¼g¾Ü”-¢<Á0$p­‹S`8•Xߨ“^ö_BЍl/ÄØÜ`ÑNÇúk—óÎr®œÒÇyá‘x¡Ÿf¡F§nEcBC€Æ£Ì7`b¢£XµÞGéªmøàživÞ“c†/;0Ó/K Gc{éÑBA¨<µ²€²š~e0Š<.Ò6õu€#¨JÄÕ * £[ǦãæYÛ4Ö©—“iyú‰‘D uVŽßicóöƘ0€þ*Ä•1çZù™šü%£Å3 öe´·7ÅÓ,=ãÇáа„1Ùÿ†þ“à?¦ŸG?œeªíôò šÊ ¡ŒÍiþñ?$m ‚¥ c|0ÜÇ׆ôYEŒ½8\ÿ¯àßàßWñïkø÷uüð¯;|´‡•ð7jzÂÐ+ðÏá/#¹àoù|ÃàÃ$ÂNP`~šíÑ?XPÜÌÃb/žâl¥ØÏ2ìqqHÇýŽÝ*ðÑ [8ަ!+p€9_yª¤.]X›Z=nßK.]U5KbŒN:…t^Ñ‹ ôJ›[½6,’·Ñú!cOÞÛÀo—ØëØÝpòªŸ¹·oë˜,°1gþøªNÊ1EoÒ uY÷ùúÖãÍÇŸz×uU{Δ€1à €ïI6f<#ŽùvBÑZ-fw]Ûj‰ä˜&+ŠÑÔ^Ü|‡Wš€œuÁóËae1 Ó +ŸvR-Ó8\œ¡3îw4H!Fk [3ñ‘ˆXO!é^§A—ZU×=ø¦±ÒoÁŸ!Dˆ[l¤¬J©ËÞ‘œé^ ZÝŸÍÇÛ[;Áæã'ÕNµ±ÂZ ¹|oýá³mÀ<ì2¤üÝq3/½ªöÇ¥Å={òÀUÕ_ïFlWñð† ÅX¯£Óáà~±¶ô å1/S²0m•ý-ŒÜ5ˆCÄU ]<$dÚC«ñÑD’T‘æ°±f§fÖ¡DÅ%ó €IÈ•"Iô.45Š 6B¯X\•sP4ÇÎí0° …+ÌðFÚJÊ?é|¼MÑ_õÈ`Z±¹ ™±|&ä"$æQt¶YÜöùþù,œ²{DØ<ó®]A%ls¨qzökœ“n~ÌÙùÖjûZ¶>k{®{À9¶8”–µ×™iTÚì[`iñˆ[—¨ê–FÓ¢Ÿü–y @«a·ø(Zª¥2ŠVY ˆ VÀËé¦Þ «QZ«v™‡é kY{ón™#ûÄüŠëÏŒE*~“ƒ¢bô}7ûèµI~:Þ´zP©érZ,÷,¸O†ÌœoÃèÝÒUô>Ù~ȇË6Æ8®~kF¦BGß!|î»a(É`ú‚N©ÈÂ)ý£×ÛX+ ´ :HMeü¯gw¹2áîÕ»B*î»ÆÖDЕµFÀ®L¿|ãù1_ÑßE_ä(_\€'åß-lT)+ËQœ‘£/7j¤ ú›ûLlù˜¹ëºÔ,5©¡¥5ñæ& ÕØ¹|·ef}¨m1žòyÉmv×(¼±é!ÜHÑŽ^ʹM]™×ÔhJS‚S4=9G^;,×..ŒÀX+„j² ë.嵐S(ûj!|ïè”KLã–¸5U[2¶ìˆ×*1¨­ÃÆK 0:)Já’ÉR¤&vaçn± Ä¦‹m‘m‚á³6$OaÚ³¡mú€5ºêƒæt[8÷Ô˜sÂTA2œ%­œoÃ~¦õh^È) ÚÓ?îår¦óÉœáU^ˆ·²cºÿI`ÏG?:Ž^&ãÙØLV<  BL cè4¡ ô±{Tƒz…Íq ÊÜ•««%|T¸VÖV?ƒÇS—îmÃo˜£ÎÆgwÜÙ æöur‹çkG^^öœ´Qp5.dlg`@7+Iâù #´©8ÜHcŒ˜¢}¸GŽ0ohb6µÝÅ\àxc~Sˆ‘\}m¦#å™b`†lÂáÞ²Ñ ðºMHˆéFQ’ËÚ •–ãºÀ|  xÂèÒÏí ÉJ’eþœ`sšÝ8þ5!ëÔ‚¢cK Ãt\ôC€š"kŽ¢0èšð)?J&y§:=æm¾)Ã2\Ý’4jæl‚©N.j,šLŒšŒú_; ÍbjÍ4F#r,p†ú™,W"¹×ž-MäXƒ§¨‘ ×=„ƒ¥ûz±cò¼¦ctïF£󦳮¥€SÅ  6 xPB@·–±9õƒ7Åþ t8q:A8£)É0—Ø­‹äÑ«h-Fºå{#éë TA¿ˆÌ%6 zj´ØÇi¥†Ü=°drµ‚€4ÌW§uò‰^¿äÎƲ¾¡GëÿÓúðÙÖúCü¶½³…L”>ö×·¶°ú™!âÔ‚÷˜-àœ»ô;Ýn“×tÞ!.f^Y½Ø?ê~<œ>Ò8Íš‹ÃsÔnÉiõâ~œí·a)\¸€£›Å6KI.†à“üþÚê•«´ÆëXE)›$G3ؤ4⎨¼ÛìÆSrªgŒ‰Í™˜§£àÙ΃傻OuÆÁ¨ËQĵIWÁµš÷p»õüåÆƒç/ïÞ5ÿ=0R~H—¦©¬ûk7È4»|ù¦7fÃÂÇà¨]L©ÿrⵞ?ž¶à(jµ:|ÏÎTlJ§ƒñ¤Ýúv‹ã…1Í›iW®$ŽÆ‘Iy§ñ‹ŽäÌ™iÝ;„vM«µ–Ïör×ëµZÿhÝož¨Ó´þêUP÷è¶%ƒCÄ@*HnF1KÆ(0¶Í’5q"®Æ×;‡rª‡?\Äê¼SѰ½k&ŠÆ‹{>@‘ºi`ŒªÂX–kTx#hóÓÍŠñË )•àõj#‘Ð.„y þî)m¨W¬ÌÍ܈J®8–\MóÉE$E¹W”gŽG­‰(6ï ­>šå¸õÿá4»ŠD¾¦‰s=ÿº§¯Ì|ں✗ÐßvXU+'@F}zÚÖœˆ'XÞ«¦¼ƒY òSóñ%ÍÝ»š»ãp%ZŠPù­×z¾ÚêÉ´ØYR;PŸ™­›g«£ÒkMDêñ´Á/*Û*såòÜ.[×v1ߥ‚ÿ ¸“™q°lÍR»½¾ö uí›ýÄûéŒmsö~1ŸwÝŽù°´cêùú{ïÕ1|Ù¢õÏËR (ΑÁÇÔ 4ÓF›%wñÅ×w´î¾øzèæÏT?Ér!ÛÖ‹VçÏÁ¡yo Ž ÌŒEmÁÖnËíA«{È6UošãMw8Þï8ËJò*‹×º¹ õŸüž1ðÅ.OöÙ»_vÜ",Àq€ë‹ v”¹….ÜÅ_À~–»Üņ}"ñÏøÔ¹þ .BxµDGS tÔRhÿÉÌd­ZÛ©N«Vç©—ÿ»*@W–ã,©‘ÅÞú:i‰ß¨R:ßçVì¸×üÞåZZ¾Qà}N‚?)¾Áæýw¥DË…ûc°¹¶ìf˜†;w*ï[ZêÌ¡o®‡ˆs…á+»Ó¹ °¥ÅˆSð¬qsÎ6Å"Ó]c}}­Óºå•{å à°‡ÁR…qx öx £Úx7ô*Ýñ¾‘êbïM{Ï÷uz«à°-ê`&>²8I|!Mfd%œcË·WBöšÇŸYÏÛàHϳª³HÓBY{0TµâzìúZ‚ã2Ù³î«Ð½†ú¼Ëj·òt}™+A²mp-’;§'î®) Ìg°FÝ´£ƒºÒ7_ìýSº~出vtìgZˆ ×å>ˆ]€U . }O!¹sìÖ“7ßë™~èä§‹ˆ™.!äÒœ¹:Œ¼ª³ 0]7É?ïÛ® Ÿ¤hN{¹5ïâ‹Q°ç]ƒè”’ uÇ`·—½Î¶®—|m¿ó¶ýŽWÒô 7Ôìh¢0T´ÐRQ?Ê&õ˜äÜ-’ Mž“‚)±Û?œ[óy§Â³»Aµÿâ°Šn`"ŲWÖB!”¬­ã½MaÓ¬­hW¯”šz–ç5m¦<ã'ñ ÙOÿËuͯKà%*–Ãa-ê£Ó_´×WêÚBmâ "ÖB·ùåƒrj/ú˜§lØfçÒÈüpXÄ0%T‚aé´Ø¼ï`etyxXÿF ‹Æ¼$þsbÎà…5U³Zû‰•`T´".JQ¯õ)ØïùÛ“£ ¶´C†¯]/Ÿw9eË^2)ó˜ƒ!æXè ”säEA‹ZÙËõ^v”¿ÿ<ØgŒ\ï-ÌÒ`"$E0‰rp¥Fê!ìú)ä,–Û`>HWÔPY­¶ÀΚOÌ••~èê!õãp`z«¢ŒÄäTñuÊG2õ oZÈæZ€£–O‚ÂAg /H@í½,3ò÷¹VÿMÐ}tÄ]àÖƒ;Òñ…×ÇY‰'ÕáúøÓ´ô’ ÍõöÔ1Q®DÝzªlG¸Bå¡R£á:‚ò ÷HBdA¹ÝÄ KSægî9e3$u?™&ÖjŽºb:έóÍá´hæX×±|ÅÐA­¢CÔ¡(sΤù³«é6¨±”çÐÝ—é hH*Ÿ•ÔËFȯVݵ¤%Û°ívXS½9¢»SÚ›5¼QÝçÿÙóŸ·m6o“é¬`çÙau iÝ XZÍî:HÚœý‚_&¥ovõ*û¥azª–3šš×:¥¢y¯&P¥9W sÉBQ’×í¦éõŽ¥ˆêI`ã {’—Ê$į̈bË$³M¢dšÏ­|ÛýË¢}¡Cßuo^r_Q†°«¬ )Ì=×X†Ç×FùËB{Ô.¹¶íi0À7!"D4Χˆj£å‡ÔT‡.U!'$¡Ò NcXS#zIìxæ°€Øô»6d;³Xa^TÈ™„èÛQÕ¼tÝð\ÚÞ…A«NÍYžO"P&½i%ï2ð´ñêä Š€#*ÀîVØè ‰UùÁ ä™S6Jê9%ÊÙR•W›×pK ÜnÙ[O±:;lë¦3zU²×+ùçç¿,ß™¯§î½=/»Ú>Ó·š‹dâõ·â²'¥>t}Õ/šž~¸XO/XK?[?Eóô ÿÞ¨j).2âßá8.’AÛ<>yõbÙÈ¿ª©šìk†ñFÚõ>&åË /ÄŒXÖü`íº0íº‰®²=È¥Fxø¿nö'€ÈL\Ã¥œL$PÍç‡ÊIÁ˜(H×¥!{X6Í6Ã"³àuSÛ Æé€"ÈÝá—§eƒ1¿ù¬°ÚûZëF •¹âgq4M_ž€…x¨z\xb\ ¸©=t[mäJËkf«tÜÇñ#|ºa?½z…?0ß{?^5o߯×ÌÇ‹îã-ütÝ|ºc?ݺí~t/ã'³s[ËöÓûøé#óiÅ~ºDŸl5Œ©óÖ Æ6r5¶Ê(ܵȎ uT÷-þn°Ï‹`çU6E$ìáAfÖ­°Ô$¸0³QØf¾ÅžŽT „xsäÅQIä1{ÙÿÍ“h¸³ ÒàGËæ+Ø¢ñWwóúÕœ³ý[ "­›øi0™å‡hÇ4ý3=0m[I)Éûædާ@XÔ¤òyÄÎÒÅ t ÖY’zvÛœE­Ú7Ã¥4œÿb[¿ˆs¶h“ýf‘M²‰&Íç6UæpÙ)D”/h±8ÇЫ©/Þe²š,¤´ä3Û›‡ ûròÂÇŽÞ4:N"WÖ%ƒÖP64͘6õj³´HF„>()nök~'F”¼ÝÔoÝî¨zpû£:±ì;˜V$þò"¸CvvÔPäb»Tèv]!ž2ØîR°æÏå;^=>ÁyTªjE§Tu ÝTŒ¬‡Ñ®pÝ>]^·kfXŽyë0ÎvÆei2»T}<µoçôå:¿ttŸ?x›þG6…³c7Néü¥;Úݨ4ÓhPØs)Úv̬ýqn˜rà.¡=OS}óŸÝrïi˜ÅÚŠ¨»î®ù Ý5— •.š—ph<ô¥ÄÞV74¦G&ûàkÞrt‡Ô”a:0sNùw²XضbÙ+vعa‡ê×5üUÕé»Sè>®kÁð¸^µ™Ë¿êô9ÍUâ´-Üu"œ|2J1¯C7 ºº †,í+ åž9/š]š7÷Ù.k4+Ù‰Èùö‰Ù)]Ôɉào IÒ&SH¢}ÁË0΄f¦t­$»óèVmêι*‡“„ï‚?‰¦”21rØx=Öž‹x #:(@ulREØ8,þþÂÉ«U¹Š?(˜srÙñ`P›Á #¥oz›¡Üæ]åÍk*!‡¼êíß²”Ã¥`#kYÇ<nú©µ}áAðGxä5­ÃÑTÛÞ%Þ-öt“_¨-·ôEõâmÚ\vá"†l*¬•—ŒHJÓ Ú²ŽoݹøÞ+5×2|‹v‚‰ÊKÌ Ôc žQïÁ¤Ø^[ÏMÓŽ)ºü­Ýð¿_)}ÿ ôýªûÎl3åƒðvè³µÒ4¨Q=SØwoÒhò ªp·æš›ªðXåZóPÞ›;”ð½÷~þ½¿ÞÜûWó{ÿêÕϱ÷7Uók-›p©°¶Ý>'„SçÓIÙ Ž„ÕAhÙthβü‚J˜à:'ýv î˜ ð8‰”¼SâëÖJ« ¬|´ébG1ÚL‡ñKaÛåâÍÌÛóK#Ï»SöÊsÃãŒÝ0ìûüxµ¬](9œAl|©›P³– Ñ kÓ@¤§.'"%8äÙdeÀ·íœÀ©:³žF ;°gJ¸Ò&\³ÎóÝÝÕåï¼xþbnÁž?_ ÙÑîT'ÍhxÞi™wÈ™­¥Þt4ñ)gàª8$KçuU6-‚3ÅÐâÔAY”o½Íûâ1¯Nô(P¥½C|û°äþUêˆ{¯™ *NªÒ7>Íálõ°*KA—P `ÞæwzbÐeÁï0ÙWï `2"ÓÝ´g¸œ³P„þµ”O£t)‚¶”b¥}.Öe¨ý…—¯tj/lÜ­6Fæ‹È_ΓŒ²#§€$l¾P|m†ZR’æÉl™öų솗ªm†8™<Þœó3®âŒ_tfvyµr‚ivþGð‘tˆ>‰Ô±`Ì`:’µ™'›")ƒj+«lÄ¿ÔYƒ¾8ÀD®É^+¤@oüɲHÓÔ“8‘Êçzø`À”õ¯tƒmj…Qc&WS|tÚñóåÄk€«o‡êêª.ED¹¬ò+7kËhZº„^½ª$&ÈÕ3¨*®§7V£#éÏ»vMλÕLôG–ÀŸj”›¡•¡3áóå4F£*dNmÚ¢V¨Œî]»}ÚðæV7ÐK_Ú3Úbüz~Ò‘øe%éH290—?mÈ?"J!« ³úÀ ]”98w¬ü…r„©§0÷%çêi(û 9ŽSÉyHNVF\Ù‹É‚`&üÀê¡)w*ñƒü«Q¹•r3‹2acp0B·~³b2ÃÛDAƒ«"ì(•±ªvN‘éóGãëyŠ%¾ýÛÆ×S()òü·—”oèü y,!¹…íÁÝ|ä=< òžÐ²ùÁÒwÑóü^‹¹–¿x¦×yðpãÁNðKO6W=^‹àÉcjœñ_€ze‡åàÉÖý­àî÷+ÝgX¨ÅðK 5@-o=/_ËD¼ÙýÑÕ¸{Á!¤„8û ݉ו‚’‘µ\gSŠ)òBÿ-&`.¬Cs g[õçàF†XYÇd¤Ü¤‰óY”SbèöŒÂ ~æ€Ùš™P6ŠOh2Ì»®Š“Š„K…ü*N PØ K(®Xj>„Ðb]Á“§`fŠù8 ÓF«;ЇºŽ¼P>«%Ár7Ä)@4îà Ô½Øå´h„:#+š µ¹ªò&¼Å}[BÚ¢jŠÌ˧½Óálb¬#¿Ä“DNŸ_Œ#Àbz í¬lñ´G!¦8žÇÊ;TƒiæÐȯFqxë¤Ê–Ópj'z0½1€TÌt ü’ƒM† ¶›ûSb]‘À“!çS2§ÈÑOŸì`ùráÒ &Y_&¶î<ª0œ®Âºp>b@ ûç¡Rtü«Ñú³L#i„ߌš¯˜>º•öBoQÍb™B~¼<)â>zéŒÌ æíWÿÍR+=lF¨Ó,@›0 ×Þ-÷Ó8JF¦¦;õUµ¾Ýð;A>>o=oèCÀÍ+ñ¼õtšÁVXÞ.¸ÉàéÖ“_‚í{[Û›O?žÎ«àÉÎò=Îî·|?S«"YÜn}y¼< >»‘ÚpsºÖ[_üñ´åÌÈçùŠa,IzÂÒ§†°oÏŠý嬆¿ohk#dˆv#øh/)Ê/S|‰Ý âÏÀ.îW>/ê€ixáT ÆÀùñ÷jj1«w3·ùž„ Tº`}µ—l~Lx³Üÿæ‹Q»ß[ßvËWÚâLæM».¸—MNÑÓ:h:Á÷7Ö·êIé›]ëíÚï›?ËãñòýûÁgŸÝxôèò¯š?ßlÙw´eÚz›w6>ÝØ²;mãWžÂè U”¶u5[bYà¶k€J]h2w¢R1wJv`ŽSC(þy·È'/¸Å½xdd#Ž$S‹ WÎú’ˆZÆK¶YÕxá»·R;x(ßÀƒ¸RÞ?Æs«{“v­y¹$è¨TÉJÌ Ï¨)Ž•RHdg߇ÊFåTÊݬŒÆm?³g¹…­éãYÒ¶\B’‘>juÌóf©ú¶UOƒ$¦¥]XµÄHM/æ T«~¾¯ŽŠ\ªòVªœ¼8\¾ºÊdzã/µ«Õ£d]%PW›µu.¸QÏQelaØ\ƒF'j¬³feV_­Vèퟆ’ku%Ï0ÚV«Y`Ö/IÍ®.óA§ŒR­‹~Ž ‘ÕA P/Ú±³N§úÅPC©åë4hÓ$·9W}”z†ÙaËú(Ûlí¤œ¥Ö)ƒöäñ2"?Ì7¦ñ1 sm–6LðvYÏðÞ$ã=P—¢s㥤èdãr â ‰èå/åÕtŠ%˜ó›¢ 댋j!ÅGš‹tyÁ®žÕt:9IGâ¢@–j"íÁ(áEàèx+»ÜOòI–#‚ * #-ÀÁzÓ†Vß¶MQ¬l¹‚3$(zibh´p{3†IÜö]›°DT­0ÆBQ$àä‚~s)T±ö ƒ_ÀN1zþ5HØë=ÿàC¸È§þ-Q0´‡ùý ]$冔§Œ2+;+6ä!õãá)Áð÷Ò–¶[&uhü€B¬’iÏ”§‚8êô&û¦¾,F§&tVˆ\™_Î+Äf@S¥LŒ…Pš{ðÛisºÁ‡«(âO«õVˆ„ÍÖîEç<‚§\ˆìĦC ¨|p§âÊÙ"ˬgÏÞŒÊ/Ý@Þë9ÅŒwÌ6Áëú Š×•ßh©©Žžš³´\³mt¡Îóªõ\÷Çí…{³¼ÈÆÁI6’Kì´ä•PÚ;öpË­.ÑÒH¢:— ½À!^'Ã.Â1‹Ò¶€u³¤¸”ÍÕÄEaÅŽÁãh„ØÑ’Ѝ=‘ÚÝ+ô;ŠYâåWËA9g¶ðE|­ÄâF‹5˜!íJz5CSÐ*í5ì3¾jÃD¼úo*ÄG—ˆ&b~õ8 yšX Ô}§uªv†ä°ÎÍ+]}ÉSG0ßÉx®‡ò®Ô´ïúW{™ÇñQ°Í>©q45ꩌ#¯»À~JÀóî\à—À¦=4§×(u¸Ð"ï2 ;¯››œ ½hó°b HÙ<7H¼C p`€ 9ek<º]°~ 1z~׷×n/|‘% Ô»ÛǺkG{'©`ÿ*W´V@z7w’-vY’ä ¥›EðAIÆIÑW² Šú„Sâàáæw7ÌJ ¬—Ž ËÁÉ(‹úv{0·K"º¸¥ô53óFW§mo6¨ÅðÒ¥Kù¥K¡ï[Âû½=XŸ–º[UïêÂv仜»{K¤§Õd/̃zm¶ÐBý–õö»Ì7ãzH›Û$YŸ5©ð#Â@úÏ~çΓ­àü ¤õÜ…‡ð&ce ÷’´j\~¸.,2rºÿH~8eêˆñªmáÊV/úݹSß®_ú[»‹dê-q,úF£4¼Æs–Êõb·â´¥Ö6ÿ!š±A™£Q|jXr1Rt®¤¥%¢$ØLYì£ÞD]àðˆPM ‰Ôã¿d¥\oÊö¯¦×‘DeO j’L$xKY,xoÍ“êD¶h&y`z„æ[ ;Q݇Éþ~L. ÖѰ/½&ëÝlëÉh³”¥4;}Ý †ìÜk¨€‚^&O«EtãOžßv»ì6/Å19ð³3;ø‚â´k¿ÌòÙSí·[œÇÏÄ<œò9 Õ ®­¢nÄ– ;FqŸ¤)Šgô¤ÇÙQLêN‰§R‚:äÌÉú‘…s`·C’|àK»40#šbb n_}Ïá6€ÛÚÌs›¥ „ƒl”O"r° ¯„VàÒY.ú+›LqÜ…jvùr q|ð¶Lš+`YÞ‹›s*°ä¾PøGJŽ$õ9¢š[! Q¡÷²ü:ïM1°ë÷è7ïØ˜f'ÉHù×›©Ö÷,ˆ_¨ó6²"ÏÝ*°ï<¡]CªUGä>š[ÚÅt†NèýY±ÿ‘Mn ãèk@è(£uÑ;®cÃ[{Ó`åέ|lÈùXèù55q¦Ð ?ï4÷¤*ðʺõ îP*vKÜ-ïc Úh”0Íbð¢œ×è6V³zâ›ÓX¨‰ŽÇ””eAo.gßNh43TeBëbÓ%ÚñÝöü c»¶Úi¸Q£÷|{º«úÔ\—/)<ðôSCk«Ce@òÐF«fù»0¡â‡ŽOÄ‹R|êÃ/Ìðs>ü†v›4e#H gNxìmÛ]ï.gÉÂåúþtÕÖD0Q@ÿ,•;8xçf°iÛöåé[ìÂßüÓ„7‘Lõ%R¾ÆîºPóÚzð0¦á™ã½bº ¬ò”ß@C(Œè'Q×váMoë(é‡ÓµùöõMðÄTZA¶i'èëæªìT uÓ—f>›lœº/fšìËs÷sR|H^wZT@3‰¹ü„^Äç™I-ª3Ë­M»!ó)Ÿt ñ›-o°6¡ÙK!]IÅí[«±X8i± Ü*Þ°JAûùÜÈŠàBÂíU«}ݹ¼îÊíkÝWl€µÑ|  –¼ÈP„ðÆ Æì×7¹|¿a ¾ñðk§ùÈ– ހ̧¿´]vHà¼À|~ïcoà >_¸´höeJéu!œh´§ºØMPéJ„§>´ßöåp–›ŒîbŠ›³(›žj4îÿ}Ê+yÌ’‘ˆiV"íôtœMYShñ>Û‹)•UïBM8y•0x/ÒŠW]!¸Aqkb) GOf–ve&p†zኤüÅúþÕZ/4Ò„3ŒÖ–q—Aj+Q_†¡&<ë©cf² ÄžpÜŠô4HpJ) í¬Ñ”øñSâd‹ Ęwóvå9â”N‚Æ#\iF1cé–æMˆömœO6ª”Êô(7@™ŒŸµÐü»F“îî×°@F}(C³Ñ¥Ú5+iXW±rjâejÛjÉÀ¶Î™¤Œn|#Y©€‚ŸÙ´»¡T”A¹J¦¯2ö‚bå8%mØ_i€»‡ó2ÙP:y¨O$ÈGÍéô‚õAAÀ²¦pWD6ë¦ÅÀXf…¢3ê¥Ì险ýÁÎM²\7CsÄm•¢ÄÕHº$¹»š-hî„(9€¤B¥Ï $0\^»]p }¥ÐZ…’ŸµÕPûBU߬uÕç.ÏWUI©h}ï‹ç¿q™ËqéÂ|+Ey\¡{·lV^ÂŽza†-ÞcPÀXi¯½}bf· ÞÖrZçlKd7<Óüá-ù%k ÑòVtýVòî¸Éᡸˆlê­0žy½½Ç¶’Ÿo…Îë-9®½io»fG"ˆm.Ë!œ`ÄGסm®ïp ÄÁç sÓÖÙ{6 †3Bâ`©aœY |J貆-K 9Ý•îý<åËðŸX7êØ½íí 6ëÑÏúƒ›pœFÖ‚0¡¦ú®gL7tra-©9R¤ër}>q©÷4ŠçnPt“WpôÄÎbëãÖ-Ш1I:ó| ðÞc0š™éL)g#F¿$)G'yЇí _|s•?˜P8|Æz ¬ºTú†‚>¿q[üÖ(~64ÍŸÚîñœø‰šª=‘  LózÆü{û³¾‹A.…zlÈQ†È£F«â{N¿sS+ ¿w£‰1ØÜ~\ÿà;Xî°(&7VV&q61Ìîäƒ^6=X™šZ’a´‚o¯¸k¶Ãb<ª'äZ¢ÓŽãÊc¥E˜âŠ3_­ïGÓ»<´¢=ïÑÞÑaôeÛ{ë'¿ý?þæOÿòOÿÊO~;øÉïüô¯ÿäŸÿô¯þOç'¿í^½WBh^´O÷ý6§ÉQdX”{~ä=?Ò¯Ž½GãC#¼ Gö×þþŸýÕÿêÏþê?ù³¿ö_¹ÒS¯ô4ÚÃÂ+æ$Œ÷‹å"[&|q4=ЧAë?üÚ?i™) Zú›ÿþ?ûÓ?üÓßùÓôïÿÚŸþ7æ‰gïoí<´µç^í9 ç±küØŸ=³§Þ£SÓ~ä~é=ü2žîEÉQšÀ0£/ÿ‡¿c¾ŸÔœìyKh(ëð(qmíyKq’<ÍrYÆÿâ'ÿì'ÿâ'¿ýÓ_ûé_ùé_þÉ™Oÿ;÷â÷âltŠ¿÷Ó¿fÞû=|Þû÷Ö¡÷V ä&þCs*ÝÀ÷Æþ8Æ{0-¦9ó1J£TÓÁ^ê*=ˆFªL?ÝIöbM~{UÜ5›"S½E½›å)Ù|44zäxÓ~Ïh #*‰ü÷]Aoîó0v ý§Ñ83ª{ì å^fôZ½öo,Fåpô7ðFrïKÓ,ôîßüøßþs¸yÌtÁ'£a°=ŠŽ³Ôì[äØïäìØP™{ê‘óç†#cK÷NÇÓ(>°Å†Þ„Ý7MåîüºRÞl}OÇ4«÷ãY‘\£C¯K¢Ñ09NÔÌ ½mt÷pVÀ’§±×ÊÆI Müßþ÷ÿ÷¿þ?8LAÖ1¥þøoýñ¿0ÿûçü/ÿøÿøþø¿så=šäÀ=õr#é=-ÜBÇÞrmOìô˜¢Ñ'¹’…_“!_¦Ñ ÃgÕg%¾ðÃsc–nçÖß[—§`:ÁêÎf“ÿþ/ÿéo&ù{ÿÏ¿ÑÀ"÷=Nÿ`6ŠpHæÃþl4t´ºï1†I*ƒßžec7¢ý/üb_¨GÞô>ˆâi¦™ñ¾·O•”vó?þÍ(q‡Ïþ©_2fù`zªÈôÀ›´Í)÷÷Ó(NF®Ýƒ¡·ªƒ¬ÈSf¤öÖOf† ¸Eó9>pràÑ×§3ÃEÌü§_D ºÇ¥í’¾´½¡|fÔxG‡Þ>ù,Þ›Æ' ‘Æ¿û‡ÿî¿øwÿèßý÷HãÐ[òÏ )Œù«_ÿï~ý_õëÿè«ßø›_ýúýÕoüšëKæ¿1M‚GY1sÏK¼03㧉ülzšwz“õÙ,ugÛ£èàTÕ‡þQ=DzÙþä×þäüÉ?û“ßøŸíO~ãOþ/î…/ý›ÆŠ›'>Õ€ì.ÛÝ„'C¿Ä9‚¢Ã(û£{)®¯ÖÑaâæ›{ªOGþ˳I9:O<¶´90ò¤Oîüøoæ£Ø°nÕ3mšc{ÎU£³R£GERÌ ûü o¢~)2ì¶³©ê?þíßøï¿ûýãÿ“+{ì—=¦²òøÈ«êÓØÕúœ8òfæ»YªvÜ‘G£ßMŽf§ŽÜŽIÏÑëØë³˜¢ƒ(?uýÇÓü0ôF'~‰L­ôøÈ6ˆ‡V*ùÉß3ÿGFÓøýŸü«ŸüË’¾0•{ujþ#íþþo}õû¿ûÕïÿÓ¯~ÿ_}õû¿÷ÕïÿoÜ[Þ ?‚M;Ò“8Îüç£aä ‡ãii°‘Y÷4¯ôI±ßG†*60.J… fTðQÕéQêÝÙÔÓS2G³©k õN„ÇÙ´8 ã½x¤Þ÷€ÇñDkC©·ðÍÂ8jL½ù¿?+H.zÍb¨Ú Fé^©'10Òànv4þñoŒHG¢ö•´þ•ǧ©QdPš–öoe¶³YÝhýÙ:޾p<;õ&úxgÇ'n¼ÙÀSvƒD«†™ÇgŸL³±«8›úÏ’SU«G1OÀT§ÉmâKسô‹hÏ­ÏÄÛWOõÒM¼Õyš˜šOZœ™ä~ ù¡Q,àÿÕÿãïþé?þ÷µAF›Ë“ÂïÁ´˜¹"»}F@kùýÇÿØ‘‹y×W´õ»w§Ñ—IÓ›?ôN_žÅU HSo‰¶#£¾/oeFK8 ™úça2xiŸzÜßeVe>ÿø¦ÿ毸¢^_¶f¹5ü}0™3ûɺò'~ÃF&˜žx‡CîÑÂ6è¾ÓÄ >ùÀlŽÌT“Rî+FlVŒ++¬"ž¦Áv¤Ôü Ô¾’wrï ØŽ§{Ù²•£m¡¤ÔƒƒÃÈ;'rï,ØeÇnuø§ÿæoêÃ6•ËZùš¾üÛPzaìwœé®y˾}˜é3Ÿ±Œõ>ËèIù£=KÛ‡?L&®Ü´ävªà$1ËÔÄÙÙµ›Âý(6w ja¼ í”[†fôüÀœHYÊqsE…ùû•ù)¸Ý6ic·„VL‡h\Ç•Ýù|]çĆj»©¨.÷yjè/8ñ«¾`P­ZÆØìV2› ë÷Ö^(ß=Åu Ç ½ªMS¯Ô_ÉèŧyùÝ›Íü©z&¨©á­Ý­{>_Âù9oeÏ1›Â²´ký X \¬gÊqçºÀ›CD;Ä­½Ó*ã>7ÇÖÕyÌûM¸¶W™0ðÅ9÷Ï’{·u|Q0¤E>/÷bÎé-<µïš\aÖÁL— N¿³ð¶>Ë"-˜–6Ù;–„Ë,ÙV"Ú*r±Tcž@dIƒ€¼€T[ï°7wîÄZ'C2gfnì]ªØ!Vçø uŸƒ|Å»!§µñ ?q‚K=W¬ÀµOyÔ¶-›êε®³ÂºÊ,]cÔ.éÜt$lj¤–* \¡k ýT5Þu劤IÎC.gNžMìe8­Kª§B³N…Ùûy޾þRÅvq 4ýF ¸Wø ŒKHÎÓ4ÌŠë¸þ­µµÕ¯|ðáê•k«ßZ]»öáÚ•o«ï°f†Mƒà['''Ë 5•;ëùŸÓ?·>žN.¨øæðF ‹ß=Özõ®ô®WVW?ZY[]Y½¬­ÝX½zcõ#ÃÌÃL6^N‚%—Œ$Ëœâÿ3V÷F`¾ì$#¯,c `æ}"¾m³QÂ8ɦGå…wTþSÉ´óJ]L;UA»Fw*Å Öð`¾>8• X’D.âišXÑd2Í&ÓšÁÒ6ÿ¹Í@<¥Ü†q–:†—1 X-H^‡YvÔ‡’íŽňéâ±]•«ëëé)?†Ê@à3ß’ýS Šƒ©–&•­3Às ö¢ÝéñaŠ«Â§>‡æM¯àŸ\õ¡Ë°›œÿlÎR¼Ö·o¸{¯NÏo Ú“€C”8ˆ¼YuDYL€ šê$³RL4 ‡Y‚$GÕ,x•LÜÐ<óxð}ó"ê¤bÀ@´šÀƒV’ò¡\«ò×1T¤ Wt ^WXÐ@KÉõ*°)?fVLo qdÙQYxDv4PvÄlZ’YäÂ÷h…_MÝ‚£uÈLëÐ1‹$ÉfùÈÞ&´Ñš :1—“«fùšìX¬ÞQL˜Öuß(Û'ÑiÎ{ »<㇣)ÐðŽñ®v*B[”âlá‹?tnx éÔn•Í{ÁgŠwDŠÌt.çšp‘—z‰Ã`IË €r'ð’Ñ›`øhø+VÁPÏÌà8}†ƒÍB6F4Ê3³Þo@ŽÉå¹>ŠÑÚó>Å‚› 'ÇÐĪÙ9s˜¶Yšž(øyã(kÖOj‘‘CâedXj|C}w½oås.Ò7İÆöR4@¹—dî÷ßä&ÑêÆ_TÁ@:¼òC²oð—›®œ9+¥a^¼úÚ#»ÙV–D@D*~kÊcCqÁæLú£K„\?ˆò0¶ê»Ü“å;Ä›X“[WFÔ±M^óœÖL%¶aÝ`ÂàsÅUä¦ËÃuår¥ô\Л’ØgE,bVBŸ8Ñ)B )½Âo@(²ife»‘þ{íµNÇ!:K-|ÀÀ¥=Cûy2^ªgq;ÇûMÄ’÷9™ %oÏØÇÇ0Uäº[îW>ºr¥Gø¼aQÞÊÂû„ôjZûsWpjÊ?âVùáùO»†gø-hhâNÙkË!e[¯-—2%—LäK- ëjˆ‡”.š,%Y/ÏÞ'üWx|PƒS˜¢-£)œ.ïdð ÌÖËhS=/Ì:ÈÌŠ¡¤‡0è¤æ»„ÅéPêfYV¨‚î,G†ÓÂú‚ü;`§‹é|¥z\½ÛÑûŒ4·Ûxk¡ehp(m¸½/´Îç&°ó†±!Ø!Ê^Ä­Ø„ñ5)µ‡d+#Scl2ð(}0¦‡èûæoèä^Lýö¹²iRq*²‚ÀLõ‚ö6×:Ž£ïWÉM…°So†±bªÐœ/ñ´1#h…wyd„3«âäô}˜Å9$X:À¨ßÂH²ê¼²îȬ,éu| ¡>µ™wt:> ¿PLÜž¡îN°K”§ÜåÔtÓ£ Êq9Õ lÙœ]f‰ùGSÒ ¼¢pMïÎÒ!H”>Ð_Nùz#G1’h„|.ˆG¢ÇÌ©w&C¹#>)Œi ³@¥ŠL—2óB?cåg¹y2¿!6 ù†?üž‡úåf˜Ò,Ëu}ãG" Ð-_ØÑù-½à¥¹€×b2sÂ:6­ l«¼4+6m,ðÕÝ!·®õV¥qº¦d]¶èg;–?ºÉ'ÇíýQvo…æ“Û§q^©lÀFF\ÞHH¹°æî&…ý•åG†bâi©Ò :/ðU¡‡¹HËe½ wî#Ÿ¸Œ##/À.E¥+ŸD¬Èyjü,ÐÓ—Ÿæ½2׬”²¿Ùµc`8Ñ̰Ðiò% !¢ñš_’”óÉSÛvžRn’iXy¼Ü°qCüf“˜Ow³Ô 0„ÃÞn½wC8$HA°?ɉQú™U)kÇUzb»D¿ë‰–{T\=óçè–®Çɰ\Ø{³Jÿ¼¤mNç½D=fuÉH[2¬ñmïôßdøB&¢ìTDî)ç5ôsÊú›ÛKP0ÁZ#Xö´*(â0Ц§š’[OaÞ}6S)Üü¶faÈYÕE§ r3w¯èFìx³$L‹ M4OæÀßJü±`=žÎVg€^  V2Ë—¸ìæ7Ka9¥ŒØzÝ`™zjU—$÷µÒ3`ÅÜ:TG3©ò3S†æòK¯òV¥”ôûIÉXìÆM÷hæ7» ¶A óiÉŸ ¢Š.!äàF‚•Êœ·ƒÃµäÙfב’Ūìít³àR‘u4<%px2JSø“QrÃKp(zÌ/š+kîÍqÿ,W:=uÁSÈÅìì[Öf‡Æ Æ“•yyŒÖ6Ø =Ì‹HŸMéɸm®­ÖÂßeÛJâÀtÔ|’²9Š´¼Gh)S9gøT¸‡fOßn vÛᤗÆÅ ‰Ä+qº"{³‡£7Ï[¨f<ýì©3p8®¢ q„[+ѲYúö(¡;BJ)$ë´|F\4s—Í˪ÙTåÎGž\ŽzœÍ”MVMàHQ$Kç¬Ë-}Õ*ûëb:cu7‰K²tPùÁg¬l7-}-.ƒlrvmu!™Ž¢<‡¬ì}Cýqö¤]QsYµx7znð®UÝ QÛ­yr–œ¥ó68Ú ³Ë禭w›ÏÑÒrÚÛvÎÅ)‚CQ¬(=E'Š$u3 ¢Ys³›»b©§iHÞ••!S5ë’Ð)`ȶ!Y݇uÔžrSЬν­‡p› ýe≹3fnØ® ±ï¦*8 &ƒN®'à€¯¸ûlMù8šJÀdÜÆJH'¡¾[a\öJžgƒ„Ð iוt`}1XÕ¦I0ËQ >IWOQ.íþ ³‰F Ü‚ÄSÞdU…”p’äåÔrÍ–ÅòE€WfúÌñÂ7Lƒ#å¿UÒÇŤ?Jö¦¥·1§úH³¤sVy+í°3@?~ö yÁYïÞÔ~z„´ìS}*WŽ-“q\Ö¥*N³5â*Øò Û´&}¬ª”|½°d/4ì±ÀÃ>=íÇ Å‚¶ª‘Oy¸þáu{ ø9ƪÛö%Z'¼CÃéü Ûw^¯À^ÕÁjÃ`i­¼³Ö'<À`0äâìrú¤ºá²ÀZT!ÿæ]&Xº!\ ‡Ü¦˜¶ËýÂÞ”¶õª[™ß›Z5†2Z/&Ë+œ5†'¶óè¡ìGd3ŽßvajÀ")®$*@ßÞӚnj`Œø‰'éËKp:£c Æèiÿ«½Sué…Ë(eA°ÛŒ²`aÅp¤–6š˜­Ï;Q!`W1h‘û-èKU¿fKÊ»;ÖüdÚæ;6ÚrîF†Ö3‚‰w1ÉNÿ.¢Ò½oEw‚[·áVbþ3k‘¥æÃü75MàÃ(ýpf$8óe62eð×Þ§aß­áÐ|9\ƒ¿®À_À_Wá¯kð×uøkz§t0™¸£Ù¯{쎮TCïtæÓ¦㨜ћf_ÎÌfJ "ÜE¸`YÒ˜tíðV6†{¸aWr¨B¹TXƒM°¨»U¾¢Tx@õǶ>Û<ÝÒðt®c8óÌiÛAùäHœÎÞ>ÁZä.ƒs€øÝ×ÿÝEÔEÀ³bä\ üE„Ÿöð¯)ü=Á–XàÛ ­‰þ=Â7‡øyXàß±:<\ÿ¯àßàßWñïkø÷uü›mtbr~g1¦¼CþX³DGF]ENXšK¾yÓ¿‚Ù—NOŒÉÊ1ðÙŸ‰Òš€É·2ÁåžÑ{`Â*¶F…YasqbÈ“x4Zf*A‡^6U ç\mL EÝÖôI†õlÚæ_æyù¸KQ9_PÒȋӟX¶ÿl¸xkåcC.¯’N»ýñàrg÷w^¼ßùøÎE\Ç87èU–ÞæTCäòj¯¾ª÷½ª.°FúwØ. MІÄÆ$éÍ­aoYaŽù˜3m† ª–Í©´ï FëTÃ[°ƒ}4„´S¡wH¥bÁîÚ‹ÐõãÙÖC9ž‡¶§»Q}QÒ™MGy›nÁ9³"ºãÀ±A^ÿ¤}+‚ºü1u½½ûƒ–™®ÎÚÇwڽˣ1·óI6O}_"ˆÚR·+ý)¯&üV#º»þS1«ŸS–ƒ{ œºR²E@ƈUÖàü¿ môÒ|Òïß42Lp ŸÀÇË—•Éë2Ü {XÓeHÓ _€ÝëØ]J^=פ—ŠÑ‘Ýk²¢]xJñ‹—nµi]:wùwƒåµnðtkãÓþöÓ‡›;ýû7õï­?Ýy¶µ!Ò@ÀHc®Nr>·6;¼’ W[>¸Á3&Æ$O¨ ¦ šÑˆi“À0Š.CÀŸLîR€Œ¤…U-¥30—äbQIåÄè†t*¼žWГ×À#m(aÖÒ°ETï¢œÈ hø&Itÿ"Y嘻PM‚åôR±{± P»yÂ-S6á$\@=(÷ðe‚}&ǰRÌ/\І5ZY°¥y&´%lDê³l4ÌÉ]:AÎB$—°yŸù6 ±gïß8^‚Ä`Q0þ9ƒûuž0ió:N;.Ÿ;¬ˆ#qΈ ƒÓÿŒ:Œz‘«ŸŠ5¯\±wh6;¢}݃ãÀ¼Y2cöçNÙœwNµœ¥ùa²€(0¥È·Ubsç¡éÕ”-RÓÚÙõ¬x]âßj+×U{õÚ6„¨ræî"ókŸ,;íÔ눞´_6‚ Ræ `„:à$F1ÛÒÁ©r—Ñ]UR‘î1Y•eNÓ>;j'/ÑP9ëNò~B“¯ÖàÐ!µmЬ¶wÂ3ç×g7jMò~:ÇÓdÀUCÞ+¬QDø—Ë—B“Æ…F >»Åá°±EtÍ9»#,6ÖÐ3©âê¼*¨`¥ae5~.‡Þ}ð‡2¸LŒ2ä§X ߯¢Ðƒ?Þ‘Œ€˜ ¦Øéy•8æ:5Ï/¯ÍuÍŒÀÅi_ "Â9p-¾¶@,?Ó52ô¬Ìྖ ¾°Û„e)hÌz¡®È±ÖðÆÊ 5ðÕÐwäðˆºn2¤•ÄSÿ ÷7ØÒ´ìij´ ß Ÿ/H±Úï e‚y„,`˜’9¬W°Ò'‰9Œ€âµ d^ë6±€O‚Np\:ÆÁ hÏqÇ·ßbÛZ±7â[\ga¦ñYo’E‚²û˜Ï]Ì=½Ÿ¼ô½Aø\sM"/öüAèÒØÝÊ/¯ ³¼3'ao… CˆÃÓá9±Å£½4!Ê­øa(¿kŒƒ²Ëk6vìâ†ÿ¶M>üŽaªV."Ð9Ãe'{><\¼T¡~u™ " ׎V_iÃaÊ/÷Ä&Ž §7Nc N­Ü4sòÂëo¡~áÿTðŸ”í]B@ÍǺvuõÃkßZ[[»zýÊ~ðáõo­®]¿zíÃoðŸ~|ü'µøuíº`@}geõÊÊÚõ`mõÆ•k7V¯F˜(Ê&Ò·ï}¶ñh½ÿìñæãíõ‡7î‡Ì!K%ôóU¸â”ç[¿ülskãÑÆãSèÁ“òûúù“ïòÛu?_ß2½ø4$[z] Œ¯ é~Àx°ùp£¿ñ+›Û;æ‰ý£«À[ë÷×ï>ܰ…®”K|¾µ¹ã•¸Z.±ñ+÷žé2•K<~²ã÷eíz]¯3TzE¼Þ\¯t…RÝY»‘³{ÌÑ(ù’®~g“!œr †¹šA4÷ú2¦c˜=þÍSWÝ> Š>Uœ·é̳÷S\À—míý|`¤ö¨Ïê5_ã‰ÉwÈxŸÅá|è-ç½ÐQ²oéQpHÎJ¬‚ˆäæ%ÔÛ ’r¢ŽÄh\nùAÜçáðÇE;ª>6›ûR \>y6» ýàÇFçD7³ŒbªJAÂx^ëVÅŸ¿ÜN±KC~R©'gXmNHÔ·¿S9™-v1~‰ÿåW½ž¢ ȳ®ë¤ÞôÙuvUi:²üNÈsˆ„SSO ?ÙÝ ¥yž ŠGàUƒœDùŠÂA/A—]}4ez'Gb»ðÛ‰ûøÙ£­Í{ØM«¡P‰›5D«lHB«O¶oCµ~9.,ìØÜ0æ&Ú‡;v»³‘ÄiÐÏwz‚ªÖÁ˜`'¡Ï rìÂù¢=Ûиü/àÆêØÎž˜æMÒȺn„g3èòð|‚Ø,ûP»ªÖZ—tA纔‡àKÏgD)ÿà -’yÃöt^¡„¸±ð›ß›†xVšâÕ oèj©/ôFyF§ŸNK0´ÛB“ÙÛo®ÕÑ€H-Boùbôæ…nMŸ=½¿¾³áVn{c§¼´·ƒKC^QºI’•:-ÏõŒÍ!šKì1»K®@š+D=ßÏ>ìÕîM쇔ä 'WEŸ?ö‡Q¬ê§§Î¾ƒàå¾ i³OÝàÉîb[?åUp;˜5Ø%6×i4)aΛRÿÙô4Ï@ïAþ¹­ ¼H7é>w˜ËâŽÞ åßັA*vxJXå²Â8cŽF·¦7´é€˜ËIèbÅë@þK Îq³8KŸTxžà”4\ÓÁki7&Àþ³}ª‰<7 •‘Ñ0­O=÷²‘æ{™†eúí ŠèSíPEYºŸ º¤º‘ wP¼êÈ*ìCm¦²¶`쇢œ™÷ÂFj„Ïf®Í:÷·7¶¾·±µ~¶³ótê!ø|æ`…ÅcPrB;Ì0i“{‹þí?^´p~¦f@V¿møs¹ @ïÃíà£Uhk¿¾0õ%Å¡2)ûƶVžÜ{E¢¬ìÛ ¶mlïôÍBÉÛÃdZÏZÁ™’—Mõ^|F‹fŠC*ZšHï}"P–QôaþsåHm$dvzÅå¦|›ŒpY©Š%à%³ø´e*ҩʤM<#óRݦ²z^ÅÄ"/÷ñå¶àGÙaøb‚•ªÙ™}|šÿ½Ðñº Oà'Ò¢ N-`ë˜b EVzó R£èdY¥Èâ3ßáØã‹\ ¸%¢Ð„ZWLοí„ìb/¤²:\±3ûš/1®7³€iíÍö÷ã))äª Öêô ÃNcœ$5oAmKR-íA.¤eC–”JmÂZ”ù¤`ùBјmIX töD,'@`›ÆÐ…¸/o·]gõ5UÅ¢nÑ‹Tq³æà3ž¯ð3ù·§GÅNÜüK_ ¢3Å[§¶§íÃ޲T‡¥ê.(,#)Â`¸œõ2…¥@¯‚HÃe²›Y-–{>^ @J;_JVNµv=s;4D1YYûÓ‡OîšaìJ }2%vCì±^nŠ´F.iÏÜ%¦7ç<´D¡o%'.èKûpƒ°NÀíʘ ? µ€²]Ä‚vo󨯧Åö‹ûq¶Íh¹ƒ/‚÷”ã3—b?ß{ÏjÜ´WV»Á5ˆE B´N†~"m "QÙ?ÂN€ÕŽyX ’9fbŠRç:Š–ƒr7>D;c™îˆNž³Bž·Ÿçïï>[/Ú»ëË¿Ú_~q¹ƒ_ÍÏÝvïý;Ï;7ñª‘,²¶óò³ Jݵä7Pv›t”åöË®~í…çÐÄ“×óONWþŠi¦„­ž­ÍÒaÐk…×êy:qÚÈúÖ,yÅ+é¼+=Ç£Ò°'Õ—^×­¶)mŵ+¾F+¾Ô¼ÖÏ—Ú»?^¼ß ÞíRb\pR–G.Sˆëä0¥¨EÒ6K¾q0MÂÿBà›´‚è"È®PÂwACf–z.hhÚk"Ÿ›æAû¢ÜIé»PC'õûö1Ý*j•óRà;¡«Ò«M/jïº}phŽ™ý ‡…KY =)Ë'à™66š.1ÜéW™î9ÁmÄ“EšÕˆgÞHZÏ—Qàzzg.f…–>h¼3Üœ2'bë‘# jPº€o]éDÍx-ä°}%Œ=Í)2.¹SmB@hFŠh”%&ñ§×œ¯MÞãðzÝõN4šGgvæä]u¯|„—{¨o$> +õ€zS½‘©§0 jU‚T …y iÌ%–Úèc‹\ô(S(N¬½-´Á~ÖM.Ú(eéwÝ…¯Ê¯KYù½k׌r­ËBúeLK¡5Wæ¡V A*Ô Â÷hY#kè¡H†&ž‹Ñœ?f놼kæ›ÈD[)—ÿ'BÃm³Ë¢ô´SoÍŠPK*ZXíÒQûb‰j‹ÕÎ@l““Ÿ5ix¨©ˆJ×XŠ@à¹Û3Pßd% Õ[á_òyf?ôøßVÅÇ:Á«WÁE­¿zõ+,¢Ð4³†7ÜZÊxÎLGPªEÔ ØvQeš-Óß;%S•tþÂÙÖ?!@”òkö Ó·ÕÛ¨%y0§­f ¡L- kÇiÜXÎgYÓ…ÿÐ!DzË=c¤x˜á<ƒä¶B8§øÎÑ_’¸9áÐk„ÂH éqö¯ß´áó½æíUÈ¡öJp@á7áü«ü–I×ò¤KfÜßΑÝ(Û/ÙíbË€Àlĵ+óå÷ÍI¶ï±·n¥‹å<Ä¥ª,1+nYj¬Ê11`—˜+ò?‰¦e‰(áí¾éÎЂ¢G]R8MÀ5¸·VhC‘Á©>ïørHA‹/t [¨R7wåóðž ê Ç™‹Á 7Öå»G¾Ò!÷C&vgáä‰>;¯£;ö~þl^+ HvîÜCRr¤s™iŒéúÀÅàëö:^±?J&d쓵Ãk…θaf!úÌ:}•ú¬cWî$N e`FN½VWlNLµYˆaËÁ•Ú®ÑÀ!20N†Q€Øj•-žSP ¸~úíú°÷ö§S_CS}SÞUå©gþS †ì7¼\^ó[ ê¸=·Ž›åhÅÄ $œäë6¸—ì%,¾4‘[¦Fš½¶Z”é ‘9JLÍF€øOû›KR’ÒrµþvÆÌ°nWÓ $ž8N†{(G©‹)æ‡3err™®G6lF`dQP$ãXò ¢03óa<&ÜUÕ‰ ÷­×òÜë‚jàmrÙ\æܵ+Š™Ô85û³ä{ÚyžËá€,§FѪúí 9žíýäC´Ûºå¶Jµö*XÀuèfY¡Zü:;7" xF+džAÙïÐÇ+•R>#ÊD¥Ÿ’¶Š+²ÙÕÉÂdû„k© ‡¬6S© Á:D1ŒÖ8ÆÊ_‹ö¥_K4UNójH.†Xr3:¬G‚ùª4ñHﶸhľd>!ú;9!˜íó^ݽp…ýi„Ô¶f’qõú4#-F8RKÝ«hØ*UÆ4Rú¹ŽTð´Îæç­`óñÎç!Ñ–éê²' Ü)fp’BÖIp˜å]´ ê^–’oRö™éß[ølc´}˜Êß—†ú¿dëç»fÙÔR‚‹'š;W»å©qð,'b µ¯ ÆJæšI†,«Â¥qzœL³”’ÉêÙâíû[Ïž®?ìß}òdg{gkýiÿ–¢Š$c¶gU†ƒx¸7•âÎvÏqRfIçŠmöq-ƒ†°M¸˜èß1*Ï1Åò8¿Íò¥³Ö’£y†{=7uÀ†ÕŽÔÌr‰Þ¹ÝÈ¡âÐ*lÏRÍÓ¸³9‚)œÅò›°cw­ M>qâÍØžŠ½^G#é0Œ"­Ûe!%žUR,ìð“dÄZò "7ÅÈzâ—Ðߣ`‘œl$ÑÐ1ܲA•êAâ˜^r"¡BE±AÎBƒRÅÂ=Úxü¬ÿhýWúO×·v¶­ùY×?å4”G’¤¨Ðâ Ù»qøÁ¥ÝhùËþ‹÷—¸™iQ¾Â:w—ŽÆà’B%(›¯it»443ûC˜Zv RA‘¹.ß DWƒÓb‘H¬ˆÒ"tƒ:…uÄè]ã?²ÿàûì,ÒG ‡Á©Y<ÌV`¸Ûæã —¼ºG€±²þø>xQøãí`5x²uc+¸û}CYóâýí{²@Š:8Ü‹ ÍÒ$†Gä½`»ˆ"ŠÏrH=çbϦ€Y )=±fN”ê ÑêXœä£1ÌÛ4^6³ Aí`•Ñ•ªhCºÄvÇ»K]‚®hHÖt*.}¬ˆêèÃKôªÂQSî ç§jdÂã&á•‚C$›>œ_Cg‚ïÁ%†ÍÜÓyÞã(?²ög´ ö’ƒiìä-¸ïÉfy€Á ï{w» ïÚœÉ \HLŸ±—æ0I)ý3L>[Ö ÁEzX¨*øƒ‡§¤3ø?•Üv=ðît)CÀ½W GGA7×Òªí䤴viZ\˜±øÓ¢¹‰…;jâç]…’±@y¨×^LxÂqEË5m¡FKƒ÷?.¥’a`ɳ¢Ö¹¨—ŒföÎ#¡ƒZ/ ZØ+O•RÉ5in/–ˆ¼À.ï‹{‘»„ºXñŸÄòd)¦Ï¥ õ+kˆÑã!Vnsj¦×å62ßœÁÓ"u/䈿JDuÑ;Ý ¤~*½æþT3.`—à¤b¿¶>Q„w§È”ÑPD¡®5`x7b}Ÿ-‹Ô¸¼~AÞ೑LÃj™ b`;2½Íå]-ë£óÜj ”¦šýo%0!=I²®5ódHPùÈ^B7`Ó/ z?yYe*5˜Ûý…»+4Wß]¸üý…ê®ÛõŽ_ƃÙ/V—õf¯vú‘&4/ªíñ/Yø¬²¶Ï¿ ”QcÕ½à®Eè_Ï|Š¢äÒ”[‰QÎ?´Dgº²G¾« ?Œ 0>TQ.hÄúûœR\ÂÄêü±á÷âN¸*Dz-JªdƒbqôŒËœÊYãòë^â_#„ƒCföª\ð³’ê$›uÔ;üÇŽ€íy?ÖD=ÿôÂ_¾\½zUz ^ã‘"u\¹re¡:ê7³Ô²¶¶ÖXKÉK&âom“´8ŽFíÖ*ÔÖêuÊ2±³8×Ý]*‰YÅÐ}a<ÁˆFpq®‘-mvŠcÁdPÓ P°Î@æî¢w Nb¸ßê>JÑÚ#Œ”–TidÔÙD6äI¼GYs»ðáe³©ê¹¸K>S0,McÜ Ãä )r/TG½ÕNzFM‚Þ®Q®3Ó""¥ŒF.³CÆÑNe`ï콘²ç`ˆ¡ œ6¼M·.9ã ÌÎ9µw- €c$¹xŠ€)4ÂÁ8.*•H6(0‡¥iê¡Ì–F…èhpêšFdH¢$#È"?ËÙòÕE­‹svƒUCždœ_ýpu‡ !ªØ6Áسû§™±Õk««JtmY)ŽJôR¯Zï`Zë¯ðõ;6?F2ú9óÝ“˜Ü!%Ï)¾ô,ÌË ™÷Ö»óÙ/„ús{š›ûðß/Sf3òÜ¢JêGèÝ š—Mf> £/’â¼íÅÁêÕU¸¸Ce«k†N§1?þ³B’ÌDûñÉÊ »ù1Gbžs@S’óEë\x&p P O\`ízû„Œ„v\¡èÈôƒ¦ ñ’+ÝÏî´jдê®ðƒWæ/j¯9êN¸•©±ÝÒI¸P»õ§b£îÓØvéü\¨í&5¦^‰©mú½ÛÁ_z£ùnRHêÕ‘æ¶ßdΛU‹&Å¢¹ýEç½$Ãà®3•´;” è$›Ú4ræèèìG—¯YJ¹Ts·9ÕQà¼ûüŒîÁPò /‰a _‚† iƒib„Lræx¼£\‚Ç´'6´O¨¿–g÷‘±¼dÖx©˜ÓqZÑ>¦Ž.쨑zÌ‘Á§=¥gHøño u™C†žäÔÍI:¡Dä¼½7¢CM i¸§°¦oÝ*f¿Ó§œoY‘µÕ-UkJøÛíða6@ž‰yP}Äßtéâ˜^iù^–ÓltÃÊËxRª‰Ç8ÅÀé¥0GvÐ0é/“¢í£FÓ!`üK@€™Ä7‚?~bº:1o³¼¬ýõ8Ae—â¶%>£&áþ“ƒ€¿jòeT0„߃Ãmf½eE>…K¼,J³›{)¨¦:Þчã ߨ>Ÿ¬*¯¡Ýµžâ}z¥â¨ì×ä¬Ã•|hq@ 0Ië!M!‘âF¼‚I¸èÀ¤g~gÀÝ}’ih²‘ÓÃ1¨ºX/nª¯ÀK~m‚ó舛'JY'0tÈkܵ~2†0l<ú“¬Žãñ2"½{]sC•©*Õa4~HÕLcø¹&å}ÃàÆìØ û®Ëô7=˜aw#íS>{É7oyB ÒÞǧÕüÅV.1O1½„Ì9@£æƒh‚ySG§Ôa~¢àÁ±þ]xaÀ=F±¹ý<Ç•ƒAÕ`‘î®Õkê’mŠ¯ËšZÁßâv«=0ô†ÀasWžFy^ʬ@í_äöKæ-@柶۾»Â.of‚³hx†‰Ì(ïozß×/“¢ª‹7.û9#:pNêõž®R¬Åâ!¾ 8gèÄ,M~8‹Ûç£h ƒ¨´òb’Љ²µßËŒ0(4ÁàŠ@©˜À1Bizl ›²} /üâ¤'Å÷äáòáÌîtà>ŽNÛ•#¸P÷"ô¯N«Ý“°,ý¬[v4šÛ‚v,…8÷+¯wôÁ‡ÉÁ!8vä1\¿§d.òº‹mÂHpåúREû=¯Uq¾”n>œ¥¿F~˹7­Õò6UOwCiÂó€× “ó#ïo×O¥¨cŒÖ“­Ì›x\ƒ§Ü&gøÕHmŸy»‡e$fäæo¢¸¬uªïÌ%|[Lï€ |:јõ@/ÔÑx“Ç\#ßT‹ë\4!½÷Þ|Â+¿í“BŸz"ÅSsàQ 6dÖÖ|Ç%ÎG• R&†J4<<£Ç8ËÎtç×bNBT& ¥…^èzSŸ8ª¹¦CöIYÝæ¦!}Ò £'Y­–ìÃчë";V¹¸&ü¤]¯­")̾yaèÀ¾S-$Ù©ã%Òš~M —t¹@¥_•Ër…fý ¼÷_€?üo0mLß%ú÷Yøß\½²võ[k«^¹öáÕ>\EüïµÕµoð¿|üo»øˆþ}ý@þþpeíÊÊêõ`õ;7®}tãƒUù›ÿODÍy`£XÀv– à‡­¢û«`œ±¼JùáÒ#¼/BIAê}OI¯Æ‡C÷>º«8®èY…Ъ”Ç(4à ta“ü//äZI z8œ°æÁÃÍG›;ËÐäÐV·Pà”K)zÀ*5˜Çê'¦Èó¦AâiY±¨•ϲ“/R“šMáQM骱ÈàªÑ…¹ªóÆC¨nZÅ9@52OfŒIêÞœÅÑÿQª[‘O8^¶hv¬IÓú);ûEëÞ“gwÚïwZC“M“ƒ|ri1 %ÆÃÉU§ë£…‰M†CîÞ)؆ÉÍ›bdÀ\°Zïm´ÚÉàè=¸»Öé¾µ‚ÁW$|²"NiÞ£¡mPúŒíAug59§½^°+(6¨Fg¦+ÀmíД¦ã?2=9˜"¸û… h­H°[ÌRL\×eBÌgf?¦Pêhtædr¾(ë©јÉ2Šñç”—®Äõza¼KëÓ­'Ïžš!¶‚Á®ÿÉJjm¡û´z`†£‰_J=#³#aöÀÕ÷¼îÊOj·½SÞìèz ÉõXòºWÛŠ¨ óM:ÿKî d(qóóçMŒ³Ò«sžgƒ„N:;~o§¹—ü=kg‚‚ɽ†~8‹ }ôiÝ”Ð*ñTr†Ôò^O)›µÞ뜀¡jÕJlöÙGM€~CÆh~üÎy„!{‘hO, œ•¢@Á8?IÎ3ŒYDoÐ{’áB5Eîn ñ´%§Ý ¿*ìOwcªBŽ&;’Ì F~h’Á:· .çSí8FûF¹fyíöÜóâr°ÆÍD47B_°)  }Ãìf!hOaù©Çײ€M—:²\³kó‹rËøù Æw+í^VRê·oNri^R8ch§¨ÅŠ^ºêK‡8Wµ‘¢NCô£]çÍ®¼À7K ‰ê†ä×€”÷Y6¡ëp×N¤\zŒwTHùúð p´Dh—F=¡.‰…0633m5²e=âGU7±¦°dر$¸¥òp5öìÊE¹'uõã7Ó·5èR"=>Ût¯n¦KSr6 ºh]º€ˆë– õ!H?š#ÛFNG¬>|Èg£èíð¿ÿoi;„Ëcò˜ ¦AÓ‰cä#¥6å÷r³kªÙ5nö?üÚ¶|}Ókõ­§”š×k~+·újõnßý¿öGçk‘×Ïk~+·xUµx•[Äwÿû±Ðìú[¡,ßß Ö´€]yuãOâþ {zØ+¿p`úAHÂÔÿe¦WÔwº”Šå¡‡"MËÚ½YëŽR: *}Mø9˜ü tg.äıæzÒƒ$Iç}}ñv £±OÕ|Ï^ÝãÑ(™•A PÑÿ­ÙËY…f`:"ŠPÅ @l;wPº=ðÚöÍ€8•æ2pÁ­Öf~¹|¹|u¥JKéö}ÎèëÆ—Þ]¿}ÓXJêöH»zÐ&ëè†jàyŒ·Ë§çÛ ’+i§Ï‚»ósš|æ›MŸ¸SS:v®‰íï¨[µÛígºµ^ ÿØÀ0<9\[àæÍøÍgOƒ‡sy*J&oÔ.F íÂÃÚvYOgŠH\ Úî2ìL89–rÛ]…U|‚¾éO§B5ð“¹ÛÛì ø„ìùb™<… Óì$5²^dcÑ3’‚OÈ¢b{礮`?Ù‘¬tA,Ž·X`5a-V›[©&ZN7hY O‘7«¨´Mh‚ÚÆ`'kCúFo÷õöóhß ¡B”í¿]œ„š6.`•ÝÍQÁçëÜ($rìmus°¹/jl”žž  ²7+Jê§/ñÕª°wœîášñEQ3»°gi`üÀùQÿWK§ßRgž°ïeE£Æk­y-«ü'ºo šéq4j6Ca¾’cH298:‰¦CòY‘1ƒ ;%ƒ# ûOc? Ñœ±%enAAþ…ß¡X2:Ý®nÄyu,»qÎß®ÎyS’¨­W5puÑXãL•À#]Ö·?~ªôz¶#††Õ«r%}íÔu\pW\ç©—^ ¦…x ÓÙÝY˜Å¡éàöv{3ªè7ÜͪV_7g+ÛûÏÍç¬9z6w«Ñ2…÷»oË//Î}h7fÅÆþ¦¼o‘q6s¢è­¸¢7áˆvD¿H Ñvê?A†øšsÁ¾s5é‘U½‘:Õ\ñ»×³*›ÙÂT0ZßÀ÷éBõi•¶¾ÛU$`ñ+j+eîÈ€¨¿@›Êk'*Ì«†¬â3ÚÁ=ç sý£SZªƒð|ìzç&½%éÈp¼*a8úùÈÞIS@0:Ö±|‡:g*éœpê}’.ý©º7›µá`¼›0â€ã Z.­š!æýä%,ñqñÖ¢ßúDƒíñ+°,$ƒ¤>Üëæ}DašKHˆa¿r‰ñÄ0\Ú>j'KU’ÂÜ`Ê¢ÀÈ%Ã’ÔePçxD3 ~¬0Ûu‘船%„i Ü=ÙÏʼ¸ 5J€y¿.—9Œ X5*Fïwáj!\¡D5R”aöÚ¤íž0ð#Ex1£2ut°gö„yË7Žâ‚2@mÒ7ަ¦ÇbùåœD ‡97æSáîºã° _³%” Û"Bc’JMу„:l£ÎP˜s1þ§ Àä‘ú‚ô¹:66jZ˜SN~…ŠÉÁ‚Rö.Ó˜ 5Qµet¾2×tT$—9¶ˆQpèöYG›&l€¨ ‡†Œ Oõ0.Ž'p¨ª¦èÁ,%KÜx²këxa½zR¼_‚×õ|ŒÍ LýK[IÿG€Œ oõÂס¼ÐoŠg¾<[ª_¶PÝ5ˆª=¸ÊÒM®‹­ãaD=º¶ûõ@ë ÌL¥>/ï äœàU²q0‘嬘M­È){gsŸÓFÚ]…i›Ag”±R s³+à¸ê>„Ô€Î}]Ci)è²Vä^Õ7[âp3 6ß‹IJv¹§f?Ã>N¾´ØAðú³­‡:™*r+Ý$©S £2\a?9˜qXe4Ý$]ŒË“穽¦]3“3€\ÞV”–ˆ:¡º”%ˆ¤‰„ÓÈ«2Éwe«Iá`eyœåÒMªeL®”SÔ 6IÃÊQÝ.9 ˜ó/9Hc{™—Æ'†ÕG˜‘ÄM¶ëÎA6ÝoØ•1u£"*UX Uª¹“¨éOI¡ö('»k•Í@#½Þ^ôvá†kN6b•”\~‰^ì÷`ÃÈŽy ËÝs®—Á™[3<6Õª ›5®´µJÆs‡æîeØRÈ̺Ûk}s$½ÚÅQº{„yâÇÝ >BnUºj/À[Ãàþ]S8·ïðÑ#BX¬S¨\áĚЄåE¸Ù¤ÜW€çûn䨥ָM/TMV85H¦Ó¶~ õ/óã$ËK¿‡7VV,·]b{¡zWm·Ò¬Y‹=Dy¢OœßWå-¾ùé§Àî%« $‰YYë­×V?0ä4=NÌj üb­ÉVô3\tµØ9Ñ(§yÓ '÷¨NâvÅAQwÛqÏœRFƒZXP?HÌÇ`a™7ñE¥½¤pG—XAÁêÄÔ&)Êè*Úø–6%{ÞŸ´²æ@A*;ŽÙ6FÀÕåÛ7ÉÎ>²X,°K':… ãrÔp_žuÿÿËÏ6¶¾ßßÚøtãWž"eûÒðÕ¥üÕ¥K¯.í¿º´÷êRÚYÑwÿ ã7ƒÕ]H‹óõäÁ/=Ù|ŒRˆžælj‘ŒdÐ÷k@‹~pß°!¸Ú?qÉuÌÜ®c³@…5¶Âê÷N‰ 4ì/ n¸†Îö¯¹ž‚½ŽÉ^eöØ(‰,Æ!YÈ 2÷Ñ‹ù]¸aÒ´–vgš6ä|:A¹SÛïÐûFð#à Gùënð#¸‹‚¹‚Ϧ¦Ù>à-f—jú‘y<ƒ”:î‡y ýÑq6ˆö€ûôµÆ\Oé6q¬Ùc&lÔb{ÏPi7Øïæwƒ*=îXô³ÄÝ0»©€qÔÎ$΄žÉ}o²ðq¯Ä5Ä]XšBœ‡îË æFðE–¤ŠØºl¹Ô¿ÐiÂ_êäMžÖ©:DÏlM-ðcª¥&à×/™ëÒ(.QÏ<'í%ì¾ÿ gÏRFrɲ—€8<# {Ý6œ S«¸BA/‰ªðZ=Î{ÕŸE°›š÷«)].~ˆJïêÔÁ>$[Ë3z·}fÕ%4t¼{ñ9$ïÔìKÅQ‘“™áªßîÆfµÑÍ€‰´l~þþ·Ýþøé­(ÍÒÓ1«3ùŽeïß6ÌÖ9-0!ƒÆ•µÙ~À0 ¸O˜p†®xZ¶6D`nÙÚÚë´è»?hw^\¾Tÿ|âD©MP°U#öõWª¢çmSóÓ;þ:ÁóŽ_#¸²¥®²“S^Pî.î†}ò¨‡¤¢{»×z¶éÎûü±CcÁ-D&•×/YóV𼬒>ðA¬å‹‹²Öþé+»ˆa9¦ÉÖáÞHÉ`§ö)Xäl^ÊãA–ûàz¢.°¤O©+ˆ^år®F¼ç2­-×Ì1Ûâ– wã %5‚cágOƒ«.9Žø(›ªá¾ŒœN)›oLNñ˜@ŽkªY:ŒNsðÉ3çb­ùÒÖ#köȘWÛƒ*‚ÿqf½mḠ²bÄ'èæãX Í`f™.e#ê’ ÔÄ ²¹ÈJ½ìQñôÙ“­OAÝÚ¸¿õ>옗²ÈK IŸÕrôݶ÷åÁu+oÊbP¼µyÙº„iÉÓXŒxxdÓÛÇk²ÃÝÚ>ÊÐí(Pý¸|;¸vÓþä%‚~}&áÚÝ®ëe­š,{>5ë|Š"ãzkßXP·ª É{:DBdC!*1Oðmw¥w;¨Û;­f–!”¶®ênmæÇ^ùÝû P–ñ¥[Ø›˜kdxj¸}2ø4d£Ù8å{ð\Ó3^ž‚Å#Úׄ#êH½vÇC^£ÉaÄ–PdÀt+50;¤’wÖZ±i›§‡{î%. Wv°¾ü«Ñò—«Ëß鿸¼‚ùGº6CxCHc%<¤×èâGr´èE“DÙö.HÀz?YÇGzަ«Dœs¬Å“ÐáŠËtÝåÛ³"]œ .9[F„Ñž@nƒÚ´Á—NÌܽb]„dpä7ì¡*€’=„r’ãQô5K22ûœýªHF‹ˆÎák}ˆNü]õª¥Ntô8•‹gî<Þ™QÝä´40ºNIF)‚ö  §FÑç¶pÎ&oNë nÏS#üÀ|ßÔH÷xCžÔ±Y ¹.¿ JÐ÷r˜DdñCåePì:ƒƒé¨ðnçv5§÷ÔO÷häCaEb¨Ì̆«A ¹«³Œ£‰ ‹åtèZ"'²D¢¦; ³¶(é$]ÄÍðy0µÜv„óǧ?èx¿œDÑbrónß¾b\Ú©Ø%xóäK™@܉ðÝÌœiéç üàƒQ)“Ùç sFaWÍá^rân Œ§QpˆÍïe_ˆžcR&:íªÉgÐ)Ûf l•ÏÄ’WÂsé§Ë¤+=3~öÛÙ|üýÍÇ;Á1äãäïn~j>vÔ®²CÕη]¾9"’vNz¥&\-¦Ònð½õ­{Ÿ­EäîÃ'w)hˆØÒŸÇ˜£t„ @ù!!ŒÈ+-`RÙŽc5l¾C4ÈQ…ù F6¸1–¬lváAíƒ@)³øàà<Ì…4CW ¹l—)Äkxº,<¢+qOC÷i’(³¯á–qÏcväôyƒ‘’ „¹õ"ÆF™§‚z*ײÖ.ˆ‚ƨƒO äjHùWWiÖ`žD”0Õ‘“”¢2…à5Éêõ€&›/k0­&Ei³Áb6Ù½xI`±F¤þj„‰7+‚­/ãiÖê’CY*XOzÊŒÔwPòŒa†#5ÑteMýF‡¼ ¹—kŽŒf"R ð„ñq¶>{;ïQÆ,%ïp<æD`éIê #uíÂ’X¦J žÑ# Ï3ðx£Ï>Õ¸÷QM;O¿­³ 2®‘Íà8£nÚ®íÊ4gtª&h—3HC‡ñ€‡0óäÀœÅ,^Cc®–¶‘¤q¡¨L0ÅsQx?›dàæcÆw× Jvœ!`WÍØTžxºÈ$Èk`-Ð’*Ö5Ig%î‹.ÆùóP@rþš,–‹È¹Éî7Õ´Ì4Û¶¸ö‚…71ª“"EZˆØ¬³Š/ºét\÷bÃtD„ÃbÈc醣'íÍÒÄèÉ(p7 ‹¦mUÊȎ摹_~4ó¾B©/×i]ÑWræ Ôp"Õ%±e¡¬eÆj¤T㨸HЦÂ?ï!¥Ô!ެ  Š4ñº ¡ì¾ny(X78"U,DÌ-N2 òc åb(“XeW+ÀÇ!B-¼'Éb·˜ôçÄJÂ’ ' ¶ŸÝÝÞØ±ÖüŠ-¡lHQbmÈ`vrÁ~æ |+ Ú˜ÍýXRº;¸Ð˜:ÝʵžÕºøúÅ£"Lhj® ÕpÙc* âI&DCÀüNJïèÊ¥+ºˆéص>±¦[~‹ÐµÄ2Â0e0Z¨fï´ˆíí¥¼€2¼\—JØúÍì.MŸÎÔô$z!(}ú÷€{ì3f}DzuWsð;Üšw•P$¿u¬ GÚX/‚ UÚu¢ü´ª¡ ›Qú ðóWh$ u+´DçjeíÊGçjFþõNÕ,“-£¹wÍ’Ú©w¯ÃORKÂ*ç…úSß™ †ÂKS…Ó×õfòNûCï”A+ð«‚Ó‘Ð/1G‘]3Œ»ltÃX.R¿ñl4EXÆSv8˜Æ'*Àn¤Kùh¿VÆKâ5qƒž×x4c}/Kg&Z÷œ,K½eJŨLU²Qù=D7À2ü‘ÝœÔùíò{t—ì½ä¹7é—áNÇ~UžLzÂxñÿ¶TÙv«d?4ÓD¬¼*hÙÔCCæ+tDVÎTgF$UZŒÁp¨cÊDi§ œ !A¢ªp–#€×ë:ï¼/Çç}’œ¬r –é‰8î…Š“Ä£i@€ðç¨Jøƒ¶ò67mÑ ß—Í­+§°¦ä|§¢æƒ=R@²Úô„3»×ßùøEýxm¹¯1ÿêËŒÅÜ¢)ê·Æ5Z–a]£­×.»;WiA!ª`ª¹°˜Ì#˜› ‹W”u`nlдöó>¯Cu‚‚…Ë&^vwÑÚÒŸL<§)D"7ÜOâK/GÜ õ[åÔ£õÖXòßoAT…ĆRQÑŸš#%ÐVQ ”ð #)nƒgÙœ´T†^Ï]…βëÖÉ!4!4Œò»‚K °Ç±ãþgY«Ê`¹/åÞªXï€ÉÔ”…ëFˆa3"ÍÒe¹%TÑ€ÿï*„„Ä¢c‡|Ëâ—˜F~†"â§çÏ)„™x3Ê‚›^¹*±Cÿ5²JTJíû¥ÐÐ[)´çb°(ƒÀ”ãÿé*Õ"ìñ äà”Ûïyf”ðC§¦Jð¸%s‘°A[YfYÛ¶ ïeóEC z!»É—I?<ëÕ^òêÏ/ñ/ÚŸ þ'ÞѾ;ìOø3ÿsíêÕ×®|kmmõÃW¯­]Yýð[«k×>\»ú þçÏâÿ)‹ØŸkWÖzWz×ü󣕵Օ+«Áêwn\½rヵ¹àŸ(,˜íŽtùcx÷lxÉ9£3c|-þ>ŽÒèÀ>ÕùH`±ð—E½ .Á=rÇÅ2®AÑã*%ÞçÁæÃþý'Ÿ?~ødýþvÿé³»7ï-h͈dMe¶6¿·¾³a ])º·µažôïonmÜÛy²õýºŠ=¹¿ùàûý§[6··7Ÿ<Þ®«iãW6·w¶û[×AS«ž>\¿·Q×—8Ó+*big'G]s†1ôÚËÈE‡ûÀh †{ÃÉw1ñÔ, ^Gàå2¾Œ†¹öÆ9g½ŽV¥¼Jlö°í×)à8®:p°íZûÖ}`D cP •…jÆóFÖw;?1ãT¦cylö 2ÒQÜ .É(v'qJ‡¦ ¥Ñ.%ë(u—QÃàÜ#8¸i²Ç.¹¬óuf„ƒã°ÇýQt³?ãw:+ÓG¦ØÛ $uØ Ú«Ýµî•îÕîGݵëÝ®t¯_í®]ùȇ®ÅEßÞYßy¶ÝßÙxôôÉÖ:R`…t¸ PàúãÇ;L<|üÙI {pÿh<‡—•Ã<­C$#<‡âÐYÊHá¶I«½ÅL ­ Í $ ÐL¬Ád»(õ—„køI´êÙt„~³‡$Ej‡i‰ØIŸDÎlzÚÇ#Á`aô¥{:ÉG L×ð}›LÍèÊ šøNÂÃn]Ýmð\Œ:‰Í"ÇúŠ_ÕÁî·µUAÒøðùóÁÙqú@D¢‘èež,Ȥ]Ëù:ž~Q[¤$^.}úðÉÝõ‡Û»!ܠ‡/px½9CïÁœKÝóçgI9=ÌêÜlîñÞR`]C‚ÕCa%‡xî${Á^n´ú"vÑŠùãQt$ Vx¿þöî^ÁaIâ:JeŽÑ˜IꈛzqýÀxà]  F C-$¦4þ+®|ywAOæï.³ Ìá™ìŸ:/êå’Ûb^9k>ÎSèZõ Îܺi¨‰ô²úñP4‹bëzÐX¶RD@ÃHø ôâ ¯æê*÷0‚ov| (ØæÔ°í&q^ZÔ¼©‘æÖnÂ%,Àû°–z}á"¾)›E¶‚}]¶¢á0Ô&bŽ2²[™M@ÀÑh‰à’TFl‘€ñäÒd‚]©k{×Uê”» T/ S%Ùoè †µV{äNéš¾Ùt&s:Xšc¨¯Ý9«¯àa‚èi]…HƒägA,U#?³7n݉;=µo¨N¢pšJO•JÌQªŽíÜé'ÛL¾í:Á‘‘·\Žåtõv߸D@=èÊà°(ª%9{<¢AMÄŒ‘Wm#Fjy°óÔ£GO™ÿØÂMœ@ŒêQuâ]5cð¿[î²#†µ:ˆû‚¥>[…3 y¸ÕÄM­U‡ðUáž°údšÏ5¯—áøözW¼}È`ïe);kxx1Œo‰-ø‡œ2º–»„”çC\™ž2Çû³…¤ZÔ—«ºö*áÑ¡ÁÝ"76·ÏÜÒ"’àˆ÷ xõt¥×ŒàÃ=D‰B8È@yHâÉ£c›e@Гôa@Ìš€íB¥nGš6àt-— Z®eǸmÉö{Kêà$¢¡|‚nŇY¶kãv0EÙIW®Ù¢#©ï —«é˜ BWTbm›úó^P«ìa„ó'㣆 <è.†:jÁlÇ£ùKî#Â"2(SÏ]Õ¹R ›êZ³±#Ÿ Mo½ÙXýðÃk¿óØB¡=‚!ô$ÞcãÒj®0Å®…©ÁapHjªP7˜7L#Ÿs%€Z  ÂOìº#XF ›ÑÌUÑü¶1Tµz"‡†EX„(4Ïö›hòÅ#‘pÞ%Ȳ ‚¬á vTç™ÓzÐá7YX–w¥ç[Øçf¤¸°L‰Al 6×µþŒú° ¨ uG¥'Ù q¡©êŸ¯ïÜûìþ“OɸR†aª£B¤˜z…èömÍÅ^½ª—Šübì$Ø-÷`¥whÎØÜ-Ð+?ARHLÎ×ÚŽ‹Ï/”d¹þ6ç4éßÏúFÂêo¡éÄülþ[ï_Y]½Þ7ÿ=OŸL(Tüq–ÆîÛå=°}:~ùi[7Õ6ÙÐî}ˆ—mè¨YÕ€ª3CÚŸÌuÒ-÷Zm™}ôÿ‡RvæËÛ ¤2ÛØ@®_¿:'†STeúݼü¦·mÍè+rk𠘎®ìMÛú}y•¼ySµd5Ì>˜‚r#¸²œòfØÁ1¸3C4JˆSé9¨¨%¥ù®Óüðb‹…r%vÁ Øï ¨hÎhŠ­®š»ºÍ+™rÌü¹SÃV/Ç6XII¦Ï­†ÌÇÉ£‘¶  ¶ù¾r.³YáHÄ&ùRËuºA" #â\IäÜëÍš“˜$^[³ŠW•9»¢°ç"³Be`¥|ºìI’sÀ zÔ{Ù¬ÛÛ7ÅAäŒïù¦:+¼I5Ñ\]ØI”Ku \è݉ÖÔmÔêÚÇ ¾0<øØv6+1á™WJOÎ×9ÛÌÍ5(ɾé;v ÊmlµvÇ¿zÁ¶Õ«Äˆ º×€õ‹«r—ñÕJ-xƒ¦ÎËÊéŸ1UoRXO •¹ÈL¸Àyâ€8eJf®œœœ¬°÷jo‰}¯×ãÿ}uBN†hB¬-Ö»°IJ ÃC±Ûgn Ys5vªw†NLAÑΪg'™'ÍÛz«(w‹‘‹Lä’Cœê•Íœú×¼WœƒJv}H°‹—ÈÄs ã•wI‡±„x^nó›bÛP':$Ì­ˆ P”/UcÛµ»ƒÛ“°ÛPªc¯+:ží¾†ì\A#Kˆ¾:-)X-íºUiOv!½èm7Ê3YÊ ·FY§ìG”Ê~—;BÞ:‹„Bœ.7gÒQŒÞuÃcÅ‚E7ç°àA6a$Ù`YÎ3^™[°‘%œqˆ¤È> w¯(õjx*mò8 z]ñg”Ãëæw7÷ù‚mµ[#UÂf:q|GB˜(žmÙ¬è £;¡°¶ âÎ)¾_öPÃP\²—ä5RIŒSÞÅ~¤8V)Ë$;Ë"ÉápìŸm…ý\8”¶'ø›rl«µ’Úcò Þ9UÇ9“|Þ1Ïžï(X†¤¬`@}hT¢Ê˶þ74ó[?[šâ-þw/6ÊR6#0å”íÂ5DÀ½Zjî§Í¯[nåéñ¨ î½Íœ,ªÿ#/v”œË^3óudX›v]µ(Ùß }šTº1ŠÔÒlzgÊt¼Ž"ûìûÉ*Œöë{Šñð-C×ÍòíšáŠE‹J×_V0¼»æˆÖô¼$Ô¾í„)[’Ðãî»Nb;KÈÇÌE*–j¢Œ@â8½QK% srÀ¦Ëw gx¾Ýpv¾!„U!j ˆîó,ØÀ¦öÄ‘_tþ2¹Ví’ùJ]%iå!ÅOV±ªÂrÀí+²·Uƒ¹†‹w;ïMguvÜ3o 3 д)gås QßdT$ÿP%Š{:ÍP}‹´ÿO@´"V%K`øÒmŸj”˜yi,!Zå+­¶ŠzQdn Y`Ê‚ÓEÜl’=¦Ôë· kâ÷ŽÒŒÆÓÀ%~bÞk•ew›Ž+"•°ÃµØ¼d¤óV»JØu ºY½05Ḝßõ!e¸òyµ'áÊ)ì¯ýü±ú|£^VÎé›àrNŠWYŸ¡êt—;Š¡ ,‘÷lœæ1Uˆ°ø El_FDwH:kΉA=Ya„Áo$,ˆinÇFE€ 36…|Žæ 3­{‘Q´·@GØClNâÊ<Š‹žxŒìI¬/z'‹­½.æÃi!ëô¹©7ª!ÞªY"§ó‘h½ÖMÀ'x0ûçò»ìövÕë©Y|µÀÝý\ò`Š6|IJ×;OÃ!ÝÔ š½WsƒîRy¯`-"¡LØ•—€ô!Or@®•dŠóÌâ?ÇèÒ//BÍ_Ä·ÿrvуTÁ=¡»${‚´f ²Ö:΀¾P— !ËA€¿yÇ€cךIÜ,`{Œ•*çEV«J¸;}§®áý™²Ä<çG=¥&Þw¸eöH¾ehö#µYg1xZÞƒcÊžN–%,k ÊÈUAèÕÍ5éC¦L®•[ú¿0Z€A¾Ce nðbºñœ˜ê4d‹Uí Ƙ¸v}¢Â«ù‹bÙH¼ÖÊ(²ˆ*k÷ 'ò^ÅKëpçÍ¿ƒYÕ'³;u#­ÑSQ¬É§©¬šV_ó‘uš‡gÈ© C6 gÚäó\ó–«z\4_0ú¾R\…6\=ÊŽçÙ­¾.Ëy_cYúƲôâLùù[–`C½¹e «¾¥Í71ÔxWYUaºF‡ F9éà›¶)h¾~ÿo—*·® R*®ä|+É)€æcH §zÍÖæó<µ`Ñš4€RG|ή¸÷ªÇ²g’EÙR`”3ö={ò}:ã(æ”’áÒ{*Ã×[|'é{“IÞ²‰YéqŸWCç¹#IÁ*F¼týdØNIX§8ZÓmx'ì7÷UHçnâ„A·àºêç:ÅSs@|.0^ôµ-¸nÝšv:ŽëÉ 9fL,ÝÏùCd°¼ÅA³´Ej÷),ž^äSWOI׎Òð.UT]_m£#èþ@b…X2$šH´på<>e-ã†c´. *쇠M°/Uõ¹*Œ²ûøäÐ(†¸d’3™¸aÉFÒ¦#z¼ˆÆ¸=%…OÒF­4’_å=Ôƒ(ü"Êt…„åØHïQ$%©RÂã¶{N„÷`¦Úö6«},i”\d×ÍŽ”³ÏùU‘'%ùI9É‚)‚Z6ýéÛþØÚ&Ù䌺Jã!?̵Ø(ã”wœ ‡¨„L‹\ƒ@ñzƒ°¦°¯­gÕS`5î屺£ˆXÀ[Û‘:rðØa¡e$÷¼¦>àŒ°èÖ¿„M_^ ‚¸P?éÄz% oiLy^i‘ŒÉg3uȪLW‘.T…ÖÊv£å/×—õÅ®t¯½~>üxi¥Õ-÷Éޝt«_‰íÓæ{öÞ‘xÔ¡Ï9æ 0É2ƒ‹Šœe²z O3ó92ÊÏK6wë[LÂ1:\j² [Xb×Nƒ#”bXî${–ÉŸ"Þßû3Øa7Êl²Óxà°H+ß5«–<$rýài&®nžËM6sjó%Æ9ž3ÖW;%zš„ƒœ_ÓÑB¼³n‰Çs­ÛÜ,%é‘òº{]g“  ÕÈ}G,‘¢ÜÞ©Ë‹¡7ìur˜ØdŽW¹åù˜%l×ÓqDXA2„œ ˆ˜»ÉÀíØ ×>Kº§$E¨ –Áò}(߆†½HeC7ÊsCɘ1O˜Ú6Au¸½ñpãÞN°ýì à6w(CœêSÖjïflÄJÊË[´úÉ]·#e¬â«Ö×Ê»: È^‘ %%s„þUxÍ/µWf«9û̇^Â{3'HrÚТ@ßüÐGÓ?ò"SÅ,ØöQ0€À7p”Ýá k?²È ìÅ™(hÍÍÙN`í9#B ÞîÓÏõ+&Ê«•¾~å¹a0/:ö±ðxV³i^¡ôn=’«d×u°ÖÕT–È·ÓÑjÚ4–êù–Ã¥-äÔùU;T‘ f¬&^J¿fD|°áurJ³) Ü+Ûó†ì :£õ‘/:±1¡•àhE•©8*Ô’SŸx:,A»f¥ó0F•ì€lˆ6¦¯ <`iíßÈhm€r•ÂN3ÇÉp¯+ñ6ÈÖì6XÜ.(½Ñú†=ë9d,æQçô®Ä‡J4©Q°¦âí8(îÎü;êD v|ÒXZmŒ-›-½ðý X ÑWy%ˆm¥`2çû3¯«R;ºR£V•¥Õžf³²¾®lqnÇ:ˆAg-Äów!‹áÁ(Û3ÇÔl`÷Àp’ùNâû¢\­ibˆ; ” rB”M(Î!±¢›‡ëä.¡Sk@¸Ä>c¶:Ä\ë¸Æ8•бå­ká&äd„L/Ñv0Z_ðo£jD¨D=ˆßЇ–ÙXl>Ìζ%cvÚ\5#»¼/*~ýµ¥J5¢(D¹òãîqâ:Õ.un—­ñœe·ôãnˆÜ Û"_¯Kõ,RUÞ*Æ“~éM-¥SìŠqê æPè²ñcäM0L )Ç#A‹à‹œÚr9£½©¬ôŒÌ§ª[Vh6µ#6íaQLn¬¬€¥3‹sºÎ¢ÑJœ®ìmfyÀÐK€:Ý£NƒáSß>{  #`Úï?ù®»;¬¹iT%7oö·7ÕÞš–Ÿ?x²õÈ+0ÏöÜt »~èE8~<̃Kãè%XÄŽ1ÓÂllí2ð„‹ÈÂw–¿W†?—êÃwÒ*D‡^ÒÎÜKËÕÆ){º¾µ³¹þ°iÆ?Áõ‡ó¥¤žaB…Ýå¼.<5ÃC"|–¥Ù 3n1ÖÀô[¤'ÊL7€ö»yÞbJ75ƒ¸;KFCkç†FhU©Úø`çÙ0»Abƒ3⣫J Þp'±M}I.·dÖ¡Ôx±ñT] Üæh-mG„iùÎ4Ãäu¹9Ë@;¹Cª±RïU-`ªøIÏòÝb"våúPU«ËøfòjaÁ 7³úÅä øbG'ü˰¡±Q5³Aðr”“¡y01ܘÅšù¿“ÐÓìÄC²Ý`¦ß‰<ÖMֹ‚B”Ã{##L¶Å‚ŒMûGÕÝH ÞùpœubtÈpâ]_TÛw«EN’ÊËãÄuöv„ùØ íÒ€Ô}ÂP_‡ ÁŒ'Àiˆí0M$6M¦t”*ƒp¸ò¼×6ÇÀ«ÉèÕäôÕà yå“W_䥕D¬‚ª/p’Z°.ÿY7X¾ Ffâ %xF§Ê £wC†­1¹<¯=©©¦€3‘»Žšj¼t<ÊóÝ&>u)Í©®ßM$g“&h$¹õ‚ðI]òRÏ5µúî›ÌhÔÎIÏó§‡5îDÚ…J›5 ×J+¬®´+$‹Çi½ã¡©iÝÊL`ÞaU–õ>šyIP6¸f}J¸ÇëÑ€ýaBq;«rMÇ×WðIX™5½ÖÌ945§ÿÚEåìMÓ>4cïW¸IÉ`^á_N4Tãd!ËR‹$§ßõþàÃÀðj²Ükã&ôÙç_[¨%õr£ýÔv"¸¬y·=ÒØ\·f£;·F DúCžR¼C¼µb~À»­¤Ç?¯˜ÎÌ ¬[€óIÝr}åÊÐVíãªÎô/o0ç®K¶-¼ÁxúÙÓPÔŽ>0m³Z¯ŸÆí/±  ^Ó->ôÑ× ³ÊRª_<‰Qe˜ajZ:Ù&œ5ï•w˜œ(•}­Â;§â t™n¹! 1Ñ0Åp¹VVvz„c€¤8®Ìl/l5¡áÙÂõ°4ˆgu4ÐY>…åC)Ô¯”‹Ð,œE>æ<9a¨)¼Î‡àÈœ…!DG,qHÉÉÌA‡§ÚóVšLË,Ó™/£eŒZ6R”ñM½¢€ÜjŠp> ïd9]ÛûÔ³6“†ã‡2:°cÈT“³¡9Á¸»µú»ö%÷/Bç¹÷øÚ3™/ØÜ ™ÐÑJ¥0ÑèÁ9%«sX¹-cšÂ t’cC ÁëÌ4Á›eØ“.B ioE±G‰å³Î.UgËç~¼*¬žr,|*€V$­;Á•k׬7 ½Ž9,ÌžÜ,r‰†"5FcŠ{ùå“qRØ8©²S(Z}M°WñÌâöæàöY1,N‡¼šx9YrˆàqÆ[ÌÅÉ)#à€»¬yúÛko²Ä׫’9˜ÓB—¼±¤ç Ââ"ð-©Äu–ÞW4jl‘$ÚÓ)¦Ñ"˜< “1e×lДe7 ¤ÛSßH{ñKÉA0çqìe.Û~vÉÓOøþNæôGeAPJÁ ê«Š„ÖY=ÒÆ´öŠE’Òo9i(,Æ :,òeþ^>ìâÿº÷õ^å Q?pˆ!J ’éƒxŠ”€;/ÿÙQ>’6j)™S’–¯ÁÄ>†5QçSÊíÖ ~5žf¥Û¹¡y)©i^7ÀÎ×—¢“ÌÙùÀœÝ´–رڻ¥3;vööÆ9&Jëö–;Mƒ²§ÝʰӲ›"‡Âû3Úèdè:†ó’jwG÷¸q‡Z{Y¤Kö]šÄfB3k,æÕÊö¬3¹–úÖ™gžÕ½.)gKèxÐgÍËyN2Uàry:CÓËӦ꼣×ôœSæ'Øé#Ÿ5tÕNá¬á§7ž3|»ZRuú­˜ % ²ƒÔT‹^%ÉØl´hÁM_»C©«èç¯G‚““™yË œä}¬¦ýÞ™âÛŒ|üý!— 7Oå_½ Ø_wC{…îPü¥§Ÿvƒ§?EáíÓÍÔ®wZInî:–&O&ŽAÕ¸§|ë±>m –½‹‡êì­‹éÖ8Iñ³{µЉËÔ€œë|³HÉ‘ÏIŒÁ$‹7Ž0–ö“nÑïxzËÑ pû®U&–ê…?ß¼¿óÙËÏ66?ýl'À¬ñáõ««/¯~´Jù»?ºöò£k!&Ug§Õh£#ÃãÜ‘ P@e:hCÌðÀÊXnöÝl®»\o«êDL3mt€p/ºüVæ#ùŒm2,â¼~o37¢oàs 0U8Žcð‡¶ƒ«´ØàÎÁì àß}AÓ‚†ðÓœƒXÄ–·`ÈLO!õX^ßA Jr,Tç[Áó7ɬKcÜ@…+^K‡×bLʪÝõnœÕ9@d¨Y…‡Î`òDE¶ü2Ü«µ—N’!¤ªX:Œá¬£c^†µ³å™0™ob-á 8‚ñ#0V~DÓ3iÄ™ ÁvGø}ŠqÈV5ó(Àôåγ#‚GÞ×m ßÇŸ1¡zyn+†·nPžݽy÷¤Ì1¢Ür î±âÍåKpEZ N¨¯“äe<Ê} `yHªRÍJØG£8’@UtQ±yE웾ªIV@=U¸ NÁú…µ´Õ}í¹NZûJõÞ‚ˆƒ„@¼±på_ÛO%{u­,Çã`£Q4=ˆozS_:8ß~Ϋ•Ø µi+¬dþ¦Å~¿»=[m}Ξ½5gÏÞªÛ³g-r ^„Šò&‹PNé^¢ R•³¶ [Ì¥IõD'/>¾$ɳѡ¾bd•eêqÑÊœîľ\ _Ö~ýMóéâØmÓèÕ˜Yg˜z'FXâ6.t%˜x^L3æü™sqlvú“4øÜÈNÙ x˜¦OæŒbaÉp¾­ ìî³gÑ'<Ù Ö|Ü Éq2WìãE£¨Ã„Rziš.Äiàr‘̸+è_þ=‡Úã,Kòµ .íh_>£ÊpëòÁ¦ŒÉc%â1hŸ (‹bKº€ò?ÅŸ¨…w·TÆb¸ÀØ1ο¾B±Î)ßÊ´ôÝc¸ˆgOï¯ïlØxŠíÀÞj]r|žН §JN–áìû\Ö£‚#÷¬äèi”æû’rs†þ²à4‰!£³<>M& 5„ãN%÷“EçÒµQ” Êrsg=4L®ft6uìƒ<Àµ†PV¸ˆr)ÆêVDP×á\‹[‘lE%tèeÓƒ•§Ó¬ÈÙ(_™î®\_».ÿ.çñàj¼Ð¾Ÿ® q'oÓ%†½ÜXy>ýøyÚþøâóâUÐ||ahçÑ¿K… @¿·õód"®Œçicáú.°Þ¡©Ðì¾µÕ+W ønp8Kr Hð1ðâŸåZ•Û:öj½V§ŠÁrÜÅý8Û‡âJ±˜˜Ã ò‚Æà9¿?ìbÓ^ Ÿå˜C{¨„až³r}ÄÞl»B/A ò …¢ýQVP9ÁÝA¾³ì¨OÇgg¤8Ÿýâ³g…‡îŽqEÈÆ›XÙ T'$êÿeKL±ãP©P“¤-¯Éh8YÅ0N@fúál1òoªÀ<±SSÏ4–A¹ÚL[v÷ª ¢X$V.Ü=Vù ¬=ÅË ™,s@O2°UTf»Ú·º(B7¥?"Š{NêaxýîZŒÜ?C›9Á|º±³þ0|Ñ…ÛšÌ%ûÄ%|rèøÄnQÀTà;‘À’¨_¨Ÿ±N€É-ÑYÊaP&tà€ë±ia/ar ˜œÌ,àÇPÍmŠB@·_Ø)¤ÚˆIlsVI våþaÁ] ¼"v³–ƒq«[Ö™D\B^áÛ¼NFû<ÎŽâ¾!óR¦Qq°Pê(vZbõ—×£®@´ÔS¥Þ£Ê…«ZKé`Pæ)[ké¯ÛÙf®d3?Hà†ßÆiÒ~ÆÛ]³¹HiGù¥Ñ%Ré~w¦Išª zÎH ºZüÏo¢C Å5♓‡ÉÐÌ ×AV=W{"áÜÚþÞcL§ã¾!A&FÑïÅ03ˆÒ´Q0™’H´Ã8*¬J®máÕ® Â1“ž`Þí|å¥<€fn\mæü™Å”çiœ འ¹$FèÕf®-:à+zü^êÞû~ÔàŠyñŠ(áKjk\à’^8˜MÅ"ý9è‚ wuK1v0/Ώ<éyF?@ŽiÌï#gDµ‹D[iWŠ+ã¶âS×{ó…aœ1ÈRVÄrW‚ŒXÇ©M¨T-ÑØZ][ rÛ;$M ‡.½Ürõ†#P ÙEÒlaI[P /=´Æü9(Ï$oXÁ¤8¤w‰y~Ò‰Ò˜xS9­—L¶¢{ #e+¢sN;¼ á jFa¥@Þç˜ÉÞ | 0Ï’îìH·<Û6‹éÐé,˜_;Ð%ìÆ+ df_¯„škÆl%ìg¸Íûˆüm„øØzFkÌïØÏ¬õÓ+î¬ñJUʬÀgü·ƒxcðþ Õ¤;¸ë\ÒTVH °£rS2CôV~T:I…L#m1€°‰Å©‚Ž:«j lììv¬sÂîê )µ1Põ3¬­`Ù½ÆÓí[ÔdØÁ¢Äpgƪ„ E#ƒJ7º¸„Û$¡6†’˜ä³=u0ùØ?þt²gyAé>— K‘#¢M&–D.k9ò+1Ið”+Ëß¹­‰Í̸{µ¥xá]™¹õdoáÈ3Utöƒç3Ì [ÏØ¦Š$•¹°’/./Á(*3ÆA;zR<3~-+vÔ+6ؤ ¥r]ïb_4„Õ”ô™åóœâu`ïsŠ[D¥R1J`Ä”â¯XàHHAé—_WèÄ»M@5PoÛZ#X~³míÃ%Öà=¦U5ò›ŸÖ*:åt‘Ö8Š ºçfòü ¶š× ³D\ÍÓ™‘íë*tZ>x}&ŠÛæ3#‡>ýì)Å[þ'Y?Þàc¥$$^ÜðB©T›xÒøNÙ‰ý €ˆJÈ|1€yVQ*¼LÇûO¶q÷|€¹8ÃÏ7‡s:n<~BfççÏqVožU6-Ê%9r£clÂçÏC­ÿø`C•ŠWŠùµ­øÁbÎæ¥×ì^%¤'™‹µ$Fáåæ<È„éJ—¯–dÕ?ɸ…1ãì' Ý ²‚3º­—1b-Îú§àW3áv†šzU÷óÇõ?ß(ïFÎñÚ«L~/t Û ™7oÈÚ­WaD5…ÎfK(ßE¯z$¿e3(ð|VÅ“ó#7€¹¬ Š›™€„=v^C—â¯i˜žï%îà ¸‘mÐ@/Ã椓žW%vå¿IÞâ.ìƒJCE*:Þ»þ7çnacækf§UÓ#Àò³!Ëå5ËžÝÏ·\V»%Wz##7Qe©»h…€%égûÞ0Ü[ªmÝ[®B”¿Õ£îQ9èBj«_[srl¢êeŽ’Gæ|Ž‚ÓIŒ¡¬6m<,À|rì7 Òú>®h­I †ÏÓ¾d̘L¬'™ö sA6`r±›Ø1~3×ncTs€\{e?^yÕ3J¦†×ÃZúD/™Õ–i“t­îíºW $ˆn¾W²AËf¿ÇpKîÔ4 ãý+d[Øft<gª ’W³®ÃEœ áÞñù4àBEú\Ìz-ð™Æ_ÒDéa™­7O–â¶%º?ŒŠl\S~õʘõÅÌÇË/Ç#¿t>=®/ éPüâƒhòjbþª–‡]±YMÙrÇ ÙJ©"¯©g˜O`l©|2ª–z¹L™€…œºÂ‡ì+í†m‰/¢iµÄÑq´M‡FÇT-ÇMEÍ“$ÿÖ2Y8ÔÐAáhxíX-Óá_VK£Áò^’Æ/¯®ª*'¼šè1cÆรÉaVd0Ê»’é^] ;V³0Ö•Ì%ÿ¸fƒW솖ÆùI6º‚¦ÓÕBzkº¢Ù°f‰àGWâààUvP3=æ+5îWKÀ¶„ÑÀjJL–·MUtPC†P,ORßQe§u&ƒ|y:ÃðL[0%¯âI )À鑦ÉD-Ü´Ž*áGW¢n¸æGNëhÏüX*UÔÕU¨©ËÇÉ+ó_ÍÎÃ_m¹“ɰZHòÄzûâdrmnÉk½5Wø%Ü¿2×ì|xäç%”Í븄.õeR³Ìð£ÛgÃz9N‡½^½Å£‘"Ò£qMƒPø ËFñrM‹ÃÞQ¹¯Gãf_óÚ—jx³†–ÆÙ—‰éSÏ(MÈ(õr´gþ«™@|3_†€±7%½<@G ES§¸|¡*ŸLŠW“º­ /¾Ö$óXY6Ô—Ï¢<É{hÈÌxÚƒ¨YïÕæÖðªÄ&ë·k6GÃÛ Í4UdÃ…_>˜F“CÃ:ÔÛÅùß^jÞ’…«Á#E¿Z³I^… 0ó/æ«1¼Y µãh ™šªò Ø/óÃX‹KYñFÔv¥a{ÔÔØ8ú͉mΛËãD_=ˆó5]×{£‡ž«Š“xφ`¶.pðž}ÙÈ/Ól# xØ[»âÕQsžcLã†y‘Gy¾œíï'ƒØVˆ„HlSºêâŒîÉ„Ìë^ñnºWûɼî9Æ·@''oØI½Ëê»8‰ê"Ü¥sú7ɪ&%Ã8?ÌNæVõ.†j[òŽ¢…:©kš×Ïw²$õœôåhβàñ}ÖŠ9 á$´5 Ãëñ=šžÎ­è¬®PEójx£™RlyÌèJç,&uëìme*y=«îªAV#CµÓd܃‡N7Hù8Ò2y“DÞÃä8AkÏ  ô; ' ÿŽ/?åuZå¥á4:Ñï4ŒÖ{'£×Œ~­ièúµ1RÝ;' ¼ƒ>åêÍÖš·–)¤_½ü²iêgiÏHyÖ‹Š×Lþ²iù½Òœ ¯m¦A>”÷ªËT,öFmc [T^--î˦Ååâ•u}Ù 3û/ô*KZ,ÔP݈’¦=u:ÞK"Cå$ìÞ8Î ©NéÈ{/›´Ê“hңǮôxÔ@fXx¬)Ò|Ëç&‹„~å¨Îì¶våWäÃ]öåòÿŸ½?ÝoãHò†Ñþ¬«(shhƒà¢Í¦›&)™Ó©!©öôCûÁ¯Á²Œ¸¸©s/ç㹎÷ÆNÆ–™•RK»{æmu["«²rŒŒŒå_Ñ)ÂS+Mãid¯VÒÓÜW%õG‘5åÌoÙ @+W–ÓÞÄÌaä zá´ºKEKæ3y«.Ä‘£ój»2§­)s:Õe¢“•â!ÂM­ÌºèEhÊ@­ÌŠ(âL±s³+ðRiãÓæÏZ¯ä«"~š·ZÛÚÏNoææ¯X5æ±Ù +“´÷Î[®~ozÓÏÍWѹ뙦‡Èv3GŠ?]¦ÑÉéZ1Þ¿ˆ01SÈ9/ÆjBò2ÊÌão=Z[ øï¯ãa´hñ€—+èÁïÊG—J‡Jñ_cºRStThÅåù4ÊÓßBí»˜2ÛˇÃy9›ú¤\¾›Ü”ïúæ¿™ù/ºß©b¦ï&Ó›w“xGøv§…–wñ…{Gw Uî²óî2^­j‚ˆ¹Æ\­Ð Wî8ïìŸõ¢Ã‚ÇNšˆnj3+ZN™D/)Pj¢„bó;`TÜÀ¿5åá½ûàÿsó¥ÙÜïnŠ¡9òxSoæg7³éÍ´8‹÷_8&Fet,”¤Jf fš­,(§ääyY³<ôÂ-w|­/Ó¼¬ˆO—Q– hŸšcÆ髇kßYy€ÒÈÅ…OxìÎtE®¯–¸Vbñ@ˆ•<{šJóÌ{¿:ÎbÄÄ›_'ð_¦ ýêI—ñ¹¡—ð«{7xïÆZ¦¼ܘÿ~×Ìï¾á „Ê™ßÿ™'Qö½˜ß˜¿t 08Ás%‰Ž&a 2v”>À\¶t!æ+ÓÀSª×Ÿ…ÀOÚO&iÌ—ÊLPwª $ýº¢U›`Þ+ü²æª*Uýª¦ûW)ÌK½Áô `íMÍDÄ)€Žáåy¡ËŒGA™bŠIÓVÒñõH{îONëJžæ3¿ä ®¤á~A¥“º¢“üÊ+9œú%áÛOaç®ÂN]…-]…-\]ÓuEAý¹žÔL$P†¹|ªo6Ô‘Ê›|1Uâ™ºŠ¿«;ùùùúü¦Ì‡….ýO‡7SÛ–Àßm™¦z¿+}€ÔŽûZÔè‰ß7½×bp¯¼ð^©{ÎýûêÕù}mÛEÓ‹ùë¦t&1*6Ó›uÃù\_ÁFÞw`ç÷"OÊÞÍìjJ™ÙÍD‚ TbAG"zãËiÞ;÷],ËÞìæRÌÛX†, Cí+dF2Ó]5qHõvæÍ“!Ï›kf…0GÔ–{#–¯_7FY'Ù.£h“Â¥7Êðî)ãeBËÈi~ª ‚ûÔÓòŸŠÐ ï us>ÿúë›óÉäæüêêæ<°î~ýõy_“•)Ú3E{¦h¯-µÞ/¨È«æ||k®jÅØ7·û¼ªûÞ»¾ÿŽ¡ ø…¼“è¼ô^ž§å»LkÀøä•Àöõ0ø~Ž!†.ª ð»ã‚¦Ÿ~Eæ÷ž–b=¨“^¹Ï”ÒãFœÉ|e¸ÿàŠ«yɈH™¿‘f½áÍìWÄÓÉšg7ÃÙÕM9»¾é ý±xôwÑó_^T9Ö…(ù\mϺ/A9€'S¬š_wîõ»þÐ#‡›þ…÷Vñ»³a®_Á¯nî½:zQAØMà¿L— TybÞ•—Êž[ ¼.y ¼ßÌ ð^[S„ªüj®K ‡c¨)–g7ÖÉ’ÊõÏÞúê#²†iYÃ5|P…‘7¼*.G•÷—ž¦ð"òþB¨6Ï\‹H U ½ÈÃø“Þ‡yæ—)ù =V+—Ž4>˦ .@öT géP)Ê\fåj%›=¨Ï<k—¢èéOò›K1^]ÿù°ÔíèW baÌ»ÀǽeÜDœÔÙ?]ÀÅ„—1ä^tB1ø Jæ>ƒü__ØdÁAv/ÚlëÕt÷lo(^àŸ†þþ}² (‘gÉR?;L‹ùÃq—(D÷Oõ‡àï­RìsVk<ï˜ß>®ºèŸ5óçуøïÚƒuÿ߇ë=üÓúúúƒkÙ¬ ™XÔ&e sˆ·pßêàbên¦ƒaÍœ*/C”S9¢éd¦`Jf-~èÆa§ŸF“Ÿ]¥06œ<ÇÔ%ôeI¨Ì¬ž¶“ ÿ]í­öÛÉÙꀞœ·]ƒŽÂ)æ"$õé¼aÓ›ðr%IÀßÔ Hå+Ò€ÿàœ¾ÈèÓ4ü°_Ì2—&Ç¥Ìha,"¢»ô‹Œ²‰3ðÀK§ù‘'û’ C&ÚÑä3‹ƒ€r)D„8™>aêíÒÊŒ$CC žó-•©-BiØ,êEŠ™•l¿x ±Ëyc2ò0·.ˆP@ ±]§`0–“ŠëiÇÌ2†‚cW»ëó&ñE SÉȄ݇5ÊÖÙ EM[’žYÛg"кù’é„a?5C4¤¨)¤ß¤l[ ½u­°½fÜ…%\[f ’dMóSà¬f±!™˜TÜs¸¡l‘‘9H1³–ÍFµ…дm­mì!23–нÐÚœ4]°§0ï­éÙ| @O®*3»c ‘{™^×LN*gWPl7•5€‚8\¸û‚,;^Sr¯úUfx$œ'È\ðl>”œXÛHÇ0±]æ"b´RÇ¥)°é§ƒU,)h ¸óf'÷ñ'*ÒÂaPØz–,ìšÅª‘"j ê­©éO&ŸÓ Dg^˜ê$Ž1ë—Læ¸ c±>¡ªpnѼLÓñ ÍÎFÄÌvX‚`Ÿ;$С0J‘ #É?îˆÎLÛœAv)_„ÅPX}H`fêS"Zžò=ÉãB€X|2£ßïY  ò×Åœ@| 0×ÓC²)D0 H^zŠ©n‰Ä³„Às$•>’Êd ò͘#8-ß• ÛjJ]Sb€?ëš±Zw& ³1 ÒY¢ Êw¿H¯\3Žü »ÓÔL5¨×ôøî ›5k9ce®u€:#Ε ˜³œ¶)L<¶âŽdóÓt™MÿsÌh»Ó—Pˆ0K<¸¥ÄÍ‹ªÉ.$ïN$Ð2›uèPØBPVŸ7µP}íÛz©¡Õ˜ƒ”w3ŸŸIR7s@öfÂ-Ý)‰ @Ecl„šN)iovÞp fa F‡ðàÌr‘Ð$öÉ Î\€¯ž•nà^~:wohl0,©ÙØàŠ•¥}»ÿu›¶Œ†/6UQ’3JÃ\§ÅdšAɼvÉP|‰HvÍ®YU†;% í©©Îð¥³Ï_ÌYßפßE¡|š ­Âø†/Œ@8äî°¦ðÛÇ"ä‡k7&Ùe$‘€¤®¤eÄXµÂ%IfHk†Ÿ—àµÂ¾†ía ,ZФÔÈ'mç0I¦Ò7„#EÆt6L¥»Ÿ¼€_ ?«Ììq HLÁ!ê6WMd³ñzwÿmwï¨{xppÜh'kWæf¼Þzâ¿ÿëÞÑÞ¯v»{ûÝãÃÝ])·± Ü‡»[;Û‡o_ÿ ¥„¥_ííÿå¨{|Ð}³u¸»o[ÿ&,÷ú`gïÅÞîN÷‡¿u·v^ïísɵ°ä¶iô¸ZðA¥ ð«ƒí­WÝã­£¿p©o TDåáæ}©vYðà‚iWkã^(š]FÙ-„›†×)Rè®Ä‚,­7Ÿ•‰Œ¸rÊù¿¬ÀB2öÎïÜ>q Åp!¢dL}Hð‡RÜ8ähê¯2Øÿé5¤†X!1Ç[t’·I|†ù9Ê™&/bãÞAG'$±åq¡$d„Ë•PHcð–jÿàðµY¨½ãÝ×f¡bä˜ÜT;êSkºÍâCI—Èk+ºãÝðç wÞ ’yoæIµà†r«MÉf®Ð('õ(n™ ¬ÈXaƽC92v0‘mjÉs’÷¦ Ÿ½}ùr÷v> í¶F¦Ü/½pâ iQßÕ h1ZZ ?…[Å_%:NèDƒ Å}M]ËL¬Åú̧úî$Kõ²×€€¡Â%Èݲúpc53Ï’ð®Š.á+LõòÅRdª<&YåœjVð”F¼e³LJàÉJó='ÍI–f›2ÏUº•Z Á½×æ½wQv±³ûbëí«ãÛz.<#8ƒœŽÅל. ´ê 8ROØ ;_¼Ýß1¯œÄûÇöeåøÝÚÞÞ=:2S°oNË@HŽ Áw^¼0£†CüÁ‚áê¡„Þ·ÆóÃ&¬?Î;b¾L$œÊu*!\e«BAן£ê2¿ÞúoX²ã#3ŒÇ0Œ{‘¬¾(U¢õy…t(¬ŠS]1#ÎG‚>Zisg÷Íñ¦Íou›áܳLß!_U‘Gó5±Lš”s˜]9€DåsÌP¶hFÌM²üpn(«°JB¿Ââ Ó8­®oÜð¹p+Vîo*¿TO¾ ‹|齯ô[÷³èŠŠdÑöNò&«ÃKH­ä]Èk`ä‡]¸pæp3ä gIŸ dõRŠ«ä:¥›Ó:ßéýO¡@1ͦ•!ÔBÂ%ÏX3t‘Ž13c Ù¾Ú O'!ÎÀêYQXÍZ_[_‡¶µZµ©æ ¾ž©p¹5áýZ1¦ÈÑðBi'I~üçÒQ /HƒOIiÖP¢¢‰£/]xÇ!5È ñ¾"ù‡‘9ƒæ˜`†Ê&tŸ„LÄðMÒU” ˜—Óy>DXjºoeð{Ÿ®-÷n1ŒÃe²·`Å8»øÎ¥ó!A–i™>á<+c LHhðLk£UŸŽžÏõK´l\Ú*2 †V]Ð[.Ý-JŠÚyKg”qÒ£#˜1Üš—njÅt·Ú<Ž2U™,çÚ ¾œCBy3/±6¶Jûó¢Á—’î…o–*mžm$:P'ƒºÍL£dDEÎÇó,LwÀ-?•y£Iny}0ô¶*J´'|ŠÉ0x°ñìšÛrzçY{Aå`O`ÐEw¢ Z!Q ª ‘ªC”H»…W`bÖyv‰r+å?†Ú8hŒ™·è0¥¯¬æÓPã@!Û3;+#ãȘ³-§!Ñ}q>Å{öž77¥{q²þ ÖQºsd]éa‘BØ^Å:ÉM eÇÂPÅi¦ÇÒåì“2 àüæ‡O§ aiˆÿïM#eçAwË]$:«œ|@Ç”¼ž>UKÔÇ… åŽU•Õ$0}‡ Oõ>‹,»ln•λ`füz5]ø¬(/»9v>‚N–ßaZJ2 ëµ|ñ ¦pàŸ!Z”eˆ§ÔIŸë1öÈ‚$›NÇy-ÙžÞ:œ\éÙ§K]HªÂ·“r$KÞñ¹Mݪ8âÙ×ÍÙìÎ )ÝJ:.AM“‹Æ)@žô¦F˜°î'Xä<¢ŠÑÜó©:˜Ïá•<”æ2'KUóDôá8ZLóò—f"Ro^o]&’>E‘Bjrê°]E9’­RPœ x¶PÔOdQ„à@YL{œÏï@`'‰ok5 6r~Îå(™+AÁ2-.c>ná«á3§Xµ3‰[ ¢DÖˆ’øß8ë)Ø]ÙkžfhÅ2#{%Ö–áñ‘ë€ùE‰ÀÐl­-÷”™×y0ç¦zÎr´C’ÇžÓrìñ"JrKbøîhŽsŠø¤ç%‘´9ê}ùäžM@‚ùéÇÝÃ]ºìí'àVË ´ÍÏíF¥óàpg÷0ùáo†ØfÉÎîÑ6&ÚvCZ™GgŒ£ÉD› 円È3o mêmª@Nµd>öŒ|¼ã2NXÎ%d.ä=õ$sUËIƒó‡üR×ÎIb±ÐÌOjÊø›‹ë”œUicá×,†´}‚C:ó?Ô÷YÈI½WÜ}Ûˆ<ùBŸ6»WYo>‹ù¦XÝwy8µ|á7UÖMѳKé§÷qò‘Ti:Ö5Uqv6 ¥%=îEÝ+ã3·ÖCR×@m—ä9bŽ—F‰0Á€×Šò±YKÇ(GÀtÒ¯P]ER¥&SózxÝF“dúóŒ=Àâ߃ÃI|”FF–Îá¸e¥‘M0ÑͺŸn.îW^Q °.©] IjUÝCBˆ¸…n1/ýw»×D䢉ì}ÄÞ%¯Ì[Ú×ÿ+H&pK'V¾W/S/1c›õBküŠqN‚Ú"úd¹Fì* äO¤J V£†t2E3»Ú ¯©æFתˆe‡Ê× %s+'—;ÊÅ Ù#Ç»Ì{[ ÔÑÄRš]‚Ö õ®wÅnÇ~Q-T‡° ZOˆy=I¨p‡°»y£uÜÏ®ð.ÏNU}lÚ!ùÞ^Å¥ÙªŽîäáCïrnïú’b\Z©$¸>243Ÿ¨(¶Ì)߉—#ººOæ(êÅد ‰ÀUÕ¦¢½þñ2-æ²ÇŠ_ ÐJâ2ƒX?_C<¬²]Öþ ðo-¬ÈÓUy B»Çº^ŠC _µØ¼âôˆª&’¥9§™aÝÕäz¹¬}b°«ôÌõžÅj·0p·–ˆV¦=NGæšÃ6£B&Jw×$ô“ÈIÐü¦ËF4ÏQÎm|‰l„…°woŒL•à,²±ŒH›OZPÉ.2Fµ&WPlC"¹¸±Š'TÞÍû$yphfRqB±'O¼ïé…cd‘k^$ÓŒ£éºüv2Ó§ú¾WëB·í~Ö·ÏKŠL°Õ±³ée:¦h%ÒUëá³zÑ|åßâãÅAu𺺠×1ïBžŽ6«¦ûƒá«çùõn ¸ý]ÃÒ̳I+܃î[×Z`"Ñ•Ú¶Ý÷tbÙ«}Œ*Ü$›N rfhK&Ï))iŽ0s“ÿƒµÛÄ.“Õ£¼r“´WÙÊóØSfYŸÏd*¢×³™£r<—4À´¸¹ ˆgVÛTxÁ8d5Ÿñ6R‘ ÿrâe¸$§Y¯aQ«Ø$P‚ ó²Ÿ6'yTÎBL¸.}eå,'fúS‰ýyW2” sg®Ëó 5ÎfrБÜ]u©2ÔBöôT›ä¥èÈ“eKêæ@Mff›éÁ«» ð€5³ë ê ±išè€Ôö8kæ'šÜzrã4l‰ö›¶#N-VÙÍÓ¢¶lɈ±aÙ­ö³ˆuÅëuUÕñD„Ö­2Ê‚`½ÍÝqfά¡¹²ƒ,%œ6MÐ Ï˨KmnýÈ8vYLÁá<}GA Ðc‹¦)¥„^·>φֶ¦Î°ÈD±Sƒb >_‡%TU¨÷'kf}7ë_¶ÕÌž¬/¸·VûçånNT'õÝö½ïí w‚™¯Œ'Uµ°#]¢E¹Øp?q€ýVBR@(!Ää”¶;…W46ƒBÉpÝñÀÈçôúD¢§QZ¢Ûɵ¥û9¤U¾fÁƆEÓñ`.‘âÀÌ‘\ZS×{6Þ¹èY~&,÷M-(XÿЋÙËê,I×ÖÛIv;ƒ™fœÉF\Íè4²!‰>?]†[ìm…¿ˆŒÍÞh¦"¾•ž!Ë2L^Ï1Ã*lyÌy/)ÖJÞÒògቻ_Ú˜‘$öI`©òÏ€ýBÎ8áXêd@r k÷©3°ä낊?r5{x=çh=j~ÆÓaœš­¶ÔB|f; º”;‘ÜäøýSdM½´ÓÙwû…?Á˜ª~qíD¸Ï·¥j?lh þÆóA6©ÚcR¬åy{ªþ ST=4„z™UL–t|BGº2çÞùÙ)'ñÄ-}ÐÕ,ºa‰ īڵcvßÙG|ØíYº„#¸f*J—fFMÕ¢fCn=ãôˆO´-…¾¹1½Sœ¦•|õU<ƒAF‹ÕpÑ–RÞWÅSMŸQä(S™y‡¡etè ‹2c.Êem©êµ@«ßQ²"Œ<à 61Ñ¥Vñ]XŒWœý²îDœ5|•Juôž¾ÕS´ÓaFÌÚmþW·UЮA*=c $j;±¾pVDúlC¶U~êÐo;å?q"H*»(rŠvJQ¬2I):<$CC°Vm¥5mѨO‘é‰l~ËxŸñ•'\%‘CIQémË@žU“_Ý}$ÒCp2‹Ç.!¨ÕÅ,¿`6 ž»–+xôà‹³€žE'ºóþÁ¢(Þoç‰RÚú,Êð!Ö0ÜíHAÎuDzÈÑb#«ˆÊÑ®©sÁ¤„’êÈàJ«§C±+e”‹ݘ 1v; ® b-u‘G@exm Umì(ôrl1ö-SÕËDíÅ-×<†:ñ+¼Ð!ÊÀ=È‚{DÅñ©zø¬ª®gV_§ªÄX/<_yš&R`P¸Ƭî` Œƒ¨Iã'˜8ØN´)ê`´?B4ÔÅêÝ…Øëªb]`šë|ˆ¾ˆã*(¤¶óivæ,{7aÒ »Ëk'É ?Çx9*EG¯ÌSM M¯¹JxÍ}3ë0¦¸Ù*-‰¸Ñ G+£¢ºó¹ù*pº!iˆÀ—ÒñÈ J }B]ØûÁ‹Vk[Æèݧs¶t]`¿iV;E‘'€#‹” È×_{^%Ò"Ù@0šB›Œ½·žñÕÂIãüL|ÛxREy_è˦r˜ŽhŽ#« %iþ!&‘ãÁÒÖ†ã©1sWHÖ=àbˆ‹hcÆ\IäÈÅ®6±ÛxMŸ4Ú%¯ÿðœdsº€ê XÐ]!Ì1àõlFÚ¬Ç#·neÂT¾Âšöÿœ ²‹n®®Df§˜VIÿµöíúÃûŒºF 1%¹§ë†>u?ï)êXRµÒ`äºÖ †bnœæÃ.UF-T=@ª<ò+U+‡ŠY‡¯’ê7¡‹FåÃС¢RÁm.Þ êŠXÏÑñ ’a±+²Ü É.¬Lƒr{ .B_ {Šá3Ïs4ZÅÍÜ{Blh¤3ïo¹|Ã4ÎüúcR³Ë|'GEØ` ØocEü?é‹VýVÎâ#¦ -tÁÀ) ºFéA=8eD59ÙÓá%DYy†$'ݦ8‡Fn•«ûóS%ÃÆ/›ôvåsšu}NH”Ëã"áf¦ †áºF“Cdæt}J±«ƒ(žéš<Êø&ÖäŽ2PjŸ* ƒËŸ™ÁL3ƒ‡E¦º¹Q-ÒÊšAÅ΢VÜÉÍSF°ú˜õÃÕ8¢®²¯["‚ñ‹ìŠbIÜ Yµ„­³*E¼üíùžË髆HÐñÊݪCúEvhI `•^q÷o²J×ÕÑûòÉ"À"¸ÍJR¾Ë' 1èǚŋ¸™OC¿.X6#›}ÑôZn“Ü÷EÕOãªÆ{é.3¾,óÅ·îtÙDç sV‚#¼tÜb±€\ úý…§=³R™¯Ž^ "÷½Üa*>ÄÙ@ZTsw«Ë6“:)ÖÛ U_ñ¨«o¨À›=›4I×[¨Ûa;󼜣üw†[I²Î ƒX‡hf„›Ž=ÜŒŽá{¡óXŸ8«IBðÔ`ÜŒý F1ÖŒŒ/ŠwìVÞ•r~Ð)žóm¸‘!Ñ>aœ"ñX¿Á¨âX+F±Gd$wñq³á wŽ ¯¸ã-€½k¯€mG¢ mŒ•4{ 5’o„!œJ€Z¾b̰͌˜…T«Ý|¸:ÍÐŒwõÁ7I6ëu*­ ïEƒÛ‚HTÛàƒŠfn„ˆqóhõ!UÄ ËWž0$Ó± O3Ö æ ¨®œÕ¬²A M„9³2%šä°à,1 u¡´cî) ÓZQõº² ¸JlNH8Vfðî˜ÓÉ$ÈÇqm‘åó/¡šN²]ˆÙÝ‚g 0w1ížeiæô õ ð F-.XÿÎr ®.Ý®ÚeXLç£.¨¹ÉžÔv m\ȶ¹ä]ãbtݽ0;útnÄOS)úVà­ÎŠkæçï8ð÷]Ï…ÕÝï@fn#€¡¼,Ë’=s’䢰%‡ @EÀ^y…Ub[vN_°„(¢aíC‡a ô#2ë¼ ú¡ë Ü†ß©u¿GÖm†íGÕ´¼áAu~Ma¸T]|&o Գĺ€Ø!?ƒ±TC¨îò#ÂU5x²*bŸØÉX$l¬=–¼s½hXÂav7Äz-nìI`&:dU¶€ôÂfÃɧÛã„›•7Ä•"2víWd¤PV(²R€È¶–º+Je¹Ù„ׄ¤é©Õády}- ¯U’ûMi«FölðKòÅ•pfeª¡“¦•ך®HÜ6$¿áGc)³ú“ùL õ÷|qM•:q+ƒ,®í3%.b¨˜†TGD\®©Íûž^7±b«Ä¶ço¼‚'‘Òí8uóiɵrvÊÞ·€Âf2p\b‡ ¼S Jqý†ï?d]ýöêVÓŸbCvÑÈ}™ ŠþBXÀÜøp·@œNknbó#ùý ÞDl¥ÓKðB¦¤û0ËsÊêÃÏòi9[¦¦úÞ2”>(“LC½8½õ„Ü2ôQ@ÔX-ãÒ ¬Gð9”4 PT]7ûŒâ¯¢VçPK¢;ù¦i{Î|^™ÿsàkªC~é޽¡÷™êÝ 8¯ÖÕ3çU*vðN8ÏF‡¦’œÏ²©ž6í¬@ÏO3#à{³È¤Ò©V) ý R³ii.:ù°?…iGHÑo¬RA>–hd3Ø|ˆž1jà \p?Coá,}H4§á¾|çu¦ —-%ñïb¯ã%)ž¦tä$a$Â=»˜PÌvU0È2RXÛ5(œ ï¤åB'7Ø®¬ã»1ü ~]rË%ù;h}S¼NëÔ™0Žk¹*Ù1bv^‡ÌÁö8.ç] CÊÇC…0Cž)¦±¢˜Y&ÎfÃ-‹†y[aˆüá’>5qkÂÈkúhÅë‡íE ÄUO š†|l]•ÛöÎ:íSJ‘k•*@΄Z¾niÁ)ç|U‰ð©œࢰ<æœn/×@‹a)é4CWPZ¬ÜEW^žC›-‡«zæûEÁ3й𘭲Æ^§ÖÈšTR²·“4{FJ¬ÂáL²G©Á#(_§“å¶Œ{¼Ü„äv®`§±i&oÅ” ¦ýŠXC8J~Ñ6fFðäI˜T÷ƒ‚ñúdŽÚäÇ—üÇ€WÊ÷l€¦Q=£Ñ!È´dx“+ÚÐÌ›Ê;3ü}å¹”¥ûGå ߉à6ÑwïœÑËå}‡‘‰¸Š )R!š>RðN× ›Îq˜m>ÁÙŠ.úÓè]¯£Cý Á2¶9zÚ1S7-HóøÕeJ`oV1ojàcÁò d:íduÎ@¼ 4¹Î©:Ô†‘-À0¤qÏoÈ.PWê«E9x˜±£4¸”9È?ÊÓd#~‘µä€ˆêê³€ÃØ—5Çœ“d˜]dÖ»´L`Ÿ:$tÒR² 7ßu+,cMÅ:'…uvRð!}·UÛ‰ÓØ/M–ó¥_\ïãív)=Z3 “ ‘M­žÝPš˜ùÊ©¹ÖN\QÙŸ¹óêš(ÂðŽdk' ;89Œåã·Ói´º"^²©³¬¾Qãe®w‹=™á ÝÎíñAš0:r*}ÖÝñÖ«ígðNzk /kgUÒ–Îu½ÖÈUsßì"vµ½Ú}qœüç™lÑú¹xT¢w3>ÞáW'b¥ruAw,;"¥3ÿ2‰'¨à;5—ì$1ÄÓ¨ã+OŒ´Û =ð,T”Ÿæ¨ã¨Ø^6Dò^áÀ£]O°°çGmhöÏv ¢ è½y­æÙŸÌQr°½BÅ–©‡µ?¤tã?„pe^zr@©v„;n"-¸Õd=Ù:Ún'“ þ÷>ÿû€ÿ}Èÿ>âó¿ßð¿ß¿K"ݶtlÉ‘W™|wa¬¡·üQf«b´Ûuå›´cjÚ߯“Ê÷6Íâˆrè™>b,9Rû(¡tU‡ò¾æ¸yßC§òIp–j6KÏK¿ôò‚ø}lpÐOVM5Ës3çæØÂ“Ò…=“ç÷˜0-Y¨—[€ÕêEM÷C™u-¢Š‡hNB¼Ê“‹Á88kkŒ”w^g%Š¢A>«˜~\ÑO¾ñµë w×Ê t{@ëHŽŽâ”'¼³¡nœÉï1&øÚ~~‘÷çY–gÃ>Å^Ôy†=XÿæÑ#«ZÿôË_WÝ»&ÝñjDÈð9U†]ò„±Ò0‰-a-¯¬°= ê—BµéN‰â¨,ØßC.š*пОfBqºmº”v’àë =ÕUÎO±¬ßùŽ’u“N¸ḃ%ûÀ7¸¾¨nc³'×,ב’K\&Ĉx+(â9d¥è2¦‰]¨Žß_Ip„‹(¨ ‡FÈØÙ°+¶}çúÛ Ô|ëýÍ×rô|4ÌKó¬i¶R+°¯+¸È·ÄÏxOü°›â^Ÿ>ûmñ“î‹{cüÀA/¾5ºóï}e)?öî¸ðöø±÷Ç[Ü?¼³ST7:˜œV9 ’zÔ™HÝÜy7 ORÑ[ÈG¾ .fsß …ý.ò²k®ã2¦fÎÇÝO±Üó¦'¸™ÖÚI¥½÷^ïìU¨òµ¹Ä7É:ˆ® ¶‚È â*ˆª ¦¢ˆZ³YLdd¼TZ73¼V.U®•K-+æ¶<4-+Âo8ID²ùÌ­4æÄa…/FÝ©|¡@ ¢ƒ{?Wz|°s°Éq€LøeFN'^}X¿åÌ„“à%©óÖëŸ<ý|oÑ—[çÓ—žvA‰¬q_Cú¡4ìËñ\6BÜÁ$¡ª5 `5êDh{­§½-Y~é’‚¦Ùòr ‚4×ãÄ Œ8CwbÛŠíâP ª¯-Gf‹6õÇk[ÐäÅ6ÿh‚yäˆQóã³9Í¿á!BÍtÌP’§™u5èÛ ŒAUþ&¥cÛm›î‘véëZ²}˜2‹gaeäÖ)+$É©n´*²*/3$éÑL‰ýƒãzEZÛ#Ùp ZÌ_ F &ÕiqYÆàÄà«Y3`8Ȱ֤övw %ù`«DCªkîl€Áв5$1{Á4rÄ4»œæÒ-"³ ¨]!ž F‚Ñ$Š ûŒh9Àdå.• `oV§,&Êu@§mº1ÉÒˆÀ_Â¥Å^¨ŠÊ÷Õ;Ž?{åwÆöÎÝxŸŒYw8µÜb¨h­JÎeìuÁ Û°íïpŸàí†å Ö7·Óûž¼¨ž“ƒã-û Êú»£Õ«[wfXÏjU¾ #¶‹ ¬çßU2–\¶Ùe747Ü'Ê ¯ž©DCf)bV;øÖ¨Woç*·Lmø]DÃÖe–Îg’R³z¶ù8GFò0éçR<½–¼‡kæ#¡ggF Qn\[gj¶Ãâ”Ð[ ±søŸÀQ×Ií¢f”UÙØŠP„hËùT’O3²"jš¬‘C–ú¤IƒøZzD33Ûi$ÎR#õºÃDͱ﹋¹¦³¼65LU5NÅNý¸¯¦`² ÛïJSOÓvœðN˜ZíS½m~°HvÄõ¬¿µáÄDœaÕ¦£A`^ªfÕÐÁ Âö€…Z :n™êxmѧVE©Ø>ÛNô³‰N„ˆ¿ÊžZÎ}©­Á6¤Ë7O²3œFôã:ï#A6N{fØtº ÍHž‰S>¦È`I¾å_et®2©B±OúúnL4†F*Ç癇M‘bÆz®‡fóqŠ[–²ÁlÕ¤V(Óc²ñ>»š9fªåXÖs»zp¿Š €[\äż^Ô¦ï0›&Àn;w½8¿xNá ·Ò•fÁçM‚ï²Ñ8Ëúê-©Ó’~_<.-!!07$Ì0óÎÉM<ôÁNiA¥:œ 0¹õ0•9ÐµÏæ=í¸“,ŸªB«¦Ö쯢9à£D&_p8ll9²Ž%. •èrœyÓäs!lmçvKÇ´^Z€ew“ÓÛÿPþަÆÃð®[Ìëÿî›ÁCBñÄ&: Â"ú ¡¹U:’Pпkëbt¦c9üѽ¼xVÎü."(J<ゾ:#ê\cæf¹¹ & PÄ‚µ 3œó¢ØÃ­"žä6Oªsg!sÇÅðÙŠÜÄÔ6$)kdc›û×OÌxˆ… ß sÚdÂÚ¤:áFÔŽE­õGñWÁðo%Ó—QsÓÆ<‹ÎLRxÑ]@QàÊW¯¦ DΙ\Ãz­O œ Éu0#·Pîžäø¸j8AæøÎè.‘ºÚÀ&Á¨pœŒ~ h¥ãóØ\¹;¬Z|ÅÂPU{âàhÝfÓ®ƒ lBCi½ØëÖa…Gó|ZÌ'˜ ÿ¼ÅÇ"Ä|ÛTwKåd£H;.¼·¶ˆîjýàP*¶`âü»€Õ,h÷æÇž<>/&ín£¢K|:R ë³%(·ôîÈ·;§«óáóƇöÏž•îüý˜ElJð£6ϲIe$D6óÄQœµcq®’Y€‘Ž5ù.iX{|²ižzÆ`ó”h餤×a–ž±•R£°èÐJKFÔRÂ.`NU™'z³cˆ}NïWHT ö\ãé0—„fø³-$rÖ'¥§«ÃüùÏã¥ß’Êæ#7&ÖÐ…ìʲ´è!8éa×¢‚¥ QÒƒ¥¤i5Ô…C,@¥$Sóq DsAÈ”@¦g‡.xmAù|•¤†¼Âã‘Láj‚dâw~¿ÏƒàuÅ‚ú¿ÄÉ…ùÞí¿V ÀŽ-–q™'ÙÝ‘j`D$岩§Y™¯ÔôÖ¸Ë~Gø°)i§~âÄ¡|Ãc-¥{Ç|ÄÍrÂ6 ¨WM†åмNáòIÞvÚÌ˸BÝxQrX³zºQÑŸAGYœèëÐÁ@™/¸Qs™ ÿP[Ãw©}eÞ›­ƒ‹¢ü}‡"ò|ý,á: NʯµíM:™\}ã… 2§ê:K¸C*¢ÖV¿Ÿ,¡XÅ–H¸($p”¥ÍuýQA®–rføi:$”uÓšsavùOÖPj]š—ÀÏ•Hî}Mž/õ">òV° ¿ýp¨z£ÝeA = ÔL ò¨&›ÖF½ÔNæÓaSU¿êªeþ¨ÆÑW•eΓ߅D-k°Õ H‰WÅlæ³Hq]Ç6Ì—Kš«JøÚGøkh__àXµ³wt¼·¿}Üt>4ßë0`K-…ÆòF¸ƒ1:H>IðãIÃVÙ´ž2Ï<!¯s™³8Ï€(vÆ’Eº¼.!ªGtš}BTjÕ¯,\—>Ãã¬lzÇ•àëHõÆdšÒéõ Y¥Íƒ2ƒÜîîQ„O»¾ƒ¹Dš¨ÁNC•×[g¹u6üy½å‰•¾r‘ˆ«¢WG·,æÓ^VYhWþ qÉœÔÄN›Ë=/(ÁÖõÓ‚ñ3>5Ï”@çaÉU1`?ª…TVɬ¾’s'2OAÕLU–¸Þ'Ì´Ì}î…l³52€ýÐÖ>`:ÚÉ·x "‰ÔõÀÂT|•d°ƒõ¦²x'K‡Œ/¢5ýtób &¤(>FÐcÉšLÎ5A– ™Å¨½2Áž3Q§Eé ¤ˆ³i“S²Æ#÷âшÜ÷PÆ+]Ÿ„® Û²û€ØÂ«/GrÛFÎs#dO{ç×oî œÅµI¿¸k•®yóñ,'Çä)µxËæ Ç‘?øneÅHÚk(¸°È`py1òÓÀ;Ãï%»|R‹— )cà˜cØr2¸A§:ޡǺxã&—Tl9PÐ9ŒÞ(jO<ºITÞyuj³Á©—ç6JÃîÕ^äµ&ßïd¥ÍýÊçüW”æÊ‚hå¶Ík o“Û£ðTˆ±¸tÔXÂä³ÈüþŒE@´,Ò”u¤]&ö2ºU1®xÛÛÃçºdÝYå¤zò‘ËíÆQ½þRû_²k}—#S´µ`ÛÄC WÆT1— IAKBb׊³Bû®M‰¨(Ýt\.ʼLÓ䉤Œð”A$iBÖŸ3vj;ÆXä¡»3kpWÐL˜j:V0¢Wp\k+ øð›Ôk¼ R ?Ià…Í*j-Å^j”0†¹‚‚2>ß3¢Ñ£˜#‹N±’ñÉ Q ÚD ºØ²!"Ý]%0Ÿ(éÈuI?î' â iÓn[îq>T‰6i†Õ:Eb«Î)›îTjý‹][`ÔOÔïV3PE,âp¨‹0[~¤î-ø¤Êõå ¯ ¹$}±8eJ IPfA/± ÎqØPÝúkÕŸõ%JܼÉ{KÔ$â»mïVä»Ñ&o¥J$ÕÅ—:Á¬Økž oñï´K*·BYØä‘D><ùf–¨ðö¸% è¶rnñ2´1C…˜åƒµðÆ©ôyHc³¬<Âif !›G0ðhŸ— fwaõï-Vþ ,,a¹°újèêò•áêŽÓSÞîÀpÀPøq§–mŠ·Ó*JÌ·$6ߌ'R…†?¥C'Ï™—ÚbÉŽ&èÞhêl’Ëøs­ƒ Ì:ñãüRÖÖÖ=•D<Û5ƒîèptd‚«íõ`´î1ax>#<6øãd ™ŠØc<6™øúë'ê›…¢î<·éQèPCõ„<¯'œ"ÕÃ;»/¶Þ¾:î¾:ØÞzÕ=Þ:úK$féÇs™ÕcÊEßçíêá^Mœ4£7ÊKГ_îÐGS+Òßè½üÄkù6PÖ° †¦JU-i‹—]X³G-Ц;Æܦlj"tµ\Ýp>§€?•ز; ~zçkÂãBËAì°žè­uB{ÓÌ,aFSòaø±¦ 9TNwØÇ‚²=êxžö‰` oJér#îV‰ Ž«pBfïÈ1—7Ñ…žTXÕÚm¬ jù4fÅ«åïÈŰŸý›/ýcø’šWÓM›‰‡Öšj±Ê“|®ôÙ9T:€ _ª *'ÒÓš£N ]ÛñlþAÌ»Ê#tßìý'Ö~þK$–:Ø­Õoµõ!KóGnHj„Ä1±²ܸÐÃ݈‘$wâSöVÇ ¢y³‘œìRÇdD|¦Ë5çäaP‚i6$4-ŒŒqnvÞ]ÓGØÖÞ+››½ìV³LnF…:í”~ÜO ¬+ã<È®¦¦º ŸÐU›Sbè'nžƒ§÷wá[;÷›Ö8÷°­§á£Ù­.48)Í@Õì¤ß®Õ:*,ê„¶ÓÜb.ºsOÖë{â”*Üm¯G6ƒ°¨TÐýŽÚ“À#bñ,Y¦v÷¹êxWa@êN9ô#À€ƒ yŒ3o´COõ¹g½I!÷l™X%3Ë/9Ï´Ÿ—p?ò—?/„³qÅàô3>g—ëXåt~ÏÆÚ¶ßÚÖ]õaû÷y™+qÁég­ŠëML³˜¬8/ý²¢ðoë¨c*>^<ÊÛEÓ™P<[óÙr/5ƒÓê;*ùTÛÉåcëõÄ©ÂM~þ‰Ä&ªº£óÙ U5HÌ‚D\Õ%z ŠVBšÝ.ÔV²ƒ~HÄmVXP¦„AÃ<µ;Î;‰ŠAQÈ—•9p‡ìì "4ØµŠ¼iúÉd¹ËÒ)ŸXõÏ€rлt휤S‰Æ…¼ëõ»$Å Ê®²žášÖ[ ¶¦ffµ9Â|5¥–h“ÜBÉ*áñšîËÝã“Æo ›åû.»Œì‡5ÔS {Q(_µ¡Ëª‹X¹„Б;j,Kyî3û‰Î1D5¸wuÛ¬æÃ@Ï OOœ3›§àÆ2k6~,FØâÝ5ÆÂÑ™‡U[”°ftã‚G‚ ^ƒ€éò‚Ö\‰mÓ`k²ˆ”qÑ[•¨ž¸žX èa´t@«z!n³Ô £`¡4v„1¢ õÐT” T’ínõ(¡Ît„`æj£ó›ÓÛÁä“EÛL0éçñj;J¬¶£ê+Ø#®a‡hEÔÕøášÝé(±¦Án§×+üÂ…M F8žU¶bsРG‡Þ‚R9MÕe>ì÷Òiß*™Ý¬8(’N£SrPüÌâð¬¢â€‡ˆ¡Á!Ü ‚ ÞöwwgŠ f‘kšgÌTÝB¸¾»ñ¤›,bq× ¹ÀG·‰ŸOûÛòí"î[ʋǿÅu:²]¹Ðl/ ¢Ö5cÁYÉ£°·wÙu›iôkfãîµÎŒKèŠ'¤ø Á%©Vü-Bʈy>x¦P84Ú£ŠÁõô#Õ„?z;ŠÀÇqdŽXŽ𤵱J2Ô¨qؘÁHéâZ¸O¶9©ÕBﻌHÅçQöò€»£ÿ`søØ­kïSÏÏëô8¦L³êAœ«(v8Êš"¨¸´cË­¶Tö¿ì 3"ù†Y<Å´e3·Ùüir±"é¾fK:êù" Ì^Ù4¢Ð°hG¿"ÅãÞ‘§…â·aÂê5óÔ´„ÌÂ@­€üùeœA(ã,”‘¹H¬‡.8Ú¿6Jš"0#æûŠñ®¹’ª&+(ßûE¬G>ÉÜŽå+ë⪲×ÀZAH#…óïå ¸©f1˜½ºsÒû ŽK’‹¡¹¾"µ U°ÉÂ&âAln{/`Æ3ˆ¡ô»¢@rZ,k1µñœUN0©F±z%ú)oµ¿ßÜÜÝp« ?þBA2«-JÁI1iª9¬I§§ ¢º¬HúùwV-àhÈRr ’p™‹÷Ë»;'¬xØø(z*äã6.æ°bÀ'­-HNhxÈwœHÊùhÀÞ¶ gâY¾B„S}6‘¹›¹E´Ëk¿¤R Ý©M²ÀÒý”Õª‰‰+ÂTßp‡ú H?Zñm6ãu^pèá§ý“%r+ðJÖ©ñ¶°Èß=¬Ÿ8vCÓ³WŽ¿£‰Q9ÀBH5z#Ü®ê/T…öíü™Ð3?f¦Bʤ<~_ö*ºf)óV,%M¸þŠÅCåú8ÌRÒµ`_þQ(0¬ùwAA±9&¸ÅTw×Üê„;³ÿ¯W,šñX•€$Í:† éYãê›Ãz¨ÜXTú™Ë/;ÍFü4‹[žÏgà,nq`› Ó¨ÉøÌÝÞ )¼ÚàÒÀËŒ{b8.ø“9 °€^0ç0 JÊ G#ônGMÞi·€Ì²:´K{ºÀKֆЄ HóWYÖ?×Í„aó0k™ão>”ëšp V:þ q!™@úZAçó^ŒÅ~¸ ®ßßÜ‚fl®WÞ#§‰2sâqØV€£'‰oZS2š-ÂI *jÑUtÀÙ^ó‰hÖ™œO`¶ó1T0„_]fÉØ^ÂÂCpdŠ5@ïÌa• ÏD CžjU­¶ 5¨mþÓ#eã¬(_äFdMªs‘Ÿe(ZPЉ¡¥’ Èÿqcä3Íñ‡ÉÆFüô³! ¹@—®j„'[#[ K æÁ¬XeÒ ˜èF;Üž§¢Þ+ÀÁœÐçy ¦Ëá=kùp2‹5 qh>+FÀÏ àLòI_É9йgû¬hVºôÄ*`¾öT\9ZºtÐ6 ÑßÈü ª.ƒÎkªãJS žF4Œñ#m?ó‚ïd‚ÇöºtfæàÔ [[ß•Nú¡‚ÔÃm¤+K=йEkTk#Š1âmZb uˆÒö-G·D¯‚ž|\LGé!ƒrÔ¢ÆÒR… :ñ¬.nP¸»µ=¯**xšºœèÞ‹äkiÍÞô¸† SÈ@0² ÎiÁ;Ó$ÅZtÑ¢"Púl[± PuŠòqAIt 3ƒ7ªAH1Gì¹ð|8ËÉGþn'G‡ÇÝý·¯w÷¶Ûz Uí¡šæªñ2âs˜Ý,Æ«[/ñ¨¢±[®¸­í¤772ДˆíÄx"A»>§Ýx‰NqAÇ«K~åb-Ø»ð…Àšæ ¨b9³qÏ‚¡WSæ5óí 6 ºJ A‚K†õLegªDs(åÉopìê—–Öiªç¤ú º§> LC‘ï}þ¤úí¤nR&Á¤¼§S/v´¿À“ð{&è§ö]hŸ#a×']Œ *pTé›ÓG(Í*`>Lo6„~BÛËã„ʧS’‘W„óúŠó–7ðH×I›¨(=GE’ަŽb5\…Í/ÄE¥ÒêØ ÓY;Рáïõ{t4t*6)`ô‡ISëá$o–7]-ÎÏE„ Шƒêg©Íóõè·:±z°1wÕ Y£*Ñ¥¼G= *¼Hé&œÕÐÏ^áL-ÍFÓ­ê^1i"á½\pÛd]†CÂHLirYLßy^!fÉ ¾ö²,Ës6LönäÖ¬²ßÈÙ 665C²)q½}³³u¼ëSÉÑîqâ¯ðmÇûA/kéHéi}˜+.Ýö9u °Û(£ñ5Ý+»sØ¢Ïr,ÉY¡ïÈëPKçnôº_sáÀ´³Kù•ÜVp.ðpuFÏ=dähf„ðSa@t˜ë·4@°3pªTYTÙ(çÐ<™Ÿ0Ë-˜¦ÙŠ ,í“9½V²Ÿ ³'hü°ÍI»‘¾g?¢Ü¨ZeË!‡‘OK0Û¤Ã@ ·ll|®D\¶¤L)É-ì= §>;Gª™^c‹AÝ3Äà§ßá¤#N?Ìùt㦞ÃebÀ¤áœ µ‹îPeª©ÎàmâY=Ç $úri9êGìP†: Ã8éŽqåᨘЖ^yl–5õOxÙÊE ´L Рѹ¿êº i¨Ç¨D/àÇ’JTq²7ffº]RÌŠÙŒa6·ìói: š+—®ÈÞ¡V}}¡ç{`ÅI¹Aá®Ð±s Ÿa¥S~[h¶WÌu•ì¼- ’†SÑ|OæS·Ìû9Ñ´9‰Ý1o&ÅWŠÊZ›;+5Ka-$ÇeãPªÄÏ¢Svô3zsšÞºiÕËR‘,‰«âÝrê /®¥£Ø QûئÃ.•÷„᪡²zy¢ªŒ+äõf="TÐ;l> ¾K/Anx ‡C†Q`#@©œÓk«P¤Šsƒx—rß%j ì›ôÅŠJ4›¸¨›RA•IA‚ò`É\“÷69-Ò¨ó¿h•ã—>`•V¨ñÇøy;ù¾ÌŒÌH\ޤî2 ÿ9¢Ì¾˜¾“.D”Y½ü×ädDCָ̦3N° ‚õMT}¡w‚%&*ª${~Zö†”§p¯Ø@ê@Ç~#óp¥– zäæQà)Lµá×µ‡1nί”¤Þ|E»¬ªöâgYýb½ÐÐÊ,²´ÌA»`Â"9w¹ÉÕ)—sçÌyéSUìW"·ƒé;rE±’¦•tµr¹¦ZVJÕ®|èò´B p„“7ÍÈ%)QdžzŽÙ:Ë=¯¥}Ù¥mùƒ¶œUI«Zn£Q¯•õNýÂ!ƒ×èp%‚»ÉžõÐYè¹Ò*èŠäDµÏ‰8P°Y‡c%ôyœÝÞm?T5wGÙÏoÌú6Vº3 ºcˆ?k?&^?¨Z 6À¯€q^Dn£‹{D…W.²Ë—˜øøY²T#¸>‘–1—iMÁOêBüS6CmRŸ¹ª_„Ô(Á ëQù”‡ªÄŠxåŒ#®1%dÑ!ì1¢KµJít:ج+uæÜ½3 lÖóàYÃÐŒñ+’³:È„½Þ©ëžv}Šõ°*s辪ìòŽB=§þ€4$™¨zÚFH¹Ùt:)ÊàEcUé—ˆ¯Ûo÷›ŽA*Cp)޹øuãuh ÒÝe1} ß©6¡Z"ä€ù$á¡•q=gªOßµ·t=”m­.>ã¥@]“ªÀîv‰îÒ_<ó.5uzmñZèá½äBKq² P¤3tËÑyjý“Þ1VAÌr~¿ŒLÖKÇUv*»X€Ô ‘Й?û9$ÒËghCÖÖ;0âˆxèZŸm1á>¤Øªêž`dÂë|¨ß÷[ñ¸ÿqÛ‰£”½ý£ÝCÐøtbsUìBNÍEh$m+Ãæ".%'u[°òø9ñ²¶’âÛV2æ"ÚÅGr+ùëÖ«·»G¶Ÿ¤ü²^ÃOü~çÿü'ÞWúozßZ’Uš ι¨%ËÿX–º‘ÚÚq«KPƒs\yISv”’vâõËÆ ¨„ÓôÚ5iKK»¢cÐq¤Êg( ‚rºt éæ}%]ã$cÉV@¤žÜùº¾ŸkƒåèãiÞ'OŸ¹L;»oŽ„§_XO–&ËùT¹¦Ïk›çl]¾»«R¢¤cŒòîƒ{èu!éæÒ«|4iø“ZÕ …1Ä-šËÃ|”g÷"·W\I©©+È(]lµb%µS ¾ïÅʽ”|øu%H@Ð5sZ©ëkiOô™÷v­Øj*{Ä€§ ³x‚2TmºÝ‚>@q,ºmáöxYCqlìãÅr¹R¹1—ý¢ÎŒŠ,ÝQ‘r1#¯.ìšÚûk©Æm¥g9í:ÉÎܦÅDÉŒ¶(z¡#e¶!£#ŠTÓY~€$ˆ)†'„Ÿ·!›¿…oݣݣ£½ƒý-EÑôhmc½AH7¾AÜ3¥Ñm3bÜm†s¥¯¢QÛ•‹Ðž"Ž›†›=ÌH`ņR±]m{"Ft6< }‚$0ÖµÝFjâ±=G?¥“FãþH¨Ø×n7ô…{Û©gÛ• 1Û sü™²}xУ{Z*àR¬{£_ÒOÊNÖùÅdC~¸/?<Êä‡ÇòÃ7ò÷ªRï*¥¥ûHÔwò»gó‹Ak$Ý;Ë 1*h²,qI"dÙÞ‡p»!lè_îë_è_ê_é_ë_¾Ñ¿|4ü)ÍBYFY,àÅUîwT¸WÕí–"\Œiåô¹û‰ÂÜ«ÚÌ‚o¬ðµHÃïGþ‰ÜµÐ+±·ØÉ ,F$1½ÌáPΦ.´"j*«vlaèÔšhko 6  Ÿ×™¶ 2Í| $eïX)È% f¨ò€‹!8òM†rÇ$5·My±6«6xËæý%Ë&ìIwÏÄ—ÞL'c³ì“¼”pÑÞòVÒ!±ÈNÜ-‘]ÍõI£XÔPÝu#¬E¨—Å&—Œ:ˆ>~c´›n²DD’z-²™Ú_§pµ}ù?ѶÂ:÷è¬l&ݾ#™!+Àv5„?µém4¼§ýVçª&D“äX5ØVÍj9éÎ$ñªMΔ%Æ Ír€“Y~$D/¡•ýÂ/&’ÏŠSaCÝæg3k£M6áV»¸€ø•—l+ò@­~‡Ò¨QÄ÷™È¤I±c’ª$[ŒßŽ-L—îjh–j'¼HdRÕfbh޼àˆ-]ÙÅþXhiþ“8®6̱¿eÔÈY’0Ì)´˜¸“ØÜÔÍÆ¦\Ël3I%£z%Eé1ƒB.¥¢BõM“2~i¯‡ü¨sJ±¿Û‚jsЀhÝì€n¿VîA‹\û/Ȩ·¿Vïz‹Âzw0ÈÜ~6~ZïâúÐ *âbãÜß++F»È®XÅñÝݹQYû÷±ÙfÌKÇâðe¯:j™¢¡­6“jÐ@w¹ÊrvžRF"®w£m½ E+Š­]sdLŽÜÀ÷÷@Œ+ô¶Å¿„úA•š÷?Ù§(Êü†Ð#å÷lZpcQ6S«}U¾'¹ÈÔËä»aó.#Öfû¢bÞÃ=Ûsš¯êµÑòĩ˩-kƒÅʾì/Éí7m>äÔf£“|ýõrno†¦¶«®è_œMR¶dw !4vcRÁZÐܱ]ªó˜†î¢ w½EN8´­:ö<ÐV ¢¶{½êŸ7á†è¶„ò±³;Ñ']ž§`¿?Í0?Oqá°`…~Ù0ÆöÂædܬµhPG@ µŽü&@ ®EÙä%{g‘bš] lYÁù™ª¯`½‹–9ùû½»©ÎðõRÄÊïQ¿GÁáRý= >°Ô0EÚîDÂh$þ5iØnÛO¿VŸÛ^JlO“Ž9§üíWê÷ûÅMÜVÕšJ†Ž¹(“pÊ€žã#´j$úP›“í”­ÐË`†v‡óŽù²oÁž­.€j}îje¼ÖbÚ§´TPuàa@ª¾Í^eÄ9ç‡8„†ýÌûËiN;Oê+†˜±ÓFL¢Ñ 6VÂKGèé½B–|^¤’´,ók”Ê`Êô€ö\î†Ù:í`fÒ%ù¼Ì²Íä|6›l®®ö³‹ÎèºümØé£Õ~Ñ[fg£t¼ú°³¶šWiä|6ÚÑÐar”ƒ¢Ýjxj³ä9ò¾ÃR}­—Šü9j7¥W÷âBïröÕõ¸}µjÉÄMœ)–U/kwvµ6Ù·‹¬æ\±À¬í®Ëˆ¥a:‡ô{<"¡vªÅ'ÎG¨‚Û¼ë Ù’ìpyi}Ak‰½ÑF€|¨p$Ì;„;ÜMJ¿tÆ(Ña‘ÎÂèôáÃ’7&ˇ߶â ä,/RöALæèô#Îç›[bî"}Ü2¢µ;¨É zBévé(x±¾€gnµ6Â>ºfux.Âr^p:²²Ü4dW¿Y¦Üü°ôkh–‚j^òrç¾kÂEÄ I¸l,b²{[v–ÏŒ¼Q’À}†:ébäÒ±ZH‹¤ÌÂõ¥ÑbLFÖvQÍã:+ºæèYPà,Wùä–1vÔzÃZÑת‰Aã¯p.‹´¬•ºÄ¨Ö¹‘• êPÝm2Rdņ*`_Ò Bd³pQÓu©¬Ç3‹èáÌ[ËaZž£yÄï“uD2Ÿî^åˆñ9ñ~„SæÖ%q úwüy{)÷<Š)Ï<%E«ÀàƒR®mÅ¥õ+E©Ô¼~óãב¶«LV6CXú§«g Ϧsö¬öGÑš¢²e™ˆ¥“óIgœÍV € Ñ¡9læƒì&àïKýÍ{ÖKeswtq •üß/›7'éÊï[+ÿ§ûóÕ㳕Ÿ¯ÎÎ~á'k+ߪ‡n-[¬û6Oaæ£\)#'¿>Y¯ÀZÈ܃¨óD¿ðwÉÉò;àG ãr¥NE%÷´-wé$×½L/"šFСÈä¶ãŸ?ñ¿½C¯ûý‡š‹ŒÀ’N¥×øß‡0š4€6ÍŒmN7'ˆ†xj2>ž°º°2IVñœá$%.›!QgØ -,m5ºhÔ;̱ÕÔªÀ™ÔÔXmQµô¦›Â^·!P‚à³Ðe&}o|i—¤&9òü›gI²ž<} Wpæ’+†£EƒO±Õ³ÜãrtP¸ž×Æ(Q>ù¡2ϸ´·p}¶^nt5±S»®8›šÀ‹æ ëK›èp JþrÄ7ü7°ŒF²©|‚^½áFÖ5‡ïbuWʨڃp·$iTãÖ¢An‰Ê½ƒgñþÁáë­WˆéfKø¸SH«ú‰+§ oÌLÓsó=]Ü}‹®-BÿëÞÑÞ¯v»{ûÝw·v¶ß¾þ¡å6âß­uøèâ^÷h¿ZU¤ 锨ˆãgZa‡7ö³ôá¾Nìgu`_Þ{=¿µûƒ+¾‚X¼Bøïîp_öù ÁfoÍ b;§`k [PgÓ©9êW¼=ŒÒ7Ëd´w/õ‹A³a„Ð`¼ Ëï ú–œ¥9 é®G‚´d*C¡¯,÷Ò±9u[íä§­ãíw^vw}ôm%Ȳû2#‚ k•„1s?ÈUû2£!’4Î#q©œ:÷GÚ3ê`C49[“ &5Ó“Ï„w:'Ý…t^‚YÞ¯4)8Ê•ÈÜ~J«ýb ZJíÒä8•ʃ¥<&¼÷”º)±‰Ó‰:½œ´îÃÖ!36ïà¿•µ¯ü 9ok–üg½(¥:T,ç>$›ç£¡ê%Ï;÷8CmµèWN;§T§(xÌ価jñzRš/IŸ¢Åˆø¼ëÞÄÄÌx¯8§f‹± !,XÌ…MÒ‰ ’'Là ¦¤á>375¶"EÒ˜Âî1—]›h!§»´{Î\9ÎSÐQò>˜Rͧ¯sc4_aJ4Tf·t­³£´6êgJú€tå0ÑÞ*sËÁEdEª…¢«S)¦;Õ—Z¬R÷dËÚŽéR‰¾®¾HçÔÛÅ*]&i¹`Ï[«¾è, y¯d|Ha‘èL…ôP‚W‹g™|zÏq¥LÍ ‡å*ºuvc=<Ë µ´Ú/~SÓz«û@O>¬åD‚nâÍËë}HlàIì˻܃ܭävní&òÎÕæz6þÉ?:cû¹ ßœJåɇvðæÆÇ®'ö]X ›ÍKÈÑ:¬o÷NÕæãÙEº iuÑM 2áÔ WÈVÜ{‚½«ÁŸ¶à{qÏ¿%7´ÅÕS¿†™«Bc.‡}/Ê<ö\ ‘7x¢óE̹ñ5œ‹Ÿ÷÷qP‹ÛRÁ Eíið‘ÎÎjÙFàe]+yhbÌ;V@rʸ2/¨…IÇוUaY–æàA€¼¡YÃw±‡›«ÎÂèÝ,NÎű`ßÓÀ|ÿÙ:p¡)=œ¾œÏrðã9[æcº©ò%y÷SͲJÐ[WW˜¶Ìƒ¨rB¥áH¶îËÝã“Æo @>-%­g„Ürê_QÕzYß¹J¢ä±7‡M³^eF ¬Û[߆9 ooRJ {[CXFÌ|Ŷb&Ì.ÚkéLõ´0WCòÜ#¥Øe^z“…Ä9¢¤Ê¦wóÖiç§>j weõù*¶\± ¢ÿÂ`@N Ôkô;[Ší'ä<¦Ä!}b8˜ôyšý67ÔEB«ç©‹-Í1­ÐHÙ1‡²íÜÔoên¶ÜíwQοLàœ[nèON`=´_cµ¡ö™óÊ÷<ølÌÑC>e6¬ë¢ YÔ˜–͵5›Õ \9B±zÞ à/¢}ÃâԜȧ…$‹¾¶lZÐqÁrá²TðÉ”Á¥G¡©Íº«X0ý2™ÎÇcFgáuézð;e*fÔè‰B=È"Y!´˜HN$ÒºÀ5VAÄ;÷rÏ!åçÕŸ¿´¾Kš7¿aé¦=NGy/iæï†/a—‚d‘ÙÒA ù5þ«öétèÚ¢'9.ÉUGšY|ôªæF£Ú,^Ýð#Äcy¹˜º‡EƒMB§ó<ÝšP÷½Z¸`©m€0üne0ß'$fû£Ñ%"ÙÕ5Wøþ½9(1"ŤIVfÅ£"uzÃÐ=ÐG¸”+8û_Syªƒ¶­ Æ7W}Ôx¨ð{#9Ï ; ÎZ;«]HÇÚ\¦ñMu®°$¼ïÛbO¨ÔIÞ#ôKÓ•>,L~ýæ`5sù_Ó[:AÔMÔzÝý×+â|Dã÷M#Zöç=–…l”$}¡ô =\ó)Ö ɳe–´,ŽWŠzÅYÍ]6èdZ\– 2Ž÷€ÃþAKÒƒ$4(Má Òb‡‘¸4YA,®!€`”'m:câi&ô<ʺØLIãê¦h0[7ÎÛlÊósg» û±AdŠžPp¤‹!T÷¶ÌÎæ¹/oÍ óÑ6¤b¶¹)…éR93ô}½D‰¡«áĕI6¶®“Œ#”â]Û94eñ<“%©£õò·¡e[¦ï8á{[ÊtH÷¿)<é~·}˜ò0Ytb—„ð’г6:¤ÐÆÍ™®uÁw‡å³<Ãü(ұˎêNþïÖÊÿIW~‡âÎ/_ƒ|×ÏuÇ™5Žñ™¦ðÊ{š%[GÛ ìCp°øCÁgöÞ8›ÎÌ4N`§»Ý-p\6KÈ>ù_±€jê†AÝp=ÿŽË“ àžº£©XeY2~±ÆN¼ ROý KÏÉÃz™aÅf Y”¸æœdÀûƆwÉ}…˜QNåŽbn9¤Áû~:ä6è8 l$•þ67up´Šfc‚¾¹Xyì)h¶°âÎÅf¥ê¿zH€÷–åoäåâo†VdÇ‹5$3¼–É2ßÂ(Û.~$骞uáe3ÔŸº†hœÍeªÃm×™ h9ª¬N¸¶ ¥1•AW²³11´âeù6¿ƒy̤FøP~Á„&÷}iý÷ß³7)} lH€û™iè˜Âö—=©Í¦÷;¨‚Ê^=naÑÁë–žDʨ9sÊ•¡×†ÿ pæ>  ·zSû_Bâß-ç#P¡=ó#¦!¼oS˸4‡YäYÍG¥—@ÈC%ÀJ­Y"'ÑH9`{ÓŒsø$ìºÃ7µk(i«¢L+XŠ Óø ,¯ÕWž¯·O"É0 šw®­´Y–þnM™Lh=†AcÈSðL:ÆóÑi|…ç<ŸO‡Ù4¿'­$:S7Äq;…œGóqucµe¸Š4ä¼|;ˆgÁk+Ÿ÷19’¥7Pt€SÒ²LLjr•$ý¿œa Ü‹Fâ49>‚ëï&åÌèñu„Í£›l˜üÞŸ,ç¿8:…GõyÀ^ÑvÆ[WY|äXˆâ©ýYk̵ÉÓª qìI–P¬·;WW"WvÜvadø2Q;.‘{·PygwTÕ"oÕÐ=v\b°8Hô°W¡É1ºž¾¥M2X?Õ—]õ²ÉŒO}è§!L¤% X÷¬–+·NœVž–‰5“ë ;ìîþ×ÛÝ£cqøeÓAÖä5ø ä`äkæ_d¦ [ÕÆïîöÁÁ_öv1ˤÎò9}ù8[ £ÆoågfAÁ…ÌPPaÄ-ä˜ÔW Jq'BË…FÞÀxmæ¸%„ÕÜDöƒÎÖˆ%6Ó°y„ß™ë ¦Ñíý›nrðã…ëí)2X¢\¦«’ ‡£ó•–Žà¼'֯Ʌ>È¢ Íßh¥R„ï¼CAU‹GâlÿìP5{·n;$ÌŸk£ŠÒƒÚ ÙT.ƒ ”tÉ;ÝÜ LóñŒDÖØå>‹7L?'kž,éž:wSÇâ ¹Ž‡.BŒÃšY†:#3í½•y®Îoo¢&-íNG–§ §;®íKÒ\2D¾º“%¨q©^¦ µŸeE!V›* Dÿ­ÚA•KŸrÔzëÜ`fŠ6SD^»ô›g®ÀEš CìøÔ'edöÌ“8l9¥PÌ„ïs‘ª¤„ž‰÷ÿJÆ«ÿùä?û˜ €HPbùg1ÞbÿÛX7?¯¯=~ððÑ:üö¿ÇÖþmÿû#þøö¿êâ£p}Ã7îƒðá·›ßúFÀÕäõõѽʭ÷–Tæ FŒ0ÃÊøðu¹Hó!;;Tn4 âXE;|àÄ‚ÝDW%ùÜ¿W„Ø þÂHÎcsÜ4"Èe”ñ­ƒT„]ìç‡ôŒ/43s‡êR›ÍåùÔ\¿Z.çè0àΪ/¢Ã°iïªnfå¬Ù ™ðù,@x$ecøºOžfh-"Z˜ðŠpMŸÀú‘Nˬk~ÆNÚ Â;ZXÌ£ºŒÁÉN‡=ªý8éTf Òå­ÃuŸÏܲÍoýŒntê,ñÁDîã|v«‡p$‡ß˹ÐSs=E›£^s/V­˜ÓÝC?b;²g–ÜP×5}ÏOÌÁ=šjªoÚ^¯ÚÞ”´½a;ßbÕÀ?³Åð„n³ úúofå÷ºÛ¯öv÷»/Þîït~:²†3ŸÎ»†Æ…ÙÏŸÁF^C¿¨x È›±öàá-Ô÷‚âî H6 Út‘&Ýu“&L;üxšÁ0JÅ!”+ÞL¾D‚í<Ÿ?æÏ·¦Ô™ Ã)ü`ýÕzj¼¥‚&òÒ\ ¾{ºj>®T€ZWËõ$ë{uÙ.ÃbA¥‹êñ®Ä4F弯_®šq¼àôèFdN T‚ð4MΧÙÙ³%ÁîÄiîÓÁêØPâêÆÃo–žïÿ¤ÍF€ŠƒiŠjvHà}Zïž®¦Ï; µ‡î‘ï$vò’; s#ý¼M:¦1PªàÉÔðîÓá5éz3Z<:"’M‹‹,8ÎèBkƒwŽ*åSïîÆqàŽ˜\e6„=ª ™ËÎ-äë]o%Lj€Æe—ª/ Ò¶Mò’ŽÅ¢iw”ÔpÊщRìÍŒh‘â³»/Â8mOþQ»Ág!õ*Â¥CqAI;h¸ñ8STL’[¦®ïßd¿à åSßéb¶ö÷w·ö´Åm±}¸»u¼‹Ç'épÍ­”ž%Ç[?¼ÚºgÙ  s!„ƒyF: : mBî5¹‡úG>S ½–Å~AãS_Ü&‘¨3½†ì©î™xÍÅ-?t¾öš°Q á×_lFý­3€ÿ"ÄïÆ¿ÀÛ„l²Ä·ÀXÍÿôõ¥5«®/!`ùë«Q±"‹ü/°²’o‹íÿµ¶XÑÿôµ¥õЬíáÁ›`eÍ“zÙå_aa§ÅÄ_I\Û»­¥ùvBkIŸ~ÚZþs–Ò,[H™ÜÀXâK³"  È¡&]y’SÛÿ6ü‹ÿ©èÿËŒb¥?[ôÏíñ?kZ__ßX[{øøþÃGZ[7¥ý[ÿÿGüñõÿjñ)úçAg£óˆ”ÿë«ëëÉÚÚæÆ·›÷,ŒB+)×…w˜!z +ìsˆ¦±Êr(Ù-&ä ð?%§W@y§µV_XKP±£»”º&$õôc]ár(׎Ÿ0ݰím¨–F!ÊŒV_ ã0›aÑaˆÅé¯ÇÎ… £ØYë<äò|^ÚÒYŒ sj ‡ÓC®Üf`éÙ™a(dƒ¿T 0€ã ÊÄ&‚€Kð ˆQH+gèTŽ!!F".¤¼NÖ¿Y3#6É>cÉá!äˆ!cív@x1!>†[\³h4 È@A¹Ï“`ÉwˆgjæÁLŽé•bšÕ…å3V5ëŽ]Űít†Œ;‚O!AXfì¤9ˆ{LùDøÕà¡i„Ï¡xè; ÿ ˜Qj#‰öMýšRu §±Ç“(áäLœ6qÊ©bâVSHp°¿¯A–tÞ,ú‘Êa[ŠV¤Ü °a#„hˆ_ö[,Æü(¼rØû‚¸‘ ib*碖„d8ûEÞËV _fø®òíC&½).ñþp©.Itö—¦ÞÐ'¢Ç¥ÓùÓ'aŽ%ó üü]Þv㛵 ˆœDù¿¸öxª½* ¥ŽŠŽlϽg;»™&ãl€Q T 1ÂN""^9Ï(òÙ쬒,epû9 › ]FttÖøL3Ó`h‹ü¶é$ÜÁSÛ‡ãÛÎñÁÎÁ¦ù3Ä ™âš\fþäÒ$B»ØÎ=ßø–›„)DÓÑôKPä·e%ÀÆ<[m8â‘ܺ…»í8p,<ÆÓ5´C:ñ× Zi¶Ûe2‚MNì‘ÒRpƒJnLyÓ’,GnR9“K _Ÿží羓8œ—íV–À£·ãüJUA~óI‘s¾<"uœW¸uŸ.`‘<2z48p&´8t·¤O€N Ðe;.«Å••ú`i˜å•«ÿ¥öeO`\× ÇÆG³Ê`ÝÏp;}¶¨¤ëݳÄÜÝYÖ´*uõþ»„òoÒa³†ëöÁsÎÐ,1V•´ŸM6Â&Ûo÷w·’­#¦ºµ8b%êt]}‡´²ZÚ´bjx lÌŠRÈ*ÌõÛ½̲:Çz¼qYú ˆPBÜ–Mßi¼‹|?2çÌ»æ‹æ2ùïÞ6õò³„Ã÷®2؃»Øaëÿê÷¼¦ãsÝqE’ö…Ü‹§KV+YA¯;J¯äÛN†ét"Å|p®ŒÄ' ìŠzpUÀPò¹R¢ç…!¥k‹ã°F0}^'§dÉÞ•NÓņ5ˆ=icÕãLœÁf‰ßQ> ‹¤±þÍúƒkk†”·f$*±Œ@u|D†öŽª`Ú…wrªºî4¹F‘h[„Ãj­Õs¥ÅÄãpžõ;w'@·ÿžjÙd\»|O4.È¢ËJ"L-!¡,ÆAØ“ýå`¯c•³ PiŒ0`¦ï¼ Èבk1B°» aþü ÛŸ4“l ^Çè±Rà5‘Aû´x l° ÈM„*/çæÀ tXsæLàÉn†úºÎÊP#¨d•ÿ³”kàæ%ãê8)‚é¤ý»C£,ë†I 1í¤9ÍVZä«í>À°`Õp) ™+e½šA×rš™E»ÐÑÚM©1`)•ë1&¡dÄðJßK–uÁu‘Å+úØéeƒ/ø}=Ðôеþm.üãÿTìVy=”¿ ÿ€øŸG¯?ûßúÚ†a›ë!þçÑ£ãÿý!|û_uñÑ øè›ÎFç>›×W×'ëk¸¾Ð ¸#~¨S9ƒlxÙeØé›¢œ ¦YĽB̃R[o,ùþï^™Cô©P!³ ˜ž9aéy—\0äò |ˆ$ñm™/­¤Iç_äœC' œ Qii<˜f#2À§~i €A%¹~xá2)òÃ.€4¤Ó¬iK%lªx½·¿÷úíëî›—¦þ–‘¬ÕÅïáI£[>»ÆÞ’ÂÞáîkÁÔ‡O¢ßx€y›áü Ä05¦#ô0+ŠÄ\L;r}ç y©näî³/y$ÚÅ…á|DÇWÕ×C‡c¹à—å ‘ Xípit:ˆêrDË幺 -YÂðp,ªw¬¥£~2WýÿîvÍG{ûKþIáI¦®¿Î­¦JÈ6Öµ*ój¾%6̬ßÄY5#šòJ„Üdà¢ã„¨º€¯þE]i6ÞŽ »³@»4ÞÞ"ÛYÒ‰ïîwŒ+„|À\ûþŸýÂ@|¡¡ èÿXÆsÐpåãüé*þF"}†ÚóÁNÒ¤ÛTš™ºø6Žìb¨† º÷‰Ao¾@¤ƒÜìæÔ"d `ø§ºè¸÷‘z'> Nµ^‰P‰ÕÍ×ÕÍ‘rõuCX½*Ä.Þg/‡[µÞþ)hÜ fŽ…«‰Ìƒ°¸ÚFüPÿÈÄ0W¥nE”`vÂа/‰ôÀÛª`1°õ‹}÷$Pµ_U”‚EÉ>†É&±"yžÌ¦iï£ê ~?8‹Š¢Oï©6nGtc’ö=+P‹¿ —tü`TR$&ÖKÊ®á9)—ÌŽ"ˆ.@Û^••W4õ²}l`ä÷Ži4õ”[ÛÑÚIÐÏj£ã$Ðù8GÐS‡ÌðZ¸.\gy©]Ô€[ÞfäqÌ/«»Œ3>g4x3Úˆ‡ê(ȘKØE¦g?/½=~ñÍÏKKAÒùÌ;Äæcˆ3tc®\¤ìcnÃjʯäÏâfµ~ˆ6—ã·2ݬOQÑZ…¤ •‚;ì ¥)•-PLÉ5²UøNÈb*éE‘÷=6ÿJCšÒÙŒSsz÷d쉨ˆy7*ð"†¶0³ò]§Ó‘Äb§t¬n¼´À·G>›“=KÏU4/)ìż;3;º¼6}¸ê$“¥ŒviŠ}xUâ(¨ NH6à²DÄǯÁP›|¦ ™¤„rH$_®Œ Íœåìd¶™|Y²IìÌüwš4Oó1Ä)¡Î„mýæÔC÷,ª'#º.ºéªß?8ÞÝ䡣鄆Mœ£\øñ3Ò3 xZ’Ó{/™n‡ eP™^-²^EfÅ>;͘ÌáÞËÐ5ÄKDÅ. bEðDzޜàE%›wE"â I^â$Ø›™&¥*~'ÿÎ}žŸ~I$»©Îlø³üŠðkÊfà|Î|¸;8+“E›^j’­£UÈ 3fiðJÐQÅÝ•ïå„ëÊàl6;j¢írSØŽkcW|ç‡î½Ý=ü[÷p÷åî¿i'j ÏÞùT7œWÍ­~̆€ù•5ÀcOʇ˜=aMm€:ƒäµæ{Ò«3åM<}‰`¸{†Û»K’gÄïgÔ‚—"ihdZ4÷П´×2 fWœC<1EGyoZ(cpBv ð!jž ‹tÖ¯“¯í¯æ7'^ªÂôÛsAB¦îº½|Šne0C]X8‹2ëºfí@§³“ ÀŽâYÄ¥ŸÇKb“yòÑS`ÎÌÉ­3cùÙ)÷Lùž:ÕK³\'î–ì–Þ|æNiôÛÀ±Êð‘?'§“çøÅfbÍLI§ñôtš¬>§ÐóÜÒÜÄCšŸ§«“çAdƒ^0›ñ-D(S…"ÑèS!©l q5#ñDœvù %ïGu§£ðš ¿›}‰—ð÷J£š@`É`My@:QÜ‚¡še穲«oÄäÝî[sïìþ´u¸¿·ÿ²6RS!¿‚Û ò'aÓæ‚å°‹àÈ8ùŠ=8ðéó»\UŸT0©M߸L±¼WÔe¾ú ë#¦ƒVZßKìnõ¦ ?ⲕ &@fL{HU¡¨Û¥ÅyñØ…0«ýì3¬ n»?viªð•¾JΠˆ–uëwÅÒ‡²Œ/UǼG¼Y~‘ÊE’y=¡d¢ë–šÛ®4NRíBòírŒ³.òþ•jØêgͪËJ€Ý’/ÚNg:–]¥˜i ¨ˆªÊKö&•ISHu(óA=!e·:ëõ´þ@:;¶TC™Pa šzü•b…\Ý"£ Y#ì“W£-§\Ù—‰”Ÿ¹%4E½t‡Uò[]⸈%¶ºQ.ùöä'º‰¨¥D¹Ú³£N‹ ¥m¾–~'°ùbƈ¢IÊô, —w£r‹Q8²´QáæDuó=ÍÎÆžÎgE>îMÉÛ VçJÕƒãu§ÍõÞ®®e—˜·‡‡ÝzÕlüÝœ¨azªÎÝ÷ÝØkn©³Ô-³ß­¥EØÃî–‰ŽÐ½s°jÛƒÆÐC/C(ˆš#'pÉõ!cxÐìʬ^‚çäZ² DâWçЍ*À·Û^™BŸïª² ¶”âmÙ^׃ë{\bl&«o/òhu  â«Cþ7¨Cþ÷éB„¥™#Íq4Š—Sbœù”(Ùãƒè‡ç¾¥Wùh>Ò ÃÖP†U|FŒU¿Pm·é`ºÈ ¡AÚ|å“b¢2( ÄßÅT8ÿÖá¨AÊ…Œ¯ö^ïÃ-ºivz‹ç¼ÓH^¼dûæû®ú>ø¸t(¨o§lÍDg¥  GØµÙøðÁ]JçÚ‡v<bÍ$Çþƒ’<ˆm £>û™Ë#éÏ•ËÛg9XÔ©‚þn°„§Ê~!9uÙŸRfæÝذë.óv !"rn¶5VT¿À3+ñœ‚ÿÜ’dÛÁÌ’÷ãe:í—˜ Ö2¨8È€ò¿` ò'D”ö¦EYªüB.ËßõDà¶0ƒ[Y‘1o;CJó-ƒùç¨ÇÕãN­>3>Zð¼Ìéþ_}0.º*ôæ0ñÆ@7üû=媈óÃ^-&ãØœyùŽa쇹¸“ÿSK;È;˜8*ø1céðÿÒYÍ!âJw_¿98Ü:üãö`Ú*Û¬97¶Žx_™êÚÿ÷œ´w:-ùjÆò:ý@{ö:Íü€j.ò—'ï ´ ½hÐ7¥$`8ÌlnU¸]Æá®ÇzÃAy¢Mpt¢0 ›bTï„]v~AÄÒªÞßvOÍM³‰uz÷ê¥ÆjæùVŒÝ‘bó2ªtµ £j}Ì„SOyí3»ÀJ?hJ¨®Ê”kPÝ”°WBÍ”˜Ù˜#ó¡§âÍ„ Oæ3öØÙõ1âߎ‡8 Ã¥à´lë…<°üöÍÇnL¢ÎqÃÙ>xmùÔz #G¾jÕ”&ŽÝüôt‰3>DϵêÄD"ÄØðùÁ<€™2͆À~‹Ê¬èÃÔ8¿ uRTI =ŽÝ„žð…?,Hxˆ?j| QÇüDðCÞÛ‰.Ä~g&ã®ä£Hò›g|À”á‡Ü(+.cëÏð_³i~v-‹e# åe³d>Y$§Ò”›Oj=¦Å݉îÝÕ(Cð€%wZëÕpÂ6Ë1æD—€Õ![ÖQ˜ýÂ@P™Ïξi´aüÅ|–#·á‡—ÓnçæHèÁÙa‡ÔüÒö¤“ì‘'­ä%ÎgNö¼,¦ï=Á{NûyI23Å'Œß™†ß¿Xùfõ-Ë6ÙI^ƒËšö:åË÷ð¶°ØÂßϧåçzœEå'ü¡ƒ5 µ,áòofN¡J^ÈÁP——— Õ Áej.Ww¬¢G?éxWG`ˆ3­ƒ9I<íãÖOÓtRVv5™pLA†‰I“½£ã½ýíãf‹®O—SH…8¥íã|B}Pï^ptà:øAM8Õ„SX…:¢ök%²ÏÃ)/þ%“ wãLõÑÆ¦CJÎI*†|,=ôÌsÞÕ'9æ$|žjÔ%ÙË0ë¨4T±’$/îP’ú_ø7¥”^{ƒ¡©x{Uv›ÃT¾(çSD!°uábFÄ#ŒÛîͺø>°ÊXyÚ%EAéÜïÜÜR€ûþ\~ýóÑ×æï­£Õ2w"¸ù²Žzå¥Ã¦ôÁþÏåŸnš¿šD.2æ‡<ZßásšO~Þºs 'IóÿûȧޗÍΟy8-óãw?—-ì"7/Þ¾¹ùqë¯{û/o0wû *ïn^¶:n­n©ÚÍ¿#ç3dÝ‚F'ë¿x®BÊ­¯yòóß¾üúç÷¿|Ý2 fƪyyšjÞèñKzkF®º‚-›Gò-¼U½‰½Ö ^ÙWº?ôŠÞ¡sêä’ïèêNõ¥îLõ­íO¿˜Ã&³2*Àübºo\ ½yÂì¯?³eàâ«w\©_éoå-½˜(pô×J"Ým1ÂÔk†¤~­-ö^OT´€^»hÝKUÀóð7H3µ—Œ ƒ‡«Î1Î.5èt*At¼#ûÙæ<­¦è„‹À" ÛH§"sˆ¢óˆÚØz³Ç߸֜ëXÕÃKrbx™ó2k ‘dÒ‰ÈeKðUÔ•Íe†Ò×Ñeó¼Ë®\j£K‰¥9i*ä ƒD™øK—îGÏ=g¯JôGíº®ÐgØWCKL¦€z‰ÀB5ªØ2¨=Ô¼^*•'ws2ÍG Î2e9µ¯SF‹x݆¨ûÍáÞkPÊþe÷oæ î$ùˆ½xÛxæÆ[ë4Z6iµkæJe`ô³«ëš_DºVY ¯.¤"µËa±v#ãÚ>Ø?:>ÜÚÛ?FíÌ2k™ßwá[K§Ÿ$o÷÷þëínlüØ„ W¥$†ÖL3K^¸osCKï“æÏãŸgKO¤°‘U¤î¥6¾jk²ËÌð=2ßeŒ+â d ×µèn,ýã¨Ê†ïê4ëíÄ=[ÿ%ØCAj[•×ËhlLó´µhÊæWPFX¬gvÉ;êï>‰Ë‹:Ž vè~¿Ë/¡h³¦ê°†tEoã5%q©ü©ôð$¡¯ôE´«Uû3íæ¢­)u§îaé»÷̉S¢RåÈ‘Ï*m¹ã§æôQ"Ö,}—EIÕNq5~6 €-\Ø+¸Ç7r=le"û!ûPJ^ê…7Éf¢ˆ'üQ!Ô•#%úÁÛŽPèí¨(g‚ÒŠ„#CcÆêÂO¨›ÄÑ¢+o™Eª»¦ÿôÉʦébÑ×äí`bhMd¬äbK5°wí°t\³pža ¢tìS$–™äi¦A]‡ß"$’4 ð‰¨Ï$yJ'Q fÙ““Zfc‰Á ›ì èë·GÇÜεüŸ=3~ª}ÓÌ$ðæ3ëÛKŠÆä{€sBoˆèrœ#'Õ¥z h=CÍy,Ê\WH" ù¡Ø¡£êè.ÚÌ!Îò+8uÒÚª4œž_Üv ºJ]w¥*Ýä{O}±€Qoíì$Û¯Þ¾ÞO굡‚3ªÛD‰4O. !È6þEgƒ'N\]s•9%&ûr­’çŰOà‰•K%ík0nŽYdJvìEHÕæ‹‘r;ªæíæÚIeD¶üL¡48y"ùO„PF#8x«ƒ÷Ibi$JŒ³ ¡¸Öò„d¡KE‘eYòHcÉMÑ’! |Å3ó% oi‘¦Ã|Ó š:ýLèÞÁAô6ÿ”n9ƒ“p±±€…|œ<…2†ìS![O¼=³œb¶^3ò¯3—±âÞºã‰>2DסãÆ(L“n‘P{â`Ù¬Ëkù;¿W1Þö¢Q½»Iû×èøFPg£š€"BÎÔðO&¿zWî[”Pµ+í9Dt‰S©2’TtÛŸõª®·öÁ¤ÖÉ»·ËÜv­˜ª­5jž¾Òÿ'­fdCܲ<ÿøU ·ÔYÝ6cºŒþËN²íݧo2ÝÝe¿DfûC îzþ3Íj®Ÿ·»rÞ¿ª'd¤VòGˆê6*A¬4WuÛƒøÌã­ýcÛ='ÏœlÖÉ.×éi>Ìgפ«A‘þ®&ü—ÏHáfƒ@…ˆSnôVêäåΛ&º(Aªñ.(ÇPn”¥cþD·ÛGÊ€øN¯êÈ@?ÕÈRü]µmÇeÚXþ}³%©zè95H u¬B/f+ÆÍÂpÛW"êD7ß%C%…(öœúHâT“~NÑ38ÊX /õ*?ÊÌÎÏ&’-„Àˤ`=iœ…—fHÙêíž=÷žƒŸe:UIíáM§o‚‡KŸ¶8rÛó‰PA½X.ü¦ŸÙ¸/]…i´IœÀh×t¼c¾â½‰êCÒ¶AExÁJ@7»ZÌ£Ý*6ó“†ö hÇŸ¤˜4F{§º®†*Цù’XãΜ8xÆ&ÏÿfÑܵ*G›¬Bi „fAç`“õ馌**89àl@-cãÔ¦жoÏÖ}Q !w¯UìZ“†¬%êF…¨RÖaäÑ&0²Sˆº£™„ùª‘+“&Ú h WäØAæ É›KÎ ¬ YK•{ùž»ÀÝ4Íœus6’[„Çòq²@„±ï4Ql³@n¬r>ÆL l~sÑ8):®°’ެS¢&82>ÝÔi®û íê'β´Z†éÛ¦²Œ‰ˆ•ŒÓ/ 6-`СÙú@‹ 4nGÅž “ïe ³Üín «È†Þ9R§´kvkÓªôÙ,Ïk{|€P¿¬­Zê^Mªýeõºlpªõúø.bÚt¨z7ž{‰oió§aÉIüŒžÔ©BmB\˜ ëtÕ€ãvd˜¢Þ•±~3 63•И•m ¶ö ô›Î5Z¡Wög³­Dãlà›DÆ}xþ¯Jþ7ö ô?Kæ7ú³8ÿÛúƒÇÿ´¾öøÁýuótíÑŸÖÖMéGÿÎÿöGüñó¿éÅÇÌo(éÛÚúêúCHú¶þxóÁÆÂ¤o/w6 %Øð]Nè%X¥JÅÉa–æP¦P§š˜Nü Ÿøñœ‡Ùlšg~x|z*lœ[¸7VÖ€Jä¬ð3v±”G! üH“«r¹Íš RdÜVÃרrާ‹W3S×?ù¦©<ßåbà^Æ7?fÀ¦tã0ü S¹èý‡KAgxŒ½³Ë¾3’‹ mÀ6 `3Â.êÀm0‘Œu¶5êꯓ ò ¤CÉ:´ìîVŽ‰Ì“ìð­žøÿ|³û2‘ªZ®NPÇEwà–Cb -†³õèµ+;É!œæ%y4­²¾¶ÖI~ÌÅÌÈe È0¢É !üZA|8E þ¿ìèî¡5ôk}Í=„ÜÃä" oîëÁ Q«ëVÄO™Õvòø¡jmdó³³üJæãKéOÿÁâ ´–éV¨Q!CWŠkÁ¿ü$|»)@;[_f¨|Mý¿ÊƒˆCàc¤)ú^3!9Çawv®²4âŸX1þ/}„’Ó‚÷žâܺwYRx¨Kf1ãÈI&‹Á废Á©•*§XEíË_›Ÿ½.uEJ}‡¤± êaãÕY|ÈS†<36AŸLê—~[ü+pá9Þ ¡µ‚怢kÖûÊüw]#hýs—I¯E ±]/ aA꛿n”ŸwwïDw÷ÎÝw·YÊó »¦Â §­e$\ wp?_þSj·KDFÇS ™ ]ª|ÃŽiP›.3«Xµ sn^ÂCû]¹iÔY;ùu2€¿2ó·‘M£CþðàzOƒ °­zÌ4ìÒÎ?ƒÎ;0<Ó#ÐøAŸÞwHP'^¹ÀáGÑà 3éà¼c‹?©ã‡®ŠÌБƒ-M#iÅ  •Óõ—Fœ&9eýb'€Ü9ØAûzy¤'ó¢x hcvËsoЉyŽƒšeæ/ò„â+ÅÄ˦«›ÀŽÉ<ãf)œE·_‚sºþñÓèÕ³ñIõÄî^ÕüÝ4=ß’E·÷SÓ0UÂ[\sÿ6/4,¤ìó@ÒVs¥˜ ˜8CÞ“P$/rDõóF¢#|á<+!è ÿ&ö¨g*1)™T@‚4ïñW(‘ãO_m ,T_h—ŽÒ«.–0ðý‡V¿Ð÷~1°á p„5f¦Ìfô6”£{S!dë´ WXà ”óvxug2–bììÕ­vòÓÖñö;/»»‡‡‡žyÚBLÈA湎,[{`W½çîÀÜ ´%è[›ÙË.£sU¡ƒ+ôUÁ§]ö¹^:CWº¸Ú_݄۷jWÄ•‘æÐKpéà0I1IKã˲±ô$(Ã]"¸K[™”zÏÿ_•ù;qŸþâw$R[ZTƒßúû{b¼ú ä k¾b±À•YÓ…+°Xð…T1u®Uô$ºâ©¥IQl4I½!B|8LÛ¢~Ramÿ0µOÌî;·| ?h˜éotjjCÀ3sÈRï];YJ–4Ò¯¥ÆnÿT£z48w§'ø;Ïæ{Î××k¿^oÕm× û7ŠP5@Ià‰55]ë —wåy* Ì¿«DÓß¡Ï-xµ£¼Z¢•lú£¾‰“†ÍSç5'OoÿÞAFÊsxRGz/ò©•ŠÛpŽ ÂÈ{óa bM?cËY¸™ƒŒˆ*8äòŽ›šmOèD®â\/æ@u³×qC¶GÎ3iKÏ—šwÞPNÓþ³,‰DÎ=UŸ!„ûùNb}ÈU`ÈË£z¢§ŠE~O¦í(ޤ 1Þ-ûÛôK,m¦wàÜ?2ÄÚ—kåÐõäùޝ"{>k”˜ê«²lmÇ‚øf®`-1”ñ¸v§V2~Õ°u&´¯Ëq4Õm°[Iè¶=ß œZÂòCIë½,Á"²*ÐUíûõŽ]zoE­••'q«ˆ,ÎËMCJݳ7}¸ŠCxú©‚¬Þ•® Ë¯È»£kò(ôß°@võ|‚ïIT¥ýFSî§\O$òXO×1æ-S¯"¬G„Øb ¶tI½O°(áL©0ÚX8(¾„ ÓI®#ûøA€ J9C1¡ÆKÀOyvéõû€×ÒO¨¤%?JÄ)ÆC¾¿ç!5²³!BýÅä8”ãÒ¦]SÊ U¼<›£j²³…쇂Ä1Ñ×Ht‰aoçæ_[&ظ&BE¨j¦8È>¥Cžm&åNrTŒ$(‚x…Í”Ɣʔá@òºœe`32<0µ7!¸ÎjN()å&Óâ"ïS`ÖÁΟxY‚4ëàAZ–Þ ñ"9xªºçãí£K3#ðLX¶ÍùŠ$Dî0+3O•fa¾8õ̹žÝýVi/„>£ÁX|G”à‘oÖ¢Ò—Òx€(’ ‰ 8ãjzv5ÕyÚªv’uö=ÉmÃŽ•Ô„‹ÞÌOͽè\8A®½€ĸÀª ˆ}¦vÐml`ˆ±Ø†ÝÜyû~2Ÿhß'::¢À{&‘ž#Òñ.·t.¨ü’éîEÉ)?·7Ow™efއ…9†C¹›ãa žîœRQ%üV"­{ìÞ•ÙªÁ÷ˆ²â¾ÛW–Dd”Ó»$9)NjË ,P¢Ž=w³#+­zf’7ØíäÇæ]àY£5HÍwÓRiÔá»E‡(ñÓËÙHy=îO‹1È€ð¡9€/ò2GV½šöGùxõtžûbQJš—pGe?{öÓÖÎÆ@×}éÙt>¶Ýêªvš5¾Ù5ìÒ©Y}S² Ü„]?©|‹†› •ïÛÛ«—@¹»·?k”[˜É}8”k½¤Sëaª(•uB+Å)ÞõšÚ ·Då~êÇëØ9ÀÛY(êÚ ”•Ù’ê…-l¢w¿´¯+¼ŽS÷FDdã¢("ÛÈ%¨; ¹ŒúúßHˆ°S1@E?Ò{NÔÝ×J9 &¾£-:(ÐaNÚ±žã׈8*9’e%<å¬g]Q@qš š5§ž»V_0åÃg¥¦u¾y‰Ì!8ëu &v/æDfCQ½£‹ò|6™kÓœp°äÔR¾ah×ãï<ÌÅð…¬ae}邪R"Fœ4T%m--´I04³ÄÆ%Ï:Xܲx¢+ͺ:óbÿGëL¬©7ž²­a4Ï`š¶”(ZU#'PÎWÁ3Žuê×4^y ¸—þµ7Öˆ¦­_¼'REÞ‹úïY%Ü÷’Ÿ¢vtš“ü¢>ô_Ô°n˜Å­È©Ob©Odm©$v‹& sò“©&Npšf¹Ó£*«¶6áТÄ×;µ‹m¦AÙZ—£¡ æ†t¡ú€nÑ<³Tè—Š"J…Õ¡„D BR°iÃ’jþØ8D.£• $“½–2'1=!E8…V)™Ét•> ÒÃC¨ºÈÌx3CéŒ(É»Óí>5‚?*’°û^šÈ4÷â9QÇ]ry‹o„tNQÖW‡ºÅ6Z&ó$?W kÖøîg_[ÀqÞp¦â²à¯uUýдéß»“ªšš*ò eÜ/;®z@•à&rÎG}šaLÌ@ Á Œa¶¹…õ@4ÿr6MÁi×ÐÕe: !:cB£%¼|ÜÅDë–¿¢ïÜbºÅtrž¢ ¦näÔ|ŠOºVMü^ ’.ŒFŠ“ô˜Þm=Òú4ùútRíT`°!S_\3Úw“ù¼;ÒK ¤i1œŒ“"À8uG¸‡L÷âST̓q¡)SkŽÊÌ[ä5äîRFJI&sJÜNu '¶:¦´ß/ýC>±D;V¼ˆ.Š.“ ñd¦SöpÆÂƸ`Ö_€X’ÆÀ€l¬Ì_1 u©ÉbmïBž­Ã¿™6WÖë@ü~Qæ äõóÝ)buîìòÎâa„5²F›gpi 7Ýáœ0Ñžï˜ÙzeÚø€^sÕé`05+h®Y\=©O¯1œ ïP@?äšguÅ”,±ßÇ<fbËIÝ%wHB|j+Jƒ9Ê+RvÊÐ íQÆîù‰TYØ[h86Ü­—/wŽöþºk†¼á†Œ—` Phmh~–˜L™¾F#Ìá‹íäþú£ #K6Ó9K+;Åt°:=ë•ðèœÏF虈©r­,Ùª<ê–Üb—ZÄ"®Ç.2èõîáKÓ_óÇPH÷»èŸ<î]o&䬈Ë2ž#5U+Øze„mª`*Øi]¢ˆ-~#¥ŽÎGæ‚ âàðºZÕöáÞñÞ6RÌUµmF¾˜›F$¦Ÿ@“Oë[FaNÔ—û<@ Ù$À…Ÿ²>~@Ÿþ”NÁµpÓL)þ°ðóýÓó]lú!}¾_˜þf› m´aâ£kµ+«Öµ·ÿ‑<¢ºöœw#ÌE®MF`=d‘Níìþð–×ö1U´“Î͈úðÏ †û\6è‹| +&g@297r.4ŠyjÁ(é»×ztµsøöÍÖ«îÇ…ëMwû`ÿÅÞË·‡[Ç{û»9Ê`ªMÍ(2#(!6v¼bï È*á[úÍe"¿³[ú°»uøêoÝ7[/w»¸SŽd8Ë4Ò 5`Ûü0½Î¦·´¶³u¼õÃÖQÀ’Å|jΗj3}pl†¼Ùf*¦†ßž¦c` çE9+oimk{Ûð7ÔmågѦ܈ʌ¼†ÏM«CŽò]ÐÊð5\¿zýò«X3À}ÇFE ðàœ¢?ñ }q(”RØ ºÔppr6Å ,ò]{ù²^Æ züjëx×_ò‡å§V¤ï6ú˜Žsh•onЃ[›ÜùÖ´hÚz¤ÚÚ;u¤)pk]î¾Ü=>iüÖøFËBæ`|ª’„j[}³uü#À­xË|¡Ò W~UMØñ)ÏpâÏò+òÿ(Gþ-jþäÍm'ߨæ‹a&¶ÌÔìÞëQ1GÇûiùD$¢SÊݰJ數ùpÉ9!TZÝÚ?ØÿÛ냷GÝý`{ÎMuãYÞ³ÚåOmøíñFè3gÓñî7®÷ö~áèeœ çW‘’{×–à(¿%!žîþîKs– »4§ÊþnÀ3ßq/êë–ØõOTz³¢Ò*.êçF±Él2Í‘™P~§^Åu%%®¿ wíÒ'‚2@òPßé´¸„Wv®úÙ,c¥s]çqdÚÿ`w Èœ÷ióêÖ×vÜúXõºµsðzko?à䯤Rð@[.¨Þ€«t çEÃØp‰eéÇÊsJHW9£m믎êª4GHÙ¦=h÷›;<ïGp X°†)ͶM.›{”à |™9?l^ª©6‡³|2¤_”þBYZÎÉÙifŽ“t肤½Þ|ù”1ƒtyõi#±­@u‡ÏºØÁ¦Ê9§-_—hs¦°³z¨%îÃ\TmÐô(ïM ø IJ^þø«ýÓ9LgèÇØ<3<|ÖÂÊ’¯í¯æ·ØwdìûÅywÆßƒ‹ç×_×}¼™¬ûJæ”3•¯‘‡dV‚Åšt„¼›êªn9Ö¢Ùã¾VnnY¾Ÿqk:ÿà%ÄèÆbrë’A¾ùüìÌ”C$Ñf“>[©£–™õµµ5æfâÐüÚÐàÔÖ×Ï*µSI1*6ø"g;šq–îÅ›ø—|‹«§ø4².è(°Ý9€Ãá¡ dö½ák8œ=ÉÓüÜDo‘ü‰ÊzËtŠÒ’&;wïƒÓç³½™Û)Ôä·X“gO,À7 c=a´š‡ â»]ûxªŒ‹šº@J†ê¬'wj~"€4Ÿ™q¯òó†LØ.¥w%QÔÔf¨ÂÔ;Ù—¹Ç¡4>¤…Ïæ7k߬­Ž®á‹Õ™¹¬RŒ¦M29Ÿ4 e–NÍe¨ÏZ,S%wiB“u‚`ÂŽC#¿áµÙ6±ü†*KÑûªè‚bT±ê{,òðNÄ¢në–z¼¨kXâ›h¯¤Cß.îÐ=dõ=Á×ëÑ.à« ¿mntÝ›O¢±{aX.ú]Û´!Ħ ^ ¾=sή ÆVtBü=ET‰Ã –}d¾,èKÞIv¨è“®ÍæÉ|Jñ·¨Zê&˜Pæšì'Ê* ÄW¼ÉùN é;IÔ×,Æ2[S6¶Èäuvø2a_Ë$©Ðå Û¦xý僛´Ò Lhà0°ÙsPhd¦Dl¢½`W¯ãâ‰ÜâQ­Œ(82`µºðE³²¦æ8`Ðû‘°ð=z»¤ˆøè«¯’/üX‹¿j^[!3¨Ⱦ¤¬åfiµ`³ †âîÑîá_wOGÛ‡{oŽ»ÒœYßÕ¾Ù¬¾y±÷j—Þ’|‹Zž©n <¬³¥uƒèB€Ý´Ìš¶Ü¦y55§Í¨éùñøøM÷ǃ£cðãm@r ö„¥n.çΧό¯ed«õ'‰yú7¿¨Ò’¡‡ú:–Z>rUPȹ…†¤äûg¾¿«‚ùØ’¡ïòcÀ†§™9àX~eaÙÁXëey «ÅZ~l1åF)ªK•y öÆ9A¹M³A¡YR¦¡B%¸-ÑÝÝÿ+¥x3”ª<÷Ë @ûÛöÁÁ_övÝﰎܯDºî÷ÃÝÿz»«¾ùêà³éé÷ $¿E¿j û{žHZ. ŸdÃãi‹ àú¸@le£ùÌ 6ÈÉwÍ3—è>‰nNŒþ,Ó3{3Ø*ãYa6%¥d;ÉÆpŸ‡ˆ ‚O:’ÿ{ç†á÷À— /ö¼Xæ@NšA¢kÛ·7’&HœðËÆú7ë­Nmëdm¼Ì¦<:êóš‹¡KªUÕ1 ca÷—yú1â—]»Ðýæ2üíy>™hÐœŰæÿûóÉwÍï6OÒ•ß×V¾]Ùüù—î/_ÿÜù®õõ2²müZo²WEÊa,¾¤€"Ø~”¤¦Ì’·‡O¾(Þå+³Ú.Ç;YÆ”h ‡Û0z¶|Ðô/BPyw>¶ùG8þäçiQÌžpXÃîâ“ú¢­wð[ž ®ÂÜ®ù$íeªÕþ)·i~ ý!BÁèº2:äH˜ÞEuS²à„œRølšzD®=QŒN@¨‹x”üU’¡|ûæÃ©]H]jó)~Á˵»Î}‚sÀƒf_Ïxˆ|?+°’š9xbU_ÔÑý¹Ãî{S—±ò„†šÕn,‡´oæÈ-}6£`{üsnîÜõu®®wÖ“kkÉFü;$cŒ 0Gḛ̀ò]mÈPØŠ­ª7Ì kˆ|,3ÊO~„€Fj¸“ìÒr æ Õ'šoૻݭW¯”óâUh4¬  Îj££¤OTôD •]\úÄÌÝþøã<4£©x!³9F„„‚Ž® ãï Ú¶-`øgÌ]`ni¿ Íí6 Ðû&¸‡\Óþ÷±k´*Æ[LîkÏr©$œnO˜“Þ¥oR#{‚ ûÌiaÇô`Ç   |5©:ÕssXú¤sékè¼¶·r;ÆÉ8†ª¬Y.kºþ@°(Þš4Ñçj†—#ÜæCR¬ÐIÒ3WXÂÄâ™™Þ%檂g€=…¨œŽ¯aw:„ô+v¬F¾–gÁ ãê Ð!ó[m6ÊS@œÚŸ"•ã(µ1mkÙ07ü©!i‹¥¯0‡®¥ŽùÐ ½Q#<±À—us§mâúx6MK¼üº²o~«ú«pI1¼@*;Eø k÷$öék'xz²†Ö7: 1‘ľömp +Ä„\ð,6S éQÆPbF7LB˜±›OyÊŽÞe±a¦ÜQ÷Þ$[ý>¸àn8óƒþ1­® L2éÈ<^0öVò<Ù@¤ÂîõrcÁGȇNÍA•U!D*ŸmX"M—€~td&e<Û ¢§Ì%›"8‹ ¹Z¾a¯Æ E“¡ ­<â) 5ÉÓ­Í8-@«%,úÜ’3\!½h“c[•Z…÷ìJØQ®:ÈÈHzŽ3Û/&v¸0 J $pLÅÛø=!æ©\«IoXä+e4ÖEGT¶¬?9YåcÅp9Á¿yBI›1åC⌀<ë §)Þ΀³¢hà=m˜ pîO3Õ"9©¡ó7ñF†Æ3`´IªÉ‚7„¢>2²~†©B>øîwòüìñüÆï 6tа9`D8§—ù €Ã`œéóÇù¶qMžLƒ2[> M;¶~´†6›²jÿàxwÓ†Äé‰LÆFXÌ,X æç1GßÆÚ—Ä“ÀÆl£ûµPZl'~øŒcñNgëF¸zx®.t®aÄa‚¯WžÃŽŽð…€]˜zGª{/Zt-²ëx;^îÕ‰ýqå¹P¯—Lý&{¨ÖXÑ”á¸ÚÝ1ëL­¸d°×ˆ‡†VÝ5»°D¬Á–¬^: Þ¥Jý¡ŒW/•¹]QpsÆŒ¸ñ·¾_+¯rƒ±•ë¤ÄÙ"¡Íâ~/Ö3\w¥n# Êi% ž‘|ܼ1·ÇÂeÀ÷Dý'\•ª‰W×Ï6¯vøüŽ:œ.G kÝà©aá±ý„//.‡ DJšâSÉ yfnØD«`9ë&¶T«H´2­ ¦„2^ùp:nÛTÑsìnFøùXáà(!e©]m‰å«¦ùÂ4‘š+dÏœû]P£5í¦ÿ¾ÜÅu¡Icå¡VÁ[ZJ, ;â6zåŽO¬ÇTu“N,Ÿ“âŒìƒÀºïgØ»±]é7…ÑE³+t÷©a/½E½>—F‡ ÔøÝÃàªY¶I:(¶šN/2ï€ã£ÏÜ´æ¥gExÃË”24¡jÔ`FBNxdJé*t‹½LIŒh”~%Ç-µÒÝ ­ÙOtìÎÄ%R¥¯B-õJEr¸¿«¡)Š Èú†öMçt¢" ƒplÆz›O09½¹–bµMÝÁ¸¯ ÷è™K /´ZõІd½”JC¡Ž^9m(ŽnÀî’‹U¯<Ÿç}ßJÇŽNÝ×»Ç?ì°¹ý¨L1R)òż¶xi/€ÎÖ¯Šþí¼8þië p_@eÀk·_í9ïtÐÉ@Úè'“Ý5×?@&ÊîÂ$7t„_ºñ­’MŠSr8‚vº8K˜õ€ƒj¼4ú ¾êã¼ 8§XžÈ ^ù¦`€mÁÍ'qÞâÂC¡ ì¯KÈ8c¨˜‚2³Å5VO£·2à Yôã6œn(¬]@6ZYÄurÚ1)DSå5ù]›ÆÕ /{Œ^ƒ^÷ÃÌE¢XXa¼ÉS2ŠYAJÒ(Ú9µª[O3Fª\ø uq€YEþwп¡Z ‚àŽóyup\k\ÕžiN³VZ슈8bìèU\ûE\Jëu7×ݯˆ²GÈ+Y)ÔnS¿¹Æ”",⸲ÔYµ–ÔE¿z ¦®ÔvŽŸ1õåL´¯‘COÉÙËÐì‡ê!4à9`n6#ï9ÿÇjØ2béðTöÊ;™œVè¼å6Èvêd¼w"0‚Ù¦z,±;Qžø”ïLC%Ôx™¡á-Càz¦\¼U—çÅ%/ìîa1d@ >š¥TœäJ.7BÓ;z¼Ré˜gʂݾ¬\âB0\ÑT7ŒþÌéŒ]l¤à‰BÁÎ+héçñ’;.ø}"I¾‚+ý,"‡?µûÓlIsRèù÷ÁlAqDgŠÀ¨I~ØtÆÛËà"pZŒÆÚ« VÒô¢R82 Ê€bî­V¨cýg¥›€“CièB²e‚(ujÈ>„Q¥ïD†·¹+3:Ó{ç‹`kD)›©ø"dC‚žÎLCFÒ!dS¥© ?¤Üt`ŽÊÈPf6I{ï0ûu›› V¦á‚ÎàõÊs~®í´Á<#†*c7†£ü⎑_T“)è›ícÏZšûœ¶Â”-`Âßî9gгlŠ&t‡œe'‰€¦¤dq!x1áp÷Åîáîa£jM¬)*c0D»°LöŒŽª+˜Ÿ¨ ÏÏ~^‚ŸL,$hÊ{ §°TP ùììíMI޽èmÊxâ Öb” øl‘¢Ât`lDÎ]à f&’GaДö¢…Þù ×‘.H±ï€ˆäáÂhKzÓNv÷»ÿõöàx÷ä(ˆ$P 'h¯´.i©LZ€ †ííñ‹•oìMu8TöŠ~À†„ëJù<>Œ7 º§FzŒw„BœPê/&ºÇ¢bÛ6Ë)õ,(SÛ[gXµ²¸ª*þÀézÁÕÔdl®]m¯%+ÉÚÕ‹˜ÈùÁé:lÈ€>0ˆ¬][”L`*à²6ÊKD2µÌÐ…Ž 1ÚÜ 988§”™÷ž^"»Â¼ =’L4Ѳ¿&ÔôÛ¼€Òˆ²å§S𞕈j?³:gœvÂÁ¼ß†)ö1ð,Ç4mœ~׬Õ¶º•9Ð^Ì;WÀù›£"À°'óõȇaÎN„Ötœ¾@UZ —¶²—c B#çq¶Ìóyö"å~´ÅLfgÏfö„¨’ÝÃpDù[!{þÀÝ„µ7¿vÄEMšfÎSáŸ&MÖAWü s¿ó“/‚ˆuÀ¨¹iNÀÕôümÍaI¤™M4}¹U¦+ÕÆ;Ëò)ªDR$Zè'g—"ÃP†f†–E (d œìœç‡IaHffë3t˜ =àxð‚ ‹‹fÊOñ3ßÓ³(Ÿ¢_ñ¹t{' fµ¢%5„©´¤H¦q¾ˆiYi1±¨Ï™X›BPlaEìR R¢§Ú%¼¢ýséºýÜÎêU¶Šu_¹ƒ³Qµ}˜C“¢-Ñd“^˜ED›ŸéøÖ„4N—ÈáH¯CÙ‹A`ƳL $³fã‹|ZŒGÚÜâay3ÆšÓ×ëžs !Lˆšb·XÕétpá‘„µú‘TÆw^}Ï>òáµ"lÌtïðoÝ£ãC¼8}|£~=õ±O k­±ÿ˜oüØìs)g£×bÜ>a¦Šü›[[¨Ù [óS ñ;W‡¯PyŠgÓ°P1øD¡pTôæ@aÖÕ)ZU°TŠüGy!77X'ù hý¶1g˜’ ×)q2ÃaHã…§þõ8~Ã]:ÛðÆ/|ÿ n‹êÜ’¬Í^h8ÈÀ¤³ˆCò^Á.Å`½Ò•"¹3’HwÉ|("ÁË»eÞ„ ·›qybab¨5<[&÷ ßºȽÅcL0å%†¤TZî¤ ©æÐà–AXTq1°Ø~ya.{ªdz$ÄnÛ¼lÎ#z¡µ"^Pá±?©¹õ”6ÖTÁ¨–5ƒ¥ñ2ÕsNyþ×!—R¾Á_4ì;½v üÚ>à2̆|/ø=%HSmÃ~ƒõÞáèébȔߧÞ-àõÉÄ»Nq™|b›Ã2ù¤›R@-‚y³t4á^!½´¹mIÑ ³J9R€Áq°jd^pDÒ$±Ð ÝÄ› !®F½]¸Ææ«?ÕP1“«—бC3EìDZ;O†ä}ãÛ‡’vö‚rΧ7ÚØl½éy!bjs*ñC5…rŽõL >zÓ°“ç(dðµüÙª!Ìr¸œ“|f6Õ0›ÍX“ÇJT­P)ªŠÂî0èìv“µf% f0< €8˜'Óøà&Õ³’4h¢öwFÒwðòÐÐý0›?KY,Ü;³àa$݉(–Í·)àR¸„°5ª ‘Ì&6k]U<Ô&ËŽ»ãb_z„Ç¢!µ¥§l)V:!K%}á„ÄQ?^TúIì}˜rõý½;U†’ÔÔ-ñ‘qÞÜ$_äã.SG§7Ni^ùqU¡k· 9Íèn¶óC%èâ^è%n†*«Îó&û,UÝq‡.KBÅ›<›ÕKfM l&÷ÎÖ% á o3’›aüójMGF/'\döŒ»„Äp…‚Ïõ>([—©IhÙVØ#Þ^"a`f½[SVöÞ/Ui¬#|“6ˉ)+ÍÒôÛØkH´MÁؘ3‡j¬kŠWp±bŒWºøo«¤ñÚ£¶8R„[¡ÚÔòa#Ĭ$n²o ¬„FY&íK€ˆ° µzµÜ¡t>-g›ã¿ãiruÝä®E{Ñ×éz3)\ݶZŸêD§2^{ä^ô‘½¯t[®LRÄðzëݾßÐ)Oh(³ ¢]*ÈCa”–ïØ 6$Zé$‡hŠ™—sÐ~¡Yù,€ò ƒ8·:Ų¢ïf¾1¾–j%E$¢^ä¯ÎO´aºàÃ~fþšr0jäSóÜ‚²½µ…§buý|ìó—¢Ù…/‚©¹Óžy<Å1j|ÊÙ5 ÈYÞT!­)È9i«ïQJÞLÍLJ`mt_H†ð%^ƒAv3it28…Vw ŽàÞ+ªÇ!F;-«V?¹kèë ÂùWʧèœWÙG¹áSwÇ2ƒ°Þ(?ÜшØzèvÃN@xGhc¤#»‰-³ùs´ë¨“>†öp°Œ #L>Q|Äp"Ëuî ¨’¢ ø;2o‹m 8±Ó¾Mªñw*ûžc³àȤºXú^ƒ´¯ãëVG6 ªür=iâüµ=ÜŸÅ‚ ]m4j °åoë#1•ë6o&u\ÞUð$S¾:øi÷cZÉ«½¿ìòZ!(`]z¿ìk Ëj0gwšŽAš4½p‰a¡4Œ¯A2ŒÎüâƒ>]—O5{ÉÊÁRU;W/¼nªôªš¾ÈrºBn¿\•rm](jšŠs3cÏŸwÖߦpç|"oÈ üY²¦žX”šgÞ=U•¤‚Ò—Rõ›“X†ÄËòÝÝêC×s„z)^âkj}ñ•žó-ÑåSæàSòÆl;ÀOÛX|s“]Ì ‡oͬuùˆ% æ”68àÝ—ª=ÒT>›Ï ÈûEþ˜Ó9ƒÞ›Cu˜S4<–ƒª B›O6÷ïb:KQWÌ×&¹Xz±Q¸>õ‰{oãwÅ*&M{…UIøL }ïz)J™ì~$•D΄ ¾˜®ìëfmB­J,V”aýcì,:¬§'[œä,^A˜[ìöìeÕÔeñšeØ·d"‹LiÁî–],^ c·f ‹¤ßú°¤`ôÇ €úàÔ`uÝ¢\4jbP·%ioæ%e$7Óúš ‰Ð‡åðŠ×ù³êRsµ+©¹*y¹Böì¶íßAŸ¹ƒ°ÑÅ»¡};±GŠÕF^MF^0©EÞd-A+yKy 3ZkœŒn>îgWÄèï¹€db·ÏŸù¥ÌI-x8‘'ú­²‘qP[—j‘J‚âtqá«O¤À×_Ëå§[][¯§µÔùD‘C%6°4콉l!l_oc™|-‹£kËå ]1umWÌO"ŸêÌI ´²ßí9î ³Ç? `X>dЂ£¨ðm×$žlå¾FÜXñBöÌý‡4ðg;æï2W ÙeGÙˆ…o#ÈR€ ¢B–‰Ó× =ÅåR Û1jÅw?%?vÃ2ÁÁ®ãrvïƒçÞ:/~ö€§äO.)Ýlüñ0Ú Wû¾iûAæÊ¾]W•íg‹ü3åÖŸ¢EŸc`ðþÃ*n t}u•¡Ê÷’®ýbœÉüÕyíz#hHlíÈû¦§ qˆ¿Nq;¡Ùc¼–¦E\W€EUÐ m ÂZKÌÅöžàÌÜ}'°¨àº·£nz†6'ŽccáÆòà „Yãv 6q]ÐkP¹ð’¶ í úÞ4G ˜ïFØiÞ7U8Ú¯×ÆQ1^ÃVð¼æ¼ú!Ãæ~¢þwO¼•mVTM·OÈH·ïYš«îZÁ²óö­‡À’.3ª¨[L2p:§_zâÌìo` ±¿@?÷Ê´6›×Ý2w%±FýÖÛ§!ö¢”îÃÌ;Û*óIÖ+pʨT K S|@… aA!’M‹¯b#riCVq]…c­frü,éš¾ÌfŽ[UÄNÕ€…Lá–ž• ñÛÖ]¾ãlZÑÈÝR¶`6FGn„’ƒ7žÿz7~Á}»¹ñ:÷…tÎ¥0×;ÒtqywNIÿÉ-œÊ‰÷j·EC‰Éc¼²í,P›üÖ¶n¹7HÚżñ–(°'z¨Ÿ>ëÀNÜä¸.Ýi²ëæG<é¥Ô{Ý矪`ü¼Rþgè¾âé“ËbúîÌH?RI,<óCøß¶üÚ`³våÊõ!õáë¶ÃÎmà|6¤nkæø€P©Â*1$‚„ÖÀàŠ’tÙ‰ŒCCÝe xß»m ½b4â#Aj®Hô]¸)VZ}ßÉYg^ºìŠj.×iÑâPGP“%ú«CUÙBh^d*Ëj}(Ùª$wÀÝ1_} †Û{ 'mÅb(Dgg+CPíÁAùˆîN&Ã\à=fLN@öœs“Ì¿‚㘙Ò.ö­&â8RŽ=ìkÖ uÔgvy4]'¡ã÷1è6/9À—{ÙPïsnq–¡Îª‚(-ÔõGP Yço®Cß¡EÍ7’ŽEtÈ*È(Øi-;Эeps¨Äkq«8n‚Õðàͤ1³ Ï6!¥žˆdÛì) 1§w‘˜E Óæț¿H,0®0otuÅg0ÞW·EKÖ•vCçé¶9m”½¨eç`ÂaûûP³ÑÄ,¡Ù£d¬t’ÿ~ýj½úP¾á\æ-@›/‹H­]J½ r*–E±Í>³}îò]B0B}WÜ ƒ‡%mùZ1œhånï7[!«y‰NW€ú„-ŸÐƒ úÙUÅ·Ü[°:éï{KCöÀ`¿Qv\aŒÓÅ ´ÒMV^…®_.´0: ôׄ_ý€bHvÄW8& ™i ]¶ÃP"¤êʰ3m ÍPpÁk*S£UG<Œ|$’öWo¦á—P öHãÇë C$+µá¸>i«ƒÊ:kÍ\S8ÇÅqü€=Áyl™›¥W k}½b OÈÖÖïyië †¡HÞãvÒ¤&[²|–\ÀW¨Aº L¿„¿ïŽ÷KA[UyLmYoÖ Ž˜ B2"N†ó)$g”÷ ?Sª « œöwÊõæ~g²’ïM/R2mrÒÈzÚ)úÎMŒ! ûxÓ=Ö+½w¦,;§ÙyŽù¾8‹),àÕ5º-ëùï•Åô2ö³þ ¦hÀ+YQ€"¬­Ž½y}plî‘;;‡ À*:Ù}P¡ï…#ÏÐn"ÙHI\œ)Ä‘†“¬µ³ « eœd„0µ²Ðÿu^2¨ž?ÂàÀÕz9ï(u/*ðqÌÖ\ Çϼ¯j¦æIÍÑÈÝìb7 Q¬¡˜2±¹ÄŒ`üß݇?m™3n~R¹p}lôfa†mæéݸ¸ûbf²¤09Éû@~ËÓy9óÛÉ¿x!à ¹µ%š Ž©‰Â¬°žÙ#{Pyƒ“9B1cÁ$¸r’’¶ég ´ùš¯pSw‹Ó®íP€áfѹü`œ9g{³iàBd]ÔÈSµ°ˆ•&‚!“@·ÈaÁ±Ža×’!§JqúŸ–ˆ &ÅÄ%5i{ £TñK«;+q§øÓ¿Æº8=ZÝ>xó·Ã½—?wfW³ÏÜÆšùóèÁüwíÁºÿïÚÚúã‡Z_{üpãþÆ£µµûZ[ððñã?%kŸ¹Ñ?sPz'ÉŸ.//Ñ]£®Ümïÿ‡þ4v{ýÍÄ[ÿöE²ÞÙ0ÿ[€¡oV×6V×%ë›n>|˜ Ì…‚à“å{÷@R¹ƒÆÂp·íbrMªùx=YÁ:DtµØ,€rÃäÍüthNœW¹a=6™K‚Óë{Pü´~Ä­'/ ó+R*uý±FÐóbÂZ á>ÅCþl>D$µ{?íÿxðö8ÙÚÿ[b¸ÇáÖþñßžX¥‡ighD…Kò%0£1‰z¯w·4å·~Ø{µwü·{Pxïx÷è(1 (ÙJÞlïm¿}µu˜¼y{øæàh—Ó/ž†{g8ˆ0#õÚ½¿™Igq½3¡æŸI &×·Ïí½AÝ8,QÍ[ê²(%¯ö¶w÷M/ É=áîv2\VÀú³{osuÒu ÆóN1¬©úrµöWì/ƒÉpe£³™Î;É D.Jê 'ÆÔœ§£túŽ\ô@¿øÃüz–fSý‘ ‰‚B¼dš¢랥kÓϼǪME÷Ò8¤b\WñA„Hè~ÅhbH òðÀÚ–tN’_ÿ nâfG¹-Öìµhýgq>åC>¸÷!g‹ðÿ×[{†²ööw>û p ÿ¿ÿèñÆŸÖ××Öﯛ`ã‘áÿ ãø7ÿÿ#þÿÖO€õoÕðpuýa²±±¹~óÁFÒÇíÃgÀ+Öý¡Àæ¦å½•ÏüÇ´²ûrwçÞ3üsïÞJòz“6¤Uóìh“}´ÅÒ²dÑ-–ðwóÞHÏ 6{èÍ0²#™¤yŸìAÅ;Î LK$Ä%ÛÕâ*±5 Ñ4HŸ:àä FË„@š˜œ`SÕmDØDʵ‡ |£Pç_ó§_Ǿ—êoJ ¬IÑ«8våÖ­h©˜NL©%©`ÂFDëî:ÃxŸéõ)e'ëበj»‚)È'gÆ…^Åà{€Nà |wï@ ?¼:x™l½Ù»ghà?!ÛyòS:|g&âé¥ù7=ÿžþ錳Ùó{†&ÜúF¿P?¼=ÞÝI¶Þÿ¸»oMtiK^ì¼}µ{µ¾.ŒPü”å³ßGfnŸ^òOßϲ_Ó2…ŒpÕš¶ß¾6ÕQeÛ‡;{û[LJPáÑ ÷7pey Zðwߟßfc8Ö*U½Ø{u¼{˜ýíèx÷µúü§|63'Cò úLÉï‰Çë88|­jøËÿóÿ5«tìÿ?ÿ¿Áµ9'’§½ó«ï!§3»0Õ9ŸWªxu°½õj—ç*y™žBBÑâ×Yy<Að{È|›g³D/÷ö_bÓçˆ×òCjˆ<šã,yJýþ~ã4Ÿ•ÑÉ4ùö{VcÕ÷×élfV´œ À¯Vz–ùÌìôØ ê õÿõ W ®“£ ä|ZÂ/å ×Q^›3ȦÑín¿=4òZH?f`ùÜɲ!Xu“§ç}þñû+ZÐÖ‘¡×#5®ÿ4ÒéÙÖØÜ-/Mß~Åß¿`UCô¹ŽUeÿõ®šàÝt:L^£›âÓQ6æãï‡Fb›óê˜}þŸE1†Tè†~5?~ß¿€k|¼£œ*ÄurÇtê]ò -OY°sÄKat=|ðí*â#õfئîUÍG¾}¬> :ò߯_­¾ÙNèýjÏlPœ5—þšŽw®ßÕW}ÿñÃÚšì~ô ÷úQ¸¶/³éy:í'17€¬œÞ¼i@O¿§žvúYliCvÇ›8qxÒ>Å×ÛíŸçüùMºàxõy*VÊë÷ï?ÜùoýáúÆÆãÇ÷×àþÿèÁ¿ïÿÈŸ§ß™¿'R ¢’×ïð¿-ÀÆÃd}}óÁãÍû<-@­ï„THöå{”ȦÙ@iswk{°¥wA/ÏE1ÙkÑÁlïeÊÑá!=Ç3)¤ÞÜó&ñJ§×F›\¹Éû$yÎ4k”c³Q>ÎGó‘8„ ÞkEeíý0 46_¨<—¾ëbÉFÔÖr¢ò~'yÁnƒ˜Š㉠É@î‹®¬òÇ1—LÝPé+º†xÝ}‘SÚâË •'iãü0Š,t„A禖bÒ ¼c §Ã!¥„^€Y™u\ù£".- VªÜÐR üKnóÎñ"‹Ð‡áö¸2/AAP猴=(X’¯TÕc Æ;”ì\R~¡üLxúÚɲ ƒ,Îm/§™?É-LÞTüOGvÄ“EãÇlƒ¼½´C ;°0f¾à £NÝP{3ë :’j°u¯Îßïž…ÈŸO´MY  8%O (j¼Êü ú“νz׿{ïRCíy¯Lš Þgs&¨!_Èðj=YÓe•Œæ¤AóÙøå¤!@]¥ŸvNHS­†*ë«¡÷ü®¦šJì?º™–"á AŽŒcQîc¸vg={s&·5‰y[à$gq¡Ðê‚2 ‘Q|¯™W=³»˜t¥ JÃez:A%.LÓëÙMÙÝ|›yý¤.Ilƒ`Û¢|äžN|ÉIaæ7ORÙHÁÇèíá+2<•¸ 7 ι…Û3€ºTïôiÃwØ 3¨©h¤²š¤‡»’L5‰‡æG˜|H|I%ºD$:ȵ¡[æUrõΟ¡BDbâuBx'X`² ̯k±CøKÆzêÂë.BG9¼¢Xžb"£q¡“ðAà•@GY¨ÍkÂK—„Y\a© ö ûJ#è¶…f%@… è+æè+H8ƒ!iJMÊû‘–ç§§Y4ÿ`!Åõâì:ÓÙJ/Ÿöæ9#—‘¢Iꑱ‚†°_EÞ'ä œ¡ò.T·â hw§¾àCo½Co¶¬0½tpŠtAÙFÅR¬Ëä£Íe4ú¨|öŒ°gy¢›Õ“ÿ›®ü¾µòºk+ßþ² ,mµA=Ú))ÎÕ'4FQ—_(@~?(fEsIIÈßqÑgRÙRÜ÷’>Rµ&à÷úd Îì¯ÜRg•_•«Òžý¡#pÇ*ú¸Ñ(^²:Ëìõ§&ÙXÏõÏ+álÛúÂÉnV+&žÛU1=úâ™çuù!ËðÕö,huÉ›ðcCª˜í1³ú^åež‹ûªL’¶tE$=ÃçÓ¡Ê ø…~€ìÁsM…|O‘Bíâþ%ÅEFö+ü‡‡ê]y¡Ï›+2»¾" WcÖMèztiês Rlþ¶©„\>ÂݹðWšÀUa…†C—¼È%,L¬„¥P±ø”}X+O«&G†É½4 °Šãâ²M·¦tL&A;°9FÒ—Å]îÀ’ŵ`XŒg¨´¤·@9$ú5ô:·XÕÔ,Ÿ™!CÑC½T܈s1¡H’̬;þ„¼–®j¤iðeÈåл³ºPd#.c€ãagVŽáF¬„Å Zá8œMóÁÉXÒ¬B%N|3O Eà· Ê®©N•t’ã"Zð¹Ç[Ëé©I{!a„%dqAvH9«¸´“‰EeI‘}+r´œ3r&6¬Ôh–¾&—gœ{týã¥N|ÝOO”’ºÐÖì\ åF:aËkÅ‘9Ü{ñíêöó³3X-­ó­Ü/Z>«ŒrÆvB>Ê…¦d„–J—4GùÞ¢!Õn’Ì+j…ȘR "9ë0ãÔ"‡ŒÒ1Ùæ(ÎÞ}Ï";Ú,ÍŽ™uPj 1RNð* 5{Áâ]2)7ôt4lÒkqw÷±æuþ e]ãÃØ ÍkÃËØÂÙs—1/FÆ4Iî²mü™Á§Ô9ðwÝfÒ$èºV(Ó' -’ß9zÇää¡e<"ˆrf„ѱZ˜­½þCiO5-‚ü’‚ß¡ùb›Ø5‘»½ôãICü™)…<½ga~#T+ó°ŸE³¹Œ!ªÔ/ª¦%±Ùï° <"äÑðky³i¥eª¡ôªaè¼×˜¹!„™G5ñÊýâú;ƒl}C³ FÍjÿfçæC¾«rœ,ËJwYr6 ¡÷ÂÁ¬Í ÜËNcUS£]\W°Ñgaücɶ(+H8ÍÔI€â¼m;‘m;Um;âv0޶î’>âÔˆAbˆJ@%7춈vŒÆD&ò@Ê‹m׺SJY/üª|-l¾¨ÎÍ&¥µÿ,FmM™¼U"”)o„2?a¹ xé xÿD*7^>es}øÖZ¶[è–M……Ã]¨¾Žî9'Pða»waºQqW„ÖF.ó`Xù9MN\ñv>öez¸‹‘ø‡³ ­cõ%ó¥’t¸,›/’ËyüXŽsà „C¼ˆÚ­7{?€†²Ü¦þ 秆[xÓ×üJ1¶êTZ d'@Y§wp{–”¸'E‹ P·²~6­Ð½vjsÄéÆèºümØ@žK?ç Ê(ú?TàõóåE.¾yσH–ÖO¤wÇc¯ „U€p=}éJù)†p‰Nã¢+ïî;Ÿ6ÿ@aÓ€ÿ†¿Ëì”yŒ0ËépHɸGNoƒ‹N‚ÇV:¬"@Mä5TsÎ*EˆMa¡d1ß3•¯mM¬*}š&ç†2ž-±w‚=,—ž‹>ºS>]MŸwl|I£òE`U1Ɔy®n<^ûÇQ\¶ŠŠÆçÍI]‚OÎ*e )ÙHfŽR÷ö»ò ®Dêj¹b„ÿ9±k§“ç†}Ã7Ç…„@ãüò`íìµ@ÏšI4Xe¢°…àú*<¸s œR§ñtÕôA'ó¨¡Ãç.¢¼nÒÌIOÅ«óçÏà4íçEiç¯:ƒ;šüÜ BAQ aY4©—ÒÄ—¾ë,Štݱcd‰Ü£¿š–_¿’¸„*!†Ý?•Õ´~þ˜< B>né¤7.š˜hWõÍ,ƒôLcI|Pï’=ÎèŽw8ðeÀ¯˜œflë°iùäVþQcsbr>Æ!×½ _uþ‚"ŽÕ7O\á§dŸ–Ï n¬í½väåøýÚ/®ŒîÀÝ—íK!ÏÊúIëÕa%¾¶.ìMnùvË¢ûâ¥!¡x“†äzȨk¹´× Ï¥Caoƒ¶L™ÿN¯eèú·h Äe1½Ã,Ø’w œ²ü¨Yhi-ÈI#í_€‡Eÿ3I)[\]LPD†t‚Èþ’å·w"gÓÒÒ1¦¯åfP¤ÆŒã ¬Ñéôšð À¸¨”§Åð¨†Í8 p <^»83‡À7® éy/|L«e[ü-¢kg©UKXç)\»HW¤øLÛ +»•¨ðúô°#è-ÇÔSëcê_‚£H°dè#)h=1åe§Ñªß¹ èßa‚Ikò™&+»}×­ôc'øN³È'0L&?9°à£¾Nát;&r÷ÊC›Ôc¼—Ò½›æ”~6Ó¦4JˆX\|\ —-ÔitEó»xY,ãF÷ûëBz…ϼ2ЊqQ§€rlÌ´Õ¹äàƒXÞàZ–röžpN¾|É¿óD5*æõ1ò1$¨Q0%¼Ê­VôÐTØÅ TÎOG¹>&|ý8ɹwløæ< )" `5ôC+T)Ýj¸íËÏÞ‡~]Ò<-¬Íÿâ?R‚‹/;çt’ŠÊwÉR³ªsƒ¦Ä²±ŽßGÿ‚ZïoµzÎ?¦ÍC¥ë]TzÊ¿¶­â‹)ü¡·šU\'4Å!3ðL$AºR-*A’ê¢$Ä-*AÇñÂ:ðepÓÖ ^ ±-¹P}­±žV³ª4wЉí»‹æöD»**‘òàü«­ìáy|nØÓK·X+ŽÛÁ*±™m£Éìì†Î͹¸ÌÙe§)UbÂ+ó`R”êYcsuÕv>·éÛM2ޱê¨ì/©fѤ"ÃÃI]ÚcÅË—¾Iÿ²„§¼úDV ×W3ûVý#Böyq ˆGTí›ßøî{¬Á^;•¿(ú=†.9êóy[õþ}È*1½Q«ÓÅ[öa×™èÄ®xײVÕlLFRfs­¤Cª\´¹v³R ÞáôÞß7ø´%}”E‹”u&×L¡6å—%[iµoÖ:虉¼ ¡˜f(Þh[Åû€ôhËFäì)@ª¦“Îäyfe}H€Ø5=•iUn ¶xÓ5ÉUkgE7~yÒØ>ØßßÝ>nøiAn‰†ÙŬGÊ»Ô;‘Ÿ=Àv±ØérÖÇË(•r*ÃK‹áæø^;Ê)•ùP'§á;$éiq‘a &«@^éI`‰ªEœøœ  f¦«åfò¥üØIŽ®çæÜ§žËΆob÷À6ÚÏ nk"«3m=üféù^å<Ÿ ¦O¸û§Eñíg¬K¡Ì¤c§JÓœä&WW¥\R3!|˜õf5ŠubÉÐq“Ò?‡aæÿ­Šò·‚ªYO-òŸ|h"²3]g>Qr¦Jn—›ë¬ä" ½ETs)nûAV{Xµ’Ò]ZK2°w§Ááòm~.Jào¢jß-dÁ5þNMj¹ÿ¶F™û°?“òR’Ÿ\Иìyå>+º Û½÷Aqs•ó„÷ˆÇiú ‘” ©†’ÎLi9KŠ7><K#*véjXP² Õ:ÿYÚXv»«ƒ©`ðïí¿™û7ˆ9Hp©Ié%œ¤ô¦qXïV"jdÖb(žÇç’õ•£|ëø¡0äÀq7ßKY¤REyøäGA€®sDhxŒ9PøFåÎ'hˆŠ3« ,†ÊGÎA9º²Äu¼ày¹ò\;¥¥×òJG·T;£ ëSÙN À(Kœ‹wþÚèÀÑÁK ûWØýžÅÒwWû®9.‰ UÏ-ùˆ¡!¢GÔê(H. icyF-ðÓ„z…•R·„9D¨C• µrQRö4ñ@é-—ä|£‚ï:Êf)hÜ1Ÿ%äÒjžã­š…É”©i Ðû >Ÿa¬ªÍ|†X¯1^ÓºÓ^äÖe¢ý{°wu¾Ý1B,ù‚h…²»µä­9G³º×”ÂÃàdNÕ©s9z™Rãšé™æ™9º:ÁØ'{PK/¹Ö†‘Ãô¶‡/yæšiúòºÌ݉ß6#½ã×Ê\’4 …YAøãÿ?{YÖ®‡asâH:¡%X‰Ø²!a›3U5S,V›ìv³gzºÙ3<_ÿ’=s¾ðëSÚ¬Ú$÷tUíšÚUdó|ݱáÄ‚( ’JbØFâ‹H€À7ºP‰¢$€HlÝ(¾0 ºI "A9YïßZïÚ?UE6§gF§‰ï›&÷^{ý¯w½¿Ï{ÛZ¾ ¦ AL bhôœUÝTR¡M­ÀÓ!y•ÙºpH÷Ë ÌýgÊ` É-Ѱ9dŠÎY™Ð€Ä&h½ÉQ$É‹.‚Ó©a-W!Œ ™t¨¦˜*†ár礆Ÿ¯R«8Ån«ÑFT[ ÜD¾ó—¥’‡+ÒÛRu9ö¶P[î\¬•¡ ޤ¶`ÇX` Á¶Ë-’R4»q€ SEi­æ–B6Ç5™ž Ì b®Ã’äŒïœ(ôÉlsåqe–…í œzNAî±D%Éô2ÂÌdUµ FÏyÇ» ±Â¯ ‹ÍlV }ý=Èþ“±£è>V.™ÇÅQÐ*Œ™˜s.OãcHÍ@=Écæ;|üh˜AŸçoå™fýÒŒ‰œÍÚ¬03ï–LÌ®›órF1V ²“†ªØ=âÂöy^þ ÏßÊC¹KLï6û“U3›UÎCPó9_á%‡ÇYG]\™Ðj+=’§ÜYb ÆÒøèE© þ ‚žB,ÝyLžùašN‘Ê3ÆV°<‰ü§ØÃ^Â)ù”/ÞgŒuà;]žéxFà*U§ØA*YÈrŽ'› ¢F^…Œƒ¹××1¹HåOûh‹Â^/æÔ²¸?˜q ì—:°Á(ì¾D°Ôˆ¸)‡äNá·‘©€1ˆÈ÷ÖTGÁž.£›øtw!E™_9+•¨Òi­,'節ŠõͽhF:íß½Óe¸ŽC0Óæ|¬5IZ&áØ0ÍÛË#ÓòË廡7¢ â2Ä(‘|Œ˜õØzÔ2à{^*wAp‡AX4ã·¼­ Þ§¥Ã3Ã̬¢¤…êZŒäØ›XûÞÒ&>Fªàò(y®ý”}ë ð’suj½GãKüÏ͘bû÷ûZÊ•,¨[LN Ð<”ø¤pvüÍæsÊχöƒû.z5ëºÀm‹Qâ†ìãçWE¶м5CÔP²vN‹ÍYÒçÐZ—”­¬èTæaèøô-`*¡ZOŠš_ ^Ëöì³1Š×Æ1*}†Jp—F‚“È0.S¾÷VIœœ„€–º¦/¡ævb?Ã8ˆ¼Ö™ª–…=W_^ë_¶¢Ìwa~y3Œ~d×®©Îsj@8ñè,5` 8nÖ¶¸À2Âç CÌó$OÒNyðà-NR¡Å ²nÙZ¥\Á¨ „¢¼ó{11bZís'ÜÕÀwÖ̲šðêb EâWIÜ]tËämáºH}Qldáª}§ž/¡g«fz×(å=ô`ù.ý‚wlk߯FBÅÉÈ×±|×+™þª‘Ûv_> Z(+Ì9vË :¢Ž¢1p•*„¾;;û;ûû»OŸVäOŠ^XÀ–ùxáÁC™Âж]_¬›ÐÞ#Bx]@쀸9“' €]!eÆÀâ :AžË8»‘®@Ú³ln;HÔ† ËvŒ ÷<›CâÀå¥AQËêyŒ;‰`Ì×Ü{müNëË]®xÓCQÍœO»“ƒgðÜ£FØËæ[ðñ„ÏlºSlÏ É§|ÆS¸þy‚6‘ºïk¤°'}àáÜðÄžèð)ýì©sölöÔ1¨3Æ÷8n¤×A]‘ÜlÕ½¨_^µÔ Ò¤„,Oá-Ýv—~Wœ¨«àPEÚX‡_îé8éÛñ¬HÂô6CÒß/VÚ•}«È1’®y"^îoË—ÈY‰£Ê¹"c½[È~懡ñâÃî÷æ·Áe ?}õ@"<6îoðžRȽéžá•°&ñ² ¹J _šó$·Wi1QÒâç%R xà‡G+ O4_ÌŸæ@"™ÒYØ‘%'Ÿ»Âƒ š‘úâ¯Þcip…îA {ãQ…ñt8$ºpÄ)ËèÈúþ•TŸ]›­Ó n•¡#YÄ#3vÈÏk)mhLˆ~ó2nL‚Z£Ä‘›°˜´±hÄÉ>C´ø£PÏSÎJÐsFAŠ1ä„C+‘ý韯ÖU¢¯Ì¥?2É4()¹/ †î¶ºI>!#‹[+¤x;ˆ÷†@¨reÓ°&cNº^N.‹‡¥ ¢¹Éµ’/[æ>ûp›mßÊY8àŒ.€7ÿÎÍXêZ5…9Œ6†b4•qXƒ`ߥ§È!dAˆTù[ ž»t?飜ÇÂIÂIx‚!@8Ó K*¹?´~G3:åÈ"ë‘¥Ž…öW:¬™ÜÛ{†¿‡x LûbîZ°*A¨Æ[€ã°£æÄ»üÙÅôÉ«´PøìpìÓ¶›s(#o½YñZˆâ|˜9]œAçÒGwZµ8æ!Uø)Ç”ó~2Û ôãpïÇ'C¥>I Ô0z5¡)ò™5”dQÖfï+£Eð<¢å÷Ìõ\Ÿ5ƒsÞa7jÆý:((yöl¡}H…HÃ.„k‹®6¥ 1V‹’QÕ9æb­ò…æ*ó\>Œ™¤€Ãžp`œLÌ•!çV(ówší¹«ñlß]Ȫ0œSᙇˆ¸qŽAèæü$#3&ç—Çá¸ÐRͲ«U¦ëhÿÜõ€hÆK-È vÅx(]D“­àÙ8í‰XäK@<㥪vo±Z+ß-F+t®ùïÀLÆŽ¾4Ý™¥Ó—Ò® >1$¥ÔÓA|åÐ<½/󀞊’ûxùÎù œ²2á}wítvþ`wÿà5þº·sïÁ½¯íÐ_Ožt¾ÛÛ=€'xT«ÚtkÖºh^T¼«¥LŸìë}¥_#€¼,?‚±OõÎ †l¡&lö(û” mGs?qÖY½ÄÛ d=–¸40!Q ø/LÍ'¸liQT[E{‰iЦ%f½r= huPƒ“ Wûà¸ã…mé``3?~&Neå£ᙺ…27•úhUp¨»óƒ‹ÝÏYµ¯u…0˜úB=Ä‹8 €ì¬¢ßÂñ¼ÍÌxhî´Þëõ‚ß ÏÂ}T¾ ø‚µÎ˜vð©Ó»0Ô)îv\AwByf€?ü>­*šˆ¹ 9Z‚óÿ½F¹ˆf¿Ci6D b <Šê6žLx5 íÒ"ñ¿®Fˆ° œ¦óG7 ‡Às ÙìŠË·Ö>Áo@ź 4pÉqö $¹7½Ä-†‰±žï=ÒE9PÐ-e|i_P¡ã)\aÃJ 3/¨ù8 'S€U–šî~¿VJªäÁñºi4]X-z¾Î‹Ïlm¬on,ß•3Hš5ÓÈ}ɆȦ¤¸gçDP¸“)x»&É$‡í £›N“@»Dci£¡ùP–wFÎ÷’µ)<¿&,$%~y î vyû>%1©ÇŽÑÕ^ÒBz‘ZÙªó&`ºÀÊꦬNAp9\Æôî Yfßý‘a,˜ƒ 6Jî Ñ;¤¦4=˜:­_&Åšl`($гL²Že•‘ÇÖ¼qž¿ÇÈK‡l|E†$µgryd!Ù㔾&•4''ÛS =eñá$žféûÎ5ÍÆ€L’Wn¿ µA0 Ïå4€‡*ëM)2g[é[aPßä^–^±z¾æ€ ÜP´ –¿¤ '‘Ú@ìJ<¤!P¾Îä1g9!1‰ö™ë ¥Âl"hY2gå– Z}ºdµ3‡4Ý=½ ;ßN³¢Ä(•ÆS&!u€àCä(K^H~ƒÐ+íxí·Í‚ 3ÑP¥®Ééo”uN3nòü®|Æýòv°"Ð2<ý(ë:>ŽNÂxHßË–ƒ 3Ú(IL/%Ã*™Oð/¥õ)WF9ÂO£ØY\‹쿌GJmáêpBÜYDø©<(Úæµסˆ±óœST—ÊU%bLДs8^IZ$½GÛj¨¸`R<¸çƒð@á¾9ºÈrÖbdÝBYæ ^3ƒRæ!«ðFb_bú—å‰]©é ä|¶½¨Û¹'З~‘ uÒ‹a×´3„¼cº2ÓÍd`˜ýlUDU8ƒiºö}*Áêf*N!Ç+*àBô•'Ž}¢DÌÄbñRÔ‘.²× jô¨GœØ­sÜŸ¦æšJSo¤K3“Ü)d6A l\P`@²0ñ°†»¬'ØR‘_œ$±›sûH1êÂS:´#¤üf‡!42Ÿäs ô'ˆþGü&ïH FÀ¢ONoÿé›!C¤«]TÕ ¾¡Ï ìr¦ì“/›ÜsõÒiÀ |øµ×ðWÈ6Y )̵gϵ!inÿB"jçåtÀÑ4øxÏÜ+Ξ×ÉPP*+ ÜÈwbÖôøh›}~Œ¦äð<¼ ôö«É¯4–ª‚h%:PYß!ØCaÆg34Îr",Õ#N–ô¢‘!ZLYNLÃãȼbç-èSì ±`9‰Fx¨y¦h¬UÏy£fÓMÁäV(­ Àþò‹ˆ·Ã Î`°kçí#žέ©´x¬ðBuZ·Oƨ.Æg™¡ÙĶpÔ2cœ+9Hü\Ð.r^eû«Ø…D![q²EvK¿”PÌà‹“ã¹HRbvqÁ±²šAì檈²nø‹‡¯8ne…[l¬-xÕÁZŒ…ÆZ&]q´Ú’®|*UŠX«"ÉÕ!VÔä•8UfÕ7_Ê*ke¾ <ñJ]tJ7h™íº^ ú— RzfêÂ*yYFÔ£ÿ^jº…m¢*›q®8âI¨ÍÌY-ŸK(‹8™”‰‰•˜öËO!Ÿ1ÆT.vPSÙäÄ+`gÂ[DA@_2…ße“øá¹‚üœTu~o4h/_c6˜œiS§Ãšeë³ibÞÂç2Ž'†ÙQ‚‡Ð7•Š"F·¯Æå͈ÖH\ÉÌéà Ø9r;¹Û»˜ñÔuÕsb½d¥¾A/þe»å›\­¹µH@ûŽ:íÆQb¢2”’Q9ˆ…S´a³x›ƒÆu„ûžœäÇ3,ÝIúw—Àsý~2ºàÄEÉc«Ð*ˆ'ÝÕ©8åŒÀ×Ú2+ü•?Ï"*¹Ôv3¬²FlNr5¿½™–;¿#~ R±E¡Bãì\J%dÂ0$÷ÉþÁ½G“W“«æpÖN6ÿzÓMo<‚Á¯áXÔlLs½ª¦±ÀrìRwÑî”E{ÛýYh¶'£ro:Åuá¶|÷›ãº–óz—ÅGívnñú²ätæêòµŒnVîuÕ“  !ú6¹p¥uy]õªÖ(;.HÐzërჀiÕ-®™í`oç÷Ÿïîí<ÞyrÐÙÙÛ{ºÇ·ºvn÷¹ˆÔY!¦±zHÿÔ#+–½,팽 x›ÃíåÕáÁr¹ë¦¬? XÔûÆ5ªš`P¤5sS”Ň D >dè·qñ9mF¯)òœ‡Ìoö›|!éháj %Âréo™/ŠäΞ¹¾»·÷d÷É×?—½ ºó~7\u7œ‡ã¡çÒ öC Ïz¨%( 2Œ‡rV\¦”x ÷<‹¼äˆÊHŽâ"ÖYuë Éu>šr&@VÍÎ÷=<[ ýÈ ÅùÑÁ‚y@¡ÊÙ¯˜×÷ É—6cnàýØhd‹\Zݺ?´Lô‰WS66_¦Ì¶åc(ñ—N¾-êeÖ3“C¦—VˆÀ)ˆðc>ÄnŽ1SˆC ý‡EØ``‚Å€èôõ(xôêØŠ´ìÕ˜ÝFKÖx0&@‘Übd€àd4>g®Æ]}˜ÝÈ≟}ío†ŒB—FëÝñÜâ¹ÈRßb¯ÿ \ì"^+xŒ/ B*ŸYÈ)â_C%}!’†òé¶ÔSt‹ùsoñ-împ«ÍCßáÖ3o2ÏÄ@žÌf=† ìñÐÙØ;B`¶,l,záa•ÔåYTœÝcÕ2x.{’H2mœ5\!ï(ÀG4ˆ"‘ÛUN8‰Fpé2OêZζKdÆ™¦uyhµ{–¬1;'ŸŠá§²'}¥WUf˜G}ͶtŸC—4*vPÙŠm͎ο‹®'{MçÕlÎÅË»ÉdõÔÅËÖI3óÑ1hþв“µgB”*Ê(égBÁ`<•çvY¦¼ó²00˜&ù:ÆØˆÁ™)—¼ ¤q( 8‘Ï£#è‘ó©0“Ý#ã…ÉuŸG`þÁÊW[M—UA? 6A}˜ï[i–ÖljD ,ÑUÙ.d3´’ÖpnOUxÅŒne“6öKç.Í)êOV{É:TÁoÛErJ–XM×Ù<²ŒÙ©Y {ðQ£þ¢0¯-BE<4% )‚BJÂ4d‡:Á¾‹¬¦ “ÿØ¥o[·x˜™ž¤%;áÕç)¢OH‹lpN¼_Áÿ'ÚÛ!Íh .–ìÓÌss!Áê‡''}lº9 Úòå¶µ‘]XÄî°û÷[{PÍUn TßåÎA¦/æûõÆdÑYuoÙGƒpür:šEi*wFA×Ü,éö²Ú/>ïáh †ƒ®@Bàá!¬¨›•¼ ºO´)û¨–G)¯¢^&ÛYKÀ,†`0™¨¶á@!¦&‰NQ%¦t¯/]W7SŠ;ª E¹¯^FpSMÐBÍ £¢=ZAṲ̈ ‹-X†v]†&<Ïd.Ï&Š}¾¿³÷äÞãÎã{Ðy´óäëƒofœÿÊþ(ì ,\Qïv0‚Ûljño‡; ï‚èU7‘;ªÍxz1:†|нl€—<—›Ã q½Ìî”T&wßÛ}´à4BØÐHËr˜†Í¾‹d+!ÊÅmS4†OâeÎ!°È¬ÅQ?îšÔƒ»úˆœ·€…uð92mÔðPø”جU¶„ì~S.e‡MG˜Ah¡]vçPoýŠÙ¥±'^ ¢.çuŦQnoô.¿»Hßl“8½ Ca>¶¦K²8Ù~‚|™é†Ÿp„ɬ²$[Ü=Ñò@EÖ4ƒ‹hÊ+É“ ;´—;ð1a Î: _]A4-èÙBÛh9™ýº§Fòºn³«óò"´ ³eAýÒ’Is¡N—ž-j®i§?N1 B Z– ùÙÌ™Ä[ªFk­…6 AÜ2Žr;i„©FÔÀ0ÛÝ ”»_ü°}g “)6EkjZ{ÒµìYR¹[+wzñY÷¶©9Äìåew+¦Óc÷ášù²ðÂ, õ‹Hˆb(6MSvr›µžhØ9J^EekʹìÀç™G(ûe°à5?”Æ'C.ªÇ£á)zYû7•Ô…Ã=c¾»c¬dxr÷Ô,‚È@nDÞG½;küŠ[°fM[B#oÀH#g`x1H¦©ÉçÏ¥*èiÏ›Äûå»ÎZH™!m’J]+Kù\”_ÒÚY¤:½ t3,Ÿy«%©Â2»¦Ø>רÏQóÔ¦Ñ'£€¼9ÎkÌRSÖna¢ùÎ\<+1ü’‚“Ö¡gëH@1ç¯ÔIÆÌ~ƒÀ4»u©ŽŒ™N…’¶¡”1\Љ ³@ düÈá8ÜâPшN|•VtJ0o€I¿×‘A BMvð¹æ} ¦¬Æwˆ¥*áD˜#¡EÑÁFÞèF§ˆ…P 0| ·$… Cæ z·„æR!ñ‰†HÃÌa7ÑøÄl H‰iÕ`.`×§ÂÎÊi­Œ@¸t "bà‚Ó}ŒM`“еªôƒï‘¶]¼êºg5‰y”œˆ@~ø¤ˆmvöô]]{dkÍ/gÙÊèeÆA mÂø¢"§³|g±KñR.}~¦•X‚øêJ”|]‰y¶Ã}…ºšó Ÿ ê9ϺÐ!¤ª£Œë» Ú‹¡–½‚”Ž"keä Ÿ¼B¬=G¤ ÛŠ'¢kÚ]½›Æ=°GS X"â0® Ç–!Ó]&°`ó‡ØºŠÄH៪˜Ä$þ9ãÓo©N£=ùƒ_Ô‘Î͵Æé„´Ô?BMó³yó&þÛ¼Ùòÿm6o­ßÚø Õjµ›Ív³}«ùA³u³½±ùAÐüú’û™ZR|p~~¾ ¢¬Ü¼÷¿ÐŸK7‚{#À"^{öͳ5–¯Eí°µtcÉx6N&‡„' 'ˆ#ÖðŽÆˆÔ}÷ćPð1¿-ÿ¦Q†'ñ0z»¯e{ÍGæ5]Ô¯YÖx x8¯GÉëôôuã“ô‡þk´U¿žŒúÕ߀Gsí‹×¯&ƒQÿuz6\¥ÚÊë?¬‚Bg5\ô#S¨ÿzgIÓÆ'¯÷¢QbØžd|ñz/I&¯“׿¢ÒòYλ!Ÿ¾Žè“×ÄLÖV–ïºðáÂPÓ_ïEË¥;knTwaV(y >Ç.º¢OH奊š(B„#µ—ŒlKOIìî{Ñ«(…J¢¡:H/G ¨º)žX†J_ì_ AQ¨ã12ØdÃæ?¸n6oÚ›ø÷#ᛵ:ÓLÝw)ç)GC˜˜3ña2\E)ª:ÏbÃ7Ìdèg0³7à¾Sv…ƒ´˜šýEIÍêX%(>Ìw÷A ƒ¼ mÒ ÕXªï?Ún¹_Ѓq ®aä7 ‰a:4 '¯&.ä~äg˜¢93¤ýL7.PàÍÐSsÁ½Àè<&õ Ê©øå{=æ[ä=¯Ãirˆ.Ý!âŒAÓÊͺ›…¥;»ÇmfÇÔ{³Ñ…Ù5¿/a¶ÜIÜíàܦ“Q7Èü4½Ò²Þ!a%]šoÚèý:ˆ77«ôàˆÇ  2l:&ëVQ”}À¡Ì }ÀÛ`7ïhÇ(èÏ5™°»ùùlëùLÃQÜ ñEûýœ^rN7ÜÅ‹¢]°S7ÞÏê%fuOtÊ0{Ñ«…u%@+X-žb.D³|C¤q|êŸv¨Ð=r{:\²÷qé€=¦»ˆqÛˆÂàQ¬ú2TïÕT-bR»g˜¸Ï7›MªìAB|X'c,¢ü$â¿¡r#ÉæÁ}uq(`²^; ú¦Æì||kvМ#Šš€?ü’¦`þØA.$Hx¨»ÇJKÏy˜ipਗ਼˜+ï²5“ â #بdÂ7XT¨EàÄ˱tŽºÛ;4:s>\\ÒÖ¢žPþ0õ ŠÑMè»ÝƒoÀ* ÿ>}~ïD#`'á§Oýš:€¼ÁTE÷­j6Äš3o ¸ÛÜ>ààd2)‡&zSŒU ÜøÜI†˜@o²qÌ\‰ÝE»™–%ÅÎAáP »VÏ,þB]YÒH±ôh<*¯*Sÿ¶Lí?l¿ÂèAØÓÎþA–Á“êMðáêñB¥z¥¥žïíšÛkŠ?weõFÔ£øûû÷^do„•ÝÞV`õ3ÃÞl´ëA»Ùül­Õ^k5ͯ[Í›[ÍÏ‚Ã4Àu¬üÂT5?Êè\ê²ëoc¶þg³µ¹ÞbýÏÍÖúæèn¾×ÿ¼›Ÿ;_€H €¬pˆÜ.ÀSÔÞh›cÔöŽQ{k½¹ÕZ×ÇHlk_ÏH{ž[ªMD†‚5Ð.q±I½ø’à`C¼p‡è%-ð0Ï€¥Bªz4NÎS‚r_.¹fU">¼FˆjÕƒºbÎ9Ƭ0Ö¯bÉáv±l„¤Õ¾uv2DdtººÕMA$*Dï›5èH¼M£ - {Aãb`(Tp™k ô¨wG«CuG Maš3÷Ý0­H°äqJêð.Fü¢œ€Sc|‚Ià°?¢QSVQ£Á_‹££¯Ž›C¸¿¨öTÐóϘ ŸÏÑ[*Ri¼Ñ|ÑøF j +À¿!;¡ù›2(A‚&‚’3ü‡öcöŒOˆp‘t¡o¶¨Il…–³ Ž¢k`þÍú$0Wf_Áõü Y¼PŸÆ;´‡A–ü{HTé]#Ó/…®U+ïí>90WÛ“û;ÇO쀣‹o{¡ª¡©³?0¨°Í¯HÌPz1œ„¯¼ä•p0ž%éädíÿþ£&ëG«™ËÛ<ØÀ »¾2Ž&Ö‡Û}b$ç-²qà.ÖÝ@)æÉÓ Â)ÔðNT >N%ýÇ'A˜v…I7 7„‰#Æ15Ç  1LrÚãlœÂáå`~ηzÕââç¿é˜ æïÌL#æ‚ø òÇUNo4±‰DS»áXÖ#(¤'æÑ¡<â¢þr/Uä-1¢Š&½b® lÄáÊâ]×JÓ6÷ZuËöþŽ}ÇιöP[iëÁÓÞó_厡ŸtO¼Åå [Q_àW»±–í²îá‚Éüöí®Il*à 8nË\[3êFÆf.[냽§ÏŠ'ÆÝíÏ8Ò”Mð‚Ú„ &':ܽƒ·Þ>äƒè…æ%HÁqžê²Ý<µXï5=|vCgWT|lcDy>W=/E?)ÜÛA àá®tB“ ëìPç:LFsGßí®â4 · × ŒzkœÏ%˃9tL*xfI…ÝÀÁ£DN”ÒËtLÈ|bÁÔ­a_:€¢¡ÍzäC™ô¢ ÷3Y`»è{Œ)þ&ÒI*©/òÕ$H6l¾ŸLî£ûý¸û2à fHj½óyÙ(˜+X*H1Uá‘95½Õé{íåraËTb첚Q̈M‹8¨-% ×ÛH/TQí²^œ¥[a ƒy(ˆTœl`ûB˜•}Z8^,NžÅsÐ5ó»L0½ CË'ÊåÝê.zf04'7²Cɵë‘0(&©C¼+=xÀsÖƒ,:¿ƒ–•Ú@žçë 3{µX¢%]÷Úö˦^NJNy ã¡8<Û|*v&„bõ/ê„…p•ϰc ÒÿCÞ?D\íèNíÈ ÌJ3ŠX‡Oýnw·ƒ¦‡öÏY]È‚Ç;9%“ {„ã•$,~„&„¡ŒËÕ…À {u‹ŠdzÓ´)Ù¯ÃEÌôz;ê)GR—ösf‡uǯÚC{ô7\U€9̰n¸ê˜| ´Ëw¾!ô8/†«_äKilù®öéL¨®”++’ueÌ{”î%BÄz˜BVµH–J±€õ“—RlÅüÕq 5*"Jbìªbiçw{²Í¤kXÿò]rë$D+Q)#ÕbÍR% —némùV´ƒò4,ÂÉk;Èb p] ¦5\ß¾88ö‚Ó)# 0ôçÔÊZÂÄg‘… KR9ð¹vߎ· z¯Úí=‡SPõ4PòPS§r4gf˜ dz÷kÍêGɨ ù'ù õN¬Íâ­çTø~\±å»9MªÅ1‚ê%ËLŸ‘9ú‘ Ó¼7þø Ï aè.¦…#Ö^8,¸Ìt¸+~ö¦÷\Á¯3KеéÍð.ƒ^r"†vYÈ0æÇsŸÑ*4·Fµìמ~exR»•ÇQÔ e;g÷³©kÙlh™µ=pÊ5òä{=˜kð„$Ä{’úÿ›•|í2r/èk*¯=ž¥Fy‹£3Cfšß7ìšÀX—^ÕõœCÊ)QgʘÍÝÚ¬0`*…èUÔ’©EO^ùíU4sN’J¯réå„ï§mÜÕ.Hú‚TD:tgÍ”ãÏ›\~«fXf+"íË;§ë¾n í/r¢§Çª²ù ÚàŽçØV.òáv Êô,Ûª»r“É(Qþ¨y£2e>›öý—®³2ÐY´ˆúsñÍa%GàKšëÇB˜ø „—ZÈðú{ÝýŽé\JðãùSÌi‹oŽe{.šQoˉàJпã®ç\'²žÙ¹(éh—ï>Idç›u ¹ß|꥗ñM)CõŽÜDlÏ›qDoÏ(å|Q> h–³ô¡óÎø*ù¯§`ðæ  »ž.y ˜û) I˜°©Àùu<&Ú|Ýù>µ\×CxèØr Zð12äâ½Æ·lIo¦e½£Þ"öªÂj:I™ž¢ l|µò &‡Öe•býM±QæˆXäKZg&ÉËhèËáø¨ZñŠù\²ØF€›N[¤Œ·HaKÖ–*[¬‡¨ucÚŠÖ&Ó’Åb¥¢¨yµh…õ<k^y:4WØZ{ã³å»»:óÆL£Õë:?eAFÌsNŒ6ƒñ€|@µ¥Í°FG!äžýeØå«Ó„´÷œCe\h„[†¼°¿.盳,Tç+¸œ§#v³°¹–=C: þrpD)¼IÂ4K¡ zؽÈñ«c<¡à¦#Êìz™Þ ¡zúÅ8Æj$ŃU웲uÃðPðXDèyá„Û–h“ [”*°{*óÉš}¨A•0¤ü;B\™c içUmyµ§¨Ï¸0K s§ƒ²1å½ûl:ÑQÉC(\.@ ×µ_ >dÈäå»ê˜†ÈåÏ­4–K&Z²…aGà`½ãùÑŽÕ(Š£¾ ˜B6ºlûòU]+Ù›£»ßI˜Štœ#b¿I4Bá,Ê [xŠ&-±ƒhrš6ndNÎr@`ÁÂÔ‰ZÆr?FBµ 70Q1ÑïÜhkUMí2müíåûl\XÖ / æO#wmk‰˜íN/ÆQo¶JãáPÑŠV 9õÞ’MËBÑlå?¢óháà´ƒÃ\ðŒjŸp9‚ ÷A V}hF•úW³„Ža“¨e˜Â•…K´Ofˆà¥~Ÿ”…‚:‰‚V‚Íz”žb ž’`°‰ž>‚"Ã)ÐÊŽ“=Ht®ä8Gˆ@ø†/,ÿöeÌQdƉŽžÈùÙØÜéí{{ŸRÏO¬W$ò–⮉@ì§¡çS±ÑxCÛ4ÿ â“Âsâé€MQŠX×*ç”#¿IÕ®=â–²·Œ!_”±À”¨°Ô÷‘L@‡—ÓÏ<Þ5Ê¢ÇrKå(îIÎSgíÓO»Á`ã!ÀºkwšÀEȳš++x­TJë= Çf¡b•ãgóæœJãAdˆÒ`T)¬ÔP¦Êì $%lI¯€¢æje›ÏÆÌÙ &k —¯Ö0é®ÁäÖ¬ý1½žÓeÔt‚Yr@UÖKD¡ÍFÛŒÂPxdõÜ>ðŒ©æ_}.8 Äba<Œ07¿¥«â ïW¤˜¼K•ŸÐ9%É@gq+Ï»ìAî©â#s¿êøŽAìX–òŠçŸä¿B9„°£þZ]Þßy´sÿ#›êÅß°Œùpïéc7¸ï¾ÙÙÛ‘WàcyïÉ,ì> ª±áWPCW©Qœ)j%A+µ{Á¡O޾7+g¼Ø™ÙÎPTÓê]ê¯ý:¢5³z •Š>Ô®¾6P7;LS"@d~ 2ÂÎN“§ ãÏp~–mµo.‘ê²™¥åºßGÃÄ/ˤ½)ß‚ßDýàNÈÞ;¸–ùœ >I‡´ƒ’MU2É<¹¸ºÛ"±fÆwÍK¨ÌŒ,‰þuC4\H}ôjZxæb,Èž®G¸ãD‹ÁK@×T^nÁ­1]“ÌN”%.Àª5â[ßBV㣣iÜï‘ñ²êT¨#¤¡º±ªÓ\Ñ!ΊR s†êÌ{ψâWM'CÕLÃ(­Ø{]äcŽY˜yÇ›ÙÒWï‚úâ°ôÄP5W¨à-hoì=vïQçþÓ½óŸÇÏîì~µûh÷à×îK&VD„ÆQÕ0WâQ«ûõ‚ÅúäQnúׯçÎØ-+ú“g*tX û!2ü¸Ëm„­ó“¸S¢0Ç cߎÍUMzÅf ˜Â›Ç´^ÐŒé"¼@"OáĬÒ1'(IB@YIXmìˆ@—Ãá„â’à¦8ö>‡[ÃЩ2—ö/´ú˜oW\ˆü¦m K–ÒQÔuŽG96Òñ{é ÄP\È¥YÈi­fdº…AC*õ"K Š d×L'æ}ea} êŽ+~j&nZúié·¼B˜Yé8q™»2|vmFó® ~FR4"«‘õ$2SÀèO¬H„ÁŒFäDÀÐt:~ÉÀbΨH!”´Ò ?f“óï™q’LJ†bÍÔîeÆ\}ù±(ó5ÆUZ*(í Èìý£ HpðÎcŽÛùñL·óâ}Šêêýc:ÖšÈ}i:†Ž""¼¬n4^Q¿‚¸#¹ù‰öœç#Vð[/ Ü.}NxIºcˆÑEãAœŠo_Ý´ÎhÍ| ™h—m§XeÞK"²®ô¢àÃp…‚Þ–ªvÁz1@_?Šå¨Ô”Âo·AE@MPQŒY:°X!PeU*ú¢°×0„@‰‚üÍòr#˜ŽûUªm ¦bMõÁyÀàé´Ñ¨¿«–þâEï¨F‘šàôÃCEÁÖ=d²3NjÉ4ìetiQØôevb#41'B‡X7?u-5ß»"$Ö á¤âtÜL]“qܵ÷´„ ňP ×Bê9Áο¤æn¡VÕy¾¿ÌÞ_fï/³V.³·ãó¡vÞywf¥’Ð+¯t½”lÌ‹…ùòM°3Ä“³<ãn]–dCÿM /&q>÷ «`Á+o™K‘hÞÏ2Ýô|ùÿ8yÛ6æÈÿÍõ[¾þ2Aßz/ÿ¿‹ŸÛYÁÿ8A©ÿ&Hü·Œ¸¿Öü,hnlm4·6Ö [»D~ EÛ¶ÌÇ’’ØänÍ?ÇapjŽ"…AÐp*·l( …!Í OÎyÑj:MOã†ù| ÖåÜlØ5øj͈ AEÏp® C|ü¿ïEgQ¶qº—U«ÓKº)×ã¯@aU¯ýñ¨‹5 ìúÜÝ Và/Ba ª bµaûƒ ®vК0Rãt2èSÅ´…õÑ+è‘w;1Ù@àøÄWAwTªÔæ½­’ 3{Ž‰Üª€ÜÐöÆÃ ,r4/ñöि¶µz€¾öº/V[å(¯©²æM¢`·0dèæ÷Uï®l'Ý$f`Êœn±Y´0}…è|ÉmÌ퉑àäæOM›¢Êtn¹åWˆÒNŽ+NçËÏe]rU‚B²ôª¤—xzªÃùÚÕEÌotèJ—×ùæq¼Ô¦'Ñä9\¬0õ©UXÁŸ‹¡‡^ÀøÄ”áÁ?輌pœ…¿YeÙ3{œïÈAÓÝmsX‡C†?Côû‘ÅRŒÏ st‚úY®oæ°v1|wÞ :±.&)>'ãiwr…1i¥)YÜ`ž†}ÐçŒaC^ôòþ›‘.áº^Öṿ™ÃÓ¡722%§ ä -Ò ,$ð;Ó£>Ä|AaÞ¸€»™=0(Q82éݵ M0äÉS¾`ál.èλnöÀ`Ç•¬ØüÍvém@œ{|wê|/‚$i³ûOe®kiŠä¶{mÁ ß‹º†PB·ç¯1ľ_‰~y¿6y6AÃð` ©]âå#Ž£*§ŽG»2À›ïG<üjLåç_ êZHÀŒaÉÁ¿ú¡W#*=÷j@ouô¯õÀûÛë±™éð)BÍÝe(Ë8ao¹Ûüµ@3(Ë1ñÜŠÑÈbæ˜/´÷Ízž ôïÜuèRÑ Ž/¾¦qg?Ä@ éŽãjéh‚2e/6¸™T.3ºk t?.y›ø#:€(Ø¢aM²Ã!HÝëÔ‘!hçqorºzll؃pÑë'oË‹Gq!˜ÌßoÏ\göc/:62™E‚Æ=6s °J3×Ä’·N7_îÇÇÕÎÕ¤‘.4¢tþˆ¾‹hèzpûÑ$eÄ;Ò8Î$ݦó¢;xŒ~ªï$ÿuˆfâNê 2e¼•È̵éÂY ­2×§¬x˜C¨U·¢W“‡¿Z2íR°ð# õö#@¨izA7{z¯2ævJ.|³gèý[0/zXϨ¶ ÊX‰5<L˜ø‘ÜrСƒ±Â‡¢g]8^¦xȃ¦ñYØ(%ZJ(ɶ´GÕ‚*ø‰’B¦pd ×`b<]…Õ¤‚ÞB+!ı<Œ‡½ÔæbCøKµ+)õ„Œ9F‰º¡ºIºzu 4d(LˆÝZÝ sÿ w«¡6ƒd"€y\¼ì°kvæÕK‹ý¡Î‡z-B‰xØáåi½` ºån2@ÿç¹ñ›‚1µuãè,N ËH·oÏëÑ\Jþûè`g¯óðéÞã{;ï=t Šò$âTðfì ‚ÄAû1$8–gi#PVA ¦€cdÊe<¤m{¼ì³ÛºÜQÒ»ÈóШpG1e†û‡UüÜÝ"R”ëI–RPV¯Šò~y‡ôC\ò^¨2 ,“^äÚÌ“ov$ˆá$I’|Güã|WÁ‘Δa¼Džðú‚§tE§ ‹iC²»šº‡Qý/² FOÍ€i7ÜwT\fܨ¾_¯V{Á7[ñV<­¸®àŒ6rWf¨²HÂRAg¤›¤ijMhcÒäDŒ]b!Ê–Ç£o³´Oˆ¾õ»%”ªt1B¹zR½vjþ7C@š§oÔªài5µbۄ¢Z¦§fÁ«XÎõþ2¤É]’Ô îA˜ÿ/a3l±óÞG¸…Ù“Hü*´Õ:MsíÌM~är‹Ë x`Vú»{÷¿yðôëΓ§»÷wêA¶* š·Ë˜†ÍõtY0K ýÈØºxêв…u!Æo‹˜y}Úg’èf{hÎÆìö?L N·ôr,«d¡sÇl¯ÁR‰)5ðrÏã¤ÇlQbulD‘"‹ð!Ví­´~^’yKv÷Ьˆ·‡´Š;¯xܾsˆÜp-¬8FpÂ"‘âCÔ„/¬’·'D猓¼/±˜ŽGym^EêËÛQ\óÄX%Òx屋\Š#NHW&¯›øUœ‚gț‚GGß–ù–?âí¬NûŒ»™JÁx…›yˆéÿfÞÌ~/»— û4ûú¡žØëNäeîHfõ®åò)ÿt] w@ÓŽ'Ãç ø £ÏçJîE;×s/Ò!ÎÜŒ_ý„7c.7ÇqU9ýúåï)Q÷/xMýT²ñ¬ ÉM©§ä£QÑ)fL´,Öð„3ÂRl :(ywB*D[·‘‚ÝÓ$†|HÌç—Ôø5ÀöW‡Sç\A™A–b,NŽpÕUɨ[£·íÜ]R×§b¦¾$@Åç'¹?•IË=½¡d‰¤;/Nå¦ ‡¸Å!J5‘œÃ¤[Ð¥ñÏ:|VRÑ=Ô©¶ ¤žû:MþpâX­ú7ó‡Û+ðúµ…zUÄ P¸²ß:éÞNfl_óRvy•8µóÕ˜f+ äJIBšrbÔ·õÆáñÄÆˆgRxدÖ>_Ìq©6mw¤ÃqI7T #ÑXØ]J-Æäª|½rœZœ³ÿ‰‹¸Å¨ãŸ¸Ån˜·>FyÇìH„ŽÑˆËªMCÁŠa×@‚‚ âl‚ïKzŽßˆ!uÅ`òQ{§Àí`ù.¥šã €®Èó¯Díz±¸*y8…d¤ä˜>¬ÛÐ<¢CÒ™1þ‚jªhãsü}­ñ'X ”&Oe t‰1µaÃy\šÅÆÖfØ@ž­Œ .À¿Ä¸Â+ÖÉâ¯ÂºNhС”ŒpVÞÃ:ýÖ-lú&0—8£ SIAˆøÛ¦ø’6gødŒÿÒIõ÷‘¹é }õQ/xº÷`g/øê×®;Áƒýû†ŸÏì5¶Æ4ó›¬PºìTÍŸF~¥q^z˜øAÆN+©0‘ˆ$¤épR VÛŽžØ“› ”ÇOýLâ3<9«W4>ejθUi¶Úë776o}öù½¯î?ØyX¹Škî0”ë*º«Òq¸z r鶿ĭî|ᦤ϶ Õåæb}^D†svO6¥[4’Ûj†GçÜ]‡É-*I) `~lMÔ}1xŽ}ÏýÇò`^Sòìø²*雿Gä8s>|HB‹Ê‡‚Ma" Wlcwö‘Wȱ ñ¹˜ ÄHGédð«ltò~PÝ~ ÷YÌ %æpŒÍŸ’ŸºÒ¨øI“¹r³›™¤0°kùJ…£²Ä¾/«¤¨[Ÿš£Í`í”›Yô'Šgëjo'²6_arùS’°¢òjçá§ ìGØZn¹¶‚/Ý:hÜ=„=/Ú}òFSrÚÜâ˜Y1˨oN{µG©Ò©Ô] · üÜg Ðöe¦ÐQOÌû»x$SÙáõ¬R©X eO¥xB ëAÄÇ ó¬ɳ3£ÀFB¢çAå&Ç4²%±RožÁOHõH²TÅÍ*ŠGN’“Hù¼hÞž/'/!«/Ã=9²û¢zË ·kÛ lÛ³ fg ºÎœ”Ÿ L%ñ¨/Öb·mßg o賂 ÛŸgdëúºørèÃ[Ã5V€óŸŸ Ù¨ê³ÒíÚVûe|š Ö9-FÕ¶‡Þ5žô+³ ncLà¼Ã‘”_ÔÙR÷d3qü8ì/õR¥†Û|Òž">óqMºC¤¡«œºoõ¼ “O'ôôvûÐá`M™6ÂFzÂ>ô§L¾&G=öbž=iP’뜂wѨ4ŠÁ¿ ú áîi’¤.ö¥&¾»ú’³],êƒÈ—ä-*¡ 8BÔ „& €+êr‹v©#%.çR¶ {,ˆ…ë¤LÖdøIgpÆ….eÙ“§;[ÁyTG´DŒºåÔº](&•“‘gc@ËœR]’£cnvø&–pÄë n`»–bPðàzÀXV†¦Ë”²Ëä#{P¥7rÄm 7®ˆoàs%Ý舻èõ,£u u&!àªØÎèùÚ¦@°m˜Ð’`ŒûªKn²8}8'ýä(ìÓá½­#iëMÁ+¨÷Q•o=Á‚5P)=´ÕÏÂñ˜ïTìÄ”'o$æž»ûµÈ×}îYÀ Å“€s*Áõ]íŸ5SãwãÄl`™Adì ‰¤rËûP•0{=À0¼®†dÀP(ˇðT˜ë’{Íq…¦X¼ÅåŽ Ì´Ù†'qµrKÜ­þáŸÔî¬ÑŸç¥NÐCåTŒø§·/>;l¾µíåv-9³67ˆí©æ*ºÉ"—XRf³»«Ã}á8:×ïvÎù?/ÖÅãfëö6s .¸Ãù² ÂQµ‚1= ¦Ç€ïàô¹I„§!| Ó’‘ÚÐX*Jy*†_ýÂSÁ84­Z°åx7àA¹JrIän¸\[ØÏ£ä•EL3/m„0ŒC›v 4QƒM™uC„‹L:®Ê #˜)Õ]ìý¥:]w3cëç&¾Ge]+~ö±ËÇg‡†^@ÀQæ Ïð”A°w­Pðµ%›E¬Ü‘0âõcøÞÖ}È»æ•ö¡Ä‹Ï¯.ãqX^Y‘k"óܸååPv8«Ç¬ O£IñvHŽ,Œ»o÷]7é÷Ãꈼ­=§‡³ÖdFAÔÁ~wòÏ^F ="ÿå_T+?w3v”|4_e ,<_Òå‡Ì®:•ÐVQ7ÆyƒZ åG—=¾kãa·?å€À¾a—Ùw¯Q©]jÖ váÛϺvè¤Ô† Ì§¦šø|¯ä#ëºQ¼³œ6{¥]¤¸-½®«8f#hǯ¤¶Ç_i"´ÀLgèÛÏó$™’˜™e>[hŽ3ýù±fXëþS-d t)‰žA¤sęƕ»ƒªYÚAtb2âÚU×B®škY‰ƒ9·Þ¥V!Ó³zùýøc¯À"×ãÌåÐúkB=¶¢8êáI¿^'8œŠÀ!æ©]½µqÚËñ*nA*{û„K´`V3No¥~¨„KIÆÃñÉt€²±JÍïÔF˜»;ïÙžNŽW?#Îu4ŽÍ©ºsçN§c ÓYºó…)p®åíåV£¹üÅÝ¥;¦ÿ!؆©ÓÇÝÓxõÓÄLÌØÌÈyœF˜ØÑ| èÁ”2bÞÅ5¾ÐNN’w)ÒøÎšz¤Ë<2{ón>GŸ”Ç×Tþ4DÏÌÇG¸.wÖ¼gTÌ,}z—wÚÄ5Mn/» ¡ËpwÇQo{ù8ì§Ñ20ûPÅö2ïŠe\Ýæ-ér°VPéW´j×X#g"…uöjŒ§—ªôΚÌÃ5»4w`¹î.ñnÐÖœop;¦¤á÷ÀÖ!¶ Ô…6j¢ŽØ¦z[IѰQúçAü>´) %rÔÌ¿<ÄÅ•ó_0Ò ³HL*†¤r–PÓ ZÕ; Ë‘r3¤)]X?Á\ÉŠëôÂ&2¦ç‡½p¦ÌpÜܲäNí¨¨éõý§ÍEp`.‚;»û÷¾z´óÀyœiñåm]YkÑÊövî=è|·g®–YÕµ/UÝÓ'~]XÛ=ßÑø„nóõ¡!¦“ªºýën„n4Mðwô­€Ì 5Ä% ºÀ` uð’éIçoÝlgЋŠBJÏWW±ã««w|$v˜lC¶c¥M©¿¨ÆzQÛ(®,³G9R¸ƒK úáÈu†jfäÙot›`d¥tm½lkêU®˜ÆÁKq.þ|õîi2׃²·†i2×gù{³{’aoÆ÷æB<-Ý /Ê_^Dáx1èiœK€¼)ÚCOéÑlH)``pÓs#We˜jY$½#ÀÙ Þ¸ [õ @4-ZˆA)ü1z£xmI*‰ŠŸr!)Ý9ÎÉ;ÂÕGfïÑÓ¼Ù«Öù¿ÂÞþûÏWÌ Æ^ýtÁ›à˜]ô-ºúQÅ=Zà~¹?$ÙnÚŒóݤŸŒ×®·¦ù¹µ±ÿ6o¶üéçƒV«µÑZ_omÞ2Ï[íæÁÆõv£øÇ°Zá8>8??_…°¤²róÞÿBŠ×ÿÛðYsO¿u°À›7o–­ûæFûƒVsc}£mžÞÚ4ëëÖæÆAóÆ7÷çOøúßùbt:2ŒQ°²ÛÛ ¼u¯Ÿ­F;h›Å[kµ×šAscëæç[Í ‡±-;¯FÁŠŸ +è°Ï²vÕ•‘aSyO¿Ñ7ðÎXXÜÊt”ƒ¨¢ÐE(ÜéëA?>‡ã { IóVs“è¤×®è ”G¦Í“åÜsÁ|ºS‡•“œõ…e?‡Ï+¦ß’j²b3Ó p“êî³'_ #¯Ê{L7(x­Ž ‘¦&˜ï$Øá 7O(Bboç÷Ÿïîí Šä鯲qIž3ïe«ÛÙÛ{ºw{öÇYñ€Í^nµÐÂ>†‡bÁz€Y:CàŸ£¸Ïk VÓfq±»Œ_9På/´¶|k… ï=´„ Š`±U­64ÿcMw7É2Nuè—` UXùkN>B– £ÉÁ4¯EÃ5Ó|ÛD|q¨¢7é—Ýf#EààÌßÓf ·TP2·Tª`‰5²xYá%z³Øý˘|uþ”\´M]j43n*9‹ª÷õ/œÉ›ñ3ãþ_Oúnš¾usîÿÖzîÿ[íuótÝ\üæþß¼uóýýÿ.~¼›_VÜÝü·ÖZ­µö­ ÕÞj~¾ÕÞN’£P]ü7TÔ=Rº~t<Ù¢€øq|rj~§“„µ/Á³°M&|Ú 6ˆU¾ öe¬cöÀ޳ªê’G\g+@•º ÄÏûIhÊ`Qø¶kØØþý¦ eЂ׃üó”<åó•–U‚Eáø$JW±ûüˆ´1z…óqcijÑ8…xö¢V\‘^r>¬îïéHÿu”LN±p58C˜ï*2‘H¦kÐ.®á+jÁ0YG#ÃjMèžnf:ÊT³*¸”f$Ájûõ}fËþ'7sÃí'Ý¢áÚ³ÚjÒ7¡ñ}j ôÑyáýÔ'è—ýSLÿyÛ\S——ÿ77Zïåÿwñ3sýlÉxË6æÜÿÍvë&ÈÿíV«}óÖfûƒfÛì€Öûûÿ]üü5#hý¹¥¨èŸÛýæÁžù÷wÍÿÿwÿ9óß¿÷ì_ú+æŸ?3Ù}¼ógþ£¥ùO}ô—þ7ÿý¿X7þô³G;üÇüàÁƒÿýÿûÿû͓ߙì=ÙÿàËð÷ŽÍî>¸wPýouÿòÿàÏ6¿úûé_ø¯ü»ÿúoþÇÿÞo/~÷w¾¿¸øÝ¿ÓþàÙÿåƒú¿súw¡»;OüϾúËÿÆO5’fž¸¨ßÁù_¿µž;ÿ·ÞŸÿwñSpþÿœùÏÿ¿ÿþ‡›èóÿé_ü;ÿbø/›G8ÿÿ÷ßù÷Ã0ü[ëoý£ôþößþÛÿôŸþÓ¿ÿ÷ÿ¾yùêìäÿéÿòÿ“ßùÇÿøÿÍ¿ù7ÿÊjmûƒ Hˆ@üoÿÿáÒÿ*øÝ/ÿÃÿÿõëòÇÿçßüõïý¥ÿÅ¿ð¿Þý»þ¿üïýßDÿà«¿røðùî£ÿtxãÿõŸý¯ÿÍ×þÚÿ4ú‡ÿÚÿü¿öïþ'Ÿü¥Õòú3ÿÁ_û¯þÕÿüŸýïþõÿöáÏÿïþþ·ÿÏ¿ñüé¿øëã¯ÿ—þFçwþ;Ñ?ü'¿ùýÿs²ó/ü7_ÿöƒÿæí?ý—þGÿÚßýOaÈïÉú™{ÿ‹Øðm̽ÿ72ò» dàýù?e÷ÿïÀùÿ¿~9ýÿ|À—ýæƒÌeÿGÿ½ö³2gùwŽ~õõƒþêŸú‹ß˜?þs£o~~ðÁ?ÿ/ÂÿçƒëßjAä?þçÿÕ?û§V~»û߀rÀïþÇÝ¿üåïüñ_øWžýò¿øç~øàÅ¿ôûg¿óAòýùÿßßù/þõzøþ¸þ˜?³ìôìíÛ˜}þ766omü×nߺµÞBý_»ùþü¿‹¶ÿ­iû­;*×?o´-Ð~¾Öl¯µ7‚Vkëæ­­õ[Jh«v£~d-ˆ®jn€»æÒþ’¥_­@² pŸ0‘85à ±‚¡0‡üÀg7°†Š8 ¯$Ó À§m«0ßt¥êf¹ ¡×ÂN@DŒDȌà €Ê$ÁÓ¸û2ê {A¦1ÂÛAAvÊ‚šÒîi4  h< 1Ò˜®NN8_X7$Ý“z€Š³¯Ãq«NT 5~VÃN<Ž‡Ã¨ßƒsÀ¥íE$|¾„œ…f²O°;ñÄ¢Õ™Î|%°oÞø9¬mf‰0’ «£ •ÚÔŽ–i]éṳ̀8…ž¢+ÕD´ L/îëÆÙ Â¤‚1%aŒh:1q™ùì¡é(l2ßn‘Åý63aPá*ÅÆA²°€ƒ¯ogöLCmšeÊ`ÍÂ!6 V €¨ç´ zPâÊüI9u»Éè¾Ãtpü½M'†ÊžFÑ„ƒh#ìÅ`KÆŒ;8ˆB ¹qy¸âË€Ì`¼F蜆si³Mв"2'&Æb¼‹%ì:<1[¸@ž'v>$šDàusDÙü뺴|WŸÛl‰ìj­ŠŽ’Ê3üD%?1³Ò8²(_%7 ÎGÉUÂï´ÓŸöW§BD½)øÒÅJr—*…q”¶ì“çIü-{|Ïí0|Ü Ñe³¸×ªÀǯ[§ kL´Éâ̘Θ3SífÚÞcÊžév¦Ýä°ç, "׆63ŒÅ]h)ÁÅB×À =eÌ´ToÖС3ç·ÂÞ4/}»ïŠPBÕÁ3õáî£Îƒ§ß=yôôÞƒýγç_=Ú½øÑ%oÄ…Â ÿAœBÍiÁœCÞ{x<ÇgàÞ¹IB±î5\mO<Ý"ò–š»»ßÛ&éŸZ„©½ Q?ŽÆˆ¿^¼¸§Ó(¸Ñú¬Õl®K]*2’A «ÿ12Œ…é"±‚wx*žÞ™°èòƒÎ]ÃåW*ç!bEV<7 ßI…üéŒù§Ì‚öÈEîßW“ç¾rã<ó–[méád2ަ“È;ƒüQpˆ½Zé ,)™ñÉõÓí ÷QÕ;‹|2ßß ÄòÊ ô]Î7Üá÷ùÈ´ç ½ënÐÔ\„ÑÐlʼnܘt˜Èo‘3 ׷ׯƒÒ’©õª[á{j›à·âg™¡ëtOÍ¥4Æt¢€,@¾áÄ­Ê¢¸-7Œ,€M&7Á‘5*WÚll$²Úñ"0çÚÌ7}Þjî3\V¦°ä¡ á  ^ä{‡±•¶ +ª¸ên_€9uu5—«HÚ‡;Qí®‰û a# èî|dXdèu#K­¼Ð š@ êöÚ03œúñäF¨8™š"užfˆ Ä{O [5Ž{†`ÎRóä4·lP.«ÂNUÍ¡3 ·ª¸¦Ü9%É(HάØp_1 È…ØÃq„œ¾¤`[”aµ ¥2=˜àWQ4b–‘8ÆdÜ£@Baê¡:#Pvu†ó@Fi]7Í:§zYáÌt²a¶ƒÙMf=Ñ­ )Ï <I¿×¡ô‰wùq4'$á]e,E€¥ÃUœ"O>0S16Œ»©ð< @-Q®¤ü(®’qTø-B£o‡õ u±ÙüÚþbè…ß_íÎê-W€ôDºá–q’Pw1å„™gWm2Šºêâ½Ë½µâêòÒw•$GíVÌ’cÿÖ´Üpµ°ÒŽá67·°•F)O áË )K%pøêº"ê.«¦)y1›Ù± X×e: .A­Lw Ȳ{¬úï3Óò³i¿ Ùí%ìõÜqP› ¡ê˜ DµdáùÊo×±Y„{*Ghš¡CÀÃì<²Ñk²GŒ0ƒÀwHp†“º_áhñ¡C%ÅÃÇKIú²z—äOLË»<º÷äëç÷¾Þé˜Ïý‰ÒI¿ãŽs&×,PsGˆÓ\ vmoçëqó¸HMj;øu¡÷xì² eê®eÇP¶øzh/2mä7ßHáFП¿Y*þÝ ø/º+1UU9yÝÎtì¶þ„ÖK)œSÊ#Ù~þl¹ ûÉI‚— ü²èíe…e±Ñ¿X‘”¸M,óŒÒIaµòa¶®5ìÀhx²ò!æUß:À ¯F¢¸FèmPϳbô^d¸éèL)?0 Á¤ÿP)Ù°K…rª5÷»YM7ö‡×K¸+¤¤Çô±iÔ­ØÄ kê]Žy~­ŒÉÈq6;±)2}ÌÎÂ7”\ÌŽÙŠìÄâžxÉIáÏx^B3`àŠÜBjR-¿! ž`ÖR 4G R9$GXb  äɪ’üs”L° Éá-ÅË…% ŒÔ)åP’Väp8¶_2°×…¹ë¤§ñ±¡%ðqøÿ—ÈæP v§òy@‡+/_àá¥bú>aWN›ò¾—ÉùÂVlÍ%¸h¥n¿ò”4Á[7Ÿ¥“#®:¢I®¸– ?ö5ú\06Sî\ÐჅ#©s¡•[²ÜâÃp|4 SHÔ Õ K¦¼Ê N»kǶ¸úU.× ±ZŽQu}?»ªïÓŠ×?­€Û}í÷öó½¢i‘£ÙŽd¾¦¶³…DZ³:J­DТhØ%AùH#„ÅÄâ¤NqEÐ1ç×áÔ:@ÜÍŽ‡(ÃC-(P1¤ò^ÀIºÄ.‰ GJYT"HíHÖ«§­ LŽ[«@}šV³‘é Ö*p(%cßß®[>Ý6±yiè‚ …¿âo î©(’±l{ÝjEÂrîü‰Æ¸eÒ eª¹?ù¾¨ý+Űù™žÌSæñ;p<ž½<ðÂR­íÒÆ)Aà Ƨ–‘ìsß¿Âà+¢YÈó`K2¯á’à·ß J[Oä-ß~~hk€[E¢Å ¬XüEZÙ§ TÁìæ¸~æðx·ˆ ¸-(Ûí]Ì:Í¢ »ú°Ü[ †Ò¬r5³PB©HŸŸy@›¶‹“Ì6œ‡µ¬T†\jË/Ö å}F¨Gßjx²èB‹ ÑE i'ÓQ@&&º`õ•Ælt±ÒSˆÙr¢Õ’è %ß–§]Ó›7òL‘9Ḧœ!÷x¥7)G˜ãD:ŽÓWn&¢ßÃÑoMψ֋ÏÔòm/«Ø Z=OØe0^-) ¿"îà·ÆÕ ù²4ã™ãù²}ˆ{ÛË|–m‡2½˜«›U‡©fž=nsz›=‡îè¾®™ÎºyF3?w.¼EÁzNÛl½ä**d*„ǹ²v~¨èò]ûèùÓ|õÈÌÌ ˆGétô`°®;£»ûêifq@À1—œ§ ìÅ£8»pGýxöR„¨Žâijx“`+Èq/îAÂ×)(6ŽÀÎM¨ €÷=†Aؘ†àù$ˆ†ñ CN ¿œ™?ÃAä¸]é´g½\Hâ`KR•íÄZþ°Ôú눈èsØÕ0Ø%›ÈÍZRèÃCºuÿ"c²gߣøùùÈÑý²fdj÷"´·j)رN%5XeuÅå,×ø!Kþ˜uY°-ŸSGÖ&æ±5$ãŒ+À +¿´÷½Ð,/çm‚ÁËØECt&Dƒ„ÒÔZì¤:ŒùÙ7Ï*©¼¥ì±ÂQˆmòñœÉž¾Á»v –êŠ6Ê–‚ PÖÊŸ %üvÁ[Û7<‹|Öhà”Ÿì<î¡ûß)Ú„!;™©<Ð!i7'vÊài$]¦áÐóºâî¡‚8˜Ì‰£)(èm‰42{½ñL}ëí£Ñ¨fFs~b³±“æs/ÍoŸ±òqʹ ³Ó*VÔZœm fpLæN é?Â"D‚SýAµŸª^ÜåªÜ+õ:p ký]ä!˜pÃD¹GÅ)QŽßTRÏ×±@Ê?Æ1é ú5礢"ë¤47JÁt¬Êt†yAØ3í.ôÙ¼ºÐ{ë*VÞV¦FDšG M ýãúÀ°_†$}Jê‘jÎl®œ_()ŸòàÆ.ëÊ—Ó!"¤ÓC¡ÄÚ"s*hÑ®öâ1™“<}é—ãyáUÃÝGè;âÏ<½ö––¿n• †6{á¸Ç “ñQ茧㘣\AÛ—÷Õ×a‡­óBŽIö| Ðí»ÅHN«Y©.ÕnDä&~Ÿ–#ce^EDý%cO¦¹NzYƒµù›¤œ“¶aq5G?³û{;÷åzoçþÁÓ½_;1§¼'ö‘È£ò"&8î›<%Â’5IÍ–på[ÚºñA8Rš§ û„·š d½aií~J/£7_à;¶€̎سœð>^Ñà?0Œ¦“qØ'ö÷ž[Kbà:go ME¯î¬æ–¢i¶$7û m)¢}a΢¨ÿÔ”Ô¬çÿ«z!Ùü¼f‡Å[Æ}ñÆ2¿HyÁÙ™&Y;b»Œètfd'— ;ÏEɼtv j£—©3HÁw2ÆÌ»~€ݺŽfƒÒÒ î¼\ nÁÕrŸ*žò+ôà Y’Ì)å8òè`7-Xï--bsa¦ÙãwÁJ«.(^«£uq¬÷Ú·ù kšW {°H¿¤ ÖMõK H¥bÏÈì"•9¤‰>9G' ÐIñ )øåLÇil|rõÆJ<˜Ü‘aéÌkë“áª,6Еâ?"rb#?Ô[Éòêê ·‰˜¢?hè:]ÓðدX뜄³ëè%&Ðs3^8³Ðkg7rmïq†iqWdfä‘×µ>(lCÁËpœ 8ÅøÈsXJŽIr ÕÇ6˜!à$ãLımÊŽF,§†°LZÉXÜ]€‡;7oXxÔ-™r=5×þqü ãØËʬ¢äk“12s2$í€À™ûNKvF*uGL§ÕÊša¸S=üMeùÅÕ/>< Wÿèŧ[¯³öi­zø‡æqíŧ5zý›Úd¯Ã¨ÌÊ=R.mH,€Pkšë¨¥ø¥·efBÕµhB ¯¢‰3©¼w’EÇn.ꢽ\ø­tK:\¨+F³¶ GÃö³ôsîÅí;nÂh»ðEdÉ\xž•]]&zÍéCïçraÂx%Š]]g¬èǼ¤—®)•—89ûŒ2ëãbžÒÙ³OŠz¶mÛ€ùb×*÷žîç¬#…®À©‹Î,[£¾']‘ö“ñÄtê”çgŽ=u&sÄ,Ë!Ž@¯*4l™¤¾I2íž.K6”|Ð^ý)~¹,“Åã1Úê·]ƒèàLgGIZµ»?…¨Žm&Í^Rz)ehUÔÓéé;ïPÊ~ˆ¾¯†°ù»Gí1ñ/ìžN‡/±ÀQ49ØîíÑ4lƲêÃæêçáêñ‹ßn¾yíþXCtKzºÚªÏöv¾îì?{´{Ðy°óh÷qçþ½gÏ÷vØ#¥+ž?Eæ'¹h›ÈúìNP#î˜(÷x’aŒ©óèé ƒóÒKHË:-*ÞIôýmGmIƒ)ù˜bš›ä¸à f\–„c'À‘Íj9#ÈÌÅM9Ÿ(Ÿõ‘.úÛ?ºxá3@âø@^« ó“H°y›F 87ãÍ]„‰•~eAo¥E¡Ç¤‹µjZøô…ë­{ Ã`¼onûŽíùÀ¯¨&š@:!ÅäH§1Òì°³Þrð£ØÜêR¬„³Ý~HNJiH@A¤×A»~yø‡æb6;º³ú¢ÖÔ_‡¸öÛŸüöðûâÓ•/qŸÓ¶ðVH6+:¬ Ý[>‚Ô!°Äy íÕZõ‹;®Öð[Ó­Ÿl™n¼ødem^GÐ1¡ #¤ ÂÀ pÞž±2ç/¿tÊ´C=a OîíB’÷€ Dz&§&N@÷i5d¢´’W`Œ¥7¾\F^ñÄÉ™¡‰ÌžvÄQ/ñŽ ÍÆsâ3¿(2‹eøP*z;óæ«•¿\ýÃ×k5Ãþ5kÀö­žoÍüþ—Ý[iÁZÒ—"G[b¨e,.SçÎÖ¥X‘·Àª² g‘<ªãôe1[‘cÆ|¦‹Y ˜º%öžPÿŠD±+«§¾ØP(EÓÎìîìwövž=ºwÇÓy bùÊ6ý·úV *P I€PœGG?/¯(ó¾ìž’ž ª¹¹y3â¡ÞvE™o'1„‚ÏáÈŠô ¥Ì˜›C«’Œ#¤Ú„á¼4[y3ˆä¾Ë¨+ËQ .—¾ò_²QGÞ^øF§¼2•ÌIØq~âu˜/œªœq ™%(öG§!Þ$1ô”jɰmA˜6'—ÜÜÇFP‹{r/äµ0f­ûL˜RÝÅ=Õ·¼4 ¢èCÃáI?rMcÑÃæ ù­õÂ=à þÚV¯íÃuó·ÆIOUh/V|÷¢–Q9á<‡½˜i$ìêê pÍÛù÷ެº2eýÅíàÓOW.ïLD™;€SZÐôŠ{¡°Ï<»Öì,zm«6çö"³—ûg2÷”¦í¢øx•{ÜžUùOK¢E¼éýª* ×âÓÖ½GÊOÛsÑ‚6Õÿòûv‰!"Ì^p„ñ—^dH{’??÷AdþŸöãn±Ê—Þ(¥/›Ô“qÏ—^Õiþòfc*-wÖ,U1iXgéhEwéu¼áXnêá¶Ž%u·cÁñ“2ÂÐÚ0³üyÓieaÆQ–€ÙÄXA=°+ÅKÃÀ5­U9_  oiNfD†ÏNYÔ~›=šâ ÞØuÀ›Þî5®˜ˆ<׫ûŸÙ‹P"£Ë÷.^,îÖü-î^¬‚/ß1y౸kö–vH/NìÏ2?‚±|Èà4róLorç3{QùSB¯=ž`¤!Ëà²Ö­»u7ŠÇß $5r-a]ä§Žâ¤eÆ >B^À#0UФo¿·/ /u ñ*3 sçé°]pu!.Ƭѱ¡Ë¨J¦XkÌs:²-<³f m4S·?Å'-Cây2Ì'½¨? k¸Äi2©2¤Îã J°§~&àn_eöÔ«™&1_5wíQ’ Ðç:ø <éÍŽ23mÈj =FQGá;§;§sïO0šåÈu 0Z ÛK2/ö¯ÞÇ-ú§m¦âyAáN!@XDœ@pDâ%7gµ.4ôE a¾Ç1# î RŽùðÄða¬]-ÐD°Ð¦[KúÓíÖç56¼Š½6WõëóSàÅùÇ„ñ(§Ã¨©³lU@Η£iðJµ Kµu©¡™ÂÛ&˜ÿ•^4L`eÔ3bjbfjbÃÔ¬#»¤­¶šO·jåp%Þû¿Ã*yÃdM·ŒÕÐЋ+*y§Œ4ùU¯Ú»AâAª°$éc)µ=_ózPƒ¦½ûÃ>ÒMt°ÛOç»Â€(¸áFdL2$f»±Ð4šÚÖqHÛà§4q-­{sACÕt7× ö¤‚žÔá9W…zó²–‘Fg:Ó°‡h…èÒGúµaðÍþ#>£@)CÊ•ðªbz~šö«¯Ðÿ,³Ç'Gmx‰í&]/.°^[lç!19Ëì.œK=1à™ˆp%ú‚€Á5ˆAà>7W&ÔÑ<ãHèƒÜqbdÏÓ"Kœ¢^®p‘±ºEWù!Mõ ßqn–z42·Zñ0É<Ί¿LK*ú*>V„pËZF ëtA¼Æ _øxaSÒÞçW^\e.̹«6_U›uïݧj•kî„gû`Úo›~¨>ˆ”†wÛiôÊÉ|ßÙxp"ð™]LxB{ÍTA`X5âaU……ʲ ù« dÉxp‚<á+¶ät­ŠÓºs¼«Õ³û ¾Âs‡Áz ÙAÇh©#ÐBÄ¡šÙ¡ËL»Þ H˜šœ'n"R>æÖÂ<{,,–Úá´è¸tQÀˇ——@Ñ‚[ ª±QÖa§d±d>c6xز§É4%g‰ãAÂÎÊ.ºÂ¼&ÓÉŒíÑåPØÃ`ïë¯dÃOªš:äÐCͼfÓT"cp>í¦;´ºÿ€DÝÈþÖ.øm]ýfÏìKó¨u©æ[›8õwe V·ƒÏrÓ_­šZîBÄW-ø8h¾zø°†j 7®/‚öƆ¹Y[µÌ @…³êM"¥¶ÖG¹XóÉQùŒò>xóI¡m ¿ÆÑ!ïQ4œZpçŽá+6a·½×êZv„•àŽ8þõªf–Í(ª¸™êÁ&Ê‘û{g÷tí<<(Ùa@Î=dæ¦p,14¿ðOq—¤  #µ£üÝ¢¿ûòw›þ´‘}êw€êo`mÇŸ‚Êø#ó7gôcþd%¥ÏàøcAàwM-Š|©PHéç4¢~€œ €˜œš:›uøá`Îeç—0еy›EU€íž™À,äᬾ¸y6ón¨òš8žDÃCÈaMWñáÊ©ƒÝßüMó™)!‡ÂL&P²Me éó>jg>j{o×ÍÛöÌ*«ÍÆ&üÀ“ÓšTï>Xì\š½Y¢k·ÌÁÉ‘äPEníäHöâ‰üÍ{ñHþ–½™EX1 þ ·Ð‡¥¦^Ö_ÿúµÈXnk³;¾ŠuŠï€XµíÙhÚYìƒÜ€.ê}šiá=¡Nª|N /Ú°P}8"U˜gþÓñ.§^ýTÊ&Ê"Žƒ‚iÀ–á¯Í_'5ÜQÐñËQf3ßžxßÙoÛ¸ŽOvÔ j8òjÛn’T5œäj0eÖ¶i½ÉžþÐi¥_»¦Ôg³ð߯#÷#üÌËÿ `ï­æf{sýæz{ý&à¿·šïó?¾“?ó³ä~¼I¹›˜ûñÖÖÆ­­›Ÿes?šO ‰›Ë$w„SiŽÀ**x·‚&än —$P4^”X0“OÒGEøx’Œü$“†¯2Ý_bÓúerM’ºy+hS¯!y5óÌOG ©'U[’Ûq ¨—©³97/%Tã×À *ó/xÊZÍ|ºËË&®ÌV>3ƒ%ü²j˜´3¬®YÒü¼–ÅÒÅtœ&f£$¦/f¦¸Ì–«Ç¥]‡ünü›ô§¬ ý}½Ù1³™1[ÍæGÙ]µXšLü’2e–|=;g&}i3ý=]ž@3?™E§‹Íª9Þ¼ÙqCS¶Í¢}×núóÞÞ ¿K¦Q²…éiÜ0ciÓWûCM辎zåÓ²³Úή¼šmÇéÀ¸bP‚OE®‘­àFE6E-§5á¥íÅ©¡M[Ö•&'µ¥«¡ŒÎÍ8•ïšþϺÿÁ0{mÌËÿ´ÑÒù?Ûpÿ·o¾ÏÿòN~nëëx0í ßÿ›kÍÏ‚æÆÖFskãfÐÇQÊ)_ȇ€P–T’yóì!¤‚R ´B^ŒñÜ,*K € ãü}ð9[ ©)ì/9ìowööwŸ>Yê’WÚfãÕÒÒí`W%š7W¶:ÜÕ öLê-˜¤ ±Íj³½ÚÞPÕ/o6ZÍå¥Ñ8ùnQó€jY^2 2ûe0‚‡­öúÆÆç›íÖgËK¿Ø,ijÎÿ÷×ÃþÏ9ÿ­&òÿ·ÚÍuó'ðÿ›·Zïó?¾“?óÓ÷Äþoòñÿ|­ÕZŸmµ?ßZo{ Ÿб:ŠNóÂq¬ç»è/ªÝd|¤E&Á, òAN&ý•ÂÝ}PÒ„ÏûÁYnn ØÕà$û ,ª•9\Íó¯ŒJõ*µ” šœ…„™ʈyUcX;é6GÓ h2_È#`&ý'À øOŽ“. K›g€ªSŒðšŽ*"&5eÌ ÿÈII‚XcjˆÞ}À‹bg= ¶eS?ŒµáPͰUu.^÷AÔMz‘òü`»i«¸>÷v;à=!ù'hæ¶„U‰ÇFÄݺðƒC´hAÿ{_u˜Æªø«ûuAߥüiF‰ †Fm “I5»7jBh„£ÌüŠ£›\.8†åSÞQÂÞ°¾{¶$è±dw8©Z?H„ï$Žð ÖŒ< f-`Ä9#ŽµáØ¯½‘0x˜¼\áÖÈ7‡¾’ySŒ1¬ÓîÎ&½¡9¸'`݇F¾¥Ë²A.ýk÷ww‚Ãæêæ‹ß4Ö4 Ceç!œTj¬ºäCÄÎxQƒÑ÷Á…ºáú±KîYè’ÖH‹^‚G?ðå¿ÔqŒIÌ]mê$îm=ø,~0‡)R‹Ç`&Ç“Æ=°lá[€¤ÆÕhÎs½m²û"b6õcÌʲm¾1f:înW–ƒOÙ-ÀÀ›w£ÎØÙeTÈŸ˕ڲžtp33‚¤‚Úðà1ͤE½x²ÊDõ€ˆ±RUGgõlóÝFOƒc\â"üì{Ñ« DÔp*KþÐÃI \usÉ1Su‡‹â4ÑQ6Z”¨¤9®Œ B¿¢EI™ÿÉßþåÝ"aßôÈ„ 4ésaÇðA*žr(¿Úɱõ¸`ô}t¢vû‡t®n‡º‰†ƒèÊ!§k^ò`š<…Ê‘2õ¡Z1bÅ«²ëWtÓU¤¿ Âz@¿œ¶g~ßÊw„7–œ{»; Ö›)+ÓR®£í÷Ê’wtqñu¿8ì¨úãù+·  &1 ¾Èoó™Þ1X”蕪:D´)ÄÞÃÓìNÂnw ]5Åü bÏÃu{)¿†i¶/î±ýÌN2Ø3 Ž—ßqlÒ‡ÚÇGÐßO·í@nÛ÷ŸNc†ŠÝ·ƒf¶q®©;Ü\ø¯œƒË¸mÂÝÉŽ-„qÅu köO’q<9Ѽ•R犈éS Fvâ+÷F„ÚÂWFŽØ¥±G^BàŸi&˜²o‚‡sp:ÈÙF÷…Ò/ÚéÅ`8í†4‚Ýã-*L†±j·Gäíù”§ã“ ä½pô·¦GGæsü¶[@6tYöR"At¾r´Dìy–% ñu*ç_°DM×o¦Ñ;!±›©Ôƒ!ÛØ*üJxwÚ£nWb+@µ…CÚs‰´1© ¨JXÿí¶/5¥€Ûm7p<ÑT+^ó¿ V{dªu§Ã6°f+{„3!zª3àiˆî†ò iýï‹ø#Ù†3¦¢™ŠvñT´íT´œŠ¶Šö"SѾÄT´ ¦¢=c*ØbèH þf¶áAb6¤ÛYJâå¦R–ö‚&ž9:þ¥_‚dø/#Æ!P¾âwôµÌñ›D×À¯„™P,Ïw#VJ÷ ÌR††²$ké¶Üšq)v¦Ó|—MЕÍf³ æ7Ž+4¹êÄÞ'uö&À«Ðî2|F×#\ˆúÏ™RÉÒÔ[~©/°ç#Ð7¬' 4µµìœêí… 5Di`Õ±»€ðîúÞ€KÅíä‡ïý BQZ=ü\,^ [U?©5bÂXu=H(™œ.Ô” PÂõh6m%Áa/!æ;÷Ô´øßÔtÝYžòûui‹9ÊZÑ«¿Jƒ_]1xà¿´AÛ_ÝÒ\)üdøkõ• ¦.KìTcøÁ„û]ÊÅZ@žÞd˜ø4šäÕÂÒ^}ñê_’Q©”“Ë D‘ÉIn­Ûöô+qô7ØmE&YWeÓÆ :}C÷Õ>ž¼F„Ú¾½d眦äQŒñ¡têEk>%Uþ£fv%ªVÌ®™Br"m¸ìß"“n—&W”wA¾5Éês€NªµÆ;ÈŠϲVQDÔYpgŽA{ IU«‰T–Ý($–óî·ü1Öe:wA—Ô—®ì¼áX«¹ÙâçvjèÏ‚ qÓá”B¹¹PaÃxBŠ‚õ`3E€ìÉvJ" Ö/;Ù”*Û̦j„ÁèNüˆTµd7;sà¯qO©*ZëjÅ0—fµë»”µÚiá€ÀŽ£1cñLïÞÔÜ:Ð}Z“rÐÌFÊêN…Ü_rœé=öåL4Š£²I+¿2ߪH'É „íº‹¡P΃EÁNªµuÔÿ¶Wõ½‡1ߎ¾V’…êLvi±\ûaý„®ÒRJKµ x;VÐsÂK`Gà÷Šª¶¸/‹ôÃïÃÜöÁÁb^ÞÔžV‚ü´3 Îvd4Οb‚ýn˜å.™ã¥Ì#»Q!|[³¯°éÆhšžêçoüƒÍÙƒ‡mçŽ<õÕÆÙf¡¿À¢Fù©WÞÍc¼pГÅËnßáˆJ àsOgëdÒ2EºQñ¿Ô’&¦èy%$ô¶wuSnU‘,ðûÜ3U«ÝS0¨Er”âÌ\þÔö»·ýÉÚÐÜ_»æ6ÀÊ{kc£Ôÿ£ÙÔþæ¹ùÕ< 6®¹…?Âí¿…ëÿiŒi(vߺ9þ?7×77?h5o­7on4omÂúßÚÜxïÿûN~î|1:-‰€¿ðÚ¸Õ^kÝ šŸƒ+ÐÍ–ç ÀÁ _xì'6F£½eÝS‹l p.fŠw¯Gé-Œ&Ã;m±€\">ž©F%ÄÈ„NÀ[Ì^µÎàcû%!ý! ½#0ùC¿º¼¿óhçþA0l c#\˜S̈J 8‹àa_˜·ûÏW»îéY2‰ÒZpo?Àß‚‡{O¿&½èM0 vŸ<ÙÙ ~ïéî“à·Ðú›`<}B-€ÿÍêtOÀCytuá.þûÝ7;{;æ€ãOST~½÷ôù³à«_/ÒñàéÞÓ–Gvöï/ãÅŠjmÈÆãæÙ.ž™Ò1§Š7%:…3Xá¼ÿôù“ƒê'µ«ÌF~€ yæ°UìJç‡i˜î¦Y€C!<Û5Éø‹w¦}Ê(u~ ‰Ö‹¨ÿÇô¤“»— -h«ÜéǬªO¯ÞåI^†¿Öø™À2 øîÓå$£þtÚÏp›ÔƒJ 7  ¥}‰Ý¦ýSq_Ë´††YœT+É(V :@] /*¤ etN[ü E2tõýíªË8‘Ë”Ä&QÌ®y:bØê2`¥â3Ú1 æaFQ@È<ŸŒdXpRñ”æ\¥5Á ®Šÿ¨Bì’šùZf1ù ¤1A`E )ncBˆë‚«Ç=¡þƒ• HDý‡Ãdx1H¦)z-šÇ%{G”lü º/ä:ÀÌV±·ÑÓÙ}ž‡f¥?s`úF†ê Ì)o“t^`½+MVN1ã¡Ê ÷äaü6Nã fy *”øóL èWÆlf °×2ŸÎ ýBóžô¢ðˆ YtÅëðûHù÷4I'Ðz@Ýá3ïVלò³B3ùäã ¿ ¦pô©Óàÿ¥³oAø¨·Ü õL“1žë*ÓŒ¤MB …mÓ pBõðãåàC—9øPƒšL‘¸àsÓŒó >F.DÞÃùôv-}$U‘±`gå?ä/xº_Vº§¨ÒQüÙÓ\Á‰ªÔe'Ôi µÂ£_Á®Èôá\^úôÓ”•žœéÂCϾͱ§'éir.µ™¥:Ø{¾£e:P„* !¾{/ûŸïO)ÿ¿ÊsÚ˜Œú/é-Ú˜Ãÿ·n™¯ÕÜÜØl¶oÝjÞú Ù6Ò@û=ÿÿ.~òüváQ h³GðgkÍ[Aó³­õÏ·Ö7J¥¯J[*µA™$ã9¾àXC‘3‚áõ-cØ)f žÄ ‚-È~à¯6ÿ\è\†+¦RÒJA9¼¤¸®dz=Ê–%¶) ÊòÂ÷梚àSmñë.x(ôѹx+¸GÎÇ sÇÇ6h¢’2à bÇžw¸8ªðœÓ©˜¶ð¹•¡+%NG. ž¤òVÍÙÌÁÀ· ÂcÜÉϵã‘î’õ/î.ie!”X¾k0n,#ÅArPY‡ÛÁøJ•ÇéÆüO€•Õà¥ù’øL›&Žÿ&° ”¿jR;**mÐXi†21‚‚šûZm‹ŠgzªŠH}ø€Zñ ×ÿSÜkú)§ÿ¸!Þžø°ýߨÌÐÿæúFë=ý?ô_/ü•‰¿® yADî€O -ͺˆ4JhZ/N‚£éd"€›KÅ iî"wÞ+¦Ìxé\Gô‹ã6!Åeªï ŸŽ";KÝrÌÄñáäØ9a¼{êQv‚Ö¾N¿ô0â(4í,f8ILs¢Ÿ:ÙN¢ÁГyX=DYZJ«“Ó´òM6iÊ¡Ì~‰S½|×£Ÿø è䖥îRGDõS¡¼ØûV}Sz‰1¢<¦(›L*6Y¦L?uÀC}š]“†¦÷îâšü³GôÕO¹þÒ{ÖãÚ˜Cÿo5×7Áþ³Þܼµ¹¾¾úÿ›ïùÿwòS ÿç…GÒßZo´- “]k¶Öš›AkcëææÖú­"ú¿ Šz›íŽ´W˜ƒƒBJf_Šªþ>ª¤YçÓpz.HÑyaµ_WÞ¹é(꼲άl•2¨ Iì¬@:@âŸ=íVÅH-ü-ûƼ›\Œ(5sÅGåöP™Ú9"¥"¨`Ô;ÀN…0Ç¢wœi_5½çþ0—ø27‚ ™@=ØX¶_X…Ze<BBÚüÈfõÿ:úXA™ÏŠXiÔM†=³2.›û,Ö–Þ£)ÎOc†²Æ‚ø×Q4lT FE€ÊÏkU*_% ⃇d›Å1E¨ï7»Assƒ«çGÇ¿TÌ;€ì /£ µ|¸#¹ë¨õKÙÂGEŽðà 1¥3—È›š¿É8µÀyéžò™¹2”>ùz'3¬çÃø‡©2FŒÍÃ*œõŸçIÇSäŽ8±é¬¿8ŠúÉð"‹Äò9:ƒÔdáXŠÜ ñu«ýÙFT©Ì†òY£Ó¬ea{òODÀHýåÈYËô*œ†˜U62ôí^pZОS62/ý4ã…¯‘ à†‘Ë}ŠnDx[zÊЪ¼Æ‹V‰ŽU†z-Fè”Ì t´/f ¢ñªÚœÍÑZ‰¸]‚xG$¢ˆ“ÚêqùPq0ÅnúŽ;}ºFËvN0c:ìƒáxІ1âß[«ôœÓõ£¯ÕÖ<žŒGÄúãŒU}¹¨ÇbC~*­ì÷ ®O?99$Wælê´cëjfæÓ˜‚IÌ}^|ðY¶DlÄîK4ešŸZ:}ÿócÿ̵ÿúæ»+µ1Oÿ¿q«úÿ›7×oÞjo|Ðl·[›ïý?ßÉO¹ý×_ø¬!~Ýj~¶µ±îÁ½·ÿl¬ÀÁþ©¤ÖO¡ƒãdzr*Î?XS°A˜êÁ3íŽç.JM Áw3êßÔü-ÍòŽ:ƒÙÍtŸÝvýþ©O>ýÌ ÿ“þ5!€ÏÃÿ\o®#þ÷­õ›­æ-Ôÿ¯o¾·ÿ¾“ÁÿÖKîÑúµõ&b~¶ÕZÏB€7p7ŽÌ 6dè±áÑ¢¼šŠ©¥s0Óˆ„ëŠYƒeÐñ<û…­ù§žÂ_ôO¹ýïºÐÿçóíõ[ÿsscàüon6ߟÿwò£Ï¿=ûˆÿùüÚí ykë&d˜qöáhZpvÂTüÖèõ+Pï.µÜèõzêÈ‘‚̆¹o®åž*ÇË·Û~.u"ZST11Šs+vôìEKI_xþVÐ Âé$±HähÅœ]? ÙN†“ÕsžÜ£¤O+„®Öø màm1ôåßêÆ¡ì¤‡í¬’2^£²ÖüÈ/@ZÉLî)¼ñÑ{Úþ~fù\úûøïYüwóß÷òÿ;ù¹í9~0üûÍø÷"ø÷g Ñ¢¿_$ÓqBš^kGH”)A`*õó$ÅÝÔó™3bæÀˆpKЦQJÀ<ïñá¯÷§üüÓ“ëhcöùßlµÌïæü·Û7o5[ˆÿ~«ýÞÿëÝüøÑ“¸ þ_ëÄBøgìÿÕnzä ¾3$}Ýõ¨1O tøx‰×ÕiÔû\ᛕQ8Œj†!ç«ô<ž`6Kx!q€è1Z {ƒx¸ŸÝ@G¤-6¡èãcª鎡pGEÂ<‡ǵ»kœ'2¥÷¬ÛŒÀ×K©â0ŒÍ¬’7³})kêS†pͨ=Ãaz˜»Õ\ß„g@ý¨CõO8ÝõI’ô‚óQ ØþGQÁ@ÖMƒé0ž\ƒ†i£BÉ£»•Û™éjèùú"bqV¶zP1ÆNÈ@ÙY{AÏuðÔ>Ì…)a0¡3èW19udHú>CcÆY+S8•­5PÝÉñæðYOn«*c}<ˆ´ºzÆCSšb³¡F€;c0Xr±5ëÎ~yàaü<¥î„Áé8:Þ^þ’Ôžðß;ká]3sÃ)º'cÌ1 ¦£‹«\ ½ 8HØ29?+,5ñUÛa`i2aG•¶Ö$úÇ ¥èÄ} zNHêÄ®µÅVð¡éÊÊ»ªŽáßÐ^2ìåàÔLì@ ™¡Œ/pƲóð̘ŽÂÞUN'“ÑÖÚš»º×¤fÿ«ä;Ÿm…@Ú¹¾›€yVæ¼ otôªa,:OÊžD“Ð’j…zv^šXÓ3«gYȃ”÷µ‚^Lb>Y¬ó)0$‹®ž£Á%rÃÚ²+†4N¡/Ú ]Álð7„‹ ¹®ZŸ¼|ƒW«Ï†/2)<{ `@A±×6\WáÌî‘ÓþK±¼è‡h®ÒÄ HÕ2s„Ga‹TÑ莔SDñÈr£Ê •Üc¯“¹Aé^/²_GÑxP|jèM~»Vøb$ÏEHµn+àªÑ Žü|Xö*^ä^¢¢üEQe­NT°9Ê P‡¡ø#`ú*3ZÇsvÁ V<ünRJpúŠy÷T†)q`ùÄ’ÐtYN„ç3±s¥%3êêÿýe‚-\áÛªnÂÄœYwÙ»Ú_¿ªùO ¦Þ}òñÇôQ!¶í;|P›ÑeÚ 3»\¾]ftº|û½U·¸x€(Þ4ô†0˜©$^ÀÑ‚Ê3ÚÕLs4<“£.ˆš$ehüA!áw2BʬÿÖã'Ï;ûÏ¿þzgÿ`çAg÷`ç±u6ì+ræÀ¦*LWÔˆUç#üo±ë£Ý·d´=º³\¡¢ÁµjþøuìüóY`ºZ…„£<¼÷hGZ#¥+~µ^8žÞ¿÷¨spoÿWo5•rÇ͘Ì=ï-ÎqA±w7¡™-XÇóõN&™ËïgÎàï…g!k‘î“°ö3ˆÍžPb›:ß/2‹A3ÈG_Ý»ÿ+7á€q,Åà.BiŒ<8Ÿ.ȦÕá+ÙÈ"+³¤ÙöÙ¥–`Ì?|(:èÜÂ’“b 4ÆOqO¹72 — æôQûgÝ€²4›ª[Á$<§‚D²ãp »õ.Ÿì*{Yî¡*©ËíRØ.€˜V@Ã}jd´Ç‰éHî,H:¼]Ùôa.á…n S$¹¶0Xn2Ž£³¨` ¨;3ößûƒª…¡[,nÄØPÃ24¼{OXà;x°ìàrA† -v HXÕüæ°äj¶4Ü~¡¡ŒWpão¾P? {Ua¾­3Nq]¸4’\eæu˜ü™m>Û,2ûˆfå#(sÃtŸí øè÷L7 “ÂoÕäsÓŽ–‘@Ó»: ¿.Nêú˜|a:˜Œ±tx™àtT`þó$†TkÃã~ܤtKr/›T(§$/ä7÷¾Yåü¸¦ ?u4U°â™Òµ?ƒnuOì.s$Å™±=êVú½‘ç–wÙä9 ù( •á`|Äé°2 ¢!ÄFˆ•ÌŒíÕa釰åZ)h¹ãU"º£œ‡—©Õ1'б¹‚ïª Ä»·Áõ…§ái›æ$wÒÖ¾W†™^g-Ðç8)Ì`L%Æ&þv/£ãcðåqØ“75ҟÄfå1!ÝJÇZKe%›¼HχýØ ˜0ª?ùaŽ:†H&]–š>Û¼ÙlÖƒÖ­ögðïúÍMøw³yÿnµ›ŸãƒöÍÖçmøåægëŸá'ŸoÞÚ¤oZë¦LÓÌì2cncH³eHú[éX6Øïâ}ÆÐ6íI`5wEgcé íiItžÝÀþ¦àêÈÅßb–ù~8B¾3²ª9æƒÛãù¼»h]GqtïPàCfvA×ÔN)êI¬ªyæÃ#Ô®¢†¼[AËÕÁ9׈uáUÒ-äüï(!¥8Hz=8#„ìmïæ`X#ãO‰ï”óS%ø1³¨fø*`ådžä8h²4sž¬´h'JÂ-‰*ÏΓ´QNø*÷ŽÉ"F0€8éÕÏ æ4y¾PÃ"ˆ¯/DDL%Lì#%C›~ZÉ“K|F­áÕNèlòAœ:4t¨O‘Aó Bº]zH <_FÞ™7=–we„ÌžyUȘ_Æ kMc#ó3êŽd2€ôÆIØ+´®äI6ñÇõàãœÄÉKä_Â-ö°O{—zs…Œ "T¾ìà(=KSº%!¾Í,0Kqç!:Pe&¤!¤Kóè”C4sýZ²ä{¥óõÎÁaå‡Ê «Z…+ÆlÌ–Ù‹·…)æû1)ríÅí G·ÁÊЪ2*ãBöFò¤Vd=uzÓEEÏrϲü¾„‡ÜS”ÜápŠ¿d¬¼A¹¬RÌm',ë§œ/ ÒÕVT i«h" Ûs„鱦9SEýô˜)æO¯$o•G&‰/‡Ê½†¨†ðÝŸ‚Jrõ¢Å°2Í„f}¸ó¢á®[tEZJoVÇ#ϸ¯²cÌò[ zÒ½ÔxËFŒI;l‰4þ#z±áž‰VTÜr/œ v(°×9sðe$ØÏ™Æèp¬\$3ºP11±z.vûSCŠPÇU÷)4"޳ƒÝ^ò¾Ë1‘šKÌÆÊs„hšh½ÉÌé¾'R‡:ȕγ§û†ÞxÏI{`ÎÌך®¢‹!’>PÆ4Ô9ÆA©ƒoª~#Y: »g*Ú‹C\#"‘RÃT»‡#ì`6ß*~&)rŒD…7(R÷d`ÃÎ3”H€¡ÐÈ?{q’²±g.¨.ðêXßǸïqÒ\kRT+LSˆ²Ç‚½NÀ«sýGç” }öSªíL¢éuÛ£$¥viEnëWãäÄÌÐÀ¬¦×1l|ošú ¡T/îÉ%;­k]æK‹ÿ,#Hä8ݼ$¼˜ù5ìW8  \Ee­›%¸ë/г?é›ßÄRífœ9ä ®‚> ÝŸŽô¾³ÖÚkE=¥ÚÉÅ8­gö¿ôœS ¢žØ,ù&Rž%wº [®&€ú¦Cä+Õ—‡VËó¢d^°JçEí6Švãè 3½é¨€~‘¨Öh«¸<;„!@â@g`¦¨ø4f-Dª5¢ùüþû4V-ý°v02b¹¬5Üdm!„MâÓÊŠÛª~<‹3ëAêz—£wÎ -”‚^Íå}r§Ç•™DaÊIòíÄ¿«U2ûÔ ¿ZdväÏ}«Ò±(Õ°—{Å%¾škBœý€.'ç äúÕ|«}!˜ºîÍ1í‹´°Mq¢%+øú´ÜŒ{:bªbICtœó¾ Ó`%ÆÍ%Êf±¯"?Âú:Çd}§gûU½þôS±z¾Q•𴹪¬Z ¹ÇÁacé‡ÖØÜgÑxœŒ«ŒÐýâp%~qÈ-×Ãyw¿°•ãˆ$'Æ ©8S¶JÁÎÕs'h»”6¯¾€ŽÀüP?~Lƒ¨¤áNü½D{f{³ 5Íê…Ûߨ­š·D•XM•”¾,f×ÅFªÍ¿y[©Ë0e…ƒG¦+¤^`nÖ‰Fªg±ŒúC@Rš7CKh^ë/4üBø…*§–MèwÑ%öãoü>k«²=Ev†ˆçr`±‰Ÿ•ØnëìÜ ¼ñ¹])œ;5Ÿÿ,Éý(ÿg²«5–l{ÊG19çßa—NWÀŠ'å,cíƒÊSF/CñF©ØeÉ­g6ˬØó§üGEÏ]™(õIðld õiù*}x8 ?J+Ë~×âQ‡ïª5¿sŠžQÏlN²ššHšuN¬–-X>Vï³ÕÖmÿ¹· $±—'AánÀØ0FãÒ8|—¹ý>œ£LPW!êeÒ)¥ d?Pãf!"1(®v'e¬Hñ _:nê¹õu¬ÛAËI·uvŸìïì»Ož «âÈPÂZðí½GÏwöƒêGæ%ý¿–Ù4¾ª²î·/.“ÒÉ#÷ǼÐ-$ª(­z}+yïÑ$oãèìæø¨—¡•9 š¹K¨C÷ÿ;k…vÝy`(•éÎü»«RXý3U1„Úä*ˆÑKÔÏÚ ·ùÆ”ƒ/ðÆC«‚ @´82,uì–$ºÀ’B¾ef,èŽpbWŠ©dXˆßK}už³Âf è5@T§ß!`&€Ël„ß„êE 8ŸÒ=ØcñtàR(†'aLþ F@ìÝŸ²#gÚÒ9ê²"Ö¬]À±~aÈÿÐy®uK¨Ï c}lçOÊmÇpÚ$\øªöÓe6“Û:ôœú®Ÿz² ÒÓ©ùuÒÐÀb%Ãþ…¬?å˜áý:ˆ{=ØPÈ÷z¼öösÝ2FçÂ{g;P-ÖÁB S$ £†­¢ØûO¸ nÏä>²úý²?'™ Ô“~ôg"Üû®»yúPÎÁäº8³S ’` î)&ÁüN§(-ïølyáöì˨âå*)œºló5àTlp¿Dí(;óZä=C$_MÆa`§¤= {áhB:7¨ˆžˆñÉó«†Põ.¨ÒÁ~Î qætèäÌ>ˆ¤¡ÜW Dþ$¿|þ»H8ôö+rÏìC°´)$ý¥h|3iŽem‹¼ßxG¬¬·Ô|È‘¨øI܉_Jº7‚Wûœ`NïÞþ~1auª"鎤H`&I¼¢ñOyîf°\/ßJµÈl…O pÀsÎ~_ Ë¿.gU|þlSz¾]CÙÏHÌø¥y7N¦#|ŸZˆ_{Ý ?;-’®0OÜyëV?ö-&Þ6¶2yÆOø·BÓ‰Ÿëý*¢6Ô"6ø0ÌœwOèÖF™KzXå­Ì«e~Qз¬]˜›ÆÐô+:Q‚Üy)•x0žÙBV0Ã#d±‚À@2s|¡/J<Η­{²äžÁ¯8T=pov_qÑ’õ²Ám f^سGQ74›FA e8‹’ãÜ1`ïbz‘QT$ZV åD Q‹ƒòÊ…É0‚A"w_"F¶í(E¼°Ê)–Y)"Ä$r† ÙP&нõ¼Ó†V4]9QC}jÞo/•;|KÖLó&Ç £2éì èM:ûà)ëO™Ql†#‘Ûø ÁSRÛçî@悱Eã1ËBÊÐ]`à{v]/’©áÈè=ùÜaˆÀûf…7å¾i™) ±í¢9IfÍîSå6@7®Õ¦Ï™#Ü"Y~´X9íT(y¡˜ù|‰YHà ”vY%4uÆÓFp³„òâöEÁœïÈã%:µŒæ9Û‡µ'ب§\òe]+A‘´+Š ùíÓ uY™Ò—ò9é`Lrê$‹7ÛœmàUowŸS¦,ÜÔŠ³íÑq”á¹áu¢3`ßAžAå©‚À륡¶öЈEnîÝ¡rÒ-Ú’þfŸ}M¼bDxã‹û}Nþ:¼ùÕSu füüK²–ýÐPy¯wÒÄýÖ^…MÒÛÜG˜¸ä£\au!ùWûoìºlÒ,èÖɶeþTw”úV›±à¬‹f¾-ËÙèI’e¨ +ö¦@Ì&’U+YZ¨£ÖOÆáè||Xxs5*Ù? 6K·Àdz%›Óÿöã¥{“Ç.ÄŃéyqL$ÚÍóÚr)KB©bSñ}ºÕO· tûÖ.¥ûákîA‘IÀÓD-±YK¦Žõ—æS}Uj†1UƒZL·[¨ÖuÀ:Ù>7¬ï!U‰yDfEMnÝwz‡gd³ucìfl÷OfÇ–pÚ.8m€õè÷{f7PÄWž÷$ûo‰0!}ÉØKóùÂÍ"éÛ<ÚMÎè­l]ã•“jš“¼p´@2Dkoiv;rg=ı9Žù"”oôO?Fn ßE†kŽMûàˆOA^ —ì£/¾rÈd»ïÓj6à‚Þû>%œOàZ‚•j/é"LI­z¾ªôµJ¯—3Øá˵†a‘ªË„ ˆ¡œC 9ã{æ—k·ƒ7ðßAñâΰ'ô­œšvÁúãÉBÖáY–{ÈQ] 6ö(F¤53÷ o2”©E?ºðu€Î53f"‡^K<Ýp«_ MXÿ<¼H .ox(Ì/ØSÐàÃéJH°8Yb»„Ëbæ…š‚ÊÉ£Ö·.“{>ûºè6Íô´uíêœ9/ï+T,¤©°fÏ=:“¼Î…³÷s¨ƒÔ¬ .9ŸS³ÄZ‘Bu]ÒB;q™¨héÞ ¥oôh­šgÃ Ž ¸‚-ÍøÚS!ÀNÆÛ~sâ}Öß—(oó:}YÓZíF9K“žt<Â3ËZM¼%ùØ6*ôsœ¥…P¬Û´K™QWª4EÆ}€BmXî“ ÆJiböd M1䜙ð8ºmø’‰¡Qð{ÀhÜXª„=$m¨B42¢y`3´ìá¹|@vߘÕÙƒt ¶º~ü2ê£yB¼ù sl%Ö2M]MŒã^Ïô舲˜ÑTõà `„0ø#ÂÚ`0²šeø Ç¢OŽõÝMÇ€nëåÓÂÝ/k•@-÷2ŸcíKF`•›ÂÏÀ5_ pl^V&P|)a¾pû”Ô}†Û¢fÒÞWG,ÇËSgñA=¯|„à Fc­ˆuVéÖ4ןѣëR~ïÍó…‹œ/¹dFîퟅÄàm™œÐPD ?Ë b „ ï罺3#úû×T]¼±BaÖ¦6…ÞÐP6·™¯gFm_+WÛ'nø_rNˆ°Ï1NîÐÀùû$h5›Á &ºb…öú¢NXSn©‘{`¸p:JW0З…~u¨r~Qwù å¸w%}rÜcurÜÓØ,¬Ó¾¢~ü>MÉ…ètæêÊi¸•ÚR"¦HY<'´Ö‹ìÊÎeéLÏW`:Ì2oîpãå<©çi'uà€+t¾[ìLEäešº„·«Ö9š™ŸŒC#Ù`³·T;®^^í¨dʼ5`îJÑÐ ¨Â¯€àÿÂ3EóÓsó‹[æLD )hbzY³Kù>ƒÓÏü§<ÿ§º”ß²yùÿnnRþçÍfûÖ­æ­šífk}ã}þ—wñSÿY-|6ëó­ ùÙÖúç[ë* Ÿý¥£Ó¹ž$îtM.›I,˜דô™ÂÌ(s|Ï üÔ²TêØ¤Ë|æØ3úÊý]úåÛåY–/Írís„Àâñ±3(±é(ßêüÍŽ™ÎægÆp¯‚LÌ*¥±.n*rÙœÓÉE?Ú^æÜ~^n¾ ¢n/KÇ6äòÝòLËüùr.t¦Þ ªßBШ †ªÈ,•–…ùÿ’@êáßÔP[úYåm¾®Ÿ™ôß—½®ÜÆ<ú¿~ëf†þ·Úí[ïéÿ»ø)¦ÿþ¿Í-ßßßïö.øg“’_í'Kÿ'á«d˜ .Ö®± ò· ¯wIþWó“ÍÿÚlµ>6®±¥?ÂééúË/ïß: üœûýfîÿ[ë­Ö-sÿo€ü×^ß|ÿ¿‹¹ùÕrëër~n­æÖúæÖÆzÑuÿc9!G»Q 6G£* ù ç¬"bç?‹CqìÿfÏ­ßú%˜ß{ÑŒ™Ã‰÷`ÍÆá‰-V¢‹Æ¼iJrP…Χ…ÿ‘¹ ±“€“$-˜Q´­ØˆIÆNR,m¦6ºmUÐU ŸxÅ™ºÎÀD‚ƒÞVª•2©F¢r·u1®Œ²òÝm ‚¥'?tpP!{C˜f'à”ƒÅj @)«:$;Îs5Äòœ¶O¯¼Œ"¸*#3JÎ~9„pNÊRW«™Ï4–\aš ·`8¥‹QÔH†û¦6=1\û^rní(Ð5;¶U˜ÍUl5:w¦àÉûÐ*¼‹ÊJ4TAuæZ{Ñxu’ŒªR—_ Ú£d2I—ª™?©©@X^n¿m(ûŸE(ê±UXß!º¿™î T` :\löù°ù¢1ù*éÅä‡i ãÁðE­öz‹Ì¹Šô,¯oî^|F«Ëò¶-.К[*èü3‹sŽ{3× ÏåjùšyuÀ¼Ðóg­Ÿr!/Ûõö5.饧í lþ{Éüï§¾ƒÊŸùü_<4R¿ÿmÌæÿ ³wsøÿõææ­ÍuÃøþçVë=ÿ÷.~|ýOvÑ‘¼Õh7ZÀ~¾Öl­579üúgEì`8_÷4„9C¥´gß“¡šþo‹ñ ƒŽƒYó}íº‚þ†;ŠóÙå nˆYŸ€äŠRìr¢ÞŒ;dEÃ} ëXq•é Ar¹Xð+ §œà(ó.×ëg¸zü*ºØ žã¦ a÷A£’ñs ùÚ¼¾ÆÃÉõtñUsÖ@aõÛ³¤Mûf o¦‹¢³r) Ty—ÛPjì\ÑHm.¨ò¡š ¶{ª’!›— |·½±q…±V*ó‹‡Þõ:ûEyçÑI¶¬ƒ*é ¾´PÕ£ødfïꑬt¹¨·*…ÀÂê*›ÆußÜásg˜ºEí‰×P²R’ôoÒÜÀlVm>Z/£  g}xb#S¾*ÌRné’EçÏáÖíÔÕy£z'´“Ù»ò.©|Î}bwGcØ×¹HürŠpü‡öÐD¥§ñÈȸ“ó(úsõ6Äð]B"µ±—›ÆÄ›²MNÈÛ?¯A-_fP•4 14L®‡¸¼ A/—€òÝ›y²øªÞ7E[Ùx/º‹½ 3{Ž;ÂíÍß¼Ã_ÀæÅ$’˜5RÈú/âª/ÌÙüÁü2ÉJHw°)CR8Èù‡Î_PüS±;þË¡{¹ØY´µD9W Æa2\-½RÒKß)ã+pØ×ÃE[ž¡˜6“×ú™íË—Áq<@ef‡BoQJF×þåŒ.º DÙ,6<9SZls(J¸™V'3 ´èužž…OoA-¹¯ËŽèxÖáL/Ìi»\NÀå9|éOvø¸“ågï—³9˘˟­”JÙùdÑ:\áÊò×H‹N<öN¦Î­EGZr8œò`ᣡô —ÒÍgµÞ±H ¤øðü,÷ݵçÜ~–j’y%ÉìŸFýÑÏn¿1 xW!msäÙã±—ëOKƒ/¡úÎÏ#€ˆz,#B€­¤£…[vCPs@ºOÉ¿ÔÃTŸòE­h½­æ—2?¨›„ç q—ÞÛ ‹O ùaÖƒ6 œ0’ZÑ É»_Ìe6E‰£Äñ^±w‹p ·Cÿ.¹¼Üí¿ÀÉr§LF‚tõ2 ’™»ËÎÐ$<ùÅÒ¢ã18ц''0f„âKÎ evÐê[u(ÝZo‹ç`sˆ|F²Àð`ßÇÑ¥íg ÙÀNUlo˜Í7SÒ3˜Õ\"ÍRš–ã„ñCo¨B)m¯¹Q®ƒµþI“…¬—…â« àªçr½ý£KÖÉ '`ZñÁ1¢<‰6Ñ!ÂÄeíi0^­œ¹¯Ë• §iKc ôOí%ñÏîÏ|ÿÄ*ƒ °Wnc¦ÿO«yËÜQäÿß^¿µÑ¼ þ?üÞÿçü”øÿØE'gðv£ÝXg öZ{#hµ·6Ö·Ú7KÀà—{œ1kLI ÉŸ˜A-RËI›ÌR‡Ôõ°H0_*á¤"Ð7x(Â!Tç]ųJ¬M€›þØ}lÓ‡fff•ÙSš±“ô¥ºí>8"¿¼…ÅvyüDå5AÒ«Àê‘·^Øt±—‚¥»/VïƒõÀG™¤dÈZœt+¶J@úÄzzâËC‹÷Máƒáص`Ë£êÒ¨ë^gÍe(kÅ!%™­©’·gW€ÝWy*ŒÜ£ç `ks*Îrbºf-3ƒ¯ÂMÊS—έ™B]£ã>Çxó‹ãÓV³^–ÛÜUN_ÎkEJÓdx¯X È챌DeN¸›Š®¹¢kÙÖ–çβË3:ƒT…ØYý¸|»a¯7«Yóúò­®™¯Öà«ešæ)€È Í ŠÚH8y;„Ïd}¦=Š4ñ1ÁÐON1=ç·V¼_ô 2l°†½ût¤˜c©G ¨RžRKi?<‹,X;aüh8G©¤1*³|ÿ猔à)i8xP ±np~=ˆ’ìÔžž'j-õ#g¯ñr ¨¾É‘è"y¢ö€Äs·ˆêsN“átãnJÊOnžv*úòa°ýJf!ܱHµ Ö*Wˆó6ûÈMÝEµ¼±’T`‡W­¯, !ƒ¦É˜¹$ ÒLFCCô^ig,Âj(tßèÛËB×–@œÒí§±MÕmó®¤ÂÑ”™u7¾yzX€°îê³­]æ¾E½<}9 ¢¶¤:ST"Ìzȸ³ˆë§h¿í*[ ³…rÌËbÓ {©É¡{ðRŸàæ}áe鲨½h«Ay{ãðäi½cFKÂåOkïŽLåÙ& ¡yâSf‹öÐÀÔ`ݤŸŽBVwlTÔɸ¶n¨‹4ePíÜMµ,¹nRUØQóíw´†¾÷©²à\îôfzpÈÔ®xÙPr”€¦ÿ2ý(?¼Ô–”ÓéïZ?U+J S©*ŸL[µ ½O€]Ý;Xeˆ«8IÆñE%&íü‚IXòÕ×j_j¸Ô2¹vé.™½@ÅM![`U¨þY”Ó:ˆøópŽS>/x©ã%ÌÐò/F”‰­è ÌœèCwW^eÐÅíƒNñãwÍ͘ƒ{àg“òøÌ^¢D„ZïB>±…n&UN÷mÈ_?fÊksfÁÞ8W™…=ùxþð];³†? úQ˜NÜ@%Á‚62NSLóG3&äÌîqþæŒ{!¥gј…Ÿ;biaÆx¿õd³Êì}Gà2aÚ5Œ4f¶Fç#Qé¡q>K½‡a²ËÖ1‰â«Òeøž;Û hÌqa.W¹ÉhôKÖÜ0ÆÃ^8î’–ºÈ[x­€Ó‹"õœÒüÈd¸Ùª4+z0”(Xöó¼¾»&S|É&[ÒäÒµi"•àp-BÐòŽ[¯0* ¼Ä„ÑT˽! *¤7åÌzNzÏ-;ã®ãfÓ6n&>ÀmíÑ! .GŸ:ž¨ÒqYc¿‹(ÃeBY¾PÛè]ŒPßQÔ §iD`µôæ9㾤<ŠO¤:…oÚ‘‰‡NIXŠÇ&é²Pi¥ŒO½#CÑ0of'ý¡oåG;÷‚Iã“zpÚ *À ¸\¤t0 vŸ<ÙÙ ~ïéî~aµ o‚ÓàéSóDâ¿”7j‚îö˜ëéÞóýW¿fEI=°‘Ä.œ8K$êA³Ž+_Bembo9"Û.³UÉ8Éûé“Ú0Ä·Ìù)¤U°ì”ÁqdÄŒ¡WeAµëÆË|6 Å-àô ó.t®QÙjZWo“k°óPÚÑtóÓO}s¿>¦¦L×s`Ç©„n+4­à”˜sC]Á¿? ÕÒ%¦éà1T±±Õ'v* åæ„Cƒf Bp…“¨oèx,4¸¼ra@ÞQ{‘(iÓ9tØ÷²Ù,éw¹„¨Htgñ‚û$»)Àó.{ñ˜âòͪȠïæâ"ë…ⱑ±âá4šÛ}¹oŠ{/®{þ}z7w›ÎJòyžh\L¿·Þ}8»³®·$ž¦Jé7~ºíp2‘hÆ)–R· žî‹^4šœÖh5Ô3¨fm±IW—Ò6q5ô#wÄ[®XÞ§º‚ܺ­®Þö^ºúõ$ÉVÒ}6jÓ¯:ЭÞö^È,mDÿ½éÀÈpI³á“æ•oMÅH0ú˜ªëÍRö7ëîäONÁTc¨ mñÍm7'w’\TÈ:Ñ16Û.ExrhSˆª,ì, ¹Cç¶ìvnÏ~êwäÓS¯dçz˜ò’Å1{[Þ¦ý”×Àv%‚ŽB Xµ8U¸?X†Ñï-_Ö¸Ò)ºòdxÃóY-×¢>¥ã!äï®CcçQå, N’ ¤ðî'I~Ìá¸ïÆzmùHg¹1l·è*ò/•CwÓ½p»­¤î¼²añ·ÜYžy¡Êƒ‚zôNö¹à ®S9#Z¼bf#¶²‹ù\±Jg±W9ö¤€ìcB+mÁ©G'ótjV$»^›öedå móòúGm±íê°ù"GŒ¼C£·›9ÜÈ›,'§Aè)Ï´×WÌ<ŸCG{à ¦…#p»ruHjÀ ’ž‹^ÛäÉb>2{)š‘,?ÍœGæUrJ œŸLõ^Y§á¢ð _½ìFq¿šéëZާÐ1’†çàøÜ7D´w!VY܈ÝÈœß ÀPŽ“#3+Á)iÃ~ÜCm UÇɸì qëL”æj&Í „)Å i4LsmS¨™Óz°kóœ¤ÑecN?‘f£`ÅŸzI5HgK½áÅ.ù:ƒh|b˜P,W÷ËP…¤Ý O4Í&i´·Îuõ΋ßk‡½³Q­ƒ§f]¿5TñøBeŒ;nŽA#C\dYy‡÷–Ïûж*š":u5âÞ\È@YÁCi2žÖùSl/Ï`FMXĹü QPÒüp\H¾ŒŸõµÕ1Í91ÝÉ4ì[3ø%ìöbè,_Ê_ÞK€î /„.&a/À“#Xwñ€i»ç‚µÛ:vÍ¿ÛÊ„VK}u X«ºX˜Ïü $I&Ñ ¿)¬óÉgz"Âa~`˜¢,\Šk¹¿,»(dótÍ]`6$ éCNÂL™~è\+î˜;̼åø&¼-|ŽMîN_Õù"øyšx¦|»=µ!þ4îõ¢¡Û×y;.~]+lF­ÝeZ2;õ×ÕÔstÆ" ¨l#ØòõDFQOȰeáûð,$ï—†j´ÀuFïúÌÑð¿ü`öáÚ€;ê(93{ºGl#IüaÐõÌõ¹ç¯®ÐŸ……ƒ•gÆò&¿« „œý˜ÝæVçŒ V¦Lb½(5,=^½ÕZMGAðöx€J1áö»f*–ËpÏr¥½Šõ]RÉ TP=Ðå|9š’Õ3]Y‚:s|Æ“Dà‰T¬ò×M#Ê<Ž–òûW\‚ì«÷£%µ¯¬cTÞuõfö¢”r‚zµ«6Ôì3çÒ#fd×ùÁTа—TÖøSù~ßY)cªè޽Ñ0 DsúöX¹Ú±ô^H¹À “ÜzÃÀú›‚ÇÉâßuÅSÎ9@sšÄ㨕MG,Ûi8,jÅ"~;b3z/‚ŽÅCb3¤_Yí~4ŽX½ohðétØIF¶"™¦!t5ûžñõ[@¼MCPÝw P¥\µ XT`ÜiZ댌s¨F›§ÇjêX„î„Áj k2ÿMÍŽŠlsc+Q26 B]=—â<5½0¿Ö!>Ù>DèŠD‘F†Ð !CŸ«ŒAiÒ—1䑃 Ï)}²]§!DéRˆ#yœq„sÀ8\>10œ†¥Ís¨)4ÛWŸüÇx~Bëæ0ÏZ¾ ù{®oŠÌž]ºƒ[‡¹1:‘Ž˜ø”jŞºÓ‰uÅa@ü‚‚«N1õÙ&È1JW²ŠgfBO„¾YM÷÷PXì9\ó©Þ’!e<‹ðó ã¶°íßûJœäv]@Ø„+r9³8†»DÚ,ô+ÌJÉ8>u[¹ø¹”æ•ëi¼lÝ•ˆ6e×t”Û2`y„h¾=I¨ §cà[y²ñ8—×%ߣտ™õ±R^hãmÐ'G/1„‰½ñÌáµ6o4uãêð¥ÀzüŒ v‚å$­‹àÃí"Eœ¼æâVˆ=™Õ4g‚ï’ÃÉ*ú{'Ôù5Þö ë°{úÝõbê±duot˜èsÑÝy»¥hdÂȾ@Uª+ë›ï¼™åú_è…Ý‹øÎʉÚ|­¢æƒ:p+€}ϽÀE•zG ‡Î—+LX–ÆÐO‚€„äZf½ìó‹É*±”$¾¼ó ÑcÈ×e7âcNÜOÑF¶Ž:®·Ì%¶Û{è2»ÈÓ?“ïIÆJÇC†hÃ4<ë,Y¡˜‹qŽÑà”)Ì­™27ú»´·;så•a^I´'Ì­.cXàEšûÙ‡ÛÙ•ÈXóË4¯NÏÆx‰%ÌùÜ-çOTÔ,ߌngIZÁæÓÔ.[ÃÛmÃr V™I½r¤0¯p¼äUtœ@ †ÊÉù¦*§ÍÞLw<)õ¶ëHM{YÌ¢¬ÿLÜDW¾zd•P— K#‹`½Ì”^Øãeð:P a?dBÍÎßx)ȰOŠó¿ŽûfW˜µ&n÷®ÀÌÚ‚e±Ûå/+½ÛÅåñ,ž—x„NFö.FÏ‘Y½‡E0—l#0•ååJ&Œåâ’·2é9n­Õо²¨YEûLJ³Ê ^Y_óWžrìÜDpj6¾ewüóÎ(Ic¼¡Xsà˜7Š UдÐBõ"R/×%æ4=ç$¾É(0/…ˆWdõÌ¢Àµ‡ÁÓ`rtË'ÓÉh zÎ+£ÇéjòÁq‚*ÂM¡ûšeîò^jKÎHßjàãh8µPâ·…®[œ:Ô"AíÌ{‘äawåA­$ð¡7P>Z¸(zïÃýé|«¾KÁ~Pe.„ÕÌÆ°Bí$] ¨§cˆ>‚K#?$¤>IEˆû‰`å‘ÇžOÊxã#X… ˆ  o,ÄE ‹äßøú]—Z¤¼¨°°àý1GC„’nv{íö5ÅÉ J66Ö³W‘mÏ ÕÌ„³g‚csó[€ ]Ô«ã¹rwì—…'çœj~àŠ¹¾ÌÖíû;ÄVL˜@3û ôÄ« 'ý]Ã'Þ zyEmpPjª½%ÐÖ°Ú{ûûÁ1øå5*5ì(ì…Ãn”ó:\|÷Ýãv`þþSïx…J¼§îÆø Ö/léíK(ß C-¢»èùÁ b`Z9‡ðƒ¡ÊÐ{ž½l»–²y Á±Ù8Â3¯8|pùú§ŠŽ§ý¾—  "Œ ,Жhƒš€I ÐŽˆˆDuÑ÷§Iò’.½p„HjJ€CFßT‚â›!æ@±¤öÃ’ðö\Ï­.ÍòŒoq}¡†}f ²Ìh]qø39ôZB«,úט=OLç›qÌZOœ¼ôx|üC‰€Ñ+Ìn@ICð¥ baÝ+£úz[û«sã]Ìÿn )Nîß/5­ûä‰Ïè"oMŸHº‡ QXŸ–ùþN¥ïÁ¬‰ÏïBUÜmß O÷Ò‡H+íèžF[Ãîºë¥„1Ú2¤h`Äœ«a “ad‡Á…·xÁ˜$kùÕ‰ö¾Ô0ƒb‹|¶ü›árÝßãÒìÀËé¹4èÝ\u„9”ôæ€/чQ£â±ˆzà9ÌÂË^ÓYìB›Ýpó:Ð ¬»à¥` çÞÜgy÷øEPþ #½gúÞ–ºÄ–Áþ1ö¶ÁÀ?&J‹{ߣÿ† ”ÍJf^|Rì˜ålÏ‹|y‹œxKÜwç{à~k#¿|/ܼx)Ñ`D$.,d¾/v´tä\³Ã!hÑlËAÂ9=:G ò.Žw*(/†Š‰!E¥ê´ç–†kñO¹†ÕÛ”º6f"¦ÑíÂSö­˜á£z™©»~ÏT‡ˆV芊;Õ"¾¨îüÍõ?-3¯ÉÛ4ß㫺š*rRì^:·3˜%ˆqVÐ5.¿`Dqß«ZÚ…D¯•³óÜå`ùÂÚ´ íÜ+L©ÕÌrÙ-Æì$'B¯Ú·EëÄ=óÉ·NïGªºkÅé|«†Þ ?Ú˜é‰ׂÍù£Îéµ4òŞ5,Ì<¼ÎÄhƒ[ñ<ÐÁö‚›¡ØgTR 対kg/‰Réãø˜ô0¨2ÜiX$iÅß&J3ójw†ñŒ¥´x*ÌÃìê²VZgóÚ=ÎD׈B‚UͰÊÓ.9þ ä‡Q ŠBVd$‹0øÕ`*‹Î"âgåJ¦ÂËgíNÙÍ.ù¢í&ÎQJÁ â>,i¯íÅÒÿ*ÞŒ´…)ç“ÏÏ&êl,<ûË›‘j¥2Û£º0NÙÄîƒ9}!@?Ñ´Ù;´p"îΚºË\wejýŒ^ù®'oÆöíì¢gÅ›‘o)³Ó-\È :t;ûÑ[ù¢}* ±ê'Ìš[n‡U¤Âò\ÎjUÊÚæ`–ú𚋸Fåv~ÖUJ9>]Q6,\3¬Ó«[½ÌSÑE…òÏñäR¶¢õÙf…ïŒî¢"hùeËr£™FÇ}págG}mõ€…!!ým®2À´T¯aC&så$¤0ŽF~H1’Æ% ››L' ±!•îq'~ì:iëÑahêE2%&œ!äHÞ²¯º§I’F.÷G¦‹u,„õâ5g*¸g“`ækŸöeéåËØ‘ƒFåΚY«Ü6ô"þÚô ”íãhÕ-;Yv’ @<û¶:ŠwYù`º,«J?di,{]fON&š¿E˜“ \/ ‰¯{C®çö¹ˆµ Ÿ­ ]Ê`>C(]ˆ±¹4CŠ,°¶¸L– ik›’ųD «_EëÜfäo+L3^B´ U-¾âk~%¾Þofþ¢ ¬.²|'1Õ?` 3¤Ž*ª­ð̆”Œ7Ý¡†ö‹JQ=V|°J\=+µ¢OÊîÎ’n¢²EA¥!eá.B8ƒ6º0dï˜0gÍæ42C F ˆ2ì%¨ÈžÕhTúú>(¼û™S•WiI/µ[޾ö‹u[E§ã'i®¾Ë~lÊÏPhýëÁKÂ4ñ"¤¾U~Šb)øZÈIÁµ]TŒo«œwË¢»4Ã<º]úaŽ‘´ÔÛ‹Â.Ïbpö–¤\mºr»Ì\Rœ1Á\ö:Èñ&?UÖyU.G›óìÓõRhE>C§=ž(žüL(³Îì´ }.?—>7siõ ü>MõÙª=/“N£5›Î^[6 ÙÔöÇÈôãÑ\eŒ@äŒÜÞ΀’X°‹«’ßr‘Kl©‚ïÉrYæºfÂP½{Λ_ I|ñž{7„uöà%S<ê)»â´ @Jpt§é$¸<“ñ„}Üôèúå7@ .ÐÛ]Œµ3÷¿Í-Qp@ßêxϽ=lˆ Y¡2yöwÄMâ‡(ƒÊâpÅ«…Ö'KñKhæõ^7?rÓ×tÍKF;õƒ÷?×ýC»usý]ÝrØðbzó6m4ÍÏæÍ›øoófËÿ·µÞ¾µyóƒV«us³}³µqËš×5ÈY?S€– ‚ÎÏÏW”•›÷þúsç‹Ñéhim-XÙím™E¯Ÿ­ÆÍÖÍF»±´›ÍÏךíµÖfÐjnݼ¹Õü<8IŽÂ`çÕ(X±·È—Ç1:PF`6íŽOÂaüGÖ¬#É×ã¡J¼qÊX©iò' $,›’F%Ⲹ-z‹„^Ç„T‰êÄ):iÛð5}ý•4Gáj¥ª&z›oü‹üvœ€XrÂñÉ$5ÔÛ’lPßåâ{éW8š V<‰{úoò†äAs›²@ö24Œ›Ú®›Û95_Cí‹,s?¾¤]Eð&F ‡ç`cŽ^M œ±Gh[+ˆv§ÂbÙùšîÓ~rNŽ)ãrŽ S7A”Ôámb¸VŒ~'œÌ ¢µ„ªB1ô´pš¦‡)–ßâ^‚¹šj'z-Tud&ìÉO¶xÂ2Ž5ÛÃÙ@'àò†¯¸}ŠÕĦ!¥"oJNVŽ“Ä5”ŸMgÅ,˜B0¦ã'êoŸ Çžq¼ ŸŽ7¬s]iSÄÙÒ³&ìr©²Rʸáœ%؉^½‹Òng3a»£ŸB¿Ÿ<}°Óùêùî£g{;ßîî|§¬ûô™švî© ÔÈlâ¡søµ(ï;‘i(‹KÄ3ô`ŠR·móÂI²:… .ß’$o:ìÇ/#ëˆÂu%„‹_b|dzÚö1GàîɛŌ)¤~éŠ@Å5äÉ Fá‹szÉk†cÊÀœáv8Ì@/#K¾8Q™"‹Œ/$UNÇÑ1yqgHìä”»“ù@Áf(Š46GKŸPâ7ir¤:à årMYse­¦*W¹šÞè |f7}ÁjÞv¹`¢ðkÌ<]ƒœ1è‘–‘Z“L½ ÉŠc6t¤G»ç¯V@$Óa²€½Â@ žõõmïcÕ’ªw»ý;Û`Áч¶Šýºd¯äö‹ý +Tgzüf©èw.Ï9}a ;ÄñÊ O ðM,MŒ¬&Ñhäú—„|NßΤ쵀¤/ñtÀ!L|´H;N˜»°¤໬³úCsp5€{g`ºq{ÅŸe'ƒ“˜SgH9³i¡.z>p ™Ðat²Ç\‘ÇæÂI&ó7²ž£p„ÜÀ-ÆqjDKX†ÆÄ¯9¬`sà¬`c̆–¸”ÚNº¨írBy >T×"]ˆ8ümž¢N<ñDµdtÆÉ<™–³ãô–æ‰R•i ³1=îäU|SKàq8DÈu¢‚u+QÀQÇcƒH6Žº°É܆ԴP%¨ö ƒW²˜ÁžÍ/ ÇvN¨¸ŠBi…¿ËÇáh`ñF<ìVÎÁÌù^–tÖ¤?‚÷›‹Æ÷ñΓç;ï=tÐyôôþ½Gƒ{û¿Êã-¬¶š ÷$ìõÖ2€%}„ ¬ñ#,j ´†þ-ËŸºÜ”±S1vz¦}ñšV=ÎÝðÖ>* W³V`ÜÑZ…¤bz¢É!zÅÏ[‘ëx3í¾ºwÿW×?™ dÖŒa¡…ç ɸž¥ŸÃø·ÄG‹Ðë…‡íTó¶E{¡mAïx½®<v6g6Âé$‘LŸ3I—*dÏöÌ-¡ø ?÷4\–”À#º‡óîõÆú/€¢ÍáÏè¦.ì\ßóˆ @c-F{— ×¼ªW¸ ‹7þå¶…°ç8ýÈtçYél€ÇÇ®À³46«‘¼ÇMÏ 4ÀÃöÞ¹„Y¬ £·Œ=«núϵ´âG¥y= ë(†šú=cë¥I|>6óÐ1"k2îUµ»ã‘I*ü\±ç.?Øy´s°<Ü{ú8ø­b8†¨f0ëœ¾ÉØs—-‰³ßz„Þ´ŠÒÕ¤Ì×ÊבÝ'û;{Á§¥©rˆù£|{ïÑóý ú‘yRùÈH™~Õ©]O[èɃF˜ïûF_Šz‚ßòó'ñ|ÖÊ Êô Ê–Òî‡ù®XÙùÍÀ,¸æÿ - Åô_jižì|gOW׌?êtûQ8ƺ} Bj¹ýAÞ«/«09‹{¢/QÊŒÝyÉýdiÀÀr×CQRm¡£Ê98˜“_¯LÝ%®W ‡·ˆ –sæ(9üÙ_©;ש¹Ï ºž2ŸjÓÖ¸oj¼@âªU9™”×”Immª;Ž&ÝS« §†ìé+pZ·ªã1g;rlEn;z°’óömSšÆÞî»04>îö/Ø ª‘Ižò!à‡÷ÃL”Q°Q½0Í$ÿ±‘±.µØ0<ïUÛZšËp*K‡^fA)Cç®%)"¢QBš†9î °ÄA…ÃÄö%¦ÜC zņŽ%Õ'å^• L±&ÆaA¨J@Ï–9I'Ù(ªzÖ nVÝP_ «Ç -„ëâêóÁi³ë…ªLÕ¡ëw;GAìÇV³J–$ÆÀS•§“ñ´k6MÔÐè$ÅUàìǤ†œåœ¹£ŒæÌ Îð@Iu$ÊêR™Ê‚lâ´%Ïzw#]&³çÌሕÁ£èH†±ì@(4»8õáTìùGÈg=¦ БJCԥ敾­ ÙìÎ’fEdB¸ dÔeAÎxê8Æ/»^Jî]u6³žJí¬Ð$¨Q‰Ú.®Q`šˆúMphéi|<+}¶n·¥ã¥y‚Ý{H¼R’fåÇMâ®{U‰£¹ßD}@%ó±K!€jÙ³\ä„—cö‰AéñǼƒÃ”ñ‹(׿œƒê YØgS'[ÓO² Á¥Àÿ׊Zš£U•ÚÓ!ýö9Ë(³ØU{·[ÿPú¸N°ÄÂÔ¡uoÛòæWã úœ1ò”…²ù-ÊŠ—-;(æjçó¯%\¶#è…Â#™®¶I žîÁmß ×QáCkk+œ>…²¨ñ¼t6À‚¢HÅC±+)ƒpùí Ì>¥MÓnäž’y]ÇÑúâÇG½ZéÈUw„V¾Q´kδ[*¢æ}ÆL»IÕø+Ùœl5ÈBP4ë¶€•OQȧ¼i÷*»†0îäìJKÖÑÖ‹Hø èêç·z]¥|±qrHßaÖ:«©†…®Ò‡EWzk‰l¾Œ£ÆÚ._´ß|²òcv¢x,DlÁó²{¾hK;hÓüþc?—€I kû¨v£tlžTr-zÕÁãR“{ZªèðÇK3/Åú¢™îž&#×d•Qþtp1ØÙ˜-ƒbYö_(ºfÞNïà!YÑxˆdQ¤í˜Áä(\ÀRU‡d`q"î9'F{­ÌoÞ:¸.ŽÝïð7+Éxd¸óœ¤’/ `ŽAŠÃLE’ª(|„8J¦NHyd®~@k§&·ô–+ƒv€7Ð|1ÉœöÌ}ÝU¢€få%UëÚÆÁª±òR³àØi¶{ÛÁH{N[J„ð„‡œ'ÏI1&µOŠ5qÎJ\YW|‡O9óÔK«’4éÒC»ò¿h%‹ókHr®wi^´ PÝ•Ï,¬ʄ»H…tT3't1zUª/û:B’žÈ&F"Ÿ+”áH¯í¼v1rV]VûŠJÓ:§ÎõfùéØ=<ÿ *Lt®ØZ«ø æCÆ'[™Äæ™È|6>õ–õÃáK¬RðihbR­¬Ïú'PL«0sá‹'ØÍVxQ ü,ÐHÓ«oµ’Ç‹qÚIenüxX͇œòÄËÊ2˜×¦î‰æqµxzêÜéZÉ‚°?Cò9ÕCf 1þ í!ÁÆá”ÀÃ^fwÝðv~3»Oâ(G€õ;Î0)Ý*ÉÅîÕ7Æ™ä`Ïà±øRbÇ×VúiÊ¢þ3N£Û’=`†~ÏRÒªAASaUg]Æ,âJsÄ:Ì­q2r®^pN}‡¾£;³”Q›S¨8•&§^Q¹º3ë6ѵ¨·Ó5)e¬·[.¬ÿ–úEÄE™KÝìĺ´‚øg“S8¢™5öƒbPˆÑ PUÙ–Ìm.‰Ï)ˆ9qi×röóË8"ÅGúC¿ºÌ曳ƳÆ'†_n`ÍyÓYðhçáAð{OwŸ”†ÁÓ'T›iuˆÿÒÕĵn#ómnÍ;{ÁW¿6EIymú˜pV÷6:fɨܱUìØ~„A• â ÀQÎ,ÕÐ9h][þ á˜Í§ Ɉ­&n/Q¼K>K›€ u3©LÂüp‡±J5¬´KO2Ušc k• ¢qR3'/]YJq/É‘35Z=>BK8|XX{‘ÎüCÝGJ¦:éUš¼•váTKÜ÷œ¦Z_À­œ¯Q@uŽ1*bˆ OVÕ‹¬ƒ ¾»rª ÌäÙÍI%—+(›&(;$‰`–œ—&hÖ ³òqÜ^þ0—?–JjääÃÊ ˜$~q¥ÔD—šPXó Ñ ÐÜÎô1°A‚~_n»´®zz1q6ÂÑ žÆ=ßãÉŽû#"WQ$ž§EƒtGo¡cèæGŠXZ’û ™l_xó•BU~d™L=¾ÔÒ]èöû¤ðfØ}òÄùw{ßñXˆîáÔ-àÄ“ÜeЭe”fY>QÏüå× ·ÇD†aTŸ¡@Žœ-¢ Ì~™¦‘¥,\Sݯ„’™};Š“~à>NV·€Md²Ñ p†¸³?¦ÆÉmÁ…÷™JwCèTö—­ÝnL꤂Ó|>)àE«6)•ŠY>QÁÅ /âoå]5g¹»¢.çÖ˜„Po, ˆ£‹LÙþºÉ`®¦ð¼püÁU×…y“aòˆn‘Øúd7‚W!Üz[`¢š»ähjö ,þ`„ñKË÷Á¶ov‡ÝÆr£R8T¡¸6‚jÆŒ¡7e“NÑN=•“<ü‚YÃ+ɬ^/AT¡`­2—ÇJo9¿°v§°7ÏÓÖóÍ'´&ZüÚ”µØ+È„É+ëg¿l5Û7ÝûAÎl!Ì‹3‡Ý‰—p]9)ŠfN¹à»S¾"³$”>#\fÃsÓBù{òPGƒÆu0€X»„†§*ö]ÖB}jÊ£ˆ§ uDÎÀþ‰×Ž(dT¬Þà2’îŠvMñOìsQt²Ê±ÌÖÐÉóü.eå!¹}™Öíf{‘%Côü²µÙS–«OÞäåþ¼5K7Ã<¢6µz¯ýKÕK¢+¹ë«Ð9/¼¤(%U€©zÔ÷'äÙ5 Z¢ùl”ÏEÆDgi.T[@çÖû¶ 4S –çDÍ”`‡ìð JP@±õNX]¿=£ (Š2ÙŽHSîøCgÈLÐaÆÃªã‹ßð·Àw\4+~ S2‰BLðixhÆ? ZŠ4Ê~ŒÐhÊÐ!8…9ø ëÙ½A‰¥¾Š2¨PëP™ÂcÖ#èsXa¯7“¿â`yÐ3õ€zM ²‹Hð ˜3ÊQ˜F %ëHÅ?¦©ÀT#Äö¤ì™gMGŽcFqÅ=L¡û4ËðPÍs!XQ;ϦBÇü+âžC+É C3áA 1³ÈîX²^!Ã'bî»1åkå±XãÈòÐ[9³nD·m˜Ã"CÿJðeÎaÏ¥C=©—’‰ZÁúS »DÀçéð>¡ö]¤…Y+æÊ1s7"ï~u·¦H·t”ÎÞx) –ºˆV{¸§}:¬@E{1æÌŸc@¦n³¢kVùS{í£s¶}rÿÕ[¥Z ¨“*ýò?]à¼çñ¾¯J•Tʘ¦Í*YÁh!K̤ŽoIŒ¢V‰ŠU\pí˜Tnøû¡!dro*æþ;œOGàÌ ÉïÒ““$ljIz‡xçõ‡Ï[Uú›RÊV‘E>ß$ñ4'èY2Ówø¶NßÖ–§‘v™>yj;é)Oôt½˜õ%µܰëT«7uÅ­<ýd]ù.i“au~úþ&:Ü9ؿʵõ³t*xãÕnUãì<ñEŒ}&'•Ì/8ÅŽ’=Wu‰(—Xg/¿ÿ©ºXB®Ô×óJ_ÏK}­q"±éz€BWäv6mï8É”ÛX6E-Gìi(¸þ( ûäZ†z†n-¡%èB4$ÿD 2Qhc9ëÜ“µ¶n²]iP»‡éѰ[sµC«Ã Ôö‚­¹ê[Ç«QªP’zg. £ÎÑ¿j²7yå _f›‹€ÀûÍEÚÚÛ¥›8 ½9“Û88»ƒŸ»û{³…Ê™fØž^Rñ¯Bª ÊñÜå=ž,a~ÓæŠ–Ü¬Ý½šË=ÔûúÙ×p «O¸Û¸þ„ߌrNEKœšå¬Ã€¾’î¬3«ÑÊÙ©õu+jn]èJpnm{+Ì.Wõ†Qó[ ÛwȰøÍõg€{‹Y–_sŽÉ¯ÜKÉQ™oéRÕømYêÖ4¼æ,'oIĨRXz×'ùib?©GÞž|÷]Xceé ©˜BŠ®@K/ «ÍW] õoóëmëZmµ­VÞB¾àzmwè›ÕÕ¡»¯ƒì>B=/µ¬¤¡—Âz>6÷ô·•!cš¨<™BÒ-%j­„,õæ Pz7sòŸŠK/ê*rR–k ZV‚5!%f’s‚P]}cV~åUuÂdMÝi^¶éö1Š‚+ÌÑà»P.;Žß÷Uyèîd>>[ù A6µoO@'zš€^]ÊíSäô™m©_îex«‹ˆûpáT¯uZªKׯaÿ×P“´Æ¼Éüe3 ÆÑp˜Š\&Y>†br\6µ½ÄµH:u²«@ö: ‰«U¨{Ñ7–…2ÿÂn„ؽ81àÈZ¶UmmÕ¡ª€ßrü&UŽÝé¬Apö_¼^îI‘rV  ³íh ´ÓĘoYý›N½mŒ,m§èPÜÆ<׊“Òs½ù¯-ÛH<ýµ8›Èµga~½2w¾¶êDøèíËË<%ž;µõ7 üÑh1ÈÙÊ_„LM°€ôòõÇd¢‹}ÚVv‰*Í5AÚrd‡¥´’Œ#—Ì2xìeTMÉP¬5žün xGø–}ž$R€Ffo7}2a¥o= pb£Î€rvŒô~Òf“1OQ,%Ji¯¦z2µ¡Çé,ºÈæ£aTœehÓçeÌL—”ú_¦´Ú…\UZ4ý™‹7jÖ} hÍ”0Jú`=­"³v=»ÃŠ„Ói&·Ì¶¤Žq¨oIôž`KÈA´²œ.*¼"ŽÛÊK—˜q´Ç]5ô[x Öì„Õ®Un"}£æ¿Þ)t#’®|%z©,0êÌEÄ:ðrtdg2ò.£æV˜‚~že³ü÷¨ÌUn‡ÉýmÖEXÕ!'@ÿ‚€^t$Jœ5? DIŽÀü¼ÎŠ?Óùñ(-ÌñQP™äã ·ŽQ:̱|ð¤6ÐJ©@”‘Îj×á(‘9÷©胊 ª…Ÿ0 ,ÎÈ1ªÃÖI§ºY’Ï ÌK1sjˆ`%g ¿v¤Á?Fr*J®¬¥ë–ä#(XqpÁ§d1y«c'm¶¶®‘1/âK#8‚õ!5Á˜•P™ÔùHÞ®‰§£áé€Cp=ÔÕä™ÇÏ_5' ìÚ{ ªúb_ª¡gíã‡"Y³[/úååó×/@šÁÆÂsñ`«GŽ~æôcªü‘¬yÁÂ6xSÏöÇkum!jýÑÀW~8|ü4*£e–€|t’iªP9TÕwí‹A9tº|–Z¬sBil(ÅýX2E%u[!FnZéQ«½.H~jŸlŽŒƒïµ‰$çó5A, -e™ªœÇ9õñ[%Y ðù¸^×[…gùlkñä†nrUfÅ/¹ß)æÐ5ÈÝv7pAY~5)éý*wA·²¼GfUÙÍé–Ö)PÆñÔ¹¥ƒ)eBÎ"Â4¬¿ÓQV u1B¶¬˜ILŒþë`57÷\ˆ?&×Ê<pݘRT6ø>§ÿ˜2d‰¥gY6¤…YÌ1 ƒ‘ãÉ㣴:Av %sR„ö5• ̇§ªÓv`å2J@Q«Wðÿmÿe“<)[¦Nú[Õ¼»1˜ûR‚¿‚ÖÏö¿¼Þ”t}·´1 î ¥à3–[-±ã*:|P×wäUà<¡bÒ…íF‚¢=Nf1‡ÈŠãÎgÓÇÈNA¿G Õ!T”xR A«v‚bbvV<‚½ ¦r0TÃfœBÇØ–Tªò=Š¡4Êgw‘P(|2#vý§z1¤.Ê~™A ïKåGÞ÷ƒ`Ã|J9¼%‰âbvû ±Rέò©ái–jB® âßôCØ!ôŽzȹ­_ºC¨Îžl( €™EÞÄ´7–®°Žc_•{Ý †)Ð…]Y@K/½Šy(CPbÙ«Tžc]º”¬ÆÐ4'8£çý¿`—³ÌsyÓ«¬²EÇGXÙQÅûV-ùi‚ÂÐc·1Ô11æv^J:'É š'Žó|1pÔ~?͇JSy„|%!~‰‰pÌ„ž‚|Õ  )|)»Åã 8ä…¡´hú&Ú!å27,ƒβt£GÙb6| ]Í%ÖQ?íx4øþ£« réºeìŒ0 …\Én•”P:ì•#»]ÇóÓràçX{Züž{Boø÷m)ô_¯ .#ˈ ØEÅo súo ¯§“æmQžs›-P›wå;/uÙ¶#$EeT´ð$èŸÁfE:*F | …1-°|Ð<64‰O02ÎHŽ’/mx®²‡UßÔ’gt†Žˆ()1%x\³{9<ÂÓðaù¦cCÑ*{(EÑÙ‚Ò²bƒhCCÙ„ìyU ·tX,¸â…€¥|û „dzŒ€Ž¢_³ ´‚åÔ\&gÑ*`%ˆF)®w-Ë× ]Àš@Ö¼ª•iê¤-[U‡I2Eø„ÜÈLyÁÖ^›‡ \?80N&É)"-Qm¢¡ÃVG#¿UH=—‹;‘“4›HX8v4&]0§ð“¨‰WæmŔυrLS]˜`±M‘ÜÄÔ1Ñ={$ âÁ"L&¤åÓbᜂnlÒbÔÆã†&ÝÐܜۜuÛ)ý›•)UdóÜ0½4@É™GÓ,è”8T)ILµw-Z]J ©¸}Û-ÐU!€”µëvÛLiöÑnóH¡$(¼ÒÁ»ËèÉþ«Ç \Ð3aˆ+wgD åG{‚]€œÖ~ðDùhãp±d2ŒYi"«†ŸÛ‰°»,»Â} ÷­úS†^—fa©@åÛÚ~­UsDgˆyÏü[ÙñäN¸$$xÁM'йó5Dë:P÷]G½a¾±úB¶k)8kAÍÇÓf£ï7˜û€5ŠÄÓŽpJ—}Te‰ÐQãsÄ ¯ÿ}X}ÉñèºÔhWz톃ÈëgÙȬ­‚„5ý¤‰`’¶™Cݹ]üs ‘å·'¯Ž‹N·ÉÅ‹I\n‘’¬':Ýš°ß^z&|Á™é[ÏlÂQŸQ0l¼þw-Ö+•°5ÌCqÜDzVã*£!õtiL­ÏÞíF½ÂýwÉ L£arQf¥g¼Üüª†þ3½!+¼—Q7>É]½ž„HPÒ÷ÁSQ-èŠÑ;Íññ Y¹ðßáÓvä-Š8Žg§a¡éÄð±^×Lœ¶­6MôUìSý°è¸Q^Ýró vô¥˜Ò‘šW -Q"î Î…ÌÛܶV¸·{·AQ|Å,˜ŽA¥h †ŠÂÒD‹ô^'(¸tšc(J ðYžèU'äàð–‹tÂʺÈfóÅ™C¹}ý<»(´®L”I X¹Ô“ë4ûœbÅÓ䢉¿‘¢Ñ…ÝBÛtJ®] Us©Çø] ¾àèͼ¢ûÊë+è9ë*o<˜>2û‡"¨!¸7·iG—˜ÿ0³ªsgÄi–_vE=Ø0—­mT÷Š<ñ4]¿$ƒxÌWfo³2ÿg…òÌBC²[p—þÌŒËõ >šIŠúІ98T¹yC·*ÂîYJrjXTÔ‡ò®šÁ.r>* j¦H¥³i $ZbO©Þ>J¶F´ˆ’žQ´Ëâ;Í“Ó>*™šÿÛ|Ó]ÿáíwo¾‹Þ¶¾£ßooÀÄÛöJ*y×Ô[V98›—Zã»õ§¡&&-OèØPáÝ(@¹cVrÃÈ‘^ýØq¨;ZLG©9%7 ƒ~¿¼¶v`íÖ·×Lîýp¯¹Âì`ojñ™¬o€œåDx‚à%ùD_¾z…šªÚeQby7Ì9x%™¥Û0o`IO=¬GýÓpzn/#‹RÃ×~êâÔ*m 3”¢àÉsx’­V«2+‹G€=Z/áÛÛŒK2QI‚¾DÇéd>ûÚŠA%)*‰ƒNÉJ(ø tñõ2›S¼Î ˜½ý8š£^dÓ Øîeéã͈ÄÁr€cì @Íz P¾ˆ£S D2<IÍEÿ0sܲ€ÚŒ äºèòybDú9e§s‹Ø‘ÆTc0 ›j?‡Ç&š§I °"©ŽxLÏ̘v£ÉøÑÞtšÌLçòvô I› üŸWñ(6¬èIRÀ­äÁ†)ºb/™Ž ™¨îúV×,w#ílu×wø×Þúft–›_6Í¿»B#k¥f6 w4³“Ì}Œ{.Vl%CÄìaô^bd›ù,[_€©fvÿѺ h™‹l1˜™9Öd'y,=zýò©ÝTãx’NçÅÀš@¡5?Yn¯â@N[öÀtžë5í~Š¶Æ gd¥Gq©v%ÚÌž6rGŒ¯Ó=ÀéýMc« 6Õ9^ ~x„sÏÇê "‰,sÖ!suùUˆÅ¦y”]L üÒ®WNq"VÄfP§dìf:·wNŸ2 J ò{å]†‰N°O«ˆ;ø89‹ÏÓ,ñtp½|öÀ~­Î$Áo³üÔLÕÛƒ“Ⱦ¶Ú’<ÂqÔ#úq"ÕJ9|n Ëf‰Ecb5´n‰@Гx f"ÌQNh”TLíŘK.BxÀP´+Ÿ}YO“l}š`…垢7 ŸÉ¦ïghæxx¡úC¼<9™ªuŠõ è ¡?Gó. ph Cmë7V"×®$DjQ‚Y-Ře8OþŠDþV;£ +¾Ì²lDþJz‘êI'ƒêGGÀ ŒdÚv’ƒ’7T†xêÌìmÊ<©’‚`4À©©áfpÀXø{(x”x/œǧÈÁE½@«6 ’Î2=ƒ_“¸MÐ툱gz¤©éïøÆca=tÐ>ÎF™9VÝÓ¯Ùó¡@~‹ Æ¢?IOç ©Ðæ}ôIž3í±$åe(b}ð±™sö©TLMÊåƒB?+3J¢là¦löÑe ØîŒÅâbjNGs@•¥â#P'â¨2H[(Ô˜²£ùÔ1CôM.²¶çóNzOt ƒ¯ù•dä!1µ×‰,Àº?“ÜIôU¿yÝÉ@“ÜYrŸ þãࢥ¼Dª@ À¡mNŸøØ<æñéºÛúÐ,dB¦_öBR€™øÊ-CMŽ2º?I¿`;Qój†+6‚ÆÀ\´ÞÉíöŽDŒ3à¶d|9ƒ,dHÉsLdÀŸ§†$@–%(] Miuãx ç+m¡ßÍúNGÈb°e;*h¥Q™£`þäðeø œ,v€è`óWåŒwo\—×\äßl¹Àë¥I­¬ÞT6çAKx [ýÅ(9™ž7tá1 ¶ýqgÂ\2#—ç‰éÞ»*Ý ÊZ`gòÏ9øè9ؼêXmTx>!y¢'p¬ÐùbŽ#Ðà”ûG%CIðõü(áRpÉ’Vž¬Ó%ˆ)[‡%!§³óDïUr~G½¡]‰t û4llᑇ*¼ªd2tø„Ä?€ÐÀ£P-~XIÇ@ŒZt&i5«o„7s_>òes”—Ss¶¡0N"<éfÊ‚6%JE¤›UÂäò¹œ’zŒ¬c~f½Nô\"¾¼ÐXĦDæìÞìE˜wœ·ã€ÊØÆñ¯ÉØ«»~)ã´(ªª¸E9—P ,^Ñtž›±Uº.ðÔxµÚ>᤾IÝ_\ÖA ;n±‘ñA¯ãe’C‰Œ,[uƒRÇÇÎ-œ·˜óU9.»Û)×UΙ¿(/ÜÈ{gÁjCôþýo¬¾‚þÍÛÁ4÷Ö-äÎ3¯½+ì=ÁîþfÃöS2U‰M« M²™ylRƒLÓh›EñÕCö‚î„ ­éB¥ä9\ nÃkfËrÀøû5Íøx =e¥ ¬Á5Å)DptóÁVuù yìÛÌÝÇ« êâ@[±ÀêäŠèE¬µ5î§k~vîÞÅ»w{þ¿ðëÝí¿ôº÷îîÜÝîmnmþ¥»iÞvÿu?²Ý•~æÅ,Σè/ë0Auå–½ÿýÙø6º}0tɱaºÛçQ¯³mv»ßot{›æ×Þîfwws':ÍŽcÃÆ§ÑmØü·fyG>\ÇCJrïÁƇ¼ Êž × >Ú¾ÞßǘÑÊgÃ,4ùúÌHcø)ê&Öéʽ ;ÉÂïøn®>55íF½éûhh^™}øõãÇ¡ŠrJ8…¯ÇævNv£móe×P`ú¾¼aþûY¾ÿÑÈÔ12ðµÛX¼ÿ{ÝÍîÿ»=ØÿÛfÿ÷îîlþ¹ÿ?Çσ§gÓ[€óäq;éÈ ~°¼ ÷}ÔÛÙÝÜÚݾ§x•þz’b|cô´³`~&PØÀ´’žŸD›˜+™Ìí7÷E¡©ÃËyâjX-* Äù£¡w)ê @ñ#ôœn”ÜÕVsqWµ€sÖWìe³ W_«'¾-š lSX®T?9w}âyq/„ùVâ÷"P*PÆ^qLóä@:¿›ôñ,§°4°È:y"« ³¡.Ÿ3M¸\¯€£(¿TÆ>y$Ö|:‰r  ‹b!ßU?ˆ ‹yUÎF çkdz’NŸXµ./†¯‡æcåw9§níðCš\ÍZ»cèý’œ—‡ƒ|>>ŽŽ1Õ.çæét:FاG0D]Ëmöúçw&UWahš2ª…@fò2úz%×”…_×m•à5]Ol¼Sq–žÌl¥^ƒ^ŸpîFªv¾§U}÷¼öu}£åšdþk6Ÿ®ÌKhÎê°ÜTï¼oÔBp%J¥uÖÂÊ!!UvÈè…BE¬†í¶ Ë“’ãb ›ñpØÿ™fC¤eÄþMŒØüÍ೎áZ²à]#!ë ýhŸ|· °RŸÅ“I2zÓ5#ºÈ^¥£‹¼8ï›!ìhÇÆ£f_“),ULzè÷ýýûØ¡8¶“] ×aÀ § $=+h}Î3³]¦ÃâO–Øya•+ôS ¡~øÐOߎC[t Ì ´÷LÏ=zöÔªsL+4$}LPä{ÐÜÕ]€À•¨”\ÙRX#Q(¾¬û{WO“=;¯½H­ãÍ=ÆÎé³.Àûòìb¥³HWI§ŽùcÆj…±¸é³¶¥Ukцáè°Ýê–.É#Ô û¯{X÷I5ý’ã’·p'Z-´Ã¯€GÁ ¶(‘R4üDz· ±.ñc0=Hå¥Cç4wï&ÿIGáì¬Ù Q¹¡Î(äž‚¦A‡€ÅxëÓ²…ìbe6¡cjv¯hƒðÄx¼þ( zgæôÄߦÊhùN;¬ Ósòýy¸V«X :»kê¿/Š>üæ‚Þ1¦µG ½#ny%Ç©Þ×Ñ·Õ b>ËȵÕ\“T!‹EÎñ/°Žˆp0ƒ¢7Œr@µîÛhÄѼ d0Sõ“u5Ñ2#„%À.®IµJÝpkYÚÏákø½o;‹€Š$UM³i“êflE µ)ßPV×u|åF¼ z<ä² –—òÆŒ|zð·}‹yçNqçN7’çHõù{]›)bš''é{¸oÐþ$BD?–uÿül˜hW˜†º3ŧ«]™&³ÃŒµÝ}AóËäÚf®€WÔ¡¶Û&oKw¸¸è°·|Lj·-ˆ¼IÙϘÂA9z<’¸H!…°HáCÄ%ªÞºecA†É,NGˆ ìFÕH ¸lôîítïnÝ*ïÿq2™oÜÀºÒ?°Çïmo×îó£ÎÿìÿDÛ7ÜàÏÿðýœøO‡žÜD‹ùÿÝ­Þæ]šÿÍ»›½{¦\ïÞæöÝ?ùÿçøñí¿jâQìmßël’+ÈÝMpémíö¶wïvš÷Èù³äQ ^ xxˆ‡62õI|žž’‡Íû6aH81G£dr Á¥'X†¸²¹W¢*‚Uv¬žèDOØÍJ>2\yk*cØ|#,‚/³©g=¢»µIGÍÆ³ýÃ×ýg{ÿÕÇ_÷ží÷Ÿîþrôkÿõ¹nÞƒ{ö5p ÅÂd€ –†Ò!}øÄ¶‘ϱ @åH,#¥ž¶C.Ö+£°êÚç ŽèõR ül ËJ[ø5+¡çœä†gê¸HŽ)¶ ãöLµæöŽ8Äé ¾Ù6¢‰õm÷løÞñ(¼³ýûéR´Ø èéØöX\‡sÔóhAb—c™d¢z¾ÈÓ1x£âø9ô ÄÀMößRôm :"…µe#0~M°aKßEF°Œæ3´›CPÁRpõ!„ übÀÄ`ê$àZˆf8ŽÍîx怈IO]øÄkÅ:Ãcœi IÐÆ[˜‹H‡&J;Kâ!-ŸdÙŒBÐÐocª¼i¼F„Ê`Fr ãÎdž!e+`<‡ûºOlP )e‰•¨f¦ µ®=¢å£„è\ßÁ…Þ9T½øÜ« ã ;Ñ+òo'þ%Aæ)aÿP¢ ¥ŒF(Í6ÈQ‰Éc„…Æ2È|%é38ËR—\ŒŽid†Ía#vTˆzMSƒJÙ8®ù,±S<ÆPo\XC±öˆþÕ' °i­¥Cœ‘=Z0â›è_‚ò —mÏëËAx•¥¦Ã%ñ]#¿ñ‰â¼‰ÚÏo/ÇwÛA­Ûã¼F\·¢fmÔ‰>%CÔt;¬µàT VºÚ®ÀÖä`×e;…Cˆ)Çt©Ò>.’ZìOfr Ì$öU¶@Gª .O.ÀåIÂTp¥×Ûzm\c!‡‡½ne·Zþ‘f3ZX=²ø™|/†bÄ¿šÜ M±˜. Õtä±=”ðpå8äšE ôYuå’Ç"$‘´º†‘Ø Â¢jc© Æô¦1ÒP¡YÄÇWS‚áfè ùy’[E•·9€9W± Tˆ»If•r”5†sœ ÒÈû×›¶´”í*4ûò Æu‹hôJÊÜ4¬|ÿ)‰£ÔöGÓKŸ«Ë8Ðc{]ÿ$ ̲ ú&Ú²ôÀaƒ¡NzÅCílÝܬ˜9yúÓÞã_°å X1Jþ³"wºÁޝÀ˜©ú“0&ª™“€ÐßàtJºAÿn.ÔŸž¥c7þcˆÆ« Èö„pÛ—éÀàí$ *Y¥–|DFB26R§ÂÜêëê3lK^\w92á?€z`‹^H¾—PàÒ;€$±ÏÄ»ÿ ¤»ÒÞ\F<¬©À»t¥ úåèä.‘D¯Ð•Ñ¿1R´LðÊȯêÀ bSÖ`a‡‰F!âØÚÔ†uqüK.Á¤Xj¶Øi=ÚC»âëXXc¥õ ]ª ØhÚ¸æÈö6˜Ùp¹i7Qê» G÷Øñ(F{¯¢éÜW±2Rfî_vá’ þ@xĸ/ßÑÑw–Í\æ=Ù€k­R¿Þ4òl~ÚPÃå/Rj•¿fç{üÛÅ՘˵Rj_ºˆ`ÅÖ¼Dî¸Ý*Ô*ûÔ‚Aéš‚Á (ÈÆ™'ÞM6g~¦eSP‰â¶=ó ,û¦ø {!Í´8~`Ta]@ TFU‘§;2Z¬ç™3‡£Ù®0õÅ´ª jB顿œjÁãÎê>A–ƒï`–E#ÊëƒNF'âŽYzÁÜ‹ªûòZ5ÿP}’´wˆ‘íh>üdy@nz&¤¢µ,ç((è;¤J„–vº°††„3–2.©€™Ô¿ƒk‚Á@|™QtÉÌ ,Pœ²Gé8µX~îkÖïV»ÊßË  É+;‡_ô±àËšCµ>Œ–þêœvòY_/6õ5îp¢.D„4SŒK2ª»¨7JµKb£ùN ÿQ Ô‹ ·éÞUµÆn—Ï6Ø<ãŽî{aNÈÁÃÇ¡9ÍBÍ}oÓÎKævŸ…´™ÕÜ3TÜç¿Ðäš: ™…ömYŽ^¹Ï˜À¨¿Qýf†"Q·4UDs9¤‡ùrË„Pfó@¾!^xвɣ@m,y=É& Ôî!Sžòô ¹ 1œŒbîq Sâ€Z‘ ‚m3÷þê¡"ƒø…ÎR³o –ùÑC—ÂZaH0‰ XŒv¹¡1äi›ÏN¾/·Çr¤çhsVm?`9ÐGiÞǪ£5 k›d)¦zn”ÒÐÚè¨ðºÆHúI(p[½«ž¡=ßïPÍzòÊ–éDyW„WW5ÔÙ_V³ë™Móã‰å£Í©šê8»M÷a|[Ñw¬‰‘÷Ó ÛBa”Jð×oxk{w·>&£h5€Þ†7@.QaÛ Îlsü[F&¾§o-£Å¿„c”%cùÛv"W¸¯¢+Bø N¯ªuó8]##ÊÚMÂ,úaE »ï¤†Cß Ùñ=R‡NdN^<’°¦7 gËedÎXŽ¹Ê±[–€ìQB@ 'ᣄùÁEk®ßkââõ_]¯UÞ`ýf£ëQ£Ÿèal˜&ŸY¸óF¤j ÛÞm†V€Á!8Y$/!w•Är§(Ù™;tÉH'ö¾)P „Èh‚€Iƒ½Ç`÷zúüñßú‡Ïû÷ÿº¯®,9úÔ;þõ<ÁÊͱŒbŽ¡­UúÐÄÓRs!ëø ‡°á7öÀoRQ.)=‚Vt¨KxK¬Œ_~ã²Ý.Éqë埭MË‚åßÃK¥Çý™û|£ 8( pO\H4% Ç.$ç«–G8…Ã×¹ƒú1°›‹kMD©…@ ‰ }\Aí(+/Ö0ÔÆåi^Ó_à¸ù3«ÓúÇ”ª™Ï8òT2Á·!†:ÊI+Ø7Êm—Ù/²Þrë =h ~ƧIÓ¦q¾ÀÀìÈ\2‹\jox¨0B?H|ߨé‹üVÊþëV[)ù/25¼«ŠÓ«(ñø.‡PY:á+zS«×¼­®ÂY½3,«Q½·fOê“ÕÝ-WÜ…Wzu™×ŒÒùûÓË×\ÙŸ†¦”ž!~^Ôè 7SP"qU-f.Àÿ8y‰ÊÀ޾âD ¤Î$n-—ìÖ´Žt×ËEØG ¬Ây& /3´_àÞa*Ïòtvéî‘t0BãzIËWÕ2rÃÇ.–’Î*´‚¢ç/Ÿì¿Œ~ú‡(¼{kÊ—J¶Á‡Ž²8'Î)<=µ½Ín…3&nše<§¯$žô©étE’TÉPæváaðÊrûu•£ZĶz×¼22¼“Ãê= ¶ K¿Ñwb–QLjMaŒûþêÂfÐ8í6Šyú†®œF ¤*2|O6k=BSîû©‘þ×_ÛìŸZ¼—‡ê˜ÂGf+)çÙ#U )L„›pæ9Ri|ޝ*ÄN‰ÄáÒ 5ŠÖòT-oÕŒôȼ—Ê#¬Sb”FZ/nCÈžì¿8ú5ZzæM_âÁ«?=ðfë-µ¸%-Ïû”^ð<¡¦¥Ñ]œÆ¥b¥SNÉ,…VF§ÉhXo•ó#x‰Uõ|sþ0Ÿ¦ÁDþ­ª8<<Óø*‡ÂؽGFälV*lø|Xª—èa6 ˆaF *[ÉêUÌù ¤s—Dùãì}dzwiç˜Ç+»àn $z‰;®dE¢Æ×Ö>Ý ò%3gËýÚñŽˆˆ¬GdË•b_[ôËw¾·µ&qø"*â)ª-ö`å-ïoTõ¨>™ëIàí·¶©úÌxPYŽ­ÃòYǹã4_‘˜3—瘮N=æÝôÍ÷Hé‘ñ°ƒ¹vFÌÒì¸;Gyžü™’õ r„—抅S\UN›ãf@Yþü+€w³pJ;¿—j‚Üb£ú|õ@IYã à˜Í—9¼ÏÜÕI¢ ïó¿­hÊý]÷N–R«›j¿vIÖ•ÆÈ£Z™&èzbUL¡ÍW¹ÒU;0KÞÏp.Ü„ÎØ¥÷”ˆ³å®{­êâ¾×?ûQÝ·ÈÏ(,×Ü(3DäÙóÈ‹¾{š@Èñ(Ë?‚N6‡ßEZœI|Ö)s„eãÇzHyòÏyšWùOˆÕ›cÙÕ„†)ù‘eµ8 Îê”L†1€í23å5'YÉ$PÖʉQOt*,‡Y“Žò Í1Ûz[(?>a¬Æ™«Ò†ªÞ¿¨ìv Ö& a1÷'Q¡nÙ½ y×øâ%'1¯¶Œ­ºzÙ*s¼< 9hæWÖW¸Sh ,0Ø“ô=XEgÑWæ[ü¬½ÊÆ:Æg9‚ÉEàÅ…](ýÉ`#~)±qò~€@®vgxŒŠJ³Í9'/+0µZW=ˆèë<¥³ˆÏ J7e¦Õ:ó8Q£Ï/Ã܇ȅˀËÔ,ƒßè­·F³˜Âº+°"éÂÂ𜡳0§¸ð…¶Ä\Ÿ§‰»’VÊY(Aõþûc/ bx•„†eÓŽGc-f?LåòŠpB#Œ›!cÔΉâ^}åÛ»N÷©çªÉâç7Jþ¤ ü¬©ž¾¡ã µm2¥Š»xl¨,û™ÙgtʦaGË¿bÞôd™ØT ÝpH¶gž7NA®'e_³‹­[ò­á6A’\'Ó;;OÀç… »ætvT‡L€Ë»Ë†FU¨÷ ±ÉÓÆ¨ºOÖ‘9;̈9ÿ9ƒÜÙ|Ol)nžDûgÙ{éðù‘dKpèšÂæú'f'5ÍÝ›8uÌ ¸†ŽO-gBýpK7eÕ&ÄKj\¡|Û§5Oïfá§—ë1ñë7·so«µç÷§]à“ÿÇÓåü?÷Sÿôñ¸Ÿò³ ÿo»»íãÂÿÌÿõY~î+à§…ØŸÛ!ìO¸U•p?? úéO4ÐÏý³hÿ#FÒ ´±dÿßݼ‡øo[Ý{;[ÿ«wïîÝ{îÿÏñÀ㉧Ì_ÍNáßz†!D€ý¶³»ÌþU£{æúÂ. ö¥8÷2:õ¢=†MØ\°_ Ìý2&K$™AÖŠ)HÐqÖáƒÃWû/AB;z^rCo*C 4mT ý}ïéëýWF°»ƒj4û_ÄcWž@Þl8J‚E×ñIÕ߈‹‘?1 Ãy‘,2T¸1Ÿó-œîñ— u0ƒÒóbŽNÎŒ tI%QÁdqƦ†«÷­ Ø9-À™™¥t€03*dzÅC#8nŸ§¤ÍÓ$›\" }aDÖÏCjß°L´õ0Á„à/|`<áÁ ȃ§`,W8Aˆ½S@rl¢ûïàA`EœD™¨½‡9©æ.O8]vl}_}, ¾5‹P½2v¨  óç¡–ÅñèUJŠ•—i†#D/­QúåNcD²I«l0sxµ°‚2Dys€&j¨x ÌEGàÔnJç™KñÔŸÖU [óÉBö¢^ ƒy‰ ˆª Æ °và´n™K»ÅUû$ïøöŠñ5‹–@%h³¬ëiüšÁoì)­X4ÑfÓuôIö•MŒö#¨âv$»ä)ÐðÓ¨ 2b"}ëuÙ¸¢Mùà,εi…ð7ñõÖ¦zÜyW¬Q8TÔ€‰]]¿(Ñ@ò·är7z=I;eƒõIg@fd•À c ùN’ãh‘y¡Û˜ÓÒ9Þuǽ¹½}ãGS9K+Ô3`pÂ`á CÃ)×T?(°c4ê:îÙk;¨žVú"1¾²ßÍ´U"¯qÉI¬«R2Ð~Á-ø¥e§ÿ~êå£üÑm,–ÿw6ïÉýßá?ï˜kÀŸòÿgø Èÿvâñ°¹c®w¯Ž­` Ï ¦ŽÝÀYU¾Ÿ Òs$Èiè àË‚˜ÆÁtÞ‰ÇV4×\hqD-¦g“Œ+…w—Ô´í}›½ÃÃúWö*[¦‚%Ï(€}ü˜Xj~`ˆxè[Wä²S¦tú ñ.ix9¥(öƒb2úâß¶_{âÑÏàzz€´±ø¦iÎ7ŠÚmÌ ;Ç+œlø(›H±3ÏIŽ2r1¡é§t°¾a¦êÉ# ÅhpJNqñRóß ýËp>NGfµØ})  kH?qšì€b_Z1’ñ¸3ËÌ$ŸúÏh}Yêê‘Å‚€g°2½BøÀ+·þÅ+LOüÒæ˜‡½¼›ãQç[DÕÛs<Šžîÿ|ý¯ç‡ü†Ì«èù!ö@M* kckɨSvÅ·vçL{àÚŽ¦›üïÿ{—ÿÝæwøß{üï÷üïèUºØBRÙ´S+1›¯i³î±£"{[Æ}ÃH·}WÒF7ºG‰ôDñú-é qq{:SŒãžOü¸k‰§?&LŸçV£ò'RÝÂXö+«é_ wÒˆnãâ‚é  ^Ü*XUÁ&vë+縺¯Ó ɺ+‘qÖñ9úZìó -¨Œ³‚;C9\g+ø©%3µ LÍ¢o}¿äåWª˜¼Ñàv샊_&3¹Øk;T|ÅøYŸ …Ãgk§€B€à:°³f]¤´×Ÿ™µq¦FÉ—OnZ?"Š•E=аâ>,؂󊊋«Dµ>ˆº.S'Õ­akb_Ù_â”+ÐX¹É„bÙ_Y°ŽÅq¾G¶?Öù›¨ð×ݺ2Œmîb!ü¶ÙˆúFÖ'&§ØÈ]é öÏÀaÞŠ:Ö¡Rõ¿.`Ó=ÖôÌ~~ugʪËW¥>•<)Ëm[oÅ›iwµ.i¾ÎÕg¡³O?O¸KÊ!š½Gʃø¢÷fîjÜ‚jFeA}ŒI\CÕË :`qcÓ«ºk^•V┦÷a×÷Ôm.6±SŽáj?Œ­\#= ’ÆìUc›ÔË7 ‹8‚Ð;ü«Õ®Cç.ó6HôLŸ¨ÞaJg:,Vü¥8ú†QÈ3z¨£5¤‹meuþýoiž¢DkÆËï Nù]ãðøï« P> „£@ˆ ƒç^†"Ñ¡¡á0˜:Zêb4½á8¼A ýyµÁð7n,ÁMâ­^Ãô­VÔÂlv#noµ•¿1ß„å®Å'úåœ_ƒ¾P/Œø8¿ÚE²Ñ+”è8–=¯AÆ’h„Ò¥®Êbý.)¢SØfÁc† e:×[ðrÍ L Ä`Dˆõ„9&IL~lãNôоô"‚Ò ús —¤(ÀmF®Ÿ@ë¤WpÞ¡²H·ìæ¹Ô­.ÐýabŽ~ÉÄcu2)¹{RWÍc Å1¾; Èå"H‡¤ˆ˜Ô‡Â˜ó ÉI˜|‡ZK''˜Æd&¾¿mª ¯à®ü@ aôg32ýØŸ$ûAeCçñØp83LªŠêíDG€Á6Èú·±.jPÔåß ÌÓ˜s‰Kª SLC †=Þî¿xþê¨%“‚r@)Ô%î§^$¤>RPUÄ’Ú„Œß÷z›;_CJtSëúÎÖææ½.\¨OÅp”N9E98FÚ¸(ðæ‡ð¸ûä›OLºL£ê¨}?NòÓ¤Iõ³7*}þš’LB‚,OOÓI<"RYMHâÀµBµÌëûD\ÝæØ0Ë@t4‰ˆAïèß.j.}¡¤‚9Ë1b%ù];ñs•6®ˆŠªƒ‘G¦r‰iƒë5ÞCdY§“rtO…éò·ÐSüUsZäŒÜ‘7ôZ‹ðíSyë 6%ˆ[^†,FÁº¸¼À›@&‹þZj®b,¨£öW1æÊËËÞv®¹ˆ †Î\Çp$ƒÓTI²°-Џ_Cý~uª´Ñ—“¯5§ЯJùÃV¨š]b—¡´3 «ˆšï†íï,XP.T4 I&¦[=ê†ÕÀix‡²·ýº3„Lr°ÉÐm'Ãù0]ªrÙ[Kø¸8¿x÷BÇÙ^‡}¬RòÑn]¾Á 5HjïBÍ ½>• ¶ÊîF@UÕZr X­qänð h‰Í˜m̳8 §¢óî*,¦cv˜ùÁ$‹Nh_n÷{çnþö^ºàKa¡K>­ÄêzîD=¬-¦rªoK›OÞà7ƪ-dXWSì?ò޵ ÷v_kA¸Åtì[—©Ä¬ŠšzP ®\UزÃnþ®|+zm.j²Ñ¨Ü mªÙò`X!‰p]ë˜cWçwG0Ûcºð–\oxµÙ(Ú~÷+_WûzþZ”K¿ç‚÷ÕÀ#oÕ¡øxðQN/Zgì׳Ÿ±9ëél‚ g©àŽâg 肺ì ¯^Û Ø)+½yŠÆ60‚“³€ÕsJpqEÚ¥U#²í”7{]vóÕ1“k×ì”f«×]W—SmÕ“BT:õ%J:z¦D6Úz“µ‚óʥ˔€"-o6õöG«V³À_éǨ™òÊu˜¼î4ÆØý]ÈH 銉-ÀoþZåûµ!JXÞJ.ó$¯Qd°:é˜kSý6“!JJ‡§3g¨ KBw[Õ„‘ÂVüûÌì=t)k®Ãš°¹+ÊFY2`¢D¤L´rA C6,lX®¡Š¼ ¼ ‚Ø Ad…kã*0_±ºX›—Bg<|H‰w@‰§ðØ4¤¼8Ä8oDšt!DkB ýËɨŽi|4òM)ô²Œ€ãØlõŸÇ®õ2ò‚ë‡ Ð‡a(/H«@š7 ÀàË{“KÖ²°î—½+ÌoçiÌQú6Ù7èwLÏ̹ùŽ×Ü]c­SÞ0•›ÈjÝìi°Ô$Ї¾µÂ]aÌ,±²WAšOÖ½‡­öÐê¯Ñ¢±&©üÑil«å…Æ‹ª>1<{Lq½ÕÚ¿Öî>Ñ ÔêàÃ+§„LXk _ŠƒñªXŒD€ÉéU ÐÀ”´¦Z‘"~Khl€Üó †â€üX@ôï@Nf"´3*üúåSWˆõme(½s’gH°t§‡”ÕžrT”¨ó„þòÒ*½A¥-kp[l+«û­:œ Çû}ä:lšÕžˆUžVÐAAÛœ…;(»ÕBaIâÃETµŠK»®²6WX—ÈV^’þŠ…Ð;ë,ãÎ^êþÇ"ʬ†'s%4™OŠ%ãz\¤!¦­{³@|‚Ž™»Y&ÌUÉ¢Ô1Ø 8* Ó+â¨îZïy3r#îÒb^BpÂê\ê/ÀPÎûìôÆV½R!¤x~, bÉ¡DD§\ª%`د"8B«ÎRéR0‹Zñ2Tƒ6†´äp³V+)8Îg+ Ôé–ퟲGp¨'s„¼€½ª’¬‚Þ! •·’´ÖÑJ´O€›ô¨I×ÂLZ 1Iã%¹.K pÓ0PR-LÒr¤åI‹’þ‡À#])´™Ã®OµnO ŽBþP+£ý1°4‰*®©!Ñ-äŠÚ½Tvø;Ġņðo8;—S”'è9¨ö²·PcÒ?çzëÝ ªû"#vÎÇæ*Ç÷1•HS½hV¯iN?Qy…¶@õµðZ¸r¢yõDæ’j„"ù ¾/0º:`œà9PÁÂ"&¢òÑÞ‰î8ìb8Ž³Ù±VŒ¼£z¦.¾n¢:(¸:è/±”¤@ÁæuI}QüŠ…ÙY?-úr9 ‘[]HÁ.+yñ¯þ<~CR7^õmõ"B³ç20‚зN‰YßLàRjÉ«4æß±½ <áµç}Í´(7]šŸÀ'¾†g«’m@*ÿ÷¿#šJÜšjÏØ1Ó>4K÷}Ô¬¹foÝ¿ª•hŽŽ$Å kñ®1ë\áF¢ï‡ ˜ëƒ9cÖìŠþë²ÝepÅ_Ëó`Wˆ»fÎ Úñh:^—éz«×ÒœK3,³eÓ\Rw,pÓ[WöEÔ<úEž $ý廳Ã2˜>2KúA(ûÓÑ<‡KºýħÌ9’MNýçÔ½û`ƒ¸dŒb`΄žºd˜sâò(„~“ŠXÔ,å õµ\(OËÛ«€ëÀ_Ñ•Qk9U7Ì—×SÛõù=Â!?ؘ>rÊæ*ñpOZpƒxÂûn>f8u%¼+x*‡f¸X7öÌÀáÆŒÙcà—‹˜lËCIâÁ‹0~\i(бe¨m;Þ¶9½*9ô¼~96OWZÎ`T·/—³x–ýmzÿj̧buÖ è¯‚kXB'±Ê&;½>{P)sE"¨/Wâ!~FuåÌɄįÞkÐØÑÁñå˜é®ŒUã <÷_Öcyx`”"pZÊ÷6긔ozé’¾uHœÛÖ¬ôoᛜ ä°d Bõ¿œWY‘WåšçÒŠx0B¾¬¾˜ª5ñ a-‰¼¼x´&®Ì|¸ )± åd•³3ɹ©¼¬Íÿ8ɳ1—#K§YBäDK'†:GûyÔÞ_Råu¶ÞýàÀ9ÁqeâkZ§â¶áRvCØ’‹úZƒ£êû€ƒy© £Y0Jâ¼è—ð&øðö ÐT„_ýi¦âošêél+" #)¶GrÕÄ 3Žà)å 3ÿ@mÚDëäUg;úmïèñ¯OžÿÒ?|~tðx¿2µ‘ “QÐ:œ¾?HYiüªåZ²+ß‚7 8§yrÚÇ(ªfcãÍÿ×ÿ»»þÃúÛ §ÒôΘ+‚+ÓŽ´-”wYô¥M¾¢:Bß@o09‚à›jϢŜU:î‹Õ õAÑš?D›ÄàxÑÊkæ½A|±œä`YåˆíwEgÍ'@YÁ¢ü®KØÅd8d“|C§î¢VÍ€ŠâóÌ1ðh½˜‚ /i£t z¾PS£+[ØIÇ1Ó+ñÛÐ2ü÷¿Y#µ<»l¨Ñ¥çF@ÿOùcoÕ=`Ó_Jä†h?¬`ô ±†UõèW“·CüAœ£ ÷—¯Ì½Y‘•ƒÈ[‘•·¬$KjɳªuôKj{,¸]/«^I³ú³Æ†WÌùaóë½µ6‹vÐÊ©’«‰£k„DŒ_%iZV¦“óÈd¿ò«O -¼©z³ÕªEC¶×××/žìAÈïæ«ý£ÈÂa'ü#HÂeRàÂNÕJO×þÃs =©]£ÜÖ•Ëßf‡·8Ýu50nå­µpEÙгÚ;þ¢MX«®}\V×2¬~½ÆÑÊ]˜´Ð€´µ.ÐÞ°¹§ÞÚ»E‡”¶ $!:,ЌŪ |öX9CIË.%Îá8ÏÞRÈ  Db=·0K7¬êÕôÀ82ç8ze=oaè?JV§?v£¤éu³a£Yžïfµt(aßÿjMEWJÛ»‚¶®*ðÔzŠp¿Vñ )SoeŸ˜ööç)txÈò_€,‹¯}ŠØ}é+×µän÷¹\*|Ìm„l˜ž¤ÌBÓé4Ru†Êv¸f˜Üµ7 ñ­ì>!ÿ0d“èûMòæ'Ý=ÔÉÉ¥MÆhb5eÅLâýk5ýXÉK‚]«ßŽ4bç*[²:‡WÛ”U³¦Û£·'ÉEŸ ׫0WÙràˆÄSéÏÄ/ËæúEúzMÿ#>Û-H™ÏËéÝ‚ -*;o”É,ÏÙÔU¤YÅ×Hd‰l²nz»~Zˆ¨åsÏwVA*î>)ËÅ~^ 9Ìü µá¤T3{FҔЬ $[Œ \(ÑÉbGo/Þ„ ™K"*¤äÅß?DxFæz͈Œ'ºÏìƒ0ï \"Îã<ýt°YןJ>§V0šC{APÀc#Å*l R4ѵn[è¸p:}úK‚’‡¡ÑñKºô‹lž’À響Ô\z¨Þx…ÝÊ(³Jb¤ÊÌûrÍÉ…_[G’RÛ |b¸dpFK¨'xp ©~…6›Ç=‚ÀîÒßÕÎúsi“R]wŠr-= k¤×±mè‰X»™‰¨´¥½îZ#2,¼%+äûTSXf'úG6Ç;ÖÀívD{´Ì©(§1+Éٚηá¿i!â%;ËȤ²„ð/vóãL|R=œ„B¹ûJ|â‚âýiïñßìë…µî(%­Áª /@|C(9Ñm32οr‘ÎóUdz¢]/Ï]ÑÐ;47ß¡ñtžI\Ð%å=Üç'®Ì)dÄ™¢\A^ºTŸDâpQ®ý•“—?"äñ#Êô;:—ú7¦ˆ0Âíc À}CÐéó×ð.vÕCdѱ!—4Éh‰nƲóùêÛ%þ«ŸO×gÙ:FA§.‹{›€Ê&Ù 5ñˆ] c?™cto¾uPøa·y,æíyRˆ<)YRÏÁ õ$1‚Ý¢¿ÓÉŒì¸# K4Ìs»”àö×Å€@F„¶t¨)³aßûÞ­N«ï0ôBëæë/ Vnü¹‚þç¬ ÔèÄÏZ Áú5E ;Á,@RÓçœR窙1´Z{ô«[T8#jP¸(—t×,WZþàyñ¥Å¢ÿ1?µòÿz>uEqm,‘ÿ»[ÝMÿôß½»µ³òÿÖf÷Oùÿsül|ë$™rÊû Rÿ½^ocó^ÔÛÜíþ°»¹£¤~”á;øYÉAâ9eñl7ÊAð…­<%/©u|°uõ³QrbmÝYLÕ³>‚Ä ÿZéãîý?YÅGþÔßÿofïÃÏòý¿eöÿÎæÎÖÝ­Í-¸ÿïloÞýsÿ޽ÿË{¿»{ÿÞîö=ÿÆ¿hïÃμ™jŸ½„r‘¼†³³ÝhsóN€%˜ý¯ ¯Ê ¼O¾4 ÿ£ê÷ÿçÊÿnÎü{wñüßÜܾÛÛÜÆüïÝ?õŸå' ÿóó¿o;9`;ê¡ö¯woyê÷ÈÓ!Öˆ¥î¨ Ò¾ßk &ç¢z ‰¼OGYQ€uÅÜQùÒ5KrÓ`6ÊN/ƒúBsMlZO@px~üêÕ-/“Œá{MåG‡ØLíî9pq±£n:mþAóYÕýül“ïcxšeÓtPppªyeokø®«?0“gâW€,«³Ãm›ÉAo0 vøRàJ”# ª<›ÜÚ›†uá£NOÁË‚¯“óì]âw¸­)¥ ¾ZkKH8?mг6æ¾&$~¨Z»òª\ ͵Cö³÷æÿïïH•;L~‡ÜuGÁß—G£œw=Ÿk¯Uì”`Ì+ŠkÂFü…”³0.Òì`ïÌ^ÿç<)hIÄ…Tð±ˆÞMßÄE‘ RTÄ ‘ëïÏâ£ùÙΉ.4 ê=¯2GZI»¡Ê(¿+²|æ¿ èK$› 4 c†¥>Aײ¿Š¿PHQí´!‹¦¤¥Hý!¼CýmUÚÕ´µ(U¹YanŸ¸5‡ŒÇ.Ý“Ì-ä§ÉŸš9˜ÊkŠ@È+‹‹hC‘^#Îæä*0ï(õ§y—¤£&—܈îVøþ0=§ÌM×0àrƒ<×éNÔ5Ïç#Ò‰ÝNÍ÷]o6ìd9²¶¤åº%à(…ãadyWÐ D u[ªiZÿݱ#5‡uûÐqØAnfj4y°aFY3ÔFGꂺ¹•o£-ÌU^þ9K¹é¨"°¶ÛéwßY„ˆšà~ŽÚr_Zöú#üÔËÿ°±n¦e÷ÿ»Ûw•ÿÇ&Üÿwîmý)ÿŽŸûJð‡G™ÿ.ßÿw6ºßGÝíÝíîîö]s䤆‘ÐÏW ¶Þòc³Äö†²ÿcv?mÿŸé$·Ñc°P¬³kf<º)E©ž¿ï¿|uðüðÖJ<Œv:ïoݺ8c"_FÎìQÍ ÅRŸ@Œ6cùa½»¹¾¹­ª_Ûéôºk·¦yö;8¥™l纅1â³EÁµÞæÖöö;›½ï×þßäåý?ŸBPÙÍz€]Íÿ öÿöÝÞ½?ý¿>ÇOÍüÓ?7t,ãÿÛ•ù7«åOþÿY~˜ÿ«ù®=î…N€×øaé Ø£È 0²#äÕN³È´p©ÇWì…ÿç™ð…~ïÿ›ñ]¼ÿ·ïnmáþßÚÜÙ陽ÿ—îf×pƒ?÷ÿçøñõ¿Þ´##èýp¯³Iìà‡no£·õ¶w·º»›[ •À?›×wõ¶vçcœl~ˆ *85ùRРCuøc\ò¾¦*–:W1ócÇÊÎŽ ƒÌE–˜âãt”Î.+!/Ðxšå³˜]‰Æ í0¾f6Ï'ðÝÅYf#7‹3G¿Èòw‰™‹ z~M'Ù©©²¼ð¾}—$SîA"}0 xBù’LiF8(+y½ÆÁ£[Ṏj‚N£+1tC\¨Pr­ñB€Ç‰ÍJ…‘û$Ø`-ð-D7î?”èJíÃ1ó®–é» —”<`]8¼ÍãÌÑ#˜»ÿFhêxÑŽØ|a¥cph£å™ŽE¾*í>Þ;‹z¶öèµ^—e-^Û«úh1󿆓¢£´›ø»ÚEãÆãVL±ö¨f-¡óax=™e´R͈úWÚüb^;¥p$ ç„¥ÌëÞÍâw‰·ÚyźNaÙµGá%ŒÝ(å±ÔÃÀ …Œ.L}Xæú=ÄbSå¢v¢èm«Œ¶ºÔ/š4æ­ æwÈiyæµ/>—RtQîàÖc<ä*Žó„_?}*©Û^µáÌA^+× Ð+T;I.>ºÊÖ Nç0‡ug½«Ò¶¡7 ˜#K¼±Jã`s¨kßI¾LÖúø I \–.°©Bð™­qtïOX!KoV˜ÃcÏ-Ž[’E‚øæ›È%” Ì­æç‚¿×áX[ðvƒ¨4ñŠsÀh&>Àzw­yWõ¢ö~sŠo×IçØÜ ]-i©ÞZå&²eJ ?Å›Ð^©Dpx1äi¬Ú,ˆž¢*ú“ÙB×mã-L˜Qª\ì¸LƒI:\S…™ç¼ðÕ— ¬Ê9àÞå³t0B@1œ ÍOU>]çDNxdéršH©õ‘l+,ò`\;YÄ'âïê‡bd¸Sx…"o× Ï©v!“àS:s«]T±O Ž‹0#½«ä÷xÌRÐYvÁ'#‹d4$3É…}A$U ’È+¹€lì•aY¢,Œ!ba×ðÌräÅ1ÔõðùËg{OûGûÏ*aY|ªf…â‡B˧L_šßP1-‘u{ƒfÒ•Ç¥ð_–òð' ¹½$ ÐkYÆN|Bº†`®×è4=O&$ Ãtòñ^¡2žf§˜f©Ù8(4ÄÜN^É6#爤qî7 pÁPÄCPètJ·\ñ¢¿Nã<G·¥Ý(Ú'ì_v Š—%zs©‰õ€F‘Fîðp.2ï’Ëb—>1³ÊA' É3hÐlf¡a‘@àòcîKP‡•àu¤î®. wõ•éj[‡Ïú˜ÂÆÖ)Hå†SÌÌ_ΈbTždzfÙÌÍœø™G!·ø¶QðÍÄÖ˜'E6šãÑta ЕëÒ¦´âîºì§ ÛÒ‰ FŽ £hâT €‹}^ÁÓà/™A™Á tH=‘õ! €à·†"}5ƒ*?Xd +sÅUuß§§ÑïÓäÔlª“h $z?ƒ ŸèýÈ\#†æÙÔl©Ù„Cs¯¿SFàq2Æ=¢ 2Ež«æ|¯»^ת=„*Ö>×@Bôôp4ü·mŸØj`-q¼·¼è¿“<ã4véd˜©yÂwô6ݨÕ%àl–£Y®Ì@©s©gv×ÕQM-±ET«Y‰-³_zÝÍ»üÏ}Õ¨,ͦþdVÛ%Èbn¶“.Ðö^c@Uiw}í8d±/EhG„Çàm¯¦þÆ`»cÇà ´½×§ñ!¸íÀŸÈ®Z3”Ǫ¼hZúÈÕ"âé¸gJkÍç}›=L“ûV‰¥â{5”[eYS‘Ã>~ßWåÚQwåKög˜]L¾³Fõ áœÓþihЏ*ᤢ¶,ò¾z4ӓηíhÞ™XLS<'>D'^Žêχhé!N:'À¬ÌWð/ឪ¾ì©×{IÒ§tÒW@N¡ìò«ù#ñ-±¥‘ð¢ÒÂ"øFWÔ໫r4«.1\IÈ]?2‚ãnÔ„Sªþ;NÇI»Zöi29…8‡RiXgRºÞ5“û±ÞÓ×@ Y\'–›Š ‹)Ÿ8CZ ©\ Ëw¹Äk¶³Nýõ âi‘ó.®÷žsÉ2Ò&]8ˆ; yL@=:L„ jkXè¥eñì{s³OFÅ Ç6&š2¸1¨˜rsp®Á é׉—2¸`:Œæ cïå«WÑI’ ‹Ž?Þižœ¤ï‰ÚÚë^õií‘Gþb~â¾ /yýZAWmu•ôêVÈoy<5ÃCE“L°è† ”?Ð +>‹Ï:¿­Î‚Õc¸U^H•Á¥CÙ:¸úà¼1<BcOX}V(2NÊÊ4Ï#†Å7Kž¸Š.òt†A[Ç œR÷Ì_’q—h¡opeÙÊzpPZ©Øß¼›èGŒ•çl(@rz®HÞLHãòo© ËØÄwêFˆX¨x­¿_þþke¥4ß› Ag'fùAKGœÏ6 ,ºö5î—z%ÕH&ï7øeÍŶ¡ç¥J ø:ž¦uêyý ŽÌjÙÔšÚKÎmÙ`Ûä‘SçÎf‡Û`± ×Y¢çífªÍ Û­ƒj`JÓòrÔÅЯûºç¨¤ÙU½ühë>sGˆú.ÒxYe'Äè8²EÉìÑ$>¿Ô_³ÜnÊ&<. 틹è¦cDÛ(3æKä…Çl8‚P÷ßç)Ș•‡ÃÕF†SB•óÑ«g¦t’Ò‡‰OÁ¯WƒvT#I%J@Øîú¯Õük&SÞñÕÙçôd»ê¥Çñ–ÄiQ“Fé·J˲¾œi^Zã*$ŠWIÝÇfÉ¿7 2XK_^/­®HâÜloÒ–Ýéj¶…¹Û²JÉ{ócÉ7$°(Wt‰vÑéÇëhn$̹àïÛPO|¹ ­„ÓϪÎ7ÒVŽkäMI×S·2½-Ë´{uýJ!g³‘Â1i¦M N«ƒQ†¼„b ‡wœ’²,ÅYzbÐ= ë¢á'¼“ß%%Þ°7*5è¦S*‘œ° µ1„ ¥ˆC}~¹~óéÕÞÎÒRÕz«ÂöRXR§—J¶nÕýµ@„ðÈçT"â/A"9ýstçpŠÜHMy6Ÿwäê€ÆÇý*Ï´K 4æ ¢SœU¸+5+^N—S䰎¡ø·Ãë_ÖT“”ó-µ¾K›8ƒ¨àðažŒ³sm¹ RiÉ”š}u'y?sjZ­»ý1ôp7¬Ðåq¿qgÕ¨‰U·©G-›÷VS³´ºü\ÞÞ…ZK)×å¬Ã™†ã&¨M]°ru:¬:žµªkÉúÞ€§Ô@.Ì5åû”˜›}6̧)߀Š£j,ñ\bÒ!Ù\àš“š³Ï¢sI:$7ø£êƒácdÕ¦”ê†ÜÀå5÷\Kª'~c#ÅÍE!È´##A©@Øi‚ÔÐáJƒ*9p/zÊèþ{ƒ ¤ôl°ôÕëgM°xò‚»ž•TrRU’ ‰÷NûPEá|ñyªóÞZ|€VÕâæ@{œMÎäE¬ÑH¹l?c³õSŠ_YÄx¤®—È\°ªŽMÀ…'¬è*RÐdÑÉ)ËÄd°ÑJ²g"P·Á¯zC«gÈ ×Œ³~S )Ü M'íŒJ;pÑJ'óDN»‰ðÜä¼^òÆ ¹ÄÎ^;I’ahYSÿ³Ñ°ë6¿3pV¹ŸëW–K×ñþsÿ1ÀË¡Ûæ;­Ëø{ÇÓÿ£´»w†-ñç@ë§Ý£Ø2ÔRU°Ï¸]™:Z’¤æ,D±^ñÕÑÞÑëWýû/Ÿíîyކ┤•t² j¢Q=R5ß° R ³Ù†]Í3,¤"†±€¬]•Až«­uMâ-Þ-Ö9•¤Î€·ð¦'¯ŽÉm¨ÄæÞQhÏGsÎù$ “mwþ‡ŽèM}D_}!I_”Îd…cþƒb´ÀTæd¡äªËæ¼²lÎ+Ë& ¡¯qóB·’rŠ<¸°yq56OrÌ! gà¥Ù©ž§Ëtd%¯ñø^hµ¿fx¿æ+H‰÷ÖóGª_ÿï’Ë oOíýÞ¼ô©•ïíþgkбa.Ö:™÷¦#€JÕ¥ZQgíÁ³ÕøÃ…˜A—-zÕDÆpµGS1&3®:mø’½×‹ÕÔ Pí8~¯4R›Û;í€ ß#Dkñ¸ÈõN ÈuxíD]­$yÖ gã8{¿ä´¸=Ķ\ÚZ8­§Ò¯.nD9FU›á—4¤Ñ,ƧaUt}'JÒc¸²–äÓöjû+i…`g]³SÖ¶ŠÑk¶Ÿ®ÐBem¯Þ.òe- ¯UùpI½âиZªtˬ¿ I«úÛžb×|Á^7Tb_8hk±'œ½Njo8ë^|·«]ä|öW6|ÖÔ}0&Ä^s×Åù) [ñ$º£BÀœzZv"çšp§ävŒn ²§MÌÍqf<úb¤º;²Ö:„NLÇf ôOÅ™p4£èw£;î¥×Ór0IÈnÂv«T˜~Àu»å9–çË‹çÝ ÜäyYÌiæõ„#¯Sjkõ%¸_… ? ä^J¸Úø½Ð.Tâi¡j_+]lšg§¹¸ñI¸Çqœ#N:%¯—þ³¯ÈEœÎ:ý­—0Q@ÕZv¶è¤1zHV0ÅíÊk5õsA?€ÎuŒ?Zd÷Ú°õ§ÑhSRu4/“õç)È-~îö&=ùØGÅN¤ ëÑ1ÌãSá]ë¾ý¾‘Ó6¦wNƒ ~å’ÌJù&Å¥XÒs‚a‘QÕE¼)ÐÔdD/Ö‘' jŽ¡oè)7̳iGm…’°PñÒÁšµÈ-ý•ظ<»P¤•mfž¢%‰id`Æßôš¡ë ŸÜt…<1ø ß 9®ð ó÷6¥5С ÙšycæžÈÊñùñé)ÂxÏh7¡«Êk¯åaaw‚CX’¦ ´QÅuò[vuË,,¤÷Iú~ƒÜ?¯¿¥ «nªÝ|ã›NSû ´©@²8«}Þ-±t‘kêÕ|ß®båʵ•+Wº½¼#ŠèùË'滟þaž‰º¿(k  ?WTû-SüàA°|9ƺÀV Ãú_ñyü ÷îúq Š&R0*þ^Rj!xé`XEI¥šÃDŸ‚˜ccj¬½ägøkïÅA„ÕÚš¦n®üÐl¨ÿíþ‹ç¯ŽÞ ø |·½k‰EÍ%굋G¨-àùcjÕæ¦ï'yžå„€ÔŸeï’ {§82 –hGS’Ô,>ÓI‡ŒkFÞÃàCSÆ[Ø’K=K… –ÙiÎû,ƒrZP’ Þ|³ f“}à”J‘b¤T¹´•¼OgM'tÜ, ÝÁ¯qŠìôÿ Ј^L'eÅúh6žZÓ6»(®‹¹¼6°RÏ•ç#¬àŠ¡X7pU»Ð|;]Õ;Œ^ÀÎ^úu’ÓFÔ„*¸oKˆ:î¡eJ+t4¾e ŽõD9,³üO a¥/Ê  +}ijÎ)>}¢B`Þ t—ˆƒ´™¯ÀX‚læþU¬/‹#óÊjŠÃó$­7e¥Ñ[‰£ZÏçÕS§y ¢$ ÛZikùõÔª9¨H«ß\Iî­kPIä×¥¥TQ:…Ñ5`⑉Kü´c÷Úw%H)Þ)j¼uÆã1‡oáÚ•w¨y¯<Æy 8JB©x‡A’„ÞÇÛ¨mËjh/>ÔÌžØðLwË–3÷´¤À¤9Ÿe¯ršE ’ˆþø_L† Ï:D+!ÊXúþ+!I`qDHERíïE6i¶:ÇÆ-06üosbÝbÏ È퀷^î´Åàæ:Lµø±™=#DÑi«ÈLÇp±0>ôáãÏe8•ÿÌ »úÏbüï›É¹ÿ»·sï^ò?Þíݽwožov·{æþ,?Aüo?ä=ÿþÁ¿»æ×ÝÍMÈÿVw¾WÍÒ a/4F´…j–;}õ~åcZðŒf-x¥¯ ŸRaÌž·ËªÑmxè3_MóäÔ”4×Ïfcãÿ¾é®ÿðö»÷ôÏíF»î ¬iBI1åkRPI!ŽAþ‹ Ó¨OÞOAë ¾EôÛÁ“£_ßÿºð˯GQ3éœv¢»Ý÷w¿ï¶ý*A7º.·“ÌÁfewirÒ²ûýªþä¯ÊÂÓßÕÅTËk*ƒU±€ž¼$ Ñi\@ê;C dóÔ%鶉ӯ+:‹™‚_Vá`ëÛn8ö¾êA•ßÖõ È™{~e¥C³¶ª06ð-« ³7 Î~^S¯4*¹æüÂéÓ+8æµ°DNKêGýõ¥¶ƒÊÓ2ÔÃgULç u#W Õïñµj Q=Ÿ¤Þ¶<ò5{]×XniÉuè*—04™k‘X¾ÂzÖgY6z—ÎÖ!‹ÀÚ#ª›Ÿa.HÔ41GÞh¾Ý¤Ë&.F?æ=A‹cTaö¯é%¸B_NÒ™âÄFká[¼¢ ë\Ôøç·ïA½;r–})äŒDørõÅæÁ5.Xj„ ^gàãÂÄm H7W\VàHù¾ŠÒÖå†3ðéñ_ÿ@—¾ëËf%‘4ìev–P" Dƒ'¸®†Âà\NÄ ½þ®}ÂÑ÷gV•«œÕP¶žý‡÷ãæöö"‚qWšä‹„‚U¨^íT…1ÖðÅE³lqXÛC ÷&ƒxq·T¤#žYé?EEA›ÍîÿíØúŒ«XOÏÌ%¸Ä/´QÏ®àúéjS[Q}ôÄ–…7+´­2©¥î|ª)µ‰"\\š›ZÄ?ãäb˜opeН,r,€piݾ°Bò—ñ˜(¯ÂCBRÂ?šd #žË¦b) wèU}Ê©‘²‰»šÑÁ»‡—ˆ ïì%y±x >³´–_©AôW¼c8œ¸ò•ÃÕ±#³ŒéÞùNÍáÁ„Ž¿UZÞ³•‘¾Xvò]Aª¨ö­½àTõל“5z?xB¢žâ%3åÍ—Wœª€æç£¦êÙ 'æf+¨F¨=\CÁÛu3¸xþdìùC°ËþU—CY‹÷Q‹áhÉ){•…PQ’ÕÇŸz\é4^qz>¨Sùk1yêsi±q”@öy%’+Eþkìb$ÛÿùÒû‘6æÅöÿîÝ­{›˜ÿ»»sogkkìÿ[Ý{Úÿ?ÇOÐþÏÓŽÖÿÎfgÓ¦ÿîî@úï»;»[߇<jÀN¹¾:°SûE%‡¥‚îöœ©Ž¥EDYc¬ n6d†úl-§l§Ü¦ºŒ€ÉvL-§y pªÀ/ /55Qú7ëb¦ƒñá.¼Ê¨29¸Æ¹vŽŒ~’!ž ¦G䮟q÷Û€†ƒIºÍ‹á%}cݺ‡ÇSÐG‡è\ØŠ)Ô/̹0Ž]±û%Õq ýç“%3  È0–v}³¸+¶h 3K;ŸÔôBޒšþª •¬f¯|épJ0k>TÆDM&rC$9»-‡q¬¡:w¦Ü~n$·ÓIEvÆw ¹Mæ£QèÜkáU×{^ê‹ÜÈùeô·är·‡k@|EÇaÛ³gò‡v|©? LÅÄ›ÈШÎÿp£ªÎ ñüºC,·P?Ôs€‹½èÌð5å cm4 V…-rºÏåãAÇç/:gVl©èrá;KÔÍJßÅY6 A<‡ãáxtQÆù`²w£Ë¤höZÚšÝVˆ =yeB|êÁRgÆq8bð„›ÆˆØ'ÄÙ!=øÂeCve”¢†šò–°Z›ßQ@‘K¦“aò>„S[bÀú£ oÃ?KY×HÌg TzãOYþ?eƒw7Ûù÷¶·ëäøù»·µÕÛ¹gž÷¶77ïþ%Ú¾Ùn„þ‡ËÿáùÇÿv~/n¦%þßÝÞÖ6øoõz÷îÝëšuÒÛÙÙÙþóþ÷9~äæ'3Žw>¼ïÝÛèmnôÌ}¯»»µ³»½ºï! fLËõ ÿà›Ý« =ONù‰'tŒœ§±d× Gp¤'æv—‚G*»O-D€ó1‹5?x)ÖfHÙtF*¦¦¹Äða8¨ÒY@aFŒg®Ó# !´ì‚î&tgìH±¢ƒÃÂVFrqibÖ…÷Œ;oD0õÃè6GÐMÔ ›š-ÀÕpöµQ܇ë×/ɬBMüLr¤ß²P ±¹ C0)%cB«u Aíâ„Û2F ãÉÀ[k†>ͳY"H'›¼2Ÿê±rU/3‹CŠJÊ}¨ñ%UØä+/ˆt7•H¤½h`6šY »dÝšx|SôæÀÔã)¸>]Bß„>üä¨DÉ·†¿Å9¦iw=Œš%Ìo/Ö•_{Ôˆ¾ójæ™RU?‹ów 4‘.Þ\¡~ÀÙ¿(ñWaÇ€º[ÊE„Y¾†œõ Sÿ$ãG˜°“Ê>Ø0GÇóÙŒ”ÀƒQ êÞζÉ9«|z]d¥y =Ï ÄÁ9Ši3ŸMž˜rz®ú!>}NhÐqVI‰ŒxM÷ÖÿÆ("-³”’sCZCÆNZ4jy]Ð`”ë l zû‘=®P3¨†»ÖgÐUtÁi]­\ðÔôc:ŠIs£ùæÿFo¿{cþ×ú–;GZÒÉ&¼¤Gßniõöf#ÐÖÏ@jÚòÄÎh¯sâ -”®–nuÕZµ•ëËFך*ªþ7Ý·ËH£[… ÃM¢bK‘†¦ß£Iã;5O^à·þŽÂVC÷š ÿ{³K¼Qµ:ñpXWR5å3B ñxWhH• 6¤GtšB*h]owdê˜B33Ÿ£þÁ¹xíížÔ¤¼ýññ:£®'ÖYMr’u •f…Ün"Oïïsï“sXm½“ê7²³¡1U5u¹RGï ÞðT9‡éÂÞÞE¤x»q%¶¼¼óŽ0Ë­ yïMÓüÏCoý9åÐØA–C4‹Ð:L¹ˆD$£þÌæid9‡J[xwèu™Éµ©uDu¬”Ưù$¬'0ìQr.4GCˆòpdÉhºç¬Ä5Í2A¬£>’vÑÈÈäñª|OæpË©Bk½àªÁ«rêUèèMàª/ fæÔ^yëH”9mò¹—¯¥Ž¬"ûÌíÊij ú[8è:œ&i6/^ß>ûéUç‹X͸˜FGð¤¹tðc#w°RW8ЃûÞŒÂ,*U;D›=ÇÛϲazréK‰ì€€ øY®0óan-*~(¨W•J‘q.´È³÷R32¢«a[ó\ˆñAlزn}Vfnl$¡a©tU >®×4'Žÿ]g{»¬¹e¨ÆâšuÁ Û Fñ±lU‘‘¸ Än¸Ø +1ܤÐDˆ¥ÙGE.‚ô}UÑÀÏŒ÷"G’d2˜çˆ¦Í!ú$bÎ Icú.¹<ÎâÍ\8‹˜µh>íx̬©Ös2;ˆe+ß6 4Æ• 0B„#6…`ˆeÆæÊ!š äU uÅ(-gGù#G`ö›Ü®íõ&æôSò*š)­Õ \ ÕÂä‡ý÷2…IIáðú™fÓù, ½†ù%ö¯Q’  ÈÖ&ó€™êή~Õ®rñj7ÕJbŒ\üÌÿiåÆŸ?KéÿÀxzm,ñÿèn÷zJÿ»ù—nïžù¿?õŸãç¾VÿÁ„£ð.)»;Ýï£îöîv€CL¹LÀ Ý%‚ïnù¸òÍU"ÏF$2›ƒ=aßÇØeÆ϶<›³ü=ŽÍyÈ L;·ÌñöN?¨È|±n‘o't>=Œþ¾ÿòÕÁóÃ[(ñ0Ú鼿uë~t ý(¯XšN–ŸFT3gÔ]P(‚cËzws}s[U¿¶Óéu×n™s/kTËÚ-jÍ‚Á”Ük½Í­íív6{߯ýÇš“ïÿ›ðþZªÿߺ×Óþ_waÿðçþÿ?¾ÿ—7ïÈ ¾¯qÿÚ¹‚ûW×6VãôÃjóU~È!®ŽFh†„q¡oôh²Ç4vüb©ëÏñR“"ÉÓx´º¡~‘ÇÈëIúÏ9«ˆ£ƒ'!ÏÚ¦å ²s÷¦]AP+N=£;ÝÅY:8sê}smL ÛÖyÿÉûV „d€°5üv–5 z‡T’ø)¹êÑr rlm ´H:k!¿É0q]*mm^‡JÝ…><¿Op D¸\§ È'ú…æÜeÂùãL9:paÇ¢9û•§ÜÆÅÓéè24,…èöGq‚Ai&J&óQ;Q³g¸?lG](N ü«õŸáÛCÃbˆv^p¬½ €Þü×ÛØZ‘y å5GÑ¡1ÃøCMÊÏ£ø4)éd˜@¹ ©s)<¡$Dëc‹ì茎 Ø9z-·ÐYþŸ U1פ`‚…cÓNjDãI;Ú4¥~ÅßëJ¦K“ПåÙl¶ôú½`ÿ=ôÄCHV‡3çíÖErŒxÒ³<>9I°„ÎÌ6áM/ãä]OqWò0D7[lÒÀZ3Ëõô~ûÀ+ë¼Ñi4¢çˆw0‰Ë#>£¥ÆEG—PÞ½IkTl"3¤vµ9£ÑB$Åš–P,W×ÁÓųýµöZ\#ºÜ'èq#GIŠ«)¦t¡¦0äPAº1Ê$$oÃʆæ‰dßfF‰[sÃ_“S3(¤Ë7ÜgçÊi^±o¾K‡YF¨cÀbFŠÎsq–°AÎøe;úf4»?É&É7§³ûTTY®¸ &Çwˆ$ËûNa]G JwB+É¥ ¼ñ}Ù»æÁl„b#üŸ”·' û rabˆ¹ÞÛžÂçfëíF±„ÓAŸÙnúœ%íè®~{©}¿Kjn€Ò1¶¢WIýôôùã¿õï=þu¿ÿ-,}#Mf”`gU¤|3Õл8NGèabu/Wõ>VNÀs‘M‰Ðul6ö|}I0nÛ[Q[ÿR»õžÅ%tW# §m+µu;n¯êg\º¿öËåu·Ød†”ˆQᣠ${S0—\ÌJá2ϸälª¿À~ÞûbàZH7·‚¯€|ËiÓ5ñ_4°¼ª\ä>ÓMnAÿyabDþ ‹„Æ’¾x•À@ð¦Í!çpÅ>£¼I«ôCÇô¯ÒíÅ[·´ÊJ³æ |Å éÓÿ\´Ë@¹¼²’h zHÖÇñP\ònXt³“'«Ð.²ãÀ\A³á2És¡¬¤Póñ¥;ËŽÓÓî˜Bâ'ÄG1¢Þæ÷7.ÀüÄÒˆ}ê9lWÛ»Žr˜=÷c…ýʪ Žã|þg¤é>uâñ—’² dõŸ± 9F~=zöT­ o{†áòÒß­U÷ÒÖEÙ£OëZå9ƒ”FT¤?ŸXŽfƒ‚Ùáì%)ŽÐ[‚•US7Hbt–R‰€,ÏÀ]˜„ Ó…4 3æ í(÷s/ÍUYØ>r9RPVA6/Ä‹®à+^äÑ¡Ç ÆN9ÂF;2ãÇ$Ã@@Z¡dds=–äêF]@Óõôÿ ì?ë3°Î&»uœœMG}µ6–ØwzÛÿqwk»»}oâÿ·¶îþ‰ÿÿY~öŸóŽ&¡-—`'Âd»›AsÐ_1jrYPÒâq¡–/õÍHUŸMNÒÓynkÙ;7·ÜÖ‚RìÂóõè6Y—Ø'l7Ú›G‚Ã_œàÁêB[­Ù6,—®³1c:v¼ áÆ`v¨_! èï¤:evš–‰DB®G¥ìÚ¥” ô‡H1Q3íâ <œ}å>vœ`.\ÒU ‘öÁoØïþ›ÛÔÅ·N½WÇCŒ'ž9WWUì¸.«XæÊC¶rxÛG ïF/9(ÈS°‰¸÷1µÄßÿ¦Û~¨ ö}Ž ´açÆ€«‹&¤D3ButCs5ÐEoQ ¬§‡Xÿs™”>zšû7'XGnœ™7PõxŸÚuÞPP{Oç§´àÿÕËò'?CîUxýÛ"»Bx篅¹í›u >\ýižðYK‡(Ìðn%䘖û 3f b™[?>ºE\Ź%ã Ïc:˜œ¤Õü½h6Ì…w°å(PGR-ù唘귦ºúÓñpp6|‘jpmO ¤6ZF^¹K©„»QJúÉViÐ@‚R¢ÏpØG)¡#m¶£Ã×OŸ¶½üäËZ ¥-E…”¢ls sC³‘®QÍk"evðàÝå:³µGæ‹3˜ŽGØ»³üË‹æñ#œcÎØ4k’$mýøèÁ†y]_’výJE%r¥(CG«Žß5e¬À¨ëHŒ5µW=¹ï*1U˜7*¦ñäáÚæZ¹ºçÓ„6dQ®Ðü†„‚'L¼3Ôù5ÖÃYŒ»¶Az|¥µº«;›Ë,r1^pº×\ÃÖ4¡†n”^a{¶ü5v¯}»½]óò C=cz mï6ôÒ)õtݺ;/è±-¤ßr¼ðÔ‚~{^¬0„Š÷*Žè£ÈñbûJ‹ã0“3Ô÷ô–¥_ÔÑ'¸*Ç+,RFÁz€s f9XæÈ'¬Y~wÀ>cÖ )qPà ŽãòJóÉš]ô)ï÷Ù©>ߨþE©+8”µPÍêd/¯¬!Ø}ίü•w¶¾ZÆXj+öOýºšËL¦¶:_XyxJX¸ -úî;Íò¤¼üJÌ©òÂTI|íÝnÝòú¤D]üâK_vþü©ü,òÿ¼™ìËîÿ[÷îîÜÿÏÞæÝ»½­»›€ÿ×û3ÿßçù ùúéÿzw;›mºó÷z›w£îÎn·»ÛÝô½K?ÞÍ¡ ì—d&…¯ËŸ7¼5Ôg?¡Œ˜8uÃÞ +~¤þMä6i¢MB=Ù9£Û¤úïc ·=8‰&F,zjÿÚe¡WéèW°‚1Ø»p @/©›0}àØø'ˆ%ܹÝÄ)Ý«T®•Ó8Å“aÃæsý9™êj³\Ô“Ð £¾ˆ¦»g77‡²,G¦V.2ÈÆoëc†ªë^úu×AÈÝ%5òÀ4üå@™±k?÷NålO)åH9MíåS§{¬´œe"æ»ä²žq¸–>~õÊ¿`Š«Ý0MyßüŒš~{¥ûY[¤PMVÓ[i÷!oR‹P9s×(»òì5塠βpbkÓÍ []€ ^îÿrðü°øüpM%Lf\|¼¬.LxE%„OºÞ@*‡ð¤Þb¬…&´”ô‚tîË„$²¡?ØŠòß¹ë“e/N*ŠLÝgçL=v‹{«X»Ý’_=Œ*§ú}ïkµ{+þX-µkó>ûæXÍ/›k¯_<Ù;Ú·~0Ñ«ý#ŽÓ0•Þ1rG9Т1w Ä °BÍaôÛ¯û/÷ÅpFE¢½Ã'‘ÕöˆZð`­]éz»ÊઠæêÛ¹Û®c•G}ŠgMåËR,$À0+Nd@7/žãPÔ ²e(yÁɧb`„§¼ÀàzåþšŒÀŸÔ.D´‰™kØœœ?yðâ†WCó•Ý) kÛi› §æo+K}=á°›ð‡`Ã-íÿªÓ¼Ájî 0f˜Òt ZçÂÉž ïnQÈ Ó¾ï`›q°ï<ñ\¥^¸íDfd4ý“Q:mÒ¯àxÓ\,H ÿ’jÞT¶ì2–3¥m›bÂŒÉešáh'©%° EW»¯n«ºÝŽÝŸ÷y˜\¸ÀÇOeQB³xoµò&ËÓDëvÖ[»èX–-2€Õñ¤“óì9'e}2‘ÁëÒ^ ܪe®ådIókäÇw8‚ó²\_]R·ß¡@x^È˸ #‡Ìj–-G¼Í©Â—ŽC>ZÂùt†ßиޖs¯€ …Í j­qÄŒuiÍ¥,¤§0b]•eÅ-ÿìÅ“!iÕM“ SÞsÜE3`!\/zöF‚lô1‡iV„{È¡d »VÍøËk‹GX…­„€ž%PmB&yö§µ~ÞpÃÀHû²kn“¥užçñˆÃuÏ€‹¤3¿¦_‰µjª¯Ã1±"Ò5Ô±ASý¤Á®Ö)Ò²”Á&)‡Ûþà•æs„zPбœ#ÉL»+.@ûe†óPŒR`aíH}˜sŽçÒ.Z^yRP÷ÊQ 95õiËQ+×=s¡µ‹3ðO¥ÄZ ˆí&wƉì¡þ¿AæOÖ™.ŠÐHà ¤M§4øöCôüå“ý—ÑOÿÀ7¬[¯§ÓU{îõØõVõšµwYQoˆýÀÚ¸AöèY5‰k¥‹¢pKj8Ð+ M÷Yé.U¼hW„FˆgÝìî2Âàj9÷ÄF„ýj-L;y™Í2ÞCÛêì”´’”·ãâ3PNs8[ohê_hd÷™zŽä̾ôWN"Œ¬vˆ**ŸÆ„Â1.õ•›xsäªK™zÑÀO¦(YnjÅ;Êæ S@üî=4tþÌjˆ%’\æ1²Í­/1bò%ÉZ  |´ 0t¯ê \¬B24,ÎÈTûÈq Ð¦Ø (–ÈH‘œ¹#í)`ãÛ„Ôäñ>‚Äz°¸‡#Nu¢} uâÈ|PÝ1kâT ô§ÔØÐñݺ|M±R4Z³+²IŒF¿ÓNtç$7â´…ÐøTÒQò”ä@9øÍÌ€_»{·ñ-¾ÅjèéüýQ£åü5é& !wJד ÄP¾Y„ÒÑøëì¤økÔ4eÖÇD¼7C…€H3e­ŽCòôæ¨óœýL› f+`悳¬4‘'Ñ6œÌ.@©xgz6íD‡¦×ˆg¦Åd0G5a:Øm¨?BØs™xì,—ɧDªŽÔ¦F¦ºšýø¨¡•ùר”<èZAuÑAPìÂÛh‡©Œ¯ë÷¸þBéJw2` [+7s³'âºa½(÷¿¶‡Ü˜.Yº¨«jŸÂÒ²ÐвXyeçÖJp+†l$ Xð«#Ãßòµ …ìFÒZUûôøùëãæ·-‘{At÷8E`å;Cvùò+²n¸Qg4XØ)… LåÌý7Éó,çˆOdö/À©”Çè A[”´+4ûH%v¾Óðn˧g™ õëøðTúX4Ýõ}¡ÑH "d+"1±Û ½"­ß-V½o„iìííh–§ãº%"çumUöVW@ôFuï•Yiá‚‘àKÏ'fyz~ÌmìFzd5OlAÁØæ:zòõ E¡éЭr7°ƒÃWû/¢ƒÃ£çå5ñÚæ…þ¶¢¿ï=}½ÿ*jÂ"¡uÿmÁ)7ù “޵’bkYÍNᩈ×d ~\R­5±Î› ’ ¹m°(ÚSM΂„§¸íªÒ}e(¹/l$dãØµšYåEÇjá¡9Ä–9†l:¬xÒ²áƒ&lñ,"vÐE1|(éÆV<“>ñé²ÒyR>/>Éi¡'}Iq¢§t…I\z˜Ôq"KâÚH—vDè nû»­ß6çE«žb×°ì®}Í0´)­eÍô{³>e¬é§Ã&â´ ±¤ä·—2rõ4G%)êÁSOüÁ´COÖù¦Ý%üÒJ[ËØ€æÍej@|7,°ò ¡²â±>·ÕOu™Óð=„™Ü ‰kƒûGW”•mv¬9|NÐ\eߥ9¿ä)èT²8žeÇ=`fÜ‹]Vn]ã|‘Ó¥Özެ>s˜5]ûÄ!~dveŸüÑ*îìé0²éCnC¤øCõÍ)ú ™‰R Ð’CiÈå³ä©š½W~ÎgÄ•ªÁn¸)AÇ$³V°N.É9ÿrOfúãWŠI4œýØÒt—ƒÞ}Ð9:_žX@0$Å“A2Â%áfðÉ5§jõc£áKÅå»Ü$ê¥0œ w_$eWåk¶‚¯.b«––ì2œ ·×8ïS'8WK„šÍy#{Sœ(-ˆSû #‚7âÍ&Ñm÷_X8 _­ç§s$±hÐo ¥° ½•qì"¼.Ã7n µžm·®¨“c+.ù2/ŽQ_ym*¿OÛ…á °±ÙMt£‹ÂãEŽÁõ'§ÚÆFô«*Fè“%¥ê’!ï9XjHVÔ<9Iòd"ùµÔad³æm )ò2ËÒÜK4<øSº¾Ž$råóbl&bˆ¡4k´ðDE­³ VIÉaàè5‘\–ìâ^ V<&MéNp–\ÕAWBÛÎ-vœ`%8Öä§')æÄ±/D£,ÃÔ`·QÏOÿõ;þ°ùÃM‹ø¸è½»»w»»Ýïká—̨!ž$“lf¿w©^À¡S‚W ƒÒÄÃ]äpSêd&T3Å™4A×Üm×{ ãrÓ->~7AÆÌÏãÉ|d˜ÃìR!´ËÍ’¼° ö ` #»NÍ¡žä‹„‘ZxwJ´{Œ) –A6†?È3‡üÚ‹ÄÇä§ï1ÇVÒ̦âàŒUz'îÈž ŒN#ý¿ØÙùüé~ôïÊã{¿€ñm¸•7MAuÓl”€ä±ÅZ›tx14…+@›“#Ìâ÷Ù$_ºìÖ×é`¶:`,8%!óæ~’¬›5€ÑJÒz4F‰&(Åh&¼{qòd\„€)¼.¡žÒ±’j—r«g£O./ZøÞyÑ ¬cHÅ™F8|ËUÌÈ’n©Ð?»3µ»1dÐÁµtø 0¿¬ô@§HÄf•%k¨ w wVpß8KÎ4ÉñÒÛrx¡N <5¾…õaHˆ$³´)@Ô¸f‘Ìàždˆ‰F3¤2­ºÏ8î.Ç8¸£ÜCì’@0g™!“™ISrtb2 e> ×èDª+±&äuiM¢ó4¹âJ"ŸD/%Rèçi3G$„ã9þÊ€OœÄ_%1¦p )¼hQ"Y}˜_å¦íá[|éB©ÜŠhm”œ˜…d˜÷qœ¯µ£µºzÀ=ƒ_ ¥vŽ£µ“ÌðfùKd@§Ss:ˆ|>®ö$‡Ñ°Sëƒ8:Ë““‡k%¶µöHôu> óÁFüHÔ–xìæñéºivÔA@*Ãx!Üõ¤tL}BZòAgQ‡EšœUë€q¼”…²pwÑP(Ój¡"ÔLøýÒ:èè…°72gÈüôLÇvÏA'ëø=óYI†øÜbñ`×~Gv%ˆÔÃh§QvšN(NëôÈ޶EEñ„`C•¬DÑcý'EÍÇbÎÖÎŽHT°óÓÌÂo~P"sJ#2ÁiÿNÐð©OrLÄ a·B1ŸNm ;¬¤ØŸ»µ“N U×ÉK`íþÅ® °fô´é’åÉ§Ò 2#+Ïào˜O/ËßQº¯™L%À0Œä÷pï6W7=z0J¹N#›¥ ü=&‰hlæÚn_Ç:£˜ƒøýȶVMÑElˆ¬VØ4+Јò*Å µ¬ç8Ž‹¼Ö±¯ÐŸ`gmGKŠvì·½Ç ¯vÛåàÁryx'Y¹–|Èw%7©¼³úþ¦ÚÁvw2í ‰Š±q%-ì Ù£áE[ȉh ä縯âá(Ã=àeoµNC`E*"Eò’W¾D |‚VŒÖkÛ”%w0Z³}>A³Èiyt.ƒ×g?‹¤°Ÿ…µ#?ì—òˆ;„‡,wö »Ú±'¸Øù*«äÙ¥„Ò:Á#våΙÙCÃËI<¶ÝщOà¶à¸ºããm©ä”ËVƃ Ã2³¦Ÿ%]ÊR׿@Pœ`øFäaBrš®Ò¹¼öè':ر³e¦Ê¦xtž˜Í¦»¤[ëdùé†T^Ò³5ª¼U|Øi÷+‚•>\­dµ*\_†²ž°ñ,>U§2öÜ Í_$kñ±Ú”NÔü…šãÌ‚ŒÒžtPÙY6ÊÇ„¤Q€æYf&^Î1s(ž²tZÑ«/|¸E/õ¹L17Dý‚¶!t 4gàÆkˆ:KGè̃C·äU˜W,la^$Ýß ä&4Qk¾M­f7A"ßáÜÐîñ‹×†kaRKPÍBð±Íä °!÷E:„›‹Ï}1Ò2źÃæ›NGžä4_pv¢½áïóÂ% †_’ÖH!÷HÇX¤kÖ~Tò©É_3ÿÓZ9Îq€*³ù°ˆk>öæÙn4Z´üL %+d5qμ^²žtV¸C‰³êL‚áᄲá“&×™ïš_¹~{‚†ÐýϬlÏXQÈÖ°à†²a …Hs>ŒUìúß92ÒÀ„¿ênWܘ£ÃäBï`'U* àÖªÉÎI؈-³,/°o”žÀòQW<í±]£n`¨Ùº_i/{VçH×(^T6ô2˜…ÊÃéB•u(Ø®ˆuÓîlóèáï'«\J HõZ£x¡WUB4d ¹b€#ä²8è¥=ÜF5=¡Wäš²o« ÈçB YÉ#|¡ÜÌ/.àâk2ß|I‚P Jü?B´2n‡ A>œ~‚ò ÇÕÌúËGJsxypŠ«—˜õÅ‹†âêH†È¼‹èöÞsCÖ3÷Ùþáëþ“ýŸ÷^?=ê?}þxïiÿhïÕ߸˜Ô]±¿WãûU7þW|¿Â)‹ G˜³ìj4îÿ^|™ýÑ›1?ýiïñßnbB°¨ <öÓÏ-| @Ý+³¦–F_ýcR«ÇZ!¹b*:9Çì?,‰@X@Ÿ=‘d>Å"ÒO7J  ŸY…D¢Šx%,ú«F*-amàSè¹ÊZñÀΉ‡½ÍA8ˆâÕ@÷·."¾v  WÌÒŽzüБâÇ:öí† í³ô@}†Ë#XìU¤Zþšë+ñ«`t•Ê'Á¡ÓlxQþNzÆÉ©„ÒÀÓ¨Ôh4=Øa¸½‰ÚŠ/Æ¢7PJà Ы×û¦^'Ü:&°ø /Ô‹{ƒ(Jšô÷×31oòI4«¹[ =©‘·Èa£%Æ}ɘA&)O±·nqQI„?qz€pô Ö|;›‚Še ÄÙ¶à—ìÒ]2èeSßœ‡XEwÁ÷Ç7õ€Wdž¥^lŒE¼¢<Òrïh+—c[©n½¡×™5ê¾<†÷íGàQ Hôg}&VYöŸ‡ò}Z–?UÂD"zºCÞ#¾Ôu‚­2?<=ÚÙÿùùËg{GÂ4ZžÒ„Cð4)Bác.ÀN÷jàÌá²e0èÊšêнg¨˜b¾Ìo•zÃÅ4Æ Ëx]𘠙¼ Àp`p/-ÄÀò¨®> Ü¥!- βp¬Ü(•ÐS®"8ítVŒãüÝ|Ú´k›¿¨)?±§[Peù–üŽpãK²ÏèÉOìîoM7bk €Ã)“÷Î&Èje›Þ•š#°ŸVü°ÊO%Ђ¸¢jê˜z¿oƒÁl³¼z))±TSgßWá|+0x®®7îw‰úÖ{ÊÈÈ@ìc‡bê“a)‡ð}QÆÀyár^ÍlŸÕ£°´@Äš},Dƒ"Ëð¸€íÙ°P™x5x80vå7á'¡Ä‡še( MyªãmoÕ²åƒ#!4 Ö±ÂT€æÎ?™÷`^tÔ'Õ´B‹ûR‚=ä· q„R ÞÔØîü‹ûãÁÑ’ÿÐ!pú1""!250mQ:èRr-(W  ‘ Oæ£~!õ6¤­\Ť1`ÛŽ‡)VÓñÊ–†Ù˜-ùùàÏÜh¸{¤®ŽžJÆ]ݼn‡ï8¹‘ÍòdùPe:æµtßo £xgÍÀËp‚ãQ~À¡Eqå¤5I,¼ñòÀ0 €²f ìZµŒjyH™’ Ï6d·Á$BkžM® ¬rYœæÎ“iêWE>’äý4Ÿ™m !è1JB9š¡/!Ú‚ìðL‰¢'~]F~+ŒhJNºzŽqB°(Š ª_—“Å;wG¡­<ß:Õ9à®ãTX4_Mø<§"ʃû•)P†Hÿ­&ÎI[tôv|ÀÐ> »€Wj§Ì;–3Ær‚?“Ä›Õ>­²£¥qß(ª_€O7"±ËÝ$út»£Üím˜¸Í ¡âÄi¢où”zw~ù'.Óƒùì"ÎÁ"ÝðØÆ²u 2Út¯òb+ †f–•M~…FVūָ„Ïx¼Â£½.û[ÐµÒÆ{‰hºMdWVÉpEJAï˜Op»,’<ªœ˜þÕ ôÜiM‚X&úïU²–{´ÕGŸ“¢”LëÄ8»ÚƒB˜ÿñİ+J¬œÉÇÓ®ÈíBÄê]¸Š€å¡œhuͲôß.ºÐ­²J;+˜`µP`î¦ÒšÐÃï|m¯ew ÑÜ"î“{²É…Ê_5†6©-Gog>ËÅVͽ>ºæVž&'`WvBv9:~ÁŠ?¬Ú A*ë;[¡#ù;èÖ /—˜œ¥Ÿš“ =ÄèJžŒ*™MÌ”ô‰°­®R®÷îÕ–#¯Å³¥ Vƒ“…u,Ÿ%Æ “Qf¤tím/˜ # ³R&” ©îYRé;uª¢*=‡€ÜÒJÔÂA¢ªYå6œ{ !9;«Á¼Ö¨–f¨¯ôº‰±Ý Ž_¼QttQ¯gUS*'æ`Þb(íàrÛ^Ž#¦l‰ÔѰ"œ6šÒKØœÃd7†‹³Ôœ@žc¼N#áJ—èz0“Ø,Äo±Vlò6l à+±Ï)dm6Ó,ª¹ôÎVM ŸùŠj4z‰~µ®†‡h€Šž²4O‡.¦]“ @êÜW…k[O^‚²±SÖqGO÷>Šþ×óƒÃ2˜Z=?4_س7—_á¸=îØ”Áü¯ŽMËÖã‚B5ôÁX)V5MO nuüFO“þGg›Æ?±qoî ®"la#f-©N–e,¯ý`£W›µ-j»¤Å¸×¥é€ ³›aô]ËT:ÀͯŽz2ÚŒK/Çé”҉ߵu HÐÔÐ3[pæWWj‹‚é¨Jj¥®âÚùú*´°Þ›3[ lƒÐ^ ­ƒÄЬYGþe{Ê«ÐßV\‚+V ‚½_*Q·vürFúfí_>—ùÐÿ—Çf>¬•mZßü˜£C|xP²ÛÂvKHù AŠiRÜ ³ÿ2ß/¿‡– UUYízé)—Q;ncíŽåB‡ê§Œ—¸(ŠÌ¡u›õm~^:ØM¯÷`UøÀ›ûy\h#›Õ°³ˆCdZ7ôiÀö™Ï yô+t=q(1øÃ‚Òp YÕ÷²*-s>U׈f=0ÿ§ÅqÙÅšÊ4aÓèŽÝ¯ºFJ­ §\hšÛ£HGÛSÛø3úWZ ¹AÈnÔŠ™¹êˆqq° |Hp£¢=ºÂu"¾Æ3Öƒ± àl˜¥â¾äW HL¬z³ÞGÑo /Ltã©\¾¢`5\Ùð‚@Öök=V=uý#~—Š×ȨÅ,›{C6„¾6 »oT,³$ Õ,VH³=诠"à2è¿Úù÷ý—o/÷ÿ÷ëýWGýgûG¿>ÂY¡ zr) JݪàŒ%`«tÈS&©ê©×÷ "pŸ$ÏþÕ~—Ï9Zþ#ªÀ0šØ÷kYf†”ïWU ‚Þ’¾ïž£%oì˜aJM "xaÇH(µ¤ÍÑþ³Ï_î½üG©•Þ KS)ê ¨·Eb¥¸†Ñ³r§$‚Y[¢ñàoÌç¢~U+à ;¶§Ù‹}VÚ˜6yy ¥8TmC"mzSЛÌÊ‹Þ2Ž´Ë ;C½úcpQ¸_Ó•ÌEóc¨~—$SD+!É›Ñú#IëíÜt}BQÁsâ$yo4¢]_yåu¸n©Nn¯º…*ý©÷zº¹“_׬mÏe³©=ž´*Ï l,¾'ÂP$ád==xsuëõÔÔ¨Wßj"ã#¶:ÑÑE&ò6÷”Âæ,Ix âßY¹Œl¹0×Ú3„ñŠª)JŽÉáiONçÈC#$MS9Ìü„ÀåÓx¦tM¬˜³Dõ4oG(àà Т:™;¹UÿÝÐASõå6nd‹~že`wɘ÷×4HˆgÙÜZÍbøËˆ²ÉdD¬Òy]4¢Â4;ŽÛTÈbyJàw«äÎhBÀŸã'&d F?ÅénqSUDn ÚHHÂ%O! ”Ф ”–OE!4„ªéX‹.–¤ýÐ"#yý·Ag¡y3.ůʡXÄé2¾•€Háæ˜3MȸZ ïÆ™yC×i€©Ao~¼.x¡»²’ÙvÀ &<ƒ²;¥†Þèøí[SD9Ä–K`KÎW¸„3b>cÀ²UYcÒ5{m*Õ+ï×ù%?XÊ4,Œ!Î~Ãâøá.Ïg† p‘]D↤2($:!®L‚$DgE„ÜQHK¸¤&p<8‡a£æ÷$>ç 9ÉÖaWªÞódº›¿–¾ "ªÀ>åy§ÑAÀ#—6mñ¡èk½L‚ ÿ­Ò8Я¶ñµyÇ­ò5oÆV©këvì(êˆÔÞŸçi³åµÃ'¤%À.¤¶&›=îK#,ÿ±áŠâFÚXŒÿÝínw{éuïõv¶ïnnnoþww«÷'þ÷çøÙøV#›GØïü¾·ÑëmôîFÝvïþ°»Õ535Œ¿Zøk1ˆ Ù‚úĈ@œÑÃT›† ²Ú¢9]gßãê' G°{Ù(Ëw£¯øá‡pÓl:á¥já»Î.ú[ÃbBªo :EÐñu©üädÚ2W”Ót²>˦»ÑÝé{õˆŒìÓ)¤œîF[ð÷<{)ï HÚ¸Ñ6`ßÛÞ®Ýÿæç/½^o»·µÕÛ¹ûûîö½¿DÛ7Ú‹šŸÿáû¿fþéŸu@~)ÖóÙè£Î‚¥ü¿‡ü¿Û»{÷ÞÝó|Óü¶ù'ÿÿ?ÂÿCŽGA‚îFwr?lww7·Uî< æ£|‰<î¿ëñ(=ì"€20Iy?J±qÖݨu;ÛÉþ…R£´cÄf#â3C·¬¶ÛÙ¤RTžË²c+Öz1»%ëéØ,»è;Üél˜ÿ7·ÒÁt`Ý~ƒcœNN[÷—74Jâ“¥úÒyÍŸÅûÿcw>ý,Ùÿ[wïnÃþ¿Û3\ÿîæÖ_ ÌŸòßçù)íoçorÚ#v£Þ÷»Ýïw{?”·þ Ðͽ·¼÷#Þüv׬¼únÔKÆúaNBŸÝF·:²ŽA>Ê$q”ŦÔP­±¬os›Âôòé]ý|TåG=âGø51¥[@Ž]G¼Ãòm¥X ï—»54|p>š¥œlñƒ¥GC=`KCÅ1¡—B+Ò ™øÜ øƒ0 X\ÕBE©”*d+ÒY·=ɘÉ/Sg>/ŒrÈx2yŠ »÷+mÓc„w•6Hz·OyÕLßGEÁ‡_híl6u~ƒàt>ë€>yô­`zDª’¸/`¨¦Ù;Ñ&‰î~`=>Eä¢O×{ßÓÇökqqî(Ge3ã§ ¦ø×J˵DŽ ¶úÃ÷w¢{ÛwtËmš3ÐkQÕsåð¶ÛÝ;´ˆÓóÎ,‰AùCX¯ë9Àôå‹¶ªìËêö¥‘IŽZÁYE° @Íþ–àZ¦yvšƒþ­cú3€(¹bê¹ )·n!6«»Î”ŠÏâ³u[ç Exù´°…i¡M㢸0‹{gQï2^ë]o—9ÊU*DäW©âVŸ§èÃwЗA”›xóYïvîš¹X'¡ÿêú{ºs%#f£øGOL)8 KìÉ¿‚u«PÌ ×¿ãêÇ”I‹4O’uL,ÛŽü¿×!O`ý>_ß1û1‚å¦ÿXÙn•ŸùOnD¸Dþëmí ügžmmnw1ÿß½{wÿ”ÿ>ÇÈzÂQúÛv÷¾Í¨·¹ÛëîÞ­ª7¾½õí·Ñ¯GÏžÚôÊ·ÀÉç“æL¢Gë•¶´pLæIcþÎÇóøê« {|j¢¤ …„Ó<¾D~9æÓœK`%ä¿ïÛsp7’ß°XU¤ÅÓ#2${zô†_=ÇÍP¼÷Ü‚Œ}«"Æ0Ÿ¡‡¤'Séì¾…xåYœŽŠÝˆS ˜UØ>eDF ÛÑ™$³ s‚^ÊÇ`*:ø„`°wã“MlïÞÖ:h½±‚šuN"w•mÆîÎïs—3…ÐÑ¢Ú ‰ë\9;úó  ³ÖÁþú8DÿÇô÷ÛzUª²sN}mK¶ ÓÂ> SX¬nÄ´ñ¥7Ý视ÿC:Nðᘠ’?–éÿv¶Qÿ·¹eØþν¸ÿow·þäÿŸãGøiÂ=Õ_oc«‹GÀæ(ßÿ7,~*ß xø5Áø¬S¨J¡O4°lU¤:¹­WY91J-¨íF_' ^ÑnT¤ÿm8w1ŽG#’ÖÊ­ŸmV:  ß YõåGi¨þ¥ìUßÿ½ëÅð¿™9B5œàÒÅ,Ïøú)Uïlmu»ŸP]"ÿ݈pÙþßìÞ£ýàíÿ{æþ,?eùÏÓnY°y@÷‡Ýͪp¹ê¯þößûÖžÿçÿ,ÔÿwÐor4úÈ6îÿ­Msæß#ûïæÝ{;]Üÿw7ÿ¼ÿ}–?ÿ»?í”~ëûÎ&Û~0wÁM4v7wïî„RÀAˆ&±Ne6z‚ ,â*IñØ=x],;ÂNÏâ"qÞ¯âtL=ó«Á¢…áêüY¹Aå*kX]‰&u‚!žô› Üëþ¤˜cÖÀxRŒ8Wû0›4f!Y°¸ËÑ,ƒ ëmp-ÇÜ;b•&•¹ÔèÍQŽÐt‡Ï!×8i¸(mÕµ7œ6  OäAÝßž5ÔJÃÁÕ;x‡¿ï¿|uðüоÁ &$—árðrÿÙþáQÿàðçç!€zÎ9bàix¿%Ç´¤<¿ ·ÈNfàÅùPÅÒпýWÏ>úmïå>¡2–{‘S• ’-Àh]ÛîHA-Ió yDÝÅ ¹tÜD”7[fI³æó@{áÉü15Mܤ¸gÄ+ÚA†'c”Ö´ÚŠv#¯ì-…ÕÄOû Í-Uúäåë{OûÏž½~Ö7=lE\vhˆo¼d=äÜlüð€>ÞfLÉ·; ;²¹Æv¹®3UïpŸ4B$?B"úéð]´‹ú§éþË—Ï_êuh'<Â÷¿O>Ê6y'8Õýrñåso[ˆä7S·+­?4ü#7ÓIJ^ç•öZÂn^Ãö™Í'æ1ºô ú¢…Øì‹>ÌlÀˆÁE[pY±aNTd,圚„ìDE£qO¢†™ A¸ ´Í Ët¢ü²““ÕDiz/$­-¸ñcàFBy Éõ^`4Rò¸FÙİwöëoVÈbê7Ë}°)ï¹éèI<0 OÐÅ<»1¾ïtCP^Â5U*J±. ¤ˆl"VBa€0’6€óðHWBŒ_F˜»Ú,ƒ\¬y¨ÀW©ÒúÍXTáݹ÷Êe)ŸËü[ÝqŠâ§šæÈ;O2SZ£Hb-\F’õç†È¿ZฆµoàÜô"naåäó‹^FUÖgJ êÒëj‡³P®=—™Í êG‚€?°–E ½œg¬\qwž­µ}n6þJ/ZkÙP<•%c3§¨èÌëô ñ„§µÑ ²¾q2ÎòËþ(#NÀmý·©Áò ý¼Ñ ÀЯÐr¦HÅ#®³zû}$Fs6šoÍ¿Í×|œ [xzeÝéM öºˆÆñ|…õšÇæˆ,’>hüOàTTïªÇQÿÙþ³ç/ÿÑzðìàÈ…ØkTL”Z9ÈÜ»qlÍ$žü¤îÆç9<îü¤\FEÁb#DÍ{ºÈöé^Ûh¥c@Ó.…LE¢±é£Íàh—ö\L¦é(°’ûF0vàC@“Ë>Ÿ¸á›X ¢Ì}ä烧ûýÃç†D/Žö~z X¤¦+€baìʪuš5³¡ÒàFöÿëàÕÑ¿ñ×—û{O ­WZWÙ{¾rÃù÷¿£¯\OÔ©ã/ ¯ÕŠÞÈÎÌŠ†tifÃÍÌ5äK‡ÀR¯(ByZ¬$ÿµ9=Ä7®wAïËû²C‡*\JèæÛþN £ÔØ¡{€9žl\5¡óL3<×è*WyZ¼Ãë%àækÉL7¹‰U<ßµ&è$™¢çI'R¬Ô2Oµª¬S‘ÄŸÏëÓ„Ž”OE¨wJ,!Dec”)ãä­Zá/ª«Ûí–P›®Ö°}¸v<¤Ì†êÜI‹þd>6À éjV²÷±Æä[Ð9,qñô†'Î{T“ÃÇ!¤!eH)éS“Æb?ðežçsc‚ Z×]|TYÌjˆ5u*}’bV¸ÇQÌi½¼AžÐÖò6K²›Ì,$$†a-hŸH>Óz[.¤¥5‡àÿà½$æô_€¼â„pÔ \‚2Ž™1 †OŸKOæ ñŽÁù;—ê@¯góªÛ-¥°1@‰cûU€Â„Å&à„÷½Eôµº¤¿xu-Ы¼9Õ4YÈÔ™„xdš¾u¢#¼áa΃’ÀO{nM2 “0»’´ÏÀ|¥(¾Apà*Ûräó1ñÀÄ껉ݬè·cH÷ýíõrãj‰Ã¢ªß”p—¨2§L®FK®H°.*;£¦±§¸ÍJø ·v|š9Zá#¤Q²@´€!ØS­V]oÚ n¹=ÿ[íÅ?hÛd¿ÎÈAh‰ËÍ/ÒÑÈUs J ¾\ˆê­û¬?¥dº3iuÙ$‚—áB­³(×Q¦–—ê%.Î`A`Æ‹Œ0D=ê›Þj;ÑQFæÉ,R6Zµ£$EÀ¿ ƒ…‹ê ³…fþüÊI„–þ„·$¿‡£òåí(ë/¸5³8 Ë7¢fã¿<}þ“YhBà>DŸ²¢ÄKdœŽH ~ ³‘ˆÍŠT¤6êÂp˜ÇYn@cstŸ†.™6Hn³dº¢}ãv•bìW˜²ë†g™Ä<¦/¸­;5¶…E|þª$¿¢£T}Ù±G`qµŠ+×ðד“_Ò㜒¥„^îg –ht6øïbcNE;æA£r·yÇ(a–÷®ñ§¾Ã~K¹-¶XVÙÒ¤š#þ¡R’”àÅqiÙ¦Péä—o öœ\mK°VwɦàPLsmÔÆ;L3sžš¸OP¼á£³ôôlt©=}lð+’!ù}«ý§<ʹ|,Ž‹r.4†©‰“N" úÄ›àÌ\ çÓõY¶Žm˜r“ääͤaA[ä윀¨BŒüµ×ek÷ ¥ŸV< X˧6^Š‹·£7œ¶š‹;-ÖÕ7ÿÊKk¿¼¬VØúRyyë‡ÖS£"7á*QÞiæÎaXá¯GG/¾Yéõ}Yœ¥ t_ žá²b9&vE=éP]¶Y¿#¡˜m>H6_ØÔÝzèéùgìãfÿPÎN œKfæJÿ®ìÁ-*(ʼÁ‡[41hðûÂ|Y툢‹IcþÎ`×g—œ¼cÀ_}Ä%ç]ÈÅŒõ‚~2ò¡’³LG.m@«Î)•˜ÝÒöª¡wl|Œ'±½N°„Ö¦>Q|zš'§èëu’$CcOO'PíyGϧÉäà ÞàÁ$JÈÿL±õ!:QbĤ‘€¿ah#|ЉÄõÂY!W6 ‘”.»Jf_ãÊÄ3ÉJZì$Å6ªéiñÏ‘>ž ªt HµìG _ †4U˜‘Ãä²ïdq-”)Nª›.˜¾g[ÞØÌï0Jc˜±Vi£u6v4àÚîÌuºŧ/Ò„4y}ÚàËlw†ºxp]ÄµËÆì$fG=è g´ëùºhQr>:x~­â·Ål­É^íˆi™ÒG¯_¾’ÑÞ+Ãÿiqö^í£fóvnù›˜Ç¶y{Óf±mEGPÀ¼Þ7S"Ú?|rÿÿ4¸®§{‡¿¼ÞûeßTjøÓÿi4D[rc¸Ò`¤3’¶úc³ÝÞ22ÿj=¾òrÕ3/$ó«,¤Ü0àšu³ðÝZÓ‘êÜXÕh¡d6nªqÕLe79DJÝtAÒ—kMðÆj£O–0¦| ׬¿ÿÛ¬¾+wõ>¥'kM#«›ËÁ„º´¸cd:He“7ÊÖo¯“Ìåí/®«Âÿ?QoKÉGQ0@žu[k"=7XÛl.<'éh–ä óC·#Ì”ÿÒ|ɳø}6ÉÆ—¤8p‰ö¤ª6•¯â FÊ‚3L̙ҠNTHÌ')\µÈI f+eÚA†Bs Ùaôqf Gé}a v`²Ð4Cdµ¥§Õ²B½Ë p„­R¼˜O“Ü'¸Ðv³J[ªm1ýò•h+þ!Oj( u;º3TDW¤]7[7Ý]ï5¼ ¨¶#!§ŸoÙˆr¼š Ù;)ì \x±·¼šv ¶(S+Þèî÷~:J†]ª ¯b©¹”ц¡ý¡hŽ[l§}ŒÍÛuŸn¯_<†)${µ„=yˆÿ]ÇÿÒÙ%—!К^nT´,šv²iÅ»tÊ›ö Ü|µ)Ï¢WëU/Ü›ð¤Ç©Y#­‹—ˆ¬†¨i§ßç4ØëUäTàfÝJeõµ9;²©3‡\­ð–×ÐÕ.+Ö,´Òƒ†H1Á`“Ö÷&›ÙÔÍŒYIì·‹n3õÚûÓà¸0«‘»YßOÑ`ÙÍŒKا³Úµ|Ü­ ³.ïÞÛ];óH†÷Ëó(ËŒ+Zg¬¸|hÆÌk n«¼Ö¢½Ã'¥µ×“f¡9niáz¡ÔJÄÄi$´é©}ð<ÝŽ(¥R[´M˜å-4~ÍÅÜÄéé³"CWwGÐ5$Œ¡Ö{ìôþSà$ºêô` 'YÆ‚žŒ¢~*»7lØÄ§ðsÐÆp‡3âO<ÌåwRýÉ_fÐÉ,ñw»Þñò?èx—( NSBçö†CÂõg¯àbÁÉL‚lŸ Ú]©’– ø3~o8)à ÃËv¯½ éNøG·:7⇴ÈÝbP*TìQ„»Â¶¦GGVußwéÙë—Oùã¥Dƒ~S…í¨´pi¥†·>#ì5bSŽÓD”þ}èʤÁ­¼°Æë ôÄü±éQƒ½#A'þù{³¬Ày9ËÒûì f³nÁ|öÉÚ,MVï‹NÖfÍd}ŒcæT€ËÝÇS.ÝíÝ_,1^QDÂS#C“XqŽÇQ¼ÛÛýWºÛ½_ìîì®q0ÍýÐòR k jL4ò5 àÿühW÷®³²*—ûc6;˜µO6'R“´í­¯¿Ögh˜§ç˜H8éœv¢çy<`À†'?™ÙÂË#Ûüз–\\‡îy _ÀÈÍý,7’+(*üæšã$´AlµÎ·i¬à{E•Ub*1Ù‡1\¿¥ü9¶LãÔœ%–—ÖÞ 4ð…É%“…íýäæ:N:ÑžªÔFÞœt={àˆ…™CôÚѨVh”ÍÌ–8OFÙŽ5¶;2\Õ '#ó“iµ-p4[Ð4„ŽÍjÞ ä8TßùVjõqˆBà{„w&˜b4ºNCÙyÑЇÅÍëÁYœë—£dr:;Ã×½ÍïÕ Ïd>"×^°€{–cºCPä|Áq¥žÓ„®ÖuБ6Vìà%ÑWæ­¬®LwÉ-õ.¹T}%ª{™vÉÆdÌ1ó;ªQûEoóù¤øœÓ©g‘+5¸&my>« 5©"g¡‘ºM^éÛÒ¾?Qñ%Ì‹âEüÔ[i ›>±Kõ¡Ä9ÕÁ“Â㉇7W÷¥9©Œõ;±ƒ‡ˆZ!øÇ“õ8ž ΖÀ‰¤CJ•Ã~mž6æ 11cŠÈ±¼£Œàè;©µ¬¯P=Õ?†êØ«OOóÆ,{—¬¶ ×öÊ”\gÌ7Ñi2Ir²eïL1óâæPךuÔÒFh ŸKhzæÌ€ttÆZŒ‹³,*æÇFL…vÜ×à:˜œœJ©ù€µ¸é¬³v ްswEZ¥cOOW›Ö=˜Ë÷‘ýʬ¦!zFòIbäNÐE\¨ÂFçÕˆ±z¯fñ(± Äâé„ä„JÄ×\jƒªId€+ò5¹C Ù»Jʦ{þ'ðEná“ÒR¯,GïM.ånƒ,.Ã!i¼ë`a]›ÙéFa¶«’ùdŸRÒ£( š „©nYx³×BgrÓ‡f·µ¥ÝGwÍëMB‰mxreËÈ“Ö^?¨•qrМBÑ %†~¿®l5ª°ñ¸ÄÔÑAÒSŠ‘°aÁv‰ ʃL+…ˆD€so AbX0m^L( ÔȈ“Úð\ D#ÐS(±ê¨¨ì’Q‰Æ§I6¯x†öDBSõ¼ Š6â–@OåˆSØï¡>CŠéUûLeWœ (\ s¶úùEÀíè2˜T‹ùÙ!0 ´_0D¨sF·ª!Èq:a%jÃ_gˆ¦±òEOwˆÂÎ ¤Á”°—Ý'stðǧ¿nÌWí$¨cئ¾3|ï··ˆ¿,Šlâ\YèÇjìëJX~ˆ@ëk…•FxA—?µÄM#FõŠ*$CdÕi¶‹%M„(à³lö3N¯¢—ÇA<;xF>2_°Ûö(]©ÛPÚ›sF_Î’:Uä§]ø nU¹ÄúP,xY‡É &XDðëŠ'pö­,˜\cW¼Ù¿><ø/%Ä·¶Ò+aKÇÉ‚_bJê…©0Æ?Lh£â$—z¸ªFï¤VB;eÙ *ÒŸ¡eÈFä—ê fÉ6ˆ^|ÅB©Àd>>6 μ´{†$ºÉ#VNUìe–¸ÂÙºàüĺ®vÆPóM´-óë6ÒǨÉV`uÅ¿úù+—¶æG€ÍÌê.²ŸÚpzEqd™÷gá¦ùו·Ùž€‘ÂÞ5ëœã1ì´µ£ê&ïß³´@ȹ¥;xÁrÜ­!Nӈςúü ŽVؤ×1Ië/ÐÔ^4I?âar¥žb:é(1ÐÙ?Ê™},)w —8w@O$l6@ûÀwzµ+£Md_¾üÉÑitQ»âáZا«åòUÿ,žðàì õFr³l5ÉžA>»¤%‚ÖÒµa^_a~X€Ç|6¨A&}xlHôE¤c¸÷mlìªRfÅ8a¸‹5éSÌxCÜÑ› Úh‰Å®›?‰ò’#ºéÓŒÒ.!{ i³ïÚ¦sm•ëÇùé'8"]›ýÀ®tñ¨OMVé'R/+QpµPv© ¹t‘‰ðH@[ ÿNÄ{,t5Ç-Y„"\äjè‰JN  À¿ÐÅ `&eNùz>b ØJ¬jLâ^˜X7 ¤^uéÒ"žïv“Ñù@“k€^BDζz+« u¼Â‹ "¸ººÚ¾½VvC>¬=¡p0ÖÊ¿£<\Ú„\õlÿðuÿéóÇ{OûG{¯þöÉ.ŒÄ¼âÚµ\ìÖ¸˜XIà!7)¨%Ô–‹ÈS ›Ý”øR~7WõçÝórÍd'KG°ôÞ ¤µ¬HWï ðXùB‘¾ á¸Àcs ©úϘ [mì¿aY«Ÿ¤Ð¨Nôž‚‘_“·!à~Bêiü]ÎSõú”pû>Ù³ÙþV·è¡Û ÂǺ9ááÏ)¢úW¥o·GéyâDÊæÙò²t‚!@‹ÌǯÄzm“/¸ãŸKÄJýtEý¥#*lQ}+ø+<&OÏ‚3! ÓóthˆŠ„‘`h#S^¦­¥vW¶ ¬ ³‡O(\̵êä<[à<ÈôÓ˜˜u{ʹ»È…V©3ìW×òþèH•ñè*š`z§<‰šðm M§8þ¤À§öè˜^©ï,ÈÛÞOuïa(2#X‚s‹ë=3l¦2rüw’g$érYvÉ}–M£DÿÁ—ÖC¯Ä>­m:Ö_]'{TRÃ"r¦áÅO/‹£féß/tÐнô cƒKmÕ€&Uºi‡ x‰|“”ÆdÀÐCä˜ßýKiÝ?tðsàø¿â|)­NyÍ-¯æŽHGœ‘}ÿe”6÷ûã„íRLm\’æ%~Õ,yŸ*_† ¡ý1·!®"®¨ÙèÿÈÁíìüq„‘æ¯bÊa¨}©*P¸Ø•©¶õÙf¹=ÞÐ0>ThÁÄÙ ñ˜é‰ÔÒ¢¦½4Ý´?ÕJ„9‹‹þà, óUWÙÏ5>c€#@G ú ¸Ã9K8|iÀ¡‰“Ì>þ"tHÞOcÈ pøûLFØh†R½ÝtѺ{FT‹G€w(Ä/t$¿µ'’—¹Ã󬯛^©‹Š†ºr@näuG- ÉgöÉ—Ø“W¹?…¡ÑQ<Î̲#²ðPÝ5Cð(àÁ0™Þ¸áAëY¦W‘$±¸ç£ë ÇæöDó‡ìäpšï’:‘’#aæaïKì ²ù¨˜›®°;c—ÔÏ¢“€ˆ=L%¸éAö{öEÆ´w=`Äâ}Š,d_´2™»N¢CÈÓŒ åI4=¤FÉ?áB/w2,J«áQÔã’ÍÃõ^«\zŠ¥áZ>ý/`æšý_æúV•…Û[3Žšk>†„޽¨Ó‰¦?àÕmYâ‚`o_Æ¿yº¹:Ù‹Ä\T†Ëèéò¦+î©›ÌÖêƒ1'Lþ‡ËÝ+ì‡lžÃ üãfû*›ûä=–+ì˜ôý{,÷®²ûÁcö=šïW Š>èÁüp…ËwúÇž‚6½Ê]€rO³¤Sˆ¨#w‚ /’‘Ót£$DYº0kݶ¿€0³Ü SBÁžî›1œVµ Žý­¶6#( <¤OwºuIì>o³B»­.híÒ¥µÜ '+TLì›øß-üï]üï6þwÿ{ÿû=þ÷‡¥ W¦ˆ~I4Y5-a“C·,7­ÑBRh/ûn®{èô þË=±ˆR° xÝN´ ³ `Íýp‹GÉKÛTÞ.Þ‚5B¹˜o>At@@mmûe¡Jnž•¨0­²öÂÍün´gçèà àœŒTó‹ãKHÞfæó—Ý{qð €uVP#_-b†sðïrôñž8Š)Y«WÝ裦¡àõä>4Q5¶ÂÉp¤Œ : ö–{y‹qgyÈA4Ç¥ìôŸJsAáü+­VòzUyZŽÐø9!½:]T îøìºŠ$/ñ|Ü'ì€Qz’ Rõô qTk÷Çœçæ*2¤J©£JÜî¿Úõêàù!$Rt&Øè*.yÀ<…\´Q<ȳ¢ðA#(Ÿ·:" `’{×I ”—¥ ºJüšÀV1µcŒ>3)™Lêb|>=ÈS±R|Ϫ1¬Á`Y¿#僓L*KMпHN f('†ñ猙ø»!æ)Ç/°»k–“†î8I&*½míQŒž0Ô“å‡âÕÀ ŽÄ%\’y°IÏ ª]Q?*˜€ûw,éq!ÿÓá Ë_Æpy}d_0 ‡ñGw¯<*9QÒ„±ˆ%Àâ3Ê)!Í}ZŠ_ʨ|a$”ÕŽ‘=ê¯Ù ö‘êD ë~\WPø‰2À…ìa àdwŸ»ó‰¸ÙYžÍVvi_Ðy¯×Ö.lOwi‡™ƒ”(ì Äýñ@înh¬ÁÓÈtýRMà±agà ºš8·¶Œ HA ´ ËY8œžMkè´‚Ój¢´ ò4×PQyѬV•TØ=ÐNÂŽ¼¶]”í¨ÒVb­‹+t_,©=,½ÏóQßÌz¼‚#´àÁ?b°8åÐXÜ5x5!ˆ‰ðŠÔ™ç”BLõ3F’ó"ÔDû¯ªËÚãš$¶cG£VÜ“ëÔT7æ!\äƒÕ%Ò ÷éªÄëÞæÒÝ ‹]H`8Ô{{)‚añ Ð}s=;Y7«`ÑR¾ÐxFñätH+J¾M9•Íûw¡Fï¼5„6œ¼›€kŸTT°XO>°L¼ä‚ÂÃRÅ|:ÍrÄhä ®IºëQ®Ä:ykŸ×¬Ó,“~€´¸|ÚŠêË`L§‹!«Íæ 6›.Ô q»<™Íó‰0=J’´½Fy‡ PçV%‹D ëçÉ8;O†œ‰«ìu7{:éÒ_ ñNól>eÓS±¾Ýy¿nΧ<Žöñ¿R5W›"øí¿0%“TE‰ú "Š™SI†È‹$œÁ‰»l:¶É]½mújy»$Þ‹‡Ã>Öބל­A8n måM»þ*F7r9¦§ö[Þévï6[f‰Ìý…¹½˜Ý4[Üì"`V[/‡S£Ú{Ód¬÷Õš=j0­ £ÞZ=Ý×<ª†'h–­ïtÞG¯Js’Žy ²ÝNpŽ^âš('îÅïþuœ™µûM'€5zz¥M™²Z¢7T„þ»é(]Bv^¸# §×¹[;½…©SˆÿòôùOFüyÓ0Žlâ­¤Àe£1¾,þ9jì–Ÿ¤ü²œÇïMÝM#‰¶L€z4kºîœjýÙÞ5!²åç—ÏŸÉÈy½`5¦‹o@¾àÞ›6š½§Gû/££½Ÿžî[b=þuïð—ýèñ󧯟F¦JüŸi‘E‡¯Ÿ>m,¬tMòÈS²5Â@Í6¿7Õ?F³' °µfëÄëÙtÙª»ë‹¦vÕùKÛÝf²È^þ¹ fÁ¨»Ëˆeïemn¼2=uBˆÝ ´B­lj•ZÆo[îÑìm¶ÜžÑ,b­ÑX qæíðÇ(ZÙ|È“»Ûë|¿5•Zy’\Xê¹o!]~Øjc þ¼À•GLzè>´ƒêÃÝ À>•‡!Øþ£× x›Í'†Ü£Ë¶jÕߣ;›vo{M™ÔÈ ¦Åd {ßWz5QŸÇjO ‰ ·š''éû¶,*µÑ‹–¿È ¹j˜ÒՑѵX‹CÀÌB=IÀÚå*™w2¼£ÔNDÛ´R;ÜT¢Ãì² »j.b#rk2Ç 1׸¡PÆ…ªbÿXÇ•MT- e¿Èøp†½EsûÙ,¿Êæ"µdyG–ZŽ,CËL¿.¡[ NàÈÂbæ©`/ž©ÌU‚9Î òaÏ1O•¡Ñ«ÿý”™)LѼ"D¿CÜÂY:Ä©v5`9Eå è$sù›8›î/²üŒã¶ù¤ ’>}kúÐìzÒ|¯tCxòòù #É?Ùÿ¯è_vY~Åênæ˜ANÑ{Ó(æô'<ÆÞðµ”ÿPjSq-fA(þÐiqÂãC Ù°ßÀÒ‘Ýa†£ÞΩ Ô¹Jϼ¾ÉCw®L*  cZÁÕã—û Ÿ¾><øß¯÷k'+ 7èóCý¾´Õ[Ñê÷ÆÐÝÌ»ð¹f£½'OÜ©¤8º½óE’Ò0óÅ׿º&ÔJ2ƒ¼f%ÐO¦­¦dyë^í6ù6¦‘Î0E3ZHL8‹P­ƒl>™I>íeGñÎMÅÁ5¦÷¤î£Y]ñ%þîïÍ+V2Ë »¾jıɯåS,d¯ao¡1=®²Új+st¹™ê„>W[¬ñ²Ç.ÍFºuß%8Îàò³S(Ù Ž;ôÛ[*OÞ«]ÄÁÑÊ\𥠹íÛÃh­ý¶wôø×'Ïévrðx?ê¬ñ\ë®ÝP¿í½<<8ü%ØHï¦ÙùòùË`›kËo¶lªeP`p¾cE¾Âl¨"F(b¢·ãK¨…»m$»þp§^‘)é= 3wfð]iz6Å‹èyÉPÉ÷€ý ðªD‰b ׳SÑ^¸M§ °òV½'Š(4ȦØ ¬xì8{NHèQE–-¾ï¯´ø¬:ˆê¡£<Ô­6<Ч(a×ɶox²Ú½— dOÚ”^¸¥ÄO$+Ò)š9ÀräöË,ŸÆF^là]Òô-!B‚þÑfa`²0¹wJ†NniX¨¬<8A ƒt2SF¸Øºª[Cè¶êF‡¥§€ây•mŸ¿> ¶bÉ`ë,B7«r«ÈiÛ>­~Ý[äª?åGÛO’ÞÚ<Õ6NNNŠ4›ÒˆFƒÙe•ãK%Ý´a#à¦Rö®¦èím.UôŠä@]ÔÉÇÔ•xí²Õ&¦ŒO*Žx~n¢(Q{ }ÚY”÷”š˜up—éacH¥BíJ4Ãl’ ÙÉj)|2Í BÎ@âù¤ôèC§§9z%£BqÙÔˆÞwnà û€KŽÒžéJãšX[Pukͧ¬ÜÙ§èUËuÙ(ê´ú7«KXc}oc—zøCä\²éÐîæÍííàvv¾K¸Ò!9dìžQþdωÀ}ÛU‹}yI›Ûî©â芼¼ž/ží½üGô·ýDM3Ròµj-¹â3ÙXñ¡ÈÖ§¡ZÕžGQzÒN}+þD“8Ê&§ƒþËΣ©s^qÝ+š#î¹L¿mEß~u×/ÝèÉþÏ{¯ŸûË˽Çp´àùúèçïÍ>‚§Uýqõ,~'éÓ…†Æùn’ÛÌùñwvÑÖ•Žpõ)ÁR‚ËR[î"mJ÷ØÆ”¥)G†ãÕü¬ÊNS§´¼aNS#/<~~øêèåÞÁá?íšô MÐǺÞ&ÒÌ%gnrãv}Üfàn,Yg*…*Wc(µÍÝ®™Ãƒþ\ÄÆU&±«öàðÕþË#´±U5eô²p-µ#iYÂpîi½q.«ðÛsw¨4ÙV+r« ÑÍ^·mû]Ô«¬ù•Θ‘é•“ÜXë¸Þà4u֞ảl£µBŸáØÄ%m õV$V} a@ø]VºñzÕ`è;h8ØVå ¹Dnm=òѽ”_,¢ §NA³aÈ# 4ËçÓéD Œ‡™ÆǶUà ôƒ^ɺ܊ù€ P‰Ù²Ç x—&·Jû†¤5™]i™l‹®&„ågÕoñŒ]µòªt9ÂøC9'‘Ù¡üŒh‹æEFÁHÌn'ŒaËKêoäÁ¹ñ"dÆ9y§à¦ÚÔ¢zÏEÇHF‹†aºd:xpÂfNô¡„‰ÁÉ3½Ág† @²J8±¬ ‹¿P¦ !OBi.#k+/õe'ÞßkjâÐd„F^§åí(a*AaOŽ¿øôÔ\ @€2üN•L,o(Á™ ×)šŽò·UŸšëW”Ž1¤¸ì>¼¤"§Äì½¾»reì¶a.!W³|Ó†«Ô ¦E´úP½ï§£Ë+Q[Ò!ó®Oê%£s¢ƒ$(‹áåG|>ƒH¹ü#*0BrË y­àƒ‰‚’3ž5l&ê$ž`Ï›˜Â,”rO;ßóF-}kx ÕÉ•˜í=j´n"# EUVJ(ÏûþÞ§©øÌæ¹ÍLM«&ºrHá)Ÿ3ÃSÀ=À ÅtKÇÓQÊ0‡®ŠJWÆÔ\ÀÌdžj=`<‚ÍUÍUÁ©...:Òô?G,?Ý0(6¾ïln`J$Ê_³Áµ¬S¥ñ.BQžqtpôAJ»ÁçR ¹^ná¾v¶Èú¡T€&BKæg@••@ÜhŠ Áq^AÈ¢Q¯©XH³"Ëò(gë\5š1î½jnÿ½¤ø‘ÇRCÛšJ9Ã×q8f\ vV oÙ*j°BŽqÀdžùU¥—Ч=õ}ÂO\x8ü°ø*öd_xµÎ‚ ï ØÚ°è?NJª‰] È5Øè*1ð-tÓ’þ¯<‰È"p¢ƒ¹ÃËÐÂòš[á8±ëŽ.eÞouˆe¼¸Õ ®867Ãt050s,L1¬ž…°á«A‡6:Ôð{݄گ,®ÚâÍ3êYÙ¢×ѹ­áÓl•ÿú4„ZÔ¡¾ÕoüÁú5e‡Ï?V¯`Iæ^ÕÞd*4ݨˆ,öwcÈa>zÑw!½œÆÎ™;ìJÁ° ;GºTõ¸Ô[—°éޏùÓ«®wÌÕ‡µlB,XÔœüùç9ðçrà_‡4]ŠPÞ<¿8ýxÄ^¾hH´s:ާNÉXº>˜‰fy"w! –¹¢Ô!íÒ4­U: Á¥Å²©Òw)¹¬[7íRoÈ‚‰Íéä6꡹è ÅÎ è •zÛŠ~ŒôßÑ.ÿ¦ûÖ¬$3°*ë¯.nòþ’3‹Šµ¹?îßO½€¨VàdYÉŒÿ˜Â÷zÎf¯E%¦Çd ‰Åº¶Íºx…[ ˜Seµ®@sÖCdb¾ýã6Ï2Ìö^ sÇA)fñ°/£D#ý§lÍì“8?Õí}ÊÖb4!ô%ßrãÓŽ[3ã›KÙ•ñ(‹òtÃÑ­{ýiû­©^‡[[¥ß'éÌ_¸Ášø8_~v»q Y«fÎäÚõD µ@ãcÎŽÕX0„Û¦5È+ÑXH°k-EÔûÏÄX°5oúÖô*þ¤­a7¿ÐÑÜðÙhæåÖŽ"¸ñ}´äiV¤ª–OÜm„¿iâƒ<¶|R«ñ„ãd˜ÎÇŒ±»<‰f’®xæBªî©ßX /-v¯«ˆ%˜|u©Ä¥¼Úünm^qz1½ßÂ)¸²@i×éÒª? ÓÉT6Ûã§Þ ^ŠÅO+'˜ì ò)["qU–T’E8 ÿSñ#F}PiÿÒá0™,jïFä3ò$Ÿ€¯î'mÆKú)GÃùJ?íhüãfN Ì`ä7ÜuBšFÍØ§lfÚ[ñ<ýHΙé?K;[Ÿ©»Ÿ©íÏÔÎÎgjçÞgjçûÏÔΟ§›t{Y;Á®”èÚû±¹W7•õú†’]‡&èe»^@”ÚÄ×+§½&iÞE˰kh‹)žâQIm \T{’‰R¸aâÔ½ ÷Ÿ¥§¹èMQIŠyëœ#ºé;å©vþt·•€ 6ƒØ(¯O 4ãŒwaŽÞ†ªË‘O“ø<=mö—Ú[ ¬{U¶¬%ׇ×595¥ b¶³ó”×$¼SØ;ic$‡uà¡Ï(÷%¢Tt¢Âù/ȧ‰  ­XÝ|9·WÙsÑÅÂ݉Ò'å4ãWÒ–Nd'³d"î²J]A~I~>p›š°´:×éú¸”Â~ñ‘%×w©D…Î^9ô§¢1 ú;=6Ê(¾L0®¤8ƒä Hîß3ˆi!¥3¦¯e"ï‚à8kÎf>˜zM^HÚ8³Š!…PƸâ³lZ&RnãÃ+©üAˆP¯¤ÌRR•J–‰…CCܨQúÎ+9)bq)ÛØ¡Tb}hÅPV<ÛK½à‰PgCy€ L !ʳÃ8{tôhe£2~¼‰½*¾b#—äw~Ó¨²‹ÆÛ–bt¤(<§Úè({žä³…&ækÎÞIJY6%¦aQ·ûãø=ª_Ø• ï[±+ÃP>„jÇÕDÿ‰§J§Ó+s9O×µwf΃eyµ™ò^ååÌãr``%”:àZÑ•ÊÈñþaikÔ© ÊJ¨ÕïôWÕA•uå7®=ðš*oßë¨;”$Z#=”å.  ¨8Ý=%‹pMôúâCԴ͵)iœ—<ÒEQôû/Fá|£WíÛUö®º®5ÿÞ¥ãä‡í®ŽÇ§ëëÑ7ߘ?0w¯ Í"ZÉû9ؼí^üVoBvC°<]3ÚÀ z-Œòâêãöêth÷` ,ôà "]¼u6~óÙÓ>˜ÞGæÊœâ£Ê±o”u˜£]'HÒµ®¸³<=M'ŒÄj.Áš 5ªœ¶´§ßèξõœÚ–r! ÇèÉqó8ijTœ×E?¥¼¤(eƒÁ<·)uA*2ƒ7+1ØFÉÉ,;§T°ö½ˆŸ®>pèàL»” Í%¤¶Aƒ¸¦6&ïRL$0Ö~_a¯K.~¥\C4^ðbÑ æÎ°J‚^»4mf*{ñ&øî;WŽòt2O|R~µù›ƒåÍs‡¼³±_8¡cŒÑ+cz.Y¹?Cì’ˆþ¾' £4ÉoeU¾a†ûö~ ,^•ð¤¤ðïS ÉÍ_Ù¾`1íºcˆY(Ÿ4:còGÊDc–{ÇÛŸtà!°%>ã}¦g{åí¡Ö-´²{‰tF¥ÖÛŽo¹HŸ›|C7Ä·÷—5Œ¿cÆâr›î¸bÃî»ò®MFf5•hÔHÍf“ž'#SÄóº«R [’Ì'$"…+ÀXr<@®88'<ùƒ p¡ºÂq·íÕI3´ãþè/e6@ã_É’¥ø»è›èÙþáëþß^üôt¿pØ?z¹¿¯Wò¦}‹9ñ`.z-éÁz}–êmbÅïö¤ÿÓ?ú{OžFÿ¦Ÿ=rðózQåêo´úâLˆ(x ðÆó4vÄààpa5æ$fß鬳 ÿÁî:ÉÖž·Å ÿýr ­vÁbÕ"¢\«fi-šf«ÐÒÆ=޵°È“Bq\\V o„cšÙ¥ñl–§Ç¦#øW…{5ÙéŸ[Þ?àa)Y„€}ÉZEO¿0¯©‡ÎÏs)7ÁƒNE€“!”YüùA»|w®non“¨“¾IÖìûqY¾ òüs½Ñ ®Ó>ƒC4oþo¼þß{ëÿ_wý‡· Õ®›ÿ³|–²‹$oú§rƒ 5i©föõ%ÍM•xGÄ…¾-ä&6Ào§š­²(¸wÀÕê8+ì³£Q~­š™ƒ)1æÀP:°Ü¿û.ÏèþþQ³7!½Åñ|2À\‹ÇÙé¼@11…»½)£Ë6;÷‚¦DDÇBW…ŠN ïvîEêx)­(l;ûìíÂy¨?% õÕœn$¸f¼Ù(u;§Ÿ-sŸìbFײÀ",-æò¨VÝk‹—êê|CñÊþUõ#$q__IøÆûgIZ ÞW=\EE$‹¹X2žÎ.+\Ì[s-Oç˜^ó ¥Ð& Åc¯‹d.î"ÿ_ ð2Ó¹ÝW&ëñhOæã$Op3¶ÙeÖP0ƒx6O k1S¢ ª«üÄÈ+Mó€XÛl˜4×`MŠ\H@û°˜Sì"~›ìAìñŽÝ,at5*%àVï´fœ›R£Ah²¹Ž›û9ßÄËö°¬ÿv÷§¥§ÑfijDë£! 8K§”†ÚÝ]j‡–ó&‚YpbJ©?6e ©7bdðtƒ¹çSÈqQ˜On^Р팲ŒbI…]’n†àåço…öf¿ù&4k¢žG…d;›(ڀ½G—žô9sTuµyØ.›”ZÚ`cC½\”à¡R¤¤—lïÐ7 ­Fºê`Ë´ÔãÞCUGlNsrgù¬-Ù Ëfš¸à„…«÷ÄŠŸKáçwù­¿u‘Ö÷×[ *ÃU"é2Ü‚7C»ÙaXôŽÀáYf0H’BÃ(‰Õð‰ÀÞÑg ¶Cýhß.Œži3wxaÞ  ”Ý-QÉ)ã¯_Ý9£ÎW9` WÜõGLÅ@¾ø!“vÝ1S6æk4å;sƒ£¦`PvØ&ó9Ž›²Yÿ¯=p X|ó#§n×?tÊ›)ª‡·.Îâß‹³ï9Ú†*äëzÊäÔ‚ h©£è¶C «Ú¿Á‘Axù¶v¾P(8ôŒ¨W?5Vá»s œ#ç¥ÜV®„.™—xˆû©ù²d•ŽlÀ`!°}×;qº¥ )H&›¨(è¬W¡ ¯dþL³ÜjZú¨•Mõ<»±Ñäs•ê§ŸßE×@Ž7SˆsÊ7Àƒ¿'¤’œa,Eƒ—yr5_ þ[Ç*4å,ŒhÕ7z÷*¢šw6¡Õ¶A`&Š”àHÃW5N(<+ÅJÍP¹BÈ5scÍPnÉì 8"5v¸!]óñqѼ|ŽT ¢i4Ö%÷û€ Û/5bµ®wùU„!éï®5‡é6[ÂVz¾U®D:³°r=dœæ„ P飌¿€Ëeƒho¢á,êò¾ß9 ð: ÝI*èÎÔûïcâ¤;fSe p:%µš¤¿km¡…Öaí™iMB\·ÉVàgˆ&;’m)U &–Î62‹0K­¥· WX~);¼&);iXȾ˜u«6ÊÊ­C¥íM–q ¹⤼Õ{ì³,Åê f²Š‘†J¤ˆ·…c2Ü£µ„Mȵ\ÔŒ¬¸€ [8^JÄ~4Fd+‹Bk¼{å%·aZC ;4Lî¹Î‚}§6ð<7b¬RQ¾‡ì7°œ³c.ÉñΦ4l¿Í1#oUDðr‘e$–ME ¯`»2Ð'ù®HÿÃ\Û9Í·¦ãÏщ…ä/:ÁòeðÀº²aÑjëä¿7¨Y6Sûh« ó[Ȇ(åMpAÑú])7U78ÅÝu5Óè–÷óóXlâ± ì@'‡\î”L¡#‘ù—á1µ£ùp«hó0Y^"|FJ+u8D65HMÙÈO5±²ü¹ûyÞ ðõC ¿W»+EhúF´ÅÐf%¶ò{»!¿¢Vt;ÏcjY¨1©êG3Ô"¹ëo¢û“J·œéšE8Ì-A@¦”Kæ^g.GÈœ’ ¢,’Vª•a9Ó^Yp1Ü0:¸X‹­æ]øM“”°lÎ,×éRùywns••F/ÃiRs¯‡jª–| Ré‹«wßcÕ´+‰ÑnqX²ôÊ–Å£3Ê€éû'OO§gÇg¯O/O^=;~~òü¬*{8\Ú{?Á­=Ñ«¾ÝÚ£fm I•Ù«ÚkŰÞëN²ò_z#U¢°¡jÒãHövtBÂCßòŽuQe¬xYË’ì]+»ºD¤[þÒÐ+ïUò×6– °H%“+P»òJ%c³j×ö Ä åÖ#üÏV³€\G€¯ÅXÖ¨Õf¯ÊþÎ]Xøýýuk[•é¹fs5Y)n‚wÝö"ÞL}Ô—Ïí³vò£V~‡²Ÿ@…¡úA8L’wÒï6M¬q䯦s=W»ê”@ý¥ƒ_‡Ué%oåU#¬I¤óÌçWj—E¢2ß”P÷ËÝ'Hqƒi¾$VÄ™J.¼ŒÁ®Áø@2OÎÀãßÌu,Ÿ vÒaƒ#³ŒéÀ<3¥È³7‘K΀5´ þßrž-låiýС áW¹ UbZß#«£åŒp`ÔÙ¢X¯ôDÛûñ#š>pdü;ž¿OÞEòZI’iNk•œJØo úcíäQpjëYe<€ïÞðô|Ç/}o[¦µ%TÒ–VGúMækH)a™ßW;°¤±*7¨²´ƒk+– jih$<‚ÖšrŒí t; hG« íÂfn0‰¼Óu#³ÛÏ îdN7èù ÎJ0–xÉÙE žŸ§á8’œY[1½çð‘(ƒs©\£ #GãéÕº‰Þs…g[µÛœ©’KNÈ…cmsò­˜\¨®¢%ÕoØY LM™b‚M1æà@X’´P/ìE­ð€ÁÄévÙ¸u½à}£‡d”¦IJ­o†Ù··éÁñty‘¬Î/pȨ;Š.›ÙœKˆýø@Χ6ßüôJÔfM]Ýå0ÇÌ¥Ð&›1Ã` K è@ãq©EiåÇñ˜‚2ÀÄÑqŸô€*Á—ÀÔ`6<1Í”™œÙN+ å2˜™%ã±<‘ä9æ8  ÆF§)‚R€q< PÓ¤¡R[§!f4þ6ÓÆË ]¡¡ ½î..¬sZÓYŽÅ°ƒPh“wØjb/öŠZ2oÎuJM*BlVQYîíÂM®\ܠ剰³q·±µUF`X¯- 1w­½A“Ñš ¸[SÚר%”z¤}Ù¥:q)e´%ŒÔ_y+†jœ˜ ³ÈàRÖ«AWf|¡¤;-æ2áPÎ: C™:Lʹ¯0ëàÁ5·¬é¼S)56RÆ^Ø Ïij÷ ‘_¹ÐMüõŒ:Ð4Ĭ¤û¼FÈnÓqkÃø¼*œì/·kÂ$…~”¤<. Bv*ý4|ºYÒë ½"4ƒÛFÅ}bEÝêz€b]‚K­Ø¡ÍR…B§@8`º²ÔÐx2 ¤˜HÖP1©|§ö»à<9è~@ª9¢Ã°MœrÎ'óˆg!Åå^k«Mt*Àñš;Ébu•ÀRÕœØ"MPiÏ~ëHnQçF~«°¦HdeQÇp¨ÌIº×,á{Gò°X7¶ª+à šëÔ#½©£r5K1È}©W¦©¨ä>7Üãý»×PŽÔ$±ªhXqNë‚™±Ý&2ñœ¾h²8(ÒG’æcB¬–‰N S»„UªïŠ%¬è½©£‡¼ô’€p0 ¼k–k ¯Ö2¼0в– &Nß‹j…ƒ8œ¨Ãf°\RX,’èdÚ#Æ´bZ¤\‹E] ôò!qýFº˜Æ£l¶ñzë›mîÎGƒ%g¡À‘Ó<@….—’¯Aç²\ÍM Þ8É4>­u™¤ï@RBÈÜŽ÷Ññóç/ΤoPÖŠI*à wò©[(Að0r`MWcR7˜Ž¿6û~Niß@ÏŠÊüøå‚T(d~ Èb²MÄÓŽ¾°Ð—&:Íç;6h#rGHt‰1Áüæ@˜»‚d¸ÄI øÉ<âòƒ„Æ âɤ ïNA­a –éj¶â±}»@Å^·Ž¨T!þ¸³a¥J1rðð¡d>vúúD‚åS(Üôˆn¢&Å83‹(ÅŠU QHBj!MˆƒO¦ X;ýÚÕÊëèSõ碧>¾çw F)Ð ßVº?/^=>y|÷w(äg½ÇÐoä¼ç ÝšüüG}%0н¾ÀàÀ:GðP/}Ià·¢ ;¿ÿ:û@ Ðt!ˆ •t ö)ÞãrWdkñƒ+Ê?h×U%-FKž>*©!{ùL¸æ…GµhÛ@Ú•—4®¤hÚÛ¾¨Í·2ý-mâ"í²Í„:Äë;&ÉÔö‹ »Ñå«û¬_rF.GRB[‹,C5òPøÌê³@t¦x ‘@wx‰ºªE’Ù¸1Ïþ~úßO±üFùé™ÙbO~xþâÕI—Üp°Å!ÞšŒñÌV ¸fÁCYcVdÍèèý“è$ ¶,ôÌG2jdT”óžŒsÐ>™x#àNp~U]<]+#¶7Áe`î·)h?¸[Šò{ ¿,6×ü%Îöc9éõĺ@æ/ˆõ‚™'è©âR&ñµÊ7a. 847Èⱺ»u5kó‡CÍÌ%¹Û¸ŽtT5MYm Ö@f\ʵÝ,KNîõ3Vk§§[#¤›GÃÞ3ðívá-+¯2‹7½ýi!¾½ìB›kQú×ÓÄeýò“….ÁP¦É×*å{¹f´ËŒsjÓ1@ܘ­SŒkN ðnm'³€T¨Z©À4…µÎjÑ¥Â-¥pm}à˜ý²Š´›‰Mnn$$iÚ^ rD¨ Ðuæá{¼+›&óÄÐ; TÚ¡—¦Þ^‘x„m-_My´ƒÿ;¨-7=/”S6ßnfhÉLù[Ò J?㈢pÿÐvÍ(1‡æàL èXÜ1B¤ˆÏ” ‡«´FWI6ÐŽ¾´!á|œD™>ˆãe©tñ«Ððü?~¼~þä¿_ŸÿuòwpÇ–Ò-k|9<ØZãÐRÓ£Z¡C×—ß‹À xþÐ= Vf9f6rïÉØh9×}ßM&ï‘ü}|×[æs("hJÁœÜ*Ò•=·À|HU¼«ÌZgæùë¯_‚ÌcAüxü·'Ïp±š`ì[€î×é×Þ¶Ÿ[æŠ^¼pZeÖ^”Üdtfï+Ó8oTu™,éªZýjSüú<æ''WÌ:ø´ðUEÅdžaò6­c6á1s2ö€ò2g×¶^Æ µËμ UÌ;y:z¾ 0¼”Dj/¾NÎͰ–ó¯²5ªT9C"êÔû¶!ïs°w åòƇ ˆÉ¼5‹î5êE}OÒ8’Õ|Ù{wÊV¡^’*;âtž¤ëŒ3vï~ž‚z­†WIlxh| ž ØbŵþòO_ütòª%%· hHE­·#2¡aWÀ%M.3ÒÉ“…ôú zºƒw"[,p4¤K{­3d²¯3jžàµÔÑ-Öáٽߦš°õ탇ÿß¿Ûÿ¶ŽÿZol ÎÁ?:oÿ¼õ@ëÛ‡íßÞBõ¡…ùí¾¼.Õ^súÐjèþÔ*yýZÿmë,It ›Dò–Ÿ² ïöªÌa*HžxWÕeq®GVÿ÷yRh©Ä땹æd]Í‚÷É(®¦˜O%YZÇY‰û+ÙL“©•­w°¡.“ƒ~paÞ‘9÷œ­‘>$ódvÕÝÈ`|Ïf^âNBŠ"Ã7·êxe.Ëœ6)1%‚Š £‰럃¾=‰s†\¸S?P Ît0ߨ`•楡JRH+p¡Úät…àE1g?φÚºÔj½åF6Р0ÄàÝFl8e>@kýªÑ0bø'S …Ni²å•‡.¢hID†™EXC8âÕÈ4µÄ(ÁÚÃ%ß[ÏØdX˜º. fpl8¶±J爢'4®ŽYÎ篟>U¤Oº2ŠCðÃ~lо»ð¼Ÿoõ"›Œ·œ–Ø•H$²Ð›!Ó¬É,|G‘»Èd˜8S˜á\&«éº%ª6:ÀK[F[ñt˜Äi&Öž@£'$žÑßµ¼èd‡XÊ$º·Ömv2×#o¬ÚäŠå!´*™¨ògrå@L¥^ž¬AmW®­¢û”:_và¢sµk7hF&6X¦Q±-Gªs´ zÎÈ«mrŒªÒ5Ù•BénÚ¦kØ8 c Þ ¦FSN]»~élY^?7¾"/[Zk`þÙñÆÛçW;8»Â Ú› Xж Þ划+?Xz"³»×BV+Æê¶¦¯j«â6AG×ÙÅñ+9iJP¨¢æ:Ì+¯–¢ÐpüfxSªêª'LDB1AEñêQ?@[]4ûèŠb©¢ 'ßí,/c4ÞÍ©¶ŠJŸÁ«G€¡èZVç²½jmJ³ñ D=˜¯ÖyJíU™ŠßÒ¶ñÜ(ñX§ú»ß?²X¾é^¿*•ŸH5¤õ­½†îÀ_ÁœÖ£ßÖ§QÆzqÈY-s3Ø£øa«ya-äÐ𵕕 'C4A[_eXQ‰±Ë["697—Jq¹Bþö…æz)¹F¶þLòç<‹+èsáýœ§ò IyÅP¯IŸ?'¥¯»@âBÑ0Î ¨—Y¤+Ü$gbÂþŠDqn¸PºŸ†¨ÐR#à{ϱ³eDÅÇyjŒ¡—úþC0™h´s-Ù8¬—.¾Å{l5J }-Å`jcÃwÒ)Ye†B˜£á½a~Áï ·Æ›€Æ¸#¶ËÀ¦¬é»!ÓxÑÔ(‡ º|%Ž?S©¢,мv+ÐDmh3E BÈÃP>6UVnê¡AÕÒ- × xµÄŽ‘‚Ú mâSoácp¥¯`µ_‘Hײ*6ÆTˆÒ‰Yxå±€ñèú$µ7¤Óg €{\q(€ÍÁº#©Úgå7e–`ðúˆØ%VßÛAé&ùÆ 4À™z“UµF ×ìß¡É?OtÿeXØJð7l8q«<“$m+NžÎ>IÒ°S,4 &1GóˆÐŠc•í/gøÎMñcCü˜é¬‰ñNöP0‹ p˜D’ŒK†Ü ^ZêÛ&škvVBf[¢?ÀúŒ[üfµL ÂEÃëEÌtzIñØÌq¹rí2˜MÈ%×Ðýñ ÔQ,ê ùwÑ™¡óó£”;=ØæßäïþÔxÑŽwWÉ*¥¼ˆ-ô•¥öôÓä£u6¼3#œ#ÇÖnܘq0ЕFGÑæM?L¼!ÞyëRÔÜ–jfŹ·±6sAF8\օŃåÙö'EÑ•†çàÞJ*:-:¢O€èyâ^ຠ#mØéq ‡èÌ!…¯å¨)'é2h9s}D³Oq#XÖ†m>@}d´-çj¤½Ýº¬! ¹Œ ¹}ÍøNëN z¯¶¯ræ*ŹUKYu ë·/Ù(rÑúö·Ö—|àg3¸HDS g8ÊŸqT§"2FÙ… A,®Ì02ë`]mG¼±ý®Äžëô ±çëuô9Ì0Ûh÷$Ÿ£vTõôšÕÆÃ¹ ±`\&†^M0[Ø@bM$¾Íe2Ósý˜m_!Zn#J6Aùç›Ý[µ@¯¶0®0rÐm· C,{r@Cµq[s=àPþìš½—¬’³ê%¶7KGÎ3ã=â:§q(!é€0åÚ–Y‡üÕ¸¥šDÛ#Þá§£@®ä@]¢ E1õaáäE­Kô_>šN²ˆ¡°çf=®c(ug™t õmˆC4F‚ƒÈItèI¬8NÏaèDº„ãêN¯×#ýáSÿˆ¥9°ñW ÔüÁF‘ŸÚ‡mï`o?{{}ÿsg§×»³ó‡~¿¿ßßÝíÝÙßÿCo§·Ó?øCÐûäÙmð·¨Á.//; ©*·îýoôïÁ·‹‹Å-Ãß~2> ¼eo¿úÝý»ûÝîîN`–éÞvog{g?ØéövwïçÉ0 N>,‚ÛááE;Þd>‰ÏW1XB2\`p˜¥Q8Iñö }4ßMÒwà? t8BvécÞRTi˜ãöQ9³Óâ¹aÍÿvò ÒñÀn=èö{è¹)VÆÀñ¿|bøÊ™9çãa<¥ ,ªúãW¯_?X¹f‰ByƒV+M’Õ|l‡Ò‹·—Ñö!…Á+¶’-˜Æ#”šÍ¹ÍÉY&ÂŽBvÂI ¯XKhCŠÏ٠ۈç௠Z‹óÔôM9t’w²|ÆsŽ1ejÏÂyxîUy“jsD*]€ÿ4Ÿm L O¬×þ˜”Œ© ¬¸‘äÑÔ„x ;/‚–އnädî4#¦zÔ€‰1%¡X<£ºÁ±á¥fC Ó9fð᱇„yˆÑ‹ôRØR˜=¦_SAmýév1^ûƒm³È÷skß­_|YËÃ5-¬¦G¦17#nܰ¸¨ &þe¥é¿0pm0y /¡ñÍʃpgVðžtÇÃÆ,Ï¥iš} záxçn8&ëjIhÈðÔ8¼8nv³Õ¶.áû0žÚ˜DãärŽ~>yõÃ_ˆ%ëX¸=¶áòíÜ­2Ár¥fäÏ«£ú›“+×>±ùÅÈü¾ ÓuU ?JäfÈA»­qDŸ0'QÎ!öê ®(»'þ0õ‰2MeÕºÕ UáDÕE½akjiõ’J oÙªVJ&¡ŠÌïËÖ‰ —/¿Ó«¤Š×,’TÜt M†ÁÏÍ¥ôŽuÞ ñÎ4$¤6…£[1uÀ•ŒÂïûÛÜ©%GSÊä>gè¸*¸£3”&,cR±º~! °¬mð?šYàà I klZ!òH{J‹Ü{˜«ðÃ_‡<žÈómˬ¹uug ŠØ[¹ƒL:¸Øi4…°‡c¼"£eEš9(ìI“¹Á™¢FªClfïu ~«UØþ1èqúøFÆ 欈Í錉ä9Î=úþaø<%eÐ.«ÎcÒ6­r,ñ9ÞuÚ,$pÕD¬ëC^š~€}þœ ³<€ùÅ5‡!œFg/ ÒlÀv6^bØü],–öNÀb¤^EïÂ¥&c¹T7&ËÝw•€ÉîÐÎh¡.o“ª hÓ1p1 „¯ÁëWOENÈ—…±v`ÍG¸ÁÑ †Dè¤V“j"ÉÏ×W8Áͨ'ˆ¾–qÇð>!È§Šªˆ@ÞM&}ÞÛÒØ*w4–HÒÂ+°UVÑe°’]e[‚ñ˰²†-Á€Tõ˜ê«ë‚ŠZ=Ø6le=ÇúéSPïTó½ùí¨]²É YŠXK&O1Í¢¤¹ÜÏ‹iV4ãrn¢?ESà[Ää!—qɨðÙ ~„›@¸Á‚C†Ã|AóR¡£Õç¤-/¯˜¬^¡â9]À™ÝÂ}ŸâˆüQ"A%ÆÏqêõ£Ð|OØzj¤ÂÑ’yÃRîÌa@Œ ‹h$Z%¹ßªÝà,±T4LäøY̳¤©Œ¦1dU‚ÛK[¡…ÔcïAX+¯9žŸ¦=ÁÜÙ)4Gw˜Ò1+4(`-`$UPJå$µ—u0èçÉ’ïmT3…½woÈ›0Ë‹Nå+ÕûøÜz„Ž®ÐdE1Ùm‹o—qvwÓt׊w¼ÉœùéeÐDކ@Ùæè&‰w¢Ï-å…"¯ŽtÚÈ ®{c6zó]í¡±#}%=³÷Öb¶™¬În¿ .x2ŽZM(l;.X |½1X$‹–«¿u¿z×ÒÉ©.$÷@»m°º#3Ž£oà’Ûø[Ðî'ˆxíÈ‹¡ ÜŒ‹FaÑŸs8!S9¥x7øîŠð*5^E±!‘½™µön~t‘$eXf®ÙáéÇG¬'ÓlÏHF£0ÀNqà6¶ÉÕ‰cv=íɵ–’¹*5´µr•˜R•®.ƒÙ˜1“-3?Ãf×^Ôi¯çS½ô#÷0U›¯ HQÝ­'á¢&¨£áÏDÍÁ}§«óXÄ Ô޵@…éÁ´"±+9ÀD™/ðLáA4;¢2ãÛæ;™çH©8Œ¦t‚~RåäqÄTÛЖ%¸/`³†JWÊš¤6º¹;¬ÔqƵå¢%+¡i‚ÈHP+¸ …°K)¦\kÛÙ‰ÍLœâ Ï.Òd¹¶EOŒ¢Qês¡6&Ù¥¿w‡éF À!>½)9\e¶-w´\*ºŒ3"ûîTaûg)_„TwKbmI“ÛtKëCFö#’ËJ̹CÊÏ?r§ôÄ$R#§¢æTVEÈŠA}èP=PSq ¾%z6Þ4{0LÚCëp:þÑÄó¨â ÕD ½víÑKéË\ÎQ\p7Oºnî,.#—‡ '“k(Ñ®HÜÓ[B¼8@QÛÂÀ@.äÔD]óDƒå~Öm×]Éé[:—¿óIéÌ‘+-ãEaãÏÏ9±^ˆ ôx„Æ×.ƒ ¿Ø–/nåZ^Õé_??Kì‹ÂùQÍ!1ED݇‡¬›0IVs¬¹$¥}¯f“n¦¾6£d“½ÎÙø©öœ l1Púc~²E¤SÃÇ£‡š` M‡›¨ª¡½Bnö<ÆzZ‰æ“ÏTpZ2ìǃà ]+lp¢õÓ¶eçíì(Â2zÔW¤N¼÷ñqOÓ³R€}~™€Q(*EéÜäc ³À•žhv ‹„Ò – +¦sw¼¶ÀîÅ”j3¥«Áa–LWa bUj5ŒÁ…4'è óAò©'é¡@ˆ ôíëË‹rƒP74C,ÙRFÉêu¸¶È6]Ö²'Ç#wݦLH‰Ø³‘•Wd@Ú6óµ£!óÅj85òÇYÄI4bU VáœRV£ˆÚ ž‰®SÚÀƒ"ÏÏ­"´Í$.YR2â¹>ŠR¸•!a„!°Ü5"Õœ¤ºèC·Òm*´BEã1@f¦¿C[çi‚rª®!Ý=Ò}›¾0 +Ô Õ—rxy™8Ë^nåPÒðЭÌ{ ÄpÊyÞã}Q ÑÚ׿Áq§2+ûL)ðÊ4S½(Qá;²°aðŒ®‰Â¹½Ï5" ©TAÃ5%êÃ|u„wKp-Ñ “¯JÚ¼jè–=Ô ä1#oªWi'$µ³¾pƤU)22¾âºÒTâdÌÍ·™•$‘œU’/ìé:cô³ðÙhË+R”\o.âD GÈ^ÍÁy§=Ìç¤xPŸQ{tÈ!ƒÁˆ¥¹ýäHïO)ªOY¸³Ã­¤Xëο]*ܤÂ:zµ[8oJÒ“ñúObLc ¹­p».LKA]fJZFŽ–iË#L1f°œ1IªchÂ|)Z¶…)[0‹¦ AÙ#C¥À´"¦S'˜öÝÑ[E™`á²"=­XS4v'Û¡!8¾ZK¢P ã=æI¶áó[ÞönœÂþv›|´ÐgQ8k@8:M Å•W§±ecàj$ÈÝóTñ> «ëu|.¢`bØë÷±!æšlbºENZ ³ºŒ€ïÉJšcæ7Ëð^®dAÄÄÊÌ"…¤a~¢îÉ '>JWtùfK>æ•Blw{´ó…m†æU(N9²™i`5ËÄ x³6Ù*¢Y·ám²Ê¨¶ÂÒ õU¦Vü²Ýr0‹Òó¨Åž=€êÉ\ IÀõiê†D.²¤¨éù M˜¼¸(R#8Ú\$ΘJÆ—ˆ# ¹é§DÕýgÿ‰žµpðÅ{8YáKõ»s@›uÓNuê¿OéŸàÛ´g§øÉ}b;×êô3õ9GÊ ûÖÅ? ÅxW%Ào0ô°€0fŸuÂÄ93ŠM»g;ÈI)×=eHö«VLжUQLzWL¬ÝO‹F5M®(¯Akžœûª—ð+a‹|@¢ñ¥¹ ¯\3Ölí„Ŷ´jÒî=N|{Û°Í‹`jŠ)ÚÏ H.oˆ¼(G³¯!-|B‘©š cÁ¿¦ âC>«4n¹ðOŒÜ¸Ì\³Ùj8‹—^Ã1Ñl_ctì(ÁD}_Ó=PÙ·©xÇ@²=xéÓ¥EV¬äé§áÔæ€„á…d‡ qR_lœèx£Ò6Ùh¸_ŠP6…óZ¸³Áy˜aÌÅ·àzd÷ºš#8i!þf‚6ûDfÿz~(d þd0¨¿YG]nÃ1f˜ÓåÓ‡vã¾H¢rûµ8†’ö¹éBC[yð‡F^Óü(™fjŠ“îF€òÓ¶eŽã$»ñ<¹z±É5-ò¥BY@ÑÍÀÝÚÝxª Üm+Nª–õµ¦§Âníßhft”mºh Æ FŠ›ïAD¶n !b2N¯W¾¦½ŠÎùÑ@å‹­\õÜxq±2.+ŸÕŒ±%7û\Eí ¯wäÌ6&Fö þÂEÛ¼ê| ¾nÎÁ«ÙÔý^àÝûõç]Kê­ºQ]v¦ïV ¯ð"&ñ-N}5q|°Ûtäc‘!iÓpªEùGê´?}X&ïj¡èyãB• ¸Bàä«8BzGÞÆÈì¿a–}›¸N7âç—±Üå6¿‡‹ñó`¶¿Ivïš{ูr’É»Àgp7¤<;yþzðèøéÓïŽý2þ÷ÕPÉè°fŒÇ–‹Îu\*sÔqö[ÕP†FÌR’-W`²%ïñ£5ÒSqŠÛèÇéQ×ÂTQ ÓP³žPÈÍzãýTU/Ýf>¼êÀUÝÌ¿»Â[¬õ“®X¡OñZa8“Ç'ß¿~z6xúÂ@gpv|ZØên½~ö’`³Ewš€ÿÐüýyû[d§r:¤vÐ]$Ý…bèn_iå±hãñtËr/Õ(&Yl+4§ÑdY²¡;†—Ø è¨M!EÐD={¼C÷”ݜ҈Ü[1ØÒÏ`.€EHÍV€¾5ø«ÿi‰²¤ü†*cä®Qâ¹Ä×<ÝféZ¤Ä†cíZÈ<rÃðåÖ¡°·áÎm-<±”q%(•ÚÈOͱOw“(š^¿~¬®BÐí9±£"}[tOµqªq‰{´ b¯·¦!%€å;šóˆï]tÉRHz+!÷6bË»ÉJÔ*:¥²¸©Á\Ï×XBP?âuÏaùîƒõšÕ¤úÕ»ƒ,ñ•[…Ú$« ,4Rqù$Ç Ìþìþë¤o¶ÚZŸýé†äÇÙsçD÷œŸbäïÊ]b+|?”ë°?y´Ù¸×K¬µê—ØJu\·!rÇa¶.ÃañT.wË`“ÿüà{|†UºuL!—t/7o2R®ëßP\ä·ö–êºKÝöºu·]õìk…4ÛøŸÊ4óuʆÇãë.,œíÖª¦Üa×,>·P¹™ÙÁeþkœNâ,WbåÜÀëH&„]Q«÷Œt ø¨,Ĩ\-=3>♤ùù•óñ lsPÖ2ê?±U}ˆn§«yã#×aíjŽAš×£˜im Kþ’wTŸcöK«NÍIgÖÍÚøL7ûgíÕ*¦†Y‹Õÿü"7NóÈŸCÆÌ‚!dqaÚTðUÕ“Åòetòúçdž¯ °vËx&Æ·AnA‡£ Bc$”pù@Ù8Tj߃£Ô¾¤¥­mxD !“×ëV‚uµÄ †‰í¿ÿíÙÅ@/?×¥2/›^s#ïl3Œe•[ ½'å×$5gxI} ã;Ax.Ó4*s—ïsyÛÊÛ ÀéS’Óüoõ¶0XŽÂ\[þä åé 8C”ªŽ‰Qxð°/mޱEx´C ï-FØ!k(I†4ZeË„—’3}êGÁzˆS-f· ñßȬ¶âQaÚ­¦þÛàl…„Œf»£ ]Ò%šŸ6;:S°>ЮÚ´‡îÖM{•¸¸e߬EÞ›Ÿ¹½ð]%£\‹à€’„àPè8gfêb°M1 .ÇC¥õ¶B5ªÊÓEBëèÖnZµƒ?Þ†‡æçÈHÑçIzeð MÛ0<”GD¤ø!šÏ~ˆD²…4­¹”{ÓÔaaW…‹iÙ`æ .Ù€‚"©Ù°]­¡º—¼ ã 2×âìx Í·[Á·ÿ$8d»âôiªþ†±džˆ^´¯¢sÝÆ‡fvBZá7Øbµ\Ôj†·?ð°øÚ¹Ø[·Â¶~mÏm3°§˜=ÈË‚TRqžúyÞ1Ñc|•uóaóBWúLPÓnѧÖÐêi4·+h»×‹èÆt˜£r¨ ’Fm¹vÐózå ìVГ/G¸`û(6H¢EÌC[®<Ƭ¤²3Œn»:¿HV)ÏÍbt/,Ün] ›ÿ?„Y€5Ú0J~ŽžüÍ#LÅrTLÎ.fÄœYª~‰ŒéR7•Ójúv²€ˆ‘híhˆˆd,î1}ñˆ‰MØ—,üt}XÛÆ¡$¢7½2|³i9Ì’Â}zˆ¥¶A³ßSh g5½4¬ò…Üv]EÌ6„õ¾{úâÑ ž¿0ŒÝ£‹{E–ƒÆ«cš#Ø™>Á×®ÊB ¾ˆIÙ(í2Çõwàe 1+SØ€fã&é§î¾ïÂ1&—‚¦Öì¿Ü~¢coõT¿ B?¾3„J•;Kœámaa¡a@øc+ß–}»Š¼—ç¦%yù|ßÊo’2С×úg¶tsÀau3»½ýýµ£RByfdÃj*ßý°Û—ÇÏÌöZQŽ›þîþ‡½{8Î1*Ož|¶fá{‡¨~ú÷ÒÅgÌhi›¯©É³çŠ´(¶^!¢-Z'Xjàb:™ÅÙLý¯£†7ëÔWÌ­‘©Ð]ÌÏ]WÜçŽègáh€¶ÝG©Ôœ.?AH—t¹ŠÚ•Âé•Dºjë—“š<é)ah8L …!ÒžÌ òO2waœS3cD’Báw€ù„­ÿ'ÇXµ§Vùy×7¶°9 1½ÄäÀq}Åì”}ÓœMã±A Ïï#øóCÈK>‰@6§Úæç?WQzÕjœž<=yt@½6x€Òæ÷¯^< þÃq–}4%‚Ÿ~åÓvçúÌâ0c®QR:r̲6hkáÉ?†“E]dÕeO&zMÈ)­â cÖçÜ9gb²BC¸€åYfìú€æ-¦µ-™êƒ#ò:(Ô[Ô$lRî« ”‡rdhÊLß‹ÇÅ£¯ŸŸµþ´Å”Žfñ‘©”(Ï€ùÙ`€[Õ`ZcwROxU¨Û µåvŒ>ù_!â@¾gÑHJp dM“ሑÐQþÈW{™N~/5ëV¤u¿¢bmUÒÍã3®lº§jº2í#®Å»¶¬/Ú\.$ÌGŠ^ÐØS,ééÁ’’ˆª.y 6Ó¬¤§¯ºéðNÔð‡#Ë@?äù¸²ÎÉ:ÀJ±‚뫨à´rÝ Ïý¾AB£tÁB_?:íjéZRc+8 ú®)¦Kò’è+ó 7²ðw=ÕU‰¯r^¬òu/z 7Uga¯¸>úv§¦ÚIHüÍ­‡,',(4Ì)ôYÑw½m(¹a¯—”9Àó´Y˜9±Gx“S±qŽ Î\a­zø†"cçØ©&p £wÑ*ø£ür…¦Êƒ y¦Óp>n‚­Ù uu;{ÓdæÙE"š›ûî5ZèÝ•ÌÔ@#D‹[ÎuÀ8ÿÆ•+>ÙnÿQ6È [¹ï5¡dN½WJ&ÊâIu'CÎamÕÌ›eý³ÃǪUп¾ÁeD \îe•®,pSß2ÉAÉê…oÜÞP븪Wh4 9†£)ƒ‘ë¶Ìøñž+Ð/5&ùdãÃÝ·þ”† TÓÚº¿Y›y¦TuÄ Ã¶=‚¤¦ïÇâÇ);<~òÊðò/^ý½ä˃4 *oßôÞz–.wßg¤Íʼ¹ä~‡M !Gz'­=ø©°Ûë-1k\ÆP€{\¨¯gkÀ†t«×®–+ϲR £1)¼ˆsXëÔw›Z´2Þɇe Ñe~4D%©Ú­Pn±à$t°ÍŽ¢¤G"8µmFGóÄÌm8ã!‹Y4^+fᥲ•²p Z‘]iEN‚Zׂ&˜ >£q:oðƒcÀ ÁEœÙº%%”rƒ'Óñ@¦ DŠžÊ“ûFÇ \"ò †*"²jžE«9ËÆøïÕ¯;GÐpŽª,Æþ5_¡?ó$UT/bW!ùg„m!L#²wjeö6º&ÙŒœ‹e9pxMÎЭ.CxødXЇÕSóͰÊãh¦VÐàÀtdÀˆ²\¡„ÎŽ!ÝÛ‹(Þ_þHßí»I’,åÝ÷ôÞ‰a[Á²×šÀRÀ² Q©%Úd 1ÆPV]†ï㑵¬ ðæ#‹õƒirž¸_¨ u¿Àþ¨¼á, ÓÑ…ú¾Þî÷"5¼¥9µP󫫙ьó/\b˜+ƒQ´,›©Ÿ¡† £iÌ–ß‚Ð7ÇGÝŸ²bs¼)^Öˆ=#'T}üêõË㧃gOž?yöúÙàå/ÙòN1FŽDÉrf’m0¤»dé¥õ­Û²)0¯f®™ ¥ôR»AÌ{gÃv Æ|@þu:*»À*§Ij?ÝŽQi%]ˆyû†gBõYs[ô„Ì`RËîäxlN޳“Ú#€*6r1Á*U"šž²^$¹œG©¦åú¹â™;v£{òüôäÕYðäùÙ 7ºnX¹V÷rÒ¹ó¯xæ a€k¶ÅVð·ã§¯ONƒní êßoÆòßVÃ"Öö'©SR¶tì²- tWÁЇh޾ r†š‡`«ÿwÆ{6T8.€Þ,?FSôQÜÓÀQJ»8•~=iS•`gùÉ’eÉ(&;M{Ê0h߇“V½`‚ñH¦q$´v޵||+¢ Y<=O<ËÚœ:¯ŽÅ»>§ýóVó8ñÛMYšLD ¯1„¨ñG]£TD5»Í•¬Ð}Ûá+Î\)˜­†; OY‰î.á8P¤“ÿ… ³Zi)ÜONyiµ!Nâ¦i8Œâ{ Qiåqx .^dZV·€‚Þ'ïøÍj×M+át Ö“€–ç±çÈ,¡BÔªÀýÙ5g^J¶FDXæí5…5˜2@lN@Qȉ}(vÚTã°ÛÑ›wî¡S–è˹bµœ†ÉÓýº•$õ¯©å+KPÜo›°(ß®â­"į­"MzѾÆÊÝf—Fí˜Ñ‚ ж“cpý愌ßγá%e)}Cy680R®ª§F@h}b˜ü™ˆ¥)íÄ7ü%¯°¬šK¾ZQȨ]±úšª †€{nStåe q[â¶•gV‚@ýQÏáÓcê^Dã®’#0EâáÃYó‘o‘®Ì¢q’JнÓv ê~¡ªû[â8ßP?oߨJo¯ý®V5Æm0á‡ec»_º,Ä+¯])wÝu`VœÖ€~ù”‡ ¼á/ׂÖÈÓ©5Ãxh»¼_ Ñz¯È:Z[yñ°¶ôieõ]…w‡V«—‰ÿ2jš™G¨bƒ%c;À4y¢—Žðäç ù³Vrj@"áI‡«¡lüýäø>áÕ¹‡_‘Ø`*óñÓ… °æ}½¶¶†°oTã0Mgt<7‘z6q>B”ѤM• Öx{²TÍb£s¥¤2½,R¶Â)z³Ã˜<ǧ[é£T(ÁR¾×H°-œL˜ãVxḩ.G’G—¹x~ad,Ô…ËAÉÉìUgaÏ2r¦Ó8*¨ÌDŸË‚C^sV¦R°• ¤œXkÝ w// ’Îâ2ÂIâ½fv®×万”@Þò)dmRlHO1È ~4OÁÖÈ´·à!iMŒM|p’ªÈXÍáêÛ0ÊKCY0øU‚»NÞ£)\nƒµlH— ÜD¹V¤–¨´ÕÝ Ç§Š@­åªÅµ4á ÷Ž.š¾½U¢uÐ{ÄnsÆR¹Ú_¸'…vãeM'(ÄÓ1Ý1³?¾—×Ñ™RÙ€LêÞ“‹ ­eîè³`+›Ca²QK«yì$W\»xR[¯ 5®k´à<28eð/Ææœb=Ãs΢ìcE¤aM(€8]¸½ÇºfÚÈ¡º7”V‹{yPº9CW£Z[.½±p‰Wm·é¡Ä E•Ö$—o ªƒÊ‚©…¨ˆÓŒ‚f™ZóèÒ™?±V— +o ½s”ð ø¸Ê/a™¦²™/`Ã=Pý ü'À‚gwjvÌj¦²|8Y2ÁÖŽ€®éÉÇ,‹0Ñ9‡Ä/ªÂ‚Qã×Ç¡r7÷R;R…¨#“b9  .+™xO §?¾Â¡ehh.Æ»_ÕíôkÏ2æ9ªb=3¹à¦Ö3LÊWã¹-Zu‹ý§†î”•ËiZýµnr–©NØ•­©Ã™ö3f2)cŒªÄ&+”vv;¢²è:ÁÐóÛ\1ÚrÒ“Ï*îR¶-Ò¼µ˜.öLT®OȨÍjïã,ÆÓxiÎ#Ì‘Õ(¦¾iAͺ[¹Yq¿Jn\´ÔÂ0ĉmû„2¿Lv/$B‘{"–MíHÝ7=ý”™©4eýD&ï•BGÕ*Ûp¿ èBYÜÑèDŒ¨9ômŒ:$Ò,i2GTš¬XŽŒ¶³¨`5 £uò+ØÊ[ÕÜè䬊lö`kèÂ6êþÙy&“-_N½á‘Ÿ•d~Æ€@×PJd_n§²Ü;{70¯„ð¨ùè'ˆ§Ð¡ÑuÛaP‡ÄÚcPó·|î}ðòÅéÚ¶à*À¥,oÙ-IæÕ n-Σ_[3 õjdŽ`‡|ˆ†Ñ(„h°¼Ô*FUhâ÷¦eÒÅžOÀˆ…”‰ Kš Jlœ]Y¥™·ÙÒœÈÉ#Æ.£2[½öpxBm/C#'€=q¢Ö5›4Û FêlL&ìÜo3¥·¡•p<¶Ö_pK23™7šU Òçl\ë„CžôbTê’,ØÆ¸ú53n·ørÅG†‡·—WbÞ‡B!ðö•ÉÊVºÀ0‚W¾Ç§ì´W=àúêœÚº¾¦ÙÁžò&e•ªµÐÓVáaÅ^tç¦e[ÌÑR N:=µ‰ñÂ!p‡h—V|oyM´8®(¦_—> 'µç Íú*ªOk€¡šÈ”¦f%ŠƒÔ&•F—d£ý†€ÞX2£ yóÞ¶¹VoÄA`TÍt`d‘–Ž÷“F„OÄ‹sœ¢]o±Ó蟫8µ¬ÌLÊ t¹ÖíÎtçw$Z¦Pù–Ù¾ KÞ;Ì2ÍØ{'B'ΩS£+Wéèe|yQw tH 1èú5¸˜„º¹µ¡JÐf h´ Wòšdˆ5·'W8Á,,šª£«L9ví¤nko…èMòÅÁàFÖQ-ìÁ”¬hÁ[‘žaŸ_Y/W„…óUÉù¹Ùn8´O@çP¯ Ë* 1ÖW ÂJQî ÔË…(• P£÷- iµ¢-ùÆý¶`E¥Þ›aº[Š\=¡6|¦”6}¿ŒÇ›«\Áà¾X-`¬p65Â&f?‹j‡ÔúJB{̧„%è+¸Êç!9–‚cræ&Õc4-áK5–Í(Bët†4ž[ :±‚–œ·é6h· ê^ÓëX±,ÈÕàÉK¬I”ºài8^Тù˸íÚÍV覱àQ?Éb‹Lèï†â8òspTc;þéÊ,Àv‹XKJh‹QòBdÀ©ÃJe®åy¡( ŒÇ1Göƒ¢™Y¶ù`Hg„GBX#  x×¼‘:3ç¶ ç€Õj_ƒÕÀ L%;°tÓ1lxÌ ÷Z’„ËAžÞˆ-µ%¢-´¦:6wŽŠµ·p‹V½-D†,iŠ7³7hc$ÊñÒp™e‡WÞm± iëÝìÐS:(}¶½ä«¾#†~¤Ö¸úQÃÞÖâÎü+`Ž( ËMe9ŽôÃÊÐÎ XX )ÃX¬:)»MV¡»²ò,:4Vð[‹Ž%á°‚òˆXÁ“çÏO^]7– ……ѧðÑÓ'ÿuÂÁ¤·¿ñ"`= zå±Éèi—2H%½áߎ‚†Ü~QB©œÙçõ‚dm&‹eèª8Y6;—PÉEFrÊÑBU!Ÿ÷f€!M l ›ð ‹8r† ›åZ“·hdÏ@˜ÀY'îõF±ø¬Æñ¦Ó‹ç½PcT${û¦- »l[¿²\€wäó„&”mìEÑv²áø2’619†…ŠA‹å2Æ HVTÓ…×N…gU¥J™ˆ-l¡š™µœ&Óíù7ø>§ÔàòŠ©0Y%Køç?dË«0#µU†*ê°R}o p‚ÌN×$™„§cC SˆºvA“i’P>6Ê3@žÞª4š &)¨Ökœ´©/¹›ÇT8FdFž :À€èB.›žË¾·wÔ[xidãàAðÍØ <0ív‚݃^OR$èæõ¨«;ÁRë;¹{°×Ãnn±¯!‡Kósn1ÿ:bž<{9@gþãN*|Λ¹Ûzl\ÆÈÎkIÐ]ÖcÆÆOÏŽÏ^Ÿbo/^C¤;•ºÝÔ½àÙB¶ßžÄ#& TXCÉ\¤·­E´ŸKƒïq+s š’ÄXz6ˆ›«™+,ÿ89oaÎ ›Ì¼¤QY”,­ŠÄ[ë ñ ´Õ0"Z6‡é0¤0ÃÍÜ•mФú$åø#ñ/é¯Üœþ­Ú(?&f´‰ÒÝØ]^Ž ó¨“Qð"½Í¡ŸÉžÆýäKû›ÒƒØ·”'q½OÒ!<Àç,´fQzµ<ÒŒ÷ÍÉt•] °"8BlÈ]fy-¢W,|u‘´ý+ ÖP™û9ÝiE䓤*ņ*PåÁ/üIÑß=eçø|ü°tUúœÞPt,¹ÿ ì@¡¡^éÀa.ܱòLß$á Pµ³öŠÔÏ[®¦¸N ”Ô§sæ–0ó}l s»¢‰Â8b[:´ÍTPˆ†Ö„y–øåsœ€pk—{Ê ‘ÖM(“òÕHFDÀ‹×ÆQ >¡œÊõª·1úAìGŽ[†’y2»Òmm2„­\(¹»Ÿ˜c»z)KÓ˜Ãó>ªhô5kþûÂ}•­Ûy’ä5VìUD· °³^¿zúûªm²j ú<‰Å¤U"\wK½TØqϟ°5físU<[z9˜…s¸ú›º”·¹¸\Þ¥b‘'ÙÕ|taÎ §À·tm°2W-¨§¹òbj œˆ…”iîoÆïAå&Óµ™–žœZÅöz(Ú`K{+øä“JwãØ^*øZ×n³ÛíÚ(ð¯gÄ’ö×¾œEF>¹Ì‰ëè…>AƒØ}Ì—%ìtÁF74 ñu áì¬ëR<€@; †+ÅïñÓ2Šß,Ûý˜ 6`oç‰Ki—󳪚¼r5ÇÞ«ÒJ ð-´úÂæ­kn¡íð’É4[„Ih§ÉÛ ¼nÿ × yÁHD;À RÀ§¦ U¬Ù%1 PÌïƒÌÌe¿ç‰<| ´^èÅ~S [˜:µG6 –„T–Òªþµ…6|Kz—{ÅL¬‘ËWË Ú¶…¶mKá´7éÕÚÊ.©DiDL­Öwµ¬…2®d`“FàOƒ'ÄáïÛØ-¾‘(–ÒÆþZæ†åóÈ·kƒO²ÓÛ®Á»Äò˜‰®rk”ôA‡ÌÊÞÏ7ÁóA¬Að±CÍC‘CgecÊ¥U¶Á8ü3Cd5¡ˆE—!jÑ¿î˜À]‡½<“;g9gÊÓi(ƒé’!øfÓµæd¸¹9µŽ\è™TßG!~Å !m ‰âM„wF©sÙ¿»ø@2Å%yª! ­ÛÅcT\8隊\ý Y<«£Nç"N?ƒøõä[”;’ÂÚðb׺ä*%—€.?«?¹¯«›—¨,îª .W«ÕÖ+ IW>¨:³øâøø²’_xöë û"üf!ðfY^ƒRÙ4ÃAõÖª4²®KMÀ+ãe1”b)K t[ºöTm~}/yLŽu&@út'gæ:q œi4õSQ00%Ôo(Æ¥AáõɧÎæKM# nœI]ëš$Öc?E䆫ÛF¤߱ÿ{¦ieHÄi57O.ç^„ÙÌ7QÖrÍN’–ñõ–g‡Hpö÷Ú8¬ŠúÚ•pÜ݈©omÙ2÷7Ò ˜÷ÁçýׂPóÉc¶Þk"s b¬_³[ –€-3¢H°Ô”øh”ð‰^Mn­Í9: –©ÁmÌIƒ MØÊŸFª-r„Ú2†¹¡òü¡~cÍW@$oUì•2vé˗鈖q–A-EA¨”Õ,Jã‘,Ë82Ç_$™rJ´‡JŽ:¾GA HPÙ_%nWÁ[ÌœæÔ³ÅñÊ!ª¤o»°§I8 ZB4VQØF§†¬»BL°¸V€ÊK,>Ñ(ÄÇÑü²>×”œM@\ÈñýzÌyi5<&Tyeãl‘;rÇ,v™}ÒÊ‘A"ˆ²œ[:—u\¹b‡¹†ãƒˆÍmtM–täâg×€ÙY3#x]~[­„eo¢ {ßð´Ôátâo7ƒ}y+^±5«QÞ½w;Ð3)* £‚{R’…KÙ¯ÇEÙ¸4˜| ¤Ö,ü0æç|ÔÜÙßoVq; •@r'³'¼„6Ö–:Ç Rhx¯h1Yk,ÁX ŽMB¢X ÀL£íEkS–leÎàÙYŸƒ(Ç&C*Yi§ß³|_<à¡ùP!V·é µnó[}Á$¦ª>¥Ó-3sXR±À´HE~¯ÙòL¦OÆëº‹½b?T×¶l¨&ÓcNSö!âlÂoÄJ:M6@þü¤Õv¼àN–×lT7?àxÜÖB}¡u§ô¼Dšý3ÿÙXx`éJ³¿{KRåTqõc檒Ÿ¸&g_¶ j¼'Õ•êòh’V‹zÆß¡(h,l‡MƸAWLt⹋³Ü7H§Ö€(Lã'e“É˂ҧCt­;êg()/±Ã>5A³^ÂoÖÓ"ft{¶* æ‘ÀWØ'´"±ìA¾·*P3WVï‹©IBû­O:ÄXü–ºx0[ËáCuj9Ÿ Ê¬Ö–÷ÏLbî”_c‰ã$SGˆÛEŽ’ÊH{MÞº‰4Lb¹D¦RªŸ Ì*0–¾'ÖF‘ @ÏZP´Uo U¡TÜí (xñ\¸Î!†zß¼v¤Ä9ë³ÞeIVñúüV™Ü¨{ÐRõºùú´ƒA©Ä7ÄxlµàÊ âVî’°‚¢ñ„ÊÈÖJ²e‡p}|åÖ„â ‰”G¯ëI` ‚TAÚ*6à‚bÔô­£ëZvú]»ç9WJƒc˜ÍxÞ*]/¼¤±¶Zx“Ûêc‡fÌ-^û- ñر'VTcÕÐ!­Õ*°Îk×ñ+ŸJHj±ÁQe’..Ây!8#=¦ÀM¾ò[Þlr!-èÄ  "’8Ç‘9]ËXˆ±l[çàÞÕÍ Ê­p·QzÛüV©`ÃM¹Ä°›,àX;CÃTâ½®(œ_Il.åûP½ßRìLÄ÷öHTwñ¾v§FëôH‚$[÷ éQ%äS~‰=%뀭Žr|ÊæØó2¥bÁ4¨F©X,[¦TÄÌ48×c/‚‘U&¢ƒbµ_€³uCÍ_qœtñÈ\F’h™‹Ö€[Ž==·® ›|/brȳþP´Y±(qýÓir tK\ó²ÃàÈ9 ¤5ßSÃ_)‰U:•¯ä–õ ûr}³ŒÌ•š/Ãd|Õ ž'”¸É6lx^(GÌíDɺ\TæUB¹¡^shT«4àSÙ &”µv”ÖKÝ»B³¤û”a1hén|bíò³—¼…ø'n׺ÈÃ?E,£ g¾! fã Açþ v I0ÂÌp$Žæƒò[Êž¹Å*{ ¦EQÎZj(h¼œ&0µ’ Ò>ÁK,[OÖ©`>øÒǧ¬¿ øãÙ³§6i)ªF|Œ Ë_­LíKí\F²dóØ[–±w/U¤U¸øIüd}ÈÝ£ƒÄp— ®ù^('ÆBÂÊÊzäÍÛÓ4Èz_€Ü= Y/ÙËà3ÊémÖoÃõ5ì>޾øl”ïíld—ñ’<<„Tƒ ±³DÀ2Öxø5Îf¹äº]"c¯nÕ&xü@ "¬Ù¤È´æ›«ŽkÌÂü"Ì2–KdÔÀýÇK*e˜Í1uÍ@š]¹Í;‚¡™ªÃÇ`ƒ©üÛ¦Šá…†Íè“!&fB ©Ú'xˆ)´Àã¶4¡»•B¶gž($¥s™ÎÑœÅòÜ©;”¶¯{2·— W€,?3ôÑøÅ:Hð3 u’[%ß¡sÍRê„JxáZÎÙ—<Šõ>N ..Æl£À^íÒ§ÌZvmNB>dà´F*X9x0Œ 0q&çW;œ­ÈOJasV ~"©ŒC>QHk‰¨TØ´¬Nœ°Àñ@«@fÝìyæðÀ~Û0q´°ÚÔÓ­?úú#šó¡·%´×9Z9€¶e=¸ÒuóGϽuŽ€öåÌÁëªÑÔÒB¼,›†óó0–<Fá1âø@Þ¸Öî—CÙYó‰? f$|Ò ¹ï³&ßc–±Õ*àso²`øðÍ3Xe•@¤eÝG‚¦üö¨h¶0ÛnæVëo{uˆÎJÓÜ)¬@$’×7š/'wÛŸ¥!K6Óë¹ôfN[rÓÎÖ:ã!¼*¼ðð…­üãm>ì˜X]ë0JÉ£{²¾º€¬?pâƒÏÓ8!çæGqï@‹KoE2+ÑxÈÈy>…Sñ 'þ¸÷¬o”³z¦ƒCM€±ZL@Þ'£pí!®’Ô¸§|êQ­ÎÑ{{詹ÿ9ñý D}qÓ·µeªP^V´eÕ‹\¡IRr)÷çPBÜõïæÇ ŠF¢k•ŽFU–1é:ïs÷ú·8-—¡¤À-Z.#¦„ÉÜK$L*=u¬åì|ã&þû V¯HõÝœEÌÆæ³…Í¢ +•F&Lë0K¦«¥ózÛÚʵdUø LòáIÖâ ÕÔ¨ªäôÜÉ÷ ABñX“$øÛ ÿë÷ð;o~!*™‡u™–©Û „tª@C%5œ Q¨Á¯´Òª‹ RŠlÇÇpãi£4þ1o€'@…+äšÁ©Qlm>Q.–³é`™ `(-!©¼ ÔÒóC.Óæ~ATµþnÓKT¯‡ÊÈcåŽsŽ–ZSuwcEUâ[tI\?v›Rý›W\­Á„5JϳÝÉÛVÚ.\‚ºµôÒÅl"NçÚõ243ÎêXÁ x“jý± jçIò!Æ~ñƒžÂ’¡aé·Þ¯BX²y2¿š%«Œ´YÇö§U…ßb)٠Ј÷T$tv̯;Xtœhm[FM€¸‚-Y˜b^b¶ÊHÀމ´K0m²JGU6<šÁ#Š.Wp(çïÊ‹œò"œf‰Ó`ÈÀÛ"ï?­Å°ü¤íïÆìbÙûSû¢ís"r’7â%7á&¯ÍO~"GyžþV¶€ŸW‘n)#uôõÞk¯ó†ãÔö3µÜg)ûIq~àJDq¢[¥¬hIa|¹U–Ë"Û–‹¥`YÕÒ›èÍyÐ+’2ÆëS´á6dFÿĤB¯_=­YéâqÔ0¡€ 7¿ßUa;*9@SÆ¿ö¦¸éöÎR,‘(áÙ¹á‘1w¡¡ ¼øFtíïìî±³—^®ÄÅr¹8ÜÞ¦Åè&éy÷:ü1‚Ãç BkùâÍXB½(×á©gÙ¹ !Žô–ýÕt]u?¢Í}ò0)ÔªC¨B&Á%sÎÞKùE¦†ÞNñÕá–´"3Ô"Û#BMSî!ÇCÆQŠYtíôûmpÛ0ÿÜëîÿ濻æ¿;æ¿ó<Û3ÿíâÛ]óßTh¦Šù×ü0Ïð¥)eþÝïâ?wÌ¿¦úü2M™MÃØôÕïá·>ü‡ßvà?¬Ô7Íõ÷Ühsñ39š rN“‰ÁBKóážøØ€" Þwï²7ø»ð \è2ÛB T«”Ǭãx¡à€+M“ù9˜iß?·ƒ¿àÇÃÃ/€bC/–: jã<Ób ý,lÉItáêò=E'… ¤c?ÌV[ÁqùãÙÙKL×bkM1x»EXÈ2‰ž"y/®1€HÛŒÒJé“à>4g+4VRÍ`Ör Ûz™¤ïEç*™•„6L#0¹Ã¸Ð2²ì„Ž$´Ö:MÙ{ñ˜­³°)ë¡0͵™~Tœ|IÀJ–A¶ YLj/á‚P½6^-Q8upˆTÜœÉÜ0¿‚É, Åæ‘Î5j 3£P\ ‚#…µÊœ› ¼s4ÆÉQ{û½^Ù›„éôS T¡È„_Q÷eÇ'ý¿ÇÝ„ð™\J˜j>·Yæðè1øÉBzù9õ !Á‚š !Î äm–¸¨$øóÚ‚d‘NãA-ÀÝ¥K‹?d‰Âߘl}z lSž…!7…óÙ¡hØÜ™QâUò¯ÐVã¿ÿý/ø#¤8Øf×ÎmB¥m4<î¤Ëiw”eŸÚGÏüìíágo¯ïözý?ô{wvwwû;ûæùN¯·ð‡ ÷9&¸îÏœÚa¸¼¼ì€µOU¹uï£Û n?Þ‚·ß†Í Ì2Ü1œÿöÎN°³{¸³w¸³œ'Ã08ù°n%½5Žßw©ê"4ìUÐÅk ™‹p<6ä÷0èw‚óßÞâ’q[)èFQºì`V¨Ô»Nãóùa0&(ÂÏÂôÆΙ‡üœA‰Ã OQÕ¹C¯œ<£‚Ò?ˆ&LïÒaéxÍë´‹Ê€œ)c=Oév··I'Xüàxš;‹$C{õÃàÞþ7Á~ïÝj†ð¶ÄZÅ©›’]à2;6lÄ踇Ž åËt)öŽ{Ò Eˆ§Í5<™&á²®áÒZÞ¸{Åuíï3àþÓ;âÿÖ_ý‡Û†Ë/‹FûZ.¦ÝÅÅâF}¬¡ÿý;= ÿ{†êìîú¿cHÏïôÿKü=øÖ¬ê-ˆ2§@Õ²ã°ÂÝí^{g/èÝ;ÜÛ9Üï«ÁòçÁpéUm9ñs±¯S™Úl¼§Ç’-Î0à´ÑHépbØtÇFZDO {…èt¸ 'ÍbéîH¤œ&³¯?‡7ÐÚpšÃ®TL›WØ€Å>¼~~tŰ~P0Ò†€ ׂ¬”•—TÉÛÆZg÷Ýon=øêñ‹Ggy¼|ýÝÓ'‚Fg{û§ÝGÛÛÏÿ­ŸûÝ^pºLãÑr{ûä9¤Ÿi0ÃoP¶{¹ ÿöÙ«íÐN*òWs*A­îx9n˜þ°›³é<{XÒ@ÿÞ½{T¯…Ávëa±Ç€ÇL™suެIÛ·G`ó’ã8­,hÞA™£[f Q8>2Ó|€zÑ#¯¼£ôa÷MñÛT çKÁûüsÌ’•¾A5«}E?ñÒîax–íŸ òÑÓÈpVÏ£hLïáûb¼N9€Öë9v5†Œf(ÌÌ|rbVÞ´<ئ†ÌšlÓ\ WÅÁù¼qÁ‹¾ q7pxÊ/?lFáõŒâNòSõ|šœ'Yîh¨3jÊmm l±0¸H£I~paF²1Ž,ÀÆý"FàýÑlÁæ•H£© yаCjènLGñì<ÈÒQOLIj"œ.k»Øö†½å¦ÍÇñ—Ù½ÁµJ'4ìZfú çÞЊ€²×çh™Ò}lÊt Lnšk!zm€=€@§þf±#¤½B4HFýâDKÀT ‚V°jqˆô† 'kFãF ƒ_u:ÁvnÝ‚NÇb¿.æv–¸U5)Ž$ìÏ'·¿:J;)CE‚¢´dÌ^·90{ÃåÐv¨v–ïnØxž t0ÕG£fbpVM+3çßÐ4e\»Ét5›ü®z²(ÉU.nZ¯M9¢ÙÁÑ™‰Aý¶“ýsEÿò š†’¡¼k61ÝŠ"L`ÏroD&-‰²éÍYBfUáiYŸ|o™A·Ü˜<º_ÞDnN™[ùú{[P™«å[×k•ëA-WyAo'á{¯”^%úU¿õPV\‡¢XèÚ8JâìZ$Åbë°´ ƒ‹[u’$KC,.Óp±(;”é}#Hñé­Ü|ûc/€Ž +œ¢EŒòO…ì|KÞÉàev^dÚñŃm`U¥1<äÑïRþ¯ä¯Bþ&>Iä÷þÖÈÿ½ƒ=ÔÿöwûæÃ<ïßÙßßù]þÿ¾ü¯–Eþ]«î;ýÃ^ÿpo¿ZäWÕ7–ò¡ŽÈñEùýžwø4= ¾K>×Ûåç|ÌÐþÑÝD$'[Å<7ã@éÒN>ûù¬yp±Sr¾Óñ¾st«äÈTGf£ì¼u|-|Éõ¯ØÿŸ¬óÓõû¿°g××ÿõïÜÙý]ÿ÷Eþüý_Ðùõû×Sú}&EßŠà ¢¦ÁjOãåU‘dXYùM]0Ƙ¬¡øÌæÜ¥¶éÇdZð>J¯(¨„\X¶É MSÂéex•ÙØ@f2Û– eÙ¡_ëÑé)ç¿”tbù/…jd—¤W4Xû+, ‚šv-QÙ¢îy—ÞdÛça:Å) ؼ ̧ÓXúгš­*óTЗoÝÒ ^gìB’œÃba¬ A 8fLy¡#IŸGãA<÷»üé CîˆÒ™fñù'¥ˆ×ƒ%µ!z£Ë3Œš5Êô-©½9ŒÙ…Óƒ)Í¢eûWÐCT‹‡A‹,ó¶òV!‰FJñaAFÇ:6r—]¦Éd~? b0©Š>,W!DõdƒPÂRùµA½i+.õ81Ÿ°‰£Ù×0 šÓeÚ»Ìfºœ6~N jP–QîvƒÐ™x\ÐV ØMPÜ8,ÉÙ“³§'Á2<×-ÏÂôE¤¤Ø'ǃ,âmä@pHCå¬ 7.“tÌ¿ÌbÓij$€XnÜ8i]ƒSøÄ¢Á<‚E Éô*žá­)ø7“ÞD¬¤5-±z¶Ð˜÷cµ¿†ïC.Eí!"rœ5dYZÝ °cAÞãüÔVûîÅã¿#ÙÂVw2 ¥‡Ø° # ´¯w Á±dµ Z3C[bC5a!´6Jú öB®µH†HÚ.PömI¤8UXÙ§ˆæcÓŠ!¤²?pïã‘$ £7$ ÎúÎ` ”q¤·MèÕpÇSM œQè–GÿµOa(“ÐÀžs£ð4`³' × $ÚÎ,FÐFÔ Ôú-ñLáU;@ š&!‡–"k`t@YQîHPÉëƒÔÔ «"?w?L©t S=ÁþäžàÕóð}|ŽpŒÉ¢0] #}HqyÔ!O&ªð~€¡ìü°Ð»LȰÊ3t̴}K°*'5 (#£dñ²%™ö ¨éL¹"·dìØƒHó1ÏÆvn —voå »·§–ˆ-Ü ï…#Øô˜ÔC‚X2'¢Ù¯-{Ò¡ÉřЖD{Ô­¬Ö’>Ä¥fÒÕlÈ|“ý ~Þñ´–áCç¬þx Gx&âh”ÌFÍtq<¾2›0ð+ 7¿Y’-§WM‡ì hÏúÑC7E¶,bçEÙʺÁ©u„pGº‘ Mš“7M&šÏÌ¿švóa¶â•6àì< 9¯ÇAµ€?# )Ónqöš1Ƶ£ÌÛ~œlllÕZXéÝzCqªsæÇÒe ëÜa•fÉÊ“3·ôߣ6o{4M2dv«4‰€™ƒ{o<ó–˜xg̉ ï|W‹¾ª’ÆÄºEñ‹-Ðk^è<‰ãj^tÛbyp3³“ƒï1£LiÆì ä™Uô²YP|‚)q¥Þ±Ðñd ßÙ†eƒDœšoŠBB8ÁÀl2 žÁcFåëè&ªÍ~7øÝDà•‰€ã2·øL6¤¿ ”Æú—3pÌpåu%–è ÞÙŸŽ­Z˜MÕøÿZ·­„©¶fD²8sO`¯nžM²TñËÆýàcnµš·Áã2óþ’†ÞA“_GF"¢j܈RËe2; ú‹A–@b„¯G£‘ò= zÝ~43ÿã¤iÝŽ³¤ù üõTÁÎ"ÞÇÉ*«®1Æâc™cE¹ñXÊaì ¼1€‘_Ø&|À*ÖÖg½LÅ)K9q5­,J„7£åN¸ ¨zzö Ö¼àð .¨Þû\_»…¾m^ ~"¹¡ ¨ÕyºêÂAû×J{Ýýhfâx>¶%Pô2ƒµÇºàÁEÄ#ìÞ!ar8= :½îbÁŽù—ÐGéLkö hÏ~AüñʲSl\4ÐeEÑE<Í#ò!Fëv·Íÿ ‹:Ú†’ÝÅü|+˜'à.…Ë ËÅPÓtЛ´Ï ¼i7Iÿ ŽûéM&ÓÑÝ€ó0]Î ¡M½¿Ÿ»u/ «<Ôß¹ã•Cb¡j¨}=!: ]ìôzYØ!ßãîe˜âmž7œÞ½^¿'=é%cšôF½|a˜WÑ 5´ò¡%ï¼QâÜëÙŽøeÉ€z½0Ô刢¾+cì£W1ŒÜÙ1ŒR˜coLû°p9ÿðRÒÁNàÝýü6òœÖ=,Ô=“þ }Ñ "v.y£“é87ÈÕT9ŸC,ØÃwöaûçB±Þ4.© #†ØÕ¤š…&:HÒápCª—L»Ë0{GÍOc}>”ObFu`DÚ}žˆ½&gލÛ# LW¶…9Lƒš&{% â³Ë T».‘™Ë<>˜{¡@ãä’Ni÷3XŽ OJŽ¡“ë^ðYø„ó¥×ôjÑÎ\Èý¾ÈƒU-ªyÇóÅj)äB=—¨Ï%¯(LB )Ú±»,òKÖÕÉNíCî'Àû»û´VªÂ4FSŸB÷þøu»‰ë¬ÀPåÚ˜C¥©kEØmIOÒp'™·ú´iŠu<\óª×!·%HGÏM/p]Ù¥€Á™eëÎ’4*!RFH°4¨#\•’ÕYßíâ<Êw‰¦Y z9ÌŒ/òݨs±P•é‘b&ÑÐépžÐ Ë¢»5wd¨×¶¤âk±‹ŽÜÜ牒Źe¼È6§Bî]©<3×»Ÿþ=ÐxÚEó7Ú|Áxܶƒ’‡çïvF“pOqgî3^æúWO™–ô÷ª–uæqž›¹[Þʲ¤ c¥È}ÃÚvg»ï¿ñaŸØÖCçw™q±qÛœâÞŸ –P+ Zóˆî°ˆ—¦1d.š¯[ÈÏ[ÕP‡0Ó ê{³« K( “¹×³p¨ì« ùÕ´+v_ê00b.2³¢òÍþ¯ ¹”îbÿ4—-$ Ù÷EpµLîçWI¨m6ašj6¼ÝK`á kEL |ŠÙ§‚ä4 ~ÈS¥‘Ñ¿0múZ6Û\€¦:îHx$zãh”)¦679a’*çhÄs7ð"@ ‡ ®T 0/…7S7ÈSÖ1øÌW»q‚õ9Ü'Ò>ÏÇx—k¶ cÊàÏÝ‹ ïËè±ðºs¡½Ö-¥ªé)DüÉï¹îïÝ»§¶û±A°Qž#“ÔªÌðNWççQÆF–æŒ4O¿ui§ª%a K‘ªš{y\Äãq„¹ÑþÕÇCˆo ƒò;ÈKE*\¤ù6 GºCi'çÙðEŠÅ–5Ï1¾¢¢ÞÁ4|ggxOw…=èÏÍŽÀ¼i2š aà JëîϳÐxf ^`N *n°{O0Z¥ªA‚C§,ȽwËiä”H=LõH=%î|3þÝ|CŒ}èè€&07ÄȽ¥!»rÆŒk„µéàP/{Ž›Ñ{QÆTÙã™8ŠšÁüÉ'‚‚55¦Ñ9ä=+“BªëÅ`É5=ú 1êö}øÖªŒÀ¨£}X„fçIwdªwö¿QhQºêÕÓ)œ娉]ÛÊØwÕ°Áè ^Ÿ7&°ëK–¦‹'' ×;‰?ãMnþ)  «-Lwÿ•Ìÿ¹Š@¸D‹ÑKÖmu¡*X;·ö&…‚?­)†qóèâømŒ¸œ†“0ƒ˜¨ÁAPÐ(`÷ˆ6‹_R.´¹5Mg¡Y@4fhà{²2ƒë5Û ;ñÉzÏÞûZ´.¢gµä¡õåÏ«ÙM±q™e´ 3;[S ž›çe³çͼv"]yj¯ÿÇ;†ˆ·²´èUdŠ» N ª my*/:¢ÂÐbǽ}Œ$YVª{žÆ‹Ey<ÿ=bËNCïð0\M~ûpsy}/I´¤>,×âzlªÖâè3bg‚ˆ¦WºlVJõYÌñö Æf.8Ic ÑÐÃs´Ú§É¢‹‡Gçø2ì"öâ½Ð…)ÄèéßwÕˆrkï'ÔÝD KMW¨“t÷…ò•\ZqоF­ «` Õ{¹Û˜]ú- Á?kÎ ñ6l"¶öƒ|ƒ&S-„šÿ:ØwݨѳÞ9èqîñ#Et¶Û®âéXŒÁPû5‡0—ÒdxR¿ç°î¶¶s QQÒ7½ðº¦G8V®ßýË0Ë0Áýh~nð–Ýî<ÝÁŸ¥»à2[Zukàøà·H»`k ¯RTj½¼VFn«å¯•†nǧS ë«SqO5 ?ϼßë¹³¿´3Om¥Yc¼â L}ÒÔ~+Wô\ „› øâ›r€âbªË…˲ïàñ1·zº‹òÅ+/O‹xä.IÿÓ6z¿ä_]þÏdþ¹.þÛÞÞAÿý>|ÙÛÝíí€ýçÎþþïöŸ_âÏËÿaÍ?ûw»;] ý´·½³ÏÁßö÷ÊM@s,HI0 ùd!ÕúsÔª™ÿúüÅO"¹FòDTÓ*+µý=å[Ì—ìqâ’¢†Ø¥0)J_…ñ]tÈɳ´Ž¡Û»ó½Ôª²Ê/pÝUͤžžxÓ¤+•bZ¥½gN\Ü+ÀŠ8¸…aÏDjð”0s ËZ_Z¢ÿñ’ „—©>s."°Å`åâž{†%ESw=b¨“=B¸I-ØH±»½^®s¾ùÞÝ|)ôPÊ™²}‹Ÿ÷Ìî2/wÆØ çÌZCà_"7aôn᜿VŽœÍ¯‡Jtò¹=zàQ ŽÚ¹õ“$C°âøÊo.Ãåèbœœw(‡!Þ*¬íBlE¯Ý Wܰ›äÝõ{HÞÙÆ+в$ÒÒ-Ò[Á‹Ž„ó謣‰÷Hõ«µž–×£%.Ú_­™è9~Ëvm>¦rêhÇÏ'FFÜ©æ½U±E™|kÆ)}Li`Ç”þUf(É3·K“Aå/,J”+ùtNµV£Ÿ?¯Ô#ZŸ`ªxéh%¤o^+Èmf¡ÌÚ8žšrÙ»Z/#q2§”줗\HXC±'«7i˜!”.¾¨a fEñ£€501ºu«¡TŸö[‡K‚²²¨mlu9nmIâlÊ5 Ç ä«~o6’)m Å#´¡» äKˆ“öçéúäͶíÃ|…ñ7 1op¾@³ÐïVÓº/Ál~Þ8jþYú^¶šgôT¡B·Ûmn™A‡nc«ØÙÇ’ÿ¼ÔmÑdÍëC Á ±Æ  ÀøijZÛÞnüÙ½¸H²eðg(MÉëhœùuÐü9KæœÒ>[aÜÚC‡Õ-*®/¦Ym.9YM»üÚ±²ÇB³{3ƒi«!âI£LÂiFyÅ‹õËÀ ׄó1˜}Ì“w9ðþ=Y¥’wÜÆot£5èËB{4[-˜­‡l˜÷U—B'Ë©— Ai·2°A6iÜÞŸ0]f¥KçL*lÅu¹Î™)4†­³‘› ©™·!àv÷`¿qÛx˜6Õ䦓G“!BD¤¾6<\É\$É’ŒT(ï<`åua [º¸=Vãñ#€\)&÷™ƒA“Á/x.”SÙ‡yüs´oc ñ‹Iѯ«†NÚîe¢].dñ…ƒ~•PKu.Œ F4øþÉœEë¨ ¢¿ÚXYŸî9 zÿ³’Õâjð[”²8 èÈ¿ÿú îaC²ÂÁÉ ¢u.fÛC vÙ‘±…í$ë<º©EŽj¿‹¦˜@.l3ˆÕº†Ðá#Þz"Zg–-’Å ‚y 1SrC—¢Î "ëšY¡qÝ®{]ÛgÃ8ûÅ«¸Ødqõ=ÌâoXÿ¡ÚLû ºŽP¯Ìm£è Ú–ÑkLðÈ`Ñ%K@#|Jk„ðhÉà#´¢GO 4‹|¡ßîÂ[ZŒìr»ÕüÚ –ÝŸƒ&V£›×B'Ó‹Ï,j;ð¦Éã=StWˬ›µY-Ƹ2zèpî ÂÚ`ùì#‚oe»Ð˜püfn8ÐÀÔ"¸*Öư{ åf»lcªõGÓeˆ¡p€º8ôÊÁŸ]ù7ØÄ[;©ªÕ5ð3Ý?|4›~óA/8ÝEx{-~¼•ÿö±têjÏÖ-ŸÚúzŸ^$—Ûhè@›€XÉ?1£ ª¨¨«Ø$Pú ×wU=Ó…†Bžs|sÐ{5™–t‘l5Ù>‡E ÒêÚqº¹o5ÎvG†÷;Z¹Ë )`IKfÐÍ9žÉïsú38­!’ƒ)@¯ó:°ÆÖ鯢Gƒ 5‚oƒ†a0/ÁaШ4Þ¹†EgIå_Èý°Z°$ŠûÌ­C‰ÎYÇuÀ´ 8ˆ"aï`Ÿ¸kpª÷í‹rVP¥;5 ¹™ØŸ[kJtg 3omÿãÛ>ÜÞ¸ý‘föa÷­üØr¬`4îÿõ«'’Ù"hä-‚ .ñv×ìÊ¿ž¾xÞ6Êá-ðRn ßæ•Ïáí@ì2?L£$JceÞz¹åÆÐìˆ~Pv½7‚n³Óìú¨OYC$m2Â{m3˜vFåVö7re’e¿Xi¶åšdË(Ζµç/ß²Yþ¹— õö?pƒøé}¬Ëÿ¾ßÛýÆ~ÞÝíÜAûŸßå¿/ôwß3ÿõöŽýƒíÞ]8öä·àû˜&óapŠoi=ÓÃàGTe|–NéÖ¿.Ϲ €2ö–Øt?4çDš)¶Ù·ÄÈûað·“W§O^<¿5‚ƒƒî‡[·îOÜM7\‹z>¼ Ü¥z@-cžFJËeÊ™ Þëôv:;ûªùÆA·ßkÜ2d Žy@­4nîÊ Êlû;»ûû÷vúw·~Û$£~ÿ“WH<}Rµûgoï`wöÿÎÎÁêöïü¾ÿ¿ÈŸÏÿç—iÁÁnw§{÷ îìýþáîÝýê<ðÈÆÛ4Á(œNAh¯pA¥Ëiàè¤Æ}pÔ—/6!¤ó+ãluÃc/9©ƒdÛ ¶‹r'Þ6’·ÙÀÏ_?}j/xž ½]¢ø=¦$L¡H*mÊÒj¨ÁаÚW†¡oß ¼«éšXÙï=àêg¯·‡–ãªyÄYÒa>b2ÎÁe7ÍÓ1t;NÀ*…š€Tæ‹¥í=[½8Ë¢%}+øã!û¨þn½v°»|õ0h¯:Mß.)àÀt0˜€º„ojX±ÏyO2°3 ©H ²ã €OPîõVSÖ"gH}ÓZ òpÌd$GkÙj¾˜G`›QYÒSˆ(y¥ÕvI²^ˆ_é':•Cw—'²ÔvU¡ñ6޼©¡ÑÔD:óÌ£l)®‰‰¤@áE“Û¦ }¤·[[[m#R¤š[bÿHì%ÜsS[øÙ]r¼zŒ‡ƒI´] ¨€ù ¡Ÿ®ZÓ“§'ÎW0Ù^;˜¥è÷¯^< þŸ¢:êcðÓ'¯N0-&Ø6mÒ›ÁñóǼŸà!-[³±e¡ÛÈ:#GÁÝòe‘ôÞýôÛý?.ö>›ò«'ÏŸŸ¼ þúâÉs.-JM‰àÅshƒ~Ëg]øÂui 3Ò°Q‰¯dÛ——ç"°€é|“ñÃiw€y|3Æd˜o~÷í€àÌ÷X— hÝFÏ…è[îÆl`':À@ BQm{M ðèM“p¿ùVßšƒ\ÏW‘”— q4ŽpÕ‚¦b•šAS–Ø(EÚƒq²‘/’äÈ/ïÚ«‘9e«^¹Lïïãc‚‘$³©ÙPät°aŠuõÄ8‡MŒÕ¦ñ¿ŒäKq¥ÍLÍœ¥þ¶ 4¸¶ó[¸c½n£yÒÖ’–î{Oß4YžÃ®šM½ZÜ1i äP1å “£b}0¤+«*êOÏž/vNùòÎ4¢8ºîC×Bk«|޹òœýŽŽ0î‹ß·å£—ˆ¾$çÖÚ º¼4ô l‘ÚB†AÎ ä3 ¢ gíۄºou},&ÿx4iŸL âØ·ãoN‰LŽxï Cº«yŒ×Ãûq|/³®7áìMkÁàÏRê¶V·€ö3jøL6ß"ŽÙ@&b>(]ƒ5žyÓ·ïëãÒƒ5ínP„£iù‡,YóAÎy¤çW¯òž%wå¬PÞ\Âß„À2œ‹ÕQ‚σ›Ì~’ª`›L–hò6F«:'o™æ2nŸ²iC4“èCŠÙ¶`Æ®m¸Ó0D";gà'浹Ā0èÓ@º8`>¢ÛÓFeÝ2I‚Ùjt¡Ï]¨`°r†5D¶‘:zMöL¨§Dßx`™˜dyJÑ¿ÐbH¾n«2„ÜDåœa~Ópnm\[93ðí¹aWà·:ÎEôpÝ”£—G³f;K»eȦš¸¾Ydåf´ßcŽß>…Žb3í²°ãrÆH10øŠŽÍ±Uµ]CdÂYp^ÑZü =^ÈÌ ­­›pì¡BÚfÝÚp?̸co©Áõ|jØòip>˜&²¤pÚµð‘åèüÖ dî¤É‡8¤-"—Ì¢ž'Ë„+6·j€…jETúÆd3 Zh„äú qÕÛb:öDžòy¯T±ÐQbï<äÚƒ4Â`9æØ1¤š]Uû(»Ç€bæÅÉ=\O¼&2[`šÄÓ–’¦ãÃàûã§§'hdf“hÙ€&ä<‹à–ñÄÇ#Lm8íkkîSÎTŸeúHÉõˆ í&ƒÈPï¥q²WÂSê¸Z¹Ë%6„‘¹4Ä-c/š°¥®ï®)Zz[¼܃`:Ý(k¶ÃÂÜ0<æxþ>yÉpÛ ‰vÐpŒï×üXYiÁç?ÔÞô{=8÷¦ D.AÖkp[T̆›Å©9 eÔ|,ê)ß—¢ µÞðú Ó„U¦Ã—™jýÒãÛA®i}JûÇoù^òè†Q·'yáaWrÕ¬Ì4¿÷¤È@´ -«  Õå¸h@c«…gåÆçBž£l™ƒX)¬ÒDÁ™¹ìÁ˧gN2ö *1½ü$júþ!Då7>•p]¯$Õ"à< M‚ìa>GbV&¹ÌØ<õ6t€“‡½Æó<«#¦½öp1s5båm 3{Ý•_?xË7]åôûµååÈç€dxT ½E“_…´E¨`[Dì4SgÐ…öãfÔˆÊb—<² ’¤ »ÇÌ茲Ìãò~92ÅšRŸwÔ¡|çVù.ÚÕë͈™ §Bzy¶r§‰½‹®as\¥(÷l)Ç%áI;.—»~ãʾéúÎëy¼QmØ‚Óü`dÿ‚zGψUúÕ #§ÁÔ8ô ‹¾ÝÁðc „õ¯oåìGûN8íÝË6R®,”o,}ÆÊâ=¥£¡äBE¹+6|Æ8Ø™2(n€ÜT!Ð/™%RàzþXäk~íèš“8P”µCÎÓaŸS“mûFu¡¦M不ª“””VÚÅ+—¡}¸üûßÞƒð´î¤QîesL Š8ë]Ka…¢„\ÞÀ¹-J!šÕ¹%ƒNõ°li¼SÊ ä¢¯f³+ÉøÄ„. ®´KÎí¨t@ã'´‚ Ù]œuK|¸1 í^{²Þ«a¯àHOÞ¼-¥Bå=™C2xr¥ÇY "Ö²{§y(væ€Úêiã5……€(ÔÐ/àåñ«×/Ÿ½xubþyöòøìÉwOž>9û»¯¥Ï“õŠ :êcâá’*%Z†Þó#p·ôGdÞÁH½êŽM™5<,¶âåcŽ¡å ¹ X¨(ÛˆŸ-²,ŒRÀ›Ÿß¸P–qzá=Ë’Q«ë­º†`ÆØgRÌÙyóÁÏòCÍô)ç §îS¿OCÎÃtÎÇ–a³££„x£#œ[°A%d®w8‚@¿™»O®é ì9oÜ×+¨Œ†É4ÃLu%¢/ô¨¹Ç—d`YÂΑKö—e"ÇÖ2€Â)b'íà·é¡A¾ˆYCPÚ, kÉGï‚WHdmÌZB^Š{Eyt:f¶[1{Î0îþE-- ¯x´†S-0r¨öÊa–Šú]ÖPSøÏ]O¿~ùøøì$øÕÇàôä,°lj/’amáH¥ƒ°AÜŽÆï Þˆ"Éðãaréù€É.+¶J›Ú£ ÇñÖWA"/h¶¡_ãQ¤ %„ÂÛ4ZVòm&´¤¥lÃU̬- |CŦáFøˆ¢TÚféö{ÃC¤|ŒÒò‡êû‡3úiqã¥./0]/µ°‚vÏ!á€)¤Ël¸òýÒ•GŒWö DõaýÓsL€U{âa½ ›ö ½&¨ó¼ª_=ܤ”å61/§ånVØ+Á3nùJ˽ Ïh•ÉíhíKPv0iƒ†¾ÑcÆïÃ.È"|ˆƒÓV¼6s þ4{ª,0$ =uÇ]ƒ¥Sp|ê䮟œ[¾S¢´ƒ‹ä2z73¨~±¾Ã6gÄ7òM M9 pÎLÇ®i³Œ¼åŽeWù:§íêj@Шèrþ¸¨èF -lmy¬§Å°¬ìX݇Jn ÙxöN±CŠ=÷Õ*E×Ë8šæÇƒþ´} f:²/…a ‰ª£ÇqV©Ï4Cƒ7d{D·a-}ƒ'7dÔ6øƒܼòŠäöÜÙEÞF™¹#ºc¥èf`KÓmn9îC–)(ø4Ù ¥¦¦¸Ó?O–• Ma"1Ó ‡Éj‰ú3>½‰~«¼!Ø$áˆFáœZ¢_U’.a/¢ÚîÒÁ¨u ŽUƒ ¤‘@®ZVsÒ ©-´Ä 'KÁðfÈ¿º"û¤‚Lý)tŠìÊÁ8žLZ¹%mçOÿ-}—P}‡ Z^¢EãqC©ÌØÉÞÑz>ŽßÇãUXPÔñ´9 èJú˜Ûœì–ç¶LW# Ù¶¡ºÏi×küÜõƒæòÚÌØ`,·i}’ôJ,éP³å?e> ^Ð%’}ÝÊÕoß?yjäÂW'f?yuòèìÅ«¿›õ,i¶i#@Å–C»ÉçÿÍc axIñÉÛs ‘½¨!(žqZU´Õ—¼$¥RÓ¨ü5 4 ßI„CÂæ¦LËœ}C æM­û?îK Q ± IãóB+Ò€œíÑÓ$·í É»ÿäÿ=9=;¼:yùôøÑ‰Öuá4\Ü“`†Ø»Ÿ+˜€4â­3ù€áY¾ð29?7C²­õµ´·]'áûØþ›b,W¤ý"ˆÈ}Öàb}‰ÿ3èXƒy ¡rä“E½&þé6KPð KÙ#È0Ut7b¤2B<ò¤@z ïD½‡×Ok¡Ë7.™vÃy¾¼*ͤ<+•šeåŸÑ;dÌQÛîÆ×­h'·ˆ‘·iºZ¯Á~œ£^ðÚª£dMåjWTå®v…éè¢bzø.€Kn).‹UZü°»#ðþ% š~—¼Þ¹!™úã|¿Óuìéz @–Uf,1ÙúÙ•ûÆaK .!_ùJ ÕÌ“ž£UÒ†Åäâ"NƒHt¿¢FéÚéJb+ýUÎ@—­f0\Âo,¯¥¶ï PAKkñ2ètÐSå]-Ð¥i®B[BxrúedþEϘpºÄ(/uäëkq4àgÃzG€mÔœgÕ™B¼gÙ¡ÂýZ«Òˆ¥°)s[‡BB‡ÓŸ¸²%×4ŒíÜæ‘²h)*P]“ÊýÏ) ´™PnWQÚ,iÁ3éáù¿ih ¶Q œye©¥¾z›*¿ÊXÀ¶¾ ­zH#*‹˜P ]’Œ É'*á´6Ÿ3V6:LÅâ3/ ¬«•ä+¡ô1§ L˜¶À…ø½”ÔjAâð‚ûA,©!‚VÁ ] aˆ%z‹#D°« „¼ëå$u~%tXw°fWM£J Âú4Ò)ÀÌÂSL8¥÷zuh°­óØÝ†B·êÈHe5HKÙ7&Bž„·!jPf]³ Ütœ9$´]BîÃumÅÈŠï˜_2L“KÍ̃Sq¾åÊ‹ÏFw¼‰u¯Mì˜>±©X=Œ º›ÏFr´2`-Xüa\‹êÐÙ¸íáqUÁg €>ÕÁ T :_„¶ø/%29™ë ]9|k²ý¤=ü!¦d@ñe_;Ûì‚5ªVÍ6¶¡yŒhÕ äÜŽÕCÝæv±Ÿ¦‡¾òÌÉ]= žiî¶È³áöÒP<ÑP9Ê‚=¬šrÛn=Õ¬r¥‡‡·VzV;ºxP©zðbcð9#›r:¨p¬¯&dz<·PËÁ”Íœ˜ñÜt·ˆFñ$yÂ|.FƒÜ@KOMø—oåN|¶9­Á¡«`ÍÁR?Xc–/StÈ8x*~îÀ,èÅðUi²¼VFÕ2%¡JçK—0d.hI’1!†:Îû$-Wð ṏL?T,~­ŒäsK±å‚T¬ÉÓK·ªŠµyYJ$M‡:Œ¨`NþY“ƒMPd,Ì5þñ?„„,®~~.äC´Òæ_€{‚‘yŒ—ÝG””"ÊUÀǸ|©„ûè4àZÀUÌ’YØÎ §ÃUà6¦“ñÊBåÃÃz_6DïŸ">½‰gKÐ¥­´ž5OA»"²ä ØÁ®«^0ÜnÖY»4¯m&m[¸Ž¥tÁȦÂXÍ,0èD…M&Zp±{=c“ g?,•Åp‰‰¸Ê)ãìè”ÙÊÍ­ÍRéÌ̈OØFçÅ 5O„Pº1жxgùØ ±BϺÕÖ½u`£ƒ¬­ƒ–90§•92£¹#¡îóõ¥ Ä Œ$“EÓ÷|« |48cV‘Õ4tÌGW¹`Ðì Å <3.§Çé——Í]lJ]w©«[Êõ¬/}Ṳ̀içƒÈ¢™/²ÿŒ%h[2%–•(OûÛ‰ÍÁ©AP‰ÏÏ]ÉtÖ§@ax]ÎEHeìÂÕÙh˜ Iи%ÂÔ°˜!Û¡Ý0š&—ŒŒ,Ad¶i{¹§ü8¼%jÎo•&«²LÞ°æÞd9Ü5aY¦!xÒ‰jÅõÙ ™Úü$©¿sØ—û–çsR=t¸@rØê{¹ þà:¿QeÞb¼’ª-V·ÃrÍ(žu3€@fVbÂ(j™ YNoËÝ` ¡'F²rýŒå³ ÛëÄ1É<‘0¥†,§ˆû"ºã¹*{0‡{$- št‘µ$(ÞNr,(·ÍÚŒÊ|è Í †ÚÐºŽ¶~^j©»Ö6™HCÆ3¾‹CbKˆ¤/[½qHÛõØ®%í:ƒ™Š©i…s]ˆÓk¸´wT¸[0Cß_„x(Yëy0ß–ï~몾kß6QÚôn³EŒÃ‡Xshóªä³s`5wqœÎê Æ™‰åèÄ„*wƒÿB’WX© ¡+‹}Ì­«É9F{rg wíûY=/òlT33¿g!Œøª)¢ «àå6 Éq}°³[.ÊïšMƒ\hqX ™AwP’ÎÊÜz oiª±ø%$¯´%{~{XíÇǰþœŒ¯S‘‚Ù¢VSˆœÍÜ[Y…ÐÎ1 |Cq¶3'K7ùåËfRáÞø„ÅqÁRH Njß`h‚›.õ¤:Ú–QˆÅŠßúÄx%ùƒÔ…¹³¦_:æ]ÎÓß›»úkG}tk?ÿâó ÝüKœüsn!VßÇëNÌAÈ¢mCª¹¾üñ¥›êšøz¦eáJ‚”Χ:@[‚#%wXnÝdÉà-vûÍßûFkDôr³ÎÛ–'ð—â1З4ŽÞ3ŸNŸ×CE±ÿA×[®" J1‚Ÿ_ÇkrÍ–l-¿1/ ທ5mú[SE·%QŸ?iSâR¼q»ó‹{« cš½»Ymˆí«¬pÞÚM–nXñ(¼@oAÐÅì¯kĆE`8<Ã÷f¨ç›%ï#¹Á›ƒý› DŠù8œî²àѯ㢔“U[6†ª/ªZ µ®::yæÎo5‡9NØJ8×ÿ>Iž*£êy¡Ê`ÆW%/Š@^/ åS¶{CÐ.[Í¿ð.h=€ Ðb¬ˆ.ª6¯fãH¾=؆RG[*# ŽyÈÛW¯ßW#ú¨¾{arn8\^æÆ©,s·«‘áÙ2°AvËå³tŸé]Æ…ªœ7BÄrÎZúáá¾àrm¨°xÓ8â/Ÿq ]ÈGoŽÇc² ÅS´°á|.[¿/»{ª:*U/ P¹ð-$¦Â…Òað•WÛÂÁ õ +¥‘pZÀ‰¶ƒÜp•ÕoÝ/o%UÕ³ú]c÷«,?jâg ý,Lß)¡Õ1æYBé@}p!y~´À\.ʺ>9]ˆi=É[æ ÞÒ·—G©¥%fpmÒ÷–ݵùË£ö²³×îøkïö¢ Bas_söŸJ«çŸÇ4oO—ªK*öõ²Ä³¥zOKB·rß\0&* ¯Ìv¶ÝV¶j¶ñÒßÄë¶°4ym£}”L4Ò”™§U²Ð§õaéà\2ãfë(eÈ${ݵ R~´«åµÏ’×b´T)xt™‘R^¿|°!à[ÉÕƒ¥¦:á+߀©Í©›ó-*›ñ§Äu[»­.úçJUš^ä&%…: ¬âI‡a+®9v\ycÿò´4œS9±Ÿe‰ÌQWo] 9oE­äºnMÙ­ØÔ¼ÖšåȹJ—ͼ ±}±‘­^‹²å—Ö\¡j¨E‚Z4X‡*‘Á³7ÉouKôДÿƒv¸ü¢÷¾G6œЏDqo$£$è4·YqÚôãÈç­DH9#ù‰Üí<É,wCFB%çŠo¿%”KIXÿ*pëvÙ}ùDÛ»LáŽw4[˜·þÑ e J“\ìÆ§A²ƒ¡dçNgˆÒ´p Q„† B,n*hdàÇUWë#ÛTÞ ‹… öJàòƒÜ½)AißÎßÜh•³‰rÅN²¿D^…-â>ȸeCÍÊ“|zš•5ˆ ¤³Wd‘`ÂiT»Q÷’œ­üNÂ[V¥; ëÌEå—÷Ý9i§.ª.v;‡äá×%…{2ý’<ªNÐ@ól6±y¥$r$GZ.G jäðoBøiÛNžM°ØzÍÓÀç3ÔÜ¢Ð^¾¨Ø–ƒ{ ØnTQžO»á*š” »ñ†Ý³4ûƒ—õ”̽p©kc×±E¬ºÈA§R¸S §f»Œ¯|vŽ™¨ê0ùáÞÙ|ŽÜ˜l"×±<Ú±•*O®Mµ‡zix¢~AÐ,ëÀAÌQ‰n­0¥Ã¸þPðFa’‚ñj–(ElѲáš5¡ì†êX€XíÞïÃ:=”V˜Þ^$õkóñ¤<;Z\ƒÜ9ek¬Su”®¶ïUI)`Šd.0XL /0•üHå-˜žl¶2ûDÅ.õ†#»Ä‹|kðÁœwãúYE î–™K#ãV?Gž¢Õ„9cœ:hˆ’ åBʪ ÀÓˆÓ‹m&<"µnÛ˜î Nýxòìxðúù“ç§gÇOŸž<öèš:Ÿ Aâ«®U|¨TT+C²Är5ZBóyÂqªÕ¯VѸÐÝK¢“b%WJxUïžÅ`¾%«£É—Óôû ³ÈZ³ôjA³Dzõ9³ª&’œ #qšZ)ç–‘Y/%Н¹]Ç1Ê8ƒUUÑžÍÌjÖ„uÉ"%ž…eƒý%MÙ4œŸÑ©¨.‹›÷îç̳lÝ0ª¸0(„ciôÑÈJƒ‰cîm ‚ôk&^\ á6™s|ÿ‹d eñåLÌ$¦Ç@Å«¸Gö™K 2×L«ˆ\D—ønƒsTnhq¤¹<8 ΦðÈŒ„e–”¯Þ«uen09Ø]ݼjx r%Ô<µQΔȉª`òN4€Ÿgö% Ošvøª}<%ñ±è!ss®“ÎJYl§Tc÷]¯tGA%` Ç¾üñf[¸µ­ ¶Â´A“8§ôòhœŽÎàŒíEõ“S LÑç!|CVm ÃÝX³È¢fRäÛÝ„¥æ£µâD¯m¸&c­˜V¶å‡·Æ.­jaß”„€”“¹X,¿²ò÷ñÖºšt®»ÖÛdù‚’è8|luzŽ×sQAÉî ͹¼ÿ68ÏáFSSk27´ß,·¨¨DVÒ±¿^íHâÊz.%ïÇÖ™ª¡œQ ÀX&Ì9ÊTL¸ZçcsaùÔ&ç~Q«Ùâ×òÞÁñË'°qm0Þîæ*¢[ UÒOxªòa½*!©VË’óÕš*ØöZ˜WVè…Êùšlâ­âµíß U]/WN¡óæp*G«ó¢±QäpÏð]INô>=yzò茼Ôtuìß¿zñÌ åå"8ä‰QÙ½ð§'BG ¿¿xõøäUðÝß±##§—ˆ0uÉËT:‰ ÑÐÝ^«0™-N²F>Ji8ôN3 :køÎXÜ”2_ùWé´žB4$h¤kIFòcäbÞÏ»êÁE’¼³ê>>ˆà©2Ï[–meQ gkzØ$CTáí•Utá—1|™m¸˜Y´él‡¼ZoíµG©ÃÀš‹’²AnУgoVåXPãR  ¼¦•cÖø¼æ×¹lèdáB"H#¢O#–a°¬¹Rdj‘Ç’·‹q«q}Øj›ß[c­õHýHÁ‚äµCŸ²¾62±“Ö$EfC|FácÉÉ#¦ínº\ê®?—ËîüKGËîŒIXð÷ïÆ'«–hž¦¹“Å»±Wî$08X‹üU‡”÷Ï­o00%¢^xKÓ°aH0¿>xÃæi#H­g¥aloú“B\ûG±Û… t¹ûsË©hþ£TVrVµä(jN¥Ñmbžcî­ÛD/i›ÊÇŽêMá"ø~ÅæSc]²¥úy“/Ŧ„&¥„Aa´Ëñ'vhy‚óµÕnæ çTb5Q³-õ¬šGÀ¬gq¡ƒeü"q#¤1¤WmâU(à ¦Ä‚(àÈØ€n\˜™,*49M²%ÿª ëü`›FRr¬`¤¦¶á½nÄÔßá:šwÛ\[©æF·@¯{¥û7–32wI²#ž“ds2d¥–ÊK]ƒàßÛû艢̓)µDŠL|R®ïÖe«^ø¼¤C o¥i’Ú,‰LQ’e²æ0“C¬ë3AvÝeù/$6å½ë}¢oÃ%ŸšŸ9W— °B8r‡p×Wæ\w…k »v„9Õ¶¾¦ªÖçùE|õ!ïN¯¹ð±Ôdc}°Â±*>©ì"¯2BÚÇÊüŒgÖ®JIuLAÖõÊ ?¢]yÆDh~ š×i­™¡™ËI·ò,k>®p.–ás“im>t×£¡ç¨65 ÀŒ²QLÈK÷2B]WËój£ô–or]ÎÌöü„Ižt ‰}}Íébß ÕÇü0šáÙZk—^døŒ3t|oJR" ¿ŽyµLfèOáð€ÔΗÁx…§8&IhCÞÀ]ÖÂpÙ—I:F£©¥c¼›á _ L#ÝqtƒDÔ#[îÑŒš#YYæ¡™ãÃézMh#alïCP#ߺÉ4žÙ0ã.d䙬¦¤øã¤”ƒ˜-wíÙ[Ü–P%£¨éHá<£‰z÷°5ûçXÚ@OÚÍaäún{ÍÔ’>Gùå†ÒðŠÑGVw”Ħ…o‘s]XH‚_‡™×Å;ˆ6%tõ³ø_‘—Ý¢>`ÿŠóŒI™xNˆƒ7Æ”´*¯_=ň‚+ ÷Ñ(.ïUЀî Œ8ïrüe\!X¯ªp˜%ÓÕ2²€±?hùó„ËúùÀÔÅì|Á·f{@2Ïoÿùð+öµÈ«B]X½¡—Cx4XÀ;ü¦ò?Ržr°®‘Úˆ´äs€ÚTw+}“zÑÂîÞ¨nÞ:ë•Â+´_Qµ×Û­@”6¹Æ†?’Ì8_ ¾MB5RqI1`6—9Çã0“HI˜J.øÆŽo»I«­"#ô™ŠÊƒ`aR†bx5±”ž¤Õ¹áუÌ~ êà½ÛW°LA¾4Ycþ'ßü ¸Â¹ÍxŽ-K@y4Ððš2:Øäñ²Ûp~û5 ÙÚ*(|áë›#™]…Û'ì4©"Ú&é {Ø|á+wíõv?Ã1dZ1>mÍcpo¿Á¡ƒñ¸˜M"ˆm $ÁK„é麅 4Þ‘·N,ã[(‰nD­ô”š“’ýËS·ÄñÛ_²½Ï²d{¶yIqœo¸\{Ÿ{¹æ ƒÂGÌ@pa%[q½+E{pj¤ÑZ¹ŸôOÅ '>‘hV¤qôǧûl};}}—Hãõt * ¬bóYzª~K†ñœT½Pë™èS^2´'}KB bC§ÿýTº€{WÓþ9Ø1þ„vw:(2¦H§Hµ¨ºJWó9kBÝÆ+¢€Ñü}lŽÜã—s kŽVÉ‹ƒÅxDþº•pð ¤%P0€ dšòš6BÓE-Œº =®Çæb&ãÏ…ý„@ØaÜZêrÞ 8Äû8ºeóOxÜ¢A¸ù-úpá6W&EømÙžÖK°‰á4½ãÚ¶D²Z.VP˜oj¨0–pKÀõñW?âÕ-xî—¬ˆânH~“Uµ^î÷èQíîìÁÇÞî|Ü=0¿€‹&ÍØóK¼ùbŸÇñ¦‡*¾D´ âF¸‘iWcÓ`O"@ÅM8ýò‹y<[ÍxƒÚÖ®‡`n ”†O£YÖÐŒóà">¿è,Óp‚™ácìòS!é3 ÏͬtĤ”¿ƒ-»ToðxíÏ"•â(š†‹,’,X(ªcC É™™Ás:=Eõ×ð}xŠ-ÛR!”5ÌZÄ*%´¿øZó33g‡˜Î˜}1v÷îb—„íS v6A©ç7Kè3î†JP˜Ÿs½6;á¸ÁIþÂÔk¨EFKÕÚV—ƒª2›‰{E‚gÇd(G[n¾‹E<¤Sܤ HÂA¨2ð×]Ñèt>)Þ8,Ä3‚­%š Yä%éšÆPùÔ³hy‘ ÁÉ<iüÞL›ä^¥éµí@¸­}ûùÝWqø¼lêB”1šV¡TËÕeOY[&ÿ*§ƒ¦~x¨`Ñðý“§†P¼øéùÓÇO/_÷ôÉ#ŒÚPþæþ›É0฀®à SŠùB6ƒEÊ:ÂiÐÑüÈÍ77T¼ƒOž‚X9ûJùÜKS3#Ì éê0¦ k*0ĘÓ.£àLGB§™Ë°V­Ãv$ðš‹öó§¯Yž|ÊÒýü›Y968þœKçÖŽCK|oø¥ %ž®™®h,г‚Ùâ¬(Æu&•,«ü2> –i²2¿Íüä =-õ¥`;*>*Ý’ÕrŒg…¶[±64|sd@ÞØ‰9A.U³.Sy‰Œ¦1êߢ€<Þ(hUL?…)ð‡%²+Ë ºˆ#à<½ûÓR™«îµÚpɰì¢âjÝjòÏ›Æn®YT®æ_LTÿ6£wa6'8Y/•Ç8Ñúº ?»ò×¾Ê*Ä&Ŷ…¥ñª‹šâMLqò-mÐÄA,¼œ‰“é*» ;öæEvÉYâ<"1{ûÿõ7Pb1K‰1z"åìþL×OxøçÊçŒ:JøO0øæ¡Ìê΀RHŠÏÂÓh~Îö3;ûû5$ë˜À§ºåûc—‹Íõ@S&–ë;F¡HÁýš>Q`90#éïneÖ¾ÏP¾xÔ&­®õaä ù²—eöæ ‚çjñ@HæAÍiBº…x÷MFC\ha8|4qZÕÊöA0!’±1ÙÙÙ³„Œá–=ð¤²6ƒQ»³a5JŠ:{L u¿ •˜sŽÀxBm¦Œ‚aL*;•ò•C*ˆÅö è|fC¹åúÜ£¡óόѫÀ4õ%h-ž÷;ºÌ>;X­qCVñ±«›+E6bªy¿Òò¢ïÄ]t´äj½øI¹÷ãÙÙKFéúæ|õäo”’[¤ç5‰üŽa)ßДzÖó‘a¢Ø\بÀîÇxÛ¯æSPÐ5dv¡µí“xuÎÓ0žcHZÊ_Ì £6ÍhÏ#²Yðz[¿H`~!pCƒ—ZÛŽxú€e’LßÅ y„Ïv¶bãn¼à¯ÆÏ³C¥‡4´˜±O¥f.”å@±0èç<¸½QÔ‡rðvfÑÙ¯›`ej,‰Q˜j]'8Y³aýaµÕÌùYkKµæÝ9çå¼ kÀ¤3’Ùqeeãz]•6QHºR¾Úpÿ•ľ³E>'V_$—Žg”`Û¯@WEãÏh¶”F›¬äÍË x¸éUæs«§¤´1ß@×8 ŠãëÝÒ¡âæ¸ßvÚÁn;Økûíà ÜiwÛÁ=hÈügžíÀeñ>\,×’m±˜ç¦†>AèYíͲx¯‡³¡èÄ1ܶ߃-ŠØË]–º÷6ðI¡çBUã?èêMQ¹¾ÿvaä«À¶4'«é£÷Ëð!|>¨÷ÓdÊ„©ÖÒQâõ³Á0e¦{„"¦}þÈnÓ1¹€Ñ•â'›z¯ÑšuUì·â¶.–oyo8‘]ÇMA¡ÌÅLa†¶é{UuRDKÈÜ£ô}Æ e¦Iònµ°Öy R¨ÒánsAÈôemÚ0g1»=×:„mô¯dŽf"ûÂoÆ·PÇY§ÏêŸ2TÙȌĔº„Í¿wfqðãaŒßoÿÝpzüs¼=Ó?ÿn~Žå'Ÿwt軳®*(͜ơnG~KCôÛkéYðs Zú9x¦þ=€÷e#zÒ…T´]rMüÍѧÑq+Ç+å?õ¸x1¿s@1O<¸¨a`m ¤ ù}ðsÛŸÐ÷Þï¿î»tJºg™„êZ=ª„¦ëÜAå{*Ò»-Ðå?˜á(0 ‡r2ÃjÞ<Ì£üÔÌ£ŠÙy H×ÔBþQa„P,7ÈÒMàŒæ(8¹†Á…ù-/»Û˜²Þ™³ÚnàÍí‰J-ƒÎ„°Ÿ[°G+#µÎÀhtR–ÂHaZI/ôæ3uƒ+UÒ <¿Y·J›‚©´dÅ>4õ{ñ©éÉëyùÆwO)È´cb éá RvË{P€ÚÞ”eÞ Klhc¾¥|•¶mxFÔ¹¢@¤Y <ÏíȺE'Me<Ì'¯Íìè&Ý(®Ü£bLk=nrköÓ… AÝf£!´ Ž–œÐ1¹œ»Y C¸T:-k`4JR¸ÒGÝËDÄ\fƒ^ݘi†ÌXc¼Œ¢w×Ä@7€*ÔcKUÁ³Õ Øöź3‘';Â0¯¢Œí €£ñÜ>ܳw•«TžíË|Ò˜ŸH¡apñÙºx Ò GÑ`nF™¢iÌ/ Á‚©›Ó¡ï±öhs]¨Æ-sV¶ª挶$UÒƒ”öMIí ªÒL#Ó ‚èÛÒÆ‘~Gh§ßÚYW& ÞmO Š}UÊ_—ŠS1ß8&jÇœ¯UDv 'XvÎ öüKêО—åd¹Øø¥f© i vkxFÜ:žkg`÷Ï5Ä·)î Ô©¿ Rù ѬÙÖ\0ó‘}Úñ8×#^éÊÕ^ŸÀÓAûÁh\c78X­Š1hãMgá|Nl‡Gdójõ·â*I—‡Œp曋}Îo¢q0,åƒlξ¾lã÷®s¤‚> Ëåâp{{q±èΣå6 a[Ä÷.TïB¶o¤€¡Bð¶©ž-ƒÙÖVµB]õn "–ŽÒÏkR®ÿ«§¤Ï_Ž”æ…™"ЊĄ×k#jê·¿†œrÃ`G:Þ€–JÛ뉩W2OM? ›T¿JŠ:ûô»>Iõ ²9M-ŽòÿQõ VMUYT½) €¥¨ðãMoczŠuõÔôiBÆ„_ˆ–ú:›<¸ŠDWh#*ª[®Ù'OÉuK͘ÂM0ß©/˜:’Z¤¨ÔÏzzªÊå©éM°9Õÿ*©èôæhw}ª ±9ÍðÿýTó©'ÔwABÊ/ßPwý;{}hiq{ÆÀ'ä,á„qà€œ'—¹¬œÊ »ªÊ*ÁἫ¯Öòy\+b¬TßáU'žTfø,U\- ªß À,ïcÓy’:E¾dC¢|ôÎGƒcM¯ ‚—n`ÚC÷ñ˜gÇZ Äx×c3^âÖ8lHôæüØøÑ¬¤É¿C£Ë}œ…•óg“Eʰ#áqJf;°ð$g“ãÕÒPF¥Ý„üŠçb¬ë¦KzÄÊw`ŽöÁÔŽç#øàwd 0¶’>ÄmQg]AA §­¥âÓpóÈÔ§e°¹æÚÁ bþ…l:5o³šƒK¿Zº.ðÎQGHýXvvÎß¡‰ì„‚xBôé%ºùhØ!ý¨X>ÀVí&yƈ1ÀtÏ!“Dš”)Ås2ƒŸß †æõõóG9³q+Ò6¸8ˆ7 £#ƒ¿Îm§|ñu œ…ï\ü´¼–Ø{‡ld³®AL `«ùÁȬïÑ·ÿ|ø`¿ÁÚs@Þ-Odž1nëæ¤³v›c{‘d-öõ6Eb ˆ–ûá¹(›5ºŠù{ãÕŠÖÇ GÑ€T ï(W#Ž <³•9`¢1;ÎcR@jö@Ì(a“;•l xEáØ“Î G Êb£¯6(”diØ1Hîršº„æ (ÒŽ;ZÀ–x˜@˜5ùF`1ÝÞÓæ©öåÝ=•󦦩Ҫ'YÖu“ô|‚Hl÷÷wö›[ d rɾõ“’U”fµElµD<~Hû´ƒrv³¶6k(Þ^˜: @[¸qä#Œy„ÀÓq­H†a±œ™}ÎÒŽ1à,D=¢“©ÀzרŒJ?ËOóú»ÚR. ø Ù'°Ò½Â)Æe«¥½4‰À¶ ’xv¹1~¼þqæ4=tiìáÉéd)òm7x6 ŒÌ1º Œ¸')×uVG|HyÁ¡.]EÌuÒ0¡²Á[\Ish#KèÚ¨ë8ŠîZe‹´¨»À£Æ’DÖK ¶§få²´“Á®hEã ]aéjŽ–´^Ì rT§Áë}K’œ*÷ÐÆÂDçp‰m5u 8L„ †´¢è˜~„ަuEmWßx¢\Öcž¡®b0Ç`g àõctþxuò߯Ÿ¼:yvòülpòêÕ‹W*1À³+ˆ"Ïgg˜‘#°aR°ŠÇbìâçí@B¼Z&Šú¢öýèO£¥‘9—é•Y¾HY¡WAëvz{{ý>,žM®üúåcp!û”>§'g8˜‡øoÿ¥¬Ê”Ø‚ICeH‘ä~¹ìÊ {ä@ºôšC½ƒ$îÁ®fã™Õ F)ò:¤L+ÇsSlÅZ·_å+ò:‹Ÿ¸yµZkòó=‚&ÒЧBݦ8êxÔ¯®3š êà Ùý8•$ø#XeÛ"‚׉`­˜#ßð|/|Y¯Å…èNÌ7¨×²êŽ–×Ó 16kY$g·GÏ ‘3Œ÷;Z®àÙ´=ìê²ï¢«ŒÊ>†ð“ìðÜ1Q’ÚåøÌ?ž={š›—ÝâÿœâeDئ~DA”\Úp¼4Õ‰µÅ¥þ3,êõ胡õs„£fuÝMGøʾթ«¡ƒ7NÊ ÏVÓL<ÇÌš{T#m¿ÃòS‹·Ôæ¹þÆl:KC™„¾?V‡.ø/ào„E¬¶ Y¨8f ÔEeuq*}û/~ NÏŽÏ^Ÿ6¼ êf÷cP¢BuVÁ©¼ŽMÕHÓž’dŇ”iXh¸Œ8Å iK3#ˆ)‚/âp¾¤ä¼ 8žÎ‘×jNí Ó˜3µftDÖìb‡y˜GÉlFñ«V±%c–ÞßW•ºËpÖɨÐ΀/8•™„óí"yîôäéÉ£3é:6[˜õÁÆfbH(_ÛÌ“ç§'¯Ö5Cg|]3t”¬ifA²Ýºf›I­mãÕá†ÈÊÛ"êƒ!ýiÌ7¬JÅÈÔßõÖü¿ÏuÈ–›.:à”üœÄóòáÁ›Ì öh}¸¯PÿŠÒÄNšMAB#ŸûMšE²ˆaóˆyÝPHtgf‰)¨¡+Õ]ǕЉC©ç‘í–£Z®›ÓîO\ŸA<ƒÛ•JÔÄxlÜ‚ÿIkáˆj¶öôª´õËаû㺦Q&¡e¨cCªæS ∔ŽW㑟ܚ¸ËªF0dGÕ±„¬<BÌð C8ˆÎI·)-ň4šc˜$hnLá,§Ü¥½ˆâ÷p«l˜’Z‚ÆÂ1„Ú4ôÞ&FÉ8&Îöœ†,嘞 ³ºzþ!­–2D—5'¹æï³ÿ¦€<¤PÖdÊGA©$ºµ˜‰Ùæ;3ÙÝlîƒf•ŠAsMLfæML3}ýmŒüˆµU` µUkÏæ0£) –§Âb0>ªC‰9¢5©Íàà§j‘‹G’Ö{áÉgïI%À8s- ü£Aµb†òç?ËT¿ v M!óP`)XÿQ ê+f™,PÞ›öGX_UØùŽÖT1;ȃjNgçQ”ÜyL‘:;X»Q"Ôi³e¢Å`œ!E¯I¯M‹Óùh^zÚUÔA“š™[ØN&wKXn«ì'~ü°€e¶,‰.ħÅEK•¢+#ü1ÎÕ,áüZ|ÄßeˆFÖ½ˆ1@{õs$’noåI?íE$þc±ÓK`ï­&Rê±!Ì%àÕÂÖ Oõ¥fåHë)9(ò¹_4Ãìb˜„)çÈËÑlÌ‘ˆ!‹Št[R%,ÏeþÄÏCãágnk©^ˉ¡Û[Í âÈT.üñ~I ýd7ƒi¼(+M%ý*ø–S/1€¾ñ±\u>12XµbLâ®è.Õ!Ž›b‡ïìñ(6F Ò)¨˜?€ F.ʶ ¦ã ™¥÷ŸŽ*)΄¤ïDfæN [¾€IÜBÁºÌˆ›v”ùZ>[áCôäœÏÍO*ÿX¨?¬j/78®*,‹÷uI…ˆ[oì“·®ÜGûíF‡‹4pÓCæ7BÁ6 až…€o…‘#`ºd‘„é·×¡[ú&»õÇœR¬¸„X= +q|Câס¶:ÔVa¡|“‰Ì›fð˜MSoß°}£wC‰]Ó#¿õÐŒ˜.H§„LW2+Ã',ï’˜¶,þj+‡'Ï¿t¤d6J—yñ_X"yWñþ§ãWÏŸ<ÿ ]R„üŠ’hSåèþ\J9ª#“”Ñ¿a²àG,8šè‘ÖŠ 8« °ô@š ù±M GiiÓ䲕miNµla*Iáx ªÒa4¥ØäÖ/uùgÃ@šè®¥ÊÅ]lçÒ|`p;™Ÿ=Àþàx!ž¹¬ Ø:cd‚Kç¶”Ò%]³AÆcæŽÖbCah›wUìb’”6,8]¾tï5oVžb΋ãóp®² †o#á'Kg(%¶0*gu„ Ž…Àý¨ð–÷wË1#Áö1…Ô0–¨FUŠ7ßИ9U¶¶¤DM\X.qZÜ*(~¸IpÓÍ^…-v嫤Š5˜ø‘”¦/ÖUצ[u<ñŸ*¥¤YìŒE+– Ud”qþi´7¨íÉ7a7r˜®K¬ƒB[Ö²~´6XÍÙGËm†ÌoˆhŠ]ƒ¦6°éê|ÎgBàj£­#€N“…(úä°}–5ê«¡jH™ÚÔ²î/æ„ìnm©œwš½BÛaÊíl…wDžÚ¼ªÖ£D47(nå$/cÖ2q½“ ë¥hV»ÍÒµñ§n£ “ã|ËiãÖýM¨Ø:#$ø¬ÿ•bç?©(âlŸîœ&qåÖìÂ-iõ:ç¥Øú×]§r…ѯm™|eÑ5UEÅ™j%ÂuõDµZ¢Ÿ„@K}õý›Q•ҸjÈÍÓåÕTˆž#ô;J|ØB#v³b"H µøUy±jµU;TðÖÊê¬p¾ƒ Gpý›Uò67dBl5šbî!ïeš”Õp`ÕÜ3Œ±š«]­\+`‡¦™IzãÝå\S§æ5ã´3•c¸f [ˆÌŠQu]󟓳W~íÜÝ¥K7$¡ïÜð®Ï´ÝHsò‡/ðG£9Øfq ºnî>zæïÎþ>~ööúþ'ýý¡ßïï÷wwûwÌóþÞþ‚ýÏ=²¿ÜÊÁ.//;€¥UåÖ½ÿþ•­?õâô¹ú€>ØÛ«\ÿ}oýwÌúì˜õï}®Ôýý_ÿûÁí'ãÃ@–¼ý>èww‚³a·{Û½»Aoÿp¿w¸¿o踞|X·oq`W&ñÔæ[¾,s<‚0š #tu…‚'`;›Ç‹E´›äd¦p ú&«XN6áô–0D…¾ŒµùyÐýpëÖýà‰öýÂî†W ©Ãæ˜M‡qËÌïuz;}Õ|ã Ûï5n-Òâ[Àj¥q Ã&-ÃX$7ú;»ûû÷vúw·¾þ%ÿªö?ýþ<}Ôï³ëwÍþ7'ÄNoÇ@õö?Òÿß÷ÿ/ÿ÷à[³Ú· ƒlÉ­<‚»ÝnöÊÝíÞÎvo?èÝ;ܹgèApž C¦¢}ú „&ƒ/Ç. TË ˆç†³¡«[íÉlAЉð"IÞ .¢é¢µ•»fÁ_܆hx†¿ Ósâj3#>±•ÏòB] #Ãþ)Pík!…CUf¿:Hƒ£i@LÈ]5ÆÓxy¥h„¢A@€E’-³.Í.¸Î£¹a§Å ÂnFLv€MÃùùŠœÅÇÑôªc“?\FÃ`½¦É`qßó’…sSã)°.ë ¯HÎ6u9å;Çâã†0®0ô ¦ü ¹0i²:'u‡ƒD;f™ÂhêhʳðʆóSXA5ˆŸÉQ#'6>ÄvާiA·H.£t²š¢ˆ<™FP6æÀ ÛÈÌCLJQ1üš•ž£ ˆu0EmÖ“…¦«óy<‰Gá|É©$! Du预 lˆƒ4ÎÞIlG™¡k²™Õ4Åä­œ@,ô\×0óp4¸èmB}šÀ¨pÐfÄ( Ý_8…ËÔ7 :€‚yZpuIŸI†¨ÑTu–©h ç©™y®nW¸W½xè[9º¡SrYºÖª‡Q˜FÐ1úÎ0/ÅB²š^6Å(“Ó£ÇöhƘ¡ÉdsåÌ.íŸÐ8ÊÃj@ÿ†Là0åTn«o°Œ”>8ò‡"N`u1ïæÉ¥‘ô>²£Ø*} ÛEÊ.ÄìÃk,oÔ5…·%Øé6í’ø_H÷¶½ê[[›Áö{2ë¡LOÛ6y‚׳•âxµñ`Í9DêçãÁ¬Êjç¡9‡fqày±ÖRQAý Ëx‘•úýmCI1’À|áÄJ“pšñ%òùÔœWÓà6FR5 #&ÈT,äа' ´¢nà,éÉááB¾a8T¤p ¨M s®Ñœ.ïÃq|ûÇs ñá9x6Þ×=ô]ú€ºØã=G`%þÐ^¥‡€ Ì£e†q.|º¡€¸aÀ1I ÄЇs¨Íà‘‡‰¼š…’SK|èÈ™Åm`(âÆzröW¿$Áw`&Œ m‰|6C/ÁØð‡ïx,0onu´ßp*¡”Ë£Q¯æCr§qè¦Ú†øŽHñˆV™mú>‰å¯8t™79A(ÍØŒÅo†·{©inIã•‚m¹Ora¨â9*èÌáŒýy ˆ7ŸöóÄHW‡k‹¯¦G xÖye¨>‚¨eºCÐðò PºìÊ,ÌDHx0â8¼ØxÐyfm6‚,|.†Í|¨ŠÂ`ì@Nmà;ŠGç&葃€Ë§Q4‹GÉ”\š7îâ¢^í=#”寲«žB±9'Ѧì1Ž’`ŠÖ]kô/Î1¹Æ€(jfÃÔ;]Þf2±`µ!Ö%9p)˜P MY̛ӵˆð/Bî1â–;¯Æ/âÆ‘:²¿ïã—Oò‡—-ÆæYWdæç6ÞZoC…ü<°'ð&yu#ø`¼& œ´ 5Šo-¦ÉÔMOÍYÏ»aÛd€<Ru†ÐÔ«dè “-¢1¾¶5\L9ǘÀäO/@;Œâ¥Kb(ÉŸF×™Éwfµ/CL'.óâ!vY˜r”€à}<éXÓï‰ñ¦9â^Y*ƒsóÍ-bš@Ì9Æ(~s ÍKHG2’Oï4ž ÁÚ>xˆ ´í8F”[D á‚ñÔÐîcˆNt•8ôÃàA4;zœ8a\ã§hj‡¨ÁÇ>í<@¨Òç˜AÃ’#²}W÷Á¶iêz§‚q‡‚VÜg⎱6‡¡µã2œ ôcl?hu©®8ᦴ Täœ2ÿH! o/<6`¤#_±a èA)>>øÇáº1ØÖƒEÝâ o­4yP™¯rYið1œOÿ¶Ñ´`j_‡„/ŽÎ/øêqQÒÂÎüU› 1ÞRcî =`a§¡äý[ÈHcN¡£U<æ€Õ…)ýúª™Ðí4±ä?输š…[Ù^Sßf PÛËb?‹[& Šï†2¡!op9˜~‰‚†®’TŒÛN˜ÉQ2œÔPÐlTŠ•­ÛɳQ¢hô¬hi~tú椸BÜî1YøšG ºqèËÁ´ =¶“õn-d¨6"Äp§Ò™ŽÃ3m:žŸ»f'Þê–µYnx3ˆáfÎÈ8¢`´„ "¥à SµQé¼MOãb©Çš¯šÞD”,3?¾'‡¹µä\‰ r¥±„Õ.üöïe¾Ô_õý/Úh–>ÖÜÿîììþ¡ß;èïîÀ-Ðzý;ýþï÷?_ä¯xÿÃ+@}¾ ÞÛÞÙ ú½Ãý½ÃÝ=ï&x ј2%ž}ç²Á…Kö¤tt¹¥r` ýàÑ‹×ÏÏZÚ ¾õâYð?¬ äÀ‡s‰P¬–¬±%é‰GT*Ç÷µ9ì8‰2L©…ãé¢vèÈ´—›ÄF| $?0‰±3‹—îZFrœ ¦ÌÖ½pžPsi4E)ß°ÁË‹I(…ôž\éVAFš;_ „6Ý'P3` éÞ “D©¦¸`&ž_ù·‘-¬)Û@ðäùÙ‹"ˆ[]#N$†f´éœÚ þvüôõÉiÐr oct¯ÞVClåìAZ³ºÏŽÿ_‹ÊU,pckËö‘ÉVñ(äs©»~V0Y|¾ü X§|A17³oÀ¾’ÒZ÷p^–7•§—9FkÎNÛrß7ÖæÃR±©Õ\0žÈ¶¸šñØ€yk+–.K÷¨}‡èQ>9¹5eyÕ]C²ÔÚ ^ Ì0CKÍáüŠ6j.%Ü2¼¹ 3ÖV䮥(‘]r ðôèÑd9E}—9ü9ì'emÂ{×0§î…K¸Å LA¢9Èïsw'CÿªÍJáy^4ÞúRfy_ì/þgQ˜Ž.>¯ àõíÿöwïÜùÝþïKüU¬?}t‘Ì@”ýOêcýOggìözû½;wþЃüg»¿ó_âÏçÿòËŽLà[õÁÐ0»û‡{;k,€ ¾¡—û!sîh؇h;ɨ<וxE_bÜGÑq`Ê™|úls` F®eH xÈÉÛŒ­þѪû8Ee 9VaÂÔ"ÿ§à—`z²6ß:aý—?Ši(ä+ƒÒ2Ï—‹‰©ÄØŒ ^‰IOˆ9[ k5æoâìô-EM]tér3§Ø&]åqllp_ì6IúÛ…r´^&ó4ñn ‡J>ScŠV!…sØà8Âñl Ú£p“@aH Ôe ùW2L’MÏA>›)Ÿœ²Î?†óñ”íÂ`Ídyð^»²ÃÛÎbë«Ùèc>F.8ZÁq^î÷]ƒâøQÍÖÐt$'oAêìe×*jTÇošf=ñвÀ–cU#œÌsgòßÏ%3Õ{Æâøš‰ºù5Aƒ¢·ÚB|,*dô.+í²9>¢T&¤®¨€¯Íí4š±ó¨Ü\&F‘_Öß“£Á`lݲ0*b °­‰ ²Ppµ?±u`òr“ëÀ7›º‘ëºÿù¡´ËËO›ÖýŒ'¢Ká)AŠMŒ%k¶X¤Äµ˜®RPjÙ&Í(ÎDì£7€ØÅdoÔ®iKÀÅÓ_¨=ŠSœ+ÈQ£\fÈžº…Á3Í’µú=#µ˜Ìê·xð5ß­`Û©Z¨ã„·¤Âý†b8[‚Z\ÅH0[åÕŸ2ïs”DȈ“nTvb³¿±SŠå‰óT1\)ßÍ9©œñ*–I.cüJ¼ö[%m–¶îb°0<Êku©/“ èR žœ†ŒÖØ: ÍÂÅý³ù ë›õÜ1ÿíÓºÂüÕÛ²ñ9ì\%4Ò¡pÌï.lÒM!©‚7ݯíà o=Jî:¢¼Š…>ŸÛŒWA~°„¤l²é º §5êŠÒbDéì[%CA8b]Ið‹=Q‹*MŒËÂe¶M<[ÍT6.›·†B*‡ùxñÂMeOÁ“‘ÓàÆpc¸e˜½C“¸žG "S¸ÂÆ«)<ò½H@Â2¦ãY”¬ØF‹Rz‰í åõ”¥ñÒŽ§<+¼ö)Ïp»eµhnñIP†Yòîö¨´PŽY®qÅ/Ý®tý‰—ÓáüÜÆ2£tM“Kæ¦Â•6Ýe.0ÑÀÿÆ/Ù1gÑ¿–É>¦`)€7û6œÃ’-ñ‚г3¦áür€šn¦ç‘³áã,=\r ¢‰ÇóÂeŠ9pˆŠ k(µpèÌnþÙ£JŒa£t«»Á‚B‚…©9§F?¿«XJ…¯°’§dòè¯ÿ…fËS`·6Z@ÝiímU,ÎO™À$€ÌÓ+gwòÈì»(‹¶ÿB:6óå¿€5«úwÑÜr‚ZT§ÔÝ‚è¨ÙG˜‡“²@Ã5Ád «(¨ ÕYLðY@d1¼ùLRÞKÎÚ.ø"œL€V݉8d]Ë"ÐR|-<»†y=w¯Â[ë#»ç¥eil€ÑÄ[,ry\õ.qCÝ1¢°ø]*…ˆë³þÆ#³bP¹˜_%­¬—EV#ËHÄÖìaæçˆÔYßsbÝ6²{6Ú4Ègê|Á©Ã¶VÔ ØBf¹s…ÇÚÚ„:_= *&UBS!Ì3‹-­µ[§¦iowçat} º üߦ`ÿ•ÿÕë?ø:ÿc~ÎÿûÎþÎïúß/òwßSüZð½M]À‰a͹ÓlF6¼àêh¹‹LøÛß¾µû¿“.§ÝQ–}bëöÿ.Ýÿììš§»xÿÓß?ø}ÿ‰¿í?i Ž4`—h@¿¿½s'èï‚ó÷º÷Á››.W ÇïAk1ºfË£«Ù`Îoš„ËÓµÁù>32J<ïàïCÒó#Pd;Ñ 8Âb³|÷PÖ& Ýö÷ïüÃuþÖì6»ËÅ-nÚÇšý¿·»³oÎÿÞþþÞ!=³ÿû{¿ïÿ/òWvÿ›[v²T¡ înï¦àîáNÿp¯Üo‚Ë[ƒ×XKbÄùfI—Šž–̇mõrëEq÷؈}³Š:voD×T¨•]&Њ7ÐLF*—žsræX„)*V¥3óꎣôJ2>(RÄE$»SQ3÷Ž®æ@¹f¤3œ)\uÙPçÇ6F²õó;„çàö*¯_=•»x‹ ”Ãà >ÊK°IþapÌN­ $Ž£Ë\i¥r@Åé,DñÄ¡Ò;·î08¥ðè Ë6-â$£eè%AJ£pLÆ’è­‘ï€"ÎÖõ20X›q[ƒÿ ˜NØ…”¸ÕˈW—á3!¾"h,,|®ž òjF%%vÕ¢îy·4æèÝcFÙ€4dAIM“™8réQÆù¦IùüƒçèÏg~'ó¦ @¡ãÕò"Ie `˜#Ô:H¦è,É‘Œó#‚ižùPÖ©ƒ§ Û#µ³î¦œšŽÅqÉ asmŒ’Ù ‰šÙ8U&=ÌÄQÑ,Bãû´Ñ¾¡#xnðìøaè\ºëì? Z˜ó}ì÷lÆŽ.J:W/6ëŸZWÝC•Ón\Ô(€N .A¾rº×g—#±BKZðçK2´EìZjD1“Çõ{)ÈöV7M#Dƴ𨅶X»§¤ÇÇ+!öÊÄ€ hm=â©aa; DòÍR˜½z 6Ø$vxg÷^ðŒ£¶c@rUdÍ#ì:Wౡƒ —âÎÖVp|{DUL%ôN’—lØ"Ò2Áº¼ÕûºÉmhóHÊ€2žp\*Nh•‹F”¤¸µÛÖ  vñj(?u`ýáš]êa€Æ¨-|5H[^‹}ñ†‚òjth…!gÊÀ鄬c#i2Ä0µŒ—6x*P|»Kô€q.LG#ï)Ö‚çp·xëÁöx ޱ»¨rdÈúÁ´6/*–\$×f*ÿi¦ê7ôWÏÿS|^Œïþ 2À:ÿŸý½ÿû†íßéíƒü¿aà~çÿ¿À_)ÿ_\ví ÔïmïöƒþÝÃÞÁáîÝõü±µÈÄÈã”ïÉ~8âfLyÃt ¶ä›°ÿ³á2´-¹†û6©Úž®†gÒ ƒ!Æ¢Ÿ€K7Ì<÷ëU6쟤¸&–•krÒs?âœ,ñDþІÄekàÒ6¬Ãôª–y宽XsŠò mçu.®ä©bäsH¦†!;à‡ÞwóU“©‰Ñ8è'ÜM/‹*e/ⱑ— ìøÀåfþš§,÷zdÑHx¨aæYç&¶k¸6ÝS{Þܰу?ѸUk¹6DzAk×áÚðzL³f5Œ–@Ñ,PÈ"Â0ZŸ¥¢¥c±«ä²J›ô¹,ˆ¦þ9˜,½>ƒ%­Ý”¹r8¯,¼x,E#®vðz†Îa†@z:õÞ=ã/ûné½Cõž}—xï0ù6<>Æç¤6i&`ÏÂið8>—ø>ñÞK½í[¨”ŒZÍ—¯N~öîîP£wïa«û÷ðçþ>6µ—ްÎþd×¶vÐÇ4šƒ=Î~„?h¨cüy‡ ÷èã€^FãÒØ„ÊM°öÍúN»¸ÓïãÇ.?Ý ñgH­ÜbÛ÷z};´{½]|´;¢ ÞÛÃ>îí÷éç>æÞÍÿÞçôÞ]ÕÚ]jmH­ ¹µµFÀ¾íÐP›!#4ãÆBDHÝ„wpfá]RH=…ÔSÈ=…ÔSH]„¦ ikBÕ†Ôͦ;äé÷qdCêixk¹Í! {8qØ1¢VF\}´è1¢z#ÙˆF6âVFc,3îíЇÙ˜ÓÆÔȘ7Æ\€h·O{ø4ÚÅ5öìÈ¢=z´ÒÇ?†TmÈÕhdш""˜Mz¡‰ÁUnl²C½O¨ŸÉ.A›brpl2ÆÖû½þî÷vïу|2.ócB÷¸Ô>—š ùGÕß5» ìÞáÜùrOFÖçÍb>#ú¼Û£Ï{Cþ¤ÊíµþÁ„ 9žÜéïÙÖîìÊÃÝ*µ¿ÃŸ»ôy‡ßáß Êþ1õwg÷äADî2…î÷°'ó¹+d¾æû]~y>û{üyÀ…û\ ñƒ]z°³ÏŸw\k;ÜÊ¡¿»ÃŸ!ésOƶÇÝíòï ûv¯îŒ¢}z8¢5ØÐgÄdx·×£ƒ£×»Ã¨ó9–vƒíöîÝã‡÷"*öès2äDæwû¼ Ì:ßú#y0rííÈ0vi|{c.µ7¦a¯ã ÷¸=CVˆ®e2Ÿv)Ì÷!=ÛÙe¢»3$êÄýLîR³“a?¢O÷¨}:j2žzN¢lÅ aÞdB‡×dÒg‚3ÙéуÝ!?Øãû“':‡&“;ü’€h>¹¹ˆG ¨‰öÄ9nDÁæóf W×"Kùl«ŠyþúÙw'¯N™ác—àŽ:pè `Èç~Ï}|wÀTã`b©Ü½ƒ>o'tbòOÚp÷&´½îM°~È…C*rá0² 0äC*1Œî0#DÇ¿ÑÛ×Qgc~ ø.GÍ> 8"Bùç˜0€iÜdw—&q½="g»fÚ–†­?ˆ¢¹æ%4_¨š%®whÚý»}¡¶}w<ÜÛ; ;ùXA“îù4©w— žФ»nßïñZíìÑù²³1uØcBpçS§;÷v-ÀÏ>ïä{nßïÞbòöÞ‘íMôc‡ág¾Ü£Ì‹™/Dvî*vuç.—J©¡l)Ùžª=ð²v,ÀÂ}…ºÏÊ}ðòõóGg¯Ïž¼xÎ{çÍ´™é&ݑϨÿD$‰hiž}ßž«4í;Xð±yÄâ“!1iô¦S‡YøýýÐ2ëÒ ³ñwCê‹ïÓ ¼O‡$0ñøAÌxoDÄ€÷‡ôaÌsòÄÂ;¸àæ¥5-üÝžÚ]šƒ›ôö˜9ý:ÙÆŒX7Vˆáú‡f¶Ì)b·ØAŸÙ¨b ,T%ëQÁ;»ûŠcbFil!ypW„´?{–¢÷è€EæGöW¯/»p‡D±Þ®< ÞÉ|2õö‰wèíó ’M̧;ô{„Šñàßwé÷.3»Œ»ÌΙ/´› Œdo™­MlÅH¶xDD¤|pïq$÷xòæ — ¦Ö|ŽÝÞï Aè ¥b@›ùÜ“„É0ñælsÄ?{'.|F ÁID¼¬ùÜ“ã·OvùÓ2›æ{ÈϨU+Lh°æs_„ü`T<Äí Ýçfúü®p®3‹ˆ1a|Ÿìósôy_EÂÀ)Kù²Q§|uæcÔÓSˆpµL:xé Ênh¤ÅŽUí@<«Ú¹VaÄ)gÝó.œ‡hnõݳ—ô,9OÃÅEÖ­¢ˆfD`ç€k´'K>aæm"Ì?Øë Ÿ6´»bO˜Ê{¢kFââ5 Ç>1¿Nš"VJ¦"ö¦Z—¬È Q–¯ÈÝ^X7ÐÿŸ½¿_oâÈö€Ñù›«hˆ¤D–%ƒ!±cLÂll&;‡aëiKm»Y­¨%ŒgOžç½­s.ç½’Së«jUuµ$’Ìì?3Áî®®ÏU«V­ß:¾]œ 8M0dͼ•Ä!àý·Ãtœ\¤X“™þ‘­áÀ1ÞQ•Ù·nQBÆlʃZ츘Ÿ±?“…©^;Qa½P*êÃŽVfÒ›Qü4AÃNDcw‚A—@œ‹ÉÈB®C¯ÿÖ,-Ö:X0Ž1G,Ls=“g*“’öGX‘Ó„ú®ÈMv#JÓÛuÑÓÇÙYú>‡õ!‹_:ú»ä¹/&× W¢Êxø"´µ‹KÀˆÃ4SÝ»Vè›ìÁhÔûìþ®il¦nšÇ7_ÊŒtä˾2[æ}–ü¼(Ýy†³>=›¥l\9‡Ãžö2rZà߆õ"f)áú7ŽÇ 3æóÅì¤A\-×ô¡!­’ @QW ªnØLã¢(³‰ÍAê覼x…îÄj[Ñì‹W‘–æ}]HLJèG?âw]ŒÖW)âND JdØìtÎê]Ó–}þúÙ3 5Öóµ`¢.5M*Èå¥utnùÕZÇÚ—´Nt»n˪4´ÝaÖj_À´¨ûÑb |>6—÷—[XÒ×òj-ýÞ–º»^| É‚Kx$JïªËM «e§áÄ]1ý˜ B®Ó'$”ºNÑË[„XT¾ÝWûPBŠˆÀ|‹Ÿ¼éiÔpÎ:‚è…°ù€”2Cà1=•Ô>Ôòí³þ2xþbðhÿÑ÷±M>@LF¡»AÍäóÏQܤCl*“ÜöÇ€uøâ­Ãy:Íæä–ÙЂ=Ç_—‹ã¿ êœ)äõ{MÞgž,êÖŒÞ^7Jâ>¦P'h{9Xéï;RþgKÑÜ%Ñ=Î'b÷áÏ__÷ÝÁáÑÁãÁÓ£ƒ¸ÈŠ=IÐ&<®¸Ä³r˜®ˆÛ !H  (õáNsbæ,£Š@Ú!×{l¤ªŸÊ€~¼’K&3€Ô°sºl",!ºÏ_¼úaÿÙÒe°x£k.Ãf€¯VY‹GÊ@Ÿ~²4å'ªGûÏž}»ÿè/מ'+`®¤Ö#òÄë•DÀZ‚ý+„Ša*Úi1]˜KðawÙÎs:˜Óu'w½ù¤wÏÅC¶ß¹Iöƒ9ã (_°”¢xÖjÒ- Î<ü¾)ð*T¥uZ.]ï10 ó —÷ø$"´#tB·¹yØéÀÜfÆáJÉZ³éÁî(1‹ÆfêÁô+px`’¤‚µxò²Å£Ûr¼>~u†4âkTêosH¦r´øÕ;ÐÔÝwͬ”Æ,z™¸l(ãØCP ¥™?YzèƒT`‘Æ×Æ“«~̧”ˆ'¡3»«C:ˆYÜùíÏà ~žÜ2W,ô¦m ªF½ØŸ>ö"ØWδŠN¶ÞÓ4ióY‚f'£êæEÑÕÍ@¹X;jé5R‹ìÛ‚îš@55nÿše¤.ØKžì?;‚ÐtDïQ]Ôæ¸lÒ6#YŽ3J²ÇrR ”/¦Ü¨^º8ËAœ‚t–XËYj¦§XÌŽ`p1N´Äì)_(½ò€ÞÎ)ë-Hd’ÁÁ¬ð+ŠE¨66Öº…#Ô4 ÊŸ|h®:Øaûm›’?¸1•~ƒ/á¬þ![›÷ J¯)ïÃ\‘¼…žÆRÒ Š&’4B?„~€Ö…£$`20³ŒY†©^Ÿ¤Uf™‹ª§y¨¹OPÛ‚ýcfÓBÈÏ™Y"Hg?à µ£ñÉ["¼¥ŠÅ”jƒÄÀ!4g­•:R§•éx°XYéñ^Sô´èò1 ±º{ZOlU%…ÄmÇœÓ1J°ƒvJÖš ¨Ì, ÏCÒ-:ªAA™Ž¡Ôp¦à5ã’7Ÿa¤¬Y,oŠÜªé)zúøIÒz:„¥Ì°£!žéÉ“A$^¶eŸaäqv±I¨x#"=µÞ¢¹¥ôÀ÷âüüRæØtà;ÌÔiw1íÁ_’gèðõ­¥ÚKx0o_alðgÛqÜ} îþÿäÓ“f™ŒÓ \˜Ÿép34bV‹5nYðòãÜëN9³ßkõ“/“þf+Dà×/ïîü?zÑIŽ¿}ï<•A캳ÀÔM “Ùh0+.ÌÚÆN/s’ßx jìPû* ”i¶c:Ó–‰³ƒòáÑÍ<>Û"qÊ”aòaL“EÎþzmô$ 9(‚mÎ+Õ©.pTf%Ïž%ÿñâés@R½ÈØÈ9¿(ˆ¯+{—eS2|ÚÄ^0|xÀ¶€µý{‘C8%ˆ(²—T¨jÞÅYß?„À1 ;§g•ñÔÍU÷̓ϥº=©ƒ–ÿxzˆ‡e×"Xg{à˜ŽdsS[ú¡w¹]Mô;î¹wµ{`㌮¿ÃäHÄa!”#›¢h4)Ü1=ƒƒ$ÎkJªä’3? ¯yœ¡È¿óœ¬¯žl|KÂY9GXd ElêHª@…X¸/¼r>›ˆ¿|óãÙ<äV Ûʾ„V ÄaWENuTÁºe`%>§• x¦SÃæ¦ãt˜ äÖÕjn¾1·Mß_Â\;ß~¹¹hÚ{Ç û05­sí.Ïæ/ÜË£bsg QZË;±oÃÛgè€~åd¬š²“<} Þ†äJ¢Š /ï±Ç'¤Wƒ YƒÒ„ÒW±ÄUíüMd‡S ëˆ¶êñe¢<ç<ï”ÐŽs˜vy0ˆÏ`É„¬¬O`Â$Í­ÞfïÎfÿë¯î6©< VÜ ÖГ­Ê”ÝèÝÙ ²”1윛{•¥# 4Ëc¦y'i½¡¡¿ý²ýFuüí—­‡{òª}#¾®f9[Áz²g,®i;x§¼ñ=´Pûu›(âo}E2c†€ˆÈJˆÃìr”–$RãF½äK‡Í!Q%N²™×“ÅXóggV¥´ß Ž\ž~ýê&(¬™€7ÝÁ†!_N+è÷ôG‰ïÎ> ³©H¸oDòê±é`@r…ä–¡CVS °B¦M RÃD;LO|_9Ëi:»\ÖS®ý`*µ ~2[ÇS¿Å4ǰ-u—È%á)^‹Qñ0FHã›Ã˜Z5Éå X “Ç€†ø»FtœÃȶä(ƦÈþ´·Ä:g™™âRÇ›¦O¹5öXó8›´  $x™–%$•Xœž<ýlneH¼D“oö°mÿfDyE AH1"7¨[8«˜Û„‚HòôÉ °I/2š 8üUúW7óÅ·æ–1«ö”$Y€7Á,7‰ù÷3 ÝäË/oåZr¥ÇF6dë'¾>\ÌlÌÍÀâØtgSOöÅ Dsç½–ÙâJl²"ìõ¸=Ê+'š>  K6Lå.‘ÏLw!ÌÉÚ­‡uµí$ÂÁ„—gù‰6è½/çYâÆ*5yÆH˜[>)œ$N‡ø–pv´¸ ÷ì1 `Ñmz7xLPOòÎÒ~°—¨º\çíg íû%ï–…'Äe$n’u÷ %Mjâ¾4—éøÉszdà w>3³à¸‚Zû.®rtNá^¢9°I²½ÑS ÿá'*cW61;õèéi; ç^u1‚ÕŠ÷¿õ¹šf™8y9XÌO¾¢iƒ¬6¾ÉÅ+VUˆÛÉZ¨¯`]EÙ„ò™îÊj]¿ú²»ýË`–g Òµøò—*ß°1Úx1o`ÅZùKËZâ|ˆл֩„“}q®“ÄÂäÍx~ I Å!ÄËGí°B«ü`AÚ¹„n(ÕyZ`ª« •5ÛaMfDTÁ©°“)g˜ÇÁ$?°6Z¥¥ÿþè‡g”ûõFf§ž]´”в£wú­Ê9µöIÆ7Œ|òŽ\“H ?ÇF’½¹#É 6•¤B8tþŒnjoþÖl¼}Øz¸cŽ('ÐS«e¿?Eô›Ýü§_  õªmË´M={øó^ûáæÃVëáÍ7éÆ?Þ~¹Ó~óߦ• /â¿ΛÒñ ¯È;QÍÐ ì•ÎK/G©)1BúßÑܧ§% »ÏMOv’fÚ´fƒ|‚Áú#¬ TÇ’´D²Ùüdªp+Îúh¥ÙÚ®¦Zlžmá»þW±wwè]ô»»ôn+önß}{u_Ý‹¼Zpú—ê›ãÚ7yíÊmVû:;¯}•ÒÀzî 0»pŠÉG@¶ÍOÁ‡p„«„¾àSP^/¦rµùcÌÒšU%‘—áj6Ó’F@“zFFÔ‘h 8Ï@…뛺NôxðxX8§…Ôƒ^”ÔAˆçš¥OÒ©<Ñ(ròÙ‡»ˆD‡ææßÊ/¾i½ùo³;¶˜?6…#w’~‡äù×Ϟ <{úÃàÑþˣׯDþ£€IÈQ7˾øˆó„wÈkx©¨G˜¿Ä´câ?†_Í…“*„'Ç TÒKD°¤;“LZ´tPÕ­ÉôΓÕðkÞ`b;Û…Z_ŒF›¨ &ë…¹H™ ó…Óƒ»Uty@,t;:¤ãË åVÉ(ý}ù‚úEAzÒ‚ép¸8gaµ¨ð·9tæ¬QA³Q*è„KÌÓá;%ts#æÎI1Å^J™kÌ¿"aõv)5%ŽUâ änäD¶“bˆÉ ©óOð/L~réûŸê9+u»ƒx6³ðê¹0õÈ€‰Ut†K躿1ˤ†/³±ƒùwN]^"ó1‰F ¨ŒÌÔ¡¤‰ív’-—õ’‹Öèøž]ׯGcJ¤æƒ)¹ñšR¹€ ¾2:ôŽÛlºy Êí…Ÿ¸ÛLÁ \ÛÍ••qa®LSBp†‡¸2›ó¤ ðû"s »@nU`"´®­ÕÞX]Ë’dÈq„†,8vÿG±ß9ê×n'ا¿Øß”¹ÎŽ]³ Ö&ż”Ãw¤h%'7¨4ÖŠ èï êÝï:fÇø¶ë’^-\ª´ Øc•äß`h µLM+ºBxó¼W7ÏÈT'¼¹¹¡„1DKÀÖ:OßZÒlgŠ™dèžOb-fÝëúµQ^¦KÐ\uŒXÙ,Ù@ºÄÜ7ñØèþšK½OÈr®ÔR瓺¥¦µ\L‚Õì$•©úôåS‚z{­¥‡­.AHÓ"ÂmãÍ ˜H²¸¹î4ÔŒÇ+ Ã--ó:DJŸ¶ß$$°5Ò¬ï;š1‰¹ôÕ›þ[oÜ•&›7 Íþâ_Ú›æ/ðgÚl?l½ém|m„à›90CÑ‹w…‰‚Þ¶áÝ  )¸Üq_ö¬ˆ@r{h2ô¼ñ`…Þ–Ž‡INi#¥‘ ô ç¿jë±¶&¥&]ôë˜_&pï™tßÃ?³.…%±íjû%™$OŸ??xÅ&)^µ÷9hîË_’¥ðsÓî ÿ%#ÖŒ!0¥<ív8Q4U'9È@·ŒêbtÀ&*Ùx@/"ka×Cù@Dß“OÜ^Âêq¥ð/7–ý­ÿú¥–éÁžÆLÆì¤¢vm$Ç’ˆYê u²É W“Ç,,­€ Ó°¿:Ù“ÔÚc¶å¬Àºì|:¿LÞ3„™uÚtp¬5½Mn‰·fçc)zº{Hõ(M'x?/AsONdêØßq!¢sú†–DÖsŠæÍÿ†(¶òáÎæ&mP’’*L‚†³§|wéŠ)½[LuH­¸*œ¼F_‰Be–€¥SîÌ"I¨Y2‰¼]V¶yzS|?A8/lûji#}°ð†²sˆµ!&КSŸY½ëk.Â)E²> z6ÓU8,4á’l%Ædãcs;o±Ñ¿¹Ñk|­‹^³ÏÒÉ!zãK›_–h¨[íG•dåÕM;Xn#üèm”¥T‹Å{êùªoIÃC¿EA7(“ÅÜKÔlVdA4Ûh1#³¥×ÝR¾0œ£»ÎhÐÒ“4…d!©L]8?½·ìZ;þ*…犷ù„ô<ŠÝ Ð¥ ̇ õò3mq¼¹0ÏXzŽž.æ¯Å$7'ß¶ÈÙ‰™A.-€|Ýïõ¸<Æ“$ R“%ZúPQÙënC‚Üm¯t¯{š*ø©ß„½Eš"y·>=wLM›IkËüÊW7?m3¦Ô¶Pêé´çÅ—_Ü਀˜ÍÉ¥¯Ÿ³¹oàH²Ò-˜bÍ+xvaø˜aG($cbjH¼…òhÈ“+$Ü©=ÃPL¿Cž¼\\Ž Ìõ§+ý—U7á_뛺[e.zHˆ.è)i¶˜Ø‹÷Æ*''ëíÛÂf¨x'<;ÑŠÏÓmàwè÷ÄÞO£¶ïÛá³ “ôÂNŠ’;§ÕûžîÀÑŽïÇžlÖ¶x4»Lœrè$Ÿ¡RVr›ç :].†CP bxú’FKJe°é$­4æOB¸2?ÏÁTÀnŸàúî°ä'[L6äA»ÃNUX+!¦ܪ:°»ÉË ÃŸ/2ëc‹ ÜgìZÈêèyqŠù›‰Vÿ¼|娑ŠÝÓÔêñdžjví|Ÿ5oñèË+;ÏN{Ü1pÚ“ýÀ—¶¨óºX/õ·"«ö¸­%̪c²u}7wKÿ<°Ä Þ•6gTa¸][W¬3NIó‰Ã;‡œpŸÎ­üuÅã4âÇw„U^pTÞøè翸ÃÚêyqa.ìÞå olÝØ¥P œ¶'¹®K«2ʪŽj9*娋iîd ÀXˆ_¡¾ŠkÖ|Ùùè’{LŽÊ0ÑߎÐáÅIö'èƒïG ,¥e½„è…jdž¤»|Uño¹8Âó×ᶃ»¤;0¬“â‚ÛoyÔÍì5е“²åÀŒ–´¯lÉìe„wžîe74æÛןÕåÜKOlË΋âb0æzF'Ïó¹t6•“îþ„d… ð'’ø’‰ìÂI¾Bç«‚œ[˜G• )#3â6Õ¨·O@ÖŸ*V¥B~5“´dŠ´¡þiH/Ö”¤ï#:X1›°!À椸h" RaD|<£øDìõ`‡NêTqèºH)äý"€A¯qk·³•v`/»Ø«Û£eS‰ã5ó#4ÏÎÊØø.æuáæòúsÔâ˜j‹)ZäRH¥fĦ”EZEØÄV1õ¢teÌÅÁ2oÖ`J"­® =Jˆ,œC6,&Wýy·æQ§ ÔTz[:̯@¾â§êz?Ý4ÏTr?}ãÕc~Ò-m—íàéÅ€÷ ê4ýºñöKäd©˜p›P‰Ds<ê2¹ã²”ˆ&¸I¨ÌÈ)©N}iÀ;âz|É));8/.í›”Ò½kkW5¶g*KslÕºp œ¶®ŽÄåõ­´ô½Œ‚ãÓg“2‚;. ŒœÄzÔ@IîæFÆN(èÂ{4…œ å™ÿåÄ›¸¼p oÚo'Íŧÿ¦i¦±ù6Ù?Ö˜ÓÈH34‡5{QmpŒêPîGuJҨͅ›±Ë®Ü˜þôÿÍèücÙAFí´nW®ƒ;mBíäfë¿ÿ™´Á”ï6wZoþ;yûE»•üóV{U–\‘øÅ†n„âëºõ6ò+hÑxH°à§9Øì—O-1b²a”n8q¤) oƒè8%«¨Œa:Ö™;+ëb†#ðéËÏ[¡C{u&q"q ›2m{K©SbSÝ=vïuµÁ_X^jù‡ôùô2a¬¦ :ÿóx Œ0e¯ÍÖûcƘdF¥1Îd^Y{eùó¸«Lòçà ÜéÙ]¨ âÒcˆÅ3•Y(øÎqü- €"±iHâ‡'³eþÁ¥ÔâàåwÆDw DÏ^4 ·!ÜßÂs¾ã„´g/ól<Þzû?½_ÐÔÞPV8ûRùÃÈ£NÒ4'Úh¨‹ê–½8*ÏB¿. É#o3í–Ù€7LhEsîÒc!û*Û`Ï#¸+"‘sqÜÅ„Ed‚ìêN<$݈'-¸ýâ¨ýÈT<ÌÖ³ìøž}ɦծT|ùž¿üðòè'Æû@ØP¸‚}ògÚÐËìÛAÖ‚48ÏÌ•¢Uy({ì:^RL³ØwÄVJ\‚Õú¼~he%UTÊpnœ‹ÝÕÔ9 _«Àð(Ça ‚fŸ÷uÔr­p’0Ø´˜FJ+1ë˜B¬·év»é¤C¨Õ¿­èvø}xO©´ÌwSÖ] fÁÇò|²È‚9.®&¨/ExŸâ®‘Ï—Ì!œ è?æ=5ûHÓˆã>¶X]Ϥk/Ñm•W±ª„ªv¤˜ù^vKÚÔW>3WÊý”p)$cf‹$ƒ¼´4×v-U¤Ž  ¨f¬ûu°{j=Ð*Ÿ¯j¶¦b¶Cù§‰=v <°a7¥“ˆ… r:9½û<=Û Z4¤ºçárV±a–‚ðq}üñc@e<~ÅðÜ9X™B8ÍC/Ž#w_¼„%Ë3Ý>ÇoÄjšžžŽ8 å#PÕ(Gte:u‹éHíIÝh‘‚ #Àº&…¿Ü3£†©y€Îê.Ba2Ã4™\ªœÍ'aMuKÈ0kð€Å€šE5ʯjuÉÔTêå ËÔè/üÍjg<:ˆ kz…qž€”át¡-XsÝgÀ k—¢†8ÝzØkµšo‚Òâíh¥ÞjÙ.—Bî¡ä¢€{ðj®½TÖ¾[®èb-YªZ‘ùÍ®ÝÛÇÞŒ¾EE¢b~Ω ¬ÙßHÍcú,ésàL–Î[¼« ¿f6:Â1Á¶1 xã®6Î|kד&=Þ fÒÝÁx":V^h¯ þŒ¬,J,àS—ùœMÔŸßr›¶˜'¶[@³öP 6”q”4ÍÈA/Øm<{ú—³‡n'·ËäömtXy^h¢\Xl1Y{‹›Vâ~DƒWò"'öñ%ç&`¯ãKÝç,.J²˜¬)ùÍ|asmpÃ-˜§ùÙÂŒÁÅ%Ç@ÛlÈî+qI@ØaBØÃ”  ¿§ˆ¶‚8e7ù¾¸0¯g‹“D/àc¨ @2¥.Dq×ÞOYùžìSJLòž’3:§zœÚ´šÀ4)‡Γ¹t€¾{AÖy›…ÙñQóÉ8j@6ç»oE!ÙaeæYJíg“ì„’!ã¥è5E3GJH6íAÅÈìè˜hþ߀En¼xÕàµÈJÝ=†Y:@BTt²˜átÍ0‘QÉ1æã1³MaØP‘…_GZS‡I Avä,…ްöCtdâX¤7£ÍÕŒÉTŽR6# }ã1Þ~Ô8ÇÂïD¿a@-}ªAa„>u– ¶Îa¸àœº#®QDRTÇ—Ö&i„ ¼€á dYÍ»e>j„º0‹­Ó#2Ò^±K­I—²{ù\0ÂÖíù[í»°vwÿƒ´"@åTŒ˜ÔÛ¼®zXŒç“rk¡±zšÚ¡1åòîÅX{NsNÕAЍž·]†¨Mä¤Mž‡Qv’"“'‡¼ëÐÍ÷éLnFHcÞ i}½iˆ¡u€øå<–Qj©[®j?×Z.=­ ֙ͫ›¬4üb`ß–•¦üF#3kL0ìÄ0ov:˃ûyL˲оÇfN¾ý‰} >²KâY‘”Bñðéc'Å2QM­]°Ö®–eGÎÁy*ã;²/á/øBQ¹ÍânÿGèP6Jg\õ–TÓ›t*Óžìŧˆ¥R¹ÔÜRD‚û]EX+gurØ0ûL\ÕjÂõÈôЈ}? BN`Ø}¹ËQ¿Ø› Ú…ÿLˆ ÉNy‰ˆ  štÖ’3k+ ãÞ[/FYV5Ž"ßšžCV¯Ó¬åeåH²A‰èFôìÇñ¡‡ aß(fâ_»zƒwl‰a:;¡!´ÓÒ•m¶ÛþmÎõÛtš!£A_KCáå¦z®œ'~zytÿãCÞtÑ^Ö9’ͨTgù^ÒЇ[¥£—6þwµë«¯ü³›A”˜îÜôÞÜy+@&„M-kæÂQŽh¯  >Iû{AW'jcÛ…X×Ôï ©÷¶Ý µ¸Últ'uëtÜú«¨ëäŸ6½™á/ Os›Žìfî’Ü9è$f*òñ•˜¨œá#ð„©TX²¦mŽp™w U8R`6ç‘‘œ¡çð»W/^¿.Dïð°¾ßÿëÓçß%^¼~~Ôú¯Ž·Í¨«,+ ˜e“­uoî¾eBqŽ!èfà[ÔâYð5 ˆMÖv¤bkZ¶§kÍßÁ‚ ÚÌV¿ÛK6]u· (bÑ5h7Õ‰èlhÏÎ {%RG[d‘½ÕÐçвÕå“èã™4°Ý²ý²e±².í„÷ì„ài†âTÁšˆpœ/Œ¼¡=enhoHpÇœ‰C¤LbxÖšëx¿‡ÔâJwƒ(1DÞðœüWj ' k@Å|ºqUJ¯ÓYz|Œú ß §ê‡ëˆPãcÑQ{vwØ(D¦[9'+̸’[„­lâz‰£jR—QÚj@.…{S£+y“çݬ Z¦Ùåû>ÊÁ=ü2Y5ÕfÖUk€Xô¦³žó:¥}óÒR`ÎL³-OÌ,åÙD|Ò@Æ/ϊŘñ‹m,ž%7Nå‰Þ^ ÿÌé ØÁx: "A…KËÚÁ.­ŽõCÖЈ-ézõŠÐ\¹;ÎÓc\GÌÃÉjÈ‚/ƒ0Õ›’ð <íŠub~Zfä<]'l¹ÁÊLæ±® €!›yÔZC׏`çózÀ’aÇô ·2L_ïéãëa±ÿñƒ&_µ+Ìú@¹Åðiô¿¤“Ëd]ÇV óôÄkÆê¬×$y8 ð."„µš2Tµbþ[ü*œjºò9ÖnÉœð V÷é„¶\Ÿh¥!·A•#G=¿á“š”ï’–Yú6;WWš%çÚù%ã[BȉLk”×¶º¹ªæÀÉ_°?Oó„ ¾5•„š–!åE`MÎyBº¢¿ÀÙlP /ÿXÖUF4œQlÁ{kàöUñG^f#Ù: <Úé“X/‡V‰O[õß0T{ÒÚ{·œzÔ^ãõÉ•9‡E1k1‘:ê0„÷ñ°Î°G‚¿Ù8@-¤U|£Sá¦àiT3¦O^ƪøƒ¹+?¿EÚp‚éÈ‹J†¥ Âñöò=ÑÐT@Ï ëôèðð†Õ1î8–ekI7Îô„˜™¼°CÄYUe 0ÿùÑjonro­i;ÙœyG 7«£Š’m€ãq‹Çá„P;®y«Y„¦Ó)à¼Y‰¿n~F=@=÷¦#oæ”V$órä ÁÖK,KÙC]æ@øûÌ„ƒ¼h~f3­5Ñwfé3ú [wñ·TÃ1€“×T¼¿w©ebª5@*WH‰îÕ5{ɪí›Qþ>Áí5˜$³Ù}Ôx€íà™+Å7MyNú\×’H©át»!Àž:ɳñHª±4í3V~Ô–LlEŸIMä2_²¦þ½ v®æû~)1 p|ÊD¦©-KRÇIÁ#¨[$GjêP41 ø:ê=?€ÆsóÖŽ¾|Ó书Þ&È!pê‘·‰.NXc¦FK{íØ@Å¡«döÝùtÜžMµIý–ûÆBéã/Y²ÍÙ¢7âK*vD¶¦Ûˆ‘Öüé•œì ˜]6'íT–ml·x–íß‘”ØDkgùh”Mü‡”=onœ /Ž`&Z@¦"·éËÛS#˜ÍÉqDܳá3a”/&Îk‰K ÌEf<šç‘ê.ÊoÛ¡gžˆeÕ¢o î¶·ÊO2r6i¬dO±1,G;ÄS©7*ñ9ÉÒ‘îQ›õp ±ù§o®S9»)}O+†kYAò,L †¦šÛUé&Ï ‚®!ÚÆLEbù‰õN&é­ò1ä)ÚxdÈÔ§ Èð{> ïðN7/à ÓBæœÓ|ož^{-Gº¸þFþõ›íájkkïaüô=üÇþ¿¹‡³v2í¤€àoµPìãHQæÉ "/K.¢D0â\6ÒŠ¸HÚÛtž¶äzï'tæÜt¥WðFä­ 8e \QZì+bïòŠôœm(ȱ⢣¶´g®„ˆ*.dE?õ±û<çÙå}€2­xÛòÄ.ë8}×±ãŒBwW ¦ÝŠg6U × *óñÁtÚY7„%(ÅS·ÈOõÔ!å°¤±Êµ³üôllþϹ’“×%ï0¦)eR }‹*:¾ýˆN*@~]½øyQ‘1lGzÊ~UfDö[?ª¾Ú$jÇ䦫³i˜ðˆçž_Z|/¡å™›s¦@Z Tõ£2¡M÷Íùø 3táóp§õð›0½_˜r.’²ýÏjVÀu>kÛœ1b§ Ý“(„˜¼SAé o´0B¼Ý0¸ùâU»Å‘âíM)`hà¬ÙÅŒíÀ4\é7w„ÝË0rZz¨ƒ“`#*ãÈõÒ—¸$h:iuÝæìbê›6 Ø;[=ýYM-qbªÑï ©oNÞÔw½_̤ þ¡„ÒÇúj”V9Ì4†"… %.9RwÓ®ÕÙG8!ŒÔü”-‹‹sq¶v[r=%âëxýìÉ Ø®î÷Ê®l ÿ1©Å$ÜâÑÓo’­í{Š=Ëœ¶•ÇCq~'õ[ïDEçãéI`¾0òŽäÎðpR‘84=¿¼ñƒ{ƒÀ[ǃ=ˆnÍâèO(WDFvNaA Þш—°òF²,ßà´>Ò ŸÔ"¸êRÌ´\B˜®ê—ø&Èš°xå…¡øï… ¬ºû¬’­QÈ·EÌÂ0È[Ó6¾ÆRˆRåˆèÇRÖÕñ^”çŒLMºÂ²­†àö?±L“xKâ=jnæ —ï‡Øã¼xòð)r½ÜŸ”© µî½õ2@ŸZ·~&'Óg›â‚ ‰xÃL͵ç^¯mê¼¹çEEÙ2Œˆ´9S¨»ÓNòUO‘œ´VRkÔœù[«¯ÜîÌ7·~Fg™iòe ä6ä—ö=\Õ~ UˆËÖ þFä˜UÛ-ð^©fy%+˜,ûX‹I–A^€Õz4iÎÉšNȵ £åhÌè4aÌCÈKïsù,–Ù…9{ºÝnS;5rÜñ{f´àK"p ²] ýwà—eÛ–`NùI§»ãÈzµ¢ù ˜d]²¼²O:Üi6yÑš´‘ÛO²‹ÃWˆ©ô3Ha[dg*¶ô¥@8èëk>@í&|*ëc>LJ¦yƒ@Lm~ƒ¥ýä§PlMøµC]ª¿¾Úa¾¡>½¥ö-ͯÛSZ_!öàõfÅš" tóë@¦˜gØ* F ø Åq£6Æüá<6YŠ’ ”ëkÏ9ƒ5 q&`UA´øˆÐýÊe]da+ÖXKúüàSŠu¦‹2Dˆa˜ÊÉ8‡H°–M¥DS<Ä›í%‰šýsÁ–ÿ§½0bœ|츰ü­gϽ<žuÿüKr0Ad—FàÉÖð}'ÖμJ¨95IW4šuUçœä“i³Iꃘ}_|QIç”NIÞ|뛟$1½6JƒCŒEòÞ©µÍ¨Z}`r]p:¾_¥ ªz×mâA?Ò?ý{üZíÞ&§ÊgV´Êmœµ¬×l£g~îݽ‹ÿöîöý{½þÝ{ý?õ{÷û[ý»[½í{êmõïmßùSÒû¤#­ùYÀ¹˜$º¸¸ØÝU]¹UïÿM¾yÚs«ŸŽv’ø²wÞ'ýn?Ùêõîoö{›wúIÿ«Þ½;_%#Œà=ø0Mn9Öv7´xUðž]›HEå\ RËÞØñ¯^+„Î}¢ä—›nI—ZP¥ -«g\ç0ë8!G;a=C,G©‘îD †7L’qLqr¤(ÏÒ™8B¦5Yü­›ÝDÖÂv÷¹õ[=W^ÄλÏÔ”›ëÜ…°Wò1cƒóÌò~¨ ³y†(·âé1×ó!­î¿Oó1ª¬VXÌ*¾Vp'ÙÛøAR—4íàe"Id@æ-«^Õ R(îDœä:DÚI ÿ¥jpÄ“ØXç Qo¶áÞ±[ÄÃ7¾Åȧ´)šÕèØ¥ÝäáyÛx`xµWÂoÊÞøfs46ÿÕ¥0¨_þÞöÿ,åÿà-÷ ÚXÁÿ{÷ïßõùÿþ{Ûðÿßâgó ÍùaÁ‘ÛßYÅíQDí*ÏB” ?4—Ûãb>/Îw’~†î.^±|Wªð¼˜îæ(øº§¿•Ý=}Z-6¢&NÌo\–vàó{c‹ŽÖ躖¿óÉI¶Ðë~µíe‘ºÃ$l†“?é|“)ì&fž½‚ù´˜Áh'Ù2µ©×±zÙ/ui¥ühV}A"êrù¯jh¿­Øÿ[wûÛü·eþýcÿÿ?Qù¯ºì#F½5®$úþ™`cÌ'ÖiÎÜZÙIn=©ê )Ed)¯v #ÂàÑßõ>6¢’#¼Ë.] ‡EÚN¥4Ûzx°/ j8Í/ùd.ŠD&͵oÛí)±C{·c± ,Ö°¢’kPå®®ýßu‡À¾wÂEð"¥çLz©Ý>¯å“`ǦuBœ €\„C¦¾5¿1"üƒf—jLŶ…¯³–­­ÆÓo6±¬êժˀòáR÷e¡5B?úã²Ä3õ{3ãßág¹üמ²köêGµ±üüï÷¶îmÁù¿µ}ÿîž9ø{[½»w·þ8ÿ‹ŸØùï–ý»|ìomöî%½¯w¶û;½~rZ§±SŸý{fB( Õ † sªî²ÉÂ~±ËIæe…§“Ѧu=]î†1»Uÿ32”…Þös†¡yùâð³`Š<ºê}wp$1´F`;û»,›Þ°)2µdĦ¼£tya¾œ³*ÍÛ :¶É¦Ž/Ê·6w  7Êgßs”s~™Ê%ÓÁ8¯}ì, êg˜^—e¯ôØæÍ!õD&ÏÁ%‘Ü]…ˆ`Nc˜#ð¥Û[ø³(îÀ‰Ê§"`Q(òüƒ;â„ëO¬®ÒÒ[íwÀ¬w?^«=Æ !ó©`ƒø}X3¶ 0!|’À®S)®#aUÛÅz1¢¬^#ÀÀzæ¾µüÂYíUiW øŒo#¶ûeµv÷¢®Àθã}OÑÎȯ^¡ ûÉÒYo„ó ã!Ò1&‘™‡L@+üöeVA”(ýè:Y ÊêôùŠäô+PÓ:ÄtMZŠ’Å[ª’ ‡ó©ç‹ÙWŽ®cÃÎß¿i¯¸7©¢é¾¡+œýŠ_‡¾…ÚPÏõ%fö¢-K¶ð•<­mǧÇXµ`JªVKOËÙäɲš( 3¬‰žššÈYŽ©,üŽF@Œiz=õB øžA:‘÷Ök=ôt†g¤ò4 ‡†½Î£Fœ=»$óá+ ΤxôW‚Lè9˜ø#±¯0­cå)bpœ@t]”ý] ëS6OÌ,hñÂNÀ;ÊâD‹ ‡¤ ϼ0˜¦Ù†Í^“#} CZÍö«wô­3B$i’P¸%󲘈!„4wïsDûA€¼à›•mÈDÐíÝ{à+Ž F™:Ÿmdr«maÊb ödŒ·&a# ð·ÊK ˜’»\ 5  ĵ[¨|"بØHk}ôβ€dÁ'ëèøæ¨ðák™WÅ_¯{-îýñ®…ÎÉŸ­ûPb3Bº1Kyî‚0 *ø ‚zMù¢#Õ—¦6Þ¼»"êÙÈÁxÏ-jÈÕ%vøÞmµ–†˜Ç®οêßȱêßäg¹þ.Ù†*>²Uú¿íûÛê÷ûwz÷îß»sõ[Ûèÿ~“Ÿ¨þ—Œ~w»[dùûz³×`{çî½;÷c*Àš$Ø\a]lûZTs “u£`ÂœŠ J#,ž§V1²NªùÅdE'T鯫ì¼xé†-éˆ)eq¶GÙ8†³LÙ/ÄöƒáßßÅ^s‡³b2ç`²[gÈܹšñÊ[:¨è/{dTå .Ò(+‡³|j¡¨š‡sÌÑ8OœYòSMÙ¨+εh¡Òµ¬÷h–ù¨ú4¡ÄÕ #5™s-øb1)óÓIF_A>(õD[àŠ½c½'¾êyÏÃQ±Þ%Ÿ>&ÿ5w{ú¥ĹìÚ>µå×çúÁ¼‡ºÓ™B~êß« Æë,ëõ{ÝA·UŸcÝ„õ]ÑMpo®9±¨yœŸ6—õñ™ä§í醻0 Ÿ(ya±~Ï2ýW#ô5„1d @î'ØÃQÌ’a"?/PXóÌóÑ "Ü  …AŠìZš›u÷¬º’à‡$-Ëb˜sªlJÕ@îl”5iõn†?jl÷®±>Í¥TÚéží‘a+0<Uoë(ñ_iéA *>BŠ{˜ÀhÜϰ˜P(l¦ƒÒ—üëñµØÀÄÅø£GF)C– }ëj™áZàÄpŒÒϧðk@0w·ãŒ²(ÍЪ˜ÍÓɼ–{0Äqü4]Î@:5;•þn¯Ã¤X–©6„Ut’µ9nƵ9–Ûà#Òéò=÷Ú<©ÒÒËY~^É.w’×4z¤ Îe¦fWSÄoÄÝÜê¹¼.«Õ g·…s¨Ò#¢,v $øÿäÓ“f™ŒÓ „ÈøyAI Ðì:3Òþq>Îç—àšG°~ iD'á ;& ì)¯€¡¹*qÖS&yB`û+ ­­qþŽNí²MÔ‚Q¨cHsñè3[s—&ÎQieBªHNffþÆ +įÿeá«+V°L¦À#ÿƇË'Ö:t®1îÉ¿æbc*=ÌŠÆ`û9íÊ¡ÈØcG©«fýKEíÅáê,F±Ê.Õ³ïÆS{šÖð}Šuh¹êÏß`5©´bXbS'¾…×÷ß[ùó§ªþï¸(Þm~â60Æg{»6þÇü€þo»çNÿÞ}ó¼¿Ý»w÷OÉö'îGôçÿ¸þ/ºþðŸn::Ï'íû ?Ëõ¿[ÿÕ7ÿÜ»ßÐÄÝÛú#þ÷7ùñõ¿þ£þ÷«îEƒ}[[Iÿë­{«<@÷¡Ž:Ph%ê* sèÉzS#fr®Û÷Ù |9z ª]>áÙ¿HqÑnÎ H¿W&¬²Ešð»Ëe>~ãdÊq _[ˆNŸͲõ'%?!Ó#:Òe£Üà3Ì„±½ð9úŒ5°Ó› @y‘¶`£+õLÈëÓºäœe鈲URLÍßš‚P‘ùõÅ4#ÈÊ2@Bg§Ôeƒqœ«éÐøh¡ëbéüc%à©“Ñít)¶?úœpWÁýÍlîSE4ôb1cŽy¬Õ¢¥WáÏý<›‘Y·Íc\8[• ³@Q׈/ñ ƒ#zX2Õpv)R{PV«ÉºŽF†.ÎÁ¯•ÚVMÏ=aIEÏà€ÏrCKFƽ$]#ÏE¥V Â=êõLûªJwd$ð-\ÐÞrNš^;®8±P™¨u‚·3 w/€4ó„á `ØÿÀz ÕÉ,åE HÀ ¿ÓJ–5©CõÈ™D×¢ ºè»i·,çœ:‰¢±d`¼Ïeæ¥v†u¬#þp-±^»e`1íl\iMÈÕÉ!söÝZ/§Tå¡ù‡àüË8SS·P*1W[±R=þUÜ®ÇÃÔKùf½g‰£™z/ ‘‹ƒ ;¾-ù*`¡oT{oÛuN)UbþW¥I>Nƒ3Ï"7´-µe‡”DfcZáº%‡_'ü¨ž€õ" |«W¨ OG¼ú*Í2²£–ç< å6à •æ"@Õ佂®9èZ¿Á›êJ T!ûOyù7Ò÷K§¤àà~@àÆUÄ`£$%½íȳѦÿ£*-9ª%›Dîä,8ˆº(m~ô%›g¹~Câ®ÞŒ"ÝLóY– L7JþfíFÅRÎ9çÒu{L6U^º)Àá:?É)×™`ÕP¾3B¸!ü·!êp$,àÈy‰ÞY˜%×8l¸a¾Ç,•ÊMNôbØ«@|ǃQ¯ößù?£ëâ1z ì•DùœCHéi]>³|–>º7Z¢¼}¶¬Um‹†“Ø Ò Âªx”‡™_IôÊÛ›E%™ÏZå%±h0f /¶ÌG†’“ø¡Ú~ пfjÏ0qN:Ñdµáìf“SÒL–¨“¦,‰£ø\v$~ &³˜MMÅäL]Wä“q>%|d NBZÆÆ[/Á? Ý™±âNPˆn-'õiüÒaÊ»m›ê“‘½UøŽææã²âx¥-6#íÑú#6øŠ?3kðšòœZ¢$Þ÷>Ê.ôàMs:æd<¾°H ƒš’B˜Œ?ºÈ$dågRÌš‚ x:lÍ•¶vë>:“H;î#Ü.p°`C·¼:TÌSeƺÎ.˜!æéÕ9ãË÷ŠÑK˜‚<úgðUr\¤£–-7m— Ðû‚ÏÓ¤Zy¥ ]Ûqä.ŠbåWfëå%åìW^Ž‹SJx„“Ýen³ü4Ÿ@FÏ"¹Í‡ˆ‡ä=]!Ô` žËÓ»pÚÔ$àtÑB¢âÞ¸0E–òä³cÙÍm¬P÷I¥ÔÒJ] "eØí'1úÓWfŪñsLUJF:ÏÊÒœ@PÓká€pJ-í—' Yqªª(!‚E;íÕIˆR—§ôÒÇbAú±«H&µ¢):\Èr­t†ùëÈâTæn¸æL /i¨…TÑ{ÔIÜÝæ`CÉ…"7õëçâÄñ˳üÄð¬½Ë™äuŠ"â•sHu+Éø•¹—Þ„ÛÌ·@N‚èѳ´ß2rNŽ¶ê°°s€G£/ òð!E2`höYÏÄ&¸å8ïQ67b„Te:¥%,»#š'Xù²à^`÷Ub3­XËZ,·$ÔÂ&¬ÝJ¾ ¹¬)¾NÛ7ËZ¨ß æ;r˜‡yDLïJ ÏØ>vA–{ÞK,Õm›+Kõ˺ïo €‰ ò¸¥;§@ÚÀê0þJH0Ÿ$‘™ÇÓ§W—¯±¯LÄiSyxfS6Ž_«6ú\Õ‡ÚíkWGºqeñ·|6´/É>Y»ü¶ôÉ«?ŒfX•—Ö}·؈Á}ˆ„›ÝåRW꫈MþGcvÎíoWû‚²Ù¯3q$öEgå^µ#çkt$`ekõâÜëEÛãAxPñà4¨çO^q­ÅP²BÎáÈÃ_]y–ûLI=xäB‡b¬ŠŽñ€Wjmõ°w½Ïfb[Ð&¿5Ð^‘+ï$GÅ4gï³1Åe‘‡‹ÀŽÙI¾' RÊ‹±¹Î/Œ<·“<ãßñ²K1ulÒ „Éé8/ϯ³ùxE(€ºGm"g@Åú$AxgôRÍNæ‰|–5ßvâ8-3€jÙA$9Sú bûEe%Xß¶“TXœ7¿xtôÓ˃ž'/_ûì飤±±¹ùãG››'ÿ…ù3ûÝ^r4K'”*onýñ§ïFvÛ ÌR1Â;2ÜRÀ‹1['†Á„%:o‡iŸ-F²î™Ym2ðª@ç²A÷ bäÁAl}¶q2ËM×Ç—Rp¶ñ d=ÈïùûÁp . Hñ¡¦àÀ­[9ÚKóï7 >šNÁ_~ ª#UÌ#ÛðöQnw®«_õ kº@ÁÍ]¿f¦ø°º‡™?—Á7üÖV/_³IÔnÈßp¨ß¸ÞÿГ>M«òl÷µÿÿÖŸzý{÷î÷þÿ~‹Ÿ]åøèb ém“¤gþw§@ÿ[½­¾ôŽ·fçãñ å‡h¡ËlÉ.¨À™Âr13|!Ÿ“üRVþT3'ØMÓá;†ö’G`¯ÙHÈ2ßYp/ùëÁ«Ã§/žßÀPÚ½ä^÷ûÉS‡#>¨ä Cô §B5cV)ì/ˆbk²ÑÛÚØÚVÕ7îuû½Æ #èü|G̪¥ql‡†^Î!Ék£¿ug{ûë{[ý¯ÿ¡<×ú©¿ÿñ9ý ÚXµÿ·îšýß»·uïÎÝ;[wîbþŸ­ûìÿßâGòÿè%×·½ÞöæÖý¤gûþÎݯÔmÑ"}ŸŸÒ¾Cèð ð#Ê‹E©óÒ॓ãÄ¿YL£¥ïùùßþSþš½?+öÿ¾Ùì€ÿ¿µ}¿ß»ñ_÷¶ïÜûcÿÿ?zÿÛ½Ïjz¶î%ý{;ý¯î«’ý«²‘ÑÙ vñ1Z(?Wú&óQòÙW_}‚üÔœÎæÆ$[ærÓKîpÚ¬8g ¨ãÕÕò[›Á«Rn©é8?ì$CÄKôzÓën/í‡ÇÕt]˜YË<»ÈGó³äîÖm4“Qþ¢JS´{£6C×*–HIÁLÿ’íÛº™OÔÊâ¦Ã!1ÿ]{L–_¦ÍÔý|²ÁµlßÓ,±=èwÓ…ÿn óóŠÜpŸ­bë:ÎG”ìh–tµ@ •q4óí™ë"¹n`L]Xu»’€íîôÃ’/ºFB<5÷örÃÌ ÚÐ"uô¢ÌgÝô,=3“±!ÁHáFF«ñdd ÓëÏNNFÑ*‚ÓË~ã—µ÷=ÿÿ4¹_àgUüo¿‡ñ¿Û=sùÛÞ¢ø_óèþÿüDâýì/ÛÿøÕ&„ßI¶îìl½c~1¤s~~0µñ¿•09:®c6]Ô¯þe )ûAâ#øôÚ‘¿¶4Â]=ð·Æd{«mvTžgi0ßepoÈÒÎ ÐÃcz ù˜ºpÔ‚òS‡Iʽ2°Ãžb¥°(§ÔWÆúC°:øùçÉ<áÕƒº€fù{ºuƒ™€íMm'h²¢ê ½­4!\Éa!©‚S›B¸ ʰ¦M€šƒ!b78{³OžIÂZ1gðÜ‚ó›ÅÝÍt0› ‹‘Ä I«Ü-„ð)!o YRPr qlo_Š"–´¿ŠÐwlž´ ´Šì Î3i±F4(·Ü¶Å_P”6i£!lG·§¥G‚ÞÕ#žä#ð5Ƨ¦6K<2lÒž’8T‹û2Ì VàbDÇÁÆk IÐsè´ªª •”7èi;;Gý¹!$ø‚ð q8ð.¶ñ©‹’ÛæŽâ4Œµ8ƒÏgó"g-•a擌­s/ ZƤÆÂ`‘‚ÄØ/[aÖ³€T½@®ô‚•ÒÜa ðWÙhj\Ø'ï&,œªáysQ\üѤ€ì,FhU|pýૼÄÒ|ëÙlÃâ3[Ȉ\)¯¼Õåã,0ŸÀú•À0®ny¹ßøre« T7¼¬oqQóP5º¬om¹),ë .biùâ×`Ýz¡À±ÖæÌicŽõ5\€8¿ðÚ°¾Ã9*U¦†ÀM—‚ƒ+ô\ÉÄ©F$›Øó>RAÊÝèj‘ø‰“ä3îÛ|–B¿­#;1.ì•hzŽJ¾ ÎZ³ÄÙV;~p“x‡×ó,šäÁ(›äY„òMyV\à"ËÅÑ†ÎØ8kÄP‹,:Ѻ~tt]V+]½ä¶’à§eãg+’ªSa]T!¥‡7Üyz\eÐMëHSUd†åJØ»<Ò¼~êh¸:,UÅšßð³FÈãM3Ëþ!¨Çð„šL't¢$—°DÈ."©YHîºÍDÕò°H¡Õ#‹àêö¢ÂAÈ|Û¯Š7ì_=À: ]eòYUÒŽ¹ú²Â ¨6v_ÞðÈ}¯?Ü?"ª’cPb“…¼oxa.è‹ k¦˜vëF¿&]’‚ý®…°lý&6jÏÛNM°ð3¶ƒÆ¸WÒ„ Ü X ol´{®‹`ÀÉ03Þ:ñ@=Bð€½£HÈ U}ÆVOrßTHN-KhF`ÃP‡oñIîB ›•~7µ§ˆís’‹ŽDayŒ%å[õX'õYc¬oq­É®ÆÜ‘M^éÝ ~Aé³è?ó¤_›SGÇcåõÃeÑÂÓîÒ‰hàD4t`ì®ÒLÞ-‰qÈ07Ý'L„í¥—‘ç……–¸€ ©çé(³WIÚ#9…TÕ(õ`æÑ·ž ZÕ>ìÞO WFºN¼ØP xàvlÖ›beT<‘à( PÖ¢\˜óÜÜÎ!;ìè™'”Ùþ?QõÁúß m0WpL"tƒÅìHåžD€²,É£.ù©Xà…ßÜõ૜.ksï@1¨¤°kºHè+ÑIÒmÈ>ihQÑËŠZ? oÿØqä·ëÔ/ëÞn0ÑîÁý æIB:‘aúFY# °Xs•y̰vVP&&L •h¸ùì¶Ç6*ûÙW(˜­%t©oëd®¥'¼À¬ˆ¤·º ÜÍúØ@$Ií{ðÌ¥V\N•ÁA(™û!Í Šœ!ÊbHéýóœp†¸_æÆôÎSº²ÚH1™döl±sœÁá2ä¼?žke+-1;uj1`p‰$ò;d¨€ûÌ:2ÚYé)4ì €^8.ÞÁÛ&j‚9¯5Ìy6Ó£¤áM2ëËè†yžN#xÀ-™òª`Z7³^/áÎ`G»¤Ë•¶ÜqΤ¬ Ë0dnßLÖ¥á#€ƒ¿\¤wŽg2g¹»¾¯’J(͆ZX')úXÍ{¡‚ ¡¥aù1ÖIÍØ¸2Þß{ÑÜ`ÖíW\öïe1iIbSí¢t;*!·Ñn¯’Åkê£\ ªÂæ2øUëÂZ>€Øû‡æ¿÷ϲøO‘û~VøÿܽïåEÿï»wþÈÿú›üDütö×­^Mö×{Ÿ ûë±÷òª¹_‘ÛJzwÔ[ƒ$8“Xe·|OtÁl}\ÂØãàµôü1 ðùˆN«Ø{ÚžÐnÅþRDwÚ¢µo6phX ãz1°Aôúéie®Ì @¬èìKA˜îië¦ØjôÐÚÈŽZ‘îôèØ>+®QéÇ:ôoÅcÉ*Í9m8~…2?€ï'ßdç¬ÓÓ7›æ/LæH>PfÙzÙ1’üi:Éÿž휀5ƒµ¦ªÔÌË \i$—Þš«ÚeBÎ'íaSÝ$Ú_ÿÁ³¥MdfòïéÐJø€¹Z¼ÏQ¿¦N ÅD¹è$9¤x X%+ÀùÀh&‰°²(ú];CÃÞŠó %TS ‚ÃçàÔËOmÊ%¶˜TºUCtTÛ=DÁÑYìü/fUQD’ŒÁmÄà„h&輘“nÕbçƒ`Žô1`©x@$–øBL[ê|]ft%û£E"gåb˜ ÚYΖæq؃÷× è1nÛd»ûš¿gþ!ñ>~ï…=_¢i½ ó¾Ú†hÜŠÜ6þî£è)C÷:h‡0“ä•63“›©®”’i‘¶yNGðãí¿| »On½¥ƒ[¬Ô¡™¡ý¥d…… u æÂ0{OˆE”‰Òl)V Šº·³e¹2eO' œ ¯‡ÃÂ쫼n’ Óp+gÙ@îéÊfÀÉ<7XÚ·˜TÕ0‡f[ähº·ä缇‡vÉT#lì&•§äe¤ÛP±.ó¡E”3?Τd‹eÀ‹e¾ 2ÞµÝ„ÛøU9ö?q 0ž·'Ò•Š'q ¦$H\Wm«6ãlu¼Ç‘kTV[!­É·Oòɬ¨]›s¦”=ùMÅsCY1A|lÈàø¨ŸFÌøÅìh¬0;M¸‘ï(µ¨ÒJ³wŽ;•ÝYäyHû¢DeE)Â4£õYm\†E’Ƭ¼ÁêÇY¾ÁH‘ð |h}sâ߀Ìýξ¨|*úZ§:ã Ï;K)2×ÏŠbй¿Ð› Õ‹fñKb”#9ä RØccÀÅ·¥oPÙXAüÐ⎒X00‰äޤ~I^¼z|ð*ùö'(Ô`Ò¥¼€ê…bº©ï$3Ô2 A¨E µ=ò+&é}–%E¹6¡’ïƒ ç¶*æaù#{`—÷€ç3êÍÆxÖ±„×Vħä©I8ŘüAâØà, I ÇKðǃ’§Nûè*Œ§kRýÕ`í¦“†Øý^F¹ÜÜc—"«] 08:I´mí/®“hÁD9_ÏúIe›·JhÂq´ý&w“‹¬iß܆éŒn,ˆ°8–¦µ¸0œ©ªÌ°TjPGú¯x¢'CuY+W¬±+|;:‡®!‚KNàŽŒTI$KNïèØøI¼²±Ã¬AÀíx±5H•qÁ;Q*ð, O'†±´Mž¦Ku‚Ηž¹O –ÐbÛöéóÃWGÉÓçG/ˆÜ±í_ÐɽÃb}'¡uj'¼KŽ»øö¸+ï»T³Ç›ZŸ›3ä?^<}Î)ˆ“ @ŽwßãΟÀ¿nÓGû÷øÕ‹—ÉÑþ·Ïìn\gZÃÕ“¹DŒpÒ°a€5wbowõ‡Qà 1™ØÁûÙõ„Kä{”i´á­þ#ÒǸà¿d#qÆtäz²ÌrH§ú„¦®qÚ3_6(‚ÞLÃãWªùÙ ˆkæV¦½a©€¸Xšk8fTÏ äÜÆ­îƒe‘ŒfÅT¥˜ ÕÏ¡ù|)yGÉçzÔ³ddbRÂ#têRŽiÏžä3ÈýÆ×\qG¹…®¼¢“Ó‰‰Ì¨¹~þ÷’»½Þ®—J&‡ 9sD¦ /˜ççÙ ‘ÐâÌ@P$êö2‘h£sµ­Óñ;'a#àÅ(ÔŠfÀÒ[8#‹\æÁ𜼄T@žHÄõœÈ`?É•›@wI}qŸ^P½(hHú)̸†p“è$À[vTdä낲ˆP²Ç€‘<´×%y=ß¼š<âñ ñviØØ[©¹íír•òp½%d²×uØ@¢U*œgÃâœ#hy*P›bùfzKÃL‚â±W`ÐV½rK»x¬@t¡ ç‡Î"„ƒ\n¾².m2$KfÝfÛÕû‹ýÍãc<1¯²´KÏ¥XQiáèÞ2|n½8Eödz®4# ›¾æŒ “÷çðãÿbEg»UÔî¹Òqúåž¿§—!&_ÑËq6W;éæÇÒ3S³R:LrJ§å p½d/O§ÝÄMàVm¾JG+'î:ûUp¹—ÕÁqøF¸ã ™qýé=ŠúkE®½Ï!d©ºUŠøÁŠ‘p\œœT÷–r>-¦+4ºZÛç”Î8ìœN€¦ŠÓÔ{yù¯†Ÿ[ùO³ô‰çLó«Êwõ'U°sž’FŸœ;m,3rÍjMà-k–}œÔ^±£ ú_™§ã.|™ì&àQ÷ p‹ó/4qx%©= cói€î‰3s·ÚáÞ ¸=±Yæ|[y8Öå5Eý;)ꆕ?Zo7|åàܪWV†úÿeU? ÍÆÊØŒïйvšrÞ碪R¥6ÏfaùÛºB»â õçÅpÃUz¬+uW¢úÙ_E ä§m(Á%7bB ›eoep5ÑÑ_-¥nWÂky®—å“·½†c™‘]\ž;Ädüç?H¶;+ß<Í—_xù=A'ø I͆ùì­Ñ놟ÇL¥FÀȰ „är˜aEÂ$¼”h¦DË((…½axé´þwóV ÇN(ª‹ä¹ äÿûÿü“&$6V\‰„¸Ôï¾N Êr¨õ†e‹W¶˜®’Cd¨ÐbJ/®2akku_ W;o–wW]çß4ëa¾Iþßÿçÿ·Ö`Xh޽¾a߆o~oiçŸð§>þ›ž|Š6–Êÿýþö]ÌÿÐßîomÝ¿ùîoÝù#ÿóoò‰ÿ¦…G™ÿîöÝî¥úz³·µ¹µôû;wïC: :ÉîÚ$€$‚¢­aNÀ%ÙuvˆëaÇ  ø š.Xý©Ã“¡ ¢XMg§ ÄG­ lÂÁ‹Ÿ¿~öÌi¹EöP†aÕ€¯ÏÅz4øòší;À7hÂ)£Y?#€æµ:¨4b±b\9‰®ÛCD ÚöêÄ!¸9\£ÊØ|ûÝ)Çå +-&Ø_ôÓöÒù2-aΡ’$®Øœ…ª²u{ƒn5zeªo=J ô›Mß°Ò Á)q# ½©î£x(PgY0›þ*¿ ’}î‰Ä»oln‚|£¾5ÏRŒòbn‘TíGËÒCßæ¬ ^Zõ°Ø¦Jõ+wA n°±â§+bÅéc¨2€²Ín1A±šå0½5ƒ@r•²´<àîºÒVðÄY³Ð¯€3,|òMàZáydáì¾æ2¢Ç‚~€Ê-¯c¤gÎØôci0ÚõÐ_ÇT (§æÜpL\«9€ÝFæUâ,ÿ ú÷Rªça?ª8 \?Û@erø“u¦æemíñIÂ6‰W`¶éØQ”Î9¿LÍ)dš?øþ´vŒÖmК‹m¦‡rq¼aákëfU‚ Ä„‰“´G¾çô†v;dc2SŽ{d“7ÓfÕÁÁ›r.)ë°I?¤äe±˜¡„Ó,½dCìÆ:A–[>t!ð4"Ò“Rôè¨ßâÖCBûÇu±<$ùjòñ°l&61YÕ’éx†É¬ø±Xô‘<>x²ÿúÙÑàÙ‹GûÏGû‡Y§=ÃTÁÙ¦\Öæ¡”©ŸË ¥ƒW²^ É·]h_möQ¢E8ÖÓ¥{°5ø3ãψøÕ§X´Û=¸f_e’á|špcRh,)~­é…XrÊï³ë7@z;Og8ýÕËq'>áfºŸ}»ÿè/WžÛ+1ƒº-Mvƒµ¶2OÇ×Çsøú»ïžü’Mä’ðÿÛ›·+£«ç”YµÒ[Õ•]6ÔúÃñ ¹dÔäÊ‹ÿ•d K–•‘—W-l)lÿ× õþÕyËÖ'˜¶ÍšÔsqé1bSô)X‰Âz6¼ä*Ì_~ì<_›qÿý½ÜÄ®¯»ùNî'ã#Wa8JÊJLG̲á’ú ƒJ§!øE~<S<Ŷ…NõĽYó¶S¹ìtÉêt¥Á¶F*ÈÙlŸS‡,™G‘Vï™0–V$‘Œƒ*Ç h¦Ô’9\Cˆ6S97B4„5Kg£æ€‹2ytx‡u„Ït:.¼ë™–ÕV‡ ‹–ÄnØë.$nAê3¥×ºù£Æåú|,˜{¶³:í9(~çÐÃÅ$‰Û/g/¹œ¡n­“*Ój]F2êέb À’æu”1‰\ÏüŽ8:V½ ˆ×Ø/Œ¾¼Èª’Kâ0-3®tGT øå›ÞÛ7Mp¯Fn"ЊJù¨¢Ply–ľ5'Æ_ 3xôýÁàåÁ«ÁËýï’V¿zñ¬ånSKïpSÙÞ‰!z÷´.Ct1èÿ ôÀH:þ•د€#"`ü“^²S“ì ~ô =¢xÁa ÎrÒðÕñØBÓ€ÂGÿ­úFS i¢þ.øË¦^pQáX…L€Ø°2[ŒŠç¤÷=}ìeãâ4)¬Ô·«ó`ø9ŽÕjh.bƬ'Þ/­q…*›†39º¬!h”rü¯ †µAŽÒ&ÙNwT™º72œ·B=˜<‘³[î(…ÃŒŠ^ê!/­¡žLï‰x&81s.fÉE†¡ð/†Éb† †ý” A&1,šë~OXFԙѧ%§ÅXLèU„9DÚ P+LÇ kŽì²:[À à SH™«XUºC΀úöhtùB×Z3·¿Tö’ˆ+¸—TšÊPÁßÑýˆÆ!Q×±@DÉB‘zÊ?ðX‡ÇñMÈþ<Û\<‘X/|t1Ë9¨É¡_“n5vo"Ñ{6ˆ’EXœšC q%‰3©ïZ 7%<±X‚ &8ņ4ܘíÅ£uIVzím¥WÞ†2Âî³ç!Ö³@€´ìì§ s±ʳüdNž;^+Q¾¬hIÙŸ:T¥P|´M’-.NŒ*ÝEv’fs·Bòòoí9*J¤Ì¦’¢ë(­“%ª0ìD_¦Òê}¢_a¾3¦­Òê2è4á¥Ò*ÎÒQ^”:Úç3OŸ Ü!Þ«Þl<Øøýž=Ä.uãUÎ~¿¦ºaÎ@@€®™j H-‰[:j§âYÁî}IéáFKÚíQB²‚áÀ~§T.»I¬áÚ­ßüï-Fö­$È~îJ`w‘“w„…"Do‘ü"9óT/ /àuÇHp „¡½„OËi6ÌOòa0rÇù8ŸCNÒÒÒðÀsQW"%ð‚&Yyrw¬¢{Bæà¾«'B·¡è …Dy4Ý®…`\»a#`ЭáU ²}l+ÇFxGaîôäd‡ÙÅ;œ—„€|Eäàk 8xªáØÉœf܆™x™ëS¦”ŽHÝmðñ àŸ-4Æ(»é›¦KŒ£MGpÛ·5d 3{^)Æ-®ƒÞÀ9B£áÊýi›ðn‡¯(!ÊLˆï W5A ó°´áþ$)ØpN`âxËÑA%ø{¹F–€#E1 BÂþµ°ešJsf3%…×C-™Ã´AÕõ-+àX{³/Û7.ÆÙ> oK`7?=¢j¶t· ªá$(4ä³$¨_t’óq÷‹uá÷& ¿ÿêB:ÿ|œ¼x.{P=þ¦5óI«ÑÅðS{«ÙAEËpŒdÿùcSP¬åIßAÊšÊH‹Ýv€ 'àɤs©ø¤oUMDzS`öéo~¡ ‘Âm¡ë°˜§ãüY+²Ëì—–ðÞÜR‰«lƒË ·ŠÄW*uPÙ™ŽçÙŒµOJŸCÑޙŲ)۪駹aªø[<ƒºzMKF=ø¼šJþ {ÅHÆ0”wÞ¶•›ˆ— Œœ*tQ•†ªÛ$'"v¥Úóƒ©ePIà]™ ÞÐñü†ÌCè^°·®öt×îÞ›ü­£¿ªÛCÜ3”–»*’èá¼× ÅD:y‰Ì@L,öê :Û)óó|œbnŠ È!Aù¤ÍT,8Î;;¥ /]µ¼Õ”ï–I0#ã,}¸Ñ½ÛK$…¼f äKJßW0GdŸÛ‹ºh¼Œ™Ê²S—¶3ŠÒ¹;=Ñ‹ò"•ÊôóÄpx”—E”P{DâËK>k0ÌÙL­ú`?¤–f@ŒW£Ššij'⎯j”Q”÷™¡AÿëbfäVÞ2¿ð|*m~=Pñœœd˜šƒÒµ&(^ ìÆ`ø!…µ9+KˆåP–®Yö¶´# µQ1‘³|4ÊÄ5Y3¾<3„x’ â6 ..È¥6hãb4·Ó#T×(¬ÆÛPáª¯Ê íÙmªó2/!.%é%šW×wBiÌsâþv„î¶]¹ ûIέ€Wzš¿7"'£€!Ð ŒAÉé$ Ô‘¢TQTÅCOIµä9ë ÎC哿 #ã6w¥ï´Ó¢ºöüñE™ˆPŒ?C-½vDŽòd'…ªä…öœŸ-J K|å“Ùxã!¾œc|wURXí° ¤2ÛsbµNô7+Œµès#¢•¨ÄùsëºzrsùìûSÊÇÍЂÂ+\4…¸LVRRNøóg©‰:’3É`ÜoW#Ê`Ì¿´Ë “°Ó­T{Ëb Íø’ÖßKBQÓÞî:5=ºá¤ý» _£çÐ w±ÔêÞºUÎ#øÀ5lÇ“*#'ÖÚLGA÷.³.šÉ‡Ûaú "BPþ¹Þ!×TäÆnôtÝØ¾Ú‘¶Ì·géY$*Ñ¡÷ÖAÕ;|Í£"ñ+ Ê#gn¤Ã9/)!ÇW5 ñItgÙØTàT†FÎ ãg¥µÖQ€雬ÒSë)Eü2›¡´‡¢ûÚ_[l4ù³TˆO`ÈFHïÐ_#È÷ ïÉåtQ)“Q[¹˜1l©Pn#޾¢@áã™cXBÔ/Ž·=ãú…² ${ ÛµE¿`aì±#è€í«xæKÜ¡V’ÞÆ0Ÿdþlü1õ³§4‰ák×ÄøÂþóÒ1pª²‰SÝ.‡áFnÂâ^Ãí‚3£©± ªU<Õl¸›K×(Ì=P·Dh° L16 F†ÕœˆñÅÆ‚Z‹Y<§ñÖLÓ|ÜN¨ŒÎÑÂüQ.߬E}’æcÎI ‰Åý$n„LÕJ‘>§~ðªÅ‰Cz"ù¥bò¾PYÈ(iH3=WꂹÚ7XGÆE:bvá6g~ñ”Z6«ËýŒÓåé©él>sônbþýf/Dþ“¤S÷4¦·òÆ[(úå—–ã¶B?¼¦Ågö›ÎN•éß«CN«z÷„óe¨øÚÐŽ¦u0¶cO@Aíò9µ·²+¤ ¡Ï9/ˆì--XS)îÆ ù?ik@æÏcÞš7G]¸Ænâí{JÚªóÏ\EaX‡`GžÎGq#sò÷y#Ѭüºô˜ü™š–ÊtËð•­Ï*K9Qûkóé]J>¢.EÕÁÇk¨1¯E¹¢O-O„6»á3'œýêKVÅ”w‹P Q\ÑpdQoRH'—mqœ;çê,„¤™>j)·¹ÐìÔÇüNÆéœ‚ÒCÛ’xA‰$…¸Áë7Uíí[}G}L6âÅÛFIØ.Fà}ŸNæhi:q|²¼,Aw3˜t>Yî¬ûáy»Á1Ǩëwè…Dò3”žgž)h´S_EU£\SÐ÷!cÀäÊeý¾ªë Ôwôsì­‡U}Ð,‚¾fÎÇÑ~ÉoÄPçYªp@~17Þ /ì&pOv'u¬ó^ažî(>ƒ›Ä'Àa9)žc¢•÷5‰"Ϙ•=á¢OœLþlV@¦V‚ƒK:*âTÎq?´ Šp 2ÿ’1öÔâÝ·|¿î²¦óà d'ñ=à(X ÙÎKõfZ`è3Î΢ä„o@HY„Ãp5hO(䤂™I8J‡–|;Z îÐÓ6\ ¡&·f¿ØÃÐÃÃþ½éDõ½ç ÊìEËø*%eµÛ ûZ¦lD ¡gÑ]wL¬_Ùpὕ z aTÐSÕû)Ò wåâ7òlLÎ^ÒÔnŘœlØL^°lµH‚»\r#Ì¡_îšÂýÀÆÌ àºC>!ÖÄbú6šŸ °’‡o‘œä¤ˆNFY6…òÅÄFmÈjÖîhém6…¥Âa“U¶¹AHaa܉d9°Çõ*+ à÷Ûvÿ}òͶî^ã™g•­nNO>fÙñçÞEiKvQõÑ-ƒì«k/ÅÄîÇ µÔxãûجäéø]¢“äÒ’-&ó| ¬ßî”`4‰Z7v~ CˆÔ©ö‹ï}‹ö½5+È_c¶jÓ¡É„Р§®ÂyŒ¨ë%Ò½’ë:÷¦Ußoò$ ´zJüMúîú|4„6zÉ.á+aøÞ&ÂìRÇ£ä¥DFÕD6øB9Ò1’XŸ Âv¼ëùlÜ÷,ÈÖºÎÐǼÉ0$Á˜IT@hh`¸Î硎›&ÿ;sY+ÒãÛŠ$OÝ…”º:ùãSÆÌ³w|o.$B¨ð¾¾1“6™?ã4d47ïÑ@[7$]œƒ?‰tÏÂK,XO“63PO;”ðË^í>UÓSï¸sãÕ عO^lMö@ÕÙ °Ñü®U"l+Ñ“+zä&ÛoË•ø¥ÒûúðǸã=“ÚJ§{¸Ý¦ÓÜa)ìƒgêˆáËTD(¸Æc?o=Y:ljÕF›V ¶U£C xðVÜø+‚wŒ&0ÇYüFÌ^zÊ–”zÔ„"ÙÈ,ðå)0±üE&Fm8ï-y  ¸¹gÃ^H䡌› gìåZS§¿oFõ÷Ç× Dqi_›¾úÕ»îéžy›E¿Ð‘#þóx‰_F™†"{ÆùÈ×µq(5ÅT<ŠE£1%ÃÝlcç"ÀqtÎzKó·ÇÈçÏ1¾Â\Ï^<>|ûúé³Çƒç/^ý°ÿŒ®vÀôD¼©@G!‡~¿¬1…½PëNð¹ç•ÕÓo]FXK'n ¹ºÔ±Î;ÑjOº:0…jES\Åh·1 v•͕ċÁÄH ÀƒAõšÀ­³•Τ˜lHÈ‹‘<ŠY©³Ý.'…›u3ÈdOªÂ¶ *ø`$¦£?€®\ÌÄÕ9â)ÜPèo+ÌëNFÂe*íj[‘R',HâÖ<ôˆÁ§vÖš¢p_ÅM¼èsã“úY^¨4?¢ÒÍg h„E™£Í#íY³C*ò>™,ùäÊ&åª~¢ö? ¨vÐÍà#'=æLmyæ¿Ç³Ûú6úLyžåÜ›ûzƒNU‹Ž9Òôi'' ÆfF9ó״δ­îÏòc¥J¼æ®•&GB¨À2çNxz桯|S¡?ýÊ#©zzpŸ¬„KqÖi"×)îäÇfqŽ–y4—Oñ2Æ —XÍx_Ò#ÉÓãT€ÏŒ0X,îYz­6yè}bÔëƒdŠrXÓ9øîàH¼l´ç`²87b̰òºn»5|pë©vôF³®!ˆ6¡)G¥Ê!E){q°ïÚÛʈR²çû±[ÿõô°_8jÍ'>Gu߹ǫ6-fsKaÝèº~)Þμc¨l«iõÔ]•e¾âÄ["oCgRÿÖX_2‰qñê§„Š'N þ¼èì¬1:ÂOoÄ+(R+ŠÄ•}Ÿtõr‰ëG HFí¨¸2ѹ,ôÏëK ÐáKHàJ±‘ôÍÿ[‘˜šÀË¢¢ð|¨¸»<̲qŠ’3öÄëÃNÒóÜ)Ÿ`+®ƒâ̳`’^mr’S˜Ì9û èĺròÇ.á"ƒG#:®«>Lž/B·ªÇ*¹÷â©êßÛq¯x{x4WkH¢‹tšÿêýJ߬šßL9Ôí6a¥(‡Ô;:D»Qj|;¥MG(žËb‘`Þ9Á¾sn¢¡ò]œ€ÍÚC¬ÌCRá^·‚O;_¶)oú@E†h_a Å©^qÈ©ÎrG)/'NM©càøÊQÝ>?½5 ´­Ü{ƒAÇz>cy<.‚„àÐÁÍ­©Kë°,^«·1Úf¬kÕx"Õüô\uzÖA>¾bÔÍÞKJ+貉Zï€HÆS‡<“%·Ü4ï ºTrü9À`´àùJšRí£ãXÄS¬jØž5Ò!~îú%h¤Ò7öå•üˆ`$PÆÃHû$û`.ÐÁ” ÒÂ\©1i#`<†i«•˧ø£=â*…Þiþº3Ò|âq\­€jGëXÌÆôª¦½Ä®•ÞòS2y©¯0¬Í™SB«—o¢‰~Xk‰ÛUPìõžÐŽÆyT~ s›ÅØÎ*u9aUø"T ñs†_цšÚÐàêUî¹j,’^’Å=)\[´f©³zY=p¡ªƒ‡~#t¥xÕ#ÛŸ*–R¯8Y‹i0U®æšÉ²I+µt\?a*odʸӵ“†&ù½¸Õ]»vCÂH=ðàÊsù³aëÏ…dÀdX ×­™êlu~ w«Í¾êC¦¢¹áŠŽÍ¡‡ÆX\øè10,PûÉ8=µ"ï#û¯5âÙÍÑI4õ»€Ry§º“¸¹‘ßéúÊ«™“\=QËKè]·è½`£ÎëWòWÖÀŸ>žq%á ^Å$ƒ,å6bPVFj§î)Ãtè{²oä•~|÷Þ3oTAf½ ÍmÂt ¼øÌ[îû0/Ð¥nk;÷N{r<ˆÔÆSôao¬[;A¤“Kv"( ÂCLU*·Ño‚Å’4a1×A76½ëÍ —xÒäQ49zffŽÅüä«° ìwÇÈ^ßÿõ V+ü½å ÝmW60ÓײŊ™L—£ ¢,ì€*¨òèÉ\q¯Î9¹9€.#8Ö%®Öm°Á·ˆ³`K%<ªèÅ”ñ S5èîˆ÷t“dŸ©‚«Ç—yiñBð+ªI. \ý(i¥ãÂÈŸxÐ!m¯7jÙÍ[ZD5tææÆ°SWnÇs!Ÿøãì0¢å4Íg¥õÓ2»L£0:<Ô­ZìFKpUÃsJÀêæ¾±Ô3"æ{B2§iÅ×-Ö2šæjª½¡ìúÅpÍ{‰Ê ùI/&¸ü»ìþ{]¹¯D:²æ…E%Ô¬ÞXNÇűÙ·ŽÓ2ƒ³°BÓÉéÂ,{UËÕÕ ×ÎB?ÿ–’†ÙµÊv#^j0›ZZm<å3FÜÚÛKží?ÿîõþwƒWGÏ*]:ËR¯sy5`Šð¢å][f)$VÊT¸"Ð20t|Â4LÄÔf Í6ý…~[6½†ãÿ(¨0“jãØ6çXÉVÛeL–35‚5ÅEÁÑ(ñ´¤OÉK³§öXaÛ{.Ã~1aŒÌ%v€¼·2_ D¢ˆ°fÀhPµñ+dV¨†™G½"mµn .f†É×›x9l15¯ð+…ðÆ:HèT•íÉÄ+0è\U‚“ƒa*¶Æ{…ȉ1®ã|Ñç&H–Z-¼°Û̆M‹zƒ°n„·8¥Ðkw°\=ÖD'}­ /.LH"ñáÒ|OR眸\vÐßħ(%Ô\9QAµ%3>@(¹²¥?ðZæ9îî!5 ÐH…›D}Á6·Žëç*«„Uò^Åô¨kÛzQñÈ[+ }Ȩ¦˜·f$¢R“QHÔÇ] g¿l\øÊm¤³¡0£¼öö¥ …w%ƒ7Sê=«ª%¿=r?ñô´ºq8nŠ& dêöಹFÂÕºqߣH;½|õôùÑn¨C§Ò|âJõ¸Od»ìªª ³-í AÓ!ªu®Â“+<_£"Èe¥Ôõt£…Ÿ ú“ "B0ºÒš¬«1 ¦"¢7U³ÒjåD¼AÂäðL_- H5d¨((UŠxã£K½fuF³T‘µÆå"ð±ðØ¢åÚ¡ÕHÆ {)¡´2¸û(!{G4ðÇXYé¬"¨¯oûºù%ž­ø¹ómåo’$Ù2O–èZà(‘œcüc¶Ç FèŽV" "óÅà´µl{Â.¬<7–¸®.ñ»‚Ï7^¦nÿ,Ð#7÷î qav$ÊûJÖš¤št4âßyÙå¸ñ*‰f8_¾–Êó CaÄÕ9-m'h0pÛàx/¹{¼§oÔüPð·ÿÑÙêY£«vM¿U‚ê¿ó2" !Âù¨Ò/5ËÆ.ì©õ%ñóü¬™x]ÆBûŸåÃñêÑdWß×ìcPçÅszã›[` $D€À^ø›ŠR&ÃgŸáp]–+[ËðÑ™Ç(Åy‘‹,€ð\°å|¶¦éUÎD–cróäÌŒ6Ï>`ÂsÓ›´¤4ѳ¬,³¡$¹‘IÌ7éd‘ŽKº=™e?/–k¿|gšúÏÀdŠ£õdÿ?Ëv7y:†už£ƒ¨@HnÒ{DÈžÆnª+é2 ¿-ŽÝÙ|ØMöó³bF YV[–ØÚ²±ž ±-½ñ¸˜¡K{þ´²E05ò Eé βëÞñ%"+II¬¯ªKƒ›™@ÍN¸$'кÕy©±Wq™Î;΄Š\°¨©à(Ìç¢VŠO Ká¼xO=tÑf°€ˆ[JäÖØ#U‡FP Žàò @x\0$‰Ÿ%Ç}ô7s(Y²ê&?’Á°87Í™Ëj¸Õà8ÎÖ‚Ÿ›©ÎeT®_€ê‹ó&Wâü9Ôì7i¶•½ÆŸq‹l`‰Æü ¸¬·4|ýýf3} œôghÜ;o7”[7éU»½ÞòškÎŒ¨PAÆÁPêòFÓhP!)¡Å•ÕVzAïf‘V/3’HÓˆ€Ö@ /nk»­ºÉzTÛ aá¶“Õ¹,Ҁܞ´[2E‡\ÏäÒ9EÂe3u€ <€aÐÇÌ 3N+ÿÏ,ÛÑ(±Þ|»(å!NÌ "¨[ c&(oHFÁ½¦NZc½uÞ÷üðqŒ”ÀÎKǃ"G©¢„%DçuÄj3K½Ð}µ»ß&U$¹§Jº&IT Óe6™)oø¿!}”ø*ÛÀv)Ü ¼Z›"Å®5GO7ýmr‚A¾èX7„RA´_Œ¿ÂÞ›ê9M¤›(šoÝaî^Û׿Ù|>ÝÙܤ{c·˜nJÍ›ôi‰ßlV;j Âc×üŽÿQý±[È}‰ˆøé—Át*äÿÈøLâe2¤‚þrfu€.ÍQ'/Q· ;'œ«ðAQ´ÆyÑJ¢ç2ÈÊ&Œ€¸?l°ÑßÍf€3ÍZ†:Ì}IÏWÖÇ¢ MŰÚ÷…ÙЕsf’\ l*û¥³h!°M“ ‘çKtV3ãÈ'dú AçáÞRʬ@5˜Ã‹  ùŠNt¥Zñó­AyÓx0ËÒ2LæùŒ½–.qÑ®1¢ªªé*;LËš §|.)°¯ÙD€É–:+â)ØÔÞì@?g‹>]¦ ÂT^… P¨Îi};àl‰iNtV 8¸ÃȘ«¼VÀæ°#1ûp×ȈÅ>;xr¤£É-ÏT¥Ï» dSiå¯ç¢8<€Bì¿U”Üôf=)aóÒ øâ óÎïúªÉ t›`dábÇlè kÞcVÀJ4Q` °¸¬;äXnËØò¥Í©‡:HФBÔäÒ‘Øï]ÖGP¬`Žy&k$+‡±íF´(_¡u>^Ú5§ª)ðѸÄÖÝ ¡¹²KIØzìÔ©µ‘÷> ®aø®²[·Åð;'!Ž>ØÊ[C q›øÑâÞ²VVœ;lƒàrÀš=¾|ðÆ3è6w¸ƒ¦´.ÄÁ 7€ü,{;‡˜[ÔÁ=ê(^¢¡€aFôšÓù²¸¼ Á¿7 eÅd8,O§7Y:6ùï‹r.48Ì2:5g3¨®«±¾Ó÷ âÓ±9Éä„›K²ùì¼Xpæ&6D×ëèP¯4X‡M£ TMzZ„pñËԦµSÆÙ|í>…8GÁÊ zB8‚– ޶ %Ý.› ç@ƒ¶`•¶\Á\xJ@Zà"ÖC8‰ÞüÔ#-Úΰ€ª@½Ï¿ü24!Ý*0‰†-dCõ ‡b¸Ç@64¨#ºóÂ$§þ32ý \&ûÈ*å;xœf^!|àá Žü‹W˜žø¥Qã™m÷WžekR¶Êš“Ð^t&Úò+ñ)“®›n›rÚOöYq‹ÿ½ÃÿÞå·ùß{üï}þ÷+þ÷kø·aƒ¸Ùxi]…w 2a+`fGù¹)³9‘1ÕJ2‰õæ Bä\S,c\ù–ׯN¬B õ¨87—…Œv;ë‚·û-›¢†¯Äõá{(u>Ún)°â º7ÈÇDŽ0üS?¹ r/r\ñMécÀ4õ^§ç¥_úÖNûK¬Ÿ0,±´Ê³tÉeº<ø`›oØ“Õ|)½W]¡^Ôt×gј䚥&¤gçy|ߟŒÐæÅQœk:§ø!}Fâ¢v›²EQjüÓÿáºÛßóïót£QmQ’"Ol¥×h£g~îݽ‹ÿöîöý{½þÝ»[ê÷î÷ïÜÙ¾s÷ÞöŸz[[wz÷ÿ”ô>ùh#? @‰L’?]\\ g¨+·êý¿éÏ7Áþmöï­§£dÙÂwÞ'ýn?Ùêõîoöû›½»IÿîÎÖ×;½¯“Óâ8M>L“[ö öçy–ÕG†gr\A‡¾ÊÏõlpòÍ$t]º4OsS3]s(' ,9Dï~kÄ™ØDÈ],çs<á¡$~y ÉÀh‚àB&è$Y'=ˆNOæ<:Eaí4£ì}(¶^4Rª-4n±‹FàP¢¹Œ3ä@yä$™ ùù¡sûR“µ™3A˜å6ûÂz•<;V#EìÀç7¾YŒÍÆùØæ¸0]Oö>?ï&øû7›æ¾ÏÏM»›ó|´Ù¿Ç%ʹé¹+1O?“âürœ7ïÙÿúË­Þ—[}]zÓLñh1œ—›FÈ™/OóÓÒÕ€²;\›áœßnB?Ýu:jk ‰!c¢VÖóñ¥²ÊƒŸ¿Ð»%• Ç%A¸.E>±Ð™æwhV_LŒEØ‹%?gx7u“Qœ?ÂÊÔRi{~Qx.k»¯Ê fmc”ä0…çFvó;9L§´r0¯ZiÖ|u²ƒ¶¶çE^žÁð“æp|‰aa¸Ù\ntk¸ÀJ¢î`=°S.RåE…» ëá;Åaè”ë·ÓMöIÿÁr8óvòгßÂEvl¶÷ì=¤Õùy‘ó]†Óê,¬=Íï!4ßxðÒQ~h‰u(kx Dq òò8vhÙnð[BÇ(À¥ÁÍ>+ÆI3Œ‹gCfy>!'†“ÒuÑ,À9`0â'8‹ÖÙÝBÊK:ÌγóãlZap7Óc3¬¦°ÝsÈŒwQ¹Ÿo$© ä3dÑï›™v®Ô ðw0½›®u“¸AéOÁYÉõ\î§ÂBç›øo¦£Q½ÁÁ„ÓæPcz¿1Wpc7´ÔaG}ò@ø-ö”Æß{AÑàÔYÃû3šr¥zCNøˆðô¦JFaúP‡©ÓT Trˆ†é;Ч›ø¸o6iƒBÕ%:5 ¿mF·ÁÕ O‘X65:Œ½}",-—fý©µ{èÌžqmsz‚èåêïbén>6]Ò⚉A$¾e³s@çŒi¯¹Ö¨°¾‘ÍîŠ6³GûÏž}»ÿè/?\Ô\2àÇXbåUȥʓJ%£VsähÙ1ÿ Nèš–MÖ3xíÃãƒ'û¯Ÿ ž½0½íJoªUË»ÌiI0¹ðïLž•1®šñ¾OKéQ™bƒI9à.¡ˆ»ƒ“ b|P—¹ ¡aŒSÕ`€š¡ °:*Ð)'HeJçs3_fz[, ÓL´ãÌœ¢Ôò¨Ûô£rá¼Kp GtŠèKˆäx«ctg—…,:XÄ“†*éÚÇÀÆB²ÒˆøÖl‚üà×f*Fˆi|Dš”ºÔK|$ùež`Þx@‘§”±'ðû¬—èÚ JTq§ª@žæÕDQm÷Ã`SRXÃØ\US—ú€¬ÃÊ”s ó¶Rÿ<øjÏÒacðó1Rí¢âTb=åPTíA"År6dGŒN2*çöw½ŽæAзF'±:¨K-|¥×6û/Ã¥ši· o­…݃½‘dj„Z¼p|Ú˜ŽNU_|ïŸ#‹¬ÃÖeŠá}Ó1’Ób>3„(–‚÷"Wè”kîÚ€!ôb“YÌOЮ} Xª*ÃÔ'^Wbù¹VGXûJŽÄìòù\®] ¦;ÆäÒá¼ü»j -3 ì¾ë·KÄKãqÿm/ézŒª,…›0$G ®ÇËw¢?+&mÝJÝŠÊ@ƒQ1iÇYJÎ3ô `°‰+§!›Ö&0ÿÈ:Ú³›3 â5óÜ\*f)àQ!ΨôPÊùÿ½ ^ˆ%ñô"V½8‡J’âÅ/íÈŒ &ÉSÀ¸É¦ÜMvýnîÁSWÕ)Ë1¬+!Lô1±‰sNT;ÏQu”mAŽmÑ‹£‰Aµù3Ló^j©É% fÌgì|–Ÿ{…ux$T·$õ£¯Ÿµ Ñ·WoôÂR¾©þ˜’“§íÜÀû·€nxœ:Ë&[Ãß³Ù¬˜‘poX„V*Vž£†¡ÛôcÄ­9Ò›z/wXfe,uH.kEAð,6qs/ ySuI©D,P56/­„pFD7M*¹1ºé„Ì!ºq&?f¤#Ç,r@fs];óR€¿AƒaÝ+Ñk ZFæ8 ›@°Œ†ìÆf"ˆê^¯åjïÝvÆùÚáþø=ló)b›×w;ÖÙ Åš4ˆºžüÚH`Údˆ[£¨L«<\C…„»–ણŠ$õ>g-èÐ IÁŒ°Óx)|«ÐóÏ{âóuQ‡}t›ä:‰ºŒ½öÚrS«YCä9/7»ÊQ˜N ¤í½Ö\a³ñÈ4¥Ð¥½Ds¢þ‰ÒÞ¡$†O1úË#Ú_ø6#°fÆ2À¸2œ¥ƒzVœQüë;þ:÷:㇈_œ5l98üpb¤¶ÀyúaœMNYCÞßúêzSâ¿ •‘fòp|©MH¹x`yŽ/YÏ·J@U 8›æª(±!v´úë9N]̵j’àc²"øPš,=Ñ^m‹ÉßšsŽNżPÔ6N˳„ÝB­¬—\Pá‹bö®+‹¨'|Ö.`^Ñ …+H«ÔQïܺ-4¦6qÍ* #"Qð¹ìB'GpgÚWb[`Ì‹3,zA]l“NR+Q{!VJ܃݂9 š»dUºDjÓ ~Ý”x+õ Ø×ßÛqâÉO½ÿ˜?M+ü{wïn+ÿ¯­?õÌ{wþðÿù-~v•ã¬8ºýÜ%/ßÞ½ÍÞWIo{g»·³í;üpx؈o¨³É<âë|Üñgšß³|VÍ ëqƒ‘Ì›¿¼:|úâù!”ØKîu?ܸ±›ºåû¿ÿÞ½íÐÿïÞÖþ¿ÉOÄÿÏ.<ò‚ûÝ-òú¿šྯ{ó r.>HyWù^’ŸÝaW3ø‡8 i‡'(ŒÃ¨_—Ý,ReæF8Mg#ñªcG2?™OJ–€ÑÂŽ` ô"h6n|›>â‰ʪAUP†6iÀ¹B’o-¤€òR ¬Íž5™jc+4B§Yû¹b:AÕ\3ç¯18Úȳ ¡LÈ~EJ–É¥ˆé`É’ SC&¸åʺ/jUu¶C  k6)ÝW”PÝ"êŒUÊ^ž‘”záRFѰ¾ýUTu?š¥çqüpyøŸÏ6ÁÄz:Ë̯î=é‰dÙ¦³ìÔŒëh5oþí‹/o¢À›`S»JŠ…‹Ã³§905ܾ]Þ¾ÝlŒÒÒseõ"qS>º ®læ_Xò>%×Ä}´‹PÝdÉq¡Äìe1£‹r3-‡rýŠÔqˆŽFa%ålÙ7/¦îPã†êÊiJ—׿V³-&\7oÑ­²ƒøæÆóñ[àìþvé3tëÏ‚;è³…ænÛy„'WôíhOó ÅõMÚ§ÀÅf^$ív¯“ô«d²À@ ò‚eo¾m’² ¤¶³zAE%bœ#äíÍ©8¡¥’³my¡PÁÆИw’È ³„æÅlùèaþhD½ƒ6ùƒ)*ÅyÂq"H¢FЖYc­“Þ]©V­ˆ ÍÛ»H/ðÛ ÏÊ‹-ÿó™|ò¾x—Y>Óq$C‘Ä‚ªîóÚÞ†«þFÚ±q§*‡(pë†Å£¾BÖó(øy˜ÄðªHv"/-Ø zBÓî¿é`ƒl:´mÚ½Ëk@¹r”{8¡ã‚ù¡­Ó¡.åW ãNjʾÁ]ä»ÄTѦ€Èe!vуœ± e¯§$þÔkØP8p– /¬1%PpÐl+÷Tú›?}ƒL÷­ñšÇ:ŸçβžëWãÖ®~Ž­ØesCÊ<úó ùû|´HǾ;Ê€¦Ì¬XLÉ—ÝÆ ýˆ5ããEÊÅ1äÛl×.Žôs_?¦a{(À!eó  Ø?ìQ`ŸL9u ÊkÎÍjeÉjÕRaSŸx©M?.–¯êGÑá_]Õÿ/B‚“$°Air–F ˆÙ‹“1øˆòuÉ!ó­É•—ø¥†²´EB[#˜X\ž„L/§^ŠH6†xFÝ[µ™©Jé.l ™mM]üÒ¯ ,€äkÆ[!zB}DíÈ‚a½šíê!Õ{~GÍfÄ̹¿u4H ©0!WýâN&¶ÿ~ä3†KúH©çohaK°K!o&‰E5Å/`1’<”U·Z˜—þa]eD JY ­__IWäîü"î$øQfŸ%%\þÑ;×l!È’2V|‹âÝqd¼¤Ïj»ìHþ™ö‚¹¼ Ö"4Ï­a­#¤pý‹øú„>>tqö\Ÿo[Òò]}ª.š*3‘3]rÌ`ÜÎG„Ãaþn½Yfp“Ê §/±¡üm]¯ ¡× ë˜Ôü3B-R PA«oºŒ´ŸPtªáïèJÊ ٖϻëÑ@Ge4Êýk6cÕ[sÙ¦dY°vK^ƒæoTM–lèÎÒ}ÜùDÛwE=×ÙWt±ZÛƒvÿHüÔ¼ÌÙ‰iÉ(‹q%¼j×rå%×6j(9+:É–&V4H´LË—øí5Müc"w´Šûe|íã•rÿtuWBw3ãNÓe…è—µ ž›aDYR.ø‰=å©•4Êÿ0žÊÙ+¦ÔϤ4øîàÀݬ2…©'ò¦²°–9Õ_>dC@ns»[²Þ¯¹¤+÷7ŠAqz—*Ëÿ"‘0˶¥ƒ®@êŽØ™×Å/Ñ.?p ŠXóªìûk\‡]áðVÌ:mñ"×Úù|–›•ÓÐ~MÄÏaÑ ­%NƒÀ_ŽkvFà6ÜžÐlØ \̸â7Í#•½&Ô5¡‰°@ ôØEÙlƒ>j<À}Y.N\qDø‰ Áµô¦IxÝ‹a³¹ä. °þ%pk;¼°Fz[‘©+½ÁºrÛ°ëà®G\6­X%C~ä9mUŒ0õ}‡PúJ×—t¾ÒýWXòû»jÿgº‚ ‹³×Š ­™6ÛaE”Á"Œ1u›-57s (+`ÉëLí’ëÇú¬ £771-s~^Ç…죉ÜVâ#ŒkñéÆÛô.„ßG2€ŸÎÒãcÄÛ°6ã%úaî1ˆãP°e%΃óY:œãç€a6ËÎSÀh™Õ*PBIöña7A£KgïÏ 8n·ä” ISü÷ö’m8¨ñp¿+·¤Oêûú0JÊ'…»þ×ö½í?ð¿~‹Ÿºõç»ùÄÌÏxüQm¬ðÿ»sÿþ]Xÿ;½{÷ïݹcÊmõîÝéýáÿó[üøþ?ÁªXO<€¾Þìõ7{÷’þöÎÝ{;wîÅp?kÜ—¹ÂŠ37èÞ geÕYå»îþÊåðÌðÚV“+ðý—k:±˜¬ê†*!y•Qb“°#¶h¬+7Tj¢‚$6@ÿi1»´q"]I骠„6ç†l‹ }û•xˆÐÝÚ·1)óÓI$~" ¥y2YŒÇ±w•ο4²Rjºû—ìr'y=É^dn Owm£Nü”×+:ýnSéL÷Zݶ¶·×î2Ò‘wí¨Yé7¸/Äznd©|𨱾ÃÕ§¹fÿìE¦yœŸ.ï_q~žn”¤4™3²-åoân%Ù†ªÆ`eBɲŒb:^5÷¿Nÿ Õ#A¶¨ ìJÂ:¶X_U€R}góÉÚ}մЋŽÁì¹Ëeƒ@½°¥`Hé=#ÝwJ#—­Ú›¿iï›OÆé)£#"VÜMPaäs·u!k'ÝÇ®Õ7ìì'—ë»fÑWM.ÉSf FÞ×M`VRdAìn1¶VeîYЂ=f±ZðŽ£j`Šê$ñº|ÏbårX%ÿ} /ðþßÛ÷AþïÝïo÷ŒÏ·z÷ïoÿ!ÿý?qùÏw¿ã@ß¿Nz÷w¶·wúwÖpÿ®óúæV¢Žß|\™ªñ&é#ã ]͇¶¼ˆ*Ö[³`†9,d‡tÜ ƒ r™-U‘ÛøÅ%l¡-æ>gMbÕËS\7-ÓYÏ}SûêÙo7¸Þª‡ºãº°:þ„8ì.Øl‡~žžæDv=ºzB(·êA>ª:tF?fŸÎêçθø,ƒ‰ß1,ÒêYa„ÊcÓÕ¬ëe¼ÕöøÞ*/Å_B¼$‘)ëÔS 9: •#Azw‘7<ŸP~O>íŒéˆg.ݘ­`ÉiâÄÀP¤óÞˆœ¤*¤?éÝã¡ò‘ T§¬ì•Ù)¦W1œS­ì¶‹×°Â;ëQp† w+fGõÜ݉z‡¬Æ¸Â™Y<ƤÞ'Y6"Ø9ÃO¬ÁX›ÝÆú~jj)ëç"5—åøTxûi1ëæÖõy VÔ?³[YwXœÓÐËÔúq§\L§Ålîí&G-Ù‚—ú¼™î”=È¿ 0Æ¿ž§W›WØ×™Ò}+ä¯;¥ØÒ§¾ ÚVÝMžeà3B ŽÙC,Äe6¡P"Ì®.{‘ëG;8oöøÈEŒûGz·Ö˜¥‘%ƒÆˆ-‰îr§8 èeÆGP‹[«<7BD6kó1\&§Ù?A>;Áœè¶ úÖð÷÷9|‹iݧ]%bPIC*ÖÇ5´„ØÔxz–gœý72—–GÖ¸µáëølªs_S(¬@Ù“Òp€†Ù—¿ñl_k%\—y•b¾Ô]réû'þlmLý9†,¹XÌÊ6 ϹSU'k¸Ê“¢b¤T¬8çx³¿ŽKaÌò ÞHÍÈÍ(´ùý•ý=¡uX‘BÓØJia C%Ôø<ØÃ©ÖWÍAAê'À6‡Ô¡b9§v ]å·¹²Y}>Ô6¬ Åš†¬‚QîŠvkÜG] mCë4kݱ¼.îJ9åª RÙ?] zØá À˜7ðIÓ"ªûÂCZ5·:+g@ò´ó3í"h¿ ½ –è%—%õ—ˆáöSSíGxè8.¤Â3_Oè1º™¢÷iØÝ\ 5ÝUNP(í 1(…í%=Ù÷ñ¤SK8c쯊×/¡ðf‡I;q%´\Ø æ¢l9B7$ú7ÐÔ[‹›çÚó¤îåCgÝs=z÷Òºm,g6ä½דZ,%ó×6˜@lA60M³‘3–Ô¬E5®J9-Ú ÚmKÖÖ{±!ô6òîHk0SnùB¾GÅi« ‹ ·mÑØqÊõác›î$?î=úþñ‹ïÏ_=}tÀ×n㝹t7ù’pÍëLy‡.wמyB³ûæþã¿öìK@äz>*òeÜYÖίõþ\¡|`÷ÆÀÙÏ*t[éî ‚XEdЏ¶®ãÔj׿aízEnáíºUèØì2)ÏQ:‹Ò1„î ˜1+“[Òòd˜œr9;‡ÁB\å°dÇÖUÇ¥Òê,çª$RƒÞkÏAŠ~*øk_z^ã¾lW[<÷+-iB¯¾¯ÕZeç¶w?~CÖ¬­°[žm­ÍþZú…„Ü¢>À3ÿ×ßö‚P¸ºÎXY¢Ç…dHì¹Ë=T‹dh`\\t½»fåö¨¡™@-¹T]Åå‚"R7ð5L*d8E(N=ñå”›áé"7D!ùÏ0÷ dÏI|FC6Ó3¥& ÌË£r¡ç²:võ~ZçLqõËý÷XE¢ü1b—|ÞŒçét–e1äý~'Ùê$w:ÉÝN²ÝIîu’ûä«Nòu'é÷Ì;óÿ;æÿw{7¿L '‹ÊðLuËVLÃçé‡ü|qγ ÖnHÜrLÚ( 1ÁÞçKh5¦ˆ»Å,9¢0°þ¸øPLMX7¦Å7OËV;qõÍtÐ,Ų9“´ÆTÚ¦Úö Œb…€izŠøˆ¥°pËxÔQûI`WÙ?EÐù?··(ÿ÷ýû[wzw·¶Àþ{×¼þÃþûüÄí¿:hïŽCëÝðV§ßß¹õÿ«de5:DË€Øq°•l\ä#ÿÀùˆä –Á}D~P9V¥õ-ØÉI:„ô„€ˆ–ˆÅüP Sïó”U<JfŽS8æl±¿5KSÈüV\¢ÔŒ©;'¤iE9GÙ¦4‘¦ZÊGéâJÌ¢n„/ÔÎ’Ô#§<¶bX$à©9ˆ¶Â¥_TŠŽ–„sãÕS¼ÝM~DE:‘’ÀK™ 0~wcUªù,±ð30VaÛsj<½dþ銃åC’}˜§ÅŤ^&½ŽŠëäSl¼ŒN>-¥ƒ¹<¶DaæP¯:ù¼Ë²)¬O½Wä$ @[˜QÆVŠS g”—ø+8N@ ×Bå@—ÿÃ%„îBT©ô Ñáé‰ üN±Ü#I …æé1HˆHRvžãçW®à‡XìË)­-%pƒnr+î‘[ƒ°fX-ÈJ*S5ÃÿÓÕ„ædÔ¦”§ÑAH$0l1è F­À•ž"OiAg›¥t—âDK±¶qâL¦³X#íJŠÅ%ùdרN*ñ«ìf+)hVA"<𲓊á¹C#3hV‚ÑëᘺÄôŽÌ5$Åç°·0”ÁSë‰ç,Éî’UÖ»8æ†wÀd1ŸaJWªþœ>ñžn-q'˜ ì®!@hIÏ'Ãñ’±œhÔ’Æ¡½‘´ÎõèLé‹t6¢lž˜hµJ~mä8—UëüÒÚ(í§•èÐÂm„Êi:›Ã"0%šÅ‹be‡ËÔÕ3È:Õ¡iˆÍôtœ^RË‹ ¥°aÆàY1såœi÷Nüå½nSÖ ;‘ݶ~J&ÚÜO'À^áää[g7XÄq­Â‘?Oß秸X4LÀJ€ÎÙ­;Œ ƒð|=9°·–áZ3ê  37ÀÚŽQË X±zÄf*rJK'y\!²«!]ÿ”óõȈ¥ÅyþlÝÕbGˆ¨î i¡évzvY‚)ñ(+ð9Cö0Ò9Þ¦ÛJ9PéɆ\L\—èNÈÕU?ÊþÔ÷•O‚,Ѩl<]ÌX$þc ¯~G…-ÞQy\†hu‡ÃÍø·fÍ1Ù.vlŽb~s*yFò HçÉGç¶D&úºxèJO×H-cvÕDà®›+z=é='3ǧ9¦PKM·C]•eT1îŠô\€ŒPÀÒVme¾LDá†*H¯ò†+Y›À{¦™MºÊ•51u[~ 4w 6#xÜ,ÿÂS@ëedB§uB·eº³Ã»Â{¸ š¬]•é\%y®\bb¹sÕ¶ÞvOëÓÇúHÞ¶_«º8ÓTº5}ê~VÝgn2Ù̸mñFƒg†’¢tuW$™ÄÙé<#9è“ÀèI†°ºº+¿¹Š³/J@¤Â{^ ):³™Ë†˜6wžœ§æX›. ]¡ b+ðìAlûŸ_vКkj<ÍFb gõSÄ…æ2ïúcÃ'êÍÌ~*ÉJdJ±e£±NÌ=w1ÓðÒ0x«hà霕¶8µ5œ©„A9Ÿr‹H¤‚Ý AÒY¥f~~Rh×·Ëiã]꜠†½õ=·ÖÔ®Ô+1à%Äfƒ±n · Rõœá/5XºÑàÌ»Ú-ÅÔä{¥À¡­°:[=§§äv‡·8c!Û<»a@¶qT#¾¹)œîmrS^ZBº¹Òû¶“4ígXFú`j+`õJÚ$ݵãbd*D„y«qÓ†¢§ÇJ/U³oâ©àpÉñs¿Gø;ì©f5cM"L£‘â¯1<Û%~éJå³W ½Fü¿zÕ+1Óµ³‚²WesàSs ˜¡æ]=܉¨JÈY¿j›ošÝ€åà•‰³„5ã ´ šß·¨ú­LÑÒ¹h8Ñjì4ÖÛ/-ügÃÐuû¸àøp{ŽI<ç¼-ÔÂMAÂv‚±Ä·$Ø©¤i›«=n×ÚU²K½ª?r§"Ñæó˜›otå®É¸žJ°þ¤ébõgÙ0ƒÔ9(°=OÙÃÎLå,}X³¬‚µ^„È<ëËõ¦úzÃl²CÑŽMâökpÁ_þHôþ+ÿ¬òÿ¶ºƒhcUþç;wïƒÿ÷öÝ;wzýmðÿî÷þÈÿüÛüÄý¿íª£ ø=å¾µÙßJúwwîníl÷–:€¿FÐ+ €Ùd1-â’0H«¦lÅK¢Y:Åh—ôÚͼ`Ø+„É8M”õ,1 Ÿ=<ÈYt2"s©œ$·ÙÉ:ÚP˜äå8™œoÒSpláj¦˜={ÕHž8ˆB}–H}Ÿ!çÒ<‘Ñ{ÐÒùÇë$ wÎΪÓn\±íš(m×ds½}㣙½UcQmttᕵ Ȧ2ÔÊuTõůŸ*úEÖjdLx×¥vò@ò”ºTóâ]F‡J©ùPËkIWþBÇŽu³¢±ê"–‡ñ?”%LÂl|\ѧ AlûZ.ºÎ­…VQlý’V ”Y5 a5;us¼£‘Õâ8T¡¾/23_cõIÇd)åŠcrw¥k ë?_o(Ë{T»…ún_šð)êðf˜ ̱pðsnÚ6ÐüG&…u­ÆMËÖ︦æV çCj?ÃÔòÀºÍ±€ËÐåÒÚr ß+,ÂOÌômÈùÂZæÅ“('®¶’|© VܱNV`:y᱑1úji2ì˜.®£iUgu‘Ò°ÄAò|ÑZ`ϹLŸCsô¯—p@ÉšY6>à\K8)”0DÞîºS¨Ñh0nZ¨îò,?qTMmµ£N#7­uâÒ+kÆW>½)—ï<3“?fHCS餘\ž‹ÒióÇîÜÐÌ{ŒzŽTpœ Ș8·ÙlÍߎQNÓsq„uç¯åbêØ•nZ‡ùW1…DÛL7áŠnºyÂì6ãÓíÑÓêÆcˆ˜N¬áú°gUà3•ÄGUô˜Hª@ï`^G0ÙD¹šv•ÆœHûµÞÑè~É&eÔß*¸{-õ¶Eˆ!Ôê æV5KÝÉ28·ª«Â@±¬Ð»&’ÛÍå¸Jq5xéç \AJÕ¸EÑËjz@¢G-’wÄàãâðeÕÔŸìMú*d¹ƒˆŠn4è:´,Sï’@¯ ’:í€ýÎú‡¢ü‚á 0Nú»Cµ@4#¦™˜±C%#_û¿MTü"hõA.FtIs¦ÌòéÔð5ŒwÊç˜nß“¾ËrI_Ñ¡ÀüÓYa®—s8ÕÑ»•“øž'

iùÖN«éYSo‰VÝŽ5ç^Cƒ‰ŽcŠ^€íº,Öêݪª6UÜ¡º^ßGýäš³Å+¯Îšä»ð‘….rMxká†qKŸç»Ín¬îZSäóSS"ÄvšWîÝQ±²ov*¸ƒPè+è–kBÓvomxù+]´—_³MkÅé8úÛkw`ý«îú×ÜO¾ÞA=äðΦo?¾«^ð´Z÷òÀN£þBù‹ÄïSj{{â°1¹Œü_E2FÁ“]ñ¬6o´;²c"|!м…›Á{…9÷˜ËÃé×õ®«.GJô·2ª‡^ò±‘^ÖÝ òIdìk]œóO&Š †ÜÜZ³Ñ@êp2I­ø¨¤üüÄu¦Ã’´¬Œ‡¢tÍ¥~­+€óUºÊà“Ðô7ˆ–"I/‘š=où’^EŽìzÍÑJéø[ î…CæaIt‰(óŠùÄ“ÿwý¬Îÿ{R|l+òÿö¶ûwUþgÄÿëÝÿÃÿã7ùÙ ÿžèóq—r¾õîmö¾JzÛ;Û½í»^Î7s÷c¸¡|÷ÍÓúžMëAN / ¿éGp‡ÙHîÆ{ó=µð׃W‡O_<¿1„{ɽî‡7vE‹xìÓoIªX;õ€ ³ñFokck[U߸×í÷7 ç‰P-p‰44cîòæaëÎöö×÷¶ú_5nü[2™êþG8±ß=ÿûý»äÿ-~êÖŸÿý ò¿÷ïmß»SÉÿ~÷þÿ›ü„þÞªìן ÿ;Å+E¢i°=ûZ’®?Å`Ÿ„2Wž ±#PœÓG ÿAþ°!]là]IÁ\O…÷ÁÉ)^$l4äÓç‡¯Ž’§Ï^$ÿSSÙ/Ikngã´œÛ×óüœ˜~ðœcïÑ}ÖøÖ‰²;Û¤‹5Oºäð=×éI?ê±_tì—d’<;xr”üÇ‹§Ï—ôu˜¼xNõ‚ùÿåÐήׇäé!6ÖðS]R?jç•0PðõÆî´UJ'' ˆ;KìÜ”5«KŠ×Aß­/µ ¨ïR L¡| j„Æ&Å…·Š6Pí¤@N øòa´+ÏPM‰¦Ø<Í0Ñ¿öšòÚ쌅¹©@Û fhF‹‹ýÍ1ÙˆTîpKlÝ¡…áiÔ÷Y1ÀkÓÙûÛÉÍ=j–¤ý®Œ~ÞwÒWlª­¯¥¯ýôÖæžáÃ.îýóùUùó¸ÕØvtð*9Úÿöæ^"ÈÑ_’ǯ^¼4’”Áœ÷Šßâý®á©€Ì¿1Ú°ñx¡em ØÌ=ecƒîóô ª°Ÿ0Î,mÕ ‚5“²¥h–;À@SçàiÊþ‚¥Kð²”iþ7[LŠò"c ÆYf 9`ž;HÐãKÂåb~|ð<øÄzyßì?ñü§^¼>ü°ÿÓóTÉþ£°W¬*BX£ëH‰é,Ãô?ºò—¯þúôàÇÁ«ƒÿ|ýôUe–P3!›Þ‡O^¼úapxðrÿ•a^ƒ—ûß)-£Y5ÜÝ`äÀ­ ™ *íZk9kBíQÈr䋎+¿+NÜuj§°[ÈË‹sä<©¡ü}¤ù—$dÞÈ9RÔñ=}L.+yÂÅ(ýÜßæˆ2—ÎÖ ¦Š¹Û¡%ÚÒÑ¥‡G´£œo…,Uϲó´V–’×ÔGúëëFˆRÁM;Siq¥I‘,à•#¯° h„q €I˜Jlšhï©ÆIiÆŸ§cín¼t²+®š±^¾œåçàñð—ìrÇʹ!KOwm½ÎWqº²KFÌ\¿?”H^õ–õtŸîÐëà RŸåÃ3Î¥ÊFG"ÎýûôÁéLÁ^§R })©dÂJÜ’F—Å÷Èè'¿ßèQœEÉtåÈ#_ü~GáäÍM· pº9+ftŽÛ©^²V©…¤F<éIàü­ª®±a§FŸéQ+3彻טfsÕt8á|>Îb}YdyßÁö¹îr•ù?ø«ãütíBˆi¬gE9·aÌ×ÜþÖWŸzvˆÄÕ,è%†¦tÕ!Ø{Æï´% }ºb«=  sà…ü`ˆðÁOž†×Ù"výÁ]™¢Û€À:®4ÈŤÌO'OÿkN€#>Ã[/WRBÔgfÈ1âpÇæ \BíÅøWØ×›<ç¨ú/:7Ô,6ñÖ•Å.#(ù›û‚î^¾l콟xï+§‘fZz´•­àµŠ³/91<ÎÛóu\AI^¢tæé¨Þû½M¾ÞÏ*û¿…›þˆ6Vå½þ_½þÝ-óûÝûˆÿsgûûÿoñ·ÿÛU'_°îVw‹ñ¶7û_'½û;[÷wîl/ÅÿÙ‡:ꀴ1ÍOúúdg‘Ov¾¡¡þÌÁ¦æ.õ!&*$SLN%lÑ0[;»`Q„7åÁˇG6LÉC-…JBi.pä9¢“2Ø>– `OEïŽï"O=ÕHœ âܰÍ|JÓÒã­)K%ÒfU]„q_¼ÏfhÝêˆá&¶îV#xŸ Ä^g³Ýä[ø¥ôQjri*á-Ñ#?ÿ±Þ¨!ø;AåÈ]ýÚô€Þ>²Ž×Fp²YÌægäµ>ç£lH o]ºXß–U§ØÓbs acæ$ùy‘-²66'@áÐÔ‘Ô`èj1D$],cjŸ‹)ù$âÈ¡ŸCÞ^U’ã\9@>p‡_‹ÕÑ´+å·Îz ø °^°yš¯)þÍ‚fÀÀnØ€y¼$÷ºC´ƒF‚ªmä 8åçèëoFùûdhÎÍrR&æ“l¶‘c>ºÆ¬³\œ¸â›¦üƒæ 1‘J¾?ÏàfM—21v_àüì”л™šÉC#4Óf1‘¿Úhô4¢Ú<É~i£ì¨á7ðú­ Æ~Ó{+;/œÀ€;,G !LøN Åv]‡á¨F×ŠÈ £qhá”þX@ê­´E÷‰ÌBYrŽR¼¨’¦s/‰L6À<‹élð/_ûìéá÷ÍÌ[[ºt¨y^36;€\½¤¦v· €&N<ŒÇ‡÷,„dëÚLÞCrgv‡ü‘ üªüåÌH&XÝå†]Ñwu’©&÷‰jÉFìU· ¯¸I'$IIà§é±pâM4Lž>~ðŠÝåHë™,À9«Aç8øW—?»Z:Kß·Gp]ÚÍÜ¢[S@®o„$ùx»×k ã¢R-v‡1C¦êDv¡ö޹·¤s·ýn Æ”IÙµ^ëêEËGºã“y ;nèüfQî,:œ}Á.ÿîC…Ù¿ƒ5¤\êã8DXµé*âܸå YÄý² ž'® AÁÏgùñbî]ñTJsÞO À°˜Ÿ|¥ê·tÜßú fNfé©5mŠµáµ‹Ù3|4 BXg€Ì»ìG[yˆ{çxÄ•gÎ}[7yAcޝ¬Õ©n„ˆc‹+fÀF© wj¯;$ü0SXÛyØPJ³pQ,18ï!½ŸT¨º œ­8ÊÄ‚g³²r|³Ü/´ÕÎ(wDjч7²×„E&*"¬ùŠï3T r+ÉE@ÿni€X}Ȇ<|s+"#x·N4¸ˆ4Aº[výŠʵ¸µa•Ạn}¦ à‰Sh€«¾lƒDÓ«ÃF"\$†P`h&æÊ P…M3æ7žÓI×na鿬+•¦Y¹•Idô×ù€—E¼³ÂܬƒUn’zÍ­«HGr˜@=,Œ¢?¡•£á 3ÃÇ+êŠ yåBTOŽ; BQEз˪J¾©Y\%™¿}Ó··os,gæ3LiÄ /Ã#IlÄ¿èá^rõ¦CßË•T7Ì×ÞP4‘ƆÈÉ*Ý¥CJ>Wes=Ü2 9›ˆ­ÂúÜÓ@9K”†’´‚†½Áº$U®œÓ¨“%žC®½–íê!P VO”~9-&#‰Æ‘ð´¿…­AÎ'ï‹wöšmìÔ±­øñû3ÂÛt†yÓ%¡6Ç\ƒIÝ5í"±y3ÉÁ^ä;¼£ä6K3:ÛK­Š=æÈûqÿèÑ÷_|«§:t ¢2§½R*º¢0#.¼ôß¡!V3‹†éÍÆ¦å3°HÜ7S ûfŠS›'ĉâ¼0d…GpVz)üÎ& Ó&Rz€Þgßåde"ÎNŠ O&*!1ÄH•N=„5ˆò>³[ªÕÁ^w nf5× ï÷–ɱ”ˆÐ¬xäôo•·ê #v“‘cñ`h. #Ód¤BÖˆ(͙وžúEžbÈG´ÿŽ‘þdÍÏÔÕà _iû Ÿùõ>ô„ã+|ç‹»•KÊŽa~s.ô! »-æ9Íë»ýs%§YÜâ. Ìãrš²¥ížÅlTÔY‚”.¥Ù µ3îºÛ¡Î¸CØ“mÕµ8@­êÖLíSäßʦpž$é¢9aââ ú9˜™Ÿ\:—Fbf“$ãEÊâéÜ¡:˜•K!öµ>c`ü¬Ê\<ýô«×âºeû^ž‹ñB¨o# sž\ë(±kŒ ZG‘ßj¾jED7±°h¦kFÇYvåòTÇ‹qLA,Oç³ÌeºAÂN¼"£b«ÍÂhÎÌýJô‰h‘Ž#ç†jÈ0Žù£zž²Ù«:bÑ©•ÔÖ—ˆÇ[u蘿Oç†b‡­à¬v<š9'i~H×Óª¤UB¡ÍO ÚÔIAíAíóôàŠîîÉgùh”MB 3¼k;Î+kë!~‰Ø“tÍ’Caן`¡¾üÒg˜!»­¹ÒG»j-z¾0l.€ø© ?3‡}=‰ XÉ1ݬõåZ‚‹'€òúòð.§87ôrH^ç.³ @ƒ!]ɬ<þ€ö{†xІ øk$ 1™Ž–™Ïq!0‹=þXöx¨1àßš!àÝïRfN„}h¦w1™kxwY¥æ[›…i¹Ý!TúÉ0/A1^Ák¯Ý/ÕEŒù,/Ý–#Èekñ襸ӵ—J²¿­ˆ…u ]ï2h_ñxȯÚ1ºJ¹+\¯yG±ôé°™y¿ihík\S~©óiàí¡ï«žH1ÈW1N[B)Ôy_C-ô¶EK¤Ò/±T“ît¿Xm—¹¶Æ¢ÄN™OjjðnW`̸ñq§ëR4R9hsòá¡tøËQã ºÖq11ò0…ø)|õ¥2ï‡ ìY’¬³†¨ët:rŸ*—K‘þ W~árÕ®‡UûNÁ\•-öV‘ˆÒŠ{§˜Ó1аޱe×à6Þ *íŒ3 Uu3âùWÁØö9i´ü¨ÁÜfŸ˜ÜMÖ:âìq¦ÈI„§ÚŽamÆËF¶• ¼ò˜Z½ Dh€02™´Fí3º ±ˆÖ?û±U9(ðVR7®~BQãÆ( ÂáœJÊ¢jd@² JûsK©¥×«FüÊ("›xÊÕØŠT0*ºäBL.¿Ç.åÕ=_rÈ­Z—o#ÆâÿùÏäæJ×ÙÒÆã}`VjÙ1tW8¥eZ;ûãþ«çOŸÇòñ&˾ªáCÞbw?6çñÑÁ:·4=4¦z–ËÄÕUÏDb+uêþå):Ò¦%Ë3þÂÈtéT^Û¥â“ùK¬#2_7Sî*ÿozþq>ÆKý¿·¶úwîõÿí>üÿà¿ÝÝîÿáÿý[üÄý¿iÕ)ùkÿ~w‹à@-þÛý;wt™û· €Ú4_² #Ÿ*/]dOÖ Œ’ ¦„&Ê„’qþâm±ä£¼.P ï‹tF¡^xŸå1NóÑ–˜C ƒg< U5¤ðõ‚Å4v’‹ìx\œâ”öí°ÝÆãô¸`'ôã¢x—/›a ¾';s\ ”!S Â}2bZè ÙÝX éEš“˜Î.–ñš<_KS[¿Zż±'ú!°Ç)yÒ'4ÂiY×Y„‹zòl€•ž=Ûyx톲S#L¬nG ©L3[«›Ab’æ¯+ŒÉB`éqݹfƒkŒ­¹eš»[×ân1 - 6’IvQaFÜ.çñVªÈ\˪ڤ¦\§…Ïë"k$Éi´ébN Eïý+L`¼5‹¶ÿí‹¿Ôì•Ú–0“ìU[úöàÙ‹ã³¶¤%À:¦°|­†qˆ¶ù¥S ‹GZìuˆZ@Ô.<#F)@ÕÖš?jã³ãÕ¡¯«ouEDø-ªæúË›[#}e{¯õøb‹D×fg®³LªÍE.LóL%Y [«âÆÕÐ}Ð’¦y<ñ™X“ ¥\Ò⺗0.Áfˆ§vÝ¡d¸Ý㧇€YsÄÅ*ÃwK«ö9xñüÙOËØš€3za£+êüñÕÓ£ƒšeT@Ì Ë¸ä5‡:C¾xyôôÅóýg5ë¦ê“´.ËëèÁ`Ð5pqgÙxZ ‡/oA”•*/ò9šà…\k†àǪnøÌêUvDÿï”­ßL€Ã¼¯ÈaÙ ³_•Éû¼Ì<ІhCT‚Iy(ñŒÌP†JÖ#A¯ì& Is¹¼XšÜÛ^ãÿ…‘a˜Ð  jŽ@qñMvþ౤oæönâ›MóNP½ Ü+s°oþ8Ëç½"|A³¯d!ìÖÈÛËu(gfép[ή;³‡^GÙö,g‡.§ã•"fìóâ<ÿG¦$\=ƤU`GµÚ™ûc“i2Êßç#Ðñ €ÞÖùÍô4¢"@å`#Â*BþU4ËšåÞ ¨ «ÉÀ’z6õ!v+-)Žœ†g‰tÆÐ!ð^ýŽÌµ×|9Éa•¬Ÿ¦HËÌÍVѦê)ÑZxûêBà¶°’ø7>ÔœEŽ \ªc€ÂÈ6v‡fÿºóE3‚š”rð,à€…ÕÄÇœ€ÍÑ£Ò¶ÒÝÈ)á(û®(Q:™{Ю4¾lGa¸ºId[ZàŸ¡‚&°†Œï„ËñýÑÏ’yzª¼‰îÖîRš~´ÐCW»æz$òDü¦ÕœBN 4ƒžŒð•¡û%LœÞý8 ÆƒGÞÈ`ëûÔMl‹lÿóùtgsÓeˆØ”&*‘f•ÖCLÈ&C‹àŽÿ|ã[<¥QŽhû`¯ªŒèaH“<ÌÒv2·ïXš`¿LªíÉÔt™ö¢ úçxoÂLˆ^- ´™r–Ê0ã-mSÑõ‘kîyaÅ)•“«ÌÜ’9Ú´„W¬e³Dºta¶·çä¨à?”!Ö:2§˜â#ÀxeÀë­Œ_FÌÛ’ñúN+kP›ø }ÊÑš±>ûvÿÑÇe×%#=€Ý·þ8±º5FéYý®;>èG©ÇW"ÙoÞF»d”¯Àý‘bÍ+)}+ p¿.tR¢7ëLDm}ªér·š¶5Î Ï2í֮ĭbÚ15›«’¤¿XšGfÀm• §æ¥¿©yiÜÔ Òá]Ææ¯©ž¾*7MÍ=¥"ÈêÔ3–>­2·˜úª\frÏ>YšgFG³¹H˜ü°Ai’›Þ­yÛMaí‚ÓËê]Ó’¼=«’`Ûw’(· Ëa`P±˜'îÔXƒRñrK†RßeÐM_Q¸åy*1»§Ž•*5‹zuÐw41Ïxž&œ€ƒß€ ‹XW$üº|Ó{û¦ ƒ iÞ2ÌÇkZBjdkÒWžË²n‚n§ŸN‰·iΫsßö;¡‚:—öAJ‹ØŠ¥)ÑW"Äú\®Ë1¿·Ã çœÁ›Ëj1'ùE‘Ú \v¦ú~—*ÁìƒI«œfÃü$'ê-ª·­Sž±=Q/1Õ”$ªY¿]Sz½Á6ªKÅGØÅg„¾€?é„Q§‹Im²Bôm…®-€ O'[âÑmu“gEjô´:;„ú.°°D•˜K ‚óMF¶WùçÏL\àJ“E嬊ºªèóôC~¾8a½šòÄŒ²¹Ï›^•NÈ!¯t¦ޏLò¾†ïzÆÄÃÒºé*fÛ>_ríx9#{$êÛÝŠÚN².Eà$¸“¼Äw5„PU-žCæýžEí;$<¨MÞ‘µ–´Õö ÕTKñÙÉI>ÌáÝha«‚¢oãT…Ø+›ƒ¨G[ux¦2Jþ'™/ XËå·Œæmœ Ù#sf¯|ôt5I¾ý ÞÖän||pø¨\@=.Ù¢$ˆ"¹zâÝI¡í+=;¡Ô.LÙRƒ×º##Aµðk[—™Þ'°ÅÒóÂw.íæÂ·á€9=E_ÚÄ©èD8”ÐJÍù’,Y8çpË n æñÝÜ`áÕÊ¥á¹F¼ãÁ`etmПáeaåwˆ×è}0cå>Š|·É=Ããã±Þé%ž™¤ÞÒ!by3›|³›ÂþD¡dÌCÛ[’Tóºw²V塹ÏÈ%”üná@ü™YV(#¥ÒñEz Ø2À5‰jÙ•*‘y,$€?ˆ¿£YÓ´ÛäÐôÅSûN däM܆G“:(UµKÚ9ñuó!›GÅpá.À œ/ÚÒ Ê×X깚ßwx` R¥“ ¡&Û~ ÕhñÑÁ߯ãU&d‘ '·|\ëþ1ž<{úÃÓ#óA[• Ôë¾ìÆ8ÒÓ¯qªøKŠ ,~7Û@ÖÖå ç>zñúùQë‹öª!#„?¹’f£k»Óm4ºÿ•³G5´1ªµ#Êÿ—^¼Ã×ß½zúü»5ÕIú¤õìàùwGßó£¶Ù@}Ã5®¹¶Fb1çJ«ºÄ(lô£¥¾Â@¿¹9ÜRÝõ‡È‰æ5ÇqÌO¾ÛŒpuá‹ÈJø‹FÞ²"¯;Šè¬7ýÍ'ó÷éXЇi|å -û¼bô•”]Šæâ&_½’K І¼ç[)r—RX9¸,]¬‹Õ8ÊØ´t\]æü…^Ø9$ 1È×±]° ü9ŽgÉ&;Tý“5¦§…ò}‚G¨5oXKÊ ç—­Óîh…‘ŠT‚£ ò°†^ DIEåÖÔ÷µ¾V߇/%»ô„D1Wžü&ˆXÄ‹†¦½hÒuÂÉß (È1´ÛÔŠ9Ù€êö¤Ȭ…ÆŽõ³Ä«ZDqaµA„{‡NIÝêä^O{†ѶûDøõ8…-Œ]7¯u2'o”Fš Lò£LL+Óñb»ÞTmH¶ïì øÔ-&U㊭ ô°*A¶ýnW"6·šÿ±0g k+èÔ³ÚŸòôÑf;ìGt'•MUHOd‚'N0ï€ï‹Î»ÒÙ…?óÕ¹‡slÕü/[ó=®€:âÕ*¨§••¸ÂZ$:ázÝ} iúC·—J×ZQ-å¯\Õʺ‚IÛ+¡Î}w–êß1KVRs-`aárWöv`y ËW $êé£ “áòQ…±~XÁš Q©¯±xØÂUV A`ƒƒ£Á‡%ˆT$ &¬”ׯ}\µiÖ%h‰¢8e¹ÅÎiF@dã. *˜%ª«Ãu²Æy*¿0Û¿dH,`á×¼ ³«“еÀ-¥É¡·.¡ƒ( ÅHÇVÍvoqHE+HCÑ.Ù`ºUø g8Ÿ%JÔ –™aÂé8!‡Ìµ—Äú-~ÄÆ}ä“Yyo×Ü®ÞÅÒÓJ˜tr"o©@’xŠU°ìQWp H傌f>·êŒ~Y”¹‘M]ÿÁ÷µoÆÙÜÝ8£°ÜH”Øuõz¾k”sxýŠrX\í5¥/Û™5ɪÙd=úZUKepWDcÑd´eiC+QV4¢àPê[YweÕ£Í5º²1ÂÆ£‡G%êà•x ˜ ž¯/»[¹@òÅlÜx ¡ €k†aä¦öFa#@{›ê»f ‡"Ë7ìmµÝö·úŒ-Ѧt5Õ0”nµµ»Ò:[лà¶x·UkB¬­Ä÷Oÿ§ƒ„IS…רÌ^Vlèþ¯P„e7ZE•Ò Ó8Ã'M“üçEæ†W¸L«ùpmÞ)nÿ1Û/j¦¢¼Zž¹k²Ì²fÕÄ¿`¿`{W%<œ3ß02ëýìñ,›lvñ.¡œ.n®ÁÏÃûÑõ ‚óeBš‰‘”æ€+“u>»D¨@ÂÁ_¢ÞV¯uÍÊøˆ¥{ÆuhgΚÝë,gUáºzQ#úÕÕû‰$‡‰xÅËì‹SV¥´Çj²Å‰«’ ‹õSÖg‰ey£JRDŸ¸EÂãæ@ö½@†KÍög¿öÝ(ÛX…VD¹¼TA¯9J ÏT\®·ŒÁVtk«´kËôkôVwÞéÉ‹št1j.–há–îxiˆ'« <öV¥ß®¡Ë~2-šò¿YÃåú“Nó¥amðþsÑWcp&Z—ÀŸÚØ.È»"¨XgcÅå©.†Ä{Î¼í½ ,Î+¼ú})ßÃÉ dž©!˜ƒÛŽ‚½qgûNž«D`½òÙžXdʬԨW´Ö°©Næ³3°s«{úüðàÕQòôùÑ‹%SÓB?Ÿ+L¼÷Ó£{KÑNþºÿìõÁaÒºm^ÁÿÉM~ëµ+þt4Uxós/”ãYuÀAÐàš`å…°]uo«©dM‚Š×Yí9g¢Ä‡Y 9‰ËuîÇqÔ%β³Þa׌+y ]Ž„,ØQ¬¨ mú»‡…øZg[àæeÔsß/µ–.xžÎÞ-¦±”èîœóÎU¶ŠØº #Þ2”Y:3,‹ÜÝ:ø³^—¸ì#øN3Îw¸Ÿ‡³±¯ptò†6+ËœÞ<–0¤›9]@1õêy1­|ȽË.¯%Àð±‡ÞB­¡¢­e>„{\ãÅ\%Ы¤~­Xy½z…×8öèªZsæáKñôƒÈ~ÈòÌö=-0ݲKlä€%ï€dرôóúåc#«êzxp”P*€SÊBQ 4©Yaµ¦Z²ƒŠC6­Z‰¼Š5éç·¥ˆ½/&ÅÊqYlc•›fŽï³›@†šQ$Å0Š‘Ù€. >3#[ŒS+oŠûíþÑÌKô;XX€u0S×\0Œ9ÒQ8)™M†Þ»d`ßÃf‚â¾0ã£pT<ª8É8\ÜÄ”‘cX)š¼©1/HÕË´}"È Æª˜:/b›1¼8sqJ¶É‹¥jk4ÃðFeCóȰ8 T礸ðâ¬ø“ªË21ôù?£ëdcA…IGRÆò°‘X)²îœÓqqœŽ‰$ó,Gã ÷ß–£^tªuí…é/Ìk+Ò,ÎÅŸ?HÇŸõ0eËê›O¸[ö“·D µaÇã®õïV7ÇQô1~hÑÃçÓb‚Äô÷ñY€ª£4›Ó;zú˜ˆªxC¿ª”ýÏðc¡@ýQ|Π8¥PQÞj¿2 §ÖjJò6Ø4$u+ s½m/stÓªƒ›¨ón6›`ÞUºd|_Vï´çiNÚ⦾̞çjA*o0‹uå©@M† UÐÉꈙì¨ÑêhÙð[ŸsÜÒDyñH¯Iªöè‰x#$K>ܵÅÝ3~+ ¹£Šèo—ضy'Óß,ˆSa9W; §à¡2° ö™}~¤Uj°üñFfý­} Ò~»B‚maŸX‡}B=T0Ÿö/Ê\nÿD’qZZQ-àr(t³ûKÍеÿY>6’#/Ax‚žxÙ'ùG¶G˜Ù‰$1¾B5Ã6Á¥u¼܎$ 2gþ©«~yZ*ª}´TÁ”ë”[†–Ÿ>:0÷dPá f·­ãkÔ†_#¼FOóJ™˜'"ÈeVݦÜ÷€'qA˜¦Q<28 µKâAu]²bah¨·q§9Úh¬ÚH}/²¥–¦èÁ"!M›}Ü™sêÌÔ°]‡¤Is¿¦cÈi8ŸåF.ãá¬kl$ºqW}tËX~ßûaÿ¿lÄÜjÍ‚fç~d j˜®aXÒØl8t“ 0’ œ[¸aw+3ô&> >éBååO];¬#ô÷¸É7^…o«ƒúX¶tµEõØt4ʯü ï¬bœŠŒÄŽT @4†¯îÖU­å-Cé{ZÙ’üÌUÓƒ|Ôò©P,Œ²ñ÷¥Æ±Ü˜5†[Äåµåq¶>ýJò¸™ñi|e2f}ÚùZ73(5!{ƒÎÆ|œQj¢‘[°xFfnèàš_°©Ô/5Éà.ŸÎ8nôªîSIãìÜ5yYÑá,kjOÈU]!ï“á«9´ÍIqÙxRîŸ ô¬Bµ8:L&¶¹ ~¶hcÌã‚]Ù%<Ä%MO@[cs4WÞµVl ®¹Yk”R¤T‹ÑÃeQ‘¥Íú^±Ú ¥ð@=°ç³ƒÅ,ò5îÃqúkÔë|ÌþóPÇWõwî-0T¤xžvÞµj÷[d @HÜ„ç.¯­¬{Úý[B„€a—NwÍàˆ át,¡B½iÍʇsibó#ÿ²O¥„]JçÀLÏ  õ±Ï ì@ Èe%sº¶´m-Î(Ubnn6±/M;ð §'¢± “¿/qÈqDÈ–K¡Ì7­YTWLÔ|]%ɘ'9Ï¡‰K9—3o[UÄÛ2Þ±"^ žÑ¡eÛ6Z:ÑÛO&l§X]Eúˆ*¨C4ÝÚøépÒâÈñÕiÓ¨Ö?W•©Ðfd^´_WЃž{µ}2-mŠ\±m‚D_Ù8[Þ:iëõ]Úuf¬ý%ûÍŒ2ÁyŽkÎõªÙ¾â|«ÿå_zæC¯Lܰ¤Aò6jý|‚èô øg%¼ûêf-Ÿl•íðTñÁ7q,t˜¸OPAö4¨ h½S)gfñŸFpˆSsfL:赈ЋÊàGÕБƒ.… )A(üÇðz MÍ‚ãMR+@mK€¥Ž/É„ŽÚñM@í|\ÒùJrÓ~iDªK;v¤%^aØw ê5§ŸUÎGÛd÷mPG¬»Au *œF¿Ñ• ñ7HŸÕÚo[°9ঠIL ISWíž©¨ Uí;…Ôç<º4À{,ñ<û€2ÂñŒ®~º$h˜LÁ-.¦Ë(ÝeðTÖØjà˜+Š3g“‚Ì9cÈt/¹î*ÚÌAYr€h ü€±¨‹UüVpiüW£Ãûæ®ûs ÿÄœõ¾‘mN…†$¢Â Ü„Ay1)óQÆZ§ìC fúþ¶ÿéÊ?òËü³Åeh !äþ᣼v)ØŽt¬r"E¸y õLÌ]¢!‰F!ê–ìû Qè&ß-‰[(Ö‚L3˜&e[ªÃj}bÃÕdRé˜ÌSÛ }Î(ùä©ÿô«hÁÌå ÊŒÄ1¼Agf)¤Z‘É'ˆöûíw^G*òh ö£ÇŒò‘Š™€-7¥³:÷CÀ­¹Q¢E³a̤¢ LHà¥q)€8.F·ú;šùÌR±˜S]ŽÂy~0òcœ¿C2Ï9à ,mòà6í ù·-üÿ+\Àô zVæ“afC ž§LÑÐÝÓ§äÌP·`á\rÀn6j~‚gV£–”4éz<Ö’"Ï,::M‹|Ì®MæmévZ§fsll$búˆâKá8aŸ0µ/Í(gi>†M‹/à P‰¦Œ®I †ñeÍ…ƒÍâ±NÖô^Ý]Ã%ŒnZ7£õPñÌäå,ۘΠ, NÞrNÖçéâê»–©©|Otªäz˜Ï×G}þä¸Õvи>W†R†øHÍXL}c'$À5Ï¢£¶ÖÉ‚Ä3$ü”þ‰@ÆËpØUµÇo(’ KjéaWT°dÑE¥÷‹Vpì¿èÂñ Lÿ€}ο‚,Ñq@ñËê‘­þ’,©~Ø%§lÜ"Õ‹;ˆs'Ìüt¦r á\j™›«/|žOÓ îÚU˜{eVuÅfCÿ$=©RåúÝ©dƒÿ´=ºúü„ùâ—÷Çí|Å+TŽë²7Q-䬋1®(Õº›ôÑÂtí­ƒ‰CIQмˆ; ‰4ºW­fÿÛ=@^´~ñÁ·Ï^üè3pwmRÇÕ±¡'%ƒ€L;úÚÕ9t-¨Ll•wLxÀ6%R>z´·ÝkÌNÿôÜ©$s?ƒjuH—¬=ÖEü$ÉçMÖ`³6˜\¢lê›qô¼{ §ša)&“±Ð)ëVE~EÌó+¬ò¸d¿6ô8­4u“¯4n½v‹é .j„Wb†ÒaŒ¿¹9nM7t¥>w1K§S$n.¢Ù›g³¤×^ºB^l [vÁMº89oÿüá=çb™s¥@ížMF¤'v¶{ÿpa 7FçEfV^™´Äª™¢n¹êj©ãz®38ðmrcŒ«µ]÷ª„.Ï÷”š8º¨é }[¤¬>ó’’ME€:Ú7âõŠ:C¾Õ¿n䦜hØ=ćÀÁgK:Ñlãç.Se2Œx~…ép¥½®¼–ÇŸdJ<ÇÇßhZþm(áã X6gg_³ºòrhÃÄË/;Ét–¿‡î`ãûù%rù 2g³Årž;ü]D™ËGÇAqÑNF¸ú'— ¼9É#þq|Å ‚¨©¡ •…O|¡®Ø}Qf4TauCÂKqóQONo± ‰ÌØäêç{¶èaS¢’ãÄëBìmæ+(ºxdx–Y#¢àDáÓ7PZ%.P]´Á™Ñ¨§Tp*ô”Šâ$˜Õ©žÕUäÕ»db-ÃôJ“;Mîtåä’µ 6N‚Ó%àIÓ8lRU®QÝ §{â¥D¶—3Ï×0èq3͆ùIŽpKhÆ|D6u DQ»î k'¡ïÐ9Ã~„-°#pxo:Šñ_Ô)Šùënׯ,%-CÌ/V_g—Ç\GHÉ­àÅ÷çu5Kˆu}öæ; –+”z*ÓÉòþM×=%2ë.“DáP­ÚصºxKýõ Á»Àóƒ”_ô¡.»¼•+@”á€1®^MEœ”" ×Wl†®Ú’D]±´q«&¹úÄÚ±(í¬>?òmHħ4aÔl,Œl+GD¾áœnYí¸¿¦ão ­ÀŽ·Æd™ôî§/ŠªŒ¯˜å§I×p¾÷ܱz’t#F{2GrñGPÏ™ác#-ÜX–"-5]BJæ¤ïÞj—ýhêå÷/“ín¿ÛƒÀ¾Ù¼@n0㌪´²˜2@š3A.çˆVy’lôÝæ²ßíA¶o¥¨¢ìAoÒ¢Rx ý©X—#ø—áD,BÖU÷ÒJF%j’"L¥õ¦¹%ˆUoú(ÃÈ-XPÂ/íü„å+»J夳¿ðò>Ü;*‘Ï1)Š šÄ#ÀÂ…´Ä³¶-ç¡‚;úç?oÀy©ñ¶Ý1YuWöãÓdÑÖ®©)j¡ê X]F{«{á“>Æ`ú.›,g'¾¶p\ÍðÄ«ž½øñàU jn3‹Š$¥ö*‰M©Ñ›(‹ðûŽ$XA“Î¥! p™DÀÉ)£›©Ntô™R)VlÄŸ~a”)ލ¯\?\Mú„²)ã €YW]cЉ -Û7qS 2xk£pý/–/²K‘mЖ¢ŠpQœ8À±Øb¸ÿ á[]ðõF¿jATTr|Q È)D0ŽKÅ· óúÕ3`{H-–Ùy bä?ÊúðxsÊåpœ%öóƒuì$y7늇9ª‹¿p€góùtgs“]¿Á‡h“"[ÍÝú›M,²lÙ+¡0t_®Ÿd3Á£:NKsyaŠà´Jl~µ(é(‘ 7.f.Á `Ã{@塤‚¡"±è=É4m¡|þçÒy_®×Jíø{ ¯lÕÈó¨ìÿÜOòGuÊSLF\nA,æ#jðòÅáÑ›f «¿;:x…>¸ûGƒÇOö_?;²ª¼º¹PÐCR±†Íîê ÍGW¢ª¾‡>ºè)mw]Óhc´1­icr¥6*&J®eñ=]=]ø=½ZL®ƒ^è.DRµá\´‰M(ŒÛ’¢)Ü–9gOB{ÆÚÐP×è—0 gÞ™Q}hÊ ¼€fªÒ6O%Æœ‡á;É0·giqD3›é Ò½xŠt[¯a“:!oLh¨¤àÕ‚¼|ñòèé‹çûÏ0SФúq ƒAëì¿84󆙫+ü÷<¯c¿ü2¸H]ÁU¨ÿu;äcÕȺvZÄjívA[=MÄŸÍ‹w©O-wô!j“nàÌP·ËšÊÁ#:“ÞŒ}†è§ÄèÖ#óLB`ÊÑûÇH!Â*ímJbÌÇ 2[0øªgÔ²ë%)ËÎý<0¸Ž‹õ^>GbÔ‘ÀQ#›-‰Ïj\yl$E½AŒ{Ï×^S¶)Å:õ5˜ 80³ù±Op¨°„Ùl×Y!ArkŸ)•=õÚÉ ‡uãS¤@iŒ!Cž³ÆÓ(‘KÒcÁ7ÄÙH¢°aqx­X²ðvµg= ¡óŸK±vŸâ„èl›ObHéi ŽLÉpV”%‚ ß`,äŸM¯‘ºN³øµ¶¾zÒ&?M‚Å1{è8ŸÏÒÙ%G‘W'£D•¬ž–7l†‹|ჾ›È¨5%#‚ÞÅYFy"u÷!XärªÍ4oºqÉ'D×Í«‹´9µ´N@ÝIxIõŠîÖ ²¥1û1ù³‘ÒEM·È¼Í¶s| ®fóyÊœÖëÍò ÍL.°ÒkY¯çÚ¥ý8ÅéÛ•o®ã]å5o÷€T¬ûÏÅô—^„øž­ ÿÞ­â¸r/½ªý"Ðz¹1që^-Ñ>põk߉=GX‚®9ÞµéM_iåMo˜ôYþa‚@Âo6¡Á‹]O\’§0*®±KgÅÆÍ˺e¡ëvÁñ =©¶º á¸Ç1ÉuÒXÅÝšÄ,›b².ÐÑwPZ[¾õžN5àp´xì_ûˈ'M`§ná)íÓa¸Qñ.G)!¹so;¥—¥NrÀ§BLºyC5ú~¦4Õè Î9¼CañN\T’Ê:Ì“/“;ýí;÷z½ž¤¢´¿Zñ5UîI”F 3•’aìnkpéIÙR®zÑÇbË´TñyÐÍjðPyLiðåecˆ¼ï*>65ïOOÌ–±§KXÌϤ<ßkÚ“nÕôª"à¬'ÞÔW³hR"BG¥¬K6T׌̎ÙB–¨%o–’V±‘1y«8âv’샑Ÿ‡¢Ý˜d.Íšûü¸]ŠÎ‚Rl…]QJQ/Á»’@Éy À  ÑY°äytG ÷ÛÉÔÍÓiþÿgïß·Û8®}a4ë)Ú0c€ ¤HÙ¤%‡–hG;²ä­K¼×Pt0š@“ìDc¡QÌŠÇø^ëœÇùžäÔ¼Uͪ®n€%{­-®‹ì®®{Íš×ßœ1á¯/z"ow69;¦=5ò¼LéY)%v7“‡€=_`°æÄIR€\Û¨;{Rü©A$£(‚¾öŽ ‚‰Ó»Hço—3ɶX?lɇ‰1âí’d—‹Ó¯;ã <]‡ÒL97B;^õ•z­Ú¶[mÓéG7»ÉÎ7â|(c:Ÿe˜§@|³¹/ªãB@f·b¶Ä\$ò˜ñÚ©D„TÆŠ[CDï,[ɲØM“â;s5O_§ÝyZHõ›mÅâþê‘ËB#ÅV®»Cº‘ z‰²;É%Å7›lÓ§FȬ‹ò„­º›2.šÕ…Öêð!(Erô‹†p’èíå…—l0¾¬ 4œ<¢p×ë½X]ó8ÝŒLœædl®' ÅÛ¥†»: G>nyÙ_ƒÕ%ÝR 8Ì¢ödRŒÞ® EçWÂîKA ñ´Åµs½+•ÁW\R[ d«?uÖ‹ËÜH@„²Åe†z…É8o/§ô‹ ï*½ò¿)Õ 6#>¶›ŒXQŸ'îVrºtmoÈÈö=DyØæ(¦õqÜ:Ä­tËO¼Ð‰¡n§»¦ k¼Wå÷“ŸŽžÿ ±[¼8æG˜÷é܉‘RY5¢á넆„ž¾+òq™Œ—³I„Xªƒx°…!¿'Ë…Y ôûgwÜÝj&8ž’JZߦ¦Žûÿh™Bÿh=øv;}ðiË1ü‘’nÛËpÍþ×ßÒK[.¨ØÞÐûe>yYCöÉc«ªn[@¯—\Å8r˶¿äèçÇɹá¢ñy]죭·-ÊëfÁnlnN£N>¤¹ÒiU*l…yã'˜r<·gOSËú™ ¹ â/ùe b´RRä|‹Ðä}…™©ÞÍ:cAƒ CFܼQ­ë°Ìëbc¸Ræƒ=ÅpÒkÌBáÑn0#Œ¿Önv4:*;›…ÑÀš•¹38¨&ã÷ê.¤Öª>a©x§vl§¬€l?•iìHœ+àlèõFμÑv¯º½áR¯}‘RgóÍEœ‚¿éÚTjŠMŠt<2»J w bE_ÈvD1”íè¤÷]k͆¬€€°ó^1Î6+äè<žqžvf…5@¾Ò†•áY2”[æ,$)ЕfËØµ¸{ö±b>Žî×úRfa²ùV>5Ô6c\OE_Eó'°Ê ŒF5ô«–”+”i¤‡ë†›Œ"A¡›ÍÁu˜“¡¸´D™Ûê˜ÈÜäo“–·è-Œç3sŽSX!-„Z&=Ý¿˜%Ð9¶Ø,w²‹7-†Z ¦ñä‡ê·¦¾Í‚8®’#ª‘|LÁk8}¢·´LÂkJ21ÔLGÈk>‹PðPaBB üj‰öØ‘û„d(b›DÚŒ“ %ö¾„TŽSØ ¦c€ ¦³¤–°ÇÆKLh⺴©ÁHÄ:d%ÕhÍÖ1VYäµ ³ ÖN«’ÝRK8ÖPƒß8­OŒÏ¾8~ñâñ³§Nyl/Tœ®Ãºb8‰X '±¶\üB¨Nm(šýf`!f¾³Iov>³tNźÊ;ûÜ£]aôë"»˜btæœôÅýjÃ6îk#aöUà?'"³.0ugF=µ>ïæÇ²™Úa^3˜~{”ö ~XaµÃâ¬ÚL¨/:°F„Ò_#‹ÌŸÛßê{0vðèI7V˦ ÿÕÓƒ;é /­}´ Ä?e£O­4ðG6Í¢83’½Kâ R>R}öž«©6jÍjÞVÞz`ŸW>¼¶±€îeÃ’KAš¢‰Z9›9ccøãñË×íÿ¬Ëy]“œt³Ú–‰Ó|‚$Yû.mùÞ`‡w¬1îó9Á‘ÊJóù48ÅtK‹’×Wo=`–ÓCéÉ”`Ý+±ûÆH\Í·zÙvY›Áú;×’E1ïÒÕûôZ”l‹äÉ&‚‰Ó5–K¯AÞä‹›Q¹»³Téú$ÉÒ‹k {ˆjNUXÚ4¿¾^Ÿ˜kŸ®: ÀÔÙl5skéÍ);á0¾–æñZ|¾<êÿbŽoZ_Ó¸ AÕœ|úïvJ¤ƒ·1#×Ì*ÕoÚQœŽæw½§BÌþO±«x^~Ïû*Èð{ÙYiÒ ¥Q ‰{< ôvóQ³ò6gÅÏÜQS:Šˆ.#ó%êâÇô½ôŠÝ©€ÊxØ)̇4Tâ§6ÜrL‚L* °3cžz(0Êæ ÿè²¥[…œœ3Q‚wµÍXO1˜I'†V*Ÿ"Jz:)‹°ä 1H9ãkèL™4N…hÀ†o³+³çòrQv=õóÑ“áÑ«—5Ðã‡G/ Ÿ?~Ô%)v^˜;´ƒ±4I2ÿÏ«Ê`N"´¢Ï b„ýÀ§Ð.AãÜSovå”0’´‹õØp ˜›©0øI6J—„³iþË7©£,.2d3·)“O²=íÚ"}_L‹ XÒALõ¼ƒ>6ÞðÚ¹m¨A¬þ¼o_ºù$›‚G@'̈n¦_:s~Ѳº„Z„™k6‹VÚ5Z«SÚVìÒ׆༫åž(P˜J)$!e6yçÖÊQÎNûÛ4Dñ÷[1G+Ÿ¶<ÀF>î­Tײ…X&<£N'Nõ!3ˆaˆ©BÏlô㔈5;wrj jPƒ_QÉæªå“ˆ'Ä5 IƒDÄÀ9#aê2ÍáŸ<›s¢¬9gŠÂÑÕ9jÄ¥,NXÑ(fejä,.uAK>©HZ˜l¸x—9b÷ýbiî´€–{Bgée]²náŠ.ª*Žñ§Î‚µ^’áÕ5W5Ò ñµ[#ÿP¥þu’­¯Íà¥Ùjh*ʽ¥ Üѽ^¯Žªã*oÀ Y=‘sŽö˜B 5vúB„p¸Ôþ²5&¡g—Ÿ –­ƒîmò[!~±J€Ç¯|öò9õHºº§Ö2‚öV}zå¶f-ºûÛ N μ ¬רn~☲¤¼2” a ?™OóEžNò™9»ÊŠ£ý׈‡†âàýD@Ì“UÙ‰õ¢¨inJßIVÆ@ö…¡&[N„kc}ö¶È×6ÿXìãH@ÄÌÄZ}¨Øôkjq}!éZ[€ÌÛÿ ÷€ØåWl‚ª³ÏÞ#0(mÁ•Œ¡hà&Î~5e¬ÿ-hõÜ·kLzË2ébèoY»'yç:~bû[¨‹¢ C&c®j.˜E¼HgCtwcßæA¿‹{æ÷Ìÿ¾1ÿÀ;àÿ¾³‡¯ûq bÈz‰a—ÇPd÷ÔÌ)‡Mƒ2ù=•ÙA"·¦Üqëàz/¸cL!»Õ×mšðr•>z²4™‚à­‚æ_¾z£µæ“%Ú¢ü%¹áD@*¥Ä7XªM±‘â|€¥Jr³t¼8øÿòÄhqA°#â7½x}Àwµ‚RMNÆCÛ̉!8o½ŽàÊÝ #x|k{IbÝØ‹ê¾¹A—äÛJ¯öúž]/^;Ÿc4s ¼S"xní9Λtf?c†?$Í•M¤÷%?×ãóÕc^„˼DÚciìNÉ5½0¿* ’ixÜVGÐð™mmŸü2Q‘J½ŠÁfÙEluU™X/š¿Y%§Ç'8ŒG%,­Ië+„‘(½[Ð¥$â B˜ª€{ä [žË €à' ž2ËŸN!¯Eû:×Gpš!„2p™_ o5!WÈíNnJ“IìX£>ý‰ãbÁ©Ÿ"y“’lAd³·0[ŒÓ´ [z$_aÏWL-cíèþ‹œ!yK“ÉÈœw³³éÓÂ\œ² 5jÖuØê>ƒŽsM} 6ý”ô„hs!K5º_‘Ú–ù˜*ƒ89®«¡††‘‘=¯ÄŠb+c#sÄf9]ðÌ sa¹6¤úËÆÛÖTê*Fi‡;SwUÒ!ëœ[h•²kÃK¥~ÃìPÓ†ìPÓÚìP$ÌûótÇÆ«@¯TÒÞ \8É^Zî;œƒ™ ú…¶)°WeÔ5ºÞ8¼Å’ïÿS±&òaýÈ0ùû@4/. ‡¤ã«ÍYÙù¼Mwkbì%ÇùBîŽne£Ó@üq¶º¼þ]=¿J žSÜ0Åçêç4ÅaQκf]½Íb«s8°Pm·$1Áz‰ŽŒ½äLÕ‘Ù”o¼ ý›¬Â5Ö€£{hTöïp Ý]Ãð)zü;/-—:ø&ÃB×Ö¯|ËQSTN1“B쟄¬j2l«‘nÔ¥Àƒ¿³1ÁÈÇdrãê4ƒx†¯”ù®à$e|AÛøÏ©[Ì{ػЅ:w7å¿á=iÛ¿O/’^[Úæ¼È.Ÿ˜-Üñ;uhMf~è dr1;)Už?ŒáE67tŸv¥Ý žE¤¡J¨ÌSIê¼xEFRy¼KÑJ!êa1-ñvƒ« «`Ñy ᪠:ƒQ †_—9Ò·=5lïY¾Àp.0vAö¥ªùf»Ãlä v÷{Éß©ñRDPX€e*yoÚzÀh>¡è:Su¢¬"¼HΊ¬<€ßAdîÌÿvº š4¿\™ÿý« ï i|“˜_ÿuÿ¡—;”¶ý¸ó/xmþKïwŽÿP gçÓÅÏig#Ol¤>¤57ÁÐA`ÙNÇÞÜÈMÛPá>imiZ)®z‚æÞ%y‚óbŽÎç)ôg§Ý7{} ¢x{ØŒ^çG +«l£rSìhvFs§ºÏwrŒ.ª×ï·=å…7‚rybºiJ c€±x ŠÇr2­÷’8üèøÑ'8FT‰=’Ësn1¡E3[ûƼ˧F¶‰¾2/çË)FðZ Ñ#À÷ãÔÏ®`ÀU&âÐnVÿÔ‚×­h¤’·wFð†­=Z9úR¬Yõ/ (ôäJSÏi)9‡6g“èi™Ùì†êºš=DkÍ»È+³b ­W#ÙX¨Y—º¹²fmYcMÜžægËy*é>0оÆ[3º«{[¶t×n>7§wÔÌFz‚Þ—†Œ|ؘ5ÁvÊÍ΄NDqËn­G¨ŠM8¡º¡ŒvjêÓ³•’øŸ¿eWpcAó½ä§eig‚x qÈJ™û|CнÏÒ² ¼ª|vnê0«Œ]dÓ‡ûXs0ÜyÇNÑ©ˆùcfjëJx]ú%sLì9ê;Ó³˜#²­ûÁ¨Š•ª²J¡æÔÚ-—Z›úà„àyÔ-C¯²tG=¢¹hà25"θ8ë´ùAºöiEÄOþ(@ÎÔÿGá"3Єè°k0 Ô's¯ƒmÈ4ŧωk„±6ÐÆÔãåò‚N¥¥H¨§3þ›³!ƒ 0ȵPÞ4Ô ¯jnÍÖÍí©+ÑýLΜe[K€5œŽÀÇé¤x—õ0ë0ðtKRѱµô«ö’cJ«w¹ì§†#ñCûÃçÔþ6«í$ ¦ü5ݬ¾ùÙ¿{ÿíßøÿöûƒAÿƒþþÞ~çÞ½þ½?ôwvúý½?$ýÛjüÇ0ÄéØýæ`w/9+NRÃwÌ’ {gý<ø‚â±Eýגܿ᧙`n„îÈítô.Í'xéYÀ2j"÷Aò$Ÿ‚:—P¿8°¦µ'Ÿ):Í.’§NG’)™à5Õ,L '‹O’ú£L3.aÌ8ü.¢ƒä‘ ~£1Õ\:`ÚãJq£Éªkê6qά«]öà†ÃïÜñaôª´¢øm9'!zÏ´õ·d 1Ýcõ^;AÏ„ìò0ùîÁ·ÛðÝïë €ö'Ê×4Ÿª‚;Éð™.ÿF?+èؼmcýïïý ö»»ƒý{;†þ÷æÑgúÿ ~=ÂËäþ.“û}Cñ“þÞÁ^ÿ`ï®i9“è=™RÞQr±yz—’©…#uSAÄ- §¹=KèÝ\iybÆ–Õ,Ýygê¢Úÿ~üœnÄýd¿÷þÎC#Ô*‰\W@·Kû»WÌ!.j†z 1ƒüf«¿³µ³§ªoí÷ýÖCwY×Ó¢ZZwÐ߆­°­ÁÎîÞÞ7û;ƒ¯[wþÛÒ¯U矂©Œ€öm4ŸÿAg`ø¿{{;û{ƒý}8ÿƒþÝÏçÿSüDù?·êÄú™ÿÀQ1¼ß°ƒ¯övv¿®eÿPQ²›2jÀ®ç<’|Ÿm’£ãºÄ3›KÅ~Lº›E@ùŒ€I²úãG¡^›„ácQe¯¡w„âÈZ‡Â$µßf>€[Åýok5óz@þ· 㪠gíV¶Ó†yÕ+¢€²åe9£9 o`ŽžÞžD- ÇÙ4.8ôcAHg /M‹å \ @°€íÉγB&ä&\J8!X™™k¬¬ŒÁÃçHF›íÜÜup¯1'i²ÝÙíÎ-¬îÒ…vOª¼¯û<]€T°ÀÔ!)A ƒ‹ÂÂŽ§g„AI$«•È7 gJ…8— èb´†ó%‡Q‚f“÷6•¨x&Úƒvž*3+f }½ã‡ð¢–Û‡0ýgx*¬’Î!í±ZñòdK"ûú÷c³DW¶wl"&G¹Åæ<‹Såk"uÍ„ª¼(\©ÊÕb¡ ´[ ?bj,JFÝîb5ÔL–P jŽn`+a ª4ÛtÕ… p÷ÌDÒ§•YŸM–Tµr°;6BÙpuau†ÔÂåÉâ´ P(ÑÆ£ùòâ$Y̮Қ{ÍA"“' Ì<¬± 8.ìÑN©¶"¸Ð9Š ÓĪ0üùÙ‹—¯Û…¤§Q3rÌšÜ-,Ä&ÜÓ–Ú0 =n1@?'t"ÿè1.­"áÀ>ôe×8çõÞ"] "ò=§r˜X!¬÷„Œ"¨òœÁ‚hÞø§›Ä®Ëñ(ZOø Ï£8vÝ·4X|ùˆý‹®×kJ8 ÚÙ:ÏŠEQ (#Öã!t>È}KhÚ‚fê(ž¶zÛI†oƒsˆó€K:ŒdÝÅ#¨ >ÆEþ&ö™Õø@ëI¢¼l§|{w…¾ãÝä"}k®·%â¦lÜ "¸PÑe‰™£°†úmÍ%C¤Ü¼È4ë©Âz)pë¸Úß^ï%qÜŠ9Õ_Ý%œ5:»>ÈP¦HqÕOühh ïlŠ«”4p4{5'dýS¢.ó‘‚Aõç[•[7O“_úÖ²5qµ7ÉÙŽ9 Xy]Ö]•_²Š÷‡ðtÏG’k î‹ð™™f<ô¢ê“`ýjã×ÁJÖ]ñœT ¾îvŠºT‰péä˜Ëæ;EV=—õ ôUgñ Ä÷è¡ú‡¿<üÒA‰ƒ¦â¼±ˆ9ñÑÄÐg#„HFŠŸ)£ˆª×»{êf÷ãßÌf¿>‡In¯Dù=ÜÏqéjí.éÌ¡±.­îN Vÿo­0ùö³Jÿ÷A†_þY¡ÿßÙ»·ú¿{ƒþνýþ]Ðÿïíï~Öÿ}ŠŸ¸þO~ï*íßîöŽùup°÷õÁN½ö/¬f-«ï5̽76ÒòÕy|ù®Tôåõ¬¸OvüÝô @mìQªóþ¬¶5³@pq$'?÷Vzp%ì#[¹~7Œ×›ü\”¤Òâ„|†HxÚ k!U:®Ò,h¯mRàkÌ4"Ž^F4c=kR8b™W±ÃÀ ] îVþŒyWLýl¶Ÿã¬›kÄL;ªGÈ×Oš;LvŒÕºV÷:s{£]µX“]"V±aÀÂ%…&c9‹tß=0Õfé| ó]‘Ñ^›çyÛ˜rwì«@Ž2 À{¸y=“ýräzµ!@¯µÎK}™ËO¥‰óݘƒ|eÞ` 5v¿´¸}ý¥}I½cg€ >¶±ïù•›¼=*jäªN„°e*\í¨-*•QW]A7EÞ8t%”‡ë»ß“ÓÃ*ÿ¯míFm¬ºÿƒ»¡ÿ×ÎîÝÏ÷ÿ§ø‰û«þ!`¸¾F^ÀÈðÉuø{­¹KÁ‡¿À”YæuY8/håT)ûØB‚™e”ö¼j‚Z+HÉKë~ÍT¾P÷™ÂÂX}§U1ox}1 ÑÔldD£…lÒø‘냕òg!_i/êB¯læÇfæûÒõL£Š9©.­¾ˆ€EKTqÏš‹éÊT'Uʵ­d x ÚåsÅÛ<³©§;íä÷û‡ù·»‡ùŸÿ,¦[Œ»&C:Ëñ•³Dß=l'¦þ¼Î%':¹ªa5_Iê;-ß°î³åâ5tþ~KUd~m½9˜‹Ž´¿ÅÜX6Þlu…ùwà=És›êa:?E…í²«E,(Ñvh—Â-ÀUŸºYP ÔqØC0Ïe–ÎGì‚6Þ?'íûmY²Ãüñ •£Í¸-±~Bq_ŒZqz yÇî'aQ¸8Þ?;íP³jø ³[·üôÏ÷¹ŸÜ”X® —ÙtÜÐNû°ÝåZ¬½ šÃ¯ü¶’šªü&ÅzçOÎm^=üÐHPÅt„a5J²Ô.4·Ùl:Ê:ÛÿøóöY7iÿq§ïåßÐ1Õæ!l‚›žÿUôÿCy?øYÅÿíîì¢þgp÷^Ðý¿÷ÙÿûÓüüŸåý$þãÞöÎ]°øìîìí^ƒ÷CF/1µ?yùÊþzÇÒC ßk88bOÇ[£b†/OOOïžÞF±ÇևĒ·úON³ô3oyÍŸðü²tv–Í·o³ 8ã÷ööjÏ¿ùñã¿{{÷öÿìÝf'ê~þ/?ÿuëÏÿöèù‡µÑLÿwï Øþ€»; ÿïß…õÿLÿ?þ¯ÿ÷W/‚Á®²ÿß5܃ÁÁÞ 1úçxÊÙ}˜Õ,9$¢\sÄœ†<Ùh‰hŠ @rL1)Xܽ êàÞP y×ó6ó4<£„Äé‚ÿ<ÄýüX#z®‚ùË&³ 67L/7f)€Hn˜ÛÁ…Ñ%uéµ¾qû—ô)é)E’½õi7)—†³N ™Ž]ÚÈr)8Û0¤K‚ªCôIqVb:9®Uò[˜kð$Ÿê7ØÏ¥M³ä¹îÈPÒI²HË·å¦ë½~Åø&tÃ÷Úßn›Õ–Ú&I€åµ"$&  0ÍÒC Ò8ðx~/ôÜVø0ìÉhfÌÇvðà§¼œÒj Õ¿ez²ëzªy³ ~€%"€§.UŒV3‰†Ç¡ »7ŸÎ ]€à»Ë ü!n·^Û›¦¡OuºˆÛ7nÀk»Í4A»–C½]+#ÇyÃ#8+ûõç`d&ô6ç`¼Äø%Äüt=‚vrG Úk=€ÿ¶€P§)b$™³ gLï}ìZ°ù$ xIÛœH;ØúM•lŠmÁ¥¸âæ"¹€çÄ×Xfþ\oä­k]N>Þ¨ñÖHG ®Fßj=\p_rWì¸U@•»Ú Q .¢:òÍÕ©ÍÌ“ÒzÀ¿à-±œ™é¼­KR!÷×¼ôÀ{áÈéÎulê³ë›`–ÍQ7x¦ƒ§K¾~ÝÐêoYÐEÕ®"&ßH—‹œ(­lp³ÇòÀ§ì<‚[w=ðƒ<·Âzš¿Ë’ë%Ë^׸I‡½ M÷ÒB˜_ µé&/ùwq0¹ç&à .îsz9uy <|x&kfNE7g&“,Øî‡f{b˜¹ÄôpŽaºjóñµøÛ7¤¢rôñ|±˜lo;ìˆmi¢"'µ«Û(ôY€ôã|¨y²¬åCé%1Ÿ¹90åëõª \:KËš ŒeˆbÙ~™M&‚&H©Õ aÐÃE{Aý “É=%2(%b%^”µGç™yã`Xí%Åa(ä\dC‰Ä ¯ºN@8IJ?<.\ú9˜H€èÒ9ƒú™‡á@,Ò“²{‡“G@â¹w9ùÌàÔ÷š¸¥†•à“tí¹Ä‚«'æãM¹ÅDýéøé«á“gž _½øÛuV¤iâðîm˜8¤2·8mòý1¦Í«ùcO›&[Nb÷omò¤Õ2aå{ -ÏÛD@¥ÌíÍ¡mö£Lb¥ö¾AiÚ…ðþw T·¹ÆD“…|ó~·6%ö–¹L%½^~‚J-ÑT‘Ú W! ï]pµ„ïÌ“ÏIY…ŒB‡Xî'B>‡=¼z¨ôýDòÊP~3•¶MHÑöSÐð7€"˼;„&ÂC„ðKÖ†Æ'çp—&_‰é ŸJîVz×DWáæ'D!7'2øð›Û*¶&,Ÿ.3TfFÐ °Ž%(~ž°¹˜\:*€W§~Š U*^€0¥’íà3y?ÍG™äR¯ۘYYÀßió·b›Ÿ›jûß;®~›:`ÝsÐtd”¶dÃa¨”m>kœ& ¿®ºÜ§<ž¦ ~êŸý *Pt"óÞ¦VoÝ@_$à4£àÝ5È3/„íú­3ÑO¾?zx=R#’N´Æ ?òo×¥ãQ#Vè+Ån j.É«Âùê«ÄLŒzÓOæDnìi>.µ͘\b —} L[ÅLKÝ! qÐ8:!¼aä¡Ó|$­ÌbáG.‰})êI¨BÉŠ@š¸bÔtªJćˆÎv²ÞY¯Ë‰ÒÌ-,ÆÊHàmke5Y™E[·“”<~ÂÖea3S¢3¯D滌 #¾K8å^j2—A¬BXÓ´—B{ÚƒÝÊ$Ö§HŒV’¦É“ã^2Z ¯§y x%T 4Šÿi6qmˆ:#h‰yD}…6ßáe®¢@¾íx(ƒb?u6RIâ´„éÇp诹üÖó×›×t 1™<‡'BÂä€Á—kä÷!|‹:©ßÖåô‘b±Ik¥0uD%®YƒD¯›°#^Ì€€£™g°¯))h³o ¾F··kœbŽvŽçEÖCú«G92YÜ2íÙ[ãqðvçí}Íå]Ÿ¶æØl¥cOÜ'bÊÁ~}ùzíÕäEà(^Û¥… N¬¹×ÆßÍ׿7š8º…ÜuØnb¨p¥áŽŸ.ÃÛ¶”úÊ^–y))s2 ¨ª -RÊÀò'9<È>vØs‹ÄX@\eöÐäJ‚v;ÁD‹ó<{¤ÓSh‹I×ukº,æo1«,ź²}Ä&»%RÀÛu¤Ü!ÎP”Úè0I&¡>ÄÁ!žXZ(b+yQþç2sHQ*àÊ_xÿÀÔ¸«i¥#Ø‚ÇY1 —jÙ»Œü„ôØYš“´ä„KÉ»<µ#Ig9&žà’{NÝ%¥«Esb7Ë”­À!·Jgƒ2’«|÷ÖŒ o”8ñø´v­­®Úbê]IY›©½®Ô¦Æ’—/ßá¯`0œg#Sú; )$.áâ;Ø3ûŠn<©®Òu ‹Â¹K`ª¥ðѪCÐ<+=©ç‰ì[} ˜¥A™¬heø‰™¸™ƒS p6K¿féÒT­¼Bx¯ÖÞŠòþ+, åoº ÿ¹kÁÿ–e3ErÒmTlà8‡¤Ë¥å#¬ ù 6Æ@¢P;&Û™¦è5놯/CpÏÑ’ ŸáÔÌ †Ù§]ãx5ÎY>>ÉÀ°'GÈ6`«â&^Ðâ›—ß WÇcÿP°þÂIÖ0¼Œ–%yâˆÓ08¦ð«K#Çy71Õ‹ÍÃÊÝxm*|€«ZqÍ/e."ÈjGŠÌ4Ö0šm^öcÎpøYMcaV7â Nºïl•ô¢˜µù:-ÓŒ†ÎX¤°$O.„SE-Út‹É-AšŠž­ë-ì2Eøó©Ý#°Õ.3ÜH´õr¬ú2£}paÍ|6É@2•.h/Ê%±ÁT(ާX d•?:Ô, ¨ç–}…àRÎ{P“_ðúó^Ǿ}@[5Õ[ îFˆ|»)¸´x;›YDÊìòF-¸Ì芦û ´5©´ ¤¨ë6S’5¹`³ÖžhÅ^£á¸Ài﮵ËÍ„4‰“ÖPyh]ÕÊ™®©:vÃ:~ýoɤÖp”I“kÑãÓ¦*ˆ½OÓßþ>Y5Qœ$s°ŽaÓCúÔ ›ŽT×<›@@6²mQÖ] íâW™­ÇŸ·óCú܆ËFn;çP'_#ŠÞkó‡}ÕÐÕk1F+z¾¬ôü:,”…ªa¡äýF:Piè?×ôK&,í¸šJþ[ÇÂt9¯ófò‚+qæáJVrö“®ãV˜iäßa­³¿ëQ¡mqî#\‡÷°p´Â~˜)ð®"ð¬Jii.r 8³ì-8²ç‹*¢Môõ&tRúxcþ¤ž+QHÀëµè0y«u¯C²PÏ]G¯ð¥§Ž®=ÃhÕ]ïì*{2ܶçûgÇ2¥#Î>t•@„üÔ6w>xÆ*PS„íC&Ï’ŽÏ¦]!oºþ‡±t¨T¸ ?g?ü}2sì\éªoK=ÕžÎëS3tÈ„„Üwú#)átÒ›+áðÆššû íYRÍ8ÿì|*û,ÍæÅlžĊ_ÒU³=¥x“Z„‡©t÷ÚŠ·UÜ­®¼§g¶üÙ„U·öS`aÀ_—9HÚ;ÂSe—äzhÓOL1»| (a$PF+¤Ë×P¨³N¢ØE-ðÕWÀ£N—Ù<áûÁ&>Åßw°,¦ŠÐWr…Aæz¹ïr]ãr€¬½ð%rˆ_m@V ø—77PW³+ΊùU˜œä¿§;)ÎrLjl~1‡Þ×ÚÝ:óË7ks¾T>Æö‚EÐÍ9;9¼á•‘»õ™Ir•ü 8IŸ¨Ö°‘LcC^Òqv\B ÊøÇGäêªUª“bÕMrf®ÇÁ‰V½9[ Æ^î!ÌË…=Ä…Æ;Vˆ|ûf{ÙºŠ]c?/ÿL·§o¶k7¤Â¡å # ] Ù­.Iða°®z%ž. ŸhH¿JrWr`Z;ͳÉy›‰ xô“—A òaÉn,Dí(Ëž!ƒTY=õŒâg­Ÿxí)‰5ôOAçà s`‡¸¨Ôìîo ³+ÌpÄ1Ez++ºè´šõ'|¹¦ýÄ®œL¶ü{‘Îì3ØC¦vyN7Õ%¶«ËËQ´§ð5| ÜC^{^hoh½½~ß•Šþ dÏ«s”xõ¼YS7d÷^tX¡øóì¢@ûÔÄ`A4 ¤&“¤‹…Jd`cÄêüü¶`jh”ÎoèÑñ“ã—ÇMŽBìýƒþ@â—™¢ï3RÇïàgþƒu%ú€6šñvvî vÿánP (ÿëgüÇOòǰ«îÀà¾Þî ô °»wpw·ýᾯKþ*ô)–üõ{ð¦vÌ ·Xä’®†ÚZ¸‡ø5÷”]=ãÂû__þô$–(ѧfö óÄ#¹ùV´½¬WÊ0±ÒX@®)G§t·ë%WTGÊé¢.$‰™85+Œb½\0:sN}šõÊöo*Ïhloe1¾ÛëÍÏ©ø±¢0¨€Fù"T¬½_¿_×oHWŽöÅÃñÖúâºï](jà6Þ‘ªŒÜ°êÈëö|9¥æö›¨Ë^,­‘€‡€xavþîó}lt9@¥ˆ <êíû9[…—d/}é8ıUS 3:tàú>¤4 Œ]á§rFpr»+>•x`Ä+™Oƒl£¸×i‘AEeá`ÖÞõâ¤ïö0tæ5‰aÔÁ—Ö¿b®H _Ò_v§ºÀ'ªÌÊþ7ªQ™•¸¾í„ׯ $;âã<¢…a“NÌ–³3\¶h©ÊVøfªÓlèEî0nb3nN¯Ù}EC ± R0âiס #ÚÞê,Ñè ódè à`ÎIøCª ù”í¥ĸ‘ï\÷Uœ E˜û7¿É®ÓzŒ¶ÿáã9€)è Bè žÈlTìY^ž÷ÄÛ|ôÊ…ˆÀŸ«ÃHwÄéºöÄÈÁ¢™H¾Rˆ¥$¥Š©Ä½ÝfÍñ¿ÒeÁè„3 Ûë~b¡-ùèÕn¯ Ü’¯íÚ,èíï\ýÑ÷ß¼féĆOÕѳh- %/ÁÂ2.Î “"¾Q÷ˆ÷ï«ó´$ß>Y!€é&v—±\ Û Ãf†˜dª£¶FûÍÏyäÐ[¯‘¬×¨áØ×ÜHa®NïÀy6ÎçÙˆô_u4;ƒWQôvE_ò€¡,wDÐt ´¸b½€"7*º*;¸ m)欱6üzñHÝ„"‚ìT¯”„ëfw½­ƒuÈ^jåYMÃÉÏŽ§g€’¨Pý¥M­ì7‚»€C6¡žKP<l™4Û:ÕD¤X3?¡JFXŠË¥håê ÿ<³é­ÞøõUúž$Ι¼Ì8» COPHÌ¥eÁ9rz=ש/¥`ûÍë7šÉ-E[æKª´é3.Á©ÕÏŒÅôóž›>Ï 6ŽM¹ò1‚ÀÁA íÞÙh‚0yla!áwäjmM}þ‰­*¡ê)ú S8åÙ"A="eÈ+Ú$æê4wÜô ’Ëÿûß …pc¼›šDÒ6ëø¡úÂ:ÚÍ+®þ©UøCêÇu‹ÎÓ†"á-,½Ò]ýý© \¢]ÉÞç5g 5áfaìérŒžƒ\`£³R±vHÚàò‘´ƒ·1šÐyë:ç÷ïGO^¿¸Åó[‘>Í;Þ̱æÔG•Š Æ¦€eÄ` ¼€qÀœ°|äƒÚë%GÉ ø±³CÅ$U)®–^ šjØúá—£V0w×="y,@>k´È7wì] Ë#üœ ÆIqº5$Í—£ÉrŒL8Wù¦µ&|lXÝqÆ9/ÈeMÙÈ^BÆUx?î)}šÕPø„2Á%ÙWq´#]Ã9 @÷€%Ü{¤ä þ>.µ¹ë9¨˜©0¨',ó ¨g››Vë¬ß=³ûÙ©˜«½Òbgc·ã¼×HÿÀÙ[zwféè-øÞOB^€-63¥“;ï2Bñ¹Ÿüýøù‹ÇÏžÞÁ|P÷“ýÞû;w}›®¤&pÿ Õ |! zj&á›­þÎÖΞª¾µßô[w ×Ë‘-ª¥u4qf?]Ñh vv÷ö¾Ùß|ݺó»uu^}þÍx&“jcÅùßÝٻ緿owwÎÿþÝÏçÿ“üÄýyÕÉûWò¿}ƒÀûÉ`ïàîþÁî×1àš¨®¯V[iß‹c­¸z õ ³Î\pXŽ žZÞ¶EˆzT$è’N u™ŽÎçÅ4ÿW%s &ž“ØFXØ“”À®E«å>Ï{ó:HšËéª1«2j⨌Ú{eWø›º~ÈkbCé¯×í?U±¥UšJgÖ¶"~Ù8ÇŽ]Wõx³l9ö3/IëPTò…mí69§ó¶“ Û”¸_ïî¨ç`‡™.'”=ðÏÔ;öàVÈöE0îŸçùE:¿Jþ–]TÄ ÈÞ5‡Ô7œ]'³±\¤qÌi. CBP• ~‰z¶û•ÃÜ~ÏsáÐì&ÐbóLø3ÁJÝØL¤6FùfS±³·wÛsÑòæ‚üüÚ¥“D@ô赪C!ñbÅhòé¢}ƒ÷›Ö–‹µ‘¼Dr˜ØoÈ4“Tl•”—“Ë•••ôóO…‘ 5š1žæ.îã.­á¦5­‹ŒC$‰Ô!¿õuù?î'äÿN&ÅÙ­&þÃuó?Cþ÷=#~Îÿü)~¢ëÿéAôVù‘ô³‚ÿ¿7ùßìÝÁ]óÿ}³þ÷öîí~æÿ?ÅÏÿû ìÿ¾Jÿ¼€þyï`°Óø³ýKà© ÿƒ6¢±?A ùæ0a³X©˜s¢xBòÓ10š©B vFE:ƒÚ:ày¡èªaØEçlb4I6àŠÊ´†N‡ ü¬Ö_05L‰U¶\A|ÊŽ–X÷Öx„¶’;’#E+yYËÛqå— ˜¼Oý àÀJ N‘¬Gî Ýœ‡¸uô²ûŒx N±Å¯zèq|åv:ãyoùºXFí¨ïR¥-¶: üFm’ ¬ˆÕ.D Ùìµ¢°¦l‚§Ïê†aç¬FËúåÜ”–ÿ9±Úâio Úâi¯\䣷Wð›ä&1Œÿ×d*¹ƒ¬‚:IúßiGžüqÌRB]ódàôÁÒ@òèøÅCÝ üÝ2mÏD:° t„CwðÜE˜Aß”ëwm€œšx2ü§%š‚¡íŽž¼8†§JÝŒ^k(›]d#š¢ÁÒqx?Œ÷ 0›]ë\âµMÑ´QÄ@aßGZáÅåjËøÖ›˜q`Ím¹Ò,;T– áôIò²–x½_Î:ÚÈ›«¶”‚?!³*M é‡ÂžÙôÄḻ5+;˜ãomˆµñ¦¦×Þ†"•öüÅ‹d+ù‚ܧ]7TÜþ*”ª>DõÖèôdBAݵDz’¢{”8WB”ë(«G8Ç().©‘z’Éê§µ‰æÇ§a×§\‘TÕ’¤ÿûRœ<-üÝîÌÑbÇh»ÚêOtåôÂSÊ­u³:M ¨öø(¨&ÆGU ¸Ã9¸ÝpøõnrJâµë¯?L6ž\½íÁÇišM^sê: ýE¼^Òk _è@.)¦|=Ͷt9=)‹Ér‘Y}N-éŽÜ¼¸\çÄ9Z_àá’­ˆ7!•êÚÞo~„ýÕDÿq ý¿åMu}Ân¢ß5þç%Œ€oÿ6]¤˜#ÏüªÔþMwÎê­ó[˹Ÿâ?õúzrm¬ÀÜÝß#ýßÎîî=x>¸·óÙÿãÓüDô?œÝ”?;ßÜëíôî²õwg{g/ìì öšñŸÄÿ€î9º)KË|rÅõgËI:7 *à%Ô€ @±žj¨!×BUŒ›x‡¨×uI‰îWŒŒV‹có÷VP9iŽÈjBäWÞ„FˆnK¾Í.8AâÛmó'† „0jH³£“K0vaFäküÎâŽ8x‘æIše‘0!’±ðMuj¢ê% UkŧÈ+OÞ…_àÒ_à‹ ü:ÃaI.: ~G.–œ†'”-I3’™F¬A™¦ÅôêbDxldî²bA+KœóáŠx{ô‚Xë|„z ×£Óˆ4éît?ùH‹ñßá-žXhz›±„@„c9KÌ`RžËɵaT0ùBô[˜ g[rq»¨{ù»™Œ˜È€ÚdOœ¾Ï)Þ]¼Þj­çY:v0"Ú½õ|«Ñ•DåµÉºüMw|o£ÊÕý D{ÍužMfñ…o6féâÑ—ÏÂ/|ÒFqõðÙ—Ø9}JöíìD9ŽUÙgzÑ\ؘÝÛÜÔ…Ô"èĹΕÀ*Ñ6p‘Ž3sïÃHĽwAšuÀϺÖ?˱ Ãâ'³ôIpýpûfS î)æårrE*ôVÈ/² Ußn›Ñ fbN!¼Ó¤#.¦›ØO Ýá˜c;”r˜§é»üŒÚ„]öoqr2„GÑŒØu ž' ÒÀSlí'"„Ì3@S\M½Æ D°2ÿ`ŃÝÎè#Ö܇ëù‚Q° k=™˜P9Þž&4ÏÄ£×i³ÖšÔcrd¦×­U ÐrQ\ ?H¹ÎÅ„&LÄpN¯°9¨ J¾¿ÌÍnDùfó]dÈšŽi†ÝCš3#½‚H¶‹báVVüÔ¦ äOi>ýbÈuªä{®hj!i&Íߣ·,„í Åö|›&çóìô~ë/X´l= <Áæ²÷täÛíô2&ðHoP% Á4ð&Xg0wÍö¤ggæô§‹bnG¬—ÈžÛœ÷K>"÷-·®SÌuCÓI* ÝUlW¨ 1¾U“ÕKNrÊÆŠa€X÷¬˜-'j¶C¶š¶QB–Úú0á¯ìЄº)hhwÀI1¾J:©Ýj¸ææލ¯p*!%O1ÏÏrðáÃýæ“É’Vä=1I¹Ì)"lݘ¼kJâŒYøÿ\š}µI”ÓòR B€7³‰,¢aɦC™òÌ!ÑB\ržšt6ËŒø í¸…‚1²w%è5Ђ¢ÒXÃ4¹U·YÐz@[v[|7tÕGØlëKOÇõxfªÆ¯iÁ©SéÔu‹H]u뛃ƒÈn¶éuö‹:<‚ø‰—†£hS·Ãr¼¢ÛnÀTøöÎÙ8‡pǸ°Ã;e$Kðzn&ç¼$‰^¶ò¦ê¬E„! g P¶X̶·]°Ã¶Ôì+~ÚÕ·V†µØ—(4éuáÍW*¸öX—¸‘£FŸ!†?¿|ÝÎ#Âpè³ù7õCî÷ñ+Öã¢Ä‘wð7d’V×¥£“ cX<$ÀòÓ¤ÀH-# ?@¡‰ó4;®…¤¢ë¥¯µ;3Ÿ[q)Çý‡SùM-?Ósm3vû°û‰6)Ü$Q=F¶Íì|0 ÀgüÎÃkó|Òá7À´ŠåjlÁ"¿i‹]Ùõ#ç~ é«êƒm<^›•ìyïOÝä´G65DƒGHOá þBºww–PÖø5É»ÞC8ˆ¿&§¬›Ï{¹¶íä½SüóþE‹ª×ÂS#:8þóЉ-OÍ2ÈK²dƒÛO㔤s¹Ê:,œF3ß d€±ÃT·Ø· ªzGι­DÖ³Ú=»¬í®jðTZlA‹oþ1m©= A“‘‚i‰!• zçƒG‰‰^{tLþ6›õüržýçbÀœ“²y(&'~áOîówþ°å¶ý¥ò–ÞÚÓаFCêé9UîYGDÔU|=µ e^)bè²ÕáCÕA4fGÉ ¾±=0×=ä£Ý<˜Q€þ©ôðXªï!ð{4_^œ$S+pô*¢9ŸÉZ©¨+¬”1ûÄVÎ(›ÿµ`²š›ðÙ÷d“îZA·¾ˆúÇ}áj¶ì£@Í£9Ôji6‰\'&´ø³·ŽêŽG|9ðD'³ç»bù‹ÃÆH(ó5 €ö‘˜ò®•4Iʉs·}a­ÿþ7'Zƒgj:4Ž f:+HƒgIÙÐà)dýÊÅ\<'… V½Èê.,}á‘öh(_—C«Lª$h ‹V®ëî+S¼µw•i£È Ò󨱷T¡®éÑÛävC !8[kl=·ã[Þж"ûj;6Ùj€|â$°B{Ú:…“s ’‚¤V„­µ¤p.5{ü޹^QV¹h“ŸŽŸ¾¾xõãÇ/^?>~yü“ÓÒfç;ìõ¨¶ÿˆ*G³¢CÑ©4 ”uk U'´Ã‚±6ýÉhªŒõ°kLŸ­õ&“AN>ºÚÖç·žË<‹øk6™™1º€ÙÂæ®EÿxN ‹¢ƒÕõ O Sߦ¶¿vŒH>Ù¬"Å5û: nß=î7X+Ø5øô‘è¹mZ#6ç ú¼­à Gw6ÕDÉbÚâ<;Î&FÀ¶¹¾+03^ð…|bcXÛëþ›×mÌOÄQ ýl›owÙ‚øY5‚› 4­ŠkÜ¡Îê†lÌÀTW¶AßGýCN›Å7€7fñÉ=©8‡© oËèÑS,øð°¡´sÏÍråfý»Âf¬w‰qu lεP.Q±rD7ð} ·î·vڹşzÿ¯Û@þ¡Ÿ•ø?ƒ}ÿg°¿¿ßÿìÿõ)~•ã—ÿÙcðŸ}ˆ÷ëïøÏÞn2Fkš‡þX ô¸~5ú}á*Î_`f!+ßg”ŸOöž3yË‹[¿Aü÷ÎþÎçøïOñ_üïÖ¢˜å£-¥[\Ì&½Ùùìºm¬ ÿ;»÷vÿ0èïïí÷wîÝëCþ×ÝÁÎgúÿ)~|ÿßæu'—`¾¾ÞîßKú_ì~s°»Wë ¼¢F”$Q*p~IîK s1:0j.¡¥íN Ýø/Èôö'Pr.ÀîMá%Ø:}eóÃY— À(øÕV²ÈàŒájàÇÄqÀB†#@²* úâÕó'«K#'Lå=Ç„Êü¸OD;„~ºzxíL¼d]G¼ÒòišŠÎÓKê»MÀ“–Ä¢l܃¦àV&Ëi™ž’q”ÀUQá<½"s)BóÒ*'F“,äÚR`ЩÝTlajÑ4ž™ían_4Ì µ†¸ÆC\ã¡Û:¢-7Û¾ó݃;xØÎb–8O›‰y›$*WL+¾©q ó-ZPb*•ºð•Xò¨ÌÌìã…ÛP‡¦`Kš£†dƒ´h¹üTóc±ö²ÔÖ7Òª©íÁÿûÿü“jc´öß=‹ ê38ÑJwÕ8ôœÔCöbdðªy ¸«ý¯6 }Oþßÿçÿ×ÐÊÙs'|ñ[“ÞßÅOÓýâúMï|ý³âþß»gÞ™ûß0† ìßüÇ{ƒÁçûÿSüÄî½îxçßµwþn?|}°÷uþK¤–ëÜó)% 4·ÖSŠ3eçZuÃmEßxhÞѺT³½ä1âÌÂ7yÒµ5]^dsÃuäã¶ [CšúÚþÙN s3©? %ËÇG¥]^ô’Ÿ1‘jæMÕäè^Œ9ƒ’Ã'ÒŒG¦Ýié ܧR†ûâOÇÖƒ¼Ú^$KŠwÈO%Ÿª©Ü¹ {R•frJê Á>š~À±[ªõq6[œ$-.“q–ÍÔ÷y)^Q2/çy6¬¾« Že'óô iCøM”íbEž‘Á/ ŠGÇE…ݺ‡æeô ¥¡ƒŒ«µN³KbJÌ~}9_fÁÜ:f ¬ ÖZÖ€\ß‘ôÖ~ß^ùႸK¾pÉÇó0H¡*†ÕÏ&HÁq™\÷¶XmÅdlr” NF‘štðkØ)shðæL‹E:#xb6£­Ž÷KtéÒr14Ìá䊇Œ¢ð’¬5çÙÜ쀔gù2%®œ¾æ´ÏÙóƒ Öä@ 6ÊuÚWÄi’p>FÒcl„n ç„ÜËrO0o³˜[¾kqþ àžÐ´7‘›3¯ëK¾Ä…2EW–ü™õã«ë|’RÄEXÚü6'6ÌŽäÛø[áoX‰K"t®„ðqCd‡œŸ;¾ÓL„š@˜_å[ÿ¬Î3Ó;×Tõ8‰•ÔôreŠI9K§÷[wmö} ’h·µ´ÐjC#¬™Z؆PÙѤà$Àl )-Å™³GíÿÇ\TïJˆ$¸”ÿTSœMÕÏŸ¤³ŠÜ˜ý_æcð–_ôÈk“ó`X‡!™@.À'üá‹Õº&Ùébë"Ÿå”f#ŸŽ­L”ÝvAâÍž!Îp³Ôì-BQ]­í®Elêš|± ȶ¢‡¢Ü‡UiA݇,ë°P Zr2N•¨k‰§Ú1U0Þ°Îà€íGÛöe®Æ™ä,¤õsgÛØþnGöEl3ûcƒí¯åµ²Uíh0«"W—ÁÒU&Ô]v‘ù<™'ÛÁ£¦•æk¯a±ùz;ÔÂíŠéV“æÍ^;5ÍÈ…E4/þ=Ü9[x+Å+q·VPKTz*ï˜zZi—‰«ù.šfA·Iþ£¼‘ßõaBà ùo°»ê÷v?ë?ÉOLþ«¬; »7QüVªZG$¢#À;að!\tDp£fÄ.Tø^™?!¨ˆ•ÃÀ̹V×ÒùR41œ ä'JY¥4–‘˜I*ç³ÂÁFm†.½A”¢'\Ò8P¡¢T7’¼Bu©Çbѯ Å(]èø‘Uæ×QÚ©áPý÷¡B†nõ ×g´ÿBÌôYA$Ü,ˆ`v=Ï=,'Hƒ»ÏiD^ •¦ëŒ©Ü¤Ì¢hO·Ó¶Wò³~ï:? ôÿÖ<@VúìùŸ÷vî}Öÿ}’ŸCEøÈ~ÄänÌEÎÅ9È÷†\ór´D`”´ ËEr–¾Óö¢*SÍéÈ4@`ÂéûbZ\\Uß°dþÙCäv~ÎyºøYÅÿíUø¿þ`çóùÿ$?þ¯¬Ñý¯Ïö•7Óû³6µŽ‘ Ze|U)Í=¤‰Ë0}oÔÈÿwaó†¨Ã1dÇ7P8Ô£b„]»»tža+†CyLHÁ}M…[µ)º&pU…ÆnŒ#ÆüňPb=ÍkŠã¥h9µ©"逾’Ø;"^UƒË¦æB­.eôÕ‘6VõeÈifAÑ{:I1L@˜s—ÚZ,20^]-ã\jeNý>›ŠÊ«lUØFr2Æe% þ"Ú“ª|^ÆÞÐlãùߨ¾ÜÄÿ!¸Á-dYÿx÷Þ]ÊÿaÞëï`þOs|¦ÿŸâ'Bÿݺãð5'ÿ ñ·0¸{p·9ùǑ«$ò:2«´v&"¨^" BB)°i¿mCsΆݺÐèŽàEüüìÅË×Mê 驼aäÅG„A·‰¡@iÎÅNÍ/T²tŽàÀh@–@‹6uË׎;áóX!$›K'r&l.²Òxx5álÐÜZ€`í·hÏ^”שÛ}T[¿†þxŽ5–to_à²nš®<¹,ÕB¿+Fé ¸_ÝñóŽãš•e1Êi¿Ðµ¬ð£m}Ùü‚§ˆo‡ÔpækVºüÅ”K´&]”öQ#$-ß"±Í†¿v¾Ú Ò†G©ÛtôðÏ~h¢ !–¬pÕ kòbÁÙê0Èœ)ƒ¾‹‡àÀ4n‚(Q;‰7Ãoýfà”¥ï2®Y_}ÛHÌ£¼‘®W½½uU‹ëÍFô 䪾ä–ß &§]¡Ìm5C_"“Þ ¶½xêÓ†åg"øºÀkÉs΢GØSœÚ›€¯ l [Ý Y¨§ø †ûZæyøÕj×ÉuÊid%)Q_F²xµØ´PÕjt®-*:¶!¤TÂåÚQÃ4ÇÆRò*Z&†>÷ؘG?~4|zü‹089ξ¬#D•f@°<°æ/¤Ó½§D±óös_نʚ†Tµ¶±_ùßxŠ—‡D º¿àtÿ¦Pá¯áßmñ^‰t’¯[°ŒÈ™"q³–³£©~õó££—Ç;"¿ê˜ƒ¸âà»ÕS{Þ¥s›«œÃo|=ÚZépMÓíûÛc2UÑ´mýž˜M#þÕÐKÀJT[r6÷j™Ñ/ðÐN¥Ïy6±­¿®gâÙÛĆnBŃ]sœ¥t2T6qy¤R0ço‚P¶ðªr¾ã¿6ûÇ{½Ë¯1pȼGü7¸[ÌjÚBwƒB“,­”ª®v³fæé8/Ê:±Šf‡¾¿æòÐG†|ÚñÅ¡Ù[cqÄë‚fIy“¨µ`®%J·p.6£\£¹=ßes€`°Á³aQQt'ƒÄH TÑ©^d¥ELúa>M–cHp —F¤åkSÿN&ä6“ÿwˆ9¸®èËîj^Ó=exüwšgÔ%e,x—Ÿ™uÕ„—8n1?p÷O%6-#neˆ±eF\åÁXµ·Ù•†ds4n^x‡âræY–++fSGèwˆ<èi™ã>P:œXÒ¦ŽY±›éüĶBùÚºYPW òT¥¿ Î1§Äü8ï¼ Å¶m±Ú!‰šV©Å¯×Ö7õ¢yR5: ©ÑžggÔ²<ãe³ºœº ÒÆ§C]+¿c‘\qwO1«‹¹ñbdþNµ¤,Àl!P0˜êÌùŸMò‘ÙÏWJu§EÓš³âI²±¿î+ƒ7¡Ï¯8žÑÒ +­Z2Åýç.ë.ÊpÖiÕ–Õ—Å—èÔ±_4RΫ`³z²eZ¸Þ)ÕLáBÞµžgjƒý9u©…]š$_ì¢PÌ„cÿ¤,8^®›SrNƒbø+!Ðß@袃R#vÑæ4µlûgŠê_ýïNýsÕ”êÀi*ˆ'JNŠ÷¤›·1634ÈH;¾B3AþžyÉ8BÂÝÿà^^â`(ÕЮé¯( !¿œgˆj€±¶á`ÃdµH@÷F˜ ÀfÝ`hVÕCØŠT¼ 5%ü¸cµœØŸZEO oÿayžŸ.\©Ã ÿ™1l"wm#´ûÎxƒ+Y®½Šògžexw§‚ª´¼£tÚFu‚›tÈbµ0yÚ5ÇpÎ&ROß¹®Ung){Œ™ñ•7þ{|ú+ÓÝÚ!ÐH™½#ýuû["ó¢X`š;:e¾“î¸.c Ð]¿»1þÖݽ¤<¢mÄ=õoRé…+ ÝÑQÀÉÖVÒB€“žÖKÅn(1ϺcÆêˆ…Úê¨j¾—å’ræMÒ‘ËbgxÚ¤“µi¸úwNí/â'm6—ÏQ¦³ÉÀœBLhp/0yǺʹ«¶Ë?xT{UO1Æ}Ý^Ý ³&GÄEOj5?Ð!í†ÂÿÑHz°Ñä:(*¬òÿlŠÿ…|{Ÿÿi0Øü§{»;www÷{àÿ»¿÷9þ÷“üÄâõºëÐßÁÎöN?éCÈAÿ›U¡¿º… ù#g³y1›ƒn‘’:"ÿÀ7±†ly‚ð~Šy̱%ã±5ÕÛAFZ | ´OñØõQbŠ`AíóO´ùgËÔ¿â?ÀÑæ3 ÐÒcD‘a1Go¯ÚkÆéBjBtí«0Â΄ ÑMÑÈ}¿eÞ´ªq w"¡ùi Zy9âãSÓ›MÏZ›ê³š&`á¿eÄÿå?Mô¾˜ôFeùÁm¬ŽÿEú¿³kžîîïCüïgü‡Oô³ý'MùyÅ=¢?ØÞ¹— v Å?ØÙWD#6¾d=³‘©Æ=úX±9jm‚ÐAÒïíe‡êñœ’½Ù{x q!àP5oIÚ׃䛯ÿ˜ìÀû_ïPÅU¼UÕÒA2È.’]ó¿>ˆ9õßô|0U2üeï[é$?3ÍB¡O§“"5]Äž®QB–†uñǶ2ª{5Oö)šâ¿èÙ‡·Ñxþ ÷·wó?À³ý»ý]8ÿû;{ŸÏÿ§ø‰ÅqjgŒþ½ûuo‡òA|½=èoïÜMßôïܽçÁTbÀà:HOšó g“Y%‹Û$á•‘¢çÆh~F"¡õZ†~èiÃà3¢a6RJ²5ëdÍ/ƒx5s”%úp¾©È8µcM"e(Ãâ pm [;w¹íÙy 9)Òù˜­?e/ùÁ…A,Ë œO²QJ9¼³+ŽU@„媽ÈÀú'¾Ð 1b€¹öòõlZ.)Xù è »à8çÔ* pæïW8Ö¹‘yO3#ªŽ²2ÍJñ‰3A²õ@ÙQ­ i)¥zÇÐyS(eɇZ`ï(ÅmAØŽO‰…O7y¢)§Tn†››­ƒÁÙÉŠl}d §çžJUuÕéG1?rU!º*‘÷Qtñ‹ÑhIa곬˜áŽI1S<¢W”˜]Xi“hÂvÕ³^™)[í7{t­¾Sîšc)žŠO‹¥;?xÊæ¤Tíî*Qﺎ€jL®6Í#D¦mÃêF®×Žiá{ÈD:jÒ¯ûmºýå7BÔ;PÛ”‹ùryíqÚó-Óô•9ÿs8K¤¹šNiÿ›i´wñd_¤o1e7$°a{-Dòãñ:ͧ’䊖³œe£üÔ¬‰šÏ^{½]ô BZ±‡V6WÞb $å¸úƒ•-'¾ä\c°½ÄÑG´­¼Ã6eÆÁ`ðû‹Kp@âÕ8¹bÍ:õÇvxø©È8÷]õ¸¡;ѾÚ~"˜—i½REЙ.Z x‚G©_,fÛÛ%h[*8çvõÖKã°ÂƒøÞoAÀ¶æAròpU© Ò›½=âðºÃøå—y!¾olÆ·È'ijBËv¤àœO#=Y.p‘‘âÔeÒABró÷ví.¬Ñµ{ÚÜÆI#&Á̪°²1ÕŠÃnŠœ¥Óü_mSÖfïSº^$èAÇI뇢·²¸,d‡Hù2_´p)ZÏÎ2DN-[]ðؘeè—6¹ºæøWœgaã GeíèoçøóC5ùC¯.Y¼ °Z™rG³L ÍÑ÷éÔüßLÜ-Mô.+3çÛKÂl_çøŸà" S`½êNéø¼ìK‡ª€yNáA G0ÍByèª$X$¹ôäÈ<Ô5zbKp¿l9KºˆDʳ ÎTôÎQŸÕ¹oˆýšü“\ypRZ; Ý¿«~]è—¬Qj~¥³ëH!:n*×6/{[l!tÏr±®¼féVuaH£©„ðìÕv–ð é0Ȥ]óÅÉ•~rêûãÊvû´IÞ±&^k4[”Æøš#ZÑÿhŸ(¹Õ5z怾Vô/˜ºêtØdÂu¶f—±hsg­qJwÇÂtsÌ+x< s:¼€¨yÈÖ:ü³aŽøZ3­>[1éSí”YÀÞ5;àʯXi« ›ö<È@¯¦y"1hduù*Ï‹åDΜy6‘ú`úšÂ¶m„¨<÷3Ôˆ3BÔùy”È™Î.¼L0Š>GõŒP#;»˜¸Jfï0§w›sz/zèð³è½£à †=WŽEcF)Ï7¶£û5Yp²o¬Æ¥qÇêðOôÁn3­Ø$‡¬¸+o-@‰E OaÅ]‰³}¯‘ Ôu5JZzEs†yŽØ³¿WêœfÄ›7¿‡%¦ö7GPP!ÎÁÝßa~v ‘×ŸŽŸ¾¾xõãÇ/^?>~yü“œ»|¢OT5Ñ ^¼÷eP1¹ní!VÂøÛ˜-Ó˜íšÏ]ž$’sÎäcÙ¦^ÃÄX`^Éú[ʺàÚ¹kœn«ÑâîÛ¯Âé´ skMç6^Z súÄ]jÁâ>:þáèÕ“—Ã'Ï=¾à»Õk¢]~?d9ü9ªÌ Çôc£q®·²¨NjZ1•^£·1¬òÿï?…V®j˜ÁRæÖiƒEùó©ÎãÞïiŠQâú£c*S½þ†¼fæàÉ÷Gÿv‹ƒsA7MÃT;êØèù(ô­›ìÝæùüÓF¿^gÊ>ûͧJTÞ8cÈ3®`A‘UÃ4Ò+d™*™kb8*ËŽ"R`ßï´IocÝQž,¦|{î$¯t–×ôEÞ~…±»àŸþ÷i VÐ Xêéövò lfâ91’ ~¼õØYaÓ§ù¦XaU–ùÙÔ&%­Š)IòøTúçqõTK^¢jѱŽ›WJ¨q‘QЄÐ‹'汞\±àDµ@Ì“êˆB7)íà@5÷®0ÂÈñÐì™ä2O‘ ½óI¢@Á5•}Uˆ§åk}÷͘ž!¸UFYKÍc^ó`ÒO=¤O8 #:ô”¨l=€e]?¬‹J1óTÇöõðØõ•› ¨Ø°”Ã=7Ù¢0;ˆ…Üù¢cOÌÜü˜)w åJNçÅ>ìŒÒÑyfª…ÏíW§«"`àgÃQGð³á-®ï×H<»H(µK~ÈjK~¨+—ízØô¿Hì¶Æ­*ߪ"¿Fúhfë{PºL½'‰ÓñØ'öõkzú×ÑHÍrØPÖßJ¨0РŽÞþhŠ9š›¥ãŒ]}LAg`ž—Yv.‹|ë1«Lgu03 S;£­šg§íêí¨6(ôÌMÈL™ƒ‘ÒðýýÚÑ QÍ—¶üxˆSä5_£ìR›Ýà{ÅÐô‡z»YÝûò/ã**ÂAfÖ=ÚÀd†6­ç§àýtÍ?P¯ ‡ÐÙÝ|³õ€è4ЄÃÕ…é¤ÐŸa@¶î¹éÂÃól„î sËGKt€»%’ß4i™[ç´E*;6*›ˆkSW¸î°±}e .…+ÊI;}6fØ£­þƒÙ;~¿˜§£…½žÛ˜6c–1‚Còø‘ˈê_ZÁ4~(úéJrX%¨‰Ý]Ç*'EùðÙ«§/;Ú¬*Yͨ•ŒJň-ù8 JZ¥¾>ÈjX¾Y,Cà ¿±ó¿Ýì¦îŸÀ± ÏÀYA8ÉÛ`h_O®¬7,m4Œºoó%¸‡›Éw^™üY29Y“ö.3Î3nkïENϧeP~#¾dS²ã'U"0D?™NK&4€ÁàðøéÓãçÉÿzöøiò_ôlš<{jMSü—ÈÅ´7‚ñìù#óÕ÷ÿÁå¿xØê&îzꂱm°20Òa³GAű+ðPý|qßßù[“œƒyÄ tå6è 5cŠÓwÀø@ G±EHt±w‰¿.r/â~á^]çJ'Hæú¢UЕFÚ@ÑÝ"ânBnfü>QnÅ è¹AnÉk±Ê!ºÆ~Ú¶ñâø¥»*¨A}YØúìïïË©¢‘]f¸ !(6ŸVuÑÓÛ‚yÛ¢y•Ü <~úâøùKs|_>³3Ð!k üüýèÉ«ãIçæýo³vÁ¢ÓU¿¡ÄÕ"”ðÊT›Ù¿’ÞÆ·ZFÏÇÑ 1åÆKuïâ¥ý¯©J‚jƒ2‰ß7zÍD,üƒÔfx!»½9DæÔtÎî(;B·¦SW95Õz™ÁFWÁätr!ª7¨÷NRÃEI“/–˜Y 1:ðÊI%}fÍŒòKÒʱúÃ<+–ÓE*[ˆú‡Û üý¥R.âù—µuýß!è‚a€@¢×îoqÕ8T4¡j÷*ÿ÷¿“Nõ‹ârZß¼/ù¯­KØÕ÷eG/‘nÔö88½±3íµú,˜ò·Üë5üÖf FÄ÷ ½ªÀšõnDýœÔ®VÝÂÇTókáCj†j_³Úš4•,v¡Ê¥6)fˆ¯Â;¸öL!¯¯É•ƒMƒ&;­%öcw“R»ÔXN|f•WŠØ:µî1"¬†ˆm »WÓ=J­ÐÅAÉÚÅß%äÄÍõT›WÚA7¯‚+iݕ̼cÜÝ´˜nêã<+5©êìÔp%šIúA;ž—]ižò_R*»dJ[ñÁùXÞfW¨*w”ŽžòxjÞdðí÷9s?Ó §²½ ”_”S»Qv—€ÁcÝÛ»ÕêÍ Õlt®õ×õ¨j.Ò‰™¥šƒª |ÅpÕ>‚åi¡ËXVBŒJ:Õd&Pü„FdIø/QQü"2 #AȆ TD›/f,Q)“†DÕª>ÔÓé02©7àõÏ0(X,¦£ 2`¸ 30†ã1L· uÔֳҲ½Í/Ì`” OÆå°¹Y,QìM ÛÝÈ »Ùx¬sFø*‚ÉËγEoÒ 5ô ˆ¯×50ñaûÎ9@'UƒëÕGÇ´±Î ßf¥‹ôìVë»0t=7çòÆuzØ’­BQw:¤©D¬$¬^T‡Å@: Ï®8#xMVNG:~øúx`U~b»p˜*5˜§[RB ºü¨£ŽÃÀn,ûE\³ò©á챊-ÜÔ4¤&—>Bô¹o^C5 ‡¤þÁR3¿ã7¦õ-QõŽ -6ÿl žÛJ²Ææ8Á&;4},püò"ÂWT¸™?U™bè›sy±_x¡¤Ôu(õ#"/PŒ,¾ ªGË9ì"P—3$·b[ÅjBpïy6âÂÝ©ËF'‹zƒ¦‘âÑOÀì&‹0*kr`ÕJnXÕVcÝ€Üøº ’µ,úQuÎz* ‚žYßÝ2ÿô¡§•Iªs×§SaŽ_ ! Ÿ8èfÀùËü©Ex—NÅcG.Ò¸ùxªÐ°ƒ5Hú;Ýd·›Üí&{Ýd¿›Üë&_w“o8ßÁÀüϘƒ»”ÿ`` L©)6ø²(ãˆ/«fÐ3WÄX»è08yOý,7h’*žžÔzŒk>ÕîJlÃç`±îþz’„íê=ÉÅËÿœˆöÞˆÎå nÒâJNzÒ‚Ò3<˜¤%üEOùEfÈ‹“Qçk¿/O¢êiú+e90aŒeÇ,x±ÚlO€…xåQùk2/Åt0ÁÅœ`3U(Ìal㜡vŒhs糨Áf˜èõã$ÐzÑ|Àúm:Ya$ñ>É|¬3s¡",ôz³ªm5¨ßVõTëöÔÿ¤C_þ¶Ûdp»ÛDþü5ðƒa›×zþ`w0ÅÛ?%/m¨ÃH)!ƒºÌÝì‰C @2 vÃŒ ƒVÙQ MòˆñÀ{,|F!˜ï†[ÒÖ´DlçÆé„kÉrFùsƒHlò‹÷žÃ;*ÕÙ¢V P™.½Ë|þ0ÃÙÄð]¤›‹U“×\ë¡ùÇ”Wx"`‚w9u¸ÉªYI;ݘ…c¶6ô¯í°x(¢‡éG_w“3¸/åeQ0¢ÙsKj–»÷!Ý¢!WϨž8‰XÄB,^³n¸>'Åû*VÁŸ©c¸?1ôfSÍãSÂ"Ý]Î`]>4J§<¾ÆFÁrXà1·¨$Ï4¾“blGÜ{od7»gvÂióá Ü{]œ'WM4ù¡Ê{èüU”Ÿ:§„YîDò „¢”­Õ}Á¥œ7ÜÎßß¡›c²Á„ÃCˆ¥\ÌÍÿw¸ˆÊPâ´#…fO`¢ÁùÞwµyÇ¢ ë´‹Š‘ü’µWi:¹rU ZR‰Cõ>3kin• ~Eo°D ÑÍnÐ…Èxïƒâ\œ¶¡šm)óé(K~ºzñ¿Ÿ$»½÷®t¹œÍŠùB*Dd¦Þúød§òdK|73UfVß>Úµ¤^Ó)Œlúg‘S$PäÂ{Ä€ìŨÃÔˆ1qeD7yüCÒ©¼_’£‘—; Q)ƒ.Å@?*O#…—Ö.£,Øó_“å€ÈúV˜¿ð—FI^HÉ¢*É×R+Ó7M¯ «!Å’þì`ÁÈXî›iY6HõÎί¤úÚE Q]2Gük½ßÓxdF<[©w¥ßG^½\Œšge‡Òäƒ@bÄ»¯ ‰­š”áÝOš+8Œ| û¨îC?H³d'äÈ'KñzýUI\†çÀÕ$3D„Ü£OÉ}kÛð3ípamòx˜N –„sv; ­Pø ö™Aˆš\eÀW¥„ÞŠ‰à²KÌøìÑ4yúìÑñðéñ/Ã'zü2`kØM”p¸œB=6¶aiÍñ>Uð˜…k¨Ï‚Cnø'Ç?¼äO …]ó«_“s}âÎñ_øìœúkOÒ´ÇÞÏFDþ£|„Çõúá©YqfœfèœÌgÄÍS7˜fN aiª%ÛLYWyÁ–¢i?›'†ÉÞXR(®Z*Tœ Ïo~èØÏêKß§£ð7Ö €ÂÒz°»%DCƒxÖšŠc@ä³çFîɳ2ü0à* Äìqµå‘}Q÷é“EŠÙäªÚ|œbؼ´0g’#x¬%ÈíðâàVY¥³‘#;˜¿M|mL8ï›PêÏÖ\]Ñ×¹‘%­Jã>÷Ë> ¹­º ·¤ÃäïéAÀn®”†kE OgÁÁªÕÍ/è|'Ç À À²·¤’r"A¾p|ÄTvŠ).PS·ŠÀ|t&uœÇHž¬ÏwT+« Ì—Sä¯ ¸›œöjœ¯žšà“z!ˆYŠÑŠEÆ|ÆÛÀïD$§Çâ1P•úNÉ›üT×uZ'…­[²N–ÜR½ûÄ©ÂÆ$J[³¡ÜŽ·²8ݶWI[o&xß>$Ýä!„ÇcLåiœ1(  9ÎP]Œ;OjÆ2ð˜gzYÌzr †Jꋆë_…‘õð',2¥->—ÖˆwÄÜ¿‹ü y67«460PTˆŒ[Ç"Š‰Æ£g°uȃYkO!{:ÑÞ0?u讋*IX«ð¿YX‚í@´ÉÂSËc&1R‹@/ǯ¡:%ËÕ%QfÞÂÑ}4ã¹Â†ms¾¿ªju}(ä¾¥W@Ìým×6¯EqœºNp1wNøAµ2§8 Æ=©wç ùmQ VßJxWÚ\í¢ÐEž2_˜bz€ÍNm¹“™cÓ¯4 ö½¢ÉRœiVïñ‘Â+ss ?¿žˆÀ­##$þ{‘ªÇ“%hþ9"~¯ÈTÂC©Ì§¢ìÌçæ¬ËNfZ/|ÊefŸö©œ!ÍdêÛß»îÒv3N½™ N™ N×!ˆU~>Æô[ šŸ®ÃóoL›£K™ÚZÚ'€”>ûï‰Ì²˜PówôÏeô’Eý™&ºŒ:ŽÛ囄¢M¸áÊyà¡e å·I’`’jä?”’ÞBeÈ+Ò¾o‰|¢?·WŒÎþXéªÚuµ™!ËÎWn$u›ñãCìXO“/*@;þ«>tQáuX)àϲL RI;Ø!Æê뢧ü©Q —]­±—I(%ZÑ0§·ŽV€§˜ ‡{ßOjGKt‘DUVÝè7‚dñóG¯Äâ•Â>v|‡t]p–=HÚðCƬ©f²R&Ã0Õ×n”óh¯ÂƒßB}1UèÄÒJÈ <¡D=¥œ"ïŠq,ÆE1ƒèÇbyvŽÆ<!e©R%Bí†%Š`¼)rªsZ Jcál¹Í?FFhÛ©žÚ`(vù±möìg\‡'-L 6F °¨?üyYžsŒé[ †¢í Ê·å|"vvœW”¤fý5öHyhxž?Ë"þ…ü¤È=G°ôÝ3(úò` ­1¨DÐØLúIf΂g¯éܲŸ¾—Ê Žeð˜lªú>/s9)ÎβñV>=ÄêãlšC¨8ù£š©ãE:³n ÞbèõŽI ÁT·Çy‰iü¨oÆÿ£X’88;Tºž¦D²HhÇ®_ãĪÔP1Ñʇ’;o|¦•|Z;4—»˵<0{]óÝŽ£ >ô~ƒnÓ3[ù#íe [r Þ S¼ Ñþˆ»qq1±®[QAFo;$^m§9§!Vm”1ª¤‹Èk` 4Þ•¸ìGŠvãwe·ö„ÄŒŽñ.´ÛUa)¬q@œñ7|}C°®†\j+S¢2/DÆÚÖá?å o"óê’(8º¢0O³lÜÁí¸EèЫþ6|:àç/^V Òu¼Öš¨9Ö(¾$yˆ24Ê0C›”KsÂK ¦;IÁØ ñ±çé¢ àJ˜âócA"'ÔŒQ¾†àZ§Ø’ž4E—"¦r,>a¹”é)šƒ¦ _€ šMlH÷w™ÖÝ4g›1浌î/»a‹Å¦£fÃ? ©¥çAWn©wxÝoc«{íJ\êsÛ0õj&å–æ„?ýmæƒ_k.®?²¦Z™±VW¸gpí·Y«„5–»5~(åJ²ÚxÂm¿ÉuëT9•Ÿ(¼FøV®dQñ;&qûò4f±Q25½B"=t×V˜º¨VܦÒ+DnP2VgHÒ‹Rþ•%ÈÞÓ\h-º%†àÞ D rÎó)g²JiïN°h— Æ<õüžb…_o ³ò=V’;ÛÛÕKÝÍÎ5·Çð½™Ä ˆ—;ˆî› Ydúï#'Ô"ÉRÙø[ Û’¿gÍ£'6ŠËhVV—Cí· ܾZ]Ñ¿²“9'ârÿ1Ù©¼o&«]ŒÇm˜ He)bÊüùÏâÜÐ0ºìr¡5g0R¦µ ‡îZ ůÌú£U\¾œŸJL„X·qß í7£j÷ÜŒ×iÀiÖšs¢7f[-8»^#†a€"à_ÈÔiƒÅ: Xs¬€p:OÏ.ll¡"AÝ|5~®3XO÷ÞpƵêÞc‰U©ª#Õ½¾#Du\dé”qÒÑW˜t¦:H^ŠOÒÑb 9KÁ&Z},Þôc‚¹f©‰ß¹ÂJôE'WBô®CzŽLäµo; ôí±§b¾Ž*Y¥qk¼²þ5¨¾©½ ›\m€O'Ñ ؠ ³@¥pí³Z¬Ýˆø_ï,_X‡"‡îʬsíks”M&öº„?¼V©`_Ô;æG@d¤=CÞh¢±¶!Ô õXáý×`“Ò·´EՄՈꖣ¶ýWœG Ë`Ù8Å2PùF¹N.OB|õÎ4%ßÓFLõ‡çí!O}yJÞ *V¥¶×¹yƒ»W’0¼Í²i‘‚ D’Ëq ÍvaÖsDU‚sQrU‰Þ¾GÙ2_ Ù*)Hg³,S,ˆÍ1Ûe8aWL*J·:ˆÌSÖñD9_™/VÙêçP4}T™ÆĤà+ìÅÊî«Ú5d2°%ç¥ qC­5bé`×@!b8îVåê |«Ç­ÀOÖøÄ®é*„•¿BëºSÐn7ÝáÁgb˜mºRé$¯q„Ö»¢ ªb‘G{^ÕN ¹ÕíGÝ•å}V7ppžk€z¶¯Zåõ˜¼Ú®#“WÙ4%°u¥€¤¥f« Ù”ÕHU½þòNó]#çè™ðÔ)rø>¤š3f¾,[Ф P:†ÆÏÑ%|3~.¨ }Á´þ–t9Ml“îµ›ô7›ý|æ/PÞÌùtœ¿ËÇxÁpnÆ-ÚÔ¶ò·½ágúÊUÙC $¦“ob¡ÀúL#–®°‹óS,†[B8".GL3¥s°µþ»´¾oÀí«¾‰˜šÙ™pO¹ìÁo€Ï0ÕlÁI^ÃüÞ>¬ ëV)Õq¼xÛ:2…ƒó2£·óÃg?ýtüôåhž=>{úä?À~ï=~qôý“ãGSÒMŠÒÜ µãLÉXý ¹*.ZÕ$®°¦†jo ~¶Yî\GÈnßtž0|¼W'7¹šÖž\áëÊPêËêÑ Ó_yDFÏ0CÐáúîÄýÎ<ÿrñ+¿ P Û I½žßš‚jÑþÍI«W…€Þi1J‚oÛ6åÀê„Íèâf¹"}–ñLqJ‚ï’šWà³&á :ó.!³¬"ñž"úøÝœŒ©-u“xŠ'‰1dPnè MV‹• ûƒŸÆÙ ŠËqÅŸWõ~’žzHžá®¨ÖDãæ¾y Üç?^kB(ƒ&¦Ùurí{ òã¼4ºòÀQú¬~*B¼˜iäOG•FZ¡‘8ÚRëSE÷I#§.çqlÕÃHÌÁVI'<(’Å»§ZÚY/|~ñ"[ÕŠ‹ÅC IùÔP¹wF–€—Í@½û”Z×ñnu®õÓ¸Ûq‚néfa•w¾öLSnFâï´FÂ'@”x„·uX&ê,ÞÉ툶Þ¬5ˆ• ,x½±Àó@'Òwâ÷½„QÕ‚ú@Y?b^MÛ4…tÛ{©+²>u!o>>¥~¢µùóëDà©#Ó()sVŽÚ1≭ìÜR+iS#»k4âÇ2^cw?¬òxÇ]c)ùÊW+wpGqY÷#“^;!ïÁE±œÍà/ÔeÉ?üæ?äg°¿M8=%ç0&Ç6Ã;/ŒˆþÁmôÍÏþÝ»øoÿîÀÿ·ß¿×ßßùÃ`0ØíïßÛßÝÝûC§ßìý!éßÂøVþ,ÍçIò‡ËËË-µëÊ­zÿßôçÛïàN7òÆÆãñAâ­{÷]2è ö{;½Ä¬È7ÛýÁvßHâw÷vï%gæRJŽßÏ’ÕÙ±ÂÚÏüV2'‹Å/QP±3 –†»H-¸ 8_pž8B¸óÒ÷õ!ÌðRpÈÈä^›^qz Y64JÇ–åšlIÒ«òª4L e½â¦@Vañ…\¸g­h\{6…quT®õb0brM%¬£¿©ýÝß“i2á™ë%Gã1!œ§h=ûâ].n7I˜eÓTdøEL]ö’¿QÞ ˆPÔnï†!âT™óL@ÀõøKxS?= ‹)`|šÉ7Ž¿·ó8Á| JGÑÒø–ÈÓÀ1Ÿ,@A2잆µóÒjcui)!yЮ¢„ hâ³ÜËùâü˜Çk(U3YÆfkEÚ§Rg|\{(`³Ë¶=H÷ØåÀLª¸@øûåòIy©Ü´„•Üô”˜€“>]kI±¬=eÃ)ð¶Ò;ën¼bèrÚL«Ô{¡VO †5g³l:¡ÅaØA³ ÃA,D¶}³½ÈX8<ç*‹½E´ß­Ð#J<ãoȦW·Ó>Î&þ¬ ¶JÛöüÙÏÉKPJ|;ÕaÛS¹Q”[km™Xþ”X9§®-b5ôµ%HûSûZ£6¯Qh°V*&¾£â»H^2^ þ¥IN‡¶_¹…‘mìa=Ïg ó¦ðrKðA%¾TH{Póqõ)$m³P¨9°ÚîÅrJ9 °¬{ÄsºœLbïDáíQ–Ø!:„4‘¨)´ÉYÆYÏöþw¿»þÿ<Ï/€~ÿ-»:HÔ`Þ­Ìâw7ì¿CìF­f®8KªÍkYÔÿ1Cgï³Õ{ÿ¬›üsÓ«wÆóþ6»ÒßI-~ˆ1;Kª™A¨çàcUöœÔ0Ì$PðO#ª˜kD M#y’RÀÔ˽ót¹€ÜÎó€Áং¦/äh;S¿·—!î;¼ I7qÐ[B?|÷TÙ[茦ŸZ¯(Uxø`¿.ÏóE¶UÎÒ‘éÙ´¸œ§3¿'k4ÛØ8™m¥Ã$Ý ÖWÿ ÓïPx–ŽÇæ&Þšd§‹ƒdgoöþ01«ñäås˜ÜÕ4gób9o™~å•ìÌÞÃÿjKþçÌ lŽ½Þ¶ùÿ‹¼ÑqÞbޝ7›ž!qWŸ™Q™5€Iá_½~÷¦Ù%ÇÆùCX³aó97j+çïz9 Ëÿew‡LEß ¸²^ÜMCÏÞA2È.’¾ù¿]³­üYA±¾6…Ì´•ÅÄð+_~ýõׇîíI±X±±µTÍÚ}\×IÚ;[Ö…#Üs`üŸùߌfÁq™çÉÝý?®Ñ"ú‰„­UëäÆ"Ýð[û­ ÔçŸúÓtÿa+Í1}`+îs×ïáýŒÀþÝ]°ÿìôw?ßÿŸâ'fÿ±ë޼ÀŽãö“þþÁݯú»š°âó_ ì~yÈP Š«pK”~‹ÄZX€àÏʦKûÁ!Æ–±˜âj÷ÀÆTŽ ÜȾ¾²°FnµºÄ®¹F ½5å_™.Éϼšƒ*”\°øË‡ [¶…Éʌ˶¸a:7'Q{%Âr( ê0‚ÒøYgtø…Ç#o U¾c~ßú‰+¼Y+èÿÝýýþƒþ½{ûû÷öîý77Ágùï“üDèdÝñ"¸ÛÛé à2øz{ÐÁpðõÁÎÎÁÞ þ2h P} D$É}ûÉ¢°>.“Ò“ZGï£wi>úç|%%J‚Â)IóŽNkšHRxÕoqä1ÂŒ&ùèí§R$à(álmÓŒtÜ£s@¸Ä ™.ûC®D‹ö B´8“.’ü¨~bz–.Î]Ȭ|D3p±o”Ê>EÀ7\ÝÃÜ,íÓåE6'\¹Š%¢QM¯Ìî1Ĭ°óqn±U­Ký®žbEi,ôâ†ÒóËaDžé¾>RŒ ‚¨˜è¼/Ï3t$p¡”~Œ yHk’NÉã€8¿ztÈåeÇH>6SÐÈ’ˆ TÎPÐ5ŠÔ;€u®ëD—b¤l\AÊÙ²²÷f¬„ÞEi%0$!h#Y%` )„µ\ÌAÙg`] Îuh¾Áç:Œ†èR]Î0L½ ² ¿w!c«€§,WÔg„}™/ÿ«$Yðyã$†d —MÂó̰@t r-æé´œ‚È+Ã7h ÆïåÿÊÆýÔÈ%<(´ÚDx²á|fe†ˆR—‚E ~i´@Á Ò±+k…?ªÕÒV™H†÷te³G&­ð<½T¹niƒ^:ìµ(ÐzØß=¸ó- /ßoi2Ž7ÃÖXúr˜|÷ õÀ0ˆß.€Ö>@~óÛÅüWšãÜMÙo·Í;(¾mË»€ ”ø~sjcÚ™ø 4&Æ:˜¤:-÷[Õnñ™;äžQù±”JÕzû ÞpÇ‘‘´Ä¿¤¬¹Þ§TLÇ5 )qC຋I9K§÷[»ñš™<Åê§°6ê©À˜Ë+ù¯ZS–CWO¬ë:ôö@5…OæÉ¶÷@Уmõ ]SWh 8 ;•²uª:[³Tem‚_6¬´S1ÇkPHå±uñúh7¼¼ãíÍÌkÚýæ8uæÝ ²Xô¶ù¿ÿŸF϶oµ tòÝÛ«ãÿáü÷»»ƒý{æù`o×ü“ìÝj/j~þ/çÿkÖŸþéüám¬ÿúûý]µþ;`ÿÛëöÿþ$?‡$ø©õFYoŸ”~ƒÁv/é}pw÷àî×Úã›=Ÿàww|„¹£ñ¸4œÎôl š6LþŒytYig·Åy¹L9ÆMñyìDç’l€éå4!ë.•–ìwŒ9ÛŽ§g†q9ïÝ™¥£·¤Û{hˆ«á«(Wx:¹ÃÎ0æÍߟ¿xüì锸Ÿì÷Þß¹s˜KþËÒÁ_“ŽüÞM8+l è&ã|žá,w™ÎšϺÉ?Ów)Q²ÍäïGO^¿H:í °½ÚLMƒ_ûðŸý­½Ùòœ ÿ2ÎNÁ`–ç`¹µ×{oäÅ-C_ùŽ7„¬e^Äù…ÏÿË3ý—,òE¶He89š+G =¾—Ös]Ÿk[[ÅïºÖ]Z>Yá¦û|Ó¹vÕdÓ³Å9ùóíÜÀM·ñ¶Ž7íÉþÝ[ë ì»ßG_ìÞ¿ž/õµý¥]‹|Ä>Y{¤‹ìÏÔðGËIú›þëÛZßâ"ÍW-î§êÌlžæï'Q®ÅŸb[¸‹D5in;RPk-/Ð Ñör³š«ì1ÿËTñ‚¸j-@±Þõgr÷V늀{¬hÀœêS^Ÿ.SnÝž½ñI3E`¢€`.luQu£·—{‘¾£y¶/ù D0z¾1+ç­pL‡º S Ï&(ëáXϱ™0Î]Ó®ê J¿ÙP¡YûUŸ)<¡U?x2<ŠX ‰¥€yñ2–úi«Û^ÖÒ?IÆR5QóË=‡UÆÛó=îå Y@VûÌ;Òõ½¶×R²>=½íýŸbÆ=ÏKWÑŠ¾Ëié&ji³r_–Ëm=s Š{ÇÙÆÃK\ÚfOx—ê ë_z®:»c¼KʽwI]Ø¢¢Ü‘ž+RÚß´Ie«çHÇFVöe%|ÂÆ‘™>P„R泇& µ±@^ZýTÂÝ0ƒŽ÷‡¸‚š|ÃûšíCïÁàU§ïŠ­“ 4±ýj1„8›Ï‹yÂVæÑÝǽ$9šLÌI¶’Ò¸HÐè‡æÐö…G¢†ÀÂĺ΋™—+¸öA ןü¶„åûr!…çÛ~ÜOœP…ú3DßÒWïû¶}ÒnZÃçsÛÑ—W TÏÌÑ´½à;ÏJÌ^uQÌWÎÀεf õÈt3þ1—i ƒ®ïUpˆkܘ?Ï—S1jr²œiá.é`4Û‰ÑrQ€Úl„Hžólkž™ ÏìŒ1Ž3öa™m®õî-Œšô2jðæ~ú .¸¤#—ÍÎLÔfã”ü¿7¯.Ø*OGf`˜x³àÍ¿jMïÖŽÎìFÈâ„õ4lF¡²Ý*B¤ÉýøäÙ÷GO^¼n›š‘kzãµggfÛµ#‡!Ú>Í'¡ìào.ÿTC¯+_IŸ¹çöé. UD{VM9Øæ’Bs»½" )ÓYáÈk]Rucœžá·ú¯•> ¦&[Þ/Õ•…ßNR.Íä§¥ã+ÍðéÂG_ivV,ò”n7<=†7…ŠH½ ¤Oš™ujZµ³öxgYsyçpÓ¦”ÄkND!…ÞW¬ùW_™ ‚îÁs©#uû C# Už˜£é!§û ÒTJ·»®"3bðßXÄy1¸ÊJáÔb5‰¬RËü©-çöˆÓaø9bTø¯0ä‡â[»ƒ‘Ú•ŽË‚XW&$D%—¶ø»t²4,åTÄ¢½Dµ#>ÍÏ Ÿ…›]¤Û˜!h[vÀ¶#I~µ(ìW|1*æÀßM®z2 ?³˜[}Xâkíͦ*N)ÙñPO]–£•ˆ°]òÒUDزî3™$qŒkX_N^i»«†“ZâLw!w§ß²M?Éæ‹l,ù¡~›+˜e™Ÿ˜+5ØÌרcz#û¬nÿØ‹ýލkúŒ\¡°¯f…û}à÷okomÛ=E»ŒYL®óÛìâ=œHª×úvÛ¼õzÙ.ŒÒÈÜår6+掦µl?ø«m¤©ÛþÜòµæçë¬Lú°ê|ôB¢Äî¡x6ÝàF‰RÉDK’ Ÿ0.MÌÚËEâ ª]‹Zp"º{#ud“âò:”ÎQûu)|á¤b—_a'BÑÞIÇpŠéÀôXíÎÞo.舆¾éä×äxŠìF«ÁˆÒò $×/®¡Š^Ä€B€*Ñ ˆCþƒuJÀÊÔÑ.lPt ÀƒbÍ”±ÍÕ–Ot:jøö‹érgUÙ,]œSá­ʶåí!/‹l+œšˆî¦`?<ëq´ŸzËSå »ÁÃ"¥ÖíÝùB°žˆéVãýü X‘a¶ž¸ƒ É‚²ÞYJM·^½h÷Z¿? XtÅì- WOî|T~—v³Øžb¯;wøohi‹õñ‘´­…µ¤ó$;]Ù|ÎàŒýn‚¿Â3x|36–OcË䘯tËï LEÞ7Š›ôØ’¶“­ÛþJÿj¤ŽÕ§\e@9Ï&³:ó ¾Ûa®›lÆ3È·/|'²ØÂg_² GœTžÕog`(^°Ñ›\Y²J!ór h?sæãiOÄŽƒÕMljÿÞ‘fcÀ†G K¡Ý wä–˜ŸÍšBC%»~zº,æoK°³gïÓ FGõNKÎfD6Ü耀HÒXt-~Z‹s öЕu+GÔ|íŽÄ<õ§ÀŠuÐPŽb~¾œÚæ»Õ¯¼ºÎƒ /ÄŠyìOvInÒB1ï¡‹À·Ûf©ƒÐÓ[àûìªðO›Ì/¿¥ÔGefóâ]>Æ@YYt°1ÃÂ^JB„,£Ø“«KÞKœÅHù]è([Ðw¹qH(cO|Ї *Äb ¡Ÿ8 gÅÀËä"½J:/=¹Ú4c˜d”Ç)Ÿ£z5›ÃhlKÔ†y>?™‰¡µ›œ,f=ëåúÎ4Ô:DàÌœSðV r67ƒÍæÿh—±ö¬ŸYò®Jömª ÑöqG“Olj}"ĆïBð ‚ @œ$ש-²•Îwhžcn†Iž–nA«´(=:]xI- =_8Ÿ4‹’òËЭÖ뵡ö$Uh(0séϨ#Ós.)^¥È±>³"ÛZ>ÝÜ\︼ԷÒâ•É!¿ôƒ§n9yðí$§ºZ¶}F{òÿ»<­¸vIþ]ŒÝf6Ž:žÅ¼E­C Ñæ¥é6©‘ ã‰>ï)ž]pˆ—Ôi¾Zíí´¸œÑõ)#ô’£ØcÅ7¤å,å§ùHô"Nu»E½÷÷+CdqÇ™l ð³pψèÀíÍ <™›œ·Öôt²0ëÙ9Š£àY X@ó²·nvÓ¿«j'»±ÑÒñ¸€ÓÖTåØL$仢y÷Ï‚žóÖž¿©3<z¯ëHR<_,fÛÛÇa›q¶½²›vÇ|»m6góæ| †±ÝaWÛ¦‰¹ÈÌ^BˆÄ¿{­eÊ)G3dk1AêæãfN(÷ǰáMå—‰þ˜¿å¢]YB‡)ßBÆl餚)沄ح —Öú©\w|Mùhm6‚€Ïôö÷¼Úcf7(¼ÅünoŽ•]ËÞS×è_¯kòXêCnk†jª=î’+\*ì@ Ây:¨HäõÐÎs÷íé)Z$ÿyÕ[ƒçXíVšÆ&Ÿ,óÉØîÎl›Kmv“6rÕ\j]Zþ. 8è:2 5&C o'ÀÕ›«Ä8½nòi]Zžèõ Ï&óá5§Rê•íê l®]Ëa…ë¯ú"7ðþ-ÔÛ!´câ¦è:ˆìdqê¶ŠÙ)!ïP"(hD¨ô‰“q…ƒ†Ýa6…cœdˇVƒªš¥eÕÖãÎVðfØ6%X§Z-däæ!I© {(/J'0·ËHøbéXÎtZ@ðÓ²L0·94=€W4¨Ëó‚/ œ4:€òˆŒ­×Zk#“æ|øíšðô@ÏÑo' *M“V:^[Ï8澄´Ž£ÉòAp+lf¡ûhg™p¼ù(@&@ãžê‰#§0@º´â&Ó¢ {7Í)Ëíœ28Àxƒ+Rz›qR’x,w»Bä ,M8P*•S⊑WñÜ»‘Æ|§×•¹^ɤ[Bbÿ–t»õ ÕÚ#¹î £…NÕxœ3]×ï HDA}/ricþ[»?6»AßÊ Œ­ö\ª#«;‡–t<ÇŒÐÒç^ºfPw¹zUÂDxz œTC° æêÕl¨C‡…u›ç'Ë…o'wìš\°>1ºÒȪ!d–×翦×;¼Õªnÿ¦4]ƒ´«®A.…_\ÿªýPVòC.,éÿµ;6 Tõ™u⚬rxÅ9=æ+Ì\m¹wApˆJEù£iR5Ú #¸,{—€²±ÜÃeiŽš­“JÂäÛT Ñä@ïHQÆ$”OÇäŠõCô!QÿS)Ø¥ÑÎÉ!\V Ss:# °÷áe ‘θyloX¼™Ì\±ÒçÑt*›_Çc¹–úEfs¶Ä`›WÔ…¬41#Q T¦ú¶pW._TÔŽ;htºJ¾¨²ƒW§ÍÛß*VLÏ<-¦YïÛmþ+‰™é«¹ Ý3 ¦(i.5M±»>àcŽB>¦—t0׈»)æÎ’iƒW¼že[|y+‚ßÛl¯«6iÑn‡†O¾ ¦(º4¨Ï”…ÚÜsöXBv)ØýæGóБc3/…¼¤‹Ñ9+fªSàæ—­üs{å1ª!–9É¢ü)ëDÆŒkݲ÷p}ŽÍPf€¿ÞÊè·Þ¨¸Øãö‡”ð-ØÌ5{NßfZ@§5˜K²é¶ÆYKdafwÁºËÖŠ-›q{Ê™gþoXÈ€žU‡#aŠí2~¶œÒ¦æd"“Ã1Õu9m.ö;>ÉF‡ÞŸdªs+vâÚÚ?ÙìM€D·tŒYïŽt8¸ ±+ƒTxˆ¾ 18ƒ*¸ÆÂãÞùÐs+LNÖÓ'øŽo´â–°4Úð<¯¡‹{+[Ñrç/~ÐïŠøÀ륔ÂV¤h…lò˜zž”pP6ò¹\‹®]oßJ–‡ ´j2\§ŠņŒ­b—cúŸUœhÀ¯0š®Rœ¸é“U®sìY©ËSFKád²}\ËCV. Aþ¯ZTEµLÖÙh/¾çÌÙúSǼB®ì}¬ð%y¨¨ ³+”‘ŠS„–3Zï«OÍ~\`’«0ߥe­q]Iú9Ù>kw•¬XyÑú%}ŒÇ("gÿf{R„´õ¶&®ÕKK®4<“`Eêkèè{ÉS˜AP5˜½lm”Oç¬9‰ :HÅco`s‹§ÃKTÆß—‚ª>Œ¦“̹¼§§ Ôœn¡FW¨ÚÖà¯ÁF2†â-Ÿ È‡NŸ ¹Â $ënã§Å"$„,¦ˆ°¶Ø¤Á tƒõ4@O³C .0F1!eÌ«:¬¦ö~‰Å.Ø'zÉ 'VÎHP1M)Ckr0Z!2œ$’»`œ½ÜMè6C¹ Ä<†êã÷fÌ("ÅÆn(Fáy«p$3•¢ÍbNÎVU ±eDê6Í‚ ™è\žç€jQ¨•¨…¨_%âa±›½äeLíÔ`\KË´Ò ¨Gx Ó'TþÔojµ?޶QÉZÚ&Ú ¥ :šòGÞq5Ku »1Ä3ÀŽ`uB™œìÇÆp,‡^£Ž\ŽhKó„Ê®¶‰g¯¡c/9Í‘íᢩ‹‘Þ•tZmÈDŠg½Ú©&ú¸Ù¨ªÑI®±ºLG´/ÎV@ª a!ÔâÜ,bÏ„7¢¢ñülà zIèñAF=îEZ¢'Ë»bò>B3¿mÇQ2ä.Ì-ö.›æh4(šíµZc¿¥B³uä¶ÚL^à 9ã÷$¿È¼él ËéØ]&n"- ÈÛ/bÓÔåÃ̱Õ}r2)Fo#ªB„FJçg¯ï¾Ap$1¥~õzC¾ÞÃÇ}‡‘Q·³°Ø¸ùËspd1•Ç…#„d¥´¸,‚û/H\5ÿFñp|ß©õ™øáášÀb+&|áPƒÎõMYM ä^V_ X¨JÉåJÝJTódIN­PȳÓ8Ù ºÜ#.À‡æ,ePŒw“ Tàž·cÎà[š£rÕ¦R %‡rG-uL`~"G2埜l`3¯k§7 ü¼g~PN)Q]•ø‡ƒ*{±/ÊÕáû|Û(1/­4ÕºWÚ“%‚¢êHÆ}áÍñsh»5–JHës¢µÊJ*tÙ–ˆ•»- 6Î0;sW4D-?²Á7??}5|tüÃÑ«'/‡Ož=Ú†\g¡‹òöîÏ¢?cf¾ž|ôpýù"Œ¬æÃ]ÝýôsEÝûD³Eל–A½ ¤Êl†ŠÐ†)”J•?Hí½çÊ¢MÄ4‚¸ôΑ­ãÖ.*,O|$új‡è.:È¢ƒKUÿ\–¨`ú‹ñ“©½C–y;ð™”¹õ{°Fhkè É‘ž¬Eý>檖YöÖ_Q– Ѻà]\óýÕe nÃ|’ÊñÓQ%7_Ô·õ¯ÁÚyð÷ÁÎ oÁY²é|ÿ1¦®2OÔgYXXë{ölÍݽ­]« ÕÁo±#¯ÍS4MàµXŠpªÖa(KôãLWen˜‡`¼à;;wœ.gIc‚þ2ïÚ¹e*$Žá„B@Õ!£D‹¦Í±8ªÉ…¨x 5ƒàU(ŠûþæÜös^•ayžŸ.PcTb V„!ò,i÷¶E1êR|ŽÚ ¡š‚è=ÄÖhâl+[®ƒ‰j¦ä¢NAïpl0nœÉë&ñ…[£ü(Ú ~»Q@NÖ6™ÛAxq1󃋹T Ä•#­0, ®x¼-Íã1nðÊ#X‚Z_x'°Ê@"ºÉWð ‡Í$µç>áëcçÏ&ÅI:I6dN…'~| ÿèvÁ鹦h¯r.óSëx®œÂQ5CFª×M±²¬V¶zœ.êCÜê ¦”œ5ùLy°™– Ôž )^b#PŠ»–Ž¿·“ÐíЬë¿ÿ¸/‘¨¢ÕÍØ}¤”´Á‚o8-Õ}‘ ˆs Ê8Ã^Q÷ÇëÁœp™r ’ÁŒÚ­KŽ–ÚÁ†LjJSÇpØÖuÒ YЬ㻤¦Dßo&ÁÆ0u‚ÿLéç)Q&Ô8!·ü…Îmf×#ytºè Nm¼ (v‹Nͼ¶ÀÕB_ô÷ªD¿7ß%í¤áÞë^{³mÆÑöAÕ7`‘µ*¼¸ ÉÿÒÕöTæÐjÌK{±™•~âv-‰Ú ²åKÍó3F‹[ð3åxsíåe¼À¬Ëšá#Î?9zúã«£‡O|öòñÑËÇÏžŸ>{z,Ѹ›nœ„ný­Êfòíýd¦{žŽó¢Äé¥#«‡$]€Iâᦰ`݆ݲ÷5û/ÓwØ/]³/`wx ïǧç磗Ý4ã‘°/9é‘À%t²7aòg¯8&G=Áýðàš-˜oìžQ7 .ášw¦“ÞAöuÚØä’døñø…¢*øjƒä}ügXš–2ù#w£z*»ý‰×.Ž<ôJuƒÂßC$ÏÄÙZgÞ´µ[Õ?±¼»úeóf 7_ÚòÁ‘«cþŸ“@oÅT_cŠÖnòp0¯Û_ÒÛ7úCE9¶}¿JwCÉÙ‘ àš ÇH¤8¾§“Kð«ÿw4û²·ù=Z7©)¹ÝØÓG˜ôm†Þž£lL~Žï²¹ê@æº;oòØrg§(ÌñTÙ,’ÂB›0Ó†Ú6˜ÖsJx»8‡¼„ü <åäüº¸‚)çôWÚ6Ê¥‘átR\jâèe®ˆm?2]ìú¯õü)§7N|ëÔòAAZ È—v^Úo¶OØÚ¨nzS±`Šƒünþ<V¦Ò¿Ê>¤¢ñÌ)yÙK;\u¬JC‚\Ø´r®ÎÄÐæñ•…4´Ž®3’æ]'E"¦¢öØK —ã Ã~/gÞטwŽ>}AŽV€µ ÿº‡ùtë"»µ#*tx²X—ÔÕ¢¾<¡ï'?=yq\§mJ BwaXÔ 9xA¡kV 2Q>Ç «Ý _só6[¨¦7ÔåM¯F:ef-‚%ƒM"žˆÌm­ò>$²wîf,e¦™J«ï€§‘…€Ü°P í‹&ñ£:·ÀF ™=¸lU ¸ÙO͉:wÛŠ±©cAšœ¤33ÙÓ@©È•ýÂŽŠX¨pç QÒn9GTëbfÑ pmÌtUj±¬4÷V2c u×ô¨u®¹çš+{„KmÚéy˜ ‹ô]“ºLžÿð2ù_Ï?­æÉ^$ÏžšºRû>Teþ=zúHWjxÞ?š;–R–=›("Ñ kᛲ'8iü <|rüôÇ—íHï7“o“{{­®Þ?~þâñ³§Šë´y°–±´y4K!;ÙE¯±Š­Ô8lªç×£çj"~ámaHWõeŒƒäƒQ»Õ£TÊßÈ:AŸ²I„D!»”‘xéDmÄ-ïöÕôñ5_D(…lüQ¨(¶qÃyo™²>å ýè{¾œü$ëábE6²Ùd•]ì6ϧØÄœ½FíÓšíïT{ÇêäÍz ©Œ¥¿¨µô’å$âc®’’>D"åqƒTÖ)Ü”ta{®ÿ €—RG㊫m¯j¨ÝýµeX¸®|ë,Þ÷íqöÉ3r³9E¥œæsʤèI–Ó1"aåh'®º—¼€éä¿tÕHU'ó„»•1{uŒ“{}Š‘9¤ç}ª@^zU#†×°ezŠñd:xÔAñÎæK »e”a›h“~Ü9xõó££—ÇÕ-þâøePPÚ¯´¯ÿ8nYZÙ VÉ”P$ŠNÉržZòd¯ß.åê­£àf 1m/jvs—/X\Æ´ôâpdðn蟾8~þ2yüôå³êø;’Ž©›Ø«NÎdWff3ùûÑ“WÇ/’LP7áÿªäóæÁf«+0¿Ãå<ïlÚ£[½mV˜¨CuRq£1&# ½,¼M̘¼¤ÊC>V š wøÎÉÞÌ›7ÓxáQÏ)ç~4Õó* É¡”œè*Gy'Õ;¡m9‘5ãbŒÙŽ!ÁöÆÔ‚rêëåIªh="1Ž3-¢‡ãv=jŸ…XtV€t3àS(¸†C5\2.‘r¢…ÖªŠ\T¨ƒ Î%JŽkKŠiJ0Æ™.\5ü„DÊAÖÙDcà­‚€4'ÕcÄçjCü´O€«b:¿²ÓRFæ%âþ‰“nÆ8Ĺè4øxnŒó98ç ÀD'Ã!¸pÄ5œ¦B ‚ÞèÊ}y~B'5—™xH%¬Y{ÓE_Yywq>Ï`tæ\„‘̘‡©JÆÄæ‚–%•CF8 pW` ˨˜QŽ¥í4ÂwŽ¢º«rVâ•}YRe–T)°[ÜPè¡E`e‚ÙuZ dò“ 7dPõxûŽì"î¿ì¦Õƒ#Xòø¼†p†™W5ÇÁÊqt¥ð1 ‡Ö¤¬ ”Ñøî‹û`óFòwµOsDw÷ì÷®Ô9BÐYtûAïN#ò‡xŒ·<µä\MW¶Q ¶$cJØø>ä€(ð)eî)¤rybÄ7ÝH¿ rè$›và˜¶À~ M¢n÷í¡8ªCWä¤ÿ -x†iøAsȸ8“Óèg:/ñJþÈÙ°ÅX‹³×˜T_©Ÿgí5ŠR¬RHï®pA´ÎVÿ®mÛUìó×ⱘ^áAaµ£ýdL4 ÝH9^’ƒji¸Èá±z]!ƒÇ•ê9¤ 'nAâyƒ³(–17–3bªõçûÍKíúoÖ»½yèσ¢Õó cc*Úi\[Ë’챵ܱ’W³Í#´*ó€yÓfL:¤áS“ƒóÖµÓ47·RÖ%E àKMúî 9)©Òõ5}¡˜¦Qÿ§ˆGŽóãÒrJôš#ÒŸ5‚Âæ"Þ­d¨2XeÓŦM4iöö)ën!1½òñZ»ÉÉrá ŠÁG§|`©D’áX‰ óWÁQ12KŽeYzr®,u:k‘â;õºã¢«[1¤8>KAÍÓù3‚lI·X®i»Ìþ‡lE¯½_cófè¿Q—Z¯Ýû'ª*ÁC¤­Êåb]™Ðk’¹Î*,Dñ7`"'ŒJí¹ÈµùØf3"–‹õj,Ź:j‘c‘&ˆñîI4ýõ•° %¤ˆ%røõëþ›×m¸¢Ñ5Ê‹Zàî¶áÿ©á|/0 †·öŽKNYnøy1]`lc„õö·øàDal <~ùºýŸí7½Â*nÐÕq=¯o¢j©¢NÓúëƒ.çDFþ™3÷š.ík­‘N%.^AQUÄt‚ßô\áF“´d?[=Œ¡âžþ«µ·‹U^ TA°ß ç{³Ò³xÔ·©æœ9A¢¥*‰¬d‡Y–Ö&Õèn´ÙÁ^w’ÁŠ%g±I ÿÖ‚¾C­ à5H=˜|7s¸âìÀßó(;Fè|õCœ¥.¯x—OŒŸL&Ú†óóvHpJ»ã¸»÷R9ô€lcµª~'2Ö—_¯ÜúóÏÊŸæüߣ²¼…6šó÷û;ƒ½? úwïÁo»{æùàÞîîÎçüߟâgûO^æo³à˜ö{ ¿÷·û_oî&ý{ƒ»w¿ZqqA¿1…t¾ÚòP'ÿ õÓÅV¹¸Xù)â#Ãêµ5Î ç‡æhZ¶Åìðóùþ-~ÂóOÊÅí[mÎø½½½Úóo~þ0 ö»»ƒý{;æüïÝ5$!Ù»Õ^Ôüü_~þkÖŸþéÑÓm£™þïõw³þýýýÁÝÁÎÎþú;ýAï3ýÿ?ß~7;Ÿ Œ·€·ìtÜëíÐmðõvÿ›íÝdÐ?|sÐß1 èIJ—•¦ÿZqi±uìâ˲%¾ãlÖAÍŸ…ÿ¦†K•ÿxDz¡1Ù_®”ÕP'´&AC/0)§lS°sS~K‡­ZÌÑ|‡¦—KÔ1LZ"—¬Ód}ãî›Âb½ëP`=(·é=§ ä1Úî Î…£È¶4‘Aø7é¬9íùÄ£†¢Ü˜4-”¬Š=µ{Ó ƒFa@òârJÒ³N›|ì,ú™©T/ŒgΕ÷®9ψ¸ø‡¬7%cìƒ=}‚À{‘N¥ŽüQv§Åt¿W=üƒ7å.òíqe6ZÎóŶSnFÇðôÙËá‹ã‡¯ž£x~h«|Èú6vJ2ç-§³å èݳãFgz–©­mìùñߟýíø‘ii§¡%¯B/ŠZ)/ó…Mèçæ“ËÖ¶jæòùñÓ—žTm¼¾fèó!V‡û~¯ú}»”ƒã²8á¾&ãz¼C=~H³¾¥øiQ!èðZ\‚óFœj8Zû«§{úì—§P3.è íßy6™UÀwØìŠï6Ø”•ÎÅ÷G0PHöƒ|jÁ‡®1…É_ÁæñÍ í2ã{®¶é „hVI'Ìâý;J£Ž.Ï*}š=4’\'.iñœ¶DµZ Ìiz¥å!Nú"³9pM»è|!ÎÇ®êÂ0ìùÚic_ #cˆh/À0!|2#ØÐ8/‰3ŸÇ£:sîdëÿ:§Î·пT@ß ´œkY•HBŠa ¬veê *uã¤ôùAÍké ¯CãÍf½Mpåøäß—3Ãþ¦Úiϸ˜_dÎMÐ* Ee¦4à™­ºH:AC $WQSdOÚÜXTQgU±éÔ¿×øé›×m̲ƒQ5ǵ…A¡üüø¿züüø'C‡ÇÏŸ?{˜Y½fš^€ñ,«Ô¨!Þ˜agóy1o{`m¹µ*íµ;öËÑó§Ÿþx ]¾  j:ç›’#‰^d•¬ÏrhØ­Å˼Æð„Í7'ÈYÕDíÈsîM± È¥8ö2‡}1Bâí%XEê-‚Cä°ù<¤=m–åk r|€d•’kšžYÓý ›;ëKêNc ZàÚ=¦]®‡™ÙYŘ3)Þ›ZMiáú/N—@;.Mz3ë¾ÉŽP“ \ ࣲÖÍÿþÒÛgôñMxëýë'ªÓ»!tLG°ÖM¨FdÐÙ‹zɘ/8‹g:<¼Ž§wñk§1Q‚&s­‚Am ’ +†l©ÖƒèrÙ¬Á±´HÞL¬Üép!®øÆí÷HèJýL<íÔr&ÚÌÚ^ÐÝË}Ø+Åôê¢X–¶Œþ×å"1v çqw'A½P&ì.®+&$ìœèèlº\§uL‚—À£&•f* cäåº3öC$_׌˜FQ cš}N€21¿"¨¦`#Å÷O|ÇÔ1$ÒL BZƒ3!û“Ad0ç^æ%ùŽ^fí9æþS:½ú#ML,Ž9'ö¸zø ±œÙ5;)Çô" ^° ßyÌOç6" îVÃ×wú›„ ¢ÉØ,ï¬(…÷oÙÞÄø"ôâS×a%*$ü´4Çq-.ëú|ÖrZ×àµê¹­ÍÀeÍ4¬¤Æ®#òA]Q\ŽŠºàcsdŽé¹ã;G¯L T.Uf£<ŒæX7ek o¹Ú4€W™úJ¯9 yØÌþ\/ Dì0q Ö¡’èÑ8ðøÔáôG0°Ã‹ ]nÖÌÌó»ì s!Ô^ìÙ¸LýþfBƒúÙ¸Nz•¯¢ñ²‚sF$q\œî’ëBe¡³¾ÂÉrU*Vy A5¹¢B™Ö­Q§À‚ö"=Ó:'§°ÑuPÒ5Û`#Ÿh†ƒp'º-NÄ?›o ^JÜVf Ó9ÊzUÁ*³^å¤>W Ý.ùŒã¼ÆL­.æ ¥ áe3»¾ åh”‚¼|^…fË_@žgbÿAq 1úN޽áxgnänêBy€ý!dÒ9ë7ųZ¼×2‘ªé˜ÕX^ð,)ÿù˜øë”¡.¸ÑaŒÁœnbÎy‘úÅ™—}³÷3‹1YY̤ãð 6§#ªX¤D`¸t™)xåFHF-^=‹ˆnAÔ:~®›TmãGÕù ÿM&´”Ю³lšÍ Éæ1 Óˆ¸€ÌT‘ÄEV(“ñ’:èæÅ´³©uÞ· PS˜É–Ÿª³Þ„$ßBHZ”kG<;Ôù£T¢NdxÓ“U&A0Ï…=² ÿ -'‰=‚Ï ±y¯¡çCâUˆSëÕÆìÜHèÊ ÿ&~‘2T”ü†;ûV6Á¼ò¸C¸Ž5§é‚þdÈRO§·ŽM÷["Ó¹l!I—NFKÌÂÊò!¼W½²)ñˆJ3Âa1[Úä\Þ’£ogúík!é(IÁ%?¬ÎßïtŠ©zÍìÊΞ;cQF.ùÌ)˜>!!·Æ[ø+¿ðë¶uꘌ ðhž—àZ ª0ÃÆsÔžz€SBZ„ã,°êÁ¹òð½ÄØgíÁ@óÈÖBø8¯xFHµch¦C—†>èÚ.3J8&³©9.åržiË*«yÈè ¤©eÓ1ÅÙšlcÔA:«ìHŽö!¾>(8Ql¶—žAi¶L¡šC³p²È²¿¨òa‰ÏJ@ÇZ¥”ÙvÈ+¡ŠÕì(’ÉWl*¯ -ʯDµiÚȯ™Ae¿^퓱Ô#ukcìsªí©w뻫xÝÊ´¥#fèX¯§5.õ>÷tj‰¦Q/ÐI˜b]cKýó<sÊzÉçŘnsÿÊ Ò”I"ß\ì4Àï@ruºé0;»øÑóAѵxfêPf®4GžoF¤PQ…±pi%Bž7 ÞOG_5[kÇÒìÆÂøJwéŸFj39ßôo@,Á~ ö-^ §¶)DÜÊÂ僋Ó”Ëk9^Æ +ɲ©é´ùk£~9ð¶Ì›}½ü÷uC÷oìê`éÂ†Óæé^û± .jnvº$DE}t=â"fÔWôSèÏ0ùêúŠ[ßzq&ÐÊtXÇÈ^[TbgzQ/:šh|¦9w­-åÎÌ ˆæÌÁI;Å ªÄ"35û¡¾Œú¹‹S†þÎaa¾œâ9h=0¿%ð:êÅyW–™H&W­ÔüMY*N'Î!'™-@R,@(@w˜_ÖÆŒ*:ÁàÚÜ Ý¹NÒßv½Îq†î¯mSl ‹Ùûáb%Q‰].ÉæÑƹÊ/GhЕoúfvúÑD¯¦ óMUˆÀâ5ƒg€ã.8K´äs€Ž>°«íeàø7}7ÉO3Z“…‡"†ØÅÙ”G¤}eñ–Õòæõ Û FôðU =îÂ3 ¨ CDQ =0Ëy1CUòBFØóÕNäÝcP]´S€¹Àu ]Ý©!4‚r0¹(L½£ljyÈ»¥SހЄ-ÍWºIqaOe/ù…ÓýÐD}컢 ˜gùÄß’©5¡\Îá”PöD3‘#ÜÅKòÆ9)ÎÐÁ3чÚ üÚniM9cç²–„…ênJ—‹6$z.RuÂ;´-…]?ö&_ ¸-+ kî$_Õ-ƒñq'o®ðö”ëÚ9Ä)³µºÔìØ©JŒ¦7;ïdñ˜Ï/8›/EG]#¢Àîr ;î8¡:Î1à•ð+«í½_(ä ,œn¸L6ÞfWšóöL–'À”×mdñ†•‡7ÉÝg ¤ QCm)¹FÀh‘¥ >Â<Æ‘l!ì¦õ…¢¼Å˜${?3,¾é*q¡–CÑ»$L!"*Æ!ÒýˆWØS””A.e);^2~4m·µ …:›2H’õFºRŠ×‰©…êêd½³^7ô>Åê±Mñ'Õ…t${Œ³Öˆ¦¶ìÒédYžS§T /U$ŠDPÎÎgI'½ˆFÀ’¡"‰jAe¨Ù…úµ" ù‹¼ÿH9jX‚©³7B­ÈXÃÅ5Éßf“+"ŠHÑ9BÌ~äÑ…öƒåœ-´ 9Àj|#SìD3zf®˜¸\èÏH$£»¿}®BØä’Œã$¸a‹†£d má+ã½¨Ê Ø“ ¶üŸ*Gʪç\¿~™§3ær€:s¶, e»˜¹Ø©wÝH`žÜ'1ƒ*ïÀëÓtÂñDûau[¯v<4këvíC°ÔÍ—@*NÞFÞV*±fèÂiÏ‹ÛP\¶ÃOsÃ`&@}Ó¿¹¤bЭƒûsW’Õ²—Eݶ§àç¨öç¢æŒ,´™uæ%Û%ú@Ý ¯üG |ÅH¡ H+=;âî¨|¹rѦOŠñ•s7Haè¬!ÍØAƒ>*j‡ êRZó5+•s iæœSEÌ9Âl•MJË…žæcÔ$ù26Ë´#V:¬ð,ˆ¸±B½°ºÉW²p]™~LUN)¢s;Jíbø'êS‡DÔ#U·L;¦M?Vã ØÊC—¬îY5 ¯.ÏH•뺲!8TdB.ʳ¡Ei…?híEmGˆU qÂÔÔÕõt‰Áê*°.«PŒU­¢°ªB® ² ƒ ¦¯tÒkýcÚê5EØùMOÊb²ä8 º]ê¥1½|éó¯$tÚ=æ0âC÷{Äà´Æ¨TÇ„ ÃX9= cÐÕÍnHº.ÀNdd=¹"kÜ‘‡±@EU¶u a,cõ"‰©·»KÇÌ;ÔäQh$Ú¥5çb‡<…mHžeqxa“_Æ©ž¢ÓÒD/yHy]H×ÇÎ`UbÖ [¥ÍÊ€¡sÁ¨a^rð “vs5´ Á%ÆpX "¢"úPLJM@§¦°³ÏR£d©©dRYÚûæhj}åT²$8œ³Wqš|I¦n³wMsøH~ô‰Æ’œ!™5j½µ(ž‘¼º©u¹WjrXÚœÅ\Ï›ÓbØý¤ºMk¢¬R·f3%ÊŽ>†6g$Üô‘b´r^êŽ! JÂÐí r$EÑ©ÃÆ-fsóé ykˆ^ëâ"‰™\}'„¾³M%1ce æ ¢ FB;SbébE%õIU /[Н·ªÿ],‡â1'ûr‚G}ùjv6OÑ™’Q™Ò“«DÙÜnc •r[õÝ¢œ²Â%¾f·26xlS·~Ø@ë–5j°¿•ŧüwXºÕ=_kaÄú ›â§tnÄuŸg ¸ã{¾”kÄMho:ÏjˆÕz$—®CËÊqš@ÏQ¥R”¹5~ikÎÅ:$ø)ï'[Ý:_ÇCä&qÓa¨¦«Ö%¤Ò*XÝ$·³œÖµõ–üZ‹£r“k¾ÌÊ}8åRrØ¡ØöA(öÓ:)­2 :3#Žï0âßŠÞæZš#m«¸·Žçf2ò¹Òû­ë:I®Ú5>’íΤ<¡…á\5uîìÙœA0ªí ¢œMJ‚)/—'†ý‘¥"‹@åJ©†¦€U²½ä¯Å%xQuÅsFùÓ¸S¤ÏQÒË3ûŒŽHr#¨û| Z—’ÕÉw8“+*ÚHó  Øý݈±‹âBŒD芶œtè\-Sçd™\MޱmÆsEco>—ž£z°ŒÈ±F•â· §”Š“ÐK~^2R!Op =Ý"Cqt˜91œÈÛ.Hgôei=QJôÉÚt!êþ¢…Þª Ë"^QÆíaèÌÖÞ¬ŸþµÝf¥ ŠDŒ¤Ì ¯\V‹ö=»fYöÖ½iZÝf}P ½T*ðãC,6{þ4Êpì¹ ½¦+`ýÒÔxØßp…žjÕ¹«íºË´ÂíõŠaLuéh2aç AQS (º<)L‰u¥á:Ëêåq«Š¼æ2œã©S 6-]W‘Ë=Š®Öä=½)Nú†y2R8_Щ¨{[GÜ ¸¾ž;í_Š÷FàHm[¶ï¹Ý_œ/Òñ8W$;¶»^;„¯.¹Q%Ñám:7w6#ª˜-V Þ-]”0¿üÁ}(x©%á¿Óp¢Va‡Ô™vÕpÜôÌ9¸22ìNR,¦{‰]'5È*•‰î°+ýWÊ—ÞyÐK@¹{Çá*%øÑÅy!瘆m„9¨6Ø…§67Uö^3,‹y~qíöÁ*O>šËû\!½ÅÎӫͼÅ.SC^XQ4%ïÄ÷.øÛ‰.7)ßéðnèw˜?Uýð¦«Ê©RuвxbN4W#¨ ®Zª5[ ‘dÖ2Íæú#M¶*§Ï6˜7rç4¬ì'Ðk5ë˜ùûÀ6VèvwîaþŸÝþþ½ý]Ôÿôwî}Öÿ|’Ÿ¨þ‡—U?w{;½Pÿ|³Ýl÷÷“ÁÞÁÝýƒÝ¯cêŸÏS®¯.¸Ô¾ üCThsÇ‚³tØì˜TzXš—©ü¶ð¤Ï³‹‚tåÊ…IDIáHBSIÜØë½P J°2Å4Òε*zß m…kyÜ.§+F® ÈØ¹ÿñ±Ûòu£ˆé¡AæpCGnÖÂSA¦˜Üp%|qºNá½E—ä¡'‚ç:‚Ã{Q'6W 9ê}‡_¥ë3psòW%ƒ2\'î­P_@W•$Ök­OrÍâÉ[ºé¯×¾{ù?æ’ʘUd¡"w8ÂÔ:¦sŒO¼¶*Eû¡Û'–«xEò)cSÛŒÕMIDœf|àÀŒ::°Q¯­ 1ÔŘ…Ï… R¶rhêzç1Ì'%|Áÿ웫¤¥ù,ãF™±ZìÑÃ%#ÜKSñð”­Wõ­üæêRîX{çãá5Ö±†ÒéEÂé^ŸÎ1%Ÿ‚-ú¿æ§™ÿû$ù_wwö ÿë½½þî`ïæ½;øÌÿ}’Éÿêœ ~*ëßÎv/és°÷ÍÁÎ@q}”–•¡=qaû¯;œþ•¶’Cžåa™ÿ+;HƒþáÑ bº§g[“ìÔìíìe‡‰éÑ“—Ï¡òÄÜ$TÇÎÎì=Ò#Û+S·øîÀV'EjÊ¢K†_´3§Ú}S›W Ò7ÛtEÓ½Ü\ZØ`8ÁhbUà_ðéå9D”³t„s/çéÌoc+1p,ŸåÓƒ¤¯&Ðô:»ÀÿáÂoÞ× sSbÞô4ÙZ3óÍì}R ôør4º·ä R-àÕØ#9VšŽÞžÍ!ÛAòåi]I;håù|<?/ÞV‹O+ÅL£Ze}Ù5ûtJÁ¡=6hmñWݤ7Í.å/ünœƒž•’/æ¸üpíÀº½$¦õÞa×›]ÒãmB\?õ¶ëºOuc—ùxqÛ™v,í Z[Ü|Þ ½¯Uâ6Äƈ7}0¯ëo,Lå,g¦÷ ´®¶gÿ0ܹk¶k-y‘S6I†LÊÝÆ p'ük½š™L4àšÊ0“=V…©®ÓI~6]‹ ­×Жµ@E¦eTL 3Ÿ_~s¯ÿC¿_?t½Õ·È99V]„„kr$=ÙrT JôzÕCÖwKÐKV¯íg¦ï#ü¬àÿÈMñÃÜ¿Vðû»ÌÿÝßÛ»»wϰàÿÕìæÿ>ÅOTÿ§–¹Á¯Eh¸Á¯·w¾Nú_ îìí'ãyn„Àõ}ÀЉªæ¥Aö>'Hر¥·a ž‚ «vî d%èq&Áq±FdžSt·áuÍÖ!¹³Hk(Ÿ. ¨,¡EÌ`LwÎvJ¸éÍÍAzÕÍe·B8$¥Ž02a$d>²üE‚À…ާæ=@o±Î!zÆÙ»¤œ¦3ÃV,8p&ÐÜ4N ðp®À{Xýd¡¡+F*GWaüpBü±“ÆËˆ+8›g¼‚^t:¸+¹ÐQ`‘öCmS-øN¼×Ç­…åq°1”¶~#c&€Ães–°¶+ÔÔ.Ìî`’“Þ ´r¨TžírÊÉÅ"X6Òu­hO¥¼XÁšz„}z±7,"þ蔤‚¦QñéàFÝ|Ì:âà€Cžk¤+x\‰Àlt“6½ph kÕ¦aõxÕ © üéáá¿ÈþìÒé„“¨@ž¬–~HcªM‚•Éì&ª+!ƒ9þ9ÙÝï÷=k®S}ÊמòSDhH ¤~ž¾R½Û€'®¿*'›Ó‰£ï$¨ÃîjŒ#1ÅšÇ[ìcì–·ùLòFðÎì”Î.Ÿ.3™Œ;úó<Ä•Â$óâm6íÅ{%U?êj¬+’Ý˶ä$è 'ÛÌ!™ÁÂ5þ‡7»Ö_Ûoßx±QØ)„‚ 7#ý¾š‘’9¼5}Øeˆ÷67LQ¼“ ³u)É#Ò‰ÙF¾Ãvs³}Îæé õ%Nynᤪ|Qf“Ó ® ÷iY2'áì‰[ÕV×Ñ8xR¼á{à¯’Ž¹Ç¾ÛL€åÊ=› »ëž‚.CÑ?—Á.Õ•™n‘@Xfàö…VÃR‚ý-_É©|,|»í]:?¬ŠàO&®‘é@Ϥ Œ0£ Äð$snÞv¥*›û$³p÷Ÿ\á8 {Ÿý¯ö¸Ö,4µœÎR€ZkÞÈUÔ2½£íKد`‹Êçnçn=7©s’9Òc,Ükc·\ÒæVMåð'þÕñÛõOȆ>Bè²Ûñ‡•A M|íUðÆ'hè"+{”1öTî@$Å”3ÉZ`|Úœ)ü{6É\UBºÁ¯Ðú4öB'ëúèÛWÑÞiaf¼’]Wç ¸ùQ¯‘Y†ÍMÞHÕ}á ºwÍ»ä é{­RÂQ嵬÷„ß×4Š7›ª}OULJQ¦œ£ÆtŠqCüëMj«wü©›ç×®ÿo^«~¿ ·õûpêj¡ïzö¾vW6}Ú]u”j\È~D„”¾𑎟6C+Ì­t™+ˆ¨ì@´&]ˆ‚³\Ö‹ÍÎ×ôÓãɪ\Åfëk’¬äÁá'ü•+¶ùú[Ÿvh„ÃXÕ†²"ÌÔ&1JfßhÃ">™n«½™|!ù~k»$Û»Ò‰é°rž¬gáÉd™]€17üjJ¼ËñáE>f“I¿Ï–åùÉr±À\ÂJ:yâåb9M࣫!OéNMÌó 9¶#ƒËËÈt É g¯6’". Óy:o!f Gì@¥½µæ!`±˜ï; D;³Á@–ë盞ʧ'el  ÉÕ¼ã¨QÊ>-u“Ü^:Ùö$®ÚñþɆé"b¹ˆ‹±%§)Ûª<\“(§‚B'ç0„PŽ ¯q{TlvÒD(7¬•jÖÿr¢XjHý6An×Ð œ_HÛÍB<•$g´|ÝfÜd¼.D3ùµ:¹t %—Bp廸«±‘Å'Å ÓÚˆ.¤ä‚P›ÅφfjGçö_:¦ô¿ÿz|ôhó/äÀ[×Dd$æSË1WÃè»vW^JZÊh TúÏÂ!äeO\UfG‘òF’8qâHø¡R“Ö^ïýÖ ·Ûêr}è•Í̦âclé*¹·i›/Ìñ08AY:âW§pûÿÓùÇøÏÿ0½Øü~ÛüG¯÷§íÈlvm­á¼B1ì¹ s©×;oÜôÒ¿BF¿ð¶&µCmß%Ú×Pwu€ž+ŒšHIM§ÅdBrš®Ë%º‡EàY€U€›d Y—RäÒö¨ÅrF>×5—oò’AX‘.AQŠN!¿ž€ÒQÿwÍøI¯~â¶þ|Ex&ÌõçötEúƒÈ2±[ ÜïË)H’S' ë+){¨ÔfP¬ÚM'µþcöÑ®‹¬a _¢ÁsÉ7`>Šhq¶-Ÿ3dÌ0]¢Aê.†½>\ñ­Ú—Þ@j¾Ó“&_¹'‡Qfn᡹¡q4[\a W)êÇÌô§\¨0&¼ôÌug5£šH/=”üœnÞóŒ9€jœö©® uë%YDP>s1¿#]6„_EiªÁÜÇkD0Œÿ¥Œ‹=œ[€C …$ Y§“ô DîËÜ”4äà’HÝBÍykéÒEµ8lËô3]µº*ŒÔ>&†®%#q/O óq޹‚§I q‘‡¤® èÓù[Û=‰|”%œÈ‹+Ìøe>†´˜6¹ß7îV^RH 5hWjl†o$FÒEzλ&34È Â5Ó BRD"*c÷“K¸…µÞqI(FæTP!øPJäR2Âm†ÛIeí¼ÃId'º«õd Ië1$,è 5D=I:‡<üQOÍX¤>µü•º0¤JÈæíRcqAuᅌɂqâgÆ)G;ÙHS"Îv}£#äm˜Ù¬IžÙµJ,º~-ƒ @6Šˆ€<#^·ñL•#HQÃ¥BºSÎo" bÍM¶[…ë·.ß9‚šdÊMÁæVÌî;á·t–•}é BŒŽ)à󈛽s²¤xá÷)¨¡*Ô‚ q2š™èôŠh‡Ú Á¸1[2R¯üÌp ÈÃ2ÂÜèdÏË8n‡AÈ7)—¦¢tˆBàýbž&Œ»…60©á†šÂÕäæh¡°¿kkDeQ.ˆVƒSµ¦è„_@$´©*LTEž*ƒþ•Ò/¿STòØ m:€ÏÏ‹eY™%$д ¼ß½ý­“åÙiþ>ùvkKŸ{XN²Q zaSÔêñ %0{ó˜ëÂMg+5ý¦ß÷VÖl–*÷*½+”sA‡¶viýßë†^‚hlL8Ê\Z›*nÒ¼œMXV>ǼÞsAçn=¡&¸š£ÃbïŽ8O 16xÑ P«ÈQØC¸mpÏ#ØežaàHüpÌ’ç»ErÐ-¢Ü:Bz% …³OhBH,ß…™Ë!‘L~D3B„~›e³é‰ÅP“Þš#½(Ì^Eé%î$²Š÷E³óZBH&áS Ì4t‰¢u=‚ïj3âT SÝ”œ‚³,âe–Ytv½¯ìÑš ¦ 'ú‰0?N¶ç”A6¬ê ¸­}AbÇ‚;¡öf¾ »¹±;‰\Š;†8c„jáXhYÈ™lVäSÉ„ òV•BÊñZá ¨1×ïÚ(0¨bºDh<2¡cóÖ´µ™ `fv¤’¡°œ€×ÄI>1…6ãL¥é+0#b§!4žÞû‹IeG!{kV,CF‰3{[<8ÿ–ÆÌBŽ:2 <¥ ªPMaq5 †UæÛu.—àYRIÑŒž%˜Ò­IßCš6èzîÐJò#s>ª»5ñ00t0Nè1y‰‚^ ½9ÊŠVÉžvT+Y­Ò8–?N8"zÌÃOa´: Òz’q7w=o‹kûZ@Ã6ŽÎÐWÙÓìQ±Pyr<@¥èIÆ®Ø,¡DÖÕ@õ:½ bI€ñœ%^+rÉôØD”uÎUO†ü_'[RÓ2¹¦üÀ;OY(;HÛwЪ¯œXQcÒZHH]ãÔôÃr¬%U2˜¤c­ËƇ®*ÔxhÙG©®êûcMC 8¨JÝ|½O=„`m ]o¨W1»Ó…„x¿ ›~è}ñÒ!§ ¥¡].^Uûi½Ò:5¼Ž˜;é§møù’L‹2m[f ·xrºaqLt+F?[Á]2X·7+_àæ^*+¯ñ±Nt JÐHov Ù[o‘¥Ýõq¹;,u…þŒ,=í[{ c{ªgµ@×Áè‚õPYÆôNS o³Ñ[†¿Ù6d÷ÿ{P¦e½ (¥o²ûøÛkl¬G¿éf²ª” \ ÿ?pã ñ²St úe¿¹Æ&Š#Ïÿî·RÛ~´U‘;‚W71ÔmGÃ6­Ç –FŒ› k›es- ù)›µÔÓÑõšºìp•óòa±}Z¡~É|GƒÁiÙvrAw©ùEÑ¥Ä\Õ(?ÂøE•bÒz^5ܴȨ÷Ord>‚èÂUf;N…Ê„ ðŒsTDâ:ª;Ýq+ׇ.´y(»hƒ»:D•îPœúÅ•¨ê–é‘ëõ£ì l†m*³É;Á¿}/'šÂl"Â4”s­kÅ%ÿÔP4*²ëÑ2N´‚R¦>qßyZÄlÆhUio6±pô¯Ó®wñi"¿ È%g²G¥½»mh¨µ'‘Q>5,ï%ôLoÊWJçz$¾ªÐýû¶k¾ä©h?·üº †óñ¹ØÎÑó<Š¡Î²7íÇ¢ ì&«+ …ßÒjئ~·]pµÜ÷•H7ìÃÿtAq6!'`3Ä­"ÅÉ¿ÿíõòæÇªsà )ìÁÍà„|E8ÝO1©ç*ãsï°ýX}»ê*[—¡®®êpÈÚ´C©M-¡,\ݺ K)nÃæ³ÊOX¥G]«ÔRÓMb)øGÅIRCñõHÒšm¿®àu»ÕPSâX·ú.ëßý#ì ’s0uœâžE|ËÁ'u*¹Ïu]J©!©]Ñ÷2ÁÌQÃ%:÷OÙSÍóCÕÕÉf½ …' £šr‰¯¸B‰RÙ¯èdžNÁë‡ûJ92Ød¶„(+él½Ö«XW‘ñ£G qý¬y¿ ‹týªPö» E6é›ígR§ó }“uEÎKyá\v(DÝ\™3äWĹ”ŠbÙz× BOŠÂ¥êhO<'ÀvkLi¦%C€z ; ªåIŸ57ìUˆŽxìj§ ÁõÕ'E'‘ºêdMïŒ|õUROÈ@(ª§dë5= S årúC±žÐÞ¾Æ,˜joe Â/ÛX¾~puK–äð²u&ÙÍugXëLÛÎõ½v'2óTųóٸə[3²¹iÿ?·šf›£`¾yÅÒü‹… ŸÊMIúÔ}q?Òª|U5X}Tû…KÕj¤*ßû_þt•…“ÚˆSÇ}»ÎpV¯Ú€þ Öa¦_Àþq®Á¥¬e:÷(ŽÒÀ×ôT¬Áº›¨JÖŠÖÔÞÂ;µ™©C‹T1óxOϺrëÁG‚nuMÚ齤”Uf!“³ÂÜ7ÉF3ú}h¡ts>'YÆÑß]ê]Fùéif¦y”•Ú:±hbRP?¬Oöl2p±Á3ÊŠ„5‘2¥¢ãÉfˆà0QiÇŸ)ìù¦ÎÉÅÁš“ôŒ¡¿¸J?¸Æ†Cõ¢4w…¨¯ñ5ÂÓBÆê(n1¸¹A8—0šA‚|Ç„*3²žz…r²Áª¾'Æ-ò ©|ì}²°$/Õ(ȧ5_\gõRžÒT¼E^W®ÜVz}áWíR\·&k$MÔÝàtb.3Ô, "¦cŒaª˜]Ø9cÓ\¬‰«Î‰ÈYìs·¥׸¢ÕåºêY6Ö»aÖª8f5|±HËsŽû€ØçšüÎ+&i|M¿Û¼ëÇC ",i« ¼V*.ñ@ÕsßêÕhòCªl¶ÐM;Џº°t—©)E,æKÀÍÂX„Ͱ±ÃÛ} [„ï÷QíÔàUEc¨q¬êòõ 0O®¯M^G6 +#³¤²»WÜÍ…ØYx©ë{HW`ºâùä*vˆâV8}†~ïÆ¾`æêy¡®ÅNBø]ÊUg]Â9œ5‹’Mý'e1Y.ì¹2Ç E€[]]O…‚¨mHP›yˆlpY¨¦`•¢ £ç¾ë¾)›±Ú§D ¬È¼¯0¯¾^£¢7rÉý³úB’ûƱ+oEµ8Mnc諾9[æÛª»?â÷rà¨(”dž©)N¼:ˆ7DöAöŽ-Y½ôÄ’¶ÔÑεז‚VÒ¤äßÿ®3>­_cåî¿™iÎÜ$ÏŸ¾lâˆonó[Q9K†Á"ÀÎÒó¿Áä¨ÞUͬUÖ“ô?@¹ÎüõøaÅp¿Æ…Âà/^Ðe{¥aøâ ÍK­tòßpÿD<ãoz㯵D9Ã2¢lîÅk,®Ó—Ûá=oÙP[€¼`ÔæŸGÖÊCém4ε¾sê` ºTô )ÕÆxM*5ÞŒ£çA¿u6OQïÒòbܤŒ;´LúJ¹©ò4b·‚Üjvš\Ñ®p]nøk[7ÁYÛp[ôgDCÌé …¡#=RýDløiQ¥éüÊ…_"ðàB̲i Š£,%žÁEŸðºÛ(@€édâ#ûÙ­@wë…ùµ¿3X´érך¹Ò²,F”Ÿ¾$h|ôkÙGG&CòÍÊšÏ\$„SCzáÖÖ¢^Ø 0ãåÂ@8ð—•gÁ$RâFè @Î 2€™CôµÒ8øÐƒÉ Rñ1?9¿ž‡0ïrÓýÒb¼øèüÕ” ò†µõAÊœ+W=ú´¦g™5‰Ú˜‘‘y€eu6-ž8ŒÇTÉI!èJ A+a•aP»áÑ %QMÀ؆µ£†Øš Ö>ù;Ò9†¼€5 Z¢Gç¾)ÞöˆZ z3¦ÑÈž 4’W·7}¹"qy«D‚¶qm%ÎUEM\úñèn{ÔDbsóëòzñ0D O1úZ°¯ ”{ª9Ož§H¤Q\ uSÖƒSM†AΩ†‘…l´øCàéŒê…ÿÖiøãñË×íÿ$V|_Ú®µq7ncI[@¨ú1Ñ÷”¶xõÁ¶èJ*/,ÍŽ°M)nmšçÌñŸ]î°åQèÄ㌠!)Ì{HžcÙÔ7hQïsg %Ö}꫇ðýÖØU$4òC€sC‘ð]°Y½ìaòÕ×þu»/~ëü5Ÿ>ìgUþ÷ÓâÃÛX‘ÿ?Aþ÷½Áîî`ÿÞäÿÜÛïÎÿô)~ƒÄï§f|ÂÜŸ÷¶Íÿñ’¾÷½lOŒóüJƒDÞQé©Í»‡„í¨˜àå*ü\ƒþz lkbõzwlø@ò÷ãç/?{z‡Ñº¡QÄêæÛ?܈Bóx¿÷þÎCs©Øc|V¯T¨3i p‰™™øf«¿³µ³§ní÷ýÖa2ͪ¥uÇÙKÍÃÁÎîÞÞ7û;ƒ¯[w~—´²ùüc ñf[uþûû˜ÿÍœþ»{{»;ÿ­wçóùÿ?ÑüovÙ‘Ü“ìoßl÷Ûƒ»ÉÎà`wÿ`°¯r¯ŸüͦkJGϤÁOþöÐÈËJœœ5’A9+pµO9š,_•¦*X8ç|`ÀD¹¼ä§\ݱI,Û—àXîYÖ1røkÎd¢†¤\ˆ˜ÉÛ›1æ/ÞØ+gæLxWóØÐ¨a#ªÖ±žÜäY±(:5l²—ž’ñ DÉû]žR(&àÉ8GX&®I€eçG~61{j’l€:òÐCç8÷øÿÙÓ¿©>€;·ê¶Ÿ»°íT,,¦‚­Ên>˜˜p»±ÞàÒ%Bžjñ‚ ÈD¨c°p*ᨾìËFSL¤”Ž Y” лÈ(°š@.ã)êLÝ'ªRs^æàÅ+YŒÀE®až˜Fи$O}DLÇ%zí2”`À=‰ÿN§å%e L%?žµ€s7sR%’,‹‰àp²ÆÛ÷ß@yÝ –!&H.Æ{»ÞIÏîCœ‹ü]J;tL´¤RpvçºI6 ÝûvCR†;Ü*Ð#[G×õše® 1¼/>_,fC x$»3_*ÉŒ|¦<‹eJö‚¿É/ľÖr“¥ ’æ¸Çf‹é}ÜÈÜoóõžsïôrð[ð_®MN¾–òúsˆ\ëžÛNœâ`§#XÄwé<‡·(¦Š>wÞÐ3§tÀsRUd¢ZZãc4h0;û}Cð?;wÍ\O6¹~ÛÝ'RŸle\üÇÅYGÑ“'ì’ßÅÐÚ_Ž^>üë£g?‚¡àñÃãn2rþ.Ï.‘×PÛØÅëêí] ±.?þìùu{,ºÛ¨¾9~dÍɯž?q]¯v[.Å8¨Q´Å–Ö‹ù´¥Â%vX³¬Ò²·K/åšÓóåÖC¹ q¸N²4‘˜]6¿2st¶$ÎÇ¿?zþêç£'ÇϞ›ÿüôóÑËÇß?~òøådÜÞTÞ%gª´É®Ìßæg&¬ö/Ÿ¿:†Dqí¯ !›y|è}Õ–úî/øî3ò (Gáq[sãùÚ&¿â·÷(Cm£ 5Çu˜¸r*ýˆå4\™MdÉHlá8!×2rÑÉ‚‘¶J¤¨c•Í©€–cIqá«A,Í €0÷±ð°ã (â€ýIÈ—"ª’.õ NÚT"?ž]€_š¸:!¹›W@1·igB¿À8M@©)`ÝчÙR¯D¶"Î}ˆ“×îmK®¾mÖõ€¼Ù&Þfé~´½öpÇ%Oð’»ÇËrl0À4ƒÀNõ×ìx`‰0«Œº€)"o¨a8|ªX…£Ž¾ÆÏÐÓì:3wÚÕ´ïµÅÀ'ìùñÿ~õøùñOÇO_ÒM«µò8¸×ºH~‚ žîïtïàaEŽÐÂ`ºá:JËEp÷ $fhPõx-“ÇI:=[’ZN~ò;YêxuÝ+X!Šâ ýå$¸gI 0üƒ¢¡¬6t˜ROò÷¡§6¯:‡uÌÌUg$âllßxM)g–&'´jå•ÙˆUÄ ú®;Zh^‹¶Å³éVÚéÊf‰8vè¼C œÿL²gDÅHޤm;¿{´±œ%_@ʶªñó_¾kÊOàv‚zA²@”$€ÿÉÉe1Ë*D!¨Ê)8uf÷Õ%`ÇWl<f£ò\9Ó{ÏÁo¿ú0=«<£‰ uÌR÷ôÏKå #$_žŠ–8AZ V¼'ÜÖ&º^¢°·¼ð8íc7+CJdìN¼Eu´ÃßÀ&0kQ)•QVå!EøÌ]qØMsÈ=Ýδ›¯|7:7hdf ­ÑÕÏ[ð¸å}ÆC¶ý¡ÁUJÌA´å¼¼®rÃHŒlj ‹,øj-Å\œÒgn¤‹ÅÜo¬C­4>Ê3 ï­¯%e<– 7¾ŸŸ?û_Ç_*W¾åI¼_)­€"Á{g¨„ÏGk2¿ŠWá>ô"Ò¨·ÏŸ½8þÐÞÊIÿ€ÞV"Y"½}yüü§í*æé§ƒJ'­l5s8‚&›åcî ç7݆k8€d dVl›õwæÇÛ`¶óÚë5ºÃÜ:»Œ»üBõù6Ü 7±Ùv6YquG†™¨}áµf¢8­ÂÕ4–Ž­û¯7hõµÒ5{ ¿lîÍ5*zÙ,4±è™¥g¶fMo²_š·ců7Zík#£- „»çÜÜ\›è+;Ï/â[lÕÇ toE9¬?ʾ¢/tËÌï]©Í8_8ï§Ê{›ãZèc×Q—®:µ]>b]YͶoP·›G-cVòYtî ² Ъ¾h6œF¾µ©Šh ˜ÿÖößfû?Ǹ} @³ý§og÷ƒ¸íÝÛé£ýÿ^ÿÞgûÿ§ø‰Úÿݲ“3P_<¾Þ6ÿ¿óuÒÿú`p÷`oßóZÛ`‘EsQ{Õ9$ûÆÿŸ²éòÚ¢@ÏZÎÄl2TÝTù¸@ÅüïYÍ¢Ù°PU*ô㦶i$l];Ö¡–™ÐʪkhÎÚB³#†£æÏ†VíÃÎÈ\…S¼„Ã4MAŽ{³¦ób9£FØ?^Í9>zMky tuú(ÏxGñ fÍgKø¢ýí8— –á~KòßAÙlÜzÐî™UŪ¿ƒø“'©¤ÎÌŽÿ è“ô¬°¦¯6>B Y]̺žÂ06@nQOá†:¨Öˆ^ùl “‚:;ù¶œA*u‹o‰¾õ cz‰6 —õ¶6ñ@NzíÍo·¡êí ÉÖ·ÛfZücÚ:+òΠ뙡uG¿Á”Ñæìµ¿Ýž=h{ËZ!}ãß´¿4Ê^•ÈùƒÈ[Æ×½òÐKë TŠ”/¶<÷iÆŸŸè€PöE,.ìt’ëÑ¡~·ÖœâwnZÙƒIÿîÖäv ÑÿÆÙ$?¡ûdZÐG“ƒw dë„ë »¿ •Þ*³o‡È]{ÛðwnRѦÿW|q¤2¿.²„½E+Ö’S}ÝCRÝ™ÜÒMãÄ–D«†„xQÁZ± ÂHË4)[qD‚CP× ÆL–æŸÓŸ×n-z®êÚô v¥å§C÷FíWéSmë,‰HÛì¦mY‰ë¶¾fË•V1F©¬n¯z–¸ r#šMÒ|ªv©X½êÎA}/ábé@†“‚ëSצN÷ǧ*®Éëö"_Lü¨åX)HÅB€p‹“jeݤòå*µq:¥U15 n¬†Z›ÑEH̔ǿªB (c£6îG5PºX7|ß¹ÀöÅÛBá#âŘõƒñJÁžldÇâ(ølý´5®òbá ÔÚQÿÞ”ÿh©¢±S‡ãÏZ䆿ãìßä<‡/îk¯•îÉ&qÕ N:FJ§§Ë?vØ+(* ¬SŸÁÐÃADÏêÁ4õ`­ +$þîÕœ¥ê¹ñaCäŠðõ62]oh™`XoºÄWò~‡=ÓŒ¦O‹Ë.“Eð–‹8ŒñϺ„ÏŸ¸Šë~ìö- ¡Ç•ù_5qÁ÷݈p‚óbi|œ£OÀj3FxsÚã o¸%*Ø]]Rbi0sàôE³&w¦fÆ¿µjÙÿ‹µIÔ ÊíM¬²†³úH™_cj­çù*ù"†“8À!_?|ˆP ÈÏŠáJm)3:¦/ìø›‡½&æÜÑ„1®¥2ÕD]ûP÷Õ:£ñ[ï¼=K­—‘¸@u¥ ¥a_JkåÞ .Ý_l­î-ýHÜÒ³2WUD·r‚­‰"R­s•J±ƒ‹ipÆÏôLÒ½4'HTh…¿ ââZ­¨w'ʨÚ)SsjµSSpµÓ—Ô™Ór-cšâàŒW£’^´×²ÿ(´ÿYΆÈÞÑÆdþO³Ñh}ÒD+ Æz«±¹ö?ð¿ö?â³ö¹mù£œÌ~ÚŒÔl®µ6½æF·Õ‚ÿ[˜džSem]† ¿žÀF{À*¹ãv½z«Œh;ѩݻHÊtkƒ32-Peàï®×lLÞ–P§«œ¬Ê“u3˜¦Ú(ê«w š—Ë.Ü>£nìÑ!‚ãÐΦ˔ÉLKœÇ«ð|œK $…]“,ÊH–z~üüŸ$ÿ¯âat¾v«u “ßìtrñߌÿ$øoð¼ÙYïÿïÜj+r>ÆùÎøóŸ„ÿ·¾±‘ÄÿÛèl|Üÿ?ÄGðÿ¬ñ¦½¿%øk{^£Óí4’Ö¾âÕrLÀÑylÅ눱øY0¢¦3BÕ–ú pûÒ‘üÞçxýóÓw­cþ_³µNöÿ ü·Ú­Í6ÊÿÍÍÎÇõÿ!>®ý¿3ìlû¿nÙþo®µÖ½ÆF·Óê®·‹mÿ–wc ¤e(0vÎò§#jÝ$n¥|ðô›ÞÁÓG;²hÜøU¥¬p^Ž¿;ÆD_ï<"à8T›<„O§­ –ËùüxïÈÁµÛÇØxc£q6.¢èUï"NdÇReqGøÁ>£Sòôœ[n,+á…AƒF×36éÆlŸqÚ Í6jŸ°] á{8™Bgñ)V¸©O ø­McÔÖE´j%&H¸l†ãÌï‡ÃpvU/U]+ï,cp¼åúC Žž,×AˆèJfQ4äÈMg!&ÈtÒØ9 Fˆ|²èÝ›ùv¸2>±âº÷‘åãy8cœ¥L¸ùˆ€Q¥žÛ­ë‡ :çh\¬Âža›zˆ»éØ ÂÍ`莺÷tì=?ÜÿÕÚA8ž¿‘FSµ€#c®³¾â¢ˆÛ"“1–؆P4Ûˆ.[¸E= ûÓ(ŽÎfÞ/Ãñ º„2nL7 ±[â€á ±²=ÜRqí{_#Œ î‘6eõUQ¤YyǾ/m»ÄPù¬ùÛTö³ÇϾ‡Ég2×éÁ,CÊÒ¶|Ñ©Ýd\^i›ÿR"µþ,IJ²ÝRÓ!âTAùºkkÀ½ëÓ:à¬ÁÌRÓ©_ÌFCºÃ´”™Þ×ÇÁlOÔkÁxM5¢.Ù0‰)K–õ5‹’†QIÕåfÖ°óP“y¢9œbügDä¼¢õ–ÈÒö±ÍbÎiêò-„ôÅH[kªü„QN÷!ˉxo’£ÂÊŸ‹WÖJˆkë…ðL›eMxŒª)G¡«?Ønî`YÝ,™µ¬S¨È/€é!Õ½³@ îa˜[ücçnŠBäZ§œîÊL!ën §›“TãâYweP"OOžVªû}Œ“SQãO"T–Ã-­+?5¥hžleÍ&·r5¯°ý/TûÔ~˜šHŸÑý«;‘â`ˆ8‚5•Âk|‰pŒ²9ñßwYñ•¦Âg #ˆÝÖ±×-*ÙÈš—#Ôè%üIÙ´)Qá,U¬8«AõaHAFþP¹=Ä]óæèÈéqDgEËë™f`ÓpËÊÝ4Õ3¬*ŠëŒ(´º ’*4¢<ƒ)|~amnѪ]fÅj0¾zºp”ëÞ®B_SÐk²Æ¨W®Qe/úX܇0( –ޱ¤@†ðì ×x¥ª¾ëÖ¼#6Kâa†©®¸xŸÏÙ¥QÔÔ¸ü]ØÉÍÞe¤UÃ×SË›¨q‡ ­±jæšLÌCY’öCw!ªÑÑ“S?Xõž#†{¬)JÖñ!“g…Ì…ºÅ6œ;R­ù"a~aÍEÓ y° "0N¯¡–¸•¼™LÞÔÉ›É[Éä-¼•‘¼LÞÖÉÛÉדÉ×uòõŒädòŽNÞÉH¾‘L¾¡“od$ßL&ßÔÉ7Ë®‹áúÎ eÎ4 ™»BÒÎÚzÀ.ƒ“íëƒã=ã*«_éù`¥E'piDú«ÈÎ(§ÊÃݽƒïj7fãÆN‡óHÛmôÀšº\V¥3ÀKfîfö²ã<Ü%!¡½Û¹e™ÍX1ˆÌšê£‡ÏÔ@ÉB³ã©P>Y7cyôz†#N1MƒÇ#OŽà!‡ +¯_ 8ý{´ñ£›·xù§#ìÂ$á¢2/Ú.LyLƒé‚TUX~¹º=™é@> 'ˆ—ëe›™$ãÞxŽá«$›šÙä”ò¥n€”bT—[¦•Ô›š—U;u«U-‰?^P¾çORÿ rÑ48GôØÛ»¼þýßF«³þñþïC| Æß|­‹iÿ ëX ÿïtZÿ§±±¹ÑnCºVssóãýßù¸úÿô'.(PcC‚­otÛ™!€rôçR`J…nê4Ih7‡F="$T¶‰­øºÊÕ$îƒDàÃE—Q^F•?/Ñ+‘jÎQ0Š^g4G'ÍiÐ+ Å Ú¯{¤œ =ÔDÒF[VзÙéãùhäO¯z¤ìX–â×,J> @Öi,IAégùT >×ñ¯Y§.Ž&‚”rŽÆ’!”q¦(ï,|áŒß<"Vb…Ápgˆ²ýpÀ:-ç1ªIáÃz Ú°l|ƒË²Å z‡ë]ªáϦ!Ž•÷‹àªë=‡ êÙÍVðöwëº}*²LRóʸ½v ‡Áø|vA¯[ÎÒM'ýZ.êÓ ÙÉ ø¼êAVó“9ó;ÖmËÒ8+¹NÃó†îZ& ‰æf´öt¡Š³°áxéfÚôld6ޝР!æ£S„ê>CK ÔÓÔ¦[¼­±ôDz.QG¬ñ0g1ÔÒÊ„|\Ùç7\ *Éœ§)¤pŽxÉÉ(´hÁ"ïáÂ\¼Ò¿š†ƒsa°[ÞȟIJ¶1—^þ‹—ö.í÷=–ÉÖÓ5-õ3ö~gѽ­C“ê¥ô¼ëÿ-¥¹õ»Œaz[‡ö ±Y¥;“á•Çi€ŠM?ŽÃóq0¸Á«ñ°¨”áx¼ œ9控^v~á¸ñü2Ëê:“,üA'µ91ÓðÑÛzø“ži¨º¥éO7wü8õ‚é¶yEs®Ó€ƒðmÛ…-Ü+{B ÅOV*ÁÖg5Ã+ýØ.±ÊŠš-!¸~€ÅûdŒèl†!Î"‰´Š’7Æ2l³FÛA?â¬æ 0æÐ|Âå$|Oj-þHct7¤ðfþOk~³:BzÒÛüAþŠ˜² ^§tMn­‚-¯Ô­">üÙp¶…ýøÙùlË“H!O4wþýÀ‚|)ÝEØö¬T™´Þçö5c“dLÆ⸲3ö¨r„Ô…åŽ÷¾œ7.ÁÌ?ÿÑÍÇ=h÷ v9ÿÜ{|rò zO¢1†7g2…Áå'!dÉ ã|fuq BØæñKÙQó‚V-"žá/Á5~tËÒ¡>Tj±Wys[«Ö%Í*YFô:[x”tvc+'þÎ3ÔyÓ½[ÌÓ–; ˆ˜†é0|΋iަ“™ IrK>¸¬¶¿KËIoÈY“ð9§d}¶å~õIæ? †ÑøÈ'wÿÏò›H‹Ê\F¨2ô‰=rÈàbdcÞCÐGx¾9Þ¹ˆÃC F%ÊA8“e}³„LA ˆ®—>ñ'ŠÁ´Ê> [ˆ:šhÊRµò¢°؆Jº©ZòÀ’<?0‰xÈè¨ hÅå›ë£!ùIä÷KÚôŒ‡Ïa.ZÛŽLBäB™äÁ¼ºã¼³ÉÃb‹+‚(ã(ÿ%7³î9f-9µ )ÅÖ£Šý› DÆ>ËÚÿ¾ Ð"ùOì þO«Ùê4?òÿñÙÊ0ü  õ  vЎΜÀ*©7è z5`l9`srœñ*GÇÇ5ïh÷kÆØ™)U{µ^úˆ ôa>Ë­ÿ yTÞ4 pñú_o­¯7(þosc½ ÿƒõÀëÿC|ríÿõ³Ìת·Xð£ÀÍ ¯Õì6ÛÝõ{Å0@ä˜ëÀÄZekyöDüÝRW”|_7B¶c å\œEv˜„®Í•ìÊZ¬ðZŠ3=>yroÁŽÍ¦°³bÄnlcÙv6ëeŠ8Ú)ÏpÆpÞhÆÎÞ„¸ì1x‡í' ÷™Ü´‡^â⌠þ)Ðp¥|¼w°÷èÄ ëŸ×¼³:C—î{gô ¡$EOèË×GOŸ¤ ½ÐÛ?<Ü;òþÂÓýÃôEwæ==„*ð¾î!‰ŸíBú¯¾ƒÇú’ÀÛÝ;~Tƒ'!$ÀïeG7ÞKQ…Ùex3=¯4«ŽÇAÞ¸£ÿL]ߟ@ñz¼Ñ@dbøä©3ð*ÊyýÏ.#4ÏÇâ®?Œm[êð·ði¤'Fÿ¾S“gÒ¢Ò))–Jnðk:¨ÛG­Òh»–Öòµ´°SƧ;KØjWMJ~È^½Ê æ6HJ>—E#t·˜6…dã/ÐRÞs“_*Óå<[VÒJtJ±‚é÷–Yßq0ëÑ:ª8!9H•µM/$¶3­J9oi ïäªå÷è”?ye gØüØ?c\ŽZ!èQe†ñ›y€ýAß'l¬¡wù5é! †Û:6£œ“¬3Ô¯ÉV>Ïc¿|¼w´ç1C@Ÿc¦ þ†¦yCŠ3Ü/´«5‡È7àªFßq¸Dòx|íi•C¹tmúÁØ„£mxV‘(èÆüBóNã’ß$ jú-œ"—AèÎ,$šù± ³XnÓ_£`Rì 2>ys9N:?gƒ; ½2€±êÑAe—`*ý[c*Úáâ&ŒåÆòŠãæñÖë{{_Ÿ¤å%Ö€ÜÒ'q䡈%ÙÉsÅæs}Íçƒ[Ìín,µ]9è(g« a&ènÞñ_<à‘Lrø7C³Œy¬Ù!xôñ+½àw$e¢ç/þäc½6Z›úÊc†é4žÊ4ˆQëûNÓ5—’Ôà¤!!n./P‰Ì„‚”ƒS¨{Ö¿èñî]‘2œØKô¤g-tÈÄe«‰Ø¯ËÌë“ÊÂùæÌ íÍS']XçIÃŪi$Sñ®%?KP.À*V·!‰Õ%,×D¼(—*='atSÝøÒÉš(ÈT²ÔT˜0ä3-יܨDi\6™ÚÏPcK(zߣSâCà 7®î|Äüßkæf Þ–Œ‰”vø"ÅO8¹b¨ääÖÇk[“Ë£ 'ý%™/âŽd¡œ±¶IôñÜbï)7.ù·ŒZ}Õ“ 6”o‚Ó w$g°nÓk ²3ƒ1 ueAžcVha  Lf„W8$<.?Y™]ÏX4LäÆ˜çEf̯´¤OöƲ”ÝnºÎt&1Á|œ*…l•ŽÃ…JÞé<ÄP[ü…æš^;™’¨5Ëyý-LB^³é¼Çóºƒê„ïb}ÙT0ä=ñ ¬»©¢äñütÎäF*k»ZjNYó^ !?ã‚Ë{/Ãï4ÙÖ$™U'–É®ÓÚpÄ»Eyí,ö‘ÓØ¿SSV2µˆVò¶™•A4 *š®ƒ+MÄ0”w¦,§úÙ4´ m"J_ö‚sëJl5é^-X’*dº‘™%«ä&aOK*¢lõ5K¢àí>W¤È—^ÓBɱ"Q°h±s¸k Yòà yŽÃé’\ÁÈR]¶ÄÅÃYሖ𠋑‚ ê¨PÌ[V£$å 'la—ìŠT¿XFqªJFš¥ô2 Rß²ã¯L?Ó&ÍîY®=¥&§Ñ;ÎË„xÕ=2‰4j«uÖCÄn@[7æáÊ 'C³ÆØòYí' èV˜™½0c ¿„ÖÛË f¹ÿ:°¼âË ˜6,ÙÞ ¾>VÄ|eÀ cŠù›ÌÈßVXCð3K)`D–O—‘YÔÜ¢‚é4šªB¡ÛßEsÒI yº ôØð¿U‚¦±:Wˆ¶”1¶ñû!…lzÅ„`¦æbîÁðâÔw‚MáÌ‹31ÛF^¤'3´Ú,ZÃ,wYžì-l¨"•^â~»[¡Ñ&dHùÒ=eSdßÔþB³2«_nI5+¹ðmÞ93»»¿qv¬hë€F¦\e«ŠTÌvÙArÃK‹ÊÄ5Ù'?‰hœŒušÙdµ5-‘؆œ^îP•æÈÚÀ/$–ôTpLçò“%fx±òøÙŠn…Lvýû¡éOi§V!ÞéAôꨫyëõŒ6©ݲÓ\«O˜1£C¢²³;Æž¹|Ñm=¦•ŒÀFfDE»g¨晑Ì":ð¤ ÉÙŒiçã#ƒ,…&Á±÷ÞıÊn™2US 6–ˆ|>+'«‘¦œÄÒ„r-¬'Šûv}ʯ©d¹Ž¬ñëxÍ”RRÇ‚¢ÆePïÌï­4œ¯òw#ëØ¡µßUTý˜Emç31ÎíJù®Á0D†“àbSÆ:„áš‚øQÁª*U4€MV]ÍÒUìDÈN”fGÈvÅ~ W.Y9ÝåÔ¼ÑÚ`í;hØãnX¶€»Y—u0Î8 ;Z_ߺ»Ê¢§ËèSg¯aêÄU³ k&»sƒEùSÂì¢ûV¶Ìžgƒ-cs £räµérF_ ákâOШyOv~U± Tªx±Dà )ñSÝ-¼N:“û!¾'úæèéóg¨Æ_®EFíO­à{"É#—DÉ÷ê¬.¶ ‹n=ÖÖ8`ŒmÕm€šT àªÎ=ÛºH£5¯m_²¨âÔ õ¦þ$[sÓ'±Æ›#‰ø/´¾[`o¤ *ˆÅÁf˜\«ÅÝȺEÉ¢2eqE9§´ÖScB-œPQp€‰ +/g°rÇÐB1ó"mt²Ãn›%JžhÇw{°OBÞd£¢ ÇË?}ö䀑B\Àu…²EœÅbˆ7b/&ÿb“RæÙëù}éôße‡Îe¶æ>…­]ÀXŠ”€ ærs&QÈ{Þ‰;ŸÕ0=×–@=]Ξ ï~×5ýw²(‘_ÄÚœ½ø§ËÞL7²YÜB ä]9–ž´Pv;LJ¹láöÑñ±×¨ßo‰GØ™}§ÍÜ8c‰f¦€[Mã4›ÂCvvy´iU•U%Úƒ ?Αï™Y/&ÖþL¹‰Ï¹µ(YÀÒœëàWÀmÃÒßIújâ78 ~Êæ@öÊ-0ý‘þ¦váplã²p™S÷j’7æ¼3"šÖ`:rŒ6Išš‰“‘5îjjÝÞØ¼_Óò¥èz]:ÞI,±E]Óòˆ‹xáØÂ¼-â8j½+Y6Á°²´¿Èk´Mƒ«àÅòïøUDàQàÜóþ@ ±˜’z\C®áá/i“ì£ÞÍ”½šÅ¥:ìØŒZ*s† ¬”±Úfõäjt=`ÕCt&ƒJÐó‹7£á–‡˜Cåá|v¶zO‰?JÄ ËF3f ™> ZQ ¡| ¨”8©k7d¥eèpÏV%fså¸ÏRž ö -â'Иq4züKY›»*(•…4Ú’íÓ‡^FZçâC%• ±Ú³v\KÓÆ…¦Í«—K[:< Xƒh«ZB¯ZŒåúý¸”¾ôð2‚Kk7éO¡ÌW[.Qè Ü-.¨\Î,C$ æºVíÀ¤`­¤::1#«—»–Ằ4«ïµŒºµfj2?ÝE )ÞIÓ55Çд6 §›¶úMM¶L{`š¢FTRšB£úriŽ×õç"Ý ÿ4ކó™e!Öµ3jža`ÝŸUÛ¶ž×ChGÚ„Ùô—/ ÕO —œaÞ¬=- ‹*^¢–jò0Tzð%ð O|=~_jÖß—¼`Ü0ì'< .ò}éK5Û-A´ô`Šªv·…y3ÒYsxÓx +n_¬Z¦5š5g¬DþN]³Àb…z¹QðFèÓe9‚-gÒ _ÃÑê0¸dZR´Ón0}j ®aŠÖÇ‚§IbªøléÙ"aXAªÝßuløuUN!…7‘¿Zè³€: º vöœä­q¡R C¸X¯©UtBb ð MTêž-ofœµÑ°QѺ¢]~£3œz¸‰Â?€L´P("-“’ŠrD!­~ºèF’ Ï$n%ôxÉ&×òÅ•ÛbPØ2's3“C•`+3^”ÐlØÖBß -±‡± À¹³ÊÅó‰€(cñç#µ—rNç}V‹×rš\zp ®Ô‹EšÓ&ø»@ƒc Fž(y00ϧÃl ¾b?`¨ÖTSÞ¦z`7Ô}ƒã¶˜i/¼íÍÚÉ»öµßèú×Ѻ_lç\9¦îê0„iöý­ cß³àŽk™é•1GÎE­ºPÍn EŒ½!ý?(ù*·ð”ÃĪ{`ØÁ‡ç8¸Á=ð-ÞÓ+ã9¹WÚäe®åSÄ3¹ox¯éœkf˜;-D¾Es1#鵦¢e‘•1å2392f¢„.¡¬5nßL~K·QŸòÊÓsèSëdáøoçqÿðÒÓ§jz“ؾl)°&É>Ê/5y'ó¢3\UÇ-— é$k²â-tO…e‘øsŠ“âXbУKЭk¡!FVÍc hn‰Ëú-Õ³a%ÿ5ZC`Ñkb´fŸ—Õ*û¡ñYÞ÷g9ü~{Ó: ñøµ¹NñÛëN»Õ@ü¯ÆæGüŸñÉÅÿá!'ðŸö&Æÿ]×ñ›ëˆþÓÞè63ãÿÚà?d5¯6K‚€U]  œ´ÁpR€–Þ¯LüÙc0¿ÐJZ|¡X«!™`6 ÐV«%­‹ôQž¸(F!"L¢Ë`z6±~•Â1©>㦠$6¥³!ßÑ1r†/ â MR‘iV‰6«†8«è”¯Tn#(Æó5p¥ßŸF1_ ^§u8-Gó2ÆH4lLìU ÆðŠÃ/°üÓat›õd~ ‚ô…8ÍâvÏ(~’8å$Šg¤ñ=þãÒ6UÑ5ûùà žï~Íϱ…æ5*m#íðmÝÚà¦Ê"úb6›t×ÖúWÐøúп¬ÃÙöA=Ìâõ”P‰“XBý²˜rkP5§ÁÊR‰ða0Æ!`j:$—Q“®uÚÎqTM¯¯iŒÅ6߉¸F´Ñ!kx0dÔ !iö©œPRÞ×2wÂ#µã£XþF¢ÂÁÒ¢Iد˜È™¡þMáJXôÖXÚaË­ë씕ODPjž‚ü“FÏÛi`Š …elÍ ᬴í5¿ÒdÃ`&Šªö``ªt;ÒP%Na>ßâ#5iÓ(dÐÙ ÄåŒ& KM‚ Ò Y²1çmŠ`_W)Ei›þ@Ódx¨‡Âd“5 8ý X¼«ÈxˆU°ú 5…¥Õ%6¦XJ.§ÐÉÙÜDÎÂs‚Ý2uÏ—¶ñ_Géûc5~Ee‡Èî~3§¼0•Vw+:‚ è+{eZ SÂp¯3Êó%+­²£ã1'¼ä¨ßþ¡ã=¸¾-/$©Nô!Îp‚¢¶äõÎâ“FÁYxšXZ ¸6«ù‘°õ)4ŒDT? &’w¦ÅËRÒb^KE±‡¶dD¯Yó:?M‘RoxËK›I?¨óÇBÚ;Áqì̦;ŽI¥¾”'Ê„~qåøJZRµG=Õ¾zK\ì±fE;ü>DµÇkhÑ »Rf‹±²ƒTI†¶;B#­:qQÂ1ù£eÝјxs 6M-"Ûq$?z¾‡(œ-!gÞ0@ÔF´ZѤÆ+4©Às‡wvœ<›Ä§¸ÆA3ø¾=Ù FÅ=×»Ö ®LZâ@ÔØÁ©DjHc6=zúüð¤òyµ±)3ž3¾“`:*_~Ÿ¶ËÈYH5/«3K´m&¹˜èÚêÚeQ#kŸc¯~ ¶|¢%ö”ÿX0ô'1c äîSe‹sÝêʼnŸ¼/t#00»P9>õâ§}ê]<áRoU$EVl@Ç…4$à CÄo4àƒX¯©èÌb GÔ5ÆÍŽ®²(Ï¥!WF¡¼²rÎÙð,´5Â@^Щôd±± UÜ)*?.æq)0³,`üÜB‘ÚCÄШ½W«)Ì–—/ÊhÁ«ã>UŠ©Æ¶NÌöqL¡§¸¨|Å 4IE@Ò45’³w J¡ošM*zqïÏ,¿ÁMø4!E’4!M5!U’5ïS JÓc7ìMÁÌÂ(lRÉ€>¶»s²—3Ž÷ÔP¢Lz:!'ÖcÈ­¼ÆìÊoO¤ÌêÏ®S}¡IùqcBko@Ìa“—-‘h=09œ®€£Ön²Ê\7Ã5ã9Õ—F °ùß–›5/ñZ¿ ¡/@c —[~RãÓÍò=ò\Ñ.þø‹€2À§³±Ñý¿„:.’©+·,ä*õRÕ©ø­õ]äãž22×c3ÈÔÜñ_Ä߯=òB¬-9ÂzÆL¸Xr±úèÇÚg&Dªõè6&U!qbnéyqÝùå¾È ‘ŒŸk‡:Öšl fËF: Ó,_ÖÖ8B­x%’èÏ“5´£¶s‹áx_D—uk›êG󱆒öИ:Käµb®dÁõHîº5xYÌß žÂ#oêR3=7;³}Ú X_%ΠÅJAà q³Ø¦ôT¹×UL¤=¨NøÃµœ•PdÐk­B5Ëég.©G<'¨3u“ 5¼Ÿr,z”a ª?ôì$[š¾n~c>Ò­´PÜ`áš|öš'¡ƒ^Ⱦԧóñ`(Þ”âD‰>ÁXªýñ—,‹¢õ½õ*²Ç:¨˜Ì tä>žƒüo§ºäTSXMβ–ŒL8Žƒ)üT’Ä7§c!%'-+l‹EM34~§=ªG^Ô¸›»sœnÝ–dRúŸ¿s´ÆJossfGbðæ¶™\zR9¼ §Ôdy‰Ï>j1TŽ¿F‚XSŽþ3V^luwf-ä¹Ò¹Ý>{P³Ú*ÚâÅRÈQÍéÉå¦ Ìß•f1ãd•?Ñ lJÿ’"¬'nïrÖ½;DÙbMÊ)3NrÖ¹#‹è7—,a©Ä⩉þ[²·Œ$ú[œµ.ž?vW@¶ Gré×3bOÕ®yqéËNÊeÊZžÖ×Üå„»¼¯ý‡fo[j²æ¯»¼-†I­¶Bš“…"ûKbÏ!°¸ì=#Çvà>(ì?9ËÒŒÂÍ÷U›bÞ‚ÝL]G—µÂ7›Óelÿ'jƒÐ<šâÚÖèO2¬“{—ÁpXÏBÍU²µ ¾k2‘ l4…©àÀ©§× ,Ó‚ýœðÀ•-´fûHã†X5Û6{—pø+ËiÝÏܱñÙvìþ0€c]Á&;' 3÷¶9–h/ÙëBJ/bâÉ9ê2ð÷þ)ÎóÙm’"KJên‘nÒ‚™Nb|MKCø"CHÕ–ŸÚRÉÓ¼KN‘&T5Ï‘lA)ÌmŒÅœëÝG0¹WѼÁÓSÏíö«'ÞÁ± B»©˜ÍˆÞ7C47L½ã˜+þl>SØ£çÃèÔò˜áòäÜð Ȧ†*Ãô“BPë† |ßAŠÛ²óÍž(ùÉÉÞ¯NöŸ=?qž>zzx²wè>;~þäÉÎÑwnîoö÷é¾:Ù?9p<ýæ©ó`ÿðë§ Gº…k­XŽ¥„’\»:ñC•ïS˜@û'{OÜ›†œRßÚíÚ?ü…S¤Z|f^”öD N?&]¾ ©c<¿§8¶nCV 5S ?/_psÅÕ®èñÑÞ×JÕaóáÔņ§'Âu‹z›Kqló¢qbøÅC¯™;r0›ôÜq â–(‰¡ý™[HíïeaãAbYº+QÒÝÖR³œ¦TþjÌ[?F²ôâ¡©¹›·tLÉ ÿiŽø¤Ññ§Kt™ÖT¼OX£ÄÐÅbLq*‰9 oÓÛÚdcË?)51„ÎÜ·WªU,MÈmŽ·²R¾À/Im‰½ÊœÔt±X¦'½[P-&Y¶¾㳈~Ý/×å\ãNïÜŠuºBrëTKÐÀÝÑò+VéŠ+V©–¨x‰mÓ°r«!x·t´ÿìdÿéaª1šñÛ‰–™x†‘$ØD6×Ò§¤x~ºªØ©g®î=Ž.xª$o4g¸Éè|þ60¥„3ÂÅ ÁŽS!œ€{ó‰Âç¤uK¨§û 6ù4ËZ(ŠTéyê°7¶Òóù–Õ(ÍÛ:ÒÈa¹øPcÌåpF|¿C´UæqHZÄØŠÆø¾9º ªW仫ùÒ¦/Ê(›£ä#Iþ¢¼¶zƒÕ'>pOƒ:¯2؇y¡DûœÒTÜ”ÕãpÜg½¾ ¯²[óÞï; RßÍ©Ã.±^ö¾yrRÖRôÿ(€“H<Ó ëÈÇÄûëM9•j¥RbHÓªŠ˜*RÁã““g0\ñ$ÇHÙÚÇšM„«XÝÆÎNÒn¬«º¤É‰9"e° fÆ‘ˆjÈ;iÕNá @ksTZö`”ÍRÚ¦^]q–( Á >DhÖÅ'á´—8™ÑyòZâ¹à×>?: H+ç.k•aÝ…"ìö&ìê,MU“Úo¨Y¦0лÁ0<åut¢ŽÕMÇZF×îfËùµiñǯ)Œ³¯1E"ƒ±w[ÇѤ¹VPôÁä*Þ¹³'[Gd9¨¨,z9øñL/(\_Âiºëųé,¢‰³8‹eWB³?@„V~ ÅÖu"£ÓRïQ•õ*¸ÊVeÙ,Ñåú4)õ–}:Ék‹CØ ¯Â¡>«YÍád‹#‚Ó²Mqt4”U[Ή¼Y›ý‚7û— Kèæa4 hÛŒ/¢ùp€ëˆ†ˆ*QæETª­h8×1;ÁT^FÓW1G¥F}àø”u!ðj\žQ~/oHeó‰žù´Èæã!2»gŸ©@\Þ¶×IŒ k³cr&¨‚¡§úCØ–HN¯KÛÂѹOû9¹…r˜Î×éèV :Rµm,-Ûæ¾¥Êª&”pb WD7•·ÒöNx{ü¤ Xay ¶ìI,€1ZpÒ’ 4ûÍÞ)j…6η\U¿þ¥”oôÃâ-™÷qΩ· „¡–'‰Z'´€uWæò3±Ùôz„ú^Ñ»CW ©ègÔÁ=X ;_ÞVb6Á[ÙÍÀ.ÚsowÃͳÎRó/˜N£)¢ÓCÑœv„J-/µß%äꂊdlÔ¬q W ÚžN£WÁfâœöêÒ]jZi‰îâvM‰ù-Z¡¸W®'º Sñ—;'ï>ý¦÷Ë£ÃýÃoKDKµý4èûÈ|£3 û>{¡´òV”,8Z¿l?¢ð½kñˆ‘Š¡xƒ®aûöŸz÷6Í:1ob48îpæÀ’ÔÁ"öÍ D;G!Š.>øÓ—†Ì>9Z;|z²‡¡dÕ€x;å: ÏÃ1mZDÚ'þù$ –¥"ÅŽèÉ4Žël ùσú8˜­U“§*¬®²‹ ô _ñ%ÛÕ$Â…R]HžÝ“¯©Ûé@«;–å/là´@:òÐ9›cÐö~ƒ÷@ž¢`¬(±]¶ûƒÙYE·Ð˜ƒL ao„K¦R^«|?øÝúÛê*þm™¿'ò·++êKõËÊ—ÝÊ‹Õ/^VU’/åËï+¯×Ê5Cd£X‘#ØŽü ¸"qØ1ÙÛ ü+<Õ­Q_6 Çs‚\‰<ÆU}äÂ^4_ªr_´Ì×¶ùºn¾vÌ× ëº„¾L"Ä.GCEÁF§9 ’À|„£‡6> rB<ô^±ŒšÛØT·°¯Uc¨ºÐxI·„zMlÐ!#þí|8§‰ë敯ë׿÷¿íÁ¦„:Äßö°ü š¢Ð=Óëûæ+Tjs×ßÓˆœ;qõêh^Ö)àSU‘#ãË3¼K²x‰ÚäæGYYV¢³3ä|@><èW*ºüϽFÕûÂôXÍz!©~‹¤>Ê4Èb€d_zØ¡1òÙÔï#çÁl]"’4Ë_¸Še»5Ÿ?ôV›©öò\øâ¡“Ö65Q&³”бøýžÖr67x´9ˆgÄÂfq¶RÅ3©Ù–ØnAñÃL(Í«Y™öƒš×ÌõÅÍ>BþlÅ>;¦®cK ³ï Q2ã.‚M” &.ã)rh ͤO!(ÌÇd øÍÁÓ¯€Ô/Ê¢ $QO?$#nç ë”,½£}ÒR¹ýL*­§Üæ‰ÞÕ{åÍhÈô˜]yÖ#ðù@´ÝX8¾ÃY¦®"xSœV¬‚3÷·œý.‹Ý‰*c&ÃR`ÅËW‚©Ë&Dâ§:½›U½©·[ØüqBæÁ™IQYîâ¿×–€°Íô«Çûx =?D¹ÈîFŽ/SM:7&–ÍNƒ‡0IæÊ‘ß“$øÓ  fãJ…Â(ЇZËäl¸uª÷KÔW£Z€—³8£.X j â¨Äê©8¾zh«UÓèøëŽ\ÀKJW÷öÇz%cðŽnG'å=«"h·ËŒjMê)>Ò“ö)Õòýqˆ’bø[k/¦ÜÊ@uEÏ+þ|vA¨÷½r>§ã°RXz&jê™ÈYE¡0H1Ã[áH¨RzÍ)¼Æe«3lRÙ5c†›¬±H±E tZouMGA _›šÊ±rxû(‹ý.æãAMír>òÖZàS.VÑêmâC¤03Ø{/£) "æO¯HÒ¶*&ž CL5²=Æ\¡ â´u2C•fÆÔIaK(0¤‹rTY’lc3ôûH÷\©^}ñÇß_nýìeýó/WP8/}ÿ}³³w ;5ŠéóÙÙ½Ìòk@>׊ÖQRé:ËåEc“â'>¢‡³z£fºý>¿*5³0rGsR«u!¾\è7Ï÷wY9æ<ðºÔÕ‘™Äm‰Ù<Ë÷äþyÅ,B¹UõPQŽã™ˆ¡¾gQ_æõ]Šëî>zº»·ë’!cL UR9SJצ®EçX¢t}µ}Ý>˜ÒÝOØ×k*óˆb„iYJ¸Åë3ª…!0âu¬ŠrÙiêìÞ šñÒ#˜ÑãèR&µfi²e>{þj>QXÙ}Ô5_OöŽžw÷ŸÃXXOíAçÑ“§»û_ïó3“ÁJh'€úöóÖº¢-Œ°VCèÔpouog¤wÖûB• ÇŠÑL<´¯i°´ê­⩨ÓéÔ›õFͤ’=õ†ïUß{¬»ŽtðeÑÞúžÚd;;¥å@¼ÈÞ© …ýíG±…ëR”«î/ûànÇ„‡aT&a?—0Ä·2m¬¡úkPÀDjº¾.2žz6¨·ƒ;ù(‘Ç‘:Œ«+N : ¦1YûSètG-áã#>\å~”i–ÓctH~h¹#ÃË‹™D†Eé_‚³C¯¶`>†íZ\Ár…²œÈ°ÒJDvI”c:Jm Ó;Ztn§¬>é=¤½z Í=¿—`r/Þ,°cÿ,^A‚1ž q.+¼*…(Úzz/¡ë‹ß‰Õ¯©3²ðÎ[3ê­ÊT°‘PÊÞ˜°öŽô%õ¶ÆtKR)¯}ñû¿ßÆ[‡Ü#¬ô®‡Ú›ùç$z=ð·½§øßþ ðŸ!þ3Û¦pëÞƒþâ?>ŸÀñlÏáËÿnãZmÖ¼gG{ßôŽŸìŸôŸööž<;ùÎõš~ aR/Abh ÐÓÔVƒðlLÐ}’¦èAšÚφó©?\e 4”¬J?§”,ƒ•òáËé}…ëqiNEÁ|Â%P¬é)¡Ï®€Ñ¿?ùøùàž@k¼ÄN$ZýÕÉ^ŸM†õÉÅäu4à³±¾NëM÷o£ÑjÁ÷fcc³Õ„ÿÚŸ4àAsã¯ñÞzm}æh€âyŸ\^^¢Q¦Ÿ—nÑûŸèçÁ—0–w`÷YÙt½â!¯½öšõ&úïl®5î¯5Û^ã^·Ñê¶ïyç |x{o&ÞŠfW?§s\q‰˜n—m¤Yz –…Z»pê˜6 t–¤ÜêfÜ>¹X[KLªKÙ¥üSTm2‚¸à€aˆ1Z£\ÆLÃe’X_9ö_RóJò­ÞFN`TÁ¢m–T v^ûá·cÑÅç«Þ 'î¡Óõ¾&‰´Ï¶.¯ØŠÍô­îQÃñùHˆçÌ Y ¤óæe»l‰ºÞ>‰bhfUÑnë€ß…A0*§¥rƒ”Ñ%7i}FJ:ø‹_E=Y=ºïñÏ­— 7(× rµšÓRlD~ïÁ,˜°û`¥Zô¶—<]r›(ÓÚ/·ïØ2¥5#KÛ°uÑb€ Ât³mËû2÷5y‹Êûdщ©üì"¬Tª ³J²«’@¼°Ki†£ ;)”ñ`„%fÕŠ.ƒ²´]ðÅÂâæ°SaA“8Û,»B{’¸½—??4ƒüÿ,µÿcÀw¨cÁþß\o­ãþßÚh¯·[í6ìÿÍfsýãþÿ!>kŸ'w~lÚé[²ÓwÖZ›^s³ÛÙì®oZ;=2Ô;ŸYú®ºÅOå_zà±`äOÏÃñê,štÑTòí¢œ¬T@ßF+÷i4›E#( ¾Ù FË”‚û,p6ŒüY×›bX¹-z}pr„ð”Z§ë vtV™¤ÈhG³žÛ :a§º¯;À†ãÙjþ6À‚Ú…4LÎyy ®²©TÜ:KYþ;·9úýtÎÙ€’½¦³vêUžƒèÀµ¥×MHC¿Ë øºOü>Ô2Ž.§þ$ÕÀd¾:*gäk²«9Ó)YÄE;sô â‘*ê‡^“ò³Üù4O×?øÉgÑù¯ÓÚLœÿZ­üÿC|rÏö¿ãÁÏ.j™ßÙÒŠ|,µåö½ †\âTFǃä9&b¯K dZìtâé]ï„X»uuRÚ§¤K…Ëp²EÅA_{{š›v C*«Öܦz[ÔÔŸØ©u¹ý?ž@Jºº¡°ðüg¾„þ·Ýi|Üÿ?Ä'wÿÏòw”²Š¼ŽØWSWàb­à=KíùjWNnø…{}*)]wÎé¥l±vš,1 h/—úXJšX )QYM®ÛÙceH’{í»o˜înÃ@E©¢:•ý¥`㬹Åé½ðÆ N§­NýfÛù¡—æù,§ÿÓÌoTG1ÿo·[Î'Í&<ÂO»ƒç¿ææGþÿA>yüß 91ýÍz‹ÿ½µÆúZ«ãµšÝf³ÛÙÌeülñhxÓíM€iëÀÆ“­;T!O‚ñ\çÚR¾8™UEŸòn¡Ž~ÙV"”¸½¦64±Ü$ã—¶éÅîõjÏ4f!2(°ìöY­*ŠÔ\ÿ¼&±Ý)VbÕÛ9[ÙËÆ³ÅÏêg°ÿ~sôôù3 õ\'£å³º˜-ŸÕ) ÊY]B9«Ëí ~e«æ³ºcÏ|Vg¤²³º*;«‹ ×YCǘàÒunÛ5bƒcš1èN§U5Še¶©Â—œƒaã´—pdr¶Ïæ&ôñŹLžoì'b9Fèb8ötð`Çl qï`£°v¹*ž-ìða¹™\3J6•ð„R:Ñ]k^)ã&Ú„D-AËæ7üN KrpjžJ©îd¿Ä>ÿœ\$ýóȘØÑ#êµT›+ŒT¥Ü’Ðį‹…V \Í«ë.Õ5 ÎfiNe‰¾P•ªX«â›”QûgLc·K´×ä4jo‚ä°‚…&èKÙ9†¡^~1œ2« íܸ° N锡íc-“@±ÂœJFá­ñœ’U•Ï\úu2%ï«Ïñ=ûÂhü8ÑKÞ~³I‡‘Å@±VbÃj¾ã6ÃŽ;œæ u‡9~k‡xS &gÉpƒMg­È»€Ôr9 .Þ–Mtýù,BÀ[Vv¢Ò` ½=E¢·"³«ƒÉÁ»sÇà—°[}f:­Aè’éÜëÌvU–ò%öõÊßåL ¤BŠRQ7Óå\„ƒA0N”“ÝÔ’œ°H[núV¤™LÁ„…'jmŒPôq+MZ>¢ºjž-ÜXNòæá‹2O“òËåhÂû¾!¶‰º7¦8²¸O„±GÕX€.ô›Ý˜²‹ìtñ¨RŽcœVÁýU(UM1j¬ ãV`}á˜kôž Œ9à–òez«1&{,$gÛ"œö·7#'t† ‘ßúª _‚í8ãÙ¶AÃçЪµðÚ”lf¹n0æÌCžc1m‹}a+6f†½4ˆùUæ¾À{l+`ûÌf¿óÂÁ,ìT>þÌ»÷1¿‹ïØ'§Õ×Ôÿðpdz)Eé& õOq³ª¸ì,HªôÒP$,ŽfÊ(±¼»ôÝNá¼vÅÁÖãÔ2‘Àà nhM{Ì[4ïÓüo ûJŠÆB/ì§fÒK‚;'OÍ–ë,$¿ñ Ï ô«¢!-Í®é:‹"©¨H÷$F l¼7}tV]‚µË‘ö»ÞåÔŽ©ñ" §€Fz0XÉ|ñIÏî³x) ‰âB‡ð̼:(×5˜èÂäÉÈ× ¡qy…]ø1GÐÿ‰w[Fiz^iT9Š*ž\´p»$3Š‘r®ÒÇ þÂGrÑ&ÁÕ‘ÖUcĆ‚(®;cÈÃiþÚÐ\¡e’ÚA»î .SòOz°G:~‰á „¦›Ì{ ”úðéÉþ£=Ñc²ª·–O%-Œ_otoÜP+Iþ]$ß ¤Ø–[Ô¬wÖi P¯ÔY‹ÿà òúU4÷HpÇ/—>;ñO“àq„þ=s¨ùe6ù'.¨Zr‡O7å7pŸ Ú÷Ç‚å4€mc!h¸iò‘{;£?B•ʰ\eňÙS(xÔ+ÆZ(ÚTX.Ükßwf@PyE˜9©‰³p3w"`b¶ÜÝ/”¸}6T¶©™¸¾WÁ9c!hc_¨‚ã÷KÓ%Bƒ*ªRBµõÌ!Ф~rÍ¢J÷É¿ãx¤TIó‚ø*¶Qñ²¯68²3ònfþWÁU©•µ‹ŒØ-ÆVJw_äÝ7´k^¯à?øÛ¢‹äÁ)„†÷ZxÁ—E××¼§€|÷Ú÷(‹ÂžÌ½¹%M!æ‡ÑÞÜIòVKŸT¸íp9 ™Bå`+>C_+JrÔîIuÜ‚R’¯ ßñÈ£k5F°}fC_{Ô2ë+t­à1ª”°1^åÓ†‚ÊC¥ ¦y<³.Â|Û¥ÙS¯*&ž9x¶icáÀ©[…ä¨1`J|]¢#Šºh¤­ÀR#£BuÈ Ëm!ÌtšŽf•/qó)H*\* *l¶Þ¾´Ò[ªå–× iȸ­7 Ýn÷ý©j‘-º–Y=6E¥›ÜÕè2󅸡¡gÀ­ùßÞ ºá!ˆ ‡iêÂ(N“6–àBÈÞ3‰¯3B©ÆÔœ‹ˆjÖ›ÂJ&­r2ê9&/GФp2 <]Uµˆ5áÈc—¬+/»·—áúb­’)åzÄõ!gBXß‹G( Žõ²3œ@bˆR»‰i~â´O­&*@ßKu@¢ÉP.‡œ…óa UÄnË“sAæþOó¥@ä(0«Ðð¼) ÃðÚfz^,ajaæÐRæ*y±ÉEÂÀ"9Aèa?ÃÐâÇa‚°±¾ôŹךÛ`˜–~v{-˜%Zí‚Ã&šr›rý÷{!׿х\ÿ¸K¯¤Û¾”Ë¿€ZNÚOÞ?ܲ§nk ‘y3¯jðú©ÿî×OÒêü¦÷Ú‹…ív[æ˜äß|:×;ºýrÅ£ßðšG[\CG½ìÕ‡nÛ{¼þHn3pW zc|‡kþû»ÑclfbÑuÈM¦ÛOJËn÷æßŠôoõVäQz2î0\Ê/}CR4¾ËÖòSÇ[»0É©Ô}ÄuVÈû¼<)øwj´¹Hù¡åþ?IÿOœÝ×n±ôòÜìtòüÿñóI³Ùì4ÛmDø¤ŠßÆ'^çÛûù3îÿ™;þêK=ŸEïVÇü‡F§ÕvÇ¿>â?}Ï;þ:£M¿ëó°±Ö¸ç5:ÝN½}¤ófw_òrxèHÖ;nØ"²5Äcv>‹V¥ ¼žŠ<ŒAîžEt0†¹IÀó fX¤‰ßÅ‘¡VvÕcí¡?¼ƒ‘‰¹šo÷ŽŽ÷ŸÞécЇÞFýÍ;[Þþ˜¯xè€{ÞðT¯GÓsK&ô_j2ªý »÷W­ÕVÇ*¾´Qo6Jw&ÓO|ø€K)Ý!ã~‰ÁTj¶ÚÎýVó^éÎOk—Z¼þßÍ÷? Öÿ.öfcs¾5677ÿs½Óü¸þ?ÄÇõÿOºA½·Öh"/h6ºíNw½}sÏUK¦ßÑÕ¸Îønれ"…%nÄ]Uµ’%3½ºAqꟆC ±íÞ¤—›Æ]~›ô£Cß[ì1Þ®·ñW›~µ:ø}¿Sªgߨoà¯MþÕªSºûR4•Ì?ø¹¼àçüƒs´Õ/®èþ=ù I[&ÓÓq4¾Eóeï½³Ë;ïÏêB)ÌL¼ü`F³j^Cg×·éeú‚["³óèI7£Ðž&V‚1¶mÀpòäö§o…}T¡œ!Óë¶9Üx(È myÁ›~€‘» ßgôÙûêâ‹h8¨»€ô°a"Çš¹ ‚Ú`ŠÄƒW«ÓHµ#Ãþ`üøh܇ÂXÙ÷=̼Æ÷e}íN£Y÷˜†Ä;úãWÚ¥dUj”ð„ŽÖ`ƒˆîè/Ãø‚î’ zÝû.šUÃ1vyæ¼Î§ãÓ4Yz.góæóÙl7W½a8Z-e§±xn[{ªàëOì¬æÁŽ“iàn &¸¿¨±èácœ…ý0÷¯ÌiC¦Ü ã€ðì‡ 5ïÚòðB"½'Ï,A|¬‚7J£i †L‚iëŽÄT©Å5/&8[5ëqšÉ¤Ã:„œ˜öq wÃ…¥ñ¥<›ú ž§x;ƒ÷M(_ Q;<»rYŽ€ Í©TD;¹‚²­&qWNçd› ZMÐi/ù!Z=͇OÝM¨žÓ¸g˜ }¦„&û6u‘€U¾–Ã"9lÉ‹ÑOøk¨ØÏ½ÍȪÞ§Ì—ϤÔõ\–3«”î2wÂht‚R‡^z›º­›DÈ_ûƾÉH•ŒÆÕ6ô^¾ÛÞãºÄã w)ºÉÞ¼ ÉdÃüQKúùSUR/>ÿó›w©£øüßl·;ˆÿºÙntÖÛ­&žÿñß?Ì'çüσN‡ÿ{mÖ6[kÍu¯y¯Û¸×]¿_|úG[ßXI² ÙÒÒ©»`õV-:4Óã¹c´þBî¬Ô> 'nJ²lÁ”ÎR D)»°GÒ¼‹èÒ’FûóYL[«²^̧(ÀÜðÈÇ;..ÑQ}p™ÊOØò'¥?=Ÿ#æ­±4{§ÓâGhÍΫ ƒ©Ö«š±Ð%à€Éù'¥ù)k».eàDôv`(„‚¸-ò"ì<Ö­Ô4ÐrÒWz,®Àpš˜–èsCG«kaJ5”‚¿$£ˆø¹Ìúu¾Î"šl]©-0Ôlz¨"܆ã×Ñ«À¯V•‘í–d‰jÙ„pU÷žÇA¢à*ŠyËÁ1‡óü¿¢qgx–¥øÂÍkÆtKŽBŽ$B0*2 e# ^ãõ/¢(&ûeÉëMÂ> P'O!ʉÊz(¡BÒ.Î×S<¸ ³‹j A*ä­»¨.,'ŽF8ŸFb$†ÛÎaͯܪùѳçÞè"ƵÕL´Ì6ªY‡¿£ÀãyÒOœCû$jHØ´2è°y9¹äà[÷~©N¾v:y[ÃsIhB¯éF0CãE5u}:„ˆÜÌÑ¢¹‚-¢žû–‹_ÎajbüÔöâÛwq²½Â`½ÂhÎ³Š¦ë#`§çr “šÐT®‡ç Z¯Äˆ.ÂYÒQ·ƒ‹¦ÆA“´øp`yè„sÑŸU˔⢀^5ñQÛ´Sa™'yûgf\ðñhÖ›B.‹HqLN<˜Éñ[35¨–ÚwèúG«)’UIQ œ \žªÖt„úŒïçãÞ3Ñaþ’L©Cžúä&ÅÉù­î=…’¦—a,'¯$!¡ÐøU8™à%Gsˆ cÝË3ÙÉM¼j|£v÷yÐËYçùšG‘%‡WR=gM„tm iiëƒ'²5:v6±®Ãº:¨1h$C'/Tµ˜6>%dBVŠ<úw¾Æ6KÏ&ˆÕб)a#$ MB­ÕAfœ…cãc„Å)VûË‹¨{OYm¤â¾ÓnŽ Ê/ÍíÅAçÈëRqõ3ØFƒÏ¯Ôb"jö;””#¹â±f[ó"áí5l¨*èú»çó…M&wÑë9b³ïè@'à‹0-yÿ3i•Ž6¹Kž lŒÍ¢(|gbN¥²‘åÈÓ;‡3Õ,NQ?GßoYëŒ1ÂÚ3T©ÁŸµFVÀ‚ò­|uI”½-¶'fnµ×j›Ê²¸i_ïµM•¤›¦†,_Äc Zh¨VÞÊêÐÏ~¦J‡s®~ì‚Ð|ª‡Ò¶»Ó„ˆ3wªfÕ˜ÀYÍ¿K…UJµgôÜO¹ÉK™å]bÛ!F¦ÑV{yy™Â•û½¸È  äôEbÊW¡&ÿú`ääê–£'¥½]‚Jßߢ¡nB§†E'X‡FÆš£éì"Do«Â@Bæ$á~Ç+„ÿæ·¼'2øo}鹬¦ª…¶+WCZ?–3†±ž7ŽK “bâVu‹FAgÉžÓÜ2C÷¾ß¿Ø Œ+:«1[µ÷&u¸îzw¥(ËðS=!Õšª)ÇM G½†–p³„Tz»2ñg5oŽÆÜ„Šþ…Ç/TÏpJ™¼b¶Ït/ºŠ÷Zðó˜>É8È1¸«øˆ¦tÖnÑîœ?øõ–šCJئt£èø»ÄÕÈ|¼Ä´©Y(È€©Y¨“æÌÃ;–Âb í׬ìÉ=2~mnn–ö{LÞÒ·8ýÙp_ôôhôPç8]gà_Q:rlY–õâ³hB¹àè±tz¤ØuÒýx¦2,dŠ‚V)xµò¯Ö´MÚ ¤ŒŽgžñH¾–;xëÃ1i #-ë»và;ö½Ìè²fãvÚÖ›@£¡Û™^4æ]ª½Ï¦!~ý"¸êzÏ×Awx¢Qó™ñÂFÉb¶[•]³DkÍR/—‹ºñFB{ÃÌaÐéÜM§%:ÈÂy‚ #3ºdì?nÚ)É—î)ñ‹Z¯c‹)&µ5«™¨¡úÁZ¹rxo‰­ ØËVkñȈ›ð†Aø¼iÍÙ,Õ’þCt㈯F§Þó£ý,_Dñ Ýß©ÍÖ½7ð±4 {Ï$\hVÓç &œ”íÏáÔ|>N@G-×h³2EyŽøé•ÞÖ¡}Ëw†÷¤÷Ó>SØ›D ÇÞ(C¹ö5&(´f¨²‚%`[|%»Å[è¯kì³ ÓNk ©K—~œË””µX8 ¦/±…9RF²ë=òæ1ýLT7‘mëUpåX¶©”n AÞÇI@ø¡ÏT?¥ÏrçÆ@|?ñ¿ëÖÚÿBšÍõÍöžÿQ ðñüÿ>¹ç=äÆxs­ÙXk50öwg³ÛiÚÓ¦ãlªq]€³¤õq4z³)ä¦ ™ Ÿƒ N¯‘NPÓ²*JÆyÕ|1#ª32F¿a@b–~ݰ-<ÂFSR‘­F–Yž’?Òe¢TTœ —Ì7¯“´RœÑ‰V«ŒlL„$‹i"XŸ_÷1XŸÕUüA‘w|ÜÉk׬PíŒnÁ·£öñÖïÍ1DåCýeÈ;¿NâäÁþ/ö¼ïË8dkwwï~_Æ{:UqI—!ƒÝo7j°™‘v¢æÑh¯nÃÂoLâ5A–ðT³LŒ¥dÞ\âÊ={AéˆIÓ«L° Nª¼=B'/§þıž5©1Nº”ĶIä\$(8tRY ®i€ÀÅC;\´‚æZã¢}ŸW[ áÒ F“ÙU…cñæ#c‚FöÊõ_Cpðê©Hèë‰Z-Ð(:„Uœ°‰<¶À˜¹w_JØNm"Ó\/«ÙCSIÒ¦¯÷P\ÒV·zgÑ­KÓaÎÆþ…)‡.h dlPôcå¤ÛCÌ¢Tðñž>?<©°…òÎ1q8%[Í72“v¾ý†|J¦ôÐ ëþ< lÍ;~þÄz7‹f ¨PÜ›Ô2þæèéógÞWßQM¥-iV¯O‡·i»ûÇ'û‡¤ÕTY%^ÓKòØÇп$wÃ>¿3_]ÀUw˜P¼7s 2!ÏRYD-(òé»Tf$,lœ¸ røä"6IÇ5hНæ2Í û/\—kR¾Õmž”¹ŒŽ)NÇ¿˜Õ!™îÒ ¤XWÊ€(”™’-Yl²Ã¡²¦˜³ŠØVqR[³{ÍCKœêÈSGšjáÛÞŒwuü9CýÈÚ‘t§]ï³…¦*:ª†û£aÎtáM—âÏ*mEÔ%”Ë|Ë•_[»&_¸©Tçri»¬$%Ó©ÛoÞ%XƳö HÒGñpÄÇÏáaŸÔ¾ý:…ÙzÈ—ëŸåàé/÷Ž*¦Â*«€+xäǯªËéõe·<Ù)jq)_Ö\fW{ôôðÑÎI… ÖMÎÞæn—%eáB®ü›ØDÏD$‘zŒif(ÖÊ©?& 3F!Ñ:Ð/Y”œO)Ÿ$‘ôkS:þs„†5'›E¢>²ëÖo“v¹¼ÜÒ0¤˜)J‘t ¿äº•½û˜RhNWýt,C„–ØÌt#ò÷”ƒÞQj†®?¾ÍE1Çû‹¥&à+¸eö•Vk hNZŒ‚nĘ[à}á­,—Ë1‘ž£±b®{:$“[â‚å»wïÆwï2§Ä7ÐÎp;xÄŒ†S̹°Qi>eÕÊe«šRm Šò&—¦Î9»>ôŽÿ|:LíöÓ¢ ú‰Bë0™g„m±"³ë&?ý1û‹žð½w¼wôíÞÑ‹òã““g½ÇOO(ØSñÆ£†ö&ç•7ëLÀ÷›&]r"•~NRºÙî{êœ1/Á”„Ĭ~hù¾ýãÑpìr¤Rôê#5(c½ÐÚ)rS0Vã°Á…í© “LG²3úÁÏoëî_]ÜáŽ,Wqê†-§oM‡‹öè€ÆŽGB›ÊYŠ4Œ¶+5óÁTOCÿ4ކóY`rUY†ÐI«TŠ\ÙŸLFæ°¤%òÎÂ!L^Ôé¬|­‰>óó ϺÐBIß‚~ W¶A³d<æÆÕú5©¡BæÓÃm£Ý½åkqL]ò*24ÇíÅPûEgÚ]»°WUoÖš]•-h‰£å5Ý7Š^о{ÓêµÂ>¯úl1qà •qa¥ÉKT계UÅög‚µÉÎa³¶å­&Äu6Œã±Ü4¤Ã"®‡e'C6À’ÛÑ•+¬X6ÌðÔ˸©¾7ø  wCÏ: ªacusíE¨Üìäár§—]Á‹b7¡%â‚gUÏ=µÆgyðÂæØp÷ ¸ü(?R~ÿÂÞõêžh§ºZXu¢H 7!M ¦±:°¨æ"Ø ÔD(V×A¯ÿ¡­<ò?Ëúÿ¿K ÀEñÿÖ7[‰øÍöææGûŸñÙÊpü/ˆ¸‘ðXgNÄ<ÀÍE¸uÒÆ}Z#Ô| ó÷ƒ~–[ÿï xý·76Z Âÿ‡ÿ|µŽë³Óø¸þ?Ä'×þÏŠÐÚ´®{ûÝv³»~¯Ðüo¹¥oý]íÏ’ÞïÏ‚kX„ø—²Xô^Á$öÈôK¡Dp`YÒd"˜*‘Y]¤6Ò=0ú5é}.€·Æ²G$H^%g ˆª;mò§„@w6¢’Þ"Æ‚uJ`lð±•á á,s=h»DM gVT |†ù¦ö‹B±›Hxðâ Î0z×A½KVA¤u”2n?†R”‘Ú(ÜjÈñ yñ†JÒ‹-®50½E䊜€£í ©õÁÐ-ÕŽ L@ qiÛú¡[à] úEÞùÅŸðÊváÉ týk¿¯ ÆUæ8ZchšÏêíU²òݶL~±åDQËÒ†Ûøþ)†è °U´y,q{2$Wäó£’™ÂiЮѢ]ôw¢9 >3}iP¥ÌûÏPÁÈ`:Œ˜bøÓÙ• [hu1êôîfœE“U}sWÚžÙy9DÄörÕ^õ–Í7\p'6ÅÏõås©‚L¬ê 3Ú Éë¨IpóÞ²©ç¶¶²Ìé¥ ‡Â:d–1Œ̓hŠ! {æ˜i‰îPñy]á—7ï†6ŠÚ¶M¤ †l©9èèˆÖ&›h»*0¯ùúýµz¬ð™ÀJ i™=Ò~Ñæ…Ñ©éÌoU>^eþp¸ÊÆ‚Y)hÒúŽ]¦l³mb‡ÅíJ1MÞ¾JÛ‚«‚èˆÝV&çä¤Ij’¢{ÞÙ„|°›Vñž¨4ã‘5¹?^gWÔ±M)….“B8ûw2'\ JÈ€9ö ÃAmÍ3›Q„A>aŒq6îYÓ¼ªÆ¦Ö†ãØk\¥8„cÒALS|Ôjúd}ÜEn®’e–Ûuj×`®É´Y¬‰»r­µÏ6¤°ù+A¸îÑ *zZ}B"²b‘p‡‰òÏ—…ɧg–ãê7 –ÞÕ0ñu÷•g¬Ò¾†w"+ªX—~KËKa03ãdü!upÐ*q–Ñg¾þÄ*õ48‹8¬Ç%e3?`–;JEžÔ³_qd{Ó[S–ß|V-§Z¿æðå õï,ê•õƒ_jwf´Iű1Qd“ÓšÂfÙ2Ú?ÃàgþÙÈ?0šBÕx ™Ùœ…S˜Í´s«ËvÕIÕ3 ÝSåô°”Š…®¡жö>Ã_ûÞ8¸Äú8€}¤ÆúŠc »"›ˆû‡Ç{G'ÞþáÉÓ$%+ãNmL@›x­ªÞ·;Ï÷޽Ê]Hܤÿßð!ɤȖRHEÏŸ·ÙB4¹*KÀéçLòƒHÄÛFèŽC’C˰µ"Ž‹|›@–‰ÆãˆÜ‚b…\3uèÃqÁ+å»ddžúÉf¾éJPî“ÞÌ?+iSO4µë}³wò¢ü›òK9 ÓÞ|âä„|«É&¹ ¹ÁÔ4n/TdT¦=˜C6<.»#µ§D=nÑå ¿·C˜*kÚäÍÁâÈÒp/…ëL&åMa“s´A¸0XÒ4ÃàïhãΑöÖÈøs;6òÊJ™œÚ>}ˆöà#lT'&A:q*½ÒÌÖ¦òÐn3®…´Uk›3iàjdÚ.mÁ^ºñËtd2“üEÙ,oœV妇“ʆ?uTÉ·w(ëTÿCÅ1ºó‡*7†·#ê„ï>2’\nïoiXXa‚òï…ÿ:$ Ù“¼Ó¬˜ÝÙ`"*CaîÔ HÝ΂[1a·³iÃ򢯾JÉt=ÒE s þÁyŸ¨´$a4z»‘å2À B”¶y+”Òbòbét…ôÒ·L2 Ô¯à&syB%+{gZµn…V欳€X&a!µè5È“*þ‡Xb¨r·ˆ»ÇRHK½ l)ÈJŸÕûvõ(¤5Ÿì>ï=Ú98øjçÑ/n…|ZsQ@¾,Ûö’àh‚€#Š Š/Žt4p0Ê4ÔÁÛ’µpŸ\HæìÑqÜ ÊK„\%S}IúSÚ9sFåðéÑ8 îŸì=I¯ûö ÇŠîçïÒ¿d»²6ö_‡çÜŒ¢µOv.&@¼Ü„¶á1KÚÍc‰Tï¶ô]<…©Ý;Ù9þÅ59§†?NSñké_êÙB²-G*èø§M*Kd$’-š'FøÔ‚¨<ø~%šÔ¼Ÿ­ƒp†ñ™…¸ ;ª!øjC+#Òª뼇zöXl$aFísÕ²§%¼¤(ê¿—°3Ö¾gé$rÉndžª[ô!År”Í*¶êm?dÏë˜|ûƒ¿ºÈ¡V¡â¥¡Ž n\æ‚f;ÇÏ;:ðüØ›O0%™˜Y·ilI·iwï`Ú”ãænÈøÀÖåUnìynOÜ#šÑ¬ß%*^"$ Ê:ðcèK¤Z%Ö*ÆŸOü©?òV§äª<ºj‰ÎøûªgͺßþÚFÔUª®ëLj,²³œ©&š f,º©§[‹Ê)Îj bÈ™u´,r8@©Œü€sìxìæ.>ÆØ&Ÿ-ÇuR:æàÜA»)va2¤šMù ¯Ì帊>™Ça„ ¼ {ôç3¢‚ÜU`?„=~UÔØÔT¿ g Ç=qy×iT\ 3f5k0j6«Z ïz//ÚºÏÍ—VôE ÞªUkÉ$ïŠ+—L]ÆIXøò±1K'®§ªïÝŠCd-(©$Åz1[L®¸\µxc ×Ç—õî=²n‘îs×â®&tŒjÆŽ±˜Iþzc}èmçä¶çnM<<ß±Óˆ"Ri}>ÙÏJŸêz6 +À‹5q`·¥Oàºë)u_@½1Û™F£²„ìC·]Er' Ç+#·ÂŠAΙù¸Ãw”ˆŒò2aM\ûw*@ݾӕќíß`ý¼(ã%0 ÈËèZÝ•õÝ ñIyƒ+`ea§cßï_X7v™ôŠ ý Ô_À™«ï™âÍ9“{¡ãEZý×–+šРDsåÒòƤvñ"´Ü³<À½/òü‹› YÔààæ­×¼NÍÛ¨y›5ï^Í»NÇðkŸ3òƒp‚|èhÀ‡vÃkµºÍf·eÇ{"à†Ïð°Ê9WðnôSšÅëÊsBÔ^ GþyÐ%ãÿÒ0:Ç«§çõÉø¼DLÏJ›89žt½Æ]¯Ó¸›x= &?ë–¯ø~‚Þ*ãóÕap¯ZÉÚSáëœÖ­bÈž‰´RŽ~]O„ Èy1 뿎½ÏèúÛ‹û¨·¸ÈZVæ%ò¹MGã ¸%ð.eáæš]«›Æ®Á³{›*{>¤´#Ø=á©0Ù)“­ÈJÀ’¯‹²:¹rónM¡BgÁ›Ù*ˆeçc±‡¹s킳(l&kAÆñÄŸâ1§¾=ó«f#2Qç›æäר·;ÁèÃâ…óÿ›Füs? âÿ­o6Rü¿½ñÿëƒ|\ü3ì´ Ü[° ¤ažBû»Þ|pCI뱂úYóvÃ3à}«ƒáprö/‚+(«w¡Þ.+½oQ)X¿3ÎÂ1œ1Ÿ>Û;Üßíí>îíî}½óüà¤÷äé.ª›BqÞ¿×¼×ÄÈñ÷7×7›­v«ÕÙÜÜhoÂëöýûÍÎfký^£YÖ åûðx½±¾¾y³±¹y¿Ón®7:›­ûíÍ{ |Þonvî56:ÍVks½C ÷îÃËÖæ½æF³ÓÚXߨhÛE®·ïuàÅýνVgã&Ç PÀf«Ù¹wo½µ±‰åÞï4ÚëÍVçÌùNg£³~ÿ^£ U5ëð¨ÓÞ´ŠÜÀNml¶ íV§}k¬767:÷ðëýÖýf‹úÖn¯wš°¾Ú­õNã> Òv«…0eð³yÝ*²½~ó^û~«sÿÝhƒT~šÐ¹·Ín·;÷Û”¿Þ¾¿Ñ¾·¾Þ&#´Ñ€!œù蜊6‰!|C¨!ìG#8×ù2èù#øÍÞ!Ž` kH¤:~¼ÓìÑmÏñþíAªõt¢£CHùôùÑ#LQ^¯×æÀrÑH5Zæ"^˜#îÄKœ,çð¸×ê5°ñìDŸÙX8{}ÌÖüùìb­Uod´27{M+³•-†½%¯5ëͼŒÜ^aÏ‚)A!ã¥("ü{íF Óƒm¼ŠrjÖß  ð,êGÃ䉙ëè©L=¬º²ÂøÛ@"D¬J„¿°" ÿ¸O'hIêù±·‚Cª÷×þÐD¨Á̬~Â×õòÃrwÀ`ÜG¥5húq€š¸J<›‚ô'­)I~=Ú_ãK|‚ІŸ‘‡Ã\#pßgq*Àœ^Ë«õÔÏÊ*LB•)xµÖ¢úÑOÏÖ?<"g+´:Q ¡cWãùé(œ*#‘5¥[6¥ Mc g å·íØ­í¤[ïR™Àªt -=XãÖ(ý÷ã§Ñàj»”ÐÀ$Ì\+åäà³ñ«—hZ¢”òÁMÄ»Ÿ‡%šÖ~í¿öùii{õÉÞ°õì±òæ««ýA¥$‚‘ª„©RµÎ… õ`‹`—M«Fèõº‡Dù~L›LC¢,—i=v¹“›zý3º¦!mTê+‰yÎL—‹±Ïü¾¶‰Åœö«Q0»ˆôª„ž?¥¥VÈ<Ðk„ÊÁw)Œwûží"ÀY¡\Ó¯銃¬æ±¹Cãjø¶´Q7}DüBØhN¡Pr'S`ZoøÕƒq¤FL½ŽçgæõZú½iùªv ÷Í,ÂÝ$ Úyˆ>ÄÖá2$ø«£}o7©¨•Iƽ7Ó°²br©ÁFMبÐ : LÇNDfJM ÂJ ãüó’÷ûß{‰‡KUÛ´ Œ¶ÊD¿T eh°{XÊŸ>tüÑe¸ö$ÆHJÈtˆŠÝaøÛ ›F0ñðX‰[Y‰Æª€4•°í”L47U`*ƒš†V´€Ü¼ž#•×Qog×ÿÈë|ƒ‹þl%ÇžFº5_(çFÒŒ-‘~kA›©Ÿë"ÙfÜÆÃI6š7Gnñâs!J¶ÝQO**“zÓ“{7kôÿÞ¯W6n kå”Õ“›*½·ÂÖ Çç“xŠK"Ho0³çl—ø[—™Ù÷c/g³wtOÊÁ Û™¯¬«M5è™N¤4ü™Aªò˜3YT+yù,Ü"ÀÜ%اrS0KN¥1wlB¾ñ|84Ž—n'pgthRJÎ?“ئûÉ\@wElÂvÈ& ‰7$Z>‹0:qÉY†3$w÷R~;ÐjÒ³üÞ°\†ÄHˆfx81Ž~Ósñí2`Tjœ¤æµ”€u™IéÉ?¼ehMŒ=ÙÎO]ô‚Œžà„ÿ™†pQW‘Yɦþ¥‘uaᎤ!// ä…áÜ4Í—ÊÐ$å{›¨ÊY\Ñøu0Eàz‘SÑUy>Y:VC)AŠŠÈªÒBŸIÈYaЪ8w´é¥=ض)ÆgÄí|¡‡ƒ;E÷ª»yÓîd¢ŒW´,½Uñ½Æûedf"ÀîÃÛÄ£ù>«Ož¬îîž\\tG£nŸüÑ®÷üäQÍ› \±v>:ÊL}†N8 %±iûùÐù@”ï~·zw´zwpr÷q÷î“îÝ㻄‡ ¾½˜VF34FTÈø 7:ï÷µMÉgs4ï1‘‡< Þ4<ÃfN~hv7öð(à‘’5àCF11IKA{ õ1£u†["ˆ´ç½ßÌ# þOª|¸€g0hý‹Jù÷°Œïã/àåÃ¥ïË/+õÏ«¸bþzéÇk_nÿ>|—¥"œÝXJk2ŒÑ’J=~Ñ~©¹¾S)A.q±/þ¸ôò ®Ê.›2!3Ö)…C¨HMÄ>ð9r\ãú­A4XE\·×ù‡Sޝ(žMpLAj* +þqèîÓqMåÜk¤/·¥^¾9u›9Ô#“LÇ6…›/SV,V5ʮƪÆð óÒf$ùãpŒ}`Úöu ­éÛ¬Zy6hV d_õ8Bž7Œ| v@›¹ …öqy RÁk´©³^’)ƒò ПUT™DSÔñyN† ‚V·)kP0Ðà~u{ä÷{Ðb»Òl6´‡¢ø/Ì$”ã¡}fÄ1r?ˆyRé2½YÔCí¡hBø¶’22|(b¿y˜ÐŸa± º@ÉÔ)QtÔË^­LÕ칫óWl×½©¹-S⥮›EyÔ#ÁÒÝÍ&çôP¤O[æTÓÙ®þ…îNÒÛsÏT©5 2'6¹³uç‰Ôº ‰ @ÔY!&àÆzo°JÏ" ž Õ­$¥T%¢"e9"Y0R¾RêR’¶NN‰$Н ’ÊdaA«Â´Þö25ÌZޠ〙 ~S M祳ätx~šøI’Yr6ÀÆ›†Xò¯„A²òõ_…´7ª9EˆJ.'_§_œïÂ/šÉ>Q‹½?æÖTQiŠ4³z¹‚ôÌÍ©\T¸ÎfIM˜={ ˜¦fˆV.‚7Ø/ó˜êY¯,Rº®à ¼±M†cé:ùÂó°œ>cþ¨s:^pñ eLgÊ>ùk76wã·/\ÎÃTÊÒ÷À%J†Ç8䓽D¢6'Û`»Ï1µçãø"<› kH°h 2´:š\ø„z5@ñß»45 ç‘Á2}…#ÔÜlmV‹+oØ·=3Â5·ÖvñhKúúCO&N9wP9iîȾ‰¦¼ãÀ…eŒP„²ÉøB~у’,æ—µ$(lpÀºz:ojûpJåoô.Z*e38µiIûðé_hš¨ü•¢é@¥|±¾¬‹æGNÃèUšhRV.Õèà¤UV³dÛbÍ'à —É?/1Oá û‘<}†EÄ}C‡QÙ瘽šê…LZ ¢<Ï XÄÚŒgqEʨ¥¦§¦øx«·hzKYª(5%2½â^fh®i%LõüÇ;Z¸–X6VýQÃ8•šV½¦­ß³J-È¥rðØÞàˆÐŠ¥eÚÙ0=}ˆ†ªCWQ;k1k& R9’œ$CÌñó3¬ ’6Ĩy¥iI GTä5ŽÝ“8˜"6Ò ¬_wdÊ¢`M3DÓ~%ù­[‰óë=âö¥s²Õ©VMJFT;Tͪ!ë¾Jg<#0Í•³Ì Úq…š9$Ó žDã˜å<¨TûOâìèy®š£w¼wôíÞÑ‹òÑÞ_|¾w|Ò{²wòøénÙ UöøÓé:¶rCÞ£ïzÇ'Gû‡ßwžak¹5®Î³§Ç'eûôI@»/ªH4 q¥<¹ÀK§p<™ÏÊÆ/o…2k\ƒ]NébäÌ’;zxÉ”Õ#µŸZ¼"AE:éYËÊÓ®c’üEdW)ÂàÅœñBµzûg%‘hY M¦‘u$3 ;ô5Wß]zˆ…Ršk(¼y«ƒ+¯«ZŽeèÅÊ+dŸóéP:^;„É ‹ÒJtÚ~€ÁJš ÚˆÖì³ÇÏÖY3KK_‘RmÒe•IùrjZ«° áT‚ž¥oОAð7sjm>’“¨ƒšrÀ“M6ÁQ©HWVfRJô¾åz™ê"9;”+ž´©ê4úJ4YróÓÜÜØ#K£l¦œÔ f=ïb/œcÿk[+¿³é¢ø¿Ö'ÍÆF»Óim6m´ÿÝh}ôÿø Ÿÿö³ÃoþÙ;ÿ<Πvÿñîüýçð¿?ÿOÁ¿•ÕÿÒ1üù§â¯öOþüŸÿóÿÁß}úÂÏþ³ƒ“½?ýÓ?ýÇÿøÿ£ôþá?ü‡úÿùûúŸþ?ÿ³ÿôü'ÿ¯ÿ÷?üÿïÿïÿý¿÷÷þÞŸþGëïþÝÿÛßù;çoÿí¿ý'ûßÿ¿þÉ_û“?ù“¿ñ'ëïüŸþ÷ý¯ÿõ¿ö×þÚ_ý?þõ¿úWÿêßüßý›ÿÞ¿õoüéÿü¯|ò§Ÿü£7Õ?}õÏý“ðŸùÇgþŸôÿ©øßú?ÿ÷¡ºOgG‡Çšÿù„þýöŸþ—ÿ$þ/LòÉ¿ÿýç¾ú××ÿUxxw¶÷«Ùqt6»„÷É¿?FÁ ô½¯ÃiÀ‘ žü M×ÿ›¯ÿõ¿þòþîÎÉ›í_üÿÎù¯4þ™?÷ïýÿãŸ÷«'/þ¥¿õçþÉŸ~ñ/þÍ¿8ù?üæ¿ûÿ÷þÎÏÿáôWþÁà¿ø—ÿÍáßùoý‡ÿô¿<ÿ÷¿ûíùßþ¯Tþ#ÿ_ þ…ÿEùOžUîþr³ôäïþKÿüìñŸûËÿî¯>ÿ¯ÿ£ÿüòçþÒ¿úäo¾ú¿ü×ê¿ûŸNþ¿üïü:þüƒûû¿üüoþþÿêóoÿÿõ?øäòŸýWÿGÿÊ¿û?Dⲿw¸û?ûê/ý•÷3þÅöÿï÷W}Š×§¹ïšÍ&2wÚ­Æ'VÙÀÇõÿ>™öÿVìßæýz‹#ßG?€&|mvÛÝæF¡€væUwàGÁð FÏ0 ¦#6p`šeB#nx¶Ms¢¸Ld´ÞÆk( «š ¨EHâ5a@#Ž|„†€• QO7ñãä‹A]qÁ¾áô󾄿 (ÈÒŒ.Ë¡Xq¥¹|UNìÄþ7Nìp[¦+&ÜVÊÁ$mËˉÎa+TÓ1tár”39…£æš‹_ Ë¾7™Ã‹>Z!L¦ák_/­ꨟÄÒavRô(DQrô¤XSÑKC åF´gÐÔDT>é¶„¾Ãè™gî(íÐ)´›÷ÔŒÃpBEh@ÁäØ4A5a–3=H©'„OŠK6¢`Ö.ÃWáÔ¼©Ãî»ÆÕu$Þá펤Ü¢úê*AñšiS[E$sÍ; PyY êçuot¥f§øI©N×ûûÙ; ÞH$¬•Ž’zŒ‚Ï"µ©§Ñë Çñ šGH°HÎ !&g9©A¤žÀ¹z·q[ãéžê‡i´å$ ǽ¨ø³#c{e«O‚”Ðc;²ªÏ–`ê–,zI@Y0Ítxçšêx ’md¢s°x¬ :;£n ÉÀ8Äø}ô˜¹¨"ÄÇšå‡Luí$` ÆW1ٯƑŒüpèÁTżMR4c\$¼3øÓ+b|Œƒ3‘˜ eÉùýã°Î5yq«™£†™SQüWL„ ‚´Ú jøãؤ ü8ÄÈ|:f[8M•Í=DΛŠÁúP|ójÞ”"èñÝ´F;òÄ[tý6€Ú`É›ù|1n2!çjÙùE4‚–öqpúÁDæ.Œá>îz;3±rÑþ¹/»ckãQ»QA¥Î3»U)·È´*ñ¦ ”ºˆ'êHÜÔxfÅ~䦃óNšwŒD‚T¬,~Ť.˜êЭÐb†:’,Tb¬¿ÁœN⣎!™ãÑ$8,k'?Ó­¥ [7ÖÒù9…æ N“¥3€7íNkPhMôšëV¡òì꘸vt}µtWxOî˜Ê §«ÜA¨bo¡!qB1dô! è’é16¹.jÉù$¢ç𵼆¥ÏÑØód á^ð=GÒ¸%ÙàÝã骗ªÍ9‘tU²¥ãèÊþºLÝ%‚3dF˜°Î\ÉèzkYÁ¹{‘C´¹¯³CN€äL92œ¹¬;>Þz¨Ô cZ÷uˆƒ¬æ,2&ÞŒ(Ú¨FÙôJØ%#޼}µ©é› ÃÏ‚¸¯ôì}¥, rævCN§ÐXmì‰â ni(3Ñ&Â%@kh­ðn%qYœÁÁH6]«ie÷Òu>ΡȲQ5È…×"Aº¤Z¦E6]þA.òÙclŠ·àšçzÓp` ¯<¡1&ÊR%ŒYfoÐÌ&øSÝëÇNœG<ÌVÊ<Ó@Íu˜êö¾‘4BS«Ä__·À_ëÈ~t?Œ&³«ŠEƒe¼"Å©ª¼?µ#fÙ1»à HN&V›æqxšFô—({‡Šo}I£™V ˜­RÅ §˜q»ɦawÃÞ,ÊAëV(Î@“Ð¥"×ðOãh8ŸºPiЋó@—á,F<»‚p´¶ýL6U]ñŽ™ˆ\}‰Ñ¹çc¥: €UDHféñˆ›“}¾Se⃖‹yWF{9Üóê6}5ƒs±ÊÉÑ¢hƒW9ÁÂÝóf…qNmhÂqÎ.S ލ5ïM4°sæ„FYð°úkVá ‡ª<¢„Ød™Ó"øuR(¡³9†6ǧ79’›ÍЗä§Î34o×0”¢ºT#+®mg¹ÜK]€,\ †À)5eï•İ8Тˆ§÷#e2åwߪˆhb#—hFYç8eì]Û´3Í”)Ÿlöú1³‹%®PÀ, biý),°q¥°9“¯YÖ²»á8‡¢€ŽÃ©´fEŸQZZçÎÓ:Vª>þÖÐ%ß°U…¢„˜‚ýè5‚E|*‡ 5¨«ÅkJkMK×´æÊrŸ†Ìš‘ˆiÔΊÁx@'MUŒ `ªT£¥Æ:¡j¥œL¦ÑdŠº7” {$­FæzbÆÌ5K·3˜ÁÆôª|äewÒÈh—¤8Õ±ÌÙ+ãoRsgÎ&ea´‰(5á{âÜâÞ0–-ꬾ>´Ü§5Œ‰y/P?ö©JeÅ«F=‘Ú±©SÙªŽ—OTØí‚é4šV2¦6a³GÓ)ú‹É†ÏŠ?ZÛZùlˆÑÈö1jƒõa+žá:káM‘Ž^¦ÏSLW½wÏð஺E*£p¾ DE‰ zÇKÔ»ËróBc¯Š@.ŸÉ …*¼_)½hÑ ±äÊ.ÊžK3¿S…™CÚ§¹ù¨˜Äm€µr³ˆóñN„²H&‚Ñ ó?¿SÖ™N1Í[ùϤhÒÓKÅí>”1 ËŠ À.Nû#„PGDzÖ≩}&óÀ²Ù¿uCãMŠÓ1Ã|N}VPùDNe™`Š¯Ø ¯Úóæ0ºÔ ái J6WãæÂbÁ¬ð¨¥¦ 1¬$ÓÄŠ%Ò$£Þ䆣w,}â³NDcµ"%Ë ¬éaYÏöáÁ¬ŸsA˜}r¼ÆÖ±T:B¤ÄåôÖVÃ4 'ÒYÐV{ ¹)AIq–µÐõ´ê1ºòC²XÐ+U~ÀÄëã‚°L,›/ʲßÅeKÇ‹ÑÊì ‘ºYäÊûÎÚ㾈š(:jàÁBNUOž¬¢+ØÀLî!cD[‘ZwúhÂ*@žµPÜvã‹7£¡º02N_¢âÆv1Tõº¦«°Ýò>5» ”±ºMʂēH"¥¼(?bÊÕR‹ÒfmÁX•Ö¬FO­þ›½Vªy ˲ÙƺÅAô~õäÀSøÍ$ =$ÐÝlnÖü£nÓà›–kX ›£$8›=Óðîܰ "RüjõWG»Ç« ß;ÑƒÄ Xœ;Í÷280Ðå ȾÏ,„4‚ž yºúxN[r`ÑR-²†Ì!¢Ý@ûЩ—Z‚ 7žävÓo0ßMö¤·JKÏüâ)ådMÄ&ŠÙ·îèQ{¤544SM·tÿЉäZЯºÑ äÎRݪkåGaQ¦_ÍEK"£3ú4oÝû ÔF÷;sÂ{ÖÍ gê¼PR)£óŒe™-/©Šmyig6Ö’©£Æ>fˆoIZæåÌmé…"1ÌKäJKWªuŽš,[Ïdzež\MâõNÌ0-R#>¼ShŒ†Ó:nbɉ›˜n‚Šž(šIï ô’a.AíÞïî6B;­êj™3À 1[x¦îx“ºN¾,!cðL™Èghf¡¥üPcMçÒîíJÊãÓ*+Ç‘eÉmc0’p§TƒÑ8°Þi¡Éiö-n—j%çLÃ&à¬óPŠ«n¡©=Ø‘½Ò;ñ*ú‘â‘fUC@¶»7˜=œÏÎVï•ÝŠ7è„*ÑnSM@;j ¤µ#vEé½;‰ef¬ªt¾¤Æ+í–o1þ¬6È V4¤!È~GÇjly‰ÆrëDA¢ é)[(p÷ñ*"):P'0›`@ P¿d¹ˆ»ÅЫ<mS6ôž`d¦áÿ’Y‰í24Ú˜YvØÈŒu'RTeš&¤¡³0Ó¬¹vž†+îïxû‡'O³a%Ékž=5ÏUäÚšÅôkž4CÝÌÃyüÛƒç{Çä§5/ýïÝùV-ÙJ/Ͻ嫥 æÎ”Œv› äæ7=Ë|­ÌÝæÒûÔ‚†é+¥,ùÀ‘`,ôy@+eØ)}ll˪ܻ„Ô@ÁB†â\tØ ÷ëYØwk…Z6N®\?ZÊcºQFè'UX…Zr­nÏ-EËõÍ¥HY¢Ë¢»iÈ’í!Ó c§¾ä·³jsp¶QøwÊñSÛ2¥íÁ¥¨w à‘åâf™ˆ—Ý(ÆT0ƒTÚV…K[t¤Lÿ”á/Û HÇÍzéhrŒ•ØfR[©ÄT‰¡-õqØÅI«h2j&W7cr%rÖÏf~ ë8U^.çרfƒ9U²…—gX—“ËR-//ÜP›……©Æ³ŠÛÕ¢çdIšøé!°ri ØÜ4 ^-ÙFÛÌŽóK¾É4Àà­EÙ r«¥rÝìdøÏ•©Q\±$±LKXË–-ÔŠ¨™Èuxš‹÷§SùÏ›ÜèZ*¦³Ö±PL¾õB^!|ÝÞÔÕ¦²Éƒ½:†1&˜²@\yÑ‘D7d]’3V˜í´¬Ì•¸?$bs¥möHAï#,Šú\ÊñižñÈ\zråípi%ËO‰íÁµ‘4QIlÄ«h¹-§­ŠLGóL5·ì-#Å}e†'#¦L_èÂ]'C¿(ê¯XF×ÞÃ\klUº6`?4FÑ©,±RÍ"é·=g­<ù[ˆåÇQ´Ø-ÁÔÝmcåJÙ]˜Ži¨¦Û ]5ávRÈ /꣓õÀÌÉIÒ”YU¤cXJ©ÖV!eÎèÒ³ã* A’µ^ʘ . SÚñ¢ ܦ󲣦¹†½ÇeYŸäyy ÅÙ›œÙy¥F®¶â!ÚQ»^Nt«Jt6#cÑáüšbœ9øÛÈ,Êa»¦š“‚ÎŒ|W>íe7…#â3Ö‹œÝt– O©?ÙyÄéî(_1& ¿È,ß=l’Ø·túVgCOWú©ÃiúÝÕ…$k }X”ó‘uX¥›Eø‘:,Hæì¡¾©å–2N™BÖU÷uçË•2Sñ¥;E@~r"òn¹­`¦Añyó‹l)øÊl>IÌÕ.CSÃIcI(UÒNÇr°£”ιÙIk\(¡±šs§¬K¬ßeÏàÃQùå5ü\[ÇdyŒÐ›FÑìZ…²’÷CýrÐŽ>鵄2±ã~XVryEå­¬lã˜rr¤×´Ë²ò1,^Ãd칔ɬ­<®©iŽ_G¯‚ž?ÔÞX8%_–h¥cÎ2L_8Xîüú$®Ä·ÅV|×'÷ ˆ<°È~pgþ'9†ƒ§Q4 üq¦. m!åªknª`‰Y;£j½¨E«ÓÞY0ëɃB/¥•ÿŸ/Ôø'ùšhûSç6WQcnœ>'莽W˜ë'äG¯VΪSÆ6j%†g˜ÕÚ]rƒ&©Â’ñ’̱Æ*.K/lû*=0*n6j~bøT²Ž“qÄL.x¥Y.žØÔÄ„j‰ÀI¶5oÖMý-Þ\ç~ u3°(°§í0¾À¸%Ëò5qyõ+ašfAôHBxu¢4µi‘ц:ÂE(]%‡îò|¨R„ñdè_Áa¥D˜G¥ª ÒY/¢Kh9ÇsýE4ÆszxMC8‡W‚¥áO^ÁÚмRrº;Žf•ݪUÍ.ª¦°×œ¢âõ«ŠžžK„, Èõº $ƒ7… ºiƒµßžûöœ‡1œRÜ¡å6å¯`å¯ëRZ\—׉V£j$@7Ûþ<¶°çöõLaLTc2fÔ‹ÆË:•cJ™öȱ‹µiøôʺíÁË»Äè$ÏÚÅc÷høÓÄ'3þ‡v;õV½)! ïcõ{Ýֽ ùì9qbm ²"ϹºúãI0žë[¨oæ(ãl÷÷e,Ç(<‡Š¢µeJq§|Éóé`œÌ»¨ ‡AÀ•Ge×e–ùvkP–pV.@¼¸UþBc A¡©[XüœNÿ•]ºø_£tÎÁ¤Ë;êͰ'Å@_˜€!NÊ V”àÚrñX­`#÷ºÞêaVXU ¢u¾º[wæva8ïä9œÚOÂ…¿`²)sg¢‘ŠSͯLT•#Ó€‘Æ;Û§åÈŸ¼õ*s¼Š%Ô ’<¹kÊzÖ«h3YM¼®° ­‹\×î)1ÇŽ¹gó!œ™X3sW߀ê¾»Ù—¢Uë¢O×Z®ç/®þÁw±Ìß•)jŸ޳FSžw‰£iÄ77L™‡ŠÞÎá®ÝHÞ&®É'V*!íÑJ^)f`.W¡–Ç’3•U9«Ûj° ·„(ÉAhˆzíÚÍ1óW"ÚP «<4R5ÔÕ‘ ÿC{¯“½ÆÍd éD„7‚ amÝIƒ5Îñ5êÎÃ!T±åí —WMÕw„áø|Í'ŒðKOpá%j40zÕ|¾‚>,²,‰EZ„DšÀ!Õ³òŽ 5Äu(DÛLHByéBBaIdb§@óú¸¤ ã=©=qâ;d‡… kKãþi†WäF%“<{-ª·Õý©íØ~M˜¶ľR3-Ö&†¡Œ0SƒÔ~˜¾QL &ªeèOÏ+MkÿXhÈp+PŠ)Ô gŒ>† Ñø,TÚqFŒê³@ÿ³Þ¦øÏ›õv þ÷Íñ_?ÈÇÕÿ¨a·mšµfÇkÜï®7ºëî% dûf¿‡ÚˆîúgSt^@ÛºsG–s‡1>pvõsU§·R~…xÄoúó)‚˜©Î.¬pf’ø4l¶ˆû”j°h¸›Ø•E$’Ñyð9÷ËmïΔÏ¢˜óM•ý×X4èø†ÄPîªõM+’v¾¬Þ㤀û8Ë!J•‡`>ì°ýùˆ1“SlŸ"J° iRQ/·ìwÓFLT)\cÓ,“é t?úf-AÞŒžV~fÚÂbŠ?ƒSÇiœA|gÎXXÎs:BsM14éQì̉߇N‘´á )2'[´¨µ]ÔïÄ<KtU‹›'ú N ûöñÞÑ·ûöʶ/i~kx>fd¡¬fX(°¿ÿ½¶…[ ¶¸4Ëø/;¡…ö‡X5tDÿ*ÏŒ64{Íku#§+Í^ãvÛß´ÛŸ‚gÊÏšªÅªÉ™6¦¦…ü²™ù$šT2fkæì'&aÏ{²Ê¼­yO|rv %ÛÎ9š]TÐVŸ ×ôÜrÛé*áUÄ_£ÙF6¾ÿ¬ÉêX;ùîÙž‰ÀY8ÚLnìd®âñ:·Ùˆ¼ÏŸqù/oüå/š?½s‹üÿÚð®ÙØlµ7;ph£þsã£ÿßù¬}Î’¿5Þ,ö‹òŸ<€÷»V·Ó´D~²ÙüLr­²`èÍu,Eسh<[åH¹]ï4’7m*ÓTgZUŽÕ˜¹ £i×ûìþýû‹²M¢É|H°ÀtÛËÆñ]o 2ÉÇûÌâÏ¢õÏÏß­Žâõßinâýœÿ[¸l²ýwëãúÿ÷üïŽ:ß¶7ê-f¤h¶¼f£ ¡y¿Ðþûx>£'ß‘õÉù|Ju+%Å®ñ÷3š¦%.NBã»Üù¯ýp¨0ï岟‹±Â\8*ågGO¿Þ?Øë=;ÚÿU¬ŒW­+aÈêDèÌ6FÓ/i›®ŸÎg­8ørŒN¡õˆ]籑|vÅÏ¿:Øõ¶nX/ž:®[]ï`ÿødÿð›c¨·mÕû˜ëò¥~¦)™ç’ÓéU LÙÇÔ2 Í©þñþîîÞ!ÔºnÕš£ÿ¸†“”öCšÆ/Ië‚ÓsÖƒ\P‹×0›ÚŒ®[Û´–L¶Ëu6û 4ĤÇg7õ>phäÉÖR‰çP!FÐ& º¢³Çjgt =”Û#Ó‚ýÂdß¡0¬t¶yŒ¶ Æàƒ5ø‰Ç:!°¯éAìfÊMˆä³k<Ú•ã)š‰Pé¶û)tŒ†#†¯ñ«Fä6$´x4šÑÆ—Ãâ`iPðô܇¿•`°pêÀ¨™Êò¯o—_'Û÷k@²­%ëIRêèÊ|ŽÆæ ±9§X|c8bgÑwÔ1n?†RÞÞæ?¤¨RÚö– ÀD™%èÜ#8Û…7ÍL¶Ø§Ñ›¥3Ð:åH—xn\6^½“i!æ_:×󣃥Ӣ°Iü` (\<¼‹)9õjäê@î;c¢(žWO1j ] £7`œ2Ö¥íg΂CXκ¶©–-‡fg€-ƒÜ°¦ªH‰'71‡’†æI6A†pI6!™tÏK¼,‘Ër†å XtŽÚNZx†ÃWcÅ4+ ÷p2Œ3ùyŽ{'‘BÅÂˬy5l@ïpb4, ŒÅò­Ô‚€©§‚ Šì&Æœ¾§b*AO}rÔ2yí¼áŒð2U?@H®Öä±ÛÁ„åv%ŠBfHÕôaŒÎ%ö³zIŒŒ‹P_SÔϳáØjrÍ;ñ ¦þù*T¼:˜F P"€­XÐ ZÛãÙ`>3×…ôìê#nƒ-J´%ÅŒq ë^å®EÊ…]<‹)vgbh8aÑœ}:.0´ë5íJövñz/ x£¦˜ÊpÂTÁ~âÆ!6‚ˆ¢¼2ž…CF¯ÅšõFqŒø¶ZP–ód†“ˆ˜>¢f8éd.Òä)9+áíâ;vò¨fïÁò’¶YYöEƒJF^ǰk³‰•£Þâ O‡»–q“P5z>¼´ª(=ªÆU®1©NãÖ y*Ðö¨:³[$@˶H¤AÝ¢E•«â³+'~×éú: .—m2úŒö¬T|àô¸zÖW.œwðdž+ûñK¾ø™e¿Põ¥.»ŒÃM™œLiÛT$°Nf÷NÑÄZ̳èëåÍ|çTÊŠÈZÍüdïðyïøù7ßìŸìíööOöžèk²$É´CmÙ8I/36§‚?SÍ©å\üÉÕ)oNáoéÀ$<7hbN|d* Y³ËI™I±œ™W]†Ørê¤]:Ó¢‰·€ŠkèV@It®r¹n“T0çy'¸“íÑÎÁÁW;~q[šÏ"呺Ĝ3Û»“qñÂãI3ä—q/+÷8(eå¥?Ûó‡ýPŠˆÄnªï›Lå û£ ÔMW×uÕuWÑò{ÚÂÞgìfêðEDXB i.Wà·+¢í•y{§p31 ®>m‹bÃ1 Ä<*“¶¤òb íZô~›Ï.0Є9ãj„,+GAÀ(ËWOýÈóèñ^ïÙÞQïÙÎ7{ÞïSž²¨¢ —æø‘ÚUR?aÀ¤£VˆR4‰‚±¦i¢£æÀ‰:Dn¶´E*šwžø|Y5Þ§$Êiž‘bSª<¶ÈÎ.½¥v Hy£ÆÉžŸÓÚ;9«å&²¹^/ e§MÌ{èÊØ=ÛøË‚ý–KšR¢Á3@ãn´f– °s-m¹i) >udÑi©Våxé*Ô$Îܬ+)[§NèWåš›ZßP%‹Ï`²Z¥¶¨e)q=éß›×J¼r¶Ý}íö± c½³`R™Zïd¦Ú“Q+ã”Íacwì÷0„‹k¢—”™´Gp4'IÔÜ`¬V,¬ƒˆ¹‘Q¥[)M g{î¦ïÃ-eªÇßÏà'MD¤&-džö¡å,ºöOÍT“él4ùt6ñŸ<9àÓêµl7ÆâÓG€ü¶¡¯vgk}qð*˜Ì4ãGþîXÜ’s ß#¯ìve ’§6¤å4Ž·«‚X‘›»Vhkq“ËnK3KÅmÔÝFI¿Ì¼×VìÍÍjtX¦VÖ+¿ñ…£õXö¼–uærO é.ä0ž"Ð÷4§ÉßÜé»z!{†&v™,EF×+'š1òßäAId]Ù/d4nv5ÝfŒêa¦Xm/zÛN)q¥³`$^³µ2S¬ÄžebµVªÛz¦ôÝŽ˜VpÆ¿ñ¡r~”óãƒO€ J'OO©ü>¨œ¡æ¹¥u9)Cé,MÞŠXNYû¬*ú&;8ôG轺Z¶u(fÙê­M¢¤ðLÝçEÕ~ËÐ §”&¥7ò_ÐkÒà—EGþM/&Þsr9ÖoòãÇ7ýR*ÏŒ•ñ£ƒ’ÂoEi¢müˆ²¶Ióã`8Á€ r^èzlc€N•Dd<¤Ðµ‰ïxR‚£j›ÒŠˆVöµlxcE1©¹â„é¾ës€š$ðö¥\Äæ(GŒ¹—°•O”´o¡ÀuH7WþdM@Åò2ÏÈxP°¹"Ѝ7|;‘.P¬9\VšˆAdg¨©ã,Ó^\kQEiÇGŽCL??:°LV93­yMÚFEƘÉükÌB“ûÞ·-Pušî-Ó5î†éªé:Ýx›<¦#é³g›mE’g¹¡Lí’)ã£“Š™‰™*OަKPÈÙ'oë@½ðð¥¼Hé³ÊÆ:L£¥Ôh–›HQ*ëôÜÖåú6ÛyD!ƒ^NæÊò iÖ²Á7·)þÀ(Ò‰ ‘¤ZJ´Ë[UWÙÎU¸¤"gneáh©H³ìØ}²y˜Ëx–QîãE²’hÛØnKqåg(Øå-U€³6Ù*» Ú£§ÏO*ŸçÌLQÆ[óm,’ºøÛbæa´L ]{F¼0޳jâxPô Û÷º>› ë“‹‰Š†‹}Ťç­õt 2Ä쑯Bô„êbÎUM\ùŽSñÅÐR!³fwà•g4lÁ„›¯wv ú™ižÜ$™/Ê“`؈“Í^Y¯,ÏkNjå3Î*N9)¯]J‚—RóÉ„œ†0·€×JH”ÔfMèúÏ×õ;î• ®…ÓC%¸½;Ûº£bu/3›énaÂz“¾2™7úK§í/ì&]«Þ={v¶…eg­xèÿ ó6Q÷ò3W2~ ¹K»P¢1cþ³5ù ÿï q«ó]î]²¦x¢ºå§¸dLNq—Z*J‹Š/µ’pšqìe$¢VavΤ­ ezâ™ 'è˜îµ¤Ñ^õ‡Æ\Šäx¶˜¢ÒÍ(Òmx¾q5õó1Œ¢„ÊÆÿ\€ÿšäò7Â]€ÿÜÜh5>i66:ö¥ø¯­V»ùÿõC|2ñ_“£n‡ƒlÜ[klz{Ýöýn»“ [ &x»¬3f¡“¦¿å´FÑ0Ê#*bÇ((ÒpŠÅhãx-脱ÙÃØQ[)Ò€²ö3.»ŒäíÏ4X¥wŒƒ©?Ä¢(¶DgCF®cÓé *o|ìA½Ôª)yâË2u£Å—ª^+ŒOß q²0I>Zï`¤XȾYu­ HéÚi0<磒"ÇŽÌÕJBª£$Seø¨é‰Šš)9áÏ.¦Ñüü¢èDEÅÙÂV—Nm_ ˆ‹ÝgSÔA]Ekxp.PðÀ(iPqe÷O1òŽôV,£E¯޽ÒÐgz¬T÷v2%8|ÉÅQ|÷8²¹0®‘uM›hÑL—¬ú¨ÉI²ï2b-ë}¹}ýT½pðPURÚ6MëÍ#ki=[¦&§ÔŽU¾ˆÿ; ˜Ö±€ÿ·6Ö7ü¿¹ÑYÿÈÿ?Ä'›ÿ;£þ.Ü?©¿[Ìû €9&³JÅ h(–#è!û‚Ž–~1òJ*Ÿp%,lÔ,³³8!g.f”¢Oézû#‚bR@=‰ºhæ ç¥W⎦Ðb] Åèbð'lŠº)ÄEu0¥ñyGP-ÝC͈œ~¡¯Úù_æU³meFW Sd¨]UÝMOuu½oiZ"=žb x<Ëd¥®ya=&«Ž…5sž¬1oVGÏš9Öhï­ñî:%/ÕûãpÜL§ÉøHYCÐX x/lUÚ¢o &cœ“í¤@r7†ÒµiÜ}#o€3‰o)ÎÂ)¢Èîk|[,…³#Q#eÛ=£Y ’ÂèYDæ@EõNvËÇMšð¢¬ Ç`²]Ü,ˆzm0dzü°Ä½Å”«Ô •&±ãd•©´^Pp÷ÁéÔ[»V^ÖwYâ}Ìô(Â3I°ÔF*Ø`zuÚÀ ’Š“7Fc¨ÆÌÒ2µ¼“í;¦?©Ûß„u¿d¢ p*ÆçÛN#]!¤}°¦R õ¼Œ¾'©é¨ ¥•kÕ]È(ý¢wïÿ/Šÿ¡‘îÞ¡Žâý½ §½OšÍÆfg£ ŸuÜÿA(ø¸ÿˆOvü=ê´÷ßS!@ï­5kÍ ¯Ùê®·»{…@vŒïUøZâZ¨kßXsGµfyþ¹á@¾Feßé<8@¢óÕPíŸxÑJ¸»‘jÑ’ÂA†XÅ(N*² µ½x~: gyøØnâ|›¥uWZ1‘ À£¾!‡øB,§|»¾‘ÓbBígL"ÞÍo€ ®†„í†DÖ—Î^"ë¹L…/^zY>ZéNû,”¥D˜DA¤gYq¿´n¨”ýš14˺°´v²Šc‹ŠåË»”‚Ñœ.»<ÇY!¿íeUl+™ik—rÀJ0* ³üÚe6e×­}÷ŠêæDU$ tm„½¯Âa<†wÍ*®TÔ— mª* ›Y¿Í¨î­x™"f´ tÑZèG£ÓÈ# Ç쥇á‚#T¬WT¤e¶‡+˜E–AÚhϤ³ÊÆÔ}ôpßN·8¤qg× 35^º<Ž*ܲ¾‚ï Ë%A–£ H@Ç.Æs”cg—1Å‚ñ˜„-µ¹§UoÛk5:!grÁyóŸ_Öç=DLÅK(W«ÙWÐ Ú¬Á²ZG„q-îœþ%ˆ_›MNŦGté3ŒƒK96"4ÚEK"¸àTÅ0r}GÀ ør+•MÅÜ);Ó2ó"²ê—:÷íerøãyžµä ×XrCÙ¼Ín¥\#$±Sä1a;U•Ñ;Ííú1?ƒ7À!†½ÌcŽÂãKü%µ6uažÐ°Œh¡äj&‚±ñåÌW~Tz¨V¡ôú°¿¦Á¸b%}Á3 !BÕôµM',ÄNze1툘YZr’ë9îød4ó_e¥S™ÔúéC/s-½HnD/É_WšÌ笲DNÛjטá=¶»s²—ÄŽ÷N8CÚîP«8†&"•ܺ#-X¶ü=Š#WÌR«©%ˆn)çahßϬ÷Ù|/^®`».[çL÷e>Ò¨ŠHqFQw'Ô±'¬ÐÛß5¬šãÈ;ŸûS< ,*…Žwˆàƒe,¬ 6áǨï~ÆQ*=·»nSmQL†s+•åª'䱡Õco¤iš|@Hù5áô³LÖeSEå‡k‹^Cèúa<ñÙ¤g =|âi¢lSjv]e ÅÍa¤˜`84eŽ Yç ìñ#2o#(1ö(üV qš"à4ÀDÀg*æ!Ö”ìRµšÝ©, B!:€q*¢q:VqÙ†ª&¼»WŒ",—ÄU…„¬¤ÔÛ¬ƒb%;aSÄű6÷+±•‘ ° ¿ êœâ\YvlúXè>É"Šƒ´lå#Ö¿È©Üâ3©g ð6c1q¢/¾0›ò="¸KÐÕ¼?Ll„ŠwÐMè–äî&žVw¸ž#Á,\·"gä×e[‰ª¾y;L"Y¡K##¦‚‚—xé ŸÒº—9;Ñ P.DZ/³lr¹ Y¶p:^UmAsñRYP¦!r‚»äIß.×~V ,Û[¥qÒgó\|ãò7œæÄ}”k²:„Z0²Xœ±„[°Y8ŒÛ ÃPMsZ#ÿ\þ€D. =Ëh~TÉË쟿âÝ£ì/‹GUŠ}!¨Ýôþ´•õú—ZÍ*ÇQëuF'ŸNÖBÄ©®µDU«‘{ÄØžX ŠK\ri©½ä$¶A’=ro-˜œä,@éÎ9çZ7¶;–ÒÅw½oÈð‰ªHð#à´Áš„µ@Í5ðzuÖÐ!Pù„’蟛ªXónVìÃ0Û8:V¶, žWÚ ‚õ‹9§^ 3íȨ(¡âSÍäT°!­.çñ¹&~Ú™è|æÄ© –*qN¤<ªãcbÍÇ36ÉD¬ó#qS¥Zõî2s5î—–[!ÇQÜ·šÐU•¡¥9j9–Ãs µð^CÞ˜•›ƒTI<ÙðGgWÔ}»óŠ9ÙwÊ2>[µ¥'Á§–¥7ln0â6ÿ_¾~«g4kò†Â…Ü]ê¹5Фީ¹ 7Ô•qÕ¾œ‰(D©ûˆÔ¹C¥/'ˆÇQe_¸±ÊôNG…¨XcV3õÈòËw_Xª +²™›È hæ¼qÜù­§/À<­ZªÁ ¥`@—å]úšÎ©*^!;d½ðê& •¨Çl@êuÆ% ¯S‘Jš†F¢*…y45¥Â8ØœQ¤Óêc´®š“!§7ñ§h`SWÇèPÐdj û†# £ów™+²ÒTÖœæ1öJÏàXA¾¶îKuCgìQï?髽¥GBI‹†AªX@Ä™mo¥‰X÷Ì;ue|:ËdÌ!§E*}í¿RÏ(îu4½!}R7©K“‡îáÇ,u-"ײ€B„7k›i1qÎT= !E¼œá¹ŽÉæw8ÔñÄ‚°xL{~t×ï<p2F!{5†cÉ¥è¦9;ˆ`}×$vа¨!ê ÔE©Žæ Hp¾.ÕD²€õ©d½kôÓ8¯PB”®/1ðl¨Ì¼ã‰ß‡7hp6¾’wêÀiÔF0!úˆr8€r¼Êj•úGÑã>j*½*õ‡p#‚ÑžGŠ¢%½#ÊtêñtÂúAz½ð'±÷ëy<3 ßeºÙ»ÁRp^‰I·gå_<íœÚ f…/AÂVb]‘±íO¬Z;eþÚµv ºËÐN^–›{ñi¨¥of—>KÐêXUà©r ÃÚ=¦fÏcµÆÆæÉ&¨ö¨@»ÉX÷4ž(?É@­{{2?jÎáL®RÍ+B[ñïù4Æðo= ¸’¤¢qÄÊ!äÔ„Qœ=á¾5™ æ›C;»>‹|N3ºÉkRtÚLÃõ“V=ƒ`œ4¬%Õ »©¡e+B ¹P×51¨Ò.3£ ¦CwvUjyf#g× Ú*U£Í£a²#Ò*´oC%Šx51NÉÑ%òª1§:6 C®ŽÜk..–ÛÇÁfÓÕèÀt7¨i’SÍâ5L7Ž.°®ûÈòšÍ[î$þ.‹5šŒ Š=˜ÙK!gäª ×ðI$7{&\‰² sK.ðÜsa³`¢,øØjŒÐ­ÐÜæ%FäÍñ.eV[£æž™!œÍÑËHs]ØÍ °I4`ilùnodÝs‘ Éýò"‚Óß™#"á{®¸$Ñàÿ<›'˜&ìÃ͆ÞÖ¼I³œ¤‡×2þ38ºË qr4ðŽ®€›¿Û¤ˆ»”ÁZW ½…²„ªa«ì?80%‹.MPåX¸Z`TêÏ©ˆ uïóˆ¸ÒÙ0as>)“½ô§f˜E%&ë»®¢óhNÌñdÏ,IŸÖ(µªÊÓQ’ÀÑÇò 3ëKÒmPA¿&|ñþ|JáM• ϰ×@îĸ9Vׅ̕åÄ-*$š–ioB°ÕŽ Îj 1ëZ‚>¦î¢ö‰¢ã&í#¡(CRy\ØT»[–k¥jA²•KYîIñië= Z†`Hf}+Úã U0í鈮Åzc£†Î5ªZ[3µáãqàÃoW„8ž÷芲R^{ñÇþêowVÿ¨±z¿·úrMY?¤ÌžÔ••e×iCé•uG¦”8³Ÿ™85dKÄpüt K#8wN‹ïóTY¶.iH‘>exaŸkž cY}œ ”õZðÐ@6°]R·Ö-ûÏä0*ðÓœ[·z9´®Ÿ¡¡ßEswå[lZ7+´À-–¨Å …¹´\C\ŠiÛõ¨F`M½–sª”`y=q3J…¶j]è®ÐµJ/žŸ¡Ò…qî¤î÷ÒEÐ]…¹ì£¾°?µ@\ò³Š=Y;ràíöÐó¿ÇsÝ)à)ß—°'D8{»)åÑÌ_>ê–'5´ˆæ§?¸’Í 9Eß¡34Í Ûݺþ²Ws·¸Õ9#êj’,.zXffgÎ…?5ij¬ ¹à³:o},QH ªoº vµãÕ.iŠkGWT 'É‚€ Yå Éð4 ä±wÝ5;‘H2IcôUÎù« ¡Æ{»T|¤ZTº>ã]§h—E-ˆ³ª–XÅq!³T‘¶'{–)‹cuí©IR³ðAY¾VâuMéßjt 3Q\q5s ׬UŒWû?󞣾ÞhûP2CÎkWÑ»xÊo]”æ¾Ö‡À¼–螟DËÍyIl>•›(qŠZ8ásSÈÔÓƒlƒsƒáŒ@¼djÞ§ðeÿºDáwÛ=vÇR]@û¼I!±Òìpw”” ]=Ù´Wco0мŽÖ:é[Ól_¢åÜì­½fïÎêÕÏÍu3Ð@Ýê§ZßvH-z`Oyd‚Rpñ¤¶ÉuZøq/Ú?àU™ûš7ë®Ù„{Nä¥\Dî$v< %akð^—±PÌÁ=×ÂlËc›ÄX¡fxgÓh¤1µ ¯\ñ‹Hš~i¦\¯æ”0ËËs[­’±ÕÒÇFÛí/ÏHȘ9̦T)*[ÑRdÜ“ßò_¶ÍÉe(H†t,‡Q£Q†„ã>ÞwÇsùréIxdÚ[¨*Ì­¿\Ò?›½ê:I7ì󀡈áá¾BK#í²J˜#å’‹’ p,Ñ\¥]‰)Ù©°^“°ÀéÒ€ª°»ú*&ZB^U5¢¥g͆¬¤ì?VªÇRLæ2Œ/°$ãúç¨EcóÍÒ6YX™Fc4kö $C4F ¿«‹Œk?Ä¢!›H„‘:ýT)=ƒAúÐÚ_­FÐ(aD‹,k!r¸f€Z˜øU=N»Úsš,—Æý`H¬%}DPk\&M⌰Ä_xH0¦—»°¤a^Úð²Á.,˜³\¿àlÞ{g17¿›`êjÒÞ@lƒÂå%·w©ë¦×-m>G.x‚tš„Zë!L(X!°0lˆ-(¼gQÛrë-òØU–‚=»ÌÊ ×%»©‹S¾{)ØÞ¹€Þª´hX4Á“°·û¿Ø3È·wïòaŒ[C‘í› Dœ, d"]xAÜÂr†ûZK {$3~¡“¤*’ÒoÐô‡ñ‡†Äù3õY„ÿ„{0¬wª£ÿ©Ùhµ7>i6›íÆÆæF»Ýù¤Ñjl´[ñŸ>Ä'ÿIFПš-ÿt­Ñ\klxÍNw}£ÛÞÌ‚ÚwÓ^DÑ«žX©æìÿú½º…“éä#C޳Â9$a/Æ1òÍ6æˆ"9˜5ÃJ¡rDN¢ÒÓ2«%LAI¢L£ß1´î‘º[ªåRG^³ÕkÞkø—8¡êIÄ *'oáËÇ 2qBæ´ì²ëê*W 4–kÊüäL|–’¡Ûm4#Ç·ýFPâχCǤTÞ¥šølŽ|Ø\u½ç„¬“hïþn]—n hÌx~Ó`ÄðvÔn[^Te·Ñ„Â_Ôj€S[ÔëÑ`< Òt˵ÃÇMÞlÝ[šÚtÿï¸Ydwh_Œ¯Ó†ÜÊ8ÛØ¾pdxe‘ÑäÛH~GÑx*wê,Ë Ømò,Ò#Ù@GÛøCÌŸg®8zŧ@Óe CÎJÝšÕíuóô¢¤W) iž ¬­ÒN¯L—Ê1òKKY5õ=,ˆÅ+Y°nUW™-§üF‚4¼<4 ³a=Ãߪ•ޝ W,¿QÓ•®ÄFJf#‘zbFÏûÿMß.ÈãÞÜkZQ'yqÛVY^¥á8‚sü½‚ÓGf?-ç²c?ec}¯Þëzé,©÷Y¶´Þ?¦n£:d§yж`]x( UñÓ aeµí„mÚkŸˆ‘©e®lÎSFà5¯™÷0“*‹€)Æ ÕÌ!¶eWr@…ë$DTv–LFy—Õß´ ÃíïÚâ]¢n±f‘ÎÆ)/ñ<´q~OV&Ž!lŒo»ÁY›»\#ÄñÆÌ áŒëLV!—…deó˜%®+uÚ’âº(Ãmµ•Ë¿ßE\OLÓù8ÏÇ ÷¯w˜Â™k=©æª£¢Õq̘ŠógWH¦|[Ÿ›¨1Ê“÷ÍÎûZQ&þ´ËAóMÎ4FŠ×<3›3—WöL³3Y+A™ÿò‚(ˆYõñs{ŸEú?ö‹zŸøïÍF³Óú¤ÙØlmtZ­v{ƒðß?Æÿú0ŸlýŸu;öK³µÖ¸ç5×»n«UˆýNq¥n€øž4pßUì,G'•­ã`SF‰·7¦;m}nFÀ|8®àŒÏ m3ÑâôÒ¿"¥#V[©y+l{§o´óÄTP{AÁûÈô¿÷ÍÞÉ‹òoК£]…ÿ€Aj öeít”z¼U–}bˆ$u¬~–µÊ•>È%YžÒk t.÷õ4,Pì)ùj¡Ý¿9¡«Ó£¡Ær‹ƒ™ˆ´()l o†¯BДÆÁiù$œÛ°1ªÆÑx•®è,àÊE‘"&¢°e^õ0å:‹NŸ… U°õd¯¹ö46 r{®ºþ$u:~è5 Æ "-¢Ž„0´ƒ»V˜@"ð¼rÍGiDÝ©“9|2ò<=Ó1 4N 5ÅrÝx•i¡ÜJ"Ãt™(ºïlàÏù’DÜ…Ùt„nz„A”/±.JG>¶<̺àòâËpÆhàbáBAbU3ú~XîX]-‚±=<¡{×U´èfÙÀ9NÿÕ–SŠqí:ÏrFñ%S<­y —N÷މäĨÎl¹5ÕA·Ìå»wé†ù†U‰,mªYôÊ ìÞ›ú3q(®³3 ŽòLï&Nêi‚ÕÎQ2¯Áñä9ÏB»7÷öa"ÿ…§û‡i×ÞÓCÎe¿¦¿¼6^וa-¡~ÕÕÀÒiÈ4t˜Ë½ntÂݽãGÀº[ º·G€³šE`e¨Âjct³ŠTt²¥–‘IL‹ž>?<©|^]Ê8”g¬ë;Ñ,)Áµj¡Ý.°Øcáh³Qª’ÍôäX™6Üó¾9zúü..W¯#þ¹CÒA‚d¶‰ßµüÒf~TSŽ·Ûv¼£§×¯ãhlø}4ëûq~éÿ~¿{ â?w›®þ¯¹¹ÑØü¨ÿûŸ¤æï×ñõT~ˆÿ®XºOb5© ÀÎw"ÇïÇipῲiLz‘Ç“ïb *YÍ‹) pHha“C1x‰Ÿ¡OH8 ¡¿UVHþÌÔ`": b=ÅæÐÑ¢@"Ko0/ýéUL*|E xÊéƒà:ÞLI«ñ+ÞïfA5"®K2êÕCM» mçoú5LIŽh ‚]¥üY|ËN#%IEúÑ‹$røË-¿ fÎø˜"˜†u+Ö¯ƒa¡ò–hà#Ýp¬âK”DðôÌ$åHN ,Sv‰ 5Î"¯ëÑørÛ½—ÒŽ¢Kµa÷ ×Sj Ba,¢N¥<›Ö“6Ð ««Öw°¢K6[tjŸ/áåfˆt%O¤FÆþ)Ù}Br5 -[Ja:X àØ¥Â=ÐY§‚¥U¡¿Áklj¹Z?f•ázè.Õ%0O"<Í3È„ ÀG(Òù4I :6â˜Çj¾ ®N#Jºk²Q¥°Aó‰ 3ƒ­©˜GÁì""Í]Y奪IÁîä ‰°‹åDü“ Q)ûgA€]6ÚJþÖÐþÄ ÐÂ>- nÉÌÉ ß–ƒÐ/Œ+å.œ+u   â®Ó‰Ñ0¢BÄn8$%G}y„1ÌU¿–¥îÉ×ÔÆ²îà2ÝÒ%ªñ0‡ai öªž¬bù&K†¬æ:Afì&¿å£õVæ"£ÄG–m¯q9YËcvÀC¨Ô¼Uw‘é[ëÜùýóŒ¥ÍÔ1/ëéåb/+—€ŠX$D&¢ÞQX’k”΋v+£¨Ã9ÆÜµ ®S LcEz˜ÊZåÅ{/¿xÿU?×mä‡UÕÖ ¾æGŸ¯Õ¼òJ«œYá×ry¬µNj±ÃávÌ.•ùej…ÅÒ%FÃK«Š—‹È“ˆt#DÊ&ŽÅ(>uÈó!Åæ {ØœååfwYºï‹D/í…—™ÜNk8£E™ì*U¸Ÿ¥*´»ÕåtŽlç ŽŽØV½°JxY·wN¬B8Ëm}<Ìý¡|œÿVEeUŸM†õÉÅäFu,8ÿµáÔç¿ÎF£µ¹ ¿F«…>žÿ>À'Óþ#9êö‘°qo­±é5îuÛ÷»íN®H^Q˜`—ïýXQ酮˞4Äî]‰?$(ÖÆ¹Ÿ\ò±0LoÙð*¤ÚÌ@¼«¢>µÃL™Bì! PYFÖ!Ã!+̱zr`E|êùL•½£¡±•»jÕ?÷V½•IH!3»ÞþˆÌ`$Pµ8=6^TÔÃpüŠDz%3Ø®…×]2©)Ç:ݧ,Ì*ýî¢Ãvµ§ «Ýµå£2!ÔÂÑ׆åL¢0,ÃzëN^Á¹í0ü*° raƒ˜ ƒÖŠé«1¡pÎeÛÞ ‚Ž5÷E~E{-hõ¼‚ÃT·Q'ºžãr• ^e¥§&t-r¾Tz<¿Bñâ’J]óÂzP¯yÊ  æé˾šô^°ükÆj¹FT­!&¢v¢¨­zLÊÝi˜”¯p$kš—ÎjâWí84AªIÄÈðuï0š‘J±/xîÄ„á 1K-0\¡ N@™ÓxF8¾Š9ù9ÖWB HçaÉ»„ ƒóFÍmœ 5ñÃ뜤}¬L·Uï<â>6´£4áEYŽÐ]ïËmY«ák¿ø°Ä½Å”«ÔŒm½ž¹\&Mf™2Q¶ àîƒÓ©·v­¼lÔ`5j Zµmõ(Â3I ™Ð !±ñ fø„Á2ô “°.‰}ùì~J"ì_¢uÌd¨¢;.mA’ÂçÜ0Õj]虎v¯]b螇 k¤–D=öòÚÒy…N†JR'÷@^ÿÐ[⟩Ïbÿÿ³è]ëX ÿ5Ö7Úèÿßi¶ÛÍÍúÿ7›å¿òÙJ:þŸE$í­‹´·N·Óèv:Þ€€”XÜóRqN½cùÀÓãùdMg±|HJJ }Müþ+£{„ˆÓ«:4Ï×k>zßîï?=¼C˜Ô½ú›;w¶¼}c,ƒ €ðT®GS”±dÜu$Â;¤CƒÕFkµÕ±Š/mÔ›Òh“è¢J\JéîÂ05F¨¾*5[íNçþF«y¯ôæ”Zÿ@´µ[®×øf§“»þác­xÞ¤+A¯sËíÈüü_ÿ™ãOáøÉmÔ±€ÿ¯þKc³ÝjuÖÛ ºÿm­äÿä“8ÿ›§] cî›÷½æfw½Ó]/výØÈ÷%ì@8SQÒ¯¢9ÿNcT:. 9(Áp’Æ?æò›ôè`ãXÖðj[m|¡”¾lÛÌ8b˜í3,@›9£«òƒÉv¹® É'tLDÁ£lbgó!uÆÑ,<#5…#„ý1ÆòúÌ>Ïgî_ŽNãAÌ¥ÁAc†òKXu\ª©¾)ø†8V/f³É*&ãâб·´m~¾ bÿ‡pŒôO#tz.±l!¾Š”­{hòU»i-Üü@ =_AMUå1Â'ö‡s ítœ£ó¸ÅÔ¼“ 1ŽÐ[½æÁãú9$ý ^Áɑ왾FÕ4„“£*æ Ñkr 4ø†meÇG|Ñ][3¯°À5¼.ª—¬Áˆo%&B½h&ÂâRܪþ ÒÒˆ*ö§Ñ¸´ÿÂÁ'Êá½™¿BÂÙÀDIxF8,¢$µÆ–åê’íýZ‡1²ê$RÑcðÑÍß),/ÂÈd—zÓnìmiû™és²µ´zlÒ lM•ìn,Ä.64ÌáH'æ˜èkxuæ® r£INÂx×2cÍDÊÙIŒâ|ümè­œ»èÁHhŸ) ê„Wƒe,ª'Ñ úbézf‰ãh(Ë@± }è5É6°"°ÛзT÷ܺ±µ=ÔIàÕ{8 *HØRÙ{z¤ØÌu²UKUëb¬Gô`ÞVÐå2"9jåÄ @CQ² ©7Èi©è„³H˜¨3>ÚQ§/i é–Yìj}PE„Xw –+§=lõëì…ã×Ñ«€P8˱Ƶ’.ÆÅ]Q³ïPñ=—±fFºkÍäð–ÄÃëÞ`dzæ%U¶¢|ùÊÜJúнºcÛ¤¾ §“~E­Fø^wÛ„£Æ¼÷9/Œz&d¶ë‚>d¯r5E ˆ(ë ÑðA *í‡Cv§”qu[àU°ŸUÃEl¬Ð_îî~SÕLàë¨õ£üäËÿ·¡ùáÏBýÏæº«ÿ?Ú~˜Ï–%øß@ùÙšŸ ùŸŒŠŠäÿŠ ì“\ÿè-ô*˜Þª èzú\ÿÎÆÆGýχøä¿ü­÷ãwwXÄÿ[MÔÿ¬oâ·vÇs³µþ‘ÿˆÏÚç¼Xãͨ¿È&‘ÿ¯5×½Æf·¹»rÖш·ÒÙ|&ټـ,ûpƒ@/¹Wýax>îz}ÂßC±Ú¤¦ÛLxf]¯ÙhÜýè#ôC|­ÿ÷ÿƒXßëäÿ›ë° þO³ñqýˆ«ÿM:kE Ü\k݃¥ÚmÝï¶Ž8x- Å L º÷ ­ bñøV¡àtüÓPÙ8Ö'‰Ó³TÓÃVØÞã ý_=çt+FñŽ/#–=à‹ùy9Q«\)sðØ+••Q½eïøÎ¤‚nÁ®Í³•±”R·Îq_ù% ÒD#§# †q—þ¥Jk2 ‰b£3cSÛ°=««ÊÙJLƒE>Á29ìL³ —iaxS[ÏÒ#H¤XŠc£‡3ÂiòØî?á|츕jl…U¤TJègñt÷i×;¡ˆ>¨RÃɇæj¯^#x3 Æ1Ì Öp¦Õ‘8YÖšÎFû>ûÅ¿!%Jsi\êÒ¸®¢.Ö`\½~ÔVš|s´·s²wŒyu’aì…úѵG=TµÑ¢êí“Á’¸”SR•Š'¨­;$øL‰ÊB\ýø­7D,j9tiHí|Ï„R1b #—ì}}"‰¤\H×·KëÓ_VGÖµ‚’p<ý`ÿ˜}øîT=©ÉTµª|êWÕx4ÛDa|€-{ H£z9Eõ#<¨àÓªIÐSk»ìhY£ZMÐöï}9£íÙøÙx ˜¬æµ:äümòÔ€Ožìž0äÄñã½Ýš‹{ø™¼ñS\*ùSþ¦ *cpßëÜeê&º˜nÄ{ŸB&àû ¹: ]Û·º€ÄEÔœlŠQ. °«P@F Œ«ay†a=«ÛÎ$° ¬LY)ס¼Px¨ªíACzðDÕÀÜÂòÃÓEÓÙ‹Z^Îëa…5R°§Í§þj‚­¿‰W(ü\ì·9V‰6&SmI߮ѨÐíšndpI w'“¨ÉÇêèÚ:›úçøš¯é¨Ò”OL Ý ÐaÏA} å‚Â.óXî–všÆ±ªæ oHõ%o*¬däO_a°T¬¿[#¡k–a*‘¼¸Øí¶è÷ ÎU™rFÅq@Yžq`Ôè™r+åO‘yþyd®;éå¦;t¨â›42Õ§†Úü Z­R©fq I$·Aqi/êB{#4éFIX¹Ô)Z?Æ_};:Ø'.׋ÀP X.¯°A˜#ø=‹ë…#‡S4ùq$â_èã.ÑÚ,+ 4K"ð–xQ¤¡hè¼ÃÃmªq«Ù‰¸5È’)Ël)\v`ƒÕòG-Âu>‹Îÿ·a¶ÿ£µÙÄóÿæf«ÝXo¡ÿWc}}ããùÿC|²Ïÿ– X³³®âÝ[k¬¯5î{­f·Ùìvš…v`{7 æ"åä> P(œ ÕsçÆö_êˆÿ.&`êä¾È ÌÕZ¨svÌg]ètQsé*mb…º } VŸ²è5‚Žp´YŽr¡ 'möž¡:°ix:×¶- Ò*ÙXq@±¸^^Ê4¨„ÝyŒ¶¬áx°X)Z»Œ÷:ôIû2~¥öcÿux΃Cg|ŠiÆ/Š&(\áE’Õ$%*ÆLõ  ÖñE ÁøÐOŽ÷§X`úÒ2£XX„¬ìš=«Êanð’긘Fãh£Í;œÕ½g¼§NaAè@dLëBà'øÍ"%G/‡0v.Q¤”ï2Ò©–jâ-8ÿ|ÿ>„ÿg§ÕJú66;Ïâ³åü´  Üùâÿ×ñη³ÞmmØ>±±/axß}ì‡+ÁDžþhø!>Éõ;ùì–Íÿnâÿ¹ÞüèÿùA>9ãÏnÅúg!ÿo­oRü¯f§½±±¾‰ñ¿hKøÈÿ?ÀÇÕÿ%‡ÝÁn®5äÚì6ïÝÜü‡ëXÂúg‹ yU„©Ëdèa<[ ˜…“¤#¿éá›&U‡zÞ è|q^iiôxy®¯a’ ûVqåš×³~ª¬êäŲ.ϯQæj3»¸ô‡¦××Ü1ŸÀw(†CØæ0.87ÀgH'[ ‚ݾá¿5o…ˆ-ÆQð3ÀHÚñÈQ”òEÌÊh>„¬R„¯(±¤ª·í55ÉUš ¢WÊá¿2icRfvËν™]¬c/•,6¡ïš•þˆ/= Ô E87,ÏlcT” ›™’r*HT1 +aûU<›)Q寵 BKžu—ÉoíKjÓ[nÐvÐÖí¡åÁ•ì¶8%ü.ì/|w‘}½ÖVx |é•é–çÈ*¼€Æ÷gi­TóJ«ˆŠ|Qå—8rЯ땷qåü§|ì½K¬·Ù]Z3£– ÌâÑpjxkü2³eÍ.oÿo‹÷ÿÛñ[xþk6þ -~ôÿú Ÿ-gã/ô[Ïòûš2&Ž P:¶¶{9ª‹žA̓‰?Ma>f8ƒ‰§ýàã±ï=|­èìpøŽu,ºÿï`üf³ÝØØÜh·×QþFðqýˆO¦ü/ÃΊ uû­Ñ†à5;Ýõn{#ëö?çö#z§îßDèToYªä_/DPN_ ¤ã™Ó=5!Œ|æ$£Wy|òä@asDÓ*Þ¼:¦Waæ|“VUô²ÄËXÆ\KVhv8÷„þ078{*˜|¢/Ï$Öú/‚«®·3ŸE«p›ECsòÙßÍŠϽZоpœ9þ¦‘îá„çcD&%}ïw2°Bç·u9Í0¾@’(¹HgÐÚ Ž!Aïiç‰â^½ö§ý j÷lŒÏgôzcý=.—‹ºŒ½Œ¦á9ââòµ¾`¥”Ñ‘A0s¾÷::üBnâÂñUa'öwiI`¼jà¡‘QÁÓ¶é…éÁ 8 Î`½ŒûÙceÝQÿXúøKj’u4–ŽñŒ´:qÇêJy"Ëf´}5Ë_%™ÃßÌ)K&£ œŒ¼4_ žRœ*5‚7AV‰M4«H­¡°p¾u™«Z ‹yì10Ð vÙg×ëÃÞthyxÙƒ“·µÙšFì™ö÷h‡®üÕ˜Oˆ§6S§jñ–aB±÷;|ô¶> ‘éëvdWþ@…]E¨Q—)^˜÷ë(D˪1ÆõVO‘¥ïÃùQñ°¯‡þ9 /2@Ë3B×±¦øC0L÷]iRdþYóð ›§žT“aËãåXÌõ’kƒWß±QW´Äv,ŸJNÓ›;TÊñU< ·ˆÇÅecni/ÒaáåG˜@ÜÍ•þùk[ÿL¡ƒ‘¹yþpøƒ+a`0ï&a€S W™üÉFò±ÒYmh8tÙäB-GÌTw-Ô¹Ù?.ë…âóÙɾçûŸv»Ý!üÏÎz»µÑlóýÏGÿïóÉ<ÿéa§à=Ëþ»µÖla<ÈV§Û^/ÆÅ2®s”}´«lŠMÐoÄsr¸þH|¥ÐcX)3ßÔUæ‹5.¿CÔéÂJ’UR•GªÒº¹…B÷4Wüb_º•`:¦ê¾…ø†QÜëŽÆÞ Zum{É»+Ú“1ÏudNEI ­XÈTJ!GkÛÅü©åŠ7$k B—oü@ÚW*–·uê±4ô°iÃÿUÃW·)oÍ+Õ°æZÉõ®£—ÄœÂd¨íWd(!Me…íÚ\dB!©$ëiñ¸©üÝVT”+ÈþÒ /NM|¡Š xÉ·ššåÏ(Œ{‹‰“l^F–ªròªN|I~WhjK$Ej¢p¢^«M×ë"%ù’ÂäDƒ ‚{aMh†)Ø9Ì-ˆÏ×RJµ°½±4§ÍCt3‰ÐçŒ'â`†: µcÄkx½e©g×öÿgïß÷Û6’}qtþöSÀŒ’ E]|Kd[ÅV­ñm[òdÍV<üA"$aL‚´¬5öïsâ<áy’Óuë®n4@Jv’™½£µ&–€F_«««ëò-s/ÉfuM©éiƒí›æ/Ú¥^óe»ZùK7é¹i:Ì ü‚ɃzÂÀs¡(×Ï+wƒ¸IM/ø%´æZ1Uïg³ Mx>­ðʼnfþ$¼ Ë÷’/ñ_ xάŸêK’¹°Ë—¨ ùˆ3Æú]é³I6/!zÖ\ÈŽ;ªÞÃ6e='©Œ—Àîz…!‰ÍpŸxõ[t8±jç½lš÷…#0 Fšà‘%³†ý¸–=8°G¬Ý¬ÆPûLÞ7E)bUž~cù :Íš¥ Š«¯•¥3èke Îx̹մº:7 ©¾yÓuwÌ–^]õ•..©XÕ¥…Õtå¾#ÇÊ|Œ3Hü ù’‡]œeÒä°Øçx½¡xYì}׺è˜Ý“Œì[e%Tw³ë…´^1P6²RÝšPØf© 3:¡$Æ{NH¾Nâ‘Ðv„Ô±^5ñ/f7™D5ëí|™uZ€·£å¹–w†` Bè†÷MÀÃUŠ üSiÚíЉF]7¡œe#Þðàá$éÌóˆÿ1âfµ3·¬œ©š‚£%^‡Â悲Kˆ¥ªxGóúž/4z"•,–ÌøÅ+ôªà—V$…ðJòëq¢Ž\ü³$97·0€ÊÐo˜òí§cÐ\e8¿íÉí 3ñ³õ,š{{p¶n¨0yª‹2{Ek° ÜDwù…‹LqÌ€_U¥o¸b¾Ž{Œ„-ÉJ<h¾œµDô“¶A1Ž{º§®Ÿß²9#â4å¤ãeÀãé´ïæ¡*¾º‰ m6‹Ïƒpš*áŽ%×ÇgEQflzˆÉ°Þ¨j›-}T¯%@N-É;…I.l%@!)rÏ¥£ ¸GBÝ’èÑ«¾T³:›fYdF¯vŸZÁ ÏCfÑuÈ£k^ƒCx_ YI«ÌÓk±â-N‘v§bþtÚJ°Ÿãý3‚À0/q×"ÙÀ„ùÇ)heQ‡«Å««`ïÂp¹GLv¾ 3#ðßÓô…ÜŠUŒÔ¹ªÙxyþ¿­%bG±ŽzøF|‘›ÑpzC nØ´1òÒ’ &kTW}¬Æ’U0P¹Ð^•LØo{¹ˆÄI+‚­uuyŠ<ýŽm„î6٨ܗ=×4]ijü(r滯,~8-W> ¢Ô„dû¸8ŸeN>ø‰vNç¹é_>6Woj?ŠúK…ð¿°n´„—ÜgA6gj¡¿ öpâIVÑ¢ qm=Øõ†g·­­[¤§ÉÂײEhΊJîÑXšÏ´JuVD¾Y!ñÅt!{Ïúú58w­ÕÀ˜#¯RÒ»3s|‰e…{܆â=€Øê6½Åm{‘¨º4ÙH@‰"©È0p½DÚ½54ÇÏ-$à·[î›eó‹?=@×/‚H…)ÅóNî„göø\(v¼àNÙY  úå£äf ZFDJ[‹]ˆ Š0”36øÃŒ³ ¬‹ìfÂFQ=¬Û¤|tVÌGC¹E‚N<µZ ³~°û ¨Lß!|ƒÕq@WÜ?G†±cÀ-šé ó£ƒßK+CˆèÆ%pjîÙ9d]‚4-7âæ>¥ŽÓx¨ ^´'DP¿#êö„oÓˇU‹^L¨¯UÚ[ O·bîl÷Œ4åLcÂ¥à¡âÝÒG¨×Ž…èÕ×%V6÷¥ÇŠ^¿|²cXQ…±ïï$r®ÀF±ÒD/±m™¿âL ?t¹XSàxÙ„ê*šâ•YN —O™ÝKH¸wâŸl@ûÀõ{".2/pkq—=™¼€m{‘—€³=K/!€"æ3©0Å ŠÛDh,BÐ"’¥úÕòÚš0¨§¯!> M}4dO€ú™f”– iþÐYÍ´â(EéM쿞ºÃiÝ.™–QÕRÉh˜êg>LÅZÁ þªQ¢UT¦TÛ …Þ—iÔ#«¾y¥p¨3ú×r¯Â…msu,]qmLV¼ò¤3gä¡)ù–sþå"£;­[Õí’e£ïj¤%¯õ&mº;˜­ M¢\g¤ÄN²“YôÜKr§‡"ðCºih…{xq÷{"L§oŸÞ¿Ï&®'Öê/H]:jë+‡ÇL›ä¾@çïÚ£ÙT–^[Ëi1+:u³˜íª²§©Þ¬¨M§bô îF¼žÁݨéjäïñÚ[Q£ÜÚ°G[µ†l{>ø±¸±ÞžqhÙ=ÿ€N˜WL×VRÙ˜¶ÆâJyf—[ºe•øUÿ‚êQ‹ÑÓì]ŽwW:jÕðâ抯:¥Ò¦Kð[´†šÏßTØÐpýn'ê8hq¯r‰l¼¥ ìtí ß$N¨#¿æÌ—|)öŠ)KÈÇWÎþv©n%µÁº'xæqf³÷c)/ÓÓZæÐÐþ?ÍÆlç.7e?Ïá>CLÏœ$«Q6™ ¸ Åg!* -œšF{4«™—2ø0AÔ¹ÒX”ƒˆédÀžß®`« ©*z5rJx£:/ý&˜d`fkMO­jÕû"¸Ú†·)ß06Ht¥ÈP”¬.!1 5š5o2XZÁ»¼2„ÚíÏ#re_ˆ®¯˜5„ϧ³âUeøc`‡Ê4Ð.ùêFÀZ¯îÕ\ó!ué2ü`‘ðYsííF8’llÄ@va¥þno~¸$—{•Ábcùu¸ö¥‘ÃáÚ.=æ†;^ÌǪ«sÛ¡iZÆk‰²FÏ»ÊHW?f3º•wÈš^L3ÀÙ>™fåY—9xdW6“º.0kKu¨Iå†YªÑìQµSë}®LѾ/„íS½•ÛÅ?F½o¸j«‹üõxÒod¾#U¾¸ él >ø¿Õ©ó*¤ƒ¹ê©< )–Ù}“+{fŽÏÌ®œfãŽO]¦#,¨€°½Yú–70£#PÕÎÍäd¬%f7duªúDWUGødeŽ“tFÀëÄi)cŒ:YVqRV™Ô¬*¢Î•Ö¹Ò‹¨k­×Ã^ÜýÖïgW¹½ê¬6ÃizzJž£ü>–t4µ¬™q¼Ñ·}ŸÕ&?T•7‚vüÊÌF°¿”ùhÀÛ½øtK*ú¯ÊžXïî\ïëvÉ’w}‘מâ' Ô鎽*†)¢Ï+Ú’ê4Ñ|}´ö£ØõSÓYIÕÑð›´÷Kªaáõ²bû±l¶^¤WÎc›žä*a‚ŸY4ú½£íþý~šã??GöŸñŸ·ïÞ¿wð6ááí{ÿ¹±ùþ×oòÿTé6×!ýÏ7þ¹±  ››[·×·6šÃ?˜šãí¢˜h<ä÷9±ÛG“øÏ5½Ï™QR‰Ÿtò62̸LZ’[ÅW¶X¡|ê·ß#ȈÁä¢ gγór-¿¶-Ö©— 8U›Z2Òö‹ÔÕÕr~œ»p´–5(:íöžì¾üðâÕ³ÉNЦLfa!hì¼Ú{ÉjÔØûÝýÇ;/wM@/½Nª$>Ð>%S³Ó†DI­ƒ0¶—LÙe"þÙæð-ÈáÁ^1R>è=!xp/cR?ÙûjEš( AE°§Yzjd˜cH MI ÄI $ïB>G‹3kOÁX/•RàÛÌ\•³ÄLøätžNÉf ©‘ǾÎÑÑp˜ž®w¼ ÏS b^2ÎyrpâOQ$†©cJÕ$ûùA```”ô§C[€g”rIŒý™]M'R P3æGŒ kg¦‹ƒÃÊç£QmŸGæè{|ßÇ•œ0؃¡€×>DjhÆÊÓ k˦$ÚÊ[f3¥v•9OÇùd>FBf@øHÁD…O&#Pì¾Ë¦¦¿ÃüaCfº*&=Љ3Ca7˜”sÐ Dë léÉ|:)JÎæEþ¦@YŽ„gà ëçfIÊ„ò‹ŒKÔ*$|*‘3€ecZtì×Qv‚~ÁˆðÁÚÈ-µc­V¸º‡SݦæbdFkSŽœg{‰¹Ý -ÆüèèP%Ô>ËÎ'Å4æ£ËÅmÂBÓ€’ùØR›Ú}'­B&ŸgˆMÇ´}÷\˜þÕÜò ÍX©@¦ÐÌ SqlöÒÛ¨‹q ½FbàÿÇä°”Í.@¼Ä9²ÙÍ|‚!•0PSôm ×:¨ÔÀ±1¬ßò1ÚE j¥¨@ƒÅNصÜA9üs_Ó¸µvÉ¡ÿðÉ9½h©[̃j2zñi@š’Å ½X®\*Ÿ—öT ;M™ú€»íé G'…™Ø pZ9IaÖ÷]9Ÿ@ÞÓ¡eOh(ÉoÎzWcGà,vlN/pU?[ž1 K²L¬‚8–{*²Ž+\—ÑeÚÛ\Ëïl¬µ G¦G,®· ¯¸1ì‹N€8¦JhHl/{Ÿ‚DÖÅ€„ÐÝ„ òôzÂÂÁNÓ$ì3EE u@Ç—~‹LìU·ÜÚ-»éøSu^‚¾D©‚ s"ÉlJÇ ±¨L•|R‘æ‘Ø Û›@ôÅœL ÏgJ’ÂÃØ[ŠIe^¿zZª£!ñ¢ e_i·ÚƒêÜÄ’°Û9±òcÓ“âÜzÁ’§ó’©öÄ´ŒR1VœËžà)v:HkÛþŠz¸¥Ú·ÈUçÓQë zÀéýð6h<ÖD=¬sóŠ®9ûpíÚò\°§Ža¡Ã˜yø8›ÎÀ[ªîÑQn]¦ÐIÂùò™,½›3ÎÖ6.ÌÒ#˜SÑ´ÔÎPä SrÕ‰ ék:U¾Ï`ÙÈç({Ÿ#¤˜½Í’q•VÿÕnF€øþ ÅÅÜex »@·gØâ2 ùI1y(ËHȉ‡Þ&ÌãG}Hó {c 1Ócdc؆»Ï09šÙˆäy”žœŽŠ²D7ÓŠé³pè>|Ã7c÷~c÷Jbýä糌÷È™Ù:Ù…YEÁ¬Xõ°O—ÎBûƒÚUÙûìxÉê¬XewxÈ¥ªÜX“,Ï^â3Ò Ê¶ÆD& bLÇÅh~>&r:M€ÓOÓÓUsH®§Å„è—Mí÷`íð¾Æd·æ;}xƒ»ë¨8&Ài©~Òù‘šâÊÍå'Z<ÀÏŠ‘Í„{^̉ƒ™rg€ ‚LðRž›Eëw“WæŒÆL¸2‡·dÉW‹>€ì[‡êT3žY>¢½ -Û‘U­O4NsW˜AâLÅ%Èœ×ä—½VZV²FÄm£üNç Ô¥¾†ž±V"€¢Ñ$«Àìño4®:e›Æ’a­í£%FLпmˈ¸d“¶,PÚÔÿæ0Ð6† `F}—ü”žÑ. àâ1€‹Ç’ j¯—Ç—;Iã[sƒhH5ê]$L¼Éé|·ÀÓÝe5€o.ET“{x×»„×¢‡²wfþÊBÔ/xT²‚”.O«œ%|è8l}æØÀ[baòØš}$“g*®ˆmEMä쥃­9—ð¸a¡žÂûëf'®iÓÜ~“#@5 Ë £\:tý¼.HÃÛ˜$úÚ+Qm«L 9}.;7ŸF¢î3N¤™Æ§ßï<®f3^Ëpd}DL¼aF‡¾,àù WCNhŶȟQI[kÌ×Jk­#íI–Ia–Ÿ:)ÑseÏÈh‚Px êïËsø~Êg—ìâ~Ö"l²õºÙhwc39©ŸHHjs:M'gŸg‰(„¾´•Sø6s·$R`vQ(=}lt#Ù§‡ØªËj¬^èÜÆÑj³ó ÊÝóÉY Ùp†T­9ÅØ°¨^`µð&V%œtA¥Í#®ÏAª‘Ÿbeô8Z91ÃꊡøÈFEˆ ÃñÌtžŸ£Èp•ã ϸa8y¹aø^ÆÇÑ ’M1Ê(ŽÄÅϰª£x=ó ž×`ÌšåºæbIWϱ¾y¼¾<¨oo†Y»b¹X Õs¬/¯¡¬y¸AöçF”%+U ž¦Ø6¾0e~u¯ãu†³·??ªÖxdj<‚úŽÔ7™†4ðršÑ‰d)Ë”‘}å½£]5­Yåô¨ÂhwÌ£ì]ÎÑ?ÔW(F×G-ý¾µM™3ŠlÇ»Ÿ‚ ~nµ~*MПÒÊ9Y²Õ§æB Þ±ô®µ}ðtÇ´DÕ4v4*Žßþs^Tvá÷ð"Á7Bƶ¨Ð³W„¨Z•‰5÷Ï •ÿ…î¤LÍü“k^aõÿŒÖ  \e9|>4î¡Âÿÿ©™,ÃggýjW(ŠÆïbÝR7ðµa¿³éöÃÙ™@_¢¬Da7Ü%óÎüg*%‡^Éãl$·yÃåÖ¨êèüÌ¦ÚØ3z¹¿ª_š[O0Žæ§á˜×Ü3û»…Ï£Œc\†¬c\¢¹™ǸÖaŸã€‘ë—i”G–§‡ót† Ðwh5/ò/G³£üËÓÙÂe„´ž(¶b9Ð3PåþÄ~và¥Ào%©½z½ŸI}Xy¿VÔLÖ<ììëqñiÝŽîÎkº;Ê(©v™†än=FVkX%>#Šú.ŒŒÃ®Í}‰¬tŒ’¾ïãÌ G838-6 ”®§GÅf ÅÀe;Š%‡ %•e…1¹ZëY‡úd³È¥[½võI¡¡®ƒ—¦¶~¯emX³€Ã™f Ãac8Û–æ'f_0à³ áW¨•d˜Ûx«g›M5 €®9¤gº²ÍšÊn7Uv;¨Ì,3s•·kª¼ÓTå°Ê#ôIwjj¼ÛTãÝJù;ÛÇ»55Þkªñ^Xc™¿— Í»nP_õ[ö=0'ÊNòÃߊyr^÷çÙ¬êqpq:œz!êÛk;‡éêÿ¬¯~ûæëîáßù×µbµz¦‡:‘Ju.ÎÒ¼=Ü pJsGŠé`@c„¤Û …Uܰ"ÞBÙ7ñB ñ¿þO˜FÕ|¸þ¦ç‡òzÓ¼d…î®á%àQÍl¼Ñ—¿É­á5:¿tþ–?ZOeáçcåYõ‰-¦–šûHRžçE‚é'œO„e¿eþ£ŠÌŸ<`CZÝúU 2ûÜŽÎddüáXÿµ>pAr …šÄg É›ç%††œ¥Óôx&žÛ€¿†`JàÎá' ëÏ[€3eš=/­ŠŽB‡…rq”B†LÁý.Ĥ­”Æ ns8î‡Rüt$»ûŽŠâmIjœ/Í“ð?ò-'æwÓS<‹ñ±­¼"S U JiU†Ðåt†wÖÊÓóÑší"?IùÖG\î·Ê)àìM†Ÿ[»¸Öé'•È¿¨¶e–雘jÍ^U“—kþ)eÀ0ìÉjvKV”{zݾîSÕ´µ ÂªšØ0ìât º6 6­ ºi¼ª8ý4Ýu&øÔ©žåf³F/D•^ÑLç|+†!Aç@Gﺗ´ é²Á©¼˜“?¥ã·ØµRMF°,vv6ƒ˜š9"€aSíÒƒÓ4e«ç†«‡XàÉŽ[íšü*S6€¬Úcċĩ17‹ÿ¦‘÷`šÄ² ^ hU–ylóÿº,•X EUØ I™„¸Öä“Qgë¿ËÅWú˜p”‹ØBõÐ ój3ªpÛeÉ!”-úí2iBÚwªì‚%Q¬~ùcŽfŒÀ"]8bTSº3j…àC!AAÍê1¢oÛB»ÛÜ\ðÄÃ(ÇšÙ·¨ôÓ½¿ì&í[·z·†½[·Ú-·e±wg> ñÌí¬Ax#­h$ñäÅ+Lً͇ ŠÅ…IØF®‚¹jmÉ^ †¡ŽQ¨¿0a .PéCdiÉo &™e? Яp>èW‹WÁâþ°uñvöÉò ¹œ êY²% ±½<Žn3U-užpñ˜Žîa—sŒñ·-ršÞ–°.Az­JPyS1€åâ<èÛ\EФÌKD$>ò2Í„—ŒØSÉåíÆsÈ]€P1°ãoªY5©‰ ¶ÓX˜ž±SM;H?ão 95OËb:³(q滞öãóI;À9£‚zE275àkvÝ€½˜Z-s!—$ ½”?¡WÁ‚‡MwVÀ;èÈó2œ˜ÞpJ4óÞ"ÒéÓ¢,FxXH\§çÜÅ1ŽÞ”ª 3ØD<Å”×'b6˲lÂl"»M?ZäK›ŠÃ‚ H$Ÿõš[¹Š³¡÷V ô%û¿áXΚ…’AñpÇš§èAp´aU˜T†ÿy<ƒŽrÔkÁçû\ÉoôA³”!ì&ˆ¢l šXÒ#o^ãÌ“„'T&¬zz´¢2@lN̉öd÷Uòýß ó2ÉÉx¨G¦™ôäÄðŸl8€;‚Ë«e(~Øà͆¤GWER‡årÜÁ†D:Að±qáâ|A›.ب4ìYã‹î*³«p^G~‘%¼RŠÝ(Ø~¬¡@.²Ç=1ÇeŽûÚ£Œêˆ"$ë#mÉcÙ"‡>²ò›@7ë„‚ÜûæAõ77‡Aÿå<ô«@‘ŸÔ]"íœ\Ñ}ÿgìî6PX¶4ÁÊþ qz "ƒãÖ%=܇fÎHD†I‘…ËÌUf>€šrPÆ¥Ç SŸW“ų×s²sÐ ÊÓÖÈ7ÃâxnqåKHÀ»eý³d¿@§ò1Sò_é»tÕˆŸBa½ÉËŸ^¢c ´u<Ÿæ³K³ðPß»|fnJ s°qJ˜ŒÇ8LÖ‡qP&I9H /fgP•¸aÓµÈrGŽ{†ÇÖH9™Kò t0›žŒÄeçc¨‰Ñu<gpñdÅä Mþæz¥ Æ€óAÞ|)ÔaÞâîPÏèąܹ|¸jÆoOùØz¶‰ß¤Ì:Äç&“<;¦Ž™CÜ‚¾Âíü`îÈÃŽ}žHÖ긄b*àêâr‘m^\ÔÐv’>ã`e‘TaYê.ã$O¨~›Ž«Ïº¬ÑèN‡ÑÑ®f”aTH²A EtÅ3¤ÇuñR— q<$:7¹–j¶y¨ØXBŠõ‰Á,ƒ¡d îÍ%G Å„›ÌŠ—Ð,Ø6{´Ÿœïrר³Â? S+¸àúÄC¸sÏ+‡æ„2ëï]ùMÿ÷ ÷6m@dlNZ?±¹ã•pbE΃Œ(ȉ~6×rô32Ò³ô`8so@ãSä~ø°'”…âZ†ÑÊ7Ì ÷Ç-01…¡Nr¼å¾"ËÁìéf1­ Ys;­_¦¿ŒdgþmuáøCf]Z¬ôz1:5»{‰¸×L¦…Ù#iÔÉÐ R·j%§S£5h|ŒžäYyœNȵŠÖ-X?s¶Ö^‰"’Pã|”²ì$ ¯N¿ë¬Ì43ËËg†O^›Õ'°àùë9Òö’@}ìɯÝeéú¤.ïÏHΑ¤èBž€Æô|~Ný9ÃAÏr²ìm˜Eºì;ׂ*ýý˽Q‡¡Js:}tî­æŒÿÙ¼ãgëõsnð™ËÀx-Mµ4á½.ä×°óPëJäD0V”„R.ñcþ}¹ Ð(š®4uVšF›1X§gдzµH‡¦®áµ€Ýä”%ƒuù¸;|BØújŽ:|­u+eÈöKVؤôÕ¤ñ ÑÃ)Ðìï¬ É6è˜ÔšOu"„“< ͲXõæ¥ gEWP"àÐH¾8.F£tPñ.!Eåm6Œ¼Sq¦‚hnßIR¡õ쀷¤G¼‰ ‡y&Ô&slý¶lÊ•i:Ì Õ)ùrfæ¶Â>¥†ÒÏŒdÏ3Þí„ÂC´‘Ò¡F.Nw_0( ®‰»”DÐUE‰Ç“|èB´t­ƒ[9 YÇKJÄoÅg&L¤lŒØ´ ŠL°;íž~g©Ä‹¡ÕE"ù?ðW]†vñ 6£‡.ˤb2Z¯=¦º}Ì1àG¦qDªNìð'_@ºƒÐÙ±™úN VµYiµÝ ÈÕSȘÕ2bËVK!”ù„øx–2|…a/Žv¸M„Qžå'Š1ñbÿ0™NÍ:N cËNÑ¡­¨F›Abh¤}”7’—#Lå ×kЊ!v!ÆÓzÀÔìStªÃâ”1º íù Üâ,u µzrä+¯A*âè6œ ÈŸníg*[Û¡Ð3‚::?Q±á¨’½äçƒÇ?=yñã`÷Õ«¯CÌdIšJ¸Îx›ž=‡¯âþ=1oèÕþu “ÍB¿¸à;ÃôÒ æeóƒ*ëkƒÔç¡uZL%¡çÈŸ?&»ÀO’VDÁÛbU^“1ñ./‚pÖ˜éRQ@•²ænu£»Ü°ë'‰“Õ%žŽ›‡–5ÅØË6ØÜd¢k$:KÄ}Y ›Iü>Ípæ\Å—¾ÙZ¿ÓºcŽüÐ<«L¤óšÿ›×ÖGÛ´Çr„ËTkÀ€z½$©?°`€.T6%|H³l\:‡%Ù+góo>Ž Ç4ÀIôYö†@Hí(•èŽJ•—‚w 2û3#Ò¤S«MwÖ˜xÍsA"¡tΘÂÙQ|E}#nI§Û˜wÁ¢A œ]|Ö0„vUIVù‚‰¶Xµ›ü•Ïè2-‡²=—[€ì@´ã xm:½äJŸº0~A~uµ³–¯t*=t¢óÝW `²U7¼°çר»ᥳRLzÖí%Y×êéÕžU¢´ÛAn“bâg6A‹eàfHi…8µ@[ü86‹ð~“ßÔ¸¯nëÊŽ‹éÕ4’ßJ:£o‡TÆ~S㑺CX!`-33lc6ÍÁ"ÈV•¹…l‡¬Df0ùd|D×Ï™hkû§ŸìqRù@*9õÃY:=?™»4¢ÓTæ?‚5îéGˆ× =ÞßOÊÙ%B„ àïbãaã >r.¥ÐÚpiçYKfΖ) ÇÙÉûYŸ]eÑóUaÉ–rœTÚÚŒ·u€ÒÕEv÷BÅV}<å²Z÷íºq ™˜ÙIç’RÔœ“ 8Pž0ÈKNKèa^Å,Ukv‡€"@’Ø60YH׫лΤœ QªðÍ"1 O'A0Å„I t5 Ób‰¶5P l)$ã8ÁT Î–§˜_ :Nš lõÞytž¾eãSÆœØXß¼Ó@fQjVCLH=–õÑ]Gœ0pµI~a÷ Á¾Ç4"  å’Äåû¥à ¼°,\W½ÿ<4¸†µE†£â}|iw—ª¼3¨@Ó5Ï9;õ8áIzb¶Àä' g%³Ah-®4eã⤀5þôiÛŸ¤çtKµš¯7q•.‰2øOÓlô¨%•¶PÕ†ªFìQÞIsCÆ,)(¦çÇ X†>±æ‚=†{”¹!–2²ÏþwÎ erN!Bþjô„bõQ†ª¥‚wÓÑ¥vѺàzwâr;—‚ÙYˆüg;BæUë~†q¹ärªµ¯ËZ®ÅHÏLHÖ“ÀE]Qút×cF× 6„’ŸU„ý ›ùÍ#‚50%7„°öKùõ‡‡¶!?óoÃvñ®ûòÕîƒý—O÷Ï_ vŸ½<ø›5ƒÐ-˜GþT·3Ή­ÐP\ ¸|’Ì˙󾅤sÖ1‘?­tbn¬è4Ùñ‹E…‚ ¢zÃê4:07½Š®]OOf9ܲÙq¿K|üìr‚ƒo묑ۻ¸¾LÍùG‹FGäiö~b‘ÍM½§ps’ÛÌ)„=`Dk‘›ôGßü.±ºÏÀ6˜¤Ge1v˜‡þ8ŸH;­ÿ§óp²ýø÷‡‡GÓ_ʯ־Ûþp˜ü2þeúËì—Λn§Ãàß~9¡¿a†gÅÖ‡òüþLOð©LÿžspÃoãì?+ËÿónS~¹ ¿ÌFø~vŒ̇ðOñwvVÿ÷úê·Þº5øú«ÿ÷‹ï¾|Ôï­=X}óUõÝ—àE×|Öï}wóÍWßu;ß=ê€fý„ÅF×5åÿŸ¼¥Âþ` &é´ÌÙ1@ªh{^›v¢C «›ëe¦øÐŒ… †úƒÕ7_ÿYÿýµyðKŸŸ¼ù×fïÎÇkò— ‹2ÂK÷Ëfkû—MÀùåvÍ0/..’a ´˜z¦y¬qºò†jê3£Y~iÿß/~á¥ý\+‹™Óêâ*_Þù‘aвç7@ŽñÃ@CÇ}Š.Á ÞYÕ&$M±\Ùí•_¼y Ö€.ðFÖU<Ý›T€–‘×,ÆÜ l7.P1Bk¯cáÀÈÃa€¢+ÖUBÑ»´rzÅ£Œû‰™š±ÕË såQv>4$v½qõBPåÔ9O'Ã6‹cö“˜>ð¤uæð‰%ȹ¨ÜÕúUëÒP-!@Åçæ ¢è¯ñ[ø÷ wÈ}<6á—üüþ1#²¸– ›ÿœLÁB„qÞyÁ6v ðÓQhß|ØA 1CÜkoº7Û fóËFeçíƒÀNã&Ó»ô¯ $ŠõI`ü®‹’=m y?Ù}º÷l`dރׯÈuÈ4C5ˆ{ÊÆ@­ì¥³Gl‰x†£nHpL §ÁKè<ŸIâ~5<ª dAˆö†ñ°of.˜t¯ªZÏ)¡í”]d»}:åR –Skö=Á†Ã5Wrê]‚c츀9¢‰™¥À¡cu ?‚8‹9Í"ØËÉûÔüK24¨´gø†ìç½ ãëáų?BèuR0k`˜Ç¬€ ÌT\{ɦUiC°Âˆ\ŸMüPš€úþµþî+íµ¶oX§·š?ѲÀÕ?ÉÍmf:dÄðc×]Jo9˜KÍÜ;”vÂhGØq!f7§áì5HèܼkàjitM ¨Kà¥-kÿŽ'qÔi\Ž}[0ÐÊû`XTP”¼lŸa‰mS¿æZø(ªž!u.¹ùÈ.‡ ôÑŸ©Ð׋²]yyrÕ;pLj!oþiÚÍ)4vd8rÒ 3ß6Î~:2;`x‰+Bæ:œEЪœJäxè“{Pó8!ÆÉMÒ#5j#ëøý¡-[ ’ §>6«þ"|Ôc~9/ÏÌÞ¯‰®Ú3¢³Öq]ª¦ÞÌǺ?½Ø{‚´{³©‘ªf}”–x{˜b„[òߟº¨3J¢ «Üæ§t£'a#ù¯¡Ãˆù'Öof¦©=—ι&h•/3³³i1?=#C‰$óª¦Zu¸7³ì›ð¯xkÙM:Í@xõñfòÉk;Y·š‘«ˆF6 .'˜=s©*À³à~T§ oäh¬Áß7²!eØ@°Û:öBÇ)ÞÜURåZè¾¢ÏTô^B½ªeÔôp——zÃVÑo·?=|L¶‹œwùû¦y*éZ€P&`–HéXÇ¿ø…­E³ëIâ¿÷³Žoé)æ[ñg™éÛÞLïŸSp`#õ êz@Má€!9€»\œ¯A™53Ê~¿˜Z\öH]¡ÑÀä¶Àê¹HÑ›táÄ–C„û…ÈÅÕäëÛ(i´M¯Ú¬`b5‰ÄÏš‡£Ltªf÷Û:¿Nn‡*Rÿ>ÞT\Ø4±0M¢C+>7æ’ŠG¡¹Cnsºr(òSÄ40Œœ¡’ïlK–brV VjÖg³5RÒ™K2¸ˆÄ—B{Èím4c˜``d„\²N}Ò3Ã;ßm!^ᇠ~˜ÅìÒs=AgƳ£bxùa6ý03EÎ> ów†£Ãá‡áìÃ|ô¡}å̵áY)?€réƒËbð¯ö& ¯Þ{óálÚmû÷s“Åt½ä!)žÂ5~»æ^¯ñ{aýq†AÛÔ7Aü=‚o±Ï:ÁÙ¤.ÑîÖñªHÒwEnnØTœjœO0NµUL+’n,œMs¾« MM…,¤øYë©¶÷Æ|‹ÃMòÓ1Ʒ˨݃µêüÂÖÐBu6¦éßÚþÜy¸öYZ\¬åNÕ†»‚+ÝWÛÝ?çÿQW:`Á’Iâìˆ#ø÷ˆÄºžÕ_×xþп}…ñÏ‘'·ÌKË2" ºÄ\Oñ¢LfèPuŒ^;Lj_m&ò¥@yOÁÁ\iÌÀt7O-ô¤óp”ÃT »…k ›‘ʉѲ¾5»‹‡©²¡Zð«îö‡'Ù½XÙØ6%ÈZcYøÉŽ0R¬Òæ_? ÒÒ›„ÖŽ¿ºÍâÍÇâÝ«‡WûªÕ}è|÷ð&mÿ.)M2†(q*òú=Åú¯>讵ê½ZãÇðOo_Ôÿ Ø´‚þó.Kþ{M¹ãGDã­bˆï¼Ì$ž³4Â3ŒUCoƒ„àwÉ](?Ÿ€-Ub3ÉXˆàgÅ(@ë¡]ƒ>Gϲ\qM唞«‹ò«ó ™•Y±:eáÝ"»D>B ¾Û”Åû ž¨d"â$˜¸S@¦dñH@°7BGúûŒú[ºi @F ñX”÷eIŸAiW°XŽiôº¡×6BM ˜®çÒ´Á¯tI@ó þgXà?9ÚNTŠ5k_á{ þšÓ L>è,+rƒiS‚BsÅNð3CÐø=C›L†9ÛÀÿnâoãïàïâï9SO® <îËüóöhH&!ø/udÂ4ðÏ?á?¥!qü€×ðȟѳY'{”ѯGÉ{‰…•oãe¬M‰Íà¿pekSf3ü¯¹Çá/Ø»¾šc ïR ºqûB"½Ì~èÛhò<Ž.“×£“ä§t:>KÏ a"J|Ä÷SÊöh(æ4ê9VànQ®Áç fϦÂ5'8&€ÏœiüOÓcp–0Õn©zÏÒþñ[p©ƒì†~0ׇxuˆ„à”{ˆ-ŠÅz…ÞÎ¥vQAU´9egÓ9Ä“Ø AAo s5Û…£ßVQ U’mÕšU]Ú„)`´ŒF«p»Í†õ_2‹mÓÇc âL‘r¤œáûò 63=+ e'¬o.™ÿHߥ´i·ºüí<1ú¬rš^Ø(š\9)¯aB ÓñŒ}™:Ä>¤ZÍ_n1=œídGew8ºŒ‘©­s-q¬#ô<Ô¬„6¬Û6!+ â§mH[Ro÷áPÀd,,Ä„0FLWÈŸôõÁ«ßˆ#“M”ÐBíódØYÉ—[Œ³gç*„%+çbðìÑlÈ/?2w•irOôV7ÙÜ,XƒùìäË`ƒï¶UQ[˜§9è†ó~MWMo2{„XÇ7|Ú?pÓÖ[¨#ˆ#ñˆæ]Ó%ëè”,ðZ°;>›vÖ», s÷ƒ6²yEÞIþkßî2¯B_l¸õ%Mÿ:üûÇ7_u~ùhþxð݇•î­vØ 5ó$;‘,Þ>®írûK+zT;ýø …vð>!y@mfÇ"ÌV–„ò:ˆÔ¬6Iu¡†®aãâ¯óF G_‰`Dö|¿oO²ãÜœ"à¡—¦¶|K_t1™TþE¬öŸ ^»…Ãÿ~ÿfý«Ž ¡©ÕÒÕ“7ÿÚüØu¾ZuBDÜù§} 7ùZ>ì|÷Hün®½é&Ép…ûÛC,ð! ¾H“¾E!¹³mˆÈ¾J…G"³C³ƒeÁ{  œ›±)¦Sç+¢8$ Çmny;ò õ i²º·Þ·•{‘Ý»ÞD¹sœ= 0ˆ=G,Ô?Ÿ\G%'òy–ŽI]71£¡+°@ÀÎñ2¾‚@œŒ(º'#D|xÈ{ê@ öÆG³+ èР3edˆ‘ž ¥c…ëAûþgª¤ˆ*5´r^1Û£Uã6L_PuLÝíÁd"@ ¯j_›ÙQ ÐDf\$±'>j&w6ŠaÊç=™ÓBŒ'Ú‹Þ¢Ñ÷|(c‰NFùÄÔîá{8ä »{WÎ7ÞØŠE )çï:bèßD˯òhù9³špÞt­í–;9¼Ã SqÉeõub¨‘+Ä£GH-ÞÀÃÚF¶9M]ÞEÃ5þþ4kæ?Ýï”û盯»¢Ëønå–Û`=6Ÿe¥vZÛÏp¿@„H:Y®z$ãÔ¢þQ¢ „Y I¬P! ta^~i_l"t÷ ÈŒ =îÞÝ~SA±×k}¨]‚ âîÝç'NtÔ$YÓo¢+ìûM‡!`K¶®aÛ-m•Û+)ÐFY!NîAT‘S¥ÙÔqV4þŽk£aán£¿þ5¸œ°F ÌøTô"v¬âEF8ª€ý `ÆÔóøžbjy ¶\3Ê0ý¯kxf8Glׇ_ × \õÎáÂø(Y·sÂŽn"ÛÏÊE1}Küt½Mmì;ôB£¨úï`«•1%äŸލ‘1Çè u=3¦èµ¿wW‰¡n¶&T ,ôRS ‡¸!x~f+å[Dö騯Ámë‚X>|°ö*ygÅ&2ò6¤ýó*sÓ#‹²ñ ìY•¼ÿîçQ¹ç-eÕéíª˜ ŒõÏy:2×ns©œøevZdÛê6̵Ù÷À#Üv#˜^7Èvœ›ËŒSÕ¤—#.u¬›__­‹ëº%²¥Áâ‡þ‘²É(˜,{obýP¯¹–›5{†}ØR‚ã9¥+zÒ,»ƒZFh! Õ@ƕŻ‚¢L£^„áà(D=ãí¨«OmËÎí£_ZÒÚ/­VíLëEÕÏcË[·,-œ=ŸHˆ­µ¿·Í̶Í̶¥ÖÖ¿Ï̶¥±vëÁR{…é„¡ãÈõÀ?u:oVo6Ï/­6È­Tï­£ ½:©^eFoýÝ^}9&¢ž¢ˆkû Nzä)`YíNBâ}OŸ@£ ¹ÓÓ2¤Ôw³½fÛþ»ýÍaüÒë´DíðE²Ú¨vsÀOBÛG ƒ›~߬‘€ŸP+auðó‹!Ø_Ú ^k›Þ}XصÚ>}–Îì‡/¡3àšíìáÁU~º_…Ÿ˜‹^ÅÛÇ,èÌîH0oãw®ÑÒ~³ö>Ê!ж`ƒàß ï>”A{=9aDzk®½V4‘+µ¡®Ëõ³6Žr¡fíQê«ìœE._ùÌeCEж ´zþJÖ Þ°Wžâ‡Üx+šzì)h1—Ž(tö ‡P ëõ#ÇoÐj» QÕäÜ©»ðÀDb2 ×Q7 éT­µÕçØVKÁcÔ©gB¥‘|UŠïm¨E°ºe’}åk”¢1Æ•oÚÖê Ö=4šB˜/ürBCø.þ;¦¿gÙhœ¡e†¢HѬ:=FO‰Î’¿¼ÈŽŽS´äŽñ}^ü¤>A”x»tf 0ŒQªCÈCZ'ˆ¼|fu¢]1ÎðLÛ²º³Š¹Ò [ É /ï2L]Í XþÉÆdw GÊÜPqE+œÁë‘4IleÅ/Æ“¢¤{œùÅE{K'Wu%·ƒ³îçŒÄ,1¦LÏEZ¥¶O}ðŸÈO.&¾tÖ9O+E¡mMǤíH°¥Ì:gC2(¥¤#êAþä¼ (5<Îgê*³}”鹚(ü4›ÝœÏèŠß)Ó³ÆvŒ\7&’Œp2á5âæáÚw_¼;Gž,æÉyʱò¥áV¯~x¼yoã&ˆÃi¸Ýßì߼äqqnÆ™—ŸËĤ>ôÈŽîG«à.;.s««ß%:eÛe”CëQÕ2O×hé‡9)ûZ@Ž¿Va… “×&kdš¿ùȳGñ)æÅTDì! –:„¹eLê?¹2¹Þ[#PÛrmx4*N×þôYÖÍÏý»wñßõ;þ¿ôó§»·ooÜ»ožoÜÝÜÜøSr÷óv#þ3¡.Iþtqq± ù™êÊ-zÿú_üoœúùøøÛ€¾wçNÍúonÞ» ëoŠXß0Ï7¡üŸ’õÏ2Â?ÿ—¯ÿÃï&g“†K®ì ·’`Ý{ï’þ=É7³$߬­»¶q?Y¿»uçþÖÝÛÉiq”‚G²âx@” +žK±ÏògŠÛƒb{I P[¿IJ…±´(ƒ9Z%J½ÔõÅJ¬œü÷“ÃD%¦ÅÅ8šP˜ènR ê‡áÈ0– P-ášÁׯŒ‘Ùà¬0 %ÔÐÒÐGa{ɆÙLQÀÏSž>¢ÿÊ?ößõF O¸£œ3€“»'‚k ÜÞf™… ´Y+¶’#ð—ɧ«Ô!â(n@nìp’¯%(Dé ”¢“ütŽqA4øgp¦lmÃð,ecJÄ—–o!$°ßuò8–Å‘@ì'å¢X3ra„é5¸?ÌÆôàžKF”¶(Š몍ЯœbÉ©¿ÙX„ä .T§[-­¡’)¤ö´„IδøõÑ< Å*D ÈàƒKàÛ€rpô)Øfy²ûýëá Ð2S±}¹÷ü‡IÝËç/öïÖ¼üyçÕó½ç?&*ÃM~nÆŠw³¼k’neõ"ÂE£?A6CYü@îô_Ý LyÂ}knsǸúñO®ë~üjÏŒmçé•ë6»‰˜«w†-ì<Ý}upÞ§£l:ãêù÷ÊÌ<Û}õãµf{/evÜß ÝóØÜX@_²=!©®³£ùi#iQ9Ì2×DdTÌ܆ ÇNÁqA!Âá’D DÀåìz6¬&¥µiXiæ¸Ý³¬Æë1Û6Üž ³|•f…Sò­€×s6 ލ„g–\Øòn8¼([€óao.ú3zZ÷ÑJ|t‘£¿ui8'=‚£BjŒ?bq õ¾.)Q‚®wÞÇ$Iõ½+téHf¢ü'ÜË%3 v¯gþ™Ó?%øóæ³KøF‹ÿæ† ÏÒó üÁ ~•Ó¶„? о—P¯8Ûì!siKöž?ß}•ü׋½çÉ¿õc2O^<§†Mæð/VБf |cä÷év‡WÑfKº)é¡p½Û9ÑvwÍs(B:íG(\É€3Ðoqò–Moo¿Oúª½äî:ª-8㤔M§§e[ùéZ *v ¹Ö’P'˜ŸRˆ+UC3g˜Îl#KÏWæ o Üñ³ÑÈi¦éÀ;¤öV·eÙ߸,{³Ž¼:Pé÷Èsx@©Ð¤ˆ#ŽXPŒ:‚¼HîÊÞ¥TWe¨üî½§ÂF…%F~há©1 ‘G ¶jÄó‘ÅíÔI™ËíáÆé%Ò ›®I™ŸÚ×Ú˜ÌÒ¹ØÚÈî±ÕUaˆ*tÁÔ7ªºjç¹E ž=6ª«‚ ùد7‘êÈ!žž@åRö‘µ€î"L \çžrÑT<…h»±GÛàœJ´h«8†.«V…¤-{ 7šuÁTñ%GÌè™»œa Ôgpî”îT¬ CÄæˆ Gß6¹?Q 9`¸tÈË9 Bí_µKdöƒŸZÈÃÑy­þlˆTãÎ ¯¢syìØ|” ×üâõóƒŽÙ7ÝdgŸ|èz‰åì–¯Wø8±L>¸GÝ24ÿ㫯_&ßÿ-öµÙqþÝKnOõûódoÿ`ïùãƒ×e˜ÝÂ`RsXuE²ÿTÆ*{‘'éS8™¿ùìÂ]üëlãÍÈ6Nlã¥6êíklT{Årï¨äe©MtÇáí@Š6ºä S4#ºȳ¢˜”q>·%l~¾¶•‚¾Ù¥G¢ÈuE¦P«Èè3ÌéåÈFt:L‚ªÁ©Þ$·Òªº£páÁnY܈•sëY$$ŒŒü”µ¯Ó¸†F¸è¬¿BsO‹c”¢49²£ñ'×iþUv)Ø5?…p;û®Ó¸>mêÛnf‚WouŸ7ó‚f-#¨b¯ÐèOF:à US£ža‰›=ãO¯3V}Ikm½l*ù T4©½8ÉTîÒï0ýb9dp&ðùiE;U·½ñÔsþïAï– ‡EA™XžÊ(ìüJ´›bTq  JvU9bš<›È‚ÒÁþîþþދ碙åà@0úƒðHw4º,©Z}Pv¬§¾”§}𡙞҆à ZØI əʤ¡ÆÜ«U(Ù ò÷áAI¶e¾êZ$ ¬à+VoÚT¯2鮸†Ú=yñ ÂüïÌu§ÛÖ®OjN¥!.ùªjçù¬‹_…q Z±C£Ã™Å_YIwv| ¿±NDåt} îVÔªáRÊ-%XKBZ1]›Â—9(¨±˜}àh†Ïaqåº3/ñ\.øÅ¿ò bÁn@RåauXÕäìžQæ@é¹¼él‘VÈ ßRBÛR¨e/û ÝaÓ‹‘ŸµÈáš¶šŠE¬•NÔ‹†NfS?PÏ<àÉ©¬ÅSbf$ÇÁ“Äžm%Étìì9;RÎQ!5Ÿ—»( ;Ìz-M'«Ä¤?ÍNÓãKu!0Ucsu›ÍÞÏ<ùsuÛ5þ"1ž?㸤 ×+\ùy – uGW…CÍÇÿ@D7´žf̦ï *727€¸åé(ÿŸ¬ÚE¹Æ¨úŠQDÌÌ,nî‚z/`œ¦J'lÑktƒ¿ˆ÷A^²D¶å¦W‘AB¼öô”¯ð?cêeHêû®±E°/ IÂ*-¸½³¥3Ðòµµhwš¶Óâµ!( UdÃX_Nós€ûKv¹•¼çÿœgö^ËIš÷žôÛµc{¾°gùx¶|·PZÄWëMÝwG6Œ %„í®x½8ƒËb~zšC"ýAÿc·¬ïý;HÑ›Nõtí{×Y»Ý84Ðyø‰=¼w2xaÒ‚Q¶ (¥…6gh–"uZ‘!й¶y”pk_v‘ìÅ‚à0›†‘NþP@.ÃH™’@ßÜ€­Y=¶Pö~þ»Œc_ôC蔸É1èÆS»pÜ FêB 5ºâ¨­(|¥ 6œßjƒ1_gó¹yšåãËæ‡HIQ—Q–Þ™¸$7͹Þ֓ήx4v.î''à›ØL¦´û”ºy÷îgߪO1Sn‘€¤‰£äË„sl]ÅH×N>5W:hÜ‘ÂpÃ|¼°[l½û4†¸ùÍgŸf v÷°½ØÄ:öo7±ø]ûœköïpÔaà}b;@Ñç€e‚â°†•N‹†nÂrÅÛLs1”g¤H>fï=ΞËôw7¢N'Á …½ß[tÿ,?Í÷¿“âs´±àþ·~wý®ŠÿÛ„û߯½?î¿ÉÏÿâwRà­on|÷Íuomýˆ÷º»¾u÷޹AÈ]ùB뉊í9ܵ›Í맃AO³ãb:,ý[ˆd$’¡þIzüD™GÉcˆ]MHUœŽnTÀ£ä¯»¯@ñr㘢Âïõß߸ñ Ù“! ʤCŽ®&â,í„jÆ ‚Ø?0Êívu}su󮪾u¯¿±ÞºÁ€Þð€jiÝå%±$ópcóöÝ»ßÞÛÜø¦õÍ öÿêt6ê—å'·±hÿI â?ïÞß¼¿¾± ñ¿÷ïm®ÿ±ÿ‹Ÿµ¯'àÅ}®oš«çÖÝ{[w¾Õ|C6¿È†ùlŽÌÕ‹i:™€ƒ=Ñ\ž£rãdT¤³­Ä"g3P‡NÌ~5slnŒ<ƒÄ×[Iÿ›ìü·TŠþ_ôÓtþÓ³Oo£yÿolÞ¿¿ñ§õû÷ïoÞ^¿³‰çÿÝÛÄÿ&?1ý/­;1äÌîFlnlmll݉êmô÷>óçÅ8ŸV+Á2‚K8C6¯Ây11áRC™\´<&€š ¼XâiÍ>%  æI¶`%(´7·^)†¡˜qÁ°˜½ |àÏóUÂá‚ìÙ_òó|d(Ã⦣$wB†õ» Ñ[²ÃÄ5ðY6šÔ(ñÕÊ$õЋÄ/<›à³/Hm TÎ?üáÒ¡rÈvÓìršH,3ÇEó¥5€ºBÍiÔ¦h!Æf Ügf©ÿÕMÃü]>œ›KÑ >{&Üè\þs!=™8g:¬ªGxU½HÇ3„YƒT%b_Cu¶™²wiE8í9UÒGúA¥w:* & ‚^ÃȘ㌓z˜áôS"×é¤?®J¢"ôŒ(¤É¡1G׃`Šûñ9†ÿ倴z޹8…V*f-©Z:E2­#O ÀZž¢4bá8è2<Â4JÐé(Òx¢lN gj‚a<‚Hn]£Ëe'²áœ#ä½ë%¦¿!…æ€JÎÌŽ Í(à­‹ïÇ·¶Ÿ( Ƹ~ÖO{µœPÇ]Ö¤òଃ (ÁBïßp¿ùæÚ-ÿ«¥÷ÛEv“ú«o¸‚ÜC´Ù·”,lyJLKN7VœÌ8I%!I1ù d6ü‚Þ§eo¨òãbã9‰G=Þø•Îðå™â=x¼óôé÷;ÿ²ü<ˆÜ…Óç`ÅW\×­³¨é`g²-`mmðõ„‡ôÐöÏ岨Ò…àñþ>£R&ŠgX„Ït8—eG pùê´©(æÎ#¿#f°ºä˜Òwº”Û’Ò9'ÿg; SulFSvCÊÞO0ªm¤­“QQ`†ÇÙ´‰sOL. j­‹€òÎ'8Öé}€ÏÓ÷ÃKÖåN%¢øÙÎS|}GÌ^¯®üSþ`·&ЂˆJ1´¹ºÄÙR_e6­sö‚W+ÅÜeAI ÿÂ3åƒ N³0[j±ÀL=nX¯_>Ù1ÃR#Úß=H(PzG7W!ÒPýêöœ#¥?z„Ý…BþÄV5{[˜Š« gþÅ«'»¯Ñ€ œC€Ãz–Þ¦(-t¯¥"l]ñ+Çr±mlõ%+.ÎcãsŠ#31ÔðÃÆ+ÖñÉ«µ÷|p—öž¼PƒÄNvò‡@~ªè ½ÄA¶ l¶1ÆbÜï9c4yÐÿuçéëÝ}jæ–i¢ÅüÿÆŸÊ».S0úC än¿AòÐÉ{]?Ç*~¨bŠðµóXzÓÕŸ9÷výÝ[¼'RÎæ&¾ / ïa>ñÿvœE —íRªM¤ÖSïiˆôÛä!O.øÅ´…6âfzÿããw]cô>ö•÷!¬7;§ ›2œBš$ ÖØ“®èØâ |€˜¯†Àvü9¾E|Â=½‰¹Ñ'ùðcîÞ ‡„´@¿­ØÆŒÐí×ÔA÷ßH83ë›ôÿŸÃö? ì÷67BûŸùÿ?ôÿ¿Ågÿ³¶¿;¿²íÌzÓöÓƒWPMň?¯À¹‘ëòñV²Þßc c€M$ ŒDH¾í%OÌqÇÛµt¹8Ý([p5ݸØBÐÑÕ8¤€¦ž#éd‰ÏYæêš]Úcs9)@ÐFeu6¦jà“ü4àÁŽüÔ8j#¾A%ˆ 3‰n”çF;45žˆä8T|´•lÜ%«'iöW‰caÖݤÿ]1™™ =à˜¤©:Ö×oA³iŸjAG0(Wà–c³ø_œœ «¥úĤ«¥³Ì/Í“T-8žD ÖÖlîÞþõŠø…wÏŒ4ŒÇ¯GÚ¯­¯¾Ù±W/Þ>cÓyüíñ·‘’ SzôíÑ·¿ƒ;äÿ°òŸþýŠøï`ÿ½kþüÿý·ø‰®?ÞW>—÷ÏbÿŸ{›wÁþ¿yÛ<½}ïœÿwÖÿ°ÿÿ&?rþë%Gà6¹nl¬mÞO66·Ö¿ÝÚÔF:ýͱzžc$s™Ì†}÷'²8ß‹Çsìás~£/‡sà)P!ðIü‹îoÁ;øß`$xÎCüˆZeiÁw:2íá€=±:êœäÕ¥k—i ¦Ãž²dòuß òJú“üxvÔPþÑBù?ÓQêìozÔîÿ>™L>=ûâýûÄ|ùÿþíÍÍõ;èÿsïîòÿoòãûÿø |`cÃÝ6ÖÁxs}Ëðƒo=€ÈÎÏúànÌ(aÆ?ÈŠ¯2°PA¾¨ä¿ö_<ðe£)ò®.)ç§§”H©ä6FÜÇн@ÏúóŽËÝ#©¿% ¹ÎÍéç)k»@†:¹ÆYXR…Í‹¤(|úâçÝWÄXKžîýE´o•·nµ»-•’33p8¹hípëìÜ@Y)òè›{Õ p2XÝð²ÛtîÝT(A(³l ˆÊ$D©-Ë pÃA‹p5¸"ð…A¾T6árÂ{?•Æç4@x@Ì¡ÍFÑ`^3Î"„?f«– üËÍ`(Œ X»·.ÎÓ÷*ÄÇüÕy½¿ûêùγÝÁ³ÿ<Ý}þãÁO½d÷ÙÎÞSõÄV9¥´~L£à)Ä&‰¡„8 »4€qva×uö7"` Õy]ƒÁ Ìè¼oƒÇBÖˆïGÅñ[u'‹J’ÍNBÊË]ùOtõ´?|HªE V[¤*„19ÍdßÂþä”,RÒÍŠša)7¦[6¤Œ›òréLÑíÅè „c…a­ðôX+¬Œ]ì¹­0™I‰ág]N#u(ƒÙóB½÷0¬jꢴiMmûƒ‰¶ýñ†•‘Ť2ÏHHRù“t±P5@<ò=õ¯_Æýb:½ì%Þj‚ËÔé˜âsÁ¹°p ÐîxŒb‰¥ï·Eè.§#s’•‘9hæˆcæÓAÍ” BÀ<ƒ¾ã í`cÌÇ”H|<ÄäáÓù1¨óGÖÙ'Ò*ZÕ0è¤ç8A—"ì¡yk!Ÿ’J¬A²Û/½3Ãï´AûˆV$%·hDgÙÒ• ÞÁ#6]Ò¦/5®¾‹ó)æTõ:‚®0èY5¡CèÕ.}W“ÉR¾žC&#äÞ4j§¥o€™ž0„P°V`Ëá(+ª×FVÍ­ŽS´cBRNvGS˜.ÁŒ¶¢ÀW 1%äDLKÄN=æP/ôcó¨jQ•ƒ‘{Ž}£i–/ÙƒÈÌ.9s¡°Hw2ßëïx>šLóYX‰6-©³­Š…)º„€Û„+&ÎKŒÍq6WƒÙoEŒgµ*_3©s@‚F‰MߤãKðmí'Ð ø¡U‡Æ¶qÛ¿ÓbVtbœX<ô¦˜›’uawXö8Ë´ÛžäPö“Í;É™!=Q¿¹wg}]>aÞ c+Ю…o©byƒ³:?Ï¥È4¾_œƒgÇp>‚6ž³"LϦ)T>Çpûïð \­ûÐÕüå—ç‚àx‰§Bâ%j}’/ÃeŸØ@nÐ)<ëx#,8é¡`¨P\Z†B0iØ÷:%dr(«ÙWÄNxXyÏ ª„ ;ò!1ÝM–9°gL?ØÐI>|NÛºž%7@ê,™,ߪÚöɶ%£Ï6 ´ƒÈ©°—~òðD³@H†G‡å̓«Ff*·«Â©Áå^sB®›)ú7œ?à±à:2AµÄ®8#øhÎ ¯TSÌ<5[õòhÍ,금¦ìiFlÑkT^I>˜‘7f>¶_ò‰E?ó¶­ëŽ¿xw§ÓuNøÕÕ…K™¤nÙ1,yþúÈn ôBâÖ°þ¨—P¯åÚ+ÕŸÊÅþ ’RcB‹“|L¾] ™O0š`~¢Ìãj=›0YîA†-²d.Ø‘ãDUÖз¨¸æMË‚ ÷&Ä%CQ¤ñ`3ǧ µ.>Þì¦<>Uîî-ÝXÕ&„ä?ö”w90k–öÑþ¦ŽA^hºìZ×uÛõ.¶'Û6»s„ÛÞÂi·D4÷ËÉèþŠ{ “:ô!pÀTùx„¡GcšIì¡Ï2– J‹Î† ¸a»Q'úÁR^¶ G¦_;–Üõ—€' ¢ÂjfLǨä%ÇEB )À¢g*"ÖÆµ´O!eÜŽvú âVX#äæDì©5M×@RXs3°¦îŽ¡åUé«4BjóN‚Ïy¦¹ã<Ë‘9à©NÓ:õ72’ßèÌ£ÿz£Ñ*åû½é†hëé»B»ï²é%¡œJÂVÎíjñéJIE»ëEóÙh©Q|l±U‘¹<…cí =è.@ç.(*G/@g ÌNªÙwX=5_vjn-ÕsqŸA©G,&òÔDO>¥Kµ¹ž˜å—Þ ¢ÈøW3%XŒæ„”äsêo³€ÚÑlæ"rc•¶ž‚–c\ÀõdŽA—ÖÍ*yä={Í>Pú^3kä‰KnKK1åK'[¿êæ3Ûúê&µóPÛñTÓ¾ØÞeÕ…3€ÿ·I †Hél.|†\ì…Ôˆ]¡üüÔõIæñ  ÇAo\f³“ˤb6pþl2êƒiëåUD4Z€V µ•Co›aœ+ðÊHÂ1ºÍ— ÅÎÝiÞ%’VÕÅ[4Ávr'¼P«Au$öŠ+N(tXÒÏ^mã¶àËUÛ"Mm‘%ÔÍç™O pÑŒ%cEÇ@­ó¥ë+›í߇m™€wï³SØd¬µ9ºL(€V?…äm]UY2;ûb";©ö%ižgJ瀨b\˜)ª± ½äf£)÷¢5³I†·ë¤Zhr4mìZÕï46!>ðm¬:ðL ŽYn°¼©†\ö<} ®rfˆež!¯§!C9Œã€«JÁŠyt ý“d(ÑQ\‘œÑ7î³Ò4¯M•¦# ^°ði3u3B?e°±O¹K Òe›Áy«" ¿æC.~èr"‘’²-6ÖÑ×Ô¦?ëÆÈ2¨WŽ ût¹šC_ñ%®Z§†çþ¦D6zEÂÏ—%ïÀl&”n¸àšËFŠîôŸN4¾Åú%Ü1Æ3'lœÌirš¿#Å‘2ìÚ.aÒ†ŠjMÚø²Á¤ ï;Êx" à [[×õ$(–$*™Æ=*¤xè$Òƒž:œ4Ñs¨’`=I^™É<[”ͦҭz7]¨’òÆM;…x5:¨š:¾mdñ’ÀþÀ™xd3¹Eu<ó†ôâ]«2ߊ›ïœ5ÉTJì'©ÃÁlñe²÷kËSjîìtøWöxEVhX¾'š~šaßÜÄQ;þ… ¿½níØ¤cÃë¥o~7í0ç ‡ù}Bz•'(è^ë~m¨9T2V×¢ÔåbƒD=¢8šáu†R%ãY›Ró¤ÓÙ`&Ƹk‡Ÿç5ÈBóž–"B'ñf…¾2ˆS˜ž¤a{Öš°Én¬¯¸¶|ÕîÅ·@ÍcM“õEý‹$oÓÝäcˆ¾ÒÀ7Ft5—csœçï̘NÙÏ%û6ˆ¸3ºÎ(1̸Ø%;7!…*0ÆH4ðÚ¢¿ä]Öð «gãYli{°âÀ6´êWþºÔ…¦ì+íiAá„vÇ8ˆX¡õ'OÀy 1- i0d ü&3œ%¤,º¢;ʼnÙÏ;zòâÇÁÏ;¯žï=ÿÑY$K´&Qš`÷(K6Öuß°«Ü£ýyíVóøìãýµvÌ„> ½;Ü&@6«Ž¦Å[¾€luµ±Äƒ¬Bµ/…Ý×f\[ŸÎ Ÿ/*d¶Èò| ƇìñSÇ…jŽZ¬«L!¾5æ~äU¡>¼aCó‰ Ø{ö\"²ãÎèš‹z¾¡X¿7Tw­)ñTa/jë “:ê=-_ ì†+3¡8\Ú-(Õm‹ˆ|V¿+@cšSöE©\<¯vÿ×ëÝý /[P_6üï•<¬^ˆŠš7H]Jgòܰ”­äçÌê¥ –ˆ”…ù alK 4\«VÁ” éQ y9!†2E#h½+ñR2™´ú‹[äZÜ.ø«±4H÷l}v)*q9±Ø Ås Kà~ÉÐ?Ii?—lê$&iÚÉþ$•™=²3EK_‚‚ü‚h…fád Añάß-6wÅûךMµo‚k²ùÀ|qÜÍy:Ì@¯‰G$.„i¬°8{ˆ³pÕŒÅÅ>ìx VÀñÐÜÕú"‡j!þx 0p£¶ÅQÇSKóš/Üþø ÓÇu%F‡ÏgŠäat¨µ¯ÝÅmYçOæS7—eTõn„d ÷.ÂVÿËÿËÿ‘Ë#ôý‡ý‡ý)EïP¬Š‹™ƒ¾¤³³d]à°”5º{¦vÃÞijں÷‚äÌU:q+@Uóº¸8˜¤¨kDß5 *l²jE<À˜°ˆ…_eï ×2ç< @½#òD¨xG7j¬Ù½Q8Ãï[ùŸðSÿ_gúz âÿ776oÿicýÞÝ{ë `ýOë››÷înüÿû[üTãkÞË ôÍÚúýdý›­ÛßÖä‚ÅHà…ÖÐä ecϘÜGóCg2ËUmEI/—%ãÿ[.öK‹ŸøØ‡°Œav’ˆ\¥xWƒCÿ!¹¾ ´é˜öžH¾·gb/ÞYLÁìŽ5H¸¢y:TeOúd½c¦æ5ÎHw{4ÍÒ·àfiÎ&Ð6ƒWÙwQ5M‡"§˜É1•õ¾’ …+Œ€CF(`gÉWÚ~5Y%ñÞ çàP¢ ‚šaË%:åóÔ“úf– &ž(ÛaPbœC¢Ööš%Æq à ë‡S&£6^ZÍÚƒût?yázÏÑ+ùøx4R™k”æÜ±e¥3œ” s.dáE[$þË"ž€ ©¨ÀYû<—¼Û¾üGé¸ÁÝII?ÜY'ABu‘¹Y³CÌ«Œ?y…õ¨ƒ9ëÛ¯í‡A–G.¼†È"wF·iwzPî.–)r!]Éæ€âŒrþ£¿lUähý©ˆÑù»ßHŽ^¬ÿÑ÷œëµ±ÿùþ½û¡þg}ýü·ßä§Aÿ£þ“u?¡¢âªzÚ®Òù;7 %¤„ê›Bðåœ6(.4b@o1±Š $„;:±4¬O¡x@*§¯¶2¦*"ÉnM¶ò˜ø # 9%1œˆ3ô’ìžÌmlôÀÐB:èú.IFUËóo­ÝùgÞWíh‚µ RÅaŠLEæÈØW@nQR…BøÛ¨pÐ0¢ŽˆY“Ò¥N3œÁ§Ã¥?ÅéàO‡êl©ÇÿüÇçÿÿÓÂü¿wïÞÛþsý¶ùÓ”Û¸wgóþÿ›üxÈŸÿ èß{Ìç¿5—àdã›­MÃç7c|~‡¢kÙ^G9CÐRv€2r?b â%b|é° U„®‡C}x}bØ}‡n‚÷—)8º’R ö²³ô]—$[í#ë{ÔÁ8Æ÷YülÁÓt\"ßÄI û’¶ÏV€¦þN ýMìC„·ÆÅ¬ãžñÆÎ —K"mõá¸èØ.ˆaZ—÷Æ”ad¥Žݾ¹›<âàÒ\ÕÀOß3X“|HlÓÏiÎÞt;ƒ9?77ªœÁ Ìqt‚±ý0Ù˜ÀU *l#œžô‰¹Ë£Ã}ÀŠ’ê%o–k»¶¦0™Á=I†ub.cöÃrFv–e€òek;þ¹\k»ýµ[³¾|s€gÁ׿vŸn'ñüÔÔO¥øŸv8kzaöe80Å-(߯v¸Çëùþ• ¿V¾æÎô*Mq-T¥£7 zÓê6¬‚·Qp%Ürš£6›îÁ¡›`*ªTÏ5›~Ûz¬«|á­Üa‹ãʵޘµ£E«_5ü­š ¿qûi™þW>¯_µ¥>Œ >ì×Ä \½‘…SI “£â=Â(™ÇFœ ¤¦ç„g^_(¥¯ªR yÌú!Ñ'ªmì³)ØVÒ«'—nr£tÔÐÛD¾{ïWz@E—N:Ì'»<•©N‡ÀŒ2I\M‚—ë¬Ì ·}üPƒ[¡£Îäè"1Ø´¿fÓüä’Ž ¥€µc ALÐkÓcë}sôu<à®pǸ~ç_É»¼ÌòQ>»ÜJZf:‡Ù¸•|T .‘³Ó.eÄw¨:’]9‚+¼º/¥`Q,^5Ÿ†rr¿ :݉ RÚõÙ_ÔBªØ²lkµ’ïà?[Š1„žnI‹­7B^ O:©9zX¹=ÍF¦óæx$as;âé«áâ¨êQò¯Óÿ´Ð'±Õã Ãæ'²6ÎòÓ3ó xkæªeœ] k‚`k®0Èðôlµô„°ñ"’½CGÇrv9Bõ&‰FHÑFnO™Q7Kåv3ÁÛµñZL±Qb¤‘›©mÉ?Þ¨¯BÓ»ÅÕ‘eø2½¶ Œ:FO°>­Øàë·L ÞSìÃúþH%Õ91!¥õÒ w»€Ð/^–õÁxê}õÕO€,B¤›Ov˜ŒP0Æ âé0/Œ¨‡f BµsÂ@âK.ä:´Åݶeö~cŽñ.²+µ/[ÖLB„[@UÕ®µA*»ANâp3èºJÍÞW1úØ"XÍ—I#‰ËW28!nQTÿLÁÈ@x.–å¨VÌÌÈ}G|Å2 7"]ÆÝS•¢Z_'UÏ>ýŠ•ýæ£ùÔ¬Í%AEZ™‚ä‘×W½2ûBOùxp…ÙTfùÄ®Å2§œŽ:æb¨×"9ãIQ‘Ø&¸PäxB_…’‡/x¼,ÊÙA•Ïø‚””ùø8óЊ1Oý(›. m}Ì.'þ³Š!?Ÿe*@¿d`2Óa\˜Y—kÎÞ¿¯\²ÆåùHb£fssT{"•›Ø-ÙL¦Ì{Þ5ÕÑ 7òŒ^‚õ{>AR=*·dFN8ã€yvh™x(¾á $ñÒHPÃ"#èÙ4?À>¬¶COÍ1¾èĨ®Û‡øƒàn{Lñ5ÀÚÀ6auÌn­îEôÔêÎÏé¥a±ˆÀ Þè¸öS¶–9‹•ÖÌ =uLø¨7*!JÆèæ¤1ëZžòoËéj¸–³´|j^fˆ-ôñ<í¬¦«ÿ³³ú¿ß|½†³Å…Ÿ³ñ:,¼¾úmPò%ô{.A¡~é¿SÝÕ§%e©tåÍ×ý¯±?èó'>^ëFaÒ-oìÑQJ0²¸½©jÊ/"ûÚ›L"/™Pâ% ÐÇ+g‰PÆÉ=ˆW˜šÉú‹‘¬ÛK&÷bm‘ÚkÖénfEaN‘é,Ö =F¤ZDh--D¿8ÅÞeS³Y ú!•Æô8-³n¤›³â)¼6ë‘èáz"5úe*£itq§|ÍUŕϜˈH³'>½d⨊ðÿæu Ç”À ¼1)êþòKM¾ô—&QzBô[!”™U_ª¹‡¡c ‹@+XYÀ Ž—ƒnIV¦˜@€^¿ûÞ9‡cò(Ú.ùÐd|ˆQ¹pǵDcéñ~—l¹f½›|eàÁc=Á+ÞŠòôA8#Ôè¶ymD)JR´öjñßз¸ùTÍEïfeÊñ£þd^ž9ù 2þH᜺ yl‹ªb±*Ô<,ªFÕU…”Îgå³bšýìs8Ã_·ÎGÛGù¶‘D¡öù¸Óz¸fžàÓ.Á¿ÖLA&·6nç_vþ·ìo6Aûöà£w¦í[A;P/CE—%¨4ALøÙ %‰Ë‡ÍG±N"ºCÊœ"lx>ï+2!ªNON@ÂÇ+]òñ¥ú§™ýè¾6å¿JVï­³Õ€²CÀê*whU:))‘Ѥ*N‰öm«‹µéŸè/ÆN—Lsr’ÿ"lÑ!ÚqÑ,‰—?0Ê „ùWâ²¶*Z836C2QÂ&)$ÅÒ’õÔUÓzÉI Kí /o%Ót˜ êPÖf ÇûÒa­öó¬3+6h"qr(!£í4´QRüï!D–>Â'oÈ£kW™¶2È8óJ¼p»Û?ŒïNU#Yß+YÕÐáaä` ù5kÐ~sˆ²,Îâ›7OXû½-~þO½ý—ž|Ž6í¿›÷nß¾{‡òÿnÞ¹¿~oò?ÞÞXÿÃþû[üDò?Ò£%ø›oÑñ üÚ&y~ßÏï¦ô»c‚Ó´7YâzmR¥7ç äºÑiG2å™uNp)æÍƒ÷wºŽqîaðq™œÅ[†µuº•*‡(ús&°pïóƒ—»ì@’¹MnˆÈT´¡¢#ÙÉgšd†“GÁ¯ýFV(Ëí—+踿@!UÐeW²`Á\ øït ˜ž8¨ió‘¼Júíņ ÑA H¿Ö±_éÔ‘ö„ä®JOÃŽÖ`¸ïùÞ]æTÁe!üênl‚øö€%½Ñóâv`zÜݶ]XV8x„³iQùÄa‡ÀaÈí‰ëf¾žn–‰•fÅ[ÊØ–ð½ËÌÚÐ1’¿d/õ*=\u8ŸÒUð„úU»‰ \«‹°­–í!‡HÇŒ àˆªžzÕ£D1ÔeAÖêàƒ1a½uc¢FH;‘ß¼a½~›vMÙã£þæ­–¿a‹e~:N¯Â ýB"íFò¿)#Já¶ Œ(Jð•ÜÇ6ë1ŒQÒcøäSÑQaØh*ò¤YT·,Ü‚u.ƒÔ?ì<ÝßuVÚ(Ü¡Û`§ ­»g¤Iå¶ö‘ c8(P2@Ëij †¥®ËÒl¥Éš* ¡šYÖˆŠ M26‚6QðÑe%?³fʪ€•­0ö_˜mÑŸ#èT0§J§à5=Ú£Üm:"/&.‘îü_ý‚!N,vñÜn±´nÜ4Pއµ¬.Îe샡áÁö*Ëâ4tïÔ.pÞà@Êe–N!–2PANQpÍçðF‡mÐ’=ƒˆMÇÓžÛ®P﹆—F—«À}ͪ®è->Ÿ¸ä³­‡ï0‡´©›v“Õå@©¶xê&<…p¬ÁÖ{ñ¥éz~Œ:±ãâ|R aoÿ=Mðp$§üÍO³‚“[ê‡7Ft06§è4?æFݾðûಚR1}1Οœa~=Q*´w=n…Ó½`ýÊ–Æg%¾|ÂÐ…û€S«ª þ6o‹J%·†Ö§ás@@Ü€R»Ä™R=ðËšÊ)&ð±êχw;<’Ja}¦º§/~Þ}Õ¡Œ7ú êî.Õ÷qI¥Í’ÊW,§ 4ÿ1™³œÒîÛÄ4ídçù“ÌðKH/NÍ5,´*K‚k>ž¤Ço;*W"ˆYˆõçÓi—ÿÍá“W¯_î<ì¼>øi÷ùÁÞãƒÝ'ƒW{O-²r"·ëW VëóÏÿöìÅë}W£—fÌ«­aÖ§ý)¤ÿö‘ÙÐ @C“i²÷üùî«ä¿^ì=çUÁ{ ¬Í4yñÜü¾5•Ò¿´\æáÞ Æ êØÅD™å0-±LÁØñ3óG>Dú¢¿äГÁF4 åZ‚Ù"¨"¹w\Œæç Wô•ž#êŸèí` ©Ã-ªˆ‚I>þäÃ&Â;GÉŠnž˜3;~x† ŠÁ1Ú˜bfÉÓ•/¸rœ ™þêX1Íœ„²ë,ˆ³Jîq¶Øž¢»ÞU5@’ê°o3[ZÁ¥}„(Óœ$4à h÷w*L K{§3Åi¼n‹ƒ4æM—ùPðeòœÅÞq&3õpÅÕ #Çí™TÇ7ÊØç}ŽK¨~âEf0}2{ä½Ð–É'X¨|€íê(&úvfW&&â\ªRhÌ&\ó D²¤MÄkzéôଧùZxt†¸|ø&"uÙwQ±«*“rù:¡TŒJ8- +þ*2èç4¥Ÿ”Šç2ÖSÎRv€ºå1ðÌ;ÄNÁÕ^e€+©F€Ñ9„€Ð"FûÊ—„¨DÛRr¸kÀ5 ŠJ}âTr±»7fJÀ1ZP ñ&—oÔ+ˆÐåE>Ã’*_4ü€(ÇRë–i¤$CšO|Ñïáuò3¡·-Oó?dø hÝÌuÖÞòa®í-õ@¼%U/ùÅpÌb4„âôH6€}Àä~Jv’-¯]b(×™Šª*³ ”«‘9`oQÝ$lÆKJVKß)šÇ°h «ù±nTž¼‘™#Ò‘ƒ´®µ‡ŠVNÒo;Ù¨ZŠ Ào4…ô‹1ì1’¹'eÆÑJPÁÍ™§üyŠV\•Eò¥ˆ­Œm½$wHca>(ÞeÓ‹i.F–Üêå–‘º¿‡D[v‡, "0çƒóÿ Mí(-gb3#À°_J,¢ Y,G¨z­;™¡5}þ€0rRø®½a  •rc¹IŠŠÆÓ{_Qep¥‹»Ü~ááÍæ½…ßÑýö¦Üo=õCÃýTïŒÆ+¤¾›Vî‘áõ4Pu[Ù&[ÝÝ:,Kÿ–EŽô$ëþ¾9Mp2MÿÞãÔ0—¾Ç9F€må™/,}5¶´3r# AÚãí´ÿþËûoÖWyÿÃýäp+çç[oþ<课ß²ÊTûmJ¸ž¹½äæÞuŠ¡É ©Z2—ƒÓ…t¶×yÿ¯oÖ?šÿµ³þÑH%öÎT ‡{û/V¿ùæî·«É×Éóï÷_zâÿ´¡¢'^E®¾ýâd¶zv91›³îÛÍõuêùå[ z²L QfPÅxÖW´ù W´éUô}N ñªž@ä Š9†•e •Ýý+»íVsff Ašvî‡Ý~¨Îtîr&¨Ï€{YûýëØŸ~¸·®ûóƒ¹r­^äC„43©¯à‡o¹‚žè ^e“‘™`p¶\bë߬Í͹PÚ$.Y¥ü{N#סæñ=úg½EÉÆ‘öŸ; áÊÕïä×îWýî×Ãü¯ÍÃÿ9Ÿ¿›¾ùpR|0ün¥½pß±W#&Ì+‡ÏÞŸ™8ži¸|$H¤¶™[ÒØ¬€àáñ)Ú.$þÿÖ¹áênÁ0cø9ES{ò<Á7ø Ö˜ÿ¬=@ÝÔYÿªÿ®?Æ¡–›˜›Xõ•d~Í Äéį †Ÿd%°.=rxI#§‰vê‡Ç‘œ¦7–{‘T½ÓìŸsÃKŒx$Ÿ’³Á„ÞjÏ~(QLäÃBi×´PóóôT;A‹—tPJ±·Í1¿ªû@hÁ°ãÅ™ †¹ÙÙ”¡ÓÀ7wßs·Ý7RÉr•âwXÜÔy{½ !¥ë›wÄ›ΨE{”Pi#² hž:m©‡þæ0O–ö{T;ÅÈ›]Oì_œ¸–¿ÄvÇÆ -ý©“󰂦¼½ñ ÂÛ25®ira„ORÈÍ1ô»2a]¼ƒB1ôF±©.ÖîaÌÙˆ“ ¡%Å4C&Yø9kF”›t†“K eãåÓtzdz!µ1r1Õ9¡‹i~ >¡Lé,ÁƒSˆY_"Lp]…´ì«Ûð_È)7x?WyqÁG@Wü7\nûí5 cm÷%]ö¤Cè·ûð š>lƒ;2R{[žS|‘6uÍOÞK~Ø{º;Øýï½ýs¹Ú}ùtçñ®E]`—ŒR«z®uH ³ÊVvÁ¬ƒpH´Àô”ÒÅŒýÝ"‘œ]ÔoEV‚6‰f ÐÁ4--Ç!íW¸ã¯´ÖÔFÌýȆ"u …Lõhr–²ªãRÍÛIï:+#Á9ØX·œ=Ý¥NP@Ÿu*+êéµ;ÙŒ*±Í£VÝ,0ðìºÅ!ð‹¤ý¢í2 R„È5tê2€Â™—‹™Í.2Aš]„–^Ê>s'LOÛ{f:7D£=jÓUz?P½‡æÑñ0;9=Ëÿñö|\Lþ9-gówï/ÿgçûÇOvøñ§ÿúËÓgÏ_þ¯Wû¯ÿúóÿíoÞ¾s÷Þýo¾m 6ËÿΦÅ*DJ 8Âô@µÁánö`>Ñʬ8°üë`7YM6¤'Ùñ(å42®D[n:~ 1êÔŠ¸×Ú>>%ûLacÀ9nœ°Ã=SFŸ.ïæxÉM%ëÌÖOÊKøëë¯n„írz)ïö ˜-}ÚÁmD1U7#ÔsÊÉ2à„L1z¤¤§‘õÅ×óð|6€f;æò Ýí¾©\ã'cæ6dšžžçã ëQÉk]Ïpné:oЇþ~Ôuç)éòu;Ÿù–2T Ã[=¶!Ê/ôk0'BñâÜQôD=£Q* ’< Õ^ÁSž ÐP.9¥9îq.&tßd^¸|S]†ç¥£ãùȆôÆ«r©zÆháá(ã¡HPUCåOH§²ÓXFý#¿§¸/âFlþvI ·êŸæ”µ–ë’KÞ4ROiŽqsäWyV̤tZ$.A§ Ù¢AE ú¾0§ÿÜL¸‘Ö‘­–@c¸^1)¿5JsÓ |Ë)‡qQâ!l'š›™-£L•ÎG„Å{¼ê‰Uµ÷Xà$6gÉ LB$䪰þêa)Þo68b4rnœ.6ÂeY—VEñøÖé‹ Ú}˜4•w䀈{Yl× ›qUæÍpΰ}ŽŠgj ¬.$xœ^©&Ô1ñü¨¬ž>:ôú¨‚¥êã!'}œÉzGw×™ÉÜÜ'/wúÝï´úÐ*Àj¸£š8ÜBFèku­ë+ÒýÖ» ¯8Ÿù‹å\æ©–¯¹šÁÉ(Ÿt²÷žÅÎÔeäyS®ëù&Äf¨k ™|ýBòÎxÓÕgÀcÚâpä‰fÀE¤™c‘œç÷ƒlô#þˆó@EÚ½ÊÆùaŒ(¦2mÞÜ:¢h½°‘¤Ç—‘é­Š“ð|‘Ù±Æä¥Â¡µ:FÆjcè“Úè+Ä[;'¬‚ZqÓšgkɾ&¸F6ÚÊ\K5.Žøµm!V&l|XK„hÒoñNÑçB#ˆÌN Rn03Òkê@ƃæÈ¸bh5C=v 0ÿ¢¾Ä ùø¨`d ­¥ÊaÿȨ’Ýs =ëºÐo…žõQè)§xŽÍtŠ¿ƒÕþÛ`Û»c¨•—Õ\Ô;,ŽÓAoª0ÚgGqWOèÍcÇèå|Ãçä˜c»cÛÝ%:LzóÝùeïªã—Úâ›XÒIß™™AœR-š3½L¤ÉÀÞoï®N¥'zUº'_ÿ’ÞEjkÒªÑÐʼn+äÞðÊûKó0« §(—­ÄÝøÏ - à![a—@p¡ Ò8ið;r×kÓ_ÀùaŸ:9¥|›OXœ3F¯’Y¬ÓR1‘ 7$ñ˜AÆQ­éÇÀ,Fež™×éI_“£™o´g!ŠnüŠÍ˜ÅÃSÖ*êð,©{xœl"מ])f pŠO§4ö½ó»—©E#Õ”êé´oþòÕ×7ÀnÉì««oðµãîxJ]º3Ž0æ{°C$ÉT¨ &öê3ØCðX¦‘Ó®— ]?œ"tÄÑIútï/»öÌ»u«¼uËl ¯ø)ÙceÌÙ¸q©L—0OÕér²“lËCjÑÑŠ÷¡‰ñèÍöG'÷GNNíQ>~‹ͧ#â$k^Ù¹sxh§G¨á¦F@dév½ÁTÃ$"ÑK®ÏuV&:ë¿õtÿsêÜñPs”%8¬ 5Æy¬{ÛŒ”U µ ,“„iî,ú¹F;Šo,ÎÄÀ!ÞY%^ÏC:C¶ß '8·Ã›åêö1f•ÌΞ¡È ð Ô8ã¨\ÌÿÀÝ¡Ï$-ÆoV7Ö G¹НT¥/6µµç©\_,< >Ö Ò}ñue€xt[À ê¢»q9d „© †gLÏÇ]÷Ôm,snþD™¹å+1Y4ŒÄØà—àL,9.ÚËïÅ3¬îaºûŽ(w)§½J.ã˜ýÑv”$p=Žš$è&ˆˆp\‰˜õ,áJkä"Ø„â¢>è9—ö`É[Þ;Êö\7ùÞOß“9£ÎWÃöT,öwå‘x(Ø“>ì(…E;*ÖŒx?x½®Ÿ÷Ö?¥[<¯ñŽñKµ¨sÛ­§ÅiÂh_\!åöõXáìWn³jݦôõrY…ïQ3<ÖÜ<‘§bÈ™ÝÛ=¢¸5UHZÑSÊ›H®PaMˆ½µ­~¼QíÇ+2 àW·Ü·vWèI¬Êä]ž²³ë/ˆœ>ñTäè4ÁPöx] …-!”1‰IeôŠoèÒÒ0¡ßùz ò˜oFö uH%vù±þòpÝœñ b è,Ú¦‰…(ƒ’Ÿ•˜I3W]PÏÛ´:ºÔÛc%ß?}ñø/ƒç/wÿ´+Êk.º4÷<}—Ÿâœ¨æžeã9)oñÛFG0lÀ¥‚A¯æs(ˆY£á¢ Vl©"MŽçFØ9ü20`¥Çoûø @5š+ë0F1¥-(±¢CÛX~h›ÁÐ~>+~iƒií¢­œþŠBljh=„ºý&oÇë¡Ð_)¢ ×÷OßoèÙu_€‰ÃfP§³ž íQ²éÉI,Éc]ƒ‹³¬KÙÅ€€ªr½âmjV'>·ö T433ÌËÉ(½Ô2¢:Íx7F˜]¼o½ä®ªˆL­¥>|ÏÓÉ‘ÚX†Øè%›½äv/¹c>í%÷zÉý^òM/ù¶¾íoú+NðmmÅË‹¡Ã »t{p¶Mû›ðŸoÌn¯ã#óŸo×é™ùïæ}øïm||÷ü÷þ&¾]§×øæÎm|øÍ=S¸k u[:«¬:g,0=Öœd¼Ú1!€¬/ùì¹úU5hGuèõäi¤ªm&,+÷Y´Ãc³ÀC¬Ï¢‰£*Gc[”—â·0xâ0PÝçFÝ,™‡ÊÖXz–Ðã‡åŽ«NTÐ:’l8O5D¶Žä¾±NÚ ´Í»@h†bàP¾‡=Ÿâgéûü|~®l¼Î‚g:Üä4“Ëï%p¬ãSvRÊ…,Ðf–Ö½Jn/ìC…‚«]÷“Xm••µ®Vcý |=~x(µ?ŽÛéPP¿îeÁk­¹)¥­|ô­¹3“O¤âÀðË‹‚Y #¤£qFÌS…ßTˆfàûnö´³N‘0è+€O$¼ßèR¬˜Ö™â°P%e½àãgå…sÖ»Ò”ë*ªªF,bAQpÞ6¶¼±® dó…•Álše@‡„šŸïÈe\®–^®w+.vÕûrÅálúÉ™`¤‰ª ãUf$ú #íÅíQ®ebv(ñc‰¹ù ÕI¡þIi$B…Âæ²/â+fpðV;ͬ1õÉ ìø7ÅÏcÁ¿_¼z²û*ùþo±áÉîþã6jЯ$¦|.»»WiÜê2je|äi_ýÛ̓%¶/ñ. *jóŠtuûSèê1Î ‘y€ ù.·.†ß¢3š<’¡ÈâW$«WR¼ÙƒìnìJ&øÞâg¢Ù—੎JÜe?hv¸ûPN ÷«¦ì=inCó>OˆÜ˜rÄ)?ÈÈŸ9õÆh¡BBh‹ƒtì øËêÁ”hb#î%OöööžÃÖêãæš÷É´£†¢»jŸ+Aú˜”,Ê¢%þËÛRÕ´ ‘˸9©Ä¶Þšº oÏ¥Æ&s²î•sUF}%YÌ«%¢Ç‘Ÿ%vd *¬€NÛÙmåw£–]øã]]õß}ô9Odî¾þÚg>>Ýþ€—2M+B»úd ØþÉé4sDîB²€2„H±µS.ж£Žïaðսشz‹Œ„eu ð¢QA¸t•Óæ‹Éh>MGáú°I­½AÞÓwì¸Êù¶hmþ±¦SÐm©ªðoŒ_¨ã÷1оêT€³Íÿ©sá“ߺ…(y#~céöÍOt!W cÛBÝöl³i¿Po7ÌAóyîkžü/®w¤ËK/É¥ý³sé|A%áS6õ'gÔcÅ'€/j椀 kD+[ðåªöîGÒ2Ë¢mùŠYIf4˜L3NS8ЖêΗ®?l²ûÁT„u[£¯·ÞfFxŒúk«Jmž2}‡ ±µa•ÚO˜£±8°‘ý×ЖUù¬âÒÙ<01KÁFmÇÛ\öciÙ^üŽ«JGÄÞZÏr*ã¢ÅèEÄéç»ðÁVÐAË‹0¼­½cÿì*ÖSG bR8'ÿPé{»,ÿm·ÙÙ;¬,5W+m‹ÞT>ŠGW°¬ü5Û× šÓÙ³ÙùÈ9á8ŽP7£NôM/i¡ÕÇ&#²]«€5ú\åEƒ _6î…áC—®ÙÊ80´Œô½O1'}!>ÈÏ€™±!]t>ô|p¶°nAΩŠ1‡Y“ß' ´½4ìkZÌ'Tf(àIø¡=è²îqØtÅgG(Æ—L _JZtÛÇɇêÌak”‘þç¼·ãö2éa,ÐŒd ulx$š…Òªƒ#ðn¢Ñ·ßb^@î%ç3ɶî×Í(,(&æ²ïQ ƒõ´ßÔô–B¼ùØwöê@HB7ÚR¤±²Ê¾õªŠÍ‹Ù独½1°³gm’wWMÙ“&|7p‰Å¾ƒH™è AÖD9/™OѨ&l¿èÄgýÑ£$`a>¨6ªKŽ­P~eE³þ²^½6)˜Ÿ¾K rÌžÝçå åqìþ\±šhI>,¦$ǵv|£¥•„lÜ!¨x‰ž«n‡à{Ó´¼+,Âb¬Ï lÃ%9â5“e64¨)gc‡ß7ÞxàXq°^mY7-aX‡=·«Óêñ4ò,0Rx  4eªCMXº0ûk€ÆÚ.™ò‰‹• ¬Òº4G”xåê’—F¨‰?´F¦g»Ï_ï<}úýÎã¿(<ŒÚT›] W~O L¥ƒÙ[ýÅ'½à ØýfáòiÝŽöôÉî;¯Ÿ ž¾0}ììÿ¥¦O–7t+â´S?ÃÕÂ+Y›:Õ'Ý…ƒ°øøýq_c­¬ PüDˆ>÷ÌP2‰Ï@Wž’ ¥˜;ÏÚ-ø¿æI°ã_u:Ø•¶õhšÏ¸—EH`fr(<·Ö–âS䄹Œ¹ùÐÂÝz†E’Ëb>ESS»”S”ÓICƆhz°Fd=Xö[2—E™Û*Û£ì¤iãRvNÔ‹Ò(i—"ܲé¤ð£gišÚÝÊ,sÖ÷0§-–H0 .ðYض6áÏb$VPqUÔë°Ôb”uKÐ~jFÑ8ŽÜæ,~öÆ(Æ/$hr•[fj+"QœjýÙlš•5l»é(Â[ÔòGKâ96s¬DcH×ÓÔ‡!'­X8“\×'ÍåÕ¸årSm¿q[°Ž‹c—R\ «q€ô½Ç£ù4‘S-V±¿0NEÝQK"jbe¬ l¢ëëqkb&ÊýýW¤uÍ¡¹½¦c’Vç¥]®Y‡,ã²ðb@p©V5 \·àäWšvL-Å)׳òIL†šä,ÐÌ{)JŒ“"©þªÐÀï;ik0ꦙۅƒûy•Á}®]EŠZrÔ󤲣²C7R ²4: ¨4{ÿ!‚”Cüèø—3ý—îÉrgüU.Ò¿½Àߣœº`¦mÑA>+1ÔœŽég˜×_ãT§1£ï[ãµ!<ª]jàTñ¿óЗãPW]p¬õß–A­‚gÓ°9ãÚ‚Ê Å3E] ³ÿç9ã?iÒÔ¬ŠÓbÞÌŠSp¿YJÉe ‹èˆ›­r/‰Ù¾²þçÖ;χ±¨5 êÙe¨#»Xòq@ŸzEc«¶Ñ]0nô¤^D@‹µGÊZ³ÄTÝÿª§ý)½†i˜à¿ª~Êo}Ù­ýÙw5ï`ÞÐhKûœºû宺Ÿ¨Õ¦"aÛK ‹¶s–¹&Y++ÕUÈzÁÁ‰PÂÑ ¿užNg'³÷u²ÝuftÍzà4ŠÉZn›\m4Ü[4^ .·éhÀËÙð1àG¸ áΊ‹¤7…zXæQǯ†“*±/°+HÿU·Î7c3OiÄ7ëÀ„9Œ9™!çõ“l‹5Ó$ÆXt¢“ÊmˆúÍHü,\O@— k«„6Öž$*îÂ;.8KTkD3oºÞ—KìE]2ºzÉm¿ÒØÖdß)×°Ðnhxù”‰üÖªkØÈ’è'êóä,äHà1?•q>cË7Ÿ‰æ"786|¡A™Z^D½Ãî3"½¹—hÁŒmúÖâ¯}Yð•MhvJ ÓS³Œu>ÎèÿŠ1?¼¼›°‰ûzÕt|i³œZð÷€q‚|ÄWŠó0ná˳À0`–×ÇÞ ø§,*Eûùqm­kͪDšb²-#˜³YJ/‹ˆÔç.ƒ0D"ÝJ;‡+>È­ÿÜ÷±— „_ ä.,`¯F÷UÁÒ€ËZ±oˆ2ss £Éß’G öšE ø Ì¹¼è2#–úŽ2ðµI1%›æÑe1–T‹fÒ“ãb:ÍÊ ¤$†ÐAB'¿eñö8Þ6K=â%K¾N6-ÆÀ_qØê¤:wÎÃIiNË3Ñ=e0ÎqF€øG™ä·¬´†ÓðÈ¥¿\¯øA9ʳ“ß;OÞ¯Ê;&Ica±©v¶OKËtÊɲª –>á$뻃.–"¸`P˲„Ï»B×ÃA ;Te†ºóÜ—jæÏ›¡sùG°©Ù’äÆ,û€æc :«’í™ÙµL#ALÀÄBÞê5_¯.{Ð… f‰Ò™¼‚6™Ø1 Úax¹°ýà!tÌ÷æE·$» úç Í ó…Ц*gvØõ $[õ@ࣀøH:}ˆÌŠ„òºcÄÌ×½‡¾q|ypBC×Oá¢ò ;í'³©)Ó·iŸª¡ÜxÄÜ(œêýdà2ç²ì‹*¾aóÚcÄ.çÚ»%)9l2e-£¼Pm–íSô¶Ãâ™oµaž£nz[¸gÅHÍ!#ãÀþSž­S´MáãKD)xFQàãGw%Ñ•RÊØƒ(p>%G{/KD^CB;Î|9p¦«'LЉ¢IЂu\N×øC9xÎ.à.3Ù¼´y×›[ëW² €#9 *ä)Æ™*§rú˜Ü‹ÄÒKäý2šGñŒO½L™ÒeϽ»Ø^Ê÷¤yŠ·ä %ºYՊɤ{nnHÏ1ºr–B–Õ‹R76t‘>Y"pYååßV·©·”(ϤK ½¡w99Ù×ß©îo±*SæY•dªÀ®®EaPY?y­Øï­y W´9iPÿCi­*„©3ì¹e}ú…a-¢15-éI„üàoK‚ eS²8œ!¦ö‘%´“Éh^ºfõ53Guê-#aWù‚AÄ“°Ó‚W{[Á┺4³@P*ó­,{mòÛÞ› aÀ€Ì½dSKhAëjŽh»¥ Kt°¡‚ôʤl[–‡-ô|§êžôðpÃ%aFaÎt =91‘ ‘Ì}œ×=//²ícÇñBqÆFT2÷[pÛƒ4É6IÁÒÝÓ©´½€S×)/uÀ‹š'iAëaÄ'G­9›>`)O¼öH%âI"ˆŸtªÉ+èk”Mñ‚biE¹ÅÒ$'‚ü5…; Q}“ áSî9¤8xã£rY/f…ÂCvňÞð"[Ý 1éÕçÇr´XˆqixÇ(hbR …kX%)X°§žöSìÐG'â˜Ö]LىΛ.Hà˜ÿLù5àÄ9l”ƒ¨íc~F¼É¦õÚK:†wAØç“t ×%“P÷³LïfÔ*µBبún)èËZØKáx³·dÿo·ƒŒ*!0ã>D.M £p€à®Rš’$@) TJ™µa6Îmf¨g†ÁfJHÒSˆC6"ar‹ôÑ£’‚Zk$KÈ’h¶:о qÞ€}ØÄµà‘ñ•È_.²‘!”bIÌàtÀ¤Ò¦”¯ Óv ú‰ÇlX¥fžA/Ü((¤ Ù”-aV%§> §;¡EF.ì*™ž_U >•¨SjdÀórŽ)ÉŠ±ùèfp”„ ,®!ËÚ­ÀA$‹BŒENîÆŠèÙXPôr‡†e4>±Hr%Üñ]RG›dWŽ™¨J²~“ER¼ÔQTºMƒ Êø£òS¼ìÿåžnŒ¼ ìucR¹‘lV¢”˜sRöÔ‡éXqg‘‚¿~ü•«Íg¼0}.Vj²¨B:ÔR_’“CE¸ð]îÆËKÊçJË98²À2!(¼üð]ZìÕb<›£r©áû)ÁSÈm˜Mß)ºùÄÁ~ô¨7$Ü„ªµPÈª× ýÚ8$d™¯×W:Y/±™µ°¨nuqj3¡Zª'oõMœ†ƒ­¼ÌdpüQ攑ŽÉÊ®‡êìÆÇñùTìée.³†qµvÀaúÄ/P™¨kHo¿˜NÍ]o>žš“ãtl¤YÅ©Š©Êªû0MÌ!vò¨õgyÖÚþ Fþ‚Œ\>3ƒDiLJ|÷p-ÝV"¦•v]^wmIö"Ÿ ‹S»A"¨dÀ"™¡ˆÀ–"´eëÝ_,±;Ûâ€Ò€ŽPôr·¤mÓó”X7UJÇ^¶èë$‚šqù1#0ÊË eò1Äa„—æÑ_"Û)²$ªD°Ò| ¢´š~Úì&I1‘bJ*¼Ãhëy*@t&€1ˆUNN ž7’]ª¦?Ž Ù8!tYô0ÉA@‚šOóäVO¹›­1ȵ¦[Г$ô%é÷P Ÿæç¿Ý›º.qúv­§Š#¨žNœÐÏÏÆÔ]¼Ý«'hœlvzuôø>é¢83L ˆ,¤Kbnβ?¥<ݶÅÀ§ey." ‚ÙÂ@ª—ÛƒÆ,HŠùŒm’¶asÂɹM£8.˜_˜Í5™fïòb^Ž.©²lŒÝÁAóNgbÁø@8²gœÍS™MÆŸ°ŒÈÂ׿ç5רV‡ƒ 1è*Û‘Ã¥½š8n9 uÑ´“弪—æèà–|¨”’x2 -v¥+7g°a¬´áv¢lÊt²yÇŸ­ÌcnŸ«P/¦€@¾G}¡§‚ÿ }ªª~Qì#ů¿5 Ô™­žWcÏWÜÝà^`¾ËÒÔí=AÈ ³‡Ñ È§¼5lš‘f³ô˜úŽžS[õ—”®Ñ3þâmÖ±ÉK9ù—Àù(- ªg¬`(ÖM-¾2ßN)I­Q!HéjÓ÷šryZ tó»LØQ’>qrFgÄVÚÄ8fÙXã‚°©—’º¾“BZÐq&nƒJ½‹¥næÃi>Ì$9õ ^üäFW;«R§'~I£„WUßj2¯Ÿ²àaÚžâIUõ“Ý¡`iø¨à±G\)³§m¿½T: –v7-©“¨×ÜYʳ>)&nÄ©fEl­„š[Ï Y"VÄ ­VÐÏÅ,÷€OŠiÄ1¥ð¾§uª>^±(*#†EGÉ8c€àS÷]=œ ÖOˆá÷M<úœ€Ä&wºt¬!¥ ®~§E&yزÆ9žÈVõ;vÌD‘ ¾òÁÉÜÂQÕi Ê Ëej9ÀèZàTènDzFql(ËÁp>žLµtûVÉr3<ù­a6>=;³Nk«4Ÿ[öÎö[ 5b‹›Òm›¨/*QTO¨çf =‹í ‡$² ê[/£Çg¬ä2ôŒ‰¹—ü¼sðø§'/~<q°÷x·GÙŽÐÿÓf7ò8ø\ÒëºTdqÃÃedow6êcK\0MyÂÖ#ðÏ¢¶æ¾]kõ½¶ÌÑz¦ ÍÓžjJ‹â¸»»M¹9#Þ£^3²‚¨b­ô<Þí¨ñöû)üNå#¹œ~𵡣U‘CáO‰—üxàmÕ§ô8ù™m¨”­T¤eƒäyïÁ6´[S‘²ØUC ´ …R†g³¸)R³³ÕD•š½;äj ûe€ÑxËG2€ûA"8e†%2D¢À GÁ `Ã&ø¦) ~—2VŸå£x˜ÚÉÿð¡ <ŽsBx“ÍOÎnVÐPØÈÎí• £ M£I4s çèà²-¸¤É´ÆH¸?IÙ„aÕÙðA2‚Ÿ³ØD:8~g˜Ýq¤bʘ÷f'Ÿ]NÌÒ ÅxhhÓÜl æZ §Æ è\Š+Š×ôkYšw½«·¶‘ÖL)5·Aï>ÛÙ{1@Gó‘·£õïÀ‘Àtc!JèxCîÛG °“º%ûåÓùˆ"=k&ó£Q~ŒóŽõ aëˆ}ÐÌVíâE^žAÅF~ÌзÇÏh·ü Äq6E‡fS®„÷pK:aY0l¼Fk±•¡nÚ Y¿{–°„ÛøØFz>PÆÊÀÓ ™µŒ{s21;#~哯uUؼ.Hx8ʪ&&H˜ûƒ?#à1¶ G æÄ±ŽkNÍËiñÎÜcðzÅ#–;™Â‚kš…šMÜÕÐÈ@E˜Ç=/Mb ‰ÿ(Ùr’±ŸÿŠ:gšûžŒh …á1 ns •Ó¼î÷¢¶íÄ bˆüøG‡Á­ð ×Ú¼B’j÷¨xymصÛ.iÛ·˜^ª”šÎYs%7ý¡áA še#òó3Çݳ¥)Ó=n©'I®âA“ÍåWnÜÉ“{¨Ùs/0-°‡ÓiJAB¹ÁHmvLœf´Ê¯o{з“ñâÉ‹-ÒÒ8U¿‘AÿzzVÓÕÓÜÇA/*Ûrž%_ll|»~û‰Äàjþ|5¢|%EZÂÃ'¯^¿Üy:Øy}ðÓîs#ºïì>¼Ú{ò¦‰>ý%S=1I½9Fb^МvCÄ¢ œY§‰G9í†ú}Á ‰’€‚9,&—¨ê¦ŽbÕMf¦Cþ‚½MØB]ý>r”ó#]ÊKñ‡Ýqo릌Âù¢D!{–á×t:F„¨­µý¥”!Œ~=Y¥ÆÐúíãâQI ^wlÚzuxdþ"~•uJ}IˆìHùг7öF=mîrFôLvm)ÉX5ÚxþPeÔ"‚‘4e˜'{!iá³1:¡y–×ÈŒžAæ%a¯­¥ïR3°bðÒ54.·†¼oº¿U|ù»Ð nCÖÏ%NÐ A¤¹^Ò!e]×%WgFB³mû¥XJÐãÃ6 `ƒØ Ôúù9!b¹D¶Cœ3‡“ÁX.='ʈ9p“1GÀMч´ô,MJºvÄ!¦~*–ÁYnÝqÛ«·¾ªùt˜µ”AÁ¸ÁU?ñ'ÂÊnw¾©™Ü1ïò©¹Ž’scD÷ž†D’ws³3 î“·ôß7pÎE¡I¸ÊÜÂ_Þ~¯ucS­¦Ñ*i:þÍÝ÷ßÜ¥@vD c†,h¾¸½þI¿´ûMÎ ™mJÎCâñBååzhUõĈёJ,ñ¡<´»'¸,a:ÃIÁp#â°juW§¼rž1¡ìlr㪭fs‹Ê›0)ûç×ÝÜ\á„ ŸMo³@‡¦}øVHÍâ·}¨¬ã)_”ïZ»UUã/w4 (¦N%äêñ‹×Ï:_uci$aØ7mtÃÓ?ï¾êPvÎGü—·pªHÕc/ƒÛ•üé8a–¾Íj|ü¦®ê&xµ©­öÑ:…ún W멜àýûº9ÎkèŠvÏgŽF®b‹='Dà–Ãì÷Öž`fç¸_†LŸ£0c„øÐX,JÚxµpãjˆ{µEÆO‘öòñ0—á¢ÁŠÆRèßå…ª>Æi¸/«6nAŠz¯óf"èÅȤqÆ*@–8"³ͯ†ú)_$d _…Ìtæ*AKBþÑæþö¸0à!,“­Äx¶"D0ùËöŠè±‡Ÿ¤˜yy¾†˜«‹¶å!%†ôö‚Ûø33_ã²ÃÕ)_ÏÕJ{ÉÖëR„öiêì¨Ù))¤ªÑ!¨ò¨^òe©®B,R_[$Mpײg¹4ˉxÍn¶»ö†+Z0 &»§¦§ŠÃø¤X÷{ÞÝöb¬©«½±‰Ã.X7äÕm[éoÏ>#¼x*Mì!ð8ìy5(d§¹ÎI%¾ßœ(›iH÷ÎÄoͦA*+_u¦z^Ø&zRU¬•ò"ŸaH¿é·“+¤§m“‹A:1›ÔƱrYŠtùã‰xF ³Ùu µÜ´×åt–ÜÄ4/>+· e]Ëté8Ò‡–m¯÷Ëø—ñ¹¿¡ÚJàhkáÞô“¿™·€Y56ÜLB5Šä&ùÔͧ9û-ùipݨØÑäê-hRÞl¹¡ÿ2¶%’›ò+”•¦Ñ—–Û6[èx”ôÆ !˜EzÖÉ%vžE’ÊÑ:‰7…#.0G'Tmû?¢y`§ÝÀ=Üóê#ÄFŽsÌÑ_î œóÞî±ÔþïéM”ÅaÊL­PL©9¼« ÖüËxu5¡EHfYzÞº"]ÐÞ (üt9ö³]2~þÃDf> Ë×¥R¿7K’ç%5ò;'=ÀÛR}Oÿ ÜÿTÂdˆºç¸ZH»‹Êó©ðÉœ8épÕ|JIÝ«¥‡Ÿ—=O¡g#ÌÏzRqÍ( šw¤Ÿ¼€8xô¸gÕ½‚Û½¥ëdîoà¦ÍÊ %„+_?DG>ۇѨ>¥ò€êãUøuˆ‡ˆañ„ã ¤{ëÏ!vÌî%{dýlÈo¶‰_)å‰øÑ»ùü$)!èÅÒ|—•<$ŠÂây Ìb]šXK=èbf‰S³Â€ ›‰÷ä߉/&{3fÊ!i¡¼B”Ç0%ß ~èî‰3C*f¼å*ûYë’tǺÁÿYø 0…e9_¥KÞß4Qy½KPGYÿF´ô랱ȶ¡ÔhÅ-wÅLØ–ÃêÆ(Š­ˆ B“y2GM+ŠEõ"ÏÕè‘#> r]W$BéÁuHÐÐP@‚‚„qµY`Mçg™®ëг =ø<³Àµ-šƒñ•N¯Ò„M÷ÕÕ~Ö´†”$©Ò”“;ä9(OaÓ•“ì8?3€zr z£õ‘çÙùQ6-aï’Æq¼51àEÿfï!±bÆ~’6Ï.¶ç)â—¦R_BW”¼”*_NBîÈ Ë0ê¿§àLYUê¾áˆmX;ŒØŽ(MkÑ1"Ñ4ˆ¹ŒÄ¨QñÃ4RUµP¡älª§OBWzz<ìPð{#/v(ˆ‰ùäS7. ‹ËMa±âÞªüÁÄ ïù‹ç{öâõ¾¸à¡ÎË+sÔ“R]«É»”ë²ò®­…:ö¿btñc2Möž?ß}•ü׋½çÉ¿\]“Iòâ¹)>EÛÁÿ%k¤Å’§{ÙMÚ·nÝ*oÝj'/^=1µ|ÿ7ó,C˛˘^+ÒÇ6÷Ñï¡­™\¬š@¨âÒ/ÆOµÊ1(¿º=u¨¸¼?gDÈfŸË‘XÅI×mK_¥fS±%u\м<ÛäÐêúC|ü·E•¥Ÿö7“ÚëEH6®'WjÊk€ÕŒ ªRUÝ ~È w dòs#Ž%ó1ò9pÃV{JÁ>ûIræ]ÂL€»»˜drUÆ-a!ÙVQ6»bAîšùTå(ÏóÓ¥GÙÈz Q1V–Hhboë¶É\ôq ͱ&Ç¢,Õ…ï?KbͳõmAûl/®ï@×gjŸ+ˆ^/ë7Î (Æí¥ÊöÝã餤ö !ˆÏÙ¹)‡¦K¯k¡tu%ª~]ecî%,/ÛHX%lœOoZ×±öö¯€•áôF´uæÁ n§À‰CGÊA!1TÈ( %7k*ÏKO·ñŠ˜ 7ã‚Ϯڞ£H[”ೇ¯U&¢Ê÷NXkkO+“±R.\ÜÐít&và CJÂwTP|Á‘%ƒí’N/C ¬`]1´'ˆíí€Ny ï¼Zig¿±® ¯ÎÃõ7Ê›Z•ƒìS¼¢mŒóß©EhkZÃ^Ml¼‘ÃêÊ $XÆÃÅCŽgºŠ°Ðssjææ˜Â1DrQÙ,Ñ”W¶ÅZQz%Aˆç‹­ý/¢Š|0f´ ÎÓQ~ G"̓Z›¹­bƒâÄ‹KÇèÿ¼óêùÞó•РüîX_Ñ›Ãæe&|àÔ]ŸØb爢^Ö™.PõœŸ#¿Ôh$Køuòñ¬ëœˆèzð6Ÿ„=e,³KßšËH~Äëæ#¾‰hì§Õmº ÃÆP~­6Âa¼s?«PaUpÇ…³~õ9ÿ=f|ñ|Âlo\u¶×¯=Û†šQP>Oºjã€äš^ñ{©p7¿½¤Â>ä{àÝ”9¾Ú°0nœ]±¢ŒªÞQ=‚x4Ÿ%eaªb¡¶ÄÍ÷爬^¼¥Ø"Ó^–íõxÀÐÿ`¹b }¤ èT¹³M‰&n¨ ž½,©”ìy#—™Å¤ymòÔ$JKë´ÒÞ¬ÍìøìZ.kQ=ÁÎÌ]Œ/f:Ï™œ›,8…“¯å¼ÁÝVëâ%`j ~òuQ‡ÝÈUþUK1¹Sþ7^lÚ[+1FfXÀõà ËsÕ¡kï0?9 ¿ëÕ¯Ó¯ºPPËyüTÞ‘tâ‹è U î‚ÏÝ0ŒÖÇD˜L³“œ1êÎGÛÝUÎOÜÃ5y:›f 4‡½= B—’4<Ö×õЍ(µŽÉŽübNÑ®«]!Êê5K•–ckîÁ~È•kÝ&-¬ªó}0«£¼2«*9+á´u“~ëáš)ù˸â—(¡xùžˆÖÀs •\Ò5D`rЦõ\%§dABøN4¥'2´š†’³}ççÕ?t3ÀœkìNŒ!`/#b?NÇ Z:j^¿¾2§æ0§<ã$æ¿¡š.úŒ(YLî^Àd'Æ´\|‰}$.‚PcZ~ ÌØË)¡»!°Ž$¾ˆ~1uÞeýdÇ‹fò¡6„yÀÌ‘èô=}XÚ¸êA×Êÿ‹¥>ËÅ©-µËöRIB#ò““DA$ûÌí)"‘f•NêA©©cÄ”®8_cO𺵭„3°¨.Ê9Ä#^Œ•Lõ»Xg†*R¶{Ü9`Ì8-]ƒdèäÃdêjíx[¤¥½‚Ì ´”¥f\ 3S×U‡³x¸Væ0ÍÇ)$£iyrUKvÙߨ XM ·6¼ár@ÞÖ 1ã(3ÊNÅH˜tŒ Q²ll.e#Æð·7nCÎ/=yµ,˜gÓyiMŽ(—Ÿ¡0é‹«˜¢{>5cD°ù˜}¬Žæå%ŸSî  C™ÄýëíOˆaá©PeE„MB3÷ŠìÆØuXJÓa”Êgó±Xî9Ù aåéœ]Ðu:<`û ½¹ÁùNiB‹™ [:ºwÓÎ< B§æ…BRpS̤ªžàqšìÒz”Î.£×ÛVb%vq¯"bV× ©²†ì€X › eA‚+5|Ã9¨R‡iS6é|„ˆkò(—(¹$YU›ªÍ Õ,V tL­>¬¡Yw鉸Ù Yt…k‰Û¶[ð /,(Ëä×Q¾½ã‹Ant%¹þž0® /ϰÿ"ŠNÿ¨%A’jbÞ”ÀM¢j"Ýre¦ƒÖÍçÈT˜5 n€ã™¤)©3…vµW;«þl¶(ÅOc;Ä·üvköG™¥Óã³z†L)FSÉM8ó©)Ði}ÕBéF\©Q°5Ô1ú1ÂìŸj30Â’ -ðmpMKê°Â§fʤC¾ çpÍ#0¶h°û,DfW*_­œåˆvè^‡T±:)kÊÐiâ‘ Ðႌ(ÚIךù‹ã­ò¼­}"œgÓÓŒÚêé!ÜΦ¥£ ˜ºià…¯U¥bÈVT4w$¦;¤°îšßŨÓVHxë¦9ŽÖ&/Ê•#õÝÑòßÙHþC)ú&yhjS~—¬n$[`Q·Ã2¶5!µÈ_\ÉF×sþ{ 4IŒÉ?‰HWÏ|Œ£82*¦øãâk}•ÎGéTêAm$Wé¹\5z-ís†™ËÀ¦„{ÌiyÄä[ïs%½"–꤇‚G.4ÖÙïT[ø®5ß^H»#ïëqDÛÿ(ò1“A¹ÂŸùuµíªeµú] ¥ôžLi7¨­]Ë©À=µbé9&ûŽ@ädfíϬÁäTî°‰ä®è¾9T5²gmàûìÔãYÓý–:ÎmaÙ…u_‡Ëë/®*'n™n•žîþpPçÖ=÷üº[^GÒé°›÷Þ~òüÅrFÛŠyw“¯’yŸìWÝ„éɧ&þC§#—ñÆA±ý±–ìµêk{Þ— ´…óÐŽt†ZÙàªSµî%ëüäH@¯]zo 8H®`Ìp²%‘§ê¸“Íÿ£²’Å!^è 62§w Éça’CõŠã$¡ÝzŠö˜•šMº2ØßÝßß{ñœ`€8]n„ Eô‡lÜÑŒâÁ¦£GRÆúéØÔŒtÊ2²®çÚ®Àóƒ‚áØªôô{ô~Ä ñUõÑÅ€”‚Õ"±Yв¡³ÿuiìÆRa©Ü4ò™8hpp2•÷úÖ>J¼½§œ{­_fž› Ã5¸c™€—HÆÂ_òW ù¿Mñ!¶‰Ð ’VFÁñh¦:…|,I ù ðŒÝªè$|È»/‘ºC×a¤µèǸ5ßX“Ÿ©x­â߀æÒvc¤o¸Ñ+ùǹÈÞ YK ð'Và-l|@ª5.'ÕÜðÃ:ŠÃP{žù×ñ¬ÅóÁ^Ëæ7õn™(Ó‰Û*ù³øƒ÷*E‹ÓzÀÏ ^¢]XSÔªWË=h¬ÎfúÔú̆ WŸ¦z°€Çn¡ž%¦Áªã'/¿\áßÐG® k‘²m‚b‚›1³´¸²è¹$·ººmËx׊Ê[3)ä‹qžNßÎ'± zê;º‹5 4G[h·ã¾Š‘°A„•7ÞÌPØža–¨ÞADm˜ ÞññÀŸ˜ÎŠ?GØX9v§<(g†ù;R->jÌ­¸%¯°Ôöÿïÿóÿ}¸¿T ¸6"ߺo|çe¶®„`Z^'"†Á‚ŒÐ\Ý'AÈ¢yäÛ>{FTb:5Æœµ¦s&AV'É C–ÊXࣔŸUÌo|I‰¥é4wî½ãz‰ Ìb®iöó‚A< ëx*HZÜ3:/'¡¤¡bª_I*-ãfÝìpš¬ù‡ÓFwx–XñŠXYÝZØ7‹Îf/ë Lûp€ÄAñÈ–¸³¾œiƒˆcЇ\Ñ+ª8ÛðxÀ“ÉV4+¢ºx|?ya,'|2ŸæÔ éµzAÈøz2ÍNŒ^Úißü;XËï¶ÖÖn"XwÏ}ok†9›Áá¡@PnxMìd€ÀÙ”ÏÔynÎù9×Îj’*ÚZeè¹VënR•|w½Äòa'm¶RÁp=4JðÚ¹„NÌÀ½Œ~`Ðw·q¢¨Ã¶ER"œòÊ"ï?¡ï4?ù‘KFÁ†·½l:% >ñPí“\ÍæW(¸Jµ_‰‡N¡òÓ ßÀ¡ â".;F¦ï 5 +y¿Nqÿƒº­à³3ð¹»þ9Ó;·Cæ§=á:Ì€êa5wª†ãà ”ü‘½{x& O f‹)˜ˆ;F¢[s³8òØ™tàAðy Ûóµž.4oÁ†jk3Äc—ª{IòB¼R*pü“i ÷8:}N~Dœ^M>ñ@;)¥Y¡Ëxã‚Ø-‘£&ƼòþîX¢W9*¥ëΡÙûæ°ZÔy7 ¡/üBv†’Yä[Æwî×-×m~Ô© ?д-°«y ËËó–ˆ5:Фb™‚J\D¡æ”Bæˆí»!9Áå¶rBuí+ö$Í€‹‰=õ]ËtÈ›?'»&Í&ÉËÂ\AaËÒº…uÔà×µ·’Ÿ³Ñ1Ækpúu+—ˆAœ9 ~ÔClŒTÉ7h,¬zY•¯ª5õ˜¹EĄ́6'ÊTñRü­ å<ìŠÊ‡?æ Á/±Ï¼’¢råø‰WJ¡])~ò ÝYve÷ú m‹.ažÚ+=Á!U¾ “ò„?Œ6¢Lâ0Ê~j `;‚ta¸Žù­&K‡ûaEm_…ä6›F[kB$Y{ÁÓÖÔ ð¹H/KÙ¥NôɈ§âÆ„÷p³`5‹áÍG ÀH2ÿ•U%¢üikh‚5ôÛÜX»6ïø4ÿ-’H¦¸’ÖÙÃB¶¿+Ü\Ã].”€\ó‘ÇÒlš‹ÂËtŒB¦NÌøÌ^h0ÇýÖ±¬Ãº©ô ñ¤*«èÉB[Æf$…¢è»ê~ÎÄ1­F| ½—òMlЋÀüL‘ÈÕó+ä㜚o‘`¯€ú9rÚ…(&Þk,²R:ŒïHq¿Eë>õ’Ú7wZBtþ?ŒðG~.tNö€¡ å7åqv~­.¡3ÔÔ1ßa>Yò.¦ ¶ƒ>ÃÔÙ•³Òâ“n çWÚƒ¼¿Þ‚/‡YÓ2'ïŸótœrÂSÕ7¨Ž§éK‰¤?"ô?—ÛQ Ÿ¢ ¦1i5R!ìl3  V™ 'Ç}=¸F¸ÑÒ%ôÖ:F×$ò’–›†­M(]`Õ‡ÃÁ?JÉãaˆd!¶5M‚9=úÿÀ„MüZà üÊ|{¡—W$L`(+zà%\“å—·[^ÎÂQq±Ï/ä‹§Å…W„®“a©gtÉÔÏòÓ³°ØOæ™WÈlçý3°£s=¼€ z/Îíé. Ò{²Ó™ ñ| –ù{€°›‘=ÊLmìwÌ~EÉxŽ˜>=?šŽ[Ì';ŸÀêRèÆE6E_³²X›×o Šò™¹\ý8ƒ—ÜWWZçji?£¿ø;ùÊec–²ƒé¥¿ fÙŸRû63Y;®Ö]SÍsyP ÏG¥ôK7=Ájâü¯J#ºì”¯µBfù…ØÉ ×yÑœhïµÂ¬iŽjk›û-Ƚɥ~0œs>µ}y^Ä E÷#ºù‹á)›$U ¥óCµìp _¿|²s°k#Ï÷wë>³¢·T|o}ª,9Ä4eÄOÎO|âÀ‘$…•ˆs>»×Xu#Y”<"á,$á9r`Îâh¹ž&ìƒ{>¤3“Ùñóoµöžïï¾:Höž¼HþE}ø˜tÎÓò­¹nšmÑãiî&Ýyúzw?Á…˜ÂÕü÷Ö“ææâ܆ 4!×Nn:?yµ#oå5½æ4jä÷1Àœ@§Vã.Òâ¬TLϽ{š Ì?Ÿ*[„9Ögéhä¾³¬c0#ª÷ VWxqvÉhÔmŒÓÉÉ¢?A©z“ºdXöν(v>j $=Á#áøu‰SÉYõ5ñô”ÐT<kSSòqZûRD „úèÁ»ljÕnfiÑÁÒ°JçS–õÁÛ(çï¼ /ëÑ}=³ªšÁŠê ʬÍEl&ð áô@œFg›ÝñWö´ÿ°à( ‰7,ûd8ظ7,B­ÒQñH`Þ3—dºðM €‹ ÊL§”ÔX3Dh¨¬é,…õfçìøêâS´Ø ¬E¼±™†Ťá¥ì…ÚøûÚ鉡Q„sh(§t>v Ⱦ PaÀ1LSÈð¤€ß„¨È·u¶UÔ >M«-¶ÏÖk>bY¦PHŒ0ÌKsà_Úˆm9m¯—žSp„KZBêÃ1€µY‡Â ñÚÖù#6jÐL\º‚%tŽžc° šƒs*¦D.Ž1³ãp>ø9ÆMs=/¬¥¥µ‹Õ™O-ŠX÷Zàw­µï®è†òÊãÂø6±|Ï9bYruv(Yg7žeºš”4Ï•lž½d@0è˜Ñe­e½ëF׺4X”uœ•Ãl3ç D4C]’îþ@Öñ¼œçOqÁVEò¼²Ž}¾®Âú‹ã׈mÒp! w„@SŠ…»Ð1Ðì“ñņ€'œbŸ0Ò|4²Q¼`Ió0§ÖÁ°^0pÆ‘xï9¨².Ym™á­AœŸnß‚‡×ø/—„,–Ƀ83**Šðy‰Ê7Žÿ„¥|¶;WߌK/D>±ÍàçT£Þ;¼â¹IÏ _ë¤ýÝP$³>s¬ŠŸl0ø]·ìñ30ÙÕ­×cÉgá¼pŽQµ)z€±!¾ß].6ÚgÊû.ª1ê6h•:5`€WR‘»ÊâÉŽ‹¾E ,Æ–ʸ—œ<0¢ÍÀâ˜rêZ!â„SóÂëi1+”s´+fõ¸hAx=„$ÓÝŒPq#ó»û1¨š9çHDÔá€rlã{ W2uÅÄÝj]ïa:ü NN¹HŠßEZú,+.Âëã˜Ü ]˜“>¤ÅÓþK¢¶ó’L‚u½RŠ/?<[C¤¢öû¨x/vóN[‘ŸÓ¡G^‚'ÈÕ¤~29,ôW¼íU ¹b¢’Õ\ês'Ñ B,’Ý"mór޾²q䬾£§]¸íàÇ݃Ãö?­í†fÙ©¹HŸŸ_º$ôÀáÌY=º\uîíè÷”ÍÞˆp¡zä‹F’Ÿ‚~ƒø8…Ëa!!-Sw[”„¸ôÄ\Ró_sÔ M±‡¥xƳœÅh}øEéöö£ÅÊ%Ñ"¬ë$-ŒSßi%ÓPW’º8A$P‚jÊÃ(K?űù]¢ÄŽW¥/Så£úÏúÝÅ“áiDýÝ®ƒ8¯þ§ãø7´ ÷yž²¯+‚–ðUŒ]à‹ª|0+÷˜XOªÂ´¨€çevÊvÈÌ–G®1áÐ,GóRom!B÷ö•8nº]à(ñë³#çøgTý‚ÍQw²ŠÌ\xÕ}$A_paÃÿWú.Ýg—7ÉBz^~GråJu}}š°ÓXû†©õG: ÿ’F‰{Ö“U"ÿ(w) „-faqŒ¹Mº}<é:rÌvd]ùCÓüš…î«ÐÁ|EÚn[lç—ÓÇFÙ¿ôÙ½]ûü )Ü“ÛëŒÈ€­|!„Ù,.`µ"jxAÄøiü¹* ÔÚ¬Hõ€0Ú¶­åoíc»»cýàn¶8éb'TI)  æ2ê?Il÷KÄL÷¼³å+ó+üa"1^˜©…˜è§@ˆ,‡øƒ÷’úþéØ\¿SÄÙÌÙ¼Ìß9à*øãΜ„^6þ°Ç.Wbn¹”E`Kê…ûÓ?•âO÷|€Tä“üƒ•g“Qr6ù„6ÖÍϽ;wðßõ;þ¿ëë÷ÿ´±~ïî½õÍû÷7Öÿ´¾¹±~÷öŸ’õÏ6ʆŸ¹ÙæÓ$ùÓÅÅÅ*Pb]¹EïÿC~gÖN¥•½!.„ ß{—lô7“Íõõûkë߬­ßOÖ¿ÙºýíÖí{æªu”&»ï'ÉŠå†Fw³X=ðö‰C‡ä9¾O Y'ñÆlîôüµ…Žfœ=ó%TIJ vlÇF_ÚÔÄ͵š¬pu[ÉÞ9ˆõhu‘ ‰°gˆP.E`í'?sÌ#dç€%óRt I†.uèlçáqÂcÛ€óÄ›H˜Ïªå›[.ÆÛê.8\?yY¨oŽR†‘'Ó“¬Ÿ|ŸQú†YA½Ò^@]ÓeàúвVjÈË ±)¦?7Aî 4;|“ÿnû†Æà—-DrÌIÓG™Ó |€!ÿ°Øÿ´ŸZþß?.ËÏÔÆþ¿¹qùÿí{wÖ×oošç÷î­¯ÿÁÿ‹Ÿµ¯ç‡%GnŸ¹ý½µÍdýÎÖío¶îlÖcx±aÃÈðOÜøÂöñí_(uŽg«tØJŽŠÑ°°¼b˜ðÍ„ð£VGÙ‰ùh£7;˜>=xÍ™ïIO¸J0Û}þ‹<ƒwð¾ÁšÏÓéi>^Rw6üzMgGEjžC»Ë6˜ôA¯šó⼡mWHwcVL¶’õÕúÁÓ ",ˆ–`1Âò ÷¯–³KîÛV26«ùÀM;vIúÈ\äÃÙ™™°õõ[aåGóÙ –ñ_õógL º.¨'®K0óª)›?ƒHæèî+kGneþ?4ó ´£èÉL£¹¨o%Ø>ÝÜ’ÙN˜HüL¼ Už—ôœÏl~µ=ëË9^Y&7u†¾hymá¾H3j¶*ƒVsUP5Þ¬Ø ÏncUGÅth¦I¸1yŸ” |q||ìõ`8R-¬Ó ::œUŠ­÷7©Xͦvß«MH¿7›ûã§æ§þüôó´±àü_¿sýOæxwãöí{÷7áü¿çîçÿoñó@ÿ°âxþß±çÿú7ÉúÝ­»ë[wï'CDm¦ë;hCŒá Í‹%Ï0¼¸¬ñŠ·î$IyYšc±c’¿¥húÇpeYµåï̵‰êüëî+@Õ¼q\ êÚ½þû7${ @ÛpzbÙ.ùKB5£?+énM93®oW×7W7ïªê[÷úë­†!Œ„y@µ´n€šÐÐÇ98P´66oß½ûí½ÍoZ7þahõûÏ^ˆøä6÷ÿÆÆõMØÿëw×Íæ¿» ûÿþ=s%øcÿÿ?Uý[xäßô7û°q¾õÏÆídóöÖÝo·6îÀ^;?é(”,ìhCµ6¼";Ò‡áƒhÔ^‘F¬@=œ¸ÈŠÁËûä8ŽaêoÐë*Â4Ç^ÂÆÎyä6rè‹ \Mà‹µuõP|YÍ$ui°4Ζêð£ìðlöP|{ˆ ’0ÔGênîxM‚Íö"÷§Eõ²×-T>ë×}g!RÅãz¡áª“¾g ãMâ%jÌô2®2j4MÎ0ª˜DÂI‚¸GÉ— Q£øäå€Só3¤yy¿åáì7‚]¯ä¯¨Œtüº"® ‚rDpßÝbÿ¬¸ c2)= ÿ·kË‚Ú×ŶJwÚ/Ð!iËpê³éÒ_˜MN-W)É9ÌÛù‰KÛΆjÁõ‡Õfš•°‰Î¬ð@°a Š‚Õ •`@ ¡¦¿œäú·Ÿ@¸4Î{ËÈ%¦³Kr ?—Là´¨ÑéçšGUx\Ißx`Ñ/õGVõ½‰†tÃ': R‹?wf<‹ä Å깎ºðMiBI˜"¯Ê¿J"  +$@s4)&‹ÓzÄ„{GY¸)í…aaŠÏy§®§„ÎÓõS­ùÜýSRÀûBóëÈV3ö" Ù“Ûk=ÊýR ’´WÐÏè"L –ù…Äݳ,b9Å_=°ÞpÍ·L¼d¤)poCáWæðÓº÷%×N𙟃„²OÖVô,`0˜Ûjeº®¯‚݆à3 õ=|6²;U+´Ï¥w/ä.Y¢Ã4ÏdùOðnïï>Ý}|<ÙÛ?Ø{n~ÁôE½„æþ¥ÁÂoÜSø•ÁE~xõâ™…P™'*Õ>£¬`æÍ“-qb¤ù|‘q(JÒo ð –¸ H,º˜J·‚Ý77Ízˆ˜y˜&`n-}üâõóƒŽ?Üîï9>ávj‡áõ’»ë=H=§GÒs•`z‰k'¡Ä²ôë^þˆ)%R½õjþžjðrOj`6]%×ÔÖ¶­·œŸ¸O(™„.—J”Fž‹sú±¡P„Œ‚»Cˆ¦,3ÂÏfËÌ¢ o(tØ¥GÙHeß æ/PÀÔJ¹Z‚Äi•ç+îm„S„Øi‡2·êÅ'ÚêˆQ¹ÆTÔ‚¯ßQ/„×Z<$jZçëé|a‹ÓŠ—T°àg Lì(¤‚áÑà$3"߀P£:¼;œ°/zñ~:ÊŠ'‘fªÅ"×LÐht¡NåUénva¥‘Zyöà Q4Vc åšËå ]I˜$­S,KØ“Z¥⢞ܤÛuŠN»ê€öVÍQN+úÕU¶ºmúöF+ØûW}éÏ*ÃÉ“z¸Þ¸XàŽ^Ð0H]µ_÷9ž»p[YŽÈEÀ4æ)§ýPn~«Û| n8ã¸eéÖá³ïÁ†“ô´P±®ðhÙÞQ]Ý._¤1º£ôUqÑ¥&ÅëˆÛ"Ô@Ëö)•†¨xŠW cÄ+‰ ËjTRGÀ@ñ$­ ¹c¢" …m·ùͨa.‘ˆ/LÒïÇÝu¸†n½¢QÁ9Aeð0Û[Õyú~ä2Îl|³þG~T +¨0ñC(6êïáëÏ0ä#¯žiqA¢äÆ]¥2 †EUû û«¨âqýj[jãso©2"Ƞи¬´\·×ê.¾ Qº‹ý½7^cŸ®±ÿ>u:~¯ÝXß™«mÊ *ݧoÈô"¥ ÁqúýÕöææo¶7µ°O®¶3ki±ºQ:¬¤ü·dm®±¯;¿×6Œw¤º¿iØ~Úkï¿jêZjâÛM¿iÜKu{H  Á‰c$b{ë¿ÎîæI†ÿîwÚ5¸Î.X~¨¿1áÇZ8›õäîr'_›Òƒ”˹äàþHðÈ(é’TgFZíb‡ŽŽqx,ò|h¥ e(ÂK#ì!0FÖ§ËWÛ EJêZrA_âXê^ëvæ–LSb˜ {G¬l¬lÀ«¤Ér`¶¶•~½Ö%E®ëªèO?uä¿éíÆuî¡KŽô7æ7ñö¯&âŠïÍ'ó®è߉Ùà6!M·³µV Éǯ±ÛítEè€ßýª;ÝuýÚû<èfððê·ù2Cþ]·x؉klðeÆøûln¯õêÖ¾]¿³%íé'ïl®è?agsW¯³³ítEH€ßýª;ÛuýÚ;;èæÂ½Ì×vâ;{™1þ>;Ûk½qg‹¹ Æ)€iK¡{ø Á¹®Ž µèúy—k2 Œ7˜”óÉ![¯Dõª=eɉúm<ÉK„Mfß Qva€7$‹€ 1q—`SfT¸Gî°gÑz 6>)M!4hÞ›ëÀJÖ¥˜âO¨Ï.É$=5w×Ù™™M@B`C>j¨ß#ȹT,>™T ?Úþu¼–zɃöúµUAmÝ××½ØÞ9Ú’6e®£Yè¼ùzëÒaPðšäøÒ_ù&b {~}Òk €€Q1Ä··Jý_2ÂìTþøHQmrýl j3–„ìò²-¶p³!þkßÛ’z{BGÎh³!ñ䤗œ†|:ݰ¶pëçÆ¡aɨH‡É»•×RÜØÉÏ7£ð„u^oB]ŸÌ|Þ^ÿÜ“i»WË·ß_w•ãµo2žGäu&PUàñƒê¤´š]#e;Ï'x’£3dŽ8{¹€µëtQ®Ý~²7k_Ñc²¥¤t¡‰úÀã²xÉ7žeã¹éزêÈûå †—S‡tø9æCØÏ (Ö௽X+SŒ«Ãœ4(ŒPŒÉ`ˆ]û˜LuܱûÇdQÇø„ ã¿ê'Ï(Øoj3›IÙå¾¼xõd÷Uòýß §·÷HkUœO`Ãbœ!n«­6”'MŽ‹óóTÈ53R+¤2:Ü{éôøÌ¦T”Ѓ\GÇ阪IG€²AűlkÊöZ@Ýçé[†Ø7ß ÑÉs˜u¦Ï=,k_щt~d(œ$á“#’Ñ$Y ž¬› ÂU¡Ü@µr¸â‚$%|rugß{  }¼þær´ qþÒªÙøÊ•¸èÑ„ ËèÖ.Oe´hg2åg7®8{¼X*Fõ õ¿1ð†Nõ8T@TRà0F=A¨8ÄÀjl5"Ò7Eñœ½þ‹Ù4s&‚0`÷ZIÆöaEU´ë¢lëá…±²fÙÃF ÕŸz_é“®í!,É×AK).¯x$EU2Æ#ä˜ áç“ ,e^@(å¢3gÔõÀUgÑE^z#F*&<Ôþ ³1$(Ãzñš-Sn2ž˜É8Øå©Ð'<‹Z°ÑÄ“ÝÆ†½\ì§ž'©zQüg|nÕÈZ{Ï÷w_${Ï^ø#ë´ƒ,ù¯;O_ïî'[C@]4tÙÒíab£b˜u€¤Y1x›]–Ëô*Xµª>^—ò6zÉ£ÍoC‡ô)s—…±gæ‹ ý9@BÂàpO¸>À,MðU\®Žƒ@¡´ ×_>Ž Ñ$ÑSHpÄ?ü9›ÞÀw£á4w"G^%Ï'lœ’Ï@ Ã{ Ä™úº‹ÀOmL69Mƒ¬ ¦ÇU¸.@t£TÀajy :èí¦*d©›þÌ™)¬>WÀøc꘢€ÕÔy”CÕ$±^§#–™ôd‡jj9>ýáGå$¥[¥ÚzþùÑM¾N6B×ÍÁ²ƒó‡¦ Ädœ:bÒGrWÎo_äˆJõ$ïVä”+¯Zat”:&שZ¹i¿mŽx³ž3&»e#ê­Åi¹x ˜‘ER÷À…^ª©^nËúÄÌrl~«ÒˆÞˆª?KMn¤¶ši òQ:xkÆA 1̈‰]èѼÙ=*»*”bbˆ×º‹X¤Ôº^í ¿¼Â'¢•‹,Ö‰Œ³ ,Ú ¡×ÌìQDH§§;Ï# *ô(yòêõ˧ƒç/žÿíÙ‹×ûƒW{O’’ðý냟vŸì=Þ9Ø}ex9Ý"áy AwLfŒ’£³$|RE$½fa1&å!!O5AÀ†ÙŠ.ñ•\ùEûWcâ$¡¥w[¬b6@g‰ ò½|ª:Ø{wtƒ‘Xlê—À.ô“Ý÷)Do%-södèlä©Ì|1ÍÓ‘¹G¦Ó!<"\PîÌÌ|·¬MpqÉ+îPþÒ$¸¾êI1â[¤Ê8”š_k36/^3`¼ñ>3Dÿ'4@·ƒj±,ã×¥3G›‹hàsÏèüê§ï i@å–®p/ã-ž:­yx©k§ÏPk/ž_…¨¡¥ñø`êåwð©ËÏooX]?sjy`–_u#<гûÀÕ&ÙyþyÖM`Z­:À]îuíkÜ“]O$ !w?…U\&·ð¿âüOî7ý䥹²”p÷)Š®­8`¿Ò`¬wwã„Çn^¼u–[G¢Ÿy ÍúÞ¼L©¾Ë+æÉ9€/¼Ã%ÉÀæÒ=ZJ¥å—ëìÇæmæ–ôõË'FðEÜß=ð¶‘øâ>¢ ­×àäXü.#W¦zו¨Ú;W*£ö5AurÎc¹ŽjiqµàS9$’‡ª+‚€÷ÒVS7"@™Ë÷ãJkåüƒ¯³VUT£Ø¢…êFZ´YV“Õ¸¯F{˜—Mf9hr’Ëݨáîƒ(,ØÂP˜˜Jµ D’^ãõN®" 21èºY’#]üúÖð¹Ô_ù³³¢äTGW¸ 9ˆNæ¢PæÂ|ÒYÁ̳Ñ’“ß(sõ ^ƒ:l§,l¯«gP>ÄjÕ öðü¦¶ çw“²Fõ¨¶ž%øùˆp„k';ÅYo:+)îòuìµf£rëKALù‰ÿ§—x Õ/l$Õx»r\~RÓ§2+tLU§å‡¤B½sjU³…ýÓ§ªíÎ ¼ õ1 #’ÆÓê­îÆæÝ×V\ÚqùzÎÂ;4'X¸Á‡ 9Ô iMlþ£d+±JU'âö†mv4*.ÍlÝ]ìÆ—ž"ôišÉÉÇWÜ÷J•´™á¬rtOÒFæÂBF£'ÏîÔkLÝ+PV/š81éÁzlBO#wgK\™cSéUƒeI×ós{Ÿ/ï\)—à¨ÞEóÈ:÷¬ö-ÖØš– §ÁÈèËdây"@c|ždcP°÷}üÛ\®¡„<Ø(dj®Ü§i>^xÍvrGöä+{-xa:À4Ë ªdjáG™{u¶Û5¡»¦D¡Mß©Ëᬻ‚ù„`¯.G˜"@ù²¡þ d9±‡?'uî>ÛÙ{ZCšvLW%MuÕõkúÒÌ"“þ a‚î&JæW%Lá«Û—ªúu8æ·T·÷òW¡Ð{w¢ƒ¹*M:=JPÓ'ÐäYt¾ÿ ÊHGë›c³Iòð²oÒQ¥Ól² –C¬<Ð_ekõ Ô,ëÙc¬y‰~ü–—7fH«‹œ˜®Ò•ÏÙ0I$ñÝæyÆ"ŸgžƒcêþU?ÛV'ñ«Ív]‡>gg*sŽ|¥yαÈç™sË€oÁo ³mU=¿ÚlW»ò9»¡æ™õ)[á›õÚ_2©úß«d.vH• (÷CÄ þgAL˜¯\æ/€eÖhõœ„hõ²¸VïLiõBÕuÇÒ'ꮯ ã]xlcÚfò(‘éG5J–8ݨQ§ÄRüür‘°XÿŒÊÔ€²èüöN&Ýó–†t”«Ûð¸¿âgN±·º ÓÕíÆúUÕÔô#3)gD«Á®6¤#·Ô‘¯ÈP[ûúq:>ÎDˆŽØ“–¦â…BAµžxâìÀi¦®¨Ê l¨WSäüJG‘ðƒÄooßðà¥çµ©ƒc^âZëî}%Ï"ß°ZÛ+~ÎÏ"Åu.àÀó{SyVgZWá,­~MR^ªý×å‘à¸ë3.Ù3_6b“]¦%(<é9w'åhLɾC‡hÙé… †¾bѾÔ˦X¡^Ì¥¸Žûô ðOþf(¼!ò½ ¾³jP¥’„ÑÕŽ5$—öÃì|›ì@7…Ì-Ói6Û@ûk«#,®Á7eÝu}a®Õèy `A ¶ 㢄œ^;zER«–µµäWKT¼Ùñ8yzÌP¹áÑ}/²=ËÞéÈYä=8|g›YE6Ûð;çoùå—It lNÝÞÕ U!HÕÝŠÔ~‡]’B ùh./銗)ëò/SÚæ×]¦°Ÿ0w™/‚Ì·Ë|â' õ¾B5<ƒff5S©SIÈÔ¯ríûÖ¢¨®¿ Ä…7Ð8Á¬ ¢rYÇ›"Bì‡ÑÄCHâ’^%ºoœ]¬ê‡ëqD¢cúîÍÜëZò…Ý:F°>ÈÝcüØ{„úÅþÁ¨^ѹh£W_ Ø¿E=‘Ä‚Tzõ¡)ÝzæÀÕ®§ì÷^õS'>žõ•{‘-~>Ùx£¦I—¦½©º7ªu40§È‚ÇÙëO£ë¿ˆÕ‡v‹¶åÛ#&;PTòu7 }­ñl/DB“ˇ> }ÕÚnÇýI¤Ârà©Ò‚:·¸’^‡ '‡„šbzí *ë&g>¤=ŒZ^EèdžÜÊ€~Øf‰ó*‡¸û$rŽë¹å àÆƒ7¥>¢P¸…òz…kcÞ?ÚÑæ"Mc Ú©˜¹X’™m;;<ÍÎ?ÈÏOMa ¥?‡Ci2åi\8E´D‘ZŽ2í´X_ ŸD‡Ûí•ÙNãHòÒ Cuþ¨Å_-ì½sÓ»bïÙé*½_Ž*Û΃„˜ô4› ŸG«r€£ùlfXp«–æ¸@›©-¶Ñ‰®ÍGÜÇêÿÓ?ÿWý)Ý[£°ÿ’„ D‰¬¶t4ú m¬›Ÿ{wîà¿ëw6ü×7×77ïÿiccãöú½û÷nß¾÷§õûwî¯ÿ)Yÿ m/ü™›QN“äO« ›Ô•[ôþ?ôçáw“³Éµµdeo¸•è…ï½K6úwû›ýds}ýÛµõµõ{ÉÆÝ­;÷¶n“œGi²û~’¬X©`Âx岎å$9+Š·ƒòØîiÜíRÞÑ1Oᯄ¿nÅKvÐ^KN×î©“Ø—•ü%”§5Ÿã¨\®DwÿâÏ>2Ähô ,þ×sÓ¢|®ACÍÝìÍqv‘Œ0àb4„_OòiyÃä•gÅèS®u¿Æè§Ù»¼˜—£ËÆQ¢“ÿ{o¿ÝÆqì‹æo>Å‘ ÀÁ‰rBJ²i‰Žu"K:ャ!0$'0Ž£µîº/r_ëþ_äv}uW÷ô @êÃÎ9æJ,r¦§?ª«««««~%”‚œUÙ<›³ò\°ÆÅô¼NYÁ¡g(?GV©dÁNÆV©Íø[í`¬÷âJõÙm íã|bÖK:A§xʨÌs™š3-õ*Æ,l³ýµû;ãu‘,r{C=Ë(­ØŠcÝFÛÿ,7~ï—Äà•`¢ŒýÛµF Ê–MWŸ±=’w¶»ñÓß$û¯búa+µÖ¢S•¾ñõ(½ˆÑ|œNÏ—éù‡Z>µ0”nƆ Yæ~kÒðdDåtRÌÿ”t N×ÔçØpòi¾J!ùìdûÈ :³w&ÐW²•DÐ(FcF@¨Sü£>»åæ0¡“™ù`D­ƒú4b–Êå:šgcØ ôÜõ“ÃéìS G2+J(3Zâ•Ê‚ãšK²FÄ™€?yÎä¢ ociòµ×  `§Û‡tÉÐCÄñÃó(g23Dž›E@5K ò8“eɼNg3ȆÙÌ’³%f9{kÃ|eù/ÄkÏæUÃLíØö½—£›º}T{4jë|ìÍ‚šcm[»†¯0,›Ìv^e4ø)•ìMk¦rMëÒµ/N>¹Ð3&¨«»Sÿ{˜”ýa8Û2Œ¸¯i¦„‰ê%ΰԸ(bFKÕŠï„Ĭ~†¿¶[Äÿ1?¡ÿÏbžNË1îN[« ðòùfo¯ÆÿÀÿgoçÎ{ßìþa{çÞÝovþì}¬4ýüîÿÓ4ÿê÷>& êçÓá ÚhöÿÚ¾»»ó¿ýÍöÝíÝÝí;0ÿ½·}ïwÿ¯ÏñãûEgÁvÅìO[ÛÞº³ìlïïmïß½sûíÂ/?£Õ ÒŒKølÉÙ2Ý–˜ßÐAL*±±tøý¦òœ‚åµÔŸ:ÀÒY:O'Ém('É30~’ú¸ž©ïP~ á€ü\A‚ß›S—˜ò2fºi¯:Sî%çóô”´có'g /#ÐÕsÀ/Ô ›LØ#@}Õe¼®D÷L·~É×zZx´-6<4O1þö–FU>Í€ž†¼Ø÷l²LvïzmÏ%|KÉù¶|"¥ Vª†=•Cu—àé{ˆ~wáŠA\P×÷ñ–)#(ytË3çÖK)š¸‚j·(-Š‹ø¬R5òUX~ òõ¤>z¨ÙàlöÞe‹}k±'ãNßÕò Œð«3£ âp(K—¡åe apÂÊRËí»ÌX‘Éð µzX8û.}bDa(U¥bßð²ªëˆbŠ«Ete@]ì ‡É·—×Ñ:á‡~¾4Œ}­cº€_ZØr¼YŒ—jUðEn[dÍÈg:zûÅòÔðÙ×(‚û™QÐgîáAPa?Z£<É r#ÙLîC”“ ûHço0ÐcŠåbDÇCô釂º¡ ,`ÂßÖ’+Êó¦‘ûåb^LÏ~ç½3­Ñã¤C¤«°1¼’¨àû7äÒP äY‘”Kpn©®H`yë’‡cËãaÙãlæE3ŒéVÚ®ç+úøj ^uÕ)Œ½C¶2/€© eó̬×aÖià4´)5SྠwC2t©8©ú¥îAd鵪`8ŽY™ÿ,;üDV•?o†zL»žTè²V¶’%ºÊdQ!¯ ˆ?F½˜Íð ‚s°?*+]ˆduHÿ¯­'ýïú³®þŸOÏŠ›¶±BÿßÞÛûÆ?ÿíî|³sçwýÿsüT˜jÔùQßÿfkûÞÖÎ^²ó§ý»Ûû;wµ¾Ï{ȣ互 e†2%Öž\b3b:Í”à"›ï(?ÃÛiwaô Q6ß»é0ÏX@æ(‘mÌÌYMÓú<3»(I«t¼!¶ÜÉߎ^¾zòüÙÆJ̸(›‚Žâ©‡r¢¦¤Rê9WU–Å0G·‰Õ#½Ì^‚Ò½©& 8ó }bðål?cÐE¼p\¸ã?ž-¨K I$¿¨Ö7ùYnŽ’Ð :’¡õ€;B©9ñ¨9ʆ9Gáä‚°hiä£fG𠔤KÀ{ÁW†ÎŸÉt…¸pŸ>5b¾ 'š6F5êôñËÃg¯ž›=ppôìðû§Gr½ &”æˆM8tUâ5õ! Üž¥‹ @/›ŸhÀðÂGý%äøìú`%8žàaæ`ÃbrCÛÒ›ªÉ/Åü L!®5˜Âûir1Ïδ¾#å¢õþå¦îo¥æLôŸ°@1`«Å»f£ ¼5«ÁŸ"±wb”*„ÌÏ̹±‹Ë©i€†‰ÞdWöØ+&iŽHÚ°d:‚µsm}}RÇ‘àñk9wÔDlñ+€¢ãÂì¡5*x2’/ Žu›ÒEØ¿7…Dž¬Ýo77¶?d\ €BÄ€š¢l¢ì&\%á[¨(vHgf"fs¹*À!áëf[Ån´¾Pñ*C* ìÏÀš¬<( mˆ d ìð?¢@"œÎ ÈH¤3²µ„<<šÉÂ!ØW­‡Om©ÕÝ·Ÿ…7B8­Ü²Oë÷þq¶€QOEV¹^ò|m" ´z««¼ÀT¤™·|2ô‘4ëö¸ÂÄ$ ]èª{dE! ýL–~€ˆÎ3…ÔB52Ü“ŒŠËiql°üñså†ë~ÔO:Í•šå Ö*T`6|(²è̲DO•u“ï3¯5, yv4w{Bz@;HX’“HËzʽ9§_nÑK5å‚Ò |qúQ8øÈt {S„¢I —¾½Œ@V+D ò@‚_Q©ìÉÕ þ‚Ä;Þšp-ié+=g¨3²õIÞæ©ÊqÀ;  ±bú6/óSŠ"5ÿ…+)”û¤™¥%'ªQ[×:r‘ï}L+²kz½¥­“ŽÂ<,óÛ²¤–1ñ.;… ÝÐÁ‹üÀÆe!w¥·£QÌŸÛ¡Ö'³dlõtåõ'X~ea•¯+ð¨9ž]FÔ  /̼)È–dék}‡õ‘އʨ'Mȸ ZŸÛÍ À6jôlqQpà<"Û‹‚ëŸm’CZL0šÀ3¦»ïi¶…iüÚ -µÓ”Ò•ÏiñÎÓ· H´QÖ~J^pS¤”iàŠ~òĨ³f„ 0¼'ép^E°Ÿj9u[¢š‘Ÿ‘»#ªn8€¢z¦¹k}n9ööC‘r ó·ŠaŠ´6  àÊdsôyØJC.¼4{¸Ãó*rP†,î›y„£b’x*aDAŒï®'‡­°´Ä@§k³ßÚ®‘‚ž±;6Ž›™\žÖk%œ'3lêÜŒ“'g0³g&–Å’¯ë"á´‚ŠG_>ÂÓá×£:µã%ౄäÂd¦[ønm=ö3A°*k,F¢^è[æœ5š£$F›£G«¢«šÞ–æê¼ »®<è‘w±XÌö·¶œÍqKš‹šáÚÕ…¸]î …×T_Øï³æ#VpwcÄTž ‘íõL‰‘"ÜáÑdÑOŽÒaå1Tý‚÷/X?^KOì€CîôJµ%÷-¥ãVŽ]Hk0/âož‘„&{Š!{7sie#q›>ë{tÝgˆz1“Gò‘oQS|ëútãlêt5gtódÙxF§¬dÖÞ$ð g'Ì0ø_Ç4¡‹¯J ul ‰›¨vïaõ:ÿï›t~¾„qi¿Ñq)e”¿^í30êŒ`ûß4Ökýp:zöóàéóG‡OLJ¯þʯ/³üü‚œjw­Ç² =êÕf?V7HØJþ€`@bC­Oœ?ô"m Ä™Ê@uîYÐÛ`ã¤UÕÁC¨GÒ}X9% 凱Rvš-M%c±lÈl–¢  ËÕ!›Õ̃öžbbh¥ï„`Ûº>¯d#ÄÀïè›t(êÝäñ=>¼% b~[Q†Û"|Íb]¹q1Q=2^ú7kSR¤ =P«Pt39ôÝøJ -@úà'À³ðB¥º9%ïzg8å˜Õ†Ž?iÕP öÍS#sXBJl_=T¯¿äì~FüCN,äõ€|QPÒàüRÆríPw­'6£Ì%ŸžMÛz7ð'J>vâ’D¿>‰D_“#Eíá^|*L/«+M»o@,Nr6/&¬=õ­+ãu»©÷½^EölVÌKD¨e2–4T©Ðž‚2’–N}l7Ó x”?øòç8íÇ ;û öéÿ,–xi€J4®"ŸÃ⃹7† è ÀÐIÃP D¥Hˆÿ!êÀ)žÎæ‹ɌݹºPç¼ù¤a$!çæIÏÎPc-ÏŸt<2!滹® ]=+© þHi¥ ÔìbÛÄu¶JÖò—xâxÍB׺N²· _HA¡{âÝk…|Æ<‡È_8 ˆ5g{÷(ø ¶1PêÉfݾ¨;ÕöjòKÐ~^ª¶Ï~+v6p‘2û`C‘¬W©‚xfZÁc:©jeíõÌHZ¿¥«;›òÍp1Y`•Ò ðž«Z\FËbâ™Å©,eæ¸o*¨×¦¹y6)Þft(õVt æv.±œ*^õÈèDrÛ&ìV^½×ó†F§_õVûö…î‘äyK»5ëâëõÙ¯ÐyÿØzÄYï½£U¸Ç)N—ýÉW†l>­MœÖÄØžÏneÁ„*>ªºÑL³úµÎ8{ì³ Š.}¬ýG¹JGÓŸ ‹ñ8!GÇßä=‡ÌÝ ræuxžÅëPzþ=çy*2¢'m”_̼¢ñ‹¯£ÅÕΪ×ÃIýl@j²ÚóWuzÐvZ¼óRÈÔhPôóÄöÞÀñÑvX ’ Øl§°OÒQ†6R{8f¬lÜ“,öI>m8û`«åm¯U?ŽóC¸õ+  °›1µLzèá> ›/X-(ÊL\I Xû¯È*%ÞÜxe_,¼|{j…ÇçPâ×^¬Û«rn®ÙΰÉ:ÖÛÕÜR¿ k˜ç8•( !3¡»™Ä©¬è“ùu˜.Ùè©M6`z"60ÜñóÔÆITw7ßO#=Oói|¾û–£©¿qǺǑ³=”`_Ÿi (j'M'pÒÏ™Ý%š 8ßF…tý‰ »r›”hÑåžýüô)xgi‰á8Àv"ê˜g'¢Ž_¢V¢FéïÀ zËõºMê0ø¸À…l$Ä%JN'àæ…ô í‘7j]ãI`fxú` ?bˆJXÍC•P¢!’ía5®hEl|ç§ò%òž´è ¬ècË·â+Z¹Ðë%àoÁAŒ~,üF÷ w2ï[áÄ6ãIŒæì¡¨ÎÕ6&QAäR1¦m]0Ÿ[òsö5¤âF A:ËÝRoDO(—A1·•+¡Ò/‘×0JÂ.&óËÌòdÛ^jÎ̆O.éìc>ÛËòÀËf¡²ßçExkMƒ™pœä1åØ ëœUÌ|׬Ù<3¢%óòVG0«t8Ê ‡«að—£ã`Óª¾vÚµ$ß›.'Ù<Æ¿÷VRõØæÇ´Å*p›·bäü—üë_É­¨É±ñ€Ëâë•ÒAŽË)+b6 sO˜!R]ÌFåWv&nô¥9÷åÓaæícp›º,V–å{ä×fÚµ1ZUØZ1ÿ.Ä0ÄçI;Ï}U—c-½N=Q‹âµNÜÊÜb~ð TØã5NIl®tÄ©ÑÑ+|U™£²âæ"ËÇö¯S„[Œ­ÑlŠJ=J6¾LK/Š…Ô²MÖZ U®²Jülu0aá舩ú!ÍE Š/ôH ÍÐéô*‰1$•ò}Y¨#xvZŒ®z ¤“@ð…®mTd|‘-¬Õ‘=JŠ„°yоqiGú¶0‡°ìÑîŒpÔ•)NFC,Ý|E…°Ð%3bN¾&×±ñÓvYµ¢¯±"€‰ýxjƸÏWÖ;S-ËE1ÑJb×92ùômñ&³ ï+"–c¶hÇiÈ’-Ò<7jÑ|á ókéü£oŒ;*6mˆ‰)f¯rñð<'AT|M;±…œŽ°ùG öÜ Ñ{1Ash·$ß5;åõIå9oýüâñáñQòßðéûäÕÑq•}g»SÂßœþ\^CœåCó·{+šŽ˜—>]t{õÌÆÁÚšÙX¢WFBg„ÊãªaÔ»#Œà/ð¤WÄ´*×ÿèr‰Í“;‘G)¸b¶Ÿê®Uccê™- }ÐÖ‰¾Xmv˜ –JÉá³Ç ›Ok‰gÔzâÌäÂBš÷Éâ<€…;°Le+çªüùK2R§|ý K>pC甎™ŽtzÕ•ó%3žLß|d;¾j8 Ä»g¯>ý… Ï¸ðÖL%ïØéh¿:zzôè8yôüçgǯºÉ/Ÿÿ$“LEÛ#¾©Ùh?;Þm%]ëÊ”#‰$ãìl¡bì÷•YŸ†>^çh–qý«]@ÛþúÙ^ÑÛðÊÄvûæMU[¢†=žœ¹X rM¥‘ÐÃG-¬ªÝwW“ÑKfùð §ÐW›Œ­lÔf¢6º¨zö¥¾’’k—oCFew¿@VIž¿||ô2ùþ?á_=êáwæ—•ª¢³~:¬¨ôçšû›ö:[Ú_ùÝ„\Áª›¹ û£‹VÜ´Bøxæâ̼*,NÝãÃ\"°æTM¡GâëFæ”ú6«Š[·°Ð?ã;: P=‡¨ v<¥[„'*“Áó™ÄmvĨ÷B5¢ƒ0Ï3¼Ž®ôÏ›æ=ß(ÇËjIö)Íl|ÖO¾w&Ö ˆ¨†P’彋…:ƒw}È´iš’TG/L¶ÏçáüH'ØïTpäùÖIikÄrªÚú»t>¬Á0"yA²Û™"”S­O}zõ­^PJoá±×!€uàꦕN«—üå<_dƒòŸc·Üû8mÓ>3Ë´o©£¥ÀT$cß-Í.+z¶UŠ2èˆeØ´x–-†âÊwªÖò"éØ]EŽÀˆ/ROu7‡¢¥ç›ynÞÔ·›Á¹ÔóŠñg_U–â÷E1ÎR¾‚m`§ÐÈFþhÊìm:ÏÁP<׉»ö Ћømܦ#>H•1'AI.¹‘‹°T lRÀ #DøÄ ߆bž±Òżˆ¬uëî݈ðš:@`Ûµêý‹I:^ç§ΦñFDc›ìJüm¼ÕÝd{…–#ËÛE›Þ¦¾y« ˆxää,r1‘4@Di^TåpwŒ >˜ƒÅð¢Óºõ¿J“íÍ?¿þºÛÙêý¯îí[­^"á°X0+»]wMâÙ&;ùtÑ•R';¯»«¼C>Ä-Âd ¿WB çÀ¿`¯€ðJúv¨'»¯Ô¦îÖ8Öº†¥>¼² ]#_ÖR©/ÎfÆ”ž‘r$HΖ!%$¶ž«jÿ’îx^•K£ðغœY™F¾e«Þ/™ÇÑ»%59ÕK%Ðõ½C°aröXéÊÕtBWF(°ÃVV\L~—þ¦;KϤ:-‚]´|ÛZø/ìW²økƒeüoøâ¿à¢ÿÈm\ÿ×<ßÙÛÞûæwüßÏñ”òüHm¬ÀÿÚ¹cÞíls÷Þ]Ã{Û€ÿ¼·û;þïgùÙúŠdÊ)ë;ýîlíš_wöÍÿîjà/D,é£*°œ:)Ø ¶å|wž›Ãb\Ì÷“?žÝ=» j@³ód— ~ÛPþ,Cxô7ÞDïèM¹hãgpQ¸Y.®Æ´Cÿ§xܘ¥#8Ìî'Ûð×$ŸçSþã2-.ö“íí/ÂÊO—‹( Põ™ÑÒûh);H yž¿„ñJe›ðÂÔØßË&þû¡9T˜þÏá6V¿y¿±õ%‚vS´`ð8ì!ÒÈzn'}øï&^lAiŽÚ§èM5¢?ï}~ jOšO³ùfNuuÑkUYº\amf‰LGéœf˜‡ ±žA9¨=5Jε{›.F3˜­DOõ\Èä†ušZr¢”AFGö»ÚÐôS/ÿ?ñÍÿi”ÿ»FîïâþoþýfowÏ”Ûùf÷Îïòÿ³üøøojâq#øóÝo÷}¡ßv·vî%;w÷ïüyÿîv#ô7Í3A‰ˆ`5•ËÓI¾P „05[BiÔÉ1žœF*Í‹óy:+¾!&f¦*ØJW½„ƒ R(Z_+J¡Rûm°ù±-iCO:‰Z®S”í0úu€~ÐîEÇ»R¤î5OÆlBúa,Ð4 O^™U}ÅHsU¤Ÿút¢Ý+ÁSO¡—eaP3~‚¡¸ÂÚ~eÈI§f•M2·@˜À0£ó¥úã¹áE¤ÐD±c¤eý8HÝzu«Œ§“Àµ}…lŽb–V¬±rè;[-~ä¯ZsrÁø@TÀÝvGi=Ä•hùÌ6ƒ˜¿Ãlgua5ëF+¨ ‚~ÜOª›Á„'s€:zcuóƒ—|ኰÑy„öGn#•*S”ª¤LÝFlß•€€Fh+³cú4Zkkæïn¾ùéQ¡p/}øÌMOLYŠ.ß®ƒü¡ò¾ÿQ;i¾N&`WÙ„ü’œßU!ë%m$è(mŠÂÊ1hó’]+cMÒ ۴þ>y‰[ÆÈå¶FÁE£·4Âv"=û†ËßõRœ5«pEhªuèePwe›­¤z©˱ÍEC^`ì(\LâÀ.–F^lBt=®CJ¼‚dz G…¯anÌ›Ì<go!œ–w>›y·à›¶"S<‡Foé1Z[q¦tÄtp×U+$¬"‹Ä)‡lúÅ–(N ÓŒ§0.†Îÿ(\¤ËnÉÐøi¶¸-AOÀ+Aßè²ÆÖØLeUêÊõ;œ\áÖÝJŠmLÜ…:L‡€¢ü¤>Á´½ðró!¬à!s¨Á;sø@öò‹q÷1’ÀðýÛ~íG[r§ùt7rÏv_[¨Žæqx)‹ [æ-’:xhŸf`«¯ÿ1ûO7brà7UÜ%ìnÛJÔ sÌ•¥ø×6…ì©”Ù„Jæ¨ôô†èšmC+Û~¦\â.#˜Öí B„y½±A”ð ©¾Ì ›9‘|Ýfÿ¥¡RžK[î†uz(ihCÄnZx´h«ÑÚŸ¨E|‰¾+Ÿ·Õѵ¸B+N­úàs!u?úd66ÇWz7Z†7kq\œ‹fÝVÍ'Í‹KlÑ2 Éh½RÞ çÅ4nb¥7te½¯==:>bïN³/ÃIкyçÎ4tŸœ¯}³¶×›¿¤¨Uú…gÛ3v¨b¿ÝJ.Uòÿ´~ƒß'ì¥Jþ¡_‘&ØM¨G=¿f„ÜBE QMÿ(ò)¹ÜßgŸ‡4òb„B(9²Üß·’&Äé¦T }+Ÿ ‹%à^Óq¦ 6€…ƶ‰aG­ˆªÒ8h;€ö{¦â6ʾçgµ e ]§±µÈO€ÔQÔÃiòãñOOI.—ùBÒ¢t‘»"^t¢™ ÷$Ц…LÃ0åʈð8á$Ÿ ûN¹<Å’ á!PC Y”O€#ðb÷znÄŒ\úžú4fÓ¥u‰jqW!ÕH+f1ØÅö_E¼,è8Ž~¡kÄ^âz‡ˆ¦°§ï\óOž½:zyœ;b%!3ª‡Öì2¿®Ìÿ"1ÔÈ2ÅÃP£‹tм”*‚Ò«ÁkãúÕ“L´$¨’Ʊì«,“”r(,ð.è¼BÅŠ|5Œ†兀Ç7ƒ”^øK…/\ ­eLR°&šýZEPom%³Ç^ñM$à8ôía„णÚ:!°¶²®^Bz™¥C¯j 1•‹y‰‘'Öm!é·þ>ÿûôþ­ÍMŒpÞÜ|·ú5@#á&žlû”¨D€ŠŒYB÷Ö$÷³­[E¬©AÝ@ž¤eéÐÙ >²+Ó­2·˜Ð=‡½0ŒâBý Æ2–“)¦ÆzÔGsÚ3×µ .–¦p:)È?„QÁfXÊ×ùTmwXÐH1#ÀD¼zpÎÔñÃà x,,­ÇÑ3:1MÎ’Ï;]f­DÐúH„NK#› hxqÁaìx¡‰xGd¸<—)¸q,óÅÒE£Ò Òi²œ2¶ž×È<ûÂïÛäŒ;tÉ„‹—.pK»d“N¹œa{ÕEÄ ÂŸEÝü€>ÞÕ Ì _G*éHÀšoå,“$±Î^¢€Ãûæ={€G$¼ô‘@Yó÷ýÅæy6Íæ°Eætú?Ì!ñ%ú…㯀˜{95 é‡r›ÍÂö¡é.‚ ^äæ,9e_ v{ÈÌtŽhœ©2ç¥Ý¦ŸL%Ç$#¹Lç˜âOþáO|ØH67ÅÕÓŸ2ä[:ɨ:@£€ú±¦Ï˜}4H|>8Kë?—É6oXœË…]›UUC.n qÁ&Ñ<ÙTr~Resbg•Í_ÈŽÿ¥Ù×û<³D7”j Â>$ƒ-îþ ±å¬Ü‚ë¯yIãʧ2.;Æ*=aíÁŠ v3 ‘haˆYž 0Œ…|ש¾‹ôÊ(š,L̬‹ïs15+;‡qa—ì÷HjóW…ÔßcàRªxðô‡£¡PÊ/ÿ(¶Àé>Øp1î à[ËO³ÔS²7GJmœÀÙÂbÝU«?Q¹/ÈŒ³\ØU9-ð~`U襊¢”`K[…@…d~ëZ:'[ÔÖ=V§súã®@=#µ‡Ì¢ö–ž~ "Gý…5GÕ%z¨\…’Xd(ý²µ£¬ÅºÏ'­¿O[VÙ%Ÿ.ìågù¼Ô" äfQ Àé9æ©Ó²Œ§ªŸ ½Ì©}Ëýú­ûõÿû¿þoÎ “´ÿßÿ‡Ÿ»i]Љãe uäÅ*‹.ȃ[ƒ{C@ŒtèŸÃÈñX„ýª¬;OÁÛz¶«{t Å c‹¸T²Öfn-lñxŒL3S¢jªµ y³d ÷Ð.о7>#óì1ЉUÜ]ݧ²úñ#È*~Ù|}‘†¾˜øû×Òùž+PÔ:¢:¦; €˜„Z/ZœÍ ”bÎ?À#(vÖö:lŬŸê ƒ:©:‚£½kÛHÙ§ôëdYâ.u7g,Š÷+/|%Ä”[WE²¿}k·Ò}«üÉ͇aàíd³B—@k©RÄbù÷$_üQ,¶>ÑGvâžë» ÎÀS;'xu´-%µûÌÚfZÉ|hoÓÀ‚Îàœ[Ì*‡SwÓQèYD?¥Äåäaë¯)ÄÄTQ›ÂÚ¸%·Ág~™qëÀk´†@3 ñ`ýT/×G1¶¶²Ý³—q4Ï\ Þv1²XÊçŒã-(´ôÒ?¬Ð·ÑyØAK‡>Uö4CmÕE‡ÑAµCG@G5?ŠÁuØë#l|Tý…ã%)­U„¤rË™´]RÖtŒ‚K[£S7JK3’Q§²#ºBðtÓ¹8¯¡ÉÌ>ú9‡¦rB§ƒ¬=Í£uEó)™«E;j;§tØpõ@“_ÉLDtñ„ÜÛ“÷€ÿB¾q@ô5¤ðd#î»#“ÿSmm]Óºz9àhkßO_#è1h(m¦ôF#€’g>>?¡õä]ºÜžÖe®© ŠF¨©€X¾¹ý©6g¨!Ÿàú›ÙÞ:ý9´¿ÚÌ2Ñ€ ÝÊAP8,[ß/ñÕÇÎÎÕËkÝš7Ò5-ÈëXK$ÀâÃe&õ 7v ¿¨W?Öðº0®¿é"˜P–&‚ý«¶H|K› †BP˜d¼‡ÚhÀ›r¹¡D3»RHQó®‹W€ì]Y«CÏkâX@X_KúÊ)qêsÌŠoô8ˆèóp{ùžo>¬ßìR1º­f¤¡bÝÊ’ñꬰÑZá^Šª@"«rD ¢œjh†ü=+$¼Þu %·ñ{ŸÁzü?U•äf3 TŒ¼q¢ëér‘¿¬Kp³¤[ˆÎ¼¦ »—s¬<ˆoËÃË)Ÿ¾Å˜ xqøÌP”=¨¶ANoÕ#ícÖ¹žúÒþ¢lƒûŸ×Ç®MŽ'Ò“zQPÎÓÙ>ã«öªmLìÖTà¿ÜûúšÀV40»}6kqoTgd7SD“Ïâ‰"˜BèëèÓÃFû Iùó"-âdü…àœ»®Ø2ìƒEüÎb `¿bÒR«!™ "6§?D®ñŸà\Ÿù8öþ”;βP ¦L A%Ù‰–qºOÝH½RlÑ 'Æ>Rcíi6êÅYÂ>¦Ñêþ±•“Ј+ÌÌ™h8’‘Èì ì­Î1„’ï…kóƒ_þíèqè+¨œÐ7yNΊ¥:Dg"°PV‘Ô£¥#¢¦žG6¢WH(¡#Ф˜çLë[M|¥ÿ lþ¾×ÿ‡§Ýÿ½Y‰²¥ÞšÌÄ™ª˜ÉúµjŸhØLýÝк]Öí‡PÊí‡ÑÐk¿\6ËS¼>ÈøÚ7ºÁÉæî áq4 ñÄVp  ðZµ ÙïWÑ—3ë8ú†‘¥J&ÁQójäpvœ’×!Ƈ¦ÞÕ5:G 8*šÁSÞ‡ wÖ½ÙuÁYÔ}rfW,``¶¶­A’iÚ±ÃBû¡x±ŒInvêç«çè…SÇ\nêM1SG6Â!_í“‘2 ‰¥¦Î€ä¼B]9†žŸ½Ó+ ÅCŸ&É’:é /°cPôè2ã+ø†<úɘ‚7ÓY xÞÚ±7ך™|]ð•?Ý—–‘z„ ©ƒPp™œN§p°‡Ö,(D^Hîì >¬=;àr~Çô‰ö;‹>H:¤awÕ ÑQIL:ÞÙ"v¾{ mâiñµÕØðõ`ý”!‹>o­‹þWU1cÖ¬ÍÄE91P›ápĤðJ¨v€Ã@#ªÚß%bP¼‚â[NPÂ{Œµ3|”Ï¥(‚NŠ·é¸/uã9ž^9Vð­©îÌ)ogMy¸!¹´È¤Jþ|¢üEÒ•Ël.c¹)"X™Á…¬Ñà–ÆtP'â¼ÿ›Ð㿵sq‡k™t‚êÁPVé* LÕðŠJd)ðÓÿ3ÅП‘:dSvUiˆ|y+üH)mîV„³ Ô÷Û~¥³{_źùJç'0ÿIËbîWA‚Éîh°;ú±4 ºÔn~H áúÅÅaáBÞ¯“µ11dÃkôyò¤mQ}¡Yyå…¿Ê‘²Rܸ½Ê•N[­Þ{ÉP’X‘oˆ­v—ýÌ#½¥7Íå2•¾:ÕºZ·~G=ܿ޴Rµ“ø´ÑXpÒööj%áû&ƒÁI›ôüj-ò\ÛijúÃ"#Òûfu-tž¨Ö!ÏÃk~me[í—ô÷+EV>U‰[”X»PqðŒK^sýç)áKu%—0þ¥þán¦R¹›b¯0ñ¾µkÛÓ—¡a¹êªùNa tÄ!Ò ÛPŠÜVC‘ ÒSÁo×Eò‡/9I1V#!%bò >öÊÐåï¤{bþ@öD;íÎx„U * B—b*h×%ö° Vª¿áE`±ˆ]¾mÏרg¥D=Éÿ³ËŸ§»€ãtþs—«Ät%çvò§—Ïb&e·¹ëôEÜV®_¶_’^=² 9…Þû¼Üu7}éõû]À†íÓìi~«2Ê,·‚é>˜íD¸m =°UöÛ˜:ïY9:¶° žL‰/pªÝè!cx×âƒ\{wæ?‰ÓÀ:ÌÈ]ðog~ Sš#Ü[ž›rg4jÌÜŠãð!ò¥rÏí‰r ¢Q`r ¤ëè[uU)½ÍÑ«÷sñÙ{|ÏÕM¾•¹á¸˜f•×û‰ÿ¤zÊA(1ìR}‹:òÂÒå„ú™:ôMŒï¥â“,)â ¦GÑo ñUqšD>¡ö&»BkJ`% ¢Ê%Ù7;àèt•Ãth>f:ðˆµÔZ‚`µ€˜5ôê´ªö{xÑÕcö£ÔdƒSWþ#ÙŒÑl*‰U9|fØ%¥á†IŠN´ ÇúÀ<â«=&Ë*`@£3 ûijô´·¢žCW55ÎÙ·¢Jöë]öÙIÏü6ˇ†üH7®‰2x@x®¼¸À=7}šÿýdÚ›“û™|óF1Åé¦*NLŒ¡óÓiÁškzê2I³Œ¥À ´2žkðÆÌ†cp¿oÍæM–ÍLëoíe.9¡G¸ú¸l….8œ ª) 5T¨ky¬‡ FÏÝpÛvx*ÄDh5NçùâÊ Ýçï¨yWÍá+» t¡ ùGéôÜidVZ‚QYè È26óOÖúiÒ*èÙ’¨ƒ¿x½¡®Á2’éåPgEâÛ¤Ñm¡†°‡)nŠFsw!˜ö[ÀôôÔ†zI/DÄÐ/§åE~¶è8±¡¶,‹ÓVD±éôÛÊò„ˆÒoµŸ<{vô2ùÏŸ'‡'ü>”·šH‘,P¹´q܉* i“n ŠŸ¸,m.'•;²sý䢸„y‚ŒÁÂ"hòÅ$ìi]·A©zlD¥¯›G/Â@À|ºPê‹'ÍgÕeu9‰â­6PUÌÒ0±G;Âñe!†§|„7†;BŒ™7| [:kír<&°ÿDÐèÒäl¹@¬Yºbb°BÒ®$ªH8Ïþ¹D,/3lžÔÑ"Ø…ëelÕ ±i›àá¶/£äÂÂMÖ¬ç]$Q8YŸD"‘h Ìe²,Ðé[¯Š/ø‡f‰›36ž €©$Š &œRþ‰¾Oˆbªô^¯Ÿ>ß°g¡{UÕTÁÛE„‘ñÀ‚;$‚“çN@¿ß°‡'>R*k5bX\–Œ 'ƒZ yÁÌŽi²—€‘aa»$É*›äH¿ßïª …[ppït…Êþa7ã55²ž<=>z9ø2°ýpøóÓ㨪J<Š”§F@/c· îžË&m€(“z`·"û±5(9yš_6y‘ñ›RÛ›!í™RM?ÚW!Ò`ꛈߺ”:YŠc±|S¬=GÛDÖÄÊ^Â- \Œ8ƒkòzTª?:0ŒO+£~«Fݘfc­>ÁÎõ½¦ ¿éÛÃuÓ5çK˜_q¢¤"Ԛʯ‚íq.õ…MñŠÛ™¨X)g?O‡(SçsÈ¡ÐñMÆ‚ùY·p}`Ö!ºÇ³1þ6BAŒ£ð޵?fã€l𙂶î>ʆˆ,WF˜ðªzëžÙ2Ñ7ßÂXõ@A *Æ­]_%Yý¿â“¬mÕöæÆw™Ù¬ó艄†Qº6` 3Ê ^dŒ¬Ûe¡~øþB=p°Ô{«í¾RÏÕÁŒ*³«ªvz÷ö?ôñuÖ{µû¹ßUÑA%0÷Ó˜ö.‘r|½£ì øš\Oho(÷?9„¹h6ìX%F¹] ¢{_+2œ˜hø\‹ßæŠD³ð¤Áf½4 Ô‡˜½‰Ék:™¸’¶õÕË8ºå{v°2ÄY4h»§‹YeÙ°»Ì3›¹âT•—9† Y¬wô–Åž˜Zä^‚CÖ¨8w9Å(¿/!™Éxq¯,;£=«ôÔþÂ%³ºä®òwiZ½àʸ gr—pÐX£8]ꞇºÄ¯Mݨ¸y*|g•¼zÃÕˆ†Ä®nóZ?ORÛ+¾fÒ¢²m¡µ‰Ï6ˆzXß÷Á;Ï‚šd—‚Èà ÍìfÝö|Qfã3¢ ,ƺ6LoV‡š$ýÃʱd?yŠùÐ032á »3Ƈ’J¾yÆ ~6O#޲ŸÕç´‚jí6mÏ@œK)¢þ¤ŒmtDç}¥_ÕÚêÉEŒ‰gä 9nFùØa3Á©@šŽ„C«¶,@·wXJµ;LôÒbF÷5kÆšô~@ˆËKôör>xk'çq:ÔYó ÙÜAݳ<ÃÝòb–gå-8O{\-ä·¦Gž² ¾ãÃP`ÀGbV¸31FÆ*Îø1öžçpûät$(‡Åluëf·fÝCwô ï©0ÓÙræÛǽ£që¨gPKôX–êëT‡}¢—äü°žØš¤5 +tjóÛ ûzŒœ÷—\…0ÔèæÓݨ7%[XÅr1_¢w㈧Ίt{Ó¶·è+·ÏÞ0e‰S0§Fe›û(›flO«#ˆàD'sÊÐhY¯ô­r˜7¤`ýp7mI5; külˆ"ñ1ÁŽ`ŠÎ$óà"ƒ3 ËÄàQ„`ü‚º4Ñ'ƒÊ8•A®»ï~òôñà˜Žžú®À¬kÐpë^†û’Šk°rÿæO ^¹_™o}oK¼ßˆðÀoƬ—¤ Èצ|ÛÂãi–Øx:ÔúbS.dYHúª”E–Ç)ÖAWÔœO×·8,ÙKjÝö…;$Õ ’ú¤#Í¡}P›¶ÊºÞ6È¥™#{3É’¬°4Å´÷³l½Ò•{­‹Â)’C´#¸$GjO 6κãæáð‚§ 8º¼s‡YÎ|€Aý‚=Ä}$~“ TI“Ûœ³ö9¿än×¹¦Þ¦$e2µZGf¹àû¢gGÉÈLú[»«®›ù•eDnªÿ ñ?Ò´ô¸HÐ$ï邲ƒc؇ Åâ/¬lšÛЮæ²ûváêšæœcÔcS¼Jà9´âûy›‹s—Z .Üjû¾ëàw^–Zæeë¡~€“Û‚”ކEž熴ýöþý-Sóîó‰jC4_ÆyfÃì›À›/Újh`·)I'ô³¬¹·äÂ/§ST@A#Ø^ÙO*Yé$=V=tâàY±Èö] ŒÓ>ãy¡™ÑTËsÓV>3:¸XËå$ ŒÆV ;sàžÎv/ÙÙvsáb{„A@w1ä é†W z¨µ«˜ädm…¯#ËÙ—9TuÏkV™ÁÀÛþk}Îø%øh:prÛWèX/ÙS¼\a?G¦ÞBI9ØwóE‰”0ÖŸa-øÐÈE()À?Š| ©B1'ßf`õœ„µ!m;Õýâ¶«‡" Õ6\…9ïW’¸ý0p â§@µq|zf#؈‹ØXœžE%MW×#5¡fךÚ}[Gd£¥°ì…{ûÞõJÛÍhç‡C.XÛìéÒŸ$`·íjUÎ#9¯´¨,IP[dçp²[AO)Дç×"¬ÔEÄÄuU…rL7ÉÍô~ }]Ã"#“Óç:¬p¯¤á-¦ ÅM9¤sAñÒ×›&Gâ˜ô¤Õ(2Ìtž‘3hs•^‘•gFÙÐbš-ÈàšºJ–Óµ±Q±<§KÁÀA­c£·ûý®Ë¾ì©‘¥¼y äÚõœÈÁšÀBŸ\¡BäóIELngJ—ùPœÿoÃór_%t* ¥ìoëí÷6é•paù¡üí/¦€ÜÔœˆ(FÙ¬J¶à ^`Þ®tŽIŸ¶û;{Õ•Es¢ù*Éû®ÅހĽÔ_U€†õuåÕû›ŒrHæ€ÊÞÍŠ)˜”1mì0eÍ‹t|¶9ÎÏ0zìžÑ §‹‹ÒÏ!{¤Åño ^<ÿ¥³ÛK:yyd‚¯Ž;?þGgÚ¿Ì^Âsý=ìSX s†²Ÿ%›FtM½÷úwïd›ê^‹°A:Ê çÅQ „Á. uª«áâ÷ÉÃcØs8¬éÞz|íI׿€:5í€ëq‡Õ+#üñdJ¹Çé%iiFÄ”l4êY º=ÜvR¤†B•¾ƒ‚Û^( y˜Ž«‰Í¥?,Ôï{ô¯²Wg·9Êà¿[IgÇüó5sLÎ~•|qÖý n¡Þ»÷x·¢f1ØÌ>&¯¼ÿ ÎøàùHl=Þ’ÏoÀXh¹ü˜|…}ùp¦šûHþOÆRÍL³D«÷ÉYeZ+WVqˆÛ—ÑÁ\ñødÎç ÛÔäNާ÷+‰^áÙ7»ØŒÀvõé+´rXPâlAǨiò&<~W²l‹»©«6ýÂo°Vˆk]â û‰b|Q¼HYà,•÷üÊ«îWG‡/ý8xyô ƒ$¢•GïôùÆÎ¹øÍÑýö +=Ö¡Æš}(zšÏfÙ¢­¼8­9u€™p];_£×Výµ-/ð2êÍ.ÒwÅ´˜\­×®«tì–RÄFmO„gÄM3艓åœq¶€Ç-Ø{Þô´,ÆK¾ÐÅÛWÏ6ضF}\ùάÁ÷ñkd]d‰QÞ`e$×3A8p´½}ö£Š¼2t© e¼WHtz‡¿z/IjQj¢ÊÞ-‘~Yb,ÍçÜìÝ0›ÏìW»i¬a£â Ý}kîÁ€Hñ[0|ƒðŸ_Þ†›8øwiÝqË€ ²ÎM¼â-_ ´á@a¾–Y*_÷JXÓZáJëÖ÷¾rI®/äÀî²àZ‹{™-0">Ák ß!jýu}õÑ!̺¹¶Ž €#{*]p€ÛE–ŽÐÄK+Î(i? ÎÑî"tÅ/äÒÖõ‘bÙój0¼0’wžM¥fk–í l“ux˜—á6ÏHé ¾>/ñ®‡°÷=OÔeú£¾Vß0j£ù-ô 1’•%ú]3ízô!ÓÓ•Ž´Œ ÕûYxHt¼]«Ù{°;z€e1’njÄ0xm"t7ü²…¶ÞèÒ“CÔhcYø©~-¾Æâ©¦ßÀ§ é¾ú®ù²W¶"Ú¢Èe„dÕ¦Ö¸“‡Í&.‹ð$9b‚1bcþ½Ö¾KfçÐÉ"ðÝ©¢OPEŽH¸:Ò[•Ûó~¢W˜Þ%ëKñùÕ×ií‹yv†%Z¸ë: –+$¹âÑû*]q2¤Ã2! Ô]d..8ŠÏ'³y/˜¾Ð•ÅÎTOoœ"Ӷѽ +ÕañÅ)JÕ[a(Í­ÚX• o«8yàP¡‚°9ë6Æ].¾Î/äbè-%vý© üÊr¢÷‚;÷Ö[N´T)ÀжDš)Ç-ü&/c_Ä«Âö€ý`s™ö¹ Ü?ÍÙâ²pI}Fxë""`’º$Vùm5lÒöàM³yÉ‘—¦Á1p8ŸlM£RÔß–pp%™WW•AÔC›vép\7sU,Å\ÏžXà€:çP©hŸ{h!i—R\©Ÿ…ÆJ‰Í «­t€ÀçDñuIº@6$V8ÜW?mJ –*úæ|??÷š°2uõ†‰ž|¼¸,±¾ä" 7³U‡9¼­wž£÷1G:+”(RùÂ|8X @ fWBB– ‹Ï‰U˜ßœš‡»ç%š‡p]‚%ælóŠ¿\}ƒmAªQgXE¿‘Î,a AOÌÔ¿Fó¢ž:ÿ ²™¼ALþ¨Ì tÀ(c‹WâCš9)[íuL䦣‘T)¡ÈWÑÜÚ¾bÊ¥b‘Ê7ܹ9޽¬]!û:ÊU/;EV2Êû\­†ÉËh¥rbž,ãÊ ½¡±ÃqϨ¸ê¶øx±…ºFºâö>ëÈÑ)*•*)3‹«—Ð x–— bT2n¸œ°rÐF¿q‰ æEFZ.LRR—´¦(½›óôl¥8]²‚"³ÑϪ‡?:ËeÀèåŒåúùtØv8õôÛ‚ËC”7 „|š—–ŠÖàðÓѳŸ¼cðôù£Ã§ƒãÃWåb*hsg{žlÊ‘°©'/ŠraÏŽu‹Þi »f6r³æ…9¨”KHQJôÇ8›ž/.zì†GUŽ8ü)®¢çG¬s¼²ABgsÓ&cÛ›Wþ;?_:EöÓðÉZ“³Eîq£¦IzIEÔfR^w¤n†ž€|Zg¤ÛL¯h/Ñb3+t©<6ŠÎǬThéÓÐ#×5‚:Þƒç’_s-Îóã\ÖZ±~§WMê#Š;®×Pá]Ðw¿d¨e¶«¹—¹(—â«f^–ýw“qãæðêUr–6vó t™OüºX¢¶4‘ŒBešòÊ.çã‘ÕI}c‡°Í@m+…?ãxå£ëª˜´áx±.‡gpnëhdóžW: ¦º²¾MœŠÑ|×µe-uŒh‡%£s=jØ/Ã݈ ©Ç¶h#§Z»WƒšU_kZÔ<4Q7.j¯#lÅx-‚®’ºkÉÝÆUtcb&ýö¹ªö[-%Ž DM7ê6ÓèM»ô˜1¬®3sT¯Ub›sø>ÜŒ¾¨ßGk·KÎ䋯FµÓ]!ö±2Ší^¡ìt›¶·ª j$6G“ï4oÕ}Iµµêüü75ž)†u ÇRÍ2j¦xüäg;¦¢ùu5ëj†L³øZ¯]éOq®ƒJO ±·SsT®/Bïë±½³+7¬qº™í“µH}?Fo®Ö dŒw?!?Z*n}±RTˆ‰9Dc£¸³JÐnÅj {Šð'¥öuNKUÂÑMÈ ÒñõV–ÎÇ9Äòñ÷DË›‰K'ê÷Ú2áÆTvGëJ‡›u…ìoj2®) ?d2ä2òãL†Ü,áœx¸%žÎ…û°Ê›ÎG£tØ{`«£®.âW9ô«DÂÑh0,ËŽš²Yº¸PÙßŕĨçHSºÝõoÊÈ#ÀÏÖ%N=âβ2·¢Àž¯éc³¿{îÝÀ‹ (­¡Ž@ËZ<{yÈÁé1šYÆ¢ÈV796;fà_á²WƦ\CFø)Nðð•\ÅlaŽqê%”‰¶æj~X×oŠ?¤Ô’«òTR¶R¢üÜfGNž¿|l>ûþ?u’ÇG¯U//Ì2òòNWf?Ìwîhybµ7Éö ’6´/(µÆª@ßø² WìEƒÖe3&#àv¼]uÅ"¶ëøuy²­1fʯ¦£|˜:$b v‡Dz‹ Ä¶ìº Æ:¾7zË_Ïž9óèG¾Ü•Órj´É䥃ÊHj?i—K¤}mÿ¤œ˜ð°9‚pa[ Oi10’o¦ªJ<·½Ž†ª‡É9@€åC‡wþ2ç„  S¬“œÕ8EI3“x“VÌG¥…í³ÉéÙ7±L:À—~yÊÃVœ‚Z"8ªˆ»þeù’οÀV(ùW±&äyÆ7T£Q6¢zøv ðP A\M³±ë5@äfìosX£ ’°¯°^¢ÌmxJ Á“ºOµ³/œöž2EÙ=ùùåÓØ€¢Ô.>ȽtâÍÏ’M`½d^N~é<©ª*g>ªDyTæ€@È‘¢ÊâRRuø :‰C7]°÷&Ž’cÅ™«…YSnùÁbÈý²€“ÝÖhVÜ¡cñ*IÇ4°Þ½(6?@T t)^ ]£µè ÀÍ)à8$kœÁªód2kuZÜ\,³ý­­™™»~1?ß ·Ârk§¿³ÕÖW™6bÛù¶à$‚5ÞÏ2Œ‘=è[N¨í¼ïÌI§Þ¾¬½1ÒÀ+‡ìý%‘x‚ßhC¬ÆÊ¬‰{ë(Ãj~¬Ë­_«:ù+†$*6_SáÄÌ¥LÊ:W¡Ÿ&ÒåÍT0"+TœH]Z!/úFu±iºB‹I5úÕ>Ð@;’®ÆV¼54à(¹ Ô} ˜äŠ!¹~D1±}¨[ð‰,6¶«ñ”˜v |l¤_-F6±¦ÆÈ¶çãd+F®Áʆ2à…!xÙ«f¶;»Rae¦á¿ ³½K{Õ¼Vð´5¯ºÔ_•fÍNjQIÍŽƒ¼Ë »ÌúÚ2:w "Ñ.Æý1ê VfUù%È`’Í’ŸXª°l1-ÉÐÙòô1NÛwç|‚ Ÿm+3„d™²âÉV1îãÛbî×Â_Òbå«s£žÇËU½ßWi¸Zq›s3{^¾Èæ“ô©DÀµÏRÃPí®Í}ËÎÛ„ce•i…ß´íÔ~í ³êÎ$¤vozI¼"ŸUÏH>X„dþP –± †J–»^Ìð4ä;¶@G²cäzm¹…hÃ^=¼=4×B…\=:•ˆ_•Aøý@Ã!Rj®B,’0ŒqÚÆXË"Í–S£ß½Ö@¤µÙÃ(þ@Œ¸µÖ£ÝŽÒ’§–•3P†Ï5kÕ+ÂH+V*AOÕßã5­×Y›MÎiGdÛá,mìŒz·¿í]¤µ¹¯†0   r$fû1î Ö¢D¦îK·.é}x©©™}÷ÔÚVËúv[ª•†ü›µZ¼,¹Nß÷È$­ûßýQÒ >ø{k§¿ý÷V’M‡x›™ËÅÙæŸþÞúöáß§ˆÆ¤‚ÏZ÷Aغo[}ÛÎI‹·^'ý–©Ñ´²ôábB*zižˆÍÊ2¬†7[‘ö÷p³vè'<¯¯ÝÐOh¼'zŠ^3•Þ'2$¥¼Áo™†©WÎ4EìYÊÍcÌÊ“Îfc8H›¦àï A@Óš›O ‘iÇšÍs£‚D÷~ʦKkg<ÐHÛc6yÃ,ŒFî4µF2ct¬µ‹iðrΆ­U'4ÌqõñÎjTÕz‘£›¿zäȆÃLÐó†Ïm“ º=]N?©cOälWcĬ˜±ÜÔ#¹[Ÿx¬ ŒÚ¬{¨vÅ‹ÿ½;FóKÛÿ`Q<ð-1ͧøTY|é´/U…t‹Ê3P-‰ÔœÆ,ªe5&¹Ã:n­=!Up{)ìPÜM ÷/v(î_²ñ2~m ‰/õ9¹ÌNa(·îo]ì<4»å !UF%-ÙŒ2 ÙaFÉJÐ*Y¢ÅëäŠöqë“‘‡ýÃ-¹?XÂxqÎx®÷Ëż˜ž?|$®Ö^S÷·øuòÐHÆÅù9ìŠææ=j;÷Ó‚(´¾C•ÖÃÀoÙœ_àßû[éÃ^‚¨f§÷)yz·—墘äÿE +Öÿ>F³y gzp³?óú©sxð-p2&ý ú7¼Ú²á¢Wmšˆ[¡Ýѳ6ª‚ˆ±tlnŽˆÏP#ˆ‘Ž-(1Iƒ6dȨþ3#d -JFÙ-—¦ N‘ìtè¸ÞOþ“ÉKP%®Wr¢aL=×ú¨¸œ‚dØn0ëÊR@O¦¦9— I‹†”-y‰s6åY‚H4 -ÈHbmîãÎÍ#ËPš_@;ÏϧnfŽ­%(ÓC:Œ[˲q+ä¶ø¢à1¤£=JáŒLÀšzQ@š"4&ÓLâ@Éc>c@‰—Bq5üÖæ(‰L t‚ç¿X5}T,>{üΟ<õAÃÜɧ7œºW(ÿ$h‡ nÊ~¨4²->õºoŜዎä2BHW0­8 KÍf‚±± P–sÑXRì–5«ë`KT¹¿°TµžÝë š-ãõfL±ÐAÐØ¨gb\ÅŒöL»*]u4ºÈƳÖCø¯/¡XA4ë²H·S£•f²­ÉóÒgqsz/ˆ:i¸BLß–Ë›ø—m#[¡øe>¸O³:ÜÇår6+æfNé¦ÿL‰˜dåÛ4Çìéz`„!gã3ähD+ÛAbÎJìr]Qz Ÿouåµ>ÆzZÌÎþ‘´Ð½{®:1ÝG•\–Ò]*IdÚíUéLm§ÂË€S«›{i‡xGëÒ6Tzâ¥ÖP¾ÞMºõF 2¿¬†ØA‡–"7Õ@íx%Âb’×2š AmB1Ô·»’¾éÕBlÌ“ô]>YN€í˶j ‹5ÃÀ3´‹tÐ âGpp0'²¨„3Ûrêäÿ™vÁ}¤!Ž&}˜IuiAy´†·º®ø@…×é‡&ô:A¨Ü²wÆ .âZú\÷‰rX¬ÈXáNîù!§è5ñ¨…WwÄX4žkžÞl26Uã¯6Åw€4…mWÖi<ޱ܄˜}kŽ¦Ã®´é¹ÎD²0K8Æï³ÿ ˆ,Ño&b±ί‡ÊÛ³8>pZ© ~ Ÿ —ã”ͨuLÉH¸'œ&X¾õöž<{|ô!փػ.¸Þm1Išó%HûZ‰bŸÊ„i(-@YËa˜.¥Â]áZ tWÑZÒ® Ä3È»D^b&Dù [Ö²a³G“$®¦îQ5ëH}Ðw8ŸmTæ«÷_"äTеPæeò‡ÜÃåÏ‘7‰A-ì¨)$¦þïayè]ˆhF§ÅNk€ÂE×#¯Rˆ?øyFÉçF9ÑAW]gK:Óâ]Vò%65#_EUšÒÏÉgö]¹a1§3dg©ßšö«ïâÆ|4™P¯¨±M;„®´ð¤Í°¬çrhmfTÄüU¬Ó¤ Á"8ËîC5úryæJ“ò´~ã'íbÞLoà\¤yÁ9—ȺÅ2’êWÄ/Í¡?¹³íš–Ý-Ð}oï:=Ÿ]Ì͆øñzàTç'í÷4;G—¤×ó©:|(áe3®(,TZ¦té.HYLÑËXù€T c1¬È:UIâPã9À³%Hêì”]íZ Ë#Ýζ÷¸nÅÑk/µŒPE˜¥ ŸE„Påêþê8õÆ’ÒË«éx:~lŸC—½Î°\$q#'b(®ëX‰/™éÍwá?š<«Ò†¸jå•ËÓI4S3•qÍ8/€æ¥nd)nÙk‹iÝwh;ÇX†×'•,hö]¨=ÿ™F_<±çÞPE¬ŽäevŽ1—Sj i mËÖ:¾Tj‡U6žLs"ÉËŒíü°!X·ðӴ̇Òˆ¨¹rÂUå 9bœàÁ”¸Pi Rº°bpó|HùªlÞô 1ˆeg÷`åao•ÖGåå€X§¹¨Rr,Ò'‰-8?àÂÝĉ*q¦JÀ[D=¨–øqq·æò~cóV(Pvù}=°Ï«kŽ,Y?RÏ´÷Ä|…󷪩½qåD¹d­ÉRÅ­’„AÁÀÖhELYNÝ®G% ¼&=pQ#]Θ öÒN{+é´NþWëõ×­™’×_w·ëo*†œÍPIVV&óÄò3ñ';¯½ùh„Òk>ÅP\õ«´éhó¦ã±ú¥7ÕNË´ã¡c´hµ\!5·ÕÖ|!žJP¹U’q :7F1J©.Á~“=‚špm^o*f—ïFÙáQ«ˆ\Ò;ö s†bÙÿf l:Lòûòª$1€°7‚ ½o0F…ù5Å{ºãóâ žLí7¸UèÖè“Îìªcnr怱S—ZÐ-È#bZÁ­WÖR]ýä`¥a¤^†@UË©ì"\ÔRÏaìSgyásqIGwé!Ô”S4`åµ[JnÍfL"Á¶aüxEs>O!÷ @“š-“ªêµM]ÎU’y){—‚é½r“SLÙMw¬ØÓËÔ0'UàY~E…Óåâ âð6U¸¨Ö‚=Èy5;‹*zñã ‚ï²Sy¦ âr‘æ` }›™ÃI‡†\’=]й_šñ{;¡ç$lÙJˆÿ ¹×EÞà#O Î éÄ@` ¡Y+¼ã– 6¨¥Et{òØpŠ„¯Ô°$Ll1×H3«çFåæ4)Øï>Ó´[à`“Òq̓Ǡw™.–¨`uL+Û=¹_˜9!Îo™ Ê”-C.u¾³d.rMòÆObï—g˜¹š½0‚žR}º»}7ÿ¥0m×Ô3D:­põ—ÄÓ$c(»†y¼#ÇÒ qÏ’À»µ•¨º%:‡‹¶E—ÿúWr+ŸÊqjòñrŠ‹Ã4¯.£F¨C¡¦›U~™b9_PÄ4ïÖ#‚J©àB‰w©‹/Õ‘·Á{ÿ2³ å‰âfwÎ%úÇÇ$&¥ÒÔñ¨˜(„º,3³Â¬A–T•ίö7\$.(»2FY—ÊôiÿV áöïñnàu »“×&Rä¥Ý_öÀ^°*̳éNinzy6utlTqFJ•#'’úÁ “"k5ý ?YÀÇ!m¢½Œ›©"Û£*ݹÂf,uÇ©aMGÕ[~M>`}=~€Òi‰ì…¼uacÂþ¢çvSÌ _Z>µ)n©6ŽÆ`ò­9¼ÃT ¼ø»FòËa‚ W“ÅÏÅPÂXHmë„ðÃç0`æp©|kõmÙ™Ûl‘ÄD‰Îì0˜.ÍÉ•+ )Î5ÍŸÈe1éÄùˆ–ºY’sð R§3O/¡‰:p›Íy‹¤,ŠÜ¯X•‚®ïÝ_ä÷m KÚ[1ìÃF²"Àz3QGÈ‚—¤¦ðx‚†Øó|Tº“¸»P=—ˆÖsѪڧœÓstZ€2èÅÀÕ&mj Ýµ™¨½ %®(õ¢,Zô^[ü/jsSó‡*/µ4I_¶¼¤_yÞD4ØèL9Ñ”©Y º^? øçfòáƒd§U½Ýæ+¨²Ã¹«X ÍŽO KÑ᯴Þi9êöX^;@âIÇ´X*±È’Ì{}K%‚Œ µ:ø|R1M^ýϧ˜²šu_Ü+à_óMª*wÌQdŽó” ôþ@Ç0œfF%%Å”[ÅOB †]Ô¨¦Ö´EB’ dÈ<µY8ÓMØZCñ®øgÞ›÷(]Ù%­rVõážC1<£(š¢<)î ߤmí±fRæŠv;ä“JÚM»ÀÄUÄo¿ßߨºw »â^«çí&n$7ÿ³cÍ!FO™À¯c¦Æ×‘óÐo’¥b§Žc9P°¨(¢ÍËÁÃb ÿÅ$_,XW¤º¼Ó$Ûƒj™YÏO7c9bg•Û©“k×fm.Ûy?ʾ»j×õ÷ÜêˆûÁ6)Q·3¿FçíÉõ;òM÷cjŠ÷âØ@¼ýT7ÓR޹P^óäe–*¨g-FsÛÇÄõœÖ²ç“ÇÖüѾg²æl^¼5J_IY™qMLsÓ4GS0öµ¨ö~r˜ˆÁ7×0ꌭ»Æ°ÉíáO­ÁÎ3g®/ìâSÀüŠ[¼’cr Šõ“k ÞÚ€}Y·tOœ•ˆªÂoKgâäÞ¥|Zoˆ®Y%8ÜYB²ÄÕpÿòôù÷FG:¡ô´¯Ã}Q‡K€âx¬|Ó¶Á;òн›â%ÜððÓõüã6>{Á’Ša$(Ì%YyÑd¯Kê …¹/LAŠYìIJëDÈ¥^78À×u/rv‰Wð±ú¼"~9ö^=¥„¼m祳¬oFp[`g¿ý2DšÍóI:¿ š¤þF;Lç='û„ÑÑ>ÔÄÍ ~FtÒ-=4jtk¯?¾‹>F¥¥úµÓeÂF¨…2$ÝŽwH¼­ÕÛLrB:¼„ëÙ|H€à]"ƒ; ‘¤(ŠéÆ"ådŸ”F¾/ܽ(DS‘Grú6#alÕ .uzeïö #)ÀÉ&e11 /fœË Ðm-Z¥\¦¨4M`’O•YÜêÝέI“í wk•™Ùtš{Éã,BÍ[•»Àú{ƒÛÖ;„Ô\™Úk¤&¶ÛŒŠi°Â°Næsólˆþ¡¡ Žm®q Meyo“XC/6òïlŸçä1½ ¿[ÙÀÀÛòHåutåT2ÇíX°:fK„T!a‡‹üü2Ú%SŒ”êçàôj k·¡ öP¼êNòéÂèæð¯ gí×]rÊ»}î4ß$y3/‹¹m]‡¬L«”ùYmq…ÞBGù¥ç܉ùƒæE,÷Á‚ VfRš…zçô Ö6­Û}„êYÊû›iˆ5M£ªå j  TÀy…£)º7]Ч½ät¹°ŸXOüB)­6&˜Ôü´ŸüdEhuËE>†@h}î¦(…Èê‘®kGŒgb4Å„øÑ4½ÄeQšå ãÚœ¼@9„B¢ŠYͧÔ$_€oCAž 8t¸’–»’-)@(å>’%Q•ÛÈüáÌö“#àiR½à‚^/îè.-X}šîС§ ïˬœC´Š[½ò;‘Iþ¢yR€˜–Ü%®Y¢)ÜMn9Nç,øÈ4ÂnšÌÆc”úT<ä’›£ìÌh¦ »À_]fþ ÃNsò]Ó` Çù0_ôuÛÜŽÚÁ_c~iï9oã‘7‰¯;hç¤õäÙ«£—ÇÉ“gÇÏžèà]_ u“¿>ýùèUÒùâì-à7÷ÿn+`Ÿ’î(0úOEð©Œ?|nGžö/ýqzžl%Ëéüb¯$˜ß”ÌáT›˜šÿdX›Mú+çí… ¦>Ù£~El„s€-$„ybN³qzEÆ,òD@æ¶Sb£Ù:½Ú3³›Š¿nÕuùAY5! hrìKi³‚+ö)™l@ÖÝv¸H|u•r­‚$ñ˜Êö¥:WZ¸W ÁöuÉã7 %4íˆdò2E纇·_Ql¯é´¹¦æ®P¿o©¹œ’÷VèåÄ{.õ;Ò‹uÝœ,lô’’„— 3©¡^¡>H’Žxñtq³õ65ö!bmr`ëS»˜¦NaCþ’†¨fS”¥j¶?©¬ÔW±’‹ñFÚ n||„‚ÚúÛ: Y ,1yTm$ º¦>ÜÌ"g[ƒYÒM5T©%-p¸ªÝù×*ÃaZâÄB³©Õ;èÒ¹ô·Ôœ¹ÉÝpQDX¥c#Ö=6âqYYø2ŒGFÒ˘U79K0:9“jÖ7bäU†ÂÜíáê£0úù'Õ€™šÝi# ¡Ó5]æ¨m NP>ððPýÁUJç  êN`sAB¬˜ÚS6º¬î'‡h·e@–{½ˆß#m€ ¢YÊrvÂ6yµšr]²„Äc44D¢Õø¡Wñô àkìâÌzÚupŠQ{Â@læ‚\åÈÄO»Ó¤EÛ04³;–³ôrJI¾±ZHÐ`f“”Qñ<>~cÏ Ùqgq±4$W1ÈÏóò Pœ¼A0Ë…xè!Ôª¡T×ÀLUÊp4uù| ALžÑ¤NQ÷$n‡ˆ; ØÂŒ”éã½£;%Q]4Pg»Ÿ<%ÿ7#ì‘Ú€‰jF"¹Ïq« $u‘U—l@¦ºBÿ¤~¿ßM&à‰ƒ[Ypsö!§=Ýth‹V"ºiL<´~§Õ*Ê-.¢Æ™M‘A#2o"ð2Ä]>ûZë 5U”©®çJ#§ÁWCt½8ЗVm±I¹W:Yºɵ×?:°Þ¾NÄê4ˆx@ý´5X¤®j@·u»ôÇ÷7Ui ò·V«£×¸¡á¯]}ñ€ÃÅ+ݸÚÈÝȽ˜N|Ž@Vi'{— —dd4KNëå·L_¿ÇT‚³âcÙÑ$#LŸÎîÝí ¤yÄ6o¡g|à™–ýöš /Ø €©d£‚ô ðU¼„köK7É–•.b·LŒ9ËÐSÏXš;¿]4 î§8³«Þ·¯u¨•êm€ÝdsÕ_¹¼÷(.±e¾)²Ô¸¨ØÈA³Ÿ@vsåÁ—Âþù¶á,%'¢m„ìaûìþ±Ým¹ã¯V̈eü ㊠…EÓõLé ‡Î%´v}d^¿Õi|zÌÈ3•vŽfêŠBõ=Jw#}ÆòÑ5ë™ñÉœ´\€Ù,›©*öÁúŽ+óby~á®*A=š¥Ã7¨?ìn÷å.Ÿ¤žÚP³é9Ø£0°ÉÐjQê—x‹‘Ayx>ç“àÁbDvzþ!;€OW f¸ækÝVj^çËÛ¼c:}›y›ŸŸ¡€oïüèd Ó6[ Ü(8Ô¸Z†â¨ðbiû ¾ dÚBoÞU… Ä2 p[tYùøÉ«ã'ÏHhé{Ë÷mßÓñkH(¾gwÛ¹8Z„´]ìÓjl®¼.wÚC/—CËZƒ">¤Vm®LÑkŬùüo(_GäìÇ‘± òuµl½ž\}¿#~ýõuØP·b3 ÛüY ȘQš´n²+È­ Ün§Ò–°*Çë¤æCU÷VCÕ¡}Q”‹M5 •Rt=!$ýíÜfFèÉR*Ñ™D´:e/æ‚Í[ š#jUÇÝu‚Mùæ]Å»AႨ¥KÌÎkö†bÞ¶MF¶:€ý>9‚„cg~V Ånqè]M¼¶tôGÚð=ÏJñTo  »—in3þ{CGöÕ8ZHl¥=n§põPB -’nÓ‹éÙ8.Ȩ€çÛð°$ Ý¢¸øb›Qór@Ørëý-ߺí:„HJï•ÆØ·™>!;½Ë¥ÆŽîA°[¦<÷NÆÝÇaìO¿ Âñô« ¦H°¼ª! •ƒÅ=ò%¸ï¯úòË/“NƒWIèÀe?€á1Iz׺1É}îMF%YŸe\kÁñÅaq„ƒ±„°n‰#ÜK‡mÅ)οÔ> Bq(¹ùð"-Œ”ÈAAp¢›ÃˆyˆŒÔ¾ŒÓÓl¬€ŽÄZÁÆ_•9‰—¦’±åj Çà•ÊE¾©¡ÔÞGè€I»|2À#òÑBZ µÝ3;;T¾ÀáÙG“|:| A°ŽÅi ZYKd Pw¡ µ‚Lu€ø$)/$ñR™òU®˜Ê"|ȵ»Qžë‹¥^YåÃꥆéÁ2ä,‰‚ÓGq+Odml?ø†“H;ì*|¥—OYÏÓ$üŽWh&\ñ„Æø™ƒDÝB iBÄø~1¤šmçÜвÁA5Ýð1õº”&"é¡!«îÁ-Ý…ï Ð^Vþú³EÉ0F)<ì3Yø–ÿ]ePœ‚L¶E+I²ñÒXH”SVŸqñ¥^ë1ëÌM¨5WŒrø8å1s]NF=Š›òÚóå”ÜøÄ\ˆYŽ^|æ;¶ef—„·Ê lž’!Vü‘àe»ÆÄG M불òJËu•+¶kW>e£Qc Ê!níÄw‹AüÛÝhÍÖ%oÝiU1§hAwƒ´WÏæ%᪌µ(œÊ9ÜWr+ÝC5ð«W ‰c³åéØMø‹»½9Ü®Â0g˜¡Ä ª+˜³¶äqIH–’åõifι9h¨XºÜ"©#y3U•Ê[SÕõf—™ž`Æ>÷RÒbp8Ñéº-§“r?Kmÿ¦´sx×£"\Ú(ÖG¡ãOp Œâ*ý÷£ä ègÒ§  TûïGÛr#'xù8²sÉI¦—%æßž×–Œ‘Ž/³ ÀY!ñ–úß™7eÌ´„|UsÊÇ£ÿ‡Sõ‘ËvE  Z¤+7ï$ûq‰šN¯*Mü*´†º? _¥Ì·ëói=y>âærŠgW<Ê|%F|éÙwZñq®›¹ëFËomZ¬P²SqŠ"² é÷•xbqNP,†v#Ýwz‰9:“;Ñ ÃåëŒ/m’#ºŸp¶•{EÐh$:ínFÅ9±#Gœž¾CÃhFBÏ'ÛëM¦3´±ùGí¤ý…³z…Éš>*å¶å,cÆijÜצÞöu¨§;óÛ¡èc›ébsQÌ6 È‘ƒ¡]$fŽŒ‘°ªn¯ODLy{M¤¯þ-é·]K¿@ݾ6¯É†¿1JŽäkp¯®K/•Œ¹Ž`/$!cHµxJÆß0Ý¢Ü*Ò×§\-«‘V.P¯uÒ™½T¸>•L NQÓæhûN%N‹®¶4$Àg¯Ö~"ƒ?D¿LPå//ò™Ï/©…&©XþªG… ßxܲ$Dë!A_.Á-¯Úèo4äGެç” × ‘ߟ%ǯy®>ª‘ní =â\rXÆ_ަê/ ÝµXÕ»E¬Ÿ:xcï"ÔèyJWR›¯8}R+m™Rˆ æ ]œ9 þig/Ñ­~œš5æX¢O.·¥arø š ‘ÞŸa‡BÄñ9³©æ? w؆&æ$‡™áy‡ãb*‡1È®d?ý׿þÆ×¿m ¥õÄLy¨?ýúæ<êÈ©¡ØßYòŸù‡è}o‹ã£¶ ŸøŸ>DŽúml›Ÿ{wïâ¿Ûwwü·w¿Ù»·÷‡;Û÷¾¹wçÎÞ¶w¾¹»»ó‡dû#´½ògiF9O’?\^^n‚:\WnÕûÓŸûßÎ.fF ¹ýd´Ÿè‰ï½Mvúwû»ý;pÐùóÖöÎÖö½dgoÿî½ý;ß$çÅij6¬Yr{•ãQ9¼È&iMæK~G;>ýuB·Fá~nÚm +n\¢.ʾìó”Æ:æ_ÇšJxKm‚“|>Y¦Î¹ÊœÖ×Yiõ‘hž§cýn9Ý0âÜ‹—S‹Øwî,ñö:=Œ ŠXœgo)OÃû¾©%$\ »FMßóéâÆ÷üìPÓÀWÛn@¶µFD#oÞ÷Q8ãV‡Ù§jiÿL¦sýRŽîìÞ ÿmuº} ŽëB>13!¿~ø@v>t nsZk´+ên÷[nÁ¡/©2Ý4«åÍr– Ç;šUn4>å¼~Ã.¯³vøTÔ‡cBƒ˜3MéÆz`T0Ì»;¾êÑÓ\Alà”×7XX7X<¤Ê¬7¨ïÊ&ŸŽÀ‘qóÊ0©ª¥»ðM: .NIóiôÁºwP;êJŸè¶þTý<Íßa<¯!Çdf±ˆhHÃÃ5~²i CúÇìñNžólhDóø ñZ?aï+^! ½ÿ…Y†?b 6N¤€~þ¼@ö“m ~è%;æ_Ó‚P×^²Ëèß'ß_}¼µáÀ¤’çÀó®»>Ípƒb^ã _Ï Øë‹e ôvÈŒM£¦kñÌ혚ZÈ…—T$æôuŽØ,ŸÙQô“N‡¹, ¼ ÛKé ë!(p6ËÒyùÉÆ¸¸–¦iDí´“òŒÙ©$}¬Ýp©ãÙ?—éXe<ÍGb(‹å|Ȇ¬œ³ršš~MG³&6ó-fGpäŇæQÉôÈ¡Ÿj&Å€fú–½Ë¢g ÐTíÎÀ?'Ç‘ROèÙüªð›à'Âì›à ñ¨(Vfö¬f|JODG¯1.ï2Ñã™*øœÂí×êóàêœë¸Û +°Ÿƒ­ÿ•¾ðÇ5¼ôzI˳¶ð“bèhiûºÂ5ËiþÏ%åLjpÎ[é„« uƒJäjjÑ“¨úH1­Þ)šc~W¦ŸÈ±P ŸÂs‹AÓ|^JòQÄ<\GFH+æ#º‚&8Q-æ˜ËÀÅÃOr:'ÈÌ:…B‚à€“ôì,.ÖìYð¯ÙÿÖ±J5]G]”êù™ k!INÀ‹Ëv©`›½D½­_aø½~­ ´¸Ã.L• E)F䯱#ðw¸>c(kÌõÊ×øœPæ×9‚Xý¢ç0 ôÃBè¦Ö'ŽŸ“6Û>Åô«çîŽÚôÿªBŒúÏO„oøm“£>õ㓃åñoŒ ëosœ£'2¦aÛÃ[Èê´jß;$ ‚y‘àDBˆ.´«|½ŠÓu•™jùÓBŠE:FŠ\ã,ß(ÜQ´^ k1H—M|H¡Ë¿6/æçjmÒ«O<^óiä×õÄH¸åÄ3겑iý‘+Û¡tÿ&&ùãh¿ödµ x>6eä¦Ñèø+w(èÀ«ùSˆÑÒÚiæ8èþ*êìµ® j.Ëôx>õ•Ù‡™ýÅŠ¿F?‚`þ+˜æÎ}jÍ ~Öï9”^³ãpa´.YëÄÿü÷æ× ,–ÿŒçë÷Î_D³ªÀµ‰£#Ùù ÑÜå(ø{½íå0¼ùð5W¿ÛŸåꆄûúÇó|:[..ˆ²Jœ^y½6go`îõNÚ7ÞýÌŽž´ ¬p¾($ã×zûêÛæ}•Qÿnº¥‚£šä ’áWn¦×s˜¤:<Û„û'ôq‘`ODúïC l˜²Vg/–“tú±»ú႞î!êS<ÔÌ18·$ÿeû_Ì—ÃE"Ðef¥sób:²ùmøXúÉF«ÎºçI²¦0;çÙY¢ÃrÖ˜Ÿ›‰ÝŠb‘׺?š’Þš+/ ò…3‘™Ñ§@Ô¨¯ÁÏ8[ü`Çí0ŒLØúŸ’äÓê͵óxÝŠ«+LIì­†#&^4oa¨_G4Tä'›DíÆ*ä¯9›ÔòÃ'Ó æ·2—>>ç5¶X£ŽBv g9Ao7J"ósÍ\9Áä…vpCÓ‡bÍ;‰5î¡Q!9k0˜Ž“Ó836Ü>àc·oóÔ• ÀLCÉøðH6GÕ5\@™ž>² ¼‡›â5ÓG%”5!Ií:M–¸—ˆï*ºŸ,$FÚ\®kfû¨´Ã7‰™?VçÅùiPI][áû”£.æùùàz:6|’OÓñ eÛ)v”?d’^‘«ÎÙY†NË6±x1#÷`œ ¦„Ŧ©bûóŠÊõNØ ïä$±Pt€Âh£_Ûé_ýDã?x›eùtøam4Çܹ{÷›Ý?ìl³wwooçî½í?lïnãßã?>ÃÿQ™x ÙÛîïöw äO[Û»[;w’ýÝ;û»ŠE|w–SŠCÙàp!ƒ~bñç'>p÷cÒJÐ&_ ÐÄìzx«î–‘) xÛ>†ÆØ T"/ñ¼^2>Â…‘bFz‹…cÑi?£(o ¥E¿>V2±kš€QP*˜Ï]ú5 ãr–²Ýå`bH+ãalèx:ê/GÐÁwøÄB µð˜O ÌkŠ)ƒ;#„áØxL`:½>,çcÈþ`ê1ÿ5z·™”aÖià¶u³maÜá¿6|séÛĘ: ɱ`E˜ dÙ„ï·$é€4ª@ùb`ùФ+a¸k‘Íï ¿ Ô/ÅÔæäü¯¤§†¿1Å£(Úf–“i_ãÄY³ÜìaÞ᜹µ‡Có´Ë—ï~Ë wŸtT/×[c·$AÄ5:–ôÛ[òY%—Z¯¡ñv;’ûÎp/†ß"I-8cs( ö#Ï¥O¯œg…ŸM%Iߦùt‹~u)í§ÇiYŠÍ³Íè¼U:OXñ5œMK½G=òÂÿ’MÑ¥RùÚz¬.<CÚ¿TÈ=»Tãù{»‡k`ÓËÅè ÏB‹¸ò²ú ÊÃýÅGû·(# À^$.I<_ƒJ/Ɖ‡sÖW^âÙ/òNÙDÔÍ@þ˜ÜQ›Ê|F¿-—X öœÁ)A½—¬CªWÈŒ5ðG߸ß`Þª”m„†AÓŽÁ¶æÒ(˜„»¯¢ëÑÅUÔÀª±dÏDÙðÄ_s˜òÖ³Áâ®ÒÂI;sT÷LA˜4áŸDÁMë¹BQ€…&·^é|FÀàvÁcPNý¥Qæ6ìÈŠr?›p"©ïþ–yDÊCòd‘°‡(³Œ2¾ò¥ó ôå4;GDp¢JÍ1m–ƒOˆ‘—ˆ2‰ƒ’¸Ñó²Ç¦ó ¹oäl1=hÓ0+ïoñŸ<"l-"ˆ0^Á œ!šÆ%ª¹åñpŸEÏwìv¦2ãÇê Ò<糎J…-æ#Ѹ{’Ém¢ÌÒ|ž\Å.hAs›½{[ÓŸ_>Öibç·iÊÍ£ÏÅe6ìæX¦›—C¸ë'?»?l¯MmFÅ(©*W³‹Œ3GÜx k°^PÒZ|¥ŽÞÀnjØEÄy¼™/÷`ã|‘M¢]áý5Ü‹blf!Ðo?>k’Íb˜N)©³…“qþy1'ú ä‚)Š xÝÍf9ïW¢â>@Ê©Y÷©(±šîÌ>½Àn°‰nˆ/ƒyo¾ù¾²up²u³ÚͪTàCF5§3Œ§ $ž}W•óÑ>žx×Hͳ{¬îˆ¨ü‡méªåU{”¿EU’©êðmjF¾A$(]¯Š‹s†|ðˆô0°UÙWA.‘wþeé"—@£“ûÒŒX§³¢í:ë hó|”qL ÍIyÇFß{/ÖœbÎ0šÝÜÅé êõvL[“Ú0í3e‘Ûf½›ˆ*«e§‰›WKDzKNÔ_¬"¬šïìo^1UPႤlT¨DµbIé£e¯*'ïÝmߨ½@›ék±í0ù+gç†NG:þXn,ª]¯vß^ªwý,´U‹Â<ƒÝ QÚïYЯ—P¬z–½Z&é>ím‡Gçºdà كÆq¿ÎZú+XÈ_V Këù¾)ßœR&uÀ¥$bôGlñoúˆ{ö\T´./D{€†/ÑQçL†ÑsÉæîe ÚT-‹]Ñ®“µ¼œjneÝÅ«=FÆ+”®×ƒžœ/™ù“—kÊÞzàzî–Lî5[z¾Àúeu /Ìq#}“MFè–—½uªÖt6Ïο^tÚ·þ×Iºù_Û›¼þúö­À&õaþ0SeÛï¸a¡6ÚÐ0eüÙ8.Üþ-YŸmVwþ`» ôʧ¸LŒ¾žO‡ ‡Ë s`°kTÁ”gY‚ÞIbŽk @ïQ7¦Bm# vª»­ZO¨'qzõ“œì{ìÏe._ð@ú-7åü¨qÖÉ€'þøåÀp&™Àí `®Æ’'j¥3WWŸG¹;¾ƒ8¯»ù‚®8Û¥¹p­w$ú"•!žWT:"N ¸¶dBÕ ¡X7¼FÊI§ˆxþŒò9©*|+$¬S;½Ï|n¦Ð Tr󾦄¦Lp±¯È3“©ÞòtÍWtBWÅ+7Ó5†&½Ñz—ÐuS©ínêcïrºæ[mt“mW7Š×dÆ7W³‰»SÇã ƒkž.ØÒHºåt H)ÕÆWûx³\†}E\uQ߉ ÿÖñè¨^ÞWx¶¸šñ1Å´f6øÒÀhö³Ïy#U¯ìuÍ·rX9ð:&~â#:¬P3œ2¢æAî)ÂÖ‰/Ôp‰xÞÍš_UT½önu¥g†K § IinòöitÝr›ƒs¢‰ÔbwÁdÓÝ(7ʈ•£¬#£°=çâÍÌ ýÊ(‘xw™.ÚìNqõ²Ùl¢J EÍûqv†&*#†—“lÄ‹ )ØJ0ÂIO€éÏœëŸö›ÃÎÕh›¡˜R–S|gk"׺p7¯”B»Á¢0ûfûu/Ño`ÃñŸÈÑÒ*ç7ÿ)œü‡Ø&=‚ãy³˜'X Rýv`Õ:ʶ‹–vd_¹µ—Yâ l†L¯!OMõÚh®E¤ay¾vøÈêd€ÔÖaõ ý í7¡ï›mÞã POÈg½qŒAió º´r˜Ò ËŠv¹–F œ.óñˆŽ—F [úOn/ )ÎÇiZw=È7 o²ó]‡5Mï"ŒTL2— óE)• ‡¢ðž áQ…}qõ yuø·£ÇƒŸ_<><>züaÝrx’~*ݦ ·J¥Ûúø¢Ãz^UZ”éêܪŽpÅéfãåÒUéïT:Êw¼!äŽJpÿ…骰’ÐúÐo¯øü;*^“5U"B^’”é MŠ$þáױБøÚjn&ó-À•Ñ…aìJh]cœ.E3çs¨+~~/QžQΛcω®¡ýà9€¢ÕÒáˆV›g£4ÌÈÊaÕ‡Ÿ/è¶ZNžàPæXÇ´{dñ}éÞš*[€×´ 选§eí™4LŸ†¡vÚß ÷R˃|úÖ¨!Ce¾ˆ‚Bm—"”÷åIxüTI›J)×°ðÝAâ>7¯J¥ÌýŽ6‘à…å´¬ º~®¨*VÕ—ü>ÎŒ?™ýÑ"ˆ§~ Fªó±¿pjg„>`²¨¸ß·—ÕÌÒ«zÉwu7OúÂ#pì]³·µßf!D>+‡†q!h¹ä_.a9âVϸáæÿý¶Áê))P!`*Ö1·L—ª×JHH”»ŽM’»NÛÜ„Å]+–‘¥'}óåýÙC£‘"Ø~b¨'¤s€ÝÙ·½n¡»ÈÕ6 £X6-àÕ98+àm;D<²ûŸ\[úàòsŒ+À]}[- ¹ u`.ÐkhΘ«×ùí5úЉálgYü»—A—T¼úänæsb¸¿e¦È©$ÕÉÿJå¥|,—ÓQ1'@W‹»âuÊy9ׯ†ͨg[ï¹ã{ÛÏ÷b^ œ¤ïùeúФvoYSš¬4…†®´N®8¬4SÞL»¥ÎUõ[§ÝÂIX™ˆ{]ý–¶î)èC5Ü_;róãüÔç[ÌÆýÙÅì#´Ñÿ»½·cÞíls÷Þݽ;{ÛÿíÎîÞïñ¿Ÿã'’ÿ'žò¿qÔïÎÖî^²»³oþw÷nmÔ¯÷=ëáÇp)„G¡RA{ˆäQãÒ‡6¦Ê¤öáù¦Yô`µÞG-¤S¦é¿ F"f¶*(Ïkw?yš6!Îêo”ý‘§Lonóóqz._Ïò¡Yè¦=jérqQÌ͹€êÖà"!âÌÊ*òsj4¸ÑrÌš¿h¤õ2ñºÑZ‡£^oq6ó([ û<®Ÿa̰×w¾¶ †žØ‘DšŠªL-:ï'QØ&æw›¿”ô$.²ù¤¤I_Èà(î"}WL‹ ¸úšM•†\m=ƒõgØ—ê”·¤ÆÌª™UÊŠ!•P½ðþ9^ WX–#ý°4§\m#ã19,fpGW¥h•陿Ùx˜ƒéœ÷³>æƒ6zÖ ••ÓqqNig—læcë¾ë’8-æE<.›enˆ>y”@3:Ͱm„¸Ô0„@Û¼B.¥Ø™eô|@AJ=ÿ•ÎÓýä9Ò»L²)ÙÊÞfÓ¬×V1µ0™²ø©âˆ0‡îªù”'ˆÖ0°ø‘Jý0šäA–Ð.¤PžgDzÐÂAÜÖÙ4Ϲ‡§ùè ùöa+Á y*GÅØ– cÎüU›Y¨}¼7Ÿ¹’·˜tQlA¥KæLSY:ß<… ÕÖà ¯W²™~k_Pí0QÝ}xœ$÷/vÞO“ ³>hUÆ Žu€ éæíÃèãû[©ù¿©žÛmàì;cšZ2™&Ù"ma_­d~š·€D ߨ÷AãÎ:_¸Šý¸¶pTí¨®á+ÜÿJÚl @[æ«°)"0½ ÆÌk­ÅMê*eå†_ë2¸éâP¨À¯­ãþþSÿSþCQõáàOXuþÛ»³³{òoß3Åööváü·÷;þÓçù‰œÿìÄã pçÏýÝþ.wv¶v¶“íý;;ûÛ÷ÖRâ?OGâºduˆ*0Çó~^&çˆÆÂª4šÆÎ—\­|DìiR0ch(3Ôçà ¨¸ ›ƒ’Óåb'€3e*eUtS™íJ>©$Ü*©Ö/þ[%Z{OÉÈñ¯6^_¨ìó×r$V7¢˜°‡Î+(ý#vñv½]\úWò·$;É¿þ•à! #÷AÒdÉ÷AÔ”Ðq±[ÿgb}rf#ï@“ÉÞͲyžM‡ }Ä yÂ>À.J§dègàƒÚƒáƒ6a<Ûé¡ZýÍN&}ÐÙ)ñ0ELXÔS]mhKA»Ð¡2á>(¨|Ó°j¬Ÿ¼¤^ `#8ÝI)hæ.¥|rrf+<VÇ ø×ÕU4@é|.|ïY¦5Ý=Û¶ê PÜq“²€#Wn‘é´Ô)é¬\cÚ^3ãï4ålóÉá87Ï]`¨¥/@E¡;rE\. 81(¬¨µ*›"f`i··Tñ„Q‚U|•íÍÏUé‡NK['§oÇÔM«°5ß2M>,H…Ø[H‡©ðÇ 8ÒV¼”ÙÖP !чx]5€ÃÒ:¡ÊâZ ½Âs‡®åéÄG£k—wzÉn/¹ÓKîö’½^r¯—|ÓKþÔKþLÍ;´LÍwVÇ.‹OÀ$}Ä0Ó•ÒÌ­‹m°´QÅÓÊ©†ÁÒ¡vÀÈ77˜€§ø%ž†çùd"‹o=Úû­ÊmÇéî1ò¶_šcÃ$÷òÌšž_Âo€¤šÁÉØ•¸kKÜ­)qÏ–¸WSâO¶ÄŸjJìlÛ"øk´ŒëìN]ow\wwêú»ã:¼S×ã×åº>ïnkâÅÊ40n‹âwB†uuXXd´¤0§x9©€múÉc\a$ºIX›íå>ÝçÃÁ0‡Á´Œi7‹³3pÃDS¼B\:mn‰üdj›MµØíˆÛ’ŠÅ"¼äÀHîɽåÕƒþÇOO“3ÈîÌêã‚7y± AÈ?¹ *î'ÏŠE¦@½dÌH {¢¼°¸u™í‘üìŽ Û3–CÍÞ‘EQî·xù+7 J³œ¡c]ÃòŸ§£¼¨ 0AŸ#M®].-÷’¦…H¤¬ÂÐ¥/H¤Qšþ¡cÿŸÌTm¬ Û4 …¾ÕáÖ|ÏNØFQ:Ô}»wo7"¢„S…öШÓûÛdC¬ÐµÜ饷[¢Ô9 íÛ[}¥FÁ&£Ô¢ÆþógÖoˆºsR`hØ^£§NR dÍ]°Á·:Ž×ý4ÑBÂÆœ§·EN| ‘ÒÌxßFIÅ}ê*a+&£Ô{oôêµ)H§CÀªñØéGÓâ˜SÏ]æ3ë{gëÌÇzžÌ„â[€ðý7æºöºî³…np¢Õ…$lNž’Š­·¨ —õÂ!Mèô ¼HÊQšz£ÚIªßJ9Sûù¡Z¦ÒÞ#q±Ó 6Pkm^ÕߟmÁÏÛãí°ÇŽ£‰¾T¬¥ã³P»çw·BýQ¶ÎPc)ºý¼cѯL„Â9ièý1?<Ï7d´WAýlîȇ³Ø—Ù–2°ÆÊñÊP•1,P¤Œ_Yµ͵«ª²Z¸€W_ÈM¢!è“ép¼W‡y:-Ç©»ç.ÁÒu™±ñó‡9›"\›KÙ̉*{iNÆ®YNÑIÛaC}|¤EŒŸgxˆ‚+q¯…^õK™çË5"_h«Žô-ô÷ø†BE{>ÇÔ`jذ@<¼‰Ï µ³!P3ò8ŒtzÓæ¼J–5‡fxçÅüª¶×¶@ØsÛ¾ °2Ý}šNÏ—Ë „–Nvs©R†bTÇ2.ŒA—x)4€jgèyÖB#Ý™fK3… p&_«/jÈ‹ZjØjØ:-9,l Õ®eÛ÷¨ãÍj»MbÎZ¦Ë U蘌#í—s,Ð…ƒœ ¸–0þR=âëñ ¹í9“Zü"—@Ô1xuôêÕ“çϰM{PS†’ð™PÉIËäÁTv ÊÔ†]b`2–¡É)/ó¶Q¾6N!PDìÛC‘Ð3t™˜u·Èñ^¼S2‰Ýâ QôäfttF(Ck4zØK[y´¯ØÊÈð)†lãã^²kC=…¤˜1¡=íC -ÅÔš¿¿µ]¹SÓ‘7ÞðìÒs¼Mãy´S"j+ÚT‹ öùÒ¥pû¦Ì“gÏŽ^&ÿãù“gɃii@QÜÆógÉ´?Åï¹2ø£ÕØcqûÑMû:»Èêj’µQ”-22%¹°¡Dï5§ÓMý (m R1×n8µÉá³Ç L/²Ø#¼ÂYPà[ø«‘@jz¿A„‚é =@?ú/¶+³à 2¡^ÍaZû,0Ì ¿\¹Jü\Ð5?Cy¿ïÉ…Fs;—$luã×€â 7Àh¨pDYŸë$qdÕci/D“»œ×¼4ÊŽ/ë„ÃVd\—d"Õ¾j…ìŸE:"×XtÓÅ#Øãï3ýÄ¨Ì QZgféÜÁ&5mr‰ŒoP Pí0mµUÌ{ð5ýB=•(}@nktÑ|R ‡ù2]¾o͆­VïýŒ…äõ7à {ûmy´Jã •y‚{ÝοþºÍg¹0Kðr˜§zIiƆ`˜Óá_’ ‘(¯/Rßet"ûøÔ>VáUi[m™n´^Côîi[EQvèq£a|ö>WÃlÅ(zšÍºÞÊáS3˜PiŠ¡²|¡A±N3Ìþƒ=C•J ƒø}Cœ§!7|i H_€<â˜ÐRÁ»¿Vsb6òa5@TÝEzê§´`Ù»ré¬Ú±ªY¬¹î[À!Åo6í‘8&çOÚtC@# 19cWóÞ¥|‡7hµ¡‚³Qf˜¿~ ñt]iðQu%Þ7°]_§gh¤4Ÿt»uó©*á3ש£í5´ßÁ§£Ñàæ¬8ÉËá4ÚÿÎàQµýì•!d&…õÔ«67z…™å2/–3Š¢Ð×;4n Ò>螈­Ö!§ù}e<ÏgìÍ&UÓzæÏ!ýϼº[©ýWרÄ7CaÉkQ‹V£r ¿.Åʵ©µ[7_íÝŽ×8^Jº[Ö·â+£›‰ÁðœüL¡ê'"ØÔ.¨{2ÎÁÉ):%nS!Ð%ô,‚ò, ë»?²£›Ñ’][ÐNíÀ@W¿?Z<„Í–œ®Ì–ËÎL°ïÒ3Öñ©)ÜFåÿ¤É”ɸ’D"7+ZU-Yì!ÄçÙ»`ù«dÁ£ËK7 ÕùÓµ²÷²»\»÷þ¶t­ÞoÆ•uØ}ÖS#Êçâ Š–¡­Zž³B–©YùÄ„÷·–c?œ<²ä%œü7I_C\6œÆÖ¸å®=@)óGT&M#žÕn¸ï=•SÎÔ I$^µevp‹Ç] ÂçΓÚ(óÃâɦJ;ãã ˜dÓ!Ä'h™½È³9oÀekš•`{u^¶¦:Aç7]ÁžXÿ5¥´9ú嵯ÙÊ4Tµ'ññIe>UL—V¯•–ÍuôjH(M(’ –É¿ÊÊ!ÓKšˆL.a ÍŠÙjóœm&R)+ RëjSŸg0ô*õ€[àŠ®­Ø“G¢Qv‰¿˜dˆƒ/KqœºMaýP‰aþÚ9ôbØ"Ç5á[†f²CO~zñüåñá³ãäÙóã£}Nô%‹ÁŽœe°€Ì)o8›éØ¿"‘r)rz¹ Ç…~òÈ”ÂèÆD#BV‰•sÅQ#…ŠØ•ÂÆbc#D¢ÕBD »C|"¼Ó|T:šô«_2‚oÁJGåYšK>¬èÈ9Œ§*¶Škò§ ›O&& Õeç6ϳtÇ^Êý‚ÐåÉ)`JeØï ü—M"Ÿd„.@o”jœÎÁŒ€žwT™ð“øãói€e‚‹«l}Ô`x}än$«×z‰hðƒpt¬lÀ½·gâʘƒœô X¼¦tá‡çºŠm)weåû¢ ÕÜ¥–£¬ÅEBk°²;Ì^RœîÏvîk¸6û3PúÐõ*Ñ´ "•ñŒpÀAí‰ “çsðµ‘ì¾8L7 Ĺö^²?0³x¸gSœE<¹§Ó?é{=ÆÍÅzÉpú¡qþ6ÒçëGˆvÁ!_‚ù —º«f‘™±`¢$d äQÆþ–ˆ–`Xr f:ö¤òš1ÔwÊóÂ* ˜Úféâ¢#p¹=ËEXW?~§íyÈÓÔãþ„¿Æ’>:Ó I£ßඨ*G>3èPS€u·œ©m1õ`1jVðÞÄTâ bªˆâðpÛÏôÙfBm[¡ÈŒuûJºÊ*Vœ`V¸º$֥ˈ¿&!Æw/•ânoKNfïÚ€U~õÎðà iäß#CY]5lOšT¤h’èˆönQÍIÍ/ŒênD÷iñ43Y„J£[Q.qé£c'é;,ãI׆òX€ÐæðWkÖ0‹NÔnâßÓ«Ñ'¸‡°Øð©ã÷zÒfC3]™x°èšwà.âþ® þrv^PQ xù¸Ä¸÷íôB@xÉ9øÀlõœË®ÊHó*/ò³Ý;pÌföÖY ÒßW >rL0«¢\lªSÂèyÓО¹Þ Q%«¨ãó?n-,¥0%½ GW`Æô1aÇ6岯¿ÖŒð¿®Ê_Ô2.)(ĺ «GŸámȼx ì¥Q¬ï%!àa€<ub u¡L@§!2ü¯X ·4¬ƒê’²»5rüŠº·ª^)QI®(%¢Æ {•^òèÛ4䊞öÎRP®\p5lî{…·•Åk:ä ?)†hÉ„ ³ò²…ÄÁ¡2é6K§CMô‘Y–ðˆá»¼ZLxøaŸ³Ñ>ìÝ ÃG7uå†û$‰1|Gn,ŽÔ\:B© ²·VÚ#Á»1•K ¸|§b‘Xi°<ÑæÌ&+‹á!; ×ðÆI\ Zél\Aäô9}hï¸;-þmzU߶·ä:„ï£wÁmu­”£Ô“Š’Øh§ÙôÎÁ9d®Þ'¿›RÁôøæ%9Z×O7iH¹¡Í2µî@4XÞ/ G¯¼ÃpeÈîkT›Žm¨ò´ÿU/YöQÒ(žS0­Ú 'tqx -Ú#OÞ'Kò"YâÖ¸Äõ·dœÅŸ¿|l>þþ?Mé!£?>zõ–1d?Ý•Î~‹ž>ÿ= ­g™Y ãåïéßÉ냼Å/òΜ}¥­s\ætÊ@§¶3˜~£ÅªÈéʃ%täKï.„SüLˆ•„˜¸–Ö÷Ÿ=;L‰iŽÙgù;ª¡ÑBûÐÖ[.ÏÜ'dyunÎ>§lBV¯ƒ:V§K²SÛì5cªrvk±ÕÙB¯Éw ðˆÛ*Ìûýñ´f¢`ïJ”ÿ¨ûj§3ÐJ²Š÷‰êŇ¥)¤Ùt³X¡¬d†œÌ¬¥](=7KvñBÅ sè3­zÁEIƒ÷&ÝœÍ숮kÑYzáªÉÎÛõ`fR­ÂùÚÞˆylÅ÷BTLz ×BÜ´uSr>¾§æIð­UÊ9>˜.냎T=%ÖP™{¶ßpÞÇ«)R&éüÑX1›¿éxßÐï,»Á=3ẽ‹t½®cÖp'æmÜæ†Âú+p ð`ì¶F¯Bw´ªËBFVø6pž§KÿÀS^CõÔ“±gçå»rdµ=^Ó-I.•kXæ4. i‘…‘ó ÷(Н:IîZûCu©Ä‡@öXA*܆L†Uà¥Á´•¢ÁÁù§ûïp“,\déˆ\\•ßÊæ³àì_ªä`˜ig÷+[u…W¥)°›¥öcïsbîò¯Ø72Ìßê"Nÿ¥Ð«ÔŒ¶Û«ýÏ+bL»‘©uþ=¾Ï( K±µÝÇììTÇ ³T=à)Ž Ú%–~^î¾UßX}ý߈‚{O´^|Ï"NTü­eˆÕ•kÖ«þýZ}ó•ÏÊ 8~Æü&b¸*C]9šgÖúzÑâU1[’ Z2Nnƒ!Œs’"Ë<Á¬ˆ£ö…\TÍ·lÀˆü„Ó´mÆå}¼<°vçTåù¶ž„å,ægy6ê%r™9¾ ùÒ~‹_§jÙÆöƒ ™Æ†®{6%F³]Pw)O g!οáßw~ î|¿Ì)|é²ùp 7øm›œUzA/ñUÜŸ˜Úc Ø¢íž÷B»-7qGcEòßÂsϾs)b5ä6Zì,vÅUD^“°cCÙJ#žKWßzbY¿XxÂæÀ¹˜ %̶•γΗJúƒË´áz#¸üÄó=à‘9c*÷å–NEF ›%ÖÐ]º{PlêU`œÝ®cf¼2A84€³&ÿò3ˆŸa‡m¿{ÂÄâÙï¼°+æˆÚÖ.eÌ:O5EâÀ7çJ×3RøB@UD¾~nx/%Iæ æŠ^ÆqI\ÎÖS×ÅŽÙ:Àpl”Àx±ýŸ›“ÍQòã~¾_&ÏÝE Ü„Ž/Ó«Ò&¿âŠÖ¢’ìIËö•¢F[¶«4¦eКÛ4£mæAêŒ*€‹(层nŸþ &ÍYdÚAt„>$Åë§x\Ä Ë5¢»ÆÓC¯}¬0æ—Ê$_3ãu9þ…(ßP¯ƒ\a9Ä"û:Ö”ûÌšº¸WZõ®ኀD„À%´Í3&bº¨®†êB÷u‹E6)6ð+XcÜ1™¥åjlaoþìùã£Á÷??yúxðâåÑßžýb2Ë;à³"9 bQÌ6)ün¶ÓsekÎGÎ×f“ýž©¢ïÓ2Ñvgúhoàvø>Ï!¸Xxe7 –3A…³˜Ç9{#„óf¤ÌÖ[úgIÿðòoËNéAU ph>šNäÊ€Œð±ƒ*3À®­¸`_#Ûjâ?b/æ ÐÒÃV†ÜC%GçxcØç€G‘K4?ìØä(ê]}ÄüQ½áˆ_¡‘x^»Aɾõf%,Çš×09Ívƒº½[ÌSQa(:ƒÚí½)ò}IŒb8\ÎËü­Õ¨òîAÍ2sw¿í?^f`›ª —j Óèæž»éãUÀbíÄómX‡Ì'ʑΜµÅ ìä²E´,þT)ˆ’*¯U祽àT5éi>Ή€ßQÌUfÕÏ!QšD_qôˆuVB2:Å•íòé@-èËõôRöM]£Ê4,Æãt†ÙÁì­¤ŠÞ}D¯ ÷^ÙmC½ãD6ÔµVaH}+ “ë ³ÚÝŽ%¤Š“Ç=‘ŠQA¥+æ¢!¯xWÖ‘7B]Qu­G¿Þ( Ÿ7óªžÖuö©Y(έ: wõDtÝñJîˆözgކS/‚ìP¤“Û0%CºMÒ†eCÌdR T¢ä~_Âm½‘8Ó\jB2ÀEþ–|úU$gÄuiÑujq2…©4À¥TüZ!×e–€ÀäaDaž•ÕÖ´ÖÂ5¢ßTV…¾Š–1ŠÏLýX9p¼ñøê:®s×áIúŽ3aA©{Û–LËE!1}@OMɶô»†=OŽLpÆþÖûkßbxcßÜiÈ«ó4ÃÛWÜo%¾H§ÅôjR, ;)DyˆŸù'H÷Ž|ÅìŸæ$Þ­§:†y|ªk6ñ©¾»×0îÉö“/ààÖO4 „W˜ÝЬ×À!X“Štö¶²Z¾õŽû7<þuUh‹:ˆ¨†‚Í0¤òIÈGV ï+òB¬MBâ&[(%8ç f7 ý>\Dì55Åó(Ôïwñž»´ +›ÚjèŒØAnÞΡOîÒÐ5n¹‘Ph˜¹q×^á÷ΜíȦK)WS >t ÅžäøÜç5L‡:,n«¬N ŸÉ9ÃgìÚ>þMÅ"›9¨í%@—Üê4eQã|ÏÔðí ÂóÔš½µ"í¨í[x(:—ˆ ˆéEç•F„h<à+#—Ýì«åj…{M„ µä‡Æè±F¼¦xEN˜íâÎö:}$ÈL×cý?ý=!pBC?{ÙÙ5'På‚L¶’Çìžv7¬.;²E3ʺS«XÌ}8smr×Aì*²JEYÄ/5]Umíæ,ºbøz¾ª“•{äOJ;9!‰aFÆh óÕ¿bÓ}¢5O³1`ïsÈﶤ+B±±pÔÖ¥ß(ÕJb™’íâ4;ϧSNõ‡Ls(rN`ó ñ­ô=-SïDT™1òOžC]¦nž³iPCW…p‡ë&…|ÎÄÕà$±﫟po³y~vÕÖõûvT/”:¹‰ôݼœ§³™ƒÚµî¦gîCÒtï]wV(¢êl¨N}n}SETŒÚ›d¢õÞìÆçŠÑ›M½Sú)ɨ¯®t#=—o¾ÝBlO¹œLÒù\ØæGâ ´ÈŽËÍ®Š´çÑIÖ ´W2Hxyqó!pÁ­1§¬ãbß—H_¿îV˜a×2ƒ\¾qè¯[è˜Ý¾2N6ÞÃH=ÔijŒÞ6#q|/K»Q$Ð>£8¢dÑ-ÉM9HEÔVwóâKë†øD? ¾mQœYü ^ýÏŸ^£—€Ô6Íõò-º}]áuŠoµÒ!êS¬dU5Ùí´:ä˜|"¤óöõa±ÎÅ)-ü=<¶Vcõme¾6%Úæ+ÏZn7/ê°Ò[Ÿ*±ð÷–½ù{ bœMz’K\! ”Œ IÅ­S®(lÅl‘gù¼\ôÌ£ajú Ç»²(Å:Òþhê˜hSÆ=+$Í4»ñÏÒ¹Û7\©MÀpW/tÜò¢gº¸íâ!"Æþþ©Üq=}©‹àOF)Û7„D~ùh°­?,Mµ£˜åº"Wš:lnrékôÏË[ÝÁÛ2ç5õ9 l šcÔ‡«Úð¢ÑÒq å0‚ ÏKÉžYØK2É R}t7Âh±'ö‹Ó<ò ‰6«ù[¹?¨Ï$8`?»¡kY¤XЛ"W–j©\,)‰âaH¦ôT¿}@ †zÞça&û±òU¨ªuTs¹pOe ÝÓ‚̓|OjÁ­²súž:‚[Ý!쩤3ö8gÏEZNÛ ßX$¬Þ‡{Á”±6ëq$5µåDÛ!z~:†Œê*Nr²ó1_Py…T9BÀüs_¨|Zþ|tV¹3}Eq9Bõâ{}’c "í}Ø1´Êp؉x5ñ:F”)×âTd”(ðy_J±ý‡ Þ1ë)t% %Ð!°¤ÇÅT‹•ªLM!°nÈû>T5aɵœi´¸·aÈ%OWZÊg}4­LB(ü}ÐGV-ÿñ¦÷äd´Ä›@|/îÚ¸ ³/}%!,÷c9Ô£\çr¯ÊQ^åkª·‘ÝÈóévÇ^.)yLnó߃Å<ŸL U’Âþx?>}uÄ)5z·% “È7†!æÌΗ€ë–|d§÷ßnD¶,±ú8+¬.ÐYÄ4|ÊJ/-,àù;ß¿µ¹‰™671T»ÝóÎÊJB¾¨8“°qËÌ36„ì`ÔI3ÎÎ2ð09ŠÒ±Yal„ᥙSƒÑï/*Õ(Ø#q°É+;¿­Ï”‡+#¾—)àž¢Æg6 ·`…D€›‹U£ 3¤513ã Ÿ0€[ÀEj™×³† ¤¨$C؇š/V×F8 â2O¦ õp\oÊdœ¿a½h¦n€:€£GàÀ€%²w³b%`5—WÓQ>$Ϻûˆà‚6ÿQ¶&ÿY,1ÝynÎóó…àÈäFÇ6Dn}9^8ê}y¾8h%0½”ýç²@Øt¸ÃÊ§Ùæb‰°ö…{óð`¤J¾èßß‚NðÚß¹wí‰!AÒ‹Æ¢(’ÚJ°_u˜†ÕŠŒ bˆH^wÚL„xÏPù>ø §û˜X±—ürxüèÇÇÏÿ2xöüøÉ££ž¢Z=¼ó‚GÃõº¾5ņhüQÈì¦Óyîóu™Û‹vYTTr ɽé™ùJ{«Y»»)»š"…|àƒ*F¨ˆ‘>´ÍMA†›- Ó •Å$#É%˜ÿ.!ß)fc7Ë£ç¬ÂœEª¢!Ð}—µc(£˜Qd¿4Ówj ì öl߸3¡ jûôeT<_I8/—sW:Ý&:§>Êõ?â«£K:yµÈpjjíßµ¨*Ï }Ì=B.’•„}Ó9’aÎŒñSNÉup!j‰íNÜ‘’TAB)´øm6@¸YµÇ’ò(¤̈X‚{dßu\öÎ:Y«Å´òa\SÜF,†X¬Š«ËIâ…ß&››†óÞH´®Ãª“¤RS™íÕPF’Üm²jkGÄ»ƒa{¼[:p›5 lHh}ë9¥E·¾µ’K™¿U.Oà,ò\ «RÇvp-0œŠ‚¾!b¸iœÍëÍÚGEÅQõ×ãä£v˜—8.±ï£—(q1K¨8L øµX}Œ^HÔhLTY¿g©§1L\ù¶“‡ßH´Š}øÞ2ÀTõÈŽ ¥iD¿ mW*uC} ŠB®YqÛ`h¶ÀÍ RªÍÓŽÜb©Ó5L{Çó7¤â޼íõ"Bß›ër´7ò¯;ÉxÍîò:ÿÐîÖ¹ Åz£»kàÔ$ß› ×qW}äZûʪ¥’͇Db&#¼)÷uVwÍZ·Ð³Öh·Z7—Ãw 0íyÞº6Á‚kVìd1¥Æä Ê-'çZÀ´®þ„pK ›¯ö§o&XuÂp0¥åžÉAÙ–0Z~è}ð9g’¸}¬õÒe?—Ä΢¨€‚£Dg´k0ý\ ˜"Ço‰rѸ֚¬ˆmjô1t…>ÓŒoYFßRŸÆÜBËÞ‡òçž™JY`¾0òŒæÁdãA˜¾¸]è›V¨»P0+» Ø×é}vá½MŠãžú¡ìfîc‘ÔÂtºíü°Fñµ‰ƒ‚U¥ÿLÏIx‘RúuD mT@yeƒ 4Ç¡/ììÀÔÚ©÷—O%.bà¦ÖŽß®Ün·b¥QåÙ[Çm–d&-…ùzêb ÉW»Ay_¾Gj *e½0ýØ{(ÿ³+ÅXšâ˜*Wúæô=$Èå³HßÓbrÕöCéUmR®´7ÙUYiSJ¹õ˜è+£®Ðd¢9²6!GËgŠ$­Nw)n´Ó%8Š­7Zê­\?_ÇÌdÇ€ÇØ5–StHM–CGÐkòiÕÐ`ÇjZÁMK´)¿Ú¯$ÂìoW$®qj÷Nìk‹Ìkɯ#2]¶²ÇGOŽæ²-Y†èËÉá³ÇÉ[þ£ò„ÎL,b{qÃ9±e{Ix:#õ«Ib1Ìí¿‡ÀzÙÀÁ° ÅšEòýˆ,.ü¸²îƒÄ”l“ èà”Qˆ¼»VÆ àH“/¶'ÒW¸Oô¤&ÙÌmlÇu~êñ?!üã´± ÿwoçàšîìÜûf÷Û;÷îÝÛùÿósü(àO˜qÄü¼KØ¿Û÷¶¶ÿ”lïíïmïïí1•g%ã}²_ß3óÙ† ò6Çc° ~"¹`¹«!V±Êí¯#å\Oƒ9ŠÍŒ.F)-ƒð¦EUÛpn;zùêÉógÃïõßmlpÒgö[Â+VÀAïóó„jÆË*ì24j†úçÍíÝÍÝ=U}ë^g»µ1›èÎdP-­ „‹±wvïìíýùÞîΟZÿ¦ ç²þŸ<{u|øôirUþsÜ_¼[|Ä6V¬ÿÝ»€ÿ»ýÍîö{w¿ÙùƬÿ½½ßñ¿?Ë ÿVæÁζEßùs²óçý½;û{;ðG‡F#<þñ(ùéêÕÿ|š<><>üþðÕÑÆfíÏÆªÀý |1kÈ4[9FáƒTb´áö"IÇó,o²48ÅÛôl±¹œY‡Þ ô<º(ÊE·/×ïgˆ"ŒI ÜZe/q†BDNœÊ+î;z:£ïↀ)ñø@Výååá³ãd6Ïßæã $Uò3ÃU`vVóT3¬å#X¥ _„ÀÛߨøbf`xOCŽŒàhÇ&ß%qq’°ìPE[Já 6rC˜øÒ &ÇÆÆ!Øôˆ°ì@Òì·ªëýäšÅ‘oР{‰Ù¾ÀÉÚrѰ˜@pö‚X4Í,ž£—æßŸ_æ?ê%tJê1_>¥ýG/9|z|ôÒTñü™G÷þWæÙñsÕÑï/˜º false false 127.0.0.1 8080 true threads that post stories false -1 3 3 1236113809000 1236113809000 true stopthread 300 6 true http /drupal6/ GET true false true false false Cache-Control max-age=0 Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept text/css,*/*;q=0.1 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/ http /drupal6/sites/default/files/css/217c09558a102a72eafbe111b6ac3ac2.css GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept text/css,*/*;q=0.1 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/ http /drupal6/misc/feed.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/ http /drupal6/misc/powered-blue-80x15.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/ http /drupal6/themes/garland/logo.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/ http /drupal6/themes/garland/images/bg-navigation.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/body.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/menu-leaf.gif GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/menu-collapsed.gif GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/bg-content.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/bg-content-right.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css http /drupal6/themes/garland/images/bg-content-left.png GET true false true false false Host 127.0.0.1 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css false name test = true false pass testpass = true false op Log+in = true false form_build_id form-e65a20482915592a68be8ccbdb9fba05 = true false form_id user_login_block = true http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/add GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/add/story GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true title Fantastic Story = true true taxonomy[tags][1] unbelievable = true false changed = true false teaser_include 1 = true true teaser_js A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true true body A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true false form_build_id form-7d25fdb5d0089c638ef2d946e85009ff = true false form_token 5f539d93894b6055bfd79011c0ec4215 = true false form_id story_node_form = true false op Preview = true http utf-8 /drupal6/node/add/story POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true title Fantastic Story = true true taxonomy[tags][1] unbelievable = true false changed = true false teaser_include 1 = true true teaser_js A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true true body A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true false form_build_id form-8a88a95909d46d432e9fe341c3b3328e = true false form_token 5f539d93894b6055bfd79011c0ec4215 = true false form_id story_node_form = true false op Save = true http utf-8 /drupal6/node/add/story POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 10 10 1236125829000 1236125829000 true stopthread 300 2 true http /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_build_id form-b2361253017b019934be93aae0d2fc27 = true false form_id user_login_block = true http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/comment/reply/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject Horrible comment = true true comment This story is sooooo lame, mwa-ha-ha-ha! Quit your job and get a life. Comments rule! = true false form_build_id form-def6cef1c57faaf54c344b6c8a6070dd = true false form_token 2ba1e45bc76391d74b59d94db2c444df = true false form_id comment_form = true false op Preview = true http utf-8 /drupal6/comment/reply/3 POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject Horrible comment = true true comment This story is sooooo lame, mwa-ha-ha-ha! Quit your job and get a life. Comments rule! = true false form_build_id form-1c9ec32e3cd967c8fd838ee71c3368da = true false form_token 2ba1e45bc76391d74b59d94db2c444df = true false form_id comment_form = true false op Save = true http utf-8 /drupal6/comment/reply/3 POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 20 20 1236126574000 1236126574000 true stopthread 300 1 true http /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_build_id form-08da3427c3411442e541fb4a605cab8a = true false form_id user_login_block = true http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/1 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/2 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/user/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/user/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true percona-galera-3-3.8-3390/tests/test_drupal/drupal6.sql.gz000066400000000000000000002020341244131713600232100ustar00rootroot00000000000000‹.Z¼Idrupal6.sqlì½ysÛH’7üÿ| ìÎ3ìçÕÁ[”Ü31jÛ=í]Ûíõ1»á6H‚"Ú Á@©5þîoeÖ Tá ÁKâm(Ô‘•ù«¬¬¬Ì?\ü¿ë4Èÿ8¯>þòÁyuóùæÇ›O¯7?9¯ÿçͧϟœ_ÇÑrá½_ÿßÅ‹?üáåÇ×7Ÿ_Ëräóv«ÝlÁïùÌ>úò3[hB ¯ºùòö³óòç›7/?¿þè|zýÙ ÜÄŸ7¬ý ©Q|øâØ%ÒÐ[­?îhäÅ1y _ÿ5vï¼ñ`FïÍþçÏÎ_ÿ:šº‘;J¼h{ {I?1½!Ÿ,“Iÿm”7å<ûƒC~øã_ž…‚37þö«sçFÐÒ³V·«ç489Á¢ÉÃÂ+Y4NÜdIúB¨õ½è˜Š6°ì‡oÞÝ|ü_ç?_ÿ¯ó ûýüÏ×ïÿöæýë?¿™ÏÃW?j“A¨òg:üú¤)mŸžÄçÛšÚ–2A´l˜èÞnÙÉ>rƒ`èŽÊNè‚ô}æ‘ΓNáü6ñ~ODa,1öâQä/ ã%{»¥é|óþÓëŸ7ï?ÿ¢Pöï7o¿¼þä<;…³)7XÎËaàÇÓ-srÊ_É¿L…Èÿ}áOþÅóÓg'ópì fî7o'þèÛƒüÞ°ÌÈÿ½#ÏE'}™ªr9/¬4[D«–¿–/¢p&ž¹ÊÌKòè3Z_:“($s°po=¥Ò4½´J ÄüÀH •Êj`VÍuèoÈÿ}"R_“iË›á5ù¿Þ,d5ÁÈfÆá"Us.¿ˆn.cÂÈà }ø Y³ oÉÿýèÎ7w<Ž¢;áÄ-£D?MUæT®¿‡êáqªÊ€€ o$±½ôJÖxüíßνqÞ’¶Ûe™Lgîb;´bm­H§_—F!½ú@+s²LHüo¶úö5eŽ—AɆ™‚Ç_Þ¿ù¯/¯ñ©Òú3ù÷çsè&£éVf“¶DçrXy.“ð›§,Ñ=Eá¢ïý™G”²Ù";ãøžµÎµ€ìì ùìà´°æž±?²¢wñÏ­ ΠÙv48ÖTzŽŠ4ì”DôŒÊð Ó·‚Ä-Òõ¸Z8õf%«­ Žÿzïù·Ó¤\ÙÈ»Õ4ü>Œ–qÎÊÕ›L£0I€heJßù±?ô?y(W{ FFÛMü¤ìDÜÑ´¨{MÈ M —ÌÆ(K8¡§œaN7H©#ÚE¢dÓzÊçá”Ož¨£P0›Úµq.%\o ¥„ÐÿäÖw>>9mž6NOoB4ñþï j'gM¢Þ´Ä'ͲŸ´OOâ‡8ñfÙvš¤à$$š`dø®£î´YAõ ø {zBJ/ÉïEäÏÜèá,ðçßâ‚/±­žø4öFá|\éãK¡„õ‹÷ [%u%J·‹+ÏGâAÞ6ñ˜5HQ9l‹–BZîқ蔰žbRd±ºgôáµ–ð÷mM¶´ªÖ2 ǺÒñ«?Ÿ„%UÍIÍ\ˆñÌ h·WÖ,aDaÚò3úï'‹.%Û˜,¶hádJØŸ˜Nâ‚ÀÀ$yâ#ï÷…y%6£Ès¯Ì6cê¹c4D N xä»ÿOø¼ú41ä~ÆÿÚ¼QŠ[˜¤bòsæ u¯;½ëÅ×½ë¯ÿNìë¿¿p¯/áY³I*F7ò†l‘‡Ÿ’0òb?pH?ˆæqŸ:ñr4uÜØ¡€CPÛ‘ê(wNë!ÕL|/Ó›mh± ½ðÇøtȰ8ŠOè<àÏ>ù9g¾ àÁðºùÂÒçÖyø.Îz×Η¹ÿ¥Çðæté;m€B(ö ›éÁ%ùÁØTô(ð`LÉOÿº×±uë{5q—A‚6ÈoüÃØßf *þ<õÚjºŸú„¼DÝbÝ#ÿÖŸŽŽ_8}ïw²£ ¼Sç+.Ÿ_Oð)”ÿïiøõ$v~™®e_Ÿâì|=Á¬¨;p¨bLËÄŒ,]ì"YPV£J»U–*@‹†,m¨˜ÍÜ›WØeJ‰{?™ú„ß¹”n£rºÛÉì\²¹Ä¾¥ˆ Kf.¹l8îb<(ìHµjË@\Ù¥Aï©ÝxAkˆ ÑÎAudÛÓ}j¤óæî0 ‹(íÓ9Q¦ 𰇧Nƒüû1þz.@7;@ëR €ö…³ E)…ÖôÁ޹¥M¹…p CQÖÛ4Çø10Ò{*¹;$t³¬òSàÞ‚¥ÞŸý'gÞ£Y7vf.Á—pžY]‰a*à£/X~äΡŸì“SØí—¹3|pXOOá2bδãÇÞüÔi‘R?ãß¶’1éÒœ±hA‚nðwI»fÛD»û©GH¨w Uò*¢G ÷¦d÷Þ0öIÙ$r'Œ1%lÎÄ“ÉgHëa šÀ’rBö“…Èo˜7¶29D0ÐrÂæ¼•#ès²޼E―‚@>£ÄŠP^Ý¢¬ÇÁ? Ì7ö í1œLÎ`ù”„z.׬À¢¶à¢GVTZš(û’0?Qçb.%D¡MQB¼@épý9°¬â☠øÂM¦H(@ÐQ°{„6ð¯¦KˆÑž’±.U^Ï ‚& ëÞ'lB0‰ ž5D¿yžóãÛ_^þçàåÍËŸ_þ°4Q1€éɺG'ëÁdVgdëâèú ‹Àþ6Þ|%ÿÎÎÌaÎ7âYóú_‘äƒ]R’”ŒyQZ,™‰ýVÕ()ùµƒÝz¡kËÐKœÖ±÷»§T3rÊY!¯~¡Òú5M…h×/Rz–ÝIwì{zoC›¢º?g8ÌB*¶‚@¤–x@­[Øéžu‡Ø…òÈô-õ.˜ùq §©Ro'H7&sHP˜Æá•g6‡m¾CU6gúÀƬˆõ™ÚÎvH1Ûo±=Æ)Ý“ý‹äûyfç!7L•{jß0™wätOGc¸þhî6a½–Øæ;Ûç4:q“šè[Ò¶X‡é65ƉÇö •EÊißÏI‡råZÈfJ›)I¤²#‡hL•f°Ï*I’Ir{ ©²@Ú@Rfj)zUOÎfîØS6ê©é¤-*ÙI5XTÖ˜×V7͈‚φliû`iµô(_Yʨ”tx·yªÁ5ßýq*Õc5Õ¥Ùêפ»ôE•WÊ¾Ž®o%t00l´SVÓ×Í#M8s0±?$í™`úGÊêöOX üÏŸß½ÕDÙ¸îj³"PyZq…//¬ªTò6PSðòdµÕ@5›l B¥„c ìb@ ÉF%òÜñÙ–ú0)>u|²kM¨êHö®²èÁŽp¤.üNà€êö¸³žºó[E§—æXT)NòÐ…ê h åþëÃሮ3› ¥Ç!eÄ ¥k'ˆÍæJµ?js­&s­n·¢Ì11‡C‰7f¬…/n]ƒÀC¯/Zø¦ »lèo‡rÓ°2X1Ƥæÿ‚ž]^aÏõ~w„ã ×Ùq7V˜7JYÂA„âd¯¼ Æmáöw œß¹wçE†¡¬°»gK(;U)E¯¹Ê(î ÷²úkí3;ߑʥY‘Å>K£øÏŸ?pاÀC¼"a›ÇXdŒca”¼Uaä)Stõ:HÎÌŽŒØZG­„¼NçYó97%=kèê¤1´Æƒ®vÓº´›ò¨ :°(­ì¯®;4›üøã_œTßÏÉÈk¹IÛd~uȃ3çͬMP°qš)=b%¡„;'PGöÓ€$¬”2Ðù*ö‹ÿǘïçó2c”]\nc.MÞGÜc}?'­’ò-“iJ0£_Î(¸ ŠŠ g½áüaª TÍ=‹—ÃßÈŠºš–]›O5ÌÉ^²ç–)(¶àVÜ”\¦ºjõ¹Ä¡i' ®v¹5i±³(Æ ÷CÏèë-è&b9ß8÷¯X‡ I‘n¢2¬Ê•¨ñ.é¬7ö—ú€Ò8’SЊݔ2b>tíÕd©áp¤ÇGÏ®vˆ“XPU])¶x ò—¡»°÷¤?â‘r:»ûÍ¥ÄMó–’|DLaeá¼Õ÷v×èê;Çs!âD ½rùŽAé)ˆË"pGžƒ® ´£ŠíAxuKföݰx“tRp#åEμb±&À#ǧCA³,Áý ¼½Ec;‘+Ð/ïý_âÞ’# *ôŠåB/˜EeÔ3×Vµq-°ZˆKvÔÞtC\iB³cºÏ§@>~±ºÑÝ3ÄÜhKo_ÌÈNÁ <—žùTwG‰zNñõ„Ÿ¢AÕÉ2š£ \Ãÿ™g&µ²µR—-+¥ 'x|³Ä2l/„ÙÂdÃ]ðÍ‚ªj%æêvBY´-Šx¾ÞE×;R›”Ôvä;[ñÊ¿* ýwT´aéÿs}vR,¿È‚*©MˆoeàÊ`,ÜI£Þý×§þbÿ¾\Œén÷žfÃs—OÂ\µmh5ïܹæ¢(ã`ýN4 Ü™yç‰L[@0P­·§ä\qÜJÙJØê‚JPcAµ¦Œ;ëA]}ŽgùôHEn½ÒꪢÚH·¶.õù$áŠ#†—þ1Ä˱B»³ÂœÑ)ši³—Ø6¶X}~‚`øæU=ÃZŠÓtâ…ËyYϺšLá%a⤒ÙÜ”&DÔ•?™ŸçΡXj¨‹¥¨*_~ ‡x¹X\€¼lѾ‡K‹ãð¶‹;èÚ‹'(½Â‡èXT“‡^r¼;~^•5#‰ÓÊû ˜‘ ¨ÉŒÄÇH{¦[“¶!^]Îvª#TtU0f$‘O´UnÍÀž* (ëÕ*ûê^=Ûjz^O…ž“YwgÆè!£žÁR §ãÿYê_†6¯ ‘y)%ìk íë6]tàÀûIï<³‡/Ü8VwɳçÎd9)gšW”Ê>ˆ@¼¥^SË×'i w£ÈEÏSÑ*3`pì9s£š¬‹Ö»ƒì£èÝ‘™?åÙ.¹wèàw^Àåæ…Ái"S÷à?çE·Þ|ôðfúÒyöÊ.oŸK¹‚«ƒ«ÉUõc=lAñ·¤ÐÅ;ß»Çñ] 8÷©£S& Eîõ]›ï&Úá¿||Ë[e®C†>@—#oBà*Z•j³öµdŸ±GÈ÷<ûg™ì ýÌúRaØ®¹—Ѭ't Gø$ßÅISîs$mÓ¼'ØS‹ÿÒx„·YÅ'¥Ö°V©®èžØeG×sfî‚  ýÔyÎ Dõ!c%aôœža.–Ôšàõñ™æ7ò<Ÿ9©_êdNÒn–IxæÏG‘* È~}L1¨n’µº?…‘G– `”k'Ï„ªŸC±nƒ¥&¦KΞ]ks-Oó¸äbN»_òjÚ6.- Y˜lõ€‡©ÿÎ#7£´æ tzÀ>öç#þ;¿.…K×Ó‹R„âú(?•G«I9GëIÚÑZ“¤=­; (NÔ­l›mC›)0í |Ì¢©Ž@”ŽxÂEökþæñ¨Å<4¼¼æ>*·Q¸\àMB1yÊÅÜŒ3žÙi4duî,;iXÕïs* –:%ÙZ‰KÁ{EÑP)oZ¨.I_ùÝõ}ñoÐ*ãžÅÄXLðÜ•;Ðô “/$Åοà‘t¼ÞÀ½•Uö,P‡õz› pP ýƒÝ~ã?éí7~‰žµœŒeÜrjîÅ.t›ˆFÄÇ—õ\œcGew… 8èâ‘Ñ‘aypŸ Ã÷sR‡CV_ø¥ôºÄ¶ê9ƒñü,Ÿª´ÓðÅ÷ó„xi‡ÂFnãwç·K~D–Ómá‰È? dæ®Ùõæ ]7 ˜}ùþÌch=%Úü½û@ æ¬íÂóùáõo˸'‚·ˆPÐ7®?gΉÍ+ƒÉMÈáý<–£{áàBI‰æŸîÇò$€ž®³qû¦®¦ò¥<à †ñcHvÓî<¥œ¢Z=Eç+8R.½Ï0ÜÝÁT¹ã%Ù°»dwéY%ãFTÒ¶;‚Sú¶P²q›Ò®éµÆ¢>v/ËöqŽ7ÙÑΓ€ìl j^½ýMß$°óÆ ýšß!ÂíwÞÓ ‚ѯ™ù‚úrÃöØÐ€5ðóâ>ò,­>–¯ `¨·–áq¶…$»©…tjdÒƒÚЧº‰Ö®‚\µQ % k¸Œ¦DÁ,1`%è™Ãš¡Õ!w¶š‡¢’FC©¿(ô@J¢AõÖ˜v«‚©§`;Ç@,ôHÃO DçFqm£Â*æ…*Ñ•Xæ"wÔåî'ùüæ²XôhW½,Ý V`V¸ Åá2±¼ddÙ½ñ`j›Sžðì™u½P¬¨#—a­S(A=„zyñ‚{<Ò”3ª@‹R¢_\ñ/xÎe¹n© IŒ3DÛá>¤4 >å·mô—!™XAuD86b@ ªƒº&«liQ€˜Þ5*¯´ª›êç;c-¡j«ä)þTÕÈ4[È’wXOݧ@ *ËÛÚÎQ}•þAÝiݹáW*8‘¶¨l˙ڢ*ox HO½¨˜š hç ߃ñ˜ „‰ƒÙÅ-:,n~¦ TLñÚÁž®S€WPA™ËÒ)“[´²Ž½ÀKD<±QΦ·—Þóæls¸:§^T4!JéŠãN&Þ()ïk€!Tu[ ù|GF©øæ•„ê"êRzërgø(¼ÇûX‘ç8¶…R/ÜìPñ(zTÈF\‡¥ý×b~fG(d9w^ÃForЀ[ø7Ä»¤Á=ÈpÁ‚OÃúM¼‰-𢱣àoÉ­öó‰Å…Í?¸#0ç>]ÈpÈÌõϾYß¼ë%_èèÀ©HocèpÛu¯†N!¬`èE;åRCg`¹ãÁÆ)“ Mµ‰„Ò©…ÃE•%̰héÚ\QLsN.)„(W¤@¿¦ËEA¨±&WÚZŽÀ'˜&ªé¤xÒìx½“í&ëŸÍÙ'‡IÚˆ]ÃÈ÷&ªOÑ TÄÖ´ò /§^P„¬xbñ3)§ fZqØ5Yv?,â)ު傴Ù1€xPÊ›F¼€3‹ˆÄ´a–x0 6•5ÏÈÒäÚ× p‰¶\„m\ˆ±°rÜÇÝÁ•îsã(Z“x§-vŸÍ“PÓ &W˜&Õ… 5¼íÍWƒ) å¦«W0]²ó»š-\rgþ|pFãt0ûúŠëQgË™bƒ€:b904u³Ð›™Õ ù»9ƒ–ÙLߦWj Ïf÷üXh &“ßµxöÓÍÛO¯Ñ}#2Þù®,øß¨Å‚åÿéj°úŸd¢Ÿ}þøåu-î@Æ\vÀŠG+E´iôËÓFaxå<’¨êðô‚;@¢SS}!žÞüùkÒvs‡’޾¾_bìž>:´[+qÛ™úWJ±ª{œ°FÂ}Û2z2½S$oèºAæ*5(êÏ ñêÑçd‚×Î%ªówEQCÒ9`ˆGªhlå w+JûU¶+é] “3¤€þ4‹\I‹&4 #=iVb󾊖 2?#8øc9>1„£¸UÑüçÎ ÙßÈp(ÞC/'o’á3× ²mŽðv0ÜÿMDÞ?–ä*†liw^.àj ó0Š¡ÆÈ àpn©îYD¼y6vH·<ãnª•¹b—C¾gVcCðq­â¹[5f3Œá|hÍÂ0F'¯¸³«JJq²Õ» ˜”*ËË)Æe¦—ª"߉–b~¦_¤3zÙ£>¸ÅæLvÅ„unÓ¡ùÆWKè){¤FVŒšÍcÃÕJJòú.<£žn4Ùs =åqÃ`eaÉðÐ@ñ¼ò Wuµç[é²›^^ÄO¢ƒõ~÷FË]i˜ÿ.~D4½m:.À…é™'ÂäXêð†ª(­‡Ãâ!qÓƒ­Ùj4(ÈÞ«´!“z;‚QÊèæ\˳’A¼ödP %Í9ã½7¯bvõh~ÆSF² Í&À4PåØvVªUO•6FtÙb8„(B_ `”µ€æwäj~Mž>[D!¸&ðhm P9!3áCÌ<¼SËÔË-HsR´j—α;õN ;K ¿yEfÀ&¨n¸5?qn½¹G#;¸àó'š.ÍÓìß½.&3Ó¡øãSaõæñ2b1›0K®Z+^g~’xê×èw„Nƒ>Ñú¸šñÊÍŠ„ŒÇ<ö»ÖM</wÎCǧ"ó™Èü‘9 Å:>‹„Dv|¾j¦à™o*™ŠÎ _<ƒÊ¨5EOc&!„\®w“ÉòæPÛø¾Gð=‚ï|7ø2œÕÁ—EÖÊUŽ1l¶I9†³Êq¸Ä(છkìÜ{AÿJƒb€ù"Á5O@u^@W/Ð6H }èÏ]»1üÓG˜>Âô¦ L3Dffæ‰Ïc}礇Án€p-AèŽÑ¿)°Ü(ès¬~r…µ×}r¥ÞøÈá;îû™—º‹æ¤G¾Ë³ò”ÒÐgsX¿£hªáà-½Û”ƒ44·p“iA7iRNí¦y.è£Ëq·­0ÜVø?Þý™_Le~%»ýîÍ»×Û¼aÂ;ÊP¬ðÆ”MƒŠH½ -%€ÇܯoWW.lM‹ë#ZÔ4–}º·Á•1‡bÜ<µ;†~‰Øa4^¬’ipƒ’ÑÊ®}2ÌQ~r碫åÕý?%¯óîbzjù*’¨üä,]7íÜô%¯ ?£®n§ôÀO–áås“´üCå=³ƒ‰d ;|O‡¨©ƒ~7Ä„¹)(a|žÜ@ÄY„oKZMW*s¬46ˆ):“¥Ó%qxºc¿Ä•Î+¦’•çŒBiü,ð& ci®Ÿï)Í¡% zް@Å2U9ZÿdýÜy OáT_ÓK[Sò'¤dYœÂYü¯¼¾ qx__dÌÎ55 ðË¿î'x? –c…îl@p?o ‰®²j­”­À¿S¢-ZŽ%5†Ó”2=jV^@®§ì ‰]›%³/ËE&`F“î£ê6Þ?| ¾ME§ö¨ñ%½fGW8<»óÇd:Ð9*Æ-7Ĥ¡+E¯TãЬ%ù¦]ÉýÌ!> :d‹RQEœgüPåëÉœ0ø-ÍKtòœÞYT,â»ê2½Jh¨Y»MuÐèyöæ•ó ¾|Îs»Yô ±’Â-µz3 ³…î MºƒiÛ¢· µ·ÐuNs,áÃ;§¬˜B? ¶úO/ E´( ªÌÅDsÀ’/ý$¶M]Í銠ƒæJ VµPbzZ"tsÍd‰[„þ<±„vÞØ*N! Ìpš¨îÀƉJ›ÁȨô™æŸÆs¶›…ó9¤Q‘³‰ßýKA£ïçø9@ýo„ [k3[f«u%‚Æ“QÂÐAE<á‹ê¤ÅóJiÛ<ÒacÛ;¼¡6ÖBn³kÝ °Œ1>–Qð Ý&à¾2ËÃn×ùÇB&±Ûû¤ÜÏŸß½…ÓnzUØÄ%ŒT©ˆ¨%Âã«–@ íÒñWˆëFçF[¾ÙH¦þx쩺ͷ†þ,ÌDDYC“¹íèfƒG²š/ãsçdRt¡ñj‰ÜIQ20V¦ñKC”Î!=ð¼y|êœÑ¯ñ#ÎÚ§˜¤2G378uxOè‹a#^» *áHT¸x5®N êê#@·oDõøòñ-ü…nCxÌ’plÿ9M’ÅõÅ¥.ï % ¬Ûðk3! ÓEЫ!’èhê㨙®¨ãŠÙ3 B¦Ñ…Ͻå2†òÌ–1o ì£NYÖNñx+C§l°p Ç:ÚãRðSV€ø DÆÌkÒäœÉg”P,ë0£\¶E°·b9u V OOh°áÒÅ _†ºÃÔ~À¹‹¶È©œˆ'Û¶Ò{TLºòC‹;î,$¼E Á3— %žÇ׃coQ—õ™V±Æžès ÖüE5E”ìFè!€Îëü™¨?Ô ‡óN+ ›[;B Þö%œà›M ²xkÌ%B”ÎÜ9Ýx󘊠׎}i@…_4.YR>ÛŠìê-š…R/]k£8¡[Ɖ32B¡ïÐÙ7ç= Î&Ú[çÎâ=Ï‹ VÅ6‹ÒIÿ‹Ód%Ÿ½?k>O—^`iØÍ.þ$žìMÿ‡|C¿Uʆ†ÂÍÑ`9#ע霟;‹+–)9ÅѸ؈mØÝIÜ*Ò²8…cìÆE$þä‘Η‘’uûÝ.«’% ÚŸnwÊ’{.#`¡=éw·,¹'þdºÝ+ÛíØÿ}º}YÐm|þu÷…êþuï…–þõå „üëþ E´ýë«ŠÄØÌ‘ٌ݆bÊœ”;6aF÷n9j$l_ÉH™PÿGÊõjÜÉ)™×œÌÐ#Üeï#?ñD=^0¦÷×YVcæ„.ÃEmVú”à"Û§óH"Vd h‚R[8¤Ø1½Ç‘LuL7X…EÄ¥i=ºIMèÆ¼ÒâÂC LÊóAòǵs#&²FÃhäq_…±áƒóáç0sŸXá›oöî¶J—Ÿ¾ù÷¾"š› sàÆ,Qâ´°óŒlÇ®ßdi6:×F?~¦”Ç¢‘9†yyýŒ™ hñIéL‚0„pÙ6KueˆK‡×Ì]Sl+|%'J‹#Z9g¹!諱4Å€°—Þ]žAf@/cþÄì¨FÐg·^ò¬¾ûŠ—þ †ÛjýXê8ìV} £ÿ?ƒO¯?}zóËûSLwÂO€åµ$ÈÌCÁôFQÇz4:‘Pj¦m€£|,Û¢šîµ3I(ÊÒä €Êð<>xIonº6Rt,aaQêZUl»,Òâ MÙ[’¥rVÌw ¬„ßS¥sWÆ=U È”¢cTðذh[™Á¿,Bá Ëœæ™çfQÛæÍÛ)µ~­Z®¶èJB{c\÷šx¥Ê…÷?ÞÕ|iÙäasš›ÐiÆj¨Ü4áàH6è ¸éÿ9§O¶èW&ñ!_bÔÓ2"…%ÍüÆýKDYP½é¤0-‰Ò™qÛ©Hÿ2 ¼¶EGßð~^˜Ž¾KÅ{¼ýõ„¹ œ;/]H-”?&2¨s9[LéøÝ‚Ô‚,ÀФLè»Ö1ô7ŸFaR|ôßl´òû«uTœ¤Šu›7ÃD›—ˆÅ R¥¼®ygL­ÕüVC@àßX¨a¨–¢‘³a)€ÆnaÛ ÅžAôYÞêÞ.¦‹”ÞCááIyª_D1¢.$1\mgÜ7&õÏÜO\pZÐŽhtu$ÂPE4£*Ö$R%ÓÛ'çp:îkž> ›.¬gàÃD¥;ãÞ‘5ñù ²oâž%.QaÉ2ù^wS€LÃðÛ€ZXï? ºP‚ªÈP×IÈÎH>ªÌ‚?YçÀ„COBDÿê ÷Y™Œƒ¥Ž›"û7Qï1d›¸Ü+¸S%VÎlýù])ÓÔÕXMý“ 6œ³œÑ^(aꩪA|‰Š‰Þ‡u±`¿š„_ üoz–kuJÆ-ˆO 'éqïQ?y*fŒ‰*¸ƒ-ŒéTuÔ†K¼£oxs„ñó)&MƒB 8ýž|ÐÎø¯„ij‹ébŸB8¥ ÙáK¡·ŠÕ'eFRúÅÍGÜ¢§­\Ô ¦q%5Še{’ÅÒîšÍ¦k¤-§:Ó1t¦šêžö6‚f—Q0 æRú]Ú}DtÕ¼að3QñŒ_p¸a HôVÊ2¡¦BšHXÔDåš•-ØÉ¢\¡gIà¶Ž]t|`XØ:›LPëEþŠ£QÁ"Î2÷×Y瀊J}ÑlmÉHÇEïÄ í¯ØìÀ@X·ÑËñ,œœ‘ >è[Üùí’GgÎÑç„{5ÿÀ4 då’÷ßèÝ*úN»[…áêæßæàÇ+Š™­Va@[ܬ‚‘C ñr±#Œ.Ê*X…ZU‰Å!—‰, rÙia…FL-œe­E)YΤ±È= Ò”Ó*kÖTÂ4ðqƒ¥Í"æ©ÝŽ‘‚X(Cø¦|ÒÆD±:`ÈÖC(j ˆÝ¥ÑŸÜ©vô=Ú6ë"¦Ì]8r‡K¢ñ>|?¿“7äcÐÝdDJrŒ•ˆýaƒÉZ56»÷µá 7fc7¹òh»L—e„• ‹6V šdæRíà¹Q/æ…µö£E÷_î•Km¾1¦ÉÃ>‡kòðwÏå(É5ªb\‰Äý=œ‡³‡Ä|æJº¬áN‰é“RÏZ:Ȱʼn| ï;µlU©ße‘¬¯ôËŒe*p‰KÖðL\±)@4$=G4åjœ™ºÇSAÖÁä¶•‚ôÙÛ^i°Û:²tºiôC˜Tú~žH”IIA:Ã6û}yY±ß°Ï£>wŠ›Æ<俚Ý"D4aÓ%Eíy¹XWIJ.äç¹Ù̺êúÌ2Šç^Zléܬ10xPê*ˆÛ6ß7ŒÌ ã¯1>àVø]/ç¹ý½³öwg ‘ÀË›K ®mðS1޼«Âw¦c·;¾ •ˆùVMô´ÚW[E˜xñ8KøŒËÏ×|AW;Æb]Dâ«H[ðC¤F9-ҙ˩Çí Ъê±Ð3„žLu—qs7œÚåwm-+5ßr-ÉÕH­ µ£\æ€ù‰çŒ wózÅfg F¨›áèÄIM‹³®‹±š©ªZ_Ëh› ãV^MbÇþðyü€nU‹`KUé<̈Ÿ‰[¼qëå‰ë—¾+ÝÙ² ½‹ÕÅ=Ùp¶ø†S=¦gD-\ Óò#öI}6Â/¦ –æYª|WN:âդà üþ“´ˆ­g¢¡Ь8ÍfzYß´§ÑQ˜à(½Ö©}`G š Böu·†œõWY3H¦PíÔ ;&$*Ô?“~ÐàDíd7GEôLÏa%k§‚ ágEó¦GüoÝÙ;ëÙŽ ^™Ç*“¦ó îrg‹S¯ÂÒ/žK¬{BîJÆý“DOŒ’^iÜç\™Zäï锿 ±—nóGûFê˜âÞYÆì8Û×à™%P÷a.Ý…sEãK?òÆûF«N–Rx¯i2°W8˘^³ÑÈS‚Ø÷vï€ã&§0‰<Wy{«ç@5A_ñÀMñAvéÒ›ˆið«ÕFHß Ë|ãÖ½nNÓ æyñÞ÷*XéïrÏ ¡³à„ «£)[üº6õ¬:ùm¨äC´” `Š.u•ãB:ãð)®±F#qô€oñˆÈ—¶¿Ÿo¥ÕÒ¤Ô1žjŒÐœy«cål6c»ÈÈFM”ªË°˜„Ÿ1«‘ K|a÷¡•Œcûl:V·mWw-¶a,Wˆ®Ì±âè·®¹¡¶îbâ£wª©Þ«‚Ô¤Õ¢£ø´53Ú åͦÄUO®¤@ž^_^PÏ9½’2+?¢îÙÈ{å®!Ô¹VÚNyd÷ôÃÑhgnúá ²gŽü±îš«ƒÔe]t¡ˆRj?ñ•è-»±¢vmèኮwn·ÞHPò—È¿õçnâÅbDQÜQ³ý\;«#9uÈ‚C·OŦˆ Þø*—iŸE6˃]^³âÉ8x¨@X1vV¼R߸F[:œµúØC¿·ôÊQdl„TV.ìŸX¯rÁ^ë|Ópø_ŽÙlž0v¦Qøƒ]˜Glþšï†£TÙEî|Ógù}cü£]° v´¦Sü^£~vÁþ)ê ‚¸Ûö[2ßRUŒ)Ð{“õl6î èésm{é+’Ó(}êm*õpWÆb6©ÝäŽÍ»Ù“aèã^t†ó= g˜5Œ»@çœgÉïúßÅç`æIžŸÒ­òfæùûì»#ã™°ÑÅa´Ò V–Ø«®ctŠ]+6÷îá¾=Œ, àj*õ«,7BtA$ĉ§aPVƒØÈ0éÑ»ƒTÍDÈë:ª N’EäM¼È›“mð ¸?„ó[U©`é 1ÉŽŒTabŸÑð'ÊdL»É2Úug›*L‰NKÕ+c¨ÞÐ&›¸„›E¼ŸStOY´³fÇMöŒ^ûÒz¶`LC¦aigØ)9Ø7® B¢6ož‚­L?µ nØ‹½²²©Ž% ê'1³³an ¯ÀO6•"€ìÿÁÒáð7o”¨  à³ççá_q«7C,t!iäÞ²šI[ñRÚ« ÏèÕŒÉØF="µÑ¨6Oó6?ZSVíh-myWDQP‘Öëõ˜¿ôéVöµËÊûZu'+z¿hÙøZ`»ùyç.èîLJD–;»K‘1lª„ùº†MÌǬ÷TZ8¡£ð«œŸ¤¸tó‰¶glË2Ô÷ï'§Óf«}Ùè7:­æéÉÉióùé³ù0ònáäêáúÖÈz6>9=!Ýh!÷´˜/ÉèÛS€ Øvp€õUØbPcðf‹€lcÔ4ä¿§ÿ=ÃZÎX-g¬:–/–è ŸãÇçþ|„Å ”žo[H6«÷}ê¤6CFš'²ãìú•Öº¤«,šÂ1ãGß™¼. vwˆg³ºpo^‰.G1Å%ÀÔÇÝR®Ç)Ç– ‹WQä4È–Ù`×TâJ’º¥“ZÔn)ÝÒ)«¿í7••sØÔ€ö„—©ÞŽ‘—Êi^Öµ[J·%¥Çr¹Ê#sÚvV’Òkî1JòóUšÒã½XÖ„B°1PÞySÃ~¡±ê“TDÞôqÈ~7…Ƽ¶ƒÆ`6$ŠuÌï»”PKáF5²´ê=Ü-Ù8Ÿ•³¹cb"Åæžùr[÷Š'!uïÄ*ÑÈ»‘·ZÕƒ§œq±[6«q¤jMQr7晹ôþU²×¨©pë³ ,¸èÚ- .;{dAÈž×!%ãixO=¡, oÐæ/ðWŬl$ÿZÌÜ^߬À¦ƒ¦ðË¡f Äž¹¦Å¼AÁ´§ËŸy >¨h4¸¢œ¯bG 9ãÞÜé½ß1Ü!#úó8qƒ  y;›ÍPMêz©>î˜løÖ¿­f»¤w&á÷æ)(7#jwÍuö/׫BXÌxì‚ÔÆÉ¦ÜvÈvsÇÄÓ«‹øŽ—|ÏIâ&,Æ¥BZtQ h@ ý³ïeNIeÞÞÐÖŸÀ ¸ÚÊF ¤Å8ˆéòê…zq>3 P°÷­—° ì_$éùxw PËÜ GÑr6”`ÞΪúöÕ¶v€Ùþ–ÙîNs‚ÚEJ¬ÍÖç2ô+f=Ù1ÏÌõ€žBç/?:˜n”LòMvn€óCäÑ©ÃEÐXö_¥#NÞç-BòzÝÈå7ú7Lc‰|X;¦0ÝÛB_±¹"”Šƒ‘;Zå2@Nïv½x\qâA<¸K[Û»¨"ú°†Ai•²«Ó1Óѓ愿çQ¬Í)&/Ll „¤à!®©Ùä« M¥™Uú™a]Ð~Ô7;‡N|Àl[RËì‹=IÈïØnô› NG6Îã;çÆ(7„´„ËdO[Ò‹X×öÀ¼‹BóF'mÞàËQ%4Ú³.9ôÔ^hKöu€»^¾hõÕ‹q3\ÈŸ¤( 6¿n)Ì™îáŽÉ}ý} üQXìý¶-zI˜(}ÛžxÞ¸T­4©êð´\A8ÕÎîíó‹Är_h§vv6Ø£ Œy8Í¢—é‰>uoÞÆ[önǤêqM«Ø®)Øf+©XŠÎíêCx<ü±ˆT4šæ6_éÞ®5 ´•Fám„а›»#¦ /Éý:{ w¡­ø¥z½kBBã÷qž¸¬·ÅpÆŒùß?ÈÃe½‡{°ó…óÚ\¦“‘~y^s¹ƒü™Ï®%7#z'î*78ánD¤Mx™³€CÛ0òáíwb_˜ò Á¹Ÿ—Nì÷ûDéKÒbt»¦wGÐ{ÁÝ瑼»"Éûˆ9„Úw˜À†ÙQv0Ê&03ê]OECLÅœR÷ñNº ©Ó0çÑ÷e £Ÿ4µÙàöˆÚ;RÃ÷ÙׄwîŸCn“Án±›[ôF'›"7à·•fî("¯D˜$èÝZ÷1KáÉM\nwwÍØX=Ü)g¦ÙVPøÄ§ýØž4ÝÅ}0PAŸ2¥(Æ nÏ"¥ôn_ˆÅ¸&ÿ°³sM>8,‚ MÝx0šúÁ8òæ_åé†ðÓÐ#‹l…´þ^tÒ˜RÐDt8Í£pË@aÍ5v¸a3 âå™íö®‰ÙËSÙc˜Cá©Nq†o·phÌ”„}u‚£ù@j,v7V•¢-YYEïöÀÊJ3Ñx{F+ifUú·–®Èû¹±¶O*‰o¼s;¦SÓ©øcGò'z·øÏ“âBôú‰_"íË6‰¦Ü*6ôsÇäƒÚÇÔ»j(¦øùŒ…ûÛ®©T¤ï’Jû¡×BGSoô­À=r—K¡Ò¿]WC!WÉk][#X/C°}¸Ñ…Z)1Ø/j)Z)ïÝPj¸L’ç¯;¢”èÝ®Å/öÂÕ®Á>L¹Ø«÷qlZ.ÊýŽlZ:°ýæ·±i¶5Ùèî‘;\nä—ðAÐÎV½ÍRž¦m»Ú:¾súR„Êtx`ï«dV·÷xçÅs7<ö’ÄŸßV¢äú+mÜBCy‚šíc¥õH´RïÖ˜õJÙÑ”w7N7eo›îᮩ֑T#ÂD/ydYá8qo¿J{<½a~l¤é*ûµkÂb ³®Cû£¤LŒ «;…K©eb¶ÔÔìP;þçL6±±[©*ËÐÎðM!åÊë£w ÁúRôLÑ9 Åy[Ñ&vU:‹&RÛ.-é•(_gÒ«ƒ˜A‘Z}>‘nÃè¡Ô¥v™)jwò¦èLië‰ÎU§Yb®Ô9[c­€ð_{¹&ü¹Ÿädµ/ËL£wÃw¥³Œ@éXY¢ëË,H˜çF¦vv#Ä®¦bCo˜ñÛ«5£¤dÒS£Ú)¬ªä™1í–ÎW:çdŸ…%èý¥u×Dke\»¥w_§·Ôq•ܹå°vKí§öf²…o›Ö-Ökd ¯Ò-Òkzxì’ÊŠÿXj@»¥p‡S8öoçn©Ý* ‘…黦¬•¼cú-0þKøé`c‡Ù¾‘Fá æXæËlðê£pÎã[mµÕîõ¯:½V“ÓgDÔÔßâÁ?–^ô0ˆ“ÈŸßÊiû¸ü{#ý?RqA›ÍØ›¸Ë ÀèþÎåöú²ÅÊ¢Üðb˜ö}À¢Ó€ñ͆\ŸÇÑráƒi’,àöâÅÉ`âúÌÙNj_[Dþôá›GwŠ=h·q5ÚM¯Ùî‡^ëª×i]]¼F¯ëzþx2î·zÍn2rÛQoâyÍIÃmŒ—“ѰÑv)ñ‘4¨µýÈ%d5N£»HØ´\2À&³`ÐÛÔUEzCÅúp) "gQJÐÀÉ)ª¡œ„ÓÙíõ[ÝË>g‘ßÜ;7EþX!ŠYÒe¼ºŠGÐÞï w>Ö_Šóé™HBjDQò¯{-ùþ?ºWä?møxÒ? `^ëü/á(Ó‡*à=¼n«&|Ñlòÿ\âˆØ·Í6« K¶ù·Ø|ÿ‚kM˜*:ÄìBèÙ¸œé0€—0Ñ)‰¢ÒIûHœ×Ù¿1¤Y×D^ê¿%[òp¶€à¶bÕMCKÊÍáˆeåSJ´õ¿¥ P܆0D&¤pùóIø×é]OýÅ9é‚^ZD,¾²Ó“ &ž‹»;o~Ëž é•çØ*ËbR;%`Œâů|àrC·9áímÀ{C‡9ÕY, j» v`€+z—s9 4áõìÔ ˆ6c©v(Á1½ží í/þðêã/œÏ7?¾}í¼ùÉyý?o>}þäüJñÁý×øôú³óר½óÆdz£À'˜êÀÿüÙùë_GS7rG èdˆì%ýÄô†|²L&ýxùñõÍç׬e­=çÙòÄÿêe*yÖêvŸ;ïùì¼ÿòö­óêõO7_Þ~vÈ $@þ¯NÎoÉ÷C|D$™Ô¯Ž?Ož5›¦OôÛQäÒŽK”¤ùŸâ_¸æƒOµ}7ðÿ ŸÇ3‚@PGÏ^ŇoÞÝ|ü_ç?_ÿ¯ó Ç÷ÃOÑágü¯çxî¼~ÿ·7ï_ÿùÍ|¾úQÔöò盄º¦dÌ¡szÆòçš‚õ'›5xœíMÍö›÷Ÿ^üì¼yÿù—4Íÿ~óöËëOγ“æu£}Õè6'ÍI»Ýs‡­ñÕ¤ÕètÚÝÆUËk4›¢ðý°øËÃjêÄþ̈ºåÏØŽ8Iè¸`Ö©ãÇŽ?öÜ^8Hj‚wB‡¥±…ŸÌkÍI¦nâàE³Ø!å Ì‚ýÓ¹÷†ÎÎOþ £øÜùë†yr = ¯]B%¢ÞRïßSl„VFš'|q{øßMÃ{'^Îf.(6D'XÍHnÞ¼ELéÙA÷CmvبdJL  F½rÓ’|ÿ£ ¾U`ûPÏQ“Ý‚&û5ú:ÿáßÎÎ _ü·³³¿Àï#á·Dø#±·Eìì Ñâ úª¶<-2=¿¾2ãœä7…s¸ü¾™/–‰#*â‹ò( wû4¹ûPæláoB_õßs+ù™»€¦/¢‰ ë/ž}(‡¨j±ï°È3%!«˜Éh¼é ûVIææçÏïÞæC¸n&4&“:7èãZE å„O±õ¸›4FÏäÕi\¤–\Ûü©é/?þ_þÛ"³8îx ÜN¸Æ;Û«òz»±Ðï)ž$ÛdRTwá=¿iÁ®ÿ$/Üÿ{›¼À¿¼™ø3N"²9?G„å¢]‰Ë@üÊ?_ü9–Oljüs Š®½õçlpå–h\ÓØAT7æbüEl”ø6 ç •Jö³&e˜Ö ¢õ(,õðJ«^iv›[ã•LH‹NH[½í­lŸúPþ‡Å_~p)ÑþÈø.ØqÉ…ƒ 6Þwaäq\êè VáêÂΖ~¸pÿ‚öXfÞ«»ÝœÝ§¢Ý“¡¢ËìQ7<ꆜØ\DKA»{Ü€n“×9²‘Aè º`¿üÜsŀܚ^~„¨á\¹¾$^h—ó˜ƒ"=Õg~J–®( *êÚ7¬ý÷|açÏ—Róê¥l©é4³kn—/¹IõÍk…F tâ+-ˆžQ)½IÐè+¶#Šmú»–؀ٯZÆÕY£MþÏiµ¯W×­žóÿ5¸c†:³Âp…×jh¾*Vµ1Ú‚¦5+˜6O³Çè‹ êƒ+V£t"a^*>˜ÕÎP…ËÍf4¦}Õo¹+®…J—é ç$©› ;µâ˜Ê×¥ä“-‰ ÎàG>§0AõŒ½E2ÈÄ}AÈŠ¢Ü}ýw³þ^´‰¥.t¬BG¯pýÍ,Û‚§Ø€%âÄ¢îˆy;ÒÏ«YPÑ€ûÏ™{÷ŽÒFžíô» D¬3ÕLœ(@oÃ[Gf&ÏØù2”ôìfî&"*1ÕÍà …Ð1Ù/ÂÒA=ȆƒfæŽ=€Ö©,œŽº§d)q–s8@LÂeäÕœ¡žó¯2--Žcî—àÓü¤¹èpƒÕB7Ä> šy¼ð§)»IV¶¡ý¦'¤ð°,‚Ÿ\à%"K,o¯]¨ïsø-µi§;M+‹´a€o=÷Î#‹¾;ÿ†šÇÞì/7ópþ0 —dÏF~áä¦ÒÍ öé£FrÍSY»|uü„Ó]µ® ´ëŽ:<ÂÖ„¨(°è‚4 †™ÐOñ<—Æ…KÑ÷ïY¤/cò+!È.–ÃÀ§Ê¦º.è¾Hm†ÙùjHy%ûÈ÷Ä–šïéðJí¢RõÖ1†ižDDOvdø–â^h;ëÕ;ñ «pˆrž„ `0¸)vBeš&B™ƒTêƒèi%rØI6 }ùäÞI_X•Ä!±Òª:ÏtÑ,Š|Sɽ‚k^ª«©n]âz]ßó—kåIUõL›WÒ©G‚íGÏÍ7xø*6o öøâ¿#Ÿ‚9_§þÈoÒQh 2µÅsd:x}GjÐ'Ã4“Õ'Hç`Ó”µl’!‚àòhKŒú0ZŒ§¡ˆœb¦©êèË#y%RiU¿Be¾gri­Ô!“gÕª2&Ÿ+JïbªU"âौX«ŽÊj°ª^aŸ»lþQ„9ËMtZÑÐåh•9Ê‹" ‡ÅÞÕz&{{ZiÛ…QäÅ‹p>†-3Ù&S8e!OPâi¸ Ƹ”Ò30 ‘u»?ƒ—3y˜8÷dw‹ç6ã1­O!°rö± €Å!ˆ’÷«Å]7 2¦«Éˆò+pdêØ<ç`¯¥Å\[ºº-áê;wïü[´®±Âøô‡÷âñ_äS¥ìU9 »ggYö YÀβˆgÜÁõ¹ åË–â²A>}G¶ÏjlŒTé&+}É¢vY-0v'õE£'fäŒüóA³ h%/¿ M‹~’þÔ©ñ¶´Nß@زÕç1˜Òf»Û¼Þ—ìoæÎIg¤{@š4—rÏÎØ—3ÂÀP¾/Ç%Ê+”I¿’z¢^Üv4·Ñie>ú kxéè†-¹ì£Ÿ>9 aÐ2~uÕÉ ÿ³5CfF®¾˜>8ìÄÝ­‰VWGüèGžó [ºÝ—¼ÀJ„™ ÷)u›W¢0).ÅÈ£BÑꨟ}òˆTŒó?l_e暦%=Wj}Æ<:æé觸§ó§ß.#;ZíL§nDT CqÊ%­K¥8GÚˆÃí"†o•V.…Âùòñ­…b û¿rñH}ìȸéÚéiu^GQ94~ª9ÛŸÉg?ùç(ÑÖ3Ÿt3Ý{¡ÞÉß|3´{ÙS !¨°µá|ÞÞr§7ð"Õò©¡a#ý)¥¢;tÉšÐZÌ ØÈPäƒa7ç#3í;= 9fŽ‘Òß]š¿ƒˆ"­íµR â|‰½¨è[i¬ ,]"»06M´`'–OºüúÚêïf9‡’ ôÝf¦…/±ˆ ”ˆž^Øùˆâ`Á¸v†ß>z#X«Ãp_ó—´™¶ŠZáÂùzBw½ј}¢£8Ȥ¥Ê íNºôó½pBT–t%Æï¦qÚ¹¹sý´#~kž¸~f.>áQ£F`N“·«ë=?{Á¨ËtT­¤Ø —I¾‰/~ÐV¦¿H(ùÒ£¯~H-Kì:Í˶ǔú™û»?[ÎÜ“àA%iÔä)ØäGìðmxMüß½1œÄ\;ŸÀŸtsü„z4Áœ n ú»±ÃLC ñS÷ dõpîq§àý>ò<¦öã¾è\*åe¬³ ¬¨ÐŸ 5Ÿ›|ÄÆÐzÌ£¸Ì¤vðó¿SoÇ^€žG>fë>AÙ*¼ Ë¿à78'Ë‚Øæœâ_S²Oò (PºÞûd"bØárˆ›1Ò!ý=!:Ù ¡åœl½È{<” Ü‘À~†Ò¼æmÔÁÛ©-2L¸2 =°0¸'n[•šì4ƒ:oÐ1Í%s ‡)p. GèAúúÕ2a'¶ƒ9w^ÿîÂyÿ5Äòš?œõu~ëyÎoËÙ‚>uЦJ¶þäÕ›ùˆ̼ߌÓá· ûCƒÏVŽW‚–%AóL¸ÎÎ4øtÅÆSþf£Õ‘s­ Û/²öDôÚ·ìHÉê l0Ÿ74UTÍÌðqÊy/¿ ¡Z¬`˜hè%{M"“[Šä èfû ‰Söûž˜2ñS9œÆ¼þCÀÕ‹ˆÂ•^F æü8åê­ ¨¯,îÖtÀ¨T§y4s@ ~Y4SŸàÖ©dÛô°czØ5=ì™^šöM¯Re|½Œ¢DãTàýŽh .Èl÷È^ÞóGô>ãnÀDd¥G·y¸ÒÁz5úR”t\ÝX†9 @aÊC 5ÿ#D2 XW!d¹´%}ˆÔÛ"µª#’.‘”"D2Ñ­NpJLElRa­,6]Õ‡M­ÇŽMÍ46¡×>Qlê^§rÓÂ>•m]x‚ {I«rfáX©ê€T¦¾ Z€BÓ £¢©leMe¤åcÕ¨Z5¡Vÿ¡–M£j6ž*lõÓ°…ÒMƒí¯‰\}”6³ËÁ–,$Ó;ì½FÆïþrèªà¦Ð_ ÝR©ÕsÑM)kB·z§1îò’³«ËvŒ Ü4)AÂïû¯çáq\s“˜©æTxÜ Ù}¢  " WUe•¾‘§£´åDïV½†²©³ñL p§Qo6ž«¨p¶gmpÔ} pÔ;8j‹ÅWÉ“Äà¥DÂ!eWºôPs‹Ù2:u$÷1îö.×Θ ¸ÞÐÈd4T=S]«ÖSçz‘Mªh‘J²uN+kÀ·ô¤!®Ù¸º®ªÃÕ@ÖPñàEwÓˆÚ{ ˆzy ˆzH»bhÑà!¾e€móÍbBà«{¹¥#0~£80ñ¼ ^K/+biSà#únCRcIÓ¶ØLð4œbÈîjhZ†œ[Ú_>è|²ç  ÜYhÞy‘ø%c¢í&Ç–±³CO>#Bà ÝBf:ÆC嬇žUM:uwy#€Ú ÛL‹ê§ôªQH«ô ‚6®„>¦£Ãrʴڥ힥(5®ðp\Ñx>‚6%‚²OÔœ¿:|Â|h·Ù¶ ™ð`,@ÚÝêƒ?>\­ÚÓZ˜É®ñi˜©ÈJ4Ñ©(åÜꪤ2gáG– ½:àlVΪdÝrÖy¤ÝÞp*¬spÈiuìpvRQL÷¤gV(ÂPìËR~ë%J¸) zÕ`ÍI®lÂÙ–ê—½¼m+*Ôö‰õÁ@ìRUÕþŽF½Žyd ؼ®‡Áª,Ï|$œæ;(|bÀßü¹ÉšWG”†ã5é}ç”Óª}çvª Нå' –QPÍȘé0 ÛVƒa ¯çxñ— ‹PãŒD¯êT„ ÇXù ,|¾%¢bÏÎuótáßÙüÇSó‘Q‰ÅÄ—W‰«“øˆ»y¸«t=ÜmŒ§ç~ã.Lf)Ä]¨Ä¬fËÐÛòet³WH žë†lœÕ~žBp†{/à_LCáà$æ)g°Ø?ÃùzHÝ6øæ#uÖt{=?“Ô5uñg¶ó³ìüeôåvuw„ÍÏÉÚs ½­Tð( ýP ÅûíWzÚŠÑc D°B€‡ŸÆÀb[†ø+ zÏ‘Äsƒ˜&£a’šÝ¢ tí‹N£Ã_(àòáçô©Õz(_Õ0Ý6X8°Cg)2›°¾ôÇ&Ä·Mhó;Õõó­LÒöó`ÿ‘™¹ÛG3w-fî‰O`8å¹aƒ|x&(ä–á¾Âö€€AÈýÔ‹0¤M€Èv0ïp F:J±oˆÒøà¸–ÁyãõP½²©»—fèà™JI£ö^æCš›æ*ƒäÍêîouÒÿØy€ýÈLß탹7¶€mêiBìXˆÝRfCPÞ-ƒö%~9 !LûýÔM_íÏ–Ç‚ßO!¾?Ò5ÈÞÇ"BòÒëy×µ 7Øò¡[øóHÆÞŸi5‚w¹Omæ—ì¼eœw*xýsq„ñ<W.á= ?”Ì"¿<¢Ÿ°¤sõbw;ecAÇ>Úó)Qü¢í˜‰¾eÌnâ.á%[ç<ÔâxJx{7|¤€={̨éO• <éexO@ãçÏïÞ:Èöܹ â>Žë0¿èÄ¡¸qÆ’¯ù䬇ô•B î}’Kl_ô‘Ý33œA÷Ëêêù¾ÌÚqMÈ[ÛéêÁܬ]µÇ@ÕL3gÉ$êº÷’—áb›ëÆÅ×Îë‚LϬø»ùáR†…¤stөŨ¯„i/eÔÏä5ÚöÓ€§Yÿ=Lxaó”h"–pþ0¢:, óòÓ'üû?>9Còï½?N¦h¬ òVßÍÌNe—ƒõ~‘¦uY³æC›Ù?=›™}E·U}±Øê w9 ß9PžÌUOú‡bQÚÐï6ô.`F~zKš(q{ ‘Õ?czº­Ã?-¦îœ€‰r\é—ÔÑýÞv“ÇDtÉkï 4GÈ”‘™;uXnºSˆuDÔOÄ)ÀŸY­ç·Ù©jVB'«–ÃÎ2d7ºô”þÚ´X§8»&¬`kÚÁ´W†¼•á‘Ù•:O×®TÿÊ ä-¿2dnÛÛ­»ß<‰ád™=Ô6•þV:Œ@ õ!žÈè›ΡÜz`_Õ:d…ë %+}æë\°O—ÎúýT÷à¬i&Žø‡ßÊœóAç€b ÂOc¢çmƒ3<4ņÇÿ©sKàmA-Œ’à%È1ñÜdI¾õ®º¬1RàrcQCí(l,hó˜7MDo›Õñ¶â¸õ¼®Y-¥hÛôýã@ÛC¹ ÕöGæšÓ‘`+ó]§¥Ä´ÌøŽÝ\T™×D²Q,Ý`ª%Ã5#ÉJY,ì0êÙAP/a l¥Rì±&TZ! œrÕæq¦³nØw@—€üý0¼ñ€²ÂPŠCmH#°ÔK„d=ŒyÞ:Z%’üCÂWiŒéá|K’™P&]Æ‚3*Õ8éîüjÄå†ÈÓ™C¹JRƒ¢r…zÎÄãt[{€I?~úä赂cIAà믴C¥ÂÞ¦zÜ{wøo‡ü·л®í³rHBêxÖÑ”ÁH"/ö€ÿ¸nHÿ¿Íþ¿c†Bhz*Ÿ"„®bÝ{tJ‰¹ %xQRB©i ¾ÛÖã@ÑŠ–CRBVGQõ;Š– ùHÓ³ùt•¸_ ¤+¸¶`+ñ4Ìwm¡)É©±A"ô{Ü|-xEÅ“Šóa`Åèa-å8W2é9d„¿Â¯ à—%îêÒóö¡îê`n—*~€+†8D”LÜßÃy8{¨É7ë¼Qªrx `W¯™j$-é£\ôIs˧òÉÒø‘l¥­© J«žs­Ãæo°FØuVýà×âÓBsñК¨ù0A­¢VF{Ï †]èÐb,m»(–¥èÀÒ“õ¬y0‘>:)Т'Ëj¤.¼ø¶XUKÜe#åfŒÍã¶4Ÿdü‚'ã— ãƒÚÿ•‚!Þžø!`~|àoRÒÈ·ãWë >¹q~ðfú¸ œ:±?ó7rü9$6›IÊÅ2DP¢VÈÉCR’h=ÎÌK¦á³  Vd>ƒ¼ Ç&”‚çÊÇЇEQ\XˆDÃÁõ@¹‹£!#ŹTÝ}Ê2þÄW`¢)¾d]ü€‘†‘;0ñç÷Gæ7ÐЬãFq°bˆs‚x¾BUqÑ*QÃãw²¯iWgóI.ä‡g· y¿‘>S«i!ïb ²ˆfWrxõI¼ª¼”·¯Zb)W—iëZ®¬÷dôÇYèòpAqX¼éjCžSo~ é ùÒÌÚøÜù ­²Ê{nŒ+<¼vçs²>0U y†«0U g„·gÿÍÃ%Ü'•ÎÜX¿¡GûEÖè{?™fÔºæ›Ô‚tÔ[–(È Iʯþ´·‹(¼#Ô¢ù¼Ý¡ø ÞÐb4³¢ òÿãÔ*ºë´{9ë?}v‚¥®¥„\'‘瑾¸×—ÝËÑå¤Õm5Z=²Ú:“îdØë¶ ·ÙµONOµ¾ÃÖZ]~d}èѱ.… †n2š®ØXöý€ðQ’³4:"[½ìè—*b@7Ñç#®¥>yr¨Ç ²ÿ¡–Äú²±·$Í\ ¦d_3¾: ûFlÊ6‡HLéYѲ#Ì2ùˆ¤±…wIÑm»¬Pýª>lzôÖ™f›ˆ‚r¾ÊáGM]‰M–À™‚­ŽÌ|/iUÎLXOLe²ÜnY iÌwƒ8t;RÙÊÚÂghùX5ªVM¨¥\>xÔ²Ú”O¶úiØBé‚)l]äꣴQƒëÌ“Ï7´%GÁB2½Ã>8á2öQfl:_Ü€1Y.ðÕÐMIèSˆnJYºåÐ;q—"™«ËM’È’¶©‰_¤\1KðûþëymDèMb¦Â4%{Ý ‰‡^°ÀMèê ßüÌOViˉnñú³‚^C™8M2#ž© î4êíÑÆsζñ¬ ޝ¿Ç G»Kç^ ŽÌ™¼(áñrä-¨8GÎu7èáGÑ‹í£SHòwß»ç´p&Q8sè` ¼¥®oa2õˆ"’¸É2VóÖSç,iäK¨s‘J²uN+kÀ·ô¤!®Ù¸º®ªÃÕ@ÖPñàEwÓˆª$¶?xD5ØòzNƒ1極•ʈ¨ŠŽN·Ëˆ‹~qS†­TVS¬ë•&*w;ÁÔK(ü7/gµ3Ž‹~ÊÚž.\xL!EáfBàÞ˹£×rHÐe0æC—˜4jžI:ñ«ä·Ëúˆd5"™b‚<4$;ÃâfU¯øÁê †;«ÿz{˜øe0®¨z VS½ÄgÕ‹SöX5–Rö  âÞ]ÊɺÎBpLc¸{7H07d±çÊGoޤF~‘osà•cµëÀxÑdïÝᕼº8uï€4ÐÃàÁzÞ:zëײÊ]î}åZåšYe çÀŽqù_ؼZ,s‘†»+‘ê%.k—[¼bw;³¥tÛ¬ÝíJ¹kvHv7kÜ«CQþêBÒ+¤I˜okca¢e‹mÙ"a|zÇÖœùs¸p¾žèÅO/ŠÂh7H‹Ñ* lÝržuíøùzkQ&í'—Ĥ½;4¶é“¥¾4Å,5?iôí /«Òè[‰ä€»y:ì†aWyú(`÷ò»6Øm¥Zäåh¨p9·âî¥ëTùÝoO¢€¥_u‘÷²*òö3ø Ý;#Ý;ãd¶Ao¹OMØ[nŽ2àÛ«¾•È~Dß<ô½|\èÛl¬¯@öZOàý]šŒqW˜ Çå’|BÏ^y !ü1v“1a†¨ùèÙÌ@ 3/ØkÑ77I•°Õº9S§÷!Ø>~n :®ï»½»¹#äv‡çÐZw£&ögì.tnº“ëü9ù ¼±CEŸz9'Soæ­îÆHÅÆr´]5š–DEí“ÕÔ>moF¹Ÿ(­:nn*@ÍÜ‘S£Êo¦á¤ªy(ýCºyg°n`ft~»Ànó ÉQ(綾³„á7*úÏ Öó%oöõR® ‡VN‘ÀaزzV Í#”8ésÔVØvÐo¡~æ ¿QH«ô Í¿èøÂÿ´ŽáêWBáç2²]ÇþéÁCSà {|êÜÔZPEŠQ2 )8° êël«Q`åµEè`¸š š€Õ6KÕw+Áj=Ä=°Í³ÍÖ…µ-¥è#ÅZš”ù0À¶Žä@8 ?ŽïXZ‡ÕAª{©Æ; c$iË`aÂ…ëtÆ4ê%,çC*ÅëùÐ 1jOÍÇ£Ö¦îuv@—€üx@=Š<‚˜†RšwfU“z‰¬‡1oÃ[G«ä@"“Iø*1=œoI2ʤËXpF¥ÚG$Ë=àXgäš'†3‡r]ƒ¢r…zÎÄãt[ù®ó§OŽ^Ë)8s!³Eq|þû,ç^`¦íî²J¸£ž“š“'ˆ?»»º"'jMµæŠY QôÑBú"3ƸXæížòMHz “íÈH·#¶¤¦ä bË*n-ᤠѥÊ~ý÷º†±ÊRŠõµ»R¡ßì zÿ_|ëXšw Ó¾ÂM£¯°¦ ŸºZ³)S¯ ®l o½,nyû2cž¿pºŒÁD¯ •š‰'ZW‡¯á÷?9Hü˜‘T÷®•Ó …±ç@}ùÀs½¢b¤œnl[®ªa öñBÚ„0æ’6M)CȺ­@‡‹9WOsš»Ký ߨ64—ÓˆJ‚Pûš«Y¤â5·fðÑKÌ‹îŒ6}´µÉ„ÓÂö / íø“-e ÷ȽÊq»-€IEôQ&ç)ÂÏ¡Ä 6_Þ”÷ FáŒ.Þ“±Â5güÊàD³Êólœ6®Y1C¬JÄ •ˆFÉVØU‚wgé¹zŠXu0žAÍV!…qR¥Z Jycóz¬ê5©â°ª¢kJÀ I@#>™‹Ú6qR±)=KO›vç4t]›íO|"ðãð~ΌÔõ©ËÉÖuH°SÑ[%“Š÷P2Ïtd.j»>˜¥åwÒÓôqgw6ëŠ:‘¸ÜÊ®¦4DI¼ ¹‹¸ûLÓv—I9Ý×ÜÃA}ô ÛXß!¡UU;7'åEvèFÈÊ)o‹2a¦ì»Ò“ö±«µŠé»#îvR'V‹ÃÁÒ(O¹AY—N+U[ÇXýVÖ—kRÇÏᬿ0ÚÎÞ‹<žjò&@^}÷PÎñ©{­¸[ÕêX°AË{«¢åÏa‘gZÆ„~Âî‘Å}Ǩ×z²÷ö*¨·w®QÌÄ%\£zÈl}/ç…|-_o½di„sñŒ]nni'ØcÚð/ëc%zRWR¯¹…9ë®÷SÇkWD3q{ñ§bK½¥¬ÝRTòÁC.ª¥5¤–YKƒî~„Êà‚ü!ò;U-j]IÎ $gž^f/mÒЬD=t8«QQë‡ÔqF‡y:Ú¯ºf3¤Á¨?å*söâ6×1Q–ž¯§i«¸Žuéá@‹ÝX|³ôþT×o¾×•ÚU.êœyw~L>]Å0Ç a)]ÍÙ¹ÖvÌ-î•.»^ÉBׂ~1ÍÄs£À'j*¯é0q²¢óZ‹_à$€Ç—Ð Ë|g@ÎBz!4=•OBW±î=:¥ÄÜ„’?¼() ¡Ô´_€mëq hEË¡ )!«£¨ú EKü¤éÙ|Š@ºJܯƒÒ\[°•xæ»¶Ðü™ÔØ ú=n¾‡H¼¢âIÅù0°bô°–rœ«™ô2Â_áWðË÷uéy{‚Pwu0·K?ÀC"J&îïá<œ=Ô䛌uÞ(U9¼ƒ°«Š×L5’–ôQ.úƤ¹åSùˆdé |ŠH¶ŠÒ¦fð7)iäÛñ«uŸÜ8?x³¿@ý?\?NØŸù u!»î LR.–!‚=°B~ )z}Ðzœ™—LÃ1¦âA¬ ~‹yyÆ~¼ÜøéÏ¡*š?*™º‰¹‘<8£©;¿õbÒèr4u\Èçã.a²_È.íÄÞˆ&P›öî½!dø9w~|pXÆ“SÖ7чÌGD^‡^ìÌÃÄ!SÞ;°¿LBëûçÓ,_ÐØÁ¾y"ÑášÄw!9æÌäWç‚®S/Xd—€-R%Î4Ū¸D¸(}Ö¢lÃçÃpü`B)x®| }øQÅ……H4\”»82RœKÕݧ,ãO|&šâHÖ•Áiù·~d~ó˜¹jŒÅÁŠ!ÎâtøUÅE«D ßɾ¦u\Í'¹JœÝ.äýFúL­¦…¼‹%È"š]ÉáÕ'ñªòRÞ¾j‰¥\]¦­k¹²Þ“eÐ{d¡Ë[ÀÅañ¦«yìòÞüÒAò¥™/´ñ¹ó!‚½"Yå=7Æ^»ó9YŸF˜*<ÃU˜ª3 ÂÛ³Àÿæáî“Jgî¬ßÎУý"kô½ŸL3ê]óMjAº ê-KdÀ$åWÚÛEÞjÅXÖúŸà-FÓQQ0+ *ÿ?NM¡¢»N»—³Î#¥ŠU…jUu…JºÂõÙùΈ »Ä¨(|?9mœ6[íËY&/;§''§Íç§ÏN°Ôµ”ë$ò¼3Ò÷zì6úýΤ7ìMÆ^ì ¯Fî¸Ùoy—Ýf·Ýjœž(j |‡­µºüÈúУc] ! Ýd4]3°±ìûá£$gitD¶zÙÑ/UÄ€n¢ÏG\K}òäP ŽdÿC-‰õecoIš¹@1Lɾf|uöØ”m‘6˜Ò³¢eG˜eòI)b ï’¢Û…wY% úU}Øôd­3‡b›9&/?&/ÏÅŸWŽý–¯yL^¾"Æ“—“—׆3OöÃ1yù1yy>ø“—›¨f=çÉú³“—“—“—o[ŽÉË+`ËÞEè=&/ß"z“—ï h“—®BtL^n–còò}Çœ'›Á嘼¼à£còr þ“—×r§ñ˜¼|ÿÐÇäå§còòƒÐ””¹zŠXu0žAÍV“—¯P]ƒŽÉËÉË·ŠMÇäå:ê“—“—owž¬Ñ1yù1y¹ƒcòòÄ®'kú>&/ sL^¾9T<&/ßCÔ;&/?lרcòòcòòG+嘼ü˜¼ü˜¼|øuL^~XŠÚ1yù1yù1yù1yù“¾còòcòrd¦còòcòòÇiÇäå?aä1yùâdEçµcòòý…Ð'ëávL^ÞÄÜ„“—W´“—ï5>Y»â1yù1yù1yùS‚º'a옼ü˜¼ü˜¼üñ Ù1yù1yù1yù1yùáØ“UÅŽÉËÉËÉËÉË•u阼&/ßÓuü˜¼ü¸“—“—“—“—oFS¨è®sL^¾çºÂõÙ)›¼¼ÕL%/_DþÌÎØ/›g#|Mù3òa”Ä„+ ä’NN_ɬçÝqoÜvÉÿx“îdè¶­‘×kõ®ú·}9zÙ<ê’]‰½V¹øbáE¸ü5©æuºå:4®¹i:-Ö¦«TjL+|°*‡ }8Wç‘ôw5qIAw ø¤žNe8ÅÚ©¯ÔÓ|†[Ö©¶F~¡+Ý5ÖÙ¼lðZ™"ì‚ÛÔ¿ ÓØò-S:{®Ü”8ªJQ|¢ép£@¯a¿¥-JÄÐÁ|9¢–a祢x¤ŒGéÄ`â'â3X~ ×qC|ˆ¥wÈV 6»ä4À©/úÙgï¢0L ”è*ô,Þ5ò][jz“ÁÛ!è£zUúÆþ=}mS9s5G)Ù øÙ7´Û¦ìÂð˜euPxêˆäZ¸š‚åØsÒ_~Oçõ3KJ6!¢YT ùŸž„èÝ–dÒ3>=9I“ vQAÕ×MFSEPò º×à'Êq¶yf|ÁÏkƒhÊÔ9ê礷‚uí;­:„CG„šeF¥ì¶$Fm3¨>t ч\YðÆå2¢tÓ˜²nd’‚¬K ÎÕ°Ò–],Z—JöuD arbÚ¼E(1ˆÊ™ ;\¨AJfŠ—¯öIü4`è­.e|V¶)e¼Í'¹*騠ÌQÛ*Koßñ¨éáíÓ!¢ßúÛíöÖøZ<1JŠú”@5ùBJT‡}uŽÒk“'^j¯¤I£÷¶ÄIkô‰¬Z©1W!\3¸áEÿ Ç}×x̲bAåÙìÍöP*côjߎ¤¤>‹ëÖ6-’OAF´oHBpð-‘ÆÕ®ÇV™Â5_]dÜy8˜…Ë8‹ÏÍvo¯˜½•eö–Ù){w)xu®¶‰ýy-‚ý›ö×(P ¥A*WJRó•‘Äý—µ¬¬)Wr["RtX– Kº‹JfI´Ri!ÚüΦÁÓ:&EOäz(#z5¬<–t+Oa 2½v#\îÍ+³ØÝo³X nÚÕiÙÖ‘U½ “¯ò©%÷L S]£"I¯*é¤Ü–h]Ù{z¦‰ŠT·Ut•åNÞ&2qòwNpZòáL0µY„¡/?>8 ë—°ñQóÞða ~V—±¤eP×d[ý¬|q!Úì*»‚«–+™@«zZÝRv´$fX³ÀlÔ¨ˆl#ÚLÜø›UD/©ˆ²2+áw+ ¦­æÞê¼Y½¤Êæà(ž[O“¨lK8aávGvË?6õ’‚U4 í¦×PVý†¤t?¼7)£rº¶¶15ñÊS—S•›”Ó&­;ñ¢‹Ä_äØw¸”†1Ù£Ò’vóNOÔ:€²ƒ œßæMªÁÂÓÊžÈÉZ󷞲ܞIœÖ1eÌ”œ[“·ìœ?;iäëI«ÍÀ–ßi·0˜;Û% ºøï…)¦˜|Ó)Mæ3žá±‰ˆÈLgä{1ŸíÕêëXö¼è°ƒuŠŽŒ"ëx‹b–šü'"b™Q¯wâ‡Uex‡ç97Ãr$Œ…wÖ2GY$L©z ^:+aV½â 8¿à;㥊ÊKÙl¾F©ܳNï™)îú¶Ö8#{ aTæå(Œu £Æì›FÎÆå¼å°8½çñ‘ʹìJµ˜5½ªJh¹ Y>‡ [)'ÏC¾HQI*wéMgeªÇ¢¿ÚÇ·É5S ÎeQTcY”½™;'I£ˆ1z/ôàtÂe$"×±–ÎͤAÖ÷&ÆË|gMiòÉz`|CÕƒ#¤á´ïÎÕgné®â1òޮǀrbvP{YûÉ¿ÑvJ'Kì „«Ç}¤€ÀB´¥­ÅµÛ):tYK[µØyõ‘"CãBCÁ<•31®ÅÔ©éuŽ'ñ·´uK ¼Ü ^Í.pà'V?‚ÌçÜ(pîüÝüp)ÂÎ(\uâGÀm½æÝ¡væÇÉÄÎ"è“v\ "ñr4u\,OšŠê>ŠênŽ×íÌôXÅ5gÀ[ZWó­×)óìQX÷QXwb‡¶°ÑcTëp7%¦—zƒ"‘¦ÝáUMzÔ}Tm–vपsÒcUûx7%«]½Å´S’{rºrª<Øš”šyè±Ê¨m´[’P–+¡¬ÀQB÷XBÙíJB%‹< £Ý’„2_d»„Jg壄²9Ú•„Jy *F»¥©ðÓ±ïHUWž£”j³´«©Ê&RRíãÝ”¬^é-*¾.ö+“ºãÎQ^÷Q^Só´¯ã4?=V™Íñ–VX’þªQ;Ž»«ÍÒ®VX•M¥´ÚÇ»¥ýjnpýεë(§û(§Êíj¿ºNDûQÛh7$¡-Ùž¸$8 ~¼§÷zŽqÃÂc Ÿ#ñ©14hÝiÔq”ìv6= £艑㵞ÝÞõE&јik÷}ЏzÿУ쵞â‘mònôÄâ± rMÐA/Õl¼¹WyO1¾ %:ö uNöçÚ1ÇFCÌÃÚÝŸ2÷†„ó ¨Jáy]G€—Å:Âã 5² ;·•WVøó†´ž~€‘D2Lù]¥#ñv g‰?³Ë=òÑ+ˆ"ŒáÁhQ‹ø÷¡çZÈ#K‚8,ø_ á=de§øãÞ ø‚±eó$ˆ Ø?Ãù6 Œ^ íŠ +@-•ù¶¦NÁÁJñÀ6mž%¡Ë½O€o^ñ"õ‰³H##ŽÑŽ PÙ%W™6&w’WÈNÓC8dÃJå³4è ÙKÅjh‚´(î<fýiŠ4z¥…ߘ*¥®Üói6={‚¹÷ui é[Ãík‘°dD—ÉòÀ$iq»ú.S}~-k:¬)e^m¹Žê±+*}Þ/©NsêaIu¶÷[H¥;t«LC_Óv‰æO“¬y¢x‘sK°8Q€Á²º®Êš7[ýÇ·Ãk6k¥„uc¹DT³Â³±åƒƒ¦Ôy/ŠÂ茆Êý ?_CaG-l¡Â …¶_÷Ü€lÍýdê`ñ¸Óh_tþBÙÂøù}*›Þо½­dâÅãî}ÓÇP.ËŽÛÚÄ—ŽƒÝÊ—Þ7ô­^¶ PÍY,ö'è“ÊïÆl@ŒÏ€ oî§^äA”à8 #ÈLù}ž…À)™z„ú–&®(èêVÁK‰.Ѓ(xD–Í"K“Ñálë^ºÅ<°ˆRfh›D“~¶yF¤ï, Ãà[Î6íÍ s‘Š¢DÁ£/§aCr#4u|õC€2AŽ?£H_Xf;ãéâyé‚£«ãÊ•ÄìÞ€5xD–M# Ԝ溭aK 8\t)5¸Mâ‹!<:½Ÿãö„È2_,8¨œ¹IŽçS³Å¼Xê4PDx&«>Pó ãÇmÙ«ÙT0ë*™Ÿ?¿{ë$îm|îÜqHŸÇŽ^UP.œ°Œ g‹(¼ó™þÙ±õ6 \•¸é%½%R©%åàC_ƒ¶áàÁçR h«¾S¹rq¸xS0¬õ†Öta`S=˜M—{±~½#ò käæÍGjîÞù·ÔkZ9uAÕèÁ!HñîˆbÀÐX<;W-1„?Üu´ˆ¼0ºuçþ?=¬É! ÅP‡©€²2o“tÓ®ý Eýž»n§…wÅÞVòªú!!FuÕr<*cÙAœ+ÃíkÉžEK·`=S-Ts‘a?ýî!k~a…¨õ(c†”Êz[»ãñK»´ k,À¶,rhÇ=JÝ®0Û6åÝν« äŽiËVÓ…áþb>Êñ±„>hmêB£i„&ï£)l"Üy8˜A†6º/¡ÚBâ¼üô ÿþOÎü{ï“)?fþ?©®A-!Ûo(vU…4GëÇ6ìª:/îÒ®ºH3ûaM™¡mÇî¤é™ÇŒ÷ò±F)h;¡¡¾ò Q…?ç.`Exn²Œˆx.ƒ1A›/(*Å“eœ%Þ‘ª^2#d`wŽ›ž ã 4•aÂùZâp‘¦Ôà6š’e¬˜ÁC^jJà£P¶/%²ñàcVn€µ—s ¦nÇvh•ÈR·öV‰;(JB›ük(™E%üØù ΕüØë¹‰¢w[ÚTùlí0£e–-·!¹õŬ1õ¿º(·Qæ5š’¯|̱vùŒ+fYÊ*ŸíB啦’¯wO]'zýU>Í×Sø±ßñz vEe‡ã•’§ŸQÚÜ=QiECšý¬² ¿>†¹Ÿèýþ–è·<† œfŒÇxޱY£¢¸[IŠsï~í}=ë1,âònùxÓž«yÛ´!+"êä©3Øwžùsê8Iû›£y‚]ª^ÚfLl £åÔ1º±?¢[\åcÅ¢Ñbà-ø9‘ÇAxë’×ÞÙÌõ€ŒˆLÞ©ÃDðT1¢e`F›²¶ÜüÂéá@éÿqÓ¿é“NQ–A·v9­œ¼,•ßwÿÖ>ÑkD¾·…À$½´“zÀ©ŸÝožœp29 àLÎ9•J@U⡆Ÿ8@a'œC¹mÁŒÒ•#Ìl ft.Ú9Ìd˜ú‘ÁLz|Ûñ¯àVÎR‰%>kÙŒ ‚> îï§¹··xà9rï6Œ˜#=.Q_&þˆ9gM¨»çfãg¶)'ÒAHð»pä—ù<@›)XÉ&s`¢&{ȇ“lúŽCÓaÅŽ]ä³øÁ¢GѰªƒFW ^Õ…‘YõàºÔ•¨³³°Îg^Ä]ekD¯·b¥Òý,$1ZKè¥2êø 꽚BFæêK „‘ Œþþ¨yÔî$Žãœ²ƒø»)v>X€ÈÒ&5 é¡AcyÄ”:gcoî{c+B ™þs¸p¾ž0b³NX;p tAPnë·Î³N£?Ï Ø IàI¨d»È5¨¶%kˆáUÑh„F-tyÏòq@;<¦‘Pœ¨Ò¼³'*,2”[u[ë•ȆYžÕݨxë bgó09›„ËyB\ „@¡$_8ô‹Ñ“aù0¢³Œd“G¨ $8u5þÙ”•—&J nc8¡\qÓ›r>Ý_à µ„O7Þ2“^–<?÷ê3î.Ô‘w+ÓlQ÷n©ÏdbjÑÀsÜ…?Â+$[:Ê­l -ˆýû„qSÆÐ\SMóûÁBHî˜6tš«$%e¬˜Ñe‘¸/¡ÞîxL%Ü6¨Ää‹wCÒr’²Cš;JòÚ’¬<Øš›¹ïp%Ø6žMI/§†¾ûrµðÝb¬-pwO­q_HƒO£±<ïè?ÍÜ…`thëOþ|ìýž+æëÇæïÜ ×Iüƒ–h²zœóÀ=)Ë÷ùû~Eõ‡× N¹Ù ©÷‡â‚™ÒÅóo5‰SRû3|qÃÖC¦­£íÓN€.ÔIë…ç®RÑ C!nYaøíÜL8(o’£–TÿÇnÎ%ÂÆ˜%:òO5Œþj±­(r¤§²N².öèÖ…Üžm%“Qç/XÌ7{ŠZînÓø åÑÔ},—SÖ,ñJÖÎq9}d3÷­ Ä(òd">9·Üܸº‚ïnœ¼Ù_ èäS‚3?p#ÇŸcœQ8u± „9`…|Ò(¹ B_2 Ç³Ø  iTiþDô.“žv»Ýĉ·ÎO‡cé"ëÎÒ¥a¸„ýØ×‡xÜÄuî½!F s~|àžSÖ7чP'"¯Cë` Å£eÄ0þÑë<4ºOK°à c~MŸG3$šø.d˜˜yÊ­ý¬rfÉv€·á•~R.Â#›±ÞOrÕvv`&ù^_µªœÂLk}SWS:jk(oV0C‡•xôh†—ÑÙ`mpÖÆ›ö7¨²â™‚y |H“ b<€2E4ô^ñæ·¨E2xâ`Ÿ;À¡ß!H—öå|L$;‰TsS3"…ÇÀÃùYàóÆ|RéÌ} ƒ”&cšá& É÷LИ.ƒØ½LB€c˜¯‡òH{Ë=Óû îÐü¯)C°°G°L3ívÐÒˆ ÛƒKKóÂKÅiŽúÄà/˜¹Õ®¾¥Òæ›v/Ë-gMI©CWlª6µð_'Ë*ÎWjG)7ëæh'›ëÙFš—¦É°°©½lýÁšE[tOŒMñ-µe'ÅéÆvÁlÈ]© dñ±žÔÞ8OÃf”/zV±V‹éYòØ](·á7'ݵ/@µ·É[[‚ÚlòôtµJx6†Š Sž f¦ðÆ3ß*ÑËê?ªWôdÀ9)ec¥=é/–ÏŠ+{:™@’ãͯí‡#ý]6@©ªnpq¿2χEöóJ×.ü’W¨ð‹}k²`GQW†”~VXç•é¡5<&Y/E« ·‘t…Ì‹½¸¯²qqßȽ¬‰|ª·›–ú¢KI›¾œµîe½ÝÝ3Ôá!çšà#À‡bñµBD¥;jÊ“8^ÞŽ>P«ÿT-àçµq]ÀæC´1冀œæ6çÌgñÓytž#w¥´ü2ñ¾ÓyÑÖì­gç«E°K$ãÛâªoÌV·é¬}%¤=/ãÖ3NfýaŒ#‹«u¥/°°%ÃhÐpaøÉq™W"Ò±ÌP_çÓÛDFªâ u«&ä*±Û/ŠYh“ÿKm½Ïxg—Üé?ÞU>OîÖ\æ¥AËnVû¿yÿ Óé™ô¶hÌËf›Ûh¾½=X·–42»¼Ý]ˆi©µ=?˜„ÜrS´=Ï9ÔCuïÔï…‹É:Ë}Ùò{aõKGŽt@¿´Mò)ë@jŽÌðPP~ã?…r`AMP¼ß·›øi4øG'ùEriý¼˜ù¦ àÊ-R.çö+a@ñQÆ(êëßµzôרòàGÛ^ä^£¢ sI¥“ÍHx¸ýbE­Ät iƒW÷j¾dhÙ&讎9PñXî’Ù¥¼â&"íë'1JuAóyZuma¾A/‹A-èÑÊcG`ýÒµHÉÈêØ‘lhû¡Åh“^¯‚´›ó#Ê„2Ûd(·ýÛ}T‰Kxûêú†Y–kØj4SMÁ,ó Ȫ€”­¶½È¢?ÔQ™Jí;:(ýÜ¢ÉQΚ¬Eëßr*QT`-åà@Ÿ‘Lºè—¬{ŽG°—ȼR*~ý¸0¡¤€ª/•”¸%ÌA8 7Ÿ>?/ÖAÛ6 ÊEAH¦½Q/*®ò5¬Ð{U¦îcC›ØÖ°ÞK+µ¼Nÿb†aëíë>ô–…¶wY1¾Ó”…ñþýv þÜ£· E€ëÜhR*°Z¢§¥4.]°ç°º5H‚Ë}‡ ÂÔ /娠qȦdcßík–"Ì{¡Ü—‘ÄXŠš*_d¯  ŒS7'étæ£7#ÚšC‹æ.ØRJr#üz }½æ|kÀÅí0µ‚Jâ/&«œø×V¥ 무:ïP\ëY»ËQf“¬ŸE.çþªõ{!Ôù¢¶1ž-XX FçÎÏ–QP(êðó%”v¾||ë(bkÁo$5ÛþódqùªóçGSnâ&èÜ÷ÝëXŠÁc>¯Cá“Sµ†l×pdW’òý ¤µôxk?ŠkÛ .FŠS%{ ŒO&f$‚ëŽïÜùȳÃî\ñ]=fƒr¢ÇèÕΖTÿÇóúñ<°QŠŒ[÷’LøXðÒï_ü À3vï,ñgÞ¤LZ.ìÒõ¼r1êýØ/ñ…A‚ò”v&ÌÐô*(Õ|8¿¯É6'똛OªöŽ‚Qy§+»áž¤Î^š6L¸” Â'2¹£Å%’;:P¶ÜŽôV6êìË’ž8•vè4l>ýy˜6bɘ¸9¯»5£\ùÖ9|3Æ*)âE‡ê­k“Nöû(Þ› ¶sñ^êüùôVïŠlê$]=#o†ºX.@i¨+ï|„Ö6Ʋ êã—¢¹s:!¼ºÍÝ Œ~»÷ ÃdsõUÝŽ³yÓÄzC1@›6¦)vSù§(ì…b·Š–ÞR%«»0Ƀ~Y6Ý~zõÎ/ÝÀ¡_ÛÙqŸÏp`†Ÿn¤HŸO¼d45£Å6÷Ȱ`'VøLö4…¿ ]ÖÛ£ëÒ¯²¿q“·Oåñb1µ[ë€]?üü!wÁ‡.2S­ªvñÎQÜ¡9Î$ÞÚÑ£tŠ¥ôÞžlðÐÓìB¢lÐòÖΆ郼:gÂyü*VÎÒþ‘JíšK˜äÐ ³%‰#‡k‘>ACŒ1š! ZÔ¸TŠ0ð hÙhKžÃñö ÒŽu"ÿô™f³çÁøä„oÏ<_ž 6¼B{~%b®“OOÞÇKáV´œŸ¢Ð~9†òq9wX¡üIeª©t Ëõƒë0IÊLîâæ¼¯ž¦¦PŽ2›<¨³ê*ñ?ìöÀ´Ÿþëm®¤+›ZÕQÈ·µ  ôÞƒM€˜ø'(Ú…DÙÎñ»šx;ï¾+ôîÅ)IÖk÷·kð™ƒë±úû¼¤¯]Nšvݸop¨ïòÖó!AÛ{DȆÕPû¾é‹²é€m’fY—z{ÙG©±çŠß*gxWŠàÓº²ŒüùÀé;š…·T˜ 5%òf@ló1»o5Ñ/‘À9{ hN·l@ŠÇdè²áé:Áf@`g¿òr qÚÉÛfËëxJˆÝ2/dŒäÚ˜C yŒùD¼èfšG׊·\¨ð^l9òööÔ¥ëÛ —±µXÜ"ú9ò·®Oùà×TY(¾Cï̉8›Ü4¯å&|ûV¸qSvµ <É=ÀÎ.ä”`ÇÇ*ýeF¾¹}@ÇØúØ ¼œÈ8Øæ+,³I@a¡0 ˆNe²ßCf–$ÞºEÐÈ€Uê ‡½9‘7ÄàåñõŠäþJÊ}ÙP—kˆ?# ’YJÈ4 ì(æÖ¯å¦Ãcî Êðåc…ƒrcßdØKiP.áASâAÑEÕq m¾âCû¦» oûlà¶ÏŽà Ÿ!+zS·z².¼;0BþÉ*ü—(û‰ëq®Ü#YåoXc™¾«QAyî]NÍÇž«ùX,W˜‘ú¬gmH±¸kÉ6y@)> T¸avþd’ëΦä:Ó«Tçy=UYó"ËÇúî^*¸¿‡ópö#Ø2q%Ygù½²ŽwFæ5ä- WE¹¦ózK¡@_éH>¨%s± £a›1Ø»pä—+SzïV¤S£Ý\°ðcEŒÂaWß tЕ9ÿ; ´ep%AºXä心ži,6r0˜q .þ…np“ñËÀ…Ɇ¢ÿÒ¤ŸÓXI6wg†^çžñ›¦·u…®ÎÞì/PÿäS¢‘Ì|"çŽ?GC‰“„Ž‹eâ$ŒX!ŸÀ”\¹œyÉ4¤Yÿ082Ùb¨£±/÷~úsjsk ÉÔMœˆˆQðàŒ¦îüÖ‹I£ËÑÔqcˆFº4 —‰NNì!¢8á„´wï 1£ óãÏP~Êú&úïêGäuèÅÎ}w~ãÒ±ˆ7›Ì/%üJ´xÎ[¬àïúC]lvúfÿÑ¡œŒ®¢tˆÐC\¤x_?Ïj'¸c³üúÄJìݦ/ÒŠÎi»^½ß•·½í+ úMfKkÝ÷*{c²eôÇÙæmvÅn6ºtç;¤¼7¿…û|Ë7¥ñ¹ó!É ;bÏq7ìc´à9ÙË<$í)ݱÒmtnA·gÿÍÃí®O*¹°×u†íÙÏÞûÉ4³u§ûcÓ:]÷øK²i$ƒ–x(¿S¦½…¤(„Z1–u‡~à'@U"[‰Ø‰7ÕæMµÊÿÇ]õvÕÁwà>bGïGº~–û7Örc/üW®Þ’?.øÑiβW.™J‚×ûÆN™fÁur\;Ø7‡€Ž¯puÆJ•dYø<…õ†â猃&Á^ÅàÏôI-3oì/gÉ1às7eN97¾ß)uD¸3ÑuŽÓwã]pø*Hi¹·ALÉÃà´ùN\U™ûó8!,ÔC€Ö_xé£2²¦2‚wãjîV#©Â›°¶fÕ’Jœ£‚b…Š3·®–b¶QËÝÓ0Xz37òç^¾ªò£Z®Œ,ÏïËÕUkß|1ÝÊØÆ@m$®´ºäH¥.m¦/ÌÈŸá9?ÿFQ늣Q쑎ŽÕ—ßSÄÉå©çI¨a™S‚@>¸â%ÏG ¬P+ÌbŒZ.(^¢4‚lÄ©Úðáùoùµ)…¾3þ#Ïñ«^ñØW°0^äP<¦%yØ´íÂ2—ÛV’lÃÂ¥ÈíÈ}iâl83‹¢ÃX®s¹QàÎÇVX¦ü›(Såê”íîÜnk>âWí$¬³ü_‹ÍVÖNöe$Ô=;ØÏ°Qþ¡>áíøÔ‰<4ÓƒSí€ÿÔ™K"펓)3î>cauŸoúPßhµk•=Êìd¹J;Ǥ¼±ˆüy¢×ƒrëQKpëëÑûàéz”5›X²ØŽn¡ÙÏÖ5ï£  ^Xì寕üh-?ã©° ¢ n‹b¯ oúG£þ×*F}U×ʰUEÑô}Y±”ñ|bTê Ï ‚¦ ÞOT5/ÛGôðTÐ ja JhÑÕÅÅ2ž—I’s—æƒZ®MëÕÚß¹2ZzBöWù3/ôÄB'ÜÓÕE-¡'ÒŒeTG[\ŸšÂNøs®àbÀ ¢¥Î [’ú¼xUôlâ¨n-Ø„‚*5›Pk«lBÿrÁ&r(qô ±)‡Ö•ô¨ž~XIc«ACÌkM‡RtÇv_eèìÍxŒñSWb›")®ì‹p£xÙaÀ¢C£@ryy"R{–Kª„êÌÊû´Oá^·Kå#ÀÊ zÄ`WJÊù62kf|aj€(E¼dtCƒì”s+³ïM¡åuƒ[ak]w:ÝËY}¦~ǵÝy©m>FVšç%Ëå.VW×FÆêêHZmJÍÜ FY¡µbCYo5ûTÕîJ@C¹XVû Ýöc†MÇ„9ÂBÝÊ„EZ×Fé¯aH5Ã#¢Û•Ä¥”un[2i›\QyÕ?ëæ*F!î®}LwU.݉Â0çÕÀFiq^å–vùÌRÍl7\Ê´,6N‚eŒL£¾8ô#;}èyÙ9+~ž»ÆTµ“È7i@°Áð3Z²Á©Òå ©®/ñÆÙ`mvøÄòÎï‹ýà :’"2L¤-ÂÄp(£À4LˆSGˆˆr¬½øRAÊŽO[E]•A…½6…uÈØO ¢E!aH« EA,+ aü{ŠH9höšÝÑZΪaB9½£Þ˜tE¼ºH°™ÛµyØ–Á3Ӈܸ":TXTÖÚ–³ÖÜ`ˆˆG­ã±Ê>¡Š27Çs•]#MY)ßÎ4R=PŒ1uÅšÒ]HÊ”[¦ÐÜ©Ùô²Ù|äfÓ͆9M×EŠRrº®ÉTÉÎi¥žÿ J\çßÇó“>¯ûˆ`£·U8°nP2ºöÉI3§‘Ú.ž ((u«tÁàªÑ}ä`°á›CG8XW-('©kBŽ'GÍ—€t÷«7|öúÝËbó^ãGlØ ûU)?ðÒè ÷&†“Ù0¢7‚ì†ÊžáÅ«¼‰mµ¯SNXñþ9Xð,pG‹rxs‘ñÈѹb÷æ…Þ¨c²)ï"òHH³Êó¤è p‚¤+q|Oº˜»,¬~…¤ËgÚ`ß¾rˆ–8Þ ÿOý#Ì "OF ŽF¡±sèRœwˆ¥ra‚r2=¯á÷[Þc£ï·}€¡ôWª’’- ²as„hñJÝG 6VÌ[>*´¨}€ë3`•þý®¥÷Ë$ØpÇã‹»pä—‹ù”\¨Ô,ñp]L+[ŸÄ뉱DÂøn 5YR‹(Ÿ1Gªfý7M11ŸÇ;0ÔË|b{’žµ mOŒÓ“U, >xœjE±ßxrÜB`F®?܃iϯ?]ÜùÞ½vè…Ö&£a†%žMnOÃû\%òËœï"å¤[ÿ‘PC6pÂÓQ°DN?øRH±/¨Rú8Hzóy ÿ{m>Zîñªë†˜ª¬þHá¦:6}6”ö«Wñ»*äàuEÙŒn#,m¾Øcè^*m_9n•öP›Q^¶§Î”áéG 0%ǾùÛûxÃX©Dâf_mv^™²[UZº3À›p‰]Ó™¥“GƒÆ!æskúOûQé?¶@ÊrkÅX+EÝÚn³ól©ÂO%>•Fˆ k>ßON§ÍVû²ÑotšÝÓ““Óæóxõñ—Îç›ß¾vÞüä¼þŸ7Ÿ>r~¹£)µÚþúâŸ^vþ»wÞx0Š£À'cpàþìüõ¯£©¹#ðH=…¾¤Ÿ˜ÞO–ɤÿâ/?¾¾ùüš5¬6ç<ûƒCøã_;ÈÆáFÏZÝîsçý/Ÿ÷_Þ¾u^½þéæËÛÏé?”»‰û«„ó[ C|äý¾ð#R“?Ož5›¦OôÛQ义7.Q’&?‰%@ý{‚O3únàÿ>g„ Žž½Šß¼»ùø¿Î¾þ_çŽï9<†Ÿ¢ÃÏø_ÏÿðÜyýþooÞ¿þó›ù<|õ£¨íåÏ7 qÿL©˜Cæô„åÏ4=>Ûâ\³³½©Ù~óþÓëŸ7ï?ÿ’¦ùßoÞ~yýÉyvB Xn"þo|rzÂŽ2{bÿòUË9¤åwWR¡n,R953Å®~”·«LðÚ ƒÜCQĸɆ¿{ð—›÷vÍ˃cïp9ÇtñÎÌõçƒW™ÎiA ]hH]¬—TpæDÞ?–„ðcQ°zÞ§Zr:!¨½…7{ó‘ïi«SCy§­[öŒŽ¨° `°D ˆÆ2ãºÁýn«}ÕE |¾y¶â0%±ÍXyCNŸÑ.’+eê©—âUi0Õ“øýRù{eRñ­Ê+"í˜æ•<½õYz¡ÔÝ)øù“ü 6õ‚…øñ³úClSáÇ;õ‡8ê‡ïùT€JøùIþ̨Ÿðà³ú@óL`ªáüí(Ù×:×Ê%øñ…ÿH'µÕãð|gÄåW$ŒS¸–}ºèwWm±þ“?ó×:1ñvVÞ˜²d0úæËç_oÞ“/ß½~ÿAya,˜óy©RËR¥âå(-«^ǾV±aÑå VQ’.2aœ0ÊÊȆÊ^ˆ2Êk™n"o‘åËŸ?@áösg9ýÛ9MëGôBa¹åí×dJSÛ¢MÉ® ­×x.êEh:)3E¦áÌ£j¡ÖRº\Þr‹\ò ÿ‘çôá\{ÈÉöŒÿ•]˜u.üs«þ•ZÈ_¥›Dmo“ÿ=ù9Œ"ب9¬ Y¦?Oý˜ I=8ðGÿã„ò§ÎìÞ=›²ÿû·¯Ñ×ù-ýÄy—‘ó[8Ĉ·YQÀŸxçPþŸrìDdKño¤…æUë¼ÙëŸ7Λ$½f«×¹ìÁVâô¤Ñ¼ E`9899±â ,GÛÚE’‰ê†I ²Ìÿ"#3,ÿgIíŠÃÖ®Bñ™_©ö˜¨¨UÀY¾RÒðS¦v]*'š¬-©. P¼RÚ¦üØâFI»w½5^V›dLÍpºÌ Y7‰º rSª,n'äòb\,@»Ž³úåý›ÿúòš¡1vóý·tÛµƒnšÎzO¨jI˜üçÏïÞˆ#°×‚ÿ>?}FþýiüMž:Å.Xo‘i²XÀ*V¶J#57•SÆ^ûõŒò+µ¢®ÂTBTŽšÌ^Ø Ny§OY$®@Œ ­$ëGö“"¶ìoˆ-5~$IŸž6l *È—mõaWò¨£>"ïáË.0²^YO}ÔÄÊ.ÕGø¥•ǃ0o‡Ã±¥ŠüíÝ¡.^†k7§™ç­ˆDëïÑ*„==•Ý8ÝÍ‚GtKÐ,·2¥¼-:©å6cå6v+Ïtâ4µCP· 7Ú š¨â*xÿªsÙᄵuòf¿Õêâƒ-Ñh6Ú]†Lk¿jRph‰-Z¢-OlÌ€Gõ4\ñVBm2>ÑŲÝÊ“Ê$(«û(6HióÕ¹A¶¾ù‰×Æ.Œµs÷οu¡DÙx¯þø<õù–¹¦ÄÎ" ïü1Q]†Î+4Mâ®Ï¥Å”H„ôï˜w?YI¡'öïÜy“@ée¼$Øô€_…sò–D{,X\I=¤-²N…sj!w0õ9­jI>š'þ ïظâSÞ‰p’xsg&žÃN!á¶“;ç³pÓ/ÎO›ž°¤ëgX9ôúÛ1þFC1m€T1vHW¡÷âÍãqíÀÅlF‹ßHgcžð’ɶ˜RàÆI¤ûy p& ãE"ÃèZ“÷á2 ´&­¸CÒ0úÐFÃÈ /Æð‰?q,OÒãÀVáryýŒÄ»%=#$ôG!,ÎÆ(qÆ™”€Q:$}À±±zF fX‹:ؼ8†kf!LÄÔëC´oï…#ÏvT\¥¹•°aT6 , >I/;èÕTa¯…ËýJ-TA¹N=ÕJ«ò–Ï©œéFþxìÍKZ I;^DP¡dñ©KØeêã¨B ÂäeOåÄ&£Pk{ ˜ˆR•Š þe{±hVá¤E«Rév¥ÒJ¥»•J÷*•¾¬Tº_©ôU•Òô¼f¥s^ÄÅòL„³¥€Î(w§ªF!¾Àg5ÊØT~ÕôSŠE§’÷OuÉIW‡N;q¦’&ü§ÿiÃ:ðŸ.ü§ÿ¹„ÿôá?WJ…J=Ó~⨠7ÉÍfg3ê[ ŒÚXÐO†n2šžÈñTÉàΠ$ýß&ûÿÔÿÂ:®VÝ‚ªÑÍæDþ{#ÜçLðÚ¯ð¿­â6ÚМOžˆ^Ò“îch×ßúƒð–Læ‰òÇÛðÖ¡‡€ Ð6:Åmt¡(ŽÏŸ'ê_?}r&ž7.1”nq3p.qJã‰øÎRw4 —¥èÕ+nä’ÏÇÅŸN”?JT~Y\yì-Ü[l¶ Òp’ýý’þåÌ(7ä5ÛÂÿï5{cbAª¨þ š c¢ÒŸ™&õ^´ÙPG*Ø9õ›1:ÑÐçDíqžGÏôYp“$ò‡†„k&”š¿Ãïéñhö_ObÕ]ä»I@Ïšœ|ÍâÑ4S¸ãñ‰öçKô;rFv™•€ƒÿ-;MvÈ®ƒž°›ÛòİóJR³­6—8N2?ñvV…fKàTŠVp‡]'™Ÿ?÷ä8¼Ÿƒ#o™vK`W³+9\KNR?~fÏl(yŹ(`™–z²%²ß #ê‹•úýQ¾©$]pûù»ïÝ;¬.g…3‡v\lbuÈpøaœ%¤5ÊI—/ƒ™ñ]Êñ¡¯þIú×'"›þðç·•GØîKß16÷BÞÉðÂot|dµ â2BŸAëÌp°æ±tO pP{K`¤u»¥UýÆ~ŒGHdØŒB{gà äõ2 3]½ù Ÿ Mÿ·Í ÝjP  œŸ’Ož8#¸Ê‹Y¤šÔ*ü¦@V£3ö&þœ™óߎà¦]0ÂŽq„êþ$û˜oWŠ ‘´úâ??±ªq`]¥þ;Ù/ã)šK–K ¼S0ð.ൺ˜Ð'ægè±Z}>/¯èúBóÏ;÷`9eP˜žê.žÁº©Jì½!¼+läÝZÑZý%Œ.ô=Ó´ÏŸ-£ÀÀÛÚ»—ðÃùòñí ­¯ç.XîÉœƒl£‡š¨qï öôq}§p¡hš–çܳmµEB ¨·|íe®r.óAgpWÆdéKoYbÐ Tþ û†A3c€ñ¡j!¨<¡ $žâP)ÓíDùÝSzpý‚Á]ÎÌqftü)ߊRÕ¨–Äe²«%s8|" Už:ÔñÈ €µ» ¦Ÿ‚ÒÖLVÜe‚+Ä„9™ªËߩ“¸·ñ¹sÄ!};è\P.œ8ô÷Lø{°A”"_²Õ¾4‘]ÇÊ’O¾xKÿ¢{çÀ[Å^ÕìöÒ+R©• žPçïnäƒÏ{àŒˆŠTL4Q §¶.ô°c›ÑÉăó1‚i1iÇ¥«y¼$¬ëbyÒä)¬zx¬ó°Q=uÎÏÏm+~3EáÍ®ÝÏì\à@ëÄø®¬­@H¼LÇq\ÓâRnC§)Ÿ s¬»¤œ«áí,yatëÎý*qBóÌ#bsÓ.ÐÛWYÑ)NÓH<}'ßWS~/»w<>1ƪ¸£¹„䎰cTú^„è3Ô>ýå½h5æh4ƒf1HFS7ê¦ye1ÞHœ—Ÿ>áßÿñÉ’ïý1Q Ëgþ?‹í’)<ê¨FfÚˆE(1óãX3á^|ЋU[äaU{åA˜î)¦@n0‰ 8‚Éq”†‘px³¢ŒýªÓ,|˲ <ËXŸmo?ÝŽ£–®¸ª©@;'ïÐ# ¹F6ÏËlàÍo“é)»n¤ÀÇY¾†ÞÔ#VÅ©ØCÓ°)°¨Ñ}µG){®2›¬N°Ó6Ð1Šã³Å’¬©ñT]Ú¬¯áàZ/_Mµniú>v꘷€Œ”x/â½­Fð@XÏÀÙjŒ/(ʼnþ² ‚3ðï*E§ͺƒnü`(íÁZ¦³O>Â_ åOü:%NÞ:ÝŒÉ:Ìš¬Ù£á*ßæ¶jnï¤S_Õ ’[ …vŒZ(¬gÊ [æ %ð0)õQEÀGÕt iXÕ³$¥NE’aSoçx©´!wž¶×Ÿ: ï4ãpíŒy)Ø/PC;F5©~ÌDBÍˤ¡Ò/õQµÕ ·ü¿y’8ád>½½R70Óχc»Ñ7ðŸöËC:zc§®úáðµQX¢§ºôùj»»¿á¥áX­Èq‡DÏÖËpÁm ¨«ÏÀ+™,ÎÈ>…(åáA¡ÃÌ'CV;¤‰¼O,?‹·ÕÎ7¡¡;[êL.O˜ bĈtƒF•$0x%Àø’;Ðn#…™E?ýGW_ìQ1”K·èñå*vN*w­p¨!N’X˜´’sÌ`G{¯ d?DM!l·`©èfÃ̱zj\¨úÐ…‚ÀÞ©<  wÊ ¡@½ë¢‹ˆâ[’:ÂÒ‰W9Ë,ã­.Ôœßr;Ý2q91>¯Jµ\ bt;Ù–õ“œÔÃr †l¿ÀfÖí¦ÛçwÏäËRhÝ^ºñŒ{2µø›-XL»—éf5ƒƒú„¿(ÕlÁ‚Õí§›ÕίÔ'ób¿FÙlÁѽJ7›² ëÏ;p™Æ @»×H7®¡’ú„¿(Ól¯ {M0ìYl›¨°ç¼*èDçTš{ÍÜ^´à,×~ò|1šz ¼å•'ÔŽø¦LIó½VnÛàRaqü¸àÞUÅÒTD.•¤¯îø4À1óù(Ýã6ô)¯ÇðÈ:5:k{+ûYfa]C'„^'·kY À3q?Fá<ëë—ü—S{.¡é|èÁá¢õìôÜP–‹ì4Jh‡¬Žü°”È4 'yý¼´Ì®8iÌyÅ|}+OêenúyP’ê–ý=뛯ªTÁ™~n¯Àó+ãÅ–îœé ë<-ÕêdÖ»ÊëÎ%š2 îm{ŽÓð¤lGH#—¹LÙ4ÓÅБe¦#Õ(r™»\¶`gÜ“^,¦R쌯>üü¡§à^ñ2î/Û`Ì3‘’>èŽÉE¥>Ò¿œ”º¸»h¦¼ÌÅúËNÞêF ²µ/MâýGoÞ-~—ì®D—¹pÙµÏj´œŸ"Å¢eÿq9wxѲ“ÜÍíWÏÞ¯ø­KôÕ§ÿz[¥#¹`~y™7}ƒLʘ¡Ã)E—¨´“¿¼9ü@5ÝùmL»<\2ç®éæ¥Ë^JÉ5X0x£*ãÉnèã•eQ…Ø?¿¥-EéwÿáÞ¹Ÿ0<„ƒ^€?‘Õ«Âòz™»Xôp:h:Ƥ=`)?ÒÔ3î•íiµŸKµ¾tKÇ$ dŽþ$ÔõG4%ÊÂãû0*sí¦_Âõªß²’f9g^#ô1•ûŸU¡TîªÒ4Ù…OòßY²Œ—!b‰;SýŽ¥o4먹oâ=q™î•8àéw-݃SBsçØ›üQ™ž”¸9Úï#B£ô„‹ËHçJ-Íf}èC^/s{¨iuÖ×z^Æ*}Ë]úýܾ!ZätŽ¿O¥VªÒ½ÜBÿÊØ=eÒ‚ëlQµØ;¢ƒtÁj˜{—»\5Šz—Ž}SÐÁthœR}¼Ê«fQ³Ñm z™ ~S®Ÿ¹[+¼+2a¤î¤Ùžß(?EÆ›ÀrUâ²,ÝΜÓaœóŒ&ÊŸ~ôFà‘F~8äßÈ_Å“‰»ñ _7¸«‚—Ö<8CÏ›£G]Žû)°8Š»*°å_uLnü 5m/>«¯t«\íN\t •a²«×UÏÀdÔOélìÍ}oœa¶ôÛÏáÂùzÂ|›èÓ¯'Ì‹»òÄ`^d?[•γN£?/&}—?øKÃàÁál&gÈ‘}æ5>:.@H2|¼Æø{rü–:’(8Y¹Êœ¬èø¢=¯Ê4\®\eW2òž~Z^e ŽXšøØZ<‘S”°¾Ngš¨¾Çîe®Ïpge¢>ƒ§¿;¡´Ÿ;Á‡äç<8àDoÜdÒ¢‡j™%n9CoôŒ‹§.D&žR':¨Ëc×ø#Ï=9ñ’?Þ>Ðë—9\'í®—HÛ\Ò7 ’‡ Žb×È>EãÓ•ã€6SÐà³eQºb|…›zÀâÒ†;\èr·„ÍF;¯G˜÷”ÃqTÚK¬zsM‹ÍF§°ƒjbւަЦR3Wêv®Í±Ùè8ŽFìʺ=Éç7w„áP”²Õ¯ Ú}ŸÜtÒK\^páäÌÙu–#‡Mÿ N·š1gpu;Éþþ@ÿ©è÷rkÙóƒ7û ÔóÃù㔀Ќ F‡Ç9¶Ë`ÌZVˆàÒÅZ4ŒÀ¯q°›…è$'=©¾ #ŠêÝ®bé•èÎÒ%$<¤Ðá‘;iàÎ{oHcwþøÀ}–NYßDÿQ¯&¯C2°4Ó€`QH êÍ^Ÿ–`®Þcî‘ÌýÜü¹Ÿø.ÜŽ›yEÊdž`º ô¹fãRŸQ¤ê‰áÁ'öoEýÝo2fUeæa½‚ €¹S).ÓÂ4ÒyEç8o~‹×ÿÙ$q’“…ðC„'¼<™a®}´VωÒ4â.d8”I8ç¼=Ã0¨l“äÌ †)Y*‡ :1¦wÓŒIgßÄ é2ÈÁdsL9 ¸¥ù€ö–ÝÉ¢ë»;ô?A?é_êa`eX¦8M#£R(:1?“/ËhaP{AóWTfN¹zØÞ’­Ü’Ð>®âêAAú×ÅfÃvî|s”,x-@´j l1Ÿj8·ö6¹”½—(PªWEúTS†5´"m-*Uê‚4 ~V&@–K•⦊Uè¢Éðž™ÊÜ^ldÖ Ž\%¦°–:™F ÖÓz¥Ó!›ÊÐÿ€'Õ-Ù6ûJdêUâ/U­¿1U6ñËVó7—͉&2$—ì"ÏŽ\¶x…XÏX¶*ÉèG ÍÊ}Ed©AñXµj2ùuFãÙ—KÖV:ú3\Öÿ•m·ÍéP¦d\\ä©gø’²Já‡gê¯-eà bâ"žÐLmô—¥Óæú#ÍFŽW×y–xøDzô£ñ´Ž¸î2Àbƒ…¾4b¶Ž¿'©°¸4c\w"žðc[Ó‘þ#“Xc}åP¡î‘ÐA é(³¦Æ©3Äx¬ Õ• EH FÀ˜'|°*Ä€Z ˆ+¦€º r ÐñR0-^øåi;=ðl$­Ô¸k ‘…U+¤¡.øß"°¬ë‡¦õÜù›pßÉb°áâä3Æbôc¢:wÌ„3=»…û&¥g³Õ—"²"TßßÍÑ¡©ÐØH´ªÂ4îßdJ‡ÎÚTzÞÆH€Q( †áïÚ`áèmî»u;ðEvÎÍ C5g>JŒ»ÛÊ _Õ’?—ÞÌü¹œb&ŒÔÒfõ/˜¯9NÆ/átðë¿C2åÑ$Î<¯'5–ÀY*­EiFùóœ¥`%ª¡y}›”æ~@{v“´ù›B›‚ J€á"!œj›•Sg,}8–† yøŸ±3èç›Þ %ºUV-ëd¹JÓÉ(o¥7J=ø(·µGæãNêéî¤Ê.&–,^[WÆÏÖ]÷QêÚ$é Äj+éßÄrW»í¯iÖlàü¦ºƒÒñí·…Eë4ä^9ºó×ÙZLœÊB.õ.ÚûÇ¢;‹ÑÕTL›2°'û¼¬2¾“ƒ5ê¨{ÿþþ oïü9º¦ÝFîÃVvv«©ÔÞérÞ²»ýZÖç'¿Ê­e%SÏ$2»¢Õ0¿Î»Î~þ÷Û² V¢àøãË-’®¶F¾ãè^óV“<œ{A௱n´Íë†a¯ÉXVŽ>Ê+-RmíxtgcÌJ]z§ǸÖt+ì;ýß=mß¹ÎnÓ´L¤D×9Á-BŒ{exë¸k<î¿VÙ5ª«C†­*®r¦ïË®r¥vg;£R–$â™Ú#–Z2SKÀŠ‹¦\Üj^6Ëx:\&ÉZoÅ>%²åÏ<ŸYꉯ›Ÿ’:}ÌKg‹/ãS“? Ù¯Á©0uFŒ0ì7©Ï‹7m¤=®bO{«ÍwBA•¼HÔÚªy‘è_î‹$‡µz‘h°¼ÚZöA]qêXÍX½"ã(^1ŽÂWt Šg¬ƒxix“cx*S™É~«ÈÒtøS🪥ÃSjµ#Yà¶#ÓŠÔ5ù·Äw}Þ ?s,¸ƒ¾€÷mÇàY\&®²^1^ýQ»Íª7›­W¡!sÄß…+ êØÄ*[ˆ%¡dcŸQ>ƒWð”1Z,&"úm†Çøbµ§ðWñ°‹‡“e‰XòÞѪ´Éa5 iÆËöä¢Vµ2R6x&yG¬éu¡4È!+‹V(Øk2m¤°·†Hžu U:`çi²ò²˜« ÜûR´…­“x"¢è–©'$°Õæ­aW(ç±(âÊ1œ=úi-+ylÅ-@€A iƒ€VIpVï\7³’b¼ÔXnðŸd7 èÚ­8p‘à¸`Èèì¤ / óQ¸ÌVŽü¾7mš~fÜÒ0«»ÀŠù•Ó|_öZ´#}çt20JA kû=É5i¡„Bß-MŒ>Uù‘íóð°*-Dløm¢•%Ä@tbU6Q£Ùç+m+ÓgÛ S‚N¹¬Sô¿&ÙD7I}'Ä(ÂNž”Ð{gSžjƸUs™®G³ š'}H—ºü²Fdþ„£Â(oãÇ«ÿ{yL{¼ú<´=Ú¯þoèê¾ù&o™£ŒY22@v6®ƒâ¬ºÂT_qŽqŽqŽqKœ€uWRaJ®åƒ ¬ºdb Ôµ:888îÑwv *°Ý ë.¼%b”\v3‘ê^tƒpènï©À@»:™pNœ9§Öè×§W:†AmÆÚcƒ2ÊÇ1ˆèù1ˆÁ1ˆÁ“ b°î¢\ã äbS2ÒÁÊKL&àAõEæñàñàñ`ü¸¥Ýìâ{Œx°oÖ]_ËD(»Â– ‹°êkŠŽ° ¿›cx„cx„£§ÍqÉ;†GØ×ðµxÚGO(¹ðUˆ¡Pbé{8£…K˜w1ÂlµdƒÃ‡¨^K3ˆ¯Oä¿?>8¢ aL­ŠcJܸDÊÀºAÚFÄz±îz ·”Kù 3Ä*ÏÏ){ð’þ“%§jÕ»lÙÌÀÊæ¹”`«˜3sçäƒ}¨^)x‡/ôðìsðƒ‡ÕµrŽKž¶™­lÅ´h¦NYx’uF¾B v4†2ɶú’U“2^i%.½òZÃ…öy‚ÍÊ?–Þ2{µäÿ–¡Ç…»€óeŽŸ*F ÓÆÛù𹥕íù «ƒ¿W!Çܻߋ¬6èËaà“%z,𱬭8ô9…š¢1÷ô1ÃW|Àù÷÷ú\×ã€ÈuY«Ô°½È¡JÌß}ïþÅå%„^··‚†ÆP1þ§ gn¯L™§LêZ°*j·>„:2§­z¤¤)C^;CoJ÷0:uâåh qÏ%rÈžù6™‚ôK?‚¢‹Èƒ{Ú1ù†tÙãUœ 8¢™Íp‚¯b'Ä=3‰H›¸\ÔAö‹È«7GsîL´™™°(wò³yX‹ºþ‘þå,¼ˆm’äD™õ ¤›Ä[z‹hÔI]‰¡Š<µ²¬ Ÿ¨Wà²ašFøÍÚ[àÇþ‡² iÒndh]Á'7ÎÞì/PÿäÂâþÌÜl ÐQ¸wèb™8 £VÈ'Ü%DèH¦áï“-”‹ƒÐBCµÁO0ŠD3ÊV 䤎ÜÈ  ½úœ0™”+wî. Ãeâ€AbáGD\\çÞât‡(¯ÌÁî”õMôß!‘ס(IèJçÎ'†‘®ø´Ûй$r$³ø.dŸyT0]§^@7…–´©Ó@^Â*Ô”ÄǃÀzØN~…ûìóa8~H¦Oò\ùúð£(Ú¡VËÁ}¼-çi³L3¹“ª»OYÆŸøÞ8õª‡VˆÑ7å…´…‘;0ñç÷!W…îý§PœYØ^\J¢K'›^[°[º`³Ð7z’£ˆEü‘‰x*@‘¾âlBÖY¸£ã~”ï£|×*ßëwÁë×T.ó­‹+=²ðÞ <ž @O³¯>‰W•E¾}Õ"¯Š³Uæ\ ââ="y‚.(BN¥ƒ‘­.l¹sŒÏì À¦^»ó9áã*cºýe@ö·Û³Àÿ桨û¤Ò™û€¾­Cö ]‡0®€>NŠ &øH—A|[!ƒ‘ªÊ£í-˵b,ëýÀO€ª°m(t3 ¨ü_jSÀÅúû·fU«?¼}ÁFŽ0r„ #…”œojçA›9ˆ­ÇBŽr„4„©!EïëßÝ\ð¿»:L4¯²£DãC{ˆTí,µÜ‘LÇg zTK$¿¨Ös™™ƒºe &ž7ŽS:ͧ‰™þ~üôÉѤÎé±Xê£ÞÃñ–-£¬ßO=R†>ˆx.ƒ1`Jh|AÏã‹É2Îï÷UâAò1$îïá<œ•ØL§Oìù—ehŒ‡ƒüÇú.¹Ã%Y&|s0cC'?Ë? n/‰{{‹­#‚Ù·þ‰l@të#’‘ËMQxàm;èæŠ?JÑ1¨†Þææ#~(½:ÕõøèYª“jfÜñÏœÁÆ8(t³Áo T©U é. ­RPÔLZGÒØR¬t¯€×òfÝþ Ò:°‘åûÛ¬L»lŽÃà<5yHUª–\|V¤)p£¤ÚfñQŸ+x¯LØ×Œ/®­/€õ´al„aÄe·6yí%R¤é`Î‘æ  ±3˜C½ZA ›’äUÑ¿»UìZ)õë‰Mxgò`´´<¥†ƒ4pP­t,™ c*ˆI.#h›A#Ø0”ЄK˜På—PÌ*Î÷½å¥^ªõ™U/êÈ6|ÐÚ&{üù(XŽa#ÏcrÓ{Z§Š³ìmg!UÔ¼ddö}+³…Âwå²>­j1xªÿpjŸD«í‚tE‚”L¿±6Uy•ícÞxÁÚQb„åÜ¡2¼I¡.9š?>kîgú* øW²çPÿc”r|ËóŽÖØù¬ÛÊn®´Æù¿yÐ^b,`Wcáó×KÉÛ› o^þµæˆÆ`èÜÕxxãüß5Ç2ñR»Œh]ü±æpê°òƒamOU4[y ³RÉŽ73™Ìª»þ@Ê]éØÌ@XÛóâ l%B€»Šh]ü±æpÊ,73 ¥}õÏõµ\Àù] I´.þXw8ñî ™µÍþY} ‘·£¤ÌÝ¥+9 <`_~]ã§lü£ø+}‹·©™C›qÈÚJ"C<@ {-ÕmS^íV9.`m]Ðqž½¹ï•É­›OÔI¸H}Õ–_Ñ–L‡¶.}Î×ýóÇ‹¢02’ÑVÖyÖi´ãç™Ý(všþ7—T%µ­R$RŽÍöt£½ìÝÈ~¦mºw‡N´x´>uï mø,xp†ž7‡¯o½q6}VY `õúÈû’&¯z`Í:˜Î1²yå%®`” ÈðÙVàJ À™ž?÷Æ–tñ9C¼)9i×lé<Öœ©@!)`Ìí¨tás‰Þ7¾sç#ðØi<£Ãd ¨‡ººA‚H÷w¶¬Ÿ@eIW^–D쪊âd]jhžy#¢^÷fâðwsöºÇ6Þ¨l¨èh ë &nJrø RMvÎZù¤£ÅÔ-¡:W"EäÍjhÝ9ªƒ½7±GÖPZ àç¶VF\Q4«œ)…‹ #YOoô¥kPá2§~e1ŹŸ†÷tþÕå펺þ çß ¿IÓ]%…]æ& ­—#´ÖÙ—ðÃùòñmzIz=GíPqìÇøçHµ,Jk.¥µ7)á”ø-µÐm,þ§¡xHÕp!2¯AA‚\¥ÜÔ{ÐÃÎVæx¡öYGý/7ëj__¹ mÌ~«óž WØ!~oˆ€«úñ)D$¸÷‚ƒvÁUì˜q¸Sûg8_‹MDç/@Z—°ÜHjŠŠ@ÚÐ)°Žx¼žY@4ˆ–Â3ºØâ-޶â»0](ÇzÙ~¿†'ŽúÄNå>Ï bzQŒÙK¥÷[§Ñ¾è4:ü…Â~þ@ŸÊ¦ÖáBˆá~VúÌ·öš¤vc¹t×ûûù夎Š)½?¹¡ï§\£ ¸‰ÆP“A•ò¹¡f…Húƒã‚²Ž#ç'+“•h…­û°‡iy¦9ðmlY×ÞÌËÄ¡g}†p†lï´áÎ}>~1|p`<1\R¤µAÈyɼ|…Ð÷çÏïÞ›øÜ¹ â>Va(N˜µìŒÝVóágHOŸ³J‘>}³¦Ù—Ô¢C^u·¤O‘6¬bË•Ôq“±Ç–ñ*—¡J3þ®B-mçºmºÉÒ©÷>Ì3mõR˜ÁÕ\“nºïüž°Ú:ô*uOu%R…ÑÝ,¶M+lw¤ú蹦Ò0³Vk-z•rL_ƒcr,r°¾/t_Y@6!\ec¯¬±ˆâ»F&Úh¾µ/ÓAf¢2¤6Œ.yëesŪ¼RꔤAü8-$a|+M£µõJª­Øë@9Å5Ýç73´ð‰ßšò5 ÃØ#z«?š:¾Z´X2NÇÇÛÈÔ Gž=Ò“¢ñ²ÒY=ª‚ î<õîÈñXÅÅ^J†®¼¥Q/ŠÀ˺ºi[ý SšÏž;w#?\ŠÎÈ;Q¸$]§»Øî3/9î÷:c2!Ú.Ñ„ÇÄèf×ÅyCRž4y æ2:ÞÌõƒSçüüÜtS©úl”vʯ‡åáu3¢p`:´N—èë+FGÎcá”bƒé…o••ÈÜ}žú¸ù€3Ð$œ«!)ãd!µÌˆ~¶œ!0pz£o¤ Ü T®Õ~%GtÖƒ/ç¢RÎ!‡Sç–¬À ¬‡`µòñz+žjAýzNˆ"2µt¾S>.ïP E>7ñ—¡c ©+(å^yš˜HR‡¬r1Ù…Œ0*šR#2\† ‡ÿØi†nžZW:µæÞýZ¶RŒwë#û7à‰§«ˆlTá›5iP6r_½l#‰R¶²ÃÀ ðä¤À¯Ä€—5Mº2¥“®¯µ{C¹›ÿ4fï¢öhªšÇ4è7Ô‹[œ^Õ<ÈïÍùd%vÀ‚åÂT§Ð€Vl2Ïh42‘pzdM8¸Ê Ëz®0L^õ*} ߦØcí±–ô»ž„£&’%G&ܯMäõ¾2»“6ëë‰}m8—c*.}x¢Õ8´’®ÄkÁZ>.Ï¢ÄøVφš×*ktžÖœî*„öÄi중{WðÔip@ÈCy¸Y …ÂJs¨ñ(­îÊã’ÏÒ¯óå´éÔ—»¥ ÛPÉÁ ôŽeûòþ½Ž¡²c¢Ä_ÈÅNc~v~Ȉ緆iÐë€ÐpÜÂ~Ò®µƾé‡TzÏ‚ð6\¦˜ÇôZô@‹E_ŠÒ²)^¼ oúW&j”"ô•Ì3Û‘!-º3e¨rÀ–fC_-™c ަ–KáÍf¼ÙLuT( æÄ-6ó¢ÚGïšfÖ»FÄ…‚Q+–qجŽ&?²¿hƘ!„ÕÑe˜î®=¹rR/ÃogÙ)ãð²êÈé/ëð6«¥%ÐG¨Ù´5ÆÁqYL…ªW!äã*è‡Í ÏS&€–8[úãwaU5µpÇX8 nt«Úi1â¸]×e /¹­@tö݃2lA(«ÕÀ&—$Vƒ3•»QñhG·)`µl700Ù%¸M!ÝãR  †Ÿ¶)0=}ÙiÇh†¦©ñkÊïŸfîB,ã@†?ùó±÷; þ»J6h§ˆ-òL‚'ÄvÓCµÑ_HÛg*4›0Áú¬ ZܤÀÁ)ŸæýMÖtË”lJ¢Ú:‰ŽÖlñ —Qˆk´vô”¿Ršš¥­?[YJ‰ò—»áÇáà[´š`?ÙRÂOÀBؤ¬Ç. 7Ž!Od¹Žåžp .[`fÔæNôþ±ôˆ*9÷î¥ñ5€i§O›ùSÃv:ÿœ¾Í‡Ák°…íµa$éu}ÅÄ^BøOloså‰d *P¤LÁ0´u²>q@î6¢œMÑÿo³ÿǸC­³Ïzõ~e'®‚<¼øÃ«¿|p>ßüøöµóæ'çõÿ¼ùôù“ó+èù¿¾øÃ§×Ÿ¿Æî7ŒâÁ(ðaSÿógç¯%[ïÈÁ¬’^°—ôÓòÉ2™ô_üáåÇ×7Ÿ_³&iCγ?8äOü+¡äY³ñÜYÎcÿb½ÿå³óþËÛ·ÎÍ—Ï¿ Þ¼'Ÿ¿{ýþó)|q—ÿÅ«×?Ý|yûÙ9iœ`qHŸò«sçFпgíÖsCQZ2pç·KB%Yº™S•'Y´ÕíÚË.E—›¦B¬§4\J^Á&-È6ª%ª¤†’R%é¾²DIš¼È+Q’0!-S4&{åo% & “)¹ó8(Չ߼»ùø¿Î¾þ_ç2æsxüåý›ÿúòŸRÞ{†ÿà;|ˆÛcAég‚èé|Öž‰ L•ôz&i—*è?àÌòLÌÇ)g Ôôé€ÊÁ3^è” Æ©§ü‚&FæPFgåŸuž§ ób™×KJ¬¥Ö¿gô_屜¦gÊçxî¼~ÿ·7ï_ÿùÍ|¾ú1îŠI|ùóÍGC¦x“Hih{ñ‡7ï?½þøÙyóþó/›þ~óöËëOÎ3ÜA*ö¸ŸÜyâ³:ì!h¶Ú½þUç²ÑPÿl‘7 ú¿d}Á=™RÑÍœF¬ŸØ*l6û­VWýS¯° ªŸ±gÌ€×]õš}õO½"Œé Tô ̳ÎŒz>jbŒf£ÝUÿTkÊ[U˜ °µÅ…·WjICÆmµâD–ƒYÉ…à–pv‚Êü¯NâÏ •v©>á‡ô¸l¥Oéf·Ú§Y@Á 9ÙÄc­ø ž/öÀßä‘Ò&¨Cp+"Š Qá,9ƒ”¦Î㺇A¼"“_­ëý·PÎ:µË%„<:Ñ£&Ÿ ¢c<¢yõ„Àþ”Tçp¡emÓJ¬íŠÆèô.s§—º0B‘Óù+DîÖ'¿Ùêç9š–?ˆ„ÀÕ¥Ü-=Š*êë|ëþyª†âxQnv““#}‚N]¯9éÇî¨Ùòºno8lvG£q»í] ɳ¸l_µÎ›½þyã¼)Œa­ËK~I*]]¶‡­ÎU«uÕé{î°Õm»Íqc2l5&½aÓXIë²ÑkòJšP¢ç¶GcÏóÆWMw<îýÿí]ë“Û6’ÿ~…*W¾qªæA€ïÉ&ÇYoR•ìºìäê>¸JHPbF#*¤4ΤÎÿû¢ J¤Dj$ÅŠ•Lj<ˆþ¡ÐM|Û‹èÈM˜Ísë…вÇ­M¸S\ûÙJO=ÿ/wš£‚¿þª ½X;Læ“Á¤Küæ:T#|Çö;ñN<Æ©'ó‰ãÛ,¶„ðÆF–ëÇ §Ï}›xVäG¶ï¸±MË=2#7$–Ófzzn­p:[ ZœÑQ±0s‡OŠR2$×Ä¥×a ~ý¡ïY Ì£QHF¾ŽF,ñ\—[4ˆiD]:r;lúŠ íê+D!Ñû¿÷r—ˆ +*E~úÛè·;õEVÙ·Ë m£ ¿Ý=0âÎâñ2sKÔë>äoFíæÌ¶+3·ÊB<{I(«’rÎôô°…ôHÚ}jý‹P`KG§´Û7Õë '“<[Ô *›¬£,[€Ç.B¹2ùž ³I™[Z<¼¦LWj“ÿ{¡Õ;S5ñÑB¼„«ÔêdHµe›ÐÏË­ã—ºÚ˦¬F£›3W  :ü¸ ºjiüÐÇ`Øxœó1òϸ¼–oá¬NùìBQiàß+”íBÊZp–$+4GÈѽûìE™[>#è+¨4ñáC×7B˜ãÇY¬”=‰þæíÛËÁ›o_É9í 1ÆóôÅç×X„=¢;éÓC*z ñ ¯Ê¸9eBÕÙð¾Ø»&Vye¹,ÂÆ7¿WÅçÙ¯SGË`ó1ŽûUÛ…¼rÝУ$Ï(¶}Îg1ŸE)ÿ“£ŠJ¯ß-Ì7è‹p"K…F9×öµ‹g¾À¬¢1Dïýòo…ÞÖA+w¤·`5|ÙÚÑò(’žJ£Â(ûÍ laV” F Çòl ¡e'2‚Fs;dÊókü‡lŒj€{2™#oÀ š*c¹ƒ;Îç`ã¬H§ÈK‚ë–S–‹;¹ƒ^9×}ÏG*ê8„°ÀÈŸ‚äÄÈÈÅrq„ÿ÷ãWo^¿D$¡®3šÍ,»Ã?Žân&Ù60¡Ý Ð–èÁZZš%· 1É“”ç À=óeˆŒ9†îc§BOÁ¿dxÛ { Ù6`F*Ì`C±~ne,&x„P‡…@ƒˆç èðàÌb Ô´¿à5Ü<˲[¡ó‘~˜w›N¹ÂpªFX8Q‹EѲ(óåhš“JÝ<'›-Ä4CÿšÀპBÒWj#‹6À†<§•ÅtÀX£l1P ÀÄ0s±ë}Kc¸(— Ï<·»°Ä(^W/·IIô9´à±=ó†[DÅR/nˆ³ ¸ê˜g¼Ö—Éû~AÛ^a¾ \ŸûÀHs™¬4HÄ”J ‘1s>g*G"AÂÔîPØU†*8á®ÿÁÍw"W;–6| “(¹OqðžŒ9À8KFê”ElÊÕO…‹¼ïÉgŽN±‚Þò^ÄbÜÒ.o”òv9‹$Éa Fè1Tí™CíÎ*§  4OXa¾ËB‹\î“ôÙà³1( gÄqˆFŠ*´á®?þ(rmÕÁ”š©™n«Lÿ0B¼ÎØC:–èâ×Áª9Ö-ÁQ;ûz‚õ/‘kX^V¹¯/ƒ]vÅrtŸ.Àj©Kµi/6ÌÐ:öíYmÈ2‘3ÕO›¼ßA¢þ[düþÛ “‚àv}&>E߀⢌¬,˜²´ëítæ¼ÓEjÎüS¡w;'_‹líÑ&„r\—üüæ‡óœZ¢1™Ãÿ“yO(ð^÷ZÍ·¶¨û ~?â1hû1y[ÌÒùœË¹´üM—°psÆ qbÿH‰»]¸f£±Ã•æaž/´.b¬¼Ÿð™!Ö&¬ ‰Gjuí ‚”M§øÇ)¯UýAÙÚA ÝŠ‘*L@Ács\yyÈ3¡!Äi’ð\*0wH3¾<„ Ôùûåt‘ÂáŽh’¥B—G7±0ó>Š€J—Æú×€U>ØÁXüZæl×*¼• œ¨b¤Y˜ÕÝ,ŸÂXŸVÕO…¼ßAï{‹· £MV•µþŽ? ·¬Äô@§t›f\(•ÏvQ9Þ–¹7ÀUÙîåÁ†ªJ4ý–Ò󌗊œ K,òÇÀ ïwá&ÌØCn»,­¨ï9C´ÜØ„HÜ7¯:;á6DÖ *!ÕºŠ6Å£ÆQNåRJÝæt6M4¸)12‚õ°,ÁÄö§jm£Mô·õEgˆ#ý£4æž7˜0©Ýàå…“z²Ã.¸ŸTÖvœÐ h.[¹Ø+U%î9ìÍI‹ûK¹Û÷¨– 8– ûCÄ0‡(Ùò×@P>ØA_ÿIæÜ0†Ù&ŸAjµâ,†3˜xÁ†F©l jÓêeã“\¨4VšÌëˆúa_}1¼•Ûtp&\³aÐ3vZÕmó¥«úXÚz«)v¹ Ö c ñT¯Û}2§ã1ò'þšÐâƒøs¶#š› X¤v#”IªèŽ5ͳòVÆ/ˆ8Sn")´#„³ÜŘ3hT?ªò¾e+ä†ýYPéϘw µ£À ûâ–ÊÁS¦G?",J³ %eð·H6œnàÜ/‰Ó©èª-øju§ë§¼^³œC3õcb«âoöþh™”±»Ôl ÂèkJ¨~ÚsA)PnFÓ%¿gy:ãÆå5çÄ£6ú N9Dý[Üð™ ¤\®´œƒúa^_Ë÷kh7[ξ)kÚ2-ù äçìhåRÁU”M—÷ê(€v$‹’ÌYLjÇ:ˆÐV0ád»ª¯4Ú¼?À¡è»B1@@]Mµ)OU—øA܉iWÌG,/aÎáÈk5j½ÛZ"©ÊëØºÕ†q}_Íøtš–¥z¡î÷fp×)TÕ´‹(·‡ˆJç5õÁÔ¤J@IãU™ÚmDž-‰\ƒÞ:¤ëœÌYÀô0¦&´Ö­zjBMù»Šœ.Ã{M,Í—Åd´\,„ÞU]j‘T=9´¡òuYÓ¹Dµ\Š/›Œ”bÂF4O q…NN²Y§Õ³iò,"þ|Ó¤Á‹{0Mš¥õ3MÖsöÐvÚ<šŠ¾r?—GqjZզ¿ôvß½%ðíª—ÎžPkáajnùµOÐJWâÔ9«í‚Ã…î‰ÖðعâöS¼jã2e77ãöÞý{¨™±h/ÊÀŒÒà&Ãn_^,g#.Šy€á@½ÙØûJ—dÇë‚U•úáZè{vÕ°@4U!àºÔç嫃{n]%F¯Ds r ÓÖvˆhÙëA°wÃ!±­Ç˜~NÚÛOgI¿Z4ilUC¥::¡ú¥›áϹÜÁw¼.PÖ¨Ø6ï›EÀBzvº{h Ÿ0”å>—ßs)«1Ýý—oéazÅ4‹G q<0u… Ë¢–‡QVP\ Åÿ²6¤CÙCõë¹” ŽÝ2ŸÙ4eÇ ÏQÕ¶©«þVäQÇq±è˜Rïù5“wyÞÄ©¢æaUæsü’˪– ~јZBhœ™ðˆÝ6é§ `M]³tˆ¾cµƒ:gEÑr-´!K§õ0ë¡!;Æ(²¼®ç7„+SÉloIÅ;O;€h8Cï˜^íyî¡@ž¶ì·v‰¨ ‚:t¡$«ù#›­ *:•Á{zqî/ÊpБP´nc·3šöP<Ëí!ŸJI iý\_U¯JÀž——FXì»ÏåïÖ© ÷®*v6ú\¨ÿÔîTãÚºDàÊp'ƒ´äYN[B\Ûq„¡ëƨm'nd1‰G!n ˜/¿_#y1Iç×Qv_¯ lo^@Bj•AYˆ«/© Ló#šŠ»¨êØ—`Ýψ²Øq#/â4…~”‹†œj9Ç`2òkøså㦯r‚À)C¹DGÍ \exáSËÒ”Y-ëB/|Øh°ÊÏh™Nãa*—Nð„4<¾ H0ŠC#02ÆìÀJlJ‰ãqlo6æ ˜Cˆóuı@Õ×iDX•ýB&®³çe—m{ØÃƒ ¾BƤ`ì8 ÍËÊÔL¸{D3pæÃ+W £V'í‘âÆTM)#Ç``‘!ÆSƒÕ·`¿…u\Ùôx8MƒNÃû)g³¡P]ËWÄ|•ËÇhx‡Û–£á22”«¨¾`B—Ïól&4@”0é­Œ_åx”¨·E1üµþ¶äùã°XäÒW²½¿Yþ¯µú®Ö$†jCÉP¤˜lë hÊ”*Ìí‹!„B‘5@#«D¸â1œ,ó!lðbi˜ˆ<>ŒtST¢yž>@íwüKò F+ŒãÈ&œØîhÄiè94 #ny.ãV'q@=âIÄl'òÎIb1+²ü$Y6+É çE†qšóB¢ a©¦lÕÍ—`t:èK“ÅýtH$iå uRhX¹~‘öwE_'[°â®¬ Îp¥¨ž@v„NxêúLð+{`Ò,0Ï ׆t9ä¿ÏÙ,n|u/*.¤Ø÷åŠKzëQ\XWSÒ[7Ä%ñ?Á¥qaá’‰xâ∸ppID\\E¸¸ì!.à„è?’P•—ت4Lië¼øø^­7Êðvhù.†ÚÍðÊ)Éò XCÅrÌs‘ïÖyŠ .›ç2Æà:«‚Ãè<ÝJÈ“bãû_^ÃQmà%`el]w¨%!Xu0äO'X@ç|8åB”N0 ì_â @³pYJµ]ÂH$$&™.*-âÖÙl<Ü‚dƒ/E*‹œÀ°’¢òHŠŸa§ïtO–ª’++Á%7-‡Phi¢‚¸ ëWµjYÄF¾ç8fy£:9°m±Ùn[î¸Öþ‘;¢‘ÆŒÈî¢ôöö^ù´Ÿ°žÙô‘®žÙlÜ·aòx[Gêí¼¨V7£Ã!PùVVѶΤö¯ÌØˆÈ dÔ³}æ˜NGÚ—Xª¥€ÐÇÑë›kîÄ—kݨ_rƒgÅø Ù6­£^9m¦-{rþ»%„ý{¶ˆ&q6> xee¯÷]ÍêËÆ„›ñ$±4•4C1šv'¥ò_´%(8ŒW‹¾RvtAàùAëµçJä§V‡‹-]g‹÷õ% ÄB1ËV‘G¬ý ½ª¯+Çpõ¬ä9Bå³^ÁãÁó$ÏîÏðï"<[dŸ_£êƒ{Øa× ¾“{¦ZÕ4©p‰Ì[Ò}¸¸´QúÂäçö榊7lß(îFM®ç“ùߥ3/ùìÔãËJ‡ÛCk¡›Õ¤£Ü:!ω¿•JðžA÷º®tD$Tí´8Øàd‹ÝÓh± -VÎ@DÊx5xwñL>{w1`àØh4èÐúígzcÙÏ3ek`xë9 "„¸Ìþd"Pܤ)IŽŽNªýîÓÛïÔ:ÁÉQÀ{:äQÆ;.wÂŽ¬»Ç“¢ÿt5=áô¨<™ xZ÷µ>³…"„bÅp .Фùàt¨>ðà ¿Ï1Pé8QrëÉô€MÉo™"Æi5žìG@`òA´ÌÑWÜRú×9!2Ð'“ÁFß3l6øþ5¤s+z!=Y’ Y:9{Ÿx“ü^yAÂøup`¿rGŽär>3®ô6¦ü“]WÆ| Àߨ`"f‚_¾û¬üfô®{“st ¯¼­ï>û ìÚ»a_mn1æÞœ¤­½ž˜ÊŠö:Æ<á_¢py+§ƒçÏÐл6¡ªÍ`Uº<-"3TTjëÖeGh :¹²oxœŠÂ¾‚ŸŽ¯ÜcÝÈí;æi¢,Ðܺ‰íâ¥Üw¨Wvs*°Þm¢‚ü:u~§r2 丩*º!=I´V àT£¼ýÑD@—†>ЃY¼*B$ý, ·R¶ˆ{ Žyë] S”çNÐVõ1Ì û¤ÔÇ:]+}1éÌ]˜*íqýÒô¸[;ˆãzÃr€Æ0˜e x‰Î äÇ~qqél—eê=}*‹€ˆb<ù™Œ;“ô„Š*ªéPŠò1ü8ƃA4eE!ÂØûÀû «ÅõÉÝôJÀw¥»i#±lŠ6'Ô)a IA›|93Ê|ÊZ(ßç+äâï(îJß3k뇻xh€Yï)Ö25 vit¿¿Çàâ{†èK‡°ó®?>¤†'J>>šfÅ!>Nf.·¨aª=Í_ŒýÄ>¹©/ªÞV`u¦xs®–&8žer  ‡ÒÞv’“v³h348µŽ(¦c…yxÂ1pA4ÚÖGIüæoö-O+’#.—=YPêK`Y!Á¯§‡’º“NzÕhãÀÜÓ¶OK'­>Ü9ÐŒ ¥üÛTàq0]!O³åF«Š-çÏšŠ±l£m·‘ *ZéGoG hÆé“°‰®M`°·½3--”~hNQ±c>Kåjd8½öÃ:±ÑÌ¢Ž®ÝTH׬sžc¶Y„S#\7%ô\°>ÛÁŸÕ”Úx„iŸÑW:5\îÞô†¬ í±[‡‡†O“Žõñìd–=€ÑDQ˜8dGu å›·+26~±ÃžƒÊÝšµCxߨ5­ŒœrÅ %®º>!¾—0? ž§1K":Š­kyÚ¡ƒÄxb ûh?èAŽ}pÕœÐþº¹‘§if„Žà†,÷ãeá¦Æ´®(®©­Ñ¸àãøOUºW¿¨Ö½%oË—{ÝÔ„§¥X­ ²A³jMÙD ß‚™¼KªÚƒY¡ëŒX”ù”³dÄ !#E6‹è>DO§ö¡”Á¡'‚C†ëvPÊêEõ×Çêù÷×àF7èclÔ%ÔñG¡óá(ñ∀ÙÌ"Ìcäé0v¬a¿TðÈÉÂH-P=ç¸ Ø¦u¨­6x óü?k"ð‘À?aÍÿÉtéGø&‚âìÛ=çÓ½¶(ÎØþ»÷—lgFr,XPñÃ^TøË ~޼4­oôZ“é,O[—cjó¥õ露eÝí…V{£$N’ñŸ¸¡$IäqJý( >­Ž5ì -4Î èE/Is'Œ+öGVäÅ–ë’dÄ,JX< kØ/Bò—”_ä·ãƒ¾:Ÿ¢áÇh¿ÿéâ»f-ëÓíþç_ü×݉š´F¢ percona-galera-3-3.8-3390/tests/test_drupal/drupal6_8080.jmx000066400000000000000000006441201244131713600232550ustar00rootroot00000000000000 false false 127.0.0.1 true 7000 3000.0 threads that post stories false -1 4 30 1236113809000 1236113809000 true continue 9000 0 true 127.0.0.1 8080 http /drupal6/ GET true false true false false Cache-Control max-age=0 Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 15000 7000.0 127.0.0.1 8080 http /drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept text/css,*/*;q=0.1 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/ 127.0.0.1 8080 http /drupal6/sites/default/files/css/217c09558a102a72eafbe111b6ac3ac2.css GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept text/css,*/*;q=0.1 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/ 127.0.0.1 8080 http /drupal6/misc/feed.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/ 127.0.0.1 8080 http /drupal6/misc/powered-blue-80x15.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/ 127.0.0.1 8080 http /drupal6/themes/garland/logo.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/ 127.0.0.1 8080 http /drupal6/themes/garland/images/bg-navigation.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/body.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/menu-leaf.gif GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/menu-collapsed.gif GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/bg-content.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/bg-content-right.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css 127.0.0.1 8080 http /drupal6/themes/garland/images/bg-content-left.png GET true false true false false Host 127.0.0.1:8080 Accept-Language en-us,en;q=0.5 Accept image/png,image/*;q=0.8,*/*;q=0.5 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Keep-Alive 300 Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Cache-Control max-age=0 Accept-Encoding gzip,deflate Referer http://127.0.0.1:8080/drupal6/sites/default/files/css/4e73ed892da4b33f96ae41a88df296d8.css false name test = true false pass testpass = true false op Log+in = true false form_build_id form-e65a20482915592a68be8ccbdb9fba05 = true false form_id user_login_block = true 127.0.0.1 8080 http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 15000 7000.0 127.0.0.1 8080 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 10000 7000.0 127.0.0.1 8080 http /drupal6/node/add GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 15000 7000.0 127.0.0.1 8080 http /drupal6/node/add/story GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/add Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 15000 7000.0 true title Fantastic Story = true true taxonomy[tags][1] unbelievable = true false changed = true false teaser_include 1 = true true teaser_js A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true true body A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true false form_build_id form-7d25fdb5d0089c638ef2d946e85009ff = true false form_token 5f539d93894b6055bfd79011c0ec4215 = true false form_id story_node_form = true false op Preview = true 127.0.0.1 8080 http utf-8 /drupal6/node/add/story POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 30000 10000.0 true title Fantastic Story = true true taxonomy[tags][1] unbelievable = true false changed = true false teaser_include 1 = true true teaser_js A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true true body A story, similar in form to a page, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a story entry. By default, a story entry is automatically featured on the site's initial home page, and provides the ability to post comments. = true false form_build_id form-8a88a95909d46d432e9fe341c3b3328e = true false form_token 5f539d93894b6055bfd79011c0ec4215 = true false form_id story_node_form = true false op Save = true 127.0.0.1 8080 http utf-8 /drupal6/node/add/story POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 10000 7000.0 127.0.0.1 8080 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/add/story Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 7000 3000.0 127.0.0.1 8080 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 10000 7000.0 127.0.0.1 8080 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 7000 1000.0 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 12 30 1236125829000 1236125829000 true continue 9000 0 true 15000 7000.0 127.0.0.1 8080 http /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_build_id form-b2361253017b019934be93aae0d2fc27 = true false form_id user_login_block = true 127.0.0.1 8080 http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/comment/reply/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject Horrible comment = true true comment This story is sooooo lame, mwa-ha-ha-ha! Quit your job and get a life. Comments rule! = true false form_build_id form-def6cef1c57faaf54c344b6c8a6070dd = true false form_token 2ba1e45bc76391d74b59d94db2c444df = true false form_id comment_form = true false op Preview = true 127.0.0.1 8080 http utf-8 /drupal6/comment/reply/3 POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 true subject Horrible comment = true true comment This story is sooooo lame, mwa-ha-ha-ha! Quit your job and get a life. Comments rule! = true false form_build_id form-1c9ec32e3cd967c8fd838ee71c3368da = true false form_token 2ba1e45bc76391d74b59d94db2c444df = true false form_id comment_form = true false op Save = true 127.0.0.1 8080 http utf-8 /drupal6/comment/reply/3 POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/comment/reply/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false -1 24 30 1236126574000 1236126574000 true continue 9000 0 true 15000 7000.0 127.0.0.1 8080 http /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false name test = true false pass testpass = true false op Log+in = true false form_build_id form-08da3427c3411442e541fb4a605cab8a = true false form_id user_login_block = true 127.0.0.1 8080 http /drupal6/node?destination=node POST true false true false false Content-Type application/x-www-form-urlencoded Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/node/1 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/node/2 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/node GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/node/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/user/3 GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/node Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/user/3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http /drupal6/logout GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 127.0.0.1 8080 http utf-8 /drupal6/ GET true false true false false Accept-Language en-us,en;q=0.5 Host 127.0.0.1:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Keep-Alive 300 User-Agent Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.6) Gecko/2009020911 Ubuntu/8.04 (hardy) Firefox/3.0.6 Referer http://127.0.0.1:8080/drupal6/ Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true false saveConfig true true true true true true true false true true false false true false false false false false 0 true percona-galera-3-3.8-3390/tests/test_drupal/drupaldb.sql.gz000066400000000000000000002306471244131713600234430ustar00rootroot00000000000000‹Ç·…Idrupaldb.sqlì]msÛ8’þ|ùÌ~q2gGß$9»[ã±=3®uìŒílÝl¥J¡HÈæ†"5$eÇ;•ÿ~xç[ƒ¤3TrW5IœHDxÐèn4 æàÀxóxý˹n×™¯zvp@þ?§yqh kúÊ$¿‘A~ø…¿ôs|h„ÙvãÇá’|Ñ/Zóg÷83ÈO¥É¹¯Ð+Û<ˆÓÛgÏ&ß=wLd"ãúôÆøþòüdqüóÑÕÑñÍéÕ‚ÂÕ^]V‰P£­‹Ë›ÓkÑûÌ[ã9!ÖÇÛ,ÃIQ‘åR˜?PÁÓ4N®.ß'G7G?]Ÿg?§ÿsvM£¤gÍ_Ýœ–„¤¾mÙÈ¢5Hÿ¢Öw“J=C0„ôqúã‘6C‰ VìQ‚8êw¤É²¦Æ¿Œ±‘Ù6(¶6VifìÙ?pžóÁ°1`絊×Ïsÿ‡‹ _qD9CýÍøþûàÎÏü ÀÙ"Ç…(äU R… ökÉÞ©ìÊxñÌ _¢ðƒ%Å „^2Þ\¼;?7ØLŸ]zoˆîîSµŸü`Üûíé…åºrɲ½=FZ{iœ^ütF”î,IÒ“jsG¸ò7>üþ49­&ó„ØÞ(¹5B"“º™:ïÄzöO=%úz³O{{¢ä”PNªN”˜þ¨ˆ›ó/I(=#ÚøÅ]Í6‹ûHîÈŠ˜øëJwÈšAM©Qš/m’G· ›F¯qÐéD’U "¼Þ<¡ Çô1ýZN΢Òò‹J7ßNä•úmq·ö72/H¾ŠÄ‹¾šòN ø[PCš¢@{$Q§$ë4ÜÆ‰5Ã]!8ª÷åço",Õ¹ï•eœ;FAñ5EtÅå¤9A]/Äqá—¤¶Õ!'Å^ï`uüð€£Û»bm†o‰sß7¶¯ Nló"]k»¸ËÒ‚-C¨ï£¹«¡;Øy×®´`{¡[d¤è?ø‹]øUÍ…g`_°¾‘Ü4e`€à¤Ÿz†|Aa=qYeÿ!N“[ê°GQ²Jºâ„k¿èwñë³¾„ÜpÞë þï7™þr&û§=ðƒ;Ü5íœàkL;ï‰O{P 4tª.=Ÿw"öKöÚD°_ 2ìxÈÎŽ»-Âël BPSÙÿ ùé[HAebk.§à²ò8 “#Z#'΃h[‡¿ç‡óÃ÷ bì'‹m¿ÿËëü‘'ˆ²h!w Ô'O£C󵨕¥É"öó‚=E–m;.r\Vœ‘r1]l²èžp~ñ?²F=‡”­|äy.6ƒ¹\׳ß¶­©¿œbžéÁrµZNMŒfó|5çéºáÜ]öt‰VEA ß"$œŠ4{\Ð…€º¢,×’x½a…Ф_£(Ó‡$Ný0orÅætÞîŠu¼@œ´ˆö%dÓ3וՙR~à•¿ Þ}@}gÊâà=.èÖŽ%á²âw=lPSGz‘n ²·ËD¶kRóIò ßR’çŸE§µJbN»êÐÁ²=좆ß$Kç´ä'%âLvw·¹l;?´(ÿŠôö–0–A &Sö¿$]“¾,Úu~¤Ù(^Üã,ZEO±*[¦$b4~¸Ž’]øTz”1Ïi9 ‰ì¿ÏÞ'ôçÈÈ£Œ:"ÆÑ'`ø…ñœ=¾ósCØÃO ?Ò-ÑDªaéö•ñkº5Öþ£‘¤ÄúÜb©ñœ|Œ¨ÚDÆ6§jIÆNêÄqú@¿I ¤ÅÐØøyþfá¡$K –>VtÆsùQÖ ü8O%Šå£ALDð‘ö—PwQnÄQòÑ ÈƒtóHŸ‹îé|QAk‘1eÆ2KHÇ M,ŸÜÐÖÈŸ4hLÒ`4û@Z «–˜Ž3$ñ#ù+À¯ÇWD?h…[Ö1©Eº5¢8¦•2ÌõT¥œ$ß ÆHÒ2%£Mã˜ÜbVòBµNˆAóW`ͦ¿” ŠpäÛå¿IWÜ*P‹v”4A?÷JFÀæ7DÅSâçš°øÝ±|díÑvi8&'Üa³#ÚgBFDr³‰…Ä3Ò "2?8#¬Þà$dÕ„WÆ%a>*ËKŒã6óÉ>?ä|§‚ó§äþÉ¥xˆò;Ê?H4ÙLJ9îS–£ª¤zTÖŽÄ܇¸ „9‰çåôHûõB‰k%/Ë¥¯ìŒâ­ØKV ÙË ÿ¶ÅyA‡›abÏ™Œ¨Á õÈ”t*±[ç©”ê¦4,(aÕb™ExõQŒ³ÂàN©Éd‚Ô&¾×#’¤#Â,Úa9{´"­½ßËi!km×Ö “՞ߖɻ›Ø0uäøÐ ºþÒ}´4m±‚ZÀ1ñqE€ëX¼?—Õÿ˪ AUÊìÙ`sU:ѬÉMÄ6ªM/»ôóAÍÿ¤…%Y‘Ž&4™)Wû€™ûiæ6ÄY’3WŸÆƒx9)¶MMË·Û(ÄDV…ùÕ5Jµ ¡\©Pµ*u¢9n«N1]ÜáxSíõ3 ³=—‡,Ë f;Âß¼ôF$ÝW ÈÿŒ Œ¨Ív;< x®¢èг––éxF®iù8@hiš!ž;vè˜öœLüuó÷‚ºtgXlþþ>Ùcé:óé̲iÛä#?Õ@‡³åÔñgYN8Yóö|Ï2Éžéà™ã…¢Yb"> .ž×ZuM{6•­ÎÉGÙêܙګ04ÃÙÌô;°Ðr:ÎBÛ™M-äN+`ÅÉW­ëNmÞ®;Gä£lwÞ ›³%2g¯oÍ1 ]Ï ÍÕ4ÄØ«´›ÓxBƒ¦ZË#Ÿ¤Ÿt«ß¯Œêëé&ëîOÍS3Ëyô’ó[i¥yˆ¶sh8…Å_è*C˜âO<Î⹬ˆ®Fl#0Yn£8œ°£%µº!§\fZT“8á¼e²À¦&DVÑ-‘\NiSJ¤$Ë%.™óZDÚd~r—z¶Ù¤q"ô4ÖhëG2!Óµ&Døè`J!Ìõä¤éûHÐÎhÓ0\N% ŽãˆSÏ)µ©§Göœ™=ÃÜló»å¶($n„D”’žö¨™t¸Kã‰çSÛ"Þ(ކÄS§>é2B7)©D«ÿX]X͉—’ä–›Y²"MhZgD9Iðƒ fÌw»©å.WT™wwP‰HRá6e¼R–W%ÕBØ÷„:Ò¢ÌÒð‘/£yÉÁÇ©–´ªlN‘-R¥!–[—áem ,T¸zRD›Ò϶ËH.oKù˜´tÊ?yµReKhãsð®—ß «`Ê0u£X‰¤€‚4N3Qn-”BH)ì×5{Ç(øP`äÅ.P¬âì¶Óàµ(žÅÂó§Å3~y&@)æ|žº"L¦Y×DNPÙwB–µòH¶kA N*…ÿ)MÒõ£ ±¬dë|”œt —톞ˆ—t#Š=ă_w¡”gZ—nÅt¥š6SITQ'g.7­-"â\®+ëY×»&a©÷.‚ÖÃ’’ÅÈ©-3%iåÔ Älõœé‰+êì:Úa±¿Êa¹Úa±¿*Ãò´Ý³¿jÝOµÝ×­«;“Ýš-V¦eÆ?ÍšR·Ä\Ïš´J6Iï1Y¬åŠá©£¡:©Ò&±¸M»Ú<¨ C`˜óàF{)ªÑ“ÙgÌXœº¨Ë*ôšDÙ´%¢ LW‘fϓшNMº7N‚â"嵣Œkœšñ±QVdyþêÓZ¬¤SSΞ¬1©»³2¡(ÄAž*ÏÛ#•$VsyáÒ¤'¬§9¬í”¨"ÃS·ÎŸ QU|§ž¶­’×Ói]Ž*DŠÑÓ™`[õ€—âuͦ`Sû7i‘U=m²²Ÿª» uªm‘’µpSŽofÕÙP#/¹5³ëZ\#«òkæHVtôé ´¡g®Õœ9¥*MJ»éD6('ÑFö6«¯AD*Ûíq¯,DŒê.*JÕsݦð1–k\qÿ­¢ÇŒˆ&0I®Ð “bÖé2¼ÂYVuÝY,¬òÛbá=¶Œ’ËÕ‚9¨|ŸÈDÚs5z¥ìn©´ÒЬ7~ „bÞ°ØËǃÂÏ…£7o8z¤§MÊÝŒr¦ëXZQ¡ Ý+ËQ“…JÊA0«a7Œë'K:¨˜V±Åm.UœŒ4c9pdºÐº®(«Ë2Ùv³¹ÓmÐNnãt©v%&Û÷Àx«{°ú¶™ ¦§ú¦r^±<³™ªðÆm.;5ºê–í:[»ë*!dkYv|D…m"c$55DvË£jR7ûpêF±´Ä]:¨j•#æŠlÒE44Í2¼I3ú ¬2Õ¥ ÎXIPYïfZrª˜ÊäbY›µÉ£5±AEšÆ£r£-$ÚY¸6Û%™‹»*~5'Yõú?t*‰¹­ÖòtíG´³Úˆm»©aªË%;Øfq)s¶°ÉuYª¿F•…$iE*T“l›Ð|4!%Vc­¯’nî6’jª§Ê“rjÍꋵr¿Ê”@ØÚñ7I«ÚÅöÇv-ušîÓÀ_nc?{”µPÝž´jÑ…¨fÕU®F¶ÍRÍøÎšå~I’j©Šå•h[¾b»k:Àr#Éåqyfy l9ù·4±lO …W8a)q*áå&•;jæÖ Ø–ɳŠ;y•EHŽ™UÎçX©U+UÇÈ¢Ô®5[Ù "¶s–9•àâ;æR)Ä8„RØM?†U¯ÑØ-×CÑT%ÍipIÄ#ì’¬±~0ŠÖZn·¼ÎiéŪyÓÃâlI«K‘c6Ä’¨â°"¶En5U[Õ7Õ\ÒøÆØ„¨”ÛøžØ‚ˆ‚;,Ã_Èj{¬‚Ÿ^9§ª:ÛÈ\mø¶7””DnÓm¹£†}ÕJxE°Éjšmåø$iq°J·Ié–9vs©8¬!N"\!v@Ÿß«`ò\šäÉ2dÉr(rC½Ï<õÙáíKíÕ;­Ã.üÕ³|ÓG±;`†‘ÖŽBõÚÉàŽ¸NXwòëõçÏô“O ÕïõÌ×Ãà0 ¾ðï£ÛÒï \à4ß—q&Æ©'ËCÔ !&"! Ó>MÔ:GÓŠ|Û:bºÒPG‡ž´ÆÑáTÙèp& ft8m ÙB¢d‰úˆ–;ì%péW—R J♌—Aíµæ²û¼©ÉSZõ\Õ˜ä9&À_~¢¢&¯vÒÕb©§8êI†N%?g’sÉMÆÎMÄhÃì?+kIýz, Œòœ®!)f“ N›Z|fGo âž3»\Úæ +Ý!VÆÚupØJÍàQ>$wòžÓa>»lñ–b.)ŒÚºÛ‡~N0ÍüÌdD>𵜫— xî\W¨g°X 9ÌÕŽ—îïæò°åbv[D”ï32aЃε[˜iŸ¢x‡Ñ“õ°v¸êaI±Càð*R;Ìo‚£RðæÑPÑø^»0̦±<‚ÏÜÁ€0Õs š hkW×' –‡Ó»Ðå˜!TªÁn v$¬Ò5›IO͹“€f K;,4²oyœ‡†¨‘á 8?s° ö ϼh!¥ ‰rã·-ÞâUGÀ¶zíTGöG1eíu–7p! |Pn>s ' €,nW5ç;^RÙ,Øc‡`@—ð4¤Yëzd_n,ãÚŸSó%v {ÒAÃàÉ Öx­½=àªI}×(ÙlÙ-´µ€ÕÁãЃ†}ØAÉEàº)„´º3·a³¥ËUjbuùz&ÊF'Ó¥Øæ¶Mš<)HLUÑØÈ4FH›¢¹ÕÒ±ñiÌ&A šÕ²lll°·¦ONƒxW-l(µ©qMx´«JáØè`ë¨É˃tB 6š”@™*ìk²!dªhldðV\“ !SEc#Ó¬ ÚLHK«¥#ãs4kƒ.ÒÒJáØèàõ¡3ýŒ…7(Ɔ©Y&t ° ˱Ñi }ö-´©P³Th“!%©–ŽO³XèR¡ù­ŽnØ‚¡ŽiÛÆOL³`èS®!É«p†D:“¹wÏ‘ˆ\Ø ÷fŽ·Ì{WÙµQB#’¶e¼SXc£{3ØÁ Û¸? òÐÓXsØŸHFí¯Ø›(v Ys¾7$¡ ÜŸðâ]ÃÖÄJ\-ƒb3¿cК¸IßÈtIýÛ•êi¢%½·, ÓI¥y»áª&z>àšGKP]vƒŽ•÷^5é åöO¹Û…ËC0®þ)»Y¶f¬êO¸¥†ïD±±ÁÙ:ÊË7hŒ5Ýs ߃Ùê´à×nÂì„§ì5…Au_»Ñ†o±!0}©õQ𦰧R¿¼éÃÕõµ±Â"Qk´Àüt`–Fõ¦¸Wd†Ð#TQs¤¨M5F»û²PWâ˱j$°ëÆÒNt¢D¤Iºè¸¥KÅζÁº¡`Î4fºó~•è*ÂqÇα»ÚÅ0Á~ïÀÛ\MpÌ÷|ËiÀ/ðmš=­J#Id9»Ï&BwÌôz>o>w¾ÓÖ¥ÖcAÓØÅŽ[t­¹6+sÝ=ÅÑX𼼩ÈkT8¸¬_ÇÅã˜Ð¨7’Œ'¶@;wd¢®.6T¿R…®Nø»ÉJÐ!΃,Ú¨Ü]¶†ÿ“øqo‡¾líÕ¨Ž%‡£ &ûÀˆÃTDä[ŠÇ]àçš ?tÔ«c^l¬å)ÄÌ“÷@8˜Þa„Äà‡GC•ö/”]HèýG |cZx˜JyÿrhuÂqA%é½ ÙéK€šÂš¼fõÙKÅ ú Öò0•Ѹ%€ÖXŽ °ÿ'ÄûãZ‚öhÞ‰¥I>·Ëœ1súZ&™³×"^ãä d¦&Q×éfyÿŒ ýÄJGÉ/n61ŸÅh@äOº º Š‘²ÊîÞt¸¾{¸¥©–Ž !Xš"Ò¸Üûu’£,MÖ$*5YBÖ‘Æ]xùxø€¾äCpšµa޹ô YŸwµr,ì†÷Žä½&šô”›ÙOÚÏ‚ÍgÁÒDJ¯Us7ŒlC‰?g«¥×êÝ·/"CùÔo~;MXµëÂ3„æú—óÐØ°—4à¶ôN‚¶§€i®<åj6œ†Fƒj4÷¢_c:ŸtGtØžý‰*%|ø´mè]uíáŠ*±&º,nÛn‘ã¸7¡Iµë¼«ßŠ@P⣠QËG,l.›ïaË.çàú]KÌv³ïH™ü¯ÆcBçÝTú¦¹=pÔ}_úqC•¾s@ÞQuØ¥\þÑëzW¶ôvðìš|ô@£˜ŠÏbp ÎÖ; LŸsöÂþAS2`c_ƒ¥É3ƒÞÞ×9f/W0H,9· ¦&á zQj¼ÿÏÅY£¨Æl¶Þ™®¥<ñãIøž&„®ÞU^Û¹"?wæ&ë]ã©u¼Øc7N‘<ùF¼î~‹ˆ.+CYÖñÜT—­ÓõR­Ó@©ÆtSÁì=0m¿°¤sŠ¿0f¢D ¥æ¸´ã…)º9϶Y9ü¼¯„©Éoé|e |`A ò]2»«9aézqŒ^@‡ru¨€–05 ßýæš®t¡Ýaõ`c­{÷Lß)Ð9ÃÝ›bØÞžÿìÿê8…RM4ãü¦â©‚X-¨ †×EòªÆQ€Þ®9ÏIs²4}˯5ÀÛbN9|¦G¿h.·Lœò•½ŽJï=x3®¢e<$Ÿ«ü/{ÿÚÉq$jÂßçWԜ۔Y7™÷ 93{(Jg$[I‡KRk»f2ÃP…nHh„HµÎÛÿýðKä¥<2ݨt_³=sÄPYOFFx¸{¸‡ç°Ôs HÃ÷Pj0¾ŽØÚ“®Ì$º6˜ mÈ>oÛn!!C¡&+¡!´“oRúNù{äþ„¦“7$¯ žºw Õé;òº9:Ú·žú4©:ˤáRË[ÀÂ)öªÚ‹½„´{ YËo!Oø-ä)[kyÆÆZž³­ÖÎÔΔWô.ÞÀ)Mí7˜qE¯í œ×/î ڇР؇pDÓ°ጦ7`Â!MoÀ>„SšÞà!NÐV£+êá›ì)68Ú¦ö‚»Ù(YB ÷~{·}»9òž"rb2¨öêÈu_-É£›ð5Ov»¿îÛ‰Ö3· e±MUá­‡3¹ wSîEèz>L+ãôr>L ^­ÿŸïìþÝJ#ùä¨nÁ"ÓòêB0–0>~â¹mË,œœ–Ñ;ãÎPKäQÒíEMlÄÂ0ùñŸ ¶c»³ÔÄaR dý듳\/·Ç›+¬ï;øö†ªG†Œ'x+èxÌ”/‘ËðRøl½”‚Ë ~)%½”ÕØ«l¦V pº­`¿ñGò¨¡GþãC°Ïïö®#a«¦_ºóK©ŸÊY ¹deëN·iÃÁƒ^õÆî ¼°¼®¼¬•Ù²¤1[V4fËšÇlÙ„1ÛN¬A°ñ*Œ_áøTa+ܘK–Ÿ*,?þîÇ×›·‡§{|%öxÀñ}íD²¯ò¸tš C¦–§œ#Lr^žr^ž ^ž ^žÊ”^[E‡bò8—;uÏþÚ5­Å7P‚r6¿¼Û>âA~!¦Þ×ÚÝ>CÉU~EÇ›ÝþÒÐMï£ +À¢.>éÌ¢Sðx°Ü~Ã"âM9¹áXû $H9SaëÔ­ò]ÿاøèõ."èïLàe¿ ö‘ZôˆÎ£ÅÎjZ´µ¸ïzd…X'§ ³œR[ÒJî*á@è~½-aÁú}ïš©`Ï" 7¿fñ8Ãsl.?àÜ÷%{±M_Sýæîêö KnûÂÄûÝæw?ýñ›Çí['$¾ÿÝ÷î&»=üúåæ[_Y.;nöwÛË[(+|M!oüYYnäîèîÇ~]ÀYÖËRÜŸ$\ò[Â1l‚è-£M§G²üÑ}4Õÿp/ÖÓù.© ™g¯7÷}ÏÉtïjþöåf{Üü²¿½õÿºçç*ÑûÃÃÛíÝÍ?{éŒ/ÝÍn!â~.‚!XC° †` Á2‚e0Ë`–Á,ƒ!èÖÊ)9ÓÈok¢ÎÒ´cEÖQrÒQ^ƒ€y =ŒÁ ƒíåú¹;¼7$­,H–~’œv_嵑<š³þhvë?T¿Ü¿sCùððzs|ºzçÇæã~ë’ÛýÝÛÇw¯ÝøüûÓ ÔF¿Øû £ûŽ]{¾Åë ¸ïžÞ_úBô×ðÑ«“;åãÁµ µxÏ×ÝÅDwÉ|ÂЛ*‚%tów½¬¹‰nn²NIÃnðÛ{ßíËgJFÝùu¯«\oÞü]ÝP~¼:ÛÚW…c¦+ÑËÂ}Ù÷—ŸÖÙ:5-¾çf] µKʯŠX|-V÷:]~ Ÿ½4™lL×¶ÀÙCKš„÷ÆG_‰Qïxc¨é ÝmïF?ïa9µôÝáévöïÛú•^§4\n¹v¯]h^@;Àyñ¬Hî%ÜW²ˆ 0Q€éÔø©ûPîPXwÞmïÞzuÿƉH¸]Ïwà0'êX‰B}Ì^û—^^zk¾=Œ·Ž¯»™¬ßO–b:]xÿØûT^xýU¿½ƒ£$\_СnÌíÞx ¿ã1tÜù:'MCçŒ7 F9(}i'!¿|Qãëäõ8é ­ž›°÷åÞ¢ìÖQøÔëîÏþ¤C¿2øH·¾›qïÖJ,$~u~ïÖëgØ™ÑÉúXX½J ãô—m†—‰½ÕòÌλß<<ÝooÝ º½uzõÍã» 4yì­®E’U$ÐÓ¿½´6ýݳ<_q\©KØ©þ~t‰Ü-©8ïàÅûJí¾ü¬ÛÞî>¼?<_Øà'ßûîǽšçt?#/Ñ)‘½{¡SÆõÈ„N¬ÂÞ%²§Á ‡Ÿü«¦AòË;gƒL~ôŠ+Æo¢Q»GcÍ(7Ç>l¶îs”GûÝ <}äÄÕeåÕ$Ï¿hÓ¿HöSÁFÌ»ƒßÇUë¦ÿEßnln®½8Þ8 À‹ȇp½‚;®Ûèêçx¨¢ý9jQÕ8)äÎÔáUòüzP†V ˜ÚþD8„Æ)à›óÚÑ¥,xô±%h¹‘út{ûæqÿÇOìšžf ‘Ÿ/'ŒŽßø7°Æn¦”Ħ•”D¨7ÇûÛí‡ãf׿Ùë¾ô„Åç 3¥Cb¥»ìŸ‡»—Xgbq÷K«ÆÖåñu²ôÀ0ø¿í»E÷p}ýæÖW>ñ}Õ»‰—`ßø>§îüu/Ñ‘³ÊÓ.5¢<|êûÝæÏ?üaJƒËÅ•ä*|UÒÞ>ï#ªi¼Ô¢´÷‡»N¸ŒÏÄÿÜ?n¶¼O…ߨl/OCßÐážÝΰ“r÷Á ñÇýÕ£natÒ÷σDé³S‰·Y0ÈÓ,T~ò¡}’K^ù¬gZ¬ )<¿ãfÞ$Â]þsC ©Oó‡Nñ~MèÝóxܺ 4ïRò.%!ïRò[ /†#Þäѹ‘}<ÞÆ›è5PxüöÇk¯®¿î6A@!;Ÿ1TtÕ?Š“=ÌPÌñ#lÃÍœÑyZtQ˜°›¹À™¤ƒ•™WöGúõ™TÕN¡Ç¬šœè˜„-Ó#[B¤Øú/nîo®z{žŸ&©¸käh˜‰:“RÆnÉ^¡ 3±þø‹³÷É/9ÝN.oâz‡"Œ^Ùî@4ÐLþyÃ)Ö EÄ‘Z »¡+¤y:I~8LºÀ’ÄI‚þ{oºPþK<ÙTÎq)» øÙÓeÏq¢@˜*€‡iWJÃ}Cóð;~øuÙ;š K¼3à8öìiüþûî//Üke¯×:Gl ¡Ô…]!”ºB‰`§1ƒޏr§ê† Z?쯼§Ý]ëìÛÇé•,lm Ûk¶ÛG4‡à6·œ@Úßù»½e{ð$îGìÆØRI‰ZPõtäö²ç§Ãýæ/¯ÀØw×nðÚWäe!’'úåÍERõ9²“x¶¾c¤pëèy«ð¼$éÒ[v+×?mþ2O+Ça“Û\´þ·_‡ ¬O \ŸlrÜt9¨FˆfˆW]i ~óí÷¿ŸxõÐ GDOìHþ¨·nÅ;nœ]íeÛ-“sÈ ÌÍ+g‡8¡÷ÂKÙ"…¹VíŠ@€EþGøtüׇûeýoû>…ðåž±§á§f…­²È Ûà×,S—eÛ?s¿¬7ÅOÂ9"¥; —™Š‡9N }ØG·ûÀîóßöw nãõ+¿Ýs6£¥«gÏ:¬õdDœ:dÇeB„³O`{i®Þ'Hœ¦%N)ÔÛ¯ë(ÀC¡Aütêý‚°¡ ô§ããáýÍ?Á•Ç(öÜ=ÃësßcvœŽ<÷TÒ{lN¢úzOäz0YlåÇîÃO}‡§¯(Ÿ‹¸(ÍIJmóv`U –†g×ü ®µcß?‰õb'áGUÃ0ú— ½¡,OAZ5"ÇÚŸx°¢]ÕRCÏwÿîaZvåAa}ïƒ~î÷Þ÷2úú ¨1¥¬Æ¤#-õÝÍ£hìxtÒÃÃ%3 8†#ÄôïŸo¼~Áuqð°²&4ÎØˆHõï°û\~Ô4ö¨ð„ïü´Þ¥O}P!If¹íQFÒÓFtöAŽ^Íèa×ÈCµàçåké‘o ×êvÃÒÍž÷ Íœ6ú°¿vúÿDœ®ÒáE²/«åG}ìáL£5⋽Ä)7'Ž] ¤Ëäënó}‡ÙÉä9‡xÞAí'Ô¼ýŒçÏ'ž¿Š6/ ã–$åIhé)ÈÜüâÔÈQ‡‚-…{ÏѹûÛýkdYR~= †Àì÷[/.7ÛÇÇí•/Åì½ð/áu-U¶È-_þ²NSxšñž§£K½ŽîÝ_çðt~D¡ÎnGÔ Ü$ø_&àt']¢kæöV/Þî/|LG·øó¥›íÃÛ'N  ÍUh‚âêh{–0OŽ•ÅRòW½ccÏÃï£ÏÕoÈ ‘,Îp¦îªÖåá¡5 ×*@"Ìd=N1À¡/{˜<aàèÐÁ9²/ –-V(ôN´êñ‘§=ê«wn6ÞîwzÐ0i{ðÖÇŽ=d÷l?ß(òúÁ å!а7wwûÛÛ=\“«mô€»£…•x‡çÏͺû§ã»Ë§ÇGÍ ³nâ©{Îc-Ýøí…àÄŽ}ˆ.»è.ÿ8ç>Óª’õh°‹zÊéHˆŸæ%FÒ¿vºì‚ƒí?¥šTt‰í½OƒãÊ£Ï+ÝzáÓ‚ß«kb4ŸÆD½Ž8cçeÜù°œ1Oo%ôzïêÞJLj߆•ŠÞ¤E×Fg—syF•¡îéÕT)cc(>5-ö˜Ó÷ŽFË­ϩÀ€7àÂØô¾*Ó[aOØÎ­îµc¼Æ'gUw'éÅíÂJ?…Ó{¦¤°¿ä‡Ò—«Á—{ÖÂÌ-:A>.ß»`)ß¡9½Ãô² Ýdô$W‡ÛÃÃçqÌKné&£ZËøÒ>¯K—¾×ø(Éø3î@i¯Ÿq2À?ã…t[/ŸñB‚¹ÿŒ{LÖqÿÎxÎ=âåÐ?£k;ßÔg£ xðb±µ.&NŽ^mêUFüôìÉÑ/K­„9žâ‹Ö¤6õ¢Ïn#‚M×Íž¿WçªaŸûUø¶ú3”?X4¸ü˜¿ |È^¾Eo¼ïþü~]Õí) ¾Gå·%mÆž@g¥»¦ïR›,²}FM¢ã¸è ð±¿wXJûŒ:D‡„÷pôO•©^½›†!ƒ“þ<ºìâòáðËñTLø¢ò?ëÝJôwM–Ç>S5=(ˆlØ-+Ž{bÌÃ'f™|1ºÅpÜJE¬5ž¶€õ™&Sr5ÜÔ(^}ý{žvþ ð2:ÒpÕEoØNÅIžQS$yÇDp«eŸÑ7K`¾¡ñò‹‘ŒÒx‘À®‡‹ÇÃýr”Áý8ô‰ôã'ÅUç’ºÀØÄ úÖpé„ NŽÀÞ ÝÓ\ðw†ªÑ8 /zÇüô޽¯ Wœ“à·è]‹Ó»ö¿'¼Ç…3¹ÕÑ»'~áÚÂß]›Î‹Ð[×îɘPÿ|Ò…R¦Wýã°*Ãô˜CÉo'ÐäîG}u—«GïVŽ .úŽ|î:ù§ã•ý»…âKºüp¾Å{C16;pñvaªÂáâŸi®Nív&á?ìÚÇ¡‚6:íL¢?ï°BS¢×b\æ}mžùªìç\µ{DãW¶¼º <¦"õÒÏãÏ›„œŒc‹ŽÃ“¢éjä§ÑKgöѹÁB>´%FjŸ¯Íµ¨ÔùC%†PýV¡ÛžS¶\sÙù‡gRÇzš€oô¢×è‰Ztðà™8{SÚ¼m.1Á†ž_=èµ·oxßùñ@K)lŒ×œâÏÊ;`ÛB‹Ôâbô»3: Ñ5 îÜã ÞÌYrçGó­]øÖNfð²#ÝV5½FOúpîàµów"4wáš;ÑïOªû|îÆ[ì¶IK—{’/Š–Þ¾zxº{sõp˜²ÓþÀ~rö*^>t²õïyÿn*„ ºˆE!\¿ÓñïS;'ý;á•CµpÒZÔ)ìoÅ×u{Zý3ÕðöùéN# Nmßøp^½!°úï^ ZÙ'˜Þu=æ\Ò+8J»/ö‚€óx§csþ­©ÉPœ6ä¿ÒkÆu¸éÌý ÃýàN£·î¥-ôT§ÂWõ0éq2†š.ëAùp(ûê¯savxÝÅ_'Ã]Hl<£EJ¢£Û¿ÍÜv³ƒ«Á{ß`ÈÙY‰Ç¿-{©á  í Îs«>Jþu(wÿ–‹ÂžÑ%½¦† ÷Ûãцs6†–|Ký¥”ºàìáo¡ñ nŒSO`&*9å1Ž´<);÷¹êÀhïon–…ÁõÌ„(5‰…M`øž‡wŽÖ½ªî>ò·ŒO¾<ã–Y‡~¢æÅŽ›<÷%ßþ¾Û¼‹œø¸N·Ü9É·ÈÃd\¬þÐ+V¿N×ôhbB.X àVá¥7zõí§‚p™߯ O*¼çÕ»ýdZJ–‹wå¯Ioáið&v}NoÛËóÊ¥»ž9æ —©Ä8žèYgOƒMlÿ‡Pâ|2Nz¼TØc]Ѷߣ!ùòá•gØÓÇh¤áá•'ÞñdÉsÀÀ0-y" €Ž[Ó_Í1Z~CŸ£ß¡Œ*Tå*ý†k *nMœö vHÿ¬äëÿõqîè“6àà°P[kÈP|-çútˆVfˆ•#Ð4_JšŸ`„ôûåÅOÀšX«‘ÈÄóh&´ù¤ÞˆÈ Iô§PÇò”À>Ó#\L²JN:$¡$0Z"(Pư_Aó94' §i~@øwRœB„žÛ aTœô¯nþñÕë4Ëó²Ìš4…‹ª*ܯ^ýêõ¯Ò¯÷w¯^¿"¢S‹Ü¡¤¨à@¾‰ÒÆprMÑ­¨'Wqú1Ô ^tj ž?ÅÊ Ï­BõêŸxâK~#l1FÎñçd~³ðœ ß7‹ÙðÅÅ¿YzÆ€_|ÄT'ûft4°æ‡-dóö«”.οêgú#»cúgöÂ]«N=úÌúua$aû=×­t85_;HO}œ敤`¨žö}Øtªø©–vV•`¾Á%ÙxyÚ-µòlï§ŠáÙè³\xpzì^]_×õpä\áië§§§{Þ2ì“sÊá²t¬ ©KxVøât"X3A™¾ÀNŠÒ¼8 ¤?v… ¦ÃâIjäã vR¸.#w.ˆœêc/ ï¦ÚÏ ¸†¯€Ýó¬høÚÈš >†ï´ÃÁsZ®ú¦/;§q¹tC°:—ðÂdÅGˆ¬¥ŠÛÏ t…oßLƒëiÃãD^Z{¾RG…Ò¸3\ÞD/W*†ËiY[®ˆ_È“ñ&jàÂÒñKŽ”†…‹QV/®™ ßÉÇ3,Vd®&™|}FÓ?c¯œ'ÜäÄÛ £Ú˜3ñ_T6s&¶‹*jÎÅmá‰ÅmÔ›]`?+^‹ V>7|ŠŠ[.ƒ¢˜‘ &ø4øòbJpUùÍ©wÚ3T½õ€>ûª“ `V·½‚_«ùæ4 >h‡oH-·í™)˜Ëãø ΤPg4œJ àQz¢¯t1½áY&Ã>+à²t¸èœVþ„6OTŸqL¸ª«e£*‘`$cÍòt/ŸÊ Æ÷ØéV©|«ñ:XÖBõ·Ø©záÜž9U6œÙ÷WU‰ Ê¶´áºTèÕ‘B\¡t­x,ñlªòoF[è(Êjï ˜"t^6^båáê|¼ EjùÁÅ…¨žó&'À7œ ¥ÙÿÛ5m³ÒΑ¼;3±•ÓÛoŽ-ÜÕ¡=4¨t0ÜMZ†#í´«H–¼Ç?Uý/—ˆÓºWì— ßd¡r ×þš‚Œ‰›¯K–ù7_W,Øo¾®YôÞ|ݰÅ}>”o‘¦t‡4£ï§þóþä/(¡ý¯¥¿"õ—ø]°%V„œÜº’¶¸ÿÀ :©*„ú1´9^Þ`Óì¤K«Ð£¡w(ÅÝpw¶Ü›Ð)Ø›)>`¤Æçü¶›XK««ŽÕmù͔ⴠ¢ðvñfŠtŠÛâ¶öoàÓ3²–2ëÔ¤T³éÛÝî¨/>³1oƒŠU{º+†U{æèÍ ˜™a¬‹ä 7dÅ"gá‚çq/èõ@-—·\´/,N;üô|¼­ÜËËö¦Oˆ½láÏÏÇœÊÅ—–m‘Ÿ0û6éã3"§Ïž‡ƒ}zqvWœ\^Eqc8? þøaû³ra™Lƒ„¨`ÄŠoÅ‹û»ýðão^f- ˜&y N÷Ù¨…ó(¥¬HdjÖ°&‘¶¨$¤¨Ò.‹¦…ì÷è2Úï6ôã'>öïG„gÏò 1(ï[ú|ó÷§ýÓþ§ag³rj"D*;ûãÌ,×;©@–Ž{ãæ#êëb%Q1–EìRR»úÑzi2YŽ6Jdᣗ&“MñHL¥D>zi²Èº ç”fiÿÓæ+"kC,˜Tš¥½_šN^&#YE_øèŠ—ÆŒ,±XZ±»_š.²PÄy%{dðñKF–Šh±4IúŸ¾4_d±ˆE1Kï·÷áKÓ-[0Âæí©ð ½4YdÁˆGoK#oðñK¶¢Kd2.ü<þ&*e<„.f¸y«Í_¸¹aÙòr»8"£gƒáE§îÏC^º›€#»ó1ù¢×þÿṑ#û{KrDÇýoðãscG|% ²D'óg†ŽøMæÒ%$ÑÅóï\S/â-™MØv'ÃÌ;O¯F¼ç 2FN†B: çá•}å³Y+³®ÜùW^NqU©Ì5ŸÜrže«a.yª?#áEtßÑÇÌÍñxs¸[¶íµôu·Œ_ÉÝZœà’jÎÒ§ÐPµ 5ÁußÒÅ›³þiÒ'àÕ²¦2Ì’æÃ?þ¸¡*P/蘯Fiô“~D[áööfû¢C­à¡VG„ötÞÑTàËY##p*ùé,s¢#Š]LdZÅBq–wÛâ¹0›ˆ˜žLÕŠB¢Óî[ø2!K ˜d½wabØtÏïñÚÍÕöqÿöððasò¥‘ÝCäs2QJW‹Ïó—êÛbN]Ó㦦õK¡EäâDBÞÉ»Nzïzúß|ú+æu¥‰Lqaãr˜Ù'*ŠßݺkÂá&/7 s¢m Ôù††Ùy’ëê7ûÇí å¹ôn¼z¸¹±»°†ÿ_NÛЙOîž_¾¨"”ñãDœIBŽ èqø~ˆôнàßFœüR*¢8¯¾Ã7ïyâ:S"Pv&‰éÒ0øõ‡Møt~¡œ"ñ©”"Šœ|)-<¦÷ùür˜Mâ”â$™M¬œÔ%Ä™·ü¾¿qwÛP‰Ó ÜyÙ”‰¨%¬Ɋð€•ü€óù Rß7Ð~1í$‹Ÿç]ÌXRÃAcIó  ûŒP K"ºÅôcv©¬¢í?áÓ‰/ x1éiDògeÔŠjÄ芊* ܳáps)½’¤éúÂÀi*Ï„ñå ¯•E¢&Ón¤õ4¢./Ìc^þ@Ÿ²‹A= ¹ÜãKò§%éóçÁ瑱pž¾/¸ï#Þ¤ç$y?óÑ>ù-äø²ˆ©ÓZ#iÆ¢‡äén>þ}.Ko6kŸæ4KñÔßÿîû— ‰¸U§r§%šÿÏ?¼M.kI ¯ÏâäÈ«I!xN–·½ÛmFW½˜zÑÈÎg¥›‹ªØìÏ|€¥Ã¢Ã—wÛ–¦½G7WÂç/O  òîE³í'ºèCÞD$Ôn2íÿÄá/þ¶wÍfò‚°²¸Žýì··›é”ÝçÙrápd’…æøhqÂüñà ÏâéÝã‘íÜñ‰ /ùZ Y«¯ÿŸÝgÞerx’ÓN’& JL?#: &T‘ªð‰»9þX~Ãy¼E—]xË Ó¢«œÔ ©¸2éˆ q«ûàÅý²ôV>ÒsŠœ']HQ8¼ÝÜÜ-z; æÎkB*ŽÙÓ›è$ï;ô»-D -¦€‰.“Nû=³?ìÿþ´?>çàÚ—øOUŒ“™âûÌA(KîñÙ'’æö»ÉPîE­—Urât”óè(Æâ²&b‰±!ûrÚb:»q{z2KTÇ¢Â(/·V½XËÔ©/“¯ø]\"e(g÷GON‰½ó‡§…]¹|{´Ã”ÝZÓçÞÈû;þÃMw Ï`«HHæÔé;ñº´W—Ð32á§ÿ™Š®:#k<Õ<.$z[>;±??ݼ/Ã+YÏŽ4·“÷9ûp²â;íü3'Å,Äý‘p‹ñ^Mú3 ö?è=̱Wìâ£WjE¥@:,>²'w8:sޝ™{£ÙÞ§¼/ë‰$(Õ€Ó0=+I .ÑXH»b&^Ï—÷Æ‚ƒ?6¾õvêë¼ï²=éÊL¢kƒ)Ó†Ú¶Û JȩɊiÈ„C‰àô¢”>…“šà9TO¿!YôÔ½£ÄNß‘7øÓÁSãxMO²”/W®©åÍ|¡´Á„ùb¯"íÞEÆ…o|6/½‹ŸF/ð œÇ‡m½AÛÛŽÛz¶-œ·õã‚¶À¶…C(|ÈÇS‰Cò£Á17µ«ßÍIÉH£°Æ÷Û»íÛ}Èf•w‡á¸¸póáðô°ñ“þåÕ‘c#¿ J7ƒ"E·ûëGid¡B6+µbÛãS¾èÝ”{ºžEËøX´œEƒWëÿç;›*TŽä“óÛCM¨_5ûx‘ÔÿñÏm@÷ë]á ž†—È£¤ÛUœØR‡aòã >l¬w§â‰Ã¤@ùú×'gT_n7W0N†ßÞàúcdÈx‚‡°ŽŽÇLùÂC& =˜òùqûž²ŠÇ KìŒE6ø8! ‘³È9£­`ñPá^æ,*<6}…×#Ô-è.ðnà >|X|-9OwgämÞ~é¦ðæöpøÛqãuºÞïo?í¥¼øD.ÃKáSS>Ô/cw`ÆÎÀ•Øun¦V pä±`ZòGò¨AdÈåƒÈ°Ïïö®#aÓmÓ;úúK©ŸÊY ¹deëÎ)jÃ’^Çî Žwä…­àu­àe­,hÌ–%Ù²¢1[Övð°.Y~ª4²üø»_oÞ>žîñ•PœßãÇ÷µÉOûØÀ>Y f‡ðÂ`²©å)çX¡<¼6^ž ^ž ^žÊ”^[EÇ›ò8ל;õÿÚµÄ7P«6¿¼Û>⑌!;b{¿ß>øi0|EÇ›ÝþÒÐMï>+À¢.>éÌ¢Sðx„=ƒ°cPŽGn¨uð”©#gÊ®z|¾ëà½Þ{]àý¼,â7áÏ>æŽþq–´X©[ËÂï÷]勉µ–%Ò,§$¥´’»J8ð»_„MX°~ß;Nh*l·ÈÃͯY<ÎðD¢Ë8÷77Ç ¶¹ß½vŸ]Ý>ùµp³½½=ü²ßm~÷Óÿ°yܾuBâûß}ïn²Ûï_n¾½=ð²ãf·½¼õ_;\Sðæê™¹;ºûñ…ßA:˜u'—<‚ê!\r©Âz‚èÜ-£Â]§‡ëüÑ}4Õÿp/ÖÓù.Ž 9„¯7÷}ÿɈtïjþöåf{Üü²¿½õÿºçß¾ßÃeûÃÃÛíÝÍ?{‰©/ÝÍn!â~.‚!XC° †` Á2‚e0Ë`–Á,ƒ!X6“r¦‘ßÖDñ­i÷Ь£ä¤£¼óz}•ÛËõsw s:%HZY,©&¹îN¦.’GsÖÍ~;ßOõËý;7”¯7ǧ«w~l>î·^!¹Ýß½}|÷ÚÏ¿?Ý<øKïö>ôè¾ãDמoñ:î»§÷—î›Nz@°ÀÆMÿç뇃pZËùº»˜èn8[QzS•Ñ„nþ®—ÿ8ÑÍMÖ)iØ NH÷s'ûò™ÃËQw~Ýë*×Û‡÷W7”¯Î¶öUáÀðJô²pFNZó—Ÿ_;5-Bqï—Ò.)S.vÐcñµXòít èJ~¿4™lL—vçÙOKšjÇG_‰ù xc¯at†î¶w£Ÿ÷0ÈœZúîðt»ûw‰mýJ o¿ <ˆ.4 /  à¼xVLþ’î+YʨÊujüÔ}(w(¬;ï¶wo½ºãD$Ü®ç;p ˜u¬D¡>æ ¯ýK//=5aßFÎÇ×ÝLÖï'ës.¼ì}*/¼þªßÞÁ¡ ®/èø7ævo¼Š„_‡ñ:î|“¦¡sÆ[£Î‰y¿´¬—Á¾¨ñuòzœô†VÏMØûroQvë(|êõF÷gf¥_|U¬[ßÍθwër0XHüêüÞ­×ϰ3£3.’¿³°¤™ë/Û /{«å%˜w¿yxºßÞºt{ëôê›ÇwhòØ[]‹$ÿªH þ §{#h?lú%ºgyæé¸|›°‰þýè¹[RqÞÁ‹¿Ú^ùjl0ë¶w‡»ïOÁW6øÉ÷¾ûñG¯æ9ÝÃÏÈÃÃKtJ$TCè”q‘:¡S ?´w‰ìiðÂá'ÿªiüòÎÆ “½âŠQ¦hÔîÑXó#Êͱ›­ûåÑ~÷O9;wYÍ=Ésà/Úô/’ýT°óîà·ÆqÕºéÑw…››k/Ž7Îðb2[\¯à΄ë6ºú9ªh?D‚K•”¢ý@^%Ï¡eh¥€©íφãD`¸‘¾9ÿ‡ ]úø‚Gö‚¶‘©O··o÷ÿxüÄ®éiÖ‘d‡ùš‰ÂèøßxkìfJIlZIIdzs¼¿Ý~8nvý›½îKOXŒp:S:¤ÈºËþy¸{‰u&–A±´4dl]_'KLhøÛ¾[t××on} ßW½›xÑy ¶ñßésZñáÎ_÷]9û¬<í‚Q¥K!ÖÃbp·ùó˜Òàrq%¹ _•´·Ï{Ĉj¯¿)íýá®.ã3ñ?÷›-ïSá76ÛËÃÓãÐ7t¸g·3ì¤Ü}pCüqõèD„[]§ôýsã ‘EúìT u ò4 5¼|Ô¡¤ÇR¸W>뙋…J#Ob¹™7‰p—?äRÝÐBê€Àü¡3]¼_z÷<·n$Í“Ðqy(&—桚œÏËŠ;8òˆ7ytKd·ñ&z ¿ýñګ믻MPÈÎg •]·”'NÉP¬ó#lÃÍœ¶zZTS˜°›¹À™¤ƒ•™WöGúõ™TÕN¡Ç„ šœè˜„-Ó#[B¤Øú/nîo®z{žŸ&©¸käh˜‰:¢Rî$nÉ^¡ 3±þø‹³÷É/9ÝN.oâz‡"q^Ùîh;ÐçþyÃ)Ö EÄ‘Z »¡+”z:I~8LºÀ’ÄI‚þ{oºPþÀK<ÙTöx)ï“ò³§Ëž=âD`UÓ®”†û†2¦Vàwü ðë²w4A—xgÀqìØÓ$øý÷Ý_^¸×Ê^¯u'~”݉e¤nŠx¦§›"ƒޏr§*À Z?`º¢»ÖÙ·Ó+YØ.Ú@P¶×l·haÖãí'öwþnoÙ<‰û»1¶TGrÝÔ¯ù†½ìùép¿ùË+0öݵ¼öù;&fYˆä‰~yóE‘Ç_}Žìäž­Ô)Á;zÞ*¿ÆµÁáÅ~YÿÛþƒÏn|¹gìi¸ÅÄùga«,2HÁ6ø5ËÔ³ì—ò¦øI8Ç Ãaätf*Ë9)ôaÝî»ÏÛß,¸×¯üvÏÙŒ–:lãÔ/žuÍkg=Q)£§Cv\ðE8Ŷ÷—¦~‚ÄiJQâ”r~o¿®È¥%#ñÓ©÷ †‚ÐŸŽ‡÷7ÿWˆÙscô ¯Ï}MØqj8òÜ5Jï±9‰Nèë=‘z`²lÎ݇/–ô…&£GggJ3±ìDÛ¼XUƒ¥áÁÙ5?ƒkíØ÷Obc½ØI8BÕ0Œþe'ho(ËSVH‚V´«Rjèùîß=LË®<(¬ï}ÐÏýáÞû^F_5¦”Õ˜t¤¥¾»yNzx¸dFÇp„˜þýóÒ/¸.VÖ„Æy›@©þvŸËšÆžð?LØ»4à©£*$É,·=ÊHzÚÈ‚Î>ÈÑ«=ìày¨ü¼|-=ò äZ}ÀnXú Ùó´™ÓæàAö×NÿŸˆÓõO:¼Höeµü¨ý/œi´F|Q£—8妃ƒÁÃAÀ „t™|Ým¾ï0G™<çÏ;¨ý„š·ŸñüùÄóWqµ'^à Æíヌ>u~M¹[óÎ’7rÚjä„KÁðÂêèD„Íðþ5²à)¿FNà®÷û­—­›íããöÊWàö.û—pÑÇÖÊ*[äC¯•Y§V<͸ÚÓÑ¥^¡÷¾²s¸E?â ÀápGT ÊÔ?i4† ¤~,°;؈½x»¼ð ¦À—n¶oŸ8Û"h+4±¡ £½\Â<9M.ýêªwZðy¸à}ô¹úMY!’…C&ÎÔ]UÀº<üã"´DãH„i¯gÂ)8ôe“ç" œ;8>øEÁ²à %äé9Æ@=>é¶G}õÎÍÆÛýáN&mÞú8*²‡ìžíçE^?Xô¯:‰ys55g—°pZÁsî1ªEÞ‹¯üŒ®íYŸñ8¡bügŒ wüŒé…ë|šü$ñO*mþšñRX ÷é—=?£î8^ ¹ðíñºƒ­àãpÁŽÔ:WÂô :ëQ’é´Äù™–î’A¡ *Þ-šìR ó3é;ŠªÆ\P‹¾q6ªP¬üŒ*(àÁ‹ÅÖº˜89z%ÉWuðÓ³'G¿¹æxrˆ/zXŠÜÔ‹>»6]7?zþ^ñtƨ¹ãÿ2È-‡{¢kD\CG'‰D ÿMç•&”Ó‘_ÑÖÆ/ egìp3¾€¿…gW?80†hÔ&‹T0ñ³:¢/£å›³JpÁ_ùxœ+‚~îWáÛêÏPþ`Ñàòcþ‚ò%ðix zù½ñ¾ûKðûuÅÖ§4øU]—´{•îš¾Km²¶ú5‰Žã¢/ÀÇþÞaõ3ê=ÞÃÑ?U|õnÆNúó貋ˇÃ/ÇS1=Šö‹Êÿ¬w+Ñß5YýLÔô  °p°a·¬&zì‰A0Ÿ˜eòÅèÃq+Õ.×xþÙºågšLÉ ÔpSw¢fytôõïyÚùƒ(ÍèdHÃU½a;TyFM‘@äÁu<,’~Fß,ù†ÆË, 2JãE».÷ËQoôãÐ'ÒzœWKê/è[Ã¥sW89{7tOsÁߪFãè½èóÓ;ö¾6\qN"å¢w-NïÚÿžðCÎäVGïžø… tj vm:/b@o]»'{`BÙûIH™Ýá—;rÝ}r˜sh"ùíšÜ=㨯îr‘ûèÝʱÁEß‘oØ¥ÿt¼²·P7~ÉýðV—.·xïq(Æf.Þ.¬³CC8‰ü3ÍÕ©sàÎ$üçÏhû8TÐFǧIôçVhJôZ„å>õYgìýÕL?óªÝ#¿²|>wRÍýöp9™pf@yLõcEÎÅ6 9LJܻgŽ]Z@~½4qÀß,äC[b `¤äýÚ\‹*ÜŸ1TbuÑoºí9Õê1—–x&u¬§ øF/zž¡E§ž‰³7…¡Í‹ÐælxZàùÕƒ^{Kð†çö´ä‘ÂÆxÍ)Þø`½3¶ ´xA-N Fϼ;£³‘]“àÎ=žà͵sÒ¿^9ôW DzEÂþV|]·§Õ?€ oŸŸî4ò×àˆ‡ðçÕ«ÿîÅ Õ‘Mp‚é]×cÎ%½‚£´ûb/8w:6çÏÛšš ÅiCþ+½&`\‡›ÎÜú1Üî4Špë^ÚBOu: €OÃC5O+≗ç€18òòDð :§>¾šÃÁ|ìÚWPjð TÄ-ý½†§x@1¡›pÌàÉ‘gþ¤DÑ?fÅÝúã謎êéhËFn\:ÅpÉYˆK@Fçùšˆ\6M ñ_ %Ñ&BEµÏ@Èd8¥-?2_‹ÕÓ>¢¼(SrZ/~@Ó|=ª9‚NÏ/:|'ãàÎ a#™7i²0jܘuóÈÍfp [?cØÂÉF€xxÑäéGŸô¦ÒPJ Ö £êÏ*6ðIHM(Q, ù;ÊÇÎ,”*NDºŒ ”ƹ<©súé(YlÄÈõ*c†–¿üŒÞ‰Mu¹Réð•-)€úéhyDÇ ÙìÚ|@ƒN~Æ1ÅŸ[G›Þð®?]ÌÆy>PWž‹Ÿ¤\:õ"jšó9ò©?[ÞœsMø¢>òãç)¿áªñÂU_ªÁÇ(—”ÿ4)›†âÕ‘U¹«J=}r(lýYD¶Ž‹>ÆDÇiñÈÏ™x=½:1ÁzRíó3PŠ˜“Ž™^x`õç —˜è‚HþÀEhK”\Bì¢ÀJ:¤\ˆ=åêCP¦`ASÐõβ —Etªéʶ1Ù&Ìý´>MÂøÛé™öÏ: ÿ3ˆòÈø—jxŪGĪ‚}VÄ‚ˆ”œ‹•yˆ”±û °,¶fú_¥Ê¢´¥UK?pJŠŒKYûmAyÌÏ«bòDoˆÅt4©„ìì—¥ý °2fN—_ËÇÃ?çÄùÏé°Ø{ŒVoJ¥µ¡?gĺ.ZÈrâø[Ÿ3bSµaDNéŽô£œ¢!0¥Á»“夙\+#/H3*þ(™¶CKÆAå¿%50k`&{Ìx¬ dÁðp?ÁÍó…JN>åݪ¾MžÜ«!÷i¯'ÕÊbòý¤ YLU4û ž2Âão9¨èÓíO*ƒ|NçDÆ®ÿ­«O7Ý)‡è”*¦W‰']/=5û3€ò £ôÏy·ÿó0bKš\^2fšžV«ü ¦Ø~FÊ}3í9 ²˜t‚´,çØ‹]¦$ç v‚T;Aj’sxÚüqUĆ'ŠTÏ‹õñiE¾Oëã,‰©2ãr"±Q8¬Kò4EÄ[Vˆ.fEjÝ}gÌÄ^V 0fGƪ~Îûš×§¥6b^¡tÇç@Ålîæëhiž˜(ûù¬ çİØLlÕ¬ù–˜™-ƒ™ƒ+?)¦rM•6™${…" EÍ£žº“båÓC©«|þDiDÞûïþá öÍIŠ€¤—'a×5£õªd§}Ázy‘ÓzµaýÇeAëUY‘^dáã–ôò¼\¸”E¦ÿæï02þdïø‚OêZh>öªûÎMZíý”~¡ýŠ;–w³SÖÀVÉQ)¡ÍÖlà&sÜßïÃCq„ î¦ó9›Ë1«ÄwØŸ¶?ß¼‹þó™¾z“²uØ~ÃUˆ+®Àj—ô¿ê¤·ò/ú ¦ö2nÞo>lnoî¤m£8òIoaÃiZ†ŸÞZ)N!B › 5ЏTáid„{G?¾zfy^–YYäðcQU©ûñÕ«_½þâUöõþîÕëWDNõÂz|(*¨8±mµsŠ¿Œcã @ô&û渤n»2*ZbwYñÍLqwMùÍ3j®¸ë!šcaµ_Öó›…•F|ýÁoúpW·ß,­²á§G2ó˜ƒÚþ |êeŒòÏ\”AF@ìVFçߌËJø¿ßÌï À]«¿ŒÜ€RŒ¤²SËÅ+{£)­‡$r¸ƒðA5t~9}u¯&ƒÿJ;ÝÀ qÿMOê$øOSÖ±FåügY¤û^eèª3äKû“­ø&ºóЫà¯,‡c8~–¿¿¸b#nx¼¾û£û[]˜ý§õX­Œïoî{.Ý_’ ¬]X›¿¢Z û ¤¾$Ÿ‹ÿ¸ zþ I=£X ˜TõX8õŽÕí¦Sá;vör¿Þ$Ãy9Ü_™Jëáé1ÜþÒLZf¤Ó±ýŰzŽC)„£ªýµEô±zgGû ËècõoöWVÑæ‡(ûkëhóCéZ6¬ªF qYôéÀôsø·Pv“–¥ŸFè¿4’ØÝÉ‚þÑ¢×?(¬™ L »Ê¡m$>OÇ](Ä›ÔÈÇì$ò.#7z|c𥴮Ÿ0ׂ¹9¶t£G¾ÁWÀî‘y#‡°Á×FÐÜñgðv8xND¡oÊñ²sz2ݬΥGˆÁdÅG8Û ®ÇÏsŽÚ‚oC¡8 OŒyiÐ|¥Ž ¥qœ\ÞD/GŽÁå´¬-Š›ò_È“ñ&áá éø%GBáb”Õ‹cWà;ùx†Å¢áj’É‚s;ÔŸôÁÃMN¼ ‘£jü(ÉFkýé 4pU¿ ÏŒ«šáb-æØá‰ÅrÞIov}ü¬cà[éPž,8À¾– §òäA,ð…œ„ñ±*ðiðåÅŽJ«ÊoNó£í•Ÿ–ƒÛöLÈÌåñðA=œI!ª!ÔEŸ Qz¢¯t§6ô†g™ ûT8Ú.K‡‹Îiè´y¢úŒ#®àªv¬–"~À&HÆšåéiVJ·,…E*ßj¼–µÐ_ý$¸¨úk˜µ—µÑ{ðU"¨ò£¤z¸.zu¤W(]Cª$Ϧ*ÿædÉsÉjï Ò:/¯±¸¸:/H‘p ¸¸ÕsÎ}ø†èöNʽ®)ûšvŽäÝ™‰­œÞnÌxmá®m´Õ¾ùánÒ2i;Î÷Â/û›·ïØcç „ÙsŠb öÔN÷ënËŽSMÞ„|]ïÙÆ=;ïÀM;oLà¶È|Ü>ÁŽÈ zq·Ä(m"Cû¥ÐHJw€ýRñ„Tøl BÂö l´Bäh}ù&Ã}ÆxL·°u%n¶óGƒNªŠDè_Üœ /o°i6± Êéso8wç §Ï½i¹71àÕX|À\~Àùm71î;¾`ÓmùFJ2î„â´ ¢ðvñDâ™í?1€å7ðéYK™ujRŠúùv·{$ê‹ÏÁ¬DÌÅÛ b$NwÅ0gŽ~Ñœ€™ùƺH¾pCV ü <{A¯êFKö…Åi‡Ÿž·•{yÙÞô ±—-üùù˜!KA€^´E.f_ÐÇgDNŸ=ûôâ<ì®8#¸¼Š âæNƒ™• Ëd„$|DCb†%Œ¡üÝ~øñ7Љ†3»„ÓEd!5µpE¢”‰¬SÍ8ö̇4€’Ð{›KÑ¢ý]FûÝæj|ŠÇ³W׿Vœ=˃8ä$ú|ó÷§ýÓþ§ag³rj"DÊ©ùqf–¸Ò¾8n>¢¾.˱,b—’ÚÕæùlÅ‹'[&kìR,¨þÖ}6Eöéb ‹(®óá9Ÿ"¦_º(*~Á­u68H\5½îzÓK‘=…§K*?GZÖaÅ)‰ë& Òiôâz[[±°')?«ûìà8ò ŒCY6EB®¤a:8ìí%É"B(í%©ýO_š/"†"±fÒ[í>{i6Y[‹Ç¹I}×ÿô¥ùdA²“ŽŒé}øÒt²tŒ„øIsâ]?=á%Éd‰.”ÈÂG/M&kÀ‘ÀF‰,|ôÒd²)‰©”ÈÂG/MY¢áœÒ,íúÂ|Edmˆ“J³´÷áKÓÉëÃd$«è ]ñÒ˜‘e"K+vâð™—¤‹,ñ@^É|üÒ„‘¥"G,M’þ§/ÍY,bQÌÒûí}øÒtËŒ°y{*üÂG/MY0âÑÛÒÈ|üÒ„­è™Œ ??‡‰JY Ï¡‹nÞjónnX¶¼Ü®CŽÈèÙ`xÑ©†ûó—îæàÈnà|L¾èµÿÁxnäÈþÞ’ÜÑqÿüøÜØ_É‚,Ñ AÆü™¡#~“¹t Itñü;×Ô‹xKf6¤ÝÉ0óÎÓ«ïù‚Œñ0‘ÞP8¯ì+ŸÍZ™uåοòrŠ«;ö/&¼bÉ-çY¶æ’§ú3^D÷}¼ñÅhnŽÇ›Ãݲm¯¥¯»eüJîÖâTs–>…„€ªe¨é ž¨ûöªwšøÂ¡8‰WËšÊ0Hšþ n_¸Tz“Ÿî˜¯Fiô“~D[!ü’C­à¡VG„ötÞÑTàËY##p*ùé,s¢#Š]LdZÅBq–wÛâ¹0›ˆ˜žLÕŠ^ßìo',Ç&È&Yï]˜vr8•§£ƒÿ6WXUâÃæäK/4"»‡Èçd¢”®Ÿç/Õ·Åœº §ÇMMë—B‹Èʼn„<ñ¬o~×Ó¯øæ$ø±KzàÈ6.‡™}¢¢èÝ~‡›¼Ü€Ì‰¶-8P7æfçI®«ßì·7”çлýñêáæ>ÄîÂþ9=n³ 'c}ù¢ŠPÆq& 9‚¢ÇNžÞ~¹ Þ®[àÛˆ“_JEçÕwøñæ=ïB¼@çqJ$ÊÎ$1R¿þ° ŸÎ/”S$>•RD‘“/Åóó?lzŸÏ/‡Ù$N)N’ÙÄÊI]Bœ)pËáû¾Áf·¿Þ>Ý>bi‚eS&¢–³&+ÂVòÎçƒJ}ÿÝ @ûÅ´“,|žw1cIý %Í7| WÂdI$P·˜~Ì.•Uô ý'|ú"ñÅ#Á/æ#=Hþ¬ŒZQ]ñBQe{6n.¥W’4ýO_8Må™0"£<áu‚£²HÔdÚÍ€4£±žFÔå…yÌËèSv1¨§4—{|Iþ´$}þ<ø<2ÎÓ÷÷}Ä›ôœ$ïg>Ú'¿…ßBñ uZk$ÍXô<ÝmÂÇŸ¢ÏåaéÍfMøÓœf)žúûß}ÿ4·êTî´Dóãÿù‡ Ée-iAâõYœyÀ")ÏÉò–àw»ÍèªS/zøÑù¬ts¹$·ÙŸùK‡E‡/ï¶-M{n®„Ï_ž8@!åÝËgwÓEQÆÏÈ›ˆ„ÚM¦ýŸx üÅßö®Ù âQ^V—²Ÿýövó Õy}ž-7@&YhŽ6'Ì?Ìð,žÞ=ÙΟ¨ðã<¼–BÖ*Á+‚ÅeúU_„hªòœñÀ&œ&T8ONkà<Þ¢K‹.¸ dÔ£4W&1!nõc¼¸_–ÞÊGzN‘óä  )0ÊŸY}s·jÁÜ`MHÅñ!bzÕµ¾C¿ÛâA´Ðb ˜‘è2é´Ñ3ûÃþïOûã#p®}iЈoðäàQõÀ8™)¾OÛ=:YrÏ>™=iþÓZ/#ªäÄé(çÑ!9P ÅeMÅ b Böå´Åtvãöôd–¨Žå¯zI««^,‚eêÔ—ÉWü‰..‘2 ”³û£'§ÎÄÞùÃÓ®\¾=ÚaÊn­ésoäýÿa¯Ú`«HHæÔé;ñº´W—Ð32á§ÿ™Š®:#k<Õ<.$z[>;±Ÿ¬ ³éæ}^Ézvìü ¹¼ÏÙ‡“¿Øi?àŸ9)f!î„[Œ÷j’П±ÿAïa޽b¾\ެH‡ÅGöäGgÎñ5so4[ býï¨ÅIPª§;azŽ$]0¸Dc!x9¿]0ÔÈê½z†(Œ¥þŸxn: gàeôÄEƒ§á%ò(év'¶Ô§*‹Ã¤@ùú×'gT_n7W0N†ßÞàúcdÈx‚‡°ŽŽÇLùÂC¦«°œòùqûž 2üÂ;c‘*,ƒL Ë,²AŽÀh+X<A¸c­e8‡ÏŸƒM_áõHu º ¼¸‚_KÎÓÝy›w‡_º)¼¹=þvÜøc®÷ûÛO{)/>‘ËðRø”Ä”õËØ˜±3°@ev›©(y,˜–ü‘<ªCrù 2ì³Ãã;_’Kö޾þRê§rVB.YÙºsŠÚp„¤WÀ©*xIÝSðÂVðºV„êƒY¨YCš«‚C=B<$± c¶Xƒ` ]¿Âñ¸‚]*,¾*,?P#úõæíÃáé_ Åù=p|_;‘üô° ì“jv/ &›,ṟByxm¼<…"Ç/OPÿ–(:Þ´Çy¼æÜ©çø×þ³¨Õ/¾z^µùåÝöd ÙÛûûýöÁOƒá+:Þìö—þƒnÂx÷qXuñIg‚dz 섃rî·^!¹Ýß½}|÷ÚÏ¿?Ý<øKïö>ôè¾ãDמoñ:î»§÷—î›Nz@°ÀÆMÿç뇃pZËùº»˜èn8[QzS•Ñ„nþ®—ÿ8ÑÍMÖ)iØ NH÷s'ûò™ÃËQw~Ýë*×Û‡÷W7”¯Î¶öUáÀðJô²pFNZó—Ÿ_;5-¾çf] µKÊ”‹ôX|-–|;]~ Ÿ½4™lL—vçÙOKšjÇG_‰ù xc¯at†î¶w£Ÿ÷0ÈœZúîðt»ûw‰mýJ ¯S.·\ÐÙ‹.4 /  à¼xVLþ’î+YʨÊujüÔ}(w(¬;ï¶wo½ºãD$Ü®ç;p ˜u¬D¡>æ ¯ýK//=5aßFÎÇ×ÝLÖï'ës.¼ì}*/¼þªßÞÁ¡ ®/èø7ævo¼Š„_‡ñ:î|“¦¡sÆ[£Î‰y¿´¬—Á¾¨ñuòzœô†VÏMØûroQvë(|êõF÷gf¥_|U¬[ßÍθwër0XHüêüÞ­×ϰ3£3.’¿³°¤™ë/Û /{«å%˜w¿yxºßÞºt{ëôê›ÇwhòØ[]‹$ÿªH þ §{#h?lú%ºgyæé¸|›°‰þýè¹[RqÞÁ‹¿Ú^ùjl0ë¶w‡»ïOÁW6øÉ÷¾ûñG¯æ9ÝÃÏÈÃÃKtJ$TCè”q‘:¡S ?´w‰ìiðÂá'ÿªiüòÎÆ “½âŠQ¦hÔîÑXó#Êͱ›­ûåÑ~÷O9;wYÍ=Ésà/Úô/’ýT°óîà·ÆqÕºéÑw…››k/Ž7Îðb2[\¯à΄ë6ºú9ªh?D‚K•”¢ý@^%Ï¡eh¥€©íφãD`¸‘¾9ÿ‡ ]úø‚Gö‚¶‘©O··o÷ÿxüÄ®éiÖ‘d‡ùš‰ÂèøßxkìfJIlZIIdzs¼¿Ý~8nvý›½îKOXŒp:S:¤ÈºËþy¸{‰u&–A±´4dl]_'KLhøÛ¾[t××on} ßW½›xÑy ¶ñßésZñáÎ_÷]9û¬<í‚Q¥K!ÖÃbp·ùó˜Òàrq%¹ _•´·Ï{Ĉj¯¿)íýá®.ã3ñ?÷›-ïSá76ÛËÃÓãÐ7t¸g·3ì¤Ü}pCüqõèD„[]§ôýsã ‘EúìT u ò4 5¼|Ô¡¤ÇR¸W>뙋…J#Ob¹™7‰p—?äRÝÐBê€Àü¡3]¼_z÷<·n$Í“Ðqy(&—桚œÏËŠ;8òˆ7ytKd·ñ&z ¿ýñګ믻MPÈÎg •]·”'NÉP¬ó#lÃÍœ¶zZTS˜°›¹À™¤ƒ•™WöGúõ™TÕN¡Ç„ šœè˜„-Ó#[B¤Øú/nîo®z{žŸ&©¸käh˜‰:¢Rî$nÉ^¡ 3±þø‹³÷É/9ÝN.oâz‡"q^Ùîh;ÐçþyÃ)Ö EÄ‘Z »¡+”z:I~8LºÀ’ÄI‚þ{oºPþÀK<ÙTöx)ï“ò³§Ëž=âD`UÓ®”†û†2¦Vàwü ðë²w4A—xgÀqìØÓ$øý÷Ý_^¸×Ê^¯u'~”݉e¤nŠx¦§›"ƒޏr§*À Z?`º¢»ÖÙ·Ó+YØ.Ú@P¶×l·haÖãí'öwþnoÙ<‰û»1¶TGrÝÔ¯ù†½ìùép¿ùË+0öݵ¼öù;&fYˆä‰~yóE‘Ç_}Žìäž­Ô)Á;zÞ*¿ÆµÁáÅ~YÿÛþƒÏn|¹gìi¸ÅÄùga«,2HÁ6ø5ËÔeç&üÔwxúŠò¹hÀÑÙ™ÒL,;Ñ6oVÕ`ixpvÍÏàZ;öý“ØX/vä„P5 £Ù ÚÊò¤U#R àăíª†”z¾ûwÓ²+ ë{ôs¸÷¾—Ñ×_@)e5&i©ïnEcÇ£“.™QÀ1!¦ÿ|ã…ô ®‹ƒ‡•5¡qÞ&FDª‡Ýçò£¦±G…'|çö. xêèƒ I2Ëm2’ž6²° ³rôjF;¸Fª?/_K|¹V°–>hö¼mæ´9xЇýµÓÿ'âtý“/’}Y-?êcÿ g­_Ôè%N¹éà`ðpð!]&_w›ï;ÌQ&Ï9„Àój?¡æíg<>ñüU\í‰ø‚qûÃø #ÁØZ4¿¦Ü­yçÉ9m5rÂ¥`xáFut"ÂfxÿYð”_#'p×ûýÖËÖÍöñq{å+p{—ýK¸ècke•-ò¡Æ×ʬS+žf\íéèR¯Ð{_Ù9Ü¢qàp¸#*eêŸ4šŽC†R?ŽØlÄ^¼Ý?^øNSàK7Û‡·Oœm´šØÐáÑ^.ažœ& —~uÕ;-ø<\ð>ú\ý&¬ÉÂ!gê®*`]þqZ¢q‰ $´×3áú²‡ÉsNŒü¢`Ù‚a…òôc ŸtÛ£¾zçfãíþp§ “¶‡o}ÙCvÏöó"¯¬úW¢{sw·¿½½ÑÃõ7éQð¸ÈJ¸;QZ‰wx¬õܬ»:¾»|z|ÔÀ0ë žºçiÙ"pÑß^P¼þÇqôØá貋îòs^ã3­*Y»¨§ÉŽ„øicô!ýk§Ë.82ÿãQ*EFWáØÞû\98¥>ú¼Ò­>-8ɺ&FóiLÔëˆ3vþàQÆËóôVòH¯÷®î­Ä¤öñmèp¬èMúPtmdpv šgTy°êž^)½‘26†âÓßb9}ïhh-Üúœ hq. dï«2½ö„íÜê^;Æh|‰SÑqVuwò—^Ü õãQ8êgJ ûK.|M~ ’ø'•6Íx),…ûôËžŸQw¯…\øöøÝÁVðq¸`Gj+aúõ(ÉtZâüLKwÉ ÐÎïMv©†ù™ô@EUc.¨Åß8U(V~FðàÅbk]Lœ½’䫌:øéÙ“£_\ s<9Ä=,EnêEŸÝF›®›=¯x:cÔÜñä–Ã=Ñ5"®¡£“D¢‹†ÿ‹¿¦óJÊÇéȯè ëá Æ²3v¸Çß@ßÂ3Š«Ÿ C´ j“E*˜øYÑ—ÑòÍY%¸à¯|<ÎA?÷«ðmõg(°hpù1Aùø4<½|‹Þxßý%øýºbëS |ª®K ÚŒ=ÎJwMߥ6Y[ýŒšDÇqÑàcï°‚úuˆ ïá蟪N¾z7 ã 'ýytÙÅåÃá—㩘EûEåÖ»•èŠ~¦jzPX8ذ[V=öÄ ˜‡OÌ2ùbt‹á¸•j—k<ÿlÝò3M¦äj¸©;Q³<:úú÷<íüA”ft2¤áª‹Þ° ª<£¦H òމà:I?£o–À|Cãå?P¥ñ"]‡ûå(ƒ7úqèé=NŠ«Î%uŒô­áÒ9ˆ+œ½º§¹àï U£qô^ôŽùé{_®8'‘rÑ»§wíOx! gr«£wOüÂ:µ…‡?»61 ·®Ý“=0¡ìý¤ ¤Ìîð˹î> 9L94‘üvMîžqÔWw¹È}ônåØà¢ïÈ7ìŠÒ:^Ù¿[¨¿ä~x«Ëá[¼÷8c³oÖÙ¡Š!œDþ™æêÔ9pgþóg´}*h£ãÓÎ$úó+4%z-BrŸú¬À3ö~Žj¦ŸyÕî_Y>Ÿ;©æ~{¸œŽL83 <¦ú±"gb›„œŒc‹ŽCîÝ3Ç.- ?^š8àïŒÎ ò¡-10Rò~m®EîÏ*1„ºè· ÝöœjõŠ˜ËK<“:ÖÓ|£½FO„ТS ÏÄÙ›ÂÐæEhs‰ 6<-ðüêA¯½%xÃsûÎZòHac¼æo|°Þ™ÛZ¼ '£gÞÑÙHˆ®IpçOðfž;?šoí·v2ƒ—ÿ¶’¨é5zÒ‡s§´¿¡¹ ×܉~R ès7ÞbçµMZºÜ“|ñP´ônôÕÃÓÝ›«‡Ã”ý›öö“³Wñò¡“­ÏûwS!\ÐE, áÊøŽŸÚ9éß ¯ú«…cÙ¢Na+¾®ÛÓêÀ†·ÏOwùkpÄCøÆ‡óê Õ÷bÐêÈ&8Áô®ë1ç’^ÁQÚ}±œÇ;›óçmMM†â´!ÿ•^0®ÃMgîýîwE¸u/m¡§:ž¸ª‡’“1ÔtYÊ C@ÙW ³Ãë.þz<îBbã-RâÝþm†à¶³˜\ÕÞûCÎÈJ<+nÙK _^hhâ+nbÕGɹu<•ïœ}ÉM]ôš2ÜoGrÎÙZFð-õ—Rꂳ‡¿…Æ/¸1N=‚™¨ä”üÅ8Òò¤FÝ窣½¿¹Y×3b .&J|6á?xxÞ9Z÷ªJ¸ûÈß2>&óŒ[fú‰š;›òÜC”|ûûnó.r<ä:Ýrçt$ß"“T€Y!ä¤GÔ£‰¹`5€[…—:ÜPèî5„Ëäø~]xÐxRá=¯Þí'ÓR²\¼+Mz Oƒ·0±ëszÛ^žW.ÝõÌ1¹L%ÆñDÏ:8‹xlbW¼NdÍ…©C_‹ûS¸¨º>ÁŠ^*ìá.È€Ž ÛûÑù$Í3Ä `´Óð$ÍoŠxÌå9`` ι<‘6ÀgžÎé ¯æ00ÀÑõPgJ„•þNÃ;å¿&Ž Õä¼Jòõÿú8}ü/AÈÕÀ8‘,ú2_‹•Â>¢•bµÑ4Í×£úê'ᨙ~­ó°fϼI«<ÂæåÌ?ø³¦ÝظâcYçTÞ#ˆçóLðóI/!dßÀo7(˜„BësLx EEOüçrÓáÂPÙÓ¿g<„_ÎámŒñò](Be&ûNŸxÒ7Øpš–áçD‚5† ,l6Ì”0QNúÀWŸÿøêušåyYæY–ÃEU5îÇW¯~õÍ¿üË›7îÿo~‚$Op¦<œIøû/_e c²ÿË_ü/¿ùá~¿ùéÛ_ÿá·›ßÿÍoÿïßÿøÓƒ«¾ù—ûÓæ¿·?ïwWN/‚óm7þÿýûæ¿ÿ÷«w[7Ê}j±ÏtÂñ+Ò'î+O×Í7ÿòÝ¿ýö§ßRÃýæ6_üËÆýáf÷_›Ÿ½B°}ø"+Ë_m¾ûÝ·?|ûÝO¿ýaãïío²ùîþáþ&þ—‹Ë›»ÍŸþçO›?ýùØüæ·ÿãÛ?ÿá§Í«W¯ýÝvÛÇím|Ö³³þ.áOûÜß<¸Önî¿HÓ_ _Mð»h5í\ùn¿ÝíŽÿµñ…vü_¾ÿá÷üö‡ÿgóüöÿÙ|ô+ÿgÿkhÿ þéWÿò«ÍoÿôŸ¿ÿÓoÿý÷ww‡ßü:Üß?¹{æÇŽ›èÙñ; Ãá7Oïï¡|§ë‡©±°`ôPñëɱÃ׬2r¸±Þ¸9ySßþù§ÿyñû?¹oþñ·ú ^Ö½xáø•Þ-ºêiÑUǧ˿a]ÒÕ4êð±pÐúñ®Ä¡æÖ@Xw³4kâwó›SÇÇíûû%˜W?.ß;;å齿ºº6܈¿¹ûà¯Íµyº;Þ¼½Ûïâ_Âï(ïÜÜËA?Àii]'á;ôK•ü*Ü7|Í—¾‡“KÞÞïQ Z_75Åoý°øÆÐéäÉÏט탹ûû?ýøÛ~ÚüþO?ýÏþ,ú¿¾ýßûãæ‹ôuò:sÿ÷êýöÖ×ýÇöÕëWnqÛÿms·üW÷KÚf_¦UóeòeúŠÖ¡¼mK÷½äuúúU’~å. z>¬•þn ºüÿÿÕë/2h%y^+U‘æ¡•Ll…[X² Âî¼/ 5I¦ÛèÊ5ÄÛ¨Ir×AÞ$KæÛÏÏ»¼w:adêÅ‹wk>O §ž×€ÙMžŸqòü,NžóÏiP,J³#h½ó‰ãåîy—û–†2wr°øË½6üŒËßß<ëîÇ›îŸñ§c±…wS"|QøœÁç[ÄÕunö¯\i8ö›¤qS}í# |ä ¯ ¸“]¢F&D‡‘òç?ýþÿüóoiÀæøïìª_¬3†N†Å`í¿šNxõ?à#7w~÷ÓÿàT·âfþ¿°r¿òE‰¯»=,¶‰û›³AÿÇÓí-_í/\¸ûó´æGìšCuvŒŽÅ Æ›.Óîwû[o.uÿ…gú.º _ÿÿ¤$·º7* ¶á(ÿ½zà êý!‘ÖûƒSHqèñRwÃ{äý¯,„·‡Ãnr« @h ‡x±— ªóØ„£§{óïíÝ øÀ§Þ_²Æ»ã¶ðí-s ,s2<Æ.UO ]k©0ƒ÷3¡«:Q²™—ÌüŒþPg%Š‚<\Ñàu¸¢BÙÐÝ#oàYp’Võ"QàÃD¦Æ|¾Æ`‚†p$½žN~ÿÌË—ëãàß^xíó-Ég¬vÿå½âŸ¬æ¿WšÝØÌ|Ó<À#â¨ÁjY¯Ó´„.¬Špø§ûð»ÃûûÃÑW~¿çk3¿þÒ;TÓ¾Ã}<¾Uå>.ýǰÉêþú­ÿÖà’öuæçTå/ÁÍ$÷gÚrBý.Á+ê×%ÝâºÜg¿ÃÂ=šîŠ«A8¾¼Êö-Æuü#ü2¬tÆ…^½~ÃM¶¯ |,¿õèï5Ø©Dº×™—î¡m:rŸCu>Ç6± þútô¥Ñ7WXdpWoò %r¤iwwH{â[Ã/®-zN.fÑ/9røÖ¼Þïoý‡K³î¦~ë»ÝÿU[0¨ j–ôJLQð^F‘»%SæÝ ½ÏÔÝ ªªÍö<•4~ûpxºÇƺú¾ð\ä÷KpЖqé Kð`Xׯý¿8X»ÚŠÛÇ |ê nïï÷Ûÿ$C–ãÍné?èžÙÇWâûàÆË×Íh ñI¬8GÀÍéû“ ÖBMkzÕø)Öþ°qª=WXÿûÓþißk®òs`4¸ø€`×ÊïïîŸ|€˜Vƒçöcø®ºü@Å?nŽ›k2¼úŤ·¾Œ.ÙbNœ¼u¯…-0øõËÍ··Ç^vÜìïœÀ‚c×4MÞøÃ¸]îèîý^«O^™—H~L¸޽!_súVODšŸ\†ÙßCšb‚„ïÜÊw~Ó“ßûÒe½ß¹/üÆ¿ïa.þzs|òEßÜäØo¡fáþîíã»×TùŠ_{—âÞ½žË½{¾Åë0äîžÞ_8„l\×ú?_?|¤›žz–œ¢Ã™`=ÉÊ¿ÓÔÆ{ºÖ¯eÚc\ÕeÉë^»ýðþàßµëãÇ«Fêdü«ATŒï3ü§»*\šŸ—”ôow].M¨ñúD“’‹ý]ú¥÷‚Ýö.þyOUÌŽïO·;½½G8•X˜3íîýÿ@8±,|Ü“ånâ¡ö7N>œÇ^Dî{c-+Og&©ú7~úí¨ înt<§/‹ýÆÏ1¼¤+é›îÝ^”EãÔV^ž†¢‡ë­{½Ï{ãÚ EøÔO\÷gÔöݸž÷ë Õw ?Àß»!ßã­%ÞQ†«ïÿ—Mÿ/ýõô7éîöÖI–›Çw\"¹ÔE’U$Г@^~ïñ5_/ÕÔóÁo§oÝû=‡oÛ»Ã݇÷‡§°²báñ÷¾ûñG/+Üœó‹íá¡GÕFVÎh}n»ý&üö“Xê¦_Ü¢¹‡ùèÅfœàŠ@5}Ÿº×üa³uŸãZ¿ßuÍç‰Ôü cÕ/{þ÷M÷ûwï^5ŹsÓÿг¸žØÜ\û!õ)_Ûa¡ºå¸éêÞ’§§Òo˜–êÚýÁwcÿÝú;¶°ÞlÜ»õºØ:Âu¨tÊrãÒë×>LE¼ëù§ÛÛ7~﹇–I}rRÆo¼ª "ÿF`<ª±„ÊÑ›Ý^÷‡0LILe~u òÛ_öÏÃ]o¶å¢`g£²tþé§íßöÝÜ?\_¿q‹9šÌ½ ýø½„UîÆkÐN¡;Üùëz …ÄÐ%šúäñ•eIx>ŽIÁÜ Ù¬¯;Sâ#,6  ãTw¿ÿçÞi€¬6ã_©Hà@g8ܳòêïÝ_QpïlÁ_h*¬ºç•°*S’›>÷"ß|òcg³ôS"ñ%ïÞÃòqEWÿ“Öšõ%w24ï+ö}ížÕÜ×^2¿î”]¬#ÜÝ£ߣ§ë€•0Ô}hñPcíÇO#’ièÅü'ê>TƒÀÚ8ò¢AÐqss52%òvŒ†É«h†\áRàçÔÞw›—…ÂÆ‰WyðPÂüu°Bá(‚ý¢®Ñ"7 xqBÿb§¢¦éeúŽ`|£ôäF´Ä<ÿlŒ5ÿ{~?ì½F·÷kîq¼Øî©ÿ}÷—A6ž íŸÃW¹H:I°/Áé/nëƒ5áMJÍäãf†Aì^„î7y5 9EK2·½`ã^JqüUïÁŠq‹ƒ@õÐà0¬ü´=ùsß\>h¼$¾²±o‡Qñ¢:$ô…Í·ßÿ~løúŰ¯ˆIxë±3àþñèßù­7ŽßnÐ½äÆ»n0ôÐêSyƒ™°®@MÉÎ)2üƒŸÛðyˆ½6M½÷Ð0LÚzÑžh´Þ•èåFWÙ¾S/—V¯÷/!ƇN³diä£MúÝ_žL³î \}½ç š¯°Þ5ï½É¯F½9hZ^TGÝ/ŠÏO-ÞÁLÐîi…nñSU¸»;Ÿ,¡þ0ÈNbÐoÏ(ƒÝݺ’$Å‘˜ùçÅU§ÁÇ÷­Ç÷åó!éÖ½_çk<ÃF#ܶß6I÷íÿ.TTî¼=}[aTµ{VÎòúÅ~û=¶0o(û {q`þ³k®K¥ñKÉîlHt¿>«(oxô*;Õ/†䉔±.ÝgÉÆZS7ðù7ÐnÜÌS ‘.Ï ×ÃmÞ]ɳÅ[7“»Ã Cš)ü7~aúÜ ú+X*]É!Ò³W¢ëjI°?yz—\êÏSýÛ‡çnÆÞ Cû¡CýˆÇ.Oß÷Á¿_¿ìßkw¼å×ÂÅü¶¾àŸºž°í§Ó¶»ù¢ëÑ5Ô¿]Üã¯O›Âú <¾Cc|ƒ/Â]wÏM уӆ÷²@¾QTVÚ®°ØÉªÁF JŽþŽø+ò¨úÀé þ6¹Ë6­óþ þí{¿b7+|—~évÙ³²-ùÇ*‡Ívúrî¡Ýþ}Uõvâ{í~_îô«IøjÕ¶IÿÇߣšùjÕÿ±ûjõºšþj$ƒ»¯Ö¯ëÙ¯Öý»¯Â®ÄôWÓ¬ÿc÷ÕÖ+Ù3_mû?v_MÑ7ýå¬ìÿØûr ûô—ó¤ÿcïËhNÎ|¹êÿØûrjÀô—‹Á½/;ewf\ÕYÚôì}ÙõÅÌȪ»\:÷c<û¾¹±•emÿÇÞ—ÝÀ™]Y^öì}Ù=ÎÜøÊŠÁüå¥ÊeÿÏéL|ÙZª··Hƒ¯ËoŸw¹[}nß/ŒNyû°½{„Þ™ñ„_|ºßÁBú _ŽÌÏɱ@Åã-üŸY#üådÐ,~áÝóèGô«ííí+Zm.¬Ü~?;Î…¯¬6æ…¶?Õ‚¸ÝÃýž“û7øâ‚<ºÁõËL¾÷?9|ëîTQž÷‹XOØQ££ôtbH¤§(vJ ¼žŒ´À^Êú­0z¬SÝàê”t·ž^gŬ§tõþ^õ5ªÞßêRïïM_êý} èôþž&}%¦ÿÁ@Wéõ•þy_±èPô•†þe_!èPõûþu!ïÐôéðÁ3$™›+û‡â ¯[QfaƒcA5Ç|xÜÞÒ쿼yë¯Ï–å%n?Ð׺Üäf‘‡d$?WÜôŸà‹þoÝ%ëÝϽ;ôeÔ”XZMõØÂA¹(cvtåjsœ1;½†.p»=Ã)ö7Ûåa÷!–ã±Ooo£_|ÆŠ¿4½i8~ŽúVD’Ö° ÑÓ%µ7Lú.—l`náÏÝÚè×WW g }.‹~ñ¸~ë²ç‘IÉ“ @°Ušüöª¿¶§äI>áÈQC~™O½Cwðî™OººmÈKó©w¨áÞYó‰wðZùl>õ-¦²ëæïá]:Áƒó‰÷È)¥9Ÿz|§èÏùÄ{øVÑ­ói÷wOðî|â=2œ#èäùÔ{л_Ï'Þ#§w .ŸO¼ôéb¼äs+7\´Ú¢MžüéM­ç&ƒÓrOÏd)¡j)¸³¿½Ÿøt{¼ eÊCÓ©·ÛËýíÂGðwGEaöæþ²gÝÛêã?Ø?¾ßÞÞú&ÊX@±,EËuþÍõßÅYrµOYzíááæíÅp”L=çP}ï©i%ÝÌ;UHð‰Xy%ßÐ߾Ÿ ›ãfë£ì|@Çí‡ ºw›¿ž vB'}öÅûíÎïäC¬ëÝîÆ)pOÛ[Ê8¾;ürç³mœ:´8º¯_½{8ÜüééWp“ÝþáËÍo·WïÜ àÙêc(p ‚¼}D¨ûŸãò„_R¼Á«Ÿü¸‡Ÿ~íé+òUsX•~ìé¦ÔÊïø=ÿ²½ƒXak‡1›7W _onoþæZ‘èÞjBiMx•2ÞrEŒ(#‚x¢qš1ù_!VÓ‡H?8 qù7>ÃzÄ´Ÿ¯1˜"X¶;üÚÿ€ "Pºñ“öõæÒ¡úè®Ë=„~Ýù°ìËD¡ÿ_n~r½N_v¯þÞµÎïÂßÅÇI¹a< ÎxòotëÇɽ{»‡RæúÈÍ;ŸŽÂO1ß7Ø%‹Ö™.Îrj¡é]µÆJÓk—š‡g¦Êºï{|ÖÀ:z@ëèAÉ:¿™ ê÷P-ܾ§^/á-Í¿[Ÿ×1õFáó5Þ#4´Hm™=Amâ$¡á~˜ŸÃ7íÞÑ@™Áë«1ƒÌW¤*<9 úΩÀ`<áK–d dö Fþ85DFW®1XFMâ°9~NpqZ ‹]w¶ö‰_£Nov]Œ&„Ÿ¨™ßÒëZü’!cÁ+ÆëV|ÁØ ¾^ïÊéÞW™Ä?/?®ïŸyWÿ•w¦#©¯oÛÇ“O'Y·î¸–.úW1í뢻»ñ üWq¤öÆÜâq ûÑ Æ)^·â8ÅŸ;NÉ/)¿ûáJ¥ý¶z=¿ämù$¦«iU±»h÷ĭѦùr/û³¦ý(¶BV!Öxkƒ70Pz]œ±ì*¸¸ºÙ½‚8ªWPPð½ÿŸÿàÅÿ=mÂïa“ùâçî( ê‰.ýsÿ7È{òatt÷^]XüæBä8–®YgXû¡²A1Øb8ö‹¬ä%ù à`àù4 =¹Êú.Áá?F#, ÇÏhVGÑNwNò«f—'ÙeQäes]í²ªn²r¿O¯ö»æÒu“X) ÃM[RÀ“"Íë²Ì÷É.Ûo/›¶©³Ë¶ÝÖmÚîŠl»I–ðM|-€¢h.ëíUs]\yác2’2oª¶¹Þ^¥ùµ|p$ßÄý“”YÚnwWy™n‹¦Ú&×íuênZíó¶lÒKù&YVµýÇ©/ˤ©šúúº¸¼ÎÛËëë}Ú^×åÎ÷JÙ.ë“æ²J÷Íõn{YÛ6Mö{÷lí6»Ìšm“Fû¤»‰œmæ¾”n«ËmV¶yQûë¤r)¯w×Õõ>ö8uÚ#IݬjvY^\–×­û§H‹ºªÚd[eÕužÆ§í‘¤Ùe™ï.Ë2­.›$I®ËK÷bó«êÊ!^n‹hÇÖÛì³ÒµË¦ØgERÔe“]»~)óËd¿+#$y1xœìò:Ý»§¸¾*š¦,\ï¯v»*¿N›*k«ùÁæIªæêúújçÆJë:4«Ê¢­’|›V×—éUSÏ“úr»oªä2ik÷Õ«+÷>Ø}â”7.’ÂÉi§Oï[§L‰Ó1œè®‹z™âçFC½s#¹,³d[ïë´mœhÝ;%Ð1N¬;ýÁ攽mâcrµ«ÒÊ)luy}íÖ ªtë`ÛDF숤I«¶º¼r ýÖ©‹åÕÕΩ&n"æéeáÌB7åóÌéGåÎIÚÓüöûÄÉ•b»Ûm‹z™~Ò¸i¶½Lœ~Öìšöòª¾¼rŠÉÞ)—n]-â°¿ »A•:ùxY'“òN2æùåeêÔÒ¼ðÃ$. ú#ÖY•[§š&¯ê|¿/Úºv¯Ê™N¾åWÙ‚qâIœØØú·ãþŸ³SòâªqÂñÊé×N7­wñŽí¯;3j*½žìœTÛ¦ÛÚuȶȯ›}åôÁˆ(p$}ËËi"EÒ¶»ËÊaìv­[°ŠÜ ¼mV_¹·Ńaß–íe9v•ºU:ß—™[IJlß´We[§qý¤?ØÚª*ÓⲺ.Óºië&q#­tsfïT%§¢/ë“Ö=Myí®“mëÖð}ëÄÀÞY"Uá –m|öû¤uòÈI€:¹®ë~äçÜm÷nœ8kÈý›ÜNMu뾃(Üs_ÆÕ…¬7”÷™»»¦È§#_zgÑ\n‹ëÜ›»,>3û¯Í) IQ–NÚÔN‡ºr"wëÞûÎ)…ÓçbžÍÑÌtKvµÝÕÎÔͯIµó·Ú^—×N 'åeÄÛÛ÷âÁMÜÿåÉÞ=NÕwbÇée×{7€öN3lò¸ 3x×­“»Nâ:íÍkþÍÞýZnMWº‰ñƒé:­’ÊË«ëK'^²Ë´qÊ{Ú–Îs‹ÀB óÚ-Er}ål§ËmÙ:U%ß_¹UÚxM6á¨íÏL'tw^©Ìõï^ÇÖõÐÎXn~î÷×±›ŒÆÉu[;])¹.R§€í½JXT‰3‹êýÖUÔí5x;×nˆUNÒ%»¢Ü]]»5!-¶M¾uÚ“_™â¸¾ð½vÿ¯uƒ3Jœ¹öêŠ3˜ëÄ©YêæìÜMí¹ÁÜ“;nxÅ*ûmØù=«8ë3.]ž|ó u æìJ„‰WS᪗‡Ã£?ŽzYôwû÷Û ŸÜ!3ª’¾ô&°z^>uxK½ uûãz¸Hc,lŽS‚ÊWÛ·oöo·‡‡Þ_â§n¦us¿„¿~Kõõ9>Üí( )þâ‡|½ùá7ÿOºþöñðåÇšýÿ½ÁóKÔÂÿvms¢ð:ÎôHé3ÿàãf}Z¼ï3güQÔpOmêoÚ? ¬ßô[øÏ á·ývñXûãæoû=ôú~{¼¹ý@upÆ™\p°ø/ûK:ן±Og½F›ßÞßð¿C<ŽºëöQ±JˆÀ^‚㘷÷÷·þuÀYéÐ9ǧ{8(ÿÿþãÞüðýw˜Jä·De’Œ¡‡¿Áz8î·)–«Ãííöò€µ[|ç<=¾óI]›K®Ü"½w÷-7ðà¿]Sð«Ð–£Ð»¾9< ‹>Ýús˜¯ ÂËázsµ€t6¬ëw áû­sñ©‰gÅ2STaÀ ½«§ã‘ Wt3!´}òÔùÆÿöÛ†?HcÞ?àåáñ]—E›|Uˆ_nvûTçSÙŽÑnßAµ ú§kï·þ‡ýãÒù8¡w‚1ÔnÙnüAÅŽÃuÎÏ”!wóÞ§äì7Û»¿QE+ªáþþ×ý–4âjL½Â5¾G¡®¢×СzKPÚG~(ª®‡ÿtÅue»‡ú»w)~J]y/¨å²¥2×XÏ‹—Øhr—<½ÇÿöZö¿ÊïòaU\häÀdÅÜÇ·û»ýÔO¹¿¹Š¿@ŸÝ ÿéZ£:~áw¬ …OIôþ±ÄǾy˜['Ú¯>Ð?]ø{¿‰ï±>ÙqƒmÞAÇ>àÁèO÷o¶þC®¹9ÜîÜà Q@owË¥ùägtÒ{»§zð{lЏ¡xw¼¥Át݉ _ôäáz{µtnìxBé ÉšNNÞm~{÷ÖÏÞ(Žƒÿt(Trm,'zu¬$0è û}¿ Ó [ì]À±þþ?]«”Ó:n5&8øÒãÓåû›ÇG<á;4JÒŠÊÃ]8>]lÛöÿéÚ¦bQÉHâ|½—è]Ýdƒÿô~zwu"œ_Ž?úâ>½â‚n¤ñ|yZu£oíÞ-KðŸ^k‡Û[ẛC—{0~>øÆ]Gínœ5ó€ýëg&eƒœ…Š}O·7÷¾àÍ»ÃeÚ§‡7e¶ð¿=¾P !üéG\Ã]qK¯ía *˜ën u¥ºF‰î'³¨[K¨Ò•ÀR[rျ޽¶ÂßK ÃÄ”Í*A),Ÿé‰Š‚ -ýÓk‹‹hH{–¬B‘P¨ó5˜´ÝÊdÙ°a® ~èï• …S¨äÓŒnÊÆRø¡×ý%¶°ùÔÀ7t‘_ÞÞï½Êts|ÿšÏü÷…¸3ÞâhVªLÀÿö0BÉ‚Ó'öÑÊúЫg€«î Ð?][øû”øÁ+0K*PÕƒA•¹I.ÅÔkî8|®þ‚ŠÕƒúµ’|›þü…;*îkˆëù„º{¥~F³ +7\J+þŒAÉÙOÎvZͪu|ùxûåý»{0*øBX‘¾µÇ:6_¹+] nxÜ÷þ?çy„ЗÝàz¿¿Ý¾äû‡¿œ¶9ñµdº÷?ûܬ¸‚ Sø§ÏodiG¼êý‘[»F:ê­3ÝûüÊI›»ýííÍð è§ÏÀ_¾O_¾ôýù…ßûýÓñÝåÓã£ëÜQ{Ý'ŸÞdïù–xõBŒþ”c¯»h ß^דtîê"Ïp¼|ƒ2ž‘?:¨g$ß/1—rZ¬àƒ¬÷¢ÅŽûÀd¦ÃyÁH¦jbt2ïëW‡«¿ýåÕÝ_Ü ZúôÅãõÝSKÜÛú0;h»+W¹]“‹†ïÉÙ+[¯2r¦Ñ#¤ûÑMú¹»ÿ:kÜÔáz÷«ôBOGY¯S»¡†ã kyR¬˜?[û•OËm·»¢¼ª®ö>´¾ò)pí>K³¤¨ö±â¯œ&ÊŠ"Ô9lª¦ûÑ×ïwÉøVi‰¢ŽgF@áùY9O—­&í©½O’ùÏ;•õt¾V;[õäÌ¿D'onüOSo0\³Æë IÁ(žf䨗agÄZ÷ØÝ¡/·ûíÝ…S¼üfà×é×ùoé_þÛ7p84×ã¢c«}€6þýápwá ÁI<e…ŸbPÌÅýÃÍÏNâ_ümÿî\îÖ×Û´ªÊ}rÕæiYVy±Íó¬Þ^ÖûbU%åÕÕåõõeøTÜû5i¯’²ÜµåõU^_¦×LGînöWþœÙ Úe?~]ú6üVäBï0‡ =ÌWïï‡×~¹ãJ࣮À°—‹wïo/R|lü€B3.ºMèã×µûæn½}º}äïÃ9:®KÞû³n( âæë¬÷áqu¸ÛIÃ;téÇÈ„Øy׳®9TB|0üéWèõM7cˆŸßGâwû_ü$xa¯Š;Ü÷øuæûëñðö­ëHhÞ‡)AÛî›—®Ylö^9õ§7×{×ïR¸®€=f¨ €/­j\ÿê?÷“ëõ_þrçÿ÷-kôw¤7ÛÇÍ¿†ÐÒ>àÈô+8p‹÷Í¿Üü?‡'8Hüîð ¨÷ ‡Í¿‚úçæÅ  bð‚ß?õ¿1l5z¥ÜoüÍ@üé×›ëÿ®Ûü+ÿÈß`ˆííñÀ—6nÆÓ–°ž¸9nnoîþæC$¯÷ |›Ç¸0Ä‚X€Ë‡Ã/®ážæ–ÿò“¿œ­ïÔÑ7^/ÅÝØ×pj‡£Õw·Ü®ö_†¿ö¡mî o1 í5as{ë¿ô°Ç‡Á4ÿê…†Žtwö—ù[S8"Àr_„»ûÿ9ùFïïq¿}σo<4ŽO—><ç~æÇ·w£aóa„7§#²»¡W&òÐûÉ=Çßànþ®ôo†îì¡gŠá{ WOÞïºù~·£¸T@øró?]Çû7Bx `ê~‡}îÍÿ7j?gÔúøåæø®%;–ð&y ?kˆò(êÒ*÷£”Þünÿè.Äí^K®/Â`ðC: ‰_6åY{r’¥$9éÏâö… òÌÉpáAC(Ì0ä ¸FÑã×?’œ®›..nö×ÇÂæ÷›ý?î|rß„ñà¾íT(ŒN¿;<ú¸-”dï\‡»g¿¹vwûË«£ÿîvn)(¿ÝQ÷Ãþþv{µ‡Àj ¤éËCêôÞ¿ìoš·ï ž"ûI÷ÿ-¥ÿ¯[JyôGXÞ,Sƒ’3JРûôL¯fʹž¼ƒXï Û7å?šR¼øãÍ?Q÷C8OÄ ß:ãyïCºÓ­›Â÷?ÖàJž‘gíG»]P°y¯½%¾î|ÌIù»jÓ¹k癀›ÙƒÚ?1æ –-º oŸYš¾xð¬ïqpó3¿vZ)cÑ×·oŸû`“5ãÆ½÷ÉÁM‹â˜²5<"£y4ô‰ôÆsïýŸ|Ø:{US*•ôc–—Eôθ Ð&=™òÖÙý–MòéÓÔ'ö©NGŒâñùï*2dÕ=\ò-íj­¥Ï*-ƱÍS#%\³ÆàÑùæK+-,)}rF~t_s<ÂÞ˜\úè+ü ê-ˆ^\(ýFFW~iØúÃÞ'½<,ÜÍ?ßáΣcã‡ñ\T 2ËFâ¹Êò5$ôp¸&[7ðzÁ!ÛàOû_À‚øzóoû÷ÿá7¿þí+÷üö¿Ý>~3ÜûßÞ>~ŸCâÆ«ÛnÞ¹Wöïùoœáù¿ÿýß!³!ýÊ«Úùoÿáÿù·¯¶ÿášz÷øxÿõW_ug)”ãoõ4Âg],œâ·û8‚ÖûÛÝUß¹6O>A+Xa׫¹ÖÀ{ð•Ï©þ ¾_¹›¼¡›>ï›Ö¢¬8´W|-~pøZ†[‚³¯:,{Ö;Aö¦ò:?í+Â3ûÍÏ_ùÚãI¨Ã·ÛßÝøòæ¯à>PZr¾¹É+^I'w”MVÖ¿òEËcMuùts»ûŠ2h‚Œ¿ô X VBÏÂ(øSßî÷^úúù> Ư__ÿ÷϶¢wÿNٜϦ+?Ÿj›tmZ`÷ sÚ1ŸÞk_û‚°ŽŽÉ ur®@¬3Eÿõ4;Màj×ÄW´K´üJñ1j_ç¡:ùêöpüÄNvòçðô¸ˆ-‚•¥í¯ 6½Í—_Tů ì½V·}Åe€%º2ÎËLv^•d©O+IsÛx…YãÊxerªŸfÏ – Y µÄ2kÉ~Œ%Êg},þd‚1K‘CÑ·,Ññ,OjóDf,Ä‚±C,r¨5—¥ª"l)ËeD@CI»Ôœ€F, 4ÁXS ©ÜŸ9±Ld÷åXt0Õtj‚9Ë1®åažÁ0‘uc‘Å™œ=…W…X&ßƈdFÅÀ·ëNfÖ¤0aiº1Á†ë\föN„&29%Os!–-ÕëÚHÒcM?3!œ{0Ú<¸f’ñ†.bÙð\Œ uŠ›fšeÁÆÂXËÄc,J1TœÍ ­Ð (ŠšÙȼc˜i¿ñê‹"ÜÖrñK3™T•`D°æ&,#R|r.ÞZ¯ t´ÝióÉŒ¨¼`oË)x+½)(͛ɉwŠаllÝAÞl&oíeŠ 4…1!XÆP‘8““ñÖê@Sð4{Œ§™´<±Ld6Ä2Á¨ŠeDÐòDPóFÄ/Âhj¾P;›ÉÄS˜Ï`Kʹxz B)Lš¥Á†ßªngræÝZýÖ‚#KÇ 1½*‚Y)§á­õÎAUø‚É6S×ou)‡Pš®_B°át@˜Õ2ìf0Œˆ\0ï5‹ó1‚9‘‹X漈unyk¾§ÇLŽÝú½BX6¶Ü œ}&§Õé.ÖD¦év@„³Wå›DχœO·.‚µ°3²±óV€M-gÔ©éT¥©î‚9ŒXšÎÞ\ 3µôt/’Y‹.¼õŸ«¦Ô‚µ”:²áì%#baÖŠžÁPÄ Ø:#kî_Â:·"Ú| Í«*¼ÞÜÏåœ8̓X6¼cNnkÚ3¡£O ™æ1@„`-°Œe„±&”˰¬E– gqéýùjÉr‹`4=„ LÍ[s–¦.3@X+bÆÜ%sr7,éqe0Ö\ˆe.7ްl¨Ë%ؾrNÜZRÌÉcIJ‘ªL0Z[u%˜ÞFrâÆœDF,#a4%øKÌeÇ–ªþ‹6Â%øKä 9ÍׄXÚ®á¬n9;n­Ñ‚çI‹5_%-gÁ­?X±/lESYÓ~K΋[ýÅŒ ·K[NŠ[iR‚m8‚±žFX6²2*pÈIqkHa0÷mU¢c(/Á˜“€%§Æ­¨Ç†¦Ö[ÛCÎy[Áš®KX6< £©ñVàì3àt÷J+0«åĸõßÂhædT`Éš+H‡Xr2Üú¯ aÎ-z£Íƒ!-'­¹!†f’1!L|«À¬©?§0K3ŽŒ\„±ë@Xš¾ÞÌ{9NÍ‚ÑÔ~k°§Í%ÇÕ`YËÉq+.P„¡©÷‚]¶,FsuæKSé%Uy Fšjæ[ Fšjæ!h«¶„a×K06| 5X¨ªn„`З@dæ,bYSrk°¢Íe½V!g½é)¾eDñmFUñEMßCÝ‚fp/!Xs2– ¥·IF3ñ˜ÖÚT›Á°&oKµ*\“‚µ,cÂÒ”³MÖ „eC%&A M0š^B°áà%ƒ‡>™9qìý…œÙ¦¦þ”9Xªº„s+Â3ÍÄcMn*À²v"a©*ƈ`#ÚŒ`ÌÉc°üÍe¼– ‡Áhe7àŒP­ûFFä0ÂLËáÕU„2'…ÁW"g¾­5vÁ†nÁ g¹éêëH&'¿­ßMàSÞG3aY;©‡°¬y1ˆÐnÁ‹¡šGÖD4aÙðgŒ­t¹\FŠÇ!Œ‘$9‚1'§KÓqÑ‚ïDN—ÓìÄÒÜÕ#õyZB2{-x{Î^>n¦ykA„¥ÉÖ‚#e¦tÜêK¸äl¹õ‡.˜S“k­¨· #j1ÂØØÜkÁ‡!gÑiÁhz.Áœ ‡ÊL ÎdF²èf-‘Á(ðëÈÙtZËC™@fc‡I0–¢Ç¢HÀƒ#§Óiö b)ŠfF0áTfE¥¸HÀo#§ÓßZáæíÕM.pEÈYtë„QÜÉ+°±­–c,zp‘€‘;Sfnõ%¡T…."Ø v+ð È vš£°4“îÁ„c‚aŒ9&KU,ƒÀFÃ(êÎбÆEkwE¦­œq·†¶‡Í«ê»¡”³èVŸ/i0Š‰ÍŒ`M²¦)`Ù«aÄdŠqŒ é` M›f€`"üal¸Ò`¬)µˆ¥™PÇJ¤qóæ„mXÆBKù´ưáaHK€Q•» húÁØþciª·ˆ gÉ­…P‚ ÇÁ˜“¸ˆ¥”W¤ 4¯ªÃ"‚±œ8ÆR•¯`¡ÊùoëÏ„1'iËD`o‘ -g­4fÁX8/cÙØC#å(²"ËYΈ[AôSóÖä.aiÊÝ Lø™ZokoÞ” ¿ÁXó+d`U[«þÆXšÎ]B0"Æš—!ó^NvÓÇ2•«\dà}áÖO£”gÁÍ+žÌF´`€‘ÓÛ4çbió†bb[‘kÈF¸"ˆœÎ¦cN'_„œÕ¦¥£'OnÍ™5gaÓà9‘“àÖDˆ`ÎYXF”e„Ñrçà+±‘êÆ0ÚQe„aM– w1Á ôÍÁÁ$ç¾­$÷ANrÓ@ˆ¥é§ ¢7/—œâ¦fy”5/aiF¢åàV’SÝÖ\À_c£zÃØðŒ5¯1bɉoJ}d£~\‘ƒ¯B³~#XóçàBY­~ÜÌkBuµœ'39o ¯ ±ŒÈc„Ñôçà„Ь$GrR›²q€dÖ<„eD-FÍ\·œ"r®›žfŽP6ƒ °¿U3ß °åÌe¾– •¸³I΃[qéŒJÎ…[k´ ‚ Å·ÈÆZ°0aiJ^B°æ~( ÀÒt?‚‚1'{KÀÒT ÁÞÑgD&gÅ©)5EPš>aBPªQ54o#Z‚`4ó5ÁZŒDÑ–ªÂ‹šùpE ªl9 ÌÙ³àbÍ— 4oC©%kJ-ai*µ„`M©%,[‘¿eCÍ-S€±¦æ–Áà‡¬l9]n­ÉªIr%±r’ܺæ„1bÙPvK0bÏž 7ùšÁš²KX¶Ž—,Á~Õ,ÇÖâ~K°`åt¹µzlÔ†ck»l„ec—­3{&ING‡@2U±Œçv÷Î4o-Ò¡ÿƒ2p cN#–ŽûwJΘ[kF£D=;Ž0Œˆ`„±{FXÖ¼8äܹ•1!ØðMTà˜ÉŽSxMˆeÐ7AdÖƒKΓ[PóDΘ[k’!‚­jD¥}¤aØ &k¾ ÂÒܨ«ÀËe$S®_Žœ)§snOE´yðßÌ$Æé,NHfÍeAXÖÜÈ„eMs®ÀÁ#çέ?ÕFU_Fk~ Â2"žÆT9û¢”œI·~Œœ?§9ŠËFìÁè(ÍÓ øžT Ê‚9‡b© hpõÈ)uëa„1çÐ@¬µôç Í=¾Ü_rZÝ꣥·‰‘ªq£BLÍ[S‡ ˆ:\ƒ[ÀHöÁhú(Áš´­Áu"gÏé*2DfC'˜ZN¨Ó|{`Ê£yºD]‚¦òKÖ”_ÂÒŠ° æm(¾£ØVW€ ­äÖ5`‘±£ZE®nÁšW˜°lDQÔ-À¨ÊXDЪ´AÍÛPm›`4U[B°¦Ú–µˆµ&,MÇ"ÈYtë`„Ñ h2@°¶ëFXš’¶»GΤ[QO! -핚·•žÑ€¹%çÊ­5:ÁF¨ÁX 7kÀØPM#U öŽœ·.‚T8‚ÑÒ`0µfÒàVhe-z°lD/Œæy„`NÎÖj qQ 0ÕåT¸õG ªrœæ«B,U½4sÞZ0O•êÀMî¼™5ALXš /!hŠßÌe#¥áÆ\i8Â:·ÂmìöÕ’Þf04Å,!XÛ #,‹¢< F2ÞFUà"‚5.aÂàøP-üFÓûfkÛ“eMûmÁ³ZjÛÌØAs±´+`´à¥QMm#Þ‚1'ËšG¢„œü¶ÖèAÞˆ\#ærÛËZ0/aÙæ%ÍÔ‰<6êÕàÈò¬ÌÀ^´‘?G03ùs«K~„2vc)!Qf`QËu넱æu ,^‡ L~9N³KUƒm°l“)•,¢æ5³éÁœK_Χ[«gAÓÙK6vÙÆZ|CÞ9oNO­A(M¡›ƒ¡o-ޱtü“k’i¦Ð1‚ 'DNk)tŒeC/&MW!(§/—9xD¬•ƒc,ûpcN$ƒ³äì)tÓÍËéskÍ!D0"wÁ÷0“'§0JËš38€œ3·þ«CM·0!t ™µ¨4Â2'”Ám£š"‡FRäƈˆ§‰œ(§9fKÓc‘ƒ“@N”[C—Àæm8„ ÆFLp 9!nM31ÌI[IJ–X­œ·ú*€±æ)&,MO1!XS ˆj\¤cC2Œ É\dcM/&¬sǪÍ4¯©ÿ"‚¹ì¸",š0Á¨J_D0'} ÀÒt % h»† È´Ea‚±¦ ––C›·Q1®,*€1uÚ0CÙHŠ+j€Ñô:‚µð4²1AXFäq0ÓÚïêó ¡lœQ€àì‰rÓÍkÖ”cÍ„¸li9!nõA0k…@Ì`X“º„¥¹ W‚A΀[´€«š÷FÖô\Â2‹†dª q%˜ÕFâƈøE­£wJp,ÈéokJÄP³ˆ`0ÖȬùtK°¬5KÊ1‚µ¶,j99n}ƒ0ªú.؈rœšYFPÖ<½„¥éé%mOo v³œ·VO ‚ ÿ.Á˜Ó{Áž>{ÖÛäkÕÌ· ìD9óm]jmFëjµâf0¬yKSÝ%^… ,T9ÃMó5!–ÁTã ¬F9ñmý·0r®›æÛC,U‘ –ÛLÖÛÚŠ/Ain±‚9± æ¤f±8FÐTz Á†Ò[õj.˰֒¿Ó3Åâz H9n­AŒš¡d„`#·˜`ÌI\°iå·õûaTe/"˜S„ÁÀ6—ÖFXš®D0’ÖVƒ@NkSS7 JGž4¢ˆLkë­ \În[è Œµè2²ᥨÁ g½iöbiî¦ „4‘Ó۴ߎ㲖éVçÈeÃ]Ì4j²˜Ú·¦3— ¹.FSC®Kd°ãËT6‚|™Æ†{˜hÌ¥¾Õr¬SÄhÖ΄`.>ºFsB›¸4ýÈÌ`í5æ²á]®¤QÕ‰Áˆ°nÆH¾Óóh•9éL\ÖBÚš¹lx:˜FS:3ùéhû)¶oÍ•Á\#.ÍZ¬qƒþÕ”:f°‘ÞÁ46<L3-”×^˜J;ï£Aÿ†œ_·þ»"îæ½-r®¦Ä!.M¥™ÌIcä’sí”0tì–ƒ7ÇaD<f43ÑÑÇ#çâé-XDeD4£Cµ*3X Ê`.þŒ½+r.Þ–µ¯ Ç C0tY˜ËÂc.Í4¼F Ò1­ÒHLeÃÌ4šš13hÆbƒœ§8«[ôáÌÔ§S„-äª5ê˜Áš0nÑ,_­r݇L4šÁ-š»ª¥é˜Aëlanßš+‚¸TKеhµ©AÇ4õ`F3'z‰KUFƒR5-l¸˜FUìƒ5÷C‹ÆîÙ ÐMö 2œ½ ]´}´^” ckáÌ¥|FE• µd£ê\ 1– R%h»ifçE¹} Á˜Ê[%hÀÊÙxkõ 1˜½U‚F¢µâr˘¾¸”JÎ…öuÝ*AÃÑFÒ] Q•¹¸A«™bÌÉ\àJm”• 4ƲíÜÿ!—99L\ê:0q(úª¤FîÝ@£"Ú7•g¨LäÙUIƒ4æd2rÉwkÍ&bP |¨’ÌI]â2§ý—OÑ‘ÇDc,¡®Jä²%§™JiS.´oM2§à9Im¤×MÍ k…Ïq˜Hm®Ò ilHb¦±æNsäÒô 3ƒŽüÚThƶ誴@.s¹äTºõ'ÑXse¤èb±‘^hŒˆm¢Ñrsûšîã]9«%ÑÍqXÌ„fËÁ4æÄ1riÖ­«Rô7Ù(\h¬ù3˜Ëš?ƒ¹¦ZÝ6FϘf±»À`Λ^9±nýùF4kÉé9)uU†¾åí¦#CßÁL‚Ýú³‰¹¬Éeæ²áÝ`~æ }-ržÝŠ2‡94ã.2t`Èùtë¿¢1"…‘F³è]`°æ¢`.{‰U†^9Çn­×†^‚™ªxk«ÅLeD 59C£X3ã.0h†ÃehÚÙ¨€Ç4r®òI?U†FæL¾Â".UL šoš•rbæû!.È9˜šÉvASâ2ƒ57qŽæÛL¼µµ¦²wÔD@³±—£)gá­5´‰AkÛŽÛ·&ˆs´£Tsî˜AUü¢Ñ&çÜ­?cˆF1ÙΞi7×¾¦×7GQέ[T5_/s+ÒQåhÄÎT¼[]m *#ª/’ª¹wÌ`ïHø€fN#®LNÉ[ëµ5È`Í5Ì\Šç¬Uy‹ ª*/1ØØ‚cs 0qi*ÀE‚ ÆŽ\:‚9J•"•5™L\ª)yÌ`#˜il¨ÏE†4š2™töå&UF³& ‹¹¬mÓ1×¹5ç¹ömx,˜FÓcQ€Ç “3ïô–+¢2"’‰ÆÚ†siŸRÁ6”æ¢Ds2™¸T•æ 4=Ì`-ýŽ¹Ì©ÈÈe$ýŽi´ƒ( tæÈévÊJ!¡ÙȽckŽfæ²åh.Ð&gé­% ‰ÁF²G¾#IyLcNH#×L»õ¹JôFɉz+\ܾA1Íh6Ät‰n9'o%Áà Ö4gæ²æÍ`.‚šilê=crnžÚòNTrŽžæH".͸ f°áxfkq%úìŒäè1Ž=½¼¢SHNØ[kHƒµ=BæÒN .Ñ%e$uhTS÷JtoÈ©{ë÷Ñœ;*c®}sB˜¸ŒaôdÉÐcU¹‹ 9OsÜ—5×3sé(ËÓË8¢Iác#â>r"ßJS­B/†œ´·z0¦£B;Ø\úsi\ÏíkîýUhÕÉ {+*¾ÌaCñ%š³×Å›|3hIÎ$æ)ÌâR•±h®­Vof´ å—iÌI[âÒTƒ+4hÏž£7×¾fzt…¦š¹šxÄ%gê­?‹ÐhSÍÛcUIK ÖÚr¶Þšz qœûŒÌ¹ömäáUhÉyxj{LL¥*u‰ÁšÔ­Á>ÌUSð˜Á†i4¥n"ôÔ]{1•¦/4Ï$®3d°!s™Æšk—¹´*+Õ9¶oNâ"—œ`·¢æÂF¤n4ªR—¬éºÌ¥*w‰ÁšW¡.‘k:Me£†Ñ4Ý»u… šª/3ØpíÍLzÂ@&.­¸àºÆö Æ3šfÊ33XKÚ`®µB¢ rhzw™Áœ&L\6’F3ǹoHn$ƒŽi¬í´1—µ,gæ²åhÐo#§Õ­>¦˜F[.7è/QMŸcYLc-䌹4årƒ>9iný7E4Öä2siú*ôÞ˜«dÇ\Öôdæ²Ì46<È úvä¬9ÍwF\Ú±i :rä̹µæ;2©e× ³BÎŽS£1èº`4sbš¸Ì‰itg(¥ÏÍQ©*Ñh¶Ë™sëO9¢1§D—µM?â’3é´ÞÞj9uQt$ÈÙtë÷ Ñhº™™Áœ\&.#ê3ÑX;~¢E§œe·z/1æÞ_‹N™<:…7…\F’èZt(ÈItk½)b°!‹[4å$:]•žÑl%e*kñÌ¥•c×¢AαÓìâ²±'È46B4ˆF5ûެùž[ô©‰Ç4çV™çÚ·±ç×¢SEμ[kÜ¢«Bβ[¿GˆÆV>SYs^´h–«ÖË#†³×Ë›d@óNνSVþ͈ø%EE •i­l^à2á±4Šä:A›WNÎ[¿GˆÆ˜\ŠB¸NÀ/ä¤<­e3P)z)ê$Gc!qËž¿" ™Ð‘ë¤@E90¨ cb0æ—\JY{uRbû¦N)f*휽:©ÃDÜE QŒƒ Æ,—bÎ^ÔÈ`D&šµ<sŠiyuÒ ƒâÖ\`°wÄ%£É9zkuO‹ FD-јÓ{‰ËT*H ²æ“Hä²!Ói4Õ`fÐÆÌ`ÍÁ\4¡Éù{š]†. 9“oë…Û7á4Ötã=r¦ÞZ“ž4ýÌ svÅ•ªHF/„µ½Àe,œ­NÑ?!çí­õΈÁ†ÂÌ4örBê]rêÞZ/‹ÌiÈÄeDC&cqÆuŠ.ŒÕÊÜÍq˜b 4&‚Øê}rÂÞª(µ¯¹[Ç šbf0§—m¹=&3yw ½D\öŽw hšzr†%kixËšžL\6Òð 9CŸŽœŒ§ùΈËD­:CŸŠœ ·Â²Îíkú-˜ÁDŒq¡¿ÂZi»ÀeN6×Zjr”})6Rðê ýš)xÁœ&.#˜h¬¹.˜KU2£ÃBζÓìâ²zÌ46ÜLsî€ãhûè6‘³í4Ç qÑŽ‰FÓ•‘¡Ë@ζÓ|SÄeÕ‘¡]®™…lhÈ9Ú™ZUïBûÓšðÚûœL¥­‡œq§8«™ËXtà²c‘£wB5lÈ_¦±æJÎÑk!§àéI!¢²¡3 Í8GO…j*^^ŠòìõñæÚ·¡3ÍZ²wŽCUê–È`ÍÁ\šúo^!ƒÁm;FÓܶc#b–hlÄMœj§9­jäÒt3ùÑöl߆#˜itb›2„fN&.Í”¼Eíà5æÐÌÁ+d°'A\ª xÌ`Có-R¤Ñôÿ2ƒ­d»"C*kz0s)W` 6|ÁEŽ4šê/3X‹Œ`.MC–­ÊxFSé-О•sêVfÐô7hÙ¨oh¬i¸Ì¥}ÊsX‹J+ЄœÉ¬S1š 4Nääºõ8Ò¨¦Ô1ƒµ-8æRÉÄ`-‚¹L_hìÊyuš½E\F”c¢QUމAÓ-Q¢é½Z&Ý ÇÙsè&ûn9Nqæ0—µ`áÍ]9ßn­wF 6Te¦±&{™KÓ\¢Ém£ª] ±æ˜`.šq‰N#ItL£é¢`­}9nß–c¸D§ÉL-;S“Ñ4c$˜ÁZ®sÉèG1—EÇ\š¾â}9rÝb‡Ú7§—9Õ˜¸l„O0%Ý&Öê×. ¦1UO©.Ñe!çÓ­% ‰ÁˆŠŒ4ærê*t¨X«j¸ žÖV¡ŸENº[}`1æÑ™ú ä»õ{„h¬©ÑÌem¹4…u…þ 9õN³oKNÅ[d8¦ÑÑQ*ô|Èéwë÷ÑX …c.kÊu…®ÕªxÌ £RO«„f+oºBχœ•·þ”šêìùy“Cˆ´Nçöµ³ò˜ÃZHFU#— OÓ˜ÆÄ¥*Œd°á{fizLcNi_G¥^9Œ¨ËDcУQ'ˆfCgfMF"ƒ ÓØ:¨‚©4cã˜ÁÚf`!—ÁJM„&gò­?´‰F3X£Î‘A3x™Œˆ`¢±æ¶¨ ä:w”Æ\ûš13ØÚñ«K¤2'ˆ‰Ë†o‚hä\¾µÆÚäª|Ì *qѺ©…§³Dš9ñK\šAr5½«¥óÍLh¢±¶§Ç\k9*¢hôÊ|k,ØØ¾jÎ3ØpC4h]Ï”Á[Ä2— ¸A»RÎÙ[iÜ0ô[Xeb4M=¸AËQ554C'´ÕäÔ<Í \rªÞúšh¬Å¹5hͽ Þ\ûFÄ.ÚGršÞZó‰¬íÆ1—µ°6æR•ÃÄ ­î6hך«rG\Fô˜FÓÑ ){ö½% š‰Ñ Š3)y #–¸ÌIa4æÌåè1—8 ¦QÕ‹‰AËõ@íŸ=oAÈùx«ŠM|sYxÌun9m­é™úukïè0•¦³—l8{™Æ†Œem·Eˆœg§9«‘Kθ[küƒùK4æä/úffªØ­.ÿˆJÓÁ Ö´à½FæRì˜Ëˆ„&ÑÂ-úHV«n·ˆÆ\;æÒÊÜhÑ7²Z-»9~a¦Q•Åè­™I™SÙŽc4s☸¬EG0—ÁŒ®.Õ¢vÈPËIsšoªE.# 4ÑLá`4M_23Xó%3—VÔ0·oL<7I‚\&´å@cB(c^&¯O½ZnÝL/ÍZâyŽÃ˜g£I2äR”Êa­\ç(GŽÆ|K1–-0‘ÄDcDH£“J7ÓGræhÆÞÒ̧k’ÖòaÌŒ¢1áÉ4Ætä&©ËDÂs 1±ï×$5Ò(F¸5 èr~Ýú=B4Êå@˜C3Ÿ®Iк“óéÖ3DcN&.{ÙvMЦžœm·Ò bâ—i4UâMº™ÌºµÕ>¦2–æ¸}ÈÌ çÚé÷ÍjùwQ4ÄåÌ»õç8Ñhº&R4¢4³ìš &9ËnekâÍ»&ES@N±[Ö5·0q½.Þ\ûšn‡Í´™úw«k DeQñ%4§`#*0Z–ֲ헪H&†sgw̵¯ªì¢=+gÔ­Ì )t34å<:ÅyÂ\6¼¾š Ö²ì—NLÛ• ïo††’œY·Ö,CCI3Ÿ.0XS}‰Kγ3À5}ℊâÇhæ„6ÚÁ6ÊáMï3hz'2ôÈIx+3‹$n2´{å$<\æ„5ri&å5š6’ò-¯Siz‡™Á†{‚iì¥4SÇÃ7ZéÖÊÝ.U]š´ã'ˆÃFy»&C†Vî]h߯Ó«¸4Õâ½;r.ÞêoŠiÖòWÌqX“¸9úsät»µF 1˜È~nrð)5ÖÒí—±S2— ÉÌ46ÜyŽ4:§M*¦Œf-價l)ÌLe¯îh“ˆf#ƒi4÷ÿrpH5ržæÐ&.sœ¸ŒHp¢Q:ñ­É+l_U‡&M×23X‹²Èk䲑Ç4¦ª>*k.fâ2—™—7ÈeÃíÌ4Fä1ÑXóuä-rÙpA3A4£YäE‚\šÁÌ`m°H‘KS&9oõ Æ46D4Ó(8¬ çÝ0gÏÛ›k߆º@§»80šª& ¦±¦;—œÂ·~/¡ŸÇFἦ@Ÿœ¾·Ö(&žç­wÕô=fP:Û-´o#V™i¬íh“kÖÉs#ƒªº‹ 6jâk¾bæRW|‰Ãœâ‹Æ¶f•¼À`Dù%ÍåÍ$ÕÌ—h*Êùvë$¢±æb¨pÏZ³ø]`Ð Pckq Ìe0V¸Bû_ίÓì2ⲡ%œy·ÂzÊíkžÄ šºo…^9Ënek§1—5}¸BO„µrwˆw‚i4}Áz&V˺›æhå|»Uû¢µQÊ.Ðhï±U%r¨Ê_b0'‰ËÆ[U!­¤9¦2"s‰ÆœîK\š±x±Z#•ë˜Æš?¸jKU'&QfU‹4æ¤3q™ÓމËFDÓ‘ÏDcM>× riëÉÄ!çέþ¶êi4}u† ÖŽÊd.kŽcæ2x£ÙP§™FsS¯Î‘ÁV%¦Òt\0ƒº@F9?Nsš— gFÎ sEï˜ËœFÇ‚œ9·þÛ##r™h¬9—k4áå$ºõ{‰hÌ)ÒÄ¥éè¨Ñµ`®si sûš®]Fè˜Æˆ&kö™êx:&¡iEÅqû¶Nb*‘DsöÒxSb§A¿Šœi·z05u™¹lç½OFªã5è.óíÖÅÄ`óܠ *çÛ©É>¦²§Ì4šê01˜ËÇkÐ8W­žÇ æ$1ÁFªç1f023<{Ñ4=ÉÌ`íà æ2"ŽÑ;!'ê­õ¦Ð —ÓóÖb@KSNÆ[™ÁVÝ¥9Os—Ám=F³UÔ©´k‚´hS=oojª1ƒ !Ì4Ör÷ˆK=w9lø*Z´Âåt½{ÖÝd߃ÁÜè­%#ð˜ÆÖaALePf4s’™¸lø[4ÂÍUÉkÑ0WÍ×cM0d‰¹ÚxÌe-c„¹Ô4äÛ7&¦‰ÊˆÎL4š»wÌ ªƒ9ÙÛ"—ªì%c:s›$Àe­Ò]à2á§4ŠÁmm’"ƒŽ$žRMšâ^`PÂÁ„*hŒ‰ã6É˄øMr¤QÎak…í—AL4ª‚˜L„O´I4Ju’BûöB'š±d6)‘KÑŒa¢1§WÀe-A/pÊDc±hŒY´ zr´ Úµ Zç6ñ¢¿¢MÐ&—“î4G qK¿ \&2?˜FNÄ[w­VÃ.Æ‘¢B3ù.0X“»ÌeÂWܦh”[Kà \Öteæ2‘ݦèº3òÔh¬iÍ)È6êàc;{ËXvHà:wLÜ\ûšÎdfPª;Ú¦è¹sñ´v]•¦ß"EOœ§×3DeC3&9'OÆœü%.å3’Ûý6²ñÚ½šÙxÁ†§‚iÌiÆÄeD3&Å‹6EŸ’Jymо9OƆǘi”¢ÚÚ }3‰x*›VŒ¦)€™a-<ÇaMô2—½úLm†þ9o­áC ÖüúKVËÁ›–L£˜&4ýÆÌ åoàö@ßfèƒ3ñÖ­D£¹_—¡ÿA3ÿ.0¨ÊW´\­åßµZ²rþÝšjqhïÊ1‡¸¦QÌun3´­Õ \Fd-ѨÊZ´¥gòèÖö³2•ý· ­X9ŸNs4WªY¯ÍdÐÔn™AS»ekQyŠ\šnf°!uó i”Ïô ֢ҘˆìÍs¤±&{‰KΧ[k^È`ï Š€¦½éÆšÊ03XS†™ËÔ‘kÊš/˜¹llÃå%Òhº'˜Añ˜‰6c75—MÇ\ªj11X cªi4½UŠ šÒµÊÁÚ>_•#—Á}>F³á®`íľª@k;|Ì¥)’™Á†£‚hT“øª &ñ1šVsUaû6|Lcmû޹45ÞªFM—4½ÂÌ`­¢GÕ —¦ÇäT½õg3êàr‚žæ›".-™[£5`$9i¬É\æÒ>8“94å.3hÊÝíG9AOsœ—5q™Ká«Ñ7’ÂÇ4š^ fÐ<À¢FÃúìí–0X«§Ä\ªÍXsõí˜KÓáÀ 6D3“·öSÛmý g¯j7×¾ªŒ%»hLcNÚ¢¯c&ënõùCT6b˜Æœ.Œ¾‘Õòïf8ŒT­c#/Ѩj¼è'’óíÖï¢1ç@?‘jŠ3¬µá6ó¦ˆÆšÜ d¦’— ͘häÄ:Ým0F³æ*nЉ£^ØŽ9´ {4è"Q-eÇ 6"!˜Æ`|pƒþ9‘n­—E æ$2q‘ÈH3“@§ÖKgÏž‹¶Þ’³×´›ÁÄ`-V­A¿œ?g€Ëˆx&kyu z伺õ{‰hÌIiâ2"¥‘fµZwsæ”dâRW’ѳb$¿ŽiTUfb°æcnÐ㣔\7G¥ª7ƒ9‰Œž9Ÿný¹…4«UÇ[F£™ÝÑ¢ƒÀH}<¦±!‰™ÆšÆÌ\64ærF =™i4£,Z´ÉåL»µ,äÈdÖµÒXÓ‰™KÓƒÁ Ö<Ìe0ÛŽÑŒˆäil©ÉL¥©&3ƒª@®A] #‡j†3˜Ã5r©Šab0¢ 7H£é–`ÍÀжE†sϵo+”"M’¹,ºÖÑXp;c•ðWŠ\zˆŽaúdb¥®CÓ žèÚ×Ñwç¨ô„°cÈÁ‚ÏÁÑ e+gÙiNoâÒSvFƲì—œe·nßÈuk1 A$çÑéÉ4 3ë: Y­¹ŽËˆ$F“I©&Þ´2¶‹œp§ù‰Kïø‰À`¬0^Ç¥* ‰ÁV厎˖“Øq¡}l"Y¯£QU–‰ÁVH[Ç¥çN“-s9!oõÑÂ4š²˜fŠß­­2•¦$NÑð•ðçsi*Ḛ̈–ÔãÐ9~ŽÊ\·CCOŠœ™·¾$MEŠ^9÷n¯µ/gÛ­Û«¯›ã0'rÑs³ZÙº™YC4¶âÔ:. A OÓ‘»è”³îÔh¬ùŒSôu˺ë¸T•cb0¸—¢SÐXB^ÇeÃSÁ4æJ*94t5Íää­®Ô•µ]?æRաѵ#çá­Ë°ZöÝôôÊÐ!çà­`UpûÖ4iæÊ}£þùÜ…?:¸›ÃÝæp¿¿Ûï6ׇ‡Í¿íßÿÇÃáðøo_¹¾|åb¶Ùÿ}·?>ÞÜmݽþFʧwœ )Í4Ö¶3ôpÌ$æéqYª ÝQiŠè ]-&ó±’w—…#à:sBÝ4&Òö:kîæ2'»‰Ë w:C/‰œÍ§ÙeÄeÃ_Â4šÚv>›BÎîÓ|SriúF˜A÷œ‹ŽÃˆ˜&šs'”̵oÃ;ÕHcÃ;Í4ãèÍZ]Ö —ªF9£oýAÔ"Ý™h,tÑÑhÆlä 2Øðl0 qÌ4:Y~®ýÛ·¦ø2—¦ç‚¬mæ`&Šèu4Ú!Ì¡—IírdP•¶Ä`Í+Á\šÊÌ W¨É1È`# ƒiTå,šôrêÞk hª)zÌ`ë| Ç…V±´=¦ÒJ˜æöh´DcÍßË\ªÒ-U9Qoý7E4k¹s£hʹxz³©äì¼µÆ 1Øð%hšËÉc.M=·@ëLο[‹mc%ò:.MÉË 6$ošÿLA<G3£éÓ8fò3qiE´qûšŽ…Í4õð:k.† É™¤<=.ƒŒ¦™Í ÖvÚ ´ÉÏž 7Ù7È 'é­?ñ‰Æš—‚¹TE41hù$¸}sB½rrÞZïíî™Zx }C\kéÈsš^`f°'L4r ÞZ=‚¾Õt;fP•¬Ä`Dù%í(˜Ãš²[¢oHN¢[iÄ”è2QÄ®£±ÄË4Ö¢ˆKN£SóI3• p‰>µÕ Ù-£±–ï\¢ÃF±°]Ç`#ÊŒi¬é¿%:’f²æô¸ŒHl¢1'±Ño³Z‘»(Z¾Šåí:#’™h4÷çJ´ûÍeÇ1—9½™¸ :‰͈:M4:[yQ*t¨æÆ!Ci.7޹´C„Ë9¬…S0— Ó˜ÜÄeC¥®¤±‘GÇ4Öiæ²¶µW¥ÈeM¥&.#‰uL£©XW2œÛ=×¾¦*Í Ö$r•#—‰L4F$2ÑØ:ˆ© †ÁU¢iePûF²êªiTE/1Øði0 %¹ªÆœH&.#"™hŒˆäi4cݘÁ†g™ilåTè.PÍÇck‘nÌeD&£I.çáiöqé4VsM3Ž4C4jô ÌTÐ[è0—f(3hú’k´ýåd¼ÕM°jÞÚs9И{ 4ÓòwåY&è¯sðÖ½Á„K9ИЌÓý&6*ãcšqà2¡§ zvl$åÅ‹4Aœ”·~rîGàP•½èŸ˜É¼Óز hF1ÑœÛe<×¾9ÑK\Æ6ðÒ%šiwAUôƒN>ôôG„œƒ·V÷ƒ1¿qàRôC†sÇGÛG?ˆœu·þ€6¶œ·¦Ö@ŠþfÐL¶ Æü¿îÿ!×Zºî‡1oà2áï 4šr6EëUά[¿GˆF16"MÑfÉ£[ÛWÆT6¼ )Zrîœæü&.M¥—O˜HS4Œäœº•¬i·)%rþÜZ}ƒÚ­œ5§Ù7ÄeCëem­—9ŒÈ^´L¬åÓ¥)êÄr>ÞºITÆ""—ª„&M03ô3š9!M\6„t†[Ër®b/1—¦«‚´ËßMµ8Cc÷ì¹uK¬¹%˜Ëšªœ¡9.çÛ­õΈÁ†ƒ‚i4Ì ˜¼áþA*1ÒÔš sáÜ26Ú~í[St™ËVèSÙpg%ÒT‚͈ø%cqÀËDÍŽ@£T')ÍÀÃVÛȨ 4Ööê˜ËœÀ®‘KÓ3Á FÄ3ÑË£K³¹ŒÈf¢1u [šµHeÎ=A\6èõÙó馿<3h:)˜Á`À£Yó]ä)rÙÕLcMT3—â1™iž!ƒ5噹l(ÏLc-¦8GÿÂjiv3½D4Ö”jæ2U)P™8&(ÍÑ÷1SúNáÝ—9ÙM\:)ÑÓJZúÖJä.#"h̉tä’sõÖR Ð !gè­¸EÉÆ7QiúB˜Áˆ‚¾9gOF+K$GŸ‡œ˜·æì!Í-Af0âÑ@ÿŠœ‚§FcN]&.¹ÑL£³U8­hš !\ /ÈFá¼@£éÛ(пb$]il¨¿L£ G rÒžîÔ.Ðá3“Ë·¶æÉTÖv™Ëšš¹4c™ tóœ=Ÿo®}UAL šr:lä ¾•¬ùˆk&soui‡ž9ooý“h4C• ´úU3ø ´®ÍeðhiÊ|¸ :Š͈~L4ªšl¸+ ´/夾5Tj_3ø¢D;RNÕ[Ñ™Æ6vë˜Æš.Ñ¢Ó,ˆ \FÓÔƒK´‰4Ëà¥%ÚÖÊà1—œš·‚ÀåöU.ÚrJžæ»!.#˜hl¸~™Æšî[¢Í´ZšÞ‡µˆæR•ÅÄ é.Á®mäT=Í÷C\ÖvèʹlìÐ1¦W‚4=½Ì ªü6È ûÀ훓´Ä¥*i[d°á\ 9OóM—ªL š¾^fДªU‚ 6´\¦ÑIˆž£Ò’¸UŠí[“¸Ìe#Üi”ëŠ2‡œS·~¯dHcM¿e.úm•#­Ã*˜Êˆl&kæÒŒ~¨ d0'¡‰Ëˆ„&k>á ü#‘;¦ÑĮ̂Ð32“R§ð¶ˆË`´0£Øè¬óêÖP[©}UÁL šÛqÌ`í(Š &F Øœ§ßKr¢œ²¸Aÿœ;·Öà&{vLc-h¢F›p¦â—µ£Ž™K«ð·¯}=sØÑDc$·Ži¬y6jôlÌ¿Óã²–ÁQ£ýn®sÙH¶«ÑvVM¶cí¬gæÐÜé«ÑJ—“ëÖH#§Ù­Oƒf°±ÌºÍ09³n­QC 6´åM#Uñ˜ÆœŽL\6NÛd 5Ú[rÆfœ[ƒ{ÅržÝê=Â46òë˜FS7h5Èùu+ê0 jãærì˜K3¬y%˜ËÖIÇ Ú)ªIuÌ0½³§â$mÐX8{†Ýd÷ƒ5Ws© d4]ŒdÝ1ÍZ*q”M(Õ,;fÐt94h0Éétš3Uͳ§ØÍµo-”‚¸äô:½%’¨Œ¨ÁD£*u‰Á†ÔmÑ0˜©ƒ§¢>0š¦ f­øãm&9·nýÁB4šún‹–€œQ§(~‘«U-ˆ×æÈ ™ÝÑÈ`m®-‘ËVœ1SYóE´r©Ê^b°áýe#’¸FšéÀ6e›ÐÌ hä’SòÖÒ 2XóF0—¦^Ì Ö‚$Ú¹llÕ1µ­:æRôXdI‚ ¦œÄJQi ŠÛsÌ 'çéÜ,I‘KQi Šò70“¿Y‚†•T¼@c¯nt@SÁÄ ˜ô‘%hÛȼ 4ʹÑY‚v¹œi§·8• ÷p 1æ»\&\ÆY‚> kÅì×ZQÃQôÈÉwë¿-¢1¶¸”¶ñ²Ý6Rð˜f&OG­ 4Uý}rºÝú/‹hÌiÊÄeN0£oÀF»@c,Ä-KÑþ’ïtE£ÙШ™F'â-J…–œ¡·’˜dMQÍ Öth没C3͹OÔŒ¶V©œa§ù–ˆË†îœ¢Ý%gÝ­5ŸˆÁØYŠÖ–œ…§Ï5SöNˆ§ƒiLÕ~ÎR´ mäèkê4s™“ÝÄeN±FVÎÛ3ÀeD«FãQ3ƒ/KÑ4“3øVf8·=×¾Ždž6 ͈x&û‚¥ròÞŠÎgæÐÜÌи™IÖ[_à2— Ë46ÐD#çê©ÑØ;ù-ËÐB]­dÞLG ‘Ì4FD2ZΚ‰|Á†?ƒi”Îv ík†Âeh¥Èé{ë2̤ê),h‘¬–¬å@[D3M/0XÛäc.k^‰ ÕqÍl½À ªüƒ‰<‘,Ç Û³gì͵¯)msoå‰ff^`0u.[–H¥\þ9pX“µy‰\Öd-siÊZf°¡Ù2©K4šz.3œ[òFÛ¯ ý™ x«K<¢ÒŒ`¦1'{käR¬9šå 2¨ÊÙ¬íª1—ò‰ÄCSÖ¨ÝÉéuŠïˆ¸Ì¥Ü1—A÷.£Ûõm?Ãöm8t™Æ†C—i¬>0—¦Û¡È‘A3TìJ‘haZ«Ç\3Yyz\6¢Õ˜FÛOQ M%çá­5ɈAS/fM½˜¬éÅÚSg/{7×¾ª>L æ¤-rÉYvëöj:]¶µ‘t:¦Q•ªÄ`DÑE¿ƒ‘„9¦1'iÑò—æVï¥2AkyÌ¥}þqÈùqšýƒÿL-»µýÔLeCB3 §ÓhjÀ%šü6*Ôe%ÞrÖœæÜ".kÀÌe#˜i¬iË%ZX«U¶‹r nf$sŽi4cÓ˜Áˆ<&#ä£T¨µÊYrk½'b0'—‰Ëœ\&.#r™hìUVÊJ4}Tå˜ÁØYÆY…†ÆL—µ@ æR®»8l¨ÔÖ á.N¦±æô`.k*5qÉYv¸l¨ØDg¯m·å¤:5…–©4ÝÌ ©T3ôdVQË*´˜åüºõ§ÑØÐ¦™F+¹Â}79çn­¡‹–²bxÆœ¢L\6¼LccgiŒ(Éh!Ëùvj4F¤/Ñ‘¾h¬ÏTÍ[]¥ªT534ã1ê4}ÊuŠ :Jï¤ZÅhÖÒðê ¹4µaf°æ§`.k.æ:G.Íð¸º@ͤhb0–žÇT6d¦QË2hÇ1ƒ½ÑMûصºAsbµ9Ko­áC ÖœÄÌeã6¢‘sõVzS ê¡r^Þê=Â4¶Î(f*MÌ 6| ªçrZÞ ž=n-/ćÁŒfM3—¦&Ü E §à­Ì`-–¢A Ø\A¼¦D.U!L ּ̥S¡4J…Šº‘¢xLcÃUÌ4æ¤s\àíì™|síkz™AÓ=Ñ Ýk®s™ÎÄecÿ®A›SÎì[kƒ¦‡¢E{JÎÝ[™ÁÖQ™ËÚc.MùË Ö”cæÒTŽ[4ìTsô˜As{Žl¨½LcCímq‹ÐH^‹&øLžŠ²KhæJÚµèóVP¹}IÒLcMnÑ`®ŒsÙP…™Æˆ F€œ ·¢K›9Tc4s-¦ášœ†·þ !kNdæ2"¦Ñ7—†Ç\Z¡¹}c‡kæ Z3r"ÞÚ£'OPƒ–ÓïÖˆy‚z³2vÆDÓ¬VÆnŽCÑ?Œù'—1 ¸}y‚¦ÞÙì¢í£3“\§ðnˆËX8qà2¶u¸ŒHe4®äÜ;5czrà2'¯‰Ëœ¼&.cŽÀe±‘'h}É9zZûJy‚ÖÆj¹zsŠŽÀ —'° ›=o®}‘Çyš E 1uE ÒÔ–ÓlHZ¦±¦;3—‰]¿@cÃ{‘fHcCO&9)OƈLΑƈL&šµÎ¨˜ãP•ÂÄ g‘§2(F²åi‰ öò?šRè<­°}cç±1—fÒ]žÖÈ`ÍÁ\:éwÓÙÐ#Üò´AkÞæR•ÆÄ œ‘8Œh¾hãÊIx+á -6Íd;fÐL¶ Ön†z”µd»À¥)m™ÁDÆsž¡¶©Yÿ.0hj¼Ì`C¾2ÍZž…9>… U9SNÍ{ÈTæd0š9uy†Ú­f=¼nÿq¸;¼÷wüîa¿}Üï6wû_6?®¶—O·Û‡›Û¿ÿŸ÷7Wÿö•ûéËWþiþm»y÷°¿þ÷¿ü7nt»{s÷ÕÕáîq÷øßõ«ýîæñ«îf_¥ùoÿáÿöo_mÿcò!"÷ó=ÐÝîEî0ÙG]áŒfÍuÂ\¶BJš©4OÙ`M÷wÓ ƒ5÷7siew7`í¶ªUù˜AS!od°¡3¦¤M‘aZή-ϘJ3tºÍ‘Á†Î46ð¶@Mœ¬E}—œ9h€KëØ¢•™,Be“ÑT11ØðŠ´¨æ®V¢/ÊJåL Âd".Me·E¥RÎ\™ÁœFes&GPGØš’®Ô:gêó­þÊ—± Ž*A]T3•00˜Ø 4&4ã*ÉFQc~‡À¥è¤®´\¬æ \Šþˆ*A|µ4Â9s²—¸Œy×¹ýÑöÑXS׻Ġ*w‰ÁDJ Q•¶È g®Ì *Y‰A1Ó¤JЈ–³ÿÖDcN–—±Œ*AÓÖF` 1áÿ 4çv=DÛGÚZÆsÍTÑ[y7%P­•ãHÑ·Q=/ÐXÓy™Ë„#8ÐØð<¤hÏÊ©j4¦r³•¢[¸JѶžI÷S˜[Èe-á/p™ÈÒ®R´nW«²7ÇaCNÑ¢“ùÖšWÄ`MWNQ‡—SøÖêb°¡!3½¬‘*ŽK9]Os!—œ¸·þ $­m:nßÚ6s™S›Ñ$•úÖAÄ 5Q¥hðÉ |šïˆ¸ŒåVW9Süš5aM\r²Ÿ.cé(ˆïƒi¬ ñ # l¤­]>n߆·#CuµÀ(Z…šÉAs§ŠDNþ[t FV"iK4:ivQª ©ŒÈÚilø™™ÆšÍ\š1Ì`#æ‚iLÁ4ržÝú4 Ò‘ÉD£‘‘µÈ`MïÍäÒt^ä)2(æÜkr—¹4ånž!ÃZrwŽCS÷Ís`°–c¸¦½kkz9êæræÝZoŒì5ÐT…/1ØP™F¹jT•£‰¢™eWå¨ÒifÙJ.ÑȹuëÓ Z©Yu¯ÊQ­4—RÇ\æÔ]âRª Ú7uˆO Ò ¢(Б“éVŸÛLcp_®@‹@άSœZjçr¶Ý S‹Û×ÇjárVÝÊ ÖDoªÝLFÝÚ¢©¬Åµè¹—óì pi*ÆÌ`Ã\ © çÞiÑÈYxÊ ¡© h´ ää<ÍiE\æ„6qiz(˜AÓ=\ ­'§äi¾ÔÜmé TÖ¥`.M21h–æ 6¶ç˜FSi.ÑÞ“SòVfДµÌ )k™Áš¬-Ñð–“îVŸ5LcÐCÁhÖ<%zä¼õ_ ÚéF2ï˜FçŒÌ9*kj1s­Áå@ï…rzÆFÔ0ÓXKù(Ñ{!çç­ßKh”Ϥäé,#ˆf$+¯D+T-+ÛWÕ’‰A¹ŽSà°v sYs&—è½°QV¯*ÑÞ“sñÔh4£,*´xfRíT„0¡™Ë¶c.Mg23ØÈõ¨Ðê2—YÇ\¶öý*´å »õßÑXsy0—5š¹T…6Ú€gÏÄ‹¶öM*gái¾â²–Í\Ö¶þª¹ÌÉmⲑ¥Ç4ÖTk没Z39yM\:Îê(U…T6"7*0ÒRÍJyUÕ"ƒªVM F´j¢9÷Æà\û:Úó´iHh6Tè:A‚˜i´¬¨Sä°álf—hÌ¥òÕri af°!„™ÆÆqœLcC1f#R˜h¦*ËUöŸjJ3h^Ïí[‹Ì ®™¢y \h·¨¦ø1ƒæÆ3h†ÇÕh­©VëkdÐ «ÑN”“õ4ç q©«¼ÄaDåE#éìuðfÚ?{VÞäˆ%M)Ú ²¯š™× r$gæ­>2™Æ†Ë4Z'^69¶¯™Í Ö¼·Ìe-ƒ¹tÂ&¢T¨ËÊx+®ƒÌ¡*uQo”ÓíÖ—1Dcm§­AÍV5É®AÍv¦Þês‰¨T¥2ê“3)v £µ*9ÉnM9CÖ| -ºàg*âéqiÊef°!—[ÔÍåä;5ƒ;nŒ¦é~`kîæ²&¦™K3T­EãJNÈ[Á¸¢öåÄ»uû@N·ÓhÄÌ$Þ)p¡ù°Z ¼9Må˜Tå.1؈o`s'¦IBS¸hiÊYuë2Èés+3¨êºÄ`D×E[ß\;æ²–RÇ\Z~an߈ØEÈj©ss6öؘƜ=GrîÜú½„~9cNÆœÚK\&|u‚~[¹su‚&­Ü¹@£è# Æœu‚F¯œ'g€ËD p€ žÙ¨ghuæ:)A1Z¢NJd0¦).qÆX^\TÈeÌM¸L>Q'5Ò˜“Ïĵ–|žáÐ̉«“LUV T:çµM9àš9ÁÝ"—1Gà2¢N9ÁM\æTlâ²&ÂÓ¹l¨ØDc-×.p­å‰r¤ÈaÂI]§h‚ØÈ· 4Š;€Aq00œÛÑmB9nýQA4¦Ž”TF¤.Ò̤թ(‰)ÚarfÝúE4FÄ/ÑXS ™KUƒ e9EûTÎÅS£1" ‰ÆÄa Q ãöå<<Í9拜›§·Œ•¦ÿ™ÌIaâҔšMgÏÖ[ ¹ï—¡Ù6“±§¢`1šb\`P ƒ«3´šf â­?™Ë†Ì4š—¦îÚKS©Š[Tzåä¼õÇ Ñ¨ ^b°(x ͆ޛ¡Þ9“·ú¤B*Í"xu†ÛTržæÂ@\Æ"ã—rBHàPȨƒË‰x«Ïñ5á™”<a˜£h-+/p)ÄÚ×ÔŒsÂËV+‡7Ç¡ðÆ Ö„nŽÚçL<©› rbžf——µˆ8æÒT›sŒ´V/pÙЙ™ÆÆ&Ñhæñkº2siº-˜Á–Û"G+TÎç[«gˆÁœ$&.k!n9Z66 ãÕ9Ú8š…ñƒ¦š\ u%gñ­Ì T|4´¯)g™Añ âº@³MÎÇ[™ÁšTe./Ä• ™Ê4Ö‚…™Ë†Æ[€1žÉÇckº/sÙˆYc!ÃEŽ4ç–Ós훓ÑÄeÐS\ˆfDP ‡DQ"v:^†S.§ãikâ2'¢‰KUm®‘Áˆ`nFU&£Ž§… ¡i¥xpûF„0Ñhz ŠŒ-Ä\rBÝúoŠh¬ à2A.kÛzÌeC(—)ÒXÛÉc.Í(ãí9éný7…j©‘<¦Ñ ¢àö­Éfâ²VÍ.p™“ÒhÞ¬–}7Ça-ヹÌÉgâ²æå`.--ºD³ÏH^‰ ‘<<¦ÑÜÑ#ÍšxÁFúÓèœ&¥Bûoµzys6N|+ÑÖ’sïÔÞU…ººj6^…ººœ·ú{br—i¬éÊĵZµ¼E½d$)ilìðU¸w$§ç©ÑXÓ‰™k­Ì9k1nÌ%ÊèµÖ ´ƒå ½•4õ`bPÍÂcÍä íÅ™Œ;• !FÓ z«Ðœ={ÂÝ\ûÖÜ MrÚÝZïM“™ü:¡KhÊõIë í%9Õn}½i4KáÕ5î>É w«÷ÓØÐrk´cå„»µÞ1h \n_[‡eM[£ f.c޹¬E3—¦^[£!gÌ­/QPÃÉ[Û_W£R¥š9Ç ª²–¬ù˜ËšÒ[£Vg.w®F½JÎ3À¥ék`k¾_â²Q/ÐÑŠ‰FS>7¨™«fÜ1ƒ5ùÌ\Öäsƒ:³j5¦‘“ø4{ = rbŸ²@"4Å0ºÀ ÏÜ$hŸ=·o ƒªL ŠAsMŠö¬œÛ·2ƒ©ðŒ&E»QÎâSp)ZNšµðƒ Ý8Å]Í<¾À €Ú·¡ì¦¸=4“¹·úŒ&*J/Ó¨J^4JäÌ—¦žœUÈ`N×ÈeCIΤQ•Ê-2¨*ÉÄ ”¦Ú7§—ªôE9)oeÅ£(ƒr¤À¡¹–'È tFf“§Ø¾¦±¦×2— ½–ilèµLc#¤h¬Õ¬krô€ÌÔ¬[{7…©lDù2(_¦YK¿r ÈZž]ಱ—£¥&§ÖiöZo3Iv«Ï{¢²¶7G\šíƒ¸¦Ñô@ähéË©u+3¨Kcô3Èisë¢1§/£ee.Y޹ŒhÎDcN #—R~ÜäF"£ÙÎïr’œâ ,Ð’ÓåVp*pûšÛtªï«°›)¨,Ï”±S™RŒf÷Á4ÖüÇîœÉÙt+êÄ!gÕé÷œig€Ëœˆ&.k»zÌe츊¦@û~µÔ»9Žsïñ͵oDZ£uºZm¼e46<ÑD£Y!¯)Ðj–éVf°ác.Ðb–sçÔüq%ªÙt%*í«UË›~OLcͳÁ\6ä/ÓØ¿LcCþêyÆš~\¢™,çÝಱÈ4ªò-c9oeÍ·-Õœ;fP<å¸)ÑóëÖeX­ò]”um9ŸNSŠ¡î«šgÇ óìÍFq‰¦jž]‰ûržÝú=B4ÓÛx«KDeCé­Ðt“³îVÈQ=ÅnjôV)2XÃU†\šb˜¬9|™kÚá»ögªsËâ¹ö5Ý*G®†ª@ksU…\šj01ÈiukŒVj_ÓÍË :§ÂOª™Uh¶|¾Lem§­jËZ¼1sYó3—¦?‚Ì ç¹lx„‰F5ÿŽTE51ØØ‘cƒþ F³&¢k´õä¤=\šZ33X =®Ñ¢“öÔ”m #É{Dc.y¹4…63hú0j´å½•4·â˜AÓSÌ #ŠÍ–Û˜©4÷ìꌈ[¤‘³í4Å-qÙHò¨Ñ±!gà©Ñ؈‹`s 2úVVËқ㰱Ç46ÊLcÍgQ£/EÎÊ[¿—е˜‹× ¥%çâ­àõæö­…®1×Z"zŽÃšpnp—ØHfÓhú,˜AÓ…Ì šêqƒ>9ÉNYØ!šœw·þ Eg€¹l;æ2'’Ñö3—mÇ\6à˜Æˆ`F+PδÓ|gÄe˻Ѡ%&gâ­%¾Q£7’× /çߩј“ØÄeNb—9‰ö˜œ©g€ËÚ– siåKsûÖ¶[4ÎŒÕËc*œhŒdðµh ©—Ç4šÛÌ ¹Ø¢]vö̼¹öuªäMš¬-cFJå1võ¦ÕwÕÔ=f°vðq­–Î73bФ1—ÔÇ\66™ÆÆ† ÓØph0 ‡ÓXsh´h¶ËY~k,¡Ô¾|>¦1èƒF´Z5ůmA3ŽTu_bPÕ}[dP …k“Cáƒâ^›¤È`ÌÏÐ&r[ݶŸcû&< L#'ê©Ñ(ÊÒÀ`B™m“i”C'‡’W!´¯*U+d0¦®.Å`‰6AMÌZ¾]àÒQ^g¨ä¼»5g5q¨Ê[ÔmäÞµ jšðÚµ·™$»µÇ,SÛO \šºnŠºîjÕð¢¨ÛΤÔ)¼#âR<’¢MQ¯³–J¸Œ9u— ¹Ì4Æ¢ÚõRÍä»À ©3ƒ‰­µ@£‘6å² hæDt‰\Ævà˜K³^›¢%§ß­`ürûÆBÒ—½ƒ*Ú-›ÕªãÍÈ#´qäì;ÍH\ªº31¨ëÎÄ¡TõddóëÖb@+üì‰tKÖÒç8L„3´ZÛš…색 †@£ÏÚ7‘Ãh¬©·Ìec×-C‘µšuËDDo›¡×HÎS£±æÈÐ3b#c.ÐèDÿF©Ðˆ”3çÖï#¢±Á\š03hjÀÄ çÉi¾4·5k×k®ˆ í}9;nýŽ6”œ·> ZÖ2á—µx 没Q稹ÎäÅ­ßKÌ¥\æƒ9䜸•¤bŽºáL-;G(£ÙP¢™ÆšÍ\6vŽJôL B/—5Í\Öê÷úäÌ:\ÖöúˆKζS3™Ê†S$Gãdµ\»(r–ÝZË.1‘ÚDcÃ-Í4š[{9e¶ªå*­n߆+:Sµ‘Sè4ׂ¹lHÝ"Ašs'ØÍµ¯)m™ÁØA?ˆÜe®æ"E® ¦±¦3— ‰L4FRò˜Æ kƒÑt ìE©2¤RÕÄ ¥Á šQÉEŽ šJpQ ƒfv3蜭6=‰ MsÃ4ËàµE‰ FôÝ i¬mó1—ªp­‘ÁVzSтѪ”“òÔhlù! ´p•êßM eBÓÊ%jwæòõ˜ËZ¾s)ž´O«(Q÷TÍÊ+Q÷”³òV%ª8r~Þ ¬Õ9#o­7B k«6Çaï@5F³V/pi†¾1ƒŽ»aúµ¡ò7“ˆ§ðڈ˚˘¹¬X0—¦¿‚¬S”¨ÄËùy믧DcÃe\¢¾>SOá—ªØ&U½˜ÌÉgâÒÔ“+Ü0“³ùÔŒs¦²êÆ\Ö¤s…–Ÿf±¼¶B«ÏHŽÑÈ9~kõÚ r>ßÊ Z¡ܾ¦Ë˜Tå,zä̼•l¸…™ÆFpD…楜}§FcD–"ÍLFÞê:nFY«`¸l¤|05Ý—¹lWhuË9zk¬’Ô¾9}íl#¹xLcpËŽÑ4·ìˆÁFyº@³VDE”l9OqjÕhJj« ÖÄÌ¥©,×hR›Ë¶c.¥êHm†õLVŠ®ÑΓëV€Dc£x][£µe­x]à2'ž‰ËšÞ\£-f$éŽiT5ZÖÊØµ5êôrúÝúoŠh¬%0×¹çhû ¦¶rÞúo‰hÌIiâÒN{fsR™¸ŒHe¢±_Q·ÈeNR—–JÝ$ؾæî]“"ƒ¦ƒŒ¤Þ1”¦±•m×dH¥qÌ6ä/ÓX“¿MŽ\6öÿši¬ÅR0—@¦±vXP–_«š´Ç :ÉÑsT6öÿ˜ÆÆÉœM…4Fä4ÑØÈaÍèã¦Fíj Ì¡ªƒªFŒ rÞZ hMÊwk1 …&g×én:0šæ>3h¸µhÄÊ wŠŠ sÙPz™FËÕТ)'á­5RˆÁÆ6]‹Æšœs§Fcð¼FÓö3‡¶Ï¡EËÌ\v]‹¿œ]·†ˆA=V5‹Ž¬ù˜KUüƒñ‹Ú¥j½;f°¶ëÖ¢Z'çÎ)ù7²$AFΦ[åu z oÇ`Káu\¨^½"Þd߃-ùë¸Pw0V¯ã² “±úxŽ ÷/ä|:\<¾­‰ŽKUf£Î®˜…×1¨Êg´ŒÕÀë¸tÏr¨#Ëùwšýƒ\r&Þú’†hô<ÃŽ=ä3ñ&šª¢L ªBÍ«™x«›1h\É)wëO%¢Ñ; ­cÐsNt z›nY’¢ag"®£±†ÖÑØPu™ÆšªË\ ãr6ÝŠJsØ ÿí¸,$jt4:õ‘\ûhüÏT§[{µ&ª™Út c‡¸ŒHg4±ådºµVOb°pæhÐØ–Óå4Ç qi:"R4¶%Îu\šº03¨Ia4­å´8]³ÐÊÄXɺŽËR4°£jʈÂL4F„3јÎÄemg/m‘ËšÀÎ䲡@3¹*:4MïF–ƒ‰$;G“!µ-=æ²u,…ãʑˆgkœ¹¬ pæ2'À‰ËR…¦ŽÊB"ž£)ÆÚ–`V—œˆ§¼Üš-œ©4$Ú*Š…ô:Nj¦±‹×ÑØØÌj¤ÑÍÊë8¬EÏeh)fêcõò2„\6ÔLcÃÂ46”i¦±¦L3—NøÆ¤‚‘£-k"·¯£±áa-6·¿VHó ‡œß·Òâ£7AÎê[d ]e¯’^‡¦©3ƒfÈ3hnæhð*æñu š[Ì`MëÍÑF1‘Çhóø:[þ†­&Å xƒM—hlxrÜí“óøVP” Ô¯Õºs\¨8É9|+[f°&{™KÓã@ 3YzkK;¦ÒÌ )PÝVªyçÚGíMÎÀ[]¾1Í´_AEÝ/Pµ’Óñ4§7qiª¾nSÈ)zk1 B¥žŽÇªâ•–™"x c•¸¬EP¨VɉykajßZnsÙP~™ÆÆ¶ÓL«Â:KîïÈ zšÃ‰¸ÌiÈÄ¥*²‘ANä[™Áœx&.M¯D‰–¯¹ô½m#é{%Z3rúžf/—¦’Ì šJr‰öÕÙö–0hJ[bSôVf8·÷a®}ñ %𱫥âÍqhhNË wë¿¢±¸À4:‡wí[ÓaKt;Ì$áiq¥&jÖu46‚˜Æˆ&sn\:>á9*íƒ*Ê9ŒHg¢QÕq‰ÁF*FÙ"ª¶‹ ræÌ&.kþ†*A.MC•"ô4^[ê1•µ¸ß*C.miÌ6¤q•# _¦±¦9WrYÓœ‰KN–[ÿí•Hc®ØG‡f-ÿ™¹4„+Tê$ÎU¨4ˉsšoЏÎížkßÚ†]…ª´¹$:æ²NL4æÒé˜ËœzM\ºÅ™:{zI#4#bí4cåò²¤F;mµ”º9M¯3hîìÕhš(–hΞL7×¾ _3ÓØð5×h'˹sšmTÕ|ºí>9ŸN³oˆË†oƒilø6j4õä¼;5k â’óîÖï%4å <­wf¬~÷‘¦ £FãØHÓhf;×h¨VÍcU—Tu^´T³ëˆÁ\ ¼m9¿nõ™Ë4š»z jáF²í˜FSÛmÐÓêV´á™Ã†vÛ 2SóNÅ5Åh:GG©ÐPͺkP…3—uÇ\ÖüÀ *—gϺ›|gÄ v̪¢U[9¿n‡·oD­s†TyÍ¥Ð5¨‚ª¦Ðƒj ]‹J¦œB·ÂjQ¥SM•cƒûjŒf-~¹¬ù|[ÔŠgÊà­-™ÊZ¸D‹ª±œ]·úÆ46vãˆÆ\Q<沦3—ª 'Mïo‹†¹¢xÌ¥énѰ›)Ч³Ðš9v–œ¾·¾P$kuÈ•ÉI{k nbÐ<œ­­‘AU7È *„‰ÁV S©Š`b°á³h[¤1‘& ÒØ+nÐŒ ^æ’3õÖÒÁÔÉÄÊDüZ 1±—&)ÒÓ‘—‰s, QhŒ)Èi’!—ò1šCÑ¡üÿoî|{Û8’4þ>Ÿ‚çÅq‹ø4Ýó§»Ûw£½5Ö±±±ýâ Fbá$Òh'ûí¯É§«iï9òššz€6¶IÍO=3õTU÷Óíšmýë9x•Æ0!vM’(\hÈVW.ºx܃Ë0a® |=‹Šf´µkPñên»)Coá KŽÁ¥ûì¦>è Œ¸ëlä‚F¥Q"Øì §ÂE¥ IÖŒ–‚î±3%‡ ÌÒsWÈc8‡Ú‚Ç'4ºϬŸàP_èî<Ë{W¸8b·Ð°Ån‡ZH÷ép‘­ã¨\½‡úèÎOÊ»>]ÜF¢ûö¦Ò40XžW(|#•†$"£ÒyvjZ¨(-=} {ú¦b@ñ¦û÷&Häú†«à*ƒá*¸ÊÀw8iE³œÙó¨ª9ì{•†m}…p‘„XÔm–¶=a°´íUޤ֣N¼sßÞë£úÐ |S¦DHîu·ÞTOFa02E»ééˆoú8&\lñU¸ ÷ª –QµE*¯ûí&h-Òè—ÝÔ]K¡2ވصÈÞtŸå»T¸,ão‹|ÉÒgçZÌùìöR!g¹ó“ðŽLa`ëæ Û¶v›Ùµº±Ž€‹#ÿó¸\88\Böæ¡àb›m.Ã]2+ƒiŒN` ‹Ñ…ëpŒ6i§uÛ¾5µá GH²3–*—e_XØsçÀeÕºë[à΃Á2 ƒeK¢kÁ0Õò†ÝR7íXeWÑ8–3thØúÂűœAh,;ÂÀ1÷Öõ ™jŠ1޹6¡áXaVhØ­«\l¾Œn—Õœœ\Ÿ£!4–áýŸ\‡J_÷ÉM5"…mNN¸Hâ0úº;Îp”z”‘w~^Ý¡'H¸æé„Š­ùУÀÕÝq“?×BÑ÷¨dèœpÂÅ‘) [Ä.Ë–Eš†í;áÒr–\ÈœI\s=2ÄÉ\scl=ŒÙ«î˜#àâȪ…†mõ›pÑÅmdÚ#î:“Ö¦ q´? ‘ÁnŒŠ­ùÑ£d²<:Ï (toÝÄ )¶Ðp„j¡±öÑ (ƒFŽÎ›þ.Ž&È€9É;÷Ö\䬼©ã¯Pq¤ÐBÃÖö.ÓHŒU÷âM§Pêö;3ŽÇ€²”Έ'\$ñ¸Ð˜Åc”ɺ ϶p4Ë}…c]†Ð˜`TÀ#'éM.à…Êr-†0XÎ ƒå²7a°ì!(¨9ÎÀsÊh¶3ð*Ⴘ€ªr2‹Þá(4–W,—^Ô²º)oú»‚z„ÌžP¡˜Úó*{Þä#ƒ\wÄœgn¶ÖÑùó0dîÏ#à²l ƒiP. íˆ0€fªð¼—#€ƒmöN¸LCsƒev0â‚vç¼±ëOÕ ã° °Ñm …p±-¡ˆ\‡—¾Ù¼V£5,4Ç• ›OZ¸ØÖÁ.ÝÊGÀeÙ/Ž-LÃva  ۅ˲Qçéž½é#O¡±ìGT0ºgÏòi)\tQ5ÖÈ!yS·V •îê›êIBu¥;ø&f0¿…Á²/Qeê>½éã\¡±ÚB®ÏÖ.Ë~DL`àX!4óv E¸îÌ3£áX¤&4l‹Ô„‹-û.®u ­Ý­7ý3Uh,óaa°ŒÉ •ì»ðÆ®O…ACç»K¨gußm»/¡°$9ºNhèBrá²lH$”¹“ÙîÆ8ØRä„ÂV7ÜMÿ$³ÀŒÒR÷ÒYÞ%p鮺éïR¡!I” ]¢\¸l=,_¨‹u»ÝT¹0°íc‘P!ëv;;.ß ¾ÑíwS¿t¾A¯›î,G ¹¬n¿³ç±åÙqQ„òJCÊ+×]wœ÷^•‡)¯Ò§Ô•ƒ.R£ìÑyS<-åú†+à|ƒrÇòü;aЭwÓ¿5…†$ÒºH‹p²òFF©ÐæÉ¾A¡;ï¬úÚ•Š.ö.’,¹ÐL5÷7ÆAÑoö *,Žô* I\.4tq¹pqÄe‡ZX·ê™ÅD¡2ôH{‡º\·ìMŸ á\_e°ŽÁ5¤nΛj,¶ ½î›˜Áp[e ˜¾ó® Ùô]å²Ì~…bý„whl чZúÍ4Ôö`°l<¸ FûýÈõuÝôl±Û®rNkm^œ‚f¸šØ»†©ú»{98Èæä*[·A¸,ƒ®oÀ`t…£¿Phîü(¼½×w¸>Ùž•Ëлá=ò9Ý;7R%Ý'gÖ=ðHž,O»« lqÖ#©bóÐU. o‡÷ÈdFœs£.Ý;g5JlçàU.¶Î¯p™FìÂ`Ù‰¶ÜØ£vнwÓ¿]Ȉ-w•Á4#. t±\ºãΫEn:™÷nŒÃ2Gˈ+ –·E—^÷ÎMÌ@Øñ4¶¤¸E‰§›ëÌÊ+¡âhQÝrgFc9%' Sr-Zº£ÎŒ†cù¯Ð°%Â-šl»Êe™ G£Bh¦ŠÅ#º«nª;ƒÒÈÉt“«%ŠÝ;?—nìú$ñ·Ðí‡é[”þçÔUºø‹’W7ÎMñ,—ë[¶#„oCbßa¶NwÆMþ [wX¸lPì¥B ªû⦿w…†-L [Â,\c¡±L“…ÍÕÜ¡äÒÝtö\„‡ÛU4[G‡Jƒã˜;ß¡æÐMv–Sá¢ à…‹.€.¶Œ»C½¤›ðì’•BÅÑéP-é–<Ë{®‘£ô&¿w¨_Ò«h–3†Â`9c( MêõÇAz•†-P —eÎÝc¦y2ÞÈ*4Ó„ ØNÍ«\Ö«5zŽ´ºï@ÃÑ ’x\h¬÷ ºH\¸lRæƒ Ž ‘èBcåïë·•üpççç”ÌÂÀÑÛ˸ÀÀ·×fE³\I' –+éúýç+Çî@BÃÖm.Ë*úmbÐ=|Óß©Bc¹@nhÀ`fäý#'ßMÝ*ŽLWh,c퀺èÎϽÛ{ý×g[š< yÔýzSÝ›ÂÀÖø-\$.½I¥åYw•kÍ…P±MÞ È1ïÜ£·÷úÈZîü ¼ƒO ò„‘sðLÊA³lõ Ö[± ‡e‚ÎÑñ„‹mœpq´z’<¶Cð*G*,4lë&„Ë*=–ë³¥ÇÂe™ ƒilÛx•‹p„ Q…gݾ7ñCdÙ÷ èôýæBëùï«åêj3hO®óõâ|¶\ü6[/®¯fWo¿?<Éÿÿ÷7Äç³_¯??zsO.4?¿ºXžœ­–ëÅr}"?ídq~‘ÿ”ȉ{sïñæOOæ"ïùIn{c7?ê‹¿­F”†~¸Íhä‹ýróeãáÉÇÕñ·ëÕÙÿýÛš6}»Äÿ]¯./¿l|ZòñÁ>aCÿn|^¿;ߎϑŸ•ÙÙåüæ&i~¶¾ø°øÂÁùèGÿçùâf}±œ¯/VËGÛÿ«ÿSùBþ/ùJþO7é•ÔAïQ›õilÐïæ¼«›ÐNv>óJêM(òÐlnBùjþìVs¿™å÷&߈Í=Xç+Ͷ{pà·¢½‰†.¿Žå?‘0Ììe2 îkåÍ|™å8Ïlõn±Ì¿ÌÏ«ëú }ô«Œ^ü“±.JüÙõ@4ƒ§DÏqhÙ;Z@t'‡žýÁa` ´€%hFðìruóO«( éÞX°††åT ¤’ˆ‰á  Å;%´:"€´:¡ÄVG"æ)­ŽD¤ AÓ*@^!Aª5!¡ˆ2…WGÊDZIH"mA’PsFZ!IH"­$¤ ‘VH¤8jBÂe„VGVGR…d§#cd´ "€¼ ‚$&ñ*HäUd1ISŠø‡$&± H,󑉵©€¬ dY‰UAb³Í²BÃÚÒŠM @V!‰M@V!‰M@Ò–Vlð±êHd­D* ¯ò I ¯@^!Ù&3ÁÑ § CÄ1ðÁÑêpŽUGp°qpšŽPðáv´2"€´2⑬:Ò†Vå#`8=38MD(øð{ºvVÄvÁ³Š‡ðÑŠŽu žUÖù È*!:©­ÝtÈ^2hGK[x`wüÐ²Š‡ð±Šö-ká×CGÛ¼@Zñ@ýÑÑÖØü;t¬õ6ºí$ˆ’N¦Gìø:Z @V >Ú)ùKÇ*"…¯g-@„UC°Moèí 12Zñ@zÕóŠG¤í^aÿÔÐóªò—žU=°ùkèiÕCiûWØ’4 |“Øx3ÐÚÓ+ mõ!€´½+ìhíé›gZ{zÄö•Aµ§SèÂG»KízX{É ½´¾ôˆ­'­/½Ò*H€øÒúÒ+ ] ²— ÚFëH¯€¬+l h é[ÃZCzä“ì hè¨:Ñ9!¾´VôˆMa‚jEg/ÂǧØ &ÐZÐ#6ƒ ªÝxè ª÷œâ¡+|´’-B‚ê=§ÀÂG+Ø?"ZÏ ðÑêö·ªb‘6«þsÛà—\Tã9ÅÈ>Ö‚[^ß¹Òªvªïœâ#i¦µ'øâ£j;'À[|¤uW@RõHpÅGÕtÎ1€=IE¤ò‘ŠH‚ç<ÒzÎÓ‘Ös^IE$ÁÑi-ç Žî¨ZÎŽîÈê8¯|¬â q¬†óC|d5œW>Ö9óä qªáœb¡q¬~óÊǺè*aGÈj8>CÃùíøhˇÖw^iëd$‹Öxž°éFd5ž'ß‚UD„µ Á¦%‘Öx.€¬Æó„]U¢j<çÀ@:ãG%£UìûY=ç•W= ¿´ÖóÔ"<«Ös@T™ª÷œ V@°5MTÝç /1¶~‰ªùœc m"€´:‚Ís"­ý¼Ò v‰´þóÔ¡NRýç€P:Հλ¦íšY#dªóœãÖ¢Q­ç€Ъ÷œ‰4«=a•HkAOØ¿$ÒZÐ+ ­€`ƒÈjAO=ò|Õ‚nŸûŸY§A°=CT­çÌûQu 3 à€WC5 Û>zØU ªÎsŠ‘ÃK«Ï)øðꪾs ¾òêÒªlÝ‘Öw^YËáã+;à‹ªíœaä*^Z×yd]€Óyd= =ÁÙUë¹í«Owdõœ§Ù õœ'Xº£ê97¾µ%êÑÎw í|Gd=ý<Á1UË9«lDTC†ŽóÛñ±Ö°G>Ûy%£•ˆŒ€õÈóÊÇ×£‚c?ª†sŠ‘«ßûõzñó£7÷äBóó«‹åÉÙj¹^,×'òOçë“Ý;qoîåø5¿¹É_Ÿ­/>,ÞÜ{¼ùÐÓùヿÉm/p¬rpØH‹£ áUÍð€P^V7|„¾‘ºá+Ÿê†ç@È«~È+oWÞiå ›æ$V?|DAõÃs"ƒQ ñ€bRG|想:â+ êˆç„Ò‘žÅžù¦UG<Ç"L³ãw€´:‚}U’áiì‡Al ’Tc<_‰1l Ä2YyyYå×WƒV>Z¼¤~øÌ‡ü€ô0ö̇WCµÃ3ñÑŠìúIuÃS `ᣭA`†Oªža…s¢?ó¡†#µÂïøX;Y"´áQì{ÉûXð]TV'|DzEê„Ï|H¯T'<ká|R}ðL|´í+øôëQìêAj‡¯|†'±ð¡4'uÃïøXël‘ =ñ{É ¾¤nømáÑ£2bµÃïY+Ù©~ÇGÛ¼*€¤¦øÌ‡ôÕß6Øë%‘šâw|¬õÇ€ì…Οɠ»ª)žãÑ+€¬¥6£I†¦øÛñÑVH«õ8ö ˆü…õ8ö ÛV\™ Ê«Úâ)†. qÀz{„´©Æx*@Úò;ú$Cü^2h¯êŒçºšY»V…O5È3 «C>¢»ÁêÏ€Ð6Õ!ω3´È‘ÑJ6õI¬æø ˆì€õPö ­‚Dd¤îøÂ74ª;žc[ÚM|Œ‘ñUÛ}s2­f ëœÇvcŸÌÇ«W9"y•£Ò*G*‘™U9 éIì™áÙð$ö½dxyIÏ`ßñÑÊÇvÓˆ HÛ´J.ê)ìwØ5åÝe• H:ëáš\H§ÌÝvgÌG*®AHk;w b ­í¼²6®\ƒHk;w[Ûy$-B*«ˆl]ñ™tæ¼ò±jˆƒ†¨–sŠÄ• Í:sîò@ÒSØ3B «å¼òÑjˆCT-çXøX ‘ Ȫ![G|æcÕ 1tœð¡Nbõ;S}çD|¬¶sçQDZÞ‘#°úÎ+mâQDZúÎ+ëTˆóHYaßÒjHácÛ8“!?eµœ;ìÊÐr~˜¯EvEkZ5è!Wª¡Ü6Ù2ZèÑÉ#=d½u‚ é!ë™Õé!뙹°á!ëcd´eÄ€ŽÖF^Yu# µâs‘»€œÊð|õ‘‘+Qu# # =e=ó!*«rã'QÖ<î2Zóxd-72*Z ¹ ¨üU 9ÃFgÒãÕw|¬â!|vâ±—l+kÎð\õ½dÈøCÈhÆlGëw1U0„uÁ-lÏŽô(õ­^>Ú¹ ¤mR@V߸K|¬M*ácmR ëš)á£mUaãGk>Ú ï„,‹Ö<.|¬5GB¨šÇ9n0yÝãØAéîqŠ;Œ,•×<.€´uˆÒízè°÷ˆ£µ§>Ö DøX'È}ÓT>|ƒKµSð¡qE{R¹Çæ-NµS²ÊGd•ýo­qÜ7Ð7Õ8NÈZ…xl?âTë8 k+«²Ö!Èê÷aÖ=^i…Di…Di…›9Zÿ¸w¨Õiýã»9Õ?ΈŠS5s¢¤S}ä€XfâøÎ.÷e–ŸÖBî± »3´ï%Ãk¡šÇ)†.¡‘`xjù^2ˆ­mÜ—öŸáå{ÈÚÒÝ õ‹·MyaéümS^XV™h^XÃCÊ÷’! UâC‡,ÏÐ(¾ [Ì9Z‹x‹=Òœáå{ÉðÂÒzÃ[läTo¸íе入•‰¶¼°|2Ñ•(œ6†ê³Õr½Xn~àÆvýÍ,/“ Õló—¡=œÏ~½^üüèͽO.Ö¾¹÷øÃÅâ·‡'óÇ·kûl~îg}RýMÊrTØÆñõjuÌ1ÞC4tˆ5´óÔ"3…Ã|w󟬮®ò}|ÿ¯æ—«ÙÍâ÷ùøý÷8Ã÷¸Û> å '׋w—;ñŸùYõW+I·Õ!ç{¸ºžy:å)ý»gâsžÒc=]Ùd×±zÒ;Y”låIßwge)(«½oúŽŒDhÏÀe®òª¦Í¥”(tþþÝåÅÙ|½Ð#ÑØF G.ù^c$c³‡ø ã¦7‹›»_T³†ˆM¢©­=ó!Õc=$="~ªîv†l¡¬æö Xž@Î5_™ñT5·s `y9×| ±ÔDªÇb± ¤#5¹g><¬¥g@iÕëÎ0€Øú˱ZÝ3`yYE¤ä”¬V÷ Xž@VéQ²–>Ä¡<¬"‚í—œêuçÀí+â -ï#˜Àç>-²¾ 3Ù™t&‡„©ißø Ûüì,òì|±¼Xlº²›‘ß”cce¬|îóïtÂáÆ¾i6’½ÕHøM:«‘ ¸~´‘LF24ð5øf0É|ý×GÉ`5’噈V#qýt´‘ŒF#é§\c4’˜÷÷îxŠ“¬FÚél'4XàÝñÇ5FC‰3·¼³‘œ|}Hž;žä¸[ÏËy(q‚wVšÓ–ør<Íq·nÕ{(ËSa%:háyw<Ñq6ëBƒfš÷VªƒUÞOuœM¡ÊÚyïdÇãVï(;6•NþU‹x#ÙñEöüeǨÔñX·æ½‘ìø¶˜#ÊŽQ­ãÛòTÉŽ/²ã(;FÅŽ/²ÓÉŽ/²Óºý§¬øfœ ~ðþ¾ õÿûÕWäÿ;õîbùËìzõ~}±\Ül;Œçóõü§ùÍbv?óü§û›úìéO_þ8ûöÛÿðÕÉÿ¥k\ÓÎ^ž¾š½zúÃéÛÿ}ñüôѽxöýÛúÇÙOòUËGÝö£/ÿúìí/¾/Ÿ”?m?¸ý\®ÿ¶ŸûÓ‹OŸþ÷ó·9ýŸ·Oþ|úä//ñüûüîëçOÿúúô“¯}òW»oÕ“?÷ãwOòoö6ÿéí“gOOŸ¿Âµûþ§/_?{õRû埔ŸðâÙ³ï^=}ñüí“ÏŸŸ>ÙügùÊ¿|ô}·×ç/^¾Ü ìö¸å®ÏÎVWï.ëü†®–3ß4éAãd×}Ó÷ß4íWÿÍøÄm1vpercona-galera-3-3.8-3390/tests/test_drupal/loaddb.sh000077500000000000000000000014521244131713600222600ustar00rootroot00000000000000#!/bin/sh TEST_HOME=$(cd $(dirname $0); pwd -P) MYSQL_HOST=${MYSQL_HOST:-"127.0.0.1"} MYSQL_PORT=${MYSQL_PORT:-"3306"} MYSQL_USER=${MYSQL_USER:-"root"} MYSQL_PSWD=${MYSQL_PSWD:-"rootpass"} MYSQL_CMD="mysql -u$MYSQL_USER -p$MYSQL_PSWD -h$MYSQL_HOST -P$MYSQL_PORT " set -e #Prepare drupaldb database $MYSQL_CMD -e \ "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON drupaldb.* TO 'drupal'@'%' IDENTIFIED BY 'password'" zcat $TEST_HOME/drupaldb.sql.gz | $MYSQL_CMD # Prepare drupal6 database $MYSQL_CMD -e \ "GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON drupal6.* TO 'drupal'@'%' IDENTIFIED BY 'password'" zcat $TEST_HOME/drupal6.sql.gz | $MYSQL_CMD $MYSQL_CMD -e "FLUSH PRIVILEGES" percona-galera-3-3.8-3390/tests/test_drupal/run.sh000077500000000000000000000073461244131713600216470ustar00rootroot00000000000000#!/bin/bash # # DESCRIPTION: # # This scripts installs drupal site and runs drupal test suite against # installed site. Drupal package will be fetched automatically if it is # not found from working directory. # # SETUP: # # Simplest way to get test running is to create symbolic link # /var/www/drupal_test which will point to ./workdir under this directory. # # PARAMETERS: # # CONCURRENCY - number of test cases run concurrently (default 1) # WORKDIR - directory where drupal site is extracted and installed, # should reside under www root so that site can be accessed # via web server (default ./workdir) # DRUPAL_VERSION - drupal version to be tested # URL - url pointing to installed site, should be specified only # if default does not work # TESTS - drupal test suites to be run or --all to run all tests # VERBOSE - to run test suite in verbose mode set this to --verbose # # NOTES: # # WARNINGS: # * Drops database drupal before site is installed # set -e BASE_DIR=$(cd $(dirname $0); pwd -P) # Parameters CONCURRENCY=${CONCURRENCY:-"1"} WORKDIR=${WORKDIR:-"$BASE_DIR/workdir"} DRUPAL_VERSION=${DRUPAL_VERSION:-"7.12"} TESTS=${TESTS:-"--all"} VERBOSE=${VERBOSE:-""} # Drupal pkg/dirname DRUPAL_PKG="drupal-${DRUPAL_VERSION}.tar.gz" DRUPAL_DIR="$(basename $DRUPAL_PKG .tar.gz)" # Construct url (note, should be done after setting DRUPAL_DIR # to get it right) URL=${URL:-"http://localhost/drupal_test/$DRUPAL_DIR"} PHP=$(which php) DRUSH=$(which drush) if ! test -x $DRUSH then echo "Program 'drush' is required to run this test" exit 1 fi if ! test -x $PHP then echo "PHP is required to run this test" exit 1 fi # Helpers to manage the cluster declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" # MySQL management MYSQL="mysql -u${DBMS_ROOT_USER} -p${DBMS_ROOT_PSWD} -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]}" # Create working directory if it does not exist yet if ! test -d $WORKDIR then mkdir -p $WORKDIR fi cd $WORKDIR # Download and extract drupal package if ! test -f $DRUPAL_PKG then echo "-- Downloading drupal package" wget http://ftp.drupal.org/files/projects/${DRUPAL_PKG} fi echo "-- Extracting drupal package" tar zxf $DRUPAL_PKG cd $DRUPAL_DIR # Relax permissions for installer chmod -R a+rw sites/default cp sites/default/default.settings.php sites/default/settings.php chmod a+rw sites/default/settings.php # Restart cluster echo "-- Restarting cluster" $SCRIPTS/command.sh restart # Drop drupal database, set globals $MYSQL -e "DROP DATABASE IF EXISTS drupal; SET GLOBAL auto_increment_increment=1; SET GLOBAL wsrep_drupal_282555_workaround=0;" # Install site echo "-- Installing drupal" $DRUSH si \ --db-url="mysql://${DBMS_TEST_USER}:${DBMS_TEST_PSWD}@${NODE_INCOMING_HOST[0]}:${NODE_INCOMING_PORT[0]}/drupal" \ --account-name=drupal --account-pass=drupass --clean-url=0 -y # Relax permissions so that dir can be cleaned up or overwritten # automatically. chmod -R a+rw . # Append base_url in settings.php echo "\$base_url = '"$URL"';" >> sites/default/settings.php # Enable modules MODULES=$(ls -1 modules | grep -v README.txt) $DRUSH en $MODULES -y # Run tests cd scripts echo "-- Running tests $TESTS" $PHP run-tests.sh --concurrency $CONCURRENCY --php $PHP \ --url $URL $VERBOSE $TESTS >& $WORKDIR/drupal-tests.log tests_failed=$(grep -v '0 fails' $WORKDIR/drupal-tests.log | grep 'passes' | wc -l) if test $tests_failed != 0 then echo "Some tests failed:" grep -v '0 fails' $WORKDIR/drupal-tests.log | grep 'passes' exit 1 else echo "Success" exit 0 fi percona-galera-3-3.8-3390/tests/test_insert/000077500000000000000000000000001244131713600205075ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_insert/create_big.sql000066400000000000000000000002031244131713600233070ustar00rootroot00000000000000CREATE TABLE test_insert ( i INT AUTO_INCREMENT PRIMARY KEY, f FLOAT, d DATE, t TIME, c CHAR(32), v VARCHAR(1024) ) ENGINE=InnoDB; percona-galera-3-3.8-3390/tests/test_insert/create_small.sql000066400000000000000000000002021244131713600236550ustar00rootroot00000000000000CREATE TABLE test_insert ( i INT AUTO_INCREMENT PRIMARY KEY, f FLOAT, d DATE, t TIME, c CHAR(8), v VARCHAR(1024) ) ENGINE=InnoDB; percona-galera-3-3.8-3390/tests/test_insert/insert_big.sql000066400000000000000000000022671244131713600233640ustar00rootroot00000000000000INSERT INTO test_insert VALUES ( DEFAULT, RAND(), CURRENT_DATE, CURRENT_TIME, 'pokemon forever', 'opwkmefovcm weofvowd fowehvfe wehg ryu ki67 w2 fe4t5h ytryu76j tkutykuj thret h4t5 hjy5tyu6j rt hyj5t jty er w cda swc2trt45yu 65i 76ujt yhjn rhjr tj6yu7kjyt jt regt h4 hjytykiy ukhr4 hthtrjtyu7 tyu jty jtyjutykj 6tyu jt hr egge rgte tr5h rthyj ry5 kt dferht rt hjyurt hregftdefgwfrovppoodmpfpp owenj vfweovwjneokmemfdvcwoem wefvowkej 0o=0943i8t5 34fw=eri=we if jfowem -jfwef =ojk frwe=fok wedfwoerj fwde f23 c2dw xr5ju76 p0- 0= 7u kiki8 rtg erf wefd qw fdehtr j k iuk o .lp 4 t5gvwed45w ty65 7u 987l9oimr tg wef d qews xq d34 t5hg 65kji 87j 5t hg erw f 3wefjfdwpewofvdsf ofvkdspfpvsmvsd wefverfbvegfrbqwertyuiopsadfghjklzxcvbnm,.qwertyuiklopasdfghjkl > $debug_log echo "-- Running test $test" $MYSQL -e "DROP DATABASE IF EXISTS test; CREATE DATABASE test; SET GLOBAL auto_increment_increment=1; SET GLOBAL wsrep_drupal_282555_workaround=0; UPDATE mysql.user SET Password='' where User='root'; FLUSH PRIVILEGES;" ./mysql-test-run \ --extern socket=$SOCKET \ --extern host=${NODE_INCOMING_HOST[0]} \ --extern port=${NODE_INCOMING_PORT[0]} \ --extern user=root \ $test result=$? # attempt to reset password back to original mysql -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} -uroot \ -e "SET wsrep_on=0; UPDATE mysql.user set Password=PASSWORD('"${DBMS_ROOT_PSWD}"') where User='root'; FLUSH PRIVILEGES;" if test $result != 0 then echo "Test $test failed" exit 1 fi # Iterate over nodes and check that cluster is up and running node_cnt=0 for node in $NODE_LIST do node_cnt=$(($node_cnt + 1)) done for node in $NODE_LIST do cs=$($SCRIPTS/command.sh cluster_status $node) if test $cs != "Primary:$node_cnt" then echo "Invalid cluster status for $node: $cs" echo "Test failed" exit 1 fi done $SCRIPTS/command.sh check if test $? != 0 then echo "Consistency check failed" exit 1 fi done percona-galera-3-3.8-3390/tests/test_overhead/000077500000000000000000000000001244131713600210005ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_overhead/run.sh000077500000000000000000000047671244131713600221610ustar00rootroot00000000000000#!/bin/bash -eu # This test measures master replication overhead by running a number of # autocommit queries with wsrep_on set to 0 and 1. # # NOTES: # - The load was deliberately chosen to produce maximum replication overhead. # - SQL commands are first dumped into a text file in order to minimize client # overhead when benchmarking. declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh stop start_node -g gcomm:// --mysql-opt --wsrep-new-cluster 0 declare -r SQL="$(dirname $0)/tmp.sql" declare -r TABLE="overhead" declare -r TABLE_DEFINITION="(pk INT PRIMARY KEY, u VARCHAR(64))" declare -r MAX_ROWS=50000 insert_load() { local WSREP_ON=$1 echo "USE $DBMS_TEST_SCHEMA; SET GLOBAL wsrep_on=$WSREP_ON; " # echo "BEGIN; " for i in $(seq 1 $MAX_ROWS) do echo "INSERT INTO $TABLE VALUES ($i, uuid()); " done # echo "COMMIT;" } update_load() { local WSREP_ON=$1 echo "USE $DBMS_TEST_SCHEMA; SET GLOBAL wsrep_on=$WSREP_ON; " # echo "BEGIN; " for i in $(seq 1 $MAX_ROWS) do local PK=$(( $RANDOM * $RANDOM % $MAX_ROWS)) echo "UPDATE $TABLE SET u = uuid() WHERE pk = $PK; " done # echo "COMMIT;" } MYSQL="mysql -u$DBMS_TEST_USER -p$DBMS_TEST_PSWD" MYSQL="$MYSQL -h${NODE_INCOMING_HOST[0]} -P${NODE_INCOMING_PORT[0]} -B" warm_up() { echo -n "Warming up: " $MYSQL -e "DROP TABLE IF EXISTS $DBMS_TEST_SCHEMA.$TABLE" $MYSQL -e "CREATE TABLE $DBMS_TEST_SCHEMA.$TABLE $TABLE_DEFINITION" insert_load 1 > $SQL # generate sql commands /usr/bin/time -o /dev/stdout -f '%e' $MYSQL < $SQL } warm_up declare -a INSERTS declare -a UPDATES for wsrep in 0 1 do $MYSQL -e "DROP TABLE IF EXISTS $DBMS_TEST_SCHEMA.$TABLE" $MYSQL -e "CREATE TABLE $DBMS_TEST_SCHEMA.$TABLE $TABLE_DEFINITION" echo -n "wsrep_on = $wsrep : " insert_load $wsrep > $SQL # generate sql commands TIMING=$(/usr/bin/time -o /dev/stdout -f '%e' $MYSQL < $SQL) echo -n "${TIMING} / " INSERTS[$wsrep]=$(echo -n ${TIMING} | sed s/\\.//) update_load $wsrep > $SQL # generate sql commands TIMING=$(/usr/bin/time -o /dev/stdout -f '%e' $MYSQL < $SQL) echo "${TIMING}" UPDATES[$wsrep]=$(echo -n ${TIMING} | sed s/\\.//) done INSERT_OVERHEAD=$(( ${INSERTS[1]} * 100 / ${INSERTS[0]} - 100)) UPDATE_OVERHEAD=$(( ${UPDATES[1]} * 100 / ${UPDATES[0]} - 100)) echo "Overhead: $INSERT_OVERHEAD% / $UPDATE_OVERHEAD%" percona-galera-3-3.8-3390/tests/test_pc_recovery/000077500000000000000000000000001244131713600215235ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_pc_recovery/README000066400000000000000000000004231244131713600224020ustar00rootroot00000000000000The test runs sqlgen load aganist the cluster, and kills all nodes with -9 to simulate cluster outage. Then restarts nodes and expects them to form PC, and then checks consistency. Usage: ./run.sh [N] where N is the number of simulations. If N is omitted it goes forever. percona-galera-3-3.8-3390/tests/test_pc_recovery/run.sh000077500000000000000000000032241244131713600226670ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh TRIES=${1:-"-1"} # -1 stands for indefinite loop # Start load SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 999999999 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 \ >/dev/null 2>$BASE_RUN/pc_recovery.err & declare -r sqlgen_pid=$! disown # forget about the job, disable waiting for it term=0 terminate() { echo "Terminating" term=1 } trap terminate SIGINT SIGTERM SIGHUP SIGPIPE trap "kill $sqlgen_pid" EXIT pause 5 5 consistency_check $sqlgen_pid GCOMM_EXTRA_PARAMS="pc.recovery=1" # kill all and restart them cycle() { kill_all pause 1 1 SECONDS=0 # for wait_jobs for node in $NODE_LIST do echo "Restarting ${NODE_ID[$node]}" # sometimes mysql pid exists for a while # after being given SIGKILL. # here we double check it for safety. stop_node $node || stop_node $node # starts with pc.recovery=1 start_node "-g $(gcs_address $node)" $node & done wait_jobs } try=0 while [ $try -ne $TRIES ] do ! let try++ # ! - to protect from -e echo -e "\nTry ${try}/${TRIES}\n" cycle pause 3 3 consistency_check $sqlgen_pid done exit percona-galera-3-3.8-3390/tests/test_seesaw/000077500000000000000000000000001244131713600204725ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_seesaw/README000066400000000000000000000013061244131713600213520ustar00rootroot00000000000000The test runs sqlgen load against the cluster and in round robin order kills and restarts nodes. After each transition consistency check is done. This facilitates testing configration changes under highly concurrent load with lots of certification conflicts. Sometimes the first consistency check fails, perhaps due to some race condition. In that case a second consistency check is attempted and if that fails the script exits with error code. Usage with gcomm backend: ./run.sh [N] Usage with vsbes backend: GCS_TYPE=vsbes VSBES_ADDRESS=192.168.0.1:5678 ./run.sh [N] where N is the number of off/on transitions. I.e. N=1 means that 1 node will be killed and restarted. If N is omitted it goes forever. percona-galera-3-3.8-3390/tests/test_seesaw/run.sh000077500000000000000000000050411244131713600216350ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/misc.sh TRIES=${1:-"-1"} # -1 stands for indefinite loop KILL_RATE=${KILL_RATE:-"3"} SST_RATE=${SST_RATE:-"2"} restart # cluster restart should be triggered by user # Start load SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 999999999 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 \ >/dev/null 2>$BASE_RUN/seesaw.err & declare -r sqlgen_pid=$! disown # forget about the job, disable waiting for it term=0 terminate() { echo "Terminating" term=1 } trap terminate SIGINT SIGTERM SIGHUP SIGPIPE trap "kill $sqlgen_pid || :" EXIT pause 5 5 consistency_check $sqlgen_pid # kills a node and restarts it after a while cycle() { local -r node=$1 local -r node_id=${NODE_ID[$node]} local pause_var=10 local var_kill=$(( $RANDOM % $KILL_RATE )) if [ $var_kill -eq 0 ] then echo "Killing node $node_id..." kill_node $node pause_var=$((($RANDOM % 8) + 1)) else echo "Stopping node $node_id..." stop_node $node fi pause 0 $pause_var if test $pause_var -gt 5 then consistency_check $sqlgen_pid else echo "skipped consistency check due to fast recycle" fi echo "Restarting node $node_id..." local skip_recovery_opt="" if [ $var_kill -eq 0 ] && [ $(($RANDOM % $SST_RATE)) -eq 0 ] then echo "Enforcing SST" skip_recovery_opt="--skip-recovery --start-position '00000000-0000-0000-0000-000000000000:-2'" fi if test $pause_var -gt 3 then restart_node "-g $(gcs_address $node) $skip_recovery_opt" $node else stop_node $node || : # just in case the process is still lingering restart_node "-g $(gcs_address $node) $skip_recovery_opt" $node fi } node=0 node_num=$(( $NODE_MAX + 1 )) try=0 echo "### Looping over $node_num nodes ###" while [ $try -ne $TRIES ] do ! let try++ # ! - to protect from -e echo -e "\nTry ${try}/${TRIES}\n" cycle $node pause consistency_check $sqlgen_pid node=$(( ( node + 1 ) % node_num )) done kill $sqlgen_pid check exit percona-galera-3-3.8-3390/tests/test_segmentation/000077500000000000000000000000001244131713600217005ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_segmentation/run.sh000077500000000000000000000106641244131713600230520ustar00rootroot00000000000000#!/bin/bash -e # # WARNING: This script overwrites files under $TEST_BASE/conf (form of # my.cnf.), # # Script to measure inter-segment network traffic with and without # segmentation. # # Each test iteration involves installing demo package, starting the cluster, # creating database with single table of 1000 rows, 1 min warmup stage # and final 5 min run with pure update load. Number of updates # generated by sqlgen and total bytes sent and received over group communication # network are measured and and values # # # # are printed in output file "results.log". # # Node locations for stats gathering NODES="test1 test2 test3" # Group communication interface on nodes IFACE="eth1" # Client connections per node for sqlgen update run USERS_PER_NODE=1 # Demo package location is read from command line PKG=$1 if [ "$PKG" == "" ] || [ ! -f $PKG ] then echo "usage: $0 " exit 1 fi declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} # Output file for statistics out="results.log" if [ -f $out ] then rm $out fi # Function to get traffic statistics function get_stats { local total=0 for node in $NODES do str=`ssh $node "ifconfig $IFACE | grep 'RX bytes'"` rx=`echo $str | awk '{print $2;}' | sed 's/bytes\://'` tx=`echo $str | awk '{print $6;}' | sed 's/bytes\://'` total=$(($total + $rx + $tx)) done echo $total } # Iterate over 3, 6 and 9 node setups # Usage: test_run <0|1> # 0 - no segmentation is configured # 1 - segmentation is configured function test_run { local segmentation=$1 if [ $segmentation != 0 ] then echo "# with segmentation" >> $out else echo "# without segmentation" >> $out fi for ii in 3 6 9 do ( cp $TEST_BASE/conf/nodes.conf.$ii $TEST_BASE/conf/nodes.conf . $TEST_BASE/conf/main.conf MYSQL="mysql -u$DBMS_ROOT_USER -p$DBMS_ROOT_PSWD" for node in `seq 1 $ii` do provider_options="evs.send_window=16; evs.user_send_window=8; " if [ $segmentation != 0 ] then provider_options="$provider_options gmcast.segment=$(($node % 3 + 1))" else provider_options="$provider_options gmcast.segment=0" fi echo "wsrep_provider_options='"$provider_options"'" \ > $TEST_BASE/conf/my.cnf.$node done $TEST_BASE/scripts/command.sh install $PKG $TEST_BASE/scripts/command.sh restart SKIP_LOAD=0 if test $SKIP_LOAD == 0 then # create table which will easily fit in memory SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD \ --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 0 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --ac-frac 100 --create 1 --tables 1 --rows 1000 # warm up for a minute LD_PRELOAD=$GLB_PRELOAD \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD \ --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 60 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --ac-frac 100 --create 0 --tables 1 --rows 1000 \ --users $(($ii * 3)) # real run pre_stats=`get_stats` sqlgen_stats=`LD_PRELOAD=$GLB_PRELOAD \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD \ --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 300 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --ac-frac 100 --create 0 --tables 1 --rows 1000 \ --updates 100 --inserts 0 --selects 0 \ --users $(($ii * $USERS_PER_NODE)) | tail -n 1` echo "$sqlgen_stats" sqlgen_stats=`echo $sqlgen_stats | awk '{print $4;}'` post_stats=`get_stats` echo "$ii $sqlgen_stats $(($post_stats - $pre_stats)) $((($post_stats - $pre_stats)/$sqlgen_stats))" >> $out fi $TEST_BASE/scripts/command.sh stop ) done } test_run 0 test_run 1 percona-galera-3-3.8-3390/tests/test_sqlgen/000077500000000000000000000000001244131713600204745ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_sqlgen/run.sh000066400000000000000000000016161244131713600216400ustar00rootroot00000000000000#!/bin/sh -eu BASE_DIR=$(cd $(dirname $0); pwd -P) REPORT_DIR="$TEST_REPORT_DIR/sqlgen" if ! test -d $REPORT_DIR then mkdir $REPORT_DIR if test $? != 0 then echo "Failed to create report directory" exit 1 fi fi SQLGEN_LOG=$REPORT_DIR/sqlgen.log echo "Running sqlgen test, args: $@" >> $SQLGEN_LOG . $TEST_BASE_DIR/tap/tap-functions plan_tests 1 if test $CLUSTER_N_NODES -lt 1 then skip "ok" "No nodes available, skipping test" elif ! test -x $BASE_DIR/sqlgen then skip "ok" "sqlgen binary not found, skipping test" else echo "Starting load" >> $SQLGEN_LOG args="" for ii in $CLUSTER_NODES do args="$args --host $ii" done args="$args --port $MYSQL_PORT $@" LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $BASE_DIR/sqlgen $args >> $SQLGEN_LOG 2>&1 ok $? "sqlgen" fi percona-galera-3-3.8-3390/tests/test_startstop/000077500000000000000000000000001244131713600212465ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_startstop/run.sh000077500000000000000000000007221244131713600224120ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/signal.sh . $SCRIPTS/misc.sh TRIES=${1:-"-1"} # -1 stands for indefinite loop stop try=0 while [ $try -ne $TRIES ] do ! let try++ # ! - to protect from -e echo -e "\nTry ${try}/${TRIES}\n" start pause 5 stop done percona-galera-3-3.8-3390/tests/test_stopcont/000077500000000000000000000000001244131713600210545ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_stopcont/README000066400000000000000000000007131244131713600217350ustar00rootroot00000000000000The test runs sqlgen load against the cluster and in round robin order makes nodes stop and continue. After each transition consistency check is done. This facilitates testing crawling nodes. Usage with gcomm backend: ./run.sh [N] Usage with vsbes backend: GCS_TYPE=vsbes VSBES_ADDRESS=192.168.0.1:5678 ./run.sh [N] where N is the number of stop/cont transitions. I.e. N=1 means that 1 node will be killed and restarted. If N is omitted it goes forever. percona-galera-3-3.8-3390/tests/test_stopcont/run.sh000077500000000000000000000034271244131713600222250ustar00rootroot00000000000000#!/bin/bash -eu declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/signal.sh . $SCRIPTS/misc.sh TRIES=${1:-"-1"} # -1 stands for indefinite loop MIN_PAUSE=${2:-"3"} PAUSE_RND=${3:-"20"} #restart # cluster restart should be triggered by user # Start load SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 999999999 \ --stat-interval 99999999 >/dev/null 2>$BASE_RUN/seesaw.err & declare -r sqlgen_pid=$! disown # forget about the job, disable waiting for it term=0 terminate() { echo "Terminating" term=1 } trap terminate SIGINT SIGTERM SIGHUP SIGPIPE trap "kill $sqlgen_pid || :" EXIT pause 10 10 consistency_check $sqlgen_pid # kills a node and restarts it after a while cycle() { local -r node=$1 local -r node_id=${NODE_ID[$node]} echo "Signaling node $node_id with STOP... " signal_node STOP $node pause $MIN_PAUSE $PAUSE_RND echo "Signaling node $node_id with CONT..." signal_node CONT $node sleep 10 # this pause needed to get node to notice that it lost the PC # if it did... wait_node_state $node 4 # 4 - SYNCED } node=0 node_num=$(( $NODE_MAX + 1 )) try=0 echo "### Looping over $node_num nodes ###" while [ $try -ne $TRIES ] do ! let try++ # ! - to protect from -e echo -e "\nTry ${try}/${TRIES}\n" cycle $node consistency_check $sqlgen_pid pause 2 node=$(( ( node + 1 ) % node_num )) done kill $sqlgen_pid check exit percona-galera-3-3.8-3390/tests/test_upgrade/000077500000000000000000000000001244131713600206325ustar00rootroot00000000000000percona-galera-3-3.8-3390/tests/test_upgrade/README000066400000000000000000000004061244131713600215120ustar00rootroot00000000000000The test - installs demo package pointed to by OLD, - starts sqlgen load, - checks consistency, - upgrades the nodes one by one to distribution pointed to by NEW, - checks consistency Usage: OLD=.tgz NEW=.tgz ./run.sh Usage with vsbes backend: percona-galera-3-3.8-3390/tests/test_upgrade/run.sh000077500000000000000000000034431244131713600220010ustar00rootroot00000000000000#!/bin/bash -eu if [ $# -ne 2 ] then echo "Usage: $0 .tgz .tgz" >&2 exit 1 else OLD=$1 NEW=$2 echo "Upgrading $OLD to $NEW" fi declare -r DIST_BASE=$(cd $(dirname $0)/..; pwd -P) TEST_BASE=${TEST_BASE:-"$DIST_BASE"} . $TEST_BASE/conf/main.conf declare -r SCRIPTS="$DIST_BASE/scripts" . $SCRIPTS/jobs.sh . $SCRIPTS/action.sh . $SCRIPTS/kill.sh . $SCRIPTS/remove.sh . $SCRIPTS/install.sh . $SCRIPTS/misc.sh # Remove previous install kill_all remove # Install old version install $OLD start # Start load SQLGEN=${SQLGEN:-"$DIST_BASE/bin/sqlgen"} LD_PRELOAD=$GLB_PRELOAD \ DYLD_INSERT_LIBRARIES=$GLB_PRELOAD \ DYLD_FORCE_FLAT_NAMESPACE=1 \ $SQLGEN --user $DBMS_TEST_USER --pswd $DBMS_TEST_PSWD --host $DBMS_HOST \ --port $DBMS_PORT --users $DBMS_CLIENTS --duration 999999999 \ --stat-interval 99999999 --sess-min 999999 --sess-max 999999 \ --rollbacks 0.1 --ac-frac 20 --long-keys \ >/dev/null 2>$BASE_RUN/seesaw.err & declare -r sqlgen_pid=$! disown # forget about the job, disable waiting for it term=0 terminate() { echo "Terminating" term=1 } trap terminate SIGINT SIGTERM SIGHUP SIGPIPE trap "kill $sqlgen_pid" EXIT pause 5 1 consistency_check $sqlgen_pid # Stops a node, installs new version and restarts upgrade() { local -r node=$1 local -r node_id=${NODE_ID[$node]} echo "Upgrading node $node_id..." stop_node $node install_node $NEW $node echo "Restarting node $node_id..." # if test $pause_var -gt 3 # then start_node "-g $(gcs_address $node)" $node # else # stop_node $node || : # just in case the process is still lingering # start_node "-g $(gcs_address $node)" $node # fi } for node in $NODE_LIST do upgrade $node pause done consistency_check $sqlgen_pid exit percona-galera-3-3.8-3390/www.evanjones.ca/000077500000000000000000000000001244131713600201775ustar00rootroot00000000000000percona-galera-3-3.8-3390/www.evanjones.ca/AUTHORS000066400000000000000000000001201244131713600212400ustar00rootroot00000000000000This code was taken almost verbatim from http://www.evanjones.ca/crc32c.tar.bz2 percona-galera-3-3.8-3390/www.evanjones.ca/LICENSE000066400000000000000000000035561244131713600212150ustar00rootroot00000000000000Copyright (c) 2008,2009,2010 Massachusetts Institute of Technology. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Massachusetts Institute of Technology nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Other portions are under the same license from Intel: http://sourceforge.net/projects/slicing-by-8/ /*++ * * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved * * This software program is licensed subject to the BSD License, * available at http://www.opensource.org/licenses/bsd-license.html * * Abstract: The main routine * --*/ percona-galera-3-3.8-3390/www.evanjones.ca/crc32c.c000066400000000000000000001173341244131713600214330ustar00rootroot00000000000000// Copyright 2008,2009,2010 Massachusetts Institute of Technology. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. // Implementations adapted from Intel's Slicing By 8 Sourceforge Project // http://sourceforge.net/projects/slicing-by-8/ /* * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved * * * This software program is licensed subject to the BSD License, * available at http://www.opensource.org/licenses/bsd-license.html. * * Abstract: * * Tables for software CRC generation */ /* * Copyright (c) 2013-2014 Codership Oy * Concatenated crc32ctables.cc and crc32c.cc, stripped off C++ garbage, * fixed PIC, added support for big-endian CPUs. */ #if defined(__cplusplus) extern "C" { #endif #include "crc32c.h" #include /* Tables generated with code like the following: #define CRCPOLY 0x82f63b78 // reversed 0x1EDC6F41 #define CRCINIT 0xFFFFFFFF void init() { for (uint32_t i = 0; i <= 0xFF; i++) { uint32_t x = i; for (uint32_t j = 0; j < 8; j++) x = (x>>1) ^ (CRCPOLY & (-(int32_t)(x & 1))); g_crc_slicing[0][i] = x; } for (uint32_t i = 0; i <= 0xFF; i++) { uint32_t c = g_crc_slicing[0][i]; for (uint32_t j = 1; j < 8; j++) { c = g_crc_slicing[0][c & 0xFF] ^ (c >> 8); g_crc_slicing[j][i] = c; } } } */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o32[256] = { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }; /* * end of the CRC lookup table crc_tableil8_o32 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o40[256] = { 0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 }; /* * end of the CRC lookup table crc_tableil8_o40 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o48[256] = { 0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 }; /* * end of the CRC lookup table crc_tableil8_o48 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o56[256] = { 0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 }; /* * end of the CRC lookup table crc_tableil8_o56 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o64[256] = { 0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 }; /* * end of the CRC lookup table crc_tableil8_o64 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o72[256] = { 0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C }; /* * end of the CRC lookup table crc_tableil8_o72 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o80[256] = { 0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F }; /* * end of the CRC lookup table crc_tableil8_o80 */ /* * The following CRC lookup table was generated automagically * using the following model parameters: * * Generator Polynomial = ................. 0x1EDC6F41 * Generator Polynomial Length = .......... 32 bits * Reflected Bits = ....................... TRUE * Table Generation Offset = .............. 32 bits * Number of Slices = ..................... 8 slices * Slice Lengths = ........................ 8 8 8 8 8 8 8 8 * Directory Name = ....................... .\ * File Name = ............................ 8x256_tables.c */ const uint32_t crc_tableil8_o88[256] = { 0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 }; /* * end of the CRC lookup table crc_tableil8_o88 */ // Implementations adapted from Intel's Slicing By 8 Sourceforge Project // http://sourceforge.net/projects/slicing-by-8/ /*++ * * Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved * * This software program is licensed subject to the BSD License, * available at http://www.opensource.org/licenses/bsd-license.html * * Abstract: The main routine * --*/ /* * Traditional software CRC32 implementation: one byte at a time */ uint32_t crc32cSarwate(uint32_t crc, const void* data, size_t length) { const char* p_buf = (const char*) data; const char* p_end = p_buf + length; while (p_buf < p_end) { crc = crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); } return crc; } /* * Optimized CRC32 implementations that follow process input in slices * of 4 byte integers and require byteswapping on big-endian platforms, * so here we define byteswapping macro/function. * GCC normally defines __BYTE_ORDER__ so we use that if available. */ #if defined(WITH_GALERA) # include "galerautils/src/gu_byteswap.h" # define CRC32C_TO_LE32 gu_le32 #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # define CRC32C_TO_LE32(val) val #else # if defined(HAVE_BYTESWAP_H) # include # endif static inline uint32_t CRC32C_TO_LE32(uint32_t const val) { #if !defined(__BYTE_ORDER__) /* determine endianness in runtime and return if LE */ static union { uint32_t n; uint8_t little_endian; } const u = { 1 }; if (u.little_endian) return val; #elif (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # error "Broken macro logic!" #endif /* __BYTE_ORDER__ */ #if defined(bswap32) return bswap32(val); #elif defined(bswap_32) return bswap_32(val); #elif defined(BSWAP_32) return BSWAP_32(val); #else return ((val << 24) | ((val & 0x0000FF00) << 8) | (val >> 24) | ((val & 0x00FF0000) >> 8)); #endif /* bswap32 */ } #endif /* WITH_GALERA */ uint32_t crc32cSlicingBy4(uint32_t crc, const void* data, size_t length) { const char* p_buf = (const char*) data; // Handle leading misaligned bytes size_t initial_bytes = (sizeof(int32_t) - (intptr_t)p_buf) & (sizeof(int32_t) - 1); if (length < initial_bytes) initial_bytes = length; for (size_t li = 0; li < initial_bytes; li++) { crc = crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); } length -= initial_bytes; size_t running_length = length & ~(sizeof(int32_t) - 1); size_t end_bytes = length - running_length; for (size_t li = 0; li < running_length/4; li++) { crc ^= CRC32C_TO_LE32(*(const uint32_t*)p_buf); p_buf += 4; uint32_t term1 = crc_tableil8_o56[crc & 0x000000FF] ^ crc_tableil8_o48[(crc >> 8) & 0x000000FF]; uint32_t term2 = crc >> 16; crc = term1 ^ crc_tableil8_o40[term2 & 0x000000FF] ^ crc_tableil8_o32[(term2 >> 8) & 0x000000FF]; } for (size_t li=0; li < end_bytes; li++) { crc = crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); } return crc; } uint32_t crc32cSlicingBy8(uint32_t crc, const void* data, size_t length) { const char* p_buf = (const char*) data; // Handle leading misaligned bytes size_t initial_bytes = (sizeof(int32_t) - (intptr_t)p_buf) & (sizeof(int32_t) - 1); if (length < initial_bytes) initial_bytes = length; for (size_t li = 0; li < initial_bytes; li++) { crc = crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); } length -= initial_bytes; size_t running_length = length & ~(sizeof(uint64_t) - 1); size_t end_bytes = length - running_length; for (size_t li = 0; li < running_length/8; li++) { const uint32_t* const slices = (const uint32_t*)p_buf; crc ^= CRC32C_TO_LE32(slices[0]); uint32_t term1 = crc_tableil8_o88[crc & 0x000000FF] ^ crc_tableil8_o80[(crc >> 8) & 0x000000FF]; uint32_t term2 = crc >> 16; crc = term1 ^ crc_tableil8_o72[term2 & 0x000000FF] ^ crc_tableil8_o64[(term2 >> 8) & 0x000000FF]; uint32_t const slice2 = CRC32C_TO_LE32(slices[1]); term1 = crc_tableil8_o56[slice2 & 0x000000FF] ^ crc_tableil8_o48[(slice2 >> 8) & 0x000000FF]; term2 = slice2 >> 16; crc = crc ^ term1 ^ crc_tableil8_o40[term2 & 0x000000FF] ^ crc_tableil8_o32[(term2 >> 8) & 0x000000FF]; p_buf += 8; } for (size_t li=0; li < end_bytes; li++) { crc = crc_tableil8_o32[(crc ^ *p_buf++) & 0x000000FF] ^ (crc >> 8); } return crc; } #if !defined(CRC32C_NO_HARDWARE) static uint32_t cpuid(uint32_t functionInput) { uint32_t eax; uint32_t ebx; uint32_t ecx; uint32_t edx; /* The code below adapted from http://en.wikipedia.org/wiki/CPUID * and seems to work for both PIC and non-PIC cases */ __asm__ __volatile__( #if defined(CRC32C_x86_64) "pushq %%rbx \n\t" /* save %rbx */ #else /* 32-bit */ "pushl %%ebx \n\t" /* save %ebx */ #endif "cpuid \n\t" "movl %%ebx, %[ebx] \n\t" /* copy %ebx contents into output var */ #if defined(CRC32C_x86_64) "popq %%rbx \n\t" /* restore %rbx */ #else /* 32-bit */ "popl %%ebx \n\t" /* restore %ebx */ #endif : "=a"(eax), [ebx] "=r"(ebx), "=c"(ecx), "=d"(edx) : "a"(functionInput) ); return ecx; } CRC32CFunctionPtr detectBestCRC32C() { static const int SSE42_BIT = 20; uint32_t ecx = cpuid(1); bool hasSSE42 = ecx & (1 << SSE42_BIT); if (hasSSE42) { #if defined(CRC32C_x86_64) return crc32cHardware64; #else return crc32cHardware32; #endif } else { return crc32cSlicingBy8; } } #include // Hardware-accelerated CRC-32C (using CRC32 instruction) uint32_t crc32cHardware32(uint32_t crc, const void* data, size_t length) { const char* p_buf = (const char*) data; // alignment doesn't seem to help? for (size_t i = 0; i < length / sizeof(uint32_t); i++) { crc = __builtin_ia32_crc32si(crc, *(uint32_t*) p_buf); p_buf += sizeof(uint32_t); } // This ugly switch is slightly faster for short strings than the straightforward loop length &= sizeof(uint32_t) - 1; /* while (length > 0) { crc32bit = __builtin_ia32_crc32qi(crc32bit, *p_buf++); length--; } */ switch (length) { case 3: crc = __builtin_ia32_crc32qi(crc, *p_buf++); case 2: crc = __builtin_ia32_crc32hi(crc, *(uint16_t*) p_buf); break; case 1: crc = __builtin_ia32_crc32qi(crc, *p_buf); break; case 0: break; default: // This should never happen; enable in debug code assert(false); } return crc; } // Hardware-accelerated CRC-32C (using CRC64 instruction) uint32_t crc32cHardware64(uint32_t crc, const void* data, size_t length) { #ifndef __LP64__ return crc32cHardware32(crc, data, length); #else const char* p_buf = (const char*) data; // alignment doesn't seem to help? uint64_t crc64bit = crc; for (size_t i = 0; i < length / sizeof(uint64_t); i++) { crc64bit = __builtin_ia32_crc32di(crc64bit, *(uint64_t*) p_buf); p_buf += sizeof(uint64_t); } // This ugly switch is slightly faster for short strings than the straightforward loop uint32_t crc32bit = (uint32_t) crc64bit; length &= sizeof(uint64_t) - 1; /* while (length > 0) { crc32bit = __builtin_ia32_crc32qi(crc32bit, *p_buf++); length--; } */ switch (length) { case 7: crc32bit = __builtin_ia32_crc32qi(crc32bit, *p_buf++); case 6: crc32bit = __builtin_ia32_crc32hi(crc32bit, *(uint16_t*) p_buf); p_buf += 2; // case 5 is below: 4 + 1 case 4: crc32bit = __builtin_ia32_crc32si(crc32bit, *(uint32_t*) p_buf); break; case 3: crc32bit = __builtin_ia32_crc32qi(crc32bit, *p_buf++); case 2: crc32bit = __builtin_ia32_crc32hi(crc32bit, *(uint16_t*) p_buf); break; case 5: crc32bit = __builtin_ia32_crc32si(crc32bit, *(uint32_t*) p_buf); p_buf += 4; case 1: crc32bit = __builtin_ia32_crc32qi(crc32bit, *p_buf); break; case 0: break; default: // This should never happen; enable in debug code assert(false); } return crc32bit; #endif /* __LP64__ */ } #else /* no CRC32C HW acceleration */ CRC32CFunctionPtr detectBestCRC32C() { /* this actually requires some benchmarking... */ return crc32cSlicingBy8; } #endif /* CRC32C_NO_HARDWARE */ static uint32_t crc32c_CPUDetection(uint32_t crc, const void* data, size_t length) { // Avoid issues that could potentially be caused by multiple threads: use a local variable CRC32CFunctionPtr best = detectBestCRC32C(); crc32c = best; return best(crc, data, length); } CRC32CFunctionPtr crc32c = crc32c_CPUDetection; #if defined(__cplusplus) } #endif percona-galera-3-3.8-3390/www.evanjones.ca/crc32c.h000066400000000000000000000033601244131713600214310ustar00rootroot00000000000000// Copyright 2008,2009,2010 Massachusetts Institute of Technology. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. /* Codership: stripped off C++ garbage to make this a normal C header */ #ifndef __CRC32C_H__ #define __CRC32C_H__ #include // size_t #include // uint stuff /** Returns the initial value for a CRC32-C computation. */ static inline uint32_t crc32cInit() { return 0xFFFFFFFF; } /** Pointer to a function that computes a CRC32C checksum. @arg crc Previous CRC32C value, or crc32c_init(). @arg data Pointer to the data to be checksummed. @arg length length of the data in bytes. */ typedef uint32_t (*CRC32CFunctionPtr)(uint32_t crc, const void* data, size_t length); /** This will map automatically to the "best" CRC implementation. */ extern CRC32CFunctionPtr crc32c; CRC32CFunctionPtr detectBestCRC32C(); /** Converts a partial CRC32-C computation to the final value. */ static inline uint32_t crc32cFinish(uint32_t crc) { return ~crc; } uint32_t crc32cSarwate (uint32_t crc, const void* data, size_t length); uint32_t crc32cSlicingBy4(uint32_t crc, const void* data, size_t length); uint32_t crc32cSlicingBy8(uint32_t crc, const void* data, size_t length); #if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) #define CRC32C_x86_64 #endif #if defined(CRC32C_x86_64) || defined(__i386) || defined(_M_X86) #define CRC32C_x86 #endif #if !defined(CRC32C_x86) #define CRC32C_NO_HARDWARE #endif #if !defined(CRC32C_NO_HARDWARE) uint32_t crc32cHardware32(uint32_t crc, const void* data, size_t length); uint32_t crc32cHardware64(uint32_t crc, const void* data, size_t length); #endif /* !CRC32C_NO_HARDWARE */ #endif /* __CRC32C_H__ */