From 9d8de06a5484f2d8be1a0d6bbd3acc616c5636d3 Mon Sep 17 00:00:00 2001 From: lylei Date: Tue, 11 Oct 2016 14:53:33 +0800 Subject: [PATCH 01/38] fix web-readonly --- src/flags.cc | 2 +- src/nameserver/nameserver_impl.cc | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/flags.cc b/src/flags.cc index 6f87831e..86f8cf98 100644 --- a/src/flags.cc +++ b/src/flags.cc @@ -23,7 +23,7 @@ DEFINE_int32(keepalive_timeout, 10, "Chunkserver keepalive timeout"); DEFINE_int32(default_replica_num, 3, "Default replica num of data block"); DEFINE_int32(nameserver_log_level, 4, "Nameserver log level"); DEFINE_string(nameserver_warninglog, "./wflog", "Warning log file"); -DEFINE_int32(nameserver_start_recover_timeout, 120, "Nameserver starts recover in second"); +DEFINE_int32(nameserver_start_recover_timeout, 3600, "Nameserver starts recover in second"); DEFINE_int32(recover_speed, 100, "Max num of block to recover for one chunkserver"); DEFINE_int32(recover_dest_limit, 5, "Number of recover dest"); DEFINE_int32(hi_recover_timeout, 180, "Recover timeout for high priority blocks"); diff --git a/src/nameserver/nameserver_impl.cc b/src/nameserver/nameserver_impl.cc index 8d5730fa..cf933c2b 100644 --- a/src/nameserver/nameserver_impl.cc +++ b/src/nameserver/nameserver_impl.cc @@ -110,7 +110,7 @@ void NameServerImpl::CheckRecoverMode() { work_thread_pool_->DelayTask(1000, boost::bind(&NameServerImpl::CheckRecoverMode, this)); } void NameServerImpl::LeaveReadOnly() { - LOG(INFO, "Nameserver leave safemode"); + LOG(INFO, "Nameserver leave read only"); if (readonly_) { readonly_ = false; } @@ -1022,27 +1022,30 @@ bool NameServerImpl::WebService(const sofa::pbrpc::HTTPRequest& request, ListRecover(&response); return true; } else if (path == "/dfs/hi_only") { + recover_timeout_ = 0; LOG(INFO, "ChangeRecoverMode hi_only"); recover_mode_ = kHiOnly; response.content->Append(""); return true; } else if (path == "/dfs/recover_all") { + recover_timeout_ = 0; LOG(INFO, "ChangeRecoverMode recover_all"); recover_mode_ = kRecoverAll; response.content->Append(""); return true; } else if (path == "/dfs/stop_recover") { + recover_timeout_ = 0; LOG(INFO, "ChangeRecoverMode stop_recover"); recover_mode_ = kStopRecover; response.content->Append(""); return true; - } else if (path == "/dfs/entry_read_only") { - LOG(INFO, "ChangeStatus entry_read_only"); + } else if (path == "/dfs/leave_read_only") { + LOG(INFO, "ChangeStatus leave_read_only"); LeaveReadOnly(); response.content->Append(""); return true; - } else if (path == "/dfs/leave_read_only") { - LOG(INFO, "ChangeStatus leave_read_only"); + } else if (path == "/dfs/entry_read_only") { + LOG(INFO, "ChangeStatus entry_read_only"); readonly_ = true; response.content->Append(""); return true; @@ -1236,7 +1239,7 @@ bool NameServerImpl::WebService(const sofa::pbrpc::HTTPRequest& request, str += "
"; str += "Total: " + common::HumanReadableString(total_quota) + "B
"; str += "Used: " + common::HumanReadableString(total_data) + "B
"; - str += "Pending tasks: " + str += "Pending: (r/w/rp/h)
" + common::NumToString(read_thread_pool_->PendingNum()) + " " + common::NumToString(work_thread_pool_->PendingNum()) + " " + common::NumToString(report_thread_pool_->PendingNum()) + " " @@ -1249,13 +1252,13 @@ bool NameServerImpl::WebService(const sofa::pbrpc::HTTPRequest& request, str += "
"; str += "Status: "; if (readonly_) { - str += "Read Only
LeaveSafeMode"; + str += "Read Only
LeaveReadOnly"; } else { - str += "Normal
EnterSafeMode"; + str += "Normal
EnterReadOnly"; } str += "
"; if (recover_timeout_ > 1) { - str += "RecoverCountdown: " + common::NumToString(recover_timeout_) + "
"; + str += "Recover: " + common::NumToString(recover_timeout_) + " Stop
"; } str += "RecoverMode: "; if (recover_mode_ == kRecoverAll) { From a83540875efa3da23702a1a8ca0ff5fc50d62c65 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Tue, 11 Oct 2016 10:49:09 +0800 Subject: [PATCH 02/38] Hold lock in Block::Write --- src/chunkserver/data_block.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/chunkserver/data_block.cc b/src/chunkserver/data_block.cc index 2ac2cbc2..fa617653 100644 --- a/src/chunkserver/data_block.cc +++ b/src/chunkserver/data_block.cc @@ -240,15 +240,16 @@ int64_t Block::Read(char* buf, int64_t len, int64_t offset) { /// Write operation. bool Block::Write(int32_t seq, int64_t offset, const char* data, int64_t len, int64_t* add_use) { - if (finished_) { - LOG(INFO, "Write a finish block #%ld V%ld %ld, seq: %d, offset: %ld", - meta_.block_id(), meta_.version(), meta_.block_size(), seq, offset); + MutexLock lock(&mu_, "BlockWrite", 1000); + if (finished_ || deleted_) { + LOG(INFO, "Write a finish block #%ld V%ld %ld, seq: %d, offset: %ld, finished: %d, deleted: %d", + meta_.block_id(), meta_.version(), meta_.block_size(), seq, offset, finished_, deleted_); return false; } if (offset < meta_.block_size()) { - assert (offset + len <= meta_.block_size()); LOG(INFO, "Write #%ld size %ld, seq: %d, wrong offset: %ld", meta_.block_id(), meta_.block_size(), seq, offset); + assert (offset + len <= meta_.block_size()); return true; } char* buf = NULL; @@ -394,12 +395,7 @@ bool Block::IsRecover() { } /// Append to block buffer StatusCode Block::Append(int32_t seq, const char* buf, int64_t len) { - MutexLock lock(&mu_, "BlockAppend", 1000); - if (finished_ || deleted_) { - LOG(INFO, "[Append] block #%ld closed, do not append to blockbuf_. finished_=%d, deleted_=%d", - meta_.block_id(), finished_, deleted_); - return kBlockClosed; - } + mu_.AssertHeld(); if (blockbuf_ == NULL) { buflen_ = FLAGS_write_buf_size; blockbuf_ = new char[buflen_]; From 40446136706a2cfe61b1a178d6ede9606fa8310a Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 10:26:29 +0800 Subject: [PATCH 03/38] Update README.md --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 68182fbf..115a49fe 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,11 @@ The Baidu File System (BFS) is a distributed file system designed to support real-time applications. Like many other distributed file systems, BFS is highly fault-tolerant. But different from others, BFS provides low read/write latency while maintains high throughout rates. Together with [Galaxy](https://github.com/baidu/galaxy) and [Tera](http://github.com/baidu/tera), BFS supports many real-time products in Baidu, including Baidu webpage database, Baidu incremental indexing system, Baidu user behavior analysis system, etc. -##背景 -百度的核心数据库[Tera](http://github.com/baidu/tera)将数据持久化在分布式文件系统上,分布式文件系统的性能、可用性和扩展性对整个上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统无法很好地满足这几方面的要求,所以我们从Tera需求出发,开发了百度自己的分布式文件系统Baidu File System (BFS)。 +百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 -##设计目标 +## Features 1. 高可靠、高可用 -通过将数据副本进行多机房、多地域冗余,实现单个机房、地域遇到严重灾害的情况下,不丢失数据。 -将元数据服务分布化,通过多副本实现元数据服务的高可用,通过Raft等一致性协议同元数据操作日志,实现多副本的一致性。 +数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 2. 高吞吐、低延迟 通过高性能的单机引擎,最大化存储介质IO吞吐;通过全局副本、流量调度,实现负载均衡。 3. 可水平扩展至万台规模 From 6d4ecd7e6a397f2fbc5cb372bbbd1c61b0ccd622 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 11:21:53 +0800 Subject: [PATCH 04/38] Update README.md --- README.md | 72 ++++++++++--------------------------------------------- 1 file changed, 13 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 115a49fe..85c2f5f4 100644 --- a/README.md +++ b/README.md @@ -8,73 +8,27 @@ The Baidu File System (BFS) is a distributed file system designed to support rea 百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 ## Features -1. 高可靠、高可用 +1. Continuous Availability 数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 -2. 高吞吐、低延迟 +2. High Throughput、Low Latency 通过高性能的单机引擎,最大化存储介质IO吞吐;通过全局副本、流量调度,实现负载均衡。 -3. 可水平扩展至万台规模 +3. Scalability 设计支持两地三机房,1万+台机器管理。 -##系统架构 +## Architecture 系统主要由NameServer、ChunkServer、SDK和bfs_client等几个模块构成。 其中NameServer是中心控制模块,负责目录树的管理;ChunkServer是数据节点负责提供文件块的读写服务;SDK以静态库的形式提供了用户使用的API;bfs_client是一个二进制的管理工具。 ![架构图](resources/images/bfs-arch.png) -## 构建 -在百度内部,可以直接运行: -sh internal_build.sh -外部构建请参考.travis.yml中的步骤。 +## Quick Start +#### Build +sh build.sh +#### Standalone BFS +cd sandbox; sh deploy.sh sh start.sh -## 单机Sandbox测试 -Sandbox目录下包含了运行单机测试的环境和脚本。 -deploy.sh: 在本地部署一个包含4个chunkserver、1个nameserver的集群 -start.sh: 启动部署好的集群 -clear.sh: 清理集群 -small_test.sh 简单的自动化测试脚本,会调用上面三个脚本,并使用bfs_client测试文件系统的基本功能 - -## 系统搭建 -1. 搭建NameServer -Nameserver部署需要1~3台机器($nshost1~3) -Nameserver必须指定的flag: ---nameserver_nodes=$nshost1:8828,$nshost2:8828,$nshost3:8828 ---node_index=$hostid -启动命令: -./nameserver --flagfile=./bfs.flag -2. 搭建Chunkserver -为了保证可用性,chunkserver至少需要4台机器(一台挂掉的情况下,仍然可写) -Chunkserver必须指定的flag: ---nameserver_nodes=$nshost1:8828,$nshost2:8828,$nshost3:8828 ---chunkserver_port=8825 ---block_store_path=/home/disk1/bfs,/home/disk2/bfs -启动命令: -./chunkserver --flagfile=./bfs.flag -3. 查看集群 -有两种方式可以查看集群: -a) 命令行方式 - ./bfs_client stat -a -b) Web方式 - 用浏览器访问http://$nshost1:8828/dfs - -## 日志规则与说明 -为了简化日志打印,并便于grep, -所有block id的打印使用“#%ld "的格式(即前加#,后加空格) -所有chunkserver id打印使用"C%d "的格式 -所有entry id打印使用"E%ld "的格式 -所有block version打印使用"V%ld "的格式 - -##前世 -突然想写个分布式文件系统~ - 1. 支持表格系统的持久化数据存储 - 2. 支持混布系统的临时数据存储 - 3. 支持mapreduce的大文件存储 - - -想加入的人在这留个名吧: - -yanshiguang~ -yuanyi~ -yuyangquan~ -leiliyuan~ -yangce~ +## Contributing +阅读RoadMap,了解我们当前的发展方向,然后提pull request就可以了 +## Contact us +opensearch@baidu.com From 48aeca0045d3bf7c921d35cfd0fc4b097c4a4ab7 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 11:36:12 +0800 Subject: [PATCH 05/38] Update README.md --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 85c2f5f4..7343e6a6 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,27 @@ The Baidu File System (BFS) is a distributed file system designed to support rea 百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 ## Features -1. Continuous Availability +1. Continuous availability 数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 -2. High Throughput、Low Latency -通过高性能的单机引擎,最大化存储介质IO吞吐;通过全局副本、流量调度,实现负载均衡。 -3. Scalability +2. High throughput +通过高性能的单机引擎,最大化存储介质IO吞吐; +3. Low latency +全局负载均衡、慢节点发现 +4. Linear scalability 设计支持两地三机房,1万+台机器管理。 ## Architecture -系统主要由NameServer、ChunkServer、SDK和bfs_client等几个模块构成。 -其中NameServer是中心控制模块,负责目录树的管理;ChunkServer是数据节点负责提供文件块的读写服务;SDK以静态库的形式提供了用户使用的API;bfs_client是一个二进制的管理工具。 ![架构图](resources/images/bfs-arch.png) ## Quick Start #### Build sh build.sh #### Standalone BFS -cd sandbox; sh deploy.sh sh start.sh +cd sandbox; sh deploy.sh; sh start.sh ## Contributing -阅读RoadMap,了解我们当前的发展方向,然后提pull request就可以了 +阅读roadmap,了解我们当前的开发方向,然后提pull request就可以了 +Please see the RoadMap file for how to help out, and then send pull request to us. ## Contact us opensearch@baidu.com From 5714b59f8375a3daba3ff48da7fd28a843481cef Mon Sep 17 00:00:00 2001 From: bluebore Date: Wed, 12 Oct 2016 11:47:41 +0800 Subject: [PATCH 06/38] Add arch2-mini.png --- resources/images/bfs-arch2-mini.png | Bin 0 -> 80313 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 resources/images/bfs-arch2-mini.png diff --git a/resources/images/bfs-arch2-mini.png b/resources/images/bfs-arch2-mini.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2e3e8f5e6fed2031c77e9712151578af4f2deb GIT binary patch literal 80313 zcmXV1WmFqow8h;D#T|+jC%C&6E$&c?dvSLw?(Qzd-GUVjQYh{giaWu1`QCd!va)89 zH8Xeax%=$1&%V)WDsq@;Bxo=&FqjJR(qCasL8RIPre} z-_QdDD+y%@7?{Qc^cOQk=rO9Zyq+rz4A$^}AJ{ZzEK=x6VmBFGHw`CCH&3%47BI>- z=0BWVp+{7zmX3mnqJ1IdB~<8We7)2G{(SgoF&g4BFG_m9yn@ zcpXZWvbaRSZfHT8_8VPV^h%jjt#(W4kWJqi?;qc4^_pdUZvRn}3wfjxu&SU(mwE!=tULs+z{5gaJkSgjeNyZhFf;#mC0F>nk}yvbWDhAq|D^$H~N%@p5{!#q!ta)f_jR;#caKfS<-NqoSaN^ zFqy%3h!^}A3!Q#qrVX9?3T%T&6jf}omj=Iwoyh5w+Tg#&P2UxUQlYm5Hr(Z9^XB^yn-nF~l+n3$IrmTNRh@V{KCIj^~ayh2Vl zucR*uw(j<_OdJmjNRJNaH6|{eSQ+s6G6q*}s6|KH@6W}}Ws1nVO zb93X%j80*dj>3pPVPasoN!}pwvLmHBjNzrR*GmXo+G3!iPc}KCRs?XkxNu;nWb`NX z`)I4{SWKq#IHYJjst}Z>EIFKE9cMgEqNPSY&D1}!%3nHmF2qyu%?o~*EpE0O1qI3M zxuttPBtDPfjihSmt{qP22{rHUr&A4&j7&hb0-eZEuYWQo5-OqGAlyh9YV<(^d|&=# z99@k*N;Djq$u6N=U=#RLC%+AQ-E(zlP$D+!-F@F^KHJ_4Cpm1SMLe*4zd>9wZ}fkTM6c0{kUF_ z@D^qM$*4AhP}>=y0*fa}bFiw-4Pp5Qzg}+wG{z$1H{BKQ=eK`3HJxvJ?1V24{j92w zL;ZVBuPVEjDt}pRmIb#r@5KxbwWYw@#36Vt0v&A!aQT)j0p`l7 zhBp+v@vMAjrqTQslFz^Of;+r1Cx)Lp(J6bd?<9I*cAclX;UI$Bq9D189!Iy= z)wi3q7r29BR}=4pG;ki{C^R1^Sy}ART%d3$6kSOea;VNeMyuwTp_LiC!d>tBce@>Z zs}q2xJU24xLPHiLOSNxsG!&uMdn0i_&N~mYd#FEN^xVWVF<<@Rwhj$N#?C$qwq9=^)cvP*PY&p>lr=Jlm0z-pS?LRM%W1Bz;NQ26D#6AF0olKL2h z{pVXF6Hw@bIu#`Xi;{c~se>fRlA&u{RR%-87fs1D@L?A{g&tUB0!@&u^lYQh0Xm@& zU5#yR#L5s;Wka#P3bllyLbbp#ogI|JH}jXlrVw_QbM*P{bY;GWIfTmb_lsz~_#-2r zd&rakOl|}JL?Dzui(F|CZxZk*bG%gVw5#U08QgTUsf#Kfxdk^Ze6rrzEHH2K_!|8r z;(wj|g^d$ff^+Icui+_3oGyhgW&U8cS)MK`acOkn5E)C_4Cy?6=YV(F{cq$v*^f+#GMX+&AN8LO^QTGe( z*ZY#BtzQbw@C*)pj zH@gmD$@)eI=`xZ)3%A8i3euu5x z@)tlE#L;S_(i`ygJ_nUn#2Lz5a(w9|%U{kPy(xNtTvKjme&F_%oe@$e?t^g_%)-3+ z{hDD$e<jO&12)V)|q#DBHL2K?4E$p$!3A506_a9=7r2~yFavCC&FQA+svQ*mj)>b$=1 z>G-znOGbH3y4kr_$`_ru&ql~qorhjWWf@9(4r{Y)c1v~27fba8ofY{@zYMHa=h71d z)r(D!ccG|JF08jxT~jA$X0qRTCifra-PH__t}_R70bjR6u|cnP^}UvxH&8t0g?t8) zX#i6gRC(`mi~@uUM10$#>%+K>q8kJ{bdXX5u6`3%FyF{SU(uQ}(S<5;XL&Bb62!3= z5%5cz%?Pp6&4TSnv2-pisC;x}#PXJu?v@^7*@KE=?_Z8nA14HpgqvfAkVQ8!;C{ub zg3oDF*nh56VddWGDGDw2=(BhxG_g+jLwN)xA1~8ZkyPZ|Xgs;yg!99t*}UiJayiB= z>(itRq0x71H0OHwk#gKaH@ZQ3Ho1jrEoCwx6)(^8BlE0YY+#XSl+^n^pa0V>C**do zw6xTX?g4BZ9&sy2;XVA97DxwO>z3ueDpk+5X1Nahwu6yDBEX7zEMl(Vb;!lmRxIli zs{>>=hP|A52r!cxT+VLNw?0d8u7$#PR;@I;o82@XQhOr{aK67^>FFvC_&^t6BU{}b2q z`9Wz`erH5Oa0DhPNeEWumx*%yicU%>3+=2hH|TkPdp<%ZWK-H|wwn1b+;C74-~&{< z)^8~O<8aitg+6!3#IXuxe0YT4(6f0Rvg>f`I@^M%aU&%rgj`;aYwEMD{`~oKwASv# zXNE&IQTw&86Zu>zI&|xh*ZixEa4(b?gZbJ5j!1c917y54HFzOy>>X0Ak~g_eQ*2^$ z6?qRL7zHn|=KbXgc^cU3s##oguTy+m+)F)tGnD{?gc8{}F5nJ1PVPD}-f#j(VKOkf zezi7QYHh`bUKu8(>6NG3liz4$SfYD1phiC%`eRC!>)-=sSccsQ-D`%O=j>b9A0Uj| zAQ$pl{H@#q7wFli56`UHqO``+X7?*ap}v9aGGIp7{5nWojRIOc)WYZhBPxmK$A0!?%tNDJ)Dhg^de>m<%LSPP$nG##baIkw?v=xYE0*0!oj7JnJ! z*cph-amUwo}qxMCZ7D|MxsIf~0SiGIPKbb-0&8z)jPl8kh)T$R~ zp0h0A<^AZ+XLG>gCZ4IxQH5T|#9mG*yyQhWXfHfbKG)VcdK;{uOb1X0GfaTub6Px+ zZLUZ`)tSs3sQ(H9`9IHATk$N&z>xDhdkKG>_|A~7-}@m7;l1y&u|#IO+ovJpa1EY> zVBxuTOZB9qV*;$Y2wJ!~JI6#@C3>#&yE!ojmQ8F7tqzm7QLG3h-tY9+ z?qlt$1>|@dhcqg^7f(BTz-CH8)3t+Z+&I~dh^b){AEoK(w{PHW64OPbRMPoEa)w;a z8cs(}R|}+x0jEN`767t8!HrnM-3XkQg(1D@9t?o&HMp%9(;Hh{&vv2OqK*l0#o5dG zUIT*8kZ3jx9xqr4wA}(IA5ay0)zrM?v^2v1q$~`IPL1{~FOaMuD(O$hPN6yiuSxI9M6MutJ|AW_4 zf6HxhYQ`SqyD!4Wgu&6TSgM-9^C0TAj(ugIr<1w3ulUQqlXEHx?`}N9=QX_G7H`#= z2LV=3N7#|zW~^A$2<%LTaMYLkH7Co>rGO?_OC@qzLu#@)py}d_*n3YF1U_}Et)zFR z>L%3RGvMTnl+DO_^JD2aoifd^-~cc z2mP3jN6~^JN$>}8+9qG8#qAZ3J*71%D=v6<4A)`3$Uf5(^k1kP9;W=WMAu;Q**chl z!2wis<;!#fM^1~7I@3-wc&prQFS#H(%{Zc|C@ zH&xL_n?&Pq5l(=K1!c#|V_$A!M1hb5!y>qpb9j|Up!pjG;Xnc{!g{Esi54g5u)6T0~Q%!w$mv70td z%#30ALx@d*ayG+S4#9c^+wPZX3yNgsl{cTK&!IA-^T>D7(CNrdj4D`9E3gJtF?V_E z9+xv!BDXLu${hT?ZYH959zz}C9F1ct2KRc<5susUDEiQ#Lmba2;Wh&lCVENJ`9|^- zUr>~_5e^y%J5&3IVvq{*zC^yCG)@`?4W{dFX$66QW7_CNqMeb2*JbLZe7i$RUVNJ$ zic`poDyFIZI;4P);2e53WH3^x`ZW!fw>obQpS#Q^3Ou&xL*WOK2l7zlW+r&zs=40U zwl{kb*K(tO@c&T-E}OYew9@X73DI5o>N}7PGIwauP02qM=Ad zz*KM+zkkr;i3kI6`&jjr%QFTC0lqjP1uHiGQF&r2Q)*0FX!q57I+CC$LpQ)0U?93y zw;3e-NP!oJ#3?aRMAHlhkFs!gkYU2BggW>|>MB?Q2?Z#ZU9@L5A|770SF}O3)1VR= z5gJtpPNu*Z29MVi9hv%=Ka+uLtqtp_KjYx!(;88`Q(raZ_v2DdNXXH~j>{o2=@Sj- zaW#U`igUE^aaHuP(9Ojykas!8gppxw5|KmEWaWuDjyTzoN{aemE|kbVDWFH8ms2R^ zbGRW37`b2i*aB5`)4$s_O|6VMna!luecof0{${Yb*&6-KW? z30rsxSjtuh`7Okn=Q9d39$!gSgs;mCF|-Hy<urc2OUT4xrHlxH{#Oyg*@>i<^k+IA61RVZP-*s^O@5*a0j%L6>p{2WQ%>S zdTZQ&UsgMD`nE12vg-}rLB0O07+a;5c}-O6X8H+%n<_IF5g%**hZPiKRQx`nl%|46 zaB*Z;arEcFeCdxc&t!uZH{c+qt5`Rtf-~u`E072aU!sxzzCr~p7BVQtcW@&~Z?yDf z_z>ijB^HcI>u%}ZuSES)>U2|*7c@1WKDwFGCuE-mc>ce^JKeN}iqxBJjrOra&JPgJ z51O6pO@eTwUM;li@5NW?@_osdA$Opqbo6C@y#<^9-hk7*XQUO8jdOwCbMEK$$xL$L zNwBd8`i$rPs)+wHDQV<0-htE2LGFr^Jae;~@Z`54mQ&Z9K14{E@8EqI=o;>P2KtN? zGUVQanOrrur{c6;6z5}XEX`K=m$4_rV$FwS1m{crH{Omxf_r0UZX%7o5XWXDIN98V zflnN(re<;~PkI5^x?vmT{AaiO=U z%>p6oSc&fmeQ40xqv|)EVOAqR;h7@`&(vZuM-y0@F7hYgAs3!ECyU>}{Ur?*YxZeH zo{14mDt|kww_aR<1qck{SW%)8v=E0RJqz2I$>gg^e1>r)JRF2WkqE$p&%}@xWtiiv z1A47+%-%HR;#eCHu8@c0r^Y>sW|~|a7$@kF%Mhm)cq`_npJEZM z1iJ*GZcP7vNCXy67yZtJ{R7UTWj`ImJ49Zb=Gck0;~`H*W0Du|uO(Cp$WkK;^Kxj6 z8#7N3NpCzB652M35)xu-UVQ$=F~F}LD>Ol$*B=jAju(wlbE_I$eWEtF)z`7tf_?#HmdA2biUHnx8t zyg3eshfac$jz|#EWSzpp(qm@^zlSCnhaR8;s>}-hU0jRFqGTDMdg*Ari^56Z7Zdwj zJd#^zbILI0Is6m%I+YWjo9ei>*wTzq=&GrKU=)MkZq8KLJcp(frJJ+?J1bOKQ4ayL z#9~2ENa*4C^fvf1xQbAj!t2VJg-cxM+kogGktF?%b?wkK_4{^fY&5IyvMowOL#*%p z2dR`MQ&wD)77Hg~?PNevd_;ekfI+7zq18qLHd~=X)4~T*-6lHhY&_qpKiLq}p zN?><0CDD(j2ExziPm6WAM1BNeqQh7_qWhGYd=_>TW0Vf2o^X&N=l+_*%;i6X7py3B zmLffNKS=Gj$M0YKfQYVCDzKUGW}1F+xUN*I!&wN&AtHZG!TdoD7C`J#_-1lRyulRg zNBBO>5gjCsKSkvD;lInRXnL|a8$eo=gFF^}+vs4dQxW@AQ=$BKuPzi$c z>{wGI=O?bInsp6GRRU$2n?8>`bF$FsA+cTDbQq*$G?aPjnc~OTb7?y=%%{A3Kz4}= zBWNuV!b4Td)Gw8Ys+G&`4BEycu*L@&xtzsq_fn%-r}~{v2V{Vi5cOZ6eV~E^ov;4< z{@V(pj-Nq%^AO#pU8z4oOI-9|;fFEO0v;s!bDV&l8#KJjmjQqBsh^$99#e&<_R3+z zI65BjgDv-9w*lm{SyR1)FvxuLy}=FdWfn@<$8`3G#O^|4&IGRVhgn+6*PEh$19rrC zt0;C34~D#^8@OLTyQ;{*a-*A2$#f5X8hbW<8Y&9Ccm)J%|7~TCLN0K$%8&n*>2rU2 zBz$Guu$|*jy-YJ6xegD*)EN={i_@sN8=$y6IQj`)vasES`N=+dRz` zPvC`25FSSgo3qqZ7sexkL)vz9MPRBQ0F@VGM^1*SLSJ#O?uWe*cIFMjGXccLlbPCe zhX32U(5uc-${z@0|y;pQ|Q|dckkTdSM zZAQXuJ{YA8td;(!bF}fS!fMBid6SZwO8Z3NH(&YBuMxn{uXf@Z>32C`Wm%I0kBnto zse{#Ri1?5A8XgT@RwGDpY+vy7bmfTL;$=UF!k|svWnB7jdiJXHX}2n$8zPGGO0-0 zAA50AWfGyECx(~Rg_W^ISu*LXsRXQ*BatUiZAhho&(DdpGrE#Nc9uyuiADn4^t)uoU8v$o8_D)Nz6$71w> zRKS06cPt9Bx!fL58B;H0YPfz@8ZA`-R_#AVVZFp0G)+#YY1Md4UI3lcB3fm5okR-} ziZlP#85t9M8+AVHX8%~!)4J6;MN`f&gV>4A^b3e};n?-PSb#ym{a@_?JST(30iE4{ zYdq^Bn)h6rD8d_=Gqj6+5^QT#No1M7x^efuAp6H4)+<~;orsO=n6PR}lvZJougVb1 zl}0f9OUiJFbq|8a){WOC7Wk2kCjCBEscs_Q?a{YEeT@zcndKu`x!_=UWI<}V0Z%iI zo4oPojUC>t61mKE7deyO(1syXqF5Ycth)J6oG$I4{9YB*6T!#l3x|=?uZ`bIx$Sjj zvia)Sl(RLpe!+aht&AjJhJnjnlg?~e>4k@*q^<9{4h3a4>UViM(ZeGZ!bYA*c+zhT z&i)$OPmmXF1gM`{Tj(<|o~SMKS-sE5+p5%_b@zCoMjPc)uOIjnL<)KI+nqFKR{n>&rz&-h|mN>MN8BQ7_Kn3kzt4z<3QDXXqT0I_{ zh3a%eXV_3mtC)3ec>QQn>B$U}=_JZPLwbj`#T4HQ3r8x=1nC>@ckzur%6`H9T8lDW zFPRuvoUglEVxi~ydnnlaDUP7viCe;-W5&QJbkRFQbBN>uf3#LFDza7y=5htw5{vi* z+eYwc(Ku2M4E$F1ad8>%EN`_4zdoQnD9b1xJILTub7;!_!!q+70pWo(j^Ip?o?c66{`%|lerkbVB}Hm<0@ug&G*ogjQBnt95Vg6*k2hit@@9_R;%QRZm-exNP?sOS@$W4D%{mUx!aJ-k z=*T=MeF>xe3gDJCbr7f<^+#2fPSpWu-_=5Rhqdje$5>>QP%|B4;*uk=1AzFdt8nqv)v;LH-D zP_#$%rHHl3_sAK)K^FIVYZVetYB%FX>Zk5B<8$B}L#8 zZ*$tBeSPw;JG-pilu%ULP-`gWMIrIGYyJMZ({I&|ebl9}y97i7`pSvzKM4~VQ zSy8m$_iuYJ#sakk*i_s8s)h$XIa-}6qn2&gLFhm}qKz?RJCH(&58vaYwSl-ogH zhxlApswZo$-%b1PfKZ2URVENEF$g9@!1?ZYV??;wVT~G(ox7#OrNw#~htMN~kNT<# z&PSkJoB*x4qOwoV zq?lQg=njiS&hoL8ix+!er)swR#bfL);=?^JsFeQTmHX{Fe^`7(cSNn}d(`5)z+8_v z&l!VP_#lqRTF5mAnkgK2mzxd4C)b80f}DaT15b4X$5!QR!^$v^$lFuzXs%Vo5&xV{ zEU;Toy}OY#q9uHz^OVVelA+@f85Er}z3GT=!4`+QcX`OC6Nmv6`RlQq#0U%?LxeB^xJztCqn_49h}i^jp_4!`%)QO*7= zHT@K|-zMzl{OhZk^v(`7cq0-R`9_vixw0@1FWQ)g9Mjj5k-aAOllR+A{}1&*+vDz5Wrky+ z&3eeFkQCI%$ektpD0jFSxgG)ygB-`M@l##@VpWEU^73qU{pno2+jTLgjvZ|QFXwor z?AxF|D>}@9_5STi$G!t4m{c?X6-LZn6m9`g7QiZxtM-m7@J+V44&@B#h{Bb^RR^DW zcVc>U-=n7OH81P%c%!@Q_5|5XD!a{9U4BM>k^0A)!-XB`Fj3rj_eK6(!>f-M9$YFa zLzQI|YN{ZnCaYN<*Cl0K4Wy?2UM(UpIKrIQgU=Hm!P*njrkX)${9rs1t4CE37*Nw< zzoItejOZB|BLFqFNj=@aYCey~_&6ORd235{xe>FO__;);vf3Tmv4%jMt4UnuBQ*a% zYWlvTnHP1H*-lq0y3bqqS$S02^_!IzeQIEz5ASmm6W%q2FOl7m5rGW zd|R~?hS8}bD^K#uF zpfF?9{4#l&PHQZx&Xvu4xqv4F(iZa*w9d`z z9*lNBX;TCS5Hi!gieGpf!5A<>eUU0{PGVHZ*dt%u+={(Io24W|j`slfAd}8q23;0I z5Gccb!$*yPUGyml$Yn9O-yh81Y|KPMGiG0Je)vrVao<6KVhK@z+xtC@*<&KVx8rM! zwU&HFUEC+Z&l2(b8l5k<1->fZzvMNTrmLE9WcZBJwL)DzNKYT_kZ+{U^WD#>%H*Lu zrVCU6l;9D&pLO#*JoJu2s}LKLA;jb4yC{gazG01PKG?d1P?|)b| z_}|?9XCNc(1bhq(cP`zgtBR#4M@N(Y33Tfbv-YBRIzX#o2;z_V2TF1wXym@7|u&$Q8HFCdG@uJz?| zh-(i4V5{j=Wt^9QRDAYbTXs-!;;cO(@q8m^B29;P!52Kj@{?G?e72DNAjfGvk6iMg zD6%in_u{PZ2!O0$kdmIjd4LZ^abSi}q8n)B1Pw-_ih_6#$Zs)tdc6;zV zKJ4{xZ5xzq7o&Y zFqW@UUE~D@ar$3Q7+ia8aSOB$2$1ZGddeA4v2a)sG5-1UT&h~28ppTYVv}H#X_S#l ztf)AZ?Kv5N>2%V{aD%O3d6PRA%y74QjzswhYC8xu4D{D%{*_ciCOVRuQE1VNTdO5N zTv&Y5D9r1@V!zz`9Mp3?;hZIS$C<@p7R6PDg83UmLhp>~iuyuAgf{MQ;pJz!$yhdS zCw>ttFe_Pzs~%VK=($CvMOrpuVmLZs9GP;RChhYEtuKUP(V5`hCuHmQc#hL1)r^>! zas9?Gj5+}Q>fgWSV(OA2UKJ=N{Loc!q}k^v05u*Fi~4oA>hMFO0k-q@>wV|5TD8`Y z+i)o>JZ>~6z@Q7;8{MRrkZt+iR7v`Th^fXL%xbf6Ot;eEk`dv3J|VvTu@jsfla|El zdcLs+*r@&UgEi3ud#T&p$$v}=TGk2TqtkWAspbhTbTX4!FV^PQ8jPkZaO0N?%>?fc zWnqW`hy#UD_--U9_WC0ZKkAiX%dcfW#fOdpARQH4ys8*NY=-4$n53JtSFwb7n4ZXw z6^d?Ua zNt&XIW5Sc_2nZiDZfWI)O@_=^JXk)OH-GCL0XY!MdT;=FToM@YN~0fh0Hd5oE*Bi! z&!A!V^RtUd6mQ?*2v0x?y=#mZ_7Ox6>xuj*Zf z-kr@F$el&r048-Lr`D1vMlF3L$SIr7Vht_bWO`ci(@PPlPv(!bnqf9NZ`2XR>afTR zHHqdVrJOdk3lU`>o4G;>iyHw9cKT2mf+dKE@a4g%5PWj*v{+olz)WYv_KK2!&ZyBHjAMtH{iO7 zLp{%HbReu-4D|V%aqvB(C4o4*K7z)*z4_AgrRYad=*mEw3-+ouZNGwg@Haar1O2Xk z6Ls!k@nTtMfIvviz*^l#sc1^4FHkP$Z-}C3un_8qID=&{L;ezn- zNp{uQrrSSzSRzk~2^4+_DD>NU_qB6~D~$7C^Qlua7ak%$lMDq7HtZPO zN_CxJ*2hb!#d-^{aW3)t%_SfvZ!}@laDO~kr977bIa99K_WrEfJtb^eSD?eGz)YM} zr@L*`CUC0tYp&Zu$=sh~2>)n#K3u#o_e5^Zt=N$QOyF=2fkJ_bbA^qQ(!- zzRHwnAE3~VuQPt-Hmi*Mvfk;M*ZuPQ`rxL_OsemG{F9^QHUNQ5`KQx(M`_>^%3e1= zGFC%lxr6>RhYd=!P_ww}wrRsPXpzwBTm+f(C=okyK^7ir__iX|7_ZivsrvYybh`E4 z2GzA>_1goC3%c>xquP8$gSf{dIpz-R=i9bD&;Qag9O+(mQ_+dGXW_s8`9s?hTTp!~ ztQoyvP0Vv_kt>lY{J1X-byd*$#A#bf=*`kN2#Y_3 zrBKYQZ=LKXW#_UGwm90=>AXEwaHc4~2lV`LmJEU0|4AWo_a;;#Q&#$EvJI28R0?vQ zoS8_KRHitd(tekwHJLsUd)ED3@7vFpHj8dsmFE3l)Cme+(YX3fbw2XS3P}eFHcd1< zMyrMkTIc6JWf5JuL}+4jr5gKqZ?~~A_rrOXPZ?>{3b$vH&ui}_jPpjgS?}o zyYHOt4@MCNL>>JCkH9%wb2y?u%S+FR^mPn(ca!(?Jj=&_wa5Pjge}Vu>HJ!)8^zLV zFwI*Jcz)(`Sp9*?&J5j|RB?Op9{h5*MBf{k6fCYFFQ2?K1k8}5Bxe@#Ap6Uak2tnu z!oK)oFy48{3xHTmq$bmS$xoGv)Q$S-D`do?G!mc3438X8`q)58jnI>6zu9AQv%;cL z&XPiC@}k}vFJsyKw`8NK!(5L_v15Sv}v>m(%GI}hxw{n&#zJ! zMi()bzn`IQZY>JG%b5B6E%6&Bt+rSS3yT3KpnTP(X%@dvi`$WV%J49~{Aj+&l;K?d z*_uU4i9)OO)&K_yINwqwmr51*9-R8wXe9G$0=f$c0=!I)^$jc?N;Q;zxvK}JNj*cx z-;BEV!)Ii38W5pSi#c`I%MP^PDk>y~ebi8yt}tE_-Dih3wCHL+c?*^c!zM=Vf==C46aZu#4-O0PM+*6^|1cqo&m^lMpnT9tB=Y+Ut3 z9A5wDFaz%Pi2eLE8S@9wM|wq)OA{hiJFIyHSfz>z?pwysZB+#(YcVYh~3Iz z|BFTTP}bs<(59=HHOkvu2oy36`Qgq+K;j^$V%rYaD&B@%7R&6hQ;XGxSnzs%k0OAK8CHKnYa zZiR+zHQk9FDV3eHSSE$C;du+CZK!i4iEq=i?^EE;p_Qk{7^>prB)f?fittwvA+zpn zE26m^C*%6zN7S@U-^tBhC#DaPE2W=HTx`AvzCA_=KYlmqJZp=wSgIT1@_(wS))S$E zb^=@$y;4)ZuzAaD`a|fUV5i`{8{N$vXExVJ8#@ZE9j!k%TZz@K!o{8wvp)YKd3V9b zdRX_)w56NZ3{_59r~xL!!uwRy-{o;7STqH`do+LHUT(j@%i_DR@IER#*SAEWFCXK$ z;p`d+WnVhktyZ2&iX(-Lr?YP5xOtqD)n|i97Bm-a1=(&k-d-sy+iv2yxa^vk=zZ^p zE49b_LeAYMh|9fS=&L*qZPAa%(*m*=7c8MN>RM{jX5s3l{I8g4lJ;1)vsL-51%Zjv zx^!q!#Wb%+eRZXg=55SAnI6YONtY|=p8v?jw%qfmr3ZWysnSoYXD;Z1FbwlDaY_if zbwg{vb*h_y*QqeRj>68;O6Ley>B;-EgBd-5R!KG+dHo5s0*d~Gi!&^;Q{1~m`LC@{ zDcZl16yEESverB%a*cfHl-EE$Tg1hVsNHyA6JfP^LMDx(kkhr+n@smFFd9#63x6lH zDyaM6G2nCCeNz89=SpF^dwiqblI^EZrcI3NmQ7M7Fx$j#=cq0Of2-YlHLK=yY?nq5 zjWvbzt*nj0(H8w53c-5XlX~i#zD^OF70|6yFU&I{o^i$%6U8#5Eg-pDNS&MQLf6X6 zF=T6rWbo))i*=U$%05jz&TA7?^L7nWm|Jk*r((l6^!j!n;QlT8jJe*B;V}QX6uhMO zbmuGgblkye)U3(qt|q2or5vVh%Uj|#N&r-tdO98qB%=8{#eRH54N=leA9 zQquMH&lh&Zy%;twrARJ@;n6RL#(Yc~Ps-_21q?d39md3Z#ee)hYn7eJ1Q5T+{jJp7 zs8tX=?CH8b5OSIfV$0J6pt*x`XzX;L6lF|4n#D+8o6XpMkgekuH#+WT`WGS3r0>eE z3v*==3gI%+MDx1?y}lNE$67zsD^%E)+$jC{QK9C9!Bo$#X>0;NH1i!v;W{*Cs_e!l zk27atA&(?m0T6z$c-nbj`bb=X2H366mMK(|b}$T#O8CcOBi)W`&D|-w@r;Ht&@X3k z2qz10_<^oZDvlP`68el6iNH7g`lZaW-PDzZuW>&wWUk6KS|d7){M~8e07_Y7CDjMQ z_5sk{UdmHT-@c?v+l7crA?)qnE!Ah}nB-NvWH6htm#rq8#591aS{;q#cyM$Cn=M7Y z&p{Xb7Z90dG;XQ+Bu0lynq8gEXOlqXXR{C*>_Pacp2UJJRv+?2iJ)NWf2i8s*RBR0 ziHr%NKFy-<(oh*Vh-ygYg$jEbyk1{q{2T6?TtR~+A*S`ssmf15zKI z^HzFKx}dF=>zznfXhM5}CQ1Lty@b2!ERjOhkg|Z+W-Y+p4J?K>I7E>VFT39Ak1(?$ zbQ{+9xl&-O(!pK(UFwSF-xFUg^tB4Eu~Jjtr5nUGlykVDnPdN$D+ zqi|14xrWYsmF1jXm|-z>Vk2zU8EuPIzZ`UWIb!%yts25IIczfCkoAB` zr2GMrf=(`w{fF{t!&M@-#SI?EYC}&WD^~OZZNilnoA&Xo)+4JZ!vJsil}>=-a{tXrIZ6x3Whkh-%yCF|uGr`q0~66Q3}Q5TE>b$0=SiGGf~>?W z%BIqF+oitwaxc^zfy#PR!9F?`QvyuPx#%|eR#Nh*_&aLn!?g<6?x@1`18eWWV>hy` zDEvWhLHXDYJTitxY}`*S`hEinG8S~J=|s;+5xQo2mA@}flebfAv9xnZv^M2RnC$k{ zzq;Kxje}({f49aFvg^}M64WQk+`Om%%HfQbBcuKMkm!5KS&j#jLiIl+opn@H-`B=P zKm-Y;8~PA`$SP>lyZ= z;M6lhCM=ruswsH1g0>6DKA~Tb+g}#7Dc>T+oMf5WDc1X)G7oH)Fpk5Go+`UPwT2Gu z;jvsQA=uU{&Eaf+xE>xe3Vpq2+mxHCA+xo{zKo#!9jVRH%vrE;3b@TRRO)PJKrmfGpFk+v_x(;(MQdc8lI7ao<5`N0@3ki5@w+lD*4fnU^Gff{0CcF_BmE^o z{&;DmP3Z5W`}x`W->hU6whMN-^Of3$>z)NAn3epTK4JUrO~vlbYz+$z*C*POsz`Dn z*K#D)C)9?Mx<;8;F|EG&Z{J-$mE??y)^t)U16I|$pFK07=+X@f_Ga5q^?Dv^13!Zf zVWzJ9NHJRhj`H+_Y#PUyR|CRkJ6iwaZ(l#4i;uxGcYjfS;19;1HOX@bWNU*{L`y7t zcoYvc*-eqx-ObZ9WS^RKJN_6Oi+1B}7sl4jIt(r-&Go$CxVN@uB;c>fj><4pbnxWV`iJAnlZIim zuj_FtVAp)#LKqj_0Zf>vdZnHMWYjQ50}+YFktP9{1QXz1O9tLW6U3j!OGFTxqoh+r zL${+s)Y==zcAG$s;2G@c&w7U;BhaKHv#IQ_<}BCOq^h*zKLZHzEK!*6>{BKn>@^8X^o)}%qJokJZEQN@Gaw@e+p~4861!7Wp4C>%*ZTu% z-m}hzLYv=ogt)f&f4hC_TyB=qc(JCtKB+|5-Y;grxNY2;ZG4hAqwYC~Df1~A#=C8u zt1`^0UVlTa%B_9R9YTwIy!KB;I8T|h>&+tnlb`&XH?AVE$F5ADLmyb3{FdS-3f3k~ zzQ0_wB^Z-hYj2Vh;6UB)DAxozvV-nMU%rJFZNw$MD&>+uijh1&K1W%mvB2M2W?!sI z2YLT-KD0`W_LAePe&dQJFemisIP`7km3-o5%%hT#f^arfp?pS(JMqrYC~@J0(D!zC zZ%w}^=UM|(2TF(3)gMP+30U(}?)AFq8KknkEi%>YUpwck3|HQlQFZj7)8Mi*#%u+HaP`%PY!IPl=xEF#=JxSXqDf3b^;$pG%WZD4y zolNH;oaiK4;Z6OVZph<*AO6{AsL^ill2VLS2jY~7j<7L=J&VRZo=FP_{jN>>x>WqM z2i@{{qxx1-&Oma5b14;{-^0!dw%ry_^KM%rUQvDO;`0Ym$5wLG!Nsv zUa8x;hl0Z-4H%@Z$3kdHFy0#|V0@^q_u2n+dOzNON#KOhut*S!?A`}~(`y@UaKacn zb)wpQkT-s_FEt+L$wj)_qRG@+Sj1ts-tYBK)S;iA04t+5B)IkLjnl)X>dECn$G!pz z1{;M_lo=7a@;)I}7FvTP(G(koEMjX*&t)OXN6QY}5v;*sVvC#=H%36wEc7}1u}fTI zt68sbXS9(m($RRV-*NS*KhXOYw7m>zFn6xO%l6uz>OyO{D2+^{E!i(d;Qh=Z_C+Qs zZe-Sc>MupU8!as1*vs%nqmR6&QE@H@g*|R%TqGH2`%v=u7wbh7bNW0I#qF*JwFpg---R~%!;9n z6$px^t=XnhlsR#=O>bi#u?Vj>-|M!mPWZ*HwZ8ek+b{=Ab*wYV{*(9x@1pCpI56H{ zd=e%zL}@#GGU`+KxZ!gd?Ro&%7IraUF|>Wbdg-4gncp`IQ8H3VpFV6b z5Zs-fxg1sWjKp!9n%%hy;fLaq!H@(YZV7(@-OCdo51PyZd^JjL%5r`g4bs(z*J*k# zOZ>ALTrht@OM{LegOY)c}ni`uUXbYNX zN=Q|6P3h2qNoI^<5Y_ z?DiMTBnB?6j>yx1oqB=&+w;}j|9_EZ9$_NsKzBAHhVOZ#0P6!tJ7r#*&rndUe*m6w zgAXo-jlP3MSji}Ekkq2D8lw%ZhI4NZf@jwNfBM%>br<-NvEd5I;)DNigvSbgEt7V3 z8Cz?S4x)cIc1q&y`Xpbp8K;DdhQTeF2E#Esb!^zpDH5!ZHs}SO-j&&dCJ2HPk^j~& zyi9&FpYy!0Z=z}bZNeS?aAii04I7#9QBjggjq*A(^*S4B*$vW^82JXYWoI495*4!k z*l&cchAi61!NGZ5HYtH>ckTfC&E_hOxKYB$Xgon2+c%8%#BZhkxA4N`Ef}{~7yWKi zLJcslFAboHe_!cp%_l1Om~D`Jw>-`4KK)C%cU2suc^IW=3F~yp$w4IpGbQ#|QRn!* zfM*G()^>bH&^-63t2GV0iU2SYFyz%0fQ?Yh7D!@P&wRP<9!ucQXl>`N@FqMBPN!i1 zg1$OcIP^xW-Yo|BBP}C?#Xue|UFLFbRLL5N4KSfd_%SkamfE(m`19pdxPH&U6(PU> zN{vG&A@f70y^Yym)exGZd8j!yXo-0zsK)wgVsR*~REuf-1t-W$`R!Qe=k=eVH^*KR zef%98u5Y}XN1|K!Nt8(C{v5Ks#_s7HgiiiZ^q)Ho5QdvQjDTR`>!~x@UeqBe|B@@p02E4FmiJKhAotga|w|)90&g zg|wvfL#0=m2h4Ad)hQ1|nSkwg4o6due6CpD^%RC1ib2MevzW?a9Ej!ez{3dy46(i_sj)yUkXf}4TaCx-ztzmm^3B@}nqmm;&5(g+3UQ6bF~9IJLaxkuu*)H>|YH1hj7G_`noM=ibFsw@JnEk*r5}xI+xy*F;uOeQf(lDJ_s3|mMI_r4r=#A z#lta83+LZd@i&*NaMFpU|4{Hp-r9SK&4`NKrGdR0Gd(AO#B$+w?Y@YvHIOFRWra~R z{i$6MNDo9i^~1jbhg-U|T-eEd!hodpd%IAc2mC(g335{S_mn6E;A#>TWPTx?ovuYB8>jYJZ+Dm1_?#<*PwDmS! zW@6d$h}k!awkEzIt>;U~6KUMI^@Vf)lVn^c&l8fD^}L9e-PIawW}IgCSFB^odeE|L z1=oShA=_3$buc>>tN3>Q^qXxe171g{=AYKbQt70pa!`_xFS^@$ z^B4!dtG$mp)big7iwkL;6*;dHOVd?+?D7Z8im`1uXf?kTQy1l;$P_im$Q&tL@7+l9 zjS(55fiWxv$hk3kl=%!E;~Dfjg;j?O(-*%|A8`#yS6%)iln=iZm=h+MPFb=kb=Z-h z6FZlF$t36KEDRP0C!DM7?T+0FCQ^h4LgK6g`4b2;q(-ijN0whDz*@oaK}@4^kj_rqGPbH;lqOq;fu3q%EW?S zJWo0M`-OR9Nu0F3JUo-=p`!Bwf`(bu9|jmsfQs&7q7b0M@qzAx{`}Fpq`d|3a7)O% z?z^jCye}B&4?37D4&a2MKq^{6^_$Z9PFwv<;y(#rkwBE;ukoLeVHkRbX7%+Hmnj;w`;heO6zCN9luzb?fXU*N4!rovInszT#{3gHE`*n{GZX= z&~ACDt7Fq2o54j;hiykSq#umV&hXwJ$Zdt zbZ*WfW^ZERcN-C;rNWa;0?Jg1ZQ{Tcq+cw5qot@MiBfWWQSy8B%Mbufkjxf~GParM2BOK}!WW<91^@_|MD214$M!aai#}@9;rZ6G1(qekEh;J9DP?B@0 zZ=+Kmxu*}3&U&NqC*-Fm%Dm=>Zp6R&W+d~1iH&WwPRm0%a=bjbz4sl>^k?X=P&#EH zlT7L_Nu$~|owIvc!c~iIwJLiQdU(}BCCEYpVn)Q{8N!>XN8y6_me4`xyYEqKqFCzN zCOdMO!L10Y-Gzl_4e$8{nbyJ7Ys}(Dbo!(6>1+gkg`xiC!AW#Xc~oyH8_j+Or=Wm0 z!`}Q(jgS@7{>>%Y=*JoX!KTtj%yM7JxfnsWkzKgdxl#GJ(^2-~$Gzd$Deg17hd_ieRYhNB?$u3G zxqC#Q2K5lwiBJa|mK&N6-JI&9Xp4t_gh#!f3D`rRkKsB}Mhhrx_26Df zv)vP_?)$+3Cn+?GB%_izw;P7JI&YR@0e2y<$_W29Gk@xib_z3JRsYcHM;+4Y@jW57 z_vfV~V~6jN@8-}{LyQfvB!~$Qb!rAXLTM@LY-!+w^j!spf>^ZsIrJt`sWW*X>aixI zx`LKv$=Nd>Pr4#6TEFx3d8Tby7qgjL+VLe(m__q?89;a``>s zyW7uYj}|nF4Coom`~NDM@79(~gpBQ^FlbVLEY>;nqb-x8mi!D5@BX@Rm4orkL#orH->EZgiLaG2!`vux zXEzwm>xlA$&v>Cs?~?y01*n3-n!`|UtX9&HP{^jc&fpqT=LSLJu^`w5=KYWLK1I-3 zhWaSV!Ol%B!LMC_REwK9ZPxpZDcuP2CV?ORU8KvL4rcb*aBmw`hl%?B$0fR z`T!sxG)5U6;cy;%-y)OZFs!hZWHj8m?MERcX@($ShW8727(9`jI6&JGslvxnQ+hVp z6UA4%C^<0cR!d!KS0n>_NM+u=R}@S-5SradoHARl)}Osfklk$xMXFf9+M3s7E${-< zX-?XC=;#o@Tkz8fX-y?xbUy4Yx(u7fN;%bztyIa~!1$@S$!bzBgw%dZY5dv9kBdaZ5rwOc(Q{W7@2wyrS!cwmNa|tc^6&2 zFRAoP!$BIEE?`M=U3ETQGB^#EuGU|WK9=&yE-$_FRC^W20q86 zib}3?zP7plTZC7nP$2Oj@cj$N6STd_d|{Amuc@Xd{@NsP=8AK9JCfCiS?o1K*B z&6c@(^LnyO0wyitz9W295s|e~BWz4-k+n^JO{DQK*R9i0Fv`i;4oAT}|+>LchR;S!wNLWg4=gG<$4WZ3|5 zF=()0vw=-P?gQ?N={Tq2YjBz3Bl+EvHAwiNB|;s^4wVnK;er*kDIVRkt1V{>`h;AL z0$e)gCU=@rg*_!Q4jW!uTzDj0mKt+Nm zsVC~*&d69^k`I{?cY*YT(^Tb4s6Gz__eRS#Y^TrhY*(k=g<@s15P^{JnifdgOTPtd zXvI-h?#h_pe0PpI+J_y93~3?bek_u^1^nsOE$-k)HZz{4Hf4_-8B<-IAX*tqKd>zS z>#C$(BO!hm_X6mKnXa050Z2rHZQ@ff*yzvSA+4fTsF_$|z7HcLu!rCNW44-%DVluD zDf+hC<7c=r8x)t2|$)_OwC1vfVq1goIp`O2hU+@uCs&E;^|DRAxcK^{1tJ28nJjmmuj_pY?y; zBKbFzX}q-ft5@+Wd-Bi{FO}}BifwQ}TQ=jJMeJxI%;$Q9Z{Q~jk;IvNGU!J&%VF2r zr6X@G=S<#YPdLj1${yHa+)Ct=*lJ9!ARKJ^^8 zeY_^bhmoWm#N9JxQ0( z45x1I>`-AZ&cBrabd-R28h%oL=DUepx!%2#yR^Ja3IW+M3+nLO6SKaSj=h@E$K7tn z$rSRrbg2phoZX{g@K$MYU;fJd#&Pn3Fa4P51A|2P^GL>P5|LpUgg@E5Piy^0e!%F&^ ziP73aW0TDKcPEQVcIJ{AQ(IAj&#Hg4u}5V0O2ys^^KF!C(pf%HlMl34%kyz6DhM|G zSD)=X@&Wc|N~as17B;}15runwp&n^OG1aA;z}RwmPei~HZ;F~Jb2z;krFnB3lVnnFAp(}>M4JBb>mLo zDA0j+Y5WbdwNa5O{2Q1qWmRu8 zw_5mq?N`v8yv3l+=G?G@x z^CRNy$sr-z&OlZIc15tpXNUn|#hT zbPWP47F~VxFH_?lPlZd|o;4c}vfb+_;ZAL1z|S!MDUKvrsD|9V+&)!F1(n~lzrA`S z8)=DrO-L>MN`w95j3%7!efCCYo1Auof`jil`BH~%iw~!NyieD;qSr}z8cuKWCzKgW&m#l5LA@hxD zk{_Ud*CNg_dr3oPK&MEh>xbxn{+VD+w&MQHC!+wY!JgNbqg5QV%`bkx3w~3P^U3=W zHLdX==K8YK1VJu#D~s87Q>bT86`C!bgC2YL9#R921KkV%-uuX#!n{3IOxq5Q-nrc8 zHlUe4KFnO#dl-OaX5bPsod)fAy!`+(C^rk4|MT;fzI3siMT1TeXE?N$ZUH%|=BlOG zhdm31=9Coc`z)i0tP#z)luDAO%h$**?dR#22%b5wRe^)P$r#-XkKVm7%z*xm)lA{T zOTzXbVJ6H~NZjrA<{u%76{6as*JRUu{SH>VWhv$@8aZD5sY#k1Wl7vfjXRWFtt6Z# z*inC$BBNd*J&;^Au7DAGd&ZrPX_zQ3YI2l=S&lO!BuA+8(3*;0z?sIAw(Betx*v4Y zIseZg@V-rpF; zAvFqrsJiH(2e(f&9gD-Vt9fc(xBLEPe5gvCNn>Y%y2YJ!;ud8RP5!ch#}CZH605EK zsf#i>ILG;YD2)vGOTl>DX^({R6trP8xmRY;Zx05V_tRlaN1EFE(QAzSn!{;}PZocF zP#GLTo+JsVJ8Pv?uwq9NkRQ#);cc(ECqo*=-<8c?^-IjwT{s-BZ0Rg@aLXjjJyFpD z?sq0)@`8HkCh33LWn;^N->--8y&??o@a6{dfx*{C(OK6F#WVJyw5G{mM# zG~D=tww#h|o_L$lR$;*Wn~iA$Ok^1azk*pLHuSk|Kl~qT#d~G1T(X=%l^h+fr@I4a zRmDmbOqv&7!mCgCsCL?fZ3uPD0A!yk+iQ?IVQ_|L2{Z!+!qWVp!zl8i+a$B@cVx-C zeej?+N`P$NnmVBDa?KfCIDGvLARmw>Yd7Glrhc(6cqi53a0ZPPLSL}W{8HNE)V7x# zFC*!YeD1`-5L_i?z44-*#tILYs81WXH^DtDn?(0qWI0uF1w8P;S+gSlR$b#sB4YDQ%Xj*Jk z-`flOd^AMHm5ULi=$UkKNMtyts^;L0y2Dyol(H{@2^{i$ZziSybXY?cj1gBo!Op7T zU$_afepsen-9309*(!hZ&6@45a;>v33QG8<%Htlro|ICZzHSh^+`5kihQPXSYuC8&Hx$L{=j z=0rjRFBBdt#1J3PLM2NWwAXgvm(X!`n!h*%sG*R|S6g|3e&p8q)3pXLfuxfIgn3f} zmr(-GjkdPQtD^M+tjE9+%C0BM_k!%+a?2n*M*1T#Cq+gDop`(%=+8u~Gh-TMAiTz} zkqkdl{^ISEiUuMcZn8 zFbH5NLMT%|^7A^#GA#6R&586h7&zKbJq57om)4i%>J@zCzmRyJ+wCV0Qmy#*vHF2l zygqDfUY!l}!gueuqp*bI{@o;&Qc6qPADMo~ap4@W>rhhBzmwJybEc|>Rz~2lf3S)? zYO)RE^I9U!v&75WUlwnbuXW9Fw%_uwXIjhI<1`|iEDBhOHa8+zPW;Ae+pr4qoNk%7 z^h-EBp!2bjNiQre{*aS0T)=XpR8PE`M5+9kK>1=6F?gbwsPzpREG9D)#x`5(hhx1| zpRD)0sXJHGSr%@b4Ay4}Z2DJAV;`3-Q%EXt#hngQHi`Ls}g6)=kzH=SbSvocjQVx!8{ox6Z zh)fw^bxt77rR4oi<^4*LaC+9xb(A6k&(2L6rX?7=h;=YK>gk=y z9(FCEiJXlkn{9ASDCVTl5m@_a7R!|)yrXTP{q%)AFMzI73|~a8+NbcMmyWbF-CQdd z`$HpYcF_Dc3>PP%_wYBF{AU0(;wRUIncQbB18@6!4qFZR;gx$JE9Ub-)@>t74B6j? zHJ3?V#SzfPGdZ9rauUBKHv|gzGR+zTHXzGK}BIM8us^hmr9h|CY#ckBmoOs=_OBWJRT4#k zi(r9A200qryL<97Z_Kqh#30s&0TNUbbl83`!w@A4Qw#C&NakPSKfAn6qfL^PD{!jr zLZ9Ea`FieeW%qcu*=gG^d10)Ff_7@p#*B}8NodNs$xyfjR^|-399Ai>|EbR(Ndaz5 zX9B^_NImBvr!LSnBkuy7!5|_=P73QTy(B(zLi+H%#h!8Y7-WhXc0$B_jhR z@48IG^Euy|@BJg4Ou~;2g+#CH){k}nzQkRmAVcBwQLFh0AS9%dHgEVq!#fRA5UCu& z%CfNOffCO9|5$UZSmd|sk7fT^pwa}|zyLYTuv$_O`v=f-<#P!}p3Dyb6fH^;F~o z_bnsdrP=}oY`iN-0C**kzdpIvh>3w``4`sj>~;k2;y6EB4oxVa1Kx|T{2s?nh>uEz zn{%ls_;$+RBrJqKonDC?R_E;ioJ;;pL_a_fxLLUGS*c;mO`#cHRAdp=ryAad-e8l>(s9M!wyy?gX2~B9Rf(MdHdQK%xhV>{pgu*1arc zjdCwXk;z~P$7$QXbpeO5{QkH$4G@|omCo5Av+f;x_Vs=f?VJxXUnGl{#^+w{s_8aeYb*-Lw12s# zu-k2PYwk}O7Q$bVQKi$G2w|KK90s+czJIS2LRKi5OF9JjY_ecbdP(k0`}NK$%pswx ze}5e)viL!Z=lek6LMtsV&w7%OnQ1ra!w$8C@%w(S`-lx>uP|5XaHbG)PP$~@Z8DzI zK?XMu8t{M_N*9)j8;jHC_l8gdAi^N?BN+-IAX-Td$D$d%I_ybDb|+TXs4-wvEtZRC z?!FTN*bZ!EDn$``t`nSuj``L?VSA1}&(x2%z#%n>?!Ra=^^Sj=wwnL5HsF{B#+`Rj zgh?n500}F50GcZqKp8=iFUW-g4()*{0-JF^0$@#Tqok%Lv~U3)EE(XO&)zsQnn*(= z|1W~RI*!#8GQ!xhYSIsIZ)5<>M6k>m=lD0H4G7`~+>x4|7n|9b=x9zu4GDh8E^5Jt z52glC;6ZT;)nug>r0Hvk0dm0hg0UI(0ADN{kPUJ$8QO^ug%olzfFU%pKanwk7t0Kk zqXS|8<6~;v;Io;90WNy_eb9SsAlJp2bUclHf}p_|=xIg~#3Ama z=(&W)YTr9a^Z{Q5^gQT+k1G1lC9WVfBidjwk!c_1!$Xpr)Efp2#;Adq4and^mp5oY zEHKFVcJf;-0do$Uuq#x)mg4=m&FN~}e>rkRGD&O}-#IFPD<_g4Ljr`C21BWz|9b9z zyPj7CJ{R5<_rGqmT8+UP^2L^zk)IVH)PXRB;$mT9n&3YHNpbe6;s)OI`O#bdUV$JE z9&#`E?#U=5>T#41Kt0VB9u~$T2Tg|y3iQcAxXt_f-(4c}eGqdXtmX9r_kwsF9na# z6_@mf&%$f-ii4{N3a*u!orQqy0>i*aS;^%j|CE&mz$T0b67={1Vng0JaHFwQu7I={ z6f|cZ^(Yd4jqUC2-Rh207m-PZ?{eCB!AlX+{_hXfHTBIsOf2hcjS($GSNlIuuz*x@ z7KlE|vvY9FS9SzyH#w{=AGDu}<^=#N@_jpy$fs?lJ0CzB!pX9Zj?eNz1GpcSKypm9 z^NIx4zvU*|nAMsOSO8l?!t3#*WkRPY|Lu)+CXlD%T>Gcnw}bU@<`y_Ds#q^p>sRwf z0LxEdQytI=#R{@joWxg0@;UT8dw2o$MUh68jzSp72ng^C`NT?A50Hk-wCeJ$nQ<$V z=`|A#)gfofb3 z5LUX2L@+fwtkD6&70%%5uR(xS#3d4snd_Fpz+6aFV5D=#ZMW(&$cG(O;#V2w)?0Zf z8~ylCD%oT=lZVZL!~YflAX{>zJOhT&)5x^Ty=eHfouxm!P@ETsbz@uxJkL=El=Fmx z-YGDgK@t@Otsg!|nsku>v5l%jZRi4M59t3fP9!1mA; zeH+jHlb5}@mbQ{#xHjgU1cLE4VT*kjTlI?PWLCHlt7DF!Z&b1;_1lSvmtF;YyOvnSA`*%`5stDf7ZN!?zalCQ_>Xv-BA+^jo0i&ya$ZVY?l~zN>C307V;e0 z1FgFo0Rdb)oRAW#(-*x0?JOWK3W6Hup$^Uz_ZcDc!~sG9Jb_fBE*qDd82(ch-Syp; zP{OsqHSF{MR<|SLd!`)Eb6izxgMg{(^QFj_=SO~WLC?Tny{T}YfuYESWkZSl8U<wQoa2U{A$CTK^eW0Td1Cei6t^!%H2w@7)dfz?L{lAsOQ)qKJ-aC+ISqukQh8^ofeBMU?QG{5F904A?6;_Z5?wYn}dt zuEJ&P=c_*hCE$MK+c%*!jdbHb1(722F=|ZYJcH{Z)-rl;SW&r}b^c3TWOdGbkAy+W zkvK8`OW*Y^yb1YH+IF*k+-8Oju&&4cgy9K)t^x4~&Gku&7^|@`H0!?Qv|Zp>c=yoF z%`29L{NLi$;IhJ7f0xN8_;P1T;adQ7IE>gl(BTznIKgDF^lWQiEm2J^jKG`D$L@wpkxf-DW|&7Pb$69UeOHGn>Q&Bl|cG zj({YgWKb}v-(Tal+P0%0x0b6madfhn1R%eZka|Af+!gCobgTFAEIL7w%va6Cq#z4; z%fkP+Z6kD=kEKXI#JiOlz6yA44dIP9P(`N5G<--;wWg zv{VObKtROPEL-$adei$}t=LXmyUpd-c$TYMM@B`v0WGJE24EK#b1kH#8H>N7@G{V- zR6)KNoo#(VgspxU$eivEa5fztyCZ{y8}`P(eJ18D<`-n_Tm2l&%*#9ErQ#$dFQ3?J zLJr%6$B>THXnSm0o9io$Cj;D?WzCp{CrP2yip#c8WhkD!f$~c0E>>#=JC+vcCu^sYWoLl zRud%Cl%7PD+v*>{M*ZQP+E4V#E`E%$z{6LmA)BH??IS*D+-xTPJ^VYl1oTuK|LUZc z(`V^show^iTCJ;pUJb$XON?Fb+>)nRx_8q-VoW8u6D;I7?^xywFos4xVE9n`GWl!0 zThly0s$}YFZE9@ou5@cZH9?-?8as2w#mD~q!C#k(e%}$Su-Fp!&z)XI#wH>Sj{!9o zAgvK6Gx?4*$*q4WNDB@natwBcW zEHZR-wd_^KY}DyM`o(mYzrd_v!|l-7mL{AxQ_094qD4pgw`N(|rZ2k0ZnI{mOYN6a z+kPi`z59s)&3uQlQ*(^KcLyn6R%K_E=H&86xFLB-#weZy4>8Q0M6flk(LFe1aF|N^ z8Pc@dL*maHfEemH?9aHkv80TCcFS6H?6fP@PP|G)&%L^0(EWIWMAK-*VhjV#UPGG8 zhlcR1GK`rbBm1xoc!v3@|Fo7;9(szJ-n;gx0AIeP9!1L?7Z>-n2>PpH*G()b@K|0L zwRrrUn#NZ4$e~f=VOvRLS7)z&Toc24c=D~(2^3uEQE5zrFUP@`Z?mue##HvNZAI*? zn!#rzKPqeW2K#%8g;7#b@slG4HC|yOqoWBJuMt;?()6P7maSlY1Chx}Uh+A&-y=dp zSaizmkfp;EokY5bfG5QzNGVZ5!hf8am(M;G{d7dd_<@Kgnqu5H%WIQ)1@ zwprule1c#BSW<)2xahU1_1*?Ki83MJ?7f*lZZHte$2Xm5n?#v6H*#{Gvq)V5jx{hW zg*A&si>L;yzTJYuX$|wn3B7wnvor_cpIl>TgqqlZVy)y2pRK1^Skw=PK-8{1_>()& z+tzI1bKHqLP11k7A}R?gY^m>ioX>XL9;%LRNe43ZoMTAdf1(oI8&>pBA&t%fSNs$B z;wW&{guS>yEUI=zlidT4V2*o=tl2#oP2>Vw$w%m{<$7(AJ?(mszqdX0k7=O_A|WUL zPTKvVpZ4;M$ququU#oiInbQcp8Im#)sc)`8=Gsj27C=b!?LfB`bd)Xm7qmASQ!~<@ zw4&B)gfU#;ZsWfbUfCZTATi27D$M)f`w4D*yGH0G(Yw8y98d_ejw4UMVqvK?#%v^* zyDsuY8E)OYWI8+iY1{ibgSpnne(RaH)mQI)jo#MvJT_YfF`77&U+UP&ox_vkfPW-X zG{ZSXzZFjfJo?Z+f1A^wG1_UU0sUv5G4ZHcBTPON{YHeu z*-)kEZ?=3khkGc9@@us{L9w$H{lBd6f0X8W+#KFI>H0dF2BiE-OlQt{tM2y|u&M3n z^yZ4}(V)h|54d_A%M^bE4we_XPPiK}qQG1&C#LkbJD5}q0#Y|8F>FEZvwz#z zo;!xvZ2M=U;DRJ>TiAxOGHz+H&{9Y;Zbtb%$|i-isXJt zX+J#@CPJnRnK_PDS#F=Mhjs2Zb~d1vHS(;Ny7L>W*7SvyD8!0FpbU=I+>lite;R`G zt0p!}7@KI=-5Lz>2+$GsBnTzdwvQ{r)f+wZ)H@!K{~n})s{F>BK79+W6`sf3Nibh1 zG!J1BUF{~}9DC0YiZMtiLhSohfvakrwxaKdU)M~%)WBcEVBZVK6l^9kF{;Ed45h52g;dGj zp~vTSh9Rx!EtBu?aHiflAq1SBZgUenrnoubI&{sbx2#<5!Ifmv^XeIMb-b}IP$GJ^ z?D4(2{5j0{KjTG_{gC`4IovSnf9pu8sjBSGFyW{H1X<#eJBq*OUQtiRp%1!d+> zJ02LljxHR{8f4sC8zxr;MF^B?f#yFjv?OX!4n~Jo90^h*xv_kga3lqR8m5LkARl-%r8Lh(ITGQNm*vKg%;l7hcw9?brHqDUNP>}NDJ9Gcp0r6 z-~ON@)xNJC*a&|B$(Lzr^&&iTrLev8WqJ|d7UYa*<3LAud?iMI(i?DF^uRwn3hS@4 zAjES$KDpbAQjJ^9PSu$h{! z&*NBR+H1EAvm6t;)2CfvYkU#oTm11SYN))4Ze)Tnn^TUQm3Fky*$C9gR`jv0>g0n? ziV!gCQ#XrYdoW-OCCGz8Gnf*7^*qzV|LCHY^*6MI%+nj9#yPaKum<+#(i^5I8e}tE z6RNXYJWLs6*;JA!uEGLH3(WR%h?+<|pwqfSY5~l0Uy|Uyn7vfk2TU(j!+bH_c@)x& z;@kue$it%*INq9^X-thWZ@kdbrlTuB-~GAYLB7Sb?@~}!uD263e6uM5;9X=qHwhe^UmTwW-xH0+R<#3CadMEwb~@f z0$48#2qPYv`Dj0<%pGXtOjZ(Fbqk6YXC+q0my`G^*+p1YCOn++MV>|@C zCc&0lh3QTrX7mCFBF4b(H3ZRD;p+v3roWMjbO(m1$jPPiZ-xoW{AL1Tcay!V;}BPb zSP1`Y1#2bVM4CQ~l^T+=KEumYdu;D0ey+$Z4Us1%=ENv<@_NOIS#z>pX89rQ{C3PGqj~9r;Z@3-E;^z7zvJ}1 zEAA=j&SKC8rz3%ci|r#`lu`(F1g-N+y0XhySC)C-7DiO~vsAgP5&`FlGQsubfXk(C zmf22u7UY@4qTOztkNw8LZ&UV=H#e*EV!aDCcrM6x_nT-J2Q89;zycvNe9R!eujX3C zBFU&xn5;95wXR+8Ro?4k8$#QCfCAfT*9IH4EPXPaX*O%l&(XiXk$Msc{k|1O7;+a3 z4VLZ>riVAqQzXQtQvNcd zd*Gr$=S@0{a)YrK$bxbvv$P#Q3Q7(PVzTxEDrYa-MNiLeo2KR| zL(M-Y$G3!j1>ABLk~_-Bz|HMtcM_NT6>}f*%xtFrc{!ihRVuV}ej`k9Fbv#3sBdAloL z1xcf1waiBteec6L+N*`z?Y^$w+qh;ipU%*X<_b0o|4B|rQlhfyaC!2?ZgzW$UB~Q} zwR)?CFQdYQa7A9;>0!U_&`|$1rG?+sijH%FU+(qEr#$&HIi+7RgS`Nofksh4KKwbU z*KuWLV-o!#1sVtqG1E;}wk&=2Ww$ujY;Ia%`XO9{(Cn!B`-IQiAgnVk*xkmOq+$taGzMHH*kn?F`P;{0)UL1!{^S-z{= z9^5B-G_6&}G$r(;0l{5~@4n zKj}@%bfsRNKW0*(mq8sY+VCC?EQRt$?-w1d`&{9LM@Q)_^^~@^gCD@QZ0&2CsHR58 zd7nZY9a$xo!d7D6T>Nab>@9IO#J0RbD&9s^K8)}1Lgj(psZ*e` z1L?ran0ch$7?CBl>9+M(B~w9XVCEYJQ~S-x4)$4&@T1ev7J+$D8Zsp-zYqW8_D?N$ zXq^S&ViBkO{{D1xDP4VM_Bcz+_Qnl$B1>|6vt_3%x_PrtYps9f`nw@*hqSYsmiv~h zc}i{r7I*4~Ihe0*Oc)pp0LkH%H{5U9QAfLahJE-Ygz28hDy!A~>fBbLRb#NM(V=Of z_&5s5ZyDL7QbysMwD-A|eK-%3nZ9U43 zc2#OS!*$@RxM%&u>`W=`E}lN(^wX7-^)4%-DJBZg%%MWYT1`Fn51KIrl^$CCN<0_@XFCisnIt!)xZ4sG+=>>hapu!o+JnJa=yiEcj2 zRo^O&E~l*QJv<4giE4IHQU)>S|5WgVwUB_y0xJ>Pq`~nSHUp|}NG1(q)$xX1+BD={ z!r#K8$EJ&+;+K6=^)VEQ$yzn27FX{XK7&AH+i@-68=H{sR3YzJ!9=4+8$i72dg4-h z;p%r2#u5WFSvZ`;cK8q}nF*`KF`b=lY$Q9cOT%5fuQ*gCosMDWvA|5K`c7t zFGIHbMFr>O;+r>d@a^!Za5}n<;e&IatzNxqMq?$tUDbE0xkI(&$in@RUc&NdQor5Z zi0EMy;+s7|-66|rc`gG94b`BEOlMrYI3M`TWGhPl*&HPIPnINQ zEW6Igt|$%_IfC=|%b&MPzoaz_Var(|>l|sYOn#4uJI-v*b=hI=Xt@(B@Y=VeQvOH# z^0WwP&rv>$qxE-_@7sl~^?XT{-rSSP&J>Tsvh0E1+ui`0RQ8ksI9+RkYbS!XPKI!S zx_YDN?-dnq3%8{A+M2=BAO_(Tlw*e?#OwCQtEt#q!6>n`NZzO$!CB>Z9lYfti6_Kx z!tEd=?15q95zVXO!EC!R0V-(s>?}33Q?a3&`mD`o-=Bd@Uz^#=z%keJ-UPBg-L>$L z_%XM!6$}_BnnixXrrPH!r^6lpYzj&DYxMh<2`;Op$kH$DNKbp(O5$Y`{QCyS9=@T+6Fy2 zB%T=b|GdcRe~~EIZs7$iOQWAYwhRc<>DDz2|g<*8K9!OO1qi0bdL|bi|rDlU_aAp>prvkup0lvdFi5E4b~q)V9z? z0)Lx|{_XO}dNSy)HCs3p+(`CAJd?7am7^3$P+Z1Ma}+Qty)v>BUj9PKJaz52oq#y8 zXb`1jnx~I#kH9}e&cSjR%PO0Rt@uW%kJ<~mnGP&+*ckQ8x*R5GaKEI^y5swn`3(tY zU_8-=SnyNjivDq^H%rGr^5ESM=YD;Xf>b|p);wxa_%9b06a)pE&je>*_!x{PDcqcB zXvx+-CCYqXDSbGhoXa!ei00tc75Ow(g>e$abzq{}OqwqG!3{M3JfD$v-$}3fZg+1y z8K#@kZaR?XDq7TXgHdY8xS<1H-LJspT&N?>TsH8r;SAj+zp6Fd@tfhSjV(uJbeq4! zN}{(Edy|_~d)pmS7Ip#VU^*AIV%_)OfwnTEO&$$U*gop4=P#g4br7n$+d3)nOtf0)okx4;W3Ft>R5cLV1)p22pau2K zw$8lH=9g+N%kRvja-q+VyUHhWS@JgxPmuoY=N-sqfW32)^$O$^ZyOxN;Ejgj{@o9?W1?vxcN;8^r{VrnZc=SEgqt`jjKKL_V|==B8Ugqf;pI#yew-lXf(Q!Kduj)H zO1T>0b4<_7Tu)x|+-Xy`1O6u3sm9L}Ey91!;t+{Rt{_22>#a_kgoC}|E0)^*qwgUO zB)lp$Cy2EZC?1!-+!IHT)B5)=!mGL3o`7?|#YA1yJ_@mYt~o9XV_ttT@0Hm)MzyiL zlamu*h5NXX%AlFwV5{rV^ZO|bm)->YfPjeGbW=n?p9k}8uY#z~u8-MtoZ-vO4#tQY z!H5JQh_X_@RlRKCH#8IvZ6u|P2I;oNUG@{&r|1_%WoG%)x7S8d0P$Nxxv}>gBbfoP z=iSMCaUj2>8Ss6G^>1EfXsnh`iq$mCGL~aTHlvfrv+m;gQ0s$c zAR?$P1EC^8 zgOo^G`bYhWs}QvSm6({gUS=cP6fr3d6KsF5*+WMo+szTe^lO{N^x>sTKPPK$z-OTl zUd5~Dy%h;(^K#w2;)NWKoR44d#tf+zHoS{n+e%B-%C>cOvkV>W2#Aaz!+$6#WtG8} zvMGHLm~zrq;NuNKyIZN}{R#BTXZ#n)D*VyvWr`p}%99djF>O-w@N_?8(br*Q;LyhS zxrN+p2sLE)Cov1C>SCZHja)=)l8aHbso_g@y+#+wMY*1rDWmn&tAGq|B28)7p3D7X zoF8s8vkaHPpym6Ha8^IyARb7_lW09GE6<9b85}=pH}Ag;h?Y|Hr)Hy4AtQOt`=TeX zfP(FHbc21l*>}h1K{du=MJrg{Za~Ck`w8&5X0>SC1=RK>s0S<)yFv=74Z6*pYLQho zOj5?ZS?Mn7mkMlu=~eNpxG=N5>>GZiv1tLu4 zY;7y7$&t4KVy4*7XJMcV_>T@f$3F;{J8{AzzzHl38=DGq*S$$AK=l+WX0u1#?{fRU zy?8vFG;f&o|HS=3O3DO~KB-mu?HPRqhTZ=E9kla!2z~qr3}CH4O37@21S)-z72La9 z0OA>H-OpkCkMB8NJ6i5O0r;sDM0BDdw*`I6AIktJ@Vys^8ccqEzM25ie$WbUBSJ%^ z0br#F0DcVmYp#d^C@}@Nd~Wur$!-Nw2Y=WIAg9ht=4phLgQPRRl+t2J^)n-M)Jj$Q z8<5_?{bl8tH7`H_x+4V$n*l7!QDZy~03R?GO+BYD-bMm{cMk%t81+NLp3ukzjE?-Z*MPJP|+G-ZZ5iiP%AQ1&{-m% zPW2xt=Dar|0~jPJWd3RJ<@s4uL<1aR7h?~-zCJmqdi)0_xkc~g0b!zw5K~tFXHP;t z*WVq0BYug&Q~?1d4!vTsWv<^mGA8ibgtHRy9KHZ5i6HmaLc}2X1f2i7iv7d`8}?+0 zKLEqyN6%p?Lf!l20!Vw}qtu2wz@~Zt4zt0q3RhRU@`2J1ty|89YJvFlP|`z_zHsz` zpwLGtoHl^1x=IF7mhRMqP&iYG_@;f)rUJ&0^DnoM&^j^!mKvBg^j;qJCh*~-!aqQE zs?z1_Wx9R}@I#0@6Byt>09PY%HcgKTpxA!m9E$t*0u>Pe z4yoe=Z^5kTA35_#{QxzKZ_eS&xJrYy(@;1|*<1E*D9ZB@pMS%7hmwvfuqAD*&+q>23Q zgoW%-a!gu)mA#}mD4<71MDrIk^m(0A-cv%|kB5x(96lgAa=+_ueejH$RmY)^@#Mg? zJKG%)U@WY2^hNn&Ak=w~)C2rL1C4fu15hbeAT&%ooQLuk;t$v>vM4+zHUobw{sv?S zby#QYQqE6aF8M6bVF(f?QNaLWH`ZCN1x6vJ^5F4}Ctu)JZw25*VN2iy0EhBE`LKBI zmIROz$X32+uhoMJj2N~U+@5d(T{5W=bCF+JFu5P%48^;m|NLf*-}QtB&pWZ{mhW;I2_>US zV&Vkf8_fq{Z{22YTLQzDNn z1XM4!lRg2mlQ2Z>d@%%i=z;O|zo`L+pR5+0R7$u29G(qiHY8b`PWW{#M05l#faq3T zDF-~ua4mq4In)7lf&=t=F@qqcjCh_1bYi;ZRp%(2jCP~g!~f8t#K#;#A4mt%2R;{a zFLR=mI`gPfew%e;MKlx1F3%BM1fU}(WdUyTP~Zwpx5g-lb*1-jdV8-mVkJB*T=kz- z#4C~cLhLw|K#@M5-XF4Q%yzxbILM#1(1FTCgDG$xh?BwJv-`7Mc-=>6mlUXKtoe~g zt_EmTt1xswfoQ)uP{}IW${xJ@IaLgGK9m!jJm|~ib!ldrVT_Im!A2o1`Bv~1h2CO3 zFg5%yChH53G{Qz>b40m+>U^Rg(j&IK-&xw%0dGGI+1Z5s;TSZG*&8JpP^W`y{mtSL z=1Lr_R<2%dG2Kg&ws6(Wa|?7`-|iJa+VJMLV#3SG?^*eBexG#|^BYp|L^thyNtGGv zrDNSWFzt*d9}qgk(+kDQd&7u~;bw4qKN@7tZ^7818Y5A~V7#v z`XZyLYQyg9^6IYTRz@C37B73JOcEXP*8^DyM7uHf+GE3yTab$j2nUAyx6vK&c(Y)5 zwu+0UmLz+&*4}JQ9}p1W0wv&aGO<(eJc%-`P%eY4u$@jv?UNJh z*gKTm2o&@FQy%F^KER{|KuoaELoKDq10qd7az#=g9U>k|K!AX-s-hh~_*eLE%csBx z60UIb*L}5lI#&F@MrOvRKu^c;vngU=DMQ1YUAD<8e|Ag~8ELeXugG{`GD>^gJi|vh zC5%jcSH$xy*MQUNW2}1;wa4#_m}*&U_*UHXw-sXz?$ch-_;nmgawQIBdr*@e8cav z4Q;IdM$4&)eHWkL8O%`gfbU+fuNcUUgNnU$p5jIMg9x4+2VEZ?lMfnINIjOp$#|{1l!aUoR*-Gf(o(gf6*SNz6!@_9oUkIIoR?eQLr{;W zgLo35aq*vatM(_C*3qB<(NTgGbp>UZ6Ju#sa8qx#UvDUiL4BODL7xo)&N6DErolVw z4nWN$DP~S-_zlh`%t%CfUPDYGW1u61%WMI+mKn}PPIP=}kJb^AS51*nPZn`!@q%tK zTtCh?8mWFBh{75W@sO-v`*4cWp37b>>C@`a9j5U^`}p8juDjSzvKq1LgPB3!q(fj4 z;wYw1<_U>l!~dBYW(te<0j&P*LslLkSWR2tMEn*Qi@zQ3)V%Q^m8clg=b%v~nTPus`7j zlY;)#8sQqljA79I#Z$sEx@{gEeznCCSVqNcFKFV#LBloP0v0*~`BKEOT(dYC$R+ab zFvhx{Lsc7|d(lFvnvjXP?Xy_xALDudTj+8jsq;2pT#mA2$}IHSH<_XmjQj|Vk*j<$ zHAaa(Mc|qGwa%7pJymfmUeaA>4)vmnbk}Py_CkDxdDLQZC64wHZom)O^ zS5u605~hm0{3({@TEF3Q1p;8e^bdtZ_%|H<2D_V{IYPCOJXXwqxuiTaSxt12!sw#y?m6tUwBAYQaDe$NlIDq?8NR#+9Z;;E0c7P1W-go z4?Ip?yY>EEfn1k+lqSJn-g2e0eQttsE$&GZEZ0la283XeXd+QmOho}0V>M(Hui8;B z#XpZ<{>3W!@Vy5b@nwC-N1peE&0M2q-5m`7zLz%RE)aG}q6j9~L_y%8k=NW^qgI(gCd@<#QccoD~KXOY}6Bn{x?t7ycu1^`s9XST$btA94kE!J7kr zLkNQ!(U-i2a5Y36!DfReZ8ZUT7iKV5qU>LZ3mjO5gT!IQ;0z3Z@uw?3VhO|JOb?!9 z`u9*7t^T=skL(Eg#(@u!@op z0h}$|=*aQD&-Y17K|!4-pqKpG-KM436C)6IO&BJbGZq=$Py!yMtwaKfIYJRX;wPdb z;0qypvH(u6e#**7>^7z;Z_8^y@G7hM}e75+-Q_1&@@8%h7vp< z?le`7NQ-R_GleY{E|ieVZrKbueJ)fBMvI^$;1UjEc)s+0wH)<`-(j_7%Bpfc6C3u= z>6e~w;4XjphYEZO7Y(pi!YnH+G@Kf)7YFC*(1DVoMIJn#m_nNAg#~d3FE}5ff3*}ltUprvO;<#IM5!5nS{z0S_#@Xi zrIoy1!d2j!z=EJW%kP6=nKl#Um|6e!=&t-+YfG3tc(OX>QQ3@ls=FfhED!=TGU4Ey z3RC!;NWht(p3nzNiJT3IEU*Fh8lDOHgoF~~Pw>NN)~5V)&QAf;UgkJFI46^G%sVC- z&=TNwUuiLE-YlJZ;{7AaHRcX?n&CrZcKm?GY2WY`An#$n8N_1;{aAemM}ip2^;b-@ zoHrhS`jd_7xLMDq$$uBj;w@rwW>TJ^rN^sJ375uD@o+R&4Aj83u@ReigbMk|q%Md3 zV^ughCHT)Ih2S*PY~p2>7lIi(jUK(9)QBbG4ibRdVs+jnGaJF_d6O>A=yqr8{A$rU=$4?H>= zd3zq-%^!hkG4B;j3ki+q^I_AEnSbUAe)?(j8s~5fQ{?#cO;lc_V!{(N@?GI+d_m$<^F9HFT8~{Z@Kh( z;dgBu3hu`?y{X~F`6LyUV%0$mwv&Yem0ubP+Res=gvuu@Ha0XKkP@p(AaLchzkmIQ z1SybHhTOXvl7cJ+o!%Pu!8wsx=>A)8--WxdZr_upN6ZW2B5+E|HD=Q$BSE>uYp{#$nd! zd$Ng*C)}$fm^T>h>wT)orEaP1Ld^7YA-FSca|IbiF7&ht`Oo^rmphvmw}c1#d3j%l zPxWD!^-RRF;2(?S%%q(Tmg*y1j}o5R<>ZOp8h!8j;CYk5pKFJuXh1YyG?x#*o~4mO z&aN>xd`&D-^{kyLCHVPj0&@SJt{HEy`Jago$XhPUOdx+ucbALHGaYdY7K8pH=W5n!#&+vtfVVJlJ79%ek8L}8zdBQBskA~xAyk`K!(TM4;Li|__8-C01n7HV_MYH zV>39rGG6+>Om}wk;_2me$w_47l6LP27zpvcj1gtCyqvbkjcAT^p2Pw@GYXy%PSFm4 zq=}<2B;sMw0MxHOLj6!tApPg3$Q;Y}F(jL34$G0P!poai2@dH}=H;^=-?oFM3%p!p zWE6OteBZBF)PWs3Ew3aEQu=y=MG#YLJFr|Mkt zsRo0AB}Fjvb~MpicnH^HZO{9+qrWqU-MFHHMbSP z2xd~F!iVidv-!|!^T)++(}jMFUI%WPzxYVee6B?wtd_;ByR6u>37)y#0^ z?6H|U>$e?F8nkDhJO!EdW~1JLT-=#?mOw_Q*&+cswxm||dWrv*IhSNo26 zwGV2h`L!F(g5(L=Wq+RNTh3diFlRQx{Xt1crCO_Q)k*D#mn+Xi9PvuitAc3j+3gwN zz4R@i@OhtLV?a7_9Q9gUjQi@}kMbPls+|-v24vF3EE`f9({ji&D(|(SwOQ?$YkIVD zHrWykaWDx=GfS*6$lzv&%>*Qt7H%Y=PB1X$#_;;b&6pC*+$sQd&zAZHxoH>8nS*05e?a9PzDZ|pB^Na1z)Q*YbL-g`}vVGY-rFJ#4t z2wrqeEQ16r-vV!K_ z0~h8uKtACCpI&S}uE^sz+mIq&D6`^Dj?>>de4jl?NT4&g^>_3Kph`*cu-GDj7kA*{ z|29T`#lK)K*_t2n#=JtKbazO>P8Yy(LrmtDIbkH9xloyaNZLNiUat|E+hz8hN-45O zRkN4Q&S(DI^fbG^)%{6fz=hcb>-6>AV9}1hdvFD8Sf&3e1MstKmX7Cgd@sK!gC8F^ypqF! zZz&;3sMkE0Hs9iyXP%{?t%yb6-Z7T$*j#V9PB_u(8sHx6cm-j? z^!Z$pVNmK!HL>v$-%vsFSxNAz+h?iXCB4wu@;O#G zXRm2r{<3CMyJYLsl3xEx5Az9a(IzRj71T^u^~7#}d}Z3pi{tqJ|Bo{rIV8)iC$oam zHg<-ux#c#Lt4oskID>(E1j;<0dJGH~?$FDcG{}Ltt=soZ>*_3j=@FXOZRuTpiE?zI z>p|h3$ZD|t`n0mMK9!^YE4u#S1!Wt|mX7*zMm8vzmE@NyvEK9YBG5OM4iY>r+_{|h zfxi(c4r|tP&40chMz&t=pk?K#GM1MrGVA|-d3S*Kem`Ys=>mje-hh#L%c%O1Nj zO^dB=NgV%NJJH@uYyY0km}OnFf5F%_W^=q8p$UlBehIc6J>uKzKwlf@iuF1b;9<_u zr>_ zQ=EeW_36cEHm$RMw)a49JkF~B75WFKBRQ4g0p5XGSwffx&(xKA2cBO^%pMwNO7rO` z!Q%)2(s{B_Ci}wS?s%XX`}R(dbW6oRA2KfeC*pm!nag0vh%uSvhmCOEMIpn23fUb6 z;-NP6w-z$95SIx-rPD{dl%n4yX44~7xnD*R?qghbw7Fd7g|&ePL(e5$-FL!8quWCm zXz(biVv~Pl4sO!;F?UZ#M2zLcvs2VW5Fr;Gm#E~;8CCZF@9m+(_>d)9NZe zP$d<8pT5AQhi0ncb@S3y%CE1iwuJqn`KjkA1E*c%-cIwk|GV_O^pBWS>$j7H$1!5* z40BoN#MCupYuB`QNX|jj!W`~&i`T9kvc5)2Hxy}U&!LZ_sYJ1JoS-2|(wnu>wr{tI z_Xh4*n;F@DVY9(;IV0(*m*)~Po_dn7C%!G|cpZ@oHH-Qe@?<_9>sh)cou1f~rf>!B z;6ZMF@Jc>&9YtsB<@FJA$=0)M<{7+(^Wm8o`@`<@uReN%Z$h33`e(`!hc(Kb_r!mn zEVm)6ridpYCnPs5;caw%>R(!}f3mFR8iT)8!}w~3kI;B=IhrDv_h>lKF>WK!bR=tz z-vZkoh%rk-eS8K#U*FMH<%kR{F=2Qu@^E3gIAF%z-x3ZXd-x}*6MKheil4D#&}ZFO zWfpEhlGG~*sH8s6ri>BKM{ek{pewyqD{7Xy`HS-gf8GCz2>rS}9y6s(0!HJpF+PU2 z9#}s+=_iF}AG6<$6K2)5mEjK-9q_e|6AheQyw+h>$Ry@PJEs#jZ&;)>>jH&^Gr*Z3 zSGR5(QXkEcWx2Y%vB}Eo@#xA>|7J+&x&c?!BY(ct?l5{B=24GO^#pQp66( zYbU-qVBm;4>8+>#ManVX$orGV6>I zh7e*~{RH~6o_iOTsC}QsbI1rhWJzX5K-H1zaTpvm#y-9E6^w)NV?ybZgEUHl6rTYN zD*m{KAOwCv-=&em`_%^pWj3gX$8j1Cy1SdC-g>-9weI9PNr*&vBdbG*LXw;6Lq<4} z#ooP_{g1doT(YHCkKcNwR-$Vlvj6X-3!PUW&RjJ*XhF{cJ9iV(;N0T?seGkem8`cG z4FO`R>5jU{Df=y6TICN7CMOrWy|n#B%swZOgJmcC&_4HOIgbC?GFknIV`>TsN|R9j zjbq3de*K%|iulE}S4Jx#LCBhS3wrE*>}`+vz6!soP9a?&r|^C1r;tpC#J{9M6t9mI zb;(INNfBPcot)N|Y0WXf`;djazbxd^Yv*T%w^5RUt!>oE+oYSE6{BpARxqZHh)hRlv^pzkOhum%G+GKj9!ho%u|xXzu1uby{Y`Or?1+pJmQ$_dOdsrqy!jvmSj? z$#6KR*-=%f6WMv$=B;V0&Sx#4WW2Aj(^Jw=Y4Y|`b>y!Dn;rg$JkP@ERu0nMBx=qe znUK}$JrF+kD1~B2z8rb`bG>_EbtYDT`$FKVW-HVybj4#A2Ktp?0@-7_;8UpiGI{pK zVyK-kJB6MoK^jk1QCiR3hF3hwD}NSM@d#D6HD5-M0!ty<>PiSG$C~G^WezF)2gz!e zgbC&`doXHm2}3m*LnKN#86i(MWl*#Sr62w36)8JL4o(~~li7FKx=5R8m#7eS(a_r@ z0;WOcIe{M^wpv~?Ij*s(CL}aTwa7%U8{2Qub&+ueTJ{LWMdR;G3wDM7Vi2$P zF~HSs`ri35N|DKeuT5qs(v*rHWeKh&LMj|t30<5ow5z37Pg$^uIjPKW8FNXx zM+l?(3L~=BhyIt3q<;F4VW`8*j{G~|a|v_*_%&MYDcXm=($rsEuQzhkIF}a|Sc@n= zM}z3IYOqd*E=mO;L{HnQVVvVVMT1*K=?OV9=Zoi#=I=&-DWvjGTqgZmR!h=s<4zK7 zd@<`iVj(yyR;CTc|$;xtN>usg?+uTjUE}2LmNx~^GS59K{_W4`f z&o^O>swaWOQOOvRp_xqI&XpA8ed=S6n{qro#z&MChqF;MY<#t#Drt~~Qe#)(h&e%^ z%moQw=|kbC^TY5t3dOOwoWu#7QY+Jt0wn*(p=KBZ8Uv4_(_6c{=?NBeTgJvoUNlygXX|w{pvSv@dO1aQ znCNv6Bsizoxj&%Cp-b1czE7v8*6DZ9)*P(evRNUeCfil%hMjmU99mKH&+XvEE8@&S zC-co|6#9yy?yms6923dK z!jE(irmVY1htm&)Zkn22=jFU?P@^{AE`CLWjAn7V&W9rTH_wJrajYU-^87P36(nL} zDe&b1cK(SGhY^+avXu_<`wmpM0sb^K(J)b2oxfKRCJa9bt9HMu()j!HA8zr>FE+He zrq{5@l=PR_tmj|;og1SG_MW$#6s3rQ3pbmWOwW~Kp^$6)7z zmJ^=XP7nSSQdHtEr*9<1a>8CgIx+NN$0G%<<=In8)iiET)_!?thpefrK4C}5M6vx# zZwMTVf*XD!pUV<%`xPPZJSL#&bD|KxZ|RVHX6P>sjeRl*Cf%Y@K7!1`o$Sr>TU#`w zB_a7Gbm~~MtfvVDiM&fH6ne;B8Vh7MpJ6u*Zz>pHC-Uq}uF{h6pTEs$5tb<-vye*p z>UA5=#muBQI=3>Xc6KG_u-qJrk5;>i)&BwcvQYGiq|j@qSX2p(?UYKK%aHgU*j$&_#(S0taJ_ z@aZ1w;UU{{Hzmx+tYNx`CFND`?VA5mZ~uzsRQYGDjlulf2H@5*H!ZrJ&Bt}X8-d++ zBTr(5+Aus%tWXqp?E(8)TZ8tl@kBk zumkSroVrP}aEuR?R zkj_%G^I3(cG~E3B!(&SkWBp;@k;?qJ2ZbKP?PV*^rua@SSGF)V4UGF-izLB!bH<2o z7!YCmXcIKLUiM?DTX+4RU#EbFx$e^Q9h+&6^qk_$LHrXtBEtTZICNjL{-& zhmrZY^4$x?w4s&eyHs%>_jaP0lp+SC7|w&2x8dYCsSH5jW1Fw%^#m8LZ9Kv9jZ2H{ z)iL;$d2-R0vLWK`G$DVjI{A-gLyA`t9RXAl#}UTOP58?c5eM1vhqwkZ+I$mLmjNJTcRwB5n$pk{Hxim``W~r`Xld&6N+jhlaC~ z_t%(F@;EzRbBOrGGnzV88f*xtKDwL-u6isCN(udbyA z{m}Q$hMl%R8m$GcwW}FJYoSARrE{*J99gbouHIBfX+yP|kj}YvMN*XJG;1>1v@-NG zWy~($EGgyjf~1ajtCvS9q9nF9I47Oo;>WemF&u+VT}y>Q0oyk(&f^({kvSVmVgJXR z@pP*!->a>K>23{N7h$G*$o1xQZdclrAYZx)w?wCTJ(|tN^yBS`6#0;8q2y3z+(bgv zp4=#tUB>A09%GCp@AU@RGV*23kBz0uBmw>dp`8PA;(3`yx)a-~@5(<@KT)Ki5&km& zE_nhMzCmBzP3L!{mS#W4IGi~lKSX3%}_+4BXO( zC!h)Q-6{F8CF7%$S6r4=S$Oz3Eo|gOk=T+SvN2d*HE8pG&lYtmeoWJ-M5j~!g?%Sm zTr!p{`pr%=$3S*u0gxUERc4?GG)I5Fx#0u9#qZOv8pDx73q*1V1KKO}8|CM#4H#w+ z?-CNSiDlLl{mjQkil<*1;Gz$FS_rk}3B5EY$k?onluD;MLKvE$ehxrLR4zStW2f|b z?p;ADwMuti>vY%K4VRa{_I;8sNYw)L>}PFLbP}+*yP`d?#t_tdO?mTuSz&Lo_5s||YN zRJtCo`=+n5F6;bHzN;_$s*Yw5UoF&vw##=aFH&maq~YjNi+7ap>fY0T?9gvc^nnwW z?JvPUENb3O^{)(9a+s3*Za6F9Z&)rXDs_C`)L3MY#;6{SIW&9JKJqltX%zDP&k@Tf z%z$QR?dbJ@*Ka8|m`yg1oBe}kR_$%h7n3N?-btvtO&B+358LWfUzIs(jPSmzYcl(9?nW&%iemgVJ{K|H#O6EBR5w2B7Xa^D?DJc@sGNv)5QuRB7 zS2M}nF%p6Q+=^@RAz#-+nGEyXZZn6l z{`kSV65lGD;%RqXi0|z(v4ynn1ytbV39%f>VL_mvFK2dDhY}lHXTuMk7v=7Lvk7Y4rf7LFOO?!&OXf=Diwc4oxjI;s~q>h znLnfZjfoiB3bNU^e7<+%nwbB+nn`Z>b=-DV%s%(3%=hM^-8r8*M?(F9`SpRnwbBDA zJIO~bto~5SW%Odwh9@|uc`EGH!xhK=qbxeU-9du-*O-w4dE_88R+uhNyRI-y7LQ=T z7t3#DNSgl!Dpp!booB6ojaVS&n`mWbOdpr!JO7i}+g)BB)JeBVWlBi&a} zNWEn@bc)TD%bPA!nfYvqbZ$>5ICZle9yjL(b5(Xa60=rH;~F|IE%bd4hj4JnYMc$d zeA|e8%=gZ5MurmTQ&T()d{qp5J%h&>PjzEDj>Yu9Uaj2lvvg9esawu><|XO*_Bj&H z)+Wfe`W2mLW>pIb>Uw9nl#w{wT9Yc#79jGIdE?IrkP`AyeAfNV^o|^#rpb;&s1(<| zUY2FPYErwvh|%V9fI)gRcypr~7LM#qxvWV*DP;|2tUbc_VL*;g+x0;`e*Jlo!h3C=>$ctOrztJ2A*3_C zNH>dNKV^jSM2Ug^NJBz*MAwz_yW2y|w2Kirup@@&b7@y6dg>duPbYc`@Ng;1;})n+dUxH9PPWqNJHm) zbv`mt+ny{mgP5`xpVjb3lz(dFae02! zRP@$Stk4nFxjVBXk9#@HUf5aN_#4zbI-6OYycE^+uQz9d?!0zybm;yr4H&_+G^B7n zhHS>vWFjx;q2Okr+MVJj`+syPN4fNCRYz6MyvlSPtcG2W=S&X=?ZWaJ(YchWgR=hv zt3Xu0)2?0A$hca*`si&@o5n1*i8o&>m*_+R_YdwXCs(d6*W7fa9C3UJne@U_^5fT^ z%NHLnl02M4DDHS@l61W0+UOl4?T_c7=dE1?yfxlC9%ceR;e44Uf5J|Plxx@2r(sSL zK*4>AMGK{O8i%a>-1=j~dg(d-Q7KdVOsU$UmK=2K$@0Zpuh@|qz=$IqE|*$v1pxqMkN{Z*3WYIiREPCpgwYO z`4UnyZ%$eG(Ly`9xcAyFa#pL3(yn(qm1#+t^1<8k(QD7kq93>DILNJwP+_@g(mm3& zOJ`}`?Hc*;e=piNz|fm=`#`y9z;J8ZxPiT-a=pgVcOtVhsiY)pO!`6eXT}%9cgw*4!O9(>DCT*ze6r+ zB>g8pE$6haC)LlZDx>BtkP$swO95*`4%LkpOTY1V$l0wLNxQ3u$OE_bHzQ)Tmi^u5 zA4>~0gmgnAgDz?!SB{!0Eju-pGaFQtY486kclYluy4TSD>>*X^H@ub(p>(xTux40c4@a`4$VJ(!c zSzYdaS!ME+^{)a7Wo_lgwGZ{IGk zg_X2kR-1m`U`IYCH|2Y=l84!Z+Mq6P{=K8}EjPYfm^3Y4OgFeb725Xz%V#?;&dM}; zPxlzo%-j2$k0L>|v|-JPKV+X`MWpAQ_sA1V*2tr}Xw_(Oq4cOx+ARE^7JehIJoccR zto59kFNd7w>igmI&vf`~kwZ(LBCFuB%4@%a^2mXQ9WBpH8LP5cuJx>yGn>@4Mfm$K zzLfV~d0vjx{1tTJJJyx+{TB;NksN&Fak5$!{W>SBC|2Qk%O5W*bM%)uPsj#wK3tH` z_^rT$ZiaI45+FGyv z$)OntoAOi?DtbVaPu(77Ky0=}2uvMvmGDJ=Q>vRZUdgMM{h>RZ{iWBPqvfgP>*Zlx zaH=+JC0(i)4@mMC(kVl6Y1#oN5lIRi@rL)PL(z?AuV!(mB@-@mR^xp$1#hCeU3`O z(Xo$>(>cY+U%r~2nk3^`xRUwvxIoRgboESE^w~orfQPimX_oJ2u^WG`O&%{Py$rx?2;O zJ!ZJdvAh)Be-E3>Jehe*x7KokmQhAs%aiuEa+d0RLZ2Rad|6qh@?PgZzZH4LH-lcJ z(u432AjUWoL~k9~HHmR90Y3L@iXWm2jN;8lABes{?9%UhpvcY5D#@K48{6t^u!s7i zcpH5rb~pKLQPKL`2Femyx+s|B=P<<&UQj74{^1)Lefc$Zvz7Z1jY?2%B$#E3L`ofV zhzy_mp)C9LM_HrwuoLTX`vjT&{d$?PV2wQZpvu~POMFvHtOP|QiEygI4Y^v zrn5YL|D7^()DUTN`5>DNrdV|%ce!z-JpJ=}ne(M8)rG6&iEsYUEo&azo#fJTCa)`A!wIgD3e&f?W_YORLSt9ogZ z6~@H*N92~DzxvYTzwB47OT~Kagt33h2{LNeB30<_FTeU@|f4WK) z(+M^abE-ATM5I2BCp+{TEVIXsR5wCup4Z0u%|EM>3rl>kok3#yfk@~?H-Xa zGApWcYh0i6<%W7EN`YwlX`ZMs{@PDa=rw7(-h~qSRWR&!?U}a;^cd z_?}v`UXHI^Q?962(dxvgKmW+wvgD^+dJg)M3 ze)Sfa`pHV&^&Df0Fqi*%cI__~f14`?%A@0%TenDq4&6-t(S6{&(y(JUdE3eBHC3#$ zKVK~;S1fNk#Q3DeJNO459l`qJ=w4o)=Gc-J2{O?PVR`1bc64}gjP5$Yr}JO7Cncey zY>OW(a%t(jGH2NJvR8q~aE+BPbtni&i&GS4Zh3>lx7FXrjPgbDp^nXe{B9>luPE*F zw_lY9huvfMaapX+J2;2k^Ja&$RAqJeiHAtPNl(isufHVDMwOAzeIj#LM00EIGUf4i zI(oEt^ea1SN0owczN)yTcq6;H<@w4p%&w9*qqno6`fNrsH|RIy;+|A zA=-3M4s+Ca8CAIr4}C;Pk7?@mutsn}h9Dwlpew}3LFX;@_CqJh{g=0sFW&f23agUi zY0F3N7%vOoe_dMLFmmfohe~}=2OO(ufqkQG`OjbdEc+iKGH=?Gc5U~N&^Qi>ZGw4` zaH#*T`QOOHcikl4e)6-FI(lEpSFn)uKD)f#i$Ve7-+pNe*}v2g_8vn`waCZxyHtv( z01rMam%Q}Q1JXo&41BvO>J_m%+TObF4Ki!Y?ehBEN2U3tm)nsB3)b1KE|RK>BIj!@ubtlZVbI~O;YW16G;LGERc2`D3xFAAUEA`|1*>aL>m-4Dq- zPtKHS1BTj@K|GQ5%)L`&{)6MB*ZohJvWO5aFq>`Sa7+Q-f8kNtPbb`)PrhL{toL95 zM^Wmd++04DugTEKkqOd&>cjHmm!HV&QTN-iYNh(kat8!oBhIOVa$p-m2cDk$m&%hw{K}1Ek$mH){JL zSvBm~UFOc1APYZVF8gY~KX~O`X>eqIm8EJGWxg*5cv;0Vi7sJ@!4!+S1S>B)XkOBq zJc3N&oP!?L$GxQP;~tZjr;nA{L+`Y+e~!x@9XVd!d1{t)8#^aDA|}1^*yqELfcG4a zfsbB(LiSgA&41`wTZHY1+%u4NxjM;b1Sc;}DF)7*D_^|xKY4b_zX%}oI1&9U!AsHWUBI><5cF?yxC7l%j5QT3M^7ozMVFQ&TlIpz5cSy z88<@C@7dpsK5o>XtBVu{#;-qYG-gFdq_cD^KC4+1rRWgI`kVN zBQCp8mM#8Ssx_=(_Y^TA&T8I426bv;53CebS&bQRgVa7KhZIsnX0x?@t6`f~4=T3d zxdL{_L5|lq+YvEC(KW zpiYL!8qgL-Wov(7^ky|>nLKqbx=eahC?WNA%QEAZtEAw*#qDS*{xLu5!t;FMm2?-! zAU?G8fpX48eWg?R1I^+Z|K4Idx~pG2ht$lUL(VFgL%#pwW4Y_a1;X#qT{`4eIpo+A zrIMN@HMOqWy0?}QPrWC9sE%Sn^A3$4gnB6lA6Zl<_F-~Dg){6CTdG#WQ#$p(TFO?d zE#=|ACedypr=E=vbW=q)R6&^BvvGie1V6 zhaMyYp7=E%sX#yyfuno3l~bzMwWA974z_3pYm?@)r#zv#o${tXB5Ulrsn5z?ecH<}3pdDssng}G z^E>I{bcEE*mqVJA$|0Y<`Kmnd@lsi-in&tVn$o`CP&FL(l8QQNuWDLNZk{WZceskWEnM1CSmW5Sb z>h8ZHnp;PfIX*rP0@hCWu6^MiE_0*D=vi`C*On%)8AGm=BTlJcFJw9mubtQ`uUy=D zXHjx<3nPIizplFPQ5oE>zAXA~lic$7lTx`sbLm|9FsY&PYI^9NI=4QRX`ijqos>xJ zR!yZv&+DY#emU%jXh7>aI=9|6V~yPz55h18=r3Rwf5y2jswOhP|=Kj-}CemJRl5KJyhk6jA)( z{8Fjm1=8`@d~&wxlZEf`@JjyZi{|>zc8Ih?>*5D2fqj`n2PH?aEa>HGl#`0}n@f-C zN83*Jflt@S*B`wjjSh_TU}N1u9dyL8a>KM)^2-lu08V;Xa_eeRNz16D+v!Kg-60Qr zxYUlcx#wlOaMwS6cdKmGa!Su5O*>yZS#9&gq1VaOcYcyp znul8-oJKfX$J%dv^p~zr@!X0o6aC5!FWA!Io{9F9mJwV`?7PCZp{wIjWEj2p`(Kn< zd#XiU%sPXjW8!h_k}FppYoJ}Lw%|Syc{u`Hv1q+6CX1!iaV2HNV% zMA@9PbLP!2Y{IaO${kZE8pl?1<CvO3z<*?`OfBSL0tXT4^6x?TD-7OW6RjTMv zRMgJ`v*ed`vi!GSq|}jz+FZoqHp^K%##4EonJ~?-v}2 zLm_wz+=ODKxI76LvFFE}1t|0KW{u?8M<0fg5+_uvBfTGd(jH5-GAwi8yLwX5bLkl8 zF;6UVcv!f2Zj%%Dh3F@f2n9i3$){qncELOU5XiD$*QjNe-zFrB5_f<3Yc9gqkt5_~%u+a1}Jgzh3){MQLM;`ZOJdP!3`9{k8pxKoG}Mq%$Xs zm2*xwRL-bg!{SomwE9h@)3}-Tq#f|`h|4BOeaUpCQ3t!#RZDc)*G3mEp38Rfkr9z3 zFU`UaEfS`GW-%G1kB!#rF;nEF|?e^;~IZno?AByQ!B zwOW2Yd(ea*i>5x>&r@~eTefJm6f04{78)Fj9Px}J586xl)SnwGQ`pJj< z7^Bu-Et_M$oH~a&E#icaaw(Jgnb+`$^57F?u2{T9Rxe+o;i7g*fx$;P)Q_$~->zG; zLJl~jh|Oo}N&V~oXQtuoaV9htOY_Hr3% zm0$y3C1i05o}^>t<|hGGsiNgf(&x)<9E$3ogDgt;l$G0NWK;(OKcAXYSY-%$#Ucj$ zUb@pMrHf_(Wqvdvtdp7-;q0ZOv_z>xt=(9jl#8Ma7bWYrs}CPK^?5qw5a3ga+q z1IK*OSy=brY?ZX?%o4}xg677J$giTgN zY8rbgjXt}4@DttikUA}^Q+d~et0XmA%enHjs%lfAdd2Y};jHb?bub><(y!-_V zTG&ojf^w`r{bRE5W%@!aGV)@%x%ymGw(#jv$_3|XAzgirOpwtYs*#vC%#rYSoJ}^BjW#a0_Pmq_U^YWs8n>!2`O-KDK=qyTrhlFfV;zHxO z_W*D66)0fGwQE#r#@t=o_+U~RVs6g{8Z)G+@UPJ@H{kH6x=$u6fQa% z49v-BaJJ=*OeeIU%rb=fYJ@54dbBebu2HvHhHP<>mc4|xAE@scm_Dn zK-kiT`3YnLOQz{aZ~4eiU0jEB7sqw1i}czXYZmWl)({-m>VZ%X`h4`)%F=63H$Ick z)j>IN9AV-h08b;Ve>k-@y$l~AS;nXz2Bn)};mYxJ%a2caE{}&@LRWZWfd1Mdq;xAn zX+BGw-qjJeAtFWbgozIc3KrJr+DGF11TGP3tkDPlq2ybTmizqnMzJj)bD|F@P=j!n^^F5N{l3^s`U7B=y(3cZCCHcHuKrggG`%$gs#uOy>w;Su_qmra5{--B~d_1s(VaK%8BBx+RQ!3o6}PMG-+A9_fkWI#nG> zbYrBW`!>-857HPY6CVO;;)ozk8n|qc(?7A}+O^HD!#0P`r2(EtI6RP$&Jn^oOjf=Q z=YTKQXkpy}-K;Wv%MsDdw}j3o2;GJ&_;yiB zE-4K}9|wHc(%|bK92a=TuYhij>o9#-cTiudx#i1<3XcHYd`Az-%cux->zut?8^Gt^yL6)6C{WBS1LGg#(Fz(Gyb^pP ze4JfpQ+GN#@a04B+tRpv7w0FSi?%plurJFTbcHcgolo!kYBY5g2Cf{VIU-(Ae8QyJ z;@Xj%2A3Tyo&L#~Ux5qTZ}}bF_YdF7aqSH2@NvG633X&ucM=_#M>(#JP$tBAdhCKc z2EEvZ_ll7BhMqasuJ5alOPM|mJWnjlpRjGoao!K=&q|&a zPdZ14)405L?c>w~33=e7LrDKKGK?z#z8qXq9dTLEi4W*;IVtFV?%;XEMQfT+4~A)y z!*M#`EAS09A9|9DD+tmg!^*)Y-a8^fdRRwRb!R~bwzw#a=7|c@n-9&!Sy1U(M07zQ zpj)0Ky7kl1lleg$@O4|c4sn?L_%4(2%ppu;(fY>~nI&8?ks}{YFS3%A)j=B^fi%E* zF{~VXmnJUD(JgOSM;3JhPq#dt2$T-OI19Qu>^i9q&wD!J>E0^i!lzd+LQqyXuzejd zO`Q*t7vJ*Y^kSP|L-o$5@x%<^%Zc-I9rOnz_(A!kF`w%w82OsU(z!Igthjw#2X%Nl zz*>$A0*)Rf)c-Ed^58pKa#?nrREL$tg`)#6FH7UoySSLHf3}gAx@36)PqMr?E`oM= z_^_pM;dJo%%>`vA^fB25^;=t^ITyp#Z)JEF(0zuuj;!iVK?k00VM~}8XMRAppwi>H z70|PsTb>Sl-9emPI+{7>Sv(*OPKn{%qDXvmz8rPH^2U)k{o^xka2{Qokk;$ zH2TNqHAfsiv}C#~3ql-6IgXwzleny)ZgWaEkk-)+j&8J=s8G7EBkmwUXygg#LA3c+ zBr6ri%U@l@byQ9Mb2e2#9{K|XP3s;LAnfJ$;jg_ zd|$S4qzTG~2Bz6SP(oSIeV%}B>4^{M(S`mG=+qI@9Ni-hhxuKfJhDpzDO1F4z;PY8 zuzV{UA9@rt7>lw<2hAK8LHj~_@*J|V?85m3v!ENoxTLZyUkbYAv5Uxs^lj?!>0O+6 z9&wO((m@FN3JBU|m`0sXHA&t^wnxg}w`#fRY zDd+^lI=lns`ShviK^|XuSQd3yzJP8QNp({e7k&|g?qOkcwq!abdiL)r;%GxhQ;tPY=PD%pbG0jt+x zIv=*S_%wP6@O?NtSRJ7sc@d}sU;kJ zxEvhUuI>c>JGzaRkgo9j_vx)1NThXfA>GoaXm3K;rLi(Xx(nO2de%-0sN3pgi57=QE-oz39&FK|FPF4&+ngip+mt2GPj7s|mM)_w+8f9u0OnB$VVBZHna}o+ z@0R7HP}2D{R2BszADRUM8qPP$5fkEEz|%k+?*j3)bNmTu9&!DIoez@B0T$Ljo|f$U zxcFL;kS4g;xJhL7sz^w2de0jr`1%bl4WHuZ*|d?&eI)Bo5}kNv9l81;_emmGhIy_G zqp5RIiN0?O@h*bT_~hM71H8zmUaI_FR-PWlnePIb&@HTgLYfEZv!a_Hd4@P$5QpVXV|Ho&J+VmCk7@UGJM|pZiMapDV}O zAJPM#BsO^!q_a;HsjQgvY4dBG)#Zo@arha~6XNubzXo9(d1#7-A$s3kB+&4EKtVrz zUjA&8*7?Av2|R-jZ`J^x!`ZMwX+b*AC%(-$dCVwjS|RIC61BZ$oV4vXDE|0#To3%j z*FTi)=?Q*P8a@$}Czpo(%dI&36NQ0YItGMoPVkBIVdsNX=`E~(LYhaW<$yR{5Qj^a zm4zL)2|Ge6`X8zr`Lc&U2K42^3&Q+Nd+%0lwk}NeOSGgQgL?c)@S~u8ze)eg*zPUm zv)`6UPXD1O2cI?-h_i-hz36q3R0lBhn+Ah3RBnn63&JCN0B?)ISM+6x`~Q&Jpkl@|~*}#*C3! zGbYKFA_pi<6ZtkNNW-PiXW=NA5i&^|r}32~!zIYH-msYDaK_LM^Wn|Cbv3!}w!5U% zNu}-6I4;V{vW4mXu~I98g{fPxFwr1uiz~-B%z5TpI83JwqvefhGi2)6k+P}q{&8GN zo+-#fl%>lMDbuE?!_xW0sp{9blx3wrSbSJyruhLMea^RPv0Of2u$)k>vV9uI7aYp# zfzhL+NyV%ergq5-Q_wJzT@*}cn@{88G1!^M4-Fb1&&_*L_9(ocrg2uEFHhkw|BReK zCh6lezOrPv1ew+y7URR2<~3+%H>q$cA5}`OxaVG3p>xW4L3X~a>VgbWU7w;m+}65DRK9O^32BzWciAS6!Otq3q~_S z^kGGIOwXiQm`>7#=^D2%0iQpWtju?ENj}!#XObsf-c24{tL91j0b9-2-Pnrt>qWX( zl^OSrki*JVwC{k~6Ga-uPBW8*sdBI|0TTgbSioI}zLSB)lTNSssOgi#Zjv$Y{iFkA zq>J2*1pKj4VO8d<;`-fMb5q;B08DwhQpiB$`KQL$YURUEKAX2@KO0>veGaMlkJ#Tm@W-> zOeC-pl6=j?*Tkn?(@SO^(@5mR%F&l1k>YM_1x(~u!{$zxYYKiNO?q8nAGbB$A_SKt zX08H(urRS>%5Gum7w(wU`C_*55sQ!azJjk7Z(Q-4v~F|0$f##Te$$n6w+s^jbNPgG zz5=p;x3co$`)|uK<_B@gD!*eoD}#lpd$?nAa)8^|0v;CSL=dJ!Ip*5(yELtHhRA)d zi7aO8rU`e;Yb#(FH!AiiD0w@Uk+3#21k;~P9z#`o(r$oRoepcY&F*5jwEpqmS7uzq~!ap4BDy$1rFI|{y zeprNy#RE1`5Q6vBwc$_OA$Ir2R{mwj*YUhcpR&Bd`UTy0DR{E*6 zWZ`EY8P7cbjJL#-RJ~|na(T?t1X$H}vsEoabNQW98oyd8d#N>ls?gxB@|5HR znF~hA04A8N>0{r?A6a48*<5mR@(x+$=6CFAvk5ck!+*u`LsOYRbz@F`I7(rBbpg{` zgtFXKg*o zv+TY+gBRQ(+!qin4Chjq@D1G?&BQkJMf033~i|kt>sxU-; z)p%Zd|0OUAd3N}WdRG5u3-Qp0tF$5xn;D;^BvLD`dSeb#x08Ke}f!BEJP9pGE2Q8B^ru5yM5AsjQ0Zw{2UnSXfLs z2L3Mr2JvfyFFz#m-De`VJ*WE5J@u6gw=i|qg{iA9OuSa(*lawH7bbR0-F0E&R~U0_ z*dVRyo+dK!JuO%(ViNC007j?|zIk&*-hM_`k~`JvX339P8^Q0GbYZ$OT$uC^NtOS0 z&7?8t1q;)qEKGB&u*?S^p*6MBIz zN>gtV=|59t=$|nT5G+ieyM+l7{N|W#y6%{&XR|O>)`h8e_*5QMsB@m|y|>5(YQ--f z^+7b(?59L`V=I(P9E<(>t;ntIMTR~f&9`I(3)3gMFtKCe-8@D;eCC*q9aDA-QwJ6% z_uxeMBr88ky>ZoYY2Bob$oSWEN1!{`R14&P8p^B!Dyt_ZiG2HsNc$UA_h7g?CVIGq z>C$)ak}kS1nfg?+$w~t}mB+%Q8dTG&<9P7h$F$Jqx>I6N;+ac!2)o@@$MNL~aVAV{<|~WUx;{!5C0^=4 z*`?~sf7YoCu@sIkquZ5V)w*RdfP-n^WaW9DDM;$Y?(_OFa#5xyI-kZuNIp@c4kT_@2zvPz#N zEs6ej1D?<>Hj+F$pGosH3!L=M@<797IB8<|d_Ih)<(cD}^0;MEXy2%f>EL-BI*%}% z3d!-w`8~2L=Wl^=FX9hlof~r5!1!v+j&ggK9pZE@U}0s6m)GV^I^T*E*S2V5tb(lI z_!~Np?0B3UpPb(#yK??cusPx8dRiVO0nO%l9tG3F=8tnepPySCkDG2Rh;GygmaZM1 zzoGL;z7CNpE*&kI{&&Ok1X<-T6ou2kx88Uj$jWopFH}ab59j$GiBAUx35pp<7|D5N zaiD9ZB{7aTo`&Mg+%py5KmO+djWpcwveA`P&Mt%O+XWY5r^&rS^2C^q&!6nz^Wa>0 zM)QJoWo3Co-^0tPz&?@VEl&SLO)MvF$)|ulLZ*2`8DdgWPI4z0pjf)QDrmdwMmpH! zAwXJn7EbDFDv+GKPCN;+#<%(AzYLHSOddK%Vp%CqcZ#fNRRF%=l2hY$S-3u=gC?;d zs4nguH2ictc5qp@nOi19{%o&qM2Dfv0K7-nArmhT50i_^l(`bh3fWSIPY#XzdA00R z<@|$Sa{~V2L(s06Z-1irc;aLP2JaL1iacx*fBXOgDE@mITmG--}-%IcF>qs1xgyUFSs zmDQxJixaZ?=3^~O%drKK9w|_M=sDkd}(>kt)p&BIc_WX)=S~j^}P zD`)}~*T_q?Fdf)D)%D&BA`NwtEc->{bWs2FRa6iQOnztO*$zk*J^#V*wMJTi4Pb62oviO%fz5*nVit9PB+029@khIC{vDZ zpwlMkmS5|JW-pF7i)Samvoq!`J_M~Qw8%UxE*n@Hm(R-OlCmh%E=Z6K_EO$FayMs5 z(NlXxONw+?|GxgpXXPyu3I0+bJmLdj#yjQNFJG%MGG4Eh*U$=RTJEi|xe@7U_GY$mq+pk2MFiC@=Cxruo%jC_Fw!4Z>MYR?4^UKNFd*hTv!a)3Q>?3dh`FZb2hWMzYd8eo+i% z@+8eIn_rnAul8$Lr|5nQd|kdsq-pW!$wK6~ z`1|PC799kS;0Llp4$n=|h3MJn8lDtT*)pd_sUfob*GLBN3qxb#bt0>lMl^I4{6jXh znEdEy%E!?Wc+LFqa$(W)@}mvpMNX7wY1M~r`IQ;aXcO{;wiDo4YCPr-JSXfT>?m)$ zEd#*g4zL2F@YO|w{;L1stzkbd0-u5P!?9kO;G0kpn`(N zgu|LZK$=xvovmdlvpho{8ZI)RvB>N@bP_22^~W^t0+HK0icGpbN}F3N|5YdA?H7p* zZY8ovEqn5=UmIP|RO@B_Ln14dC|!lQ_dM%JgUIFrepO;ot z`P`>`(*ccanIMc$cFs>Izfe@=&K7xC<&&3q&G)E|iKEIz<>c3a{^VGZo@c01)p5e4 zTJ&A?$o8FGMS3ZnNlUp{g2<)IY1*C}bb`1^Gvor1%QWx*RQBv3kReAa1DcBTt{yFz z`)H#WNAqTC{!^nztapOKGkynr&6LFkO>8oAnL>FP&0VKO4xK#Z>x!J+MipHj<)x14 z2X7Tw{YNA#<_SC>*+pfge0yBwl22uYazuv6>bc1(E0rONtHL?a$woe>>>gDk<**Z@ z2IbSbo>7_h*2NEgFJBxfSQIBpvPV^2@RZlgTNE&J3t3GXph`<+#he@3UgcaG*^N2Og=sP`3=het+pfDaoW$Ks_Tne+1X6io}SNB36#s}B1}cV6GBQFx2aYo25@qfqmr4+k}m zWctZ#(PFeo#}6{OtB1&2PerF8rW=12>3?ptVPKI$Ke9+ZukxZ?+PZ^4(#B`_?U)<# z*hYdSAh12)g*RSMT%xX~PM9CR&<-elly)+|4*m;|6*)`kRdhi)U#&ctPc8c%Aaa!o z<)<%IajB)wr<lSj!py>QdiwYJ*R_swle7Lxgve4 zsZv#?$#$0`DXjmFx+pg4E>c(N7apgBLCb5lpGakGL&3tT@LEPs8!q`lq}@>>t#yY` zsA!b-0Az~jNunB3lx_b~|fKOjnmN zP%P`!@#GU@jh7j}cw2e;Tr^=gK04qqT|9IkV*o7Boe>LD!F_f2tBcBvTSU&)fx1@5 zz_H~;mg=r~sg{Lt!Mj4I)QB4PqAn)vf`==u{>7^FbRlALqSSbKvWZTr4#((jKnDrq zrj8mMcfBt1n9BOoH&mIO9<}3YmH+ik)UwyOy>*f{)3MYVk-Tk&~!0WD_r~YZm?csAg0iC>Hhsn#)GX}ES@VoX=`K#TM;yR~3e=8dQ zDEhmU4|}Uz;2TERM;yx`t0KDasG)b?H7YArR4f38Dvy!bue#_kFDav3Z4GFPURA4| z-P7%ygs9QbQ;kOGD5=wR9<{ha{wk5i+IAMY9h8-|Q~$$rV7}wIFO6P(5X`Q##|4aewhCBK34<)p3X}>N;+fWEJsl)Q#PA%n68f>7E}$2w;X@p9E28DFc)g_a zjD<2IYbrhbPpo^GE>oBs)FB5$kY@WpfqcQxhp`wajF)pcjzbVHYJ@J%w(_#`;f(xt z-D&CEuvPnT9q3qPyhF(GPqWJ-!7_;k=q?8)GkK^7%NUK{Q72Cs9pD%1Bt)6+t(x^= z9qc>;{Pp`{PYzu^dpcC}GWJxK8Vok>JNRMmNI z3*ADIFSWc&bZ+v*W8d*nx!?R4&1L2(ryhKH<5?}6KD1T2o}~ukjzYU?ZS_n=oa*3r zrZTf+K2I=LK?d1VgLVK4VDaUCJSRjf^zZ4y{Is?i^@$-qTxG|O=$^;b08twKVa#KM z{P2?+gCkUrT^8{YeqW(GTXf^o>a(bD+CW9T0DQbIe(iKTaO(s^<`GTLJuGAn-qN}c zI8=>zoyQe*p+X-KKk?x9knBu5Y zqjbEp!nPBO1eZti&_;F$#dNpEu>+mI=}EVvQ{>iup=85RnGzb$WMCmiS;tPV3n@=# zkCIB&YRm814L`^!(MolL)o6~M5tuaUS<_rz;1?q+i#BBn79jhep7H_taI^gI6Lmr; zvp9;as|)%JRX#=3$T(m5^|%gdj)D$Si|WF`BA4reQrI;DORK@9s>~)uM|vD*z(WWly z#)a`O3R*8o%Us@D6)c7hvbsulz8Epg-Mw_|t&5aYw(#>Sc1~8bd;KOkc=?x-i=#;G zVswupsy-8AjpPOb@kNx^@&~kRfvlKY+#dMx+lZz?<0GHg89Y(P>onc@zo~rC_WrDM z3`4D&j^6`xr!+(5!d#$I=1_w!(Gm4aDw~>W@S!g`isP95mNpR&YN(#%wgsK%n|(H~ z^co!vxq-^_o)_7cqbibEB`44rq2O z6JFA5EG)O8m#r09-Ip#=L2=?$bAo6NNBaT>J{DklfGrwXtie|;>bs% z?GaAx^vk-a!SunSwkogkYTa=^YT*|mAF3tCjd(1$Gh0OMuB`*1jJEMwoz&W71I1+r zU++>CB41YEr%w4@1db-cJY8SU&aDi+nAQ za*(^HX9U{+@vF**XOu^3p*7k+I$lt{XN_hN@2RqQ@U`uzgsz4D!b+DjK6 z?jby{mKVwk*&e24aPNo*Vvg29jk2Rvuc+0|LUpcMTUcbAVIw0JGY=;1Dy^6MPgmX@ z84l0sg2vBMo?1t($-b(Lb>X~IjU5#3(Z@%1A+dJsAFMUt+HC73*l8`q6aeOs~K_|KfDW`+b92)O^-uuqye=YB9n5<%yI- z)hcMBlVzGR_M~bNvko{&vR0fbgjtq#u5n`=8b6Cb96)1u_4vXNjj zK*0?w<+@MqmJ@HNAvMNcAiX{rYab@Oc>c|DZ=*6Y>hZ^93E#BSw4v1%S_d8`1mZJ5 zoR9RbOvV!k%S?+6+D9xbp2p&FRG!?rL}k=xv<@g8E%2WEYy)&b;ql^T%72WD4%bJP z+G)C*Q6o?8)d~2j4(KCv!tm1!$gSN#k&A|CIT}7idCP>jOv~rq-6fTy@o}CSAxumR zgbgas_3E(TdAOpFD#O+%XxW#ET&MLTui@&W;5Zs?)h`+sh-tFQcZ{a%r1ke!!>F|G zw0Q^vWt`n4QfB4UMeLgQM@ZAzIuB_=BsxQz*m$p*h`(bGU_W?Q%I3Bn~cSG!qQKaOhE%5IFZ9fkhb<+9SP5V(+ z%RfmMsSA3DQ{<|zACODm8X>*EpD7=I@}(3%^k7p7 zFxK-n6CS&16uD4N>TF?haoOSz&4^+jbGhmiT}{$U@p&dcT$0OwYC$EtnAC8erR5wm+ zQ&Vo8F;$kTe(=2Y2>G0&Mw1J+Tt0T9E#@!ZKT3vd)P|j`4dSRIEAT-!UxM=4er(^i z2HI#IGvwo@Y$16vh<>05v6eUF1lC$sePt?7`0!u^M{zuwOg;Qk zC6k16TGDWA!=lDE6pN3iQfL>0Q`bLPqE>L%Q*}{N>ur$=vbG9+4wBVGSebn7l=gAv z&hpKplv#az&;tuy`*_fxhVu0bvn983cfS%P<{%C+>Th7fns>-eLn#IOoeoey;;RaQzC!8X3wlb=p8Xhd3l$%e})5Q%s9%vK! z$(K&q(MOf_UIQA-x_PstLbbExi;q8$J_CnHr%T$|&r~tQ)@c{)p*Jm`DsW`Yr`?)z z-&i^QnDpPuJLBA@a`l9n(U<#O0eFDl=~}Yj9cef5DK)rMk4phEiO@8g1$veHH~ zrx^DsWu^Iazq~6$V&6Gl7uUNGUy{Z<=V!w?A2NFlU7^4L?InIxn=%Wi&SOg zFddAnU<1W#4)cAOhu0>I9wld&J3%T{Q6-&(AHH2Emku2#7xy0&cah9^fM!22Y@pmx zObuFowL4vV(Ob+HV7gJqIXt(4qw;~*=rBIGNCg=2RElgkH9)5!Z$LvB%j|r~OB`ik zaKJz0i!nzhO;&pC^)@m?&K%P-7RbZcKvsZuHP*TGjHaWV)wQnaKS$}AmwY%Fa3oH> zJSI*#^dlYe6_R5HH;}iUe?%56`d!NImq#j8tuD{M^ql;xO=OtxycJ!?QJQBLMHeX| z(xqh^*<-Uxlm449tWtG^(_sbMXy@2c!vw2I|DX&hgU%37+6_+m&@mWGI>HEv`#t{X zg|a+jDTnqT0ACLRWU*oqqI@qnUdSaaX{e7Ib}TS_nx~ms)U{NxwK+m9@0TM*$^c+u z`S#fjZY_)anLv{kEV#FHyyQ}8)3vX(>~yJIaoM#t4ye}H;aRC^jq~a|FLorcbb5ha zM;7U@c~cZmndS&XpdLrJKsM!ALaZZr?46xYyEr-kU+s8JI75z%olRsQGE5{W0GUfymD0O(o&~sGkJ6Vi}K^QzuCt*4RBr^GW9|L7S>`+ z5cn<)<6#p!!Zcum$9NCN)wc|6tBC_F1lhQ@$6X4^L z!yd`;$p~rb(t$8OU0N0yEbH5zS6O``_8JMwIaS)^GP80pOULwHYnRIG$L7jOzyl;#!MCsnrOVUY%VLiU3Bo0MN6b`Vcj95KtYw`x)saflPb!HFJ?;cuEiLPgfrbRu%s(1%jT4owXG!NXPLw{w zZj*b4+$QC!RFx739U&jT_oh^>RVy-bG_4!wmJLUkKPDR`Fln5e>_nz#^G5P$nxnj$ zwd+csDNjTjPz34<#sdhL6S@~CjFuapd`sl|dvyS6gjKu)__xV0kGd<)mpj|mlFE%* zORhY7$dwnhlCjgL%De9^l!FgF)C>jYnz2~_#K*8ogc8-4O&F9+8Ow_$O~Q}tHC{GaJ5oWwOI$*uS6l4 zJ$Z^POm&(xmW7{xuXC@YEgrGF)OjTb-#I4l(XNx+H)4p&F7@J6xqef*e#%VKgCLw+ zI6iLC?8GDG*Zxn69IiWz3^sb%!WyX1HvZ$mn8RjoQ&wJ>GfiHaH($DRZ!c||wv@s5 zOp*m3y{|IMD@PuCT$XbS{l(8-bZ*j2a`fohWy>iY2TGBBm7?It^5)j($n#kL`>938 zb}$v=JX1sXbi`>mSDrkwY11aX+#;JcYHL#E$pWs3?E@LowM*g4jmy^n3<55Grg?X-g{_y1f3uEt-p(AdSb^9MKdvIoK zH3jgOu8af_=jb_e<=)SjsD0r3BHJ=8qy=EV;i`Fh)yU|2`OboASladE}iA^ zG<6)W<@@nd8Fu}3QuBi5b~|*_rr+h7&TZw+DO2s8aT}_d!SazmsSFJ7CRMA;tMhbc zkOtkmbe3aVT`naLIW$3Dz{=NaCgQ!ly2_LnU&So9^0#&>05p(H2SNH=Dz8o2M?N}g z@=8&bzw||Bgj8+va0LGDJLJiqsCemIQ@(><*FGk*hwd4 zCC@Ex-*7wah8DHu&RKLR*BTE2(rfM6KKu{7EY5Ufu$w z2eeu*AALyRfICeg3b=>iA1K`;1k!cU8zn9e3 zg^76xtUR3ad>I&hKm72cOunU`jJxkXqEq7Lf!E6)rE5qzoy-2VPTW^5$egx?W8PeZ zvy)X8bpGHM$*+b>%l2~Ev8AP3|Gu)y^)JY_ZP*dgroj)=#qk=5-QtP9hr z6-^NU;(R(_`P4y=~m!1 z#IaJWxDN7caLUOi%PlXyCmY<{0-pcATtA*t@x~+MP3RM_u$EEu0Fj=Jn#)@+JtMWx zYa`d(HNrj(=@I8qWF;@)uVZ?UCZ^G5C!m<7h|>kcguLz|fd(|N4NVdDnhY2c1p3I%Bz9up(kfem%TZUOM@d$EGrY=e%oHNv;Mh);_~pJt8a7* zM6h6x2l!}w@_N}~v@iPUCpqur17+{RMP=59KPxS#&1b8_xj1Z@)e(+7Lqb^7WIDG( zp8(;Y3cJWowsE;eiTnf|rwLe?I_tu8y<3><@GVT^d>r5;qNW<=AARtC)RuckjgV_v zx3tBCN)tLkBXNXD?c*HX;OIU*&rZx4|DaT^bFQ4(u%-OC@N@a`tKZDpB;Jy{ay;V8 zpj_*OE7wOxx3Zx?MoMOt1Tp^l^; zVYql9k;Z49F0*INa+LI#Jn??%+qj0k-eCQpe1(;%btb$N=;C6&faEqq$3b&+z()q& zc~K@{$M3*2;)T1`7vis5_iEmQbB#b#(Kf5eFdn zIG5fo9o@Vny061LSB{T!QC45TqWD1+3rC)1^&(M3M-(3@= zU%Q5O9}M_DA}c=!{QWXqP^6`a`L1cQnp-3w%A#E!gQEkhi#WUBkAq8ZbpE&uB#Fxb zN)NMHJOT1*!1$ITjX~2C*Zz0!&{>Awe3OwZu0rLia`uTO<&JBInAK%vP$|w87z-(& z`wF2Ol+MIsWgI=|a_Mqq7y0$OZ{&ut)8wkw_3Y@&x0pPki<#^Q_}g^CrSb8;Zd}-= zFr$^}%1x!LExmK*IeJVB=&AaR1KtnY=+khix_}op_@q^Gkgm#u(V;0=fFO!Sd6$U&}QkZ<7HR zwXlzR_&RMOI2RPLHSE&(x?==&TVmqz9Nm|hitg*gv%V3>wRg}#Qk>GvVX}^^8B3V%oy}} zO;*|=^3yLR8H_btkd8Dd>WJ&M#9R4d`AF;N1TAfLbZ7zH8biFN6X6g94Hie5=+fXw zRt8lTS3}^gJH|PvzHZEPS<5{vm&fM|%k_*2)A*I#r%7N0G#3|6I^Q1O zCSPt$!$DHImB&R$hh{{DqjPCAN4Ihud{Qf)3tz6!>l|U;yFghK)kUd6t$K3GVF$=1 zUAmGzV|2Q-yVN>nf4S(a`Zj@h67SE*DkWdIR>!Mi!ykIV9`52MI-A|0)1Hp*mH7PX zvXm9hr7`DdmX7Nr9+?A+oUAALey1l24-^%7Wv&IS}%=uEWaow1A$>OJFqOfunP2w195q5$2CI z!qHrwtm;Szs~4B4@Nu!P9`A)BuNe=_l)kMS%KIOFNYae)$P-V?yOVE|du|+RpJL>- zN59K81a+nCBk`WDE~eq@H4gw(s8L^9b-P68*eY4IY?)j>^e)}$9=r7cnILamUl=Bu zcmg1Z&vI@h(c`(wHF4?^#sefD2a@O(zzg#P;jmn;jpXC-mCni9e(aPw_mpqnohSE< z*=q3FJth}6Jpas7a$%Pq((JOEr24r{q(DI>az7&|5I8UPtpPr$0fbplCt&NUHDt=X z=VbL-o_=!ik!MJiA8Zp2;1fRs*HQ8E47#m*&cHm0_v}k+uozpH%T##d&(*ZB3&A+LcOH z7DqUc74Y&(pgA8{SuPER0z3TP9oovcNfTs+DhDPvPY7*P`g?DEECYIVmReQH%ivpv zTK+$axBmC4G;7^f>4;&Te*r$;K~x+zKZrwKg;ZW`&#EgE=RRRK z)ZIJT3Hd=n8TdhhFb=wB7ciO+Z1rNFfRz=L{(EnKB-eHCB=u@ml|eV%Z2A8T?j1E!29LZ~F1m4)ls}`2?8Rg2+75pM z-}B42)B6Orp((=j$ccwI?jL%m99OQ2l&f-b{GdvhANX)gON!U7ZtlGC~D>vUWLGtTbV9zgTe)J&UG<@cRnEE%QPAz0@>(XHky$i_0WABv49lOe!Rjap2=C5NOIfAF- z`&M{bGSbRQGlw(_^T!br;#?!}{Ll#FV}yCN@;!5Gmbs72l6vP|AnVt!lVyt+%j%WO zW#!_Zq*D2^a^p>dRo1FWb`mDvKVBwHoh~aktGo&!uYK(+6v&GK591RD;`k(FI=4U^Pr%1Vo>k=MSElmHnJc$^ z{^2{4GiOdY{MZw8G1{o|TBJL}<+5tYFD9?SHxH3L!_RH)00s}dUY>mR1=&)dnB>Y| zQ1&TWJSsbRZY4F`U#5x!xpU`{4_|*titc}q?03*1YP4_MCYisE`4S``i1V!oq7ty( zvf_`Ai#!AA?0%lR24OfxkS1@weDdhDNm8R;L)kM|E?s<8R=+Khl}ne%=JhM3LA|=t zvv(htIuTheOd-~-UL_msw}rAznt($4>?2jrs3tGZdr6k_)#fa)eWm_I2pW-Td-AIp zFyxk7q{3+xq*A4d@;l#w%K}(<`TRG?{z9x@yIR)UPd@A%uI^K~uvD#DP3Fye(Pa2f zl~q>QL$^lj*KLrl-MY#2X}Y+tSYb-9K*53rg3IuAH1+ zrLyUce~p|R3Kc3O&0DmT5yOW`ewEMWO`FV^FW^6|k_H(qOgn-z&NxF}dg_3y)N zx7{YEpMJWOFaPI{Y_pyHc z`sV-Bz~Xx4l~-EW_oZ{^&gTDHaOa(O%A0S#DYkrRkF-grYk`Q#I$WrDwCVPep{{`%{7{I}0O z`^eKzKP~(3zrTz9ci{Nrk2fp3Xwjmw-+udSs;DQTmaG~J%RD1va{awtz2OJ9>c;JEZ?YG~` z^UtUMHrziIr=EJM9COSuvU250nKNgOqy96&vFlMs9VMTC{`tT1`1Rq3AGYK3V#SI{ z)22*dKOpR~tG|7;(!1O20KwC$|3&PsdKMIR13 z>@c&=|3C2d+i%-B@2|i9YR5c(7VLPr+00g)9mSsoJ4&7y!)oG&XeO9Ed9uu!HOpkl zdHi1i#s=s7>;`Msu5DvKE6|6$dGpG-=bmfFxH}VL$Bvc9AAj8L&+f>0WlT<+HceWz zXd$ast#Z`u2jdk>m-(CN5zMvMUTfoy_WxCL4q35#r~Hy7OWOR-3iN^9e)sO(<-`+D zbkrROb86nac^3Y&{mhpypY6_RAG?X@spmfjct9CPAAPi=WDkydKmPdRzx24bNRc9T zpR-%HZYHZg!mnH>fj*pc(n)gcvB%o=HVe~LS6wA@=gyUe4IA!|LIVhmt?G_U5P(u* z+xy5PkJu3fWv0V`0Rv3v93}qM=j;qHCO~!ri#{-+IEvsVU{*g`wlly}FetiPZ@o1> zX50~=jCb_@5@Ue{hQ;QKFTOBYro%bsoMQ_#Gc}0Pp-Gb__DTWAR67cuRD*ZvUNgxA=;?Rgeb>h1r=Nc6sHuUj zVgchxVvetOR5xS?3?;^5cCw-mJj}vF66lA7g^8QMUAlCU2@@vl&<^LX0E&Y_cJs|Q z%VUo{=BV3(o4?#loHAvKEM286`Z zUb|9XQ5IOe>=03WSph!y(}1;W-S0Q-BA^e9xjJ>~*e+p5z?^#Fg%{+q%PzCUX;%UU z@~f}DYCG0+PbzXxjs=><2}5yL0tVGP@4RC!;e3R5AFzym`|UTg40k2RF%ni8Pl}}j zM>6d8=mRTts? zz7Oo?e*T%?N7ym&s4%;XU9qoNxs0Lgc5$3yut4wVF72-Xec%XbXY54Lk1Wy{5UJ+( z-{~-T8AsXem@wRVIEIBaRXKmBL${xN^2zpeX~M#UGDCowP7u9>dPN2>m06_-p8<1zuexO8oVKigAo*pBVV z2ev0|2>P%y*;8i-tTK8#C_`zL|6(_iGo@f1AZ=mR>A z;{oU#g&-@R2cD6~yX}3eduM|7a0C#xhq31;AN?bqa55Ns^d(i?{};A*&cSOh6UM9W zCq8}guP^vMLr1QjH~zhnzpKyGn>>DKtB*r=S=|@rC_F1!{(r#pI#ZxOd>@%hfc%U* zWasCc*E#rJ7vY$5+gm5;cP1DwzCE-#)DOrp6^P49cV>z|wJP|EIfme7V9lB}W%TIL z)(IGc&l6!hsm6f8&ie+PNz?*?9tq zw$gqE5@-M4eDh7rVDDIvpMCaOyH7;e)Bj1Jy-Wm-0C>=V7lt{eV2h7D7=$xt&b0dm zC!BDC@ri+myY9N{?ENO>+n_-MJ9lT`{vAM3^E4Yz)X^S%&e)MHalFgJHRILG35Rl^ zuiO-;?Yp}CXdiQkr@{D)4f5h%2Z|bHLI3*o>t}R6al?ZdjAQcgLMOaop7K&E$Ecnk z|DT{f#t-*c!|}t@vnX$5cJ^miE&@SJj4{ zP*%kAv@*wrp&Yjde`;Z(GAgC9yeKwi%ow}3)3IYmDN&+?J;}op7WdwJuk`NS+nzS^ zgN=#BW2HWL=+DewQA2gm|r0$Cw9o($uK?$b^?&6FUEDhn@1yvPs*h>uJ;x~89u1LTd{Rb@y& zF_KVdJVO7!|NYO7&oB&mMLOh$oRAk`95P0)ds#8xwr8yU>4k}fh8w_VpMAF7_+&Eh96FWr zJuAM7z`FxjY2(I?vq|F{R;ElDv+DZv>0=6xC!GEcr3UB=?`dGYz-W~4ph1I-xjdza z^5SuK-ZE!E@nnv-Vwe~#t_Te!K%T#&4}S&>D1WoMbm`JIsOTe#o&J9R{rC2y6@~`K zLp*{`|9O&!LB?m8m}JNtp51fLJvLY=_x~HzN&9Il4^}YVnCOhdufF=q7FWg>y9KOQ zlrwUoA1F!|Ta*S*m!SlAMH#|d6c>~H;DZmg#g!);v9KAVyiUR5OkcRU&Exp=+28x& zoh10fr?W63Fh;UEiutPn-x)hN3-(sqTk8v}{{)va6CA{(gHJy|Y2P`~t+}1w1*2!sTWh zlK{)^x#ymLBJs4 zapzr8hVUIlht+k>IQ z{9)X1q{Z%+c44LSY6vfZqU2eW(Ge`Xj6-%3JOb{={kse%+Ja;3@YEbTR~966KDy$<3okU? zh|!J_ft-*haz(#$_@ag}q_AZeJV~DiQ!V;ry22js)MdiULTpY14k z%-i3~23{ucg~c2BQs%CpBYoTOX%CLM#OVt64$=93eDT^2n-dmh4A|{yf5O6)$si>S zm9jhHcn2#KO8|?2`w%E{juMzeY)83i&d~~!#4k)7c@btZ&7M8ml%comb_TXrfNVKw z4@wt{4bVsWNr{KDEytlgFjOSV~Y0pdk@?P<31DPit=bT@7rLla&*Mm zKI!Qn*C-GA^#8r%%cQTQp=~H-j(zAWa-!Yr2w6~>L+mOThxCmdF84Rc2k0w~69Mk+ zuxldU&cgQ2xp4fjD?;(IJI6<6j7M||$3_=le6byc5r>h;Lm%iIcIrE0yk&|^WrYm5 zZ^TZAKCz=fe{j3Q?>dknw>lV)+^c7|fgWOEhBus6pdZ=Iv-{6y4cf)&dqB`2bH*u?=L{Zfg8=xaaiP>^D}r*=9z4_QGDAwiMJP-SXWGbex`%t6D%A0&r>&8cyfEJMOr{KJSDgWD#TXke7QhC`rZu7SqIu6YYpIlfefMXk$8fIc8EGX=p!BF>y4> z(J?zDc1OsGy4c+_E}0;l_2VOZ`hvyEy%)x5ri&{IWP6S#vI2GazGemD7>^t&b7aSZ z0^B%99w>0m`x%?`16i?yXD7@z;*bg8n38eLE(EKV6AlzeCSx%>e!z!J%JE1ZKg>Bk zp@lL-UKk6UPH=pV#f?lb9Ek%M#oW_nvC8DWZl>cXJ5WX@h6@Wm_x{iu@S0;{`iPE1 ze=v41c6ne7IiR?a7x^%Z;RX57q4b%fOAO@fusu8A?U5H75Kc_c2OQOLWQ@M1E*4M> zKyJri+yUr}JK`{IF>>h#?aL0n4+&gm;$msC;`^hlWQSq`>>fDA;y8ih1N&V zxL`In^iZ@+TH1;NL+QbI?kDjS8aoL3&({eUFj%Kd6aEf_rQ+qXBRjM0vMU@_(N2tyDWbB-Mp$FJ;s;l~k2 z9AW+EXq`TCZ-%)7UsBZ-I`kCz*wv&1vh0koU;p&!_MFi&`B z4TFi@5;`4&3Atcc&=1BdMic7*Plje!C;51y79Fw8M_gI;c*@QngQNqEhaq$TVX$!c z;;6(A3OYdt7>EefgYr?1*$sR^8qSrm2($ZAFcTI*bCWw=A80Gb34XDo4%*}M&<7@x zPe(uL3u%1c=of<#UeNz^mI&oAIN4>g<^8L`BEz7;V$KBglYznHrGH)?@P#<~4Ik(? zV1UtIKpuFIi44hu!en4$`KJR`777(MvVw-(NW)mp z?sHL;houf*uxxh*P+|aOm7M~moz#tNm~+U>gT8q_&_Ch<1`~Z{{J|GLrn3WWVIgM+ z##~AVj_o;;@;C9b0`=1VRO5#@YHNxtkr`7B9zPyafjY>`&YnJ`{MieR+A{qldYC;NAeqoX z7?%~uL+6>mtfrZOqe4EAnOz^!wTC!=?bD^ZPS+RWQ7U|37AxYf20K^oF)$#~waX*9 zKOU**o(3{08<2;#a3sjiJQHA@Vof6Z?CMF^CgMCT41;uW$snFSush@_)13({P3}W% zPhV4|OBLs7AiJ_X$b;f!vGGq`W(SU+7 Date: Wed, 12 Oct 2016 11:49:16 +0800 Subject: [PATCH 07/38] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7343e6a6..d171c374 100644 --- a/README.md +++ b/README.md @@ -9,16 +9,16 @@ The Baidu File System (BFS) is a distributed file system designed to support rea ## Features 1. Continuous availability -数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 -2. High throughput -通过高性能的单机引擎,最大化存储介质IO吞吐; -3. Low latency -全局负载均衡、慢节点发现 +数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 +2. High throughput +通过高性能的单机引擎,最大化存储介质IO吞吐; +3. Low latency +全局负载均衡、慢节点发现 4. Linear scalability -设计支持两地三机房,1万+台机器管理。 +设计支持两地三机房,1万+台机器管理。 ## Architecture -![架构图](resources/images/bfs-arch.png) +![架构图](resources/images/bfs-arch2-mini.png) ## Quick Start #### Build @@ -27,8 +27,8 @@ sh build.sh cd sandbox; sh deploy.sh; sh start.sh ## Contributing -阅读roadmap,了解我们当前的开发方向,然后提pull request就可以了 -Please see the RoadMap file for how to help out, and then send pull request to us. +阅读[RoadMap](doc/roadmap.md)文件,了解我们当前的开发方向,然后提pull request就可以了。 +Please see the [RoadMap](doc/roadmap.md) file for how to help out, and then send pull request to us. ## Contact us opensearch@baidu.com From ef468877adb7df23c593ee6130bbe6f6df1d3c90 Mon Sep 17 00:00:00 2001 From: lylei Date: Wed, 12 Oct 2016 12:13:17 +0800 Subject: [PATCH 08/38] slowdown report process after first round --- src/chunkserver/chunkserver_impl.cc | 10 +++++++++- src/chunkserver/chunkserver_impl.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/chunkserver/chunkserver_impl.cc b/src/chunkserver/chunkserver_impl.cc index 92a911ac..1fac8d92 100644 --- a/src/chunkserver/chunkserver_impl.cc +++ b/src/chunkserver/chunkserver_impl.cc @@ -81,6 +81,7 @@ ChunkServerImpl::ChunkServerImpl() blockreport_task_id_(-1), last_report_blockid_(-1), report_id_(0), + first_round_report_(true), service_stop_(false) { data_server_addr_ = common::util::GetLocalHostName() + ":" + FLAGS_chunkserver_port; params_.set_report_interval(FLAGS_blockreport_interval); @@ -184,6 +185,8 @@ void ChunkServerImpl::Register() { assert (response.chunkserver_id() != -1); chunkserver_id_ = response.chunkserver_id(); report_id_ = response.report_id() + 1; + first_round_report_ = true; + last_report_blockid_ = -1; LOG(INFO, "Connect to nameserver version= %ld, cs_id = C%d report_interval = %d " "report_size = %d report_id = %ld", block_manager_->NameSpaceVersion(), chunkserver_id_, @@ -256,7 +259,8 @@ void ChunkServerImpl::SendBlockReport() { int64_t last_report_id = report_id_; std::vector blocks; - block_manager_->ListBlocks(&blocks, last_report_blockid_ + 1, params_.report_size()); + int32_t num = first_round_report_ ? 10000 : params_.report_size(); + block_manager_->ListBlocks(&blocks, last_report_blockid_ + 1, num); int64_t blocks_num = blocks.size(); for (int64_t i = 0; i < blocks_num; i++) { @@ -268,6 +272,10 @@ void ChunkServerImpl::SendBlockReport() { if (blocks_num < params_.report_size()) { last_report_blockid_ = -1; + if (first_round_report_) { + first_round_report_ = false; + LOG(INFO, "[SendBlockReport] First found done"); + } } else { if (blocks_num) { last_report_blockid_ = blocks[blocks_num - 1].block_id(); diff --git a/src/chunkserver/chunkserver_impl.h b/src/chunkserver/chunkserver_impl.h index ca8a9a98..7ef5a487 100644 --- a/src/chunkserver/chunkserver_impl.h +++ b/src/chunkserver/chunkserver_impl.h @@ -94,6 +94,7 @@ class ChunkServerImpl : public ChunkServer { volatile int64_t blockreport_task_id_; int64_t last_report_blockid_; int64_t report_id_; + bool first_round_report_; volatile bool service_stop_; Params params_; From e7ea629b1d999b353ebed2ba667bb581dc7c9334 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 13:19:06 +0800 Subject: [PATCH 09/38] Create roadmap.md --- docs/roadmap.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docs/roadmap.md diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 00000000..ee0c4d58 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,21 @@ +# Roadmap + +## 基本功能 +- [x] 基本文件、目录操作(Create/Delete/Read/Write/Rename) +- [x] 多副本冗余、自动副本恢复 +- [x] Nameserver高可用 +- [ ] 磁盘负载均衡 +- [ ] 文件锁 +- [x] 简单多地域副本放置 +- [ ] 副本放置策略插件化 + +## Posix接口 +- [x] mount支持 +- [x] 基本读写操作(不包括随机写) +- [x] 小文件随机写, 支持vim,gcc等应用 +- [ ] 大文件随机写 + +## 应用支持 +- [x] Tera +- [ ] Shuttle +- [ ] Galaxy From 91ccc0fb8a4c2716b3021a2eab91d09930c6abe2 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 13:20:33 +0800 Subject: [PATCH 10/38] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d171c374..2c29ddb2 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ sh build.sh cd sandbox; sh deploy.sh; sh start.sh ## Contributing -阅读[RoadMap](doc/roadmap.md)文件,了解我们当前的开发方向,然后提pull request就可以了。 -Please see the [RoadMap](doc/roadmap.md) file for how to help out, and then send pull request to us. +阅读[RoadMap](docs/roadmap.md)文件,了解我们当前的开发方向,然后提pull request就可以了。 +Please see the [RoadMap](docs/roadmap.md) file for how to help out, and then send pull request to us. ## Contact us opensearch@baidu.com From 5b110a00eca1a27d56541b4b5240b3d517e3ce93 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Wed, 12 Oct 2016 13:24:15 +0800 Subject: [PATCH 11/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c29ddb2..e403ca05 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The Baidu File System (BFS) is a distributed file system designed to support rea 2. High throughput 通过高性能的单机引擎,最大化存储介质IO吞吐; 3. Low latency -全局负载均衡、慢节点发现 +全局负载均衡、慢节点自动规避 4. Linear scalability 设计支持两地三机房,1万+台机器管理。 From ea83b1a0a2108c4e2a9a9c487dfee1fd69752bee Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 12 Oct 2016 18:42:30 +0800 Subject: [PATCH 12/38] Update roadmap --- docs/roadmap.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/roadmap.md b/docs/roadmap.md index ee0c4d58..ba6c57ba 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -4,13 +4,18 @@ - [x] 基本文件、目录操作(Create/Delete/Read/Write/Rename) - [x] 多副本冗余、自动副本恢复 - [x] Nameserver高可用 +- [ ] Nameserver拆分出Metaserver - [ ] 磁盘负载均衡 +- [ ] chunkserver间动态负载均衡 - [ ] 文件锁 - [x] 简单多地域副本放置 - [ ] 副本放置策略插件化 +- [ ] sdk lease +- [ ] 读文件跳过慢节点 ## Posix接口 - [x] mount支持 +- [ ] fuse lowlevel实现 - [x] 基本读写操作(不包括随机写) - [x] 小文件随机写, 支持vim,gcc等应用 - [ ] 大文件随机写 From 7adddadf66a9c0bf192c81e9aa8c34e183dd38d8 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 12 Oct 2016 21:09:20 +0800 Subject: [PATCH 13/38] Add build.sh --- build.sh | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100755 build.sh diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..b77d5a94 --- /dev/null +++ b/build.sh @@ -0,0 +1,203 @@ +#!/bin/bash + +set -e -u -E # this script will exit if any sub-command fails + +######################################## +# download & build depend software +######################################## + +WORK_DIR=`pwd` +DEPS_SOURCE=`pwd`/thirdsrc +DEPS_PREFIX=`pwd`/thirdparty +DEPS_CONFIG="--prefix=${DEPS_PREFIX} --disable-shared --with-pic" +FLAG_DIR=`pwd`/.build + +export PATH=${DEPS_PREFIX}/bin:$PATH +mkdir -p ${DEPS_SOURCE} ${DEPS_PREFIX} ${FLAG_DIR} + +if [ ! -f "${FLAG_DIR}/dl_third" ] || [ ! -d "${DEPS_SOURCE}/.git" ]; then + rm -rf ${DEPS_SOURCE} + mkdir ${DEPS_SOURCE} + wget --no-check-certificate http://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.gz + wget --no-check-certificate https://github.com/gperftools/gperftools/releases/download/gperftools-2.2.1/gperftools-2.2.1.tar.gz -O ${DEPS_SOURCE}/gperftools-2.2.1.tar.gz + git clone https://github.com/yvxiang/gtest.git ${DEPS_SOURCE}/gtest + wget --no-check-certificate https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz -O ${DEPS_SOURCE}/protobuf-2.6.1.tar.gz + wget --no-check-certificate https://github.com/gflags/gflags/archive/v2.1.1.tar.gz -O ${DEPS_SOURCE}/gflags-2.1.1.tar.gz + wget --no-check-certificate http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz -P ${DEPS_SOURCE} + wget --no-check-certificate http://pkgs.fedoraproject.org/repo/pkgs/snappy/snappy-1.1.1.tar.gz/8887e3b7253b22a31f5486bca3cbc1c2/snappy-1.1.1.tar.gz -P ${DEPS_SOURCE} + wget --no-check-certificate https://cmake.org/files/v3.2/cmake-3.2.1.tar.gz -P ${DEPS_SOURCE} + touch "${FLAG_DIR}/dl_third" +fi + +cd ${DEPS_SOURCE} + +# boost +if [ ! -f "${FLAG_DIR}/boost_1_57_0" ] \ + || [ ! -d "${DEPS_PREFIX}/boost_1_57_0/boost" ]; then + tar zxf boost_1_57_0.tar.gz + rm -rf ${DEPS_PREFIX}/boost_1_57_0 + mv boost_1_57_0 ${DEPS_PREFIX}/boost_1_57_0 + touch "${FLAG_DIR}/boost_1_57_0" +fi + +# protobuf +if [ ! -f "${FLAG_DIR}/protobuf_2_6_1" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libprotobuf.a" ] \ + || [ ! -d "${DEPS_PREFIX}/include/google/protobuf" ]; then + tar zxf protobuf-2.6.1.tar.gz + cd protobuf-2.6.1 + ./configure ${DEPS_CONFIG} + make -j4 + make install + cd - + touch "${FLAG_DIR}/protobuf_2_6_1" +fi + +#leveldb +if [ ! -f "${FLAG_DIR}/leveldb" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libleveldb.a" ] \ + || [ ! -d "${DEPS_PREFIX}/include/leveldb" ]; then + rm -rf leveldb + git clone https://github.com/lylei/leveldb.git leveldb + cd leveldb + echo "PREFIX=${DEPS_PREFIX}" > config.mk + make -j4 + make install + cd - + touch "${FLAG_DIR}/leveldb" +fi + +# snappy +if [ ! -f "${FLAG_DIR}/snappy_1_1_1" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libsnappy.a" ] \ + || [ ! -f "${DEPS_PREFIX}/include/snappy.h" ]; then + tar zxf snappy-1.1.1.tar.gz + cd snappy-1.1.1 + ./configure ${DEPS_CONFIG} + make -j4 + make install + cd - + touch "${FLAG_DIR}/snappy_1_1_1" +fi + +# sofa-pbrpc +if [ ! -f "${FLAG_DIR}/sofa-pbrpc_1_0_0" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libsofa-pbrpc.a" ] \ + || [ ! -d "${DEPS_PREFIX}/include/sofa/pbrpc" ]; then + rm -rf sofa-pbrpc +# git clone --depth=1 https://github.com/cyshi/sofa-pbrpc.git sofa-pbrpc + git clone --depth=1 https://github.com/baidu/sofa-pbrpc.git sofa-pbrpc + cd sofa-pbrpc + sed -i '/BOOST_HEADER_DIR=/ d' depends.mk + sed -i '/PROTOBUF_DIR=/ d' depends.mk + sed -i '/SNAPPY_DIR=/ d' depends.mk + echo "BOOST_HEADER_DIR=${DEPS_PREFIX}/boost_1_57_0" >> depends.mk + echo "PROTOBUF_DIR=${DEPS_PREFIX}" >> depends.mk + echo "SNAPPY_DIR=${DEPS_PREFIX}" >> depends.mk + echo "PREFIX=${DEPS_PREFIX}" >> depends.mk + make -j4 + make install + cd - + touch "${FLAG_DIR}/sofa-pbrpc_1_0_0" +fi + +# cmake for gflags +if ! which cmake ; then + tar zxf cmake-3.2.1.tar.gz + cd cmake-3.2.1 + ./configure --prefix=${DEPS_PREFIX} + make -j4 + make install + cd - +fi + +# gflags +if [ ! -f "${FLAG_DIR}/gflags_2_1_1" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libgflags.a" ] \ + || [ ! -d "${DEPS_PREFIX}/include/gflags" ]; then + tar zxf gflags-2.1.1.tar.gz + cd gflags-2.1.1 + cmake -DCMAKE_INSTALL_PREFIX=${DEPS_PREFIX} -DGFLAGS_NAMESPACE=google -DCMAKE_CXX_FLAGS=-fPIC + make -j4 + make install + cd - + touch "${FLAG_DIR}/gflags_2_1_1" +fi + +# gtest +if [ ! -f "${FLAG_DIR}/gtest_1_7_0" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libgtest.a" ] \ + || [ ! -d "${DEPS_PREFIX}/include/gtest" ]; then + cd gtest + ./configure ${DEPS_CONFIG} + make + cp -a lib/.libs/* ${DEPS_PREFIX}/lib + cp -a include/gtest ${DEPS_PREFIX}/include + cd - + touch "${FLAG_DIR}/gtest_1_7_0" +fi + +# libunwind for gperftools +if [ ! -f "${FLAG_DIR}/libunwind_0_99" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libunwind.a" ] \ + || [ ! -f "${DEPS_PREFIX}/include/libunwind.h" ]; then + tar zxf libunwind-0.99.tar.gz + cd libunwind-0.99 + ./configure ${DEPS_CONFIG} + make CFLAGS=-fPIC -j4 + make CFLAGS=-fPIC install + cd - + touch "${FLAG_DIR}/libunwind_0_99" +fi + +# gperftools (tcmalloc) +if [ ! -f "${FLAG_DIR}/gperftools_2_2_1" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libtcmalloc_minimal.a" ]; then + tar zxf gperftools-2.2.1.tar.gz + cd gperftools-2.2.1 + ./configure ${DEPS_CONFIG} CPPFLAGS=-I${DEPS_PREFIX}/include LDFLAGS=-L${DEPS_PREFIX}/lib + make -j4 + make install + cd - + touch "${FLAG_DIR}/gperftools_2_2_1" +fi + +# common +if [ ! -f "${FLAG_DIR}/common" ] \ + || [ ! -f "${DEPS_PREFIX}/lib/libcommon.a" ]; then + rm -rf common + git clone https://github.com/baidu/common + cd common + sed -i 's/^PREFIX=.*/PREFIX=..\/..\/thirdparty/' config.mk + sed -i '/^INCLUDE_PATH=*/s/$/ -I..\/..\/thirdparty\/boost_1_57_0/g' Makefile + make -j4 + make install + cd - + touch "${FLAG_DIR}/common" +fi + + +cd ${WORK_DIR} + +######################################## +# config depengs.mk +######################################## + +echo "PBRPC_PATH=./thirdparty" > depends.mk +echo "PROTOBUF_PATH=./thirdparty" >> depends.mk +echo "PROTOC_PATH=./thirdparty/bin/" >> depends.mk +echo 'PROTOC=$(PROTOC_PATH)protoc' >> depends.mk +echo "PBRPC_PATH=./thirdparty" >> depends.mk +echo "BOOST_PATH=./thirdparty/boost_1_57_0" >> depends.mk +echo "GFLAG_PATH=./thirdparty" >> depends.mk +echo "GTEST_PATH=./thirdparty" >> depends.mk +echo "COMMON_PATH=./thirdparty" >> depends.mk +echo "TCMALLOC_PATH=./thirdparty" >> depends.mk + +######################################## +# build tera +######################################## + +make clean +make -j4 + From 3d12e7b1abc198a45a39aee040de580e6eaa4abe Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 12 Oct 2016 21:20:21 +0800 Subject: [PATCH 14/38] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e403ca05..1cda0f9d 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ The Baidu File System (BFS) is a distributed file system designed to support rea ## Quick Start #### Build -sh build.sh +./build.sh #### Standalone BFS -cd sandbox; sh deploy.sh; sh start.sh +cd sandbox; ./deploy.sh; ./start.sh ## Contributing 阅读[RoadMap](docs/roadmap.md)文件,了解我们当前的开发方向,然后提pull request就可以了。 From f945604f62ef99459ba91eacd26d880829c23e1a Mon Sep 17 00:00:00 2001 From: lylei Date: Fri, 14 Oct 2016 17:16:36 +0800 Subject: [PATCH 15/38] report do not modify start_id --- src/chunkserver/block_manager.cc | 9 +++---- src/chunkserver/block_manager.h | 2 +- src/chunkserver/chunkserver_impl.cc | 37 ++++++++++------------------- src/chunkserver/chunkserver_impl.h | 2 +- 4 files changed, 20 insertions(+), 30 deletions(-) mode change 100644 => 100755 src/chunkserver/block_manager.cc mode change 100644 => 100755 src/chunkserver/block_manager.h mode change 100644 => 100755 src/chunkserver/chunkserver_impl.cc mode change 100644 => 100755 src/chunkserver/chunkserver_impl.h diff --git a/src/chunkserver/block_manager.cc b/src/chunkserver/block_manager.cc old mode 100644 new mode 100755 index 013120b4..a7d1ad54 --- a/src/chunkserver/block_manager.cc +++ b/src/chunkserver/block_manager.cc @@ -234,15 +234,15 @@ bool BlockManager::SetNameSpaceVersion(int64_t version) { return true; } -bool BlockManager::ListBlocks(std::vector* blocks, int64_t offset, int32_t num) { +int64_t BlockManager::ListBlocks(std::vector* blocks, int64_t offset, int32_t num) { leveldb::Iterator* it = metadb_->NewIterator(leveldb::ReadOptions()); + int64_t largest_id = 0; for (it->Seek(BlockId2Str(offset)); it->Valid(); it->Next()) { int64_t block_id = 0; if (1 != sscanf(it->key().data(), "%ld", &block_id)) { LOG(WARNING, "[ListBlocks] Unknown meta key: %s\n", it->key().ToString().c_str()); - delete it; - return false; + break; } BlockMeta meta; bool ret = meta.ParseFromArray(it->value().data(), it->value().size()); @@ -254,13 +254,14 @@ bool BlockManager::ListBlocks(std::vector* blocks, int64_t offset, in } assert(meta.block_id() == block_id); blocks->push_back(meta); + largest_id = block_id; // LOG(DEBUG, "List block %ld", block_id); if (--num <= 0) { break; } } delete it; - return true; + return largest_id; } Block* BlockManager::CreateBlock(int64_t block_id, int64_t* sync_time, StatusCode* status) { diff --git a/src/chunkserver/block_manager.h b/src/chunkserver/block_manager.h old mode 100644 new mode 100755 index 47bc98cb..b7e5c18a --- a/src/chunkserver/block_manager.h +++ b/src/chunkserver/block_manager.h @@ -37,7 +37,7 @@ class BlockManager { bool LoadStorage(); int64_t NameSpaceVersion() const; bool SetNameSpaceVersion(int64_t version); - bool ListBlocks(std::vector* blocks, int64_t offset, int32_t num); + int64_t ListBlocks(std::vector* blocks, int64_t offset, int32_t num); Block* CreateBlock(int64_t block_id, int64_t* sync_time, StatusCode* status); Block* FindBlock(int64_t block_id); std::string BlockId2Str(int64_t block_id); diff --git a/src/chunkserver/chunkserver_impl.cc b/src/chunkserver/chunkserver_impl.cc old mode 100644 new mode 100755 index 1fac8d92..0ec782f3 --- a/src/chunkserver/chunkserver_impl.cc +++ b/src/chunkserver/chunkserver_impl.cc @@ -81,7 +81,7 @@ ChunkServerImpl::ChunkServerImpl() blockreport_task_id_(-1), last_report_blockid_(-1), report_id_(0), - first_round_report_(true), + first_round_report_start_(-1), service_stop_(false) { data_server_addr_ = common::util::GetLocalHostName() + ":" + FLAGS_chunkserver_port; params_.set_report_interval(FLAGS_blockreport_interval); @@ -185,8 +185,7 @@ void ChunkServerImpl::Register() { assert (response.chunkserver_id() != -1); chunkserver_id_ = response.chunkserver_id(); report_id_ = response.report_id() + 1; - first_round_report_ = true; - last_report_blockid_ = -1; + first_round_report_start_ = last_report_blockid_; LOG(INFO, "Connect to nameserver version= %ld, cs_id = C%d report_interval = %d " "report_size = %d report_id = %ld", block_manager_->NameSpaceVersion(), chunkserver_id_, @@ -259,8 +258,12 @@ void ChunkServerImpl::SendBlockReport() { int64_t last_report_id = report_id_; std::vector blocks; - int32_t num = first_round_report_ ? 10000 : params_.report_size(); - block_manager_->ListBlocks(&blocks, last_report_blockid_ + 1, num); + int32_t num = first_round_report_start_ == -1 ? params_.report_size() : 1000; + int32_t end = block_manager_->ListBlocks(&blocks, last_report_blockid_ + 1, num); + if (last_report_blockid_ < first_round_report_start_ && first_round_report_start_ <= end) { + first_round_report_start_ = -1; + LOG(INFO, "First round report done"); + } int64_t blocks_num = blocks.size(); for (int64_t i = 0; i < blocks_num; i++) { @@ -270,32 +273,18 @@ void ChunkServerImpl::SendBlockReport() { info->set_version(blocks[i].version()); } - if (blocks_num < params_.report_size()) { + if (blocks_num < num) { last_report_blockid_ = -1; - if (first_round_report_) { - first_round_report_ = false; - LOG(INFO, "[SendBlockReport] First found done"); - } - } else { - if (blocks_num) { - last_report_blockid_ = blocks[blocks_num - 1].block_id(); - } - } - if (blocks_num == 0) { - request.set_end(0); } else { - request.set_end(blocks[blocks_num - 1].block_id()); + last_report_blockid_ = end; } + request.set_end(end); BlockReportResponse response; - int64_t before_report = common::timer::get_micros(); + common::timer::TimeChecker checker; bool ret = nameserver_->SendRequest(&NameServer_Stub::BlockReport, &request, &response, FLAGS_block_report_timeout); - int64_t after_report = common::timer::get_micros(); - if (after_report - before_report > 20 * 1000 * 1000) { - LOG(WARNING, "Block report use %ld ms last_id %lu (%lu)", - (after_report - before_report) / 1000, last_report_id, request.sequence_id()); - } + checker.Check(20 * 1000 * 1000, "[SendBlockReport] SendRequest"); if (!ret) { LOG(WARNING, "Block report fail last_id %lu (%lu)\n", last_report_id, request.sequence_id()); } else { diff --git a/src/chunkserver/chunkserver_impl.h b/src/chunkserver/chunkserver_impl.h old mode 100644 new mode 100755 index 7ef5a487..78a0a572 --- a/src/chunkserver/chunkserver_impl.h +++ b/src/chunkserver/chunkserver_impl.h @@ -94,7 +94,7 @@ class ChunkServerImpl : public ChunkServer { volatile int64_t blockreport_task_id_; int64_t last_report_blockid_; int64_t report_id_; - bool first_round_report_; + int64_t first_round_report_start_; volatile bool service_stop_; Params params_; From 5dec6c181b12d42042654d7d2d3f89d6e1aa8c82 Mon Sep 17 00:00:00 2001 From: lylei Date: Tue, 18 Oct 2016 16:48:35 +0800 Subject: [PATCH 16/38] report size fix --- src/chunkserver/block_manager.cc | 0 src/chunkserver/block_manager.h | 0 src/chunkserver/chunkserver_impl.cc | 15 ++++++++++++--- src/chunkserver/chunkserver_impl.h | 1 + 4 files changed, 13 insertions(+), 3 deletions(-) mode change 100755 => 100644 src/chunkserver/block_manager.cc mode change 100755 => 100644 src/chunkserver/block_manager.h mode change 100755 => 100644 src/chunkserver/chunkserver_impl.cc mode change 100755 => 100644 src/chunkserver/chunkserver_impl.h diff --git a/src/chunkserver/block_manager.cc b/src/chunkserver/block_manager.cc old mode 100755 new mode 100644 diff --git a/src/chunkserver/block_manager.h b/src/chunkserver/block_manager.h old mode 100755 new mode 100644 diff --git a/src/chunkserver/chunkserver_impl.cc b/src/chunkserver/chunkserver_impl.cc old mode 100755 new mode 100644 index 0ec782f3..919c8eca --- a/src/chunkserver/chunkserver_impl.cc +++ b/src/chunkserver/chunkserver_impl.cc @@ -81,6 +81,7 @@ ChunkServerImpl::ChunkServerImpl() blockreport_task_id_(-1), last_report_blockid_(-1), report_id_(0), + is_first_round_(true), first_round_report_start_(-1), service_stop_(false) { data_server_addr_ = common::util::GetLocalHostName() + ":" + FLAGS_chunkserver_port; @@ -186,6 +187,7 @@ void ChunkServerImpl::Register() { chunkserver_id_ = response.chunkserver_id(); report_id_ = response.report_id() + 1; first_round_report_start_ = last_report_blockid_; + is_first_round_ = true; LOG(INFO, "Connect to nameserver version= %ld, cs_id = C%d report_interval = %d " "report_size = %d report_id = %ld", block_manager_->NameSpaceVersion(), chunkserver_id_, @@ -258,12 +260,19 @@ void ChunkServerImpl::SendBlockReport() { int64_t last_report_id = report_id_; std::vector blocks; - int32_t num = first_round_report_start_ == -1 ? params_.report_size() : 1000; + int32_t num = is_first_round_ ? 10000 : params_.report_size(); int32_t end = block_manager_->ListBlocks(&blocks, last_report_blockid_ + 1, num); - if (last_report_blockid_ < first_round_report_start_ && first_round_report_start_ <= end) { - first_round_report_start_ = -1; + // last id + 1 <= first found report start <= end -> first round ends + if (is_first_round_ && + (last_report_blockid_ + 1) <= first_round_report_start_ && + first_round_report_start_ <= end) { + is_first_round_ = false; LOG(INFO, "First round report done"); } + // bugfix, need an elegant implementation T_T + if (is_first_round_ && first_round_report_start_ == -1) { + first_round_report_start_ = 0; + } int64_t blocks_num = blocks.size(); for (int64_t i = 0; i < blocks_num; i++) { diff --git a/src/chunkserver/chunkserver_impl.h b/src/chunkserver/chunkserver_impl.h old mode 100755 new mode 100644 index 78a0a572..6c3fc771 --- a/src/chunkserver/chunkserver_impl.h +++ b/src/chunkserver/chunkserver_impl.h @@ -94,6 +94,7 @@ class ChunkServerImpl : public ChunkServer { volatile int64_t blockreport_task_id_; int64_t last_report_blockid_; int64_t report_id_; + bool is_first_round_; int64_t first_round_report_start_; volatile bool service_stop_; From c51ec80d856a5a911fd95ae32db2f74d5cbe7f36 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 19 Oct 2016 10:30:35 +0800 Subject: [PATCH 17/38] Fix du return value --- src/client/bfs_client.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/bfs_client.cc b/src/client/bfs_client.cc index b4a9cc28..3a9ff613 100644 --- a/src/client/bfs_client.cc +++ b/src/client/bfs_client.cc @@ -269,7 +269,8 @@ int BfsDu(baidu::bfs::FS* fs, int argc, char* argv[]) { std::string path = argv[0]; assert(path.size() > 0); if (path[path.size() - 1] != '*') { - return BfsDuV2(fs, path); + int64_t du_size = BfsDuV2(fs, path); + return du_size >= 0 ? 0 : -1; } // Wildcard From 7ce0932f587b3338a5086cc022318441a00a6df1 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 19 Oct 2016 11:29:50 +0800 Subject: [PATCH 18/38] Disable change replica num interface --- src/client/bfs_client.cc | 3 --- src/sdk/fs_impl.cc | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/bfs_client.cc b/src/client/bfs_client.cc index b4a9cc28..062171d9 100644 --- a/src/client/bfs_client.cc +++ b/src/client/bfs_client.cc @@ -37,11 +37,8 @@ void print_usage() { printf("\t put : copy file from local to bfs\n"); printf("\t rmdir : remove empty directory\n"); printf("\t rmr : remove directory recursively\n"); - printf("\t change_replica_num : change replica num of to \n"); printf("\t du : count disk usage for path\n"); printf("\t stat : list current stat of the file system\n"); - printf("\t shutdownchunkserver : shutdownt chunkservers in the list file\n"); - printf("\t shutdownstat : display stat of shutdown chunkserver progress\n"); } int BfsMkdir(baidu::bfs::FS* fs, int argc, char* argv[]) { diff --git a/src/sdk/fs_impl.cc b/src/sdk/fs_impl.cc index f2a18d58..8a2418e0 100644 --- a/src/sdk/fs_impl.cc +++ b/src/sdk/fs_impl.cc @@ -399,6 +399,7 @@ int32_t FSImpl::Rename(const char* oldpath, const char* newpath) { return OK; } int32_t FSImpl::ChangeReplicaNum(const char* file_name, int32_t replica_num) { + /* ChangeReplicaNumRequest request; ChangeReplicaNumResponse response; request.set_file_name(file_name); @@ -416,6 +417,7 @@ int32_t FSImpl::ChangeReplicaNum(const char* file_name, int32_t replica_num) { file_name, replica_num, StatusCode_Name(response.status()).c_str()); return GetErrorCode(response.status()); } + */ return OK; } int32_t FSImpl::SysStat(const std::string& stat_name, std::string* result) { From 7b8b520a1d65d36d2f06b98f3fe4310e2fe747b6 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 19 Oct 2016 15:32:15 +0800 Subject: [PATCH 19/38] Disallow create a file with same name in a directory --- src/nameserver/namespace.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nameserver/namespace.cc b/src/nameserver/namespace.cc index 2007df9b..d94dcb9e 100644 --- a/src/nameserver/namespace.cc +++ b/src/nameserver/namespace.cc @@ -251,6 +251,10 @@ StatusCode NameSpace::CreateFile(const std::string& path, int flags, int mode, i LOG(INFO, "CreateFile %s fail: already exist!", fname.c_str()); return kFileExists; } else { + if (IsDir(file_info.type())) { + LOG(INFO, "CreateFile %s fail: directory with same name exist", fname.c_str()); + return kFileExists; + } for (int i = 0; i < file_info.blocks_size(); i++) { blocks_to_remove->push_back(file_info.blocks(i)); } From b7805ae3b5eb1d365195b031d045920ff4bb243d Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 19 Oct 2016 16:32:13 +0800 Subject: [PATCH 20/38] Fix return value --- src/sdk/fs_impl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdk/fs_impl.cc b/src/sdk/fs_impl.cc index 8a2418e0..05f689a6 100644 --- a/src/sdk/fs_impl.cc +++ b/src/sdk/fs_impl.cc @@ -418,7 +418,7 @@ int32_t FSImpl::ChangeReplicaNum(const char* file_name, int32_t replica_num) { return GetErrorCode(response.status()); } */ - return OK; + return PERMISSION_DENIED; } int32_t FSImpl::SysStat(const std::string& stat_name, std::string* result) { SysStatRequest request; From e4dc71ef1fb252718343eb772edeccea54b2379f Mon Sep 17 00:00:00 2001 From: yvxiang Date: Wed, 19 Oct 2016 17:23:44 +0800 Subject: [PATCH 21/38] Allow change flag clean_redundancy in web --- src/nameserver/nameserver_impl.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/nameserver/nameserver_impl.cc b/src/nameserver/nameserver_impl.cc index cf933c2b..33e641d4 100644 --- a/src/nameserver/nameserver_impl.cc +++ b/src/nameserver/nameserver_impl.cc @@ -38,6 +38,7 @@ DECLARE_int32(blockmapping_bucket_num); DECLARE_int32(hi_recover_timeout); DECLARE_int32(lo_recover_timeout); DECLARE_int32(block_report_timeout); +DECLARE_bool(clean_redundancy); namespace baidu { namespace bfs { @@ -1072,7 +1073,10 @@ bool NameServerImpl::WebService(const sofa::pbrpc::HTTPRequest& request, std::map::const_iterator it = request.query_params->begin(); Params p; if (it != request.query_params->end()) { - int32_t v = boost::lexical_cast(it->second); + int32_t v = 0; + if (it->first != "clean_redundancy") { + v = boost::lexical_cast(it->second); + } if (it->first == "report_interval") { if (v < 1 || v > 3600) { response.content->Append("

Bad Parameter : 1 <= report_interval <= 3600

"); @@ -1103,6 +1107,12 @@ bool NameServerImpl::WebService(const sofa::pbrpc::HTTPRequest& request, return true; } FLAGS_block_report_timeout = v; + } else if (it->first == "clean_redundancy") { + if (it->second != "true" && it->second != "false") { + response.content->Append("

Bad Parameter : clean_redundancy == true || false"); + return true; + } + FLAGS_clean_redundancy = it->second == "true" ? true : false; } else { response.content->Append("

Bad Parameter :"); response.content->Append(it->first); From b2ae8f548f464a0c9e6bf133cf84772c8b892775 Mon Sep 17 00:00:00 2001 From: lylei Date: Thu, 20 Oct 2016 17:21:10 +0800 Subject: [PATCH 22/38] small fix --- build_version.sh | 1 - src/test/mark.cc | 6 +++--- src/version.h | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build_version.sh b/build_version.sh index 1fd54332..5e30501e 100755 --- a/build_version.sh +++ b/build_version.sh @@ -19,7 +19,6 @@ gen_info_template_foot () echo "extern const char kBuildTime[] = \"$BUILD_DATE_TIME\";" echo "extern const char kBuilderName[] = \"$USER\";" echo "extern const char kHostName[] = \"$BUILD_HOSTNAME\";" - echo "extern const char kCompiler[] = \"$BUILD_GCC_VERSION\";" } gen_info_print_template () diff --git a/src/test/mark.cc b/src/test/mark.cc index 7f3dd972..88301dbd 100644 --- a/src/test/mark.cc +++ b/src/test/mark.cc @@ -20,7 +20,7 @@ DEFINE_string(mode, "put", "[put | read]"); DEFINE_int64(count, 0, "put/read/delete file count"); DEFINE_int32(thread, 5, "thread num"); DEFINE_int32(seed, 301, "random seed"); -DEFINE_int32(file_size, 1024, "file size in KB"); +DEFINE_int64(file_size, 1024, "file size in KB"); DEFINE_string(folder, "test", "write data to which folder"); DEFINE_bool(break_on_failure, true, "exit when error occurs"); @@ -87,7 +87,7 @@ void Mark::Put(const std::string& filename, const std::string& base, int thread_ int64_t len = 0; int64_t base_size = (1 << 20) / 2; while (len < file_size_) { - uint32_t w = base_size + rand_[thread_id]->Uniform(base_size); + uint64_t w = base_size + rand_[thread_id]->Uniform(base_size); uint32_t write_len = file->Write(base.c_str(), w); if (write_len != w) { @@ -145,7 +145,7 @@ void Mark::Read(const std::string& filename, const std::string& base, int thread int64_t bytes = 0; int32_t len = 0; while (1) { - uint32_t r = base_size + rand_[thread_id]->Uniform(base_size); + uint64_t r = base_size + rand_[thread_id]->Uniform(base_size); len = file->Read(buf, r); if (len < 0) { if (FLAGS_break_on_failure) { diff --git a/src/version.h b/src/version.h index 1bef16af..c748402c 100644 --- a/src/version.h +++ b/src/version.h @@ -8,6 +8,7 @@ static const int kMajorVersion = 1; static const int kMinorVersion = 0; static const int kRevision = 0; +static const char kCompiler[] = __VERSION__; extern void PrintSystemVersion(); From 5c79e35b4bb9009ed6f89c2043e11b45abf0f7eb Mon Sep 17 00:00:00 2001 From: yvxiang Date: Fri, 21 Oct 2016 15:08:13 +0800 Subject: [PATCH 23/38] Update doc --- docs/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8d3b2ed6..ead513fc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,5 @@ TODO ======== -* chunkserver支持全异步写 -* 整理错误码 -* 目录移动(In progress) -* 副本恢复 -* master主从同步 * Docker image * 负载均衡 * 机架&数据中心感知 @@ -21,3 +16,8 @@ DONE * 自定义副本数 * 多盘支持 * 扇出写支持 +* chunkserver支持全异步写 +* 整理错误码 +* 目录移动 +* 副本恢复 +* master主从同步 From 2ac57f51501887bb0ecbf626ef7e9bc623cb93df Mon Sep 17 00:00:00 2001 From: yvxiang Date: Fri, 21 Oct 2016 17:03:30 +0800 Subject: [PATCH 24/38] Remove README.md in docs/ --- docs/README.md | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index ead513fc..00000000 --- a/docs/README.md +++ /dev/null @@ -1,23 +0,0 @@ -TODO -======== -* Docker image -* 负载均衡 -* 机架&数据中心感知 -* 规避慢节点 - -DONE -======== -* 文件移动 -* 滑动窗口 -* 定时器 -* Tera env -* 目录删除 -* 增量Report -* 自定义副本数 -* 多盘支持 -* 扇出写支持 -* chunkserver支持全异步写 -* 整理错误码 -* 目录移动 -* 副本恢复 -* master主从同步 From 2b3a2fa9617117acca88fa93cbbffcf55fae9996 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Sat, 22 Oct 2016 09:19:49 +0800 Subject: [PATCH 25/38] Update how to contribute --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1cda0f9d..6906ef42 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ The Baidu File System (BFS) is a distributed file system designed to support rea #### Standalone BFS cd sandbox; ./deploy.sh; ./start.sh -## Contributing -阅读[RoadMap](docs/roadmap.md)文件,了解我们当前的开发方向,然后提pull request就可以了。 -Please see the [RoadMap](docs/roadmap.md) file for how to help out, and then send pull request to us. +## How to Contribute +阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull reques。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ +Please see the [RoadMap](docs/roadmap.md) file or source code for how to help out, select features which you are interested in, coding and and then send pull request to us. After the codereview, your code will run in thousands of servers~ ## Contact us opensearch@baidu.com From 2897acab44016dd97f480fb8c1329762a8ffbbc5 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Sat, 22 Oct 2016 09:25:50 +0800 Subject: [PATCH 26/38] Update README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6906ef42..5e9ef183 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,10 @@ The Baidu File System (BFS) is a distributed file system designed to support rea cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute -阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull reques。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ Please see the [RoadMap](docs/roadmap.md) file or source code for how to help out, select features which you are interested in, coding and and then send pull request to us. After the codereview, your code will run in thousands of servers~ +阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull reques。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ + ## Contact us opensearch@baidu.com From b7204c29eb4db16f49d37ccc4810662eb84f7a15 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Sat, 22 Oct 2016 09:27:14 +0800 Subject: [PATCH 27/38] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e9ef183..afcbd423 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute Please see the [RoadMap](docs/roadmap.md) file or source code for how to help out, select features which you are interested in, coding and and then send pull request to us. After the codereview, your code will run in thousands of servers~ -阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull reques。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ +阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull request。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ ## Contact us opensearch@baidu.com From 23d3c299928f2bfe367595650fdd27feda24a72b Mon Sep 17 00:00:00 2001 From: yvxiang Date: Sat, 22 Oct 2016 12:22:14 +0800 Subject: [PATCH 28/38] UPdate README --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index afcbd423..0a6ac19e 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,15 @@ The Baidu File System (BFS) is a distributed file system designed to support rea cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute -Please see the [RoadMap](docs/roadmap.md) file or source code for how to help out, select features which you are interested in, coding and and then send pull request to us. After the codereview, your code will run in thousands of servers~ - -阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向,找到自己感兴趣的功能或模块进行开发,并进行自测,然后发起pull request。CodeReview通过后,您的代码便有机会运行在百度数以万计的服务器上~ +1. Please see the [RoadMap](docs/roadmap.md) file or source code. +2. Select features which you are interested in. +3. Write the code and and check whether it can pass the test(make test && make check) +4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ + +1. 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 +2. 找到自己感兴趣开发的的功能或模块 +3. 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case +4. 发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ ## Contact us opensearch@baidu.com From a547ec9655f339ff5730c4884119fad374a74a84 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Sat, 22 Oct 2016 12:26:59 +0800 Subject: [PATCH 29/38] Update README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0a6ac19e..b007a2ff 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,13 @@ cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute 1. Please see the [RoadMap](docs/roadmap.md) file or source code. + 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 2. Select features which you are interested in. + 找到自己感兴趣开发的的功能或模块 3. Write the code and and check whether it can pass the test(make test && make check) + 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case 4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ - -1. 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 -2. 找到自己感兴趣开发的的功能或模块 -3. 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case -4. 发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ + 发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ ## Contact us opensearch@baidu.com From b41ae4d268d3eb56b679431b39e94a716131bf85 Mon Sep 17 00:00:00 2001 From: Yang Ce Date: Sat, 22 Oct 2016 12:32:03 +0800 Subject: [PATCH 30/38] Update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b007a2ff..fdf42b25 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,13 @@ cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute 1. Please see the [RoadMap](docs/roadmap.md) file or source code. - 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 +阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 2. Select features which you are interested in. - 找到自己感兴趣开发的的功能或模块 +找到自己感兴趣开发的的功能或模块 3. Write the code and and check whether it can pass the test(make test && make check) - 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case +进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case 4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ - 发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ +发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ ## Contact us opensearch@baidu.com From 31db1a6fc108956415d804372e41dec76b1593c9 Mon Sep 17 00:00:00 2001 From: Yang Ce Date: Sat, 22 Oct 2016 12:34:47 +0800 Subject: [PATCH 31/38] Update README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fdf42b25..23b62b55 100644 --- a/README.md +++ b/README.md @@ -27,15 +27,16 @@ The Baidu File System (BFS) is a distributed file system designed to support rea cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute -1. Please see the [RoadMap](docs/roadmap.md) file or source code. +1. Please see the [RoadMap](docs/roadmap.md) file or source code. 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 -2. Select features which you are interested in. +2. Select features which you are interested in. 找到自己感兴趣开发的的功能或模块 -3. Write the code and and check whether it can pass the test(make test && make check) +3. Write the code and and check whether it can pass the test(make test && make check). 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case -4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ +4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ 发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ + ## Contact us opensearch@baidu.com From 10607fdf44eaef855649edcd263c627d512f0356 Mon Sep 17 00:00:00 2001 From: lylei Date: Mon, 24 Oct 2016 19:22:33 +0800 Subject: [PATCH 32/38] readme --- README.md | 64 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 23b62b55..c93e2a16 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,15 @@ The Baidu File System (BFS) is a distributed file system designed to support real-time applications. Like many other distributed file systems, BFS is highly fault-tolerant. But different from others, BFS provides low read/write latency while maintains high throughout rates. Together with [Galaxy](https://github.com/baidu/galaxy) and [Tera](http://github.com/baidu/tera), BFS supports many real-time products in Baidu, including Baidu webpage database, Baidu incremental indexing system, Baidu user behavior analysis system, etc. -百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 - ## Features -1. Continuous availability -数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 -2. High throughput -通过高性能的单机引擎,最大化存储介质IO吞吐; -3. Low latency -全局负载均衡、慢节点自动规避 -4. Linear scalability -设计支持两地三机房,1万+台机器管理。 +1. Continuous availability + * Nameserver is implemented as a `raft group`, no single point failure. +2. High throughput + * High performance data engine to maximize IO utils. +3. Low latency + * Global load balance and slow node detection. +4. Linear scalability + * Support multi data center deployment and up to 10,000 data nodes. ## Architecture ![架构图](resources/images/bfs-arch2-mini.png) @@ -27,16 +25,46 @@ The Baidu File System (BFS) is a distributed file system designed to support rea cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute -1. Please see the [RoadMap](docs/roadmap.md) file or source code. -阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 -2. Select features which you are interested in. -找到自己感兴趣开发的的功能或模块 -3. Write the code and and check whether it can pass the test(make test && make check). -进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case -4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ -发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ +1. Please read the [RoadMap](docs/roadmap.md) or source code. +2. Find something you are interested in and start working on it. +3. Test your code by simply running `make test` and `make check`. +4. Make a pull request. +5. Once your code has passed the code-review and merged, it will be run on thousands of servers :) ## Contact us opensearch@baidu.com + +百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 + +## 核心特点 +1. 持续可用 +数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 +2. 高吞吐 +通过高性能的单机引擎,最大化存储介质IO吞吐; +3. 低延时 +全局负载均衡、慢节点自动规避 +4. 水平扩展 +设计支持两地三机房,1万+台机器管理。 + +## 架构 +![架构图](resources/images/bfs-arch2-mini.png) + +## 快速试用 +#### 构建 +./build.sh +#### 单机版BFS +cd sandbox; ./deploy.sh; ./start.sh + +## How to Contribute +1. 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 +2. 找到自己感兴趣开发的的功能或模块 +3. 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case +4. 发起pull request +5. 在code-review通过后,你的代码便有机会运行在百度的数万台服务器上~ + + +## 联系我们 +opensearch@baidu.com + From 120bffbd74b6a0c9528d17a2a8f87c2c9ef475b8 Mon Sep 17 00:00:00 2001 From: lylei Date: Mon, 24 Oct 2016 19:22:33 +0800 Subject: [PATCH 33/38] readme --- README.md | 69 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 23b62b55..f3d2b613 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,15 @@ The Baidu File System (BFS) is a distributed file system designed to support real-time applications. Like many other distributed file systems, BFS is highly fault-tolerant. But different from others, BFS provides low read/write latency while maintains high throughout rates. Together with [Galaxy](https://github.com/baidu/galaxy) and [Tera](http://github.com/baidu/tera), BFS supports many real-time products in Baidu, including Baidu webpage database, Baidu incremental indexing system, Baidu user behavior analysis system, etc. -百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 - ## Features -1. Continuous availability -数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 -2. High throughput -通过高性能的单机引擎,最大化存储介质IO吞吐; -3. Low latency -全局负载均衡、慢节点自动规避 -4. Linear scalability -设计支持两地三机房,1万+台机器管理。 +1. Continuous availability + * Nameserver is implemented as a `raft group`, no single point failure. +2. High throughput + * High performance data engine to maximize IO utils. +3. Low latency + * Global load balance and slow node detection. +4. Linear scalability + * Support multi data center deployment and up to 10,000 data nodes. ## Architecture ![架构图](resources/images/bfs-arch2-mini.png) @@ -27,16 +25,51 @@ The Baidu File System (BFS) is a distributed file system designed to support rea cd sandbox; ./deploy.sh; ./start.sh ## How to Contribute -1. Please see the [RoadMap](docs/roadmap.md) file or source code. -阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 -2. Select features which you are interested in. -找到自己感兴趣开发的的功能或模块 -3. Write the code and and check whether it can pass the test(make test && make check). -进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case -4. Create a pull request to us, after codereview, your code will be run in thousands of servers~ -发起pull request,在codereview通过后,你的代码便有机会运行在百度的数万台服务器上~ +1. Please read the [RoadMap](docs/roadmap.md) or source code. +2. Find something you are interested in and start working on it. +3. Test your code by simply running `make test` and `make check`. +4. Make a pull request. +5. Once your code has passed the code-review and merged, it will be run on thousands of servers :) ## Contact us opensearch@baidu.com +==== + +[百度文件系统](http://github.com/baidu/bfs) +==== + + +百度的核心业务和数据库系统都依赖分布式文件系统作为底层存储,文件系统的可用性和性能对上层搜索业务的稳定性与效果有着至关重要的影响。现有的分布式文件系统(如HDFS等)是为离线批处理设计的,无法在保证高吞吐的情况下做到低延迟和持续可用,所以我们从搜索的业务特点出发,设计了百度文件系统。 + +## 核心特点 +1. 持续可用 +数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 +2. 高吞吐 +通过高性能的单机引擎,最大化存储介质IO吞吐; +3. 低延时 +全局负载均衡、慢节点自动规避 +4. 水平扩展 +设计支持两地三机房,1万+台机器管理。 + +## 架构 +![架构图](resources/images/bfs-arch2-mini.png) + +## 快速试用 +#### 构建 +./build.sh +#### 单机版BFS +cd sandbox; ./deploy.sh; ./start.sh + +## How to Contribute +1. 阅读[RoadMap](docs/roadmap.md)文件或者源代码,了解我们当前的开发方向 +2. 找到自己感兴趣开发的的功能或模块 +3. 进行开发,开发完成后自测功能是否正确,并运行make test及make check检查是否可以通过已有的测试case +4. 发起pull request +5. 在code-review通过后,你的代码便有机会运行在百度的数万台服务器上~ + + +## 联系我们 +opensearch@baidu.com + From a6ea32423144ea2dbefb7a00ffb609099c2f0e14 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Mon, 24 Oct 2016 22:05:57 +0800 Subject: [PATCH 34/38] Fix build.sh --- build.sh | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/build.sh b/build.sh index b77d5a94..7f1614ad 100755 --- a/build.sh +++ b/build.sh @@ -18,14 +18,7 @@ mkdir -p ${DEPS_SOURCE} ${DEPS_PREFIX} ${FLAG_DIR} if [ ! -f "${FLAG_DIR}/dl_third" ] || [ ! -d "${DEPS_SOURCE}/.git" ]; then rm -rf ${DEPS_SOURCE} mkdir ${DEPS_SOURCE} - wget --no-check-certificate http://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.gz - wget --no-check-certificate https://github.com/gperftools/gperftools/releases/download/gperftools-2.2.1/gperftools-2.2.1.tar.gz -O ${DEPS_SOURCE}/gperftools-2.2.1.tar.gz - git clone https://github.com/yvxiang/gtest.git ${DEPS_SOURCE}/gtest - wget --no-check-certificate https://github.com/google/protobuf/releases/download/v2.6.1/protobuf-2.6.1.tar.gz -O ${DEPS_SOURCE}/protobuf-2.6.1.tar.gz - wget --no-check-certificate https://github.com/gflags/gflags/archive/v2.1.1.tar.gz -O ${DEPS_SOURCE}/gflags-2.1.1.tar.gz - wget --no-check-certificate http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99.tar.gz -P ${DEPS_SOURCE} - wget --no-check-certificate http://pkgs.fedoraproject.org/repo/pkgs/snappy/snappy-1.1.1.tar.gz/8887e3b7253b22a31f5486bca3cbc1c2/snappy-1.1.1.tar.gz -P ${DEPS_SOURCE} - wget --no-check-certificate https://cmake.org/files/v3.2/cmake-3.2.1.tar.gz -P ${DEPS_SOURCE} + git clone https://github.com/yvxiang/thirdparty.git touch "${FLAG_DIR}/dl_third" fi @@ -81,11 +74,11 @@ if [ ! -f "${FLAG_DIR}/snappy_1_1_1" ] \ fi # sofa-pbrpc -if [ ! -f "${FLAG_DIR}/sofa-pbrpc_1_0_0" ] \ +if [ ! -f "${FLAG_DIR}/sofa-pbrpc" ] \ || [ ! -f "${DEPS_PREFIX}/lib/libsofa-pbrpc.a" ] \ || [ ! -d "${DEPS_PREFIX}/include/sofa/pbrpc" ]; then rm -rf sofa-pbrpc -# git clone --depth=1 https://github.com/cyshi/sofa-pbrpc.git sofa-pbrpc + git clone --depth=1 https://github.com/baidu/sofa-pbrpc.git sofa-pbrpc cd sofa-pbrpc sed -i '/BOOST_HEADER_DIR=/ d' depends.mk @@ -98,13 +91,13 @@ if [ ! -f "${FLAG_DIR}/sofa-pbrpc_1_0_0" ] \ make -j4 make install cd - - touch "${FLAG_DIR}/sofa-pbrpc_1_0_0" + touch "${FLAG_DIR}/sofa-pbrpc" fi # cmake for gflags if ! which cmake ; then - tar zxf cmake-3.2.1.tar.gz - cd cmake-3.2.1 + tar zxf CMake-3.2.1.tar.gz + cd CMake-3.2.1 ./configure --prefix=${DEPS_PREFIX} make -j4 make install @@ -128,7 +121,7 @@ fi if [ ! -f "${FLAG_DIR}/gtest_1_7_0" ] \ || [ ! -f "${DEPS_PREFIX}/lib/libgtest.a" ] \ || [ ! -d "${DEPS_PREFIX}/include/gtest" ]; then - cd gtest + cd gtest-1.7.0 ./configure ${DEPS_CONFIG} make cp -a lib/.libs/* ${DEPS_PREFIX}/lib From 1713ef4e9a6d7372262a676e41cc1ed00a4e7595 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Mon, 24 Oct 2016 22:07:51 +0800 Subject: [PATCH 35/38] Fix build.sh --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 7f1614ad..3b6a6135 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,7 @@ mkdir -p ${DEPS_SOURCE} ${DEPS_PREFIX} ${FLAG_DIR} if [ ! -f "${FLAG_DIR}/dl_third" ] || [ ! -d "${DEPS_SOURCE}/.git" ]; then rm -rf ${DEPS_SOURCE} mkdir ${DEPS_SOURCE} - git clone https://github.com/yvxiang/thirdparty.git + git clone https://github.com/yvxiang/thirdparty.git thirdsrc touch "${FLAG_DIR}/dl_third" fi From ba65104ae81ec46c6917e8e5290566f47b093b53 Mon Sep 17 00:00:00 2001 From: yvxiang Date: Mon, 24 Oct 2016 22:09:36 +0800 Subject: [PATCH 36/38] Fix build.sh --- build.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/build.sh b/build.sh index 3b6a6135..b4a59839 100755 --- a/build.sh +++ b/build.sh @@ -96,7 +96,6 @@ fi # cmake for gflags if ! which cmake ; then - tar zxf CMake-3.2.1.tar.gz cd CMake-3.2.1 ./configure --prefix=${DEPS_PREFIX} make -j4 From 8ce4c32c154483e5dd1bb54de436b5e7b24ca20c Mon Sep 17 00:00:00 2001 From: Yang Ce Date: Mon, 24 Oct 2016 22:16:48 +0800 Subject: [PATCH 37/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38ac377d..86c168a9 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ opensearch@baidu.com 数据多机房、多地域冗余,元数据通过Raft维护一致性,单个机房宕机,不影响整体可用性。 2. 高吞吐 通过高性能的单机引擎,最大化存储介质IO吞吐; -3. 低延时 +3. 低延时 全局负载均衡、慢节点自动规避 4. 水平扩展 设计支持两地三机房,1万+台机器管理。 From 65d521068df1374e150e706fe3cd8fea695d5474 Mon Sep 17 00:00:00 2001 From: Yan Shiguang Date: Mon, 24 Oct 2016 22:58:09 +0800 Subject: [PATCH 38/38] Update roadmap.md --- docs/roadmap.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/roadmap.md b/docs/roadmap.md index ba6c57ba..084ff365 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -1,26 +1,25 @@ # Roadmap -## 基本功能 -- [x] 基本文件、目录操作(Create/Delete/Read/Write/Rename) -- [x] 多副本冗余、自动副本恢复 -- [x] Nameserver高可用 -- [ ] Nameserver拆分出Metaserver -- [ ] 磁盘负载均衡 -- [ ] chunkserver间动态负载均衡 -- [ ] 文件锁 -- [x] 简单多地域副本放置 -- [ ] 副本放置策略插件化 +## Basic functions +- [x] Basic files, directory operations(Create/Delete/Read/Write/Rename) +- [x] automatic recovery +- [x] Nameserver HA +- [ ] Split the Metaserver from the Nameserver +- [ ] disk loadbalance +- [ ] Dynamic load balancing of chunkserver +- [ ] File Lock & Directory Lock +- [x] Simple multi-geographical replica placement - [ ] sdk lease -- [ ] 读文件跳过慢节点 +- [ ] Skip slow nodes while reading a file -## Posix接口 -- [x] mount支持 -- [ ] fuse lowlevel实现 -- [x] 基本读写操作(不包括随机写) -- [x] 小文件随机写, 支持vim,gcc等应用 -- [ ] 大文件随机写 +## Posix interface +- [x] mount support +- [ ] fuse lowlevel +- [x] Basic read and write operations(not include random writes) +- [x] Small file random write, support vim, gcc and other applications +- [ ] Large file random write -## 应用支持 +## Application support - [x] Tera - [ ] Shuttle - [ ] Galaxy