From: Tor Didriksen Date: March 3 2011 2:25pm Subject: bzr commit into mysql-trunk branch (tor.didriksen:3723) Bug#11792200 List-Archive: http://lists.mysql.com/commits/132378 X-Bug: 11792200 Message-Id: <20110303142555.4B30F37E4@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7377364919870709718==" --===============7377364919870709718== 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-thdinit-gtest/ based on revid:alexander.barkov@stripped 3723 Tor Didriksen 2011-03-03 Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS This was a buffer overrun in do_div_mod(), overwriting the internal buffer of auto variable 'tmp' in Item_func_int_div::val_int. Result on windows: 'this' is set to zero, and crash. Ran fine on other platforms (no valgrind warnings), but this is undefined behaviour on any platform of course. @ include/decimal.h Add const qualifiers to function prototypes which are used by sql/my_decimal.h @ mysql-test/r/func_math.result New test case. @ mysql-test/t/func_math.test New test case. @ sql/my_decimal.h Remove several C-style casts: - some of the were up-casts, and thus un-necessary - some of them should have been const-casts, but it is better to make the underlying library functions in (decimal.[h|c]) const instead. @ sql/mysqld.cc Expose init_signals to the outside world, so it can be used in unit tests. @ sql/mysqld.h Expose init_signals to the outside world, so it can be used in unit tests. @ strings/decimal.c Check for buffer overrun in do_div_mod() Add const qualifiers to functions which are used by sql/my_decimal.h @ unittest/gunit/item-t.cc Add mock error handlers. Initialize signal handling, so we can get stack trace when crashing. Add unit tests for decimal division overflow and underflow. modified: include/decimal.h mysql-test/r/func_math.result mysql-test/t/func_math.test sql/my_decimal.h sql/mysqld.cc sql/mysqld.h strings/decimal.c unittest/gunit/item-t.cc === modified file 'include/decimal.h' --- a/include/decimal.h 2007-05-24 10:24:36 +0000 +++ b/include/decimal.h 2011-03-03 14:25:51 +0000 @@ -29,14 +29,14 @@ typedef struct st_decimal_t { int internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed); -int decimal2string(decimal_t *from, char *to, int *to_len, +int decimal2string(const decimal_t *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler); int decimal2ulonglong(decimal_t *from, ulonglong *to); int ulonglong2decimal(ulonglong from, decimal_t *to); int decimal2longlong(decimal_t *from, longlong *to); int longlong2decimal(longlong from, decimal_t *to); -int decimal2double(decimal_t *from, double *to); +int decimal2double(const decimal_t *from, double *to); int double2decimal(double from, decimal_t *to); int decimal_actual_fraction(decimal_t *from); int decimal2bin(decimal_t *from, uchar *to, int precision, int scale); @@ -47,17 +47,17 @@ int decimal_bin_size(int precision, int int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param); -int decimal_intg(decimal_t *from); -int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_cmp(decimal_t *from1, decimal_t *from2); -int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, +int decimal_intg(const decimal_t *from); +int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_cmp(const decimal_t *from1, const decimal_t *from2); +int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, int scale_incr); -int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_round(decimal_t *from, decimal_t *to, int new_scale, +int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_round(const decimal_t *from, decimal_t *to, int new_scale, decimal_round_mode mode); -int decimal_is_zero(decimal_t *from); +int decimal_is_zero(const decimal_t *from); void max_decimal(int precision, int frac, decimal_t *to); #define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) === modified file 'mysql-test/r/func_math.result' --- a/mysql-test/r/func_math.result 2011-01-14 15:36:19 +0000 +++ b/mysql-test/r/func_math.result 2011-03-03 14:25:51 +0000 @@ -656,3 +656,11 @@ Warning 1366 Incorrect decimal value: '' SELECT 1 div null; 1 div null NULL +# +# Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS +# +select (1.175494351E-37 div 1.7976931348623157E+308); +(1.175494351E-37 div 1.7976931348623157E+308) +0 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: '' === modified file 'mysql-test/t/func_math.test' --- a/mysql-test/t/func_math.test 2011-01-14 15:36:19 +0000 +++ b/mysql-test/t/func_math.test 2011-03-03 14:25:51 +0000 @@ -500,3 +500,8 @@ SELECT ((@a:=@b:=1.0) div (@b:=@a:=get_f --echo # Bug #59498 div function broken in mysql-trunk --echo # SELECT 1 div null; + +--echo # +--echo # Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS +--echo # +select (1.175494351E-37 div 1.7976931348623157E+308); === modified file 'sql/my_decimal.h' --- a/sql/my_decimal.h 2011-01-14 09:29:11 +0000 +++ b/sql/my_decimal.h 2011-03-03 14:25:51 +0000 @@ -178,7 +178,7 @@ void max_my_decimal(my_decimal *to, int { DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& (frac <= DECIMAL_MAX_SCALE)); - max_decimal(precision, frac, (decimal_t*) to); + max_decimal(precision, frac, to); } inline void max_internal_decimal(my_decimal *to) @@ -277,14 +277,19 @@ inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, int scale) { - return check_result(mask, bin2decimal(bin, (decimal_t*) d, prec, scale)); + return check_result(mask, bin2decimal(bin, d, prec, scale)); } inline int my_decimal_set_zero(my_decimal *d) { - decimal_make_zero(((decimal_t*) d)); + /* + We need the up-cast here, since my_decimal has sign() member functions, + which conflicts with decimal_t::size + (and decimal_make_zero is a macro, rather than a funcion). + */ + decimal_make_zero(static_cast(d)); return 0; } @@ -292,7 +297,7 @@ int my_decimal_set_zero(my_decimal *d) inline bool my_decimal_is_zero(const my_decimal *decimal_value) { - return decimal_is_zero((decimal_t*) decimal_value); + return decimal_is_zero(decimal_value); } @@ -300,7 +305,7 @@ inline int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, scale, + return check_result(mask, decimal_round(from, to, scale, (truncate ? TRUNCATE : HALF_UP))); } @@ -308,14 +313,14 @@ int my_decimal_round(uint mask, const my inline int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR)); + return check_result(mask, decimal_round(from, to, 0, FLOOR)); } inline int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING)); + return check_result(mask, decimal_round(from, to, 0, CEILING)); } @@ -337,7 +342,7 @@ int my_decimal2int(uint mask, const my_d { my_decimal rounded; /* decimal_round can return only E_DEC_TRUNCATED */ - decimal_round((decimal_t*)d, &rounded, 0, HALF_UP); + decimal_round(d, &rounded, 0, HALF_UP); return check_result(mask, (unsigned_flag ? decimal2ulonglong(&rounded, (ulonglong *)l) : decimal2longlong(&rounded, l))); @@ -348,15 +353,14 @@ inline int my_decimal2double(uint, const my_decimal *d, double *result) { /* No need to call check_result as this will always succeed */ - return decimal2double((decimal_t*) d, result); + return decimal2double(d, result); } inline int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { - return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end), - d); + return check_result_and_overflow(mask, string2decimal(str, d, end), d); } @@ -379,7 +383,7 @@ my_decimal *date2my_decimal(MYSQL_TIME * inline int double2my_decimal(uint mask, double val, my_decimal *d) { - return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d); + return check_result_and_overflow(mask, double2decimal(val, d), d); } @@ -409,7 +413,7 @@ int my_decimal_add(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_add((decimal_t*)a,(decimal_t*)b,res), + decimal_add(a, b, res), res); } @@ -419,7 +423,7 @@ int my_decimal_sub(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_sub((decimal_t*)a,(decimal_t*)b,res), + decimal_sub(a, b, res), res); } @@ -429,7 +433,7 @@ int my_decimal_mul(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_mul((decimal_t*)a,(decimal_t*)b,res), + decimal_mul(a, b, res), res); } @@ -439,8 +443,7 @@ int my_decimal_div(uint mask, my_decimal const my_decimal *b, int div_scale_inc) { return check_result_and_overflow(mask, - decimal_div((decimal_t*)a,(decimal_t*)b,res, - div_scale_inc), + decimal_div(a, b, res, div_scale_inc), res); } @@ -450,7 +453,7 @@ int my_decimal_mod(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_mod((decimal_t*)a,(decimal_t*)b,res), + decimal_mod(a, b, res), res); } @@ -462,14 +465,14 @@ int my_decimal_mod(uint mask, my_decimal inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { - return decimal_cmp((decimal_t*) a, (decimal_t*) b); + return decimal_cmp(a, b); } inline int my_decimal_intg(const my_decimal *a) { - return decimal_intg((decimal_t*) a); + return decimal_intg(a); } === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2011-03-01 12:05:37 +0000 +++ b/sql/mysqld.cc 2011-03-03 14:25:51 +0000 @@ -2323,7 +2323,7 @@ LONG WINAPI my_unhandler_exception_filte } -static void init_signals(void) +void my_init_signals(void) { if(opt_console) SetConsoleCtrlHandler(console_event_handler,TRUE); @@ -2544,11 +2544,11 @@ bugs.\n"); #ifndef EMBEDDED_LIBRARY -static void init_signals(void) +void my_init_signals(void) { sigset_t set; struct sigaction sa; - DBUG_ENTER("init_signals"); + DBUG_ENTER("my_init_signals"); my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! @@ -4632,7 +4632,7 @@ int mysqld_main(int argc, char **argv) if (init_common_variables()) unireg_abort(1); // Will do exit - init_signals(); + my_init_signals(); #if defined(__ia64__) || defined(__ia64) /* Peculiar things with ia64 platforms - it seems we only have half the === modified file 'sql/mysqld.h' --- a/sql/mysqld.h 2011-02-18 11:39:05 +0000 +++ b/sql/mysqld.h 2011-03-03 14:25:51 +0000 @@ -76,6 +76,7 @@ bool is_secure_file_path(char *path); // These are needed for unit testing. void set_remaining_args(int argc, char **argv); int init_common_variables(); +void my_init_signals(); extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; === modified file 'strings/decimal.c' --- a/strings/decimal.c 2011-01-19 13:31:17 +0000 +++ b/strings/decimal.c 2011-03-03 14:25:51 +0000 @@ -248,7 +248,7 @@ void max_decimal(int precision, int frac } -static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result) +static dec1 *remove_leading_zeroes(const decimal_t *from, int *intg_result) { int intg= from->intg, i; dec1 *buf0= from->buf; @@ -326,7 +326,7 @@ int decimal_actual_fraction(decimal_t *f E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW */ -int decimal2string(decimal_t *from, char *to, int *to_len, +int decimal2string(const decimal_t *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler) { @@ -942,7 +942,7 @@ fatal_error: E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED */ -int decimal2double(decimal_t *from, double *to) +int decimal2double(const decimal_t *from, double *to) { char strbuf[FLOATING_POINT_BUFFER], *end; int len= sizeof(strbuf); @@ -1461,7 +1461,7 @@ int decimal_bin_size(int precision, int */ int -decimal_round(decimal_t *from, decimal_t *to, int scale, +decimal_round(const decimal_t *from, decimal_t *to, int scale, decimal_round_mode mode) { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, @@ -1695,7 +1695,7 @@ int decimal_result_size(decimal_t *from1 return -1; /* shut up the warning */ } -static int do_add(decimal_t *from1, decimal_t *from2, decimal_t *to) +static int do_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), @@ -1777,7 +1777,7 @@ static int do_add(decimal_t *from1, deci /* to=from1-from2. if to==0, return -1/0/+1 - the result of the comparison */ -static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) +static int do_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac); @@ -1846,7 +1846,7 @@ static int do_sub(decimal_t *from1, deci /* ensure that always from1 > from2 (and intg1 >= intg2) */ if (carry) { - swap_variables(decimal_t *,from1,from1); + swap_variables(const decimal_t *, from1, from2); swap_variables(dec1 *,start1, start2); swap_variables(int,intg1,intg2); swap_variables(int,frac1,frac2); @@ -1912,35 +1912,35 @@ static int do_sub(decimal_t *from1, deci return error; } -int decimal_intg(decimal_t *from) +int decimal_intg(const decimal_t *from) { int res; remove_leading_zeroes(from, &res); return res; } -int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { if (likely(from1->sign == from2->sign)) return do_add(from1, from2, to); return do_sub(from1, from2, to); } -int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { if (likely(from1->sign == from2->sign)) return do_sub(from1, from2, to); return do_add(from1, from2, to); } -int decimal_cmp(decimal_t *from1, decimal_t *from2) +int decimal_cmp(const decimal_t *from1, const decimal_t *from2) { if (likely(from1->sign == from2->sign)) return do_sub(from1, from2, 0); return from1->sign > from2->sign ? -1 : 1; } -int decimal_is_zero(decimal_t *from) +int decimal_is_zero(const decimal_t *from) { dec1 *buf1=from->buf, *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac); @@ -1971,7 +1971,7 @@ int decimal_is_zero(decimal_t *from) XXX if this library is to be used with huge numbers of thousands of digits, fast multiplication must be implemented. */ -int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), @@ -2095,8 +2095,8 @@ int decimal_mul(decimal_t *from1, decima changed to malloc (or at least fallback to malloc if alloca() fails) but then, decimal_mul() should be rewritten too :( */ -static int do_div_mod(decimal_t *from1, decimal_t *from2, - decimal_t *to, decimal_t *mod, int scale_incr) +static int do_div_mod(const decimal_t *from1, const decimal_t *from2, + decimal_t *to, decimal_t *mod, int scale_incr) { int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1, frac2=ROUND_UP(from2->frac)*DIG_PER_DEC1, prec2=from2->intg+frac2, @@ -2181,9 +2181,12 @@ static int do_div_mod(decimal_t *from1, } buf0=to->buf; stop0=buf0+intg0+frac0; + DBUG_ASSERT(stop0 <= &to->buf[to->len]); if (likely(div_mod)) - while (dintg++ < 0) + while (dintg++ < 0 && buf0 < &to->buf[to->len]) + { *buf0++=0; + } len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1; set_if_bigger(len1, 3); @@ -2355,7 +2358,8 @@ done: */ int -decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, int scale_incr) +decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, + int scale_incr) { return do_div_mod(from1, from2, to, 0, scale_incr); } @@ -2387,7 +2391,7 @@ decimal_div(decimal_t *from1, decimal_t thus, there's no requirement for M or N to be integers */ -int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { return do_div_mod(from1, from2, 0, to, 0); } === modified file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 2011-02-21 10:36:31 +0000 +++ b/unittest/gunit/item-t.cc 2011-03-03 14:25:51 +0000 @@ -24,6 +24,59 @@ 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; +}; + + class ItemTest : public ::testing::Test { protected: @@ -39,9 +92,11 @@ protected: 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; } static void TearDownTestCase() @@ -54,6 +109,7 @@ protected: virtual void SetUp() { + expected_error= 0; m_thd= new THD(false); THD *stack_thd= m_thd; m_thd->thread_stack= (char*) &stack_thd; @@ -66,7 +122,7 @@ protected: delete m_thd; } - THD *m_thd; + THD *m_thd; }; @@ -189,6 +245,38 @@ TEST_F(ItemTest, ItemFuncDesDecrypt) } +TEST_F(ItemTest, ItemFuncIntDivOverflow) +{ + const char dividend_str[]= + "99999999999999999999999999999999999999999" + "99999999999999999999999999999999999999999"; + const char divisor_str[]= "0.5"; + Item_float *dividend= new Item_float(dividend_str, sizeof(dividend_str)); + 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; + quotient->val_int(); +} + + +TEST_F(ItemTest, ItemFuncIntDivUnderflow) +{ + // Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS + const char dividend_str[]= "1.175494351E-37"; + const char divisor_str[]= "1.7976931348623157E+308"; + Item_float *dividend= new Item_float(dividend_str, sizeof(dividend_str)); + 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)); + EXPECT_EQ(0, quotient->val_int()); +} + + /* This is not an exhaustive test. It simply demonstrates that more of the initializations in mysqld.cc are needed for testing Item_xxx classes. --===============7377364919870709718== 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\ # tm6atd2qzyduwdnm # target_branch: file:///export/home/didrik/repo/trunk-thdinit-gtest/ # testament_sha1: 969741063a269056cf384deae92d341fdec6ad2c # timestamp: 2011-03-03 15:25:55 +0100 # base_revision_id: alexander.barkov@stripped\ # 2s4n0wnrb67b3iz8 # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWWeM+u8AC4r/gFBwEATb//// f+//6r////9gFo531ug29yecd73m++999CrQZJFaX2+gb29j6u+jcTOsTcyxY93XeY6OVbAhqrdu dr64Cva99DCSRAjTJlU2xoTNU2CaaaJmhQfoiaep7VPGqAAeoPUDJATRpPQI9VMeknqPRNDRtTag eoGgAAAAANTGhE1U/VN6U9TagM1ABoZNAABoAAABoCREEEyJqMACp+lPGqfkCnknqNBoAPU2po0H qaGgIpCJkajMhkhimmp6MKmj0n5U/1E1MRgjQD1AAGgkiBAJiaNBNTNJkyj01I2oAGhoANABoGki LzCiGNzJHjggF65mGGK38EDttZmkzP4smkPbjJRpP7dsokKMYxNNjVYhuG3P1/0+ri+Px4ZqfbG3 19vPpwaxD7+7FS6b+O9JQNFrzh9c+nG1zKWB0HrozrONl1CBEFAkDGi0nd167D4ipOlrP8UvroBC q5NlMeXywaFKLfIx46wEAbWSJX59TYwRdsNk+9E5zN2jUyEK8KS9jW5JmVDIwqqWaHLUMWEh5WEZ tjhqrkbtj8vJyZcRgYvc141hmHmBCWYJDMgGGA9GEnDAVr99C0hPV2RYMjNKWHW/TyhnYSR+U4It EkiuNKRhoG4ueYDX+4FQGk2hNptNobBDYNps3BruP8IA5+ns7KCDXLf/tV7aYOv3CnVbKb3luYmI C7hlXZy7vtwjMMItWGzC8uW7vFlmXeyITatMY4zjFIeTu7OcYxavaJdYhQ22yLw6wNlKxhhFYyiT F0yJwrgWiEBCURIQzZzSYmqxFoAV5dkrqnuaVzaBxuONWkL24MUZV3A8nwRkQMYWHB/gmJ/AMr1s iPrCQF1rhkTpKhUggIuZxCLQVjVR1YNq5Ev+3E14fTMUoEdRikXu1ptBpLoxLboiiOPXIowbTYOu EodlAJDSWPkUXN0EFcBkof2LGq1oZQBe22yr4G59zEdRSkVlLUr1OrXsoCamMMQ6yRvKFmRohQsL Co8caG01rtgyXjEpyas0dQAM0Axw2MCkXJQRYejwG94RxoQtuH4sKAitA8mY0tud4gd5eTsbP5Z+ wzzmrwDOwuzMjfeWdCy2GRbY5LAOy59JFTtEaMUvm2AiVMUkMY4tX+uWCiSMksil7+jm2a8zP569 vTPDb7XcePhHOG6+yHsgsQk8wEc8N11NPp436lkEvgVXr9i3HGkbmQLteMMjabHB0/1OPDLnu5k6 t8Sc78rUhvJJNcslWiPo5Z1v3DVjqKYkmLd4iIMT9UX1ydTuN4xmu/BR3SN6IA2xMYyGv8jhhttc QNZByVWJRcWVvzptzeUyZoo97ThTn5Ga3gIqB4Ue1SgzdYIyur16xJB8sIiiI3e5OGFZzGRrnlSw yYnX833ma3uGh2r3GbpCD5/H3ZhDU5GCNkNsCGVcu6PDto5AbVhjYOQs4C6vwN32UldaNlNLZAUq LXCh1meDeLAQmU3Oo/EoG0tMgEZ8YwaZDueZ2GzyOETlayHkyYfyTk6AowI6eTn3hZwLqUMPASjF I46FzDuxYuYXautwrMR7Ws08NUYoCK7ebqrCO28DszGYZ7QCJQMDYvmUvw1aFW5d+sDSjYRDGBt0 TDCwNNxZNpCogT8XHRWYmm2cVdgjwXmeHgN5sBjS/BcLgZncTXcpgY87vHbCPlDdsYGkizEHO0oa DsaF5GKYghlWHZ21rh32Bv0TmGjF2rMVFKR0mRoiVVVUIAvASJhmJgamp4Lddqp5U5TATTTBDME2 K7WmSWZNjuaGUCFB33L26bYNGAQjFia3m4pxE5Fwx1IDnntLi+bynIP92c0SzamAgJQqg1T2MEbH aniW/CKuvBbKc7vpAKKdkYAjlXLDzQ/qqKiXzXimQHYBRUBzuNJBmestlMHzsQBlrSL25w+g4WtK /IA1crKaRVYlQOIi2AKBD6r+euEaLl57du5thrR8XNmudYTURtjWqT7xDFMCoEOioa7qxurlY5PE a8pmKwNzEzqbVXX23GccpRn+YHIhPi74G++lFjiJhxjFoDe7eVG0pcwE2LwY9YlAKBwOHE4pXkMT pEQRGZb7LptxgbItORGGMroxhvZ66p9oBFGaEKpKSsWnZjnG4vsu42kS2goM9dzlhTkwVSwsYIy4 AxBuE1iYrZ2DKaUuW4jNc2muzTLNLUEZEVHNN+Ra6m2V6yWE+gc4tuuuI1XKqvBSEri3MxKFLzHA 6++z5u5VHNVm81XDoWSVOdqkCMlBWmj6D3a8rXHfS5oThuamzd0VtinaVY3JlJEEe0JWLW062ZWM HkGPIGAI2hvsYDb0dR7lZQaGQ1emaup2dmHEOgWRF8wgouGkiNWBSSbPaQndaaBKpYYxpgMoF4rI tVdCswM1JOTPJROavXRTMFx9PjVi3SXPDDEZlm7TbN2eUmwnBcNqGGF2sjdqLBD1VSIdXdiAwIeX M1LbhqVkHFbInVXhf8WGuJTJ8EVkxHmmRQgxWAU3EytlQKKT5On7PRuLjnFBUxiPRzPwrJ18E5V8 Z08BxOU8BmaNvCLrcqXZLGqZmcJh7numuGZ53IVCKzStpO4IeyVpAO2lQStoRpzXlGTHLlVbeYhP TAmSAXZZCqgmVEdMh12x0mGQVRbUtIGDNoolLE4ZXCYsEgg/kRQKX6Q4c01iiYvyFx49+++5RxQi aSTAQ7hMiSkqcSBIZSo3iUJpUBkGejsYS1LBFQ5igQTmBZFVZqFseevyakuCpS9zYNiF5eOVWxph DCqaYmBxBLihw4TNhgeguLt/HxcXW0+pm4LXPet+6OTM0jctdrzYIrlDNqydAqjMmd63BffxuMrL AvIdiu0oEivMY3jFZeWQMYhtyO8KzKAEubwhrtf28LaCNkqgdbDKJpkMrlwqW9YL07+qnvML8cNb jUk8WnxnKkCbFK4TkNRxUNTQtogjaV2onN5suthGMxlcz5BeVkbCY9/c5vs3mwj0wLro7qxzM9zm 1ZYdcCJiZHLadj5jYlKaBu3bt12NJXu1IYOxdXUKKZgaKgRw0YIqsojBwwqBnEwLFykGYSYqyylS GRjEZUuamSNC1yyMw0pgZFJEai4tcobom02KHfScL9hzoPeYDmw1cmNu7xk3tV8suBGu/hyNm65Z oWZlmCljcRTwBOCKhBe0thAWgtFLwIqBGLhBjgXtlOJjAKmVnVEYYfx+YQeprY+ZnC4a6Bgx+r30 k5XdpVdOM/Yzj9iCPnCl1YZY0yhhyNNNpjZVtpiXoAevvA/D7DjYDVakCSxWnoRQdwfr+n1H8mf6 Q/3f8RWOLhZlbYTbAb2BY666rkfyGin0hCISrwI0ovkDFUeI3I+89DWHEEFNHilwFydDmNoSzJgg HGwYb5CYQ+nj+DwOCOwKPoMVWo6BrjmF0gcOn2yrJj9YyNgcLSYS3851zD9ZSgf3K374JlEryG+o dxtxKBe+lTD7An43f8SYLg5lY7BPAP+FhIkDItIA612NyCIRDYW3B/0uzCYxSYRVVZI1G7Q56NmO FYyv6FCvH6MjuMBYlzBiGmsTgFzlxiuJaTlDy+Jryt6hppasLgwvZnhGhMR4b2OY5QmeoXh8GlKq iyg++gZ70UO1XGgOEVWmwswxAsxpMXiayFZZo+HxkVQWh+6SwjsIbRsM9oWZ9GVhfHC4CwNoxjbd c2hJUe4B6xrKmm4lrSphsfYTFAjcMA48+/yNw6pVEA7erTz4dFo3jG88x56zE32lswzyaic8FX3j V33CSruYp62oL17YEkuZu6FiC5Iu3Ny8OVF9ElT6D2QZu2Dh4sAEQdOCERSyUJHEiJ+lAJGDgcOt D0a7l4MquB3tgjXfXs7/4VrjB21nWoYM36bCLOq6lpeTOgb5lGXxhGY4P3gjffOokIwAseaPDG1e 3ap/f8ugRiu8hBIXuPghuZrZ5LR4q+RVF1MtC4ykslosmmEmKIzT2KGKcrH2jCryMA0Od1b1e5VP woZmYixqjVYg/MZG2NQPIYEBtYAZkAORgLmjXenhUKZPwmQvj+R4qo6kjFVFR4dBhiGpcY7D6ndJ eJy2pb/eMwyPc7DzuPgtQNRjaS3bTlLIgUZWrEKmuSUkJWcaWM5VNJj4PTUK1mpuVeGebA/celRk oLP7yggwzQpRGj0ovOVI6GE2CKEsivkvBNYqOBjgPLcziclE3IChS7rkVXMlfKgjpWfOMDqdQRps 82JjCxEZEonUvV7BngI8y+JZAoXdxnNmmYIBnQMg7yhtOzuPuBkFpYdTwq5jq5Wzn9ui+NZcpomy P/NDfIwIY2oYQ0C/fB8It2mkSG+H8R1HeQ+tB7kK99uNrob1IofAgJJIkEivbWI+sE5NSfgYKmKr xHtIqe33glrpc+x+L5efzuCQaOWelIAj4yOj28jChZo5SncugjH1HHoHO169MbUNoxJPWZA8xvy7 vHKgfq5C9lH4ET3mm6uj+vZHOss95zkbCouL50Wp8hA14F/MBgON1AmyH0EKxI02k+Uu1fWOW+5y 05+qgISUa0qx/IRP2F25x7KKtpFZIa4iQQTu3ns89C+dtNxNAwOhosgbxeX1YYzMyg2rNCb0jXie u1oxObHbJAq+XZNrsK95xogyO7cJcFsEAYMCeWoO3C0eiRobaJUzC9KBlheFZvt1km4sEtTwGDAG OI9tZUai7hSJdOCVYocbH6CFJwG6tHK/bNTQQdI7RfnGis829XZtsC5AfDDz9NAsg4eYg5eh7ThN OQGOQ0DzGuvPKQqb3LklJz3GlTkBGPQZTQrL1Us6CyqFyc62qsiNgHBjAYCtBVzFM6y2QM48AmWN UFspeSnqYVlEQLSxOPseUpMqxlefE6MgguYI8JPu8tjXSuNb8j0M/McYFjTaV84lXB8W/xpnCxp1 m3b6m/ucWu7z7NrmiCQMq5iGTTbmarMQW5g4k0MYhlEDJGbslKFVntabRv+6wbmmaC2SZ52QFbaF OjHex1Zu9rfq7RVo8IIcCHftaRw8omERyClVOwbzrhU5jAT82pBq8ec5hgiiGcuLRIEcHnzIBkYi K2m4TA9crdnZOJf7Ei241q3+zCozyeW1nGe8vEyLAQy8QZfU8QIMiXl5+m2uWGjBq4J1z4MXLJhk XrONUKdrAnX7T4WhtF8fEjDe06Nbm5Ump2EBVCJ7DBN6LXawJoHl8H29fenWXn1XYvBcxeeAtHhg 46RnzTdTOCDa/j630KWOh8tzqdENz7BGvLmSuCuJve2NctI4EMTYJogIQ74JihML2lFn76IIDJCR r89ps9Tj8O4Mcy0RzwNu1j3uA6xB3vEk4D5pOARW+hoJz7BMQUh30VGeJ2wJycrPicWLfJQB6/hA UAMpiTGGwidGnkpbfi8PaQyhBBzBIgOA4AXK0ESqjMPqxHQn+T+8Rwb65m/PR+RwEJKgsiAho21X E2s3AZ0uQWnu3qryU1gKy804K+5BiFddFWu1d3wWU/X19ycfyii8/XSytDdIk14jV7vGyaCYwoSU 5CYTKMg62rEwVmPOb1VpyBRIT9CeGDBgbQLYiB5RCGiERAsFCQybsgVCF9MFFIhVL7Iwq0nAKrB0 xC4UbA+EHnBHF1WM13q0rMBNqoc6RBnJJICJEL72bKFOeTc8HTpc/S7+v5ljgW9RAdLhyDSUshoi IRleq7VsCo/Mguij+pKEli3pcWXx4OsND5DkHQ8JdunOL6hVgA95+CNnG2NgGyQ9zlNCFyh7MfSr 6z8/MoXmIKkGAkQjA94rMHryK0utqYNOvsH2XT5iyglnZWdV0H9BlwFXepBeO+0Qq13R61/EwDCC pSIOMRgUfRjV1YrJ1mHqwynsmUerPS+GVOgsX12eHgzxx6+NHusfTbwU2wrk+vJqbzaQGZmaHJ2N wI0XAnzqAghjDiglpS11EdvjCAqTMtH5PJcKIF6YUVaLwEIUgxeWYQIntl5G/nVp1Dcd5hOn16JA 6Pl2Id04ziPl69YILkr9lahWx3CPDBN9+ZtM0BqYlkpCUDA3MpjtzyxFTC2oQmcX0yLWSAt1Tw6l lZ738lSmFTMe7whYzFd9dkQqNgYkPhLkJRhoCjQwCGIBK1RcdWnXBOtcGDZ78RG/ktRjDQ0MdA5l /gIXSsw71XVJLxY0ApfuWRBQB70K0gSFhUXfZBzuq8Eyoj3Jed5REREREREREGxWViU++REMz4QX UgFDUCbCGGVY6+EML0sXpikYbgnugJYdZGlscBjnG4UEq+fnXWtPMXyBoESwBkTidSCgIYhDFSCT lmhvqQGyytFa1LBIsKFlKhXsEVmTTnT4rVZ63d3MmYjRIwH4AXAYECLqwkTOkxeUFj2oBrmL4oue M8ArqZxLSTpA/VeCwLEWXKAgoseXJwZuDGEkj20j7DCDtVK5QiBa9BTiGmtqrmCM9yzFzPck2kwy G1HcPMq9ty2GIyoGAd2wAqFRS9JTfg5EL6QkyNNMigjvgfaUilkkiq3tVi7TvlE+AzhMXiYld4iJ ifn6ReYNkvcjeWtcqt9VIlhJiTuIUk9hRJUHE4VTxGC3vzbFI86g3ayxzVmh2uQJa4PH0CJGoqgU Bn2BdZwoUbJ6VKrPLEyiz7YBR2Hd2VAipxKxSBMni0vOXF8LB5oITGXDZabzb2vCAStq19Mte5k/ JEQOy19zW0MPT1OGvk4NbU0dPlpreyxu6jJ1N29xc7bUVifvOZkIWvJvpBfkayZzPmx82oX1TBNE 7Qrc/dvY1tatbi+83MZ2HK+Yl7CVowtEp7k1lUKa4tKqoBFcyzBCycPZzf+LuSKcKEgzxn13gA== --===============7377364919870709718==--