From fa7ad6414083b7a5bfcdd62ce1921bab11f139cc Mon Sep 17 00:00:00 2001 From: yanweiwen <525390802@qq.com> Date: Mon, 5 Sep 2022 14:46:40 +0800 Subject: [PATCH 01/53] =?UTF-8?q?Topic=E6=B6=88=E6=81=AF=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81Timestamp=E6=8E=92=E5=BA=8F=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9F=A5=E8=AF=A2=E6=9C=80=E6=96=B0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=88=96=E6=9C=80=E6=97=A9=E6=B6=88=E6=81=AF=20#534?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/topic/impl/TopicStateManagerImpl.java | 16 +++++++++++++- .../common/bean/dto/topic/TopicRecordDTO.java | 7 ++++++ .../km/common/constant/Constant.java | 13 +++++++++++ .../src/pages/TopicDetail/Messages.tsx | 22 ++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index a0418bb21..59e91b1c7 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -36,6 +36,7 @@ import com.xiaojukeji.know.streaming.km.core.service.topic.TopicMetricService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems; +import org.apache.commons.lang3.ObjectUtils; import org.apache.kafka.clients.admin.OffsetSpec; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; @@ -161,7 +162,11 @@ public Result> getTopicMessages(Long clusterPhyId, String to maxMessage = Math.min(maxMessage, dto.getMaxRecords()); kafkaConsumer.assign(partitionList); for (TopicPartition partition : partitionList) { - kafkaConsumer.seek(partition, Math.max(beginOffsetsMapResult.getData().get(partition), endOffsetsMapResult.getData().get(partition) - dto.getMaxRecords())); + if (Constant.EARLIEST.equals(dto.getFilterOffsetReset())) { + kafkaConsumer.seek(partition, beginOffsetsMapResult.getData().get(partition)); + } else { + kafkaConsumer.seek(partition, Math.max(beginOffsetsMapResult.getData().get(partition), endOffsetsMapResult.getData().get(partition) - dto.getMaxRecords())); + } } // 这里需要减去 KafkaConstant.POLL_ONCE_TIMEOUT_UNIT_MS 是因为poll一次需要耗时,如果这里不减去,则可能会导致poll之后,超过要求的时间 @@ -185,6 +190,15 @@ public Result> getTopicMessages(Long clusterPhyId, String to } } + // 排序 + if (ObjectUtils.isNotEmpty(voList)) { + if (Constant.ASC.equals(dto.getSortType())) { + voList.sort((o1, o2) -> (int) (o1.getTimestampUnitMs() - o2.getTimestampUnitMs())); + } else if (Constant.DESC.equals(dto.getSortType())) { + voList.sort((o1, o2) -> (int) (o2.getTimestampUnitMs() - o1.getTimestampUnitMs())); + } + } + return Result.buildSuc(voList.subList(0, Math.min(dto.getMaxRecords(), voList.size()))); } catch (Exception e) { log.error("method=getTopicMessages||clusterPhyId={}||topicName={}||param={}||errMsg=exception", clusterPhyId, topicName, dto, e); diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java index b16f2e526..972e24928 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java @@ -34,4 +34,11 @@ public class TopicRecordDTO extends BaseDTO { @ApiModelProperty(value = "预览超时时间", example = "10000") private Long pullTimeoutUnitMs = 8000L; + + @ApiModelProperty(value = "排序", example = "desc") + private String sortType; + + @ApiModelProperty(value = "offset", example = "latest") + private String filterOffsetReset; + } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index fae5db213..2ef958b0f 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -64,4 +64,17 @@ private Constant() {} public static final Float COLLECT_METRICS_ERROR_COST_TIME = -1.0F; public static final Integer DEFAULT_RETRY_TIME = 3; + + /** + * 排序 + */ + public static final String ASC = "asc"; + public static final String DESC = "desc"; + + /** + * 消费策略 + */ + public static final String LATEST = "latest"; + public static final String EARLIEST = "earliest"; + } diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index 4771e0c7c..4e7fa8ff6 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -10,6 +10,7 @@ const defaultParams: any = { maxRecords: 100, pullTimeoutUnitMs: 5000, // filterPartitionId: 1, + filterOffsetReset: 'latest' }; const defaultpaPagination = { current: 1, @@ -29,6 +30,12 @@ const TopicMessages = (props: any) => { const [pagination, setPagination] = useState(defaultpaPagination); const [form] = Form.useForm(); + // 获取消息开始位置 + const offsetResetList = [ + { 'label': 'latest', value: 'latest' }, + { 'label': 'earliest', value: 'earliest' } + ]; + // 默认排序 const defaultSorter = { sortField: 'timestampUnitMs', @@ -88,7 +95,10 @@ const TopicMessages = (props: any) => { }; const onTableChange = (pagination: any, filters: any, sorter: any) => { + defaultSorter.sortField = sorter.field || ''; + defaultSorter.sortType = sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : ''; setPagination(pagination); + genData(); // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; // const sortColumn = sorter.field && toLine(sorter.field); // genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, asc, sortColumn, queryTerm: searchResult, ...allParams }); @@ -119,6 +129,15 @@ const TopicMessages = (props: any) => {
+ + { showQueryForm={false} tableProps={{ showHeader: false, - rowKey: 'path', + rowKey: 'offset', loading: loading, columns: getTopicMessagesColmns(), dataSource: data, @@ -169,6 +188,7 @@ const TopicMessages = (props: any) => { bordered: false, onChange: onTableChange, scroll: { x: 'max-content' }, + sortDirections: ['descend', 'ascend', 'default'] }, }} /> From 8e50d145d57fb054b61af49d31c033119529e069 Mon Sep 17 00:00:00 2001 From: superspeedone <525390802@qq.com> Date: Wed, 7 Sep 2022 11:17:59 +0800 Subject: [PATCH 02/53] =?UTF-8?q?Topic=E6=B6=88=E6=81=AF=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81Timestamp=E6=8E=92=E5=BA=8F=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9F=A5=E8=AF=A2=E6=9C=80=E6=96=B0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=88=96=E6=9C=80=E6=97=A9=E6=B6=88=E6=81=AF=20#534?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/topic/TopicStateManager.java | 3 ++- .../km/biz/topic/impl/TopicStateManagerImpl.java | 16 +++++++--------- .../km/common/bean/dto/topic/TopicRecordDTO.java | 7 ++----- .../streaming/km/common/constant/Constant.java | 12 ------------ .../src/pages/TopicDetail/Messages.tsx | 6 +++--- .../rest/api/v3/topic/TopicStateController.java | 6 ++++-- 6 files changed, 18 insertions(+), 32 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java index 0e8436d95..e467253cc 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java @@ -1,5 +1,6 @@ package com.xiaojukeji.know.streaming.km.biz.topic; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.vo.topic.TopicBrokersPartitionsSummaryVO; @@ -15,7 +16,7 @@ public interface TopicStateManager { TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException; - Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException; + Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto, PaginationSortDTO sortDto) throws AdminOperateException; Result getTopicState(Long clusterPhyId, String topicName); diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 59e91b1c7..092fb5713 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -3,6 +3,7 @@ import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; @@ -22,17 +23,18 @@ import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; -import com.xiaojukeji.know.streaming.km.common.converter.PartitionConverter; import com.xiaojukeji.know.streaming.km.common.converter.TopicVOConverter; +import com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; +import com.xiaojukeji.know.streaming.km.common.utils.PaginationUtil; import com.xiaojukeji.know.streaming.km.common.utils.ValidateUtils; import com.xiaojukeji.know.streaming.km.core.service.broker.BrokerService; import com.xiaojukeji.know.streaming.km.core.service.cluster.ClusterPhyService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionMetricService; -import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService; import com.xiaojukeji.know.streaming.km.core.service.partition.PartitionService; +import com.xiaojukeji.know.streaming.km.core.service.topic.TopicConfigService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicMetricService; import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems; @@ -121,7 +123,7 @@ public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, S } @Override - public Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException { + public Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto, PaginationSortDTO sortDto) throws AdminOperateException { long startTime = System.currentTimeMillis(); // 获取集群 @@ -162,7 +164,7 @@ public Result> getTopicMessages(Long clusterPhyId, String to maxMessage = Math.min(maxMessage, dto.getMaxRecords()); kafkaConsumer.assign(partitionList); for (TopicPartition partition : partitionList) { - if (Constant.EARLIEST.equals(dto.getFilterOffsetReset())) { + if (GroupOffsetResetEnum.EARLIEST.getResetType() == dto.getFilterOffsetReset()) { kafkaConsumer.seek(partition, beginOffsetsMapResult.getData().get(partition)); } else { kafkaConsumer.seek(partition, Math.max(beginOffsetsMapResult.getData().get(partition), endOffsetsMapResult.getData().get(partition) - dto.getMaxRecords())); @@ -192,11 +194,7 @@ public Result> getTopicMessages(Long clusterPhyId, String to // 排序 if (ObjectUtils.isNotEmpty(voList)) { - if (Constant.ASC.equals(dto.getSortType())) { - voList.sort((o1, o2) -> (int) (o1.getTimestampUnitMs() - o2.getTimestampUnitMs())); - } else if (Constant.DESC.equals(dto.getSortType())) { - voList.sort((o1, o2) -> (int) (o2.getTimestampUnitMs() - o1.getTimestampUnitMs())); - } + PaginationUtil.pageBySort(voList, sortDto.getSortField(), sortDto.getSortField()); } return Result.buildSuc(voList.subList(0, Math.min(dto.getMaxRecords(), voList.size()))); diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java index 972e24928..0a83ef014 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java @@ -35,10 +35,7 @@ public class TopicRecordDTO extends BaseDTO { @ApiModelProperty(value = "预览超时时间", example = "10000") private Long pullTimeoutUnitMs = 8000L; - @ApiModelProperty(value = "排序", example = "desc") - private String sortType; - - @ApiModelProperty(value = "offset", example = "latest") - private String filterOffsetReset; + @ApiModelProperty(value = "offset", example = "") + private Integer filterOffsetReset = 0; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index 2ef958b0f..36575938b 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -65,16 +65,4 @@ private Constant() {} public static final Integer DEFAULT_RETRY_TIME = 3; - /** - * 排序 - */ - public static final String ASC = "asc"; - public static final String DESC = "desc"; - - /** - * 消费策略 - */ - public static final String LATEST = "latest"; - public static final String EARLIEST = "earliest"; - } diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index 4e7fa8ff6..220781f06 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -10,7 +10,7 @@ const defaultParams: any = { maxRecords: 100, pullTimeoutUnitMs: 5000, // filterPartitionId: 1, - filterOffsetReset: 'latest' + filterOffsetReset: 0 }; const defaultpaPagination = { current: 1, @@ -32,8 +32,8 @@ const TopicMessages = (props: any) => { // 获取消息开始位置 const offsetResetList = [ - { 'label': 'latest', value: 'latest' }, - { 'label': 'earliest', value: 'earliest' } + { 'label': 'latest', value: '0' }, + { 'label': 'earliest', value: '1' } ]; // 默认排序 diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java index 52a279e9d..808c7a327 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java @@ -3,6 +3,7 @@ import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationBaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.metrics.BaseMetrics; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.PaginationResult; @@ -91,8 +92,9 @@ public Result> getTopicPartitions(@PathVariable Long clus @ResponseBody public Result> getTopicMessages(@PathVariable Long clusterPhyId, @PathVariable String topicName, - @Validated @RequestBody TopicRecordDTO dto) throws Exception { - return topicStateManager.getTopicMessages(clusterPhyId, topicName, dto); + @Validated @RequestBody TopicRecordDTO dto, + @Validated PaginationSortDTO sortDto) throws Exception { + return topicStateManager.getTopicMessages(clusterPhyId, topicName, dto, sortDto); } @ApiOperation(value = "Topic-ACL信息", notes = "") From 0e49002f426d102eda69965c9676b1cf7f99b043 Mon Sep 17 00:00:00 2001 From: superspeedone <525390802@qq.com> Date: Fri, 9 Sep 2022 15:45:31 +0800 Subject: [PATCH 03/53] =?UTF-8?q?Topic=E6=B6=88=E6=81=AF=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81Timestamp=E6=8E=92=E5=BA=8F=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=94=AF=E6=8C=81=E6=8C=89=E6=8C=87=E5=AE=9A=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/topic/TopicStateManager.java | 2 +- .../biz/topic/impl/TopicStateManagerImpl.java | 29 ++++++++++++++----- .../common/bean/dto/topic/TopicRecordDTO.java | 9 +++++- .../src/pages/TopicDetail/Messages.tsx | 23 ++++++++++----- .../src/pages/TopicDetail/config.tsx | 3 +- .../api/v3/topic/TopicStateController.java | 5 ++-- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java index e467253cc..ec3a3207f 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/TopicStateManager.java @@ -16,7 +16,7 @@ public interface TopicStateManager { TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, String searchBrokerHost) throws NotExistException; - Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto, PaginationSortDTO sortDto) throws AdminOperateException; + Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException; Result getTopicState(Long clusterPhyId, String topicName); diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 092fb5713..0fb368e0e 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -3,7 +3,6 @@ import com.didiglobal.logi.log.ILog; import com.didiglobal.logi.log.LogFactory; import com.xiaojukeji.know.streaming.km.biz.topic.TopicStateManager; -import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.TopicRecordDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.broker.Broker; import com.xiaojukeji.know.streaming.km.common.bean.entity.cluster.ClusterPhy; @@ -40,10 +39,7 @@ import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems; import org.apache.commons.lang3.ObjectUtils; import org.apache.kafka.clients.admin.OffsetSpec; -import org.apache.kafka.clients.consumer.ConsumerConfig; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.apache.kafka.clients.consumer.ConsumerRecords; -import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.clients.consumer.*; import org.apache.kafka.common.TopicPartition; import org.apache.kafka.common.config.TopicConfig; import org.springframework.beans.factory.annotation.Autowired; @@ -123,7 +119,7 @@ public TopicBrokerAllVO getTopicBrokerAll(Long clusterPhyId, String topicName, S } @Override - public Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto, PaginationSortDTO sortDto) throws AdminOperateException { + public Result> getTopicMessages(Long clusterPhyId, String topicName, TopicRecordDTO dto) throws AdminOperateException { long startTime = System.currentTimeMillis(); // 获取集群 @@ -163,10 +159,29 @@ public Result> getTopicMessages(Long clusterPhyId, String to } maxMessage = Math.min(maxMessage, dto.getMaxRecords()); kafkaConsumer.assign(partitionList); + + Map partitionOffsetAndTimestampMap = new HashMap<>(); + // 获取指定时间每个分区的offset(按指定开始时间查询消息时) + if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { + Map timestampsToSearch = new HashMap<>(); + partitionList.forEach(topicPartition -> { + timestampsToSearch.put(topicPartition, dto.getStartTimestampUnitMs()); + }); + partitionOffsetAndTimestampMap = kafkaConsumer.offsetsForTimes(timestampsToSearch); + } + for (TopicPartition partition : partitionList) { if (GroupOffsetResetEnum.EARLIEST.getResetType() == dto.getFilterOffsetReset()) { + // 重置到最旧 kafkaConsumer.seek(partition, beginOffsetsMapResult.getData().get(partition)); + } else if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { + // 重置到指定时间 + kafkaConsumer.seek(partition, partitionOffsetAndTimestampMap.get(partition).offset()); + } else if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getFilterOffsetReset()) { + // 重置到指定位置 + } else { + // 默认,重置到最新 kafkaConsumer.seek(partition, Math.max(beginOffsetsMapResult.getData().get(partition), endOffsetsMapResult.getData().get(partition) - dto.getMaxRecords())); } } @@ -194,7 +209,7 @@ public Result> getTopicMessages(Long clusterPhyId, String to // 排序 if (ObjectUtils.isNotEmpty(voList)) { - PaginationUtil.pageBySort(voList, sortDto.getSortField(), sortDto.getSortField()); + PaginationUtil.pageBySort(voList, dto.getSortField(), dto.getSortType()); } return Result.buildSuc(voList.subList(0, Math.min(dto.getMaxRecords(), voList.size()))); diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java index 0a83ef014..74e5611b3 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO; +import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -15,7 +16,7 @@ @Data @JsonIgnoreProperties(ignoreUnknown = true) @ApiModel(description = "Topic记录") -public class TopicRecordDTO extends BaseDTO { +public class TopicRecordDTO extends PaginationSortDTO { @NotNull(message = "truncate不允许为空") @ApiModelProperty(value = "是否截断", example = "true") private Boolean truncate; @@ -38,4 +39,10 @@ public class TopicRecordDTO extends BaseDTO { @ApiModelProperty(value = "offset", example = "") private Integer filterOffsetReset = 0; + @ApiModelProperty(value = "开始日期时间戳", example = "") + private Long startTimestampUnitMs; + + @ApiModelProperty(value = "结束日期时间戳", example = "") + private Long utilTimestampUnitMs; + } diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index 220781f06..6862596e4 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -32,8 +32,8 @@ const TopicMessages = (props: any) => { // 获取消息开始位置 const offsetResetList = [ - { 'label': 'latest', value: '0' }, - { 'label': 'earliest', value: '1' } + { 'label': 'latest', value: 0 }, + { 'label': 'earliest', value: 1 } ]; // 默认排序 @@ -42,6 +42,8 @@ const TopicMessages = (props: any) => { sortType: 'desc', }; + const [sorter, setSorter] = useState(defaultSorter); + // 请求接口获取数据 const genData = async () => { if (urlParams?.clusterId === undefined || hashData?.topicName === undefined) return; @@ -56,7 +58,7 @@ const TopicMessages = (props: any) => { }); setPartitionIdList(newPartitionIdList || []); }); - request(Api.getTopicMessagesList(hashData?.topicName, urlParams?.clusterId), { data: { ...params, ...defaultSorter }, method: 'POST' }) + request(Api.getTopicMessagesList(hashData?.topicName, urlParams?.clusterId), { data: { ...params, ...sorter }, method: 'POST' }) .then((res: any) => { // setPagination({ // current: res.pagination?.pageNo, @@ -94,11 +96,16 @@ const TopicMessages = (props: any) => { history.push(`/cluster/${urlParams?.clusterId}/testing/consumer`); }; - const onTableChange = (pagination: any, filters: any, sorter: any) => { - defaultSorter.sortField = sorter.field || ''; - defaultSorter.sortType = sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : ''; + const onTableChange = (pagination: any, filters: any, sorter: any, extra: any) => { setPagination(pagination); - genData(); + // 只有排序事件时,触发重新请求后端数据 + if(extra.action === 'sort') { + setSorter({ + sortField: sorter.field || '', + sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '' + }); + genData(); + } // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; // const sortColumn = sorter.field && toLine(sorter.field); // genData({ pageNo: pagination.current, pageSize: pagination.pageSize, filters, asc, sortColumn, queryTerm: searchResult, ...allParams }); @@ -106,7 +113,7 @@ const TopicMessages = (props: any) => { useEffect(() => { props.positionType === 'Messages' && genData(); - }, [props, params]); + }, [props, params, sorter]); return ( <> diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/config.tsx index 5bb75eb04..085ad0463 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/config.tsx @@ -85,7 +85,8 @@ export const getTopicMessagesColmns = () => { title: 'Timestamp', dataIndex: 'timestampUnitMs', key: 'timestampUnitMs', - render: (t: number) => (t ? moment(t).format(timeFormat) : '-'), + sorter: true, + render: (t: number) => (t ? moment(t).format(timeFormat) + '.' + moment(t).millisecond() : '-'), }, { title: 'Key', diff --git a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java index 808c7a327..d1e09e661 100644 --- a/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java +++ b/km-rest/src/main/java/com/xiaojukeji/know/streaming/km/rest/api/v3/topic/TopicStateController.java @@ -92,9 +92,8 @@ public Result> getTopicPartitions(@PathVariable Long clus @ResponseBody public Result> getTopicMessages(@PathVariable Long clusterPhyId, @PathVariable String topicName, - @Validated @RequestBody TopicRecordDTO dto, - @Validated PaginationSortDTO sortDto) throws Exception { - return topicStateManager.getTopicMessages(clusterPhyId, topicName, dto, sortDto); + @Validated @RequestBody TopicRecordDTO dto) throws Exception { + return topicStateManager.getTopicMessages(clusterPhyId, topicName, dto); } @ApiOperation(value = "Topic-ACL信息", notes = "") From 0d227aef498d8f53c49eda2d2bb3b54675712bc6 Mon Sep 17 00:00:00 2001 From: superspeedone <525390802@qq.com> Date: Fri, 9 Sep 2022 17:29:22 +0800 Subject: [PATCH 04/53] =?UTF-8?q?Topic=E6=B6=88=E6=81=AF=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81Timestamp=E6=8E=92=E5=BA=8F=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=94=AF=E6=8C=81=E6=8C=89=E6=8C=87=E5=AE=9A=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/pages/TopicDetail/Messages.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index 6862596e4..eecf792a5 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -104,7 +104,6 @@ const TopicMessages = (props: any) => { sortField: sorter.field || '', sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '' }); - genData(); } // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; // const sortColumn = sorter.field && toLine(sorter.field); From 405e6e0c1d73ceabe44e907d2b4371c2bbb3b412 Mon Sep 17 00:00:00 2001 From: superspeedone <525390802@qq.com> Date: Fri, 9 Sep 2022 18:56:45 +0800 Subject: [PATCH 05/53] =?UTF-8?q?Topic=E6=B6=88=E6=81=AF=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81Timestamp=E6=8E=92=E5=BA=8F=EF=BC=8C=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=94=AF=E6=8C=81=E6=8C=89=E6=8C=87=E5=AE=9A=E6=97=A5?= =?UTF-8?q?=E6=9C=9F=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../streaming/km/biz/topic/impl/TopicStateManagerImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 0fb368e0e..1afb12106 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -24,6 +24,7 @@ import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; import com.xiaojukeji.know.streaming.km.common.converter.TopicVOConverter; import com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum; +import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; @@ -38,6 +39,7 @@ import com.xiaojukeji.know.streaming.km.core.service.topic.TopicService; import com.xiaojukeji.know.streaming.km.core.service.version.metrics.TopicMetricVersionItems; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.admin.OffsetSpec; import org.apache.kafka.clients.consumer.*; import org.apache.kafka.common.TopicPartition; @@ -209,6 +211,10 @@ public Result> getTopicMessages(Long clusterPhyId, String to // 排序 if (ObjectUtils.isNotEmpty(voList)) { + // 默认按时间倒序排序 + if (StringUtils.isBlank(dto.getSortType())) { + dto.setSortType(SortTypeEnum.DESC.getSortType()); + } PaginationUtil.pageBySort(voList, dto.getSortField(), dto.getSortType()); } From 61efdf492f23b20913e4b9fa1ea6ef8327cca800 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Tue, 13 Sep 2022 23:20:41 +0800 Subject: [PATCH 06/53] =?UTF-8?q?=E6=B7=BB=E5=8A=A0docker-compose=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 95 +++ km-dist/docker/knowstreaming-es/Dockerfile | 6 + .../docker/knowstreaming-manage/Dockerfile | 10 + .../docker/knowstreaming-manage/esinit/es.sh | 2 + .../esinit/ks_kafka_broker_metric | 102 +++ .../esinit/ks_kafka_cluster_metric | 187 +++++ .../esinit/ks_kafka_group_metric | 75 ++ .../esinit/ks_kafka_partition_metric | 66 ++ .../esinit/ks_kafka_replication_metric | 23 + .../esinit/ks_kafka_topic_metric | 117 ++++ .../knowstreaming-manage/esinit/template.sh | 662 ++++++++++++++++++ km-dist/docker/knowstreaming-mysql/Dockerfile | 7 + km-dist/docker/knowstreaming-mysql/mysql.cnf | 15 + .../knowstreaming-mysql/sql/ddl-ks-km.sql | 356 ++++++++++ .../knowstreaming-mysql/sql/ddl-logi-job.sql | 119 ++++ .../sql/ddl-logi-security.sql | 205 ++++++ .../knowstreaming-mysql/sql/dml-ks-km.sql | 7 + .../knowstreaming-mysql/sql/dml-logi.sql | 98 +++ km-dist/docker/knowstreaming-web/Dockerfile | 6 + .../knowstreaming-web/conf/knowStreaming.conf | 46 ++ km-dist/init/sql/ddl-logi-security.sql | 2 +- 21 files changed, 2205 insertions(+), 1 deletion(-) create mode 100644 km-dist/docker/docker-compose.yml create mode 100644 km-dist/docker/knowstreaming-es/Dockerfile create mode 100644 km-dist/docker/knowstreaming-manage/Dockerfile create mode 100644 km-dist/docker/knowstreaming-manage/esinit/es.sh create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric create mode 100644 km-dist/docker/knowstreaming-manage/esinit/template.sh create mode 100644 km-dist/docker/knowstreaming-mysql/Dockerfile create mode 100644 km-dist/docker/knowstreaming-mysql/mysql.cnf create mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql create mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql create mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql create mode 100644 km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql create mode 100644 km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql create mode 100644 km-dist/docker/knowstreaming-web/Dockerfile create mode 100644 km-dist/docker/knowstreaming-web/conf/knowStreaming.conf diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml new file mode 100644 index 000000000..ee4b34665 --- /dev/null +++ b/km-dist/docker/docker-compose.yml @@ -0,0 +1,95 @@ +version: "3" + +services: + + knowstreaming-manager: + image: ks_manage:1.0 + container_name: knowstreaming-manager + privileged: true + restart: always + depends_on: + - elasticsearch_single + - kmysql + links: + - elasticsearch_single + - kmysql + expose: + - 80 + #ports: + # - '80:80' + environment: + TZ: Asia/Shanghai + server.port: 80 + spring.datasource.know-streaming.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + spring.datasource.know-streaming.username: root + spring.datasource.know-streaming.password: admin2022_ + + spring.logi-job.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + spring.logi-job.username: root + spring.logi-job.password: admin2022_ + + spring.logi-security.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + spring.logi-security.username: root + spring.logi-security.password: admin2022_ + spring.logi-security.resource-extend-bean-name: myResourceExtendImpl + client-pool.kafka-consumer.max-total-client-num: 20 + + es.client.address: elasticsearch_single:9200 + ES_CLIENT_ADDRESS: elasticsearch_single:9200 + log.path: /logs + + JAVA_OPTS: -Xmx1g -Xms1g -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08 + + networks: + - ks + volumes: + - /Users/haoqi/Downloads/ks/manage/log:/logs + knowstreaming-ui: + image: ks_ui:1.0 + container_name: knowstreaming-ui + restart: always + ports: + - '80:80' + environment: + TZ: Asia/Shanghai + depends_on: + - knowstreaming-manager + links: + - knowstreaming-manager + networks: + - ks + + + elasticsearch_single: + image: docker.io/library/elasticsearch:7.6.2 + container_name: elasticsearch_single + ports: + - '9200:9200' + - '9300:9300' + environment: + TZ: Asia/Shanghai + ES_JAVA_OPTS: -Xms512m -Xmx512m + discovery.type: single-node + volumes: + - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data + networks: + - ks + + + kmysql: + image: ks_mysql:1.0 + container_name: kmysql + environment: + TZ: Asia/Shanghai + MYSQL_ROOT_PASSWORD: admin2022_ + MYSQL_DATABASE: know_streaming + networks: + - ks + expose: + - 3306 + volumes: + - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql + +networks: + ks: + driver: bridge \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-es/Dockerfile b/km-dist/docker/knowstreaming-es/Dockerfile new file mode 100644 index 000000000..6a6f6143f --- /dev/null +++ b/km-dist/docker/knowstreaming-es/Dockerfile @@ -0,0 +1,6 @@ +FROM docker.io/library/elasticsearch:7.6.2 +LABEL author=haoqi6677 +#EXPOSE 9200 +#EXPOSE 9300 +#ARG INIT_SOURCE_FILE=./esinit/* +#COPY ${INIT_SOURCE_FILE} / \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile new file mode 100644 index 000000000..021a592d3 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -0,0 +1,10 @@ +FROM bitnami/java:11 +ARG JAVA_OPTS +ARG JAR_FILE=./jar/*.jar +ARG INIT_ES_FILE=./esinit/* +COPY ${JAR_FILE} /app/app.jar +COPY ${INIT_ES_FILE} / + +ENTRYPOINT ["/bin/bash","/es.sh"] +CMD ["dumb-init","java","${JAVA_OPTS}", "-jar", "/app/app.jar"] +#ENTRYPOINT java -jar /app/app.jar \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/es.sh b/km-dist/docker/knowstreaming-manage/esinit/es.sh new file mode 100644 index 000000000..9bd811bc3 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/es.sh @@ -0,0 +1,2 @@ +/bin/bash /template.sh start +java ${JAVA_OPTS} -jar /app/app.jar \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric new file mode 100644 index 000000000..78933a4d9 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric @@ -0,0 +1,102 @@ +PUT _template/ks_kafka_broker_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_broker_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "NetworkProcessorAvgIdle" : { + "type" : "float" + }, + "UnderReplicatedPartitions" : { + "type" : "float" + }, + "BytesIn_min_15" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "RequestHandlerAvgIdle" : { + "type" : "float" + }, + "connectionsCount" : { + "type" : "float" + }, + "BytesIn_min_5" : { + "type" : "float" + }, + "HealthScore" : { + "type" : "float" + }, + "BytesOut" : { + "type" : "float" + }, + "BytesOut_min_15" : { + "type" : "float" + }, + "BytesIn" : { + "type" : "float" + }, + "BytesOut_min_5" : { + "type" : "float" + }, + "TotalRequestQueueSize" : { + "type" : "float" + }, + "MessagesIn" : { + "type" : "float" + }, + "TotalProduceRequests" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + }, + "TotalResponseQueueSize" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric new file mode 100644 index 000000000..76d51cbd8 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric @@ -0,0 +1,187 @@ +PUT _template/ks_kafka_cluster_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_cluster_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "Connections" : { + "type" : "double" + }, + "BytesIn_min_15" : { + "type" : "double" + }, + "PartitionURP" : { + "type" : "double" + }, + "HealthScore_Topics" : { + "type" : "double" + }, + "EventQueueSize" : { + "type" : "double" + }, + "ActiveControllerCount" : { + "type" : "double" + }, + "GroupDeads" : { + "type" : "double" + }, + "BytesIn_min_5" : { + "type" : "double" + }, + "HealthCheckTotal_Topics" : { + "type" : "double" + }, + "Partitions" : { + "type" : "double" + }, + "BytesOut" : { + "type" : "double" + }, + "Groups" : { + "type" : "double" + }, + "BytesOut_min_15" : { + "type" : "double" + }, + "TotalRequestQueueSize" : { + "type" : "double" + }, + "HealthCheckPassed_Groups" : { + "type" : "double" + }, + "TotalProduceRequests" : { + "type" : "double" + }, + "HealthCheckPassed" : { + "type" : "double" + }, + "TotalLogSize" : { + "type" : "double" + }, + "GroupEmptys" : { + "type" : "double" + }, + "PartitionNoLeader" : { + "type" : "double" + }, + "HealthScore_Brokers" : { + "type" : "double" + }, + "Messages" : { + "type" : "double" + }, + "Topics" : { + "type" : "double" + }, + "PartitionMinISR_E" : { + "type" : "double" + }, + "HealthCheckTotal" : { + "type" : "double" + }, + "Brokers" : { + "type" : "double" + }, + "Replicas" : { + "type" : "double" + }, + "HealthCheckTotal_Groups" : { + "type" : "double" + }, + "GroupRebalances" : { + "type" : "double" + }, + "MessageIn" : { + "type" : "double" + }, + "HealthScore" : { + "type" : "double" + }, + "HealthCheckPassed_Topics" : { + "type" : "double" + }, + "HealthCheckTotal_Brokers" : { + "type" : "double" + }, + "PartitionMinISR_S" : { + "type" : "double" + }, + "BytesIn" : { + "type" : "double" + }, + "BytesOut_min_5" : { + "type" : "double" + }, + "GroupActives" : { + "type" : "double" + }, + "MessagesIn" : { + "type" : "double" + }, + "GroupReBalances" : { + "type" : "double" + }, + "HealthCheckPassed_Brokers" : { + "type" : "double" + }, + "HealthScore_Groups" : { + "type" : "double" + }, + "TotalResponseQueueSize" : { + "type" : "double" + }, + "Zookeepers" : { + "type" : "double" + }, + "LeaderMessages" : { + "type" : "double" + }, + "HealthScore_Cluster" : { + "type" : "double" + }, + "HealthCheckPassed_Cluster" : { + "type" : "double" + }, + "HealthCheckTotal_Cluster" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric new file mode 100644 index 000000000..9fe7008b6 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric @@ -0,0 +1,75 @@ +PUT _template/ks_kafka_group_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_group_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "group" : { + "type" : "keyword" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "HealthScore" : { + "type" : "float" + }, + "Lag" : { + "type" : "float" + }, + "OffsetConsumed" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + } + } + }, + "groupMetric" : { + "type" : "keyword" + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric new file mode 100644 index 000000000..2538eba31 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric @@ -0,0 +1,66 @@ +PUT _template/ks_kafka_partition_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_partition_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric new file mode 100644 index 000000000..b7beda547 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric @@ -0,0 +1,23 @@ +PUT _template/ks_kafka_replication_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_replication_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric new file mode 100644 index 000000000..a2456dc61 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric @@ -0,0 +1,117 @@ +PUT _template/ks_kafka_topic_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_topic_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "topic" : { + "type" : "keyword" + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "BytesIn_min_15" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "BytesRejected" : { + "type" : "float" + }, + "PartitionURP" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "ReplicationCount" : { + "type" : "float" + }, + "ReplicationBytesOut" : { + "type" : "float" + }, + "ReplicationBytesIn" : { + "type" : "float" + }, + "FailedFetchRequests" : { + "type" : "float" + }, + "BytesIn_min_5" : { + "type" : "float" + }, + "HealthScore" : { + "type" : "float" + }, + "LogSize" : { + "type" : "float" + }, + "BytesOut" : { + "type" : "float" + }, + "BytesOut_min_15" : { + "type" : "float" + }, + "FailedProduceRequests" : { + "type" : "float" + }, + "BytesIn" : { + "type" : "float" + }, + "BytesOut_min_5" : { + "type" : "float" + }, + "MessagesIn" : { + "type" : "float" + }, + "TotalProduceRequests" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + } + } + }, + "brokerAgg" : { + "type" : "keyword" + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/template.sh b/km-dist/docker/knowstreaming-manage/esinit/template.sh new file mode 100644 index 000000000..bd69d1d10 --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/esinit/template.sh @@ -0,0 +1,662 @@ +esAddrPort=${ES_CLIENT_ADDRESS} +echo "Wait ElasticSearch Start..." +while true +do + curl -s --connect-timeout 10 -o /dev/null http://${esAddrPort}/_cat/nodes >> /dev/null 2>&1 + if [ "$?" != "0" ];then + sleep 1s + else + echo "ElasticSearch Start Success" + break + fi +done + +curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_broker_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_broker_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "NetworkProcessorAvgIdle" : { + "type" : "float" + }, + "UnderReplicatedPartitions" : { + "type" : "float" + }, + "BytesIn_min_15" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "RequestHandlerAvgIdle" : { + "type" : "float" + }, + "connectionsCount" : { + "type" : "float" + }, + "BytesIn_min_5" : { + "type" : "float" + }, + "HealthScore" : { + "type" : "float" + }, + "BytesOut" : { + "type" : "float" + }, + "BytesOut_min_15" : { + "type" : "float" + }, + "BytesIn" : { + "type" : "float" + }, + "BytesOut_min_5" : { + "type" : "float" + }, + "TotalRequestQueueSize" : { + "type" : "float" + }, + "MessagesIn" : { + "type" : "float" + }, + "TotalProduceRequests" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + }, + "TotalResponseQueueSize" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_cluster_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_cluster_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "Connections" : { + "type" : "double" + }, + "BytesIn_min_15" : { + "type" : "double" + }, + "PartitionURP" : { + "type" : "double" + }, + "HealthScore_Topics" : { + "type" : "double" + }, + "EventQueueSize" : { + "type" : "double" + }, + "ActiveControllerCount" : { + "type" : "double" + }, + "GroupDeads" : { + "type" : "double" + }, + "BytesIn_min_5" : { + "type" : "double" + }, + "HealthCheckTotal_Topics" : { + "type" : "double" + }, + "Partitions" : { + "type" : "double" + }, + "BytesOut" : { + "type" : "double" + }, + "Groups" : { + "type" : "double" + }, + "BytesOut_min_15" : { + "type" : "double" + }, + "TotalRequestQueueSize" : { + "type" : "double" + }, + "HealthCheckPassed_Groups" : { + "type" : "double" + }, + "TotalProduceRequests" : { + "type" : "double" + }, + "HealthCheckPassed" : { + "type" : "double" + }, + "TotalLogSize" : { + "type" : "double" + }, + "GroupEmptys" : { + "type" : "double" + }, + "PartitionNoLeader" : { + "type" : "double" + }, + "HealthScore_Brokers" : { + "type" : "double" + }, + "Messages" : { + "type" : "double" + }, + "Topics" : { + "type" : "double" + }, + "PartitionMinISR_E" : { + "type" : "double" + }, + "HealthCheckTotal" : { + "type" : "double" + }, + "Brokers" : { + "type" : "double" + }, + "Replicas" : { + "type" : "double" + }, + "HealthCheckTotal_Groups" : { + "type" : "double" + }, + "GroupRebalances" : { + "type" : "double" + }, + "MessageIn" : { + "type" : "double" + }, + "HealthScore" : { + "type" : "double" + }, + "HealthCheckPassed_Topics" : { + "type" : "double" + }, + "HealthCheckTotal_Brokers" : { + "type" : "double" + }, + "PartitionMinISR_S" : { + "type" : "double" + }, + "BytesIn" : { + "type" : "double" + }, + "BytesOut_min_5" : { + "type" : "double" + }, + "GroupActives" : { + "type" : "double" + }, + "MessagesIn" : { + "type" : "double" + }, + "GroupReBalances" : { + "type" : "double" + }, + "HealthCheckPassed_Brokers" : { + "type" : "double" + }, + "HealthScore_Groups" : { + "type" : "double" + }, + "TotalResponseQueueSize" : { + "type" : "double" + }, + "Zookeepers" : { + "type" : "double" + }, + "LeaderMessages" : { + "type" : "double" + }, + "HealthScore_Cluster" : { + "type" : "double" + }, + "HealthCheckPassed_Cluster" : { + "type" : "double" + }, + "HealthCheckTotal_Cluster" : { + "type" : "double" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "type" : "date" + } + } + }, + "aliases" : { } + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_group_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_group_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "group" : { + "type" : "keyword" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "HealthScore" : { + "type" : "float" + }, + "Lag" : { + "type" : "float" + }, + "OffsetConsumed" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + } + } + }, + "groupMetric" : { + "type" : "keyword" + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_partition_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_partition_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_replication_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_partition_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "partitionId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "clusterPhyId" : { + "type" : "long" + }, + "topic" : { + "type" : "keyword" + }, + "metrics" : { + "properties" : { + "LogStartOffset" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "LogEndOffset" : { + "type" : "float" + } + } + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }[root@10-255-0-23 template]# cat ks_kafka_replication_metric +PUT _template/ks_kafka_replication_metric +{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_replication_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }' + +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_topic_metric -d '{ + "order" : 10, + "index_patterns" : [ + "ks_kafka_topic_metric*" + ], + "settings" : { + "index" : { + "number_of_shards" : "10" + } + }, + "mappings" : { + "properties" : { + "brokerId" : { + "type" : "long" + }, + "routingValue" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "topic" : { + "type" : "keyword" + }, + "clusterPhyId" : { + "type" : "long" + }, + "metrics" : { + "properties" : { + "BytesIn_min_15" : { + "type" : "float" + }, + "Messages" : { + "type" : "float" + }, + "BytesRejected" : { + "type" : "float" + }, + "PartitionURP" : { + "type" : "float" + }, + "HealthCheckTotal" : { + "type" : "float" + }, + "ReplicationCount" : { + "type" : "float" + }, + "ReplicationBytesOut" : { + "type" : "float" + }, + "ReplicationBytesIn" : { + "type" : "float" + }, + "FailedFetchRequests" : { + "type" : "float" + }, + "BytesIn_min_5" : { + "type" : "float" + }, + "HealthScore" : { + "type" : "float" + }, + "LogSize" : { + "type" : "float" + }, + "BytesOut" : { + "type" : "float" + }, + "BytesOut_min_15" : { + "type" : "float" + }, + "FailedProduceRequests" : { + "type" : "float" + }, + "BytesIn" : { + "type" : "float" + }, + "BytesOut_min_5" : { + "type" : "float" + }, + "MessagesIn" : { + "type" : "float" + }, + "TotalProduceRequests" : { + "type" : "float" + }, + "HealthCheckPassed" : { + "type" : "float" + } + } + }, + "brokerAgg" : { + "type" : "keyword" + }, + "key" : { + "type" : "text", + "fields" : { + "keyword" : { + "ignore_above" : 256, + "type" : "keyword" + } + } + }, + "timestamp" : { + "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", + "index" : true, + "type" : "date", + "doc_values" : true + } + } + }, + "aliases" : { } + }' + +for i in `seq 6`; +do + logdate=_$(date -d "${i} day ago" +%Y-%m-%d) + curl -s --connect-timeout 10 -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_broker_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_cluster_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_group_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_partition_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_topic_metric${logdate} || \ + exit 2 +done + +echo "ElasticSearch Initialize Success" \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/Dockerfile b/km-dist/docker/knowstreaming-mysql/Dockerfile new file mode 100644 index 000000000..1c5d8b9b1 --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/Dockerfile @@ -0,0 +1,7 @@ +FROM mysql:5.7.39-oracle +EXPOSE 3306 +ARG INIT_SOURCE_FILE=./sql/*.sql +#RUN mkdir /data/mysql +#RUN mkdir /var/lib/mysql-files +COPY ${INIT_SOURCE_FILE} /docker-entrypoint-initdb.d/ +COPY ./*.cnf /etc/mysql/conf.d/ \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/mysql.cnf b/km-dist/docker/knowstreaming-mysql/mysql.cnf new file mode 100644 index 000000000..37c970108 --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/mysql.cnf @@ -0,0 +1,15 @@ +[client] +default-character-set=utf8 +[mysql] +default-character-set=utf8 +[mysqld] +skip-host-cache +skip-name-resolve +datadir=/data/mysql +socket=/var/lib/mysql/mysql.sock +secure-file-priv=/var/lib/mysql-files +character-set-server=utf8 +user=mysql +symbolic-links=0 +pid-file=/var/run/mysqld/mysqld.pid +sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql new file mode 100644 index 000000000..506969175 --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql @@ -0,0 +1,356 @@ +-- KS-KM自身的SQL,KS-KM依赖 Logi-Job 和 Logi-Security,因此另外两个ddl sql文件也需要执行 + +DROP TABLE IF EXISTS `ks_km_broker`; +CREATE TABLE `ks_km_broker` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', + `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'broker主机名', + `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'broker端口', + `jmx_port` int(16) NOT NULL DEFAULT '-1' COMMENT 'Jmx端口', + `start_timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT '启动时间', + `rack` varchar(128) NOT NULL DEFAULT '' COMMENT 'Rack信息', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `endpoint_map` varchar(1024) NOT NULL DEFAULT '' COMMENT '监听信息', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_broker_id` (`cluster_phy_id`,`broker_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker信息表'; + + + +DROP TABLE IF EXISTS `ks_km_broker_config`; +CREATE TABLE `ks_km_broker_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', + `config_name` varchar(192) NOT NULL DEFAULT '' COMMENT '配置名称', + `config_value` text COMMENT '配置值', + `diff_type` int(16) NOT NULL DEFAULT '-1' COMMENT '差异类型', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_broker_name` (`cluster_phy_id`,`broker_id`,`config_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker配置信息表'; + + + +DROP TABLE IF EXISTS `ks_km_cluster_balance_job`; +CREATE TABLE `ks_km_cluster_balance_job` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `brokers` varchar(1024) NOT NULL DEFAULT '' COMMENT '均衡节点', + `topic_black_list` varchar(4096) NOT NULL DEFAULT '' COMMENT 'topic黑名单', + `type` int(16) NOT NULL DEFAULT '0' COMMENT '1:周期均衡,2:立即均衡', + `balance_interval_json` text COMMENT '均衡区间详情', + `metric_calculation_period` int(16) NOT NULL DEFAULT '0' COMMENT '指标计算周期,单位分钟', + `reassignment_json` text COMMENT '迁移脚本', + `parallel_num` int(16) NOT NULL DEFAULT '0' COMMENT '任务并行数', + `execution_strategy` int(16) NOT NULL DEFAULT '0' COMMENT '执行策略, 1:优先最大副本,2:优先最小副本', + `throttle_unit_b` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', + `total_reassign_size` double NOT NULL DEFAULT '0' COMMENT '总迁移大小', + `total_reassign_replica_num` int(16) NOT NULL DEFAULT '0' COMMENT '总迁移副本数', + `move_in_topic_list` varchar(4096) NOT NULL DEFAULT '' COMMENT '移入topic', + `broker_balance_detail` text COMMENT '节点均衡详情', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态 1:进行中,2:准备,3,成功,4:失败,5:取消', + `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务开始时间', + `finished_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务完成时间', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + `description` text COMMENT '备注', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群均衡任务'; + + + +DROP TABLE IF EXISTS `ks_km_cluster_balance_job_config`; +CREATE TABLE `ks_km_cluster_balance_job_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `brokers` varchar(256) NOT NULL DEFAULT '' COMMENT '均衡节点', + `topic_black_list` varchar(4096) NOT NULL DEFAULT '' COMMENT 'topic黑名单', + `task_cron` varchar(64) NOT NULL DEFAULT '' COMMENT '任务周期', + `balance_interval_json` text COMMENT '均衡区间详情', + `metric_calculation_period` int(16) NOT NULL DEFAULT '0' COMMENT '指标计算周期,单位分钟', + `reassignment_json` text COMMENT '迁移脚本', + `parallel_num` int(16) NOT NULL DEFAULT '0' COMMENT '任务并行数', + `execution_strategy` int(16) NOT NULL DEFAULT '0' COMMENT '执行策略, 1:优先最大副本,2:优先最小副本', + `throttle_unit_b` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', + `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态 0:未开启,1:开启', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群均衡任务'; + + + +DROP TABLE IF EXISTS `ks_km_cluster_balance_reassign`; +CREATE TABLE `ks_km_cluster_balance_reassign` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `job_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '父任务ID', + `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', + `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', + `original_broker_ids` text COMMENT '源BrokerId列表', + `reassign_broker_ids` text COMMENT '目标BrokerId列表', + `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务开始时间', + `finished_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务完成时间', + `extend_data` text COMMENT '扩展数据', + `status` int(16) NOT NULL DEFAULT '2' COMMENT '任务状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群平衡迁移详情'; + + + +DROP TABLE IF EXISTS `ks_km_group_member`; +CREATE TABLE `ks_km_group_member` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', + `group_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Group名称', + `kafka_user` varchar(192) NOT NULL DEFAULT '' COMMENT 'Kafka用户', + `state` varchar(64) NOT NULL DEFAULT '' COMMENT '状态', + `member_count` int(11) NOT NULL DEFAULT '0' COMMENT '成员数', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_topic_group` (`cluster_phy_id`,`topic_name`,`group_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='GroupMember信息表'; + + + +DROP TABLE IF EXISTS `ks_km_health_check_result`; +CREATE TABLE `ks_km_health_check_result` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `dimension` int(11) NOT NULL DEFAULT '0' COMMENT '检查维度(0:未知,1:Cluster,2:Broker,3:Topic,4:Group)', + `config_name` varchar(192) NOT NULL DEFAULT '' COMMENT '配置名', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '物理集群ID', + `res_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', + `passed` int(11) NOT NULL DEFAULT '0' COMMENT '检查通过(0:未通过,1:通过)', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_dimension_config_cluster_res` (`dimension`,`config_name`,`cluster_phy_id`,`res_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='健康检查结果'; + + + +DROP TABLE IF EXISTS `ks_km_job`; +CREATE TABLE `ks_km_job` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', + `job_name` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务名称', + `job_type` tinyint(10) NOT NULL COMMENT '任务类型', + `job_status` tinyint(10) NOT NULL COMMENT '任务状态', + `job_data` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务的详细信息', + `job_desc` varchar(1024) NOT NULL DEFAULT '' COMMENT '任务描述', + `cluster_id` int(11) NOT NULL COMMENT 'kafka集群id', + `target` varchar(8192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务执行对象', + `running_status` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '任务运行详细状态(json), Success:7 Fail:1 Doing:2', + `creator` varchar(45) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '创建者', + `plan_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '计划执行时间', + `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '实际执行时间', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `index_cluster_id` (`cluster_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Job信息'; + + + +DROP TABLE IF EXISTS `ks_km_kafka_acl`; +CREATE TABLE `ks_km_kafka_acl` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `principal` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Kafka用户', + `operation` int(11) NOT NULL DEFAULT '0' COMMENT '操作', + `permission_type` int(11) NOT NULL DEFAULT '0' COMMENT '权限类型(0:未知,1:任意,2:拒绝,3:允许)', + `host` varchar(192) NOT NULL DEFAULT '127.0.0.1' COMMENT '机器', + `resource_type` int(11) NOT NULL DEFAULT '0' COMMENT '资源类型(0:未知,1:任意,2:Topic,3:Group,4:Cluster,5:事务,6:Token)', + `resource_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', + `pattern_type` int(11) NOT NULL COMMENT '匹配类型(0:未知,1:任意,2:Match,3:Literal,4:prefixed)', + `unique_field` varchar(1024) NOT NULL DEFAULT '' COMMENT '唯一字段,由cluster_phy_id等字段组成', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_uniq_field` (`unique_field`), + KEY `idx_cluster_phy_id_principal_res_name` (`cluster_phy_id`,`principal`,`resource_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ACL信息'; + + + +DROP TABLE IF EXISTS `ks_km_kafka_change_record`; +CREATE TABLE `ks_km_kafka_change_record` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `res_type` int(11) NOT NULL DEFAULT '-1' COMMENT '资源类型', + `res_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', + `operate_type` int(11) NOT NULL DEFAULT '-1' COMMENT '操作类型', + `operate_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间', + `unique_field` varchar(1024) NOT NULL DEFAULT '' COMMENT '唯一键字段', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `unique_field` (`unique_field`), + KEY `idx_cluster_phy_id` (`cluster_phy_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Kafka变更记录表'; + + + +DROP TABLE IF EXISTS `ks_km_kafka_controller`; +CREATE TABLE `ks_km_kafka_controller` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', + `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', + `broker_host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', + `broker_rack` varchar(256) NOT NULL DEFAULT '' COMMENT 'BrokerRack信息', + `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'controller变更时间,-1表示未存活', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_broker_timestamp` (`cluster_phy_id`,`broker_id`,`timestamp`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='controller记录表'; + + + +DROP TABLE IF EXISTS `ks_km_kafka_user`; +CREATE TABLE `ks_km_kafka_user` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '名称', + `token` varchar(8192) NOT NULL DEFAULT '' COMMENT '密钥', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Kafka-User信息表'; + + + +DROP TABLE IF EXISTS `ks_km_partition`; +CREATE TABLE `ks_km_partition` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', + `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', + `leader_broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区的LeaderBroker,-1表示无Leader', + `in_sync_replicas` varchar(512) NOT NULL DEFAULT '-1' COMMENT 'ISR', + `assign_replicas` varchar(512) NOT NULL DEFAULT '-1' COMMENT 'AR', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_topic_partition` (`cluster_phy_id`,`topic_name`,`partition_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Partition信息表'; + + + +DROP TABLE IF EXISTS `ks_km_physical_cluster`; +CREATE TABLE `ks_km_physical_cluster` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群id', + `name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', + `zookeeper` varchar(2048) NOT NULL DEFAULT '' COMMENT 'zk地址', + `bootstrap_servers` varchar(2048) NOT NULL DEFAULT '' COMMENT 'server地址', + `kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'kafka版本', + `client_properties` text COMMENT 'Kafka客户端配置', + `jmx_properties` text COMMENT 'JMX配置', + `description` text COMMENT '备注', + `auth_type` int(11) NOT NULL DEFAULT '0' COMMENT '认证类型,-1未知,0:无认证,', + `run_state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '运行状态, 0表示未监控, 1监控中,有ZK,2:监控中,无ZK', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '接入时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='物理集群信息表'; + + + +DROP TABLE IF EXISTS `ks_km_platform_cluster_config`; +CREATE TABLE `ks_km_platform_cluster_config` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', + `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `value_group` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项组', + `value_name` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项名字', + `value` text COMMENT '配置项的值', + `description` text COMMENT '备注', + `operator` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '操作者', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_id_group_name` (`cluster_id`,`value_group`,`value_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='KS平台集群配置'; + + + +DROP TABLE IF EXISTS `ks_km_reassign_job`; +CREATE TABLE `ks_km_reassign_job` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `reassignment_json` text COMMENT '迁移计划', + `throttle_unit_byte` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', + `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务开始时间', + `finished_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务完成时间', + `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', + `description` text COMMENT '备注', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='迁移Job信息'; + + + +DROP TABLE IF EXISTS `ks_km_reassign_sub_job`; +CREATE TABLE `ks_km_reassign_sub_job` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `job_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '父任务ID', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', + `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', + `original_broker_ids` text COMMENT '源BrokerId列表', + `reassign_broker_ids` text COMMENT '目标BrokerId列表', + `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务开始时间', + `finished_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务完成时间', + `extend_data` text COMMENT '扩展数据', + `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='迁移SubJob信息'; + + + +DROP TABLE IF EXISTS `ks_km_topic`; +CREATE TABLE `ks_km_topic` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', + `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', + `replica_num` int(11) NOT NULL DEFAULT '-1' COMMENT '副本数', + `partition_num` int(11) NOT NULL DEFAULT '-1' COMMENT '分区数', + `broker_ids` varchar(2048) NOT NULL DEFAULT '' COMMENT 'BrokerId列表', + `partition_map` text COMMENT '分区分布信息', + `retention_ms` bigint(20) NOT NULL DEFAULT '-2' COMMENT '保存时间,-2:未知,-1:无限制,>=0对应时间,单位ms', + `type` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'Topic类型,默认0,0:普通,1:Kafka内部', + `description` text COMMENT '备注信息', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(尽量与Topic实际创建时间一致)', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间(尽量与Topic实际创建时间一致)', + PRIMARY KEY (`id`), + UNIQUE KEY `uniq_cluster_phy_id_topic_name` (`cluster_phy_id`,`topic_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic信息表'; + + +DROP TABLE IF EXISTS `ks_km_app_node`; +CREATE TABLE `ks_km_app_node` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', + `host_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'host', + `ip` varchar(256) NOT NULL DEFAULT '' COMMENT 'ip', + `beat_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'node 的心跳时间', + `app_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'km 集群的应用名', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_app_host` (`app_name`,`host_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='km集群部署的node信息'; diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql new file mode 100644 index 000000000..3ba229832 --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql @@ -0,0 +1,119 @@ +-- Logi-Job模块的sql,安装KS-KM需要执行该sql + + +DROP TABLE IF EXISTS `logi_job`; +CREATE TABLE `logi_job` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', + `task_code` varchar(255) NOT NULL DEFAULT '' COMMENT '任务code', + `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', + `try_times` int(10) NOT NULL DEFAULT '0' COMMENT '第几次重试', + `worker_code` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器', + `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', + `start_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '开始时间', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `job_code` (`job_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在执行的job信息'; + + + +DROP TABLE IF EXISTS `logi_job_log`; +CREATE TABLE `logi_job_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'job taskCode', + `task_code` varchar(255) NOT NULL DEFAULT '' COMMENT '任务code', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', + `task_desc` varchar(255) NOT NULL DEFAULT '' COMMENT '任务描述', + `task_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '任务id', + `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', + `try_times` int(10) NOT NULL DEFAULT '0' COMMENT '第几次重试', + `worker_code` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器', + `worker_ip` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器ip', + `start_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '开始时间', + `end_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '结束时间', + `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行结果 1成功 2失败 3取消', + `error` text NOT NULL COMMENT '错误信息', + `result` text NOT NULL COMMENT '执行结果', + `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `index_job_code` (`job_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job执行历史日志'; + + + +DROP TABLE IF EXISTS `logi_task`; +CREATE TABLE `logi_task` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `task_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '名称', + `task_desc` varchar(1000) NOT NULL DEFAULT '' COMMENT '任务描述', + `cron` varchar(100) NOT NULL DEFAULT '' COMMENT 'cron 表达式', + `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', + `params` varchar(1000) NOT NULL DEFAULT '' COMMENT '执行参数 map 形式{key1:value1,key2:value2}', + `retry_times` int(10) NOT NULL DEFAULT '0' COMMENT '允许重试次数', + `last_fire_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上次执行时间', + `timeout` bigint(20) NOT NULL DEFAULT '0' COMMENT '超时 毫秒', + `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1等待 2运行中 3暂停', + `sub_task_codes` varchar(1000) NOT NULL DEFAULT '' COMMENT '子任务code列表,逗号分隔', + `consensual` varchar(200) NOT NULL DEFAULT '' COMMENT '执行策略', + `owner` varchar(200) NOT NULL DEFAULT '' COMMENT '责任人', + `task_worker_str` varchar(3000) NOT NULL DEFAULT '' COMMENT '机器执行信息', + `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `task_code` (`task_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='任务信息'; + + + +DROP TABLE IF EXISTS `logi_task_lock`; +CREATE TABLE `logi_task_lock` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `task_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', + `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', + `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', + `expire_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '过期时间', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='任务锁'; + + + +DROP TABLE IF EXISTS `logi_worker`; +CREATE TABLE `logi_worker` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', + `worker_name` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker名', + `ip` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker的ip', + `cpu` int(11) NOT NULL DEFAULT '0' COMMENT 'cpu数量', + `cpu_used` double NOT NULL DEFAULT '0' COMMENT 'cpu使用率', + `memory` double NOT NULL DEFAULT '0' COMMENT '内存,以M为单位', + `memory_used` double NOT NULL DEFAULT '0' COMMENT '内存使用率', + `jvm_memory` double NOT NULL DEFAULT '0' COMMENT 'jvm堆大小,以M为单位', + `jvm_memory_used` double NOT NULL DEFAULT '0' COMMENT 'jvm堆使用率', + `job_num` int(10) NOT NULL DEFAULT '0' COMMENT '正在执行job数', + `heartbeat` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '心跳时间', + `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `worker_code` (`worker_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='worker信息'; + + + +DROP TABLE IF EXISTS `logi_worker_blacklist`; +CREATE TABLE `logi_worker_blacklist` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `worker_code` (`worker_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='worker黑名单列表'; diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql new file mode 100644 index 000000000..7efa1f3ac --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql @@ -0,0 +1,205 @@ +#-----------------------创建表----------------------- +DROP TABLE IF EXISTS `logi_security_dept`; +CREATE TABLE `logi_security_dept` +( + id int auto_increment primary key, + dept_name varchar(10) not null comment '部门名', + parent_id int not null comment '父部门id', + leaf tinyint(1) not null comment '是否叶子部门', + level tinyint not null comment 'parentId为0的层级为1', + description varchar(20) null comment '描述', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '部门信息表'; + +DROP TABLE IF EXISTS `logi_security_message`; +CREATE TABLE `logi_security_message` +( + id int auto_increment primary key, + title varchar(60) not null comment '标题', + content varchar(256) null comment '内容', + read_tag tinyint(1) default 0 null comment '是否已读', + oplog_id int null comment '操作日志id', + user_id int null comment '这条消息属于哪个用户的,用户id', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '消息中心'; + +DROP TABLE IF EXISTS `logi_security_oplog`; +CREATE TABLE `logi_security_oplog` +( + id int auto_increment primary key, + operator_ip varchar(20) not null comment '操作者ip', + operator varchar(20) null comment '操作者账号', + operate_page varchar(16) not null default '' comment '操作页面', + operate_type varchar(16) not null comment '操作类型', + target_type varchar(16) not null comment '对象分类', + target varchar(128) not null comment '操作对象', + operation_methods varchar(20) not null default '' comment '操作方式', + detail text null comment '日志详情', + create_time timestamp default CURRENT_TIMESTAMP null, + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '操作日志'; + +DROP TABLE IF EXISTS `logi_security_oplog_extra`; +CREATE TABLE `logi_security_oplog_extra` +( + id int auto_increment primary key, + info varchar(16) null comment '信息', + type tinyint not null comment '哪种信息:1:操作页面;2:操作类型;3:对象分类', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '操作日志信息(操作页面、操作类型、对象分类)'; + +DROP TABLE IF EXISTS `logi_security_permission`; +CREATE TABLE `logi_security_permission` +( + id int auto_increment primary key, + permission_name varchar(40) not null comment '权限名字', + parent_id int not null comment '父权限id', + leaf tinyint(1) not null comment '是否叶子权限点(具体的操作)', + level tinyint not null comment '权限点的层级(parentId为0的层级为1)', + description varchar(64) null comment '权限点描述', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '权限表'; + +DROP TABLE IF EXISTS `logi_security_project`; +CREATE TABLE `logi_security_project` +( + id int auto_increment comment '项目id' primary key, + project_code varchar(128) not null comment '项目编号', + project_name varchar(128) not null comment '项目名', + description varchar(512) default '' not null comment '项目描述', + dept_id int not null comment '部门id', + running tinyint(1) default 1 not null comment '启用 or 停用', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '项目表'; + +DROP TABLE IF EXISTS `logi_security_resource_type`; +CREATE TABLE `logi_security_resource_type` +( + id int auto_increment primary key, + type_name varchar(16) null comment '资源类型名', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '资源类型表'; + +DROP TABLE IF EXISTS `logi_security_role`; +CREATE TABLE `logi_security_role` +( + id int auto_increment primary key, + role_code varchar(128) not null comment '角色编号', + role_name varchar(128) not null comment '名称', + description varchar(128) null comment '角色描述', + last_reviser varchar(30) null comment '最后修改人', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '角色信息'; + +DROP TABLE IF EXISTS `logi_security_role_permission`; +CREATE TABLE `logi_security_role_permission` +( + id int auto_increment primary key, + role_id int not null comment '角色id', + permission_id int not null comment '权限id', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '角色权限表(只保留叶子权限与角色关系)'; + +DROP TABLE IF EXISTS `logi_security_user`; +CREATE TABLE `logi_security_user` +( + id int auto_increment primary key, + user_name varchar(64) not null comment '用户账号', + pw varchar(2048) not null comment '用户密码', + salt char(5) default '' not null comment '密码盐', + real_name varchar(128) default '' not null comment '真实姓名', + phone char(11) default '' not null comment 'mobile', + email varchar(30) default '' not null comment 'email', + dept_id int null comment '所属部门id', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + create_time timestamp default CURRENT_TIMESTAMP null comment '注册时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户信息'; + +DROP TABLE IF EXISTS `logi_security_user_project`; +CREATE TABLE `logi_security_user_project` +( + id int auto_increment primary key, + user_id int not null comment '用户id', + project_id int not null comment '项目id', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户项目关系表(项目负责人)'; + +DROP TABLE IF EXISTS `logi_security_user_resource`; +CREATE TABLE `logi_security_user_resource` +( + id int auto_increment primary key, + user_id int not null comment '用户id', + project_id int not null comment '资源所属项目id', + resource_type_id int not null comment '资源类别id', + resource_id int not null comment '资源id', + control_level tinyint not null comment '管理级别:1(查看权限)2(管理权限)', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户和资源关系表'; + +DROP TABLE IF EXISTS `logi_security_user_role`; +CREATE TABLE `logi_security_user_role` +( + id int auto_increment primary key, + user_id int not null comment '用户id', + role_id int not null comment '角色id', + create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', + update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', + is_delete tinyint(1) default 0 not null comment '逻辑删除', + app_name varchar(16) null comment '应用名称' +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户角色表'; + +-- ---------------------------- +-- Table structure for logi_config +-- ---------------------------- +DROP TABLE IF EXISTS `logi_security_config`; +CREATE TABLE `logi_security_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', + `value_group` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项组', + `value_name` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项名字', + `value` text COMMENT '配置项的值', + `edit` int(4) NOT NULL DEFAULT '1' COMMENT '是否可以编辑 1 不可编辑(程序获取) 2 可编辑', + `status` int(4) NOT NULL DEFAULT '1' COMMENT '1 正常 2 禁用', + `memo` varchar(1000) NOT NULL DEFAULT '' COMMENT '备注', + `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除', + `app_name` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '应用名称', + `operator` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '操作者', + PRIMARY KEY (`id`), + KEY `idx_group_name` (`value_group`,`value_name`) +) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 COMMENT='logi配置项'; \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql b/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql new file mode 100644 index 000000000..2d354a879 --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql @@ -0,0 +1,7 @@ +-- 检查检查配置 +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_CLUSTER_NO_CONTROLLER','{ \"value\": 1, \"weight\": 30 } ','集群Controller数正常','know-streaming'); +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_BROKER_REQUEST_QUEUE_FULL','{ \"value\": 10, \"weight\": 20 } ','Broker-RequestQueueSize指标','know-streaming'); +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_BROKER_NETWORK_PROCESSOR_AVG_IDLE_TOO_LOW','{ \"value\": 0.8, \"weight\": 20 } ','Broker-NetworkProcessorAvgIdlePercent指标','know-streaming'); +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_GROUP_RE_BALANCE_TOO_FREQUENTLY','{\n \"latestMinutes\": 10,\n \"detectedTimes\": 8,\n \"weight\": 10\n}\n','Group的re-balance频率','know-streaming'); +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_TOPIC_NO_LEADER','{ \"value\": 1, \"weight\": 10 } ','Topic 无Leader数','know-stream'); +INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_TOPIC_UNDER_REPLICA_TOO_LONG','{ \"latestMinutes\": 10, \"detectedTimes\": 8, \"weight\": 10 } ','Topic 未同步持续时间','know-streaming'); diff --git a/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql b/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql new file mode 100644 index 000000000..927a0bccf --- /dev/null +++ b/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql @@ -0,0 +1,98 @@ +-- 初始化权限 +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1593', '多集群管理', '0', '0', '1', '多集群管理', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1595', '系统管理', '0', '0', '1', '系统管理', '0', 'know-streaming'); + +-- 多集群管理权限 +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1597', '接入集群', '1593', '1', '2', '接入集群', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1599', '删除集群', '1593', '1', '2', '删除集群', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1601', 'Cluster-修改集群信息', '1593', '1', '2', 'Cluster-修改集群信息', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1603', 'Cluster-修改健康规则', '1593', '1', '2', 'Cluster-修改健康规则', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1605', 'Broker-修改Broker配置', '1593', '1', '2', 'Broker-修改Broker配置', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1607', 'Topic-新增Topic', '1593', '1', '2', 'Topic-新增Topic', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1609', 'Topic-扩分区', '1593', '1', '2', 'Topic-扩分区', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1611', 'Topic-删除Topic', '1593', '1', '2', 'Topic-扩分区', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1613', 'Topic-重置Offset', '1593', '1', '2', 'Topic-重置Offset', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1615', 'Topic-修改Topic配置', '1593', '1', '2', 'Topic-修改Topic配置', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1617', 'Consumers-重置Offset', '1593', '1', '2', 'Consumers-重置Offset', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1619', 'Test-Producer', '1593', '1', '2', 'Test-Producer', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1621', 'Test-Consumer', '1593', '1', '2', 'Test-Consumer', '0', 'know-streaming'); + +-- 系统管理权限 +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1623', '配置管理-新增配置', '1595', '1', '2', '配置管理-新增配置', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1625', '配置管理-编辑配置', '1595', '1', '2', '配置管理-编辑配置', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1627', '配置管理-删除配置', '1595', '1', '2', '配置管理-删除配置', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1629', '用户管理-新增人员', '1595', '1', '2', '用户管理-新增人员', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1631', '用户管理-编辑人员', '1595', '1', '2', '用户管理-编辑人员', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1633', '用户管理-修改人员密码', '1595', '1', '2', '用户管理-修改人员密码', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1635', '用户管理-删除人员', '1595', '1', '2', '用户管理-删除人员', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1637', '用户管理-新增角色', '1595', '1', '2', '用户管理-新增角色', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1639', '用户管理-编辑角色', '1595', '1', '2', '用户管理-编辑角色', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1641', '用户管理-分配用户角色', '1595', '1', '2', '用户管理-分配用户角色', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1643', '用户管理-删除角色', '1595', '1', '2', '用户管理-删除角色', '0', 'know-streaming'); + +-- 多集群管理权限2022-09-06新增 +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2000', '多集群管理查看', '1593', '1', '2', '多集群管理查看', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2002', 'Topic-迁移副本', '1593', '1', '2', 'Topic-迁移副本', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2004', 'Topic-扩缩副本', '1593', '1', '2', 'Topic-扩缩副本', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2006', 'Cluster-LoadReBalance-周期均衡', '1593', '1', '2', 'Cluster-LoadReBalance-周期均衡', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2008', 'Cluster-LoadReBalance-立即均衡', '1593', '1', '2', 'Cluster-LoadReBalance-立即均衡', '0', 'know-streaming'); +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2010', 'Cluster-LoadReBalance-设置集群规格', '1593', '1', '2', 'Cluster-LoadReBalance-设置集群规格', '0', 'know-streaming'); + + +-- 系统管理权限2022-09-06新增 +INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('3000', '系统管理查看', '1595', '1', '2', '系统管理查看', '0', 'know-streaming'); + + + + + + +-- 初始化用户 +INSERT INTO `logi_security_user` (`id`, `user_name`, `pw`, `real_name`, `is_delete`, `app_name`) VALUES ('1', 'admin', 'V1ZkU2RHRlhOSGxOUkVsNVdETjBRVlp0Y0V0T1IwWnlaVEZ6YWxGRVJrRkpNVEU1VTJwYVUySkhlRzlSU0RBOWUwQldha28wWVd0N1d5TkFNa0FqWFgxS05sSnNiR2hBZlE9PXtAVmpKNGFre1sjQDNAI119SjZSbGxoQH0=Mv{#cdRgJ45Lqx}3IubEW87!==', '系统管理员', '0', 'know-streaming'); + +-- 初始化角色 +INSERT INTO `logi_security_role` (`id`, `role_code`, `role_name`, `description`, `last_reviser`, `is_delete`, `app_name`) VALUES ('1677', 'r15477137', '管理员角色', '包含系统所有权限', 'admin', '0', 'know-streaming'); + +-- 初始化角色权限关系 +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1597', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1599', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1601', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1603', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1605', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1607', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1609', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1611', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1613', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1615', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1617', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1619', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1621', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1593', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1623', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1625', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1627', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1629', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1631', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1633', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1635', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1637', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1639', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1641', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1643', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1595', '0', 'know-streaming'); + +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2000', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2002', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2004', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2006', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2008', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2010', '0', 'know-streaming'); +INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '3000', '0', 'know-streaming'); + +-- 初始化 用户角色关系 +INSERT INTO `logi_security_user_role` (`id`, `user_id`, `role_id`, `is_delete`, `app_name`) VALUES ('1', '1', '1677', '0', 'know-streaming'); + +INSERT INTO `logi_security_config` +(`value_group`,`value_name`,`value`,`edit`,`status`,`memo`,`is_delete`,`app_name`,`operator`) +VALUES +('SECURITY.LOGIN','SECURITY.TRICK_USERS','[\n \"admin\"\n]',1,1,'允许跳过登录的用户',0,'know-streaming','admin'); \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-web/Dockerfile b/km-dist/docker/knowstreaming-web/Dockerfile new file mode 100644 index 000000000..f1bb3a193 --- /dev/null +++ b/km-dist/docker/knowstreaming-web/Dockerfile @@ -0,0 +1,6 @@ +FROM docker.io/library/nginx:1.23.1 +WORKDIR /pub +EXPOSE 80 +COPY ./conf/*.conf /etc/nginx/conf.d/default.conf +COPY ./pub /pub +# HEALTHCHECK --interval=30s --timeout=30s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf b/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf new file mode 100644 index 000000000..9f5007ffe --- /dev/null +++ b/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf @@ -0,0 +1,46 @@ +server { + listen 80; + server_name localhost; + gzip on; + gzip_buffers 16 8k; + gzip_comp_level 4; + gzip_http_version 1.0; + gzip_min_length 1280; + gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xml+rss application/json application/javascript text/*; + gzip_vary on; + root /pub; + location / { + root /pub; + if ($request_filename ~* .*\.(?:htm|html|json)$) { + add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; + } + try_files $uri /layout/index.html; + } + location ~* \.(json)$ { + add_header Cache-Control no-cache; + } + location @kmfallback { + } + #location ~ ^/(clusters|config|cluster|login) { + # rewrite ^.*$ /; + #} + location ~ ^/ks-km/api/v3 { + #rewrite ^/ks-km/api/v3/(.*)$ /ks-km/ks-km/api/v3/$1 break; + proxy_pass http://knowstreaming-manager; + #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; + #proxy_cookie_path /ks-km/ /; + #proxy_set_header Host $host; + #proxy_set_header Referer $http_referer; + #proxy_set_header Cookie $http_cookie; + #proxy_set_header X-Real-Ip $remote_addr; + #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + location ~ ^/logi-security/api/v1 { + #rewrite ^/logi-security/api/v1/(.*)$ /ks-km/logi-security/api/v1/$1 break; + proxy_pass http://knowstreaming-manager; + #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; + } + location ~ ^/(401|403|404|500){ + rewrite ^.*$ /; + } + } \ No newline at end of file diff --git a/km-dist/init/sql/ddl-logi-security.sql b/km-dist/init/sql/ddl-logi-security.sql index 69fcdc661..7efa1f3ac 100644 --- a/km-dist/init/sql/ddl-logi-security.sql +++ b/km-dist/init/sql/ddl-logi-security.sql @@ -38,7 +38,7 @@ CREATE TABLE `logi_security_oplog` operate_page varchar(16) not null default '' comment '操作页面', operate_type varchar(16) not null comment '操作类型', target_type varchar(16) not null comment '对象分类', - target varchar(20) not null comment '操作对象', + target varchar(128) not null comment '操作对象', operation_methods varchar(20) not null default '' comment '操作方式', detail text null comment '日志详情', create_time timestamp default CURRENT_TIMESTAMP null, From 0c14c641d00483e77cd7dccb55703be41a73d624 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Thu, 15 Sep 2022 14:26:45 +0800 Subject: [PATCH 07/53] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0docker-compose?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=96=B9=E5=BC=8F=202.=20=E6=9B=B4=E6=94=B9m?= =?UTF-8?q?anage=E6=9C=8D=E5=8A=A1=E5=88=9D=E5=A7=8B=E5=8C=96=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=203.=20=E6=9B=B4=E6=94=B9es=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 40 +++---- km-dist/docker/knowstreaming-es/Dockerfile | 6 - .../docker/knowstreaming-manage/Dockerfile | 9 +- .../knowstreaming-manage/conf/application.yml | 107 ++++++++++++++++++ .../docker/knowstreaming-manage/esinit/es.sh | 9 +- .../knowstreaming-manage/esinit/template.sh | 41 ++++--- km-dist/docker/knowstreaming-mysql/Dockerfile | 2 +- 7 files changed, 157 insertions(+), 57 deletions(-) delete mode 100644 km-dist/docker/knowstreaming-es/Dockerfile create mode 100644 km-dist/docker/knowstreaming-manage/conf/application.yml diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index ee4b34665..3e902498c 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -15,31 +15,17 @@ services: - kmysql expose: - 80 - #ports: - # - '80:80' environment: TZ: Asia/Shanghai - server.port: 80 - spring.datasource.know-streaming.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - spring.datasource.know-streaming.username: root - spring.datasource.know-streaming.password: admin2022_ - spring.logi-job.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - spring.logi-job.username: root - spring.logi-job.password: admin2022_ + SERVER_MYSQL_ADDRESS: kmysql:3306 + SERVER_MYSQL_DB: know_streaming + SERVER_MYSQL_USER: root + SERVER_MYSQL_PASSWORD: admin2022_ - spring.logi-security.jdbc-url: jdbc:mariadb://kmysql:3306/know_streaming?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - spring.logi-security.username: root - spring.logi-security.password: admin2022_ - spring.logi-security.resource-extend-bean-name: myResourceExtendImpl - client-pool.kafka-consumer.max-total-client-num: 20 - - es.client.address: elasticsearch_single:9200 - ES_CLIENT_ADDRESS: elasticsearch_single:9200 - log.path: /logs + SERVER_ES_ADDRESS: elasticsearch_single:9200 JAVA_OPTS: -Xmx1g -Xms1g -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08 - networks: - ks volumes: @@ -63,15 +49,20 @@ services: elasticsearch_single: image: docker.io/library/elasticsearch:7.6.2 container_name: elasticsearch_single - ports: - - '9200:9200' - - '9300:9300' + restart: always + expose: + - 9200 + - 9300 +# 对外访问 +# ports: +# - '9200:9200' +# - '9300:9300' environment: TZ: Asia/Shanghai ES_JAVA_OPTS: -Xms512m -Xmx512m discovery.type: single-node - volumes: - - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data +# volumes: +# - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data networks: - ks @@ -79,6 +70,7 @@ services: kmysql: image: ks_mysql:1.0 container_name: kmysql + restart: always environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: admin2022_ diff --git a/km-dist/docker/knowstreaming-es/Dockerfile b/km-dist/docker/knowstreaming-es/Dockerfile deleted file mode 100644 index 6a6f6143f..000000000 --- a/km-dist/docker/knowstreaming-es/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM docker.io/library/elasticsearch:7.6.2 -LABEL author=haoqi6677 -#EXPOSE 9200 -#EXPOSE 9300 -#ARG INIT_SOURCE_FILE=./esinit/* -#COPY ${INIT_SOURCE_FILE} / \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index 021a592d3..05e28155f 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -1,10 +1,11 @@ FROM bitnami/java:11 -ARG JAVA_OPTS -ARG JAR_FILE=./jar/*.jar -ARG INIT_ES_FILE=./esinit/* +ENV JAR_FILE=./jar/*.jar +ENV INIT_ES_FILE=./esinit/* +ENV CONFIG_FILE=./conf/* COPY ${JAR_FILE} /app/app.jar COPY ${INIT_ES_FILE} / +COPY ${CONFIG_FILE} /conf/ ENTRYPOINT ["/bin/bash","/es.sh"] -CMD ["dumb-init","java","${JAVA_OPTS}", "-jar", "/app/app.jar"] +CMD ["/bin/bash","/es.sh"] #ENTRYPOINT java -jar /app/app.jar \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/conf/application.yml b/km-dist/docker/knowstreaming-manage/conf/application.yml new file mode 100644 index 000000000..80323cd0d --- /dev/null +++ b/km-dist/docker/knowstreaming-manage/conf/application.yml @@ -0,0 +1,107 @@ +server: + port: 80 # 服务端口 + tomcat: + accept-count: 1000 + max-connections: 10000 + +spring: + application: + name: know-streaming + profiles: + active: dev + main: + allow-bean-definition-overriding: true + jackson: + time-zone: GMT+8 + datasource: + know-streaming: # know-streaming 自身数据库的配置 + jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + username: SERVER_MYSQL_USER + password: SERVER_MYSQL_PASSWORD + driver-class-name: org.mariadb.jdbc.Driver + maximum-pool-size: 20 + idle-timeout: 30000 + connection-test-query: SELECT 1 + logi-job: # know-streaming 依赖的 logi-job 模块的数据库的配置,默认与 know-streaming 的数据库配置保持一致即可 + jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + username: SERVER_MYSQL_USER + password: SERVER_MYSQL_PASSWORD + driver-class-name: org.mariadb.jdbc.Driver + max-lifetime: 60000 + init-sql: true + init-thread-num: 20 + max-thread-num: 50 + log-expire: 3 # 日志保存天数,以天为单位 + app-name: know-streaming + claim-strategy: com.didiglobal.logi.job.core.consensual.RandomConsensual + logi-security: # know-streaming 依赖的 logi-security 模块的数据库的配置,默认与 know-streaming 的数据库配置保持一致即可 + jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true + username: SERVER_MYSQL_USER + password: SERVER_MYSQL_PASSWORD + driver-class-name: org.mariadb.jdbc.Driver + app-name: know-streaming + resource-extend-bean-name: myResourceExtendImpl + login-extend-bean-name: logiSecurityDefaultLoginExtendImpl + +logging: + config: classpath:logback-spring.xml + +# 线程池大小相关配置 +thread-pool: + scheduled: + thread-num: 2 # @Scheduled任务的线程池大小,默认是一个 + + collector: # 采集模块的配置 + future-util: # 采集模块线程池配置 + num: 3 # 线程池个数 + thread-num: 64 # 每个线程池核心线程数 + queue-size: 10000 # 每个线程池队列大小 + select-suitable-enable: true # 任务是否自动选择合适的线程池,非主要,可不修改 + suitable-queue-size: 1000 # 线程池理想的队列大小,非主要,可不修改 + + task: # 任务模块的配置 + metrics: # metrics采集任务配置 + thread-num: 18 # metrics采集任务线程池核心线程数 + queue-size: 180 # metrics采集任务线程池队列大小 + metadata: # metadata同步任务配置 + thread-num: 27 # metadata同步任务线程池核心线程数 + queue-size: 270 # metadata同步任务线程池队列大小 + common: # 剩余其他任务配置 + thread-num: 15 # 剩余其他任务线程池核心线程数 + queue-size: 150 # 剩余其他任务线程池队列大小 + + +# 客户端池大小相关配置 +client-pool: + kafka-consumer: + min-idle-client-num: 2 # 最小空闲客户端数 + max-idle-client-num: 20 # 最大空闲客户端数 + max-total-client-num: 20 # 最大客户端数 + borrow-timeout-unit-ms: 5000 # 租借超时时间,单位秒 + + +# ES客户端配置 +es: + client: + address: SERVER_ES_ADDRESS + client-cnt: 10 + io-thread-cnt: 2 + max-retry-cnt: 5 + +# 普罗米修斯指标导出相关配置 +management: + endpoints: + web: + base-path: /metrics + exposure: + include: '*' + health: + elasticsearch: + enabled: false + metrics: + export: + prometheus: + descriptions: true + enabled: true + tags: + application: know-streaming \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/es.sh b/km-dist/docker/knowstreaming-manage/esinit/es.sh index 9bd811bc3..8d5383a9a 100644 --- a/km-dist/docker/knowstreaming-manage/esinit/es.sh +++ b/km-dist/docker/knowstreaming-manage/esinit/es.sh @@ -1,2 +1,9 @@ /bin/bash /template.sh start -java ${JAVA_OPTS} -jar /app/app.jar \ No newline at end of file + +sed -i "s/SERVER_MYSQL_ADDRESS/${SERVER_MYSQL_ADDRESS}/g" /conf/application.yml +sed -i "s/SERVER_MYSQL_DB/${SERVER_MYSQL_DB}/g" /conf/application.yml +sed -i "s/SERVER_MYSQL_USER/${SERVER_MYSQL_USER}/g" /conf/application.yml +sed -i "s/SERVER_MYSQL_PASSWORD/${SERVER_MYSQL_PASSWORD}/g" /conf/application.yml +sed -i "s/SERVER_ES_ADDRESS/${SERVER_ES_ADDRESS}/g" /conf/application.yml + +java ${JAVA_OPTS} -jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/template.sh b/km-dist/docker/knowstreaming-manage/esinit/template.sh index bd69d1d10..430972794 100644 --- a/km-dist/docker/knowstreaming-manage/esinit/template.sh +++ b/km-dist/docker/knowstreaming-manage/esinit/template.sh @@ -1,17 +1,16 @@ -esAddrPort=${ES_CLIENT_ADDRESS} echo "Wait ElasticSearch Start..." while true do - curl -s --connect-timeout 10 -o /dev/null http://${esAddrPort}/_cat/nodes >> /dev/null 2>&1 + curl -s --connect-timeout 10 -o /dev/null http://${SERVER_ES_ADDRESS}/_cat/nodes >> /dev/null 2>&1 if [ "$?" != "0" ];then sleep 1s else - echo "ElasticSearch Start Success" + echo "ElasticSearch Start Initialize" break fi done -curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_broker_metric -d '{ +curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_broker_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_broker_metric*" @@ -113,7 +112,7 @@ curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' - "aliases" : { } }' -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_cluster_metric -d '{ +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_cluster_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_cluster_metric*" @@ -298,9 +297,9 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_group_metric -d '{ +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_group_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_group_metric*" @@ -373,9 +372,9 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_partition_metric -d '{ +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_partition_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_partition_metric*" @@ -439,9 +438,9 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_replication_metric -d '{ +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_replication_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_partition_metric*" @@ -528,9 +527,9 @@ PUT _template/ks_kafka_replication_metric } }, "aliases" : { } - }' + }' -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${esAddrPort}/_template/ks_kafka_topic_metric -d '{ +curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_topic_metric -d '{ "order" : 10, "index_patterns" : [ "ks_kafka_topic_metric*" @@ -645,17 +644,17 @@ curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: appl } }, "aliases" : { } - }' + }' -for i in `seq 6`; +for i in {0..6}; do logdate=_$(date -d "${i} day ago" +%Y-%m-%d) - curl -s --connect-timeout 10 -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_broker_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_cluster_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_group_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_partition_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_replication_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${esAddrPort}/ks_kafka_topic_metric${logdate} || \ + curl -s --connect-timeout 10 -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_broker_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_cluster_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_group_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_partition_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_replication_metric${logdate} && \ + curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_topic_metric${logdate} || \ exit 2 done diff --git a/km-dist/docker/knowstreaming-mysql/Dockerfile b/km-dist/docker/knowstreaming-mysql/Dockerfile index 1c5d8b9b1..edaf3ad8d 100644 --- a/km-dist/docker/knowstreaming-mysql/Dockerfile +++ b/km-dist/docker/knowstreaming-mysql/Dockerfile @@ -1,6 +1,6 @@ FROM mysql:5.7.39-oracle EXPOSE 3306 -ARG INIT_SOURCE_FILE=./sql/*.sql +ENV INIT_SOURCE_FILE=./sql/*.sql #RUN mkdir /data/mysql #RUN mkdir /var/lib/mysql-files COPY ${INIT_SOURCE_FILE} /docker-entrypoint-initdb.d/ From 792f8d939db6a71bb7991bc81f2f2f33d1843351 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Thu, 15 Sep 2022 15:06:19 +0800 Subject: [PATCH 08/53] =?UTF-8?q?1.=20=E6=9B=B4=E6=94=B9Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 11 ++++++++--- km-dist/docker/knowstreaming-manage/Dockerfile | 14 +++++++++----- .../{esinit => init}/ks_kafka_broker_metric | 0 .../{esinit => init}/ks_kafka_cluster_metric | 0 .../{esinit => init}/ks_kafka_group_metric | 0 .../{esinit => init}/ks_kafka_partition_metric | 0 .../{esinit => init}/ks_kafka_replication_metric | 0 .../{esinit => init}/ks_kafka_topic_metric | 0 .../{esinit/es.sh => init/start.sh} | 8 +++++++- .../{esinit => init}/template.sh | 0 km-dist/docker/knowstreaming-mysql/Dockerfile | 9 ++++++--- .../knowstreaming-mysql/{ => conf}/mysql.cnf | 0 km-dist/docker/knowstreaming-web/Dockerfile | 14 +++++++++++--- 13 files changed, 41 insertions(+), 15 deletions(-) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_broker_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_cluster_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_group_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_partition_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_replication_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/ks_kafka_topic_metric (100%) rename km-dist/docker/knowstreaming-manage/{esinit/es.sh => init/start.sh} (56%) rename km-dist/docker/knowstreaming-manage/{esinit => init}/template.sh (100%) rename km-dist/docker/knowstreaming-mysql/{ => conf}/mysql.cnf (100%) diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index 3e902498c..3ea2655d0 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -25,11 +25,12 @@ services: SERVER_ES_ADDRESS: elasticsearch_single:9200 - JAVA_OPTS: -Xmx1g -Xms1g -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08 + JAVA_OPTS: -Xmx1g -Xms1g networks: - ks - volumes: - - /Users/haoqi/Downloads/ks/manage/log:/logs +# 日志文件持久化路径 +# volumes: +# - /Users/haoqi/Downloads/ks/manage/log:/logs knowstreaming-ui: image: ks_ui:1.0 container_name: knowstreaming-ui @@ -61,6 +62,8 @@ services: TZ: Asia/Shanghai ES_JAVA_OPTS: -Xms512m -Xmx512m discovery.type: single-node +# 数据文件持久化路径 +# 记录实时指标信息 # volumes: # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data networks: @@ -79,6 +82,8 @@ services: - ks expose: - 3306 +# 数据文件持久化路径 +# 记录添加的集群基本信息 volumes: - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index 05e28155f..e22f25d42 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -1,11 +1,15 @@ -FROM bitnami/java:11 +FROM amd64/openjdk:17.0.2 + +LABEL org.opencontainers.image.authors="haoqi123" + +EXPOSE 80 + ENV JAR_FILE=./jar/*.jar -ENV INIT_ES_FILE=./esinit/* +ENV INIT_ES_FILE=./init/* ENV CONFIG_FILE=./conf/* COPY ${JAR_FILE} /app/app.jar COPY ${INIT_ES_FILE} / COPY ${CONFIG_FILE} /conf/ -ENTRYPOINT ["/bin/bash","/es.sh"] -CMD ["/bin/bash","/es.sh"] -#ENTRYPOINT java -jar /app/app.jar \ No newline at end of file +ENTRYPOINT ["/bin/bash","/start.sh"] +CMD ["/bin/bash","/start.sh"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_broker_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_broker_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_broker_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_cluster_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_cluster_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_cluster_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_group_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_group_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_group_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_partition_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_partition_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_partition_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_replication_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_replication_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_replication_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric b/km-dist/docker/knowstreaming-manage/init/ks_kafka_topic_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/ks_kafka_topic_metric rename to km-dist/docker/knowstreaming-manage/init/ks_kafka_topic_metric diff --git a/km-dist/docker/knowstreaming-manage/esinit/es.sh b/km-dist/docker/knowstreaming-manage/init/start.sh similarity index 56% rename from km-dist/docker/knowstreaming-manage/esinit/es.sh rename to km-dist/docker/knowstreaming-manage/init/start.sh index 8d5383a9a..db322fab3 100644 --- a/km-dist/docker/knowstreaming-manage/esinit/es.sh +++ b/km-dist/docker/knowstreaming-manage/init/start.sh @@ -6,4 +6,10 @@ sed -i "s/SERVER_MYSQL_USER/${SERVER_MYSQL_USER}/g" /conf/application.yml sed -i "s/SERVER_MYSQL_PASSWORD/${SERVER_MYSQL_PASSWORD}/g" /conf/application.yml sed -i "s/SERVER_ES_ADDRESS/${SERVER_ES_ADDRESS}/g" /conf/application.yml -java ${JAVA_OPTS} -jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file +java -server ${JAVA_OPTS} \ +-XX:+UseStringDeduplication \ +-Dfile.encoding=UTF-8 \ +-Djava.security.egd=file:/dev/./urandom \ +-Duser.timezone=GMT+08 \ +-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs -XX:ErrorFile=/logs/jvm/hs_err_pid%p.log \ +-jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/esinit/template.sh b/km-dist/docker/knowstreaming-manage/init/template.sh similarity index 100% rename from km-dist/docker/knowstreaming-manage/esinit/template.sh rename to km-dist/docker/knowstreaming-manage/init/template.sh diff --git a/km-dist/docker/knowstreaming-mysql/Dockerfile b/km-dist/docker/knowstreaming-mysql/Dockerfile index edaf3ad8d..4e6917c9e 100644 --- a/km-dist/docker/knowstreaming-mysql/Dockerfile +++ b/km-dist/docker/knowstreaming-mysql/Dockerfile @@ -1,7 +1,10 @@ FROM mysql:5.7.39-oracle + +LABEL org.opencontainers.image.authors="haoqi123" + EXPOSE 3306 + ENV INIT_SOURCE_FILE=./sql/*.sql -#RUN mkdir /data/mysql -#RUN mkdir /var/lib/mysql-files +ENV MYSQL_CNF_FILE=./conf/*.cnf COPY ${INIT_SOURCE_FILE} /docker-entrypoint-initdb.d/ -COPY ./*.cnf /etc/mysql/conf.d/ \ No newline at end of file +COPY ${MYSQL_CNF_FILE} /etc/mysql/conf.d/ \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/mysql.cnf b/km-dist/docker/knowstreaming-mysql/conf/mysql.cnf similarity index 100% rename from km-dist/docker/knowstreaming-mysql/mysql.cnf rename to km-dist/docker/knowstreaming-mysql/conf/mysql.cnf diff --git a/km-dist/docker/knowstreaming-web/Dockerfile b/km-dist/docker/knowstreaming-web/Dockerfile index f1bb3a193..4ec52a71b 100644 --- a/km-dist/docker/knowstreaming-web/Dockerfile +++ b/km-dist/docker/knowstreaming-web/Dockerfile @@ -1,6 +1,14 @@ FROM docker.io/library/nginx:1.23.1 + +LABEL org.opencontainers.image.authors="haoqi123" + WORKDIR /pub EXPOSE 80 -COPY ./conf/*.conf /etc/nginx/conf.d/default.conf -COPY ./pub /pub -# HEALTHCHECK --interval=30s --timeout=30s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 \ No newline at end of file + +ENV HTML_FILE=./pub +ENV NGINX_CONF=./conf/*.conf + +COPY ${NGINX_CONF} /etc/nginx/conf.d/default.conf +COPY ${HTML_FILE} /pub + +HEALTHCHECK --interval=60s --timeout=60s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 \ No newline at end of file From 27d1b92690be3762466ae9bbbc7d64c4c8d45c7f Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Thu, 15 Sep 2022 16:22:51 +0800 Subject: [PATCH 09/53] =?UTF-8?q?1.=20=E6=B7=BB=E5=8A=A0init=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=EF=BC=8C=E5=8F=AA=E7=94=A8=E4=BA=8E=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96es=E7=B4=A2=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 17 ++++++++++++++--- km-dist/docker/knowstreaming-init/Dockerfile | 9 +++++++++ .../init/ks_kafka_broker_metric | 0 .../init/ks_kafka_cluster_metric | 0 .../init/ks_kafka_group_metric | 0 .../init/ks_kafka_partition_metric | 0 .../init/ks_kafka_replication_metric | 0 .../init/ks_kafka_topic_metric | 0 .../init/template.sh | 0 km-dist/docker/knowstreaming-manage/Dockerfile | 7 +++---- .../docker/knowstreaming-manage/init/start.sh | 2 -- 11 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 km-dist/docker/knowstreaming-init/Dockerfile rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_broker_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_cluster_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_group_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_partition_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_replication_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/ks_kafka_topic_metric (100%) rename km-dist/docker/{knowstreaming-manage => knowstreaming-init}/init/template.sh (100%) diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index 3ea2655d0..446129ec5 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -68,7 +68,18 @@ services: # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data networks: - ks - + esinit: + image: esinit:1.0 + container_name: esinit + depends_on: + - elasticsearch_single + links: + - elasticsearch_single + environment: + TZ: Asia/Shanghai + SERVER_ES_ADDRESS: elasticsearch_single:9200 + networks: + - ks kmysql: image: ks_mysql:1.0 @@ -84,8 +95,8 @@ services: - 3306 # 数据文件持久化路径 # 记录添加的集群基本信息 - volumes: - - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql +# volumes: +# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql networks: ks: diff --git a/km-dist/docker/knowstreaming-init/Dockerfile b/km-dist/docker/knowstreaming-init/Dockerfile new file mode 100644 index 000000000..8f47558cc --- /dev/null +++ b/km-dist/docker/knowstreaming-init/Dockerfile @@ -0,0 +1,9 @@ +FROM debian:stable-20220912-slim +LABEL org.opencontainers.image.authors="haoqi123" +ENV INIT_ES_FILE=./init/* +COPY ${INIT_ES_FILE} / + +RUN apt-get update \ + && apt-get install -y curl + +ENTRYPOINT ["/bin/bash","/template.sh","start"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_broker_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_broker_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_cluster_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_cluster_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_group_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_group_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_partition_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_partition_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_replication_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_replication_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric diff --git a/km-dist/docker/knowstreaming-manage/init/ks_kafka_topic_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/ks_kafka_topic_metric rename to km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric diff --git a/km-dist/docker/knowstreaming-manage/init/template.sh b/km-dist/docker/knowstreaming-init/init/template.sh similarity index 100% rename from km-dist/docker/knowstreaming-manage/init/template.sh rename to km-dist/docker/knowstreaming-init/init/template.sh diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index e22f25d42..c73fd07da 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -5,11 +5,10 @@ LABEL org.opencontainers.image.authors="haoqi123" EXPOSE 80 ENV JAR_FILE=./jar/*.jar -ENV INIT_ES_FILE=./init/* +ENV INIT_FILE=./init/* ENV CONFIG_FILE=./conf/* COPY ${JAR_FILE} /app/app.jar -COPY ${INIT_ES_FILE} / +COPY ${INIT_FILE} / COPY ${CONFIG_FILE} /conf/ -ENTRYPOINT ["/bin/bash","/start.sh"] -CMD ["/bin/bash","/start.sh"] \ No newline at end of file +ENTRYPOINT ["/bin/bash","/start.sh"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/init/start.sh b/km-dist/docker/knowstreaming-manage/init/start.sh index db322fab3..9741d7cf0 100644 --- a/km-dist/docker/knowstreaming-manage/init/start.sh +++ b/km-dist/docker/knowstreaming-manage/init/start.sh @@ -1,5 +1,3 @@ -/bin/bash /template.sh start - sed -i "s/SERVER_MYSQL_ADDRESS/${SERVER_MYSQL_ADDRESS}/g" /conf/application.yml sed -i "s/SERVER_MYSQL_DB/${SERVER_MYSQL_DB}/g" /conf/application.yml sed -i "s/SERVER_MYSQL_USER/${SERVER_MYSQL_USER}/g" /conf/application.yml From 474daf752d03d2aaa1329aa04dabe434bbd13111 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 15 Sep 2022 16:54:52 +0800 Subject: [PATCH 10/53] bump version to 3.0.0-beta.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0a21cf839..e30add738 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ - 3.0.0-beta.2 + 3.0.0-beta.3 8 8 From 0d9a6702c13e44f37cc9c6dfc0a3ee0e8c74adeb Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Thu, 15 Sep 2022 17:13:58 +0800 Subject: [PATCH 11/53] =?UTF-8?q?1.=20=E6=9B=B4=E6=94=B9es=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E8=84=9A=E6=9C=AC=E8=BE=93=E5=87=BA=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E4=B8=BA=E9=87=8D=E5=AE=9A=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../init/ks_kafka_broker_metric | 102 ----- .../init/ks_kafka_cluster_metric | 187 --------- .../init/ks_kafka_group_metric | 75 ---- .../init/ks_kafka_partition_metric | 66 ---- .../init/ks_kafka_replication_metric | 23 -- .../init/ks_kafka_topic_metric | 117 ------ .../knowstreaming-init/init/template.sh | 2 +- .../knowstreaming-mysql/sql/ddl-ks-km.sql | 356 ------------------ .../knowstreaming-mysql/sql/ddl-logi-job.sql | 119 ------ .../sql/ddl-logi-security.sql | 205 ---------- .../knowstreaming-mysql/sql/dml-ks-km.sql | 7 - .../knowstreaming-mysql/sql/dml-logi.sql | 98 ----- 12 files changed, 1 insertion(+), 1356 deletions(-) delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric delete mode 100644 km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric delete mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql delete mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql delete mode 100644 km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql delete mode 100644 km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql delete mode 100644 km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric deleted file mode 100644 index 78933a4d9..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_broker_metric +++ /dev/null @@ -1,102 +0,0 @@ -PUT _template/ks_kafka_broker_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_broker_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "NetworkProcessorAvgIdle" : { - "type" : "float" - }, - "UnderReplicatedPartitions" : { - "type" : "float" - }, - "BytesIn_min_15" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "RequestHandlerAvgIdle" : { - "type" : "float" - }, - "connectionsCount" : { - "type" : "float" - }, - "BytesIn_min_5" : { - "type" : "float" - }, - "HealthScore" : { - "type" : "float" - }, - "BytesOut" : { - "type" : "float" - }, - "BytesOut_min_15" : { - "type" : "float" - }, - "BytesIn" : { - "type" : "float" - }, - "BytesOut_min_5" : { - "type" : "float" - }, - "TotalRequestQueueSize" : { - "type" : "float" - }, - "MessagesIn" : { - "type" : "float" - }, - "TotalProduceRequests" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - }, - "TotalResponseQueueSize" : { - "type" : "float" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric deleted file mode 100644 index 76d51cbd8..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_cluster_metric +++ /dev/null @@ -1,187 +0,0 @@ -PUT _template/ks_kafka_cluster_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_cluster_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "Connections" : { - "type" : "double" - }, - "BytesIn_min_15" : { - "type" : "double" - }, - "PartitionURP" : { - "type" : "double" - }, - "HealthScore_Topics" : { - "type" : "double" - }, - "EventQueueSize" : { - "type" : "double" - }, - "ActiveControllerCount" : { - "type" : "double" - }, - "GroupDeads" : { - "type" : "double" - }, - "BytesIn_min_5" : { - "type" : "double" - }, - "HealthCheckTotal_Topics" : { - "type" : "double" - }, - "Partitions" : { - "type" : "double" - }, - "BytesOut" : { - "type" : "double" - }, - "Groups" : { - "type" : "double" - }, - "BytesOut_min_15" : { - "type" : "double" - }, - "TotalRequestQueueSize" : { - "type" : "double" - }, - "HealthCheckPassed_Groups" : { - "type" : "double" - }, - "TotalProduceRequests" : { - "type" : "double" - }, - "HealthCheckPassed" : { - "type" : "double" - }, - "TotalLogSize" : { - "type" : "double" - }, - "GroupEmptys" : { - "type" : "double" - }, - "PartitionNoLeader" : { - "type" : "double" - }, - "HealthScore_Brokers" : { - "type" : "double" - }, - "Messages" : { - "type" : "double" - }, - "Topics" : { - "type" : "double" - }, - "PartitionMinISR_E" : { - "type" : "double" - }, - "HealthCheckTotal" : { - "type" : "double" - }, - "Brokers" : { - "type" : "double" - }, - "Replicas" : { - "type" : "double" - }, - "HealthCheckTotal_Groups" : { - "type" : "double" - }, - "GroupRebalances" : { - "type" : "double" - }, - "MessageIn" : { - "type" : "double" - }, - "HealthScore" : { - "type" : "double" - }, - "HealthCheckPassed_Topics" : { - "type" : "double" - }, - "HealthCheckTotal_Brokers" : { - "type" : "double" - }, - "PartitionMinISR_S" : { - "type" : "double" - }, - "BytesIn" : { - "type" : "double" - }, - "BytesOut_min_5" : { - "type" : "double" - }, - "GroupActives" : { - "type" : "double" - }, - "MessagesIn" : { - "type" : "double" - }, - "GroupReBalances" : { - "type" : "double" - }, - "HealthCheckPassed_Brokers" : { - "type" : "double" - }, - "HealthScore_Groups" : { - "type" : "double" - }, - "TotalResponseQueueSize" : { - "type" : "double" - }, - "Zookeepers" : { - "type" : "double" - }, - "LeaderMessages" : { - "type" : "double" - }, - "HealthScore_Cluster" : { - "type" : "double" - }, - "HealthCheckPassed_Cluster" : { - "type" : "double" - }, - "HealthCheckTotal_Cluster" : { - "type" : "double" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "type" : "date" - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric deleted file mode 100644 index 9fe7008b6..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_group_metric +++ /dev/null @@ -1,75 +0,0 @@ -PUT _template/ks_kafka_group_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_group_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "group" : { - "type" : "keyword" - }, - "partitionId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "topic" : { - "type" : "keyword" - }, - "metrics" : { - "properties" : { - "HealthScore" : { - "type" : "float" - }, - "Lag" : { - "type" : "float" - }, - "OffsetConsumed" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - } - } - }, - "groupMetric" : { - "type" : "keyword" - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric deleted file mode 100644 index 2538eba31..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_partition_metric +++ /dev/null @@ -1,66 +0,0 @@ -PUT _template/ks_kafka_partition_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_partition_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "partitionId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "topic" : { - "type" : "keyword" - }, - "metrics" : { - "properties" : { - "LogStartOffset" : { - "type" : "float" - }, - "Messages" : { - "type" : "float" - }, - "LogEndOffset" : { - "type" : "float" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric deleted file mode 100644 index b7beda547..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_replication_metric +++ /dev/null @@ -1,23 +0,0 @@ -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric b/km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric deleted file mode 100644 index a2456dc61..000000000 --- a/km-dist/docker/knowstreaming-init/init/ks_kafka_topic_metric +++ /dev/null @@ -1,117 +0,0 @@ -PUT _template/ks_kafka_topic_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_topic_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "topic" : { - "type" : "keyword" - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "BytesIn_min_15" : { - "type" : "float" - }, - "Messages" : { - "type" : "float" - }, - "BytesRejected" : { - "type" : "float" - }, - "PartitionURP" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "ReplicationCount" : { - "type" : "float" - }, - "ReplicationBytesOut" : { - "type" : "float" - }, - "ReplicationBytesIn" : { - "type" : "float" - }, - "FailedFetchRequests" : { - "type" : "float" - }, - "BytesIn_min_5" : { - "type" : "float" - }, - "HealthScore" : { - "type" : "float" - }, - "LogSize" : { - "type" : "float" - }, - "BytesOut" : { - "type" : "float" - }, - "BytesOut_min_15" : { - "type" : "float" - }, - "FailedProduceRequests" : { - "type" : "float" - }, - "BytesIn" : { - "type" : "float" - }, - "BytesOut_min_5" : { - "type" : "float" - }, - "MessagesIn" : { - "type" : "float" - }, - "TotalProduceRequests" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - } - } - }, - "brokerAgg" : { - "type" : "keyword" - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - } \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/template.sh b/km-dist/docker/knowstreaming-init/init/template.sh index 430972794..2b091e101 100644 --- a/km-dist/docker/knowstreaming-init/init/template.sh +++ b/km-dist/docker/knowstreaming-init/init/template.sh @@ -1,7 +1,7 @@ echo "Wait ElasticSearch Start..." while true do - curl -s --connect-timeout 10 -o /dev/null http://${SERVER_ES_ADDRESS}/_cat/nodes >> /dev/null 2>&1 + curl -s --connect-timeout 10 -o /dev/null http://${SERVER_ES_ADDRESS}/_cat/nodes > /dev/null 2>&1 if [ "$?" != "0" ];then sleep 1s else diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql deleted file mode 100644 index 506969175..000000000 --- a/km-dist/docker/knowstreaming-mysql/sql/ddl-ks-km.sql +++ /dev/null @@ -1,356 +0,0 @@ --- KS-KM自身的SQL,KS-KM依赖 Logi-Job 和 Logi-Security,因此另外两个ddl sql文件也需要执行 - -DROP TABLE IF EXISTS `ks_km_broker`; -CREATE TABLE `ks_km_broker` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '物理集群ID', - `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', - `host` varchar(128) NOT NULL DEFAULT '' COMMENT 'broker主机名', - `port` int(16) NOT NULL DEFAULT '-1' COMMENT 'broker端口', - `jmx_port` int(16) NOT NULL DEFAULT '-1' COMMENT 'Jmx端口', - `start_timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT '启动时间', - `rack` varchar(128) NOT NULL DEFAULT '' COMMENT 'Rack信息', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '状态: 1存活,0未存活', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - `endpoint_map` varchar(1024) NOT NULL DEFAULT '' COMMENT '监听信息', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_phy_id_broker_id` (`cluster_phy_id`,`broker_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker信息表'; - - - -DROP TABLE IF EXISTS `ks_km_broker_config`; -CREATE TABLE `ks_km_broker_config` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', - `config_name` varchar(192) NOT NULL DEFAULT '' COMMENT '配置名称', - `config_value` text COMMENT '配置值', - `diff_type` int(16) NOT NULL DEFAULT '-1' COMMENT '差异类型', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_broker_name` (`cluster_phy_id`,`broker_id`,`config_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Broker配置信息表'; - - - -DROP TABLE IF EXISTS `ks_km_cluster_balance_job`; -CREATE TABLE `ks_km_cluster_balance_job` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `brokers` varchar(1024) NOT NULL DEFAULT '' COMMENT '均衡节点', - `topic_black_list` varchar(4096) NOT NULL DEFAULT '' COMMENT 'topic黑名单', - `type` int(16) NOT NULL DEFAULT '0' COMMENT '1:周期均衡,2:立即均衡', - `balance_interval_json` text COMMENT '均衡区间详情', - `metric_calculation_period` int(16) NOT NULL DEFAULT '0' COMMENT '指标计算周期,单位分钟', - `reassignment_json` text COMMENT '迁移脚本', - `parallel_num` int(16) NOT NULL DEFAULT '0' COMMENT '任务并行数', - `execution_strategy` int(16) NOT NULL DEFAULT '0' COMMENT '执行策略, 1:优先最大副本,2:优先最小副本', - `throttle_unit_b` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', - `total_reassign_size` double NOT NULL DEFAULT '0' COMMENT '总迁移大小', - `total_reassign_replica_num` int(16) NOT NULL DEFAULT '0' COMMENT '总迁移副本数', - `move_in_topic_list` varchar(4096) NOT NULL DEFAULT '' COMMENT '移入topic', - `broker_balance_detail` text COMMENT '节点均衡详情', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态 1:进行中,2:准备,3,成功,4:失败,5:取消', - `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', - `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务开始时间', - `finished_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务完成时间', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - `description` text COMMENT '备注', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群均衡任务'; - - - -DROP TABLE IF EXISTS `ks_km_cluster_balance_job_config`; -CREATE TABLE `ks_km_cluster_balance_job_config` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `brokers` varchar(256) NOT NULL DEFAULT '' COMMENT '均衡节点', - `topic_black_list` varchar(4096) NOT NULL DEFAULT '' COMMENT 'topic黑名单', - `task_cron` varchar(64) NOT NULL DEFAULT '' COMMENT '任务周期', - `balance_interval_json` text COMMENT '均衡区间详情', - `metric_calculation_period` int(16) NOT NULL DEFAULT '0' COMMENT '指标计算周期,单位分钟', - `reassignment_json` text COMMENT '迁移脚本', - `parallel_num` int(16) NOT NULL DEFAULT '0' COMMENT '任务并行数', - `execution_strategy` int(16) NOT NULL DEFAULT '0' COMMENT '执行策略, 1:优先最大副本,2:优先最小副本', - `throttle_unit_b` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', - `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态 0:未开启,1:开启', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群均衡任务'; - - - -DROP TABLE IF EXISTS `ks_km_cluster_balance_reassign`; -CREATE TABLE `ks_km_cluster_balance_reassign` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `job_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '父任务ID', - `cluster_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', - `original_broker_ids` text COMMENT '源BrokerId列表', - `reassign_broker_ids` text COMMENT '目标BrokerId列表', - `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务开始时间', - `finished_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务完成时间', - `extend_data` text COMMENT '扩展数据', - `status` int(16) NOT NULL DEFAULT '2' COMMENT '任务状态', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='集群平衡迁移详情'; - - - -DROP TABLE IF EXISTS `ks_km_group_member`; -CREATE TABLE `ks_km_group_member` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Topic名称', - `group_name` varchar(192) NOT NULL DEFAULT '' COMMENT 'Group名称', - `kafka_user` varchar(192) NOT NULL DEFAULT '' COMMENT 'Kafka用户', - `state` varchar(64) NOT NULL DEFAULT '' COMMENT '状态', - `member_count` int(11) NOT NULL DEFAULT '0' COMMENT '成员数', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_topic_group` (`cluster_phy_id`,`topic_name`,`group_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='GroupMember信息表'; - - - -DROP TABLE IF EXISTS `ks_km_health_check_result`; -CREATE TABLE `ks_km_health_check_result` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `dimension` int(11) NOT NULL DEFAULT '0' COMMENT '检查维度(0:未知,1:Cluster,2:Broker,3:Topic,4:Group)', - `config_name` varchar(192) NOT NULL DEFAULT '' COMMENT '配置名', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '物理集群ID', - `res_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', - `passed` int(11) NOT NULL DEFAULT '0' COMMENT '检查通过(0:未通过,1:通过)', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_dimension_config_cluster_res` (`dimension`,`config_name`,`cluster_phy_id`,`res_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='健康检查结果'; - - - -DROP TABLE IF EXISTS `ks_km_job`; -CREATE TABLE `ks_km_job` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', - `job_name` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务名称', - `job_type` tinyint(10) NOT NULL COMMENT '任务类型', - `job_status` tinyint(10) NOT NULL COMMENT '任务状态', - `job_data` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务的详细信息', - `job_desc` varchar(1024) NOT NULL DEFAULT '' COMMENT '任务描述', - `cluster_id` int(11) NOT NULL COMMENT 'kafka集群id', - `target` varchar(8192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '任务执行对象', - `running_status` varchar(256) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '任务运行详细状态(json), Success:7 Fail:1 Doing:2', - `creator` varchar(45) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '创建者', - `plan_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '计划执行时间', - `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '实际执行时间', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `index_cluster_id` (`cluster_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Job信息'; - - - -DROP TABLE IF EXISTS `ks_km_kafka_acl`; -CREATE TABLE `ks_km_kafka_acl` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `principal` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Kafka用户', - `operation` int(11) NOT NULL DEFAULT '0' COMMENT '操作', - `permission_type` int(11) NOT NULL DEFAULT '0' COMMENT '权限类型(0:未知,1:任意,2:拒绝,3:允许)', - `host` varchar(192) NOT NULL DEFAULT '127.0.0.1' COMMENT '机器', - `resource_type` int(11) NOT NULL DEFAULT '0' COMMENT '资源类型(0:未知,1:任意,2:Topic,3:Group,4:Cluster,5:事务,6:Token)', - `resource_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', - `pattern_type` int(11) NOT NULL COMMENT '匹配类型(0:未知,1:任意,2:Match,3:Literal,4:prefixed)', - `unique_field` varchar(1024) NOT NULL DEFAULT '' COMMENT '唯一字段,由cluster_phy_id等字段组成', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_uniq_field` (`unique_field`), - KEY `idx_cluster_phy_id_principal_res_name` (`cluster_phy_id`,`principal`,`resource_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='ACL信息'; - - - -DROP TABLE IF EXISTS `ks_km_kafka_change_record`; -CREATE TABLE `ks_km_kafka_change_record` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `res_type` int(11) NOT NULL DEFAULT '-1' COMMENT '资源类型', - `res_name` varchar(192) NOT NULL DEFAULT '' COMMENT '资源名称', - `operate_type` int(11) NOT NULL DEFAULT '-1' COMMENT '操作类型', - `operate_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间', - `unique_field` varchar(1024) NOT NULL DEFAULT '' COMMENT '唯一键字段', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `unique_field` (`unique_field`), - KEY `idx_cluster_phy_id` (`cluster_phy_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Kafka变更记录表'; - - - -DROP TABLE IF EXISTS `ks_km_kafka_controller`; -CREATE TABLE `ks_km_kafka_controller` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群id', - `broker_id` int(16) NOT NULL DEFAULT '-1' COMMENT 'brokerId', - `broker_host` varchar(256) NOT NULL DEFAULT '' COMMENT '主机名', - `broker_rack` varchar(256) NOT NULL DEFAULT '' COMMENT 'BrokerRack信息', - `timestamp` bigint(20) NOT NULL DEFAULT '-1' COMMENT 'controller变更时间,-1表示未存活', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_broker_timestamp` (`cluster_phy_id`,`broker_id`,`timestamp`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='controller记录表'; - - - -DROP TABLE IF EXISTS `ks_km_kafka_user`; -CREATE TABLE `ks_km_kafka_user` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '名称', - `token` varchar(8192) NOT NULL DEFAULT '' COMMENT '密钥', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_phy_id_name` (`cluster_phy_id`,`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Kafka-User信息表'; - - - -DROP TABLE IF EXISTS `ks_km_partition`; -CREATE TABLE `ks_km_partition` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', - `leader_broker_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区的LeaderBroker,-1表示无Leader', - `in_sync_replicas` varchar(512) NOT NULL DEFAULT '-1' COMMENT 'ISR', - `assign_replicas` varchar(512) NOT NULL DEFAULT '-1' COMMENT 'AR', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_topic_partition` (`cluster_phy_id`,`topic_name`,`partition_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Partition信息表'; - - - -DROP TABLE IF EXISTS `ks_km_physical_cluster`; -CREATE TABLE `ks_km_physical_cluster` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '集群id', - `name` varchar(128) NOT NULL DEFAULT '' COMMENT '集群名称', - `zookeeper` varchar(2048) NOT NULL DEFAULT '' COMMENT 'zk地址', - `bootstrap_servers` varchar(2048) NOT NULL DEFAULT '' COMMENT 'server地址', - `kafka_version` varchar(32) NOT NULL DEFAULT '' COMMENT 'kafka版本', - `client_properties` text COMMENT 'Kafka客户端配置', - `jmx_properties` text COMMENT 'JMX配置', - `description` text COMMENT '备注', - `auth_type` int(11) NOT NULL DEFAULT '0' COMMENT '认证类型,-1未知,0:无认证,', - `run_state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '运行状态, 0表示未监控, 1监控中,有ZK,2:监控中,无ZK', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '接入时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_name` (`name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='物理集群信息表'; - - - -DROP TABLE IF EXISTS `ks_km_platform_cluster_config`; -CREATE TABLE `ks_km_platform_cluster_config` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', - `cluster_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `value_group` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项组', - `value_name` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项名字', - `value` text COMMENT '配置项的值', - `description` text COMMENT '备注', - `operator` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '操作者', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_id_group_name` (`cluster_id`,`value_group`,`value_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='KS平台集群配置'; - - - -DROP TABLE IF EXISTS `ks_km_reassign_job`; -CREATE TABLE `ks_km_reassign_job` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `reassignment_json` text COMMENT '迁移计划', - `throttle_unit_byte` bigint(20) NOT NULL DEFAULT '0' COMMENT '限流值', - `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务开始时间', - `finished_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务完成时间', - `creator` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人', - `description` text COMMENT '备注', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='迁移Job信息'; - - - -DROP TABLE IF EXISTS `ks_km_reassign_sub_job`; -CREATE TABLE `ks_km_reassign_sub_job` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `job_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '父任务ID', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '集群id', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `partition_id` int(11) NOT NULL DEFAULT '-1' COMMENT '分区ID', - `original_broker_ids` text COMMENT '源BrokerId列表', - `reassign_broker_ids` text COMMENT '目标BrokerId列表', - `start_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务开始时间', - `finished_time` timestamp NOT NULL DEFAULT '1971-1-1 00:00:00' COMMENT '任务完成时间', - `extend_data` text COMMENT '扩展数据', - `status` int(16) NOT NULL DEFAULT '0' COMMENT '任务状态', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '任务创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '任务修改时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='迁移SubJob信息'; - - - -DROP TABLE IF EXISTS `ks_km_topic`; -CREATE TABLE `ks_km_topic` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `cluster_phy_id` bigint(20) NOT NULL DEFAULT '-1' COMMENT '集群ID', - `topic_name` varchar(192) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT 'Topic名称', - `replica_num` int(11) NOT NULL DEFAULT '-1' COMMENT '副本数', - `partition_num` int(11) NOT NULL DEFAULT '-1' COMMENT '分区数', - `broker_ids` varchar(2048) NOT NULL DEFAULT '' COMMENT 'BrokerId列表', - `partition_map` text COMMENT '分区分布信息', - `retention_ms` bigint(20) NOT NULL DEFAULT '-2' COMMENT '保存时间,-2:未知,-1:无限制,>=0对应时间,单位ms', - `type` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'Topic类型,默认0,0:普通,1:Kafka内部', - `description` text COMMENT '备注信息', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间(尽量与Topic实际创建时间一致)', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间(尽量与Topic实际创建时间一致)', - PRIMARY KEY (`id`), - UNIQUE KEY `uniq_cluster_phy_id_topic_name` (`cluster_phy_id`,`topic_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Topic信息表'; - - -DROP TABLE IF EXISTS `ks_km_app_node`; -CREATE TABLE `ks_km_app_node` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', - `host_name` varchar(256) NOT NULL DEFAULT '' COMMENT 'host', - `ip` varchar(256) NOT NULL DEFAULT '' COMMENT 'ip', - `beat_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'node 的心跳时间', - `app_name` varchar(128) NOT NULL DEFAULT '' COMMENT 'km 集群的应用名', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - KEY `idx_app_host` (`app_name`,`host_name`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='km集群部署的node信息'; diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql deleted file mode 100644 index 3ba229832..000000000 --- a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-job.sql +++ /dev/null @@ -1,119 +0,0 @@ --- Logi-Job模块的sql,安装KS-KM需要执行该sql - - -DROP TABLE IF EXISTS `logi_job`; -CREATE TABLE `logi_job` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `job_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', - `task_code` varchar(255) NOT NULL DEFAULT '' COMMENT '任务code', - `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', - `try_times` int(10) NOT NULL DEFAULT '0' COMMENT '第几次重试', - `worker_code` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', - `start_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '开始时间', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `job_code` (`job_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在执行的job信息'; - - - -DROP TABLE IF EXISTS `logi_job_log`; -CREATE TABLE `logi_job_log` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `job_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'job taskCode', - `task_code` varchar(255) NOT NULL DEFAULT '' COMMENT '任务code', - `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', - `task_desc` varchar(255) NOT NULL DEFAULT '' COMMENT '任务描述', - `task_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '任务id', - `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', - `try_times` int(10) NOT NULL DEFAULT '0' COMMENT '第几次重试', - `worker_code` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器', - `worker_ip` varchar(200) NOT NULL DEFAULT '' COMMENT '执行机器ip', - `start_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '开始时间', - `end_time` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '结束时间', - `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行结果 1成功 2失败 3取消', - `error` text NOT NULL COMMENT '错误信息', - `result` text NOT NULL COMMENT '执行结果', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `index_job_code` (`job_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='job执行历史日志'; - - - -DROP TABLE IF EXISTS `logi_task`; -CREATE TABLE `logi_task` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `task_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', - `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '名称', - `task_desc` varchar(1000) NOT NULL DEFAULT '' COMMENT '任务描述', - `cron` varchar(100) NOT NULL DEFAULT '' COMMENT 'cron 表达式', - `class_name` varchar(255) NOT NULL DEFAULT '' COMMENT '类的全限定名', - `params` varchar(1000) NOT NULL DEFAULT '' COMMENT '执行参数 map 形式{key1:value1,key2:value2}', - `retry_times` int(10) NOT NULL DEFAULT '0' COMMENT '允许重试次数', - `last_fire_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上次执行时间', - `timeout` bigint(20) NOT NULL DEFAULT '0' COMMENT '超时 毫秒', - `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1等待 2运行中 3暂停', - `sub_task_codes` varchar(1000) NOT NULL DEFAULT '' COMMENT '子任务code列表,逗号分隔', - `consensual` varchar(200) NOT NULL DEFAULT '' COMMENT '执行策略', - `owner` varchar(200) NOT NULL DEFAULT '' COMMENT '责任人', - `task_worker_str` varchar(3000) NOT NULL DEFAULT '' COMMENT '机器执行信息', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `task_code` (`task_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='任务信息'; - - - -DROP TABLE IF EXISTS `logi_task_lock`; -CREATE TABLE `logi_task_lock` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `task_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'task taskCode', - `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', - `expire_time` bigint(20) NOT NULL DEFAULT '0' COMMENT '过期时间', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='任务锁'; - - - -DROP TABLE IF EXISTS `logi_worker`; -CREATE TABLE `logi_worker` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', - `worker_name` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker名', - `ip` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker的ip', - `cpu` int(11) NOT NULL DEFAULT '0' COMMENT 'cpu数量', - `cpu_used` double NOT NULL DEFAULT '0' COMMENT 'cpu使用率', - `memory` double NOT NULL DEFAULT '0' COMMENT '内存,以M为单位', - `memory_used` double NOT NULL DEFAULT '0' COMMENT '内存使用率', - `jvm_memory` double NOT NULL DEFAULT '0' COMMENT 'jvm堆大小,以M为单位', - `jvm_memory_used` double NOT NULL DEFAULT '0' COMMENT 'jvm堆使用率', - `job_num` int(10) NOT NULL DEFAULT '0' COMMENT '正在执行job数', - `heartbeat` datetime DEFAULT '1971-01-01 00:00:00' COMMENT '心跳时间', - `app_name` varchar(100) NOT NULL DEFAULT '' COMMENT '被调度的应用名称', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `worker_code` (`worker_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='worker信息'; - - - -DROP TABLE IF EXISTS `logi_worker_blacklist`; -CREATE TABLE `logi_worker_blacklist` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `worker_code` varchar(100) NOT NULL DEFAULT '' COMMENT 'worker taskCode', - `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - UNIQUE KEY `worker_code` (`worker_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='worker黑名单列表'; diff --git a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql b/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql deleted file mode 100644 index 7efa1f3ac..000000000 --- a/km-dist/docker/knowstreaming-mysql/sql/ddl-logi-security.sql +++ /dev/null @@ -1,205 +0,0 @@ -#-----------------------创建表----------------------- -DROP TABLE IF EXISTS `logi_security_dept`; -CREATE TABLE `logi_security_dept` -( - id int auto_increment primary key, - dept_name varchar(10) not null comment '部门名', - parent_id int not null comment '父部门id', - leaf tinyint(1) not null comment '是否叶子部门', - level tinyint not null comment 'parentId为0的层级为1', - description varchar(20) null comment '描述', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '部门信息表'; - -DROP TABLE IF EXISTS `logi_security_message`; -CREATE TABLE `logi_security_message` -( - id int auto_increment primary key, - title varchar(60) not null comment '标题', - content varchar(256) null comment '内容', - read_tag tinyint(1) default 0 null comment '是否已读', - oplog_id int null comment '操作日志id', - user_id int null comment '这条消息属于哪个用户的,用户id', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '消息中心'; - -DROP TABLE IF EXISTS `logi_security_oplog`; -CREATE TABLE `logi_security_oplog` -( - id int auto_increment primary key, - operator_ip varchar(20) not null comment '操作者ip', - operator varchar(20) null comment '操作者账号', - operate_page varchar(16) not null default '' comment '操作页面', - operate_type varchar(16) not null comment '操作类型', - target_type varchar(16) not null comment '对象分类', - target varchar(128) not null comment '操作对象', - operation_methods varchar(20) not null default '' comment '操作方式', - detail text null comment '日志详情', - create_time timestamp default CURRENT_TIMESTAMP null, - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '操作日志'; - -DROP TABLE IF EXISTS `logi_security_oplog_extra`; -CREATE TABLE `logi_security_oplog_extra` -( - id int auto_increment primary key, - info varchar(16) null comment '信息', - type tinyint not null comment '哪种信息:1:操作页面;2:操作类型;3:对象分类', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '操作日志信息(操作页面、操作类型、对象分类)'; - -DROP TABLE IF EXISTS `logi_security_permission`; -CREATE TABLE `logi_security_permission` -( - id int auto_increment primary key, - permission_name varchar(40) not null comment '权限名字', - parent_id int not null comment '父权限id', - leaf tinyint(1) not null comment '是否叶子权限点(具体的操作)', - level tinyint not null comment '权限点的层级(parentId为0的层级为1)', - description varchar(64) null comment '权限点描述', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '权限表'; - -DROP TABLE IF EXISTS `logi_security_project`; -CREATE TABLE `logi_security_project` -( - id int auto_increment comment '项目id' primary key, - project_code varchar(128) not null comment '项目编号', - project_name varchar(128) not null comment '项目名', - description varchar(512) default '' not null comment '项目描述', - dept_id int not null comment '部门id', - running tinyint(1) default 1 not null comment '启用 or 停用', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '项目表'; - -DROP TABLE IF EXISTS `logi_security_resource_type`; -CREATE TABLE `logi_security_resource_type` -( - id int auto_increment primary key, - type_name varchar(16) null comment '资源类型名', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '资源类型表'; - -DROP TABLE IF EXISTS `logi_security_role`; -CREATE TABLE `logi_security_role` -( - id int auto_increment primary key, - role_code varchar(128) not null comment '角色编号', - role_name varchar(128) not null comment '名称', - description varchar(128) null comment '角色描述', - last_reviser varchar(30) null comment '最后修改人', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '角色信息'; - -DROP TABLE IF EXISTS `logi_security_role_permission`; -CREATE TABLE `logi_security_role_permission` -( - id int auto_increment primary key, - role_id int not null comment '角色id', - permission_id int not null comment '权限id', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '角色权限表(只保留叶子权限与角色关系)'; - -DROP TABLE IF EXISTS `logi_security_user`; -CREATE TABLE `logi_security_user` -( - id int auto_increment primary key, - user_name varchar(64) not null comment '用户账号', - pw varchar(2048) not null comment '用户密码', - salt char(5) default '' not null comment '密码盐', - real_name varchar(128) default '' not null comment '真实姓名', - phone char(11) default '' not null comment 'mobile', - email varchar(30) default '' not null comment 'email', - dept_id int null comment '所属部门id', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - create_time timestamp default CURRENT_TIMESTAMP null comment '注册时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户信息'; - -DROP TABLE IF EXISTS `logi_security_user_project`; -CREATE TABLE `logi_security_user_project` -( - id int auto_increment primary key, - user_id int not null comment '用户id', - project_id int not null comment '项目id', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户项目关系表(项目负责人)'; - -DROP TABLE IF EXISTS `logi_security_user_resource`; -CREATE TABLE `logi_security_user_resource` -( - id int auto_increment primary key, - user_id int not null comment '用户id', - project_id int not null comment '资源所属项目id', - resource_type_id int not null comment '资源类别id', - resource_id int not null comment '资源id', - control_level tinyint not null comment '管理级别:1(查看权限)2(管理权限)', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户和资源关系表'; - -DROP TABLE IF EXISTS `logi_security_user_role`; -CREATE TABLE `logi_security_user_role` -( - id int auto_increment primary key, - user_id int not null comment '用户id', - role_id int not null comment '角色id', - create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间', - update_time timestamp default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间', - is_delete tinyint(1) default 0 not null comment '逻辑删除', - app_name varchar(16) null comment '应用名称' -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 comment '用户角色表'; - --- ---------------------------- --- Table structure for logi_config --- ---------------------------- -DROP TABLE IF EXISTS `logi_security_config`; -CREATE TABLE `logi_security_config` -( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键自增', - `value_group` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项组', - `value_name` varchar(100) NOT NULL DEFAULT '' COMMENT '配置项名字', - `value` text COMMENT '配置项的值', - `edit` int(4) NOT NULL DEFAULT '1' COMMENT '是否可以编辑 1 不可编辑(程序获取) 2 可编辑', - `status` int(4) NOT NULL DEFAULT '1' COMMENT '1 正常 2 禁用', - `memo` varchar(1000) NOT NULL DEFAULT '' COMMENT '备注', - `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - `is_delete` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除', - `app_name` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '应用名称', - `operator` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '操作者', - PRIMARY KEY (`id`), - KEY `idx_group_name` (`value_group`,`value_name`) -) ENGINE=InnoDB AUTO_INCREMENT=1592 DEFAULT CHARSET=utf8 COMMENT='logi配置项'; \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql b/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql deleted file mode 100644 index 2d354a879..000000000 --- a/km-dist/docker/knowstreaming-mysql/sql/dml-ks-km.sql +++ /dev/null @@ -1,7 +0,0 @@ --- 检查检查配置 -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_CLUSTER_NO_CONTROLLER','{ \"value\": 1, \"weight\": 30 } ','集群Controller数正常','know-streaming'); -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_BROKER_REQUEST_QUEUE_FULL','{ \"value\": 10, \"weight\": 20 } ','Broker-RequestQueueSize指标','know-streaming'); -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_BROKER_NETWORK_PROCESSOR_AVG_IDLE_TOO_LOW','{ \"value\": 0.8, \"weight\": 20 } ','Broker-NetworkProcessorAvgIdlePercent指标','know-streaming'); -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_GROUP_RE_BALANCE_TOO_FREQUENTLY','{\n \"latestMinutes\": 10,\n \"detectedTimes\": 8,\n \"weight\": 10\n}\n','Group的re-balance频率','know-streaming'); -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_TOPIC_NO_LEADER','{ \"value\": 1, \"weight\": 10 } ','Topic 无Leader数','know-stream'); -INSERT INTO `ks_km_platform_cluster_config` (`cluster_id`,`value_group`,`value_name`,`value`,`description`,`operator`) VALUES (-1,'HEALTH','HC_TOPIC_UNDER_REPLICA_TOO_LONG','{ \"latestMinutes\": 10, \"detectedTimes\": 8, \"weight\": 10 } ','Topic 未同步持续时间','know-streaming'); diff --git a/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql b/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql deleted file mode 100644 index 927a0bccf..000000000 --- a/km-dist/docker/knowstreaming-mysql/sql/dml-logi.sql +++ /dev/null @@ -1,98 +0,0 @@ --- 初始化权限 -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1593', '多集群管理', '0', '0', '1', '多集群管理', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1595', '系统管理', '0', '0', '1', '系统管理', '0', 'know-streaming'); - --- 多集群管理权限 -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1597', '接入集群', '1593', '1', '2', '接入集群', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1599', '删除集群', '1593', '1', '2', '删除集群', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1601', 'Cluster-修改集群信息', '1593', '1', '2', 'Cluster-修改集群信息', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1603', 'Cluster-修改健康规则', '1593', '1', '2', 'Cluster-修改健康规则', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1605', 'Broker-修改Broker配置', '1593', '1', '2', 'Broker-修改Broker配置', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1607', 'Topic-新增Topic', '1593', '1', '2', 'Topic-新增Topic', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1609', 'Topic-扩分区', '1593', '1', '2', 'Topic-扩分区', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1611', 'Topic-删除Topic', '1593', '1', '2', 'Topic-扩分区', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1613', 'Topic-重置Offset', '1593', '1', '2', 'Topic-重置Offset', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1615', 'Topic-修改Topic配置', '1593', '1', '2', 'Topic-修改Topic配置', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1617', 'Consumers-重置Offset', '1593', '1', '2', 'Consumers-重置Offset', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1619', 'Test-Producer', '1593', '1', '2', 'Test-Producer', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1621', 'Test-Consumer', '1593', '1', '2', 'Test-Consumer', '0', 'know-streaming'); - --- 系统管理权限 -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1623', '配置管理-新增配置', '1595', '1', '2', '配置管理-新增配置', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1625', '配置管理-编辑配置', '1595', '1', '2', '配置管理-编辑配置', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1627', '配置管理-删除配置', '1595', '1', '2', '配置管理-删除配置', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1629', '用户管理-新增人员', '1595', '1', '2', '用户管理-新增人员', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1631', '用户管理-编辑人员', '1595', '1', '2', '用户管理-编辑人员', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1633', '用户管理-修改人员密码', '1595', '1', '2', '用户管理-修改人员密码', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1635', '用户管理-删除人员', '1595', '1', '2', '用户管理-删除人员', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1637', '用户管理-新增角色', '1595', '1', '2', '用户管理-新增角色', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1639', '用户管理-编辑角色', '1595', '1', '2', '用户管理-编辑角色', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1641', '用户管理-分配用户角色', '1595', '1', '2', '用户管理-分配用户角色', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('1643', '用户管理-删除角色', '1595', '1', '2', '用户管理-删除角色', '0', 'know-streaming'); - --- 多集群管理权限2022-09-06新增 -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2000', '多集群管理查看', '1593', '1', '2', '多集群管理查看', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2002', 'Topic-迁移副本', '1593', '1', '2', 'Topic-迁移副本', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2004', 'Topic-扩缩副本', '1593', '1', '2', 'Topic-扩缩副本', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2006', 'Cluster-LoadReBalance-周期均衡', '1593', '1', '2', 'Cluster-LoadReBalance-周期均衡', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2008', 'Cluster-LoadReBalance-立即均衡', '1593', '1', '2', 'Cluster-LoadReBalance-立即均衡', '0', 'know-streaming'); -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('2010', 'Cluster-LoadReBalance-设置集群规格', '1593', '1', '2', 'Cluster-LoadReBalance-设置集群规格', '0', 'know-streaming'); - - --- 系统管理权限2022-09-06新增 -INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `leaf`, `level`, `description`, `is_delete`, `app_name`) VALUES ('3000', '系统管理查看', '1595', '1', '2', '系统管理查看', '0', 'know-streaming'); - - - - - - --- 初始化用户 -INSERT INTO `logi_security_user` (`id`, `user_name`, `pw`, `real_name`, `is_delete`, `app_name`) VALUES ('1', 'admin', 'V1ZkU2RHRlhOSGxOUkVsNVdETjBRVlp0Y0V0T1IwWnlaVEZ6YWxGRVJrRkpNVEU1VTJwYVUySkhlRzlSU0RBOWUwQldha28wWVd0N1d5TkFNa0FqWFgxS05sSnNiR2hBZlE9PXtAVmpKNGFre1sjQDNAI119SjZSbGxoQH0=Mv{#cdRgJ45Lqx}3IubEW87!==', '系统管理员', '0', 'know-streaming'); - --- 初始化角色 -INSERT INTO `logi_security_role` (`id`, `role_code`, `role_name`, `description`, `last_reviser`, `is_delete`, `app_name`) VALUES ('1677', 'r15477137', '管理员角色', '包含系统所有权限', 'admin', '0', 'know-streaming'); - --- 初始化角色权限关系 -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1597', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1599', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1601', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1603', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1605', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1607', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1609', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1611', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1613', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1615', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1617', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1619', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1621', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1593', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1623', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1625', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1627', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1629', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1631', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1633', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1635', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1637', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1639', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1641', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1643', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '1595', '0', 'know-streaming'); - -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2000', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2002', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2004', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2006', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2008', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '2010', '0', 'know-streaming'); -INSERT INTO `logi_security_role_permission` (`role_id`, `permission_id`, `is_delete`, `app_name`) VALUES ('1677', '3000', '0', 'know-streaming'); - --- 初始化 用户角色关系 -INSERT INTO `logi_security_user_role` (`id`, `user_id`, `role_id`, `is_delete`, `app_name`) VALUES ('1', '1', '1677', '0', 'know-streaming'); - -INSERT INTO `logi_security_config` -(`value_group`,`value_name`,`value`,`edit`,`status`,`memo`,`is_delete`,`app_name`,`operator`) -VALUES -('SECURITY.LOGIN','SECURITY.TRICK_USERS','[\n \"admin\"\n]',1,1,'允许跳过登录的用户',0,'know-streaming','admin'); \ No newline at end of file From d4f416de144fce95eea4556b5bfdadf68176b746 Mon Sep 17 00:00:00 2001 From: pokemeng Date: Fri, 16 Sep 2022 11:34:03 +0800 Subject: [PATCH 12/53] fix: adjust os judgment method with uname --- bin/startup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/startup.sh b/bin/startup.sh index 8081f2ddc..cbde7c56b 100644 --- a/bin/startup.sh +++ b/bin/startup.sh @@ -9,7 +9,7 @@ error_exit () [ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME if [ -z "$JAVA_HOME" ]; then - if $darwin; then + if [ "Darwin" = "$(uname -s)" ]; then if [ -x '/usr/libexec/java_home' ] ; then export JAVA_HOME=`/usr/libexec/java_home` From 85e3f2a94693cae690bfeac951bb99a1b67e6431 Mon Sep 17 00:00:00 2001 From: wangdongfang-aden <49342405+wangdongfang-aden@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:40:34 +0800 Subject: [PATCH 13/53] helm update 3.0.0-beta.2 --- km-dist/helm/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/helm/Chart.yaml b/km-dist/helm/Chart.yaml index bd9b7d985..4b764af46 100644 --- a/km-dist/helm/Chart.yaml +++ b/km-dist/helm/Chart.yaml @@ -4,13 +4,13 @@ description: knowstreaming-manager Helm chart type: application -version: 0.1.3 +version: 0.1.4 maintainers: - email: didicloud@didiglobal.com name: didicloud -appVersion: "3.0.0-beta.1" +appVersion: "3.0.0-beta.2" dependencies: - name: knowstreaming-web From a6f1fe07b351d3341a6ec73c09aca1aff4e17069 Mon Sep 17 00:00:00 2001 From: wangdongfang-aden <49342405+wangdongfang-aden@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:41:02 +0800 Subject: [PATCH 14/53] helm update 3.0.0-beta.2 --- km-dist/helm/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/helm/values.yaml b/km-dist/helm/values.yaml index 036f5cc88..2c422f613 100644 --- a/km-dist/helm/values.yaml +++ b/km-dist/helm/values.yaml @@ -3,7 +3,7 @@ replicaCount: 2 image: repository: knowstreaming/knowstreaming-manager pullPolicy: IfNotPresent - tag: "0.1.0" + tag: "0.2.0" imagePullSecrets: [] nameOverride: "" @@ -73,7 +73,7 @@ knowstreaming-web: image: repository: knowstreaming/knowstreaming-ui pullPolicy: IfNotPresent - tag: "0.1.0" + tag: "0.2.0" service: type: NodePort From 12b5acd073dc8356955a467e4aac1a6db244ea98 Mon Sep 17 00:00:00 2001 From: wangdongfang-aden <49342405+wangdongfang-aden@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:41:40 +0800 Subject: [PATCH 15/53] helm update 3.0.0-beta.2 --- km-dist/helm/charts/ksmysql/templates/statefulset.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/km-dist/helm/charts/ksmysql/templates/statefulset.yaml b/km-dist/helm/charts/ksmysql/templates/statefulset.yaml index 15ab2858d..a536f2f8c 100644 --- a/km-dist/helm/charts/ksmysql/templates/statefulset.yaml +++ b/km-dist/helm/charts/ksmysql/templates/statefulset.yaml @@ -21,7 +21,7 @@ spec: {{- include "ksmysql.selectorLabels" . | nindent 8 }} spec: containers: - - image: knowstreaming/knowstreaming-mysql:0.1.0 + - image: knowstreaming/knowstreaming-mysql:0.2.0 name: {{ .Chart.Name }} env: - name: MYSQL_DATABASE From fe6ddebc493a99f7f4bd764ae149896d7379286d Mon Sep 17 00:00:00 2001 From: wyb <1164642317@qq.com> Date: Fri, 16 Sep 2022 14:41:45 +0800 Subject: [PATCH 16/53] =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...07\347\272\247\346\211\213\345\206\214.md" | 25 ++++++++----------- ...77\347\224\250\346\211\213\345\206\214.md" | 2 +- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git "a/docs/install_guide/\347\211\210\346\234\254\345\215\207\347\272\247\346\211\213\345\206\214.md" "b/docs/install_guide/\347\211\210\346\234\254\345\215\207\347\272\247\346\211\213\345\206\214.md" index 48417bb4b..2af3f69a1 100644 --- "a/docs/install_guide/\347\211\210\346\234\254\345\215\207\347\272\247\346\211\213\345\206\214.md" +++ "b/docs/install_guide/\347\211\210\346\234\254\345\215\207\347\272\247\346\211\213\345\206\214.md" @@ -40,8 +40,7 @@ thread-pool: ``` - -**SQL变更** +**SQL 变更** ```sql -- 多集群管理权限2022-09-06新增 @@ -80,12 +79,11 @@ ALTER TABLE `logi_security_oplog` ### 6.2.2、升级至 `v3.0.0-beta.1`版本 - -**SQL变更** +**SQL 变更** 1、在`ks_km_broker`表增加了一个监听信息字段。 -2、为`logi_security_oplog`表operation_methods字段设置默认值''。 -因此需要执行下面的sql对数据库表进行更新。 +2、为`logi_security_oplog`表 operation_methods 字段设置默认值''。 +因此需要执行下面的 sql 对数据库表进行更新。 ```sql ALTER TABLE `ks_km_broker` @@ -98,7 +96,6 @@ ALTER COLUMN `operation_methods` set default ''; --- - ### 6.2.3、`2.x`版本 升级至 `v3.0.0-beta.0`版本 **升级步骤:** @@ -123,14 +120,14 @@ ALTER COLUMN `operation_methods` set default ''; UPDATE ks_km_topic INNER JOIN (SELECT - topic.cluster_id AS cluster_id, - topic.topic_name AS topic_name, - topic.description AS description + topic.cluster_id AS cluster_id, + topic.topic_name AS topic_name, + topic.description AS description FROM topic WHERE description != '' ) AS t - ON ks_km_topic.cluster_phy_id = t.cluster_id - AND ks_km_topic.topic_name = t.topic_name - AND ks_km_topic.id > 0 -SET ks_km_topic.description = t.description; +ON ks_km_topic.cluster_phy_id = t.cluster_id + AND ks_km_topic.topic_name = t.topic_name + AND ks_km_topic.id > 0 + SET ks_km_topic.description = t.description; ``` \ No newline at end of file diff --git "a/docs/user_guide/\347\224\250\346\210\267\344\275\277\347\224\250\346\211\213\345\206\214.md" "b/docs/user_guide/\347\224\250\346\210\267\344\275\277\347\224\250\346\211\213\345\206\214.md" index f2efc936c..6179cb3b9 100644 --- "a/docs/user_guide/\347\224\250\346\210\267\344\275\277\347\224\250\346\211\213\345\206\214.md" +++ "b/docs/user_guide/\347\224\250\346\210\267\344\275\277\347\224\250\346\211\213\345\206\214.md" @@ -11,7 +11,7 @@ 下面是用户第一次使用我们产品的典型体验路径: -![text](http://img-ys011.didistatic.com/static/dc2img/do1_YehqxqmsVaqU5gf3XphI) +![text](http://img-ys011.didistatic.com/static/dc2img/do1_qgqPsAY46sZeBaPUCwXY) ## 5.3、常用功能 From 68f76f2daf3d9f7f0e83f7ed4bfbde7b38ad2c58 Mon Sep 17 00:00:00 2001 From: wangdongfang-aden <49342405+wangdongfang-aden@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:42:34 +0800 Subject: [PATCH 17/53] helm update 3.0.0-beta.2 --- km-dist/helm/charts/elasticsearch/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/helm/charts/elasticsearch/values.yaml b/km-dist/helm/charts/elasticsearch/values.yaml index fbbc599d8..e325ec689 100644 --- a/km-dist/helm/charts/elasticsearch/values.yaml +++ b/km-dist/helm/charts/elasticsearch/values.yaml @@ -173,8 +173,8 @@ antiAffinityTopologyKey: "kubernetes.io/hostname" # Hard means that by default pods will only be scheduled if there are enough nodes for them # and that they will never end up on the same node. Setting this to soft will do this "best effort" -antiAffinity: "hard" - +antiAffinity: "" +#antiAffinity: "hard" # This is the node affinity settings as defined in # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#node-affinity-beta-feature nodeAffinity: {} From 7288874d72e40883152fc9dabc4201ab46da4e81 Mon Sep 17 00:00:00 2001 From: wangdongfang-aden <49342405+wangdongfang-aden@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:44:14 +0800 Subject: [PATCH 18/53] helm update 3.0.0-beta.2 --- km-dist/helm/templates/configmap.yaml | 32 +++++++++++++++------------ 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/km-dist/helm/templates/configmap.yaml b/km-dist/helm/templates/configmap.yaml index ae09f6b9d..6395aff13 100644 --- a/km-dist/helm/templates/configmap.yaml +++ b/km-dist/helm/templates/configmap.yaml @@ -71,6 +71,7 @@ data: driver-class-name: org.mariadb.jdbc.Driver app-name: know-streaming resource-extend-bean-name: myResourceExtendImpl + login-extend-bean-name: logiSecurityDefaultLoginExtendImpl logging: config: classpath:logback-spring.xml @@ -85,11 +86,16 @@ data: queue-size: 10000 # 每个线程池队列大小 select-suitable-enable: true # 任务是否自动选择合适的线程池,非主要,可不修改 suitable-queue-size: 1000 # 线程池理想的队列大小,非主要,可不修改 - task: # 任务模块的配置 - heaven: # 采集任务配置 - thread-num: 20 # 采集任务线程池核心线程数 - queue-size: 1000 # 采集任务线程池队列大小 - + task: # 任务模块的配置 + metrics: # metrics采集任务配置 + thread-num: 18 # metrics采集任务线程池核心线程数 + queue-size: 180 # metrics采集任务线程池队列大小 + metadata: # metadata同步任务配置 + thread-num: 27 # metadata同步任务线程池核心线程数 + queue-size: 270 # metadata同步任务线程池队列大小 + common: # 剩余其他任务配置 + thread-num: 15 # 剩余其他任务线程池核心线程数 + queue-size: 150 # 剩余其他任务线程池队列大小 client-pool: @@ -99,17 +105,16 @@ data: max-total-client-num: 20 # 最大客户端数 borrow-timeout-unit-ms: 5000 # 租借超时时间,单位秒 + es: + client: {{ if .Values.elasticsearch.enabled }} - es.client.address: elasticsearch-master:9200 - #es.client.address: {{ .Release.Name }}-elasticsearch:9200 + address: elasticsearch-master:9200 {{- else }} - es.client.address: {{ .Values.elasticsearch.esClientAddress }}:{{ .Values.elasticsearch.esProt }} + address: {{ .Values.elasticsearch.esClientAddress }}:{{ .Values.elasticsearch.esProt }} {{- end }} - # es.client.pass: knowstreaming-manager - # 集群自动均衡相关配置 - cluster-balance: - ignored-topics: - time-second: 300 + client-cnt: 10 + io-thread-cnt: 2 + max-retry-cnt: 5 # 普罗米修斯指标导出相关配置 management: @@ -158,4 +163,3 @@ data: curl -s -o /dev/null -X PUT http://${esaddr}:${port}/ks_kafka_topic_metric${logdate} || \ exit 2 done - From 227479f695944612c05ba15ddbb4c0bc74fdae86 Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Fri, 16 Sep 2022 15:13:18 +0800 Subject: [PATCH 19/53] =?UTF-8?q?1.=20=E4=BF=AE=E6=94=B9dockerfile=202.=20?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8=E9=85=8D=E7=BD=AE=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 4 +- km-dist/docker/knowstreaming-init/Dockerfile | 10 +-- .../docker/knowstreaming-manage/Dockerfile | 38 ++++++-- km-dist/docker/knowstreaming-mysql/Dockerfile | 4 +- km-dist/docker/knowstreaming-web/Dockerfile | 90 +++++++++++++++++-- .../knowstreaming-web/conf/knowStreaming.conf | 46 ---------- 6 files changed, 119 insertions(+), 73 deletions(-) delete mode 100644 km-dist/docker/knowstreaming-web/conf/knowStreaming.conf diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index 446129ec5..62d153246 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -3,7 +3,7 @@ version: "3" services: knowstreaming-manager: - image: ks_manage:1.0 + image: km_manage:1.1 container_name: knowstreaming-manager privileged: true restart: always @@ -32,7 +32,7 @@ services: # volumes: # - /Users/haoqi/Downloads/ks/manage/log:/logs knowstreaming-ui: - image: ks_ui:1.0 + image: km:1.0 container_name: knowstreaming-ui restart: always ports: diff --git a/km-dist/docker/knowstreaming-init/Dockerfile b/km-dist/docker/knowstreaming-init/Dockerfile index 8f47558cc..8dfec0a53 100644 --- a/km-dist/docker/knowstreaming-init/Dockerfile +++ b/km-dist/docker/knowstreaming-init/Dockerfile @@ -1,9 +1,7 @@ -FROM debian:stable-20220912-slim +FROM centos:7.9.2009 LABEL org.opencontainers.image.authors="haoqi123" -ENV INIT_ES_FILE=./init/* +ARG INIT_ES_FILE=./init/* COPY ${INIT_ES_FILE} / +ENV TZ=Asia/Shanghai -RUN apt-get update \ - && apt-get install -y curl - -ENTRYPOINT ["/bin/bash","/template.sh","start"] \ No newline at end of file +ENTRYPOINT ["/bin/sh","/template.sh","start"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index c73fd07da..fbfc2edfb 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -1,14 +1,36 @@ -FROM amd64/openjdk:17.0.2 +FROM docker.io/amd64/eclipse-temurin:17.0.4.1_1-jdk-centos7 -LABEL org.opencontainers.image.authors="haoqi123" +LABEL maintainer="haoqi123 <1148648445@qq.com>" -EXPOSE 80 +WORKDIR /knowstreaming + +ARG VERSION_MAVEN=3.6.3 +ARG VERSION_KM=v3.0.0-beta.2 +ARG INIT_FILE=./init/* +ARG CONFIG_FILE=./conf/* -ENV JAR_FILE=./jar/*.jar -ENV INIT_FILE=./init/* -ENV CONFIG_FILE=./conf/* -COPY ${JAR_FILE} /app/app.jar COPY ${INIT_FILE} / COPY ${CONFIG_FILE} /conf/ -ENTRYPOINT ["/bin/bash","/start.sh"] \ No newline at end of file +# SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN yum install -y git + +RUN curl -fsSLO --compressed "https://dlcdn.apache.org/maven/maven-3/${VERSION_MAVEN}/binaries/apache-maven-${VERSION_MAVEN}-bin.tar.gz" \ + && mkdir maven/ \ + && tar -zxf "apache-maven-${VERSION_MAVEN}-bin.tar.gz" -C maven/ --strip-components=1 --no-same-owner \ + && rm -rf /knowstreaming/*.tar.gz \ + && ln -s /knowstreaming/maven/bin/mvn /usr/local/bin/mvn \ +# && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/${VERSION_KM}.zip \ + && git clone https://github.com/didi/KnowStreaming.git \ +# && unzip -o -q master.zip \ + && cd KnowStreaming && git checkout ${VERSION_KM} \ + && sed -i "/km-console/d" ./pom.xml \ + && mvn -U clean package -Dmaven.test.skip=true \ + && cd / \ + && mv /knowstreaming/KnowStreaming/km-rest/target/ks-km.jar /app/app.jar \ + && rm -rf /knowstreaming/* /usr/local/bin/mvn \ + && yum erase -y git && yum clean all \ + && rm -rf `pwd`/.m2 /tmp/* + +ENTRYPOINT ["/bin/bash","/start.sh"] diff --git a/km-dist/docker/knowstreaming-mysql/Dockerfile b/km-dist/docker/knowstreaming-mysql/Dockerfile index 4e6917c9e..95720f050 100644 --- a/km-dist/docker/knowstreaming-mysql/Dockerfile +++ b/km-dist/docker/knowstreaming-mysql/Dockerfile @@ -4,7 +4,7 @@ LABEL org.opencontainers.image.authors="haoqi123" EXPOSE 3306 -ENV INIT_SOURCE_FILE=./sql/*.sql -ENV MYSQL_CNF_FILE=./conf/*.cnf +ARG INIT_SOURCE_FILE=./sql/*.sql +ARG MYSQL_CNF_FILE=./conf/*.cnf COPY ${INIT_SOURCE_FILE} /docker-entrypoint-initdb.d/ COPY ${MYSQL_CNF_FILE} /etc/mysql/conf.d/ \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-web/Dockerfile b/km-dist/docker/knowstreaming-web/Dockerfile index 4ec52a71b..ef7e6b780 100644 --- a/km-dist/docker/knowstreaming-web/Dockerfile +++ b/km-dist/docker/knowstreaming-web/Dockerfile @@ -1,14 +1,86 @@ -FROM docker.io/library/nginx:1.23.1 +FROM docker.io/amd64/nginx:1.22 -LABEL org.opencontainers.image.authors="haoqi123" +LABEL maintainer="haoqi123 <1148648445@qq.com>" -WORKDIR /pub -EXPOSE 80 +WORKDIR /knowstreaming -ENV HTML_FILE=./pub -ENV NGINX_CONF=./conf/*.conf +ARG VERSION_NODE=v14.20.0 +ARG VERSION_KM=v3.0.0-beta.2 -COPY ${NGINX_CONF} /etc/nginx/conf.d/default.conf -COPY ${HTML_FILE} /pub +# SHELL ["/bin/bash", "-o", "pipefail", "-c"] -HEALTHCHECK --interval=60s --timeout=60s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 \ No newline at end of file +RUN apt update \ + && apt install -y git unzip + +RUN echo 'server { \ + listen 80; \ + server_name localhost; \ + gzip on; \ + gzip_buffers 16 8k; \ + gzip_comp_level 4; \ + gzip_http_version 1.0; \ + gzip_min_length 1280; \ + gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xml+rss application/json application/javascript text/*; \ + gzip_vary on; \ + root /pub; \ + location / { \ + root /pub; \ + if ($request_filename ~* .*\.(?:htm|html|json)$) { \ + add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; \ + } \ + try_files $uri /layout/index.html; \ + } \ + location ~* \.(json)$ { \ + add_header Cache-Control no-cache; \ + } \ + location @kmfallback { \ + } \ + #location ~ ^/(clusters|config|cluster|login) { \ + # rewrite ^.*$ /; \ + #} \ + location ~ ^/ks-km/api/v3 { \ + #rewrite ^/ks-km/api/v3/(.*)$ /ks-km/ks-km/api/v3/$1 break; \ + proxy_pass http://knowstreaming-manager; \ + #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; \ + #proxy_cookie_path /ks-km/ /; \ + #proxy_set_header Host $host; \ + #proxy_set_header Referer $http_referer; \ + #proxy_set_header Cookie $http_cookie; \ + #proxy_set_header X-Real-Ip $remote_addr; \ + #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; \ + } \ + location ~ ^/logi-security/api/v1 { \ + #rewrite ^/logi-security/api/v1/(.*)$ /ks-km/logi-security/api/v1/$1 break; \ + proxy_pass http://knowstreaming-manager; \ + #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; \ + } \ + location ~ ^/(401|403|404|500){ \ + rewrite ^.*$ /; \ + } \ + }' > /etc/nginx/conf.d/default.conf + +RUN curl -fsSLO --compressed "https://npm.taobao.org/mirrors/node/${VERSION_NODE}/node-${VERSION_NODE}-linux-x64.tar.gz" \ + && mkdir node/ \ + && tar -zxf "node-${VERSION_NODE}-linux-x64.tar.gz" -C node/ --strip-components=1 --no-same-owner \ + && rm -rf /knowstreaming/*.tar.gz \ + && ln -s /knowstreaming/node/bin/node /usr/local/bin/node \ + && ln -s /knowstreaming/node/bin/npm /usr/local/bin/npm \ + && npm config set strict-ssl false \ + && npm config set registry https://registry.npm.taobao.org \ + && npm info underscore \ + && node --version \ + && npm --version \ + && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/${VERSION_KM}.zip \ + && unzip -o -q master.zip \ + && cd KnowStreaming-master/km-console \ + && npm install -g lerna && npm run i && npm run build \ + && mv /knowstreaming/KnowStreaming-master/km-rest/src/main/resources/templates /pub \ + && npm uninstall -g lerna \ + && cd / \ + && rm -rf /knowstreaming/* /usr/local/bin/node /usr/local/bin/npm \ + && apt remove -y git unzip && apt autoremove -y && apt remove --purge --auto-remove -y \ + && rm -rf /var/lib/apt/lists/* /tmp /root/.npm + +#ENTRYPOINT ["ls", "/ks_ui/km-console"] + +#CMD ["nginx", "-g", "daemon off;"] diff --git a/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf b/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf deleted file mode 100644 index 9f5007ffe..000000000 --- a/km-dist/docker/knowstreaming-web/conf/knowStreaming.conf +++ /dev/null @@ -1,46 +0,0 @@ -server { - listen 80; - server_name localhost; - gzip on; - gzip_buffers 16 8k; - gzip_comp_level 4; - gzip_http_version 1.0; - gzip_min_length 1280; - gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xml+rss application/json application/javascript text/*; - gzip_vary on; - root /pub; - location / { - root /pub; - if ($request_filename ~* .*\.(?:htm|html|json)$) { - add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; - } - try_files $uri /layout/index.html; - } - location ~* \.(json)$ { - add_header Cache-Control no-cache; - } - location @kmfallback { - } - #location ~ ^/(clusters|config|cluster|login) { - # rewrite ^.*$ /; - #} - location ~ ^/ks-km/api/v3 { - #rewrite ^/ks-km/api/v3/(.*)$ /ks-km/ks-km/api/v3/$1 break; - proxy_pass http://knowstreaming-manager; - #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; - #proxy_cookie_path /ks-km/ /; - #proxy_set_header Host $host; - #proxy_set_header Referer $http_referer; - #proxy_set_header Cookie $http_cookie; - #proxy_set_header X-Real-Ip $remote_addr; - #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } - location ~ ^/logi-security/api/v1 { - #rewrite ^/logi-security/api/v1/(.*)$ /ks-km/logi-security/api/v1/$1 break; - proxy_pass http://knowstreaming-manager; - #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; - } - location ~ ^/(401|403|404|500){ - rewrite ^.*$ /; - } - } \ No newline at end of file From f7f90aeaaa5fd376ddd127ac81757c303bef7928 Mon Sep 17 00:00:00 2001 From: Peng <71620349+PenceXie@users.noreply.github.com> Date: Fri, 16 Sep 2022 15:18:29 +0800 Subject: [PATCH 20/53] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5830ffe3..afff4b6cd 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ - 无需侵入改造 `Apache Kafka` ,一键便能纳管 `0.10.x` ~ `3.x.x` 众多版本的Kafka,包括 `ZK` 或 `Raft` 运行模式的版本,同时在兼容架构上具备良好的扩展性,帮助您提升集群管理水平; - 🌪️  **零成本、界面化** - - 提炼高频 CLI 能力,设计合理的产品路径,提供清新美观的 GUI 界面,支持 Cluster、Broker、Topic、Group、Message、ACL 等组件 GUI 管理,普通用户5分钟即可上手; + - 提炼高频 CLI 能力,设计合理的产品路径,提供清新美观的 GUI 界面,支持 Cluster、Broker、Zookeeper、Topic、ConsumerGroup、Message、ACL、Connect 等组件 GUI 管理,普通用户5分钟即可上手; - 👏  **云原生、插件化** - 基于云原生构建,具备水平扩展能力,只需要增加节点即可获取更强的采集及对外服务能力,提供众多可热插拔的企业级特性,覆盖可观测性生态整合、资源治理、多活容灾等核心场景; From 597ea04a96f90e7b7886d945ea549c3a6a167485 Mon Sep 17 00:00:00 2001 From: Peng <71620349+PenceXie@users.noreply.github.com> Date: Fri, 16 Sep 2022 15:20:04 +0800 Subject: [PATCH 21/53] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index afff4b6cd..70585679e 100644 --- a/README.md +++ b/README.md @@ -57,10 +57,10 @@ - 基于云原生构建,具备水平扩展能力,只需要增加节点即可获取更强的采集及对外服务能力,提供众多可热插拔的企业级特性,覆盖可观测性生态整合、资源治理、多活容灾等核心场景; - 🚀  **专业能力** - - 集群管理:支持集群一键纳管,健康分析、核心组件观测 等功能; + - 集群管理:支持一键纳管,健康分析、核心组件观测 等功能; - 观测提升:多维度指标观测大盘、观测指标最佳实践 等功能; - 异常巡检:集群多维度健康巡检、集群多维度健康分 等功能; - - 能力增强:Topic扩缩副本、Topic副本迁移 等功能; + - 能力增强:集群负载均衡、Topic扩缩副本、Topic副本迁移 等功能;   From 7b0b6936e0dc16ff77569675a15aba26c784febc Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Fri, 16 Sep 2022 15:54:34 +0800 Subject: [PATCH 22/53] =?UTF-8?q?1.=20=E8=B0=83=E6=95=B4docker-compose.yml?= =?UTF-8?q?=E4=B8=AD=E5=AE=B9=E5=99=A8=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 34 ++++++++----------- km-dist/docker/knowstreaming-init/Dockerfile | 7 ++-- .../knowstreaming-init/init/template.sh | 2 +- .../docker/knowstreaming-manage/Dockerfile | 2 +- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index 62d153246..1e736d313 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -3,22 +3,22 @@ version: "3" services: knowstreaming-manager: - image: km_manage:1.1 + image: knowstreaming-manager:0.1.0 container_name: knowstreaming-manager privileged: true restart: always depends_on: - elasticsearch_single - - kmysql + - knowstreaming_mysql links: - elasticsearch_single - - kmysql + - knowstreaming_mysql expose: - 80 environment: TZ: Asia/Shanghai - SERVER_MYSQL_ADDRESS: kmysql:3306 + SERVER_MYSQL_ADDRESS: knowstreaming_mysql:3306 SERVER_MYSQL_DB: know_streaming SERVER_MYSQL_USER: root SERVER_MYSQL_PASSWORD: admin2022_ @@ -28,11 +28,10 @@ services: JAVA_OPTS: -Xmx1g -Xms1g networks: - ks -# 日志文件持久化路径 # volumes: # - /Users/haoqi/Downloads/ks/manage/log:/logs knowstreaming-ui: - image: km:1.0 + image: knowstreaming-ui:0.1.0 container_name: knowstreaming-ui restart: always ports: @@ -54,23 +53,20 @@ services: expose: - 9200 - 9300 -# 对外访问 -# ports: -# - '9200:9200' -# - '9300:9300' + ports: + - '9200:9200' + - '9300:9300' environment: TZ: Asia/Shanghai ES_JAVA_OPTS: -Xms512m -Xmx512m discovery.type: single-node -# 数据文件持久化路径 -# 记录实时指标信息 # volumes: # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data networks: - ks - esinit: - image: esinit:1.0 - container_name: esinit + knowstreaming_init: + image: knowstreaming-init:0.1.0 + container_name: knowstreaming_init depends_on: - elasticsearch_single links: @@ -81,9 +77,9 @@ services: networks: - ks - kmysql: - image: ks_mysql:1.0 - container_name: kmysql + knowstreaming_mysql: + image: knowstreaming-mysql:0.1.0 + container_name: knowstreaming_mysql restart: always environment: TZ: Asia/Shanghai @@ -93,8 +89,6 @@ services: - ks expose: - 3306 -# 数据文件持久化路径 -# 记录添加的集群基本信息 # volumes: # - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql diff --git a/km-dist/docker/knowstreaming-init/Dockerfile b/km-dist/docker/knowstreaming-init/Dockerfile index 8dfec0a53..ddb2120c4 100644 --- a/km-dist/docker/knowstreaming-init/Dockerfile +++ b/km-dist/docker/knowstreaming-init/Dockerfile @@ -1,7 +1,10 @@ -FROM centos:7.9.2009 +FROM debian:stable-20220912-slim LABEL org.opencontainers.image.authors="haoqi123" ARG INIT_ES_FILE=./init/* COPY ${INIT_ES_FILE} / ENV TZ=Asia/Shanghai -ENTRYPOINT ["/bin/sh","/template.sh","start"] \ No newline at end of file +RUN apt-get update \ + && apt-get install -y curl + +ENTRYPOINT ["/bin/bash","/template.sh","start"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/template.sh b/km-dist/docker/knowstreaming-init/init/template.sh index 2b091e101..ce41db734 100644 --- a/km-dist/docker/knowstreaming-init/init/template.sh +++ b/km-dist/docker/knowstreaming-init/init/template.sh @@ -1,4 +1,4 @@ -echo "Wait ElasticSearch Start..." +echo "Wait ElasticSearch Start...${SERVER_ES_ADDRESS}" while true do curl -s --connect-timeout 10 -o /dev/null http://${SERVER_ES_ADDRESS}/_cat/nodes > /dev/null 2>&1 diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index fbfc2edfb..95c20f7a5 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -31,6 +31,6 @@ RUN curl -fsSLO --compressed "https://dlcdn.apache.org/maven/maven-3/${VERSION_M && mv /knowstreaming/KnowStreaming/km-rest/target/ks-km.jar /app/app.jar \ && rm -rf /knowstreaming/* /usr/local/bin/mvn \ && yum erase -y git && yum clean all \ - && rm -rf `pwd`/.m2 /tmp/* + && rm -rf /root/.m2 /tmp/* ENTRYPOINT ["/bin/bash","/start.sh"] From 121f8468d5282e6cd4aa03677d85e38ebef5b81e Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Fri, 16 Sep 2022 17:33:19 +0800 Subject: [PATCH 23/53] =?UTF-8?q?1.=20=E8=B0=83=E6=95=B4=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E6=A0=BC=E5=BC=8FLF=202.=20=E8=B0=83=E6=95=B4docker-compose?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=EF=BC=8C=E5=AE=B9=E5=99=A8=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 26 +++++++++---------- .../docker/knowstreaming-manage/Dockerfile | 6 ++--- .../docker/knowstreaming-manage/init/start.sh | 8 +----- km-dist/docker/knowstreaming-web/Dockerfile | 16 ++++++------ 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index 1e736d313..a687fe077 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -4,26 +4,26 @@ services: knowstreaming-manager: image: knowstreaming-manager:0.1.0 - container_name: knowstreaming-manager + container_name: knowstreaming_manager privileged: true restart: always depends_on: - - elasticsearch_single - - knowstreaming_mysql + - elasticsearch-single + - knowstreaming-mysql links: - - elasticsearch_single - - knowstreaming_mysql + - elasticsearch-single + - knowstreaming-mysql expose: - 80 environment: TZ: Asia/Shanghai - SERVER_MYSQL_ADDRESS: knowstreaming_mysql:3306 + SERVER_MYSQL_ADDRESS: knowstreaming-mysql:3306 SERVER_MYSQL_DB: know_streaming SERVER_MYSQL_USER: root SERVER_MYSQL_PASSWORD: admin2022_ - SERVER_ES_ADDRESS: elasticsearch_single:9200 + SERVER_ES_ADDRESS: elasticsearch-single:9200 JAVA_OPTS: -Xmx1g -Xms1g networks: @@ -32,7 +32,7 @@ services: # - /Users/haoqi/Downloads/ks/manage/log:/logs knowstreaming-ui: image: knowstreaming-ui:0.1.0 - container_name: knowstreaming-ui + container_name: knowstreaming_ui restart: always ports: - '80:80' @@ -46,7 +46,7 @@ services: - ks - elasticsearch_single: + elasticsearch-single: image: docker.io/library/elasticsearch:7.6.2 container_name: elasticsearch_single restart: always @@ -64,20 +64,20 @@ services: # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data networks: - ks - knowstreaming_init: + knowstreaming-init: image: knowstreaming-init:0.1.0 container_name: knowstreaming_init depends_on: - - elasticsearch_single + - elasticsearch-single links: - - elasticsearch_single + - elasticsearch-single environment: TZ: Asia/Shanghai SERVER_ES_ADDRESS: elasticsearch_single:9200 networks: - ks - knowstreaming_mysql: + knowstreaming-mysql: image: knowstreaming-mysql:0.1.0 container_name: knowstreaming_mysql restart: always diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index 95c20f7a5..94553bce7 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -5,7 +5,7 @@ LABEL maintainer="haoqi123 <1148648445@qq.com>" WORKDIR /knowstreaming ARG VERSION_MAVEN=3.6.3 -ARG VERSION_KM=v3.0.0-beta.2 +ARG VERSION_KM=3.0.0-beta.2 ARG INIT_FILE=./init/* ARG CONFIG_FILE=./conf/* @@ -24,10 +24,10 @@ RUN curl -fsSLO --compressed "https://dlcdn.apache.org/maven/maven-3/${VERSION_M # && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/${VERSION_KM}.zip \ && git clone https://github.com/didi/KnowStreaming.git \ # && unzip -o -q master.zip \ - && cd KnowStreaming && git checkout ${VERSION_KM} \ + && cd KnowStreaming && git checkout v${VERSION_KM} \ && sed -i "/km-console/d" ./pom.xml \ && mvn -U clean package -Dmaven.test.skip=true \ - && cd / \ + && cd / && mkdir /app \ && mv /knowstreaming/KnowStreaming/km-rest/target/ks-km.jar /app/app.jar \ && rm -rf /knowstreaming/* /usr/local/bin/mvn \ && yum erase -y git && yum clean all \ diff --git a/km-dist/docker/knowstreaming-manage/init/start.sh b/km-dist/docker/knowstreaming-manage/init/start.sh index 9741d7cf0..79c5d77aa 100644 --- a/km-dist/docker/knowstreaming-manage/init/start.sh +++ b/km-dist/docker/knowstreaming-manage/init/start.sh @@ -4,10 +4,4 @@ sed -i "s/SERVER_MYSQL_USER/${SERVER_MYSQL_USER}/g" /conf/application.yml sed -i "s/SERVER_MYSQL_PASSWORD/${SERVER_MYSQL_PASSWORD}/g" /conf/application.yml sed -i "s/SERVER_ES_ADDRESS/${SERVER_ES_ADDRESS}/g" /conf/application.yml -java -server ${JAVA_OPTS} \ --XX:+UseStringDeduplication \ --Dfile.encoding=UTF-8 \ --Djava.security.egd=file:/dev/./urandom \ --Duser.timezone=GMT+08 \ --XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs -XX:ErrorFile=/logs/jvm/hs_err_pid%p.log \ --jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file +java -server ${JAVA_OPTS} -XX:+UseStringDeduplication -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs -XX:ErrorFile=/logs/jvm/hs_err_pid%p.log -jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-web/Dockerfile b/km-dist/docker/knowstreaming-web/Dockerfile index ef7e6b780..54b277db2 100644 --- a/km-dist/docker/knowstreaming-web/Dockerfile +++ b/km-dist/docker/knowstreaming-web/Dockerfile @@ -4,8 +4,8 @@ LABEL maintainer="haoqi123 <1148648445@qq.com>" WORKDIR /knowstreaming -ARG VERSION_NODE=v14.20.0 -ARG VERSION_KM=v3.0.0-beta.2 +ARG VERSION_NODE=14.20.0 +ARG VERSION_KM=3.0.0-beta.2 # SHELL ["/bin/bash", "-o", "pipefail", "-c"] @@ -59,9 +59,9 @@ RUN echo 'server { \ } \ }' > /etc/nginx/conf.d/default.conf -RUN curl -fsSLO --compressed "https://npm.taobao.org/mirrors/node/${VERSION_NODE}/node-${VERSION_NODE}-linux-x64.tar.gz" \ +RUN curl -fsSLO --compressed "https://npm.taobao.org/mirrors/node/v${VERSION_NODE}/node-v${VERSION_NODE}-linux-x64.tar.gz" \ && mkdir node/ \ - && tar -zxf "node-${VERSION_NODE}-linux-x64.tar.gz" -C node/ --strip-components=1 --no-same-owner \ + && tar -zxf "node-v${VERSION_NODE}-linux-x64.tar.gz" -C node/ --strip-components=1 --no-same-owner \ && rm -rf /knowstreaming/*.tar.gz \ && ln -s /knowstreaming/node/bin/node /usr/local/bin/node \ && ln -s /knowstreaming/node/bin/npm /usr/local/bin/npm \ @@ -70,11 +70,11 @@ RUN curl -fsSLO --compressed "https://npm.taobao.org/mirrors/node/${VERSION_NODE && npm info underscore \ && node --version \ && npm --version \ - && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/${VERSION_KM}.zip \ - && unzip -o -q master.zip \ - && cd KnowStreaming-master/km-console \ + && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/v${VERSION_KM}.zip \ + && unzip -o -q v${VERSION_KM}.zip \ + && cd KnowStreaming-${VERSION_KM}/km-console \ && npm install -g lerna && npm run i && npm run build \ - && mv /knowstreaming/KnowStreaming-master/km-rest/src/main/resources/templates /pub \ + && mv /knowstreaming/KnowStreaming-${VERSION_KM}/km-rest/src/main/resources/templates /pub \ && npm uninstall -g lerna \ && cd / \ && rm -rf /knowstreaming/* /usr/local/bin/node /usr/local/bin/npm \ From c73a7eee2f84aaba606e285a50a781938ff9b49b Mon Sep 17 00:00:00 2001 From: _haoqi <1148648445@qq.com> Date: Fri, 16 Sep 2022 20:03:58 +0800 Subject: [PATCH 24/53] =?UTF-8?q?1.=20=E8=B0=83=E6=95=B4docker-compose?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=EF=BC=8C=E5=AE=B9=E5=99=A8=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index a687fe077..b05e29b45 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -3,8 +3,8 @@ version: "3" services: knowstreaming-manager: - image: knowstreaming-manager:0.1.0 - container_name: knowstreaming_manager + image: haiti/knowstreaming-manager:0.1.0 + container_name: knowstreaming-manager privileged: true restart: always depends_on: @@ -28,14 +28,16 @@ services: JAVA_OPTS: -Xmx1g -Xms1g networks: - ks +# extra_hosts: +# - "hostname:x.x.x.x" # volumes: # - /Users/haoqi/Downloads/ks/manage/log:/logs knowstreaming-ui: - image: knowstreaming-ui:0.1.0 - container_name: knowstreaming_ui + image: haiti/knowstreaming-ui:0.1.0 + container_name: knowstreaming-ui restart: always ports: - - '80:80' + - '18092:80' environment: TZ: Asia/Shanghai depends_on: @@ -44,18 +46,19 @@ services: - knowstreaming-manager networks: - ks - +# extra_hosts: +# - "hostname:x.x.x.x" elasticsearch-single: image: docker.io/library/elasticsearch:7.6.2 - container_name: elasticsearch_single + container_name: elasticsearch-single restart: always expose: - 9200 - 9300 - ports: - - '9200:9200' - - '9300:9300' +# ports: +# - '9200:9200' +# - '9300:9300' environment: TZ: Asia/Shanghai ES_JAVA_OPTS: -Xms512m -Xmx512m @@ -65,7 +68,7 @@ services: networks: - ks knowstreaming-init: - image: knowstreaming-init:0.1.0 + image: haiti/knowstreaming-init:0.1.0 container_name: knowstreaming_init depends_on: - elasticsearch-single @@ -73,13 +76,13 @@ services: - elasticsearch-single environment: TZ: Asia/Shanghai - SERVER_ES_ADDRESS: elasticsearch_single:9200 + SERVER_ES_ADDRESS: elasticsearch-single:9200 networks: - ks knowstreaming-mysql: - image: knowstreaming-mysql:0.1.0 - container_name: knowstreaming_mysql + image: haiti/knowstreaming-mysql:0.1.0 + container_name: knowstreaming-mysql restart: always environment: TZ: Asia/Shanghai From a7a5fa9a31159a973f17038aa6695c8a132000a1 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Sun, 18 Sep 2022 19:10:22 +0800 Subject: [PATCH 25/53] =?UTF-8?q?1.=20=E8=B0=83=E6=95=B4docker-compose.yml?= =?UTF-8?q?=E4=B8=ADnetworks=E9=85=8D=E7=BD=AE=202.=20ks-manager=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5=203.=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=8D=95=E6=9C=BA=E9=83=A8=E7=BD=B2=E6=89=8B=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...50\347\275\262\346\211\213\345\206\214.md" | 90 +++++++++++++++++++ km-dist/docker/docker-compose.yml | 26 +----- .../docker/knowstreaming-manage/Dockerfile | 2 + 3 files changed, 96 insertions(+), 22 deletions(-) diff --git "a/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" "b/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" index f9f5ad1a4..5110fa723 100644 --- "a/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" +++ "b/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" @@ -59,6 +59,8 @@ sh deploy_KnowStreaming-offline.sh ### 2.1.3、容器部署 +#### 2.1.3.1、Helm + **环境依赖** - Kubernetes >= 1.14 ,Helm >= 2.17.0 @@ -87,6 +89,94 @@ helm pull knowstreaming/knowstreaming-manager   +#### 2.1.3.2、Docker Compose +```yml +version: "3" + +services: + + knowstreaming-manager: + image: haiti/knowstreaming-manager:0.1.0 + container_name: knowstreaming-manager + privileged: true + restart: always + depends_on: + - elasticsearch-single + - knowstreaming-mysql + expose: + - 80 + environment: + TZ: Asia/Shanghai + + SERVER_MYSQL_ADDRESS: knowstreaming-mysql:3306 + SERVER_MYSQL_DB: know_streaming + SERVER_MYSQL_USER: root + SERVER_MYSQL_PASSWORD: admin2022_ + + SERVER_ES_ADDRESS: elasticsearch-single:9200 + + JAVA_OPTS: -Xmx1g -Xms1g + + # extra_hosts: + # - "hostname:x.x.x.x" + # volumes: + # - /Users/haoqi/Downloads/ks/manage/log:/logs + knowstreaming-ui: + image: haiti/knowstreaming-ui:0.1.0 + container_name: knowstreaming-ui + restart: always + ports: + - '18092:80' + environment: + TZ: Asia/Shanghai + depends_on: + - knowstreaming-manager + # extra_hosts: + # - "hostname:x.x.x.x" + + elasticsearch-single: + image: docker.io/library/elasticsearch:7.6.2 + container_name: elasticsearch-single + restart: always + expose: + - 9200 + - 9300 + # ports: + # - '9200:9200' + # - '9300:9300' + environment: + TZ: Asia/Shanghai + ES_JAVA_OPTS: -Xms512m -Xmx512m + discovery.type: single-node + # volumes: + # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data + + knowstreaming-init: + image: haiti/knowstreaming-init:0.1.0 + container_name: knowstreaming_init + depends_on: + - elasticsearch-single + environment: + TZ: Asia/Shanghai + SERVER_ES_ADDRESS: elasticsearch-single:9200 + + + knowstreaming-mysql: + image: haiti/knowstreaming-mysql:0.1.0 + container_name: knowstreaming-mysql + restart: always + environment: + TZ: Asia/Shanghai + MYSQL_ROOT_PASSWORD: admin2022_ + MYSQL_DATABASE: know_streaming + expose: + - 3306 +# volumes: +# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql +``` + +  + ### 2.1.4、手动部署 **部署流程** diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index b05e29b45..d916a51e9 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -10,9 +10,6 @@ services: depends_on: - elasticsearch-single - knowstreaming-mysql - links: - - elasticsearch-single - - knowstreaming-mysql expose: - 80 environment: @@ -26,8 +23,7 @@ services: SERVER_ES_ADDRESS: elasticsearch-single:9200 JAVA_OPTS: -Xmx1g -Xms1g - networks: - - ks + # extra_hosts: # - "hostname:x.x.x.x" # volumes: @@ -42,10 +38,6 @@ services: TZ: Asia/Shanghai depends_on: - knowstreaming-manager - links: - - knowstreaming-manager - networks: - - ks # extra_hosts: # - "hostname:x.x.x.x" @@ -65,20 +57,16 @@ services: discovery.type: single-node # volumes: # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data - networks: - - ks + knowstreaming-init: image: haiti/knowstreaming-init:0.1.0 container_name: knowstreaming_init depends_on: - elasticsearch-single - links: - - elasticsearch-single environment: TZ: Asia/Shanghai SERVER_ES_ADDRESS: elasticsearch-single:9200 - networks: - - ks + knowstreaming-mysql: image: haiti/knowstreaming-mysql:0.1.0 @@ -88,13 +76,7 @@ services: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: admin2022_ MYSQL_DATABASE: know_streaming - networks: - - ks expose: - 3306 # volumes: -# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql - -networks: - ks: - driver: bridge \ No newline at end of file +# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile index 94553bce7..b522eb5ce 100644 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ b/km-dist/docker/knowstreaming-manage/Dockerfile @@ -34,3 +34,5 @@ RUN curl -fsSLO --compressed "https://dlcdn.apache.org/maven/maven-3/${VERSION_M && rm -rf /root/.m2 /tmp/* ENTRYPOINT ["/bin/bash","/start.sh"] + +HEALTHCHECK --interval=60s --timeout=60s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 From 375c6f56c9aa4533f7b13419e2b44a1fe4da56be Mon Sep 17 00:00:00 2001 From: zengqiao Date: Mon, 19 Sep 2022 13:55:59 +0800 Subject: [PATCH 26/53] =?UTF-8?q?=E4=BF=AE=E6=94=B9GroupOffsetResetEnum?= =?UTF-8?q?=E7=B1=BB=E5=90=8D=E4=B8=BAOffsetTypeEnum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/biz/group/impl/GroupManagerImpl.java | 12 ++++++------ .../km/biz/topic/impl/TopicStateManagerImpl.java | 10 +++++----- .../common/bean/dto/group/GroupOffsetResetDTO.java | 3 ++- .../km/common/bean/dto/topic/TopicRecordDTO.java | 9 ++++----- ...oupOffsetResetEnum.java => OffsetTypeEnum.java} | 14 +++++++------- 5 files changed, 24 insertions(+), 24 deletions(-) rename km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/{GroupOffsetResetEnum.java => OffsetTypeEnum.java} (50%) diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java index 15aafdb5a..1095d5ee8 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/group/impl/GroupManagerImpl.java @@ -19,7 +19,7 @@ import com.xiaojukeji.know.streaming.km.common.bean.vo.group.GroupTopicOverviewVO; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; import com.xiaojukeji.know.streaming.km.common.enums.AggTypeEnum; -import com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum; +import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.group.GroupStateEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; @@ -199,12 +199,12 @@ private Result checkFieldLegal(GroupOffsetResetDTO dto) { return Result.buildFromRSAndMsg(ResultStatus.NOT_EXIST, MsgConstant.getTopicNotExist(dto.getClusterId(), dto.getTopicName())); } - if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getResetType() + if (OffsetTypeEnum.PRECISE_OFFSET.getResetType() == dto.getResetType() && ValidateUtils.isEmptyList(dto.getOffsetList())) { return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "参数错误,指定offset重置需传offset信息"); } - if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType() + if (OffsetTypeEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType() && ValidateUtils.isNull(dto.getTimestamp())) { return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "参数错误,指定时间重置需传时间信息"); } @@ -213,7 +213,7 @@ private Result checkFieldLegal(GroupOffsetResetDTO dto) { } private Result> getPartitionOffset(GroupOffsetResetDTO dto) { - if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getResetType()) { + if (OffsetTypeEnum.PRECISE_OFFSET.getResetType() == dto.getResetType()) { return Result.buildSuc(dto.getOffsetList().stream().collect(Collectors.toMap( elem -> new TopicPartition(dto.getTopicName(), elem.getPartitionId()), PartitionOffsetDTO::getOffset, @@ -222,9 +222,9 @@ private Result> getPartitionOffset(GroupOffsetResetDTO } OffsetSpec offsetSpec = null; - if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType()) { + if (OffsetTypeEnum.PRECISE_TIMESTAMP.getResetType() == dto.getResetType()) { offsetSpec = OffsetSpec.forTimestamp(dto.getTimestamp()); - } else if (GroupOffsetResetEnum.EARLIEST.getResetType() == dto.getResetType()) { + } else if (OffsetTypeEnum.EARLIEST.getResetType() == dto.getResetType()) { offsetSpec = OffsetSpec.earliest(); } else { offsetSpec = OffsetSpec.latest(); diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java index 1afb12106..9c03737a9 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/topic/impl/TopicStateManagerImpl.java @@ -23,7 +23,7 @@ import com.xiaojukeji.know.streaming.km.common.constant.KafkaConstant; import com.xiaojukeji.know.streaming.km.common.constant.MsgConstant; import com.xiaojukeji.know.streaming.km.common.converter.TopicVOConverter; -import com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum; +import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; import com.xiaojukeji.know.streaming.km.common.enums.SortTypeEnum; import com.xiaojukeji.know.streaming.km.common.exception.AdminOperateException; import com.xiaojukeji.know.streaming.km.common.exception.NotExistException; @@ -164,7 +164,7 @@ public Result> getTopicMessages(Long clusterPhyId, String to Map partitionOffsetAndTimestampMap = new HashMap<>(); // 获取指定时间每个分区的offset(按指定开始时间查询消息时) - if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { + if (OffsetTypeEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { Map timestampsToSearch = new HashMap<>(); partitionList.forEach(topicPartition -> { timestampsToSearch.put(topicPartition, dto.getStartTimestampUnitMs()); @@ -173,13 +173,13 @@ public Result> getTopicMessages(Long clusterPhyId, String to } for (TopicPartition partition : partitionList) { - if (GroupOffsetResetEnum.EARLIEST.getResetType() == dto.getFilterOffsetReset()) { + if (OffsetTypeEnum.EARLIEST.getResetType() == dto.getFilterOffsetReset()) { // 重置到最旧 kafkaConsumer.seek(partition, beginOffsetsMapResult.getData().get(partition)); - } else if (GroupOffsetResetEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { + } else if (OffsetTypeEnum.PRECISE_TIMESTAMP.getResetType() == dto.getFilterOffsetReset()) { // 重置到指定时间 kafkaConsumer.seek(partition, partitionOffsetAndTimestampMap.get(partition).offset()); - } else if (GroupOffsetResetEnum.PRECISE_OFFSET.getResetType() == dto.getFilterOffsetReset()) { + } else if (OffsetTypeEnum.PRECISE_OFFSET.getResetType() == dto.getFilterOffsetReset()) { // 重置到指定位置 } else { diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/group/GroupOffsetResetDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/group/GroupOffsetResetDTO.java index 09d12bcdb..378709dd9 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/group/GroupOffsetResetDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/group/GroupOffsetResetDTO.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.xiaojukeji.know.streaming.km.common.bean.dto.partition.PartitionOffsetDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.topic.ClusterTopicDTO; +import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -23,7 +24,7 @@ public class GroupOffsetResetDTO extends ClusterTopicDTO { private String groupName; /** - * @see com.xiaojukeji.know.streaming.km.common.enums.GroupOffsetResetEnum + * @see OffsetTypeEnum */ @NotNull(message = "resetType不允许为空") @ApiModelProperty(value = "重置方式", example = "1") diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java index 74e5611b3..ca625f010 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/topic/TopicRecordDTO.java @@ -1,8 +1,8 @@ package com.xiaojukeji.know.streaming.km.common.bean.dto.topic; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.pagination.PaginationSortDTO; +import com.xiaojukeji.know.streaming.km.common.enums.OffsetTypeEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -36,13 +36,12 @@ public class TopicRecordDTO extends PaginationSortDTO { @ApiModelProperty(value = "预览超时时间", example = "10000") private Long pullTimeoutUnitMs = 8000L; + /** + * @see OffsetTypeEnum + */ @ApiModelProperty(value = "offset", example = "") private Integer filterOffsetReset = 0; @ApiModelProperty(value = "开始日期时间戳", example = "") private Long startTimestampUnitMs; - - @ApiModelProperty(value = "结束日期时间戳", example = "") - private Long utilTimestampUnitMs; - } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/GroupOffsetResetEnum.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/OffsetTypeEnum.java similarity index 50% rename from km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/GroupOffsetResetEnum.java rename to km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/OffsetTypeEnum.java index 178fb90ea..6bdc8b801 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/GroupOffsetResetEnum.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/enums/OffsetTypeEnum.java @@ -3,19 +3,19 @@ import lombok.Getter; /** - * 重置offset + * offset类型 * @author zengqiao * @date 19/4/8 */ @Getter -public enum GroupOffsetResetEnum { - LATEST(0, "重置到最新"), +public enum OffsetTypeEnum { + LATEST(0, "最新"), - EARLIEST(1, "重置到最旧"), + EARLIEST(1, "最旧"), - PRECISE_TIMESTAMP(2, "按时间进行重置"), + PRECISE_TIMESTAMP(2, "指定时间"), - PRECISE_OFFSET(3, "重置到指定位置"), + PRECISE_OFFSET(3, "指定位置"), ; @@ -23,7 +23,7 @@ public enum GroupOffsetResetEnum { private final String message; - GroupOffsetResetEnum(int resetType, String message) { + OffsetTypeEnum(int resetType, String message) { this.resetType = resetType; this.message = message; } From b6c6df7ffc138657267acbc3b8d85ce8c1bd9111 Mon Sep 17 00:00:00 2001 From: Richard <49510754+f1558@users.noreply.github.com> Date: Tue, 20 Sep 2022 09:42:42 +0800 Subject: [PATCH 27/53] fix issue * SQL specification comments to avoid direct operation failure --- km-dist/init/sql/dml-logi.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-dist/init/sql/dml-logi.sql b/km-dist/init/sql/dml-logi.sql index 86eb9a690..6d6e81592 100644 --- a/km-dist/init/sql/dml-logi.sql +++ b/km-dist/init/sql/dml-logi.sql @@ -48,7 +48,7 @@ INSERT INTO `logi_security_permission` (`id`, `permission_name`, `parent_id`, `l -- 初始化用户 ---INSERT INTO `logi_security_user` (`id`, `user_name`, `pw`, `real_name`, `is_delete`, `app_name`) VALUES ('1', 'admin', 'V1ZkU2RHRlhOSGxOUkVsNVdETjBRVlp0Y0V0T1IwWnlaVEZ6YWxGRVJrRkpNVEU1VTJwYVUySkhlRzlSU0RBOWUwQldha28wWVd0N1d5TkFNa0FqWFgxS05sSnNiR2hBZlE9PXtAVmpKNGFre1sjQDNAI119SjZSbGxoQH0=Mv{#cdRgJ45Lqx}3IubEW87!==', '系统管理员', '0', 'know-streaming'); +-- INSERT INTO `logi_security_user` (`id`, `user_name`, `pw`, `real_name`, `is_delete`, `app_name`) VALUES ('1', 'admin', 'V1ZkU2RHRlhOSGxOUkVsNVdETjBRVlp0Y0V0T1IwWnlaVEZ6YWxGRVJrRkpNVEU1VTJwYVUySkhlRzlSU0RBOWUwQldha28wWVd0N1d5TkFNa0FqWFgxS05sSnNiR2hBZlE9PXtAVmpKNGFre1sjQDNAI119SjZSbGxoQH0=Mv{#cdRgJ45Lqx}3IubEW87!==', '系统管理员', '0', 'know-streaming'); INSERT INTO `logi_security_user` (`id`, `user_name`, `pw`, `real_name`, `is_delete`, `app_name`) VALUES ('1', 'admin', 'V1ZkU2RHRlhOVGRSUmxweFUycFNhR0V6ZEdKSk1FRjRVVU5PWkdaVmJ6SlZiWGh6WVVWQ09YdEFWbXBLTkdGcmUxc2pRREpBSTExOVNqWlNiR3hvUUgwPXtAVmpKNGFre1sjQDNAI119SjZSbGxoQH0=Mv{#cdRgJ45Lqx}3IubEW87!==', '系统管理员', '0', 'know-streaming'); -- 初始化角色 @@ -96,4 +96,4 @@ INSERT INTO `logi_security_user_role` (`id`, `user_id`, `role_id`, `is_delete`, INSERT INTO `logi_security_config` (`value_group`,`value_name`,`value`,`edit`,`status`,`memo`,`is_delete`,`app_name`,`operator`) VALUES -('SECURITY.LOGIN','SECURITY.TRICK_USERS','[\n \"admin\"\n]',1,1,'允许跳过登录的用户',0,'know-streaming','admin'); \ No newline at end of file +('SECURITY.LOGIN','SECURITY.TRICK_USERS','[\n \"admin\"\n]',1,1,'允许跳过登录的用户',0,'know-streaming','admin'); From e06712397e8ba1f984233f4317babd70f2905f03 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 20 Sep 2022 10:27:30 +0800 Subject: [PATCH 28/53] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=9B=A0DB=E4=B8=ADBro?= =?UTF-8?q?ker=E4=BF=A1=E6=81=AF=E4=B8=8D=E5=AD=98=E5=9C=A8=E5=AF=BC?= =?UTF-8?q?=E8=87=B4TotalLogSize=E6=8C=87=E6=A0=87=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=97=B6=E6=8A=9B=E7=A9=BA=E6=8C=87=E9=92=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cluster/impl/ClusterMetricServiceImpl.java | 15 ++++++++------- .../km/persistence/kafka/KafkaJMXClient.java | 4 ++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java index 075c53c29..9fdd9ec00 100644 --- a/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java +++ b/km-core/src/main/java/com/xiaojukeji/know/streaming/km/core/service/cluster/impl/ClusterMetricServiceImpl.java @@ -751,8 +751,8 @@ private Result getMetricFromKafkaByTotalBrokersJMX(VersionItemPa private Result getMetricFromKafkaByTotalTopics(Long clusterId, String metric, String topicMetric){ List topics = topicService.listTopicsFromCacheFirst(clusterId); - float metricsSum = 0f; - for(Topic topic : topics){ + float sumMetricValue = 0f; + for(Topic topic : topics) { Result> ret = topicMetricService.collectTopicMetricsFromKafkaWithCacheFirst( clusterId, topic.getTopicName(), @@ -763,14 +763,15 @@ private Result getMetricFromKafkaByTotalTopics(Long clusterId, S continue; } - List topicMetrics = ret.getData(); - for (TopicMetrics metrics : topicMetrics) { - if(metrics.isBBrokerAgg()){ - metricsSum += Double.valueOf(metrics.getMetrics().get(topicMetric)); + for (TopicMetrics metrics : ret.getData()) { + if(metrics.isBBrokerAgg()) { + Float metricValue = metrics.getMetric(topicMetric); + sumMetricValue += (metricValue == null? 0f: metricValue); + break; } } } - return Result.buildSuc(initWithMetrics(clusterId, metric, metricsSum)); + return Result.buildSuc(initWithMetrics(clusterId, metric, sumMetricValue)); } } diff --git a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaJMXClient.java b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaJMXClient.java index 68d1011ef..39ae1ebe1 100644 --- a/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaJMXClient.java +++ b/km-persistence/src/main/java/com/xiaojukeji/know/streaming/km/persistence/kafka/KafkaJMXClient.java @@ -191,6 +191,10 @@ private Broker getBrokerFromDB(Long clusterPhyId, Integer brokerId) { lambdaQueryWrapper.eq(BrokerPO::getStatus, Constant.ALIVE); BrokerPO brokerPO = brokerDAO.selectOne(lambdaQueryWrapper); + if (brokerPO == null) { + return null; + } + return Broker.buildFrom(brokerPO); } } From beb754aaaaef3950ee36c033f6024e7315e850c1 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 20 Sep 2022 14:22:06 +0800 Subject: [PATCH 29/53] =?UTF-8?q?=E4=BF=AE=E5=A4=8DJMX=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E8=A2=AB=E5=85=B3=E9=97=AD=EF=BC=8C=E6=8A=9B=E5=87=BAIOExcepti?= =?UTF-8?q?on=E5=90=8E=EF=BC=8C=E6=9C=AA=E8=BF=9B=E8=A1=8C=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E9=87=8D=E5=BB=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../km/common/jmx/JmxConnectorWrap.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxConnectorWrap.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxConnectorWrap.java index 0fb65589d..ca7c01c4f 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxConnectorWrap.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/jmx/JmxConnectorWrap.java @@ -90,6 +90,8 @@ public synchronized void close() { } try { jmxConnector.close(); + + jmxConnector = null; } catch (IOException e) { LOGGER.warn("close JmxConnector exception, physicalClusterId:{} brokerId:{} host:{} port:{}.", physicalClusterId, brokerId, host, port, e); } @@ -105,6 +107,11 @@ public Object getAttribute(ObjectName name, String attribute) throws acquire(); MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); return mBeanServerConnection.getAttribute(name, attribute); + } catch (IOException ioe) { + // 如果是因为连接断开,则进行重新连接,并抛出异常 + reInitDueIOException(); + + throw ioe; } finally { atomicInteger.incrementAndGet(); } @@ -120,6 +127,11 @@ public AttributeList getAttributes(ObjectName name, String[] attributes) throws acquire(); MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); return mBeanServerConnection.getAttributes(name, attributes); + } catch (IOException ioe) { + // 如果是因为连接断开,则进行重新连接,并抛出异常 + reInitDueIOException(); + + throw ioe; } finally { atomicInteger.incrementAndGet(); } @@ -131,6 +143,11 @@ public Set queryNames(ObjectName name, QueryExp query) acquire(); MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); return mBeanServerConnection.queryNames(name, query); + } catch (IOException ioe) { + // 如果是因为连接断开,则进行重新连接,并抛出异常 + reInitDueIOException(); + + throw ioe; } finally { atomicInteger.incrementAndGet(); } @@ -186,4 +203,26 @@ private void acquire() { } } } + + private synchronized void reInitDueIOException() { + try { + if (jmxConnector == null) { + return; + } + + // 检查是否正常 + jmxConnector.getConnectionId(); + + // 如果正常则直接返回 + return; + } catch (Exception e) { + // ignore + } + + // 关闭旧的 + this.close(); + + // 重新创建 + this.checkJmxConnectionAndInitIfNeed(); + } } From 0a03f41a7cadc446e67c9bb70725701dd3666d6c Mon Sep 17 00:00:00 2001 From: zengqiao Date: Tue, 20 Sep 2022 14:42:22 +0800 Subject: [PATCH 30/53] =?UTF-8?q?=E5=90=8E=E7=AB=AF=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=91=86=E6=94=BE=E9=A1=BA=E5=BA=8F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/VersionControlManagerImpl.java | 36 +++++++++++++++++-- .../bean/dto/metrices/MetricDetailDTO.java | 28 +++++++++++++++ .../dto/metrices/UserMetricConfigDTO.java | 4 +++ .../config/metric/UserMetricConfig.java | 18 +++++++++- .../vo/config/metric/UserMetricConfigVO.java | 3 ++ .../km/common/constant/Constant.java | 2 ++ 6 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/MetricDetailDTO.java diff --git a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java index 994b2c8a5..ad98d51aa 100644 --- a/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java +++ b/km-biz/src/main/java/com/xiaojukeji/know/streaming/km/biz/version/impl/VersionControlManagerImpl.java @@ -7,12 +7,14 @@ import com.didiglobal.logi.security.common.dto.config.ConfigDTO; import com.didiglobal.logi.security.service.ConfigService; import com.xiaojukeji.know.streaming.km.biz.version.VersionControlManager; +import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.MetricDetailDTO; import com.xiaojukeji.know.streaming.km.common.bean.dto.metrices.UserMetricConfigDTO; import com.xiaojukeji.know.streaming.km.common.bean.entity.config.metric.UserMetricConfig; import com.xiaojukeji.know.streaming.km.common.bean.entity.result.Result; import com.xiaojukeji.know.streaming.km.common.bean.entity.version.VersionControlItem; import com.xiaojukeji.know.streaming.km.common.bean.vo.config.metric.UserMetricConfigVO; import com.xiaojukeji.know.streaming.km.common.bean.vo.version.VersionItemVO; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import com.xiaojukeji.know.streaming.km.common.enums.version.VersionEnum; import com.xiaojukeji.know.streaming.km.common.utils.ConvertUtil; import com.xiaojukeji.know.streaming.km.common.utils.VersionUtil; @@ -159,6 +161,9 @@ public Result> listUserMetricItem(Long clusterId, Integ UserMetricConfig umc = userMetricConfigMap.get(itemType + "@" + metric); userMetricConfigVO.setSet(null != umc && umc.isSet()); + if (umc != null) { + userMetricConfigVO.setRank(umc.getRank()); + } userMetricConfigVO.setName(itemVO.getName()); userMetricConfigVO.setType(itemVO.getType()); userMetricConfigVO.setDesc(itemVO.getDesc()); @@ -178,13 +183,30 @@ public Result> listUserMetricItem(Long clusterId, Integ @Override public Result updateUserMetricItem(Long clusterId, Integer type, UserMetricConfigDTO dto, String operator) { Map metricsSetMap = dto.getMetricsSet(); - if(null == metricsSetMap || metricsSetMap.isEmpty()){ + + //转换metricDetailDTOList + List metricDetailDTOList = dto.getMetricDetailDTOList(); + Map metricDetailMap = new HashMap<>(); + if (metricDetailDTOList != null && !metricDetailDTOList.isEmpty()) { + metricDetailMap = metricDetailDTOList.stream().collect(Collectors.toMap(MetricDetailDTO::getMetric, Function.identity())); + } + + //转换metricsSetMap + if (metricsSetMap != null && !metricsSetMap.isEmpty()) { + for (Map.Entry metricAndShowEntry : metricsSetMap.entrySet()) { + if (metricDetailMap.containsKey(metricAndShowEntry.getKey())) continue; + metricDetailMap.put(metricAndShowEntry.getKey(), new MetricDetailDTO(metricAndShowEntry.getKey(), metricAndShowEntry.getValue(), null)); + } + } + + if (metricDetailMap.isEmpty()) { return Result.buildSuc(); } + Set userMetricConfigs = getUserMetricConfig(operator); for(Map.Entry metricAndShowEntry : metricsSetMap.entrySet()){ - UserMetricConfig userMetricConfig = new UserMetricConfig(type, metricAndShowEntry.getKey(), metricAndShowEntry.getValue()); + UserMetricConfig userMetricConfig = new UserMetricConfig(type, metricAndShowEntry.getKey(), metricAndShowEntry.getValue(), metricDetailMap.get(metricAndShowEntry.getKey()).getRank()); userMetricConfigs.remove(userMetricConfig); userMetricConfigs.add(userMetricConfig); } @@ -228,7 +250,15 @@ private Set getUserMetricConfig(String operator){ return defaultMetrics; } - return JSON.parseObject(value, new TypeReference>(){}); + Set userMetricConfigs = JSON.parseObject(value, new TypeReference>() {}); + + //补充rank不存在情况 + for (UserMetricConfig userMetricConfig : userMetricConfigs) { + if (userMetricConfig.getRank() == 0) { + userMetricConfig.setRank(Constant.DEFAULT_METRIC_RANK); + } + } + return userMetricConfigs; } public static void main(String[] args){ diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/MetricDetailDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/MetricDetailDTO.java new file mode 100644 index 000000000..0d51d2c66 --- /dev/null +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/MetricDetailDTO.java @@ -0,0 +1,28 @@ +package com.xiaojukeji.know.streaming.km.common.bean.dto.metrices; + +import com.xiaojukeji.know.streaming.km.common.bean.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author didi + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(description = "指标详细属性信息") +public class MetricDetailDTO extends BaseDTO { + + @ApiModelProperty("指标名称") + private String metric; + + @ApiModelProperty("指标是否显示") + private Boolean set; + + @ApiModelProperty("指标优先级") + private Integer rank; + +} diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/UserMetricConfigDTO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/UserMetricConfigDTO.java index 02bb1d2a2..bf71b6637 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/UserMetricConfigDTO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/dto/metrices/UserMetricConfigDTO.java @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; import java.util.Map; @@ -17,4 +18,7 @@ public class UserMetricConfigDTO extends BaseDTO { @ApiModelProperty("指标展示设置项,key:指标名;value:是否展现(true展现/false不展现)") private Map metricsSet; + + @ApiModelProperty("指标自定义属性列表") + private List metricDetailDTOList; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/metric/UserMetricConfig.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/metric/UserMetricConfig.java index 6895fb403..9f85d7cab 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/metric/UserMetricConfig.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/entity/config/metric/UserMetricConfig.java @@ -1,12 +1,12 @@ package com.xiaojukeji.know.streaming.km.common.bean.entity.config.metric; +import com.xiaojukeji.know.streaming.km.common.constant.Constant; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor -@AllArgsConstructor public class UserMetricConfig { private int type; @@ -15,6 +15,22 @@ public class UserMetricConfig { private boolean set; + private int rank; + + public UserMetricConfig(int type, String metric, boolean set, Integer rank) { + this.type = type; + this.metric = metric; + this.set = set; + this.rank = rank == null ? Constant.DEFAULT_METRIC_RANK : rank; + } + + public UserMetricConfig(int type, String metric, boolean set) { + this.type = type; + this.metric = metric; + this.set = set; + this.rank = Constant.DEFAULT_METRIC_RANK; + } + @Override public int hashCode(){ return metric.hashCode() << 1 + type; diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/config/metric/UserMetricConfigVO.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/config/metric/UserMetricConfigVO.java index e50fc6e7d..2b4e76b3f 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/config/metric/UserMetricConfigVO.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/bean/vo/config/metric/UserMetricConfigVO.java @@ -14,4 +14,7 @@ public class UserMetricConfigVO extends VersionItemVO { @ApiModelProperty(value = "该指标用户是否设置展现", example = "true") private Boolean set; + + @ApiModelProperty(value = "该指标展示优先级", example = "1") + private Integer rank; } diff --git a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java index 36575938b..f86c1d8c8 100644 --- a/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java +++ b/km-common/src/main/java/com/xiaojukeji/know/streaming/km/common/constant/Constant.java @@ -42,6 +42,8 @@ private Constant() {} */ public static final Integer DEFAULT_CLUSTER_HEALTH_SCORE = 90; + public static final Integer DEFAULT_METRIC_RANK = 10000; + public static final String DEFAULT_USER_NAME = "know-streaming-app"; public static final int INVALID_CODE = -1; From 9a25c22f3a8934c929be4ad3740d0296add98759 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Tue, 20 Sep 2022 19:23:18 +0800 Subject: [PATCH 31/53] =?UTF-8?q?1.=20=E8=B0=83=E6=95=B4docker-compose.yml?= =?UTF-8?q?=E4=B8=AD=E5=90=84=E4=B8=AA=E6=9C=8D=E5=8A=A1=E7=9A=84=E9=95=9C?= =?UTF-8?q?=E5=83=8F=202.=20=E7=BB=8F=E8=BF=87@wangdongfang-aden=E5=A4=A7?= =?UTF-8?q?=E5=93=A5=E7=9A=84=E8=B0=83=E8=AF=95=E5=B0=86helm=E4=B8=8Edocke?= =?UTF-8?q?r=E9=95=9C=E5=83=8F=E5=90=88=E4=BA=8C=E4=B8=BA=E4=B8=80?= =?UTF-8?q?=EF=BC=8C=E4=BA=8E=E6=98=AF=E5=88=A0=E5=87=8F=E6=8E=89=E5=90=84?= =?UTF-8?q?=E4=B8=AA=E9=95=9C=E5=83=8F=E7=9A=84Dockerfile=E4=B8=8E?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E8=84=9A=E6=9C=AC=EF=BC=8C=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=E4=B9=9F=E4=B8=8D=E9=9C=80=E8=A6=81=E9=A2=9D=E5=A4=96=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-dist/docker/docker-compose.yml | 23 +- km-dist/docker/knowstreaming-init/Dockerfile | 10 - .../knowstreaming-init/init/template.sh | 661 ------------------ .../docker/knowstreaming-manage/Dockerfile | 38 - .../knowstreaming-manage/conf/application.yml | 107 --- .../docker/knowstreaming-manage/init/start.sh | 7 - km-dist/docker/knowstreaming-mysql/Dockerfile | 10 - .../docker/knowstreaming-mysql/conf/mysql.cnf | 15 - km-dist/docker/knowstreaming-web/Dockerfile | 86 --- 9 files changed, 16 insertions(+), 941 deletions(-) delete mode 100644 km-dist/docker/knowstreaming-init/Dockerfile delete mode 100644 km-dist/docker/knowstreaming-init/init/template.sh delete mode 100644 km-dist/docker/knowstreaming-manage/Dockerfile delete mode 100644 km-dist/docker/knowstreaming-manage/conf/application.yml delete mode 100644 km-dist/docker/knowstreaming-manage/init/start.sh delete mode 100644 km-dist/docker/knowstreaming-mysql/Dockerfile delete mode 100644 km-dist/docker/knowstreaming-mysql/conf/mysql.cnf delete mode 100644 km-dist/docker/knowstreaming-web/Dockerfile diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml index d916a51e9..a9fe2bf30 100644 --- a/km-dist/docker/docker-compose.yml +++ b/km-dist/docker/docker-compose.yml @@ -3,7 +3,7 @@ version: "3" services: knowstreaming-manager: - image: haiti/knowstreaming-manager:0.1.0 + image: knowstreaming/knowstreaming-manager:0.2.0-test container_name: knowstreaming-manager privileged: true restart: always @@ -12,6 +12,9 @@ services: - knowstreaming-mysql expose: - 80 + command: + - /bin/sh + - /ks-start.sh environment: TZ: Asia/Shanghai @@ -27,9 +30,9 @@ services: # extra_hosts: # - "hostname:x.x.x.x" # volumes: -# - /Users/haoqi/Downloads/ks/manage/log:/logs +# - /ks/manage/log:/logs knowstreaming-ui: - image: haiti/knowstreaming-ui:0.1.0 + image: knowstreaming/knowstreaming-ui:0.2.0-test1 container_name: knowstreaming-ui restart: always ports: @@ -56,27 +59,33 @@ services: ES_JAVA_OPTS: -Xms512m -Xmx512m discovery.type: single-node # volumes: -# - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data +# - /ks/es/data:/usr/share/elasticsearch/data knowstreaming-init: - image: haiti/knowstreaming-init:0.1.0 + image: knowstreaming/knowstreaming-manager:0.2.0-test container_name: knowstreaming_init depends_on: - elasticsearch-single + command: + - /bin/bash + - /es_template_create.sh environment: TZ: Asia/Shanghai SERVER_ES_ADDRESS: elasticsearch-single:9200 knowstreaming-mysql: - image: haiti/knowstreaming-mysql:0.1.0 + image: knowstreaming/knowstreaming-mysql:0.2.0-test container_name: knowstreaming-mysql restart: always environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: admin2022_ MYSQL_DATABASE: know_streaming + MYSQL_ROOT_HOST: '%' expose: - 3306 +# ports: +# - '3306:3306' # volumes: -# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql \ No newline at end of file +# - /ks/mysql/data:/data/mysql \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/Dockerfile b/km-dist/docker/knowstreaming-init/Dockerfile deleted file mode 100644 index ddb2120c4..000000000 --- a/km-dist/docker/knowstreaming-init/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM debian:stable-20220912-slim -LABEL org.opencontainers.image.authors="haoqi123" -ARG INIT_ES_FILE=./init/* -COPY ${INIT_ES_FILE} / -ENV TZ=Asia/Shanghai - -RUN apt-get update \ - && apt-get install -y curl - -ENTRYPOINT ["/bin/bash","/template.sh","start"] \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-init/init/template.sh b/km-dist/docker/knowstreaming-init/init/template.sh deleted file mode 100644 index ce41db734..000000000 --- a/km-dist/docker/knowstreaming-init/init/template.sh +++ /dev/null @@ -1,661 +0,0 @@ -echo "Wait ElasticSearch Start...${SERVER_ES_ADDRESS}" -while true -do - curl -s --connect-timeout 10 -o /dev/null http://${SERVER_ES_ADDRESS}/_cat/nodes > /dev/null 2>&1 - if [ "$?" != "0" ];then - sleep 1s - else - echo "ElasticSearch Start Initialize" - break - fi -done - -curl -s --connect-timeout 10 -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_broker_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_broker_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "NetworkProcessorAvgIdle" : { - "type" : "float" - }, - "UnderReplicatedPartitions" : { - "type" : "float" - }, - "BytesIn_min_15" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "RequestHandlerAvgIdle" : { - "type" : "float" - }, - "connectionsCount" : { - "type" : "float" - }, - "BytesIn_min_5" : { - "type" : "float" - }, - "HealthScore" : { - "type" : "float" - }, - "BytesOut" : { - "type" : "float" - }, - "BytesOut_min_15" : { - "type" : "float" - }, - "BytesIn" : { - "type" : "float" - }, - "BytesOut_min_5" : { - "type" : "float" - }, - "TotalRequestQueueSize" : { - "type" : "float" - }, - "MessagesIn" : { - "type" : "float" - }, - "TotalProduceRequests" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - }, - "TotalResponseQueueSize" : { - "type" : "float" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' - -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_cluster_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_cluster_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "Connections" : { - "type" : "double" - }, - "BytesIn_min_15" : { - "type" : "double" - }, - "PartitionURP" : { - "type" : "double" - }, - "HealthScore_Topics" : { - "type" : "double" - }, - "EventQueueSize" : { - "type" : "double" - }, - "ActiveControllerCount" : { - "type" : "double" - }, - "GroupDeads" : { - "type" : "double" - }, - "BytesIn_min_5" : { - "type" : "double" - }, - "HealthCheckTotal_Topics" : { - "type" : "double" - }, - "Partitions" : { - "type" : "double" - }, - "BytesOut" : { - "type" : "double" - }, - "Groups" : { - "type" : "double" - }, - "BytesOut_min_15" : { - "type" : "double" - }, - "TotalRequestQueueSize" : { - "type" : "double" - }, - "HealthCheckPassed_Groups" : { - "type" : "double" - }, - "TotalProduceRequests" : { - "type" : "double" - }, - "HealthCheckPassed" : { - "type" : "double" - }, - "TotalLogSize" : { - "type" : "double" - }, - "GroupEmptys" : { - "type" : "double" - }, - "PartitionNoLeader" : { - "type" : "double" - }, - "HealthScore_Brokers" : { - "type" : "double" - }, - "Messages" : { - "type" : "double" - }, - "Topics" : { - "type" : "double" - }, - "PartitionMinISR_E" : { - "type" : "double" - }, - "HealthCheckTotal" : { - "type" : "double" - }, - "Brokers" : { - "type" : "double" - }, - "Replicas" : { - "type" : "double" - }, - "HealthCheckTotal_Groups" : { - "type" : "double" - }, - "GroupRebalances" : { - "type" : "double" - }, - "MessageIn" : { - "type" : "double" - }, - "HealthScore" : { - "type" : "double" - }, - "HealthCheckPassed_Topics" : { - "type" : "double" - }, - "HealthCheckTotal_Brokers" : { - "type" : "double" - }, - "PartitionMinISR_S" : { - "type" : "double" - }, - "BytesIn" : { - "type" : "double" - }, - "BytesOut_min_5" : { - "type" : "double" - }, - "GroupActives" : { - "type" : "double" - }, - "MessagesIn" : { - "type" : "double" - }, - "GroupReBalances" : { - "type" : "double" - }, - "HealthCheckPassed_Brokers" : { - "type" : "double" - }, - "HealthScore_Groups" : { - "type" : "double" - }, - "TotalResponseQueueSize" : { - "type" : "double" - }, - "Zookeepers" : { - "type" : "double" - }, - "LeaderMessages" : { - "type" : "double" - }, - "HealthScore_Cluster" : { - "type" : "double" - }, - "HealthCheckPassed_Cluster" : { - "type" : "double" - }, - "HealthCheckTotal_Cluster" : { - "type" : "double" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "type" : "date" - } - } - }, - "aliases" : { } - }' - -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_group_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_group_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "group" : { - "type" : "keyword" - }, - "partitionId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "topic" : { - "type" : "keyword" - }, - "metrics" : { - "properties" : { - "HealthScore" : { - "type" : "float" - }, - "Lag" : { - "type" : "float" - }, - "OffsetConsumed" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - } - } - }, - "groupMetric" : { - "type" : "keyword" - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' - -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_partition_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_partition_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "partitionId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "topic" : { - "type" : "keyword" - }, - "metrics" : { - "properties" : { - "LogStartOffset" : { - "type" : "float" - }, - "Messages" : { - "type" : "float" - }, - "LogEndOffset" : { - "type" : "float" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' - -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_replication_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_partition_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "partitionId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "clusterPhyId" : { - "type" : "long" - }, - "topic" : { - "type" : "keyword" - }, - "metrics" : { - "properties" : { - "LogStartOffset" : { - "type" : "float" - }, - "Messages" : { - "type" : "float" - }, - "LogEndOffset" : { - "type" : "float" - } - } - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }[root@10-255-0-23 template]# cat ks_kafka_replication_metric -PUT _template/ks_kafka_replication_metric -{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_replication_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' - -curl -s -o /dev/null -X POST -H 'cache-control: no-cache' -H 'content-type: application/json' http://${SERVER_ES_ADDRESS}/_template/ks_kafka_topic_metric -d '{ - "order" : 10, - "index_patterns" : [ - "ks_kafka_topic_metric*" - ], - "settings" : { - "index" : { - "number_of_shards" : "10" - } - }, - "mappings" : { - "properties" : { - "brokerId" : { - "type" : "long" - }, - "routingValue" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "topic" : { - "type" : "keyword" - }, - "clusterPhyId" : { - "type" : "long" - }, - "metrics" : { - "properties" : { - "BytesIn_min_15" : { - "type" : "float" - }, - "Messages" : { - "type" : "float" - }, - "BytesRejected" : { - "type" : "float" - }, - "PartitionURP" : { - "type" : "float" - }, - "HealthCheckTotal" : { - "type" : "float" - }, - "ReplicationCount" : { - "type" : "float" - }, - "ReplicationBytesOut" : { - "type" : "float" - }, - "ReplicationBytesIn" : { - "type" : "float" - }, - "FailedFetchRequests" : { - "type" : "float" - }, - "BytesIn_min_5" : { - "type" : "float" - }, - "HealthScore" : { - "type" : "float" - }, - "LogSize" : { - "type" : "float" - }, - "BytesOut" : { - "type" : "float" - }, - "BytesOut_min_15" : { - "type" : "float" - }, - "FailedProduceRequests" : { - "type" : "float" - }, - "BytesIn" : { - "type" : "float" - }, - "BytesOut_min_5" : { - "type" : "float" - }, - "MessagesIn" : { - "type" : "float" - }, - "TotalProduceRequests" : { - "type" : "float" - }, - "HealthCheckPassed" : { - "type" : "float" - } - } - }, - "brokerAgg" : { - "type" : "keyword" - }, - "key" : { - "type" : "text", - "fields" : { - "keyword" : { - "ignore_above" : 256, - "type" : "keyword" - } - } - }, - "timestamp" : { - "format" : "yyyy-MM-dd HH:mm:ss Z||yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm:ss.SSS Z||yyyy-MM-dd HH:mm:ss.SSS||yyyy-MM-dd HH:mm:ss,SSS||yyyy/MM/dd HH:mm:ss||yyyy-MM-dd HH:mm:ss,SSS Z||yyyy/MM/dd HH:mm:ss,SSS Z||epoch_millis", - "index" : true, - "type" : "date", - "doc_values" : true - } - } - }, - "aliases" : { } - }' - -for i in {0..6}; -do - logdate=_$(date -d "${i} day ago" +%Y-%m-%d) - curl -s --connect-timeout 10 -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_broker_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_cluster_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_group_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_partition_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_replication_metric${logdate} && \ - curl -s -o /dev/null -X PUT http://${SERVER_ES_ADDRESS}/ks_kafka_topic_metric${logdate} || \ - exit 2 -done - -echo "ElasticSearch Initialize Success" \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/Dockerfile b/km-dist/docker/knowstreaming-manage/Dockerfile deleted file mode 100644 index b522eb5ce..000000000 --- a/km-dist/docker/knowstreaming-manage/Dockerfile +++ /dev/null @@ -1,38 +0,0 @@ -FROM docker.io/amd64/eclipse-temurin:17.0.4.1_1-jdk-centos7 - -LABEL maintainer="haoqi123 <1148648445@qq.com>" - -WORKDIR /knowstreaming - -ARG VERSION_MAVEN=3.6.3 -ARG VERSION_KM=3.0.0-beta.2 -ARG INIT_FILE=./init/* -ARG CONFIG_FILE=./conf/* - -COPY ${INIT_FILE} / -COPY ${CONFIG_FILE} /conf/ - -# SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -RUN yum install -y git - -RUN curl -fsSLO --compressed "https://dlcdn.apache.org/maven/maven-3/${VERSION_MAVEN}/binaries/apache-maven-${VERSION_MAVEN}-bin.tar.gz" \ - && mkdir maven/ \ - && tar -zxf "apache-maven-${VERSION_MAVEN}-bin.tar.gz" -C maven/ --strip-components=1 --no-same-owner \ - && rm -rf /knowstreaming/*.tar.gz \ - && ln -s /knowstreaming/maven/bin/mvn /usr/local/bin/mvn \ -# && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/${VERSION_KM}.zip \ - && git clone https://github.com/didi/KnowStreaming.git \ -# && unzip -o -q master.zip \ - && cd KnowStreaming && git checkout v${VERSION_KM} \ - && sed -i "/km-console/d" ./pom.xml \ - && mvn -U clean package -Dmaven.test.skip=true \ - && cd / && mkdir /app \ - && mv /knowstreaming/KnowStreaming/km-rest/target/ks-km.jar /app/app.jar \ - && rm -rf /knowstreaming/* /usr/local/bin/mvn \ - && yum erase -y git && yum clean all \ - && rm -rf /root/.m2 /tmp/* - -ENTRYPOINT ["/bin/bash","/start.sh"] - -HEALTHCHECK --interval=60s --timeout=60s CMD curl -f http://localhost/ks-km/api/v3/open/health || exit 1 diff --git a/km-dist/docker/knowstreaming-manage/conf/application.yml b/km-dist/docker/knowstreaming-manage/conf/application.yml deleted file mode 100644 index 80323cd0d..000000000 --- a/km-dist/docker/knowstreaming-manage/conf/application.yml +++ /dev/null @@ -1,107 +0,0 @@ -server: - port: 80 # 服务端口 - tomcat: - accept-count: 1000 - max-connections: 10000 - -spring: - application: - name: know-streaming - profiles: - active: dev - main: - allow-bean-definition-overriding: true - jackson: - time-zone: GMT+8 - datasource: - know-streaming: # know-streaming 自身数据库的配置 - jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - username: SERVER_MYSQL_USER - password: SERVER_MYSQL_PASSWORD - driver-class-name: org.mariadb.jdbc.Driver - maximum-pool-size: 20 - idle-timeout: 30000 - connection-test-query: SELECT 1 - logi-job: # know-streaming 依赖的 logi-job 模块的数据库的配置,默认与 know-streaming 的数据库配置保持一致即可 - jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - username: SERVER_MYSQL_USER - password: SERVER_MYSQL_PASSWORD - driver-class-name: org.mariadb.jdbc.Driver - max-lifetime: 60000 - init-sql: true - init-thread-num: 20 - max-thread-num: 50 - log-expire: 3 # 日志保存天数,以天为单位 - app-name: know-streaming - claim-strategy: com.didiglobal.logi.job.core.consensual.RandomConsensual - logi-security: # know-streaming 依赖的 logi-security 模块的数据库的配置,默认与 know-streaming 的数据库配置保持一致即可 - jdbc-url: jdbc:mariadb://SERVER_MYSQL_ADDRESS/SERVER_MYSQL_DB?useUnicode=true&characterEncoding=utf8&jdbcCompliantTruncation=true&allowMultiQueries=true&useSSL=false&alwaysAutoGeneratedKeys=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true - username: SERVER_MYSQL_USER - password: SERVER_MYSQL_PASSWORD - driver-class-name: org.mariadb.jdbc.Driver - app-name: know-streaming - resource-extend-bean-name: myResourceExtendImpl - login-extend-bean-name: logiSecurityDefaultLoginExtendImpl - -logging: - config: classpath:logback-spring.xml - -# 线程池大小相关配置 -thread-pool: - scheduled: - thread-num: 2 # @Scheduled任务的线程池大小,默认是一个 - - collector: # 采集模块的配置 - future-util: # 采集模块线程池配置 - num: 3 # 线程池个数 - thread-num: 64 # 每个线程池核心线程数 - queue-size: 10000 # 每个线程池队列大小 - select-suitable-enable: true # 任务是否自动选择合适的线程池,非主要,可不修改 - suitable-queue-size: 1000 # 线程池理想的队列大小,非主要,可不修改 - - task: # 任务模块的配置 - metrics: # metrics采集任务配置 - thread-num: 18 # metrics采集任务线程池核心线程数 - queue-size: 180 # metrics采集任务线程池队列大小 - metadata: # metadata同步任务配置 - thread-num: 27 # metadata同步任务线程池核心线程数 - queue-size: 270 # metadata同步任务线程池队列大小 - common: # 剩余其他任务配置 - thread-num: 15 # 剩余其他任务线程池核心线程数 - queue-size: 150 # 剩余其他任务线程池队列大小 - - -# 客户端池大小相关配置 -client-pool: - kafka-consumer: - min-idle-client-num: 2 # 最小空闲客户端数 - max-idle-client-num: 20 # 最大空闲客户端数 - max-total-client-num: 20 # 最大客户端数 - borrow-timeout-unit-ms: 5000 # 租借超时时间,单位秒 - - -# ES客户端配置 -es: - client: - address: SERVER_ES_ADDRESS - client-cnt: 10 - io-thread-cnt: 2 - max-retry-cnt: 5 - -# 普罗米修斯指标导出相关配置 -management: - endpoints: - web: - base-path: /metrics - exposure: - include: '*' - health: - elasticsearch: - enabled: false - metrics: - export: - prometheus: - descriptions: true - enabled: true - tags: - application: know-streaming \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-manage/init/start.sh b/km-dist/docker/knowstreaming-manage/init/start.sh deleted file mode 100644 index 79c5d77aa..000000000 --- a/km-dist/docker/knowstreaming-manage/init/start.sh +++ /dev/null @@ -1,7 +0,0 @@ -sed -i "s/SERVER_MYSQL_ADDRESS/${SERVER_MYSQL_ADDRESS}/g" /conf/application.yml -sed -i "s/SERVER_MYSQL_DB/${SERVER_MYSQL_DB}/g" /conf/application.yml -sed -i "s/SERVER_MYSQL_USER/${SERVER_MYSQL_USER}/g" /conf/application.yml -sed -i "s/SERVER_MYSQL_PASSWORD/${SERVER_MYSQL_PASSWORD}/g" /conf/application.yml -sed -i "s/SERVER_ES_ADDRESS/${SERVER_ES_ADDRESS}/g" /conf/application.yml - -java -server ${JAVA_OPTS} -XX:+UseStringDeduplication -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs -XX:ErrorFile=/logs/jvm/hs_err_pid%p.log -jar /app/app.jar --spring.config.location=/conf/application.yml \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/Dockerfile b/km-dist/docker/knowstreaming-mysql/Dockerfile deleted file mode 100644 index 95720f050..000000000 --- a/km-dist/docker/knowstreaming-mysql/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM mysql:5.7.39-oracle - -LABEL org.opencontainers.image.authors="haoqi123" - -EXPOSE 3306 - -ARG INIT_SOURCE_FILE=./sql/*.sql -ARG MYSQL_CNF_FILE=./conf/*.cnf -COPY ${INIT_SOURCE_FILE} /docker-entrypoint-initdb.d/ -COPY ${MYSQL_CNF_FILE} /etc/mysql/conf.d/ \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-mysql/conf/mysql.cnf b/km-dist/docker/knowstreaming-mysql/conf/mysql.cnf deleted file mode 100644 index 37c970108..000000000 --- a/km-dist/docker/knowstreaming-mysql/conf/mysql.cnf +++ /dev/null @@ -1,15 +0,0 @@ -[client] -default-character-set=utf8 -[mysql] -default-character-set=utf8 -[mysqld] -skip-host-cache -skip-name-resolve -datadir=/data/mysql -socket=/var/lib/mysql/mysql.sock -secure-file-priv=/var/lib/mysql-files -character-set-server=utf8 -user=mysql -symbolic-links=0 -pid-file=/var/run/mysqld/mysqld.pid -sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION \ No newline at end of file diff --git a/km-dist/docker/knowstreaming-web/Dockerfile b/km-dist/docker/knowstreaming-web/Dockerfile deleted file mode 100644 index 54b277db2..000000000 --- a/km-dist/docker/knowstreaming-web/Dockerfile +++ /dev/null @@ -1,86 +0,0 @@ -FROM docker.io/amd64/nginx:1.22 - -LABEL maintainer="haoqi123 <1148648445@qq.com>" - -WORKDIR /knowstreaming - -ARG VERSION_NODE=14.20.0 -ARG VERSION_KM=3.0.0-beta.2 - -# SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -RUN apt update \ - && apt install -y git unzip - -RUN echo 'server { \ - listen 80; \ - server_name localhost; \ - gzip on; \ - gzip_buffers 16 8k; \ - gzip_comp_level 4; \ - gzip_http_version 1.0; \ - gzip_min_length 1280; \ - gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xml+rss application/json application/javascript text/*; \ - gzip_vary on; \ - root /pub; \ - location / { \ - root /pub; \ - if ($request_filename ~* .*\.(?:htm|html|json)$) { \ - add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; \ - } \ - try_files $uri /layout/index.html; \ - } \ - location ~* \.(json)$ { \ - add_header Cache-Control no-cache; \ - } \ - location @kmfallback { \ - } \ - #location ~ ^/(clusters|config|cluster|login) { \ - # rewrite ^.*$ /; \ - #} \ - location ~ ^/ks-km/api/v3 { \ - #rewrite ^/ks-km/api/v3/(.*)$ /ks-km/ks-km/api/v3/$1 break; \ - proxy_pass http://knowstreaming-manager; \ - #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; \ - #proxy_cookie_path /ks-km/ /; \ - #proxy_set_header Host $host; \ - #proxy_set_header Referer $http_referer; \ - #proxy_set_header Cookie $http_cookie; \ - #proxy_set_header X-Real-Ip $remote_addr; \ - #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; \ - } \ - location ~ ^/logi-security/api/v1 { \ - #rewrite ^/logi-security/api/v1/(.*)$ /ks-km/logi-security/api/v1/$1 break; \ - proxy_pass http://knowstreaming-manager; \ - #proxy_pass https://api-kylin-xg02.intra.xiaojukeji.com; \ - } \ - location ~ ^/(401|403|404|500){ \ - rewrite ^.*$ /; \ - } \ - }' > /etc/nginx/conf.d/default.conf - -RUN curl -fsSLO --compressed "https://npm.taobao.org/mirrors/node/v${VERSION_NODE}/node-v${VERSION_NODE}-linux-x64.tar.gz" \ - && mkdir node/ \ - && tar -zxf "node-v${VERSION_NODE}-linux-x64.tar.gz" -C node/ --strip-components=1 --no-same-owner \ - && rm -rf /knowstreaming/*.tar.gz \ - && ln -s /knowstreaming/node/bin/node /usr/local/bin/node \ - && ln -s /knowstreaming/node/bin/npm /usr/local/bin/npm \ - && npm config set strict-ssl false \ - && npm config set registry https://registry.npm.taobao.org \ - && npm info underscore \ - && node --version \ - && npm --version \ - && curl -fsSLO --compressed https://github.com/didi/KnowStreaming/archive/refs/tags/v${VERSION_KM}.zip \ - && unzip -o -q v${VERSION_KM}.zip \ - && cd KnowStreaming-${VERSION_KM}/km-console \ - && npm install -g lerna && npm run i && npm run build \ - && mv /knowstreaming/KnowStreaming-${VERSION_KM}/km-rest/src/main/resources/templates /pub \ - && npm uninstall -g lerna \ - && cd / \ - && rm -rf /knowstreaming/* /usr/local/bin/node /usr/local/bin/npm \ - && apt remove -y git unzip && apt autoremove -y && apt remove --purge --auto-remove -y \ - && rm -rf /var/lib/apt/lists/* /tmp /root/.npm - -#ENTRYPOINT ["ls", "/ks_ui/km-console"] - -#CMD ["nginx", "-g", "daemon off;"] From e626b990904cb81436d522db23deb9ad6e00d1c4 Mon Sep 17 00:00:00 2001 From: haoqi <1148648445@qq.com> Date: Tue, 20 Sep 2022 19:30:20 +0800 Subject: [PATCH 32/53] =?UTF-8?q?1.=20=E5=88=A0=E9=99=A4km-dist/docker?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=EF=BC=8C=E4=BB=A5[=E5=8D=95?= =?UTF-8?q?=E6=9C=BA=E9=83=A8=E7=BD=B2=E6=89=8B=E5=86=8C.md]=E4=B8=BA?= =?UTF-8?q?=E5=87=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...50\347\275\262\346\211\213\345\206\214.md" | 43 +++++---- km-dist/docker/docker-compose.yml | 91 ------------------- 2 files changed, 26 insertions(+), 108 deletions(-) delete mode 100644 km-dist/docker/docker-compose.yml diff --git "a/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" "b/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" index 5110fa723..b429b9d5f 100644 --- "a/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" +++ "b/docs/install_guide/\345\215\225\346\234\272\351\203\250\347\275\262\346\211\213\345\206\214.md" @@ -94,9 +94,9 @@ helm pull knowstreaming/knowstreaming-manager version: "3" services: - + knowstreaming-manager: - image: haiti/knowstreaming-manager:0.1.0 + image: knowstreaming/knowstreaming-manager:0.2.0-test container_name: knowstreaming-manager privileged: true restart: always @@ -105,6 +105,9 @@ services: - knowstreaming-mysql expose: - 80 + command: + - /bin/sh + - /ks-start.sh environment: TZ: Asia/Shanghai @@ -117,12 +120,12 @@ services: JAVA_OPTS: -Xmx1g -Xms1g - # extra_hosts: - # - "hostname:x.x.x.x" - # volumes: - # - /Users/haoqi/Downloads/ks/manage/log:/logs +# extra_hosts: +# - "hostname:x.x.x.x" +# volumes: +# - /ks/manage/log:/logs knowstreaming-ui: - image: haiti/knowstreaming-ui:0.1.0 + image: knowstreaming/knowstreaming-ui:0.2.0-test1 container_name: knowstreaming-ui restart: always ports: @@ -131,8 +134,8 @@ services: TZ: Asia/Shanghai depends_on: - knowstreaming-manager - # extra_hosts: - # - "hostname:x.x.x.x" +# extra_hosts: +# - "hostname:x.x.x.x" elasticsearch-single: image: docker.io/library/elasticsearch:7.6.2 @@ -141,38 +144,44 @@ services: expose: - 9200 - 9300 - # ports: - # - '9200:9200' - # - '9300:9300' +# ports: +# - '9200:9200' +# - '9300:9300' environment: TZ: Asia/Shanghai ES_JAVA_OPTS: -Xms512m -Xmx512m discovery.type: single-node - # volumes: - # - /Users/haoqi/Downloads/ks/es/data:/usr/share/elasticsearch/data +# volumes: +# - /ks/es/data:/usr/share/elasticsearch/data knowstreaming-init: - image: haiti/knowstreaming-init:0.1.0 + image: knowstreaming/knowstreaming-manager:0.2.0-test container_name: knowstreaming_init depends_on: - elasticsearch-single + command: + - /bin/bash + - /es_template_create.sh environment: TZ: Asia/Shanghai SERVER_ES_ADDRESS: elasticsearch-single:9200 knowstreaming-mysql: - image: haiti/knowstreaming-mysql:0.1.0 + image: knowstreaming/knowstreaming-mysql:0.2.0-test container_name: knowstreaming-mysql restart: always environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: admin2022_ MYSQL_DATABASE: know_streaming + MYSQL_ROOT_HOST: '%' expose: - 3306 +# ports: +# - '3306:3306' # volumes: -# - /Users/haoqi/Downloads/ks/mysql/data:/data/mysql +# - /ks/mysql/data:/data/mysql ```   diff --git a/km-dist/docker/docker-compose.yml b/km-dist/docker/docker-compose.yml deleted file mode 100644 index a9fe2bf30..000000000 --- a/km-dist/docker/docker-compose.yml +++ /dev/null @@ -1,91 +0,0 @@ -version: "3" - -services: - - knowstreaming-manager: - image: knowstreaming/knowstreaming-manager:0.2.0-test - container_name: knowstreaming-manager - privileged: true - restart: always - depends_on: - - elasticsearch-single - - knowstreaming-mysql - expose: - - 80 - command: - - /bin/sh - - /ks-start.sh - environment: - TZ: Asia/Shanghai - - SERVER_MYSQL_ADDRESS: knowstreaming-mysql:3306 - SERVER_MYSQL_DB: know_streaming - SERVER_MYSQL_USER: root - SERVER_MYSQL_PASSWORD: admin2022_ - - SERVER_ES_ADDRESS: elasticsearch-single:9200 - - JAVA_OPTS: -Xmx1g -Xms1g - -# extra_hosts: -# - "hostname:x.x.x.x" -# volumes: -# - /ks/manage/log:/logs - knowstreaming-ui: - image: knowstreaming/knowstreaming-ui:0.2.0-test1 - container_name: knowstreaming-ui - restart: always - ports: - - '18092:80' - environment: - TZ: Asia/Shanghai - depends_on: - - knowstreaming-manager -# extra_hosts: -# - "hostname:x.x.x.x" - - elasticsearch-single: - image: docker.io/library/elasticsearch:7.6.2 - container_name: elasticsearch-single - restart: always - expose: - - 9200 - - 9300 -# ports: -# - '9200:9200' -# - '9300:9300' - environment: - TZ: Asia/Shanghai - ES_JAVA_OPTS: -Xms512m -Xmx512m - discovery.type: single-node -# volumes: -# - /ks/es/data:/usr/share/elasticsearch/data - - knowstreaming-init: - image: knowstreaming/knowstreaming-manager:0.2.0-test - container_name: knowstreaming_init - depends_on: - - elasticsearch-single - command: - - /bin/bash - - /es_template_create.sh - environment: - TZ: Asia/Shanghai - SERVER_ES_ADDRESS: elasticsearch-single:9200 - - - knowstreaming-mysql: - image: knowstreaming/knowstreaming-mysql:0.2.0-test - container_name: knowstreaming-mysql - restart: always - environment: - TZ: Asia/Shanghai - MYSQL_ROOT_PASSWORD: admin2022_ - MYSQL_DATABASE: know_streaming - MYSQL_ROOT_HOST: '%' - expose: - - 3306 -# ports: -# - '3306:3306' -# volumes: -# - /ks/mysql/data:/data/mysql \ No newline at end of file From 1d3caeea7d022cfd587a18c61d17a2497da09c43 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Wed, 21 Sep 2022 16:11:14 +0800 Subject: [PATCH 33/53] =?UTF-8?q?feat:=20Cluster=20=E5=9B=BE=E8=A1=A8?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=94=BE=E5=A4=A7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DetailChart/index.less | 138 +++++++----------- .../SingleClusterDetail/DetailChart/index.tsx | 88 ++++------- .../src/pages/SingleClusterDetail/index.less | 3 +- .../src/pages/SingleClusterDetail/index.tsx | 8 +- 4 files changed, 88 insertions(+), 149 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.less b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.less index 6a1dfd38e..e52fa78fa 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.less @@ -1,53 +1,20 @@ -.cluster-container-border { - background: #ffffff; +.cluster-detail-container-border { + background: #fff; box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.01), 0 3px 6px 3px rgba(0, 0, 0, 0.01), 0 2px 6px 0 rgba(0, 0, 0, 0.03); border-radius: 12px; } .cluster-detail-container { - width: 100%; - - &-header { - display: flex; - align-items: center; - height: 36px; - - .refresh-icon-box { - display: flex; - justify-content: center; - align-items: center; - width: 22px; - height: 22px; - border-radius: 50%; - cursor: pointer; - - .refresh-icon { - font-size: 14px; - color: #74788d; - } - - &:hover { - background: #21252904; - - .refresh-icon { - color: #495057; - } - } - } - } - &-main { .header-chart-container { - width: 100%; height: 244px; margin-bottom: 12px; - .cluster-container-border(); + .cluster-detail-container-border(); .dcloud-spin.dcloud-spin-spinning { display: flex; justify-content: center; align-items: center; - width: 100%; - height: 244px; + height: 100%; } } @@ -61,7 +28,7 @@ flex: 1; height: 100%; overflow: hidden; - .cluster-container-border(); + .cluster-detail-container-border(); > div { width: 100%; height: 100%; @@ -73,65 +40,64 @@ justify-content: center; align-items: center; } - - .chart-box { - position: relative; - width: 100%; - height: 244px; - background: #f8f9fa; - border-radius: 8px; - - .expand-icon-box { - position: absolute; - z-index: 1000; - top: 14px; - right: 16px; - width: 24px; - height: 24px; - cursor: pointer; - font-size: 16px; - text-align: center; - border-radius: 50%; - transition: background-color 0.3s ease; - - .expand-icon { - color: #adb5bc; - line-height: 24px; - } - - &:hover { - background: rgba(33, 37, 41, 0.06); - .expand-icon { - color: #74788d; - } - } - } - } } .config-change-records-container { width: 240px; height: 100%; margin-left: 12px; - .cluster-container-border(); + .cluster-detail-container-border(); } } } +} - .chart-box-title { - padding: 18px 0 0 20px; - font-family: @font-family-bold; - line-height: 16px; - .name { - font-size: 14px; - color: #212529; - } - .unit { - font-size: 12px; - color: #495057; +.cluster-detail-chart-box { + position: relative; + width: 100%; + height: 244px; + background: #f8f9fa; + border-radius: 8px; + + .expand-icon-box { + position: absolute; + z-index: 1000; + top: 14px; + right: 16px; + width: 24px; + height: 24px; + cursor: pointer; + font-size: 16px; + text-align: center; + border-radius: 50%; + transition: background-color 0.3s ease; + + .expand-icon { + color: #adb5bc; + line-height: 24px; } - > span { - cursor: pointer; + + &:hover { + background: rgba(33, 37, 41, 0.06); + .expand-icon { + color: #74788d; + } } } } +.cluster-detail-chart-box-title { + padding: 18px 0 0 20px; + font-family: @font-family-bold; + line-height: 16px; + .name { + font-size: 14px; + color: #212529; + } + .unit { + font-size: 12px; + color: #495057; + } + > span { + cursor: pointer; + } +} diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx index 6ecb7604e..db241e4e2 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/DetailChart/index.tsx @@ -15,6 +15,7 @@ import { getDataNumberUnit, getUnit } from '@src/constants/chartConfig'; import SingleChartHeader, { KsHeaderOptions } from '@src/components/SingleChartHeader'; import { MAX_TIME_RANGE_WITH_SMALL_POINT_INTERVAL } from '@src/constants/common'; import RenderEmpty from '@src/components/RenderEmpty'; +import DragGroup from '@src/components/DragGroup'; type ChartFilterOptions = Omit; interface MetricInfo { @@ -279,7 +280,7 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => { }, []); return ( -
+
{ {messagesInMetricData.data && ( <> -
+
{ @@ -354,14 +355,25 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
- - {metricDataList.length ? ( - metricDataList.map((data: any, i: number) => { - const { metricName, metricUnit, metricLines } = data; - return ( - -
-
+ {metricDataList.length ? ( +
+ 0, + onSortEnd: () => 0, + axis: 'xy', + useDragHandle: false, + }} + gridProps={{ + span: 12, + gutter: [16, 16], + }} + > + {metricDataList.map((data: any, i: number) => { + const { metricName, metricUnit, metricLines } = data; + return ( +
+
{ @@ -379,15 +391,6 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
-
{ - setChartDetail(data); - setShowChartDetailModal(true); - }} - > - -
{ })} />
- - ); - }) - ) : chartLoading ? ( - <> - ) : ( - - )} - + ); + })} +
+
+ ) : chartLoading ? ( + <> + ) : ( + + )}
@@ -421,35 +424,6 @@ const DetailChart = (props: { children: JSX.Element }): JSX.Element => {
{props.children}
- - {/* 图表详情 */} - setShowChartDetailModal(false)} - > -
-
setShowChartDetailModal(false)}> - -
- {chartDetail && ( - - )} -
-
); }; diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less index 7baae7b8c..3fa013deb 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.less @@ -231,9 +231,10 @@ } .chart-panel { - flex: 1; + flex: auto; margin-left: 12px; margin-right: 10px; + overflow: hidden; } .change-log-panel { diff --git a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx index e4b4b2c69..59e679b39 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/SingleClusterDetail/index.tsx @@ -21,11 +21,9 @@ const SingleClusterDetail = (): JSX.Element => {
-
- - - -
+ + +
From d83d35aee93a39708857ff8419b995cd0b242215 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Wed, 21 Sep 2022 16:12:13 +0800 Subject: [PATCH 34/53] =?UTF-8?q?fix:=20=E6=A0=B7=E5=BC=8F=20&=20=E6=96=87?= =?UTF-8?q?=E6=A1=88=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-console/packages/layout-clusters-fe/src/locales/zh.tsx | 3 +-- .../layout-clusters-fe/src/pages/Consumers/index.less | 4 ++++ .../layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx | 4 ++-- .../layout-clusters-fe/src/pages/LoadRebalance/index.tsx | 2 +- .../src/pages/MutliClusterPage/AccessCluster.tsx | 6 +++--- .../layout-clusters-fe/src/pages/TopicList/Create.tsx | 4 ++-- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/locales/zh.tsx b/km-console/packages/layout-clusters-fe/src/locales/zh.tsx index db190ffc9..85c9014b3 100755 --- a/km-console/packages/layout-clusters-fe/src/locales/zh.tsx +++ b/km-console/packages/layout-clusters-fe/src/locales/zh.tsx @@ -21,7 +21,6 @@ export default { [`menu.${systemKey}.cluster`]: 'Cluster', [`menu.${systemKey}.cluster.overview`]: 'Overview', - [`menu.${systemKey}.cluster.balance`]: 'Load Rebalance', [`menu.${systemKey}.broker`]: 'Broker', [`menu.${systemKey}.broker.dashbord`]: 'Overview', @@ -45,7 +44,7 @@ export default { [`menu.${systemKey}.consumer-group.group-list`]: 'GroupList', [`menu.${systemKey}.operation`]: 'Operation', - [`menu.${systemKey}.operation.balance`]: 'Load Rebalance', + [`menu.${systemKey}.operation.balance`]: 'Rebalance', [`menu.${systemKey}.operation.jobs`]: 'Job', [`menu.${systemKey}.acls`]: 'ACLs', diff --git a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.less b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.less index 09af80b82..2ff718b75 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/Consumers/index.less @@ -53,6 +53,10 @@ align-items: center; .d-range-time-input { height: 27px !important; + padding: 0 11px; + input{ + line-height: 100%; + } } .divider { width: 1px; diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx index 4b11b2e7c..024fced33 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/RebalancePlan.tsx @@ -13,8 +13,8 @@ interface PropsType { } const typeObj: any = { - 1: '周期均衡', - 2: '立即均衡', + 1: '立即均衡', + 2: '周期均衡', }; const { request, post } = Utils; diff --git a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/index.tsx index 2ff2b9605..1a7b035fc 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/LoadRebalance/index.tsx @@ -330,7 +330,7 @@ const LoadBalance: React.FC = (props: any) => { breadcrumbs={[ { label: '多集群管理', aHref: '/' }, { label: global?.clusterInfo?.name, aHref: `/cluster/${global?.clusterInfo?.id}` }, - { label: 'Load Rebalance', aHref: `` }, + { label: 'Rebalance', aHref: `` }, ]} />
diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index 908c2f57c..6ca8666c3 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -202,7 +202,7 @@ const AccessClusters = (props: any): JSX.Element => { } if (modifyKey) { - extraMsg[modifyKey] = `连接失败。${message}`; + extraMsg[modifyKey] = message; } }); @@ -338,7 +338,7 @@ const AccessClusters = (props: any): JSX.Element => { {extra.bootstrapExtra}} + extra={{extra.bootstrapExtra}} validateTrigger={'onBlur'} rules={[ { @@ -374,7 +374,7 @@ const AccessClusters = (props: any): JSX.Element => { {extra.zooKeeperExtra}} + extra={{extra.zooKeeperExtra}} validateStatus={zookeeperErrorStatus ? 'error' : 'success'} validateTrigger={'onBlur'} rules={[ diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx index 218b0754b..288b99c77 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/Create.tsx @@ -218,10 +218,10 @@ export default (props: any) => {
- + - +
From 30fba21c481b0d53b7629815ebfd9a0a1249dae1 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Wed, 21 Sep 2022 16:15:19 +0800 Subject: [PATCH 35/53] =?UTF-8?q?fix:=20=E7=94=9F=E4=BA=A7=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=8D=95=E8=AF=8D=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=95=B0=E9=99=90=E5=88=B6=E4=B8=BA=200~1000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/pages/TestingProduce/config.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx index 81503271f..97589f322 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingProduce/config.tsx @@ -152,6 +152,7 @@ export const getFormConfig = (params: any) => { rules: [{ required: true, message: '请输入' }], attrs: { min: 0, + max: 1000, style: { width: 232 }, }, }, @@ -391,7 +392,7 @@ export const getTableColumns = () => { { title: 'time', dataIndex: 'costTimeUnitMs', - width: 60, + width: 100, }, ]; }; From 8749d3e1f56415c78dd07db45254a011c8b310a7 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Wed, 21 Sep 2022 16:21:07 +0800 Subject: [PATCH 36/53] =?UTF-8?q?fix:=20config=20=E5=AD=90=E5=BA=94?= =?UTF-8?q?=E7=94=A8=20axios=20=E9=85=8D=E7=BD=AE=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packages/config-manager-fe/src/constants/axiosConfig.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts index f08ebc777..3e05e105d 100644 --- a/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts +++ b/km-console/packages/config-manager-fe/src/constants/axiosConfig.ts @@ -47,8 +47,8 @@ serviceInstance.interceptors.response.use( return res; }, (err: any) => { - const config = err.config; - if (!config || !config.retryTimes) return dealResponse(err, config.customNotification); + const config = err?.config; + if (!config || !config.retryTimes) return dealResponse(err); const { __retryCount = 0, retryDelay = 300, retryTimes } = config; config.__retryCount = __retryCount; if (__retryCount >= retryTimes) { From d67e383c2832c88fff3c10653193247875d2d535 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Wed, 21 Sep 2022 16:21:57 +0800 Subject: [PATCH 37/53] =?UTF-8?q?feat:=20=E7=B3=BB=E7=BB=9F=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=88=97=E8=A1=A8=E5=A2=9E=E5=8A=A0=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ConfigManage/index.tsx | 39 +++++----- .../src/pages/OperationLog/index.tsx | 48 +++++++------ .../src/pages/UserManage/RoleTabContent.tsx | 71 ++++++++++--------- .../src/pages/UserManage/UserTabContent.tsx | 40 ++++++----- .../src/pages/UserManage/index.less | 10 --- 5 files changed, 114 insertions(+), 94 deletions(-) diff --git a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx index 84b5d2f6e..762661f9a 100644 --- a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx @@ -15,6 +15,7 @@ import { AppContainer, Utils, } from 'knowdesign'; +import { IconFont } from '@knowdesign/icons'; import { PlusOutlined } from '@ant-design/icons'; import moment from 'moment'; // 引入代码编辑器 @@ -431,22 +432,28 @@ export default () => {
- getConfigList({ page: 1 })}> - - - - - - - - - - +
+
getConfigList()}> + +
+ +
getConfigList({ page: 1 })}> + + + + + + + + + +
+
{global.hasPermission && global.hasPermission(ConfigPermissionMap.CONFIG_ADD) ? ( - - +
+
getData()}> + +
+ + +
getData({ page: 1 })}> + + + + + + + + + + + + +
+
{ return ( <> -
- { - setSearchKeywords(searchKeywordsInput); - }} - style={{ fontSize: '16px' }} - /> - } - placeholder="请输入角色名称" - value={searchKeywordsInput} - onPressEnter={(_) => { - setSearchKeywords(searchKeywordsInput); - }} - onChange={(e) => { - setSearchKeywordsInput(e.target.value); - }} - /> - {global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? ( - - ) : ( - <> - )} +
+
+
getRoleList()}> + +
+
+
+ { + setSearchKeywords(searchKeywordsInput); + }} + style={{ fontSize: '16px' }} + /> + } + placeholder="请输入角色名称" + value={searchKeywordsInput} + onPressEnter={(_) => { + setSearchKeywords(searchKeywordsInput); + }} + onChange={(e) => { + setSearchKeywordsInput(e.target.value); + }} + /> + {global.hasPermission && global.hasPermission(ConfigPermissionMap.ROLE_ADD) ? ( + + ) : ( + <> + )} +
{ return ( <>
-
getUserList({ page: 1 })}> - - - - - - - - + + + + + + { }} onPressEnter={searchFn} /> - - { }} onPressEnter={searchFn} /> - +
{/* */}
-
+ {/*
*/}
)} {/* diff --git a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx index 84e702986..5432b4344 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/Jobs/index.tsx @@ -1,6 +1,6 @@ import React, { useState, useEffect, memo } from 'react'; import { useParams, useHistory, useLocation } from 'react-router-dom'; -import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, message, Modal } from 'knowdesign'; +import { ProTable, Drawer, Utils, AppContainer, Form, Select, Input, Button, message, Modal, IconFont, Divider } from 'knowdesign'; import API from '../../api'; import { getJobsListColumns, defaultPagination, runningStatus, jobType } from './config'; import JobsCheck from '@src/components/CardBar/JobsCheck'; @@ -10,6 +10,7 @@ import './index.less'; import ReplicaChange from '@src/components/TopicJob/ReplicaChange'; import ReplicaMove from '@src/components/TopicJob/ReplicaMove'; import BalanceDrawer from '../LoadRebalance/BalanceDrawer'; +import { tableHeaderPrefix } from '@src/constants/common'; const { request } = Utils; const JobsList: React.FC = (props: any) => { @@ -171,35 +172,44 @@ const JobsList: React.FC = (props: any) => { {/* */}
-
- - - - - - + + + + + + @@ -354,8 +365,7 @@ const LoadBalance: React.FC = (props: any) => { */} - -
+
{
-
-
getACLs({ page: 1 })}> - - - - - - - - - - - +
+
+
getACLs()}> + +
+ +
getACLs({ page: 1 })}> + + + + + + + + + + +
+
+ +
{ const maxPos = chars.length; @@ -426,34 +427,41 @@ const SecurityUsers = (): JSX.Element => { ]} />
-
- { - setSearchKeywords(searchKeywordsInput); - }} - style={{ fontSize: '16px' }} - /> - } - placeholder="请输入 Kafka User" - value={searchKeywordsInput} - onPressEnter={(_) => { - setSearchKeywords(searchKeywordsInput); - }} - onChange={(e) => { - setSearchKeywordsInput(e.target.value); - }} - /> - +
+
+
getKafkaUserList()}> + +
+
+
+ { + setSearchKeywords(searchKeywordsInput); + }} + style={{ fontSize: '16px' }} + /> + } + placeholder="请输入 Kafka User" + value={searchKeywordsInput} + onPressEnter={(_) => { + setSearchKeywords(searchKeywordsInput); + }} + onChange={(e) => { + setSearchKeywordsInput(e.target.value); + }} + /> + +
span { - margin-left: 4px; - color: #74788d; - } - } - } - .right { - display: flex; - align-items: center; - .dcloud-form-item { - margin-bottom: 0; - } - .search-input { - width: 248px; - margin-right: 8px; - } - .search-input-short { - width: 120px; - margin-right: 8px; - } - .batch-btn { - margin-right: 8px; - } - .add-btn { - width: 117px; - } + > span { + margin-left: 4px; + color: #74788d; } } .operation-list { diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.tsx index 5bce3d6ce..692da9c25 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicList/index.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/display-name */ import React, { useState, useEffect } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { AppContainer, IconFont, Input, ProTable, Select, Switch, Tooltip, Utils, Dropdown, Menu, Button } from 'knowdesign'; +import { AppContainer, IconFont, Input, ProTable, Select, Switch, Tooltip, Utils, Dropdown, Menu, Button, Divider } from 'knowdesign'; import Create from './Create'; import './index.less'; import Api from '@src/api/index'; @@ -16,6 +16,7 @@ import SmallChart from '@src/components/SmallChart'; import ReplicaMove from '@src/components/TopicJob/ReplicaMove'; import { formatAssignSize } from '../Jobs/config'; import { DownOutlined } from '@ant-design/icons'; +import { tableHeaderPrefix } from '@src/constants/common'; const { Option } = Select; @@ -66,6 +67,7 @@ const AutoPage = (props: any) => { // params.sortField = sortObj.sortField; // params.sortType = sortObj.sortType || 'desc'; // } + setTopicListLoading(true); Utils.post(Api.getTopicsList(Number(routeParams.clusterId)), params) .then((data: any) => { setTopicListLoading(false); @@ -79,7 +81,6 @@ const AutoPage = (props: any) => { }); }; useEffect(() => { - setTopicListLoading(true); getTopicsList(); }, [sortObj, showInternalTopics, searchKeywords, pageIndex, pageSize]); @@ -285,26 +286,17 @@ const AutoPage = (props: any) => {
-
-
+
+
{/* 批量扩缩副本 */} {/* 批量迁移 */} - {/* */} - {/* - - */} - {/*
*/} + +
getTopicsList()}> + +
+
{ 展示系统Topic
-
+
Date: Thu, 22 Sep 2022 15:19:03 +0800 Subject: [PATCH 45/53] =?UTF-8?q?refactor:=20=E6=8E=A5=E5=85=A5/=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E9=9B=86=E7=BE=A4=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/MutliClusterPage/AccessCluster.tsx | 583 ++++++++---------- .../src/pages/MutliClusterPage/index.less | 60 +- 2 files changed, 277 insertions(+), 366 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx index 6ca8666c3..7435d9a77 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/AccessCluster.tsx @@ -6,9 +6,8 @@ import { regClusterName, regUsername } from '@src/constants/reg'; import { bootstrapServersErrCodes, jmxErrCodes, zkErrCodes } from './config'; import CodeMirrorFormItem from '@src/components/CodeMirrorFormItem'; -const rows = 4; -const lowKafkaVersion = '2.8.0'; -const clientPropertiesPlaceholder = `用于创建Kafka客户端进行信息获取的相关配置, +const LOW_KAFKA_VERSION = '2.8.0'; +const CLIENT_PROPERTIES_PLACEHOLDER = `用于创建Kafka客户端进行信息获取的相关配置, 例如开启SCRAM-SHA-256安全管控模式的集群需输入如下配置, 未开启安全管控可不进行任何输入: { @@ -26,37 +25,25 @@ const AccessClusters = (props: any): JSX.Element => { const intl = useIntl(); const [form] = Form.useForm(); const [loading, setLoading] = React.useState(false); + const [confirmLoading, setConfirmLoading] = React.useState(false); const [curClusterInfo, setCurClusterInfo] = React.useState({}); - const [security, setSecurity] = React.useState(curClusterInfo?.security || 'None'); const [extra, setExtra] = React.useState({ versionExtra: '', zooKeeperExtra: '', bootstrapExtra: '', jmxExtra: '', }); - const [isLowVersion, setIsLowVersion] = React.useState(false); - const [zookeeperErrorStatus, setZookeeperErrorStatus] = React.useState(false); const lastFormItemValue = React.useRef({ - bootstrap: curClusterInfo?.bootstrapServers || '', + bootstrapServers: curClusterInfo?.bootstrapServers || '', zookeeper: curClusterInfo?.zookeeper || '', clientProperties: curClusterInfo?.clientProperties || {}, }); - const onHandleValuesChange = (value: any, allValues: any) => { - Object.keys(value).forEach((key) => { + const onHandleValuesChange = (changedValue: string[]) => { + Object.keys(changedValue).forEach((key) => { switch (key) { - case 'security': - setSecurity(value.security); - break; case 'zookeeper': - setExtra({ - ...extra, - zooKeeperExtra: '', - bootstrapExtra: '', - jmxExtra: '', - }); - break; case 'bootstrapServers': setExtra({ ...extra, @@ -78,21 +65,19 @@ const AccessClusters = (props: any): JSX.Element => { const onCancel = () => { form.resetFields(); setLoading(false); - setZookeeperErrorStatus(false); - setIsLowVersion(false); - setSecurity('None'); setExtra({ versionExtra: '', zooKeeperExtra: '', bootstrapExtra: '', jmxExtra: '', }); - lastFormItemValue.current = { bootstrap: '', zookeeper: '', clientProperties: {} }; + lastFormItemValue.current = { bootstrapServers: '', zookeeper: '', clientProperties: {} }; props.setVisible && props.setVisible(false); }; const onSubmit = () => { form.validateFields().then((res) => { + setConfirmLoading(true); let clientProperties = null; try { clientProperties = res.clientProperties && JSON.parse(res.clientProperties); @@ -107,7 +92,7 @@ const AccessClusters = (props: any): JSX.Element => { jmxProperties: { jmxPort: res.jmxPort, maxConn: res.maxConn, - openSSL: res.security === 'Password', + openSSL: res.openSSL || false, token: res.token, username: res.username, }, @@ -115,7 +100,7 @@ const AccessClusters = (props: any): JSX.Element => { name: res.name, zookeeper: res.zookeeper || '', }; - setLoading(true); + if (!isNaN(curClusterInfo?.id)) { Utils.put(api.phyCluster, { ...params, @@ -127,7 +112,7 @@ const AccessClusters = (props: any): JSX.Element => { onCancel(); }) .finally(() => { - setLoading(false); + setConfirmLoading(false); }); } else { Utils.post(api.phyCluster, params) @@ -137,7 +122,7 @@ const AccessClusters = (props: any): JSX.Element => { onCancel(); }) .finally(() => { - setLoading(false); + setConfirmLoading(false); }); } }); @@ -154,125 +139,224 @@ const AccessClusters = (props: any): JSX.Element => { } setLoading(true); - setIsLowVersion(false); - setZookeeperErrorStatus(false); return Utils.post(api.kafkaValidator, { bootstrapServers: bootstrapServers || '', zookeeper: zookeeper || '', clientProperties, }) - .then((res: any) => { - form.setFieldsValue({ - jmxPort: res.jmxPort, - }); - - if (props.kafkaVersion.indexOf(res.kafkaVersion) > -1) { - form.setFieldsValue({ - kafkaVersion: res.kafkaVersion, - }); - } else { - form.setFieldsValue({ - kafkaVersion: undefined, - }); - } - - form.setFieldsValue({ - zookeeper: zookeeper || res.zookeeper, - }); - - const errList = res.errList || []; - - const extraMsg = extra; + .then( + (res: { + errList: { code: number; message: string; data: any }[]; + jmxPort: number | null; + kafkaVersion: string | null; + zookeeper: string | null; + }) => { + const changedValue: { jmxPort?: number; kafkaVersion?: string; zookeeper: string } = { + zookeeper: zookeeper || res.zookeeper, + }; + if (res.kafkaVersion && props.kafkaVersion.includes(res.kafkaVersion)) { + changedValue.kafkaVersion = res.kafkaVersion; + } + if (res.jmxPort) { + changedValue.jmxPort = res.jmxPort; + } + form.setFieldsValue(changedValue); - // 初始化信息为连接成功 - extraMsg.bootstrapExtra = bootstrapServers ? '连接成功' : ''; - extraMsg.zooKeeperExtra = zookeeper ? '连接成功' : ''; + const extraMsg = { + ...extra, + // 重置默认信息为连接成功 + bootstrapExtra: bootstrapServers ? '连接成功' : '', + zooKeeperExtra: zookeeper ? '连接成功' : '', + }; - // 处理错误信息 - errList.forEach((item: any) => { - const { code, message } = item; - let modifyKey: 'bootstrapExtra' | 'zooKeeperExtra' | 'jmxExtra' | undefined; - if (bootstrapServersErrCodes.includes(code)) { - modifyKey = 'bootstrapExtra'; - } else if (zkErrCodes.includes(code)) { - modifyKey = 'zooKeeperExtra'; - } else if (jmxErrCodes.includes(code)) { - modifyKey = 'jmxExtra'; - } + const errList = res.errList || []; + // 处理错误信息 + errList.forEach((item: any) => { + const { code, message } = item; + let modifyKey: 'bootstrapExtra' | 'zooKeeperExtra' | 'jmxExtra' | undefined; + if (bootstrapServersErrCodes.includes(code)) { + modifyKey = 'bootstrapExtra'; + } else if (zkErrCodes.includes(code)) { + modifyKey = 'zooKeeperExtra'; + } else if (jmxErrCodes.includes(code)) { + modifyKey = 'jmxExtra'; + } - if (modifyKey) { - extraMsg[modifyKey] = message; - } - }); + if (modifyKey) { + extraMsg[modifyKey] = message; + } + }); - // 如果kafkaVersion小于最低版本则提示 - const showLowVersion = !( - curClusterInfo?.zookeeper || - !curClusterInfo?.kafkaVersion || - curClusterInfo?.kafkaVersion >= lowKafkaVersion - ); - setIsLowVersion(showLowVersion); - setExtra({ - ...extraMsg, - versionExtra: showLowVersion ? intl.formatMessage({ id: 'access.cluster.low.version.tip' }) : '', - }); - return res; - }) + setExtra(extraMsg); + return res; + } + ) .finally(() => { setLoading(false); }); }; + // 更新表单状态 React.useEffect(() => { - const showLowVersion = !(curClusterInfo?.zookeeper || !curClusterInfo?.kafkaVersion || curClusterInfo?.kafkaVersion >= lowKafkaVersion); lastFormItemValue.current = { - bootstrap: curClusterInfo?.bootstrapServers || '', + bootstrapServers: curClusterInfo?.bootstrapServers || '', zookeeper: curClusterInfo?.zookeeper || '', clientProperties: curClusterInfo?.clientProperties || {}, }; - setIsLowVersion(showLowVersion); - setExtra({ - ...extra, - versionExtra: showLowVersion ? intl.formatMessage({ id: 'access.cluster.low.version.tip' }) : '', - }); form.setFieldsValue({ ...curClusterInfo }); + if (curClusterInfo?.kafkaVersion) { + form.validateFields(['kafkaVersion']); + } }, [curClusterInfo]); + // 获取集群详情数据 React.useEffect(() => { if (visible) { if (clusterInfo?.id) { setLoading(true); - Utils.request(api.getPhyClusterBasic(clusterInfo.id)) - .then((res: any) => { - let jmxProperties = null; - try { - jmxProperties = JSON.parse(res?.jmxProperties); - } catch (err) { - console.error(err); - } - // 转化值对应成表单值 - if (jmxProperties?.openSSL) { - jmxProperties.security = 'Password'; + const resolveJmxProperties = (obj: any) => { + const res = { ...obj }; + try { + const originValue = obj?.jmxProperties; + if (originValue) { + const jmxProperties = JSON.parse(originValue); + typeof jmxProperties === 'object' && jmxProperties !== null && Object.assign(res, jmxProperties); } + } catch (err) { + console.error('jmxProperties not JSON: ', err); + } + return res; + }; - if (jmxProperties) { - res = Object.assign({}, res || {}, jmxProperties); - } - setCurClusterInfo(res); - setLoading(false); + Utils.request(api.getPhyClusterBasic(clusterInfo.id)) + .then((res: any) => { + setCurClusterInfo(resolveJmxProperties(res)); }) .catch((err) => { - setCurClusterInfo(clusterInfo); + setCurClusterInfo(resolveJmxProperties(clusterInfo)); + }) + .finally(() => { setLoading(false); }); } else { - setCurClusterInfo(clusterInfo); + setCurClusterInfo({}); } } }, [visible, clusterInfo]); + const validators = { + name: async (_: any, value: string) => { + if (!value) { + return Promise.reject('集群名称不能为空'); + } + if (value === curClusterInfo?.name) { + return Promise.resolve(); + } + if (value?.length > 128) { + return Promise.reject('集群名称长度限制在1~128字符'); + } + if (!new RegExp(regClusterName).test(value)) { + return Promise.reject('集群名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~'); + } + return Utils.request(api.getClusterBasicExit(value)) + .then((res: any) => { + const data = res || {}; + return data?.exist ? Promise.reject('集群名称重复') : Promise.resolve(); + }) + .catch(() => Promise.reject('连接超时! 请重试或检查服务')); + }, + bootstrapServers: async (_: any, value: string) => { + if (!value) { + return Promise.reject('Bootstrap Servers不能为空'); + } + if (value.length > 2000) { + return Promise.reject('Bootstrap Servers长度限制在2000字符'); + } + if (value && value !== lastFormItemValue.current.bootstrapServers) { + lastFormItemValue.current.bootstrapServers = value; + return connectTest().catch(() => (lastFormItemValue.current.bootstrapServers = '')); + } + return Promise.resolve(''); + }, + zookeeper: async (_: any, value: string) => { + if (!value) { + return Promise.resolve(''); + } + + if (value.length > 2000) { + return Promise.reject('Zookeeper长度限制在2000字符'); + } + + if (value && value !== lastFormItemValue.current.zookeeper) { + lastFormItemValue.current.zookeeper = value; + return connectTest().catch(() => (lastFormItemValue.current.zookeeper = '')); + } + return Promise.resolve(''); + }, + securityUserName: async (_: any, value: string) => { + if (!value) { + return Promise.reject('用户名不能为空'); + } + if (!new RegExp(regUsername).test(value)) { + return Promise.reject('仅支持大小写、下划线、短划线(-)'); + } + if (value.length > 128) { + return Promise.reject('用户名长度限制在1~128字符'); + } + return Promise.resolve(); + }, + securityToken: async (_: any, value: string) => { + if (!value) { + return Promise.reject('密码不能为空'); + } + if (!new RegExp(regUsername).test(value)) { + return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); + } + if (value.length < 6 || value.length > 32) { + return Promise.reject('密码长度限制在6~32字符'); + } + return Promise.resolve(); + }, + kafkaVersion: async (_: any, value: any) => { + if (!value) { + return Promise.reject('版本号不能为空'); + } + // 检测版本号小于2.8.0,如果没有填zookeeper信息,才会提示 + const zookeeper = form.getFieldValue('zookeeper'); + let versionExtra = ''; + if (value < LOW_KAFKA_VERSION && !zookeeper) { + versionExtra = intl.formatMessage({ id: 'access.cluster.low.version.tip' }); + } + setExtra({ + ...extra, + versionExtra, + }); + return Promise.resolve(); + }, + clientProperties: async (_: any, value: string) => { + try { + if (value) { + JSON.parse(value); + } + + return Promise.resolve(); + } catch (e) { + return Promise.reject(new Error('输入内容必须为 JSON')); + } + }, + description: async (_: any, value: string) => { + if (!value) { + return Promise.resolve(''); + } + if (value && value.length > 200) { + return Promise.reject('集群描述长度限制在200字符'); + } + return Promise.resolve(); + }, + }; + return ( <> { -
} - title={intl.formatMessage({ id: props.title || 'access.cluster' })} + title={intl.formatMessage({ id: props.title || clusterInfo?.id ? 'edit.cluster' : 'access.cluster' })} visible={props.visible} placement="right" width={480} @@ -306,30 +390,7 @@ const AccessClusters = (props: any): JSX.Element => { rules={[ { required: true, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.reject('集群名称不能为空'); - } - if (value === curClusterInfo?.name) { - return Promise.resolve(); - } - if (value?.length > 128) { - return Promise.reject('集群名称长度限制在1~128字符'); - } - if (!new RegExp(regClusterName).test(value)) { - return Promise.reject( - '集群名称支持中英文、数字、特殊字符 ! " # $ % & \' ( ) * + , - . / : ; < = > ? @ [ ] ^ _ ` { | } ~' - ); - } - return Utils.request(api.getClusterBasicExit(value)).then((res: any) => { - const data = res || {}; - if (data?.exist) { - return Promise.reject('集群名称重复'); - } else { - return Promise.resolve(); - } - }); - }, + validator: validators.name, }, ]} > @@ -343,26 +404,7 @@ const AccessClusters = (props: any): JSX.Element => { rules={[ { required: true, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.reject('Bootstrap Servers不能为空'); - } - if (value.length > 2000) { - return Promise.reject('Bootstrap Servers长度限制在2000字符'); - } - if (value && value !== lastFormItemValue.current.bootstrap) { - return connectTest() - .then((res: any) => { - lastFormItemValue.current.bootstrap = value; - - return Promise.resolve(''); - }) - .catch((err) => { - return Promise.reject('连接失败'); - }); - } - return Promise.resolve(''); - }, + validator: validators.bootstrapServers, }, ]} > @@ -375,35 +417,10 @@ const AccessClusters = (props: any): JSX.Element => { name="zookeeper" label="Zookeeper" extra={{extra.zooKeeperExtra}} - validateStatus={zookeeperErrorStatus ? 'error' : 'success'} validateTrigger={'onBlur'} rules={[ { - required: false, - validator: async (rule: any, value: string) => { - if (!value) { - setZookeeperErrorStatus(false); - return Promise.resolve(''); - } - - if (value.length > 2000) { - return Promise.reject('Zookeeper长度限制在2000字符'); - } - - if (value && value !== lastFormItemValue.current.zookeeper) { - return connectTest() - .then((res: any) => { - lastFormItemValue.current.zookeeper = value; - setZookeeperErrorStatus(false); - return Promise.resolve(''); - }) - .catch((err) => { - setZookeeperErrorStatus(true); - return Promise.reject('连接失败'); - }); - } - return Promise.resolve(''); - }, + validator: validators.zookeeper, }, ]} > @@ -412,142 +429,65 @@ const AccessClusters = (props: any): JSX.Element => { placeholder="请输入Zookeeper地址,例如:192.168.0.1:2181,192.168.0.2:2181,192.168.0.2:2181/ks-kafka" /> - - <> - - - - - - - - - - None - Password Authentication - - - {security === 'Password' ? ( - <> - { - if (!value) { - return Promise.reject('用户名不能为空'); - } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('仅支持大小写、下划线、短划线(-)'); - } - if (value.length > 128) { - return Promise.reject('用户名长度限制在1~128字符'); - } - return Promise.resolve(); - }, - }, - ]} - > - + +
+
+ + + + + + +
+ + + None + Password Authentication + - { - if (!value) { - return Promise.reject('密码不能为空'); - } - if (!new RegExp(regUsername).test(value)) { - return Promise.reject('密码只能由大小写、下划线、短划线(-)组成'); - } - if (value.length < 6 || value.length > 32) { - return Promise.reject('密码长度限制在6~32字符'); - } - return Promise.resolve(); - }, - }, - ]} - > - + + {({ getFieldValue }) => { + return getFieldValue('openSSL') ? ( +
+ +
+ + + + + + +
+
+ ) : null; + }}
- - ) : null} +
+
{extra.versionExtra}} - validateStatus={isLowVersion ? 'error' : 'success'} rules={[ { required: true, - validator: async (rule: any, value: any) => { - if (!value) { - setIsLowVersion(true); - return Promise.reject('版本号不能为空'); - } - // 检测版本号小于2.8.0,如果没有填zookeeper信息,才会提示 - const zookeeper = form.getFieldValue('zookeeper'); - if (value < lowKafkaVersion && !zookeeper) { - setIsLowVersion(true); - setExtra({ - ...extra, - versionExtra: intl.formatMessage({ id: 'access.cluster.low.version.tip' }), - }); - return Promise.resolve(); - } - setIsLowVersion(false); - return Promise.resolve(); - }, + validator: validators.kafkaVersion, }, ]} > @@ -565,29 +505,15 @@ const AccessClusters = (props: any): JSX.Element => { label="集群配置" rules={[ { - required: false, - message: '请输入集群配置', + validator: validators.clientProperties, }, - () => ({ - validator(_, value) { - try { - if (value) { - JSON.parse(value); - } - - return Promise.resolve(); - } catch (e) { - return Promise.reject(new Error('输入内容必须为 JSON')); - } - }, - }), ]} >
{ form.setFieldsValue({ clientProperties }); form.validateFields(['clientProperties']); @@ -621,20 +547,11 @@ const AccessClusters = (props: any): JSX.Element => { label="集群描述" rules={[ { - required: false, - validator: async (rule: any, value: string) => { - if (!value) { - return Promise.resolve(''); - } - if (value && value.length > 200) { - return Promise.reject('集群描述长度限制在200字符'); - } - return Promise.resolve(); - }, + validator: validators.description, }, ]} > - + diff --git a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less index 3108c4c03..f459fd1ce 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less +++ b/km-console/packages/layout-clusters-fe/src/pages/MutliClusterPage/index.less @@ -656,43 +656,37 @@ color: @error-color; } } - .inline-item.dcloud-form-item { - display: -webkit-inline-box; - margin-right: 16px; - - &.adjust-height-style { - .dcloud-form-item-label { - padding: 0; - label { - height: 36px; - } - } - .dcloud-form-item-control { - &-input { - height: 36px; - } - } - } - - &.max-width-66 { - .dcloud-form-item-control { - max-width: 66%; - } + .horizontal-form-container { + padding-left: 16px; + .inline-items { + display: flex; + justify-content: space-between; } - - .dcloud-form-item-label { - margin-right: 12px; - - label { + .dcloud-form-item { + flex-direction: row; + align-items: center; + &-label { + padding: 0 12px 0 0; + font-size: 13px; font-family: @font-family; + color: #74788d; } } - } - - .no-item-control { - margin-bottom: 8px !important; - .dcloud-form-item-control { - display: none; + .metrics-form-item { + margin-top: 8px; + } + .user-info-form-items { + display: flex; + align-items: flex-start; + .user-info-label { + padding-top: 4px; + } + .inline-items { + flex: 0 0 80%; + .token-form-item { + margin-left: 16px; + } + } } } } From fc82999d458fda694f979cadc217b5077169703c Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Thu, 22 Sep 2022 15:19:56 +0800 Subject: [PATCH 46/53] =?UTF-8?q?fix:=20=E6=B6=88=E8=B4=B9=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20Message=20=E9=99=90=E5=88=B6=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../layout-clusters-fe/src/pages/TestingConsumer/config.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx index d27f8d4e5..fc529e9d8 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx @@ -268,6 +268,7 @@ export const getFormConfig = (topicMetaData: any, info = {} as any, partitionLis type: FormItemType.inputNumber, attrs: { min: 1, + max: 1000, }, invisible: !info?.needMsgNum, rules: [ From 802b382b3682d15e7932607e1f1456038f69b85b Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Thu, 22 Sep 2022 15:20:31 +0800 Subject: [PATCH 47/53] =?UTF-8?q?fix:=20Topic=20Messages=20=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E6=8F=90=E7=A4=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/TopicDetail/Messages.tsx | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx index eecf792a5..1e1f65822 100644 --- a/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx +++ b/km-console/packages/layout-clusters-fe/src/pages/TopicDetail/Messages.tsx @@ -10,7 +10,7 @@ const defaultParams: any = { maxRecords: 100, pullTimeoutUnitMs: 5000, // filterPartitionId: 1, - filterOffsetReset: 0 + filterOffsetReset: 0, }; const defaultpaPagination = { current: 1, @@ -32,8 +32,8 @@ const TopicMessages = (props: any) => { // 获取消息开始位置 const offsetResetList = [ - { 'label': 'latest', value: 0 }, - { 'label': 'earliest', value: 1 } + { label: 'latest', value: 0 }, + { label: 'earliest', value: 1 }, ]; // 默认排序 @@ -99,10 +99,10 @@ const TopicMessages = (props: any) => { const onTableChange = (pagination: any, filters: any, sorter: any, extra: any) => { setPagination(pagination); // 只有排序事件时,触发重新请求后端数据 - if(extra.action === 'sort') { + if (extra.action === 'sort') { setSorter({ sortField: sorter.field || '', - sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '' + sortType: sorter.order ? sorter.order.substring(0, sorter.order.indexOf('end')) : '', }); } // const asc = sorter?.order && sorter?.order === 'ascend' ? true : false; @@ -137,11 +137,11 @@ const TopicMessages = (props: any) => {
=-2|Oh)+E4RJ zBsEzHVR0(!_~t0yB~qM9Roq{k)aAr-hY^c|IABc@X?$fhShq7rBh>|~WCdKf3QxQ! zyRAPlcg|^$h|We$DsyJhPqi&o(2#YTR>uzih|;+4ii!0uFph3(?^|-HDTOOH+{^ika z8lvaTRv0}IXSjARQh1vIP2Wry8<`f3EA&t8riThqg|O7^aVwXJ68gz#RfY{G+%#(W z{Eo+J>ux=YTj!PFS`bXEfALJKfOpw?R|s$NdaShllokKue)5#m@*gZ7`w!VPMX~Di z_bx3uhVdH*Ux|EJ$FYN%diHnl(XZgE`hLY%+t;a$Z<*6u!8ySnA%vUk8p&u~&3o}1 zf(H3tbr%Bx$xW@l)_9Owy0vt_q%>*nJ$f3i9b{l!2|U-jmRtS(xVzXI$J6~R>#)Ld zX&gmUxJdX?Ie9Y@y)pLj&#Efng2~}0ZCKKN|9+p@LvP(yd&5$??RT$yuj+g!Uz&~K z)nulce1Jb8an2K;t<2r!bDEX!n(G40?#)xW=kE)@Y-rsJd8DqkNf1#V+JpUb`Edrh z$i{(ow({sdmH#c}-fLeYB2WHH^>^NT1Kfex+?2>Mvy-<%Q*3sY`EBm*ehRWjDzO^gv$w9aU&yQn0hgX3aai8{_5$$ zxzMS5tQY5u1JY$ao+|nhE5_5ivU^>tTc*O*7rBSpe+ek)57Ad)P*1c)Y);Su;I?JB zNTpM^JoP0@;=?d$&i-$aaM;BegA9Q#om{H{{vO}G$oHycuFlZv@p4!@sJXl*cB=Qb zZ%aq_`>WuO(f`CG#LKdpR?8HjRC&sb zP!A4yGFqS^vC%(ny6>nednm#NA|E$a{*6F7+d%-g9KhxymAdl8b?5u1prje5R1p>E zISb3-iT&#q#VMmAGSricnOF;9>M@L&M9I*6<5Nv2QI>afPj^>gdp1EXzAIbvQug@u zXd%(X2Op+%{w*Fda&d)cH}joP}R9EA77@dmu*|A;@aNseUCvL=$?N@z3e}3W{F9}M zIT%KAQdScM9L(wJZtkYmv1d8l71+?+Le7;Qcl(W6t16at!Vz&%9b~zSyirK-r`Evt zzyAU-+Us=){|?b}v2Ab1nEX>AfQ1DwAgU)%P=nJprSv2i2lK5f%RcDMyEl9dEhkGO z_`htwW!(R={h%NwI-Jx-JcXx+|=J200?)!b)kF~4DuC;5fIlsz9BW>Tk!rV~SuCHyUUoEaFzCh>s0XA#>GaI z_L}rJoBpZy7$E>rcXuqyt*cWgRo*U)RTuCS`+C}g)Hf8|%mY9OVY@YD{x%h*RPbN)8a+|miZ0GEN zLALeaE>(qi<;~uaaz)T~766j#4f*=Ee%iF8KeRw+B z+M;a1a#37HUxF;eG98~2N!PICA`I3$AA1!JCSo5Eanumh*zBo;kAe(yuxBiVO z)`Vu}4Ef#c#Yb5URW*015KO~FIplBpoVpEq$WF3N{&bJQkd|Z(|1^Z~dBXteazkzC zYr4V=V{e8hocnBj2$vz>ra|R)mV$Yd6vgMSvc{g=J}0Wo9L&s_Jf8JT^P8K|u2TOS zE#SEBCT_xy;N#Fc*^N_8PX7jYfM)(&`NUGZnsUNlvW<>#QG2Ho-6|m|nX5S&3tsHA zh)ZgH*3^e+UD)WflGd$%(iy{2AFkG(hrRg<#EW@`q$NDlJQUmF4P7QkuuBnkKhRvm zQ{(6Un&ruO*^);~*BDkCyru+=FD%vE}q9)S8E&j&uOrnEdfn-BaRV1{E{Dl&}UG&WCkBi8lz?Y@VW<>K}<5N{7QvQ!6 zDm4HOYo&SQ2Ah6UO-o)wz6}q%u50(dU?!JNr)kP9mk#=tI*oB5O`V}4pmJFzYuM|< z;M6+H?5_b7*EAIn_GMF%9#rq2CZbhr!7&YYOub;{q9Nl@uK1iFeclf?$pmIVnjuS_ zFlU-Y+*#Q-`<6JTlpYDg+)j^01z6-9oVvM}Umvc2T5T_{GDmGKh1m|z=VaB*o99;w z*wD=`>6QSYM0Un=Z_5}DuBYZ#Edya z`VXl;az7VLkaT_L9$M_s&C z`^iLB^KzXh^v4-2J({iAEq^Qle504f%y7u|7KD!CzfN%S(xJ#gAiuYEM@YV zdP-gVUbcFIEThDuzDY8>b=GAPnoAIZmmgIT$?Y}iKycE+!-OOm<{C_> zKNB6wH6Qvs@ddwHEtFq7ySO}eo5Bb+!!@m*gS0|OG%o}84c_Y?pj#`SDxu4L3$4)V zz~>GT&jA_SaHfx^%>%u6ZPGd^@$B8fO%#Q?yF+wvI}yRm(VwR2K4zzL4)O+$#_hcC zZGMqUc*OUsh}ZSg{MO;i_|X(nlmbL4eP|#G`ChQ6mIQuwUp#idZXRj1I+uiop*a*G zN^L@~el9qyCE>g+!B+dyy|$DR5i!?|UNYZH9Zw>LE-c9%=n{&-7aNG)OZxk1yDwA) zP2ee)jB9=?(i|9RBvloe8=o`Djhe5&vK}7RO>DRFietAkY-1Zl(R+JRps>WKdE|<< z;Wnae=aH7mFEsq}_gc17w6(>I9qJ<~(9{|0j{s-bLQ+B^#vB#ggzg#m^m2cy@-L4Q z+-)T3n<8LGlv~a7FvOOG7goP_CUzyU^yx#X{zwU=!V33pfgSh(1bm@)M=a>38+hV? zV!_vL7IWunB-Gwwiv^Vnp#Ttjf9_V)q!I=w z-vJEKg<)ZKfjE1ac$fG|Wi&51UwY*FBV`Dxtf7l3X4&vk5#*t(BZY0;sdktOf)}n) zmbR4#0l-+!IA;O;1%4#*Sji}Nv#-rvXur2Fj*pd*@^p}BC18_~d-IlD<0j2>jSWYw zgS7C&Sn|sXv}1nDF_QT2cc#B$W z`-hqLD1AfC1G z>`JxWLmlQpyt6#>s6Xe%0O%i>LV3K#{(RawYFZ8XfMt^GF3yR|zvl~RiJ9lVl z<*^i`DGv$Od7Oayf25Smd3h8r(zDtv~z0{|bl9jPb_Tnikzt_s4fG4PhpT_ey^ zzupEKH;vLTnv4Hja^&UTXpsPL1kCuJF%&JQx>OV`-(TU zgI_XCv+QLDvMR5*B>^f>6#Z&>KfXqkw9h;QR^l(}nW`zKdcnAgq8L`BM(~%iq%A80 zrivy${sba9z7{OP(hfh`GuL2rur>V~!&9O5w^q3ek>^JH+c%A&^0KwLszJ1vNyD%j z%3uptFwDY9YWIj2%_b?2`TWb};mO|4$XK75hUtNFGJ}TMi2Ivyu(jos0IaHna|i8+ zEM{Lgs&eLaPYh7ZcWL9lS>4=3Mfro1!19_$lmn5_+l#xg(;Dn9ykZ$Va?tr$&=OCU!%tbp;-D zXyt3{Hzbtl+f|p|2~iomw+60yomld(?wl|hNOVE>%>!ph)I>{E_0xw=a#o5;)PVXC z@zEBiUVlFvz~^X5Lohcv^vo~hZ9{MO`LB}9 zLuavQ5vZb4FteaM?oEO!oV8BRxNz?&j!dyLGd@`;&2dc7@0ha%;<792x_?5q zLHT|atUbrp!rrXKy*y+t0CvE>Y;AgD+V_15${GIWHTj@8l-lK<;R)##d{tv?|1lYm zh;NA`2tPjDOAiX2FD)DALC#h)Il-|b1XTQNUc$1yA zPgLOG{Rd5?B2)xkE*cX5&%lL<)57t&_{oYZFQCl|^;XL;x)$iq@ z6np{pv3Q38ePPt${2KQlm+y?PJA-DWdolVg0h1`QU&yTwhG|D39}5Ic+yX8MLpH>* zcti~~-t?`045~46H^p2r zH&pbkFh6EI?c`46AQo19Lif`9Ih%`Pz<9c)YiWA<_!4;4|IWjdtUy3> zBzAAuM6$6zefAw!bPFpM^p~jU z50+oc(>94ulbt8$s#YgoU?>q`6^PusirPP1(dE0KR%cBiLAd39A7k`Mk z^U29>K>1$Y>h)%j!Petxne1mrvG94jHRuIcd7xs1P*o&N+0$5C`0w9!BQWgK-zhjE zSDv*{G^*eSBMY6JG4ES#!C~>|`6`lx+l5TZoY$qcWPZExI4;)L$ceypWbLPDIjr zs$S1srj%X%%6*YEp`Ih+d*!=5FP8#4klo!+<#-hA?+_H%PW-6gE-X?6x@xmZY26Dy zRM`<#WBRF`i5?OnqB&eI_Sw;nTtK(YV|z*&+ZN3W@|=IOrvkp|?fO_9wWRIsxc1A~ z4btX~xooj#7s$W0Sf9PD-I=A2MndQV^?pROULH`D>luBB%*EIKSy4&W?q=Zy*Gpt( zdI#PSuQqpCB)bR|ZS=Oo!K07rj4dRbs`?PlD2}9x=B1tsJpV_z+Lsa%N1p43%JP#w zOo}*%mgLT^V-Ec)d)IlNq!Mc_ zqx;eUc8eNs^Bk0NiMIAw#?G#$*!C@K8MQl@NvpIrDLal(ex#YU zJT7B=d}ki3;#sx1)1y{>!F7dL$ygIsYm%OA^cOeo6VQf)Oll$I+t_uj219WjlGXOr zz0p~b<)K5|k!D;NajAUOp^uwd2c<}*)NolK9Va?+z?mJ3E@KnaMFsP&DtZv02sj%z zEm?iiA3%@syx0b3!fp#V{*RufI&t!=AFrF{(B*kAfy3q`1%Ot_=aCu}`OVNpg-h59 z19ggo|F>)|>NzQ7=oLb;d-48 z(+9F~(h&ut4Y(Rm#-^nL@^6o)#xvn7*{Nt5ELo}@+VK*Dp}S_n3A_|#!Jx zNS)3sK9YcU$LU+wI*vTE@>V_=)A8Qy&TQ$gh3}MuorBzbQYkn7n zhns(6>ej;RMzgi5QyjXMhGpM-wdFXha?tpsEojok>`bU&{_*IH^b|~y-y4%EJ_Mtut7KWM zMd}-ENB+uRt~+&N%Y33e)SFwSp1JlC?U3$~SFRRns_747{GrRHaf^>Cx%$pF z@Y5r3Tx-u?S6W{sR|6Qz`+?xNm$4IU2K}z#F*}2w3pt&*1-#wRs5*$@DETr77FvGo#RAGGRI{rQQLoZX)2$g7iAYK{D zk)GILwQFk$*S$lpL2~Nser8%ke!>=db-g zLGC*Tt1X5jUjjlzloQwZVtQ=9Rko@ie>E_~&FJ=jbOXathN~H10&)GVCx6OY;0KgX zdiePUj_N#zO!DRA-Tbxk%kp84+LJu*5r2&;K_rFlCmDSDOLBqe{caKebf5c~6dgIH z(18N8ZY^8qRtcV|?)zN7rf?%0?XRD(-9)Hq)BR?p7~-&AF(LoOXiRWp?(2;q@9FZo zJE2o!ElwBv+l>g(cOwc6P37ZR;g&%{Up8$@AVTZt8IoIqX?(b22-lU9Zm*J5C zdLLvJ1QxuKFhgdqcvh6I-sK!%ESU(RC|rjSp&0Xtqv7?~wx*t$z`X@0!rGO2&b!A4 zCT0-dS@h~(?`2KNoJdD|qevzISB4HeM$5lacZVd+juZZqhEf>#e6+r+KB!-j6Q^^WJcJz4;AgS0C3O*HNH= zs8G2BpgrUdmw;?dP7p1^EBe&XtZt$#dKw5uN?0JF_V3Qnf6p7}=vXhY2PQj6cRL$u z?x&c2==f%J{aD@9QUYaq@=|~gtJswzI(QAylDCMCbMLVwnO$)?M{KLlR+9SgVYre( ztRLv_yHibb`Fv_TQ%g#!p@;78z9+)eQ;fRo@|~ut4WUlzr_#@~Z0z8;iCv^E_0b!- z6oe(DsWeUg!EOc-j+{Bqi(wP*zHNI8aeA|6p=t&6kVM?h!dV5)(+gPv?cqa^9hGrf z%J^2d@=Q19nVjFdlBa>e_t}py2Gs{4M|({W0cWAOpQMXWIB`27oZE!T<_WS@ygYAf z30U^n`sa74Gj(T3g39Bhmjk2o?+PF_jtM0s!7&Q+G_ncdBaaatQ!pYgY?)`s@z5yq zh6uv_s|lX{yLPe_H`yNQS#C-H%F**o#xTGS35h6Tp2jS06{@PJD=QoQ(A5NrAEkNO z{wP@IbUXmh5XgY#umiu+=i^G|44$RUiOn7NS}EA8RU`yMVknkIlqTJCDWF z#$qt9LM8!g%ViE-Tl;x>n4OK;?gN)VAF~E2(43ow)@T1B?6*X~ohB)`4XrT`cL>#M z*@~G_2i41ibY>UyMx=(fmnI9cYV+`7sk$x{3B~wX%$|7_cVwvSjM4F=D+nv6S z^R#%0Dbgw-6Y*(ZAf7!JN=?W&lNhM5IRur}Wz|^!es8#%`bwLG4!66}M@S9QB?@{l z9FY!bSNbLVCwF(oT8WTZ=Q&f;KPqtZV5J_IswY<&=pTf(wEo-4evCgeqq%aj^q5H% z+y9iK&&sIXn#FHdZyW9 z1fd5U#*xhY1HT#4NBsohSFi}HQ;>7Q9EV?s`3@e2;>qn%@08(xgKZ{FY8IB#!Im|j zY4Y+3ctnYgYPS=X9X%)9Vio5uj02=eSTTPLwy!>hP97P#>?Lf3YVnPJiu&-7B4>=R zZPE(*6p*oO7Ir8h;25v#)Ki=H}P5Agc2Y!~R^LzhgvZ#H$ zGW?Z1H0jiJMh*r#V2VBompp>*N%|= zSDkhV?Se_CDQY&qN0ZSusVDjyT_?c`0f6B+{!;x!Ihg4m>N+(&1ssu{8;Dft^RY`* zi~nnRWQx3V$3)tyAXX&Rml`2J#;L`+&=YcD==VD(MT|j$v?7I4(OaxMAwX_yNi^bw z=KjG`=)vckx<6D|aQwP9e>i8LXq68tO*8){Ie!5~1|0GA$rwpdIs8KAhhZrCK_~2+ z;_+94w&>$1f1l0ptN`1!{3FzH9#f!%?gyKl}Mf5`1u?uM@RztqXh>GAaiaVEz z3_V$wm~U=sEOoGgZ0NvR{a3<`+#;imnV#@(cnu9!Jk&*)Woaa!lYd*#T3o=~7)GN+ z!4H~J%JK{zSOp~5!hi5rM%|Gxi*cvJkt~A0dl=^}@qwU=+XO0>FWp^z=avsGM0^LD zTrLQiI0$k`P{sGq)!q@po|>nF9xziduJKx!5|H6Z=o}pXIkqf)^fVj{i^up2n;K2R z)UCpn7o>|=(OV(!N~r!_pYx9_fW8#a&dTeq-=GxSFLW}MhiRAHBvh=?jvBxNdxBmp zn*0CvFbf|L!TIO7OwxLwrl<*w|Lnj6p@X~Vd{@aReI`#AKcasy7r z_0E=eT=iDL3x0>ZuvoWn=pT^q)PA8++5X6umkw8#)(Dsd~r;QzJI5j<@9=EmqFJM4P*Q z=E=Gco8w19V6wUBKdMIx9CnP-(r7UYX1#}>3eA>bcLp5+$o^e^7Egrl)K@ljM~OejA~+*qxPND z*Y>L23Zib%rfz^`R0QeU4`zI61~(EE0};N3AH%biv|vbMtp9Z4acHe;5@T;~wJozB zu5FZKEsXy{ld6?f8RCHE!8q4uW+=M{S7zm;48#QDJMij*?)IuwyWwBN6Epc!HKQ>i z%Y%?fSeXOD2;}|D2i`zupy8oqb&g@Qk^a%P zn-fm13Y8%MU8*<$OX^$P@2i`lxb}MZy?^cXsj2AD1;V7Cm|+oMzjWWB4zhpUjmR*O zPBEE3Z+m|nU;nwTTT#BVK3~ahtS`^xbuh+lK2iVWX`~y6wx*UD)w*X3=x-yZP8#P% zXkMlQn_Zt1KLI;~?{5Z;d?;z8P@*>pxZ6teuO{#|fkU26NYuhTLLBw}ZQ6tPlJkia z#}cFUk|vfSDuWe~0!tS9!v6IwUW%O%Ar7)ySW*&hCkp!Y>(|byX~(XE7}&CCg|cB` zurRvvr1qEFd9xN8f*?uz!#3T3MrE21*3+4~yNx{`l&kUnXXs^+L!&AZ-x~`wHKtPj zD4C@dT(>qn8Y5#%`?EKx(>D#eSbE|2avpPRN8=M-71tT@! zz#5qL#R56T+`j{H1PwMMa(4oEll|M!oKXkk7J3!w`w~(&@~$LDocgC@;lGQpL&!e_ zM4zBAjBii_O6tryhwlMhU0?N6sd12C+{~Mw33*6*_lxj_$Lk5o{*?{v-)xN|z6KG5 zi=b{^4Zw&?8-ljnH@v1*o4F8>KY@Nu82kau^56sBJQWfqkTa2m*+L4=V~2FiI0uCc zC`h*+CD*1c`sX(`4sO7_YXL${^9ri@78h`9v2$7fXX04V!MIgKdIS$903$$%6y08uoLGa@ zpk;M+RW~ckrZNn+BJ8Om*Lhp`*rQ*=^4z*XYgPMNqHXjB{?)rh_pMK))(k-79!)RZ z)pLz;tfgWJ4IMP#z`twS*fR#p%Hj|4&n85c%3Xi^H*V>U#)V9vQjLDJ zzjJP@#vJ+_>>YPfR-X2|8}PykCG)PUtJ|-?{V-i`_N(1>#Zvlamjjqh0z_*{5gELO zqzM&n@?gPr7oD=Aq{;0c(4URt#LF*XNo5?2r!-q{Q3)GMAVVub72bhTV)Xn32(ZHq z&@6#beFp25_ISSqztsO_twF=IxFk;P-}D!ZbFPbCk}PX|FTs`b^irBlW)HtcH#o7}^hT79JM<3v*+^l=ZzAO}l$PdfmYqvA&-qrY{R5 zkye_3Za`wa1fv=lQ$Q)SdO`A_+=+bmu1<>n=^8BvL+B*-H`aBm3@{k+=)w8XnL3>3 z_Q<}7DDn}*HFKKVQ2lnH5G*|@| zZCLirL;NpD+7!>&`GK=-9V%0TEg%f@GIp3L!^}_3{anR8xwjUpTg@TAYb5Dn(6l}k zxD+U;+7psG!I=+qcxuS0b8Q95*LmVL667_63f&Y@NGJCtMZA7VEq|?6))^8$%5bM= zlx3z%)3l}8sRCc#OSCaH2xb`Meh&Mcle4AHm7XT{Wr*dIt(P#cLxGWix9@LFXVVk` zp_|B1b0i9Ab`fgE%YF)3$Xssm{qUDRJta%P8mAqfDstSzDRX6!`a{g3sfrHk!1m%f z+ryBsKW&bwio-an+X6K*_;~&$jWFtu7GZlkP83<{pc%9)iYg3B5o6G9U%<-J5Sy00 z&f`M0noz61&eEk&5h2vQpmVw`^pfG1@O~4mWLfp|v-Na`r8~0Q$|!jhSoi0>?!x*c zcrlyX>|Lg$*^Mrp&iivZRlu8m+X*Z8sc6v=#Rwc(ylxwuURE}zO|8uPMxr2NEZ>9q zzMk*eCmK_3entK^@;?%7E_}EDLRl^nQ@!P>j~6@l7ji!Ca7YS6)!A#$3--ZIWi4Ji z^bfDHtp+=3Xy~xOKG<|d3tHH{kGXaHIT@vnF)#JYt-kaHAKq*VKK)`{p2&)3_3_l5 z5nLd`cOVQzz4oMV$TZiNDR7*koeVSvB)#wkkrG$8w3(x*!iP>)i;q}i_)y>QAhxmT zw9O)(Ov|ZNl#@wEeOk^C;QQ@6>z;4&rwS)>rm@lZ*|9 zLDeKZ%=Aice}|ziEtcEezD@O$Txh?Kq35>uYuPTmJSA7vooICtD`bVkESg0gn26eK z^w*LD>e(avpN^z&b$!TSx75vh$u`P2Fs3nS`%_HF|3D83oJ0;YZ#;B;py;xMVDPva ztX}A&dCoILvFv-L#*{_Z4e%9>?@kiid4oGA@u09D3O=it1bn*Ltb_9VpDdaZOifLV zTj93z;=JK%QeWJY-MSXj2lQ6fK*8mQ{$?6$9Fg?n@-yp8bchMW{_g8r%aNd(G{ze~ z4WS~uG8MV!%uS>_6?r(Oe(TN3o%P722_8PC3BqgN#AXlsGy6cy?k5mHZ-qb&b~kL< z7E$y~1tyCn9F(2i95tB-ai1-;f!RU9IDhC`XNu)}t(Wnd{-i&acKCqZrM{hBjY-q> zwobQSKbuND%O(dp?QXklQ6_uUr6W!dMg2*>`1+WtHn(i9OZ&L-?v*9COfX&5b=?J) z5<3p4@!);b z=5YwbD8Or+ARdWhhU^DEN5SuV6}$eL|>#D2VgfB1gbWvd{8!ePg{OG>2M(_C)XJBOF0rLvtMVLf`N zK$gAN$0{g;A4F&XYrnRvi%C6?Okkb~EFP6Y%O`NCrs8M1#ejDK+Sp{;hP-WsY8-zr zDgTaJ1xoxfIF#Z0-e*Ek^sR&5e66!J5+8&V14a0U^kzM;`DrZ$)}bnj91pxA>ox3m zY>Imy-tpd zDkfXQ-XgUuC#PmDzWe$P;`XIKR0G0o%U01 zJ0<95b2`YV2qj(NParZGfvTMGr$x zXuZ9!Orh@r6YZ}eKbzk7ROrhQ9L8$OVq{~_!u0B2)D<-FQt>)KyC09ONxl8FET=IU zLU%V*5sS&bjAu@P&s-G`)rtGoCwSp|G&MMwl6}7V73QPo3%6LI{dMj6;Nts+S9se$ z@`IEVAX-q?UFWV&QIu7Gnev0LrO08QhZjE#<9Y&t|nQ#jmc($0TIFb@Z4mM6JU z5*tP|n1hjOjFTXUuOf$T|8NWeep3o~+|S>!`r4JAnCl3 zsdH+oKapX5`7r%f0(PHe^vbZfuuZkmX7%g5NHJrdrQLGv z?D6^T!!uv4v3X*q!-~T&P`49xtG8zM^*qLJn4xJs=Z1UtcHh@lSBhcF&N^&|qcY7M zbG&@eRqx^YmB!e~r)bLlb$)SSc%`Z7d;L^%vaJew%jqQ@Tj6rOM`-)qjW+(YOzQ0# zlAVE*=p~d`i1~{%Sye};9&h5VH2fJujzS_++mZucvg01oFRzlrCm24*SMn;p4xB}4 zkxRv1#rNw-?~_&8g-mhX=itaaF0KkCDc^xZ#yCI0n|60T&TCqxz8Vd@!WM8gXs?R2 z(|Oh#a&wD)Gm**iQ`fWt8q?4AZB#I8L%^2b9?xOYC-y$v957p5X`b!HKq-LtnR2!J zDF|&vkWxUOc-{Q0i(~bhBZZlxVin@>9ir`g(ep3Kym=K1pzjeG{LqfL6Sjb^>#@hj zEq{zTkp57tr7%IJ&UT6KVVQmxG&dmai^N1lK3055P|&-lL=4}K5O(1^-~HIHeZKcK zm48r+dCo46LoMbx^y?qwVOSAXjMa2O@E<4B?Z9PPBAauw?zxgRtH4|6%l5Lfq8wd@ z)#~*-GX%~*QBLh95tC|~HM{P@6;MYCo+k`n{NfKu-;U?6#r%C z5rvrCkKJ~_zV5{O3hkS7#|mCYWIFF`m&Wj_^F>wMrewbLB-%$j!bGXVM7U%+&L~Gb zXSz)c)4txw+6?x&>OE%gqT{6QgC5swOTQd$O%ks?-VUl?Y+{$tJ4tJhnmv-d#2eam zT0L5!mNKT3BO!vqMb~}|Un-JTrv@;you%cYr5py-_2&z&c~^-!G+~d|buUsz9+t54 zY}&nFxpAKi{i`+X;~e;&7GuiHG@jyiYI=f|QCtRi4L8E^c>%{Llk}x!`=;|=dIJBX zLNH_Mt{+u!bHuAyTVMV7Uo)+jn&sgS2Z$LyzMEAc@M#D2Ci1XX%0cYW<02}i06RkU zCh9=rWa-VCJZGfMR|`LMcHjny$!Fg7ID0;lRUxuIgm`$SyHYsc zwFI-}sSLiYoS~2byn>D0TDZ8?-EzMJqorl+u(Hy6M_2>ECZeD#^GV)qBC6*)Gk}x& zQ!F{5#?^Ah=kGq~7JdqVjFKr#G{$&-T^4+OOW9Zo;@B>nq(szX$`?Dk=%K&MUSRw` zGMt9XA>F4LeU4XrRby!;RndF_zC0|`if2tR7tK+l(=Y-+OFnw?=zB_fR?1KK(VKm= zR?S!JKmnbheL;PeohKnBnWD@I;VoyCXHcxR{#{X@^}v=82MU`W<~vAzH^Cz;g~J`! z;C`^W-cTdFgAhGccZt|@rdF?zd8|~f(NJXTdR|yuoFs@JQ(K^kOMKttF7%@A*x)mG zQckkLP(6k0>xOQaF`YHxB{axk{Ynqf9o;QzSC!YYtM{_s%(#_9!0NTIqVGS|0Id0$ zmWq%>rVA+fj~I9y6!3NW`TB`UaN8gqn6P zk2vcvI6(r-erxJSpLwB7@9PKXrx?Q^IDoXD=D%!jCX zRm_fzLoy6&)ND)(H!;vQ`0b?5f74w8IU%^`8fyq&v1aQ@$!la7kj901O+8H=UxYA$ ztK@m*vb!5WAM0}9>YNWvK%$p2)BirL0WI@l4(wC!^&_1_bK$09FP}{7L??Y!q42;CF@nnBl0;+syp}wM4V_J#Tc+ZuV3=)-dMs;Ff(G+CmQkj576t!ZXu>Asn8P*_q?S&j zp6k3`=2>L_R>e|psn?d55sY)kwsjmhBs8;uZdmfEwvekmL$udSln+gb*$CZ#gnDLU z1KY;tJdB;oE_(al_cds(bW%v$6l0aW7va~XjRm63^=e+87Ta1i{!Sh|6v+yA_6z83 zH;;DWdjgy_7G|iR-ERx|g*(pwi9A^z9+<_mITx<10IEIECni=Xg-FZ{=5u@Wx9|55 z16Wmf2Z?UF{8f8_68zgxt>$PJ^dVl@^mMJhiVCm4z#f8p2ub1`#Y`Iul2RbQR>SW4 z;8P|yQEi)^QC1yqK7^oaYs9>)Tva~f+8%0>hti%8j_?tWaMH^>{WF`0K{YU&v@H*E-E#@U z_WgSMZ=40Gb3)bMn`?}qxDxjVvFXhn3n7MH~p_iE?I(ErEuP*M0s8(>_#$Oi@uW zmimi>*WWhnROWKmlew~W;zy4^wCsj((BRJjp~Rj$VS*d=M(_nbM{jL^v$9YeD4!Fb znml)sARROK`6rT?er*cctXf^aeA;c)wB^zV(sfvuY0GFL8T1-~fj)w^e(?6~u)vE? zF_AsjKIe3ae(vZ?8ieK*$1m@9i`{7wr%%TUENLi5z?EUU-NER}nVBCNl9KTF0iPst zt(l?Sn2%h7MT9kggpT6mh8pYy%98G)WJ5m~Q-kfj4e!Z_O;fhCOjpuu#mGk**In_} z2crZK?2$TeHKt?#P@p=NygiRR7?+uun`;n0eFxEl)**g3b=To)VVWr6;k zozVPr79YUL^FiAM*>iS(KMRw3t--9+>(IiuUs=(zdV9H7mzR&8UtiB6y(41|VSVDQ zsIC3M9BS*$ug;98q;Gj_LWlMFyF~X)@3ukUlNHq##jB1!m9c$D3F&Ro5Lw)DedR_M zT5r`ABVN6J%khP+sxRY3s}3=9z{DOo(?6fH2k8^A^b;aM(Vk)hn#uBhm_Lphq70lQOc%#&#<(p?0h-F>LU8}-tnLnnp-!B~TB_~ea*xh#rWKCq9_^Zrt7R4OHRqHYs#RvNZnC)smO*2;={gPD0U$!rh z(}BeG;&xBHcZLZw6^xdG!OU;|ss4V<-=8gfF>cxBANKe{6@7TgUwe z&{wY|1v>o+^`<3Wuxqg!4@8a`n8>X;)H8bD`&n10>EeP})5tneT3K2B%gRb;em21iie-RqS;zVz+ zo@Mw{cnlHp2U>qE;^iop^O77}&@jKn!EJSj35~pH#-$0dV(&dspky2jqA|eeq+VEA zi5YMeT+nOXwXq?({y3FBHQKaUr&Z$D@kw~%Y4Dux(>;VNq>xT0vR~MIokNQKj+UjCe z-q|S-BTwq!K|a}K5T$lVaW|23k#y(sBqXL^G~1s85eO^CG_8dng>~ML8xsOq@?tto zIpl8)DqyCoDDo%6Zl<#shqSe}uAm^!!>FMmcHzS2F$z^`Q2$II)FfwFW?I;r~U zr~vPAFWASC696jw@UGiXWU6SkH~Tfx6qsI5X3G$jN9Nn_f6)RbZ~2GW1g=7fNSKC@ z^44FFf-rvP2}JlKisimUh+yMrx4GI_kEe4u9HN#QHV&JN0s`d31o)Q?!aFApDImxn zWMmhKB7Rkgt+BH8AVXB1^Wugo439~#jooxUk6NS;f#j9q1!#469pIkqpSzoma-ZCz zPGTU;53S#2*xs3-tv`Bh0_Z!@PO=(13I>FCLGJpvBCft=rV7Fd-35_CpuBy3(=e`1 zQUPYLuOdoz!OY*ngoF^A>g&b0>^9^i&{M7AR?{+t42s1BRKCq1b}1xclgFckHg>V=ER}fUBfULkfdOjqj%I{FiAS%(H{U<)zAKc0QsQ& z&dn}-P)!Vdij9f`MyTz+qRVFk4A{OD@#aDhVDdhL-ncr2`gSD>y#B^FgfHyn<>d~F zA)2Pn@n$W=7vc<4!|16u$XFriQM6+Y9~8*wQ9mfR7-K{60w$1tbO1X^uc?)(1FB@a z=c}KiWtWhtRi@nc?C2BuZ4+pekO-t~Km@bKgB0 zc>no+c}HC$>P~fCQsv(%O%3}h*Zm1Q4n39`se7W3ICJJeg>0mHEQv#?581l=>~wQ` zYO!bG4>lb0(n#j9<8yxIJyt1i58$JenFG?H;)W8hVnJMFhW|s`ImJizMPEKf$F_|Q zJ4VGeI~}K^j%_>XI32rV8y(xWZQE6u`u%6-aUSP$-z#-1=bpRI+G~CH{3P2X%mcH? zB&kEMm<~Ooy3ss9;^)aHIwbd4;`61y{9b0|_XGc0(hDf69V>Qs6iLySI?mF}0mHAz z(CD{Zcn{UEmYYpl_oxF1L;PRyWhDsN;n)%ZZ2@OTrTfx2=~K&z;Sk^c-0$06U+dYi7AKqSHBb{;+6W7xN9@yZk>Q4TN7VfJ z*w@2e0^{^hFE!rh;7wq#!@RtLu1)m4aNW3nGG!tu-|g51$UKZECm(*MGEeZ%4-u+!imzdHSDLb2`quU=aeHHFc5wgdtY0m@>U;9(vz_(?nnMwmO*>3Z#iA#1-0 z0>beC%}tT*oxWL%8+zw^1Y~|2dsQu-0`9NBq~f=X^zN3Cg*nFe-54G*cM)FAU@^TAYu**@^YA1tbhYPr_JQ!{ymdAv{zD zB&OWozxH!@n`YWskyW6lH8}JVS_Wt|mrEp1jC)k5VY83eOs13g5~;E@lI1@%J&p zAfpAL;$NPh>-;%X zP$8JgjfsdSuzL#enS9Q)E!g^r3@k#(zh^f!uvUj)T`?A=JH}q_l4~Lc+}1(pM4UxUAFVcmiQwHPoWyVbnXZ$?+|#0Tb+HV4zgHKEgKz zHfw`Zd=I(M#eXdP-0QqVq_=o8Gw;0ZcQ=Ns#Z0BjNel|aCwplBmse?8-0C5Bsp}kW zIDazvYYE~@t3CUqW^0u#Hy1nBh*sS670*nmZ4a+ijw>Nn|7Y8G?Ps8XnQU1N3m$8&mm{5?lDasTcC6 zzfKM1?0n%OTub85{XlmbQc34SazUI~tl06e=B=*TnA&%lcPEP^L zQ0gyphVo8ABHL!uO#u%&5Q`$vB$z}>=T)Ogo*A!Penx2>3_PAv#=M6yM}pwhd9<}T zyj_flh&XBOkGEX!0I^7~*2fZg5VA%^>byyO{fz5S2&O28}SqNS`(o^V~PkH;bBezYyAlG>2a zZnl6W*BGLpTK@SGUbX4QtwG2yRb*`&R%a}(R{X5=D=`6OgMGKlzACDcKb=k*KhXbV zfxE*$O3A!gx9#fRX>)xg9^1da^+~iH_ z88cfNR5yB6jBPh?1RcDZYT7F&*7|1Z>?R^e&+&I&fE8!^^;Q-NT9>t&#Y8_$oNlne zgQZraWAYYJJju3Wmr$lxRkpu%MC*(+wP2O&&>P^?HDl0O&VJSXVN2TsDo_O?@Z*^Ar;7z2WzPuZF3e?f^?vHsp8@ZJ&lsz&nJgd_mox-eXLE1|c zcHTc_GSjn%wqVv~d8}@T|rUG0(GAoKd+HGWWo{ZO3ewys+wFTe>SFrN$rwbWBL!FYPry@=d*nMJBh+$&vkeqS0Y6X3L9^~B%YThkF6g{<*+y6J zJ-k(BIh{E=U3r#_Z-cxHIVMG-$%TYBYsRNdKZkLaN3^@#$|lkUs0e(4t}SD6{!fap z8y4LRfDh0kV-`%eiUNO~b`9{aBWvgQI017RLyPI|!9u!Nexq;cWg2H$BMml!W@kMK zU;bLzeJCuvpE^pPjd*%4C-nMK9uZxST=2~&?P}|J%FY3+uJtHB zvJT;bC|*Zk4K;ps-B;yaY6ANuraDH0o@aZ7=gqrE?Z92vFSG{O{klBfD%@_xj&Yy5 ziu$(<-QIt#=R!Pj_F#RV!^9j7ltqh;SYPUSGci1bFwyoqpn&!Pjvbw4x^4gBaMi=5 zE-;<04V(6(#VelJhQD)422$(~X>J9@?pi32l8YcZX~oFwI-GP7n%eux zOLkv@)=lwvaYW%&bQG67P_z_Wx(K7|H4#2f>#o;&e#wiO#t#7&Gu<$Hjt2_Lai6jE znA723dHy+r6n@GNFPo%1m$2($9uA$#F+&*twb>P8P)hS071g6`P3jofPZ`6k>1co4 zoC`(5+uN{yLRO~#`z`iIIn5)Ikv zt@AoS!!MBAxsW^&;g7Z!n^l61j@Rs&^O_p8_H{W&_ei{mO~Pk6$q6bNaPxD}lQ4}Z z_>P**9@b3Yp(<}GsR!Si(XRCJKuZPTLH^3KNS@XRX0j5U4XVQm&E)fjX>)GLDivR> zXUP3;f~NblKFya&+y0zPtgrt(?OVXQw#W_sU7F(2d4*#+pLA-=CDB5`s4sbN*2$5FHNl?x~3;xu;LW2Io# zXd}t7qlt!;_0b;ftA`WTG<1aEGjRk!393c(Qk~t?r(Xz=5mfOI?I@O)C&f*gnR9yY z)p856>q0s^1a3vz+Ss*7n%U+iGZzZ*;|^w1&#vrUUS0}S$DflF>o#@i{#f%K=o=UN z>fOgX88vRz&#n_EbY+L$MB3_0Z+lw##nVq64_`qcHb}TG|)^rQ#9IoDJ^!eq25gVqMygbCu{*VmUvG{oV$ zcUAB#b#{@Rw9ro9#|r@udP2^BDO32=#vBkbsy}-snr?7W@I{eMM&dw(r3Njdba9{c zb`y5D#0sg$A&^GwM|P<=03O_yEhNNO)y??O@G3)XzD4Uxy>8WVx$R`h@uN{uIuho? zqB@IiU*pT;;NDtF5cQiKrvI6#L(?B2*697A-jSk|!`Duhn*98R=1sB&lh%789RpU! ze}h4C$92o?g_Ru&SAL_cHJw=Kc*Pj==WPKq6>w*Kb(DMXUr>=yNQ2?&K`V}H(Z2Wzi(SC ziQ;_8n-K;<)YO+jSt-~+3;C(C1`^oW#wb>)@udG?UUzwhDg2wYR$~yXll!MMR8XL@ z%eX}$GoyT>>#!NVup!AhuJ?E%xdxHgR3sN8e zbg3;>Zc@hy-PW^R8KME`h`8;NLXpfz%Swo8cs5LP#anMao<~ik+pz}C27|nm5eeSa z(l*`cA;rUdOQ!ugJNt8b6?1nIojOj0wI&AcoJKxYD8BpzT2+3W?ESl^MB-JJ6<&7@V(79E#1W}3><%T9EX&iNKQv88G>$|C$1SM3Hzmo z?(V%GwR&PtA4r8}*{wAh4;%l~_UUZlJbX=*A+Q%ymF=ipwg@(c;Kp-*K?I;jj0mxc zy&f|pkW+u$k{{6#e`i6eg{>|_n(GNu^EAICm3$%dF3=fDZ8H_a(YV1Us?7g#mVd^< zihv#oSb||whuCacM%Y1thyE0+$L93&SxvdSQ=1SKDg{KP2euUo(I~Qe$neG*9;m~F zTvoC4o7t}jTZUf~-EKFOs0RiNKGT(es6kaoO)Q#1oLNw#>;le44nE=#%5)=XH6>XTZ&$yK|SuTtD+B!JN|Tq3zA8dZ)0m`IGuE zt8?MMz=t)JdNf!6SeiY6#!AfNgHA4_$Q~d?B-Hd?L0S2v)u9#scZwMavH*~6IU8%} zAHZjBj%pv2!`38-Yhd%FmHh8AA^e-BCXRN%iy@-xxcIJ$ji-*J=W9-EjtV{Iy;0=^ z>%HfZv)fFt_AC#V>-f=8US$p12o0S=qS3(DBnJSyIT?Lqn{Vl_o(Q+be)zJ_v82tt zTMZeAx62%n?^Z*BFI2xY`BKV79yUuMzHJ*2LF_KirF%vHo`;Og#{C_}uWx6FBgjyU z{rq5ZGb|o&*s2X)0z*lZL`0b_U(qkuD3dEX@&ag>ad+P zVmy48ox@|Q(#*0$zocQ!!#9QeE*00pN$X{ns@IVtiM@}lhsxSyv*y>cCgL4<=PjQL zW%my&Ia9~ShA**t8_bmwuwo61oj%^e1P*&>xW(mItxNr$P|UndKB8sq%1DmajzNT0 zL<(BylbGxO4>AFXQW z-_b45V|8q@MfaEc`CVB>t()kKI%BI{BP|onX`q$u!|m6vL6hX3+maHxR@htTF*#pL^}njI z9wk`a3B;kuY1pm5Dlmy#nDkj4}&tj4VG4r|AVsD#d*9qXo zOq`9a3?p?|l)9w`+K(0b4)VL+=Zz7RL#X>OOP%8!)z2E z>%L^441CTM8d-SHL4Kz>@GQOFN-F7MEYufyNA0ZB4JwYLf(v|_ss_9ZUd7!89$QjV z>Wh}T+{B%wvcZ|+Q~Kb;s?Uqj)C*cb87}{Y0wUBK^|mXGf8B(DO64x zbEBL*4?opR&T)Pm|5}L~#-;x0j}zpbNFE!_p-A{-gw3_1Ynrs}V27Vls8DVGD?$CZ zFQ$t_@gl+H<}JuS{SW8x;o{{_j%qF{D+00UQp;fcPk*PTEyJv{iTbgr?)fM@0KynaENvYx)aALNE=gDBl*UFsyNy?JMi)E`u zmEOEXaha_^2>}(PQ<44#DTZGLPnLt5TX1ABN{u#TawMip4Ez7k?dWLPJwKZAI*yGd zY!HxsN)bb4^xX3YZ<5qe_xh7sLrDMpIt)$*^oo#MAVXksosi4i_`SnY8DFS^I}2X& za^|(FV6VQqgSs)a>my4Cg~XnGwjie1B37y#^MDg;7dJKNvC2>9x3@rFof``a(`HxV zgeYe2`dO+vt`^P1XI@6>Q^0Am(@mBYI=crC}nsNS_zH%*F0DLb`b8PWJ;bli#Q7i#BW0nc#pTZD}*%ogp=R2LuOO-W}F1?8a! z_g&iHD+TB~*>C9r4~CJnzhNR%_yNQFO>UQKTm4`gbm0kP_%RgFyva9%(jeKXX?1Ep8f@||Ng7x~p zQL_=bOPTh%5NRqI9Hk^zKyjcT#r`(GUcbsS=KeKdo(Y(w`XKe@B9Ez3mHa?NewuA> zr{u7Zn+kI#OAEgcz#*><-4ha85i(Lx6(cXf=QJDpLn~6$_)A&2w5tqyxc{ps0j8OAniy7gh6nQ%eL)b%%+Av})sSSz%h{quL8`4>4Gq-` z_F#)=?T~Z)JVZA{=8_>hk#{YGYysy1tGrZ#7}sa9t>TJ_ZmSqWBT*mUjBf$J5C6*n z`K-KINMB{rfj0Q*O>X{6-T29|eLela{A9Vzj_k=l96A^=GMM|lU0mQ}k0J(Z2{7zV zJ(?C2*M%ulPlEZGe8ZZtuQ@?Z6MTCB0~PX2%odP@_7&%8P&YG@w)NZf&0Ghj|5BuQ zeBIR474OuQrJ#8&$J74Jn#F}!n1~YMXmxW=^>e#VLYTC>TS?$ zHbn}%K03~*mH+(Cg6HX(41;pY8=F){B;DGTS4z;pxZkr6(<_a^7VGemrZg|()2)7!sJL$z4Hbo*ACYNa&CKeAFGCXb3g|;^bJww`=5g}$i{sun@ zfWW((y@mH`9jcE-Iug0}+Zf)kqn!vdn_UtyFpDirsXTDc>>I=dT&3d|#<)>_}% zf;Ra5L|{yDo&7E1OT!q1!KwzpdTHRSY9m}HDDfZ9zXs0eujv#`nhhK9e_>rHhUoW@ z+N6H9A<6gTUrx>T@8g^#FPJQtq`q8WB zX>@N{5OY?n#+)xfxzdCUaeEDk>`{sPOhO3u5jmk-T3JP2ZEfP(f(>-W?+uCRD}<>p zYTh;uy;C*U=}WngnNj&zl*$hI{kV0!493(R3HC> z_v{`Ce|KM^JRI84+7&Pq8EVSCNgQzf6Ly9>DWkY}1X z*(GQsd(clVB7i`e)8v5a_=+ppMsBlJG7IZ2{f+QzxISF=+6^Q3KV+DC2*`~l?5m3h zY3RVE@7~^Y)zZv^Bacw_?)fgP#WhnEdGd>zGdiV9*a>C`rZG_qF}bZe39RU5c3)OD zF%n%-AnkN|xsVY0Ww*esO0GjYzQer8Rsy}k>Y+qvbB&5z)AKV~NZI!n)wsCsF(mjx z|0$SKl-*&hHpoA+gl&)d-4mGxw9{2r@tW%x0nzZRrSai8cB#MAYafu6)OMrB_%E=} z5ET>eV_DB(3uyl#=Vykw_Sw!`;3U5MoMx$gL!!m|tmHH&+o+7;gdl7iMSs~4; zxZOV=qRzwiGw{6Z*9NyPDcpa(`pQ^D2Z|U_INVAa<}7V&kp8l*id$N~4vROb@TUhl zL$-G71o$C|@GQOJ2B31f`BB82fRgi%ItooKJetHc5tYoDuUVi}*#DUAR)m){wko19EsG@sX5hY=Bv>Z)l$ zQEpuCa%(P;gYuAtkc_N!Ys^~2%0kA*#>99zcVVG#jM_;MyWyjI#^a1JI{=h1-3r0u%GX@78! zFlT^J>m?@wN!K=6?0Yaq1@gK{E3Z6MbwulxpX6x%sWPS`^Nm<`|2G9?P1FN#-45+v zqKN6Zc1;F7+wkFvZ?DTV?d^L`hjDIWyW{25_)Rlm5ekD;N84`*<~UJ(siW@pcFFtO z+DzX3f1N(+qo`vn8ZXikVxShbf`*o z>I68fZxh8vVH&&f-@7-8L0GgbScb@9v=_V@bD>C|2C91~^I-N%hOu8=AsSi5=z11Z zRoUKz7kDHQ=?Vi?ubxZB!ukCXeArvsvDJNJsaTsm+=uAF-mvGsX@if+2h8vGg!_cD z2w*FX$ItU6LUgpIck|vX{w9Y}vIaYS=fx%cM>>`)-DfmRAA_SIYd?ynH3dkC+|QfV z_Rh6*@|QvnmOQi?_gKgBcn4=fkp&v_+q3X%p&2S&?WPe?__!pM5`EC>@b21inP%(D zSJ9OO{Kc_nVLr%bSjoed?{q7{u90M$TP$=WKPaTH!&CpRe#f6gumOD1n*71C?X`i$ zo7Gp-(ece3i$4UILNRmH(Z-kRl?7I|wYA-pYgXu`p?p_VRIE-+#H?s&m=Be|cX%(| z#z9UAoPpQ(^GAzpKMOWuGa580GQt!^iiXm*`3VUFhb*>gioB7$YYN35dm2sPi!Nel z-Ju3Rg)w|}oMf@DRrJZ{O)Se6>R4T(ec8C)MjsC0RMH153jKL;+|tMJ6aFk+6#j8% z0sF)m4?G9Oyp^yyD9nR}k>Y$$<aZc=hBA_! zf(W@LFcXCy5LACe+d`N&DVOfNjs$X$W#pw{%E<&+@0BYbWH=)}{B!gfa$lz5(nICz zhhqA%;+bIxE;}gqne?3o;XMl)2%$R@B3+QRKhaT&v=+3r>Xf4s2T_+CrjinIZCjt# z{_~A3RrW5*$ydI;dEqQAEtzZHjH#ywkKe9UiR7(+fdewKV1EgCfoDf5RrAwRud-qO zN}u`2yUFlKI9(bJf#y{7DTC=5_N%jNN09{m-IV`*((vkGHI%@+rppk^AJZ?P37yp| zvU>@5z6k(g_^Sk)3Y}hZfHp+PWf7i=UY3M5AxBPVIu2jMFAjE-*`h+A*d-E~OyS;p=Fo8lcih(Ovys zWkim|-|wNS8CTk-Si^I_p;|*cEdt-d=ghlYbg_Wc@?u1t24v4W$2bh{Y!F1qPF1{V z0hOwN5}l0XO@{0-)Db}@`v07BnTQfFEeE|jq6%ixp#%O=jGEyzw2JerR zzV};`e6(Ja6m{O;(IAT@au=FsF&=Y6IZot}{4mocXX4Gz5EW)GcAKeqn%uv<471SeH!n@9yP;W;G7!MndY#{{&v zOBn{I`H9bbb(fKDMPYsYVbB4d3nWL+js+pFVyChXv)QZzY1tse5MVovfS*?@r8`!m z#wln_tQ11+$hj+Jr4?<2hnK(WuurS}HcHlN5EyJ$CV3L%Z1X$};nFm<3eo?KDo?;y ztA~wn3e^TLx9QppnV&i7(v&cLPx1S$xCqvLpkE~IlR^oi@Me01aDO%?0GM9r7iJwi zdqSMYzp}y?CXz^hP@ZE=>c8PUTM4w!`L6z|imvtLV=VrA&89}2v;m_7S-kWnQ2ej_ zBRWx$-MT_y6G0G(9Xtgru_-b?A}2f9r}@HKo>PkKA_kB6$~oG15r{QUADWv2=8t^2 zD5*`F5SP|znMsa?D_Yt;_+UKpqAI2kPE_#hwtD55ru%oix>IeSLl)ENC_6esCIe7KpyN11Bfo+vGR@_iH0u>!c8P<9wxz3I} zTaZ2NH@uP~>!PBSNxHJKX;=ilck}6isP0p!F5la-BUKAa*gmXuN8Ami*|=h_|{J} zxDK^4-{JjSjW;IOsZHWIac7Y}@hivMx8K5iY3XAt*cE{z1M^Q6K57~wj%b!`X%pfU zj0)b9T*cdq5lT8r8Gt~9uezW(H9W}M0k!Y^XxwyzIpmm9XjNB`^b3{)XbOZM#2MpA zgkTB{B~J0u1|}hJQA;hsArd7GdASc?;pb))Zf$28L0NH&Y>y#^EQr!pAOn zkCVG(F`!a31EfKq80gp46iKD|dZ3)f2fq1rNl(m=n8Ic8Ib8M#_sXBKLT078Y>!>6!CkA;;OpMQyL|4SY2%8h7% znnJyy7`t?I-+7uN6o0@eoFMz}mQ*1E*#{w33~Q>_K{XjsiSr&fTnoUN&)|c3t$`fD z0D(X@_K5MC3hQ#PfZ%K67Ze!q|K;jA2^3M9g4}Ux%=#nX)nn%;%Matw!{SKDDpbq{ zgd0X`F#PgQ6YK#Grkw+lw{v#SPYTOC<2iMwHODZ+fPIql*Dm)OZc%{DNp9X8Mazu( zIr8|}7Nzd_Y;|Jy=3gRE+1%tVUTeUAI$g2y?(_E1fdOFwSf@?vzn+h^UK<7xkYmrU z*xXRb^BmJ8ty|`=rmHd%zYPmyAZAceOpB+WN%yvQ%dgVY{4fET7*I> z05BM+;n`0@4mZr{8jd&)2_uC({QRWLfqC30njgt$t9bD1oKHHu{SE!d4=$AUq48EDh4SOH znNyJ;+DPDSVNm2J*zERTv=dj7nM;bDv2&jQ*Y?Z0C3e1fs$z`j0=Z|0m)uIBnj+7E zLp5?peedfgp+A>_1<5e{{XQ5VKFvm-1(Q8s;6EYV(hQCsA5r8lb7zI!U?B`qQ{=&i zkz!9l_6GL$qRXzVT|S%#rD+lAZIK+)Y_{2ut2Lojp1^@}N z@|PJm)_qfrZ})wZaelVvE*aoD0Br|kB9+gh`vUoC%SFTv3fB?c0Fu=%k z&%OVx*vMfcEc-Q67a^KD7VTv`abTMQgFVUFAwJET@;W$kAgB2roC`YrhBY&gYeoPj z%Ai7`A`>2CuP_{jqf758XOi7UxzYNV5Fjs`^`%?!GO18>mYwWL3v%&R2mAz?5`Y6$ z_rLdFFn;wZ4do_-y>crLkooYTNi(UGwur*E0{h={%psKark&tz|IVJo&!M#$CDq20 z@BE39dEnaBo)ZqizGW2u>Q3QW={s)G*-zyjQd?^`D0x;+iSM2wscjY8lnm*wQrzL+_j#|2aQ2C$*Q zGXnIr64QoF>I#W&2~cpaIKnb}RAC{7*ywRi12N!c>2A@W;Dc(R6J$a{mVY~-3F8U> z=7oV2MW@>zj$1yQq1~I=YA=)IC+m`83urs2T-tfr$~QL&M}>^Zd>y`(&>e+&`w4M6 zkQ*F6r}?Jw9Sh_%a9TsTOG^bN_oS2&K#b3mWzna_6`{=`hp8gh(X@P?`${hs-R9g!R)O0x>lmxP$=Il3) z95?OQxp;?eP})Kc$uyxvG238x%QKoR7AG5w6x{Iq+Tu2IkL(9m!V+=-bnGp$&!4XU zv_d{|Ml8d(9Thdgy)E?ZuL95Ua*DP6e~{eEOs zL!BvumA9pV+_?@~kkTl?*MTkeG%e@wD*1&X{ic|=pWPmKV2sgwyoE-~6{4Oq}e-}XmV2tjEw;*g+>bqyX%-B~G0k~rlr_IBM z&=fX%*?19*`dDYFhCp|xA_wLCS*_~5g+Y$tVn#S18-}+mPJ-l(1T;L-y*fKsHpQhx z(?6c~ik=#tgVLAEo&vR#<-Jwlz*J981tXOm#w7^`XlQ^K)+fZ9Arcz($HJ|&Q7Ajs z4qgxdVH6NDjWW88g#bgDot-^fU(aEEwotZIa91jpM^jHd3WJFp@D~vgP~?ZFm+|7g zYYq;snhX~A**weacwipGLq&om)t-~Mvy4vJPbIj#$4}n~e>TQ>6Gw*N@}=S<=qB)} zOSXnbhG7_NG8nIS(t3ym(OWzWC!__SC|dwT;U{^Bzdb@&B0#vJt82^3(z5md>SGOu z5}X`5G=->G)B1;cPaHOhc9yI7@t(U&NX#l+$WV`KK{lM!upufUc7Bj8yGmL0Oy``3 zJw2U6STY5{EAk+H+D(a>R3>D+inbkOsW29<{Gyrx_I(FHIE=u*?uMkTzr$s&`IME1Yku75W0PrJ8Jn%ggk*YBpUw7z^D|n zzQ)aa1yk&3fdU1N_jWEV8ty+_<+|+EAOdW`fVE8kJiP1M+dj6AauUO1YQjnQUk*sS z{{$hpz{IigcX_7qZYv!YcbFfaMl+W|Z^N2Dew5#8XB4gO4NLJ71gsx7ueGn0UF~)o z5Yu7Rh7$kJLy8qJ1QvJSgZ6DMM34i1Wewy)OZxw~E149{hY!nvbimECfU>H6q2fR@ z{!a&nhe~A+3N+m9geb=TCW?W_|LkEaG$F~ zG>@1Qf*JH<<#E5Snv4k(5lY+Q%L3p_ZZ@*fXrz2)ReN)}!%@DdxVqy;4k9>Fsf(5o z1sBw#;*e#=XYmg@xhk?-sRRyQ&=+3H5H1fs68B-5uV+ogEcvLcO(;K*ZOg^X~d|7U7jF)sg;=B$2zi)*D4rSiJpRFN1$?QC25nlHrS>EdcyBzLXG%7K7#S;_0>#k5vLSKVr>b%#(HlWdXMojYW2uE0TghW8jb=vDB}6D{YS(P7;#dveX4 z_vZJ<*pjQLp!WpTNRHBD--!YDmG>&ZFV#n7Z;SRQWwtND`>=~i#q2;)BYNH(+2`D{ zjZO@I3$J5xSyUDasC{m9dKV^UJ0?}g}~e)ONFf%fPhU22C%jMcw4@lE_@@vyU zoCI6H(B>sMIas<^U$9Bto=-ZiZmkN$o&wk?Zk?khSQQSt**!x=m==TxLD{{$X>~N# zKfK;4LWGSCFHa_H8ysr7)m{si=W@@&Poa82G}IlKSp(L=`==@-x*(IG+Xu<*ha4h~ zTV+=AWl$61XxF0svV@6RuV>5`hXBG3r4B?**c9GxNXSS>5VjL%PlE8dyuEMDkhPi_vp30iIf2B~WZJ`p_U@@SeaI)^kN_cPrt)^Qm<4Zuo<#-U}~P zUwTUAkW&RLSV0$!YIpSB`iOdYJYqA&KDR7)8$|*ThtIc|Mj-laHn1EpTax{qda7vmbW1NKcd{P5n6NVb zv069owx$$0qy3{;n3;m@gPGl4AWW*R9f@}A{OR=>8FqpOndK?p#vDVynt7&%?6azo ziBU^IG@FY|#-}diq$ywpe$hfmVetKi9)@q(bf%Uz?$$Smk<=>^g@FE!Ag1hYE6I9$ z%~KFb&x=rdZQ1%F@6LkY-*!ez%1W#m3p{@Zaq({9(GC)-Rq`6dCjt_7W`1!Su0@GU z99kag#?0){vbfAU4n{E-bZ*vggSiD#Fp z!)@rG_LTc}dy_=_N>f1gwLxBxoPAHiGN=GKz`3ZXwSnCDzo3BN4aXPS8DVL#;^D|CJ zf#rQennMzWkGUGpDzANh9p9DWVjVi4lyO)7-_Ml;q~QkGy>=}@`eQ=}spcrAHzz6R zSUloe!=`@Py9&1e$O#B&nNk$goU@eW^8&TgaZ>1)Rb@XqG|+vWD8*mew*N?RjK2JV zZg1CJ$FybHf}$*KJ5iA1ONWU!4bi%G?}o|J;nIIq`8;1G877X}3_-F*k%NE5o|6sV z1`N(uJAPH@J;qGSdU}4sQx+>VrOy~35t<(S{gK+SiJi1Iz^!NSJcCTzRTb0j&+J)2 z5!E$`_IS)-m|AG}N_;RqqEqj)*NVmZ{1nXcI^gL9=3|vn=XQSx)K}!oUcC<6C+YY- z`tw*&gMt|h_c`WS{tq*bNlzI!=g8;{#~s8;^U!9vmAJQ@Q(i9j3Z{Ie7_m`b3%&m2 zZ;cZwbNl-N+#-4pLE|y{w&T%@;a~K1r;Pl=@ORSRdCYTXYVuWD{Lj~_X{2rta)KsR zwbFeLfK=0Xb2E}^n7_|hTVn-2!e#5h2~3)+P^tkcl%Q;4(MG3wUw>x5KttmAfFXN> z2}6_xeZzULZRMm;=T&3dQ?d7z4gmP&x!RZt z`eniO!`8(%EZdUWe!E@ zcw=0ZkAd5zRZ8rW(yINZC&NCQ`s#!@n8ob-v<=4JDtYb%_9A*t`FK0W!4b3a?)ify z&}ysLir;GntE9<;Nt<&}Wpya;BX}ZzCqgMW_$K$2H!19fVGa4OqNaVd1wvtjg~+Jv zKQ7VCZWBXCU4mU7!e^9Bh2JZu%lEoKG2_X=F(&&j>8f4=joazkE&KaquZaqQfBcX2 zm&fHZPPbdaujdLpOB+;y`@x~N%AgW$ep-;t z_RchtAT50Ijy z3o4W11$De0@rScE{K>~sY5Vt>(%z&!&Q2oFGU2jV9g z5`PX(f0Bc942BFw*EQQ@t^Q_mZMnck?Z*NtKhMp@H9qS1{$qbpjJMp658Y88jpd6< zdkw$6QIW9AuG69JvBTVVOU&?W&u<3cR88?3-Fh(?k4GNqU!Q~tBd+tJzDuIhmycLt zXGkkCpZMuGOvch+uB-Re`2aLQ89K%=m zz-ZWPwaVo2Un?`*ih_N|Oto1fQGaj72P{pkM88XEpXZxY^%3$-YEVf4*~O z&aensCQQz99bF7o54$`r0X`|yDY0WmigMc+PfPYUzY3^*c;A2A;dP#o6;sVFLtkK# zeb)QDcY~nkkHiy=6`W_Kr~Y!$7r?K6g6_HxZu(Qp1xvClm2+K%f*CClBERig;3_5Y za5-DWc?Z;Y*t#Pq63!MCL-5Yd*x{!lW z`<)A1y74RFPI7{{)mu&15oo(CWCmy-bGR@@ey#^uy%ft14MU*L zL*WBi>8FX!s(x@)&QHxpfEw?W#yfJ6_dm&(O0=BBiNCNBrVzxRt=GHMqV8eO$6dQ` zfN_d&=7ekgcc!xJh4+swf)ZafnGSI9qV~XMXQDwVq2}}WSVI-?va4yeevjt&;Mydj z;NLddh!1vQCg(6$fJ_E&gD64p0#AP3tu(ZoD-3@%{*n{2b`n8Ck0?4ng3Mzu4Bz&+ zIA|PS z28m(zx@J}HJa8&$Og%V|)LaJcxwhG?7Y(pHkhR~Oc#?WLHcUd)>nqQu@C1RWX$cD9 zG&B$Wr~o#CkF#=~B)fGChqJwo&^#Sa|-D%{E&s{_Xe6jJ~vbo!48^2gfU} zF004Fv}D~c7p83uQ!kBrx38ax=k_lK_0kmU*ZiL}mCaE!fzukivJ08thUnHmB)UHerP(S!_^RvsE?wj9Uw!uLVAvsB z1rgC&l?RBrno`DhUhqZ7D?tn8p0>TPdQCwi%C>d| zh?lC9RI4k``4AG*pZ#+Td{oKa)CU*FYzr`OJ-bNB$Q8;Xoe09(e(>!STF+Ij@!UhvWNW zOLL*)c)<{V_SoX-9$7TKcRxSxR;#VTvK==3A3SSp5sJKGaE>bDZi2dTE*t=YdWYL| z6B2(7u6jOd{=nN`bJVO6E!N=ph=M=smG_6^6DnN=kK+YPQK{nD(iD{iQ+k;})_cwr zm~#lsuXD@%L@in$n)6DFqymHEMbc3NG_zQ7yr3liXWt3Sv+MA|CP3@e;~yf=u8*kj z0s3H6M*sSTJ0+HU8LRJ4eEONya>t5?QzAM$yT$pXMCQ?>`;t}eXpPFmDwn*7H5_Mn z9-C7TRT&&Fh;GPQBb>NgY&c#}l0WZy=PnSwuRH_huJk`~b;Kl3ttp&p3KhrO z+q+V5ln~<;%g%Q#cz2c0n>zm5_H;_k_|)qYHf-E3&pfwU&N%&eyc>}!nCS7sv7z0Y zHtmr4^JgSGNyq8&qa$>B`qyvRCi^Y4?-$bPb-H}n#g5|zCHWt-AN0T=7DwrYKu~`V zFZdxdfcuaUxCL_amYs6hrROO`ZB7tv5`H2gzeiTSsBrDTB@2{)a;<$=iAG4Kx%Dp( zq~Ifoy#5&Bbf+YAcr@W>5Q)70c&b>tb#hAmte@Wl4?d-X^JCKJwwyr4CP-UViEMDvIM^?i~Ay^A&eLs>TZQ@q6&!&nWxOyB3xQnlZS9Pwgk{Q? z%dmNKZG`Qwj&<*Bk@uc*lpK5XK`KcDo}Q!8$f`UU{@nDtyXErFo~L5&|EEo$&-%b} z@%w|a>eaV1bA`*K4;Hx zRfOY@6F+bI{aq@C<(zqjeQnCF#N$I6C!LbNGjArm)p?wf|L&G{NA3A_rs8sO;kezS z`GwbjwLK4=|I=@W<(U0_vSvHg1S4-UA!2%~($l=Pc9T$NuMsvqz4nvn^P?#%E0N=m zJ4Ci@-Kp&P^JnU0%8o>$s=VWmTb2xe^Q{d@Hyx~x-+NCvdce9@#={uU+Jf{B47NxeSsTs{J_QYl)%Hpk3ROIOq!JX4uHn@ zhF!bm{BuuLWri_BrQd1(_3-n;Z}sc%D4TIQuQOc`x8*+lto_af>*wc`{Qq{xL(+;j zEk@E5BaRo8A)>5KspZGG{EdK~+;wFUA57(y7~G$$-^N|Y)nr+?Ckx~{CPtrOCW zO|;X~yz%A+Tw81<2MzNCgJCJ*vDP7&Gfq2B>GO{}_7Ev8@u@*@(t8eUR>d5gX^8WeedfG=aeC^MNjkeY-8yi?#;r+Wf9qfVse}92CAby$ zgoLo8>vu~2eKO=BK;v>T<9NXlf9?oLsE1`19&B&xipl22sD#1^F3>x(%0m|mu0&p` z>LH@j5c&AgKXF2}eDtFC%k~}i8>G%OPd>d$rGMfnTbg2?yY6{ZK8EzS{q>*tJrQLy z5&bkSOs(tcCW5eU2IFu^OKS(}7$OL!#jr4o`yfCq$_UYtM-xPk#&!q`@Ek!7pz zYFArlcKY1+|DQYG%$d8hWp-z0+c~>;PQB-x``vT@-*>*#o%2i~r@>_Uldh^^lr-&66G6|K^HJ%_7(m$6xBZJesg zCg|eN7!{O4zhj;(R>vTI5aOO>v z=qaGg#853d9rK^x{gHYWyMmhKPUpVardbMYTtn$X+||>3IS=g5s2A>xs2@RM?8Ks> zi3~M#6#k&j5A>J?6T|G^jFSRyK zHBzYf(kT>~;4FUHEiG8q55uu5Q7t|B)bo0l(Rc5D$Rtrk9`h~vFT^%p>#m*)PV%pK z+eHt#Y#NgPi!WZjssf?QWWdifQ^iX@b7}J&h8JJty{n@D|G5PIxqOaB=DpO~xBx$C zXac|K_lFC;cU-VpJI^8*MLzHa;8hm)`uG(fw#|PK}Hybv;1;{>Rhm z`b(nf=@WT%dVrg~Iq+L%FlWS{LB2v%I=|TW#YVGpItn zZ?SE>-V|Nr`7Nb3K9ku#&@5<;*POn_EXI1D>&asPIIj+3mIzBcbvCa~0r>ev$|hlR zS_zwZO%y2LCGkDUyP>-iV>nNq$g1J7g8K2HMKjaKw(*+Y{PIb>gxdJD4s-Fa)*HT~ zyCEhlI%1T#qQy}+TuP}wr>@=sX&+&MN%YMld&0y;(8oozNZc@IT z0VI0XHjWlGN~JvQ=k`{?>%)qrw$&4YKI5%z?>N>s2jkb zpTs*8GgrVb`RDV+MIaI|ft}6dTrvxv>T;rXZH7;fVB7fgskr1*F6uTu$=fmYCGz2z zAA^8AZHn9SQHVe9NlzDbWA)(HE*j#t92fKB0 zAEuvR9me_RcumUx&KgxW%oi`U7Jr%X(J>uYpuP}){KqxEjk{>)j&AF0^R|uq3AxPt zi>Zy*@@o8&KR*utC7`cA1jMs1@4sp(v*xrfxgx60Ssl_~FE{Vr9#KEomr@q^g(CB3 zw>1USPp}Y=s-2B^Pc(dI8=$5mgPv={9%(jS-d zj!70%8=vm`5%4!Z9J);jpY9xFBz_p&WzByzWd7dvqC`20DT4(4y-#^k<`4F!P$g^T zlLCAn+@600j;^DdgYq;NY;4TD{!AuYNTpKTJIQRvx(-1V)?uel^p)Z$`QxJE-)!gH zQOdS)O*Q-Dr@&%pbJ-a2 z4h7L{UKdi&o%R-e(NEO^FKgz90ypg`t91gH?pdJxJhwwY;~tcff3~>gYa-$4^~WVD z2Beb!e;f}722en2_rM=&AJ=hnj_YKg>$h!uBH}I6@Ws}~r~8^r@E72xZA$%=gf#F& zN=jkxm=f^AABNxTJxsUU8K>L2A*6U&v+yXuf%y3`P9Xzbekz3>25THskE5HxdmBK-ywvGFVXZ@N23%!lk@|yf8D!?z`FFH_yzo>aA z@pDt15I&k9E`Yz4ylWx4O7T&BYOxRe@hh9E%@yQ)4R&`7FRcU&ur8 z16`F?^+2C!+qlrl+6#*UwX|`i4x;kq9{EI1QVslt0f@d|Oa1_PO8pVol=efAns_gE zS&-w_Cn~~*TMEoA1pxYmcs!v88Ug`I{cN(;O=2YBX2B?OnOvce1NetsE%^iZwYo>Q zafLRnY#XmmK^r073>ifMxu%gsY;0Nf3gD`O8J8`HpWg2TN1?G(c zqoZ-Cd@>mDg&yB90Tq!ptwZ}x54!5&4ktbwFJ#bLfbKsZ2}iP!{zGWXY3y_r)@?kG zHXg8T+#scO&NBt3+s3O^bC=px@f}DS4gP5OX!ClQj){1Q+J_<(bvjh>Q1aJm9t@Uo z-+11`3DY?Yl38OZFmDt{rLy@P1o=dw*Bu@nMMDmuNqSQ}%}OmFa;M1}lgH*_+&BhkM*@=PPyY=5zDO zc+$xvGtl}M0#44!#$vHlCYRyl1qVF=2QA#T@p*frwqQR6rrXBlzBUCx$7gO+w^f9h z;LoItQUmn(L zDbNrKJpJ_XR0aZkDm74`%0~+IgT92*9_SfxgXtip|3WSe#eXKB!*WIp0-%lO(Z&n5 zjhpnc?)jy_OxieW+^xDx-$S)0D1kqOA0{*}6a2GHO-*Ss09;8({$qhaAP##J*D%)0 z4CgZG4^%6_hFJ>C6$Re*<`1kN8X7J1^$kJapDs}94-7#1*ZO{{eEjC1I&$EMd+Nw3 zH$D(|NBc($*?2aeP2#kHoXR#u(8hCU<2l>L{gku*`Juo}+W2&9S^|IH4P*iW{xan= zgC+E7fPD&f5?6v(GMP+dv&oUM(fE(@xy)bq^08h^fjOZ7KMJaQ(&-#jK7AEZKMNF< zkLdgT17U-w2Hn1+eTBrCM4k))vqJ&@3Tl6}@vLp*bMn$`rZrJuwrzZ>!YXwBl>TAN zd&mH2bdLaFj}x1MSWuHGaJnbdJ~><=^a6spTril)416AG{%!5Xa~}6@v%i)C^`!u` z^O;|L(+4&a_=koPd8&Iv*Dq54WGWvHggw3QX|=v>z1qHhyE}Y**qg4<1!1R2xe#kq zFoHIYKikIZ`|fOR)1yE=+PIW7(KJuSSAf6V0NdmMWB?lcv2&su3Wf5KNF<*~B!X#7 zti}ftKsdlZgeyyi5EvR7IUnu-PFD(KvyOw_0_>~<#!#9U1gCZ*O+`5UMm?-^iBf=j zYVy&bM$`wW&<|OHyK}nSt4A(O;mi*X4nw+6Vn$CkKQa<8jE*Mr9N_KiJDw--kBlS> z0{qM~sLtwvUXl74X0CdqF7&{C2h`5)on91sxvSyqz}^nSXyZ+2Mj1E8(_0DJ}TFGQo!!pO)7nLuuIbTkOnPaqr)2QnF6X#jmD0LB2& z&%qyX&{J^0BOEdSR>)%nbVn7Kgbu4@3|<)1TC?;hz+E`yspy7qp#5CJp2MbVXbXCq z25#2I`OTc>#zkBL`l(b74B#~VB|X377f=Jpt8%YFzsg6_9{ln_ccyPxEB>IPhm+aqw54b3}j9xZAdEbNB7r7r@|e z;mnyc0Wbjv;7=ytkO8FAO#uFMAekI!ifb`#8u;;P>nL z87ESIwYkq^0P4#SbZ*xP-EBM3#*d?oueNPmQ^fwvhyn|#jZgFdRl&cMm{9F~rlpVd z$dMz3?(S~J6i%Et!2x5cfC7VqgHB6Ji!(CPTl8 z&Q@`yOL*@MmHT(WSfG zgST_XIPXI_aNvNuYu7I4)TvXNIgkOw<8f!rnyZ~eVi=Nt0#bic=Rn~10Dl!gJq^j< z>jmWVl`0;;zf`hyENKe(cjFYG=R?mM6kXm_9L)Apzu z#b)SRuuE24`*X?z|C~xY1yuxmMZjN+Q8v$y9d&hDDZYTk!{WB~@}@v}s|Jq_vS*J8 z`i!BU1H5z#@KfExeNF`Ut4aOiz@Hhw*f#Fb!T!!Y1?H=bPb&FiTU$)Y(0lpRM1h#1 zw6&#l4;cVI%*yRQ&mx}t#;wH_!C|T%Bj8PP?ke4W#=tOZmNo?h;Qdcop2F!#`W)Dm zu;~K7KhK%^Z5y8{gf4M}!)>O~HnKsxv3*)iT~3&zh)bTQ~4$fz{MM45y(Qh_;^z zFpTOT+G6|+LBf}%y}t6PSFP$Q(WLbkX`WGXREh41l)u0_YYdK(~wu&}|w& zQ!wL}wELX$)2&&vO4F{ZYlYL%;emTwTPtQ&HS6%^=9spdnxfj~ot%DK&S7!8Vll7L z`=6q@xupb7EiE4Sx3y(UVeRc6BQP0&Dg86Qb?erZ();r_{ijc#uApaMQSvu|A8TH8 z8cchJ-KlR+B+B4FHkPQ!L-OZTXmK~n#`>Gmb8}`D%jL`}IryH3hR9(1*|S4BzPGo( zbdNgGsG2U1a!imnpI88&VSdnOn139LVWz}S|3p$h<7N&1%w!@4z&IHMrdyZ*-O>}F z+hhdvPh=)y5)-9gbm5!JHD0%_+gY`0rL$s1yF;*VZEbRzo12_iEb2s~5q(7>VXUPH z>Gc$$P*8)2*yWrSmun)h_di8blSuxfs<~O*O0~9njDYD)w=e_AXT^#YWiXS#N$jDa zp$d=|u;(qD-6pr1?y)iNoiI+OJWINX>_#yIE~H}}Xk)=8S61t_6`Y>PYhYjq$6_Wi z#WwC@wZ7Zmj}y>fPM_}c==MB)*35(gCa6z#zW~0dcOx<|O{5N5rJo<@=wD`h5vA-3&9CLp8tLHxoWsQargEZraLIN9F7~XZ+uK^hv&-9QU{7nDa+XLWv00vXPQs~E{e{87 z5x2MZta}XSA?T_fn1=^g7Dak9)clV+5$H4BOn{&Fm82GWCNfijKku820Z6`PPe8)_ z%s|4IjlJ7@Qs|={=%$^nt}X{E39h1s^uH-g#dmYQ8+nFu`6Z zU`qN7^MgLaCR6n=o`zDtXKU}|Khpt!=HO=l43lvHx=mA!5t#AI#(jfQ+qZ9b)~{a= zDZi5pAkfj#!7B)L~CH9gfCAJV52k_Ox zNPvmLYbB2CPi5X$EsXIKg`4*_(5-1z1b@0U_Tz`=aFYSh2L9tXWY3TZ ziYeUSJvG7qqKhsH5cn}L8N?JtO8f-=5UwymA0`aY=SAS>HriaHLGb6<%47s31_1xG z->X-Hh5L)=9tZH%YCBQ7iNdSpQA-%`u_}!x3ODnfP8u_P9o-uAk)H;B*p&VW`Z>A4 z1aPz&PBg$p9smZA#lBrR^Z@ec0pzioKaYWJx5NPMt7Gk!X;#$$z8WcJ1NxGmNd5Fz zZNQSyZ`Z;Ac<)3^K=PdqGmx}P(!K>;9NS|+&EtRp5cDbWhoIsKK~m)v0q_&>BfJ3c za&g6__I z;Ai-x4cEL;+_f?Q-ZvE!ki3_jeY;ZEUw?gI_3G6DsCY2I+oD0AQa-?ofFA|G^NN8s z+HKgH0l;5k0B{TN*Zf{_uQf}b0s{V}Q~Ch#WB?lUVH5PzXnRSxd1Pyfelmk1BM>H# zKYR9U9(w=6!GqWp^>(DTrXdul74W4}e&A;~fuknFOloBS)hfK~8N%(D-?VclrgFA9 z+!C8=9)Lc+JFV9j;Ew_Ln|R?R(Iyk1JBmy90$`H~Xz3resrrG}8cTr^1*Eqmhci*y z&!f!=@bie)48nLucL<=*D+u7np-g$6#lbNQOj}JVv{e_E?CvZ1mI|_t`ca@7cGjAE zHQ;9+GnNo*WdOBSc*&>tJ{i(qfSZh%Ku%!iMUZbUUfkna+?o-pY;^>Gk^IR32>84xHn5nZYj(h zNl=P4b4G!QfS(1{Ecr_7DY$v)1_g?6QQ{B6#@QSNebgp^zko3)9Ge;7(XH$; zu(zrO1=$0s9#SgGx26sh5PY62s~Lm8Wa=-(G6SK^v}_ajr3XMso`7yj{{;WG;$`*% zn1*RZ^&{Y~KT3p`3_jYDn+|^16#>?>94Jr${%8Z-RyU1{;7^G^46xVg9xwuU6^_Yt za%ekxHV_AWapj@W8Gv8%_k%xs0%QuJ`VqaqJ0gVFJGfbGY?=Fkn4jiU z6G+TY6_;kI_^1f>WWKxz_AuqIj)@Emub|PR0N#z&~41-MNBl!*r}l9S?4@ z#!{db3P9_Vz!I?UI)&`las28q?i~W?k3#K(vEIZO#sE^7@1J@8`R8*-j~>k(xE=HT zi^k6creXjV{DpFjwJk_AmfpIwqJ%Asmp0#nT%!7+G*6vA0bVYd@gp`FMax)L?ZCAy zn^zqc_(2hCW=#RKqZZe3US9}CJ|B#=eH*hqp%RLQvRUjYi2bF&2=v8*utVQw{dm;uvCLoMJ+nKytHO(?? zGE0G3Q=qN0>n9lW1@PyBnM^tm4zF@XM!e~svODi&3}B)Pgk0wyY(vgn3H8Mt%JCOS zrLqrBbdQ8%pP}EuxdhmQC^L#fY5uBzY-~fZXDvyrJplzQ_)kEX1_g`MFTl_D!OLU- zW-oxMAUzw%O8gCaL$;U-3as6@VIOAv1hUyofG3m{3fVwB?wvz16$7ZI{(1gh70nm& z0DUz4BKY%I3NixpGG0_scy-U;U=kA6BotaPoB6-t=LC8r1?)zu52``Wq+%vg^(>ZW zs0IJ|d+!8%8q+qJ02zSE2^@s4BNsmbAI0OkO2HR&H} z8x8uLWy&=Md7LsyMt~&+U!IJ<*xUTCz4*!T9nya>-DJ5fzc>s2^ZU;It+pBiFvE0u zPUoE8YTMG6GX=7k`42#K$N(T;YYgET+hhQ8KDRJ{>CoxfBmFC~nXD@0asYoy>rev~ z+;nqG?2QxMkFy2-h>U`U=_fOooiu3=VX}Lda-0SK`G316xch5k#+BT5I;WpZ*5619 zV89pay_&%Q(vbR7Pyr>iP{KNx41j(a05+w6hMQ*ho-HFQR<3YH;_*8YLxcY#k}jf9F< zSVh9P;K!l_&KS}&hrpmdSh~SFGzBd9FW`pYo2ej-U;)?IR&6;@fRaBM0QLTS-fXr_ z+tr@kl>R4E{nWbIBaWOu=9L#vu^4ARdj|QyfdS(@#sjc79V-?DbBIJ@|58k1ts(_1 z_}ivnDPSp3GX+HYXAc0!ygPZ7b;e8osR@}v%?0{y00a6ggDCZLeE^Nt{6ihY0pJ|K zKZgNf>_w{bIE)7C22Sck_NPPv3;rciEL?}L2QV)c-9Mnz6TAk?#nW$1<0xR#n{K|7 z{l@!fR81iGbB@2h%4M!CJ4-Ha>LHQ^sDjVScai)pIxY)gDisQbX^j{1E z!bPJo?uBKIj{+9_eFU-I>J*T5H{7|M-`EppU3GD1^|Us0ZYZ!BLzYjRE#{3E!gqq{ z@bhH2=O9%+T{+{um4RVL63$nG~?# zZ&Jg$C#1l|T}pL8$f8XEy12_xNge`dO~WWaoIAJGEzy4^@R#qS(FXJTwbW154|@P+ z`F_<8i{Ir zW^5-XGb=9bcGPC{1TID|z?!+I0O?K8r%iJyHuD}zdGBa{9|GVcV`#MTt9=@&_n+!n z@4eTxnvF?_WWj$D;wimdMp$IOrsu_Gfsm@%QeYm z02i8{_qyt`H2@meG-s0q_^sTai7^j9@*W0~=#4?^{R|G$x@=A3Dk1~EW{H?l?_iFN zZXlleCpxYl!s(vfs(W0xnNL03`%a}VER4m2nbwFpKA6GoqwdyN%z3sRc`v0r>=(R1 z-zN4VA16&UO7(N7zpTjbP2e>6VogxKr(Rf~G+Qp!;(L&Hu^qj!gmGR;5__0EH`EwP zcq$(rBW)UQzCZW+F+&^S=J#>nYVGOu11Pw8&-Y~9tkeMv|D*!PZk;X(~upu zBYe4-FS%~;$==M)p}4ou_mVZO_)s#=W5*L}V`qzU!{P4Z$K8>Q8=d5Gp~+OwDPQwc z>1_NwQD8n+_e#I~iF;y5}4gHbK_^ z`HUOAW-xQ%Ks@7SR7P!G6H$*Ji97c_o=}5W0o^-*(2P>6SF5cL9Y5Y6%1lt%1r%&0 z{{{3i7D81-%4c1EcB-JRSRYW2_Y_oDv!ga(5ZIc9MS-84cJ)B~c`F?CM6cIdTUa%m z+uGdwoV#L8Q|6rG0C<|Moe}lek%Y>^8!7Jm(3{ArR?L*jfD!Coea=?&o)2Lv=;SBB z%x$$7MDAAdUl6Zh;Z=gtBUSuI23%~C1?dUB0BaT&1%7rCXWruI!>6I@S&5lI*u!i= z8UOzN^{(85M^jrmgPC&%;~CWoq~8eOfBabw_|3A&1D@^8Li*2e0GPdi3(ffD>bBs& zT;F_^=iUb}*>}Rz`4d=nZwRP!Iy@$@7@`04sWaZdXq9KJN01(Lon}S@1NC2Tw7#R* z6Dv;e=R4wA=m#^%_WDWkAMNt^nw9k z3g|`Jvy6YN+GiQReDl%MId29Dc12PBnBgNz?u#>Yf+B@D{UZ^{xN-lo}nu zz}%*FI-Kzj{HXHmZn?({?>{@FR&}jV)zUMgH{J3+b=P-3t=iks=l2=O&lgXom$v2_2zgNM~`-TINzbG-JK-c@p! z63x=Fw$)L*#E@B&d2?4wzQ@JLu;p1MvN_@5(VonO>9LFhZI0Rq;7@=7JPu$t_V+B^ zPT(ixhY=ahgw>N60N$~&MKgfW(e%!?w&=l9;$`Nr;J?gX_(YEz4RK#|9)|6zRV@Ma z{6KlS=S26+G+Y4O1k@EP+BJy(pTE0(T(%$mgO6dau7JA#hj&&0{p((RYXzWw<;&ku zXL|c9?*G)k+=(rH%dqg?_rI+aFZCz|7>+mH^8S+Vr$70*cGJH4n#AefD?;Kn~z9zv9vp>$wU9eF@R-FjPR$`{3TegbIv}xf`3Con^TPkOhBf z7}i!-Z1BM100wvo9D9%Dwe*O=F#t;aG=yLH{5MO~ru&8)uTdK|tf>HUN$@F1*FSvl zky0Fi(_|Wwj`rQ(eL$^T*{-&1-Bbz=7LW2{z!yIM4P}Bq!%T3dpXSobDi?)*;d9^6 z;k0*LxJ^C$@MGFf`_6y=w))NY{Hl83frr(v{OW6TIDZ7-{dKKYUg@S8Iv&A$qWr%e zgT5l}lL0J6!#-&QGX7R3ed#OzsI$7Ms1|zT8{S(1{$_nmx4-qDYBa6f zHthPm_lZI38uGNN&9|tpef7U|mS6n0 zZ>vq4)@w=mGoSvldiv?-D~b|urY-Js&s|@UW;ULG{QJ+9r2m_4cuUD`=6Tn*@6p~{ z-}xbR?&b|p_k2vPUDvG$__TRR-Q+&AzT)<$k+ie5cVMdxYWew|Hg^To5zPMKz%Sov z&&b@V?`B)?TJNX6e=CM>9_vx6l_R)7eS*E24-OahxE?uz$rZ+X)i?GHI)}hS!t5n1 zLt`cXW%$zlkF2+4=9U2fkW<4LFf=}=tIn-2@Jrc=L_$07_|xChfGYqg@rR!|szBNp@ceqT&aid9#p^co|XO^mxX^(fdA0w=o>p)Tkk9s za(@yGhW~6?yqN|*WRU$o0zN*Y^&J6qVj!nZK!tE>Ft2v452}{vB;VHz>PavpP}08c z`m0KAGppZz-)-tUcYnqVsw$ONB!K55AAMg*?Zf=d**?`k_&fh`Unz_4e&>F5!H%uU z3}fVb-uE{3iGTQI-S1gpYF@JTi0g50K$5}msx3O*HXOb`lSHIFpO7N{l{Y& zHQ0+G0W1XT+!#^6_q$mAwG7Ro0RLzta;NL&F&icLr+7ye{O6#dUUgo%DFna_P6GI8 z_MghDtBtsN6fM&u&Ad#2BuM*#pJ^oxh${?q5Ym0lODEx*rN z@>v9F-AE*||7}-BcHQ|{9Gf{{RWBGo59fVqBev(G)bHv2mBX~(dn5s70S7(!dF&yq zi@0~w0iOQ2+{~hAA*p2Q=Rp;{EEEiWeYw4$MnCTeq{S6jEqXT2t^jnabFgRsufO9B zH9ywL6FsVH)k;Wfl^=J_85uWJ17#z6LZ>jFY6<+HK3Upo_s=wpsygD=Rp$lO!_RpP zZKioG^!up(*}He|Q?I=6;tTG3761+)-`WyZ@oZ(=5Ooh#KMAC{TTA>z{fNpy>v-T$ zA;14WHe;)Yh5p2IQ@=$4{wr5>Ts}9CZ*%oiAf0tp7z?|u-r}hb{PFYQ|JToaT>bGM z{Z*;x-~QcS*KPstZ{GE(Qd}(#KTw(>vVbJzCaDPoWT%6rm$pm@_vg*Dk zsp`pK251E1HW?Lk14H}2zWGE0s=8o{m{*>c&7}H5;ph%<@_CtNb??3RhIa0{?B4_7 z;A^pKeb5O3@Sq0ZQH4#>z&*i0?suZmwgdHkdz`g^Jc+JUMn-Y*By7%KXv5Wks}s{7 zSAi}#tWW6+ZcK1f9GPlQ=A4UR*VUZCtdQ010Yy6n&B3NlI}xm|1a4qvKY2E%uGxw? zj^F|*;9wJuG_R-m)>prCMQ`ufvE#>kQ^$_=rk{NBVEW_}{rP|jxfmfT1l3tLpdvU! zG3vIc?m|o*aobdz?n?47mtAU?cHgFM^SYPC%3)PbX7ps#lejY2_>I7S{D@K)>})w^f!}*G<-TGg-juJ5NObaPB>nyU8#+5z zp1|y`zrrk^5BhGOw)eT`o{PoWSD(bz1)baw#KnkaBot7b<&uL!uz;^6ivcrA{2c5I zhXX1NwJEncaD#ytX0w_99S%o6Fzo^tTS7q#)VsY2#{y!7?~kAH7{Iaqyn4a;{Ftm+ z$Q1bTGn9B8%+vw{koQ@Xqva&Fg7v{$JQeQo2RH`=Y7OQfDx$-h*KDvtPA^4^Y)cIf1wkO_o-ze*A{GBVPY&*f4$ zK>9DM#rK>|yz2xc{IS4_+ReBeOFP+N|xw&jdkYc#PH30&(w6>j6g?t24KtF_pAC}smI5WHt`kO1z zV?ea4T4Dh;HkMI6@q!A4_%Q?l@Ywax&8ee(DYc>{gkC@Z^VtI${2=bD2tY6h@Fy4& z2IKLuUTiM5I*9H9f^dJ~%~{MY0E6fW21DLhto&o&2sqK|jN0)9ic|9a>r1MVYIW-Xf+{wNX zcVINHfuFNh63Mha#_h~7b)N-wtS_w&o)}X9 zhL0$y)j(`B+#VO8zdFob1J)aGPBrI;b59zmhSs9N6+77e8ZI7xFIM(Gdj=vuj6976 z{>AhDSW^N&jl92~J@3u=*MZCD=g>!fd5wx=Mvof{4t(p6yPsMu8FQvgW2=muiLtC6gF#TA{Z zy(OZ)v#(#B8O^ILt7Dku5>c@T%EVt3`u-;55!MoZQSwI*0=gpQ6jUF&m+K&5Xp|fq zOCHYWb6fefff1kw5L|24Z!x(KpZ0*ijgo$mmHp^RPl9a4y#GtjZCq1XOmtfab(QzD z2P&RZ7^L5_I;bR!_6v6`pD`PJn;61#4{p9J()O2c>>OSQ?`NUbVNSkimm{SrpK$_V zPGi*O=C?opmg7$k-xdnRRM0u@basunFM8Hu&d@DqrkT=8z^ zuj_mqzZKwrvVY_or~2csp}>RrI{Kb{hvF((2&)JHzh}@@PaG+zbjDRLzrs;n9U&Eq zhP8hGn(b}s(dXls28SMo7}Pp~%)$VFhxus^#9jv<$Gsuk9J^nV(r#{U+BPsOS3fm?B7)3xl6gEc}|SVg4RH%Q=zJ2efL> z3p;yuSao%Arfb<$yYKJ*@!!h{4A*bJ_sxoNVjEGIkNmOF%_||>uI2MdC%?J*V zX>V^)_uju(U9@wn+V|)ob*67nt?pi_o;iH1bUV||g-ML1R7*2w`OeO0Ngv<9BZtAP z@eW@Euz$8k_lReg@glvO3;vqmFzAYD^~^m7$(iy!(T2YsBhU`*Cj0;hFc$?=5c@}7 zbBdC_a$ds$t{{LK;Eb6&5Y5NPG8{FUQtF&l(A@_yn42!Bd!E2dh_gJ8mdqfhes(0T z)q(6SK_+NBk zM1uxrKwZ5ptoCBs=QivXNeWyu%h^7E_m6jK8V(MPswegz)+D*}D|c()7a*ri;Q!?R z{hE&d)?N3jR2phIn1B7uH?=K40>-p?U32v%+GafcdAwu)>0Jc=A(X!hAkQ=`udjbl zvQ*sw{KL`4Bynw=Z~JQNW}69{PO%2ku`dnC}N?Z z@*RrKN8TqHfi;!_)hJL`$sgeCKyQBmB@u!q4aP*VX^MJZxVb$MZgSla7(@0<&V`D{ zNhNZssl{7IX9$HPLqLb=@d%wl|j_pR-O|0T3aodpOGn z|Evc;CaR$@Qv4eTc^9s6CYMcj2See$93B?j?yXKJ^l#%5EwTVg+-p|`^)=h7Uwn~% zwQA*xHuW<|*Z=e{U&RrJudm2<_vIIA|BeebYn$L5E1tlW7)w^9oyKA|E+KO!My>BmGb)f=`1(?hERoqhY{NpFTtjB*CAdE#K z-~XOBX~wtt+;!?-Kl@Gf&bPltqO{HQ5AQvouG+J!BD@yQ?k#12*S&yRZnkNcEd@MO zt<&Q}LPpzj^$c+~LQbWO#loAIeNr7c9cvC^+B_LT9!vrYsYX&N3#@fLPH1t3IeCZXLQPXnY@Z#M%9l`Xb8?VB<8lTs-FSt}4 zdh&Vo)YH%FwB|iifv;H!NlVoYdu%H@+VEcS4q<-vt*=mTzU5^Gb12_=CBSzDm{S1n zn>G#e@-vC@9c9-A+t1Z$-}ct>>|fr?>+e5tC)7;6Dv?NP;1`Ax(YsH2dGz+2EoWAv zi|^*dS#P|C@9vuI5&ixcuD9y0F+ZDp`B0#);7_t)G1PV}xVSKgDV6w;2Jr!E!2IXm z+>?FX?r`WWuV{DP{O&8&JKncPz3jCcgD>74EL?XnPM$8BmRPI<;PB2=GMyPq#NXC4 zl=<*5j@%g-O=|Vd%GM@@&Vw4ks=cp0+^@d(_>lVc&j$2>?MkdrVn)C@t%|V#06+jq zL_t)07;*t9{>BPw7|dZ?cR}sg(5x=NwXP$q*5U{^nizn;9ZVy_0bfY`ax0}kf`_-_ zoHkTJfxvn&rm9NXR5ttX{MbBJrL$giKdd{MHtlP7cp$PL`@+*dRNUxoCJ%M=SdaSR zm;S2+x))z`{C|HPL{_xNwny)l1a(VxXktSfi#QdeEM z3p)G(b>W5QRiq>UpTBKmMOZ7^Rrjh+90S>=-uU{LR>V!^p_++Cb_n&SXB}Evw8pX& zB^%W7o*S;;Qwp!e@j#JDAL;SHpYsxU5ShHk$Cu}9pIS(`tkahD9(5!GB;hBK9T2n9 z{Nk<_-T%MkOK$MXZ}eu&RHpEJxc}4m_&P0)lns$8jof|{yhma^|W4?9QefoBSZYUU1@A=I)l+-Kl{mnP( zxB}ks|NFvS+AR_@Jt8SHjBeUgv%LR3-hKK8px8 z|K*#J{9JfWNF6%vskAsKFFo0Ij9raD=(*h3?5&1uZPH~zfpGxc=;w})r8C%1 zCLDr({=WMk2;X?)jk%-!@js6`?nkI1;vAk3y5dRbZJ||C9hjz>!p>vgKQO3zhO00j7%Kc|HvRPUJq^*rLPzUrb<0T2E7G5t)O<-@Uv zuYKcQ^}5&IsN=u>&3n}^zVuqvtVdA2Tb_RAnA(26)?AkIn93ncYN~YgjKBYhjJp0} zPpGM9zSZ(tNE^FVtDg;<9tGz0t0o90Q)vjzJcAUfh8MixnZqZBHmOW55Yqa4N6*}d zW7bD|E6jaWSDa7q=FH#{AOv@p;1VRrAc2tJ?ry<7I1H{qf(L>GcX#*T?(Xhx!%lwx z-HSbEKfs>8nX7)gpQ-Aq>aKbU(-@K0Kul!sMqqJ9J?k{<>6erC^e^1$KK99}8CRn( zPZ4zjMXo&v=kM0vN(9hwK!joLbs+MyiC}Vi(GXSj#L`E0rm1zGzF45i&w&uE8xYs8 zv91NiWqRb@P{MkR6@0P7_SXyUy8G*2D8OLLAS?c26CfebN9|xYNk_G4;n&RX@FWYq zIs+o0Pw>m7l`VI6O|#nip6s#aaP5X?R?#Iw@eQ_OaHM&e+r4hN^jBQ&z9!9@Mas;YaDQo1%^2Yf^ z`L0bUx|lIXBWPndKa&;_Y735Y_jf6vI8@BR`IOP*`D6stHX(JiRa2fwr#Fce;LGw6 zwdLXHIWIf(la7YGu4gyx5`?ctt((7C9IoG0=X^Bb7mj#BzGpZ2Zl#7ey=u;Bi7sm5 zrP^oNZ*CyI8xJz+vPMqZ7rDZkcI4H;R=r#uUBgl$ZfX&={oMi8Kvl_tgoLV65#c(| z>8_#vpsBXxO9xHcE8vcY5ela<#><)4a?7cXjWd{q;$*Q!0C{YM`z*YQ1yWVDt#$~k zu_LoEVcCFRq$FOblXn7;EbXEI_xxBVK=9qe1U7gtj7k*ZLB|Nsx+)%=Nos$@cTM$| z;dysf+t(9L6E6-ad*tqZ%lu$34nM;ukzaQ2*2n_>iIljqe=NDUtlJG>rSOAIj$S%7 z&j+XBlqz?ookx7o%iJa1u)l9}bVw-M zOLsDsC3TS5%qv2e;sy>{j4r_LpW*N8xy8lqC%8CY~9pn_Aa72f1bnds| zQGM~yC0~0=h6kVf%2Vb$>oT=q}P!fL=E;^96lRQddHK+jl-Z=b7f4>$+N+H|MV5XWKG`xp&{&Ir@ zOCscL-om<3CIGYnwg7j~w2u^#D#nR3wE`^T_ZGbBP)~A%l~%ekTX^bSPm1&E{9)JW zS(1tluzHWa{{!~Tp>0KJw=ujKhsO9#{}|!bmM0SS=PtjFHK&e*fYLO2Ss|fZch+@F ze=_}I?PTEPfXImBHZxvnM|b0}$^+I9jZdhj0r^|M-0fK~9n!cw)#`hvi_0|LtnYP{ z@g^uQh4#NUVaK>8`io`aLo)O}WfLC}Jaj&Gl;wfCq!_O>B?|3mW;eZ1e@~TnTY=n2 zQ+rQeMZ1!=C_ayHLk7SQ-IIh2e<3**6L-O4O6*Gs(u1+!%x-CbJHM#j zZ5cR@5D=;0%9!{0_kr-LopKg_^?vo^kA2R1=Szcytp7)wk>MRWywe`PT==I$Vi{1I zQ%pNYKUqL|x5iE?@E-Oon$=S#OX#_=`Up@y2StHV5;_ZI1gB3322U(Iw{)eMXx zEk(^1mX;p)h|0fBKEC)OlU4AFX*p9|WM^&H{3SyXuzYobvt+xS0Sm>}e@Pve^2wCfg(B9)z18XPPdCZtL?_NG*$LymKoojcfxXEOrAN%8r$Zi9{ zD76a`Z^48KROsKh-ejyOK_H|#lg-W zKm+OD>Z?kXer|6thR8=2aG_WaB8JWo5rO!f(}2gb1EL0}bUmYc+U3W6eb({M5t;IC zb0t575C=~I=1_-H2oJL&Iw9mB>HH$=XSijy2F>MDa)L9jGS{2}cd$(%tWsBV1EUG$ z&tfv2Ya>D`%_-D=o#^DovkID4 z5QaGMa3G_ZdZ6ttf6jWc>-PT^^TyQe`=46?8ry4U| zg_!;Ibr!!|wX{--@ZN#TFN4dS`#eC@K1rd~wME3bkiBl{%OdM3sT~&Lxx6VFukjv# zXz#}0IC*di3@>I9M5p&^H(8orsDCw42X1E0N1h{8G{2Ff9UQK+T zcU3;V3Kd8ITB3-$pw!|QY3TxGoE9@-s?992qP3`=C!Zv!^06?wd$pIZ!-*$$P~ zy#MH%X5QsL9IkQ^th>w*munTLz~8OyStA{u)=DBnWM?AfV2RvGzzOt;1!dnH(vQs- z;J>NCQi3UA5&^O$)OBR626tnw@`>Mn^5OLr6P>3*#tyRKeHP#F@}5N%oq?4QJ&R6k z7h!LOl5L@>5!ZP(Z4r{Qex_mDVAV#-nQd<=W!jpHD=|NQxYzXbiJAGB6VEjFE!k4$ z0(@O8wKe`^^^=(G)QX7ByqQ(5&wy(>f_F(bH8P-&I|kfYNq#`Dhgcs-i<0N4l`^r~ z<|pgd06j?ey;f;IUAw_x1T6%iH8Pv1%xLL5f|{=O zWPz)A*o{DJ;?BXt6WOmMCH7MM?e^kiOgm=DjRz0v4cyOPdB=u3mo;ehdUHL zuVZ$T1{0S|!Sd=KvH_jsli=B1lLp=-0YSm=^6zq)CQvd*!gw853Vtp=#AT#!aC(iG z>_I0)$j_z8-Q^r{;D+!-x(fx8esa#pbEMCxo{!t?^Fy6lqx9>7zuEK59o6Oih3~En zA3^diqH;}w%R|cb?<*z%mUum!wTvIXrKnfl8xA!fejV4|He2=0Sd zp0-Og+7)f(Dxy+m+419W$3CMvc?&jxLR{ZZ=zeP;?eH6`+(u9FoN=k-yKx`Ea|5bk zwHlnM3%$@s5;lr?Cuy^wdyi6-sl*E#Llr7EBR|1y-mq z#@QxU)gNDq4PB%c>!^CiVQdTO{Z?Qb%N93#7H3b2_}LBtugPL(k^}YwFvUoNRc|Vs z?CHj@EK(f8ZY5!v*9r!(GCZtk`hq)G{{D>1Fq06d`v8mKtX?t>d#sb%hvk|^tC%JN zKpffpP91swqmrd+GcSJ-i+>C{VCwzvtWR2`d^|;M0bFkKTc66VMlE0tpwSP#tcc!D zk2O-{7YUSAVmJd=|4B9kgRf5{=cIj)Kkr^t%RTn7R7H#g=_pEL0=l0v#tPx{exZhX z-Z0Lh)F-_B3^6|vyvBS<&%TGT8Z(-28>_V-L;qZE1lR{hr?0>fi=6d2{MaOtEH_6+ zuOl<1wt_)#nJ+@cp+-O!guTFT z%f+y_Z1oS}fWqZc|Q*Owm~+X7A4)FfUZW}fOKrsREXa6Isg}e*e^!q zG647Qv@Bk4fL@yqMLADNzbIaG?+jdYl97{k^zXGNc`n&k$qaSD^6Id)yjdy4?cO?YPuc1 z@=K3Niko{i(xb~?;Nr)OIOf=04|=$7kZIg)MVt&e zMt^$gx5s5fMz*e-hrZ5z7lMvX_~T}HpA;(lkOOPa3%)F+#|-t;k1eIMyw>5Ls# z*ET*R${DhbiNXZP0wX0v$1&nKP8is)<~?P5%rdK^M$-P&$0~$rQ$j#%`g$*dp5n}5 zpGwK}-z26HyhEosglAO>SERhmcW;4{d^!kE;rie8xT2s;2DoEs=1EW|=^t1u~fw<}@(hDn4Fl_F{$h>65{5=Cn{Y6!Y_Cr zILf~!?+U#JQx+}KO|_VD=1Mw!?Q#0;cCJS4Idk(fJ~ilaijpx{6nwb8a;#8`8Ks8s zV*Vv&THm$We`CLx7wqw;+59@~7uCF#T$jNJgFP#o%Gc>v-hhcuR8fzmNxX%~&QjgR z8Y;ov>#vv8{V?8HnNoiGa2F668snZ0vw>Jd?TrUzliZK6NjGx_jrjwCtD}!EftVi7&-UX3uFAGo9+%V_Cu+%dUdD9RygX6 zo)#ba)S)7k_r)N$-;G%EfB!rpDGBJa#moZR4!Ttc0OMxt>bsM>G9)1p^?azAijBx4 zAAi%&R2#_*=|^+0FF_vTnw1XcSA|^$XipBa?5+#)Qq>L@#AKw`_YOBpmzLOd5t|qs zL;qY{PO8RbzOPHt%Qw}v$6X#y44q=GS8vR}r3e6?o8b+fMv+k*93MMBJwBoWUc5L{ zhO?1kx(5d-2mt>6ez1BScxq(fhn}q82JjfQVhhYCBuL04?3hg-MESKkK=!r{6K4x% z1S_-5vZ$H)x|a1M;+wrI{1#5-WMzvxy$CvK{bL7dX*1oOx`+3Luz*q@-UnSWNJse) zKOtH{{`w_v@bhNT!hMrk^h}j)yuPg)m>5l0aRV3z_F(&#RT)k2aP- zmej(!4RkUdezF|7Yf15dA1T72-Kc7s-J{%vaHL-hI^|mc@d1E)KNT3?6YpL z*x@l!D}+!mNpH5S?e&D~Fi*Wq?abGOxIZF7rbn6Uq@hLjx0{EIX;#GJ6&pq|*vl%U zEbhyo(d@^+#y4>0%)W;0U&NBKTP(GOM^5wLA}sVRPOV@ zdEnxKGhfV@dBDBfhjX}jI0JM!x_9<3iJ=gWHk1DXB2 zRC=Us0nW{?wGj+5+l7vVW}S{+_h-;!+T=irkjf1Xtq=KmMrqMe(q&KGqfb^(SH%ac z;hOg^0T+}a#-CpeE~kUE)$C%tZcn}IsEO^PU0itToum<%4+y)&M(g)A%cz&EdYi}d9B$cXz$c>Wx zF%%X&-|>CEZ1^K2Zq@bgIEVoAqV zrFlQyBG_~Og6nV{N253w$j;6NUc&>R7T4HnfbFT6>uSIM=r$O2EcWA!JURl0Au=K& z8IceK5hohcacv{iMPuJY5`>Q9h&RN_IT0Zh_Fx}j2HtO1W#|O{#pv`3?glrt6I{>z!rV~1|%DaV?X`o^KJ$`z8q;{)E6!6&vDs3 zW9yyq*<~$`w4?hj(``s&MP;>yLMK;S`lPc(xtQ&hx?GU<=VJ(}0X6@Di+y$)SIB48 zxnQ%K-Y4wCk+~=QzlYy-%iyJFN%AwPWJ`NT@>@MdX39^2nSHC`M@q}opQFBgc6H_L z)K^Aq1p;q7{{AgcW-zG*!%DFRwv){O244FJ5Gi(e-!ZwQWWY-o*1lRVLU)3pUgV4J zGETww(Xz%5aDM5{PD))#tsd~_H-bK`{`i)<=%+uiIXj3|X8iOS<>$b$gZ-G#5vffP z^|wSgW?CcB9Ksz&k;Sm7A&fuQ@b5aksqslX)ugN~I_0#h$lOMcvW;GqiI? ztPBf?P?WQHw$;}~yqQ&*w*IG9K0d+nx^TFu0ynzU_OjO2mynNbK(GOS!WsNb^H!9= zF#DV9e7WC_h_J3&Zqh?#Fwg8bM+xObK0i+31tQ&LQf&ixuKB*_NcIj=B=tmS*K|;C z_MiX(*a@@v={@JN5F?)3;PTqUv7|EYsKfcJ9vwVd#XY)bBs_l!>idO_JX|xM-nPLN zYhNJ{WQ;pkuE)>X{yF30_ncNn4>H%C>poy6;vbDc3GIqjVm>c4Wvv6+ENh%q(~m70 zxA1&ZNGG_wuOllKwRiy|B;TM1-P!MdGZfh1*B4;6l)VuMM;sSmD1URFUOPW3J@PwC zO?xu407MI*iCVQCg{Bx&k0p~rr0@C%?U7@f|bdjP>{xlwa>86|KO)zaxK5yK^a^kZ`B)_wF$n`1~sU zpuj76)E`_pu959$#3OOK(#+f9zJx$%J7>SWZ7_DKn>zb&C9o>6zgr>egoO@4s5&a)kKjMMew>$(27!qC?nOt+1I~s=&=N&XP>ZAEn`N zrQBNex6Q9ow+AVo3fZjG@ZzTVfrFqeb5UhwSm^uJz)T$`HFNBi0*Hyyahem7V^B%M~HspHwAWPk`yl;ae3a*c;ZRV%2KZ z4k=hC`fXa!b+Cj9tyzbP)dQTejV~TsACwgd)$Qp*{dAO&4Cyf^5dCzLRQdCDKaEZ0 zubwgIS!NPc|NbEOGv`A+ClPNv<&;z?AyY`pwoAo@=Fk zeYwyKUym6(MTDL}JqBy>JO^2*atI4U# z>9xE$QQ=j^eC9_B6T;e+7*XcKmZ;q|zwP|=6U?M1`)Ka=0T-)#L=W)7JxP4-wOW3S zKFofk*M@_2u$lwWpEM`Q^~N|IgbKkb@qZ1N-LvaOQf_{UsohHkZ5cT5?EF3^JPwl( zw`#DDKx)i^Wh5@w*v_y4r9Qmlcj+JelhT>qABsP1+!o zW$&E!SmgXl@-Yt$TH?R|dT{%X$%O<`#|~^Vm4Vo{7xoc6Ta@@7D2V`8Ujxn9emaot zC*^tvYp&Dd;w4S2D~!D-7hHZ?ocYb7pKrUyB7)7f4X6?&*-Lf@SjnwTzqMTOHv6_; zhD^6pjnv^B-_+^=n9d1ZBzt#G09imAZxPAnnX1B9;I`)?cc-YN)iPMA)}%XSrlWc% z_MwG+xr0oE9cMM_Ih}EBjc?AH5McEluG4wQ4Y0yZ$8|2&_bS&%)0baI84(NeQOMXQ zggDmVe#barbqvh zQN@Fo@Xdh5z-Az&({Ls*NPihE^av2ztFpHrWbnxu)L5n)3q+ozmideytBpzYbU6I< zo*dl<4I?lBA!f`dos3{6hLdx=fdO;A8??!z5P@!Lp3TIr~iq4P0YX>#$# z7RJ9dSs%NUxxsuf!-V)8AdK5^0v|1&hda<}VZ3Ot{2!EC8AFipOPrtZ7CoF#pY}OD zE|J~WbslvI@cmyd-n8oPJLMT}tRA@IJqz>la9zsMd`gZ~(&oj;$m6d@m}*1+fe- z#VZvgZL?}Dde#_FSzZOp~Y|~%PRMy9^pJDwA<2ZnQ zQ!2)YFdJEmlbj6l=`jEL?)u9;h6A%fJ0Z9hbggkqAiG)yoy@F@+OG0gxjJ9A`h@?N5+T%c6&P@T_zJgbZ zVeJYFrMM4&2xQ76{&n_2wExasdY1ibkb5LHX3)rle~4w?Kr2=3E~Gn_xF#P1%w-B- zUL1obFuO(EukTYbpu;(b6TV7D*_U3p?;9d7g4b%M#5q@}qm+=<`J2>!buNoKEHlCJ@6z9$1?${qe1!tQ}*E(|?rR%?Gq zm@86cTB5u#mV?W6Xa7af3~ZX~)Rj!3WX0(`A^pp?$w$*?m9_Iz%V?D~2Zcm%tYH@! zu_7P{Kcrh0Q|>uuDmn$@UfT8_NmX$l{5IKCU1VoYu!}mJ8(6gn*p`#>buq~q#-)mV zWt=o&?K4=;aMPAS_IPqTo7Wx`E_DaudlUbYPc(zx_pRv%Ij%s05%3GVdjs;c6b1gI z!IoCS*M4xL`_=57zaq}9@WpXP`RU=kRA4K*^(CI9e1HrDQa*-lklxGb(wljo{}@sn z5Jylx-W-o-wM?=TNfl|l{&$djl-9P(;paLn!CL6dkGxuTfSMH*okB@fUEUDZuxH7V zk^yH0{-F&1HEk<`Z&uIqybD~BhuSOgn(y|+Xw>YGT1}rI9bkQrTTX};2f-qYM7*k` zMR*Gz@PG4^sZw)P6H(AO`1W!1MBVQ2w89y4Zy1 zS0;8MnCJmn2Ie2%K;hlIw`uOB(UpYz0e`-b-XGg>J+*W{zXFGpj?TFpgA#-%nR0!9kcaP?d) z6T7byI1ZO=UK=|Zokmpv*4D%h-|{uzvsT-0L$^NGXP7tGqj(r_JqvK-hvb|^lMbHW`Yg^vMtV&Pxu=Dtrr^)b&)}3lrR0@4|7L_^&sgDvizAv9Qbrxd zIUc!WK2M!a2D|EtT0+UP>wc1ZKKAf7FQ)3VSdw!>usi@Bk$y_;eYOSu9q3B)aZ*gl zB8+5`?`D+1bp^r1^kfIEL44X_cb2RGLTL=2;MZ;m8-tf%mg#jKC94Pyn!}C;r$! z5tT+8C~C|Gu0X%W0cEMwZ`It*RgdzpNdsX621iGg;*-~bw0@U~LK!?=!`7c;j7o4c zdo(!(RE;B#m(twB)Xv2rN-UP1gfJFvSEmRFuW-nB? z(E9Tu{v)DWj2~nYNiOeV$?8Ur^dO^&yj0>;z=lRBjt0+9FuSiZRXV)A@@_wQGeE>^^fD_|TY5{MjcBTf zB(TvIg4AH;B9Hu6ew`j}{6Ycf;Fof=>x6fYZ!}fsQU#kPITG}#gVrvJoct8M9&r@0 z12~zy$rv&)gg5FzjKYqPvR9so0V=7EgUqzUh;YM00*wlIuHA%!RM-h@FF_~exe(as z*v#svih1@7dDN%SiDGgoJld;!1Mk|^Sm3)qAXYw>0*;KZeXrd39+ys$WQA+ zL3{p1a@()ep=9t@$v{))2HmxOIpn6fC=Q_rdZc05N5 zGhj!4TZW|5mr~TtP1d{Jyu3W}edH%&7y*L;V+ArJ1?YmR#KT5ac!F!c&*-hZWq+y4 zgR-xDVMdeZE%N@J1hvDWHhRD)IHJ|_Ps8UcbhccWVfznGFB}a#OY*ivbGh3!jzk&p zpL?^z8YyVwbC_cXAJ3Z+FpiB>*;pNszoTEPs@&pC9$1NONcDhTH?6ko`Vv8jpe;s) zc#Hne%)K$Ftrmp88EO0ST()+=mdd_rGn&{rP39*s*&nS@(#4h%B} z{_Xz(wtqjc{?*2ow=I0;Y3X`yQHa4=q3?AG`7J6)PB7tXn-PpR%7s6{>Vb#tY5U*j z&=NpHk|)$`21|Xmd-H{D(HPNDxedBbWeR^C9?b>GUXK^rCVn%i*9e@P*x0~qi_vV| ze>?rR+yDPZ2hZ&f8vmiVDJ!npymA)T)I}IjFsK|+r=3lX9Qh8$Ht)CJ^!5FxReY!# zBzLVpn^5MI*#j+i?z{6YrDt9aXqI8d;NPgu>iC4-MJ}9>;c}ioaig{W8!lq2+CunN z@1J%fi1-!FM|eDR=U-kaK3iOGu{e{=C8TY_GCr>1Wx6sl?t9H#dW2$a@=}IJ_=pDj zuNL(G=UgacRKT5fNF~%8VKFqSrg3<(;Tk>5(;wk|SIJkVAMl^1YNX*{4d2YIqL=R` zvRAsdH@wsl?zv8Z&-lui6u0C@{GD*k40kDQr_zT{qPbpv<@N4egrqur5U!H7{ZFhF z{y+dia7B%TbQ^gmnB}{?SKMc&d_Mv$Ny+PNM&5;AAEwEO%xZJlI?Glgex zw}h}vW4M`K#&Va!b420eFjXe7Rl!#_VCl<@z>JWHh!C2Z_qN>vt?tpL(>gf9v#Acu z_Gm$)v;46lHoLK@g9z3c*nQb1jvZYYi+6>pW-5K4w`IG{@}VjUo7Hxa8y)5r{wFo> zQIQR}em5YrywnZgJlj6zdvfSs`S|ifo5sPkMf`(?!f`|qTX8@8CI6ErIn?BNdRuT= z_*#!%yJr)D?P|YQFPrIj-o=tjrvuy3vJ2ATWWU^R2@&o$2dgK!$qzH!@Yc84P zmNDn2tHjG*I^6xdw@X(EzVxVU`4z1H1T9wv2sC=-`pRcBWdmwrN9ddS&9<1Q-Surq zl|}CoTl+HpQkGaV;gFl7iDO13xY0whBBrhZq4@y6e!YI)f8hU`-|Xc7F~1+@PgUXE zKr|oDMBB}hzy}U>_SB6{o)d(SttrLJbxljoEXzXrx6cR_7HCfFHvVmZ_6E&972B{o zE(|U^M&-kfqA6Ke6)N#rlD(DoKZ6BEMGj!k(CG>kO|D}{YiE(k`t@6U7u&XpHnMKO zdY{gA!fc`DMe=YTGovkoc3H2d|93^R!%F5$Xt$UVh-86({tz_1%uV(|k`td<1O;>a#PTyz8UkL9lO< zz{2;_wSN29Ek!K`UfIO2pO>L__^EdpBPbhelE~sBhSwyQC;N|q>feCHe?~<6&s?h} zMCh3rb>F_rbhgusQ|kpnnU^)!>1={ie1eCBHb=9UNmv(KP#bkvql;tY@(;e(+bs2Q z=IYsZ$@Zj%HIlmi^7lnL7YJlWg;IJWWYwW`;i{Bs`B4*C8V_p({^)bR<&xtg5) za~BF=#saP1Ds$9X0JNp?Rq;N_{_Xt%Z;(%uga|Ki%>;Ebih^aOMz+2u!e*BmU1~6< zDp$D1LW8Za_#Rdv55Y`zA7Q}sjQe-c_~${`-%R0&ri!)e|LRcQOG=5a0%m}=0+TRx}W1Q^$9$}0G#HY>rVg)$jDeDqoSI;y}eI61CU&F?V4YB z3c1361!t|xI|)^!61~#t{JFq{YZr=Ld%9_Yr_78%N zC2|zx_+h)Lfe59rPayT9s0j7<1=O`MTx~g0+zTXQ1a8wRf3vj2_EHvbJykgdEN7iE z1brD?n#LgoS-x1vbY>8}R;`~Myh_~5i=VqfmSRzZe)Kv}Hq^4ffKArUibPRc=( znq8AVQ|$h3M?TL`kLo&tos|@zY)>DDC7N+-lEjWvIpS610?5OLYQ8uOb6~C8Z2c(D z<`V9FH9wOEY!?;P*s52`@Eo2v{(2AS9W7E1}|}j^%1jLh9R3i12&O z!ED*A&!Gob!U2ezq}Y#O2#|>R5Q9Y#Nc%K-P}^ix{`z!Ue08XHQ+#+R=Q^qDVte^m zcGh;+R`l^qU@zUXJdptuE+Rxl!G3sS=>Z#WH!q;7DwkJRs`p)#dTW$_B)QEDr4=In2kU;FL7+Srk+fr%0!kC z0+s1FoAOQF(D&1aktaaDqKXVeAhR(f9doe+YU`O`$E7uk=>_`oFW89+kTJVX*$VK_ zc{?CKm^07Cdm1v|h2_X{nK8JNl^4{t2bq_bR@N!OQ zuepA7YduXw^?*AGOi?thQtB-T$TiZX@~3K`^jXXbhU=jaRg!NnNC)y$C;5eij6a;e zo0!m`nNrNHtz{6Ck>xGP+ja-Pad)cbI2vxcG#9xuhSLd*JUeQ~a!flFE{(}eZSz<+bfA6{Gh49%izU@yZ+b;ZWNmVKSJ zPK;Q(2hQucpf}lZpST>GrHU?uH=%5%R`V$)*~`xog)IsL0Yp_kRL-)4lT}j8#Lr6I z?3dlNBc(Ec^aF5iii>ma?|?aXs3!}|L>QpG5xd>#rL2sXUfM*<=ler}3Sl7La2{or zG9O9HB%bAz5P{7|7Xlf}w-WqK#YiE=i=B@ngvx@)&vYdatPE#M^Z{g~ZzY|YBUmaPf+BOlqB^#I*w zwVHqVrzHy8k&fiAvk9L`-?LDP#DL2>zF$XLuMvI3v1{1HB$)R^-(vs$X{hido!V17 z<{>0|*)j>(>s_01zAd5f{9y}G7I*du0Lq=npn{>H0295?)}G5h2Fz@jg~rUNkn2ui z>TE(Mc$_BG3~a4$3h+2U34>rNz`_inttFJo;zN)IU4obXMre4m9@Fv`u=DN{qtk@BOw>M{K zpHs6p8n1Re>U@9tj+It3^z&0gs&u?wg;JIyFR-GBLrc{7J)1 zn!4fObSdv&wHE|Ug2f#FawRbVk4E+JJ&gL_WtqDQ9Su2Q`;x_MXT?su9Xt6P4zl9zYUm4xz?KQ{JBZ(cpZ~BM4<}5BAd(0$)u%a2@W=9*mHu^- z^4&PkyRH`T!Dd%9GykWS&|`E1NUpPs&E#$JPL(dYj^90J-7APMvgHtJ64Po-6z`! z!6Yxm?-63_1GirtKxHFd?38L^;SWiNF-BBtq(8Iv{ zqNRs7EWP+6f-QD19Jq8&vZO|T1wwfP+t;`PGKs_Vp}@wi_+3U-1#431|iSB=6ypOk{F z0>>|mihagW@NX{HemY$-K;a$78tM$ zpqnTF{FWf|o%|U&wqwjQe93b*J9IquQaL)hWlHvx5Wbg7jLgpp(Lpf|w;UX*4F@3C{ z^%uUbEFD(jJWhzqt9WVY2nCc{0a>#2d4zzC^*zw46q^Fjh}yB*)|&MK_aq+stw-+O zl(^|dN;_-#mv}~LpJ{MW!OAif%=-*=)r!QzlaSDE`-SWXVq9SdIT^~V8^#^cnklbIKSK?6HS zgIxt5h(bCDwPGM=E@PXp+tRdrBaw2X>g#7s<&pQGf7084ER#!uFCJA4Xqff=Ly`lS zwtU&+w3)(oY}7#(pQrV9!Z(cKqy9UTlha1V6;{HLij+p*9Y;QQvW@n|cIJU^vGl;7 zEiveuH8G1K{NY=_{E*0l4zXCF<@ZI*$0VJO31MBgbp=)dJs+{#V?EGoh%OohX(~~~kOB)y!SIF;^7xr%Q$WS4#gLG9-U7`6HtDS3-yCcw zyae`&S8wthz0%mC)p&70@B3S$JrB39>3>1!jv&h~>s^-SORI=Lro;n5{*eelw*`9e*Z>6qpS!_duv14-UY-RU)D z_|AH9*{5hFato?ls;N88a)g{>N}3Df#K}mC7Q4|xn-s6A_Q}Yn7-tC&hagI1zQvk< z8{*;{FMsI$nzU7q-F>#nsB!m%?Ou(FcpQ}+5jbYN($ys88AwhfPl*!}Ewq_2mM=~~ z(t~Xiaiv*Z+=C!B%J>66!7QII-*FjEW#=Bpx3Z>LGXyetvH6+j#<67|s@yW@m!H>r zxmKVCy%5HDgqE+N{e&xiML`pzfKp07@^f}{0?GK9<6qd9U{1v$iC;d_B?a`k>}u#t zLVM#j4&so~9xWG%Y)#mMtSQP-X3kep2G;R3nY8PXd)~PkM20*arw@%8)gv>##+Lzb z5Y}xlI@e8l$gHL>esWKf~?mLGO`B_~( z75=vCL~`ik*!tAvS0hB2J~$l*3UuqlB%2$YkV|=NLwkaZ$-NCzInXXP$6>w&6^Q;e z@^!_WxCzmQ+#kDw-tJytP$~P?M~${(;H)gi9?x`phqBW1s8I)ziTl%uvL_RiS@IVX zf}5z?YitXCcX=T;`N zy;!m;ymdd>(;8;|(o6EV+ay&>#y?LJ65X*H+p>V6?@Qd^2KuotIRAgR0J`2$JX~r2 z;15Fu#2?aEFn{BfoGrka7SAmI_Tbb2g>K#|uS#B4-L`M9BtxOUoi;)=C>0jISrYkv z%IrFDQH4d1Wx{ga$>O1qK?ls|!k=5q*TuaxIC_!BV2#I@a;~HIvq>3Q+wCN=4ws*9 z4P!9nMoszfw%d9|Io?FjvOJ^Hv$6i7Ozm=y>k8JV{KfEgJU~+zs0}0`L+dxZ(QnSY7oe6SzTK5+s?a=f9Ii|OM=T$1OHgu@ zN-i9e>2v%|IV=O$`p7r*`AS$XVu&95QA5k|oyK{W~j^&$7(7QS21$JerHIp*t>0%L$4@h~TnR0an zzYN$7Z>83$w01<>J-Ey~dK7uB`@PvcZ6+tVi=73x44i+v?ntP)Z-!kpqCA&15Uz>~ zT$wr9t&#+|^EziA_4*LPC4VaKOrF@T&?2V0mr&pr7VW5Mq+%C^0U(dgUUtt_$z^F* zn)pgoQN@N}p}vln&w6#8_gVCq5Tkp0rK^jE=S(?9%xD08x#1||^&nywAN=~eb*=Ex zssGFlN_>+1+XwYpu}xn~m=+<@IYik5%Q2`aOjefAF0@y9*^?YabM=siiRkh;=ES>^h7oo@zB#yp^hQHr(A%ul?>b zc0oGgKx@QS^v0{9!zVK21Y|K?5YmY`XV5}W| zkMGkQ)QZ4+Jo-yHNp-E`FjFv6Z#$DpVa)Ma0$(=LItuBTc=i6P)67gc;gn1$IIM!H zzK{EpXsw6(XzOm3E5dK#4bFP`^yOs|E`8`CI2DF*%tH^@hYT^z)@evy2oC4y^|bqp z6aTgMLFRE|6Tfw$XN!7Qn-`kOZ`5n(be4{yZ))JlVZoz90Cl zMup6@n%`-T^nWq-mQhiDU)V66(k)0MNJ>i%Atfm&AxNimNC?c(-QA<4N=xT}bPGtw z(1S_9( zD9RB24v0^sRp57B=^3R4gi{8rtXN2vN5iIqNz5F7?2#BD65-c=C|9iq7v4WT-%TF{ zwBiiZS6;``llVJ!$SN|=YaLP5y#ZB*sdEfm@ehUXys8EtLy%+H;~>;!%ifMbk|+uZ zcjhg6dXcn~Nqc62yo-u+<<@@y1QzjKS0Cew4x@Bq)ZI|q!-;I?P{IK@+Fzv@hU`8i>aF*bE+ipJ?=x)Ej zYg9TR1d$2$qk=w6>aJF4LvPnWECx?;6-7+{j&9e2uAXWl$Hp8?&3A8m;r$tig%B9l z(XWorT^V9W43kTuT~_>6mklxwTRA>F;W$2+dD^c+3D!P%tojb!XmjeXd>t&;)-|cr zEJJp~Cs^{1SA5@o7kq}wzp;2bM`EPrBEHKvLXjI z)wNo5QFt1>&Trb?`n`$&4=goXuk3LB{64=E>5hnPJArh&x*_HT>Q28GML_%$HHLZXkEt)8x<^?#`Cw;;0OYd8LB9UqW;U90V-Hv{X=@7jLWC7-!( zQ^4BpsW_l@H=gUEBlneI{%7am0Bcu=ZimevO+;?ip@@Lu9pU$MiS2>fj;-A&HR;08 zl{sh4jD%Xy_N@KYYqf-hfrRhLHZwv-2rF{C{Db?J-Zgx0Po>S2LUOG`P@t7q$kk)& zP%oUnuaofGSlW?yyYz2HLGbp|Ja^EcTIP3Gc<6AMrXWyrpc?@DR-1#mZ8;qJJ^OCT zW1;XS_W}mE-1N)yo|K!IpFKO@p_SO)z z49jSlEn@=cis=n>9CDp}*%AvK2+Xo$yr%NbJw$vuA-&i{KzFw6X9k{x|@* zg}n#g2Md?GmD4s3C71}4)%fT5aj-om%uOdwKT8fhMGd|WfZZ0!0>g`T0pW!$EhHZ6 z=n5j#TU?A5-TZSS11uh{7xHNMvQ2LCUwPH&2mG2F-8})AZEKVIt^m&-z;#Q`sPkZ7 zDT|h*19x*2cEjfM&_unnQT{@97j}~L2New%I%Cq?=q>%&m0H=mrAoS9sWEO_?L616 zy@aLR9#ud-L`6k$Ri0CGplhW#%tA{)^Z|(>5y6FhFlykDEAg-gA^?C=br%? z=)X8ikVoLm_&5tc2mvZ z{P*{GTvA_N44;}y-$Gb!OTRz@t2dV%{Bk&wjQ>gkVB_fsF{+GQ%Ay-tcfrgZE+oSq z_j3>2<_lPvb^!kmLtD{9x=VjzHN>rh#Z|rq>MDOi*A1QtkJl6wa}QoQ9B=6st(Vec zWbIo>yTtQ~iosd{0j}9HM#j zI3gaCKTY58%L;?V5z%nCXTw~L(a1Y*BA*ZtW)+{&4`>rd-SU zp&g&fpW)A7zrqbe)aQGasQejCi;F$sDy5_QyD@urTP;y^c$B@YV7I50|mZ9~DAu+os>KfHu{jPy< zuImr`lrcmsWHV>rVS-;;301m#vNNC%4s^|R_kR{On1I$N*8~jR-@@(Q#xM*y!`Y)_?1UR6`F*& z*;{2;-Ct*OjvoRV0(p|5p46u#x{9p!h~N*7k8mDqB!NR|hFbfD-dj(~55a-~^k9+f z>C(Vop*X4E;%RSkvb&FP@n!C>L1f`J@G7Vx~5)=>Ud^2?JF zidZB(+YDi^c~nM1*U5Sg8hcwy>O+$juNi1Ek+_QrT)43k`}Abbyo}8>Uh~zMR3cL{ z_mI=-Ybp6AC^;8udt-^ndCQCc@L8xKGK~ULm+DNC!g}q+*rKLU1Ml8UL3Y>06Ppvb z!U8oAZqeFi&EILMm7ptJ<9NEd4x!Ktqqw1!I{vS~&7Zhj>8ZI6w?FsYzxw3njk&j; zd+V{5+f$eA#p{$?z20wj@P1~FRPFdux;tYr1^X;d~>8Lvg|gIw=-$FkqZ)xO)UK<-NS*%VuCM{!S} zzg7oYzLE?YWD3~X1R@nES9>nj17*YUvrUocG;1$#b$ooh_s7OCcT6a-<+$iafu>BY zS^YTT&d6_3$%a%Gm6n&4-B7 z<#(ZdDfzjuPNaF$DQl9;=P`P=wqePpu)zEd?zAgcb#`A;1}^cUc66x9gG(fVk!RTz z{oApZXCAV0Vj1dJH)K0^cTuTH``0IHSqH~Y#@$w$`RM+}@AWnUbMKN{3!9iq7RVsh$Pin>M@U-Q|4akYJ^U2+|P59S@ug<|h(6ZY}^ z?0QKqoEK1)AVH&@r6%Xv_pe|HBB)>p1trLI@jgORLg?8_?9KHGGDiHKuj5hM!}B#L zz%ea0!^tf+x6OMf=~MeL*gq&c{;{Ly`cll|6NZy&+RoieK8rr_OV-;uvraa^Qn~UWT{Omp5Id|9UdY%nd1|!> zq1n}OP%q&1XAqNO0#iLQ61uqh%HUP;i7`&WhV>VoUuOwz780podra_NWn_W=*B=8z zh0m{d{l(MFF?mgo(tu7kNJwxcXXPOHPHVc|V%>wiAH1KWcDsg@;ysFD-I}^X*J^{z zZYv|@+)DESiC$Y%B7&U4(?I|ANV-BhvT_F-Jt?3EK%5Ija|Zn6K6xZq^|$Y7{9eSw z_o6zsgNlmePFdc9ngR4k#^WnR&*__C05=Nhq)8i48{uZ=z%13Vx6Ab5g~RsM+oY*M zUF}m73J-EUsgn@lj~Zy;(OAAq(%F}U+EKZ;0^|pHPjJy~svFiYMG>V6+k4%Lsqx2! zFn62iL_r@tQ$W*7$gq6cOi@fx+eCqGK0Q|_x4W;?d!AY%BCUb7BsXEVfxV1u8@3l6 z;PKr3CvOWXUORq%U5G}8I(6jLgA>}-6wv(-D(1<4W;p0P_tQY8TpdB0)CSK>3Ht!i zrx>%~7i603kh)}-vBgfYQV~7Q$D&t+SKVmdNiv2Slo{`Q-~Bh~(59bM!E@FthFO_M ze1HoW@z^=@`~;hfM4x*$zRs7l&tHK5P<05nTHfU0KU69x>+ZTTnGoOM=kV{KgYCbqNnG%gpE^6{)@M+ zF{4wcg_}WVeSK7sUw1htOU4(}EeLpiALU9lk^vuG07j75n!C_m`{0YS7z_r!3q0cW zMg~;mqV8t2eQm1wpqJS;%fawUfXK+34_a-edSegm#}3}oe{Ou)eJ_rCBJR~%w)}`M zK;u?L_k}B2(uyp;N8QAb1@ENkk?sb#jNVum8g0TYTbkXg0m#};N*$JJK+gn^JkN$p z@+XLeq)ST4MmMuNZ<$;~nyX69L^w(`W+SwxTOaL*MsXJfO(OnEg6d8m9XPLC%lQh< zT-e2zer2;Zk{H9TWTN9Nmy|zqzqnk7vK4^D^u8H zt|E{j&5dH>NeoYOr?GC2HEle`(acLbz5>9>$I{z_iWVEj8=1^i&LCxz2<2pLY68YylfAIS9ZJ_E%F;A+-o#g zxU(a4`F)jHiyEF1oyHCyakhN%jaEngfS!-V)HHA6t^4^p{!Ed`^>2guyoO0x#kg12 zqY3$-TSo7Zf&HwEg)}E;R|&xFbhSOVgm}l_iQ4DY!yTauZtl+F=+1C#%{pJF{1r*~ zYJYsMzp!7siFp&j7wKl|Ogvhjpvi{VJh|HYI;VEq4<6Vr z42)}g0G*~krP*e5L$opA_5xQ-ElldQ0|sEzlF6?^!%&yANumw~C(ooZmvJdRtxxsz zq|^r0)wV#IF72e_=yqvpyIS>InhS(F{eyltws^zl?np1^~^8KO{}k{2bwXJ5ETONMFgsf-CFnQ05_8o4f?{o>CMoFx|!uthCxF=Cg^H9 z+IHlAdawOjpVyy}oHA+KdhY#irXn|HasM}dA`I92=%DK!f5NZ(hFBD|&eY(wYZZl8 zc%gtj-uxsGVV%SS4%(UqBHw14?^NV2hWM>mY0_D3*C(Z2TqN8lRHaX2w-nsmZ_yRm zt;3tgMs;gfI??^z{q$ecbBr?p(R?4bukCmj>qCW2WUA<6p9v4rFYSF_ArEVEd-d9A zhUsJ^2GTqJdG)NK)%4E*`x|EWj(~Pd&o>G`=UqF{809C%A73a#Pn$=2Qt#s}x|fQ6 zW{=onN7gddd>Sh&r!gHCz3fXoK;Na+W_n!FMQ1g<8VHT@96{OS7uD~(LhDzy`n-kO zH+*0vEYJ^Q0c3AJ?Ci4A!RKmGmd$P}Z^J@=YXl9wC(Dao0GKx=Hdbf12E7qTd<#-d zFA}NC(G2{chx0)}VYihqgAo8{uoJo&C19vGgdCOauZX~5VZ^%8{3~JG4Bkh=e5|KK z?@nqVn-$GcXgGj3#oZ{>l0nUz!Q6KwK%(Zd!fdi0?6vd&fOIoPbk1@kGbV0U@6|Q3 zcL$l0j%FTyq^*$Y?tMg~-*gP!4fH_2d+^!1%q%yGsXi-EYWs4#y4Z$s{&xTC+?cbA ziN(Z!<0OL-P+}{z&8iA=)plsTH}b?7&YdawaNfE3Qi(8GHedLmkC{RWKK%4Bp8w+& zy*B}D%;MooaARd{P+354WSM;CShhejPBUUjZp)%S@d^bW$lsVxZII8|6(W?fh_Wf4Qv1S>yBMx|c5Yw?V5Y>Tcm768f;4-8KAcj+>azhf^fW=VY~Ms(E)T^~)54 z1i-~9S-=KTnQZ2UM5s(Pz|WC&a_>uQBWydbuk=AePfspxR9lKf7sPU(@?SmMOis4( ze`50P)2VXDYpq3xbv#a8<7wNy7m(Ldy4!<_3cLPSQ+XUsEup`?IB(WYTUWuFTzIiQ z?Y|>cJ~;~{{C)-W_y27M>eF?({+MmyvNv_Zf2J=ayk_>pgueiDK`*slU(%faW&SZ| zFbbRTVb<99M5@A=QfEMUxeilJ1A^2(MeamcWVG>WUjljC9?*tt)@`(>=K}6Q0c*({ z-#0}Fn}7L)n&cBKx{yPL7((xV{32@MmIOGjwACn3 z1B1@RB!|YUTcFNl2MG_)W5^vCDG!Bg(yAkj-rr$~)^?1!b11$2OU9`~6C@rTrHVi< zvDDU+&$H?*+TH2ixQl^09lB5=_r1wLV#tz?HxxTLw*z%s*A*FW;nSQ5zep$NJ<=cB z-}dG=>FhBSw_@9&y={GE8O#_3NzbuF^n@qpHcUxRSDDpQ=QOLQx5r0sHcUZNSc z8Pk0`HsARnC|=9l4MP9KMN()Q^Pj7&gCB=n_D#C~K2@V42}ci8M_I1!)QTeb#vgn) zLtlxAMoFn<*tvBL*V04_)fZL>QwBa!wSIQGidK!&GMHDBaQ6zzxLCozNua3rXw1%+ zvyDxJNERK$!62voLB$0+BdwOgQYrV41wv`vWhO_nshWIrt8=*`{Ba)*bzqJStWnIa zQ%aCY?`(f9qiDcM2Qn1-`J{8P`^n~s>_5TBWmPaRo)(>FH|r~NP)XljsFsi&BsS`5 z^P$OS&IWyfs zPKg>+K`;E>siJ=H=C#a8L-dM1|BZXcU;Pe+@PzRn6I?=4Q;(TT1`7DnCAsGmv~+nZs`YqsVoOf*>&KZB7G&$XN56G% zm|LfNoLlXTuG|3cki%p}tmJpP&(k6k;ryBS&|=x!!Hn<*Z^!jLMFUQl)D9(NL#FNvwX_~KCik*%T6@}f9`bRbWKtO&PR2jLDR+ggx$wefOSU9oF=jo z$r^%jN*we>9pmM$41BGV`2&!S|2l0;!qxw$PWx?Mij$Ib)TJQ72MxxCpe2!pPsbFS z97eT|s^#tN{7(>*!&_z5sq@$Kjtd1f>SDC6KOx4N&YEcV47b6rwxX)XdDTIrG`0Z* z7t0Ds9M`)qW^Ug#e(4%LH@UcXEL}M|Wf>%J8fR9V>T+;rSry^Pxm>X`BIX!5{j*`z zF4kYq`jVM%2zM^Cxxg%Gu+%Dn*~lw0&#boLon5h(tcs1O9)@oM3K0Z-K zyCM<(?IwpA&^1{Fo2}{?G&4wZ$i)$lB&5WrzZoaV_YwS1v|1$WCrd>4c{{F>zV0yC zm?maaQ8Z4smnr1yc4bgV_WUeOXuHY=A^ClwUe&%|)VQZw2D1E`EcDj>$}DtJ=F1=2 zw=I@`!nI}4KzqfLEvJqi|H_lrz*>drYW0)0;$J>^H5apHR;2wt<~MrR)m{j_VwRxe za1EpiwiUnH+53sGnGP1sT5ft=FBi})McE(MNQ3L`_kzjI= z0@0fC5+_%uvOgCf@c4mHHhpeX{_DOww6pCAq=d%!r}sed*QGd;+oEN{c!2p9lT#pp zU;y@c0ZJx(Zn+>(cJDLw-fOKfZ3+7d_R*J7nn1(iFJ3{0K$lOm4LF#Y+oCt&d8BGS zH)R{;QokiCEvPSqXSRlE)Q)DUi&C7r)oHDOJxDL)EzUz1@g_lebyoiSl(m~F#d zMn2vo?ZK=4i99q_yJ4?nhOw{=-E4x}SXM)gk!y5e`9*EIGAe!&WHQk;CQ;(Z%{108 zG#xQTo(cPhQyK#M;6)d=K(xsnMnRI7d-iletjgxM`2T3;Z&X>sM&=PD!jBSn5`$w| z1&FRTiA(HheCO>q{(k4~%}kmHeJNY?|6LGR(2ivi^8I0Rg9~NyB%TVQ#6DJ8_?GS? z@6h3v&F|=(-v9k19f2JSbG%*8rV3tnQvr)=FoS7}53v92E3M#*Z%eD^>NBh16rmD4 zIK@n7Ozk|f7{uj_lY{zSgpbU>D^fU$;ka${FqFMyvotS~I`vQPOuyxRKI40%I+X?z zta{k>wr|Z#<{_RLa*6X^L{i6d?9`9OhX4F6he>N)_b~fG2(v5Mulj>mN2l9gw`A$-ljEiGu zoUqnQtdUa_Ok9SlJcc>nc5I$TL&}10wS`+D4WD}X^CxyhbG6W#p56LvY?Z!JWiPQp z-HN)a`uCq*T_k;!e5xL5T-=PMCRG@lPtf4*^-3{UoPr(tXJ=cBW_oot?tdG3djS^$ zZMF(UzH;j3N6@LV3E1t{ui(3wix>mM$v*OY(g-VXSuyaz-l96cUBf061?ep65%wIt zJZ$#Z=XmD5_imDyC!qxvl`7A|fr}nBsw!Iw_^y}nF@c1vc^wCIt$;@K5O66bzJ!DI zn}mLF_rv|2oV99!KWVZIv(EU3MaL`rrTx3TmtQy&5-g(|G;sL2jlIlCgJIG=IlBXk zYHL}sRoBb@BJW2>ZJhdA-F9y0*U*Et^N+IzkD1V0hdgYSb*SRdnZ_1g!AckYxOS`) zhvGVju+{0NtVdFm>{)szqe1&f)rC_itK*pi(3V{B7HN7qp);qJVw^A zubdNWjA`~^pr*r(T0HC~-F3p!(r|K8QVXtodEOum6r zdd9whc`atEu$^}C$IXB7;v?6PgH8&L?7PTOJ`k8Q83ScrHjg>CEhsl5e^%c}2@*zD z?EVGN6~;X*Z!B~I8zfUbCpKR1CtpN>s+gwosXx6%hY`eXq2ap1`Y$I*OHI~3^1CUlsny{se->d;!xzBz zKsom7jQ%2-?iCRZw43u6p-p%F`=3Ik7I#_BbMMFTFIln}BK&(lw-BKLrR$#dHfBwl z!MvY~e4mlSi8sIRj40^iF*JZU@~D%7?9`W@eS$X$UsBE9r-8_Uw}=YwoQ-_g)BEyc zTj*=!lkIb~kvd)Shl5_EKhXAt)!z7F-9*(c%OI$~jR2{rx`J&BAf`$lz9=pOxX;uf zEA&_>ekLcqNy5fSQWr*3zde3I;?N{an{wqO-37@pZWQa^M!eLLERVN48kZ(IUo3R) zOa`-~T2G&sGvx0oMz9Q+Z^Yw&W2za;3I6Ts-|Hk`Pp%m#fBi_}Db|QofHu`WGAkky z#=eL9LW~E^MeI?z4bF(Jxvtwh-E&GvI9|*aC*Gj-yWG6m{kttM8VkTv7C5hf050Zt zxhbEuUq&cRW9^nI2xfIWsDC=0><+pKlQJCj7ywVVj;OE&J+Ebrpuk|XJZ-6wW4*OX z1NA!@qd3rU5l29HhUyn71xJyuII~AR6<6cmCS`AZY5Uh|p+~~hW9J8m>)Rd35qr=` z21_wc%2!yK0#tX96Oo{C_f7Go!k=SJET@#!89&@*;~&Y=lf)a&F%O@U@1AyZiaJ;h zQ2tZW=*eLD>dUGQ{*^l`!!!ajabJ^?C9@w3oIm4xc=YJeu5vI{-xqhNf_%5_@5Yaf zJF|NP%N$Y(OzF3jR1Cp2|@Jz0NkWxPBT#$u2fPmg#T11FEU48 z%KX&gRj|B@W!yjTyn0cBK}ueQr8mdzdzZG^g-}0OYn>>#Un{*;^eNndDGcC5&^IrC zFr+zftz4Y^DeZyZT;BHw{ftwFfs>x$BXaahKu-|Z6)wQ)rC!!oLn0`tb_99iU%rPU zrTDEF_1|JE-Z%rH-TvKO&du@|@vod~TqH_^9{HKfSQL${_Y4uA?j2TQy>sSD*OUEG4k~$$wzBA%_ z9t_U&DjS~UE`0>o!BC(IHLjqj;?JpUExb~&Ewr70ZOZ5Tc=zTr;eRqJw94VpUTo?P zH{}6;HPUQ1+7R{98YIso*nS_8n4c6|6?IjX^VE8!Xvy_3OTd&lj;t7(8sX&TG|8=& z-bRq6{rBka_>Ktm6!jJ>Vx5{e33E|I9f)iwWg${{ofOSFl!)dWb3Ro5C;y=c{g$;o zP!w)}p2>jlaaz8by;DLePWBEEmoq2d!nAx(y0~P2=>8Ovzf(e%6}mdhV4kbFybpZd zn{X_esvcp8q#o6{wP`KlLM{@#h-w1q)o@_o=>I2qqs0mi#%@bZonAfjDB!>dc=td> zI7Q;<=tv!v!G6Fp1+_?VPW0Wozb4I-I>wVnl`s`feEjGe`R5+2?ND#ywK#fi%qPJV z(I{A;#==s5-2R#MZk1-d2FG^yg(@MtRpxeB{r_ZZ1X#0dL;2d#nG*u#Dz=SgHJs)S z^KYw#oD#GM;eNbpI-C>685j~D$8xhiHM5~woF6!Jwm%2z5ebo{1@mHPvm&)U$l?^) zdfL6wbOp7OP&ZG(zyDUwf7-E>+vKG322LdFy~)%9h#aR&{Vp7X@ZGjWR&<~nOpvcc z#x(KZ@5!j2-^YD}*f;bg7;V2}Br7mV>fmPiYj5d`0c+PDS7x((T>f=j@*?#q7YgIQl2eQn3vJU1;5tW>LIxu&l5dmi?@sso zzZbJ_w88z+yz~o$lhaeSR)*;hqKlF_$y2cn!=vYK==QGIU*^{%L3xA0{B+>Cw1zJCJXUMjJoVa{|Sio2@D?&R*kG8kYJHn}P;HV+!_m0;o zfuuNyBH&+gK`S%mu+Exw-#_e;LDrgX1N%V^pKBq97gV-aLijFIdva|_d!(9|`yVG8 z=H%AomZmqSpBo}aBwHl+MW5uFang?1us<(-o@F_?WkK)7gi^RG`9&ZrMe4`GH^jj^ zH0C+~Pl_idh&3xP6mAA2?T3QFzv(Y5uFr9uNICCQ`!}t1 z{_ct^oOo+_Gw4wwc`hW5vvOU0UKDC|HMW(&9C#M~H6CaY9eYSuvqa}X+zrIT(vn^? z(0&s(Mc91_yNQ9kr%mcc*4>E`oY&f4(PguoQ|$(rO1O;pwfOAc_#L&p>iN_8ns#3S zp{z&Xb&%?l(}A+aWgW*N*wfybW1Sups0oOdYp^FPt0 zqdyL578CccOf%rqzo%2(SR()e=|`6~Pmw?5V&yGZy<)HwW`u|^Y|ifaM?m!W)v8v; z3B{4J0?17tX@LL;>DrIr7wb?zH)o>-3meOg%s-m{wk{8vq~3FA0qZVnytYxZaQXAL z@OE~sqTm+acNG-@Ue8<2J2hW^@;7IJ;_ty9;apBt4C#E>($gcv z3KL;I>F`b6L-vGqIc=#3%I=mf5cj3>>r%`9*HVIiK2)I}lo->4CNdku);Hn2{rl@R z#^TH6_Ie&n^qIuPf?lgF`N8M7uUQ|g67Ux3@L(ghX>XfJ<1ki466LV!GG+Y;>jJ3a znwpvB%Q-On|5MtITjTUAi7_ASbId4pt6$foxv#K(mVQok-Gz~PkiL@H_RJU)%vGT^4LFxI6Re7z3 zeFdSD{pU^c973q;bx zq@hym9%8;ciYSv$RbRB`!E%IBURZZxM@NBIAuTt?=Hw;#n_SUCU99t~*PfkiviOE= zRR6@3X!Wlmfd|&2I1BP9(C=h5oAT!rmuy>4ZtE?*sH5ch)_3{te6pg=o)|z&7@;|> zTi-Dwf+D0z&KagG6Rq^(qEJ&>`3=^%l9?>tg)TSC_|I3QN=a(H_ckfp89Oi1w9#;6}Q=Z)$8pzHw&#Xjg*4pXD8HofTOWu*cA`Ekqzs2$93X z!&AR_KnxGZfQ5K4-Vo_QDPENw{Rue+k75Yrjre;?7ZQm}w$Qu8gx}fs$sSJEaHZvr4AQ>|)XnY0th!HgHv zwSGJp6C_<22?k<$MIVU$B|+TGdhBkhzE^2sE>ix1o}`aS5Sjgr=>}s4T>!E_ zr$Sd7^4A9RQx{WQg~3>|*Owb<7+fJFWh}7|KN1-wqipJP1crzJ5+}#UB$DFdOP9ZX z=^2koQL;L<{$%2F< z!{+}wJV6ud-`$$*Qv&w}W~MIvOTn(TCR6%G;N=*=6y3#CV}x@}*Pv$2)oz=xocX71 z^I^|cyxbBGSG2l2_un!392*^?If8tU1L>l1VKH}HvG`tC#fWu8DlQ~LLuD?oTyF4eurO*g)J&|AKIo1rUmcWRhajOMnH>f ztQ|Xu1#gbh`PjUbXvX47p_(nrA|^`}wDEu`VoszP)!n=KWy^b&BCp@&H#uQU(bX?^ z{V}-`(Ru9m~itigN;~e#b+kLcTT#1zfYtScrr(*|_v)5K; z3+5{0z%|!6cb72rq2bN?@Cv=F{$gU*|IP+z%F2tVekUOr(461Q_Kw&Q6?$p$x7D_y z<8`+2t%=Z1xB6XIL#Y}613!&3V0Je>(8O?LF8ZS)THM;yDJE~vI#esJy8D7+_Frxm zr9gL(+aTU_uY1o95>AvGHn*zmm1y8d;k|_~$}Ps~X^$}3r8+J>&%nrXNGKtoSEG1d76EXMI1<`(TFk6!T&JZ) z?mRTReJlSj0+ z(rSOj&_#RbpvvcrMPkwp7j{QcLBkC2c3SX!M~&P#nw%!C30TQY2WDy0oI6-N%B04a z|Hi~k^p7-V+03RVnBH|?3y=b;4?}_&c)MgrEtp&Y-IP5V-9<9wD;*`6;~gAWeNU`B72Hs<&MK}VWh_JqD7jftC!?4FFQ4wsicNnSAPGNwXX^JJ!D;W zcqS>?lI*myynK-T(dX!5_NWA{lIEQHQKp%lmC-8+;hd776zn+q5%+P%zVmi3-<=eJ z91Rk@2{QSuINDklUdlj5=1uL_WFaQ~PI@a}>yvjU0#DtaShkhRe7SI6yxA8)>EdkW z<-QFTzBfHuX#rV7qt_ZxxmSef&f^tc&O5NY@w2l@<|)TMLzO=5gAXoM-fLpH4m^?@ zZ$#GXTm`(*rsyQm83>pv?=y_5N)cc*Jk)90`9Fjx;K7q*q+8LEz>nu!ztt$7-%{YpkH%-q=dnj{g%_f)%8i}$Kzv_ zAMWFBvvYIe635mb1;A5pxZH@8JU2McezN8VN8_mLV)p`%_6g00i zqo8ME>JKQ(^N}_G{^+bTHMMw!8@3yIKai0v{z=~PLRy&N@nb=_PAk=d2^6h@(VzOU z)^U^g%%+WGh4V{2`}05w9`2iy^o-=mSB09_V`?ADw51M&xDhjM?J`D$}sjRB5fLU0Y2<|hPnJPdaY z_~~R-FyB`rSPkD-OU2O{ww0A-pTDo)G}DluG|<^4RI0O8Uj7woJ}Oq!M$p*Y{Pw9z z~jTrmeqvVAZ%41y73QI?bp%xz$OKkQb&uJB-abN$USwS&)$DA{yo;>TZ(1;@;R;R;{)Nt_e8HIZeg5nfDLfI5X`K#E9@7oP4j%kO^#`^^Hrs%Y>4 z)L;!vp~d^5!6|lQv~Wmj5p(j9pWjry-H#&|H8s<(O>-;x#Z661C(3Lu(FQJlZb`p? zQ`hf%rAsq+#`K#@A6W=dJ}W<-_ycB0R?yV6i--8ZJPlmmgt+p~8R?VqW_DQOJ|lN~ zcvBi4)3H*kwzZaK-LC&${4ltFawWZN(bQ>ljjFt{T-fV}bCYcKj$O+K$t>-Y&b3NA z8yPqI?8$hq9yvi(H7eXPOHRNG`j&%k`4i7jzl-%^kvi9v6MYrShSkWyxSnwpOa5;{ zkcClBi+6ab!SmWtXPV%2Pgtt=do-sI?5G|-GKl{jWq?tyhLtJAIo}Oza5x_^|a62%OcJOu3PFIr-K;%`~tHcq`a4vkB_UrG&j?_sHzo1 zsVT#B(^wK!k2X{9>$q+?&o`eZr?7Cm9gcQEEy@Z#-+O=FInyz_`bCXZYLB)qJ>c0i z!)$Tm=eD+s0*vN<`{=j#jJ4fa@~=)EKY0B(ux?ua-t^6oJGh-u>Xk{8v2T!&>#SK` zb%U8;wh$a?X`qwuXVaYOtG?tzifbMqsH+k>ia87tOdr_`@DK})t{^XkF>$3d&267g zBYG5Mp$q$oL`UmuhtNLnDJhtt#BYYhyB7`Ap@}vp9RqK&J9fF>u)}9+D3`MDKGev~ z>?x>2E`?opz;ro8xFHX}i*f4Si>riOQGR$$R9f9n^_Fr+Hqn6%tAh44V2;=Q+0sC~ z+ywxH407RL!2Jm&Jp@*+1wSq&p+!91>ucOg{}X;23XL{#v&o1INcp{j^^}}5k?#|3 zBqU8}RU?*tBa3F{@q{JL)9*NEug|*9HT28WDx0A1R^GNxzRAR=I;rnkSQd0Nx~}ia z%=*3TcVO}{6$a5&x;}p+2)~)FQVV&k_ec-JrAQcy1|xqcMj>ewL!OvXnJ`>m!H%_X zsPveLS~7tsVNW>C=6(o~807Bm4qT{VKZpLXiwC*yA=`W2u@sY1&?o=Km%H$P3Euy$ zbiL%pO8~gH;^9V`=T_&n0}RSAhM&xRCs4nCM}y@wl9U<#WBu5sD5v(MZ3f zjBXFpgyYvd-m_V&B}Mhxbk-vVgu@qP*qNA8DNUmo)B=?RA&C8y!C{3_Bb*J&EGPs7 zVy={53Jlna<#us7J@oxAVTe8seHRn_3;Xx0>wuFtl)$!ZGy%7rkl6U3?w#x$QAl8Q zEHAd#iERd!l+m`d%7(~k+kCaD0|;L;i=WU+Jd-@8yXj)~Cs~@i06I|4JHaKoVqN`Y za>em*9H{O#QS*3gpSmemi09_Um1o|^(|V^pV*KJbh(RFK<+GJ9`*Vsg3uJ_zL_E&- zPOqqaMJDd6wYOm`x4njU%<657qS_}@FNS>BnmHl-g#tVnCK>lm8B1axF?g{EBxvn0 zz^{`yu$gE!VlZMrNhO%{3?VWpk}Q_{lZ9{+Mv38I{w+}Q|L+CB;4ND7S&<^Aj6f@5 zBO9>gLk?_HrGi%}8KK}U`qurMfIV(?=MQ#L~P&^=r7v(+AJ z$mz>eo{55$ydN^TRU*&rB=uOHWP;Q#js}A8{Cx+ps@CNTlJ%k7IJI3#!?3(qWErl3_zp)ngv|sJ}#7oT%CvI|lWz3Z5 zXUP=?!aR_yJqHS`g-EwUjM7v=Gj?o!DOsX*=OM$`vT``UHw@{ z;q9VA{ebXBIrZyY!4zbgm^ws&jthgM-0Aw17n_Mh0h+^9P$#I!MEIGH{5p8p#^A*% zbL{{P8m9Xg($mWh-_@H_y4x)XfAy5KjGdLtOu*3Y%VX(}Z~Urn_&HI#{a_?wYZ?2( zJr)#tsphmfl-qbBDOCy~v>RWccjCoLvv$o9Zti~Eq_U(07oe#Tkg*P^A_U4S4yaF8PG=0e2?90>I* zT^itWv8teP{y_;68;$QNEw4g&uyG@MjBq@H(iSg5QQ|Ia7-<}yCtsYx>h&+ zF-6a5J}kd&t4Mg3i8;)Xgs~V-ggw)UblA`zna0q;n)DJmL!%Fc1ZKq;X7S8pVZ7LO zA&$*o$a9E_S#Z!0ZURx0{8wH=(Z4qNu98$Qt0Mh1wUh)o3x#7lQ~cTB2}3ewxFP#v zY{4D6t#Mi^Yt(=)VTtoq%9--&-TEJ_SSx1m7y_#0)^W zket`^KglixZNV}tT$}UiKhcYRQScK+OA*1Wqh^bS7#|5wpQBHj`pfVKH zj>>2joM<~~{Z5c!UDCD`uTX8~*IuMI((A)k`7o)Da~8JcXHLqttkfPELoCewnr=&o zbDis6;HyJXeSVh6pscPn8*--BY^bYyHGS0v?%pVyeBw;}fB8kmg^&Z+A*Fn2pvLoR zWC}&rS&7zaF#ojLI+{yO*r*Y<(@@})KXmyOC#K6)(@v2T?L#H|naOqo24;f~jXE*3 zKG+_hAP!SS{6?tIDbS?gLo64-`Ms;%cj{1O?Vlmv@KiQFb3Auq_xyGGM(8Vn7ABUz zNn7c1(*^OlgO>gYw(5%~=#<v>BDZ;+K_LbY=e05u)**)r=!!hb-dP2n`tw_qxL<;Z) zRoGQhNLutKRKykh6?u>5tC%Ko5Zjs(GCT&70;)gh-~>C}kgF(Izow^8zibeC&F?SJ zCP?Sy{>pZI(_al%^uHOva~bmCeNe7;l6mw5@K_x~9Yndxq9&nI0wC2yIz2>Nr$mnF z;*C9Xs6R0Bg?0zGIe>#DhSorBF!!lrx#GGE*?S*e%(-E}I)jhv_rG~>yh`$3J>oGyH$UiRbqe!}~1*_;(i3ZC!-P2nU0lQ_Vh*bS~5IuZt-POdbp$_=qCr=Q;2W zK=Z=gO-SjN&C?nJEnm(MA`Dgbtmej#vM~?ybWwFQN}LJ$>!cDE(auzR{I=U)^pH<- zD$c66-lJiR9JKx-((^jl{?m{_cnD8-!WbD+a5a21ln2iZJ!>Io^CN`tJmRureJJE` z^3I?{eS<%5qWgzlvJpfmjr}uP6n5xEm=fo+M_Jt_`>RpC@G;`aO+foB&OfKdNbSRW zr4R#WGvHrwzK-(G04(7(SZU=pdU6wJF14O(Kb2)-Sz4Ky?|$+`D8ceO&b1#7oXm7) zik^>$-UYsxl(^)+@j>O6z0Q*s=wrsq>ubTGg6KtU$+dpJL_8JCWs0x2*m>7{hq%E(u;ru;LEIU4jRaH}~@$U;gB0 zcGjL_)~uOpomW8z2uG{(kpBZJ9xZOw4v}~|X?R3$gs!gcxW~O@coS1BT-fwYnaOXL z1gYp3dkV~(tykuIvpXps?(R!gf9=p{x-%Ve5RKWiZ^~yj8J&eAGop@3^YS-XI*3Qu zf&gpzaY__>I;-)r0JE=;Q@-jY^r#$&-Op~lUZhpZ@M@IytkCSI%=XM*U4tMpu##pF*g^*Ue}9M;E8=ug-p^NFkyf8Q;}AKcy9R>|WYb^SXEsdx0}%#i)s?L- zMm(9YnPSNu2v+}3Qq{I0E;#Z;gKUP}iWiYJ9u}QKiR3;_WcjeKQhduNwhHP0+|m4r z+Fhzq5F3>!mDvYqfUvrK-HsBv_TI?j(?Y%VskOB=oyrOE{#Dfp;3q0z8c|WrbNg+y zs9|4%5$)F}q%a$)UwCa{_V=|S_nvn&_Azp9r$M;-^XeBjrR2n}ZVmGJ|2KuA#fum) ztqmga5@n(OaflYpMy|)Mp~l8`Idy=f@|@A7j9_mPiPOK%v;V!^Vs7e2;apGXkI5T| zogq8ykN#s1Z>Lp2pUH379%fX%voE$p|4M;K6oBIa(H36JTpZR}>3$z2I|f&CH-82h zt=kF&ci#Jt7j`8N7N3gH8;-eCtk`|K!QV>o*BQckTZ;3AMfoQ(P~40$p0c%RQ1}~m zxw&Aw4;hMv7R~J^vUw)|jfhKFNWdDFse&CeHC)NuLAd6O(Sd`A__z zvX_nT=F)o>ukGrAoIRiIX!1NaJK9G!bZ&~s5X{?7~${#aAD}1qMHBuzQ1doFXtHb9HkV&6h`Ke>8t6GIldY0tT_25-2ami zXST)Pzw>`%8Z*Px-ZD63`rfW8u)c_M2 z$|m6HAF=AppJ%1`sUJ6y+c1)0%Z*UEo+(K-susJ^4T*hdRO@Y7ukG zOtqc_xl*z=Cz}PdEY8`M zl;L0?e_086;4;MEj0ms6N&0%4d0?Rb=6{i7Ljq>EZGQ^-A64>V$?aLHf=*DfXh_L5 z64~|?Fhluafrxq$o>zGcLdx3l3!KO<)Lm)iyzWcLNRagI13HGIgMm?${%5^j((SfXZmu;(NZ6IlJ)Slteb zt&uH7>j#CYcZfsD{mSO~_YbN@5!W-1=N5N~ANr1n+lp(e>rvV>!!hN|P}4+*#ik#b z5{K50JI{WJ1H2S>Asc!K4(R@CMXL|oskkHN?l`h2Xr}bviqibjsgmi#=N?9@rd#c*}`keBIr|JL!0FyfgrCd+#nu+J0$Fs2nLrXk-r_9{7mu;Hl(-P(PuM za3S}Y5E^;8<85}T$wz^T9r2+zKu=p2`O=ifaiq_bB#MoQ2^So8-^l|;|4@vr^l({j z{MX}H{}n;apfs6NmRMu8Fi>_Z#*LQc<9_xn)BL#aiwaw{Z^mV5D;tNoOKcYGhwLPH5W;kEL*xbx0n z4raq(e`bbl;e;SWgiyks3+TXXe_xFCjaTx#$h-ep29FV+PQ!UgcU65;N)dtnQn~Kw zE2?}SUCSL^+P%D#6T!O4-r`xB1xP4$ph1$0|Dr>=$-pQ9%&%@ouF=_8%7nJmBckaa ztAnLxqi@e1z9r3#Vl`Jz8s+-Tb(p&N75F(K3B{>d_33anBQhNzf)ahfje*2TN{j~! zqS6kz9R7k!<)?)7v#SbJ454>TWz8cPXB@{49-Aj>`Kq%OiA@Ojo?Y$OAJFPkVaqFD zbUq5a_ev=WKbd|&8oe@K@3;t0>~)NPz+XgI)o}Q@+SA$DiIgg&#z+d-QoXHotim)F z|G|LFcP);#%hmI5Igfo=vThv~YshF1q!*N5iM`rO z@A-Ys6DpKBb)K?6zO^{=mkqvdwiRUl;4By(BJ<@QpNw|$BZetBCeCv{Y=mapeBL7D zM_HGGx^x`YQ?fyD7I=dsb^jv&TR-?Q8CKpJ=I{oM{bMnI_I5Xl5K_UC$l8PMazDpy5s*ja8 zvvO$fby-LN_q&l*Nnqb4Qt0|xYQJG_g!WPQe3}eB~}bteH$PJ)ANG^C=Xg6 z&KCru={R9-D`z|ERv>iB%Te#`;Kmyq5YJ?Cefh-tM8Sn+O42>7dG+Q&$a^G2VxgEB z1Z+#qJ-9nZRw#$CtA~n{+nqm{q1Ag^PP|GPNx8iSyuR}mO>^G+JqA1B{;6?Y&H{K@V@EN~ekW3osq;A-!Wa@WU<;<>Z6I@rK` z$Z=-RXbV2fP&3Z&aIyZm`bpSINVhNTXNyowhe;{tNlwVg?^j_my^ep5txzNwJ}Vb4 zQKA*U!KaAeQD@E{?+1$xe>SNjde)DfJ>#O@+;PIEi)ukssfZR zo=FmOcNrM(Hf*QRWJ_@5rRc{bDvkWI+J-xe&c?iLml*o%`H;(IhwWvzSpe8=Nq2RM%vLRIfZ|~s|?ok^bv~%u~wb`#*(yz5sp;G z2!(=fX{1GfH{(XOn1`@;2?HC-ipXUfb@%lEwYtyObBAY$K1Jwr;@w+%)Dnj;5zox; zm}YNaLap`ZFRTHqfbj%@E+c`p_Z=aiHD(d#SI_$q*Fyc#m-Z)&JppEauI*cc@F;jP zHG(rO6ept>&#Kp|r@B8j^XEdCVvQsRE_OV{%r@>1XXa9r1Kf=PO3Q}-9fL?BIu>i) zZo2>BDO_(_M9Ie^(B-;GBbfi$#u*&2@u1D5pwvA+B`c%^qqrZ;t$Wv8zy{{_TkU$2 z#T1bK^W6ZH2&M3rAc00xMG{*bT?KVvQb*6T%dDW(b?%O;CrAy|V+B|6FF~ zrA-a__{n29neQtagx=4W$$M#{B`xV=mI_fMj2L;4#Xr#|u{Vk#rDLh#Z{eZb;-$#K zOa;eZG7iF{t!+)nxOiy6vOw_}hXNJ&l}vp1<*?)I6%$4!Qg=rg5tLvWb{@!{MjxRC zuH+}o$8H_K#PL$rDejI2_59r^{^h-6E(y!4qYh8g47)k`-9KRY4LT#dbsk?in9LN- zXd2djOU;earE<^~c~Z7a+`q$-Mc$^0>!!N0OO0#C)D_F~)u?HAtx4iCC=6(szZ9Py z{#U4QqlS|f7nvuLuicNEdC|y~H{aYpa&46*F&vC*rC3hRm~SW%ZxnM_v&d=1zC|J%biWOM%?-5s|y0op-Jy3G#~TDRbtHWk?L34K|iEi4-!Uv&@^!K zjsgS>&Pks^KbNv?g%io!cA?X)r=up8jqfI(e8lyAh1h%1P2uXNCC9=iN|*~p($;{B z+S+VMmDF`7yZ0)upiFv;za)}L(H*mdt|pd~WzeTE_teXpf?;?2Z4>!ayeCo&v-w#P zXvjK@Zp&!i)fj^_93_xD^t;{CzPrWF`9_umU*~`eQP$<^q&0vv>*J^SSC3r8oT__T z_q<}_DlF1{Zzw&t2w>~!O-6<7_ui)xXeubg}1 zVd~Iy+2QzhG}Hu;mEF7ZT1;5jP4S8NToQ>-fR0?hsoPYi>RD$e!}Wuv_PS9D(01vb zJ?!@m@Az6kugtm^yAkMSCdWr<^XaqRr<3^#1MBB5ULK3|G9b4tTddtrE6Nj|hvWGs z+#q27f?n+6{P|!vUHdMB$v`h!+_lQhKgx)>z}*$K>DjB+wd#Yjm&@|m!kD%NIUGk9 zCn5!40Mq9#lCUCky~i?L-3J}nQ{Wrj6QRav*$e9DFoMs8x)S6d2 z>y-U(#pE~PZ!AlJv_!}dBD_mKM(0DDBmLZ$mlNpvKxrceT~P}Xv43FP(YM5kJ;%sM zGs>nA_@XzLq-7JjyOFD#FPXhMIXyz}9u_!qrz36{!pPF#8MGaU7~oe5(HfPR6Qxo_ z1T6mIem@}#Glo7&S-rEl`X{x#xBJq({*8@I-Ffv77?Lc;wKAtJB<*Tw4Tsmm_#b+2 zx6j3>Z2V1iLw`fFq~Mi^yW-e5y7_ub$9mWm*Xp;7>jv-VtcN&a;Ih@nLpccD#uKmK zu1S&Mu!e6T5>>$k`7lz)Bje5Kk~J{y`mp*haI$Aa-Jrg$U$G0wj(x=>GVS*JyO=?@ z!Wtb&jT;l{a_c=2TBM;9d;Br~}jr)OwZU4((_y+j*fm#Eo)Acmos%uOQg3 zkW2{IQjDPGC;*G@f&?|>?z_auI!^t65O9ovPZz!Od zOo(OEwXprWh`2aR*r)%1J6eZ%WoEezVb8Xadc;UQg=r+MjqhcCRKl}pFe9iWt$oiC z=xn5#Gj==%hK^+Q3 zzzZKX0yM2DI|-Z^6*7h)FJ=TFqh^QwmS zdb6mz!~bwgb)enbClX&)^awQG6R2d6CjcL;+;FXL|Htb0ysRX(@igHIkz2p{)L~xq zPN`*e(#zIW@!=AYQG55ioxFGCQRJne!7FeadStuK^)Lyz^%!rihv7qOx_V7&s^82Y zId&k?NkHH7z|~rih7s(;L!3$N>nhIS`t|hRK_=wpEDyw5%k7sUP$XQ;yuW^Jt?M>_ zq5ILA!bI^VUWnQzED-q^eCpO~hLKeFo8#xAlOgk8DMsr-El2I$33!>p{TnG80pM2P zNcgkD2PNI1B3hsdq5eCJWdL0s_hiO}5q5ER!4HM}j}GYPB?|%UrWZ)I=3vKDZRxT; zxbjx)?PXOPF?iSLX|o0Wow_jQySxv~j$h~!(rJ@(WPpo`Q>$&?;PDV!U%nYUv^!06J$WC+z3+%z#Ofsgj;iG<# z8XLHo=&zOq8!yGD=|EVV1!-6xegj3}jauQ_-mVZJ|KVPV4!XMEP{$2Tl$+OHT?4WD zk-hu`fawB3j;y;xr+qrTK+Z58Q{`dbl>27-cqucL0?XjD+&yjEhn$zT@Skn@x2<~6 z`asa=)96^yal#jjCPP(|O}Pzt`opf!S^evl={tDc`!1I~c71ttv>PJt$)w|>*OM8P z&vlJYNFdG9#2c|cVp|P#H5P*g$HHG-s#b_>c&cqEDJ*g(KfC zmujIQRpxC%AZSA?z9MTk!(^=hu(4>_|LdF?m<1F!*7B|9oS8E4MoMvYXKG`~ww`V} z&%vx3gRA!`3!^R0+Pm=Z>1Bdx`i#jQ1XJDSW(NI3;N|F^_gd$Ge5d=d{aPn8^iR8&tr1@ju{+~;jp}=QPFw$+1$XaATR@+2iEnZ5LPzl zC7}~J{DC{Cb2JJC)ZA;#A6Ozr-gP>iL_gJn;?yNaF5)V#$$~);?~HWJFnR4QY&3Pg|HbG^JjbHet09X#zeFut1 zAt1IBO;$ubWD@vrL)Hhp^{W@{K6t8Otgltl#bemojuGlyxALD3Hgp)t?DEK}{R&SB z>}hgYs?MVB=M4E#G%EBL&L65)GF0--Vp%=_nBUu{lh3@4c&aEmIv1JvqC}(CVob@qwm>Z}c_y#rGA94R8#$iq3Hi9v?k)Q#uZ#L>mr(u| z)AU!^)~dezpr3UdaWn}EYaJH(92{RNAIpUPO>5fM>GfbO69<`V+pqVT@~}&an2@=vzj(k*57E zl-T5P^kmApQuj<#tJHwxACd+bIx{;rL@4$2xQ4BGzd#l+_$3|b2BsW`5QVZ-Jr@As zGTV|jqn#V@;rA{Bv2i5}at`yVCHEJa8fFX*4{s+xDjlZ1$H#86h?XPc$_~jNGcs>En_`dRNrfiDepN2c=$!3x8>Dw)42;A8g=8`#KA6l`sV2_jiLfK>dHBiILqmZ=w`B>&FC%xsDQnh7rU!ws1RRB+GCL$S`6{ zuhbMXz}JRi{+Tjk8?gg%j~Yqt@A2$n?C=^9r1Nl?`Jf4A&bYr!{tE-eKDt`CP3Lq4%p?O3%c-ixB*)wwQtD@rjA8i=d|Fr`>=El^1StM{k-G(>_gTt73bFP4{or zfyDRly^F~%+_|_&B4`lvSoU#XzRqBBoa0$fJah4zn;UC1c`R%!tjGXD!UjSr^il_A zX+!=!qUgjSTXxs+<;V~Ox$7T-tPKg-vBXaP?smn2MAgQw`(L{=8D@|!={j5vYQQe^ zfn9jBH$@i0%~fI;DMPok|0eF*Q09A6(XWW>-#+sNQTJc`jL|>gIXQ{&Kk>(&ehB!l zA%8{M4vdrN|GAe`E#rEZ$@KK}t+dqmBgvi@7M5Y|`g*S_@r!9}tXRClLYS|$_47k0 zY#A@2$VbGjpLG{Q2V;x7|9y}_moU@3$S86COA(hN4tgoMA#Y*Ae^9zSkG-t^8psdB zoM5TkeBOULeneOS8smP>oc&5Zo66Q69>?xurlw3MyiM!fSzQE`m zeyyDQWE3!BbQ+HIZ zazbmQr`2Le(u~BfnoOH?Rbs$XUzbB2*E{08@F2eS4=gSgD>aKAxTF(lnSCiyZY3D^ zjEm{l=rM&+(hz-$$64Shx`f8W^7*$TYm&hw`9Nq?MWEecbg2euX+Zq94#f8K!PkQ6 zoY|;_iR5@N>H*1ltd~+bTc>alQ8qvEcGvJi5-6gUHoO^pP|51UO9J+uqRBc6SMDt< z>y`=E$Q3NyfqCg+I%Pf=;Zq5IcLBScVVn1`&wLuglJl5+-v+?ex)gJ{taWNC3;Ye> z@3Kajx8kn5HBc^z5O{N1YN(_KXT3??PaKNE{u$v_i&F6M)A#2ICPC?!f0^zVoix>9 zfubZiO*^25N?4K(>%(Q|%aZ~({*Tb6$ev*6-a)P_KTwT*{%%}ZIqdhy@@(|{%EDaB z;tm^vK6%(4QNNfo?hH|pSL8n5Mzs@tsKwn80Y&`6;cv%qLR-~~qr*WHRhbwev|u{k zVxs)U!o90Yn@}C>^US*E#9F$UcjwytK)mzwE>?A`#mzD%9QT=1U(Yf4fHv)ZW>hlZ zo*gD<|Ie?F{|S}(19vhAvmLwmk0T#`zfIpmv+CY;M<*-u=0O~*4?T`k-@eqDzhUch zk9C;Kpw9-OqsU~ze#*x$TLbw-AT`KF4j0khxJ8}SZ)2%BlFhL2faCd_p0l44+Nz~N zSC(|xx@3DnE{+_V)$0V5%B(Jm^WUl`2FN4STd<>xO#wk}%EHt@I;=e@q=L)YV0>7YMf5( zZ%JM%t{~kSu2k~PD55YS5(Gjq8U&0AM-^mfEFpca;ox%;0Q{;h599Ojp<);OnGLh~ zm_#ppROVqKBlXs%3PXj#?I+Wf#MfTp(__d>J2t(r7LZ~vJw6T+xjXLrc1?A-;1eug z&O>EUe%d7lBP(^_C>5y;d6x1!ZCSX&4^1f8Og4Kti4jM@tzhJxJ|CJKl7703J$XLQ;`|DLV7_iGHTm0m;){1=l5VfNwlsX2*8URwNT z(XX$CbOuYX(1+>L0?f6er!k7A0<4SyQ1kIEY({Fm@-xg!kSKwJUI(gsRaPi~nWRqM zcXna16&?F+9$7OSO&q2W<6u7xS9|fy^Q7h#{#x$W2l;Qd;xv%k$~b(^(cZ|aeY=>? zDQ#Pr&C{woVkBt&zp2Q}^>CO=M}|JlDml$P2H|{XdT00ogM`c8sr6aevLK8X3zYO_ zKj8YNFc)V;5v!(Bh%h!%JdF45`=naBu#IGqDh$Yo7vmM@z2WrREbtvk4t64I_d6MQ z&y;{SZY~SGl8XjF4ki#iRroLd#*AL+?4?S!j0}idYeNhK;r8MK%+a-yO7UJ zLpKmG>}fSQFvuF?*HG=T@;Fp+RtFm7d+^Kj&{@tOjYC${Y$067^ArPSR_PC~r0K(4 zOU-qhO0iXb(xE{q3?YX;8O|M>5#T5e5bpPfhBT!;p5RjDdmYd3>I%PD0+Rc_KhC*T zzl7g?B(jQ%zsrx>x_EoE$L5Kbv$X#%O3p$Y{U6g%jRS^cBz8%aegOR~4|W(~GCkzV zRhLMJsF(Mx>xl9!T6Zca?C~!o(CvHq|Z@nu)k>#1Ru*6?g50j8SuM z=t(1D@X=R^8=YZ&5m{8VdJ~{sGquGj{CR!suf;1McZiq`JzdD{SSQiyQ-VqExKgXd zV>M0^b_5NS67;a=-~;$K8k4(zK?7(doV4z!IBT;-bnTu7ealESZNIjAd~&niIkQq+ z(LonsUt>ma{M7!d9YDPd<8Z7+R%^fDaG8^A+N;r zI4>o9-H*CZV#JM`7>=+vC1)ajMrpr1XFQhDz4<`mMh`ZolB|=SZX$jJ4lpAu8Ua3` zEUp#@yP4nLD3_!h7|t=L8>;^% z_c4eSD(vhe!H8u|Nh8h`b~(${a3Cf|4VzM_0{4twzbBh3ovPIFVlw4nd}iYEuxAKgSkzinj&9Q%dGBQ8ornR<*y;1{GDbKN|8naH3v=j?!v@3>$L<0(j%}{a zl4PL$i>1kJ9K>GT@9~mfcF9(gaD#@pOxlRf3E=nkVVnTk9KLZbFANJt6J4j9#Jlbv z9{TWs!(M;xVnQn4!?Pz>P^(B9&7-3T^+80d-Z1_0t(D*M0+14?;BH)X?BCwOOmS#m zgVNm@hxcw_+34>I9nM6{aLB*DKXElvp^eTg@K=?csXE?bGyBRPFJB3+r*uONHppi} zF@Ho3>CCi7Y)*NR>`k@_DjX*kR99LvG`g8vqN>D&ld6^-Go6a{`3$}&@zZzM!15rz zlTVjqSX0j&B=ZSlcddU*A@08D#H1IoSq3y7v+%p+uR7i=@p0FVb&xzg7{X1rASDV? zWgjbAdOh~_Ys#Pk3C31sCvkrh4nN38vUr>8Qd8>E;)gM}au7H}m6{Jd*MBcFV06b# zqf2S*HJDpcK4Xcv)IpC(RgF4;E!~F<#xy^GHlqYao8i(<_SlSO1A}VpNrJl+2UeEO zKbpDr@sEU|z!eBK!7QDjYmEdu&5~E_l5}1pHv}9kk&`dO{QYlpg8e>_O?_xT54oe- z`~GO_)r#gihe6=FYMDhKS#S^+~jTaI$)s!`G}qrU|9@Edf9q4FA!oRQEWP z^^R5I_5s3^rt^-p#{_T_i!jG;C6`EdrcjR}&&*G|7s6@;LU%b@#J$34IXxpvPtF3> z9a}FB9{ZKgY7@6}Mhobu7hC2a?`+6~x5}A&?3;Z){GzT`0#R3KV?^dq6RSt=HzgMp z6RkYI@(# zjNOG76j6LrTQ9A+s`oa{(F4>aT)7J|FPX%fUJ}p=t4Z5a6sp6)IPcGur6cgBCb+KB zC=y(3EvF$x0ZH|P z{~GtAWJS_~kM8|ABDl&;H(3hRgTt6ej9I5Qd+oRrdPpzf36dT!g>8Olw4h`{Ge?Kx z{5m|Va45=2Fes|thJH(%T*H_tyWw`-_$aYF^*vrKJaTQQk)`)iOY>y{37*StLRQM@W8X*r@|t_228b-Kh?hU2KbvnOq1i2>(h8j!e|`= zq=S|f*NP#9&0;#@rbTtm%YXdzsL&=vwJ9enxdbVba}ZAr2r=mXc>2C7Z=py7ERpK9 z4U^7!*!D^rlO$HdkEJ%y!0PRG7sPVoNpxm@o#V9oIo9m+pUsp)7=!_IUpKpJ{?{$r z>uy~VdThHPwAJ~N9u1tz4oO}3*K7Oq=We{YIJm>&!!Vf+R&>g%r}O92fxUFiwy#GE zc*fhdHISg0&qe}w1+Lci6S6aSirWu#Rdd7fIvzS0O{v2Qdne~^UgV~hmyDaY+_H+m z!}$Ul$vdTpc*=O1W`f8EvXh}VmH%nez(J%r*E>w?L71O+vqC1CBg45ET~)3`$2=#9 zF^&U?uV>D>JGkE11`=W`y1MTG{EFr;^dQ{(lr0+Q`ksdZE`QUNBi?cvq-#w>oVm$L z;Ge2UxK$lF4XE&DH$G^J%&*deS$cZvrroYjl$n3gN8f^k^9eEOu@+xWwdBvQeVsqTa-^b-XfAuRn2?BJX3z8eahzF+$Ij|bBk}aT=%tGnW`ds} zCr-cli>ah|l0r2#X#prFSR3;eA|&tmW_^sy+i=e)urE_157eGUC^9zA7!bv%?!c zJ@`SaHuz;mH`{vs;vVpEQ0UG8v+~y$S$N+HVtvL%|HD|9E>og6J)=@mH&Zx&JXLh- zg^w3!{WXXG+D(Me*}%U2B>};nZMEdeNS91EaKW{|e5U0yKb!qqoi(;qd9*ki<+{u3 zfvsrY!O!l(MxCJGsQmG=R7LystBUNbE9owf9h}~8ZCTs?4lsy>RVZly@LxZSWi4I^ z*dm&?YT?i#znEVp&rL5PN9b(s9H0+E>+j%4Lbj+Zu7gjLZDG9jcnE)d%l!nDH`Z;k zVRK?dE2=H#Z`_l35{!p+KI0(u_1U7N2rypvTQonWUXw{IPhEd=2u z(wx~Hpp(;%Y*oe+ZM5M%=O~XBFH`JoKfm;6)}X^vW_Y>Oho@h$B;sSG%0>jYjurCM z#Ms}Ud-=wl;}|Ml%Hrs3Y)h*3O5|?tKZqe-Xhz;RLz4T;@tU9JYb~TH2Yil>;VDQi z%i|+=1>R|`jBQxK0~MZ?NcE)PG8G%Huj|HzjX(d)$0}l4v3Uq*<+U?9|2sd*IL8t} z#T-Gd3H2fFI20<1M?2HYq7e^ALfG zGPNLv@-_Nip4e$(8C4BN{zqbM&~zmI^6c`9m|*E{&qb0)l~h66s52!~Y6sRA%EDWo zpjC+GqXkLf{*TYIH#iYF*y@&3FkHF27&>m;LT0abIh`~%Z&C6|3J3mHD zCi<7k0p)(pOQvlJ4wZVTQzxL93yJ`$SUAqQG85?D_)juj) zGHp1^%638$ZGw{d47a@3f6g?9f?!7iO4phkAqezTS{r}Y!VZZ1zD16;ZPQ@E$7NPh zerdoYoc&+cqTz4XRhi*JHZ2z=tyVcXfcDG04^sFOxrn!V7$NeW<_NyFRTnGEmOqax zHD8t1#qk8Kt$X%{+j{<5J^lJ>c#3Ze?>%Yr4FaChDW&@l7k}JZBHMe;9F>J?;P6>t zmX`f6MB}5>O};Td4S)YudSMtDcHjHi@7+d90Z*^#j;r7_!l{l*%C1U99X|STn9QzF zAep~O*MDpUBZ3GmU3k+WRB)4KP+K7Db@@86^#yQ{#mFFHgq)NrUMXlFG{3OWGm;9U zvR(Lz=utWuw|5K?|I88LoXF}D?58dARtF=CzfKCeH%DP0WPnm#T3!&xG?`o2TYm=oXt>-bns*#9{@GHdD#(%h5*JX&KI?<#qQ|CpGr+m3c}odt z7Akx%d9FLEVO{lz|FD0&MjB9$HPG057{~Y#V2e6$ZnsS(_H!yzM5q_#NO4G*2z69t zh$~Ue!GM}VYiD0lT}MHZAe&Y-Ut~426XDB<^0?)4fB%;hyO;%XI))!lhBp_I^XezK zA$r@tFxrje^ZeXe?&SA%hJ<0nnxyEht0;|avc*`kF!3kS7#j3&`#Cpt$^0<6cZmH( z0k`;gWjktsrex&(%q3uQ>wJHGoTk}VYY~D*a~R`X6}1*@p8BtYSiRZaqde4inE~_y zW7nx`Lak>H;q@G|I$zz^t{AOmpF0=$0c2ZegwU;}L|*&IpW81sVNHQwgcd++|R-S^+C zUiKg+t3Kvlh+G~B6-dX$x+-BHYJO%3{bwJpZo%~xWLi$%!1C}$ns+uAOR%STj3Rk0T7%5dne`jZ3 zVs4h(%rJMV7nD=|W;&rU_qZxO$3j;NOv8{a4R3yAAH0dL@(epYq?1%*D~O4cnebot zT%ArO?7}1;;vKAS6@S$x68L^7KJ2s5JEHuti9F|dHuO#|A+_%n_p~*=FST1(Zb0@NBrBp zo7w^ov@d-wv=>L2Ygkm$#tfvdva4!$fI1jl6)0g`PrO6HMbVZe4#USqN-mI(=8w5? zGofuKO>|^yg%(A;Zd@zrn?oXeHi;-dg}l4^GDex6oqB>t6Bl0J@kfm49F_mv9eKJ9 zOwEatQb@_&L2!w!8&(}{Ya0;$F|Nikp%7_PCHxF3%?6$1mh>lpU1E5_ zE@gELoyLP}CWMdA!lvY(GfWKBI<048Z62;%@gJ-M&S(tAJFH#0))wEj=z88V9VjFG ze#UK`G-orJ@}qvuJ=H%G$+q$rj819X1X~2042W1V0goE5$kV4f?dl)KJFy|TQ)87s zSQxbAig{A*#ZI}}8XE4yw4Ufh2K1$bg$b;}SR+X;O91Z{P;rDXp-FsoN7Mf$&3{_= zi``ur_t31aWvD9r0rsuyQNF8FBcS^QhVO?ENPpeiiop%m(&GOb|G#j8Qq#-oBzyiu zbtA{pv2ZN9V=s(|INU#Axl+ap>+WtIf8+K->`(P6F;Pl`kbC+J2hDq}uhmqx*!}u5 zB~b&jJ^TDJpF5;#QgW6$1AjkV6Dx4y7KUb=aYNd)UuJN;H?aQ2X4t^b@ z2-NyiaAUR&lhf3+TEW>TAe^DD(CtQc_G ze~itOHh11r#CUV5;+?}qwY*#N>a)`Mc2Bkw%I8EbWR=#R`vs)~V&k~42_JjyQt8nQzC7QfZA`VwDtCVCt9eh7X8iZr7) z>$f%!eT{~$7dpRn&W!5YS6D)(`Kg-zuetuR@+S;U9^~}o*N3o3RfqniSF%5Ntb#i4 zMr5=!$Hp6O43hhPY-t^`V3N!JIP*dGZlQa>2i#V(goGMkvbwv{c;W47SpFcj?$}eE zkrH-eynlA&P=$yhm88dzZ!ypv%Cp|NJIfElhAelWr}0ou#>8B7Y&ing8+XEkEW`t@ z=_g;8Q;F;xIbe&5aS`_*0bzOCUD@BBMb4GLcQ5Deq_dL&z5#D-yNcYJChh6nZYbA<{c`;2k}owdX#upk^XlWJ^=Zf9 z{dkkJRxEhNrF8$Geoyzu!7uou9rM@2(^J0dYXVkz~cH(ruQH$M>rQ{d>lgh!mj9;-5YkOhiZ2Gky(lxqjOzN8F z7c`cfxBsWA0Y}Ffqhd01ml_na9#P7qp;nrmaQdmy=cnplwTy=l5rn?M-NQb^`=|v9 z=mP>B)hoV)Aihf=LO)e}W|`>p7`i)@O*DrzNxRZ!9OWb=FZe#h4ne?_DsT^ej&Eyo*7ZovMVQuC9veDE3p9L@;VRMa5_i5km>NsQf*U7dFmidOZ z&!Nb{gHdI1{;>3zP|b^vU_<&N$yV0IPL5~K$shM$jKlwoFYhgt;+gd}QP3`KFq?{8 zRjPeGu1@$?_A)k345WD{xLeC0ML*-ogAq}~7C+ciW=tbyF^b3`VF-xmVk!$sdgjZaP_;U$_d0Dv?XQDk&;ha~PU%CVQ1GjiLQptjr3HWq|flee! zeZoZDo*);i^+(GqX5?SgcR%*R=if!G>#5WQ{o2P;;-s&?vE2s$Ru^H@>+vTGvswKv z+d$KN<8-U7VDU8NzP+?G;(^jkLkK4n4Zgwt^eeIv!b?RF$IosJl)aZDPOM zf(mX66ZvN+;$(|A_yxikL1@=(as@O7j)GApB_0z<;|!*l6zO^oQ@`|q9JNK@&)~og zdIV+FzmFZ04x_lo-zDYWlTzyzdi)^BX?{vQzd;BJYejDi(N1<|;rtEqufP6`z%qXv z^=+VBmCsqR?)W92D{eAe`)rI9(~ri3lQ;|_C-2vTE>e{pmA{8;Tt&+gTzdtx?X8uhI-{SweDIZT!qsgq0pqE{Bv9%p$ zAK>wWe~Zq=gcY+tKsHA^6aP+I0SgcAO>tp4n<^aZ~5r0pE1cmB3d4Yie6IM_;cEgpiIy>V09?TRskgTL zj$TCMCV`F40=Lln4lkj1YJogq`lCV0VcO*m_YBil`T+gq+8!|8V!1rw|KO`W1UNcc zSH!-HIA|+Cf^CJ`*PPAYq;nXT>9Cdr>|XcQ#-i7$WtcrpMs2#LVTUCpMl(^dqmwyL z_cSz%iKZMAsCMMP<4s=7^0c0&mygy33Cqb=in!$E|5HtAHv~h`qiv(;?9oMMLr;#P zwpUNWDdg-vU@{yGsR+CKI;`#_B!;R`Ma$vsr;{X*wV+S9#|$)7bdb2Dz}yY`lXvTf*%hP1q;Y!lb(#gb=Yr8 zE%8w|&qhS|0`q6~{LKsAMyi1&z2egF{sILhIVZd}m$PNn?eo`})W&J5j8D;$Dc^4mc*VYrdmkhJmQKu?ao(oLWSn+L6g}Vc8_FB*q3q?6j zK5RWITUwz|yA^UTvs48P*NKrHG#)>cBULvVq0Dd@fC{8mh9Qn(Q?W5o=tx^N?^2~W zCE5l@>BvVXn1;?znE8dO0KKe6>OAR0NeM%TF+6;PxrjOyrNoLn~wOtM-#h^cf5#=NN2&*kDx2F=qn*GVjhGvgR-LBvRiwtJuvJ>|gqi~a>xYb8{wIdDsjZP8 z;6JAHI_NN%NY1R|m`R|r?Dg$&)Skna4wSoh;lj!RrNS=9Jna`uCV&I_!+i})8S|vO z{Ugi}$)p?sA=L<=>HJ!5;GGQ1bCOv(Kt1SuS!P$V7OrG!rrPJ`5_GXq7H|VJnrJCS zeuzu3Z%#M?{VS>@$Ai4X=Rd~udPHE5Uh9m8|PjzyAf#ESsXP7=`8O>~a1dyi& zAp84yg#yX!BDF*g72Gb->%{x_B8cV6WM1^gL=U7FqaltwI|!feuv2OnE9cxFc>c6f zDTlxB!v798H{iaf9h-Xt-$SS%EK&&(8vcgf}pT zOR6beMwV3qZHm19%9?mY{lvt4r_U7&eec}s7Dh!Y=L)))xxB*ck8I{~<-rnUp=5CW zzx}^c2flNOq8 z{hf)SZ&Xm4gQ(QDsFbN;mewb7lEJh=7@JQ#fYZy+zf9b+pLb^v1 zh2sU3zXzyI`NKX1$Qz+V@TkG*=;+)JIp*i*Kfd+zgVv?{+_UPir)mB1GXDX#8#q&% zU048Sv~PU!5b>Y8iDE+O=;krt4?l}^jAVzptEm=&PaaB(?EP@){Hy=UnUJ_Uw2%QA)lzbSHZQ!aL*(bo7+E}Hx{Lo8($s!hPbIm=XQakiB-d?#A4 ztDa9~!Sz1x81mF6I7_WC~MIuzyDN-A9ExM!B2tqZFMH&gdA`(1Y^!0QmdqhX;ht2z)GqC?FSk_5UpdVf5XL;RyP9r23*h9O zP++7Geal_U%5!%k*GB4=_3`LB@+D%e=Q$B*p@iP2-56Y~sN4o>TxYE7M;K{Db$+^$ zIve@+SweSb(gH1FJLs1C{ofD{GnVhmXB5Ng&ws$9cMc1!t&LYl8O-H4E8poz1)Z1g zO~|&}n0ay$h?N|=qUQXvCMG`ZytwWVfAaGY`f5*20pa=*8T^&%;#Mm9bVS@gnc{&b z_KKEm89leSZxzTeXeAg}0 z#w{p!-hkuOXTZZrQcs?DXIKL)l+rlF`!V<%n3}i~i@S#otz!5gZ?1S#FuzV(_{%CV z0L(vEQ5r1r>^O~vP(sLZb8b*Sa&4aAzZq4UjWi%+okEe%<$b|M9?E8WyaPpgrAT7z zi~`XiYb6R_5emy?p#^?kZ$%!}Zlbb?=CHrzu z4kx@GG%#?=OgV3l;=uO1@HQ_N-{z5dJs&F^4k_jm+a- zb6R71aoK`jKV2i$(h=%Nf)Lwg_*V3REOz!6t=yz;pC84p)1Bd2T6*0(g(|5dwjzX! zxP@N8e%`yr8@Yx7Jg+-XkC>)$k~JJy%S(j^r5nhp_fa}X?JG$eK6x99kWm2inL*^i zs{|^D_y(!Wv%hRlB!zOz^ig@a1$#wpxTzla?WEnO}kF@B>;SEnfQ2C)At66 z#OW1t(xX+^F*g(wm{j+3W0|_*0<3%Dt6j8}jbtMxk=7zL+zUfDGntbwWB410L$)svbWOB42u+) z36anHp<#nq-aJzd1Z2X(lis}mf;SpkcafrBe#D3w2hUPJ^Bf2jUMsd_417&M(T})c z-G!zJHXozMZJFvuy**_;C|yCn^LqI~%{XOK*V7{6sQa^?Eb~fm6A_iKhTA7m$^u?g z9`}i!Sj5z}KIJCYB}aNE@fK;<+fWI#=9EL`)x3iqUV#Q9v5pas@*&{SegK-RWyH5N z*H+~;xOTgAUnKlJa|1~R5 zX*tcQrB*ao)7zr`%d(c=kdom6;b-?Ywwo%utDAz3k#EVIWGc4;GQYA5u#tPEM5*7X zDv-k1I$=d9*$WJpip6f2aiJ}VBMf8AWC`3iWzU*uUQ!>)Asn@K)OTo^!(ITo7iC^f z9T>qG!kwH`fwEtX(tVp#GN}e=`dG$T)a_ni1qhs{md0muvadTmN_XZcxfgWsTVULi zS0bL{_iOZe6`s8g{ETD`u~6*Q2HNXs4Uv?pPcj}|nWq+mMK)R#N6~^{Hw13@-ggXl z43Dv3utHd^&^%^Km9GQCljk}_8ZkxV-&}%08Gu=fPm(w8vuKD!9~5OzV)tX0#qtq1 zyI@7dU5@7PWYk}P9unYN-v?CetBd9NIgv9s{MBUPso)8L;}1`2(%62z0Xl|(jh1vL!ZGK(>EbQpZWgJQ$7 zmv7lALF=7dtRKFu1bII6g+{0=SpnuoOwEHR{Op51L=Pwtl0S&_;%WV7WTcGE7~<5W zm|cvG%LD}l^(AWsr7-|@iw7c{oPIMCv$04$#&?Dc*ez_J!SCS{ww-WGt;fH0wxw$Q z)1%-%wcuzat04^(zY=Mcl1V)k#8iqPT?(n^BtQ>SYG76<>>^(?zJ z7=+b}`zEYAb)>@D1KfqCr}Knhzui}tIp!~T?)KKf>p~7xj_byt@hzb8`un*CXOM3C z^$$*9>MAN)ESWd;8w(t!cqYa)KmVq0O$6$jm$t8V2Y>&f(;MgmM4J?8$J((a;76~7 zeH#%ji5f6A$xi6=_yx=%W+`mg>aW8r_pY=5h=(48k(QSB{9gAcyG!3v-<8Z22+;CM zJo0o2JMEzCmg@4ReFTMt;jS?}q#kag82|7t9v?w{Dt_ z(=?|*%g46`M|9Y(P9tW6wKpBJ`Ic4}hdVSd$DzeHDLe%5Y7;t6VPG69OA-#ot)Z-ggxVt2sA?!%&iZSeSCK(YmQIkr3d}{-IIVYIRuqVJXB6P9*{Gvxfk+@xw4ANs@l0c*p!i;e_6 zQ1L1wzaQ;oWR#sYZlRdUnu-H2CzzrT#VFS> zUU+qxY;$k$$x>QqOuG}E_G-8U;J)ej9r76XRc4cSCRW*`tN*U%B{cbqs>5qIN@apH zVG*Orkqbt^vh@d{Iv99;Ws`A}*=6{$<{@s5cZN#cn8_0Ydw}!I` z1^B%{YQUX*&T^|el%%(;4Vu#ai;ZQR3m#os@;`K+^MpQw-$CWiY^R}CFAR3}DOz8B zPKvm>eEgDh>lE*8oVp+evqb+ctR`nHjr-zxo+-O-{RX`7ZT<3a_!ec(8 zLvMmnH`g?dg|J+%v{|h!Ee(o(|)%n^ro{15z3m5me&sa6yGZpyr5eXgs;qQFHW zOJ4Ej26Oa!g#ZMUA`;Pq{VzCML%EkW7Sj(%?%cl`IgJ zmTYTfL!!fYU-rcIzw>Ny_(ExWb*jVqM*J|h;x>lJbo<8UMr4-+pfBv@Dzr9|1P!{i z>}OHtqlvsBut_=$rjd6?GEXAL-l&AV2%klsXfc7NE>t3=H ztg4Y?r@U$(wi8dtzw%+hFnL;kqTRWU(L)_Pk|86=+vSaNOP->X6;|Tw*!Z3JBd|m) zkwnLX;GKWEi(XUW1;cX=0V8#Q)Z&KW#cuJTC)(?JtZ3x5lC#+rRDJ}HfcVb%>q^lv z+q*ad7X!HwOQEaqir}1BxfqqqV;vjtDQt$4`{l)FsP;6aU@TwDT!^>Kqm`!eq^PMD zk{8a$w-sFKYm<{kUn#j#T+LNLBSR=vc;8S}_dN^6rJQ#)$lnL~ZM7U92ndL_WGrH2 zG}PAJ7*=2`WF!nsgZfA#bqpmXRk!IGOc@>YzoIQtM9ws|$WP?a6)g6hEjoJ&H@Yr2%ee&X$i3( zSrp^Y{0dO*PGX$Fx5f)*#+(?Ru&=UJQ3fIWAbTCwbGs{XhP!L7&X-70sRB~ZEzJ=; z=vF;hZroo+>h8f^L7yu|YT2wL?2Sqd8RZ#nBOd3u-y5#v8pUs*&O0n!Yi+%dRXiCd zwX7o&v_5EdzaY{Qx&M}nx^5*U@5Err-pu=npN2J&twDb9{otM>=g%|;j_EWB4y4O$ zA2RCRq`VrOWL$ohV@UC`==$xs94F+``LdZ>(V4>4)KSJ>+|eLWJgucz;%Gc4Y9L=_ zgY@tjsI8ffuCQOiP9!0R@SwW#p#8t#yVYeLxK%L11*E9woqdv|!P?A1ir$2^y9ZxX;7F#^pvEmNXl0b}lereG zBcx^UjsQvF;ZUVzY3GC3zC?0=By<`c9o4>k%)5joU>}j@_I|$X1^Gs1s;%CiEq9iCbh; zGAZ!49;G=#YZ!`k+UGs#1xA(7pJvSj)&`)KhH`l5GUIZMr(p6`iYaVm0j!N}eP2Ke z!v7hMg=UKFvOQ#6W{fYGwUVw-$rR?Lrc`Xp3Jafjvpt=3Pff<1#}<~HU=YK(P>-<{ zO!0;ZJuYWrq(tD}1v5pCgr8 z?l!iGL4(yp@zf`;_Q?E1oC?r5syZZIe~@4L-7lyl;al}1jTzvx@~sJ)d}&6FCgC-F zb&gp1j2}GW@P^nMx4&e${b}WRQb3>-Rg@6>U$;5uFWlK`)9a$=qpuRqBqh=JrjxeQFo58ik@C#5ozG(PjP5$8Y&N4^BSJ^<(68#VcI#)BaQic?%y2>qhHRxMeY(xqb zqM^0QeU;-a?@Bw((Z)0KRE;3+d-w3$BQcGGV^S^+YA&$?Apc8>$_hrS`gC&MODw@G zfR1xD(IB$6WOczyE5j2fMf^WYb}aUdl^7mM!5)U!*dzII(uVrG*}^@M- zlfjaf(6~Y1tYJZf13}bR*YU#>hVGZB(!Yin{5T%o`s{h>vAyVhe!+DtEJ3iVi$S|+ z;W3SCrPg{iybV{}J$6k7IT^^<2Uk>s=pEGJmz0s=_U3?3Kh20G3sr7}SrByG{HSZ3gS@Z|B9Zq&yXJ0{9rQH)^XvdS61QzL5w!cW6STGc|O9vva^pm;#aqT*{VlnITpf>`>`7j5JQzD2ubsW?gi7>uE~y)iGpVi{CoGfrwq=JdNtiqzjf4By{dusx z%Y-alZ2jkPCjH*Si1;F@eb6SFi$N$X@tuP#FudQSu|-PxlOu%}^a_WSHDPBS`pcVh zUbs8M+a0GH;R?229X6%WPdeVP4Du$huX^2IMIU?vtOWQxJ$bW(6z5M)${y-C)udW; z@+S1bAWqeObM8+MLKC(GS2Y_IZ|1dx z7L}0MP4(5f4m;vkqPiOtv-=|yb7@3w~tey}8PDhGRkyy2D-RQptd2%7(9kT!%)^ zDy#S_pY`*$EiQp^`vv)z8d4{0tY*ge6`K4$g!}rvOmm4GAJF?`1!Z<7n!QbJ=c4#T zX!f|}2G3xw-UKS0NRp#Ki*-aqi!u@O_eRsk#2iQ_Eli(?JKiz>A{^8DGoXBeyGAb> zevbXL@0;33sW{NrnV?T9aBbtqsH!I`?W=9LY&D#??aRa#@!XNw&yjr*7t6vE>VM%- zm+2?;)k);{E8;Jnjrw+<0}BHHE`Pj`pUSdr<|+cAOtT4iaf0ulz{dH71;nx|`qlJw z>eD1~PEN4Nv{GKy8l%cI}C=2Ab~^d|$wwi8JyN1x`ePYg#tV>O^}-Af$tR+j13)sc~_ zm614FaavP1ln$`!;Bs%5l#tYA`c8*xaD4Zb`x%AI_M&pHij)6nKIYpJ8)`7uI&=gy znCK@def_M#!TKl~$GxOM^f`%y&$9Hjr1>l3l4f2L?@P{M8O6<*#*$Dm>YCjNqjiG>wE--$0Yp2;ZX<6J8(DG`&g3}|aZ zM^+iIcr;$|Y|58V>^nZ!t z6YhBg4t=|F9s%WB1Ai^T`@T*VV!L1OfPww?AdtN#O{vh64)?h~2`fhGUZS01# zO~QEdHV1Ue=H11Zj^pQ@zMpgFJ3cM&d^fH{KGpRT?z;w8>|`rev#Ucge)X38KW1AD zswK>(e;yv(C&qgpGv&_bj&TwtY^ga}-cP6aK2Zv~j+vE@C(BU~+L70tCbT1};cP)r z@l+Jo-#Ne4rr}i${aJU)h?PTxyj$#9o6fz4bD#O+;H;J_8KQ&plbpzf*Yf_`IfWjD zaFS>mrM%9QpAaXi)D&3aA_E6`SnPT+tU`w<%I(XSq8n5k>Wl4!0RQG@@obK0VwsG_ z?6&~B--XGjmz&^2U%B6{@&S|PQ!ecG2$w_QE@?~cG(06O=ZWf9AgVoSfjK6>pBl?qk>TE!(AZANCc zc^Qln)}4eYi9CL)VtovUaas{BFlKB^2F}nMYZb8|1Ez^M6FCsHGh#b@1S=}X--1lE z7q{Xil8*YvEK_YJMkGg9{{;GriB``h8XP7z1viUh(+3?%{034u4k6oDHd9Hf-iJWe z9ruSkB$hsHNqSkrp*$crN8XNO)w7G=>aAlOP)CFku~;OAE{mx+2kcN<*N9UQ0SMrr z@D5IVGpb54sV?P$i`hAJ%Q)}UJskG{eL~r=w#8X=By!rFj`K*96lwSviAe6_rRB0ya#<2`H4KwPL-hDLhV?*K1f-gR|L>2jTv zK^d(QC!+$vZiR9;r_CNKwaUN6u0Lq)NTXdJ_g#G9)idc6o3%+^B(9aW-Bl*>%Y}FE zwuRuhK6=^9rCS}`%s*}_z5X-$EBT<-P~dt&6V-8Xsk&!Sp)kYYs0eR?ia2!OH;w4= z*0rdm%F<~t|8c$TRdKfwa@Z|6!jK3<%0v^P0_Zd9+1-SIWZuI`$L-F7#5oYyXcqN3 zNYrHrxCYnv3I5go27L3~wuBKC?LLejP)C%sdqT=(6d1pe$7EugflOw>#rwg#<+J_b zIj3b>$E(20TpH$QmxGa{O7>!&aA&FW?rjED%*u!6+_B93mDW7dfk9_i<9VIo8Jbe@ z(y zH8v1nvGrXYm-DYiL)Jkp%((A1E5AGH@Dx5w*ptCMvhdtx4MgA1e#c?4q2h1dBuS>+ z`vY3ITSNy&9N=+6-5zKZ$$B;aHMdtI&l9V1u)xw-BdZM~Jn1i&6d1GB^*os#5jiEm z@JGQp|w{PA^l6QP>} zyKgpu#D_$$jj-3vQTKVWbhl$~s>yH#@qhr6eabxC){1o^Bpu?G)V0F(n3W&?MH?n)2LpVUVXe@9wx80%T`+ zp)9>d3#|+#mUP>Sjh;b=^gdjg7(!$p>CWX4f1n&z<{yDK)6uS9FCO^gU|x z3QRte3XicZVq)&|&;de})NyssT$Sffl`?$nGmUvjaUBLdbnHA~toz)r5twwGvkDnz ze5zhRSa*PoC0L(B=bjp~*57d{v^2Edw_Jkx_pWkPja-Kx9%^E5D+Q*$m7U~nGnS*a zDlu4JSS_wrE&oa0HCG8iz5d7<$MdMc2Knj*uO*J$Qk%#*7>j~NK&prUTUw<+&O=3M z!1>$eDM0t5A7H(%PzxdDy&;+LV%<99?WPv;Oy=F+(TT&$ms{)+Nr!7tskZ7>l7R54 zr7eVq!_>(XPD-4VPX?_C6fh1aVQ~DrGhrYo$T3glKb-`NVUV!ey3vuN4Jc{h6(en! z@C&L_IVK{hT2`cRHb6THE8|5u^?I&roF5fl;JPb3_k!LdfE6V{QB43HU|A7>R9GQ$ z;3X25!8uLVxtJ{fz92eE z&5a{2YJE0aru^IC(`=(#xL9?xN>4xBe;r2o)@2+PPNtHJmdM+3z%^5w#P zqhXR{zIvU_sb6HKWLu^On~Qi1+egj_RPPLEVjn~pCShox*qaSAnuBc#=$A(fBlp9v zKTbPyx+D>T{j>H(Ge{VkG$d;igC!*iVt*Fis3(8(mp7(m6!4+fiH=sk!odvYo?{&} zn(t^aHXvX~w3(d(_|Y=VnyyMmB{6MA4FIiYF}PQDxGNc!1~`79gOkqpevEKC<+K}) zGAiXhf(7zerc7I_*@S|jwG|aXtrcsH0Pu` z@$tC9>EQZfm@LyS*hGrlHr#i*shZT-Q%D{{G9i6R!2kmMR(OpI97(r zS0qZKREMla$EDnJVpiMc`a1U8J}cgLBdYE15}3!Z=?3S{NfpJ@5+7x$)tCq!?(c_0 zOt5)O+I7%Ee0C}ti(hdL_V}cgTq~A~lHyt@_xf{~q_oO%s7t>v8Q=j&62NclwKQL{ zkr8s<+?a?dkv?W|FBdWVkaDKFn&Io!dw~&^NF0?C-TR?3Q(b1nM zzu5G`GXFWIR?1LoPB5a(~IO#~1PSeRM zl0)=xt!K&-EEG@deynva`XQq7df%Nlhml*X!EH zfVZ_7yH4Vs@|#>)evAi?TFayG(f$nonSgzNJAu@b!FCTlQrST?62i>14$zln`#Mri z@nmME3~sj$>LYd2T~p{oNM;Zt~k@Q%kd5mxUat>LFp_HiYNp9I49Gus71}F=V}(Jcm)!9h==%wD#-&= zKk(#J5(G2BHcXw3nQ*Jb17%t8yLs;r@ZC2&m>S4$6r z4x#21Yy86p69AjvkVBlLRb{XRUw(vs!~I+Rvd;n~&DRfYuO)Fu=t3bp2Mh!6hVY!J zJ^@TXOtU?${nEKYSw^fVcFnq1?6HrL@$vB@5*KwejVC!H^%tm>0gB)I#}hS-;|N7hVNS;BWOoHm4lFVGSUEy|u zF*U$HBO0~7zVy3!D~S7wUD}Vn(e^66a|YkU(>=sd-H-9G7>91KJrS9?k2nny`M%Ok z9Oj>_ir{i>azyx9h^idhw9H-7FG7vbM~AcNc^w7UeK|Sy$6)B zkRP<@*D`x4pVis=Qit-cJCmgSOl;-S<3Gj%A`)EEe2@GHP=A$6j*EljNc@d**Yf!V zc4wAVnkkzA?S@3SyGr&6L1d5(+4rP-?(w9>Bn{+bE+C-%tYIAw^l&(dUev0AL8SUO zcV!G$keXXUFNOV4_J@}%4&x&>+NC8okQzCq50`Rjw&n8IJ%v9OQ#2c<0dGUbY4w~Z zJO5X;iEm|ff;8ws9~qi9YUcF+EXb<#E89?6|B$0r5~Z>{mjg%&hdOh?_Nl3<{|Jmq z^uBdMb?l&r?OQ?ja0g?t0|<6|mQR9OcH_bn9yKwo-948RD1MX+DCFDvi^uW{WMw&k zk`|DS)V3%vtPj$|?=Uf*8F6gPc!b8561WHDsI@uD zqI`A6TFGN#&AkXoq}A6(2m)SmYUuc2`gr@^n6?D=633D@D)8Zu!Xr3qk_Jmpny7+G z+-f;sPHNCQ9a5avdh&2DW%sw%0=o0{L)ed}Q@Wf@3w+?uk9!tCpv@BEcA#{0PrZjb z)>MLG)vrB#knlCY$9~`y;2J?=UxBoi2%B=3SuH*>rZuK)pa9*aW|{txSQ+27*y;ue zJ?NM4Tfk=(mq4(>ZmXjMkf;9y=f^c-Xw4hoTJg7Y($Sm(K1ZH8WQ5?Rzg8~%^iP5m zd!U~1^-YgG9bP{FkOSRujtvZmBv~tSDCXbN#d@D?EpAG_w;wP|f-zctZ85Dhd2Y7E zD;CC^nt{@7gA6c3Tg?;3K}`K+$#*0n>G!=C9UVWGut+>04k^l|9Na12Sm7Yd(<>2( znrqJ}`JM(h%3XZi=z<~KlmB{Mk#$f$H@4^!|BbKlYp=k0-M{X>PSB)#x7ym#=NUp@ zC4V3DuQ9nI^UYFLkdKuu*4J8 z#Nyr(Shd^GeQPtl9I-Mhp`|G3a!{4~cZ6(^PNq-(0N;90&U?riSJ3_Bd5*bE5gPWk znV*dR&X8PVeg=M`mf^s2u1Xu(6x@tZV6{A3r4MIVO5$Nu*k+a34|BlreB-r6a;k4Z ztt*U-m>w+IQ_+|N!VYn)_F<5SOly2Y`Dx>dmeNlCZBFWL!j;Y(mp8xPvp%iQwVfco zSFYJe8IITOP#K4QaM53N|0}sv1~?xHjNzyHmCY90>%|zh4HGS++Nx_44=I1KSzTp^ z@PQvTp;0IPY3r?kJ`=9h4MV&zG~|4Y=zY|3v;@&Kw`?oLf@5?0AJO1hRKfS*I_5}ODep4AK>v@cW%dST= z7&#@SuNKW<)mvEeyzf_x=Xe~mk0^hJE*IuJiy}J6yhD{C#USG>TOZ^@TjLFT zCK?X}J5bWjS9%!ZtN#bw?)TVXBSwcASD<5wh>{yOCZe0MIj z$h07V28UyvuVf7s)oVWxd*=E$6COe=f|_zU0ER%ul)Q!36%2*BMXyj&sF!j`&Bo z0+-Uu>DiQe*B?XkWFPRN;s8-DdW*iJ;LXE9uh9)!F1z)w*sp{dNw-m!0IZkBr6r;A z(iNya7E*QSQT~@;ArUwMp4n~u?tr8X;iU$D!icxcL{_AH*4XSE7S`(r^+6-Qn!^A6 zCSj5`NR2{^^GV6Vm$PO z20>nSoRRP#_tyLhxxe|d#y;1a^;Try$CWx~XXkqZp}!Dw|B>(Ci<&sF@XGOwOCrN{ zacsJUH)g1sZ>oo&T&Fj{Kk>2WyNDLFvy2HDi0fK-p)u66elmH6=P)9u6;!4VWIST$BIIaqR~6pbT1mhf(`h1F2510@4bM2fT&p*VW{^H}GPEpl;5at(b+mkS zhP1dqzOX~Q|1CikFz~1CUM>reLg4sGPsZTjaxr#*z_}xH`xwui z8^Y=8`cR7NF>n!hz%ye5s9|Kg-M*8Wr5>#oNTGs^6ze+Lrj@|4E&fTD_-7vc6OVau z3$tCensS5FyORtHaEN)C$gDNjTeGvQ?9Jk9n-~Z8laH zt+CSdy69u35xWS}ZuARA%!ivk|3iBJ|L*@aAS+08xPrbm>Q)n7AMN`uoTX7q!r|)D zsw4x(1re&x4_T~)UkHgKwm4B$(AoXK8{NK{^?~t9dtu@{#!UY%HyOu=FAJQAc!IB_ zjF}qk{yqyu7B-VJ{!IUKn6M)2`-lvD_qijWG=lY ztKA$Ab*&6Z*m_Q>2IAkw_~5@lMF06kQ+;aN?Gr%D7ma>G!A*0rUcq@@$A0E;&w<^* z>z{cVf$BR({WP^}+BFxv$DQM?dPNc<-lJ?3hXU`!c#oEIzVf%QSFxaip+Rmyw;41d zLD)T@)jnod(~x-T@NQj!!s7bT`Jsc1ZOKUf-wo{@J?FfClkgIa#60KmZt2^-4l@tP zj$`A+l-1uQAr~8HwLzo$UswQqu+klG=Xwe6DwE9B(znu<6=FTgR1^v;iGAmShQv=b z2DS5+Bt;YYi!f~}i$x(QBq6u?pY>Eh`sZ}VB8>n2?56g8qvbDNsC$7?-rZ)#$mzIt z#$QEFbO+U1{%YBNsw!`1Z<&X~T#P@!hbw(=+pU0J0Z;JrnkOL##>`dp1O28wDf_eH zY8Gh;@xLszK!j@_*HHE&&)f!1FQ{81uo|J74Z7Olb5qp<4oivz!^~n-S{{4a; zKOYaYvJwoMKFf58miLR*n;hHYI}>%Hp{XheaESuzyy4qM>xES7v#9eb{q5lS_DmQ- z+MZK_JZ!j{Hag~(GJ%4+Cm5zeQ=UZM$f-|J?U`Hm?Xcm*s<}nw7w5!|&hl~L`jhCt zKBX0fpKHG1m?Wi}_Y-)7E|T;5njTnMpi><9m~&%BUs7B5Bq>#_X? zJGK_#<*qNcDk3jO?CZwt;RWQpk>`P{^O?`ja}C%4p)k{hhTjR!{duW~`1rbssg+!$ zrkUkf-AI;{c0eeF-9vZxsz{Uy=NJPbiofcx5Q|R$5FfvP^~ed*Q98rJw;&=?x$APw z|4ylrD$jCjNEN=9I6I5uh-S{!B*{~DZoYr*jf@~AiF={|Q2E24mO|@_l;30D!kL^K zF&88<{3!tWP%t3!OUR}IE-q3(BEr_p18*w7%+_3fhkZ*K!;PSXwNXcvv?DQ&Azf&g%lHu2Vi+7PFVD|d*;#(Z`NCgSWu3H^M=T<#HDU|qW$wl#z?KLNsIOtM=!Por7HV!}4w0b3kcEFORd zYv+`}>FhS?12gu)o(4RFA9`p#Da+8&fPRumV8GKS{Jf;n%eAkAA7K z>AtPENE8r{kUv+VZRvjFMCuv#GBuCjN_SM9C{v7myB31Q6X7A5-1prvJpkS*7*vY~ zsI*uUFyR%>k&v%;G zRsDeJujD0Le3FVh;1%Mf>z%Ep!J?%Mnq&TRI5}XcdG2Ypr}~lLxb%O%r_3!oZood^ z2(ghEVi6*U9rLweqHDNk_v&6gy}c!}2BgiM#J^_C^wouMkt~sR&4T<=$fmo_#uhdK zk^&9Y4m&;C)vcUL-fzg9D?V;sy^ zW_3M@mbDt*kg+kYar&pAkOV54ZC^=oRD|6CXyY3vVy2`tR98aKTW8{0Y>XRtzk{RJ z6W>#2HU*CcyrABYUJ`sHB;S4+9}!e<2ep)pxlf5ei5}WfdRz3zkl=99&Lm6P;f<~= zji9T>emjod?fWb%nqBsL;i1W4+IqIC5!7WK>D6^|>RUW`J9ILwLpbn>72;p&(EE_m z@ndUU6x8amyDte=x^Yc^eYk9TyEVd$3G2U z3PqHG2}5O1ivQ}1#vLe;3OOC+llX%$mck12(@y7ZqumQa;IiM(NJP)}ZwjlF0;|dT zG&9JjO|-D}dN7B?kW&+rF!2~yPaS_r*LB-NJfyr278tp`$*4#VZ!!uMDN!Psc1^H9 zC30cK1U#C603fZW$&ld;6+y$U%aXKmAzn1Gvy5inxI5w>yb>Co;g@Mv*f3Wav*KO9 zL-5o2yWYK~MmTzL0;b%?mT@I#SgZ^Rk$L-;kjb#M9h$iJKCr_i_$#gIA)V1V3p(CR zW7tjjXDh3fFG({!&KjuZgI2haF}nC8L#!?Z6S-O~>EnD(#kpC@5o5zDfhVVfxN&;$ z7v(GiB|b#2gKk6cm(8DsOg^34(=Y0=Xp##^`F*Aj{yXXwD1|d831r4bYqGTp+Y%Rtlb_4ngj^r z5nlf{8b2742>8T(ieUXCp;e)lMQ z)pLxIM;Ccau)7G-^PawwIl&pzlv9X`_;n#NSP%W23SmG07^Bc|E08xNJlG;+W-Vy; zG(>yuAW9-35v(-w%2N~#zYiDb6&^wivjZh9_Q~Pd#`?=YPVAKc<8i|ci`G>65dS0r zY0AOHr8E>_(0S|S;-`%y)cKVT>xD-4WmIV<_(Cp>i8A*6?;;NZ#&cq=E-+P2j8dU) zis;edujuadNctc{u{{d(&&6LM#`rFdAOeW*hW5b`5ijLML)B<6-|>=vXz}(c`~6#c zj8z&FF+j+1>tx8jr`yJi#BdKZISm=T^9Mi3oRp5YAWX@d#GKe;Fx(Qs^&DSP^1M52 zWu2_~yEQ5RtzF_$E*B79JCh+I^hzc~#?{*;$+NHD$;s6G*I}UhjJ0yGUotP-M>p{1ifzWF}Ya`BL0|ctLElbzCjg*qg z0E)#2E^4l%<8AW_gIs&ss8FP*FZQDXT-h#S28TU4C7DDuHot5l1tv2~mHqBU;Kl!W z^|GW?hIUW><)rMTUn0WKt`2vAhLKU}2=l6h%Z!05G6|br_VGEsGuko-Ujk!Y^;3NB z*GIi`fYg*6qK~iwLPz5)+YJWI2)=s(J6!q@xz-K;w3MXxU_9dY1_=!Xrn-3N$9y?8ev!z3@OwM1dQ|X zY3OL>aqMZM{Sqp;f#3rtYM3a65GWl*wBihjS>Gt-TZTh1lRfp3{KN>lh(29c&*7ZS zJp{J{=34AvTY?`|3rVJ2W_eGW4IXohLN+ zUzoIJB?-_EH!ffXMk0RrYaQ*t^PjvGN#I-VxiNgoLrzXvM~BP+fbJtECqmDk-`6Rn zZ?+KAz-z4e^kxWu4hU;2^K%>`=r^#DX`Dvp(vW zeje=M0+gkP-K0g;rHMn$@jjv)m^Lg^fkZl!zZF6kb+yJmoiZ@i!P zigqG6mul#Z^hHyB6&c@){5% zUrx<(L-SxVhjn&wv6K!u*&#>DEG33N1+2aoJxxk~oBtgjODtSHaK1aP;9Rs0^@!?y zI!Njh-}$*+L<$K|Gt5-`pC>*eOl|$)Bi41Xy=nL{TjL(A0q@^_|7d57^fB{Bq1?%r zZ;8&trwg7;QZ{ln_4{9HZ|ZK%;HyuTnlyW+sP1-Zlk!9U<)YNsCuBI|eUBqfgdBoR zNzgs)YU|MHI|ZwVVU5v}tla!5Prhn`7tT(KwNh5YFO1%M-q^hsFG+o3LhM*{ zwpm}9mJTkiUi4XM?{^LB)$YP{O7p*%oJiOx8H>9PK6!-QLW_!0wpjs1Ks0UIJ02~N={AqCj>zhx1B+Fy0;*kX|Pjnm|z(IB$%DcxFgY)=@ zq-7^CivVbrMG)rCOqd!9phY!hjw=ovyY~0Y?cTq#`6=m`T<|^G1x&^Klm>SQ3(G4a z*!tojszi+h$x&;M!U+a%9Q6a!L47^8I3ZFq3Pz_dRj>oXYVRoSt_v+50VZbL}>?&^`SUr5K`3PX~i7$a=$GAB#I<9L~c5Iw?3Yf5~ zWJ94cCdU-KnnwQ$4eJp}5DMXjLgZLH})x-*f13qgyEiyb+yLUV3KPYrl=NpR>%0Xrri z1%&4BF|9yn;h_dx#HbPbO)J@`nyQh6w3H0YxHzm#ZvRZP+W)kS1}lN@CHc;8jIEn5 zOBMwK)mAw8h#vWzgoe8cz9tB{5u45e7BqG9E1W!8W}RDi-^|ipelgQZXJ-awlo$1p zj&9Kyv;BhjFZsJ7Ow9`OsmXL6K8>v(ph4vdd@R6`zdOQlSs4UE%%)XI_uL&SWbLz9 z)xa7k0G1yDYz)Z;T)S=npjMKLY97H(H##@AQsjj82R~#78~gChMDHO9_#f2WIyqr{ASdk=-MbJ3i z=Xai3ip<>YujK<%h0t4534w10PB|;uXHTXU;$flr`&DcS;3q<;N4UQi$d>~)h_{g3 z@W0By4|1JZOx3~#8FI%T8HF8K*Q9A<%k)^I!aDQ_PXN73wbnHTsA1`71P;uT!y`agXLvj>Yb7_fthBODZwec1i@_J^2R(@$EmhvZA>(_g;FZELoefk&Kz zITrCE$naV745Zv;93I3H2Ar?{teQy&{3xwmh!d3lDtVt`Y;m$0&l4GiPED!l!?>f) zmQ8=DbpDLtE|~}}^iHE8m;bV_fp)@i6J}U1o%q zmzigz7_e|6PD}!utV!o=SfQO6_eyD|xbioHs_p+Y_AM|tm0^fVsdj9?pD`xKg0;-b}c*~S!GJb=Eu{H%y>r3M5;NzJ-~24 zm?&vS_<&h_<6SChj}m~CKPw`I%u~lB#YRi(X8z6|wu&T);RLBwVRc;84X2qeIW7c$ zhQ);qc2jEZY@UZhxK2ejRS+4Ae|<1w`SYJx1hK<+HcRjU0lg2uFGn|S@=Fp<3r=BH zC);8jBapxrJXtc-k~UQ$@#EGu`Hzzeu2u}PJj-QQj=RHVrbq|5?Ux{t#`{h$kqcyI zZ-tT(s5nBk43SZdDH#Ag8DMRnfERbofUt&m;+DEIkD`~t3y4`g{@?0^*z_zDK>y`a zk-JhPK@E(3<=vz3<##O6n^ptzG8bamDtiwoeA(<0U8SS`qsz4F32_x>pkZrq1Yx6^ zUS4!QfP=rbTZ(Mw@SEdLS0jLnS7tbXG7eOW=jNiEp87-hAB9v~!2W{=fS&|dBQ@c1 zlEo^oF;|3f7~y!md_zene>)o!qF<_+=VPT;l8W+m5VIu!<* zVRWFJGL_$B2*&cg8FuKi^I7h046PyEt-eUq$}>K}1KEYAY<&$M=<@A9`t ztM81@osl#tths5pNBYNFQy*Mf!py$v{Y%A)IdBU{Qe7Ep(dD=OHC`SbArYmoLJw39 z$K_>70W|$OO$zA$?#PXA8xFLFaHMV}#Znw5+ z=(Y7@;hd19;w9_@y# zrcH(h8yGKui3FtB;TxMLSaR*PXpP;qOZ@83J0}_(Q?=vUoW}pX=Y>+x)&(U6!rnfj zi%d2M590l?5%qe0<{{l;H;)WJj{Zp!0ZZbiPQI?^PjuRkD^q$o^Gp9T$?Z_N+*|MV zA8)x4m)B}s<33dXnH~$_6(v@6!W^Uj2Mkj%lWK7fU2!D3mzF+P?2rOj97D9DZqPf& z4vs4ags8<;X!VZQg_h_tqsE(z-T%}Mqr)uH*x_57PREeB6-)cOgpxC7vuFbBfdq~2 z*Gm6;F-$JBv}#-^OM2FQdZwR^MHsQ^<4@!c=!SP5EplC;Y@qh0h@G3{kUyAw|Bm!HZTZbM>yd*r6SG>S%Uyfn` z8_OQRpE?V8-xcWWTs;dW0GKVJD|lVqfw0e`hIlVXl&RD}VR3@|{}Wm~J9fbK=7Jr% zMgTe3a5hfiy4%URtNMTYUXu?hivIC@66^Htz&6RS)KyG?;iV>YXSrKXdpZ~X%);R``6NG-?y?Q*R@=z}d zCrEb@om@{F0j+Q7hY`6j472>~=+BGwDVlP^SAX;HzZ8)NKiL1$Rp%Z|J_SzwW{WcA zUzhF8=nH>VdKuZ1Xm_d}97*#p@bF=;P!>pZxA%U2M?rSUWuELZz6c6ze8bUB0Ki-U zIA+Z{wFhnwhqo?~n!J38(99w+Q-5xx97GK~FULE<1j=lbSC4yVU6QmpmOb5R-0+!37? zbRac~x-gD6bErLUVOfzugi8O-`6)%1zbG$vCw^#1GP74yK3?#J(pnx_wQG?xuDr~x zibjr?tyaguXPR|6GjVM(2i`{YY^>jH_uh@SSN$Kp=}a%qrW?pS^Is0phc{kwb5XvM zBLX&{2rq{Fcf~-4h5K;{3;l0ig@NM8e#JEyrWZN0tedMof01j|@&Wrw##VTN!zO~Y z;5O53E<~=9P|fz&W1G(KJ;q=wSv&t{6Bq2ZmQ7SmW_7ybjCpK4@9s|nscsNci`mbw zyuS2#5qpAnlW1j}a@jDcVU@xKZm<}3SO4bw{J77Ue#B~^ix03kzvq!>;FI-F0`{G+ zntcn*R<%A$VW|qx%tn;^6QWG(c`suXl1haS8H?WPQarK7-I;_24(z-p5y0snk1hdh zw)`Q^)UMRy`VjN60^+wQ#&pvFvmTdiJ!_Edq`)lA>)$GiKG-tq{T6iQ+L|`GzKO$z zpgROQx1ZX-v=v^VA@0+CsNTa@g9kG5so04ZB&Q8rzUJg5)Wyb@BxA2v2{rd8zZ5mb zMvbr*_I?v4ezat>lSKX!lVKkYJ~sfnR{Su?@?L$<-P{(?!fn$gJ^MUF=N(%%At4YJ zruY&sm;*N~&R8nxp_mHbosy@&RNKC0Wptn-9Of(OGqU6prma5n+cdW1FR4J?=IQ-Va+uP7uSpS!^=dlCY#$0DkNHyOOFokRayl&YZTouTQ+pm#!kqIs64WCm+%G;oCfBK`$8Sk7sD`ow z+ng404uH3qSMwI;e4csTHsoh~-vd4R`c}}QLN;PY=d8Tk!%x;SClW#>Mtd8Z+&()R#ZlceeWgH5gQwf6UT~pz$&Ll5KNwH>h zsaZOKg|f+rP&cNW7}MG3!5RZ`ELw$xdk`pvE9gX~^FrrYEOHsp;J1x1GI_njCsjp`7=rSCeXXpMkyip|B z+d)CnvomoUD0^~TY`Yu&NyO9A?YmQ6fkF#b|#UyrttgVIm{O zkg1`?bmKQe!{Kq=P*8&1+l|ZjSCR&!>O-2XH9d(D@U-`@v`Z+1ZdPd!@BD&?nY;$; z8{OOsKR~3uSpixJLt^7uv`z@W7stu6HqypE4c!FY3tQ5OCeL=TfTD&G*3uOToq_cJ z%tl7PiApB9tM=DzrYo+2o3}Yf7w&%6)nL##HHQv6#&e@6aD$gAC}d7zjAh_rr%M|F z;qBWyrtm7Ed(?I7Cq7kHrp42OaL<$Do^k*Z+WUz%aBe5a(>2n~TlkgH8;W9FT&{Qv z+1#fnn9L^|Ia1fBMH#k1TG71%ubmmYkP_utxo9$0r^2id?HD1kK=devEXwd_<)ij{ zCo2lJ$}l^($*(@T50CRhKExp4cxKE&mhcae17V9t&t~)lpEB~-0O!Adw1ZqlWp`%6 z+@vQ6c#~hhjKO7u^sl&ji?6Nux~LFiPzGRJpZ!1^jU4A9mveT`>D$vWQVl)+6GPMA zA9h-)h8qa0KckmRaZkd`tCR}}6*&IsuIi1~)lV<8zWF^YEa@x8%N@qRxPhl-{oq!6 z)U)F_<`5#nmxREX`of>b2z%Se8Qr|H!8lCN+Y0K4ttZI2J{EY$nhT<>AaEH*&U~&_ zsJCT5*xrPO@n8QkuPN+7{u6A(_bn3aTLn3IqiiyAw4Xrj@|66QZBmD>HJ9V-T3jcR zDEvA6X`$*v=vx$`Zdl`|mQ{ikB%GGF(x!m8zNcD8(DPco;(VHP2xBS1gwI!~rbLkM zVX>p_XQZTs*X6udrlUoMK`TlG)6W^a`3ikm9P&l8Zbpk~E{vYNJ$|x=3FIq z>)kmT$m58`Zw8~PhF_w+zWXL7f=uUw(ZK}8p^l6*?Td^4SV+u7OI_S)lQ%rm-F()7UKX;6qpi718k9my~l9(57`ui6g-4FEL_>K+M zfjZqyP&?O5BDzrL%5F-%=s}uJ^-Ix@tRK}#x%s%%rYxczNCZ7|q8UC@@+)xUvaGT2 z|Ga^$orZbiOAQq(y{!0@uA1Sq&S-xcbMSIZxiQOXYPA|N?j^zj0$Z(o{HDyd4#!y( zwYrP?Iv6*HEOdh{tS;>M#2QF0Y!Lyy=9|8%!@Wg7(%KE$7)^9)+i$-(m%qI`HCTsC zqxVE7zna-Ey~zo>$u7wLgt3uMg+0+#dY$mK=ic<_Msk?;y%s)QQA-TvUT}Ck z%bJn}o8y%*Rg1+El%DqQc%$)z&!{nCquWvZm;zNZYF9H&u3in|gO6^pek&NWTe60< z16A9#R`LUMhp4uoy|hq$tYgaoz+X`im;7;jR4R9FA-ru2{w zjV#6!U&3O4|24=eb%(i#o9Dc4?#TpKK{bxZjCY6{E!^`U6O+!O9GF^%A*SFTH(vDv ztG9E*r4$JSQj7*WE(4p}SQvZq0ldS+plUfexHqlE_McKhv|-SK)Dx%Zks`eX!s^@c zMw-R9GRps8@SY^LlpqC{JFuK2)vB>J!Z%Ehqb~P?{`-_k#3lbuA-|QBv1NDLxk!z4 z1I-}`kgvCa3uaP@QRLI}t^I}e({Q`oDGjdOZ)aelx1L!<>R7_%v1gnm*bIselXb&; zIU#8vHS`lbivBIyC6oSP>VMgj>e zKOVfYki#hOD*7yX6qKB*$vG}9re;(t+yQ0PzHSSA{bM>|oyH@6@boZImDT6VI|Fkc`^ElS zi(b3yv8B_Jhrnu^H<>D~+<`%!{9}xli$i053mNL*iUdIz9PFDh3H9p7}j4|;;Zrjb4mk`a6 zOTq;u0xn9xTI@;>)Sn1a&zS^d_?|2n%(UN+>OfGVnt$%$aqz8F!Y zNXitkZ!G7|CYAp4La&kf7q+~6br+bgUYR4NIwT8eC%`J?J{t^gX0$?(~WIQ(BwQp-{Enw7_FB`_!1xok&6LS=m;+QLI zcwcpcv-p}Y!zaeNO2#uVpl)WuvRc8ciPsGLIq@Sk!nHy9F{(*O6Kr~(W}THkCXK$z zPeAq0-o-uo(D+HfPCZj-R)yCbm76Z&_$%QiIx}!+4)Lve$ctPFb=40!yab)s$UgmI zX<&xDEMFYXzgRGr(pzysW*yu^kp;~sUxx+7IUTe3n_3Oq9X>Dm78qfX95+lhypi1M z1$IV$l50;BSvS^z9z5`4LG>|AHaIxt&yOh=_|#239oTb*_KOUl>%i-Nl;!v2MR-=4;;*&Axs)irB7dPqCc| ztm5`>g|fohatP7w6YuecMV2O|=km6iXH#iW29t6Cp@Fre_YU)u4|SF#j;V`>G#<7$ z&2`~L3qL~NXGGWDK$ZFg;a$6s&9t}?HTvJqIP^6Bu>0MTO&On533MiqXBid+mNH+t zud>e+=>hSxHRd(T76N+OOn&1bDU$otq{xbjn2Lw z%D^0}@$9jgdm1yhg@(H?fdbi5F}Qc(hqiQ%Z6(qwl^Vd2&3x>2zcO`XP`fAi0objT|n=pFX-;@ z^TDC{?Vr2RZG+Do2{Me|4VbuPE_bapl>qS znZR(Ill{A*qJi8Q7;4Su-dA(;?oaFSQHdwfrlb+ zL5Ut;zLd6{_*4AF-DpjdR2$4V1HmcpxlP#hK3+#0PD`G)mc=4_a!X1dDlRPlg^&Fl z9ddEUO2>;Vc@j`iyO-?%YOZ@p1LX!~%r-14a>;FP!GPm05}AYDb~g9H?We*Wr)gxe zTMvx-lYQ%hZw0{J>(Vf@igabtUCUQpT2JyHDsqG259>a3b7`+-7CE)vdJzc@ouJs& z#@**%&6d}-jI<8+0|QpQeha%tln@W)jt8P%U((F1&Q=C~`BN~8?gqb5f1;W+Z-2T% zvpACI)ONe7Rz_wcjo}T5A?~h}sK-xQ*(a#vjS25RsB>8UuEUa`A!Iyq>}d%f8f!bp zS6xCPfkunJB7jXL9DtIFig%h)0g`DbsZtG@?ahNf%GvHGEp2THwMc6T+t@})sT%5% zs;WHtaQ4Ph>W=`-hozsskzL-pqXXhf{Z0bkuY4Ik_0K>q(?fqfc40rLH$E|FSVj>* zeG9ZK(oj$8>@q$lH_)sGVc&S!lVh)G8WmqqJTZ_#bw@*fxoo{1sZlfAo}s-gF-IKS zA8?}+7JWkJZq0nyZQBxjOwF9bo2}Y?oC;yl?kDZAx7S(DD7ChmMM+}8p+Lu9CmwSM zoM4Ido;;5|m|$SnBVn&1!{$`$T5;0L8G1o(?kwL+^<=Gf9HI-qBLUHpWxmah&>L-T z|ARM>jeLYQB`U#bIf>PO8ShQ-Pc}pmmgla3-lD$PP?v1DpIWgtqa&ZJFeV(PTk%xG zFVJm6J|~;8vTFT|jE5ePitTAXo48n}-0!rVR~BRJM&_;XNU3l^vJ6s?QE) zIlAIiv!(M^)5YoO;&yZ>ALsN+;M=~smYML)E}hkJf0s?I!w{257__#lH^&N7m8 z62YmE#RW~MH{6j^jJSUjm-%6G?Boo@)`u|2R@r$M<2{VHSIzOsH{4XFqFZ%1%r%# zar0@gy?BWXXea7U4j+7KMt5^N9+&|y{md5byQe94IOojPPYa!PMcoc3$?7OXknQA$ zg$13RqizK$)@5-reSWaiqWSp%6|60w2@a#R;aba2iB?1(F%*KX!r|tviCOvjX;q`f z%KbPxzpYI-of}4%!dvmgBnICECzCtr+e_ezTEZFnPIM;D*2OW z713FR)kwn7pTW;9%N@<1_H4W|B+||wJ?;w^~8!O23ern+4x$qli+4s-1 zzJHme)6fP%&YiA7pvG5i7n8=>UD8n4ukcfDTQ{wG4^zzhgfhM{|w=RU?CTyskLS%##V26gc<>MUC3t>==VidsJDmy|SIl z>)S<_Pwy>P1%I|8)pF}Z9(Bv@&nhvXxt4mAanah|Wk|2M?V)}{>MY_xZg7)=p5AAf z3G`wL=xAwKQ5NCR=YLpgA6T+8lC{62FGFH+5@|Tj<0gsR5=<7?EWK%?5i150WtS|r z9a%%)C2+;S%H3`Z>3nxG(!BAr+k`KNIseH9noo!p-*ApX%?_UW)6l)1mmsX%ej8(P z>b>qYuHNVf-;+HLyQIFD^fIWu{`f` zcC!Q2o5s=Wz22jd`Q$<0O(aUr9Ww+Gy1 zM)|JQA@HRA@Wb`2G0FAQIH|xIGFi}U(M*x13|DU2Fvugx_j;ybhWXM{pANZKM)XFXoefwI228D(IF0SLb0aS*<1?$!Fi|9pAst;Qjmw&`f=^t%Ug{@jb$@kY4* zX|cX@bZMQCV1E~=P)wz5NTFkEavKAZu4$ou&S~kgXldw<)v1_*urTQbuP6xvBjbqW ztIgjD5fk4P2PxKoei!wLHDpdYnf@!wJyDy}SM&)qBhS!|ewKHWDdPhMmz>bpv-9A9 z@HABl96zw4hsVvul-8#eeND03n~4$&%fsr|Zz|t^73cnuh2RxM>$JQNEyCj)QYzaJ zxwmyx&y)~eIz2kly@IB6t((m(riZwve?Vdl&a|ag)FHQ$Qaevg5-fZw*CpG8_~L+UD#UNzJu=jT#^32qUP=aBAhwE#1@&bz31$5BnywO)kTC*e+?^G?TM+kfRjiUIvgq~TZRW|YW)N@K1p#{-$Y{9oGQMC z!@~O@7Sy!&RKn!dSFzm#TNY)5!W@1k>hde;xV1y+R(V^Yg{bfm?lH2zib`w|!9+ct6qzGu*3| z-TkSyj=Ef($I?gHGSo4_UsX4)ts%bN-9*0^&oO9iYMoJwJtLw_NAvzQ6|^hO9MJ`H z6S?m^xiG^aZqL*GT%1tJthBT4( zmg`8dy1U$#XjBHd6@36Dm&tX!26;3IAI571QYXh1N*&LlF2n~LjZ54E!mvZ~u z{==bx=OgvPl&AoTP-k?*V14St$oUzslX;#Qn~b|PA$QjGZ0gX`=&}8in0>_#nNeB~ zk=m!j$rW!K`yFdZKDF-?K#@sCO>XLaqw*QDJ{MxpI|>JqR}oC!=}xoKTEPv`_so%e zscq|bEwz4)noM4)5~r%GB3TvnDFhCHsR^yB%Ce{4tE@5fckat3vSKh={PWaL=zyXJMMJruJtUg-I=>GI;sAup^Xg4zFNijL|I z6DA>rm10b(6Xm#+@x~SSp6{o%~&))+N`O^T`2;e_rQ%cf30I3p1_(j`bGRowL0DyNhC zNXDb9=T9?I4K!P^BIk$8al@XLZT$9n^4wKSlTs!dEy~k{p@P1$b6oooq6|fJ5@(dZ zKPv2t0Zuu?@HGV^n5r>Dh{q7i4FSU=A)pm>q()%>cF90_f+ND14xtOaI3^kAq|Q1C zoBBYuCHib)VWA*aX5+G1hGg-L1u0f6>X+tYQ1)VVxPJShkgr-z^Ir*U&{!R6^UQ<6REXNT3I8n(yw+zn ztucSZks#kuN=kYRHg^W2#NJw4bxC&h3rxm3*B)4S7u~jc09Y)35Eet%HuBssIFx>y zRbkRkaHH+R?}-6pIOv^u905?`13I6Ib4+Ge*Q1A$AazEkuVz7#`?G?g_JDtDfojQ^ z*#)%Rw3P@rK6gmDF3bBf3T&-f0=h7vw?+b!EZp{X)Fy9@jfw=nXi}Rw#YiV>b9l0x8BlI3DzKLtetrZaP z*yq?*cL`Gvmy&+}m*z%pqE{C6_3oqrRCsKCTJV@B;-}#cy5r`h*hQGENs!Fhgol~l zHyLuMxoErW#TAZDYoC#Sn81vx5!zLuOxI7;gJ~>s(D+RrsyavyYbleoh$VMWB=HZqZOR=K=af>rGou}+?7oSW(O67B#!M+|m- zCf7lrE`gfoJ0NZPUEd)j;2XXeG`RE8EtG-#(Ahr4w1Pg|yZvEkg!lxVO6vI6-z_en zQz!5!a=WFH56C?==Bf}Dx6A1K&vUJO($;GGL!76s`X=(n+3)-Oc%wF9c^s{IdSjz* z0~r>gP(mM|Q&j1GE!@j8%9bYgM-Z*0^5Vn#=}51Va4SjktA9j_DBcdq2A;F|eP5ac za-Mzs;Ov?CeJ0t8Z0f4a$)P1*06^5n-;jtm^EtuIzH_UWOr|(3l?$24t>yHNi3{dE5*7u$6jeeyP zemiXA1=XfT!InVe;p~iytFzha9^=hkh)pa_gS6}<>6aDz`ehxClN;}(H_Hvo0#)bQ z)(f9~c@+K1y`1J~3vzp{>ft|agYN8G>pU;nn4LY|;+D*w#?{KZ4Kmz@4t6Eo^j<@d676MgV<5D3^(O-vs^K+G4M7i$Fc@YkB za7$V}r)x(mla^`=cU|9YUeojn^F+mgeP&e@gMI2nU6Ig}FCyWH(T8-_e$CEEPF4NA zYE{skqZ?_nbnYq|xvrFzE!FF{<3mAojrps!Rx9ed<6F&wOK$mrE(;xNzaFaE^^FV? zIl67gEtT)}(m}u6=ynFJ)y?gco%&BPq;_V~)C|eLB?1CdA=vwv0Wf5vtoD@e>ZnC} zUeAL{5@;Xl69?QPfVQJ}YDV(8Jl8Z$pK;Vj+$a;G=6EjPq3p)kf~bqzbB&PjD~F}? zQZxk8IyuNJ;_&-!#kp$A7QR7HQ6sIij2wrQ(wTWHs27ZF{y@v*4gaR6o5F)i7@rD# zkEsj1Zvnd2TSxYGg2j&+vp)~`XGz3p`Z*+9+2xNUK&(%FEOtIK!t5oNJc$iKEq{K{ zS?#2bjD8X$Z$S>lLcS|)hbMLPk7LMDET2EEGDC+O0@@DwY|jVU&cC*NNm}s&XEZGI zgAwDWUovK9W-RX>>AKWCP`3U7`TxBDB#zFI9^Noh^z6Eas7a+l6&Q+!YEGw&x4bcx zBL??px9S-LcWoa)kdtM;^312ju_NcyeWeOyE6OQgmyN%Rg3G5>@C@H8$apCP!?lK8 zj^KJe?R$5^@efu0#-PfLF|!tiH<#w>30S|M&C;YuS3CR>D&;e3?738e1a=x`-=RhVyQaG4sh-ADinbEtlX4N~O{TX-7mbL7q zdT+~N7xEm4_P4d-w$h4D(wQ@XL7HzeoS#pulk=gzg&cmGh?N}U7!4F{YA`EN$g)L@ z{28?nxJ)NP!eqybp=N^8E&iJu{OJe-b*z2 z_!9W>M*YN8hDZ~ zFvQ@X1nD7Bh45@of6$=_XLvT12BMg&Pp{`>&;{IV0QvSUy{3#ZK_C9zn{sE zuufblHIFIXjGr^xD@=LHBtG@U_ z*??vVyOxSSf^hLY2{DOij05xf*bq;^!g%|pG0-U;bTfs%d=3W|z;8!(k{k^1USd$~+xO9!e49@ES|QhtJ9gmzm`lxpOI5^%HOTGT+QUGq4r8s64@9g(n>XDt)^{YdjCu~sgE%Gw30Pi^rdm4KMkAs6J?uknI|Z!L(}+~@sG{T81B{NRRjuKx{@{&1*2 zPImpQ+VOr4$UF3H+N!iqQ5mrmCazOD=T= zWt@ChdT_s$;t93e_3TxRxyhbWY5rta|2@ou6PAwj3usFJuRha9ndQ;%{1!ryZR-C% zyufsS5dU{)e3BG(2F70EPkXS&A2ou%-evHwT>aZ4tm>;dFS;+s&Hby*-{7;`vlrhn zY@iel&nOW#@*gqSg~cnlAv53JIBhgAT;F{^LQ(9W^V8u~&K?EfRAoHN1!gMbN*tS= zF@e&>ES+?ncyZqY%9V(4jaw8kkPqthOj95A?-FZSGI@0zXDKD62CXq{PuN2!IKD~a zXnvH$=ku?0-y3(J6`D{QA}}*c&)x}q=>4Q>`diGqe)jm?sGo)xgsD=D&gO9ML5Q|b z&`V_ud_%WcytDSRhzSpIT4IK@yec$-YQOK%(#1t`|ox6EQUp&Bkk&2;2 zLBqdpVO>l-Y!NI>6CW7w?5RKUoF3@e?cWt2%!Ux?{h`BY{nJH(Y2CrWhN;%SRay&G z-`c3jQ1iKJunj134zxIJ`2dP*v|_LK>=3Ph*rT$aLTC%*KSyJpUL8<(VX+;G`4#Mw z!iMl$lW~9GNGN|hOPR-CSQuBI87{gf{p(|Gjg79OjWAw-YO$Q@zsmS0QrJL8VTkOZ z@16Y&IEQyj=O)q0e>@7!pAFQFkdWWTlpLPB1=L)aZ2vpHV4sZt9$x)4$20AbHa~q1 zT0&-MRlK%RBB%HMg*JazN+Y{=d?BSI;eU-Z&@2|bJ9T0HC^Fa2{xwz%KKG;L`syCE zE%r{tr2(I@WG$ZBQ^}akRv9o?s$nW4Wcc~C9Z&%-5&9Fu-Q#O_L5uUHx~hI^qwM#n zx#T4)d{4dpmtKJD=A|Tm15Vs*%I5!A0_r>mE?Ym5|UvH0Js`Tj?%Ja=Z=hr*ocM3n!nA z)5^@`zgdpJrT8aT%*^Tu*Q4V*l+i#Pcl&tm$0;b9FaLGr6aUuNW{JyIiY%B)Mznd2 z4a&X4gapNGg(oh=S@f^8KAUoW*(xBjo1qt%Z+s$I&mFVifyYpHB0Xk7l6!f~Jv}zG zLI10sUkc}&=^uTd)oC#kw)-N0#y8wxtk)LClAafOr9Qto5zclorM>o>*}*p)I&F*a zBB>xRo|F@EjQzq0hTKSBvHV|M<;m>p%TuKujq#$<(8WRjppr7l!ubd>O?u}AW@XwY^R_+ARl@A8=$bvqU2Wnfu1b=h)Sp@q2*#I$fFm%1uH z*gLvWEUTz6Es$vTqoQlS6Vc_u8y0fQZ#sg$>|QGHowC}SO?F3@JCFUEN0Y+XS&X?t_H z#z@ooy(0TNJ%b`q{j>7Wk&30o>EF5P?b{}2JvvpT;nB&iFCE1`4|!uE9YJ9QUG!fi z9aHJ%RaHJno=a90XnVSLH&;I1;G2%r>-Q#J-E9X~I&tqt*(12JK%1lF9NTI1ejo?# zI=aV6a)5GSD)K2J;apt1059qhHR($Wf?S^M*xlJDvm+*l>)d@u8yj_=eNfmSXAMQP&F=2XjB9Y?ct)=xF!!ei2hvyfv4Mh;!wl?a2c{)&A4Q zLx|noRg~Sh^u}>sPCZwR;M_37C@MVz^fb4*_ZEK_;_JQ_)NYm!_}@J6-!ogP_!vU)hg@Pwo~x9(7+q#=rr z&$Qhr;JjROQtm^O??s7$w#a&aS(`>zxugA|CsIn8slH*+^+vbK?sEz^CiOPAHIb*E zzkkwPrqE&DB5ap>iaY(rScfoNn1u1J?@yUlqVNxWQR--zh$774wmnyL)mM`Q6#;B+ zNUzE3ZNzlm$~q`C27al1$_HuIB0(two4|`7b~x&M+@qV1Vsi~ zblF}c3T^^TTLFXK2x3QSzo~U1+tn}V*PZr6H>Vta z&l@Ee50te734iMA35%A)np|-l{rU?){Ie=>aAU?qfci7#+%|>dvg;h?mKY@US{`1M z*^amUOxC0bb={#u{(9xr!$T;+0<`r`oMuEEwjCVkM%c&fAOzpi6f zBtDf{y4O&NT3TtJyLmbIeWJWR4TPEat9uH8yp_J`8Ggu)FqTg|bKNB`0kdNuJU}Mk z%R}3TI0t#W$;qx)6FKSPB0ixxFD{<8KXYWhx_L{B;$>xj^gE0kyfe&me@nN@R+AKu zNki9T(LJ39D1z*1qhuCaLvtUGb~}gSxe(bQf#c@QBin-&*ha{yG)y{{P5De20pBE> zWccAl+gf$A=>CHA#&m0IJ2GD~L zZdj%6Mp7yQBNP@n@udNmVRYucOKSQK{zXwUcAXLREA7%lm8I3~l4eDMeY7anL(q56 z%K(p(x)%UHw^Lckx~GP{*v4PUU-(Paq@+j5_fjEn7RxDHmbz)q*OjvkpsAFiDNU%p z`?@vI7@dYLDQTVWW9kw5sVf+n%s7y{jyT8> z?G)ZlgV*_q=9X+vz6h3;Z(?HU%{8W$4jXNo7fKvK7sF^)K!86yt316N#VVX3^!>D= zQ;xOJuFUq5k4lUu99w82O~S*!YqP$#eqRU|REU|K)1QxXv!qUfHmQ!`u})3%Ydk!H{LI>z|tikB_Ju?Ahnc) zltFh%hk$e}DI(HJh@^xxNJ}Fj-Q6rmcP%Wt+~e-Kc`a|aZ3^)^880G787nD;<7Lr5 zCC^S;z03ksioU9_e+DQQM3;5=!c9)IE>jM7HhDZATmec~b1wBGG6xCqyBHsu2TDb- z4hq}Nf>K8oytdQ**{$Bb{{H$6(Gxc@H;0$a2QA^r+mwRXurv{uxhliq%w!{jsQJ?7 zc6mmdg}e64EAq>Ob2neppJnF}@gxWP<@9)>qrjOSX^3I;_BjErJc|R_3C25}$9}wT zgZ6f3={a-Oabjsjm--bWhJ9x$SMwramENw6yXLp_S+>tOelrk><7krZ{P}&oURKui zrF5nQ7md>BdfEruVB$b6ox44C7Y@^UJH-j}WUk@Ei7d2rfYBn}a=ecttD$yrS)6WJ zzSfYAeKmWJLg!0YeuBrzsA^^kjg=5I3tMSE^3y0cW^~KO2AamxqBVj3 zJJDB>bmA_Wx+XJk0Bbz@XN@dZ^5l0`c<=9@is{%EMLG;zKL6^0oe4WqliZ9fFZ`=S zJqIlpVc36`rtqG9w@UHqjBCcPDluYkC~=e7ZX;s6?eZ066@g~Eq+6Q{5#Q3*PIue8 ztjkZnN1JiulD}_-@i=+@VgehIdP$*VMRYGpv6*DSuZTwS-Tk-ACU_k+n~!YK@JQl0 z7q5x@5mbJ%58t@7)+c-a9G@|2g0)rQ4fpVfKbgoP&l1a#-daaR>-QSD}73^e)9=Zm%8}S{1COm63E;wm@EKdHvQ* zsYiaAl+9X88I~q_-E>krsV|;tpyBLI^;eYCPC2e~CA+faw_3)fSy4}8z;Ru2`c}78 z@j0E?JArcdw7hesJL^P22%olo0_sWJ_;=-VsXzbJ%lhqpz!co#g;7ly()u1>4RWyYcHuXl(qV9G#7f&wx>3$HbguW7PioEwJQQ z!4m&?xwZ>75|QBVpcZeW_!p<}WObVEbtPXl6|0yic*^zlp!rE7GCSU>dE`lQ-?-Ik zWB(_-W8e!<#&ZI88_Gdo2wax7ZZ;Z&p*+*?z0r8^QAiFXTI+z2mhy39zWFi9{?* z=Cu)htwi5NiP%NQ%^*xeI7nHeihK2oeK3t&0@cmB2VE5?jn=z#?VN7ddUcunFhQ1 zFvHjUzqVI6rc|876Ek@C4eug-t$^9a1F9dt(e)$s87 z4U;lMIq$i79H3)?;kaLBgS6EB49EI+EdkK5w*Z4tf? z;zclejAgaia-UeXTdX7VEwgbAL}U;NZ|p{6eAWvv!tN88HTQ-_gTqSMB6$!2f_fD# z{=+z;mVtpK>F4JR3Z9~F*H8B@#i^fau6p;uk|bN6N@;lxkXef7v^=u9t&RQ_hJa+Gia#X_4}o$7Cb<3tZ;i&FyO!)&7>6;eV;NRw*IT2P8{7^80At^ey%(8=Vxv z4#siE9&u4@U@P-byh(g1^8`OKzW-j>{c_jU=D~1n*5BN>mP9Sh!MT%fafup!Y-x1$ z#cUq}`&nnR05(K8?sbM5R#Prp300D^$96yS<-$+16sd11{dh4zNe|sG$v0c1ez)_p zm)0GOP~v1Q^aYu};IW-H^u2~3`WZpP(F^2JO^pBH<+BBw?H?=~lcnPG&2s=~XMgzT zkauCCIJ15KHor+pO=-XFBXs`qJM`1+LL$Qz{n0U*bR>4;{#MfaDBQ8S*;V!CTkm~| zp`@!tA8Ova-&YS7?uRoPirF@643F)qdVYTCQ84i-I>Vr%g(7NQ?dCnyGf2!w4XiD^ zoxN-xceCqg%eq(wA#wwrIQwIH7Pwny>^}0Ime}tdIN8qpGNVBYrEU9NujN!NqXG2P zIhT->sEWuMY~Mlz1*l6*zz8=mB+WgaJ2Sp!&Fzd~t?L4B;gJ4Fcs<>=!IZaB!nmP+ zcLV+@bIgtD5pn0e`gWE^29!K+m3|B~knOHvLt-IWrd-B%@dt^ES6NxdnZvx8E5SbL?^r zL7LwDlj^Ur>fSG^H`kV7dRkKlSEaRPJQk}6b82i~J##x`!`N~?7D=JP1NZ?%R*jjD z7OhE#!sJ?8qq~@96&op<%mY%W>=~-=T_x$ZEyk%QhZ|5C-z6h*h|N*1w|6u%2jRx{ zZe8pq$fK01N(`#nb=sr*#cr?dgYF{4qvI1rigql>UUFI)Km9X4bNxLpt;9Zs4z+pG12$6 zlFkh%obJgE%ro03{fku02gx)p2lWt}_uA`<; zzt{)Lx~MwK=)*hzIF;K^(7w_x(n*Y8o5Vys*;`BY^lilvUDs@@U#6K=2`_Jo3zsB& z+;@!p&Jbgxoy?oD-CAQe&yNft?zB|3on}|i+Fc?NP{OL3F!-%zAGnh-xSAQk=-ctg zvB8vwmo_Ui5;l`>IsVn*_s4l+Le=-gE)&Dm93SiJiDl9nZ|ZR!#sm!+f@}iCA}fve z)*pK8H^oscb0nbDs+*TH?f(*inPF!?xauaZ(BUnu-XCC|1)sG#Y@|)k$ zeD?D>CMWO{$q@+@Tmw_P|`@!%IXf`y2?KB>X=R_A~nb^Lc+sAflbaYt1ke^~~ zydD(XPf;{M_@1^rBSQ-ZQlG!_C792oy0Cg%1-gpA=pArr zbs8qSmS?>8o5NyyQQHw0A#|ha){Wq>lXyi{QUM^U=bC5PBmDBmiD4fdyX?0)&chE1-ft?vX+pi)Al#Cj{!)Ez(6^R)R?aji}0RYMci~lyi=y~24R^W zmPAI1;SHd;p9IFKmf>ALoAo~2}{*2HxK@Drvu&{dyr^i|(Zp*EXFii{iI;mcC-9^8>RduYgv$~YQjbSyOd*EI`4b;W7b2(I({ToJ0WlekJeG>KUDObSnT5C>+ z(?v-ZNmYxi1SDnMHHYC{? zl>HcBV>DEc7UuPAF0v14jithh+FdkJAULiDng6hWe8xTp0@YRRBn}3oWB)P`E6@lu zDSG_n$;%d18+SYY1nE5xnn617 zqIN%ow+l}NW#cT|?lVV1#V-B5)B+1*aS2=)u7*PN;Yq17m>__4Fx+!#p56Nb;d=#p z?xDQ(FBa;%>ctH3R+2w>_HXns?MqD_bp~d6?Bp;V9zT19_ocm|L|@aDeK^0FuONzq z4}4(={rC+a2eM&KxA4E;U+ipXz`=4ESapl5v#4aia?qE_w{+tAER5-@(A1LIFOi>3*pk$`C(&L_wE1Y#2n zWD|HW_WSmNPR~a(pFvk#-Ax=S@;($^kSKYWe?EVS*zv5^96bt z0?r&1Iq$HdHhdMD2;?o+$RuoLjmld&aE(gZ#B$m><}Sj$#l@BvEdy0uaze$N8><(^ z?ClnOwK-)lZH6hnr#~l{x|kj;c@Jbv{4>u4p8ZR2Yy=9P3JBjbUZ;>MD^mka28!q8chCj;ml=QbZ_?J~MIG$}tKULp!c3G&IcdRv z{8EhWEFa={I?i+_uykiEAa6GLsE6#R$gO4}f zzk2r02LGH;BYO;-Q$4c@J|6m~&xmo%branmEx>kU6&GNnxwz7RMPE>dn)s*r;+ zt)i2ab&I(c>?3yj8yphzTJy++!RiWRJ(EKwKzCyfIcbPgT7FE zC!geDQ!4yT_t|))mUF7V6GbD4pIaAU2!NAT^VWFG5kPq-HC zRGfG_1}-h@(oFm}nxClb9S*NLZVAjke^xE1#`XN-Z}P8-QigRn7()785z)9Gub4#n zFWt4NpQ$aIwdB9*ad%-O#;rczXwEP)%BtZP`ieVnW7yTDJ_PxGe^l+e;)2q;+JH*m z$zFiWo^`F5g>d?<00t{*nX7n1?^KRI5G@XqV`H|^4tu&9PgMv35$5U7p;1t=#jm#N zh!OiL8K+mOv2-tib7eW`o&MDPIK%#KFXrw8$ww|1qdOdTJ%)efF{qqgzsKW9@qfI2 ztd8(4Zr5tM4^|3!8ZB(+L?8jI@+q5*Z}Edxg;xZ=v41-$hoq6Z`;UFv(yt^_&z}p` z4pD9F2}^f#O=yJ?&&N{Ty_!?z!xQ8TiEW>*nfOPf2|XL%q)`RB{cXS-8km9wW(ITL z+lhQHXq048*~W5M4ya3mRl+@>XLKfV^TZF2Rugp-q}qy7b7?BQ&-g4P+&LGgVn6M`&Id&?>ln13;0KPL4{~x zQRsT84apfPIP4e(5u9e0({>bXendr-AvW^s=N$x-GNdE;ZS4MA;*VqE?k5#qwH7Nv zD7-{oC>2I{RmaM{l%ngC*AYV=7RQXl91BPvZ*Q#hvSP0cTUEU69(z-Hh4)`9HkEtq#>s2uVk7D zZ#aEs)x3uD_`{AB+;}F;) zCY2Wv` ztHavIlB?aX;~xcnVYo06p7cqxYoY@9J{D zy{%irP8>@HfNtLva6TqiEs`EfpPS{Jw^$)|$LR6@koHwlY@FEdD&KMXMbt!^|Hl~& z!ouOM!nk7c&UTyCUrWBSWNBk21=#nIj29(wd{u-6#LLSIJ*kyI`a9YoP+dxE1V9w= zQmLdBaAbWJZ*@S;fP-lZb$_JkcBqY^>F#DqqC!EGmKEf=K@dg`CQ#IgJ5dC%W;D#e za9PrDT3!{l7EY^mOW`a@_>e=Iz6&V&&^uhqySjao{+J@hP_L3%zw5@)`3C>y5)c)+ z(LoLs>l%OvD+A)&R|<%;i&U^|DS@CJWlRV8*;-9pi=`!w#cESsTsw?{G|;Y8{QafX zTCsI$e`JNB(J%KbpqcNxZI$GuAS3ZAON56xx6 zVA|SCbx%w@Hw>F84l{=OMmblSTDfPI(|3eK9Y9{JsqROBpHWJ@H^Ni)mR}9~9TaaqT6IO^07bf@2`)QBG zg6#@n$0<@HmhkjyiOUk;d zUkNKmMU7ReVARUSd?VZ!l*@Y+b>s7S?)7I|oQQaee1Lv(U%|=-2vh*4y@c#h@2^S+ z=y1Dv^Is+q1GosDiR}>f!(4u0*|I7jp0w=-u@*SM1r1}b=`+bu{ZMXT-NY^(s7;Ot zWy<}+x$~Kk_)IA*gc0*3q>g?S97Nz*s8gD#80N3}>9?sf-}%AfmW+C@_f4zKcWq$| z-@UK|wrh%CGf)WPj(?<2ZKp_M9ezazj3fd2%%S!Z;DNZd4xu;TL8wVJw!1}BJ}*Ld z=2eDxAFBSzcAlvW=6o~ZSP2r$+gqMze&_)rGNPRDyr9&KgV?qUP>4o|zzzE0Fc<(; ze2D~dF!O94w<3YPEcyW!XEdaewZ;^h@V51_%(u*G)wy~f=~;@dW*Bm-_{)JSKh zm=q!J&THIm%yt^8jT@Yn;dM>7hhiMQr0J~M1EC(7O@Fo7x z;QM=$I2eV=?C@KO_9X?#U)SX9ii)McJFJZI3?r+>MRL=Kt^<_-WVH-BO&IikEIu8e zDpx=S{;waE2DqZL_L~{;8Km1%S~Ws;hje%9W*jBX!8VH zBK~*&NZ4N9q#SN%?z|yWoQx#%?PH#R_3W&d4D$7;7`=<6?WDA?8o{W(WT@xADvJ}9 zoKT!UQAx;dajI(zvcv^H|5ydHCi2B-E9QhkI9aS7?Ul~tCgmUM1X;to?h zRAyOzir_@l7bNGma1a#{5EE|=0=2pDoKxa>&z zrtrH6*hH5i^X7E(&m6b+JQpnSaJ@cDJQN@`@dp!Hf!nW7fNFfinN6Zo<}#da)Mhkj z)njs0T1yskADo7ziz#ny^A*)GY{xOb-_XGE^$1~^=*pBMew!EhKrjsz#dMy$rac1t zK%r7vS}IBswM*iCSsE z6p_)*k-@z2H#82@0h*hQjTZ0{-r><0hECj84f?AQM7~?<7iEk153C0eAbE^mR%uXb zPTkqXcP&iQiQc;|+oltE(ZvMU&14t8;+!%I-U*{(jG9^fc^TEqD7~}+XT6xT01Bn9 zD&Sc=VJ6x>^vZv(*B*g#CfBsO@QQ`2MV`6;8^j~Uv8bw5MK3S= z?Q^gH>80f4k%r73sooS&xYEkPJ@I~4w-^EHzG5oZ+707zTJjN<30jnp6NuV#FPf&*zg`h%m2 zZ^Usi%XVkIQB%bhmi!sFI*B=qtYNW<4yVay>_JDGKmP~aqyS^StiQHnybtm^@9%h* z*gUrIYr!DMCFpa+eF)WMGzNuTg9gmEnmfrpBKLEu$A*W`DGJ1R7NhUX-m**wp!TUqC=^+It$@~Qxz z9O%@Ne>P_%RLGgJD4+E|JS$}s=niS^$uI4zpZez5TvxYz^3V6>Ah+|lWM^OhQq;tW?hqEp zLzO3RsoP-Vzj+hDj9i1)IVSu@-bmg+fPvP=5}a9?bPtC|21k(IG4EtxfmBW!2E*zL z84uG7l|Q>IetQ-Azu|rP0MZEd4+!WVwp;4qcpH*2T3@gAm0h!^go2Eq*gwjr!PzA~ zmSOhCjRgPgG#cIMCrF&rWbkpEFC0H6Fg>1y@O2g&f-YQlElsDYu-&n5&yFQ9ahZ3 zer*Y7&Di>e%6RN>_gGj(M{PrG-yYq*b?b5~S6CgkOzTU0-KvjM=o5q@MHMN!vu2le z4Zb!>#i-xi$9o9f1HPh5wm<(B3|>JVBmsR8(){a;VNa87uRdE?W-7k6SNVnuf?P6% zC=h~cn@Gw-i1l{<`YZhT4Vhz?=8Kc4fSNA8lOqpJR9 zQ(@U(XUT6|No)j4=iq`uRdo=JI6D7GFLI=+3QYHb(!1n-Lnq|u;lGA+D%+jz#Q&^J zL^*Cv`=^ZU`^3t_+r&bQke|4qrIafX%YQJ}|8HLD>y_dCBv6SvWX2Wxo7?-{yW76~ z;2fg{t!PnV2PGs1yPHGjGpzFVH)oS2Ee9y9_deM=S;2_)*-A4;rxLeU;Za1y9sAmv zL7L7w=RfQ}+rS7x28j5?ODK)`gaSyN==E#OKxvJ@Z||}FaXL0uRS6jF-u{EO15qdC zoP@w7f=%1$A)#OT?hDeB)>yUBrH4`W9S?4YCBVK^cg!srxW`9}>X>a!x%%P-?(bd( z5jU%@Pdzgo;QsudD91kp@5wfF>FiN0dU-jewSD$C$09Od`r~$|%u-3gzE!v*uef`; zv9a}Gxe=0)B^UZWvRwcbeX$YMf=-Z!4uf{WCE9uhtDE_~9ip;fC#PvOg5OV0C8o$J z{tZ%&@?$*Kg0nbcVAG2ga_^uefDMZ~2X)YcbAESNRRb7)NfP8vp-|CzP7B`z+6VXX zdV79T+XI4sw(&v_l2ATOHFJA?p_Dgv>*E#qUEt<4;Kkq&ZcGroJ0{3QJo^+=O0319 z(UoKYc6No83sqjYH+XGL0fwF3!0&$JnENO54}><4MqmJUd{%olMWDQxi#`{XCK!q+aoJ$#Zt4s3_p7U&B@ikGWrt3i4CY;LS@ikq^!!*l+wG zoMEyrgypeUUq7I{i00w57x@Fv#gUi8ghZ%xk*BF?2qhPA2v1H5FHZ)n)~#G;mb4!= zdF`*XEl*B*rrr zt4UDTBuTi_89a4tQb9~oSzY&Gw(m|vgTvd`X+?+7For&6Fv42Y<^FV3EG(16S}N}Q z7luBE^5{B@ALH&zVfnEC9(_V)5bqvXUhSHH6CY4q#pC~BCR>oi5w$BU`3)mP5l@S5 zvDmu%8^#}b5NFQPS2PpJB;ye1frnd16YYNw*uez1M7H1WkIHIXXT{c{-PxhTb4WVR zKlD$1^8x+7;q6Am?AQB_vA*lu@K$UA3b`7_=0$$xo5#xM0}^r4CGY5u!`upF^8h8q zGH|FTG_G>f^{b2V_ZyPh%Ql=p#|3}4LakB~clxkh8RK0KZZWtyf{%{-@2F^O_W~CEmX6L4NOOd{2Y)&7FZ>SpwCI zePYoM9!Yud(DzZRP`mI_-&0Y?SUx2XCv-Ux_*v9gLH$?GTM{%$;7wPhK?`pzg8PDv zhPg05%2BgaWx;)G1Xe9vf6>N1XC+>;f9F3gN`#2%yP4p6!YWp?5y|@XZwW%gO9i ztSyagU#3{VQ8hODmU)BS_<8N=|D88g@R97h&7!zRGU*(r@s6m{mOCYl;EkccyeqWH zf%=$DVp=Kcxc~C=Hv4u<&-}Ae6#rJxBCLDrZW0c(Z{j`%>4<#8<6H=bOFR&HSm{N7 z{KqX{_Vd4Kd=Pp`-?tnfWvmT7;7+;2H43;ksvzy~Aj4Eeq*suGPQp4ez_0&QZFAgg z6a0=QFj%9*$Efn*-8{ijqT_~qe!jJ|G&LpcM@ICY2J<^w%=2>sM&z(h>pdOcX?C`G zmjrF~WnZ|s&`mT2c%v%mnN`JA_Mtuc^$=ximo!59lRqa&E{FmjbOGvy=|MOx>G^jh z9z|8A09vnd*UWF*dQa;VBvbBGB&j#}BcQY@*dYms@UdjXA`OT%nC>;HYSHA49Owr* zSoN-Ym%8Qtvu90mQFe|nC{bIX1{l=X3`9fYoBy_x*=d}QN;HhC&O-dM#J|y?99EZ_ zU2>&Ma|AKOyIyjSXXuMx^<2u36x(`7aTJ1>_QB-8fB*hF zlrFr~I_tXE(T?P+6Er^^&vijiLZXw2_VE%96 zV^^KIL=AFGe|S92jmm*Xew0&Z77%YhT)PD>HwWudU4M*)x(R)GdZ0ZTCmTNI2npfO4&KTAek^@b z0lf{x(>s5;p-p%1-`&1a^C3XH`V#oyxVOhQi)L+mR?PQ^SNz8oVasT6-F@m&OYL*e zpHa)G^>TZ>R)W6~hoN4elm6af<4+q7ErbHE_9gi29m{~X$owQ%8V7d@ecFHfvy%)o zHzT9+r|q-4tot3p{p}5_OCV3EowTrUaztx8uSKw>B}Sro{IhnkQ0xxQJ#B=bw&vr^ z8o`V+g&&ITS8Nf~iRQg2Y4TN@>H_eK6K$YCg` zC3@Qammq<|AeUgvgU?)V9y$^38{kAL>uNx;d#s|je}8eulRD>1kBsaQ3VhfRPU1Zt zn-HAW%@7#0alD9#>CN`?R^;#Qmo&QH`UC43)b43$S4W$YkjmYkZgLkCV>8AWA(-83YdN?WA%$}FpJ-VN{rLLZ zKW}@8+^exuQKvdfG2eeOG~?VneENX!)2?6=^~5Nem5AbT(`*RBj!b`GPAu-C?@M(# z4j@;&LkLzqV1wLHZyb{c)pr_LN6QYXAp~W86%Yj2g^?$83HQ=q4Eu316J+q;)Rd2J zc#cGCYR+?uNd`w#5H%#wZYPxK#;A9ctlyvJja%-6ISKc-U5tGy-$YGgR23nAhOOw2 zJ0-GuB-*&6%MISqlZ4Eu0*cH=pitLGefn6?Xy~ZZ$GaNKPaun!)4n7WlWjUt!1WRD zvd?PJ)CGrcRYDl3)>;Hrt{mw(M9>PiE{0{j+0B5K z?NjI1{5rMh*1`HOvYa3RP38`KkUo>}It29Rh@nd&m>llQ*n1il2k%x72R5p2jNqly zg;uPFC5DFi-eI2&i6dake>b_Aov924QJrqd3o#(Oa&bQ4QXLz0X)=Rig8i~OE83&m z+SyAnqod1`<;*^`0a(O*M9*lGlCvKW)yY^!;JLB^5L^}%Fp4(%)+5+b6+ zlK|G+z?WfbH3J>Uc($W4wDBu#3=DR8Jbdgj+Obpm7_a*M#g#_A{`YN{#{kD*qZDhk&tT+c z%_pUH$*W;MRm9{j;Rk5nlg8nQlx+99!c~qto}xm=D0fr8g)_Ou(OTcD>Miydv{r=C zJ?E(%9iF?0vX;niw(mt{gOPGacQ2o=%{>7XFM=Z#< zTAhum8)I~I5F`XGM~bsNO|r{qJNmWXV(ivBofP1JZJ7hkWl{?bc|(fd5*>{vMF0v2 z_S~B)R&sOWM|Nm*Xyg@fgwKc4sQ+Px%rzEq5S%lcgF@bqq*PZ1qM7rfI3*(9M22N} zV~07u&az6Z!6nCGeJScmO68~kn6xAg1{d2>ROi?4s%DUO?UVT#4rC1Tymo<*!Jk1v zmtJo+qhRK{3D~!ElKrpD=m}hS?QYFAXZNc9A`+jlVfo{vphAZi4jkeB3EsBS>s<^- zd`z6C0G!h``p3Wv4s@7O-jMJ!ziZmlHDn`al{;|Zh4UKM&k6VT_71SHu!zZsi*IL2 zxIgZs!MsuzX6nVl!t!SCNOKwLf-868lf}fefjWdnzyjWOAoA#^wTmG6oW~Cuzryq% zt~I$Y+*wt75Y?Y5K4VHqYV<77vi@gEL}2^y)uGG}RI4uBv_UC}YcaOjH#aw@CBcy= zH6v^&zV!w#qB@lG%hFRjhoIRklS`fIOSk;X_^)?Wt8+{WAZ|fACMV2y^zqNs2`K-) z3QG>$7kjO+?{wgaXmJh8{X}NL+8>=(e3t^Bodh>k{~k&M9V!SW6Pl;N?r^ReYXS8L zpja|~HuJSgG7C*h%R=)F_`sh@!CmGAEEfL|g7%w8)7<$u2>fcoWV=^Z>8uO1XpWa-5?xi$#!Tg7)vnlhv~TBs z<{jGc#UW~>N0zpo>(GNqFtdm2y;zcQNYx$lf2;Kd`0y+5cgyCc?NAl8Q##`}d*0vb zC45`?L2{&PgHsD=b#B9lLw6Gs%)Ub>`q^6^o|cuA4VhC5`jFrzlkvUO=Oj5O@5OTC z5zNuj>CM!^OX|A?Ei1I|%D`y!u5t`uj5*k3AIOm}z8{kYUe|xO$@Z#9F<-a^XRicu zEd&?Nh9PRQZ53*|SFgNs>Qxx}oCL?o{|!y%-_Xz+3Xe@qTLLSd47X1X$FeIs*>Eku z#4-h`H7x%h3qXKE_gdJ=_V-;8zx$gdVSqgP%RI z|IgtGlM@Hrw(=W0Ty9EGp811PQ4cVvt;z%=gkV+)v^I5>v@RLST_rP{lS%*vX@yf` zVT5>BKL&lcDx)V2T8+D^rNm6K4Ull*zZ|Fb(s^iqvGqYV^)F!HIY`nEam;*}LXUb9 zgX>GD^be4Re73S01iN+%Z0Mn8=I3|IzdRFX-0w_sN`io!SjUZAj&ZNM-Lr+8kfy7z zPRyXHS=$Iuy(c!t-+er+vKWGw%*++B|J^tOSjKiDNw01A(kt2T(o6nMAL^;xnI6mP zX5yyTP2BcfnpSG`o%;W=Z~AxK@q>Q_(NmX0Pf3Oy_0BEJbj}&Y-wf?PdRKez!FWUn z8nnR)+4X0aD@!&671Ag{PCO|+`2C`TYMA~8PBJ~QS$wy zbH+?D_Brlx`s!9EobDC~#@Q=M<_=VX=_~V_x7z0y7O^3kR^D>o(q`~+f(cNikZ)|5 zXm2XJ`RJ^+V2BQ+%_JEKLhL#owoP#)FV!_j=1Yz&v$zy zQ`ax0lLMwnGg#SDQh?p$8uEP3TX>3J;p!GtGf2Gi5lf6c1>o-8gnc|HepdsGq2!JsWkJq5$P>X1ioifVi?ke6@rXK#PKZ zK80k*+y~Sv$Ol#$E!0B}Owc3ZZYvLvi?j?3alCf%bYh5R6aLladV4mozrSOD;04-0 z0BMbrlYnXWXXc+Q+S{3RkhdtlJ{W2 zaU(o#?)WT`Ma6NTDJGz{y}!S|o1>mP5kgFHMWubSQWrgrDfPL`}KpHqC4Gk*LcezTc`LIq*i{%T^>^XoWb zmIW<+-;xAd>2L&x_-|&TdhkFz@%R|yG@yF-Sxf;&4seyUBwdFP-Y^7fLJ!WTV4;t) zTdsHUBvPBNb+Fc*KY1%!%}7gIR+74ci*su|SYQU9QOT*STzJRf--kj?M`T}OVO11n zv%yJmOyxlVDJr!nXG*)h8mHNcUrL8b>U_nhahEt!&xXx}%=G zecIEXtC#5OV3+a#f)i6Lw`VV2c8#8W^oy@GGFu!?8LufoA6O1 z)A{-IQu%p!A`eY4Iw|o@LYcS-yYVr(z}s&Yn}A9w4hzMH)3Yi zBK;tYZFLVkfe`OofQ*{kN=uVvYptgkD`bJF*k>P%P2eTekiK98)DP92=hPfZEzw6L@spBWy$5zHmGTpLPHKWTYg zRM>TK3a7A?jJOIFD8PG`!%J$fbg_luhzE6Y6h-m4q+Havu*5?5^{tP7pPOtPZ{J+= zbUBLNd-T_lgXYYactC?e%pp%;Q5J=)A}oZei?&vj^k3zRdlnDMTcN246*UC$XwuXn=SM!R}>vo#-yLNux>a(}DKO$<5MLF&d zE}X$3%A46i!XnMY9d4%Pkc8Vt8jRv(-||SzU41x}%39JMa@Ie1j@|W2Zp5^-F>7Y!aCLUAnJxI2*^P%cG8iT25~Zb9l<2!X z{#7gG`Bnl#zbGg)M~BN#dd@QU#o5Pau-*{NPzctiCy)8Jyuw{3=F7Z)w!qFWhQvGMvXSTYx5 z(Io+)V%p)4$JikVrEKxV4+n$4r&v&Bl|_ek%l;HFvzjA|!2#Rf^Y-X1T03q~RkpGM zXg`AtJg24bj5C3}x2{mpwY+fg0Y(&pV0SyYvAf+6h&_;$!(RPqBMpj^)qYSnous5Aj7kN_DC+ zk)f)t*lGPT+IMq!Tnr0mc*WA46%S|b?s5Jd-W8f%(ft4?g#w(X0Kx{Dad3fufaG*U zYN;?Ot@y8}2|H8kKhY%yIrxa>X9tzd^qN>uX5B#&M@Y+s|lsE zzXp{aHe6)wDu?=zCfuLgJ|@&T;&X;mIs76bwbzrdFEkYnQxtX?VRIfPz1UjlPQF@b zcC9x(OwZJR%(@yRRK)WDl>f8~Ig0C`gxHc#1)?3xMx+3e ziE1-jeBl$Q!~1duvr4PWqXuJQBvzO6?fA~gg-~~Pem11Bn=ytjnH9~q%drlG5#FS1 zvG8JsB;0c%NzO64^u!WG;E)@V$grGPW!?{R!kaSwi-;qgb>o)X-$+%Yh2gygZ`km0b;~wy5ATt#Yn>3qM^b`g#sPnx(Isb1AGi7 z)Ej(^cidbGa<4H%lI~}aGdm21;IC{qd?v%B!S!zMFKU*XSkVWt9xN{H66%@f$We3# zC1|ex-x2vxkA)Cnx3?OnwDxP@wWo z7EL6&k>Pa+?^;*JmmB;(&ym672$kq|dnB1LGAjfTmCtx15Q|m<<;<)WhNrRijewch zXYI_0SxY0%b;%xk=dCY2u6mVccI>J*IqEo4?1S<&Bwp_pQ6HJtQ>fXlY7NNxcHGOo zJ1A4BIjMk_ff?Z8wXxlD65v6z;&&5vns?cw~4mnm0V!FCLP93Olw= zFHAg88K4;?3^BH?P&}F`As^<%+{O;w^0lZD-#Qz!9W`{CSRL}3{q~|v^u~uV&ycx8 zMrDGV3}=%*R_bBsKKJNv)NvRu|jr;WK zA|K1ibjS4QG?EYS!cR!cVK0=!T%)1Z9Hx&?RaSacg^4HE&|<@BVIZtXP@wEp&J)sE z%rWo>CkzRKkaYHf2}hdjS3>y2eK=*f|#YucY#ZuYPWO_D8EBpk}l~c zGl^78P^F)kLP)?U7ipvYJ3~pPdscLyN7B7*H1tC%8)E9{oM}Dvp()<3wi>Nqzsxx+ z@@k2RAqlqW$7r8oK@&cV?DssEBD$Ti&m=V<=xU=1Dw~A!1*F%IVJ?l#mM}Jq600J+ z7dTLX^d9IJAi1pWEWgwfv7%Z=Ji1ri;49;_g`;&KriNd7VIddWy~EXK#A}a%s<)dqdlc`uPc$@IChi?+^5&w56*r_&a8g3`1a1qmxi%*o_%5hbBR{}a z=^n*0rj`#q`u+-&F>2uBK*T{ahZ>Fb?SUP`q$U}xwuY6_{Urptk@q?La?t}Hqf`D6 ziY1C>n?nn0m&0fXV28AzX*8A$5pQgVQ3BGR#J55XTDeGgdc8Q^JSfU(&W|DIdTD}> z=|L1L1q#JN3!Aw2P^Kuk&HwE2zsik;dMnlCXWPmuAmlG-6b{=G0?C6fSi4sX6FE-p zB!_Ta4m3cM5(k8Gq{i|fhZTa!Pg`;mh0AFU|I5URDCB%Z;1We%#DFa7(5yQ@s1Ica z{|`~`;m?Nqy$?sMC~CE6l^8`;i9Kq>sH$4sv^K51)fTZ;%~CarP)gM-htc*PT1(KI1yqbYaF=Jjg?^lV+ykZQlc#S?JK+IzzyNm{GsfcU_Y|m? zYOH0|aJ}a@RQ7MYHiG4u=t6syO_D%cHFm3#aVjkmi7;;&m4V>78vq`{H+;9yOG!YY z4audE4jAkQ0%5$Zm;lA+;FTnP>}E?B_wlO}272hqHFkw2OhOMEqh|8;TSaOb6kQKV zE|Ss14Z;ud5854TPdYoM*q~{gl(>FR=TY{#*(eFL*^5xQHLM68E@vKvTzC)lLLu*) zDFD8YqEfKgFXR~W?#n4JLcgZs!~{i^vx2&|MLJg}f)o?dv$XHVE<9q32dW?htRn36MX2W*nvrqREb*Lhdp$)Dg zvHMK?OQNc5ZCw1PYNwT(+M_Z2kUb5Mx#^`l*1K%bpScTi5&7+mSaLUtcb8;d)#}+2 zeVwVeMY}LkyV+r0I%SUwm2$$jlNV=gDfWj{am=1P5zU8saRT-N8H@2y(*Ck9 zUy5l*k_7d?bnX*LDAeHuJgoh>EvfHyE%4z&6r2y`YkBp1V@VflD$hof_jSjMd0lH5T&B&uj-I)21AjUxDvb-C#TWlpr zTU<#U!?xDBud6XLSxdT7NYCsM$Xao3kd0N1z!>K4th4OK0~urYW*<93>RKH^Ch1)x zExKf~T{vv9!?DQQkO~LC+3j^!_hFKa?gR(9uK%u|`1QcDM08vSdKV-WnpiC_Oo5w> zg{9?yqr%_QGO;B>DiXY-On#w418*PXe~+oi=&t3$q&S?It~Mvo^#;zPekQ`&^8US| zTNGi2l3olvM72wP)?-Kq%KqF<)XG0-a+Vz!M4C@`&*Q2+{)9cA^v3qC$Q3t$K_LFx zr=o4U-Iv68NqogcU<;w-GFMH7R0wbJQcR>DHjI4wP^I%h`NtJ9_+xZVf3)y}hTmk4*#tH)t1HMF=^W>4J0@ZU2=`&AKa0<~O-<{goA)ECuX~n0) z|G;Du#vj^*BW(QG<#Q1C(S}@y91ZhuMPHn@TsLP5sSAo%$sFGKpwgNeM_(-bv}0MU z)t+EuZC$%L=|?eBZV{@9ARYog8xE~7*pR;<(cN#}=L)_m7xOfPRK2_9hK8BVbkP8gE!X;Aen57(!*ODBs2^XgP1>_>BY70x6oTI0 z1*+jN0XhwljBpOC815}^k{2hq8|p&C0A1t98|)2sUyg#TkwISa)oV8aU2=vG2cbXz z0N%j&anZSoN=hc*Cc*pY=%!a~;mCD>p9|v)kS!qY)o*&>j@I!`uo`gG%i?!S;mC*= z_^htcf@f5%YCg3s$RDJdl8WTGU?fwmBC6rSaSiEkyZ)2!(5SWa{U#8VJ2KHsCSu)b zTE>~YvBSVC#Q#_Rzk5t(WF%|hC+I|fSxCp4$CR&vk+3TOuUl#}ak?Mmxq4GoW?|P_ zYr$<4qraZAvyqiE*k9D4Xa@bBapUb00!vTN%8mSPR3_2IIKith1<~&kiT?X_g8v8- z?=8Zwb$Nyk0ms813Jd5mFAdjPPMKZw5m47 z@#yFX=v@jBCS^*=>@wM*ht|Nfo|%P{^pM8L4t8H6W=}P$a{giXE)-#>{jiQtaP5gd zEzIzarTkEK!Qw(apI>X2GJ<%+rQi;(@2>!W97yn@(I~?)1e^2Z4);<)p*}NEmH8&| z_9GI3Ci2fhoMvcfXjEaLkpD0>16S2M>>y!NvS)9~kd?CR@4cYokh?z8WBj1^*D(i) z!z2y4FGUzg`<{&$BvKm}o=SU^VpxU#GsRE*BQ@Lg34Sg#`Ptv~U|6>wFT=T_G56j` z=7oiYhN~S3Bu{2^?XAqa5ly1sML`*!Do-6nhM5FnC9Ju@S;42c03;}Dv?Mq*Ttt>Sgp5zVDAph|opAUQ zd!9pLoNREB@u2?*Yx%aIN?yk@!n;TWicyKKPX%Ky3t}RT=Y$26?^urtUdjoE-rovc z0mA}+fp21-gC6nZ=OZaBg77n(;~FRM%hRon!si9sSEa52)6*!QkO4k8JfV2?fm8}! z2j&mXvXM2WZa3Q=zBvAsWca977yx=oB7ZdI<<1cOLV~K2PV)4-+)Ex*ILdrclzeio z!|Esde<_D~GDzy?<#K(o)5vC)y>KG2-H+m%&C-*xD>o%+CG4URcWnA$CI1&1V~Z7978a=>%OM} z-sT{AduI)m56vANs-rRCF`8C9yK0O4UecFp$GH_GnD~CL&6RhRupD!);FZLHUdM=+ zP6%dr;O&2Gzies7N9M)aF<+WGk{VxJPWBfLn0@!dDyR3IItO#zj#6qVACYZ664z=2 z+hSqAp%P-4oauO_Z^Ps%h$tG#R<{}fQq$u()3u)aL4IdNB9SWX;%`XEjT`6==Abs7 zG_CSFsE4+jpWwD?_6ROTa>*5p1Y6U-B1>D0rWTr(U$XI||KxMhNmQ8RTtF(Se_WoW zG1y#UUGkft&J=HEtA|SfaxI62?v=1)z#Pl~bF-QJu{)O&%M19A9^06?}F|h09ZD^0dU&!@AE_=+=g8wCE)fxb`7L|jMh++O`y-i}2 zA%n=jIIDp?0uu76|9kNUSeg4AxHx6Mx$oibKANAFQvQZaWys7yl-|jQiHj-^b-TPN#q+FJ z8remcYAl+Rfk14e+LL=>bzP4jj>L9}S5E*RSb#Uv03|cHjeY@X$(qB~7x&MMT+P$9 z1QG?J{%|o_Du$U*m`D`n)!j|$N5#DcyqrRV5d^2_|2x^opm>0p@_s9d`sCk>tzCtt zvy!!lkf?kgh^DrEKTW+h4gU4fNesexmAjdQ-&ur(rZ2=$`6RSeD})ueA?Kxb0{s{O zmw1fM^{qBxATwVVk9N^1NOU>vd#8P#q!nMS-FzBiG1Gi4M6n~Jzj8W@!HOzqayCYtj|QI9rZ_*B+wMtGRf(88t+IH2t?*>r7*E#F`tUO-b;(wSRAhENc8G$ z{#xCpQu@}5)WiOdmqofW=HLZFD}4DTz!k1g{S1&j4^<*-MIl8bt)tV@Zj^7qu;NYotq#gurcF<2x*BA#qRiPMb9iBO`M!n|kVWW#Uf9@9%(5 zI{96Ge*WNltlEMpSHhE0U!$!>4bTR~(moK1(C#dG59{0e#w7CZ5EU6ew@qkP*6a|- z^+n1jCDAW_UAW9gw{#_k)gLvl&P&vYYD1K5%l>D4aSzRRC>5ML$pvcLAq>7#Is(b5 z2!!_O`T0}@Np<|((%E?^e>wuF@&aTS1t@1eLF|?i1XTp41y>iYo(`aQQImw($3p;g zCE3(o5C;#TRB_neDwP4xaQb;*!+lDmWGWJBq*#WdsMUkzv2=?zjRR45f|Z0Pxt1aACeLF9l)+gILU{i-icM{+BIFA$2xLF@8d>5ekw zWag}S@Q9T=ZTzQzYkBxYYYG7J-5x5RGAN81;$X_`sJuyH90-}Q|CqaKLmA-PB1`@_ zeSG2TaNDVkqhm27bExsV@!h}9u8eau)_S!|Zs=R;!T} ze8Kl`|Knqj><1hyGFuJ1`O%@_&>)LdX8+~NA`bUH0oishtqT}*%Hx(x*)p2{G((R+ z%RzBpeEmRTJsL2+Yk<)B)N)^le*cdg6Z)_oa?;yq#zwORR#3sy>KE$urk zB_-LmH-lfo+`jIcaNGr!LCuGN)K|JZpJ*m z0w8=ty=ap@&=Tn9Vd!1!*hjtr$Z?z?)(-cyPhqr9tXduIf~|~^ zP{D}xAffNd=QMcFMlQ|bMeox3PA}ahw*g3`ozl7?c;bq7AM5Y%Qk?dWYJjVi?Vp2c zS55U?`%|qye9<@wEZX*ZmS6FoGcpNnSsXdkMwgG{`qd#KFLmIoY~iOINs@`CX@K%K zCx~Dta=~cK^8EXgtxA8~yPIK(*QoAI*My<2P$XEf_Jxm{^;H&2>AjNx=aeABp4pv| zI!>gOZ+Ce8lE$(@QsJabA>VxTA?JsngtLe7ugYRS%d*IBo9+A;*EW49%$JXErxv(2 zh5-^t%Lz$_GLbh$+;C5hMW&Nr`On%<1%;t!fj!l($aa@K9cGgq@1@PU< zi|vS=dAPHBtLy(L{r4$UQfqFGsk=azZ)Cik?#GLJFi-oRXfIo$L2+rMSTKHg^dR@i zQ_k|X?EK<-joe#og!PlHNh$kW&yPXTD(DptTImwddmiADc43r_Hx1r>OQ3#CfaC|V zLGML@i@%jzU#9JDO+R9g))GapjkzC{DS9d&6h!C00vJjVsLUNXNUY}*j?O__qW9kP znYV|{dRAq5c^G}o$9#|){WpDsugc;V0}m=*1el>zP?FvUTv?9qoBTX&h6b9ihjd2F zT>cPyGHY4KJW$#gP$%=Ij5OcHo=@Nri8J(Kb|VtPPx+Aarb++O;x5ynG_h&qS+og> ze}82dbs60~B5NhTqxK##uo60;jTr1;+iy5@u&uc` zH1Srdx3S&Sor*5b7&>(fzcErU+PUn+r{JYHq62kv%AW2X>WX$*qf^`K59j~=-3>nu zIXPdvDKzlt1uM(AOR=;`9Lb7AiNMVj*$3t#4_71DMjrp?a_Y&*Dliw6L4gSbNuJr{ z8$p)h)T5~98gq7pF)OO4UXT2xgW z33Z#3EhiNTfignZ46SwkJTgvWV#LC|$;Bpdg7(#N}u#RK8r7d?}a6&=vvx4h=0ozI2W;=`^}`2D((wDu{-JfS*7^{$pA&m~5G zhR=ezfux72?`7QvYh;s=(nyY=+?O9!_$U@B+rYnzI69MG){JEQ&)dYQ{04|!fv6}S zK{%k!53$IJeCX7~PDUJR&GM+VHl9-fY$Ra@bDJTk_Nws)|&TM*E-my@h6$3C{qaJPsz`rR`78u**-KiimL4z_$MgZWuD zZ?@n1>KoogV+?#JM)~@MWp)JET2(q8JPPl}gmOk!IJP)HcxaI4r4QU!4U+I-YIF18 z{p0Z?pHJio1urREj|Y5v{ohyq_vaY;Q`ip%2B@}}?KV)ponT{pRfIRgDwv*d9drno z=@rn}9@tGJRi_6Ov`u2DcM&^ei-Xj8h%oS5WY}QWBIgISAOz&=TVDAToqW@S^Bg;k zY%bEJ?eOHTeQdeH^g*2b=gYO?a($;#Qm*)qUKSKvx$DE8Nd{`dwG0-B&kk=tHJaZU z?uzBGQ6-%0t6Q75lOzCT<#0I~-sug2_Vc&IvSh~Hp_Z&(5fQwQHG}nhGs)SEtCIqz z(%ULyCfgttx<4)>_5MHIedO_s{$|H$vbf0gWfBpnH+4*olxAl}s4z7;77twnRv2Pn zhqCUDIb&IbT|~j#n+`++%S(@Q@5*YWIiHnSE^BC;3$+Moo9qCz{J4UxU;;tRMqk*F zhajsHm#;Al8}06aeQHF;pdVFONO$Q1yzTUjBz7XBo4S?QAUdb8hs@sXr`3njbF$II zb8t~DE#-7{YiNvRhP04pd)XW|LFHazA6&@CabY-e02vIQYk!w0l-zcBumhGR3bBTE zHc!kBPumeq#+P>q^Ot9OU^!QSLtr#2ap(Npy29STJ=PL^)XLEbFMNS~Gn!UqaMxe| zyYQcfO17CK^BEbR98yvp`|nANtG6`6(A~cDv5;49pdYlhwAP;zdt#H_b%lVWP&pIdyQy}wj2Pe4=R*g%qxC1xl#dQ*@Oav#c>iaA2;F~Q_T5z`nv_A4FIjc@ zlTa7)KKUx^7?--m8s-CKLk=BmUC08@&JH25h2;e%YcM{V#&JMqVgVpXpjn1Pc z*1I}Lm9%ac;Pvj##9t${a6Z)8NUNrP9@=v$GPO%fxKt%nOv#E)jV{LjMdzA?gn`|d zDTO*tiHN?pjR)@n(LJ@wRXR+zVL{D-96A327H>H(#X~=buP&<7f8-fD5S}!Z;Ep>b zeEK3!-i$s4DPBQ&xGT&!5Y0!~{HP_b|JpEe_qVPs$mME?iY%mKR>RFF1+<|uwuTdz z1T6Nh=NA+(ypy<*)Un?b>%1^=6raqiMbN?t0npTnSa$YH+}iIb2im>xpamyk?(DL~ zSLkb}Tr*r`CV*XdSOZmzFU5ebOv`6af20jpY?FX~Td@UmoMNr(9?9w4r&VpaUucWf zHwCLO{m?Myk~H?6!aN!I9l>b`JZ&G#ssjnAvaKv0tb_!I)ww_CyEK?}5&ZmN9*Mo@ zrq=RU7d}V0`Q1fIHp^hddvC_GD|Hlxw!Y^p@LGljp0eQjv!~9tAOA^^SVQ7y(ij1F z%v*1R{ffqnlRm19f!_ZKvl>gaRo7T7X55_UYzDr8EWGoNNYzfI+|1J(z`hyof5@_K zF#yQu)zY?-ITIM53{7s#zZUHEFdLviYygTt5upxZVEPdFhR`-9wvM6dfEm>74}4zh z6*y7ZaG^X!&>v559TpB+u*Q+`)dFmQ=C_}}^zxciM%sjSctlpl(a}CUoId;t&&{VdCz!bElDL zTsO@IVEvdSUy;yKY`CM`Ue_r3=dvL^P{^Zfhb2%L65gqiq@AZ5Zy*)@0c#&dCVI&! zp)S34impWMmI*N^DC^TOVlj)OsQ1oGJCBHUt32EZd+kGll!AThPY)A659K|ZOv|gG zen>>5c#+U?VGWgD;$x<<^Z%k+Duvr{%MV|W0G-uzrg;_|HleS9L)XM`E%5{1p@w`K=6^}< z%}n~epJfg2$lf{LcQgC$O+8|!|KBh6-;UcCGv}k3tTnUO=7Q3&caAo^e`Fnwl%OE6 z{c{cOeXJ7cZ?;RoL`NujK+oH1+57>A=LiL~#uQ*SInwk!r%=`MV%ha)Q>J@N}Rb{`87p2+CGSY0pPcXsHZ*bsNRK0`exYb>Pju?fPSUkA#Hfx5f41{6fd@wC8R9UToz$nI4ijU^8@+wa`3 zTx}tP_#QNw>KEKiy?^rDp`_qhC1T=I@znWR@PuX%1wXS4l?*mg4|BaiHE{cn-~N-j z!ZK5*JS&ne*y)4HTp-)N)e{voK?~Fuoi!aNE$#@XleGRbf_i5f+_%Pyo6gH*%AeUc zW5qvo+s?-gQaA0sn?1%-`Tr{H)siG9TU;`CQju-V9`^eJ`ms*DM>aloJ$P*b@IKvZ z{VBKTE7d4ym7BF6LsgpPWm4BrQZ9_jSy}0XyAhuefq;`PyoRqFRGCF>6C+RAHe61- z@0xbWGXSsUGAADl#@#hS(#LTthCCn;Cc0gh1_@Hi{l+)f83utQ>9QbfPgu zlAP#8W+ctLdHJJS&aAzFIV&Y^#Kwy0#7g=LZrI7@K+hM#0w+xZ;V59iu|4Ij{ell4 zx%F7p##$sxRPR|WThl`u?(B5p5c<}c&>MY~~3ZUht_A<2zP z4yrP!&MSD9FQk#}&zSA2FO?C(c(`e9G9Xl()H-FMyH=l!9$VEE`_>KC^7an^G!u}@ z)?Nu{$UrE1mh#nWa)Qg`n^^rdmL}iIm3awPQ9KQ}-w3tINgdURH|lCAl`+KKp>nn^f5-Eyh4pjoQLnafJ>V zUeW7m!y7E|bByA9d{l4 z)EXJ*&w_ayd0;Ukj(sy&Le?9VRpv`NA7cV47}Rb={*^$xi23OG-MwuU=#3ENvNDuC zF`JTI(HYncp4A&0LaPrO6JYqyB;j67S!B*a0_DPcS8n``Blfl^>{PM80eH@x1Xfz z`%)oM*P#unkO@y5hv_N zNw9*j(HjSmjIO9W$MfxK`?9KgmnQuU>!L`9X%uFEhgfcW@}cZ3sk8oYTTyF%o$NBI7Te23Pxu#Od&p9Aeu zu#(TR;Gorh)oo|?3R{QFmzVlC9a$EZmQDm4$yU}b=md3{&vA=r<*^M-q{G`0j>oGk z1aAt360m5hu(vvvG-@y=2Y=2qcCv!~#b!>m$WsgG4E)zte?##THTC=K&A0#Zd1+wl zj`x5)p5AM(q}0oU^Lv~JScg=<+-0;q^{)-6H1j{OBT`qh&o4%Ia%#aWE>^>S6&905 zDc7ZVj7s!|uAB31rpWuleyUEenE8)zOegmqv{noCinF6P)CU76>~UH+L5o$mkK@9e z-(=%;+PE0D46nnx(kUV-k1?&C8YH3R-EJd9eA!;(Y|m-L_24u0pe)UA8CIcx zpWRe1f$oUT7q|CZ!g&3@>uF@OogB99rF`t#r3@IC>=vE%V6;TK)Hd{_)$rwuSlJX6&RJh(gmGrA`ZWm<)w}X6VYl3k2Ya>MDoN zgd`;t93HOTBt>&k;N^tZpOJr((HA_2A9Pb~3rdvPL7AV$U`Mv2G1LMyOhh}@hA45c%Os=bOWrHj+6YYjUzlI z$;&UY^XNV3ak{B{p@gTNiPj{UWWZ420hA8b=c?}&aEsP|F9`#uZpC>syj|+G8H#Bi zn;8!XN88XliG(WtCidt)6}$6xp!$&V$?t+n7fx1q; z(|<4lsnnK#twt519|u1u{3Xu>BG>Q%UM{#H8l^VXimnBhYAz~t_kTgNe4sq6K2Y5C zKc22=Wy?6AbtE=${kTfG*ni>QzVlbEDjreh(p)uMHQKlY#~mufkjA zS>BN}ki8%DpILjT%8F?-o@8SeQ;h#%u^oIW-gQ%_GlV$Xq4rRVo6R_Hk`xy8N9V8T zbYK%>Bnl! zVV2n#6u@kaj?CpqvenE+IOwPQe+ayIC%ZQu$9X;Em~LWX^+;jmV8omJ<9*zZeZ?i> z%)^SLbB!r&b#;Fpm3U<{zo{5!-L;ytYs|eBc0>Y9jll`ZcK!|Y)h~_Di>a)v)u!lS z9_pZz*zdI>mlDzfAfSP&3o%#I$8Cp3C^yMn$=)b=E_!8em8z&n6HSi9chv6!2l>PV zI}nQG-BW45fv!!Wh;rD7 z$q)EGjSnCs&3ZUZavdlt;XIc+;dLMQ6LWB?Z-~%mGUNdgDJ!|4ByxHKE$3Hp>uxG5 zu2i)fJ>ANhJ3eP|VRbBCgmE2-5e`PB>*D)WMKz$+$#|xe8 zZYXx*CW323XS3+{F=c$~v1RZYC+y!c_^(2bsm-Na!2xxv?yt_MA4@C~Q+-RX5I6O?iqznfRoG%f4 z4_mF)UqUX#jqOm*(49}s);6O77Z!TC7-X`r_lx&#&8~}S%&(!_2P^k7rl=_Q*eZ6a zBhFP8`_0Zrw<6uy_UAs|40?rH5imL3P*)&6O~(YCCFRCv2Gt;1nh_*55Icm!{N`;{ ziXfm~zIXQgla42~DG)^47S4}T~m89{`E2(57kWYZgcNHXP6x(v9B4eogj`!qs&c@`VdkO zOyR~~C$qBUn!ptXks}*?D8nsjy)^zFt;cPjBl?1!``$a%qgYQ2z=S%(G!wgAqu+)X7p4HQ` zJK-v5+4gmWC=F>3u+g6-dh#0V|bsB>_m+s(1JU>Pq zfh&}=dCMgz9%5NWqyz@ZlbSKZtc*k@KCP2>7O|%-!pmw2iC%Q2`ELe%jF*RP{O}xR z7Fib|HilzN_WOv741=%3uqBr-usQcS$H1lENb6br5w%Oz5gTEJ4MsShjrt?O;Zym248*G&&;}V5<6p3b)a^FV^dUe6pqs7s+gQ}&2{18dpFqSwn{Xr zfemK`GOxd&V^H=PFL(4=N${PAG}8&FK&|(Yq*n*#C^x3E~9f&o^k`Q1=*~VscOGF2 zr)y>iPi%jr63SzzXrBTWV}Q4))0~0kr$>x|FQ$j8`Psdkjh&gq09iiiqY}n5vYt$;NGi0VI5jC7(36wAe`Wh(Q*A z;;!om%k|Rtor&*Agm0lW5qSH`+S)tQ5f#FU8XV0ldq|^~rw|0@+mhR$71uigTHi%% zw%SQ1zV>|?Kk@nVF_}S@TGzCkni|=Am6RsukqdCOLFFvGxES@f*9jC;HdcJ)VRc^K zXD-jSrJa>1Hm5hTRxrx-^Y^a(;wG3cp^+Ta-us-I@@#AM9mwed?wqo#6Fq|W`tl@A zbM919r3&`24&0jHc~?Pu2ofC{E8vbDfwV7XPs2#mr3&4zGKBy}-YE^m+mE~O}BO~1XGqs@7Sjtfhh{_?bwQ~2c=acx!pi4kOehL!XVbk`@pz&D4BAq7D z#4m2Tk)&VsmEwD2mp+PX1vfYRyr20vjfh{mNSDPeH|+9GKBTDMejwO>M*YWid;Ep% zV-^EqJ9xpWnb@TMXKd&-VY>*%!aH+5JT#P+$>u0)RO2WS-*V+uBjf)!3xF;(x?(Qq zGi)OcJoT-pv{}*dqH#lM&~ZlR%`=W~XwJ~?+!PZcN>?IHq9(A!Po%vYdaiYH6u)3R zt3~@I;KEj`*thuguy=yspMvQ5BoD3+-)yQGp{ru-hl)E*6w+^6Y6WC} z_33SLZa@e)7HOM?cejZs^riQJCgE7%qyl-Y`=r{DvqZjIgmHQJm;T&ocdBXG-*00( z!;*-zwvhFi!#9oiM`^PQotbN>`n`s8^K?nUvmWSyP+Z2&S zo{jP@>kZe@nBgx26?Tb4J^$k&I9HkNGpmtmkCoD=Qx_fS)U9-YdElDv<=d{stFejjpb>i2Ubt*P z-(}3lme;&u$}7*4I5}>GCzdB?fAH!pxp{8V*xk7O7gA9ptI%LhI4FSHj6LfbcqZx+ zh|fHzT+{bI*3QA0nL6OA&3sEtZVe=5k;22Q#|nXDh4_5miAscHY4hb3kBv<4ZfQI0 zuV=kxd~MX2eq^oCZQ`-HEO88>B_Ts_@_BgKn(5s+p=FW5-CFNn_u}0KWN((I8p%QU zl7V17;26p-E`g3+ts1Z=X^04W%1J`)?`8moHT;Cd#g%b1H5cqhfFOrU&(fa`(R~d* z_ftAnKtl&~rL|E|^(3oDN99AjQ|zrB$yWY4a#t!K4J1qYxgnjRjIzt+WnV_hlLIJ^ zS7s*3eN7|ElrwqD1wbRDQHZH$j;-lIG^xB(j1RCiHKN#p8t@VN1h>)Lg>=EelvywK zXPT4-;Fuz!ZPt<0%mFs~p7wR6pe7DsD05-*^)SUtq|A;>eO^>_lhrtR0BLiLo? z-XwzXIc26wp>1j1Jwz!nrUDWqRyfR1D z9N&8IXupC%h9L8x@1L0cp*ik{mf~@unk7o5tC9<*f~#2(&I&(=N?oXOU27}_s4Tm{ zE?4m{I&~x}Z{}yOL0GF{Y+XL-b-)kMzb83TI-2)4;3Bt)qxpZA z4G4~nli(U0=RrUy=7>$HXsLv_gA5QVM*077_UPV&ikV$5Pl{w&P%=*$f`HGid@V{I zuq!rUWI zB}S@3UHSCAvwH9ED;5^ol*4!WI*Y%*LIhWo&8NKouD5-|ssb`aEFi*$jQy{Bv2qaq*Gy10Hk&62nrI5IK>GoR=R&Hkwd&sgI zUVGui8Qq-Fc@y$P)nir`>2S4i!^wivX{n4@D4V7q__Lz$v5y*upy|<1wn%R{RhEx4 zW|CO$TZ3bYpW~>G(hgX5A(n{*5@-4Hq=dcUqXiXi&?YT#>XQLbfsS2 zdQ6YheGPBdeJGFK(jflIaXOZ7iuM@8%zJ}nWbt?##|;Q}8qClOrENY&5N)+ewQ+WF z$Jcjtu*nbMZ$rpdZPGHT?z0qNxiKKxP zF&O7V&0US{;e11-1xe^Bq-D&I;0-*!gY zY=2Q8R6;rAFxm&k1Bx3zgO}iqoH722R_9Lbyt6HJ#2%F{KSE)Ar0^|JZ;AvDI(N9 zok5+8ek#a6bvr+DshP9SIz&4R$Sx7yUk=)NQX%%>n*10XusJyEaztf`kt4S@Dk(w=U%ScO)4!Y?rp`( zLM|&NXHJxlk5CLvRDX9izrh*?zQ@nmzzEOdF4t<1L#I+py#h04w+iE{3sVGnHvZhv z(H%^^Xu44M{95ao7{^E44I*t2W+q@HiCnWd0~Ch#<=S96o%G7~NphKA6sA)a=lGIX z@>wWZ>4cGWq+w~~DA5%F0~tW^`4ADz;Zd6brt+&ad|gLy9EA3+-#; z(qcJe+5L`QN2_=j^oQ3V_q-jG3e-|B=PwBMFHfws0{?1pez}2&h3g((bioSds`lz+8s=7{+Pz+MOQ|-#8@mrdgLgB#8Uw#bSDT!4Eam6=vG0IAV-){ ztuF#SDN1S1fj-uR8c%6s1MRVUqU}o(<|Bdc5xV0ADQX;X z?|>)I%fM!8h^UK_5-dZYYt1xlDK39lA%z}`^-u9c)xDZTZe&pp)FAP&S(DFb+4?T` zO7L|9gpkM1Bq8Uifry#xhu772=#jtW6|!c4%7Joe#-eFT!xa?G zvVO<`3w)w&mhlyaL|AJ4ej`aPAVr+bBst6XoWzGCTsoA!>%LhJBGp?CrxuXpkI2cd zeT^hU?y0YRV&PkHWI6h?^tLJKx4!|B4PCjVNc9yS*0PH-ZZe8w!ni6Q65`t^);IVa zR`@i#28h^+3&+b|eP833oRT%L6NTy+Q_l(EfSu}t2#%!89S5%a?-9Q35FCSlT8-So z=bC6SR zPeeViw0Y6Qrz^d0PH|e&^bowiIWodHD}FT`?9C7p=KB_jr&p@B6m z{f`&<&&$fZ?!dceQ4V)(#T1XC;tM5;K3bNagrF(M_YN~0Jmaf2pfo3l-nw7Y${A7| zSXfuL=i7J1G$SJfkmF31owcLm<xQDG}O1KK=TxPYQw zm(>^b)mWZ1mV6pKNld-^WFIAO7CPS$DY&uTxI1k8b$)=dC5aI*@S|)NOuo}C&|)oN ztj=!psa*nviyQ-<-m+&qr;7I5*tl~=49y(IPZ&AZx6EI9I(&<>0WUklLQ8sUP zw?jn-P)+_mQfpNNdOEQ=E9^F~2DEkl6t-<((08fjV?-~g^Y5UDnxcgH}bUgfaX`pNakfrQwoKP39I&VekpU24Z!O!mdv>n?zL(Ud#V zYmbl!zbBGr60K3W1a?7GmMYa)O`7;E2A{<*-C8of130V?P!b>6jkGhn;~ItheP9#p z^wEI53ZDUB@4gI4t8?G#)#vg<>%;BF?s2)BWc^tvCD>_E)E_(PeQPK$KNKo64*0f_ zteo&DZ(%YKF(ltyXw@wM(K*ixyb?Okp{F-!lDf^YEwa>Mb@&Kxf3d+8JgqUjzuDmX!Tr-eS(Pm%#mC?o z6hDFB@;7xbRcK@+5cDJ};$kN%Ky>n?t%%Cs8KZ0s$gTi~0mLXrvpVkwsn!BAX|EG4 zcOYs(Q5Tz`_8GD8a%^{-88dM~xf0D%HoyfvT=~j6U^K%Z+_dsrGh4WqxVpO>Pj{YY zw(4U2*#{CB1djmoHl}%d$*ptl=JPh7t*Dkn4)9UASexV%(1;t9HNB9L&f ziYEWT1vb-UUDPq`$5zfyaOd4cHxR%WKqsiOfCHL#yc#=jz}byUUbQ6QKWGn&gKO5> zk1*{)9$T~UE2vn)pVI--W}of~8%4e)hC>TJ-S?6}lfngU{{;}MzVG|~C?4rZD5pb9 z01@RY&%5hC*ys9PXC24)^m&jq6B;uf-l}dwQJ8XnRzvC_ zv<5k%c(xG!*Kx$w0J#g2!`#E6!r&_Iy2mIdBQPcs6ugzt5Qo;%cImh~puz@?Ci{plU%x zV!RV7>^Rj<1Q3d+t1Lx9(E(dLwHge^MsT*6dICPFuDL+*C*nS5g93QZ6NFRL$9PS1 z5Wg?Ki?xj|a5!6IWW59#vrw>Z&O`GlJeq<9B^@L#Mtq321LB`aNg+ne>*X{j3?Ah} zdNEMuYub?vGU^euZtG=keEVwWa+BPqiNEiDBMHQUl>41xt$Zy@VU)* zQEml>-mz%WTJ$@{Oz**bgb+OjhR)q90qHCC9I(s6`I&9fOBY}4q+(bu+1&8la<8$+ zhX;a#2^DdA$A*fo<|QZnUw-T@-sgyhFfn3j!L$+dfPHLev9_h1-5#&0n470o{q+k2 zDQBUiA(`)@zGX9#WXw`-M_rUP4OtR3n_H9v{AsTryHm1Bp&7DELbscys(v)xSvB2H zuayp2-Vf7S{L>Lplb}f=JW_${!Lj`&GVYL2#gVC!uXD){}@v_4%OOp@$i zP+~Iy`9~Y@j?aSTia$6|c!XH&3@6~^k%o=KO}wxySx_@T!}SPMO2@&RM&2zz&~W6P zP{O<@`d{GcMm^ipF7UV>q{PO>SLPDMUg`eD^0@!ERr(u7hIeF&55~k_ZVFu9I}Y99<(^st?^krZ@Xs`C8yJ-$kvARj$dB1|dun zHT2lF;v+b2{?YO3BM`6oAlM5xjdh6Z3Fl4ucDC{2$kX25o`VK>Vz}o$32~idgdjIB zvLd6#(x2N*uA25I0i`;UyL_+=eM;8CdNT{8rV$)tN-U;TwysTqAF(IKwuV@*dw(Oo z=0q1WNpxc@_kF@xxE;gQ0GSC5`*4PfiG_js7yR7;1=`%G%&e)7qfjV^XI`0W7O;?M z_V_#r`*JITXWjkG33GZ?N!e|-GI|sfAq!jJ7*8OAjN$eQyQz(7l@7jhFW5B8}55oZ|01fAEwJI$D1OCC!hd@y{iU z6!0DHy}8G3eeMVw?rNC0{qi`LKGtwpwlAahZVo+(F7bu4PyUt- zTisI6oUlM{K5lsF#lzy#X+x_y?W~}^Ha5e5oijG+guz9pYoR2QDkRHX+e33enh&}0 zbJP<|-bM{h^Q&Kr5u0tpVuS+p%}-MXA=6$s&fJrS(=@xw9bwp9?gyb(TvhF?8MmJ+ zbkPL1du6-t{P#2Y4yWc^623}KA$9E*K~f#TAsy*B|x+SvBee>qZ#M<%keKd+!XmaVC^pcba+qofH(<@?o$u0Bj^C&hrY|dl^it)MO-tAMPmO$Vf|&l~ zMe}q1fULvMQXdYuy&kP(r8EIAdru}{*tKoci5*&EQzcX(%h#P>M5Q}Ss4-|>yu`u{Mb;m`Y4F<_Z<+{EdJZPUhzcgjWZvG`%lu3t=Out z-DWp?Qcelh>*Obu1t2wn0hWCWE8B#?tLcSp^F9}_kWEOa=`cC*RaYS$+TuO^wUT2z zzmUOk^do%$*978v51=K{p~*(VxEfTSzOPg=ZsmFO;$n9L<2fMAnFEB(H0&ZT*U|5$ zfioY)GDqH==c(P(2NJg_@|-xqwA7u7O`bG5 z6h6Ey;8`}Wcxc&(WDMF|yqv#iPg8;ChrcE`84;X{U%o!q8nZ@k66rYa3~aThWBRMG zK0Rr5TZuH4281oE6@o5X5|MXizqk2wd0XiIbECKK;zXK5MfVl86FkrZXM$aIMBk z$XwGT?-74IBW=nw^@jh%!^9Wc2prI)$ZN-6ytkV>O&YxD50dK1{DGrRuv4XI9u8SY zuqt|`IIsjB2%v^Gyfw9G54TO?e-v)3Swrkb35m3PH_3y;Yo8r9a=oxXq<+JFBm9Rr zbJfFkzBQ}c?2tqodK)-B_S@XD`%;DKQM&n-3F*XDdsGHTBZeQc+O7fd2aThzOWcz8 z285xkDio}8>d^JiYV1hfbK`5_p8D@UQtc;T*Bb-iaO&t%k9R2XqF!fB2PVOhUULvvxPIkUA za?Fg1O|Jo@mr$apMG#424PQi8nTQ8m1I~hD5SQ%dYK4PGB-XFC;rwf8;`^aq3`$<0x=>uq#xboFm{GqN63}2@2Fz6xq>gT^1Pz~ z*Hq(?_^q&QOPN*7!$I#@x^0KQ6`enOH@xQF)md~=x%guqig}&Py8<$^Sfx|7-=r}8 z&;OWCM4ApwVVKVH(prYxtG;V%?eMp0ySL7axHkWL3w3gUTz|12OaJG5dKE?DI;;Jb7Y|P_(Ie%O*?Tiig|Gdh`h_eb z_iqZoqS;&r2w8&FcZ)741fk`M)1BaySp~v}#|Q$ZBAms0b=hpw`7A8w>k>`}Nm4;G&wt*06_3KV|R2+Tnl2=*0npK;i4++!e# z%-w8k-0)3YGZe?9@DXO&|A5}=ZZlnY!CHKXkl)zoGa{uacEES;2R3Z&Y@V*>qDqb| zerXo`*IB*XCuCuY;(wx?pI~k8bz($*Af+HeRy?P2T~#S@0>=2&gU=+PW5ZKYr@fME zA#FHSJ5E}IZ50Yp+12D|5A5&=gm5{?So5%-b#XUZA1`oJ9@MQ!9725@Y0;}?Wg`kPL85cPBM zeo^(_>giy*d4i9zaopH(+RGSTD+@WCs~QdXc2g4`4e!dgl+b>@J(niNk2zPsHdfUx zjk@pT1Qs5VVh#hP6ZE+zpVd`1R>#*PEga^Uf|nlzY88@r)rzQ>1*@hC z8?w0SuR4=NzW1EqH!yx;7EC%vhRF`3ij3LAso7el|8cl{v~NjWfLCVOc7|zINz65fvu4gfj$Yjubm2 zK#Cq>AZfLj)1>j3ydY$y%k|U?^md}%Z&LLr`qi*;X~eZkFE?sIMClkP~Alg#)Vc4fBna)G{2nMX_fkB zvo6ObOpAtcFU|r!VIWEO_4(&1qJTFIiTCK%LA-y7;QVC2MGlZz<-z=1lAcLbEpo

k`;2xY%Qf_TVlrj`a9FZ}`9q2RZ>^By}s;O|_P@FbwF+^P7PwM(2B`*~T^VF=*MA z`7RLEv;K?1UqC8Bqt=$fjVjxB^L2FnsleX5=Ycdqa>%8_MKZuYDZt4~Hhcidv%1nn z{sLL-$?4wFFQg?sCI&3o(+W;<_2F=%d&O=si+JsE%vZHWd62=mmRQ9bvY=m z^Awe`lLH!?;-M@RsXwe{cxqJu6@A3+eq^5lN*F1^eKlP^Y~m|FjK^3J=T?m;sm;A1 z{*I4ffCIn4LRVZ}Uf$=Gm7xdKKUiH^PfBEy(OJ6Pnuwn8x)nvKE9^=y7`=b7w%iBs zOFT`3B7`)#+P>{YdgtxRYn{(hflGU>5>B=l>5t=bxu&hOT8mcvRu}j6PELS&t9NU; z`(4+oA3vab`2F;8y5uj{$nE};Q8KQObvI z1hhYpv!1b@w_03l>09$RT6$WszZ-7g`&p915j6Ky7#<^<`CRmAXS+G~pMRz+m?WOn zwV&>fy5|L2_?11|zXjW*TLY>qCZG*x+FM<7(qNNXqs#s>X~Db%w|{yA307g!gAoR;5SLr<Lw|f&_CQc9`JiJv4W70L{%1-v@!i zTNMP+gcO}F|8f7{627zI8)Ko~*zJZ%u&JU%bnLO5H(Z~ckTopc2aDVifByg{8Wu+B z%k$~AHkaI(yzP+J^%|@DP_vk~asd7Yh&(#F^z>$X9dSAp_U~VB1t~Fc#gEsWehTrF zsUHXaDnNmDj*i|0M`a2=R~DY%#WW4~*uh^(GrM(q%vdp$)q_Ap4y_E>(0N|Y&8#v_q)SoXJ%&f3SZlt)_~VPb)>p6Jmx)&h)Q5l zQ;N@p77&egd-(nxQ)>?oa>V?%>;o|IeyajP_U!YeR92(@@Gj@%=!pzMR_n{#`@3tF zZDsIfPX$=t_mJbnb*R3rUS;IqxKkMCF8EhM#laZM!b=eold^qy&c@)9a19%a4u3~= zmtzn?`JC^%)k*PS8iDwRFYf3J(|ge!8$?ZCEbQ7&psd6Cd=bH_Y!HprUJsmk@%2{# zE!tzwT=Ku;%*mAe1P-DY0O`Hl#WSwb?#(SnnWh_G)`Mm5L4ii~zP$}DRtaIrz4d1V z+%1dENtkoxUopH!lFsj$+qJQVDFy@HGp5^xvLF5Z5$d}2i;PubmgeUwZm%z8nvU6y zwLb0+edKT4O(9I#q>tLy-fE2A)0a032!I(bygBK}tE(!$Yc|OzJ}c<^9s3h1MAt!~ z9oeGWLY|a{{cSOcpEtk5>1h{p;6g?!t070e;3Azme=3FS3`kqA7~^)0r|7kjLEE?N z(oA2OisPkVMf2+Kxds?fPnyrERuov$0)(?w%pAj69Z;7`&)v!*#V{$eD{WDA^D!~@ z-ZYGGesQ{|&vgv&VT#&f@pn>Y-@tIE@7}vPS?F2M){W7vIbC9Y`D7rN5Qawq8=M5^ zAOy#K|BWvo4_*D?e)#PuJm*PnEd9`OD9r3D0<6j{yie)(ZhwvsP)zGz^_(TecI|cy}+9e%236oX7hbAX^i8n=eAm^4_vn)St-#e)e?GxXz5uwB|ps(h# zR~L0|?UhQjt~5!X)w``WvntED>3jH{6P}r-&(rYnD6UcmgAT*C&r{D7?jCEvL+Nam z+ny=+w9_+()-kzd+)+zwTD=($it(0Je(%b`HIqfsHH#Qj$kDBMxKCTNGbunEBiDbB z#{KdwFI{>M+d=^^-b=huVN&&@ic9R|lo9Jy5`p&jAi6q&XlahBH}$%t;J@I#+ttu4 z~(-Kycyez$dk*5JSubO882DxS#Mo!4!hueuVu|MF7ocT2M(eV742W;F9 zyrWxR!1^N}VsfDO?BSo#|Yak-%jVv<}etPUQ=!Th{L zfTxX8_!#k)pjc$j1!TA7_6l<*xO;d0g3F>o_&A} zYP_tl^sT?#_7)C0JL&oFr{udcToh4Y2GkwH3Q@Y01f=nL#b<8}DLy&BR2JK0*n|m{ z0Z@5WS|B?P7aLB7)ROo{B3FOqCliyFnuuI+$csTXzQ}7lJBrI%A$S)BR0Rv+n{S)D zoB!=}0oY=VS>O5D;o&0}};ABHOAlA1U1LF1xa%`7X|P z+y}=&4>1q8a$EY3hJfoq-v?;rZLhdrsp)dFkx8pZ$mSEIjukr7v+ct%&=-YsSz==* z!;3U)G>;yid>sl~66Wa4JO1`p>l>#Qke|KTk!dbizUzCC!Mj}G_Q8Nx() zk4aXo=%h8I(>VKGba@gjtAH-}sAE*7iTK;f#XxOJ3k5giU9bH?d##U5G=0mr!k;L%2dqYv1WU$ z+TM|RvG6$6hS%tmWs~TV*(hXi{ zsiR`UPIJS9PQb{xXSjM8b5-`U2@XW#bO3RtDV3b*srM>cv4!-S*q1BuoH>l!l|LUp(9YBqpJu95Wt_-)OrxnX053Ka z*UyJA^(J;W0h+}|82UN@;}25QV2S#@T8^WmBWcmUME{>>$)3cyJcMJi65F0m6=pIW zKB|`&`7`92IP<#jcWOVbrd z$5j-tI8K+r|3TKN{(kC`8bMgLy6B;Nw_<==m*Nkn+#V!ZIu1)G!5g#wp!$BO^pBbN4v8 z>ky}EcC2Lj?}Xw``_A zbIdXPDYVr6&5MSoYSV&I*>!sY@ox$~{Ar@cGpF`NlWPuPrXSJ2EEl=Vx%Xqc|7!S^iNk_;*yZZ9ZnqZxnwMg+~_#0PuGF#H->V&h(v>pplJi zTEpYOcgrLOlknQVSj$_jURVxd?7JbqE2JsLDZx5R3+$aMZDoyW8r*Atl1z_NWj6=# z%VA4-<9~u32qtU9NQEsadLdO`$)KVPUY<5msl)S&i}&_)pWiuoC9Rls`)q|>WpzFg zdw@{QJe&}SSiBh(!h4moyb5{UWG!#g)FNyTnF&$bG=Jrkk2M!*$XMP8cKq<~mF;9|I0dq+fBB%xZP!cR7kmk+B-91=MzlJJ+2Eh+j@OCu`diMR zk>RNrDIQ-o9-oL1jRF3~`3^6nz5#Ozkxmig(?_B9D)IR0MxyX3B6sYkfak^~T#pSNm*hXwuU^7#Jfg0PUch{aQmT7abrdte2*CgLPIAi~G4*fro3P`H{ z1wlrF(!op|aAG&5#5cfDa1-zk!);3+N|3etNhcmWv^sP<=ttafwMBObS9wpL5DY>Y z2)FuT))a)+wBw$dm_8R@*Dfj7^DC~KsPL1QCaG&^05Y)PR*}6Rpu-Q7Yt@2kY8z8G zDz9NX7>`_C>|{j+|5^SVXdr*w9DDgm=LM(S6ubT9#oGYWk!(9s!OMSL-l#denWgRQ zeddC_XdU3PGcopqF$o+JV2jQ09dPNDS9%-&%$Tc-;vL{jVWap-h>v5lTh@D9{ zCf!bNv@NK!wGa>XXIo>O@?7?AOYOITUI;T=$_~-nY9@s-A%->aQ@pO~MQ>+Pr;>Lx z!m1Vp{|iRyPXFDbtbtE_G0M4qBu*4Sp3N6N-w6~%ZLN*Ljb&x0)ck3=agV;Zq=&g( zL)|Lw!?*Cr^g$onnVjV7t_V$*7XSlMsD*w|&@;0yM)U_*xmd$mXy&V(lR{-v&6|9Y zz*`iIou(i$>*h>1abGrpY2bCBteH42p7XJ}138{{%-2`vF_8n0!wj5j4{G!f!5cw&MOMMv*6QW)yA`0?Bf(0n!UfkcE5x-lSJ{;cf z6D!c*A8ZOA5LG_(6}VjbS(3rKi=x#f3T{@VozGk_6g5)`yFFO;Z9TmdBtAjplr zUhIhzZ09oC_J<&qgU=m%t$w&(SGaDgG7UOnmp((B9QP$Q4R3`XgPFBy!%EO;e3ndj z)aZ#vi{RtxVMg&%8pPObTDfWA!lF_4(QeBLq(tqZCM;90#RC|7Cw@ln%=k(z+{ObD zt1O$l7b?l!!F4#;xV*I!-$63wP=P|9w%jb0w>C4a3NyZZOpRaSt>EK5?^tolyZTs; zr4y^OyPmuE?RE+#hp>~z+xcNfAVdT>8rMwPI1OF=5;idxtXQ92F=jpZxv@%rC^2}@ z(bM?PHt)|nJw7KIs%7%41n;w>@XTK)Gxy`rtmjtlY&tVDj#hAQpa2kGn-Hv=$r1EU z2D6R)H0D>>s6|2iud7Q$a_|vIlkO`D1&70<;1<9Gt*68!`6u@F(I?!A=ewakKxbL` zalf6{`-Z6l8&Ewa&dv5d&6+#&Q0Jpm0cgj2-)OyGN@FLXtWje*Ia~s30cJWDC8)7g z6v41(Xt(s%?HBPzVmqh4YnA}cS17(z0RZs2Zf&y|UApW zMPVPTk|Sjwq2<#7o)4T#oTb_JC+#@x@GD*M-XZxqVdT_kJZWUkCyagP+s0+yWMs-O zUxs|GV58D=7+#>goyn(heJGh{`%@%k4X_mckI1ETGOyBJ$`sB52>rf8_qagv117ro z5)?lM_43tJzM)*qu5!UlVAg6))Sq3u>#00qg;*h2w|ZBO!fJ0~6rVr2#`?eV9-%BL zwkRrp*-tU*E;xBX&6FgmKUgUq+M)@%HNO?+=1N zv^_8k2LmySlXebE%2jOff{V4)`FY$}pMI*CpH1s>Qw+_=O#I`YitvtAotpNZv*k;U zX11wJZzY-JX=d)z#;2YxNW`DzN33FZ+I1WEeBVt+<;$ zmBm`QwRz##F6^)h?n{>C;ghBwbt+CqX|FvM8ND7-8+-MCg;P4uBgd;c!;WYtmW9#f z;hczHdUj&g^Y4rJkq)VN`WwTxV~~g2;tNmHC9e^F(-Gqpab2XL-(SS1=4|sH+M##p zhzPH8w1CcYKfVOs<;u1k@5`fuRPhzao2jJzy3c3L&CS0^NJy^5x;GdZ7#P7(BO0^7 z5#*z3I>|FATz?a=pEK?WeRa6K=2(a$1~s-n2EOf@##``AzGXVrC;>XrlT(JT!2W#q z(0?BVhn8*k#x4YY@P`qLltbAW6LA1bzV`Tl7vZb?3t$THd6@q_oo$bf=Z(+GI9xw0 zI%zr-N6BlD)p=VhIFYt9mV&_wGBZyBYX>xrzrI863=)XFnViO3iHRMUAr!o1L)w_^ z{23t^y=hkZRNZ|yU}5&OoFE-f^D|PQ_x-!Nf8*0FyorQ(^RhcoHFf`=k|p;QeWf+O zJ=dgP5}uJ<8xwhZF?BZguwmTrAGwPRget#14fHv`5&mc+1vx8DI+f(Hv^q4g`f7a? z$}^y5RNKH39R^5pKlbXYJ4Qedxhgo$=!Le1ChryOF?^eo3p+*VJt} z>_uyiN*?5P!-ajI=N9aD1|JI(Q>f8I+RTuV#}7LqyKA5XAqjX36{zWOEc30g9XI2G z>XX+*R3Sz`t!X2+X{Yj+Q}6YYaqUTJa3UZ*UW@bPN0Hg5T+hT9o&6BGeM?u7tZuW+ zvn}50&OJTBT;d%s2TGiKF}q-jGPx*}-{rwK&$nE-w>466WB$4lc>G|8volEF+)r~areys`}=Onl0kx@ZhsX6{~%&zPxrmHj?zj8@R0J9+j zurGIbvE@sZde0js+<#uotRnQc7=uB|7Hwh2vET*r;OOwD4*0?cg?)O=WsVVRpFYeP z0QrmV3kSzXyPo2a`F`JwTg7M{H!fsm48n7knEEOCS(FQgRW0F5Kb~BZ%WOv+<~mVk zgRkHZ@Y8)#2KtiI-h0geR#Tk5ReTlOe)`s;o8(vCc=oya8&_TzJS%0Wg; z7ei32oyq7cvmI{tDjSghfK*x)#-%j0Sd1?1&S%9v{!bVarWPItBr87el2Vj4Z)*;2TW$lH7Sv2xVN` z+G_h95jUkWf33_#giWx+-sFwx*_$`<{2=r^R8@fIXAi9WUv=FLCTp$I7VRmYv5`em2k$D9&!s0QE+7< zwn^cYtJu8eN9}|0k5^reV~iTx7D9tb|G( zdY@e{o5P@@k){uBu+I*=6{Z(_+jK9>Kl1`?0dIYZ1CaW zZ;tL!h~}f~AbHys6mt|qIjHm?mIW4?FJPezmALs~mF_ZpweIbR(NkiYyvm{-rbRvT z;tsC)1iG1Uk0S~{#A4N!oV`Nh!e<#v#7{OlZdg9PS*W?LG;FfWX;7`J=X@ zyxyoHlq;j;i))FK9g7=*v1RDZmXa4fi-*VI9NBDInf-jV@Ex6#k7G>pxBKU|w{?q? zJ%|o1rA{Zvrpf;NPJ{g7Di*(zq0b}LV&yO7VybT$_6#b4TVAMKh>U9WPIf$t`#zEyJ2)OZ zMKEd^vh>b?wT&bZ>%S8Z3;2kOR;h8|PPsi$mAFum?$Jk-KVMy-BRuj?n`nRy#kP>a z%~uf%V2@p&2|4E`vg|}YF?XniNs;OzTzc5^eNVbS(IJ_?FK=rm06BHRrPjg>-?=M4 z)?M|!q7w03>i@eKI|9@EGF@U*C6#2=IAVG9|5*SQ0&U|jclL=C*KyX@^sB-f0G{dc z4)7=(U0jWd)SWID1a-Fc{+{0RiVLyVKs4LMh#+HB$HmsSzX701sl$j`4>K&k`aME? z)dSwl1YpTq{_jf#Od}q0cO4X&X&&Boy_!2|0>U2K_$-@YP7iYz^_#|S=HB8kkPHgm zRTyZ${43?0d(Ebu2B{_XK#Z_ynXWXebgeS1E^2r5u~IZ%GXBTdWh7Rn&j>)%>y2DVzK~om!VBb7xdY2blF!j)P=<4)_H@b0MV{&I_(XB2EPDj1KXkl8}e-8FMnRvzEkq|xCy!{E#qM~^vl7R)0X~3>=y;t zO?vsWn3=2E(#L6B#;8lad!NE#^vE`J`?vc(cHmWmpdTBaGDvVp9JSNdax zcv-Kg{YO$XerWRgQT6`0*i|f}@Z0?u=4MeU-%+rAgT0W?#po;zkQ}Kgn+mg!XWgk? zd7yPa2KmaE{7i@~Tc@Zq{w-JyN`5ewifc~XUUJFieWLwMs*(9CNPmKFK2%UrfCgcM zgK1ikrsl+fixjT#=vlKGN5|0WL0iN0+XND6R>m3FpiAfe!cGQl_TlTFyEdKu@q`pA zg8f&?B*Uy-7wXFXw|zbBYM%IDiMJD?fHqI5=M4-b022h-?UXOLKxd7@)Yd>D+Yl3i za;~(T0a{9C!!9C&0vV9Hk#@$=mUmw92d6;qm~2P9XKsb^PicZZspecQsm+)F;JRl6 zhuW6fhWv|g6kxqQQPGT=876mcUB5zj<@#0OvE^U*3FUUR|AI)IWM&ATn$%57s|VOp z1QRW0?q#j2&)S}Cg=M7BspBB6M6vy-ej@qZ6h8gp{FjlU@9}&+nA|=-r<(BQzC%n% z=q#(!?zSk0>BZ<4E?(!8Il%!M5{-~+RvZ?q#!HQcUi+c#EE!T`;-gKgicf3S^#(ZT zroOF#S@Vw26Ra)<2l8Wo-kQhn-RU>hN&8)|xS{*Pbo>d<(an}*$+Y2Ngq_o0Fh4}e z4DDrJZfI~~A?sLRfoJ*OSd+!sTrcS1TQj+>12Lg9mlu~q0udZ1dnM^P@<9e4Fh!pK z;BznMVO~~BYO4_?8~HO^nuY{g$0ePE2(pN+qSVR$A%Bn=xX8v5?0z(;d^vQah^XGs zS9_&kzm<+#wF*2C#!-?c{TLWAVf=<9a&wKXC{NkhzyQ-)$z;SLMA4sRdsKC|2i%dhtUt^Ew8^Lh|Gu}VSI-O zdKV%}pa1^+t)Qer2NjD1iRz~o8&(7`?1d<0)^@|#x*U63)oh`m^Wg5Yp};>mc~^c! z(htVf>V7Jj-^5!Vi&T2AcmwQ8;jg5D5U1o(nirhpAq zCr$v?)y78o<<{mmj>Ze63zQasi=QLy-*#Ioi`f}i5g@VH4@N#h_BKv>%q)W?8HLsM zo?35#n>|3XLNiS3g{80wvXE$Uh=l~C>Qtp&J>;5>Qgb80{#iva*%uD87=3tyr)mKs zvy`tMzVhdO+sd$YEb7!Mo&5JXF*Z+-Y)@U%sfJ_AomvDugzG<1NFoB=Vw1dWnwmVt zHE-MKSl%S}P5Iu)3L<9GEU!${$sdzcsKb_Af-8ag_$pcc6sl%5Z@bC-)APxR%-d#UvJadhTE5fK*84xSEew zU@|6#(D2t?7ey#Y&hM4tIUUo}Aj5=N%dG}y|-(O0B481`89kT1F;cHuB} zZcH-SCo?M)w0?J~bLT%HYIHy?JXz8AQ~`?4G-u)0F(kAzaRKRrauRTvK80)`Eu0L9 z2B3xT4mntpIRj|0nW8}0nbjVJ;exI!fJM5j`qR%L6EHjF+ezksljf|=9LzOyg)63f zS#(DR>7O&nV^qpHvPhCY3HP{GEmZsogD`MPdYkTO(6PXFI#Z};`;nf=r-#erG%ynG zA+e3%_fBvdUD-mf2lnVOSEnWoBhq0S(jV*nH)uplXT)j_-LOEEncvwT`klJNlN@Hd z5aDf~*EMYa*X-g9!m43F#RnW|Xrx7iprpMvcnWJI6S~7=-}pN$Gy|@PR5{1<2S_k@ zLa^-b+!}=>nTkU2Tro?qPK)ZZ*MnXWF%YcSh%!j7hzDLp2&80lG2SF;G``9YiLg$b zA;9jW(v}dz&?P15Qx?u(YecR6#L?$RDpK|wuW>^`;`ll~PU^n+yLR@k1H!&x-+%83 zQU)=J<6sXjdI?+NQ7i=y#IAB>MCdQ<#1I<$AT~Fk8{gVpj<~B+iBa6`W7F%#lH1x6 zw+*77rjGu#J`w@GZltxII)`R{b_}1;DY(RAibmx$vf9uytH=unaA`16zQoercC?%|0*;D=$Vq^;6S;?_OVuRXxx2R zSUJnvBoDcOlNXd1>r}k<0|bUQm0KH$)-uyqlutQ|U0DkVNaaQ4JF+-MvxQ@}sWkW8 z#n0KZIOQvjfaH$fvBb~}Iyp=WPaEAum%Ju*kVUn5M$=<{5*$ja-d-e_uRK+`1tb8B zuca#^j`}cAdy=Z^V7Zb3`h%-SD5Q3%I5Ug#<1z+R!kU95t?38(zkBbz&QnH=m-lyF zlm6``-LZp}R!zP_GO)KdB7(aF?MO&!p6?j+f2zdtGQ=UB@Nsc2wCJp5xT7Zv-Nvu8 zn6f9)OZK}7d38@Q93*B+u1AHB5Pe^UFm&yDc8RmFaP?RNKyQWvULcr1?t}SvN5WPk zc04;<@w73x${ZYsnl*=&kqnLh3@*sf`T!B5eig{iAEuw{mEAl(pnLSjTn~*Y;Sd34W%xsGa zKr=IObuQ!n3Fao|u^6`n)pe2kEu2Y)vIKK^2@)5+)xO&Ou&$=BOEgPGTz@oX#jo+P zUFEV}O-Gb#vEqMHx*cdF*29`JG7B!wqBVGS6kvM+s690T?_KnLkVazy@*%&X&)eYv zOcG+rD1{;>)QBs+TDg}*8tCXCa{-dv1-B~f>3Hn+fOtY{Y<8zA#-+1}tp7#@EtUh*<48HZo&)YJ`Y`!u(srJQ?c`}~>=NY)4 zW1ul3F$C)hmiVvEy|cf4t;~-CX}GzPV-o_(T^eWdm}QDw)?yMg#^>~|Fqjy*i`v>G z-MuQaqe*u@@YhOlNZO-@)-&TXeTJF7=iEz9C+UB@SX&;?HxdJ6Zs_bTlFk0KaDS)& znpYM3gNmYdn~hbHeX!5F+fy)9;vU{OV!6A}wV)=F)$- z(u85O`$Cu#A^!9|(HB4tv_h?Vlt>PpwSSfOS&%uP@=62204m&hnJnJly;Hi8G8ZRk zwlOFE3a}GmGLzFU&sBV0#8i$vT9b8n z2ywz2A&u4uMvMRJGBv@Wk&~z}g#dm4G+Lp!wnwEAs(tTGqTVO zd{dL`mp4__E4!d+wm-l*U;QfeWf5uP5pg~I!laS*Qql+i+j%n0Fn0u9!0X9$My@c%h3lzJ)eT-5Axu9%=-m@@Ga<|9=2xm$yRHKh zSTn6fIvH)@bU`ji0sm}}^Ig!RRQNxs(2I`H-J{3#FH|(;6h|JcjH>s)C-aZ<+RpS1-b6B;@D_VB=eCdT zFs2=Xt=aH4Q}j2m*H~MTC4{o8)du#{bXV*4--q`D8#2j{yo zl7&+*%Zxu0=s27D#|&))!1+DyEf=*aWS`kiS$ugU^@?K~&)$rM6aX;>Ul_ z6q^qG0m!kiW23^a+ppVl|J5!UwH)K-zNVQvd9w2-GyhGdm3#LM#*3R7^{ae?{_9WK&1H%ue6UnSy_f6a($nayt_d zCR{xTZMERmzP{MfrEI+nW{Z4n-obAOCSh^6qEiI;kg`|$6_T?uMt^4b?)=9@#V9=$ z|Aol8yf2BIC@N5mqpe!5*hbe}%6hskL{pYg+{#ro?;qWa!8R`2?{qo7B%?soQ30{l zMc2%}jRaowZ(U;ym}^f1G_2 zkdgv!!e@*M*IIBx6ojbMqq#q@{**?-$AR(%Q>RnckCi zV7sw`(foljAfOW$?(-O;lk440xi{|h(>}^spyA;ilM|YqvAjd|mw49rc-F+oFkEyC zU=A2YuU7lB0qn7E@ivx-OwNoTq^q2{v&yRP6;@n9Ql*_|d)Btd8D3;3F5nO2T0sqP z!DC?|LLA7=;pIg;lv|!cwwI6lWzYQUy!hl2P;SivTNb5)kk0jvq5*10U-_ z-i{#QJC-aS=3yJG9cvN2VJ|*2YP~VXu@e33?dgI?l2>Rk)={QZ+C4k@@ZrGXgb``v z2u5m6-G*EHiR}~9h2P1i+H}^o8rX0GO+PI|O62kM4a<~mDK)^l>&{_E;$A|) zDpMdwdsom{WAEFxuz#$~A8JqJ8x0xFVGa2-)GBd=R>t$O>##J_?w|fdsE?f4Ozoet zBlTNINsEFC-|rjvy#-%SS%dJ+nL<$y9-`=LtdKMvoS48z7+N?#0DZcYn-Pn4nih$#4@ zk^T1b>V3fze9qV-Oi+P#cG|39sUq;J?N`X?ct%h%)`d{-Qd+X2z@BiphD`5{M&q~q z)A#Q!dKNxY`zm18KhVCMzD{efc4^Eon+PJ%$9zm~B~~TLVKKvhd*m_DF;a~FUHvWJ zKKHE0t!yw@Zrd36#V|PkA)p5B82MX9Q8H0aP80sm6xdl)(meCkPVJQV0zJS%Hck~x z0a>NZWMDCk;p%-7sPvVcmxidr!Orf<>gmO<4smoV{$`86p|gDtebEfrdT2>hOEmF7 zaicGXk~{W_hb9T_w1C(FZh#FjJc-VIYoMF<{D+Vrck#Qiu1FjFqo-AaYPmojJYJI*8L%H| z|HDQh8N3%#ceQgqQ~ELJpF#61ho`{By3iXSA%uL*&V|v_yczirquNZ-n;%+ z3eG8z1@f5DTQtB;5-)NQw{L0JhhU7+5^S?wiaIevs`#~|`dfzI)>+!5#D5`eVFKbU z?iL}orKy2BYU<2#3lb9o#*dPd7eHHlckkp{`Px^;+cRS>&$eHzZh!TJa1=u+{M=ju zdDuj_L81PjW&dR`P7etLXYO~D;-n}!N+qC05N3%gdf5Ih2DvyacObKp#|xeI1v-du zVm7r*aI_16aau)G3dLGuOz?(9s{kFb#*kRh%PXkGO?%$mp?ZG8V*-Bt^KmuiQ>zst zp;%{KeBs_}9*)lGI|G7qx=;J2+c1F(QK4kV0#a6@$iXZN*4HCK1V=wJI2i5{FzU1P zu~c`H&612nrqDic0BI`QF?j$V8+*5>if)>O+~jt(oX>X881E_7i0NmtIaGlGhtVh z5?kn6m$<0=xC*A2BAFY=IQl9;ZQ_YI+1F$&hMTdy`zoU#z&ewraQl@yt=weDi{Do8 z!)VZ9Z_o(&%MIBKS!{lD^JTW`7DdyD^z)MlARc1Gv@2g7b7?~BDBE7gP*ii#qaFyT zK6R4q2Z+xz|MpTA;~8^V`Wc7PlMB#y`=?<)PjvcQ&(3&NRZaIa5y#)Y6+&rb&}#yqO{|TZm$9`hPX0g1;x{WOFNg z+;&drl)%nO&c-j~7kz8z6qxl*yUO1<_Rq-CLh-l-Mq56a?5x^>&syU85Yse%Q&8;e z-W0N+j8aDOnmvQ$%NWXv^c4{WlDQh~obR)2aB_R&J|FuEHgm$?&=+wwI=bboMGX_`u1Nk}Em?2zCbpFBl?zb+xk!`$@WSPXIPQbbox_ zy(asviWU1mK$lR3_vWO3@=1@^DzK9TWo7t2cmqqH>oi|0dkMdqLAlW81v;7Ru{!Zp z;H&XKNB|YF8+7*KezgB;gZPRcD=sMYIl?JH4zGyeAK|J-7VPI^HFL>4F)G6Mnq|Lo zRIQNZg2F)CHu-VqmZ{k(&Z zR=O&fi-Hy*B`uzNa2~g`xkHqimZ~$?dY|kZ*p_NJjeKyu4)D{?jk-*2zE2LaBSwnw ziBaOCwj{92vi{d~QO%8jFS3|&9gR5YI2i>Am^dnoRrLzjx>?I={uk|xU+HA2&X(bi zk>rb8GeD1i*xhY1oS_J<{#ySgl@WW)vo@Q;v30w3Nq`Tei&hW8*Cc zp8%QJVk%X%LP@zqm&JLm^}54ljNEMZPbS8K|1@JxRlSBe=P#H=t8JD8O`5i8asKr3c8mL3me*8 ztDf9N*U^-n#rV*OO6~=!iW{*A6WCk9WVzS)o40WXTT8n{>Ys7zP#@AD#25E_S}~iG z!%2meiMLEWN4o}R&J;CEjq{F={i950*hLQc4VI%p!~3FoiJhubSWZzyqI?QZS-2VP(NEfvZ=(OK9qc{cP*rpNas0g$}-9hS{^NnX^f~<#A8srS_Eu0!{b2^2${{;F8 z7x{e80xraIdZZ4`J5rk`HTXyWkl~pn@))EG4Ip1+vs5BIfF6;?ssiu-mfhaB$rhGf zbDnh#=kpp-eGbt!kq2x>I{El3%}tEB827w6u(|bR-JFY?ZMM$&#vimTKmkEvj5`*h9Fq|eTfjM z1<0MPh^g9Gjy?s8as{jVt*PucE2ubhK@<)09Yg9ezk$}65H4`;i#|izQ?|1G?^jIJ z>Z~O(p8n$awNC~DL4)JTt~tv7vC^vF#nPRoU1-UG7qWUKCBur8B_lRUy=Qi@cN^+^ zCHw-zXzZS}3>6d}j$8(rS`&Y{)IUfGn@^vhFc6c-g`J%K(O&76d(=^O-V8rg$UfuP z%ofeIMtndz*k11&}Q)Hry+S)HdG}S+;mwf-SwT69>rsbat#~P$armt@1 z%OA2^ia8GSLx8;zv`wQ(zv44!O7}kmEWO9y3jD$`A=|$GH#L`U$4sJF3?WbqN2}<# z{fBH8_PgPan!LQXM_yN=6S8|clmUE~+y7?cU@PN>Q9Vzc z@v968_Azb~Q1u59=jpc>wqWnqSEUv$;?zp}=$vGf=IUmPOx5}?Vu>Hmr`rs$SHwRG z=Q0lgB(Bw1_MYRgAS+IY0#kncWuP~R`u~2(vQ_*MM5F)oWa3lUMG-PoaIHaWf12Mu zXEXh#k}5zEVY!f6gC$vnB$gYZrtV$oFpf#)!wU5O>e$tZ@ua$k1T|Fbd}YhA{)K%? zkpvWvnk23KuPnpFCpr!p_xJ1~Y102hu)tIICF0ws1$bRerY!8a1Ie0`Q=?y zN}9eZ@}cYgGZuGj)ExJjka};93QPGMj*eX^q<6*lVA~I+Z+gmS7NpW8tul6Z{ph!i zTm#w*6gO{j5JYnHZjq3d$f_ivj{D<&L3K5PDr7!p4yF=V01YMX(~pM=5eW?+g|Et) zF}NCFx0Dh!GbhPS4*tXHD45Dl=`rvv2(o2{@e`_F=r zpj*4Z6>^E4j8(Ly`Ty%!e;Z(+uJ&j%VK`LVGPv7%`69T{fq+A-h;kBFVN{|6f0cvRMDA$70qi#1 zt>;A$9iY;9wKVP;v3D5mb<2VXWk7#G^i&S#QuP2_| z)=+F32_J{=0Aa=7=3ffZEIu~Oye21XD22ig8*Vo{;Sy%OS~F>F2x`C!ZkdIyYzkjA z7)InZU;+s3FGNNi6BQ;1;a)ES;gLHpv1y{?SI>}aD&GY~0`!3@oXWuPb#cu%Ij2OE zB1Eg@T8KMThvZAHTFQi{V7LSTn6K#d9Oo0 z(_8@eS1#_bkrI*8a2j{?fwwc1@udb3#MsEVOhnuP4S}r@^u9DTu5`~5|J~Xw+rpuy zySLASEp6hjYxCasOw}q=1yjyIW7GgSh1sK+XO_f|M97;1|52ZK)t^}E3;H&!jIaqo zxz4ups#)`;*Dw{ITv9GkR*ZDuX@|I1) z@ACpJnm}~uBL!qQqRa;pEAiUPGzT7mkn`xp;*Z*k(MU^gl5rRFvuL!a>lnbyfw(NS zJgjOo?r(XeD$&A6R$JN24wZg&H`D#NnBQ(=3{E^OPxmhuJnUJ~#-eHG+Jb*JkDn#X z99>zKz3jN-5P$s>hRs0)3*f`+K8UaJjqB$O4<7WtPh$?IWdbxNcA<7g|5vb?i9~d{ zinTqT3_=24^lX8$t6)+afu&QVx&+c1d3qZ=ON;+;h`#@s0Sf3Yfk~k^g>YU~U-(zbq<#fN+7%dUH>;}!{%&1+C z@ba&XS??5sf_|246-C8E)BLq@whIb3;?V$a1a1mxfX?DR`|C4C6%618+u$?RPPxy- z{Edd>g-rFo@Mnk|u#`iwACrvQyv9ge8sjpIRX-a?9opKJ$`L6Vi2yHz@UGi~*iM)&0_odI1zgIC>>J<;72_kquo4q=(kKCo=#chC-@ zlgnn-`E#pPtEen?>F><2QDPp-&J}&5>QW zxhsZxvYFKAqQ39UnB=B%;N)WJGpVu&%f$j|_OnFf?W3XQvN+Z8^8bqr{GzN7udJ>p zTul7cqPZa%-7`zNPbc}zD6iDe3_jFxrJZXiHV~)xxku47`Ex zGWFMC2$3Sy5SxfJ-`}(7fUBhMK%74JGqjo1cYFn8ssef%nam~)Z}%jD8wk2+9g;JX z_z1@W^VJ4`>{OVHtr{9`HkQ0`dP4TgX4pIp^mP@$Omg8i6PjyTVN0bBB3#xKRl9;d z_3ezV;w4{Wq4SJf*y>7F?vH8J{GL!bN!%2ta>wp-$mii-(@AOQ+sn}*RY)+<%gqIC z4%iy#2j;1L1TOZE-;;EwK38{G_XY>J{MRJ}=?o*-yb`Ug8usT9P=Qwes%2d~e0%e= zBp!(do>$j|9P+ZP9=5_;ltQ|P_;&&ws6s@pff{qJ(N6mxy1**v5unoT5S?GeE7V-| z%1G<2;dBzk^n9T;sexSgSY3ohns}Z{qLapkw{e6TmS!>rEp2HB`m-Hqil8Q9tb>8wVu-uVlBe$_*&;CC$A@el?@g&1C&vUJjp4 zP)RK&ro)u9R}}V6)GKjx5xTTSm-G}PVT%UGNasll)laxh3#!JY-tYZu?G-ZgwZ-zZ zOb2A82jtz72%rPTLI41Y`9N!mr7NYB_Y@bj?k)GoxBp9y_*nS^EdyBVVfFNo&x!pA zM(b?Oov^B0-C4c4|EeGiY<1Nk!mHl!RhL)LIivV?X@x6Ug;6s+a3IgWl>rC2`y0w@ zC^&?6dC@$%l%oDltP3)KZ}#JKe+pTPrWW_T5+>0s^~uYheJ$qWZzXz~b#k=j7#H+@ zR%LIj;NL$yzMl!gC9g0Y%2JhwAgh1F1>oN)A_Nz*dM9uQ{2X~OZt3$kCZ_cPDXhfk zM7zce;%uuPX|`3_)lNrH{XJM$Xx)zMp>rbOutGN_jFIb@ZXC$&=g(scF+XX4(7gIr zM@I0#Y0m|pJ=@OPTD-SH0HiZlY)ZSMSp(ttp_IRnV-f?g%>G9HuVc4146$F_nIY(P zy$90%U}lD&^*PQs#9y6h8SX8V)Ue4M5NGi<~>inu#vq`Z0sd(Psntb(8mLN_OViwIlH9>0{uwEYKev!D8+&sm5^% z7e7kKcSX=Y&wgXji9Ev;l=Dl6#E+efL$H)pwP_}><<)%yhA!9RRJ=mYcy0A`HxoiVvw8u@rfiuODIvG zn|`~vYhnoHc@4(q4LNuBUjXw2z!QT>A?lnI-^)H)|Ho#AoR7gkU(V7k1)W>W{W(-2 z&}B{~Aa2P%?qPNr32knTsz0i&1wxXO2f>0e1+H<^;`>_%PO@`UJ7WL1w=*hQME)96 z2!8keUk~ym9p7x#Y$7XmFD`x$CJzr-BuyOx`z*$M@U2*pBQ+S_b|=eZP%F8<(=SdqLjZM8h!^vm zsf?u`k8p276h{ zWtkyO`{Q>*miZs)<;+251-KzH+@U7!glNTQXQZKcK$(JYHM-knSe?MSkqXm(#B92x z*xcG)3daocwkvUPFO&7{L2{kkYdMv)DB8^(c~iE#h-0&#mbGwpVE1)#^Xvran95kr zxUlR5S2fl=uYL1vn(A;;lDSD`^J-_axq8NCWLquoJ%^el@D>Chs~>nIe-H#BK_Dy_ zMF4;}FraOXj}kkYYVqWf&Ntm(nY^0y{}Q0uP{dE4N`UpSAW>WtpIFgjqxWQq;NIX% zo@a7_nbwy^A5DC`aAJP$CiHtXX-Gz;juk|F9V` z;<7jq8aewvCAd5p2H@(V^!RuVk+p%)W$NOcskPK{Z<_f?e77`(cxg@Xj zwH@CX#Yh>+4==Y(Pn8N?Le-QC)Dpgf#Hj;Ef9^d0Cs(-%>`2j>jU~LmiySSGRJaQx zDCjNfebI9~$!r)#5X{1^#mH-SYAjS}>9edbW#+D;Pn1+WJ7cfH8y~W2E!ymC2YSdl zLI#)FS2BbyL0cDPq34ThxxV-=m+545r&rP2lj!%H=>b+Reqp9O&!G_f+Rf}=HUDj> z&~!33H_wloH}ZLOR`4JDy09CuFtCw7czwe;f7oF=o347=O1Tue+x79)VIshV#(4=b z{kpUVt=J?_n_%l#^#BbBNDofh<$_M`zqdL0t}B zA)7{9&uj!;u~ndOHw7ZKAa|oc1#Nz2$5K{Cg#PdzMiAJYkQ&WdoZN!qUrXZ4Eb`Q0 z%liZn*A4%Pg$#+sh8XJga&u8Wi%qvLvDDnCU`;B45cw_9E9?&zaA7PAPo%qrmeDeX z8sOR6FTOztoa|EUqhrg#o9?c~q5Q1XZr^cb(hgfwv8d9v$H<{ZF3%*o2qFw-ECk1tR%awIba zl@Ul#QdD#ts~8kVNTiuERp1)7K8`Fs*~&*Z;XL`^dNbS0?{?Tyqf0hgre>*s%Kwct zBh!OYDcV})-q-4uU0Oqnkd&|UQ-twTV(9(b0I_}oXFS)v1|$u_wsaM0GL*qh#p`uS zE=OF<%#Q1}nw&xvhi;!ZUZV#UYSOSK&iZbIW5a=2%;n6`G~8`Q6F@eex{+1RA;Tua z;=aeXLXrHUJ+PjvF95bHTC&5G#97jbH9-FHA$vJK@O14z6!IIVoO_Kb0Nh3oPSa?) zy=(cK9^%l?`~4y5N#pbyrdao-Oc#4h0b7CMBKu?hd}#C^YThm2q`*P6|LrLHm&*~H znPgH09Ud0tNGy>%tP;R0SQ1Ka1?4{7ZE1%{6<%~!=4K3c`)t3quKmAj6`}bZ8Xe@;NgnIH^rAzsF<59IL*dpO5l|b|Bp7b0> zJZ3QltNf4-u+h*Rxg(yx$-8?eqlqeZ=X;L$yAK@0!@>Aarf%(R*1>X-cJwicHpibH zp%y2U-7E36Y0l37V#pHcFHojPfUj`^+2tQ_q7wBfI&Ib<$O`(rj%>gDdV{Zb==%?# zPkH|Gvhi}G^=8v(n#x~a56<2WCFKOOvc?R@|GAGZmhzHXSUIs3e(~hDoJmH!_FGs$bpaSMf(gzRN zirW4DMW<`VVx+?Ipm=W*$mEW5V3&k2Cfgfh-7CT<<5v`5J!hRV$M(Lxp$oV(3fNiz z3xsHZ#{(uhvV z`COVT>-Rkq0{dp-NuXvp0L8$EzkMQsfspLUJIR+I2xcfP+$a-fm;8UDfH8Xj|K)Gs zr!KJJr>|ho`&aoojvw9O8-)J62KQN4A8+qtUsr!A_#dGGIn&wQFOm^wLJ>jlX5Nk+ z+xbHj{SRO@GWR0EgOS5^QA%{5WBas6uv)!mShz29K<|rIl)nDm2^C%2FY*)NML>K{ z;6ytve~}^a8@|8=nhB4aMi~7|uSK%iX)vap%KgQdsNqyM;($J%Ow&{^lFeWa6ja!V zbL12H#WQ@2HXb-NxK6BY%Np}uJH8AdKvcMvAS*5|X%@E{77`yS z)zT000WphM`$fE%r|3P9g`@p&DwdplO2}3K4G-iK+_c)Vh@>%EGS|P5xg(zK?}+F$R9ReTG$qfnc*w8Bu>{aD<_$&)$EKp9hbL=7#gyJF(qstF}U4 zYn}81K_3>NI9L`eACX=riCmf`SV%*eWUQ7b_qn>M>tLX3U}8{L0#|~f3zF!yPLE)_ zE_G@mzW~MufOi-78JTg;8D+6PYN*6?i$aK-G_SHooRrldD-dbihbygw#pCBXx43!X z4NXCLH_TPB$B&$zDAP_6Lmlk-gr>r0Vi05LnE+JLQAl^tIn`P)!qtHIaaY})hLC_g zqt2}`i@8Uef^*rU$QF4H6YVZKYkvhq$Fw#9@$PHGSe?JN_fme8nmH&a3DdK_<*SPU z%4?NT{b_{U@q3xLj{f+R8k6RPh4jq(tygwqj+t4?Jfm%$A&(B=6zq0g>HMJJv%Tz~ zPm@z$U%$GrF!=NqkW+yV0s?)rPUHmxAY*=3z&^dg!zTiIh*zH~DuNdT8>81p`-qZU zpsljD^;td0cvHBZa@ptqc*nyD1nAC=|J6&j0c_k62Hn{-u1Qj|q|Am14X3!n+yWtE z0eq~8(AfEnRA>yhrP;Yr)#~!|!uGdUcu6`Q^Z^MT755zlaM;?clY;$Naywxv&7^1> z+2i8*J2Hi8VCVt?^c?)2prR&ZDe?!|FFlpW0X@rftyi0>#wOSOU@VAaDh#b{xuNmv zu9J3n9XsMFo;)0|k0!KR8@CMS)xh*m}|2)`$Q@TsSQ<}V&lPX-# z5@XEyRfqDF`4wEg>e*6Dp0pIBf>j=iL%B-&h>1_o%$)w@YchFizk#!DC4 z#>E~kv(JwrF7b8O$<@f|s_h}M2eSA+k-#ep3Y^dRu#~LX2V|iR+P!3+OLUy2oT86> zD$mOH5U%IC+xvdgKODZgW*E}4AOOJc73Z9rEu+bhTwGo~tCbL%`cEYZxF1Y0&`?7c zyrTCvh_MG@m^!g;PxU(gV>iPQm+bEL1Fq91A=O{^gX*+avd2vk$^8x5y8>o&lw(Jn zIc@4;4nY~kO%HEIcLwR|(f-2_tG-F)xafSG%GLhF1%0Kvy8m?UZ|P6{>19OTM743U z>B;R652t`jB;r3C<0@0Y(9dSI6>$lzB$VSx1C^ACzncxw-b>h9ytN?C`>}Yz`NaU8 z29*dAyvpaQ)}^;`w3WxK4ue`r=fEQ1T}qqnyL| zWU32<-?)H;$)5nzCw#8w4h4GJJ(2g=d_tgVvAE?mEi?1(vYO@nh^b#k!y6 z%18eky)XRcNhM2mei_sKnbPcUO$?$q5p z7oIAcU$qpffJ?MNt0ymCO_QH0!tT*-t1Br8UU2!KrY#?BB9Q&LIzeSn2{Xpd%fV>S zjkn_Qe8@W|Ve%6q_KJIuZgsM>LZn1&JHnAE7;%#Y;qfZzlR{GE%<3W&2F6exJNmfw zdzmg;Y<+aJ9aFylbBC>#05^;-A1sFWp~0p zYDzclH#Ni$|L(W9j@3K8OO@%KzaCxLt~ePY@W91GCPh|hnkbz_EZpoQO6qfNExwg9 zWoj8Xy)^q+O2uxvZdM5=X`FXdsxsSn*lO+V#*8L;rn|`ve3L18+*D(ex1^os)gB&3 zR$Gd1;hGUb$T^#XeXaY2y0jgec8;|;mfW8ePAvuziPJ^h#G#ql1IGF&PfbEy1!7(1 zFQcftq_z-b0{xI~_I^k309 z2JFqpEv3Q0fMB05_y@<@A%5?vodo#1I|Kbb^nOJY?Igdk?aGcI$+nrAY={w5E(j;& zy`Qedxt;_)#8=%~MsK6|)SN#E)ezREAgUw7Fq)@No1MgX8f;t*HI;=r_s?OII2#gq z@C~n{f;CnTw>l_YmeeUg0q{)sYXXA}v+Ha-PA44=Ark|zzb%;{VEUafwTczLn$#&q zSN9hRU>cw&E*Prdg67^6i>*&djXyI!Qdao&N~Qn_(O^%7trcH^-qadrd(rQAIc#gI zPT=b5!-*qmF^1OG7%&j3F;LVX1ffQ8F@VMKmlpi3TK6#14+TyrOId~=)M0EE&%1w^ zb1~3(IcKP~!MOw0^^EWTh$f$d*~|V6zRz~-rJZuzSSqgm`J1sC4S6O%%FW@HskvyB z8!Y`-&dm2OlwMgq?PPMgq`+-r+~NI679L zf(X%bKIG{nRAc32e-V94+C@*yrHgBfDbQ>wjZ6AYn2nA4)`fpS7dKKWFAsz;&t8V8 zK!R>vBAwffiacgnOaydwkPKwI=V|zlKBUeYwww<4*>zvU2U)Yg4%y=-@)OQ@rSsz5 zg_OJX?YW!8@SN;mt@YXerv<=X|6;iL`dobP*;ofFivC<%E_vo^9#?7jC1wv--=i=l zT*mRz>pAeV&G55XY(frj^gk_R0m&utwzQ(c7nLzTZMYnMV|8Fk>C{~Hde{s1yy-*~ zGfHKhK^6~D4K}h;&K-;JpjJnVrwsPjRoSd#v*Vjv_5-RlX`w{!f926Jl)}F0A zqxipvW)Mn~ek{psMIiDp8wZHB9f$qdxhA6P`O#T%K+3`#}I51`4 zzr^|%9u(twOR8B8Je#Yu95fun`sWzyiC(@GCe*0~>xwPQWq^On$xgW8UM$j6?q${V zU1G!htn}3m>g2Y{NmzcnZbc^oET7xtt)YMU{D#x$D|z(_zAQGuT`m}*Cm#5s1gRek4nOSPGFF7J#7QrTWA8K}l!A zq%#x-?e#O9pG_<0X%OJ5%G_vz$lCKmbY%zgJqn&{v~=jzBLcZsF+Si9A6T z$0-!yP9CqtKz#FMb2De>I;$>*=1mgj!E0O45KH0A2QX5EIeu$5UX9L241SsnN(mj# zr@!JsT7U~+KvjcL6)L6x^8rD&GRjlCn_}nxnIPF4HqnlCE376_ZLJvfe-an{&~BW24?@vL?PEP4cUjBuOF)liwFnesDJEu`eNH`b8g9rQius< zNK6~Fo>6#^as8y|Z>#R>*UsCEU@rZu2B+iZsrxuxmx5#~7m4|GKi3gPDCM)C+NDmo zCLX_>*RYxLi9DiSB60zuc|n{gb5X|({@W7E^xbwL=FBFwji9j_VD58}eje4Dfy!Ss zLj&i}f*c4x{OE3bIs(ZT*~=^2IzDsvI0j(4!x^4Nj#lD}EVllT6+&ijHoQJdgypIv zD(5La^jnmq_Wy{RgGp~L3^R@f+_VaNAw+UUJ)B5`*%k}&7OrKM~yT|ED zp$`VAjtPwb$ejXb+m^@@`VB0s`f^99$v+QIIcE^sv*&lAK>!+2u#-3)vp7#HTK8iV#t84 zr`zL2EY#cSgU;FSP|6x%+k*D``Y4X5eEVTtcP^*nvLX?*;O*o;TN|M;zc^lXzad&1@FLP&d&$@j?_w4E88*`B&$1c#> z$^_B)aS~>ry#R^1>D^$x9TwTN#S3`2U0DE+`bkAS`wh{yi6QAXap-a+1G#L+6dtQ zsNy3#ue_}JSjNAHU%37JGQ}2IMgi!WO*C!h{qS`fqicCr^{(REZ&IZAln@d-N6#EW zDg&dxm}lzALSfArjlBjQKP`BSdCSqVTi>m?ntDzB^VP`?X`1Bm2k6&yq{E8y^PLjLk)%@P)Wwgg%->4;wEC}+bMhl&<5+*qF9yaxSp-Apc z$tsDst$3_{i-UKrs3vxff*&E@Av69*-@3D9RMzQd@pPxIuJCkqiAN)U6q&l3cbvNf+nJwrzZln`yca(B#6fm zwGH!hhpA|yx!DK_5SmN9pFyG?Dw|QAVB8!Bs%}S~?J?j;>j!MqmPcqy$1edqYT!&z zAj3t7xB1Sx@5kTqLZ}_gyHUFoH9>t1ej5dN{z+av@xF%nVE6nG+<@pOpMMZ5A7z%u zsMKo(5Hd}5L>;C}mg~|rFRuu*?~9vuZ2aql$I>?ZlGOliw0?J6^`_+u6bEwq2;Z5e zw1i_t7M*Ana-y_^#ADL2QBcR<|67syP{ERjXTa&wqv+u%wCC(N>=0d9eOypJwlMSC zf&Yl&G6MT|94P*{XTyIB$2Qk#CDuAWhfx{aXmR&hlPRpC{)={s+1ETght=YUbJ%)o z4}tQi+It0?0NwgP5G!8f~m>(!4_-4jH%~%yQg(v!HwV==34^22AS)>q*0yx?_qEk6YE>YCMl&* zMvwVtgzd_chBeBLec^M}P86_j^&tGOG?-bx!RoJa1} zG?cJ`?R_0SMp>H~bIDiQ>-oZc(QORSp_MDD0~sG#NV(6#L$3`UyqNWXw*n7tH@lGt zKMCpZ+6kDYgY+P~bZq^lrGM*GgUdG$er6T%dXd)DBJqDST8@Y3Shu{j_jGq>Yv{hP zj%$v67I4*EWZ2~C{`gzLn$daT7QWb{?geqc((|IDAczKGqcBz9vG zM{rH>k?~cRz)^koDC9aG-J2}besN)Tdw~?SI$DNqJ{*@6N%`0BhGd#0T3`cK*njce zQov;YF!SQY(FlECOK$6Eaust$aNMc!QjAJV_d zZf^!*QUD(QNmF@AsJ6T8ejBk}s3aQ^`wcH)sYMKvPw6nc*3+{s@$*=ifAN_<&wHVM z_Bf!+7-zYhqAG57$~( zM<+3#3PkAoCUj!U`e}YM{9NNC&Qtcv-4bva?|?_BQ%SdgnNi`seT#unTVGMMK95@T zeJEgh!l%b)x-+@%u#9FA&}FCn?C7n34gTtE01rtonfvz?VBWIgE*=l+TswI;d3g!9+$xo95Nljxo`la-%Tmt*f} zQyK@r?wzgik}vzcBr`^I;L8a3d)0u4?@&Y}`nOY(#yIQ;#FVjjJ2R}X-k(3iI^*r_ zFQyy~8jAE+R@+~)vL8;L{Vy3h9sRUfVF%w?12!@(ll={cOK{cJfEs!5$R~{cgv0 zc|-U94Y&{aY4pP8DwEgx8qTGPHS z``G8YnHt+4hLVEGR!xyRiE({~?=t^7xVjCytCz0{GlaZnKPa2l9lu>07=ND3YCqR( zoEV?x=qe&(3n2|JHDw6q(PmB4wnao_u&{ATq+9c=ft)pJqREcyOjtT)oimGd z&gVM;6+MeYNFiWpbS9b?K zs^TNOzQ;gOs=vJELR%5zcV`=V>+(;kStOU>x(TqG3@ivpfVT(+vg@~Xwh)xurbmt0K;L`tNz*Uyqu|D7zpnO=>A$o; zZ0!->=@GKar&)d9C>+n@@_t9}CKVQA_791pJe1GAJEw6Tt9~24o<~uq)xI6%#O8xpDMRwz>lfdeIB}Qd&RDGH z1+vZaKBfPezG+dzw+|P$!}6QaA$b4eM$#~I{<>yndPP~_a`0sYcjOajMndgQdX$&k zqpr(ve(iw76}}ybvJLHZe)wAtHiT{td@_8XRzKw{U-g}$!uKDFp!}O?`Jad-0PO9+ zsOj4Xs3JscfX8g`-cg!+re*KGc#w1~Ks_=fq46OPdhqvAUDl%1xo(3#WjFy_dub`Z zDuighKMDT1gRsD@!`F1n9{WhL{q7rmw|@o*l}BWIo?JV&xx(Tib_=99013ATS4m~3 zFoF~~H8~4h_St)e<3u(aDU!Hd0`%?@4`aytBQYH@y+M>n$09d%EypZleMjm%RZNA2R1;1d_gG zInZk^-lUgkRsF#BwX3F8f7c=)C$Re633Al1Qb8do*ovdyQ_?ax&%uTYi;Tu*BdhsG&r>yNS$6)AG^>M)7WY)`}-~_oJ-V)OXZQDb%GljiZUJEdWcbV#A9|LfSp@CDJ5#S zwj4pHn=$H^h;N3N=PCKnrsx!$YRlETG z=pFETwoGD>nxOy|FZ5vB=c>0!=7d^>|*S8CE#`;;1T}NS!vkL zc+=#_=nFd}f%lu%Ll+v%F(`E&S+Puz0mtxdim$obh1^FthhG3U*`2lm!HJlJ#tYvP z+N&kM-l&6ZKcWA&RQqBtO5a9-Gih3)#(TxW-FMN=O4yqiZ*Tn)@ElMzybi08hTAf2 zU4@xG9M{}3B+JC6IEmd1;Q4dqENK@a(l!AIDU%`%h6DDOq5uBb=KCUkR#GQVfg)z8 z=D{y0Zvbo~C|CfMtW2cHhV?YS;z!DNJ=qZL>f{fvUObf>gpBv7dPWz2l4qEFA+5LC zy0Ltl51}}Xm=ueI9K{pdMnHxkD#ilLs1gnWk{-`ttPuFMr6zGF4pbKfaHWjzcxgW} zTJC;)I|zF)1N(0aZahvrOkDo*AD#a;S5WH#3+OjJoIIVkx#BUPfu$l%MFg_rCIswE zH%&YL911!Amk*aO`~B{Njlor=*Ve#+*y^BQc;hW7c?%OtuvD>JzC(7Lu|589`JD;~l1*qp z#B(4B!S}+>TU%UvynEcO?W|BLI^dGM!da~O8?ab|2v~%&hz{XUfVwPKg8)a`0z)}n z%Q^3W5}W34r{Z^>TgPdk@9#%_#sZcjAy0Ij!7%B+EpoCTrFX#Zmx_NY&@MlUT<+8d zIKfViTL1DJ05urV9tQyc#~SAP1s)#Qbv*R0>gB3+{g&l^Wc5tZ_n{Y@6|lC@@i;%e zLUA2woN|H7j*O6sfa}6!BknHdeGB$W3J=Ew{kB1Vpmv)a`T1SZz%9tH3d|D_Zy}$Y|rE4i2sYgmCVW~O54`a3lzTyi;*7` zVibIJ8g`_hMN;XpAIl3=0sk;q6G=3OljVw-6h{Go;`4Bn7I5RviyHN_#uYMxCURP% z&`^px1Mt|bDjl4V-cwb*B3ehL$J~2`Kvpo3bWxNO(rp!7r@;6L5@5Cqi!ZrlJH_>#n_WTC! zx6`xvQArnOYmj2zk@{@vjcFCd;=5YjjIC8UnqNAMI^37N7u5b*x!84fDlR|sJ7 zdpH*IZ>{^WZZQ%J8;MP>w``G%_q}FZJ@L!!I5)aJOBN#4`*;D1&%&G09RHWbBhzj^ zt{G37y?=RK3FE&&SvGq9z4*RB?N9!whiHY~XTK&DX{z{H<>wS~pXkYKAcJ z|FQR8VNGsZ*k~wHq=cq`l!T5VMNmLW0-}bZG?iYZsgwZHO9BD{QUcOMq)Ah$QUyXl zlwPIx-aDZ~LQY(JueIFgITz>pfBq|O_%i1=>ido{=KQ`SzqQq-IpZ{bOS;DxS7XSS zZEsR6$}Ly21NoSDkYT`OwfEd|KjNl&@Gs6xy zjm@QGWR6s;y5fpAiE$&@g%a>ds$CL%%o8Qg5LVF)VlYtri%iOp;#D!Q9GOPAKvo=L zKvsPYwcaM4LHHUR9!~YafSl9jL$|Nr@odZXH|N!fZE>;gx-a~ZkE=*UlWZny6@*2! z>ei5w6aZyMi<{aGgr~KPZw~HnrpGTuh>NjqOD$W?|idsqL(#6R7Dn!BP z*gh*yutpeKgjrL2?bW3U1F|2C#{#gAzQF#3uR(_Mgw`Lko2qpcpKR?=Cw0rmnt^7% zhi4*7^NZR3sbi`y`2BZ&g8Y9)5awh-q(&@F@;+RFZj ze+I8-L=GgFH*WxiIv?Df`N_-Ry-GVVWd}JL0Hzw6p3a6;_i5}Nn#Fkfg4xD()_8ta z@SQDK*?GiF*yi_NPOJa*!c)&WTN_c z%BHT)h+^{v7kz#=fapE>G2L8oNRF;yBJbcd1PUd{|C)9CfU*JrtXsIqGc-A=lzbWT zFwc8+GcgGUO5|Y;pYLZtf5{j$3*q!$LVqC!6sdM${wJmnkT+uOcu9r00)uC}njI1Q zS?R`xa#hFrVx|Tsqv|;(S6l1#V{p3c8eYKzR;D##7uJIBn;!iN&%RV8L@2NFT$^ng z=dgT^;nfIppw|9CE!4X438R7eMbR%F%if8S`bn>&`5j=bUEu<<(N_69D4$w6&G!XyJ%zm3G_E^wH55QVD;3)p0Zdxr|LsO?1WHdbW z3>0UimVTon(}6qEEDRb3q0n;4VBRjXt0apefe!R_2q)H`PmFB=H3p000tcqAUFv`* z+DToW4Ip8oxU~4<9(UhmQ^}mC%jO#!H!+!08v|bk=RoQ~o9dZfR_^X6LO&}6gQ87i zAEnT%pSxI5ase`;l!E~AKn|*gmb@wAaVO^h3sr5V!2Sp&{zDH!7K7j3t=nNcKbFDS zpaV7BZwAB$3XIo?Hg}hMVN#9NK1f0?BJm)Rgt-*Gq{JyfbS0n0t2Y^6z!zgLY47OKi;biG9$gg@mh_D4=iqxzr#*%C@3H=l*uW@ zjnyP?Qm@TjWTVY^Ycw~=v;^-!T9}L%RaAMTxQe_=rTtjK_1P)sia67Hby;MKo8i!@ zlT@p9)b;PzIvnVVxG*>MFQVFYKYGd@eSU;`0SMp#-J}V?S_T1*!BO&TVHIA2ztd|Z zszIU@E=tdf-(kN@1YZ1M(6Lx^WxD6eL^sR3K+>{hd!Fbbo{GfJqNaV9lV7ra2|4sM zm3_J78{FXJ@usOGV(;bhdc|ba3-_&$*O^~Tn2b9qAn_gtb0-OsQ)JrBr65am4GjYY zpiwm;W1e3v+;u>gYnqMC{O(KA94fL)lH9g8f)?fpYTgdKz7(Mp#W2S~X3B+xK8{t- z!x0{@jfalxJFVTSHI6TGOcEA#ZR%K4sbgpiMC(+BG@)N880m>KlIXL98 zmu-{)k)gmIRXYivgpZY?8AddRbIWNVhD6$WJ_2$^9W@`97o?dot3#dhpPNd zp8KDxG#pQbW4814i!U!eBTV$*m-=!vJVW4TmBmx1iJ|91$=fHGZMeByE$&!DEVbUG zDWV}bEK$IRD~WLT>ar^47KZLVXXYJiG@sVxJO$Ql{WmfCjbilA**Dq($9iwwru^h% zVCbgm+F07Za4;b3*i6w&p@$XD)EtA~d_UV`ET+}^H{42E zYEMbkU50(hS?jU=!tJZKH8hi~YJQ&!F!MBvmUN~nod{2FF#fJ62!=NZTTd6sTw4u= zhSz7_S0g_}HQa6MJg;>@-y(Ev`^~Wuqp|-pn@pp^_LroUv{dpJpR<_MpMTD;q_&s-=k4YMqaJHaw?ow4p;Vj+tZEMjo}E_YWxm;ifbPeWgVp z_DvX%LtD^5DNd*pC_o6&zBDJUQND1c@3qC_{Emq6axO!pRB{?_U?=tFxD}gRy7*k))MwDC}KmHl8zAuKDZEx~2j7~jA?{z8? z_Ky6211aE2hn1;Mc|s&+Ep1s;$?L0Yjn9IRC*P5T zhwqY)PlurlX5P~_0)rPi9m1en)MXssq?-l5imJM)6STC#I@U)>Q%iy|GX&xNQ}^(> z;l)*>YOtxRUzi z<|+xm$?1b3fXoU?Mv}iSKuP%@Nmw(E0IPc{El=hJ@k79qOB?43$+2&#J}{AUX2}b9 zDlAA7CPDtEP=(rWr_5NYhT$h6*IC^ez#7(Wm%)8Tce{7fB@JSp^EFGTogLp_B^60i z6RZgT=);>}QWf%310!6qn=bv)KdR=mg~>1<*o1%b2@v{3R))Myn7wHk=G5d_w46?WTdYBGH8IDp znNCJ1UXw`MDyQ_a=J!#?5Ejg=rNH6mGI5S~Z9>7-27VqHd>TPU&|A>@W6y~vd3O|P zv2dBnbmf4-)B%fzu`D7f3!vg;33O@0)K6t+;fE@5eY18EMDS@uuC)G6k_t`0r}ilV z{SMDHKOvkgi(D_10bY(I-_O>z6xaj*j2(cHMhWtUZ{4|aOLmRGYZ1H6DKK(;8a@sE z%Ee+??;m5GndJIu(y!e1srb_aOw8tFs!#3YaWF0U`Jl$~5+c+2XmVUPWA%s|v5yTY zv%~P(uXL0OeA%+jzH1gHLqQ521@8-_Dl%O1R{N&Hcltv4vf^+6VqXWgT64&J-UoZ2 zKxGJY4`0Zd?|wAt(g;?oJc(b@dBdZryykwVaLDvD2-DRO^yA%C;!&ITwZ`LcL%Ekr zsQ&x8cW)DGi%z@XAV5%95XpanVwTbj`0n(nr$O-aSm@8<;vOPh%cBcai1rwhVDqX6 zo$jRLDqM50p8A*bi(7oW(L8M1biIyuLoiP{v@^ey25H{$3PHaT;tQN_yb|sgY}5m8 z`RKMEV*N|&{hPM&1hB^A`qALBt+)LJn^cxgMHq zB>xqk=j9oK`(ZAYW%G-9N|{1?go)*un)=0s&5kQ4aLX|j^pbVJlkZ@SQZLV-cZhtG z)U!jxQCM!Y2-hJ1aC9qNSqbVVE4va(yGb;P1s(}%*YsgA2bl7y3)hK%V-F*-#x+PK z43r^=12&Ju%VLtBU32vYz+M91fOfJU`Us>*YUTU0UL^y!47zH=^*S zvWGmEcV;4v@)ezHp+#wo_@2d7STI&cNwv*x|+$&qgrk3O-a zo0--fCwOA^QV(v_=5HZStL@AbWz2E=emRc^NdjV!0@$!~4P*`3tC9MVbXl-=w0NQL zWD+T@X88|ibt z$d#7g(Z3GRode;0q4+VM*(IzZ>-HIH+kdrg+N5}Rn00A+N*by^=}`H;DwtlMm367I zJ)zGxrHyPTPggRyJE}N<_pYFmj7DZD zgJ>h!-6Z%I*(4f3Wf#8Pd4yYDsHk@l0-IcAhlIsY22YC^;2m#hI?5H1C|zctrz#DT z&?0Kvg~$1W_4Kqxn$NX5eI99_m>=k%(NH4HcPo zJKt(aTDm6wBPG(Y3!3%_z&^Z!l++0HWAb8EkGA7@8aGK2@ZvNnDCwi+Dif6-hqXBq zv7NcRG5`u9kLN*oUSG*jNm;ogU>tKEkB;(M^T2=K zJiaMP2ACEqerYlDD?^jGQ)R|?mtCi~A*!cmJSu0;VPH$wJg(PqNCN0=f4;cd?Hp(2 z)pj{?ki~Sr{(}N8A~`_y+$!GelV9Zix_S8MTso~Pq}8A7r#b(9vQHe$tw@vRN8iaX zPsQG_jDZNOo_Fy&`ZNM4l28b(!^3YbZ;uhxMyd7C=YDHVXC-n~ z9FPi}pZ<)z#E!q88m9Ddt!dfG5$*Z%rOeHc$LkvH!6lvxlcZqW%+|X^;qafi^6iTP z#U^HLUX86e3J~!SyDK|RB!(40;}3iRZw1+jpAWrvBctRq`L0SA{F=>}lY{0d0hvqJ6Yvx&$4TDV5ZWY0>)|C*@rkL^86B_$AA%y?RrzVY{?t|p`w3O3>Rufq+sIT55`Uwte2Znec+hSm z7{qhV&@~d;yhYrJL>$%5nTH@$+T-*cgT(^jT>$h;2gD!0*|C-6Is5$wj-4Q zC*eW&oe0hiE-d_xCg4-Y<+_ni^g!4-Uy<{1E(sbs^Jy)QO6E zpUeIrAqyr{5wyP^0N^9x+4p+J3S4>W4}FkPVt6?My?GeK6|(7R zni3Da;8O;l;l24;7w?5N zP~Qz$Adn+Id1xGAaD(-eYvuaiv-zrF;W~%H%0K66>X>R{+@p4bf;(v1mAZB>&l_c3 zjrC=-q8WN)+5r{5F8YO;_sk0e2(Hh8amofvW??Xn2Jy!d5^PABOkj?yz{b`VCdXdU z+o&ESMSoFq%C1YEm-Md1P4ZKJ@o2piGh(izRS8%?vfYs~Iv;pxZ!S)YOSu>}!1qDS zjU(6?7}abaW2zCHM8gQn=2}0_q?&EH!uk32GKmq>uFMPWEbKD@CNEmx7=h#>S+dK5Kml1WwjM z)*UH`w&ayKpxRijby$PH;o>KiiUzb1B9Q_38uQPW>+iLKh0#0DdpDi##AA4}O}NVj zS0L?Qvq2i}N|>+YATm;cW1}Y+%)J-cW)~f`kn!`WB&X)C;ljZi9a0o>?;4~?``BJz z1fSeXe%M=h--V0a^6uR9rZM`9Nxt?Pi~0d*L)6lVffN_Z6-?hjtj2(U149N9aE!L} zE0e{XrnO!``Nej() zhNhOtS9BEGue0xHUYSj5mQYn04mLRu@)cf2`&~`}v z-K+d(;XpNTLo0z_`$MU8+Hv0=+{rVM*!HJL+V)Xeh_V@R?4@gPg64WweZ5%s$F6Eb&=k{*R44Rr^ooaeLD&_=?RV!71ZVc|} z@x2ky0)wJQiKfW-Z|jKE8>QRp2IciOXWk#XtUm+SRs|MW!t3iVCo)&;#K6mbJ@d2s z?1tz%BIcC;3idB-@tqNT0+oIJX!uV4BV68yY0D>f{r9iMV5ZdG?}HTk{6&($bz2mV z_2y8wPD>+UjRf_%S+PZ8n|_2=b($=Lf~D;g5q>zX_wm}Vj4h$ycGcDn@SU*wPGGS1 zG~$z7)xMhOT=?%O{kLQ-K2pWtv{<_5;Ts~uPJZ^a1~`g>wrxRB3d)+pZgJ8y?~_`E z>W1>fR};$G6N?M68>f6g>K6Wr**uzvIR#SQ^D77Xl$|UVrbv^mpd5&**Pi&=ftkJs zTi^G)%2T-UQ`q3z9OYoL&_7EOttc>@kHK*CXNpZwOGv|9%W%ix z%C&?0F7{UP*E^s5XuR`;d+WliCI!i=5clm$df*N~OahR}+I1{b&|AS0Y;Hm{eTe#edg^t{_Bu1AN{kn)lS z{0P#_$Dj96LXYddlJ@-X9>R&C#PXx>Pe=W0Ir1pJxtGWPqX zVU-&de84$r8==(Pm9Tap`<)yZ8>c~E;4AB=3udlZXd5ujC2Eh4)>SFBrK z`79bT!IkO1gzFhLU7rk{cKDpXzPrV|#jS>pdAad3h}v(=fiK_nk_O7vqQ48Z& z@phw(ZwEqaR->94wijj?^T;I7VTEt5KAAHK5WBj@Vm2~nhCIV!Pqd6{e>dR&^=w$E zQjNjfvWhV2IU~3|pR83@Hpln9xiekHHd$IeV_~{+d#5bEpb%&mb ziF$}D-oHnZ|5htQ;5;!|6OK#Lj}wZgrx1Q$b;qu^-*!b>t+wWjAKk@7n|eRi z0G%gPozAtHdV8}D9q0MtXy&VIA! z_rXO>x91|TuAxB<HjZmQy^Z1pL93KQoBttGH}@SKZZ zkZs4Z6c^%?SmA0JpdLVLDYq$h+ z>W`F=OG3;)&yQIIM?#TD>so}eC@vmCmu&;s!n5kK(MQ(r-619OWJxW)_mXU&HIcB^ zI)!f$LY~Go^4c1DyA^HCgJVTkU~L^qvtJ?{&&}yK-AkUgr~vg$LQvL zV_BhJ2*&pg6aab3TUQQR-q%)Co%e$X;q^*$$eo^O(SIG`?u-PZ>ReT*H+7{yClzrr zAQhW)mX;KXw1H`bpC^?(%)3jt^}hI*&%U}X`OPoljDEtZy!*ESPXzen1D^&9-&(v5 z#H#0-eA$p*s|Ce;Z$SDlbtb3i5{F6uF+pNVA)}JOLdigVh??Wds!Q*yDk};1vqndi zvbljp=zLl?3T^0&_0yY2z{5EF95qCUj$FpYAH0N?)h?KG>&qn7tB_E-%v3t-%D`?gJSCk^6r-j>l4fkM@N?zkn zIsW0-|ALf1x8+p;iTB(0%1QybOptz7V#6Ac-l8c7Fp`+xz%EJ7lwMFQn5C`8s3x_p; z$q#=7!3w3mfKFwi;XcrX`Kv6CvK~CN@BszAvGfN$#!O54IR~wcQOdtToka5rO->09 zX9NFnItdP{jfi)^ZxuRY97|H4{OWC1uo*SJPT@f)#TeR~F(_bgsGlEL;rd?{eqwxd z{=&!>krf>o z3py8sAxj#6;OW3DB@320NUKos23UGx@6!QYx&l&UJ(kmJzk#u}#dp^t`VV=u1T+Yn zc*JO#jVe0?SPYy}=%>{u9H?SpEi@*^-^@GT0s$n;Q-x2D~Tk9KJuVq)7NY{hZ4!26YCFi*@_0@Q?q- zB`_83Vuru=m46;lCq8oc*CUJb+}S^dfT^wA7S6H5RRvwkb@UT{2wk7bNwgo7V?z}q z{_B4dbM)mv<+}>S*X=ptk8CJ^1*+Dcj!LTZoB>M>liTAUD`3#}$+uV@&@>q}-QU&~ z*1*UY(_&mm<85O&o`DvZ4~stE&rcWS$lG2@X^-n}>E}>D*t%1*EfljcIjAEf^_eB#f0-GN-Y;_d!=v~&>yuTk6o@%xbz zVz1}Keqr%!)MD7JkAibye$}f1^0XE2ypA8(9nK~e4gU*LKlqWCnz+TwcjrrWCW;<; z_domy%uV?a-&IA%)n?8oKHWo6n;X~MvWbb-(ERX|p50=>RNQ{=M8Q9%tNl=9_x65% zivE&gZ)^dgbF&LrW_(-VA4L&6sZmOak;Z3+XBp^(2ua(9(6H`OCkz z2P}ikfI&i_VW@T5-+N*Re15k<7G4Se?{migAJ3(GLyBZ>T*z~X@tHQ2n*sbd;?t5D z7nba?d(5!~?eUD6Orq=4d2PMfVsh@yl8$>{{x2iQ<09eP2y$-S+pV;$N!W%h4YCiu z_HExgIMi`J<}viWvD{rIO`-%zLwKcW_)c+NwJ>FBMf=q?zCYmXx=MiFF)a-g7HkY(q%H zL!BrA(vuwuXA&vmGL!sc(uz9$%ApAdA~MLhscDBl*~dF_Qan|8)$%Id!S={CCc4z& z1U&u;(;&E>Qn9%Bm(nd$##*A5owdm$%WTJY z4;AXtyEe?|`*adTLDn3DtVeMNU1M16RN~+sw&bBGXt?{~YFpgQ*BY+|<=3V%T0X{l zFid(^`)jp{WrUxfV*kTa$oJRrc6%P~>Y7XIj(;v9K}{YRc~)5}-H{Spyc%OxB?*^G zM@XAPzGziOFX9jO95566%6&=7uu@3#htw7ehY;;n_>Zyo0sNrt+3~~GcjS$^DK`ho zytnNk|04tzQg5_`JyGE%<8G?O#>rL5TF?}6(4dfU3-|w;g2g8G@|3yS=Y> zw@YG$kG+=OK1$*uD{`7Xqm?XmJVCDp@wfX`6P?7bdN@K&ekw5!xc7r@d2sJgVba0O z_5iKmp!!Yl-x#MvPX9^?qBEtDQJ22z-8Wt;hxN$l$z5(cjB(8;CKp_6L0Vfu7d9wc zJSdvz7@XaqKL?t*-o>Eu6eb~;&a6+>_JYc-F^MvxJx+^%z7X5%1~YDUd+SXI+$U|n zvLG7G_3h27x9j6H#V??u!1y}7A={JxNb1mvep%(|)wg4nf8Pc0VjjEe6q>8g!SRKW zf*td)pHeOU#I*y(yZ7qIaJ)o;_$>-{H%GtsqpoF9ymdgg^j@()-$^jA!R#%k@xgD) z-T6u;nhbfcM0cgM($d?6Z(VAmMi_=gB!c+;4T*~HFtOTF?M8s_K#F4GP@pz*Zt*++ zL^@6Y$$ZwRAbN6Nhu?2QDJ2&e=dB=T&ym=2s}%C1D8iM0+wS*E*tjpCQc*3M4+!1` zN_*rK>>i3*1Do^M%7Qf3cSq910Et;OTu5R5buF2cq~1NOEr=iAVDZjrQSevMs$gB0`EZhN?QkHh9-ZKQTNO6?l~#H#M9OaB z2^_8vdULX)fXGusecAF3J>XK4{I~}_>gLj_N5faLIVhH_{$8?|`%g(VD}zhRa993Z zQc;UL*SK1(+`dK)zBhcZIJM;t?h}XG{Pw7!j)1I1gKk7%_g6QIhI<`k?LKdssZKeR zyW^%P{Ch3Q$oIaY)kZRnAzDkL1yjEb7Udddyq1*r<8^T5b?-@s82rXm=%1tl%K*si z)|g7m<6wkM5{)z{TL_JI3!d?Jfh>maXT}uB0}8^74;6*$u)hV z7%c;Nw*t(Oo{u-PbzeB+YR)N~zzSN1I-Mva+m-qJHd#nJkJD%KG>J{-V#&`Qss4XiAfbeM9IHn-ER zK9b^+BqppbAk$Ux-?7@qj9dCob#s!F^jfC-P3PKX4EU_p@r(nq975lbGDI+v~zQ zjC3vGyQE+I|5RZXi$iU&vO*;H zUkM8BY_AjdWVz?j;rl#@d<46XAfw!?z`A6cb`0N0QL~@M#&{e{mMQZtE_Q9%=)t(# z#=@(ugZ?6W8#DC-w+s?_UFd4Z!0yPq@h6^(2xY>B-Oueh zntnXnPbT-CtfY-Et(GKDy2a^DW3$@PKDJWfl^MoU`)G7RxUUhVbT*9duqBoZ#~ zn(BvZEYkzosx>9nlD>2`+CNVKf zbU(pQ;iQ}%9PP?$A^bU^=jQtSUhcBm2#!Qm!JC*N$^uE-vA?ZLKwqY(C+Te6%N#C4 zw2c%|tv9|tgj`>0E^7C(t38Pa?C+N?EQRm7{gcy}7)z92)e`|G_P34u(#PO`+6GZA zJgf=~9K8;gtk94e1z=7_GP3eaaAk|{Jw0^f^<)M!GwK_|$LzX4D06ky`Z83s*e=@k z5Is~ey{qZ%kK5+%IG6YgDCv1lwx*$MWu$Z?*LxXy8tx7E4i4!3k(%& zylJbtaJ4-)PA=Csyz-{_=KhXjnTk5QpHDk;%HYFsHxC^xMi6TN{rl*rq!tT`=P#X_ zTby1SdC2+0*g-ieOW#UFG#7U(sb_9NJglI{jbPJeA!YrMzJzFiR`jZ^8z-&J)voSSFCbh|% z>G6Rbmc5xCU!QZd%Gag-it_!=O6|Rp`t&Q?(C{$LJ3x%|%|I>XKx$b2;M&cUu5SF% zbg}!}({DoM^EuXe{87yNuy4@UxGZ$e$umO%P|wNTww9Mlng3RQ(hRfWc}!z>x2BzymC8XC=AiIfu0VyMVA5bt2=n8j z8j+KR`pwnts-v$7=c5_O8_A>r>CXY5|?Az9Z9Q25jlK*0O9fp;~H(y^@C2t9wc$Ko*eK|Q6PCtkE(eoXr!`%9d z+Ej&&iSf8h4(lB%w3Jq!k|u<=XmAs!T*bFLbD7%?-%435V>%*E6L!{`!{c5E*=O*~ z+f0D|O?eWjR3m^!;^i_#(VS+GDZ}H5j*6wHS>o$;@vUY0l5V%e^k)AMyc73b~3q=J-pAY z1`+%8P>0FY3CT>kHKiHQ(PUGM6z>;p2+q?_gFMN_X8tW|G*i zDpSa&Eh3&Kp-SAqed+!^euq&q+>k@A$nwJtA{0+c?c%7HK6gO8 z5CUxofM#2nF4z zp+*J<2G80sgnQQDS)r>+m!5wMcCG&4Do%4Av8}qQIIH;F^s#JwIN;_+(0QvdcKmGN z0^Yv?gj1lvKTN!1dfWHvW8cg358g*`3|D%zwQTPFXMFQ7Fl0*-7%xM=;xN>*{4kW$ z!)uGqe15`A2;>R+8N2J^*`@a7kUk*j0brk2)oE2ZS*l1T4_5T1qSK|c(%+x>CS&MJ zVSihiCWI7>$G;VqGR?ugK2va$cW@3wubPcn{Lp}oXq)n_sWq671wI5;JBXB305@s| zfqrigSiD(^80w>e(5 zI}k{LU!*4WZ-W==txtF_ry7YdlU*3cQl6hZL|o__i36}ca$-Mq+U*x#fy*8g?X(0d zEj0g%-bB=xRP*@2cc#6h{T}qRqb2S8{X~J`JwLFyDnx9vYiOLjdU&$D*reD*yQnH? zUS6M~Q_nvkuuUak}r%?K>HKhRpK??vv}^ ztI$aZXA8OP;o0dPTbrTWK_V4j*GenLs2tY9M)v4$|ab~BWg}T-nS(xpN~!v5<_qN%H*{SsaJmh0PmnwDvzEIuOHBp5-JCK zmX>UniI)YvnXZ1h?2M1WtQ=i)rPQbniq5Bob5@Rl&amU}&n?H#z$Mdk=P8v* z!TYlm*<9|O(!XOtSVI`qh!XF*lSiCz=+yRzRD-IYF9o|(uVoN5mm9xFML7L)WxwJd zxgNV}2S0O9emc41_?4xo&-q&6hiNnQclSh54T#9C7HX2oH9G{t%n`C9jxboAZkC23 z2BEJAR5*=k(pQ8Y$XUS}N&y?zE&}@Yk!dkbbv5G$<+)=;{q%VKbu<&@o&CxtE%?lI zE}4%F?Ha7eUIh2>3g~`BZV+m|{$0=fl(+QGTEXPE$_g9rxUX8fa=oH(Ieyuf(C|{U zO6U7Xc*@P%HiU-=RQf7%`O$cl6)1ef5F^c?|{dC=_p zPC7WwQc<<@6)Su6GuMtW)h)a_o_YAm&hH|MBWT{j7(|YvVG0;#JrRUZZDdXOJ%-hO zgT=0Jm~G{gUW@)&bbqBS5n4H^rAz@F8KX2lUy1M+=mpmCi35h@p3ze0pYtRoCDB~Q z!KU(HjeIMQ-WLT2JtQCTP?98xsr>wAa}yN_Jmo7u5gs&~Ox=DuWx5Mb4{U1A>x{UuI~C*4&rkV#1f8SBGT858ynz!}Xz&PSR&458kAlb155P zZEQLCTMj@2L#;Mg8HG}DuD|0XL!gREMyL>dt$L$YT}m-r&iW7x^8Cal1*+<4J6Q1= zaH+(Tu!96_*aflP(&aWbhR^xAhydv)L>$O*`g{Q@AE1PJd%Td4$=&WRzhvil7&nSA z;_jOcoy;EEF8Uo$;oE|t zVLT!3^ulNhXmd^RO?+;|GnrICz_o){Xy`bO29}n_Oa4ajA?(FK~0t@G83iL3s@ z8?uSfg6G!0PALKcmz$gEEu*C1lwKibQ^tl+I$a=jfy!lp9ePB_C0uhd*qu~KEKlSt z&XpP~Vt1#Se3P*WCV`=9=kdNNbm47m1DfK15uKEczvSEJZ@LJSXCgiOhKK<`(zr_! z@CK7`O2G>bqyTXeG4L@;&dXbZpXuEqG>Cyt+b(%;e zm*C#C;a(O5q0+lE(|5N6|D~0(dgSrI=-!}$bfP^$XcT?fj$Tjh7mynYfhfP8jvZ`94_O1vl53N^nJr2bk!FSY_En1%%dI<)2(8E3x;BQ?+yB&+iZa`U91$(J4#3T zLHW4x!55b*HA~k(zUQ7pLqihpE;8Y^9UL6ooTkvD)gGJg=?AQPkfJmoHhlAa?~4tj z1cTjrSMQt>XQxbU)1p`QuTRSMntaV&#YY^sr_Q~a#Lvk*VM_I%xMN#*!{C89whdH8 z6sjcwU-zNfUP_buw#QXd?fKhP!)+}v!pjVye_WJ!N!69W{`Qtof8mzfBmoCHL8p|G znDp!*y3fx@oXTh2(`9@){oL@^!=hbRsNSTAas*VN>F&f-1;U`Klw7@gYwx(zt->Ty~0BK{PUhu0rc32+&*A1qXR0=$F;>7^s z_RaAg%U|^cXE9{sRPMpUYM;zs;YY^me|_q>h~(U)Cp}G2zei)!iFXPet+sWI8tui5Wi<{7r7-|6J$FqIMf_;P_g6>K?@AP`JsM^l z^%4`Ng!1`NKZ+J@%s`f9XE!FdYK8e~)C<|gD&$K$uKml;m58iqm#25t?<=O(zhdwi zgztmilvM9?^#+WkoZe>3C4zAOy>r*bH-v{>t=38!r1+XSP#oDDssRamg)dosgCsxy zI%i%<^1`YK>U25(Jl$(9+$n?LS<4V9Nz!{j&vV8C(8H~tpU*AmxOTbQT$ae)4dzkcdM<-qAY{CDY}&!pY+|wnie21NN6wFx!0KXJpSBNnwO9|! z5bsS!ZN{O_P-%abv~59w%&jdgC)&|gq!ztjkmThsH7Ykg!(QmpVOpUdOSt`yo>yyT zGAS3vVt;c;4+{XvBn1<(KB=r)Ddy*cvwlLTPPO$K)#O75D6ePQjGc34{wy%Y2_C{vD>cYthcY5UnT1(gCe;JDk`SO;psWf6O0fs8zs zNuhI?%?d5pXp#4~AyrZrNKntmzM7VjWYiXQa!j~4^rkcqX-R~G9kXRMHSgC->yadj zvf4x9TyCU*voquI#p-W^T3<~b8C^HvEA$d`U_Ofd*Na(}Z|ygdfd;PoePmNw#05iC8#7`f+{|e+e}2JO1F{pj?3_P!m9& zOdi8$Z0nr@2)JnsJy|(`(P)|Y@(u&XaT(l|C%XqOcE;nzzg~lp@C=X#r;7-EdJWLy ze6qBJSZXx&tSdGV(WvfxKo&c81e}X9yY80NHVVC9Nj@my3n^ebV*E8?28e&n~O)UcF$vTRe;7 zAE~b^i$WMHw*HFVr>4fbpla7+>EK5we~#95J$#_c#jwitp9==tU2>mydFq zb;BCs*iD~cjIk#ZiiYT1v3o5_oOqCU{y~0mq)1Ujg#)87NR0LDf9~!B19@;(_f61r z&l+KV;*^r#xBjYp!w%U6`k?UWF7i4b+aZp2}T2vg-Rj34G16$W^|7>ifjmysE! zF*ZhYr0c7W23dL@1vWaZq$;R>39)1b1nCisIbwRIz0A&@65TZU!WmB;-7Er~*Wkdb zljg}LbZAr3o$ zRfa{mb!}p3Y3Udm6bVH-h7ge!=|&nPr6h+G6=6^$qy`WHr9rwwx}YH>Y))px`H!YTd(Ju)UfJyR41mAV~kZjnl*NB38Ql6*h!#BpkLX~nobi2hK zs^KW3;LiU6XdXC}6r+9z2XKoM5N83jNw#r|4#UHCCBuDXDG;z3Rf}}~4X@3iP|(|q z4ANtmUej)H8Bypfrm0^|UVhO2Uvo|E`&DyqloepF->B^Y*I$qNF-{|YYR1TlL#Xkt z?G|`lFOzCiRxUA=S96WPiD!_@zYj1-{2?SHN)M2W<9!_+Ot@Nt0u=?LPc4pKb%Lj5 z>Dhs64s!VKdR4vsZ< zltI9r!<}ZQt%#u0z9Ow^mdeXyq39JJ^RuV@(KT6J3tXe{a(IK5A_t#?s z&!=w*%$$M`b+HCF;u`t0rZQ`8EG==;sS(|x!q`|}lS^Rr76pQOBsBhiJnBpqS8J-O z{7%?QS<06~DhrR`wLclAq>5~YeR{hui(GZ7CR7!fT4$QeV87VC4T7U)goX6I8>?_0j9E z@02KEnmlq;Bag*v8X5!&k%3Swd4G{JeDuryG^}Zi-D9e8%MIpBR1dT`XlQDx0o8_B zI6n?FKpigse$hR5lA01ZXsP6La;)0gC-xut#1LqhqRIhAAoP18nt%u~XGu;d^_h1+ zX)2s3J!mdr{L)*~Vn>=t&usUP@%~5>H?P5CSL<>j4 zDiD~PvB0ukITCn(!!|W`<2f{!5ka;(J;r}>EE_-a|0;#q(3sZ8r^g}Mt3zrSVF;fW z3+-WIPM-$pE&e}waSO@!*sZWna$GJTOP~X`KDWWg5E%>rZYF206WX{0BU0jS*2>%DR7BTL2eV-U$~cQ9%&7SllH->S_ljWagT z4dJ)~8v$Ei;-Lu6lM}EbMqV=fOAg+(e&QH$5%Yn7ix8J|2hD4Kssor6D&ucMEhZv+ z4$b#rObC^9NDQtlbuBtSo7&^4)aFSs&&Qd65;~9e{75u<@cjSF zcriODu|TLH4Fv5ip7oni{4UJvP$t+t;@AHy zIz<>IWeSa4Gjs{fx%{cwY@x%8z7XZWesuWodDDVhU~5GL`BjRmwmIYf4p^QQXK-VY z2&+iqgc@slGQXi}SknAhkqWv)xHLBH2t*x={eBI2n3nFCyY>DTG8DgoNz z(Gh6vu#4PC0$UjHfc9UOe(4uysI2nC9%1IPl^z24OIQPPxI~6Kv^Z$!Rh2=Z_%!JK z658JNPz@CVzj1eU{f?}G3rk{7lbnL$U0%7u=(gm*SsTV*|7YJY-6)EKg2d07VI)1k zjh|@Mpo)wU)jB_aDpFQErmqvq!9ok$-g{9aN9EYjz0K!F!hwXpq}gR^SlS2c&&<8A zEkQ^A*SpOQ4 z7q}Te?p#g${k2op)N{GGr51!K8xTmi`u;u_5Tpa-b$@%i8p0xk@sQyG717r!`4Gq| ziy4G=qa%piLFEX{U350>kucS9-u~Oe6T)IQeX^-m``PsEYjvY@^uf_VcE|>lml7cq zsTj@vN5r)pp0`X3tj3u!wj*61H+qqwBoUpSO&m<6S|i=A^fpYVDl1JF?ZFYR0r=*#G;;;Qx?$wtGh zGztXNl1p`)Lvde%f(-~F8~4||bzrT%3ZX%WwVz~F$cNS@2byK>Eo?%vM7PFu+<60>(qh9g%1i~iLAN`#IF3v z+ke6qEgqcB1pVu)p>9uIoEvD}J%!+}6!LOHu02l_EJiGYk0T-g_qtt=gLxdn*`$tT zTnU$stzr4KEslQh%qCN`V;QLUGXTvk)P^2e5F;dm&s^}jzR|!dM8WlY7nMLQs?)vQ zykRS6H41WaNGN6CU$ke6J%*3TzaEpkY0kJS7pIR#jxe1ow;*>Qub@9#(S*3~JP)BL zk&jq77mTULRQ32~8XQ+t=PpaYYhJD;bOFHMw@fqQrZ?i|#2a2X{PsxywVwTs<-2*@ zf0&q$A6s)|F0W?2*q45kQ56`Uz{?GGBZn8aB8B>LA7H1H2E#vhdXkls@xc^+hQE(o?K0XvG=v}e|8Sqj`(o)NaAoe8!ydT`y;3BP?^rEBE z88L-XKsC>PsQcMd^Qzxt7s|DKDpxufWkR?0WN)8>T0EGo0em%ls9^ zW{B^frfU0iabk{iBGNVTSU2vq$VX|_%Ct`^1O`6o*WskF>9=n`s*+|`~K{>Mp-Td z0mTl)$SKAV5n*%`8mWD3b&0W9jeZY@A~<1dzlv@)S<#$eTkmu+fWglwkM$tJscNa^ zB-dj8j4#-BW{&q>XPXgT3er6;fas@bs~y=_hGpI9`u0$wl27ikA1=}NyV+*ksln$W z`fs~PhK((Ae9q`UTR3??QmDuW$Dm?`*G{u~&$xlIUDBVIKSb9;kh&9N2ky;u>Ou4iOBc9^<1qNj)cI|b z5WMP9&-vhadtJ;U_4Uz>N&989s;P|+Kd8c#lrakVeA#aGFO#4fjX8ny1Kx8vfAsfe zV}v=-?STGHKF`tcgmU-Mln)^JNfE0;O5pkWdnE3IDK3fAl{h@xPHhfJeWI%tv&Dqy z{h(?)Q<#IT_9p4qyR85PRYr?XG+D`O>&;io|8IM+49;5EgjNkK_IWr;3W*y8f!$&=$!Al-iTf-NQzTn6{kmX6hCdz)si~AVn zysdWg>j6Ic@H4`zezS!fC>!uUp$K+8R*@V(u;YY^^) zib8m>XZ{%9UE;(6;FS5wNxI*zKSx%+74&QIesO!>hxkNFY98VHiM0^tmiyD2EqXiV z$Pu?*S~;byku2Ac8}pcpgjmevdr?9Det)e6l1*N&891)xn_;}U%JlME8I`T{CrWCI zlR$1WhAl`i3dXW1JK`|CUYl?&9BCw%K={~pH>!K>dy{sb1*-l#1SPT^8JHwhFG~@Q z62Ac;Pu=KE0WUv?{$sc8nZh=!Pa{x)2WsI6ux|r(8L^W-tzipFk;ukukxC zMab>q|#6S(rSZSV@8AeT7UKU_!xO`4xSGk9{7Nc!1~?&fjoTi&twz# z9N+wB{fqM?GsCxyr@yso*+>oyx{O@Gng-U^7xbl9%8D`@MdK~QnV$^{idS^wcdMbIdPNCG_tSdbG}HG`$enUjXC%N1 zA6}fb+?yL-NJ=R~H+95BTzk(PqmDbfKQsh8KHjMa2P;gs+Ye=;7m9-sVxamRkgXxo zZ|?D63qh;Px4zio*!F8le`dR9v&H+gw6ys)4ZxFQcHrb)ngmP+JG!mpFPy2xhO@TH zd!&@HBrr$}9G=?+k-uGCJlO06pt=_}2qMT;{h>szDj!3GXqQi4MLm8Ou8nv6=9#}= zPO~1R0z#x><)nE61)XuzHLy^V-mljC94S_2h%Q`Hj-6QKov1?Oe2j4K!;v-vKX0cY z869GYi9q64wLSVfU`-(d9DG5-r;b-SdP82_1UDGky4RkbZqV#n3GEv89roq@3PYk- zFF*>_XrkqM4U2DgOfhYRkWCG-mwiS~mwnU5WI~irOHX(Ti}BZ&IVlWjeM+ef&sND_ zc3T|HA(!giWKC2owoIReqZhD121wAe2~}!NgRN1&zrM60CIN$tdge?zyjX~TU6`ysB0JdwXfE!^fMHXW>8Io zi(Lle>CRM`yiQ)jrh3Ot=v&XY8lH?|7qtdu{L)qU^`CSC=JcYnaT8d%8J?U#cRFj> zyr`FY4{+xh>leI<-*Pd4=jg)kERA=Jz<#-Inmk#cKv_ATB)og5#p^8a3-Y+$!`Mkm zWOXBSjl13uKrD4p^f?5di)|D07}6^0(OwnZulbEJ z30wom<`Wl{@0jeu)oLrP{3W;h&q8&}5uVus50fIG%dfve56oJ82Al%p=`On*`njxx zV8|<$AANpcN#p@AR<3bRgWXCx3)C=C{u{kK`&4C-gtJ9?bB~yPuaDMO)5RuP6IC

&mA5r*Sw}x_1PT0Z047^uE5_&2{}X*c3zF6P>{OE$WnEt6dZmvxZ#gzV z`t9yp7EU-vUHcpVE`zLD9u*2*ET}LQD9SZ!FU1uwUSFYy7k#k0bj#@Tk;?x#gd+MM42ogxj%Pxpbf76-fb#q)m}n_&C$}E*^*G)emMW>b>h5(7~0` zfr0vdqZ!_Q0pu6HzOzF?m6MJBryETQI3^aHgoHTZp=?%|dy8xFq5v+0w)`MD3NH|@ z&(SLZcUK9A;ODf!ZIRCF#&bPuXY;485-q}3Ee5L-MMcYl*Jxtf6w&u5PoQ}F2uEL9 z?`1we!eC;rCtE-~*7vjk0JZ`fKV^>y`hp-5_1>p4bh85Y74zghoG%BqKrEnGnU~e+ z6H{#HBmS;!ES>>}i#ko^w+Ow;kH(QG_N+T6-^>H~&L%D%k2QlGlWL(hPDsDYY65zw zg!A6s9baN*l~3&b9EhuU1>lACa(4&YCqe~z3JL%qOyQ~g)v*G;jFN@JW}Q-+i?%v9 zXi@$B@s#i-_3UJJ&=6rPIven8F(UxLQ!Y81M>ee@w!gm$CFJ7R0MX2+yVyH$yxMq` z-HR_4HuAFy{V93uWj|1*OMYZF+KElV^6WSp!d!i9IfRqUp}S?h_Sy394`b&05O8ri zKiZxr7!Zt^lmx2S%FfvckUDTWV&N;;QuVtiVRf>cq2Ae-SSF8to6LFTjAf5JG%9ma zFJBy+VtGZA5FV6lw9DmJK^ZzpnZU?lhld7CW5lH+UGJ8llwn?q>6uCNBhk1($6B|H-Tp;3fE8=}XUo zXHHZ9=BACXqH%=$uNLigh{GU-y2@X3>7mE$+;B>^nz7P;kYDxjD!-$$n*UZ21tNd1 z|MQ12{II9AxtQA~)YrEu7RkPLB~ru+kRssIFg%ra&qOrw?`4E&iLdV2&7jEBoS#qh zK>i+jC>sS0cFK8qPdd2h8ld`4*N>BKgF{o7KSR$nQnI(_E$QYushqROK594UH823s zxVVU=^r?O0N#!O`fK_vQM|EHbOq?d9Pws^oA8-R0>TUU#g0U-N6pS4wB;GP@2=OMz z7e&BOpHkZI+y;uf)4kWkMaGCD>%x;=-l2W&8scn~AYJ_6*~7@QU~z1_>ci-fPCndE zeP?PpYH8mr$6x%=;PsI2H}i-t!+XDB9=$A*_0jba3DK=xy4`?s3chZ$u-=Yzl{51} z-f2gJs5UqHv>}=xszI%9)79wC*Sz_R+qI>u3D|??7iNDtrXM>lH#YbmbOsS7_%^+^ z7Lc-1RV#l*6J;;FHlqat2fs^Z|9zHM$4MDlZEhB`eQCF{mZCfD`W`)PB8s2^OLkQ$`cj^ zlg1cN-#?7r572AnyUI;FVZrJJ zQ*1kcChkf)-GPQstC8WnP13o#%DylnfuNd#0d%|240QA2)WpO(-~C5oJU4yPdfOPq z6Fj;7vv?x*_dvqdIM@(xULR|0&Q?SL-M<^C5G8I!&BZHbUW9{7r_x?@H&h%w8@$}K zQNY_fhPzaMEEZoL>#k2djCUwn9}N4$O=d^d*4GiH3D2VJWf*7_OorN54%!;7iPqgW z8Bjz3V-uKu2oyk;mOX3WKdUM5GP7Gbb>H+0Ez7`#&w!_LnmnJ4S& zB33Y`Ao4S!pXtYmvC>DShj42ZR}!Jqelf7g>hDOaO?M!sd*cqJuecOn#{JX^ z`TS1)5etl`-1tQz8-+MVUb{&XZSVfQc0FvjmL{u>(MmT82xJR2lUa2|z=N74l-qC# z)Sce}!(NEJ!XhV$*Y5O6+#q=Cxf>#Oh^wiR@Y?7%nCI0^H~-nx`kLV1uz`&*mkFnC zBi$Z4?ptvL4DooJxQ=&c9M2l}5m>gA1Elrq{fH%J^30_XS%~gTrG<7YPyr0%M7#li zQg@YH?$(Vd9slQ5@m~oEL787y#psJ!?}r586%!IFC(Qr(NQdBMApaq#O4y2MQ}D?% z$W1bFR8{T?w*DIN^lNI|+{>|+43Q;pb1kDCBX%`1>MsGg#Q-kyY>=pPkr^3sZ{)<6 z9#CH+89;`+J}1Tqh*=8U-$=GDHh#8(8hia+ zvgo-&v5R|4U0Ol@RH+Mxl5}}aYZ;^{kleNVt=K#HJK;rOUxB%^=rh>UCOMGLaXq6w z)yWk}ms@fCf6R8g8=-e4D3tXAFVv|hbW;}Yjb8~8`N{mN{-N-p>q`;8cS6=+EY6ur zQo%3Ll8stdMayIyP3hXb?~}mwvA#Do`T6dI;T_^!9K;Cjl>49M-?3t&JKy8r^K#*Bx{q%FX*g4Jgol+*`2OU7ALr(qWb$y z6o9ulVTq(~M=Xam9V0TQ^a9^}*x9Ia`RxXMIT^=UNX*h#*Ce>Qs_R;KaaEf>;6N;L zO?itQ6>hO(n6U-NKdWVp8IktG))&ED>}-r^265YMn3WKTfXtp3!|VqWn}-I4Q=->| z;enb}E>ra37~ud4qj8T_Wa=^gnOTu8%^)<{FMBzRo4cU50@JA@*d=UG5b<)%=UmRxSGU3_z=@etj#-)-LK_MdtYGI7(2h*Ys*71e^mZ(rH&6B($ri(sF+O$pkOV10$s5 z-A}9m*p!HVabY$<(1RtT<}^`+F~v(lB&YsnelSZX#?OvRC5|bsIXg5U8%)mdu>m|< zsb&loAx~oyCPi-wzLVhGjb~rO6n`7>nkY#j?x+PX)n2v?Tq6+=hUCl z`|UH!fypV6z_Zes#TR@Ig|-ql%{zEHKFZA>!vnYDl{QCnRc+vW0=?n#L4;PT*R4{Z zVwX@5W91#aqr^Q}O8y-mu-Lw?#^aFM)%N(H7j%jRa z`o*I?kXCx5s}%8$R>*`_dJIcfUG2m64BbJTiMpR3c}CERLrz}46!xp^ZYaX*r)7fA zISDA!M@fp0rO!9S41kU}VX!+?zxYM%Kg|`UU~-ieMcXAc`R38U`S|IN(0hBo=ze)Z zwZy&Ix)Z6TrN@2fMR#C7Cf*+5C_*rCmCps^^@-7P?Fa4Vsk`qzlx%2*k@qJ>Wc-lGmjTEszoGz#ffPm9)kboW0}Ed%-$Yx=WiZ@i>nFb(S)a(Oi^uf`H~m|Y zHbOk^n3FMCY6Hs8UZbgW!C-21g+e2%8{iHv-!wWQ3KUwXCLH>($5u+^uW1HJo z)DXfCG3Q4KKvdXb2t1g-Uq=O~C=LsVJ)eiR8aqIr)uyJIZkg7g!sX1W)%0;IpV65g zapSBaPAwPJD($sN3sE~lL8)4x)2p&Kft@eJhP`FeoJJp8+X^6e|45(NC|TERr+QtgMrqz49H+dPfBg0;bkQ<)3 zpN>J%C#zTd44vr|B}vJNPl7pbs4=br?_q!BhF`Q}tJ0k8q_k3hcYvUf(035xnBZeg zbn|&EbWHj%D67IU;F_0%7`gA0?cRd8w%pe-kkI=^kPmQ!>v*?;b#&N~FhehEE9XVB7Z(H@ROt z+(U|&w}e^<+3Q!sVak!3?gPP5GSSut*UJHc_?^bn`YxQ5(ClL;FJ_0GN)Ze zUp!WTB0BBt-$N7bsYx6|T+Y&45a%^Hyt6No9$dd`?#nY4tuu2A*iM8K?LzfNVl5j| zhmcpjKMGP0ZsuCHG8?|7S!wpFS2n&_?yd|9{T}Ga8K2tn&a=hhk-Zeoh*rAAYK~~& zuWf7r_fXm#)p&)nJ)6gK2f$vs0i1o8rzosgo4`)RaCr{G$K_3kVY47vAMdirf!vdm zNA;U1%Po}vpJgQjBb;6(wq$WSHwRMmlY(SdXzNgj%rEO}#&(+6`~3aih*6k};rWta zIDr}9rcEK93yf7(+V;VLBmHiWM&L~4U@)y3 z4;i@AfZzLx7*M7l5l1fLYU?GNS}n#D4!*(;{Q>2XyUtT}uitghXcnwydR#c9P^Y8y z$Jn3yHa0d6!#ISm;vaJ&MIPJms7XY8i}WIaignrLOQX-QWRD=c#RWRwcDAxrP*$>+ zyhm5xh6!jo?yc$(AtNlf$c=CPi7}|N<7WiN70{p~BXuZgjZ%PqHCK>a`pV9s32rR? zhk&!=K_lN#RM$6=p7B=NYGapt6RqgrknC(_EE9a8l++en*Ip11C0l3qL!{-G@4o$w zOxoo!Jfej=Wy-VR8``*G<)rk_jZYfEY*X0@7}f6@?A#bl(-;4a&eG@^==vBqGp@lN zjE=Va?ti+;^?jY75*-CYVQx>F@>#62%*yL(^4vV+=Zsvuh$UneK&`tsE5k2qbWHi@ z9JeE+q_4>{V(YK`yD!YEQ+nE%7azB6bjlZ$RHw4-xw|`T-qWZBpH4yxkHYZ?M*YA? zH23*Q{ZUwhYljI$1qS|7LB)1hMJ0NlR@%xC%%R8<))Tun)vk}TT8$7_-r&G zHk5Cfi|NnRuDSzv`c>c`zo93Cm^&56!GwmEXPvs>??3NXi#*^W?3Bm&7W$=UFP^ef zm@6jfEW~%^;o@Aogj-cOwSY_lr2-Ir8|8^ZX}H3#vVKHIF_{|mQ~JIaNcb)F=}_25 zI4%QNzl^8D_k(Z`22*R;nc=rf9YbEqDquvh?XkPvhWPL%=BkY5YxMxHWsV7kAfUJz zI+#Xo|KsZRt~i)|gGardW2A>yxukKAXST+@Wug<8EWMZKweycy&9@;Y$dDw(D4Bm)I#7;#HpGFN5xb$Ig?3}>`x4K+z4ZAlRJV86WvVqnY_Z4Z%*C!F z)mr@q(l*e^fi<;1=QUTTR_O*};`iRx(`SD%08AKrJlEP&mc_Sx25x;q#Ot~D)`W=n zn3g>FeG76Os*q3nc_wF));E*y%Rh|hN%-R@@&L4x1mDa&7onihL&|9E@us-M7gZFv zPIK3fL%9hauCwH6Jn4OUQQ?o9B9YR$LH2Xyh$w#0D6igqGd+-a!DE#sxH->hSgwAF zx=lqA{$Lz(hvKz`=k=6vVSO|3dn||Ff{ml{WkdK~x=6|N=dT;0pO$TUOKn#}gEU1q zCkz+!=0bu9eEj?hH|a71V?72fJ+P2#7p8n52;_q68L+V>Jx+Ef9H3760Gg z|KN7@NK68!-F8|LIcE;~)~nlPr&c3Ukuf*jxF9G;=>Q!bp%jH3lOK>4wYB6As_RaF za+h>}-Em1e;P>n3sl@0*KkH29-#mX=YIzF!+YpT$&@`S%!<|0GO0V*Q6pM2jM8W;C$A))f^IPOnA60ugu<+4$$hP`-P>g@S7gWM=M`%fgQNv&uAjYGIi@2tqW&%YF~>CLQjcwIye!+|k8)DJ-uT-tyDrMf);ywdI3wh;VL&)XJWhR*pkvNR(I+ zEC(<+=Ae-ijk@+$3`Q+Qtluj?M$f1ZsTZ((P4z$9!Wgn%&{&dy^ma51U0iVuk&up> zT`nywtmZXcuBf1rx=F#C^s>aB?$Z9^@nV?(hGy|^aYmHM<2Y-Z%Dzs zZzq+QoIDCVd`v4Z%-}J+0C}=Uh0%lcE`H8DRomB;twDC09+Vp*qBS!HWRhC4Gn6!& z<)zHcv-KY(u7;glyq=Sip#P?dw#YHkeMwN2eUB4^KUM|RB({qqsnO5!{D%7aUNeG1 z^wb!QEd&S5)j~!2H8G1-QJhM}gbVHKQeOyf#iFEWLt|loSvlq`n>tc*B04H`%?q$P z*bM!oWnyt?)7{GMvvT-@Hpznm{A<(0;+6+EL>qLo8LTix;&=t z>MYtF?H}Sb3;rYIhUS+&KTIxiS?!9=10znwC%t6C+!t?10#?ucii^6T9+7rrT_2dO zu;K* zns;)1ewjDr6q{WPI+pd@F<+)8Vguqs$&BT0uPZl;of8q0ZOgC;ZLLP0t`$~wh!wTt zQr_V5rBgj~Fma@w{+7{Q!4n|$;?=8$N5@`g52LAQ!x*QkUWwz0*8Kb#ZWSF;R#03V z!7^t-S$&P=(8;MXIl2HwCr^AauFSs|-Q03LVcs}%Qo(ST51vO$xH^ESW__FW*>G`8 zYYuYLS}w-e5{&9+sCnY_^AfEdslu_hwzsp>-0Ne-CC$!a-7VDfGkuGO1TVQbpZ9nz zhI_r^1#&~pV~ulSr;m2IP)942|gsKLKl3)%?tYQf!J}`^wZ!_)(8;o z0ZMZV=(`U_@oMEWH3vkUGiztn*2Xu#*>~8EgTeZf^wYhOq{(Bva{l%A1JJ>3TEUdt zz75-XrIy7d`Oq8k<<8$V&8K!!*I&M^`kR}q%`_E$LZL3Bw|{TaRhUVf)!zMcFP~Mt zW7b%JS|AAO1Y3b%FhbQA)<3asB(@f*2p21lH1#?xl>w?DPANY7Y8 zyruTk$LoyS_h%I4o#&BL5U>9@{`ThNrnReHl)>hOy&@`D27RzPcv=5~H?~wB@0Rk6 zC%vUmNx!A|2UBpTpV3!(>$fwwc#B0A?Vp^Sys(D>gW>DL=$w+agZxIJy4xR{$$YOq zQ^A0cZO~JviS`V*W;V#=J06KW$)HMMld$G<*xomt^&z&+NIs)J#XGlIA40aH2G}CY zo23y9bTvsmQy@}8992RQ_Z)HUZa(%ViOl;gUb7YWsIYiF8#!fpFb_^bJ|0LHjj|ui zRO2o8Dk7q`NmJd~IbfgO0iP$a3&v?h)20vfl=uoDEDig5Cq~&Qt>F-H8 z&(CZIebg2Tdf*&T&*kmw`=^6kR-OEmM>Vja8cI7aMJK)9yuE9gB{D3bI|ZBc`%%gW^T`9k z$Xj)h;Gs%jxDCohy6(A}5Dh9Rtw2IEANfr4yb(5??>Dw0>nXge6N_*Y6Soq_wY5() zO=b5u@XsHO6*o_`FIKbgYW6*)OZ=LO8lN6p&4y$gZKLkS8sWE}Ei_yhISDtN>>nbb z=jnoBV9<3%1xe}Ls_*8A5EvKT;>k(vjui*E^m(W<{Vh)9s%48GVCO#|9`6K^saI!p}o z^qwS}`LYI|gp2TrYpL{%XM5 ze_yx3`L{ak3L`%IJ^}^)!Lua(puUDp{D5iFo#_7SwkQXD+10jX!i{V_Goz9#4mZT? zg!e(WcASt`c-?*|Xz?gq6VJPX6eYX&+l-&y znvUi4$D*cqd#6d17Ng-Zmm@cx7>QLOh#rDp@@mck=zs3kcrU-lAq`DEV<@j0a%Ib6 z79m4~^YuLzYHEq<%)igf`?Jy;R58R3+C$L{9#Lf66EVj0-1*^qIBuzu(ZwGGn zCM#K(7=LR{9d)9@2k8Fw<4V2#!R$LBdRgg6f|fF88i z9#S0%gkYC&eaFMNWbK%jJw;D7ihTdns##OxT7-|V0MLCqfb#f99OpOn@(P8Fjf5 zR&lrar-l}&Dz@l`DGR@Qni*mW4v^irF>FoE!LvJaD+I;HO<`{EV;1jSad_#yyHhb^ z!eins!7R&aV!_KXz0$uw?_tV;gN37_uSwB2`#Eo#!WQ?B|2WIZuX;;44e=4slySnW zFTfGh-X8dOmch~_aQ|Ur;_?tROYqhOh~z zW6V;JL~Qk$s6OF4Dy^U%o}9>tg#0Pkk>t(wFp62v-_@Ly#eXe`J00|9(M67B{&EF1 z5k-zS5f-f+BWL^j2N3_a&FPYO3q0$6tTfFN`gjVm9%pHEf z=Qc=9`3o0G{zhVuT#;PH$6Xf~*j1!NeRQc!zV&xS-~$OBgG*#J8ST<4ND~h+;ZsSP zRiFsw#wU8GltoncIvGO7XyZb^6|k1+PbiNIxR~8v^KICJM9|`kF!sgg-K;OT{9M=e zLqxEG_pZwfW9g0iH(rIPtv`6I%{yD~!<#lqG+7|IIzYYcWoVI=TIaOtdxP==Q;)B` zYVrO-^~hR@?XkdY*Hd+M)8{OoServm=^WQT_#{EXZiCxAjj!@_7I#C6#9v$+c}iCw z=4hLrts5Cz=QSZ)F1Mz?-O;eNU+bKmbq+Xt4?0gAR0Ey<>MuTej-MI0ZE;`lK64+B z?eB){`Ihj_$C_a?I^BQ+IVi+n&wC{NSg_9_795|c-4O860by-pCFUM~TQ1UibX%3O z$LOxp&M<#`mph$^2s`r~)zHjl`jc)}Kl;Q(8s4)w$FJpYgO-5WqrsOlw7D9Q2;Pd} zvP0w&zW&|a_XG#vQ7PAv@!I4PWV^WjEQV>;77y7!eM~_xF;_D&R`I=1FSr*qQx&LP zQTXM?nr*}~q>&9$OMb{6Rw|;99uSZYkJy5s&OT1Su46VNN3?qn-Q{ceE%R9!lLYP6evDdgqZ3W z9yvU?l4J2`^~TW+ncOz?$ZTyn&QiO2xsqF+t+R9O2fkv>@Ee-wLm}`GCEwy$Sz+2w zgt;DZQa|4B1Avla<`buD>{rtT2;Q^aQdDq zj&J!+5{3?lM7i#>oFOVpD=Nlg^2T6C;AGu=&0Gv$ou+4OY|ovPL~ELg)|NY_LS9Vy z88hJt$)FjRQy=-@!1>_5EdxL05F=xe>U^h^TSA~ra-#c29tmJN3`g7&wLF4Li6D>G zVQrUd2ZkN6GC9K=TNs%|eDjAh3 z6l`EFg{^Tdxf$}YjDbo`Fgd2A>ELrgT;=nN#Hny3QRL(w=w|&VQExPE8!z3BuC|Pw zb;j!-CHIq8dyYd>+Wf6b!6wBqlNCRtHM{~!nam$eQS7*R|4|T8p+ALEAvj0VnQ(oP zvFRuLx0z}A#~7yyd8={pJBCW@>>-AmIn!?s%R=kYnW?}pEARW<`T6r_R_Wp!8Wykl z?1!%zRDqzwyX{r}W4<>nLSV?n{#+^5Wa*s7W~L8!+Zn~(4=d;Vq3uTbt#@qh_w1g3 z8m3ba`}`qUHG>OL8wBVe3Oh@bAkEk5S!q5&*ug050+C@ulSxtq_0!68X~;dSlzrMX z#&|V~_8DQ!%_iQICq#B+IPX)085~OmQR6cYWI)m-&Ifgebe`)mywre25?BCNW|4w_ z7X+9{m0gA81~u>Vz*j@ttz00|C}E%9Ker0L(T((@kt#(GUOI^fBc0ntjl6rmZ&H>x zuGv2gK}7!f^O@U%;@N$ivO)0H6T1DSYxlrPZ6fqBjx1W?1XMDr%Gr+-qb>{HkttLE zIEHCd%#k1^_TnpBeC#bGkNw72r=1f?%|O@rfojM>z++UCh#-#(8gd|5e=vJE65WrJ z=WRcf`m<|)d@OFereZwuz0DSE7@;W%K=qx&@~f+TrIuR1p2b)$sNvyV)AAex+^%*K zbrKU+?g9CS&4UzgG8?EZExUf|j#}U1ESDfI(Lf49Q^6C(7v0OO0Wa}>u2M|Wt+0(w z3`>0s+=?2+H+whrQVc~!`_wFMYIo2s)}5xSve}3&szTBQO>5v@{6=K2I#K6Z!lFeT zW}e>Ni&QqI>1ygw(!Cb^!Ub4b4_en+tm~p{$N8XG{oZ$p{!Y_>t4c7;QFyB~Q#Mgo z!o6Iy#_9A$i=47UXOBCW^36{9=4Lt3ozm{r^KuYvb6}9HY!mar{&_$kvbcC3mC0IK z)6|r(8i-g}UrS zhSvSAhi)c#Ern6V$2{s=*%p{ z@3r+!Ov)#@vY?=+%`drQ+v9a(%(ZY|GtaFYo4({!^(k6N(|velY#^Uhm$Q z_0# z+*8UjOv4ukXF|&{3>F;>__tO!&TVg3HKKHLWm)m5`F@_>}6C|Np za;9(_28z%c&rqdslu@Vc(*3t)1rQd(Mj;iAKU{_^c>V#S=B;J7*@2f22S!yfmiMpX z=GzAfSjHBg^Z*`_hR-OT5r%D$fm~mm=$QJ+uRZ^Am{m@r6`t`}x=!gMc_6Ox-VE1+ zziU};M-j|6^6DmNEO4iUaEFOhKyJ3T8Mj_0L{aX6mfD-R%;)>L9AY)RT$o?Z+$NW1 z9>$H5{PX33TmL%1DCAW9vO(8_0EymF&xb&xkVr>8G zXN1|2*><*Hc0?;W&*ge=-}uiK;NwuNFyVmrvY2p!;2SqxvU0Ocp!o~(zSic;=(&&P z5i{S+^i24euujY|2>%0S6knxYkGlOc3XNMfNdwrnJQMQg3YfW?=~2qA5&9e(@Co-B zj6GDi{Vm(eQ&tx;3CAZ4Xp;&&&gdyRKD%+n@&0bC>iu(F-LzyGHNoYqAm168oB>r% zHJxbv_ktXLf4?4+n_Q)A{Zi{%3Spc>jCU~Jq!^!irR(XcJ+7Z;c#LKctN%pcmGdy! zITlUYcn{W^cKR}Mf@tHpO}BiM;ojDFNt=1S7i?ay=q;$&|C>8jJ^iOH?Gf26n0M>R zZ6o5qghBvprji+H*?F(DCHbf-dAV?_>`H<(fZ+We1<7WOwuop^)bdA)c4EToWY>Le zZTEt*aLv2k)UNglT^sm06^gurjQcBUe|zOy*%(m4N?YnT!fk2beIh)ph!o5O)rd-6 zoxISI`#-9_Ixfntd7lnx6p&mR6_jq+rBNDDL>lSt?gohk=`IDNyL*xD?(XhdSbod% z_`bjQ`~QCSKKD6uX6Bmfnz=_2^)=0qGc_!+6U98zRnF~^{Ge7)3d(2T^hN^fAiByxPGo=y0$VHC=Y;4$21w7}O^zu*?V?%Yj%lzC<+`_HEf%c%^Pk}% zqKdRf0ig0f_L&s?WEs3hW8eN-#)bIP!pWbTD(~UrM?Av0iqG7QUsqvKp;mJ(U~Yoh za#om9M=D;(B6>kt2B2G2VAAkdDB!sk6+{kyE$&3DU*MA~9d9Q^@_}BbUZu#tbQAo~ zdmK>Qns9k+jW0S9K@qN8Bc&_1xaS$*ZB3IqS`fzdeX2;yH>V}{nHRj4W+&rE#E^yb zq2PM5TiY=!Lg>ox*F;&ZNXlL)zSt7*6=G9xnO6MW+PNp6FozS$^(yeGMiIDTq(3>r zH8yv@1BjHaS1SY&i#C?k``agSe0L)LCNf`EFw^ezz)yIZFV@fIFjGX_7qwpaXF`!B zoI(B{a!iz(6Te4)s4zb8c#fbn{Vu!O%OWl;)nYEMIK~;vA_>dhe_MMaNi(<~|3Ke= zsax=D4o{@&4jx9~NE7eLIIRbM{`q@Rcm3fz40lvxKPKql);gh|I%&Nly8|9ds6=j0 zb4O-__bL4d+ofBaSUAe7ZghKlC>vZvu<+0yP(sahI$`*s3=+-E8e%EMXIyA%Zg+wtt#cBrR z*NcDUzb~IM9{^YWrlfc{oUjOXK?s8E_doMzz@xOts|%LD+CH29qP>wR&ICbbW9F#P z%?TzV(~Czi{r_Uc8d`+y1}sL>7)psd;e#fUjysA3+uCdQ)_T1X#U4Esgk+h2e+-|5 zb+Ud+%W(Vm{sv(^kzonZR7(%x#qW5U%A=QEO~mFRBV z0Lh(Fg6PJ7PrA)U1Yv&N^#Bk39I(})pz}d3I1Mqk`n2E zMW!ge@L7Ri^s*==CmQOzZ?oL#{&VCQ0J1Bn2`B}yvwK+?pY5M1|4HRpN=Lh2m|2Z+ z6W}UTer|kC#R+yg9pl)?M^%41LUhjH)lpMlYEw!_;%lb#0+DeWNDc{g7B%#kJ`$3eO)6 z*d@C{{nD|m$@gFDK$gs`otA~C7N6x6B2(-JbEJSyYDbrDn6_emB5&|bAoo*!=Ne#e zst^rvd2a?8@sRjBi15(-JUWtG9b()38Hbv)rn+Kw1BIH+$<2n@+9ARHCWjsal9cDqVy7>A zw4NNplcs^wyy<7PUz;x7$kLLeq~xvt!(5e{4xS*9g}JdtsNAiq>nF8Dl4{Qr?w7q2 z-zJcLM3p~nZ@D-V4gdiTivb8Okn$a%{t@<312M;r;KxB5xb|#1mTcC%pQ0)ll_J^c z;1UfJ2AY|WwYd+=c4I|!byN#`<8*YXjBYMBM9P#=+Ql({)c@6`+3k|i%)*Qj+&$9g zB#`!LsAHxcT_K0RlIeQZ(8Qtj8umuL-i@xh8WpHn+bQ^cTo{vNyCrPS~b?W#SsbfDT~NBLlM)FAByoS z%ZGkG<2NKr^Zn93aspR7{-y&v>TXxJys^|?4_%fHr>J>9umnRs&?dOmDks6Z%G!PQ zC#Mre&WQGRSEY5b&xiPZ3kv(6yP0ciTZwf*o87O+zsHdix&<2yv7itaU%$$`$~sSS z#ZaIO5(n3mQMWdym~@$l-{5h&xvP8b>0pkXCghc{oE#(MAzq}0UL%ywi`arV+=A8ph@Fq?$67zP$<@`>XB;f1t1Lnr&)<|H65dUg+O6|c<5*=8^8|RUQ zU55c>^x(Zau-lYLIM_2DHx)Hi1~Psoes^iaadxzPzBbxj1rk5l=YyB6?aCZoa#57>v%Mp zrz5%Yf;*(dCH`9j=^g6FSZl9|#`( z9~e^4%ISU=j4jAx8~kcrKBtFkm1n=L;q4vMR7rgK!uxQp!z$r$gTFAR*>e{a15D-a8H;>Zip4UVGV900=4|sB(hfk7@!{Ar?`$me? zwmY*Kj*F`TU^!p;U&oJtRE1A-MSJk{9><5@{S=OX?v%Jc$_MV8*E4-&INui*rZTgt zF@;GM&8&Ur<4#q4%@R`b8&KYWLTf);wY`~;T0D2t^%y_4$DJ|}_@*noL?wlH#s$C6 z10G0+@7ZIiE&y;n^fjPS?`uVrB^H2PSUTx+cZY|`s2Z_N&oMY0$qzHzpK(JeKk2~M zqCq(a2 zk}AG2bpCYgY+MW$u;Cz&T$x$~NS?x!d}f0gKhc|27nA6EgLwFNI7u?71hMkg zc8*&!yyQ3izh+b_fEbNPQ~5#@GPy6HAm9sYr{083j2D$Sk4UN%kWiihPq^nvUb1*O zkxceLRhqGPO-jDz=0&MOIZzX^aa$SCeB;&W<=kYXs_~g(!}+X4lp$p7hy8>2(gXa5-n#7Cg<{WaQyQ(Ru zU(pZPjz+$JCWkjLM22=%*aA(*Oc-v^HFa6C_*Hbx{6rv9SP!YT9h+$GQv;!%M7x~AW7+go_-7(H&&YYy zgaYDc%k%_^*p2A+3dF*sJX`j@gUxR(CWJg00@8JNnOlDvqah`7@*Z4$6iz7!lN?_q z>3(sq59H!O4ae~}!95CdRrnJmgpsms>EVW(g5YY=-`dpE?mg|2qxA%>DxR=#rPcf3 zpW?kAl?XOdR#yAB$Gb>$T+D3fL6&n({=_Y}E#FIDvHsc}?+)H9m(~^6eVg$S4X#H2 z?fx_4I-w-DR!yHWASN$^WBH-$5tuo6KjgCGZ860~JUOZQhpXPd`iB+`v#J)dynUt9 z>WwX(zN){Y5}kFEkBrRs-yD9S(>$u$V|jzsiUG;V&+Z&3WF**i-i4Zm!n1x;ewML( zQ4x5l#vj3sr_shE!#Iwrh z5+50TsBd2laH72YHpiqL%gMYGLP<0o74z;KPUi1TFS?5h zZ$bS`whhr&Z0Zm@R5i@r!OD1)Nd1Mzt6?es%aNXRJpsG@@y!(;L4?_j=cLC18Ol6- zFz`u1AFk?cr}9yq8>$^gj-;9};+H5v*Ei<>=~?86f%a zP3j4AOW`DN@qBo~+#f__xKHVnx{xCGJ~DCFyi5jrwTM2q+w1Wu>o^pnns}Z3{gf_c zksow#LfKpr0As<__tRar>h}W7g99i(z`wc;%^v$f%WxyzvUpJU1q%j!6MW$WtT~&g zEG=)FIr)HKT%OUgwLf4#f7=eaXMgGE4I}ULBBQ>!t|;IlE~O6N?Vhc- zrVThIOjdo!qFnHXb`*mg-zQy2QwML?l3gV{51WEmwVviFEOt-B0Xek$4YTP#=)Us_ z+n;8}KDbKUcFkylf2mDOe?cI>Xy%!Rp78%Vyo8i^ztVd^(i4_Tedp@UK-r+{WI}w2 zU72%YjV8e9hX62Ae7v0TPE=%@ns~EL{UCB$FtgQJTMFzRX8~kc=ag!lrI`yKzrEE1^R=i?9A5q}h$7o2gc0+1?BVtN;R8fdQJ;C9 zoXa&!3);k0kvbS{1B9z#=tg>YmUTRKy$4XpdhkEwDd=H|wOw~LsTZ96iJ zjS=#I)U}&?qU~K1M_wM)B^9_JQnA4F3NEeL(%>ULG=>(Y>_nkf&S>vcS^)dXB%O#^ zE6!HR=n>V~tcel9O6u)%TFhT8v&E*AI=0#ZPT~ETBrUhT7%*{P@}S|y*iLQ?bYIfEP}*QKG^+7vUxEPZF`5!RoxRCwR=JLNM{%=+vOjS zXU>N8MbRR^TIL&XBN)wnKhzd*kXh~sdq?b2#mp3n@4^>LO1-Z|*yDoY=H7guw5z4w zs#iEkf)UxS8)=|%H;RFz{#HaPT?!~hZdSXfJq0<&WOKLaB1$`5s&FJ}zBrqYzrx+~ zU0=xo3x!m7tS=YsSuY_}$%mNj-gr z=ope$DBB%#yQ~Mlf(TP1OyAU`q4W+qj^Dd-?g~%UbmT%PyTqI&O!k-SzBD2~*yOvD<3DM{`;&;ap0WQx-?*B4Lq$qNb+ z)5#SY{2N(bm*ZGoLmH&A-p3<#@E95?&nQA?y#v4)KFuJ4)IyC2G+@w;_ zs2!IbmkRcdht5!)^;t&mOHY)d!5ZaNJEU@{{Wt>qob$SjKWiWy7Yn^tw%Q z;a^p|jSdFnFBPYW38uYk*cdmKn3$V3By6s&s$w>_di6zJox&cOd9;DS`;MlpzFl_y z>Sb6LetpxA>FtxQYsB@%Pn|91Vy3sMJg1O14O_7v^wq`zSC6%Jo*H%9VGd{#GaVZI zcmq3w8L2ZLhzhka;dFCfj5DdZhjq? zc2l9u#(sMsQtP1B&luH`mPV{vp7xm3gm`k5OhxSQ^46(5)W44~;|$TKBJ;B7AwQLZ z3{2pyr)n^W3$!d-{$Q_`NgMkWqpI@lfOlDhi)D^C;k-5|2K69x?BHumZ0=()p!l;w z4a{LX$6=L85ts1ls)BC0JN<^0JCPjw&mT#Lsif|J=4Vda%Q_7*f5dYh{1j8=s(H3G z^-!}V=nJh!)V<+)_E;kUi{T8XvuMl|lJ8@kqG3UcLw9#le&-8m2cJl`JXc5%J8s4m z`F~KkZAebW=cRk4mDJs9_7C6=JPO@T6u!a9b%@l}YfiI4(Hc*kjlqm;DD$za{F(u0 zE9YADYh}8A)6$6x zI`GL)s$o+sKz+Bb%_?V{2cuKikrA<-XhYyH2(p4H*jG1fsMP4Fn zU>Ak_R~%gDdJKkBFL~cCclhygdNP;`QE|M5LuApVw5AWbhgA8`ZqQvXu^bYQ-ES`t zEC3LcD5WiGg!6amJ787og}OAa$L`>@Js)C<{ef;uPDRr@(8GWjaogpHKOVW$mSe*M zl^N&9JVys74S43-K05))RZ`y$b;=NOWl3uXVsJ4OTBqj-N~5=A8+zE8sS)yK+@wx81kVT?H=X_vNVM4yIxi^h%y#N zf}9ZLlZ2$wEJlsImCAe`2;~ylk{RVG2Dfsy&M+DI>tCRmph<{~Q|0a)oX4d@Cn!Bv zet+mboauLRm2dZcp0L=Va8z6$p;$h+8euDM7>H|T!ow&md`UBCJp`XlLVJTkF;Dcy zuu|-afMC0S5}e&c+={rTvY-+vw}c82Dp9wG8qKVMjuLOblSHI)x_{Gg_YB>v?E53b zch1?_xp{{(|F+dmCHv%lmQ!YS{y7|EIa~ZPevqavD>(3`{P+<+lXgl@$ifZRoc*d| zWawSIuFXY`YsQeDSL28DK0+pWven#(MkMuGfW^TtNN#=apAI}eG%LONE>+<+jcHRn zdx})*?<0Ur1L8EB1&@w67C%;>!cqa9&%vnjkaW*JTn`{tO8+dHhoj@yfiFbF8>0!O z&3s1bF3)2od1u1f#VAJ(T0P0yAGyHvYV;?V}?pf2hLxbIhw4gpq}gP(%y6m5wds)OplLTQSq%IT0U! z9(fXvHT^dj?nUH0R_lYlhkXkp1(W2C#4Umo?A8|F$XMHGZjq^@4T zldmu-i&v&+Ms%xCS%J#%5eum6O27&IqbP}9}cw?{H`68SQDT&m0vK~aKF)@DIn@z z^AN|C1<{?sbq`J`x^sqWH_=!5;kf2BjwVdFx`^y0S(!;AA`>vx(9l05in3av*D1f9cMx1~X8yH1I8N2PhEtUyWhD;)x6FucnuHUolnZp1b zOii2nCMyWf-qBu`|5p{vs=G`MCOHiQLm-#e0tOlXSXuuwXrZU+5ed;I z^B`-g#K;6>Nvk}x;s8=@#!2&I7%A<`(Qcp!?y)5$J7fmoSkE3%A5uKGmL>E1jweV>r-8(eUGefFl| zEkyZN>YCCy@x|g0;~P;v+h?oJwzgSr3c-Lx0UY7LlyIljSneHN;9GY%(-7yH;kaKr zhKwgnqADzBLT1F}A2TN?kW*s`Ot}ltDKQw!dnfd{_pR>OD`g$bUW?#~IL)WP{x1Ea zh7&dQ$FYN#-Bo+2j6!)s>d zT-0-;piVT9wnO{tc7hKseS@~+noAgM46&{l8)ZppklTwC@Zs%5D{S9ABEKbk4E1JNjRoFMa))wnqqgNKm!|Zc2a0SteQ2 zBwGp`1QHw2%lBX(Rd7AATX3F}x*y*sW~YUxZFzo0FN2G(H%KxsBWR_^+><;~8l{o*?f8%BPsO*nEvUrf7&dn%3_sCL~v}Hf!9*?w5)b~v`Gvo>o`b! z^-{38$~_|?2K(^CdSt3sbu^oQ8Uq@?J7)3!(9uAA6J2|Ib7!}Z!JDAx!(a5xv4byH zLxsr8Ju|LvKWS)?d~_{Y+y3bE%wwfVX_wvg!upFi!k?n`)D ze8WcNvFp}>ft?V?NKA4k^OF8`ln{!#phuNkV}j)^RBZzhQ5dbOw4)AOaJJ^yJTYl$B6(zbHTKad(FH#RxnjJ92k>@&r#zdYKq}-@I5&e=<4kG?I=P31 zOnWa7*{@#%^`CzEe<~jmqHSfp%aGh1>>#9BHt;S#_Avf|wfV{DRTq_jfqLYbxW7wO zg7E3PEu2FuZY|Pt75>ZlAJXt_T&CwFRzs=9XF_ z4{zJEY%bc}VGo1_wE>WxN3~2>8aSQaMv0*mQv>H~f~m%`;+fhT1cWGK_=p}G zdxTy>4^q@DK=0^ok_#um5Mi*u3=WR~Yo)+?==32hPGynnRs&NJz4-E%& zM`inh-*z$5M^}F-mZE^gXcg3VIysbwwxr%`0OXnnlglCUV`mAG!UyUWT?3Wiss!}yu^){=PU z$50H@%_er;=n}yVPh6lV8>sWb@3R!rKSuV1{;*LB`ct{cJKTh8XSS20>~aeAYKG)T zHoUDZ6-QEeJuPtMsYuJJdaMxN4@T2C=1W5b2iW9R>$RdeWK*f52vH7nnsD=YBD}PdAr{bRkI;&6eQ;1_QM?QzO`aE0s=R{0&(yB$L}JD=D?whWLep% z%a_l>h34>`d@>J1%EkgVwmFE`hSOfaOvOSzs_tYGX&@Cu!hycY8b(3|6mR@liZj%N zDFy4Sj2~4CbU>>}zMh+XzcPq&Y4q-6%7ye0P1`VE5=%hcfoyNkj?9&$B|8lDWYa(+i5=UTZ{aAj$STPr=|dm4I*p@j064ms)n`-CL#M2sfbp zdG1Y?X0TUek_2k!Kbp_}EbR1Pn>XCR@Iuj)AoeF=%@GT3+(lZ4g!uV5N824G1ReBYprjp!hK z9cCcClFCswWOnP3)+uV|a_u?ooZ9g(Vdw*wbwLWFt?U1eG{eu=&1(uSD+3a?r-Qcg zsg``EP~Of%j5c0%UkVI)1*1I@aN5UV3J!oH-r~2Cr96u|`x4JLfmXu>~F}iY)!CeBU+s)6@zsAA{_mcg2)EJ$?A{?lXZtT9i z`zJ~)^g(NBr&(|7Um!7{2KA=FIuP5t+3oFi{4bkPG=62OE=j1}WCbe{wUOFb40Bw{DCPsyXYmhWS{WqQ(3J-MNz2odw(3{|VkSLiKS!ml@7QF(5m0{k`Z z@U{x8Qxqb=A0~v{^Cm*P_JPIJ(4fOdmowS)4Vtz*w1=)g-RMb8+8N7*+}J;^lVhhh z))n|XWZI6EA{}uET4^>EZ|D8B@rMjh8TuhgPtIKl?9=qms8D!peF1-0aRO59;aPYj zn9u)HOBk_a#&%hE@NvwSJ?p_9#@u);D-%vjoAx4 zZ(lF%Le{V2;yLD8T$TI3SD(I~Kn{+Smp#-H&fW9!v!2(^QUnEuK*eGf!@ zNac9Mx3ip_I>;l`T~u^O_o$|tj8z2UKEaCDInrBjR59I!GaO z*t@JaB?i0K8Pyt`LKP!e7F>UJR(D0fZDGX+r~ZjYVt;o#r*}( z$%2)mc;NRP&Uf5Ch2&fP!~-e=GEn*fjH$9kf+0nB5@RdK8qO7q*Ci3lC0 z2z+mz%P68WX~)#BY`Lz8^!z+JqGB#uN84YTZI>oy#_?JhAK!PboJVh(N5=`4=;1nt z@Wyfup`9=lc1Q__PLjCPHb;tB+-JdBcwxNnhw2DkvVn$-MxR+SnZmne$lZEhJxPMw z%AU}O9_Pfvo{7NO`omriK9S6)6R?q)(Sj!0^{n0C{rqwHv)OY=obw|**8H@r-G-%+ z8<%v)ul0EBNH)oJ4$VwE;*cMoylt8-=Dl&SPQO?m|8iBa!`O0-1X6#Qy<4s*{8Fsh ztc`Ad&n=o((V$;tt)$Pw3Qow{41&6HfDSPwW} zG7z!eyU_1c(7iLgzmb8X_VutR?SJh`;3@T|teI7_Z-7f){VZwU80ns@GeBu+K9XuB z2xs8VpYPXwT0T{Hz=c8?gnBSUz8oUM>BWXm#mejgYKCO~0SFzPNg&;GY_r=wu+5(P zMyh6CzoQ+69bdjzDOg(r?yeE;`<%R8qiODIr}OqFoj(CnmW??ee4R!2_JidbS(z^VQuLm6<6dnu{^reg%D{uD(8gq%}=3u~;ty zQHt{3d`SP!s+3%2lZ}X;%K>ABkNx28T#WWe%Au=*@}=|JP(us<(|NvL!V7Xa<)0rL z-Ytliiog)Ch?ALShh6eYI8VGVaRi>SaDk08v46r)&_7A}{%Wm2#_RjK$rWtO&cahX z#wOMX+QIyFs!*}Jv|o9nIHo-p;mfRTeas&#~~9=q2w$mv29dzVOiWDe#$A+ zkZD^B@!1>f@FrIap4I%>`l<+d_M&+!4CR?Y%I4bKltCDuDXfa(vjaC2)nvi?nZ<0G~N zmbf`X00N$ODXOiJDuy56 zBZW?k6@S3Ue?1yy84DDR!zD54r}63k8Wh@-qeAnKl9GS_#Y-rH`g`N+)1psh2q85+ zBUk|=B(zjN$1m+oQiX+=*i<)cwO9tO%h^Dx+C?EJ+8d!$(h7uREGW8ouE2RoFEICQ z1S;B6cvd^xE)7RV)a`J_URMwf2kNL=O{-8t*N6U_3xvow{sIji7id@(QlA?!W1cA+ zphvu^y#Hr4)EMxNN4rG2WX|aAz|hsjAP9S^)ci2+${|-nSFy##{JKM3i08ln*>P^1 zMj2*=D^|em8xMHy(1^EHuV}J^?-N9@RC3(FU~@1(Ir-=60l5a|nA}oZ{iigrw4dJ1 z+RE&dB>YXJT2aFM)**K+shvd=4m9>8MqmJmh)iXrH0iZU8Q?=A;B}-9w#UI21K8ZK zP&Hkm;`SFT5S8u581F}T>Pty(n)FW~oqZa=GAq>Jc`bjwdRHR*6AM%_A7gsmg7SDZ zX=<`e`)d~!@r)LG%=V7zwL;$Pv6|A3F?3C=`?V$GkiMcUSJ7hEH-;f%MZHcE(X1>9 z__*t<3>O=!LxcIAeWwdT=B3}l2T56Q>P=$NXuR_vZgxjh91kvjciafwXQ<<*0n&8y0<+OTv?dh2Oc)*DNyPstgu> zr>e$E5!Fpq1KPg<9yfJ`{xS@>%EoORB=LG7gN~vrOFAurIYbENX9HgyoR3MTVDEya zTFhsELe!n`g;KaVpmP#0O~`*X{e>w;G-c7Kmnr*$l=_vsR#!O!VBT2SnRM@_0CCfG z>AFcGYtmlc8w?RuTqq3xZogKV5C$o?c6J8GNpDjgxF_uDP?I!D^N6LSRSxBhA3C$Vys-aSrml3-$M6FIfaIRv zJ4-^TZjNzUH-hddJ>zwnGb!DG+(hpL zqDv_~ejo^Tedk;LK1gNweO07pRFiU4sxtbs*I!9^1;E!5r@4upg5@N5Hq1YFLrD^I z2D3up=d9&}Am6YW4?C}`1Fo&oD+oRY@eTR`6f&U5isz7DuzTZ-s77tV!ppglA{61-Vw$8 z%sBOm)CCHbVdAF&c+X~UtpWl8wNm0w2{7+do(kVFwkIV#;FVv}S0LO{1|&E~_SF0y zMM`eO)cAG+L)9e`|2XhXX|Yn5WlycDIXAbB+#bTWl5G{Ds*`C?LVq!BIq6(kZ`aR- zQs$x6RFI-x9jX=ns)fhiK(KL!=e&W6h}T;EUHb>R68WOuP)Y;*J++$jbDN|jeS4En z5!!DH4gLdmdhAf9DoyL(Ho7R34FVFMZ^`v2Z@G;;P`bOUyD)o zrDncoj~NM(5@FG%$U|tlw?^@Besz4f!Nru9)wDGl2ry==NP@fWt+4fBVpD_~H2q>_A2q;} z-S^HxXfB_%lkOlOJ4XIySXpe=uMKMMo*x(pyIb$@goOiwfUVdIiA@0zXyU?^-`Kbwf zjmFcF8RXg0X39>9setzL*vREtyR_mFl(TV8db&O9aR?Ju3n`KKAD z)wI~0Kn2{ga2?DWqQ*`~l=C$=PJ~mbm+1*NN@3#Xi|}+|j5q42l)y`9QTqKH)02IP zxIIBix5$2_syB+H1%HBWzbz`mJ(0OVnsgqWV8>lYhe*PxUQzxf z5`=2X_O674B+GdsFA$ogC$x_ATd>q4Rs~4ccQ<)Bd00hAA4Q5`qT}vH%|3&%-#)FE zHpH|Rx1w`xrI{9HBYIM4X3xs%8)qUk=gV-`G%j?*7}x^6(_ohUq6* zGI06=h9w3ds&DuR2YwpnW_eZ+6Q^cE%vSY)^XvFW`y9mZwh_=0xv8)39~5Hp@<_~_ zqUJ>cNP#`y6~z+IgSG-;A3cguC27!~LSYL>Vu%@b(L-dZSnt^_Fj@ZQQ*02HLzK5c zoUB$cC2$Vnh192ZqC&*LdiK=m{{(0ac#whz20o{>XchHD@Kb}PhXhcran8FHt_X5? zo`vs98J3|IBiSGcSz5ddGyEk>{eVBx{k{4(0OL`ZN)r(ZvpFc#STYruo*WjvZWdMi z;BBHmA0(L@@pz;F2Jy0Ho*vsZ>h7T*8n6Q?3`n=UsIQ0n2mPmjD3|zm%;>GDctz|k zx=~Ym-5``f67v{f2m}pr0NSRAPz56ho}<3w?LcFVEXxhiTkYl+nze`bvb%SEbo*zj zc$+TV0&jG))0U3==)Ia+-%lw;RHyG)Q-;Qe8GkMy##4TSD-W^PAt5Hb`s17R)qsT! zAMC)e!F%35)9^sr;oUe(<*r3QLZV4!P#xAUe!lFs#noIVnyM5;qols^^ZC~1SZJ>im<1!Cz)lH?83&7j>gByT3IT!f zkWgRK117W-6tSd01iAYaJHAw4X>GUl^p&(?Rafg#Tt8}F)8Jltb@k#JfD*TsXv#Il zc3Gu$SckKMmiGBLBoF_FQZ?Cdue;j~#$yj+DdI(e-Jl+0`3fggVxHg>drSGM#I^yX zQ3o7kF{R_y-%q;z#qTduazStbC>f(rj&f(je!)kbV7D5Ghs zC7Va0K4tFhoZ}4pBSCI7%k1y$M`8wBkM{80>-Z1^707O7{<$#0L`wx zl8^8z`FOtUk^ZCqb~YE(m*`P91QtfI*GITSRYj+$BKSzF<-sU=V@s|;3V7iqv>vP^ z@K4wjk$P&=l)_f&h#27V5?aOWdc~Gv#JmKQiuYoYd~q+$ew{;}Mf~!<>-{i%i6gRD zHT~7!6ecydHFkm*{}ao zOZxW)@*}B3Fq|P-rFvV^&g5_}z5#NPlC(L%g2L`*8}eob@DA?Rwf>;~+Kbcb+fd@| z_znt=(Mg2rwS#Uoi`oE1m%~B#oa2{KtaH|+Km|h-vaT!`GOR+%8l*fl3cy?i~D&p>xzq-#1rZ>pRyMt zt08j0Jad}Xmit_K)=R+&kI|Oa@inBUq5LUt#Gj7Wf zPaY4Nv7#tGxKXJ-q>>I``ydjBq2ksy*4EZ`BS$)fNRJadlQdy{A1J3@MVUL?j*;vY zC_nzgFgcsPkLGKb;d|^}rx`aTC$;$9%p03TS%G`q5K;Aww{KBhIb47A2>LWNZ!R5C zSs^YUyc}@9J3Q_$XcZ`IC}?cRbI>R;R&xIZ5*Dk??i{JQ+Ook9OVLvoEr5gXux zkB=lKf`NfZV`GHRhL_{ixc?10KHsWd4F9ax)pM#xS04*2EBj*p7>CCtx8pw~3HDvu zc&cAYF4QC9&4atWfBREnxuj<x4)kY5F=OTa3-XsbIo_SC`TYJGwK|M}D?XZVTRmo7`G;}uhv6A*52j^m3{ zYy0oZ5L!xdWevv11>_gFMIDwg*Kv;?&qWKNpC$$7QDRc4F)H%-|fzMjSVC;K?0+TyvVD4 zL{#v}Rrb;I+Bvk&@_M=4s`;)V^yaZ} zVFlr-dqdYx(mIh4_4lyg7hVqFD*26Dw+ZzjcW) z-wPe9vwkx=20Yj1!2~g_4nf*pt#8J_ypl@sV9Y25p#nNG;rG|w;BH6Ox1MJi`kWqk zOPrc(_Ue3qFF`GI52gqrDc)HH^nZ8Z-?LZ6H{nWF6O3;tRz;_O6df_EUg18TD#7(L zt43Q}4xGSrDLXzo60fB~-L>BTSfm2o9IX>>TdM?Idslhs8c&hY=hx z>DB?B?OuY58a?!q%y&7&AALron*c8nST?}x*IKE7?a>U{$9f=M2Kxjgg2qm!$=@6+ z)QbWmTrA@rZ~8$UESPvf^S|q3!}g7-qSC=oU32!)8{VkZ!Ym12>^=sW)?=Iwht6g% z_uT5mRP%t0XG6S(Cc8c)e7%l|SUpm-14MjXdZ0)dj64DNc*O7aTGx}n<>0GeU<;y; z)H8*dj!s$0Pp9ucf0;rMBTc|+4mp>A$ zfgUV0SD>B3^PZ&ra+)hCwXHfvg8Qz$cX{)#ok>W&ni6OD;_c;@Q!-AWq(j}k%2$xv z8!8w}!XQFa%kRB^Z}?xs&!h5v2f1SF#A|*yG$mc@zP`%yaCQb+@is%YHZy@!iRAkl z&DG4?&-YJ}1E|&2G;KJj&ieVe{f%l{l(vc0R6pD$P}(XY0am?;6Y#+=I)R{_-s3a2 z2|Ubun3YCk7xO1u?nq>R#Qw+=XIB>!8zQ$w6U*XDJ|E@(W8g1C+d|dBV2@#e2ZY? z7=rtw5$(N|Z?o42ylWXjp%SFW0!L0!%$SJ(bF!&+D0Nr*App7uPit@BUArg*d9+%%r zSfSLr3(8bGyoi7S1=BL?p6j87e7h7R?b6E_!57KSC^!gxR5B#T!(zPEnRKHtdG&u5 z5+2z0K^r`L-rjOgXcy}3HbIxfL_l&Qbp++_*45Ci;AwdgWng^7WIp_(JmP25_^N?g zWQf=G4_|@iP>Nf?CQ*}3nIbO-!U%?L5Q6lHI4dKRT~#xP>BU?c$;3Mjq1r^tGd)+2)iVNAVyz(%8EeZ~piNglS_2Hew z#g?distA>BhFhP-5IePwaHMY=jrg z17ycXD_Ui}B9Q#Kd!l~G9I*fY4{yv_Zgiv51Y28LTn?26>Um!g1m)Lf(8IEp4omz7@l^co^F$E>K#Pw_ zny&^!E}W@gv8&(Ay@hcr00Km;17J>ssQWw`AIlzQHVPAA+?D@(SV43)gwyMg3==Q) zZW>tqNo@ie(0B4Muyd}+O0hQqmF}kaU^}-v)$@>6+1e0(J%pYKUwn07rOxNv-t4%O zaKzeIky<208nI%(r#!`LX_Zu@*B(ubt+j3B7@~txHX(-Ipi|5Ik0;x>~>eMH5;?+fCn-p{@F`}qCgA3S)^d7tw<=RD8zyk0}+SHfjCxNnYctO+Jh zMYW_OV4e@9t1kF8f^PKk?~}`4bnKbv-sc-8zOj-T+Ccbh<)Bgmzce&Jg<1#M(0Qj# z%Ta3w1c@v)UOcZ%`~#}@P2H)R-wc}aa6an$--K}MIp|n2lG%@>-GLrG%+$s&VGTX1 z>J(bJwdod6^#>00+H+HD*z@Uck1U{r!pK-@hsISmh3eLuRDNC zQwreSLEpB1=Q}aB_QzBfjs#0vupY$gj zWH(UCrjxN?o#a%ymb>6t_Ka~OIJp^=7w4qWKJztDuI_@(aVvt20s8@X(w=aZeZ& z4-9QFf^Y4RTWGtJ446Ap$N%vpV>W89EckWaFueLHY@P9V(hm#ePiBrGt0q*}a}5|( zFN+yRnr~KFok{;ddMKC&Yhui*pOaQ1^@w?k!#_%J(HSkbK#OG4$B1rYiVOsP{IDI! zsHmNnu)pQ2n^(#w5t*ic`!f%#GOLV_wumVMe5CCpW6vl&Z#^b7?fNl{`wbr>6*fei zgTwkf!eMu|>>3fqzuXR?RkFOgR~&e+IPK5`+X)wtQchr<^+nAOo^C3(SFFOBi&M&z z$z;XofMA_ZW2iy}1sF%E9`3;Z1r>ce7Z*Idmd?-2vR(2Ijo+4;#u|c`aOe8rLFr}m z!rlR#2>i&BS7;h_j`2}H;zbyB{}-wk23Hrd^0w|tBJ+zv;9v*L?F8 z^cdlOK+isvv=+OqG6Ov#8T^sFVx7S5XU2J40nsdA}TG*k{&>!b|ufUGB5+GP8Ve_yH;f6QQf z!4=9Y3@LqrvY+@rq4TJzx0iuspqU%Cun2)A?7GhMbfYEVefRuB#TVP{A()u6oLf+xbJ`*61wl(SSC#jeGlvw}<0cG3t6vQ)Z(sPv^=JdJ zU5daMzGi6(VX9V}el0GXZbhD}jqq*Y8a|Q0@Si%RpUw^<@O@MXf@}}ZK0xPM-$Sw; z_|Ma^L^rwKMe^^RMyfVK@oGuC=)<;bM(--J6Yt*_@i2GJH5p11X(uyWgh;zdb`%9$ zE2~RIgAtyBfr>&MC%%X#l2`AP3_d&|+;t3N=iO^mVxnzh)&SNAb(f&f?fbuKk5{CP zQmOEYo3_<=KHO$R#FqZI+HU6k8N9h&N^^m4l9)P2N26D|o3!XH8H^N;HWImony^g< zfH)c@P1-4CziP!iW)fGbR{Q0kY_Jr7ESO4^z+)fg%2iT7$!(Y|lsYhgSxFmWIc;^) zkY9kl#owE}C{u>@IYGx%BS^a!D@C~VS$s535J0aIK?aC>=k6g@!=b`tMGjPppq^AQ?PsZ5`wMwCP+NQtTD7v)=B2`wUm4y=s>U8~rrc7C*z@qI z8N0lmlhC2IiHl{AZ^gfevJOA=rFx^Ay*~B|$KGs1xH^()gso>Tk+`*=a(s9VfB(Z% zm?qx?LKUMd8Dqg+hb*`yGXImJ!zI731)yllP+A<3MrCd()|>X@xYt@T(Z)A74`J%qBczJEedlghkHC@*tXV2 zVh?*mSJO1`QR-E>H}o}nD}8Yd`@iI%vn+hq!8c;!=G7gTR2TM0biss;Z!P^Nij0<`da_h+(L$gwaRK z@>-Oo5D5^wj~0Jh{$XtEBP7$Ltj;Y3EkX){t^gr?2Q-$s=-Rqr6@R{Qe%IH96330jJ>*X&u__DLh{?MQiu8Q|y1nT#Aw%cOWw?hOJ`R4@o?=LeE~aA}FN&qa@r_}iS1^}0nYU1s+w!k~ zDvjB;U#Q{JirdKqrWLfVvaO5;f4E#sfiK6z4 zRMj5t!`!5=&&P^uzJYj3+Ra`7$@*#8zpayP1~%CW4bR2&Gwx%isBHKBrKh_xP#HzSPLT>8(Av~Pt zq8ao0;(sfIo>Q!Kbz#sA7x;QRV>91SsQ0Tjwi|k(l^-0UQi&wa6Zx3434kPqDccVh z_JThi$C=Z*&^FVfgC}tUx@@2)+YC5x6hbKJXjL2MhpXZnrfj-zY)Yy9WC zj+XT5qZo}WuPPfJlhkRniI*3wgzAP`j|(*%-{sbSGcQzObCH>e)gvH`W(}J zG(`@0aAbXDC|#LZ9IFMvg5Ejo*FB+jpjs8Nc5S1+x3~o67m&vo?h99T???Y9a(pD3 z&a`^bC+nDfw)8#>JIhqfF_nwYGC^{Klrfk{d zKVzB|K-)Vc7<)-RD}$DvXRe-*M$yPYtaE}OoA8ax!`#X8UqX4~oeV%l5h$&%q2nD) zS(p6^1>bl+-Wdwj0-K@!T{<6vJOHp@Q>hbvrY zNb2=tMWv;hH&Lu2t!|yC?(W;`?Tx>4s5633SXfw{7*VL|0#}9XI(!jBm?tswxVRW` z)R!V#vKkIen@X6+FF%8y{tjw7BFHkN_EDtWzUfG+++8Gf4t`s~`g>^h z?!V)3>a4^oQt)R!E)3A@aAMNIsgZ&?CKXHB&)d^qh0N4^w z-5Xo5OqJaIQ{6NbeHII-Bz=UdMyTDf$DX6frTWC^oY`G50g-0@-0$ignVJld5^^_|yOYACv&;djHj+01okyrfj;Uxli-IZxA-gIBvI zb?*OI_1A1zGeK|tQIt1%Q9ZXxbeuU=1*3VD7D>i?mo`vZrn`&o-9wxp^Uv9Nj|3W0-w(uKc|JPF z3*wTS{ZEjMDsSy~;Vp0sc&>p;8IL&>!4a=fE0pUpLyZ%$KK?&n*X0G*dVdvsJG|u2 zw`T3XPP$mq{)gKZ6_Fi8k?t<68p{(gztqbn>ULMrYE*mT|!cVpaK2j5wb$*>p`>C!3=qAfoFJ>yNidFDSRh`aJB6lc3k)_YR>?4 z9Hc|)LJJc<%5MjJgEXDG{1g$k0vI%!_13B=2gk}|KUkjCiqGp;Bz3bJe=|zn$9TVo z)~^k1Hg0jkxq6pF>pL)!H76M!o01%$+bbBOsGPRE3iK6=Wz<9X@uUnYa5aIcJw)x~!xZ2DfL z`!28Bba4rdMmxmvPeyCMy-M-B1bq_+It!`~-5N~TM$e@F2-R-kStkrPkaqPdMc~S3 z!QK!{NjGhiv+_XMVkFD|7qjSnjOTkOU_M4R|Hd|Y@~kmD{?2@RCExh$#MKraHbld1 z0cB5;#H~C9?)89U`JoLq<@{GwLEb!al0)!P^THZxM(o;I@GCC_e_~SSH+95bQ1~Wp zJ17Vf?_=JlHr{qkgOha#NiuN2O~{=(#L4Qem@fCmxxyZMo!8d=YF!;w_6eTVC6Vs> zIC3RpBXKbOp?DrIbv=R=H`-tO znQ&iId*?c`hLJ zPMDQEdsf!ihJY&(_L*OtmXnL0$A+GK_jOi!%tAdBX=>C@6(yz)No>ljb_xlvJuT56;@PW6BJkPd*rf@1=3KqUHR2m*i+=+%U(KC$(=&gANE9N^V%*k{S6<({CRpgefw<;5tG>q>gT4!6fG zSWLc9rwE_{HRYCl7MUS9v8DuO-o>V)^+@^q(5r0Et5^ z9wSWq(WovNa`Crk;f1PR=k?2n9W7dcLCW@!%f!rPg;nto4*_kuN|l0+4P1ib@=?W> zG=cTyAieNd3F><_xn`6Dx&g4AzpaY8v$++#E3<7=p*Cl8lRFynC`)kjfngIK_k3v9 ztuK^j{@@6uPrw)#d5%XXNYNt(DKd%u8trw(mI3hqaR(v}8^w|B8 zn^j{m`o}Vh`lfnW-#U>;)F9O#s2!4|tw8q5G5SY+x*6q-xtq7Az1xE*yP6IHg7GX` zF5rTSjxg6n(y_lH>${=Y_3va$_NzJ}#HyQItZHTP_rvo0xUmkDg<`J&)K4`F)D*s? z{o*539{i)EO0BKY`Yo&;`J?-ESb05VBzJy^`jTb zFMdo0&&J&iobO7lUPazF0Pb!Lk?Cs$u2UNZvbaEcdOCIgo^N(s9Ov)?Q63V+HZ`XL zT-N=KS6ni4w;*=66SDcUr=+TGhe<6I$nz9TBc5uWSQM2QRCdo}r>9D3H| zXNEm$+JN2mj?>?dsyFq3r$b^fdP3v+Bs!p?BYb)L0Ns&$Yg{IeSQRw~L;bA!EdK~M znn9hU72y+U?uT;Mo$S6p`0{pIk^e_<6EZSEC*^3!msgYZ$qa`O{!C>A_pvu>gy5A8 z=zCK2bTa^bqMWIJ&mFTpz?CAyp;|=Srn@T}^%o^-h#OGdE67F7)CKScN%EZyS>q?Ej*Tcdt!9-(dxaKKuyh*eP6n|YVN|lN->g6 zDIq$D)H7A8tVO-`#0^mqkZ>0}Cn%-rUg!G76pNQ!eO~!b_8zq8-h_YrtRkCq>7R_@ z3*LlK>th5GML$Q|;2H@8!sPcqCS>p9+OF`?Qn*j!(xr z<)OmUfz55y(A72}RLsyUYPx4Dd1yBOgkzhvEwT{0yY@g^=UI%@-zXI?0(itH5mcM$ zL^vNa#599C$`=?+Ck^j6+TOmQ<~1ol(GV8&ZgRh9I8T)=2BxjxCl8fMfCetonXeUr z=I~qp=;)J6OgjDICMw5$KLV2g0GL5VH(}1ZM}^)IdCwd^+8p|*hR{gQ*jW!H^)A|hQF3X z3LtO^1lLG*GW)M8zM<+9O+HrW-)B12g#dTHDu1ryZtL|r%ihBLc*|S>rF9cCu=i3e z8rG2)sEM0Jk!7z;1=S_D|0D*EO^yfO`G<3wsucTJv-iL*;%sk)U?x(lPN<%=)i3)9 zN8yyDyiX3dhuA8}mL3^Bp!?0W!A}0^<2S%`SLJEQ-WbniWB33n6sCE+Z}SJ|Z&xKr z=6(2I-=`$adJh?mxZci!KT^`(fI>TnKZt%x*^pNA>j{{$a|My2Akq3b4L+jI1qQg5#<)zWy;CRF`cODEcR~F8BW?C7o?9 z3qXRtCwy%-fe8$LvSsIFircr!%wGIs=?km#XO;RxX;&}cl%Em zM>TEy>LWzS_FU>eE*P(D)QB?sb)_j@fJpeC*FgTVg@>RBwGy!1Lp5@7zv}DcKe8DN4OfOgB|YuP>AOyIvIo zFR(>UD?;)Y)OUe%!=5)9W$0{4_;ntdc9@+D*{RS*uDV#-aKJyG7|MU(Uop{~AuBqI{&d5Z*Veuq7(Tn6tOad?0FDAo@LqL0NIo6q=~ZB=DjHSoIoa6h(iK2P$LP7#XL5_wW6bw^}F11-_8kt#6$3I;h5f zsrh!>sZi(=U?3&o$j}J&M4cjXbF()qj-sHTfRt)YPgk5413JU6yuq7}ey1^PBHE!^sXmXmpJT0G z{+R*2>mjlF%V?K-QFAURvrEu`r-^iT(a&RPYXcHAjiLG^M)ue^FEjf`Q44)t+*O_pA;1Tx!f1l@sm8U zjYWyR(}*uS;c;7;ae6T=_*pSm@-ipBtvPSOokDUE|b@% zTl7MOgoN}-pFe+oz2jDcY^-p&P;%Fb(%7CzCE#_bTLzS=MdKM!&D zBF58+FyKbh8z`Sx2%peFM}drQ+)oXT0(ttHn76=dm=)srVJf5gvJq?<&qsG}=tjOz zpbMj)MMFu_;tQI{4CEpKC+1e5qFym$JJgYblTGzQ83(DsJoyRE&^SDK;fq!Ns z3xJDCQKD}Wn=qwafc<;KS=HLI1_leU94F5y*fwU2!KU?eVlcI}Nn=P=D;piP%A5=M z-ZSw(@@)DlD=U=-H=a-43Duh_5LY^oi6X^bJ^)*(tJjhTV?motYM*?b7#E6R4z4c9>oxAh<(LQ{zi`8s-96)XX3#cpwIo&}fd`LbWUBG4DN$LZCc9&PFLu?W5=^f! z{GPqm1iiCt1?e`tHUKRj`{hE5C7@;JH?D&F%iGef0Z?)a(e&agYI^jOTn!kjiY?-- zw5|_^>9*B5B~s+%uCmqQdpWy~@o#mKpFE*72`r)IUMCasYk^cXU})#+8g2@QAM5T8 zQKnpXYdLCeZm^UIgM+e8y9d7Xs8REy|B8r#vNNz zp(@+0$^|G1&V6V0<;SsPvV=1kp`KYwt$TGo#{2%v5bF2AZ6`?s141U7x9TzsF;Gw5 zaunrq1NFV;scCGZ;ru){%;Kfx42nbbCqwS6{?cq7&#o>p>DvdXdhxRHhR79Vctu>bX3eao(k)0gunj2EmOPG4A zRd-NbXEkM2tt7IE;1tqlz5gxLYfpW0$HGrE`g;|lu5R}0r05+K+4%6fT;NJ`NI87k z^QM+0#Q#DIC)i@m)uJ#}IDdj51POPD^b%X|ZnSUW{-Y9u;!v%u7~not`6*TFv7Lit z$nH8Nbf*LnMiy~Cu6Wp%JQnlv^q+98#0GwzOksS}e}qah+rL3+DAMBU!|Kc?(O3Nh zno)FQOE-#q!hjOJM$3NeZ`F#?rr6grJ!12fSbsK1E3@Cl6__FVH#pgVlX(?dE{dom z9g5_8)C6gUzF0-2EUG0zUrdn?M98`DQg!mYTI=U8jVnfzeBF!Q-KIEE1H0xg3XW~g z4Jqb0WbEoJogaMCWO2#P$H(WakLr0PYK%y9O?yE^`^34X1E&2l8?WA7yYFa(R5m3U zcaXMe)LimX8jT_qp+5TM%a>Nn?0%}kys39{+Ly3v>ItdO z5feSanB8m=ZHTDe0h^>&L*QWqK7E>BbNh9MAJ>2q$UECO7PP8H@C5CY`3pE8;u3rJ z$ARA}M>s^r6&sarT;AG_bnB_ziKFOsGdvGvjG>~Rga-?6P)BUl&j zqPUax{Za3P5^`w7CT=ub^5Q*bc2*oDAn@HHfa{U}% zB|?7wG|J^$U!R_h#KV~M{cPm|S(^XDBH38oq}D3WXz?wNSbrVhd3>bBDI>&>xpd*j zOVtP9z4k|zM3>k7;`_A{m{AV**g^5<-t!_NGPxW$Ach(8RtcmW=UgwNj0NknX#nUt zNGheQ!(j;Trs>2o4xcx(Dl@m*oq}K2s?^`J=6c;TFSc%FQyLw;e2*idTQIj>ZyTUA zu5>DH?HSFHJ88g~?zOyI=2hc!X@0^O_s|s8Jr9cjbPC0YY<#ZpG`JVcx=YS6Z50-0 z9mr_6kK>A7BetA-|K*G5tW+x6_%%Km|CL9>9X|PH#Jv^+|4LBTEDp(RU(H?jkIgnD zP)*Z^jE5s`;=C%#=ij=7|D6-#-pHQG7IyqRXiN8(B3PQ z?tn*jYjE{$JnIJL)e5uT>($q^-;!}~xbCsfQ@7X=0tb%*DNkJ!((~vY3f$0=0Nl1{ zYz$k0o+(Goeq)=)h8z*6>ubY$&0g});G!LKV?pOjT?N?O<)NsrB`ompUj$5sK3FGJ z8=YWX+3OsHubX3lpyux;y;wh1Vftb>cS!xbV)w;_Hh9*xw={QgyH@HmvDtSS50pnWVAP7I*8J7rJHIc-e`tquZsY$Ho zTajL;hQEIM{Lj`=_;92v55?jZkg2>Jat+FHxp8|jCm9-hA;3hm)b%(>U1Y#M2)H+5 z8|vc3vxu|zH*R~}Ct$1(>DkAs5e3Dk0g46)T$1{p$j8X}@PJu_Nn33ayZ%4vWfNkBFg8BuAPT%WInaSezd zRde5N*zrUr%Vq8x(eZd4F*WlqvAD(s5nMPIbPmF2yKLB6#V)yuQd zsqaMYyk-r!mUbR=!z442`QwucC&-z@h9Jbmo@aIU@~R8d3fXL( zugCr3(b6s80DE{ipvx*$wJY^^{}|QO!;^8ojA-hAObQbREp^0v^AheyMJ&MjG>Gh= zN9tDr(!=HD8)dP2{T(#NzL9F9(_oXctfkJ_Nf~Tn(_N=R`=0O#@EFqB;Av_#Wu^=(hC!t%eg^zcw89d{nc4w!}ZesLQ zZz0vgXJk8i-b9cFOKH#KWgfXZ!U5{}21%IYw5tOdF-#wVc=iDOkW|^PV6eLeb~c{l z&gzmkhSd@4lj+&`>L`r%Sd5sg3G1F0LIrwIA2C6!=3otk|C*;{D**yVZJcG5=T|s4 z&>XhVDvarEgR8(9!IF0CgJtCM&q!~acq|&B`=r)s!NxbhH0_<=T{j1j zREHC$3!_Ex*`3?PXVPkhK289_i(9i+k`d7Eq`kFY4XhFxG8L4PXs?ROd&bDrU-k4( zan$IzLT5l;R=si!V)QsWF3EKLr7{iNDH|I|UJNcfW_6zvuP zR7RHr9H%qn#oo+I`^A}snU6RE8Rr*Exd4isl^#X*zf;=pja@qupOp>0qTf0WJMi+S zI>eE0a2f)$1b(|mwOeX3|8tMlLu4mxS>h`xyPTJq)*kT=dnIKiuze@%h(;$&T9x%K zK?p>%1_jD`=dv`(Fb`P2Wzn63=KZPu?>Q2gFGZ>lnJeI>GgO72ZsXNu;xp7c*+I+~ znw|~_Xu7|}(?@3|J{*d?^+@;mu4weOY1rOlBfsd)q;0j=IN$c~hEdQM*iilvzReW2 zKc1g@(Jj5Tc}ZxlOs6|hgqc=To?d5330QWvz8#g_Ia<+WBHrJ5IxDs&4&VI?SnRGq zdQ=m2uzp#GY3PR;v*+14*!*(w=iMhCW}Rj=7)9?V&09E0ZjC4^B;Oz}hs}*l|U_Ys)7ci_lI|G!0nF_)qy;BJ(9Ne=x5Ifu095ky6adwAsQxhtjdpO+I{k zEzV&{#xQ0L*VWyzyD~}H>SyLK5eL$+70OKu>cv)VPh7>{`$Xwp1m7%xhV8Y&)6mcs z3cxC)Lm{PLEb)(68q$v=OF<|Gt96lJ_>@J)P$+~_ojv5F>10OeTAdm!KJhwZ5zX6D z>XLfBEjwm*_mnkx>^FcOkq}E_9)Z0Nmf|I#x5BjdnO?p*VG5h*g5}E2;$KFbs(2A# z*q9Z2E$oW(nnAxR(&+}WJH?O`RkCzf$j^$PV{U>sVBA6$KoiwljDkGX-^?fPOM(I;(P~A2pl%;Pp)9aZtal`ie`ZYyydv^eY`e zz@FSY4Ix|3fUK`8Rj#DIwszU~FymNnbS`~if?ER0HPKRzGTNL~kS;I3^+-#4GtaJ| zp)oEOz!XKYoSm7l7e(>bmCX1jXOI))?y~om{j3&}EZjNBQRMRord?=dS&| zQ5NaLBW9dy(%6$~oMd>VXTZtU*|DM1%0xwbxqaL}wnt5He(8L2W=Uak1={m;(Cm$; z0n%r9hq%m&yqwav*g`ibJl$TQUvL|uth@Ai`+cf2thku>u12jjvn@~T2z_)Z0S6bm7aA!eF zGV{}(#>?!+&Z6Gz7~iX~kc^(ue=)GXRw^FP`J;Zgz%dhDJ!>i_3fnbm{7ecbkLbJJc-BHo5_#hdqt%_ZL3IWvv!&vDB8{5-;?QeRoD2E&p(9{;lR&yyI)-3g0dR z>l-lvcb)Hx{(nD})bc=Q`kQWZ7n?cXxeNY4!VSG0R1i_SD#&W384|R(TL3i80#x{uIA#3bG1%n3?#6g05HmrDVB!yd~VTh04Rk2|0{Rg}DU zSt`F}UbB@A%QVnu4#d@i}#yR>-5W1QALv|{emS_X@?IX?tHrt-GgUUOY_R7rRp&|7JyAIS?%Ad;7UM^ONMdVJM&gpU-{DZ3gwGPM>{C6S*_CG(~ zXT^uC%i#H+3wWu4U~!fw>X4 zBClFDk!1T;-de4prfXv|Tw+1v&MQ}yKix(Q94`_%ccsLX;3o~s;@y+3szqtCYA?Gu zL0vS6&y7PDtIJW3gR5ZMn?yVOyKc!7wzxo+8_o{*!rXyPMM?S@G)t30$Bk7YtKE|r zzgN}>eoht+vV%DMyUe;ab8Ci<38bDAy%qRpNBqlCWx?@}SIII~Bsp|V_P)wk7WAIb zaK$e^8q9*){-m;H#^33`EbyL?etm&&-F(L{tzucaDtp#KBZul?{+a4BSo{rDnwp7L zTvpxlEu@Cj_FUkjemfgejXG6-9B7n(k3E{S#1by+QB~xq8r|kS>qj{UBH%( zvbgA{ppSJ)Yw?x)heguMtzYSsa z;D^{RC|AD)>5=S2k@jT^BAG?e*rfRg9~FpW-pOC0aT#G2)apY1E~%)Tcfs8ulm7t4 zf5a%vt*Un3qP0J%M=~`I5MZ~N~_J|kR zd4`3Bd2)0J%%VJ`_N+~snKNHsm}E}FctT}u@B({YY;jrCI#x%p0KfLq@9CO}2y2Me zhH=Q@q*GV+@yJpxckA8&U3>q_&Br0FiqOeR;ey?aul#2V(FgnsT@u%&xBO78RlYX8 zu%R>ss>8iZKl>5vfYZ>Pd{41^Kv-Lm@N#A=M$tthM}4S=&-SGYjBnyMzW=s&#yM80 z;jNps-8wOU-Kkr12xV$XXU4&+^7R>ELg>S|B}@PdK_#R+)ASB{AOkeB`d*0>~+r5$qb zEC|4|Y{~89?rhYcM@f<8h_8-jH!N2{Nasek6n%t%_Mh;|dMDf$? zWqzG_+p2O@g*(5+rvHeeLM+#)1^#mLgreodGg@SJ?~WPNaMxktek%qwW&-MB-~Ntf zdz9-}cAj74nJ=-qxHguKExQ}&SEaJDz8TcU8UNLphmlfq11d|F*u)qjnK?N*lWlEJ zTiiW7;;_Q4(=gA9z+EZHrfKCLkY6YosRiym=!zoKW;@U(H)H+$mi~;%rd6J%?gV-~ z`Bx0r#X?-PuP0dM)R-0sb>^nK@RA#2=gk7*bB4O>P@NSEuGj=pxP?FlM-^0L2Bns3 zz6ld~d#<4EpPgf8Btr6C!`N=XFH8$e{9%$FH;x|fil387cB31!UWk4~I6`Qs=f_ zP2?iQ5dwUWmaQTC3+n2SMG|*EYC7U>U^I1x$8JZ+Xq$pwAN}NZQj%$b;Tt!W&+yzA ztqR_qMl1|Mn(*d->R2NOVt{KjMwh}bX{Y{zqA7QYCVmC28hS3-FWIuU>aG8X%}lwk z37MuY5{g>{&gr!^ndy;NMuDMC}vmUR55M#(LvFF?w_j{l03M7&av-quMwhLlIcUu*o}@I zP~Jp=FpXkO8_}$O(`#iqjrBSvH6d$o&IW`~1m)PYx(${CMSpOqD z`h^__cy;H#&|eKxwSNl0^2gli$A*fi&cb%_7dZEcF(ytm#IFP0M#!Gf5)lG-*(XLN zhR~9?@lTY19iku`CV*HXOu%{Dp`Gx?gE`?TbsqJ-3udA+wrudoW!@myC2=JsF{Ns} z%c8YGvBKAezz6u6gJsr)s+UdpvCmH0d`{tk-EQAZKC&mlk1FP-{CBgzM}S3u?OuZ? zv7*6z7Ogu~>TtqYgegXwRe8p+L65j2R=m{T0!Nu_f~J42;5y)2yE04ImWXe&qCWH- zWwGnDtqmha@-9-8^i8b#a1%ty;KF-$g#8?}S#&Vcc5PJ6TF%wR@`J-DqvGw0UEPTGY7zFiT%<3@hK(HxKn4YL*Uj9VTa)L$SS^>9u-aR zPZnio>5`biyja)qlmxBFZXs~rCMPFtqJ3z<;Ug+RplvQLE~{$M)}5fqC17Yz&<b`8citpUr-K`YwtUy6l%p=d}f2=mkM*ie(+L&eSLuM-; zl;71TX4w^4=RN)EQ{*V|OYi1z8ct}kGbA)HRMdKaRqVe>y)nN_u+T3%E6F4lr#;38U&V_Xv zbB!BbpS4I7)&2K@8BO()pxl}P*K>@Xoq;u6(}i@Ah3Z<5q}>9_^dj;?C&Og_H2elp zeG@ZM&<=m$#6#y4UZ#HXY_K67-@vLfEiEmzB^kI7{0ZNmUzV32DhB(VJ$;!Iv}MBZ z@;ayUboMBt`${pTU3bTJ-wQ7e_>C{mHKb@4@dK=gIh|9;hg@gV%wFY*QAFDwsbD^o z2GqR~^{Ntr`Y>pFh9xil+Pnc2o)GvQ(UCQO$zM?b40+D6I`A;1TK0mPd=Jl=BRhRN zVvW=e=YZ=wi>@W*sz|O{^h$0;=;8ePRfO8H7QMBrjpt>cNPPHrE*~ho)8uw^PN(e-Nf83a!pC842xLwFRJ;{1SYAw@fXR8A#x6}O7c zO{I^|S=7XNXyB*QJ#5m_$0nvExYi=rL;v!~-!I@-n-pnYu{SIVrBSemZ8RQwe@9d) zg&WIix6lDU0&J@d&P`+DciT5V{Xz@VO?X5^eqBw?*x1kAiOH5|?l3tyIbfNVTLPHm zJxt-XOJhe^L@_jess~StJz#i$GN%Sj=U}>;batAjY);(pDS*DA;hc6q9^uc|YX#2g zlByJK4RC=3AMw|O(rR#&aV(57fbtyUX-||a=o4-3MT!>Q{s0$NeSv!9mlv6DrLcdu z%-7)1rKE#hsaI}%eS*pl3$DEIV_otm?6v~=SlF9>oE+&&LI6&`{Z)wfIwVvJZ#Ta= z-@Vee6`)Kg)A2jY?F8hY?2F*Tn7Q7mt(C;za&I(OLO;~hgz8qhPN*eDDVcRZCA@)7WKUX1y;u$?Ao>KYY_iCy}AsA4020-6xeTh`4*L0kxW@39YTH+|K0_X=(56?e$ZCxeGt@$CXlFeMmj6 z#pOb)m9Y6D)}=~?EA#CJ$lz`Nt*JZFPYyy0nqL11`@TkEh-N2;v$Va3KmUFk6Pz6^ zJX1CZ+yMiqBS6M~@ARuTKnl#~WA=Z0nBOx8^W4sAq;M0R$LC~PtQ8>%y5q$53hcD;KEz!*mbzr@!9}k36xVUz% zQmIrEo6=z`6Hs8_=c}5UmTx8|&dAh-l6-#z^3}1}oIU|wd?9zJXw9y!Rjx3uoMhL~ zDp#7bsre=6aH;);rO(5Uhuiy2$>bGoIDT3~y{wcKt+dUx7t-DreW^jREa%xIHLqu) zo;l5pr#y{#Ad5K6M0@V0iYeZivSeE4m@M&i#v9%V!%w#q+ReZ-3!pGhC47nG3b*Ft z??3z6;{pUwtPJ`h*MoC&6w;+ywf7Jp1}u+K2rPY)$ZJnK~x-rpCepN*>VC5&g09+HGk zEQx9-`E?OZnH^WSEbA-m?sSPp+E3YD%F)dDbGzu4AtEZ~pYDy_##coo^FrX8tm~e8 z?*a#eWXQ(-?OU5r0}ShjRTsLhY4BP z+rJ?r;lGAccm>}!x~2Ly&#A-e)9-me#V^Tk3B)I3-m4rzAdtyxghNmZ?P_Tj*xac=w7>cG zbW*;91Ad>O;|f>O=Bm0neJi3T7NnI`8vf&&@RBNGM8aaN=p$tOrr`TNad2x7nDcUx zixSmY4pyMV_xwep7Z#B3vAVgmZ3OsR@fM^BPF`a4;}BrKz4nnfAM66PH><_e`HlNO z&@P3e^KH}DPJA~}2SA^Z)2lqUJowk65uhl-MU+(#=i41+%ykbxvwLITa<1qoy~7P{ zhZ{nv6)?Mez~d910+dI8(vjdy=FsA0pmfjFAP>ZPU*USv4cM~HNmIboBKoMQ=#OB8 zE|3uOLI{xX&np*F5c1APDkN@QqRR0YtNtbH2xZljRmJ*54W@wF)P%fB~xSY^MFc90x~5}Qbljd3Ds}d;cctRTmhVu|Hb+~ zcIFc2U5DU#^r`Z%hqa*(y!p$K(5Mma=8L<~U;btvy#`x8iPmNz=1Oo~rIND@}F^&B`Ena}&0S4}N3;!3@lgpMCW zkYIk)Auikt$8_%`C708n@i5$pP2`Rpc*?=G6=w-U31_<3Edenclmro&g9!gv+^s2{ z&zwvp#L=rgHmRLl1pI}=JYAGl#NlWAupk#)B=GA=P#;=69Y2Jdl$8!4R0i^jL>_V(Q1n9cnn+20jALmHYxh+(U({2!qKE>=R` z>Ep@HDNLBUg9v2zZ6BKt8zw}QasT~YSf@ad)W7HVPyUw>r6_d0G_+!d3Bh%R@cyMN zF+mgo*OR%W)&X^_#IDYTEq?D=)GOiac#H0z9K`ph5(mI+*5nRww(+>p2qff?mq}X8 z0*;n|V}s#mnN6&$xTE%YtXPf7ULiYR_kio_qr$oNZxRIctX$19d{{jJt9^Hpa_Z`* zJFYV^vYA7;@`{Gb@ML)PIeUM9B(Cnc%T-h`87PY+4cobvz|C*fG0}7mX1$;$C^sko4x-%RYgYyJe>}mH0&6fm&*~&s_MN`Qra4+(8Raz%@YJ zi=(*q>l+7OUEyAvF*CosWK9fA-*-Dhf*NIIeO^1AQB$+D%*{Qt@$i7vwX}@R%+Bu1 z`=hT;x-%o!<`kUAEo}p2&4GscmA@y{Q{zLe@KRZ6F16<5WvjJ#<)5|MQyZpa^DE}U zCF%R=WpMw?(>|o{Fw)oaYprYXlP!#9jU6Vv!ep5wSZuIObVCQMx9% z6d~!b7=*e5S2ZX9YsY zAY!{pSo2jW4buOSG31h5BXixufN=;zxBkwWJMMM?PaJ*`3xR=4aGdtf;BCD>NWq3A z@ER@dRs}U%lqXW%BmP97u96m+u*%kdVLa81d@kV192+2lsKKvcMx34 zP7^p!J`(6Bh*iacc=2fVZ7eRkoqkwb?8IZiuWrbU9>j?aKAWDdgDMw^?VcvPbGlD} z(c$3cVfaLk@VS5TmAMyWIEG1UbrK^Rs&0Y`}&MPlJw`|oIG zZ|3(x!Z5u&xNB!N%&1{vNDnt|4p4w5ybo>SVpIJ2BYn$+O?qn>B_i^~ygh7H%%~{I ziR|#8AocvYnvRTtYATP~GH2kEo!#Pd)Y_v~;_mQaZk%itJa-=t@!E_P1Gw4$#yfmd zKT%*cw`E2RQe-{%*1zMGe_}dbhOpF-o(v;JzcciziqHjWjlGeDZI(qymmu3;*RbR} zN>2?_5)>pwU+UcJg}ebBBNi9(M1TTOC@6;@Od-k>=Vb*2pc>w7EOd}}!lS+`Kd%?i z^1d523>&=M&ixS&zOy>)m1 zex0jCOaMBU2OU1xC3u}}v5D`RfAAewO=y|C3U0wVIQE6}l!u<^IP327(j5aF*cO== zAUTFqMdL2I-wsLeLRw!8g!hXk-zc#=oXVU9jM*s-CdK7ux`ZgX+@2`j?1@!k8+Hk! zeZe9L6&=!Pdur6bwhwh-|3?n>E+3w30g-1n{{8LeKuf*!y8Zmw=@R?XL#I5B{|83d zP!LKG{ZhsY-#HKfdm(lu_i6}_z-la%BU!lJJ29)cJIz?yqjiW60w1n}D4HpflC%uMc2O9fLT?&D{Vn4XXv*Hedvc3Xngrp_PlH~HCS(R# z0={HNE5~IL26Pj%#j`Dz18hW`yNSna?_`ULMUxHVG?VoAX1rc0-39smDO?DsDt6&k ze|`O{Uo${M$U(PGg_ritdiu9H{tru!CvT$(s2@BK!7a^Wp98a7J;1%VSOgq!o<;7w z3xl6gHa_OY6(R?}A4BdWbK#JUb3@=RrG}aJV(+qrO*$17`8Jpqdk=O2owDC@Lr&mP zG*qFw@|Js@8lazH&bNF)E$2e2K%NMhGHqkA#{0ZPAIUt&g;JQGeW{)icJsG(aBvW8 z&7t@c&&X+M4#C{c+kfZQ6S&2@X5gCvBq^&8!V|Lo2g`-D*(!4F?de#xSvKSN+82;# zaH1o)!Sc(eY*}dVg(uEtY6rT&Dz^z~8Mjy1>{+jKlE_S1^s;bY@@cCJJ_mIY=hu`d zeB9k=Z(Bt-MQ?(7{gY|kztf`SELlk3XGeLnhCo<*Xb{(fsIAA|h7q90o>N%7sbhtF z);B(980gW?uNC@7?%`upKm@LW`!U%+kr~g$kbERQyfRg?@%ixoJ)(?6cL>fUv=eY! zGT$fEaQ7xl=}#^b&`2r*2aqg%0V?R2m^ANyl7hAn;8m^@K{n$#ZDAr$ zRf-8@@M6D-65^YnlCupj5KFK&*lp|gLO$i6ZO|enjJE|LkSnEwT<1hMe>tikkGf#X zLdmF~lHGDVvDCcm$L~!>Z{wX{b7+*|8|39qe?M+u?4RD9fh z=m}c|;uaU21Xb5G$2qJI9!F0$+Asz$PB-Lf8}2E5hxXK`-aU&HRw{qyVc_?7iSY9u z3K18NXiisq7ZX{V0~Y2s9yYhTBQ&$Rmkn>Ik+QuBb}*+sgs?+oMOU06Mr@S`$f`)u zBQsoxtqj$}?1~%ufbM841)0P>Bvu9L>^p&pQ@g7xzJe(Ns5Dp$*4j%4Uqz5S~E7k-ByS`l% z1&!?C61#5jQY;yL%gRA2?BslmMoVSc8qc(4>xvjLkHSY@*HU9iJ2Wwv@$r5SvJ<{P zPJoS$&$^UOgkV#}`KR&^yn9Pw{o#aL>YXq1x0*uslY%oNL1Fn;eEr^^|X) zwKIH1k3fRp!^`qF17>MRHzpzJPvlRpXrfCJZ=`BE6i+&0Br`M+D?Au>x!(eh_~EjT zh?LZJcFDZ|aW)UReh{_OS7CA&y1|}-}Ir{IS+a5UAH#5)g6^pNiElFy$`^=nwqjulxcA+T=m4o@vVX>-D z_YgV&{+|c9&EW^X6pd9nBUkLgCvku+VKuvwFE+Z9M~X!*P_FmDjs|4&49a5{@l80y24N>+$E`sm^q+Z zH!Vnh{=^lxR7k=~VS0{NYc?b6yA@*&LnpmDUKG12DvGnH(YGz!G|dzIjgpv|2wN_q zBU4ZQab$~6X=3Ye6>a|Z(wK6l)*graZmrKoLW!UE#=i@D7B|+i!6V5mNUph(abRa| ze!t#bLn$4e{zeH=afJsHvv*}Y>d$k+6&Hy-XLZbj@OLfrR&RPJ0Be1+`#rJ!?$yKr zDl=}(#Jfni@ZHl*P*A$^F9;!owQODW<-IQZ@zZ+RY$Sxnlabr$e&6vpSm9*6}ZRGAI_t==sGOU5+XZ=xL*_ir9o?{y49!_P)G zo5*s-R?ZeW4*d54&aUv|wy3^Xu4-vYV9O!{+JQ^2&{c+J(^c&Z`FInx0PboRM8A{6 znQfShsbj-=Z_h(+qaG60<|$+OYE&mHJ1~?x27I%_#tMtl9ga=E87q(V4wQARppyxu6@9<6kD0VtNjQrGNP6sp6_YaqD4B3x|IU5&}6sXlt+& ztFO?fXg#dNP_>DQ$6m^fA@>FmY$+*9+Y142Q@u58m;z(b7DNQW+T&ZPI0X$poTlDu zsQ*)Fdo0)=>e|502fBD!f(y0ee^x#lav{4Vn&#$>u^=zwW0FbxL{~sdP%*#bhuOh- zmFr%Lm?|o?!D5CLZ7L?W%tQ?OI92Vl#7@2EAcWpCmKzoiSy8vLXv{icS0mmUzI&|@ z0)%UFh3qICAyyFs3!)X`q9Og0`VEo((3=L0;3qe3`VtcVlcYui2x)PuL{*M|wF+`+ zm?vkT-2{1hokf^Lo*x9A$7JdJY-is+o@3dZnG}W2uLB|87YPV>-3nX~*)PWx-%XT7 zj6fGr5)_`Os>JZ)vjy^pi^36oEpyciGs(w+-t8Q|)(hS&`)KdA7eeO+HbIL!KKYA* zvYRbTciMaB{6>P`)`ct_3Niy8`SAcc#KD*{d=kb{WB2=Wd)$$svy=!}`};I%!Eh$+r5zVrSeqPk z?=$0Pe*Oa96T`3Mt2Qh{9x3KiZv&eS7*jTaGUvR@D}(&*XX-rvi4y-(<5ZpAGG|wM zbQ8FV`{{@$9aH)iLQ3=TqC1;~C|L@h_Y>j|+1<%9wDkQ&H{BM9w;+Po4RFdIai=Bs z@Wc3clT2m619zLyl5RY<`O9<`L=%|j1;Ol-f-)Jy3N{$%m*pYATbW{`UqSC3$VZ@d zISy?#Jukn%CU_dqZuyl_YU^+68_h(B#m;v-il*%1FKTyTl@h{hIug6+r;F7Y2FD zoBA6WW;;TEdIu8H_$h{*F!skrzXw`&%zP$h(k9#&W{EA4p;g_ROH zJimNkszqF!GK9R{PBW zq4zggj;09A!i2U_MMX!tTsp8vsuw?a-(ud#44~QtddkkzGO~Db?xzIBd9Iqm?5FTRwL3{MGBSRG>Mh={Od*p82w{@bL_(*L9>L zn04%OY`SXznI%>pt<V zvL_d!3b=Ji0~nh0$dxCeH6j)(S!AIk9?s5u`8U9%astjxPz)glw(a7+AULkh^3K^~ zcEURflq+o-e&+{H9Mr>bCX0vXP=QVymtVjk$5Pv((ZnJ~=ZZ_B6b)U3OC2h*Xu^7} zyeR>~umM5@EInXmPF!aVywlD(Q9%IA62SLDA7Ucqa^S37r7&l(t;&vc=L^ehGaQo)3tVj(grzp{%a!q(a^I%%HttO+A#;SqBHG4tyrOwS2k-ydQpG}ZofP28}S zpA^T@;#+amc`|SW%_A~ID=k#n*RS?w1B1GdWql~pGe9ikSSuz3_aNkrC5HH8MYJ-@O84t^zUQ7$hA!ma zew4tfPy#lBpm5+#BmvoR*sGT-rkYBFp`<*AoM8!<6!&q6Y_EdC^Yr6yhBUs*E;Mre zG;e=#p8+=ru}P0Axsh?V1_R;t0r9M>b7i2K-Ipl@0nZ3|T539PG>-h%ay z8yRLlZB?z!K6?Qol;Lhct*0j~P83I;!lcR+eEjj9Wvx#g_oaf(cBSls4xM;TURE)j zOeCi#CH0MjZdkN7RJO2};M`$#sGIq8{`5kBR;C~ZPX%mQ7192e_Xl1j%F`$-<*HSP zNNDbQIwabC`-~W&wL#G#=S%!OmF2#qJ=X+Y1oJtIFZ|_ZSe-NtDNr~)X61*4m}`}r z{$HA`kcKde5HU20CVTUo>DtVjU&d#Lnk|dGh+hy&-V>v@PsO4Dd)m_H9o|#lFkqt< zlo-D$n+_jDq3C#WWa|X9wzfNRhyh8gG&_SI^gPMHeOAkqYniF@S;H$CXP>QOEZz1J zVCK&{4dae9zK*<>^0Al$LJPGEuf}49pAsMcDh^NVq;Ym@Ft-)G1M{!cgP)wgJ!lUm zYi}<#$=4IK3Ju==6F7Bg@SuhyF#d0gH=8`sN!GoKrtN6eC<1v&IGPW5HtoJaN3Gqp z6rIuugN_aOn24x`z#A-Y+Z?^Pbw`}kgXE(OT6*`3&Of>O-7O#=Rw0kG8`Ba%<8_4$ z?O$$2k<}ww*^k%izclUnpUEH^eQnH0wI7tXn_1Lzx= zBLOV4tra29`f1)RoQT{fRAO`k?Jwz~U=5iBHbgS=tCX~s894Ru1!~KjPcOXXJ^hMS z9=){_bo?^xUu%RRv+(!DcDHn^I%YWepXApZg=)xtxt%ere7EB6eNLSRLHOZM1wJWy zd>ge$!nqAA{VDu{raLI}RfDNx84qr=&R*6ZDmzDB<@VkE5T~=UF4lTC4g9A~|8BMT4}Y=|#K!lFs6?9*MyY ztTas_G+ex3bkIhl{h(7Kf!l9aA^GuS-=q<3uGhUe6Su#XQ40K_tL20V*24Wl9MIyr zw))yp;02J_O%?e^}65}rZI-pZ|D^^2<7X48Y4)j=cUo2J5r zfu~0-vseg{kXtc=v-+n_{(Bn5nrAJOc9Le!kZzpnIW+r;(}W?@_Hesl1MYICYiz(JO|`|64n3n^FqsX$cAcKC=Mm zk9>~ML$iB>!U;y5+u)irckkc_Tl#MLm6MD>8DE3*izZw_+`*p70V7+A+20A_h%wQm z;0xUFyc@xHgQOkY{8m#{OM!z74H1COjt2OE<_aU_St0O)CFI7h_g{XME36u~7hb0+ z%D$>c9(3JIn6($HhCJo!qV7;3t3B?=mKaiKj-J#? zM;*GYUs1k4uC7AQXwnC6Mjp*ik3t!||vNmUwgP;FYaDH71 zz8a~Hn<&-p$y28bCJfMg`RF!~89+&7b-#@UXBE`@u8Bl-pvDsgmaze|G3peQ|OT_L} z!^u}{#MQVoKXrrz`-we4%E#Efm_NHsWR-+`8;lv@Z(1b&mbH@CR$Qds&rF2gUyGC| zoUsCmn5_RQG!t@v;gHv8Z}PcO;puYw>{!rxt1CZVI%3QJ(a}3D84D^H=7u;lmf#IO5#Z`B1=d#w2$Ju6$g&w zf`jtQ`7WE<))RJZKEGAuugjV5XW-Wb2U@+iju$2=rwHf{T<+7rfztv?@)wR!d9{`L zH>A!qOaK?SPD7O-{pZu4#jqRz0>mTlzKW;14{fIrisXtX z+F2r=(g9%`>1gS2GD2pnMDIfc07vZF9{1Eug0_3c5tDm^6aOtp(-p$)6TzIR1Cj)t z+i-Ec`HgXE@4d!V$VLEf^M+*5xlOEPD{1>qO|B^kiMxnfGs`W98y++|*$6oSr{9Lg z3gGbmen_pI6kj;A>=qky;-la3l7pHY(ucY#IJv;-3LjY??n4F4kv)$oGP75{mTkW% zTr1!PtNZ5n67(u&$10Kbb442&3i|Ln4#Ae6|NP~u-UV*6Q?XvuzWr!;P)b@4mpWJFS{R!Qhf$h135c;{< z5qRleSq^!x6fnt?I%RnqVmjF=kqYo*v}U}{bSEUO*XZ`W|2sJ}fz&jo>E7xG42FXT zV@s`fsFb|Y)_E2WA|1F^EZHnSw?b$bgZg5dIEf^B2wHjPkh9O$=eQPmV(;4K_UV_$*I5J0_tBo6o%wE>OYtgOM}iBaWtf_n;Xb z;1_0rhyx;S&YN6lFTH6C3#Yj&{7DC8M9#?L(|TAlwjoqXSK>8J{|PKP!r;>>c9OS4 z=y|Nx<~X5}bvmPU9=xHU!Ebx)>)Tu$?5Cs&{&f_2Eh8XNAyfaeJmso1zlbXH$lB?y zdB(jTQFx5M`fH4Y?iDfL)$1|YF*|Z~TEU2V)2SP`Tl8JJiI5Rq|Cw6bFB;FUH+h4F z%C57b{6{(5^4{sLe)snHHl0&brji+)^jhmp)9u^v_Au`0Iq8GnM;9AIK#nt!cA`eV zGbt&%zdO=r2MDxn_a-C@#f7H-Q0~#|J=qDS9LdyIIH?Th^*3xYuPw@af1KciKQ>_hlE8x zZ%DZ~%lrdg_a9^qtI1f(Alx&JRzU(7=KkD@RIJE{5GBy3O&gm~uQ@Nxu3KGj(oTD- zfBX^t2nKLI9+9hGS>0E)FFANLd;4%cL0xu4^0hkqNi7C}fEHUrDhI&ZCHtsgr=pg~n6Eiu9qxkshuM39%;! zVijihIK8($R-_4MFU03jvB!iB+NFMW`;Uvjf*YMu#u)$Pid$GFK{H*Ii;dzR%&`ls z3WberCRgWidiFx-$L!i_LPOo7j0KJl$-0?ya88qxmv3&B-RR=C-FbFEIgnw?pjsws z|N7|n)+q%CaAQHAVx~>M{0%6~0C$c+2TZj6-XI+(-vxsS3~I)fzXh%%y{Z~W8!(Ma zL~x%jDbSkSpIhyC!dT9yLABO#zoy5#acnS!jOv{}AmOhUBMrR8txIG+(S4IIvv(op zm+nIP$=t(~!}&aVtBE_w#(fckm&QCvagXF{wZZ{r&so}9>?MPU3Z2=cJ9l$@hd=VS zU0RbffVF-{#xo$%$-YI6MzgS#N^!dO5zml&o6*wKtn+}oX759km*x7WHq?ABE-o=+ z!^7U^E3y$u$QmDMp^cuvrW;{1_IT8OQ83DpHIJuCUVqUYH@d1Xs_6n>?gow+R| zaKSsrQbup^&hd|t1-|7)=$kwvrGUEMiOH#3l)hMcd@>-V8f{nJweeP`f};_8lEJ5U z-}~jW{F~gHr%VDGSb!cxSvrd1ThGxc8;wZq;n^^8rHPBF2KGqv%^GUMBH75oOwgj` zh<^EWe|Ahfq4#@!if_YfQwwZg&&y|{d7mpYry7vMpx$7Jmx|=6r`*xhu-{V_!SOvU zqt4m}Ozq`r78on(vD=lv*rzJ$qvHticxl*renb31U(W;5ct9#7w!z|`5XOT@;KbnX zZj;3|ASCYL_BN8Aan6V6Jv4@6xOzx|x zJfr&zgkZOKwo2yhDxoac)w!)D9ddTk9d^ATo7CqquBz9}r^5k|MWF#d4Rp=4;OXuf%C6NUqY3r?2`O7!hm?tA z>Z#gNDw9DxYH;Ak4*~JVv=uv2CyDZ-qBT_oW9Pwy zhXHFIn_qSAaiWdB#-`e2g@D(5I}o1*tD?7wSP6lUYGL3+e`BbFfsL#u@6_;(#8bRw zs6IyBtzpS-vQRrKevIfM_jp8rbQ3O9cwK;n2;ITvXm*K?F;_9ogpL!^YRwlHp$+e{ z6{&OueZcxd-bAiYNjI;_)MjMBB5a8`RYSH6_U2P*WB_=PxZ#{iUEnl#DLRfE zK;-hPdCH|LF1# zV&IE*Sfuw;?{?O;z)Q~L)>eP7v#BJPZrg)+q{X>=!{)Nb)p6FwP6jH@rW4_Y<$?ks zmz780zP%a%x+l9a91??vyd)|wn7 zLD8F}25b2#hQ;t1vFDNl_h7Pa^{lrHcbou77z^*5yi-MjvvZ>w6PXQdH&rf41tr`7z zh^&y`nBxq!#0}NO|Gy7qS(HFfqivJ26fZCtj$9OTtdO5N_;9|;@26{FLVtp~+H3Jc z=d2#4l3`8p*m+F&4kcg39i?khiYrEs-L-azURK?)uKpbK!AN(zj>~vrGe)zru*dcd zEHU%0sns^Li2I})@tO;~Zw#Gc!@{0@g~5`-9y-2RbyS<0b>D%$ zBfh&& zMIW1EIqOYp9UTTw^-PR-rO^wL`g*j zx^gLvdI1nnJ}Q*AQ>W{8E^zOHe-(ZkqObTIdh?Bp`o)d`;WR;ZFC?%VY*d+c`TSPV zt6?s2LjcHr#*@m|lZ<6=0Y~n8ObEoMuC2V$c6mA?+Y&Er2T6Wy&#qV|Mcf1pT z@IV^Zr~gZG%hPF6jUD<2?C36{M~(|sZu5I?s;`RCC~Ges=G1_PFMM)di8nNR(wJUX zyp~NU*O@IF*g@3Hf2amr0|XYwJ#*$QLcTo{R_usIvU3XrMw&)fo~v3tfwPM(Z-%3=yOO} zqL|;B)pmaWHK*m9P8a0}rzeGLb!O7`rV+yyScjKtBd2AkC8O@r&f(fRZtbpIoacQH ziRId=TuuMOs)ZO&-+E$JY5Qa+3%@z%@F!DE3&)Jg=$MG1bCAkP^vTk<^Jf3q1m<6L zT^7Dhc17jZ4uzWNW6D8!YQ7MW2b*G_`siZHIpfR;2EzU{w`BUW zu5Xjf)aNEmywr(aE^LjmqrDQ_&xXi8A;KPh z_z)2G9X=`g75_~oLSbBrVOIAb?xgM=9of$iUa>mvMX_K0MI5j5xz?p!8xCn$`$QP< zvwFe3dmx}V&9+hN#oN59hmAv0c_bS$K0*t4}4Ghwe;31tk>HNp^) z;9y`;1?y-~E+_@pzR=aGg`NfDzG;T$wQ7TLQ=F@PFhBi+qP@pDE%;0ZzMi<^{^3My z`%crb#R1rYQIy4xL_<}z&Ud8)?;W_;3}4%HK2Z z!)0f52bXXMwv_JxC|OR9VBM$13V~5)*bRk>>@Gcqyl7qXy;F^s5cmowWxry}%XYpO zzoVJ>Pa5$qoXVxj;OYM*v7FqoTCyXIy|KJ{rtg{N<4>Qb0JkFUYKTTCKkiW~s8=;5 z4iJ5_6`aDCOwabrNp0rP|05p&hV8DgvOD|U83QVQi`_f$Q(_b|Pu*ErOPTB&NE_uN zShgqxnfnGJYKphI7v^d*krGzarap59R%e!FfgZR_2)Y4%SVp#Xxo{cELMK0!l5s?h z`X#8q#akNiYrJCT%;J1mb!}E!)T*ka>$3rgj%i)~mPL4N3wIPyrS)R#^0hm6KVexll_0nctUyzON4 zTJTXY7;~>@zo{oVd&}%>lUIlOGV^>&tSq^6V|aYLyE-%QU?4gILOLj_#h2(Y7Iq5t z+0XBIB>;~E@^MWa&l)0I^AD80(|1^q!YpObDIS-Bt41Tybnb6tY5K#$2=i{%d$8*l z9@sgi{UJi!#fa*7V#W4T1F_X>?3)_bUD8(}j$uJs%E@a2sJU;7EqL~G<-7N{jfaVE z5`}x;9--nZHYkWM8u6olgZ%U`AkH2fy78n^!Pts`9NpnvB-5WdTk6<%7jS;Vo2b(m#N|;6Ltj)O5#`LTyGnrMGp`KE-zCGQ* zZ&$Oilyse<|E9~mrLNqbk=^XlcM7g6s+#DJVRX1VdFQ@9*u$mENpz)JQTWR40oa+1 z);9avhdJGna2B)MX?L(^U~u)c`=zOn<;cEr_9T^szANZPGbcmV`{HpP#I6|VnLfT_ zxs+?1)GX_fH<@j>mn6pDknNr2_;(i(~{oD?2)*%AGXP&01#~NX>ZJF|85J9vOn}^nYHtN@9 z(>;9tp}7KM+OnVxoafAG!hbXV-(0;VCD65P#)7|6AQmt(j}^%c(b-T;)?NyWQT=50 z6IGI#o%O6lAc{3`GSlZ1Lh{ZWV#j1HY$sCvjGY82zrE?DQH+_gF@G}mpj--l482V5 zgYTbet{z*|yQbv1z8bcThnJoQQ;hha$*)-IKIPLKhP!V5=&9kPBw4GI##)*>XsuyD zfr43{=KD(G+d1z8Ga8EU=Nh7VL%1)D!|?K$8Y&D{%?R&M3Bp*!$n)+@NcLZxrdzLE z3?5-P{T|dmv#vi$)A3Wz@;z!;qK<0NA}O4IpWO|!42@FvVG3lKb&^6pi|-@d8JtV6 zMDn^p`{r}MjO&b86kgmmk>WwLl#Slv8c~rN{9To>tm9QogE9#7je;dPM0@#Yt@^}9 z70=)Fc-j3L?FWBgs^i0`#};=T@Ox0yO_{m*3NBn<$*sl<#`MWryg}_~A9pp&fIlQK zegr(YvQM$S`HCbDQg(d?OztmD<&ZLv#RJI*BhX-@P3SAq7imAFas(|`1%U{TEd;l=l>Bk@&Ss{-!DX)zxWL>x2|z-vMRgJ z9SkOL%H7=Ax|<`XAKF9ejB8M7SqXjYU_3Xp*ydUNBM)q+dn3@`E7$G1iR4P67yOff zy}MV5I^(dr5&B>!Ib`tBBS5$rK|JI&PeotbS1mmBilE5Tbn+D-U0mDA!}BkbFs#U( z7pKGpGIC|o-s=)IwXXJ)`(hAWi+F9D+WToNthLfHud~3H5@_nNcd)vizR#ijsID(f zb6)br+^`vz)@w9j{bmF+aSWk{Lo9&sV{nh%F?&o%R9&q1l?kO!zyUukhqQpg; zQU!ZW=M9KVct$&((-%-6iiN)A@S7qZ1d@#;5G9jTPQMSR7Wg?l78>M;SVVs->+pEP zGXLQY=G2v^DW6S;C<`?^E=71Ik(}px$#4r450)i!2}ZskxR5L2-E~Tty-m93=5`To zxCl~iHEWf{1nc=Wm)B4L1|~FcP*s{;Ccn5}P7g&&H_~&H6&G+{jK@$O#6(q$<8kp% zITraOa&*7txw9BYNXMl8N!`zXr|xYy%0Y(z3&eFiZE4sdhimz^1JRO)?GB*tkx^5X z4Q^6In93)4ydMmW3ji@!^i8&ti-V`6Nl6tb+iBf23YMOQyz)oz@hNLfw*WV}nt4yB zCnv=?ahpctOGwD#p3Beh`CInmlUeURAWl23z`k!_FVk;}i$`QP@gG@m-i4&7;hyWf zq5wSuEFXq6@32E@ux7Uno+N5IiSc}SHHzo>V6#z41SWOW-*1W=&bsvw9}xpO9bSJK zH{j!l?Dv3Us%HJ47Z7!q%$wI8Y~&>1zUr9rCkRe58TPJSSrNrw@G1P8S)9FYfpe07#E}r~JXWMHVTXjFw!hI89I1Y^vznVlz2@^lrk8W_wAv7CBC*zs@}-hC znoXYUUfo7Dq4pNctQ1>yCe;+3Al-ML&QRRrTx1B5N z>tE~HKXYv>(J$0#!hF?w|C`Hg`_1JN@AFC!OZ{7LYs-4D*f4m_^E@HTnLb}l-K5^+ zRUBC_?uHr_=~8Li4FVQ`>u0ijDd1-1QZ1i>)-(o)sA@o0EyVZWFeTf~m6iALw2L*K zfc1GNm^(JywBVP;1K#SzLEsIKTBxBA;K?B@wy5aH)GYJf(RbxFEEyy+iQV?ldmvoZ z^veTW0_Q?DH;Y@kfbd;DGiU6}a~WF==kM*@P2}-cn(mpA!n|6;G{?^22nP! zc24^q)u93HzTlhbQjT#jzZH0BdkD^Tc)`W3JHcyxi)l5j&|~(6C6|Dc%s~mek;s>~ z5f42_8Q&N!`#J~EY2HDr%H?;9i=b$ zf$QM1w}oEU9qc3q6mwh1rq_EfD{49HWgZ2;@y`##o;()&?!CDI!Kqrzf7Q$x7;RcW zkt>O-jQd}F{CYIi4+i9Zn1MVmyc3V!M}oVG5||A$Luh&&SIZR$i=9W2FB53FU>sK_k&5V?-vK0T^N3;<8{4VehlX3J$e0siin<`aF*CP z*ST>5#;JxcF)1Gxpx&@3?T+SR#KbzCGZ5+$`@NLbCT5{bhJ@FN30kejUmF`x5V7Ng z-YFBedFpeo=^UK<)dL}AR!Hq<^0$-rMzm-Okf{lbs0?V>2803)^pXavieQA z>i+iI0T=buS?vmwBlz96su>G_NRY~T|^~_ z8`=Fv+57-s4ov}rUm81iAsUs8d=htjme#ju?|tovXWZmrDv+aHPJXx&ZT}$Cf0NaQ zO_PXYlGo+79Gj}1-u2y)RgVBg8=Dy4&CkP{WI*FgJG-LQbrV=p+jSXK3I2|qR^w!I zgm=Rh$fN&~dtr2Xn!DJrG&zb@s(8{HpgdRqTyu!k1PRW%NkyD4<&acR(7R$=us!cT zbJbO;)jo&m zKU+cV;5HQvM7}=G0wD*Gp?%9^Hs|chwK{Y%8x0>TNMr4}N-5Assnn=>z4b}(v4?=2 z1;5#NEN)3QOzN9a;1cittBB`7y|8|&#NS+z;X ztx2OX;4w39{StdGTm&Ac!TzLtzy4hwE~7c2upE90h;YwVg=+NWgv9y|i_(BzRX8nP zYb30*ne|wRaX&(eLhqwMYZt4%N#5>-|g(m ze%%0Mw4&L2oR-akcd(S#_wS;?k)yA~_k7%qm{oAEP<=bUpyYFE(;E7Za>oNeLs!Tz3 zHpQ+(go})}mE@2FO(f7T?8_#-Za!i4akd9hHiZ^Ij>q+>4PUOL2Yr~(C*`Me{z7_n z+FGs@MMA(Y5XJE@+BBBGPvJYkyNIBKtkG=9oy)E}#68^A?Ur#nI3<|rA{+d{=0^LFLF69}aB;k1&a{8b;^wCIw)LU?=9B-((mFZt>}}*4zES6sj-V`zoUR!Aet=c*02;=-H&xpGoH3^H+{@(Uz55fK%x@@Yc~%Zuk?UizKFy%6Db*m07A zukcmpH!sC2SlSmF*t=Q?Mw|dg8Vx`$s$2`K5&v|K-4*C|tkhnsBFzi;STIMZ%w})7 zE;3_5qEonfwc2}}Vup34@+{GtZF4=;YQD9?-Jfbxsm{N-KjNKB_z0?>x- zXK=B}+)^jl@SU#4$&{)vcD=>lB4+frhyk9v=${;)1)pQ?Q{e64i+M;s;xIwp9Zs+m z7d3bd!Y`_Z4>q4~NkMQt{6v6LPMq_9e+#9}-@{U2UtKeN|1>BPW`UFNycEnCQjD4a zu4>8`a=!O)$~L}NgWWzir7ab>e8 z1p;*_Ov>DbvtWhGhp~(&a|T=h$^C@?o`SOv{>K@>_EG(gdtZk{EdL$-wv~zQrEZx5 zh_bLsE@{qcW{Qc^`PM6!gL#mXSpQIM(&vpyDdHY|lZQ#svCh9F(J^uW8s%-arIk}c zBN=OkhNey^At2i-uG*9E3Gz8^JE_(9LcbEC)Mm$RfHJuejU<-!%64&vA_EYJnW)`( zjO}H%5?pgj)cjs2-ONOPssF*SX;S2knx=MBCN~bRqpf_0=q;WKBg{@C^H~les@D~_ zvO|5!^)ROF@Z-jUBa{arkoA`VoeAh>p+-egg%W;=M!lljLl+rPS;eIzh&g^8w;mmK68BI6(8*2}wqPRbRe z`s{HNU%c}z2O5s@>vd~>J*D?+jo?o>6>SHhbBUI(7~g-jyf~%_!s8bi+iK#PsM$&? zeD7%}_pPfQF@|*^$nM>dmZo$+pEh`CkHuf9M%5Ks{K4;dGQlvrUk3Qs@b35~W|EIz zcn@JABbzFkUb^y}DZq7pufek8Pp+4m#2k0?dq@?xg!l?LN7-EpS;wGmhtUY+$Y1+% zYXYAQQ9GNy>G-lgSD3ryXeDF_tFLsQd%yTY-1Yjo_3$pl|1#2&@*oT*xE8%xeMhu4 z4<}&TW!UemIZ^Hvq<5`H!cF_4eH5Ov(XMWHw>2wqYX!eI$v5aUFdP(7*=Yxia`*O$BW70 zSLe{d?Y6V74jpc1=zD@9kPRAan(ohCP9fMd0ajdF@UD`S$EqIfxdz50a%3L$rVJpaD3IdAorX)_1&8SNOwnZDu~JNcYA- zCTZw#vfq#~q3!C?=jz(fPkwJKtFsrU!e=x2r=T>cr`8mBGE3=$j(tV zZaYnj|gI{E}QxLc0y8CH?ErgfT&82$WAU5K{mbp+i3FjVNIhOFc|^sc$_L)=z#5{+5e>^boyCUWLjurNC%!@;mwN<3pK)a zC7Lc*$3PtT`5=F}TJhM6=@^9WZuz%mS3J1DUuy7{Ewg&5smX2F-~Z_t7afuI4f=;F zMoO6WX3$ap9I{}0;el`>1K*odrKGHVaJ}4`TlXOS$Zi0;?C>q96+yi8yc>1u3taD3 zBEfJI==t%dP5+BZ$*U5sX0Z${R1Bv>!$SVl#HO;`L{k+ai^Kr?f}ajt%->qBkc=iK zuKwnqcED;oJf;(ya78883ERsHX>Z0I|A)ucsT>0fZy;@&)n5@`+`tK8h^0a#PY|@C z$d}#1hz2RjwEXtxOW!brTw+9k^?E}OAWq>4VHyIf3xf`jg-7_aoERl4ojrOxM*;$ldF4oWMq+a-Z6=+I%COb)Pr(8{P znw$zed7Zn>-YG!P*w3p!=|1nMHV!~cSXazE6uTSwJpjEK5~4saTd^V0OzRfNrmVN_ z#sK$9y~76^YaQS3-@iA{O>Gain+MEnkrtmPj>;nU zPJ6+$h-5F;%oQFM21IQQa_o0^tX}8+Q&Cp-p{nDoYz5``sNC$&3H@KC%I=8N$XL3F zzNp8gM^IPH>-NTmw2LJ4;^)Q!yZ)g4TF_#WhiHo(AfEj`JfGakA#NA?wYH2ncV z9@Pm-$4P1q_o{@N$ZErLbj0BJx+81aBH zUzTB)3WSm{4P{>1faWsn#vohb?2U=|`$e6TD0krCx2{luZLz9ETUL80z-uCDl}Nfa z)`Q*M%&DvrewnLGayUt=_Mu*!_*e~QY=6eTjJ4~na5Wv@65IK8o;C|XF>=B>(z`Y+ zEBn{g!K8*COMDQ&F{X$}74+{UsgRBpv3WDuX5L1C6EGDT__m@r$8X7?!4k(`NaaCz z*0rFmtqm9JF7WBe3lUyLD!qfB$A$Ud5k(z09Cs-_l5W}|Nc&CKdhH$$KINUj=OV?d zB$7`iCi-m9L!UgBRnup)?q?M-vGun*_lEk1ozSa`{HBwVB}FpGbSjWORsXKjc=^fL zwPXpc^#Gkiq4$GvUEp%I97ATa*vQD0xbbHhRETE75XFRXlb*K4>T_NO#=SU?3#+mdh|8+@xw6B)40w)&&NB1Mg*K%fNEo$5K z)n!$0z!>MhKbp)BR|~MYkBB@r#R)|YpK!uI><3?%9yzeU1@mkEm|QUZr%O4<`5`b9 zwJAj8AdQSEB%;O1N?O)>U|Rd$EixZ!vF9tM#q{vAg!Cc@5ZprYDHr4~tv?3lm^ z#sgD!R4zG?3X*Kly`~W1?9=oXDZqNJl0H{QdnLSTu$Uf=lK0lN2Nr5W=8uai(hc^Oh zU{?(UPrzyUgP6%?y~>#W@n!@2)o;dSllKllMFQ78`#*MelZN+g1r@+`n!3e5+jbJgR zQ#s-y6qnSpklv7rZF%f&s!y_r$@lr%gP7;}zy6EA>cQ@yuKJ8=TqSeXjphS9b5Hb3 zP%7}H%>m>qx9t-m; zWzNV)YPd2*2M3Uewt=)*5tn!z$9*?7ygr-5H;Tu%>PT3#5+mxI^i_d+0`lz%hArfA zj@`BDxJgFcoib@j_@`|mALu_Hg|X(aUx%~KpH?NYNQ+b*AQ?>!Ax@s?}(QV%R*q=Fbx{F_&% zEOFk|j%R{=m>gA#q6hAH1lS?-;k0*dE@h~zV$?%TD?d_ zj-G4bFF6(x3oH~^{XJL$HyoR!mOTvpocC7#+v%%e$5y@)Z6>%f z7=EVCE{_VE0v-$zuW1f%Ut+URt0ymUm1p0pyRWzZ)qHxt4V+QZai~=8ffCt?(t_tt)D+q4&d)C=+ z6S-dlOVfth)`SZE4>uF~9AfJgZjILdLk@rYEARdZ3Q=Z!(OBLW;Ea#(F7>ruq_y0v zwp&c3O%%k~fq4KNtRWN`N-UVQzCFqPc2uK4Rjqd-Uuv02KBYIk952=&DArtfV&|h!7Q#j|lrM3A=C-#EYLr?uNAxFRHcP zT~&(Z-c)-W47>IF{VS+Oe%>I9$?- zOF*~Rio@mDue6!ipo%m+w$;xJ`C!a#UGq}XGX#s@Wmfk;TabdXE41?1>HH}Az&q93 zfrfKE#Cx80rHx1S+!_4%oFQFV_Lcq1ZVFF!<78vNBzvnoR6|PBTwQfOG*r%-8;y^^^|}JlRtvm#HB2InuN_an zGO^rVMp-I6b_-lhyW8eMuYJ%bnQ27CQ$mUp?LlPPMK%1z`jSqrLh;+PWa57`RYEwaQ<1037Pkp=4Y! zStR6vV&p-wkm2Rc^1@`JIPI)>EqEu}X!3hpOGAR$O5A<@?ixozM3}J%)0_4|dng>O z{l}az3AvKv4|o!t+=Q~8ZJEhSckU;$Hrf+1;gSoi;Bt75O2<^Te6-z$5W$n+*EW*n zTgNY&C2$jdviYA7l_V})RFZ{jc+G4@8M^`9>HtfbXS}Lp;)~+P*Sy5U;f3B9ZjV~C z(D%6v|H1ANfO+^9AkvG*_2?KY-c`e&QZD!2Rt0gxZlBCS(1!!f4p=Pj$&F;+@(5_UC{8xOK`4Ycynt->YT8x$oI4wu{DM1acn9vMN_` zH;vow`!nx$=_Btfgv*PU<~hBz`{|(VvyRzQrBw@c)$wIF?aq$>Y<6-O;qYlgJI7tQ z;>s#TuaVK$@82w*;h-4jcBeI>0`5?;r}GU9fEFEw68q*Q-95P35REH`6JY)s4>?=_ z!~P6$6H7by3s6jCm8Ey|LN+ZyGqD&^n*S%+=6%u8H{I z<<+U@r1Rmn+g|JdmsTtu+qlo=NX-*Z$XDf!!W4Mw!G!E$MD&h*bc6yLZdx6Ms#ZhF zkK-Zt5bi0XRrWAt_Z0H&h{8Q5g5ef?=0Y*ttwIdo^i?*hW2cu)f}C^`l+s zEf9~>^*_ELGT7^V7B=;}O~zG@3_4!*~=sWcy2ve`~1*@5UkffeWg zl*lh1*qM*^*x=L?A&;@Nzk+YLH&E0{kxQ`>$YYB=wx*>} zL^pHU#GraODnX_69pjZyZpd_+NfNPbKA&M>MMt@{K`FX_VAJr3x7dwcge3L6!6U>)6y1u$f)`Oa0WM##Kp=;fbJUU;Y zZSp&fJA4gi$=3#{Bdr%PFc>co`wvbQ$1+R&50VwWpS||m&x*T21E})D&l`O0$hmP7 zDaaB2_k6(ykeDaCNf6PC(}t47-Jqm{vo2b?iH=4^iOK)D4Rk~R_KU5v%PC-1hV9P4 z{gD;kq`@D|h$~EFs|?(bh9A9ZHc&EL?(obXO#%1)zqDj0W1q{jt?JoFR)3fDmn~A= z&vkeV@2Np+P!~4*-uSPrA2SKb;q2*Z5~CpNVPj*ghF3F$8;Go8+ya9Y#Q-Xx?7{_v zpADvcC|0~49@RpPi~eE;K(k~L`yytL@QOl+tcGof4Yr-f$cJf-OR-B)7wISZQA>$0 zu*2iOlkRdqIM_K*62?QIQf@4gnS*4 zybX4856IKSXwL%7OSC{E`m+W^i)gouRW8ohpHW42*D0PT4&wM~XsSCd4uhJd8hwRuGW;9ga*9sjEq$${{5N%1p5mg#vvd z`v!i1@fJS%23st{6CerKiZsGP$>BZpHH*CsbezQXg2eJB=lMY>{i#-Fkt(-j)f;Iq z5?c#dY#dmgE+=^}y#v+*5k48*KButr{vSWFFT6~j3v*|!i1+yxHtM!314ZlpJ@(Px=Dith|*eb7dD3 z5=Kfzb8gimmo4}WipiH=DPJ}hmFV9p)GY0l7<^FW5YW(WH=af>{gEp@O%Z-Fs-xy* z=^hZl>GgAJ!82w3*(S3;HHeL({T2Umr%o|*p!^!?-RLzvyu_J!2A0v7r<4s6++k4W zR98xNXydvlo~B>I+#IN@QNC<0RAPo05hHVk2I~A3p?jhc$nHZ+#rU~ShILBQH!!N2 zpUF&&DRaV~f+v0Pacc>w85N-O(=Qf&!^y_N?RpUl%u;7ycNuo}S?bEbY*qk|P>Cly zs2JDO-;tQ&#zSsWlkh`m+Wz9B34pCb#QM?FU5^0-QO3^ zc$2qhaexmfxn!1zDZ}o0z8r%IM5u|-qf{i~7`6@J+<5QP3Hcbe>A&f?>>+A%XYm&~ zQ>vhp23Ou_jL;`gV&GHHZ1xWk6yl{*y~1T=>cW9wcD3et(Vm8&3bFs62+;)&>Uu+1 z^=N(kdx##sPU*m#08yrw|6G4F0J_#*(#v;Te_qR5-Th$W{%Z)|=#r#lNz6oKsA=iY z51NGJxZVk0k|70t@qh@~i0?>m9!@m3uj*esgcJC)2tV~JP5I-4G+TA?u7np}!>r+v zs@RfubU+n4WWR8UlN6i_;V3W|1PG$V9dVoz$VKgmC{*EPqfEKF*q(4nzvZ1H_J9RFDSWR?4q49zr zDe+ifA6-Nxvd!D1a$A@faH?lJF9xzZW0SQ!|v1omz0dOeRXU(RqWpIwdCFSkUvR3sN zKfoSbtPfaq=%*-1N3|k(;*f-aU>S7kS6?^|_*`GWi#zfjE-^qZ7cJ?&WN`Q*Esog& zlLgBZJH-E7jCe=bYwK~!0Ua+{^y6OifC*!G0d@tJEFpp|^7BNx9&9kc=V=kfAnC?f z1Jtrxay)syjx!)Y^Ljp*jbVcL7PjPg=2Mbdgmuz!P`H}A>wI{V=-mmPaq1)Az#3sg z4RShzn!ij0L#~%5jpJb7faPz&2L%tP&42HQR>hG~Mi35ym7qaRH*@raX|7P{sWoAG zCn`;s{zLREGn@w3UmAvxEYLaq@M3q{fj|{Y7>uTBQpoD_PrUeFXp9i(F7xrnWfG&$`ld;wq0~1MZ2qKL=5C z5~Yc60HmS%Tcii1X7(^F6<*{7h-F-XA$+12F3()KSV}?@qBzDQk*UmJ&>0;@dHdm< zD6+2POhU8zaAor9XW>fc1u2+FlO`_Y3-mV^WW_jqx*;u#zd}SatExIlwrd~Ii^DsJg>GdW5nPmD4hN?olEi4_O#6lFOIjau$9!dy;bd|0<)C6ge?*uZ81`{(2cWQYrnSWoY+f)XXDO z`VI49?ayQ(%U`>Mv-{t<8hd3rn%6ujUsHQ6Z_Bo6fq}nJS(L+P-v0wZ?w}k1E5dMe|JJp~ z?$wDQ>)~lmGd#O_Cqd@-pR)sjQnf4F(b@?Z9AUEg^WlKFySM-(7KeDc!8z6J@a(gR z4&r`lWNA5hpDPs?1?JIquKYD5EH5lmPh|K4U$FwLzL|@va7|!@f5HP(1C4qET=eEKo6GsS(#u zO>8DFl?71W>E=l;;G3-gyiSf?%DPM5^RQhIKjv|m-8&QAorjwuL5x`ojyGek9ix53 zS7qp`q@V;q8}mekH^SMYYaTdbt2E7`g&2{<6sgNMA?863SpZC#MM&#|`yl+PWu<&} z`%uACP?YppY!T+cUGitn>ZLWd5F4#-i^NKVI@!nizILAbC^cRPHB`+cXA>LCc z0y`Iep?n!TqDHLE&`=bkko$PE-*5v(wpyl&db+f70_L*%e(Zl!XzA0`yyN;dwqg;7mJ=k^<88HB?B=2Q3 zP4aojd4=?xZyQ4Pb0(fMk0H3pf6OmnKj(y4Jgd4C@yEAtmp_AE%@0Q#SF5Wh(8rkX|qe_S7i%b7tS*$t5Dn0MMpeH1YOh{L&u7f^vlR-+qY4dX=6M?HDb;d z_l3||AzZn~r#`FR=SN*Hl5VPUw#y{QGV}h~$I*&ey6@Mo7A<@a@_p9=LnY-Hb#RnJ8up~{dPFj356UwsSB_#|Y7m9%-{;Xf$mDu&I#Jx1 zV#71q97q#sU@@u~dY;b!0=SLy(UFB&C;GdFc1pp*MDe0sJ`c-d|ET*alr?pM%)#{G6el}2sO;e$ns5#KaleHh_m2b9x*ihg+{L{iXf^A0ON*z)cFdSuD)<;Nm4j6^h?} z`<$O6S}G{j0}(L84VIamozUA%(t#jPkw78|-!#B^3YQvp9B=nASWs2_FFP9okU|hnmrTPb%k^c?yix z*6?WZcqPa_tu<%h5m{Idq3XbJ<~gqs`Ln5&zTv`gz0dC{dDdJ{s&$4dThwMo`;Dov z-b-FV&|CGQr-?2F(R24cNDQ$BT?P0lf#@~9eEm;W%H0~R@Q&Rjl3gi^SwTn`fTA&O zG{3`^@t^P>1 z1+xBkm5JbI$NMQl*^c0o{lgaL03yGv2ls%+Lp8x`(gARr7PS+f4EXk-*Y4me*U@vG z+2{!xdwb2#_VyRo9N+`!VS1KkLE^5!o{tBx0p#d^EP)BFch1zpzp6Inx*a#-SP;&3 zi4n{dagAGFww+(W^lc&7P2sLKtQcg^Sey5>5AU?(+55IDH~|XE^GtcXXxl_GXP)qV z4GIjs_0`MD8%1qg3wmEh9&-r3efv%J9m)KtsCxEtV8K}bpMtE90pwA!)dN^_jFIba z!QGBRg-c=gK**be#UE0XhJ-wqv54&g-`6r5ftuLD9WkKt$Ho(rW*)piJO-MYpZ{c* z;7BolNI+D-s=9ikKjvig2qgz5eD-Rb%5da}@O= zK>femtZ=p~b-b3BV-4J+8a*zNvYVIp^Cic*8$2$nf}_QjbVUMPryjYI(@XQM=&QX0IOWul~SWip)5HpHgjgeu2!bsHJD!JrQf&Ic2G%0YwdG$=L#d&tS)nN1O zb&FFIldXTv?k)F1Wm8m#D^t(Q_ice&quvp{YUo|6<{q1aJ9;&OcbFk=M;`*uP5j|sb=@H>YuwL7bHbaYwGFwsifKK-adY9cPy1tNDaHStzJS)EC}(gJ?b zk6NFKkNafRH;PUWxK|EoxhJBs^f2z6Tlt3p?LTH5)$avv>#-7f8dhEdaf^+;eyQrP zq)eC;`V_7)#}4|-HUGS5zq zkmFTbb==Z-YTQV5q9Zx__r1ZrznQd(zQg~~

$>dfFI`c_re=%UpQT z(C!E?)N0}@c3_xY#z4?-_21HAkL zGwIgQB996)68L!O9kRa}}5 zMbE1+b8%Lyaty!E*G=P=+dGh)u6GJAvmjSz);HjT20zZ5oVJ?q!0zT1pV3!bGDinl ztqOVvfpgb1;nK#MrIN>(af6n_lxMXpn!Snm86}~wvriC@8*R_CM@_XXz7DWj8mGxs z#O?Nj0wUrU4-7e;DD{Z=65GWU`i!Q=?%Xpk3BLEUBh%Lt#I;y1&|SfRV|n^ph9^w6 zwUyn@AGqcF&E>Ow>HfOV2IGXk{WEI8#R&Fn6Gs)s`S*^CHKtDQEuMBP=b(%Z3NAwx zM~cYU@(|%e1|T&sy<6DlPW8VD^ZeKYkTJ zRz2#s@K!-TF>TM$Qo()Frcc(&lIuSU=X=cQ2%JW8a+$=J7QK#|QJtgEGo07llm9Y} zf(y(O&MO{g{Uu+{YO&0+;nqPldLH@_ZAgFFJ38b;3b&P4A$~x7*WE*=7$aq3aZ1-R zg#n_*0IItB2kwE`u-wRDF_$Y8(4y%8vqQx<);=Tf0L-RO@M2o7i34>80$ZLtVdknfznMheaNH+{Ccy7yB| z%PwrfgX<}0O5}llK~RhHy_s0oGY^U*X8N^Lc4}mz?=N+_Gp(t&^4{WW`L-^)dKwPj zy7Bg1wr#2>AbsIdR-`V{P{HjPftX`rs!S2fHC1=A2VUx0x1;n zyMiV9wv&@}bLX&rzXHG?kC?et&|XipRmCdcP>`n>V|{qnPGlY#q>sXQ&p^L`QuQRj(+)=2GOkPNR8 z_2c)S%ObU=d@U+&<1ezM+to4K)I_YrgzjBd`wVn}lUOfcBw7zazRTx|&djr>`PV->Tn4jg9iqNGx?)&J|@tntF>*$@v7NT+Z7;G;JpDE-I3w!H?0l*7h(k znN1lzxy-8c^TRf8DQJHE5~@DBKW8vV0{h()qlIS2Ln3KpivD zRTGUa97J)M2T)Z}FnFwpqab+^JL2ad)BPeCgl@`TLLKXgoReAND> zU~p{rP2y{&h~dKxx1HnP(wzr!0}%_#RLZahwzeq{Ih zh;uF8?(OgBwO$V=#AJuG*9l+>kfX6M)in2B^+@C# zBZxh1Z_^W1%a}H5e!px%;J`i^+$7U(ntVX zs7ldm3f6guwnreggb><^t+)*F=rvQw`o+cd2O^ou{b@v(LpP8v2_r!E_juH#CJ(?e z=n!^0<2Dst7xph*B&7`Qh%k6P+dqLLI)jPWq4O9!B^zws2D|IFBB_h&VlecuLHyKM z+@XABKslT6SLj?C5R)j!1$x=5wp&fcdRbZ7`z?n(w2qFc=gQoBA#y__s!k46BtM5p ztW$#*p|1M?t?tf!A*y6KACgnipiSG}+nAswd-9sYampG3sK4=y(DI)9S2sx=-bYan z-CJKqG;J=F?ALA_*N0+i}L>hSa7fS57LUmbIN$l zDxHirAKcbkN~jBYd2W@VeBL&}U-XXRHhor$VIOphe$U4@|Dgbne8s(o#Mg21*UE!& zlBnsKYbiWYyWjTP#n#GC9Ws3rLbgSjZUZO?mDh`_oGEK-5ij7qXXk-$j?HgOuSrWo zK8^w2$&>KeCGY)ab)Ipa-+uYzApFUk2VYU*YMY4lKJdQ7sjb()-6E8W=c22h!e{v_ zZL@ui@%HKD_uX{JLSDW9~!yZJPc3+k92RiOWm>oP`ZJbYK zUMRkSWjgNwXj$*=mWpKj&nA#y^i}msu}bZld1&Y6b|uZc!gJ2a{9oGozBmyQwMT7K zmpXl?PxU$Q@pPIKB&5!cGt~DFA4?PYG%m7ly6U>3n=niPI>}1tDlq?@Zhm-pnA*=k zrap@W+#WPG5_CO7w@Uw0v${^h;=kd$FRQ(H_U-QXoQIwpzup#Vut$%+9?8XXVF+4Xv+2u+2O_3aOBy>jb;(KlTJgP&XrY70>BtMX(=?_EuJ9dy}Ay=oF-xGk#?EkiQN zwk`j+YyPi*C{aUQ1NtAEpc<=&*1D^5kC7H+1>@3XvS9_0csPm!@I+Q5JXcZFMKu9* z0!8*kaiEyOhhG*p%x~M+@na#BTAynL=K(|vT6J{|Jc%C;Jk%`KF=YrxODpbmeML~v zJPR4tGa@AP84;f01_DYtS8^j0V|v>Ge*#APpPvX#8{x;nKXQwxM3DA~0*wxzups^{ zJGEI05?BIjGfGV=lsx&!)?V`br1Xbi`b-ZhW{F9BMAX6V+4=5S{EFf)4o-7X;J$~O zU6aft68A_mHx6&@7SzSp&G+_XtEdD$a+&HBu>qB_CK)tf&v-I2+!$HYsm2(vd$9;z zu>_@$;K1g!BW^W$gv{1YrG!5S#S{Ai_!F39`&%?`lnzDZnJ7PR(Hkf!8R}$vm;qQQ zOJ>dqa?9X{ws}S`v?+xgaR)bAbIVO-kqZQ#-(9Ls7#0xJ#lku1ZgJp>C8%&U{}hK` z{zQGlaZHD8$|n%ec#!)B3%|bTkuJS150sT+l3ugb6)B^irer(#c)kDi4rXrEjdirwtSXn?%3YfbnRrMjF>Nk{rXD z{JMQc7JvAgvIat_96KlF^PM+-sHFNrhUFLdvKOGJ*63Q4ES-P$jqAg5D>p6-`=_6U z@QTB~kd;MAow)v7D~5QvuiUzO>^GIlr@1e@!@e4HaM!lTaii9Ntw`|i&G6EdZ+qFT zhNQR{c&k*AqwE32odEJRgU2^?7;V0X$rx9Ci8td-&V-XJIftPH^Chh7C0P?2*Vj~Jt^*0%&bw!|B`aU| z*RgBJ@!$$Vr6=&V_;{wiK^zHPElIWN8@0jvtr=!0JKixN(G%nJ2FL5&=C`-5`lV9N*~tGSJ^wda|1-Q)P9fBZN%4>sOp8vRSc`UH zilGE)NFQf{Rn;ffhE9rzlcaT?bLup{l3_o8BeTY1k(L|!DysBJFww89pxuY;n4lNIWp$pMWa5zl;i+LbSJ;&%6pp9ef z>>bAohmElL>NcFMWiaRJ*X03U_j0Auxyon8Qnj)+=JOQ@M6#V7G&VA#B1>1Q7FF`p z*=*1r;bBM~5AnDpA2Vs_xl+N&Qru@o+zYBj0T_{I@OPc`f5gsVP{Qn+vLa|Ovyx&& zYyC6c%+!l>(dP=I*e|ySaHQ_e=OiEpY&;wirureAtZ*{iWC5<$Q)1H4XH$^ZmIb3D z#RvDNRR+E^oLA?8n^&qE+Ef@(lv*8)EyhN582(#VAd0Cf1>kHAT;eTV=j+3 zoGI!RP-1D#M9d@+Qj3)5LSSM!m!#>#9AJ?4^ot`mfn$%f+C zGl3iSMpWrNe|VR?=?H-^25cwl(=}W@k=EkkXURBAR7TQH`t;)$AKp4DY{b`ISNLQU zj%mzS@H|$=?XgDG9nk8n^}FgbkvFcgE_}DSAdTtFPb@qu*EDzeukZF6egr}eZP$Fj z{x4a>dl!Y@CqZQs?ax{6y<^m=ioYd@835q9*mesIYWpR0jPGM5>rLl1k9)vZO2%US zm-^m({?ZFAWsRKNy1~;X{cw!%RAZC%m|xlERWJGLe#8vOWh8h7{wHk{L+a~aO-&Wv z6KR2|0Dm?w5Hg=i^j$-2?4I%|{01wkv_W&*Z}XvWcJ1xAfq?)% z*gr8J5_1%F^38EE{SqrLhg?M|U;^|a8yh8~CP$cI9>ezy0v09@QhO2bxw(Y#Ba5fu z%UKpL^=Q|oab*GU^nXTJ(khZ>N@a?)*xDg!)5o!20F&;eh|%A;kp~a~cWrohcn~-p zA9u+-utEb7&orga{z@7{z`I=?Wi$O$>Ihqb5SIVP)mQjM{chdP4BaI?2uLd(Lw7fd zii9w9m$WnpNSAa=E7B=7ba(gApmYv3Tz>Dp=e+0K&-xR-&v!rT*=y~!>CRt>;XUrd z%#07VPPSxGWJ#_IHsX^e*|spD^P^~IX0~4y&jebyB}%(K=K4kbLUlEmx)Rof=lGIT zV?#h%%5g}%RPDvsSJ*d2e9lu-fu$&!V^c+%zEDdCqzDtTgzidSD;wWgoiYGJPF3_i z1R@0F?3aa10Ur8Tyj}oY*${xQjKc_}9y>i!K7E~Ml@B0wKg^kM0|?C)e|XP=jiEmn zUHY+{4DiUUj7p*;-3;w#l!11qoe;;-0%&5qDNe81_lzWUe24L$gKa@<#V{+jvz(X0vp^x0S4tU5hC zT?<#(^bhsg#8WYq1n}Ja+3o78+4=j5ii62X1itfzO=gY6RV-R3h`jl@kR%u76nBXc+yU2Y8)n3HNH13^8iKePq2(|OPPjVT|rJI zwKVzkk=(<74;E@Fj0Jq|P`4jXM*PX-19IuUrG^fG@w~5T_@6494dm_PUH6cPU4| z_%q1|rmhLDpVh087)tSoJVu#ShfP#~{to4htfmiCe)z`5=uGLrqLEFshPikd>h`en z`)@-kX{)%9F^_%Bb6OZ%2003!K7SUegmwNQKXQoco+g2ahq}&dN~8s%*JFf{rFFh= zDn1-Z?IgC67dWP~hQq&h!LM;Wo)ah{^Ijynp+m6S_j=V}6Yx1t0;86IR)YZ(lfb!P=Ao zYg&O}vD!8elce2~LFoIVh8*a3H4<*pO3DiWwzIruiptI7Nhu!gfoPxd+Vq&VUHWBjgCVIMMgC` zPzecVml=Oyzf;35A|vbqIu!)1*>j7dNKq8M8bFL2#g4ue{7FsHt4Bde>BUU-D-*=J z^pr`#C>e%E3F`*L`vD{D!!bh>E$PU%B2dBuXVIfS&dMiFh0L4PpRiFd-+F1G%BhV% z(;zf>17PjX;Mrym3IjX+2x?}Tx2poQ`x*k=1^|LKgQ{=-aNzxI%yM!qv5V<=Z7v#f zP%l&C_|b7O^ZBb(u(bb`ZH9`sg}KUso{F8Cp-<__1W?1XLOw{<}YBjBE#R z(wv4&>4W z4%$;&bL^W`jfdp(NT!Wxm}^~6S^2*XaBr*ccs%DWcG4EhzQ>wBcidk3Dy4y1fzwjM zZHJjO_WEl71#REXimKJQaBbFkYggJWoXM$B1r7k*Z;pG`((*cx`FJliyi|*oAHkpB zGs2Su6f3?EO8cTRJu%=Y2oc=nrT!N3n5Z1UyrsD`#NPoACb~nq4*m$>tc$hoEiP`h z>D?XHBHb$@f!;*fzi4rvUz+3gELwa&WD&V<3oWl2o`o17QTZoweEu*!J4G{t!`<_} z?(`i~E}B-Eu?C;l?8N_B8aInU7ZJ+lm_Me{$MNUl4!2U@|FS=YS9??X`myWSn@?(? z8qhgiu31>-7^Q3(Q@mR4E0UC;9?X60^cfQEKUpbhxPFp+=fKz6`f>e*tkVtc`a+8j*|L=#B;Z7I7a@s@t<{OO9%X5EQol|%Usd0loJPTT3o zu`2CF*y$$iV;+^T%Vsd|PHEDy@1xiGa(3%Z-9y+q=PO%@6Rsmip?Y)itQ}KYUmbOt zEQ<5bQ%{2QnBS436E=gb)u+f~bGIX~AMKm-9E~c;TjQ27*`423RDUsI+o9Qgp>q;q zwuZ+(eJd72J9U$5g}306v}MxN_3CdKbNu2dFcWgJGP9K>yO-XvU6a<7&yMaK&Q)yB zb9@X%4C11lekG<3k86Ve{>id6DMD#q@Hrv=Pc(ibK7l=YsWi8?J`nNyqDqo&<~L1T zrg<)L<_1ZkjFe*l`1{Iko)2X<7IlfC{VaqK2q=J8y{ZjH{ab$i+@#IG+vf5!F})(E zrLqoucW0Id27V$KCQ9WG&}BBRp^bb;SL00A37RxP%NS)GS;YIuJe9z!Jn!ll%+i}} z&c^qd*=T@tD85wYJ1^?pu_+0_$=IApkFA3sAl%iXulRPg-Yfb>+of_L^#ew6uXiQZ z8BbY|KR6gcm%E0K9N$?ENECrikG=z7mM5bL7q$9c;pkv&6KCP8<+kB`>QobAz%v6i zUkkk_famn{7ME4m;5bg}zw~B#9y3MseL<119e3t4@D8mQP|}+WRbKg$khpG@%_5ysvqJPlo1#w28&Jk88}|^|pLw$9eAFa*(Ax#Uy_I zc`)#qyK9N%W51S!4-I@9x|h-P0Y(%F?(4B9VUWaMG}g}X#}}r z@aJnYB{FgBVp91==asH#L4oK2BVZw-uF@bzh&wR_4aWCiW5qnFXe8^73M?n$2=&2h zI&&=Xlci|%0@>_Op14Q?T%g+WE>S>_$MwdF0CJoW8 zFB@vXp)(T9+?)-o44zjGh;Rux9e4>-ANgxx+-8~HpF08`&ua#%5UXg1%q zQ%_GeYBtSZe@ClvEiK@_*YC^etgw% z#lU#w#^%1}a2vCh^zqRT`M1VhedOVm1lM-1jQ?>XY!w#@uE!!mL@j;&!8v(C1-7tl zq>M@ZE2vW&!{ht3fWFhVx;{^rwrxz0T8LmLwAU_>nYE(b;U{9BZlpuD4+ZW&Gq~-N zeZMa9xZ3QcN?t~2;%lod| z{=#CGqfe8DwgvS+!5NP#cH$oxgf65My(zeSS@&>v&GJNo*02w=jMSMEmw@iBQy_v| zT|fw_Gkh?FuC6?f?op_+OS87V$Vei^xa|1rGh$`FFB0CENEA9Uyu0#bv+Y@1ZPysg zgDMU^)?XXxwICG!YIIUhVgz^Ha@7$(H(oc@H@T7bu;gC@m{$1~R*gYDwpA@<`PI&i zR^`ChV3+8jkw>24bMM>-v{c2W=jQEzupmbuG*hAJe)1K_$1w!D3(7&?R`kOp`z+Ia6m+bm76ucBa?0b&t1$3f~?N_gI-Y(ZCWBPk;< z&!KH19|SKUV}#c4IxnM$EQTQo9_ejoRs^ zLGQ4P$4{)T z`6svfc89A9s+?iMu2LvGz|v2C0>N_G0bs8;)Zu5Fwu#Js-GZP2VIKa38~T9-R)Se8 zIvPvsp=BSe+aWI6401gHVBMXa1Qr)^Am`79#S__2ez?7@CK30-T!-_4IA*lP?bD|- zz9-AMn07ln?`dADdx)$3zVPzzoImR4zT?TJ$QzdD1s$RpUFKelWGhcwjNCa8bYikx zf$}c`CzKHkSoW@GD<2*WXY2`Vg#HUTJB+Oyi$UU9HS(-=8kE*Kpy>&)>}b z`8E19T73~5g!c*0*LR3tmn7%-L#J8^(IZ}JH$AL$ohsm)qxaCEy7c=(@f^gqP9uMf zG2iX)RAYhwcwgIfnXB_-hGUn9P|Le!DZqSdq>o(wxb20G=41;0;M@d#omRjlt-0hP-? z)^z@2swjUui{%OTHPWAXhIq&!9{^`ca@V=k6i5nibXO(E$_l z>?LXXB#gpZ$c@h=f}jZ)TeD)M{3U1H!9uLaGVmLaNCeELwI8s= zSvn7SQ}lM=5jykZon|JOQrBE%f>z?Q&4KBF-2Ki(ICz-J*cAa(h!Tv$mNMkbb_0&Q z#qH-3ICul7FOAO*YyWaOkO^*Jft#V!>sKx$$gl9%-fDI*j#aH^Qf6?P($k_iWfR&z z=AC{Q4pa|#Vf7l98o_fuIFKnUp~v4mXEr>T{S6G%08y|YMz1Pp#?p!A*DSx9v~rDp z;eq0Yy*zEyJ$x@}6Zi{_<pe4!65;TZURFe%l(a>5V;Lr7D~U6XyziS1v$WV;}Oc zpv4*9n+oxsWY_Wh8PKZL=v zOAZJjB!Q`EaD|8K#gXaH5PVUOqf82FYJYqvOgv7yIVO0gdXS=K_-pVM#jA-7m!{>b zw=e5F^7__qys!)$uw12Z5^{oTjo7)oaFtA%gIb00pE=H$ANsUY)eyrUF*TC2p4ZWi zZUWw2<*=r4Jdp9{VbP&Yf&7kY0(}@OLDrL;=I|W7%bdrbVW$t)0;f7%<@W@w#}YoH z`ntl_{L!oDqu#^hZJ3HbFxT#935H`~%b50~a~SE^!ou9FJ=C+;T^e@+0*p93WV{9L z7alaMqhU`wSJrIP?G>hRzjJm?`5SAsmW%XfgM~~DgV?ChLC4W*GpOCZk*uZal7jb(p^Qi zvo@1XT@gF}6tiW9#;XK5L^WuOkGnfKC^ejW9GeG~WHaY}PV?09unT-5cFbz@{fNhM@lh4ik{z zp6eSU^-184q<@p-ZuuC5E=^}*tX&^MS|ZUC3ER-=hg%}I_Pa;3=E`iiSc=Z85HTN^ z9`WZbk5#)(Frf0gGX`v@*p&%+Ic+7{ycMI2Pub&c;f7|th{zVTh zYI_#RbX+EuwXdKWHj_;9ss`vO3&7kxlt&b3<;~ z!oSUz#F0V5pzGqqZP`dU86Q|ATuJgLgEqKVGIoWSUlX?fUNK{;2!mKXH*?3~41Rhr zpO*m=N#u&_i0>+H`%Kx} zD;)M6VOMIxv?3+BJH&!oLeGKsuerLCsc)L)##2TxB#q(uM$;~L6uf4xr7#*v#RJ5JE{_-n_p z4M_tul)P)I7+?z+0gz)sXvKV%!NOv6R|^YPG_dXK)?IaJZ|0}2wk9yu=RTYqvoAf#SyB2DH z?J-)prukc8UHy91%yTA;7Dj(KHP$kG%yORpc(!7KUlfn-@7wH@J!+11%SSk0K`?#R zejY;&_3$I;Me-YJ{~Y#!epl)0z2x&nwOTRx>XopQPwT~^ChM!c>hF&v_qV@=Pp4>j z=)k;q1vmEOZhKM;`r<)ZqJn7O_Mw<%pr4_y>#WIJBMCRbAJ~?r808 z4K1yGR*a5Cxf;OZ96Xyp)izNGFZM)8d|X+3RTL6q!oIFeLk%f|9CwB439)zYN~Ny7 zQJQ*dfE`Nda(oj4Sxk_; zU0rx>!G5#(bA-p6i}?TSrWYo_*vH|8e^#$+2#FC>nyWHNKNw=jXRZ$_#=Us^2p(Ad zX5E;IiW`hOnu$j85qSue7x6+-7mVd%gVed=H6Ezh@qt)1ExZCZ_@3pymBitz*`T+o z8F!=sm!J#9u0yQdMJYh)CF-rQjQsGTnQ^D3-3v#7C14}(*CVzBRAcM>Z1;mrp&jm| zp>zgI91Dto$vwFausF)@NA8hMZ4lduZP?YzHNY}1;qLFf^xSrIV5#$xV5%SqBEGUn z)cUiNN&vG9KYLfFzwo!Km!vTSdcVfad{OFUOMh|sOsod|f#V@lBcc*p!XwYa&FP#YXjgxm-Py`;IDv`8@PjbSn{9$1DI z)U8;-REZ4*UeK~D5dY1!f2<*wU3xAdo(;~(yq6Ip_QqHxA#yGs;lr3mg=L4+M2l%n z1xE)oDE9Rt8L+wb6*6c-+P$$1e6S7xU)xcze_XtlNyHQb!n8F%0^XfWh}t$9n+}V$ zrTD2=Ziiiu_z5Z70WoXPuVTE?;b`-cvn2YrY`L^}(`Cy|oXn6U%R@MJh396pDR6JB zR4Y-Z&MQNmLqn0%Ezkd5h1ZFt1nLxR*M_S*6xuI#zWfSEdN}I1*f_B4a_t}%d9wS1 zNw=hG9B3mn{`|h_OR4q2Y*=SqrMZUa{q)xEvb$Y7^IO}*SQPke{#W%LT7T4%#1jJqn|w?r1y=SWG8JVwcv3px1c%!PzA@A8Fk;w$Qd~cYEfB z$vYl5C2v<@Y!2ca=Z;{Zi0ChnG9w!u41P2vuL&SKilB6-g=fL|ih`mQ)nMrD9E#wZ z?0_qgu8$r^__c#S*RJbVI0O#^E?X0Ho83chkOWt$f!gl0NZ;dD&0fn=vg1~A2~LSi zxMH{QasHau;CMIbrjwPUBi}W2%KE%WV0|NWzoB&-(uEh|xN*@phrHq`i~TXQJ3C9} zLJP6BN^F0f%kD)Z{8b`q{A2YQgI2QBQGQ%IfxDwx|Mhg6DO2itt)<(IuiUxY&y)qcz)G>kQm3)H zD{&>o_CzNe&CenwyB3X4a>sunMHR&7&tX^|kMQHlKt+F>sc@DWEB zm2G|uYH_d9V@vw9t+M^M#|KGWCAZ1Fn=qQBoBKS>U$edwU%VWZo(&ICc1c>Uh$ z-cw%PPn5T_*sr21ws_-frt4?`3>@i&TTNd5#lsHXpE0Q+t`X4W`tv~KN!EriJ6PUj zY6msIKZse`m=8@GR~w*#;0$y83}89xlCw!UvOnLc+gYasx&PHoYc(ZF_VDGLJ(i`sOOD>M?cBwBvu-=aPeu>W z$x8EeE+PQla=85Sl24oH9JX{EXW}sZIFRE@Nj1!u;(Y(-H%|K9dgYTa1kAnD;YcCD zeH_d2D=p&CWV6aOHABA@gXR*1;r)HDeEVh<^T)YJ4xnA%B<7FL;%q}+BK&rW|B`>? z>~CdwwZq|3Mtr9B%8eg>Cdv7$IIF*ZQrCN~J1HO)E{O0Bb=#op^;kR+poBosh%o2H ziNpbFK)c)JvSij0;OhMBzZE1Xj}ojxg{(`vQOy+KNkv1ObI${~@kec}MqyS#T@Jab zMGK;t93;mId~cHotmgU_(NppM>}E})uA#j^R?+uhe0)4vMdFHn{GK8P+m4-dD4@@{ z2%YMz)|eJ~sN$rXr(cBil4OqsPZOl|H;Wn-^do`z@%yWgv$xnWJ{@VJRs!=p3c1R9 zkRBPOV0_Zr6-oYV!Pr&^vxd_`Snan|-^KWOx7KM^{XAQB`QgF(FZ+L$WS02X4{k6R zYnWaAy2E&Lo_gfl;sq=YJZiq(-PH+GoODUf=>jk91Hj<^tSZJ`hrRApt z5clF09iJYg5*2WlbA^p0c4uzn?Jknq{ieZ^#vBH1oAw?N(T|byS(d&;Oiq9ppIH1q z$Klu-Sbf9l^Nm-=&Z=-*BV@1o3CEk4&s4SzIAa^NLajd(IJfAb!_lJ+cCV9Ql=iY9*J;N1dW~V@gSztN zLF{(D;7`fj>dgJcYWi`I9a5B;YOU2&ca%93Jei7p`wwkX2X-II*(FRRrfLoMJ9+#l zN1N3fTQ$A^Uz5hb4+}v$yzP&kVvlNSI@Q3$x1Uq?ZHPurtu$|h)`*O#dj+|~i)`#7 z5b!zgO4ryzNqTF;H2gy>RgIZ|Mnu4UB`~ncDD3i~8N0`XJcdv4#rUKqfmlh`I=q9;#beqSoqcMfEQejsvYrk zeb&++>oYasjVg#0m~3Y)VXd$I@IgRR1V{rVGsHi@8fp|4_Ht)SYv2M#v|}SgP(%>u z6lWX~!8qWh98x%KbJcf7k%eaJC#50JJbjX4`6}8VT|GXfeh`-AoDXw{f$)UL4k4y= zCa6tlJco$H5#h&xiv15>@s7T6x(lbdrc1bE>{ccuVCq^@{lFLZdh{6~!r6nnJY-&r zm*CwDjEerfy*;D~TXF>44R43nyG?^lT2v<6EPTUBjZK?BB>4QWYwC%LaS-P&1XBw# zjkq`pozObwT3(S4|2mxf+jlkH5NSvg=RadAi4>tgcVtUwGiC z-@?ywAI*KgwYhKs|BXPLr&)L;mz1Z@Cv8C5Keh=a9>@C5&~~dSl9sI=I=U)#?6^@z zX;%kAz(EvwM4_lcafDIMOSOt%-CR#J_m9RK&!r@3df#;A6gh!Q*nQYpyF|Hy&Pmxj z&jB#3d0yBzLR)r3tPqf{NkCRxVp+&3Hzrcak@DS7JIY1nH76y&$Rnnw=v5Jlh5zdB z)~*BUfWyaiFa)C@1kHZJjSBW!kpFXXUC+p$a(={oG?uE{k%uVGFzWq;s0Nrqh}eai zhypihSxD!GD1pb~Iuz6HzKf{Hsx=S)@&!v%ykaoyw-#C!@)K<^%d2kP3KXQS1&RM<@+S4r#E}KEp_+d8}wol3YuCgrG7VI#YI{SYCi`36(Nl`KtjNTd))NNxZ&! zaW|g{VFYpWCuzfkMl8N2X?LHJ_>p<7+cliTMAx#1d))WCuK_nw3|8MscM3$Nm%klS zRCf}(zMc30_6BX6R(blQXQ0`6JYTtC-em@IEx9C4ndfbU{|a2Mrlf4h37l^b5O?}E zKi8v)BcvaOw@nR|^%?^<3-*mwvRv=<91wJ*-Jbl34-&@Xy1ZQH$HvdBEo_D`wrqBP z2Hv#%Q_PqWVGq|UJ_EOBG$WjWDfpzr;}ml%5U1!~{&v|_A!Buek737=+2}FuMv4!o z^geS=>ygKWxEc>If zv;B+x3BG;T8(i3W+o#eO{oIFJQ}}!x>gZ_vO=dga(*k@cmE6mbnP^NOJzi5)%9Wmy0TRc#I2xtqnSGTa} z;}u(OoPc=|Av#N6^JRs|ZrBY(sinXfDb5pwKb4Eg2PERg>0>~^$);U-4ADGLwfRUM zp4sO8#OtW%uj$%V$Fmp92Ry-gNU|1k?!^JTF+GKHlj-6&9Ew<;m`Mx?B;=liTNPs? z8aWKk`M_WI!_s9f?0CloX_S9dw+qnvQKvlYEUj(Qh!j1j0q@7!UTe<34exnxjPFQG zMI};cx4?@iYdg{6R4i96(iX;+&ko6m5Q_@Dpx z85#cPjF|fYQfls2S7T7dO^~>Dv`EOedJlkWLnRl0IxrAzxGW|vSMuPBI#r#YDWC#2 z!}Ni7mBw@U+Xx8IKqbf|R6)w&U;ev;1#lP7f+qbU2+5QQ$VC@YAAu$RP8*!SVx$q< zC{)S*Z9`D}nw|b_FQhj)eO*Ya|8Gn^MI_80M})yyO379t^;Pa7^;6evxSO z>Zo#I=kMd=NlHmXnQZvms~{3*L$5mTNVzEGb&=Q;j*=M>;Ij6e5`8cBh+Z%~cmhJ! zZ*n7)g`xRP%}D?CFmaue8aJsjpECbK7akxK8llwv;=%=>9}mT>q;#noi)Qwq7#~It zKWs6;Ld3Bg$!uZrKqMGE-b$O%)s(G*C50q684IYp%UE#ork=I#bvsQ{Ne&+b74b3%Qa*)8<64BNR>@ehlVNzg(v0|dE7tJ^Jyd0T z`_y$C24?rYyk~+H)3)u5bu=`V5Yq`gf&=bCrPoTn?l)fFRcwu{h$a@{F+V$6&gPCi z4ql*jK+n&Ht5C#IhIr*r23DYMhcjx%oz6%rM*mD1$-P4R*Ar3I0A!FDt$rF=aGN#m zG_?ETsl&vzt?LnjBa zI+($7o@s#J4l~9*u%DqmghcT(7Ut5)D>EeZcxuLwj|@zR1yp?>Fg^#c@DzL;mkjuv zZDG~1{{Djgc$3avB8oc22p{m)Mu(q>S!Jbzuya(CpepKr)FRzQJ9XOU9vP2 z&bWUvVKRYasGRE5EX2Ew++=Cn3n#EY*u6;8LwBOZW6k+vAY?X}LjBPbc&`IS)@Qek zhS#yA%YtrUyL9I>Df%E1dP4Kw4~S=!%Tw&@HTJ~R09>}zug%_y*f|593{AIlfa-%M zF)BIQcRtT;TY5OOURWCvz4KT3-yU1oI~HJhPtb9|$+c`Nqn6@!iW{Ph6|OjPZ8VCJ zE2->-EhX*0V;-D~6lKk1iT~?}UA&68>&5stIr)dC1opfDR-Cqf$nG`=_cgCQ94*6O zu=6IX+eak@Qvy(13x@4(;|#h7ocZbbo&2FU^4pTg_fWCGn-`p%epnI2LOYW>f8q$a zDI2Y@r1%a^c;$dErVeD61IO#1Wi`Q`ait&7r)qdVItN_6!&dF@kqC56e@T@woT1&N zyWnbN8{QSAIT=G!;4Y^&|4jN==?m5JJ;@$fQnF~@=xHIKR+CYdatodbYe$=hmwx;Wr|NtxWm9zc-P<|ZK@$7~=hrfR@oKxu&$ zPuU5}x+F@OBawNFZ%qmvH?PR^LHcbKN4(00L_w^qMor0!rJ|7|AVLaVT2#aH=YQH)a<5 z5R&)Z-IjQQWxLpa-@^`=NzML0zt>YZ|I@|7P*jEVm?U>ylYY3qD)3lE_kJW&7#ur*Hgzp(q!QgC#x@!-}x*U zO0oj}@UNf{FE>(3DgL%OPot2mJHj#~na0l_7!C>MtP0=O3bp_%dTI|;Tm4bhCM3}w zlacka;>S3=eF4EBE^6jrqQ@h9EH8`e&mq}5m;bURApZ9?(MrXh1t^)Bs zL433*Vxz)06ZX$yphgLqKs-t3O<9qo z-@*H^2<)nBE5@|P#i2oU~pX&$ISE6pG(`a1VXEW7jP!J3+;rkeQeUcOQ5 zBl2z+uRmDR#K-3c&3m8Zp=ZK!g2PhFg!;lkI-Z4ZUy==JK5d|tm1qbw5`X)$X<_51 zBC)D#(fv`QsrO_i#mlrg&68(DtI@ZH9hqqb4Ba%gP4tmtHR#5I2Mn}e)^u5vdpigM zw>-7aaJb7=W^x(i5BQIZfj?2|)w2kP73|`V>YdU)ec)aXJe2kf#Dm+=`%I9+(yf%F z-u02nMl+VZ#_LyoehvFnaceGzP9Mh9gB1?{-uw^q{a;f*tneR8KUZ}vkg69uq?6_Q z#GZeUgBym_`Q7-o(c8g7h5*cVbZ_`r4{~LD;-vA}+qwJkyu)GCar}Q|5e+P6Agla8eX1Y1KeN; z_tg2Q`qwl9kmf3$TqNkk%{1Fnz!8$`v#H`!KT1^1UF8mEgaofg#TV^3DXAfk2adn0yq7)}x8Z<;W*YNN`z zu?>Nhk+u2)L!i_ou%H82)E=hYoTDWAh}r0(f|`g`>mtoj&k-0}?F)irkiey*-Il^& z1@2^O-+!Tn%Wkt09>tKW@0hJSLcx(2JXTklol$aRQf;ZYGC5{>fl!I1H#Xpmkq~Qk z$5LlJj9!K!@ps&|zY~g@N#XuMR}bs#}Q>RR?#QNOVlnwdM0&FFWS&=vKo~06ih!9n16G6s8b626XwSB6!Hms^c5@^o^rbV*#^Lu z7CpaEQm*Aa+%-KMR=U2hMO$#ipBt}TPMfGUU~fmJf6<){BvAdg2-5=0qP=6@q8iCsuYvpe~ggTRa z=-X?;qGJJo$485-0V~d#^y7G6{(O~%+0~7Ah7HdF>rt<)&$IDE`rrnL1G9yw-LeI6 zf`0s>0yrZolC<9mCBT$Ej(uM6O+mbh@>|hOv0fk=tyl)RR$B$$TXVpbGT?fAU>67w z8J(%OV;iPyrZZPc6quR?6F}YrFsE)DY=4{FiVQlX_xX&QiqR{w;0&xnXp?|g75 zwEVmCJJ|5UOr14MVY~2KvYhJfpW=E$edW1EH0|E`{7T)oFH_cP9Ac$rfD2RHE5y5jP7>Z+;KPo$U*p{2C4uNJT_i z%=^cW^fJFe4hW8ZjQ+JEVk4mJmF&g8YgFUj|I{a9=W;Di?j#kY1X+f)2}RxvW|p}A{ukAs*PspGN{Z+;@T-)m zS{4*`2~@fz4bl(wa4w)Fu`~k>oF77uIbqq&eNS)|udxQ;aC+xUq|SpATEzpL2Kqn=5Q5z9FhMGpjPj z7b|O4RdN}XFzb^bnIewNpT{jAa@U#4lnQ=7conhFs;JH!*nkP)HQ@Go(j$ZYF^trzD;CTX58TH|87tLE$gk)t-c(5w=?=NoMi||r_BgV5|2cZSqz`tCe}kT4 zgqIz-vUNL@9F;e(;gyY+R2cVBVZx?D@W1t2oiC`3O+P!zw-3{^%?%c8D9>-c`;k!a z@xO<7{OFXKEd)_NnVup~l>znRh=rUCv?V52zt{?>*T1_rVCb^uLhr7twz?uYQB0=>MWJ=~zWRE#C-9*> z-BdCipO`+L@JmHU>_tOC5 zQZ^xpXeJIY8Bexsi#pd7H3QP;2EqCnl6q9T)j6E{=DXF1BQxS1$``-j)m)O6?-^VM#+nH}}^ zPlN7rRNj~3^Mt%T_ZM@glefaAkjxsayx&KhmdPeNh1xA~Rjd^Y8#wFYw))6<5BlYb zS6?mN~;2{jq-G4VNAt^$#8x|*xj@tJ%7w{$T-|C zUe96)sffvNd$nOe=3f#CgD3$ceG@bK@(&Ooadg1lyp z;C{#Hm1)D*j?d{`Jvsw1ZaghDL$G25$$Vke+oM8tc@qH{! zzn)1=F|r&$9&2~6w37_D|1&U@k9qzZO~mi~e^pud%Y-LhPmVCQWM&q58Q$#>5G9J* zP3PYLuYEQ78~<<0bJV3QZQWXb(ivKmJ^zyOcX4QYq{8kNTW#75i8(Rv1_|UCs>~Q| z0#(Y5e-bijzX6QTbLv?u(BqG{0S=K^sgrCSsf)EDbiR+H>;K=0Uv9fCZ=2 zmpE2exj2qRAITFk|1uvQ#DQf@J3K{ZIH2s)S2+PAJ8WfRjdGi*6jDsz&B!(q>e*P2 z4)m5RAeZK9%xEa$6ttGgxgUGYLX3~*vDN8P@jv^lef7FMdB$odz+*Bw=mhg5CS!<+ z>bxNrSsk}mOHoe6hCT8N3d{NAx|vq=<42lyf4!pvgSX|fzcwk$Y<~vc)7Y^ec68a? z1wZeoa>dF>6m{SwpRA-eVz`%;d{0#Z%^@!6-C2-)WF^=im+&sM126ee&t<8yVQhGQ zNtihm*m+Ik$DQB%g%z*n-FM1-g}|hwBqG5Ws7WbHqMBjs^$6v(!1OIGE$wj^&fc79 z)qJa`Z;vqPS-m71o4SMOdeeHK4AOFNyT2w)?e-Z0O?#Y&V^T;=Lu12)R;UKYJyqNru7rZj#dc z*0+FVl&rn>9&`7pNt08tl}njC6cUp#Jkvk-FWuA=%OLNc%NHcsm~?pfv<>riKh}P+ zcAsQIZo@a+YHRmR=`g+!x;;i51^xJp5WpbJ!vJ)EIulvA5!sIv8omdY7qiSuilm2p zcHTE4h|zeIdzr1r9P=4%E%#-VR4e{bWiAH!uP+gsPj1z|I`*ve!LBc(wN)&%K#eXU zE?X=8oB)vu;zjPFAYt|C4@;L|qC25J!cM~iH0nQ~r5WcT=}Z*U{5$~6|E1!1yWQwc z1b4ga=O~oJl9gBLUR^!+_S8!w^++0<561H@f=;5+L$b|wdH3rqP15 z;h*@N?j)f`%PE=Tno2$u?KwS#xPOrVgIGCC#(W}^&_CG4!RYJzaHreVaCAv+8%Xtr z8T#g^{K;K}8rJHK4^1IcznQtcSk1H!gX~1>6I;v)T;>ql{f}$lpLPQ*i9IlB$Rt!J zU#dntRxGS5rP{E54frdKRjrfhbjijd(p>1F4xObZW@PK7N3Ai?%0e z-}mTN`$zdZt9#hLW}i6o|CxIt`r<#t(V#VAhB{|-cAHq7qv2!qcUGTo0zuPX5!su6 ztlUkK5$+887AyY?z)Mog)Q{u+MN>xpj*o+*RQyt}TQN4~DpN%CrUJ0%hh2YN@sy~AOcj!Hr2dZG6X-3+6TP>it7AvTG*iP0$ zU0@C}a=FruK(}Vx_eW69j_t0V%fH)BG?O6M?^(t|+>(j0DKy=H6B58(AK;c?{TWEp zl$eT`EneuE(5|Rp-IE%VE1BzlrqJ5889y0gUnb1fiw^tU_Wm5H*6FjmZESVj#h9=; zf`=Z|*GZ5SYr@WzIhZD42eLCnr_OQeSM_41dzGC^7?5Sp!{eMBdA0m3*O~^WQ@?ks z56444myK{U5j_Y*~FiTT|Z;C)d$luKS@hdzgl`w3>zZ_pNUYC=0|J?uHuOHS^ua{M`=BQCMMj>Q4U%CC=jnS-w zwYon`Uqt4G%QJ-BC!HzjsyU61No}7RpJc!)CuofOddFtbm9^y6%*@QUtr~odee|u1>=Dl&I2qs|R=1nXH@y~A9^&(1ME#CO zziF)>MhyfCF#55=1YiO^xjVqc#0*s)Z-zN1xTGlCdnnX+JCwgJ!kWOr2Y|o<1_Y}z zO5BC;M!c-z)FpnQ(YRQR9^f9<(Vf`KrEMs;(8qDriH1jCNnmA4!Eu@)@@)L`q0-LRiPK3lg8Y4Axb#;t0o@0Uc{615Od}AaMYoV zEb<3k*8Q;-fi8}~N-O7#*pF#pksQgbwaW`=i)b;Y^Q5bBqauo1hXb+G2Luw^$k6DI zBQER5WcF#ySyk1hzA>uV!I`wk?-c`o#Wi#`^R-NsekPp_u^7gOgFPyONomK77*H?! zbd>V1okoWzCz(cUcF&u9Y{{>$yxa$X=P=m5nPsd5I39OQj8x>-O{HR8V1%T*`1<2_ zM27Qac!5PzRWU0?;f$(SqJ?d*q$|P4g`Xvk88QOi^TQ>wX))fne+rCsNaG{1o@$n; zr=jNFrhIztmlf>`2pL zi}e6d3E<7GvZ;|3DQpVtiY6%K&Xo0feQj(l?;qn+zic-*qNKP*_v4@X!~j}B75bo) zK_@V=OHbWp3m>XaX3ab_G?afdJtu}z#sIk9>GO7#!FQCKItjjj6Z>$wh+`!^lHL>~ zRMzSn#*;J{WM6S(9K)pLLoJZ4hqAao4AB}h&|+i`+GEXaN@Rkj(-AO{%eiWtF;qz+ z_n@uHdJ+cr0cS_K+5QUxs&;9#?1Xv8+L*CMePnoHuDTT=a2kC~aET&os(^Hum$PC( zfTltJA*1LN9;%+q40{{QQhd-dp>nSshL-|AA%DSR4V{d3jBQXtIF7XJ&w6MWH+bG2Gii{}q^KXf}r6D0c zZFf~f?BADNl`7J1e#0#>@x#JS!}gSy1Nc0oEA^{L)fm5tg@E_3Y2ywI1r=yL_2b`G z?yh|IZv&XS8T0>DmQw#)Wt1?~YPVd+h8mK(EWo?8kuKY1Yh-quTEqAYOZsj7cx$U< zkqeJR88I6|%)$843^oWV4^!uaaOseC%gtgo4Tq9#Ni}r+ZN>7VVb6OS1GW!slos|X zBaDtr>70O5PS(kYx2chRls`2*a7^xj%g|OZNF}ZBSNibn-EUPm*eeN9md41|lu{>Q z<-I0g*R^{5%5b}L%LLu&uvzKnqdP;DHc*xE#m4q8}gYG%G#Mj;mTq?VN#0E_~4DcFY=a0S=}%_{Sm;aImHa z0D{JN3r&Yo&urRjP%}3AvP0&~3Q_y^l+q_EPzTSJCJIZL_%^H7I?U&LC59ZAKj>cV zbRXbFG;B4ly;eF3aX3R>*DvIYXZ=De{gZ=p_qZ59k9v$w!xg;dp(oKMNM*wTKH+NC2+uO(u-`FaG)Ii)4h!kAS&{YYPAK7M0jF!!E^VXn<7Dz*z*7@a~e zXsY(w1Xwu3Ufjqm2*iDHDpD}=ZZpaG$`z}w>OIoZT{6!2XZxz|=>XrgxPXaa3vwoq zz-la`G%ZLBSmh4e20dJg&fNCd!H5B$7&Q$38CTM}#m=)3QE@lFdLl(H|7xv2|b;)knEu%5}ST1${?hH#SaP5P#k1D)%Pw(KSaeT|?egKG1Q%N0>}zbFBp8q)C6Kkx`uFrHp6b3A?2K`c$g zcE?2ieag7!U0kJN9V%GoqOrVXj6E6**p)#_8&$_nX<@6mpY@ecYi#B!RL1 zqMBiA$~S^}$cYhtMM8!A0VU$oNn&1Kdd3I-U|5_ElU{Rvz7*@$;>>~T?{4;K`%=$j zXnf_ZKqgyUobi&wCuoy#g|Q?9D8E^&_j16LA8+dkEXDjf({3qafCbk`ed3zR93n4H z6h;CK5Dwllw+A69G9*^<;@%xRhy?i0Ij2^_J8A|?mx-hytwH( zeR9m;V&kpsT!^h^|HJ~nx`WEjO-@(h?n^*F;+r(O`ySMprw^&L{pAJ38pUqYegPXR zL4m*_>A5Dqkzf@!@fi4slf$N1UVgN7KMkQyV!!-d&AvIn$x?3xK*m5uh>sX5%IEw- z>{l1+@x$%!-<>!A?FA57r1n9x5Gnz#Mh#q}<5s*jF{4h+0gpD!+i;Z#m?+6_QSCQL z6O~0jA-0ji)}oDDo`s+A1%P0utqXijvNF!G<{AYZu&ea^&1n&szss$r#PouFdJByn z*x@QcsLaq;uJ8$mv$T?vRIgZ07=b(UW7qX)*sSCY#!@JX$AuH|Jy~8?yRe`V?8_#x z<#?SrGfANs7zyp0l_UE4pOnTa5-+(lUYr+U^wKs*GRoPu1*80<xN9J$Vqg2_PtoXQGXR=P}{yud+3dlMTJ-INLdObXAXI_0n z1PbOVQ%Og};lPv*I8$>0Sm}hMw$kMm3e(SS0}~%;i^sbO8oX5}zZyq})@hTYE=^xY z1s!ck&Sbr3(J?5cIGl>Kx9$y#@#lHt&ipiy{YAX-MKd!qsp9l%YK@!UpMu=Jo@(Vt zs~RDg)^Cf?*7DpRnMfzhyOcGBs9BDg4~1xm8OE?ssIiu?jU;syxd>{BF<6Gm)*bku z++-o(2&cj;Y42K4jo)5rufU^ad?DN~FuTq$k=80}XjmA;1F?*qgb`Vys=>SXKx(OT zjVaRUx^p0ow5B7QLnrn+;i(%+z{o*n19w3H8gD^ zXBpgXNRf+bvKpn;zfluk2rFU?&^2y5xJtbVXgaWS)rWG$_;R~SH=T?2^gq39b21iwD!l2AfK6zqH6td?9#U(NVXds((;vup$I^gC5u9M=D7LE zOP%79$MJtU;x%+sTbhEYk8FZEW&Ix6gzNfIgJ77`C=t;T^*tA1(T;FStlt#u%D0h( zy?XOt8dUrs?yoGTYUe=zd*Sit-P)R>V$hd-v*LQdtMLZe2uhxC(z=o^a<`Bu$XkJU z^6Oizf?Id=z!Wa!0O)$SM zB@zba!)Y;~hCWUwMr3Ma)7QIuA=8lMEnghATKBrMSv{VtrKkF9CD2V%Xa;fLQ5ziw z7Q+6fi4Hli{|;Na*G-TVX7@8M7XDRB{M#ZaXVpT8yv_8NGcL{r)w&g5a*q8AHPVAH` zFg0HZqo#neIooU&pmu+G5WjJ?LS^B2C@w0vYxHq;RT5Dy`t7L7694pK{kNw^Rwk@f z@$Cdp@dOnJ>a_1+K-<@_MU=Ym?t`gC-%nS;feJJq?*UoS36Sb)ZcuTwU&iA{4w0wJ z87!XiGI~(nf0^PLAt`jjKvFNab9leG>)V-uni(SI!$w2IKb%c)&{a7o9buk8_wJFg zK(*8m(;El*XN)xHE+enL>gE?+KOfbNz{no_Nznn@ex}(9P9YO+cz_BuGdiY$c6&fn z%#;kcESVjwuqs*i-R;@Dr&|BL*76)ckDCSXr!?#o|H8+q8>Bs|O-y+>WeS6>iXC$1 z8zn=dbSiDPphfmswt)qopJy*I;h=Ox-k^ikDPnL`%lMA86cGr| z?sOt8nS|cijFA9q1=GiDbHPAZS4$fOWo?%*F0~T*m`EYAK*A~B;^(pxvNd{4R7mSO zsAk&Y*9_SheT(Mu5=G541v*C-`U;}yyezc?J8)5TR$~-JnGc}+jEq6o&nqZh{G?Nb zUA&OZmr!l;Dqq6nTTk^K5*m%)TE<{v3U;C(B z>_lteOMPV5kL4IgyJD^dm%%$tf>TGcrZB;zl9-6v;`oZc3cdM|xAsz~WI`hoEr}n&gS-wgl*Bcc4F(HE7{yHQbO&Fleu7Ux;$5I!iz8s-c`Rr^5 z`vvOO5S|H=GX0)c3(5L{ImQ%Vo%VoL(#`0)Q%0FdX{+?oUm8Pb6wX~{MM8+;9_EF7 zTMaXtwkxaf(Ea#_x60{YL3!@0nI179^{9s+nROo#4UEW*_`_nNE=e0{0_<*cCs7~f zCy86BXD=MbvjVR!5x5^iRU;@%N%>|aXpJgQC83MgWdEp4B!Os04l;w0Y)m%)qz0UB z$(lysLc`{VCD9>?$PU2{NpE8x{>gvUHh42(!*k~xuA=mgBXE%-1r0_(=R=Wdfp)@d zhgfz}V)B<_q-a|rEz&jFzMCGcT{(YF8wQo#`c}VG2iq6Y9Q=Ue58RlzGI;<_&Ue|A z6w$NRZQA4byf0R`^-=6*LM*qIfGLpDLzX0?#W4DxG68hJ&^(j?o zf5kcO1?%ccQw``mbIYH0pL>hhVwo>YNFSVD*jscsI1T*QC%;?wz~0aq zZf3HVZ)G);Br4@8Ht~y&=PV03OVJ(~NrZr?Y9`&tKFP}5eu3Uo%6IO5zqVwz%dRt| zwaUuW!G|nEyJN&R_8vj4ZF?Sb{4;aKG60qzgWFCKL);6ig;cLSk5ZF(_dqcZ-@V^9 zCGYp_JB}3@rOb?R#w_)*~1$Do@r)K}moCb^QPmi7!~s^?(-^2PMhipfRH72yP&O<>=W9i_gks> zK`GjbMC}=2MEn<``U_XJ@KfcjfUi6|62_DwBXaGyZA;HoI7DoYX)_x$z_nV?w!`s+ zy%Cas^mOIJGi>-xWUKc^$STcKIX0}_nSWmCDQiD={#``c{0rghcrnU47#ZdL?$`B$ zlYs}0Q{Y`gp+k)AI@8|$EPp*$%6lMIl#yYynDQIw1czh*gCP$><^qnZiN+9+P z8N(1#9mxoE) zKN}JTl?IWZbLwh#0x}J$(yGunkOOUUc#SHF#2O9x+Kd%o{_tV1MDAHe@Kv`4HkFr@ zH)$XbrL(YyzTaN@k?t{V#!RqyVEdG zW90cvMh<~huk8sya$)|Ag|7koTtvzP>tKc1vJ(p54A7z#!zM0cLd3@@QSSd!+)Px0 zwL}d+bj4@q13wLPBFBQJEUvhbY3J)Xw>l3=y@8_MNr0blm_={4p-o82*&PJ?y9P=! z3@f}*GCLQ?vN}NG7n@pa>(fEWmPP9F2HE9%`EiCqE(LOHeyev3M(jywvf=|h^=3t= zqC}kUmD2j2iY#yOYpmyU9awu%H8{CHGA4sr=VqTy#1e}#wx(XZ{ud{jSd#bLom!i3g@sW`kvOQ+W-ZEgb zPV7|lF>KR*&iVTjGRMAk*t!5NkjpUO_t*1_jhp+F$tFmaES1N8WDx-;D)i(tlk#N- zyqCPFIg(Z+Gw)~08UR(kB;dVfypc$_7ky3oM5@0<^2GN^PU5(PNVNATh5Ms{^1F?l z1{bNf6?5*2D)`@NA}4i?fOJsmLSl$GA0+JQh;2~3kX|f zquuP*$N=#c%jpCJ9#!Y7r)4Tg&%wtEX=zv zw(Bce`7|0=wol@Q)@5U#Hsn25?<%IGN=Rk1WNR&m#S`LvwJgd1YG{L);u}hV*oFFu z>dt(;UipM;A`Ku2W8G`L@1-H~7$;^#sOUFvmGgn&af$+dZ)^%$E=Y82ICE2lSCw+T z`{=!3(5kR$Ap(;r1;`m1q7%mZC@Z@1KdkLvveSTaQRw-{W^^CQniI#y*FI$*dgzR& zk0qT9*eefR1d~2HGy`sDKM-@-aT}cA_&L8XK8tnw`_%@Mags9^SJHI+zN{9_>;g!30Hk2WL2IaFPSHxRiBj4g z-=H(VY*1C@S?gQ&2;3Y6YW!}&zhy@V!ZLA^a{J2yVFwdKe?jPaTZ@|8a*+G(RG3$}Pk)8try6<}S1K`d{{4b=w z9d>z1zxBkl7uut!Ey7Lqp(*naH-sy?g%;NN)Kh}PY?lJPqUH4QgUdeHiho{|ue-}4 z;;#OH>LEijD)IETLAI`KU!G=9Y;Y#zhFgELt+P3uXDEug z6_OudU$^mIexhw7Xs~cjgqarir3Qj=$$()7<6$skTw1FV_rHF2Xq8z1d4j!#nFhKk z)(eNC`M1D8wlm1TzYeg+K&EM%tzK>>lrM8@5y0fI|2tdKyg^Z*!Yq4|5<|n8N=c`& zy&o>Z$)X;*i2FoK_?wz%G2;LWzUH!G#rQnvC+qj66h*z3|!u8LgfP$vDh z83Mqm!N=%mnpb6yhbMp9(awzXPj(BYusu_=)?<<9FHj$%FgHx zstp;{-tWAh#j>6^LKw?oUL2L0M%6&h(?l{6Rxo>4IRVa+C8226RhV;V! zd-9~9=kE`s?EM14yqpXtni-EH;)&>8i?$7~M9U9`<1s$pl&Y(8t5al-503t36afF4 ze(^$do&uZN!o$meoy;A_zTJeFe5dgWx0)%lS3E1{?S$3o+nk2|Wz`y(aS=6O&4O*S zLW|KYgkb-4uh{#gk*1$f84ZSnC7oeyfA&;CLO+=a{kK9ux05X2AE(Bq1KtuN3p#{3 zDY-0Os}`ud?1h0{@^U8hC|7qcLfY>YrKRaATLxibmmB*dF@jpOJ=CHO^(}85S))+) z41%8yqQMq@RI4o%P`iEBpIbXZZp2Xa5|#>g_5D(i!u4yE8q@@)JE-eG4N|=5Gu8>H zL`8iQ`-$#ve*dzzpAX(A)vHu~0iD#PG(crjI?nz~F{vVc(ZHIYwjoD+WG_vZnAoz6 z(UbR-piIjO;HvBeO6|lS*gUelqEhFnuu@GB{y|4ko%23%*^KroJ_)*>Yw67K+8ZDM z23^Byv>QIEDSW_-JQ@n-J#!Nk=7G^NP&3-JhYjWe!CfMd42?AWLk0fR=Z}X4Jf|W) z>)J!a;YQtlTp6-JuiTfI8p3nk)MMViX7b%fXGT?poP_P%{QVyTXnc*gQO(>iPvF;5 z>{YM6?ukmK2oc$4v-7|SQNT@i!6jFf(Jd;$#1(!GkO=lu0E>n^pe%n6BMwMPPfdfE zGe(Z)`>IdKrctnE;h9V}oPoz`AqLZ;v|1-WoFu*Kq&FIN)TSyCstBb?T7vn5&s1mD zIWbE6>??P@oznpoAf?{1m6cU@$ONHGKsEOoo7ix$CErh8UBEv?AuV!^eR)ylul}e z3vk4n=M|lLU)Q_HIx&fPQxZ$Qa>vqZ&7}0an zrrhz0jvy*|fH@?~O8$XmiFG7r_B6e~yRK1jvqvh}&9Jmd z-C&+w+UL*j>+O8W$2D55mKBxdv8t>kNk}Q@qOG8x#^o{3rRHLARxZtCTd~stH64B? zHrGjNjCW~y{37jZf_L%3rk_Jj`Y4b@kl|j>!ZtwM0K`FsxSshy2&0LJc~o)-b@V}h zG~oB4<%^RJ4=n7ijKE;RAbh!!48syZ_~Qi+;{Vo@7BNGCl7fD8HJ)Hd0WDWI1Hr9& zr0>D*+OqZ#JG>PSM6|}&DIGZ}rQhd%h500qfMN>!{Us0P7qAlHi~K*@)BrE}ZWzh~ zvYN0w^XKE49*ny$O`zNnv!4hhh%f*?tEy>26k@$WAE>lKr>4`7QG%(2u+P>KKnJLC z*eocVq_sy#{R53r3W;XAQHRe+<-NXwT%EZ>9kp)VI@;i%sDx=sF~YP=W|6hWoREK} zy??bx>_NRC=kyY%X?+u+MK>e7onk%ej|rNU$c~W&d%2lAdUFLM;Fi(`DHFL7fEMVfqv;>&aw zb@y^N+^PF-O^%!AD%Zzz8{HakasC5xdki}wSRiWSDr;5X{amMx^0n}f+@^$ekdNOI`>Dg7yCmH%_M%114Bc2mW1gj(y_7TNX~6_(l({vfgkq7u4P=w@-HAp zlANA_n^T__$dm(GNUNDJ$Bs!ZZT`f^J=v0Y=~&7!QVx9=4;n`@SJAd@mo-=By-Q5I z5t69C-(yWHE+?O#O)TL*A5Krn%&}>W|Iw$5#^=#@FL+&1p2E%?>q_i--t(udYkf-M zU}Awa#DL=`Ug3A@JAp5QMtW70D#*BPLB%s7E{^)P#KRcH*dk_K65r0ul&nQ_R4{=q}loNH7$!DL|RdlLc^ba2;`;AV}rN^iu~+X%gB*w;pGy=eb| zVVi8xnvPF@y6mVH(mC!nNmj!B9vkF^Fv0H^bKCE&g9KiG=Y)c1NM4iXkjVJPOEvcmr7QRND2)A&5(RwD9nD24D$L+*>%b9&n0 zy>YgA1`KizxsTBzv(v~Jwj|M;9lbx6`G9p*Lyw(`eQ*N^W1I^XXJmW zgEr)gE;q!5HOalu1Ch+y4mzF*S=d4##UXYGwdhr!=~(s!J5t+^Y{@_@lTD&k9&2aq zA6&GmFh{70<2^OnpG7+Nv6*Q;fl$2%fT&UVs^*5+{aGKfaXss2CXB{uB79-Hth#YN z!i*S((TWoTmawLpv3b2)Xm_2A6V^;vm+oLiXu~gg^O3mZcK3PRzaU+I zqB{HeBeZNF0z)Z3THCWSz*a$RHVXQnp9Bml_e|jUM6#a+>(VNt*1e4EGzgmDAbHqR zxA!>SN)m9lnvAw*X!U7VaIj;%$nnfS8kF{*(3-R-oofB1%kHpt+@oo;Pvw%Xn>hxiUV00^2ifnBt0T!ssx-xtxl)ZA ze{{I=<2SOHo^S+O!gsmf01hACpFItsq|aD5#-iy{rm;Ocd$AcIb|&0G^Bgw}07tn7 z>hx;0l30u%v*SA-Ns83{&AJv^Z*s$)M~MJbHy;mTz@E*1v8ZQJcP#DTZCFg9d91^d zSGLqKqALtmM#6uxhCjK}FG{D&ty&QqBU+-j5TSUL2nTwHX3t`ZfU?@mzW0Ip+n?Xk z$E!3R%FSH$H?HH0FBf_XI@N=EcBp@aUqE^6zXIn?1WNBK;NH^J{ApOj)2XsfD@v)l zgQ6Wp7aq#|7HRn0Zn%s^;8d(_v0K<61LjBs<{G&BVlSY8C?Y;f@+ziGfz9)0#}!q} zl+c9`11|KCrgaKa4BHfF4oc3&Ll&fZ6tv@^PX*Q)I|=#=+a@lhuK#HWQzi?(A+S8~ z+&F`4{bk+&NC1Z21>UBHZ1uJVBahBXF^^v6e@viVKw)S zQ6-cbdUj+d-6k)%@$Lazqcsj=SMcjs*vzsh(_x`rILv}D*C7_S_15Jo0Uz(l3H{R6 zOb5EwiB-?;I*%kyOM&y*3Rf8wH+}SvlA}vcU2wZEZ@b9ux9$CZt+FG|B{@^Z&2{D$ zC^C?EsvPnA2@(>Y15#~{&$l3cdlts#wuMr z0lw}TK3B5z7mDmW^E~nkV9P-~kKX?|m@Tr7r)_`5f;x0@e;Gm#@XQk1+js;cVD6Tz zaWsqhC|dk;=fFd~@eg?qw`J-t3YDi_l_`+}#HQu_!3;~1=B>dOgMN#`QRs5!3D=ma zc)k`jzrp=f;gBc1;is4nMkSAO3C;MK;ilVqQ2UVtL3~Wj(}wPcJN3xDxGqC=w&K#W zxw(e@%=;5Tfg@S*Uk^a6SqB~x0Rpo;nspAe=-cb)KfdC)-{52Z3=?>I3Uj^B_HKUj z{iEy4s)!Ati_hEFVz`^onG+_r6iG*5{zOINJljMTsVg_GFw2!sQ6PP@UAnOx7jq$S zXYku$$ngsQ^wS`pbE!RLcUO{I(HWe_73?G{;D{wM*aTi{My&4!T{e3bs*gwVzy{3& zR;FLrjq{|bH$n~mN`x)JmFHr-ZPoo?n~bbrx!un1oDJP|P)NwBWxMmzu1_eI4+GZO#duwRzPQ_a;{+KJ&hQBFRJUp(z^LHwFWeKc`R^zlWIDwWcc; zyzYcVM6lf7*XW4)i@qsLa)-#uNZtMb6V5?gKceL9RdemZ(vN!JRyF9 JYBe>>q^ z#~m(v;qkS*DKPe6n2%27XY{jxwTE^P)+Pd2wQDZ-J}>pkt>xqD*@L;l-ez}!Y6ywK z-^k@J0JBI4{b<2?cb@wi4a~44)-TkloIxw>@-Fx^3q*MSk#l;lqADv3kxal_FlmP9 z1V71HHq?A6X-~{;WcnwcNno-5@dI#D#iD2PYBJ*1Wy+iFj_4yr9IIp`F$Vvn`xU+CBZ^98YtZ!r^g+Mg(VuzYPcZpvaBW^a7v>(tOG}Z?A4$yOK+9DgH z1l)gauaF%tSI2-JmqWjhb5D_uwaE;kcv6xbIIN|(WyVcyfr0!VJ*J2q+UgS#Z-VPd zS|Ek0!&^!yVQlpdZ`1M6yf#*IvF8^|4=gtwA=(`?&evOoC-a%-#R5%j*u?y6HJhS& ziC$Ss-M(3lDry145(T55KE530CDm6%oH^_7y|x~g3N>NWmED{CYFTsC%)xud{7I2Y zM|L6X2GeDkzYXFnkmvDR1=S!UHq90LjWWAdQ>9)^OYS>{D*-ngaF@;1++-VUpI&{Jl z@sB9|r?u!!SPec5lhzO>2vu*H2)fBv4EM{_NV138u`FXF&n@N~aDV2BV@+3`zI=_; z58g6$QrMMq-B%4aZAw}hk}l}Ri#yNX+($4)TNrY;zltv=c<^T1axtsla}URUz-Fsx z(!N^B|7N&l6Xp`r`67ouR9{qh))ktryA!JQnyH0-I|h8QMa z66aA8!>w=buyM8?SsLv$yVg>@%Z_7?`HIHF74$6zQ_vgp%X!DZyG|+pZ+*@1G1>hA zJ#$Q&^rkW*;?VCrFIZb(g|_wbrtVzyne4RqT#L7vv&w?#?b}B;D$haN^ozj{+Zv8* z=cDhWUo2@4I*%GP9*$FS_mp72r)2ZS5r|E)CocF*jM1MgYWxEGItwvBtj;~xxuTZ_ z6=!!)4NFlc0~92Cj=_Xkb|UQT>~-W4phDRvY+vAQRlicL;#lOK-5hXbhTWBX13zBw z1q2erI90lpd$u)XqU0_=y)6-(rM}7?=2M=&XnyDZx&zca+}a#uT6%(PUJ8VIeEYvZ zkr85r2ka%2g+Fz4vZS2@kxa_Z+wm# zbK((d-=2leH>}ty03t#TgrU}bJVl_1qAaI+sc(BLKJeI{ccwo{VZNF#z*t0}=O3qjtQIND zIYzg+NJXohBS_ruTyXtOGa*6gYo2*0eM3S?X?ii>8nVd7hy`U7U}*ca7Y;@KwZl|V z=Un2`%Jap~V|mk-%Uqf_%Km4`t2y@cwur({7D%_TFZRzc`!rf}3QI!!)7*ise0h*M z)${lajp(co5hmO0#5$>`sv0r2w?30D%?-rK@tCXsRe>OE*>?% zhO>A)9k@K53mOD{?)7tTqN$^M3%O2xw4=>fO~vPjW+nq5@v0x@QCACzE!W?uEJeCI z93mVge4CH4=Y%_5<-pX8@CBROHc^EF2hIX%AecMyLtHsa*0)*|)pL`%ZbWx)$M+LK zzpne;$IIh8;E<>liI(W|E0f68f9MNm8`({0`%@zkQYH2dOrdM48XC=;#V{y+u@bRj zzwsgaBf4~-vxGq+$!H1}aNCp7FMn8>I4?X-PGqJ4FPW)G8FgN=JL3B%PI2lrcs;hdfqYQ+^T^P;Nky(sgA&kdlCy{)W zSQvly!$VytRV75<(1(#fr~pvlWv+_KW4&nl0*X^F98uiN9&KCtQ<;KDJPV!!qlOH@ zGeQ;b{{l%Ta8TZk?YCtr!p{?3S0B0{pk96O*)FEx;7u4MU`*cRdCYP-IRQ-1EZncs zvD%e;Yq;zHnZH(}M!BiS6<=`p3wqb!zL7l-uoCXWSCN{Rj&w34~nSyMU@?!dfv^`U`ubp3J zE^V$Y02&?CF%l>23@@rE_#<~eBN5%$aG4D-?i(;%KlLYY%abxdmCT1KV!x(`Eg$#h z_brxn9b~2(xG1?jgfzRQIxBuNTIBx02Ri{NncQ8*aQo=Chu$Os8XFp>-GaxPSpz`dkl=LznaAVxkXb>l@C&<|`lFRlHmG zNxv1xWIyp@7?EGW z`^m#~ZgSn%kZ@<)8&NTYJg0O2JfR(l+jHqMqi8@8>i~QY{#r4&$?cTzvyh}wSd|Z3 zT;-Gct0MQRL-R^(Lwh=~`qQ8=%xtb%T@e)G)@ImV9OSf&NBRb8;j3f^`FylrDdwWN z6F)G{Gd3-;p(JY(FavkR5)(j%PdFx9cOr7Dup17k-t{XssE+&rOf?7f4)ZQ67JT+Y z7ui%LB!Vn>lS2|8d0@}~cZ@7DKtFz2681R;twNfCuTx#kT8w^^BEtQtcXkV5m#xIJ zA~X-Cv$^g&4eYate z&L>SY6{aY8Z1)No(Dyt{>PvnRqK{kkJro*C4m+)a6P(~|ViM&`)5#ZyOpjly7o2TE z31NsJeU`EzOKaWcB2gG4n=Cw>8bo#fH5^OWR!I2+xBhvg-=tN?l4bg&A+>^uAc@{J z)Ho#{eQ+W&a7q29VF%}%LgM6y!&*0g*~aD5calK-Ng4KBTTAY80snhmlArR}8iw0B zTdU1xYpFc=Yh_AO9@cf|()XX8Ent)p2KYYeUJ@&w4!7f|c&s%c`SIQ`PQpDtYwqdY zRSAmoZ>w%{@OBeQzNVu0VL8?AO>X;#-qbUB?26A#EM~2CQiib#dHS+G?yzvK?O#QG z+xakh?fp(i`(YZtc-<5zaNxeF<&L8}S{EFIU{SNvb$0$d`mx!XgILvb=@EW(aUEvX zPm@&a^i|C&Q7*OEjYYqp{Jr7$n#&jXdkhr9rTvf%&MHRP0R?`iQ8O%z@^x#VRa4t0 zJ2!Xe+V3rovkY;^g^r@aIVhk+w1Ob0j7LrSDYa ze_v1RjSl;T^hVn?oBdsv|C>~HvL~B%XvXlp=P(3;4Iz7*-2v0Ur~ zu(P1w=vzmT<*bT87{W}tnA@hwz|^$r$9MHwJ>M~2^&ejPS=^`(2VyxnembgI=UCl% z<2Yg=pew+epGrKlUyDUt5$Smr4X=Xa_QZ`oJ@KP*q6K6R+7;z}UWZ`&!2!{NgP?y= z?Xss8Cw)eV0jPW|Qb9b%?TMn=uKt*!7gEM8PXOy@p4jY-i`0IhL2KM7#U%U7*^R1Z zuxk9Nz>y;_oa)IVAhQ8ZQ=FK&u zvvTuxMF5dIE@lqmO?)Fwq_!nocE>(SNmpJ7G}a$7J5W9hI_r3|Ze=curp%@$vt==! z4%-MT?BzFsD3B$-;Bvw(cTLsaG$(68%rW}~OM65_#N#N-Z3&4})XPAVq1dC&k^J`yzH-)9hs7)h1s4uuh$C$uytAjng^{CadgxTO3-!q=9 z-FkK5<;`jWWBb7_ivNG}(#+70``m8ZYat$xTa}KNX0A{X%Whuq_zMyQtOcIewoC15 zU~!47Zm9OZ?Mm@@slGQdG%@~9DQEObS@X7h7l)R4Ev{ugdxM)x5!1-99hnPAy zpbWuYG73#}FnZv|*gW%J8f;QugnQZ?X~a@r3#%4$B5;!JW$?0zvSYfb*o#oGJ_XNGcE3RxDCX)ent2AN6 z&kjj>Y19_iV<=jw)=^CxOl!$_G$-yQ` zthqt&kJ(bZC1DuuYm^8U>-8!s?eOUP>n^qfZoNvzEl#Ah(C0&fRGMRe*SrREMrNdqjg8o^{Y8W%wYfv74JC)G%)%;hZ z6{9%T7r7^nD-R^&65&XH)-H{z7!Y?&vnM!ke3ZG{9`i|s@-;SmBL^(QN2>aAdoXV- z;={QeWtluk(H z&P1axC4~$Ke7l~%_yPWw^sanwUAM^&4A$$stbEkxk^zX-{&(8xeoyIt;jZpl@9KA5 z8!H4N0)o1OhOB*;&V8HifE$@(6Rk%_+D}?B zm@&vZKI5ra=X23TB)23YPR9u5KWgkp%cFj6VeUsPcqz3=MXjru&caOrsAbA!;o`<$ zrqU!UxLy>+4wQIRlaxiUCb%rAY8(an;#vi&>D@K9(7yB0KdYf>QIOd%;WrVzf(kvD za$hUSb!?N#NpmeR1Z;~e2F@Wke%%7BL%Uz2>`(8Vzj_hx3P91Sz&z>;ZVsS>653fO z4qzyuNs%@S2_EUG=5Va|FqB#3lbWw8d_bb>Lf7eX%@4)jS8L1vq_U=XsLv64ES~&C zeA$rznK|XU_l!90#3b-S^%mf1D@N9xH?&=IEbpjOVJrF8Ab1@&jVK=oLed$0OSZ4;|2v-i$^BJS zxa_Pl`-;m5gLegI>>8ZNE@d zyXSnrk})#!>y~G&Ij=RJi_(p6QxY+^fH)2bOM`+#SNqqKfNkl{)5JyyOf?Z^#MVhA zRZM~PL+oI{=b%RFH_Bf5!GPeO?q zybXll=&ZNs)w%E7>@mIJn(%{Ka;-MuDt-uHin#hX;4@7787tDvUp5em{|DZkeLWjy zLdS&{QmZ5*jA}pi47;yk9BWvgsQBN6sHM)Y`*48h{ulN6 zHKQDsZb6K@or<7b-x1Ipg+z9q-41q$hsy@?VI#3A0MuH%cSmyof4}O?MS6`Ox68?! zt7OL!jUt`QHCSyeyl{of0{J<2*nYKqATAwJdA-B|>q=KC>I!Y$6ae<>blRe%L{OVq zPnpkgMW5&`uXUvdjPN#b>3a?i z;^8lLv-TJYBnm?K++ezTZvIi9djk_{Pv``i6K+jcLOoR$=^WahdcBRXJ5!uNS>AZO z67<^Vbfx_Mk&Zi(*;9w!$mMA{O?u=>Tv3zM?ogm=HnbbagAsiXN`jQ@Ux!x`+ zX`C+6T9^N5BSgL6_Y#oy==q@8NVLr*q8)U@)$&mnZP3-x673P#?+9-|zYacMoPG^e zIko+_|AXNzIU65S`y3TOVNX?lXMG1(`3IQGxeoTPw+`uOpQMF&`*0-%`Ll9Cvy-`A zJ00hcp=|i0I<-)ke)hAt*XHVSHy0oLt-UK_a+6)ZBQ&882oOTt!^Q89PdI)Q3j`2+ zmj#V>CR&2g!@pT87d1&2E()R=LN`w&L9`5b2fyINqiel@(RI!UGpK25d-~EI&@D|! z(O&b`jZ8@^Yv1dU{srdl9uv`fHXAM773?IrjGxNV{YiGkrTr(6mSTUxPb3x}KXTgs z3gRzX-`)MBn~4$xYbm0#z1Lm?br82>Bp`0*yL+zZcviJG96jgA&+H$+l^gj(VfTcD=e;d8u-i0Zll+q6rX$k3%)Mr z?H(kipyTH_Z7yqbYLOQ|30H6S;OPA_r+fwpT)WhR3CFj3JMX?L4FlW>tPO87`P@E~ z)ho-f4?3(+jXqMM7+G=GY^pv$(lOKMu6!YV^!I7$wX@|8{Qm8f{iPLkW|%NnNsa#o36 zu#U3|;ijBin8Ks)GdlL4jriPTR0n=<7ASGw|8iO2D0rW0^+r-mK;VkQtBG6P(GXq1 zFK3(6{v5>_)Ixt)0zWPo?7Hn53%E1~1)*7Zew#R!rS`FQJ9iLt=m%F+Ew`6lb&+6& zLM}GCnIC24kXqTCkP|EhaV$-xlzZyl!vc>9ws_v$?_4LRbm4ESv?M?S?gLz=I2%m# z3rDtk^4^{}B+a1>_ai1ka<>@3AMvpzG3}IP6z}fCd*R5Y| z=eZfw;5$p{_VXIIpuDh{QPTae^R#>YIh=myq23j~E8KTCxQd<`wmCE*sM4s-2O{R; zY6+kGvi9~MJ(RN-i>Ky%$a=%S-;mgIGFDjFLTB*)b#T=*k(?>xtxme7;mg7Is}}|; z*^OZ;Im2>ab-7KsigfY<#8lCn<}=DC;p0O?C4l%tu!a4=h&D;ks2hT_8zXkh-z)%) zNAx2Uv;|xWp#&C^?T=W>ln50AmUwV+9Hhp<5ZKt*yN61pefw~+n#xC4S664EcML9_ zl;0idN42W%M~+@za6p^pyNai*=Llb|YJ?-mc+g_IAp8(1QVJbfW*#PZwsic*%E{6lO@q`%kSZM|FnE{_|&>9r2TvG}q$8>bXW{ z#>xQd#_+S(t>KnbW25U(_LI1PH1opzTfOn{%WYsliF6Hw#R?j55IhtxqOI~!r|x*9 zk6?fMr=Q_TI9PN&w-&^mTabBnM~xZF|9{x^pPdsq|)WxKr+wP(U#MLFw2w!@DYhKUE2s`a_k0%pe7J+?U{(Xk?~< z^)WjEgz#Ph{GHC|l~&2ggg^AVE3TyY`2=O2d)=WeFgRNm>0=k+<#m$-*Ee<)-cxkw ziqH=*oyR@(Lr;D7U_oawrp(z^;Ci-WSu=shUHqq7(8g*Mi0TwnWfCq<6(1C-S)@GP zTdDG5MV0t*VWyuXAdfK+cMU|yR11nEJq8M6T;=1^xkX>>uhpct!J|P#;KuCEh;b0q zAhv-J%Q39W+i7~evuew6Evy%yScK?yN_=ps)zT<5z26r({dKzSO2AJp}sgUkhOE^c2NGssd1!R^Qt*SJfp3;?^%pVVS~*pJpY zefd2@Eijo$JxXnDKsI1`LJ%p#F4yvIdliA5uRjh2F3^o)k=Iws*KIc)mOf4Uop)Ti z8Um;fMsUJopHikolBk%XsRiKGNGc7Oh7F^gFQ}Uj0@IEb`St%5SO0eyo%|c0OJknD~eR7}20yxOg>_y5qzn{aKere?kr5K}E6%*TcB% z6%KP6W7qqa($G0Xw{PzCFO8cgH`m7mXy#Y>YnJJp7I42(3!&90DHi<{y1vWyvKlh(C`2;w`u^Wu+s|u>2cM#O8Xd%a2>~hf`&h0_n zBOK&`gVRjDUg-2v_Dl*?fE{xXoi{7dW&5PL_*h`W9n+x&_cX?@9+~?t}=hiDwqi@{<|vbN%T?r&Q7zoJpWs2!c$?FLWrcp zZ8FTeiD-M$DA@e5ZeJw{R`2v*-~LGPdwBPeQ@ha#TDl%*L?K~E z$6y2X%F?I~Ltz97zB^3KeQCz0h*zz($KIyrol{Q-Io$V$5@ErFscoBD#dD1jYwo7Q zY?pNi3Ed&5Slvc{Q0ZIV>=0%{5mUVR3@y~LQp$sam)arafabk{#+0=sFKM^3#eQ8K z3RxK$p26=9eg}?bO_I3?P^kVuHd;>fl6)t2INqkW>xB4~%q*qo=GW|Qn_B8z`ab6P zEA5R>ZpPkLtq{_Z^h6;fs|sa>m#NJaXR2y& zkz2Oi-QC0R7_%MHSBPt}@M?y8Z(YJD>gpf8;gV3(M5oP8f0H(m7dTX6OS2LpD-fU2 zKeMI9{uU@kEzE}PULTK-m8Ran6}mktMcOgK>JUki4qaVg?SXRmp?VIEL9(XR$Wpy1 zv8wk9vL`hSLRufH{FdSXwjBHD7b2?o7aKhI@vRhXHJyJ6)qj|dV_NQr@5c5w0au;I zP5EPscQ8r_tG3xQHv4J753fbNg#gMvC<@lKnwb*s9H@%H$|YD?pdL`%&qTD4T%B2m zjBajE20Vpyr5pOsf}PQ1BF&6bSJ)nnQ*`0$=_hX3fy)S;F zsrnkZ3{qw~Zi^SC?ktkjIONnjVTt~JHEVo;@Z66#L-LV~?>>vwsAD8CDG^@p%@G_k97EzUCHW%i0YKFg2j=5Xw+mFmB`lB)CHMMW6Afm67!l|>HpsGXDJw(uc%V-q z$SNt(bG)KEPR${w95r7Q_UIgIFf7P%CDeBTis(7-)AjHZy8tHyWw}wn$4_mpAW)WE$%gm70P+1iFTVwc^~6D39KrzuA$}^laTsM1-0y;+0Q>rEE3@JmgjB#j zRQui$@paVM`t8>T=gI|-2C%>ZDx_2oM7KfGe8^9auBnwIeDVI9|LPTp+&G#KQ(*U% z=B#PRhP@8G)lj49S%LDrS&?%351LAuyE>Gw8h6Bis@C;4Iiy{yS$V#YC7_{|S@P%3 zJ3OTbIIQe;;|{hEyUzytLqYh-DY#GcMF=Fq7YEhrgQdk#Q00Hth>)_}d~?Q{m}I zsa1q4SM^iG=j65XFaCiV)MzztCeP-@e3DXXZ>%nFn?Dv%&(97xuFDUAwE-?RJN`sA zkY&e(I~K#j&FSZzD$}lH9t67$Tn8IZ9|xZUs{jFHX72z8+f3EVBKne^n{QkR#SJoK zNQgB)uH`JH7`Y?@#fe^Fm!5UjOHCCKG!0mOB)D44PVw)ZR>UIly(u#N^xjqAW4gQA z{fi5C^}OTOBCh8k*?0ODT1rDsDgCARkJa>$WP5GiEK%^Q$2KgNuE-|j2%hs%sQv1C zE7KvUx#(CTGPXZmZ4R%ZHna&X$G6we(o=8(iFxNe5{^J@lOgC3oBRVcV9 z|0W1Iq#*oRM>=};Z)>0VwZoArjoTJ8j_^XQ0#ZR6-A}sr!6n{v9mYqW+)o36ccrvr z(EyiB_ClHlID2+3cv!`9GLb6zbITX}?vCjEgyO@@HOTK@=RS*VY4x6H(2~<}*&sCi z%Nar@H6=)%xG%|(jna1*EZ`nK9_e*`@bwgSj}s^t(F29bpdom|2SxO#ZcwGT%DUt~ z;g?u(FL%A2?(%xbw?H5Qetw`7MHf<7ANjA4IIn2JQk%#3T49bYv1?5im+oe_Q#BD% z===M=yQx}Ul83XSF5g3Jd2+_Z>_Ic$rV<0NVi5mB^3b7A@?-V?38CG$LETcdJC8am zGvz{VS3Bb^j`szLwwGTBo)~7q;eFh_Rookro@RCXTLpaZ3+?=XyS4zB;zs*%wPen6 zFRrA)u*1qzw@%sPf~{~9$7Jw3QI1#1a&;kM(m}4n7R}VT)DsNInePjr;ioU!Wk~60 z%jAzfwFhD=NnjCk9Vga>=GSWlUz-qQrUVD-R%G1Z-R=?87gKpotGkN7`A&Soq!325 zloOp8Z<`EUN4gLen&bhizLSvhxSAbt)QF_{tv>kt?ac;=@O^zJVgiF=+ zzA)b$wdjYy?h}rfg*RHy;~F?ANt8R)UGbF_pmzHgdee2*YBZ>!Dc$*v)S~|b^%p6% z3DY>rro)oj?CuH3myTT=asG2o({LCzS7q}vgXUS&$G=naj$l!a2|1TQh!x3+>ftc> z{@V#_;TbSH3RLXt>WJdR@{mo`$`oDriQ!9%GXGGL2=PB!U+6B0@LOpo0!26bkl z2ao7Aip@i%=P)95%lgZpcM223N}@V{vJ_1E`{2BvuQ~65F}^0RqCR+E4KwYRQI+`L zoh}ERarysI<$L{D+I2qmQu%4sr|kW>qZuuzHqJuP%$zpckBrAX2lB z_mDfGK^ri)($hX`gWcy?P@??rFv#m*=R~&ev%56F;C`$!eqtS3p7bNu zS}E!mHA{6Ye0EU8l&q@q&X1!N=lE4C%}G-k{Iq zj7RJ_e;4y*eZ47l{XAgrTXxryi@qo68fVDnwo={f`+MlFE08zOvuVvpzM1;GehUOm zKbJ?R5h9FQ0!<#q-)DltWg1Tg%5|H3+3tRAy+;yD%3!-6qBo`6Au4p2KtjY4LF;q> zEtBK6?Z2ZVKcd>e^`UT^yOiPnv!zl+ucU*~VEDWlbCE~ovOQe4&JeQ9q3=;Soc%UH ztIdc51&DGv*@6Y`8j~0MlSTtyH+hz6zy7EO$Uz2M(=Q>f!r^gwX+HkjY5>-HJ*?hG zFR;l~=WOIK%q_x*7ofcoI8!ZALqKPVZKPg7lp4Dh-(6k!S2uC)pu_W+F+SVp2w#dn ztS1^)Uk~kjT1k4MFrV7)NT~|BD24f~|Cwyz+lH*xb`twIwEb(V8H}P=L@+m}k-D_F z`fdfG)owmLNjl#vH9Ycx{Xp4DB}vMb3Wcd|jFbp#PsWNvX@rNR>V9|Ay^>F*TyC%j zYHBad6PLkQi1-yW6k{>N+o{0-3cFNM9;gt^8U{U4C>g3h@}0()eoT#E+B{(#OYB)I zRtiE-#Nc_yqLE-DU7l60p-xE*KF^o2iO?%5ykm5+-5m9?douJn7AL+7ld`BTqn0kb z?K@`YBGV1Em(4u+z(;_JM!c?5*}0}ZbCbYf)UfP(l`(%IN+YMqs|tg|h4 zc`FBgTkq@yaT;wajmg&A!SH^*mN#9Jf5<+!W}$C^=a_8A!wprh@{>hevW%3Ba| z5Cr=Wx59)F)=bb44nsA?!pxRDcoH{H&~<)st?q{GJ|`9uo)|j5lD-7~d>YM7zvcT& z2)+#3r?1wi4FIQg9JmbmH?$<|S&h!fNj9L~TaIoyOBi)tY#EJIz1g0;G^)seQHZKN zaHa?RjwY|L|JO1A;Z<{;G+WXD>L#f>ycBshpSF~Wp_nM4ztK?D4Zr+`B~u&(mF0d` z^nj~RF0>i@93NFlxIWBqweO-y2F$der3iMOqHPhX=Tnxu9l|vmv>vEVpz`g#h6FPg>CK4Cbaft=%g^2b3_i`FBqYJv{N6Cw zWX@RgVLZP9nyEj<&QUV-P!0Obi?$w4TCPj_)ogQ8W__g(ZCv$tosKoL0$^JqQTRJf zyf;2>UH1|-x$i8Dkqw`zT-t~KL*VPYXxnsmX7A<-N|8+8wHvk&dam`#7W_|+fvqqv zs$TYi*22l~9`&`|2;Oq^_&J*SUBk6nc@QV661Z zjP{tUqVH@5Gib=?wHDcZ{HT$xb7*sE`LA27mTKBo@n7Ppfk=`~7e&#Hp{!?#?N;PA z9%*RaPCrCnb1l?@s&GX;Vei)6Cj|+8cZ*)#Po7sctLIO)a)}$c5&|*oUU|YS#wh`v zpkLY1phnSAhOU0tLQRbCwH=$|W@8R@KB2C{%%8zuDPJ+ZWRg)wzQCDK97Gjrc|cwmByONbvco@*X2844F{;;Uht+|Jhv7<;HflF;gUp{-0y$c;%*l_ycI{` zD02BjFc#^XTGvV^w*9MfmNYC_y*%C|!>>9TC*_Rf7^^ja2!hC&ny;-R=%_AyvfX^` zJ?t`jqh4Vfkmt9}VNSn)A0Pi&VU^6O6C?{q2ghR_?s~!?!inTosNUOWtiXw0wVwrF&mfw1n&HvSEpLZk&~{?r*o@f6G=5D%&-@hX8o~ za0cE?Zf~uVJF>Kl{A7B-7_IcZ0_huRdocFhQ**mwroYQUO9lqtHnYd78u;A$zqb@O zbbsPS;>Ha=xn{HrjBzS{-t@AOP9<)lXI87R2gvi0k&>r1HmN5#L2U9+!k?)is8#-a z61=`913B<4SO(!^=RaS1H&8AddS#Jn3};o8A;04g8ycH~r5eKa*>Xp@Mc@2;aQ*@N z?a+dXF(AbUtqD_$RHL+apVGlDhb}D^l7nOl54fxAlM?Tu@nQDHPS1sUjFTU77fJ2- z-(`E0lk)Dn6^5|AwHtVXr*Gc+b7hi|LxQJm_czo?3jk7Ik}eop@_K12V!)Hs1GY}r z-_C9{XI;5++TPwas@`Hz!v_{S9A7_{KgM5UsZ({<>2SbSyc%2tBVg|v6bxnh(ZT8q z!eimrGZ&IFu<*7l&`=t@Pd=YPfRaoZQ-0V)kqk72ULKi6;=^de!BQZ_hqYvl|0^|A zcu<2pEBdqgi=@uhsuF*~QGcIE1FY={Zo-wN(!AQ}A3zfa!NF)`ndvJ+HRf?Z(~KN+^XM?ipWD?@}WZ;jJE83LdPH8+{xw?RZH^ zjN1B3SB#m7^0+3W_NVgVn|Q3-Jt`U6wJip@k2)U&vd`*Q&s@*cu9*}LjsbbgHRkh9 zzYRV`*jJCrY^e~yMG8_y5Yl8}vv>Pp@M&*DkUqj`R|cWf8P}~s;4zP}DnY*;%NmIR;9WZ0)imTBfqdtB%+Lt}}(E)L;l_7WA25-0Z-6xx5Q~%2R z&o?gKip!H4d}IPzWDMOI;@A}hd~vI|5~qPQZU6jSnFUY7M4IVsnU+iHSFZN7W$xvg-+pH5&5~AXmPwO%ro+KUD3Cb8>DcPR`Cv+@g0B<%r>sdHH4jGAZAj^t_I1ry$5hkh?Yo zQTU!|ygj$rt_GS>y5gS)n_zUHXiA_#3xc0bKn8XzlkiD8C4kuld(R_OzDCEJDX&+! zQNI<2-~9TyK{a3jPfFPBBYdwM^~VbIPxm1V6dC=B@*&=a5eIRTz5`esOw(Y?_&*Dp z8-;|fnn0$j>)r)D;H-{lTD{}9g`_@CMb>F)>i+37v7>?kxNFfU@V9=hUtp!1ugz=z zuJZy9k_s|#m(k#|%!&#CZShZytbvU7@2sj8LrIcy*S6I;Q=pEhYJrYuRtSO6!{6P0 zgn_KNpGl_!ThkBhuBmOt1mIQE)1ZPU$o=lmrPNY1JUE<#X~OS4qc&8j*nlEGCoA!5 zk|4em5bIC8@>jK(gp6SyJtHrDr60M%*|)63Tm?$yzu1sq_tdYymFOIGJv16&S1JRE zJz{bZH@wW$=Kb=fCY62jTl4iZ%+~}n@4n&Kj+~#B=Hcx!*As?`9VyX|n6#C}K0Sgo z=ucqBN(;H7>(1*~OJM593#l(H=SQ+#Q{?BYExwLy&1Mqo`&HLi3#4DPwlcCbWkrV# zoVT&}rLb1ot^e2^l}DLv;?Bf3ilLE3i$4@;PFuZi`z4k>DVQ}ra6Wf34mY>AKaIgL z1>Z(@&(pyoxBkJ`J^3jSD4c2p5tlkC6cKJe@4WmjF>9NHw9#`_bs(oB@wvq2KgHtn z_!KG1XW4}+w^%mX`}sQ;rGR5jg_}D6vfQURUDh02cOb*IIz&7A=1@lgO8DYGQw|2k z=*-5R{*}j=6{u}JeEI&54{0i$5M+G?#SJ6&gTa&!R#57xQ_l4J%e8()samZ7uWlBZ z7yDPh4f}Uyi#JxzQWs2?$GtwAf+Vuc(i5FqmT_$x{-cl)orq_(aegEL#eo@(#jQ5gK;+pwDWb%GFd z5(#BmQw>F!(XXA;N0`$e!H~+`7eV?t>L&brkX*NKZACCi;v5P7caoa(@R}*;085YQ zsuyISDXYAppr63m!z_HN;C*Y26CZAd7ucwHO)Z5%Pztj$bz^;OE(>k~B zd;5(+A@fVGX19A9PJo1M;BQRziGMWj~l5* z8`txjvd<=)6l)K^teow7p0Dt;*+v@}35m9~tvJBRy(l_MmqG0mhggAKmP5obvEB*n zlY88lIv(dJ-Q<{SNmS_iE*&n{jOhf&5{K2bRKq;3@6rt!Yv?t99iPzYG2bL^uFhZ z^i0F*mp5stN~_o#A1(A^$A6GL2JQWl;Yu>?z@i6X*ws?y&)$9K={M~ofv4L_6mZ7N zBoH=n=h!Oc4fjybpGmAZHU;1p03?uJ>WgE3ZUN#oXZ3X1rPG8S*jeY+g5C~)iYGF98dz`A!pd}dT}cG6uGi~q2o^fp%U33G z1qe|h#z17~h$RrJd(hDsEXqnPyro!o2a|QrJw$Wu--s?+H`>x%=7(u+d5XA>tEY_4 zulTj;p3XH=dk?GfqO<3hC{hW3>;Ny+0C0A|>(|%g`lVJ@mmbn;1G~B?IWc%ML&8jO z1%zG%j8ZmI2^9Mi<PAQzJ0* z4Sp&6!h25VCxbgVdQ;D*ZQJmtWFA0HT+hPN{tc2iTHk%W7#=k)w->=1!zT1C3?=H!^7^PzM!37rC^n+p)4mA8&$b*v#Gj=s z?x^e_^bb$-LMU?s)oT=}y$L)m|68pa`s&w6U7Mc){x;u?ec1tmU3Vs(2DQ&a5ayne zgQl%nZP2F(=$*}vE;G~r{B4mONjvvv%Lc;Str+xTdPK|L_WZq|eZXL!&i*Rioz+VV z$s_lv0+Us+F-xQ-73NqjID!Ht>*d9$H-gwJsSFK(HP?`)2y*M(Qj2vtWk^ODhx!t@AZ83lAC>jRk;u3{$Bv#Z zY93+hb+$6Ty`%{-7uia{-7MZr2!D9iBhO_oOp-e( z@G8W3)m|v9Q}eUoAhj!Z_rX)2;A71_-csQ~D0c;Xh^#ZHhTN4A!kY=yNwbV$)IAG; zW&)@qAP!fbmwH5qyV;O2Qa3eR)`f-9AqQR65rhj ziQ(_V=J77Paj)-$wSSQ;F^1JgTMYqDv07&$tWbYQ<|i9v`|pnK{^2anhEo*q>;4}*SV$bpv!-rNM)lEF*e7KO%~Y_uS$}9$S0{(3-POp{Gx4xAr?y4QNaXqz$$_4P#ewZJuvQ5JofHc8uM)#atb1XOysj@cCAEkpNRVokwuNcTW0O~ zA9y0aDCX-k(&oe%YYazx-`%>KW(U|#muwi=)ys|lj4Pb;k^2~Gh*~li*Xci1Uc&e7 z?Mo@~^&iyn-?PfbRDY^wHqHhV_GV`;e7NE$B*)(QidCs>_4-r!)+B9dn9~4q&^LfU z``jqY-peosiC|irVcg%>OttKJr;RI;XO1EM%#tyH9RNJsSCU~G~;!D=`aF6SQX~MyH z>Z&hTp`s?|b8(cSaXk~o!^6XueiFt%=WSo?xt{xOLQ1HrFJyhl7uW$c!vIc;1{{PH z9c40_@wSWNn=!eE zff*Lf_mHa;%McsD~m!`5gGJ{&qaCfLf1C;5(V-5ANiFGB!2ZqhOsLCxuW z$Vw!h7K`v}#fetEqCXdRL2M*fzz7d-$CPFjKSKk5LTm(GgQS*>bWY%7(tm zlRvtu2d;#B*idi#)btWK3-k2Qc`a&g>pRqc4QPh;b zBPBjkvdNneTifh})x6Cu>N@##ykAZ9CPObg?DL1`sq9KLMdhLEy?EL%%CN%1uVRF- zygDi$`eco2+5psJ9Ar6CygXyaK`VfN9@v1^e!dv2a9uX6+VDO?vVpo2DJOCK5N}d& z!)^G052w`9m53q#n$`6xbn07_)1AZI@9X?S27IdW(B06>MSi_zw@Y&A(pMA~WW_JS zrLoLq3)bb+6@yldzg#a5*5*#g6>ES|4qQ}FYeu8+n@J)7xi@-32-bG|Y6y46vCk)$ zzp_D7>I}$04N}sHB%b~66#2`b+rVx;!rSz^gZTu=rB^xaqm32EP{2wH$#eA)jImjD zvzkr1^e-c^)hbIf^<{Crbz%Qoz@Kypt(M(So*>Gy1;qo~%E-&<%c|GZl~7H4^^NHD ziPG*+$58dH1(&k=mJdVjD-Jm?#=ImM&Xqkz0ISVgaHpgn?MZu|tPtbSoDZLI*}WSv zy`1vTSHM6#DS~tACvn76Pl)fUccveb8er1DQ^|h|Geltsl24UzCU-q1k;*51_>r?# zT^}AW!vi})%&jlYNW)qr8P(NSiY>pimQiMk$1RU!=I?UD$lVEGcU_^I4U^;U&S_*6 z#-hb1dLJoGv{&_dagEL8OyYKgg`O9sbyj|f88k3h_gnGBOJT2o&RfKrBa}jP?;HX< zX6BvtPjrX!=lW}rmTHP64C(c(t{5X3n!!###sm#Jmepcr*f)8Hf@ANUn!Nlo3*z2S zSJ!m38VDaEH9`-iADXxq-eFH52$3wMs_xfSO|om}^?Q?Dpa_NR%lxPqcxL)HK39B} z#LNW`RS>5KbvMYtTw9+z<*DMT1$-${yZx6_!ZraMLTGNBY5%=(pU+q|8Iqm+@qK)a zUQ+(uLe$Y>i=k?WZR+n;dqRMCWuLZykAzEWKLv$$uBkuGHMzrQC!a=O z4(9ZN@iFoHhoxDEak;{}t99nrz?#GnRZQ@h7iW6a;_DTTOq&&axncdsYnL$jrd>{i9wDq96^%gdEC-hnEJJP2C7I#h`m=* ziqa>gjtp&hOV0^5O@<9J>jle&COZ7?joUj5W!g_4KLS9aFIY;uF+zeuh^&&|&UUsc zSucvB>0Bv`*fEay?wc}5qBbi&=GVg~~-u z<;{Ur`sb(P<=EQS=-_Bq>_2^NQmbA8HLjbIPWBOpEK#HF30qts2qBReF`{pdBYgo1)NkW6!lp?vwh-o?mN7A>NN~B;<^G9Ui%FJiX zc2tIfggMQ`pMzIa((pm5PZn|1T>_um3k8^vQCpS_h8ey0rA6iKru#!a&a)J_UYG~# zg~qP<_2%a0xL8dX_DtNBl&3^Hn*BI+Zmwt3{sjziI1liY^ugz14-^J{7fj|1r(xL2*^b8xOwKfrr5bKN)+>s=WW||z4mB(I@Zhj@ zh^ACu$&DUlmkM2MF~VR%aHuM#mpXiXxcJSLCNKW4Ui5!Hx{e*nLed=d+a@;Y8`m7W z)Kl%37we;)gUn?AId;{Ecr;Cx!+3Zo0lUb6mZo+a2xZYel>CiC`DUBL=+JvzKhCY7 z?lqoqK}4l1ULq`IbHD|6>xd>1{%<$TDLU5>HGDHNYOWAB5@D`Ra!L0ORHgL;NpORm zPctOP$-ay>W95t2t``movK7>J&z>&U+|BhxaetL9{dCfB-NE6}J{fJo3SB(vyPY-H z&IdNgwfJaW#?1?YN7h2biUc_^4K$0}xzij`kK=Yx_s2rnYQOFrcYP*>^}O8d_2=np zZPZKLLOsx{%WVhEQ~n&nMLOQB@VE+&ig3C+!h(9u@Y)0!>Bpk@8{**KfyXv#JOGC4 zKGF9P%tOmz8BpMcb&En>Xfg{~AybZU_rMF5Ol&=C2B4Jb6bnC$j%n_<#%0-pN<5F51Eh2=Z#E^VorPgv$wOv*i94N0o zTF73(hEg~{GU9B>!!Z4ELDW&o_eaTbk|q`48-9n}@}#ursDcA?GRd1%&VtZ{a>5`~ z8?4d9J-#la+%%_45b6rCFxPMfd#wzTB;HiTh);VG0eItcbpde#G)7WAdHl<+U)!p1 zpsW?Oi2v7v-E;VbEZpZDc(xgrpq84eKd^Q;ZtiGSPlqO8C7r^D0V0dO51BRjKurs! zo%QW`G2(yCS~wUz#+g_HBih68>)x&m%a%8+4{fFo%KYIS(;L!h^m3VXm z8<#HX)BFO1C0^Nsp) z7$)EAZ7VWpG4|)=K5wrV_@PFT90HN-HW#;X3Aevh$bx5y2&l~y6G}_oQ8H4YpP+pX z7MC?K(h=W1RYe;^w>|AOpm<49)H@EUTvjW6+LsZy&$l|T%FD>k7WF*L^_*~i`@Rbb z!HwIzuGR1KJ?UFg|D*zb>dO&@*@RD^!KH)QxVjkEyG#R}6hXuBs^T!EH9(B~m82R)v>LKEgl20jR3mSkIIbak+<2Tc zx(k)U2c&7=JHmq0ycpuRUR-{LeuOqef&3Jqv;G&@=0*{CjijBubUx_Wf&U}|@C!bM zgcWi8tsLx8P!hK-M_&Wz)ZlDi!bk?5XpooHNWNI$>y%HLUFu^=jLn^hYR)Yu5 z+z9k@=-x5hELUjMq6D=W1a3Ey>?ZTprOAO7&UE1!?<2oeRW~Uy?ha;78J|UCqcV~yLv{p69SFN&1)Vx_Q{%j0Dk1N$qW^?tf zX>-IN%L+wL`>Re}Pw0E2n3Tw9atBTlkmBs7_}HiAgPLh=y1VuSh*)*Hg~X)Qmh~9H zOP0a-`at}9@~ucfGn(~f>*;WuLC6;)E`lHZa+9PzQvq9ASjB^oqzLH z{t4>^%A*+B(*bziEwBx5cD?b7t~+OX`u?BA3c?NxoG~G{Uv6A$P}rgez>nVd%lMbu zr2>fBip~dveir*7&Pg_^x;D85{iqLlhv=Pcd6CKdLSuz+fpyS|Xhgc>inbW}_iV*a zaF;}w7L3_ZSsWEgagUM;xm_6F?Pt_im%W*BMscUl`HQ@G|P1c?Is;Vh_qRD7ls^%9hNUJY=d#?kaHYScC57``)G1 zOkYvQej2TsuxJZ>EeZ?b@N6CR6P^#`;33>G=1xUj9>&3*-WDMS5G^MfF0qqx*pU}! zG0%D+vd;-OI(-=L6zgWu*g#^)|Ju~Ww5trO8)HBTn8HKkvc@zd#K)2+xJ8hWW&P9s zluU3dYn24^tCQM=4&Fsr2F0E(Jb|u ziJ~$oHc@GY@9L5gxbivWefv=TV{Nqo3x1NH*pZ1I*qn%nUPB#5PxFK}@&`TG7Iem{S;jolU{5YsCqCH#ksc0#LZ? z2P6Pqg%89=sprb%>3Iy!8)iyvw&fJj6}5;?x%xnRx!I%RhH}Z0!u{^3U*f_rayQEL z;-o-aQrjt^aXM`@|Ew{)D|tM9BQoH+&?4QE7GX~O=je=4mkRkXOLf3`()hm*?EgCz ziYP!u7r>N%k7xdcrPYV>;eS_2fDVcLoAYvn;N5FOzI?#|vSH{B8r^HA<7lWL>XZIHTS{75YC*~!O zDNg`C_yr#c%Bv5d!D$wVkui?ZyE_MqMysq|!7brc~raPZ4-E`ut zLzT^FG-{}ejhinBRFilLSbZz;`0Hha`*H!NkQb8vMh?0cKK(fYx`iZ}L*uCN^rc(N zpibZRjy4jFf37E=ibnBQ1|v&~G8B26-m_9ZRAnlZ;f`!nXj{UC%z$~RB!>TntO$d3 z!sFcKaFbmu>)ft%yPNI9?X$F2*hU?zy&~_#!|X)lwz^|s0vORJ3--sXPA=8NbXl|J^PH&5&<{?e4(=s?HWiTS?q)4Xvm;EyW&(}5u1TJr7Y<3c{wY8^by zklwr~Tf`AIr1W*LM6ITyD`|8id31l^I&*E>vGMxt)wO2kK#NPA0c+d=Cgb9GDla%$ z)HCh4->k-c)Bm1-aqw7MVl-S5zUMGMeJM#sUABgHB^iAovt5ay9+f=tre!>xA>}z) zoC}Ul^GKj7Q)_Ph_2u^mWO0ltLu?HiNNd9b=otj4|Ii=lh)Jd(Lxw z|ATY?aJ^plb^mf-pU>yI-tYUm?$7(9IDdgp0AUUZ^BQtH5qAZ6+IFgp?4948e4w*- z(pq6xKiXF89>)zpICUW(?xvi-XZj=0So?G`huP^%oX>R)DGVj4x1;qRdtX`q0>VvU zV}ujT=t1R=9rbQJVRP3`X$B@JyIqWwGYhKqdH{PDJ_+pS=YnN*S5(Qd{WxAFM|PN+ z%swvv;)m9sl?l#^GE1%^HYJ~cWe&!?|IGAq5@b1ET*na5VVp2VgM^u1^*43g?{BLa z?m;02eWUD|Z|Hr8wF=A~r^%k+f$jT{0Cx{0Z!t?BHkqv*n|IA-A2E@U_!`4*g4j~J zDR-wUuOp@KJL+m%Uc}3S6h3o~-bwiulc`m(vowpoSCAH|44p@7;s^fS0 zmX3=4nH-Moeddx2=40w&amR6fl3c$5lrf+zxyMMB*U(J(ccEVFbEr^V))FZ8i6-+H zkNIEJMXI2D?G0~Yfcj(odx0PR*yU8Z$Z{M(xcKw)3kH}(tLo2=G&PN@wp5Vb?(D;c zHfy;9vz;&>C2LOU$=v(=X8CzHNt>o!R=7x9fM9!>nB1-!_`ZQ}wiLu$_FG zLpJ%JPSACF+I7E76lfc+ze*>er@kS4GSW_nFRWRcDw^QEwR9?@4JxCDxp}xaP1i^= zZT9+28fOO--amf@0=^)5&0|<+1m%41W_$-ClifI8Ml=6v$@n?GylVx$l-dOCFg-3l zKJYD@d3>O+s^m}K{bNMs!pu?J+dv(M!0#vie8TAyD9*TPrx?%v$k_C4&>&4~l#_A$ z7QZ?jFz_ph?kkmUm%q<9cC^W}Y1|Auz0`a+s{CcgmdXTAvQe0Gw{~NkBvbP=&$%$G z0hvXOMX6!h_0Jz)$%^SGP^)zGURq6A{FV#%-=2G?By@AUz0Ocr#)?ecJGd) z;xx+VWW|}Ssq(2TE$1+$>A|5)OU476a0FGA)9}iTy07I*kB8hi!%q{fFZzk4PD^#f zP+m->PD>R3M%W%^U$xY7ztI@-NLERgJwqz5*mB4>W_+1Z9cQwy`sYW@vI%bg2iIwg z;5@qxBUIJDW<;ye>_qi0y*4!*X4@@5x|WsX5teydl@rwO8GK)N#lLFQAbXc(K0E%P zj&IAenRQvDFkm9_8iI*Qh{yEC_1o-T$zq!np$EEu`>};%MjPiyHEVEh8S5W=A5?Sh z*bKhW!8{xj$;i8_;!YLo(&m><=ie|rXYljZ7tZe+)^ko?Pba+aE!|RurZ3-gljfoh z4jw;I;#fi>nLTs`rHImdudg0#{3KAtlojPk(#cmY&C7LtIJxJiejasOAsxm;(|lC~ z;%A@=r#R)pNe5fdHTfBwqN<4gLm-I(yZ~r^x`SOt$=C_(ZmSDC2-SSad?= z->SaUB|Ujf94FGMC;!+bDL=_lzW@t-cuoFAyZv=0DHw5a@dv1?=@4GmoO9~UWMR9s z-y9u`_wbf(+SE#R950{}bF>kU111H<-Ji9`pD_@O|H|bPV=Z{|=DF$^c60sL;@nPW zKfk#7THiZfoXa3unXCJfch&P_{NGMryWfl}rf6`@a)aSea%W%TvJ7jtwRSVnUOCwj6eTCI2$UjHOdZ5o13^MGt@t zPSAYx1i74`QhGMMQ-+08{0Y-vn{XG#f)-9uZ{I&fR%EYqLq>Q_;%KI-elzMX!>qjO z9dh+kh~N!}E`eu`_UY%6W8jxl>g z08&i9fVyiKqmj1h&Z`$U<-F*UZ`&MspxpSaUO3FW-W7JPm9j zh1le82HiafRP5%d;B|!*tr$MzFL5nC!#yW|-UkjGTgTqk7{IMet@9wmk>!r&YZcaf zh$__h!Hs&^3DO8agVsehjly~lL@I?V43_h_B*l%q#w6;P6p_yx<8 zmo)gMvaea>{*GwtdK4v{r*N66Brw9$b9uxthVU$5MJa_y`kf}QSXSWWjO`#p=c`6* zh1f$Juq-g`Q0l066RC_4vI~s;6>voOFy20ny>oS3qRm3_WOS;$=l9)>BF7o>9u#=s zG8*1jTM{TNvU^jL_!+>+g2KK5xnqv)@g|xHyhWt&#Lm>e*V3xXlwTy#O9nphlp=3) zY}~J1!7%x!CaRvs3IUgMWNjPqb{kHKoOJt2twF;F`MV~why|AoGh4^zOD(m&?|NE$ zFnT+m8})Vby2t(S8e|GXx4LyOAZjMS1LkVS^{>>UQ4AkVrpOi#~kJYh{_+@6@;77FBFG3bh`v^~pU5UEm?#E9q!!;sV z$PyM-=Ob3ZJfpe?q@5^_QOA%6%E*d*(@o_ux!$FSiM$BWEzFD9L&$Udp@S#h92e41 z??mG~s4KbRTFi@LA>e!-oz!~EHS{9=0=a6~84o?RHd0EWLNM-riQmCi#l!S^Q0wG4 zKhNH0o+IL&i6z$bNePr^82k)$-BW67tAjVa@7E;9njb-#yR#umScJO;f!`1+zGtMI zWv|xVW_uSmJS00ugf?bV%AL)g2 z;TGOM6KUY$!XtC-2iy+0NRaB#CA%G`j0yoV;+-1%D@*$DUKN&E{b<5*z1s7SPE;!dk-`ndXh+v-~8)p_LqC}s|QJ$=BUf( zvq<;6CF&7w-+(VcClxS6qq(O0TTS9=k$jsR7tf4qcGA7#JONy~53M*LX$=D1DO9^q zrCxz~R~BJstV=iCguHA%X!s=L_+X0aa06G6n3kH3{>|m>-!Q~M%KnrV0-OREhpb0E z+6-ll6x)t{tYMoH{hZrWf`LEl4SFRHz}z0B6GT` zF6_f0p}7?Arz&LWa_QYGutk}-kK}fGS^Y%A+-kj?U=cEI>|UFVhKE1b1@@)3ns#0F z`nV_^VL<*PZC}5~de7GUF?S9|tO-#Y$WeKFO_{yYVyS7Oz!X(8u;?V6=Se9#mjkEf zn%s{;M5rrpk?jY^>r2wNBW4jn+E=xvqXP+%p4$|tHkAF5h>fAWy(`pZeVU2L$Pq{f zIxA4D`j>;Vx?pWu17g}o`G@m@4f9jFBqed7CZ(aB3JB_V_i@Lp2T>~?wNK0QHwX=k z`Q^ec*Fs#&1&K`Ur>Q~ScFSab&38{5A~*;9m!g|Eu>SB>KT;B7{kk)9P4-frz3I3&b$;PoW)=?m0Qqc8Rxa@ z?8wlH(^SRi=@cugLjMKn&=Px(9U>*5BaLF1NVX0fT?q_9L8SAQ+FB>38AZg$#(b#8 zp9xb!pd+G+nJqbs=`;NiH7N+tWsrwY2Y`b~t;HY==Z4)YglUKtrV>OQu3Loo1k=OS zLfp6OKXk{FBd_V+GTRZTrREP{*NfaMhM>3O>utJ(UEfMhOULOPgso%xQo)Qt>T+0Mh{9PZ8%O~N%B zo-awUS#QLIB>BHnGQ_kkLIVQn8*O1H=dliDw0^~w`JEEG;G2|4bGk>w@7uXzw4GZGt^ql@0(I;wW!d26MeU%?v#R)TCqd%NJXu^poy}g_ zmoVD-m`!13yySX?#bnF<6^9Q-O4y_~oOqV-UCKt$Gr=XFxz z6ZA||*bmT_MkO3|i7Nh5sQOMkvvtu7*9)}{V>iZbu=vMH^_$CQNA0&Cmz4Hk1*!rZ zwbd#HQ^z(*xv;~18PTY%&+1)-iKBgA$USxGp7!dsDF92j$Lvs%`RG^*WTkjh&mH!w z@>4Ou&BemQg~`KN9MMFt8w=6SPI)j z(CSP&Z%L?!R9Q*1mAn`MA3Jifcqda#7QFth!T{=<*W8BlS#?_T)c6&cZ#`YuAy=0( zm8yoTex_)G^{6^uMIDHI0d%huuY#4j_ z;gT89sv(y?Q4-vDUu}(&ZLrs45K2A$5m((GiJdjF3*zm0(_Q-wV4Czfc(>mxEfkMq+=Go z)&~1kWC$mf=#^Y-P%i5*$?}*WBNi8G*TU zI62S_%i8YxKpXr)&D@aza9YobrfZg`eWkuxE7VmQjioIL&uHMjn%V6yUKvfgiu|{O9iQQ?GHf-D0uYKWMoUFE&%+&Ql%oX zZTK2xdj|-&l%XwA&qB=iA^fPc)gqKKGfK|aCD(M&ITLKRJE5Qp0ny6KL%ayUx&?&A zrD;cuJ;`LLsRGpN==?iMO;SWU#*&VI?knYfH|XD;)%RSbBL3sS41e?v|q z)deG|U{%X~bQBs@{b|@u8`gI4la*JeirOuiQp=#G0V(<1<1de*LI3SLl9e2VnE&lN n60QGhzoRkZA9lH58cpZ0;(2x;?$JBM#JEh2Zr!Lf@O=6|_jZf_ literal 63932 zcmYhi2T)Vb_dX1wpj7D)I;bEZy$NFIO{yZGAV`NGRYZD_-a-*+(mMjuq)CgkfPf&q zDkUJjgc=f(`-ac=_n&$1+}YW3%5$DQdv|j8CdN=-lZqTfPDDgRrLCp*l!)jCo`{H~ z>Lv-HN4U;ZiO?W2)HPNoG8_a>5WnT}tM;d-^^>IIR9mO7?kF3p!&A z|1SF|;@dev=F<>PTGn)OZiOKH{X2pnPv{IRJ0TDvC4E)@-z_C;^1sU1%*y2@_NxBz z|Ax@$3xZbc$1iayl>{TwvL>jblkNTEnB*@6vDlQW(mQ`=Xa9&Gv$2a>-PqH!gZB;3 z#3p~SfG$)Hqt-X~ZBw=g{api7T%uF!TL#rx4b|GcvaxZq2yar?Tgu$A8i*qa%@2twq{;F&d(Fw z#c*T72PK|9U;a&GD*3_nj>2t*8n$~iqy`^;+HrlMfSaq;UmTgkKAWA5oq6xJP&hQV zkzAuSH}}27sx5x@DH`WSM0EODTTR*6cYZfVp?X4zK}pq?_=c1cZ}_qi5u-nYlwrq> zNA@>vj@1DiVgMU<1Wg|h>Y5`-;{752ZIwdGO=_5>l!mU?keJ zcP)8|s=uIbggsB$pG1l{HA(GGQr5}XvfQV+2&Ac`7mGis*k>D-2Xosqgic?d9rU%) zV1J?l|GOVGe;Eve*rV7LyaK6@G})JW--hr`kUvD*`$WiJ#;wZj&Y&JLXz<#Eyewe& zSJc;*H0!}GGM9{eI}l7NBN$UgbVK8AA=YU%%wKtRN+_YnjU!JQ%@zCVHiXHhTNpU#SV&a9~2evKucpZ2+C$;tqnB_Yf)F=6z+YE(fz%l?XV9HU9D1$T}- zgi>?A#3Q@Ww!cO-B6&|m69sxro~cCs&O4HiJql*Hfbu68FG`8fU#0k=<;|D#sNQqn zobU7Z^ej1Q*RwVBJIW}}%m|Uyl2=5Ea@yf0Twmn}CukFTD!z9hhoEdKQDcKD75Sts z3A53Is{K6n#XCmqQB;OMQ91^|idZ0{d~6~SpV5c#$B16*2YsGq3XJSE(cV1vS}YZD z1$QioEW|!VSM&sw%_qqb_eCbS*|q$cn~YlJwsO>Ef(bqIW?@KE zqgGly>vECeTYkq&L>k;VT09jA44U6zr2W<p< zA}`8{piz;_(eI~MN+^0)w4f!M7|1>z*$N5@Mb?4@<*FIrxCyInCr8@Q!@wIXKXmAx zcs3j-$wkiJd?zJGEo5udzcUJCNLRn37tV>Iw!pH|oF z7or5#B^EQ~BFFZ5O_IIj@_sdeUvU0%s9Tg!h(=9RWoT_9>#1XUqD>*Hoh&e9)w?Q4 zg3yq=6t=BSD}uH)Nl=A6;oOIK%};8J&>^0K3$|pvqk!^ITby`uh-wyTE_V+pW ziOA&?@6bINR_*hA$j-|8j7@*S84yW(aI>Fhl!@Imcjo)WjQxNaLr;>34WoEez_){g zgMH#yGrdP&Xuk0E^7JG_kQF;z>`|ODE4~pZD~`C+FJ=hdTYNsr6^GK73713zN!LAF zwYci2V^kxHhUa{{(OlhKo&(<)`(0qb_ERY<4RT~)8o~O<9)%FP>4YKOr(B&0Vw|`m zPrC&}(<1tPyeGR9o0kOw(2)gNDc=j6*(QhcylN4AsU7Hlev8{6i7(v7Gf0brE{ZE5 zKClAz1qsj#Jxoyj;40_lb7S{OrET4(0s^L<_p}u^6)zb(N#yVtu0li^{BPQ?kAjp%QF3a1Z6cFrzey3!OvtSuluj1`HoD&J5Gr1imboXS1^p0s% zA|It@1#Cpq7Sn#(3?NL)c^Mc^H>u5D#ZYk1TDC=o<9m@$Q(>jx~*vXX&! zbm|0Xd)mbwsFD7=M^t7QTj-y`Arci?w5;I-Q_uyzu5d|Hzhp&$&Q}1BZs^B2x5Zks z;$uVlunw^YPx+bLMaD^#C@feXL`HKGyeX@fPK+sn64Km!UD)}H{zO10siBHW6`E+vGSNOD%2*zHmPWPtFkGd$HWKF?${lh1u`AJ&Ja_1M!x?82A7} z<(|v&zAzdHdWqWxeO}-srP?R=I8E2?WiNyv{!iVYUGCsdEdP<4aJo;?~x z;-D!5D)n;DB-<)T`{Rt0JPzD%-O1rYvpZk3FxC?)Ij@760v&>LJ2%1BdOtCj69SKT z$Q6rKr@im2Y+}z3BG_jBz_y)?-5aKO+3-e4Guvm#Qw$Mxa3w$BCrKx+BdQxa+C9E; zm&nU7NWekMI%>#zMeEP(Gud45%$QTOMzw||^`xBBkldtim|%PGzZJOGQH|SZQ+K!=ZJOV^?w=AFAbp)Q7L+O>a?6g7`*QEX3dd$@9)Vn$fgLr|E9UQ&AV%Mu zr6dHO$Yf_(*A4Uvblm1oOO2x0;@PAp8mVvh6^BIMxl^aQF3^+Q##3Zuf?S>M>LUJ5 zJN5fSbnO7w5J{MUjBL;W)j^zsY)_w|s4j)niKM@wxd*c*#=$<({>* zV#LyaT`)9Vn~>+`yAHm>yyA-#Y2Dr}zv4J8FIkE1UpGGyC?uO(@$!`;chhnSL=}GN za;pXPI%sL=WP#wJAhO=IN#8`N?%n=wcynJDWt@6;tQld^6$`Wsjs9sn;i+l)(a_yk z@X7y;;Ul_-0_@+}`upDx!wRJn#|Xo}s<*0>T0db| z8A<;fiHibQ;@clI@zps<>eGqq#yt)De)`b*l_eg1-ep{0{p7adFm+l_x6yWFGXext zg9W`)oji0}gUFez?e%~m?D2lE^A!B?ij}*XuX%O`&x5)M-U%ChKkYcH@b+i_)*>9Y zbG`1DYVt<4trQt`vMNJ%ouvv#(1#vSznqjo2vWN=ObptAxe zNMtGRu}Zesv{Q!#@*ISc@HJ?Q(BtCe!1XHDymnUrh`ftlzjGzuBzgDBNVNE?HC z9adiDJE9YT)dnu+5}W(Ju+B5Iu~bBuUfPFR9+6H^PxXMHf}JM1G^wiHMjk!x8d6{C z?n08-4wl^0!^Zs6nxx(SGw~haqDV^0h_}_bjA>2HQs;OUUrkoOOCjX)O*51RV2Xbuu@k>AsJjUWk-0@AV>8Yjm@pdy5I15`7E1z$9F&QkZ~K6a(n zP&d#1ykb-QvYnK>r(|Y7>Sw`vp$5RBaAzojwFG!%4Gl8;dpW@cs)biO_YK*B0A5UzZ z9em@eK{=Lt{=QZ85~;#f1k5rAh_xOMgeEukX|m}#WU$ahS&A;TnUE~Mq4KLWonvhS z=~}|lT=G(-J7Ym)Ig(z|)h9{#AZ%ik%{MM^hcP?Cd7V>@=^ z-w%zTJKBu$GM(YL1CM0WkzhmQ>+72xh@8I@@bf;;Gh~-j=HzWjH-3j&mQj#25ouo+ zCtxJp#&o`uURk%7Q@5FH0Q}q}B!~v=FQgsV11I3~9_vx}eSCe=wXbUSO!xtc{9eK9 ze5t0hc1br-yjvyfEKnHfNOw*wu3)ZM)rkEIS={nJKi{)52)4D#CgpR9J5|%oTBV{? z>$>d}SmIO+xtw1znB=~TwmvEX%#c=uz=}7k5qyenfaeK;Uj+tp`Q$H~-Jz7~f8zag z)w(=p>7)b2wts5HXVA(&x;O<{t`(cXRKVg zr~a29yIq^o`zm1tZ!K%oiy`elTa6lVMTjn~32WGSBW}iP0ZO2% zb2e;jp;<_pC~`#B2uV|^>=uY=_~|u#eGqLmwSxI6Naw5S z*Mp7tklCP}ycuu@qj_HRNJ6jTKqs|rg4!Z2k=*O@N%W@*6r#K!J$bzdh1^6reVPI* zplv%(QuW#G*nQPu@o%?lfaANTc|jaU$3=@9t1fc1#EXa8mDZf`rEZj@4e@3`7RE|1 zo2DryES@Blw1tRG)&XBJnh53FyV)p`3aI=U{PFq4J98?3VSja^QuRD|=y zt^j0oN|5{zwVR9Lg-ihtO#qsAxNoYoCuR(JaUUdkOCmjc$_qBNhc3%7V5^tFfZSos zAIZ-5xbrXgx936In3*WvH>XflqUHDlA?d$0>9j^K0Pm%;$LG#hAz4}v$!+BCSY;OM z@rmo(R$SPbQ-gkdvga~=TKr57aJrMng>{51 zQ+qEbtwe%E8$k6oI0Ce1h>PaVB!bj*{M)l?0BL>-O`d{(r+mT{)2RkoWG0fcJ<+U0 z;X9u8wD8#11mfTY3S7gDCIsB90SF)nzpw+S7~z)YO^_8tKUj@EfWEMdn*cq}aT7T- z{}XzModN2Cwt@YJ#33YFFn1lQ8((<7(m=;!igpMg6&QZ>9O;??6yrb`Eh#sZ>mqgK zJOT9$1njpd@3I2t7hLz>02Gi@S)1!b)EAO^f4HTKOTBP>NNyG#iIEEekBJyEo~}u; z-%>WG(EUXrJND~peu&Bq@HSTiLmUV}5rBg#A(RC^*=HXgoI*j65V6|wf_~ac!0`nR zu5e6z1tQIJ61*v9B27L6NSXld1mYeFBj5dJBLzIM6$yGMJ1J_8gZ5&`x(stsfGIFq zKzf+vDt*VO0iXBvYH|t;b3LiIxxB-(L4&X!30asS!0jt2k$@q4Wp7UPeT8%y>_oE8 zy1{Ofk5?Arkxm$wu$hS7hDKw^KGfMFZV>>Gnh$N(zR-}mQuVI5QsuB$g%y1P4N?|H zoziqiIkwy2xop^9-HAIxYM@zCnNRA(G`>=Z0@3NWyeeK1V@4@BtY+cCaC5G%ou znV_Ud+fx9CLdOyPm0&gC9b+g)Xg@7Nqei*E0{pG`r3?%-Ha;xPE_-4Sb1-V#XTuwk zerbmA%)W%EQCB03N)Xmrpsq=<#J()2Lty&FQYa?xPTk5mVktOxn3p*F&_4N+uJ@6Q zutp(kJZM5snzYZ2(*MJi0xOSQ`^=6KPBYH8&kpx36Eh)7oSlS6jyf~<2{{z9wt%KD zz*;*%%=u|zJXYf-t0{cm3V^RlQ&?}hnE$&bXWg`={HfOkQAnHtLQw8US_0NrcG;Be z+9`IRwDkY}%xVDwU2zhc@xQ2Jy?V;K>Q^D`){w(fU=T@Ii$Q$x@s&${^QM5dZhRx_ zlZ=%#PZhVzgqR2?($09w@2Bn~IGWv40K`hxb;WLTH6HFHnI_glds6B}n+(!ZWVtJ? ze_vYv<&@YS7le>^`?q+J^{1!cxEMTy`GMv&x$wmdIrM8?NcL~YY-uw4^{2ocLA>0O|Yd&8e<8u_U{S+wjro*DUi&=!m{S&fuin%PI|@Es{zgopYKH5Fd}7MNSj=9WMG3tKc7WbYLab4^LzV+{#}a_KVAix!0LEUsFKl6baDW z<#>DWCvFCP*Ih2;uhj-+10v53b}$Aqs2t1DzKla?t5_k|o1r0H{@_gVAF+~~`LgZ} zZfAcXEw>vqSof@?^y#-j(6F<_mUpt*O`T^ZBbt7+LG8Fd+c4VdbwA0$$}zH(M(CKF zbc@rYA;1d>waBsF?!DPf;qk7Q=C{=;=Ndd~tXXB1VCmXp5P(75LxFogY;Gp?5_PX< z_^Tf9eb467bYU3Bt0V6$7onil_)m1ed|Bek^b8xGy1Q@F-;tEX>YHJXIZ0kTZ7@m{ z#81o*gW`PS&;|)CNU35_2lX*Jw8Gp9_C0Cimp~%0RCVQzL>~lAJOk{(L}OF89^OXX zodvO?oOG@<73$LEVPIfYb*C<{lba1Vm;tsZUUdL#7h<=@KB6YsjU#Qhn~ zVD%qn`M;^^H)t$tUjp|)K%wWL*f@G7aeQ^D(%*Kzv;cBmD^&(5v3q{PX#5QFxUuU) zxfpedL-WYJOKD|-j2CO8bS8jq`aS78fURHUs+#vi zRS(e#_?2c@Ma^*}5%}Do)Pto@h|2<Kda*`4Ztr3vHngzJ zu(x6Dh#^-1TQpsD+m9xfQiCV%?jpGG$vnX<+ljO#1Y0vL`m&gncKvsJ{%7QmT;3~t zR2YzGDeirdIBq4(w5*atbb)u^HwVSeq1mg-u8e{kYm*M)h6x1tqMI&{7SN+o_!Q!M zIKTeXun26G%-ZE!6}d+76_vC0`_+lhj^*m!X3@r>{|82O8Om@QFuD7g^B`bCx!B#f zJ5(tO5+@A*we`#&)*ohcH6a(umPq>sz(~5{7PM)`^2E#akVAWpRxfF=FLMQ(*fgiF zvK83$33qk{_VzYtbOGQ49^#=nHn71;rTVBB?p{du+6gwvLE_D|--H)eKHl^WEE^l$ zm*bDJZt=zwqPJKsMBTld>xV9JGZ8hAGuPi7q-I7iRgPu9p*7T_pnXg*E#fieOS=bk zN^ZOHjP?Ko{s0Utcu8dFch|7WdIULCx}Jv6Q76 z)}5_aOMG>R3DPu|$#ZlC_5TLQX5OG>Sk;@9YI{W-(AQe$enevbT@90ey3&h+xS2$* z(Ti?y)~nUHiJ>3xdwrC?MoGZj&LH629)Cvj)s^WVasJWMc(l!oyG;MRRY4{FKry@q znD8_!QPR4iPU)bEV_~nfX-qUol&v81_i0e0DPPBBSlzUf(%%jO#otv8k>+SVT_n`; zngm`lF1+`6I49w_bkBZIKA83$q4*ong5qaRYk?RP* zT>QmM)Ox2!y2>1)rB&mSCY!QqtmRQdlI zYu~5(Di}?w)^q$~qP{ClHmOvCf#_O=(CFW58$)d)#Mfl-p?_}I6E+qi`GJ=7b-E`J z<5k}s-;EOs_+Un-TjbAbw8APyUVz;1=c6i2el_E=te-rmNl(j2vRgE=-MdvtB901N zq!`78N>LdQEw^XScB{}gLtWQI^{($)d8j6YT<-sQ^HTDre*EcSj{Tv8xu6Foy$Dt2 z;=!o#9JZl|L(XiPSN5F??&A3Gq2r5YmWKQ1!IIlXH=@67*j^6fr91DJMb_fN_CVVK8!SJ*7x(>YdV*cA?+Yb&G-qxAe}j>ny>^1*iv_X?}+<_%gp6aN7We zNXoGwm+POsVI*qEaIeSwdrNvx-f!NWi=Ks2;gedwFCLV=x|tE7nX-9}K^hn5)P6|i z=G6wC`UaJj&OJT>>wnV7dv8p0?QToxoz@N8m^r9LhB-H>DdJ^CIZAsR|IWnsXm^Rl zRgjx@JKid##AxwEG#}M1+j1WZZsB3ldHnKGf90DJN3X$ppls52WCAKX#*%fOkgweg z2tM0pUz-Ix;T2M9Whz|4pAS3#dT}|6{|dpp&o<{~6^^y67Z-8Ez`vmCyYv>oVUJy1 zwszH0lT=3kpRu5&*v%d~3bn_pXW(0EXGae_YH%rl0e1tCUP<-FmBX_)|K1ybjmF%i z`?dPx^jrXZNpeBl;k*674P&Z}tdMCDdw3C_G4YLmCyws&`suFKt*cz5d}}jh-R(9Kug@TYkvL*{;i(2->+SOPDbPRNW@mh|mKBoh_zF(2TkC_q z=HrA4t|kV=nu96}NQ(7!O)?J-UNCh5oPcSu9()e5wWF5r0A!M}5%?Ch3FXAEFzShX zo~u7l`7i<30hu;-{i+4fem0JrTln_6JVvNJ^0-Pzh_mq=QfKNQiU2lwJ6ns z{a<7QzwpgX$kILNja~uOZkNUEc`>`bU!qLWUk7B(P9jRXNv%FnL*F!=I z0d{;UTEf7n(@8)3`xeL@v>xhgWw!{~`b`M#{czfp?D7uaeu$X{jN8;^r#sN<)Y zlv==X8vU#oN*a_U5}{u*)C_#f@t!&rq(Ck~!pzZ1Po^Uk`JdVXsf^fg9yeg1_pEl} zCiGbJ#R|OB*p6UEyyupD=k)%Q3w5 zUr}%Fa0civ<%ld4PZtJiq4LDF-DDhhjNI=zC}mxK5SRd{uD~|o*jf#q-@=+2AV*X1 z3YQSHj}WN`rwzdNuLE*~%4vFL|9p@nmXsDHW{GeM~$5*wvpDr7%J;V>W zEyx`c95;*lzWGW%HlGQz=yY`_*m(z#2b)d&^qj4b#Kt2{HvHY0G-^LH<0BnuQIG)ChNz~&fNL|=l`;M#1Y1@eJ%H7{W=hXPB4x)u?FHYvf zRm~Tsh+pq=^}dgO_Fu3*VOeBYQ+?z^1E6EBzsfW!pZ6uYYKC(28Y*O-s2*sOE8wS? zgWeDdpOdhtgMz;IFPvr{Zt1iQ;a&JeyZ?p?BlJe9hlKjbSZX@vyiJy|xHw4rER~zc zuGK@>hCJ@QuVmv6*^N4q;zUvSd+s|{X9u+*B6dLI80N>RA_jqXkxkFBF>+gv0b&-dv9-5^l{T6(Oh9@0-A$Z^o(`eD~5>R+}{ z(w$_;)~^~Z^acp?lR=b}*(0Vd_PyLGq% z&fv~EQEK&Y4fLO5=Z=XGC7(j@W8^VG4twJoy4(%WSzq(p&A`gMY63`U6EIIQ@Ksu9 za~PA&bpXoSci_`OBnUUPY5AFs; zN^RwT=5NbIcHF3k%7xY9W|(CD9D|Rb3)i;7jb`4^?X8wTJz>mkU3&9?AMH1QFTltM z3vEHX&Bp(_XRVRKJH9rI*KA?>F#iKMpm?3|wvd=2BQGw)%d8 zdbAOc!oo~&;qu7z48T%}%z>kJt-hgpbQVvP6=554xWugRpYMwU>x-hCT;Fhi&}d8+ zhDAo>kQ|;auj`_8#2)J`l-ar*(qn79u-dJ8?60!%#ov+MV_WWtud7YV22if`{Ec|Nb!HdQMq*>cN z8$jsnC;6lYNBf-%22dD(c6xB1yaUlNMQh1bJ}NjFKj7L!oz;9q9B1QK-Z8xrj>0DYN-2UQ#}v=cj<;jX8$Z-(Y=Bp< zOG_8bQ^`2uNU%_%KMrbnZLhrNDqnmctdaj`nQd5);>l2ktyDiN1s`VwryHQ-{AhG* zsSGUBA9S-#V3zO_;BbT8eHsy%dZ&sCBUP=^i%(Q0>*$vC6V1O1IgihIJBSye3dK!U zDEIC{UH%kagHxL*2Ugie-mv|Qq*mgYfY%}@{w~Y3i{g^->Tf$?N>eMCg&@dDyG zU-(65&--j*wi1*{8C2had_m$NZF`p6C3J`vlNDaiZY%)2!3YbNjZy3Vi%^waXTn7t z9pK-7Jr?_-MiUI`VIUHfjE+v&f)joLxP>YB+6=r%svYHcL$5On7Xq?|o^`h!)l?(Q zbMbdwA-?~L9b@{Q@kn8k}k-ShE;xD||kzdI2{? z7!0Nafgzof<^H*ex+16){lkyaVmNq}=N@P=w9A_APW)Sg&bNE>UyblnQ!Tt(OEyts zNJkU0zX*x@avTMC=AvWn!#2aOm+z@(>~cok^wjzduW`xItiu%mCg$Kwnr#XPs;tJJ zKgJaQ&uX@%#k2>i&o5hXoqQdPj{J{U0_M3FpYmRAK`PGc=EbRxN5b6o%O)}b%Cj8f zwiJeR_*_I8<*ONvZpHp5oL}4wz2=J1#~T5xkt>v-5mRfJK?rRS<--iT)pScRm0Op{ z(la=}!oAX4z#D97Uq4lcDZ!CI#V1kO_I#GHB$4DeA*;0>8H)yDu6@@TBNWJJe}oEs^v6ZnTk0e8`6_cqHPTi^r3HrodLDTT1YE z+nG;{kJddN=cy(c8Y5$ip%9oNw~q2t#E%~*i6B#2BV-1C3>0lgMIj+ZIPgmicVVA^ z20i`_+NRZ>{{5KH#i%wZR|;()<$clffl`<7LC4({Q2$Bdv{GjsX(@EFB{rJS1bA&7 zx~e3vEy_YPuAPiq?Cfe~n0imo=b$$3Vyvjb^lMzeM4dzyt!#3!Ao34-d&YjplK3U3I`pm@w&+G4(&IPf;M8grI6#Kae~;_atVOHke`16Gne`DZ)v(yJk{C%cWu{4A?Q17=aNansFp0W5s$gA9%j*sO2T!`v~)lZap2B8IJb9I8t`3XMtbvv2GwL ziI{kY+RGP_zSnozELB=>5H{u=vluWn=rDLnjyxhm~(p9=X11#aG@*k(bF<;P%ix} zZ%l~j3r}HnvO(c>!LRa#)lZSpkl|w76U6sJ0i?w|{3SkdU&2{kd8q#R%)6`pxx>4J ze!!bquU7o;R<1TSJ^uKcAL4rhu*KT?x`?-soWhx4-bZFsF6#_zsojOBou10jB8W*g z_#t}S072QWUl=W?yyz0r*Y!1DW=*e+H9>#MS!Fps+B~yrlG=>hx*ywqeNAO;_ zLZ_iZ7NE-d)EO5QAdr~9&RHPzk9&KHS-|!Es-SLZXjM>eN+Z~PC9s(}w>BnC!;Qfu zpNAh-gVRhwK_6C`as_td|2g2<6fR}=S!r5uGi$~}@TY4H0=1b7Z10knCS1KT2PS4{ zpssskmgk}GeKyvi!0W^^nsi|8?|f9s`yr@a9G&ghuc(XFHB=)2-_3z1RJ>$Bq*G0y z1*c6?SZwsgX~g;-INgl-6%)geb1Oo3rLHH2MO%&DnO(0GrFe#2>@fR5N_HS-ndpYU z^g8(AvH14ikLJhl8*HCmBAbgOv50Y+rU}L=k3o}Z-3WK?tx+de$Gv=k=QF-B6To5m za-v+a472&tvN$^TXU5(>y8Ag-MZlc60FuWB9!!xZrl>-9?ouQLz%TuitBka^-x^;YyAr!eVk`^{@Iol2)5MJfm^P4VIaOdRNgSPjLEzCq}6ksG~(rOV-f#|tjrG!b~Ah->GX$~Esf$e7vg zGO$;FPKa=TYV{82y2p6tPAMcym4Jw_M~S{tViL}aus8$%d^w+V?I{BI zgeie)O9vy*m_lz54*bIpnKK)jV%0}7$e4Gz>*zO;$PhnfB^q=mIspY z$PG4u7M1vIxnoTY*iu8s-3BV=V$$Ayi_izvE2D8|G(m}^^tgDG5bkE4seXI)zUx0_ zV!;{|T^ZD{6jdE~BZ0@KqCBImDD#eGJ&p?hIZn=ZHzA&bcT@&zOn>h__RXx`9x$7* z5@FxB!|_uDH!@N7(AZ)#^HL#FegvCth=i7O?77!!I%kvir)UMJ>x4QNydA@A8p>;SnfS7cc^*&z1vo? z`d_y7jXf*w;6>`|cEIhTdnG(ey`vv)YWQQcTQG8i>Zk2HrjKDj&e@qgW5vvV|5?pE zYLV2wXO^>Rmm|?GEJ| zPIKClanRObwlwvL2Ai`3v40zL@LK;HLWe}x)D??vBr0WZh<%(W?6s4UFb;WH3cZlR z%PuS^+H%Fe)pO*TM;bWeh)wuFmAgX-rY5KkpUS#Ls-=6Ks`Gq0^i4uR*xoSqU zMr@L62CuA-k#5d5{n1~{yzuL(HyakV1HAiZ?6J)(6Wx6pH&)e$lp{1>8;X36W*u{e ze8!hdpqJjb=dmmx&fpGJ6k0RX0pw7PmP={L)nNq5(m@i=D&t)AuT8L8gtX<+NuKrZ zIFX!6gp=K)%WsD-*+h(W7Nd+Ye{-1WDZCpL-9=RIyt{-$ zk8oO1nC!ssVyL!M@bTHSJ&*F*FS2@on_AxG%<2qI8%8k?4_g-?e(Kb&v&Dr!@mF-_ z46S#(vn*rvxMZ^R+6P35`+GtlP0%h1Zr8MKM8yk>dLRfrF_SM+OT&By&$gd^^cTN` z{=lxBb`LjHiehVQHlKN?7f35jDpU`=I8i0Rg7=mRx*X4zG%SzymU^aDuND6$gaT#> zOdL@rHzre$ySJd%+{$L`(@p(#Zj{xh17}-Pkh=gM_56*mYj5%n6|e_52E+ndaFuZM zhis+)bJW!QZJ;al#_<3?r-%_gKhz8rM=#=Io_FHfb_xH;>K=D$r`xh(WkCp8b&iXq zhKTqy`1(h#&5l$iOoOPf-qy40Zvj!-F?h$XEyVE!anR{=uo?2l;#=fF;6O4t6qt8Rvl#;z2~KInDOv}jlXRg|Ix zi=nn7@9pIzF?t_IW}8_Rs?FmiS+r zyo=v)$G^Bf&H@?KMF~TekJ?K9Zdu9y_h2D2rM~V{My5h?Xem_>bkf_1{~P=4^%K9x zT3_Vf_CxxN@cPS?8wYIBzU9!!95Lf!kzeHc*z!*6E}n*a(srExKo^l?)*-g*kG0B? zUU+$ei~Z|6P5E$b7GRPE599d}%ZxY4TSzj71A1@Do$3SQ&X-Ml4<7pF1zFSN6U~7| z>Kl5OpQH!BlKdd9@S@r1M7_KfF_eeb?8p#rU$r69I_bomvF+r*+uIpQc2y ze=dvbscr^BO8@r#o(n$0abMadkZhb8C~F6N!qIfU!D`;PBO!NpahhJU0r6j``5g}+ zfZ-2(+~_4wc4#_Os0KA&25saQD@-G2jfS0bL@*?Rk{npraV>}28XC(yqZ%)LC`=^du~xvVBN z0|#qvpxf@;G2AjaV%+@aC+{n!cWOVd~1 zCx^epE_)FZ2D|V*1*RR9AH8qCZN98&@?ocOiCWB?1DW)oRA<2*JUN_pz_DewfPCSE zUFBvxAF}4K81y zeml?fVOjQH*ZCb;Tv4%eP_73{c3QHzfpvv&in8#dcWY|js4QDxuyx|`FI0d3-BglYa*@!olx*$kbWV5 zw>Zih@g%K)4a&(;7kiT3^^@bDZRKSL4x7;YTD-I@V#*eR`UP_lE=lmS%Tg2wU>oiD zjCOe=!5odHo-Pf&c(W2H=%HEvPbRT*YHUs7pUK9FXez>e>F@ZCqh=F)9*^<~TRnqz zpB|L|=hu2M&TppZe2V8s&+gJt9n^Q8leHfgf0{$^T!JqFJgVx>@@~#Mc3r2(#(Y#E|I##2~Fn-=$v!n z_eklt*3bI;l!jCDdtxSKaZgH6@bSO$5hmW8Al`?5KoF@>67O;~#470L^U3t4<{~N9hToIkAQLYHIT0t%I+9 z6pJ+PL@abO%Z7K)J>)sqlqMhI(v^@i&CT8@-y-E)9P{_RA^UGk^Vo+wkFf4v$Qep7 zpc*9%*j6PcRbKb6=}t5`t&YRQLxY?}8^he?+{;{z)Um>cgim}@{mXy~m%x8X@^NKA zQ7sf8$8mR2&y} zB=XmK%2U+Na*D$KF2Z;8@8M%y&HY`yD?2J{(}bNBF7de&o=D~?_1Vt7IRF|#`X%Ee z$q^4|WixUZrUm6CaI2=^*t53-?#+B9naVHUeEKE4H7i5EK zbTM3yC`wsAp^tE>qSt@Dl6Y$Uh$2#~;D*5HeM=tY)f2#=2o*_~Nr^4+E6@SaShfBE z^j2={!l7t@<2Xe6w%W>5aeV>u(3=TzJmux(0-+>xH)BPtdWrj3Zbe@Y1#`Dm)yn|W z-h#5JBYQiy-R1vyJ?<)-`Lpw^e`0D1M|!=nN>7{7Jo8hegM$|EyCt!u8U@_L^Cb3j*bn?5;QR!- z$b*&TOic}2D?S9sY_WPTv;h^+EbH9rCJr0re)$Rm-Af|i;9QPF0OGiVB`3g21WMS& zf>*lBMk!J?ESghji{47M$FDf8&OY)-_Tm zfOl9hg!+J2WT1LXVnD68##4x3dKvl~4K4w~p6vo6FStj(2`8E^oflWqEhfCkZL}Yl z>+t>cF-d0mDF#Xm3jAowFxkf)IiHnpWhvR(*Brh%$XoL3$HK$G2s@#q z7^EG+9$5uHKFRwx6jor}jt3O_nt;(NAia=M1#XN!b*^Kh@ukkB>YM71NnRWJF= zV(=SuBIy;_|JW2zNG!<*{H{-_3mv^5mApsK#4ekgik9><^-h1+RI`nks4hUdWo3Tl zgZO&5+NYrm#zwS;vp-<$xa$d$VpdZlo|-5}ozUyv=$5};(qGVR_=0kk z+nMQD&P!hRGYZCkg+8el5yWm*M7ik6$JRsd5JDLokA43Cdz+gW971}_VV}BvJw={U zW6i+YX77V4g)=pAq>9rgzi^GQ&mCp!3=+5H7%2Yur2mReQa{swj2#qO*ugVX!8R+n z=i+yHnJy`*_ZhK$p{_^08PRF;I`hMwbh#K0zQpTa6>ln9Cnb6V+I+e!oocnQ@2OAwgn$L(gjz0y}wnJa7?AOsHQz4LX8RD01NW%Re?ZS1F)&DVv} zllw1sBiAq+%tEX|9?$Pmq`MInEcNn}f9J?X70G%cs^@9=`{Cwpk#4d%0>~Sq_QvA8 zGJ_9^Rzgx#m3uTXC5}t~NIN?|K|2QY`$&%5h38MJJHEr^#tAL!Vq#w1=W7*Fs5)V3 zc=<_gfyKKcr(%V@?yV|H=kynGdV&XQ)^>rD#0&HYQbdGI0i}r3>t6e8e$d$geev=} z6NRALIWfF7hi2Gr-ex6|j-*Ru4JTThe~8@~EyNE z!~5+~;ifeQ$JZ&MT3$6e6IS|0SI#wXS1j-^Vg9aS*8^jFgXlphuQfjp%7KOTp;_Bi zUm$jD*hTu9@!yCmJ8!sO8wn-dxw=2K`?X*gF$e>F7dNpp7QZpR6qRvmQa@Ui`X<9IU3JxPw%`c=VrurwH1|k3F&%Cw4N-|l3ToHr+N@`ie`D_L`J~bQ;sO&g z%hUwK)0r$Q#q_)`YPCi;7X9FLVmK9hY6-iFGk|s~2r6_L^O@UMz}Eai4Y}9RH&96| zeb(Hx1#0o!`C#ZA{`hb5?~VJSuzxpL@o>fS(*ek7_4mo%FO5aohfA*_MVV!~;^ju% z?2_(|zJ9xJw2UO2oH#Z3s6{*SIhY4~vfckTH^;$iB$oaU;z|$wT3b=r`8a*2WVNH$ z#a3har3S6;CT0@tWv2I+2uf-@#dIZ*r$ll48OH6DYGJ@>i;gxRa&dh(tWw++%Lk)W#Lh#KE#I66OXOf<_;TiU%{s*%U zcs|C2XRP{?O#k4AAZYJbuZH0^t`AVk=ppZ1IHIfdT%`YXBZK8>Hm>RTpXgUSw$C-k#3UXB-#;y8 zESb;W08|=#d-t5iUF&Wd`f+aOO!IVIoxi3c$^PTc@d0FQ*Hu=?X9c5dvUNZR;MUMK z#Q16qJ##zXcjbtIq4r4a#V>Fwwi4l-2E-I0>EQ#h=xjKB27Ez&jhfa)Pi#ksONd^N zIWUTuMz6&CPurQ#Na$ROZL5YBwA;WGCCpuE=f5Tsa%$rUl?Vo%EkG>K{;;rn#;k5Z ztE;vy4S2!BSda)xZ~OEKNt~*7F~5WHg4Hsi#Tg^dffp3yXwov?AqzX3u2X$c{2sI0Dh=|gC_3Zkf zPxD_f9ryi$?1(HZJ8!2F=&iZ4g$(wqXE08*HWj=XsKzyH`~w5R-J><7aS7p*XWysk zaRUrDsO=miMa$A{)-Py%Q9$w!+ifcV`p6a42jLP-{^wo#%SiI0q*Mx6v`z+`^p4c% z$&M0=aj&G=Jiu-Mr`ZT9edaw2_)5vrm_ph!wRWES5*EdkVSN? zf*j$cWsHgAEZC^N^PhrQjbiRTL>Z9;8w0!8Y3wo{^Iv0nX5&mH_;$_?oCjlj|AAZ+ zO_aG?3HPSF1RoK+4!kjs>)XG4q2!IZ_JRp||?gw~6|<<95_0)U=a`M|#XWV!lG;Q;7icELI$R@=X%W z7D8V?{uha*ly3J1AcONYbUbG+6$tzgaz+E>=O?mhY%-1QUkxq#46uQU$!)(N)i?)^ zhA8n4nVzYbj!4XMTs;lM(5z#jtX3oMaQ91olr~Zr#b*Iu2gZU@A22vvwRS`2C++1n4>)#g9rSz-AjVSNaB6ri10!kMzdw zR&fauubVA*Je`icQ0znM>G1+XA4Ks`WsVQigkH#|d7FhJc;a}kh^WzGRKFfJ=3`07 zUOagrNl5zbUH41RDXiY1-}pf@ZLr#RMY%IEO=s+fyj~KMK#O6Jr^iXSo&v=SN#Er8 z?90VX$HxpD@hNT*_EJsSwizqSRM$3%zu1h`)5(}>!RhwLta2M+gJ-W*b`RGs!7Dn@C#1Jcp~d(X7E~I?IWhfxqxCub7zl zPVwbT(v5^dXr=eIarB^L??GeZg!&M3PzJJuORV0jR-U*#fA6Zv)sTvdtK*z9BQ$Il zz-S}ZbmYSrl}?<4+ZHe!!R}SAaSbO*L`0?M4)-*kRwG7ZXF=U7@Es8c<`3x8pPBU@ z&BT*7x*eYhEG=KDT<{=>WaxK%`eI;C<{v^*Tb`ei8=>X58pWjvVT`E;bYrn?{qKzH z%qxbAh1L8o(QgbMxX9R>9X6pGti1x7dLfZucfY?Eje13e;=O_2e*#@)&8&_3-Pz2q zCQeG{)Ny@?N*sWez;?^I{}_6NC=?$Lxz6DM!lakZFJc#y0H~}eWfO&yb~8kx&pt$D z)Lbh&`qbZ(6v^Guf2t?ej@Kr}KGxYhK&XvDGd7vABn#$5J!Yl!yXVmE zhaZ2lb)ep@P9UUz3)=?D|6JU{X0>*RIu#MqNYz^qiNUOPhC=!7*VcW_a=e(A*t%RH zKI`^+!A}05jDAkVqUOv2Ws~1L`NSGhH3rp1i&Xt7GI&J2EVBH%x5mR0k_OpajyCl& zxdOw)c%;;9W|m7~kc8grv9G=+^YX*Tq4>hDc_f26-J1cfWd#Y68*-&`&M#)soAEo4 zdMbOvrEOjrr$22Og5BbGl-wV4UNy{(`3~niMWYtBzd5s#VWO{mH^pSE;|;C<=QclG5AD=g5N566;^ ziM!O1xy|eaRi-;G`hYOskPXx}1M0?+m{tywFEm9YvTg1KD9(4QcRCiWE-|+ZRaJjr zc-Fr;_@Pt~Z!0&WZ!5?eUA7N48BxbM2BjAwo~0TD?|;mV6|9ha=H7oZ>SRQ@d;L+p z6)n4;HhXDP-#JmgYPc<1pHR{JM^K$V_H*WX84sEzct|GQuzYMC5HyhU)U&9>49#ca zxVLI#aA^FM3=6l4n_j^AP=P>qo7PyAx$~u)Gqhmc{;kG<_y1bY$uO6YoEDyFsgjH`45du(q>~( zqeg|I&0Odkaa}*p-C&Q;JXRmT$Cww!)TMdkhWICov;1^+NHxSjGd!B(W*hpPRH`q4mYYLwZ3;MvHCBSNvog?TVio z!g+38c7O2#lDl7GgirRwm`W%5UEk3uy`=oy>UwwH{inw|++}0Fl{->%*N*N8*tZVN zq3IqrOQ*z`Hh(&f3YFPnkH3!LHJ>q;41Ps`GovAYD-#!faIZH zHIK&x(UD=osL1JAMPm_RmD~q^uNO)2NvE8e#JolevMhRQ$w)C*5Mq|1&Bf?$Y8DHk zjl}x6m|fa~k9nmiKN(+Ac*F9|mD!}ydO&eC^}0EV`E4ElksFLqhD~dUcn=A?*K@Yo zQs8CNAm-KIv+cr~m-H^V0`+evj=Q?uWtmZ%Y$CT__{1xDvgfTJt?%^*msfFFOYAF5 zGpx-V+}}=`@O`Sq?VEKi(puSs3^FWcUPxR^46Q%!TymuGo6WQRHT8F573V`+e~3l? z4LJ37;LEppP1o?WwHW&9K<+jpUBq(cMZp0d-gk_d{lhkoo6m^TR;&IBXwBFshPl^q zRW0}1jPkMsWA83xBm(NAh!!#K7v&!hg88EIeW`O2ciA@nh+RmBGgUU8V> zFym1V8&K`B&+_d%{ZFX@i&PWY{DXTbq1C$Ene>gM3!e&zlmZED58a92%Z&@3KW=}x zFe-RZh;_~U&J1-9YP~hY_`K4e^j)T?+K2a( z*}i?Dt>VU4L2Wfikz$ApzV$vKHc=rAclv784&H0&j;|CGXKWa({C=3Wkpb3XRPB#7 z4v86BmQno>&JM1@jw^{!&}qT$i$af%^<5;rY&9BObAo)S24_)OXIsDLg!{U9*EQ^B zdh4o>zc4%hlNa}1tk-nlJk9^;dTi**=-EcBLz2erAxh#F=3t}2`GLOsmokVeiPO$6 z-3Bk~5B4Wbj@*&`Bk3Cyv7Oy)+%-V73ek56VR`bgC!(Cb?N$y$u?Nj`&lTiM$t@V& z8f!T+kD8J>8x)~sk^8K{&^Pa93CC59D7!!JrhRW^#y{`+LKb-x$9nH{f%|KLLQS3f zBfMtmd5}IIKk5=AFL(9Pv=Dv!i<)(|HZgkNd;KW`=l?a$<3mNvsgPeeHWS@7j27dGC>?R9iRsf4eh`K6QuTIB=ShEmfg zOMUix^1py>pV@)(``Ig|)v;GMj)-tvn@v5qQ&c0rdFMs#RUpG~jXyNC^znItOU$d? zmFC{c)L)oa(#^ff1q@hhUf0x0CkGY6ACbuXX55ocUN4$Z z+s{}iA8r~m;#~`FsYklD+h8?!K0qgh_)w=cr5*+I)DY-f)J#oe^ZEVH$HStPD{Zx` z;vzHe2KoO@IWgO~C!e)(gL8)U?%zM0oqpmu=MN2{?tJL#b+3C_(}CEL(dvcchXxNQ zuW|-{RZzZvK_{;B6noFM#PAV0dfwN9r9WTVy(N1H0%ovnw{$%NDDd@fCy_9ist-J)+2J+n?tUEE`HU*4S})?GX5e}g*N z`p~cPKEonET{irHTcYAY-AaS7FPI%dE-E1P?OSo4yE#cIqA{u%!;kr}?V;F<=0A-x zgufm7wreBVlPt77_WavK`IX~?48jSW++J>G2d=$UW%TCDs1*@5o5k$E0hz zhfFSw!s;)UTG)@?HZ8a$_T+8Kt6z`fUdR87xVLy|-W#d0vRS|QrSP1rrnwL5bMVWE zOG>WwxD$-M%xibzH=B?(GW}?LF3!h=d;ZorjKep89w971dt~n6cv0(Z!ztEwK@FNg zPep!6?A>hNGX{1J_k<@nLt@@A%QU`4rz%PyM zbdRrsEor+RooK}tU#u;!BQZqVBV5M)=1nr%%Edk1Ot?7Wxsj{gskxWw96v_gyp-}C zb~V>ZfB!bDzNe?_$kX3gruIhgZ7LhIYKm|&_Z<`#y4Z2S82+^9fVm%yPdFa^sp3}u z@AEHgB`U4_>%uuXOG0WGVh*0{I>5FQzuAe*0y9)eu)HjbH~IFwd}Fk2;R3<8Rj98EI!SM1AS*vGLjAmfwM`4dIdzXxOK`kMHVf^%*p#+r9IwOES;IU z$=W;C`mD|3$bFbLU$=+a4;f&HyAoUyeh4*<8$h>_UvQlm!SHHc$yGXCE?1$k>AGD( z%5{ynvLNzcjgaUm zA6ejfY1f~gn~3>^{A}wdE_Dg?e5UMg6&<*KgKts}MMB>|`0w$WOg|GhIoyKiGlU|l#pMB1LHlmG17 zu_ZgSgJPh=ev$j=SZ>o7{B2}4=>3Ll`f)e2iA5LqYtU^D4c3uN#p1P{o{$I;R*#9= zbt{h%DUP@~_J(7VEcbbX*P)X#{jYm%^}zIgCt}T~DRW?9mf!`Y;HQEvK%X-2ZCieH zU6ee`;x4<6%3-KM^^nkLB>Eh@p+$NB3oCY@nz(+)SZ5eGoP9N85Zd77Y1sjl6?{TZ zOLIsE-PIH1CKyzy>`eq>9+iL4Ixch3Eaqr|W#e6QzQ(AA6B~&yXTHs5Zvk~Nz7YIs z#%0qPO|FO;Svjp_j#oSnE)pd*a_{FWWyvPE6olMecl6%!2WA^c^uao7d1Kbj}wbZ|@GFy=FdNN43w zu|}Sg9H^Vme*o5XU?6I(@SBkZmJlx?57+~hh zh=oTx>4_%23{IM_QO8iFP1>M>w!t3uJ~{E&toC&(y^2#F{ug>Zk|K%-wM}_hx9x3> z?HUT4dWn(z*-^?HEe$>OHjKlmcOx?!+~ z7vPvP?OZ{>`FR9;ing)Q4ReOR#g_Wayi72yQRHH5N138_g75Q?tWw^~HBN1cZP9D4 zzfX`|hU_M;ke1h7nUrWka|v6YUci>fU0{qn-W|+?J|55HPMY?}ImSeH9d+PjWpE)& zpDQx>uV_%Ybd9ATNJ^8DQBd2KmcNIuFEIv7l~Rxern0n7HQ7kjfBnlh=SBZ@n(LlR zM*RypE-tzkOsI8+NseHZ;4WZ9#yQu0PS2vgWr#ieX#VD1z!*5K_!VOerQ*L~($G!T zJ<i1u%aFMZs$4X7HY zAzoxX=q0dy;vaN$E5v`nR*Nm*KmaO>k(Y|`0ybn!7QE6&I~?+r60Z)f?N$FKoCbnp zoVz+SEmCB-T=qdmr(j(aU0s%p5WHauJ>AD4th|_q_Epn_-Hj6T5Kt}$kD`8K+6iNv z+ifHGzuXtcLd2gAdrvF=DEpDBBVzJ~!7%tV>I*}f$qHgXC5&Q_P1kQp_*rIKtrf*X z16$B7+U*(4SNw&bzI|VEGkrE(xo_Nl^lXUpe|qU|-a~x@zEu7-U<0&U>E~{y11C9i z_t33-1~Ue8m@t|&k3Zf6+-j>jv9ew5N-q!Ivx9-In>a6T@@_JvUF}3QvP@28d!oi? zAk-w8UfKBxrR^Oc2XmDl{nm2>43OFsF<E5`cBkLpB7RU5F%6{1U3&4V zxKxI zw||cP-jxUxDVJn0gMGg*A62+#u*6BOr7mo0keqeqwM{z1o}WU>{9Q_}={g9Uh(7Ek zFK1JIwoE8>pzy|#)4x-U^~{QYS?ZOjU)S=XMm|uq-ZS1Yrg6HMX`j^PqNrRV)IHql zPRhMmDY!!IlJHe|{G=y+|9SE|i0diq7na3?bi?FPQqogE6Kp~k;kR)h)D5R27yjr5 zEi8a!YKfs!c|U|!LSc$}M;r8Kkfh zv7>Za_ny+%{%!=8%Frc2Nqd8f@>|vGk)+fYDk+kxshg6pKAd#ofqp=8_H9za@WNn6 zNhvxq!{@aC?N`Z*HjJ}y@Jnz&TGg!isd$we0FgMK|zoi4XvJ1iC?0L zLN(}l9JkbLT4UIyuN_z6lv6IDwW}KVuN{qT4!|MJBEeGA8dY~7fgg1qpw*8J00&r{ zLf`hXCEqp$b#ZSJ_Kd6naWj6IRR=SGT&JC+MAL(10ro{wvSMm-`dHP&NrRb`?B?Lw z7!7<}oCb89ayz0+potH4sByJ8kb&;yuBif&1HY=VWTv3o;O`8WaidlH(0J@f zzf{UabDNhjB8b8DDU3H1i|8W*aLB&SR`e4F&ge1=BPgC$*Oj>!X4AE}y)yZ?7I`k$ zBo-H(!5|wfhe{1)w)e9-cybizuHd%&@UMV8RwMQ+<^rt#TwGCGE!${6d2Ij9G`b!? zLfFwrz>J~YFuC?Up{hq}thb&@wGW~dS>Ipx!(nglz>e+dJO*r5s5%y#rbEFsAdG@3 zhVBx<(jV6NKEwvzj+J9yDx~@h!1e^|BHVXa#d9Z;&N0i=+Yi#^)0)lt6iq}QEOILO zzg3$(d_sXj8^PSqhX&N2vN0b|X+OwyL-W^H)WLno3(i@CbOGmy%eP*>2G6A(wbk;L zTIE}VngR)5DD11yu{{HN&;Q^)$|9{mYkl@TS99I*U3s=$`e2~!PzChUtZliYpsme| zx_x5@e}BPb2)rN-IylG2DYDm=yz-{b@9KTG7Za6efd>qS1utd;>I;h_6%m= z3fTVX4MxTZy0l0Htw*nv=%j6EAknH(MJ?l}EjN@}Vca1eSQL5;g0x2*|0dX=ih(mC zeG3dtp~q=@)G!h!ysdbX`#1OJdz0NtVJE-eODh0cY{s~or z{=EfDTfmZv>qtrPUgd<_=7TuUt^eVqMCQ0OQit&Xv1hWA9QZdcQ3e?PBsYM?Fw`fK5@270I1*W=MvxsOT=hoZbeZ}mH zul0sfpxz@CT*CTqycHOM7h6jspc@#4?c`s~d)DNI(tdbWerm$*?X8|IIvZS; z0-Q8aQ2SY@{j=#;GeuiB z*IQZ1obOg$##+_!OY5wPfDL@5Bu+pLC*Za;S_if@P|i9in-;$WB7PJ=n%<0;$Ka>fh)lS1b^1f;(!CNSdEE5eUf8mdki%v{K`|Y3m|qAJ8=+lglU z4VfaCi}U|ZW4@lAdoa8YU;kv2HggD7{_Nh@?IK6q2>i1d69pO(>9oXljwy|}R8R;s zsf<~&pjI9q@CJPsN(3qdGr8gijKQnd$Nu(|n!q`f!F5()JR3c>6~m@m5Zkb-oy1;{ zB`^fz6v7?qebp~``7ISv(;|f-GGW|E9L_HUy8B_9rNg*AY4wh^*@=y7i-eOD*31<^ zir8=FasoaKmN{Vg-=7`K@SEJ<7{4Hke^4d$)eC3|9;PLTv;@Y~V@2R^>~Ppwc;o%n z*PqCn@FXZc}=h!dmz zxHRP1Hux2fIeix#EQc-w>*)NEA>=aVf?8sFhHdR-<%?a1VmdG(*FY=_wAv$I2(1O3 z+q2*V86*kyo~$?|cc=7GE{L?ib$)@gLC|AgYWU3iLK5bR9zk~AR4!0J{gOuDBAvq@ zeKVyfrmHlm|M=?2A*$ZP_zyBeq5j92pA}nsWcb{(9U?x_5 z*QXHbf`?)WCu!)1Y)g!X^g*dEh`#}>pKgNpZ@NoHQdX(@J3xep|9*bDa(+_x$uFO9 zC2hT4Vff2=)oHGzQ`1Yp-U5z~een;h%-N8775^q6o2UCQoe&Z5%ckzNv`|^ zrv8}$jU7&H_?fK96^`ep2i^Jb%BuR3NoS5OK|&PMBgoJ)wv?>BUx5pW*kM=61G4o$ z0W;4eeZdF~VMlR=gKG1KOR=B-xjW+}G14E8Yb(51#O!b_VtoemrC!T{!dBswWlcbS>_57R9o@RU4YSQ)I(R?#kqS#GV+&8O(*sNKMY`aW zCh*}Gqo5am0NHfquzq|cMsgK-XE01Tb8XCLm{$7iwsIID$*1K=WP%*`KM?X7dAx4H z3Z=MIQonVrNA7UuKt%i^dYtn&^loj}r{O78aRP29o5Az#Zps=zw&?wF`&|lEt;MaaHPJQ7Ma(imc zk*cGhcL+vjhSD`}|6~`WnZw&r*xv>x{_R5il++!3^=*1>q3`VQ%n^()<3x+q#EF}q zLySEDv@P`sN|L;l3v~s4{R=X53<)(k6#OB$2D3?uw&2y$BAeyI~w;V=Kc&&alTo3>m#u9cFBTYOa$8wD?A z)DE?bYJZu$Qyd-K(Q`7~DVbiuV2ANy`ptiqeQ$VaY>Lf>GKL4Vvv5s{PmBG5{7TZY6W9z>hdum?Pe!Xmj{0j`*BgEmu?AMRUfQbFJFN~JA3o^5ja9(~kUh1OvhvOvuX4fow_MbSY1gxsCsIgi}u3x=Tg>s(D zyT|yCd?mhz<6#D0db3h9g!&%nj8rJT25uBTmXk3PWGIFfHgv2ZXm<_@Cig~E`V)O{ zWK0iAH=8a{Vvn?4(BA;}kx0uDo{ir)xB2sz#6`kGXkm3UvOmRiH{KV?pSZA6^!M-| zrI?pA)8h`PP)$V3?g#A;MVfdV`Lj>n61Xt<<=P*m?+u3qC^{@B56+@<=jNb_WGD*n zad{heWGT;X-(zdM{nW( z{eo!QV9cMuNWWx~zoUM2A@!bZs|xLa105gv_n>r*<}*(wEWUh#Y-GB9C#$SY?)X#_ z6f#DCkXXMWLNn<9p*7G69j51QSrjFI^r6)f^P@F9&d?Z-sKB9y2~dL7Nf3hkDZz_F z8`Z-PY1Px%ZJYTw@L^2>8@dt*`Gml|(1qi3ssB!Zi1EeyE2g7_ylc~otW089Gt$Ru^kz{mwd8acCB0I&k#BAYX z7obCP_?4yJ0#0D@?}Y#Je)@i=&+$S;Oty3?>8GAhq>L`L^-D)cZ=KKCp1g_+1ES$HRtr>yX~U_eZ0J=fI_2 zaI6!wz9eHpX~{rsp(9dJXeh83cld`RwgFJ9Hcpq!h|JpGo&s5IwMqrrwn9ZrWQzYD zs9Q<@H81c}IS`_waS;TrQW5|`hb#NyNyE(dyVk=C9WaEd5D(oqyX>vd2XoD?(K zCKQ@Uw(z14t9L1_eW#ZsLOk)9)n8Pd~9*U z-Kd}9OBB=IKP^(mdTRye1nO4{N9&??o@syB-Vp4k#DC0vT}z9DmzN$@G$&5BCf(eEhXjdCX?0_8lkCk?T3n=y?q2T=k9dV zul4Oevjdn{QpwK(`~v(Z-SUXoO0;^chI$Q952ICB9)0B}l5#E%wE00UZh(i0Jsh)H z8Ar0dClu|#Huo{+?!K$Zub@EedQ!#nf}43WL%5BQY1a&em2 z=C#);={f_?ro(Fx7wF{zsG=A!9pF#!yqH=DNc@*JoiBKANmt6+mv)f}#jRUw=voYF zg`Q|=N5KWc754>sIA>(U)51eQE1s?#4#%>LmgxXlYwKh)lcRGJE3!x0uaQP#9kXhJXQtK>mrxQc6* zsk@lHOTXpbqn#DC^=&C6^QBbA7g(KMY<6h6mG|6F48lV={Ys_?KRp~*taOE!r=_9l zITh;p2uBx{q9+_lXwnoKbXJ#twVysKuc#MzjYDR$BuYxI55dYE1KM@?%g61YCSlZM zWFXDLL`MvHS_Tufb-%OI_;(wE!pthXnmB-g;U}WDt-j_ zlFxcLjsy+Q2Yr(?{)Lh2a;}1i%WXeuzCD3Y1TqKE*Rnk9d@pn>6`vjUR%avQ3&wm} zTu#bLU(<{F*foe`=8fQMwm9CoZh<`^GG|?}81l^5f~B4z`5?jcP!!EXFl`O3xBbo= z^k|3SMm>3=W9WE}WC*K!lQcgWTl>hu}Yf0GcH=&4UA_+GEXa58HN$&VVrvqgx_!r1AGtl&3oZt*0mNxcvX=4}$DguB>--;KE?}cj8 zwog7IZhW10IX{lH5lf-2W59dTV%w9JPDIaQ?w7wK@muomzwwzYz%j=T{y5X86to7I z$b>jrzy;(y!cIHq4MuYdqI7pmkIDGYbKIvt=n%;)*^p-#9dD&Or}w5s>1P=X=!6_3 z*pi;Hdc+e=?dcC@g7u$7w535ataYzC#hA8AP)b)eJ| zfyWMHAL>Pm{4KI;_UqZh_k~S87}jw$r?v08-Xz7x{>-gCb?_lyf6_IIBaL-vN(j8b zCO5o(`%P#u^?a4CozYGE<%jpgKG6_0r>8$g<`g{g^OWw>OA~u;=#N8$QDA^D^4pH$ zldK;4-T#c`Wvct6M$B^%Vbd}Ns(Aa1^jh=%<-cd@AMMGXwd-C)bTQC## z4sBpxu@?fyYNE{7o2|gX%3Vz2Kyf;zcQ;;g6i=Ft{X?il&x7vnNNc7|CORIU z5;70df1YpDPnF8NwlZcsJ_7D(?A7|_)7&CIQ*XbIB$`f!d(lQwr*sY)zXnwWE0D?S z@6r3H=shTkuyp!*^mM55%iLo_YdE>A?1x@JjN~03AnZxA zF_^)%Ljg(K1nQvQUSDMAx+v4dxe!@y@3qf&?s5dml&9(URKd}kZ8<7|BAjS&K!fxZ z%xK??n%B{%=*9U6Mck-gvd~@YveM(}seq$ppVdIg2vutzJ&v@Hq~*Mi5DDJWkuN-N z1h6)moQ}hK?caiHkyRLL(iLKk-q2Kl;y9 zFDqX?98%6>BwZ!z!eq{CMxck$+dRg! z5DnJhcgLJ&rhw`Q{`?gx|KJ36V(0OFisEMDIV3rfm28&Z8u3!MIyuAeQ2diAXA9$B z89n2l6HlX^O0GL)T2uL_*8|2Nj0spG;^GBBI7DYFenP#ETq>!{>+gk;Lw7k(IXpHc z1@2koSUgoH_oBf+9-8UV;gXyB?+USp#LOS#v25i%g|KPHmg4l2b!Uji0|WkNuKORZ z^0g5O-`6W2n+w$U9n#$~=F-*U{`W65fuFB7jhBz_m_R|yOEHr;0r%oi2?c(;fc|TT zZdvzxLCrUqxS3$-%!fgW3o(ju^63>OuDuISPKacV_eX~Gk}2wV)ze=M{9q_kGHdxE z3Y%CWWfpZaQc73zuFF-P1~YZ(8$V3(qidh97o2~4^^r|WlT=2d-D29ud%>yhKHj&C z*k*LAg(kCI{i$uJ{)`Hrhcr3p&2|cBifxMc zdhLCV_fnpgj$ZJJR5~c@c!x>+Yrv?XWcE>V~Apm&4vz4Op5m|_wIk% zL${=~+frHGzIjOqjTUP;30$rx6!;bVu78-v7)_p@oBl+Tj4k7PkPih*xj;wG z91T$$5UNpgKyb{v(2cL`iq#+PS~ls03jZGNc$iMq({Ilo*~2Ph{Fzg}G|HeW2cuQ>gC)Ie zP?0@4_awXoSLBH2UBZ}F)_XO(3i&kclv)An)mASfa51DHvDWY-R}o9jm8zbvrzd}x z2KV9J*bA*`M|QI*@+%o9ir|%uqLn3RMAByGUwh!f&#XRd^%&3{&dRN$po4W@3{?Ew zJoW;){r*Dlx{VG3A!d`!tl_`ZkkZXK< z{^I6}ei}lZ%EYuDgoQao{LCUltigvNA5^w`*jE^3f-@`W`@^y@_mJzyLDSwg715GlrFKs}L_AT)OP*K181r9Q(yR)+VvyG zoFc!Nw%+Z?xG-8QHClH{%7)g@n4?$4pi%_H4|$lyA<}$k>jDt=2;tp4etzruND%YU zT%e8_`MAEZn!^qW!^vn%inZq?9kvl&Mj3Xv+8!)U=w~E{m~IJ1P6@7N@O8`=l?=zoKHpm#Zzi_dBG3Q!8#!^e}=EL z?d-gsW2j6K;NfEb4er>Kh(d!TO#K;t>~peSqR5=ZMp6NyoC9uDKIMUrXa6Cw_dysZe_~=ZeB#IJ~ZWd-yl}IO~!`qK%J}DTm)+YhDQ+W zb0Zq0Wj+X>zHqV(@eoYSp8whArdrllz;oyj(*B_#IDG&T4|uT|x`G4m_4b7sM?c4} zaeZX9*%4i}9rzg@d@+?irzpztxp%`5>2NFPYXydaJ0Y20h>41AzePp6Tx8Cw=8`Nh zj4s*lO}SrV%#aieilIN#lPYX%UEP_OPa4PeULd{&%TrH*SFJhwKj`?e=YAi(Z(X8A zYrj9dgnc%-&aWZky$SsK@g(Lym=F$r9~nBeMLj6J&P>Xlv{y%8mxi!-PsS9YcJTt7 zEQ5XE>4g=%$EeG{e8?SPUWWR@hF0*px1l;l3Y!3ZzSgWD{AqwpTZhU)YK(ll&GiHS z5l{~>E9t-Pi!!|2aX2RL4G&jFm#0&?F-SJt?d2G`GXS;ZmWELx9WNFte1GKs?~0@p zrMGNKy#NyYjcHthc>MId?RlIAur%I z>;etnomX>N!p;!!FJr@=>k6dU_u3cD*>^PFQ4dz$uuR#(R*7`YPN+dif&3}Ims-bG z6K-3BfE$eANK1D2`^e^HY{uD%nrDKC!F9T_69Jc$fY0!jcsc%AdTOiO7I7dQ4=AH( zD1l+}NkVwq652TK%sYV-SNdYSe?&&aGK}Vco+Q#zx7-lfqMDnL{zJmUDc`h9I9Yq7 z6lq@YtCJVPLH{1e#~qV?SB@vp##;Qk4_Gqd9#Wmat6*aBye*ey2b#&2 zg3Rdh{-)zw{Q&X%a2d!u34>63c=ARcgRm%I3-j;oRLs{0m`lnV<>3Az(PJMHE8rtRPn7pcw|vu?m!@A#Cd)0d4$N!minm z{^#`K!>=W|$K-q73nRVe-m0x)7k~+f8fFSt zRvO3hLHd1t@M~3oy6#PcQSuMm3#{@0=@=fb5YdOn&*{RaX2t(x_NMiglK_3=+d0rq zHM@JQ2eF5&^@)b$m>UEJV-yQOv~_1(V36{? zTLD9;&&O7zf+KfN9OV296vk=lo?f)gL$Ay@t^zkKX_zvndRZ?)BRKQ@54c;b{}xeR zpT-$o0azRd-C^f4K!Jw;z5%0Vi?KnB^-2uR|DWY^U4!=|ASg&ZeZSfLtCW`g?3^$S zJ)yD2l0dFCO(lPMPZAgcZYj4;@C1fj%0xd!G-AvqHh^T`4%gTL zS6Au4P5NwcHb7hL~pdf=eD=ko-K# z{{k5_z}a)nJO`i-;pTx{;3bv%On@%m3ac*cL@qd#1PY=VBxDmS5nluvC1jrO?i?s5 zI-BP=n&rbBK_Yd|N1vawfQ5PwAJ;4)q8R{wns5j%bf#KTN^rCw@77~eUx}E|o7{1XyA8MgSqSa&j_V)si#WWNZ zc`b@@l^c7^eQ;DfI@b06b8QPH?ap%pKr_=*(BIuspL|0eFf4L+8=nlx8-!W0tclrY z&OTdR+#fTh@E`Nha#ssDzq2^${G43BKjV+B4>X7}C!KESjqD`>7Y0$~up({RzJLmW8YDbcU)f!$CnFd|cZV6t+?rfM({S? zM?I%+TqN{#mMY4&J%o*ixt%8-f&vHnVLhFj_WDiCIT-+1yNE^D-3BOKl+-J#eH-<= zO2{@bM8@%c>+27%TmYMMk?*x;xixOTR-W~&Hc%H>2AZ>gm9yDdu3u^Sw&$;NpzRpO zcaA1O1Ms!HAv#?3dx4-Z>f6D8y1G_~pXF6i5scj!c03lad6vJW7RmEoQh~Y3L%*9_ z`xLnEK7>7OTkh6OQJ$w;Z|gK=Y23(r!!v|)fH5i6AjXNR@kc*M@tx`;xNeS5dkp5n z6fLo21#!<`;BR1USg+bL?iD|p2Y*#evZEGYcm;3MDjj>JEjx$^V>yCuF8qvv)+cM7 zvl~a1`YgRNYsI_ov5^6*{9Ki?LU%QFqFyKFJ7(iJ6+a(j^b_VcfMsou44(x@uP|>u zGI47hD&`;D^x=t8+Ie37%iv|Z9xYgp(ayjck-fjjqLQ?{?!>mwr^3SaFyA=(-4yaY zOQXjY@+pWPRbKM0iAtT*X^kj{6%$DBpv{aJ4!d;Du2qlWMpJ=Rz&h!c?Ctkop)>7d zxP5pR_y+cDV87e&d7P9rP44OC=##Czk=%1kUjN+vUQj&9NW>5Pd3`1n_E9?5F;9TI3j6U-;oBe|RmDNn1ZohEx-Ly_D2%b%!LNJz7j)aUnB9XH zw zT)WAb{pdI7ISE$13T1yr?hVLYZ!1~RxBtzz^XpGN%YLGods@xqh@2|SJBCBh7%D@7 zErN?B7u2SC%l$j5kPB^2NV9rI7s~5hg0nk)*1Dc<9P6T!qj$=YV%Y#QO-jPWfjz2$ zq{DqRzU)^xNNjW4w|!T&z!O0uPhGeV!gI6REiKzF;^{qLTF}91bn>CvCJ_Z`2O`1y zKplEP(asFKtaWDKZRUWIkDi5TmKEe2zvG~_{`LB5{igErT|Dkz)Hx$)?piKXEx2kOgQ9X(lK>NOeqnb;R;JT)D;rS&$nY4b^|WcpVO*SSy{K@y~c z7T@7;?C^};7yG$CFBaea1TPyL$b<$!AD&#t*cQoR5R)9& z^L%J8oOIe6R+%rCtwXrf12C~RY&Bc zeH138R*^-9hT2~pSi_!94xG<8xhGWgr`;mA|NR|!@WtY<+=`|xCR{6h9les`Ea(D1H*EouGvGYJ1S8~Khg(w1M3VxwtV&@$IgQWhy#i?*-V-J;K82|;g|^h?>cARb28PHUlrg61mhgT;&hK4+|j;jP|Fg~}(7_|6UU zdij656Z6@HIeG#|QM+H;W6_Avq?O>$Pl9vR1uVOb74M?qzYz6YHPRhL#WP1gbG#(6 znvK;Mwrm_mWU07ZA}-dfe$4##(@6SQFkOVA#qyOT$T12l@*FrHqSAh`9gH0F@VK5O z$P$tR{3QQa1D+rL4K#51Ggg9>|GD}%?N8Gj)Rhfrg>so8XhDaJUsZ3DR@k%zzA3Aj zpQ{isR(y+w-@$^+mzXkKeFxx?a{2h7oAo0rc;k+^)om#n=5wJhiwCDH;->!{)0P7YS zUUwKjv3OX{@xw-F9HJAc#d?V70L%sXw3Z z#H=bz1t9L1-015Qi9LFH4Svq7~>bvP$%hW?fcM(vJ4s)fG z3CGFGl7XI~o^xWo7Tz7&Gj~dl>~U>%+25B5IGA-v(>rJH?Mv4+#9=CDXz}5>AgO;0 z&0WL4=!R1)Tdj$mdL5nddP8nIl4A%OGE+6^6i9!4yc3D%aIpw(V^(qJxxRqY-CN97 zv?|LoQVX#HtJq5)Heojg{*m)ADO5O>*Kw%#M1vL~LNsaJq)nIk{@y z`d=mi2S>abyr8kaHYXL;g2|HmV(~}x^z>8?HAvj_I1#sb*~(&J`6?hc@PeN zXYl+w$ZBzk($IdfzAbm3i0_{oF>_2*MXi5{)O}1-7nF7Ck)?e2!kmb!Mce^qmCmAM zY3GBkUBv#|MkvRq3^zrL@d{JkpX!V&E~uKgwuE$-HSO3v?YY5awaZE8l*~@od#tl_ zo3~h#G_U&i1~*G_BtI2+a35}DGF+v&)gvYe$j}=>lV&){N~4~K=$Wu|r% zubIGJA2|kvUx{2LkOt+AGlP9tSYDQUrd^AJia}%-yd;e}qfLD~y8b~>TSe8|YL0W8 zZ2>4JhLRG_eP*-hFaA|i6k^JC>?7k&C*b$M2O{v_1@s}kPjrbD?OoJ~=*~dY0VCS? z3S>DEL2fsnnNOitGl8$Zc#^%D^&w}}o%@OUE5`8HB3k92iI!4XS^3pubU>%aM!Cys z#Y|gSG|C3p44ay|2d}^q*W^|HcnT>ZEG+cQL0U1g9)?y12mocy=<4$OBK7L@(dc_* zNic5}U;Z((#eigEL4EPNoy&PSojPNwpn3>4WU1KMMR~q(^J9znmw0FdUydFg4ld=qgiin|sX$4#7xD1h^k5o`^P6?}=yemB_cwHBE$~{hygy>CXQA)Y~mMp}oZ=F5H9MMvgJ(t%85 zVLDJLDaSZ4H@a&q{R=HbJL|lChZ+xx4P3Yf@k40%lKVd_Ue_{(a~h%3N@M)Z=M@L_ zRz?-B=sv`%9DGiSAV;{x{j&)aKr^zJ4~W-_Cr`C+Ob8^lwq9r!Ja+WIC#pk^R zrV4(~eBJfkafwfK*k{cdz0467P=s0q?3P+0lP(+W@Ws~+KrHzZb35(n4=9E_j<;e4 ztxzImOzsbE($h(QaBNR;1fU5+^Q2CJ({*e3(}ggH+ufAv(&*K&F7u6Z9!}#W;m^NR z`tB)Flh*^2uMJsEj!(2I3LJsoq_|FPKc!)Bui_U58?mx}E9!=>mO>U$^E`**@Pi8162rKp$KzRBw0WR|CE_!OoI)2XTGh zVy_3Dzd8H~n%1ZVqlm~)P*dgnd=r$uOL)A2I4NIJBL0i>8^khmAb1f=jVd9T&|~DG zvHKL+Olg_Wv3gaByf+O3$rbZnT6&^+Hm%NN>esRdIQ;Ttm$*q_eIbAG3yaZIvi#S8 zdO?{|*H5`mOJC#;XG%kVeiEJCB0Df=j)huIU&Qv@hrU7UmzZD_{the=~viB zp)UQzDrN=^T-utw~FvEpxav+e0^Z*FW5Yph0@ygFd~0gQV$npesV=p zVUkuThIibbIAfUw#77+i8m8A-(+u}o?R`QZcq$g5eDK zcsc0U_@MtuZ`m((VtK_{sJCx)jAj-(<+^Mb(2x2G_n|Bg2D8o{T|td-+VQ2RL9sbc z>4#r5!5tJS8RE|=!ktSEhLKD!GS zj==rHZaq3w%?7EhA;&9-ZMEPH2}^U6y~KvMReU z@!{|C`v%i&q_6s_0nx;SKEC~F)wz94tCtehYwQFO=U#eR2lihYHxeyUO*QaR-`IIR z7QfB=rROJJW-21a$uY7LmjpeOQ~zw5BJ}!rPN~D=RGXFwq1jmtpK&x~I1ke)KJq4y z+Y7zGcHaG#_KgrRy6C*CE%GDkMDw=%g8Vv?fdHb8^#55Pve1yy)OM|`A65h5!nfv7 z{IPsg#B*tsP~~ju`cP!;KcScK_f@>s1EMjV^PFr?(Msr9smW)fFCPk}Gi#|v>VF=N z^ZlGt8A@MMc4|J+lXWFrCfqx@a_bd)GTp00JWXe>%!YWd+3?j)pyh2)KKv4^N1eZ< z0y=kZl)koOWu*#M2I`7!`1dJ!&>)7=B*LWhYU%O9ZR$Cvw!RdcYdKG))5FhvVkGb$cIGlC) z-^mgox`kPx?qhB>KjY~ zie>JzOMz*_6YIc+Q-_|l9{PuKjMc}kqJ*TOi;#11F;}`{Vd3+bd$puz)*JzI&6J0y z5(~=013r*wzw#B1Zto4Dc0BT;zeAPOrxntX{xRSFneviw!NYf~Zy#;1 zAHZ6r?;-_8GGJkb?vGvRKB21&-ns&NqqDoIX=LPvRG{eSahkL5`&F}A^>BBS}(tDt? zw*pe82Go4HwTqr*oAY$}dhRGieDg*Ae+yfYG5$G*jJo#y5eBnTUHged!LIfTS12Mng z{cZ_~l6Rug@F7;oHN1HT zHl*LQVj#r!6K+mtyG!XpKWqR$H~)==B)s^3RL}FDFee8Ki-j(_OLKS|y^2y{dx(0v zkCtK#oi_6FpV;jie8kc~A=EY>TEzw)6ml&Zx3q9vukdjS$+$RtWAo>+@#%>Pi3@@9 z2Y2=!!h2^ei8-H0xP7L4lkE8q((mWP6AynhcxZZRJu|=3FMqV{#n4&v$g|PWk+Ch> zJ0bihB*Zn5_pXTSvYfXHG&ywTW!g>Q;!h@~^H+CTTZob7Ocf{@soAbp^PKeiBzmv% z<>ifDo$sHU3R00_VU|WNl29*Dzt@v={Z?Xm&3COe+^YTZ2=3XuA`R(q_Poo=cU%wS zj)x+fA#XGABRik2;1y_sd2OclQX0J28*f^dG>1AKO?;K@c5nFkZ5U&-3NuyO|E0ek zxYsd3zx!9Lm8Q$i{ELnMCZ$8PN!*bpG1V6x_mA4dVbBlbKl$0tB#UW84W@X^zawj z%BO(`hozzZM}ugz)c`KGYw}^Ev%!4+jmH2dtqE0uaJyo74 zBpW{S%y|<^7Qqd11w6rCWyv8H{{CHCR>*7Mf1DQ=doyj+C}&(BKEr7j@EA^~AZYT> zI80-7|J^9Nl|*Z=EN02E7(<==@b>3;{6dT)rSDG$N&}!aeaU6R#37pP_FJH z%AW_4|;4~?gl zwtTNgJipb-5%DdJP1VOVouC}T()EMXYNs)=VMsm|TD`yapr=P@5C_Sa2rxLVqa4OM zU?myV@me-GwXI9~VFCEJuQTbo*qg#fxS1N69gL}|@zSS64ZAQ9rX3LKm66*$g8`8Q zns@`m8xRSI0Jx9La6NNE5_X={)P@_-wL$mmvta2@90#>L?#V{8-D5YhJ=L_pQ)}?z z5uxZ;d{Y3LEEnR2$nxVWojuWevK)xavQ!>{Y9g~vt>9`|Uu&=76IL--cAj+= zih77$5fVAm~i))w9W;V;+SLt`G*%F{re1e+^P6z~*L_wY5 zK6i=~hqwR&-6Z%_A+5o%V^w-*&%1tTy_q$56xeQ)N%5n^+~ci(%p~q4-{5t*-0l%K ziHc1{#XtBX@aNqKdSxHxY73@{Z=^I;qi*ry4(SJpmNnsiK#>9|ao{4SKWPa`$l9dl z0tF|UTJuo0Y8Gdc^Tya`-4LM^sj(KFJw}>*H%R zfU&%*<5iiNVXb$b`l{VPVbvU~vFbAYT?pn{`a)LY6} zF-|aXq?~)B(FxQFCeK|D;Q#X%4t_}U7AxYHQuo*%`MyYWcA9!Q-$&pnJ*CxR{ElBl zi3y~DmTlGw>M!D3XSmL-OrX`|k%yoTt4|~Jx}*Mp&I+ux;K=oe4j7)cw(N|Y={=sx zrn6P&%XzW-@aW+C_sO={FQa_iZI@{Bax${Ajkh4}()%6Tk$=Z+-qpqsTF#gdVFC_T zzs;pK%fd2yE%X~m{Z%*@guAj?Gnff<%|wLd&@Ov9rj9^);^64np@=-*^Yo(Jy{cNf z?42;q#plyuOD^AKo~-?T*S~y>SxRQl82sxMV`0lflP9<$Umeg;9fiDi(0&FvKqUp7 za1{fQ#mo%t?llKrb~%Pe{-19J&Zh-Tzr1+>zbl{XG%X|$+n>$sXWg>fC6{6*_nJ9} zjlEx}`~3S%KYv~e?Su<4r%nHibn#(ZjCo@{WAtfFy|XneDXA(fN#b{kq4Z%ij9)Hy3qVMI^ExbkJ@VYR|Rp9g`f8CaVY6yR!w~vTPiG|E5k9rIw zbjTWGPWS}NzT4IFbE*Ov<_Fn@vYQaC8}sP#b&Ml_fxG9kBlzK=;;3~TT%vMl)cen%`9Q-5t6lj2bI^{1pW&yQx@NDRf^VdJy*t{!~GGVThqv|UW6dV+G65z%i`HPvBzFF=a~NF)X#C{vGHKFirOVXiUVjbRvm3E~S4{O$}}|K3vhysQ{YL zAduW`R=C0soQ+Wtbf~OngFoD*dPL`X=%2}UysDGNT=k~Z#TmC}lOs(VwY!iO^4mxc zVhyOwz2#06v%cdJOSn=&65Ls;)$lTzLi*mf$v>@V^@dRhm$oiuE0DVJ6$od|RhqeQ8Y_RWk6o-K+Qec6x-*?t6?~}+Eax+$XOH(* zzv7)|`}wv&?8f%&z)SDd203B(W}b;#so8lyA2^X>6!&MtZ-43Hyazk%Krcb>)r;@q zm{F1QF}&Tm!>xd=akQmLhI%82KoI43eF7dmI9<78gfNHi0RGM2tq%lT4>h)Ut$)q@ zM>G4=ND&Pt_}tM=Yn$8D4$Te4)WRCn{P4S&8)*gj#Dm$sn*h0n!E#hAKvK!2MMC*yZE32 zU+$^>I7`1$4R|50!rqBJq-7-xyn-o|7Kb=V7<-f&3fbEYEdbxxDD%vBu$vHto_(2F zFIr>=JG33?3wonQ_y(yKmdkHCdTZ>hh_3-J38$FBZYei6U&i{)$h%gX?JjmQ2t0RH z?I%3{7ir`^mN}gcyY;#D>HWL)%pXLtrzFd9|A{HZnVYqGnvFgbcz<4-@5vFp9;YR& z_m{hg$LjX79gh?7m2P0E+o7GC2axeO1l%X*7ooD6$Y@S(ipPlI>@7Nk`a9O{mXE70 zDT%dBAH<3B`I34}z4pB<0$sFXZQA1qmX`LpG`&juquBwEp~lF^D+f)?PV7o{z(ogY z<*juR6Tb_c=rgcL)j?KcWW-N4~a+!DNo5wrsPR*VI zAGjYS2VDa{^}{6&{vSw50IxZDagDC#u4KJ^4^!2A(dD}#c)DM$;aWl=a}mo@>OP?O z5ucYU%xao*Ps>i_LGyOQsN<38jK=ZCn=BhhA;F~K=@{phbMi26WUKKuD(*pJRl~ms zb0R|Pz;2KEY?swI6d+Y3$TDMD@p7F=C5~WaeNE_nno^nRB_$z?N7~=UAl)u;g31jK z&58;J5wy+lMwXR-s;^(P%snDC}JrTzByt)A8Plk2$=pt%AEh=7GW?D`4%a+jWB z4>0dkRd;vtU-O&4QeDCm%eG*?`fEuMQPpUbce`5j_GX@(Lakn<(( zTJV(=me~bD?Za+_E{#Lf0SGR^y<{@Y4PdB8^^0I1fo!>q+SsODhNFpnYgKw~+}_Ce z@p-SPk)*+6%J>!)(9?6%{0!?P$#zskceLTI%s-#t58SlvGEZ@zg!2%?PoqD3yg6{wO-d*b{Qd_8;e%nkk>SJ98qoaxWZqf|+t zaTe|TTRGs~(8-1X(O1PNrGRuWj3GOYzYEj$oqfW_U1t5{SCEqtegsC$3I<2ij$NmD zm&;8q|76<6=@QC|d3zX{NO+%2Mm!;M(r-uE-HU-Wgs&-E7ZpY9CiXke zC79_n))I{67(9oIYXKd3`hngAB3Sa=&< zg|FI=F+14Ag7=~Oy4O8NDi+&oGsVYIdAqk&XaHWKxXIo0L;E*(%i_isk|A8Hh^ zGLUEVpTdZ_kzt8godZ$ncuWOw^2zlc+7UYaA)V`+AIiUS;uP=*He#HqQ74cJhet+7 zpPn`RsB~70^*aN%^%qqFz+&{C@tL!Mb>WI?FMoHwV;-Q{0a9PLM1}!=5bAm%#ik~c=3a-!g(p)?XbI{9JTmxKX6sIKJxxaRP8#1IOsav zhv5^UqG$7wRrCv>9+{Kg=h6XZ1eKx68P8fHH)1Ff)WUmkA))93w6RAEsNJ*Q^Q5Lg z$v;bqu-@R`V6=+?4=$@Gm(QV&l`6n_;KLm;Y23RilV@Ue>r?v$JDn zjPGnce(F{(uh1DDe196UtXhlN<@61$Igk+)8tZZWwPlcETQXT}{u7ir7~}Cc_%W1p zOzXf&aPuMxlBxBgXt~>Mjy#} zJ1U2-{Qq!s(&NfqNnaGQ11`|wJ6IoVHAdLLojX@#w|S4ow$#n>4D5$8s}6YYGO&Z2 zi1_;A_ixcn&W+STeBDSe(9}&r;A_ugM(LHqxV%%hvudw;kHA!{Xj1(xlv)za`;q|j zM{waBdm=V?DM+(`7Bv${R8kaVhk5H83LOCPm7&YE=)X|$y1l^&%(jN=l?){52U&^I zRPC8Eg=2<*pSFw>JZeQlgl+rZ@lAp96mQ(xDS7N@Fo!by_<=p;Ta}{Lrh(mmHgoI= zgYomXFPcwWMb;1mF5LzxQu`@M+|B_Wc^=m~APF`* zuuem5PJ;JgyKcl>Wh=D_Z(5p%n%tVFg%1v9CGMKSqR_e^bn4UP@`)udpQNu-44qtQ zPY+%Sa;M;+VCN1MwBPi}W<-}v8R1r6PMX#UD5*Ua18 z_f%PI0b|HADAQ2QQi*ZMfd^Ut4&eZN_`&D(zCia@F4X5r?aTN#;Bc~5=CilZ{2{tO z*z1!r3i^KSRKu_C?Qjj&)_FtwMD!x|ZmCj+N$^N$iQnVt*qE-aN2{3PyAGV*@yc`a zTa%R*-^UX`^sNc3=>DFmU*i!JGjsRc=W>|3qYtu0F45~A{COAA2fMHSlw#_qhar6j z6SF?_mC{0M^;-^xNs7|qJRmLaqEjF3X^HN3tw9H_a@S`4je09X{r1w9d9yaU=rwb< zILV`iK9VgfktT~z`8KE;)N~STU(5x*eQ5)Xj;C|^=I>_L3;C9%(Re6G;F(CIdwp4T zsSpH0e@ak+n{P&aclSA}D8RHGG9-_0T6eNf6(n>#1{3uoq)VTRr0au-TCb0rhX+>2 z|FGoWvhHT4?yREwANaM`hFl^9D%Zy)fH>7_+ylr<>9}FYVOOOO_K-+C1aHTrT@Bop zq!b*aB7?+JZc_E;IAb>m2^$0?ov#&u>ks_NSV?+#sak;b&tXSc0vxRfS#&+|`?F(s z6Yd?nuJLdrSDWNFiWW;vl11_UXFyI;0X{O_i7ERQz2e6L{GR@y-f~Jk?Gw-EE1a>7 z&cvPxh&K+Q^mU_#6g|er?kSv2*l@1;Dc`WzXIu=0d%)g7Cc;GcGeQI0uW#u!giYNH z-~ziFOQB|8N$qVQo9A-k)eK{cp@+yA$5q$pyqk%ev5tok{>!_QcTa`wmWd_BukUn_DM@38i;LHciX}60 z|GM?wa9=j_S1T73LuXE5He7YmGSBSHcYF6u`G&yv+T)dC9|*;8+rk<&6kj@U25zAFcFFMf*7JL|Rt*DlxnM9nPBZk(%a(QuMR}c5dvqvj+~0cG{38 zt8;oeSL)vzUW8OtsE8jaqy12aelDChZql<4D7CBBx{{gIZ8v!q!eO4bOg-w+nO*v? z+sJVtM?6aM?f^`5%7-Z%;icQN)vPlz?|zR{P)GVH2b~&}*Y#aJK5)bYe+TF0HeWzQmWnCqVy|INAQz7Jf9-R1N05!~=k@zMcCe@gQ)Q?eC z22*6XN`<0a?6!3}qJt>s9{zeaM1s@q!yGBM@%fqlO(^FW6jOLApVT*NE^v*OHxr)L z*KN*)Q|ZK(YD_nLZG{Lo8Csydrprt`c zM0?BjH2gFM!i*B()W5K0Kb-vpt|hB#fbj+yYwQZ~Us@OOrP_*4(2HE`;nI%{d$C3* zU42rb^-%504ks3wH{0`|fJfF0EKxOL3#>CfNp@kM0q7B2O4n2RFDh+T;28XrQMo5k zhAOdB4uq9OAb*^jY*Z_{ZOIq?MyJ3YIDra0It{whu@CB9AKm-#P3i)OB946|FEeeB4w0sm_o|*gmj>OHEjC zn7}ygHj^tosQz2o^Y_U6M8dbU^yOLGNd(;YZifWWE}&s&STi1*1}p#QM`eP>C*Q9n z04>T2kafhd2aGlGmJ8G&^nuEj44~O2BG8|b&m>&is&?8VGwuL9h~$%C*P4KD!?y$hLG(pbf*(y|jkEp1qhh;|n8Ghr#N zI&})tL#rv2L97qqzF5e0({L5;Tp^(=vMZ9(7V#3Lc>6aplCy8bm%vRGyU5O$;OW2c zH1l{u_@MegNTh0TZA?IU!8b6=KFGx3y{>Qx@1nU#_c6G#~XM0`F_Q*E@WzolHc@@^2dtgdZ=>h?zQd#+#6ySwiMUJ zU|jN`hkk^Xvld21>LDE9=R@ZtqBh>bv%sZmR$M!jCgblSPP}|?4++x`aNV-@y;T2O zhQo3YXPMrTwKNmpEm7xYGBdnmRcBz(T|aELM5ri1oiiH*c+^jNUI5VWCva}XMLnfj>uh!lLRW@et-2MD1JFB%!lESnhb~f_rn^0;aPf}Pdru;ijqpA z4pUIqmw-$;x$8#oJ`+HGOAHm(?YD4U63O~t-b95=yy^_X!)E*{2EA_3m3R6-4+CC; z@MtgyUO#7Gc=?(XurQKxUMMZb$=MA^IpZiC50XMUgV{pTvR zUWe(77Zqa-MYz&Q*Fd`W_R7DhzUzP1nzhsk!Y*Zlc_$%bSP|S)PZ^h$XJ9f_ug5VC zPmdju02clAS@NTW0UUHcRgFJcHH_Szox_RRX{|<5%!&j zJ5;pszME#6tZR6tTim3i)|d4C)SnvB%`SBZ@qn^dKcfqJ0*}}JDB5{G`SX)rws!qV zxs?=&)RKu@>hsZikQv=^g>3J$X8(wcpqHzE{Tieiv!yjim_pt9C{(+OI0o&lAQEAu zW(M49EV@(rMHz}YND5qb=Xnj^hYKHocx&dlA0H}emgFY=PBF+HX9Ew6R(_qd0eo7c zDil8)tGIAsvh%6gF*qgPPH>~(N@_{TOqX+ZitK_@`}yic=S$C1uJ%GdRxp!t9-Gty z+47%QzAAzu=gDzUXpQ3Hv4jHBDGv2Mow86aLxOG}p1e*o*>MH*D z5&T$G6Y!&I=!KGL&8YLMG*|;tWHuSLx-{wt$JP4!6%2@z=6?*iy61Si$ammpUOGSC z(Yvr9XnG1ILT(4LlCP5ZWx-Mi4UuXXHwK{9_?U>;q5q(}5l(|=C!EoAG0|twN9-HB zzuQ4TIzxwy_!iaKL{nyh;>R&V!?kizCw%Gji>sBUsx`{auU@`n)D$mHBF_Uae0#vB zU>fs7PFGMlSeNI@oZE$^6Jv3^@_7>Y{+af-_Bo8^<)8=`5FpyiIqOl-b)+sSx%ZLv zG{k$Tf5Le*3^NPxupTzhH6tHqj$R_Ohc+wKG1ClIr|{~)-bqa5O_lAjR+Bm-O}f2+ z>>nr%_z3r`3kVqgq_9pTxHT3h(4BlfLMduR6OXp=P1&ZV2|%-*tH3@)xT5$BNHzsV zaGCK(4#Ph(0d27ai^2kbTBU(Sz|;3^nQ((Arf~rI3h*IoX*S4|w&Z=Zo5w~r@?wi8 zb>ZnbrsW;rQFSkl2nHRmR)%#D0eA2HCERERBl#p$MU|x9P6?rD8BBJ;ly}LhhK8f1 z(Z{AXZS#yDYuCTtaAy4m#s)LAbl}h4kDy9L_V%nLcxBz{D7c@@`0EYEnnLajKAtqD zya>l78Y>ZeL*CTY%!lbZG-akL4$5L%f9CU+p&2fyJd&A-G<>&iM$6kKtfNZTr1!=C zo@rdy|3d0pWd0?J+&4dA0ESa=F<|}{O)|bR(mVBCbS6Bz(zoMo1_3>#C?>odiYRpp zB6*&s8d71==A9{e@INFzQnN3Jh6khR~L8 zpsE^>1uHz6ZP#g|I>#;l-< zxHJgtuOJG+-33%1lm_29*nfV{u4Z{MB%&|uEaS}YX;c6|NYJy=av4r6K^ed#4o!G^ zUEm{R$#Upxn$q+?t{l5h^qq)|1vAtNa5;2g{Ugk(er4KE12@Pu_c=?FdRgQLEVhEO zy;M=Us^UePn;)`XL8;K17n#6m!a#|LS_&<5^SbUKH=S5gqFN(*!@Wb}& zv@g%@PHp4h|FEEW2fK!}RM6}Q{PkbN1yww%q?W-1aB-$*G6OK%ts5vPg7zLjYx-xe z*(SWynqX2&hPvS%j+yi7WAsmBy;BV0cX)%@nluz7q=D$V50 zg4RUmh|?BS!Al^L$^AtJxU+9y?mi_JvN%<;)3hp_T`2PQ8$wT3tVd9DzioiZL%Z!u z;og+h1e~BKAZiBbpf)*cfL{>$Pb)bc;He-ByaZIB+h8cf$8r13BMMRu6aWdgw@vVh zlUO2xtImn%n7J|cT(;XYfY3hHFVvr>5+HrDGs`B&Og&fl zjU;J(^~NQnj`k|R+j-KGGL&!A2u<%wnuap8gNX9RFPYFy;DhPj>OTFh!3&p%ZoQ9( zsILewcClKhzSSM%I&v2`fD?J*#{q18+F_zks5p5%f$ORp${x4?EAc@(A`SqX&3YPi z0a}*cs+jEf4tg?6^{-KXfaBopHdyG%Z6)|~JcB4uENR7L#`{nU+kvlOJB<^RKl=92 z<6+!=_^t3z;sB(!eZL1WOD+YJocBjjVZb0tEid}6gmzub2raax5o}P{wI8e$zUo1; zmOu+dZa#)Xm{`L!c5oiI3^2Fh(DeG9Jm?`!S;`7yk+zg=kUNGk()z zX?RVr(7>_m9~Wgyi#fxZIMf=T;9mq3F|J*bB;S)Ug6Kc6wUoSnKnxt#cwEH%BF=8N zJ#B9?^K1{@Fi(SSNXvk0f3!h@)a^}Y|K0X&OvfprG4KEygg&R+h`oea-&+HszD65@ zBS0E>xP?j7t`8d6!zu8Kw)}5y2UWZ-WLNm*bghMNVh+NbQp?O3g}V^rdu=E_jx0Yu z#W*QG-JJTD?y`B?Xggt!e;hJ!-Y?zl;wK~4u#-p=#v%nxLX5zJaMQDh;|0*eedqpb z+mo4Q`74ASO#WylIO#N+fA5{fi1MjV#65{#$ZfjvQO9DnDSYw{d_pu7xId06*P>^? zjfQk+E8krQfiwmp3VsR~!RRBQBDaJY7s3Cl?8^V4`r`f_yC|fh#3)InQdvv6QqiJ> zqOy!qw8#=A+uX^Ts8JM!Mp3r1W=o97PGsNreI3jUv)p^0`M#ci;Cbe!dClw2xo3HQ z&iS14`JDGV)(YLG@pq^uITO*Ow+f-T+yEA0&cC|swm){BVp>b+9$fTm=I%%K5%2P8 zXo{C)^W+$GJLH6`vjB-HJOZx=m(fHn872P*9{LQ0j{k_g#8#zR5$hC|g(K$_qcx%u z-p;;k)5y~o4j>;t$fu9rwS(iChyCPU*s{2VcVYdv@S#EhgKh~KuGfN*<9L0{8le~e zb2)4j?u4%ZRUpQzEPZCMZ>~N;2Ra2m?m)JNAzRUZ*jXufNNNr+=;ScyRRAT28&L7_ zJgCEHdy5ClD`;n$^;asCBzfHY2dXZC;d$~06i((4{sQh!9wJ3O;7{6|BdSzRsEZn# zX~f`%it+XMW9-(_HNuJp37fST)enF|NlBj(j! zlh0)XuGNgVC}RH$^5KP$79@+U(lFFiI?}6p^kf&R z^v?2P26y^F0+GunLXk^Y%HCgx{iadacW)fBe+PcAWp=_tNIS5{?fS2x4QSvM-i~!q zrL^#xKB}sZeMEcDn86!ofK%{vnxEuA$6zFKu9lJ^t3NNjCaAX3I=hA~Qn2_oiCg=1 z(AKwvk|pHQckDivjE4e$OUnPm8sEXepi4J;Kr3y}E0d>%qL&l+>f{7OUPwlH2A!4^ z(>i@XBi-VAN<#nTP)#$cQKj(R>mFy6lU}?yBe>5X>xtphDs{J=@V4Sh6@MKJsmB+Fg%VWKD9$kPdL< zhu%_;@D7gqs2bg+H$Q^9cIv6YxzP(2;BFmWP|gCS-U;80uD;|!wuVjZ1;K{uC%u1C ziW$*F&D4r$oAm8CHn|t>Kv$H9bZ7$`Cz|%FIpVH!&Y~Am-DyTndTK*7wHwIId8_Sw z_wJNT`kQep(twP(!`d?8CHMr$e^50c(x-pMl0OhjMrJEA^1j5Z=G|*P=etN6@qW(Q z zn8&$Ox+dqxh@QdI!Rr`MDN5>~I((*I0qhIZZKE}3IyWvGt-EmH6WTfB72FChyk=Dp z{GY7|h+ru^)wSu%bd`oUQQeyX*uzL6zGTFV8Y7*8S!HteGI$$u%hHxfLaf3$w&f^d zf=aI-Px%rM7aR3+-aqku9&8h>R!f`u7cKA>aH|q*vw-U$k`io*i<6dU!u(7nbhOB!lvfCyQ@hv zlvZj7VsJLTIA(l;V7uD?tv&5EBeZlTgeuI;yjpKMU$Of1`6Jj~x&=#c(xFL8is?Ul zHVw=Byz-!yRV8Z&jsT+xafhyDSOFAa)5|ag`gP>tT@7jb7sV7kPwu~I_*vYq+jr_W zZpBW56YUb|_)ixq?1)^!)t*}&oBvVzBqEklXBOX5?MMCbE!5d{i;?VFbVNY^IyaR_ zwzN3$Pqpi*kmSDyRr&K&z4)yc*_JZAxv6y)IgS$%F4H@e_+Hl2bPazEouyMYIS|p> zMl%+F$oUlHAhy*4F2tLIowH*64AZYMTDj6iaTZ zq*RiSs}u$ol3!bo)J8W9Qm6;FpWmA3f)w)ZB@y3Y$U!<)2ltdUTfxKYVcyMsMkWIZ zd9<7s#8#uR04;dtI{#Wd+^Dx;wEd6PDNgLyal!8vduh77Ow1-8C;Ln1 z`RNH=&CF3=&S2lT;VW`AI@OHlF?s0e_}(;Zn7aZ3F)*@n>J};?LDCj~>2S;UYao!9 z!S13e&)#cip7MxhX4;hr|L*KaOJgZ90yrlzz;(A*QuBxFDG`?5TdfQbzGcttoxRQv z^J0gP%t+5INvu=lLxcqlz9q|jNyNUQuH+QF{ItmxZ{qlBNVT~A*t|qLoCb=Zjq97G z{_D}=%it%w^X!D0Rd)^8+y?WI(e=%uxROla+r*Jd;m(Hr>M`oU2T;?9Mi4Vv=e=>e zOa5={iy4VO;g-RW&!(VY6Pxf63Uq{iayyN~eSGFJWw2dwkL98boGiUG*z?JU7pIT zpoxxPtf<30&BF5xm;)cfMesw-^JE7DW4F~){C3GRyfy~X+ODR{PE&scK9mSVepgiq z6;X|_I8N~!YL{db^`SrOrl$oIMZJ$`Utq8563fd2ICBm`X~W%3M=Z@X+CHxgy!fF#$-eSw(TmIG3l zb|)`M@AyAl1JxpPLMD|y-9oKMStfiPs9wmX&JmBi{hQwmo}_OU_&9l?HvqeieScD% zmlx!si+l;G6dL$+1|+(GRLl_|g8UFlR)I92sZB%8GC$EyV^XT#Fu@XpI}O}tocOF6Tc5f{}kcd^Q@<= zW6Q6Ve!A=B6@X1D8UsPF3oa zy;0wt0#&7=eUxuW22#G2wVrplqkM|#32CCbeV9jn8`E z@ZmFOY2{Q1(pT!&Cc8B?9&J*A+}-~{L*^uHx((1Qc%ORW=Gvfi-G9C3IMbBdDONci z9#&%xvA4;J!Wq~=r57$W)#q`0rJu zQxE;%&eMxck_;`lz!DP<1UDhyc1_5R4{|yFWfp0SF`WlU1=V&fQqtjXyiL%uijpvC z|5|SNPS8A?5h)7Wy$dxK8aL@m16R>e>79QTSzjEK77H0wPeeaGhCd$lU7?iHc6A<9 zvfCC zSi12R?i~!x61>lzT!3k&V11SzA10y5^w}(IA@ue}V-`m=4Ozbz>4QgT@GnjgFh!dL zn`<-2pdnF`l71%E)@Qhuvp7WKc}QkYN6q}?>%c8*-dSt0o6c%LVa56<7I5y)`6kS= z4lh7oEV%KR<5F<`<@un4T=uPg$L4dfTQf_Pc|JN8FSVajL}P>>ZlUAJ;01V#lZ=H9 z@lSYw#G;GFrp(C^e15DbxB)zOax$#?I6TAUT4k`pVcVjOAOF(}Ebo-KPTui56ghPX|{PVe{O2lO) zGaV!yc0b((TR~_Tm-0CJWOXRl=}_r%YPEISlYa6`xd`IJThCPPkH6jA$9kLT?U_^a1w8sfy2q@}7mmm#XM3K4spVaGqLJ3=? z&3WNJ*nJhzK&`0cdHD@fY^U(TRWYbEjJWjL zZIe^%n1t0OanesRGdWgo?cpaxYQgQ#dqPd7@AnJ&bE#`DtmDP=D2ND1bb2E7*p zn8=O2m{B}<%O~=Fx5Fx5^(*;UiK8cn#O+Gu$||<4Upo26`8RO{H%1gagJht4Iq7|g z70Afbk&RP?=e{VJkeLyp0)@>$iaJY5hg621FQ^RpAD+v&g#^WQ$^U9q?;)g=h-O}< zhaDwVQ2T%D;#dm(tlx`QF0#2D864ZoFTmk(gb7QK0%-cE^dr9KTWJ?%9N814lX4rP-8yLI5Jjkf|t79)~AzXp&GLt ze0fb1)D3cVgE>Fv20a^7TJblQl;-iakjSqW_xynu)aAUn62I00Y`umZILJLfFE*;$ zj2#85Fu!6FNOnvnH~w9gEPF`A=+iDD#0>@NS@U}QAd#Y%%b`1W4Zk$Z<;~9~MfkDI z{mkT&g0;?J*ei)x8$67lKKwBlgG{j)mA0GyKs(`nf~PS!*HrlY1GswRmDOsj>AZ=1 z!fB@PqvJT^-o`L4zHQqWcvWBTFLaIaME3^6{Z8iLCpDl!+=P^9lqzscN3L9HNJHLk zR`9louv;H_x!RMSbWWUe&s={geTIriyr=Zz@z62ugNQcef@?_&lSWH}D^sEF)bE)s znot~W%x5<@Dmvs1*!m9q#X_2v6*@5|a7jyLj#6Q?fw4ht2jH}EILgaZ_trc(2wdQV zyS*9VW`4ve8cE6W3%|ZDD#54oaX|sc8UCHQv;-YzD$$b8X|%ANh|b*Aq21GuU}ulQ zA{uX_GuQfB5-b)rbtd1@oW;18{PHRD7P4P&Yx-h)Mi4Bkb9{W%Av7F1aL?{C_rk`esy@7us7EW_W*P5nN*669o+e!0R85M34pNO^E`-p9LuYc`;Iv0PzMegb* zlH(h@7DfF{dtBCyGz#rdc^|>sVT2QOHf&z9PS1Ba#>c+=n6km4QzxbD?%%JfR?)e!#>Jm}#J=vh5~Zry#RAXs1=BP+K)bkRa4lbkHrr(R&3s2&DxXG> zu;hn(!+hR=@8j!xkU`mxZ6AE5p+iDvw@Y5*=qY^ubnh|jve?~<*_*NP8x3-A0IT$O zxNm%?hN+dn>o3oEg&XMbYtc9G8`2m)%A|;z54(!!OWxh3bpjM$T}!&OoD4E-A6~`? zz0>h1e-HL$%xbdfT5`ZvTukb2^|Cg>HaJf0Q0s15>gKj>t+TVg;~jMiT$Z_5;rWL>6;tf zw~BqW)8@noMSgqAY(?y2_MF3U5u+kXCozv3>F)9|_flj8vc4?8QL@aM6flqcPWFq@ zp|uph(^33U)**2PuBWc1sYMfavG7|;!(U@7y4i9QbyMx_S)FUSy$gu8%M^uQ|Kw(% zj$1I=Xr=kct0bcbaUL{mjBKx+d-XZzy8-{H_RoVZ>2x@Y-PDns%3?5#zO|N5$PW2Q zbr~8E`S{9q)gT)WJwkYDOdMqaag`KS{>-aSevzgMrx&jh?s2y7bl9?Uk1Gv%$`Er; z@2Xeznd7bPcDDh^1k(w}DB_=pQwB;ZW;|9CDIwh0l)m4U#2L_`HK3#@{30A6kviOVJJw1al-bZyo3DshFgPG z__q3M=-y73#EE~Lze4q3qMLB!x@rA1*UA2I{M2w2V!y z19l5RqdOjpRMeh2ZZ#Z7D28QEVYk5WNL|kC8{laEC!(x1>pjwZ?5b1D zp_qw9v1*c(&${3f1`%Mrp~|r34=*=~!~L0Zw+GrIrxS>mxHp;ikeJV4$E{o0Q`1yg z+Z4t7TbbJk+<5N+J5(zJL0#sEoNejn7_O`0z1N_f12Cw}~nuC(9?r z{M9(B-0)B|By{ofn2Qs}(o#fMJ;5f?T=rrn2pC|f8ps@#)i_}$iQA?vr~ROrc72tD zuY(z}({=gxMa!MRmLaO)w)Yn+(5Dl>f336>KCbJ!zm_#!@-j0p2X+8f)oOvO)Q!K1W#-OWK4?|c9oNSP!pHGSVDSUy zSi^d{n^Exqr^3NU3!3Q{nWbu^Y0fPQ&#dno{A8h*)FSb1IcGKftbMvT$n{9)#@nsx z(p?8tJ5ucnRKUfl4_lXp@7NIym+W-D%+{Sa5`4dGm-y1E8nOw=LeBtC^+_eKFTj`R z!l)+ET;0BuaGNlR4kS1LDtnt?ZEzjGdpq>YbkV%5;{Z+X^7rkxBro3sxNfRKiWk>K_MlB(wjyj z^q)_PXD}YOmH4Z@N$`u)Td6pyCcE#=Qc>sM>j9+xb|C(+;O>#0;M?HH!tpWk)~T^m zZ@{O~WnWuuU=14c#jDx}U>^rIISaGu1w0LGTBIT)eJj+1@A~xcgv;+pJ8lr@c}El= zonIa}k@L@84Epvv0Rf}ag91=37Gz&b(e`@R(j<8#Th_E47?c(kKcU`v z#NUcEfTO5U6gSor671(?iuL0k&72ju+`=}xs|#lSTG+^75>vyrm&C5jKD+sWFnT%e ztRAlrJvTkci_E)MCr=@=qBgJgq7^ePZV1DwH(Vn9a0Vv)19%KzCs#SK z%W7X_#}80tv$)6y7^5@*ALCM(+rDwk=kl&$RVZO=nDwOq*{2?AT7=xHG8BM z@&|f<|BJy^2^zycL7wHe-=Ctv`@`EdLV=NYjOWw@4#_cEkUijA!{3;t;h7#=sRB$m ze4G$G3*x}+JY~HiBczrc61i%;dVXGi)mOp!==Zy$4^~%%T_xSh&V5GlKZHbzO@O-n zMqHq@{WlkudOol5vdJ$89}R)Ifx4Enm;LT07FLsq)9hB??Pf5)WH7Ow6bKCmw&R_Ub67~s(uE)F zSR7caaya$wx06o233lWsC>9`zlb8~=tUIXE`uk{;Mi!g=IKj9@RH!{u4c)^F!8Y0E z2!)R(0bhQ_9r`-=7_rOIV@M$jss}*^m)a5ke2j9vE0K;wqb|-^Km-t*1OAqv_Hi3^ z68Lwr2`4@a<2vO;ljXj0r5OJ>lPcd%jy}aE<)BbpxqK{PPL2M%UH1I(xB9@*K6iq> zXrwAdLwXYlFIXFJisN7%=`Xk`R2EMOI&uJ0@G>EN`+1^$acw-)9VDr*_6>D|YnWrz zrj0^@(*H{LBH7etYm7(ze^iST+5Wfk4h>cV+fdl%9Z4(-^W>Y$Y~^J)1J4Dv=x$N- zimQnJnV_Nq;cp8jUB5lF;0;R9+2fMpy?DxN-W4NMLYmf>Dc@P?*Bu39knG;R%|Cx- znf3{L;A;9X3NNX$L*lHfcylGCe8W}1ixNGCDovM5R)`(cRUVZ}SU?OHUkw^$75rWO zv$&NQ-_pM$2f?jWA#G$J?7&4q-xE%rluo3POI^{19tnED53y#Rz(OY5om328R#7QZ zC{xX+?f_r0Y#|S(`UA;q-R4u6(tmK_omM^mvjvrqqo^5175xT<(Dv(v-d{`fH@ThU z+4~M-AT1ckum6DmvZ#>Fnl5~m5ps8z?>pfobH$-1V@@RZ8G`{24VMPgWTPhMKJ@X4 zs0ad|ZBiUDde1Rm zw(h#bBmnmXZo(Yn$s{%jDHcHGqPsDVjU2J>zFD#-LuEGdE>F6t9HFk|jZYS{xEZg3 zl9xmUc-{d=;KHj+QbaUQolg6g(ory*cm7znS}^w+Y+HD1{Z3{)3vaF!3YAkUfJv$x z&op%2Uw^R=oKkxgrV3ToaOd8um!4+V<%w_x5&nq94qV{+Gsi%(9F)5%jC|Phwx!n0 zA<=9veh_oZhrjZ4oT+uN4QkT;foBu1wx0apm`#=Z({^jq5ic6z&!?{^<_VGg8eVFU z4;pGS`Ni}%LDpryB8LW{JsZEv>mS{|X1e#~E{-{p8nr(g9gY2nf@>-R-aMTNY?>u# zM-YgRRiu;M#JV?I&B1>f_8%}(3=$@!>yqMq^M6TM+3LUQN<1eSU<>logzPI7+ z&Nh&i*0X@fBC)%#{tEO`gESzOZ~>8`kLrlO-bqF-Y6|`wTN)WUJ~w+Bb#Vap&rTI` zrZMfN&JrGG70fRjzKY|s3ZU#2i0HK0BXCA5=gcxJLkd@hWaD-9)ek{`LGh{jU#<>4 zS{%17jC2XWy7udLG0zD=pC2&QMl!B{%4SHm77KY3$+jxs z6-Iuq7JaMO>jiWs9SNulvP(Fzr&lcML(2!AHj6HfY@@T!cV_8DY%s>2fFf z=`K>HiXEy0YOX8bPZ1gR;}lgNgqd@>{Ir))v96N8>x-^i$fuXhCSj`CA{Ktl16xI) zzY`9}_)QfB3&#+5!7i%Uo(<~I&`F$PK;#}}JH;aBg(hY9v`tZe@^J59YZAI11&3F+ zV@LH^_m_H>xm>QgyR+U#KUMaOM0ArM+Ft4YX~{@Iz5tVR5{1f1c426cBJsV=jox}0 zo9H_I%fdYZ`rl$DMVXl#E_qYH0#wL%r8xq93m7LL^AXiE8zdBtwl9-aD^if8He=om zpVd+>XSh<8Ot=w#rmk>OLrCHIEmt*n=H!Eacb%}F^1Sh&uu*BpZ>`nuAVqP$d>+{U zsNnmqg&DqZ6-%&(Ca};Sqe=a3yzHzg0d9KozK1W+@t|gJ@8D4-Sv73v=H$Db`J`|U- zNqD>K$KSY3lW+O=9XxHisc-KFoo9+u7BscOEzvtS>{++(1^>ERpHc)pA8O>MrhaI# za2thbaXybubbkG7-nM$~!$fiRV8QFjxHup0mFlIN2<_-P{<>BC+q(yz=NDQhyAN)k zglK=uu%>sUHt-%QyRD?ZC7Y_)TI#T;GW^lF$}C9x#GE_YI=79Zx(R2i;T4zo`|ZC6 zPrRt|cpSvN?%Rd;eVrF_DJqP7UU>uG#o`Qp`JOQ(9`|<*B<@yBN51^^L04uL>D>Kw z1v4&r;k?DBn@&kRT^p-ChFk*i$>e{Zq&?nDHtr?|znrSWKh^rRsKiHtgBL5Xp$B`n zTT@H9w14xx1s4hiN{S3JpKyvskII!oOB?dq|ME!1!!8H;e$r&Kw-6vUPCt-<@M2IcX;dS{Y}zk2Y91pb8gm4go4 zOq{+9-{u>?x&q z{0ZuiL9gGIYpwHw<8$ymQ^^{;i;Fj4cS7^X))3w5!5sABs$`hF_bKFG3L;5*kjBT8w)x2~7Ej=@&cw zm`!>0Yid{Z;_(D{HKTE~1x@Yd<K1l&y!r-?Z7pziY>KG-%>_Dpchsg$&AJdB zVn@zOEL`rUz~{`XZq{Hb+tF23AS|EC7P$qos=xiR9qw)+h%yWB=sqJ<37k?+{* z3bOr6D%Bu=QZ)|K{)VZlIlf$zLnTOJa}q@D@et)%WIgom$(HrF@24XuV^Nn;6?)A3 zM)!3C7t=VuG^yY2ahuqa%hcm@sQNV3cuC9p{xj=O7t%o8`*`(VnF2h^33v+m4w~=0 z2sJ-e)DYV9aKLQiiP!eG+OXhrDcO-jHMEJk`9@B@*Povw53k$YNP~}XdT*lYeyxZX z-QM_>OIvO&JPU6@%{8C%*927zHlv{sgdI2zl}485pQ?P*fD>_ft6g%Ez zy$Z=lLOW8xf){#GdwG1vOKe)P7U7-*QiL>jr9IW5(eBhDHksGNC&wY;x{yo9e^qRE zWDDaeUv*!o;+~%VS242TF*OpSUf}i6y6ZR4X)2RE13$mU6?(t+{mKE{%NXUM)4)XS zo9v9AIHi|yh&mjVzYW;vG;9D(@wZ7}8@P|tE&i1^lkqG5 z`r8E9?#Wkn&cj6O(x*#3U(U>~8<^}u$o262#|d!bKsut$k`T;Bb}@EHL;fGcJ9cp< zCDdv{F)6+>;RGVBGy5Lv->|32o9-{$qCQ>muGwTH-~Yq0>0=&Yh4N^g-C}hBoLx2P z`qw>ZyolTfdtQ7)m02p+z>#f&hb1fu*+|mR_&Pk4g6GDsRRl{=pDfIINek{LhXpV1 zIJm?a(7wFq5j&HeNu9D`C(o>bFX>2CJ~s?i#o2ty{@`0j#~S2D#wGAj44(UTt+c@7 z-T$3yi^1NRm z$$e^*63j`LqKSj(RW!K>mX7hvry7g**1`7P*jxVC5~>&;lErgX<`B9?3upr+ zxzweQ9&#h^5O)0ZXaDb9PXmQ-Ma<0ou~Rq*s@V~ApkS~h7wep$?BR*rRbRcZJ&9ew zBv)do*!)#XU}8yLg&=5*T>h%}u@N}NQ7wTFD=m=ut=OTryhA5zF|~_E5mmw07B&SY zM;_-rdh~Yr{KD*{3+#+J`8Fe(7U5{#nz`7%H(d1$lyRZ#&-P~&ns`5`DmJ=l8T39nnQPC3$L*Euyo;yFxnHF>G9 z8gqOyIdxr)*8zdG+J7*Eku}PyVM+>CG)KtpKau2JjUDH{xr|zN8Z-YJ&G7O+R+p9s zFMb1$nFS|9j2AMQDy%T{acT&efjH=uE{Q=rjgIf$%zf2epqcYVaIG-1R6p#ULD$T-v(GoBT7Y zRez?uUei5gG(%Y6I$cmB{QLyU7C~zyIUIADzl($PJ@V%W9qm8JpQ3ZtbrMZxC`_~a zaJmC3T;3?+w#FJ40wtr@mL(v`#D`%Ig6!9Q4aB1lsI(A=CuX7GryMIX2V33_sk%V- zT6#nI2XN45`t8aqOO`JN49ZQ^Se7#`v4b`$ZAiM@9Ap|sb)t7W^WGYmU&4BqZjkbV zIkwwQg}5&Y!6RE1pdE$SId8@`Y)%Z4{8C*%xVx@>ur+NzY$H+)M-;L-Twn{LW(JRD zB@053R1Z6K?Qree5w^@t^h7Fk3?2=OAD0+)G2vq}R*ih)D_0t^s2uW-PMs9vZRt~-cD&4JcHt(ksq}DJsl3xUmmE#+<>L0`yESkyUQk!c)2D< zG)O(cZ`}c(^Ip*zl!6q^dIuzqg4Vb&YUqXyK1l^NM^fQR3bHL6EqOFW`BgS*3qjf5 zrPdL(9&hC2m*cV#u z^%}!hQNDz}J;rUXl#f{zhMu?g`NSfT?qH=)R(IG0Urx9`!iFXLPi_UotH_2@8Ur3M z{37B_W)4&+)q|i&Uuo7xJGPyTyK@gJ6Q>oVi z`wEhaU1HW-)bj*99M9IRIa-52v;)x1J2>V8~T%S78q!$7u>%l06iZ-SA+KLAE5u<4(qlD_D3~*@cG^a1%Y|ng_oeb^W;O4z%_Vl5?ln~hSjp3nRC z^~#o)4*r06KY#r8cemjz&*zy>amyP`E+H1Mcz~SjecCJoC7g6dtlfOj5Y#i+0;Z!9 zsEJQ}tY`Lrl`&oL^}WM^J5C4n%lNUwgWnL-wE#u=-sHse%37=%q@U~Lg?iPY+7A1N zGg~`cHF7+mQqeW`$`|*QE-d@DE_vE#LBDGFrqa$)o9k;f}7m^g}+IXXCH>%YvY?4gLvk6%8MqdJXo2* zdpq_!O*d;caCooi2)Mcce*ENjk~NXqiV3qEujhC$4~r}=PU*F+T@mmsU_@6W$EpL1I= zRw+esUGS!Qt)gee7wq_pe$)IK`-U2uni^t*^D&odL=MOiiubV)?C+q365@*+i5NfU zr2tGgpsId^G12n`Pr6IbzpfKC&vj8FRT-7AA8HdUzLOm>=x~v&p3|G0dE`=CD_Ha? zvi%ZpQ<&6c+!C?tj@u7--;12%``^v}dz Date: Thu, 22 Sep 2022 15:31:13 +0800 Subject: [PATCH 49/53] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=97=A0=E6=B3=95=E5=88=A0=E9=99=A4=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ConfigManage/index.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx index 762661f9a..1430fbb63 100644 --- a/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/ConfigManage/index.tsx @@ -27,8 +27,8 @@ import 'codemirror/addon/selection/active-line'; import 'codemirror/addon/edit/closebrackets'; require('codemirror/mode/xml/xml'); require('codemirror/mode/javascript/javascript'); -import api from 'api'; -import { defaultPagination } from 'constants/common'; +import api from '@src/api'; +import { defaultPagination } from '@src/constants/common'; import TypicalListCard from '../../components/TypicalListCard'; import { ConfigPermissionMap } from '../CommonConfig'; import { ConfigOperate, ConfigProps } from './config'; @@ -385,7 +385,7 @@ export default () => { const onDelete = (record: ConfigProps) => { confirm({ title: '确定删除配置吗?', - content: `配置⌈${record.valueName}⌋${record.status === 1 ? '为启用状态,无法删除' : ''}`, + content: `配置 [${record.valueName}] ${record.status === 1 ? '为启用状态,无法删除' : ''}`, centered: true, okText: '删除', okType: 'primary', @@ -399,9 +399,11 @@ export default () => { }, maskClosable: true, onOk() { - return request(api.editConfig, { - method: 'POST', - data: record.id, + return request(api.delConfig, { + method: 'DELETE', + params: { + id: record.id, + }, }).then((_) => { message.success('删除成功'); getConfigList(); From 7dc533372c8136265d5f45b709056f565cb9baff Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Thu, 22 Sep 2022 15:31:34 +0800 Subject: [PATCH 50/53] =?UTF-8?q?fix:=20=E6=9B=B4=E6=AD=A3=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=BC=95=E7=94=A8=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packages/config-manager-fe/src/pages/CommonConfig.tsx | 2 +- .../config-manager-fe/src/pages/OperationLog/index.tsx | 4 ++-- .../config-manager-fe/src/pages/UserManage/RoleTabContent.tsx | 4 ++-- .../config-manager-fe/src/pages/UserManage/UserTabContent.tsx | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx b/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx index 2a9a9a74e..835abf51c 100644 --- a/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx +++ b/km-console/packages/config-manager-fe/src/pages/CommonConfig.tsx @@ -1,6 +1,6 @@ import React, { useLayoutEffect } from 'react'; import { Utils, AppContainer } from 'knowdesign'; -import { goLogin } from 'constants/axiosConfig'; +import { goLogin } from '@src/constants/axiosConfig'; // 权限对应表 export enum ConfigPermissionMap { diff --git a/km-console/packages/config-manager-fe/src/pages/OperationLog/index.tsx b/km-console/packages/config-manager-fe/src/pages/OperationLog/index.tsx index 064d89d11..02de759a4 100644 --- a/km-console/packages/config-manager-fe/src/pages/OperationLog/index.tsx +++ b/km-console/packages/config-manager-fe/src/pages/OperationLog/index.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from 'react'; import { Button, Form, Input, Select, ProTable, DatePicker, Utils, Tooltip, Divider } from 'knowdesign'; import { IconFont } from '@knowdesign/icons'; -import api from 'api'; -import { defaultPagination } from 'constants/common'; +import api from '@src/api'; +import { defaultPagination } from '@src/constants/common'; import TypicalListCard from '../../components/TypicalListCard'; import './index.less'; import moment from 'moment'; diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx index c24f8e4a5..5adeac583 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/RoleTabContent.tsx @@ -21,9 +21,9 @@ import { } from 'knowdesign'; import moment from 'moment'; import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; -import { defaultPagination } from 'constants/common'; +import { defaultPagination } from '@src/constants/common'; import { RoleProps, PermissionNode, AssignUser, RoleOperate, FormItemPermission } from './config'; -import api from 'api'; +import api from '@src/api'; import CheckboxGroupContainer from './CheckboxGroupContainer'; import { ConfigPermissionMap } from '../CommonConfig'; diff --git a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx index 092b3c847..34bf61801 100644 --- a/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx +++ b/km-console/packages/config-manager-fe/src/pages/UserManage/UserTabContent.tsx @@ -3,11 +3,11 @@ import { Form, ProTable, Select, Button, Input, Modal, message, Drawer, Space, D import { IconFont } from '@knowdesign/icons'; import { PlusOutlined, QuestionCircleOutlined } from '@ant-design/icons'; import moment from 'moment'; -import { defaultPagination } from 'constants/common'; +import { defaultPagination } from '@src/constants/common'; import { UserProps, UserOperate } from './config'; import CheckboxGroupContainer from './CheckboxGroupContainer'; import TagsWithHide from '../../components/TagsWithHide/index'; -import api from 'api'; +import api from '@src/api'; import { ConfigPermissionMap } from '../CommonConfig'; const { confirm } = Modal; From d4f0a832f3dba35530c2477075b672dfb8e05141 Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Thu, 22 Sep 2022 15:31:52 +0800 Subject: [PATCH 51/53] =?UTF-8?q?fix:=20=E6=A0=B7=E5=BC=8F=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/TypicalListCard/index.less | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less b/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less index 06516afaf..9a48d1347 100644 --- a/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less +++ b/km-console/packages/config-manager-fe/src/components/TypicalListCard/index.less @@ -22,6 +22,20 @@ display: flex; justify-content: space-between; margin-bottom: 12px; + .left, + .right { + display: flex; + align-items: center; + } + .left .refresh-icon { + font-size: 20px; + color: #74788d; + cursor: pointer; + } + .right .search-input { + width: 248px; + margin-right: 8px; + } } } } From a3a9be4f7fbde00f99ad7fc121f61eadf5d509ea Mon Sep 17 00:00:00 2001 From: GraceWalk Date: Thu, 22 Sep 2022 15:37:24 +0800 Subject: [PATCH 52/53] =?UTF-8?q?fix:=20=E6=9B=B4=E6=AD=A3=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=9C=AC=E5=9C=B0=E7=8E=AF=E5=A2=83=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- km-console/packages/layout-clusters-fe/config/webpack.dev.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/km-console/packages/layout-clusters-fe/config/webpack.dev.js b/km-console/packages/layout-clusters-fe/config/webpack.dev.js index 60f2bbf29..6c7776caa 100644 --- a/km-console/packages/layout-clusters-fe/config/webpack.dev.js +++ b/km-console/packages/layout-clusters-fe/config/webpack.dev.js @@ -34,11 +34,11 @@ module.exports = { proxy: { '/ks-km/api/v3': { changeOrigin: true, - target: 'https://api-kylin-xg02.intra.xiaojukeji.com/ks-km/', + target: 'http://localhost:8080/', }, '/logi-security/api/v1': { changeOrigin: true, - target: 'https://api-kylin-xg02.intra.xiaojukeji.com/ks-km/', + target: 'http://localhost:8080/', }, }, }, From 27eeac9fd47956b5398926fc82762cfb8b33e9a6 Mon Sep 17 00:00:00 2001 From: zengqiao Date: Thu, 22 Sep 2022 17:28:51 +0800 Subject: [PATCH 53/53] =?UTF-8?q?=E8=A1=A5=E5=85=85v3.0.0-beta.2=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Releases_Notes.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Releases_Notes.md b/Releases_Notes.md index 616d1eab8..5dda16856 100644 --- a/Releases_Notes.md +++ b/Releases_Notes.md @@ -1,5 +1,39 @@ +## v3.0.0-beta.3 + +**文档** +- FAQ 补充权限识别失败问题的说明 +- 同步更新文档,保持与官网一致 + + +**Bug修复** +- Offset 信息获取时,过滤掉无 Leader 的分区 +- 升级 oshi-core 版本至 5.6.1 版本,修复 Windows 系统获取系统指标失败问题 +- 修复 JMX 连接被关闭后,未进行重建的问题 +- 修复因 DB 中 Broker 信息不存在导致 TotalLogSize 指标获取时抛空指针问题 +- 修复 dml-logi.sql 中,SQL 注释错误的问题 +- 修复 startup.sh 中,识别操作系统类型错误的问题 +- 修复配置管理页面删除配置失败的问题 +- 修复系统管理应用文件引用路径 +- 修复 Topic Messages 详情提示信息点击跳转 404 的问题 +- 修复扩副本时,当前副本数不显示问题 + + +**体验优化** +- Topic-Messages 页面,增加返回数据的排序以及按照Earliest/Latest的获取方式 +- 优化 GroupOffsetResetEnum 类名为 OffsetTypeEnum,使得类名含义更准确 +- 移动 KafkaZKDAO 类,及 Kafka Znode 实体类的位置,使得 Kafka Zookeeper DAO 更加内聚及便于识别 +- 后端补充 Overview 页面指标排序的功能 +- 前端 Webpack 配置优化 +- Cluster Overview 图表取消放大展示功能 +- 列表页增加手动刷新功能 +- 接入/编辑集群,优化 JMX-PORT,Version 信息的回显,优化JMX信息的展示 +- 提高登录页面图片展示清晰度 +- 部分样式和文案优化 + +--- + ## v3.0.0-beta.2 **文档**