From: Li-Bing.Song Date: January 31 2010 1:51pm Subject: bzr commit into mysql-6.0-codebase branch (Li-Bing.Song:3859) Bug#50157 List-Archive: http://lists.mysql.com/commits/98779 X-Bug: 50157 Message-Id: <201001311352.o0VDqLCH012191@anders-server> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1399502040328500501==" --===============1399502040328500501== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/anders/work/bzrwork/worktree3/mysql-6.0-codebase-bugfixing/ based on revid:horst.hunger@stripped 3859 Li-Bing.Song@stripped 2010-01-31 [merge] Manual merge for bug#50157 modified: mysql-test/suite/rpl/r/rpl_semi_sync.result mysql-test/suite/rpl/t/rpl_semi_sync.test plugin/semisync/semisync_master.cc plugin/semisync/semisync_master.h sql/rpl_handler.cc === modified file 'mysql-test/suite/rpl/r/rpl_semi_sync.result' --- a/mysql-test/suite/rpl/r/rpl_semi_sync.result 2009-10-26 14:02:26 +0000 +++ b/mysql-test/suite/rpl/r/rpl_semi_sync.result 2010-01-31 13:48:35 +0000 @@ -121,8 +121,27 @@ min(a) select max(a) from t1; max(a) 300 + +# BUG#50157 +# semi-sync replication crashes when replicating a transaction which +# include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ; +[ on master ] +SET SESSION AUTOCOMMIT= 0; +CREATE TABLE t2(c1 INT) ENGINE=innodb; +BEGIN; + +# Even though it is in a transaction, this statement is binlogged into binlog +# file immediately. +CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1; + +# These statements will not be binlogged until the transaction is committed +INSERT INTO t2 VALUES(11); +INSERT INTO t2 VALUES(22); +COMMIT; +DROP TABLE t2, t3; +SET SESSION AUTOCOMMIT= 1; # -# Test semi-sync master will switch OFF after one transacton +# Test semi-sync master will switch OFF after one transaction # timeout waiting for slave reply. # include/stop_slave.inc @@ -136,7 +155,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 0 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 show status like 'Rpl_semi_sync_master_clients'; Variable_name Value Rpl_semi_sync_master_clients 1 @@ -151,7 +170,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 1 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 insert into t1 values (100); [ master status should be OFF ] show status like 'Rpl_semi_sync_master_status'; @@ -162,7 +181,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 # # Test semi-sync status on master will be ON again when slave catches up # @@ -195,7 +214,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 show status like 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 301 +Rpl_semi_sync_master_yes_tx 304 show status like 'Rpl_semi_sync_master_clients'; Variable_name Value Rpl_semi_sync_master_clients 1 @@ -214,7 +233,7 @@ Variable_name Value Rpl_semi_sync_master_no_tx 302 SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx'; Variable_name Value -Rpl_semi_sync_master_yes_tx 302 +Rpl_semi_sync_master_yes_tx 305 FLUSH NO_WRITE_TO_BINLOG STATUS; [ Semi-sync master status variables after FLUSH STATUS ] SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; === modified file 'mysql-test/suite/rpl/t/rpl_semi_sync.test' --- a/mysql-test/suite/rpl/t/rpl_semi_sync.test 2009-10-26 14:02:26 +0000 +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test 2010-01-31 13:48:35 +0000 @@ -13,6 +13,7 @@ disable_query_log; connection master; call mtr.add_suppression("Timeout waiting for reply of binlog"); call mtr.add_suppression("Read semi-sync reply"); +call mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT."); connection slave; call mtr.add_suppression("Master server does not support semi-sync"); call mtr.add_suppression("Semi-sync slave .* reply"); @@ -195,8 +196,38 @@ select count(distinct a) from t1; select min(a) from t1; select max(a) from t1; +--echo +--echo # BUG#50157 +--echo # semi-sync replication crashes when replicating a transaction which +--echo # include 'CREATE TEMPORARY TABLE `MyISAM_t` SELECT * FROM `Innodb_t` ; + +connection master; +echo [ on master ]; +SET SESSION AUTOCOMMIT= 0; +CREATE TABLE t2(c1 INT) ENGINE=innodb; +sync_slave_with_master; + +connection master; +BEGIN; +--echo +--echo # Even though it is in a transaction, this statement is binlogged into binlog +--echo # file immediately. +--disable_warnings +CREATE TEMPORARY TABLE t3 SELECT c1 FROM t2 where 1=1; +--enable_warnings +--echo +--echo # These statements will not be binlogged until the transaction is committed +INSERT INTO t2 VALUES(11); +INSERT INTO t2 VALUES(22); +COMMIT; + +DROP TABLE t2, t3; +SET SESSION AUTOCOMMIT= 1; +sync_slave_with_master; + + --echo # ---echo # Test semi-sync master will switch OFF after one transacton +--echo # Test semi-sync master will switch OFF after one transaction --echo # timeout waiting for slave reply. --echo # connection slave; === modified file 'plugin/semisync/semisync_master.cc' --- a/plugin/semisync/semisync_master.cc 2009-12-11 09:01:00 +0000 +++ b/plugin/semisync/semisync_master.cc 2010-01-31 13:48:35 +0000 @@ -65,7 +65,7 @@ static int gettimeofday(struct timeval * ActiveTranx::ActiveTranx(mysql_mutex_t *lock, unsigned long trace_level) - : Trace(trace_level), + : Trace(trace_level), allocator_(max_connections), num_entries_(max_connections << 1), /* Transaction hash table size * is set to double the size * of max_connections */ @@ -115,25 +115,6 @@ unsigned int ActiveTranx::get_hash_value return (hash1 + hash2) % num_entries_; } -ActiveTranx::TranxNode* ActiveTranx::alloc_tranx_node() -{ - MYSQL_THD thd= (MYSQL_THD)current_thd; - /* The memory allocated for TranxNode will be automatically freed at - the end of the command of current THD. And because - ha_autocommit_or_rollback() will always be called before that, so - we are sure that the node will be removed from the active list - before it get freed. */ - TranxNode *trx_node = (TranxNode *)thd_alloc(thd, sizeof(TranxNode)); - if (trx_node) - { - trx_node->log_name_[0] = '\0'; - trx_node->log_pos_= 0; - trx_node->next_= 0; - trx_node->hash_next_= 0; - } - return trx_node; -} - int ActiveTranx::compare(const char *log_file_name1, my_off_t log_file_pos1, const char *log_file_name2, my_off_t log_file_pos2) { @@ -159,7 +140,7 @@ int ActiveTranx::insert_tranx_node(const function_enter(kWho); - ins_node = alloc_tranx_node(); + ins_node = allocator_.allocate_node(); if (!ins_node) { sql_print_error("%s: transaction node allocation failed for: (%s, %lu)", @@ -271,6 +252,7 @@ int ActiveTranx::clear_active_tranx_node /* Clear the hash table. */ memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *)); + allocator_.free_all_nodes(); /* Clear the active transaction list. */ if (trx_front_ != NULL) @@ -311,6 +293,7 @@ int ActiveTranx::clear_active_tranx_node } trx_front_ = new_front; + allocator_.free_nodes_before(trx_front_); if (trace_level_ & kTraceDetail) sql_print_information("%s: cleared %d nodes back until pos (%s, %lu)", === modified file 'plugin/semisync/semisync_master.h' --- a/plugin/semisync/semisync_master.h 2009-12-11 09:01:00 +0000 +++ b/plugin/semisync/semisync_master.h 2010-01-31 13:48:35 +0000 @@ -26,6 +26,267 @@ extern PSI_mutex_key key_ss_mutex_LOCK_b extern PSI_cond_key key_ss_cond_COND_binlog_send_; #endif +struct TranxNode { + char log_name_[FN_REFLEN]; + my_off_t log_pos_; + struct TranxNode *next_; /* the next node in the sorted list */ + struct TranxNode *hash_next_; /* the next node during hash collision */ +}; + +/** + @class TranxNodeAllocator + + This class provides memory allocating and freeing methods for + TranxNode. The main target is performance. + + @section ALLOCATE How to allocate a node + The pointer of the first node after 'last_node' in current_block is + returned. current_block will move to the next free Block when all nodes of + it are in use. A new Block is allocated and is put into the rear of the + Block link table if no Block is free. + + The list starts up empty (ie, there is no allocated Block). + + After some nodes are freed, there probably are some free nodes before + the sequence of the allocated nodes, but we do not reuse it. It is better + to keep the allocated nodes are in the sequence, for it is more efficient + for allocating and freeing TranxNode. + + @section FREENODE How to free nodes + There are two methods for freeing nodes. They are free_all_nodes and + free_nodes_before. + + 'A Block is free' means all of its nodes are free. + @subsection free_nodes_before + As all allocated nodes are in the sequence, 'Before one node' means all + nodes before given node in the same Block and all Blocks before the Block + which containing the given node. As such, all Blocks before the given one + ('node') are free Block and moved into the rear of the Block link table. + The Block containing the given 'node', however, is not. For at least the + given 'node' is still in use. This will waste at most one Block, but it is + more efficient. + */ +#define BLOCK_TRANX_NODES 16 +class TranxNodeAllocator +{ +public: + /** + @param reserved_nodes + The number of reserved TranxNodes. It is used to set 'reserved_blocks' + which can contain at least 'reserved_nodes' number of TranxNodes. When + freeing memory, we will reserve at least reserved_blocks of Blocks not + freed. + */ + TranxNodeAllocator(uint reserved_nodes) : + reserved_blocks(reserved_nodes/BLOCK_TRANX_NODES + + (reserved_nodes%BLOCK_TRANX_NODES > 1 ? 2 : 1)), + first_block(NULL), last_block(NULL), + current_block(NULL), last_node(-1), block_num(0) {} + + ~TranxNodeAllocator() + { + Block *block= first_block; + while (block != NULL) + { + Block *next= block->next; + free_block(block); + block= next; + } + } + + /** + The pointer of the first node after 'last_node' in current_block is + returned. current_block will move to the next free Block when all nodes of + it are in use. A new Block is allocated and is put into the rear of the + Block link table if no Block is free. + + @return Return a TranxNode *, or NULL if an error occured. + */ + TranxNode *allocate_node() + { + TranxNode *trx_node; + Block *block= current_block; + + if (last_node == BLOCK_TRANX_NODES-1) + { + current_block= current_block->next; + last_node= -1; + } + + if (current_block == NULL && allocate_block()) + { + current_block= block; + if (current_block) + last_node= BLOCK_TRANX_NODES-1; + return NULL; + } + + trx_node= &(current_block->nodes[++last_node]); + trx_node->log_name_[0] = '\0'; + trx_node->log_pos_= 0; + trx_node->next_= 0; + trx_node->hash_next_= 0; + return trx_node; + } + + /** + All nodes are freed. + + @return Return 0, or 1 if an error occured. + */ + int free_all_nodes() + { + current_block= first_block; + last_node= -1; + free_blocks(); + return 0; + } + + /** + All Blocks before the given 'node' are free Block and moved into the rear + of the Block link table. + + @param node All nodes before 'node' will be freed + + @return Return 0, or 1 if an error occured. + */ + int free_nodes_before(TranxNode* node) + { + Block *block; + Block *prev_block; + + block= first_block; + while (block != current_block->next) + { + /* Find the Block containing the given node */ + if (&(block->nodes[0]) <= node && &(block->nodes[BLOCK_TRANX_NODES]) >= node) + { + /* All Blocks before the given node are put into the rear */ + if (first_block != block) + { + last_block->next= first_block; + first_block= block; + last_block= prev_block; + last_block->next= NULL; + free_blocks(); + } + return 0; + } + prev_block= block; + block= block->next; + } + + /* Node does not find should never happen */ + DBUG_ASSERT(0); + return 1; + } + +private: + uint reserved_blocks; + + /** + A sequence memory which contains BLOCK_TRANX_NODES TranxNodes. + + BLOCK_TRANX_NODES The number of TranxNodes which are in a Block. + + next Every Block has a 'next' pointer which points to the next Block. + These linking Blocks constitute a Block link table. + */ + struct Block { + Block *next; + TranxNode nodes[BLOCK_TRANX_NODES]; + }; + + /** + The 'first_block' is the head of the Block link table; + */ + Block *first_block; + /** + The 'last_block' is the rear of the Block link table; + */ + Block *last_block; + + /** + current_block always points the Block in the Block link table in + which the last allocated node is. The Blocks before it are all in use + and the Blocks after it are all free. + */ + Block *current_block; + + /** + It always points to the last node which has been allocated in the + current_block. + */ + int last_node; + + /** + How many Blocks are in the Block link table. + */ + uint block_num; + + /** + Allocate a block and then assign it to current_block. + */ + int allocate_block() + { + Block *block= (Block *)my_malloc(sizeof(Block), MYF(0)); + if (block) + { + block->next= NULL; + + if (first_block == NULL) + first_block= block; + else + last_block->next= block; + + /* New Block is always put into the rear */ + last_block= block; + /* New Block is always the current_block */ + current_block= block; + ++block_num; + return 0; + } + return 1; + } + + /** + Free a given Block. + @param block The Block will be freed. + */ + void free_block(Block *block) + { + my_free(block, MYF(0)); + --block_num; + } + + + /** + If there are some free Blocks and the total number of the Blocks in the + Block link table is larger than the 'reserved_blocks', Some free Blocks + will be freed until the total number of the Blocks is equal to the + 'reserved_blocks' or there is only one free Block behind the + 'current_block'. + */ + void free_blocks() + { + if (current_block == NULL || current_block->next == NULL) + return; + + /* One free Block is always kept behind the current block */ + Block *block= current_block->next->next; + while (block_num > reserved_blocks && block != NULL) + { + Block *next= block->next; + free_block(block); + block= next; + } + current_block->next->next= block; + if (block == NULL) + last_block= current_block->next; + } +}; + + /** This class manages memory for active transaction list. @@ -37,13 +298,8 @@ extern PSI_cond_key key_ss_cond_COND_bin class ActiveTranx :public Trace { private: - struct TranxNode { - char log_name_[FN_REFLEN]; - my_off_t log_pos_; - struct TranxNode *next_; /* the next node in the sorted list */ - struct TranxNode *hash_next_; /* the next node during hash collision */ - }; + TranxNodeAllocator allocator_; /* These two record the active transaction list in sort order. */ TranxNode *trx_front_, *trx_rear_; @@ -54,24 +310,22 @@ private: inline void assert_lock_owner(); - inline TranxNode* alloc_tranx_node(); - inline unsigned int calc_hash(const unsigned char *key,unsigned int length); unsigned int get_hash_value(const char *log_file_name, my_off_t log_file_pos); int compare(const char *log_file_name1, my_off_t log_file_pos1, - const TranxNode *node2) { + const TranxNode *node2) { return compare(log_file_name1, log_file_pos1, - node2->log_name_, node2->log_pos_); + node2->log_name_, node2->log_pos_); } int compare(const TranxNode *node1, - const char *log_file_name2, my_off_t log_file_pos2) { + const char *log_file_name2, my_off_t log_file_pos2) { return compare(node1->log_name_, node1->log_pos_, - log_file_name2, log_file_pos2); + log_file_name2, log_file_pos2); } int compare(const TranxNode *node1, const TranxNode *node2) { return compare(node1->log_name_, node1->log_pos_, - node2->log_name_, node2->log_pos_); + node2->log_name_, node2->log_pos_); } public: @@ -94,7 +348,7 @@ public: * 0: success; non-zero: error */ int clear_active_tranx_nodes(const char *log_file_name, - my_off_t log_file_pos); + my_off_t log_file_pos); /* Given a position, check to see whether the position is an active * transaction's ending position by probing the hash table. @@ -105,7 +359,7 @@ public: * (file_name, file_position). */ static int compare(const char *log_file_name1, my_off_t log_file_pos1, - const char *log_file_name2, my_off_t log_file_pos2); + const char *log_file_name2, my_off_t log_file_pos2); }; === modified file 'sql/rpl_handler.cc' --- a/sql/rpl_handler.cc 2009-12-05 02:58:48 +0000 +++ b/sql/rpl_handler.cc 2010-01-31 13:48:35 +0000 @@ -190,8 +190,8 @@ int Trans_delegate::after_commit(THD *th { Trans_param param; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); - if (is_real_trans) - param.flags |= TRANS_IS_REAL_TRANS; + + param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; Trans_binlog_info *log_info= my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); @@ -218,8 +218,8 @@ int Trans_delegate::after_rollback(THD * { Trans_param param; bool is_real_trans= (all || thd->transaction.all.ha_list == 0); - if (is_real_trans) - param.flags |= TRANS_IS_REAL_TRANS; + + param.flags = is_real_trans ? TRANS_IS_REAL_TRANS : 0; Trans_binlog_info *log_info= my_pthread_getspecific_ptr(Trans_binlog_info*, RPL_TRANS_BINLOG_INFO); @@ -228,7 +228,7 @@ int Trans_delegate::after_rollback(THD * param.log_pos= log_info ? log_info->log_pos : 0; int ret= 0; - FOREACH_OBSERVER(ret, after_commit, thd, (¶m)); + FOREACH_OBSERVER(ret, after_rollback, thd, (¶m)); /* This is the end of a real transaction or autocommit statement, we --===============1399502040328500501== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/li-bing.song@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: li-bing.song@stripped # target_branch: file:///home/anders/work/bzrwork/worktree3/mysql-6.0-\ # codebase-bugfixing/ # testament_sha1: c00e25c209184b8d701054663c01d28213517277 # timestamp: 2010-01-31 21:51:21 +0800 # source_branch: file:///home/anders/work/bzrroot/mysql-5.1-rep-\ # semisync/ # base_revision_id: horst.hunger@stripped\ # 6n6er2tamdlb1ygq # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWXEZvTYAFiL/gFVxoAh7//// /+/f7v////9gJP8egAAHQAAAAGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcaGTTTJoAG CANBk0AAyaAAAGTIBoRUHlM9KAAAAAAAAAAAAAAAHGhk00yaABggDQZNAAMmgAABkyAaDVPKR6mE mNJpiNNGBMNBMTTQ2oGEYJkaYTEYjIcaGTTTJoAGCANBk0AAyaAAAGTIBoFSRAQCACZACaNBMamQ 0U8mqfiZJp6Ymk8k9CPEptDvUEaFJIT/pFLE9p/d4KWWP81JZdSlFixZSmCiylz/49Bgwe5SexlZ su9b2Mj5WR/JWCqUpSrVWS4wUQIh/GQIyIzkggBoZnLrMmFm20MIBBgcIxhJyDA6FPkUllLJg5Hz Mlil0uwJkyWYP+WbNxMGTJztjBmu/6aO5isaMlP9i7awf0eR9bFuUZGrFcav6PIumT6SWSbWSyxg pZOhYsnFmwXZLM121RZ95SzR0rsm9ZmpkMlOk+pSNFyg6m0scywYKMWKxtS6yzmXWarLDJiWLKZq NiS42qTFsU4UaKfzf7vK2PVo9bY6noNqmxsbGTatr6U0TxWWVJiqYW8uXny+yy2GGenR69pNris3 M/OXNqP4rJ0ZWWmN5DVUiZVKroqVUks5LGRUkzZDg/rm0cnJc9rBdk52L2qLX1q2O1o1asGLDW9q b2yrY0x2V5tjwY5aOB/z6vM8rxdJJIevv4e3txCEckm5REnsUQilm1ckYIpSUpKBRSGikllITcPR 6Em1+t5n4H43FiWUbj/dqXU4rKfIzZsC5Skeh2WfujixU1Us2nMRtUnMyYsgpTIpLFKfubjMTN+K J/RHqRRVVUqoqpKUiqkqkilQ2R7zNLJR/whPX6Of4vi2Xwx9XRixfG6Tez09uVvdor3UyXS26yb9 +GdUx1yMdOphgZ5Z663tWXFmXUnJzFOsxTZu/Oz21wrfaxZv3sWeLiKRAIHqAIKUDCB6ECCB5iGQ IzCApDCY4ggQRMUolKcGFss76WxwwtWuGi+KoxVetKkvRnUsoyVmr3uRg7X9DB8rwc70lPFO9TY9 7RzszantKdz9w+83MXTYyZvIfmMGCUT1qfApR+p7y4+NSOl8yy7kwXTRT5x9ax73UcDNwauiOop0 v8irneLR8x1PjUk0U0T4FLyeY3es2DNs2P5xvP9SxaHvOY9LN5KnpYFnSp8rwXck6vLWHfg8kyYe cseDcp5nsHVi5Nx/A6TY4PIcdt5LuJRaGL9pbcuyWWY4FFlts0fWswj1ZMXqZmPCZNXguwdzRY6E pdh9e3lHGMTTNZ9Vz8T2sXBR7FJiVyMFNq9LN6l8Tn52FRvxRVKpN7JZkZXXLHQu+R5HSJ1MG6x6 jzbtu3fzOOy/LyLnDRhmsWUpqXMdWBRRsP7uI51N2Sd2lj/6pubE7vSVgjsZrGwbNFY4XdLlm+wx FijgpklOlTBqb1lzGhhHWtajpUi7Y6XFhN77XvLo18lnhuN9jFdTaxbqHFRTpNPR3tKFC4p0rNTS iqSydBtXTDApSmHJZdmb3PRcwdZxWXYl19FTtdbcXNpoNxF25UdeBiu2/K2nmKOJi2qnarqs4MG1 gbyl+hvPT3zqRm9huZqHWdRsdK7medxLKZ2WbFLsXysXEwaqcmhZZLOddgwKludZZ0KYHamCUZ3W FlJhKLf0Nje6WTI0bk2L850oxm3OMlztczBcpRSTG247Di6n4HI6lG9GCitkueB2rp29bgyYHQpZ zWcXItFOhKnI/9jxPITsPEju2M+kjg2Zt/FydJqcynMxaLsSlF1Fsur0MF6zyZraYFngUpTBsZrX sniWsS7aM9XFKWb3BSlGJs4nleTTius2NpvJ20UNiztMkxYCppgVmpudPUZHuNCzBsnJu8rfqmZk yLMNtvOcEzUM13pXkT8H0V+Cvwfg+3+vZmj9aCoVDeAmymF+xB8vMRcQBhHIo0RmYTUCxOzBEkSS zq5+ar55efO2PH5X0KRMccXq737WQk+t3qUpRSlKUU/2PdV3mfBMUzUe9+75GDJ1vCk3lFy6xZS7 i/S2JupZQaKLKPjUWZPiaNS6yyUre+0+1+Aas3epNFxYs5y71lJZstD/6/zXf/HtaHF1Pebnyvau ZKYFnWiz17X5zpPoevpPBq3O5c1b3B9HB9TRiXbHmbWinZMKVWxgYNrk0LszYfWkn6HfFI6lFlEl CR+x+R+s3yZOhuXdb6u9S5g52bJ5GJyTpOk5lzVo3PWfU09j2iet4nsd7tLN79Q8jsepRUnapY1k WXWIY/P/+Wt95f1MH1HkbZ3tWT4p/VVXV3uRSinkHMoKUspPvt8qST52HY3bcBPrY8IMT4PMdbCf ddtG59iTRxbDJT1KexzLG6yxSmIsss9i67N6pjS+akwiy1rKssp8MT6H0erjx48+d9Hg9D2rJPig nlLnDBMpHKZpaSSk9xI/zfKnyJ+18iJ71ROxs49vCLWtH+0j0e/3WtVKqu16ncuo3EYUg9lEwqe+ sqmFQnu692Oj+rzDMweejFeltW5dsWQe+UxLt9EPexWQXenOb+FpJMHoTL0tkhtxe9YwZWYvlZxd dwaywpgn1f46OEjI0y4m8wmM2topvaaG5LG9gvdUh3KgzbZJ8mmrcTToI+k7X5WDJnN6qfPi2t6s xxfe3JDmUjBSlI6LrX42YdBbTG1U6xRpJSlz8apnB38l8k3kNVv5rGbow3Gbj3tgxYMdjwMZamLZ MUllRreJnMGCporyNJtztbmyvbq7taYtS8zZySa7ElYuKt82LwudLqJZNGFnHas4MYtVVksw1tVh YqzabWDWbltGCzPnswgped3vzYMNVk1rcqb1M80fkXdiUWU4koybH7nJsnSp3PgnY+fVdqxN6P7Q eI8s4GG1ZtpvdexbBXBa2WO+/cxtLV0Wvj14tj3E3UeHx1UYlkuWWGWKIeDzOTCRrk4OLoGUyjI5 lLVe1bV6eYwXTqbFuSlGC1lHMp0NGOu88GKzRkyZODRepjisqayLF2DfBow7l1pi2t19dtrWtOZV 2psl45nUpxMJJyNW82uKnU2sWWt3hPjcHXOLfL5b+mYYcbYqnLK3YY31lnNxbWy2raYYmyCzpav9 RqpqxubC2aTa3r2bLTJWYpOn2XXU3y04K4XdDB6NzAXWW8zhpSTRZcx3cEmGVWWXv6WjgpfxZNHJ 0bWGtTlqvqwaUi3PwTpNzgwarudd2Pjd7Vg+pwWOZ6WM3ujeuMficXJzM88NmHZiYW7OnPobevdH XTgqOCWb1FRMcc3Q2zJtZ2dS04F5goctHFudndo127+dzFsdK4t7K7DfNXJgU4uDFgx3YbUnatOb Bg2OizHRzru13cxNWbnauLp6bODa4uDg5nQzfnffb51S6zgbctHWx2uvm3a4YYa44r6LaczXos0S X1/YmVm7HZIdGu1dZ1o7M1LOTXD+7abf0tjkyM8jB4ud0N7o5ul2suG9uYqTSsWHqpbZhj3tu3Hf gxy7lNyzexbHJq63M5lnMp5lbmTS1rbl1Vhza4sBoXmbu22kZykya8aVsbGTBjjuUvkzaOjPLCDU 0atZgxVjZzO1jdMGxiwc0TBzvIaOD3LLvK9Kyp1voaOpo6p5HO7Xi2tcYMuEbXM55bswrnlTG97W yyxdWCyt7kzYbnI621Ys+Vjo+t2NjDex33dzUswcLbXd0F3Pctxd7mbHex4NzVg5dGFklm91sTV1 cyzmePjzuD3PkeDrb0m5s53Ytr0unjWHR2X41ljm6cLMaW2tuWulGymBqi1sdWTqVB5mDubcNmwp J2r/RNmmTI4O1sbGuOjg0xWW2r5Nlno4NcVlnBxWZsXe1nXBdycHDRQ4VsrLotfbWV7328Txmskc 3VtXMZUTLe3YvDeyiczZYrpW2ZmDKlmbbZWDLKc67N7Ol4+OybM1jWWc7iu4NzpcHSxc7xSdbkzW d03bFjB7HJ0uxYcDno+OnTTduceR0MLkqSdOOViWyklao1fwetxT8z2OS7FT5X8GrB9z8i6jiUn4 1De6lm1tfO0WYKUaFPyLLmJi4rMFMEyKWKU4smLFiyUaFP8G5ozYtDVk4rvBwbjQ4rGbyHJk0aN5 tj8Sb/q8btVIf+lJiu51jROI+1dR/MpNpmXZriiWUksuWPxtizi4/K2ItSmhSWUr1vCKVFLKUpSk pSlSLmwn/k+N+hH2POsu0XYVhWrMspi+lnRKUkLj75KKdrGR8zlLySel3Zp2wcVn9RY/QfqkHg/9 P+GMTRoOLZSylKcZFLSy8KpUqoqlUos/dB1LP6KH6D96x5v+W7odjF+g4IslP2FLAopSiLqIat6k OBQo0ijWGbAi5ybVRPng+Y65DG8LH3HbDKRvNrsZu5kTaj+oosKKGafuP/ZxNjsYvBUk52yMTnLM 3gxZR/Ac7pFycB6zcdBNH8ymUbEOkk2QcYc7iSdrFihzLk/i54drVwJclobjI8fo5GQ//DMpTnQz Liii6hoHilJghg5lz80SlIPEaOciw5iMS7lDpJuFj/eGwycDnhvbUS8jcbImay60PEyJxhrJ3ouc SkOBhC473YuMhcZsxgoyMz/HCfoft4xo6BqLlmqak0g2M4LQwHkHMXKQo8EpKU4U9S5en8GCRZRS p3qJ/2pH1eQdUm4k3j52Q5lTBC0PIb2D6HJSU9y78Z0vmbFmD6HJqZFXFLinuMj/tD+yxq6D+6Gx H2ajYiXSkopE/0UkpSUpJgi6UbvdPgk+dZ7Bl9iUmhRSUtUGM+Yn8SkXTQXNzNMCmopSUNrYooow H4kbBe41GLQ2yt025GKRsGqibijY9yR+A/PR+XRR5Sxv20ihvRsHfJHlqJq/M5E9H+Viav0qYYXZ H3T970v3v1n+C7JjxI73Ot1P82rvXOo5ln/9TSDqP04vtV4snS53+SjV0Nkj9NLxvknP4HQ8qh++ inE53M87a6akUqT50tK1l5P5MliT75TKkcCcd8pxkSy+MxTztkwXPTSGqoxRgcSoPVUEzYMFKKKH 7+aJgziFiTobnnKa6l3fwuwUUZSaTasUUQzbCN1SGeQs4UbtifGqROo4JMMcCGem0wbUfDnSeift eZ6FPM1n+j3OD972Kdjuetkzepo9rzTFZ2uEP4N7c4Gq3M5OdTJ2xOhU9SoeNQslHcinJ4we6SS8 k9EJ5fYu/E1UssllLKUpJLKWe1dLi6UfjULlC6jBZZKRRSlmCxLKKUp7Vy7FifzbGBHyT3G5vN70 PVKfM5O1v3UdIOaqqKpKpJPDUV5ClRYo4LE9TM6Dk9B6E93iaOptXet6WDV1PY9LR6Hz5ux6Wrg4 Em9z9aphR1wLFRRRFpvaNz3xKclsk2m1KUmL2PUweHPxZOB7SomVKtk1YeLknJI3jAppSSSqKoSW UiLKJEf3c7I0MmsGuDlBNnp+jBNS6j+y8TvUmoz4RSUUUKVHOmB5T0LD7ll10sossse57ku5eubH QqRSo76WK6S0WSqRRSi6wtvVepJeFU+dTzJSHoeD1KddOp5Xw62jhi3s2+Jkvqk8zBo9Da2RJxwE x2uD0vW9EOZ7nQxdLeyPEqIT5lEn8njldI5lEjkbScXewSfB886B3trsSUsyizsc/YZvBZNz5Fi6 z5t2KYmKngl0lyk8WjFk50slKJRS6yylSfGa3WY4GZWhhYuuZMF8Pkik+lcyLtqKOi5tNiWNEopn kLqP+6aIuYKKUVLLFlHBgU3WUqODfaRtcG5TVriZtbsMCxUkUU8qsC6qkrZFzUowZNnFZ5KRtUTF ZtWXSx3LDbwxUyMmKy6lRiXintujsavKry7tHOlDa8XX2FjB/LHz2/mv1bdtnpb3g+8u8XnauCzn d7kdRTtofWPBTsidhzSMZHlZ62SqLshgmBRNYmck3rJgYCwseWxR3OZ526eU2lJM052Tfo8j0ke1 16+dOpOZzFKczhaL2tfn6F1Fc+BZGkzYl73NVKKW1Orse1qJ1GiDd5LITi/AtKYM3adbIn31SHc5 Q87ey97oI6B+OpIcyOTDe62qfGpaNzGy6KKO96hm+97m2bVJnda6SS6WLIajWR3NrD81DtbXEaSN ip1IpHgvaSlPGSiqTq3e6XkZSknBJ0uW3clXKpKJNrYG2hf3rGzUsjCknOUH30YJzEmTdGd3/k4I wXTBiss24HM6DFClBg5eh8k1xRLn/gpJJtSN7c3OY5kKSkqUU7JQn6nus6HxPjdz3vY7GntfE97e 1atHvfKu/D9u1izR711mOOr5mj2HM3NjUnM0ed0jB1kyYnsYH8Uek5V9COaxPjSU0UfSfa+xcfa/ U/s+P7jHyO57lzVxtG+JPkWiTiomqnwKZtyxgutIwVFKTF6HYj9Uo6Xe974LHJJSknw32JHl9qyD FJMXNsI60WYy9LPbjkijk51JPdB6HnfHNhtP+p7p1vgfE95PnUldBY7anYqUUw0wixehLPILuZSU nqfvY3qD4FFKClKUVRVSCilVIoUkqpDdq2SMXjt+58I0UeyRRZsUmJYXhPWYXVFPI4pFz5Nixo2t 04JPakkxfpeqST6xfaLSRb1faevJhQ+/IY+g870vYeKScXzuBtPkfEKfMpZ1I5idbxUzTwePQnPE S0mCg6Vo1D2qSlQmijJm/ap+GSXeT5bt02Q7lk7k/G/LI+aSSrnFOHJIxkn8i+Cp4qetSUeUWQ8L J8HOwck61FSpClFCU+t3vnOuDsRM0O2kpRJVJRSKVJ/rk+npelEoeyDI85SSzzHSVHdgwPGnMsVH 0IcfxOlG6lfhTqn4Z1HB6HSk+KQk5iKISz1LERzudT3STJq/CYz4M0kfmcpE9VIUVD1JZZwfmjqd STtcHyJOENEpE1O053CSj7lPufOp+B9BZ8jIyPSxZv0OY8JxOt6pXJ+GwfOUUVQqRRUiUbkyZi/d 5Wi/6n2io+1S0lRd2jVsSKVHz00k/IUb5KikpYosUpKpUn0ynpWWMFSqBSKRzK5NUknwbhSikSiU lKRRSIopSSUUlKBSUJFKUJSHmNtf3eJ3sE60/4UeVTNHm1nO7nJP/D2HJmenQs6EWbGOp1bGSWll n3i8kiixi/KyZJhzPLK+lTzKFwopF5NnsZoznPTCFSJmfIUjYkrZ532NGBTEJkOh6JgbB9jN5GiL Koqjc3EvxcLMMX5nZB2HwklKbGP9H/a0ni+k5HM3rKFOJekWXUsvSUpeyVCnDCUosWS0m1QwSYDB USxisMEcYJTe+1ymTBIzadyb4lD6kn2TUSlEm5mMyxSRZVkpSoqSWsNF1H+yh502m1OZRPpWT2qL lEsUnBZSzWRDSBzTaudCk2FSR71STIVH6Dam+FJtKkN6xSykslihTe+MsXClFJO5RZFFOKWWFJPK 7X3OLmOCjistB/BaXHUsqKUoqKSpZSSSkWHSlIXSpKSMdqNqLjBO5iEvIqbtpHOfrs+2XVI/E+8s iZfK9rzzoe9JJyT8oshEbYn+KlIolSpKlKlKUiUoUpUoSpFPbSJZRKSiNyTgaWaSHepDndQ9zakj 5z5Ems3qVBOiup9iWHcibikhRPxMWMkl2KYqGakUTN2KYpaLP8FowTBhEmzBOwoGfRNjHEyUlFoN 5XDB0p40Mi3g1PJTJHB/pJdm5nldk4jY8G1sg2ujnf5p8Fz71I+p9S6S9fP1OxsJTF1o9T9h0cUj /JFLDzTNJrr6IK8Xtdxiwe9m/K/Gs6nVFSze0mK49E9/U61nlXVD3ODztqKOlo7nQxWLLFCwsVFV FRQpLCiVRZQop1PQtJC6KSfsXXkmMT0LxGEkimHnT85kqXTMuUWLEpRLFi1LLJaFKTQ50nk709of EpAxmLFImZJ9dw+lPlWPwrrLOp+xLPO/OzSz40ssozZp6XnXR6VSXnTOBXLofJTV1Q864Mz9bF36 TsN1sEdiU80H53Kqr32yXWqqlVVWcN6ROSZl5SRazvWjivZOAok8H4nmwDHFSZVCzRM1nsLKOlPY ZsF351MyZsFJSj3XtkpMEXTOksp8RUix7VmKlU3MFrqUWWjAyUsZ0mxa2bBZnS6VLJYtLM1KKUpR utZTausMFFk9zFdkUjA+/RYZszGropeQ2xbufCZnS2qaKopvpPSfGyuqtB2JHadtO6qqVVVgO/ly 3kmu/KXfSuMybSZXMmbyrOdelKEyR7XSksYp8UklOA4OTtcKN8nKO6y0qb2ayi3nLulTEwWVZKYQ uUoUilFJF02haEUyaySyet2LOJmnPhBMscVHAbS5KiUjQ/Q2N7A2tpu8j3qMbGCmGa78S20anrXS 2JVUs1KNL9wzaMSybV1r4KbE2lNhsKTA1WMFFZtK0YeKmupsLsFKXMGxsY6KvUtyJPazQ9TVVkm8 y0XGiyUpFFKKCkpFEpRSlKUpSKQsRRsGsRgjYe2YsFB9TQ14KOGKxtUMTwLI7ZUSlJNb/qFPMaHB ZRUlLQl1yyPKnOZkU8W3ZRgE7qgPkVJJxKPQ6cs+RxTezjCHdGNFik76SYqj1MjMo3KLKFE6tCM5 JdMDa+J6neYQUxyGDUfeZLOLJOKhVJLRzKUCmLVHJlPaqePJ0bPBm4vdTwg1HcbGY6+Kuo9LmOpt MJ4LJxIpCffmQsd6cnc8oLpExdrySyOfqHIzY9DqHXBxHi2p1OEG4tr2LTpirl14oTJgh/EtqlRZ m9a/ak0WRO8dBuPS/I9TxMGY0Sw7lSd3QZM3mNvppyRRo2S0h9D0rSUKKUh5StDzvFfuVT4Lotwe 13vSkqSR4qxD89pHlsLdpEdT7Xi8qTTepmqZuxaYSy1U2KWVSl2qTitP2nbExeHUjuemY8zthPup E93sfS7EZp1ux9Zk0db9cHBr6p5nck7D1Pok+qpuaJNr5Zq9RHrJ7H2LviU/soxSh/2pYyZLLslK U//xdyRThQkHEZvTYA== --===============1399502040328500501==--