From: Tor Didriksen Date: May 13 2011 9:39am Subject: bzr commit into mysql-trunk branch (tor.didriksen:3081) Bug#11788245 List-Archive: http://lists.mysql.com/commits/137300 X-Bug: 11788245 Message-Id: <20110513093943.3E76C3793@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7582804661255354611==" --===============7582804661255354611== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/trunk-test-utils/ based on revid:bjorn.munch@stripped 3081 Tor Didriksen 2011-05-13 Bug #11788245 - 60110 DO MORE THD AND GLOBAL INITIALIZATION FOR UNIT TESTING Move server/THD initialization to separate utility classes in namespace my_testing. Add new test as an example of how to use the utility classes. @ unittest/gunit/CMakeLists.txt Add test_utils.cc @ unittest/gunit/item-t.cc Use new utility classes. @ unittest/gunit/opt_range-t.cc Another example of using the utility classes. @ unittest/gunit/test_utils.cc Code moved from Item test, into new utility classes. @ unittest/gunit/test_utils.h Code moved from Item test, into new utility classes. added: unittest/gunit/opt_range-t.cc unittest/gunit/test_utils.cc unittest/gunit/test_utils.h modified: unittest/gunit/CMakeLists.txt unittest/gunit/item-t.cc === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-04-13 11:31:44 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-05-13 09:36:13 +0000 @@ -219,6 +219,7 @@ SET(TESTS # Add tests (link them with gunit library and the server libraries) SET(SERVER_TESTS item + opt_range ) FOREACH(test ${TESTS}) @@ -232,9 +233,9 @@ ENDFOREACH() FOREACH(test ${SERVER_TESTS}) IF(WIN32) - ADD_EXECUTABLE(${test}-t ${test}-t.cc ../../sql/nt_servc.cc) + ADD_EXECUTABLE(${test}-t ${test}-t.cc test_utils.cc ../../sql/nt_servc.cc) ELSE() - ADD_EXECUTABLE(${test}-t ${test}-t.cc) + ADD_EXECUTABLE(${test}-t ${test}-t.cc test_utils.cc) ENDIF() TARGET_LINK_LIBRARIES(${test}-t sql binlog rpl master slave sql) TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex mysys) === modified file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 2011-03-18 12:25:56 +0000 +++ b/unittest/gunit/item-t.cc 2011-05-13 09:36:13 +0000 @@ -18,112 +18,42 @@ #include "my_config.h" #include +#include "test_utils.h" + #include "item.h" #include "sql_class.h" -#include "rpl_handler.h" // delegates_init() namespace { -/* - A mock error handler for error_handler_hook. -*/ -uint expected_error= 0; -extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags) -{ - EXPECT_EQ(expected_error, err) << str; -} - - -/** - A mock error handler which registers itself with the THD in the CTOR, - and unregisters in the DTOR. The function handle_condition() will - verify that it is called with the expected error number. - The DTOR will verify that handle_condition() has actually been called. -*/ -class Mock_error_handler : public Internal_error_handler -{ -public: - Mock_error_handler(THD *thd, uint expected_error) - : m_thd(thd), - m_expected_error(expected_error), - m_handle_called(0) - { - thd->push_internal_handler(this); - } - - virtual ~Mock_error_handler() - { - // Strange Visual Studio bug: have to store 'this' in local variable. - Internal_error_handler *me= this; - EXPECT_EQ(me, m_thd->pop_internal_handler()); - EXPECT_GE(m_handle_called, 0); - } - - virtual bool handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) - { - EXPECT_EQ(sql_errno, m_expected_error); - ++m_handle_called; - return true; - } -private: - THD *m_thd; - uint m_expected_error; - int m_handle_called; -}; - +using my_testing::Server_initializer; +using my_testing::Mock_error_handler; class ItemTest : public ::testing::Test { protected: - /* - This is the part of the server global things which have to be initialized - for this (very simple) unit test. Presumably the list will grow once - we start writing tests for more advanced classes. - TODO: Move to a common library. - */ static void SetUpTestCase() { - static char *my_name= strdup(my_progname); - char *argv[] = { my_name, 0 }; - set_remaining_args(1, argv); - init_common_variables(); - my_init_signals(); - randominit(&sql_rand, 0, 0); - xid_cache_init(); - delegates_init(); - error_handler_hook= test_error_handler_hook; + Server_initializer::SetUpTestCase(); } static void TearDownTestCase() { - delegates_destroy(); - xid_cache_free(); + Server_initializer::TearDownTestCase(); } - ItemTest() : m_thd(NULL) {} - virtual void SetUp() { - expected_error= 0; - m_thd= new THD(false); - THD *stack_thd= m_thd; - m_thd->thread_stack= (char*) &stack_thd; - m_thd->store_globals(); - lex_start(m_thd); + initializer.SetUp(); } virtual void TearDown() { - m_thd->cleanup_after_query(); - delete m_thd; + initializer.TearDown(); } - THD *m_thd; + THD *thd() { return initializer.thd(); } + + Server_initializer initializer; }; @@ -239,7 +169,7 @@ TEST_F(ItemTest, ItemFuncDesDecrypt) Item_func_des_decrypt *item_decrypt= new Item_func_des_decrypt(item_two, item_one); - EXPECT_FALSE(item_decrypt->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_decrypt->fix_fields(thd(), NULL)); EXPECT_EQ(length, item_one->max_length); EXPECT_EQ(length, item_two->max_length); EXPECT_LE(item_decrypt->max_length, length); @@ -256,9 +186,9 @@ TEST_F(ItemTest, ItemFuncIntDivOverflow) Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); - Mock_error_handler error_handler(m_thd, ER_TRUNCATED_WRONG_VALUE); - EXPECT_FALSE(quotient->fix_fields(m_thd, NULL)); - expected_error= ER_DATA_OUT_OF_RANGE; + Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); + EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); + initializer.set_expected_error(ER_DATA_OUT_OF_RANGE); quotient->val_int(); } @@ -272,8 +202,8 @@ TEST_F(ItemTest, ItemFuncIntDivUnderflow Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); - Mock_error_handler error_handler(m_thd, ER_TRUNCATED_WRONG_VALUE); - EXPECT_FALSE(quotient->fix_fields(m_thd, NULL)); + Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); + EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); EXPECT_EQ(0, quotient->val_int()); } @@ -291,8 +221,8 @@ TEST_F(ItemTest, ItemFuncSetUserVar) LEX_STRING var_name= { C_STRING_WITH_LEN("a") }; Item_func_set_user_var *user_var= new Item_func_set_user_var(var_name, item_str); - EXPECT_FALSE(user_var->set_entry(m_thd, true)); - EXPECT_FALSE(user_var->fix_fields(m_thd, NULL)); + EXPECT_FALSE(user_var->set_entry(thd(), true)); + EXPECT_FALSE(user_var->fix_fields(thd(), NULL)); EXPECT_EQ(val1, user_var->val_int()); my_decimal decimal; @@ -323,7 +253,7 @@ TEST_F(ItemTest, OutOfMemory) EXPECT_EQ(null_item, item); DBUG_SET("+d,simulate_out_of_memory"); - item= new (m_thd->mem_root) Item_int(42); + item= new (thd()->mem_root) Item_int(42); EXPECT_EQ(null_item, item); #endif } @@ -337,7 +267,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor= new Item_func_xor(item_zero, item_one_a); - EXPECT_FALSE(item_xor->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor->fix_fields(thd(), NULL)); EXPECT_EQ(1, item_xor->val_int()); EXPECT_EQ(1U, item_xor->decimal_precision()); @@ -346,7 +276,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor_same= new Item_func_xor(item_one_a, item_one_b); - EXPECT_FALSE(item_xor_same->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor_same->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_same->val_int()); EXPECT_FALSE(item_xor_same->val_bool()); EXPECT_FALSE(item_xor_same->is_null()); @@ -355,8 +285,8 @@ TEST_F(ItemTest, ItemFuncXor) item_xor->print(&print_buffer, QT_ORDINARY); EXPECT_STREQ("(0 xor 1)", print_buffer.c_ptr_safe()); - Item *neg_xor= item_xor->neg_transformer(m_thd); - EXPECT_FALSE(neg_xor->fix_fields(m_thd, NULL)); + Item *neg_xor= item_xor->neg_transformer(thd()); + EXPECT_FALSE(neg_xor->fix_fields(thd(), NULL)); EXPECT_EQ(0, neg_xor->val_int()); EXPECT_DOUBLE_EQ(0.0, neg_xor->val_real()); EXPECT_FALSE(neg_xor->val_bool()); @@ -368,7 +298,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor_null= new Item_func_xor(item_zero, new Item_null()); - EXPECT_FALSE(item_xor_null->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor_null->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_null->val_int()); EXPECT_TRUE(item_xor_null->is_null()); === added file 'unittest/gunit/opt_range-t.cc' --- a/unittest/gunit/opt_range-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/opt_range-t.cc 2011-05-13 09:36:13 +0000 @@ -0,0 +1,150 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. 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. + + 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 */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include "test_utils.h" + +#include "opt_range.cc" + +namespace { + +using my_testing::Server_initializer; + +class SelArgTest : public ::testing::Test +{ +protected: + static void SetUpTestCase() + { + Server_initializer::SetUpTestCase(); + } + + static void TearDownTestCase() + { + Server_initializer::TearDownTestCase(); + } + + SelArgTest() + { + memset(&m_opt_param, 0, sizeof(m_opt_param)); + } + + virtual void SetUp() + { + initializer.SetUp(); + m_opt_param.thd= thd(); + m_opt_param.mem_root= &m_alloc; + init_sql_alloc(&m_alloc, thd()->variables.range_alloc_block_size, 0); + } + + virtual void TearDown() + { + initializer.TearDown(); + free_root(&m_alloc, MYF(0)); + } + + THD *thd() { return initializer.thd(); } + + Server_initializer initializer; + MEM_ROOT m_alloc; + RANGE_OPT_PARAM m_opt_param; +}; + +/* + Experiment with these to measure performance of + 'new (thd->mem_root)' Foo vs. 'new Foo'. + With gcc 4.4.2 I see ~4% difference (in optimized mode). +*/ +const int num_iterations= 10; +const int num_allocs= 10; + +TEST_F(SelArgTest, AllocateExplicit) +{ + for (int ix= 0; ix < num_iterations; ++ix) + { + free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC)); + for (int ii= 0; ii < num_allocs; ++ii) + new (thd()->mem_root) SEL_ARG; + } +} + +TEST_F(SelArgTest, AllocateImplicit) +{ + for (int ix= 0; ix < num_iterations; ++ix) + { + free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC)); + for (int ii= 0; ii < num_allocs; ++ii) + new SEL_ARG; + } +} + +/* + We cannot do EXPECT_NE(NULL, get_mm_tree(...)) + because of limits in google test. + */ +const SEL_TREE *null_tree= NULL; + + +class Mock_field_long : public Field_long +{ +public: + Mock_field_long() + : Field_long(0, // ptr_arg + 8, // len_arg + NULL, // null_ptr_arg + 0, // null_bit_arg + Field::NONE, // unireg_check_arg + "field_name", // field_name_arg + false, // zero_arg + false) // unsigned_arg + { + m_table_name= "mock_table"; + memset(&m_share, 0, sizeof(m_share)); + const char *foo= "mock_db"; + m_share.db.str= const_cast(foo); + m_share.db.length= strlen(m_share.db.str); + + memset(&m_table, 0, sizeof(m_table)); + m_table.s= &m_share; + this->table_name= &m_table_name; + this->table= &m_table; + } + const char *m_table_name; + TABLE_SHARE m_share; + TABLE m_table; +}; + + +TEST_F(SelArgTest, SimpleCond) +{ + EXPECT_NE(null_tree, get_mm_tree(&m_opt_param, new Item_int(42))); +} + + +TEST_F(SelArgTest, EqualCond) +{ + Mock_field_long field_long; + EXPECT_EQ(null_tree, + get_mm_tree(&m_opt_param, + new Item_equal(new Item_int(42), + new Item_field(&field_long)))); +} + +} + + === added file 'unittest/gunit/test_utils.cc' --- a/unittest/gunit/test_utils.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/test_utils.cc 2011-05-13 09:36:13 +0000 @@ -0,0 +1,105 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. 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. + + 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 */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include "test_utils.h" +#include "rpl_handler.h" // delegates_init() + +namespace my_testing { + +/* + A mock error handler for error_handler_hook. +*/ +uint expected_error= 0; +extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags) +{ + EXPECT_EQ(expected_error, err) << str; +} + +void Server_initializer::set_expected_error(uint val) +{ + expected_error= val; +} + +void Server_initializer::SetUpTestCase() +{ + static char *my_name= strdup(my_progname); + char *argv[] = { my_name, 0 }; + set_remaining_args(1, argv); + init_common_variables(); + my_init_signals(); + randominit(&sql_rand, 0, 0); + xid_cache_init(); + delegates_init(); + error_handler_hook= test_error_handler_hook; +} + +void Server_initializer::TearDownTestCase() +{ + delegates_destroy(); + xid_cache_free(); +} + +void Server_initializer::SetUp() +{ + expected_error= 0; + m_thd= new THD(false); + THD *stack_thd= m_thd; + m_thd->thread_stack= (char*) &stack_thd; + m_thd->store_globals(); + lex_start(m_thd); +} + +void Server_initializer::TearDown() +{ + m_thd->cleanup_after_query(); + delete m_thd; +} + + +Mock_error_handler::Mock_error_handler(THD *thd, uint expected_error) + : m_thd(thd), + m_expected_error(expected_error), + m_handle_called(0) +{ + thd->push_internal_handler(this); +} + +Mock_error_handler::~Mock_error_handler() +{ + // Strange Visual Studio bug: have to store 'this' in local variable. + Internal_error_handler *me= this; + EXPECT_EQ(me, m_thd->pop_internal_handler()); + EXPECT_GE(m_handle_called, 0); +} + +bool Mock_error_handler::handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) +{ + EXPECT_EQ(m_expected_error, sql_errno); + ++m_handle_called; + return true; +} + + +} // namespace my_testing === added file 'unittest/gunit/test_utils.h' --- a/unittest/gunit/test_utils.h 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/test_utils.h 2011-05-13 09:36:13 +0000 @@ -0,0 +1,75 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. 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. + + 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 */ + + +#ifndef TEST_UTILS_INCLUDED +#define TEST_UTILS_INCLUDED + +#include "sql_error.h" +#include "sql_class.h" + +namespace my_testing { + +/* + A class which wraps the necessary setup/teardown logic for + unit tests which depend on a working THD environment. + */ +class Server_initializer +{ +public: + Server_initializer() : m_thd(NULL) {} + + // Invoke these from corresponding functions in test fixture classes. + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + // Sets expected error for error_handler_hook. + static void set_expected_error(uint val); + + THD *thd() const { return m_thd; } +private: + THD *m_thd; +}; + +/** + A mock error handler which registers itself with the THD in the CTOR, + and unregisters in the DTOR. The function handle_condition() will + verify that it is called with the expected error number. + The DTOR will verify that handle_condition() has actually been called. +*/ +class Mock_error_handler : public Internal_error_handler +{ +public: + Mock_error_handler(THD *thd, uint expected_error); + virtual ~Mock_error_handler(); + + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); +private: + THD *m_thd; + uint m_expected_error; + int m_handle_called; +}; + + +} // namespace my_testing + +#endif // TEST_UTILS_INCLUDED --===============7582804661255354611== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # uvazltd2qb22rrrv # target_branch: file:///export/home/didrik/repo/trunk-test-utils/ # testament_sha1: 2048c24a894603efd48e4c177535475bb5b55a4b # timestamp: 2011-05-13 11:39:43 +0200 # base_revision_id: bjorn.munch@stripped\ # 7ddtbc95ctu22ori # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWVldDjMACkX/gFjThyRf//// f+//+r////tgFv174+z333vt87eHT3fPve5vu0+9zy69Cn0F9dvMX2k7d2+9dzebtZR2NHrXoY6x Wyvu+3tXvkpy+npTdjazyDhJIgCTaYRpNNU9k0wVPT001QPU/VNA0DI2k9J7VAaNPU0eoCSQAjQB JolPKeCniho0zIgNAPUxNAAA9Rpk0GIIKIPVMnlNGRhGQAAAaAAAAAAAJNSJMQmmpPTJNlHhTEPU MR6geo00NAAAAABoEUQgRoE0aKbaCaT1J7QTU2hNNNBpkNNNBpoADRpoJEhABAIxNBTMJEbU9HqI 8kNNpD1PUAANAHpG44bvWTJIAzw8ac/VSnkgVTFFPq0YdHcPCaMSUkikh64nPG8WyZEIQ/hQPSHt 6vYVLxbNzXOl1k7WXhZlcmsRmEETMR5yiSRaCxXesA/V59wy8+CElQPrF9V1C++4gmYAw1uV8pPR 40c7VEDHE3ZbPRXCYNXOGENRZdZOJx/qahFgtLgCoufGogeseTIJKA8drhayYZqvhEvkqxfRbABY 0NgHnrVQQwTAC7zNDlxxCURF85nmbnTrNaNm3qzSGXDmDRqra6E1o/Xw4RW5yiIWSA7VQGRT5IU/ F88gc50TpokqXjCgQsB2ZH4WjWFiRjEnDEJUnXlVIsYRibUAqIoC9nwHkQbxkMEAu4rL+5JSfwHg +ZPP1GayJLxjHfa97JcYUY/3ThcaHGYYQzMwBiAthVQvWAGvktkCxopcSjCoernWatHdO5Cbfhnx mg0zVjN0DfKyKNXHbFx22WzpxUKtuwqeqJX0vq1K7146K8XcxRXXlw0zHgR1l/1ZFOuTQudX0SdC pcUQEgl1M7NAuC/byenzny+XJ0obYGX6kOP7tbotlHgZB0WQyb24Ppl/7R92ZPu7ywHmh9t4uTih hnn3UdMRD/pDboxGcXMjVmc+AeVszm4gNo02EDgjT5HAvrI2OzoAOUqmiYpc5ZitQ/C571KpJfBS QynIyMM8LI0kXFx4u9SnKou8x72C+TVT8uLt/+jeILTIrmD7QIs3gvBEOYkyCtxVYEC2bjsMjJXb ric2Xn8pZeP7aLD1LP0MdGeonEGyLjoGY3UVk6CZN3SVsSJ12J54kX+XYdkxjeb9zjY742opnfJE /vQR2rH7iNy8coti/I2Uz9xuw2kulgh4Pg0y26vI3mGxL8jJDTzMuVnJ6qu9tiPQ/03rpLPyroop tDtJCpz2E19XbwD7x8g7DURmSWU7vVi6eu5ByQFz1Xep2jSC2APowbPexhmqO0dlRZO1MrLuYt6k wh6yIha7sFq1Pleu/OqWxYru27FmTVkRXABXxEzPjGQzHVFZOrGRv8cTb96z/FIrssKJPmh/WrP0 Nf37u9JjWXUuT4WSgVYjEB6CR+wTNCooKinBx8tp3Dj3+DZShxUf52r9i971bGwMZAAMzw7KHnaW YaCIYyEvhelTeBONgMQgZgLf5931wFMIN5ybWhnHyPcrK4Glihk5R99iZxucn4yk5H4hr6HjngSI xIPJz+jFTwqICwa9MsfmfHtolf5RyW250ZateeJDaJM71tQx6qYoWYzkpbiYl52bUGTNbZazrTa+ pN7tyJlCuvDsIlqkh+CLF9eHZa3lGMYx9x60Pd3nz3cD2apdx1XaRWY7xi70lAPOzezyk6ak0yxZ wwPQRpMHm0PdTCZn3Eq1rNMC1XjFcoEEw+FeexX2FDJ7pZFGTgb3Df9qiPa4pbKSB3n9YaPZvRPQ SerrJZvdKR+DtJ6xkHU+hMOmvmTXA8r8kjlzmrUHmv1GtkYOBNDJAKiAgkEZjiBqQ/Rt4KVddBlJ o7gM0g7gLzFIent4PG4NCd3AhRTd6XANoc7ILi1PgZr/PgRj7Mfd2SWYFMnGyWedOdwrmLTpqsog 9zwd3KBfVKTIZe0wAWCCDZVXyKnvmRRUCwwCK6mpHsIJ8IuA/YiAgyKARC7MjE3KkJ1d6BgM3BAn OX4tOnRbXliBi76MsARvh3xgRpUhRxJ8RySbvDNvSuhlhAITB2Jusfwy0eFzGaGd9FiekfdUbeT6 zv0ouUk9BtyshBgbSWCMzNL+wUNPkqlu1IIsQ+pbnRPTnV1Kfm4qjNJCSF5FpWccmHZXslBkzWze 7pnFSvJPMIAUooJ4ASTnkiqmI3bLSquE1qdXD6VmJTnZBqZhgoqHyxlYjH5IOI8nl2Rfho56iOeN PWsoOara6QO0udb1A1XU3HGt1ASYSy5pmVHM6b5EopKUpKLoIAoquc/dguMS7CY97bgDhzsJEMNt sDTczGWVOMrD1irohlqwR0jp9Eus8t0LRgfOmuBrId9NQOkOlyz1FTsHQkE3sKonTZZCZqeBIztu leEeC3u4VN+BAZrE+dOR10a6x10sZu0xhWbixTEiJLIqu/qeAK4VZ18UFi5Pm8/DOQ9rK5hY52ob ElUiUj3WzLWwi8vRgRZB5JNjSwfUx50wrBYQSzm2iKjU0BKGJLFYOdRyhoR8yxJRWKn4b0+7I1Nn J16P4G6nJtHNDcMYzzikzqGRE4WXYUK5q+VIebxVqNDEpTwtI57U8mYz0qbu2NNKbxiHU4KGQ8Yu 9oujLm8FS0AKPciBhIendo5JcQsi3c82ffk1OFDAaZicbi9zh0jg1HBSllMw83pxRWubjyRmw4Bv UOJtjrS40QTiyqDhpZXigQe5F6S1M+JBgFVRMkNWzWgmQGWOWGV7BWhthh0+s9IJpqbGAqhvs4V4 A2lkYilJDkusoswa7MgRPrEh6S0o7tcCd5NOksQhWh2r2qpXFfQHsfxfAiBvwrnhBnmeY+coUmX6 G3nZWthq5tVyVgxhSqr1IOR1/Xh3u3uJIY6cY4A4LuXELtSxGzs8h5kHedUjHrTJy1Lvg8D2J69H nP8vZ9s6G6BVwZGYTMy/P8krJFJlhP1LEyfzRRgGFMdIi0wyqVFuSLmG7I/oqltKyO0RvlpILuQe dwwi0lJUMuAB7jBbynuK12YmkITD6dJirQJkgDPRBn6FRCklx9cB7WJXaCqCQhjQdi0YiB7BoTKJ M9oudNoVAURCUZi4EILEpwyqF4MG+xKFXWycDAIyB0FZU/59ZHOXYFn5jxz3w4hQ1w0GSw1E9ynM kUlZMWpBjaBwiJrp2LC3m4NIOcNbJx7Hb42/NiHtAL2harwIBgOoaJsYGLWubm1sTRJ1GF4czVwC G4lyau1DJ0NvUdYWJFSojaDF3jGPeN+wggbaFdeubmU5D0J8QaC4Gu91hrVa1WTXDpexSWCmFQMJ j1rTTuu0aFY+wT5O2KiNwL6YG/DVKCbS2hh3tjWz4CY0LLBBwEMX2B6kKvJ9H2azXeDgwDhK+sY5 XMLqzmuwyzES5ycwbPdD22XXtOPH44uvqt+eRMK6UiQd4XX+mkVKxA2DKJE1NjUL1AYFAzG6EghC 8hKjekBnjMZWVwdX3pbgLlkrJqQBnUklFKGEGeBaakKsoiek12JnuWuBpAZKYLqZqmIBkbl5gqcg ZQ9w1gr/oPj/IP9cNXHxFCJIf9EYjdDVflYBj4jqLlRHUW0BazXkFx7cCa+DgKwDC5Xe8NTQfqMm Hvp8Q3CNR0IV0v0XfQ4gEuqEDLPrMNDnhSIHpQCRKwG+pNU6YHEsJzAR/carDRHahT4Zr1SRlpWY eoRv2IWmWs0NrYuSHnReNVNkUoL2sopFLbcCC8fTdErYAZZv+Eu0m85Z5t+aNGgmM5GaTodcH4y1 Xh1avHaOKj5TFjRnsU9IlqEEHZ888cB4x9PsoUcjZeixcLBCQHNBrZJQ7Hq9DL7ZxOY1jVytXE1k ZwNjBwSs3nm72hHI4mnFDMGMxUqdUAm2DlGDXkF/0TFUJUPc0r0A4tCyppSAX1XIX0dvTsQh2WDA t9cj2+1uZIDnxNetgQ1HBr37kbCeRgJI8V9CZoFfMqTBQkkImQJCR6DPu6zqO4XQnaeBNsV8ZoDP QuBS8pTEhjaLUiGNCoTQaPCQuHDivIcp/gJLyI+w34fTxWXS1o7TWZoF3qG2LTK5q0CjuJQD3Ws+ reIbwI4uVQ9fbLk9bchTok62CzVhXJ1jppjVsYv55C1UqEoYhiZJSs2mLvOGCkobJ6l9hpWXhTUL T9uzighhsH83hKVR7/TSlVOhKrQNRDQipMWB0Vm2pbzOJzrOtzKjAn2naWaDPId2pyUodGaUNHw1 tE6ORtMqqAaLYERMCArXnx6yutVeoRfdVtK/MRC6Ld8jiWtC4qikQcJd/Q6yhFmJsxJlKOkyB+N6 ZHWbM6eHll5dcc+zYxpl6qzWhQRpWpHNxfDzwbBZpBiGGS3AtgmGW9SUlS3aZLTNAOzf3/Mg5FNg LDQWQ0XLwhL3zv6lyz214UZpGNwTUEML2uMghrCkbJwAqrGF5JbM4pCpw798CrgY7DciDJBGDG5F xUqq0b0l2RhgQKxSa16DWtImxbN5UNIVgSBCkIaoTmMmHMSQlirsNNq5BIJqAMRKUg0g/ibghXJH Vh4Bp9XKRJMRc1049JUPe41kOo0GEnPuraMyC5moS1LAG62lngYQ8Ua+dDRRFyzXgBLCw0eqfiNK s6DlIv6YWdahat6C1VzPlRkjIvAflYBgOYShExOxjFXOSLhNgSCF9cHZYLCweUodIQXWxI+6bi/m RJFZkvE5bGxOBJwjU5ElNsFkF61wiBiCqlVpckBAqVIDvgQiBe+4vuJvcLl8PW4jQDJMG9ozGQ+X qUeUPNY4UNrQGIR+4yMAzhCS/jBxbUObnQNScsKe8fi8ECuBlHs+AYoTcmjejJ0M0GAJN8wP0Exl yBgAyPOnYygVg0R6r19qB7jNCSD3QND07cSujQEktyzv2rB98QEBChA22+8MwcDCSIJd3lzxxWKB jTEw+NHUs+zgMMEukS51IDrLxdc0/21haxMO4YjBrYuS8PCvcNkS28y9PYguQOwMXxRFE2jpO9sd xB2oW8Q4Qyg4u53cj3YshjbBE46z8LWoDReg5CDigxsrEQnGotLKGxGxsl/ZsGcLUWgmhI1ZhQer azPlezajY8EycfYgQq2daSdm9pFUSJTUy21gVEoFsxwd3P6MEG8tylmcWquSVlq1HkIRDvx29phc JcZTt2EzTNlaphEEzCEPKekW7ajGfB3F40ICgJJIxPuP2a2p4ezro768QZMVNDALu7JpdnX8XNeR KIdJDYNhYBx5rIJ5KxisYq+vxR0YLb5L7BdQpkWmyWh86kTPOMEWRKYtk4p8bKygpDK6qPDTVyCU 8VRms7B4D8FmElAyZiQ0BMUIRMFdooAOQBBGi4ce1SZwU5Rb7sx1HBNcIlraRkuBRAXoZReiIgI1 w6Z6TokTJ/P7D2e9CsXIoEwYZYMRjBZrgZ+nbqG6UCQQkSaNF5w5TyZSCoKb3gqAEGTIPb4Hg9Mw GCCa6WMjdI3EW82DXHwbHCfWXQpqdrad3tCdj8wszD8xIQUAF1V7xdSkmjERaUA9bWHMQLWhFTFS uMgqTJF2ghOpg2sF0RNGDwW4sM/WikjETPZ4rr8vXER5qeVDN2uafDZkycRlkTseVAkJhEg+1Eoh U5mfzOmq/1c3dc5Hzvj6QIYprHv1HlX3rCuQTLRUOy+QRc7kTeVNG9DrmkVGRLTkeiAcBuelW1pp ooWGsBh7nDR6zTghpp0ebhqVvvC5hyqr1C96Z9aQhu/Zl7ZZ+RDG4gNTMESCCKoiQqgKRQZvvK3J arPBAvUcIUQGTmYBThQpchRQQsEFU+uVBZQ8BssPhnyRhD8EM6XVhikbm0uiGDohiREdfDBXDXvC 7laNg1d20yxwQpK1hdxgVKAfGMDOgcNTQ4t75BCm57C7CFqHIEshk6mbXCbXbmJS4UOwm7z4GLky gnYLgLK5Fpi8JqKF+lRBzAEZOi8tbxBKKaoSHuTT6VPI2QvbnGMa+nGOO8CMi1iCzI+qGRL4GcEm 2ozOMzc3XjyRihWyEd/MTsE0sWeezl3CFKHfxqoYpcLzaTisInwq0T0sGALdUTqSDhRAgKzxQ2HC Eo7F9u7jVj4pOUblhYM4hY0ksglIEmBC+736U4GA6iqHF2gV5ubGkxeMXkowdWHNjtO1TmblWoAs MbKJqdUEBVIJI6BlgRjfnxymBdMJvYFhl4jGZy0MZyYzQusPE5MlAvhYCMdOVBLhLTEyQ4JDiLE5 JaEiwBvHkhiW5gToeuhzC3uhpLpTKDo1bi9qWoL77eEJC+Lul527cGwxGob42DikvQ843ylIG5Rt AifuBiNlxkk0XTR0L7QBByNJZuDTdIXokLCScEYd63fLaZxasbQJQoOngIWg5bkHGuwGKGrkc4xU VZtNwmiPZMS5gMj4d9IGFrGJfTS9UdrcOyllgdbQIyv4wHUhehzpgMuIbx4swH5SNr8iED4+tGrl eIt/uVcuA3N6dcBasOBVqwTmQa04eKVGgRyIpeUlVc1rmYMsQUFtaffV1TqN4tqhFygGtJUAbYAi rrsTHk4nkFv0OcVZKPYEQ4sgGKXUkKgbENWxKgXEF0bEL1MYdyGos+qECylUJ4JgyHoQ1i4u5qb0 4aRsr7xtQ0hRSIx0tXtsO+He6ylxGyH4HpAPjSNrXB282oELWoLropwQID7QiQ9MrIkBBsCAk5H/ xdyRThQkFldDjMA= --===============7582804661255354611==--