From 959dd959953d8df0edd291d57687a4e2736e285f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E7=A5=A5?= <1366971433@qq.com> Date: Wed, 17 Apr 2019 11:31:20 +0800 Subject: [PATCH] =?UTF-8?q?storm=E6=95=B4=E5=90=88redis=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/Storm/storm-redis-integration/pom.xml | 57 ++++++++++++++++++ .../com/heibaiying/CustomRedisCountApp.java | 45 ++++++++++++++ .../com/heibaiying/WordCountToRedisApp.java | 57 ++++++++++++++++++ .../com/heibaiying/component/CountBolt.java | 44 ++++++++++++++ .../heibaiying/component/DataSourceSpout.java | 49 +++++++++++++++ .../component/RedisCountStoreBolt.java | 52 ++++++++++++++++ .../com/heibaiying/component/SplitBolt.java | 35 +++++++++++ .../component/WordCountStoreMapper.java | 30 +++++++++ .../src/main/resources/assembly.xml | 25 ++++++++ .../Storm单机版本环境搭建.md | 2 +- pictures/store-redis-manager.png | Bin 0 -> 19112 bytes 11 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 code/Storm/storm-redis-integration/pom.xml create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/CustomRedisCountApp.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/WordCountToRedisApp.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/CountBolt.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/DataSourceSpout.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/RedisCountStoreBolt.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/SplitBolt.java create mode 100644 code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/WordCountStoreMapper.java create mode 100644 code/Storm/storm-redis-integration/src/main/resources/assembly.xml create mode 100644 pictures/store-redis-manager.png diff --git a/code/Storm/storm-redis-integration/pom.xml b/code/Storm/storm-redis-integration/pom.xml new file mode 100644 index 0000000..0b641e6 --- /dev/null +++ b/code/Storm/storm-redis-integration/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + com.heibaiying + storm-redis-integration + 1.0 + + + UTF-8 + 1.2.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + maven-assembly-plugin + + + src/main/resources/assembly.xml + + + + com.heibaiying.wordcount.ClusterWordCountApp + + + + + + + + + + + org.apache.storm + storm-core + ${storm.version} + + + org.apache.storm + storm-redis + ${storm.version} + + + + + \ No newline at end of file diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/CustomRedisCountApp.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/CustomRedisCountApp.java new file mode 100644 index 0000000..c3986b5 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/CustomRedisCountApp.java @@ -0,0 +1,45 @@ +package com.heibaiying; + +import com.heibaiying.component.*; +import org.apache.storm.Config; +import org.apache.storm.LocalCluster; +import org.apache.storm.StormSubmitter; +import org.apache.storm.generated.AlreadyAliveException; +import org.apache.storm.generated.AuthorizationException; +import org.apache.storm.generated.InvalidTopologyException; +import org.apache.storm.redis.bolt.RedisStoreBolt; +import org.apache.storm.redis.common.config.JedisPoolConfig; +import org.apache.storm.redis.common.mapper.RedisStoreMapper; +import org.apache.storm.topology.TopologyBuilder; + +public class CustomRedisCountApp { + + private static final String REDIS_HOST = "192.168.200.226"; + private static final int REDIS_PORT = 6379; + + public static void main(String[] args) { + TopologyBuilder builder = new TopologyBuilder(); + builder.setSpout("dataSourceSpout", new DataSourceSpout()); + // split + builder.setBolt("splitBolt", new SplitBolt()).shuffleGrouping("dataSourceSpout"); + // save to redis and count + JedisPoolConfig poolConfig = new JedisPoolConfig.Builder() + .setHost(REDIS_HOST).setPort(REDIS_PORT).build(); + RedisStoreMapper storeMapper = new WordCountStoreMapper(); + RedisCountStoreBolt countStoreBolt = new RedisCountStoreBolt(poolConfig, storeMapper); + builder.setBolt("storeBolt", countStoreBolt).shuffleGrouping("splitBolt"); + + // 如果外部传参cluster则代表线上环境启动否则代表本地启动 + if (args.length > 0 && args[0].equals("cluster")) { + try { + StormSubmitter.submitTopology("ClusterCustomRedisCountApp", new Config(), builder.createTopology()); + } catch (AlreadyAliveException | InvalidTopologyException | AuthorizationException e) { + e.printStackTrace(); + } + } else { + LocalCluster cluster = new LocalCluster(); + cluster.submitTopology("LocalCustomRedisCountApp", + new Config(), builder.createTopology()); + } + } +} diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/WordCountToRedisApp.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/WordCountToRedisApp.java new file mode 100644 index 0000000..170ca40 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/WordCountToRedisApp.java @@ -0,0 +1,57 @@ +package com.heibaiying; + +import com.heibaiying.component.CountBolt; +import com.heibaiying.component.DataSourceSpout; +import com.heibaiying.component.SplitBolt; +import com.heibaiying.component.WordCountStoreMapper; +import org.apache.storm.Config; +import org.apache.storm.LocalCluster; +import org.apache.storm.StormSubmitter; +import org.apache.storm.generated.AlreadyAliveException; +import org.apache.storm.generated.AuthorizationException; +import org.apache.storm.generated.InvalidTopologyException; +import org.apache.storm.redis.bolt.RedisStoreBolt; +import org.apache.storm.redis.common.config.JedisPoolConfig; +import org.apache.storm.redis.common.mapper.RedisStoreMapper; +import org.apache.storm.topology.TopologyBuilder; + +/** + * 进行词频统计 并将统计结果存储到Redis中 + * + * 编译打包: mvn clean assembly:assembly -Dmaven.test.skip=true + * 提交Topology到集群: storm jar /usr/appjar/storm-redis-integration-1.0-jar-with-dependencies.jar com.heibaiying.WordCountToRedisApp cluster + * 停止Topology: storm kill ClusterWordCountApp -w 3 + */ +public class WordCountToRedisApp { + + private static final String REDIS_HOST = "192.168.200.226"; + private static final int REDIS_PORT = 6379; + + public static void main(String[] args) { + TopologyBuilder builder = new TopologyBuilder(); + builder.setSpout("dataSourceSpout", new DataSourceSpout()); + // split + builder.setBolt("splitBolt", new SplitBolt()).shuffleGrouping("dataSourceSpout"); + // count + builder.setBolt("countBolt", new CountBolt()).shuffleGrouping("splitBolt"); + // save to redis + JedisPoolConfig poolConfig = new JedisPoolConfig.Builder() + .setHost(REDIS_HOST).setPort(REDIS_PORT).build(); + RedisStoreMapper storeMapper = new WordCountStoreMapper(); + RedisStoreBolt storeBolt = new RedisStoreBolt(poolConfig, storeMapper); + builder.setBolt("storeBolt", storeBolt).shuffleGrouping("countBolt"); + + // 如果外部传参cluster则代表线上环境启动否则代表本地启动 + if (args.length > 0 && args[0].equals("cluster")) { + try { + StormSubmitter.submitTopology("ClusterWordCountToRedisApp", new Config(), builder.createTopology()); + } catch (AlreadyAliveException | InvalidTopologyException | AuthorizationException e) { + e.printStackTrace(); + } + } else { + LocalCluster cluster = new LocalCluster(); + cluster.submitTopology("LocalWordCountToRedisApp", + new Config(), builder.createTopology()); + } + } +} diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/CountBolt.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/CountBolt.java new file mode 100644 index 0000000..2884315 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/CountBolt.java @@ -0,0 +1,44 @@ +package com.heibaiying.component; + +import org.apache.storm.task.OutputCollector; +import org.apache.storm.task.TopologyContext; +import org.apache.storm.topology.OutputFieldsDeclarer; +import org.apache.storm.topology.base.BaseRichBolt; +import org.apache.storm.tuple.Fields; +import org.apache.storm.tuple.Tuple; +import org.apache.storm.tuple.Values; + +import java.util.HashMap; +import java.util.Map; + +public class CountBolt extends BaseRichBolt { + + private Map counts = new HashMap<>(); + + private OutputCollector collector; + + + @Override + public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { + this.collector=collector; + } + + @Override + public void execute(Tuple input) { + String word = input.getStringByField("word"); + Integer count = counts.get(word); + if (count == null) { + count = 0; + } + count++; + counts.put(word, count); + // 输出 + collector.emit(new Values(word, String.valueOf(count))); + + } + + @Override + public void declareOutputFields(OutputFieldsDeclarer declarer) { + declarer.declare(new Fields("word", "count")); + } +} diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/DataSourceSpout.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/DataSourceSpout.java new file mode 100644 index 0000000..c4a351f --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/DataSourceSpout.java @@ -0,0 +1,49 @@ +package com.heibaiying.component; + +import org.apache.storm.shade.org.apache.commons.lang.StringUtils; +import org.apache.storm.spout.SpoutOutputCollector; +import org.apache.storm.task.TopologyContext; +import org.apache.storm.topology.OutputFieldsDeclarer; +import org.apache.storm.topology.base.BaseRichSpout; +import org.apache.storm.tuple.Fields; +import org.apache.storm.tuple.Values; +import org.apache.storm.utils.Utils; + +import java.util.*; + +public class DataSourceSpout extends BaseRichSpout { + + private List list = Arrays.asList("Spark", "Hadoop", "HBase", "Storm", "Flink", "Hive"); + + private SpoutOutputCollector spoutOutputCollector; + + @Override + public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) { + this.spoutOutputCollector = spoutOutputCollector; + } + + @Override + public void nextTuple() { + // 模拟产生数据 + String lineData = productData(); + spoutOutputCollector.emit(new Values(lineData)); + Utils.sleep(1000); + } + + @Override + public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) { + outputFieldsDeclarer.declare(new Fields("line")); + } + + + /** + * 模拟数据 + */ + private String productData() { + Collections.shuffle(list); + Random random = new Random(); + int endIndex = random.nextInt(list.size()) % (list.size()) + 1; + return StringUtils.join(list.toArray(), "\t", 0, endIndex); + } + +} diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/RedisCountStoreBolt.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/RedisCountStoreBolt.java new file mode 100644 index 0000000..9a5cfd1 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/RedisCountStoreBolt.java @@ -0,0 +1,52 @@ +package com.heibaiying.component; + +import org.apache.storm.redis.bolt.AbstractRedisBolt; +import org.apache.storm.redis.common.config.JedisPoolConfig; +import org.apache.storm.redis.common.mapper.RedisDataTypeDescription; +import org.apache.storm.redis.common.mapper.RedisStoreMapper; +import org.apache.storm.topology.OutputFieldsDeclarer; +import org.apache.storm.tuple.Tuple; +import redis.clients.jedis.JedisCommands; + +public class RedisCountStoreBolt extends AbstractRedisBolt { + + private final RedisStoreMapper storeMapper; + private final RedisDataTypeDescription.RedisDataType dataType; + private final String additionalKey; + + public RedisCountStoreBolt(JedisPoolConfig config, RedisStoreMapper storeMapper) { + super(config); + this.storeMapper = storeMapper; + RedisDataTypeDescription dataTypeDescription = storeMapper.getDataTypeDescription(); + this.dataType = dataTypeDescription.getDataType(); + this.additionalKey = dataTypeDescription.getAdditionalKey(); + } + + @Override + protected void process(Tuple tuple) { + String key = storeMapper.getKeyFromTuple(tuple); + String value = storeMapper.getValueFromTuple(tuple); + + JedisCommands jedisCommand = null; + try { + jedisCommand = getInstance(); + if (dataType == RedisDataTypeDescription.RedisDataType.HASH) { + jedisCommand.hincrBy(additionalKey, key, Long.valueOf(value)); + } else { + throw new IllegalArgumentException("Cannot process such data type for Count: " + dataType); + } + + collector.ack(tuple); + } catch (Exception e) { + this.collector.reportError(e); + this.collector.fail(tuple); + } finally { + returnInstance(jedisCommand); + } + } + + @Override + public void declareOutputFields(OutputFieldsDeclarer declarer) { + + } +} \ No newline at end of file diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/SplitBolt.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/SplitBolt.java new file mode 100644 index 0000000..d92ca07 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/SplitBolt.java @@ -0,0 +1,35 @@ +package com.heibaiying.component; + +import org.apache.storm.task.OutputCollector; +import org.apache.storm.task.TopologyContext; +import org.apache.storm.topology.OutputFieldsDeclarer; +import org.apache.storm.topology.base.BaseRichBolt; +import org.apache.storm.tuple.Fields; +import org.apache.storm.tuple.Tuple; +import org.apache.storm.tuple.Values; + +import java.util.Map; + +public class SplitBolt extends BaseRichBolt { + + private OutputCollector collector; + + @Override + public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) { + this.collector = collector; + } + + @Override + public void execute(Tuple input) { + String line = input.getStringByField("line"); + String[] words = line.split("\t"); + for (String word : words) { + collector.emit(new Values(word, String.valueOf(1))); + } + } + + @Override + public void declareOutputFields(OutputFieldsDeclarer declarer) { + declarer.declare(new Fields("word", "count")); + } +} diff --git a/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/WordCountStoreMapper.java b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/WordCountStoreMapper.java new file mode 100644 index 0000000..21e4ab3 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/java/com/heibaiying/component/WordCountStoreMapper.java @@ -0,0 +1,30 @@ +package com.heibaiying.component; + +import org.apache.storm.redis.common.mapper.RedisDataTypeDescription; +import org.apache.storm.redis.common.mapper.RedisStoreMapper; +import org.apache.storm.tuple.ITuple; + +public class WordCountStoreMapper implements RedisStoreMapper { + private RedisDataTypeDescription description; + private final String hashKey = "wordCount"; + + public WordCountStoreMapper() { + description = new RedisDataTypeDescription( + RedisDataTypeDescription.RedisDataType.HASH, hashKey); + } + + @Override + public RedisDataTypeDescription getDataTypeDescription() { + return description; + } + + @Override + public String getKeyFromTuple(ITuple tuple) { + return tuple.getStringByField("word"); + } + + @Override + public String getValueFromTuple(ITuple tuple) { + return tuple.getStringByField("count"); + } +} diff --git a/code/Storm/storm-redis-integration/src/main/resources/assembly.xml b/code/Storm/storm-redis-integration/src/main/resources/assembly.xml new file mode 100644 index 0000000..3c38fe4 --- /dev/null +++ b/code/Storm/storm-redis-integration/src/main/resources/assembly.xml @@ -0,0 +1,25 @@ + + + jar-with-dependencies + + + + jar + + + false + + + / + true + true + runtime + + + org.apache.storm:storm-core + + + + \ No newline at end of file diff --git a/notes/installation/Storm单机版本环境搭建.md b/notes/installation/Storm单机版本环境搭建.md index 33fd993..579b3e2 100644 --- a/notes/installation/Storm单机版本环境搭建.md +++ b/notes/installation/Storm单机版本环境搭建.md @@ -58,7 +58,7 @@ export PATH=$STORM_HOME/bin:$PATH ### 4.启动相关进程 -因为要启动多个进程,所以统一采用后台进程的方式启动,采用后台启动时需要进入到`$STORM_HOME/bin`目录下,命令如下: +因为要启动多个进程,所以统一采用后台进程的方式启动,采用后台启动时需要进入到`${STORM_HOME}/bin`目录下,命令如下: ```shell # 启动zookeeper diff --git a/pictures/store-redis-manager.png b/pictures/store-redis-manager.png new file mode 100644 index 0000000000000000000000000000000000000000..66f8a2e8d8752713fba1612c4bac81382040993d GIT binary patch literal 19112 zcmaI82UrtJ_%DoN1%YEhn!xb@(gdVSR}qkow9um>y-DxE1}LCNml}Er5IUhqq97n$ zT0(#%(o3WhS|EHIJm>!J{qFNz9`m^DZf0lRnVtEScX)50r@=tSPDevS!=U--p&<uf9hpNW907i z;;FZfoi$58j)vxM8qJ6IjRP`%<3fEb7oINcbGx>T<*s}e(=_UY&7S_m9AP(6)ucgR zOH8P2V>M7z_2SPcpD=3Dp|730b5AnqTBqx<&J^#JiEFH)6F23j#1*_1g9H2?^*5bS zoUDX9Xc_CyIrUV>^afYO9s0#8Ro`%JhYmVh(KefFjPzCfdBvcJMH;4o{y<`z7O zhFx7Ebwp`*(rC?@dhOn;bbRP8E(mkVQ6R*gdd5{vc2I=7m;uU0{mpVvmjtIC(9oDE zoK`+Ln4meuO+9$&_5=gl4dE9I-IZJFQ(M~H&EGv1Z-J~?4~eMohE|#%{NOK`2=mE= zQG0@hrrX^5>v8`v-%-1mmMq*<)PLB0$$|35XB`Y*mO8m3TfUTjFN{2~|6(mbr-}To zcHzxZCkUTtqavKDU(j>d=W%uY6!p%rCv~ykP!vd0Fa)iC$g%VSx}B#2wPD;Xz}U4U zB)VIfN5arhHqV~8bs1$TlP*%zFc+I%m!ipH ztT>%A;ntHx>U4qB6I)~U=4`5vA8u_OjBi#{^sSiY>s5G)z&}#r;FOeO%M@;=OM}%g7AhV!cVQk$w~odgP0n+?;8mFm3fbfXGaO!H2=r6XQo%@WeZITA(Ul zn@U43Q8@K9Wi(5K{44Et%-^fNYHVzk&U$$+^6^}a&dO6#QbS5WAmO5 zPlc{Tbu-Ic`(gZj>Z0RqMNtQV+?lK(jE8UUquAFMq0dS#Gh0b|jx6kd)~1(ELaew9 z;VTYb;g6?177tnpOPe$ISB{*`v`YS-Ts!LK{!w4y^v0Qi8W>{f&h^7|k0f^mgV6oL zqak>xG}N9nlrt`CAn2MF)!>%wIoBRLOq@>6p>Yp;sNQAEc2@P=B&A`FHRAeJQD1K1 zviCD)2&?z)y&FOpzEwn*>CZ_p4Bpct!g1YTq?L2GDDw7fmaRJ>DGO1uwDHzzYQ~~O z_2Ha+K2*cArKSNJj3>MZVYlxeJfYWo8M78>ZIBk%2A80S0Sf zQ{HcbsWoOO-FYddDZ-!R-d@q#c}#-o#a+i38*lm=N5!|>4dpbMd+v+OtZn7|%$+m9 zc6y?W@Zs+564t~{`Fw*rRlk3~fAVOVwdWG;ospJbNs=5AeS9LtYLQwtPG&#j>mJxG zPcN-&(rfQGr4O^~H_U3qxX7anwdwaUUt=2PE@{!GHWkI35?r*pUdZymJv{CF5RNE0 z!(s}-1Mx7_UgA$Oa^r+uChc5n>G;;`^81qmZ^37Muka7sJM0}#$9ANh)v*0tguuB0XJ=R@@Zl`@>w*Oe3>A+2ist6Zt^5dm}NJZ znba=yF%xXsVKwyn3SC6uNE}C)hvU8ba^B^5#Fr`N^G| zVAqHH&Vf=_wgfNVxLpi-fMcf*n0;{<7KWdXzn-WBk{iY32&q+URJntu)MD!%X*PN0 zt&3B8M=E>tY=|b%fc*IZZIz*$nn7g4ptwXEjF({(`3H=Ndv{{i`oe-mvWxJHVLQ8vx482p#HE0e36)}{hq~YQF?;P!0#12l8u=foIp<%4da%*ZKr$cDmkLH z%C-+ngYZlAjLgmB6*-IrHZ!Dp#Yu;b$u*bm@IxYfn8uIuKs|mMpjCc>!@xlIn;DLaeg<(|9OSl0zF|9;Gy#hJ$i%I9~y*qNHT=q-t7QQ0YO<5yF?JjZnT zv4BPH_@Kd5;Dg74{#@GDw>y_E-nw0LSYgakU`edYHYf~+Kg|=Hup9h;vJbK3839CoUcypTRjfMLE6hvZvrSJ%SJ{#C`iMRG0d9`8lCOHq}^J5>(f4a)4SY#f5FQ?dk|Zr6t-D}h~g(v}6oxTxQV?vU*C z4C)-cBAKjz!z@P>i#~YR%08R4R0yrKYIx**X8!rx0)zPs8HY!79BK4rlc70H3oC;^ zGIGp%UOzw+?mKEln1^yI@Noo(qX8#Oq(vQ3 zwS1^3OS|IaYc%Qhn5G+ZZ@4il(EVm#xoaoiD8?P=S5t=t4UG&=x7n{;pGUdUXg!s> zN>?(kjMq5mw-9Nh5|x5?7FQ4ixW6>@RsiTsxHp&MeQDUcr`jUzYOu@JCu_)$!2P)t zwl_>8Q75z66X9ofPUZp{hUrXy{Ahu8N|F{%!0h;F4W;+>Uvo|+)Im7sw4TsQN-ILH#)=pDfoHto-=$-VarC%>M@bX(YaWnB8d>!S*5UrJT> z6N*T$nD8Q+O-FD1i3cA>s=Y99!r#A6nqO&R-Q;6VEq#|$kr$YyX4Jd9WZ__k>!H*Z z(bU6?mpiIAcIJM*rq07OU$2AUbNHz1C+{vz{V9t-c*yZ@?dUMe^*w_v{YU?tlq?`2 zF8+8;$TiT~+S(4WaZnzEsR;5w?$_f(wsc#L(3Xw9*n42tiF1eiSpm6t6QJxdDShSr z=Pji#-R6J9@sQxH$-XM06&2ebMSlaW9#@2qq ziWo!3Z-mpm?=1T_+}XTO$t_#|!Jpm19tA$6qeM7ZyGt=xa}DXK8}Bob**tsKtJEED zH@w;+vqFAZ4x2H5^E;fLC0WVF392=>EJ6+`BMCE4_Kd1DBS*x`ChB2>$1B|QT)PxR zGq0v>(!{rz24H|Z_ttnWN)SNw-AeB(e`juwx-!9Q87Cc1wnsnLK&ak~CI1Ud(DZeBUL=ZllQ^i_q8& z@qw=HFDm1zJz{Olzrg9YFwe7EEQZCSY2Bq?9kqtj^Yz%Zt(h_+u}vPo!{2YQugDv0 zQxLbUQALE(2Bjl8IhFAwa-(U>@e2GkpG&6Yx~^_4zk~|^wHqYbf4x@+&)n`-W+)APb~($n_)k(U@J#_A>I zEDg=?+o@~3B2U>m%5FO23eA5P#Vmbzy08FCCZL#d$P)X!O{(LXjr~Ls!ZOp6f?XAt~A>}-Ep4; zISLGw*jiNJVOkPbDp)w$U8v_CLH$G(H(0wgvC52ZSbUoSr|nhdlNk3l?w`Gy+&L)N zuA!)P%=XSjNJvvOyi?ul*g)aNDZ6965i;GPy(Etk-K~(Q0(Il{qM^r7(ZhK|97PHs z2|*G?01y#Wy#9%2m+$*cqIB56BdwA?n0|=C{cu@(v%I!AmBPo*j;V30e`UT_s= z1LOZ{dSSoxaf$zfQN}{mCf-nf#Bz4sSGozzEsjMu*%ia(j=IT%YU^zm2LOI+#am5% zZWYyx5~?k0Hh2(CT#tP=30=80SAh(hG-ZWbuT4^Zd&@Ed_~_ED z#0&D#S-_h;wsRwLq`K9=wt=u2$|LJj{h})@RN#>7xi^_vc56Z_^n8zYSkX4a9f!wi zS(p1hNVU57*bFGSFLe`04Ot3M!olRs`RzUL1!-r&nzHoc{l`l9x>j*@=vTVZ8f@il7e2D zLwiWex?5ou9l(Rsk1S;Ai@FL~%l+u!Y>2nT5`JHq;fx~Pr9EEF_Zv&SDtInV{UV53 zORBgvaq#(?GaUB0sEuFb_T2HO=WyfZD>G^Jhu_RCK80{D{cuyC^g35?il@L>s31}N z@3Wabt=kWNlpAclywvt7jxGMLU4=R8Mbq0gYi5zxgck8n9K~7dKTUO4dR*;^6{gAeYwpBJX*qwfrqQRUZ z(yx@mMl^XV4~nrBgIElJ8?xzHvM@$a$m7^h6{B zc1v4SP)8-_v(UCY=#`;iFjsud@xD*$0(6L0Kg^s-Ns5=JnXsk5G%N-&hjRBp8`GLb z^@Vl`#)D1H=Bh3Q$0m@ZKnU^fk>P-gcgIGB?wahXu$lYh zBb16M1t5Q&_R6 zKCO0a1@hDzcr+i|ZI#^w`iiysYrb#ElP`ppeVtD#3tY1CR=ZD6Gs@-8=TBnE+~0t?qak1(obL2eVq_kVthp)5!b2H&aKkoyo~elUaymb6Y{ zTE5zH6to?#G78N^+?W}JkRbmw58Myk9A?rIgYa|LGC>|dD_xHtlJmkRqGLVRuR4br z550jV6RKAepb!HwR&4)}3A+3h^Z9kJV*+D0=}z$o9axv1V(LB9;frhVw2t5YKnQ4j z(q$p{tGP9bO})uizWIBr7xT65j};(fG@>t+BbJ-NoFeWQASEH2f=uJs=}LMhv?$^n z2Vc&R_PSw&5S}32#wp=3Q*lLYDQk95{*au=?(;7kYOE{(ZrTLUoa1{*SPa%R@SKTH zcxeIS=nH1f9{|g#2jI?2x4tR1!AUDEL7u|ovlSUK$8-#Ih5s!1K)EZR42ya$wjV%) zX%SA>`?0)ovvORb%Yj%{!{jW+(kr_uZ0D-f6c3CG3$_H6U@ZBQ#kQIYs5}8-?XkTYDAQW|8K$uw)Ty1pQHH_V-LnMb1vMzaGIRmWdIJ_-JKLp;0 zG_JmwJ9)6uFZoZ~-K^lnv1%}f%FW{xt`Sw$yv?v&%#||kk(4Z`!P>WK1yetWu{Beu zIaA0|psvny#?8qY`8%~8%Ww^x-zVqhHV^3!#uy7Ll&AF|A+YfYPVCrEezu~G_0UJw zOHj!VH}%3S`K5e_;ZAa3fvdf6^^Adbko__Bo#IUGT2WjE-YezI)$mUoSHbXboSE?h z5!hWHWG}KK*Z0%?gV(C<@Ew<8)u~1RMxwFR@O`$?ZNsu3CH5(H7wlF;v@Oh*6vnRC za@nqz6DknZZ%zign6RuO<=0WrlX8)1g824pE|X@yaOiP=v`dNoc+iL&hX4ztJYms} zJ4G15{G9kSbGril0%ek=T?g4mtO=V{qq)|hP%Q-B@|J1U=8XZL@>s^MwO!#W?|Y>B zwy(tgSn2EiLI~BV`;y;izKx4p_TTjRQFJz30=KnQ8mbi&S^GD1v$Q6m&&)nldS){? z&!jhG?Qx`-lGM%S3bt4Q?}S%3G@jg31{vERz#G3^o~235Y`lJdQ5f?rM^yyfbx9jq zYJr{sI+L?CW&xR}8Sj)9MOFpCxomY*&)OvzpD8Q}IkL+_+)eMjePGwQr|^f!b`1 z5p@%asup5tKCZ`mNdBFUD3H(Cu=o9&nS%3(|?`QM*0 zgb$aK-aj1V76#;m_us2k*nvqnrV^McZhA-Lzwq@X#jr-z#q^|O5e{1H(fd)_PS5)R zI(t9ox68CoH(Of#Q&aHyfp^wGJ)7rbpS{cNO)XiL`Wo$pXNJN6|AkdBXT>jRRuB3+y8MHe!Cf^K}tVOr7Xj8V%6C z?T^S6;klfMp$5(jrCuI*3Gzm6Y@$MgR2v~tGs^ut^XC>gKBC$d#~t(t$_>lG9zLl+ zQVPy*7h#W7Jc^Hr;Gs7}LyR;K$=|q?)g@0t=u&V7!F%Am&wvuQfLV%2O+2aT1J0DG zr@ifblm`(p*RpP>wDVIn=ttAFNwwTsFOj|a6q_Kyy0Bx)hcYi~#f|S*gEqVPiB!J% zlA&{#s|@k}{Y6eWuYCOISapAvQYjn`ub#kc9`GH{$KwxIN8=}y_u_EX$Ft?aTzSR< zVvL9FQ-pC&lySD0iC-O>OsY{XN~$lvwT&U4?%YKkHys>=8J&knDV>^YW+99k@qp;M z&*+DkrHF!I?(s?|>o6Cu#bL3y?zE(+l`w@?*dirHj=yyjOf zD+N_J?yf2|1(BlieSY!(VWL0pArHtNc914s&4a#y0x`PF|5D4pFmS6;56CJlAL74L ze}gG1^!%%bLntkMWJ5VE<*L3SKsKp$ps9pcze0}HGwk*9QrUkQ9$Vu;v<{ExAR=VG zKmt!FXz-enbRQQpw9JjOUf&}ejT7VRJz4%G%XzNZ15H75QSjkEO!S^@;C3wIHAOCR z+0FO=a%T39QDKnRD&aKT?UV*<$K{V#AY19nYioqx%hYF%O@F*0X9xt`*Armq@x&S+;)UlA zDHKTPoG>_!m-@wF1nS65S5I#_8hkiy4+6LwFft>&_hOHCUw1A*=2Wy{!@R-3H5O7* zMTlAj@&JY;m3v%XJuz5{4P}0^luq0}pxz)YE`Gn^gvMu|+f@sz`n4g9REaZQn3(nT z^&Qn0{x1}fqt*F;TjocS8pnV4Yjs7+xpEe?yd%k#*7#P^XiU;J#+h12Ao#i3YuY#2ln^^CCs=$fx zK*a(=u*bfd3Q{K{?_OR*$V@e5X8*X>^+-Q#girGz8g%t6@wjcjNP2xkEO7 z0Ba>1wAB8+FRxf<>ZA+QS#RxiYez=4cY10ZS0GE1UB01K!KL;lmf4l}KN3}6oq}G= zG<^C!79jNd=T1Khs?8KQLOwck9uxq+Vc7ZA>_9SJ;+o6*ZiR+=dW$(iDbSX$-PNyx z>ktrOkp}pZ%d=<{tEo^*^K`vMuhSh$q9jtDEiWvt5Oj zR92z=%TtEsZJ>9M)kOl}j$Qn)0CHBGGOVdVvzKSFd5Y2RE-mnccUI^0-qe3`59xZO z#JMR56Lb-c))y3l%IuGysgHNYvoOXg?lX05(u1Wfr&<8F^rhPr@Vd-GD8T3ndJZ#+ z)tT$WIdBiOBtu=-vXuN&l(OpVAdoPV>os`(^-aa^x)I+z)V^Td7Pc?;93f!HLRDV$8!y1J4i1cr@< z@p#lAjHG3`hd|In&QMYpVKA0!uNWURLq4GF+K8A@7W~23GR>VE^5_-A7eesM3-KLS zl^FtfOH`FT9syW9vM|@nmm?kBu9V~6{tQPK7<^4m2E@8KC*(XT25^Yv9yz#^WcEuQ zcuBGL(>DRA;Q|87O|_4~*9@98v~~ds8adgYZP6MrKQBR?hF~AKD7nn-QkODz!T@A8 zL4NB1k=&PmT<5`%d^-$t{wlZRf4Klz3M74%A=9nE3jizwX8c0vK?yXGms9!o$iIrR zz}9kU#VGzYDrV-Bg;pIad$bl{YKjlBl+)c(j*&FOi=m6{y(=;YuG z(=8idj=$H|JXdJBO@BVj9edD-xpEe_Sp%8+nl~OijAtk}D%jYzVjVL>5FqKwhf~4Z zsw&%4ujf>`n}Rt{BNgSj`~;Wldhu=@bGz4l^>_Y%XxX4h{P)MNpIhm=Q`1wwjBJV9 zb<8AJ4J~n9e7|v@;Uj-CljT>&q*Pb2Eu_F_pF#QOYVp1Af;v);ZC#bnIoIbRD<4VB zTn?uTB7sio`ql5n-p=`vwL@QABe}oYZgn!WNO|G+FfD@HVpOioc1yS~8{GFi@a^G& zS>#JGxzpYft%d>$*T>l6f$pL^U?{RAUVWeY_uA4YvAD|GWe=Ii)869yx%kPl;~r?N zky1`UYs+ccO}^ZyTOsV(VN%tKoQ=C`-^i1ff0{L@&0u$p2XfDKw0b2eeVSzxzvj-C zA}NVPo*-JfZsR|7+@aP{3Ygk|Y{ls>Ox{-&QJ;dSHD4tZn z`7M6ZaI#d>kg7Fn7CmGO|53WnXZ7?$+}g=$OB#_qX>n%HiRU$P%!&F{jWh|wlMD4{ zEY@A70kNW>1DXkpbKrrvzfQ28tCPb(Ryh^Q+&h6im3AfyZ|>4`{0q87T!}9STDq$) z2Y{&sjYZY_{%e*L{pV&d{3(cL?A(RD_-RP`sw68k zc{DzbG}GO)&QJ=jFWgL`h5Ta|O^p5>*6fmpoB8Zz*1Uj4L5`1DGCfMV#RM}msG(6oP#eN7ke zZzZ;P=v}bnYD(Yy^|np_zo>R1^c?#ORw|Z$+0n@xY!Vd|oc~e0z)-NjFrta&wb#K6 zUr!p4_<;{UyzBb=!p67kYs&EMl}%4wH9qk9@?Gk4(U|^=RFy3iz5Cnn7Bpp^!{BdO z@if)WChMWrp=#3*$?02@YY*)o<`iq=I)#phW*`;0NY z!;7cZJ!mf-V~>S1AtowacxS$ma$vefV!+8IR#nha{_wc zC20e1DQF$4Qb5EQN(|TxHG5bk@Z$UyMCCqC!qWY*wZRp-WaTHN%K_&ZZ~Qn40bC`! zSkQQpVPjIi3$9}Cvy0r09wP5FMcvz%JE3#tlO&LrqW`e-g15qhIW$?P0i@HB5xGk> z;!H*MTcr!!^VfELdyq;^c7&|SdeHTXqOeNMa<^cu6&u5nCt%SRmOYPp-UP}tfSfbM z>OTC9f?U|+_Rml1!mWaJ$F|Vb!wjUN6aCx z)F*W}FWl1-`%ZwH&EFs3B>Evo{rbdMHp_{NxhQdJOvHmPvYd5Rr9Ux?r4ke8P~k*a z5(8TJ2$eCtZUdJ_88?V2>uvZwI9kRTuK{od_>lp5-Vxh9COr%w1l0bSP)y55To24+ zz7ed>oYhx|T=TH_ zDjPdos-Uk`P?(X>dtdXILjdEl02(;AXVJASosfws{N>x-2TF7XL&w)pE8 z;`$#rF7>h*5`a*icOOb8v{-nN&#P2h`X8;YGRGP%?f9X;f_3-6CFzj5Dd_4U@y)+% zq?M9@&}#D4?G#{c(#COB7&ba%FhP(qhJ@d4m8q0lbqs$*03e7mAh}=s4pNhZLg1%& zsF0GXeyOy}ZXmBbO#Q>2PGu6WwB%%=3~|A>VVf)@H(XJFOLT|YxUsv;ry+)INF#aw zz5IDGo00Zt7HJi1L3_U`X~5OyEJn0ss@^oyAZ31GL9$2FSLq)t(OO!ncD7PK^QyJH z9F!7bm7yZ2>(dSTYdRrq$-{^!ShDYkJITX)a=!Sl^_AuH%uxeyu;_(}39?T$h&{CM z)fLF5xo(CWZ1|fpc4en`2#(y@3Bp`r5Girs?=Rkc4jtd({_AY>$K~GdHT$NAsg-&q z+FLdEIpIdSz*waDeQ6>rUa8rrPd?9EGs&$Qy5un=8QV)-msHMVRpQZN;-g1T}x$ah8xzr1xL4wHo0Ws4el{ju}xXiB|0q`-j)zV065(czCO3IgkE6 zZ4Hn{qsyu}cNL;uBYBK;;vRBs<~{cocx>7DiN0_)`{oGiy2EyF@rVNUQ8{6SE=w7P z?w48G);uesbfrvPAyi(8ZM6MnaM0>0aFGSM{3fnMLr-0L#2wT$;ae)-7JKdOUb~T- z#c%nN{lMnuV952>qn#lx#d4$aa_8av+)zKh$WVFd!Llx_`T=#ky1D_@IthOI=N;!X zwXi~zQC>@e(BPex0xa1c=&iE$_j+|Q(n(oQDt7Y^szs`H{740z{|Lyke#66eLcp$d zDnr5|>}NaW@SYh=?-+XHp|G>a@I*j=w^ zQJ*%U#(YX8m1(yo^n=RQmlkW)nuO)iVxfNK&r-FY$$@5W<(Y;cI^V7kCP*$6tHE3{jJd&)PgJ7OfT%ER?VkPa!ny$ zOD;sk`)_9S7n|z^?=09TJ#&KSvq!_wgYd{vJicfVDAD8d61x6Peop&uavQ8+;beMn zji)=M5_-I+mx&JfDax0iWsw{amod1$t^@DydTuCrR3rrh3gdLU6QtE9*>$K~q+Wp6 z7@8?riS(__Zl+X*Ty=1UN41E-hUIfi4_?SB1A~`+wB+^vjrgTNp^tt`Q!63Tmw@Vi zO*U5k#Sb0*&Ze2iKQcaUQ7dH%+VZ|y1RTQ(3vboc*DohFNy&llvW*W8^A|XTI6FHV z8o3nRO5@+!Vi+S|Q^J+KM{nrKMT;YE3*BI9c%{Y=f5yQVhwvYhq^mfatUc4qF8+8yED+4ioZ?A{V54E}cx+ zh2*0!a_2$0*cmPN^v|EiX2)qPwd)X3Awc3woy!{{khMTV;{pK6xFFD};%Feh2W^a8 zo|vV+xj^1)^q<-7tIR!?P|X!p7W!M0C(~^9;D321G6wZ$!wAUGbn_E|=UzuJ20y}) z0v;xDfP5#intc~UxRZ42rMY*%zM}0x11o-xD|Xtg0Bur3u-L7zSNW-SlK)X3<6m)@ zN0}Zi+TK(M16NY&asI@jHL}_Ys-+G#lSsE|xPJ#Me0mrC@C01G6#3OU5mvfj!#+65 zk&@yTyt_;c+EED0o(~?MZQ5M`x%P=MBYVOrT65JZEZl2AhJ;Doh~@48#cK6)!A_}h znCP9`8h?tCZw?@F_e2DjwsZF`XIU~XzG{XPx~6K~N2Vno{T>jm8v@ZSq9xjIqO4w4 z__zjLGLC$SV*I~yQWzFcsLez;zM+hXK;dyd4ydpRwABowOb<7%AXbsqAdfEtU2d2LU8WrFlAzSDxZx2qMaU0yo>`d*36srEULJc1WTLNy6#8t+IV`S z_^zO4N(Hj06hjab7!FxGhCv(F65{hqWkrdHmdCd3GhBCHWIqu^^e+SPX|#pRV(Y-U9<@3S=B6=y2C(Wz%6*S|LCyAzn@5HwoFcvd$HR|YVqHEy8E$( z8@4=_)PzYf>U$V4w`u||NkRsEz9$_OdF`)N;ZiD%(U{y+x2EGJ^oK?>mDoPf0ratw z#2hniWBj+ny`u(#;MxPkvlH3OmeWwcEMTzh-?U$e6B&)Z;{ar&9-oWnD&aBW<|$kS zj8?n(tM@_yAZfVQ;00y$)}(jt^2dl(X7j;EfcoAW%0z@1BUbbx50BT#VR<-N!as-> zZ3ND%XlJ#_q@PDe2 zb-nLVJ!wpEEg+eJ8BRcJ$`3ElDGjs&)FauyK6MVw z1$}i;x@Yy~+uM*TAdz!s@KJBk!xsh{u%74C%wVX_iLQ6$a#*xD51m>H0-Z8@H-8TE zoC<)Au+N9}3A@qp`5YyQ6rxIqDhQ6Mh)fSNw?3YgCGq%66S3jN_%GX`nnSeyM={Di z#3NxYMDoQ=trgIr_fAzE37KrUIT{p~({Nj4PuOxpCXkwMa7t6cE-m6*uq$2NcPWgc zGPo^~UC3-|e|>QEz$l7b7A|hZs60 zaPaUhV@bi{Yh9a0I2owJSc%mx<;!a0+)K)4U6C)TW6o}ZyMgH7vmJTNw9>eQz7otL z#1aFd!wB~^fp4INIg0{rtKf*THVmg!+RR4kGwlZeR~W51#OvL4rHGp5{5HztpHEo< zmCesmx2r6retpV!?#|}}1Wa?b5zsz5xG2r~;s^b7Ix_+wLuxfN)qPR92-L(+BHcCU z7aTfBQGn((c_bqeb@HH*OcVXYM>F85v zZxEa`8?{34NP>~lj&p_@zy_Z zWGdlH&O7;xCC@#3#asj9ROI23L}#0*TnogPHC24a-U?Dd+HnH5TfB?7w)CQ~b1L0a zt$vG0c-OnVMgV9Yho``uUq(MC@_tlpPcj2#WIcI+9J_(|0Zd8vG|7IU27UfvUZdm+ z(7Fg$Fu12tNVgi)CwFnJ)Cdxpc z_Jv)k1|*vYeLbow)O#}jUn-O^;noQbpm7cTL*8iWUyVDQ@V1w_K7is6zzoL=XAVVr zCF7sfQ{nP&$I*`}=Ky>G90Nc${Qu;0G-anm{@8A=wEq=&>fb!t37VP{S~nJ-6)^oC zD0u8jR>)=-tb6p@y2C;Gh}?K-SG1}#*raZmuVe}W)r-mMQdEZJweT}@I;XV2Ne|l6 zmOw@efS{z|8w4>8O_c?CHGq*<^W+n-Xa%-W1BEq300lW4bGW`-fhE&ho18zKeUYvw z!ZkW*Vp5V7&+hIr`hI>m4H`R-R!TQko*dXN?YrPyANw<0sE)}AqTCP?Dp7{k>q-q3 z?%OUUeb3b!0FRVeYxQ61!C+yOu4s1WveM@#4R2UJ4e>HVUhR{Y3o|RS7;t-$gf{<| zc?~LKz4vjVF3AA?B^9%=XW(o??hBMWB@}AL{q6$ynHiG%L0)Q(iQ*0!J-L9LV<#AszJ9pM3M1rHBpZ9BZtq+DM~&!UO-(SzUlhL33l_^!W~4ENXHE9_~%O^h7OBt!S{mmEe4_K{aQmz7G8 zJ60%Hr6J)DqJDyo=DRO2k2CM4BrX=?_Tt;*rGt#Ew@eO2SM;PkPAua3g1WccB)a)h zEXt}yyPUtlwyyj9VJf6f&<e^X&z%+>=Sv}A)OX&j~mT}bCo`-t6QNeZ+ZAgPFy53WLeG|lvke$n@@eb6f-jJ^9)W%#DO9MVP0#9SV3;8Lz2)V&Z;QX#lX;f;dEh`QVZleePrmU3RNfhc zB;nz08Uv2g*!+XCEd@n|97&Dl#X9POu2ssg)J}|2ttNSHY;>;}t==6SDMts<3YXkD zM}Swe;oUtlUc>_|uV$!?X~GUMk)(4g=@N9PI7r&b>4lQyMp=9)b|Tr1f1Zfp*;3ut z+>tLw+@no&YDo#=*KQI1y{v#Oy_%`aprTl++?<%fmMkWTQf&)~pvEn`&c_Yx(e5ia z`Wn3Y;DKQ6ciTExgRaetf~==jdHK@BuYZ}IQ{xJl{4+nu_d$8GC63DX!z|=S(;7#u ziGoYpA#M71-;t!RDg({Z7dBgk>61Ur^QTM41#;K<=@kch*?hR$1nB%vge~0!xVX6o zL`s#QzQ=~07J`!?A*PXM?Gv-imAg(m)8|H?=Z#HBOHIIYqQb|erGh=p*@6k5?8)70 zSY@B8=Pr;E62R6>4u^m`_*PXsYp-liI%v6GgJ5#nc{b<&H_)o(JVVTZSJ}-_X_2in zL9U78e`eL+_s|A5eF0=G+vA!!SnA!1$-wUNw*Ei)4wbeh9Pz@sNW>6ta2?!oY5HEH z*BQtkZC|RkZn6g=ZN06{$zvJmOdGTlGWvGg8OmXORK;`aMB=OrHEycQ^o?)syYwZg zHPloZ(PN2{N0ql9%fmNNA!;5V66?gj^F6y>$vrEWG}5Xkumq~D1TRoddO*>dLZ#84 zDc#(es8do`73Nsq1vVa}l7QCGyks_+7;%x9{hTbFcAhtMA2gC4Cf?rvEkRqg#e0@v;3=?uB8l?$?zPY9!d5dE9lx?9`UA$P=s#4hZ>GWA`HLg^Vq;onQk1KL zCrWqqU5O9Tb!TDD&UN+Okfl!hkvrD4etUXH7#YIis!;e(PH_nBT{;AFF*P zbAR30y9fNwy1PE(*>fRUXU;Q=nQ;SK92=iFs0YnjFDA!n2_{KgBiejI@N-bALfI^I z8b-<*4&5zRC8u{PwwnjOgvmR$P-UD-q|mt#Ab~z24%psmb1Bb~P97k>!YlRCYAwn1 z%=-o3Z@dnq;^)ys(o#p!wIuzekn5Ny26VA@mY$rOXU@%P$GD`uMYW`ATNpg}_A^nw zqZ)cym6oo1NtAo@|FkifE!WH2);K@DRDY%{C|?i}y@&jKsm-kZdq|SsCUqm3_eB+) z$ON;pXlx==pdL|;wjvks$;Z|m-Zps)D#|=dwHmlNuu*AcC%XRqNG6b_RpQZ!y&`kZ zB;hyn3&37)XDIIO5SBLor6o7%t#~^{GXIBX?CCThpP^t?oajkS?xef(SFnR8u*Y$f zsM~(j@6#ZraPveODeH?8+3R7A)@n$rvn|AXQ!{RJHk^#+w;Qg&-8p-1Np;?=`)Pqv zl^e|n1Yf%Ykd5n{-35Dqj}h}{Uz4iIg*{KTe>_v|mA`)WL`~w0fsKcL1_oU^^|H#v z-!>i&mMw8{GBsZ#S=jf>>ZWeo1yt)`tR`#lwJyqLUjx-a1hU+3-jD#ii#Zds4o`=J zmZ#>__wI=jP_`bY#if$YRHzz(&B8#t_vfS@F?JPjUoV?T#bsKF4P5@5a5?z_)^ks< zDCmJUsf1r9#o?iPnPqfNufz9~+&z^JJdoV+z)(t{XxO}V+p%-<6IGh}T3Fe#J)~W7 zMBZg7JH%C}ZCipbjFgsx4N(|eZJz^El{-nK)-SX2~#5u7@ z`oYHePbMH>-#X)ed({8eyZy)0qpvfTQoyi`E8+ zI7pvxc(6@RpX!O?^wYpqX5w7^5a3PXydv_iW6othQ+TH@xV((6iu$ngB{}`W$;|Ua zy9VoeR=dO(?dEcY+xQVqV*X=k;EKisHb6v{^Q0wTlRIF;Ls)${QL(kz~Ylh2i{{XKjcE)q>ss&!+iS)@+caeUs$+3q*AlNY^mQh z1*p;`+klEZ9+41km!3wKQZGZY?4}7!QsM4OeM&-@6O6v30KI~4YpO-(@k&l7OA0VN z@4%dFEAEZS@&6$yQDof9-`FYvxRCP~HZ0o#DVFL<`0Cw2cP*+}fB9?^F)mx=R`AoVdUV4?0Azr(exPeI&OA9Y_W$0ZC}$x^!JANxi~zNtuP+w>KMxhNC* zRDvV~nw6TdMg8q?9mEQtw2Q!o5wu`TM19(ThM{De+wu)1z*p}=9c03? zl4Onp$Eq6coAX}CEWf*}$-={$TMG`O8VFWk&4rn_eUYAIA#lb1L~;E|6Cnv_rQcN% zMacp=KMji1eyVQe4c73Lmw(O%b_E5m*M5|F#=4R@a(H-HZC8zWh<&ZOBkHUiWVoPL zcfJ2RG~;oYr6rsLl1|ck)uKN*+?VFq=huhW!3~^gGbM&c=zUm@VNJ$4!pI?GWc#hF zGV0uelE_O>v3HQ{1ZbB#y)_7%u=lRC^6>nrjh+cCGI(w7q=u8-bc&|@s> z@|Mp7916`vP1~x6-?lFu*3@jtmtUnD5V%U?RPGVtvKPWT@ZO2)3BnTGaw-ZGD~*8h z7s?;(JO5U{4J(LGkYwM<{F#c^@H6hQm5|GW5H4oQjTc0&#Q%=;HIA03#)`__COi!P zksKnUbTi#L{)CR@WhSR?C1~`F%X`b`3g9X7Wg=sINdBD+MMH@;&Oc;+vVE zDYN>hec}B*8BO>43TR(EMz(pvcqlj$$vrHV@Z2|{*NZIDYeV4enm&zG1$v5TQ-&ex z&ur{~PV`iH@P^*rQfJuUHe-6jp6{}Jk7QW-vr~|L4usog=wHi7m8M?`&E2aMi zB5?*`CECn&I^+LaFQ{18n}Hs1<3z!33(inFK(C7Xl71O@A!DxZ-Rfki(#E z&(_lhw|dj81+PxF7x&NnECg~ZuSM!IYxzsd z&s+)L8?xY37vnE~kda?JZl0-}dO@$N-utb7JIJ>di)#X=pY6$)ziqeu)TO_xPQUQC z6jb=t?hAIo#dm5IzYp!qS}=c?cKy}s)8@|6sOp={_*WU^0jVkTSL#>Sgil@i?K#hz zyBYQ(AI)yRRtGz4!=l^IR8Rg3SXa!wdl%o_mIMiq&mGu*)t%ja_Ggiwp| zDZSw@_$PyWka1w2?90<~r`t;C7v8-y>X8Ix*7*$XW&t2Ta!;IK7G8ZE+yjTMT{yQa||l`PKLT{QLLs zNzkI6FXv0F-d1s}o$aIMIW0AoKiNQL{kOht>h_wLP0H2?+@PhgeeX(Qtc zJZ@{VKP;|^1bQaziM8T=e&;Q{fBwiHj6bvS)wPR_`oM+e4O)v_|9#6pxGVmjgk{)U zE3FSlf&Gkvo{owBrhVbR`?&si#QOomwNj09p{=|AMe(0N^F<%Y-3rZ~Y&#L?jyKBh z7S?XfpZwe#xXNV8MeYmxqKrW)#9=>5z-(QAaD9^1T(h6RqVxc(2PnpP+LB9edNKdM z``bQR1~_YTpt$?!BCzn$?ypsUGi~I`ZTWyEEm(Fo?XeUnlsmA5GD_Tj*z{uh?6b?> pf^)y9=-qew3_f(v1050Z<@)~IfRF9py6nJ1b)K$%F6*2UngIKBsUZLW literal 0 HcmV?d00001