Commit 54e26d9e8b644fa67b11354b06b2fd9497620ace

Authored by YunaiV
2 parents 5bd63163 b8d4c374

Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/errorcode

 Conflicts:
	src/main/resources/application.yaml
Showing 314 changed files with 16140 additions and 3768 deletions

Too many changes.

To preserve performance only 100 of 314 files are displayed.

README.md
... ... @@ -35,12 +35,12 @@
35 35 | | 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限 |
36 36 | | 岗位管理 | 配置系统用户所属担任职务 |
37 37 | | 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 |
38   -| | 通知公告 | 系统通知公告信息发布维护 |
  38 +| 🚀 | 短信管理 | 短信渠道、短息模板、短信日志,对接阿里云、云片等主流短信平台 |
39 39 | 🚀 | 操作日志 | 系统正常操作日志记录和查询,集成 Swagger 生成日志内容 |
40 40 | | 登录日志 | 系统登录日志记录查询包含登录异常 |
  41 +| | 通知公告 | 系统通知公告信息发布维护 |
41 42  
42 43 计划新增功能:
43   -* 短信
44 44 * 邮件
45 45 * 钉钉、飞书等通知
46 46  
... ... @@ -50,6 +50,7 @@
50 50 | --- | --- | --- |
51 51 | 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
52 52 | | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
  53 +| 🚀 | 文件服务 | 支持本地文件存储,同时支持兼容 Amazon S3 协议的云服务、开源组件 |
53 54 | 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
54 55 | | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
55 56 | | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
... ... @@ -64,7 +65,6 @@
64 65 计划新增:
65 66 * 工作流
66 67 * 错误码
67   -* 文件服务
68 68  
69 69 ### 研发工具
70 70  
... ... @@ -87,14 +87,15 @@
87 87  
88 88 ## 技术栈
89 89  
90   -**后端**
  90 +### 后端
91 91  
92 92 | 框架 | 说明 | 版本 | 学习指南 |
93 93 | --- | --- | --- | --- |
94 94 | [Spring Boot](https://spring.io/projects/spring-boot) | 应用开发框架 | 2.4.2 | [文档](https://github.com/YunaiV/SpringBoot-Labs) |
95 95 | [MySQL](https://www.mysql.com/cn/) | 数据库服务器 | 5.7 | |
96 96 | [Druid](https://github.com/alibaba/druid) | JDBC 连接池、监控组件 | 1.2.4 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
97   -| [MyBatis-Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
  97 +| [MyBatis Plus](https://mp.baomidou.com/) | MyBatis 增强工具包 | 3.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao) |
  98 +| [Dynamic Datasource](https://dynamic-datasource.com/) | 动态数据源 | 3.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
98 99 | [Redis](https://redis.io/) | key-value 数据库 | 5.0 | |
99 100 | [Redisson](https://github.com/redisson/redisson) | Redis 客户端 | 3.1.46 | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao) |
100 101 | [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架 | 5.4.2 | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao) |
... ... @@ -102,16 +103,16 @@
102 103 | [Hibernate Validator](https://github.com/hibernate/hibernate-validator) | 参数校验组件 | 6.1.7 | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao) |
103 104 | [Quartz](https://github.com/quartz-scheduler) | 任务调度组件 | 2.3.2 | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao) |
104 105 | [Knife4j](https://gitee.com/xiaoym/knife4j) | Swagger 增强 UI 实现 | 3.0.2 | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao) |
105   -| [Resilience4j](https://github.com/quartz-scheduler) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
  106 +| [Resilience4j](https://github.com/resilience4j/resilience4j) | 服务保障组件 | 1.7.0 | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao) |
106 107 | [SkyWalking](https://skywalking.apache.org/) | 分布式应用追踪系统 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao) |
107   -| [Spring Boot Admin](https://github.com/skywalking) | Spring Boot 监控平台 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
  108 +| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin) | Spring Boot 监控平台 | 8.6.0 | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao) |
108 109 | [Jackson](https://github.com/FasterXML/jackson) | JSON 工具库 | 2.11.4 | |
109 110 | [MapStruct](https://mapstruct.org/) | Java Bean 转换 | 1.4.1 | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao) |
110 111 | [Lombok](https://projectlombok.org/) | 消除冗长的 Java 代码 | 1.16.14 | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao) |
111 112 | [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.7.0 | - |
112 113 | [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 3.6.28 | - |
113 114  
114   -**前端**
  115 +### 前端
115 116  
116 117 | 框架 | 说明 | 版本 |
117 118 | --- | --- | --- |
... ...
lombok.config 0 → 100644
  1 +config.stopBubbling = true
  2 +lombok.tostring.callsuper=true
  3 +lombok.equalsandhashcode.callsuper=true
  4 +lombok.accessors.chain=true
... ...
... ... @@ -22,15 +22,16 @@
22 22 <maven.compiler.target>${java.version}</maven.compiler.target>
23 23 <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
24 24 <!-- 统一依赖管理 -->
25   - <spring.boot.version>2.4.2</spring.boot.version>
  25 + <spring.boot.version>2.4.4</spring.boot.version>
26 26 <!-- Web 相关 -->
27 27 <knife4j.version>3.0.2</knife4j.version>
28 28 <swagger-annotations.version>1.5.22</swagger-annotations.version>
29 29 <!-- DB 相关 -->
30 30 <mysql-connector-java.version>5.1.46</mysql-connector-java.version>
31 31 <druid.version>1.2.4</druid.version>
32   - <mybatis-plus.version>3.4.1</mybatis-plus.version>
33   - <redisson.version>3.14.1</redisson.version>
  32 + <mybatis-plus.version>3.4.2</mybatis-plus.version>
  33 + <dynamic-datasource.version>3.3.2</dynamic-datasource.version>
  34 + <redisson.version>3.15.1</redisson.version>
34 35 <!-- Config 配置中心相关 -->
35 36 <apollo.version>1.7.0</apollo.version>
36 37 <!-- 服务保障相关 -->
... ... @@ -42,10 +43,16 @@
42 43 <!-- 工具类相关 -->
43 44 <lombok.version>1.16.14</lombok.version>
44 45 <mapstruct.version>1.4.1.Final</mapstruct.version>
45   - <hutool.version>5.5.6</hutool.version>
  46 + <hutool.version>5.6.1</hutool.version>
46 47 <easyexcel.verion>2.2.7</easyexcel.verion>
47 48 <velocity.version>2.2</velocity.version>
48 49 <screw.version>1.0.5</screw.version>
  50 + <podam.version>7.2.6.RELEASE</podam.version>
  51 + <jedis-mock.version>0.1.16</jedis-mock.version>
  52 + <!-- 三方云服务相关 -->
  53 + <aliyun-java-sdk-core.version>4.5.18</aliyun-java-sdk-core.version>
  54 + <aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version>
  55 + <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
49 56 </properties>
50 57  
51 58 <!-- 依赖声明 -->
... ... @@ -133,6 +140,11 @@
133 140 <artifactId>mybatis-plus-boot-starter</artifactId>
134 141 <version>${mybatis-plus.version}</version>
135 142 </dependency>
  143 + <dependency>
  144 + <groupId>com.baomidou</groupId>
  145 + <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <!-- 多数据源 -->
  146 + <version>${dynamic-datasource.version}</version>
  147 + </dependency>
136 148  
137 149 <dependency>
138 150 <groupId>org.redisson</groupId>
... ... @@ -212,14 +224,14 @@
212 224 <dependency>
213 225 <groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 -->
214 226 <artifactId>jedis-mock</artifactId>
215   - <version>0.1.16</version>
  227 + <version>${jedis-mock.version}</version>
216 228 <scope>test</scope>
217 229 </dependency>
218 230  
219 231 <dependency>
220 232 <groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 -->
221 233 <artifactId>podam</artifactId>
222   - <version>7.2.6.RELEASE</version>
  234 + <version>${podam.version}</version>
223 235 <scope>test</scope>
224 236 </dependency>
225 237  
... ... @@ -237,33 +249,19 @@
237 249 </dependency>
238 250 <dependency>
239 251 <groupId>org.mapstruct</groupId>
240   - <artifactId>mapstruct-jdk8</artifactId>
  252 + <artifactId>mapstruct-processor</artifactId>
241 253 <version>${mapstruct.version}</version>
242   - </dependency>
243   -
244   - <dependency>
245   - <groupId>cn.hutool</groupId>
246   - <artifactId>hutool-core</artifactId>
247   - <version>${hutool.version}</version>
248   - </dependency>
249   - <dependency>
250   - <groupId>cn.hutool</groupId>
251   - <artifactId>hutool-extra</artifactId>
252   - <version>${hutool.version}</version>
253   - </dependency>
254   - <dependency>
255   - <groupId>cn.hutool</groupId>
256   - <artifactId>hutool-captcha</artifactId>
257   - <version>${hutool.version}</version>
  254 + <optional>true</optional>
258 255 </dependency>
259 256 <dependency>
260   - <groupId>cn.hutool</groupId>
261   - <artifactId>hutool-http</artifactId>
262   - <version>${hutool.version}</version>
  257 + <groupId>org.mapstruct</groupId>
  258 + <artifactId>mapstruct-jdk8</artifactId>
  259 + <version>${mapstruct.version}</version>
263 260 </dependency>
  261 +
264 262 <dependency>
265 263 <groupId>cn.hutool</groupId>
266   - <artifactId>hutool-crypto</artifactId>
  264 + <artifactId>hutool-all</artifactId>
267 265 <version>${hutool.version}</version>
268 266 </dependency>
269 267  
... ... @@ -285,6 +283,27 @@
285 283 <version>${screw.version}</version>
286 284 </dependency>
287 285  
  286 + <!-- 三方云服务相关 -->
  287 +
  288 + <!-- SMS SDK begin -->
  289 + <dependency>
  290 + <groupId>com.yunpian.sdk</groupId>
  291 + <artifactId>yunpian-java-sdk</artifactId>
  292 + <version>${yunpian-java-sdk.version}</version>
  293 + </dependency>
  294 +
  295 + <dependency>
  296 + <groupId>com.aliyun</groupId>
  297 + <artifactId>aliyun-java-sdk-core</artifactId>
  298 + <version>${aliyun-java-sdk-core.version}</version>
  299 + </dependency>
  300 + <dependency>
  301 + <groupId>com.aliyun</groupId>
  302 + <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
  303 + <version>${aliyun-java-sdk-dysmsapi.version}</version>
  304 + </dependency>
  305 + <!-- SMS SDK end -->
  306 +
288 307 </dependencies>
289 308  
290 309  
... ...
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java deleted
1   -package com.ruoyi.common.annotation;
2   -
3   -import java.lang.annotation.Documented;
4   -import java.lang.annotation.ElementType;
5   -import java.lang.annotation.Retention;
6   -import java.lang.annotation.RetentionPolicy;
7   -import java.lang.annotation.Target;
8   -
9   -/**
10   - * 数据权限过滤注解
11   - *
12   - * @author ruoyi
13   - */
14   -@Target(ElementType.METHOD)
15   -@Retention(RetentionPolicy.RUNTIME)
16   -@Documented
17   -public @interface DataScope {
18   - /**
19   - * 部门表的别名
20   - */
21   - public String deptAlias() default "";
22   -
23   - /**
24   - * 用户表的别名
25   - */
26   - public String userAlias() default "";
27   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScopeAspect.java deleted
1   -package com.ruoyi.framework.aspectj;
2   -
3   -import java.lang.reflect.Method;
4   -
5   -import org.aspectj.lang.JoinPoint;
6   -import org.aspectj.lang.Signature;
7   -import org.aspectj.lang.annotation.Aspect;
8   -import org.aspectj.lang.annotation.Before;
9   -import org.aspectj.lang.annotation.Pointcut;
10   -import org.aspectj.lang.reflect.MethodSignature;
11   -import org.springframework.stereotype.Component;
12   -import com.ruoyi.common.annotation.DataScope;
13   -import com.ruoyi.common.core.domain.BaseEntity;
14   -import com.ruoyi.common.core.domain.entity.SysRole;
15   -import com.ruoyi.common.core.domain.entity.SysUser;
16   -import com.ruoyi.common.core.domain.model.LoginUser;
17   -import com.ruoyi.common.utils.ServletUtils;
18   -import com.ruoyi.common.utils.StringUtils;
19   -import com.ruoyi.common.utils.spring.SpringUtils;
20   -import com.ruoyi.framework.web.service.TokenService;
21   -
22   -/**
23   - * 数据过滤处理
24   - *
25   - * @author ruoyi
26   - */
27   -@Aspect
28   -@Component
29   -public class DataScopeAspect {
30   - /**
31   - * 全部数据权限
32   - */
33   - public static final String DATA_SCOPE_ALL = "1";
34   -
35   - /**
36   - * 自定数据权限
37   - */
38   - public static final String DATA_SCOPE_CUSTOM = "2";
39   -
40   - /**
41   - * 部门数据权限
42   - */
43   - public static final String DATA_SCOPE_DEPT = "3";
44   -
45   - /**
46   - * 部门及以下数据权限
47   - */
48   - public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
49   -
50   - /**
51   - * 仅本人数据权限
52   - */
53   - public static final String DATA_SCOPE_SELF = "5";
54   -
55   - /**
56   - * 数据权限过滤关键字
57   - */
58   - public static final String DATA_SCOPE = "dataScope";
59   -
60   - // 配置织入点
61   - @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)")
62   - public void dataScopePointCut() {
63   - }
64   -
65   - @Before("dataScopePointCut()")
66   - public void doBefore(JoinPoint point) throws Throwable {
67   - handleDataScope(point);
68   - }
69   -
70   - protected void handleDataScope(final JoinPoint joinPoint) {
71   - // 获得注解
72   - DataScope controllerDataScope = getAnnotationLog(joinPoint);
73   - if (controllerDataScope == null) {
74   - return;
75   - }
76   - // 获取当前的用户
77   - LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
78   - if (StringUtils.isNotNull(loginUser)) {
79   - SysUser currentUser = loginUser.getUser();
80   - // 如果是超级管理员,则不过滤数据
81   - if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
82   - dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
83   - controllerDataScope.userAlias());
84   - }
85   - }
86   - }
87   -
88   - /**
89   - * 数据范围过滤
90   - *
91   - * @param joinPoint 切点
92   - * @param user 用户
93   - * @param userAlias 别名
94   - */
95   - public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) {
96   - StringBuilder sqlString = new StringBuilder();
97   -
98   - for (SysRole role : user.getRoles()) {
99   - String dataScope = role.getDataScope();
100   - if (DATA_SCOPE_ALL.equals(dataScope)) {
101   - sqlString = new StringBuilder();
102   - break;
103   - } else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {
104   - sqlString.append(StringUtils.format(
105   - " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
106   - role.getRoleId()));
107   - } else if (DATA_SCOPE_DEPT.equals(dataScope)) {
108   - sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
109   - } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
110   - sqlString.append(StringUtils.format(
111   - " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
112   - deptAlias, user.getDeptId(), user.getDeptId()));
113   - } else if (DATA_SCOPE_SELF.equals(dataScope)) {
114   - if (StringUtils.isNotBlank(userAlias)) {
115   - sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
116   - } else {
117   - // 数据权限为仅本人且没有userAlias别名不查询任何数据
118   - sqlString.append(" OR 1=0 ");
119   - }
120   - }
121   - }
122   -
123   - if (StringUtils.isNotBlank(sqlString.toString())) {
124   - Object params = joinPoint.getArgs()[0];
125   - if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
126   - BaseEntity baseEntity = (BaseEntity) params;
127   - baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
128   - }
129   - }
130   - }
131   -
132   - /**
133   - * 是否存在注解,如果存在就获取
134   - */
135   - private DataScope getAnnotationLog(JoinPoint joinPoint) {
136   - Signature signature = joinPoint.getSignature();
137   - MethodSignature methodSignature = (MethodSignature) signature;
138   - Method method = methodSignature.getMethod();
139   -
140   - if (method != null) {
141   - return method.getAnnotation(DataScope.class);
142   - }
143   - return null;
144   - }
145   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java deleted
1   -package com.ruoyi.common.annotation;
2   -
3   -import java.lang.annotation.Documented;
4   -import java.lang.annotation.ElementType;
5   -import java.lang.annotation.Inherited;
6   -import java.lang.annotation.Retention;
7   -import java.lang.annotation.RetentionPolicy;
8   -import java.lang.annotation.Target;
9   -
10   -import com.ruoyi.common.enums.DataSourceType;
11   -
12   -/**
13   - * 自定义多数据源切换注解
14   - * <p>
15   - * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
16   - *
17   - * @author ruoyi
18   - */
19   -@Target({ElementType.METHOD, ElementType.TYPE})
20   -@Retention(RetentionPolicy.RUNTIME)
21   -@Documented
22   -@Inherited
23   -public @interface DataSource {
24   - /**
25   - * 切换数据源名称
26   - */
27   - public DataSourceType value() default DataSourceType.MASTER;
28   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceAspect.java deleted
1   -package com.ruoyi.framework.aspectj;
2   -
3   -import java.util.Objects;
4   -
5   -import org.aspectj.lang.ProceedingJoinPoint;
6   -import org.aspectj.lang.annotation.Around;
7   -import org.aspectj.lang.annotation.Aspect;
8   -import org.aspectj.lang.annotation.Pointcut;
9   -import org.aspectj.lang.reflect.MethodSignature;
10   -import org.slf4j.Logger;
11   -import org.slf4j.LoggerFactory;
12   -import org.springframework.core.annotation.AnnotationUtils;
13   -import org.springframework.core.annotation.Order;
14   -import org.springframework.stereotype.Component;
15   -import com.ruoyi.common.annotation.DataSource;
16   -import com.ruoyi.common.utils.StringUtils;
17   -import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
18   -
19   -/**
20   - * 多数据源处理
21   - *
22   - * @author ruoyi
23   - */
24   -@Aspect
25   -@Order(1)
26   -@Component
27   -public class DataSourceAspect {
28   - protected Logger logger = LoggerFactory.getLogger(getClass());
29   -
30   - @Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
31   - + "|| @within(com.ruoyi.common.annotation.DataSource)")
32   - public void dsPointCut() {
33   -
34   - }
35   -
36   - @Around("dsPointCut()")
37   - public Object around(ProceedingJoinPoint point) throws Throwable {
38   - DataSource dataSource = getDataSource(point);
39   -
40   - if (StringUtils.isNotNull(dataSource)) {
41   - DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
42   - }
43   -
44   - try {
45   - return point.proceed();
46   - } finally {
47   - // 销毁数据源 在执行方法之后
48   - DynamicDataSourceContextHolder.clearDataSourceType();
49   - }
50   - }
51   -
52   - /**
53   - * 获取需要切换的数据源
54   - */
55   - public DataSource getDataSource(ProceedingJoinPoint point) {
56   - MethodSignature signature = (MethodSignature) point.getSignature();
57   - DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
58   - if (Objects.nonNull(dataSource)) {
59   - return dataSource;
60   - }
61   -
62   - return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
63   - }
64   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSourceType.java deleted
1   -package com.ruoyi.common.enums;
2   -
3   -/**
4   - * 数据源
5   - *
6   - * @author ruoyi
7   - */
8   -public enum DataSourceType
9   -{
10   - /**
11   - * 主库
12   - */
13   - MASTER,
14   -
15   - /**
16   - * 从库
17   - */
18   - SLAVE
19   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSource.java deleted
1   -package com.ruoyi.framework.datasource;
2   -
3   -import java.util.Map;
4   -import javax.sql.DataSource;
5   -
6   -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
7   -
8   -/**
9   - * 动态数据源
10   - *
11   - * @author ruoyi
12   - */
13   -public class DynamicDataSource extends AbstractRoutingDataSource {
14   - public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
15   - super.setDefaultTargetDataSource(defaultTargetDataSource);
16   - super.setTargetDataSources(targetDataSources);
17   - super.afterPropertiesSet();
18   - }
19   -
20   - @Override
21   - protected Object determineCurrentLookupKey() {
22   - return DynamicDataSourceContextHolder.getDataSourceType();
23   - }
24   -}
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicDataSourceContextHolder.java deleted
1   -package com.ruoyi.framework.datasource;
2   -
3   -import org.slf4j.Logger;
4   -import org.slf4j.LoggerFactory;
5   -
6   -/**
7   - * 数据源切换处理
8   - *
9   - * @author ruoyi
10   - */
11   -public class DynamicDataSourceContextHolder {
12   - public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
13   -
14   - /**
15   - * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
16   - * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
17   - */
18   - private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
19   -
20   - /**
21   - * 设置数据源的变量
22   - */
23   - public static void setDataSourceType(String dsType) {
24   - log.info("切换到{}数据源", dsType);
25   - CONTEXT_HOLDER.set(dsType);
26   - }
27   -
28   - /**
29   - * 获得数据源的变量
30   - */
31   - public static String getDataSourceType() {
32   - return CONTEXT_HOLDER.get();
33   - }
34   -
35   - /**
36   - * 清空数据源变量
37   - */
38   - public static void clearDataSourceType() {
39   - CONTEXT_HOLDER.remove();
40   - }
41   -}
ruoyi-common/src/main/java/com/ruoyi/common/config/DruidConfig.java deleted
1   -package com.ruoyi.framework.config;
2   -
3   -import java.io.IOException;
4   -import java.util.HashMap;
5   -import java.util.Map;
6   -import javax.servlet.Filter;
7   -import javax.servlet.FilterChain;
8   -import javax.servlet.ServletException;
9   -import javax.servlet.ServletRequest;
10   -import javax.servlet.ServletResponse;
11   -import javax.sql.DataSource;
12   -
13   -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
14   -import org.springframework.boot.context.properties.ConfigurationProperties;
15   -import org.springframework.boot.web.servlet.FilterRegistrationBean;
16   -import org.springframework.context.annotation.Bean;
17   -import org.springframework.context.annotation.Configuration;
18   -import org.springframework.context.annotation.Primary;
19   -import com.alibaba.druid.pool.DruidDataSource;
20   -import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
21   -import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
22   -import com.alibaba.druid.util.Utils;
23   -import com.ruoyi.common.enums.DataSourceType;
24   -import com.ruoyi.common.utils.spring.SpringUtils;
25   -import com.ruoyi.framework.config.properties.DruidProperties;
26   -import com.ruoyi.framework.datasource.DynamicDataSource;
27   -
28   -/**
29   - * druid 配置多数据源
30   - *
31   - * @author ruoyi
32   - */
33   -@Configuration
34   -public class DruidConfig {
35   - @Bean
36   - @ConfigurationProperties("spring.datasource.druid.master")
37   - public DataSource masterDataSource(DruidProperties druidProperties) {
38   - DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
39   - return druidProperties.dataSource(dataSource);
40   - }
41   -
42   - @Bean
43   - @ConfigurationProperties("spring.datasource.druid.slave")
44   - @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
45   - public DataSource slaveDataSource(DruidProperties druidProperties) {
46   - DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
47   - return druidProperties.dataSource(dataSource);
48   - }
49   -
50   - @Bean(name = "dynamicDataSource")
51   - @Primary
52   - public DynamicDataSource dataSource(DataSource masterDataSource) {
53   - Map<Object, Object> targetDataSources = new HashMap<>();
54   - targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
55   - setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
56   - return new DynamicDataSource(masterDataSource, targetDataSources);
57   - }
58   -
59   - /**
60   - * 设置数据源
61   - *
62   - * @param targetDataSources 备选数据源集合
63   - * @param sourceName 数据源名称
64   - * @param beanName bean名称
65   - */
66   - public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName) {
67   - try {
68   - DataSource dataSource = SpringUtils.getBean(beanName);
69   - targetDataSources.put(sourceName, dataSource);
70   - } catch (Exception e) {
71   - }
72   - }
73   -
74   - /**
75   - * 去除监控页面底部的广告
76   - */
77   - @SuppressWarnings({"rawtypes", "unchecked"})
78   - @Bean
79   - @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
80   - public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {
81   - // 获取web监控页面的参数
82   - DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
83   - // 提取common.js的配置路径
84   - String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
85   - String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
86   - final String filePath = "support/http/resources/js/common.js";
87   - // 创建filter进行过滤
88   - Filter filter = new Filter() {
89   - @Override
90   - public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
91   - }
92   -
93   - @Override
94   - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
95   - throws IOException, ServletException {
96   - chain.doFilter(request, response);
97   - // 重置缓冲区,响应头不会被重置
98   - response.resetBuffer();
99   - // 获取common.js
100   - String text = Utils.readFromResource(filePath);
101   - // 正则替换banner, 除去底部的广告信息
102   - text = text.replaceAll("<a.*?banner\"></a><br/>", "");
103   - text = text.replaceAll("powered.*?shrek.wang</a>", "");
104   - response.getWriter().write(text);
105   - }
106   -
107   - @Override
108   - public void destroy() {
109   - }
110   - };
111   - FilterRegistrationBean registrationBean = new FilterRegistrationBean();
112   - registrationBean.setFilter(filter);
113   - registrationBean.addUrlPatterns(commonJsPattern);
114   - return registrationBean;
115   - }
116   -}
ruoyi-common/src/main/resources/application-druid.yml deleted
1   -# 数据源配置
2   -spring:
3   - datasource:
4   - type: com.alibaba.druid.pool.DruidDataSource
5   - driverClassName: com.mysql.cj.jdbc.Driver
6   - druid:
7   - # 主库数据源
8   - master:
9   - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
10   - username: root
11   - password: password
12   - # 从库数据源
13   - slave:
14   - # 从数据源开关/默认关闭
15   - enabled: false
16   - url:
17   - username:
18   - password:
19   - # 初始连接数
20   - initialSize: 5
21   - # 最小连接池数量
22   - minIdle: 10
23   - # 最大连接池数量
24   - maxActive: 20
25   - # 配置获取连接等待超时的时间
26   - maxWait: 60000
27   - # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
28   - timeBetweenEvictionRunsMillis: 60000
29   - # 配置一个连接在池中最小生存的时间,单位是毫秒
30   - minEvictableIdleTimeMillis: 300000
31   - # 配置一个连接在池中最大生存的时间,单位是毫秒
32   - maxEvictableIdleTimeMillis: 900000
33   - # 配置检测连接是否有效
34   - validationQuery: SELECT 1 FROM DUAL
35   - testWhileIdle: true
36   - testOnBorrow: false
37   - testOnReturn: false
ruoyi-ui/.env.demo1024 0 → 100644
  1 +NODE_ENV = production
  2 +
  3 +# 测试环境配置
  4 +ENV = 'staging'
  5 +
  6 +# 芋道管理系统/测试环境
  7 +VUE_APP_BASE_API = 'http://127.0.0.1:48080'
... ...
ruoyi-ui/package.json
... ... @@ -8,6 +8,7 @@
8 8 "dev": "vue-cli-service serve",
9 9 "build:prod": "vue-cli-service build",
10 10 "build:stage": "vue-cli-service build --mode staging",
  11 + "build:demo1024": "vue-cli-service build --mode demo1024",
11 12 "preview": "node build/index.js --preview",
12 13 "lint": "eslint --ext .js,.vue src"
13 14 },
... ...
ruoyi-ui/src/api/infra/dbDoc.js
... ... @@ -8,3 +8,19 @@ export function exportHtml() {
8 8 responseType: 'blob'
9 9 })
10 10 }
  11 +
  12 +export function exportWord() {
  13 + return request({
  14 + url: '/infra/db-doc/export-word',
  15 + method: 'get',
  16 + responseType: 'blob'
  17 + })
  18 +}
  19 +
  20 +export function exportMarkdown() {
  21 + return request({
  22 + url: '/infra/db-doc/export-markdown',
  23 + method: 'get',
  24 + responseType: 'blob'
  25 + })
  26 +}
... ...
ruoyi-ui/src/api/infra/file.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 删除文件
  4 +export function deleteFile(id) {
  5 + return request({
  6 + url: '/infra/file/delete?id=' + id,
  7 + method: 'delete'
  8 + })
  9 +}
  10 +
  11 +// 获得文件分页
  12 +export function getFilePage(query) {
  13 + return request({
  14 + url: '/infra/file/page',
  15 + method: 'get',
  16 + params: query
  17 + })
  18 +}
... ...
ruoyi-ui/src/api/system/dept.js
... ... @@ -46,7 +46,7 @@ export function addDept(data) {
46 46 export function updateDept(data) {
47 47 return request({
48 48 url: '/system/dept/update',
49   - method: 'post',
  49 + method: 'put',
50 50 data: data
51 51 })
52 52 }
... ... @@ -55,6 +55,6 @@ export function updateDept(data) {
55 55 export function delDept(id) {
56 56 return request({
57 57 url: '/system/dept/delete?id=' + id,
58   - method: 'post'
  58 + method: 'delete'
59 59 })
60 60 }
... ...
ruoyi-ui/src/api/system/dict/data.js
... ... @@ -38,7 +38,7 @@ export function addData(data) {
38 38 export function updateData(data) {
39 39 return request({
40 40 url: '/system/dict-data/update',
41   - method: 'post',
  41 + method: 'put',
42 42 data: data
43 43 })
44 44 }
... ... @@ -47,7 +47,7 @@ export function updateData(data) {
47 47 export function delData(dictCode) {
48 48 return request({
49 49 url: '/system/dict-data/delete?id=' + dictCode,
50   - method: 'post'
  50 + method: 'delete'
51 51 })
52 52 }
53 53  
... ...
ruoyi-ui/src/api/system/dict/type.js
... ... @@ -30,7 +30,7 @@ export function addType(data) {
30 30 export function updateType(data) {
31 31 return request({
32 32 url: '/system/dict-type/update',
33   - method: 'post',
  33 + method: 'put',
34 34 data: data
35 35 })
36 36 }
... ... @@ -39,7 +39,7 @@ export function updateType(data) {
39 39 export function delType(dictId) {
40 40 return request({
41 41 url: '/system/dict-type/delete?id=' + dictId,
42   - method: 'post'
  42 + method: 'delete'
43 43 })
44 44 }
45 45  
... ...
ruoyi-ui/src/api/system/menu.js
... ... @@ -38,7 +38,7 @@ export function addMenu(data) {
38 38 export function updateMenu(data) {
39 39 return request({
40 40 url: '/system/menu/update',
41   - method: 'post',
  41 + method: 'put',
42 42 data: data
43 43 })
44 44 }
... ... @@ -47,6 +47,6 @@ export function updateMenu(data) {
47 47 export function delMenu(id) {
48 48 return request({
49 49 url: '/system/menu/delete?id=' + id,
50   - method: 'post'
  50 + method: 'delete'
51 51 })
52 52 }
... ...
ruoyi-ui/src/api/system/notice.js
... ... @@ -30,7 +30,7 @@ export function addNotice(data) {
30 30 export function updateNotice(data) {
31 31 return request({
32 32 url: '/system/notice/update',
33   - method: 'post',
  33 + method: 'put',
34 34 data: data
35 35 })
36 36 }
... ... @@ -39,6 +39,6 @@ export function updateNotice(data) {
39 39 export function delNotice(noticeId) {
40 40 return request({
41 41 url: '/system/notice/delete?id=' + noticeId,
42   - method: 'post'
  42 + method: 'delete'
43 43 })
44 44 }
... ...
ruoyi-ui/src/api/system/post.js
... ... @@ -38,7 +38,7 @@ export function addPost(data) {
38 38 export function updatePost(data) {
39 39 return request({
40 40 url: '/system/post/update',
41   - method: 'post',
  41 + method: 'put',
42 42 data: data
43 43 })
44 44 }
... ... @@ -47,7 +47,7 @@ export function updatePost(data) {
47 47 export function delPost(postId) {
48 48 return request({
49 49 url: '/system/post/delete?id=' + postId,
50   - method: 'post'
  50 + method: 'delete'
51 51 })
52 52 }
53 53  
... ...
ruoyi-ui/src/api/system/role.js
... ... @@ -38,7 +38,7 @@ export function addRole(data) {
38 38 export function updateRole(data) {
39 39 return request({
40 40 url: '/system/role/update',
41   - method: 'post',
  41 + method: 'put',
42 42 data: data
43 43 })
44 44 }
... ... @@ -51,7 +51,7 @@ export function changeRoleStatus(id, status) {
51 51 }
52 52 return request({
53 53 url: '/system/role/update-status',
54   - method: 'post',
  54 + method: 'put',
55 55 data: data
56 56 })
57 57 }
... ... @@ -60,7 +60,7 @@ export function changeRoleStatus(id, status) {
60 60 export function delRole(roleId) {
61 61 return request({
62 62 url: '/system/role/delete?id=' + roleId,
63   - method: 'post'
  63 + method: 'delete'
64 64 })
65 65 }
66 66  
... ...
ruoyi-ui/src/api/system/sms/smsChannel.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建短信渠道
  4 +export function createSmsChannel(data) {
  5 + return request({
  6 + url: '/system/sms-channel/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新短信渠道
  13 +export function updateSmsChannel(data) {
  14 + return request({
  15 + url: '/system/sms-channel/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除短信渠道
  22 +export function deleteSmsChannel(id) {
  23 + return request({
  24 + url: '/system/sms-channel/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得短信渠道
  30 +export function getSmsChannel(id) {
  31 + return request({
  32 + url: '/system/sms-channel/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得短信渠道分页
  38 +export function getSmsChannelPage(query) {
  39 + return request({
  40 + url: '/system/sms-channel/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
  45 +
  46 +// 获得短信渠道精简列表
  47 +export function getSimpleSmsChannels() {
  48 + return request({
  49 + url: '/system/sms-channel/list-all-simple',
  50 + method: 'get',
  51 + })
  52 +}
... ...
ruoyi-ui/src/api/system/sms/smsLog.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得短信日志分页
  4 +export function getSmsLogPage(query) {
  5 + return request({
  6 + url: '/system/sms-log/page',
  7 + method: 'get',
  8 + params: query
  9 + })
  10 +}
  11 +
  12 +// 导出短信日志 Excel
  13 +export function exportSmsLogExcel(query) {
  14 + return request({
  15 + url: '/system/sms-log/export-excel',
  16 + method: 'get',
  17 + params: query,
  18 + responseType: 'blob'
  19 + })
  20 +}
... ...
ruoyi-ui/src/api/system/sms/smsTemplate.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建短信模板
  4 +export function createSmsTemplate(data) {
  5 + return request({
  6 + url: '/system/sms-template/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新短信模板
  13 +export function updateSmsTemplate(data) {
  14 + return request({
  15 + url: '/system/sms-template/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除短信模板
  22 +export function deleteSmsTemplate(id) {
  23 + return request({
  24 + url: '/system/sms-template/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +// 获得短信模板
  30 +export function getSmsTemplate(id) {
  31 + return request({
  32 + url: '/system/sms-template/get?id=' + id,
  33 + method: 'get'
  34 + })
  35 +}
  36 +
  37 +// 获得短信模板分页
  38 +export function getSmsTemplatePage(query) {
  39 + return request({
  40 + url: '/system/sms-template/page',
  41 + method: 'get',
  42 + params: query
  43 + })
  44 +}
  45 +
  46 +// 创建短信模板
  47 +export function sendSms(data) {
  48 + return request({
  49 + url: '/system/sms-template/send-sms',
  50 + method: 'post',
  51 + data: data
  52 + })
  53 +}
  54 +
  55 +// 导出短信模板 Excel
  56 +export function exportSmsTemplateExcel(query) {
  57 + return request({
  58 + url: '/system/sms-template/export-excel',
  59 + method: 'get',
  60 + params: query,
  61 + responseType: 'blob'
  62 + })
  63 +}
  64 +
... ...
ruoyi-ui/src/api/system/user.js
... ... @@ -31,7 +31,7 @@ export function addUser(data) {
31 31 export function updateUser(data) {
32 32 return request({
33 33 url: '/system/user/update',
34   - method: 'post',
  34 + method: 'put',
35 35 data: data
36 36 })
37 37 }
... ... @@ -62,7 +62,7 @@ export function resetUserPwd(id, password) {
62 62 }
63 63 return request({
64 64 url: '/system/user/update-password',
65   - method: 'post',
  65 + method: 'put',
66 66 data: data
67 67 })
68 68 }
... ... @@ -75,7 +75,7 @@ export function changeUserStatus(id, status) {
75 75 }
76 76 return request({
77 77 url: '/system/user/update-status',
78   - method: 'post',
  78 + method: 'put',
79 79 data: data
80 80 })
81 81 }
... ... @@ -83,7 +83,7 @@ export function changeUserStatus(id, status) {
83 83 // 查询用户个人信息
84 84 export function getUserProfile() {
85 85 return request({
86   - url: '/system/user/profile',
  86 + url: '/system/user/profile/get',
87 87 method: 'get'
88 88 })
89 89 }
... ... @@ -91,7 +91,7 @@ export function getUserProfile() {
91 91 // 修改用户个人信息
92 92 export function updateUserProfile(data) {
93 93 return request({
94   - url: '/system/user/profile',
  94 + url: '/system/user/profile/update',
95 95 method: 'put',
96 96 data: data
97 97 })
... ... @@ -104,9 +104,9 @@ export function updateUserPwd(oldPassword, newPassword) {
104 104 newPassword
105 105 }
106 106 return request({
107   - url: '/system/user/profile/updatePwd',
  107 + url: '/system/user/profile/update-password',
108 108 method: 'put',
109   - params: data
  109 + data: data
110 110 })
111 111 }
112 112  
... ... @@ -114,7 +114,7 @@ export function updateUserPwd(oldPassword, newPassword) {
114 114 export function uploadAvatar(data) {
115 115 return request({
116 116 url: '/system/user/profile/avatar',
117   - method: 'post',
  117 + method: 'put',
118 118 data: data
119 119 })
120 120 }
... ...
ruoyi-ui/src/main.js
... ... @@ -25,7 +25,10 @@ import {
25 25 download,
26 26 handleTree,
27 27 downloadExcel,
28   - downloadZip
  28 + downloadWord,
  29 + downloadZip,
  30 + downloadHtml,
  31 + downloadMarkdown,
29 32 } from "@/utils/ruoyi";
30 33 import Pagination from "@/components/Pagination";
31 34 // 自定义表格工具扩展
... ... @@ -48,6 +51,9 @@ Vue.prototype.getDictDataLabel = getDictDataLabel
48 51 Vue.prototype.DICT_TYPE = DICT_TYPE
49 52 Vue.prototype.download = download
50 53 Vue.prototype.downloadExcel = downloadExcel
  54 +Vue.prototype.downloadWord = downloadWord
  55 +Vue.prototype.downloadHtml = downloadHtml
  56 +Vue.prototype.downloadMarkdown = downloadMarkdown
51 57 Vue.prototype.downloadZip = downloadZip
52 58 Vue.prototype.handleTree = handleTree
53 59  
... ...
ruoyi-ui/src/store/modules/user.js
... ... @@ -53,7 +53,7 @@ const user = {
53 53 getInfo(state.token).then(res => {
54 54 res = res.data; // 读取 data 数据
55 55 const user = res.user
56   - const avatar = user.avatar === "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
  56 + const avatar = user.avatar === "" ? require("@/assets/images/profile.jpg") : user.avatar;
57 57 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
58 58 commit('SET_ROLES', res.roles)
59 59 commit('SET_PERMISSIONS', res.permissions)
... ...
ruoyi-ui/src/utils/dict.js
... ... @@ -17,6 +17,10 @@ export const DICT_TYPE = {
17 17 SYS_OPERATE_TYPE: 'sys_operate_type',
18 18 SYS_LOGIN_RESULT: 'sys_login_result',
19 19 SYS_CONFIG_TYPE: 'sys_config_type',
  20 + SYS_SMS_CHANNEL_CODE: 'sys_sms_channel_code',
  21 + SYS_SMS_TEMPLATE_TYPE: 'sys_sms_template_type',
  22 + SYS_SMS_SEND_STATUS: 'sys_sms_send_status',
  23 + SYS_SMS_RECEIVE_STATUS: 'sys_sms_receive_status',
20 24  
21 25 INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type',
22 26 INF_JOB_STATUS: 'inf_job_status',
... ...
ruoyi-ui/src/utils/request.js
... ... @@ -73,6 +73,18 @@ service.interceptors.response.use(res =&gt; {
73 73 type: 'error'
74 74 })
75 75 return Promise.reject(new Error(msg))
  76 + } else if (code === 901) {
  77 + Message({
  78 + type: 'error',
  79 + duration: 0,
  80 + dangerouslyUseHTMLString: true,
  81 + message: '<div>演示模式,不发进行写操作</div>'
  82 + + '<div> &nbsp; </div>'
  83 + + '<div>参考 https://www.iocoder.cn/Yudao/build-debugger-environment 教程</div>'
  84 + + '<div> &nbsp; </div>'
  85 + + '<div>5 分钟搭建本地环境</div>',
  86 + })
  87 + return Promise.reject(new Error(msg))
76 88 } else if (code !== 200) {
77 89 Notification.error({
78 90 title: msg
... ...
ruoyi-ui/src/utils/ruoyi.js
... ... @@ -120,11 +120,26 @@ export function downloadExcel(data, fileName) {
120 120 download0(data, fileName, 'application/vnd.ms-excel');
121 121 }
122 122  
  123 +// 下载 Word 方法
  124 +export function downloadWord(data, fileName) {
  125 + download0(data, fileName, 'application/msword');
  126 +}
  127 +
123 128 // 下载 Zip 方法
124 129 export function downloadZip(data, fileName) {
125 130 download0(data, fileName, 'application/zip');
126 131 }
127 132  
  133 +// 下载 Html 方法
  134 +export function downloadHtml(data, fileName) {
  135 + download0(data, fileName, 'text/html');
  136 +}
  137 +
  138 +// 下载 Markdown 方法
  139 +export function downloadMarkdown(data, fileName) {
  140 + download0(data, fileName, 'text/markdown');
  141 +}
  142 +
128 143 function download0(data, fileName, mineType) {
129 144 // 创建 blob
130 145 let blob = new Blob([data], {type: mineType});
... ...
ruoyi-ui/src/views/infra/config/index.vue
... ... @@ -2,24 +2,12 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="参数名称" prop="name">
5   - <el-input
6   - v-model="queryParams.name"
7   - placeholder="请输入参数名称"
8   - clearable
9   - size="small"
10   - style="width: 240px"
11   - @keyup.enter.native="handleQuery"
12   - />
  5 + <el-input v-model="queryParams.name" placeholder="请输入参数名称" clearable size="small" style="width: 240px"
  6 + @keyup.enter.native="handleQuery"/>
13 7 </el-form-item>
14 8 <el-form-item label="参数键名" prop="key">
15   - <el-input
16   - v-model="queryParams.key"
17   - placeholder="请输入参数键名"
18   - clearable
19   - size="small"
20   - style="width: 240px"
21   - @keyup.enter.native="handleQuery"
22   - />
  9 + <el-input v-model="queryParams.key" placeholder="请输入参数键名" clearable size="small" style="width: 240px"
  10 + @keyup.enter.native="handleQuery"/>
23 11 </el-form-item>
24 12 <el-form-item label="系统内置" prop="type">
25 13 <el-select v-model="queryParams.type" placeholder="系统内置" clearable size="small">
... ... @@ -56,7 +44,7 @@
56 44 icon="el-icon-plus"
57 45 size="mini"
58 46 @click="handleAdd"
59   - v-hasPermi="['infra:config:add']"
  47 + v-hasPermi="['infra:config:create']"
60 48 >新增</el-button>
61 49 </el-col>
62 50 <el-col :span="1.5">
... ... @@ -95,31 +83,15 @@
95 83 </el-table-column>
96 84 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
97 85 <template slot-scope="scope">
98   - <el-button
99   - size="mini"
100   - type="text"
101   - icon="el-icon-edit"
102   - @click="handleUpdate(scope.row)"
103   - v-hasPermi="['infra:config:edit']"
104   - >修改</el-button>
105   - <el-button
106   - size="mini"
107   - type="text"
108   - icon="el-icon-delete"
109   - @click="handleDelete(scope.row)"
110   - v-hasPermi="['infra:config:remove']"
111   - >删除</el-button>
  86 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  87 + v-hasPermi="['infra:config:update']">修改</el-button>
  88 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  89 + v-hasPermi="['infra:config:delete']">删除</el-button>
112 90 </template>
113 91 </el-table-column>
114 92 </el-table>
115 93  
116   - <pagination
117   - v-show="total>0"
118   - :total="total"
119   - :page.sync="queryParams.pageNo"
120   - :limit.sync="queryParams.pageSize"
121   - @pagination="getList"
122   - />
  94 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" @pagination="getList"/>
123 95  
124 96 <!-- 添加或修改参数配置对话框 -->
125 97 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
... ...
ruoyi-ui/src/views/infra/file/index.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="文件路径" prop="id">
  7 + <el-input v-model="queryParams.id" placeholder="请输入文件路径" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="文件类型" prop="type">
  10 + <el-select v-model="queryParams.type" placeholder="请选择文件类型" clearable size="small">
  11 + <el-option label="请选择字典生成" value="" />
  12 + </el-select>
  13 + </el-form-item>
  14 + <el-form-item label="创建时间">
  15 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  16 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  17 + </el-form-item>
  18 + <el-form-item>
  19 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  20 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  21 + </el-form-item>
  22 + </el-form>
  23 +
  24 + <!-- 操作工具栏 -->
  25 + <el-row :gutter="10" class="mb8">
  26 + <el-col :span="1.5">
  27 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">上传文件</el-button>
  28 + </el-col>
  29 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  30 + </el-row>
  31 +
  32 + <!-- 列表 -->
  33 + <el-table v-loading="loading" :data="list">
  34 + <el-table-column label="文件路径" align="center" prop="id" width="300" />
  35 + <el-table-column label="文件类型" align="center" prop="type" width="80" />
  36 + <el-table-column label="文件内容" align="center" prop="content">
  37 + <template slot-scope="scope">
  38 + <img v-if="scope.row.type === 'jpg' || scope.row.type === 'png' || scope.row.type === 'gif'"
  39 + width="200px" :src="getFileUrl + scope.row.id">
  40 + <i v-else>非图片,无法预览</i>
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  44 + <template slot-scope="scope">
  45 + <span>{{ parseTime(scope.row.createTime) }}</span>
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  49 + <template slot-scope="scope">
  50 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  51 + v-hasPermi="['infra:file:delete']">删除</el-button>
  52 + </template>
  53 + </el-table-column>
  54 + </el-table>
  55 + <!-- 分页组件 -->
  56 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  57 + @pagination="getList"/>
  58 +
  59 + <!-- 对话框(添加 / 修改) -->
  60 + <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
  61 + <el-upload ref="upload" :limit="1" accept=".jpg, .png, .gif" :auto-upload="false" drag
  62 + :headers="upload.headers" :action="upload.url" :data="upload.data" :disabled="upload.isUploading"
  63 + :on-change="handleFileChange"
  64 + :on-progress="handleFileUploadProgress"
  65 + :on-success="handleFileSuccess">
  66 + <i class="el-icon-upload"></i>
  67 + <div class="el-upload__text">
  68 + 将文件拖到此处,或 <em>点击上传</em>
  69 + </div>
  70 + <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入 jpg、png、gif 格式文件!</div>
  71 + </el-upload>
  72 + <div slot="footer" class="dialog-footer">
  73 + <el-button type="primary" @click="submitFileForm">确 定</el-button>
  74 + <el-button @click="upload.open = false">取 消</el-button>
  75 + </div>
  76 + </el-dialog>
  77 +
  78 + </div>
  79 +</template>
  80 +
  81 +<script>
  82 +import { deleteFile, getFilePage } from "@/api/infra/file";
  83 +import {getToken} from "@/utils/auth";
  84 +
  85 +export default {
  86 + name: "File",
  87 + data() {
  88 + return {
  89 + getFileUrl: process.env.VUE_APP_BASE_API + '/api/infra/file/get/',
  90 + // 遮罩层
  91 + loading: true,
  92 + // 显示搜索条件
  93 + showSearch: true,
  94 + // 总条数
  95 + total: 0,
  96 + // 文件列表
  97 + list: [],
  98 + // 弹出层标题
  99 + title: "",
  100 + dateRangeCreateTime: [],
  101 + // 查询参数
  102 + queryParams: {
  103 + pageNo: 1,
  104 + pageSize: 10,
  105 + id: null,
  106 + type: null,
  107 + },
  108 + // 用户导入参数
  109 + upload: {
  110 + open: false, // 是否显示弹出层
  111 + title: "", // 弹出层标题
  112 + isUploading: false, // 是否禁用上传
  113 + url: process.env.VUE_APP_BASE_API + '/api/' + "/infra/file/upload", // 请求地址
  114 + headers: { Authorization: "Bearer " + getToken() }, // 设置上传的请求头部
  115 + data: {} // 上传的额外数据,用于文件名
  116 + },
  117 + };
  118 + },
  119 + created() {
  120 + this.getList();
  121 + },
  122 + methods: {
  123 + /** 查询列表 */
  124 + getList() {
  125 + this.loading = true;
  126 + // 处理查询参数
  127 + let params = {...this.queryParams};
  128 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  129 + // 执行查询
  130 + getFilePage(params).then(response => {
  131 + this.list = response.data.list;
  132 + this.total = response.data.total;
  133 + this.loading = false;
  134 + });
  135 + },
  136 + /** 取消按钮 */
  137 + cancel() {
  138 + this.open = false;
  139 + this.reset();
  140 + },
  141 + /** 表单重置 */
  142 + reset() {
  143 + this.form = {
  144 + content: undefined,
  145 + };
  146 + this.resetForm("form");
  147 + },
  148 + /** 搜索按钮操作 */
  149 + handleQuery() {
  150 + this.queryParams.pageNo = 1;
  151 + this.getList();
  152 + },
  153 + /** 重置按钮操作 */
  154 + resetQuery() {
  155 + this.dateRangeCreateTime = [];
  156 + this.resetForm("queryForm");
  157 + this.handleQuery();
  158 + },
  159 + /** 新增按钮操作 */
  160 + handleAdd() {
  161 + this.upload.open = true;
  162 + this.upload.title = "上传文件";
  163 + },
  164 + /** 处理上传的文件发生变化 */
  165 + handleFileChange(file, fileList) {
  166 + this.upload.data.path = file.name;
  167 + },
  168 + /** 处理文件上传中 */
  169 + handleFileUploadProgress(event, file, fileList) {
  170 + this.upload.isUploading = true; // 禁止修改
  171 + },
  172 + /** 发起文件上窜 */
  173 + submitFileForm() {
  174 + this.$refs.upload.submit();
  175 + },
  176 + /** 文件上传成功处理 */
  177 + handleFileSuccess(response, file, fileList) {
  178 + // 清理
  179 + this.upload.open = false;
  180 + this.upload.isUploading = false;
  181 + this.$refs.upload.clearFiles();
  182 + // 提示成功,并刷新
  183 + this.msgSuccess("上传成功");
  184 + this.getList();
  185 + },
  186 + /** 删除按钮操作 */
  187 + handleDelete(row) {
  188 + const id = row.id;
  189 + this.$confirm('是否确认删除文件编号为"' + id + '"的数据项?', "警告", {
  190 + confirmButtonText: "确定",
  191 + cancelButtonText: "取消",
  192 + type: "warning"
  193 + }).then(function() {
  194 + return deleteFile(id);
  195 + }).then(() => {
  196 + this.getList();
  197 + this.msgSuccess("删除成功");
  198 + })
  199 + },
  200 + }
  201 +};
  202 +</script>
... ...
ruoyi-ui/src/views/system/dept/index.vue
... ... @@ -2,22 +2,11 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
4 4 <el-form-item label="部门名称" prop="name">
5   - <el-input
6   - v-model="queryParams.name"
7   - placeholder="请输入部门名称"
8   - clearable
9   - size="small"
10   - @keyup.enter.native="handleQuery"
11   - />
  5 + <el-input v-model="queryParams.name" placeholder="请输入部门名称" clearable size="small" @keyup.enter.native="handleQuery"/>
12 6 </el-form-item>
13 7 <el-form-item label="状态" prop="status">
14 8 <el-select v-model="queryParams.status" placeholder="菜单状态" clearable size="small">
15   - <el-option
16   - v-for="dict in statusDictDatas"
17   - :key="parseInt(dict.value)"
18   - :label="dict.label"
19   - :value="parseInt(dict.value)"
20   - />
  9 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
21 10 </el-select>
22 11 </el-form-item>
23 12 <el-form-item>
... ... @@ -28,24 +17,13 @@
28 17  
29 18 <el-row :gutter="10" class="mb8">
30 19 <el-col :span="1.5">
31   - <el-button
32   - type="primary"
33   - icon="el-icon-plus"
34   - size="mini"
35   - @click="handleAdd"
36   - v-hasPermi="['system:dept:add']"
37   - >新增</el-button>
  20 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dept:create']">新增</el-button>
38 21 </el-col>
39 22 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
40 23 </el-row>
41 24  
42   - <el-table
43   - v-loading="loading"
44   - :data="deptList"
45   - row-key="id"
46   - default-expand-all
47   - :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
48   - >
  25 + <el-table v-loading="loading" :data="deptList" row-key="id" default-expand-all
  26 + :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
49 27 <el-table-column prop="name" label="部门名称" width="260"></el-table-column>
50 28 <el-table-column prop="sort" label="排序" width="200"></el-table-column>
51 29 <el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"></el-table-column>
... ... @@ -56,28 +34,12 @@
56 34 </el-table-column>
57 35 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
58 36 <template slot-scope="scope">
59   - <el-button
60   - size="mini"
61   - type="text"
62   - icon="el-icon-edit"
63   - @click="handleUpdate(scope.row)"
64   - v-hasPermi="['system:dept:edit']"
65   - >修改</el-button>
66   - <el-button
67   - size="mini"
68   - type="text"
69   - icon="el-icon-plus"
70   - @click="handleAdd(scope.row)"
71   - v-hasPermi="['system:dept:add']"
72   - >新增</el-button>
73   - <el-button
74   - v-if="scope.row.parentId !== 0"
75   - size="mini"
76   - type="text"
77   - icon="el-icon-delete"
78   - @click="handleDelete(scope.row)"
79   - v-hasPermi="['system:dept:remove']"
80   - >删除</el-button>
  37 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  38 + v-hasPermi="['system:dept:update']">修改</el-button>
  39 + <el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)"
  40 + v-hasPermi="['system:dept:create']">新增</el-button>
  41 + <el-button v-if="scope.row.parentId !== 0" size="mini" type="text" icon="el-icon-delete"
  42 + @click="handleDelete(scope.row)" v-hasPermi="['system:dept:delete']">删除</el-button>
81 43 </template>
82 44 </el-table-column>
83 45 </el-table>
... ... @@ -119,11 +81,8 @@
119 81 <el-col :span="12">
120 82 <el-form-item label="部门状态" prop="status">
121 83 <el-radio-group v-model="form.status">
122   - <el-radio
123   - v-for="dict in statusDictDatas"
124   - :key="parseInt(dict.value)"
125   - :label="parseInt(dict.value)"
126   - >{{dict.label}}</el-radio>
  84 + <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
  85 + {{dict.label}}</el-radio>
127 86 </el-radio-group>
128 87 </el-form-item>
129 88 </el-col>
... ...
ruoyi-ui/src/views/system/dict/data.vue
... ... @@ -3,31 +3,15 @@
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="字典名称" prop="dictType">
5 5 <el-select v-model="queryParams.dictType" size="small">
6   - <el-option
7   - v-for="item in typeOptions"
8   - :key="item.id"
9   - :label="item.name"
10   - :value="item.type"
11   - />
  6 + <el-option v-for="item in typeOptions" :key="item.id" :label="item.name" :value="item.type"/>
12 7 </el-select>
13 8 </el-form-item>
14 9 <el-form-item label="字典标签" prop="label">
15   - <el-input
16   - v-model="queryParams.label"
17   - placeholder="请输入字典标签"
18   - clearable
19   - size="small"
20   - @keyup.enter.native="handleQuery"
21   - />
  10 + <el-input v-model="queryParams.label" placeholder="请输入字典标签" clearable size="small" @keyup.enter.native="handleQuery"/>
22 11 </el-form-item>
23 12 <el-form-item label="状态" prop="status">
24 13 <el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
25   - <el-option
26   - v-for="dict in statusOptions"
27   - :key="dict.value"
28   - :label="dict.label"
29   - :value="dict.value"
30   - />
  14 + <el-option v-for="dict in statusOptions" :key="dict.value" :label="dict.label" :value="dict.value"/>
31 15 </el-select>
32 16 </el-form-item>
33 17 <el-form-item>
... ... @@ -38,22 +22,12 @@
38 22  
39 23 <el-row :gutter="10" class="mb8">
40 24 <el-col :span="1.5">
41   - <el-button
42   - type="primary"
43   - icon="el-icon-plus"
44   - size="mini"
45   - @click="handleAdd"
46   - v-hasPermi="['system:dict:add']"
47   - >新增</el-button>
  25 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  26 + v-hasPermi="['system:dict:create']">新增</el-button>
48 27 </el-col>
49 28 <el-col :span="1.5">
50   - <el-button
51   - type="warning"
52   - icon="el-icon-download"
53   - size="mini"
54   - @click="handleExport"
55   - v-hasPermi="['system:dict:export']"
56   - >导出</el-button>
  29 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  30 + v-hasPermi="['system:dict:export']">导出</el-button>
57 31 </el-col>
58 32 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
59 33 </el-row>
... ... @@ -72,31 +46,16 @@
72 46 </el-table-column>
73 47 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
74 48 <template slot-scope="scope">
75   - <el-button
76   - size="mini"
77   - type="text"
78   - icon="el-icon-edit"
79   - @click="handleUpdate(scope.row)"
80   - v-hasPermi="['system:dict:edit']"
81   - >修改</el-button>
82   - <el-button
83   - size="mini"
84   - type="text"
85   - icon="el-icon-delete"
86   - @click="handleDelete(scope.row)"
87   - v-hasPermi="['system:dict:remove']"
88   - >删除</el-button>
  49 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  50 + v-hasPermi="['system:dict:update']">修改</el-button>
  51 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  52 + v-hasPermi="['system:dict:delete']">删除</el-button>
89 53 </template>
90 54 </el-table-column>
91 55 </el-table>
92 56  
93   - <pagination
94   - v-show="total>0"
95   - :total="total"
96   - :page.sync="queryParams.pageNo"
97   - :limit.sync="queryParams.pageSize"
98   - @pagination="getList"
99   - />
  57 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  58 + @pagination="getList"/>
100 59  
101 60 <!-- 添加或修改参数配置对话框 -->
102 61 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
... ... @@ -115,11 +74,7 @@
115 74 </el-form-item>
116 75 <el-form-item label="状态" prop="status">
117 76 <el-radio-group v-model="form.status">
118   - <el-radio
119   - v-for="dict in statusDictDatas"
120   - :key="parseInt(dict.value)"
121   - :label="parseInt(dict.value)"
122   - >{{dict.label}}</el-radio>
  77 + <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
123 78 </el-radio-group>
124 79 </el-form-item>
125 80 <el-form-item label="备注" prop="remark">
... ...
ruoyi-ui/src/views/system/dict/index.vue
... ... @@ -2,52 +2,19 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="字典名称" prop="name">
5   - <el-input
6   - v-model="queryParams.name"
7   - placeholder="请输入字典名称"
8   - clearable
9   - size="small"
10   - style="width: 240px"
11   - @keyup.enter.native="handleQuery"
12   - />
  5 + <el-input v-model="queryParams.name" placeholder="请输入字典名称" clearable size="small" style="width: 240px" @keyup.enter.native="handleQuery"/>
13 6 </el-form-item>
14 7 <el-form-item label="字典类型" prop="type">
15   - <el-input
16   - v-model="queryParams.type"
17   - placeholder="请输入字典类型"
18   - clearable
19   - size="small"
20   - style="width: 240px"
21   - @keyup.enter.native="handleQuery"
22   - />
  8 + <el-input v-model="queryParams.type" placeholder="请输入字典类型" clearable size="small" style="width: 240px" @keyup.enter.native="handleQuery"/>
23 9 </el-form-item>
24 10 <el-form-item label="状态" prop="status">
25   - <el-select
26   - v-model="queryParams.status"
27   - placeholder="字典状态"
28   - clearable
29   - size="small"
30   - style="width: 240px"
31   - >
32   - <el-option
33   - v-for="dict in statusDictDatas"
34   - :key="parseInt(dict.value)"
35   - :label="dict.label"
36   - :value="parseInt(dict.value)"
37   - />
  11 + <el-select v-model="queryParams.status" placeholder="字典状态" clearable size="small" style="width: 240px">
  12 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
38 13 </el-select>
39 14 </el-form-item>
40 15 <el-form-item label="创建时间">
41   - <el-date-picker
42   - v-model="dateRangeCreateTime"
43   - size="small"
44   - style="width: 240px"
45   - value-format="yyyy-MM-dd"
46   - type="daterange"
47   - range-separator="-"
48   - start-placeholder="开始日期"
49   - end-placeholder="结束日期"
50   - ></el-date-picker>
  16 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
  17 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
51 18 </el-form-item>
52 19 <el-form-item>
53 20 <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
... ... @@ -57,22 +24,12 @@
57 24  
58 25 <el-row :gutter="10" class="mb8">
59 26 <el-col :span="1.5">
60   - <el-button
61   - type="primary"
62   - icon="el-icon-plus"
63   - size="mini"
64   - @click="handleAdd"
65   - v-hasPermi="['system:dict:add']"
66   - >新增</el-button>
  27 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  28 + v-hasPermi="['system:dict:create']">新增</el-button>
67 29 </el-col>
68 30 <el-col :span="1.5">
69   - <el-button
70   - type="warning"
71   - icon="el-icon-download"
72   - size="mini"
73   - @click="handleExport"
74   - v-hasPermi="['system:dict:export']"
75   - >导出</el-button>
  31 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  32 + v-hasPermi="['system:dict:export']">导出</el-button>
76 33 </el-col>
77 34 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
78 35 </el-row>
... ... @@ -96,31 +53,16 @@
96 53 </el-table-column>
97 54 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
98 55 <template slot-scope="scope">
99   - <el-button
100   - size="mini"
101   - type="text"
102   - icon="el-icon-edit"
103   - @click="handleUpdate(scope.row)"
104   - v-hasPermi="['system:dict:edit']"
105   - >修改</el-button>
106   - <el-button
107   - size="mini"
108   - type="text"
109   - icon="el-icon-delete"
110   - @click="handleDelete(scope.row)"
111   - v-hasPermi="['system:dict:remove']"
112   - >删除</el-button>
  56 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  57 + v-hasPermi="['system:dict:update']">修改</el-button>
  58 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  59 + v-hasPermi="['system:dict:delete']">删除</el-button>
113 60 </template>
114 61 </el-table-column>
115 62 </el-table>
116 63  
117   - <pagination
118   - v-show="total>0"
119   - :total="total"
120   - :page.sync="queryParams.pageNo"
121   - :limit.sync="queryParams.pageSize"
122   - @pagination="getList"
123   - />
  64 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  65 + @pagination="getList"/>
124 66  
125 67 <!-- 添加或修改参数配置对话框 -->
126 68 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
... ... @@ -133,11 +75,7 @@
133 75 </el-form-item>
134 76 <el-form-item label="状态" prop="status">
135 77 <el-radio-group v-model="form.status">
136   - <el-radio
137   - v-for="dict in statusDictDatas"
138   - :key="parseInt(dict.value)"
139   - :label="parseInt(dict.value)"
140   - >{{dict.label}}</el-radio>
  78 + <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
141 79 </el-radio-group>
142 80 </el-form-item>
143 81 <el-form-item label="备注" prop="remark">
... ...
ruoyi-ui/src/views/system/loginlog/index.vue
... ... @@ -2,56 +2,22 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="登录地址" prop="userIp">
5   - <el-input
6   - v-model="queryParams.userIp"
7   - placeholder="请输入登录地址"
8   - clearable
9   - style="width: 240px;"
10   - size="small"
11   - @keyup.enter.native="handleQuery"
12   - />
  5 + <el-input v-model="queryParams.userIp" placeholder="请输入登录地址" clearable style="width: 240px;" size="small"
  6 + @keyup.enter.native="handleQuery"/>
13 7 </el-form-item>
14 8 <el-form-item label="用户名称" prop="username">
15   - <el-input
16   - v-model="queryParams.username"
17   - placeholder="请输入用户名称"
18   - clearable
19   - style="width: 240px;"
20   - size="small"
21   - @keyup.enter.native="handleQuery"
22   - />
  9 + <el-input v-model="queryParams.username" placeholder="请输入用户名称" clearable style="width: 240px;" size="small"
  10 + @keyup.enter.native="handleQuery"/>
23 11 </el-form-item>
24 12 <el-form-item label="状态" prop="status">
25   - <el-select
26   - v-model="queryParams.status"
27   - placeholder="结果"
28   - clearable
29   - size="small"
30   - style="width: 240px"
31   - >
32   - <el-option
33   - :key="true"
34   - label="成功"
35   - :value="true"
36   - />
37   - <el-option
38   - :key="false"
39   - label="失败"
40   - :value="false"
41   - />
  13 + <el-select v-model="queryParams.status" placeholder="结果" clearable size="small" style="width: 240px">
  14 + <el-option :key="true" label="成功" :value="true"/>
  15 + <el-option :key="false" label="失败" :value="false"/>
42 16 </el-select>
43 17 </el-form-item>
44 18 <el-form-item label="登录时间">
45   - <el-date-picker
46   - v-model="dateRange"
47   - size="small"
48   - style="width: 240px"
49   - value-format="yyyy-MM-dd"
50   - type="daterange"
51   - range-separator="-"
52   - start-placeholder="开始日期"
53   - end-placeholder="结束日期"
54   - ></el-date-picker>
  19 + <el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  20 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
55 21 </el-form-item>
56 22 <el-form-item>
57 23 <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
... ... @@ -61,13 +27,8 @@
61 27  
62 28 <el-row :gutter="10" class="mb8">
63 29 <el-col :span="1.5">
64   - <el-button
65   - type="warning"
66   - icon="el-icon-download"
67   - size="mini"
68   - @click="handleExport"
69   - v-hasPermi="['system:login-log:export']"
70   - >导出</el-button>
  30 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  31 + v-hasPermi="['system:login-log:export']">导出</el-button>
71 32 </el-col>
72 33 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
73 34 </el-row>
... ... @@ -76,7 +37,7 @@
76 37 <el-table-column label="访问编号" align="center" prop="id" />
77 38 <el-table-column label="日志类型" align="center" prop="logType">
78 39 <template slot-scope="scope">
79   - <span>{{ scope.row.logType === 1 ? '登录' : '退出' }}</span>
  40 + <span>{{ scope.row.logType === 100 ? '登录' : '退出' }}</span>
80 41 </template>
81 42 </el-table-column>
82 43 <el-table-column label="用户名称" align="center" prop="username" />
... ... @@ -95,13 +56,8 @@
95 56 </el-table-column>
96 57 </el-table>
97 58  
98   - <pagination
99   - v-show="total>0"
100   - :total="total"
101   - :page.sync="queryParams.pageNo"
102   - :limit.sync="queryParams.pageSize"
103   - @pagination="getList"
104   - />
  59 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  60 + @pagination="getList"/>
105 61 </div>
106 62 </template>
107 63  
... ...
ruoyi-ui/src/views/system/menu/index.vue
... ... @@ -2,22 +2,11 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
4 4 <el-form-item label="菜单名称" prop="name">
5   - <el-input
6   - v-model="queryParams.name"
7   - placeholder="请输入菜单名称"
8   - clearable
9   - size="small"
10   - @keyup.enter.native="handleQuery"
11   - />
  5 + <el-input v-model="queryParams.name" placeholder="请输入菜单名称" clearable size="small" @keyup.enter.native="handleQuery"/>
12 6 </el-form-item>
13 7 <el-form-item label="状态" prop="status">
14 8 <el-select v-model="queryParams.status" placeholder="菜单状态" clearable size="small">
15   - <el-option
16   - v-for="dict in statusDictDatas"
17   - :key="parseInt(dict.value)"
18   - :label="dict.label"
19   - :value="parseInt(dict.value)"
20   - />
  9 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
21 10 </el-select>
22 11 </el-form-item>
23 12 <el-form-item>
... ... @@ -28,23 +17,14 @@
28 17  
29 18 <el-row :gutter="10" class="mb8">
30 19 <el-col :span="1.5">
31   - <el-button
32   - type="primary"
33   - icon="el-icon-plus"
34   - size="mini"
35   - @click="handleAdd"
36   - v-hasPermi="['system:menu:add']"
37   - >新增</el-button>
  20 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  21 + v-hasPermi="['system:menu:create']">新增</el-button>
38 22 </el-col>
39 23 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
40 24 </el-row>
41 25  
42   - <el-table
43   - v-loading="loading"
44   - :data="menuList"
45   - row-key="id"
46   - :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
47   - >
  26 + <el-table v-loading="loading" :data="menuList" row-key="id"
  27 + :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
48 28 <el-table-column prop="name" label="菜单名称" :show-overflow-tooltip="true" width="200"></el-table-column>
49 29 <el-table-column prop="icon" label="图标" align="center" width="100">
50 30 <template slot-scope="scope">
... ... @@ -62,26 +42,12 @@
62 42 </el-table-column>
63 43 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
64 44 <template slot-scope="scope">
65   - <el-button size="mini"
66   - type="text"
67   - icon="el-icon-edit"
68   - @click="handleUpdate(scope.row)"
69   - v-hasPermi="['system:menu:edit']"
70   - >修改</el-button>
71   - <el-button
72   - size="mini"
73   - type="text"
74   - icon="el-icon-plus"
75   - @click="handleAdd(scope.row)"
76   - v-hasPermi="['system:menu:add']"
77   - >新增</el-button>
78   - <el-button
79   - size="mini"
80   - type="text"
81   - icon="el-icon-delete"
82   - @click="handleDelete(scope.row)"
83   - v-hasPermi="['system:menu:remove']"
84   - >删除</el-button>
  45 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  46 + v-hasPermi="['system:menu:update']">修改</el-button>
  47 + <el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)"
  48 + v-hasPermi="['system:menu:create']">新增</el-button>
  49 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  50 + v-hasPermi="['system:menu:delete']">删除</el-button>
85 51 </template>
86 52 </el-table-column>
87 53 </el-table>
... ... @@ -92,43 +58,25 @@
92 58 <el-row>
93 59 <el-col :span="24">
94 60 <el-form-item label="上级菜单">
95   - <treeselect
96   - v-model="form.parentId"
97   - :options="menuOptions"
98   - :normalizer="normalizer"
99   - :show-count="true"
100   - placeholder="选择上级菜单"
101   - />
  61 + <treeselect v-model="form.parentId" :options="menuOptions" :normalizer="normalizer" :show-count="true"
  62 + placeholder="选择上级菜单"/>
102 63 </el-form-item>
103 64 </el-col>
104 65 <el-col :span="24">
105 66 <el-form-item label="菜单类型" prop="type">
106 67 <el-radio-group v-model="form.type">
107   - <el-radio
108   - v-for="dict in menuTypeDictDatas"
109   - :key="parseInt(dict.value)"
110   - :label="parseInt(dict.value)"
111   - >{{dict.label}}</el-radio>
  68 + <el-radio v-for="dict in menuTypeDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
  69 + {{dict.label}}</el-radio>
112 70 </el-radio-group>
113 71 </el-form-item>
114 72 </el-col>
115 73 <el-col :span="24">
116 74 <el-form-item v-if="form.type != '3'" label="菜单图标">
117   - <el-popover
118   - placement="bottom-start"
119   - width="460"
120   - trigger="click"
121   - @show="$refs['iconSelect'].reset()"
122   - >
  75 + <el-popover placement="bottom-start" width="460" trigger="click" @show="$refs['iconSelect'].reset()">
123 76 <IconSelect ref="iconSelect" @selected="selected" />
124 77 <el-input slot="reference" v-model="form.icon" placeholder="点击选择图标" readonly>
125   - <svg-icon
126   - v-if="form.icon"
127   - slot="prefix"
128   - :icon-class="form.icon"
129   - class="el-input__icon"
130   - style="height: 32px;width: 16px;"
131   - />
  78 + <svg-icon v-if="form.icon" slot="prefix" :icon-class="form.icon" class="el-input__icon"
  79 + style="height: 32px;width: 16px;"/>
132 80 <i v-else slot="prefix" class="el-icon-search el-input__icon" />
133 81 </el-input>
134 82 </el-popover>
... ...
ruoyi-ui/src/views/system/notice/index.vue
... ... @@ -2,31 +2,14 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="公告标题" prop="title">
5   - <el-input
6   - v-model="queryParams.title"
7   - placeholder="请输入公告标题"
8   - clearable
9   - size="small"
10   - @keyup.enter.native="handleQuery"
11   - />
  5 + <el-input v-model="queryParams.title" placeholder="请输入公告标题" clearable size="small" @keyup.enter.native="handleQuery"/>
12 6 </el-form-item>
13 7 <el-form-item label="操作人员" prop="createBy">
14   - <el-input
15   - v-model="queryParams.createBy"
16   - placeholder="请输入操作人员"
17   - clearable
18   - size="small"
19   - @keyup.enter.native="handleQuery"
20   - />
  8 + <el-input v-model="queryParams.createBy" placeholder="请输入操作人员" clearable size="small" @keyup.enter.native="handleQuery"/>
21 9 </el-form-item>
22 10 <el-form-item label="类型" prop="type">
23 11 <el-select v-model="queryParams.type" placeholder="公告类型" clearable size="small">
24   - <el-option
25   - v-for="dict in noticeTypeDictDatas"
26   - :key="parseInt(dict.value)"
27   - :label="dict.label"
28   - :value="parseInt(dict.value)"
29   - />
  12 + <el-option v-for="dict in noticeTypeDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
30 13 </el-select>
31 14 </el-form-item>
32 15 <el-form-item>
... ... @@ -37,39 +20,16 @@
37 20  
38 21 <el-row :gutter="10" class="mb8">
39 22 <el-col :span="1.5">
40   - <el-button
41   - type="primary"
42   - icon="el-icon-plus"
43   - size="mini"
44   - @click="handleAdd"
45   - v-hasPermi="['system:notice:add']"
46   - >新增</el-button>
  23 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:notice:create']"s>新增</el-button>
47 24 </el-col>
48 25 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
49 26 </el-row>
50 27  
51 28 <el-table v-loading="loading" :data="noticeList">
52 29 <el-table-column label="序号" align="center" prop="id" width="100" />
53   - <el-table-column
54   - label="公告标题"
55   - align="center"
56   - prop="title"
57   - :show-overflow-tooltip="true"
58   - />
59   - <el-table-column
60   - label="公告类型"
61   - align="center"
62   - prop="type"
63   - :formatter="typeFormat"
64   - width="100"
65   - />
66   - <el-table-column
67   - label="状态"
68   - align="center"
69   - prop="status"
70   - :formatter="statusFormat"
71   - width="100"
72   - />
  30 + <el-table-column label="公告标题" align="center" prop="title" :show-overflow-tooltip="true"/>
  31 + <el-table-column label="公告类型" align="center" prop="type" :formatter="typeFormat" width="100"/>
  32 + <el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" width="100"/>
73 33 <el-table-column label="创建者" align="center" prop="createBy" width="100" />
74 34 <el-table-column label="创建时间" align="center" prop="createTime" width="100">
75 35 <template slot-scope="scope">
... ... @@ -78,31 +38,16 @@
78 38 </el-table-column>
79 39 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
80 40 <template slot-scope="scope">
81   - <el-button
82   - size="mini"
83   - type="text"
84   - icon="el-icon-edit"
85   - @click="handleUpdate(scope.row)"
86   - v-hasPermi="['system:notice:edit']"
87   - >修改</el-button>
88   - <el-button
89   - size="mini"
90   - type="text"
91   - icon="el-icon-delete"
92   - @click="handleDelete(scope.row)"
93   - v-hasPermi="['system:notice:remove']"
94   - >删除</el-button>
  41 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  42 + v-hasPermi="['system:notice:update']">修改</el-button>
  43 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  44 + v-hasPermi="['system:notice:delete']">删除</el-button>
95 45 </template>
96 46 </el-table-column>
97 47 </el-table>
98 48  
99   - <pagination
100   - v-show="total>0"
101   - :total="total"
102   - :page.sync="queryParams.pageNo"
103   - :limit.sync="queryParams.pageSize"
104   - @pagination="getList"
105   - />
  49 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  50 + @pagination="getList"/>
106 51  
107 52 <!-- 添加或修改公告对话框 -->
108 53 <el-dialog :title="title" :visible.sync="open" width="780px" append-to-body>
... ...
ruoyi-ui/src/views/system/operatelog/index.vue
... ... @@ -2,72 +2,28 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="系统模块" prop="title">
5   - <el-input
6   - v-model="queryParams.title"
7   - placeholder="请输入系统模块"
8   - clearable
9   - style="width: 240px;"
10   - size="small"
11   - @keyup.enter.native="handleQuery"
12   - />
  5 + <el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" size="small"
  6 + @keyup.enter.native="handleQuery"/>
13 7 </el-form-item>
14 8 <el-form-item label="操作人员" prop="operName">
15   - <el-input
16   - v-model="queryParams.operName"
17   - placeholder="请输入操作人员"
18   - clearable
19   - style="width: 240px;"
20   - size="small"
21   - @keyup.enter.native="handleQuery"
22   - />
  9 + <el-input v-model="queryParams.operName" placeholder="请输入操作人员" clearable style="width: 240px;" size="small"
  10 + @keyup.enter.native="handleQuery"/>
23 11 </el-form-item>
24 12 <el-form-item label="类型" prop="type">
25   - <el-select
26   - v-model="queryParams.type"
27   - placeholder="操作类型"
28   - clearable
29   - size="small"
30   - style="width: 240px"
31   - >
32   - <el-option
33   - v-for="dict in this.getDictDatas(DICT_TYPE.SYS_OPERATE_TYPE)"
34   - :key="parseInt(dict.value)"
35   - :label="dict.label"
36   - :value="parseInt(dict.value)"
37   - />
  13 + <el-select v-model="queryParams.type" placeholder="操作类型" clearable size="small" style="width: 240px">
  14 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_OPERATE_TYPE)" :key="parseInt(dict.value)"
  15 + :label="dict.label" :value="parseInt(dict.value)"/>
38 16 </el-select>
39 17 </el-form-item>
40 18 <el-form-item label="状态" prop="status">
41   - <el-select
42   - v-model="queryParams.success"
43   - placeholder="操作状态"
44   - clearable
45   - size="small"
46   - style="width: 240px"
47   - >
48   - <el-option
49   - :key="true"
50   - label="成功"
51   - :value="true"
52   - />
53   - <el-option
54   - :key="false"
55   - label="失败"
56   - :value="false"
57   - />
  19 + <el-select v-model="queryParams.success" placeholder="操作状态" clearable size="small" style="width: 240px">
  20 + <el-option :key="true" label="成功" :value="true"/>
  21 + <el-option :key="false" label="失败" :value="false"/>
58 22 </el-select>
59 23 </el-form-item>
60 24 <el-form-item label="操作时间">
61   - <el-date-picker
62   - v-model="dateRange"
63   - size="small"
64   - style="width: 240px"
65   - value-format="yyyy-MM-dd"
66   - type="daterange"
67   - range-separator="-"
68   - start-placeholder="开始日期"
69   - end-placeholder="结束日期"
70   - ></el-date-picker>
  25 + <el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  26 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
71 27 </el-form-item>
72 28 <el-form-item>
73 29 <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
... ... @@ -77,13 +33,8 @@
77 33  
78 34 <el-row :gutter="10" class="mb8">
79 35 <el-col :span="1.5">
80   - <el-button
81   - type="warning"
82   - icon="el-icon-download"
83   - size="mini"
84   - @click="handleExport"
85   - v-hasPermi="['system:config:export']"
86   - >导出</el-button>
  36 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  37 + v-hasPermi="['system:operate-log:export']">导出</el-button>
87 38 </el-col>
88 39 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
89 40 </el-row>
... ... @@ -212,7 +163,6 @@ export default {
212 163 businessType: undefined,
213 164 status: undefined
214 165 },
215   -
216 166 };
217 167 },
218 168 created() {
... ...
ruoyi-ui/src/views/system/post/index.vue
... ... @@ -2,31 +2,14 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4 4 <el-form-item label="岗位编码" prop="code">
5   - <el-input
6   - v-model="queryParams.code"
7   - placeholder="请输入岗位编码"
8   - clearable
9   - size="small"
10   - @keyup.enter.native="handleQuery"
11   - />
  5 + <el-input v-model="queryParams.code" placeholder="请输入岗位编码" clearable size="small" @keyup.enter.native="handleQuery"/>
12 6 </el-form-item>
13 7 <el-form-item label="岗位名称" prop="name">
14   - <el-input
15   - v-model="queryParams.name"
16   - placeholder="请输入岗位名称"
17   - clearable
18   - size="small"
19   - @keyup.enter.native="handleQuery"
20   - />
  8 + <el-input v-model="queryParams.name" placeholder="请输入岗位名称" clearable size="small" @keyup.enter.native="handleQuery"/>
21 9 </el-form-item>
22 10 <el-form-item label="状态" prop="status">
23 11 <el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small">
24   - <el-option
25   - v-for="dict in statusDictDatas"
26   - :key="parseInt(dict.value)"
27   - :label="dict.label"
28   - :value="parseInt(dict.value)"
29   - />
  12 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
30 13 </el-select>
31 14 </el-form-item>
32 15 <el-form-item>
... ... @@ -37,22 +20,12 @@
37 20  
38 21 <el-row :gutter="10" class="mb8">
39 22 <el-col :span="1.5">
40   - <el-button
41   - type="primary"
42   - icon="el-icon-plus"
43   - size="mini"
44   - @click="handleAdd"
45   - v-hasPermi="['system:post:add']"
46   - >新增</el-button>
  23 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  24 + v-hasPermi="['system:post:create']">新增</el-button>
47 25 </el-col>
48 26 <el-col :span="1.5">
49   - <el-button
50   - type="warning"
51   - icon="el-icon-download"
52   - size="mini"
53   - @click="handleExport"
54   - v-hasPermi="['system:post:export']"
55   - >导出</el-button>
  27 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  28 + v-hasPermi="['system:post:export']">导出</el-button>
56 29 </el-col>
57 30 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
58 31 </el-row>
... ... @@ -70,31 +43,16 @@
70 43 </el-table-column>
71 44 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
72 45 <template slot-scope="scope">
73   - <el-button
74   - size="mini"
75   - type="text"
76   - icon="el-icon-edit"
77   - @click="handleUpdate(scope.row)"
78   - v-hasPermi="['system:post:edit']"
79   - >修改</el-button>
80   - <el-button
81   - size="mini"
82   - type="text"
83   - icon="el-icon-delete"
84   - @click="handleDelete(scope.row)"
85   - v-hasPermi="['system:post:remove']"
86   - >删除</el-button>
  46 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  47 + v-hasPermi="['system:post:update']">修改</el-button>
  48 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  49 + v-hasPermi="['system:post:delete']">删除</el-button>
87 50 </template>
88 51 </el-table-column>
89 52 </el-table>
90 53  
91   - <pagination
92   - v-show="total>0"
93   - :total="total"
94   - :page.sync="queryParams.pageNo"
95   - :limit.sync="queryParams.pageSize"
96   - @pagination="getList"
97   - />
  54 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  55 + @pagination="getList"/>
98 56  
99 57 <!-- 添加或修改岗位对话框 -->
100 58 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
... ... @@ -110,11 +68,8 @@
110 68 </el-form-item>
111 69 <el-form-item label="岗位状态" prop="status">
112 70 <el-radio-group v-model="form.status">
113   - <el-radio
114   - v-for="dict in statusDictDatas"
115   - :key="parseInt(dict.value)"
116   - :label="parseInt(dict.value)"
117   - >{{dict.label}}</el-radio>
  71 + <el-radio v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="parseInt(dict.value)">
  72 + {{dict.label}}</el-radio>
118 73 </el-radio-group>
119 74 </el-form-item>
120 75 <el-form-item label="备注" prop="remark">
... ...
ruoyi-ui/src/views/system/role/index.vue
... ... @@ -2,52 +2,21 @@
2 2 <div class="app-container">
3 3 <el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
4 4 <el-form-item label="角色名称" prop="name">
5   - <el-input
6   - v-model="queryParams.name"
7   - placeholder="请输入角色名称"
8   - clearable
9   - size="small"
10   - style="width: 240px"
11   - @keyup.enter.native="handleQuery"
12   - />
  5 + <el-input v-model="queryParams.name" placeholder="请输入角色名称" clearable size="small" style="width: 240px"
  6 + @keyup.enter.native="handleQuery"/>
13 7 </el-form-item>
14 8 <el-form-item label="角色标识" prop="code">
15   - <el-input
16   - v-model="queryParams.code"
17   - placeholder="请输入角色标识"
18   - clearable
19   - size="small"
20   - style="width: 240px"
21   - @keyup.enter.native="handleQuery"
22   - />
  9 + <el-input v-model="queryParams.code" placeholder="请输入角色标识" clearable size="small" style="width: 240px"
  10 + @keyup.enter.native="handleQuery"/>
23 11 </el-form-item>
24 12 <el-form-item label="状态" prop="status">
25   - <el-select
26   - v-model="queryParams.status"
27   - placeholder="角色状态"
28   - clearable
29   - size="small"
30   - style="width: 240px"
31   - >
32   - <el-option
33   - v-for="dict in statusDictDatas"
34   - :key="parseInt(dict.value)"
35   - :label="dict.label"
36   - :value="parseInt(dict.value)"
37   - />
  13 + <el-select v-model="queryParams.status" placeholder="角色状态" clearable size="small" style="width: 240px">
  14 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
38 15 </el-select>
39 16 </el-form-item>
40 17 <el-form-item label="创建时间">
41   - <el-date-picker
42   - v-model="dateRange"
43   - size="small"
44   - style="width: 240px"
45   - value-format="yyyy-MM-dd"
46   - type="daterange"
47   - range-separator="-"
48   - start-placeholder="开始日期"
49   - end-placeholder="结束日期"
50   - ></el-date-picker>
  18 + <el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
  19 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
51 20 </el-form-item>
52 21 <el-form-item>
53 22 <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
... ... @@ -57,22 +26,12 @@
57 26  
58 27 <el-row :gutter="10" class="mb8">
59 28 <el-col :span="1.5">
60   - <el-button
61   - type="primary"
62   - icon="el-icon-plus"
63   - size="mini"
64   - @click="handleAdd"
65   - v-hasPermi="['system:role:add']"
66   - >新增</el-button>
  29 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  30 + v-hasPermi="['system:role:create']">新增</el-button>
67 31 </el-col>
68 32 <el-col :span="1.5">
69   - <el-button
70   - type="warning"
71   - icon="el-icon-download"
72   - size="mini"
73   - @click="handleExport"
74   - v-hasPermi="['system:role:export']"
75   - >导出</el-button>
  33 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  34 + v-hasPermi="['system:role:export']">导出</el-button>
76 35 </el-col>
77 36 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
78 37 </el-row>
... ... @@ -85,12 +44,7 @@
85 44 <el-table-column label="显示顺序" prop="sort" width="100" />
86 45 <el-table-column label="状态" align="center" width="100">
87 46 <template slot-scope="scope">
88   - <el-switch
89   - v-model="scope.row.status"
90   - :active-value="0"
91   - :inactive-value="1"
92   - @change="handleStatusChange(scope.row)"
93   - ></el-switch>
  47 + <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
94 48 </template>
95 49 </el-table-column>
96 50 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
... ... @@ -100,45 +54,20 @@
100 54 </el-table-column>
101 55 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
102 56 <template slot-scope="scope">
103   - <el-button
104   - size="mini"
105   - type="text"
106   - icon="el-icon-edit"
107   - @click="handleUpdate(scope.row)"
108   - v-hasPermi="['system:role:edit']"
109   - >修改</el-button>
110   - <el-button
111   - size="mini"
112   - type="text"
113   - icon="el-icon-circle-check"
114   - @click="handleMenu(scope.row)"
115   - v-hasPermi="['system:permission:assign-role-menu']"
116   - >菜单权限</el-button>
117   - <el-button
118   - size="mini"
119   - type="text"
120   - icon="el-icon-circle-check"
121   - @click="handleDataScope(scope.row)"
122   - v-hasPermi="['system:permission:assign-role-data-scope']"
123   - >数据权限</el-button>
124   - <el-button
125   - size="mini"
126   - type="text"
127   - icon="el-icon-delete"
128   - @click="handleDelete(scope.row)"
129   - v-hasPermi="['system:role:remove']"
130   - >删除</el-button>
  57 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  58 + v-hasPermi="['system:role:update']">修改</el-button>
  59 + <el-button size="mini" type="text" icon="el-icon-circle-check" @click="handleMenu(scope.row)"
  60 + v-hasPermi="['system:permission:assign-role-menu']">菜单权限</el-button>
  61 + <el-button size="mini" type="text" icon="el-icon-circle-check" @click="handleDataScope(scope.row)"
  62 + v-hasPermi="['system:permission:assign-role-data-scope']">数据权限</el-button>
  63 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  64 + v-hasPermi="['system:role:delete']">删除</el-button>
131 65 </template>
132 66 </el-table-column>
133 67 </el-table>
134 68  
135   - <pagination
136   - v-show="total>0"
137   - :total="total"
138   - :page.sync="queryParams.pageNum"
139   - :limit.sync="queryParams.pageSize"
140   - @pagination="getList"
141   - />
  69 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
  70 + @pagination="getList"/>
142 71  
143 72 <!-- 添加或修改角色配置对话框 -->
144 73 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
... ...
ruoyi-ui/src/views/system/sms/smsChannel.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="短信签名" prop="signature">
  7 + <el-input v-model="queryParams.signature" placeholder="请输入短信签名" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="启用状态" prop="status">
  10 + <el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable size="small">
  11 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  12 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item label="创建时间">
  16 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  17 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  18 + </el-form-item>
  19 + <el-form-item>
  20 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  21 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  22 + </el-form-item>
  23 + </el-form>
  24 +
  25 + <!-- 操作工具栏 -->
  26 + <el-row :gutter="10" class="mb8">
  27 + <el-col :span="1.5">
  28 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  29 + v-hasPermi="['system:sms-channel:create']">新增</el-button>
  30 + </el-col>
  31 + <el-col :span="1.5">
  32 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  33 + v-hasPermi="['system:sms-channel:export']">导出</el-button>
  34 + </el-col>
  35 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  36 + </el-row>
  37 +
  38 + <!-- 列表 -->
  39 + <el-table v-loading="loading" :data="list">
  40 + <el-table-column label="编号" align="center" prop="id" />
  41 + <el-table-column label="短信签名" align="center" prop="signature" />
  42 + <el-table-column label="渠道编码" align="center" prop="code">
  43 + <template slot-scope="scope">
  44 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.code) }}</span>
  45 + </template>
  46 + </el-table-column>>
  47 + <el-table-column label="启用状态" align="center" prop="status">
  48 + <template slot-scope="scope">
  49 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  50 + </template>
  51 + </el-table-column>>
  52 + <el-table-column label="备注" align="center" prop="remark" />
  53 + <el-table-column label="短信 API 的账号" align="center" prop="apiKey" />
  54 + <el-table-column label="短信 API 的秘钥" align="center" prop="apiSecret" />
  55 + <el-table-column label="短信发送回调 URL" align="center" prop="callbackUrl" />
  56 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  57 + <template slot-scope="scope">
  58 + <span>{{ parseTime(scope.row.createTime) }}</span>
  59 + </template>
  60 + </el-table-column>
  61 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  62 + <template slot-scope="scope">
  63 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  64 + v-hasPermi="['system:sms-channel:update']">修改</el-button>
  65 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  66 + v-hasPermi="['system:sms-channel:delete']">删除</el-button>
  67 + </template>
  68 + </el-table-column>
  69 + </el-table>
  70 + <!-- 分页组件 -->
  71 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  72 + @pagination="getList"/>
  73 +
  74 + <!-- 对话框(添加 / 修改) -->
  75 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  76 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  77 + <el-form-item label="短信签名" prop="signature">
  78 + <el-input v-model="form.signature" placeholder="请输入短信签名" />
  79 + </el-form-item>
  80 + <el-form-item label="渠道编码" prop="code">
  81 + <el-input v-model="form.code" placeholder="请输入渠道编码" />
  82 + </el-form-item>
  83 + <el-form-item label="启用状态">
  84 + <el-radio-group v-model="form.status">
  85 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  86 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  87 + </el-radio-group>
  88 + </el-form-item>
  89 + <el-form-item label="备注" prop="remark">
  90 + <el-input v-model="form.remark" placeholder="请输入备注" />
  91 + </el-form-item>
  92 + <el-form-item label="短信 API 的账号" prop="apiKey">
  93 + <el-input v-model="form.apiKey" placeholder="请输入短信 API 的账号" />
  94 + </el-form-item>
  95 + <el-form-item label="短信 API 的秘钥" prop="apiSecret">
  96 + <el-input v-model="form.apiSecret" placeholder="请输入短信 API 的秘钥" />
  97 + </el-form-item>
  98 + <el-form-item label="短信发送回调 URL" prop="callbackUrl">
  99 + <el-input v-model="form.callbackUrl" placeholder="请输入短信发送回调 URL" />
  100 + </el-form-item>
  101 + </el-form>
  102 + <div slot="footer" class="dialog-footer">
  103 + <el-button type="primary" @click="submitForm">确 定</el-button>
  104 + <el-button @click="cancel">取 消</el-button>
  105 + </div>
  106 + </el-dialog>
  107 + </div>
  108 +</template>
  109 +
  110 +<script>
  111 +import { createSmsChannel, updateSmsChannel, deleteSmsChannel, getSmsChannel, getSmsChannelPage,
  112 + getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  113 +
  114 +export default {
  115 + name: "SmsChannel",
  116 + components: {
  117 + },
  118 + data() {
  119 + return {
  120 + // 遮罩层
  121 + loading: true,
  122 + // 显示搜索条件
  123 + showSearch: true,
  124 + // 总条数
  125 + total: 0,
  126 + // 短信渠道列表
  127 + list: [],
  128 + // 弹出层标题
  129 + title: "",
  130 + // 是否显示弹出层
  131 + open: false,
  132 + dateRangeCreateTime: [],
  133 + // 查询参数
  134 + queryParams: {
  135 + pageNo: 1,
  136 + pageSize: 10,
  137 + signature: null,
  138 + status: null,
  139 + },
  140 + // 表单参数
  141 + form: {},
  142 + // 表单校验
  143 + rules: {
  144 + signature: [{ required: true, message: "短信签名不能为空", trigger: "blur" }],
  145 + code: [{ required: true, message: "渠道编码不能为空", trigger: "blur" }],
  146 + status: [{ required: true, message: "启用状态不能为空", trigger: "blur" }],
  147 + apiKey: [{ required: true, message: "短信 API 的账号不能为空", trigger: "blur" }],
  148 + },
  149 + };
  150 + },
  151 + created() {
  152 + this.getList();
  153 + },
  154 + methods: {
  155 + /** 查询列表 */
  156 + getList() {
  157 + this.loading = true;
  158 + // 处理查询参数
  159 + let params = {...this.queryParams};
  160 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  161 + // 执行查询
  162 + getSmsChannelPage(params).then(response => {
  163 + this.list = response.data.list;
  164 + this.total = response.data.total;
  165 + this.loading = false;
  166 + });
  167 + },
  168 + /** 取消按钮 */
  169 + cancel() {
  170 + this.open = false;
  171 + this.reset();
  172 + },
  173 + /** 表单重置 */
  174 + reset() {
  175 + this.form = {
  176 + id: undefined,
  177 + signature: undefined,
  178 + code: undefined,
  179 + status: undefined,
  180 + remark: undefined,
  181 + apiKey: undefined,
  182 + apiSecret: undefined,
  183 + callbackUrl: undefined,
  184 + };
  185 + this.resetForm("form");
  186 + },
  187 + /** 搜索按钮操作 */
  188 + handleQuery() {
  189 + this.queryParams.pageNo = 1;
  190 + this.getList();
  191 + },
  192 + /** 重置按钮操作 */
  193 + resetQuery() {
  194 + this.dateRangeCreateTime = [];
  195 + this.resetForm("queryForm");
  196 + this.handleQuery();
  197 + },
  198 + /** 新增按钮操作 */
  199 + handleAdd() {
  200 + this.reset();
  201 + this.open = true;
  202 + this.title = "添加短信渠道";
  203 + },
  204 + /** 修改按钮操作 */
  205 + handleUpdate(row) {
  206 + this.reset();
  207 + const id = row.id;
  208 + getSmsChannel(id).then(response => {
  209 + this.form = response.data;
  210 + this.open = true;
  211 + this.title = "修改短信渠道";
  212 + });
  213 + },
  214 + /** 提交按钮 */
  215 + submitForm() {
  216 + this.$refs["form"].validate(valid => {
  217 + if (!valid) {
  218 + return;
  219 + }
  220 + // 修改的提交
  221 + if (this.form.id != null) {
  222 + updateSmsChannel(this.form).then(response => {
  223 + this.msgSuccess("修改成功");
  224 + this.open = false;
  225 + this.getList();
  226 + });
  227 + return;
  228 + }
  229 + // 添加的提交
  230 + createSmsChannel(this.form).then(response => {
  231 + this.msgSuccess("新增成功");
  232 + this.open = false;
  233 + this.getList();
  234 + });
  235 + });
  236 + },
  237 + /** 删除按钮操作 */
  238 + handleDelete(row) {
  239 + const id = row.id;
  240 + this.$confirm('是否确认删除短信渠道编号为"' + id + '"的数据项?', "警告", {
  241 + confirmButtonText: "确定",
  242 + cancelButtonText: "取消",
  243 + type: "warning"
  244 + }).then(function() {
  245 + return deleteSmsChannel(id);
  246 + }).then(() => {
  247 + this.getList();
  248 + this.msgSuccess("删除成功");
  249 + })
  250 + },
  251 + /** 导出按钮操作 */
  252 + handleExport() {
  253 + // 处理查询参数
  254 + let params = {...this.queryParams};
  255 + params.pageNo = undefined;
  256 + params.pageSize = undefined;
  257 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  258 + // 执行导出
  259 + this.$confirm('是否确认导出所有短信渠道数据项?', "警告", {
  260 + confirmButtonText: "确定",
  261 + cancelButtonText: "取消",
  262 + type: "warning"
  263 + }).then(function() {
  264 + return exportSmsChannelExcel(params);
  265 + }).then(response => {
  266 + this.downloadExcel(response, '短信渠道.xls');
  267 + })
  268 + }
  269 + }
  270 +};
  271 +</script><template>
  272 + <div class="app-container">
  273 +
  274 + <!-- 搜索工作栏 -->
  275 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  276 + <el-form-item label="短信签名" prop="signature">
  277 + <el-input v-model="queryParams.signature" placeholder="请输入短信签名" clearable size="small" @keyup.enter.native="handleQuery"/>
  278 + </el-form-item>
  279 + <el-form-item label="启用状态" prop="status">
  280 + <el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable size="small">
  281 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  282 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  283 + </el-select>
  284 + </el-form-item>
  285 + <el-form-item label="创建时间">
  286 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  287 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  288 + </el-form-item>
  289 + <el-form-item>
  290 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  291 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  292 + </el-form-item>
  293 + </el-form>
  294 +
  295 + <!-- 操作工具栏 -->
  296 + <el-row :gutter="10" class="mb8">
  297 + <el-col :span="1.5">
  298 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  299 + v-hasPermi="['system:sms-channel:create']">新增</el-button>
  300 + </el-col>
  301 + <el-col :span="1.5">
  302 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  303 + v-hasPermi="['system:sms-channel:export']">导出</el-button>
  304 + </el-col>
  305 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  306 + </el-row>
  307 +
  308 + <!-- 列表 -->
  309 + <el-table v-loading="loading" :data="list">
  310 + <el-table-column label="编号" align="center" prop="id" />
  311 + <el-table-column label="短信签名" align="center" prop="signature" />
  312 + <el-table-column label="渠道编码" align="center" prop="code">
  313 + <template slot-scope="scope">
  314 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.code) }}</span>
  315 + </template>
  316 + </el-table-column>>
  317 + <el-table-column label="启用状态" align="center" prop="status">
  318 + <template slot-scope="scope">
  319 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  320 + </template>
  321 + </el-table-column>>
  322 + <el-table-column label="备注" align="center" prop="remark" />
  323 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  324 + <template slot-scope="scope">
  325 + <span>{{ parseTime(scope.row.createTime) }}</span>
  326 + </template>
  327 + </el-table-column>
  328 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  329 + <template slot-scope="scope">
  330 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  331 + v-hasPermi="['system:sms-channel:update']">修改</el-button>
  332 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  333 + v-hasPermi="['system:sms-channel:delete']">删除</el-button>
  334 + </template>
  335 + </el-table-column>
  336 + </el-table>
  337 + <!-- 分页组件 -->
  338 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  339 + @pagination="getList"/>
  340 +
  341 + <!-- 对话框(添加 / 修改) -->
  342 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  343 + <el-form ref="form" :model="form" :rules="rules" label-width="130px">
  344 + <el-form-item label="短信签名" prop="signature">
  345 + <el-input v-model="form.signature" placeholder="请输入短信签名" />
  346 + </el-form-item>
  347 + <el-form-item label="渠道编码" prop="code">
  348 + <el-select v-model="form.code" placeholder="请选择渠道编码" :disabled="form.id > 0">
  349 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_CHANNEL_CODE)"
  350 + :key="dict.value" :label="dict.label" :value="dict.value" />
  351 + </el-select>
  352 + </el-form-item>
  353 + <el-form-item label="启用状态">
  354 + <el-radio-group v-model="form.status">
  355 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  356 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  357 + </el-radio-group>
  358 + </el-form-item>
  359 + <el-form-item label="备注" prop="remark">
  360 + <el-input v-model="form.remark" placeholder="请输入备注" />
  361 + </el-form-item>
  362 + <el-form-item label="短信 API 的账号" prop="apiKey">
  363 + <el-input v-model="form.apiKey" placeholder="请输入短信 API 的账号" />
  364 + </el-form-item>
  365 + <el-form-item v-if="form.code !== 'YUN_PIAN'" label="短信 API 的秘钥" prop="apiSecret">
  366 + <el-input v-model="form.apiSecret" placeholder="请输入短信 API 的秘钥" />
  367 + </el-form-item>
  368 + <el-form-item label="短信发送回调 URL" prop="callbackUrl">
  369 + <el-input v-model="form.callbackUrl" placeholder="请输入短信发送回调 URL" />
  370 + </el-form-item>
  371 + </el-form>
  372 + <div slot="footer" class="dialog-footer">
  373 + <el-button type="primary" @click="submitForm">确 定</el-button>
  374 + <el-button @click="cancel">取 消</el-button>
  375 + </div>
  376 + </el-dialog>
  377 + </div>
  378 +</template>
  379 +
  380 +<script>
  381 +import { createSmsChannel, updateSmsChannel, deleteSmsChannel, getSmsChannel, getSmsChannelPage } from "@/api/system/sms/smsChannel";
  382 +
  383 +export default {
  384 + name: "SmsChannel",
  385 + components: {
  386 + },
  387 + data() {
  388 + return {
  389 + // 遮罩层
  390 + loading: true,
  391 + // 显示搜索条件
  392 + showSearch: true,
  393 + // 总条数
  394 + total: 0,
  395 + // 短信渠道列表
  396 + list: [],
  397 + // 弹出层标题
  398 + title: "",
  399 + // 是否显示弹出层
  400 + open: false,
  401 + dateRangeCreateTime: [],
  402 + // 查询参数
  403 + queryParams: {
  404 + pageNo: 1,
  405 + pageSize: 10,
  406 + signature: null,
  407 + status: null,
  408 + },
  409 + // 表单参数
  410 + form: {},
  411 + // 表单校验
  412 + apiKeyEnableChannelCodes: ['YUN_PIAN'],
  413 + rules: {
  414 + signature: [{ required: true, message: "短信签名不能为空", trigger: "blur" }],
  415 + code: [{ required: true, message: "渠道编码不能为空", trigger: "blur" }],
  416 + status: [{ required: true, message: "启用状态不能为空", trigger: "blur" }],
  417 + apiKey: [{ required: true, message: "短信 API 的账号不能为空", trigger: "blur" }],
  418 + apiSecret: [{ required: true, message: "短信 API 的秘钥不能为空", trigger: "blur" }],
  419 + }
  420 + };
  421 + },
  422 + created() {
  423 + this.getList();
  424 + },
  425 + methods: {
  426 + /** 查询列表 */
  427 + getList() {
  428 + this.loading = true;
  429 + // 处理查询参数
  430 + let params = {...this.queryParams};
  431 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  432 + // 执行查询
  433 + getSmsChannelPage(params).then(response => {
  434 + this.list = response.data.list;
  435 + this.total = response.data.total;
  436 + this.loading = false;
  437 + });
  438 + },
  439 + /** 取消按钮 */
  440 + cancel() {
  441 + this.open = false;
  442 + this.reset();
  443 + },
  444 + /** 表单重置 */
  445 + reset() {
  446 + this.form = {
  447 + id: undefined,
  448 + signature: undefined,
  449 + code: undefined,
  450 + status: undefined,
  451 + remark: undefined,
  452 + apiKey: undefined,
  453 + apiSecret: undefined,
  454 + callbackUrl: undefined,
  455 + };
  456 + this.resetForm("form");
  457 + },
  458 + /** 搜索按钮操作 */
  459 + handleQuery() {
  460 + this.queryParams.pageNo = 1;
  461 + this.getList();
  462 + },
  463 + /** 重置按钮操作 */
  464 + resetQuery() {
  465 + this.dateRangeCreateTime = [];
  466 + this.resetForm("queryForm");
  467 + this.handleQuery();
  468 + },
  469 + /** 新增按钮操作 */
  470 + handleAdd() {
  471 + this.reset();
  472 + this.open = true;
  473 + this.title = "添加短信渠道";
  474 + },
  475 + /** 修改按钮操作 */
  476 + handleUpdate(row) {
  477 + this.reset();
  478 + const id = row.id;
  479 + getSmsChannel(id).then(response => {
  480 + this.form = response.data;
  481 + this.open = true;
  482 + this.title = "修改短信渠道";
  483 + });
  484 + },
  485 + /** 提交按钮 */
  486 + submitForm() {
  487 + this.$refs["form"].validate(valid => {
  488 + if (!valid) {
  489 + return;
  490 + }
  491 + // 修改的提交
  492 + if (this.form.id != null) {
  493 + updateSmsChannel(this.form).then(response => {
  494 + this.msgSuccess("修改成功");
  495 + this.open = false;
  496 + this.getList();
  497 + });
  498 + return;
  499 + }
  500 + // 添加的提交
  501 + createSmsChannel(this.form).then(response => {
  502 + this.msgSuccess("新增成功");
  503 + this.open = false;
  504 + this.getList();
  505 + });
  506 + });
  507 + },
  508 + /** 删除按钮操作 */
  509 + handleDelete(row) {
  510 + const id = row.id;
  511 + this.$confirm('是否确认删除短信渠道编号为"' + id + '"的数据项?', "警告", {
  512 + confirmButtonText: "确定",
  513 + cancelButtonText: "取消",
  514 + type: "warning"
  515 + }).then(function() {
  516 + return deleteSmsChannel(id);
  517 + }).then(() => {
  518 + this.getList();
  519 + this.msgSuccess("删除成功");
  520 + })
  521 + },
  522 + /** 导出按钮操作 */
  523 + handleExport() {
  524 + // 处理查询参数
  525 + let params = {...this.queryParams};
  526 + params.pageNo = undefined;
  527 + params.pageSize = undefined;
  528 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  529 + // 执行导出
  530 + this.$confirm('是否确认导出所有短信渠道数据项?', "警告", {
  531 + confirmButtonText: "确定",
  532 + cancelButtonText: "取消",
  533 + type: "warning"
  534 + }).then(function() {
  535 + return exportSmsChannelExcel(params);
  536 + }).then(response => {
  537 + this.downloadExcel(response, '短信渠道.xls');
  538 + })
  539 + }
  540 + }
  541 +};
  542 +</script>
... ...
ruoyi-ui/src/views/system/sms/smsLog.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="100px">
  6 + <el-form-item label="手机号" prop="mobile">
  7 + <el-input v-model="queryParams.mobile" placeholder="请输入手机号" clearable size="small" @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="短信渠道" prop="channelId">
  10 + <el-select v-model="queryParams.channelId" placeholder="请选择短信渠道" clearable size="small">
  11 + <el-option v-for="channel in channelOptions"
  12 + :key="channel.id" :value="channel.id"
  13 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  14 + </el-select>
  15 + </el-form-item>
  16 + <el-form-item label="模板编号" prop="templateId">
  17 + <el-input v-model="queryParams.templateId" placeholder="请输入模板编号" clearable size="small" @keyup.enter.native="handleQuery"/>
  18 + </el-form-item>
  19 + <el-form-item label="发送状态" prop="sendStatus">
  20 + <el-select v-model="queryParams.sendStatus" placeholder="请选择发送状态" clearable size="small">
  21 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_SEND_STATUS)"
  22 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  23 + </el-select>
  24 + </el-form-item>
  25 + <el-form-item label="发送时间">
  26 + <el-date-picker v-model="dateRangeSendTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  27 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  28 + </el-form-item>
  29 + <el-form-item label="接收状态" prop="receiveStatus">
  30 + <el-select v-model="queryParams.receiveStatus" placeholder="请选择接收状态" clearable size="small">
  31 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_RECEIVE_STATUS)"
  32 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  33 + </el-select>
  34 + </el-form-item>
  35 + <el-form-item label="接收时间">
  36 + <el-date-picker v-model="dateRangeReceiveTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  37 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  38 + </el-form-item>
  39 + <el-form-item>
  40 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  41 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  42 + </el-form-item>
  43 + </el-form>
  44 +
  45 + <!-- 操作工具栏 -->
  46 + <el-row :gutter="10" class="mb8">
  47 + <el-col :span="1.5">
  48 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  49 + v-hasPermi="['system:sms-log:create']">新增</el-button>
  50 + </el-col>
  51 + <el-col :span="1.5">
  52 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  53 + v-hasPermi="['system:sms-log:export']">导出</el-button>
  54 + </el-col>
  55 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  56 + </el-row>
  57 +
  58 + <!-- 列表 -->
  59 + <el-table v-loading="loading" :data="list">
  60 + <el-table-column label="编号" align="center" prop="id" />
  61 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  62 + <template slot-scope="scope">
  63 + <span>{{ parseTime(scope.row.createTime) }}</span>
  64 + </template>
  65 + </el-table-column>
  66 + <el-table-column label="手机号" align="center" prop="mobile" width="120">
  67 + <template slot-scope="scope">
  68 + <div>{{ scope.row.mobile }}</div>
  69 + <div v-if="scope.row.userType && scope.row.userId">
  70 + {{ getDictDataLabel(DICT_TYPE.USER_TYPE, scope.row.userType) + '(' + scope.row.userId + ')' }}
  71 + </div>
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column label="短信内容" align="center" prop="templateContent" width="300" />
  75 + <el-table-column label="发送状态" align="center" width="180">
  76 + <template slot-scope="scope">
  77 + <div>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_SEND_STATUS, scope.row.sendStatus) }}</div>
  78 + <div>{{ parseTime(scope.row.sendTime) }}</div>
  79 + </template>
  80 + </el-table-column>
  81 + <el-table-column label="接收状态" align="center" width="180">
  82 + <template slot-scope="scope">
  83 + <div>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_RECEIVE_STATUS, scope.row.receiveStatus) }}</div>
  84 + <div>{{ parseTime(scope.row.receiveTime) }}</div>
  85 + </template>
  86 + </el-table-column>
  87 + <el-table-column label="短信渠道" align="center" width="120">
  88 + <template slot-scope="scope">
  89 + <div>{{ formatChannelSignature(scope.row.channelId) }}</div>
  90 + <div>【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.channelCode) }}】</div>
  91 + </template>
  92 + </el-table-column>
  93 + <el-table-column label="模板编号" align="center" prop="templateId" />
  94 + <el-table-column label="短信类型" align="center" prop="templateType">
  95 + <template slot-scope="scope">
  96 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, scope.row.templateType) }}</span>
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  100 + <template slot-scope="scope">
  101 + <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row,scope.index)"
  102 + v-hasPermi="['system:sms-log:query']">详细</el-button>
  103 + </template>
  104 + </el-table-column>
  105 + </el-table>
  106 + <!-- 分页组件 -->
  107 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  108 + @pagination="getList"/>
  109 +
  110 + <!-- 短信日志详细 -->
  111 + <el-dialog title="短信日志详细" :visible.sync="open" width="700px" append-to-body>
  112 + <el-form ref="form" :model="form" label-width="140px" size="mini">
  113 + <el-row>
  114 + <el-col :span="24">
  115 + <el-form-item label="日志主键:">{{ form.id }}</el-form-item>
  116 + </el-col>
  117 + <el-col :span="24">
  118 + <el-form-item label="短信渠道:">
  119 + {{ formatChannelSignature(form.channelId) }}【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, form.channelCode) }}】
  120 + </el-form-item>
  121 + </el-col>
  122 + <el-col :span="24">
  123 + <el-form-item label="短信模板:">
  124 + {{ form.templateId }} | {{ form.templateCode}} | {{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, form.templateType) }}
  125 + </el-form-item>
  126 + </el-col>
  127 + <el-col :span="24">
  128 + <el-form-item label="API 的模板编号:">{{ form.apiTemplateId }}</el-form-item>
  129 + </el-col>
  130 + <el-col :span="24">
  131 + <el-form-item label="用户信息:">{{ form.mobile }}
  132 + <span v-if="form.userType && form.userId"> | {{ getDictDataLabel(DICT_TYPE.USER_TYPE, form.userType) }} | {{ form.userId }}</span>
  133 + </el-form-item>
  134 + </el-col>
  135 + <el-col :span="24">
  136 + <el-form-item label="短信内容:">{{ form.templateContent }}</el-form-item>
  137 + </el-col>
  138 + <el-col :span="24">
  139 + <el-form-item label="短信参数:">{{ form.templateParams }}</el-form-item>
  140 + </el-col>
  141 + <el-col :span="24">
  142 + <el-form-item label="创建时间:">{{ parseTime(form.createTime) }}</el-form-item>
  143 + </el-col>
  144 + <el-col :span="24">
  145 + <el-form-item label="发送状态:">{{ getDictDataLabel(DICT_TYPE.SYS_SMS_SEND_STATUS, form.sendStatus) }}</el-form-item>
  146 + </el-col>
  147 + <el-col :span="24">
  148 + <el-form-item label="发送时间:">{{ parseTime(form.sendTime) }}</el-form-item>
  149 + </el-col>
  150 + <el-col :span="24">
  151 + <el-form-item label="发送结果:">{{ form.sendCode }} | {{ form.sendMsg }}
  152 + </el-form-item>
  153 + </el-col>
  154 + <el-col :span="24">
  155 + <el-form-item label="API 发送结果:">{{ form.apiSendCode }} | {{ form.apiSendMsg }}</el-form-item>
  156 + </el-col>
  157 + <el-col :span="24">
  158 + <el-form-item label="API 短信编号:">{{ form.apiSerialNo }}</el-form-item>
  159 + </el-col>
  160 + <el-col :span="24">
  161 + <el-form-item label="API 请求编号:">{{ form.apiRequestId }}</el-form-item>
  162 + </el-col>
  163 + <el-col :span="24">
  164 + <el-form-item label="接收状态:">{{ getDictDataLabel(DICT_TYPE.SYS_SMS_RECEIVE_STATUS, form.receiveStatus) }}</el-form-item>
  165 + </el-col>
  166 + <el-col :span="24">
  167 + <el-form-item label="接收时间:">{{ parseTime(form.receiveTime) }}</el-form-item>
  168 + </el-col>
  169 + <el-col :span="24">
  170 + <el-form-item label="API 接收结果:">{{ form.apiReceiveCode }} | {{ form.apiReceiveMsg }}
  171 + </el-form-item>
  172 + </el-col>
  173 + </el-row>
  174 + </el-form>
  175 + <div slot="footer" class="dialog-footer">
  176 + <el-button @click="open = false">关 闭</el-button>
  177 + </div>
  178 + </el-dialog>
  179 +
  180 + </div>
  181 +</template>
  182 +
  183 +<script>
  184 +import { getSmsLogPage, exportSmsLogExcel } from "@/api/system/sms/smsLog";
  185 +import { getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  186 +
  187 +export default {
  188 + name: "SmsLog",
  189 + components: {
  190 + },
  191 + data() {
  192 + return {
  193 + // 遮罩层
  194 + loading: true,
  195 + // 显示搜索条件
  196 + showSearch: true,
  197 + // 总条数
  198 + total: 0,
  199 + // 短信日志列表
  200 + list: [],
  201 + // 弹出层标题
  202 + title: "",
  203 + // 是否显示弹出层
  204 + open: false,
  205 + dateRangeSendTime: [],
  206 + dateRangeReceiveTime: [],
  207 + // 表单参数
  208 + form: {},
  209 + // 查询参数
  210 + queryParams: {
  211 + pageNo: 1,
  212 + pageSize: 10,
  213 + channelId: null,
  214 + templateId: null,
  215 + mobile: null,
  216 + sendStatus: null,
  217 + receiveStatus: null,
  218 + },
  219 + // 短信渠道
  220 + channelOptions: [],
  221 + };
  222 + },
  223 + created() {
  224 + this.getList();
  225 + // 获得短信渠道
  226 + getSimpleSmsChannels().then(response => {
  227 + this.channelOptions = response.data;
  228 + })
  229 + },
  230 + methods: {
  231 + /** 查询列表 */
  232 + getList() {
  233 + this.loading = true;
  234 + // 处理查询参数
  235 + let params = {...this.queryParams};
  236 + this.addBeginAndEndTime(params, this.dateRangeSendTime, 'sendTime');
  237 + this.addBeginAndEndTime(params, this.dateRangeReceiveTime, 'receiveTime');
  238 + // 执行查询
  239 + getSmsLogPage(params).then(response => {
  240 + this.list = response.data.list;
  241 + this.total = response.data.total;
  242 + this.loading = false;
  243 + });
  244 + },
  245 + /** 取消按钮 */
  246 + cancel() {
  247 + this.open = false;
  248 + this.reset();
  249 + },
  250 + /** 搜索按钮操作 */
  251 + handleQuery() {
  252 + this.queryParams.pageNo = 1;
  253 + this.getList();
  254 + },
  255 + /** 重置按钮操作 */
  256 + resetQuery() {
  257 + this.dateRangeSendTime = [];
  258 + this.dateRangeReceiveTime = [];
  259 + this.resetForm("queryForm");
  260 + this.handleQuery();
  261 + },
  262 + /** 导出按钮操作 */
  263 + handleExport() {
  264 + // 处理查询参数
  265 + let params = {...this.queryParams};
  266 + params.pageNo = undefined;
  267 + params.pageSize = undefined;
  268 + this.addBeginAndEndTime(params, this.dateRangeSendTime, 'sendTime');
  269 + this.addBeginAndEndTime(params, this.dateRangeReceiveTime, 'receiveTime');
  270 + // 执行导出
  271 + this.$confirm('是否确认导出所有短信日志数据项?', "警告", {
  272 + confirmButtonText: "确定",
  273 + cancelButtonText: "取消",
  274 + type: "warning"
  275 + }).then(function() {
  276 + return exportSmsLogExcel(params);
  277 + }).then(response => {
  278 + this.downloadExcel(response, '短信日志.xls');
  279 + })
  280 + },
  281 + /** 详细按钮操作 */
  282 + handleView(row) {
  283 + this.open = true;
  284 + this.form = row;
  285 + },
  286 + /** 格式化短信渠道 */
  287 + formatChannelSignature(channelId) {
  288 + for (const channel of this.channelOptions) {
  289 + if (channel.id === channelId) {
  290 + return channel.signature;
  291 + }
  292 + }
  293 + return '找不到签名:' + channelId;
  294 + }
  295 + }
  296 +};
  297 +</script>
... ...
ruoyi-ui/src/views/system/sms/smsTemplate.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="150px">
  6 + <el-form-item label="短信类型" prop="type">
  7 + <el-select v-model="queryParams.type" placeholder="请选择短信类型" clearable size="small">
  8 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE)"
  9 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  10 + </el-select>
  11 + </el-form-item>
  12 + <el-form-item label="开启状态" prop="status">
  13 + <el-select v-model="queryParams.status" placeholder="请选择开启状态" clearable size="small">
  14 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  15 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  16 + </el-select>
  17 + </el-form-item>
  18 + <el-form-item label="模板编码" prop="code">
  19 + <el-input v-model="queryParams.code" placeholder="请输入模板编码" clearable size="small" @keyup.enter.native="handleQuery"/>
  20 + </el-form-item>
  21 + <el-form-item label="短信 API 的模板编号" prop="apiTemplateId">
  22 + <el-input v-model="queryParams.apiTemplateId" placeholder="请输入短信 API 的模板编号" clearable size="small" @keyup.enter.native="handleQuery"/>
  23 + </el-form-item>
  24 + <el-form-item label="短信渠道" prop="channelId">
  25 + <el-select v-model="queryParams.channelId" placeholder="请选择短信渠道" clearable size="small">
  26 + <el-option v-for="channel in channelOptions"
  27 + :key="channel.id" :value="channel.id"
  28 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  29 + </el-select>
  30 + </el-form-item>
  31 + <el-form-item label="创建时间">
  32 + <el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
  33 + type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
  34 + </el-form-item>
  35 + <el-form-item>
  36 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  37 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  38 + </el-form-item>
  39 + </el-form>
  40 +
  41 + <!-- 操作工具栏 -->
  42 + <el-row :gutter="10" class="mb8">
  43 + <el-col :span="1.5">
  44 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  45 + v-hasPermi="['system:sms-template:create']">新增</el-button>
  46 + </el-col>
  47 + <el-col :span="1.5">
  48 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
  49 + v-hasPermi="['system:sms-template:export']">导出</el-button>
  50 + </el-col>
  51 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  52 + </el-row>
  53 +
  54 + <!-- 列表 -->
  55 + <el-table v-loading="loading" :data="list">
  56 + <el-table-column label="模板编码" align="center" prop="code" />
  57 + <el-table-column label="模板名称" align="center" prop="name" />
  58 + <el-table-column label="模板内容" align="center" prop="content" width="300" />
  59 + <el-table-column label="短信类型" align="center" prop="type">
  60 + <template slot-scope="scope">
  61 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE, scope.row.type) }}</span>
  62 + </template>
  63 + </el-table-column>
  64 + <el-table-column label="开启状态" align="center" prop="status">
  65 + <template slot-scope="scope">
  66 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_COMMON_STATUS, scope.row.status) }}</span>
  67 + </template>
  68 + </el-table-column>
  69 + <el-table-column label="备注" align="center" prop="remark" />
  70 + <el-table-column label="短信 API 的模板编号" align="center" prop="apiTemplateId" width="180" />
  71 + <el-table-column label="短信渠道" align="center" width="120">
  72 + <template slot-scope="scope">
  73 + <div>{{ formatChannelSignature(scope.row.channelId) }}</div>
  74 + <div>【{{ getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, scope.row.channelCode) }}】</div>
  75 + </template>
  76 + </el-table-column>
  77 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  78 + <template slot-scope="scope">
  79 + <span>{{ parseTime(scope.row.createTime) }}</span>
  80 + </template>
  81 + </el-table-column>
  82 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="150">
  83 + <template slot-scope="scope">
  84 + <el-button size="mini" type="text" icon="el-icon-share" @click="handleSendSms(scope.row)"
  85 + v-hasPermi="['system:sms-template:send-sms']">测试</el-button>
  86 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  87 + v-hasPermi="['system:sms-template:update']">修改</el-button>
  88 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  89 + v-hasPermi="['system:sms-template:delete']">删除</el-button>
  90 + </template>
  91 + </el-table-column>
  92 + </el-table>
  93 + <!-- 分页组件 -->
  94 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  95 + @pagination="getList"/>
  96 +
  97 + <!-- 对话框(添加 / 修改) -->
  98 + <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
  99 + <el-form ref="form" :model="form" :rules="rules" label-width="140px">
  100 + <el-form-item label="短信渠道编号" prop="channelId">
  101 + <el-select v-model="form.channelId" placeholder="请选择短信渠道编号">
  102 + <el-option v-for="channel in channelOptions"
  103 + :key="channel.id" :value="channel.id"
  104 + :label="channel.signature + '【' + getDictDataLabel(DICT_TYPE.SYS_SMS_CHANNEL_CODE, channel.code) + '】'" />
  105 + </el-select>
  106 + </el-form-item>
  107 + <el-form-item label="短信类型" prop="type">
  108 + <el-select v-model="form.type" placeholder="请选择短信类型">
  109 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYS_SMS_TEMPLATE_TYPE)"
  110 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
  111 + </el-select>
  112 + </el-form-item>
  113 + <el-form-item label="模板编号" prop="code">
  114 + <el-input v-model="form.code" placeholder="请输入模板编号" />
  115 + </el-form-item>
  116 + <el-form-item label="模板名称" prop="name">
  117 + <el-input v-model="form.name" placeholder="请输入模板名称" />
  118 + </el-form-item>
  119 + <el-form-item label="模板内容" prop="content">
  120 + <el-input type="textarea" v-model="form.content" placeholder="请输入模板内容" />
  121 + </el-form-item>
  122 + <el-form-item label="开启状态" prop="status">
  123 + <el-radio-group v-model="form.status">
  124 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.SYS_COMMON_STATUS)"
  125 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  126 + </el-radio-group>
  127 + </el-form-item>
  128 + <el-form-item label="短信 API 模板编号" prop="apiTemplateId">
  129 + <el-input v-model="form.apiTemplateId" placeholder="请输入短信 API 的模板编号" />
  130 + </el-form-item>
  131 + <el-form-item label="备注" prop="remark">
  132 + <el-input v-model="form.remark" placeholder="请输入备注" />
  133 + </el-form-item>
  134 + </el-form>
  135 + <div slot="footer" class="dialog-footer">
  136 + <el-button type="primary" @click="submitForm">确 定</el-button>
  137 + <el-button @click="cancel">取 消</el-button>
  138 + </div>
  139 + </el-dialog>
  140 +
  141 + <!-- 对话框(发送短信) -->
  142 + <el-dialog title="测试发送短信" :visible.sync="sendSmsOpen" width="500px" append-to-body>
  143 + <el-form ref="sendSmsForm" :model="sendSmsForm" :rules="sendSmsRules" label-width="140px">
  144 + <el-form-item label="模板内容" prop="content">
  145 + <el-input v-model="sendSmsForm.content" type="textarea" placeholder="请输入模板内容" readonly />
  146 + </el-form-item>
  147 + <el-form-item label="手机号" prop="mobile">
  148 + <el-input v-model="sendSmsForm.mobile" placeholder="请输入手机号" />
  149 + </el-form-item>
  150 + <el-form-item v-for="param in sendSmsForm.params" :label="'参数 {' + param + '}'" :prop="'templateParams.' + param">
  151 + <el-input v-model="sendSmsForm.templateParams[param]" :placeholder="'请输入 ' + param + ' 参数'" />
  152 + </el-form-item>
  153 + </el-form>
  154 + <div slot="footer" class="dialog-footer">
  155 + <el-button type="primary" @click="submitSendSmsForm">确 定</el-button>
  156 + <el-button @click="cancelSendSms">取 消</el-button>
  157 + </div>
  158 + </el-dialog>
  159 +
  160 + </div>
  161 +</template>
  162 +
  163 +<script>
  164 +import { createSmsTemplate, updateSmsTemplate, deleteSmsTemplate, getSmsTemplate, getSmsTemplatePage,
  165 + exportSmsTemplateExcel, sendSms } from "@/api/system/sms/smsTemplate";
  166 +import { getSimpleSmsChannels } from "@/api/system/sms/smsChannel";
  167 +
  168 +export default {
  169 + name: "SmsTemplate",
  170 + data() {
  171 + return {
  172 + // 遮罩层
  173 + loading: true,
  174 + // 显示搜索条件
  175 + showSearch: true,
  176 + // 总条数
  177 + total: 0,
  178 + // 短信模板列表
  179 + list: [],
  180 + // 弹出层标题
  181 + title: "",
  182 + // 是否显示弹出层
  183 + open: false,
  184 + dateRangeCreateTime: [],
  185 + // 查询参数
  186 + queryParams: {
  187 + pageNo: 1,
  188 + pageSize: 10,
  189 + type: null,
  190 + status: null,
  191 + code: null,
  192 + content: null,
  193 + apiTemplateId: null,
  194 + channelId: null,
  195 + },
  196 + // 表单参数
  197 + form: {},
  198 + // 表单校验
  199 + rules: {
  200 + type: [{ required: true, message: "短信类型不能为空", trigger: "change" }],
  201 + status: [{ required: true, message: "开启状态不能为空", trigger: "blur" }],
  202 + code: [{ required: true, message: "模板编码不能为空", trigger: "blur" }],
  203 + name: [{ required: true, message: "模板名称不能为空", trigger: "blur" }],
  204 + content: [{ required: true, message: "模板内容不能为空", trigger: "blur" }],
  205 + apiTemplateId: [{ required: true, message: "短信 API 的模板编号不能为空", trigger: "blur" }],
  206 + channelId: [{ required: true, message: "短信渠道编号不能为空", trigger: "change" }],
  207 + },
  208 + // 短信渠道
  209 + channelOptions: [],
  210 + // 发送短信
  211 + sendSmsOpen: false,
  212 + sendSmsForm: {
  213 + params: [], // 模板的参数列表
  214 + },
  215 + sendSmsRules: {
  216 + mobile: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  217 + templateCode: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  218 + templateParams: { }
  219 + }
  220 + };
  221 + },
  222 + created() {
  223 + this.getList();
  224 + // 获得短信渠道
  225 + getSimpleSmsChannels().then(response => {
  226 + this.channelOptions = response.data;
  227 + })
  228 + },
  229 + methods: {
  230 + /** 查询列表 */
  231 + getList() {
  232 + this.loading = true;
  233 + // 处理查询参数
  234 + let params = {...this.queryParams};
  235 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  236 + // 执行查询
  237 + getSmsTemplatePage(params).then(response => {
  238 + this.list = response.data.list;
  239 + this.total = response.data.total;
  240 + this.loading = false;
  241 + });
  242 + },
  243 + /** 取消按钮 */
  244 + cancel() {
  245 + this.open = false;
  246 + this.reset();
  247 + },
  248 + /** 表单重置 */
  249 + reset() {
  250 + this.form = {
  251 + id: undefined,
  252 + type: undefined,
  253 + status: undefined,
  254 + code: undefined,
  255 + name: undefined,
  256 + content: undefined,
  257 + remark: undefined,
  258 + apiTemplateId: undefined,
  259 + channelId: undefined,
  260 + };
  261 + this.resetForm("form");
  262 + },
  263 + /** 搜索按钮操作 */
  264 + handleQuery() {
  265 + this.queryParams.pageNo = 1;
  266 + this.getList();
  267 + },
  268 + /** 重置按钮操作 */
  269 + resetQuery() {
  270 + this.dateRangeCreateTime = [];
  271 + this.resetForm("queryForm");
  272 + this.handleQuery();
  273 + },
  274 + /** 新增按钮操作 */
  275 + handleAdd() {
  276 + this.reset();
  277 + this.open = true;
  278 + this.title = "添加短信模板";
  279 + },
  280 + /** 修改按钮操作 */
  281 + handleUpdate(row) {
  282 + this.reset();
  283 + const id = row.id;
  284 + getSmsTemplate(id).then(response => {
  285 + this.form = response.data;
  286 + this.open = true;
  287 + this.title = "修改短信模板";
  288 + });
  289 + },
  290 + /** 提交按钮 */
  291 + submitForm() {
  292 + this.$refs["form"].validate(valid => {
  293 + if (!valid) {
  294 + return;
  295 + }
  296 + // 修改的提交
  297 + if (this.form.id != null) {
  298 + updateSmsTemplate(this.form).then(response => {
  299 + this.msgSuccess("修改成功");
  300 + this.open = false;
  301 + this.getList();
  302 + });
  303 + return;
  304 + }
  305 + // 添加的提交
  306 + createSmsTemplate(this.form).then(response => {
  307 + this.msgSuccess("新增成功");
  308 + this.open = false;
  309 + this.getList();
  310 + });
  311 + });
  312 + },
  313 + /** 删除按钮操作 */
  314 + handleDelete(row) {
  315 + const id = row.id;
  316 + this.$confirm('是否确认删除短信模板编号为"' + id + '"的数据项?', "警告", {
  317 + confirmButtonText: "确定",
  318 + cancelButtonText: "取消",
  319 + type: "warning"
  320 + }).then(function() {
  321 + return deleteSmsTemplate(id);
  322 + }).then(() => {
  323 + this.getList();
  324 + this.msgSuccess("删除成功");
  325 + })
  326 + },
  327 + /** 导出按钮操作 */
  328 + handleExport() {
  329 + // 处理查询参数
  330 + let params = {...this.queryParams};
  331 + params.pageNo = undefined;
  332 + params.pageSize = undefined;
  333 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  334 + // 执行导出
  335 + this.$confirm('是否确认导出所有短信模板数据项?', "警告", {
  336 + confirmButtonText: "确定",
  337 + cancelButtonText: "取消",
  338 + type: "warning"
  339 + }).then(function() {
  340 + return exportSmsTemplateExcel(params);
  341 + }).then(response => {
  342 + this.downloadExcel(response, '短信模板.xls');
  343 + })
  344 + },
  345 + /** 发送短息按钮 */
  346 + handleSendSms(row) {
  347 + this.resetSendSms(row);
  348 + // 设置参数
  349 + this.sendSmsForm.content = row.content;
  350 + this.sendSmsForm.params = row.params;
  351 + this.sendSmsForm.templateCode = row.code;
  352 + this.sendSmsForm.templateParams = row.params.reduce(function(obj, item) {
  353 + obj[item] = undefined;
  354 + return obj;
  355 + }, {});
  356 + // 根据 row 重置 rules
  357 + this.sendSmsRules.templateParams = row.params.reduce(function(obj, item) {
  358 + obj[item] = { required: true, message: '参数 ' + item + " 不能为空", trigger: "change" };
  359 + return obj;
  360 + }, {});
  361 + // 设置打开
  362 + this.sendSmsOpen = true;
  363 + },
  364 + /** 重置发送短信的表单 */
  365 + resetSendSms() {
  366 + // 根据 row 重置表单
  367 + this.sendSmsForm = {
  368 + content: undefined,
  369 + params: undefined,
  370 + mobile: undefined,
  371 + templateCode: undefined,
  372 + templateParams: {}
  373 + };
  374 + this.resetForm("sendSmsForm");
  375 + },
  376 + /** 取消发送短信 */
  377 + cancelSendSms() {
  378 + this.sendSmsOpen = false;
  379 + this.resetSendSms();
  380 + },
  381 + /** 提交按钮 */
  382 + submitSendSmsForm() {
  383 + this.$refs["sendSmsForm"].validate(valid => {
  384 + if (!valid) {
  385 + return;
  386 + }
  387 + // 添加的提交
  388 + sendSms(this.sendSmsForm).then(response => {
  389 + this.msgSuccess("提交发送成功!发送结果,见发送日志编号:" + response.data);
  390 + this.sendSmsOpen = false;
  391 + });
  392 + });
  393 + },
  394 + /** 格式化短信渠道 */
  395 + formatChannelSignature(channelId) {
  396 + for (const channel of this.channelOptions) {
  397 + if (channel.id === channelId) {
  398 + return channel.signature;
  399 + }
  400 + }
  401 + return '找不到签名:' + channelId;
  402 + }
  403 + }
  404 +};
  405 +</script>
... ...
ruoyi-ui/src/views/system/user/index.vue
1   -<template>
2   - <div class="app-container">
3   - <el-row :gutter="20">
4   - <!--部门数据-->
5   - <el-col :span="4" :xs="24">
6   - <div class="head-container">
7   - <el-input
8   - v-model="deptName"
9   - placeholder="请输入部门名称"
10   - clearable
11   - size="small"
12   - prefix-icon="el-icon-search"
13   - style="margin-bottom: 20px"
14   - />
15   - </div>
16   - <div class="head-container">
17   - <el-tree
18   - :data="deptOptions"
19   - :props="defaultProps"
20   - :expand-on-click-node="false"
21   - :filter-node-method="filterNode"
22   - ref="tree"
23   - default-expand-all
24   - @node-click="handleNodeClick"
25   - />
26   - </div>
27   - </el-col>
28   - <!--用户数据-->
29   - <el-col :span="20" :xs="24">
30   - <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
31   - <el-form-item label="用户名称" prop="username">
32   - <el-input
33   - v-model="queryParams.username"
34   - placeholder="请输入用户名称"
35   - clearable
36   - size="small"
37   - style="width: 240px"
38   - @keyup.enter.native="handleQuery"
39   - />
40   - </el-form-item>
41   - <el-form-item label="手机号码" prop="mobile">
42   - <el-input
43   - v-model="queryParams.mobile"
44   - placeholder="请输入手机号码"
45   - clearable
46   - size="small"
47   - style="width: 240px"
48   - @keyup.enter.native="handleQuery"
49   - />
50   - </el-form-item>
51   - <el-form-item label="状态" prop="status">
52   - <el-select
53   - v-model="queryParams.status"
54   - placeholder="用户状态"
55   - clearable
56   - size="small"
57   - style="width: 240px"
58   - >
59   - <el-option
60   - v-for="dict in statusDictDatas"
61   - :key="parseInt(dict.value)"
62   - :label="dict.label"
63   - :value="parseInt(dict.value)"
64   - />
65   - </el-select>
66   - </el-form-item>
67   - <el-form-item label="创建时间">
68   - <el-date-picker
69   - v-model="dateRange"
70   - size="small"
71   - style="width: 240px"
72   - value-format="yyyy-MM-dd"
73   - type="daterange"
74   - range-separator="-"
75   - start-placeholder="开始日期"
76   - end-placeholder="结束日期"
77   - ></el-date-picker>
78   - </el-form-item>
79   - <el-form-item>
80   - <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
81   - <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
82   - </el-form-item>
83   - </el-form>
84   -
85   - <el-row :gutter="10" class="mb8">
86   - <el-col :span="1.5">
87   - <el-button
88   - type="primary"
89   - icon="el-icon-plus"
90   - size="mini"
91   - @click="handleAdd"
92   - v-hasPermi="['system:user:add']"
93   - >新增</el-button>
94   - </el-col>
95   - <el-col :span="1.5">
96   - <el-button
97   - type="info"
98   - icon="el-icon-upload2"
99   - size="mini"
100   - @click="handleImport"
101   - v-hasPermi="['system:user:import']"
102   - >导入</el-button>
103   - </el-col>
104   - <el-col :span="1.5">
105   - <el-button
106   - type="warning"
107   - icon="el-icon-download"
108   - size="mini"
109   - @click="handleExport"
110   - v-hasPermi="['system:user:export']"
111   - >导出</el-button>
112   - </el-col>
113   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
114   - </el-row>
115   -
116   - <el-table v-loading="loading" :data="userList">
117   - <el-table-column label="用户编号" align="center" prop="id" />
118   - <el-table-column label="用户名称" align="center" prop="username" :show-overflow-tooltip="true" />
119   - <el-table-column label="用户昵称" align="center" prop="nickname" :show-overflow-tooltip="true" />
120   - <el-table-column label="部门" align="center" prop="dept.name" :show-overflow-tooltip="true" />
121   - <el-table-column label="手机号码" align="center" prop="mobile" width="120" />
122   - <el-table-column label="状态" align="center">
123   - <template slot-scope="scope">
124   - <el-switch
125   - v-model="scope.row.status"
126   - :active-value="0"
127   - :inactive-value="1"
128   - @change="handleStatusChange(scope.row)"
129   - ></el-switch>
130   - </template>
131   - </el-table-column>
132   - <el-table-column label="创建时间" align="center" prop="createTime" width="160">
133   - <template slot-scope="scope">
134   - <span>{{ parseTime(scope.row.createTime) }}</span>
135   - </template>
136   - </el-table-column>
137   - <el-table-column
138   - label="操作"
139   - align="center"
140   - width="160"
141   - class-name="small-padding fixed-width"
142   - >
143   - <template slot-scope="scope">
144   - <el-button
145   - size="mini"
146   - type="text"
147   - icon="el-icon-edit"
148   - @click="handleUpdate(scope.row)"
149   - v-hasPermi="['system:user:edit']"
150   - >修改</el-button>
151   - <el-button
152   - v-if="scope.row.id !== 1"
153   - size="mini"
154   - type="text"
155   - icon="el-icon-delete"
156   - @click="handleDelete(scope.row)"
157   - v-hasPermi="['system:user:remove']"
158   - >删除</el-button>
159   - <el-button
160   - size="mini"
161   - type="text"
162   - icon="el-icon-key"
163   - @click="handleResetPwd(scope.row)"
164   - v-hasPermi="['system:user:resetPwd']"
165   - >重置</el-button>
166   - <el-button
167   - size="mini"
168   - type="text"
169   - icon="el-icon-circle-check"
170   - @click="handleRole(scope.row)"
171   - v-hasPermi="['system:permission:assign-user-role']"
172   - >分配角色</el-button>
173   - </template>
174   - </el-table-column>
175   - </el-table>
176   -
177   - <pagination
178   - v-show="total>0"
179   - :total="total"
180   - :page.sync="queryParams.pageNo"
181   - :limit.sync="queryParams.pageSize"
182   - @pagination="getList"
183   - />
184   - </el-col>
185   - </el-row>
186   -
187   - <!-- 添加或修改参数配置对话框 -->
188   - <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
189   - <el-form ref="form" :model="form" :rules="rules" label-width="80px">
190   - <el-row>
191   - <el-col :span="12">
192   - <el-form-item label="用户昵称" prop="nickname">
193   - <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
194   - </el-form-item>
195   - </el-col>
196   - <el-col :span="12">
197   - <el-form-item label="归属部门" prop="deptId">
198   - <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true"
199   - placeholder="请选择归属部门" :normalizer="normalizer"
200   - />
201   - </el-form-item>
202   - </el-col>
203   - </el-row>
204   - <el-row>
205   - <el-col :span="12">
206   - <el-form-item label="手机号码" prop="mobile">
207   - <el-input v-model="form.mobile" placeholder="请输入手机号码" maxlength="11" />
208   - </el-form-item>
209   - </el-col>
210   - <el-col :span="12">
211   - <el-form-item label="邮箱" prop="email">
212   - <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
213   - </el-form-item>
214   - </el-col>
215   - </el-row>
216   - <el-row>
217   - <el-col :span="12">
218   - <el-form-item v-if="form.id === undefined" label="用户名称" prop="username">
219   - <el-input v-model="form.username" placeholder="请输入用户名称" />
220   - </el-form-item>
221   - </el-col>
222   - <el-col :span="12">
223   - <el-form-item v-if="form.id === undefined" label="用户密码" prop="password">
224   - <el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
225   - </el-form-item>
226   - </el-col>
227   - </el-row>
228   - <el-row>
229   - <el-col :span="12">
230   - <el-form-item label="用户性别">
231   - <el-select v-model="form.sex" placeholder="请选择">
232   - <el-option
233   - v-for="dict in sexDictDatas"
234   - :key="parseInt(dict.value)"
235   - :label="dict.label"
236   - :value="parseInt(dict.value)"
237   - ></el-option>
238   - </el-select>
239   - </el-form-item>
240   - </el-col>
241   - <el-col :span="12">
242   - <el-form-item label="岗位">
243   - <el-select v-model="form.postIds" multiple placeholder="请选择">
244   - <el-option
245   - v-for="item in postOptions"
246   - :key="item.id"
247   - :label="item.name"
248   - :value="item.id"
249   - ></el-option>
250   - </el-select>
251   - </el-form-item>
252   - </el-col>
253   - </el-row>
254   - <el-row>
255   - <el-col :span="24">
256   - <el-form-item label="备注">
257   - <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
258   - </el-form-item>
259   - </el-col>
260   - </el-row>
261   - </el-form>
262   - <div slot="footer" class="dialog-footer">
263   - <el-button type="primary" @click="submitForm">确 定</el-button>
264   - <el-button @click="cancel">取 消</el-button>
265   - </div>
266   - </el-dialog>
267   -
268   - <!-- 用户导入对话框 -->
269   - <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
270   - <el-upload
271   - ref="upload"
272   - :limit="1"
273   - accept=".xlsx, .xls"
274   - :headers="upload.headers"
275   - :action="upload.url + '?updateSupport=' + upload.updateSupport"
276   - :disabled="upload.isUploading"
277   - :on-progress="handleFileUploadProgress"
278   - :on-success="handleFileSuccess"
279   - :auto-upload="false"
280   - drag
281   - >
282   - <i class="el-icon-upload"></i>
283   - <div class="el-upload__text">
284   - 将文件拖到此处,或
285   - <em>点击上传</em>
286   - </div>
287   - <div class="el-upload__tip" slot="tip">
288   - <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
289   - <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
290   - </div>
291   - <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
292   - </el-upload>
293   - <div slot="footer" class="dialog-footer">
294   - <el-button type="primary" @click="submitFileForm">确 定</el-button>
295   - <el-button @click="upload.open = false">取 消</el-button>
296   - </div>
297   - </el-dialog>
298   -
299   - <!-- 分配角色 -->
300   - <el-dialog title="分配角色" :visible.sync="openRole" width="500px" append-to-body>
301   - <el-form :model="form" label-width="80px">
302   - <el-form-item label="用户名称">
303   - <el-input v-model="form.username" :disabled="true" />
304   - </el-form-item>
305   - <el-form-item label="用户昵称">
306   - <el-input v-model="form.nickname" :disabled="true" />
307   - </el-form-item>
308   - <el-form-item label="角色">
309   - <el-select v-model="form.roleIds" multiple placeholder="请选择">
310   - <el-option
311   - v-for="item in roleOptions"
312   - :key="parseInt(item.id)"
313   - :label="item.name"
314   - :value="parseInt(item.id)"
315   - ></el-option>
316   - </el-select>
317   - </el-form-item>
318   - </el-form>
319   - <div slot="footer" class="dialog-footer">
320   - <el-button type="primary" @click="submitRole">确 定</el-button>
321   - <el-button @click="cancelRole">取 消</el-button>
322   - </div>
323   - </el-dialog>
324   -
325   - </div>
326   -</template>
327   -
328   -<script>
329   -import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus, importTemplate } from "@/api/system/user";
330   -import { getToken } from "@/utils/auth";
331   -import Treeselect from "@riophae/vue-treeselect";
332   -import "@riophae/vue-treeselect/dist/vue-treeselect.css";
333   -
334   -import {listSimpleDepts} from "@/api/system/dept";
335   -import {listSimplePosts} from "@/api/system/post";
336   -
337   -import {SysCommonStatusEnum} from "@/utils/constants";
338   -import {DICT_TYPE, getDictDatas} from "@/utils/dict";
339   -import {assignUserRole, listUserRoles} from "@/api/system/permission";
340   -import {listSimpleRoles} from "@/api/system/role";
341   -
342   -export default {
343   - name: "User",
344   - components: { Treeselect },
345   - data() {
346   - return {
347   - // 遮罩层
348   - loading: true,
349   - // 显示搜索条件
350   - showSearch: true,
351   - // 总条数
352   - total: 0,
353   - // 用户表格数据
354   - userList: null,
355   - // 弹出层标题
356   - title: "",
357   - // 部门树选项
358   - deptOptions: undefined,
359   - // 是否显示弹出层
360   - open: false,
361   - // 部门名称
362   - deptName: undefined,
363   - // 默认密码
364   - initPassword: undefined,
365   - // 日期范围
366   - dateRange: [],
367   - // 状态数据字典
368   - statusOptions: [],
369   - // 性别状态字典
370   - sexOptions: [],
371   - // 岗位选项
372   - postOptions: [],
373   - // 角色选项
374   - roleOptions: [],
375   - // 表单参数
376   - form: {},
377   - defaultProps: {
378   - children: "children",
379   - label: "name"
380   - },
381   - // 用户导入参数
382   - upload: {
383   - // 是否显示弹出层(用户导入)
384   - open: false,
385   - // 弹出层标题(用户导入)
386   - title: "",
387   - // 是否禁用上传
388   - isUploading: false,
389   - // 是否更新已经存在的用户数据
390   - updateSupport: 0,
391   - // 设置上传的请求头部
392   - headers: { Authorization: "Bearer " + getToken() },
393   - // 上传的地址
394   - url: process.env.VUE_APP_BASE_API + '/api/' + "/system/user/import"
395   - },
396   - // 查询参数
397   - queryParams: {
398   - pageNo: 1,
399   - pageSize: 10,
400   - username: undefined,
401   - mobile: undefined,
402   - status: undefined,
403   - deptId: undefined
404   - },
405   - // 表单校验
406   - rules: {
407   - username: [
408   - { required: true, message: "用户名称不能为空", trigger: "blur" }
409   - ],
410   - nickname: [
411   - { required: true, message: "用户昵称不能为空", trigger: "blur" }
412   - ],
413   - password: [
414   - { required: true, message: "用户密码不能为空", trigger: "blur" }
415   - ],
416   - email: [
417   - {
418   - type: "email",
419   - message: "'请输入正确的邮箱地址",
420   - trigger: ["blur", "change"]
421   - }
422   - ],
423   - mobile: [
424   - {
425   - pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
426   - message: "请输入正确的手机号码",
427   - trigger: "blur"
428   - }
429   - ]
430   - },
431   - // 是否显示弹出层(角色权限)
432   - openRole: false,
433   -
434   - // 枚举
435   - SysCommonStatusEnum: SysCommonStatusEnum,
436   - // 数据字典
437   - statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
438   - sexDictDatas: getDictDatas(DICT_TYPE.SYS_USER_SEX),
439   - };
440   - },
441   - watch: {
442   - // 根据名称筛选部门树
443   - deptName(val) {
444   - this.$refs.tree.filter(val);
445   - }
446   - },
447   - created() {
448   - this.getList();
449   - this.getTreeselect();
450   - this.getConfigKey("sys.user.initPassword").then(response => {
451   - this.initPassword = response.msg;
452   - });
453   - },
454   - methods: {
455   - /** 查询用户列表 */
456   - getList() {
457   - this.loading = true;
458   - listUser(this.addDateRange(this.queryParams, [
459   - this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
460   - this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
461   - ])).then(response => {
462   - this.userList = response.data.list;
463   - this.total = response.data.total;
464   - this.loading = false;
465   - }
466   - );
467   - },
468   - /** 查询部门下拉树结构 + 岗位下拉 */
469   - getTreeselect() {
470   - listSimpleDepts().then(response => {
471   - // 处理 deptOptions 参数
472   - this.deptOptions = [];
473   - this.deptOptions.push(...this.handleTree(response.data, "id"));
474   - });
475   - listSimplePosts().then(response => {
476   - // 处理 postOptions 参数
477   - this.postOptions = [];
478   - this.postOptions.push(...response.data);
479   - });
480   - },
481   - // 筛选节点
482   - filterNode(value, data) {
483   - if (!value) return true;
484   - return data.name.indexOf(value) !== -1;
485   - },
486   - // 节点单击事件
487   - handleNodeClick(data) {
488   - this.queryParams.deptId = data.id;
489   - this.getList();
490   - },
491   - // 用户状态修改
492   - handleStatusChange(row) {
493   - let text = row.status === SysCommonStatusEnum.ENABLE ? "启用" : "停用";
494   - this.$confirm('确认要"' + text + '""' + row.username + '"用户吗?', "警告", {
495   - confirmButtonText: "确定",
496   - cancelButtonText: "取消",
497   - type: "warning"
498   - }).then(function() {
499   - return changeUserStatus(row.id, row.status);
500   - }).then(() => {
501   - this.msgSuccess(text + "成功");
502   - }).catch(function() {
503   - row.status = row.status === SysCommonStatusEnum.ENABLE ? SysCommonStatusEnum.DISABLE
504   - : SysCommonStatusEnum.ENABLE;
505   - });
506   - },
507   - // 取消按钮
508   - cancel() {
509   - this.open = false;
510   - this.reset();
511   - },
512   - // 取消按钮(角色权限)
513   - cancelRole() {
514   - this.openRole = false;
515   - this.reset();
516   - },
517   - // 表单重置
518   - reset() {
519   - this.form = {
520   - id: undefined,
521   - deptId: undefined,
522   - username: undefined,
523   - nickname: undefined,
524   - password: undefined,
525   - mobile: undefined,
526   - email: undefined,
527   - sex: undefined,
528   - status: "0",
529   - remark: undefined,
530   - postIds: [],
531   - roleIds: []
532   - };
533   - this.resetForm("form");
534   - },
535   - /** 搜索按钮操作 */
536   - handleQuery() {
537   - this.queryParams.pageNo = 1;
538   - this.getList();
539   - },
540   - /** 重置按钮操作 */
541   - resetQuery() {
542   - this.dateRange = [];
543   - this.resetForm("queryForm");
544   - this.handleQuery();
545   - },
546   - /** 新增按钮操作 */
547   - handleAdd() {
548   - this.reset();
549   - // 获得下拉数据
550   - this.getTreeselect();
551   - // 打开表单,并设置初始化
552   - this.open = true;
553   - this.title = "添加用户";
554   - this.form.password = this.initPassword;
555   - },
556   - /** 修改按钮操作 */
557   - handleUpdate(row) {
558   - this.reset();
559   - this.getTreeselect();
560   - const id = row.id;
561   - getUser(id).then(response => {
562   - this.form = response.data;
563   - this.open = true;
564   - this.title = "修改用户";
565   - this.form.password = "";
566   - });
567   - },
568   - /** 重置密码按钮操作 */
569   - handleResetPwd(row) {
570   - this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
571   - confirmButtonText: "确定",
572   - cancelButtonText: "取消"
573   - }).then(({ value }) => {
574   - resetUserPwd(row.id, value).then(response => {
575   - this.msgSuccess("修改成功,新密码是:" + value);
576   - });
577   - }).catch(() => {});
578   - },
579   - /** 分配用户角色操作 */
580   - handleRole(row) {
581   - this.reset();
582   - const id = row.id
583   - // 处理了 form 的用户 username 和 nickname 的展示
584   - this.form.id = id;
585   - this.form.username = row.username;
586   - this.form.nickname = row.nickname;
587   - // 打开弹窗
588   - this.openRole = true;
589   - // 获得角色列表
590   - listSimpleRoles().then(response => {
591   - // 处理 roleOptions 参数
592   - this.roleOptions = [];
593   - this.roleOptions.push(...response.data);
594   - });
595   - // 获得角色拥有的菜单集合
596   - listUserRoles(id).then(response => {
597   - // 设置选中
598   - this.form.roleIds = response.data;
599   - })
600   - },
601   - /** 提交按钮 */
602   - submitForm: function() {
603   - this.$refs["form"].validate(valid => {
604   - if (valid) {
605   - if (this.form.id !== undefined) {
606   - updateUser(this.form).then(response => {
607   - this.msgSuccess("修改成功");
608   - this.open = false;
609   - this.getList();
610   - });
611   - } else {
612   - addUser(this.form).then(response => {
613   - this.msgSuccess("新增成功");
614   - this.open = false;
615   - this.getList();
616   - });
617   - }
618   - }
619   - });
620   - },
621   - /** 提交按钮(角色权限) */
622   - submitRole: function() {
623   - if (this.form.id !== undefined) {
624   - assignUserRole({
625   - userId: this.form.id,
626   - roleIds: this.form.roleIds,
627   - }).then(response => {
628   - this.msgSuccess("分配角色成功");
629   - this.openRole = false;
630   - this.getList();
631   - });
632   - }
633   - },
634   - /** 删除按钮操作 */
635   - handleDelete(row) {
636   - const ids = row.id || this.ids;
637   - this.$confirm('是否确认删除用户编号为"' + ids + '"的数据项?', "警告", {
638   - confirmButtonText: "确定",
639   - cancelButtonText: "取消",
640   - type: "warning"
641   - }).then(function() {
642   - return delUser(ids);
643   - }).then(() => {
644   - this.getList();
645   - this.msgSuccess("删除成功");
646   - })
647   - },
648   - /** 导出按钮操作 */
649   - handleExport() {
650   - const queryParams = this.addDateRange(this.queryParams, [
651   - this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
652   - this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
653   - ]);
654   - this.$confirm('是否确认导出所有用户数据项?', "警告", {
655   - confirmButtonText: "确定",
656   - cancelButtonText: "取消",
657   - type: "warning"
658   - }).then(function() {
659   - return exportUser(queryParams);
660   - }).then(response => {
661   - this.downloadExcel(response, '用户数据.xls');
662   - })
663   - },
664   - /** 导入按钮操作 */
665   - handleImport() {
666   - this.upload.title = "用户导入";
667   - this.upload.open = true;
668   - },
669   - /** 下载模板操作 */
670   - importTemplate() {
671   - importTemplate().then(response => {
672   - this.downloadExcel(response, '用户导入模板.xls');
673   - });
674   - },
675   - // 文件上传中处理
676   - handleFileUploadProgress(event, file, fileList) {
677   - this.upload.isUploading = true;
678   - },
679   - // 文件上传成功处理
680   - handleFileSuccess(response, file, fileList) {
681   - this.upload.open = false;
682   - this.upload.isUploading = false;
683   - this.$refs.upload.clearFiles();
684   - // 拼接提示语
685   - let data = response.data;
686   - let text = '创建成功数量:' + data.createUsernames.length;
687   - for (const username of data.createUsernames) {
688   - text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username;
689   - }
690   - text += '<br />更新成功数量:' + data.updateUsernames.length;
691   - for (const username of data.updateUsernames) {
692   - text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username;
693   - }
694   - text += '<br />更新失败数量:' + Object.keys(data.failureUsernames).length;
695   - for (const username in data.failureUsernames) {
696   - text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username + ':' + data.failureUsernames[username];
697   - }
698   - this.$alert(text, "导入结果", { dangerouslyUseHTMLString: true });
699   - this.getList();
700   - },
701   - // 提交上传文件
702   - submitFileForm() {
703   - this.$refs.upload.submit();
704   - },
705   - // 格式化部门的下拉框
706   - normalizer(node) {
707   - return {
708   - id: node.id,
709   - label: node.name,
710   - children: node.children
711   - }
712   - }
713   - }
714   -};
715   -</script>
  1 +<template>
  2 + <div class="app-container">
  3 + <el-row :gutter="20">
  4 + <!--部门数据-->
  5 + <el-col :span="4" :xs="24">
  6 + <div class="head-container">
  7 + <el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px"/>
  8 + </div>
  9 + <div class="head-container">
  10 + <el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode"
  11 + ref="tree" default-expand-all @node-click="handleNodeClick"/>
  12 + </div>
  13 + </el-col>
  14 + <!--用户数据-->
  15 + <el-col :span="20" :xs="24">
  16 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  17 + <el-form-item label="用户名称" prop="username">
  18 + <el-input v-model="queryParams.username" placeholder="请输入用户名称" clearable size="small" style="width: 240px"
  19 + @keyup.enter.native="handleQuery"/>
  20 + </el-form-item>
  21 + <el-form-item label="手机号码" prop="mobile">
  22 + <el-input v-model="queryParams.mobile" placeholder="请输入手机号码" clearable size="small" style="width: 240px"
  23 + @keyup.enter.native="handleQuery"/>
  24 + </el-form-item>
  25 + <el-form-item label="状态" prop="status">
  26 + <el-select v-model="queryParams.status" placeholder="用户状态" clearable size="small" style="width: 240px">
  27 + <el-option v-for="dict in statusDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
  28 + </el-select>
  29 + </el-form-item>
  30 + <el-form-item label="创建时间">
  31 + <el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
  32 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
  33 + </el-form-item>
  34 + <el-form-item>
  35 + <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  36 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  37 + </el-form-item>
  38 + </el-form>
  39 +
  40 + <el-row :gutter="10" class="mb8">
  41 + <el-col :span="1.5">
  42 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd"
  43 + v-hasPermi="['system:user:create']">新增</el-button>
  44 + </el-col>
  45 + <el-col :span="1.5">
  46 + <el-button type="info" icon="el-icon-upload2" size="mini" @click="handleImport"
  47 + v-hasPermi="['system:user:import']">导入</el-button>
  48 + </el-col>
  49 + <el-col :span="1.5">
  50 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  51 + v-hasPermi="['system:user:export']">导出</el-button>
  52 + </el-col>
  53 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  54 + </el-row>
  55 +
  56 + <el-table v-loading="loading" :data="userList">
  57 + <el-table-column label="用户编号" align="center" prop="id" />
  58 + <el-table-column label="用户名称" align="center" prop="username" :show-overflow-tooltip="true" />
  59 + <el-table-column label="用户昵称" align="center" prop="nickname" :show-overflow-tooltip="true" />
  60 + <el-table-column label="部门" align="center" prop="dept.name" :show-overflow-tooltip="true" />
  61 + <el-table-column label="手机号码" align="center" prop="mobile" width="120" />
  62 + <el-table-column label="状态" align="center">
  63 + <template slot-scope="scope">
  64 + <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)" />
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column label="创建时间" align="center" prop="createTime" width="160">
  68 + <template slot-scope="scope">
  69 + <span>{{ parseTime(scope.row.createTime) }}</span>
  70 + </template>
  71 + </el-table-column>
  72 + <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
  73 + <template slot-scope="scope">
  74 + <el-button size="large" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  75 + v-hasPermi="['system:role:update']">修改</el-button>
  76 + <el-dropdown @command="(command) => handleCommand(command, scope.$index, scope.row)">
  77 + <span class="el-dropdown-link">
  78 + 更多操作<i class="el-icon-arrow-down el-icon--right"></i>
  79 + </span>
  80 + <el-dropdown-menu slot="dropdown">
  81 + <el-dropdown-item command="handleDelete" v-if="scope.row.id !== 1" size="mini" type="text" icon="el-icon-delete"
  82 + v-hasPermi="['system:user:delete']">删除</el-dropdown-item>
  83 + <el-dropdown-item command="handleResetPwd" size="mini" type="text" icon="el-icon-key"
  84 + v-hasPermi="['system:user:update-password']">重置密码</el-dropdown-item>
  85 + <el-dropdown-item command="handleRole" size="mini" type="text" icon="el-icon-circle-check"
  86 + v-hasPermi="['system:permission:assign-user-role']">分配角色</el-dropdown-item>
  87 + </el-dropdown-menu>
  88 + </el-dropdown>
  89 + </template>
  90 + </el-table-column>
  91 + </el-table>
  92 +
  93 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  94 + @pagination="getList"/>
  95 + </el-col>
  96 + </el-row>
  97 +
  98 + <!-- 添加或修改参数配置对话框 -->
  99 + <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
  100 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  101 + <el-row>
  102 + <el-col :span="12">
  103 + <el-form-item label="用户昵称" prop="nickname">
  104 + <el-input v-model="form.nickname" placeholder="请输入用户昵称" />
  105 + </el-form-item>
  106 + </el-col>
  107 + <el-col :span="12">
  108 + <el-form-item label="归属部门" prop="deptId">
  109 + <treeselect v-model="form.deptId" :options="deptOptions" :show-count="true"
  110 + placeholder="请选择归属部门" :normalizer="normalizer"/>
  111 + </el-form-item>
  112 + </el-col>
  113 + </el-row>
  114 + <el-row>
  115 + <el-col :span="12">
  116 + <el-form-item label="手机号码" prop="mobile">
  117 + <el-input v-model="form.mobile" placeholder="请输入手机号码" maxlength="11" />
  118 + </el-form-item>
  119 + </el-col>
  120 + <el-col :span="12">
  121 + <el-form-item label="邮箱" prop="email">
  122 + <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
  123 + </el-form-item>
  124 + </el-col>
  125 + </el-row>
  126 + <el-row>
  127 + <el-col :span="12">
  128 + <el-form-item v-if="form.id === undefined" label="用户名称" prop="username">
  129 + <el-input v-model="form.username" placeholder="请输入用户名称" />
  130 + </el-form-item>
  131 + </el-col>
  132 + <el-col :span="12">
  133 + <el-form-item v-if="form.id === undefined" label="用户密码" prop="password">
  134 + <el-input v-model="form.password" placeholder="请输入用户密码" type="password" />
  135 + </el-form-item>
  136 + </el-col>
  137 + </el-row>
  138 + <el-row>
  139 + <el-col :span="12">
  140 + <el-form-item label="用户性别">
  141 + <el-select v-model="form.sex" placeholder="请选择">
  142 + <el-option v-for="dict in sexDictDatas" :key="parseInt(dict.value)" :label="dict.label" :value="parseInt(dict.value)"/>
  143 + </el-select>
  144 + </el-form-item>
  145 + </el-col>
  146 + <el-col :span="12">
  147 + <el-form-item label="岗位">
  148 + <el-select v-model="form.postIds" multiple placeholder="请选择">
  149 + <el-option
  150 + v-for="item in postOptions"
  151 + :key="item.id"
  152 + :label="item.name"
  153 + :value="item.id"
  154 + ></el-option>
  155 + </el-select>
  156 + </el-form-item>
  157 + </el-col>
  158 + </el-row>
  159 + <el-row>
  160 + <el-col :span="24">
  161 + <el-form-item label="备注">
  162 + <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
  163 + </el-form-item>
  164 + </el-col>
  165 + </el-row>
  166 + </el-form>
  167 + <div slot="footer" class="dialog-footer">
  168 + <el-button type="primary" @click="submitForm">确 定</el-button>
  169 + <el-button @click="cancel">取 消</el-button>
  170 + </div>
  171 + </el-dialog>
  172 +
  173 + <!-- 用户导入对话框 -->
  174 + <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
  175 + <el-upload
  176 + ref="upload"
  177 + :limit="1"
  178 + accept=".xlsx, .xls"
  179 + :headers="upload.headers"
  180 + :action="upload.url + '?updateSupport=' + upload.updateSupport"
  181 + :disabled="upload.isUploading"
  182 + :on-progress="handleFileUploadProgress"
  183 + :on-success="handleFileSuccess"
  184 + :auto-upload="false"
  185 + drag
  186 + >
  187 + <i class="el-icon-upload"></i>
  188 + <div class="el-upload__text">
  189 + 将文件拖到此处,或
  190 + <em>点击上传</em>
  191 + </div>
  192 + <div class="el-upload__tip" slot="tip">
  193 + <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
  194 + <el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
  195 + </div>
  196 + <div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入“xls”或“xlsx”格式文件!</div>
  197 + </el-upload>
  198 + <div slot="footer" class="dialog-footer">
  199 + <el-button type="primary" @click="submitFileForm">确 定</el-button>
  200 + <el-button @click="upload.open = false">取 消</el-button>
  201 + </div>
  202 + </el-dialog>
  203 +
  204 + <!-- 分配角色 -->
  205 + <el-dialog title="分配角色" :visible.sync="openRole" width="500px" append-to-body>
  206 + <el-form :model="form" label-width="80px">
  207 + <el-form-item label="用户名称">
  208 + <el-input v-model="form.username" :disabled="true" />
  209 + </el-form-item>
  210 + <el-form-item label="用户昵称">
  211 + <el-input v-model="form.nickname" :disabled="true" />
  212 + </el-form-item>
  213 + <el-form-item label="角色">
  214 + <el-select v-model="form.roleIds" multiple placeholder="请选择">
  215 + <el-option
  216 + v-for="item in roleOptions"
  217 + :key="parseInt(item.id)"
  218 + :label="item.name"
  219 + :value="parseInt(item.id)"
  220 + ></el-option>
  221 + </el-select>
  222 + </el-form-item>
  223 + </el-form>
  224 + <div slot="footer" class="dialog-footer">
  225 + <el-button type="primary" @click="submitRole">确 定</el-button>
  226 + <el-button @click="cancelRole">取 消</el-button>
  227 + </div>
  228 + </el-dialog>
  229 +
  230 + </div>
  231 +</template>
  232 +
  233 +<script>
  234 +import {
  235 + addUser,
  236 + changeUserStatus,
  237 + delUser,
  238 + exportUser,
  239 + getUser,
  240 + importTemplate,
  241 + listUser,
  242 + resetUserPwd,
  243 + updateUser
  244 +} from "@/api/system/user";
  245 +import {getToken} from "@/utils/auth";
  246 +import Treeselect from "@riophae/vue-treeselect";
  247 +import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  248 +
  249 +import {listSimpleDepts} from "@/api/system/dept";
  250 +import {listSimplePosts} from "@/api/system/post";
  251 +
  252 +import {SysCommonStatusEnum} from "@/utils/constants";
  253 +import {DICT_TYPE, getDictDatas} from "@/utils/dict";
  254 +import {assignUserRole, listUserRoles} from "@/api/system/permission";
  255 +import {listSimpleRoles} from "@/api/system/role";
  256 +
  257 +export default {
  258 + name: "User",
  259 + components: { Treeselect },
  260 + data() {
  261 + return {
  262 + // 遮罩层
  263 + loading: true,
  264 + // 显示搜索条件
  265 + showSearch: true,
  266 + // 总条数
  267 + total: 0,
  268 + // 用户表格数据
  269 + userList: null,
  270 + // 弹出层标题
  271 + title: "",
  272 + // 部门树选项
  273 + deptOptions: undefined,
  274 + // 是否显示弹出层
  275 + open: false,
  276 + // 部门名称
  277 + deptName: undefined,
  278 + // 默认密码
  279 + initPassword: undefined,
  280 + // 日期范围
  281 + dateRange: [],
  282 + // 状态数据字典
  283 + statusOptions: [],
  284 + // 性别状态字典
  285 + sexOptions: [],
  286 + // 岗位选项
  287 + postOptions: [],
  288 + // 角色选项
  289 + roleOptions: [],
  290 + // 表单参数
  291 + form: {},
  292 + defaultProps: {
  293 + children: "children",
  294 + label: "name"
  295 + },
  296 + // 用户导入参数
  297 + upload: {
  298 + // 是否显示弹出层(用户导入)
  299 + open: false,
  300 + // 弹出层标题(用户导入)
  301 + title: "",
  302 + // 是否禁用上传
  303 + isUploading: false,
  304 + // 是否更新已经存在的用户数据
  305 + updateSupport: 0,
  306 + // 设置上传的请求头部
  307 + headers: { Authorization: "Bearer " + getToken() },
  308 + // 上传的地址
  309 + url: process.env.VUE_APP_BASE_API + '/api/' + "/system/user/import"
  310 + },
  311 + // 查询参数
  312 + queryParams: {
  313 + pageNo: 1,
  314 + pageSize: 10,
  315 + username: undefined,
  316 + mobile: undefined,
  317 + status: undefined,
  318 + deptId: undefined
  319 + },
  320 + // 表单校验
  321 + rules: {
  322 + username: [
  323 + { required: true, message: "用户名称不能为空", trigger: "blur" }
  324 + ],
  325 + nickname: [
  326 + { required: true, message: "用户昵称不能为空", trigger: "blur" }
  327 + ],
  328 + password: [
  329 + { required: true, message: "用户密码不能为空", trigger: "blur" }
  330 + ],
  331 + email: [
  332 + {
  333 + type: "email",
  334 + message: "'请输入正确的邮箱地址",
  335 + trigger: ["blur", "change"]
  336 + }
  337 + ],
  338 + mobile: [
  339 + {
  340 + pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
  341 + message: "请输入正确的手机号码",
  342 + trigger: "blur"
  343 + }
  344 + ]
  345 + },
  346 + // 是否显示弹出层(角色权限)
  347 + openRole: false,
  348 +
  349 + // 枚举
  350 + SysCommonStatusEnum: SysCommonStatusEnum,
  351 + // 数据字典
  352 + statusDictDatas: getDictDatas(DICT_TYPE.SYS_COMMON_STATUS),
  353 + sexDictDatas: getDictDatas(DICT_TYPE.SYS_USER_SEX),
  354 + };
  355 + },
  356 + watch: {
  357 + // 根据名称筛选部门树
  358 + deptName(val) {
  359 + this.$refs.tree.filter(val);
  360 + }
  361 + },
  362 + created() {
  363 + this.getList();
  364 + this.getTreeselect();
  365 + this.getConfigKey("sys.user.init-password").then(response => {
  366 + this.initPassword = response.msg;
  367 + });
  368 + },
  369 + methods: {
  370 + // 更多操作
  371 + handleCommand(command, index, row) {
  372 + switch (command) {
  373 + case 'handleUpdate':
  374 + this.handleUpdate(row);//修改客户信息
  375 + break;
  376 + case 'handleDelete':
  377 + this.handleDelete(row);//红号变更
  378 + break;
  379 + case 'handleResetPwd':
  380 + this.handleResetPwd(row);
  381 + break;
  382 + case 'handleRole':
  383 + this.handleRole(row);
  384 + break;
  385 + default:
  386 + break;
  387 + }
  388 + },
  389 + /** 查询用户列表 */
  390 + getList() {
  391 + this.loading = true;
  392 + listUser(this.addDateRange(this.queryParams, [
  393 + this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
  394 + this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
  395 + ])).then(response => {
  396 + this.userList = response.data.list;
  397 + this.total = response.data.total;
  398 + this.loading = false;
  399 + }
  400 + );
  401 + },
  402 + /** 查询部门下拉树结构 + 岗位下拉 */
  403 + getTreeselect() {
  404 + listSimpleDepts().then(response => {
  405 + // 处理 deptOptions 参数
  406 + this.deptOptions = [];
  407 + this.deptOptions.push(...this.handleTree(response.data, "id"));
  408 + });
  409 + listSimplePosts().then(response => {
  410 + // 处理 postOptions 参数
  411 + this.postOptions = [];
  412 + this.postOptions.push(...response.data);
  413 + });
  414 + },
  415 + // 筛选节点
  416 + filterNode(value, data) {
  417 + if (!value) return true;
  418 + return data.name.indexOf(value) !== -1;
  419 + },
  420 + // 节点单击事件
  421 + handleNodeClick(data) {
  422 + this.queryParams.deptId = data.id;
  423 + this.getList();
  424 + },
  425 + // 用户状态修改
  426 + handleStatusChange(row) {
  427 + let text = row.status === SysCommonStatusEnum.ENABLE ? "启用" : "停用";
  428 + this.$confirm('确认要"' + text + '""' + row.username + '"用户吗?', "警告", {
  429 + confirmButtonText: "确定",
  430 + cancelButtonText: "取消",
  431 + type: "warning"
  432 + }).then(function() {
  433 + return changeUserStatus(row.id, row.status);
  434 + }).then(() => {
  435 + this.msgSuccess(text + "成功");
  436 + }).catch(function() {
  437 + row.status = row.status === SysCommonStatusEnum.ENABLE ? SysCommonStatusEnum.DISABLE
  438 + : SysCommonStatusEnum.ENABLE;
  439 + });
  440 + },
  441 + // 取消按钮
  442 + cancel() {
  443 + this.open = false;
  444 + this.reset();
  445 + },
  446 + // 取消按钮(角色权限)
  447 + cancelRole() {
  448 + this.openRole = false;
  449 + this.reset();
  450 + },
  451 + // 表单重置
  452 + reset() {
  453 + this.form = {
  454 + id: undefined,
  455 + deptId: undefined,
  456 + username: undefined,
  457 + nickname: undefined,
  458 + password: undefined,
  459 + mobile: undefined,
  460 + email: undefined,
  461 + sex: undefined,
  462 + status: "0",
  463 + remark: undefined,
  464 + postIds: [],
  465 + roleIds: []
  466 + };
  467 + this.resetForm("form");
  468 + },
  469 + /** 搜索按钮操作 */
  470 + handleQuery() {
  471 + this.queryParams.pageNo = 1;
  472 + this.getList();
  473 + },
  474 + /** 重置按钮操作 */
  475 + resetQuery() {
  476 + this.dateRange = [];
  477 + this.resetForm("queryForm");
  478 + this.handleQuery();
  479 + },
  480 + /** 新增按钮操作 */
  481 + handleAdd() {
  482 + this.reset();
  483 + // 获得下拉数据
  484 + this.getTreeselect();
  485 + // 打开表单,并设置初始化
  486 + this.open = true;
  487 + this.title = "添加用户";
  488 + this.form.password = this.initPassword;
  489 + },
  490 + /** 修改按钮操作 */
  491 + handleUpdate(row) {
  492 + this.reset();
  493 + this.getTreeselect();
  494 + const id = row.id;
  495 + getUser(id).then(response => {
  496 + this.form = response.data;
  497 + this.open = true;
  498 + this.title = "修改用户";
  499 + this.form.password = "";
  500 + });
  501 + },
  502 + /** 重置密码按钮操作 */
  503 + handleResetPwd(row) {
  504 + this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
  505 + confirmButtonText: "确定",
  506 + cancelButtonText: "取消"
  507 + }).then(({ value }) => {
  508 + resetUserPwd(row.id, value).then(response => {
  509 + this.msgSuccess("修改成功,新密码是:" + value);
  510 + });
  511 + }).catch(() => {});
  512 + },
  513 + /** 分配用户角色操作 */
  514 + handleRole(row) {
  515 + this.reset();
  516 + const id = row.id
  517 + // 处理了 form 的用户 username 和 nickname 的展示
  518 + this.form.id = id;
  519 + this.form.username = row.username;
  520 + this.form.nickname = row.nickname;
  521 + // 打开弹窗
  522 + this.openRole = true;
  523 + // 获得角色列表
  524 + listSimpleRoles().then(response => {
  525 + // 处理 roleOptions 参数
  526 + this.roleOptions = [];
  527 + this.roleOptions.push(...response.data);
  528 + });
  529 + // 获得角色拥有的菜单集合
  530 + listUserRoles(id).then(response => {
  531 + // 设置选中
  532 + this.form.roleIds = response.data;
  533 + })
  534 + },
  535 + /** 提交按钮 */
  536 + submitForm: function() {
  537 + this.$refs["form"].validate(valid => {
  538 + if (valid) {
  539 + if (this.form.id !== undefined) {
  540 + updateUser(this.form).then(response => {
  541 + this.msgSuccess("修改成功");
  542 + this.open = false;
  543 + this.getList();
  544 + });
  545 + } else {
  546 + addUser(this.form).then(response => {
  547 + this.msgSuccess("新增成功");
  548 + this.open = false;
  549 + this.getList();
  550 + });
  551 + }
  552 + }
  553 + });
  554 + },
  555 + /** 提交按钮(角色权限) */
  556 + submitRole: function() {
  557 + if (this.form.id !== undefined) {
  558 + assignUserRole({
  559 + userId: this.form.id,
  560 + roleIds: this.form.roleIds,
  561 + }).then(response => {
  562 + this.msgSuccess("分配角色成功");
  563 + this.openRole = false;
  564 + this.getList();
  565 + });
  566 + }
  567 + },
  568 + /** 删除按钮操作 */
  569 + handleDelete(row) {
  570 + const ids = row.id || this.ids;
  571 + this.$confirm('是否确认删除用户编号为"' + ids + '"的数据项?', "警告", {
  572 + confirmButtonText: "确定",
  573 + cancelButtonText: "取消",
  574 + type: "warning"
  575 + }).then(function() {
  576 + return delUser(ids);
  577 + }).then(() => {
  578 + this.getList();
  579 + this.msgSuccess("删除成功");
  580 + })
  581 + },
  582 + /** 导出按钮操作 */
  583 + handleExport() {
  584 + const queryParams = this.addDateRange(this.queryParams, [
  585 + this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
  586 + this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
  587 + ]);
  588 + this.$confirm('是否确认导出所有用户数据项?', "警告", {
  589 + confirmButtonText: "确定",
  590 + cancelButtonText: "取消",
  591 + type: "warning"
  592 + }).then(function() {
  593 + return exportUser(queryParams);
  594 + }).then(response => {
  595 + this.downloadExcel(response, '用户数据.xls');
  596 + })
  597 + },
  598 + /** 导入按钮操作 */
  599 + handleImport() {
  600 + this.upload.title = "用户导入";
  601 + this.upload.open = true;
  602 + },
  603 + /** 下载模板操作 */
  604 + importTemplate() {
  605 + importTemplate().then(response => {
  606 + this.downloadExcel(response, '用户导入模板.xls');
  607 + });
  608 + },
  609 + // 文件上传中处理
  610 + handleFileUploadProgress(event, file, fileList) {
  611 + this.upload.isUploading = true;
  612 + },
  613 + // 文件上传成功处理
  614 + handleFileSuccess(response, file, fileList) {
  615 + this.upload.open = false;
  616 + this.upload.isUploading = false;
  617 + this.$refs.upload.clearFiles();
  618 + // 拼接提示语
  619 + let data = response.data;
  620 + let text = '创建成功数量:' + data.createUsernames.length;
  621 + for (const username of data.createUsernames) {
  622 + text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username;
  623 + }
  624 + text += '<br />更新成功数量:' + data.updateUsernames.length;
  625 + for (const username of data.updateUsernames) {
  626 + text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username;
  627 + }
  628 + text += '<br />更新失败数量:' + Object.keys(data.failureUsernames).length;
  629 + for (const username in data.failureUsernames) {
  630 + text += '<br />&nbsp;&nbsp;&nbsp;&nbsp;' + username + ':' + data.failureUsernames[username];
  631 + }
  632 + this.$alert(text, "导入结果", { dangerouslyUseHTMLString: true });
  633 + this.getList();
  634 + },
  635 + // 提交上传文件
  636 + submitFileForm() {
  637 + this.$refs.upload.submit();
  638 + },
  639 + // 格式化部门的下拉框
  640 + normalizer(node) {
  641 + return {
  642 + id: node.id,
  643 + label: node.name,
  644 + children: node.children
  645 + }
  646 + }
  647 + }
  648 +};
  649 +</script>
  650 +<style>
  651 + .el-dropdown-link {
  652 + cursor: pointer;
  653 + color: #1890ff;
  654 + margin-left: 5px;
  655 + }
  656 + .el-icon-arrow-down {
  657 + font-size: 14px;
  658 + }
  659 +</style>
... ...
ruoyi-ui/src/views/system/user/profile/index.vue
... ... @@ -13,11 +13,11 @@
13 13 <ul class="list-group list-group-striped">
14 14 <li class="list-group-item">
15 15 <svg-icon icon-class="user" />用户名称
16   - <div class="pull-right">{{ user.userName }}</div>
  16 + <div class="pull-right">{{ user.username }}</div>
17 17 </li>
18 18 <li class="list-group-item">
19 19 <svg-icon icon-class="phone" />手机号码
20   - <div class="pull-right">{{ user.phonenumber }}</div>
  20 + <div class="pull-right">{{ user.mobile }}</div>
21 21 </li>
22 22 <li class="list-group-item">
23 23 <svg-icon icon-class="email" />用户邮箱
... ... @@ -25,15 +25,19 @@
25 25 </li>
26 26 <li class="list-group-item">
27 27 <svg-icon icon-class="tree" />所属部门
28   - <div class="pull-right" v-if="user.dept">{{ user.dept.deptName }} / {{ postGroup }}</div>
  28 + <div class="pull-right" v-if="user.dept">{{ user.dept.name }}</div>
  29 + </li>
  30 + <li class="list-group-item">
  31 + <svg-icon icon-class="tree" />所属岗位
  32 + <div class="pull-right" v-if="user.posts">{{ user.posts.map(post => post.name).join(',') }}</div>
29 33 </li>
30 34 <li class="list-group-item">
31 35 <svg-icon icon-class="peoples" />所属角色
32   - <div class="pull-right">{{ roleGroup }}</div>
  36 + <div class="pull-right">{{ user.roles.map(post => post.name).join(',') }}</div>
33 37 </li>
34 38 <li class="list-group-item">
35 39 <svg-icon icon-class="date" />创建日期
36   - <div class="pull-right">{{ user.createTime }}</div>
  40 + <div class="pull-right">{{ parseTime(user.createTime) }}</div>
37 41 </li>
38 42 </ul>
39 43 </div>
... ... @@ -82,8 +86,6 @@ export default {
82 86 getUser() {
83 87 getUserProfile().then(response => {
84 88 this.user = response.data;
85   - this.roleGroup = response.roleGroup;
86   - this.postGroup = response.postGroup;
87 89 });
88 90 }
89 91 }
... ...
ruoyi-ui/src/views/system/user/profile/userInfo.vue
1 1 <template>
2 2 <el-form ref="form" :model="user" :rules="rules" label-width="80px">
3 3 <el-form-item label="用户昵称" prop="nickName">
4   - <el-input v-model="user.nickName" />
5   - </el-form-item>
6   - <el-form-item label="手机号码" prop="phonenumber">
7   - <el-input v-model="user.phonenumber" maxlength="11" />
  4 + <el-input v-model="user.nickname" />
  5 + </el-form-item>
  6 + <el-form-item label="手机号码" prop="mobile">
  7 + <el-input v-model="user.mobile" maxlength="11" />
8 8 </el-form-item>
9 9 <el-form-item label="邮箱" prop="email">
10 10 <el-input v-model="user.email" maxlength="50" />
11 11 </el-form-item>
12 12 <el-form-item label="性别">
13 13 <el-radio-group v-model="user.sex">
14   - <el-radio label="0">男</el-radio>
15   - <el-radio label="1">女</el-radio>
  14 + <el-radio :label="1">男</el-radio>
  15 + <el-radio :label="2">女</el-radio>
16 16 </el-radio-group>
17 17 </el-form-item>
18 18 <el-form-item>
... ... @@ -35,7 +35,7 @@ export default {
35 35 return {
36 36 // 表单校验
37 37 rules: {
38   - nickName: [
  38 + nickname: [
39 39 { required: true, message: "用户昵称不能为空", trigger: "blur" }
40 40 ],
41 41 email: [
... ... @@ -46,7 +46,7 @@ export default {
46 46 trigger: ["blur", "change"]
47 47 }
48 48 ],
49   - phonenumber: [
  49 + mobile: [
50 50 { required: true, message: "手机号码不能为空", trigger: "blur" },
51 51 {
52 52 pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
... ...
ruoyi-ui/src/views/tool/dbDoc/index.vue
1 1 <template>
2   - <div v-loading="loading" :style="'height:'+ height">
3   - <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
  2 + <div class="app-container">
  3 + <el-row :gutter="10" class="mb8">
  4 + <el-col :span="1.5">
  5 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportHtml">导出 HTML</el-button>
  6 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportWord">导出 Word</el-button>
  7 + <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleExportMarkdown">导出 Markdown</el-button>
  8 + </el-col>
  9 + </el-row>
  10 +
  11 + <!-- 展示文档 -->
  12 + <div v-loading="loading" :style="'height:'+ height">
  13 + <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
  14 + </div>
4 15 </div>
5 16 </template>
6 17 <script>
7   -import {exportHtml} from "@/api/infra/dbDoc";
  18 +import { exportHtml, exportWord, exportMarkdown} from "@/api/infra/dbDoc";
8 19  
9 20 export default {
10 21 name: "DBDoc",
... ... @@ -25,10 +36,31 @@ export default {
25 36 };
26 37 },
27 38 created() {
  39 + // 加载 Html,进行预览
28 40 exportHtml().then(response => {
29   - // var blob = new Blob(['<a id="a"><b id="b">hey!</b></a>'], {type : 'text/html'});
30   - this.src = window.URL.createObjectURL(response);
  41 + let blob = new Blob([response], {type : 'text/html'});
  42 + this.src = window.URL.createObjectURL(blob);
31 43 })
32 44 },
  45 + methods: {
  46 + /** 处理导出 HTML */
  47 + handleExportHtml() {
  48 + exportHtml().then(response => {
  49 + this.downloadHtml(response, '数据库文档.html');
  50 + })
  51 + },
  52 + /** 处理导出 Word */
  53 + handleExportWord() {
  54 + exportWord().then(response => {
  55 + this.downloadWord(response, '数据库文档.doc');
  56 + })
  57 + },
  58 + /** 处理导出 Markdown */
  59 + handleExportMarkdown() {
  60 + exportMarkdown().then(response => {
  61 + this.downloadMarkdown(response, '数据库文档.md');
  62 + })
  63 + }
  64 + }
33 65 };
34 66 </script>
... ...
sql/quartz.sql
... ... @@ -178,3 +178,11 @@ CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIG
178 178 CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
179 179  
180 180 commit;
  181 +
  182 +-- 初始化默认任务 用户 Session 超时 Job
  183 +INSERT INTO QRTZ_JOB_DETAILS VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', NULL, 'cn.iocoder.dashboard.framework.quartz.core.handler.JobHandlerInvoker', '0', '1', '1', '0', 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000027400064A4F425F49447372000E6A6176612E6C616E672E4C6F6E673B8BE490CC8F23DF0200014A000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000000000047400104A4F425F48414E444C45525F4E414D457400187379735573657253657373696F6E54696D656F75744A6F627800);
  184 +commit;
  185 +INSERT INTO QRTZ_TRIGGERS VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', 'sysUserSessionTimeoutJob', 'DEFAULT', NULL, 1615706340000, 1615706280000, 5, 'WAITING', 'CRON', 1615706125000, 0, NULL, 0, 0xACED0005737200156F72672E71756172747A2E4A6F62446174614D61709FB083E8BFA9B0CB020000787200266F72672E71756172747A2E7574696C732E537472696E674B65794469727479466C61674D61708208E8C3FBC55D280200015A0013616C6C6F77735472616E7369656E74446174617872001D6F72672E71756172747A2E7574696C732E4469727479466C61674D617013E62EAD28760ACE0200025A000564697274794C00036D617074000F4C6A6176612F7574696C2F4D61703B787001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000037400114A4F425F48414E444C45525F504152414D707400124A4F425F52455452595F494E54455256414C737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B0200007870000007D074000F4A4F425F52455452595F434F554E547371007E0009000000037800);
  186 +commit;
  187 +INSERT INTO QRTZ_CRON_TRIGGERS VALUES ('schedulerName', 'sysUserSessionTimeoutJob', 'DEFAULT', '0 * * * * ? *', 'Asia/Shanghai');
  188 +commit;
... ...
sql/ruoyi-vue-pro.sql
1 1 /*
2 2 Navicat Premium Data Transfer
3 3  
4   - Source Server : 127.0.0.1
  4 + Source Server : local-mysql001
5 5 Source Server Type : MySQL
6 6 Source Server Version : 50718
7 7 Source Host : localhost:3306
... ... @@ -11,7 +11,7 @@
11 11 Target Server Version : 50718
12 12 File Encoding : 65001
13 13  
14   - Date: 09/03/2021 20:39:41
  14 + Date: 18/04/2021 00:36:06
15 15 */
16 16  
17 17 SET NAMES utf8mb4;
... ... @@ -43,7 +43,7 @@ CREATE TABLE `inf_api_access_log` (
43 43 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
44 44 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
45 45 PRIMARY KEY (`id`) USING BTREE
46   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表';
  46 +) ENGINE=InnoDB AUTO_INCREMENT=3750 DEFAULT CHARSET=utf8mb4 COMMENT='API 访问日志表';
47 47  
48 48 -- ----------------------------
49 49 -- Records of inf_api_access_log
... ... @@ -84,7 +84,7 @@ CREATE TABLE `inf_api_error_log` (
84 84 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
85 85 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
86 86 PRIMARY KEY (`id`) USING BTREE
87   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志';
  87 +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COMMENT='系统异常日志';
88 88  
89 89 -- ----------------------------
90 90 -- Records of inf_api_error_log
... ... @@ -125,6 +125,32 @@ INSERT INTO `inf_config` VALUES (5, &#39;xxx&#39;, 2, &#39;xxx&#39;, &#39;xxx&#39;, &#39;xxx&#39;, b&#39;1&#39;, &#39;xxx&#39;,
125 125 COMMIT;
126 126  
127 127 -- ----------------------------
  128 +-- Table structure for inf_file
  129 +-- ----------------------------
  130 +DROP TABLE IF EXISTS `inf_file`;
  131 +CREATE TABLE `inf_file` (
  132 + `id` varchar(188) NOT NULL COMMENT '文件路径',
  133 + `type` varchar(63) DEFAULT NULL COMMENT '文件类型',
  134 + `content` blob NOT NULL COMMENT '文件内容',
  135 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  136 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  137 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  138 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  139 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  140 + PRIMARY KEY (`id`) USING BTREE
  141 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表';
  142 +
  143 +-- ----------------------------
  144 +-- Records of inf_file
  145 +-- ----------------------------
  146 +BEGIN;
  147 +INSERT INTO `inf_file` VALUES ('427.jpg', 'jpg', 0xFFD8FFE000104A46494600010100000100010000FFDB00430006040506050406060506070706080A100A0A09090A140E0F0C1017141818171416161A1D251F1A1B231C1616202C20232627292A29191F2D302D283025282928FFDB0043010707070A080A130A0A13281A161A2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828FFC0001108017F038403012200021101031101FFC4001C0001000203010101000000000000000000000607010405020308FFC40051100001030301040507060A08030803000000010203040511060712213113415161811422357191A1B115233242C1D1161752545572749394B2242536537392E1F0264362083334374482A2F163C2E2FFC4001C0101000203010101000000000000000000000102030405060807FFC4003811010002010204030507030402030000000001020304110512213113415114223371B13235617281A1D11552C1233454910642B2E1F1FFDA000C03010002110311003F00E5000D57E96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001832600905ABD1F0F8FC4DA356D5E8F87C7E26D1EA307C3AFCA1F35F1DFBCB51F9EDF564006572800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000115001E49F5480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060C9802416AF47C3E3F136CD4B57A3E1F1F89B67A8C1F0EBF287CD7C77EF2D47E7B7D400195CA000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000454007927D5200000000000000000000000000000000000000000002407DA9692A6B24E8E8E9E6A893F26262B97DC84928B67BA9EB1A8E6DBD206F6D44AD67BB8A931599ECC3933E2C5F6ED11FAA2A09D26CC6E8C44F2AB9DAA05EC74AABF6184D9B55AFF00DDDF2CEE5EC4949E4960FEA1A6FEFF00AA0C09AD46CCF51C6D5740CA4AA6A7F753267DF823B73B05DED795B85B6AE06A7D758F2DF6A6508989865A6AB0E49DA968997301E517D5ED3D10CE000000000000000000000000000000000000000000001832600905ABD1F0F8FC4DB352D5E8F87C7E26D9EA307C3AFCA1F35F1DFBCB51F9EDF500065728000000000000000000000000000004BF41E9EB75E9B54DAD95ED9E3C2358D5C70EDC7ACE4EA7B14F62AF5865F3A27718DFF948638CB59B7279B6EDA2CB5C11A8DBDD96BE9FA165CEF549472395AD95F8554E7C957EC3ABAE6C94F63B945152B9EB1C91EF6EBBA9727334ED4BE86F14D58CA7927481DBCE6B13B950EAEBAB9BEEF7064E9473D3C71337732B719E3EE2B336F1636EDB3631D717B15B78F7F7E9F24681B16CA29EE3591D352B15F2BF97777AF7131D47A4286CFA7BCA24A87F96B5513B9EAABC5A89D98CF12D7CD5ADA2B3DDAF8347973D2D92B1EED7BCA060032350000000000000000000000000000000000000000000000000000000000000000115001E49F54800000000000000000000000000000000000063217FDFAC9D58F4A525B6DECBD6B391D4D46BC61A245F9C9D7AB29CD3D5ED2621873E7AE18DEDDFCA3CE51FD37A6AEBA8A454B6D32AC2D5F3A793CD8DBEB5EDEE4C9275B7E8FD2EDC5D677DFEE2C5E34F0E12362F7AF2F6AAAF71C8D49AD6B6EF079150B3E4DB4B3CD65343C329FF0052A7C1381172DBC4766BC62CFA8EB967963D23BFEB3FC2695BB47B9A46B4F63A5A3B452FD56C51239D8F5AF0F71DFB1E89D41A9EDD4F71BBEA3A88E2A96F48D8BCE55C2F2CF144F7155390FD41A178E8EB3FECB1FF002A16ACEEE7F1498D0E2ACE0888999EFDE50A8B63B6A545E9AE55B23D79AA6EA7D87D1763B65C79B5B5C8BDBBCDFB8B0EE956DB7DB6AEADCD57A4113A556A2E15D84CE08F684D6516AC6563A2A39297C995A8BBEE45DEDE4CF0C16DA1C5AEB75D6A4E48B748EFD9127EC966A3C3AD3A82AA07A72DE454C7F95508954EADD53A5EED516DA9B836ADD4EFDD7B676A488E4E6985E0B83F43751F9B369E99D7977FF11BFC8D22D1111BBA3C2F516D6649C79E22D1B7A43AC97FD29A85772FD69F936A9FC3CAE8F967BD138E3D68A685E341D5C34C95F60A98EF16D5E28F8573237D6DEBF0E3DC43B0746C97AB8D8EA92A2D754F81FD6DE6C77EB379298F789EEED7B2E4C5D705BF49EB1FCC39EA8A8E5454C2A73EE058A8FB1ED09158F6C369D4CD4E0A9FF7752BF7FBFD641EED6CABB457CB457185D0D446B8545E28A9D4A8BD68A44C32E1D4C649E4B46D78F2FE3D5A40021B00000000000000000000000000000000000001832600905ABD1F0F8FC4DB352D5E8F87C7E26D9EA307C3AFCA1F35F1DFBCB51F9EDF5000657280000000000000000000000003260EB586C35B7C9256D0B1AEE89115EAE76319CE3E0A45AD158DE593162BE5B72638DE5A343593D05547534B22B2662E5153E0BDC4F6D90566BAA886A6E6D6C5434996E234FF00BC770CF1F611ABC693B9DA6916A6AE362C48B85563B7950B0AE73A69ED0ACF2576EC9D135AC7638EF3B9AFC54D3CD7ACED34EB32EF70DD364C7CF5D4EF14AC6F35F5F462B750D8B4DA3A929A26BA46705644DE4BDEBDA6AD1EBAB3DCB14F5F4EB0A3D513E7111CDF12A9739CF7AB9EE5739572AABD664B7B1D7BCCF562B71FCFCDEE5622BE9B2D1BC58D6C73A5F34EB58A8C4557C38CB55ABD68402FF7CADBE552CD56F446A7D18DBF45A84F765D717D5DB6B282A155ED871BAABD4D5EAF72911FC19ACB85EEE14B6E63563A7915155CEC22679214C3314BCC64F2F367D752D9B0D2DA5E95BF7AC7AA38090DDF48DD6D544FAAA98D8B133E92B5E8B823C6E56F178DEB2E0E6C19304F2E5AED2006CD0D1D457D4360A385F34AEFAAD4F8F61699888DE58AB59B4C56B1BCB58FB535354554891D2C124CFF00C96372A593A7F67F0C2C6CB7A547BF19E898B86A7AD799D0AED5561B1B560A18D923DBC1594ED4C7B791AB6D56F3B638DDDBC5C1B92B1935778A47A79A1743A0EF550D47491C74ED5FEF1DC7D8874D9B36AD5CEFD7409EA62A9F1B9ED0EE3322B68A28E99BD4ABE73BDE71E5D5F7C91DBCB5CF4EE6A22215DB5168DFA42D36E138E79622D6FC5DE9366D588DCC75D0B97B158A872EBF42DE695AAE8E2654353FBB771F628B7EACD473CCC8296774F33B9377117259F6375CDB48F7DF1606BF1BC891FD54EBCA98F265CD87ED4C4B7749A3D06BFA62A5ABF8F928CA8A79E9A45654C3244F4E0A8F6E307C4BF116D77E8248D3A1AB8D8AAD72A71445EE5217A8B67B86BA6B2BF971E8645F82FDE64C7ACACCED78D9A9ABE01931D7C4C16E7AFEEADC1F4A8864A699F0CF1BA3958B8735C98543E66E38131313B4C00008000000000000000000000000000000000000454007927D5200000000000000000000000000000000180A4CB67F65A693CA7505ED11B68B779F85E3D2C89C51B8EB44E1C3B704C43167CD18693796FE9FB551695B3C7A9351C6AEAA7F9D6FA17261CE7753D53DFDDCF99C1D58DBE5C60A6BFDEDAE6C558E5640DEA6A226530DFAA8BED534B545F6AB51DD64AEABCB73E6C5167846CEA4FBFBCB6E66FE1BEC9DAE6377EBA18B7B7539F4B1F344F5A27BD0BC46FD1CBCB6BE9AD4CF9BACDA7699FED8F48FF2816CEB453756256495334B052C0A8C6BA2C2ABDCA99C71ECE1ED4265F8A0B5F5DE6A53FC86E56AA685D96A45F42E13B373873E95FCFF00CA9F028E491E9F5DFF00E6513111DD5C56D4EB6F7C98F272D62768E9BAE45D90DA7F4CD4FB23FB8B26C940CB659E8E8A29165653C4D89AF5E6E444C654FCA4B23FF2DFFE653F4FE85E3A3ACFFB2C7FCA85A9313D9CEE3183363C75F1727346FE9B205B50B3EA9AABBD4D65BA6959676D326FB12A3753088AAEF333D857DA3ED7A8EE6CAAFC189A46246AD499193F45955CE3DC7E93AFA58EB68A6A69F3D14CC58DD85C2E1530A7274B695B66996D425AA391893AB55FBEF57724C2732663AEEC5838B785A79C5CB1BF4DBA7D5D6B7325650D3B6A155666C6D47AAAE72B8E3EF3F3A6D3BFB7977FF11BFC8D3F49A1526AFD9A5D2F7A8EB6E1056D23239DC8E46C8D76530D44FB08B44CC6D0AF08D463C19ED7C93B46CA7CCB237CD345144D574923918D6A75AAAE110B1FF14179FD2141FE471E742E8DABA3DA2A535CE2456DB99E51D2373BAFCF0663C73FE531C527CDE92DC4F4FC96B52DBCC46EDCDA3E9AB4D9B4F58E28B14F7557B299B331708EE19739DEA5E39E79535A92AA3D4913B4B6B0CD35EA9FCDA5AC7A61CAEEA455EBCF0EE72779CFDB25DFE52D58EA58DD98685891FF00EF5E2EFB13C0DB9DD6CD59A1E965A8AEA6A4D4540DE8D1F2C88D59913922AAF6A630BD4B9267BB9F4ADE34F8EF977DE67BF9C6FDBF4F5416F16DAAB3DCA6A1AF8963A88970A9D4E4EA722F5A29A858D0B9BB42D32F8E4DD4D4F6B8F79ABD7511FDBCBDBEB2B84CA2AA2A6153A94ACC6CEB69B3CE589ADFA5A3BFF3F2964004364000000000000000000000000000000003064C0120B57A3E1F1F89B66A5ABD1F0F8FC4DB3D460F875F943E6BE3BF796A3F3DBEA000CAE5000000000000000000000000074ECB7CAEB2BA575BE548FA54447A2B51738CE39FAD4E6022622D1B4AF8F25F15A2F49DA5DCBAEAABADD697C9EB2663A1CA2AB5AC46E71CB9162DCA1FC21D0ACF244CC9D1B5CC6AF5AB7A8AA2DB433DC6AE3A6A462BE47AF57244ED52796D9EB3424D0D3DD5EC9E86A9729D1E556254E784F1434F3D2B1B453BC793BFC375192DCF6D56F34B46D33E8AEA46BA391CC91AAD7B570A8BCD0CA16FD65874FEA755ACA791A93393CE7C2EC2AFEB27DE7CE9744596DCADA8AB95D2A3173991E88DF12DED95F38EAC73FF008FE69B6F4B44D7D776AECBEDEFA4B5D4D7D43771B51F45179EE275FB7243DDA9AB28AF171A9B5CC8C65448AAA8AD4545C725C2F592FBDDF16F953F2069D5661ED54926CE1AD6A7344F7103D4164ACB1D524558C4563932D95BF45C570C45AD3393BCF933710BDB0E1A534BBF2D3BDA3D5F7BB6ABBB5D29169AAE76AC2E5CAA3588DCF71C3077748E9E96FD5E8C4CB69A35459644E58EC4EF3667930D77DB6871A3C7D6E58AEF36B4BC69BD395B7E9D1B4EDDCA6477CE4AF4E089DDDE5979B3689B5F9A89D22A72E7248BDFFEF81F2D437DA1D236E6D150318B528DF323EA6A7E5394A9AE15B3DC2ADF535723A495FCD57ABB93B8D488B6A3ADBA55DABE4C1C223931C45B2CF79F2876F51EADAFBC4AE62B960A6FEE5BD7EB5EB23CBC7060F46ED295A46D58707367C99EDCF927790D9B650D45CABA2A4A466FCB22E13B113B57B8F8451BE591B1C4D57C8E5C35A9CD57B0EBC4B73D29748A5960E8A656E51AFE2D722F34E1CC5E676DABDCC18E26D17BC4F246DBCC2C6B65B6D7A2AD4EABAC91AEA854C3A554E2E5FC96A7615FEA7D575B7A7AB379D051E5710B579FAD7ACD0BDDE6B2F556B3D6BD17098631A98462771CEC1AF8B4FB4F3E4EB2E8EB78A73C781A68E5C71FBFCD3AD93D6B9974A9A4CF9B2B37D3D69FFD9B57ED435DA6B55D4B51566A295525E89FD59E7BABD5C5148D6839961D5743BBF59CAD5F61DDDADC28DBAD2CC9CDF12B7D8BFEA63B52BE3ED31D261BB87519238673E39DAD4B24371B75AF5B5A1B5346E6B6A9A9E6BFEB357F25C9D855573A29EDB5B252D5B1592B170A8BD7DE9DC6D69DBD5458EE2CA9A755E8D78491F53D0B23525B29B56E9F657DBF756A9ADDE8D7AD7B5ABFEF9889B69EDB4CFBB2AE4AE3E2D86725236CB5EF1EAA8C1E958A8AA8BC15382A28C1BCF3BD9E40010000000000000000000000000000000008A800F24FAA400000000000000000000000000000004B62D9452DC6E14D474C999A77A46DF5AFFA71F0261B47B8436F8A874ADA9F8A3B73516754FF00992AA75FAB2ABEB5EE3DECBE28A821BC6A6AA6A2C76E85590F1E72393FFA4F138D43A5EF17EB5576A06A31D1A39EF915CEC3E454E2EC263AB897ED0E6E4C94B6A37C93B569FF00CA7F8847510B4F6157748EBEBACF22F99335278D157EB27077B787B0AB10DFD3F7296CD7AA4B8C0ABBF03F2ADFCA6AA61508A4ED2D8D6E9E35182D8FCFC933DB55F56BF51C76E89D9A7A06E17BE45E7EC4C215E9F4AB9E4AAA996A2672BA595EAF7B97AD5572A7CC5A7795B498234F86B8E3C83F49ECDAE34F5DA3ADBD048C57430B6291B9E2D72261514FCD87B8A5923CAC52491AAF5B1EAD5F7135B72B0710D0C6B6914DF6D9FAEB982B9D8EDCE066908A3ADAE8D6A5F50FC3669B2F5555E09C5724EEB2BE9691A8957510C0AECEEA48F46E7D5932EFD37789CD82D8B2CE2EFB361EF6B1AAE739A889D6AA7E7AD65AD6EB26A7B8FC9179AA650B64DC8D237E1BC111171E3922F74A999F70AE62554EE8D677E13A45DD54DE5E499C60D2C7798E6EF55A0E114C13CF79E6DE3D121A6D69A8E1A98A65BC55C9D1BD1DB8F765AE44EA54EC52F4A2D534357A424D4316EF46C815CF6AF36B9138B17C781F9A910DDA5B955D35A6B2DB14CA94954E6BA4677A2E787BB3EA222FEACFACE178B5115E4888989FFB8F36B54CEFA9ABA8A99955D2CEF591EABD6AAB93E58E27A05267774E2368D9BD60BB4F63BBD357D2AFCE44EE29F94D5E6D5F5A122DA65B608AB69AF96C6FF56DD5892B31C9B2638A77679FB4873932A84FB492FE10686BC58645DFABA2FE99479E689CD513BB394FFDC5A3B6CD2D57FA57AE78F94FCA7F894010C9843255BA000000000000000000000000000000001832600905ABD1F0F8FC4DB352D5E8F87C7E26D9EA307C3AFCA1F35F1DFBCB51F9EDF50006572800000000000000000000000000012DD0BA8686C3154F95C323E57AF9AE6222F0EC393A8EF93DF2E0EA89BCD8DBC2367E4A1C808638C558B73F9B6EFADCB7C31A799F761D4D394EFADBC52D2367921499DBAAE62F1443A7AF6D8EB3DC618A3AA9E68E466F7CEBB795173DA722C35CDB65E292B1EC57B617EF2B514E96B7BDC37EB94735344E6471B37115E985771E65662FE2C6DDB667C57C5EC56DE7DFDFA7C9C6A1AC9A82B22AAA57AB268D72D54F82932D47AC28EF1A696966A6779639132AA89BAD776A2906C054C96BE1ADED169EED7C1ADCB8296C749F76DDE188911CF4472EEA2AF15E782F4B23AD36AB5C105354D3B62DDCEF2C89972F69456015CF83C6888DF66D70DE25EC369B4577995BB5DA734DDCAA5F34956C59DEEDE7392A132B939170D9BE51CEB65723BB1923787B50AE5155392AA1D8B56A0B9DADED5A5AB9309CD8F5DE6AF82987C0C94EB4B36E78968B3DBFD7C3B6FE712F85DACB70B4CAACAEA67313A9E9C5AE4ED45439E5B162D61417C44A2BB431C72BF8223B8B245ECE3D671AF7A01EDBA40B6CF3A8A593CF6AF3893ED42F4D4ED3CB9636953370BADE9E2E8ADCF5F4F387D7669624CADDEADA88D66521DEE5DEE23FAF2F6DBCDDFE670B4F4F9631C9F5B9657D44D35EDCE2B269F8ADB46A8934CCE8DA89CDAC4E0ABF615314C11E25A72CFE8C9C4AF1A5C55D0E3F2EB6F9867ACC036DC077345AFF00C556CFF17EC251B5D5FE9741FAAEF891FD9DD3F4FAAE957FBBCBFDDFEA7536B336F5F29E2CF06439C7AD57EE352DFEE23E4EEE19E5E159267CEC84AA130D9C5FD2DB5CFA3AB911B493AF9AAE5E0C77FA90E43286CE5A464AF2CB95A5D45F4B9632D3C922D7B1D1B350CD2504AD91B2A23DFB9C511CBCF0BEFF00123A8B93BD45A5ABAB2C6FB9C4B1A46D457231578AA2673F038284629AEDCB13BECB6B2324E49CB7AF2F37587900191A8000000000000000000000000000000008A800F24FAA4000000000000000000000000000000C2B55EDC378AAAA22027A427B7DCDA365965A16A2B65B9CCEA9953FE945CE17FF00892DD9DAA7E28EE1C3AAA7E0A4476BAE4A7BA5A2DCCFA14544C6227AF87C1097ECEB09B23B8F0EAA9F829963ED6CF39A98DF495BCF7B5B7FFB95231AFCD33F550FA1DAD11A6AAF54D7B29699ED8A38D8D7CD33933B8DEEEF52D766C7ECDBA9BF595CAFC717239A99F7158A4CBABA9E25834B6E4BCF551E0BAABF63D6C5A7779157D5C7509F4164DD7373DE98429EBADBEA2D572A8A1AD66E5440EDD722725EC54EE5422D598EEBE975F8757BC629EB0D606327D994D52E6E5296A1517AD2272FD846CDB9B447796E69A6A2EA6B46533FD2E2FE742C4FFB40222D4D9F2D4779B273F02B7A1656D1D7535545493ABE091B2B5AE85D8556AE533C0ECEAED4577D54FA67D75BD635A747237A389FC5171CF29DC5B7E9B39B9B14DF578F2C6DCB113BA30864FA792D5FE6951FBA77DC3C96AFF34A8FDD3BEE29B3A5CF4F57C81F6F24ABFCD67FDD3BEE1E4957F9ACFF00BA77DC3639ABEAF883E8FA7A88DB9929E66A76B98E4F8A1F14767B3DA0DE27B4BD926D9AD7FC9DACEDEF72FCD4EE5A77A7739387BD108C9EE095D4F5104CC5547472B5E8A9DCB9FB0989DA58F3523263B527CE1D1D5543F25EA6B9D12261B14EE567EAB97793DCA72C9AED7E344D61D3B795452C7267B578A7D884285A369534979C982969EFB3000219C00000000000000000000000000003064C0120B57A3E1F1F89B66A5ABD1F0F8FC4DB3D460F875F943E6BE3BF796A3F3DBEA000CAE500000000000000000000000000000000000080005920000000AA1E8B1F456B58A2A54A3BD4D8731311CEE4CEF2762F7F795C031E5C55CB1B4B7345AECBA3BF3E39FD16F576AAD332488B53D1CEEE48E743BDEF53A13592C35F44CA9968E08E191A8E47AFCDF05F615269AB6FCAB7BA5A6C658AE473FB9A9CC9DED52E694F6FA7B6C0A89D2F9CE44FC94E4685F0456F14A4CEF2F4FA6E2339B4F9353A9A56623B74EF2F9DDB6750CAC74B68AB54EB48E5F39BEA472724F6901BA5AEB2D550B0D740E8DC9C979A2A76A293ED93C756E8EA279679168DA9B8C8D578679AAA7FBEB3BCDB8D9F533EAEDB2235EF89CADC3B9AE3EB34B57364C569ACF58861C9C3B4DADC35CB8E3C3B5BB47AA25B26A5E92E557549F4638D1A8BEBE3F61C3D7D56955AA2AD5AECB23546278271F7E4B3F4FD95BA6ED754C8DCB3B95CE7B7098554C7042A2AEB65C96592A2A68EA5AB2395EB98D79AAE54BE1BD6F966FBF46BF10D364D36871E9F6EBBEF2E6032A8E6B951ED56AA75298375E776D96BECB2A52A34FD452393290BD5BE0BC7EF2B4BA53AD25CEAE05FA92B913DA4CB6472B9B71AD853E8BA34763BD14E3ED0E9FC97534FFF00E54E93DAABF71A98BDDCF68F577B591E370DC593FB7A23200371E7C0000000000000000000000000000000115001E49F54800000000000000000000000000007DA878D7D237A9D33117FCC87C4FA533FA3A9824C7D0918EF63917EC08B7D994BF6C0F576BCAA6AF26431227B1549B6CE7FF292E3EAA9F8290BDB1468DD7123D39494D13BDCA9F6135D9C7FE525C7D553F0532D7EDCBCFEABFD8E2F9D51ED84DDA9686E1574352F464956C63A2739708AAD45F37D6A8B9F02F4CA769F91ADF4F3D64D4F4F4713E5A8911118C67355EE2C28748ED05226EED554B13A9AB5DC93DA296DA36D95E29A0C59337893922B33E52BD6491B1B1CF7B911AD4CAAAAF043F3F5EA2875B6D4960A273BC9267231D2C69CD8C6F9CE4FF7D67DAE5A3B5DCB472255BEA2AA1C79D0A566F6F78678FA8DAD8D5CE86DB7BA8B6D6D2AC771A95DC64F2734DDFF0094A8A9C3EDF61333CD310C5A6D357498B266C578BDB6DBA797E2B4AC1A46CD628D128A8A3E93AE591379EABFACA4811AD44C235113D4641936D9E7F265BE49DEF3BCB184EC4184EC432031B184EC4184EC43200C613B10613B10C803CAB1AEE0AD6AA77A114D4FA0ACB7E85CAFA665354F36CF0351AE45EF4E4BE24B4113113DD97166C98A79A93B4BF2DEAAD3D5BA66E7E495ED4563F8C5337E8C89F62F71C593E8397B1327E93DA5D823BF697A98D199A981AB3C0E4E68E6F578A653C4FCD8EE2D7276A60C36AED2F69C375BED78666DF6A3BA7BB57F3A4D3CFEB75B98AA40C9E6D7711DC6CD4D9E30DBD88BEDFF00420645FBB370EFF6D5FD7EA000AB7400000000000000000000000000003064C0120B57A3E1F1F89B66A5ABD1F0F8FC4DB3D460F875F943E6BE3BF796A3F3DBEA000CAE50000000000000000000000000000000000000002C00000000001F482274F3C7146997BDC8D44F5952B1369DA1636CA6D8E8E19EE52A265C9D1C6AA9D5D6A43B565C9D78BFCF33155EDDEE8E344EB44E09ED2C7D412B34D68A4A68977667B12262A73DE5E6BE0995207A06D6B71D4502B93E669FE75FE1CBDE68E3B44CDB34FE8F4DACC3315C3C3A9DE7ACFEA9DCCE4D27A11ADCA24E91E329D6F77595452D4CB4B591D540F564EC72391C9DA4DB6AF74496B21B6C6ECA429BEF44FCA5E5EECFB481A1934B49E49B5BCDA9C673FF00AF18B1CED18FA47CD65D2ED2A9FC9A34A8A2996A31E76EAA6157B8F69B4AA4FAF6F9BC1C8A56461C9927D9317A2238EEB3688E6FDA16FC17ED357F448AA5226C8BC9B3B3757C17B4E45FF67CC7C6E9AC92F7A42F5CB7C14AD53872243A7356D7D96446A3967A5EB85EBC113BBB0C7E05F1F5C53FA33D78A60D57B9ACA47E68EEEBECE20A8A1D552D354C4F8A5485779AE4C2F343E7B564FF008962E3CE99BFCCE2C5B3D4DB6F71C572A6463E66A6EE7939B9E6D52BADAB393F096344C2E29DBFCCE2986FCF9F798EBB3775DA5AE9B86F2D6DCD133BC4A16003A0F22000000000000000000000000000000008A800F24FAA4000000000000000000000000000030A64013CDA7E6B6834CDD5BC52A6912355FF00AD31F79AD69A9D676CB33ED9436FAB4A37EF6F316937B3BDCF8F89B14C897ED924D0A7FE2ACB51D22679F46BC797A957D86FD06D6AB696869E07DAE199F1C68C5916654572A26338C193A6FBCCB8B1E2462F0A948B72CCC6D3FF0071FB23D60A7D57A7EADD536DB3D5367737737E4A5DF544EEEC242BAAB68B95FE8753FC127DC7DD36C75A8A9FD4F022F674EBF719FC7257AF1F91E0FDF2FDC4ED5F553263D565B735F05667E6D776AADA2F0FE8753CFF00324FB88EDC29354D75E52EB35A2AD2B9AF6BFA48E9B772E6E30B84EBE084A976C75EAA9FD4D073FEF97EE0BB63AFE3FD4F073FEFD7EE1EEFA94C7AAC73BD30563F56AFE156D1BF33AAFE093EE33F853B465FFD1D57F049F71B3F8E2AC44E367833FE3AFDC6536C757FA1E0FDFAFDC3DDF563F66CFF00F1EBFB357F0A368DF9A557F0483F0A368DF9A557F0486D7E392AFF0043C1FBF5FB87E392AFF43C1FBF5FB87BBEA7B367FF008F5FD9ABF851B46FCD2ABF8241F851B46FCD2ABF82436BF1C957FA1E0FDFAFDC3F1C957FA1E0FDFAFDC3DDF53D9B3FFC7AFECD5FC28DA37E6955FC120FC28DA37E6955FC121B5F8E4ABFD0F07EFD7EE1F8E4ABFD0F07EFD7EE1EEFA9ECD9FF00E3D7F66AFE146D1BF34AAFE0907E146D1BF34AAFE090DAFC7255FE8783F7EBF718FC7256FE8883F7CBF70E9EA7B367FF008F5FD9A926A7DA33915AB4753854E3FD09086525A6AD75050D05652CF4F3544ECF32566EAE15DC571D9C3DC4F936C95B9F4441FBE5FB8F8E8FB83B54EBEA8D457089B0D3DBE9FA456A3B28C544546A7BDCBE0368F566C739B4F4BDAD8A2B1B7979CF9381B56AB4AAD735AD6AE590323853C1B95F7A9123EF70AB7DC2E3575B2AAEFD4CAE9573D48ABC0F818E6779DDD6D363F0F0D69E9000086500000000000000000000000000000C19300482D5E8F87C7E26D9A96AF47C3E3F136CF5183E1D7E50F9AF8EFDE5A8FCF6FA80032B94000000000000000000000000000000000000000B00000000012FD9A5B52BAFCB3BD33152B77D7F5BABED2225B9A3E99BA7F46BEB2A3849235677F7A7D5F763DA6AEAAFCB4DA3BCBABC1B4F1975117B7D9AF5945F6A1745AABCB68D8B98E99BE0AABCC92ECF28E3B5E9892E350DC3A66AC8ABD7BA9CBDDC4ADE9229EF97C6B132B2544B973B9E11578AF827C0B1768B5CCB669F8ADB4AA8C599123444E68C435F2D76AD30C7EAEA68F2F364CDC432768ECAC6EB58FAFB8D45548AAAE95EAEF51AC8A39837E3A4443CCDED37B4DA7BCBD000954306401D5D3D7EABB1D4BA5A554735C98746EE4BFEA6B5DEE53DD6B9F5554A8AF77244E4D4EC434C15E4AF3736DD59673649C718B9BDD8F27900191840000000000000000000000000000000115001E41F5480000000000000000000000000000000259B2FBAC741A93C8EB38D15C58B4D2B579657822AFB71E270F525AE5B1DF6B2DF322AF42FF31DF94C5E2D5F61CD5CA2A2A2AA2A7254EA2C5BF3135A68E86F50222DDED8DE8AB1889E7491FE5227BFDBD85BBC6CD1CBBE0CF197FF005B749F9F94FF008482AE9E24D87365E8A3E956919E7EE2678B9133929CC96E4772A6AED87D4454F222CB4B036195BD6D76F27B95389512136F263E17CDFEAF37F74B2002AEA8000000000000000058BB0F8A3935157B64635E9E4C8EC39329F490AE8B1361B2322D457292472358DA3455555E089BDC549A7768714998D2DF64675F2359AD2F0D6B5111B3E11113098C275120AACE97D99474DC1B72BF3B7E444E0E6C489CBD9C3FF729E6DB6EA6D59B40BADC5DE848245A89A57A61AAD444C357D7BAABEA381AD2FCED457D9AB1379B4ADF9BA762F0DD8D392E3A9578A9333B4CCB5EBBE6F0F079562267E7E51FE5C2001475C0004000000000000000000000000000000003BF6AF47C3E3F136CD4B57A3E1F1F89B67A8C1F0EBF287CD5C77EF2D47E7B7D400195C90000000000000000000000000000000000000196B55CB86A2AAF62264CB1AAF7B58D4CB9CB84253B4BC827743B38AE9988B55590C2BD8D6ABFEE3AF1ECEADB1373575D3B913B15AC4F81AD6D5E38F37571704D664EBCBB47E32AB816CB74BE94819F3B246FFD79F39F78F93F44B39F92F8C8EFBCAFB6567B44B63FA0E48FB592B1FAAB9D376E75D2F34D4C9F41CECBF8670DEB5279B53B8A52D053DB61546EFE1CE6B7A9A9C13FDF71D8B63F4ADBA7596DF352C52AA6EEF23B2B83DDCA9F4D5D67E9AB24A79A54444CACB8E1ED35AF9F9F245A6B3B43A98387F81A4BE1A64AF3DBCF7F245B6516BDEABA8B8CA986C69D1C7EBEB5F670381AF6E9F29EA19FA3766183E699D9C39A96B5B1B69A3A1F24A09E28E2E3F464455CAF5E72466A367543222F93574E8E55CAEFE1FF007134CF5F16725FF45753C3737B1534DA7989F39EAAB0137AED9D5CA1CAD2CD0D42272CF98ABF123770B15D2DEDDEAAA299ACEA722653DC6ED72D2D1D25E733683538637C9497300EE54C283234DE800480000F2002C0000000000000000000000000000000022A003C83EA8000000000000000000000000000000000ED692BFCFA76F11D5C397C2E4DC9E1EA919D7E29CCE2810AE4C75C959A5BB4A71AC6D4B6CA49AF1A72557E9DBBB375EC6F28D55728D54EAE3C97AB910545251A33543AC6E9E92B61F2CB355652A299533CF9B93BFB53AFD66C6ACD2294B49F2C69F93CBAC7226F2398997C3DCEEE4EDE69D65A7AB4B0E49D3DBC1CBE7DA7D7E7F8FD51107969E88744000480000000000007574CD35D2E35925AACF9DEAE674736170891A2E55557A93B7D878D3F64AFBF5C19496D855EE55F3E45E0C8D3B5CBD44C6ED78B7E8DA096C9A6A549AE9279B5B7044CAB57ADADEACFB93D64C7AB47559FAF838E37B4FEDF8CB5F5A5C68EC9676E93B0C88E631735F50DE0B2BFADBF7F821040AAAAAAAAAAAABC5557AC1599DD974F8630D36EF3E73EB2000360000000000000000000000000000000000001DFB57A3E1F1F89B66A5ABD1F0F8FC4DB3D460F875F943E6AE3BF796A3F3DBEA000CAE48000000000000000000000000000064C1D0B25AAA6F35CDA5A36E5EBC5CE5E4D6F5AA916B45637964C78AF96D14A46F32D4A6A79AAA66454F1BA491CB846B533927564D9E4D32364BACDD0B57FE5B78BBDA48E286CFA26D8D7CBE754BBEB632F91DDC9D49EE20B7FD6572BB6FC71C8EA5A65E4C8D70ABEB5E669F899337C3E91EAEF7B269387D62757EF5FFB63FCA6EEA9D33A61158CE85274E0A8D4DF7F8F6156DCEA23A8B954555347D147249BEC6A751A88864CF8B07873BCCEF2E76B388CEA62295AC56B1DB67726D5D7B9A1489F5AF4444C65A9BAABE27267AEABA8E3354CAFF5BD4F8221932463A57B4356FA8CD93ED5A65E40305B661DE59000D8DE59472A72554F529B305C6B29F1D0D54ECC7E4BD4D403963CD6ADEF5EB59949A835ADE6937512A3A5627D591339F1E649EDBB4785ED6B6E74CAC775BE3E29EC2B23260BE9B1DFC9D0C1C5F57827A5F7F9F55BCB43A6754C2AEA6585B3AA6731F98F4F5B48A5FF0041D75035F2D0392AE24E3BA9C1FEC21B13DD1C8D9237398F6F16B9AB8545269A6F5DD651B9B0DD57CAA9F96FE3CF6F8F598BC2CB8BE1CEF1E92DEAEB347AEF77534E4B7F747F984338A2AA39151C9C1517A816D5FEC16ED554495D6C7C5E538CA48DE4FEE7779555653CD4750F82A58AC958B87357A94CD8734648F4973F5FC3F268E627BD67B4C3E20C193339EF2002C0000000000000000000000000000000022A003C83EA8000000000000000000000000000000000000614EDE96D4B70D3952AFA2911F0BD7E769E4E31C89DE9D4BDE9EF38A60989D95C98EB92B34BC6F12B0DF66D3FAD58B3E9C9E2B4DE1C9E7D04FC237AF5EEE3B7BBD88436F565B8D96758AE7492C0BD4F54CB1DDE8E4E0A73D1551C8E6AAA3938A2A2E153BD17A949759F5F5DE8A04A4B824375A0C6162AB6EF3B1D9BDF7A293BC4F769C62D460E98A79ABE93DFF49FE51045C99276AED077B4CCACABB04EEE2AADCBA3DEF7A7B907E2F5954DDFB26A2B6D73179239DB8BEEC93C933D978D7E3AF4C9135F9C7F9EC82026B26CC75335331D3D34A9DADA84FB707C9366BAA57FF431277AD4331F1239656F6FD37F7C7FDA1E09D45B34BAB1BBF5F5F6DA38FAD5F36F63DD8F7994B0E8CB53B376BF4B719539C144D4C2AF670CFC49E59F356788619E94DED3F846E83451BE591B1C4C7C923D70D63132AABEA26B6BD06B0D3F97EADAC65A681A9BC8C5722CCFEEC757BD7B8FACBAF696D71BE1D2566A7A16AA63A79911F22FFBEF5521973B8D6DDAA9D5171A996A265EB7AF044EC44E4883DD5667519FA7D88FFB9FE23F74AEFBACA265B56D1A4E97E4DB5E30F97FE6CDDB95E69EDCFA8861E51307A2932D8C382986BB523F99600043280025600000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF5183E1D7E50F9AB8EFDE5A8FCF6FA80032B92000000000000000000000000120D1FA7D6FF005CF8DD32450C288E7AE32E5CF5211F3668AB6A68645928E77C322A63798B829939A6BB57BB369ED8E9922D9637AC792D6752E95D36DCCEDA7E99A9C77FE724FB4FA52EB4D3CC7E237244ABD69163E053F23DD2395D2395CF5E6E5EB3C9AFEC713F6A665D98E3D7C73FE8E3AD63E4B8AFBA7EDBAA99E554D53F3FBBBAD918EDE6A772A15EDDB49DDADB22A3E95F347D52429BCDC7D8722DF5F556F9D26A399F149DAD5E7EB26F6DDA44B1B11971A44957ADF1BB0ABE0A56299B0FD8EB0BDF51A0E213BE78E4BFAC7641DB4B52E7A3129E6572AE1137172AA496C3A1EE3707A3AADAB494DF595DF497BB04A1DB43B5747BC94753BFF93BAD4FB4E05E75FD6D5C6B1D04494AD5E1BD9DE77FA133933DFA56BB295D2F0DD3CF3DF273FE1094250696D36C449920595BD722EFBD54F2BAA34B54B7724647BBFF00541C0A9E59649A474933DD23DDCDCE5CA9E10B7B26FD6D699944F1C9A74C38EB15F92D8ABD2DA7AFD0F4B6D7C513978EFC18C78B79107BC690BB5B65545A774F0F54B12653C53A8E35256D4D04C92D1CCE8654FACD526F69DA44F1C691DCA95B32E31BF1AE157C0AC53362EB5EB09F1B41ADF8D5F0EDEB1D9075A4A8E93A3E825DFE5BA8C5CE491D8744DCEE32B5D551BA929FADCFE0E5EE44257F8C4B5247BCB4751BFF0093BADFBCE15DF6895752C732DD036991786FAAEF3B1F613E267BF4AD76234BC3B04F3E4C9CFF008424EDB6697D371A36A920E9719574D87397BF1F71E3F0AF4BCB1A325466EFFD54FC3E054D34D2CF2BA49A4748F771573972AABEB3C389F64DFADED33289E3B349E5C38EB15F92DAAAD37A72FECDFB6BE38A444FA54EA889E2DE441EF3A3EED6D7F9B02D4C5D524499F6A751C2A3AAA8A2A86CD4933A291BD6D5C139B5ED1AA216232E14AD9D7ADEC5C2AF811C997175ACF341ED1A1D6FC68F0EDEB1D908F23A8E9773A1951DD8AC5424363D1772B948D5A889D4B065155F2271C762212C4DA1DA5D1E5D4751BFF92AC6FDE71AEBB45AAA8639B6DA76D3B57948E76F2FB303C4CF7E95AEC9AE9387609E7BE5E6FC2212DA082CBA3E95D1AD5246E7E15EAF7E55EA9D78EAF035AA35669AA97AB6A3122F2557C394F815255544B5333A5A891D24AEE2E73972AAA7C488D1C77B4F55B271FB563C3C38E22BE92B764D3DA6B5042AB6E74314C9C51D02A22A7ADA56FA92D12D92E4B4B339AFCB51ED73792A2AAA7D8685354CD4B2A4B4F23A395BC9CD5C2A18A99E5A999D2CEF74923B9B9CB95532E2C56C73F6B7868EB35B83538E27C3E5BFAC767CC00677300000000000000000000000000000000115001E49F5480000000000000000000000000000000000000C003200212185C271C267A97AD0C804ED3DDF48AB2AE36EEC75752C4EC6CCE44F89F575C2B9CDC2D755AA75A2CCE545F79AB83284EEAF875F41EAB22E65739EBDAE72AFC42222270320895A221E4C80000000001200090000000000000000000000000000000000001DFB57A3E1F1F89B66A5ABD1F0F8FC4DB3D460F875F943E6AE3BF796A3F3DBEA000CAE4800000000000000000000000064DDB6DAAB6E7D279053BE758F1BC8DEACE7EE3E75F41536FA8582B617432A26775DD8579E37E5DFAAF38B2453C49AFBBEBE4D5001650000197183AF1E9DBBCB4EDA88E825753B9BBED9131C5BCF2724AC5EB6ED2C97C3929B73D6637650C9843AD6DD3B77B8D3A4F4B412BA25FA2E5C3729DA99C649B5E2B1BCC98F0E4CB3CB8EB33F27254C60E85DACD70B56EADC69A4811CB86AAAA2A2F8A2A9CF4E02B3168DE117A5B1CF2DE36914C19530595650F4793AD53A76EF4D4CEA89A865642D4DE572E38276F322D78AF795A98AF9379A5667672000140C9800003AD169CBBCB4EDA88E825753B9BBED9131C5BDA56D78AF7964A62C9937E4ACCEDE8E51930096260004A40000000000000000000000000000000115001E49F54800000000000000000000000000000185036AD9433DCEE34D454AD474F3BD23622F6A9743F4DE8FD196D864BE3595133FCD49266AC8E7AF5EEB392271F81586CF2B22A0D676AA8A876EC4D955AAABD5BCD56A7BDC5A5B5CD2B72D40943536A6A4EB4E8E6BA2DF46AAEF2A2E533C3ABB7B0C958DA3770B8966B7B4530DEDCB49EF30F355A4B4AEAEB33EAB4F24704A996B65851588D7A753D9C3B53AB257BA0B4749A86FF53495AAE869E8B854A27D2DECAA6E278A2F1EE2D0D9369BAFD3F67AB6DD11239EA25DEE851E8EDC6A261155538657BB3C3079D13554B0EB3D59429B8C9DD5093353ADC98E3EF5F796DB78DDA11ADC9863363C569B4476969D737679A7EBD2D7574B4A950DC6FF004913A5DDCA7D6771C29C0DA5E85A2A2B5FCB5624DDA76E166898BBCD56AAE11EDF154CA72C2E7860D6D61B3DBF55EA8AC9E8216D4D3554CE95B2ACAD4DD472E551D95CF0CE3867860B1AF141F27ECD2AEDF23925753DB1D1B97A955B1F34F14276E9B4A273469FC2C98B24DA67BC6FBABED9A684A4B8DBD2F17CF3A9D573143BDBA8A89CDCE5ECCA7B892DB23D9FDFEB1D6CA2A3A474D85C6EC4E8D5E9D6AD77055FF7D477FE467D468186D146F48DF251C70EFBB8E115111CABE1922745B30B22E528AF957E5B1F37C5333CD5EBE08994F69131B76567575CF6BDF2E49ACEFD36ED1F8CABEDA069A4D337C5A68A47C94B2B7A485EEC671C9517BD17E2871EC3047537DB6C33377A392A63639BD4A8AE445453775969FACD397875256B925DE4DF8E744E12A2AF3F5E79A1A9A6FF00B4B68FDB22FE7429E6F498ED33A5DF9B9BA775A3B55D2D67B46974A9B7514704EB3359BCD55CE1517B54E26CEB67A97BA76DCAF0E923A157622898BBAE971C15557A933E2BDDD735DB5FF6359FB4C7F071D8D46AFD3FA02A9287E69D4F4BD146A9F55708D47782AE4B4C46EF398F5D9ABA6AD2B6F7AD698DFF000E8E43AD7B3FA49FE4E99B6D64EDF3375F2F9CD5EC572AF05F1227B44D9DC16BB7C973B12BFC9E2F3A5A772EF2B5BF94D5E784EBC9583955CAAAAB955E7DE48A4D6D7E75A62B6A572B69591742A88C4DE73718C2AAA67970226636DA61D5A6835382F5BE3CBBFAEEB0B65FA52CB78D27155DC68239A7591EDDE555CE11787594FD6B1ADAC99AD4C35AF7227AB25F9B18E3A162FF001A4F89425C13FA7D47F88EFE6522D1D224E1D92F7D5668B4EFB4FF002B37641A6ED37BB657CB73A38EA1F1CC8C6ABB3C1319211AE28E0A1D5972A4A48922822930C6A2F044C21676C13D0F74FDA13F950AE3693C35CDDFFC6FB106DEEC234B92F3AFC94999DA23F84700055DC00000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9AB8EFDE5A8FCF6FA80032B920000037AC75CB6DBCD1D52265237A2B93B5ABC17DCA5A5B47A08EAB4ABEA226377A07B256AB53AB92FB973E060C99BC3BC5663BBA7A4E1FED583265ADBAD7C94F82D1D95D0363B4D555CCD45E9A4DDCBB8E5AD4EFEF55399B58A0486BE8AAA34444918B1AE3A95AB94FE62B1A989C9E1B2DB845EBA38D56FFA2020BAAC71C162D150C93469F334FD33D1C9C55CA9BCA9ED5C113D9F69E8AF12D45DAE8DE998B22A318E4F35EEEB72A75A71E5CB9911AA8DAD331D2192DC12F16C78EB6DED68DFE5081A31EE6AB9AD556B7E92A2706A76A9E50B86E1AD2CF6AAF7D0F412BBA25DC7AC4C4DC62F5A734E5D7833A9B4ED05FED0EADA16312A959D2C534698E93AF75DDB9E5C7914F6B98DB9ABB44B2DB8145A2D1832C5AD5EF0A74F4D6B9D9DD6AAE1155709C910B4F64B1B24B0D52BDAD77F497734CFD461BD2DE2C3A6EB27A573F153348E9665646AE54572E7CE5EECFB09B6AE62D34AD779571F04ACE1A66C9962B13EBFFEB81B1F5F9EBAFEAC7F171C8DA8AFFC56FF00F099F6926D9DD67CA3A82FD54888D64AAC73513879B9763DC7CF50E9B9EFFAD5EEC2C7451C6C49264EDE786F7FC33EDC3178AE79B5FA746F5B4D6CDC3298B0F5F7BFCCAB005C7A8EF16DD2F6E6D252C50BAA91BF350639762BBAF9F8AFBC8169CB14DAB6AABA69AB12196356AB9563DEDEDECF7A631836A9A8E6AF3DA36872753C2FC2C95C18EDCD927CBD3F5464162FE2CA4FD28CFDC7FF00D1CDD43A1DF66B44F5EB5E93245BBE6245BAAB972273CF793ED38A6768952FC1F598EB37B53A475EF0B0ACBFD8AA3FD85BFC88413416A3B5DA2D33C37255E95D3ABD311EF70DD6A7D84EACABFF000551FEC2DFE4423BB298209AC555D2451BB76A5C89BCD45C26EB4E7D6622B6DFD5EA7356F6CD8231CC44F2CF7EBE8835DE782EDAA24922CAD3544CD44CA6155382722DED4B5EB62D3D355D2C2C73A246B58C5E0D4CAA2272EAEE21F4178A3B2EB5BBC53C123FCA266471F46D4546AF7E553B509CDFAE505A6D72D65546F9216632D6222AAE571C9553B49CF69B4D6BB7462E198AB4C79EFCF116999DFA76DB7531A8F50D55FE581F56D8DBD1355A8D622E32ABC578AAF77B0E4265CE46B532ABC93AD549356AC3ABB5840DA06BE2867C22AAA615A8D4E2BC17B13813DB957DA345D143143499924CEEB1A89BCFC632E72A9B7E3785B52B5EBE8E25787DB596BE7CB97DD8FF00DBD7F4538F4731CAD7B55AE4EA54C28452DFB2DFADBABE3968AAE85AD95ADDE58A4C3DAA9CB28BDBCBB17895CEB1B2FC897C969D8AAB03DA9244ABCF757ABC1514C98B51CF6E4B46D2C1ADE19E0628CF8AFCF49F3ECE3977EADFEC857FF81F6147A17FD7B29E5B3CADAE544A5E8F32E796EA2657260D6CED6A4BA3FF008F579F1E7AFAC7F2A011AE56B9C8D556B79AA27043C97258356D9EBAB9B6EA589F4EBF463DE62358EF5617811DDA85860A564572A385B12B9FB93358984555E28EC7B7DA5E9AA99BF25ABB353370788C13A8C3922D11DD5E9F4E8A4E8FA458DE8CFCADD5C7B7916168BABD376AB52544D5113AE1BBBF22BD8AAE6AE3E8B729F0EB3A769D72CB95C9B4B0DAA7742AE46F48C5DE56E579B91138278936D45A26796BD20C3C270DEB59C99A226DDA2237FF00B54C5EB65FEC551FEC2DFE44227B4DB0524148CB95344D8A457A32646261AE45CE171DB9E1E24AECD84D1547CFFF0002DFE4435B519632D2B6875B8568ADA2CF9715A77F75461E991BDF9E8D8E7639EEA6495E824B1433CD517B9A2599AA8D8A2918AAD4EBDE5CA633D9D9825157AFA8E3AEF24B6D03EAD8C76EAB99C33FAA888B936AD9AD13B56BBECE2E9F8762C98E32E5CB11BF977955460B9B54D9A9AF9627D5793AC356D87A68D55BB923571F45DF035B65D1B1DA71CAE6B557A777154CF5214F6C8E49B6DD9B3FD06D1A88C336E931BC4EDFE151E1CBC1A995EA4EB55EC430B945547261C9CD3B0B62A2FDA7B4DDDAA69DB03DF52F955F3CAC622AA2B955DCFB133D474F5A5AE96EFA72A6658DAB2471ACB148DE7844CE33D8B823DAE62637AF4947F43ADA979C79626D5EF0A50F4D6B9D9DD6AAE132B84E484E3675A660B8A495F708FA48A37EEC71AFD1739138AAF6E3284AEEFABACF64ABF2148A47BE3C239208D1519DDCD3DC5EFAADADC948DE58B4FC222D8633E7C91489ECA73031DE5B1A9A8EC17DB3A55A54D2D34F237A48A773918AE5EA4777110D05A763BD5CA5756377A929B0AE445FA6EEA4F5732D5D4C4D66D31B6CC59B84E4A67AE1C768B7376945DB1BDF948DAAF544CE113A8F05BB7BD5D6DD3B55F27D2D1748F89137DAC446B19D78E5CF1DC6C4715A35B595D3A41BAFE2C47AB51248DDEBECE463F6B98DA6D5E8DBFE874BDAD8F1E589BC796DFE54D983ED594EFA4AC9E9A54C490BD58EF5A29F1373BF5702D59ACED20002A000000008A800F24FAA400000000000000000000000000000001B36DA292E15F4F4703A36CB33D236AC8EDD6E5782657D782CBB97E1DE90B440E4AC4ABA654566236F4AB172C6555B9F6E53815631CE639AE6395AF6AA2A39382A2A75A16659F6B55D4B44C82E56F8EB646A63A56CBD12B93BFCD5E25AB31E72E6EBF166BCD671D22F11DE27FF00B4D765EDBABAD75B75D4324AB5154E4DCE993755236A705DDC26EA655DD5DFD656D414373D59ACEE971B055454F347374AD91F22B17755551B8C22AAF04E29DE7AD59B49B95F28DD474B0328291FC246B5EAF73DBF92AEE1C3C08AD86F35B60B9C75D6E911B33515AA8E4CB5ED5EA54ECE05F9A22366AE9B459AB1932CC445ADD223CA13CBE5E75F5BEBBE4674D34B2B9C8D64F153B7E7117B177797BD09AEAC992C1B319E9AAE6E92A56952955D9CABE47261CBED5555F122ADDB34BD1A23EC91BA4FCA4A9544F66EFDA41B576ACB8EA99D8EAE56B208D731C11F06B7BFBD7BFD98226D11DA5829C3F3E7BD2B931C5223ACEDB755D50CD35F3661BD6C72AD5CD43B8D46AF1DF46E1CDCF6E5150ABB66D65BCB359D13D292AA9A381EAB3BA462B111B85CA2E7B7960D2D19ADAE1A5F7E281AD9E8E476F3A07AAA222F5AB57A95496546D8AA16354A5B3C5148BC9CFA857A7B11A9F12DCF129F63D569A3262C548B56DE6DADB4C1F29DD74FDB69918EAF9164C22BB1C155A888BEBC2FB08737485DB4FDE6CB51728A3646FAE8636E1E8B95DECF57A8E5B351D63F53C37BAD72D454C72A49BB9DD4C27D54EC4243A9B6892DF56DAAEB7320F23AA654A625DEDFDDCF9BCB8732B368DF796CE3D3EAB4F4AE0A444D769DE7E69F6DB3868C8FF698FE0A75AD7241AC342358E7E3CAA99617AA7D493185E1DCA992A8D69B419753DA1281F6E653A248D937D25DEE5DD84385A5F54DD34DCCE75BA66F46F545921913798FF0FB899B44CB4E9C2B34E9A2BDAF13BC3E957A2F50D35C92896D55524AAB847C6C5746BDFBFCB1EB542C5BA682B1DAF447945DA356575341BD24D048A8AE7AF1DD4EA5E2B84CA761A71ED8E548D3A4B2C6E913ADB51BA9ECDD5217ABB595CF53AB1957D1C548C76F369E34F373DAB9E6A47BB0D9E4D7EA2D4AE48E488EF313DD676C42BA39B4C4F468E6F4D4F33955B9E3BAEE28BEDDE4F02BCD5BA26F3417CAB482DF53534B2C8E7C32411ABD15157288B8E4BD5C71C8E0586F55D62AF6D5DB65E8E544DD722A65AF6F62A7616353ED8E7489A953668A495138B9950AD45F056AFC47344C6D28B69F55A5D45B2E9E39A2C956C974FD5E9FD3F3FCA2C58AA2A65593A35545DC6A222222F7F055F1294D5F5CDB9EA7B9D646A8B14B3B958A8B9CB51708BE2888A493546D2AEB79A57D2D346CA0A67A61FD1BB79EE4EB4DE5E48BDC840C8B5A3688867E1DA4CB4CB7D467FB56F2640055D900000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000171E8DA88EF9A35B4B33B7B76375349DB8C613FF8AA14E128D0FA9A3D3B254A54C52CB0CDBB848F0AA8E4CF6E3ABE06B6AB1CDE9EEF7875F836AEBA6CFB649F76D1B4A6775CE9DD9C369D331D43A148F08B8547BD7CEC75F5B94D8BC52FE13699B6CC89973A486454C752AA35DEE55F610BD6FAAE2D410D2C54B14B1471B9CE7A4889C57184C617D7ED37B496B6A6B3D962A2AC82A247C6AEC3A344C61573D6A9DAA6AF8178A45F6EBBBB71C4F4D7CF6C336FF4B96223E70EDED52E294D638A89AEC3AA9F877EAB70BF1DD36B6613324D2D1C6C5CAC723DAEF5E73F0542B9D637D4BF5D52A236BD903188C635D8CA76F2FF007C8F3A5F5154E9FAB7490B52585FC2485CB8476392E7A94C9ECD6F07963BF76A7F57C71C4A734CFB9B72FE8F86A7A6969350DC239D8AD72CCF7A653E922B95517D8A5C3A4A1928B4B5147548B1BDB0EF391C98DDEBC2F6703851ED06CD335AFA8A6A86C8DE288B1A3B1EA5C91FD55AE9F74A27D15BA17D3C12262491EA9BCE45E6984E09ED52B6AE4CD1159AEDB33E0C9A3E1F6C99E9979B9BB424DB2D9124B3D7C8D4546BEADEE4CA617E8B4AD75348B36A2B9BDDCFCA246F823951090E8AD594BA7EDD3D35553CF23E49964CC7BB8445444C715EE22972A86D5DCAB2A58D735B34CF9511DCD115CAB8532E1C76AE6B4CB9FAFD5E3CBA2C54A4F58EF09E6C753FA4DCFF00563F8B898DDB51D05AAE1494750F5E96A1C89C3EA22F255EECE3FDA159688D474DA79F58EA98A593A746A37A3C70C6739CAF79A5ABEF10DEEF4EACA7648C62C6D6EEBD133C33D9EB31DF4F39334EFD9B9A6E2F4D270FA56931CF13DBF54D3699A716A62F95A8D999634F9F44E6E6FE57AD3E1EA2B6A5ACA9A4DEF25A89A1DEFA5D1C8ADCE396704FAC1B40829ED51535CA9EA67958DDC57B11151C9D59CAA71209767D24B5F2C96F6C8CA67AEF35922222B73D5C15781974F17AC78778ECD0E2D7C196D5D569EDD67BC79C4BEDF2BDCB8FF58D6FF10FFBCF94D70ADA889D1545655491BB196BE6739171DCAA6A21E9BD66CF2D63C9C9F1B24F49B4AF1B327FC1547FB0B7F910E36C8D3FA8AB3F6A77F2B0E5506BBA1A7B0C16F75354AC91D3242AE4DDC2AA371DA73F43EACA3B0DB27A6AA86A1F23E65951636A2A222B5A9D6A9D873270DF96D1B79BD95788E9BC7C36E78DA2B313FB34B50FF6F65FDB19F61606D23FB1F55FAD1FF3A1575D2E50D5EA675C636C9D03A76CB8544DEC263298CF3E04A3566B5A0BC58E6A1A7A7AA64AF562A2BDADC70722F538CD7C5799A74ECE7E9F5986B8F5516B6DCDBEDF8F77336673321D55123F199237B5BEBE7F61616AEBD45656C12D4DBBCAA27AAA6FF0C317861173DBF614B413494F5114D0B959246EDE6B939A2963DB76894D25224577A47ABF1873A344735DDF85F871275386D378C911BA384710C74D3DB4F7BF2DB7DE276DE1B169D62CADA87A5B2C2F9256B72EE895A9C3D7822DAFEE53DCAB699F536FA8A27C6D73712A7D2E29CB87124EFD7B65A389CDB75148AF54CEEB6346267BD7FD14AFEFD77A9BD5C1F5556E4E3C18C4E4C6F6211831CF3F372ED0713D5D674DE178BCF33E91110E7A17B6A2824A9D3159140D57C8EA75DD6A75F9BC8A250B366DA3D1B6955B4D4D3F4CD44DDDF44C78F12FABC76BCD66B1BECC3C0F53830D32D735B6DE3F942F47D2CF57A9681B4E8ECB256C8F544CE1AD5455CF67678962ED4E546699E8DDF4A499A89EB4CAFD86BC3B40B4246B23E9A78A77226F31AC4CAAFAF3F120FAC752CBA86A63548FA2A58F8C6C55F39557EB2E3BB063E5C9972D6D35DB66CF8BA6D0E8B262C7939E6E9EDB34F5A74F587CBABE9A3A89A38D1F2BDEDDFE3D8D45E073E8F5B54DCEB62A1B2DB1B1ABDC88AE72E775BD6E5444E18F5A9F2B06BFA46DB23A5BB4122CAD62315CD6A39AF4C63976F69F2B9EBCA58617C760A148A477395EC46A7B13ED31C62C9369E6AEF3FB36FDB34D4C549C1922958EF111D6521DA871D2927F8ACF89D0B3FF0062A8FF00616FF22108D55ACE82F763928E3A6A9648F56B91CE46EEF05CF6E78F2E47DEDFAEE820B053DBDF4954B2C74C90AB911B8CA371DA57C1BF8711B79B2CF12D2FB55EFCF1B4D76FD5EB679A628AAEDE973AF8D27DF72A471BF8B511170AAA9D6B9F81F6ACD75494150EA4B2DAD1DBAEE8F7B1BA8AA9D8D44CAFB8E368BD60DB2D3BE8EBA37C94EAE57B1ECC658ABCD30BCD3ACEDD5EBBB3C2F74D436F592ADC8B87BA36B3DABCCC96C7926F3CF5E68FD9AB8353A6A69A9E0E48A4C77E9BCA5B13EAE4D3CE7DC11ADAA7D3ABA46B5308D5545E18EEE470F653C74BAE787CF3FEC39147B42A75B6F4374A7A87543D1C8F744898C2E708995EC5434B486B0A3B0DA568EA29EA647F48E7658D4C71F131F81922968DBCDB7FD534939B1DF9FA444FF8EE8AEA37B9DA86E7BCB9C554889FE654FB0B9D7FB1ABFB17FF00A147DD2A1B5773ACA9635CD6CD33E44477344572AF1F693FFC3CA04B22512D3D4EF793F45BD86E33BB8CF3363518ED7AD368ECE570AD6E1C3933DAF6DB9BB7EEEDECC26649A5D91B172E8E57A3BD6AB9F82A15A6ABA59E975157B6A5AE6B9F339ED554FA4D5555454F053EFA5B51D4E9FAA73E26A4B4EFFA712AE33D985EA5276CDA159A68DAB5305431E8B9DD7468B8F795E5BE1C93688DF764F1B4DC43494C3932725A88851E86BBD5504554C4818D91BBC8C7B951E89DE9824FB257B194972A6739AE959322AAB573BC8A98E1DD96AFB4E76A6D7E957472525AA17C69222B1F2BD51151392E113E2442C178AAB257B6A69153B1EC5E4F6F62FDE5FC3CB931CC5A1869A8D1683554B6199988EF2B2752EA9A7B2DD24A6AAB42CAB8CB64554C3D31D59416DD592D450F4F6ED3B52B4EAABC6356F15F51F06EBFB2D5C2D4B951488FC6775CC491117BBFDA1AF72DA1D2C54AE82D14922BB186BA4446B1BD8B84CE78FA8D78C56988AF27EEEB5B5F8E26D97DA2397CA2223741B51543EAAF95751240FA7748EDEE8A44C39BC3AFE3E2734FB544AFA89E49A672BE591DBCF72F5A9F3C1D4AC6D110F179AFE25ED6F59790012C4000000008A800F24FAA4000000000000000000000000000000000005800054000580005800000005400120002150001200094800090000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F4614C9850960C9801564C80580C29930A40C000AA59064043C8009480000000000000003D00025E40010000B0000000000000000AA193201000003C80091E8005800007900048000000022A003C83EA900000000000000000000000000000000000160000000000016000000000004A0000400000000000090000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F400097900040002C00000002A0000000000000000000000003D000240001E4005800000000000000010000A800000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B000000000000000008A800F20FAA400000000000000000000000000000000000580000000000058000000000012800000000000000000000000000000000000000000000000077ED5E8F87C7E26D9A96AF47C3E3F136CF4F83E1D7E50F9A78EFDE5A8FCF6FA80032B920000F40009000079001600000001540000000000000000000000003D000240001E40058000000000000000000055000000000000B00000000000000000FFFD9, '1', '2021-03-13 13:10:28', '1', '2021-03-13 13:10:28', b'0');
  148 +INSERT INTO `inf_file` VALUES ('5e8609290e915c4fa8b08e67.jpg', 'jpg', 0xFFD8FFE10DFA4578696600004D4D002A000000080007011200030000000100010000011A00050000000100000062011B0005000000010000006A012800030000000100020000013100020000001F000000720132000200000014000000918769000400000001000000A8000000D4000AFC8000002710000AFC800000271041646F62652050686F746F73686F702032312E30202857696E646F77732900323032303A30343A30322031373A32343A3135000000000003A001000300000001FFFF0000A00200040000000100000320A003000400000001000001C20000000000000006010300030000000100060000011A00050000000100000122011B0005000000010000012A012800030000000100020000020100040000000100000132020200040000000100000CC00000000000000048000000010000004800000001FFD8FFED000C41646F62655F434D0002FFEE000E41646F626500648000000001FFDB0084000C08080809080C09090C110B0A0B11150F0C0C0F1518131315131318110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C010D0B0B0D0E0D100E0E10140E0E0E14140E0E0E0E14110C0C0C0C0C11110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108005A00A003012200021101031101FFDD0004000AFFC4013F0000010501010101010100000000000000030001020405060708090A0B0100010501010101010100000000000000010002030405060708090A0B1000010401030204020507060805030C33010002110304211231054151611322718132061491A1B14223241552C16233347282D14307259253F0E1F163733516A2B283264493546445C2A3743617D255E265F2B384C3D375E3F3462794A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F637475767778797A7B7C7D7E7F711000202010204040304050607070605350100021103213112044151617122130532819114A1B14223C152D1F0332462E1728292435315637334F1250616A2B283072635C2D2449354A317644555367465E2F2B384C3D375E3F34694A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F62737475767778797A7B7C7FFDA000C03010002110311003F00F544924925293A64E929F18FADE19FF3ABAA48DC4DEDE49FF454ACD369FB3380796ED036EA74F26A9FD78C97B3EB8F55606C8F581FFC0A958D6E43DC037807B28C86505BB87D62EE9F91F68AEC7BEE6B5CC6BDC6480F11A4A1FA7D77AB07DD8F8F93934564FAAF631CEADB03D477AD77F315ED67BFF48F540820C1D7CD751F55053FB1FAB6EA8E4BFD3DA69AF09B90F26CBB0598CCFB45EFF45EFBED67E830BD1B1FFA1B327DFE95753D002D0644079DB3A5755AB26AC4B316DAF26FD68ADE20D83FE05C7F4767F61FF4FF0047FCE223BA3758AADF4DF876B2D01C4B4B44B431AFB2DF536BBF44E6574DCEDB6FBFF4562EC7AD136756E977D8DFB3D565B6DA2CC3763D4E190FC7AB1ECC4C6C8B1EFA6DB30EDC5F4F333A8F52CFB55946162D5F6BA2947EAB4B68CAEA05D6E43AFC6C4B9B6E28A7631BA6536BEA18F5E55F6751CFC1DFD532EAF53D4F4E8C965D93956E374FFB2E3D6FA0B6DE4BA6617D6B654DCBE9D8B9FE9583755763D76ED70F169AFD962EC3A17D64EA76D96616774CCAB32714B5B9365143DEF66EFA1F6BC6637757B9BEF66CFA7FE8D65F45774BA0FD5DC3774F77AEEEA15E583F68792CF55D87898D9AF69C766E6E6BB1ECCAA719DFF69ABAECF53D3CA62E7F17071B3FA8E3518782E155F6D6D6E2073AF7866E69CAFD27A75D9FCDB6EB5FECFD13130C227AAF8CE4351B3E96329ADCE6B032C60225A2EA6DAC3B69F7B7F4F535AF757BBF495AF37EB34578DD5F3E8ADBE9D75E4581958101AD277358D6FEEED77B56C3BA8DF4F5CC91439ADAF1AFC8A716AAC06D2CA197595B71E8A2ADB4D753FD365967A6DF52EB3F4F6BEDB150FACEFF00B47557E735A5ACCA6B09932058C6B6BB5AD77F65088119505D3265004F47296AFD52FF00C55748FF00C34DFF00A97AC995ADF54BFF00155D23FF000D37FEA5EA4627DE13274C8AD524924929FFD0F544924925293A64E929F09FAEEC9FAE1D59DFF0CD1FF8152B01DCF9ADEFAF0E23EB87578ED734C7FD6A9584E1EE07B4C7CD3482B82C0CB869F246A6B0F3B5C246920F1F728B29703C401C9F056B1D90F1A73AFC934AE0750D9C3C5ADD680D6001C35811C15D0E374AC79935336EEDE06D1F4A3E971F4952E958FEF693C49D7E2B7EB969E254323AB6B18EAD46F49C7F730D4DDAFF0073840824FD29597D6FA5D54EE2D1B77341606E9A8F6ED11FC95D334FB493A203B1ABBF21B65A37067D169E1464906ED9B844855393D1FA1399563DD60DAF68690D8D23F74FEEFB5687D60E8746474DB2DA5B16D23D481DE072B535EDC4A85969D0763A1F81D101908365470C786A9F2EDC473F72D5FAA07FECAFA47FE1A67E47ACFCBA855977560406BDC00F20568FD516FF00D95F473FF7699FF52F5781D9CC23523B3EF6993A6450A49249253FFFD1F544924925293A64E929F05FAF263EBA756F036B47FE05542C62241EFBB50B63EBE83FF3C7AAB876B87FE7AA56383EE1E1FEBEE40AE4AE2E207808251702C7D9696BB9747E2546BA9CF7348D7C63556FA7623EBCA24F0D2224729922297C626DE9B0A88EC0761F2F6AD4656EDBA842C0A9A183C5690600DD79EEA06E44506ABC32B682F78682A01F48FA37327CCA3BA9A277D906741BB80AA64D9D348F4CBEA6DA4C0687B43893DB6EE4C902BC16C8C80E86348772496F1082FCEC4F53F4B686469E253E3E2399510C044F8F654EDCBE97D3AD1F6C7B2BBEC05CDDE1C4C03B67DAD7353575E9ABC8F5EA5B5758CAD9AD56BCDB518896BFDDFF00548FF545B1F5ABA47FE1A67FD4BD5BFADF6D195660E650439B657657BDA080763B737E906FD1F5551FAA766EFADDD1C0ED94CFC8E57212B01CDC91A9C878BEF8993A65231A92492494FF00FFD2F544924925293A64E929F07FAF4377D6EEADFF001EDFFCF54ACEE8F875E7754A31ED1348DCFB478B180D85BFDA5A5F5E04FD6DEAE3FE1C7FE7AA5677D5BCAAF1FAC62BEC23D379752F9FF84696367FB4992D8D2F85710BEEF656F4FC73B5B93815D41803BD7C56ECF4C1FA2DBC7E77F2DC8195D2D941DF4925BCEBE20AD5B711F71BADCCB36E331D3B0BA1A770F6EF8F759FB9B10290CB2921ED2DD7DAC773B7F35D0AB027BB7A518F64BD39C7609E56A31C0F3ACAC9A5BE9FB55EA9F1051486593D2B032B5C8C7AEE3DB7B7700818DF57FA7E3DA2DAF1A8AC8320B2B00C8F376E5A55BC10028DD76D6B9BE4A39DD32C00ECCBD4AC360113DD0ACC7ADC009DBBF50476542C3D4FD3230D958B5D1165B25AD13EF3B1BF49C9E9ABABB2E0E7BD9E8B87BE352E70FE49FA09A9156D6FAE5D2DD6FD5E7E4077AAFC1B1B7B4F70C77E86F1FE6B98FF00FADAE33EA79FFB2EE91FF8699F91CBD22EB59753762BC82CBEB7D4E1C887B4B3FEFCBCD7EA583FF3ABA313CFDA980FDCE56701B15D9A5CDC6A57FBCFD04A2A4A2AC351749249253FFFD3F544924925293A64E929F06FAF13FF003BFABFFC70FF00CF74AC0C5A9F6BEC63352C63AC81FF000637BB5FEAAE8BEB9D2FBFEB97576B4682E6973DDA35A3D3AB955FA1E1D15F556398F3634D193EA480266B737D8D4384D13D14271E211BF53B9D07EB6E364D2DC7EA4F155EC01A2D78FD1D9FBAE738FF00376AE86C6B1CCF546C1A4EF90411CFD29DABCE31F01ECC9BF19F040D58EEC44E85AB5717A65C5A186D2299135C983FC90D55E7117A3771E43C3A8D5E9F7B79699F056B1DEC70826216457B9839D111993E9EB29ACA24EDFA80409F821DF6082663B954075105B13D92AAD16BE5CE803523C5327AE8BC11BB62EEA36D5596D741B081A1710D6FDFAB952C6EABD6ACBC0BE8AABA5C61D1634B88EDB55CB286E437520055D9D3E8C571BDD74EC05D06001085689120CF2F26BC5C5BF2DE76BA8ADCE209FCE03D8CFF003F6AE2FEA5B09FAD5D1FCB25B27E4E5B3D55CECF2EA812DA9C7D4DAE05A5DFE8DFEF8DCCFCF46FAA5D2998FD7B02C277385E3F2394D8FD3E64B5739E33A6D10FB028A928AB2D35D2492494FF00FFD4F544924925293A64E929F1DFACEDFF00B24EB193635CDC4A725AD73F69D9EA3AAA6373FF003ACFE42CBC7E8D93D7F2ECCBC1B5B895E3868B6F735CC68304CB760DDF41BFA47ADEFF0018DFF8A0C4FA3FCE5DFCC7F52BFE77FEEF7FEEB7A6B56AFF00C478FE6FFA3B3E87D1FA2CFE95FCBFFB91FC8F553A5C7C236A598FDBE296F77ABCF3306FFB0FA79370BEBACFACCC86506BB1A5C1BFA11BEE6EF764B5F47E83D1DFBEEA7F3DEA66814BFD116B4E4080EC7782CB8388935FB3D6ABD467F5DEB62EFE9479FE7EFF00E6B8E723FE4EFF00CD97FA1FF805CBFE60FA1F487F3BFCDFD21FCEFF0027FD2AAD2E2BE8DE87B75BCFFABC207ED7571DCEC88143D8E71240638ED7123E9358EFE6EC43C86E5D409B68786FEF012DFF0039B2B773BF9ABBFE4BFE6AAFE6BF9CE7FC07F23FEE27F2D407F363E9FD11F4BE97F6FF00EFC992ABD131E2AD5E6DB90D2ED343DC23D7925BA83007753EABF4FF00C17CBE925D17FE50C4FA1FCF33F9CFA3CFFAEC4CD1935AD1D0651955E39C9CEB3EC58AD05CE7B9A5D66D1F9C31D9EFDBBBD9FA445E82FC6EA37BC574DB752DDAD7E45CE643647AAE2719BBBE9D6DD8CFD25B6FFA5F4D56FADDFD1B2BF9FF00E98DFA7C7D13FCFF00FC0FFDC7FF0087F595CFA93FF22BB8FA777D1E7E8D7FCE7FDF7FE0D3870AD971D6BB3A9D4F0CE660D95B768B1CC2F617090D73C86D6E688FE73D3DFE9FFC26C5CEF4CCAA717EBBD5D2DAC706D394C635D21DA966F732CDA7F95F4D7517FF003C3FA5FD3ABF98FE6F86FD2FE4FF00DFD55BBFF141D2BFA1FF0049FF000BFD33E8DBF4BFF44A78DC5B19D8D767B851524CAC3554924924A7FFD9FFED160050686F746F73686F7020332E30003842494D0425000000000010000000000000000000000000000000003842494D043A0000000000D7000000100000000100000000000B7072696E744F7574707574000000050000000050737453626F6F6C0100000000496E7465656E756D00000000496E746500000000496D67200000000F7072696E745369787465656E426974626F6F6C000000000B7072696E7465724E616D65544558540000000100000000000F7072696E7450726F6F6653657475704F626A6300000005682168378BBE7F6E00000000000A70726F6F6653657475700000000100000000426C746E656E756D0000000C6275696C74696E50726F6F660000000970726F6F66434D594B003842494D043B00000000022D00000010000000010000000000127072696E744F75747075744F7074696F6E7300000017000000004370746E626F6F6C0000000000436C6272626F6F6C00000000005267734D626F6F6C000000000043726E43626F6F6C0000000000436E7443626F6F6C00000000004C626C73626F6F6C00000000004E677476626F6F6C0000000000456D6C44626F6F6C0000000000496E7472626F6F6C000000000042636B674F626A630000000100000000000052474243000000030000000052642020646F7562406FE000000000000000000047726E20646F7562406FE0000000000000000000426C2020646F7562406FE000000000000000000042726454556E744623526C74000000000000000000000000426C6420556E744623526C7400000000000000000000000052736C74556E74462350786C40520000000000000000000A766563746F7244617461626F6F6C010000000050675073656E756D00000000506750730000000050675043000000004C656674556E744623526C74000000000000000000000000546F7020556E744623526C7400000000000000000000000053636C20556E74462350726340590000000000000000001063726F705768656E5072696E74696E67626F6F6C000000000E63726F7052656374426F74746F6D6C6F6E67000000000000000C63726F70526563744C6566746C6F6E67000000000000000D63726F705265637452696768746C6F6E67000000000000000B63726F7052656374546F706C6F6E6700000000003842494D03ED000000000010004800000001000200480000000100023842494D042600000000000E000000000000000000003F8000003842494D040D0000000000040000005A3842494D04190000000000040000001E3842494D03F3000000000009000000000000000001003842494D271000000000000A000100000000000000023842494D03F5000000000048002F66660001006C66660006000000000001002F6666000100A1999A0006000000000001003200000001005A00000006000000000001003500000001002D000000060000000000013842494D03F80000000000700000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800003842494D040000000000000200093842494D040200000000001400000000000000000000000000000000000000003842494D043000000000000A010101010101010101013842494D042D00000000000600010000000A3842494D0408000000000010000000010000024000000240000000003842494D041E000000000004000000003842494D041A00000000033F000000060000000000000000000001C20000032000000005672A68079898002D0034000000010000000000000000000000000000000000000001000000000000000000000320000001C200000000000000000000000000000000010000000000000000000000000000000000000010000000010000000000006E756C6C0000000200000006626F756E64734F626A6300000001000000000000526374310000000400000000546F70206C6F6E6700000000000000004C6566746C6F6E67000000000000000042746F6D6C6F6E67000001C200000000526768746C6F6E670000032000000006736C69636573566C4C73000000014F626A6300000001000000000005736C6963650000001200000007736C69636549446C6F6E67000000000000000767726F757049446C6F6E6700000000000000066F726967696E656E756D0000000C45536C6963654F726967696E0000000D6175746F47656E6572617465640000000054797065656E756D0000000A45536C6963655479706500000000496D672000000006626F756E64734F626A6300000001000000000000526374310000000400000000546F70206C6F6E6700000000000000004C6566746C6F6E67000000000000000042746F6D6C6F6E67000001C200000000526768746C6F6E67000003200000000375726C54455854000000010000000000006E756C6C54455854000000010000000000004D7367655445585400000001000000000006616C74546167544558540000000100000000000E63656C6C54657874497348544D4C626F6F6C010000000863656C6C546578745445585400000001000000000009686F727A416C69676E656E756D0000000F45536C696365486F727A416C69676E0000000764656661756C740000000976657274416C69676E656E756D0000000F45536C69636556657274416C69676E0000000764656661756C740000000B6267436F6C6F7254797065656E756D0000001145536C6963654247436F6C6F7254797065000000004E6F6E6500000009746F704F75747365746C6F6E67000000000000000A6C6566744F75747365746C6F6E67000000000000000C626F74746F6D4F75747365746C6F6E67000000000000000B72696768744F75747365746C6F6E6700000000003842494D042800000000000C000000023FF00000000000003842494D041100000000000101003842494D04140000000000040000000A3842494D040C000000000CDC00000001000000A00000005A000001E00000A8C000000CC000180001FFD8FFED000C41646F62655F434D0002FFEE000E41646F626500648000000001FFDB0084000C08080809080C09090C110B0A0B11150F0C0C0F1518131315131318110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C010D0B0B0D0E0D100E0E10140E0E0E14140E0E0E0E14110C0C0C0C0C11110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108005A00A003012200021101031101FFDD0004000AFFC4013F0000010501010101010100000000000000030001020405060708090A0B0100010501010101010100000000000000010002030405060708090A0B1000010401030204020507060805030C33010002110304211231054151611322718132061491A1B14223241552C16233347282D14307259253F0E1F163733516A2B283264493546445C2A3743617D255E265F2B384C3D375E3F3462794A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F637475767778797A7B7C7D7E7F711000202010204040304050607070605350100021103213112044151617122130532819114A1B14223C152D1F0332462E1728292435315637334F1250616A2B283072635C2D2449354A317644555367465E2F2B384C3D375E3F34694A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F62737475767778797A7B7C7FFDA000C03010002110311003F00F544924925293A64E929F18FADE19FF3ABAA48DC4DEDE49FF454ACD369FB3380796ED036EA74F26A9FD78C97B3EB8F55606C8F581FFC0A958D6E43DC037807B28C86505BB87D62EE9F91F68AEC7BEE6B5CC6BDC6480F11A4A1FA7D77AB07DD8F8F93934564FAAF631CEADB03D477AD77F315ED67BFF48F540820C1D7CD751F55053FB1FAB6EA8E4BFD3DA69AF09B90F26CBB0598CCFB45EFF45EFBED67E830BD1B1FFA1B327DFE95753D002D0644079DB3A5755AB26AC4B316DAF26FD68ADE20D83FE05C7F4767F61FF4FF0047FCE223BA3758AADF4DF876B2D01C4B4B44B431AFB2DF536BBF44E6574DCEDB6FBFF4562EC7AD136756E977D8DFB3D565B6DA2CC3763D4E190FC7AB1ECC4C6C8B1EFA6DB30EDC5F4F333A8F52CFB55946162D5F6BA2947EAB4B68CAEA05D6E43AFC6C4B9B6E28A7631BA6536BEA18F5E55F6751CFC1DFD532EAF53D4F4E8C965D93956E374FFB2E3D6FA0B6DE4BA6617D6B654DCBE9D8B9FE9583755763D76ED70F169AFD962EC3A17D64EA76D96616774CCAB32714B5B9365143DEF66EFA1F6BC6637757B9BEF66CFA7FE8D65F45774BA0FD5DC3774F77AEEEA15E583F68792CF55D87898D9AF69C766E6E6BB1ECCAA719DFF69ABAECF53D3CA62E7F17071B3FA8E3518782E155F6D6D6E2073AF7866E69CAFD27A75D9FCDB6EB5FECFD13130C227AAF8CE4351B3E96329ADCE6B032C60225A2EA6DAC3B69F7B7F4F535AF757BBF495AF37EB34578DD5F3E8ADBE9D75E4581958101AD277358D6FEEED77B56C3BA8DF4F5CC91439ADAF1AFC8A716AAC06D2CA197595B71E8A2ADB4D753FD365967A6DF52EB3F4F6BEDB150FACEFF00B47557E735A5ACCA6B09932058C6B6BB5AD77F65088119505D3265004F47296AFD52FF00C55748FF00C34DFF00A97AC995ADF54BFF00155D23FF000D37FEA5EA4627DE13274C8AD524924929FFD0F544924925293A64E929F09FAEEC9FAE1D59DFF0CD1FF8152B01DCF9ADEFAF0E23EB87578ED734C7FD6A9584E1EE07B4C7CD3482B82C0CB869F246A6B0F3B5C246920F1F728B29703C401C9F056B1D90F1A73AFC934AE0750D9C3C5ADD680D6001C35811C15D0E374AC79935336EEDE06D1F4A3E971F4952E958FEF693C49D7E2B7EB969E254323AB6B18EAD46F49C7F730D4DDAFF0073840824FD29597D6FA5D54EE2D1B77341606E9A8F6ED11FC95D334FB493A203B1ABBF21B65A37067D169E1464906ED9B844855393D1FA1399563DD60DAF68690D8D23F74FEEFB5687D60E8746474DB2DA5B16D23D481DE072B535EDC4A85969D0763A1F81D101908365470C786A9F2EDC473F72D5FAA07FECAFA47FE1A67E47ACFCBA855977560406BDC00F20568FD516FF00D95F473FF7699FF52F5781D9CC23523B3EF6993A6450A49249253FFFD1F544924925293A64E929F05FAF263EBA756F036B47FE05542C62241EFBB50B63EBE83FF3C7AAB876B87FE7AA56383EE1E1FEBEE40AE4AE2E207808251702C7D9696BB9747E2546BA9CF7348D7C63556FA7623EBCA24F0D2224729922297C626DE9B0A88EC0761F2F6AD4656EDBA842C0A9A183C5690600DD79EEA06E44506ABC32B682F78682A01F48FA37327CCA3BA9A277D906741BB80AA64D9D348F4CBEA6DA4C0687B43893DB6EE4C902BC16C8C80E86348772496F1082FCEC4F53F4B686469E253E3E2399510C044F8F654EDCBE97D3AD1F6C7B2BBEC05CDDE1C4C03B67DAD7353575E9ABC8F5EA5B5758CAD9AD56BCDB518896BFDDFF00548FF545B1F5ABA47FE1A67FD4BD5BFADF6D195660E650439B657657BDA080763B737E906FD1F5551FAA766EFADDD1C0ED94CFC8E57212B01CDC91A9C878BEF8993A65231A92492494FF00FFD2F544924925293A64E929F07FAF4377D6EEADFF001EDFFCF54ACEE8F875E7754A31ED1348DCFB478B180D85BFDA5A5F5E04FD6DEAE3FE1C7FE7AA5677D5BCAAF1FAC62BEC23D379752F9FF84696367FB4992D8D2F85710BEEF656F4FC73B5B93815D41803BD7C56ECF4C1FA2DBC7E77F2DC8195D2D941DF4925BCEBE20AD5B711F71BADCCB36E331D3B0BA1A770F6EF8F759FB9B10290CB2921ED2DD7DAC773B7F35D0AB027BB7A518F64BD39C7609E56A31C0F3ACAC9A5BE9FB55EA9F1051486593D2B032B5C8C7AEE3DB7B7700818DF57FA7E3DA2DAF1A8AC8320B2B00C8F376E5A55BC10028DD76D6B9BE4A39DD32C00ECCBD4AC360113DD0ACC7ADC009DBBF50476542C3D4FD3230D958B5D1165B25AD13EF3B1BF49C9E9ABABB2E0E7BD9E8B87BE352E70FE49FA09A9156D6FAE5D2DD6FD5E7E4077AAFC1B1B7B4F70C77E86F1FE6B98FF00FADAE33EA79FFB2EE91FF8699F91CBD22EB59753762BC82CBEB7D4E1C887B4B3FEFCBCD7EA583FF3ABA313CFDA980FDCE56701B15D9A5CDC6A57FBCFD04A2A4A2AC351749249253FFFD3F544924925293A64E929F06FAF13FF003BFABFFC70FF00CF74AC0C5A9F6BEC63352C63AC81FF000637BB5FEAAE8BEB9D2FBFEB97576B4682E6973DDA35A3D3AB955FA1E1D15F556398F3634D193EA480266B737D8D4384D13D14271E211BF53B9D07EB6E364D2DC7EA4F155EC01A2D78FD1D9FBAE738FF00376AE86C6B1CCF546C1A4EF90411CFD29DABCE31F01ECC9BF19F040D58EEC44E85AB5717A65C5A186D2299135C983FC90D55E7117A3771E43C3A8D5E9F7B79699F056B1DEC70826216457B9839D111993E9EB29ACA24EDFA80409F821DF6082663B954075105B13D92AAD16BE5CE803523C5327AE8BC11BB62EEA36D5596D741B081A1710D6FDFAB952C6EABD6ACBC0BE8AABA5C61D1634B88EDB55CB286E437520055D9D3E8C571BDD74EC05D06001085689120CF2F26BC5C5BF2DE76BA8ADCE209FCE03D8CFF003F6AE2FEA5B09FAD5D1FCB25B27E4E5B3D55CECF2EA812DA9C7D4DAE05A5DFE8DFEF8DCCFCF46FAA5D2998FD7B02C277385E3F2394D8FD3E64B5739E33A6D10FB028A928AB2D35D2492494FF00FFD4F544924925293A64E929F1DFACEDFF00B24EB193635CDC4A725AD73F69D9EA3AAA6373FF003ACFE42CBC7E8D93D7F2ECCBC1B5B895E3868B6F735CC68304CB760DDF41BFA47ADEFF0018DFF8A0C4FA3FCE5DFCC7F52BFE77FEEF7FEEB7A6B56AFF00C478FE6FFA3B3E87D1FA2CFE95FCBFFB91FC8F553A5C7C236A598FDBE296F77ABCF3306FFB0FA79370BEBACFACCC86506BB1A5C1BFA11BEE6EF764B5F47E83D1DFBEEA7F3DEA66814BFD116B4E4080EC7782CB8388935FB3D6ABD467F5DEB62EFE9479FE7EFF00E6B8E723FE4EFF00CD97FA1FF805CBFE60FA1F487F3BFCDFD21FCEFF0027FD2AAD2E2BE8DE87B75BCFFABC207ED7571DCEC88143D8E71240638ED7123E9358EFE6EC43C86E5D409B68786FEF012DFF0039B2B773BF9ABBFE4BFE6AAFE6BF9CE7FC07F23FEE27F2D407F363E9FD11F4BE97F6FF00EFC992ABD131E2AD5E6DB90D2ED343DC23D7925BA83007753EABF4FF00C17CBE925D17FE50C4FA1FCF33F9CFA3CFFAEC4CD1935AD1D0651955E39C9CEB3EC58AD05CE7B9A5D66D1F9C31D9EFDBBBD9FA445E82FC6EA37BC574DB752DDAD7E45CE643647AAE2719BBBE9D6DD8CFD25B6FFA5F4D56FADDFD1B2BF9FF00E98DFA7C7D13FCFF00FC0FFDC7FF0087F595CFA93FF22BB8FA777D1E7E8D7FCE7FDF7FE0D3870AD971D6BB3A9D4F0CE660D95B768B1CC2F617090D73C86D6E688FE73D3DFE9FFC26C5CEF4CCAA717EBBD5D2DAC706D394C635D21DA966F732CDA7F95F4D7517FF003C3FA5FD3ABF98FE6F86FD2FE4FF00DFD55BBFF141D2BFA1FF0049FF000BFD33E8DBF4BFF44A78DC5B19D8D767B851524CAC3554924924A7FFD93842494D042100000000005700000001010000000F00410064006F00620065002000500068006F0074006F00730068006F00700000001400410064006F00620065002000500068006F0074006F00730068006F00700020003200300032003000000001003842494D04060000000000070006000000010100FFE10DD2687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F003C3F787061636B657420626567696E3D22EFBBBF222069643D2257354D304D7043656869487A7265537A4E54637A6B633964223F3E203C783A786D706D65746120786D6C6E733A783D2261646F62653A6E733A6D6574612F2220783A786D70746B3D2241646F626520584D5020436F726520352E362D633134382037392E3136343033362C20323031392F30382F31332D30313A30363A35372020202020202020223E203C7264663A52444620786D6C6E733A7264663D22687474703A2F2F7777772E77332E6F72672F313939392F30322F32322D7264662D73796E7461782D6E7323223E203C7264663A4465736372697074696F6E207264663A61626F75743D222220786D6C6E733A786D703D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F2220786D6C6E733A786D704D4D3D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F6D6D2F2220786D6C6E733A73744576743D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F73547970652F5265736F757263654576656E74232220786D6C6E733A64633D22687474703A2F2F7075726C2E6F72672F64632F656C656D656E74732F312E312F2220786D6C6E733A70686F746F73686F703D22687474703A2F2F6E732E61646F62652E636F6D2F70686F746F73686F702F312E302F2220786D703A43726561746F72546F6F6C3D2241646F62652050686F746F73686F702032312E30202857696E646F7773292220786D703A437265617465446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D703A4D65746164617461446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D703A4D6F64696679446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D704D4D3A496E7374616E636549443D22786D702E6969643A34656266653730652D643236652D623834312D613962612D3232623834663439646366312220786D704D4D3A446F63756D656E7449443D2261646F62653A646F6369643A70686F746F73686F703A64633333616566382D343164372D343134372D626566652D3133623366363839326632642220786D704D4D3A4F726967696E616C446F63756D656E7449443D22786D702E6469643A39633734393932312D633861652D393634382D613065372D613762366131393131336266222064633A666F726D61743D22696D6167652F6A706567222070686F746F73686F703A436F6C6F724D6F64653D2233223E203C786D704D4D3A486973746F72793E203C7264663A5365713E203C7264663A6C692073744576743A616374696F6E3D2263726561746564222073744576743A696E7374616E636549443D22786D702E6969643A39633734393932312D633861652D393634382D613065372D613762366131393131336266222073744576743A7768656E3D22323032302D30342D30325431373A32343A31352B30383A3030222073744576743A736F6674776172654167656E743D2241646F62652050686F746F73686F702032312E30202857696E646F777329222F3E203C7264663A6C692073744576743A616374696F6E3D227361766564222073744576743A696E7374616E636549443D22786D702E6969643A34656266653730652D643236652D623834312D613962612D323262383466343964636631222073744576743A7768656E3D22323032302D30342D30325431373A32343A31352B30383A3030222073744576743A736F6674776172654167656E743D2241646F62652050686F746F73686F702032312E30202857696E646F777329222073744576743A6368616E6765643D222F222F3E203C2F7264663A5365713E203C2F786D704D4D3A486973746F72793E203C2F7264663A4465736372697074696F6E3E203C2F7264663A5244463E203C2F783A786D706D6574613E2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020203C3F787061636B657420656E643D2277223F3EFFEE000E41646F626500644000000001FFDB0084000202020202020202020203020202030403020203040504040404040506050505050505060607070807070609090A0A09090C0C0C0C0C0C0C0C0C0C0C0C0C0C0C01030303050405090606090D0A090A0D0F0E0E0E0E0F0F0C0C0C0C0C0F0F0C0C0C0C0C0C0F0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC000110801C2032003011100021101031101FFDD00040064FFC401A20000000701010101010000000000000000040503020601000708090A0B0100020203010101010100000000000000010002030405060708090A0B1000020103030204020607030402060273010203110400052112314151061361227181143291A10715B14223C152D1E1331662F0247282F12543345392A2B26373C235442793A3B33617546474C3D2E2082683090A181984944546A4B456D355281AF2E3F3C4D4E4F465758595A5B5C5D5E5F566768696A6B6C6D6E6F637475767778797A7B7C7D7E7F738485868788898A8B8C8D8E8F82939495969798999A9B9C9D9E9F92A3A4A5A6A7A8A9AAABACADAEAFA110002020102030505040506040803036D0100021103042112314105511361220671819132A1B1F014C1D1E1234215526272F1332434438216925325A263B2C20773D235E2448317549308090A18192636451A2764745537F2A3B3C32829D3E3F38494A4B4C4D4E4F465758595A5B5C5D5E5F5465666768696A6B6C6D6E6F6475767778797A7B7C7D7E7F738485868788898A8B8C8D8E8F839495969798999A9B9C9D9E9F92A3A4A5A6A7A8A9AAABACADAEAFAFFDA000C03010002110311003F00FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8E35D5BCC737C2D3C9BFBFF666A389DAABAAEB92D09964A9F7C78D5CFA56B736CD2C94EF538F1AA82F96F534916762EE10D78F8E112B54DEDED35BD3EEA09B45B992D25620CA14D3265239BD8EDBCD5E6BB286DA2B8BE79A375FDFA924D4D3205B0232DB5BD4EF199998E5459C58F6A9ABEA16F71CB9114EF9125B120B8F3A5CDA026573418AA583F34D616346AB5298A09A424FF98F2DD0F80D2BE18691C4925DEBD7DAB05B61522434CAF2C51C6FBA7FE7122F60D17CBBA84175B333D4D7E6329E172714DF5E6AFE7ED22CE1043865814FAAB5F118F0B9A26F8C7F30BF306DEE7549AE2C8889391A95FA71E1499BC4758F3D5037A77ACDEA0AB47CBAE4E30713366E12F35D43F302DA14901531CE7ECCA7C72C11718E7796EAFE6ED57516663AA12A0515431E99608B8F2D430D9A677E524F3FAA4F5A9AE5822D0750978B98B8D140D8E4C63B63F9843BDC13F64532431B1F1AD0C5DB916EE72D8E362656ACB7457BE4BC3606368A13F2553F7E5321BB5F0EEDD0B6F916C0141ADD0558F5385BE2690CC5536E98B682985A4527312ABF1A6F5C9F44527A6F5255114979C48EC4E424136EE70A2D2593E54CA2516432D265A76A6F6B5FAACACBE041E995F0B319DE9DE5BFCCBF37E8C54E9FE619A075E8A1C8FE18699F88FA4FC9FF00F395FE6ED08C0BACAB6A71A302D2BFC5B0F98C890D8323EA6F247FCE5769BE63B8449ECD62F50F5D875AE564360C8FA2EC3CC5A46B32DADF898514F2F4EBD72B21BF14F74FF4D7626F1F53F8A192BF5207B785320439FC4115A4693711DBDF5F5F12CE8C0D913D857B640865CD910BAFAE46A41FEE46F95909115A6CE4BB46B98FAC20D7214C643662170CF7323C858AFA27E2FA314452DD56DE2D4F4C9F94A6B1827AF862DF163FA65C8FD1C2C11EADCA80D716F09EC33DE42A6D1472A2824F861069AB502C331D3BCB3E55F3C412795FCE9A746D05DC6CB0CEEBBD4A9A6FF3399784BA4D445F8C9FF3931F9253FE507E61EA96B145E9F97B57919B426A6C402C4D3AF866C605D3E41BBE5BAFA5230FC32DB583B90724F865D8B930CC5BCB5A16375C55AC5578E98AB78AA8BFDA38AAA2F7C55A3D7156B155EADD315560D8ABFADEFF009C6EFF00D677FC84FF00CD73E56FFBA45AE5A39349E6F68C28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF917B754FE45FBB34FC2ED532A855A803C71E1551370C0E3C2AADF5A26361ED863155D0DC52840DFC72C2A39A6893B3D0124F8D7205B423E172F227A6C401D86D9516714AB5F0D52FD80A139193607916A21A49641526A722125825DE9F335C1F4C75ED96C434929D699A6C96C434DD0F639708B519B2F86D62F8446DC7EB1F0971B52990CB0D9871BE87FCB0F341D3236D0D5B8C6E3E2981A1FBF28E17231CD35F3479E9A06B8D356666080FC7CAA4D6BDF0F0B9919BE7FD5BCC7246F2B3BB10C4EC4E3C2994DE7979AD87666AFDAE9921171331B2C0F56D4F996EFF003CB045C5931D8EF2A483F765822E3C93012875EBB1C988B4108794A034D865910C68BA38D5CFDACB0048895EF171AE4C36479A0A470A7A6580362A4738A2F877CC49C775A4724E0D32149016B354935AD71A4A1DD6BD77C7853689173C4000D282981B835EBA75A0AF8D30316FEB00F53CBE780C5810510B7617A1A7CB21C2C68DA6FA7EA011872EBE39021BC16463520EBC791A11BF8640867128FB5D46EECDD26B2B9642A6A021A6408660BEA2FCB2FCFDD73CBED676DA8D64D3C301752BEE42FCCE56437639517E927903F33746F37E9D6F35B5CC6CC69C5188FE272B21CE195EF305FA4D63FBD6531AAF4047864086E8E4B486CAF94DD3C40F0427627A64086D8CD96A5DDCDA59B81C5A07EAC065720CA52B09035922C373792515250683B641116276C6D6D61BBE6F53302029E9BE2DF179F4113DAEA124A8F54249515DB16F0CA34926E2FE49AEE5291C6018F7A54F860465161EA22FDB4CB9B1BE11ABC42946201CC9C45D46A60F8AFF00E73E6C935ED07CAFE6151B69FEA733E1CB966C6127479A3BBF21B5802DEF21BB07F772A9A2F6CB896A8B7129F492423FBC15197E12C7338F7CBDA14FB8C555475C55CDD7156B156A98AB78AA8B1353BE2AB6A7C7155E3156EA7C7157F5CBFF0038D9FF00ACEBF907FF009AE3CABFF748B5CB472693CDED5850EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF91688D3E8CD770BB55732D29BED5C3C2AA125C2826831E155317408208D8E02155E1B85AF4C8951CD358A7AEC0640B684DB436F56492BD16B9596615B5884496D2F7DF6CAE41B2245BC82F22E370C08A6F82213221279612262C82A46E7E599100E3CCAE5B8127C2F41C732621C6949524D42354F4A234917A1AE47306A2535D3BCDEBA4425797FA536DCC1FEDCC76FC4509A9F9B4384B899EB24952C6B5FE38D39824C1F50F30477E480698D24CAD8EDC5C8D85474E95C9C766360A4574C1CF635E9EF930D6404B3D13EA5541F0229BD72C01A26023D4B200A41E5D969BFDD9688B498A9C8A643CC30A7422BD32241B4C601C9CD0D0D4622D78559E6DA85BE9CB031A4148391EBD7EFC95A3758ABD0572A31B6611B1823A838384A95415A9D8EDDA98F09415600537EFDB070962DFD589EDEE477CA8B782D7D5877207CCE16629B36E3C4570F267C214BD23C80EE4F4C2427802690DB9461BF5CA484009D470F214276A6FE232B21980A5CBD19290CC580EB4DE83DF2B660332D27535212DEE8FFA3C9B487DB20591D9EA7E53F3E7983CB371CF47BA75B588D42722361ED5CACD22322FADFF002DBFE729E486FECA3F324A5B4F43C6EB7AD6B403F6B2B2DF0917D9AFF997E53F30E976D75A2CF1C72CA0114615DFE9C8172A322F48F2E1BBD5F477844BCCF02EA6BE032B937028CD596783CBD6EAE486690291DF2A6C890F3BF35C434FB6B478C9AC8A0B530D37C4879A9BFB99670B1D41AED5EFF2C0DE0B228A4BA8602D3935603D3A78FD1912CE554CFF004DBBBDD461B5B6949F4D3BB6DFAF32313ABD48BE4F08FF009CBD8E0D47F29B5582DF79B4BF4C311B9F889E99B081D9D0E789B7E39EB9664FE87818D4B86E5F7E5A1C5029425A239806C20F8732B0726190DA1CF7CC86A531D462AAABD7157375C55AC55D8ABB15506FB47156B155E3A0C55BC55FD72FFCE367FEB3AFE417FE6B8F2AFF00DD22D72D1C9A4F37B56143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF91745DBAE6B5DAA0270038DFBF4C557A007DF1B569937DBBE025217C042073DC654C931B4B9E50CA83AF638153ED2A660AE69F7614A367BA58ED6466DC57BE210497946B3748D33508EB930030322C65AED519B7A6D930C0A4B25EA976A1A6581AD2C9AE872FB4704D38D012DCEFD72B6D40CD37A94DCD07BE2CACA024DF7F0C56CA8140C8FF00BB32CBD8569F0F7CAB27369C922D18005B7B89916CE2B561340E5BAB2F4EB92C64B5D943DB5FDB89F5295B5385DAF559A094950D1CE7B04AEF99B8C2D95595FCC31E95FA5A2F2DEAB79369A4C971E6692CA54B64886DBBF1E1B7BE654698F1747A07953F25FF00357CD5E47B8FCC3F2CF921F5AF26DAC924BAB6B8AEDF686F20A01B713919D1482F2ED2EE9AFF0053F4EEAE9567B5774B4D35A8AB291B1591BF678F6AF5C85320537786D4C727D62D7D2746ACB0024AAB57E1A37BE16C1BA0A592333C1F5AB6956F6452D6B040A646283AFC2B8B2D91111FAC46DF5AD0357B7907FBCF3A594ADC97BBF4ED8D30F103505E5DC61A19341D524914F1B6B916725593FDF9C698D3094C2BC17577C9A69749D5DD17E004584A7930F1DB6C698198519259239ED629ECE48EE637F5EE6CEF94DAB7A0DF64D1E87010C6D165EFA492CFF437FCEC1AD7982636B06996E39B2843F0A8095272AE0B6424C9F59F2D79A3CADA9E9BA7F9E7C8D3686FAFA7FA33DD1786BC056A3985C85331262333C3A54F76F7BC648AB4B360D5AF80195D16C12513E60D2CD80917D45D661916331703F0A31DDBE818981642749BC3AE6906375955CC900F87512A429FE19594FE60222D35781D3EB68CAD1034926660015F9572B3129FCC840C7E65D1D24BEB4B581E196ED089EE402E021EE32070CAAD7F3211EFE61B4168AB6D299934E50F75301F184E8085EF90F02523417F34193E95ABBEB4AB7361A9FA4427EFD88A72403A53C6980E92498EA8047DBF9C7CB567070FAFC915C4CE561708580643F1127B54E0FCA49C886AA2CCF4DFCE48343113DBF98273C2842D0D36FA71FCA172A3AB8BE9FF00CBBFF9CDB4D1FD0B6D435C905A2AD18F0A9FF896425A434CA7AC14FAC348FF009CD2FC9CD42C53F4D798CACC46EA631D7FE0B043465C6FCE29EAFF00F393FF00939ABD91B3B0F33299266A44F22AA8527BD4B659F932D90D6EEC1B4AFF009C92FC948F548E1D6BCDBEB7D5488E20B10E0B20DAA581E9954B4843B0C5AC0FA4F4CF3168FABC116ADA4C424D0EE943D9DEF51231DCD3B653E018736EC9A8E21B326B4D5ED26FDD28E20EDB6D8D535DDBC63FE7231043F97F76F6EA5FD68D8B83BD681BAE646271B34453F1A350B93EBFD65BAC723023C3E239B1C54E8B53B294BF1309FB5C0E4332C38504337F1C2CD662AAABFC3155F8ABB15587AE2AD62AEE15DEB8ABB80F1C55DD36F0C55D8ABFAE5FF9C6CFFD675FC82FFCD71E55FF00BA45AE5A39349E6F6AC28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF90949CD3DF35AED52FB89CF2AF7C55B86E091D7E78AA21AE147461F7E02A39A924D50F534F0CA99A334E620B96D86F4AE054F2D6EFD2473D3C3154A750D59DAD254AF1F88648734179BDEDD33C8C49D8E4C302C72E27356DE9930C6492F362E77DB26D6A44FC66A69B7538CD38D42523B1FA72B6E435483D7156B155F63A7CDACEBBE57F2EC774BA6C5E65D66CF4A9755A8E708BA9021600F600D6B93C70123BB466354FD9DB4FF9F49FE51E9B35B5DF9C7FE725E596D2C19259EC276B48A07400311EA48EBB7C865808ADA838F7BBEA8D27FE704FFE70B7F2CBC93ADFE62EB5E4ED2FCFDA1F97AD1F53B8D68CE66458A1AB332885B893F4E5D007DEA4EFDC5F217E7E7FCFC07FE716353FC95F327E49FE4E7952E35AD3FCD1A73D92DB5DE9DF548AD1A421898DE956229B1CBE2A0D9B7BB7FCFBAED6DAEFFE7DEDABC11C097125CEA9E608E58A641C5CAD0F02C474D8EF91931E27CE5FF386BF901FF38ADFF3939F947F9A5E46D4AC20D13F3DE4D4AFA3D5B502693D8AA5C31B692CB911EA29FDBA74FA3229E2A7E6C7E75FE48FE62FE43F9FB55FCAFF003FD93DAC31B9934FF32509B7B8B752CD0949A9C492805403D7037465694FE5779EB49FCAEFCC9F267E62EBFA147E6CF2EE9F1490DDE9774291BF26A6F8B2E2EAFDABFC97FF009CC4FCA9FCF4F37697E48F21FF00CE3B5ADDCD7052DF51BD5B3AD9D9DB103D4066084034DC570B1E305EEDFF00393BF9B5F917FF0038B736896771F9223CD9E6AD663E3A258D869FF588BEAA48520BA275A9D862C38DF24AFF00CFC07F285102BFFCE28EA5A6B472F2BE54D1A4243F7A829818193E5CF2EEB1F945FF0039A1FF0039BFA5493F92469FE42D5B4CB5D2E7D04C660314D0D43332281435070B0326BF337F28BCA9F919FF003F16F267E5FF00E5ED82683A169F269B7D6F08FDE822E95988A3D41D80C89E4CE25EFF00FF003F7E5B6B6D7BF216FAED56EE1B8866F5D446B172F848FD803B9CAEB9B3069F945A4FF8720F3D7902F7CCBA4407CA305FC0757B66735684CAA5B90FF572BE8DAFDCAB4F397FCFACEEF5A9560F2669B26AD218AD25536AE12579540001F528C7B5460970F716278AB9BE8CF3FF00E497FCE0E7E5E7E5C69FE7AF387E5468DA6F90EF8441677470419BEC02858124FCF23C239D7E3E4E29B7CC49E6EFF9F50CE925A2F93B4A8B4E1113C84120527C38FAB5AFD3938C224F543E93FC95FC95FF009C13FCF1F2BEA3E60FCB0FCA9D1F52D0EC646D3EEEE9E378D870A93D5DBC32D18815DDE0B79E65FF009F5A683AA6B3A4DE792B4AB0D6B4B9A7D36FE25B7763CE0AAB0E5EA53AFB75C9C71041BA7E10595CE9716ADE686D3E258B449B5DD4A4D123AD185A191BD15A7871A65BC23AB5926F67DC5FF3827AD7FCE27E9FA779F3FE865346B2D425D52E61FF000CC570865F4A341FBDA85652A49A1EB8384364645FA0ADE64FF9F54F0E2FE56D1154776B7907FCCEC7843689C97DBEBFFF003EAD240B6F2B684EC4D14185C024F6AFAD80C026539232EB55FF009F5B229F5BCA9A1AB20ABA7A7202A3DFF7DB618E30D5C459F7E5FF0090FF00E7DF7F9C370BA2790BF2B6D35DE5F66FADEDE6FAB236FD67595941DBBE1300CE32931BFF009CC4FF009C6AFF009C4DFC9FFF009C73FCD3D534FF0021E85E59F375CE85247E5495A765BA92F792F130866DD857B0CA66221CAC5399237D9E1DFF0038E06E1FF24BC8D6FA85CDC48EB67037D52742BC18C62AC09DCD7357A900BB9C123D5F4B695A658ED26C48DC819824539F1281FCC5F2E5A79A3C9FAA5A7107EAF03F15EE7E16E99386CD59793F083CE5A73699AFEB5A5BC6D088677081C52B466E999F8CBA3D4C5283B5B59A9054AA1A5733226C38110866FE39364B315545FE18AAFC55BC554CF5C55D8AB5CE9B53157733E18AB7B9DE9D715750F862AFEB97FE71B3FF0059D7F20FFF0035C7957FEE916B968E4D279BDAB0A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8EE4B96A57F0CD6BB54BEE6E4F2FD78AAE86E01502BB62AB1E41CC1F7C05211724A0FA7E1953247B5D0458CD771D302AC9756E0B4AE2AC5EFF0053332B28F1E9921CD058C5DDC9A1C98605209A72C684F7DB2618C96890713936B5093F7854786F8CD38DBF476F6CADB96AC542DF462ABFD318AAA691E55F3379E7CD9A1793FC99650DD799AF254BAD31DD8AC8AF1B7C3C69EF976201C4CE5F60F993FE70D3FE739BCCF6ED6FE636BAD4D0A7A0BA64974C55430141414FC72EA01A2CBF643F2F3F273CFDA2FF00CE0F79D3F27751D3560F3D6A7E56BAD3AD2D236678CCF22154058926A49DF7C9C764136FC52D1FFE701FFE72CB48B23A6C3E43D327E0C6E11A590B4CA587B532C0520D3F6A7FE70B3F25FF00307F2DBFE70CB52FCA9F37592691E78BBBFD6E6B3B02DD56EF8984D76EA01C892C0C9F94DF94FF00F389FF00F3995F93FF0099EDF98DE46F2ADA43ACF97B58B9B9BFF5A5741716D34DCA84568C0AD6981417AE7FCE7FAFFCE51FE6E79534AF35F9F3F2AB43D1FF002EBCAD1B32EA1612BCB7E1CA1F51AE118D5072AD074C590953F38FFE71DF41F23F993F327C9F61F9CBA9DDE9DF96FAE3B23DCB201688E1C22891CF40316CE27EE04FFF003953FF0038D3FF0038DF77A57E43FF00CE2AF97F45D77F31FCC37D67656F7518A6957724DF097B9BD427E3626800C58195B18FF9CAAFF9CCDFCF4FC80D7BCAFA67E687FCE3DF94F59BED56CC3691AFD83497715B5C16A2A4323861EA03B85271636FABFF002FFF0038507E40CFF9F1F9F7E46D13C8B05BDA9B9D3F4E4445935042AC10CEACBB48C69B0C5812FC5DFF009C15D5A2D67FE7381F58D3AD6DADAD7CCBAE5CEAD690D688B677723CB1C6941D830DB16264F56FF9CB6980FF009FA17962F26790A01A3C56CD08AFC512BA95FA2BBE25B81671FF003F8D92E6E35DFC86B458964B3FAB48F6A53790B537046408641F93B24769776F1C5A8D8BDC5E5005AA9AD32A21B8153B8D1ACADF59F24FD5E27B49CEB5640015A8FDE83B570034CB9BF793FE7E412ABFFCE01F962299A79644D5F458DA471425D6A77F6DF2C8C6A9818EE5F822DA1697A868B63A7E97A1869E3B413DF5D92F5F5075EF84367007EF97FCFA0C347FF38C9E7F8608E44B9FF10DDC61C0FDA11353EECB049AB806DF17E12F9AB47B1BAFCC0FCCEB8BA8DA7BDFF156A70A3396A02262C6BBF8938253D9B3806EB5E3B64FAAB416104933FC0DC4D7EC8CC7F14B1F0829A683A75C3FD616C230D727F7CA091B8F91C7C52918C27967E5AF2D4C04779A2A4DE22AFF00D71F14A784226DB4BF2FEA7AAD9F93BCA1F97771E62F34DF4C9FA3B4FB38E4964E75A091954D4283D4E4A323252007E937E427FCFA63CE7E6BD624F38FFCE42EA16DE50D126845CC1A268937AB24A08A94B9E6D5414EA2B970B69343DEFAFBF303FE72AFFE716BFE708FCA571F975F92DA2D9EB9E72107A561A1E8CA67B496FC01F15E4C0B1526A6B4C8CA7B338C093BF27E59F9CF5FFCCAFF009C81D6EDBF31FF003BB537D6EE21B8F5743FCBD8E42FA6D9467EC96E276A53BE60E6CF5C9D8E0C3B6E1F657E5BFE6369D731586871B246D63122D22A1B745A50468C07ECE61711939F5C2FA534DBE8E15925460EAE054D72328B7C24CC22D5AC61D12EA696CBEB7CA290B102BC7E13918AE4E4FC43FCFDBED3F5AF3EEAA2CE0F41D256DA94A6ED997093A7CE1E1FEA48CAB1C8FCFD01C57D8667623B3AF229D96A1D8ABB155CBDF15546ED8AAC1D3156F15770077AE2AEE03C7156B9D36A74DB157733E18ABFAE6FF9C6CDFF00E71D7F208F8FE5C7957FEE916B968E4D279BDAB0A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8D34BC51D4D0F8E6BA9DAA5D757887900C2A71A55B6D7229BB0AE34A897909F881D877C041506914D7085128E2A32AA2CB88285DDE7100A372E23B634578825125F3B6DE3DB0526D0734E0296AD08C9008291DD5D541EF920C0A4C65777FB27E7930C485FCC81BFD3930585174720E677DA9824530148B0F5141BE41B2D48B91D8FCF15B6BD4C56D917917CEFE6DFCBCF3E68FE74F25D8DA4FADE8686E21BDBD1FBA4E07970AF89F0CC8C3C9C5CFCDF7349FF3F5EFF9CA09EC6E2F7F40F96EDEE2C9C5CDC4A63A3948C50D169EDE39750B71DFAE1E46FF009C8DF3C7997FE70D7CC7F9F77D6D65079CF43D126F318B287FDE7668D4B05229D0853DB26021F945E58FF9FADFFCE5A79B35516DE55F22681E62D56E938AD859DA9967DABFB0057B78614BF5BFFE7113F3E7F303F3EFFE71A6FF00F34BCD7656107E6269DAB6B5A78B38978242DA7FD8475A7C2DB1A8C04354DF9BBF941FF3F0CFF9CA9FCDFF00CFA87F28345D1BCB916A1ABEA975A7BCB321458A3B4765E4CD4EDC70522934FF009CF1FCF6FF009CA8FCBB54FC9DF3CC3E4CD4B45FCDAB77FABC1A0167BE8560F85BD6561F0D6B51F2C5987E547903C85E7FFCE1F31E95F90DA75CE97A4DCC5234B6925EBFA51B3F2E410B7892705864FD16F257FCFA23F3F26D7B44BFF33F987CB7E4EB2D2CACD0DEF97A57FAFA5C210D14B5634E4AC01AD70A0BF577CE1E75FC81FCA3FCB5D0BCB7F9F7E7DD07F32353F23411CEF26B7325C6AD737D0F499537AB531624BF32FF00E7323CE1F9DBFF00392DF975379D3CA7E4D9FCB9FF0038CFE50893559ED75188C37B3C51FDA96341406234F84E1A60FCCAFC9CF2BF9BFCFDF9CDE47F2C7E5B79864F2479AFCE0F1D9F917558E43088E40A5C7AAC3703883D31E140897EB27E5E7FCFB5BFE727B4DFCF1F24FE6C7E63FE61689E709343BC49F53B89E691E765414DAB4AD6B5C69B86CC2FFE7EF9AD68DFE37FC9DF2EE8BA9A4BE67F2DDBDCBEAF6D237C36EB22928CDE0180DB2259805F3C7FCE28FF00CE04F9B3FE7277C8B379FED3CEF2E942398C3C1E42073EA05011EF913BF26775CDF5A68BFF003E80F35DB6ADA36B1ABFE62B5E3E957F6F77F57E65AA20903D055BA9A5300891D14CC17E927FCE507FCE31CDFF003909F913A5FE4E5B6A8FA49B39ECEFCDFF00EC97B4D954EFDF2C0C0CC9DDF9B23FE7CF5E6CB5D3445A7FE68CD0DDBB5651EA3052BDD766A644829F10BF463FE710FF00E717AF3FE717FF002A75DF235E6BF36A771A95F4DA9497719F84348A568373BEF954C90A245F9F1E67FF009F44F98B5AF37F9975FB0FCC06B6B3D7B50B8D4C42F211F1DCC86460C037515C4094BA289D17C03FF393DFF38B1AC7FCE29F9FBC85A4EA5AE9D56D3CC32395915890415F72727E1D06CF11E5115ADBC0BC0ACCAD3B3189E9B75DE990E109E22AF02A25CA98A4775EE7B60A0C6CBEB5FF009F6E24C3FE73B742F456393FE752D5CC824EC9C7E265F714DB2E8061225F657FCFCFFF003C3F35FC97E6DFCBAFC96F2179A27F2BE93E74D264D47CC3E6289FD3B9611CDE998B9D3BA8E9965048912FC9FF002E796B4CF2F6A1746D8A5FCB75704DF6B7A99ADCBC86A4C8A6BD77CAB200DF025ECD06A30454B7B39648D29FBFB81D251E0C7C335D962E7E29109E69570F65730DF69E56CA20DF15B45B4751D5BE6731E31A72B8ADF587E5979ECDFABDB5F5C28E2005E47AFE18261BE05F56793754B6B9B7BDD2DD11E3BD8D979B741B532B00B39BF217FE726FCA5FE19FCC1D4EE238EAB732332D3A1A96E999100EAF5043E588DA30F351BE22DF1A9EA0E67E2D83AD9157A1F0CB98BB7F0C3452D12075C08B5CA46FBE2AA8C46DBE2AB01DB156EA3C715773A6D4C16134EE67C31B5A6F883BD7AE3687701E3855FD72FF00CE367FEB3AFE417FE6B8F2AFFDD22D72D1C9A4F37B56143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87A96FEF941ACBF8E623B3B0963DF5F16DA5AE34B611515DDF541F571A5D9318B53BD42A1E4AA7ED2E0931927706A3CC0E9BE52D61166E7638B38A5E6EBE33D4E2D8103717049C52833FBC23155616C42F21DF15434B1D3B62A868D7E36F0F0C5894746A3DBE8C582BB461BE43155168462AC93F2FBF2CFCE1F9BDE7FD1FF2EBC9776965A8EAF19905C4E6900A1A7C7976271B31DDFA2BA47FCF9FFF003D7597F43CC9F997E58B4B688049A0B3123CA57AD18AEDF7E640F268B7EC4F907F217CA1F937FF0038F179F955E75D6E26F23C1A335AF9A359B87280447FBCAB9AD12872616DF1CEABFF003963FF00381FFF0038BD6BA743F96BE5BD23CF9A8D847C5755F29411C972838D2B3CEC2B5DC8241C905B5BFF003EB4FCC58FCF1F979F9AFA45BDB470DBEA3E63D675CB68140E5026A2EC544B4EFF00150E4BA2F0DB17FF009F7DFF00CE324FF963E63FCDAFCFEFCCDB44B09FF4B6ACDE5AB8B8F84DBC31CECCF23927F6C74DB010CB81F96DF9DDF9D7FF002BE3FE7253CE9F98D6F74D045A7CCD65A2E9970D50A9033C3CA01414E4054E56436C616CDFFE712FF28FF257F327CF9E6FF31FE72FE7149F963AB796353B69BCBCB6F75F56B8942307356F0AE459786FD51F38F93BFE71CFCE8D7B3AFF00CE71F98B48B4344BB5D3B5DE01005028483E032A32A3CDA4E2277A79DF977FE7DABFF388BF9C724FA9681F9DFE67FCC6BB8EA6F35A1A8ADDB0A750CEC07864F8C745E0A7D95F97BE4CFC8BFC81F25FFD0B3F99FF0036D7CCFA7F9B4496BA47977CC577EBDF4905C8A0B58A951C00FB2B931913C07B9F1A79AFFE7DDDFF003895F947E615F32F9A7F3CF59FCB2D465BD7B8F29DF0D405ACB64ECC4AADAB863C4A5683DB26269AA1C932B9FC9FFF009C6DD4E4B4D31BFE73E3CEE249C520787CC4435C9EA55985795326770C385F15FF00CE607FCE3DFF00CE35793FC93A9FE677927FE722AEFF0035BF320CB15BDBE9DABEA02FAEAE854A30AD6A780ED95C837C075A7C55E4DF31FE71792B429EDFCA5F991ADF923465E12CD616174D00776151B2E634B6673887D0DFF38F9E6FFF009C92F3EFE7CFE58F92FF00E576F99F50875F9E3D66F2CA5BF77A5BD9C80C9148A76A3807614C8F38DD72712517E82FFCFD9BF3BBCF5E43D53F2BFC95E46F376ABE50D47CC9A7CBA8CF75A64ED0168E297830629BF6F1CB9B7146F67E4949F9B1FF0039096D688A9F9E7E6F8AD66FDFCB72DA8CA013ECD5AFE382DCA9C283F6FBFE7D73E78F3479EFFE71CBCEFAC79EBCD5AC79AEFB4CF30DDC2BA85EDC34F27A0B192A159EA695A9EB8251704737E2FF009DFF003E7FE720AFBF30FF003022B5FCE7F34697A7DAEBF7D69A7410DF3A2450C729F4D68294016836C31A05CD8E332890C035DD5BCF3E67D574EF30FE64F9EEFF00CECFA07C7647509CCECBCF614AE4E73586911714D00BE54BA9663752A97D3E2AFEEC022A6A3E5989293951D3D2B5AB7A48ED5FDAFE3862584B1BEBEFF9F69C9EA7FCE75684C3FEA4ED647FC933991170F2C69EDFFF003F6FDFF3EFF26475FF0070139A7FD1C60916A897C11A8C06541DF8C9CA998F22E5C0A7769767EA8B08FD9ED9448B971679A34DCA08E393ECD77C85B75DB34B4D4A5D2EE2196CBA0209A64245CAC6FA93F2F7F32121B8B35B9702BC565AFBD3DB220B64F93C6BFE7316D6CB516B1D6AC183B3AD5A9F4E64C0BAAD445F9DD35A43EA99631F13EF2FCF2FE275A614A6E782D075CBE05690E243D3DF2EE882BC0E79596B937C78ED819479378B2762AEC55ACC79736D1C9BC4312578CB43592EEB920C097F5CDFF38D9FFACE9F905FF9AE3CABFF00748B5CB87260F6AC2AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF864BB048AACD51DB311CEB4BC2B147612EE01C56D17621DC0AC98ADA65E8307525EA2BB8C124129D5B45D38F4CA501306040229D716C8A58E28E49D862D88571C9F6DC629548E36A8DB154D235AAD08E9DB1541DC42687E1FA7154A1D5D0F43BE282A91C8E0F4C58F0A3519A9BEC3B62BC2B8891BA2938AF0B21F2279EFCFF00F94DE7DD13F323F2F2682DBCC7A3AFA3682ED3D5818B1AFC51F7CBB1CA9C4D40DDEF1F99FF00F39CFF00F3963F99305EDCF983CE163A19D22DDC48BE5D88D8BAB28AD1F89353F4E5DC40971E9FAFDF975AC7983CE1FF003EDFFCC2D67CC3ADCBADEAFAC793AF6692F6F5CCACAEC87A96F0C9476B5A7F387A7BE85A5F97E686F0C4B71A859A08A7863264776DF812A09AEFDF240AD3F707FE7D29F951F9A9E58D67F327CEFAF794AFFCB3F979E6FD06D2D74586F289F5A962209786B4A13D6A72D06C289D3D0FFE7EADF9D7E75FCBCFCB8F2D7E4FF95F4E9747D37F3126922D63CDB6EA5623146D510C6CA2AAC4FDADF7C494F1EEF91AF7FE70E3C83AA7FCE05F92BF3AEF2F5BC95F997E5B8A7B89B5A998AC37BEA48591645EA49A0A13EF9592D8323E2BFF009C7CFC90FCC1FF009C9CF3F6A1E5DF285F695A3F99A0478754D4EFA15781907C3CD50EF5A6F91B6632ECFD44F20FFCFAB7F26BF2AB40D53CD9FF003943F98B1EAF1E9122DD31D16E0D85B451A7C6C6757AB301DE83A60113F0419DBEF0F30F9D3F2CFF00297FE7157CDDF985FF0038E51E8F77A2E99A34D3E87AB584002CA507C25DB882FDF7A647C2A533B3BBF9ABD5FCC1E62BDBFD3BF38B52F3E1D5FF00332009E6CB79656692289588A59C486BC597C06110A62723F717F317CA1E4DFF009F8A7FCE1B683E61F29DEAA79DFC9B6E93C371250BAEACB12ADCC53746E24D763921162676F3AFF9C76FF9C4AFCACFF9C2AF256A3F9DDFF392BAF68DAC6BB25AC8348D2EEE1F56DE1050845489C37C66B4AE4B8D1C4FC98F3C683E4FF3F7E6A7987CE9A0F95AFF00CB7F97BAD5E493E91A34D227AD21690B17B72BF654D4103C32B3367E3523BCC3368DE5ED38437CCF631C29EAC4D72DCC48631544A0AD49A532A3BA7C6B7EAA7FCFAF3F21AF74CB6F31FF00CE577E62D9AE9F1EAD6D2BF93BD61C560D302B7AF32F2A5140527135F00C38ADF0C7FCE507E6BC1F9E5FF3923E60F3559336B1E4BF277ADA2792A590F34B9B5726B3475EC1AB91F136761A7C24EEF13D4A2B98216F556DEFED9374B08928CA3C0D76C7C47272E2D9FB2FFF003E9130C7FF0038CDF98534B0936D279BAFFD6B75D8AA08A9C7E8CB89DBE4EAB83D4FC42B8373FF002B0FF346E6C618E5B6B7F36EA8E7D75E4157D634041F0C864950761A68F34C66823B9FAC35E7A572978ABF0C0BC42537E99852CCEC052AAA97948E11B154E30923E3000EC721E2309CC24B3CE90432F3902146A3D4F427A65F09383972D3EC4FF9F65C7327FCE717971E44204FE4DD65E13D792F03BED9990E41D74F2713DD7FE7ED2449F9FF00F92E10F22FE5F9CA7B833E5732B10F862E5828B84A5655AD5331E45CBC6126D3AF59262937EEF7D81CC79172E2F55D2984B0523352AB5DB204B918E36C8F4C9E559024919604D2A72B949CA80A679663EAD494CBE9348414FA32024DB241F9EDEF35FB18ED9C35C431A101FA819938E4E0E585BE39D634AB9D26FEEA39A268D2662D096EE3DB2EE370E5898E354B6FF7E6463938D38D34D18D88FA73281D9C5915363C7A76C8940709053734381B03B9A78E2AB81077071575478E2ADD3C329237656EA1F0C900C495DD865803592DE4A9812FEB9BFE71B3FF0059D7F20BFF0035C7957FEE916B96057B562AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF86BB8802C67311CBE240DB460B32F63B1C57899159D94483A7CB15E25595139003AE465C97891F6DF00CA9215659878E2D914A669013D6A7B62D81411BE21E18A519137BE2A8C57A6F8AB52BD57DF154A6615A629014E35DFF008629A469140B8AD2262C5682DBA92EE182EA4897D5B636D227A6366F588F8581F6C944B46585BF40FF00E70A3FE70BFF0024FF00E723FF0029B5BF3279AFCCB2E85E6CD3F54FD1B7D1CF7CB1F2A8279716604E5FC449B718C2BA3F4B7F3B2EFF00283FE71B3FE7103CF7F9456BE72B18EF350F2ECFA4796A059D267BDB87144850231219B975392053E1DEEF8D7FE707F47FF9C0DF27FE58699F9D5E7A920D17CE3645F4EF33E9FE629BEBB0472C5F6A58ED983503B74A0C9DA38084AFFE7217FE7E75E7BF365C5E7907FE719F438FCB7A1D9BB245E63302FA77D68A6A9F554D84551B9A76C78E9A678492FBA3F267F36BF20BFE73B3F246D3F2E3CE2F6ADE69D3EDE14F3568B7AC8B7B693DB95E53432C86A3D4707ECFBE0333C988C469F327FCFCB3F353CABE53FCBAF26FFCE267E5CDFDA3C1E60317E9B4B77594D8C5624344ACC8763215A1191E3A663097E57797752F3AFE5FF9C6C7CCDF943A9C9A0F9CF47B37B69ADC3304BA5917E290814069EF94F8AD834F27D89FF38B3F927AAFFCE6FDA7E64798BF3E7F37350B297C93A92E973E8C3516B68AE39C65D8B46CE015A8A5732465003038E4FD4FB9B5FF009C5EFCACFC8DB6FC88F3D7E61E976FF96F73A61B09B4D8665F5F8B1DCB4D11635DFAD301CF148C322F85A05FF9F51FE534B65AAF9524BCF3E5F69779EB5A587D6E6BA592E54502399556AA41E94A644E701B069645F0D7E4CFE707E71FE4DFE6779E7F353F27ACA7B7F2BDEEB5777FAA7901F91B67D325959D04716C81E8C454657F9A8B68D148F47EAA587FCE5D7FCE207FCE64F97A0F277E7DD8CFE44D68148A2F29EA333219A56D898E455E2373B03F7E40E51F51E5E4C65A390DBABF3FBFE735BFE7193F2E7FE71D6EBCA4BF931E6B9F599BF306493F44F97BEB7F5C7B6892AE2854B05A8A0C81CA48B3C9A8E9A47A24BFF3851F919E41FCF8FCE08BCB7F9D5E708F47BEF273A5EE8BF97374C527BFF4784AEC676A2B2AF75EE36C1C6472EBD57F2E62FB7BFE738BFE730D64B5BBFF009C5CFF009C7DB8B4B9D4AE02D96BFAD6931886D349B68C7096D02A1E279A93BAED8F89E9B972FBDC8C7A49134FCD7F2F791E1F2BD8A68176E65963AD2F474AB6E687E67304EA2CBD060D36C9D5FF00962CDEC2E4C7290D6F197694577A7CB271CD6DB9F4FB3F537FE7D471DBC1FF0038CDF9836D79756F682FFCD9A8A47EB4F1C6DC425391566046FE39B033B1B793CF4F170CC03DE7EF7E383E88DABF9ABF332F6D2329158F9BF538A57471C64549295DBED5731F3CEA2ECB1E2B0B64B2FAB6DC295ED9A83959F8450935A7AA80863180EB571D695CB2191AE78497A47FCE3F7E527E5A7E66FF00CE4DE8BF97BF9B2B736BE4AF3858DC5D45789762D544B6F1928399200E4453E9CDB69C931BBE4EB73E120D53F757F207FE70C7FE718BFE71AFCE927E65F912FE4935C165716D61ACDEEB114F0C16970A04CA23671527C4666125C2188F73F2B3FE7E3BF9A5E4EFCDFF00F9C87FCBEB2FCB3F30C1E6A87C89E5FB8B0F31FD554D22B812972BEA74AD08CA67CADBF1E3DDF31DAC4D05A3A188C69337A8439E4E1BFD6CC69173A18924F4C0BA048EF98E4B950C4F51D01855631D5C01954E4E4C31D3D46DF46944493053B8AE63CA4DA229835ADEBC6A5222C22EBB64449245AB5B5C4A54C33C541EF9938E4C4C2DE59F9A3E5C4BCB14D4ADE3DED50AB53DF2D949A32627CC778E915B014A4B5A1CC8C527559E348462CA23AF565AE6C22EB25CDCA390DFB64CB3839A315C836114B7D35C50EA53618ABB155C1C014F0C8916825AF572403025BF532603025DEAE5822D64BFAEAFF9C6B35FF9C74FC823E3F971E55FFBA45AE0661ED78A5D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF881BC880420F5CC3E20E424B0A857A1EA4ED8F12B24B50B4218D31E20AA8F08670CBB9ED809B0A39AA03C41076395F0B604BE5662C6870F0B30504E1C9AD31E165C6D29E277FA7070B21205171354FC382928CF8A83E78D2B8D698D2A12406B8A625A8D0D7A6D8B2B45B23300145698AD85F1EDB1EB8ADAA4A225884FC4CD3AB045B6AD0153D5BE8C429A2868F47BB86133689E66D47465BDBA56BFD32CEE6585789FB529E0402465832531E005338FCBB6FA84CE751D4B53D461B17E766D79772CEAF20E8C15C9030F8BDE98E11D11F0795F499EFEDAF6F2C266B595F85D69026222007FBB997ECB57C30F8C19F83BDB33B782934292BC7E8C4ECB672C2823F4231B2D78815DB6CA67985B64710EA91EA7E5A437115F68D25EF97EEA32FFA4F52D3EE5EDCDE06FB3511914E390F1E9B3C081768DE5FD3ED8FD72E26BBD7F5E0DB6AB793BCAF427B1724ED909E7B671C1001E86B6EF2DC590922A49044CAFABA1E2483FB240DF7CA8E50DBE0C52883F2E6D4EB125EC771AA59E917959750B0B1BE96DBEB128E858C64549F7CAFF3738F271A7A404BD4B4AFCA0F20CF6D75A85CD86A90996129159DE6A12DD0527BD5C9CA726AF24F9B762D180ED0FC95E5FD05E19F4BD0603769271769155C18BC68475F7CC796693B0C7A50F52D3ED674B48A28163B4912E1A66754142ADFB0C0751EC72BF1A4E6474B163FABFE5BF943CCB3DC5D6B1A12EA3716A39D98B522DA49246EB491402299911D4D7544B4B1287F227E4F59E81AD5C7992EAE2F3EB112D346B2D46E1EF7EAA0FDA0A64AD36F0C9CB59C5CCB8FF901D143CF1F94BA579AAE96F74992E3CADE648DAA3CDF6933C721435E6948E8DF1034EB9286B047CC2FF2782ED17F2EB4DF2AD9BD969566F737F74419BCC533F3993F9B9330E4C5B213D582092E54745188D833187CB62EAD134DB88792A75D40F53FC73046716D98F152B4FE598AD6DD2D6CC85957EC5CB0A807C48EF96C753109CB8F886CF269BFE71FC4B7D793E99E62D5B4A17B5B899AC6F26B783EB2E7E26F4A3206F99B1ED1A157B3A89682E5C54CA34AFCA7D23CB5A63D9C76B2DDDC475996F4C86AD3B7DA771FB44FBE5597571946ADCAC7A7203CF75FD0E64998087A1F8B35E32370D384AE0D338C0E49F4DD47C2C45687B6646292CB00609E67F2EBEAF0D8DC5DC93DB6B36CFC6DEFEDA5689E28C9F8802BBEE336DA7CDC2E0E7D2C65CD8A6A3A0EA36B2B45A7F9B35FBC8C7C715BFE91B85141D57ED77CCD3A814EBB369611E5F794CB42B39B42944DA3DD8824D64F3D75661EACAA4ECCBEA1DCE512CE1A2189EBB1D84090ACF0C6C2D8AF0F58B16E4DF2CA279A2E6431A0534EF527AA2D77CA2598391114CF346D3E7867B762945E42B944B286FC71E3E4FA7F44D352F2C21089CCF115DBDB293305B0E0932587CBA3D27458E8CC3714FECC00B0F0A439B17D4FCA324619C2D3AF41FD99930986420C0753D0A76B1BCB59D39C12EE58F63965F1726196161F1E79A3CB8D63A8CFCA32B6FC8956CCBC669D26AB1960ECBCB91614543C53E599F09874D381054A46F4E95D81E872EE265034A4F2F1343D698096C26DAF52B8A1557703155C411D462A8377F888AE203592B79FBE48062EE7EF93B6041772F7C9713120BFAF7FF9C68FFD671FF9C7FF00FCD6FE54FF00BA45AE066393DB714BB15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8779E6690D0E6BDC86E0B62C55A9D0D6B8AA7B1454C555F8814C473508693A9CB59A5E480C49E98AB4CE9E18AA1A465236C05945742699536F1047092A078E2B61716DBF8E15B08391B7AD701482A9130DB026D16ADB1FD78ADADE4395715B5CC6A062A9859FD93912D914FACBEC37FAD95C9BA09CC1906F8A6B0A0645AF8E565124EE5B5E56640EE320531482C21F4EE0AFF29DF2B9330CEACE0F56829B9C8368E4CDAC6C8B24629D3205B22F49B3B43FA35969534C81722095DBD8BF3A50F5CA8B97065B6766FC7EC91909392190E9DA51E60F1A6F539510D822C94E9842EE2B4182922294BE9CBBFC3DF1A6D10413E9C95E9808D9918A3AD6C100A53AE505ABC3569B4C47A10BB8C57C3455AE9E00E9D714786EB9D2B9A3F14DE9B62830A0F10F35689708F3388C77C945800C0A1B0924B69D5D00DF7CCCC658CA2C43CC9A64B085600D3332127032879C5F44D1D651B3014CBB8DD6E68EC9569E93493D373BE4096BC707D0DE5ED224BCD3238D81217E2194CE4EC2186C27B0F95E4120223E9ED98F22CCE9CB2BB2D12485E12E869514DB2B3272F498082FA3BC976F1FA31C6CBD80C00B9B2C4F5CB6D22065A85FB5D72C12689E35F75E5C826423D304E4C16838DE5DE70F28FA16FCA18FE12A4B003FB332B0C9A270A0F913CE5E598A54B82F0FC42BDB33232B755A885BE51D7EC24D3EE1A3E344EA332A05D2E68531CB9903428D5E99931710841897950E5A98F25656C595ABAC805315B5479401F3C56D2F91FE33BE4C354B9ACE7EF8B1773F7C55DCFDF157F5FF00FF0038CFFF00ACE1FF0038FDFF009ADBCA9FF747B5C9ABDBB15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88316FCCD45335EE42630C7C17891F11D862AAE55A3FB5F862AA7CC9751DB08E6A164BD4E58CD00D192493F67C71552654F1E98AA832AF6EB91290B797134C832564620D6BDB1557E551B1EBDB1542C8AC687016512BE3246C4E0656881228DBC715B5E11CEE294C56C2AD0D003D7B629B4CACC1A53B9C896D8B20B34655607B9A8CAE4DD04EA089F20DF14C63AA7153E3BE56512656AC0D9EFE1902CA2C7A01FE94CD4D89DB2B9320F44D1A22C54D36A641B43D174E882B0E4366E9902D917A259DB936C4506FD32B2E44175B598E7F677AEF95972E0CB2D2D502EE3225C90C86CA10A46DB6574E481B270E8A474ED8D360012CFAA73AF15EA71A6C0109258B03BAD3011B3202D523B609F6B314B2E04D22B3590034AD714702362B38D4D08A62BC08D92CE26864A0DC8D8E2C670D9E75E64D0627B39A4352789ED928B8A214F04F4608659A2058B96A71236EB97424C65040F9A34E89EC95C28AF1CC98CDC1CB17806B5108838E3DE800CB3C475D9216A7E5FD3A7B8B80238C31276180CD9E1C4FACFC9BA25D0B4F4DA1019539357C331E591DBE1C2F4FD1740FAEC9C12352E3AD76CC796473469D93DC796E24291B4604886A6991E2B6EC7800667E5DD3440E9F0D0786112672C6F5FB14B68E3024AD587C3B65824D13C69CA476CD41BFB6D9609B41C4A77FA1C17F6B22320208EF97E39B899A0F913F337CA4B6E2E0DBC436AD4D3E59970C8EB33E2B0F827CFDA605F55B851D76FD599B8E56E935189E113865050F8E66C0BAAC91A520A4003B66406B05554D3AFD38A6D706A1AF6C56C36D20A7738ADA14B124EF930D6D54E28754E2AEA9C55FD837FCE337FEB37FFCE3EFFE6B5F2A7FDD1ED726AF6EC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88EB5527A8EF9AF72138584000F862AB580622B8AAAAC0BC4B6D5188E6A1033851F3CB59A058A952062A876E3FD715506A74EF912BC90EDF6B2B5E254AD00A615E25367618AF129FAA5B6F0C0520ABC75207BE0648911B1236E98A11A88C314DB60126A7E8C59C135B35DC644B745925BAED95C9BE09EC0BF08C837C559C5181CACA24CA6DC7A9694F6C814C52DB7B73EBF4EF95C9987A5E876C788DBB641B4727A3E9B685DA314E832B2CE2F46B2B6263094C8172609D5AE983903E395972E0C8E1B001694C8C9C909A5A5A8AF4E9869B849363682831A6626BA2B44A7D9C69B04D42E2D12A76C8C86CCC4B74B4DA1AF4FA3304B7DA6F69684F1D8605B4CC590AD298ADA30598F4DB6ED8944B7093EA9610CB613A9515E27F5620B488BE60D5F4C486FA62ABD1F7FBF260B19063FE62F4CDA08EA2BC72624E0E58BC2354B0E572DC96A9434F9E4FC470B82CB37FCB4D05AEB534E70FC3CBA91F3C066E5E2C54FB7B4ED02D6DED144680394A1CA2537678A349BE91A6AD9CA5F852BDF2894DC8B013A36A269D98AEDDB0464D9020B26D2ECD232A4AF4CB049259A5BAC2FC435053A659C4D134E3D3B7420F2C989341451B988008879061BE4E33A71F246D83F9B7CB36BA8E997521505CA93FAB32F1C9C2CB8DF97BF9BDA0BD95D5CC623A0DC8FC336584BA6D563A7C937D66DEA91D2873658CBCEEA0520658FD26E077D81CC98F27094F0AB44818ADA8B362B6B7AE4C2BB15762AEC55FD837FCE337FEB377FCE3EFFE6B5F2A7FDD1ED726AF6FC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A0B7896BB6D9AEB72116C388EA3DF1B553E05BEC918DAAA51C2F1E43082A94DDF21DF25C4CAD2AA495D8E3C4B68696564D88C78D6D62B926A41380C946EAA2367351B0F7C8DB2F0D50055346618DAF86B1E30C2AA7AE36BE1A82A146F886C7A6048852696F172DE98A784A64B1AAF5EA7A62BC255982D0D06F8AF0950E209D87CF10120F0A696686A36C0436C66192DBA1DBA6552722124FEDE2240E9ED951939312AB340C29B8391E69E1B647A78ADBF1EF4C8908BA46DB5848CE1C5284E57209137A2E836CCC428A5477CACB744BD434BB378594BD083E1954A5BB7443D074EB477A11403DF21C4E5420591431716F8874DB225CA8C29378D4505075C8916DDC48BB65A374DB0ADA6C232C36A615E3A44288D054A934C5B233B509551C6C0D7232E4DC0A10C04B0D866010DE3284DED6DD956B4191B65E222429077180C93C48F8684712363913365CD21D4D084954746072226BC34F9E7CCF02C124EED4249DA9F3C98935C9E37AF34B2B829F647519306DC3C91B49ECB467D52EE2855284EE49C375CDA31E2B2FA6BC83E4C86CA38E568D79F723227239F0C74F6EB4B13EA0DA8A17A1CA897240A4E96C569F0819598B2E1255C5B46801A6E3AE08C59C2242716691BF414A78E4D914D2283E3156D97240B4C85A36508CB452464F8DA4C54EDA89255892064E32B6990A446A33A3DABC22B475A0CC9C73A699C6C3E1FFCF3F2C7A51C978C8ACA63AFC3D7B66D304DD46AB1ECFCEAF30DB98DE4923015549DBBE6DB16EF2FAB86EC2259FD56E46B502999575B3AEE02A7CC7BE4830229631A9F6C242A91563DF224D32112570141BF6C226B54B4B81E3878969776AD7256B4B4B01D8E2B4FEC23FE71977FF9C6EFF9C7C3E3F96BE53FFBA3DAE4D0F6FC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A889788DF6CD7539086B99B8D6871A5538666618D2A20C8C0548E98D2A0E6FDE0A8FBB1A54BC2D1E871A540DC805F7F1C6954F9704AD37E98D3387344464BAEC298D37F120A6B794B7C24E34BC48A855900E5DBC71A5E257DA62140DD37271A5E24C625E031A5E256049231A5E2452AF2071A5E25F1435AEDF4E4834CF74CAD63A1F6C816706456895207BE51272E0CAADE1A2034E994C9CA8F25EE9C8D298C4ECD80A75A5C7521299125AA4CB9221146AB4F880DF2A2562CC7CAEB59D790DAB9025CB845EC16F10E4B45DBC731E5CDC880671A58A28DB22E6E309C2A0E75A77C5CB099451A918B021116F1FC74F1C5253A48A806D8B54954A2D3F8E2D9050E0B5A78E097272A28848158F4E9984425191A0414CAC8641A6A02476CAC86C0BD245515F0C810CC1A63DADCE1629187864405E37CFDE636699A6205687A64C313BB03B7D224BFB9E012A2B97458F876F5CF2D792A38E786478A8DC7C32333B2638A8BDE749D320B481005008194B7009FC50C75D862D8023046A0785316C010F20500E29A57B324134C2A426292B066C0D642A3CAD4A62D6421C5C145624EF5DB2C816B942D0525F173C589A65F02C0E379AFE66E996FAAE8570B40CE10D3F0CD9603BBACD5637E4D7E6158C9A7DFDCC0148018FF000CDE603B3CA6B31EEF25039027DF326F7757214D85F965D171A4E2BF2C99601BE3D3A65127231A9323576E9910C64A0C8D920C56A96AD0E58155D0035AE495FD83FF00CE337FEB37FF00CE3EFF00E6B6F2A7FDD1ED72618BDBB15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A8F54702DC7305BD2695FD57E9424E2A898542F520E2A887914A15F11D71542A9AD452A7C7154BA7942494A6F8AA5D31323020D2B8AA22180135770569B8C5944EE8E411D28B8B6A1979198A114DBAE2AAF28F4D775E55F0C556DA71E4E7895A8C551EEEA829D7C062ABA08DA46240A0C55341198D6A472F962ADC13A92CBE99153D7161229DC101A06AFD19596704DECFED57C0F4CA24E5C198DB30740A053DF2993971E4ABE8947A7DAF7195B34F74A819650FD457A64496B3CD99C712CF2569C41A6C72B25B718671A0D9849148A139025CD84767AD58C01D5052847539496E8C7765768521A2952D4F0C0E66308812564340684EC3172404CE1734AF86282138B70052A7AEF4C5849368D948F0F6C5AA4B1C507DADB16D8286E7BF4380B9314744D4ED98A42551989208046F9590C8284C5BEEC810D810AEEDC0F6C8109972633AD4B5B765A9269D7234E3C4BCC24D39EE5DAA6B53D31AA72602D3FF2DE80AB74ACEA0EF5A530F139508BD86DECA389A3E294A0C04B394682747E08C7C3906B015ADA60E7885208DEB8B301184D462CC0404A18EDCA9E18B346D8802B5607160423FD440C7DB162434F32018B59096CD729E1B6374988492EAED549A0CB2326528B1CD465FADA3C4DF65D78D0E6CB049D5EAA2FCECFCE9D1E2B4D6AE233462E49047BD3377824F2BAB86EF96678C452C89D402733E06DD0E6145439004ED991170A4B8508AD29932C03741E19449C8C6DF25029C77C8863258789FD9C218A1D901AD053BE5A154591BB1A6495FD84FF00CE32FF00EB377FCE3E57AFFCAB5F29FF00DD1ED72618BDBF15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF89F0E3D33BE6370B90957306400773B63C2A893C9057A531A5414B39AF107738D2A6360038353D31E154BB508584E08FB23BE34A81F41BAF8634ADD1B74AFBE3C2A0A32D41F9E0E14F1353B32CAA4277A63C2BC49B7C0D082CBBE3C2BC484A537514C785789A1148F22D477C78578995C16E91C4848DC8EB8F0AF122B8464531E15E2524B74120A0EB919041DD3B55548C6525BA2BAD1AAF41E3BE5127320CD6CD78C60D329939514DA35E681B8D77CA645927FA70008DBE79592C3AB2FB280C8E1E9B1E99025CAC4377A3E8500E6A4FD39592EC71C5EA7A75B5694E990655453A11716DB172F105648A86A7BE2E5008C8F614C58108849CD7AF4C5A64994539D8E2D5269AE0B122BF2C5B20A911248AF42712E5453D8A9435CA2412BCD011E195C83243CCCBE34AE564360404C418A403C36C8D32E618B5E219BE06DFC31A6B1043DBE9C88EAC57E795C9BE019569D6D142438503DF2A2E4C4D0653115722831059C8D84C245063E98B00142301771D7BE2CC05766DB16C010ACA64AD0D08C595226D548A8AE2C486D890C77C5AC8519588077C2C084B26734EB954CA46C92DC826BBED8C249914B48F8C0FA7365824EAB54762F867F3DA0FF738E69DBFA66EF049E5B56777C797AA05CCBB53739B5C6E833F34BD97AE65479B8325C3651932C02ECA24E441AA0C88632688184315608BC47CB2D0AA4C8BE1D724AFEBEFFE719F6FF9C70FF9C7E1E1F96DE54FFBA3DAE4C317B6E2AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88C69196127AED9570B9096DAC8649D09D80618F0AB26963050B571E15484A8697C287070AA610308CD41AF88C3C2ADCF2ACBFB1F11C78556B47C63E5C7B74C78552891B91200E27C7052A6FA64609DCD70213292D95E4A70A537AE0295CF6C586DB64789544DBB12AA13EC9DCF8E08CAD53386D49A129C6992B545CC68AA03538F6F1C6D54EDCB4A695C6D5368AD893CB9F4ED913BA2DB9A42B48C0DBC72A945BA324C34BB33248007EA6A4D328945CB8167013EAEA13EDD7BE5243951927DA622C90056D8D4E52609326436500120402BEF95CA34DB0C76F41D3AD38471ED94C8539B8F15335D2217F500029EF95172E269EA9A7A88E38EA2A69BE066237BA6E6207E2AEDE18B91134E238D3BF862DE26AF1C7CE9BF1C549B5AABF11F638B4C8A3D361F2C585371C7CBE2AD37C52364CED5796DE180B7C7226491D3F6EBF4640B3E25B27C3DEB4CAC864248095B96F5A65526D0508CFB78E479320503E887979D694ED9599B6844B5B86150DC699519338A6F6E802019592D802776D1D5280EFE3823CD289766E3403A65BC2B6A28581A15A0F1C7859892282961B1DCE3C2DA0A998985487EBD4E3C2C81B5D1A322B1E75A63C2B24BE49DCB9DBA63C2D6A4CEEFDE871E16B2859A1928183D699465145318DA477AF242A0D0B1390894CA0878F9B3A9A54115AE6C7049D4EAE3B3E30FCFBB7923D45AE78F2AEDC7EECDCE1C941E53571DDF1B6A16ACB3C8EC69CB7E3F3CDBE09ECE8B34774918D0D3C333625C1986E95EF97736B6CAD3BE5320DD02B9412064445245AF1193DF080BC2B0AB02464C15E1586363DF1B5E17F5F3FF38D029FF38E3FF38FE3C3F2DBCA9FF747B5CB03597B6E143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D98A8B7639072125B39544C3E78AB27797F75F462A948156A62A88A30C554E163F584E5F67154E27E0D0D075A62AC7648CA82701546E95381285F7C8143339230D1864153DF2252A0A08201195211D0C695078D7C718F34A39A48047C76072C548AEC8E69C0D41EB8AA63A7C144E647CF154CE175AB8F7C082B1A1F524141D4E466CE2CA34AB6F488246F98F37331B2066569157282E4C59269F6CC5D4A8F848D865726639B34D32D97EB09C865322E6620F41855508551B28DB289976100C974992928A8DF2825917A04120E2A7C70B743927B6EDEA003B62D88958F93118B64516917100E2CC287A7F113E2716B3156040F9628E144C4B45DF7C578530B55EB812228A1CA83205B5425E546C8499452E7E54CA4B70429EA3C32259072FDA39410CC146A005699021B01B4CD015400E4086C0532B7978AD46301452792351CB76CBD00A2163E54DB61BE2CC145A41B74A571660AC922A0DB6C5B6254516BC875C5050BF54E4EE695C581287961E1DBA62D64A02694468478E63E50CE058FEA24BAA9032B8865296CA5C9A28E33C7AED99D846EEAB57C9F257FCE4246D0C493B2ECDDE9F2CDCE11B3CAEAB9BE25D56759642C050140299B6C01D0E61BB139012C69F4667E37026BD010287AE5E1A951BF865726C8AE465005722DA15D5D7EEC2AA9453BD3AE2AEE2BE18ABFAEAFF009C6BFF00D674FC82FF00CD71E55FFBA45AE5A39349E6F6BC28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87EBA9D962318514F1CA2DBD2086568E74237E4DBE36ACCE37F5223DB1B543A8E2F5EB4C6D51AC57D3E58DAA5F50581AD0D76C6D5305E4C8057E9C6D5053A108C08DBC71B5405BAFA73F20DBD712ACF6C6E8AA54A06DA943912944170E6BC403E195A15D2E022BD5474DB0412C76F2F19A4214D07B658AA96FCD8835E7E3ED8AB258A65861DE9B8E98AA5E977C653C68C09A9C5053DB39C33A92A0E426CE2CC6DD8351BA517A663CDCCC689854B5CA6F9417262F56D06C8488A37F63944CB7445A791C0F0DE2A28A8AF5CA497371067F6567249C7634A7DACC79173E316496561E8C80F224E524B221964638A281BED930D914DECE765A7C35C2CD3B81F93569D4E2D91473B6DD3166146353254D29BE285850F2229B62AAE8EE9B7018AA6768F4EA3AE2551ECCA83C72B2C908F286AED909328A11C8A74CA4B7041484006942476C052A51824824532B21368F8EB5DF61E390219829824818053B656436028F80A82141AD71884996C9BC4AAA011BE588053355AA29A52A77C5B01560CAA37C5982879248DC30AF4C59C4A0165547206F5C524A3519284FF375C5AC940DDAA052791C5812C62F1BE02C054A9E994E4512A414BC1EDD5C8A1F0C8C53C4E6712A20540420AE66E1165D76A4ECF9B3FE724B4F79FCBB1DD2C615947D91ED4CDCE10F35AA7E736A49E9BD1CD0F1155CDA61E4E833F349C0A0E43E23E199D8DD7CDD52DF115A13DB2F0D4D9A93D32B93645408F888AD37C8B6856403BB6154482B403962AA8154FED9C55FD75FFCE35FFEB3A7E417FE6B8F2AFF00DD22D72D1C9A4F37B5E143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF876BBE87315C8485CF160DE06B8AB2DD364F561FA31555941018E2A88452D01F962A955584943E3B0C5538B771C77FBB156AE1D1D4A8EA70C552A02928F9E48A197589AAD3DB22528D63C72A4202EA7288287AE304B1A7959E5A7BE58A9D5BCAD12123BD3156E5D4491C4B6F8AA8C37039160D5A9C50591E9B745A5515EF909B38BD1ED5FECFB8CC79B998D3AB14E57287DF282E4C5ED7E598D43A46DE198D939B918D92DD411A5DA35075DB289173F10675A5BC7E94629BD331E45CF804DE8CCD551B786524B221388549550763DF2D8F2484DA24E00649926D6DDB16C8A3DFA62CC23ADE35E35F6C59D34235E67DF15A44FD5C374C569AF4590EDB602B4BDB91C8162A251B7ED909328A83A353AE525B8210A357A6053C9B58DC6FC71402AA0B1143B7BE408660AF5661DF2B219828BB695BD51BF6C88E6C89D936FAE84E35392620B23B5BB8E48802462D81AB89929B362D80A5227ABB0E58B3057AA826BE38A928D8CA804571604A1AEDD781DF16B258E3CF17C5191CB91A8CAE41ACC964482E3946A9B0ED8C42789A82CE732B2AA1E20666E1145C4D472795FE7CE96F2792E591A3FB009CDC610F39A97E4E6BCE5EF64A6C17E1A7CB3658DD06A39A5F08063DF3371BAF9B7407A65E393535C4572B9364541E262C48E9916D0B789185555436D8AABAAB53157F5DFF00F38D5FFACE7F903FF9AE3CABFF00748B5CB472693CDED7850EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87BBB5531935DF31E9C863A543921B61ED8D2A6FA4DD324A200070AD2A7AE1A54E75173071F4C0656FB44E0A54C34F904B0716006DB61A54B2E222B72A00AA93D7052A342468952C41231A543955506452491B50F4C2020A1A83D415385871325D3E4F8B8F6E38299DA6373444E4BD7DF0708674C7EE1E4956941B1C1C20208A4BE38BF780B57E8C076502D386904501E00134E87236C8458C4B2C92CA6A00DFB640C99885A3AC80F4E466635076C788B194190E94DFBE06BDF2066CE117A759CCC4AF4D865129B9708B35F2E446F2ED44BB007F67283272A317B669F69F5495668EA76037E998F236E4420C87D2378E1CECC3F972B21CA86CCC749B3A471835AF7CA65172A136530C25187C35CAF80368926D1C2397235A9ED92029B446D328E20C37AFB6165C29A4302A01427E9C590D915C1586F5C520A362015401DF167C4E650096A9AE2BC48A85CED418AF1225959874FA3015E25AB6EFD5853293265C2E3180694EBB642526622AA2C95C7C24D72A25B4042B69D3A49CB882A0EF91E25217B5A3FECA60E363C28792D66542C62F8475A6478923642B46C3A46D8136B6349C3AF08CF23DCF4C40DD0648EB9B19446B21A863D874C953113455A7AB1A0E47638D33135D7771E9AFDADFDF1A6CE341C127AA58D7A0C04536C668E499D76FC7032E26A5BBE20107AE2C52A9EFA490F1DA98A0C6DD691722CF4E4D5D864A301269C9B328D32131373F4D4D7AD4648630A192470DBC70BCC8A0DC336E87A53333144071353C982FE6C68306B9E45BF515F552363C53C7369843CDEAA443F147CC3A4CB6DAC5F5B5C03188A4603E55CD96301D2651658DB22C5550DF2CCB8389382C415515CB9A0C5771CA6452154283414C900D814E445180AA9C6C4B71A6C3224A53058C507BE438D5FD727FCE36EDFF0038EBF9063C3F2E7CADFF00748B5CCA8F20D079BDA70A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8749E4AC447B652DE9347F131A77DB1557B6AC3386E9BE2AC8AE5C5C427F9A9B62AABA7B98D4027154C4C625607BF6C550579CA31C7BE2ABA08CC916E31415268087C5AD34B4E51B03F462D8134B97E51FD18B68415AA076901F0C05126A5B602A5464648097CC484653D32B6C4A963A927C7BE565B62B91FD30E3C4E218493CD1A4E532FCF2126507A969FBBA8F1198E5CB83D5FC9B6D5BAE9DF292E541ED92A18ADD683282E54026BA2C2EC39B0D8644B7443D0F4C8D782E5527222190C71AF31B641BC04C52104834EBD316F8A67142076F9E2C9305B72698AAB0B638AA323B7341B62C9CF6C7154C2DAD136DF154E560840F703014851692255F88019410DA95CF7766A08E601F1C810C9049AA5BC469EA8DBDF2B21B0228EAD1488C88E3938F872045325B15C4951591720C11C2E55455DD597B8C55DF5AB56EC98AAEF5ED88FD95F7184319206EAF2071C3D41926210735CC7140A43D77ED8B20C62FB52E4E141F6C5B137D2C92189E8C36C05B2298CAC1109C8B3B486F2EC28DCECB8ADB1A7D7218A5E25FA75C56D33B7F355A5BD393800E5B02C08B4DD3CFDA7A2D0381F4E49908D2D5F3FDB199B8C808E1B0AF7CBB1C9C6CF0B4A0F9D67BAB6BFB49B7826560A0FBE6CB14DD0EA30597E74FE7368325B6B97B7B04748A51C811E273638A7B3A2D462E12F9DA60F1BA07EE73371C9D76514887015A83C065D6E21E6B7204A40554FE1841D99A9C9D701296E28F7AF8E564AA37A0CAED5FD707FCE36FFEB3AFE41FFE6B9F2B7FDD22D733A1F48683CDED39243B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8739D15050D6994B7A56838C8A53A72DEB8AAACCDFBCF87C7154E2DE86024FDA036C551B6EBB6E37C551F1CA237523B763EF8AADBF40F1FA83ED1DF156ACE5E30D0D3962828D58E3937A5716B5748B7A1FB23A62D817CA6A287718B68528488CB15EF80A24AE5CB0C8C9012BBB4F877CADB12C8C1DC0CACB6C50EC84B1E58B0927DA3C6038206F5C849941EA7A38F526507AD36CC72E5C1EDFE4F83D39B95329939507AE9ACD1A2D3E119417371F2659A55BFA70F151DB225BE219469B190429D88CAA4E44427D6EAED3053F6720DE032686D01A6C698B604D52D1788A038A5328ED8F15DB6C5518966081B7CF1555312203418B2433E2ABE3623BD3155579F82925BA024E2AC5AFF5A8F81A380720437304BEBDB89598A49F09CAC8641266B8946E646FBF2B21B436BAB4F1FC21CFCF2B904AE3ADDCAF499BEF394B05875FBCA504E7E938AAD5F30DE29DE7A62A887F32DC471971354F4A610C648287CCB712CB4692B9260190C1AB4D31285AB45A818B30EB6E7753FC7B8AF6C5B1E81A7C451197A055DB0499DD35773908DB8DB22BC4F3ED56EE5A482BB0AE2BC4F2DBFBB732B166A11E18AF124536A2EE4297240E94CB20CE25080DECB25217600F8EF8934D9619058E9FA9F2462599BB1DE9928CF76899B67B67A56AB7118528294EC3336191C2C98ADE51F9ABE4D9A5D3EF649E127D0879A353BD333F164D9D06B70D17E7FDFAC4CD70B30FDF40E4474D86C7BE67E2C8F3DA914972492301EA50B77CCC8C9D613BABAEF4AE025B61BAB2004D3240ECCCB6F12D2A7224AAC0FC7E8CAC9558F3B76A7CB236AFEBAFFE71A8D7FE71CFF2049EA7F2E3CAA4FF00DC22D73610FA47B9A0F37B5E490EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87FBA8BD4048194B7B1D95BD16A1EB8AAAC3FBC353F3C553112FA6A476C553AB12255A8EF8AAF9E321AA3B74C5549AE015F4D8EF8AAC4AD76E871414E6D7B138B5A6C801E9E18B6042DC6DF3C5B52DF50A927C701449176CFEA353B646480985DD972841A74195B63152BC1C8EC0E565B62A4D4635F0C430927FA42FEF07EBC849941EA7A0445AE51BB0EB98F272E0F7DF2E22D40194C9CA83D12CB99611F5DF6CA0B9F886CCEB4D0C38AD3E8C89E4E44597E9F0FF00A415237DB2A939116530DA8F5850641BC06490460103C31649B2C6B4C551491B6D41B62A8D446A0F871569EDCD09A6E7164817B73BED8AA1243C176ED8AA4379764065AD6A08C55874D652DCEC95381B9520D0AE08355241C890C9171F961E43464A8F97F66565B0233FC191B293C7E2ED954F932E88197C9A00E998CC12CB8F2B8B78DA5E05F8761DF156297F6621AD206DBBD31563176EC6328B0B29AF5C218C90964D289B743D724C0335D3999E52A548F8716619DE89680B863D716C6573968D2918DFF6A980A4A4924C4F20FB7BE4516C475754653C37AD6B8ADBCDEE74C92791A83A9C56D42CFCB5732CDC1622E09EB4CB22764893D3347F216E924D1F1EFB8FECC848A99BD2EC7CA9630AA82AAC7AE40163C4CA6DF4AB5800E2829F2CCA84940619F99FE5A1A8F937549EDE1065F4986C3C01CCFC52D9D36BA1BBF1A35FD2CD96A5A84338E327ACDC54FF00AC7363864F27AD0C6648CC52943D466C205D213BAF4C9B978BBD156E393D0E36CA489BB4E2A3B57204A1219A52B5C892A8749F91A57A6564A1FD7F7FCE346FFF0038E3FF0038FE7C7F2DBCA9FF00747B5CD9E3FA47B9A4F37B6E4D0EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88FE09E89206F986265C86217D18790FE1928CAD5640FE91DF2684C42ACA093B8C2A9DE95F01A1FB3E18AA6578547D8D81EB91B4A41229E7CB2064847C0EA29CB718612B2829FC7E888EAA37F1CBA835A26DDD016277DB225B0284E19CD17A65664DA103242114B30EBD30192D5AAE9FFDE644C9908B241CE489D4EE00E982D980C4F50B52AC59453DF06CD8024EBC91B89EF9125B238C1E6C93493FBD51DB2B914F000F5FD094ACC9C45052A731E45B601EE3E5621A401B7AE504B9B08BD5ECA14AAB22D189EB98B3951765860299FE9502D15996AD90E22DE22199E9F6D1FA9EA71F8CD2A7236DB10C9E1894B82474EF8B626B144ACE7E793114A611464B713D3C325C2153A8E3000DBA0D8E0E10AAAC0A8DBEFC7842AAB0F86BED8F085B40BF5C7842DA577708E2DC0531E15B62F3E9EF2B13C490712026D1765A5246DFDDED9512BC4C892DE355A7015A656496C125C88A29F08CAC96F8C95C01D29D72B2CEDC638DBED2D722634B4A0F676EC0D23049ED9548522987EABA7C6C5FF74BF2A0CA49626DE75A8E99C8B462314AF4A61848DEE903BD278F4708F511EF5CBEC32E109FDA69C435553E223AE3B278598E9903C34EC3BE1B09A4E652163241F88F5C8C9B211058B5DFED6FD6B9149800C6258DA4675AD47718B510A967A6C4CFF147518B512CE74AD3ECADD59961018904138AC4B2B49232B420500F9603BA69689A388D176AEFD71A452256FA9FB59206992716CF16A9A65E69B3012452C6FCA33DFE1399FA736EA759B97E31FE70E94BA6FE656B564578DAA3B3431781A939B9D3879AD6403C655A49EB34E794A5882DD36068336511B3A1C9000AA00074DB2B9158121176E55483DFBE52665CB8C6C29DF5C301B361E22A62C6E6766AF235C9B02104B38434069878583FB10FF9C653CBFE71BBFE71F1BC7F2D7CA67FEE4F6B9B087D23DCD079BDBF248762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D8DAB09F719801BD8DDC8A4849EC77CB2294B5C736AA9CB1531B69285636FDADB0A19143FBB5AD7A60554F53D45627B602942BA77F0CA8A143D4DC01E38C0D154FE02C621E19719288A362069F3CACC9B045308E2046FF007E5664D822A7731064000E991253C2A7A7DB7EF3A64789908B2BB5B6AF30456B8F1331143EA7A627A65A831E26C1160A6CF94D41DB6C04B6C62CA746D3099936AF8E5722A43DA746D302F134DC65132CE01E9BE5C88ADC5076398F22E7630F63D1A20F22A1F1CC69F376388507A3D9C3C19401F4641B87366D610D29B6F8B6C53A4401C7862CD31B789CB123A65A392A610C3273C2AC8228C71507AD3155EF18A53BE2AD32EDFC715413AEF8AA19A307AFD38AB696D19EC36C0555BD140360065549010B22D180F7C810C8158401F3CAC86624B3991B9391E16C8C9DEB0C4C5B4168DC8405ABD3299452C72F6F1199878E6398A6AD875ECAA5C90054E400A4F0D2053E371B77C3C48643656C6B5A6D4DB1E254E12260BB63C4AB5A195C30F0C902DB89239AD253CBF56499C9237B57491B6A16C5A24995AC0C083DF16892730C8D1EC72405A225182E881D70F0B2B51376A49E477C7856D512ED36DFDB1E15B649A15D1127C3FEEC0CB4FA0E6660D9D6EAB72FCAFF00F9C90B196DBF342F66238A4AC493F7E6E74E5E73561F394A156460BF66B9B2076745946EA7FC72A996B886BD42A72AE6E643925D7331634C980892493DCFDA51DB6C980C4A56CE49D8E4C06A7F645FF38C1FFACD3FF38F1FF9ACFCA5FF00746B4CCD8F20D079BDCF248762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D880E040E87B66006F492FA2F88803AE5914A1C5B7186BC7E2F1CB108781585C46CDBAA9C2ACB15E3684803738154955A35663F6476C05285594BC9C6B55AF4CA8A157D052E2837C8F567109CDB3AA808D8993688A6B0C44B0A7D93DB2064D8229EFA01635A2D09CACC9B0456081581F86A720649E15D6F6AC1C7A6BC71E26422C9AC6D242D535A63C4CC4532BFD3CBC068B534C789988B036D34C731F82849C789B04597E8765C654257204B121EB9648B18400509198F32CE019C688A82652A286BB9CA497371F27B068CA81D582D0F8E5122E7E3E4CF6CCF29D2BD3C322DA39B36B4AF3F84D17B62DB14D56A5B03364368E811011BD284E5D1E4A9B200402A389F1C2A8F49102AEDBD3738AAE3221EA31543927715DBB62A82949036C550F473FB471556457A801A82BB9F6C555E458A31549BD4F639021925B35DB80CA2DD189E8DE190216D45EFA38AD889621EA53EDF7C810C4C92A4BB8DA29A46958B28F8129D72206EB19A0D2EA607D53C9D3F9299618B68CADB5ECB7069E87A71D3E2343944E0DB1C9691DD7EF83F01C58577198F28B609B1B78A560C492483F6B299C68365DA2ACEDDCC82BBE55C28675676A0AA80BF1531E154D52C588E98F0AAE5B1707A75D8E4A21B71A12EF4F2A84AAD0F8E58CE4C4E6B26939A96E2F5F84E2D1256787D2B16319E52C42AD20F018B449E6F79F9A5E52B099ACF51BD4B6B984F16151BE5916B2692D93F387C822A1B5B2BF223254BC4BED3F363F2FAE24A0D6D9B7DEB4C697899345E73F28DE11F53D5D2A7A02C31A5E2665E5DD574C9264F4F555256A428208DF2FC45C2D46EF833FE7278423F31E36DA482653507A13439B7D39741AB8BE3F6565BCB84635556345EC01CD903B3A2CA374422214625457B65536B8849677605E86832500E4C521B8B97527E3CB00625262EEECC791DCD7260312B94E4C06A7F64DFF0038C1FF00ACD3FF0038F1FF009ACFCA5FF746B4CCA8F2683CDEE7850EC55D8ABB155AE683E9C554F97B62AEE5ED8ABB97B62AEE5ED8ABB97B62AEE5ED8ABB97B62ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88BB53C866006F5971082E0D3BE5914A16E00488FCB2C42550D19E83AD76C2A98DBC844BC3DFA6054E2E29F56603BD3014A4515564CA8F3423C5C0420F7A65726DC7CD745704B8232B25C9AB6490DEA22A6E2B5CAC96C8C593433ACB1AEF9025B04535B4B70E188A1DB20649E14FAC6C55985464789970B281A7848C328C3C4D9108EB6D3DA78DAA2BB63C4CC063B71A3137205325129AA4EACB4A68DD6829824C4866305B32B2023B663C8B38B35D1A03EAA6D9492E6630F56B106109951E6E6C59D69DF100D81B073673A6FC4AA69D7BE2DB14E917E3C59A7D6B6C48461D0EF96C792A751A711BE155C57DF157703E38AB5F4E2A849BA62A82798462BBD71541B6A616B5AE2AC7F51F31D9C1192CC63A77C910D8C02F7F30F4BB763CB520A57AA93FD99590C0B179FF003C3CB167270BABC593DABFD99590D04A47A97FCE48793ED2A91852C47C27DFEEC111BB59953CAB56FF009CAA82DEE78DAC21A3AD1401FD99710C2390DA5F27FCE4A6BFA821FA8D89E0C09E407F665120DF1C858D45FF00391BAEDAFAED776C556BDC7F6663C839519BE91FC9EF3EBFE61426231805D4B961ED954837C256FA2AC7437AA9E3F4655C0DCC9EDB4C78CD48C3C0A9DC160481515C1C2AACFA79A834EF8914DD8D0379A79E1F7E06526177962A03963C585787BE2D1248D61963B1D453ABCB1B08FE74DB16893F32BF313F293CFDA8F9AB50BE8209A5B79A4668F8F402A7DF32314801C9A64C462FCACF385B6D73A4CF2D3BF13FD725B215D7F2EBCDF34CB1D9E893C751BB713D7EFC7657A0F977F243F30A7991E4967B343BD09A7F1C695F5FFE597E526B1A5DBC6DA96A0F34CAF5662D5D89E9D7251E6D1946CF1DFF009CCDF253680DA3EB11356474EBDFA1CDAE9CBA0D587E7F593C9373965D9DBAD73640ECE8B28DD16A7E07F1ED954DAE218BDCDC0124895E8694CBB1F26F88D9239EAE4E5A031921F8D065803595226876EB9301ADFD94FF00CE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A0F37BA6143B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D8294F845330037B52D4B29AF7CB2294AAF6BB8CB152D8D5830A547CB0B13C930854870DBD7C72122C2253953585ABBE54496C4A1BFBC6F9E441552641238567283AD7F86322299E306D98F967CADABF98AEE2B5B3B62C8C69EA01DB31CC9D8E385BEDAF227FCE2EC17515B5D6B32155900A293FB5BFBE5129B9F8F102F43D57FE716EDA2B988E9CF5403EC76FF89663CA65BBC10F25F35FE476B9E5FB932C687D193E1555ED4FA72066C7C10F3E5D0750B0B8F4E5571C4D0D7009A462A6616D632491014AF11BE59C4CFC20BCD9DC4428B551ED931309F0D012DB49CD59C50F8E094BB94C02636B1134F1C8711699C53368A452A791E9B60B6BA65DA0C94750C706CE442DEA763229E15DF289F3765879334D35C55476F0C8B7B3EB023E103618AA7D18AB0DB02DB27B16F8554F6197479330980DDC006A3C30A551862AAB18046E31545718986C82B4C585A57716ACD5E228322B691CDA75D716F8493BD32B2516F3FD674BD4DCBA4523A73040A1E99124A5E3BAE7E4DF9C35F467835BBB8977AAABD3F8E4F88A402F1CD4BFE71BFCE6F3D06AD732B576ABF5F9EF82D9D16357DFF38C5E757A97919DFF0098FF00B78B218D8A5C7FCE3179D43F22BCCAF4AFFB78F2639310E1427FD0B379CC48ACF6EBB1EE3FB720723891C459FF00973F203CD715C436F39F4A0604391B536F9E4253722185E97A27FCE37581BC59757B812AF2ABC2C6A0EFE15CA8CDCA8627D4BE51F22F97BCA10C49A3D9C5048ABC4B462808EFDF2A9CB67271E3A2F52B68AA828287C72102DE629D5BD9B4AA07877CB835909BC569E9815CAE4C0AAB428C0D08F837CA81B402424B733060D18415E95C2DC0B0ED474F6A973B835A0F0C5B0C424F1C216A196B4C5A6710105736314EDCC205E1B103BE0B21C59C2F9249756B69103CE352464F88B5F865298A6B78A5A450278D699602BE19661653F35154070DAF8659369F7D0DA144745FF4821547BE46CDACA1B6EC37FE7263C99179DFF2D64586D926BCB088C826A55C0E2C7AD7365A693A4D5C03F119A136BA9CF6922F131C8D191EEA48FE19B8C727439318B5194888DD21D890787B6DDB26402B080616EB44AB6EE6BC98F5C9844A21047ED1CB034C821DBBFD3930D12438DC9AE58D25FD957FCE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A4F37B9E143B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF889B535CC00DEAF28EF9645528BA1C8E58AA10C60B8AE2A5181789C045B590982FF7669E191314829431FDE36532D9BE22D52D2C9F52BE82D233467351F466365C941CCC18ACBF49BF21FC950E9D6105EDCDB2BD003C88F9E611CAEDB1617D71FE2ED0B4B8E21385E286813C0E512C8EC71E057B7FCCAD0EF6EE386270A76037CA2591BCE165F7369A4EAD6CF2CC527122FC209AD32BF111E03C475DFCB0B2D424966B78946E69B63E22F80F329BF2DEE609654856A17ED532D195071525571E49BB86BCD0ED93191071A437BE567442CEB4206DB6113B6AC90628BA7345395F7E98789C5945329ADB8462BD69D71B6BE156D224E33818F137462F48B49887515EC32B917618850679A4C84B2FBE06D7A3E9CDBAD76C5594DB8E4C3154E6D5C89197C32D1C9984DE13571852886FE38AAAC7D3154C228BBF638A6959A21DC74C82D21999882380CAD692C9ECFD53BA0A9DABE1919288EEE8ADE6B65F4924EA29838DC8F0D092DACA8793C8013D1BC31E36631A5773F003CAF01FA4E3C4D831B1E96F2047DEE86DEE72139ECCBC2B496EF568492A9722A7E798A7228D3282B5C489EAC373561D1413959C8DD1D3A274EB7964B80D2C859ABB2E40E46E1829E8D6914CC1226B6E117FBF48C8F1DB2963A65B6D6E11176AED96C0B5109D4238A82075CBAD810ACFCB8E5732D6425CED22568763D72B896043A38A39012454F8E49B6297DC5AF21257A0FB38B7249FA3958B6DF4E2D3916C1A423ACBCBB1DB22538B1F131ED53CBE8FCA87AE20B6F82C364D0258A60231C93A93938C97C047C505C5BAF43B6596BE026B6B0C976D645BED452127E583AB899B1D3D3AD2DC6ABA76B1A6CC39ACF6C63507DD48FE399D84D3A3D5C2DF87DF9F7E50FF0003F9EB50B20BC6970CF4A7F3B31CDB6296CE872E3A2F1CD4855D641FB4BBE650DDC7E4C4AE362C3C32C6322969FB67241A64876EFF004E581C7921C753963497F655FF0038BFFF00ACD1FF0038EFFF009ACBCA5FF746B4CBC72692F73C28762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF889B360BD730037A3E4A1E9DB2C8A529BB42C76CB10A50AF165A8A625211B55C622D8494E52786C77A8C998ECD60EE83BCF8AE9388A506F4CC2CFB39F845BD1FF2CB493A96BD68047CB8CAA6B4ED5CD5E59DBB7D3E3DDFA93A3D8B69DA6DABA0F4D1211555D8663176D8A2F2BD72D751D7353962B3321084B1504D32893B1C71D952DBCBBABE9EA26657046F5EF98F26FE009EE8DE78D5B41BD1CCC9344D45911892001DE99595107B868DE79D1B5B31AC92FA5310014069BE36930658D6A8E1DD40E128F81BC72C69945299F4A421AAA0D7C46581A0B0DD574359012117A1ED9312A6A9C5E51A9E83C2524201BF618789C69C58F5D69DC410476C789AB85274B5E126DF0D0F518F137C22CBB4752028356DFA9C376E5C0507A4E974053B7F98C2C9E83A6CA15803DA98AB288E7008A62A9AC2E480C3BF5CB63C998E49A42E69D4E14A395BA62AACADEFB62A9BDA5D536206D8B35F7373CA945A5720B4840ACDD09CACAD221232BD6BF3C84CA62375D2AF53D0E637139A12B9622FF0D49E5B6F8789B404A2EB492CA69DB071338B1A9BCBCCEE47106BED919CB66D88DD47FC2E3FDF43EECC4B6F115787CB8D1C8A40200ED902590A661A6E841543155A8F6CA8A788271E97A478D6A3C3082899B08E801D854E5F02E3109AA82A0153990C4869A471EF954CB590A2D2B32B0200C840DB54C25A4B89050903C32D6714C963F5A3DCD0A8DB16E4B64B295492010B5C5A72289825D8455A7ED655334DDA734BBEA32CA28687E782DC9E2583494460B201C9B71F2CB014F10448D060906EA3EEC9028E25F1796914F258FE9196C5C4CC2D36B6B45B53B2B03DC8EF97E39EEE9F518DF9A7FF0039C1E5223518FCCD15B8F4EE295217F9797539B2C32743A8C6FCE1BE9B8832EE55968066CF13AB9ECC50124B549CB4B594249D4E48354940F4CB038F2511D4E58D25FD957FCE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A4BDCF0A1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88089A86B9801BD338CD40F1CB22969E30C32C420D8713B6291CD6D4E4A00B1C8B58D46E69979AA681CD40FC7331F019ABD4BB4D353E9EFF009C74D21751D692A952B535A78669C9DDDDE101FA397F6CB6DA3D360563A01DF2120ECB0B7F96FE5B8F503777862ABD08AB0EDBF88CA661D96309BF99F4A3043246918E9D8663C8373C0752D0F50796436F096321A37C35DBEECAE99458DCB65AAF96E48EF4A4B50C0D02B78FCB101127D05E48F375D6BB6612E418CDA850BCB626B4F1CB0071E6CFEE66658C7BE594E34C149A525D1AA3AE46450030AD4EC83B31A6F91DDAA51613A958D0F4A6DD71DDA845864B6A56423EFC6CB7C629EE92854283D6B9747937067DA79A32E4959BE9FBB8FA31564A83718153C85A8A9F2DB2D076660A6B136DBE1B4A354EC3F1C2AAEA4D3154742E148AF862DC119556C8324C6DE256A74DB2B28559630B95CF92421D979661B900A87A7BF4C0CE25B30F2ED8B60696C4160481B74C05B224DAAFD487F2D7E8CACC5B812EFA90F0032042D9575FDD0E23E9CAC861C454DE124FA9D7DB214CA3225673F4CF4CB62C885C353111AB6E3A65CD65506A91C9DB2120C0B6F771D36DABD7238F9B44D0E675AD69972628BB797D571C7609D716F64B58A587871DE98B4CC162B7F21D31F8769872194E45C7612F87519A46A274F6C886EE229B44E646066D9874F96482F116416C22E23A64D788A756F2AAC4151030AF5CC989D98917BAA344D37488610E0E78BE6AFF009C9CFCBF4F347E5EEA73BC5FBCD3E2661B54FD963E199D824E83541F83FAA5A1856F216D9ADA5650A7AECC7B66EB09D9D0E6D8B0FEA58E5E5AC1D9072F7DF2516B9287ECF5ED96071E4A2A773963490FECABFE717FFF0059A3FE71DFFF00359794BFEE8D69978E4D279BDCF0A1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87EB35F7CC572138A74DB2415A634196054B67900E44E487355B1CE38D2B96EC8282B9AB74F1CA665880A912F22CBDE99ABCE5CCC5B3EEAFF9C4EB113DD988815E25AB4DF6CD69767A626DF647999435D5A5BAB1D880403FC32B93BDD3F37B97962CD6D34832280ACD0EF414CA245DC621B30AD5A77B849A302A6A77CA2459494B4AD209812478C115DC951FD32316A1CD3AD5F49D15B4D91DCC3EAAA134655EB4F964993E64BFF300D235631DB30085C8F82806C7DB1453D5F45D7E4D52D54D6A683F56147084DE0BB3C9C4B4DB619645A728A49EE7799DFB1E992A68A627A944199EBD4EF8D2D30A9AD944BF3C6928AB440B28A61566BA79A30C559A58BFC43E8AE2A9F46FF10C55388EE00551E191BDD04A3A3BAA8EB8414A363B91B6FF003CB1B02312E47CE993661328DEB43E3DB16E099C4E38FF000C82A2606A656528D2A5C0A75C84D5BF4CE6310DA1A2877C890DB169537E99590E405754DC572239B656C98C511A74AE4E419C10D7111A1F7CA64E4001085780DFE9CC793090097CD7263A953F17860873681CD26B8D4E58EB5A6F97AC92A7BD9A405877E9938B4C9AB7BC9D09CB29A095433DDC8E4AD7010D68F82EEE0515D6BEF819C5368272159E9C69DF16F82223F307A4425457A62DD1016DF39D5F871FB4A28299092C804A6386EB4B928C84A9EE722C53D86EA3640CFF0068E2A98DBCF0D462A9EC13D221C3ECD76CCBC5C94A6B67744115CB1C2CE16F9AB4B1E63F2E6A1A4900FD7A090014FF00248CC9C45D06AE0FE76FF3A3CA4FE54FCC6D7347652AA9348C05283AB1F6CD96293CFE68EEF03BA6FDE483A10732E25A2B648E7152773BE5C1C69F35315000AE6445A96E5A036C407F661FF38BBFFACCFF00F38EDFF9AC7CA3FF00746B4CB43833FA8FBDEEB8B1762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF884B31D2B98AE426E47C3920A8694EDB6F9605482ED982BD01AF864952E86670D435F961B414D50730396D909A0370370B8907B7539AECCE5637DD7FF388F76A359642E05617A0AF7CD74C53B4D3737DAD359B5DEB30730410C280E63C9DEE9F9BD5EE3513A558B2745F4F8E5327718B9304B6D4629D679188EA69BE63C99496DDF9DEDB46B231B952D355547707C72316A1CDE15E63F38EA77F2C896933047A8A2939364C22DF48D42E6669E7E72173553D7157A56853DCE9A1622080682A715672D70DE9A3AB862FB900D72D838F991729E56E186EC7A81D726D2905FC25CA9FF277C558B5CDA9049A6D8AA95AA71931565567B32EF8AB2BB37A11BEDDCE2A9E46FF0010A9C55358CD40DF21D58946C792641191E58D811B1D6993661368998003C316F4D6273415E990423918D4532B294EED8065DF6F0C849513C465242789A2828720437464B553C7AE4087263255A002B4E9910376CB454520E3D69ED864DD0536219C0EA3C7289736F082BB1C50D3AF8E63C98C986DE4AC3950EE0E087368EAC3758BA99281493F2CBD125897130B346FDA66A11938B4C9111C92B15A6FEC32C0E396596B6D298D0AA924F51896B45C92C36A959402E3AAF7C8B6458E5FF99A0A18E21E9F0AF3AED8B7C5875C7984090BF30057662716F8A79A379A8C328726A95EBDB2052433C9FCC16DA94694515EE46458F0B514913505413E0315E14EED0C408E5F0FCF6C53C29D2CD1A2715229D46F97E33B302AD6F78A1BA81F4E4F89AA70B09B5AEA9CAE91030658C153FECB327149D36AF13F22FF00E7387C9B168FE686F3446800BE6259C0DAA6BDF3618E4F37A8C745F9A7786B7136D4F8B3638DD7C85256E09ED9787167CD408A66445A9665A1BA2FECC3FE7177FF00599FFE71DBFF00358F947FEE8D6996B813FA8FBDEEB8B1762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF884B33D37AE62B909B337C24788C2150E57E1396854A665FDE0C4AA4F29A4D5F7C802828E0F545DFC36C24A02E97EDB53C33132072B13EABFF009C5AD5E3B7F345BC6ED40411BF8D735F986CED34BCDFA88F12B6A36578375E20D730A4EF74FCD11E719DCE8F2CD16E6BC49CA64EE317278326AB710C14E5BF2E998F26526317AF79AA5F3210480A29918F36A1CD97683E45BBB86599E33C4D0D48C9B27A641E5FB0D360637340C47C18AB1BBFB6B494B7A43A74C550FA4A869DA222841A0CB60E3E6667058D09A8EBBE4DA503358061257F9B154A27D257D36FE98AA4034E546229DFAE2A9D5B5B22815C5536854290A3A0A62A9E47D302A2524A151E191EAC4A670CC7EFC90649847374CB1B022D26AE4D984E6396A06FB5316F098C6D5A64109A44C2A32B294D216A50D76AE4648298FAAA76C890805BE55CAC86D896F9656439112E26A322DD12A65C0EFF003C8C9C9C6D7D657A65126F086BA9818CF8E63C98C983EA32F10EC3C7A6087368EAC1AF2F19A4A7865E8936B7C562A1DF261A648ED37518849CA4DA996071E48ED7BF31F4AF2D69F25D4AEA0A834AFB62583E6AD6FF00E7226C2732CF030660C40A1FECC8B38A3BCB7E7A8FCCF6F73717527A224A7A5BD2B8B7C53237D1CC5E2AF348F7AE2DF1627A87E63C76529B0869198F6A0EF902D8032DF2B79D6FEEDC0E478B7BE4534F6FD0F5096499096DCE2B4F4225E5E1F175C5691261936A4DC76E95C9034D13E6EF425FF968FC71E26C10B08CB698D9D02B739240791AE64E29381AAC3B3E3CFF009CDAD163D5FF002CA3BF02B25A30634EBB54E6C71CDE57578F77E2BCF2195DE43FB44FE1B66DB0F27479051428EA3E79921C39A1E41B9F9E6445A90A577CB83745FD98FF00CE2EFF00EB337FCE3B7FE6B1F28FFDD1AD32C7027F51F7BDD7162EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87DB371502A2B98B4DF69C13D01C90554E3B7D19312094A275F8FF005609482B1EB8DA6F964225055E3625900049F0C9A014D110167327C238EC4FCB31F240B938E41EA3F935A8FE8AF31DB4AB2846332802BD413D7303340D3B3D2C85BF5FF4FBEFAC6876376AC1C7A43E319AF90A77DA722D34B906FF00CB573DDC3120663C8BB9C4367CFB35ACCF70B0202CDCF751D466392999A7A8E81E5AB7F53D69286408A48F0C62D319025EA16D3456B0085221D280E499DA4B7BA7C9A99268691EF418DA5E5DE60BA83439191E550D5FB24EF82D52DD0754FAE6A30B28E20FE396C0868CA1EC8564540C632011B31193B684ADC1624914DF738ADA94F1A985A8C09A614816C6CDB92C4D3BE282295046CBD01C55150EC77FC7154F22208EB8AAB2005AB9162533840A75C21923E351B64DB0146C69B64EC3208A89CF2A5698DB784EA17D86F90B54D616AD28722529AC6F414272242AA2CC01153898B0E0368F4DC546FF002C818B6C415F46F7CACC4B9116B953A9A7CF20634D91284B89000486195483978C84A4DC7C62AD4F7CA241C805B966AA1DFB65120C64C33569F843235413D86463CDA3917973DEF2BA615AEFD32FB6264159AF9A12ECC85815D864E2D5229249E6048924DC230AD01EB9686821F337E6C6A3ADEBF6F1D8D8A4A07A8DCD97B838086145E59E5AFCABD62E21ADDBBAF26E546FA0F8E459C43E91F2CF96E2D234B68AE18C92C207A2ABB9F7C69BA3B2AEA725EDB594AF65138918100537C5B8178FE9DE5BD66FF547BABE57ABBD547B64241B4483E92F2CE8A6CE18A886A06E70527883D934189F9AB73E86871A5E20F4069278F8904D3C7052F105C6ED89AB392DED80DB44B9B5F5BFF29B23BB91090554BE113C4C5AAA55AB5EDF3CC9C4D3A88D8D9E47F9E9A41F30FE5579801AC92C51B32C23AD02935A66C71BCAEB31905F8377711867B8848A18A46047FB239BAC3F4BCCE7152418076DBBE65C5C19858EBB9DB2F8B4A1580CB04806E8BFB2CFF9C5EFFD667FF9C76FFCD63E51FF00BA35A65A393813FA8FBDEE9858BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF874B265328CA593246507853C72259C513C07139596D0935D28562721D5279311BC929375CBA1C9A24BE0B90268E872F8F26013B9650F1EE72126FC68DD12FDAC351B5B98DB8B472015F6CC2CE36761A73BBF5CBF267CCA9AFF966D6D24903148C0A66AB287A1D2C9EF3A5AA3C9FA30AF10FBD735D91E8714B6615AEF96C695E6084C43E0998548F7CA29A739B7B3E89E598CC6B3247EA19D0034DE996403878B9B2EFF095959C5F5ABB70AA054A9C910E482F39F3AF9B340D26C192C028B85560E57B900D32B21982F8EB53D425F345F4CD2A91463C09F9E565B014C740B2D46CEEC39AF18D870F964E0C66FA4B4DB8379651ACB27C400D8E5B17166956A21E262886AA456B9634F54B2332383B6581C8835E9301B8DF0144D690475C0C694FF6CE2B48F85C01F2C569188D520D698AD2650B50628A4D633D314D23636DBE58A8B6D1C73A62E60E49A44FD37EF8A53BB6906D8AA64241B6298F36CB0241CB9C9149B5ACC1471AD2BB656BB2600823AE40ADA1A7038B37865534DA493C828731CB740A4B3C94AD3AE51272E054DAE1BD322BDB2892C8B17BEFDE73E7D32B71E658826968D7264A7535C21A2D327D2BD40401D475CC88AA42FE528A69099146F99015747E43B157E7243EA03D0787E38C92194DAF9574C8900FAA8DBDB20C9CFE5AD3CCA812D40F1DB154F57C91A75C45536C3953C3FB714A4375F9736C2559628F804EBFE75C8948445AF97520223A74C0A9FDBE962CF7036AD4E2A9DA32BC746C550727A49B03912CFA2025B845DAA3DB20D40EE827B9574702868466463E4E55EC93F9C6E3D6F27F986253F11B4947FC21CD962745AE2377E0879810C7ADEAA87AACEFFF001239B6C3C9E3B55F594A17F8E67637026B24077FD796171D02EBBE5526E0FECABFE717BFF599FF00E71DBFF358F947FEE8D6999D0FA47B9D7E4FA8FBDEE99260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF861D3DE432034DBC72964CB565278537DF2259C51C6600152C2BE19516D093DDB13CBDF23D5279308D403ACA3623C32E8726892193D65742548F039911E4C03258F9B415E276CAE4DF8D49039755A94A1AD7E5989945873B0BEE7FF9C71F39AD95CC3652DE0EC3893F3CD7658BBAD34E8BF49F4D9C4C12F512944AAC9E39AEC90779872A6B75045AA442EA420CF17D95EFB653C2CF24AD9FF94B596B3B6953D1FAC49C6853BA8F1C9014D111458679F7CD173E94886630F20691FDF890DC0BE62BB6B9D42E984E8E6366F858F7A9C810CC1645A779360216644E04EF9510CC1640DA298978C49CDA9BD30C42C98F1D46F6C2F56DDB946A4F4CB22E3CDE84B492C83BB0666DF2D69EA81876276DB261C88372321620900D3A602C8A0E414DFB604521F73B8FBF15A5652C3A0C5691F1F2A2FEBC56933849A5295C569348C9D85715A46AB506FF004E290162960DD3E9C5BC724C627A002B4F1C529DDB38DA8698AA6AA4F615C5239ABA1EE72E6DB541280CA396F5DB2056D324B903E127E2CAD6D7CF23189FC29D72A9A82C7AE255E81B7F0CC72DF0293DC39505A9D3289B95028069DE9D0D3C7289A494AAE999D08A6F5DF2B699157B5B55600D37C21A93AB6B3ABD38D76DF3222AAB3D8AEC547CF3202A360B3429B10580F881C64C8223EAE9F6792FCB20C913069A240EC08057ECE2AEE735BBF02E062A8EE64C4C18862DD32254242E8166AB0A6F812A978C161AFE38AA412DD98E062AD52062AC4DB54B862C0D46E72126CE88492FE43B16A6443472288B5B8E714A7957A664636F32F4A035894C9A16BEA4D57EAD257FE04E6CB13A0D74DF86DE6D503CCFAE85DC0B96A7DE736D8793C9EA0DC98F053E199D8DC19B9CAD3AEF96171D06E2A76CAA4DC1FD92FF00CE2FFF00EB347FCE3BFF00E6B2F297FDD1AD333A1F48F73AFC9F51F7BDCF24C1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85DD35C96DF2964CB6023E1F9E44B20BA47FDE1DFBE5526E081BC7A2935E8323D527930FD45CB4887BE5D0E4D1253673CE1073223C9806516854C237CAE4DF8D12618E343336FDB31E4E66366BE45D767D175482E623455606BF7E61E58BB1C137EB17E5579EA1D734AB485E60D23280457E7EF9ADC917738723DF2D678ECAE638E75062946C7B6F94F0B9B1DD1535D496978CF6BF0C53281B63C283B21750D223D6007B800D7C7224282803E4ED387A4428AAE4086C05192E8F15BC5C621B814C810CC1632F697AB3858A22EA7A90322366576C7353F2BDE5CDCA4E632287241A26C820B0921B658DF7232D691CD4A5B431C6C476C9872209210DC8961BE02D94A72313B605E15200814C5695D6BBE2B48D4278A8F6C578531B76E9B62BC29B420938AD261E9B1FA714D2F119FA462D815D63DE98A53680D0818AA6F149414EB8AAE6980D89CB99F12D5605948EC6B5CACAF12A7D6292EE77C815E245CD755888F11954D416352CE7D43ED98E5BA086B89B92F1F1CA66E5C4A5D24C146E731E4A4A57713165F8776AE56D5229B69DCDA95C218B2AB5421AA4F514CC88AA37EAE5F71D33202A8C917A2373C6BB63264103FBB06A64A78E4192610DD451A37192BE3BE2A96DC319E4E4B21A0C551714AF1B202D514C894847CBE93A87D8918158F6AB72681074A74C55894D73C636538AB16B9999559972326D1F4A4C2EE477A1AD322E393BA716F70638580EAC4664636523B286BB2341E5FD79D8F10D6B21DFFD439B1C4F39AF93F11BCC8E24F30EB0E0D435C3107E939B5C3C9E6729B293667637126A2CB5AE5A5C7502BBE5526E0FEC8BFE7183FF0059A7FE71E3FF00359794BFEE8D6999D0FA47B9D7E4FA8FBDEE79260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85EB109D5771E394B24EE19497451D3950E44B208D724C840F1CAA4DC1037B50A4378647AA4F263B7B18AC6C72E872689206EC51A2653D32F8F26B08F82E48A440FEF295E39093918D3FB23F595759AA225EA7FCAED94172E299412FD5A2223FB75F8328C9172B1CA9F48FE507E663685756D0DE5D985C90B1A13B577F7CD7648D3B4C3983F4F342F325A6BDA35B5C3DC235D7006300824FE398C767698B202C860D46692358E54A18B704E0B05BA62D35B6BD77DBA0C890C63128A79D8107964086D102AC932B00246DBB9C898ADD2296EE2B643E8C425E5BB31ED95914CE3BA167D4A2991B946108F6C431940B13BCBC049111AD32624D3E19B4ABEB13382AC2993130DD114974E3892186F8DDB6092041DCD46D8AF12E6EA4D36F1C57897091456A715E2565993615C578C2656CEA69EF8AF104EEDA4407738A6C27B132151BE295540189A62CD1023351B7D38AA24232D0914C55148DD29D31559373AEC32DB544DB9A0F8BE9C812869C7C7C874F1CAC94B6F229000395CCDA84AA68DB996A6DDCE63B7C36414CE95A577CA66E540A45792D09DEA331E6C88B41C2FCE4006E7C32B6B9448DD9259C81283A64C45AF8939FAD3715E0475DF2E0BC4135B7BD2A9566CBC49788295C6A1137DA3CA9D4612CE26D8F5F6A9044A5AAAB4DF761FD723C2CE982EA5E7AB3B105566524D796E36FC71E15A63C9F9AB6B1D47A8A5BE63FAE34B4A4DF9AE92238128592BFBB507AFE39190544695F99324B308EE25A027615FEDC8D26DE956DA8C1A8C0662D56E831A5B63BA93FC7C23A927B531A543456723C3FBD4A313F86464D8262A90ADA70462426F91693024ECB5ADCAA0929448D8733E19763906194F0879FFE736BA343F26EA571EA7A69776AE96EDFCCC54803EFCD86298797D76404BF1AE617524D2CB74BC6791D9A415AFED1CDBE290AD9D1CE24EEA7C18F419990C81C498A5AE8C06E2872EE305C7A52E058ECB5CACEEDC1FD8DFF00CE308A7FCE35FF00CE3C8F0FCB3F290FFB935AE67C3E91EE75D93EA3EF7B964983B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85BD3BEC652C938B6FEF53FD6C89641399500ABE5526E090DF3B32B11D40C8F549E4C7AFDE4E31FE397439344905217668C78E644793584C2C406BA27F9475CAE4E4637A6796B49FAFD95DBA0E455AB94D5B951E4C7EF266B5BC6B775A50D304A2CC4D7C26EBD7496194C7E97C48D5EF985931B918B23EA0FCA5FCDFD5B48BEB6B6D4EF19AD9481F131A537F139833C4EDB06601FA51E59F3FF9775DB2B764950C8CA3910457F5E53C1C2EC6192DE8D0C7672422789AA08AED91B72E050F34C84A88C74FB59025BC6ED2C8DF3F0C899354A289496A8CBD2BDB21236CF0C50922D011E390A6E314BA4B22416A634D44255246633BF638D3021033905B7F0E996C5ACA0682B5C92AC734247E18AA8337BFCF1572B74FD78B594CEDA6A0A62D914EADE652462CC325B6605462D89B4282A3BD71668EE031558ED8AB68DD3C3155772A77C9AD2989950100E56534A46707A9C84969A1254D474CA8A40DD648F5539516D8A4B350354E5126F821258048390DC0CA26DF14B638945C71E5C4D3AE463CD728B8A6358E05E4641B75DF2C70F850ADAC5B16E0660BC4D6B5C9C53C0D4FE71D2ACA2224B95A8F7FEDCB578581EB3F9B1A3DAC4FC640C4D42D3C7EFC945B2029F38F9ABF379DE597D19DD63A9E95FEB926C7906A1F99CD71EA52E9AABD4127FAE2AC557F301DE46ADD356BE3FDB8AA656BE75BD915E4B79CB2A1A36FDFEFC8C9059D7947CED24B7F18BB6661C803D7FAE455F61F973CE960B68891EE0EED5F1C559347E6182E6752B106A9C55939B95940658F8823A64486A3CD0CEF5AFC19590E4C64A2FE9B2FA4C2866EDF2C9C22E0EAA5B3E40FF9CA7F308B7D046911BFC71A9F86BF3CCEC71793D61DDF9A864E681D8FC4D527375861E975929521B91AEDE399020E26492E33A13C5B7236CB40A68B4D2CE28A4EAB9600DA0BFB03FF009C6A017FE71CBF2000E83F2DFCAA07FDC22D73363C83AFC9F51F7BDB324C1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85CD3C715A1EB94B24E228DC303B75A8C896514F44323C058D3EFCA8B70499EDCB24B5A647AA4F2492F638CAAFF91F6B2E87268925A5E07F8D2B48F63F4E6447935854B3E4B73327ED15247DD95C9C8C6FA0BF26AC66D5D2F6D22512486A287A6541C8E8C6FCFDA1A586A5710950B75093EA0ED936B32A79F192E1220A4D2A39291954A1698CD562D4A485158BB2C8A762329389CFC59DEF9E40FCD2BDD0960334F2B46E42F52694FA7313538A83B3D36A1F767917F3C6C350B782092EC06A00431A78660183B5C595F44693E60D3F558D7D39939103BF8E53214E7C260B295B66E21832303D286B94CB666775DE8488EA781A1F6C31DD944D35246EC6A23603B922992A64648A11A98B8820B569418D06B24062FABC2D683D4996887A531A6B25884B751B92C84D0F8E16050F57FB5514C285BEA57BEF8AA9B9F7F962AEE42837C5ACA2612716C8A3A17756152298B30CB2CE71C455B16C64115C28A55A9418B3470B943D0E2AE3206E877C55B57A0F7C5548CFC07C677C9B6D20649CB37C26801CACAAAC659B71D32125562DC76AEE72A2AB7983515DF2A2CA2955F3D15941F88D29944B937C1A8A4021F8CEF4CA26DF1631A9DD7A3C9D1A86B4C8C39B29724A9EEE49E3203354E58D54C4758B3D4562F5226DCB5363BE4E2B4C2A5D0754BE722494F1EF56396AD05A7C8B6654FD61CBB1EC7A64A2B4935E7E5C79767564907C4C3C324AC0F51FC93D2262CF6E7883526BB62A935B7E45D8FA9B9A927AE2ACCB4AFC83B510CCFEA705E42A323241677A0FE53E83A5C81A62A597C722AF51B0F2BE90CEA96BB1514A2F4C55153583E99708A895DF638AB2386FDFD3459051FC3034CB9A2D6E19876C8F0AF1D34D342CF1CA4F1FAA2B35D7CBAED9918A3BB81AAC9B3F327FE7257CD967AF79AEF2D74D9DA48E0E4AEAFB6E2BD33638F1BCDEA4D97C82C5D763D3B66E30C7D2EA66511000C4572DE4E24CA356D6126BFB44EF86D880C92C2CE20061E26F8C5FD757FCE3780BFF0038EFF90AA3A2FE5D79580FA349B5CCE87D21D764FA8FBDED19260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85BB6F848AE52C9904352B5F0C896514D3D7E36C77CA8B704AE3943AC9BEF91EA93C921BBFB2FF004E5D0E4D124854D2198FF94BFAF2F8F2601358471B966F18FF0086424DF8DF5BFF00CE24D8A6A7E63B9B6715564634F7198F234E544585BF9F9E5A934FD775396342055B7FBB1136B9C1F3100C614E4370B96036D06C20E54F8078D72756DB09334D247FA1C629B9EF9467C761CCC597853D827BFD3254B8B6BE642A6A141CC09E27698350F58F2A7E73EBFA4DC470CF3B988951CABE14CC49E276F872BECDF23FE7858DD476EB3DD8694815527E5ED9893839A26FA16D3F306DEFE28A55911380A28AF5FC32318A99D2723CCC6F10233A229FDAC970A0E54AEEB5C834C9030BD578C8E4C6BDF1E16A395E4DE74FCD485A64B586753DB63FD98F0B039103A66BAD7D124BCEBCBC30726C89B4F45EB1A2F2DCE2CD1092357AE2A88F888EB8AA834850D3C31605562B923BE2CE2895B86AD6BD716613AB4BB7000AF5C5B03238AF8FC3BEF4C59A651DD934DFAE2A9925C57BE2A89593E1FA314C79A065763BD726DF4A22BD7E9CACAF0AAACC13BE424BC2E6B8AFC43B6545045209AFB8BF5CA8AC50571741DAA4F5CA64DF04BE7D43802AA731E6DF148E59BD77A3FD9AD4E461CD390D04F6CCD998C291BD32C71B8D4EE6D2240640BCD5B6E3FC72617898FB58A732E4045EF962F1A51A8CB688AA88FF001D77C9C59C656C3A7748E4E6D27C35AE49938EB9A728547DC8C55522D734F520C7154FCB154C63F30B49F0C44411FED29DAB91920A5375AAF2B9553217A9ED9157A77945B99568C1E05A8D5F1C559B798AC80B713AA0E406F8ABCDE3D44F221CD181A53080E3CCA6D1EA238F5C20346495060DF999E7087CAFE5C17AB2859EED1C15AEFD08CCCC31757A89D87E54F99EE6EB5CF30EA3A93312B2B311F4939B5C50D9D266365881B52546D999195075F38DABDB5A9EC3194DA2504F60B08D8AF8F7CACE4651C4CBAC3490C071E9E190395CA8627F58BFF38EE9E9FF00CE3F7E45C7FEFBFCBDF2C2FDDA55B0CDCE23708FB83A3CC2B24BDE5EC59635BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85884F361C76CAF8536C96DC111904D6A301816424D4A58C5C075A65462CC6441C41E1560CA5C9E80654765394525D76A423B31095ECD96E336D12CA18F05E69242AC0B484107B6C733230348134E0FC0EA6849910814F964278C86F84DF60FF00CE1AFA8BE6C997890CB5427B6F98594539D8657B3DBBFE720B44F56E352AA8320526BF40CC7E2A679214FCFAD422F413895A713C4E591CAE14F6485D8351286B5CCA84C14464F40D0A20D0C709A127BE3964006F88E264377A544A16AC797E19892C81CEC008418B78D5951D6BE04662642EDF164A099E9E2EED2E565B29CA1435A1398920E58D500F50B0FCCBD6A0F4E192770F0ECBC4ED4F7DB2996CCBF3024CDED7F37358E01259E4E245363FD991B41CAA7A97E61EA7771FA705CCD461B963FD98DB0F1187DA6A375A8DFA09E4919F97DAED8DB1337D27E58965B5B3854B971D70F0DB958A7419A457ACD2AB576F0C781B78D90C37CB51F153E79122990926B15CABAECE3E9C090B6491493DCF8E282143D555F1F962C86C8859EB4A57DB1640A696D24840DF167C4C82094556B5C53E204EA09169DF14F1A3A19949FB58A414DE27523ED8F962C816DD4788A0C9B68CA165630A41EB4D8E40848CA12C9E4E3FB5F3C810CB8D086E9551AB5395485053249E694B3F2076F0CA0C911507B8526B5E998F2986E8EC954D3879295CA8FA999CA229B69D6F1CF22ABF422A708853564D4090A6616FA65804AFC5CA985C7F1107776E2353E99A8EC3240AF88C3AFC4EA181A508E8327C6BE2306BCB3672F20635EA41CB319B6DC79186DFC7292CA49A65DC2DBE284858411732558B1E95C7857C5097FE9178643C5453DF1E14F8A11BF5DFAF71E6CD13A0A2F1E87E795CC5309660CAF42B41EAA34BFBDDF6AE52649196DEDBA3AC91C6A21554A374C1E2065C69DEB17D722C9A3908269D7263763E2878E3CB28B89030DEB52C3A53261C7C99022CDF47042D34AFC238FED13964604B87972BE3AFCEAF345C799357B8D2F4F98FD4ECA80723B1AD6B4CD861C6EAB3650F99E6B7BA8AF3882BE99D9877CD9E3141D5E49A0EE2DC076006C3265C594952DA2A76CAE450236CA34DB28E591405353D7316526F8637AF68BA242630596BB6527239718BFA78FC884117E47FE4D443611F91BCBAA07B0D32DC674FA7FEEE3EE1F73CBEA3FBD97BCFDEF56CB9A5D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF858B4FB432AE36EF0D94C1F6457A77C789061488210F4C89DD81539220637E0C15E9F0B7865660C244524D756F13A52693D47F019761C6E31905B67E5ABED43F756D68EAAFB89E9B0A66C61065198B425DE8B7BA7DD4114CFD036D95640E66220BEC4FF9C378DD7CE37019830E62A335D99D8E10017D63F9B7A7A6A3AB6A7005E47D36DBE8198526DCA6DF997E77B23A6EAD25AB0E2A0D7200D38138B07922A10C33271C9AC459B79526E573E9B7602992CC6C3958B67A75E5A7308CA3A8CC493B0C692359B89375DF28C8E6C792BD9C6E26238E63C925131C00CEC5C5083B644C6D946549998D5694C1C0CB8D1B1395E31815AEF8F02F1BD5FCABE5F49D16764F8BAE3C0BC4F5AD3A16810474D94ED86A9CAC4764E919B983F7E25B814DE201A8CCD4272A93644A690F1029C8E41B0146FAD40003B0C5928B4FEF8A559273F0D4F862A9A5B5DD286B8109DC57CA08DF0B105358F50403ED7CF16C051297B08228F8B3051E9A8A01B3F4E98B3B6CEAC4FED64896622B7F4913DF205988A067BD249F8B204B608A0FEB47725B6CAA6526282B8BC201A1CC599445269AF5FB5731E4DBD17DAFA93480F63928868996716303222B74DB2E1071AF74EA3770295230F84B6A53B32AF23BD71F097898EDED5C1F871F096D8D4F0121885EBD72CC71A6C81B63B77A6990310BB9AE5CDAC12FF4AB80CDC50D0F4C558EC9A3DE3BEC877F6C551B65A2DE8956B1B52BB653910636F54D134C962319910E6290D9183D46C42C7C05295DE980067253D7A655B76DFB665422E34CBC8AE2ED959C0FB3FCD968838939879279F7CD7E8594D630B9591C1008F7AE5F8E0E1E49BE6986D2E66B998CE4C8EC49673EF99D8F675D96492EA9A6709AA13BE65C4B8336373E9D234AD45EF84968E04759E8D2B015427299C9B61167BA2E84EAF1931F5CC6939110F67D1F4BE318F87B65326F8BFA35FC955E1F937F94A9FCBE4CD047DDA7419D5E9BFBA87B87DCF29A9FEF67EF3F7BD372E69762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF855B670AC2A330CB984B2785D5A23C4EE46C300938D3C8037146EC0D640A57B1EA73271C6DC59E7013FD17CBB7FAEB98A106353D588EB9991D3B85A8D50112F59D1BF2CACE1557BF01993724E5F8F03A39768B3EB2B0D26C08B45317A454D401F16C3C732BC3D971F68BE7EFCC1D3E117D1DCDBB5631C8041D7BE60E78D3B9D2EB789F437FCE1B5928F37DC48C4A6FCAADEDDB35595DFE973F117D6DE76B8853CCBA848F19742AC38FDD98530EC4EEFCF4FCE7D0AE26D50DF5BC263889E5D3AF4DB292D5283C3230655657431B275AF7CB612A6A31A651E578C9BE1C5A94A65933619E30F7148792460EFB653273F1AF4B1ABB029C89E87C3289B9B16EDB4CFF004A3F0F5F6CC7924A3C6845A6E741D7A530C5814DA3F2DB4D4A2D3DE99246E9B59F955DAE230141A7B62BBBD7748D35ACA255DABE00615B2C9238C83C9969ED95973709D912B1FC4081F31912E48298C7C788D8E552660A2D08A743EF90660AA7A95D80E9D31656EE05BF6A98A6D772A7C35E9B62B6898A4E3D4D7145A244DDF9D315B442DD11D1B1640A3E1B84A8AB6F8B65A6D1DC42109A9E98B3077524BA534DFE5809724144FAE0A9A1A6DB6449660A02595BFDF832A25B0150FAD71DB9572B994CCEC8692E958D28731A4D112BE38BD42083D7B656D97B325D36D5415240F965D8E2D332CC15408C00287C732E107189B2B7E207ED5465BC010A95E638B0AE3C0150B2DB07E8B8F00543A699CF9D453C32328D3762431D138B54D18785320DE8693CBF0CE45502D3C7156E2F295B83560A47CB154CE0F2E598707D351C4F865536704CA6D16085032D001945365A47724C33A90A7805EA3C7271834E4C94C63CC5A8C0B6EDC9E840DF3371E375B9333C3755D61A4574B67F1ABE640C4E064CFBBC875ED367D4A61297F881DC9C988538F3C96A56DA488630CD1737237232D8871A52B492FF00449A798BAC3B78658254D2425FFE1E666DE2A1F9644CD90C6C86C3CBDC40AC5DBC321C4D831B38D3F468D387EEF7A6F9592D822CEAD2C5234038819596603F7D7F27871FCA4FCAD5F0F286883FE9C21CEAB4FF00DD47DC3EE792D4FF007B3F79FBDE8D9734BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF84F5A9238F5CAA50699EA135805C2D19413C7A0F1CA841D7E5D4BD77C9FE4C9F5955BAB9531A36FB8A7F0CDAE9B15BABCBABA7B25BC363E568B8428AD2D3E13B75CDC474FE975F9B54642929D43CD1733551578D7C3251C4EA660B1C79EEA4E530908600D30CE1B231715A437D65F5A82269F76DFAE6A75317A5D04097D2BFF38A5603FC513C69B50F519A5C8F59A4818BDF3F32C8B6D7EE550D4EF503E8CC4C8EDA06DE35E6CD274ED634C8E1745F5C2F2DC6FDB31645BC45F0F79C3499F4CD4E482088842DD40C6326A9C55BCB703DBDDC25B66722B97036C22FA334EB45963889EE06093998D91DB69F1FA87E1AE5191CD8F245DB5845F5ADD46512E6929EC1A746D253877F0C8DD2631B66365A3C2101283071B2E0641A7E9B6AB2F22A0536C7897813496D944AA517E11D71E35E0463C28C415E94186DB63B2E580602DA0AA88B88F6F0CAA4DA0B74A641902A65A84D3164D09A9D7155F50686BD77C55DCC0DB90C554DA6A54F2C516A26EE9D1B16C06D552F883F6B0330518BA937F37E3859834AE97F4FDACAC96C1345AEA15523976C812CC4D4DAF474E5BE544B671A88B82CD4E5D72124CA7B2AAB0E42A7BE504B18B23B331FC3B8C039B6B27B39A35A6F9978A2D190A73F5D8F8D2BBF6CCBAA71495CB728DB636BC4ACB301B8F9636BC498DB3ABF518DAF126255154103AE4265C8C25AA467ED0CADC97048491B0C5556910EE31550692256A823DF2B9ADD216EEF23E34AE5643194D846AFA82420B33058E952C72EC637703365781F99FCDF662678397A8A4D0919B2C7074D9B3BCEE7D5EC0C9584D10EFF004E6588389E2DAFB7F4AF4811906B80C11C68897479C39A3D01E8BE19514A9FE8B71F69B204A695974DA007803EF4CA8C9CA84764C6DED78EDC0636CF85905B45180BF08069BE368213650028A0FA3157EEEFE50FFE4A6FCAFF00FC04B44FFA80873A8D3FF771F70FB9E4753FDECFFAC7EF7A265CD0EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85F8ECA6827585979C84FD919084FC474B9674F6CF29F906F35036D773218A18D833A95FB437DB719B1C3A1E274FA8D43DA2E0C763686D6D2216DC06CE3BE6D30E8F81D5CF2F11610F34D76CEB212EC8767CCC3300535006ED2AB986E56455F4CB03FB54CC7F1699CB7539675B32AB335030DEBB532B9E76EC1877633ABEBD05BC4817E3095DEBE39AFCDEA7A8D0E301F49FFCE3379B34BD275C3753CAABF58466DC81C4F875CD5E6C342DE931914F72F3ADEC17BACC9A94171F5A4B9DFD21FB35CD7CE36E44254F2DD5E40F74AC253188D3E28FDB31A78CB951C8F3BD4BCA69E67B826C23334CBD471FEC395F0D322049E6DA8F93752D03518E4BC89E28D5BEC95207DF4C2254C6389EA9A33F3B58E48979851B8C4CDC884699569EEACE6BD5FF000CA652722324EBD158255940E61BB6545927D6AB1D43EDBEE47865728DB644D32A8A7884600F0C1C0CC4ADAFAC952283BE3C0DD18DB27B39964B73CA3DE9F6B1E06C186DD1A90A6A77A9C9C62D528515707AED84848D950380A2A37CAA41902A4CC7B0FA3214CC490EC549353438190921A42AB53CB14F1297390814AD3B62B6A2C66F7EB8ADA8BCAE2B5E98AD201E46AFDBA62C97FAE07FBB2A7BE2CB89DF5C03ABD0F8E02CB8DB5BFE34F8ABF4E506569051B1DF7203E2C896C89561755FDBC8D3305556E7810FCAB4ED8382D24A252ECBB57A7D39138523252716B7C626525B901DB11869978CC9ACEFD64A7C5C72F87A5AE53B4DE394935E5B53AE5BC77B35108B8EE82903957DF229114CEDEE62E5566E43C3DF1663127705DC0A2B8B3181305D460208A74F7C05B618F854A4BF87C46001B2D06DA8C6BBF2FA3088ADA1A4D622029CFF001C9702DA17F4AC4C681BE23D05729CB1A5AB405CDD731BBF0F01918C2DC7C9B3C4BF35FCCF268FA60B6B78DEE2F27158E34AF434DEA332F1E3751A8C8AFF00959F947A8F9D3433AAEA90B5BFAA2A3983B75F119B1C717499A565BD67FE71E6F9B549EC74CD4B9F04E6005EE7B74CCC842C38E254C2A7FCA7F39795E57730C9731C7D5829FE991941B23240C3785A76B4BD06DEE22DA507B6634E0E4455269E35902A2FAA9DE40731CC5B8056F5410027D9FD939518B9319505E8CE36AE222C84938B13CC8A8E9D708091BA7885760570A781FBABF947FF0092A3F2C7FF00013D17FEA061CE9F4FFDDC7DC3EE78DD57F7D3FEB1FBDE8797343B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8D2F23F91A57BA4BFD6D6BC0D68D99B874D4F199B556F6FBFF00315959471D8E9F1AA0A7024019B9C18F85D466CD6C59E49EF25615E4332A52A0D50DCB2DF2D6856B70C52551CE43DF31324DCEC38B88D3D353C81A7CB0F32AB551E03FA663193B0FCA3E7DFCCDF2B2E9FEABC7B2C7E1F4E53293938B4F4F9C6F56297D485DF7198E64EDB4F0E146E83AFDC797196E2DE46AA9A00091D7E9CC6CDB876719D3DDBCB3F9BD24F2C31DE0DA94AB1FEA7308C1B0667B4D94D69ACB0BD12208D97E3151D3289636F8657A07911B4F7D723B3D2E146909A39DB7CC738DBE395EB1F997F96F6BAE687305B355D42DA332D55454D47B0C8F03938A76F86AD6E6EFCB17173A65F42C9F1955E429DF0183920B2BB7BC4616F2C5B16DDC65660CC165F14EB3463B9032071B30532B566E2C3B83B65538D1499526D019BBD6990E16719A6917C5DBA63C2DF19A6D6F7CB1008C7E8C785BE395344BA420107AE061396E881329C892A0DAD663C8D0ED9592CC054571DF2BB6C017F2B7FDA1BF7C2A8599ADE876DBBE2A82372A361D3A0C5541AE7155295D4AD477C52934EC6BB6D8AA0C87F138AA8307DB7380A43AAD502BB7865062DA0A3E1269D7A60A6C0510A5BF98E34D80ABA3316515F98C69369846687AE16B4C2075322A96D8F7C55328A7F498156AD31564767AA23108EDDB08544B5EC55DA4FC724C81444378A5A9EA7BF5C2CC14C92F401F6F6F9E06C1277E9458EB593AEC37C84CB6715A849AC27412F4F7C8829421D6A25AF292BE1BE580AA026D6226DC3FE39602A841AA52B2C64B329A0032AC82DC5CF9B81E8FA0797EFF00CC36DF582AC8AA3AD30C62E064D45B23D2FF002E746D666FABEB1682EAEE27FDDB915A27874CCCC61C0CB2B7BEC5E5C8B43F2FBD969AA96E889B050053F01997034E0CE16C3BC93A446D35E6A37975CAECB32853E03A665C25B38C63BA6F3C3CEDB526BEB5496201B83151EFED82526710F942FF00F2B62F34EABAAEA1631FA2F393450294A57DB31E45C8807897983488FC97713E9FA8CA1A624844277CA0B7C52BB760F0C4E05030A819590C81A45AF5C14CC14D74F6F888F0C7859829D237C58D3305FBB9F945FF0092A3F2C3FF00012D17FEA021CE9F4FFDDC7DC3EE78DD57F7D3FEB1FBDE8796B43B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF911B5D4CA4450905BBAE74F1C603E6D3B48AE67FACCEA900FDE16A6D9682038A626D9EF97B49957795D99CFEC9195CE6E660C6F47B1B58EC87AAF540BB961D4661CE4EE74B87D4191C5AFAAC65616692836E5B65066EFC600F1FF3E4D71AB45708F1045607E21F4E5329B64703E3BD62C6EECB539792FEE8B1F88FCF31CCDB04292D9AE9C158E18C484915AE57C56C8DA31A49596358E416F21EA54E44840059C68FE69D574B44824D51BD24151F16E7D8E63C837C6DEEDF96BF9A30697AC437F733A5B98C8A9E5D7E798F272216FBDBC9DF9E9E4FD7AF7EAF7B7111F56309212474C003978362F14FCFAD33C9F3EA31DFE8572B34929E46314A54D7C301736DE23636377C39471820F5F6C8101B0499559B2DBA8F59E847619590CC14FAC751B37996105CB374DB6CA671B613932D59618940988453D0F7C8F0A04D136CD6F2352390BA9FDA1BEFE18385B064A593E9D74D30689498C9DD8E3C2CC66461E76A80354A81BB65538EE9F15B87528DDB846416F0272B316C8E54DE3BC454025A06EF4CACC5C98E45296FE05DD4B37B5321C0DE24BA2BC570095007BF5C8B0326E59EDE9BB004E28B4B5E48F7A1A8C56D41A44DF7C56D45A4DB167C482797AEC315E24135C76A62BC4A06E0D7A75C4A89287AB43D72921B414545734A53E9C785B01B45ADC8F1C785982AE2E42D0D7A74C14C89D95D2EEA2B5DF035DAAADD92C17953DF15B4CE0BB006EDCBDF15B44BCE78F247A3FB6109050E2EEE01FB44FD392664A69697B329A93DB147123FF4A3014240FA71533A434FA846D148EF394310AA81DF018DB28654A6E3518B9DBAC324B2198D1CD3A60106CF142A299A4BC92D622F2040086237DF2622BE28651A77947CC5A9C4F35BD83945E8C4102996082F881EB3E4EFCA9BD9D44FA8388EA7918FE5898BAAD7E4DDF4559E9967A26872A40024C828A0EC09C9083AFE3280F24DBDEACF7535F5BA2C8EC5A075DFE1DE997C4522ED966AD33DA5A4934D2963312A213D299785E152D23CBF696D62D3ABB191FF007A2BDCB76CB449A670DD4BCD4C2CF402DC4249715529F3DAB80C944698D7953405B5B06BB9A61140D1C923CDFB5D2BD32B25980FCBFF003D4B379FFF003D6EF4486FCC7A769D39ACAA7ED509EB9021982FA1F54FC9D96DF4DB7BFD27525BB9258C39B52C28BB0D85322907778AEA52AE8F70D677C443780D046761F7E2C814CEC599516534A30AEDD30365A6515E425FE26A7B61676FDE9FCA021BF297F2B997756F28E8841F63610E74783FBB8FB87DCF21A9FEF67FD63F7BD172D68762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8EF578F9B5C06FDDBF4CE9B8DE267A6651E54D1967BAFADC9BA72AAE552C8E29C1BBD62DE25826E4AB45AE56656E6E0C28FB8B9068427241F697C72B9F276F871F0EE94C97B4256184257314C9D96395B10D522BB9CC8D23058687965129399116F07F30E857BACDF35B58446572D4F8728949651A4E34BFC8DF335FC6918B3912693756A76FBF2B126118D966FA67FCE2079E3569D2425E28DBA7F9F2C4C9C918596BFF00CE13F9AA29D1E5BD255853896E9FF0D944A4DD0C4CC2CBFE706B5A9E359DB5858C2EECBCFF00E6ECA2526F8E265563FF0038CDA7E8171691DF7994594A8F4F50494E4476EB91126D11E17A95A7E487956EAE62177E6E597881D6407F8E032660A7179F957E4CD35D2DE1F32C444A28C798DA995993602A69F929E539E932F9A6293BF0120C812D82491F987F2C348D2EDBEB1A7EAA048836F886E7EFC46ED3964C33FE55FF009A2FECCDDDAAFD7517A01BFF001C970B57131F6D13CF3A6481DB4B6B5B68FED02A454F8E3C28F11136DE77BCB598417D6E4229A31A634BE2338B4D6B48D6A25442179EC6BE380C2D81CD45BBAF28385F5EC65A93B8A1C81C6DF0CC92CBA4EB91A13E9B3D3BE40E37331E54BCCDA9DAB7EF6D0923DB2BF0DCA8CD53F48A85E722346C7ED2F8661CC516CBB516D4ED5BED311F3C82AFFAEC741C5B63D3E58AA8B5E27F362AA2FA82F4AEC3BE2D96817BF5AF5DBBE29B59F5A88FED62B6DFAF19EF8A82A2648EBF6BAE45B42BC6CB4FB5BE1640AB2B8DB7C0D815B92D3AD70164AD1B0A75CA9AD7F2DC50EF8551D0135A5715477A8513956BBD310CA3CD6FD61BAD324CCA9BDF49F663EB8B548A3ED2C750BFA705635F0C5ACC99E795BF2D359D7F538AD591845506507C0FD396E38DB0964A7D476DF933A0D959033C4867812AEC7B6DF3CBBC363E2A47A4F937C9BA5DEDDEABA95DC29145BF027AF1FF006B2C18D7C5629E7CFF009C98F23796F4ABBD13CB56714B76A0A0950577029E1ED93F0D7C57937E5BFE746B779ACC375AC4AD0E9CC4B70EDC6BF2C84E14E3E63C6FAAB53FCD9F25F9AEDA0D1F43981BDA8590AF5AF7ED80069E07B5E83A3AD8E9B6019FD4927456E47B03DB260278588F9D0BDE6AB67A65BF660580C902ACD043E8C3A7C1D2A02B8F96264C4861FF00987FE997DA7E996FD178F35191E2470A335A8DA0F265F5869B66D3EA4B6CCA0815DD908C921F9C3F96FE439FCB3E7ED77CC1E77D224852EE6768DCA6F424FB9C3487D831793349D5EC21D5BCBBADB441E3E6D64ED4E1ED4C348B7E587FCE45F9ADF47F3B0D3667A346FC5A64F6A60E1660A1FCA5F98F1DD086D6693F771A84563DC78E34D80D3DA2CEEF4FBD50F1CC391F7C69982FE81FF26E83F287F2A829A81E4FD0E87DBF47C19D061FEEE3EE0F25A9FEF67EF3F7BD232C69762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8BED12FA6D457F46FA12ADBC7F626A7C47E6736E72BCD5193DAFCA1772C114D67796EF4894FD51E31D5BB72F6C899A63A6B6609AB5DA32C37B6E2DD587C2E452BF2C78DCDC5A4012093CFBA5D95C5C4123AA9B7157693A7EAC13C9B39630D30CD5FF003318397B28A39E2ECD18AFF0CC4326D863A62B73E79D575085C4517A61F6F886DFAB29949CC807D51FF38D7F96B36BF24BE60D7A33C62F8E30BF64F43BEF98F29378C40BEE7D22C74E69E9269D0C76D07C10CB1AD18BF45AFB655C4CBC1E1DD9E8BFB58ED1ED0C421BF857933462881478E266DF8E16F93FCD9F9B3A89F3543E5DD06E92E5E7904370EC6BC2BD48DB2894DCD86114C9FCEFA4EB5E4DF2D0D6EE7CD33CD77749CA3B3864DAA7B5331A536C38E9E45E5CFCBEF30F9C746D43CE7E64D66E20B0B2532DB425E858FB0C89C94C463B64BF967F973179E359223BABDB6D26DEBEBDD31A6CBE06A32072527C17977E75585B796FCC53E81E54B9BBD4A68BE15773C8F2DC640E56DC7A7B286FCAFF002B79ECCC351D62C6F9A0421B801F0F1EB959CAEC31767F13E9997F303F2DADECC68BE67D3A6B4BB20707028DB6C4E1198863A8ECDA28BB3F307935EDBD0F2EEBB25AA1FB2B2BD313A92D3FC9A82D7B509BF41DC2C9AADB5F475256456ABFCB251CE4B4E4ECFE17805ADC68374F7306A7693F224F0940D8E644276EB3361314A5FCB71DB96BED36F0C31F22521734232F0C2386C59661A17994D9010DE5D212BB75C90882931A7AE681AF68FAB442DD6E22172B5E418ED919419C7210C953CBDA4EA2A566A7ADFB253ECE63CB6726398B18D47F2CE695A4789223131AA377A7DF98192365CC86434C1755FCB7B8B552CB1866F0EDFAF2A316CE379BDEE87A8DB170B6D29E269D36FA3234C81481A3BD462258245A7B645210F34BE98F8C1030B7525C6F2035058838B3115212F03591CFB53148802A6DA8C6845198E2C8E20022A1BB59A95241F6C5AC48A3967229C6B4F138B30510B73D37E98B74510B703ECD7AE03BA65B045070AB50D91E171BC42AA92EC64AEEB9131489A36DAEC3380DB0F118084892266BD759111006889DEBD71886C81DD1F0992E18C50C4657A7C210572CE16D243D3BC97F957AF798E482792310C524A1645E8426FBF5EB8F0B8D393EB1D1FF002374CD2AD24B8FACC8B2409CBF7A76247D38F0B8D29A0B4DF33689E5E3793CF730C571A7D79F134A8197618B10789E11F993FF003955A5E97697F6FA0A9BABC98323B49BA8EA36F87325AE669F188F3B7E6079FAF9ADAD2F561B59FD46B94534201A9006C3C70DB8E7290C5B4AD3E1D275392DB592F717334A03C8FBF53DB27C69194BEACF2AF93E2D6E1161A2A492974A3B36FC411DB2B99B6C8CDED5F941F9172796BCC4FA84AD2CE8CFCA6F537E277E9BE56CF8EDF74C691C2A8109E1025501F6C3652082F3BB1AEA1E6A7BCA739223C78FECED8DA683D06F1115A198578A312DEC72F8C0485A90180C006AFE6C9243F14708DA982500189A66B1C4F1488518AA4B5E5F25CAA52A6069E4DE67B48BCC7E67B6D2DADD25B585C7AEC07C54077CABC621AF64279ABF2B6EF4DD2B5AD5741BE6B484216823534A0A0EBBE4865B6C1005F879F9B02E6E7CD9A80D61E3BA9E1958073B9DB26269E00F3089B568627BAD3D12358E4A1E636E3ED960368D83D2B43F3C4F63259C11C9CE5968272DF641EF4DB274178807F551F9093B5D7E45FE4BDD350B5CF913CB92B11D2AFA65BB7F1CDEE1FA23EE0F2DA8DF2CBDE7EF7ACE58D2EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF90FF00CB7F20CFABEB70F9784FE9BBB0569CD76FA727E3B8A3474FD1DD03F23BF2F3C93A589BCC5E60B79AEDE3E4119F707EFF007C7C76C8E969F1C7FCE4679DBCA97925BE9BE5331C6DA651649E3E8DC698F8EDF1C34F985743D435AB73A95C5AB244568B514F57DBDF01CEC8E34D74AFCB3F36EB344B1B65B6B63FB4C074FBF29395022CB74FFC91D5CEA169646F0CB792B82B02D6868457299657271C5FAB7F90DF96FA8695E588AC2E2331968C027E81941CAE6460F7693CA361A1E8F705C896E5DC145EFCBB1CA8E46E10BD9F397E76FE60587923CA7269D6404DE66D67F72186EC81E9BE0395C8861A60BF911F93BA0E956D75E74F38EA0B3DC5CC06ED8B36E8C6BB75CC79657371E36216F637DF9B9F9A52D868F792CBE5AD35E9287354A2FDDE198F2CACE589ED7E70F2C5C6B0963E42F2E5C1B68B4F939DEBC6688E0F63959CAD4715259E7AF3EE89F933F97B37956C5565F325C2141243F6F930237A57227236E3C5C4F19FC99FC9EF3579E357B2F3B7982E85BDACF299409BAB2F20DEDE390395DBE97476FA57F323F30348FCBD8C68F62F6D3B88F837115DC0A7BF8656723D0E9B40F813CDFACB79A75A6BE9E0145242328E80E0F11CC9F65F131F9AC2248F925F4B6EDE08D4C81CAC4F6481D1434AB8BFB2BB8A73AACD71A746F59A177AD4F7C9C32BAFD4F66D07D412F9D7C87AC79623B2D3ECA38F5644A34B415E599B8F23CE6A7414F0F3A6EAF7777248B3B95AD16253B53E599D8E6E8F2E1E03499E9BE5C56BD53AB192DE2247276DB2F127127165D7FA0E8F0317F2EEA85EF1002C8ADB93E18CA4D6229B7953F33A6D26F5346D6AD65424F1FACB0FA3AD330E72722117D2D63AAD9DEDB42F6B79CD5D4155AE634B9B971E48AF5AD89E372BCD7C72B219A1DACF4FB9E4A6C57813B371EA3C72B21B2293DE792B49BB25BD08D49F6FEDC810CC3CE75CFCAFB296390C4A2B534A7FB78B787916A1F965240EFC54D05698B6061D7DE50D42353FBB240E9F462CC31B974CB8B7E4B25B9AF8D31672E4848D2584EE87171AB74D61B9A8E25295D89C5B150951DF1640B4B28A80A773DB14CCEC9AC658A0DF22E2A3ED62326C7A1AE34B68D58A15824653F18E831E15B645E43F296A9E67D5E1B75899A194D2B966385948C9C2FB83CAFF0092FA779295353D5A2170654E410EF4AFD3991E1A0E77A4E82DA4699F5ED6AE255B3D3ADE3630C55A55C7418F86D32CCF3DD5BF33AE7CE574749D20496F6ECDE9B4E36047CE98F84E34B23CEBCF1A3792FCA7A1EA926BBAA97BEBD80FA4BCF7E743D725185328647E5DEBFA8C32EA57C2CE212DA991B8B91534AE4A98E4928F9735ABDD1EF0DD69B251CAB7A918F9634E29927A350BBF32B5ACB1DBB3DFB5C207A0DFED634CA2FD64FC8CF29C1E5EF2B0D66F63A5CC9081F17662A3010D8F77F23D85DCB6FA9DE5CC815667261AF8646922D3CD6EEC69D62189A168F8D7DF1A6C8DA43E4EB4FAB9B9D4661B4D5E24FBE34CF74E755BCFABE8B3C8C68ECEDC7E9E9878E934520F29DB1B2824D4E71BDC92149F7CAE5918905956A139B4B19A73B7D514927FD615CA253B6B312C23C8F6AD35FDFEB972B54B824424FBE5129313128BFCC0FD23079435716F2B969636A460F4DB2D8DD391189E17E06F9FFCB7AE0F34EA9A85FD94CD01998F220D2996C4B0902C7749D26F7CCD7834686136494AA9229C865824E348909B47E4F86CB506D288E57711A09325C6E399C83FAA2FF9C7E80DB7E437E495B375B7F20F96E33F34D2ED87F0CE9307F771F70FB9D2E5DE67DE5EBB96B0762AEC55D8AAC7DC7D38AA9D0E2AEA1C55D438ABA8715750E2AEA1C55D438AAFC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF233CB9FF0038C3E4DF2ADCBEB13B133D0B1911C0CC3B2E7ECFCE5FF9C95D5A6B1F346A1A7E95AB4E6C625612C5CC96E229B03DB1B29A0F89DEDDEF00926B97974FF5394909AFAA47BB63653C2FA87CC9AF797F56F2279774DD25D34B4D3A86707FBD6A0A751BE365061B337FC8DF2C5E79C752B7D26D6F2E0CAEEA11B937122A32B258460FD2CD3FF27FCBDE569F47B4B9B432EAF28065BC6DF8F427299172618DF40456B6BA6D9C16FA4C4102A51E4661D69EE72891A732106272C4F737978F79C94DADBC970B272AA1F4C578D077395D972B1E3DDF9E76B6317E6E7E6FDCDAEA08F69636B318F8CA7ED509FB35F96425272B829F42FE69F927CBDF977E4FBCB5B1FAE896F63315A4924C4A7A8694A0F0DF28916D8079F7E5DDB5EF907C986636E96B7BAC9ACD7DC6878B03D0E512939118A6307E6459E97A6DCD968086FF00CD3316F4EE07C67936DBD2A72B2594B0DBCCBCB9F94BE65F327999FCDDE78B1B8BA4327A932C95E0141AEC08DB2264E4E9F4FBBD4FCFBF9ABE57F2AE8F0E81E52E7677F0A18E242F550D420EC32B26DE8F498007C75AEDF5D6B378B7DADDCB4D7B292CBBEDD7C32B327A0C31012DFADC21FEAF343EABAED118C5283DF07139825174B3C0842B583B13D2B91254CE285BAB580C5EAADAB41714FB1FB253C699289759AA31AD93BF21FE5BF997CF5AA25B7942D9E390B52E6465257DE9B6676393CB6AA9FA0BF97DFF0038C4BE5FB186E7CD3299AF1497996BFC33618E5B3CA6B620CB646F9AFF0025F45F3497D3AC6330A8F843A6C7C3AE64893AE9C5E7FE59FF009C4B6F2E6BEFA88BA9E78B90608EE5878F4C12935883D1FCE5F91FA16B366919822B5BC450A27550A6B4CC49CB7722317CD97FE5DF30FE5DDECA90C72EAB696CD44F4EA683000D8F40F2E79AEC35E884733AD9DD746B7907C55FA7010CD983EA0F1AFA3C1404F85180EB9590D812B7FADCADCBD6F84F4036C810C834F248AB406BDB7CADBD21BA53293CD41C5B42552E936F221AA038B20C2B54F2BC3217A44BB83DB16C3BBCCF54F2A4B17F751803E58B5F0B13B9D1E5B706AB4FA314243346F1FDA53BF4C50A5146DC838041076C0589927F096E03236C0A6F6C582FC3D7FCEB931BB548A3A0D2A6BABC820B40CC2660251D7AE5A22D7C4FD0BFC98F24E95A1E9D6B7A2D985F08F90673515A7865F8A3BB4CF23D4FCD9E6780AC36D247CE78E3ACC3F6683AED99341C7F11F21DDF9E17CF3E61BCF275ADF243A7D94865BB8D0856A0EA2B5F6C691E25BD5935BFCBEF2569062B7A34F0A7266EADCBFD6C683025F9C1F9BBF987A879ABCC37C25AAE903E1B5727627C0602144A9E07E85AB1755670AC4D77C1C2C2791D64B67A6DC898BB2CBB8849355DFAD463C2D5C56FA7FF00203CAB16AFAF433BBC73C664570817DC1C785BE127EA25D4634ED0934E0BC04DC5828DBA0ED9121CDC401E6CF7CB6D0268F089CBAB2814A1A7DF829BC4425FE6C65BF8AD6D636E3561C877E38D331009F689666F74B92DE195614B215766F6C69B0462C1FCF9AFE876D2C3A341AA4308545370ECC0EE7AF7CC79C776C1008D7F39FE5FDA687656D77E64B5630D0944700D7DF7CACC14C22C4BCD5F9C5E4792D27B1D3F5980FD6C2ADC55813F08A0A6FB640E32D6718653E49F37F93EEB4286C1756817D221A3F8C035EBBEF90F08B0F0C273AE79A34C3A7CF099619CCBB2B5410C3DB7CC8863A0E44202980CDF92FE44F3BE963EBBA72FD6AF3ED3A902B5C3C0C258C3E78F3E7FCE23685A523EB9E5EBAFAB6A963FBB823076A2F4040EB83869C69E10F9423FC92F3C4BE66FAC49A6CB33C8D46B8553C4FE18971CE9EDFD0E7E5058CFA67E52FE5769B72A52E74EF28E896D7087A8786C21461F78CE9F4FFDD47DC3EE797D40AC921E67EF7A2E5CD4EC55D8ABB1568FBE2AD547862AEA8F0C55D51E18ABAA3C3157547862AEA8F0C55D51E18AADC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF30EE7FE3932FFBDDF60FF7998EE4BF25BF357FE537D53FE39BFB5FEF6F5EDD716D0F1497FDDBFF001C5EA7FB9E98B745253FDFDAFF00BC7FDE0FEFBFB9EBDF23264793F4DFFE7143FE3BBA67FC707A2FFBC7FDE74194B18BF42B56FF0094853EC7D8FF0077F5E9FB194CDCA83C8BCEFF0061BFE521FB5FF1E7F63A9E9ED98F272E09DF927FDE49BEDFFBCB27FBDFFDEFFB2FE3953938DF1A59FF00E4EBB4FB1FEF50FF00783FBAEA7EDE464DF27D01FF00395FFF001CEF2EFDAFEF63FF008C1DBAFBE53258F3625F985FF92AB47EBFDCAFFBCDF6BA663C9CDC6F00FF009C69FF0094FA7FEE7ED0FF008EAFCFB65679B9717EA37997FE51BD43FDE3FF00799BFDE4E9F64F4C94F936E93EB7E3179D7FE531BAEBFEF43FF7DFEB9E998E5E9B4FC921BDFF008EDDB74E9FEEEFB1959E4EC23C936D3BFE3A375FEF1FDB1D3E5DB029F8ABEB3FDF27D8FF009E790973627E2AB17FBD717F75FDC8FF007A7EC7D39383AFD47C5FA1DFF389BD2EBFE385D0FF00BC3FDF77EB99F89E675DC8F37D49AFFF007D71FDF743F6FECE6645D066E6C5344FF7A24FEE3AFECFDBEB99117124CCAD3FBE7FB5FECFA60C9C9AC3CD3CF1F69BEDF5FF0075FD398736F8BCA74FFF00A587FBC7DFFE3A19747E9497CB7AEFFCA552FF00BCDF6FFE95B80A43D7A1FF00792DFF00BCFEEC7F7DD722DB1504FB67EDFD1959641565E9DF2A2DE12997ED606D0843F4E2C825571D5BED7D38B6B12BFF00DAFB3FECB14179F6ADF6BFDD78B51611A8F5FF00757D18B192017FBB3F67A603C9804543FDD8C805926D69DF2E8B44F9BD2FC89FF1D6B7FEEBED8FEF7E797C5A25CDFA15E5BFF8E6DA75EA9FDD7D1F865F071F27262BE69FF8EB6A5F6BFDE47EBFC32E71DF97FE4FFF00C995E66FF7BFFDEC93FBBFB7F4FF00938ABEC7BDFF00943F52FF008E77F70DFEF47F7FF47BE2AFCCCD7FFDEDBBFF007A3FBF7FB7F63FD8E1632E4C6A3FB4DF6FE8C0D3245C3FDD5C74EDFDEF5FF638583EDFFF009C50FF008E9C5FDCFDA5FB5D7A8C0E4C1FA41E6DFEFB48FB3FDCF7FB3909399064D63FF1CF8BFBBE9FB3D320DC3E2C67CC5FF1D0B0FB7F647F77FC71671F8A62DFF28CEB5FEF67F74DFEF07F7BF4E167F37E67FE65FF00C746F7FE526E9FEEDFB5903CDBA3F178737D97FF008EDFFCF6EB8127E2952FF7FF00F4B5EBDFAE2D72F8BD3FCA9F6D7FE526E9FF001EFF006708607E2FA3EDBFDE1D1FFE523E8BFDFF004FF65930DD1E5D5F5BF977FDE0D27FDEFF00B2BFDD7DAFA72054A7FE6EFF007960FF007B3A8EBF47DAC816324FB4DFF8E7D97FC733A0FB5FDEF4EF902C1F62796FFE51ED07ECFF00C73AD7ECFD9FEE57A7B674DA7FEEE3EE1F73C7EABFBD9FF58FDE9D65AD0EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD9, '1', '2021-03-13 12:45:48', '1', '2021-03-13 12:45:48', b'0');
  149 +INSERT INTO `inf_file` VALUES ('8448cada8c714e4ab61f521c8da21990', 'jpg', 0xFFD8FFE10DFA4578696600004D4D002A000000080007011200030000000100010000011A00050000000100000062011B0005000000010000006A012800030000000100020000013100020000001F000000720132000200000014000000918769000400000001000000A8000000D4000AFC8000002710000AFC800000271041646F62652050686F746F73686F702032312E30202857696E646F77732900323032303A30343A30322031373A32343A3135000000000003A001000300000001FFFF0000A00200040000000100000320A003000400000001000001C20000000000000006010300030000000100060000011A00050000000100000122011B0005000000010000012A012800030000000100020000020100040000000100000132020200040000000100000CC00000000000000048000000010000004800000001FFD8FFED000C41646F62655F434D0002FFEE000E41646F626500648000000001FFDB0084000C08080809080C09090C110B0A0B11150F0C0C0F1518131315131318110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C010D0B0B0D0E0D100E0E10140E0E0E14140E0E0E0E14110C0C0C0C0C11110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108005A00A003012200021101031101FFDD0004000AFFC4013F0000010501010101010100000000000000030001020405060708090A0B0100010501010101010100000000000000010002030405060708090A0B1000010401030204020507060805030C33010002110304211231054151611322718132061491A1B14223241552C16233347282D14307259253F0E1F163733516A2B283264493546445C2A3743617D255E265F2B384C3D375E3F3462794A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F637475767778797A7B7C7D7E7F711000202010204040304050607070605350100021103213112044151617122130532819114A1B14223C152D1F0332462E1728292435315637334F1250616A2B283072635C2D2449354A317644555367465E2F2B384C3D375E3F34694A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F62737475767778797A7B7C7FFDA000C03010002110311003F00F544924925293A64E929F18FADE19FF3ABAA48DC4DEDE49FF454ACD369FB3380796ED036EA74F26A9FD78C97B3EB8F55606C8F581FFC0A958D6E43DC037807B28C86505BB87D62EE9F91F68AEC7BEE6B5CC6BDC6480F11A4A1FA7D77AB07DD8F8F93934564FAAF631CEADB03D477AD77F315ED67BFF48F540820C1D7CD751F55053FB1FAB6EA8E4BFD3DA69AF09B90F26CBB0598CCFB45EFF45EFBED67E830BD1B1FFA1B327DFE95753D002D0644079DB3A5755AB26AC4B316DAF26FD68ADE20D83FE05C7F4767F61FF4FF0047FCE223BA3758AADF4DF876B2D01C4B4B44B431AFB2DF536BBF44E6574DCEDB6FBFF4562EC7AD136756E977D8DFB3D565B6DA2CC3763D4E190FC7AB1ECC4C6C8B1EFA6DB30EDC5F4F333A8F52CFB55946162D5F6BA2947EAB4B68CAEA05D6E43AFC6C4B9B6E28A7631BA6536BEA18F5E55F6751CFC1DFD532EAF53D4F4E8C965D93956E374FFB2E3D6FA0B6DE4BA6617D6B654DCBE9D8B9FE9583755763D76ED70F169AFD962EC3A17D64EA76D96616774CCAB32714B5B9365143DEF66EFA1F6BC6637757B9BEF66CFA7FE8D65F45774BA0FD5DC3774F77AEEEA15E583F68792CF55D87898D9AF69C766E6E6BB1ECCAA719DFF69ABAECF53D3CA62E7F17071B3FA8E3518782E155F6D6D6E2073AF7866E69CAFD27A75D9FCDB6EB5FECFD13130C227AAF8CE4351B3E96329ADCE6B032C60225A2EA6DAC3B69F7B7F4F535AF757BBF495AF37EB34578DD5F3E8ADBE9D75E4581958101AD277358D6FEEED77B56C3BA8DF4F5CC91439ADAF1AFC8A716AAC06D2CA197595B71E8A2ADB4D753FD365967A6DF52EB3F4F6BEDB150FACEFF00B47557E735A5ACCA6B09932058C6B6BB5AD77F65088119505D3265004F47296AFD52FF00C55748FF00C34DFF00A97AC995ADF54BFF00155D23FF000D37FEA5EA4627DE13274C8AD524924929FFD0F544924925293A64E929F09FAEEC9FAE1D59DFF0CD1FF8152B01DCF9ADEFAF0E23EB87578ED734C7FD6A9584E1EE07B4C7CD3482B82C0CB869F246A6B0F3B5C246920F1F728B29703C401C9F056B1D90F1A73AFC934AE0750D9C3C5ADD680D6001C35811C15D0E374AC79935336EEDE06D1F4A3E971F4952E958FEF693C49D7E2B7EB969E254323AB6B18EAD46F49C7F730D4DDAFF0073840824FD29597D6FA5D54EE2D1B77341606E9A8F6ED11FC95D334FB493A203B1ABBF21B65A37067D169E1464906ED9B844855393D1FA1399563DD60DAF68690D8D23F74FEEFB5687D60E8746474DB2DA5B16D23D481DE072B535EDC4A85969D0763A1F81D101908365470C786A9F2EDC473F72D5FAA07FECAFA47FE1A67E47ACFCBA855977560406BDC00F20568FD516FF00D95F473FF7699FF52F5781D9CC23523B3EF6993A6450A49249253FFFD1F544924925293A64E929F05FAF263EBA756F036B47FE05542C62241EFBB50B63EBE83FF3C7AAB876B87FE7AA56383EE1E1FEBEE40AE4AE2E207808251702C7D9696BB9747E2546BA9CF7348D7C63556FA7623EBCA24F0D2224729922297C626DE9B0A88EC0761F2F6AD4656EDBA842C0A9A183C5690600DD79EEA06E44506ABC32B682F78682A01F48FA37327CCA3BA9A277D906741BB80AA64D9D348F4CBEA6DA4C0687B43893DB6EE4C902BC16C8C80E86348772496F1082FCEC4F53F4B686469E253E3E2399510C044F8F654EDCBE97D3AD1F6C7B2BBEC05CDDE1C4C03B67DAD7353575E9ABC8F5EA5B5758CAD9AD56BCDB518896BFDDFF00548FF545B1F5ABA47FE1A67FD4BD5BFADF6D195660E650439B657657BDA080763B737E906FD1F5551FAA766EFADDD1C0ED94CFC8E57212B01CDC91A9C878BEF8993A65231A92492494FF00FFD2F544924925293A64E929F07FAF4377D6EEADFF001EDFFCF54ACEE8F875E7754A31ED1348DCFB478B180D85BFDA5A5F5E04FD6DEAE3FE1C7FE7AA5677D5BCAAF1FAC62BEC23D379752F9FF84696367FB4992D8D2F85710BEEF656F4FC73B5B93815D41803BD7C56ECF4C1FA2DBC7E77F2DC8195D2D941DF4925BCEBE20AD5B711F71BADCCB36E331D3B0BA1A770F6EF8F759FB9B10290CB2921ED2DD7DAC773B7F35D0AB027BB7A518F64BD39C7609E56A31C0F3ACAC9A5BE9FB55EA9F1051486593D2B032B5C8C7AEE3DB7B7700818DF57FA7E3DA2DAF1A8AC8320B2B00C8F376E5A55BC10028DD76D6B9BE4A39DD32C00ECCBD4AC360113DD0ACC7ADC009DBBF50476542C3D4FD3230D958B5D1165B25AD13EF3B1BF49C9E9ABABB2E0E7BD9E8B87BE352E70FE49FA09A9156D6FAE5D2DD6FD5E7E4077AAFC1B1B7B4F70C77E86F1FE6B98FF00FADAE33EA79FFB2EE91FF8699F91CBD22EB59753762BC82CBEB7D4E1C887B4B3FEFCBCD7EA583FF3ABA313CFDA980FDCE56701B15D9A5CDC6A57FBCFD04A2A4A2AC351749249253FFFD3F544924925293A64E929F06FAF13FF003BFABFFC70FF00CF74AC0C5A9F6BEC63352C63AC81FF000637BB5FEAAE8BEB9D2FBFEB97576B4682E6973DDA35A3D3AB955FA1E1D15F556398F3634D193EA480266B737D8D4384D13D14271E211BF53B9D07EB6E364D2DC7EA4F155EC01A2D78FD1D9FBAE738FF00376AE86C6B1CCF546C1A4EF90411CFD29DABCE31F01ECC9BF19F040D58EEC44E85AB5717A65C5A186D2299135C983FC90D55E7117A3771E43C3A8D5E9F7B79699F056B1DEC70826216457B9839D111993E9EB29ACA24EDFA80409F821DF6082663B954075105B13D92AAD16BE5CE803523C5327AE8BC11BB62EEA36D5596D741B081A1710D6FDFAB952C6EABD6ACBC0BE8AABA5C61D1634B88EDB55CB286E437520055D9D3E8C571BDD74EC05D06001085689120CF2F26BC5C5BF2DE76BA8ADCE209FCE03D8CFF003F6AE2FEA5B09FAD5D1FCB25B27E4E5B3D55CECF2EA812DA9C7D4DAE05A5DFE8DFEF8DCCFCF46FAA5D2998FD7B02C277385E3F2394D8FD3E64B5739E33A6D10FB028A928AB2D35D2492494FF00FFD4F544924925293A64E929F1DFACEDFF00B24EB193635CDC4A725AD73F69D9EA3AAA6373FF003ACFE42CBC7E8D93D7F2ECCBC1B5B895E3868B6F735CC68304CB760DDF41BFA47ADEFF0018DFF8A0C4FA3FCE5DFCC7F52BFE77FEEF7FEEB7A6B56AFF00C478FE6FFA3B3E87D1FA2CFE95FCBFFB91FC8F553A5C7C236A598FDBE296F77ABCF3306FFB0FA79370BEBACFACCC86506BB1A5C1BFA11BEE6EF764B5F47E83D1DFBEEA7F3DEA66814BFD116B4E4080EC7782CB8388935FB3D6ABD467F5DEB62EFE9479FE7EFF00E6B8E723FE4EFF00CD97FA1FF805CBFE60FA1F487F3BFCDFD21FCEFF0027FD2AAD2E2BE8DE87B75BCFFABC207ED7571DCEC88143D8E71240638ED7123E9358EFE6EC43C86E5D409B68786FEF012DFF0039B2B773BF9ABBFE4BFE6AAFE6BF9CE7FC07F23FEE27F2D407F363E9FD11F4BE97F6FF00EFC992ABD131E2AD5E6DB90D2ED343DC23D7925BA83007753EABF4FF00C17CBE925D17FE50C4FA1FCF33F9CFA3CFFAEC4CD1935AD1D0651955E39C9CEB3EC58AD05CE7B9A5D66D1F9C31D9EFDBBBD9FA445E82FC6EA37BC574DB752DDAD7E45CE643647AAE2719BBBE9D6DD8CFD25B6FFA5F4D56FADDFD1B2BF9FF00E98DFA7C7D13FCFF00FC0FFDC7FF0087F595CFA93FF22BB8FA777D1E7E8D7FCE7FDF7FE0D3870AD971D6BB3A9D4F0CE660D95B768B1CC2F617090D73C86D6E688FE73D3DFE9FFC26C5CEF4CCAA717EBBD5D2DAC706D394C635D21DA966F732CDA7F95F4D7517FF003C3FA5FD3ABF98FE6F86FD2FE4FF00DFD55BBFF141D2BFA1FF0049FF000BFD33E8DBF4BFF44A78DC5B19D8D767B851524CAC3554924924A7FFD9FFED160050686F746F73686F7020332E30003842494D0425000000000010000000000000000000000000000000003842494D043A0000000000D7000000100000000100000000000B7072696E744F7574707574000000050000000050737453626F6F6C0100000000496E7465656E756D00000000496E746500000000496D67200000000F7072696E745369787465656E426974626F6F6C000000000B7072696E7465724E616D65544558540000000100000000000F7072696E7450726F6F6653657475704F626A6300000005682168378BBE7F6E00000000000A70726F6F6653657475700000000100000000426C746E656E756D0000000C6275696C74696E50726F6F660000000970726F6F66434D594B003842494D043B00000000022D00000010000000010000000000127072696E744F75747075744F7074696F6E7300000017000000004370746E626F6F6C0000000000436C6272626F6F6C00000000005267734D626F6F6C000000000043726E43626F6F6C0000000000436E7443626F6F6C00000000004C626C73626F6F6C00000000004E677476626F6F6C0000000000456D6C44626F6F6C0000000000496E7472626F6F6C000000000042636B674F626A630000000100000000000052474243000000030000000052642020646F7562406FE000000000000000000047726E20646F7562406FE0000000000000000000426C2020646F7562406FE000000000000000000042726454556E744623526C74000000000000000000000000426C6420556E744623526C7400000000000000000000000052736C74556E74462350786C40520000000000000000000A766563746F7244617461626F6F6C010000000050675073656E756D00000000506750730000000050675043000000004C656674556E744623526C74000000000000000000000000546F7020556E744623526C7400000000000000000000000053636C20556E74462350726340590000000000000000001063726F705768656E5072696E74696E67626F6F6C000000000E63726F7052656374426F74746F6D6C6F6E67000000000000000C63726F70526563744C6566746C6F6E67000000000000000D63726F705265637452696768746C6F6E67000000000000000B63726F7052656374546F706C6F6E6700000000003842494D03ED000000000010004800000001000200480000000100023842494D042600000000000E000000000000000000003F8000003842494D040D0000000000040000005A3842494D04190000000000040000001E3842494D03F3000000000009000000000000000001003842494D271000000000000A000100000000000000023842494D03F5000000000048002F66660001006C66660006000000000001002F6666000100A1999A0006000000000001003200000001005A00000006000000000001003500000001002D000000060000000000013842494D03F80000000000700000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800003842494D040000000000000200093842494D040200000000001400000000000000000000000000000000000000003842494D043000000000000A010101010101010101013842494D042D00000000000600010000000A3842494D0408000000000010000000010000024000000240000000003842494D041E000000000004000000003842494D041A00000000033F000000060000000000000000000001C20000032000000005672A68079898002D0034000000010000000000000000000000000000000000000001000000000000000000000320000001C200000000000000000000000000000000010000000000000000000000000000000000000010000000010000000000006E756C6C0000000200000006626F756E64734F626A6300000001000000000000526374310000000400000000546F70206C6F6E6700000000000000004C6566746C6F6E67000000000000000042746F6D6C6F6E67000001C200000000526768746C6F6E670000032000000006736C69636573566C4C73000000014F626A6300000001000000000005736C6963650000001200000007736C69636549446C6F6E67000000000000000767726F757049446C6F6E6700000000000000066F726967696E656E756D0000000C45536C6963654F726967696E0000000D6175746F47656E6572617465640000000054797065656E756D0000000A45536C6963655479706500000000496D672000000006626F756E64734F626A6300000001000000000000526374310000000400000000546F70206C6F6E6700000000000000004C6566746C6F6E67000000000000000042746F6D6C6F6E67000001C200000000526768746C6F6E67000003200000000375726C54455854000000010000000000006E756C6C54455854000000010000000000004D7367655445585400000001000000000006616C74546167544558540000000100000000000E63656C6C54657874497348544D4C626F6F6C010000000863656C6C546578745445585400000001000000000009686F727A416C69676E656E756D0000000F45536C696365486F727A416C69676E0000000764656661756C740000000976657274416C69676E656E756D0000000F45536C69636556657274416C69676E0000000764656661756C740000000B6267436F6C6F7254797065656E756D0000001145536C6963654247436F6C6F7254797065000000004E6F6E6500000009746F704F75747365746C6F6E67000000000000000A6C6566744F75747365746C6F6E67000000000000000C626F74746F6D4F75747365746C6F6E67000000000000000B72696768744F75747365746C6F6E6700000000003842494D042800000000000C000000023FF00000000000003842494D041100000000000101003842494D04140000000000040000000A3842494D040C000000000CDC00000001000000A00000005A000001E00000A8C000000CC000180001FFD8FFED000C41646F62655F434D0002FFEE000E41646F626500648000000001FFDB0084000C08080809080C09090C110B0A0B11150F0C0C0F1518131315131318110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C010D0B0B0D0E0D100E0E10140E0E0E14140E0E0E0E14110C0C0C0C0C11110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108005A00A003012200021101031101FFDD0004000AFFC4013F0000010501010101010100000000000000030001020405060708090A0B0100010501010101010100000000000000010002030405060708090A0B1000010401030204020507060805030C33010002110304211231054151611322718132061491A1B14223241552C16233347282D14307259253F0E1F163733516A2B283264493546445C2A3743617D255E265F2B384C3D375E3F3462794A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F637475767778797A7B7C7D7E7F711000202010204040304050607070605350100021103213112044151617122130532819114A1B14223C152D1F0332462E1728292435315637334F1250616A2B283072635C2D2449354A317644555367465E2F2B384C3D375E3F34694A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F62737475767778797A7B7C7FFDA000C03010002110311003F00F544924925293A64E929F18FADE19FF3ABAA48DC4DEDE49FF454ACD369FB3380796ED036EA74F26A9FD78C97B3EB8F55606C8F581FFC0A958D6E43DC037807B28C86505BB87D62EE9F91F68AEC7BEE6B5CC6BDC6480F11A4A1FA7D77AB07DD8F8F93934564FAAF631CEADB03D477AD77F315ED67BFF48F540820C1D7CD751F55053FB1FAB6EA8E4BFD3DA69AF09B90F26CBB0598CCFB45EFF45EFBED67E830BD1B1FFA1B327DFE95753D002D0644079DB3A5755AB26AC4B316DAF26FD68ADE20D83FE05C7F4767F61FF4FF0047FCE223BA3758AADF4DF876B2D01C4B4B44B431AFB2DF536BBF44E6574DCEDB6FBFF4562EC7AD136756E977D8DFB3D565B6DA2CC3763D4E190FC7AB1ECC4C6C8B1EFA6DB30EDC5F4F333A8F52CFB55946162D5F6BA2947EAB4B68CAEA05D6E43AFC6C4B9B6E28A7631BA6536BEA18F5E55F6751CFC1DFD532EAF53D4F4E8C965D93956E374FFB2E3D6FA0B6DE4BA6617D6B654DCBE9D8B9FE9583755763D76ED70F169AFD962EC3A17D64EA76D96616774CCAB32714B5B9365143DEF66EFA1F6BC6637757B9BEF66CFA7FE8D65F45774BA0FD5DC3774F77AEEEA15E583F68792CF55D87898D9AF69C766E6E6BB1ECCAA719DFF69ABAECF53D3CA62E7F17071B3FA8E3518782E155F6D6D6E2073AF7866E69CAFD27A75D9FCDB6EB5FECFD13130C227AAF8CE4351B3E96329ADCE6B032C60225A2EA6DAC3B69F7B7F4F535AF757BBF495AF37EB34578DD5F3E8ADBE9D75E4581958101AD277358D6FEEED77B56C3BA8DF4F5CC91439ADAF1AFC8A716AAC06D2CA197595B71E8A2ADB4D753FD365967A6DF52EB3F4F6BEDB150FACEFF00B47557E735A5ACCA6B09932058C6B6BB5AD77F65088119505D3265004F47296AFD52FF00C55748FF00C34DFF00A97AC995ADF54BFF00155D23FF000D37FEA5EA4627DE13274C8AD524924929FFD0F544924925293A64E929F09FAEEC9FAE1D59DFF0CD1FF8152B01DCF9ADEFAF0E23EB87578ED734C7FD6A9584E1EE07B4C7CD3482B82C0CB869F246A6B0F3B5C246920F1F728B29703C401C9F056B1D90F1A73AFC934AE0750D9C3C5ADD680D6001C35811C15D0E374AC79935336EEDE06D1F4A3E971F4952E958FEF693C49D7E2B7EB969E254323AB6B18EAD46F49C7F730D4DDAFF0073840824FD29597D6FA5D54EE2D1B77341606E9A8F6ED11FC95D334FB493A203B1ABBF21B65A37067D169E1464906ED9B844855393D1FA1399563DD60DAF68690D8D23F74FEEFB5687D60E8746474DB2DA5B16D23D481DE072B535EDC4A85969D0763A1F81D101908365470C786A9F2EDC473F72D5FAA07FECAFA47FE1A67E47ACFCBA855977560406BDC00F20568FD516FF00D95F473FF7699FF52F5781D9CC23523B3EF6993A6450A49249253FFFD1F544924925293A64E929F05FAF263EBA756F036B47FE05542C62241EFBB50B63EBE83FF3C7AAB876B87FE7AA56383EE1E1FEBEE40AE4AE2E207808251702C7D9696BB9747E2546BA9CF7348D7C63556FA7623EBCA24F0D2224729922297C626DE9B0A88EC0761F2F6AD4656EDBA842C0A9A183C5690600DD79EEA06E44506ABC32B682F78682A01F48FA37327CCA3BA9A277D906741BB80AA64D9D348F4CBEA6DA4C0687B43893DB6EE4C902BC16C8C80E86348772496F1082FCEC4F53F4B686469E253E3E2399510C044F8F654EDCBE97D3AD1F6C7B2BBEC05CDDE1C4C03B67DAD7353575E9ABC8F5EA5B5758CAD9AD56BCDB518896BFDDFF00548FF545B1F5ABA47FE1A67FD4BD5BFADF6D195660E650439B657657BDA080763B737E906FD1F5551FAA766EFADDD1C0ED94CFC8E57212B01CDC91A9C878BEF8993A65231A92492494FF00FFD2F544924925293A64E929F07FAF4377D6EEADFF001EDFFCF54ACEE8F875E7754A31ED1348DCFB478B180D85BFDA5A5F5E04FD6DEAE3FE1C7FE7AA5677D5BCAAF1FAC62BEC23D379752F9FF84696367FB4992D8D2F85710BEEF656F4FC73B5B93815D41803BD7C56ECF4C1FA2DBC7E77F2DC8195D2D941DF4925BCEBE20AD5B711F71BADCCB36E331D3B0BA1A770F6EF8F759FB9B10290CB2921ED2DD7DAC773B7F35D0AB027BB7A518F64BD39C7609E56A31C0F3ACAC9A5BE9FB55EA9F1051486593D2B032B5C8C7AEE3DB7B7700818DF57FA7E3DA2DAF1A8AC8320B2B00C8F376E5A55BC10028DD76D6B9BE4A39DD32C00ECCBD4AC360113DD0ACC7ADC009DBBF50476542C3D4FD3230D958B5D1165B25AD13EF3B1BF49C9E9ABABB2E0E7BD9E8B87BE352E70FE49FA09A9156D6FAE5D2DD6FD5E7E4077AAFC1B1B7B4F70C77E86F1FE6B98FF00FADAE33EA79FFB2EE91FF8699F91CBD22EB59753762BC82CBEB7D4E1C887B4B3FEFCBCD7EA583FF3ABA313CFDA980FDCE56701B15D9A5CDC6A57FBCFD04A2A4A2AC351749249253FFFD3F544924925293A64E929F06FAF13FF003BFABFFC70FF00CF74AC0C5A9F6BEC63352C63AC81FF000637BB5FEAAE8BEB9D2FBFEB97576B4682E6973DDA35A3D3AB955FA1E1D15F556398F3634D193EA480266B737D8D4384D13D14271E211BF53B9D07EB6E364D2DC7EA4F155EC01A2D78FD1D9FBAE738FF00376AE86C6B1CCF546C1A4EF90411CFD29DABCE31F01ECC9BF19F040D58EEC44E85AB5717A65C5A186D2299135C983FC90D55E7117A3771E43C3A8D5E9F7B79699F056B1DEC70826216457B9839D111993E9EB29ACA24EDFA80409F821DF6082663B954075105B13D92AAD16BE5CE803523C5327AE8BC11BB62EEA36D5596D741B081A1710D6FDFAB952C6EABD6ACBC0BE8AABA5C61D1634B88EDB55CB286E437520055D9D3E8C571BDD74EC05D06001085689120CF2F26BC5C5BF2DE76BA8ADCE209FCE03D8CFF003F6AE2FEA5B09FAD5D1FCB25B27E4E5B3D55CECF2EA812DA9C7D4DAE05A5DFE8DFEF8DCCFCF46FAA5D2998FD7B02C277385E3F2394D8FD3E64B5739E33A6D10FB028A928AB2D35D2492494FF00FFD4F544924925293A64E929F1DFACEDFF00B24EB193635CDC4A725AD73F69D9EA3AAA6373FF003ACFE42CBC7E8D93D7F2ECCBC1B5B895E3868B6F735CC68304CB760DDF41BFA47ADEFF0018DFF8A0C4FA3FCE5DFCC7F52BFE77FEEF7FEEB7A6B56AFF00C478FE6FFA3B3E87D1FA2CFE95FCBFFB91FC8F553A5C7C236A598FDBE296F77ABCF3306FFB0FA79370BEBACFACCC86506BB1A5C1BFA11BEE6EF764B5F47E83D1DFBEEA7F3DEA66814BFD116B4E4080EC7782CB8388935FB3D6ABD467F5DEB62EFE9479FE7EFF00E6B8E723FE4EFF00CD97FA1FF805CBFE60FA1F487F3BFCDFD21FCEFF0027FD2AAD2E2BE8DE87B75BCFFABC207ED7571DCEC88143D8E71240638ED7123E9358EFE6EC43C86E5D409B68786FEF012DFF0039B2B773BF9ABBFE4BFE6AAFE6BF9CE7FC07F23FEE27F2D407F363E9FD11F4BE97F6FF00EFC992ABD131E2AD5E6DB90D2ED343DC23D7925BA83007753EABF4FF00C17CBE925D17FE50C4FA1FCF33F9CFA3CFFAEC4CD1935AD1D0651955E39C9CEB3EC58AD05CE7B9A5D66D1F9C31D9EFDBBBD9FA445E82FC6EA37BC574DB752DDAD7E45CE643647AAE2719BBBE9D6DD8CFD25B6FFA5F4D56FADDFD1B2BF9FF00E98DFA7C7D13FCFF00FC0FFDC7FF0087F595CFA93FF22BB8FA777D1E7E8D7FCE7FDF7FE0D3870AD971D6BB3A9D4F0CE660D95B768B1CC2F617090D73C86D6E688FE73D3DFE9FFC26C5CEF4CCAA717EBBD5D2DAC706D394C635D21DA966F732CDA7F95F4D7517FF003C3FA5FD3ABF98FE6F86FD2FE4FF00DFD55BBFF141D2BFA1FF0049FF000BFD33E8DBF4BFF44A78DC5B19D8D767B851524CAC3554924924A7FFD93842494D042100000000005700000001010000000F00410064006F00620065002000500068006F0074006F00730068006F00700000001400410064006F00620065002000500068006F0074006F00730068006F00700020003200300032003000000001003842494D04060000000000070006000000010100FFE10DD2687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F003C3F787061636B657420626567696E3D22EFBBBF222069643D2257354D304D7043656869487A7265537A4E54637A6B633964223F3E203C783A786D706D65746120786D6C6E733A783D2261646F62653A6E733A6D6574612F2220783A786D70746B3D2241646F626520584D5020436F726520352E362D633134382037392E3136343033362C20323031392F30382F31332D30313A30363A35372020202020202020223E203C7264663A52444620786D6C6E733A7264663D22687474703A2F2F7777772E77332E6F72672F313939392F30322F32322D7264662D73796E7461782D6E7323223E203C7264663A4465736372697074696F6E207264663A61626F75743D222220786D6C6E733A786D703D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F2220786D6C6E733A786D704D4D3D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F6D6D2F2220786D6C6E733A73744576743D22687474703A2F2F6E732E61646F62652E636F6D2F7861702F312E302F73547970652F5265736F757263654576656E74232220786D6C6E733A64633D22687474703A2F2F7075726C2E6F72672F64632F656C656D656E74732F312E312F2220786D6C6E733A70686F746F73686F703D22687474703A2F2F6E732E61646F62652E636F6D2F70686F746F73686F702F312E302F2220786D703A43726561746F72546F6F6C3D2241646F62652050686F746F73686F702032312E30202857696E646F7773292220786D703A437265617465446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D703A4D65746164617461446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D703A4D6F64696679446174653D22323032302D30342D30325431373A32343A31352B30383A30302220786D704D4D3A496E7374616E636549443D22786D702E6969643A34656266653730652D643236652D623834312D613962612D3232623834663439646366312220786D704D4D3A446F63756D656E7449443D2261646F62653A646F6369643A70686F746F73686F703A64633333616566382D343164372D343134372D626566652D3133623366363839326632642220786D704D4D3A4F726967696E616C446F63756D656E7449443D22786D702E6469643A39633734393932312D633861652D393634382D613065372D613762366131393131336266222064633A666F726D61743D22696D6167652F6A706567222070686F746F73686F703A436F6C6F724D6F64653D2233223E203C786D704D4D3A486973746F72793E203C7264663A5365713E203C7264663A6C692073744576743A616374696F6E3D2263726561746564222073744576743A696E7374616E636549443D22786D702E6969643A39633734393932312D633861652D393634382D613065372D613762366131393131336266222073744576743A7768656E3D22323032302D30342D30325431373A32343A31352B30383A3030222073744576743A736F6674776172654167656E743D2241646F62652050686F746F73686F702032312E30202857696E646F777329222F3E203C7264663A6C692073744576743A616374696F6E3D227361766564222073744576743A696E7374616E636549443D22786D702E6969643A34656266653730652D643236652D623834312D613962612D323262383466343964636631222073744576743A7768656E3D22323032302D30342D30325431373A32343A31352B30383A3030222073744576743A736F6674776172654167656E743D2241646F62652050686F746F73686F702032312E30202857696E646F777329222073744576743A6368616E6765643D222F222F3E203C2F7264663A5365713E203C2F786D704D4D3A486973746F72793E203C2F7264663A4465736372697074696F6E3E203C2F7264663A5244463E203C2F783A786D706D6574613E2020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020203C3F787061636B657420656E643D2277223F3EFFEE000E41646F626500644000000001FFDB0084000202020202020202020203020202030403020203040504040404040506050505050505060607070807070609090A0A09090C0C0C0C0C0C0C0C0C0C0C0C0C0C0C01030303050405090606090D0A090A0D0F0E0E0E0E0F0F0C0C0C0C0C0F0F0C0C0C0C0C0C0F0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC000110801C2032003011100021101031101FFDD00040064FFC401A20000000701010101010000000000000000040503020601000708090A0B0100020203010101010100000000000000010002030405060708090A0B1000020103030204020607030402060273010203110400052112314151061361227181143291A10715B14223C152D1E1331662F0247282F12543345392A2B26373C235442793A3B33617546474C3D2E2082683090A181984944546A4B456D355281AF2E3F3C4D4E4F465758595A5B5C5D5E5F566768696A6B6C6D6E6F637475767778797A7B7C7D7E7F738485868788898A8B8C8D8E8F82939495969798999A9B9C9D9E9F92A3A4A5A6A7A8A9AAABACADAEAFA110002020102030505040506040803036D0100021103042112314105511361220671819132A1B1F014C1D1E1234215526272F1332434438216925325A263B2C20773D235E2448317549308090A18192636451A2764745537F2A3B3C32829D3E3F38494A4B4C4D4E4F465758595A5B5C5D5E5F5465666768696A6B6C6D6E6F6475767778797A7B7C7D7E7F738485868788898A8B8C8D8E8F839495969798999A9B9C9D9E9F92A3A4A5A6A7A8A9AAABACADAEAFAFFDA000C03010002110311003F00FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8E35D5BCC737C2D3C9BFBFF666A389DAABAAEB92D09964A9F7C78D5CFA56B736CD2C94EF538F1AA82F96F534916762EE10D78F8E112B54DEDED35BD3EEA09B45B992D25620CA14D3265239BD8EDBCD5E6BB286DA2B8BE79A375FDFA924D4D3205B0232DB5BD4EF199998E5459C58F6A9ABEA16F71CB9114EF9125B120B8F3A5CDA026573418AA583F34D616346AB5298A09A424FF98F2DD0F80D2BE18691C4925DEBD7DAB05B61522434CAF2C51C6FBA7FE7122F60D17CBBA84175B333D4D7E6329E172714DF5E6AFE7ED22CE1043865814FAAB5F118F0B9A26F8C7F30BF306DEE7549AE2C8889391A95FA71E1499BC4758F3D5037A77ACDEA0AB47CBAE4E30713366E12F35D43F302DA14901531CE7ECCA7C72C11718E7796EAFE6ED57516663AA12A0515431E99608B8F2D430D9A677E524F3FAA4F5A9AE5822D0750978B98B8D140D8E4C63B63F9843BDC13F64532431B1F1AD0C5DB916EE72D8E362656ACB7457BE4BC3606368A13F2553F7E5321BB5F0EEDD0B6F916C0141ADD0558F5385BE2690CC5536E98B682985A4527312ABF1A6F5C9F44527A6F5255114979C48EC4E424136EE70A2D2593E54CA2516432D265A76A6F6B5FAACACBE041E995F0B319DE9DE5BFCCBF37E8C54E9FE619A075E8A1C8FE18699F88FA4FC9FF00F395FE6ED08C0BACAB6A71A302D2BFC5B0F98C890D8323EA6F247FCE5769BE63B8449ECD62F50F5D875AE564360C8FA2EC3CC5A46B32DADF898514F2F4EBD72B21BF14F74FF4D7626F1F53F8A192BF5207B785320439FC4115A4693711DBDF5F5F12CE8C0D913D857B640865CD910BAFAE46A41FEE46F95909115A6CE4BB46B98FAC20D7214C643662170CF7323C858AFA27E2FA314452DD56DE2D4F4C9F94A6B1827AF862DF163FA65C8FD1C2C11EADCA80D716F09EC33DE42A6D1472A2824F861069AB502C331D3BCB3E55F3C412795FCE9A746D05DC6CB0CEEBBD4A9A6FF3399784BA4D445F8C9FF3931F9253FE507E61EA96B145E9F97B57919B426A6C402C4D3AF866C605D3E41BBE5BAFA5230FC32DB583B90724F865D8B930CC5BCB5A16375C55AC5578E98AB78AA8BFDA38AAA2F7C55A3D7156B155EADD315560D8ABFADEFF009C6EFF00D677FC84FF00CD73E56FFBA45AE5A39349E6F68C28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF917B754FE45FBB34FC2ED532A855A803C71E1551370C0E3C2AADF5A26361ED863155D0DC52840DFC72C2A39A6893B3D0124F8D7205B423E172F227A6C401D86D9516714AB5F0D52FD80A139193607916A21A49641526A722125825DE9F335C1F4C75ED96C434929D699A6C96C434DD0F639708B519B2F86D62F8446DC7EB1F0971B52990CB0D9871BE87FCB0F341D3236D0D5B8C6E3E2981A1FBF28E17231CD35F3479E9A06B8D356666080FC7CAA4D6BDF0F0B9919BE7FD5BCC7246F2B3BB10C4EC4E3C2994DE7979AD87666AFDAE9921171331B2C0F56D4F996EFF003CB045C5931D8EF2A483F765822E3C93012875EBB1C988B4108794A034D865910C68BA38D5CFDACB0048895EF171AE4C36479A0A470A7A6580362A4738A2F877CC49C775A4724E0D32149016B354935AD71A4A1DD6BD77C7853689173C4000D282981B835EBA75A0AF8D30316FEB00F53CBE780C5810510B7617A1A7CB21C2C68DA6FA7EA011872EBE39021BC16463520EBC791A11BF8640867128FB5D46EECDD26B2B9642A6A021A6408660BEA2FCB2FCFDD73CBED676DA8D64D3C301752BEE42FCCE56437639517E927903F33746F37E9D6F35B5CC6CC69C5188FE272B21CE195EF305FA4D63FBD6531AAF4047864086E8E4B486CAF94DD3C40F0427627A64086D8CD96A5DDCDA59B81C5A07EAC065720CA52B09035922C373792515250683B641116276C6D6D61BBE6F53302029E9BE2DF179F4113DAEA124A8F54249515DB16F0CA34926E2FE49AEE5291C6018F7A54F860465161EA22FDB4CB9B1BE11ABC42946201CC9C45D46A60F8AFF00E73E6C935ED07CAFE6151B69FEA733E1CB966C6127479A3BBF21B5802DEF21BB07F772A9A2F6CB896A8B7129F492423FBC15197E12C7338F7CBDA14FB8C555475C55CDD7156B156A98AB78AA8B1353BE2AB6A7C7155E3156EA7C7157F5CBFF0038D9FF00ACEBF907FF009AE3CABFF748B5CB472693CDED5850EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF91688D3E8CD770BB55732D29BED5C3C2AA125C2826831E155317408208D8E02155E1B85AF4C8951CD358A7AEC0640B684DB436F56492BD16B9596615B5884496D2F7DF6CAE41B2245BC82F22E370C08A6F82213221279612262C82A46E7E599100E3CCAE5B8127C2F41C732621C6949524D42354F4A234917A1AE47306A2535D3BCDEBA4425797FA536DCC1FEDCC76FC4509A9F9B4384B899EB24952C6B5FE38D39824C1F50F30477E480698D24CAD8EDC5C8D85474E95C9C766360A4574C1CF635E9EF930D6404B3D13EA5541F0229BD72C01A26023D4B200A41E5D969BFDD9688B498A9C8A643CC30A7422BD32241B4C601C9CD0D0D4622D78559E6DA85BE9CB031A4148391EBD7EFC95A3758ABD0572A31B6611B1823A838384A95415A9D8EDDA98F09415600537EFDB070962DFD589EDEE477CA8B782D7D5877207CCE16629B36E3C4570F267C214BD23C80EE4F4C2427802690DB9461BF5CA484009D470F214276A6FE232B21980A5CBD19290CC580EB4DE83DF2B660332D27535212DEE8FFA3C9B487DB20591D9EA7E53F3E7983CB371CF47BA75B588D42722361ED5CACD22322FADFF002DBFE729E486FECA3F324A5B4F43C6EB7AD6B403F6B2B2DF0917D9AFF997E53F30E976D75A2CF1C72CA0114615DFE9C8172A322F48F2E1BBD5F477844BCCF02EA6BE032B937028CD596783CBD6EAE486690291DF2A6C890F3BF35C434FB6B478C9AC8A0B530D37C4879A9BFB99670B1D41AED5EFF2C0DE0B228A4BA8602D3935603D3A78FD1912CE554CFF004DBBBDD461B5B6949F4D3BB6DFAF32313ABD48BE4F08FF009CBD8E0D47F29B5582DF79B4BF4C311B9F889E99B081D9D0E789B7E39EB9664FE87818D4B86E5F7E5A1C5029425A239806C20F8732B0726190DA1CF7CC86A531D462AAABD7157375C55AC55D8ABB15506FB47156B155E3A0C55BC55FD72FFCE367FEB3AFE417FE6B8F2AFF00DD22D72D1C9A4F37B56143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF91745DBAE6B5DAA0270038DFBF4C557A007DF1B569937DBBE025217C042073DC654C931B4B9E50CA83AF638153ED2A660AE69F7614A367BA58ED6466DC57BE210497946B3748D33508EB930030322C65AED519B7A6D930C0A4B25EA976A1A6581AD2C9AE872FB4704D38D012DCEFD72B6D40CD37A94DCD07BE2CACA024DF7F0C56CA8140C8FF00BB32CBD8569F0F7CAB27369C922D18005B7B89916CE2B561340E5BAB2F4EB92C64B5D943DB5FDB89F5295B5385DAF559A094950D1CE7B04AEF99B8C2D95595FCC31E95FA5A2F2DEAB79369A4C971E6692CA54B64886DBBF1E1B7BE654698F1747A07953F25FF00357CD5E47B8FCC3F2CF921F5AF26DAC924BAB6B8AEDF686F20A01B713919D1482F2ED2EE9AFF0053F4EEAE9567B5774B4D35A8AB291B1591BF678F6AF5C85320537786D4C727D62D7D2746ACB0024AAB57E1A37BE16C1BA0A592333C1F5AB6956F6452D6B040A646283AFC2B8B2D91111FAC46DF5AD0357B7907FBCF3A594ADC97BBF4ED8D30F103505E5DC61A19341D524914F1B6B916725593FDF9C698D3094C2BC17577C9A69749D5DD17E004584A7930F1DB6C698198519259239ED629ECE48EE637F5EE6CEF94DAB7A0DF64D1E87010C6D165EFA492CFF437FCEC1AD7982636B06996E39B2843F0A8095272AE0B6424C9F59F2D79A3CADA9E9BA7F9E7C8D3686FAFA7FA33DD1786BC056A3985C85331262333C3A54F76F7BC648AB4B360D5AF80195D16C12513E60D2CD80917D45D661916331703F0A31DDBE818981642749BC3AE6906375955CC900F87512A429FE19594FE60222D35781D3EB68CAD1034926660015F9572B3129FCC840C7E65D1D24BEB4B581E196ED089EE402E021EE32070CAAD7F3211EFE61B4168AB6D299934E50F75301F184E8085EF90F02523417F34193E95ABBEB4AB7361A9FA4427EFD88A72403A53C6980E92498EA8047DBF9C7CB567070FAFC915C4CE561708580643F1127B54E0FCA49C886AA2CCF4DFCE48343113DBF98273C2842D0D36FA71FCA172A3AB8BE9FF00CBBFF9CDB4D1FD0B6D435C905A2AD18F0A9FF896425A434CA7AC14FAC348FF009CD2FC9CD42C53F4D798CACC46EA631D7FE0B043465C6FCE29EAFF00F393FF00939ABD91B3B0F33299266A44F22AA8527BD4B659F932D90D6EEC1B4AFF009C92FC948F548E1D6BCDBEB7D5488E20B10E0B20DAA581E9954B4843B0C5AC0FA4F4CF3168FABC116ADA4C424D0EE943D9DEF51231DCD3B653E018736EC9A8E21B326B4D5ED26FDD28E20EDB6D8D535DDBC63FE7231043F97F76F6EA5FD68D8B83BD681BAE646271B34453F1A350B93EBFD65BAC723023C3E239B1C54E8B53B294BF1309FB5C0E4332C38504337F1C2CD662AAABFC3155F8ABB15587AE2AD62AEE15DEB8ABB80F1C55DD36F0C55D8ABFAE5FF9C6CFFD675FC82FFCD71E55FF00BA45AE5A39349E6F6AC28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF90949CD3DF35AED52FB89CF2AF7C55B86E091D7E78AA21AE147461F7E02A39A924D50F534F0CA99A334E620B96D86F4AE054F2D6EFD2473D3C3154A750D59DAD254AF1F88648734179BDEDD33C8C49D8E4C302C72E27356DE9930C6492F362E77DB26D6A44FC66A69B7538CD38D42523B1FA72B6E435483D7156B155F63A7CDACEBBE57F2EC774BA6C5E65D66CF4A9755A8E708BA9021600F600D6B93C70123BB466354FD9DB4FF9F49FE51E9B35B5DF9C7FE725E596D2C19259EC276B48A07400311EA48EBB7C865808ADA838F7BBEA8D27FE704FFE70B7F2CBC93ADFE62EB5E4ED2FCFDA1F97AD1F53B8D68CE66458A1AB332885B893F4E5D007DEA4EFDC5F217E7E7FCFC07FE716353FC95F327E49FE4E7952E35AD3FCD1A73D92DB5DE9DF548AD1A421898DE956229B1CBE2A0D9B7BB7FCFBAED6DAEFFE7DEDABC11C097125CEA9E608E58A641C5CAD0F02C474D8EF91931E27CE5FF386BF901FF38ADFF3939F947F9A5E46D4AC20D13F3DE4D4AFA3D5B502693D8AA5C31B692CB911EA29FDBA74FA3229E2A7E6C7E75FE48FE62FE43F9FB55FCAFF003FD93DAC31B9934FF32509B7B8B752CD0949A9C492805403D7037465694FE5779EB49FCAEFCC9F267E62EBFA147E6CF2EE9F1490DDE9774291BF26A6F8B2E2EAFDABFC97FF009CC4FCA9FCF4F37697E48F21FF00CE3B5ADDCD7052DF51BD5B3AD9D9DB103D4066084034DC570B1E305EEDFF00393BF9B5F917FF0038B736896771F9223CD9E6AD663E3A258D869FF588BEAA48520BA275A9D862C38DF24AFF00CFC07F285102BFFCE28EA5A6B472F2BE54D1A4243F7A829818193E5CF2EEB1F945FF0039A1FF0039BFA5493F92469FE42D5B4CB5D2E7D04C660314D0D43332281435070B0326BF337F28BCA9F919FF003F16F267E5FF00E5ED82683A169F269B7D6F08FDE822E95988A3D41D80C89E4CE25EFF00FF003F7E5B6B6D7BF216FAED56EE1B8866F5D446B172F848FD803B9CAEB9B3069F945A4FF8720F3D7902F7CCBA4407CA305FC0757B66735684CAA5B90FF572BE8DAFDCAB4F397FCFACEEF5A9560F2669B26AD218AD25536AE12579540001F528C7B5460970F716278AB9BE8CF3FF00E497FCE0E7E5E7E5C69FE7AF387E5468DA6F90EF8441677470419BEC02858124FCF23C239D7E3E4E29B7CC49E6EFF9F50CE925A2F93B4A8B4E1113C84120527C38FAB5AFD3938C224F543E93FC95FC95FF009C13FCF1F2BEA3E60FCB0FCA9D1F52D0EC646D3EEEE9E378D870A93D5DBC32D18815DDE0B79E65FF009F5A683AA6B3A4DE792B4AB0D6B4B9A7D36FE25B7763CE0AAB0E5EA53AFB75C9C71041BA7E10595CE9716ADE686D3E258B449B5DD4A4D123AD185A191BD15A7871A65BC23AB5926F67DC5FF3827AD7FCE27E9FA779F3FE865346B2D425D52E61FF000CC570865F4A341FBDA85652A49A1EB8384364645FA0ADE64FF9F54F0E2FE56D1154776B7907FCCEC7843689C97DBEBFFF003EAD240B6F2B684EC4D14185C024F6AFAD80C026539232EB55FF009F5B229F5BCA9A1AB20ABA7A7202A3DFF7DB618E30D5C459F7E5FF0090FF00E7DF7F9C370BA2790BF2B6D35DE5F66FADEDE6FAB236FD67595941DBBE1300CE32931BFF009CC4FF009C6AFF009C4DFC9FFF009C73FCD3D534FF0021E85E59F375CE85247E5495A765BA92F792F130866DD857B0CA66221CAC5399237D9E1DFF0038E06E1FF24BC8D6FA85CDC48EB67037D52742BC18C62AC09DCD7357A900BB9C123D5F4B695A658ED26C48DC819824539F1281FCC5F2E5A79A3C9FAA5A7107EAF03F15EE7E16E99386CD59793F083CE5A73699AFEB5A5BC6D088677081C52B466E999F8CBA3D4C5283B5B59A9054AA1A5733226C38110866FE39364B315545FE18AAFC55BC554CF5C55D8AB5CE9B53157733E18AB7B9DE9D715750F862AFEB97FE71B3FF0059D7F20FFF0035C7957FEE916B968E4D279BDAB0A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8EE4B96A57F0CD6BB54BEE6E4F2FD78AAE86E01502BB62AB1E41CC1F7C05211724A0FA7E1953247B5D0458CD771D302AC9756E0B4AE2AC5EFF0053332B28F1E9921CD058C5DDC9A1C98605209A72C684F7DB2618C96890713936B5093F7854786F8CD38DBF476F6CADB96AC542DF462ABFD318AAA691E55F3379E7CD9A1793FC99650DD799AF254BAD31DD8AC8AF1B7C3C69EF976201C4CE5F60F993FE70D3FE739BCCF6ED6FE636BAD4D0A7A0BA64974C55430141414FC72EA01A2CBF643F2F3F273CFDA2FF00CE0F79D3F27751D3560F3D6A7E56BAD3AD2D236678CCF22154058926A49DF7C9C764136FC52D1FFE701FFE72CB48B23A6C3E43D327E0C6E11A590B4CA587B532C0520D3F6A7FE70B3F25FF00307F2DBFE70CB52FCA9F37592691E78BBBFD6E6B3B02DD56EF8984D76EA01C892C0C9F94DF94FF00F389FF00F3995F93FF0099EDF98DE46F2ADA43ACF97B58B9B9BFF5A5741716D34DCA84568C0AD6981417AE7FCE7FAFFCE51FE6E79534AF35F9F3F2AB43D1FF002EBCAD1B32EA1612BCB7E1CA1F51AE118D5072AD074C590953F38FFE71DF41F23F993F327C9F61F9CBA9DDE9DF96FAE3B23DCB201688E1C22891CF40316CE27EE04FFF003953FF0038D3FF0038DF77A57E43FF00CE2AF97F45D77F31FCC37D67656F7518A6957724DF097B9BD427E3626800C58195B18FF9CAAFF9CCDFCF4FC80D7BCAFA67E687FCE3DF94F59BED56CC3691AFD83497715B5C16A2A4323861EA03B85271636FABFF002FFF0038507E40CFF9F1F9F7E46D13C8B05BDA9B9D3F4E4445935042AC10CEACBB48C69B0C5812FC5DFF009C15D5A2D67FE7381F58D3AD6DADAD7CCBAE5CEAD690D688B677723CB1C6941D830DB16264F56FF9CB6980FF009FA17962F26790A01A3C56CD08AFC512BA95FA2BBE25B81671FF003F8D92E6E35DFC86B458964B3FAB48F6A53790B537046408641F93B24769776F1C5A8D8BDC5E5005AA9AD32A21B8153B8D1ACADF59F24FD5E27B49CEB5640015A8FDE83B570034CB9BF793FE7E412ABFFCE01F962299A79644D5F458DA471425D6A77F6DF2C8C6A9818EE5F822DA1697A868B63A7E97A1869E3B413DF5D92F5F5075EF84367007EF97FCFA0C347FF38C9E7F8608E44B9FF10DDC61C0FDA11353EECB049AB806DF17E12F9AB47B1BAFCC0FCCEB8BA8DA7BDFF156A70A3396A02262C6BBF8938253D9B3806EB5E3B64FAAB416104933FC0DC4D7EC8CC7F14B1F0829A683A75C3FD616C230D727F7CA091B8F91C7C52918C27967E5AF2D4C04779A2A4DE22AFF00D71F14A784226DB4BF2FEA7AAD9F93BCA1F97771E62F34DF4C9FA3B4FB38E4964E75A091954D4283D4E4A323252007E937E427FCFA63CE7E6BD624F38FFCE42EA16DE50D126845CC1A268937AB24A08A94B9E6D5414EA2B970B69343DEFAFBF303FE72AFFE716BFE708FCA571F975F92DA2D9EB9E72107A561A1E8CA67B496FC01F15E4C0B1526A6B4C8CA7B338C093BF27E59F9CF5FFCCAFF009C81D6EDBF31FF003BB537D6EE21B8F5743FCBD8E42FA6D9467EC96E276A53BE60E6CF5C9D8E0C3B6E1F657E5BFE6369D731586871B246D63122D22A1B745A50468C07ECE61711939F5C2FA534DBE8E15925460EAE054D72328B7C24CC22D5AC61D12EA696CBEB7CA290B102BC7E13918AE4E4FC43FCFDBED3F5AF3EEAA2CE0F41D256DA94A6ED997093A7CE1E1FEA48CAB1C8FCFD01C57D8667623B3AF229D96A1D8ABB155CBDF15546ED8AAC1D3156F15770077AE2AEE03C7156B9D36A74DB157733E18ABFAE6FF9C6CDFF00E71D7F208F8FE5C7957FEE916B968E4D279BDAB0A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8D34BC51D4D0F8E6BA9DAA5D757887900C2A71A55B6D7229BB0AE34A897909F881D877C041506914D7085128E2A32AA2CB88285DDE7100A372E23B634578825125F3B6DE3DB0526D0734E0296AD08C9008291DD5D541EF920C0A4C65777FB27E7930C485FCC81BFD3930585174720E677DA9824530148B0F5141BE41B2D48B91D8FCF15B6BD4C56D917917CEFE6DFCBCF3E68FE74F25D8DA4FADE8686E21BDBD1FBA4E07970AF89F0CC8C3C9C5CFCDF7349FF3F5EFF9CA09EC6E2F7F40F96EDEE2C9C5CDC4A63A3948C50D169EDE39750B71DFAE1E46FF009C8DF3C7997FE70D7CC7F9F77D6D65079CF43D126F318B287FDE7668D4B05229D0853DB26021F945E58FF9FADFFCE5A79B35516DE55F22681E62D56E938AD859DA9967DABFB0057B78614BF5BFFE7113F3E7F303F3EFFE71A6FF00F34BCD7656107E6269DAB6B5A78B38978242DA7FD8475A7C2DB1A8C04354DF9BBF941FF3F0CFF9CA9FCDFF00CFA87F28345D1BCB916A1ABEA975A7BCB321458A3B4765E4CD4EDC70522934FF009CF1FCF6FF009CA8FCBB54FC9DF3CC3E4CD4B45FCDAB77FABC1A0167BE8560F85BD6561F0D6B51F2C5987E547903C85E7FFCE1F31E95F90DA75CE97A4DCC5234B6925EBFA51B3F2E410B7892705864FD16F257FCFA23F3F26D7B44BFF33F987CB7E4EB2D2CACD0DEF97A57FAFA5C210D14B5634E4AC01AD70A0BF577CE1E75FC81FCA3FCB5D0BCB7F9F7E7DD07F32353F23411CEF26B7325C6AD737D0F499537AB531624BF32FF00E7323CE1F9DBFF00392DF975379D3CA7E4D9FCB9FF0038CFE50893559ED75188C37B3C51FDA96341406234F84E1A60FCCAFC9CF2BF9BFCFDF9CDE47F2C7E5B79864F2479AFCE0F1D9F917558E43088E40A5C7AAC3703883D31E140897EB27E5E7FCFB5BFE727B4DFCF1F24FE6C7E63FE61689E709343BC49F53B89E691E765414DAB4AD6B5C69B86CC2FFE7EF9AD68DFE37FC9DF2EE8BA9A4BE67F2DDBDCBEAF6D237C36EB22928CDE0180DB2259805F3C7FCE28FF00CE04F9B3FE7277C8B379FED3CEF2E942398C3C1E42073EA05011EF913BF26775CDF5A68BFF003E80F35DB6ADA36B1ABFE62B5E3E957F6F77F57E65AA20903D055BA9A5300891D14CC17E927FCE507FCE31CDFF003909F913A5FE4E5B6A8FA49B39ECEFCDFF00EC97B4D954EFDF2C0C0CC9DDF9B23FE7CF5E6CB5D3445A7FE68CD0DDBB5651EA3052BDD766A644829F10BF463FE710FF00E717AF3FE717FF002A75DF235E6BF36A771A95F4DA9497719F84348A568373BEF954C90A245F9F1E67FF009F44F98B5AF37F9975FB0FCC06B6B3D7B50B8D4C42F211F1DCC86460C037515C4094BA289D17C03FF393DFF38B1AC7FCE29F9FBC85A4EA5AE9D56D3CC32395915890415F72727E1D06CF11E5115ADBC0BC0ACCAD3B3189E9B75DE990E109E22AF02A25CA98A4775EE7B60A0C6CBEB5FF009F6E24C3FE73B742F456393FE752D5CC824EC9C7E265F714DB2E8061225F657FCFCFFF003C3F35FC97E6DFCBAFC96F2179A27F2BE93E74D264D47CC3E6289FD3B9611CDE998B9D3BA8E9965048912FC9FF002E796B4CF2F6A1746D8A5FCB75704DF6B7A99ADCBC86A4C8A6BD77CAB200DF025ECD06A30454B7B39648D29FBFB81D251E0C7C335D962E7E29109E69570F65730DF69E56CA20DF15B45B4751D5BE6731E31A72B8ADF587E5979ECDFABDB5F5C28E2005E47AFE18261BE05F56793754B6B9B7BDD2DD11E3BD8D979B741B532B00B39BF217FE726FCA5FE19FCC1D4EE238EAB732332D3A1A96E999100EAF5043E588DA30F351BE22DF1A9EA0E67E2D83AD9157A1F0CB98BB7F0C3452D12075C08B5CA46FBE2AA8C46DBE2AB01DB156EA3C715773A6D4C16134EE67C31B5A6F883BD7AE3687701E3855FD72FF00CE367FEB3AFE417FE6B8F2AFFDD22D72D1C9A4F37B56143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87A96FEF941ACBF8E623B3B0963DF5F16DA5AE34B611515DDF541F571A5D9318B53BD42A1E4AA7ED2E0931927706A3CC0E9BE52D61166E7638B38A5E6EBE33D4E2D8103717049C52833FBC23155616C42F21DF15434B1D3B62A868D7E36F0F0C5894746A3DBE8C582BB461BE43155168462AC93F2FBF2CFCE1F9BDE7FD1FF2EBC9776965A8EAF19905C4E6900A1A7C7976271B31DDFA2BA47FCF9FFF003D7597F43CC9F997E58B4B688049A0B3123CA57AD18AEDF7E640F268B7EC4F907F217CA1F937FF0038F179F955E75D6E26F23C1A335AF9A359B87280447FBCAB9AD12872616DF1CEABFF003963FF00381FFF0038BD6BA743F96BE5BD23CF9A8D847C5755F29411C972838D2B3CEC2B5DC8241C905B5BFF003EB4FCC58FCF1F979F9AFA45BDB470DBEA3E63D675CB68140E5026A2EC544B4EFF00150E4BA2F0DB17FF009F7DFF00CE324FF963E63FCDAFCFEFCCDB44B09FF4B6ACDE5AB8B8F84DBC31CECCF23927F6C74DB010CB81F96DF9DDF9D7FF002BE3FE7253CE9F98D6F74D045A7CCD65A2E9970D50A9033C3CA01414E4054E56436C616CDFFE712FF28FF257F327CF9E6FF31FE72FE7149F963AB796353B69BCBCB6F75F56B8942307356F0AE459786FD51F38F93BFE71CFCE8D7B3AFF00CE71F98B48B4344BB5D3B5DE01005028483E032A32A3CDA4E2277A79DF977FE7DABFF388BF9C724FA9681F9DFE67FCC6BB8EA6F35A1A8ADDB0A750CEC07864F8C745E0A7D95F97BE4CFC8BFC81F25FFD0B3F99FF0036D7CCFA7F9B4496BA47977CC577EBDF4905C8A0B58A951C00FB2B931913C07B9F1A79AFFE7DDDFF003895F947E615F32F9A7F3CF59FCB2D465BD7B8F29DF0D405ACB64ECC4AADAB863C4A5683DB26269AA1C932B9FC9FFF009C6DD4E4B4D31BFE73E3CEE249C520787CC4435C9EA55985795326770C385F15FF00CE607FCE3DFF00CE35793FC93A9FE677927FE722AEFF0035BF320CB15BDBE9DABEA02FAEAE854A30AD6A780ED95C837C075A7C55E4DF31FE71792B429EDFCA5F991ADF923465E12CD616174D00776151B2E634B6673887D0DFF38F9E6FFF009C92F3EFE7CFE58F92FF00E576F99F50875F9E3D66F2CA5BF77A5BD9C80C9148A76A3807614C8F38DD72712517E82FFCFD9BF3BBCF5E43D53F2BFC95E46F376ABE50D47CC9A7CBA8CF75A64ED0168E297830629BF6F1CB9B7146F67E4949F9B1FF0039096D688A9F9E7E6F8AD66FDFCB72DA8CA013ECD5AFE382DCA9C283F6FBFE7D73E78F3479EFFE71CBCEFAC79EBCD5AC79AEFB4CF30DDC2BA85EDC34F27A0B192A159EA695A9EB8251704737E2FF009DFF003E7FE720AFBF30FF003022B5FCE7F34697A7DAEBF7D69A7410DF3A2450C729F4D68294016836C31A05CD8E332890C035DD5BCF3E67D574EF30FE64F9EEFF00CECFA07C7647509CCECBCF614AE4E73586911714D00BE54BA9663752A97D3E2AFEEC022A6A3E5989293951D3D2B5AB7A48ED5FDAFE3862584B1BEBEFF9F69C9EA7FCE75684C3FEA4ED647FC933991170F2C69EDFFF003F6FDFF3EFF26475FF0070139A7FD1C60916A897C11A8C06541DF8C9CA998F22E5C0A7769767EA8B08FD9ED9448B971679A34DCA08E393ECD77C85B75DB34B4D4A5D2EE2196CBA0209A64245CAC6FA93F2F7F32121B8B35B9702BC565AFBD3DB220B64F93C6BFE7316D6CB516B1D6AC183B3AD5A9F4E64C0BAAD445F9DD35A43EA99631F13EF2FCF2FE275A614A6E782D075CBE05690E243D3DF2EE882BC0E79596B937C78ED819479378B2762AEC55ACC79736D1C9BC4312578CB43592EEB920C097F5CDFF38D9FFACE9F905FF9AE3CABFF00748B5CB87260F6AC2AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF864BB048AACD51DB311CEB4BC2B147612EE01C56D17621DC0AC98ADA65E8307525EA2BB8C124129D5B45D38F4CA501306040229D716C8A58E28E49D862D88571C9F6DC629548E36A8DB154D235AAD08E9DB1541DC42687E1FA7154A1D5D0F43BE282A91C8E0F4C58F0A3519A9BEC3B62BC2B8891BA2938AF0B21F2279EFCFF00F94DE7DD13F323F2F2682DBCC7A3AFA3682ED3D5818B1AFC51F7CBB1CA9C4D40DDEF1F99FF00F39CFF00F3963F99305EDCF983CE163A19D22DDC48BE5D88D8BAB28AD1F89353F4E5DC40971E9FAFDF975AC7983CE1FF003EDFFCC2D67CC3ADCBADEAFAC793AF6692F6F5CCACAEC87A96F0C9476B5A7F387A7BE85A5F97E686F0C4B71A859A08A7863264776DF812A09AEFDF240AD3F707FE7D29F951F9A9E58D67F327CEFAF794AFFCB3F979E6FD06D2D74586F289F5A962209786B4A13D6A72D06C289D3D0FFE7EADF9D7E75FCBCFCB8F2D7E4FF95F4E9747D37F3126922D63CDB6EA5623146D510C6CA2AAC4FDADF7C494F1EEF91AF7FE70E3C83AA7FCE05F92BF3AEF2F5BC95F997E5B8A7B89B5A998AC37BEA48591645EA49A0A13EF9592D8323E2BFF009C7CFC90FCC1FF009C9CF3F6A1E5DF285F695A3F99A0478754D4EFA15781907C3CD50EF5A6F91B6632ECFD44F20FFCFAB7F26BF2AB40D53CD9FF003943F98B1EAF1E9122DD31D16E0D85B451A7C6C6757AB301DE83A60113F0419DBEF0F30F9D3F2CFF00297FE7157CDDF985FF0038E51E8F77A2E99A34D3E87AB584002CA507C25DB882FDF7A647C2A533B3BBF9ABD5FCC1E62BDBFD3BF38B52F3E1D5FF00332009E6CB79656692289588A59C486BC597C06110A62723F717F317CA1E4DFF009F8A7FCE1B683E61F29DEAA79DFC9B6E93C371250BAEACB12ADCC53746E24D763921162676F3AFF9C76FF9C4AFCACFF9C2AF256A3F9DDFF392BAF68DAC6BB25AC8348D2EEE1F56DE1050845489C37C66B4AE4B8D1C4FC98F3C683E4FF3F7E6A7987CE9A0F95AFF00CB7F97BAD5E493E91A34D227AD21690B17B72BF654D4103C32B3367E3523BCC3368DE5ED38437CCF631C29EAC4D72DCC48631544A0AD49A532A3BA7C6B7EAA7FCFAF3F21AF74CB6F31FF00CE577E62D9AE9F1EAD6D2BF93BD61C560D302B7AF32F2A5140527135F00C38ADF0C7FCE507E6BC1F9E5FF3923E60F3559336B1E4BF277ADA2792A590F34B9B5726B3475EC1AB91F136761A7C24EEF13D4A2B98216F556DEFED9374B08928CA3C0D76C7C47272E2D9FB2FFF003E9130C7FF0038CDF98534B0936D279BAFFD6B75D8AA08A9C7E8CB89DBE4EAB83D4FC42B8373FF002B0FF346E6C618E5B6B7F36EA8E7D75E4157D634041F0C864950761A68F34C66823B9FAC35E7A572978ABF0C0BC42537E99852CCEC052AAA97948E11B154E30923E3000EC721E2309CC24B3CE90432F3902146A3D4F427A65F09383972D3EC4FF9F65C7327FCE717971E44204FE4DD65E13D792F03BED9990E41D74F2713DD7FE7ED2449F9FF00F92E10F22FE5F9CA7B833E5732B10F862E5828B84A5655AD5331E45CBC6126D3AF59262937EEF7D81CC79172E2F55D2984B0523352AB5DB204B918E36C8F4C9E559024919604D2A72B949CA80A679663EAD494CBE9348414FA32024DB241F9EDEF35FB18ED9C35C431A101FA819938E4E0E585BE39D634AB9D26FEEA39A268D2662D096EE3DB2EE370E5898E354B6FF7E6463938D38D34D18D88FA73281D9C5915363C7A76C8940709053734381B03B9A78E2AB81077071575478E2ADD3C329237656EA1F0C900C495DD865803592DE4A9812FEB9BFE71B3FF0059D7F20BFF0035C7957FEE916B96057B562AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF86BB8802C67311CBE240DB460B32F63B1C57899159D94483A7CB15E25595139003AE465C97891F6DF00CA9215659878E2D914A669013D6A7B62D81411BE21E18A519137BE2A8C57A6F8AB52BD57DF154A6615A629014E35DFF008629A469140B8AD2262C5682DBA92EE182EA4897D5B636D227A6366F588F8581F6C944B46585BF40FF00E70A3FE70BFF0024FF00E723FF0029B5BF3279AFCCB2E85E6CD3F54FD1B7D1CF7CB1F2A8279716604E5FC449B718C2BA3F4B7F3B2EFF00283FE71B3FE7103CF7F9456BE72B18EF350F2ECFA4796A059D267BDB87144850231219B975392053E1DEEF8D7FE707F47FF9C0DF27FE58699F9D5E7A920D17CE3645F4EF33E9FE629BEBB0472C5F6A58ED983503B74A0C9DA38084AFFE7217FE7E75E7BF365C5E7907FE719F438FCB7A1D9BB245E63302FA77D68A6A9F554D84551B9A76C78E9A678492FBA3F267F36BF20BFE73B3F246D3F2E3CE2F6ADE69D3EDE14F3568B7AC8B7B693DB95E53432C86A3D4707ECFBE0333C988C469F327FCFCB3F353CABE53FCBAF26FFCE267E5CDFDA3C1E60317E9B4B77594D8C5624344ACC8763215A1191E3A663097E57797752F3AFE5FF9C6C7CCDF943A9C9A0F9CF47B37B69ADC3304BA5917E290814069EF94F8AD834F27D89FF38B3F927AAFFCE6FDA7E64798BF3E7F37350B297C93A92E973E8C3516B68AE39C65D8B46CE015A8A5732465003038E4FD4FB9B5FF009C5EFCACFC8DB6FC88F3D7E61E976FF96F73A61B09B4D8665F5F8B1DCB4D11635DFAD301CF148C322F85A05FF9F51FE534B65AAF9524BCF3E5F69779EB5A587D6E6BA592E54502399556AA41E94A644E701B069645F0D7E4CFE707E71FE4DFE6779E7F353F27ACA7B7F2BDEEB5777FAA7901F91B67D325959D04716C81E8C454657F9A8B68D148F47EAA587FCE5D7FCE207FCE64F97A0F277E7DD8CFE44D68148A2F29EA333219A56D898E455E2373B03F7E40E51F51E5E4C65A390DBABF3FBFE735BFE7193F2E7FE71D6EBCA4BF931E6B9F599BF306493F44F97BEB7F5C7B6892AE2854B05A8A0C81CA48B3C9A8E9A47A24BFF3851F919E41FCF8FCE08BCB7F9D5E708F47BEF273A5EE8BF97374C527BFF4784AEC676A2B2AF75EE36C1C6472EBD57F2E62FB7BFE738BFE730D64B5BBFF009C5CFF009C7DB8B4B9D4AE02D96BFAD6931886D349B68C7096D02A1E279A93BAED8F89E9B972FBDC8C7A49134FCD7F2F791E1F2BD8A68176E65963AD2F474AB6E687E67304EA2CBD060D36C9D5FF00962CDEC2E4C7290D6F197694577A7CB271CD6DB9F4FB3F537FE7D471DBC1FF0038CDF9836D79756F682FFCD9A8A47EB4F1C6DC425391566046FE39B033B1B793CF4F170CC03DE7EF7E383E88DABF9ABF332F6D2329158F9BF538A57471C64549295DBED5731F3CEA2ECB1E2B0B64B2FAB6DC295ED9A83959F8450935A7AA80863180EB571D695CB2191AE78497A47FCE3F7E527E5A7E66FF00CE4DE8BF97BF9B2B736BE4AF3858DC5D45789762D544B6F1928399200E4453E9CDB69C931BBE4EB73E120D53F757F207FE70C7FE718BFE71AFCE927E65F912FE4935C165716D61ACDEEB114F0C16970A04CA23671527C4666125C2188F73F2B3FE7E3BF9A5E4EFCDFF00F9C87FCBEB2FCB3F30C1E6A87C89E5FB8B0F31FD554D22B812972BEA74AD08CA67CADBF1E3DDF31DAC4D05A3A188C69337A8439E4E1BFD6CC69173A18924F4C0BA048EF98E4B950C4F51D01855631D5C01954E4E4C31D3D46DF46944493053B8AE63CA4DA229835ADEBC6A5222C22EBB64449245AB5B5C4A54C33C541EF9938E4C4C2DE59F9A3E5C4BCB14D4ADE3DED50AB53DF2D949A32627CC778E915B014A4B5A1CC8C527559E348462CA23AF565AE6C22EB25CDCA390DFB64CB3839A315C836114B7D35C50EA53618ABB155C1C014F0C8916825AF572403025BF532603025DEAE5822D64BFAEAFF9C6B35FF9C74FC823E3F971E55FFBA45AE0661ED78A5D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF881BC880420F5CC3E20E424B0A857A1EA4ED8F12B24B50B4218D31E20AA8F08670CBB9ED809B0A39AA03C41076395F0B604BE5662C6870F0B30504E1C9AD31E165C6D29E277FA7070B21205171354FC382928CF8A83E78D2B8D698D2A12406B8A625A8D0D7A6D8B2B45B23300145698AD85F1EDB1EB8ADAA4A225884FC4CD3AB045B6AD0153D5BE8C429A2868F47BB86133689E66D47465BDBA56BFD32CEE6585789FB529E0402465832531E005338FCBB6FA84CE751D4B53D461B17E766D79772CEAF20E8C15C9030F8BDE98E11D11F0795F499EFEDAF6F2C266B595F85D69026222007FBB997ECB57C30F8C19F83BDB33B782934292BC7E8C4ECB672C2823F4231B2D78815DB6CA67985B64710EA91EA7E5A437115F68D25EF97EEA32FFA4F52D3EE5EDCDE06FB3511914E390F1E9B3C081768DE5FD3ED8FD72E26BBD7F5E0DB6AB793BCAF427B1724ED909E7B671C1001E86B6EF2DC590922A49044CAFABA1E2483FB240DF7CA8E50DBE0C52883F2E6D4EB125EC771AA59E917959750B0B1BE96DBEB128E858C64549F7CAFF3738F271A7A404BD4B4AFCA0F20CF6D75A85CD86A90996129159DE6A12DD0527BD5C9CA726AF24F9B762D180ED0FC95E5FD05E19F4BD0603769271769155C18BC68475F7CC796693B0C7A50F52D3ED674B48A28163B4912E1A66754142ADFB0C0751EC72BF1A4E6474B163FABFE5BF943CCB3DC5D6B1A12EA3716A39D98B522DA49246EB491402299911D4D7544B4B1287F227E4F59E81AD5C7992EAE2F3EB112D346B2D46E1EF7EAA0FDA0A64AD36F0C9CB59C5CCB8FF901D143CF1F94BA579AAE96F74992E3CADE648DAA3CDF6933C721435E6948E8DF1034EB9286B047CC2FF2782ED17F2EB4DF2AD9BD969566F737F74419BCC533F3993F9B9330E4C5B213D582092E54745188D833187CB62EAD134DB88792A75D40F53FC73046716D98F152B4FE598AD6DD2D6CC85957EC5CB0A807C48EF96C753109CB8F886CF269BFE71FC4B7D793E99E62D5B4A17B5B899AC6F26B783EB2E7E26F4A3206F99B1ED1A157B3A89682E5C54CA34AFCA7D23CB5A63D9C76B2DDDC475996F4C86AD3B7DA771FB44FBE5597571946ADCAC7A7203CF75FD0E64998087A1F8B35E32370D384AE0D338C0E49F4DD47C2C45687B6646292CB00609E67F2EBEAF0D8DC5DC93DB6B36CFC6DEFEDA5689E28C9F8802BBEE336DA7CDC2E0E7D2C65CD8A6A3A0EA36B2B45A7F9B35FBC8C7C715BFE91B85141D57ED77CCD3A814EBB369611E5F794CB42B39B42944DA3DD8824D64F3D75661EACAA4ECCBEA1DCE512CE1A2189EBB1D84090ACF0C6C2D8AF0F58B16E4DF2CA279A2E6431A0534EF527AA2D77CA2598391114CF346D3E7867B762945E42B944B286FC71E3E4FA7F44D352F2C21089CCF115DBDB293305B0E0932587CBA3D27458E8CC3714FECC00B0F0A439B17D4FCA324619C2D3AF41FD99930986420C0753D0A76B1BCB59D39C12EE58F63965F1726196161F1E79A3CB8D63A8CFCA32B6FC8956CCBC669D26AB1960ECBCB91614543C53E599F09874D381054A46F4E95D81E872EE265034A4F2F1343D698096C26DAF52B8A1557703155C411D462A8377F888AE203592B79FBE48062EE7EF93B6041772F7C9713120BFAF7FF9C68FFD671FF9C7FF00FCD6FE54FF00BA45AE066393DB714BB15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8779E6690D0E6BDC86E0B62C55A9D0D6B8AA7B1454C555F8814C473508693A9CB59A5E480C49E98AB4CE9E18AA1A465236C05945742699536F1047092A078E2B61716DBF8E15B08391B7AD701482A9130DB026D16ADB1FD78ADADE4395715B5CC6A062A9859FD93912D914FACBEC37FAD95C9BA09CC1906F8A6B0A0645AF8E565124EE5B5E56640EE320531482C21F4EE0AFF29DF2B9330CEACE0F56829B9C8368E4CDAC6C8B24629D3205B22F49B3B43FA35969534C81722095DBD8BF3A50F5CA8B97065B6766FC7EC91909392190E9DA51E60F1A6F539510D822C94E9842EE2B4182922294BE9CBBFC3DF1A6D10413E9C95E9808D9918A3AD6C100A53AE505ABC3569B4C47A10BB8C57C3455AE9E00E9D714786EB9D2B9A3F14DE9B62830A0F10F35689708F3388C77C945800C0A1B0924B69D5D00DF7CCCC658CA2C43CC9A64B085600D3332127032879C5F44D1D651B3014CBB8DD6E68EC9569E93493D373BE4096BC707D0DE5ED224BCD3238D81217E2194CE4EC2186C27B0F95E4120223E9ED98F22CCE9CB2BB2D12485E12E869514DB2B3272F498082FA3BC976F1FA31C6CBD80C00B9B2C4F5CB6D22065A85FB5D72C12689E35F75E5C826423D304E4C16838DE5DE70F28FA16FCA18FE12A4B003FB332B0C9A270A0F913CE5E598A54B82F0FC42BDB33232B755A885BE51D7EC24D3EE1A3E344EA332A05D2E68531CB9903428D5E99931710841897950E5A98F25656C595ABAC805315B5479401F3C56D2F91FE33BE4C354B9ACE7EF8B1773F7C55DCFDF157F5FF00FF0038CFFF00ACE1FF0038FDFF009ADBCA9FF747B5C9ABDBB15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88316FCCD45335EE42630C7C17891F11D862AAE55A3FB5F862AA7CC9751DB08E6A164BD4E58CD00D192493F67C71552654F1E98AA832AF6EB91290B797134C832564620D6BDB1557E551B1EBDB1542C8AC687016512BE3246C4E0656881228DBC715B5E11CEE294C56C2AD0D003D7B629B4CACC1A53B9C896D8B20B34655607B9A8CAE4DD04EA089F20DF14C63AA7153E3BE56512656AC0D9EFE1902CA2C7A01FE94CD4D89DB2B9320F44D1A22C54D36A641B43D174E882B0E4366E9902D917A259DB936C4506FD32B2E44175B598E7F677AEF95972E0CB2D2D502EE3225C90C86CA10A46DB6574E481B270E8A474ED8D360012CFAA73AF15EA71A6C0109258B03BAD3011B3202D523B609F6B314B2E04D22B3590034AD714702362B38D4D08A62BC08D92CE26864A0DC8D8E2C670D9E75E64D0627B39A4352789ED928B8A214F04F4608659A2058B96A71236EB97424C65040F9A34E89EC95C28AF1CC98CDC1CB17806B5108838E3DE800CB3C475D9216A7E5FD3A7B8B80238C31276180CD9E1C4FACFC9BA25D0B4F4DA1019539357C331E591DBE1C2F4FD1740FAEC9C12352E3AD76CC796473469D93DC796E24291B4604886A6991E2B6EC7800667E5DD3440E9F0D0786112672C6F5FB14B68E3024AD587C3B65824D13C69CA476CD41BFB6D9609B41C4A77FA1C17F6B22320208EF97E39B899A0F913F337CA4B6E2E0DBC436AD4D3E59970C8EB33E2B0F827CFDA605F55B851D76FD599B8E56E935189E113865050F8E66C0BAAC91A520A4003B66406B05554D3AFD38A6D706A1AF6C56C36D20A7738ADA14B124EF930D6D54E28754E2AEA9C55FD837FCE337FEB37FFCE3EFFE6B5F2A7FDD1ED726AF6EC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88EB5527A8EF9AF72138584000F862AB580622B8AAAAC0BC4B6D5188E6A1033851F3CB59A058A952062A876E3FD715506A74EF912BC90EDF6B2B5E254AD00A615E25367618AF129FAA5B6F0C0520ABC75207BE0648911B1236E98A11A88C314DB60126A7E8C59C135B35DC644B745925BAED95C9BE09EC0BF08C837C559C5181CACA24CA6DC7A9694F6C814C52DB7B73EBF4EF95C9987A5E876C788DBB641B4727A3E9B685DA314E832B2CE2F46B2B6263094C8172609D5AE983903E395972E0C8E1B001694C8C9C909A5A5A8AF4E9869B849363682831A6626BA2B44A7D9C69B04D42E2D12A76C8C86CCC4B74B4DA1AF4FA3304B7DA6F69684F1D8605B4CC590AD298ADA30598F4DB6ED8944B7093EA9610CB613A9515E27F5620B488BE60D5F4C486FA62ABD1F7FBF260B19063FE62F4CDA08EA2BC72624E0E58BC2354B0E572DC96A9434F9E4FC470B82CB37FCB4D05AEB534E70FC3CBA91F3C066E5E2C54FB7B4ED02D6DED144680394A1CA2537678A349BE91A6AD9CA5F852BDF2894DC8B013A36A269D98AEDDB0464D9020B26D2ECD232A4AF4CB049259A5BAC2FC435053A659C4D134E3D3B7420F2C989341451B988008879061BE4E33A71F246D83F9B7CB36BA8E997521505CA93FAB32F1C9C2CB8DF97BF9BDA0BD95D5CC623A0DC8FC336584BA6D563A7C937D66DEA91D2873658CBCEEA0520658FD26E077D81CC98F27094F0AB44818ADA8B362B6B7AE4C2BB15762AEC55FD837FCE337FEB377FCE3EFFE6B5F2A7FDD1ED726AF6FC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A0B7896BB6D9AEB72116C388EA3DF1B553E05BEC918DAAA51C2F1E43082A94DDF21DF25C4CAD2AA495D8E3C4B68696564D88C78D6D62B926A41380C946EAA2367351B0F7C8DB2F0D50055346618DAF86B1E30C2AA7AE36BE1A82A146F886C7A6048852696F172DE98A784A64B1AAF5EA7A62BC255982D0D06F8AF0950E209D87CF10120F0A696686A36C0436C66192DBA1DBA6552722124FEDE2240E9ED951939312AB340C29B8391E69E1B647A78ADBF1EF4C8908BA46DB5848CE1C5284E57209137A2E836CCC428A5477CACB744BD434BB378594BD083E1954A5BB7443D074EB477A11403DF21C4E5420591431716F8874DB225CA8C29378D4505075C8916DDC48BB65A374DB0ADA6C232C36A615E3A44288D054A934C5B233B509551C6C0D7232E4DC0A10C04B0D866010DE3284DED6DD956B4191B65E222429077180C93C48F8684712363913365CD21D4D084954746072226BC34F9E7CCF02C124EED4249DA9F3C98935C9E37AF34B2B829F647519306DC3C91B49ECB467D52EE2855284EE49C375CDA31E2B2FA6BC83E4C86CA38E568D79F723227239F0C74F6EB4B13EA0DA8A17A1CA897240A4E96C569F0819598B2E1255C5B46801A6E3AE08C59C2242716691BF414A78E4D914D2283E3156D97240B4C85A36508CB452464F8DA4C54EDA89255892064E32B6990A446A33A3DABC22B475A0CC9C73A699C6C3E1FFCF3F2C7A51C978C8ACA63AFC3D7B66D304DD46AB1ECFCEAF30DB98DE4923015549DBBE6DB16EF2FAB86EC2259FD56E46B502999575B3AEE02A7CC7BE4830229631A9F6C242A91563DF224D32112570141BF6C226B54B4B81E3878969776AD7256B4B4B01D8E2B4FEC23FE71977FF9C6EFF9C7C3E3F96BE53FFBA3DAE4D0F6FC55D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A889788DF6CD7539086B99B8D6871A5538666618D2A20C8C0548E98D2A0E6FDE0A8FBB1A54BC2D1E871A540DC805F7F1C6954F9704AD37E98D3387344464BAEC298D37F120A6B794B7C24E34BC48A855900E5DBC71A5E257DA62140DD37271A5E24C625E031A5E256049231A5E2452AF2071A5E25F1435AEDF4E4834CF74CAD63A1F6C816706456895207BE51272E0CAADE1A2034E994C9CA8F25EE9C8D298C4ECD80A75A5C7521299125AA4CB9221146AB4F880DF2A2562CC7CAEB59D790DAB9025CB845EC16F10E4B45DBC731E5CDC880671A58A28DB22E6E309C2A0E75A77C5CB099451A918B021116F1FC74F1C5253A48A806D8B54954A2D3F8E2D9050E0B5A78E097272A28848158F4E9984425191A0414CAC8641A6A02476CAC86C0BD245515F0C810CC1A63DADCE1629187864405E37CFDE636699A6205687A64C313BB03B7D224BFB9E012A2B97458F876F5CF2D792A38E786478A8DC7C32333B2638A8BDE749D320B481005008194B7009FC50C75D862D8023046A0785316C010F20500E29A57B324134C2A426292B066C0D642A3CAD4A62D6421C5C145624EF5DB2C816B942D0525F173C589A65F02C0E379AFE66E996FAAE8570B40CE10D3F0CD9603BBACD5637E4D7E6158C9A7DFDCC0148018FF000CDE603B3CA6B31EEF25039027DF326F7757214D85F965D171A4E2BF2C99601BE3D3A65127231A9323576E9910C64A0C8D920C56A96AD0E58155D0035AE495FD83FF00CE337FEB37FF00CE3EFF00E6B6F2A7FDD1ED72618BDBB15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8A8F54702DC7305BD2695FD57E9424E2A898542F520E2A887914A15F11D71542A9AD452A7C7154BA7942494A6F8AA5D31323020D2B8AA22180135770569B8C5944EE8E411D28B8B6A1979198A114DBAE2AAF28F4D775E55F0C556DA71E4E7895A8C551EEEA829D7C062ABA08DA46240A0C55341198D6A472F962ADC13A92CBE99153D7161229DC101A06AFD19596704DECFED57C0F4CA24E5C198DB30740A053DF2993971E4ABE8947A7DAF7195B34F74A819650FD457A64496B3CD99C712CF2569C41A6C72B25B718671A0D9849148A139025CD84767AD58C01D5052847539496E8C7765768521A2952D4F0C0E66308812564340684EC3172404CE1734AF86282138B70052A7AEF4C5849368D948F0F6C5AA4B1C507DADB16D8286E7BF4380B9314744D4ED98A42551989208046F9590C8284C5BEEC810D810AEEDC0F6C8109972633AD4B5B765A9269D7234E3C4BCC24D39EE5DAA6B53D31AA72602D3FF2DE80AB74ACEA0EF5A530F139508BD86DECA389A3E294A0C04B394682747E08C7C3906B015ADA60E7885208DEB8B301184D462CC0404A18EDCA9E18B346D8802B5607160423FD440C7DB162434F32018B59096CD729E1B6374988492EAED549A0CB2326528B1CD465FADA3C4DF65D78D0E6CB049D5EAA2FCECFCE9D1E2B4D6AE233462E49047BD3377824F2BAB86EF96678C452C89D402733E06DD0E6145439004ED991170A4B8508AD29932C03741E19449C8C6DF25029C77C8863258789FD9C218A1D901AD053BE5A154591BB1A6495FD84FF00CE32FF00EB377FCE3E57AFFCAB5F29FF00DD1ED72618BDBF15762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF89F0E3D33BE6370B90957306400773B63C2A893C9057A531A5414B39AF107738D2A6360038353D31E154BB508584E08FB23BE34A81F41BAF8634ADD1B74AFBE3C2A0A32D41F9E0E14F1353B32CAA4277A63C2BC49B7C0D082CBBE3C2BC484A537514C785789A1148F22D477C78578995C16E91C4848DC8EB8F0AF122B8464531E15E2524B74120A0EB919041DD3B55548C6525BA2BAD1AAF41E3BE5127320CD6CD78C60D329939514DA35E681B8D77CA645927FA70008DBE79592C3AB2FB280C8E1E9B1E99025CAC4377A3E8500E6A4FD39592EC71C5EA7A75B5694E990655453A11716DB172F105648A86A7BE2E5008C8F614C58108849CD7AF4C5A64994539D8E2D5269AE0B122BF2C5B20A911248AF42712E5453D8A9435CA2412BCD011E195C83243CCCBE34AE564360404C418A403C36C8D32E618B5E219BE06DFC31A6B1043DBE9C88EAC57E795C9BE019569D6D142438503DF2A2E4C4D0653115722831059C8D84C245063E98B00142301771D7BE2CC05766DB16C010ACA64AD0D08C595226D548A8AE2C486D890C77C5AC8519588077C2C084B26734EB954CA46C92DC826BBED8C249914B48F8C0FA7365824EAB54762F867F3DA0FF738E69DBFA66EF049E5B56777C797AA05CCBB53739B5C6E833F34BD97AE65479B8325C3651932C02ECA24E441AA0C88632688184315608BC47CB2D0AA4C8BE1D724AFEBEFFE719F6FF9C70FF9C7E1E1F96DE54FFBA3DAE4C317B6E2AEC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88C69196127AED9570B9096DAC8649D09D80618F0AB26963050B571E15484A8697C287070AA610308CD41AF88C3C2ADCF2ACBFB1F11C78556B47C63E5C7B74C78552891B91200E27C7052A6FA64609DCD70213292D95E4A70A537AE0295CF6C586DB64789544DBB12AA13EC9DCF8E08CAD53386D49A129C6992B545CC68AA03538F6F1C6D54EDCB4A695C6D5368AD893CB9F4ED913BA2DB9A42B48C0DBC72A945BA324C34BB33248007EA6A4D328945CB8167013EAEA13EDD7BE5243951927DA622C90056D8D4E52609326436500120402BEF95CA34DB0C76F41D3AD38471ED94C8539B8F15335D2217F500029EF95172E269EA9A7A88E38EA2A69BE066237BA6E6207E2AEDE18B91134E238D3BF862DE26AF1C7CE9BF1C549B5AABF11F638B4C8A3D361F2C585371C7CBE2AD37C52364CED5796DE180B7C7226491D3F6EBF4640B3E25B27C3DEB4CAC864248095B96F5A65526D0508CFB78E479320503E887979D694ED9599B6844B5B86150DC699519338A6F6E802019592D802776D1D5280EFE3823CD289766E3403A65BC2B6A28581A15A0F1C7859892282961B1DCE3C2DA0A998985487EBD4E3C2C81B5D1A322B1E75A63C2B24BE49DCB9DBA63C2D6A4CEEFDE871E16B2859A1928183D699465145318DA477AF242A0D0B1390894CA0878F9B3A9A54115AE6C7049D4EAE3B3E30FCFBB7923D45AE78F2AEDC7EECDCE1C941E53571DDF1B6A16ACB3C8EC69CB7E3F3CDBE09ECE8B34774918D0D3C333625C1986E95EF97736B6CAD3BE5320DD02B9412064445245AF1193DF080BC2B0AB02464C15E1586363DF1B5E17F5F3FF38D029FF38E3FF38FE3C3F2DBCA9FF747B5CB03597B6E143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D98A8B7639072125B39544C3E78AB27797F75F462A948156A62A88A30C554E163F584E5F67154E27E0D0D075A62AC7648CA82701546E95381285F7C8143339230D1864153DF2252A0A08201195211D0C695078D7C718F34A39A48047C76072C548AEC8E69C0D41EB8AA63A7C144E647CF154CE175AB8F7C082B1A1F524141D4E466CE2CA34AB6F488246F98F37331B2066569157282E4C59269F6CC5D4A8F848D865726639B34D32D97EB09C865322E6620F41855508551B28DB289976100C974992928A8DF2825917A04120E2A7C70B743927B6EDEA003B62D88958F93118B64516917100E2CC287A7F113E2716B3156040F9628E144C4B45DF7C578530B55EB812228A1CA83205B5425E546C8499452E7E54CA4B70429EA3C32259072FDA39410CC146A005699021B01B4CD015400E4086C0532B7978AD46301452792351CB76CBD00A2163E54DB61BE2CC145A41B74A571660AC922A0DB6C5B6254516BC875C5050BF54E4EE695C581287961E1DBA62D64A02694468478E63E50CE058FEA24BAA9032B8865296CA5C9A28E33C7AED99D846EEAB57C9F257FCE4246D0C493B2ECDDE9F2CDCE11B3CAEAB9BE25D56759642C050140299B6C01D0E61BB139012C69F4667E37026BD010287AE5E1A951BF865726C8AE465005722DA15D5D7EEC2AA9453BD3AE2AEE2BE18ABFAEAFF009C6BFF00D674FC82FF00CD71E55FFBA45AE5A39349E6F6BC28762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87EBA9D962318514F1CA2DBD2086568E74237E4DBE36ACCE37F5223DB1B543A8E2F5EB4C6D51AC57D3E58DAA5F50581AD0D76C6D5305E4C8057E9C6D5053A108C08DBC71B5405BAFA73F20DBD712ACF6C6E8AA54A06DA943912944170E6BC403E195A15D2E022BD5474DB0412C76F2F19A4214D07B658AA96FCD8835E7E3ED8AB258A65861DE9B8E98AA5E977C653C68C09A9C5053DB39C33A92A0E426CE2CC6DD8351BA517A663CDCCC689854B5CA6F9417262F56D06C8488A37F63944CB7445A791C0F0DE2A28A8AF5CA497371067F6567249C7634A7DACC79173E316496561E8C80F224E524B221964638A281BED930D914DECE765A7C35C2CD3B81F93569D4E2D91473B6DD3166146353254D29BE285850F2229B62AAE8EE9B7018AA6768F4EA3AE2551ECCA83C72B2C908F286AED909328A11C8A74CA4B7041484006942476C052A51824824532B21368F8EB5DF61E390219829824818053B656436028F80A82141AD71884996C9BC4AAA011BE588053355AA29A52A77C5B01560CAA37C5982879248DC30AF4C59C4A0165547206F5C524A3519284FF375C5AC940DDAA052791C5812C62F1BE02C054A9E994E4512A414BC1EDD5C8A1F0C8C53C4E6712A20540420AE66E1165D76A4ECF9B3FE724B4F79FCBB1DD2C615947D91ED4CDCE10F35AA7E736A49E9BD1CD0F1155CDA61E4E833F349C0A0E43E23E199D8DD7CDD52DF115A13DB2F0D4D9A93D32B93645408F888AD37C8B6856403BB6154482B403962AA8154FED9C55FD75FFCE35FFEB3A7E417FE6B8F2AFF00DD22D72D1C9A4F37B5E143B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFF00FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF876BBE87315C8485CF160DE06B8AB2DD364F561FA31555941018E2A88452D01F962A955584943E3B0C5538B771C77FBB156AE1D1D4A8EA70C552A02928F9E48A197589AAD3DB22528D63C72A4202EA7288287AE304B1A7959E5A7BE58A9D5BCAD12123BD3156E5D4491C4B6F8AA8C37039160D5A9C50591E9B745A5515EF909B38BD1ED5FECFB8CC79B998D3AB14E57287DF282E4C5ED7E598D43A46DE198D939B918D92DD411A5DA35075DB289173F10675A5BC7E94629BD331E45CF804DE8CCD551B786524B221388549550763DF2D8F2484DA24E00649926D6DDB16C8A3DFA62CC23ADE35E35F6C59D34235E67DF15A44FD5C374C569AF4590EDB602B4BDB91C8162A251B7ED909328A83A353AE525B8210A357A6053C9B58DC6FC71402AA0B1143B7BE408660AF5661DF2B219828BB695BD51BF6C88E6C89D936FAE84E35392620B23B5BB8E48802462D81AB89929B362D80A5227ABB0E58B3057AA826BE38A928D8CA804571604A1AEDD781DF16B258E3CF17C5191CB91A8CAE41ACC964482E3946A9B0ED8C42789A82CE732B2AA1E20666E1145C4D472795FE7CE96F2792E591A3FB009CDC610F39A97E4E6BCE5EF64A6C17E1A7CB3658DD06A39A5F08063DF3371BAF9B7407A65E393535C4572B9364541E262C48E9916D0B789185555436D8AABAAB53157F5DFF00F38D5FFACE7F903FF9AE3CABFF00748B5CB472693CDED7850EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87BBB5531935DF31E9C863A543921B61ED8D2A6FA4DD324A200070AD2A7AE1A54E75173071F4C0656FB44E0A54C34F904B0716006DB61A54B2E222B72A00AA93D7052A342468952C41231A543955506452491B50F4C2020A1A83D415385871325D3E4F8B8F6E38299DA6373444E4BD7DF0708674C7EE1E4956941B1C1C20208A4BE38BF780B57E8C076502D386904501E00134E87236C8458C4B2C92CA6A00DFB640C99885A3AC80F4E466635076C788B194190E94DFBE06BDF2066CE117A759CCC4AF4D865129B9708B35F2E446F2ED44BB007F67283272A317B669F69F5495668EA76037E998F236E4420C87D2378E1CECC3F972B21CA86CCC749B3A471835AF7CA65172A136530C25187C35CAF80368926D1C2397235A9ED92029B446D328E20C37AFB6165C29A4302A01427E9C590D915C1586F5C520A362015401DF167C4E650096A9AE2BC48A85CED418AF1225959874FA3015E25AB6EFD5853293265C2E3180694EBB642526622AA2C95C7C24D72A25B4042B69D3A49CB882A0EF91E25217B5A3FECA60E363C28792D66542C62F8475A6478923642B46C3A46D8136B6349C3AF08CF23DCF4C40DD0648EB9B19446B21A863D874C953113455A7AB1A0E47638D33135D7771E9AFDADFDF1A6CE341C127AA58D7A0C04536C668E499D76FC7032E26A5BBE20107AE2C52A9EFA490F1DA98A0C6DD691722CF4E4D5D864A301269C9B328D32131373F4D4D7AD4648630A192470DBC70BCC8A0DC336E87A53333144071353C982FE6C68306B9E45BF515F552363C53C7369843CDEAA443F147CC3A4CB6DAC5F5B5C03188A4603E55CD96301D2651658DB22C5550DF2CCB8389382C415515CB9A0C5771CA6452154283414C900D814E445180AA9C6C4B71A6C3224A53058C507BE438D5FD727FCE36EDFF0038EBF9063C3F2E7CADFF00748B5CCA8F20D079BDA70A1D8ABB15762AD374C55662AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AB97BE2ABB157FFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8749E4AC447B652DE9347F131A77DB1557B6AC3386E9BE2AC8AE5C5C427F9A9B62AABA7B98D4027154C4C625607BF6C550579CA31C7BE2ABA08CC916E31415268087C5AD34B4E51B03F462D8134B97E51FD18B68415AA076901F0C05126A5B602A5464648097CC484653D32B6C4A963A927C7BE565B62B91FD30E3C4E218493CD1A4E532FCF2126507A969FBBA8F1198E5CB83D5FC9B6D5BAE9DF292E541ED92A18ADD683282E54026BA2C2EC39B0D8644B7443D0F4C8D782E5527222190C71AF31B641BC04C52104834EBD316F8A67142076F9E2C9305B72698AAB0B638AA323B7341B62C9CF6C7154C2DAD136DF154E560840F703014851692255F88019410DA95CF7766A08E601F1C810C9049AA5BC469EA8DBDF2B21B0228EAD1488C88E3938F872045325B15C4951591720C11C2E55455DD597B8C55DF5AB56EC98AAEF5ED88FD95F7184319206EAF2071C3D41926210735CC7140A43D77ED8B20C62FB52E4E141F6C5B137D2C92189E8C36C05B2298CAC1109C8B3B486F2EC28DCECB8ADB1A7D7218A5E25FA75C56D33B7F355A5BD393800E5B02C08B4DD3CFDA7A2D0381F4E49908D2D5F3FDB199B8C808E1B0AF7CBB1C9C6CF0B4A0F9D67BAB6BFB49B7826560A0FBE6CB14DD0EA30597E74FE7368325B6B97B7B04748A51C811E273638A7B3A2D462E12F9DA60F1BA07EE73371C9D76514887015A83C065D6E21E6B7204A40554FE1841D99A9C9D701296E28F7AF8E564AA37A0CAED5FD707FCE36FFEB3AFE41FFE6B9F2B7FDD22D733A1F48683CDED39243B15762AEC55A6E98AACC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5572F7C55762AFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8739D15050D6994B7A56838C8A53A72DEB8AAACCDFBCF87C7154E2DE86024FDA036C551B6EBB6E37C551F1CA237523B763EF8AADBF40F1FA83ED1DF156ACE5E30D0D3962828D58E3937A5716B5748B7A1FB23A62D817CA6A287718B68528488CB15EF80A24AE5CB0C8C9012BBB4F877CADB12C8C1DC0CACB6C50EC84B1E58B0927DA3C6038206F5C849941EA7A38F526507AD36CC72E5C1EDFE4F83D39B95329939507AE9ACD1A2D3E119417371F2659A55BFA70F151DB225BE219469B190429D88CAA4E44427D6EAED3053F6720DE032686D01A6C698B604D52D1788A038A5328ED8F15DB6C5518966081B7CF1555312203418B2433E2ABE3623BD3155579F82925BA024E2AC5AFF5A8F81A380720437304BEBDB89598A49F09CAC8641266B8946E646FBF2B21B436BAB4F1FC21CFCF2B904AE3ADDCAF499BEF394B05875FBCA504E7E938AAD5F30DE29DE7A62A887F32DC471971354F4A610C648287CCB712CB4692B9260190C1AB4D31285AB45A818B30EB6E7753FC7B8AF6C5B1E81A7C451197A055DB0499DD35773908DB8DB22BC4F3ED56EE5A482BB0AE2BC4F2DBFBB732B166A11E18AF124536A2EE4297240E94CB20CE25080DECB25217600F8EF8934D9619058E9FA9F2462599BB1DE9928CF76899B67B67A56AB7118528294EC3336191C2C98ADE51F9ABE4D9A5D3EF649E127D0879A353BD333F164D9D06B70D17E7FDFAC4CD70B30FDF40E4474D86C7BE67E2C8F3DA914972492301EA50B77CCC8C9D613BABAEF4AE025B61BAB2004D3240ECCCB6F12D2A7224AAC0FC7E8CAC9558F3B76A7CB236AFEBAFFE71A8D7FE71CFF2049EA7F2E3CAA4FF00DC22D73610FA47B9A0F37B5E490EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87FBA8BD4048194B7B1D95BD16A1EB8AAAC3FBC353F3C553112FA6A476C553AB12255A8EF8AAF9E321AA3B74C5549AE015F4D8EF8AAC4AD76E871414E6D7B138B5A6C801E9E18B6042DC6DF3C5B52DF50A927C701449176CFEA353B646480985DD972841A74195B63152BC1C8EC0E565B62A4D4635F0C430927FA42FEF07EBC849941EA7A0445AE51BB0EB98F272E0F7DF2E22D40194C9CA83D12CB99611F5DF6CA0B9F886CCEB4D0C38AD3E8C89E4E44597E9F0FF00A415237DB2A939116530DA8F5850641BC06490460103C31649B2C6B4C551491B6D41B62A8D446A0F871569EDCD09A6E7164817B73BED8AA1243C176ED8AA4379764065AD6A08C55874D652DCEC95381B9520D0AE08355241C890C9171F961E43464A8F97F66565B0233FC191B293C7E2ED954F932E88197C9A00E998CC12CB8F2B8B78DA5E05F8761DF156297F6621AD206DBBD31563176EC6328B0B29AF5C218C90964D289B743D724C0335D3999E52A548F8716619DE89680B863D716C6573968D2918DFF6A980A4A4924C4F20FB7BE4516C475754653C37AD6B8ADBCDEE74C92791A83A9C56D42CFCB5732CDC1622E09EB4CB22764893D3347F216E924D1F1EFB8FECC848A99BD2EC7CA9630AA82AAC7AE40163C4CA6DF4AB5800E2829F2CCA84940619F99FE5A1A8F937549EDE1065F4986C3C01CCFC52D9D36BA1BBF1A35FD2CD96A5A84338E327ACDC54FF00AC7363864F27AD0C6648CC52943D466C205D213BAF4C9B978BBD156E393D0E36CA489BB4E2A3B57204A1219A52B5C892A8749F91A57A6564A1FD7F7FCE346FFF0038E3FF0038FE7C7F2DBCA9FF00747B5CD9E3FA47B9A4F37B6E4D0EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88FE09E89206F986265C86217D18790FE1928CAD5640FE91DF2684C42ACA093B8C2A9DE95F01A1FB3E18AA6578547D8D81EB91B4A41229E7CB2064847C0EA29CB718612B2829FC7E888EAA37F1CBA835A26DDD016277DB225B0284E19CD17A65664DA103242114B30EBD30192D5AAE9FFDE644C9908B241CE489D4EE00E982D980C4F50B52AC59453DF06CD8024EBC91B89EF9125B238C1E6C93493FBD51DB2B914F000F5FD094ACC9C45052A731E45B601EE3E5621A401B7AE504B9B08BD5ECA14AAB22D189EB98B3951765860299FE9502D15996AD90E22DE22199E9F6D1FA9EA71F8CD2A7236DB10C9E1894B82474EF8B626B144ACE7E793114A611464B713D3C325C2153A8E3000DBA0D8E0E10AAAC0A8DBEFC7842AAB0F86BED8F085B40BF5C7842DA577708E2DC0531E15B62F3E9EF2B13C490712026D1765A5246DFDDED9512BC4C892DE355A7015A656496C125C88A29F08CAC96F8C95C01D29D72B2CEDC638DBED2D722634B4A0F676EC0D23049ED9548522987EABA7C6C5FF74BF2A0CA49626DE75A8E99C8B462314AF4A61848DEE903BD278F4708F511EF5CBEC32E109FDA69C435553E223AE3B278598E9903C34EC3BE1B09A4E652163241F88F5C8C9B211058B5DFED6FD6B9149800C6258DA4675AD47718B510A967A6C4CFF147518B512CE74AD3ECADD59961018904138AC4B2B49232B420500F9603BA69689A388D176AEFD71A452256FA9FB59206992716CF16A9A65E69B3012452C6FCA33DFE1399FA736EA759B97E31FE70E94BA6FE656B564578DAA3B3431781A939B9D3879AD6403C655A49EB34E794A5882DD36068336511B3A1C9000AA00074DB2B9158121176E55483DFBE52665CB8C6C29DF5C301B361E22A62C6E6766AF235C9B02104B38434069878583FB10FF9C653CBFE71BBFE71F1BC7F2D7CA67FEE4F6B9B087D23DCD079BDBF248762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D8DAB09F719801BD8DDC8A4849EC77CB2294B5C736AA9CB1531B69285636FDADB0A19143FBB5AD7A60554F53D45627B602942BA77F0CA8A143D4DC01E38C0D154FE02C621E19719288A362069F3CACC9B045308E2046FF007E5664D822A7731064000E991253C2A7A7DB7EF3A64789908B2BB5B6AF30456B8F1331143EA7A627A65A831E26C1160A6CF94D41DB6C04B6C62CA746D3099936AF8E5722A43DA746D302F134DC65132CE01E9BE5C88ADC5076398F22E7630F63D1A20F22A1F1CC69F376388507A3D9C3C19401F4641B87366D610D29B6F8B6C53A4401C7862CD31B789CB123A65A392A610C3273C2AC8228C71507AD3155EF18A53BE2AD32EDFC715413AEF8AA19A307AFD38AB696D19EC36C0555BD140360065549010B22D180F7C810C8158401F3CAC86624B3991B9391E16C8C9DEB0C4C5B4168DC8405ABD3299452C72F6F1199878E6398A6AD875ECAA5C90054E400A4F0D2053E371B77C3C48643656C6B5A6D4DB1E254E12260BB63C4AB5A195C30F0C902DB89239AD253CBF56499C9237B57491B6A16C5A24995AC0C083DF16892730C8D1EC72405A225182E881D70F0B2B51376A49E477C7856D512ED36DFDB1E15B649A15D1127C3FEEC0CB4FA0E6660D9D6EAB72FCAFF00F9C90B196DBF342F66238A4AC493F7E6E74E5E73561F394A156460BF66B9B2076745946EA7FC72A996B886BD42A72AE6E643925D7331634C980892493DCFDA51DB6C980C4A56CE49D8E4C06A7F645FF38C1FFACD3FF38F1FF9ACFCA5FF00746B4CCD8F20D079BDCF248762AEC55D8AB4DD315598ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC55D8AAE5EF8AAEC55FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D880E040E87B66006F492FA2F88803AE5914A1C5B7186BC7E2F1CB108781585C46CDBAA9C2ACB15E3684803738154955A35663F6476C05285594BC9C6B55AF4CA8A157D052E2837C8F567109CDB3AA808D8993688A6B0C44B0A7D93DB2064D8229EFA01635A2D09CACC9B0456081581F86A720649E15D6F6AC1C7A6BC71E26422C9AC6D242D535A63C4CC4532BFD3CBC068B534C789988B036D34C731F82849C789B04597E8765C654257204B121EB9648B18400509198F32CE019C688A82652A286BB9CA497371F27B068CA81D582D0F8E5122E7E3E4CF6CCF29D2BD3C322DA39B36B4AF3F84D17B62DB14D56A5B03364368E811011BD284E5D1E4A9B200402A389F1C2A8F49102AEDBD3738AAE3221EA31543927715DBB62A82949036C550F473FB471556457A801A82BB9F6C555E458A31549BD4F639021925B35DB80CA2DD189E8DE190216D45EFA38AD889621EA53EDF7C810C4C92A4BB8DA29A46958B28F8129D72206EB19A0D2EA607D53C9D3F9299618B68CADB5ECB7069E87A71D3E2343944E0DB1C9691DD7EF83F01C58577198F28B609B1B78A560C492483F6B299C68365DA2ACEDDCC82BBE55C28675676A0AA80BF1531E154D52C588E98F0AAE5B1707A75D8E4A21B71A12EF4F2A84AAD0F8E58CE4C4E6B26939A96E2F5F84E2D1256787D2B16319E52C42AD20F018B449E6F79F9A5E52B099ACF51BD4B6B984F16151BE5916B2692D93F387C822A1B5B2BF223254BC4BED3F363F2FAE24A0D6D9B7DEB4C697899345E73F28DE11F53D5D2A7A02C31A5E2665E5DD574C9264F4F555256A428208DF2FC45C2D46EF833FE7278423F31E36DA482653507A13439B7D39741AB8BE3F6565BCB84635556345EC01CD903B3A2CA374422214625457B65536B8849677605E86832500E4C521B8B97527E3CB00625262EEECC791DCD7260312B94E4C06A7F64DFF0038C1FF00ACD3FF0038F1FF009ACFCA5FF746B4CCA8F2683CDEE7850EC55D8ABB155AE683E9C554F97B62AEE5ED8ABB97B62AEE5ED8ABB97B62AEE5ED8ABB97B62ABB15762AEC55D8ABB15762AB97BE2ABB157FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88BB53C866006F5971082E0D3BE5914A16E00488FCB2C42550D19E83AD76C2A98DBC844BC3DFA6054E2E29F56603BD3014A4515564CA8F3423C5C0420F7A65726DC7CD745704B8232B25C9AB6490DEA22A6E2B5CAC96C8C593433ACB1AEF9025B04535B4B70E188A1DB20649E14FAC6C55985464789970B281A7848C328C3C4D9108EB6D3DA78DAA2BB63C4CC063B71A3137205325129AA4EACB4A68DD6829824C4866305B32B2023B663C8B38B35D1A03EAA6D9492E6630F56B106109951E6E6C59D69DF100D81B073673A6FC4AA69D7BE2DB14E917E3C59A7D6B6C48461D0EF96C792A751A711BE155C57DF157703E38AB5F4E2A849BA62A82798462BBD71541B6A616B5AE2AC7F51F31D9C1192CC63A77C910D8C02F7F30F4BB763CB520A57AA93FD99590C0B179FF003C3CB167270BABC593DABFD99590D04A47A97FCE48793ED2A91852C47C27DFEEC111BB59953CAB56FF009CAA82DEE78DAC21A3AD1401FD99710C2390DA5F27FCE4A6BFA821FA8D89E0C09E407F665120DF1C858D45FF00391BAEDAFAED776C556BDC7F6663C839519BE91FC9EF3EBFE61426231805D4B961ED954837C256FA2AC7437AA9E3F4655C0DCC9EDB4C78CD48C3C0A9DC160481515C1C2AACFA79A834EF8914DD8D0379A79E1F7E06526177962A03963C585787BE2D1248D61963B1D453ABCB1B08FE74DB16893F32BF313F293CFDA8F9AB50BE8209A5B79A4668F8F402A7DF32314801C9A64C462FCACF385B6D73A4CF2D3BF13FD725B215D7F2EBCDF34CB1D9E893C751BB713D7EFC7657A0F977F243F30A7991E4967B343BD09A7F1C695F5FFE597E526B1A5DBC6DA96A0F34CAF5662D5D89E9D7251E6D1946CF1DFF009CCDF253680DA3EB11356474EBDFA1CDAE9CBA0D587E7F593C9373965D9DBAD73640ECE8B28DD16A7E07F1ED954DAE218BDCDC0124895E8694CBB1F26F88D9239EAE4E5A031921F8D065803595226876EB9301ADFD94FF00CE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A0F37BA6143B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88D8294F845330037B52D4B29AF7CB2294AAF6BB8CB152D8D5830A547CB0B13C930854870DBD7C72122C2253953585ABBE54496C4A1BFBC6F9E441552641238567283AD7F86322299E306D98F967CADABF98AEE2B5B3B62C8C69EA01DB31CC9D8E385BEDAF227FCE2EC17515B5D6B32155900A293FB5BFBE5129B9F8F102F43D57FE716EDA2B988E9CF5403EC76FF89663CA65BBC10F25F35FE476B9E5FB932C687D193E1555ED4FA72066C7C10F3E5D0750B0B8F4E5571C4D0D7009A462A6616D632491014AF11BE59C4CFC20BCD9DC4428B551ED931309F0D012DB49CD59C50F8E094BB94C02636B1134F1C8711699C53368A452A791E9B60B6BA65DA0C94750C706CE442DEA763229E15DF289F3765879334D35C55476F0C8B7B3EB023E103618AA7D18AB0DB02DB27B16F8554F6197479330980DDC006A3C30A551862AAB18046E31545718986C82B4C585A57716ACD5E228322B691CDA75D716F8493BD32B2516F3FD674BD4DCBA4523A73040A1E99124A5E3BAE7E4DF9C35F467835BBB8977AAABD3F8E4F88A402F1CD4BFE71BFCE6F3D06AD732B576ABF5F9EF82D9D16357DFF38C5E757A97919DFF0098FF00B78B218D8A5C7FCE3179D43F22BCCAF4AFFB78F2639310E1427FD0B379CC48ACF6EBB1EE3FB720723891C459FF00973F203CD715C436F39F4A0604391B536F9E4253722185E97A27FCE37581BC59757B812AF2ABC2C6A0EFE15CA8CDCA8627D4BE51F22F97BCA10C49A3D9C5048ABC4B462808EFDF2A9CB67271E3A2F52B68AA828287C72102DE629D5BD9B4AA07877CB835909BC569E9815CAE4C0AAB428C0D08F837CA81B402424B733060D18415E95C2DC0B0ED474F6A973B835A0F0C5B0C424F1C216A196B4C5A6710105736314EDCC205E1B103BE0B21C59C2F9249756B69103CE352464F88B5F865298A6B78A5A450278D699602BE19661653F35154070DAF8659369F7D0DA144745FF4821547BE46CDACA1B6EC37FE7263C99179DFF2D64586D926BCB088C826A55C0E2C7AD7365A693A4D5C03F119A136BA9CF6922F131C8D191EEA48FE19B8C727439318B5194888DD21D890787B6DDB26402B080616EB44AB6EE6BC98F5C9844A21047ED1CB034C821DBBFD3930D12438DC9AE58D25FD957FCE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A4F37B9E143B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF889B535CC00DEAF28EF9645528BA1C8E58AA10C60B8AE2A5181789C045B590982FF7669E191314829431FDE36532D9BE22D52D2C9F52BE82D233467351F466365C941CCC18ACBF49BF21FC950E9D6105EDCDB2BD003C88F9E611CAEDB1617D71FE2ED0B4B8E21385E286813C0E512C8EC71E057B7FCCAD0EF6EE386270A76037CA2591BCE165F7369A4EAD6CF2CC527122FC209AD32BF111E03C475DFCB0B2D424966B78946E69B63E22F80F329BF2DEE609654856A17ED532D195071525571E49BB86BCD0ED93191071A437BE567442CEB4206DB6113B6AC90628BA7345395F7E98789C5945329ADB8462BD69D71B6BE156D224E33818F137462F48B49887515EC32B917618850679A4C84B2FBE06D7A3E9CDBAD76C5594DB8E4C3154E6D5C89197C32D1C9984DE13571852886FE38AAAC7D3154C228BBF638A6959A21DC74C82D21999882380CAD692C9ECFD53BA0A9DABE1919288EEE8ADE6B65F4924EA29838DC8F0D092DACA8793C8013D1BC31E36631A5773F003CAF01FA4E3C4D831B1E96F2047DEE86DEE72139ECCBC2B496EF568492A9722A7E798A7228D3282B5C489EAC373561D1413959C8DD1D3A274EB7964B80D2C859ABB2E40E46E1829E8D6914CC1226B6E117FBF48C8F1DB2963A65B6D6E11176AED96C0B5109D4238A82075CBAD810ACFCB8E5732D6425CED22568763D72B896043A38A39012454F8E49B6297DC5AF21257A0FB38B7249FA3958B6DF4E2D3916C1A423ACBCBB1DB22538B1F131ED53CBE8FCA87AE20B6F82C364D0258A60231C93A93938C97C047C505C5BAF43B6596BE026B6B0C976D645BED452127E583AB899B1D3D3AD2DC6ABA76B1A6CC39ACF6C63507DD48FE399D84D3A3D5C2DF87DF9F7E50FF0003F9EB50B20BC6970CF4A7F3B31CDB6296CE872E3A2F1CD4855D641FB4BBE650DDC7E4C4AE362C3C32C6322969FB67241A64876EFF004E581C7921C753963497F655FF0038BFFF00ACD1FF0038EFFF009ACBCA5FF746B4CBC72692F73C28762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF889B360BD730037A3E4A1E9DB2C8A529BB42C76CB10A50AF165A8A625211B55C622D8494E52786C77A8C998ECD60EE83BCF8AE9388A506F4CC2CFB39F845BD1FF2CB493A96BD68047CB8CAA6B4ED5CD5E59DBB7D3E3DDFA93A3D8B69DA6DABA0F4D1211555D8663176D8A2F2BD72D751D7353962B3321084B1504D32893B1C71D952DBCBBABE9EA26657046F5EF98F26FE009EE8DE78D5B41BD1CCC9344D45911892001DE99595107B868DE79D1B5B31AC92FA5310014069BE36930658D6A8E1DD40E128F81BC72C69945299F4A421AAA0D7C46581A0B0DD574359012117A1ED9312A6A9C5E51A9E83C2524201BF618789C69C58F5D69DC410476C789AB85274B5E126DF0D0F518F137C22CBB4752028356DFA9C376E5C0507A4E974053B7F98C2C9E83A6CA15803DA98AB288E7008A62A9AC2E480C3BF5CB63C998E49A42E69D4E14A395BA62AACADEFB62A9BDA5D536206D8B35F7373CA945A5720B4840ACDD09CACAD221232BD6BF3C84CA62375D2AF53D0E637139A12B9622FF0D49E5B6F8789B404A2EB492CA69DB071338B1A9BCBCCEE47106BED919CB66D88DD47FC2E3FDF43EECC4B6F115787CB8D1C8A40200ED902590A661A6E841543155A8F6CA8A788271E97A478D6A3C3082899B08E801D854E5F02E3109AA82A0153990C4869A471EF954CB590A2D2B32B0200C840DB54C25A4B89050903C32D6714C963F5A3DCD0A8DB16E4B64B295492010B5C5A72289825D8455A7ED655334DDA734BBEA32CA28687E782DC9E2583494460B201C9B71F2CB014F10448D060906EA3EEC9028E25F1796914F258FE9196C5C4CC2D36B6B45B53B2B03DC8EF97E39EEE9F518DF9A7FF0039C1E5223518FCCD15B8F4EE295217F9797539B2C32743A8C6FCE1BE9B8832EE55968066CF13AB9ECC50124B549CB4B594249D4E48354940F4CB038F2511D4E58D25FD957FCE2FFF00EB347FCE3BFF00E6B2F297FDD1AD32F1C9A4BDCF0A1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF88089A86B9801BD338CD40F1CB22969E30C32C420D8713B6291CD6D4E4A00B1C8B58D46E69979AA681CD40FC7331F019ABD4BB4D353E9EFF009C74D21751D692A952B535A78669C9DDDDE101FA397F6CB6DA3D360563A01DF2120ECB0B7F96FE5B8F503777862ABD08AB0EDBF88CA661D96309BF99F4A3043246918E9D8663C8373C0752D0F50796436F096321A37C35DBEECAE99458DCB65AAF96E48EF4A4B50C0D02B78FCB101127D05E48F375D6BB6612E418CDA850BCB626B4F1CB0071E6CFEE66658C7BE594E34C149A525D1AA3AE46450030AD4EC83B31A6F91DDAA51613A958D0F4A6DD71DDA845864B6A56423EFC6CB7C629EE92854283D6B9747937067DA79A32E4959BE9FBB8FA31564A83718153C85A8A9F2DB2D076660A6B136DBE1B4A354EC3F1C2AAEA4D3154742E148AF862DC119556C8324C6DE256A74DB2B28559630B95CF92421D979661B900A87A7BF4C0CE25B30F2ED8B60696C4160481B74C05B224DAAFD487F2D7E8CACC5B812EFA90F0032042D9575FDD0E23E9CAC861C454DE124FA9D7DB214CA3225673F4CF4CB62C885C353111AB6E3A65CD65506A91C9DB2120C0B6F771D36DABD7238F9B44D0E675AD69972628BB797D571C7609D716F64B58A587871DE98B4CC162B7F21D31F8769872194E45C7612F87519A46A274F6C886EE229B44E646066D9874F96482F116416C22E23A64D788A756F2AAC4151030AF5CC989D98917BAA344D37488610E0E78BE6AFF009C9CFCBF4F347E5EEA73BC5FBCD3E2661B54FD963E199D824E83541F83FAA5A1856F216D9ADA5650A7AECC7B66EB09D9D0E6D8B0FEA58E5E5AC1D9072F7DF2516B9287ECF5ED96071E4A2A773963490FECABFE717FFF0059A3FE71DFFF00359794BFEE8D69978E4D279BDCF0A1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87EB35F7CC572138A74DB2415A634196054B67900E44E487355B1CE38D2B96EC8282B9AB74F1CA665880A912F22CBDE99ABCE5CCC5B3EEAFF9C4EB113DD988815E25AB4DF6CD69767A626DF647999435D5A5BAB1D880403FC32B93BDD3F37B97962CD6D34832280ACD0EF414CA245DC621B30AD5A77B849A302A6A77CA2459494B4AD209812478C115DC951FD32316A1CD3AD5F49D15B4D91DCC3EAAA134655EB4F964993E64BFF300D235631DB30085C8F82806C7DB1453D5F45D7E4D52D54D6A683F56147084DE0BB3C9C4B4DB619645A728A49EE7799DFB1E992A68A627A944199EBD4EF8D2D30A9AD944BF3C6928AB440B28A61566BA79A30C559A58BFC43E8AE2A9F46FF10C55388EE00551E191BDD04A3A3BAA8EB8414A363B91B6FF003CB1B02312E47CE993661328DEB43E3DB16E099C4E38FF000C82A2606A656528D2A5C0A75C84D5BF4CE6310DA1A2877C890DB169537E99590E405754DC572239B656C98C511A74AE4E419C10D7111A1F7CA64E4001085780DFE9CC793090097CD7263A953F17860873681CD26B8D4E58EB5A6F97AC92A7BD9A405877E9938B4C9AB7BC9D09CB29A095433DDC8E4AD7010D68F82EEE0515D6BEF819C5368272159E9C69DF16F82223F307A4425457A62DD1016DF39D5F871FB4A28299092C804A6386EB4B928C84A9EE722C53D86EA3640CFF0068E2A98DBCF0D462A9EC13D221C3ECD76CCBC5C94A6B67744115CB1C2CE16F9AB4B1E63F2E6A1A4900FD7A090014FF00248CC9C45D06AE0FE76FF3A3CA4FE54FCC6D7347652AA9348C05283AB1F6CD96293CFE68EEF03BA6FDE483A10732E25A2B648E7152773BE5C1C69F35315000AE6445A96E5A036C407F661FF38BBFFACCFF00F38EDFF9AC7CA3FF00746B4CB43833FA8FBDEEB8B1762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF884B31D2B98AE426E47C3920A8694EDB6F9605482ED982BD01AF864952E86670D435F961B414D50730396D909A0370370B8907B7539AECCE5637DD7FF388F76A359642E05617A0AF7CD74C53B4D3737DAD359B5DEB30730410C280E63C9DEE9F9BD5EE3513A558B2745F4F8E5327718B9304B6D4629D679188EA69BE63C99496DDF9DEDB46B231B952D355547707C72316A1CDE15E63F38EA77F2C896933047A8A2939364C22DF48D42E6669E7E72173553D7157A56853DCE9A1622080682A715672D70DE9A3AB862FB900D72D838F991729E56E186EC7A81D726D2905FC25CA9FF277C558B5CDA9049A6D8AA95AA71931565567B32EF8AB2BB37A11BEDDCE2A9E46FF0010A9C55358CD40DF21D58946C792641191E58D811B1D6993661368998003C316F4D6273415E990423918D4532B294EED8065DF6F0C849513C465242789A2828720437464B553C7AE4087263255A002B4E9910376CB454520E3D69ED864DD0536219C0EA3C7289736F082BB1C50D3AF8E63C98C986DE4AC3950EE0E087368EAC3758BA99281493F2CBD125897130B346FDA66A11938B4C9111C92B15A6FEC32C0E396596B6D298D0AA924F51896B45C92C36A959402E3AAF7C8B6458E5FF99A0A18E21E9F0AF3AED8B7C5875C7984090BF30057662716F8A79A379A8C328726A95EBDB2052433C9FCC16DA94694515EE46458F0B514913505413E0315E14EED0C408E5F0FCF6C53C29D2CD1A2715229D46F97E33B302AD6F78A1BA81F4E4F89AA70B09B5AEA9CAE91030658C153FECB327149D36AF13F22FF00E7387C9B168FE686F3446800BE6259C0DAA6BDF3618E4F37A8C745F9A7786B7136D4F8B3638DD7C85256E09ED9787167CD408A66445A9665A1BA2FECC3FE7177FF00599FFE71DBFF00358F947FEE8D6996B813FA8FBDEEB8B1762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF884B33D37AE62B909B337C24788C2150E57E1396854A665FDE0C4AA4F29A4D5F7C802828E0F545DFC36C24A02E97EDB53C33132072B13EABFF009C5AD5E3B7F345BC6ED40411BF8D735F986CED34BCDFA88F12B6A36578375E20D730A4EF74FCD11E719DCE8F2CD16E6BC49CA64EE317278326AB710C14E5BF2E998F26526317AF79AA5F3210480A29918F36A1CD97683E45BBB86599E33C4D0D48C9B27A641E5FB0D360637340C47C18AB1BBFB6B494B7A43A74C550FA4A869DA222841A0CB60E3E6667058D09A8EBBE4DA503358061257F9B154A27D257D36FE98AA4034E546229DFAE2A9D5B5B22815C5536854290A3A0A62A9E47D302A2524A151E191EAC4A670CC7EFC90649847374CB1B022D26AE4D984E6396A06FB5316F098C6D5A64109A44C2A32B294D216A50D76AE4648298FAAA76C890805BE55CAC86D896F9656439112E26A322DD12A65C0EFF003C8C9C9C6D7D657A65126F086BA9818CF8E63C98C983EA32F10EC3C7A6087368EAC1AF2F19A4A7865E8936B7C562A1DF261A648ED37518849CA4DA996071E48ED7BF31F4AF2D69F25D4AEA0A834AFB62583E6AD6FF00E7226C2732CF030660C40A1FECC8B38A3BCB7E7A8FCCF6F73717527A224A7A5BD2B8B7C53237D1CC5E2AF348F7AE2DF1627A87E63C76529B0869198F6A0EF902D8032DF2B79D6FEEDC0E478B7BE4534F6FD0F5096499096DCE2B4F4225E5E1F175C5691261936A4DC76E95C9034D13E6EF425FF968FC71E26C10B08CB698D9D02B739240791AE64E29381AAC3B3E3CFF009CDAD163D5FF002CA3BF02B25A30634EBB54E6C71CDE57578F77E2BCF2195DE43FB44FE1B66DB0F27479051428EA3E79921C39A1E41B9F9E6445A90A577CB83745FD98FF00CE2EFF00EB337FCE3B7FE6B1F28FFDD1AD32C7027F51F7BDD7162EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF87DB371502A2B98B4DF69C13D01C90554E3B7D19312094A275F8FF005609482B1EB8DA6F964225055E3625900049F0C9A014D110167327C238EC4FCB31F240B938E41EA3F935A8FE8AF31DB4AB2846332802BD413D7303340D3B3D2C85BF5FF4FBEFAC6876376AC1C7A43E319AF90A77DA722D34B906FF00CB573DDC3120663C8BB9C4367CFB35ACCF70B0202CDCF751D466392999A7A8E81E5AB7F53D69286408A48F0C62D319025EA16D3456B0085221D280E499DA4B7BA7C9A99268691EF418DA5E5DE60BA83439191E550D5FB24EF82D52DD0754FAE6A30B28E20FE396C0868CA1EC8564540C632011B31193B684ADC1624914DF738ADA94F1A985A8C09A614816C6CDB92C4D3BE282295046CBD01C55150EC77FC7154F22208EB8AAB2005AB9162533840A75C21923E351B64DB0146C69B64EC3208A89CF2A5698DB784EA17D86F90B54D616AD28722529AC6F414272242AA2CC01153898B0E0368F4DC546FF002C818B6C415F46F7CACC4B9116B953A9A7CF20634D91284B89000486195483978C84A4DC7C62AD4F7CA241C805B966AA1DFB65120C64C33569F843235413D86463CDA3917973DEF2BA615AEFD32FB6264159AF9A12ECC85815D864E2D5229249E6048924DC230AD01EB9686821F337E6C6A3ADEBF6F1D8D8A4A07A8DCD97B838086145E59E5AFCABD62E21ADDBBAF26E546FA0F8E459C43E91F2CF96E2D234B68AE18C92C207A2ABB9F7C69BA3B2AEA725EDB594AF65138918100537C5B8178FE9DE5BD66FF547BABE57ABBD547B64241B4483E92F2CE8A6CE18A886A06E70527883D934189F9AB73E86871A5E20F4069278F8904D3C7052F105C6ED89AB392DED80DB44B9B5F5BFF29B23BB91090554BE113C4C5AAA55AB5EDF3CC9C4D3A88D8D9E47F9E9A41F30FE5579801AC92C51B32C23AD02935A66C71BCAEB31905F8377711867B8848A18A46047FB239BAC3F4BCCE7152418076DBBE65C5C19858EBB9DB2F8B4A1580CB04806E8BFB2CFF9C5EFFD667FF9C76FFCD63E51FF00BA35A65A393813FA8FBDEE9858BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF874B265328CA593246507853C72259C513C07139596D0935D28562721D5279311BC929375CBA1C9A24BE0B90268E872F8F26013B9650F1EE72126FC68DD12FDAC351B5B98DB8B472015F6CC2CE36761A73BBF5CBF267CCA9AFF966D6D24903148C0A66AB287A1D2C9EF3A5AA3C9FA30AF10FBD735D91E8714B6615AEF96C695E6084C43E0998548F7CA29A739B7B3E89E598CC6B3247EA19D0034DE996403878B9B2EFF095959C5F5ABB70AA054A9C910E482F39F3AF9B340D26C192C028B85560E57B900D32B21982F8EB53D425F345F4CD2A91463C09F9E565B014C740B2D46CEEC39AF18D870F964E0C66FA4B4DB8379651ACB27C400D8E5B17166956A21E262886AA456B9634F54B2332383B6581C8835E9301B8DF0144D690475C0C694FF6CE2B48F85C01F2C569188D520D698AD2650B50628A4D633D314D23636DBE58A8B6D1C73A62E60E49A44FD37EF8A53BB6906D8AA64241B6298F36CB0241CB9C9149B5ACC1471AD2BB656BB2600823AE40ADA1A7038B37865534DA493C828731CB740A4B3C94AD3AE51272E054DAE1BD322BDB2892C8B17BEFDE73E7D32B71E658826968D7264A7535C21A2D327D2BD40401D475CC88AA42FE528A69099146F99015747E43B157E7243EA03D0787E38C92194DAF9574C8900FAA8DBDB20C9CFE5AD3CCA812D40F1DB154F57C91A75C45536C3953C3FB714A4375F9736C2559628F804EBFE75C8948445AF97520223A74C0A9FDBE962CF7036AD4E2A9DA32BC746C550727A49B03912CFA2025B845DAA3DB20D40EE827B9574702868466463E4E55EC93F9C6E3D6F27F986253F11B4947FC21CD962745AE2377E0879810C7ADEAA87AACEFFF001239B6C3C9E3B55F594A17F8E67637026B24077FD796171D02EBBE5526E0FECABFE717BFF599FF00E71DBFF358F947FEE8D6999D0FA47B9D7E4FA8FBDEE99260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF861D3DE432034DBC72964CB565278537DF2259C51C6600152C2BE19516D093DDB13CBDF23D5279308D403ACA3623C32E8726892193D65742548F039911E4C03258F9B415E276CAE4DF8D49039755A94A1AD7E5989945873B0BEE7FF9C71F39AD95CC3652DE0EC3893F3CD7658BBAD34E8BF49F4D9C4C12F512944AAC9E39AEC90779872A6B75045AA442EA420CF17D95EFB653C2CF24AD9FF94B596B3B6953D1FAC49C6853BA8F1C9014D111458679F7CD173E94886630F20691FDF890DC0BE62BB6B9D42E984E8E6366F858F7A9C810CC1645A779360216644E04EF9510CC1640DA298978C49CDA9BD30C42C98F1D46F6C2F56DDB946A4F4CB22E3CDE84B492C83BB0666DF2D69EA81876276DB261C88372321620900D3A602C8A0E414DFB604521F73B8FBF15A5652C3A0C5691F1F2A2FEBC56933849A5295C569348C9D85715A46AB506FF004E290162960DD3E9C5BC724C627A002B4F1C529DDB38DA8698AA6AA4F615C5239ABA1EE72E6DB541280CA396F5DB2056D324B903E127E2CAD6D7CF23189FC29D72A9A82C7AE255E81B7F0CC72DF0293DC39505A9D3289B95028069DE9D0D3C7289A494AAE999D08A6F5DF2B699157B5B55600D37C21A93AB6B3ABD38D76DF3222AAB3D8AEC547CF3202A360B3429B10580F881C64C8223EAE9F6792FCB20C913069A240EC08057ECE2AEE735BBF02E062A8EE64C4C18862DD32254242E8166AB0A6F812A978C161AFE38AA412DD98E062AD52062AC4DB54B862C0D46E72126CE88492FE43B16A6443472288B5B8E714A7957A664636F32F4A035894C9A16BEA4D57EAD257FE04E6CB13A0D74DF86DE6D503CCFAE85DC0B96A7DE736D8793C9EA0DC98F053E199D8DC19B9CAD3AEF96171D06E2A76CAA4DC1FD92FF00CE2FFF00EB347FCE3BFF00E6B2F297FDD1AD333A1F48F73AFC9F51F7BDCF24C1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85DD35C96DF2964CB6023E1F9E44B20BA47FDE1DFBE5526E081BC7A2935E8323D527930FD45CB4887BE5D0E4D1253673CE1073223C9806516854C237CAE4DF8D12618E343336FDB31E4E66366BE45D767D175482E623455606BF7E61E58BB1C137EB17E5579EA1D734AB485E60D23280457E7EF9ADC917738723DF2D678ECAE638E75062946C7B6F94F0B9B1DD1535D496978CF6BF0C53281B63C283B21750D223D6007B800D7C7224282803E4ED387A4428AAE4086C05192E8F15BC5C621B814C810CC1632F697AB3858A22EA7A90322366576C7353F2BDE5CDCA4E632287241A26C820B0921B658DF7232D691CD4A5B431C6C476C9872209210DC8961BE02D94A72313B605E15200814C5695D6BBE2B48D4278A8F6C578531B76E9B62BC29B420938AD261E9B1FA714D2F119FA462D815D63DE98A53680D0818AA6F149414EB8AAE6980D89CB99F12D5605948EC6B5CACAF12A7D6292EE77C815E245CD755888F11954D416352CE7D43ED98E5BA086B89B92F1F1CA66E5C4A5D24C146E731E4A4A57713165F8776AE56D5229B69DCDA95C218B2AB5421AA4F514CC88AA37EAE5F71D33202A8C917A2373C6BB63264103FBB06A64A78E4192610DD451A37192BE3BE2A96DC319E4E4B21A0C551714AF1B202D514C894847CBE93A87D8918158F6AB72681074A74C55894D73C636538AB16B9999559972326D1F4A4C2EE477A1AD322E393BA716F70638580EAC4664636523B286BB2341E5FD79D8F10D6B21DFFD439B1C4F39AF93F11BCC8E24F30EB0E0D435C3107E939B5C3C9E6729B293667637126A2CB5AE5A5C7502BBE5526E0FEC8BFE7183FF0059A7FE71E3FF00359794BFEE8D6999D0FA47B9D7E4FA8FBDEE79260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85EB109D5771E394B24EE19497451D3950E44B208D724C840F1CAA4DC1037B50A4378647AA4F263B7B18AC6C72E872689206EC51A2653D32F8F26B08F82E48A440FEF295E39093918D3FB23F595759AA225EA7FCAED94172E299412FD5A2223FB75F8328C9172B1CA9F48FE507E663685756D0DE5D985C90B1A13B577F7CD7648D3B4C3983F4F342F325A6BDA35B5C3DC235D7006300824FE398C767698B202C860D46692358E54A18B704E0B05BA62D35B6BD77DBA0C890C63128A79D8107964086D102AC932B00246DBB9C898ADD2296EE2B643E8C425E5BB31ED95914CE3BA167D4A2991B946108F6C431940B13BCBC049111AD32624D3E19B4ABEB13382AC2993130DD114974E3892186F8DDB6092041DCD46D8AF12E6EA4D36F1C57897091456A715E2565993615C578C2656CEA69EF8AF104EEDA4407738A6C27B132151BE295540189A62CD1023351B7D38AA24232D0914C55148DD29D31559373AEC32DB544DB9A0F8BE9C812869C7C7C874F1CAC94B6F229000395CCDA84AA68DB996A6DDCE63B7C36414CE95A577CA66E540A45792D09DEA331E6C88B41C2FCE4006E7C32B6B9448DD9259C81283A64C45AF8939FAD3715E0475DF2E0BC4135B7BD2A9566CBC49788295C6A1137DA3CA9D4612CE26D8F5F6A9044A5AAAB4DF761FD723C2CE982EA5E7AB3B105566524D796E36FC71E15A63C9F9AB6B1D47A8A5BE63FAE34B4A4DF9AE92238128592BFBB507AFE39190544695F99324B308EE25A027615FEDC8D26DE956DA8C1A8C0662D56E831A5B63BA93FC7C23A927B531A543456723C3FBD4A313F86464D8262A90ADA70462426F91693024ECB5ADCAA0929448D8733E19763906194F0879FFE736BA343F26EA571EA7A69776AE96EDFCCC54803EFCD86298797D76404BF1AE617524D2CB74BC6791D9A415AFED1CDBE290AD9D1CE24EEA7C18F419990C81C498A5AE8C06E2872EE305C7A52E058ECB5CACEEDC1FD8DFF00CE308A7FCE35FF00CE3C8F0FCB3F290FFB935AE67C3E91EE75D93EA3EF7B964983B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85BD3BEC652C938B6FEF53FD6C89641399500ABE5526E090DF3B32B11D40C8F549E4C7AFDE4E31FE397439344905217668C78E644793584C2C406BA27F9475CAE4E4637A6796B49FAFD95DBA0E455AB94D5B951E4C7EF266B5BC6B775A50D304A2CC4D7C26EBD7496194C7E97C48D5EF985931B918B23EA0FCA5FCDFD5B48BEB6B6D4EF19AD9481F131A537F139833C4EDB06601FA51E59F3FF9775DB2B764950C8CA3910457F5E53C1C2EC6192DE8D0C7672422789AA08AED91B72E050F34C84A88C74FB59025BC6ED2C8DF3F0C899354A289496A8CBD2BDB21236CF0C50922D011E390A6E314BA4B22416A634D44255246633BF638D3021033905B7F0E996C5ACA0682B5C92AC734247E18AA8337BFCF1572B74FD78B594CEDA6A0A62D914EADE652462CC325B6605462D89B4282A3BD71668EE031558ED8AB68DD3C3155772A77C9AD2989950100E56534A46707A9C84969A1254D474CA8A40DD648F5539516D8A4B350354E5126F821258048390DC0CA26DF14B638945C71E5C4D3AE463CD728B8A6358E05E4641B75DF2C70F850ADAC5B16E0660BC4D6B5C9C53C0D4FE71D2ACA2224B95A8F7FEDCB578581EB3F9B1A3DAC4FC640C4D42D3C7EFC945B2029F38F9ABF379DE597D19DD63A9E95FEB926C7906A1F99CD71EA52E9AABD4127FAE2AC557F301DE46ADD356BE3FDB8AA656BE75BD915E4B79CB2A1A36FDFEFC8C9059D7947CED24B7F18BB6661C803D7FAE455F61F973CE960B68891EE0EED5F1C559347E6182E6752B106A9C55939B95940658F8823A64486A3CD0CEF5AFC19590E4C64A2FE9B2FA4C2866EDF2C9C22E0EAA5B3E40FF9CA7F308B7D046911BFC71A9F86BF3CCEC71793D61DDF9A864E681D8FC4D527375861E975929521B91AEDE399020E26492E33A13C5B7236CB40A68B4D2CE28A4EAB9600DA0BFB03FF009C6A017FE71CBF2000E83F2DFCAA07FDC22D73363C83AFC9F51F7BDB324C1D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85CD3C715A1EB94B24E228DC303B75A8C896514F44323C058D3EFCA8B70499EDCB24B5A647AA4F2492F638CAAFF91F6B2E87268925A5E07F8D2B48F63F4E6447935854B3E4B73327ED15247DD95C9C8C6FA0BF26AC66D5D2F6D22512486A287A6541C8E8C6FCFDA1A586A5710950B75093EA0ED936B32A79F192E1220A4D2A39291954A1698CD562D4A485158BB2C8A762329389CFC59DEF9E40FCD2BDD0960334F2B46E42F52694FA7313538A83B3D36A1F767917F3C6C350B782092EC06A00431A78660183B5C595F44693E60D3F558D7D39939103BF8E53214E7C260B295B66E21832303D286B94CB666775DE8488EA781A1F6C31DD944D35246EC6A23603B922992A64648A11A98B8820B569418D06B24062FABC2D683D4996887A531A6B25884B751B92C84D0F8E16050F57FB5514C285BEA57BEF8AA9B9F7F962AEE42837C5ACA2612716C8A3A17756152298B30CB2CE71C455B16C64115C28A55A9418B3470B943D0E2AE3206E877C55B57A0F7C5548CFC07C677C9B6D20649CB37C26801CACAAAC659B71D32125562DC76AEE72A2AB7983515DF2A2CA2955F3D15941F88D29944B937C1A8A4021F8CEF4CA26DF1631A9DD7A3C9D1A86B4C8C39B29724A9EEE49E3203354E58D54C4758B3D4562F5226DCB5363BE4E2B4C2A5D0754BE722494F1EF56396AD05A7C8B6654FD61CBB1EC7A64A2B4935E7E5C79767564907C4C3C324AC0F51FC93D2262CF6E7883526BB62A935B7E45D8FA9B9A927AE2ACCB4AFC83B510CCFEA705E42A323241677A0FE53E83A5C81A62A597C722AF51B0F2BE90CEA96BB1514A2F4C55153583E99708A895DF638AB2386FDFD3459051FC3034CB9A2D6E19876C8F0AF1D34D342CF1CA4F1FAA2B35D7CBAED9918A3BB81AAC9B3F327FE7257CD967AF79AEF2D74D9DA48E0E4AEAFB6E2BD33638F1BCDEA4D97C82C5D763D3B66E30C7D2EA66511000C4572DE4E24CA356D6126BFB44EF86D880C92C2CE20061E26F8C5FD757FCE3780BFF0038EFF90AA3A2FE5D79580FA349B5CCE87D21D764FA8FBDED19260EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85BB6F848AE52C9904352B5F0C896514D3D7E36C77CA8B704AE3943AC9BEF91EA93C921BBFB2FF004E5D0E4D124854D2198FF94BFAF2F8F2601358471B966F18FF0086424DF8DF5BFF00CE24D8A6A7E63B9B6715564634F7198F234E544585BF9F9E5A934FD775396342055B7FBB1136B9C1F3100C614E4370B96036D06C20E54F8078D72756DB09334D247FA1C629B9EF9467C761CCC597853D827BFD3254B8B6BE642A6A141CC09E27698350F58F2A7E73EBFA4DC470CF3B988951CABE14CC49E276F872BECDF23FE7858DD476EB3DD8694815527E5ED9893839A26FA16D3F306DEFE28A55911380A28AF5FC32318A99D2723CCC6F10233A229FDAC970A0E54AEEB5C834C9030BD578C8E4C6BDF1E16A395E4DE74FCD485A64B586753DB63FD98F0B039103A66BAD7D124BCEBCBC30726C89B4F45EB1A2F2DCE2CD1092357AE2A88F888EB8AA834850D3C31605562B923BE2CE2895B86AD6BD716613AB4BB7000AF5C5B03238AF8FC3BEF4C59A651DD934DFAE2A9925C57BE2A89593E1FA314C79A065763BD726DF4A22BD7E9CACAF0AAACC13BE424BC2E6B8AFC43B6545045209AFB8BF5CA8AC50571741DAA4F5CA64DF04BE7D43802AA731E6DF148E59BD77A3FD9AD4E461CD390D04F6CCD998C291BD32C71B8D4EE6D2240640BCD5B6E3FC72617898FB58A732E4045EF962F1A51A8CB688AA88FF001D77C9C59C656C3A7748E4E6D27C35AE49938EB9A728547DC8C55522D734F520C7154FCB154C63F30B49F0C44411FED29DAB91920A5375AAF2B9553217A9ED9157A77945B99568C1E05A8D5F1C559B798AC80B713AA0E406F8ABCDE3D44F221CD181A53080E3CCA6D1EA238F5C20346495060DF999E7087CAFE5C17AB2859EED1C15AEFD08CCCC31757A89D87E54F99EE6EB5CF30EA3A93312B2B311F4939B5C50D9D266365881B52546D999195075F38DABDB5A9EC3194DA2504F60B08D8AF8F7CACE4651C4CBAC3490C071E9E190395CA8627F58BFF38EE9E9FF00CE3F7E45C7FEFBFCBDF2C2FDDA55B0CDCE23708FB83A3CC2B24BDE5EC59635BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85884F361C76CAF8536C96DC111904D6A301816424D4A58C5C075A65462CC6441C41E1560CA5C9E80654765394525D76A423B31095ECD96E336D12CA18F05E69242AC0B484107B6C733230348134E0FC0EA6849910814F964278C86F84DF60FF00CE1AFA8BE6C997890CB5427B6F98594539D8657B3DBBFE720B44F56E352AA8320526BF40CC7E2A679214FCFAD422F413895A713C4E591CAE14F6485D8351286B5CCA84C14464F40D0A20D0C709A127BE3964006F88E264377A544A16AC797E19892C81CEC008418B78D5951D6BE04662642EDF164A099E9E2EED2E565B29CA1435A1398920E58D500F50B0FCCBD6A0F4E192770F0ECBC4ED4F7DB2996CCBF3024CDED7F37358E01259E4E245363FD991B41CAA7A97E61EA7771FA705CCD461B963FD98DB0F1187DA6A375A8DFA09E4919F97DAED8DB1337D27E58965B5B3854B971D70F0DB958A7419A457ACD2AB576F0C781B78D90C37CB51F153E79122990926B15CABAECE3E9C090B6491493DCF8E282143D555F1F962C86C8859EB4A57DB1640A696D24840DF167C4C82094556B5C53E204EA09169DF14F1A3A19949FB58A414DE27523ED8F962C816DD4788A0C9B68CA165630A41EB4D8E40848CA12C9E4E3FB5F3C810CB8D086E9551AB5395485053249E694B3F2076F0CA0C911507B8526B5E998F2986E8EC954D3879295CA8FA999CA229B69D6F1CF22ABF422A708853564D4090A6616FA65804AFC5CA985C7F1107776E2353E99A8EC3240AF88C3AFC4EA181A508E8327C6BE2306BCB3672F20635EA41CB319B6DC79186DFC7292CA49A65DC2DBE284858411732558B1E95C7857C5097FE9178643C5453DF1E14F8A11BF5DFAF71E6CD13A0A2F1E87E795CC5309660CAF42B41EAA34BFBDDF6AE52649196DEDBA3AC91C6A21554A374C1E2065C69DEB17D722C9A3908269D7263763E2878E3CB28B89030DEB52C3A53261C7C99022CDF47042D34AFC238FED13964604B87972BE3AFCEAF345C799357B8D2F4F98FD4ECA80723B1AD6B4CD861C6EAB3650F99E6B7BA8AF3882BE99D9877CD9E3141D5E49A0EE2DC076006C3265C594952DA2A76CAE450236CA34DB28E591405353D7316526F8637AF68BA242630596BB6527239718BFA78FC884117E47FE4D443611F91BCBAA07B0D32DC674FA7FEEE3EE1F73CBEA3FBD97BCFDEF56CB9A5D8ABB15762AB1FA7D38AA962AEC55D8ABB15762AEC55D8AAA62AEC55D8ABB15762AEC5572F7C55762AFF00FFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF858B4FB432AE36EF0D94C1F6457A77C789061488210F4C89DD81539220637E0C15E9F0B7865660C244524D756F13A52693D47F019761C6E31905B67E5ABED43F756D68EAAFB89E9B0A66C61065198B425DE8B7BA7DD4114CFD036D95640E66220BEC4FF9C378DD7CE37019830E62A335D99D8E10017D63F9B7A7A6A3AB6A7005E47D36DBE8198526DCA6DF997E77B23A6EAD25AB0E2A0D7200D38138B07922A10C33271C9AC459B79526E573E9B7602992CC6C3958B67A75E5A7308CA3A8CC493B0C692359B89375DF28C8E6C792BD9C6E26238E63C925131C00CEC5C5083B644C6D946549998D5694C1C0CB8D1B1395E31815AEF8F02F1BD5FCABE5F49D16764F8BAE3C0BC4F5AD3A16810474D94ED86A9CAC4764E919B983F7E25B814DE201A8CCD4272A93644A690F1029C8E41B0146FAD40003B0C5928B4FEF8A559273F0D4F862A9A5B5DD286B8109DC57CA08DF0B105358F50403ED7CF16C051297B08228F8B3051E9A8A01B3F4E98B3B6CEAC4FED64896622B7F4913DF205988A067BD249F8B204B608A0FEB47725B6CAA6526282B8BC201A1CC599445269AF5FB5731E4DBD17DAFA93480F63928868996716303222B74DB2E1071AF74EA3770295230F84B6A53B32AF23BD71F097898EDED5C1F871F096D8D4F0121885EBD72CC71A6C81B63B77A6990310BB9AE5CDAC12FF4AB80CDC50D0F4C558EC9A3DE3BEC877F6C551B65A2DE8956B1B52BB653910636F54D134C962319910E6290D9183D46C42C7C05295DE980067253D7A655B76DFB665422E34CBC8AE2ED959C0FB3FCD968838939879279F7CD7E8594D630B9591C1008F7AE5F8E0E1E49BE6986D2E66B998CE4C8EC49673EF99D8F675D96492EA9A6709AA13BE65C4B8336373E9D234AD45EF84968E04759E8D2B015427299C9B61167BA2E84EAF1931F5CC6939110F67D1F4BE318F87B65326F8BFA35FC955E1F937F94A9FCBE4CD047DDA7419D5E9BFBA87B87DCF29A9FEF67EF3F7BD372E69762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF855B670AC2A330CB984B2785D5A23C4EE46C300938D3C8037146EC0D640A57B1EA73271C6DC59E7013FD17CBB7FAEB98A106353D588EB9991D3B85A8D50112F59D1BF2CACE1557BF01993724E5F8F03A39768B3EB2B0D26C08B45317A454D401F16C3C732BC3D971F68BE7EFCC1D3E117D1DCDBB5631C8041D7BE60E78D3B9D2EB789F437FCE1B5928F37DC48C4A6FCAADEDDB35595DFE973F117D6DE76B8853CCBA848F19742AC38FDD98530EC4EEFCF4FCE7D0AE26D50DF5BC263889E5D3AF4DB292D5283C3230655657431B275AF7CB612A6A31A651E578C9BE1C5A94A65933619E30F7148792460EFB653273F1AF4B1ABB029C89E87C3289B9B16EDB4CFF004A3F0F5F6CC7924A3C6845A6E741D7A530C5814DA3F2DB4D4A2D3DE99246E9B59F955DAE230141A7B62BBBD7748D35ACA255DABE00615B2C9238C83C9969ED95973709D912B1FC4081F31912E48298C7C788D8E552660A2D08A743EF90660AA7A95D80E9D31656EE05BF6A98A6D772A7C35E9B62B6898A4E3D4D7145A244DDF9D315B442DD11D1B1640A3E1B84A8AB6F8B65A6D1DC42109A9E98B3077524BA534DFE5809724144FAE0A9A1A6DB6449660A02595BFDF832A25B0150FAD71DB9572B994CCEC8692E958D28731A4D112BE38BD42083D7B656D97B325D36D5415240F965D8E2D332CC15408C00287C732E107189B2B7E207ED5465BC010A95E638B0AE3C0150B2DB07E8B8F00543A699CF9D453C32328D3762431D138B54D18785320DE8693CBF0CE45502D3C7156E2F295B83560A47CB154CE0F2E598707D351C4F865536704CA6D16085032D001945365A47724C33A90A7805EA3C7271834E4C94C63CC5A8C0B6EDC9E840DF3371E375B9333C3755D61A4574B67F1ABE640C4E064CFBBC875ED367D4A61297F881DC9C988538F3C96A56DA488630CD1737237232D8871A52B492FF00449A798BAC3B78658254D2425FFE1E666DE2A1F9644CD90C6C86C3CBDC40AC5DBC321C4D831B38D3F468D387EEF7A6F9592D822CEAD2C5234038819596603F7D7F27871FCA4FCAD5F0F286883FE9C21CEAB4FF00DD47DC3EE792D4FF007B3F79FBDE8D9734BB15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF84F5A9238F5CAA50699EA135805C2D19413C7A0F1CA841D7E5D4BD77C9FE4C9F5955BAB9531A36FB8A7F0CDAE9B15BABCBABA7B25BC363E568B8428AD2D3E13B75CDC474FE975F9B54642929D43CD1733551578D7C3251C4EA660B1C79EEA4E530908600D30CE1B231715A437D65F5A82269F76DFAE6A75317A5D04097D2BFF38A5603FC513C69B50F519A5C8F59A4818BDF3F32C8B6D7EE550D4EF503E8CC4C8EDA06DE35E6CD274ED634C8E1745F5C2F2DC6FDB31645BC45F0F79C3499F4CD4E482088842DD40C6326A9C55BCB703DBDDC25B66722B97036C22FA334EB45963889EE06093998D91DB69F1FA87E1AE5191CD8F245DB5845F5ADD46512E6929EC1A746D253877F0C8DD2631B66365A3C2101283071B2E0641A7E9B6AB2F22A0536C7897813496D944AA517E11D71E35E0463C28C415E94186DB63B2E580602DA0AA88B88F6F0CAA4DA0B74A641902A65A84D3164D09A9D7155F50686BD77C55DCC0DB90C554DA6A54F2C516A26EE9D1B16C06D552F883F6B0330518BA937F37E3859834AE97F4FDACAC96C1345AEA15523976C812CC4D4DAF474E5BE544B671A88B82CD4E5D72124CA7B2AAB0E42A7BE504B18B23B331FC3B8C039B6B27B39A35A6F9978A2D190A73F5D8F8D2BBF6CCBAA71495CB728DB636BC4ACB301B8F9636BC498DB3ABF518DAF126255154103AE4265C8C25AA467ED0CADC97048491B0C5556910EE31550692256A823DF2B9ADD216EEF23E34AE5643194D846AFA82420B33058E952C72EC637703365781F99FCDF662678397A8A4D0919B2C7074D9B3BCEE7D5EC0C9584D10EFF004E6588389E2DAFB7F4AF4811906B80C11C68897479C39A3D01E8BE19514A9FE8B71F69B204A695974DA007803EF4CA8C9CA84764C6DED78EDC0636CF85905B45180BF08069BE368213650028A0FA3157EEEFE50FFE4A6FCAFF00FC04B44FFA80873A8D3FF771F70FB9E4753FDECFFAC7EF7A265CD0EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD0FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF85F8ECA6827585979C84FD919084FC474B9674F6CF29F906F35036D773218A18D833A95FB437DB719B1C3A1E274FA8D43DA2E0C763686D6D2216DC06CE3BE6D30E8F81D5CF2F11610F34D76CEB212EC8767CCC3300535006ED2AB986E56455F4CB03FB54CC7F1699CB7539675B32AB335030DEBB532B9E76EC1877633ABEBD05BC4817E3095DEBE39AFCDEA7A8D0E301F49FFCE3379B34BD275C3753CAABF58466DC81C4F875CD5E6C342DE931914F72F3ADEC17BACC9A94171F5A4B9DFD21FB35CD7CE36E44254F2DD5E40F74AC253188D3E28FDB31A78CB951C8F3BD4BCA69E67B826C23334CBD471FEC395F0D322049E6DA8F93752D03518E4BC89E28D5BEC95207DF4C2254C6389EA9A33F3B58E48979851B8C4CDC884699569EEACE6BD5FF000CA652722324EBD158255940E61BB6545927D6AB1D43EDBEE47865728DB644D32A8A7884600F0C1C0CC4ADAFAC952283BE3C0DD18DB27B39964B73CA3DE9F6B1E06C186DD1A90A6A77A9C9C62D528515707AED84848D950380A2A37CAA41902A4CC7B0FA3214CC490EC549353438190921A42AB53CB14F1297390814AD3B62B6A2C66F7EB8ADA8BCAE2B5E98AD201E46AFDBA62C97FAE07FBB2A7BE2CB89DF5C03ABD0F8E02CB8DB5BFE34F8ABF4E506569051B1DF7203E2C896C89561755FDBC8D3305556E7810FCAB4ED8382D24A252ECBB57A7D39138523252716B7C626525B901DB11869978CC9ACEFD64A7C5C72F87A5AE53B4DE394935E5B53AE5BC77B35108B8EE82903957DF229114CEDEE62E5566E43C3DF1663127705DC0A2B8B3181305D460208A74F7C05B618F854A4BF87C46001B2D06DA8C6BBF2FA3088ADA1A4D622029CFF001C9702DA17F4AC4C681BE23D05729CB1A5AB405CDD731BBF0F01918C2DC7C9B3C4BF35FCCF268FA60B6B78DEE2F27158E34AF434DEA332F1E3751A8C8AFF00959F947A8F9D3433AAEA90B5BFAA2A3983B75F119B1C717499A565BD67FE71E6F9B549EC74CD4B9F04E6005EE7B74CCC842C38E254C2A7FCA7F39795E57730C9731C7D5829FE991941B23240C3785A76B4BD06DEE22DA507B6634E0E4455269E35902A2FAA9DE40731CC5B8056F5410027D9FD939518B9319505E8CE36AE222C84938B13CC8A8E9D708091BA7885760570A781FBABF947FF0092A3F2C7FF00013D17FEA061CE9F4FFDDC7DC3EE78DD57F7D3FEB1FBDE8797343B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD1FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8D2F23F91A57BA4BFD6D6BC0D68D99B874D4F199B556F6FBFF00315959471D8E9F1AA0A7024019B9C18F85D466CD6C59E49EF25615E4332A52A0D50DCB2DF2D6856B70C52551CE43DF31324DCEC38B88D3D353C81A7CB0F32AB551E03FA663193B0FCA3E7DFCCDF2B2E9FEABC7B2C7E1F4E53293938B4F4F9C6F56297D485DF7198E64EDB4F0E146E83AFDC797196E2DE46AA9A00091D7E9CC6CDB876719D3DDBCB3F9BD24F2C31DE0DA94AB1FEA7308C1B0667B4D94D69ACB0BD12208D97E3151D3289636F8657A07911B4F7D723B3D2E146909A39DB7CC738DBE395EB1F997F96F6BAE687305B355D42DA332D55454D47B0C8F03938A76F86AD6E6EFCB17173A65F42C9F1955E429DF0183920B2BB7BC4616F2C5B16DDC65660CC165F14EB3463B9032071B30532B566E2C3B83B65538D1499526D019BBD6990E16719A6917C5DBA63C2DF19A6D6F7CB1008C7E8C785BE395344BA420107AE061396E881329C892A0DAD663C8D0ED9592CC054571DF2BB6C017F2B7FDA1BF7C2A8599ADE876DBBE2A82372A361D3A0C5541AE7155295D4AD477C52934EC6BB6D8AA0C87F138AA8307DB7380A43AAD502BB7865062DA0A3E1269D7A60A6C0510A5BF98E34D80ABA3316515F98C69369846687AE16B4C2075322A96D8F7C55328A7F498156AD31564767AA23108EDDB08544B5EC55DA4FC724C81444378A5A9EA7BF5C2CC14C92F401F6F6F9E06C1277E9458EB593AEC37C84CB6715A849AC27412F4F7C8829421D6A25AF292BE1BE580AA026D6226DC3FE39602A841AA52B2C64B329A0032AC82DC5CF9B81E8FA0797EFF00CC36DF582AC8AA3AD30C62E064D45B23D2FF002E746D666FABEB1682EAEE27FDDB915A27874CCCC61C0CB2B7BEC5E5C8B43F2FBD969AA96E889B050053F01997034E0CE16C3BC93A446D35E6A37975CAECB32853E03A665C25B38C63BA6F3C3CEDB526BEB5496201B83151EFED82526710F942FF00F2B62F34EABAAEA1631FA2F393450294A57DB31E45C8807897983488FC97713E9FA8CA1A624844277CA0B7C52BB760F0C4E05030A819590C81A45AF5C14CC14D74F6F888F0C7859829D237C58D3305FBB9F945FF0092A3F2C3FF00012D17FEA021CE9F4FFDDC7DC3EE78DD57F7D3FEB1FBDE8796B43B15762AEC5563F4FA71552C55D8ABB15762AEC55D8ABB1554C55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD2FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF911B5D4CA4450905BBAE74F1C603E6D3B48AE67FACCEA900FDE16A6D9682038A626D9EF97B49957795D99CFEC9195CE6E660C6F47B1B58EC87AAF540BB961D4661CE4EE74B87D4191C5AFAAC65616692836E5B65066EFC600F1FF3E4D71AB45708F1045607E21F4E5329B64703E3BD62C6EECB539792FEE8B1F88FCF31CCDB04292D9AE9C158E18C484915AE57C56C8DA31A49596358E416F21EA54E44840059C68FE69D574B44824D51BD24151F16E7D8E63C837C6DEEDF96BF9A30697AC437F733A5B98C8A9E5D7E798F272216FBDBC9DF9E9E4FD7AF7EAF7B7111F56309212474C003978362F14FCFAD33C9F3EA31DFE8572B34929E46314A54D7C301736DE23636377C39471820F5F6C8101B0499559B2DBA8F59E847619590CC14FAC751B37996105CB374DB6CA671B613932D59618940988453D0F7C8F0A04D136CD6F2352390BA9FDA1BEFE18385B064A593E9D74D30689498C9DD8E3C2CC66461E76A80354A81BB65538EE9F15B87528DDB846416F0272B316C8E54DE3BC454025A06EF4CACC5C98E45296FE05DD4B37B5321C0DE24BA2BC570095007BF5C8B0326E59EDE9BB004E28B4B5E48F7A1A8C56D41A44DF7C56D45A4DB167C482797AEC315E24135C76A62BC4A06E0D7A75C4A89287AB43D72921B414545734A53E9C785B01B45ADC8F1C785982AE2E42D0D7A74C14C89D95D2EEA2B5DF035DAAADD92C17953DF15B4CE0BB006EDCBDF15B44BCE78F247A3FB6109050E2EEE01FB44FD392664A69697B329A93DB147123FF4A3014240FA71533A434FA846D148EF394310AA81DF018DB28654A6E3518B9DBAC324B2198D1CD3A60106CF142A299A4BC92D622F2040086237DF2622BE28651A77947CC5A9C4F35BD83945E8C4102996082F881EB3E4EFCA9BD9D44FA8388EA7918FE5898BAAD7E4DDF4559E9967A26872A40024C828A0EC09C9083AFE3280F24DBDEACF7535F5BA2C8EC5A075DFE1DE997C4522ED966AD33DA5A4934D2963312A213D299785E152D23CBF696D62D3ABB191FF007A2BDCB76CB449A670DD4BCD4C2CF402DC4249715529F3DAB80C944698D7953405B5B06BB9A61140D1C923CDFB5D2BD32B25980FCBFF003D4B379FFF003D6EF4486FCC7A769D39ACAA7ED509EB9021982FA1F54FC9D96DF4DB7BFD27525BB9258C39B52C28BB0D85322907778AEA52AE8F70D677C443780D046761F7E2C814CEC599516534A30AEDD30365A6515E425FE26A7B61676FDE9FCA021BF297F2B997756F28E8841F63610E74783FBB8FB87DCF21A9FEF67FD63F7BD172D68762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFD3FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8EF578F9B5C06FDDBF4CE9B8DE267A6651E54D1967BAFADC9BA72AAE552C8E29C1BBD62DE25826E4AB45AE56656E6E0C28FB8B9068427241F697C72B9F276F871F0EE94C97B4256184257314C9D96395B10D522BB9CC8D23058687965129399116F07F30E857BACDF35B58446572D4F8728949651A4E34BFC8DF335FC6918B3912693756A76FBF2B126118D966FA67FCE2079E3569D2425E28DBA7F9F2C4C9C918596BFF00CE13F9AA29D1E5BD255853896E9FF0D944A4DD0C4CC2CBFE706B5A9E359DB5858C2EECBCFF00E6ECA2526F8E265563FF0038CDA7E8171691DF7994594A8F4F50494E4476EB91126D11E17A95A7E487956EAE62177E6E597881D6407F8E032660A7179F957E4CD35D2DE1F32C444A28C798DA995993602A69F929E539E932F9A6293BF0120C812D82491F987F2C348D2EDBEB1A7EAA048836F886E7EFC46ED3964C33FE55FF009A2FECCDDDAAFD7517A01BFF001C970B57131F6D13CF3A6481DB4B6B5B68FED02A454F8E3C28F11136DE77BCB598417D6E4229A31A634BE2338B4D6B48D6A25442179EC6BE380C2D81CD45BBAF28385F5EC65A93B8A1C81C6DF0CC92CBA4EB91A13E9B3D3BE40E37331E54BCCDA9DAB7EF6D0923DB2BF0DCA8CD53F48A85E722346C7ED2F8661CC516CBB516D4ED5BED311F3C82AFFAEC741C5B63D3E58AA8B5E27F362AA2FA82F4AEC3BE2D96817BF5AF5DBBE29B59F5A88FED62B6DFAF19EF8A82A2648EBF6BAE45B42BC6CB4FB5BE1640AB2B8DB7C0D815B92D3AD70164AD1B0A75CA9AD7F2DC50EF8551D0135A5715477A8513956BBD310CA3CD6FD61BAD324CCA9BDF49F663EB8B548A3ED2C750BFA705635F0C5ACC99E795BF2D359D7F538AD591845506507C0FD396E38DB0964A7D476DF933A0D959033C4867812AEC7B6DF3CBBC363E2A47A4F937C9BA5DEDDEABA95DC29145BF027AF1FF006B2C18D7C5629E7CFF009C98F23796F4ABBD13CB56714B76A0A0950577029E1ED93F0D7C57937E5BFE746B779ACC375AC4AD0E9CC4B70EDC6BF2C84E14E3E63C6FAAB53FCD9F25F9AEDA0D1F43981BDA8590AF5AF7ED80069E07B5E83A3AD8E9B6019FD4927456E47B03DB260278588F9D0BDE6AB67A65BF660580C902ACD043E8C3A7C1D2A02B8F96264C4861FF00987FE997DA7E996FD178F35191E2470A335A8DA0F265F5869B66D3EA4B6CCA0815DD908C921F9C3F96FE439FCB3E7ED77CC1E77D224852EE6768DCA6F424FB9C3487D831793349D5EC21D5BCBBADB441E3E6D64ED4E1ED4C348B7E587FCE45F9ADF47F3B0D3667A346FC5A64F6A60E1660A1FCA5F98F1DD086D6693F771A84563DC78E34D80D3DA2CEEF4FBD50F1CC391F7C69982FE81FF26E83F287F2A829A81E4FD0E87DBF47C19D061FEEE3EE0F25A9FEF67EF3F7BD232C69762AEC55D8AAC7E9F4E2AA58ABB15762AEC55D8ABB15762AA98ABB15762AEC55D8ABB155CBDF155D8ABFFFD4FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF8BED12FA6D457F46FA12ADBC7F626A7C47E6736E72BCD5193DAFCA1772C114D67796EF4894FD51E31D5BB72F6C899A63A6B6609AB5DA32C37B6E2DD587C2E452BF2C78DCDC5A4012093CFBA5D95C5C4123AA9B7157693A7EAC13C9B39630D30CD5FF003318397B28A39E2ECD18AFF0CC4326D863A62B73E79D575085C4517A61F6F886DFAB29949CC807D51FF38D7F96B36BF24BE60D7A33C62F8E30BF64F43BEF98F29378C40BEE7D22C74E69E9269D0C76D07C10CB1AD18BF45AFB655C4CBC1E1DD9E8BFB58ED1ED0C421BF857933462881478E266DF8E16F93FCD9F9B3A89F3543E5DD06E92E5E7904370EC6BC2BD48DB2894DCD86114C9FCEFA4EB5E4DF2D0D6EE7CD33CD77749CA3B3864DAA7B5331A536C38E9E45E5CFCBEF30F9C746D43CE7E64D66E20B0B2532DB425E858FB0C89C94C463B64BF967F973179E359223BABDB6D26DEBEBDD31A6CBE06A32072527C17977E75585B796FCC53E81E54B9BBD4A68BE15773C8F2DC640E56DC7A7B286FCAFF002B79ECCC351D62C6F9A0421B801F0F1EB959CAEC31767F13E9997F303F2DADECC68BE67D3A6B4BB20707028DB6C4E1198863A8ECDA28BB3F307935EDBD0F2EEBB25AA1FB2B2BD313A92D3FC9A82D7B509BF41DC2C9AADB5F475256456ABFCB251CE4B4E4ECFE17805ADC68374F7306A7693F224F0940D8E644276EB3361314A5FCB71DB96BED36F0C31F22521734232F0C2386C59661A17994D9010DE5D212BB75C90882931A7AE681AF68FAB442DD6E22172B5E418ED919419C7210C953CBDA4EA2A566A7ADFB253ECE63CB6726398B18D47F2CE695A4789223131AA377A7DF98192365CC86434C1755FCB7B8B552CB1866F0EDFAF2A316CE379BDEE87A8DB170B6D29E269D36FA3234C81481A3BD462258245A7B645210F34BE98F8C1030B7525C6F2035058838B3115212F03591CFB53148802A6DA8C6845198E2C8E20022A1BB59A95241F6C5AC48A3967229C6B4F138B30510B73D37E98B74510B703ECD7AE03BA65B045070AB50D91E171BC42AA92EC64AEEB9131489A36DAEC3380DB0F118084892266BD759111006889DEBD71886C81DD1F0992E18C50C4657A7C210572CE16D243D3BC97F957AF798E482792310C524A1645E8426FBF5EB8F0B8D393EB1D1FF002374CD2AD24B8FACC8B2409CBF7A76247D38F0B8D29A0B4DF33689E5E3793CF730C571A7D79F134A8197618B10789E11F993FF003955A5E97697F6FA0A9BABC98323B49BA8EA36F87325AE669F188F3B7E6079FAF9ADAD2F561B59FD46B94534201A9006C3C70DB8E7290C5B4AD3E1D275392DB592F717334A03C8FBF53DB27C69194BEACF2AF93E2D6E1161A2A492974A3B36FC411DB2B99B6C8CDED5F941F9172796BCC4FA84AD2CE8CFCA6F537E277E9BE56CF8EDF74C691C2A8109E1025501F6C3652082F3BB1AEA1E6A7BCA739223C78FECED8DA683D06F1115A198578A312DEC72F8C0485A90180C006AFE6C9243F14708DA982500189A66B1C4F1488518AA4B5E5F25CAA52A6069E4DE67B48BCC7E67B6D2DADD25B585C7AEC07C54077CABC621AF64279ABF2B6EF4DD2B5AD5741BE6B484216823534A0A0EBBE4865B6C1005F879F9B02E6E7CD9A80D61E3BA9E1958073B9DB26269E00F3089B568627BAD3D12358E4A1E636E3ED960368D83D2B43F3C4F63259C11C9CE5968272DF641EF4DB274178807F551F9093B5D7E45FE4BDD350B5CF913CB92B11D2AFA65BB7F1CDEE1FA23EE0F2DA8DF2CBDE7EF7ACE58D2EC55D8ABB1558FD3E9C554B15762AEC55D8ABB15762AEC555315762AEC55D8ABB15762AB97BE2ABB157FFFD5FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF90FF00CB7F20CFABEB70F9784FE9BBB0569CD76FA727E3B8A3474FD1DD03F23BF2F3C93A589BCC5E60B79AEDE3E4119F707EFF007C7C76C8E969F1C7FCE4679DBCA97925BE9BE5331C6DA651649E3E8DC698F8EDF1C34F985743D435AB73A95C5AB244568B514F57DBDF01CEC8E34D74AFCB3F36EB344B1B65B6B63FB4C074FBF29395022CB74FFC91D5CEA169646F0CB792B82B02D6868457299657271C5FAB7F90DF96FA8695E588AC2E2331968C027E81941CAE6460F7693CA361A1E8F705C896E5DC145EFCBB1CA8E46E10BD9F397E76FE60587923CA7269D6404DE66D67F72186EC81E9BE0395C8861A60BF911F93BA0E956D75E74F38EA0B3DC5CC06ED8B36E8C6BB75CC79657371E36216F637DF9B9F9A52D868F792CBE5AD35E9287354A2FDDE198F2CACE589ED7E70F2C5C6B0963E42F2E5C1B68B4F939DEBC6688E0F63959CAD4715259E7AF3EE89F933F97B37956C5565F325C2141243F6F930237A57227236E3C5C4F19FC99FC9EF3579E357B2F3B7982E85BDACF299409BAB2F20DEDE390395DBE97476FA57F323F30348FCBD8C68F62F6D3B88F837115DC0A7BF8656723D0E9B40F813CDFACB79A75A6BE9E0145242328E80E0F11CC9F65F131F9AC2248F925F4B6EDE08D4C81CAC4F6481D1434AB8BFB2BB8A73AACD71A746F59A177AD4F7C9C32BAFD4F66D07D412F9D7C87AC79623B2D3ECA38F5644A34B415E599B8F23CE6A7414F0F3A6EAF7777248B3B95AD16253B53E599D8E6E8F2E1E03499E9BE5C56BD53AB192DE2247276DB2F127127165D7FA0E8F0317F2EEA85EF1002C8ADB93E18CA4D6229B7953F33A6D26F5346D6AD65424F1FACB0FA3AD330E72722117D2D63AAD9DEDB42F6B79CD5D4155AE634B9B971E48AF5AD89E372BCD7C72B219A1DACF4FB9E4A6C57813B371EA3C72B21B2293DE792B49BB25BD08D49F6FEDC810CC3CE75CFCAFB296390C4A2B534A7FB78B787916A1F965240EFC54D05698B6061D7DE50D42353FBB240E9F462CC31B974CB8B7E4B25B9AF8D31672E4848D2584EE87171AB74D61B9A8E25295D89C5B150951DF1640B4B28A80A773DB14CCEC9AC658A0DF22E2A3ED62326C7A1AE34B68D58A15824653F18E831E15B645E43F296A9E67D5E1B75899A194D2B966385948C9C2FB83CAFF0092FA779295353D5A2170654E410EF4AFD3991E1A0E77A4E82DA4699F5ED6AE255B3D3ADE3630C55A55C7418F86D32CCF3DD5BF33AE7CE574749D20496F6ECDE9B4E36047CE98F84E34B23CEBCF1A3792FCA7A1EA926BBAA97BEBD80FA4BCF7E743D725185328647E5DEBFA8C32EA57C2CE212DA991B8B91534AE4A98E4928F9735ABDD1EF0DD69B251CAB7A918F9634E29927A350BBF32B5ACB1DBB3DFB5C207A0DFED634CA2FD64FC8CF29C1E5EF2B0D66F63A5CC9081F17662A3010D8F77F23D85DCB6FA9DE5CC815667261AF8646922D3CD6EEC69D62189A168F8D7DF1A6C8DA43E4EB4FAB9B9D4661B4D5E24FBE34CF74E755BCFABE8B3C8C68ECEDC7E9E9878E934520F29DB1B2824D4E71BDC92149F7CAE5918905956A139B4B19A73B7D514927FD615CA253B6B312C23C8F6AD35FDFEB972B54B824424FBE5129313128BFCC0FD23079435716F2B969636A460F4DB2D8DD391189E17E06F9FFCB7AE0F34EA9A85FD94CD01998F220D2996C4B0902C7749D26F7CCD7834686136494AA9229C865824E348909B47E4F86CB506D288E57711A09325C6E399C83FAA2FF9C7E80DB7E437E495B375B7F20F96E33F34D2ED87F0CE9307F771F70FB9D2E5DE67DE5EBB96B0762AEC55D8AAC7DC7D38AA9D0E2AEA1C55D438ABA8715750E2AEA1C55D438AAFC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD6FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF233CB9FF0038C3E4DF2ADCBEB13B133D0B1911C0CC3B2E7ECFCE5FF9C95D5A6B1F346A1A7E95AB4E6C625612C5CC96E229B03DB1B29A0F89DEDDEF00926B97974FF5394909AFAA47BB63653C2FA87CC9AF797F56F2279774DD25D34B4D3A86707FBD6A0A751BE365061B337FC8DF2C5E79C752B7D26D6F2E0CAEEA11B937122A32B258460FD2CD3FF27FCBDE569F47B4B9B432EAF28065BC6DF8F427299172618DF40456B6BA6D9C16FA4C4102A51E4661D69EE72891A732106272C4F737978F79C94DADBC970B272AA1F4C578D077395D972B1E3DDF9E76B6317E6E7E6FDCDAEA08F69636B318F8CA7ED509FB35F96425272B829F42FE69F927CBDF977E4FBCB5B1FAE896F63315A4924C4A7A8694A0F0DF28916D8079F7E5DDB5EF907C986636E96B7BAC9ACD7DC6878B03D0E512939118A6307E6459E97A6DCD968086FF00CD3316F4EE07C67936DBD2A72B2594B0DBCCBCB9F94BE65F327999FCDDE78B1B8BA4327A932C95E0141AEC08DB2264E4E9F4FBBD4FCFBF9ABE57F2AE8F0E81E52E7677F0A18E242F550D420EC32B26DE8F498007C75AEDF5D6B378B7DADDCB4D7B292CBBEDD7C32B327A0C31012DFADC21FEAF343EABAED118C5283DF07139825174B3C0842B583B13D2B91254CE285BAB580C5EAADAB41714FB1FB253C699289759AA31AD93BF21FE5BF997CF5AA25B7942D9E390B52E6465257DE9B6676393CB6AA9FA0BF97DFF0038C4BE5FB186E7CD3299AF1497996BFC33618E5B3CA6B620CB646F9AFF0025F45F3497D3AC6330A8F843A6C7C3AE64893AE9C5E7FE59FF009C4B6F2E6BEFA88BA9E78B90608EE5878F4C12935883D1FCE5F91FA16B366919822B5BC450A27550A6B4CC49CB7722317CD97FE5DF30FE5DDECA90C72EAB696CD44F4EA683000D8F40F2E79AEC35E884733AD9DD746B7907C55FA7010CD983EA0F1AFA3C1404F85180EB9590D812B7FADCADCBD6F84F4036C810C834F248AB406BDB7CADBD21BA53293CD41C5B42552E936F221AA038B20C2B54F2BC3217A44BB83DB16C3BBCCF54F2A4B17F751803E58B5F0B13B9D1E5B706AB4FA314243346F1FDA53BF4C50A5146DC838041076C0589927F096E03236C0A6F6C582FC3D7FCEB931BB548A3A0D2A6BABC820B40CC2660251D7AE5A22D7C4FD0BFC98F24E95A1E9D6B7A2D985F08F90673515A7865F8A3BB4CF23D4FCD9E6780AC36D247CE78E3ACC3F6683AED99341C7F11F21DDF9E17CF3E61BCF275ADF243A7D94865BB8D0856A0EA2B5F6C691E25BD5935BFCBEF2569062B7A34F0A7266EADCBFD6C683025F9C1F9BBF987A879ABCC37C25AAE903E1B5727627C0602144A9E07E85AB1755670AC4D77C1C2C2791D64B67A6DC898BB2CBB8849355DFAD463C2D5C56FA7FF00203CAB16AFAF433BBC73C664570817DC1C785BE127EA25D4634ED0934E0BC04DC5828DBA0ED9121CDC401E6CF7CB6D0268F089CBAB2814A1A7DF829BC4425FE6C65BF8AD6D636E3561C877E38D331009F689666F74B92DE195614B215766F6C69B0462C1FCF9AFE876D2C3A341AA4308545370ECC0EE7AF7CC79C776C1008D7F39FE5FDA687656D77E64B5630D0944700D7DF7CACC14C22C4BCD5F9C5E4792D27B1D3F5980FD6C2ADC55813F08A0A6FB640E32D6718653E49F37F93EEB4286C1756817D221A3F8C035EBBEF90F08B0F0C273AE79A34C3A7CF099619CCBB2B5410C3DB7CC8863A0E44202980CDF92FE44F3BE963EBBA72FD6AF3ED3A902B5C3C0C258C3E78F3E7FCE23685A523EB9E5EBAFAB6A963FBB823076A2F4040EB83869C69E10F9423FC92F3C4BE66FAC49A6CB33C8D46B8553C4FE18971CE9EDFD0E7E5058CFA67E52FE5769B72A52E74EF28E896D7087A8786C21461F78CE9F4FFDD47DC3EE797D40AC921E67EF7A2E5CD4EC55D8ABB1568FBE2AD547862AEA8F0C55D51E18ABAA3C3157547862AEA8F0C55D51E18AADC55D8ABB15762AEC55D8AAE5EF8AAEC55FFFD7FBF98AAD6ED8AADC55D8ABB15762AEC55D8ABB15762AEC55D8ABB15762AEC5578E98AB78ABB15762AEC55D8ABF30EE7FE3932FFBDDF60FF7998EE4BF25BF357FE537D53FE39BFB5FEF6F5EDD716D0F1497FDDBFF001C5EA7FB9E98B745253FDFDAFF00BC7FDE0FEFBFB9EBDF23264793F4DFFE7143FE3BBA67FC707A2FFBC7FDE74194B18BF42B56FF0094853EC7D8FF0077F5E9FB194CDCA83C8BCEFF0061BFE521FB5FF1E7F63A9E9ED98F272E09DF927FDE49BEDFFBCB27FBDFFDEFFB2FE3953938DF1A59FF00E4EBB4FB1FEF50FF00783FBAEA7EDE464DF27D01FF00395FFF001CEF2EFDAFEF63FF008C1DBAFBE53258F3625F985FF92AB47EBFDCAFFBCDF6BA663C9CDC6F00FF009C69FF0094FA7FEE7ED0FF008EAFCFB65679B9717EA37997FE51BD43FDE3FF00799BFDE4E9F64F4C94F936E93EB7E3179D7FE531BAEBFEF43FF7DFEB9E998E5E9B4FC921BDFF008EDDB74E9FEEEFB1959E4EC23C936D3BFE3A375FEF1FDB1D3E5DB029F8ABEB3FDF27D8FF009E790973627E2AB17FBD717F75FDC8FF007A7EC7D39383AFD47C5FA1DFF389BD2EBFE385D0FF00BC3FDF77EB99F89E675DC8F37D49AFFF007D71FDF743F6FECE6645D066E6C5344FF7A24FEE3AFECFDBEB99117124CCAD3FBE7FB5FECFA60C9C9AC3CD3CF1F69BEDF5FF0075FD398736F8BCA74FFF00A587FBC7DFFE3A19747E9497CB7AEFFCA552FF00BCDF6FFE95B80A43D7A1FF00792DFF00BCFEEC7F7DD722DB1504FB67EDFD1959641565E9DF2A2DE12997ED606D0843F4E2C825571D5BED7D38B6B12BFF00DAFB3FECB14179F6ADF6BFDD78B51611A8F5FF00757D18B192017FBB3F67A603C9804543FDD8C805926D69DF2E8B44F9BD2FC89FF1D6B7FEEBED8FEF7E797C5A25CDFA15E5BFF8E6DA75EA9FDD7D1F865F071F27262BE69FF8EB6A5F6BFDE47EBFC32E71DF97FE4FFF00C995E66FF7BFFDEC93FBBFB7F4FF00938ABEC7BDFF00943F52FF008E77F70DFEF47F7FF47BE2AFCCCD7FFDEDBBFF007A3FBF7FB7F63FD8E1632E4C6A3FB4DF6FE8C0D3245C3FDD5C74EDFDEF5FF638583EDFFF009C50FF008E9C5FDCFDA5FB5D7A8C0E4C1FA41E6DFEFB48FB3FDCF7FB3909399064D63FF1CF8BFBBE9FB3D320DC3E2C67CC5FF1D0B0FB7F647F77FC71671F8A62DFF28CEB5FEF67F74DFEF07F7BF4E167F37E67FE65FF00C746F7FE526E9FEEDFB5903CDBA3F178737D97FF008EDFFCF6EB8127E2952FF7FF00F4B5EBDFAE2D72F8BD3FCA9F6D7FE526E9FF001EFF006708607E2FA3EDBFDE1D1FFE523E8BFDFF004FF65930DD1E5D5F5BF977FDE0D27FDEFF00B2BFDD7DAFA72054A7FE6EFF007960FF007B3A8EBF47DAC816324FB4DFF8E7D97FC733A0FB5FDEF4EF902C1F62796FFE51ED07ECFF00C73AD7ECFD9FEE57A7B674DA7FEEE3EE1F73C7EABFBD9FF58FDE9D65AD0EC55D8ABB1569BA62AB315762AEC55D8ABB15762AEC55D8ABB15762AEC55D8ABB155CBDF155D8ABFFD9, '1', '2021-03-13 12:29:10', '1', '2021-03-13 12:29:10', b'0');
  150 +INSERT INTO `inf_file` VALUES ('add5ec1891a7d97d2cc1d60847e16294.jpg', NULL, 0xFFD8FFE000104A46494600010101006400640000FFDB00840006040506050406060506070706080A100A0A09090A140E0F0C1017141818171416161A1D251F1A1B231C1616202C20232627292A29191F2D302D283025282928010707070A080A130A0A13281A161A2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828FFC200110800EC00EC03012200021101031101FFC4001C0001000105010100000000000000000000000701020405060308FFDA0008010100000000FA14000707A3E3F659B5F2B3CB1B171B57BAFA2C000BE1ED8731AFC752DF3F2F2EF249DF79D0000A465CD59E5ACA5BE7B09BB71441BBB943DC0017447C95DB0D662E4FD0192237F3E17E8600039B8AF556E579647D0B60807A3DA49368003D7E7AC1A5B678CA3255081A4AEBC0007AFCF5834C6E8BA3DDF756902CE39200034908796C661E82C04073E003D755A4B2FC9F48A34CFA172404152C6F415C4E175B9BB879F8EAB41CEF792A807CF1B1903B7BADA5DC0737D47ADCB3CFCBCE3FD2CCBDB807CE35CAF5E8B3F0757D0FBF1BE7DD655B65965BF384B9397B80F9C6A2EDAF577F05A0F3D9499958BACF4E7F41D0654E168118657B59A8E2E43DD71B31FC73ED26EE33FB0E939E8FB135FEFBA9528007159783CAD981B8C5DDC9596A5231D6E17173476200BE26D8351AFCEB33FBED077DABE2FCFB6DB59CE463365A018B156E4A3CB7DDBC65CDE3EDF71259C945B3D7900725CFFB554C0EA3B769E32BEC92F794A4711EEE3BDEBAC0380C657CB7FD6E50F3D4E266EE0C2E2F9DE73CA6FD90237B7CB7FDB5F554B6911C8BB8A948CB039CE5E79E94230B3B6E98A82945453C225BB87D44E3DA158BB77DF56A00A1452DE6A2DB397D6FD5C562696B215002DAE1E4D29CCF8471C9DBF4E9EB03CF952A028A539DE8296E1C7DD3C2DABFA80BA3690760A5C28514A626A37F4A523DC2D7E9A772B1CC9B7733B2DA2828A2DB628EAFABA523DD1D29302BC6767EE88E46DB1414A29486A1A9CF8E99E2BD91303CF98ECE8897A9EC5428A294A70B04E5E279751D613038FECBD5485BA5911428A514530780D5E9B7B62930B93ED2D6A222EA64A28A514514ADB444FE56D7FFC4001B01000105010100000000000000000000000001020304050607FFDA0008010210000000F3600075E70AD558EA46005B9DCE33E1B7367000694AC32CD3CC00034E58A1A69A59A125A512766681ACD81C9A194D4F44E2B280D94750E8BD1383E7AE6F60E4D500BB0F4BB3CCEBAC540E7500BD5CB7D135B33E0E769342FA6DDE51AAADE56CD084D7DE780014F9CBF8EFEA2E800346D4CDC87F57654104628C38ED9DE6B841064EB5978DEAAEB155104115A7FFC4001A010002030101000000000000000000000000040102030506FFDA0008010310000000EB00043FBC939A35CE4003A76164A7AFC9800061CB22B8CAC0006EDA78C4B0B845F5B8C23981D3533A3CA742D7F0DDCD006A346783E07D9FA05BCFF7A92016EAF9EE0FABE6CE8DD4901AE84ADC1E8F5BCDE0CEC483FA72520BD62DE8D54E46B8F500019F429A318AC001259BEAF3215C8009BC1B5F4C55D2B5924B9560D55CB5AD2490B4EB3FFFC400451000010302020604090A050403010000000102030400110512061321314151203261711014222330425281D11524333440537291A1B116436292C16382E1F0357383A2FFDA0008010100013F01F4FC6B4931051908C2222ACB706690B1EAA397BE9E719811335B2B68D800AF9C4D735CB6D6A56E48036229BC3DF575B223BCDE861A84ED71E3F95AB53091D672FF00EEA270F1EA66FCE8C8863AB187F68A335A1D58C8FD2953F932DD2A628FF2DAFEDA3249FE5B5FD94F2D9BF94D3415FD236D4518C6ABE66D627A9E194AADF6047585622C3B866352E54C49533297E43C3684F61E54E105ACC946B788038D09B2E495063220A77802EAFD696EBF721C79DBF2BDABBC93DFD0346AF750424152D5B9291727DD587E8ACA9090B9EE888DFDDA76AFE02B0FC270FC3BEAB1939FEF17E52BF3AD62A9195C405B4B4B883B8A4DFEC0B4A1D694D3C80B6D42C526B12C39583FCE226672028F96DEF2DF68ECAC4594AB24A64EC3B7327876D22521D4E5988CDFEA246DA7A294A758C9D635CC784D1AC330F918A492D46B04A7E91D3B91F13D9585619170A6B2C74E678F59E575954493BFC3F25BB11CD6E1129C8CBF66FE49A8BA55221B89631D8BB0EC0F37C6A2BEC4C643B0DD4BAD9E47D38B1052B014856C20D488BF26622B84ADB11F1999278734D3CD969D520F034CBCB65576D56A25895BECCBDCFD534F34B65595C16FF346A0C473109CDC465594A815297ECA79D448CCC18A88D15395B4FEA799E88A75B43AD943A90B41DE0D3C1FD1F9499905CB344D8A4EEEEA0A0E34DB805B3A42BD3E92C432F075A9B1E7E3F9D47BAA7283A961F4FF00311E14485253915671BF655FE3952D0082B64E64F11C53DF583CD187630C495FD09F34E7603C6962C766E3D1462130904EA7F0E534EBB20A9A8F159D74B705F28DC91CCD46D185BEE25EC6A46B2DB7528DD4A3BAC2C06C03D3B7B4E53B8EC34B4EA98531F72FAD1E1357208209046E229C3981CC37EF238FBAB43315D73670D92BBBAD8BB2A3EB2797BBA3872017F32BAA819AB4559221393DC1E7652AE3B10370FB0B5D7152961C7A42C6E72438A1DD7B785C7128EB1DBC071350B02C5268CC969319BF69EDE7DD4DE8728FD63123DCDA2B0DD178906735284A7DC5B66E01B513737E824EAF0A98E0DE465FFBF9D436F5387C4680B656923F4FB0E3738C083E6B6CA7CEAD94F6F3F752C25166D06E940CA0F3EDF061B02462920B516C9423E91E56E4F6769AC2F0785860BB2DEB1FE2F39B5468A89DFD37ADF213DF8BFC8A1B59688DD907A20835227C18BF5898CA7B335E97A478524D92EBAE7E06C9AFE228C7A90A72FF00F9D0C7D9E302701FFAFF00E6938EE1C4F9C53CCF6BAD102A563586C58FAE3290E83D54B67328FBAA6CE7A64A54A90323A5391B6FEE91F13E04A1C79C6D9605DD7559103B6A2456A0446E2C74D9081B7B4F3F43193AF852637150B8AD1E942760CC281BB8D8D5AC768E9EFA992A3416F3CC7D0D0E00EF34EE9148977460F12C3EF9EDD4A87325FF00E47107560FA8DEC151F0B84C7518413CD5B68009EA803BA8D1A34F448EEAB32DA467F680B1FCEA4E1EA4254A64A9CE394EFF00CE92A0ADDDC472AD098E97A5CA9AB17D479A6FBCEF3E899714D38168DE2A338E33255270D7FC5DF59BADA5F51CA87A48CA9496B1465511FF006BD4FCE9BCAEA02D95A5C41E2937ACA7978522FDD5896901538A8B82A75AE8EB3C7AA9A630B0A735F3DC5497CEF2ADD49B0161B055EAF57A2689A346A7E30F78C29A8694D926C5445EF4EC85BEE053A84B723DB1D55F61F8D684048C04A13F4A1D59713C526FC7DDE910FAC2321F2DBF655B4530A61B5E646BE3AB9B2E5A9B9F3B66A31726DC1D40AF95B1C693B04391EEB1A5693632D9F3986B67B81A7B1BC5719CD0C3488ADFF3549BEEE550E3B71590DB42C07EB4FBEDC76CB8F2825239D3FA43B7E6D1CA87359B531A4842AD263651CD06A3496A4B41C616149357ABD5E8D71AC230886BD1790EBA91AE5A5C257C516BD4194BF18650B480D1010A17BDCF3A8921FC2DC131ABAB56723E8FBC4703DF51A435362B72A32B332E0B8F4C1453D524771A87AE7DD09D6B9946D3B69B425B4E540B0A52821254A3648173498F37185AA42595AA3A4F93C8549929662BEEB2DA17A95645051B1BD61AFB38A5D011AB780BE5E75143D86C82E37D5F593ED0A8B25B94C875955D06AF4FBEDB29CCF3894279A8D7CA71782D44730DAAD45F4C98EE884F20B994E5B1DC6B0275E6D9721C8D6A2DD64AB7281A7F4714257993E689BDEFBAA4C96A2CA4B6F1F36F2721ECEDAD1F9FF22622B8EF9F993EADBFD0AE7DD446E236A4EE3E813A1E7F9B89AFFDA9A4E8743DBAD99257EFB57F0861BF7D27FBA95A1F879EA48909F7D3FA21251730A685F24AC5AA6C79B86AAD3D8213EDA77560907E6F9DCD855B4FC29C8A35B649B0B5EB1D516F0C91CFABFAD600DB4CE09112DDB206C7FCD692869CD209EB67E8CBA77568FB4E7CA91CB69E3B7BAB1646469C58DA40D82B0D8A21450D5EEAEB28F6D3697E63C598405D3F48EABAADFC4F6541C1A24539D49D7C8E2EBBB4FBB97827E0F0A68BADA0DBBC1D6FC950AC423488032CE0A7A2DFC99281B53F8870EFAF9D048CA10F208D8A0ACA4D3985096A0E4C514AF8250760158AC44B91EE91D5163DD5A218C2B38C3272AE7F92BE7D94458FA4D2D7C96A261C9EB495E65F6213B6A23EDA59B28D88A724A8BAA523603B2B1B19B0C7EE6DB2FF00AD6172DF430194B8AD572A95804790F1790ACAA3BC54382C4004A7CA739D7D6E50B6D69A55D479AB9504392A408B1CD96A175AFEED3CFBF95458EDC5610CB09CADA770E8101408201076106BE4A5AF5AF610E06D21C524B0EED4120F03C29D5CA8DF5D82FB607AEDF9C4FE95F29C4E2EE5FC4922B15318A82E3C8403BD3955B8D68962C716C36CF2AF299D8AED1CFD1A05D429D77C771D9926F76DAF30DFBB7F87158AA99096CA1412A36DF50E0C88EC84A9E43847022DFAD66929D81827B42C56A243E7CFA836DF241BA8FBE965319901A6EFEAA109F589DC2B0F8660425EE724AAEB591EB2B977560788B8E4F991E5150505272E6EEF04B9CC450758BF2BD91BE9CD296028846AFF00326938FC89CBD461CC05BCA1D6DB64F693585C4F1282DB19B3A86D52B9A8ED27C0A48575803DE2B178EC2602C865B06E3720560EB30B4B5ACBB1124588A56C51F4531EF168129FE2DB648EFAC211920357DEBF2CFBFA4EB8865B52DD504A06F26B0684B71D4CD94828007996D5BC7F51EDF0694C53E3D16446506DE5052566DB176B581AF18C4BAB9503B75A6D5E28EBC6F31DCC9FBB46C1EFA4B6848B252903BAB01467C656B4F55A672ABBC9D9FB7431F72CDB4D73398D48F271BC29437EB2DFA8A77AE7D1697B9ABD1E75237BAA08A69391B4279003A3E3216EEA6321521EF61BDB6EF3C2B0DC1D7AE4C9C4B22DC4ED6D94ED4B7DBDA7C38AC3F1D8A50956475273215C8FC29D73C5DCD5CB4961CE4BDC7B8F1AD6200B95A2DCEF4D2D7255921365F5F31D51DE6B08802045C8559DD51CCE2FDA3D0C614A54F702BD5D83BAB16D6F8E40547FA54AC94F7D31A4B8CC43F3D8A1F6C6F396C7F31585E9161D889080B2C3E7D473E34A491DDE834CCDD186B1EDBD7E83257254530DB2F91BC8D891DEAA6B020ED8CF794E7FA4DF928F89A8EC351DB0DB0DA1B40F5522DD15A12E272B894A93C942E2BE4A819F3F8947CDCF2548C4998A754CB79B2F04EC02B0F9C8999C25252A45B37BFA12633525367537E4788A9FA3C1E19DA78EB1BBA9A047ADC298703CD058D97DE391E22B11C2DB76EB69365F2158563B3B082942FE710C6F4AB78EEAC33108B8AC7D7435DFDA41DE9E9E949CD8E618DFB282AB781D73265012A5AD46C94245CA8F6544C194F0CF89916E11D0760FC478FED484A5080942425237002C07A03B8D390714724A9866304241B78C38AF27BC0E3585406F0F881A412B513996E1DEB573E963917C46619681F357CD9DFE85FB5DC68D6251B617503F10A61C7F0F9224C0564706F1C0D6038DC7C659B27CDCA48F2DB3FB8ECE96909CDA551C704B17FDE9E73568D892B59395284EF51E558461BE2BE7E45973163CA57040F653FF0076FD89E6D0F34B6DD48536B16524F115219561B24457AFA93B1874FAC3D93DB46A5B3A978A7D5DE2BCE30FA64C45143E837045617A510254342E63896246E5A4F3ECE871AC636E972FFA628FDEB47E3090F2A7AF6A5376D81FBABFC7D931D85F2843530DB812F6F483B95DE3FCD403250B5C793B54DEC39B62D3D879F7D62A9F36857236F03B192B5E6B91D01BEB1F51563D2D2D6C756866324F6AAFF1A8ECA23B0DB2D0B21B4848FB03EFA59C80DCAD672A1237A8F431E694A845F66FAE8FE705B88E229C8AC6330997C9C8FDBC9751BD3F11D958C3722235AB9A80368CAEA7A8BF81ECE937D7AC3E5993A62DBE47997242F2F7E5B0FB0E1C7C664489AADC545A67B1037FE67A12D84C98EB6944A42B883623B6B47642E015E1F33638855BE07B8D62AB4BF065B4B48394849078D4A82B601531771AF638A7BB9D254142E9DA3A093635A4C9660CEC15D650869297944D85870BD4394DCC6CB8C056AAF64AC8B05768ECF4F2DCD54579C1BD0852BF4AC0148560B0CB7BB563F3E3D1D286836F44969EB156A17DA0EEFD69C92A5EB2FEBA520F78F03F874779C2B505051DF9556E86C00A9442509DA49E1410349E787568B6131890DF02F2B9F750000000B01E0C6F11F1169B4A7E95D5048ECEDAC35F5488895B9D6DA0FA4202810ADA0EC35A3B3061932561524D834B3AB27D9E0698D21C35F9DE2AD48BBB7CA0DBC951E40F434CDDB4161A1D653A93D2DE6B1B5AF11949C1A2A8A507CA94E0E09F6477D30CB71D9432CA421B40CA948E1E1D28CCAC563A6FB3589FDAF58565F106B29BECDBDFE974FE225296662363AA56AC914127665D878562DA4AE468AD371D00CB50DAB56D48EDA81A5188C792954B73C618BF969290081D94FE2D15A4660E67BEEB7C6B1A7D53A6C7521C4E6CF982378B749D7931A3BD217D56D2555A2ED2BC4972DEFA696B2E13D9C3A1A48ABCC2AF61D47C2B00776BAD1FC43D2E99435CBC1EED0BAD956B2DD9C6A1B49912DA6F7A6F750ECA95152C4D534D9590948B85F0A71BF20D3816E93AE56729397B36568FA72B4FEC1B17BFDDD2D2E51F929A8E8DF25E4B74CB619690DA3AA80123C24D85CEE158A2F5ADBCBE6ACDFF00EAB0755B104F6823D32224742CAD11D94ACF108158E600FC99CB950D6DDDCB67439B368E37A8BA332B5A15296C8037041BFBEBF86B1242F54DA1A5206E74AF7FBABC45386B288F9B3BBD65ABB4F4B1FDB3B0349DC645FA18B2CA2039978ECAC4C5E0BBB48D97D9583FD7D9FF00BC3EC4EAD4E3AA5ACDD4A37E87FFC40029100100010303030402030101000000000001110021314151611071812091A1B130C1D1E1F0F140FFDA0008010100013F10FCE0B032D36BD74B69C8F6137A56A00C92E87777A82C152709D05827769D2D7B9F63F9A46C9B00FBB58E2CDE53EC547DD0BE1FDB41C2099E4F34E5A46241F4524D856723E655FC52A491A36144F10CD40C4961A5C0BFF8103389AB0DE8E169ED3DA981205B99E90B6F348CE90978FE14B61C15F4914ABF205FBE8D3D0A94B3D0E3F81769770BD97397E02682183E43CB1E2294727B5459448C1F25223088FE782179644A756382AA57C9FE734AE1D0F0A701E6841A16200E50FD7B5470BDCBE9DFD05429E19C96DC9A7BA2ACC52D45BBE8705A90953D65F35AD3FEB99A590583939461F10F15A997264EE64F3F9E17411A4473255DDB9BE3538D3C6F578EB43B9A352612C991EE56128D1979DAA72568E4EC7A0FF3C04C5986AE87347DCF7BCBAC9AAEAFA548290C636AC7B65C8D3BACB3232B35930F151AC466D20FEFF3CC91C50966E4F24FB563C096344FFBF1D1A6C29CB58E56553F01BAFC6DB92D589215DF9F161A0910DE1309E91A4CDA29F33334A674442CB680DA8854C0743C2EDBC7BD0282100D0FCE0719341D4A99198FBCDA64FBA69E8D4598425190EC4041DDA3C5B82951A60E51DDAA3E3B52228E4F427CED4F18FF0071508A74B9647DCD673FF804D4A38B5059803F0D34D47E461BF60AD946AA06E1BD452466E708EEBFAAB2938A163582A6777A1B4417B4508404404130FF00C248277E82EF8177C57B207167C957A5BF1A24CFA0F83DE8309CD60E1D0E0A6EEF1EB825B909A199214F63F0E714B2520DDA2A51BE056E096A589D2F5DAD52A33D0919F769379F44C1EF4895CE0F71A1286E36727605FDE2A69EC7647BB3F36C7484A6721AF6095ED45888919D64EAADFF0009631BDD8FE42B946162DDFC47AC15012D0471C8F60CBE29652EC840344313C2BDAA752C85BC7FE2A0133A73F9A3E01C400FAA4EEFBD2A6A65A33146488BB82F4E5E9BB25DB53DE895948C8215B268D0F0109B429EF441E5A5555CBF85500DEC3C539B9C696FD37699342E895CEC3DCE6A18E24207DA93D5489913A5DE017574A0FEA8371DB47BE3BD33BB64287CE7EB8A02103004051428F502ABA8AEEEBD8331B14A11200C06CEFB7BA928269B796034B0FC8B944B27FF000F15DE8A43C9AD4025299D5E162529513F4BBBD642AC6592CDB6B71A6A54C1026E2FD19AD4FE9D56EF35A945965D8DDA621FED4050052E66C78735ACD18C8EC9A3D0D1A2A1B3BD4F34B5BCA10E9114E98389E470D4FF00E47B1F402D3C157ADC184DC4D11B27E1289EBDE9A95790A51C2F23B1B79A020917BAE5776A73848E819A57822058E3777A12C6DA4081E68776F0320E1A9FA41C6193BECD61BD6E422644D1A69C1E605290A6D53DD14EC582B905A4C9521224524A4A6F522922B4B3B54EE99E4108D4C94B898ECD23C8CFF544090121713F036F227061F745B95C4087DD76EDA1FC5679B4929F45446DA8786A51E4BC5E51984B7EF8A8C0B0846F3A781F3489EBB4DE198A24320B3903483C8D4C2A4A7CCD00A4B060A597DE69CE00BDD97A839230195B07BA5199B32B5613E2D1531C9029E2FD2F31449AC5B8EF06C780A2C416363151862F7BB7933D9A8BE618658C8659D948A121381A28DBD9A3492C7BB254BBC94292C0466187B944DCA59CBFE7DA9A24FC6498A56248B9542F760F7A04762C3ACBA525502026850E3C127540D1A046D2B454B42CA124F6A72E4227A1C5044809A72C1ECDDF053088498961EF606AF050512C64795755CAEAFA0CB140488E89519BAED8014AE5DB0516E50404E66EA9146859863DCA9B889A276AD83EA92922BEBA4BDA1FEFF1C1A9B1F9B6190EEFDF54A42870B38AB1438400D8FE454E3B10FF009A619765E0DAC03C5EA43892D4AA039573DDAB53A1BA0B0E1603F9ACD1C4C659243819B76A8767DAA22904D9477D03BD04082D2C5F21158C6E001E16580F35255E63C4C7DC3429853B50503EC0FDD36AD1A0667B50146DEACA90E39068C0E7F143BF432DF3152AC253754FA8CA2CAA029E88A344D93D1160C837BBD0AE5E121981C4B0E4A5489372FB2682C64C80ABCB2D1328C00A7B21306CD1EC9A8EA60376EC163E569366ABDE4FE684245BF12BC8C9E32CFEAA0500B670450FA1405C987F403BD4CF6F28F7AFBF834EB02C03C9074791669747BC1CD8C5A934A7A8C5065C622F3E1838A8357E2C4BB1B183D02C2003EC99F32D12B97A62200EB6D2B548D8B7163DCADBD6912F183F15756FB8FC196AC3F11FCD4CAF49A52B50B97C96F04B436BFA8F698F913B560E6C31FDFA1A6AD7922786818BB16A38A686076D63E8AC2D08B30CA09EC4F9A9A7A427A30DBB0D1B85CC0C6C5DA684C5487C95939192811733667B73C52E6B2309E593B62AF84360DB27EF1587D473B2270C3367E28A13D80DA61FBC1AD1449DD2ED0DDF047750AEB8181B018EB1D5E854861441DA94CA50A46CAEAB513914657E8D0F531347030F63D80F3DE8503721835E7F9A70B66248EA27EA99413CACFD9F4A4461B3E832536A2B57F4A8242424AF03BFC6684A9180FE006EE5758F5C7E078E92244C952415959E636E392F4444491B2351565ECD31F559963FDE6823CB5310D61A3E830A3321D4BA4FF4AB81AD22063BEA2381DFF2BE99A5A88064DF8934DB21BEF460EA448D0346C1868D8B794F09FD534A825C81AFA04939A2ED9229CC98E0978A80023E023FBE87E6C7179CC09B6C05D5B06685426CEA4D34B57E252E63F717EE14980B7EB539375AF53A83177B1BF23C539F4991382F4C8109B710E07708F7A3F24F468BB065A6BC089D4C23915EC14B4BD09FCC0E497026CC51B17AB362717045F4A0BA5FB81446803032E45CB4719A26D2613D17789DCA38AC640334FB538887699CCB7744DA7D735353D66A7A26084F09FD531AADD9CC899795A9E93D0F68921BA65DBED404EAF3B86FF153577EECA2BBC1AFA08B60AD002EAB57153A1D4B7060B7EDB1320400401B1D00ACA5ED58A4175E8081873E89A9A9A9E934B53445424371CD397D2CD97B1113FF006A2D52499E215FBD3ACD030B14386DFBA72F7A9F4020196808A198B6F7247C73446CF80054F4BB44F801C3EEA232129773254FA96A6A6A6A6A66A5FC86214473E2D5282BA08B43367DEA76ABB504090CAB36C77A304BC800B021331AD16000384BE2EB1506C402D1D5E0BDF55A5BFA6226592C4C18FD79A8F63DE31876CBE881F77D885F74D25600BE1FD749A9A5A9E9353D27AAA8B716502437B53C09D614035DAA5D36095370388A8ACDD20E56C548A3D3591858C050002B042E9063B7AAEFA600C4998F8286E0083608A9A9A1658095E299DC9DDD894C4D1AF69FD7A67A4D4F49F464C0062F98A8FF00F9260110139B5A9AB865D03BAD74D0A5F6D3000272E5344461216360FF006DD1A9EB6AA660E40FE6B4A73D1254306F0B0D43C7824E1B25081958925CB7F57AADFA36E8DBD0E29E8B03DAA75809A7AFFFC40032110002010204030506070100000000000001020300110412213105104113202232510630618191B11433425271A1C1F0FFDA0008010201013F00EFA005803589B860B6D0578F61615918EED5D98EA4D1897D2961075B576D147A5C9FE2BF0F14BF966C7D0D4913466CC3BF0CFA76726DF6AC96391BA55CAEF57BED4C5635CEF52CEF2EFB7A72EC581006F5886CB1647376F711B67456EA34E445B514F1F6C997A8DB996CAAEE3A69EE625C91853B9D68024D853CF147A6E6BF1A4795451249B9E4CA5A3751BEFDC8E1793CA2861E34FCC6B9F8566897CA9F5AED97F60FA50923BDCA0A570FE2AC4C9D9A651B9FB7776371BD3AA3EAEBAFA8A38788ECD6FE452E16306E5AE29E62DE14D052F02E20D1F682136FEFE9BD302A72B6879E178370F970CA81487B0F17C48F4DADFE5710C2BA390775D0FCBBA401BB0AF07EE1F5A319B5C548731D36AF66E34476C532E62B602FEA7AFF005A50C5BE6BB6D5ED7080CC9227988D7E3E9586C0BCE331D05370A005D5B5AC171AEC90418AF091B1E84563F1D1CF8C695366FF0005AB130766732EC7BD86F046D27CAAE6B807168B02AE92FEAB7CAD53F1BC3019CBDCFC2833F13C419A4F28FF00AD4B6B694580DEA444986561714FC2A33E52453E0F247949B8A6194907BAFE18517E7CF0D8379CFA0F5A862585422D30B1AD0520B0D79620D909352E14C84BC66F7A65286CC2DDCC568557D0561F0B24E7C234F5A8387C716ADA9AB5B99B2EC285EDAF2750E0A9A9E37C2CA452BA4EB6715340D11D76E428C071188C9D2911635CAA34F738BC3ACE963B8A40639321A5716B30B8E51AE670B58440333F527DC13D2AF47515361927B31D0D4913466CDCA30C5C64DEB0CAC175A26DDEBD1366157E43734543687970CC383E33D7EDC9F6A1CAF57ABF26B11AD48E249028DA9E219C2AD5AC4D5F9605408C7CB93EC6877C69A8ACCD7CD7D79FFFC4002E110002010302040503040300000000000001020300041121311012204105223251811330610614A1F02391C1FFDA0008010301013F00EB3B559AA88F2A7535A5647B566813524EB1FA8D3DC17D947CD3C3247B8C8A041EB5668CF325238750EBDEB7E13CE53C89BD63B9DF81914024ED52B2BBE536FB168D82C9F3C6EA3E53F507CF1BB3A2A7BFD9B55CB17F8A670832D4F72EDE8D053176F5371BC182ADD04814B148FB0C50B53DDA85A2FB9A365ECD4A81005153BF3BE3B0E9650C30C29AD31E83FEE8C128ED9AFA721D31515BAC63277A6F17B20FF4CCA33FDEFB50C30C8A0280AB8F16BF8AE1A4E60533A2FE33EFEF48EAEA255F4B6A3E7A4DDA7615FBB5F6349728DA6683A8D0D78FB3CAAB6A8DCA18124FE0634FE75A6B28D63F2EFEF5FA4DE6681D24F483A7FDA9EF121381A9A5F12D7CCBA55F7833BC867B3F306DC7706BC3EC1E1B25824DC7F1939AD54F2B6FD5127D4900A118049AFD41E152DF9478775CFCE6A0F04BD7C465703F34B1A786DB8863DCFF00734C083AD04276A46784E41C1A5F1271B8CD49389FCD8C11435E9B25C966E33DD2423DCD4B2B4ADCCD564904CBCB268C28086DD73A0AB997EB4A5C708572401455A3D185039DBA2C47F8F353DC2423CDBD4D7D249A0D07428E6DCD1C674E0AECA722A1916E2306A7B4C6A9BD03D8EFC6398416C1BBD3B973CCDBFD9B59DA17C8DAB21D79854F6E24D46FC09C0CD5C31C2A7B0FB0077E0A706A19DE1381A8A8E5590647038C6B5211A0EF4064E051D3A95720D6382EAA281236E12363845EAA61AF1C56382120E94A9CA849DE94F9799AB3A0C7190F08877A7DFAF359D318E3FFD9, '', '2021-01-13 17:15:36', '', '2021-03-12 20:30:44', b'1');
  151 +COMMIT;
  152 +
  153 +-- ----------------------------
128 154 -- Table structure for inf_job
129 155 -- ----------------------------
130 156 DROP TABLE IF EXISTS `inf_job`;
... ... @@ -175,7 +201,7 @@ CREATE TABLE `inf_job_log` (
175 201 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
176 202 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
177 203 PRIMARY KEY (`id`) USING BTREE
178   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表';
  204 +) ENGINE=InnoDB AUTO_INCREMENT=2322 DEFAULT CHARSET=utf8mb4 COMMENT='定时任务日志表';
179 205  
180 206 -- ----------------------------
181 207 -- Records of inf_job_log
... ... @@ -209,7 +235,7 @@ CREATE TABLE `sys_dept` (
209 235 -- ----------------------------
210 236 BEGIN;
211 237 INSERT INTO `sys_dept` VALUES (100, 'èŠ‹é“æºç ', 0, 0, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-01-06 19:45:52', b'0');
212   -INSERT INTO `sys_dept` VALUES (101, '深圳总公å¸', 100, 1, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0');
  238 +INSERT INTO `sys_dept` VALUES (101, '深圳总公å¸', 100, 1, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2021-03-14 20:26:18', b'0');
213 239 INSERT INTO `sys_dept` VALUES (102, '长沙分公å¸', 100, 2, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0');
214 240 INSERT INTO `sys_dept` VALUES (103, 'ç ”å‘部门', 101, 1, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0');
215 241 INSERT INTO `sys_dept` VALUES (104, '市场部门', 101, 2, 'è‹¥ä¾', '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0');
... ... @@ -238,7 +264,7 @@ CREATE TABLE `sys_dict_data` (
238 264 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
239 265 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
240 266 PRIMARY KEY (`id`) USING BTREE
241   -) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='字典数æ®è¡¨';
  267 +) ENGINE=InnoDB AUTO_INCREMENT=78 DEFAULT CHARSET=utf8mb4 COMMENT='字典数æ®è¡¨';
242 268  
243 269 -- ----------------------------
244 270 -- Records of sys_dict_data
... ... @@ -298,6 +324,19 @@ INSERT INTO `sys_dict_data` VALUES (61, 2, &#39;管ç†å‘˜&#39;, &#39;2&#39;, &#39;user_type&#39;, 0, NUL
298 324 INSERT INTO `sys_dict_data` VALUES (62, 0, '未处ç†', '0', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:19', '', '2021-02-26 08:11:23', b'0');
299 325 INSERT INTO `sys_dict_data` VALUES (63, 1, '已处ç†', '1', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:26', '', '2021-02-26 08:11:29', b'0');
300 326 INSERT INTO `sys_dict_data` VALUES (64, 2, '已忽略', '2', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:34', '', '2021-02-26 08:11:34', b'0');
  327 +INSERT INTO `sys_dict_data` VALUES (65, 1, '云片', 'YUN_PIAN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:14', '1', '2021-04-13 00:20:13', b'0');
  328 +INSERT INTO `sys_dict_data` VALUES (66, 2, '阿里云', 'ALIYUN', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:05:26', '1', '2021-04-13 00:20:16', b'0');
  329 +INSERT INTO `sys_dict_data` VALUES (67, 1, '验è¯ç ', '1', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:57', '1', '2021-04-05 21:50:57', b'0');
  330 +INSERT INTO `sys_dict_data` VALUES (68, 2, '通知', '2', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:08', '1', '2021-04-05 21:51:08', b'0');
  331 +INSERT INTO `sys_dict_data` VALUES (69, 0, 'è¥é”€', '3', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:51:15', '1', '2021-04-05 21:51:15', b'0');
  332 +INSERT INTO `sys_dict_data` VALUES (70, 0, 'åˆå§‹åŒ–', '0', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:33', '1', '2021-04-11 09:30:18', b'0');
  333 +INSERT INTO `sys_dict_data` VALUES (71, 1, 'å‘逿ˆåŠŸ', '10', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:43', '1', '2021-04-11 09:30:20', b'0');
  334 +INSERT INTO `sys_dict_data` VALUES (72, 2, 'å‘é€å¤±è´¥', '20', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:49', '1', '2021-04-11 09:30:22', b'0');
  335 +INSERT INTO `sys_dict_data` VALUES (73, 3, 'ä¸å‘é€', '30', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:19:44', '1', '2021-04-11 09:30:23', b'0');
  336 +INSERT INTO `sys_dict_data` VALUES (74, 0, '等待结果', '0', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:43', '1', '2021-04-17 23:05:19', b'0');
  337 +INSERT INTO `sys_dict_data` VALUES (75, 1, '接收æˆåŠŸ', '10', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:29:25', '1', '2021-04-11 20:29:35', b'0');
  338 +INSERT INTO `sys_dict_data` VALUES (76, 2, '接收失败', '20', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:29:31', '1', '2021-04-11 20:29:39', b'0');
  339 +INSERT INTO `sys_dict_data` VALUES (77, 0, '调试(钉钉)', 'DEBUG_DING_TALK', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-13 00:20:37', '1', '2021-04-13 00:20:37', b'0');
301 340 COMMIT;
302 341  
303 342 -- ----------------------------
... ... @@ -317,7 +356,7 @@ CREATE TABLE `sys_dict_type` (
317 356 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
318 357 PRIMARY KEY (`id`) USING BTREE,
319 358 UNIQUE KEY `dict_type` (`type`)
320   -) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';
  359 +) ENGINE=InnoDB AUTO_INCREMENT=115 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';
321 360  
322 361 -- ----------------------------
323 362 -- Records of sys_dict_type
... ... @@ -340,28 +379,10 @@ INSERT INTO `sys_dict_type` VALUES (107, &#39;定时任务状æ€&#39;, &#39;inf_job_status&#39;,
340 379 INSERT INTO `sys_dict_type` VALUES (108, '定时任务日志状æ€', 'inf_job_log_status', 0, NULL, '', '2021-02-08 10:03:51', '', '2021-02-08 10:03:51', b'0');
341 380 INSERT INTO `sys_dict_type` VALUES (109, '用户类型', 'user_type', 0, NULL, '', '2021-02-26 00:15:51', '', '2021-02-26 00:15:51', b'0');
342 381 INSERT INTO `sys_dict_type` VALUES (110, 'API 异常数æ®çš„处ç†çжæ€', 'inf_api_error_log_process_status', 0, NULL, '', '2021-02-26 07:07:01', '', '2021-02-26 07:07:01', b'0');
343   -COMMIT;
344   -
345   --- ----------------------------
346   --- Table structure for sys_file
347   --- ----------------------------
348   -DROP TABLE IF EXISTS `sys_file`;
349   -CREATE TABLE `sys_file` (
350   - `id` varchar(188) NOT NULL COMMENT '文件路径',
351   - `content` blob NOT NULL COMMENT '文件内容',
352   - `creator` varchar(64) DEFAULT '' COMMENT '创建者',
353   - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
354   - `updater` varchar(64) DEFAULT '' COMMENT '更新者',
355   - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
356   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
357   - PRIMARY KEY (`id`) USING BTREE
358   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表\n';
359   -
360   --- ----------------------------
361   --- Records of sys_file
362   --- ----------------------------
363   -BEGIN;
364   -INSERT INTO `sys_file` VALUES ('add5ec1891a7d97d2cc1d60847e16294.jpg', 0xFFD8FFE000104A46494600010101006400640000FFDB00840006040506050406060506070706080A100A0A09090A140E0F0C1017141818171416161A1D251F1A1B231C1616202C20232627292A29191F2D302D283025282928010707070A080A130A0A13281A161A2828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828282828FFC200110800EC00EC03012200021101031101FFC4001C0001000105010100000000000000000000000701020405060308FFDA0008010100000000FA14000707A3E3F659B5F2B3CB1B171B57BAFA2C000BE1ED8731AFC752DF3F2F2EF249DF79D0000A465CD59E5ACA5BE7B09BB71441BBB943DC0017447C95DB0D662E4FD0192237F3E17E8600039B8AF556E579647D0B60807A3DA49368003D7E7AC1A5B678CA3255081A4AEBC0007AFCF5834C6E8BA3DDF756902CE39200034908796C661E82C04073E003D755A4B2FC9F48A34CFA172404152C6F415C4E175B9BB879F8EAB41CEF792A807CF1B1903B7BADA5DC0737D47ADCB3CFCBCE3FD2CCBDB807CE35CAF5E8B3F0757D0FBF1BE7DD655B65965BF384B9397B80F9C6A2EDAF577F05A0F3D9499958BACF4E7F41D0654E168118657B59A8E2E43DD71B31FC73ED26EE33FB0E939E8FB135FEFBA9528007159783CAD981B8C5DDC9596A5231D6E17173476200BE26D8351AFCEB33FBED077DABE2FCFB6DB59CE463365A018B156E4A3CB7DDBC65CDE3EDF71259C945B3D7900725CFFB554C0EA3B769E32BEC92F794A4711EEE3BDEBAC0380C657CB7FD6E50F3D4E266EE0C2E2F9DE73CA6FD90237B7CB7FDB5F554B6911C8BB8A948CB039CE5E79E94230B3B6E98A82945453C225BB87D44E3DA158BB77DF56A00A1452DE6A2DB397D6FD5C562696B215002DAE1E4D29CCF8471C9DBF4E9EB03CF952A028A539DE8296E1C7DD3C2DABFA80BA3690760A5C28514A626A37F4A523DC2D7E9A772B1CC9B7733B2DA2828A2DB628EAFABA523DD1D29302BC6767EE88E46DB1414A29486A1A9CF8E99E2BD91303CF98ECE8897A9EC5428A294A70B04E5E279751D613038FECBD5485BA5911428A514530780D5E9B7B62930B93ED2D6A222EA64A28A514514ADB444FE56D7FFC4001B01000105010100000000000000000000000001020304050607FFDA0008010210000000F3600075E70AD558EA46005B9DCE33E1B7367000694AC32CD3CC00034E58A1A69A59A125A512766681ACD81C9A194D4F44E2B280D94750E8BD1383E7AE6F60E4D500BB0F4BB3CCEBAC540E7500BD5CB7D135B33E0E769342FA6DDE51AAADE56CD084D7DE780014F9CBF8EFEA2E800346D4CDC87F57654104628C38ED9DE6B841064EB5978DEAAEB155104115A7FFC4001A010002030101000000000000000000000000040102030506FFDA0008010310000000EB00043FBC939A35CE4003A76164A7AFC9800061CB22B8CAC0006EDA78C4B0B845F5B8C23981D3533A3CA742D7F0DDCD006A346783E07D9FA05BCFF7A92016EAF9EE0FABE6CE8DD4901AE84ADC1E8F5BCDE0CEC483FA72520BD62DE8D54E46B8F500019F429A318AC001259BEAF3215C8009BC1B5F4C55D2B5924B9560D55CB5AD2490B4EB3FFFC400451000010302020604090A050403010000000102030400110512061321314151203261711014222330425281D11524333440537291A1B116436292C16382E1F0357383A2FFDA0008010100013F01F4FC6B4931051908C2222ACB706690B1EAA397BE9E719811335B2B68D800AF9C4D735CB6D6A56E48036229BC3DF575B223BCDE861A84ED71E3F95AB53091D672FF00EEA270F1EA66FCE8C8863AB187F68A335A1D58C8FD2953F932DD2A628FF2DAFEDA3249FE5B5FD94F2D9BF94D3415FD236D4518C6ABE66D627A9E194AADF6047585622C3B866352E54C49533297E43C3684F61E54E105ACC946B788038D09B2E495063220A77802EAFD696EBF721C79DBF2BDABBC93DFD0346AF750424152D5B9291727DD587E8ACA9090B9EE888DFDDA76AFE02B0FC270FC3BEAB1939FEF17E52BF3AD62A9195C405B4B4B883B8A4DFEC0B4A1D694D3C80B6D42C526B12C39583FCE226672028F96DEF2DF68ECAC4594AB24A64EC3B7327876D22521D4E5988CDFEA246DA7A294A758C9D635CC784D1AC330F918A492D46B04A7E91D3B91F13D9585619170A6B2C74E678F59E575954493BFC3F25BB11CD6E1129C8CBF66FE49A8BA55221B89631D8BB0EC0F37C6A2BEC4C643B0DD4BAD9E47D38B1052B014856C20D488BF26622B84ADB11F1999278734D3CD969D520F034CBCB65576D56A25895BECCBDCFD534F34B65595C16FF346A0C473109CDC465594A815297ECA79D448CCC18A88D15395B4FEA799E88A75B43AD943A90B41DE0D3C1FD1F9499905CB344D8A4EEEEA0A0E34DB805B3A42BD3E92C432F075A9B1E7E3F9D47BAA7283A961F4FF00311E14485253915671BF655FE3952D0082B64E64F11C53DF583CD187630C495FD09F34E7603C6962C766E3D1462130904EA7F0E534EBB20A9A8F159D74B705F28DC91CCD46D185BEE25EC6A46B2DB7528DD4A3BAC2C06C03D3B7B4E53B8EC34B4EA98531F72FAD1E1357208209046E229C3981CC37EF238FBAB43315D73670D92BBBAD8BB2A3EB2797BBA3872017F32BAA819AB4559221393DC1E7652AE3B10370FB0B5D7152961C7A42C6E72438A1DD7B785C7128EB1DBC071350B02C5268CC969319BF69EDE7DD4DE8728FD63123DCDA2B0DD178906735284A7DC5B66E01B513737E824EAF0A98E0DE465FFBF9D436F5387C4680B656923F4FB0E3738C083E6B6CA7CEAD94F6F3F752C25166D06E940CA0F3EDF061B02462920B516C9423E91E56E4F6769AC2F0785860BB2DEB1FE2F39B5468A89DFD37ADF213DF8BFC8A1B59688DD907A20835227C18BF5898CA7B335E97A478524D92EBAE7E06C9AFE228C7A90A72FF00F9D0C7D9E302701FFAFF00E6938EE1C4F9C53CCF6BAD102A563586C58FAE3290E83D54B67328FBAA6CE7A64A54A90323A5391B6FEE91F13E04A1C79C6D9605DD7559103B6A2456A0446E2C74D9081B7B4F3F43193AF852637150B8AD1E942760CC281BB8D8D5AC768E9EFA992A3416F3CC7D0D0E00EF34EE9148977460F12C3EF9EDD4A87325FF00E47107560FA8DEC151F0B84C7518413CD5B68009EA803BA8D1A34F448EEAB32DA467F680B1FCEA4E1EA4254A64A9CE394EFF00CE92A0ADDDC472AD098E97A5CA9AB17D479A6FBCEF3E899714D38168DE2A338E33255270D7FC5DF59BADA5F51CA87A48CA9496B1465511FF006BD4FCE9BCAEA02D95A5C41E2937ACA7978522FDD5896901538A8B82A75AE8EB3C7AA9A630B0A735F3DC5497CEF2ADD49B0161B055EAF57A2689A346A7E30F78C29A8694D926C5445EF4EC85BEE053A84B723DB1D55F61F8D684048C04A13F4A1D59713C526FC7DDE910FAC2321F2DBF655B4530A61B5E646BE3AB9B2E5A9B9F3B66A31726DC1D40AF95B1C693B04391EEB1A5693632D9F3986B67B81A7B1BC5719CD0C3488ADFF3549BEEE550E3B71590DB42C07EB4FBEDC76CB8F2825239D3FA43B7E6D1CA87359B531A4842AD263651CD06A3496A4B41C616149357ABD5E8D71AC230886BD1790EBA91AE5A5C257C516BD4194BF18650B480D1010A17BDCF3A8921FC2DC131ABAB56723E8FBC4703DF51A435362B72A32B332E0B8F4C1453D524771A87AE7DD09D6B9946D3B69B425B4E540B0A52821254A3648173498F37185AA42595AA3A4F93C8549929662BEEB2DA17A95645051B1BD61AFB38A5D011AB780BE5E75143D86C82E37D5F593ED0A8B25B94C875955D06AF4FBEDB29CCF3894279A8D7CA71782D44730DAAD45F4C98EE884F20B994E5B1DC6B0275E6D9721C8D6A2DD64AB7281A7F4714257993E689BDEFBAA4C96A2CA4B6F1F36F2721ECEDAD1F9FF22622B8EF9F993EADBFD0AE7DD446E236A4EE3E813A1E7F9B89AFFDA9A4E8743DBAD99257EFB57F0861BF7D27FBA95A1F879EA48909F7D3FA21251730A685F24AC5AA6C79B86AAD3D8213EDA77560907E6F9DCD855B4FC29C8A35B649B0B5EB1D516F0C91CFABFAD600DB4CE09112DDB206C7FCD692869CD209EB67E8CBA77568FB4E7CA91CB69E3B7BAB1646469C58DA40D82B0D8A21450D5EEAEB28F6D3697E63C598405D3F48EABAADFC4F6541C1A24539D49D7C8E2EBBB4FBB97827E0F0A68BADA0DBBC1D6FC950AC423488032CE0A7A2DFC99281B53F8870EFAF9D048CA10F208D8A0ACA4D3985096A0E4C514AF8250760158AC44B91EE91D5163DD5A218C2B38C3272AE7F92BE7D94458FA4D2D7C96A261C9EB495E65F6213B6A23EDA59B28D88A724A8BAA523603B2B1B19B0C7EE6DB2FF00AD6172DF430194B8AD572A95804790F1790ACAA3BC54382C4004A7CA739D7D6E50B6D69A55D479AB9504392A408B1CD96A175AFEED3CFBF95458EDC5610CB09CADA770E8101408201076106BE4A5AF5AF610E06D21C524B0EED4120F03C29D5CA8DF5D82FB607AEDF9C4FE95F29C4E2EE5FC4922B15318A82E3C8403BD3955B8D68962C716C36CF2AF299D8AED1CFD1A05D429D77C771D9926F76DAF30DFBB7F87158AA99096CA1412A36DF50E0C88EC84A9E43847022DFAD66929D81827B42C56A243E7CFA836DF241BA8FBE965319901A6EFEAA109F589DC2B0F8660425EE724AAEB591EB2B977560788B8E4F991E5150505272E6EEF04B9CC450758BF2BD91BE9CD296028846AFF00326938FC89CBD461CC05BCA1D6DB64F693585C4F1282DB19B3A86D52B9A8ED27C0A48575803DE2B178EC2602C865B06E3720560EB30B4B5ACBB1124588A56C51F4531EF168129FE2DB648EFAC211920357DEBF2CFBFA4EB8865B52DD504A06F26B0684B71D4CD94828007996D5BC7F51EDF0694C53E3D16446506DE5052566DB176B581AF18C4BAB9503B75A6D5E28EBC6F31DCC9FBB46C1EFA4B6848B252903BAB01467C656B4F55A672ABBC9D9FB7431F72CDB4D73398D48F271BC29437EB2DFA8A77AE7D1697B9ABD1E75237BAA08A69391B4279003A3E3216EEA6321521EF61BDB6EF3C2B0DC1D7AE4C9C4B22DC4ED6D94ED4B7DBDA7C38AC3F1D8A50956475273215C8FC29D73C5DCD5CB4961CE4BDC7B8F1AD6200B95A2DCEF4D2D7255921365F5F31D51DE6B08802045C8559DD51CCE2FDA3D0C614A54F702BD5D83BAB16D6F8E40547FA54AC94F7D31A4B8CC43F3D8A1F6C6F396C7F31585E9161D889080B2C3E7D473E34A491DDE834CCDD186B1EDBD7E83257254530DB2F91BC8D891DEAA6B020ED8CF794E7FA4DF928F89A8EC351DB0DB0DA1B40F5522DD15A12E272B894A93C942E2BE4A819F3F8947CDCF2548C4998A754CB79B2F04EC02B0F9C8999C25252A45B37BFA12633525367537E4788A9FA3C1E19DA78EB1BBA9A047ADC298703CD058D97DE391E22B11C2DB76EB69365F2158563B3B082942FE710C6F4AB78EEAC33108B8AC7D7435DFDA41DE9E9E949CD8E618DFB282AB781D73265012A5AD46C94245CA8F6544C194F0CF89916E11D0760FC478FED484A5080942425237002C07A03B8D390714724A9866304241B78C38AF27BC0E3585406F0F881A412B513996E1DEB573E963917C46619681F357CD9DFE85FB5DC68D6251B617503F10A61C7F0F9224C0564706F1C0D6038DC7C659B27CDCA48F2DB3FB8ECE96909CDA551C704B17FDE9E73568D892B59395284EF51E558461BE2BE7E45973163CA57040F653FF0076FD89E6D0F34B6DD48536B16524F115219561B24457AFA93B1874FAC3D93DB46A5B3A978A7D5DE2BCE30FA64C45143E837045617A510254342E63896246E5A4F3ECE871AC636E972FFA628FDEB47E3090F2A7AF6A5376D81FBABFC7D931D85F2843530DB812F6F483B95DE3FCD403250B5C793B54DEC39B62D3D879F7D62A9F36857236F03B192B5E6B91D01BEB1F51563D2D2D6C756866324F6AAFF1A8ECA23B0DB2D0B21B4848FB03EFA59C80DCAD672A1237A8F431E694A845F66FAE8FE705B88E229C8AC6330997C9C8FDBC9751BD3F11D958C3722235AB9A80368CAEA7A8BF81ECE937D7AC3E5993A62DBE47997242F2F7E5B0FB0E1C7C664489AADC545A67B1037FE67A12D84C98EB6944A42B883623B6B47642E015E1F33638855BE07B8D62AB4BF065B4B48394849078D4A82B601531771AF638A7BB9D254142E9DA3A093635A4C9660CEC15D650869297944D85870BD4394DCC6CB8C056AAF64AC8B05768ECF4F2DCD54579C1BD0852BF4AC0148560B0CB7BB563F3E3D1D286836F44969EB156A17DA0EEFD69C92A5EB2FEBA520F78F03F874779C2B505051DF9556E86C00A9442509DA49E1410349E787568B6131890DF02F2B9F750000000B01E0C6F11F1169B4A7E95D5048ECEDAC35F5488895B9D6DA0FA4202810ADA0EC35A3B3061932561524D834B3AB27D9E0698D21C35F9DE2AD48BBB7CA0DBC951E40F434CDDB4161A1D653A93D2DE6B1B5AF11949C1A2A8A507CA94E0E09F6477D30CB71D9432CA421B40CA948E1E1D28CCAC563A6FB3589FDAF58565F106B29BECDBDFE974FE225296662363AA56AC914127665D878562DA4AE468AD371D00CB50DAB56D48EDA81A5188C792954B73C618BF969290081D94FE2D15A4660E67BEEB7C6B1A7D53A6C7521C4E6CF982378B749D7931A3BD217D56D2555A2ED2BC4972DEFA696B2E13D9C3A1A48ABCC2AF61D47C2B00776BAD1FC43D2E99435CBC1EED0BAD956B2DD9C6A1B49912DA6F7A6F750ECA95152C4D534D9590948B85F0A71BF20D3816E93AE56729397B36568FA72B4FEC1B17BFDDD2D2E51F929A8E8DF25E4B74CB619690DA3AA80123C24D85CEE158A2F5ADBCBE6ACDFF00EAB0755B104F6823D32224742CAD11D94ACF108158E600FC99CB950D6DDDCB67439B368E37A8BA332B5A15296C8037041BFBEBF86B1242F54DA1A5206E74AF7FBABC45386B288F9B3BBD65ABB4F4B1FDB3B0349DC645FA18B2CA2039978ECAC4C5E0BBB48D97D9583FD7D9FF00BC3EC4EAD4E3AA5ACDD4A37E87FFC40029100100010303030402030101000000000001110021314151611071812091A1B130C1D1E1F0F140FFDA0008010100013F10FCE0B032D36BD74B69C8F6137A56A00C92E87777A82C152709D05827769D2D7B9F63F9A46C9B00FBB58E2CDE53EC547DD0BE1FDB41C2099E4F34E5A46241F4524D856723E655FC52A491A36144F10CD40C4961A5C0BFF8103389AB0DE8E169ED3DA981205B99E90B6F348CE90978FE14B61C15F4914ABF205FBE8D3D0A94B3D0E3F81769770BD97397E02682183E43CB1E2294727B5459448C1F25223088FE782179644A756382AA57C9FE734AE1D0F0A701E6841A16200E50FD7B5470BDCBE9DFD05429E19C96DC9A7BA2ACC52D45BBE8705A90953D65F35AD3FEB99A590583939461F10F15A997264EE64F3F9E17411A4473255DDB9BE3538D3C6F578EB43B9A352612C991EE56128D1979DAA72568E4EC7A0FF3C04C5986AE87347DCF7BCBAC9AAEAFA548290C636AC7B65C8D3BACB3232B35930F151AC466D20FEFF3CC91C50966E4F24FB563C096344FFBF1D1A6C29CB58E56553F01BAFC6DB92D589215DF9F161A0910DE1309E91A4CDA29F33334A674442CB680DA8854C0743C2EDBC7BD0282100D0FCE0719341D4A99198FBCDA64FBA69E8D4598425190EC4041DDA3C5B82951A60E51DDAA3E3B52228E4F427CED4F18FF0071508A74B9647DCD673FF804D4A38B5059803F0D34D47E461BF60AD946AA06E1BD452466E708EEBFAAB2938A163582A6777A1B4417B4508404404130FF00C248277E82EF8177C57B207167C957A5BF1A24CFA0F83DE8309CD60E1D0E0A6EEF1EB825B909A199214F63F0E714B2520DDA2A51BE056E096A589D2F5DAD52A33D0919F769379F44C1EF4895CE0F71A1286E36727605FDE2A69EC7647BB3F36C7484A6721AF6095ED45888919D64EAADFF0009631BDD8FE42B946162DDFC47AC15012D0471C8F60CBE29652EC840344313C2BDAA752C85BC7FE2A0133A73F9A3E01C400FAA4EEFBD2A6A65A33146488BB82F4E5E9BB25DB53DE895948C8215B268D0F0109B429EF441E5A5555CBF85500DEC3C539B9C696FD37699342E895CEC3DCE6A18E24207DA93D5489913A5DE017574A0FEA8371DB47BE3BD33BB64287CE7EB8A02103004051428F502ABA8AEEEBD8331B14A11200C06CEFB7BA928269B796034B0FC8B944B27FF000F15DE8A43C9AD4025299D5E162529513F4BBBD642AC6592CDB6B71A6A54C1026E2FD19AD4FE9D56EF35A945965D8DDA621FED4050052E66C78735ACD18C8EC9A3D0D1A2A1B3BD4F34B5BCA10E9114E98389E470D4FF00E47B1F402D3C157ADC184DC4D11B27E1289EBDE9A95790A51C2F23B1B79A020917BAE5776A73848E819A57822058E3777A12C6DA4081E68776F0320E1A9FA41C6193BECD61BD6E422644D1A69C1E605290A6D53DD14EC582B905A4C9521224524A4A6F522922B4B3B54EE99E4108D4C94B898ECD23C8CFF544090121713F036F227061F745B95C4087DD76EDA1FC5679B4929F45446DA8786A51E4BC5E51984B7EF8A8C0B0846F3A781F3489EBB4DE198A24320B3903483C8D4C2A4A7CCD00A4B060A597DE69CE00BDD97A839230195B07BA5199B32B5613E2D1531C9029E2FD2F31449AC5B8EF06C780A2C416363151862F7BB7933D9A8BE618658C8659D948A121381A28DBD9A3492C7BB254BBC94292C0466187B944DCA59CBFE7DA9A24FC6498A56248B9542F760F7A04762C3ACBA525502026850E3C127540D1A046D2B454B42CA124F6A72E4227A1C5044809A72C1ECDDF053088498961EF606AF050512C64795755CAEAFA0CB140488E89519BAED8014AE5DB0516E50404E66EA9146859863DCA9B889A276AD83EA92922BEBA4BDA1FEFF1C1A9B1F9B6190EEFDF54A42870B38AB1438400D8FE454E3B10FF009A619765E0DAC03C5EA43892D4AA039573DDAB53A1BA0B0E1603F9ACD1C4C659243819B76A8767DAA22904D9477D03BD04082D2C5F21158C6E001E16580F35255E63C4C7DC3429853B50503EC0FDD36AD1A0667B50146DEACA90E39068C0E7F143BF432DF3152AC253754FA8CA2CAA029E88A344D93D1160C837BBD0AE5E121981C4B0E4A5489372FB2682C64C80ABCB2D1328C00A7B21306CD1EC9A8EA60376EC163E569366ABDE4FE684245BF12BC8C9E32CFEAA0500B670450FA1405C987F403BD4CF6F28F7AFBF834EB02C03C9074791669747BC1CD8C5A934A7A8C5065C622F3E1838A8357E2C4BB1B183D02C2003EC99F32D12B97A62200EB6D2B548D8B7163DCADBD6912F183F15756FB8FC196AC3F11FCD4CAF49A52B50B97C96F04B436BFA8F698F913B560E6C31FDFA1A6AD7922786818BB16A38A686076D63E8AC2D08B30CA09EC4F9A9A7A427A30DBB0D1B85CC0C6C5DA684C5487C95939192811733667B73C52E6B2309E593B62AF84360DB27EF1587D473B2270C3367E28A13D80DA61FBC1AD1449DD2ED0DDF047750AEB8181B018EB1D5E854861441DA94CA50A46CAEAB513914657E8D0F531347030F63D80F3DE8503721835E7F9A70B66248EA27EA99413CACFD9F4A4461B3E832536A2B57F4A8242424AF03BFC6684A9180FE006EE5758F5C7E078E92244C952415959E636E392F4444491B2351565ECD31F559963FDE6823CB5310D61A3E830A3321D4BA4FF4AB81AD22063BEA2381DFF2BE99A5A88064DF8934DB21BEF460EA448D0346C1868D8B794F09FD534A825C81AFA04939A2ED9229CC98E0978A80023E023FBE87E6C7179CC09B6C05D5B06685426CEA4D34B57E252E63F717EE14980B7EB539375AF53A83177B1BF23C539F4991382F4C8109B710E07708F7A3F24F468BB065A6BC089D4C23915EC14B4BD09FCC0E497026CC51B17AB362717045F4A0BA5FB81446803032E45CB4719A26D2613D17789DCA38AC640334FB538887699CCB7744DA7D735353D66A7A26084F09FD531AADD9CC899795A9E93D0F68921BA65DBED404EAF3B86FF153577EECA2BBC1AFA08B60AD002EAB57153A1D4B7060B7EDB1320400401B1D00ACA5ED58A4175E8081873E89A9A9A9E934B53445424371CD397D2CD97B1113FF006A2D52499E215FBD3ACD030B14386DFBA72F7A9F4020196808A198B6F7247C73446CF80054F4BB44F801C3EEA232129773254FA96A6A6A6A6A66A5FC86214473E2D5282BA08B43367DEA76ABB504090CAB36C77A304BC800B021331AD16000384BE2EB1506C402D1D5E0BDF55A5BFA6226592C4C18FD79A8F63DE31876CBE881F77D885F74D25600BE1FD749A9A5A9E9353D27AAA8B716502437B53C09D614035DAA5D36095370388A8ACDD20E56C548A3D3591858C050002B042E9063B7AAEFA600C4998F8286E0083608A9A9A1658095E299DC9DDD894C4D1AF69FD7A67A4D4F49F464C0062F98A8FF00F9260110139B5A9AB865D03BAD74D0A5F6D3000272E5344461216360FF006DD1A9EB6AA660E40FE6B4A73D1254306F0B0D43C7824E1B25081958925CB7F57AADFA36E8DBD0E29E8B03DAA75809A7AFFFC40032110002010204030506070100000000000001020300110412213105104113202232510630618191B11433425271A1C1F0FFDA0008010201013F00EFA005803589B860B6D0578F61615918EED5D98EA4D1897D2961075B576D147A5C9FE2BF0F14BF966C7D0D4913466CC3BF0CFA76726DF6AC96391BA55CAEF57BED4C5635CEF52CEF2EFB7A72EC581006F5886CB1647376F711B67456EA34E445B514F1F6C997A8DB996CAAEE3A69EE625C91853B9D68024D853CF147A6E6BF1A4795451249B9E4CA5A3751BEFDC8E1793CA2861E34FCC6B9F8566897CA9F5AED97F60FA50923BDCA0A570FE2AC4C9D9A651B9FB7776371BD3AA3EAEBAFA8A38788ECD6FE452E16306E5AE29E62DE14D052F02E20D1F682136FEFE9BD302A72B6879E178370F970CA81487B0F17C48F4DADFE5710C2BA390775D0FCBBA401BB0AF07EE1F5A319B5C548731D36AF66E34476C532E62B602FEA7AFF005A50C5BE6BB6D5ED7080CC9227988D7E3E9586C0BCE331D05370A005D5B5AC171AEC90418AF091B1E84563F1D1CF8C695366FF0005AB130766732EC7BD86F046D27CAAE6B807168B02AE92FEAB7CAD53F1BC3019CBDCFC2833F13C419A4F28FF00AD4B6B694580DEA444986561714FC2A33E52453E0F247949B8A6194907BAFE18517E7CF0D8379CFA0F5A862585422D30B1AD0520B0D79620D909352E14C84BC66F7A65286CC2DDCC568557D0561F0B24E7C234F5A8387C716ADA9AB5B99B2EC285EDAF2750E0A9A9E37C2CA452BA4EB6715340D11D76E428C071188C9D2911635CAA34F738BC3ACE963B8A40639321A5716B30B8E51AE670B58440333F527DC13D2AF47515361927B31D0D4913466CDCA30C5C64DEB0CAC175A26DDEBD1366157E43734543687970CC383E33D7EDC9F6A1CAF57ABF26B11AD48E249028DA9E219C2AD5AC4D5F9605408C7CB93EC6877C69A8ACCD7CD7D79FFFC4002E110002010302040503040300000000000001020300041121311012204105223251811330610614A1F02391C1FFDA0008010301013F00EB3B559AA88F2A7535A5647B566813524EB1FA8D3DC17D947CD3C3247B8C8A041EB5668CF325238750EBDEB7E13CE53C89BD63B9DF81914024ED52B2BBE536FB168D82C9F3C6EA3E53F507CF1BB3A2A7BFD9B55CB17F8A670832D4F72EDE8D053176F5371BC182ADD04814B148FB0C50B53DDA85A2FB9A365ECD4A81005153BF3BE3B0E9650C30C29AD31E83FEE8C128ED9AFA721D31515BAC63277A6F17B20FF4CCA33FDEFB50C30C8A0280AB8F16BF8AE1A4E60533A2FE33EFEF48EAEA255F4B6A3E7A4DDA7615FBB5F6349728DA6683A8D0D78FB3CAAB6A8DCA18124FE0634FE75A6B28D63F2EFEF5FA4DE6681D24F483A7FDA9EF121381A9A5F12D7CCBA55F7833BC867B3F306DC7706BC3EC1E1B25824DC7F1939AD54F2B6FD5127D4900A118049AFD41E152DF9478775CFCE6A0F04BD7C465703F34B1A786DB8863DCFF00734C083AD04276A46784E41C1A5F1271B8CD49389FCD8C11435E9B25C966E33DD2423DCD4B2B4ADCCD564904CBCB268C28086DD73A0AB997EB4A5C708572401455A3D185039DBA2C47F8F353DC2423CDBD4D7D249A0D07428E6DCD1C674E0AECA722A1916E2306A7B4C6A9BD03D8EFC6398416C1BBD3B973CCDBFD9B59DA17C8DAB21D79854F6E24D46FC09C0CD5C31C2A7B0FB0077E0A706A19DE1381A8A8E5590647038C6B5211A0EF4064E051D3A95720D6382EAA281236E12363845EAA61AF1C56382120E94A9CA849DE94F9799AB3A0C7190F08877A7DFAF359D318E3FFD9, '', '2021-01-13 17:15:36', '', '2021-01-13 17:15:36', b'0');
  382 +INSERT INTO `sys_dict_type` VALUES (111, '短信渠é“ç¼–ç ', 'sys_sms_channel_code', 0, NULL, '1', '2021-04-05 01:04:50', '1', '2021-04-05 01:04:50', b'0');
  383 +INSERT INTO `sys_dict_type` VALUES (112, '短信模æ¿çš„类型', 'sys_sms_template_type', 0, NULL, '1', '2021-04-05 21:50:43', '1', '2021-04-05 21:50:43', b'0');
  384 +INSERT INTO `sys_dict_type` VALUES (113, '短信å‘é€çжæ€', 'sys_sms_send_status', 0, NULL, '1', '2021-04-11 20:18:03', '1', '2021-04-11 09:30:02', b'0');
  385 +INSERT INTO `sys_dict_type` VALUES (114, '短信接收状æ€', 'sys_sms_receive_status', 0, NULL, '1', '2021-04-11 20:27:14', '1', '2021-04-11 20:27:14', b'0');
365 386 COMMIT;
366 387  
367 388 -- ----------------------------
... ... @@ -382,7 +403,7 @@ CREATE TABLE `sys_login_log` (
382 403 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
383 404 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
384 405 PRIMARY KEY (`id`) USING BTREE
385   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录';
  406 +) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8mb4 COMMENT='系统访问记录';
386 407  
387 408 -- ----------------------------
388 409 -- Records of sys_login_log
... ... @@ -411,7 +432,7 @@ CREATE TABLE `sys_menu` (
411 432 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
412 433 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
413 434 PRIMARY KEY (`id`) USING BTREE
414   -) ENGINE=InnoDB AUTO_INCREMENT=1087 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨';
  435 +) ENGINE=InnoDB AUTO_INCREMENT=1110 DEFAULT CHARSET=utf8mb4 COMMENT='èœå•æƒé™è¡¨';
415 436  
416 437 -- ----------------------------
417 438 -- Records of sys_menu
... ... @@ -422,63 +443,63 @@ INSERT INTO `sys_menu` VALUES (2, &#39;基础设施&#39;, &#39;&#39;, 1, 2, 0, &#39;/infra&#39;, &#39;monito
422 443 INSERT INTO `sys_menu` VALUES (3, 'ç ”å‘工具', '', 1, 3, 0, '/tool', 'tool', NULL, 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-06 12:44:42', b'0');
423 444 INSERT INTO `sys_menu` VALUES (4, 'è‹¥ä¾å®˜ç½‘', '', 1, 4, 0, 'http://ruoyi.vip', 'guide', NULL, 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 21:54:28', b'1');
424 445 INSERT INTO `sys_menu` VALUES (100, '用户管ç†', 'system:user:list', 2, 1, 1, 'user', 'user', 'system/user/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
425   -INSERT INTO `sys_menu` VALUES (101, '角色管ç†', 'system:role:list', 2, 2, 1, 'role', 'peoples', 'system/role/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
426   -INSERT INTO `sys_menu` VALUES (102, 'èœå•管ç†', 'system:menu:list', 2, 3, 1, 'menu', 'tree-table', 'system/menu/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
427   -INSERT INTO `sys_menu` VALUES (103, '部门管ç†', 'system:dept:list', 2, 4, 1, 'dept', 'tree', 'system/dept/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
428   -INSERT INTO `sys_menu` VALUES (104, 'å²—ä½ç®¡ç†', 'system:post:list', 2, 5, 1, 'post', 'post', 'system/post/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
429   -INSERT INTO `sys_menu` VALUES (105, '字典管ç†', 'system:dict:list', 2, 6, 1, 'dict', 'dict', 'system/dict/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
430   -INSERT INTO `sys_menu` VALUES (106, 'é…置管ç†', 'infra:config:list', 2, 1, 2, 'config', 'edit', 'infra/config/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-08 20:03:57', b'0');
431   -INSERT INTO `sys_menu` VALUES (107, '通知公告', 'system:notice:list', 2, 8, 1, 'notice', 'message', 'system/notice/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
  446 +INSERT INTO `sys_menu` VALUES (101, '角色管ç†', '', 2, 2, 1, 'role', 'peoples', 'system/role/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:04:49', b'0');
  447 +INSERT INTO `sys_menu` VALUES (102, 'èœå•管ç†', '', 2, 3, 1, 'menu', 'tree-table', 'system/menu/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:04:28', b'0');
  448 +INSERT INTO `sys_menu` VALUES (103, '部门管ç†', '', 2, 4, 1, 'dept', 'tree', 'system/dept/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:25:19', b'0');
  449 +INSERT INTO `sys_menu` VALUES (104, 'å²—ä½ç®¡ç†', '', 2, 5, 1, 'post', 'post', 'system/post/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:38:23', b'0');
  450 +INSERT INTO `sys_menu` VALUES (105, '字典管ç†', '', 2, 6, 1, 'dict', 'dict', 'system/dict/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:16:58', b'0');
  451 +INSERT INTO `sys_menu` VALUES (106, 'é…置管ç†', '', 2, 1, 2, 'config', 'edit', 'infra/config/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:10', b'0');
  452 +INSERT INTO `sys_menu` VALUES (107, '通知公告', '', 2, 8, 1, 'notice', 'message', 'system/notice/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:51:39', b'0');
432 453 INSERT INTO `sys_menu` VALUES (108, '日志管ç†', '', 1, 9, 1, 'log', 'log', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:34:28', b'0');
433 454 INSERT INTO `sys_menu` VALUES (109, '在线用户', 'system:user-session:list', 2, 10, 1, 'user-session', 'online', 'system/session/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-26 08:21:20', b'0');
434   -INSERT INTO `sys_menu` VALUES (110, '定时任务', 'infra:job:query', 2, 2, 2, 'job', 'job', 'infra/job/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-07 13:01:36', b'0');
  455 +INSERT INTO `sys_menu` VALUES (110, '定时任务', '', 2, 2, 2, 'job', 'job', 'infra/job/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:25:51', b'0');
435 456 INSERT INTO `sys_menu` VALUES (111, 'MySQL 监控', '', 2, 4, 2, 'druid', 'druid', 'infra/druid/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:32', b'0');
436 457 INSERT INTO `sys_menu` VALUES (112, 'Java 监控', '', 2, 6, 2, 'admin-server', 'server', 'infra/server', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:41', b'0');
437 458 INSERT INTO `sys_menu` VALUES (113, 'Redis 监控', '', 2, 5, 2, 'redis', 'redis', 'infra/redis/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-02-26 02:18:37', b'0');
438 459 INSERT INTO `sys_menu` VALUES (114, 'è¡¨å•æž„建', 'tool:build:list', 2, 1, 3, 'build', 'build', 'tool/build/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
439 460 INSERT INTO `sys_menu` VALUES (115, '代ç ç”Ÿæˆ', 'tool:codegen:query', 2, 0, 3, 'codegen', 'code', 'tool/codegen/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-03-06 03:43:14', b'0');
440 461 INSERT INTO `sys_menu` VALUES (116, '系统接å£', 'tool:swagger:list', 2, 3, 3, 'swagger', 'swagger', 'tool/swagger/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:45', b'0');
441   -INSERT INTO `sys_menu` VALUES (500, 'æ“作日志', 'system:operate-log:list', 2, 1, 108, 'operate-log', 'form', 'system/operatelog/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-16 18:25:45', b'0');
442   -INSERT INTO `sys_menu` VALUES (501, '登录日志', 'system:login-log:list', 2, 2, 108, 'login-log', 'logininfor', 'system/loginlog/index', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-18 05:29:58', b'0');
  462 +INSERT INTO `sys_menu` VALUES (500, 'æ“作日志', '', 2, 1, 108, 'operate-log', 'form', 'system/operatelog/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:42:56', b'0');
  463 +INSERT INTO `sys_menu` VALUES (501, '登录日志', '', 2, 2, 108, 'login-log', 'logininfor', 'system/loginlog/index', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:39:23', b'0');
443 464 INSERT INTO `sys_menu` VALUES (1001, '用户查询', 'system:user:query', 3, 1, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
444   -INSERT INTO `sys_menu` VALUES (1002, '用户新增', 'system:user:add', 3, 2, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
445   -INSERT INTO `sys_menu` VALUES (1003, '用户修改', 'system:user:edit', 3, 3, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
446   -INSERT INTO `sys_menu` VALUES (1004, '用户删除', 'system:user:remove', 3, 4, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  465 +INSERT INTO `sys_menu` VALUES (1002, '用户新增', 'system:user:create', 3, 2, 100, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:21:47', b'0');
  466 +INSERT INTO `sys_menu` VALUES (1003, '用户修改', 'system:user:update', 3, 3, 100, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:21:54', b'0');
  467 +INSERT INTO `sys_menu` VALUES (1004, '用户删除', 'system:user:delete', 3, 4, 100, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:22:03', b'0');
447 468 INSERT INTO `sys_menu` VALUES (1005, '用户导出', 'system:user:export', 3, 5, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
448 469 INSERT INTO `sys_menu` VALUES (1006, '用户导入', 'system:user:import', 3, 6, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
449   -INSERT INTO `sys_menu` VALUES (1007, 'é‡ç½®å¯†ç ', 'system:user:resetPwd', 3, 7, 100, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  470 +INSERT INTO `sys_menu` VALUES (1007, 'é‡ç½®å¯†ç ', 'system:user:update-password', 3, 7, 100, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:20:55', b'0');
450 471 INSERT INTO `sys_menu` VALUES (1008, '角色查询', 'system:role:query', 3, 1, 101, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
451   -INSERT INTO `sys_menu` VALUES (1009, '角色新增', 'system:role:add', 3, 2, 101, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
452   -INSERT INTO `sys_menu` VALUES (1010, '角色修改', 'system:role:edit', 3, 3, 101, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
453   -INSERT INTO `sys_menu` VALUES (1011, '角色删除', 'system:role:remove', 3, 4, 101, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  472 +INSERT INTO `sys_menu` VALUES (1009, '角色新增', 'system:role:create', 3, 2, 101, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:05:24', b'0');
  473 +INSERT INTO `sys_menu` VALUES (1010, '角色修改', 'system:role:update', 3, 3, 101, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:05:14', b'0');
  474 +INSERT INTO `sys_menu` VALUES (1011, '角色删除', 'system:role:delete', 3, 4, 101, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 22:05:05', b'0');
454 475 INSERT INTO `sys_menu` VALUES (1012, '角色导出', 'system:role:export', 3, 5, 101, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
455 476 INSERT INTO `sys_menu` VALUES (1013, 'èœå•查询', 'system:menu:query', 3, 1, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
456   -INSERT INTO `sys_menu` VALUES (1014, 'èœå•新增', 'system:menu:add', 3, 2, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
457   -INSERT INTO `sys_menu` VALUES (1015, 'èœå•修改', 'system:menu:edit', 3, 3, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
458   -INSERT INTO `sys_menu` VALUES (1016, 'èœå•删除', 'system:menu:remove', 3, 4, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  477 +INSERT INTO `sys_menu` VALUES (1014, 'èœå•新增', 'system:menu:create', 3, 2, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-03-13 15:49:36', b'0');
  478 +INSERT INTO `sys_menu` VALUES (1015, 'èœå•修改', 'system:menu:update', 3, 3, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-03-13 15:49:30', b'0');
  479 +INSERT INTO `sys_menu` VALUES (1016, 'èœå•删除', 'system:menu:delete', 3, 4, 102, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-03-13 15:49:45', b'0');
459 480 INSERT INTO `sys_menu` VALUES (1017, '部门查询', 'system:dept:query', 3, 1, 103, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
460   -INSERT INTO `sys_menu` VALUES (1018, '部门新增', 'system:dept:add', 3, 2, 103, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
461   -INSERT INTO `sys_menu` VALUES (1019, '部门修改', 'system:dept:edit', 3, 3, 103, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
462   -INSERT INTO `sys_menu` VALUES (1020, '部门删除', 'system:dept:remove', 3, 4, 103, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  481 +INSERT INTO `sys_menu` VALUES (1018, '部门新增', 'system:dept:create', 3, 2, 103, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:25:30', b'0');
  482 +INSERT INTO `sys_menu` VALUES (1019, '部门修改', 'system:dept:update', 3, 3, 103, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:25:37', b'0');
  483 +INSERT INTO `sys_menu` VALUES (1020, '部门删除', 'system:dept:delete', 3, 4, 103, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:25:43', b'0');
463 484 INSERT INTO `sys_menu` VALUES (1021, '岗使Ÿ¥è¯¢', 'system:post:query', 3, 1, 104, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
464   -INSERT INTO `sys_menu` VALUES (1022, '岗使–°å¢ž', 'system:post:add', 3, 2, 104, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
465   -INSERT INTO `sys_menu` VALUES (1023, 'å²—ä½ä¿®æ”¹', 'system:post:edit', 3, 3, 104, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
466   -INSERT INTO `sys_menu` VALUES (1024, 'å²—ä½åˆ é™¤', 'system:post:remove', 3, 4, 104, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  485 +INSERT INTO `sys_menu` VALUES (1022, '岗使–°å¢ž', 'system:post:create', 3, 2, 104, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:38:34', b'0');
  486 +INSERT INTO `sys_menu` VALUES (1023, 'å²—ä½ä¿®æ”¹', 'system:post:update', 3, 3, 104, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:38:41', b'0');
  487 +INSERT INTO `sys_menu` VALUES (1024, 'å²—ä½åˆ é™¤', 'system:post:delete', 3, 4, 104, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:38:48', b'0');
467 488 INSERT INTO `sys_menu` VALUES (1025, 'å²—ä½å¯¼å‡º', 'system:post:export', 3, 5, 104, '', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
468 489 INSERT INTO `sys_menu` VALUES (1026, '字典查询', 'system:dict:query', 3, 1, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
469   -INSERT INTO `sys_menu` VALUES (1027, '字典新增', 'system:dict:add', 3, 2, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
470   -INSERT INTO `sys_menu` VALUES (1028, '字典修改', 'system:dict:edit', 3, 3, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
471   -INSERT INTO `sys_menu` VALUES (1029, '字典删除', 'system:dict:remove', 3, 4, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  490 +INSERT INTO `sys_menu` VALUES (1027, '字典新增', 'system:dict:create', 3, 2, 105, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:19:29', b'0');
  491 +INSERT INTO `sys_menu` VALUES (1028, '字典修改', 'system:dict:update', 3, 3, 105, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:19:36', b'0');
  492 +INSERT INTO `sys_menu` VALUES (1029, '字典删除', 'system:dict:delete', 3, 4, 105, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:19:45', b'0');
472 493 INSERT INTO `sys_menu` VALUES (1030, '字典导出', 'system:dict:export', 3, 5, 105, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
473 494 INSERT INTO `sys_menu` VALUES (1031, 'é…置查询', 'infra:config:query', 3, 1, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:00', b'0');
474   -INSERT INTO `sys_menu` VALUES (1032, 'é…置新增', 'infra:config:add', 3, 2, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:05', b'0');
475   -INSERT INTO `sys_menu` VALUES (1033, 'é…置修改', 'infra:config:edit', 3, 3, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:33:52', b'0');
476   -INSERT INTO `sys_menu` VALUES (1034, 'é…置删除', 'infra:config:remove', 3, 4, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:12', b'0');
  495 +INSERT INTO `sys_menu` VALUES (1032, 'é…置新增', 'infra:config:create', 3, 2, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:18', b'0');
  496 +INSERT INTO `sys_menu` VALUES (1033, 'é…置修改', 'infra:config:update', 3, 3, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:30', b'0');
  497 +INSERT INTO `sys_menu` VALUES (1034, 'é…置删除', 'infra:config:delete', 3, 4, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-10 01:12:36', b'0');
477 498 INSERT INTO `sys_menu` VALUES (1035, 'é…置导出', 'infra:config:export', 3, 5, 106, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-20 14:34:19', b'0');
478 499 INSERT INTO `sys_menu` VALUES (1036, '公告查询', 'system:notice:query', 3, 1, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
479   -INSERT INTO `sys_menu` VALUES (1037, '公告新增', 'system:notice:add', 3, 2, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
480   -INSERT INTO `sys_menu` VALUES (1038, '公告修改', 'system:notice:edit', 3, 3, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
481   -INSERT INTO `sys_menu` VALUES (1039, '公告删除', 'system:notice:remove', 3, 4, 107, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-05 22:36:55', b'0');
  500 +INSERT INTO `sys_menu` VALUES (1037, '公告新增', 'system:notice:create', 3, 2, 107, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:51:48', b'0');
  501 +INSERT INTO `sys_menu` VALUES (1038, '公告修改', 'system:notice:update', 3, 3, 107, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:51:55', b'0');
  502 +INSERT INTO `sys_menu` VALUES (1039, '公告删除', 'system:notice:delete', 3, 4, 107, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 21:52:01', b'0');
482 503 INSERT INTO `sys_menu` VALUES (1040, 'æ“作查询', 'system:operate-log:query', 3, 1, 500, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-16 18:28:10', b'0');
483 504 INSERT INTO `sys_menu` VALUES (1042, '日志导出', 'system:operate-log:export', 3, 2, 500, '', '', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-16 18:28:23', b'0');
484 505 INSERT INTO `sys_menu` VALUES (1043, '登录查询', 'system:login-log:query', 3, 1, 501, '#', '#', '', 0, 'admin', '2021-01-05 17:03:48', '', '2021-01-18 05:29:26', b'0');
... ... @@ -511,15 +532,37 @@ INSERT INTO `sys_menu` VALUES (1074, &#39;测试示例表导出&#39;, &#39;tool:test-demo:ex
511 532 INSERT INTO `sys_menu` VALUES (1075, '任务触å‘', 'infra:job:trigger', 3, 8, 110, '', '', '', 0, '', '2021-02-07 13:03:10', '', '2021-02-07 13:03:10', b'0');
512 533 INSERT INTO `sys_menu` VALUES (1076, 'æ•°æ®åº“文档', '', 2, 5, 3, 'db-doc', 'table', 'tool/dbDoc/index', 0, '', '2021-02-08 01:41:47', '', '2021-02-08 01:49:00', b'0');
513 534 INSERT INTO `sys_menu` VALUES (1077, '链路追踪', '', 2, 7, 2, 'skywalking', 'eye-open', 'infra/skywalking', 0, '', '2021-02-08 20:41:31', '', '2021-02-26 02:18:45', b'0');
514   -INSERT INTO `sys_menu` VALUES (1078, '访问日志', 'infra:api-access-log:query', 2, 1, 1083, 'api-access-log', 'log', 'infra/apiAccessLog/index', 0, '', '2021-02-26 01:32:59', '', '2021-02-26 07:53:46', b'0');
  535 +INSERT INTO `sys_menu` VALUES (1078, '访问日志', '', 2, 1, 1083, 'api-access-log', 'log', 'infra/apiAccessLog/index', 0, '', '2021-02-26 01:32:59', '1', '2021-03-10 01:28:09', b'0');
515 536 INSERT INTO `sys_menu` VALUES (1079, 'API 访问日志表创建', 'system:api-access-log:create', 3, 1, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:00', b'1');
516 537 INSERT INTO `sys_menu` VALUES (1080, 'API 访问日志表更新', 'system:api-access-log:update', 3, 2, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:08', b'1');
517 538 INSERT INTO `sys_menu` VALUES (1081, 'API 访问日志表删除', 'system:api-access-log:delete', 3, 3, 1078, '', '', '', 1, '', '2021-02-26 01:32:59', '', '2021-02-26 02:21:27', b'1');
518   -INSERT INTO `sys_menu` VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 4, 1078, '', '', '', 0, '', '2021-02-26 01:32:59', '', '2021-02-26 02:23:22', b'0');
  539 +INSERT INTO `sys_menu` VALUES (1082, '日志导出', 'infra:api-access-log:export', 3, 2, 1078, '', '', '', 0, '', '2021-02-26 01:32:59', '1', '2021-03-10 01:28:13', b'0');
519 540 INSERT INTO `sys_menu` VALUES (1083, 'API 日志', '', 2, 3, 2, 'log', 'log', NULL, 0, '', '2021-02-26 02:18:24', '', '2021-02-26 02:20:17', b'0');
520 541 INSERT INTO `sys_menu` VALUES (1084, '错误日志', 'infra:api-error-log:query', 2, 2, 1083, 'api-error-log', 'log', 'infra/apiErrorLog/index', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:54:40', b'0');
521   -INSERT INTO `sys_menu` VALUES (1085, '日志处ç†', 'infra:api-error-log:update-status', 3, 1, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:53:20', b'0');
522   -INSERT INTO `sys_menu` VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 4, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '', '2021-02-26 07:53:20', b'0');
  542 +INSERT INTO `sys_menu` VALUES (1085, '日志处ç†', 'infra:api-error-log:update-status', 3, 2, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '1', '2021-03-10 01:28:18', b'0');
  543 +INSERT INTO `sys_menu` VALUES (1086, '日志导出', 'infra:api-error-log:export', 3, 3, 1084, '', '', '', 0, '', '2021-02-26 07:53:20', '1', '2021-03-10 01:28:21', b'0');
  544 +INSERT INTO `sys_menu` VALUES (1087, '任务查询', 'infra:job:query', 3, 1, 110, '', '', '', 0, '1', '2021-03-10 01:26:19', '1', '2021-03-10 01:26:19', b'0');
  545 +INSERT INTO `sys_menu` VALUES (1088, '日志查询', 'infra:api-access-log:query', 3, 1, 1078, '', '', '', 0, '1', '2021-03-10 01:28:04', '1', '2021-03-10 01:29:38', b'0');
  546 +INSERT INTO `sys_menu` VALUES (1089, '日志查询', 'infra:api-error-log:query', 3, 1, 1084, '', '', '', 0, '1', '2021-03-10 01:29:09', '1', '2021-03-10 01:29:09', b'0');
  547 +INSERT INTO `sys_menu` VALUES (1090, '文件管ç†', '', 2, 0, 2, 'file', 'upload', 'infra/file/index', 0, '', '2021-03-12 20:16:20', '1', '2021-03-13 11:07:05', b'0');
  548 +INSERT INTO `sys_menu` VALUES (1091, '文件查询', 'infra:file:query', 3, 1, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0');
  549 +INSERT INTO `sys_menu` VALUES (1092, '文件删除', 'infra:file:delete', 3, 4, 1090, '', '', '', 0, '', '2021-03-12 20:16:20', '', '2021-03-12 20:16:20', b'0');
  550 +INSERT INTO `sys_menu` VALUES (1093, '短信管ç†', '', 1, 11, 1, 'sms', 'validCode', NULL, 0, '1', '2021-04-05 01:10:16', '1', '2021-04-05 01:11:38', b'0');
  551 +INSERT INTO `sys_menu` VALUES (1094, '短信渠é“', '', 2, 0, 1093, 'sms-channel', 'phone', 'system/sms/smsChannel', 0, '', '2021-04-01 11:07:15', '1', '2021-04-09 23:44:07', b'0');
  552 +INSERT INTO `sys_menu` VALUES (1095, 'çŸ­ä¿¡æ¸ é“æŸ¥è¯¢', 'system:sms-channel:query', 3, 1, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  553 +INSERT INTO `sys_menu` VALUES (1096, '短信渠é“创建', 'system:sms-channel:create', 3, 2, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  554 +INSERT INTO `sys_menu` VALUES (1097, 'çŸ­ä¿¡æ¸ é“æ›´æ–°', 'system:sms-channel:update', 3, 3, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  555 +INSERT INTO `sys_menu` VALUES (1098, '短信渠é“删除', 'system:sms-channel:delete', 3, 4, 1094, '', '', '', 0, '', '2021-04-01 11:07:15', '', '2021-04-01 11:07:15', b'0');
  556 +INSERT INTO `sys_menu` VALUES (1100, '短信模æ¿', '', 2, 1, 1093, 'sms-template', 'phone', 'system/sms/smsTemplate', 0, '', '2021-04-01 17:35:17', '1', '2021-04-11 19:34:21', b'0');
  557 +INSERT INTO `sys_menu` VALUES (1101, 'çŸ­ä¿¡æ¨¡æ¿æŸ¥è¯¢', 'system:sms-template:query', 3, 1, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  558 +INSERT INTO `sys_menu` VALUES (1102, '短信模æ¿åˆ›å»º', 'system:sms-template:create', 3, 2, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  559 +INSERT INTO `sys_menu` VALUES (1103, 'çŸ­ä¿¡æ¨¡æ¿æ›´æ–°', 'system:sms-template:update', 3, 3, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  560 +INSERT INTO `sys_menu` VALUES (1104, '短信模æ¿åˆ é™¤', 'system:sms-template:delete', 3, 4, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  561 +INSERT INTO `sys_menu` VALUES (1105, '短信模æ¿å¯¼å‡º', 'system:sms-template:export', 3, 5, 1100, '', '', '', 0, '', '2021-04-01 17:35:17', '', '2021-04-01 17:35:17', b'0');
  562 +INSERT INTO `sys_menu` VALUES (1106, 'å‘逿µ‹è¯•短信', 'system:sms-template:send-sms', 3, 6, 1100, '', '', '', 0, '1', '2021-04-11 00:26:40', '1', '2021-04-11 00:26:40', b'0');
  563 +INSERT INTO `sys_menu` VALUES (1107, '短信日志', '', 2, 2, 1093, 'sms-log', 'phone', 'system/sms/smsLog', 0, '', '2021-04-11 08:37:05', '1', '2021-04-11 19:34:25', b'0');
  564 +INSERT INTO `sys_menu` VALUES (1108, '短信日志查询', 'system:sms-log:query', 3, 1, 1107, '', '', '', 0, '', '2021-04-11 08:37:05', '', '2021-04-11 08:37:05', b'0');
  565 +INSERT INTO `sys_menu` VALUES (1109, '短信日志导出', 'system:sms-log:export', 3, 5, 1107, '', '', '', 0, '', '2021-04-11 08:37:05', '', '2021-04-11 08:37:05', b'0');
523 566 COMMIT;
524 567  
525 568 -- ----------------------------
... ... @@ -579,7 +622,7 @@ CREATE TABLE `sys_operate_log` (
579 622 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
580 623 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
581 624 PRIMARY KEY (`id`) USING BTREE
582   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录';
  625 +) ENGINE=InnoDB AUTO_INCREMENT=177 DEFAULT CHARSET=utf8mb4 COMMENT='æ“作日志记录';
583 626  
584 627 -- ----------------------------
585 628 -- Records of sys_operate_log
... ... @@ -610,8 +653,8 @@ CREATE TABLE `sys_post` (
610 653 -- Records of sys_post
611 654 -- ----------------------------
612 655 BEGIN;
613   -INSERT INTO `sys_post` VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-05 17:03:48', '', '2021-01-05 17:03:48', b'0');
614   -INSERT INTO `sys_post` VALUES (2, 'se', '项目ç»ç†', 2, 0, '', 'admin', '2021-01-05 17:03:48', '', '2021-01-05 17:03:48', b'0');
  656 +INSERT INTO `sys_post` VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:39:03', b'0');
  657 +INSERT INTO `sys_post` VALUES (2, 'se', '项目ç»ç†', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2021-03-14 20:39:05', b'0');
615 658 INSERT INTO `sys_post` VALUES (3, 'hr', '人力资æº', 3, 0, '', 'admin', '2021-01-05 17:03:48', '', '2021-01-05 17:03:48', b'0');
616 659 INSERT INTO `sys_post` VALUES (4, 'user', '普通员工', 4, 0, '', 'admin', '2021-01-05 17:03:48', '', '2021-01-05 17:03:48', b'0');
617 660 INSERT INTO `sys_post` VALUES (5, 'test', '测试岗ä½', 0, 1, '132', '', '2021-01-07 15:07:44', '', '2021-01-07 15:10:35', b'1');
... ... @@ -645,7 +688,7 @@ CREATE TABLE `sys_role` (
645 688 BEGIN;
646 689 INSERT INTO `sys_role` VALUES (1, '超级管ç†å‘˜', 'admin', 1, 1, '', 0, 1, '超级管ç†å‘˜', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 12:40:20', b'0');
647 690 INSERT INTO `sys_role` VALUES (2, '普通角色', 'common', 2, 2, '', 0, 1, '普通角色', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 11:46:58', b'0');
648   -INSERT INTO `sys_role` VALUES (101, '测试账å·', 'test', 0, 2, '[104]', 0, 2, '132', '', '2021-01-06 13:49:35', '', '2021-01-21 02:15:26', b'0');
  691 +INSERT INTO `sys_role` VALUES (101, '测试账å·', 'test', 0, 2, '[104]', 0, 2, '132', '', '2021-01-06 13:49:35', '1', '2021-03-14 22:17:20', b'0');
649 692 COMMIT;
650 693  
651 694 -- ----------------------------
... ... @@ -825,6 +868,116 @@ INSERT INTO `sys_role_menu` VALUES (238, 101, 1065, &#39;&#39;, &#39;2021-01-21 03:23:27&#39;, &#39;
825 868 COMMIT;
826 869  
827 870 -- ----------------------------
  871 +-- Table structure for sys_sms_channel
  872 +-- ----------------------------
  873 +DROP TABLE IF EXISTS `sys_sms_channel`;
  874 +CREATE TABLE `sys_sms_channel` (
  875 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  876 + `signature` varchar(10) NOT NULL COMMENT '短信签å',
  877 + `code` varchar(63) NOT NULL COMMENT '渠é“ç¼–ç ',
  878 + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€',
  879 + `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  880 + `api_key` varchar(128) NOT NULL COMMENT '短信 API 的账å·',
  881 + `api_secret` varchar(128) DEFAULT NULL COMMENT '短信 API 的秘钥',
  882 + `callback_url` varchar(255) DEFAULT NULL COMMENT '短信å‘é€å›žè°ƒ URL',
  883 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  884 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  885 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  886 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  887 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  888 + PRIMARY KEY (`id`) USING BTREE
  889 +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='短信渠é“';
  890 +
  891 +-- ----------------------------
  892 +-- Records of sys_sms_channel
  893 +-- ----------------------------
  894 +BEGIN;
  895 +INSERT INTO `sys_sms_channel` VALUES (1, '芋é“', 'YUN_PIAN', 0, '呵呵呵哒', '1555a14277cb8a608cf45a9e6a80d510', NULL, 'http://java.nat300.top/api/system/sms/callback/sms/yunpian', '', '2021-03-31 06:12:20', '1', '2021-04-13 01:03:19', b'0');
  896 +INSERT INTO `sys_sms_channel` VALUES (2, 'Ballcat', 'ALIYUN', 0, '啦啦啦', 'LTAI5tCnKso2uG3kJ5gRav88', 'fGJ5SNXL7P1NHNRmJ7DJaMJGPyE55C', NULL, '', '2021-03-31 11:53:10', '1', '2021-04-14 00:08:37', b'0');
  897 +INSERT INTO `sys_sms_channel` VALUES (3, '测试', 'YUN_PIAN', 0, '哈哈哈', '23132', NULL, 'http://www.baidu.com', '1', '2021-04-05 21:10:34', '1', '2021-04-11 16:21:58', b'1');
  898 +INSERT INTO `sys_sms_channel` VALUES (4, '测试渠é“', 'DEBUG_DING_TALK', 0, '123', '696b5d8ead48071237e4aa5861ff08dbadb2b4ded1c688a7b7c9afc615579859', 'SEC5c4e5ff888bc8a9923ae47f59e7ccd30af1f14d93c55b4e2c9cb094e35aeed67', NULL, '1', '2021-04-13 00:23:14', '1', '2021-04-14 00:07:10', b'0');
  899 +COMMIT;
  900 +
  901 +-- ----------------------------
  902 +-- Table structure for sys_sms_log
  903 +-- ----------------------------
  904 +DROP TABLE IF EXISTS `sys_sms_log`;
  905 +CREATE TABLE `sys_sms_log` (
  906 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  907 + `channel_id` bigint(20) NOT NULL COMMENT '短信渠é“ç¼–å·',
  908 + `channel_code` varchar(63) NOT NULL COMMENT '短信渠é“ç¼–ç ',
  909 + `template_id` bigint(20) NOT NULL COMMENT '模æ¿ç¼–å·',
  910 + `template_code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ',
  911 + `template_type` tinyint(4) NOT NULL COMMENT '短信类型',
  912 + `template_content` varchar(255) NOT NULL COMMENT '短信内容',
  913 + `template_params` varchar(255) NOT NULL COMMENT 'çŸ­ä¿¡å‚æ•°',
  914 + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模æ¿ç¼–å·',
  915 + `mobile` varchar(11) NOT NULL COMMENT '手机å·',
  916 + `user_id` bigint(20) DEFAULT NULL COMMENT '用户编å·',
  917 + `user_type` tinyint(4) DEFAULT NULL COMMENT '用户类型',
  918 + `send_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'å‘é€çжæ€',
  919 + `send_time` datetime DEFAULT NULL COMMENT 'å‘逿—¶é—´',
  920 + `send_code` int(11) DEFAULT NULL COMMENT 'å‘é€ç»“果的编ç ',
  921 + `send_msg` varchar(255) DEFAULT NULL COMMENT 'å‘é€ç»“果的æç¤º',
  922 + `api_send_code` varchar(63) DEFAULT NULL COMMENT '短信 API å‘é€ç»“果的编ç ',
  923 + `api_send_msg` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€å¤±è´¥çš„æç¤º',
  924 + `api_request_id` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€è¿”回的唯一请求 ID',
  925 + `api_serial_no` varchar(255) DEFAULT NULL COMMENT '短信 API å‘é€è¿”回的åºå·',
  926 + `receive_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '接收状æ€',
  927 + `receive_time` datetime DEFAULT NULL COMMENT '接收时间',
  928 + `api_receive_code` varchar(63) DEFAULT NULL COMMENT 'API 接收结果的编ç ',
  929 + `api_receive_msg` varchar(255) DEFAULT NULL COMMENT 'API 接收结果的说明',
  930 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  931 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  932 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  933 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  934 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  935 + PRIMARY KEY (`id`) USING BTREE
  936 +) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8mb4 COMMENT='短信日志';
  937 +
  938 +-- ----------------------------
  939 +-- Records of sys_sms_log
  940 +-- ----------------------------
  941 +BEGIN;
  942 +COMMIT;
  943 +
  944 +-- ----------------------------
  945 +-- Table structure for sys_sms_template
  946 +-- ----------------------------
  947 +DROP TABLE IF EXISTS `sys_sms_template`;
  948 +CREATE TABLE `sys_sms_template` (
  949 + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç¼–å·',
  950 + `type` tinyint(4) NOT NULL COMMENT '短信签å',
  951 + `status` tinyint(4) NOT NULL COMMENT 'å¼€å¯çжæ€',
  952 + `code` varchar(63) NOT NULL COMMENT '模æ¿ç¼–ç ',
  953 + `name` varchar(63) NOT NULL COMMENT '模æ¿åç§°',
  954 + `content` varchar(255) NOT NULL COMMENT '模æ¿å†…容',
  955 + `params` varchar(255) NOT NULL COMMENT '傿•°æ•°ç»„',
  956 + `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  957 + `api_template_id` varchar(63) NOT NULL COMMENT '短信 API 的模æ¿ç¼–å·',
  958 + `channel_id` bigint(20) NOT NULL COMMENT '短信渠é“ç¼–å·',
  959 + `channel_code` varchar(63) NOT NULL COMMENT '短信渠é“ç¼–ç ',
  960 + `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  961 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  962 + `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  963 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
  964 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
  965 + PRIMARY KEY (`id`) USING BTREE
  966 +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='短信模æ¿';
  967 +
  968 +-- ----------------------------
  969 +-- Records of sys_sms_template
  970 +-- ----------------------------
  971 +BEGIN;
  972 +INSERT INTO `sys_sms_template` VALUES (2, 1, 0, 'test_01', '测试验è¯ç çŸ­ä¿¡', '正在进行登录æ“作{operation},您的验è¯ç æ˜¯{code}', '[\"operation\",\"code\"]', NULL, '4383920', 1, 'YUN_PIAN', '', '2021-03-31 10:49:38', '1', '2021-04-10 01:22:00', b'0');
  973 +INSERT INTO `sys_sms_template` VALUES (3, 1, 0, 'test_02', '公告通知', '您的验è¯ç {code},该验è¯ç 5分钟内有效,请勿泄æ¼äºŽä»–人ï¼', '[\"code\"]', NULL, 'SMS_207945135', 2, 'ALIYUN', '', '2021-03-31 11:56:30', '1', '2021-04-10 01:22:02', b'0');
  974 +INSERT INTO `sys_sms_template` VALUES (4, 3, 0, 'test-ooxx', '测试模æ¿', 'biubiubiu', '[]', '1111', '110', 1, 'YUN_PIAN', '1', '2021-04-09 23:58:42', '1', '2021-04-02 07:47:12', b'1');
  975 +INSERT INTO `sys_sms_template` VALUES (5, 3, 0, 'test-ooxx', '测试模æ¿', 'biubiubiu', '[]', '1111', '110', 1, 'YUN_PIAN', '1', '2021-04-09 23:58:42', '1', '2021-04-02 08:32:22', b'1');
  976 +INSERT INTO `sys_sms_template` VALUES (6, 3, 0, 'test-01', '测试模æ¿', '哈哈哈 {name}', '[\"name\"]', 'f哈哈哈', '4383920', 1, 'YUN_PIAN', '1', '2021-04-10 01:07:21', '1', '2021-04-10 01:22:05', b'0');
  977 +INSERT INTO `sys_sms_template` VALUES (7, 3, 0, 'test-04', '测试下', 'è€é¸¡{name},牛逼{code}', '[\"name\",\"code\"]', NULL, 'suibian', 4, 'DEBUG_DING_TALK', '1', '2021-04-13 00:29:53', '1', '2021-04-14 00:30:38', b'0');
  978 +COMMIT;
  979 +
  980 +-- ----------------------------
828 981 -- Table structure for sys_user
829 982 -- ----------------------------
830 983 DROP TABLE IF EXISTS `sys_user`;
... ... @@ -855,11 +1008,11 @@ CREATE TABLE `sys_user` (
855 1008 -- Records of sys_user
856 1009 -- ----------------------------
857 1010 BEGIN;
858   -INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 'è‹¥ä¾', '管ç†å‘˜', 103, '[1]', 'ry@163.com', '15888888888', 1, 'http://127.0.0.1:8080/api/system/file/get/add5ec1891a7d97d2cc1d60847e16294.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-01-13 17:51:06', b'0');
859   -INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 'è‹¥ä¾', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-01-05 17:03:47', b'0');
860   -INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋é“', 'ä¸è¦å“我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '', '2021-01-13 23:53:12', b'0');
  1011 +INSERT INTO `sys_user` VALUES (1, 'admin', '$2a$10$0acJOIk2D25/oC87nyclE..0lzeu9DtQ/n3geP4fkun/zIVRhHJIO', 'èŠ‹é“æºç ', '管ç†å‘˜', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://api-dashboard.yudao.iocoder.cn/api/infra/file/get/5e8609290e915c4fa8b08e67.jpg', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '1', '2021-04-05 02:16:10', b'0');
  1012 +INSERT INTO `sys_user` VALUES (2, 'ry', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 'è‹¥ä¾', '测试员', 105, '[2]', 'ry@qq.com', '15666666666', 1, '', 0, '127.0.0.1', '2021-01-05 17:03:47', 'admin', '2021-01-05 17:03:47', '', '2021-04-01 04:50:36', b'1');
  1013 +INSERT INTO `sys_user` VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋é“', 'ä¸è¦å“我', 100, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '', NULL, '', '2021-01-07 09:07:17', '1', '2021-03-14 22:35:17', b'0');
861 1014 INSERT INTO `sys_user` VALUES (103, 'yuanma', '', 'æºç ', NULL, 100, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '', NULL, '', '2021-01-13 23:50:35', '', '2021-01-13 23:50:35', b'0');
862   -INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$wTJ.1LVmhxcujss2NR2SMeBo8AaFsjkoDfDafHYsdHmitAiwmnvce', '测试å·', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '', '2021-01-21 02:14:13', b'0');
  1015 +INSERT INTO `sys_user` VALUES (104, 'test', '$2a$10$.TOFpaIiI3PzEwkGrNq0Eu6Cc3rOqJMxTb1DqeSEM8StxaGPBRKoi', '测试å·', NULL, 100, '[]', '', '15601691200', 1, '', 0, '', NULL, '', '2021-01-21 02:13:53', '1', '2021-03-14 22:36:38', b'0');
863 1016 COMMIT;
864 1017  
865 1018 -- ----------------------------
... ... @@ -914,6 +1067,41 @@ CREATE TABLE `sys_user_session` (
914 1067 -- Records of sys_user_session
915 1068 -- ----------------------------
916 1069 BEGIN;
  1070 +INSERT INTO `sys_user_session` VALUES ('04c6624c7bf14b1ba1a01cb976a9d876', 1, '2021-04-05 21:40:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 20:21:09', NULL, '2021-04-01 12:25:35', b'1');
  1071 +INSERT INTO `sys_user_session` VALUES ('0e235ce5ae7342a09b372a00bd7d1b41', 1, '2021-04-05 01:43:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 00:51:03', NULL, '2021-04-01 04:18:06', b'1');
  1072 +INSERT INTO `sys_user_session` VALUES ('0e6943f8ca9b4215a014843eb489ccc7', 1, '2021-04-05 22:53:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:43:59', NULL, '2021-04-01 17:25:41', b'1');
  1073 +INSERT INTO `sys_user_session` VALUES ('12166cd28b4f448ea468d13c471dfc6e', 1, '2021-04-09 19:48:58', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-09 19:18:58', NULL, '2021-04-02 04:33:15', b'1');
  1074 +INSERT INTO `sys_user_session` VALUES ('134d908ae33146bd9b5291471c04f604', 1, '2021-04-10 00:29:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-09 23:10:26', NULL, '2021-04-02 08:08:17', b'1');
  1075 +INSERT INTO `sys_user_session` VALUES ('1407ce21e47947b9b8d93bff1b55c7d6', 1, '2021-04-07 01:09:11', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-07 00:07:43', NULL, '2021-04-01 18:10:44', b'1');
  1076 +INSERT INTO `sys_user_session` VALUES ('1477c38290ff4cee8887ebfe593faa02', 1, '2021-04-17 23:34:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 23:04:57', NULL, '2021-04-12 21:36:29', b'1');
  1077 +INSERT INTO `sys_user_session` VALUES ('3c75ea73e13b4857a18eb57ca2eea80f', 1, '2021-04-11 20:06:52', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 19:36:52', NULL, '2021-04-11 09:10:53', b'1');
  1078 +INSERT INTO `sys_user_session` VALUES ('40d532d8900c43b791266429a7911751', 1, '2021-04-05 22:11:34', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 21:41:34', NULL, '2021-04-01 12:28:20', b'1');
  1079 +INSERT INTO `sys_user_session` VALUES ('43676e85d0e04980b2a67181f8d9933b', 1, '2021-04-11 10:41:09', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 09:56:31', NULL, '2021-04-02 17:32:07', b'1');
  1080 +INSERT INTO `sys_user_session` VALUES ('505b4e7d8b0d4b40aa23bf540da81234', 1, '2021-03-14 01:25:13', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 00:31:43', NULL, '2021-03-13 07:35:26', b'1');
  1081 +INSERT INTO `sys_user_session` VALUES ('56a92b99f7b642ccbb7508042a25cb0c', 1, '2021-04-11 21:16:33', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 20:14:54', NULL, '2021-04-11 10:08:20', b'1');
  1082 +INSERT INTO `sys_user_session` VALUES ('5a7248bf87d14e7e9f0578b05969986c', 1, '2021-03-13 10:42:50', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 09:37:36', NULL, '2021-03-12 19:53:07', b'1');
  1083 +INSERT INTO `sys_user_session` VALUES ('5c30d80eb72048daa1a24d3d4f01317b', 1, '2021-04-12 00:31:10', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 23:08:14', NULL, '2021-04-11 15:47:45', b'1');
  1084 +INSERT INTO `sys_user_session` VALUES ('5dca80a5c61541479a4dbb6e004c2e28', 1, '2021-04-14 00:57:25', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-13 23:38:30', NULL, '2021-04-12 17:33:48', b'1');
  1085 +INSERT INTO `sys_user_session` VALUES ('7324a76b029a49ee95bf54ceb4164ba9', 1, '2021-04-13 01:29:14', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-13 00:18:40', NULL, '2021-04-11 23:15:00', b'1');
  1086 +INSERT INTO `sys_user_session` VALUES ('749619894bc441bb9773902515f81e6a', 1, '2021-04-11 00:39:51', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 00:09:51', NULL, '2021-04-02 16:50:56', b'1');
  1087 +INSERT INTO `sys_user_session` VALUES ('7768ae62ad974fd989f5159649a4be82', 1, '2021-04-11 00:53:39', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-10 23:23:27', NULL, '2021-04-02 17:04:58', b'1');
  1088 +INSERT INTO `sys_user_session` VALUES ('79efcb8f64aa42af9f4b327fb383532f', 1, '2021-04-11 22:44:07', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 21:34:53', NULL, '2021-04-11 14:10:45', b'1');
  1089 +INSERT INTO `sys_user_session` VALUES ('87d5b95fdad9447189a95abf8a5152df', 1, '2021-04-17 23:01:18', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 22:31:18', NULL, '2021-04-12 21:03:27', b'1');
  1090 +INSERT INTO `sys_user_session` VALUES ('8b3eac5e4a104a4191c8070e03d553ea', 1, '2021-04-05 02:45:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-05 02:15:12', NULL, '2021-04-01 11:05:25', b'1');
  1091 +INSERT INTO `sys_user_session` VALUES ('9ae27346d8b7491aad1385f51e8aa196', 1, '2021-03-13 14:02:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-13 10:43:06', NULL, '2021-03-13 06:40:35', b'1');
  1092 +INSERT INTO `sys_user_session` VALUES ('a2fb443b31c049008975ff8ee5499db1', 1, '2021-04-11 09:42:09', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 09:12:09', NULL, '2021-04-02 17:16:00', b'1');
  1093 +INSERT INTO `sys_user_session` VALUES ('a71a74adf9d141e2849d2a411d558205', 1, '2021-04-17 18:24:44', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-17 17:54:44', NULL, '2021-04-12 17:54:50', b'1');
  1094 +INSERT INTO `sys_user_session` VALUES ('ae9ee7452ee54e4b983d658188c15c4d', 1, '2021-03-14 21:32:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 20:25:00', NULL, '2021-03-13 15:19:10', b'1');
  1095 +INSERT INTO `sys_user_session` VALUES ('b727853eccea4c8589e006ffea985146', 1, '2021-04-12 01:36:00', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-12 01:06:00', NULL, '2021-04-11 19:40:07', b'1');
  1096 +INSERT INTO `sys_user_session` VALUES ('c095616db95044c5bed66a3f84519b8b', 1, '2021-04-11 19:59:33', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 19:29:33', NULL, '2021-04-11 09:04:19', b'1');
  1097 +INSERT INTO `sys_user_session` VALUES ('d0adf48f82914212b947e5ab04d9fb65', 1, '2021-03-21 19:16:28', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 18:13:37', NULL, '2021-03-15 05:53:20', b'1');
  1098 +INSERT INTO `sys_user_session` VALUES ('dfbce0af867547f4bb01ac6f2e583337', 1, '2021-04-11 17:06:15', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 16:36:15', NULL, '2021-04-11 08:24:03', b'1');
  1099 +INSERT INTO `sys_user_session` VALUES ('e5ecf10e40a5463b8f9b5b453cb1649b', 1, '2021-04-11 17:06:22', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-11 16:36:22', NULL, '2021-04-11 08:24:03', b'1');
  1100 +INSERT INTO `sys_user_session` VALUES ('e80c2400724042a2ab73732166cde8fc', 1, '2021-03-21 21:17:12', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 20:47:12', NULL, '2021-03-15 08:18:56', b'1');
  1101 +INSERT INTO `sys_user_session` VALUES ('e8872f5192584440a548641b83c877ef', 1, '2021-03-21 18:36:01', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-03-21 17:51:48', NULL, '2021-03-15 03:54:20', b'1');
  1102 +INSERT INTO `sys_user_session` VALUES ('f1ab99b09b5a475795579ff99d60ac78', 1, '2021-03-14 23:04:31', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-14 21:12:44', NULL, '2021-03-15 03:32:38', b'1');
  1103 +INSERT INTO `sys_user_session` VALUES ('f2a4182f62ea4559b9946a523928fac4', 1, '2021-04-10 01:45:57', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36', NULL, '2021-04-10 00:55:38', NULL, '2021-04-02 14:52:48', b'1');
  1104 +INSERT INTO `sys_user_session` VALUES ('f853b50d064340a581e9a49bba9411fc', 1, '2021-03-10 01:55:41', 'admin', '127.0.0.1', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36', NULL, '2021-03-10 01:11:53', NULL, '2021-03-12 18:37:05', b'1');
917 1105 COMMIT;
918 1106  
919 1107 -- ----------------------------
... ... @@ -946,7 +1134,7 @@ CREATE TABLE `tool_codegen_column` (
946 1134 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
947 1135 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
948 1136 PRIMARY KEY (`id`) USING BTREE
949   -) ENGINE=InnoDB AUTO_INCREMENT=381 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å­—段定义';
  1137 +) ENGINE=InnoDB AUTO_INCREMENT=447 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å­—段定义';
950 1138  
951 1139 -- ----------------------------
952 1140 -- Records of tool_codegen_column
... ... @@ -1100,6 +1288,72 @@ INSERT INTO `tool_codegen_column` VALUES (377, 30, &#39;create_time&#39;, &#39;datetime&#39;, &#39;å
1100 1288 INSERT INTO `tool_codegen_column` VALUES (378, 30, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 10, 'String', 'updateBy', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
1101 1289 INSERT INTO `tool_codegen_column` VALUES (379, 30, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 11, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
1102 1290 INSERT INTO `tool_codegen_column` VALUES (380, 30, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 12, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '', '2021-03-06 06:48:28', '', '2021-03-06 06:48:28', b'0');
  1291 +INSERT INTO `tool_codegen_column` VALUES (381, 33, 'id', 'varchar(188)', '文件路径', b'0', b'1', '0', 1, 'String', 'id', '', NULL, b'0', b'0', b'1', 'LIKE', b'1', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1292 +INSERT INTO `tool_codegen_column` VALUES (382, 33, 'type', 'varchar(63)', '文件类型', b'1', b'0', '0', 2, 'String', 'type', '', NULL, b'1', b'0', b'1', 'LIKE', b'1', 'select', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1293 +INSERT INTO `tool_codegen_column` VALUES (383, 33, 'content', 'blob', '文件内容', b'0', b'0', '0', 3, 'byte[]', 'content', '', NULL, b'1', b'0', b'0', '=', b'1', 'fileUpload', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1294 +INSERT INTO `tool_codegen_column` VALUES (384, 33, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 4, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1295 +INSERT INTO `tool_codegen_column` VALUES (385, 33, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 5, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1296 +INSERT INTO `tool_codegen_column` VALUES (386, 33, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 6, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1297 +INSERT INTO `tool_codegen_column` VALUES (387, 33, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 7, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1298 +INSERT INTO `tool_codegen_column` VALUES (388, 33, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 8, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1299 +INSERT INTO `tool_codegen_column` VALUES (389, 34, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1300 +INSERT INTO `tool_codegen_column` VALUES (390, 34, 'signature', 'varchar(8)', '短信签å', b'0', b'0', '0', 2, 'String', 'signature', '', 'èŠ‹é“æºç ', b'1', b'1', b'1', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1301 +INSERT INTO `tool_codegen_column` VALUES (391, 34, 'code', 'varchar(63)', '渠é“ç¼–ç ', b'0', b'0', '0', 3, 'String', 'code', 'sys_sms_channel_code', 'YUN_PIAN', b'1', b'0', b'0', '=', b'1', 'select', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1302 +INSERT INTO `tool_codegen_column` VALUES (392, 34, 'status', 'tinyint(4)', 'å¯ç”¨çжæ€', b'0', b'0', '0', 4, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1303 +INSERT INTO `tool_codegen_column` VALUES (393, 34, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 5, 'String', 'remark', '', '好åƒï¼', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1304 +INSERT INTO `tool_codegen_column` VALUES (394, 34, 'api_key', 'varchar(63)', '短信 API 的账å·', b'0', b'0', '0', 6, 'String', 'apiKey', '', 'yudao', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1305 +INSERT INTO `tool_codegen_column` VALUES (395, 34, 'api_secret', 'varchar(63)', '短信 API 的秘钥', b'1', b'0', '0', 7, 'String', 'apiSecret', '', 'yuanma', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1306 +INSERT INTO `tool_codegen_column` VALUES (396, 34, 'callback_url', 'varchar(255)', '短信å‘é€å›žè°ƒ URL', b'1', b'0', '0', 8, 'String', 'callbackUrl', '', 'http://www.iocoder.cn', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1307 +INSERT INTO `tool_codegen_column` VALUES (397, 34, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 9, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1308 +INSERT INTO `tool_codegen_column` VALUES (398, 34, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 10, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1309 +INSERT INTO `tool_codegen_column` VALUES (399, 34, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 11, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1310 +INSERT INTO `tool_codegen_column` VALUES (400, 34, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 12, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1311 +INSERT INTO `tool_codegen_column` VALUES (401, 34, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 13, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 00:51:34', '1', '2021-04-05 20:52:09', b'0');
  1312 +INSERT INTO `tool_codegen_column` VALUES (402, 35, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1313 +INSERT INTO `tool_codegen_column` VALUES (403, 35, 'type', 'tinyint(4)', '短信签å', b'0', b'0', '0', 2, 'Integer', 'type', 'sys_sms_template_type', '1', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1314 +INSERT INTO `tool_codegen_column` VALUES (404, 35, 'status', 'tinyint(4)', 'å¼€å¯çжæ€', b'0', b'0', '0', 3, 'Integer', 'status', 'sys_common_status', '1', b'1', b'1', b'1', '=', b'1', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1315 +INSERT INTO `tool_codegen_column` VALUES (405, 35, 'code', 'varchar(63)', '模æ¿ç¼–ç ', b'0', b'0', '0', 4, 'String', 'code', '', 'test_01', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1316 +INSERT INTO `tool_codegen_column` VALUES (406, 35, 'name', 'varchar(63)', '模æ¿åç§°', b'0', b'0', '0', 5, 'String', 'name', '', 'yudao', b'1', b'1', b'0', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1317 +INSERT INTO `tool_codegen_column` VALUES (407, 35, 'content', 'varchar(255)', '模æ¿å†…容', b'0', b'0', '0', 6, 'String', 'content', '', '你好,{name}。你长的太{like}啦ï¼', b'1', b'1', b'1', 'LIKE', b'1', 'editor', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1318 +INSERT INTO `tool_codegen_column` VALUES (408, 35, 'params', 'varchar(255)', '傿•°æ•°ç»„', b'0', b'0', '0', 7, 'String', 'params', '', 'name,code', b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1319 +INSERT INTO `tool_codegen_column` VALUES (409, 35, 'remark', 'varchar(255)', '备注', b'1', b'0', '0', 8, 'String', 'remark', '', '哈哈哈', b'1', b'1', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1320 +INSERT INTO `tool_codegen_column` VALUES (410, 35, 'api_template_id', 'varchar(63)', '短信 API 的模æ¿ç¼–å·', b'0', b'0', '0', 9, 'String', 'apiTemplateId', '', '4383920', b'1', b'1', b'1', 'LIKE', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1321 +INSERT INTO `tool_codegen_column` VALUES (411, 35, 'channel_id', 'bigint(20)', '短信渠é“ç¼–å·', b'0', b'0', '0', 10, 'Long', 'channelId', '', '10', b'1', b'1', b'1', '=', b'1', 'select', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1322 +INSERT INTO `tool_codegen_column` VALUES (412, 35, 'channel_code', 'varchar(63)', '短信渠é“ç¼–ç ', b'0', b'0', '0', 11, 'String', 'channelCode', 'sys_sms_channel_code', 'ALIYUN', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1323 +INSERT INTO `tool_codegen_column` VALUES (413, 35, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 12, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1324 +INSERT INTO `tool_codegen_column` VALUES (414, 35, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 13, 'Date', 'createTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1325 +INSERT INTO `tool_codegen_column` VALUES (415, 35, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 14, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1326 +INSERT INTO `tool_codegen_column` VALUES (416, 35, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 15, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1327 +INSERT INTO `tool_codegen_column` VALUES (417, 35, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 16, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-05 21:42:22', '1', '2021-04-05 22:23:38', b'0');
  1328 +INSERT INTO `tool_codegen_column` VALUES (418, 36, 'id', 'bigint(20)', 'ç¼–å·', b'0', b'1', '1', 1, 'Long', 'id', '', '1024', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1329 +INSERT INTO `tool_codegen_column` VALUES (419, 36, 'channel_id', 'bigint(20)', '短信渠é“ç¼–å·', b'0', b'0', '0', 2, 'Long', 'channelId', '', '10', b'0', b'0', b'1', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1330 +INSERT INTO `tool_codegen_column` VALUES (420, 36, 'channel_code', 'varchar(63)', '短信渠é“ç¼–ç ', b'0', b'0', '0', 3, 'String', 'channelCode', '', 'ALIYUN', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1331 +INSERT INTO `tool_codegen_column` VALUES (421, 36, 'template_id', 'bigint(20)', '模æ¿ç¼–å·', b'0', b'0', '0', 4, 'Long', 'templateId', '', '20', b'0', b'0', b'1', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1332 +INSERT INTO `tool_codegen_column` VALUES (422, 36, 'template_code', 'varchar(63)', '模æ¿ç¼–ç ', b'0', b'0', '0', 5, 'String', 'templateCode', '', 'test-01', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1333 +INSERT INTO `tool_codegen_column` VALUES (423, 36, 'template_type', 'tinyint(4)', '短信类型', b'0', b'0', '0', 6, 'Integer', 'templateType', 'sys_sms_template_type', '1', b'0', b'0', b'0', '=', b'1', 'select', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1334 +INSERT INTO `tool_codegen_column` VALUES (424, 36, 'template_content', 'varchar(255)', '短信内容', b'0', b'0', '0', 7, 'String', 'templateContent', '', '你好,你的验è¯ç æ˜¯ 1024', b'0', b'0', b'0', '=', b'1', 'editor', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1335 +INSERT INTO `tool_codegen_column` VALUES (425, 36, 'template_params', 'varchar(255)', 'çŸ­ä¿¡å‚æ•°', b'0', b'0', '0', 8, 'String', 'templateParams', '', 'name,code', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1336 +INSERT INTO `tool_codegen_column` VALUES (426, 36, 'api_template_id', 'varchar(63)', '短信 API 的模æ¿ç¼–å·', b'0', b'0', '0', 9, 'String', 'apiTemplateId', '', 'SMS_207945135', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1337 +INSERT INTO `tool_codegen_column` VALUES (427, 36, 'mobile', 'varchar(11)', '手机å·', b'0', b'0', '0', 10, 'String', 'mobile', '', '15601691300', b'0', b'0', b'1', 'LIKE', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1338 +INSERT INTO `tool_codegen_column` VALUES (428, 36, 'user_id', 'bigint(20)', '用户编å·', b'1', b'0', '0', 11, 'Long', 'userId', '', '10', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1339 +INSERT INTO `tool_codegen_column` VALUES (429, 36, 'user_type', 'tinyint(4)', '用户类型', b'1', b'0', '0', 12, 'Integer', 'userType', 'user_type', '1', b'0', b'0', b'0', '=', b'1', 'select', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1340 +INSERT INTO `tool_codegen_column` VALUES (430, 36, 'send_status', 'tinyint(4)', 'å‘é€çжæ€', b'0', b'0', '0', 13, 'Integer', 'sendStatus', 'sys_sms_send_status', '1', b'0', b'0', b'1', '=', b'1', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1341 +INSERT INTO `tool_codegen_column` VALUES (431, 36, 'send_time', 'datetime', 'å‘逿—¶é—´', b'1', b'0', '0', 14, 'Date', 'sendTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1342 +INSERT INTO `tool_codegen_column` VALUES (432, 36, 'send_code', 'int(11)', 'å‘é€ç»“果的编ç ', b'1', b'0', '0', 15, 'Integer', 'sendCode', '', '0', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1343 +INSERT INTO `tool_codegen_column` VALUES (433, 36, 'send_msg', 'varchar(255)', 'å‘é€ç»“果的æç¤º', b'1', b'0', '0', 16, 'String', 'sendMsg', '', 'æˆåŠŸ', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1344 +INSERT INTO `tool_codegen_column` VALUES (434, 36, 'api_send_code', 'varchar(63)', '短信 API å‘é€ç»“果的编ç ', b'1', b'0', '0', 17, 'String', 'apiSendCode', '', 'SUCCESS', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1345 +INSERT INTO `tool_codegen_column` VALUES (435, 36, 'api_send_msg', 'varchar(255)', '短信 API å‘é€å¤±è´¥çš„æç¤º', b'1', b'0', '0', 18, 'String', 'apiSendMsg', '', 'æˆåŠŸ', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1346 +INSERT INTO `tool_codegen_column` VALUES (436, 36, 'api_request_id', 'varchar(255)', '短信 API å‘é€è¿”回的唯一请求 ID', b'1', b'0', '0', 19, 'String', 'apiRequestId', '', '3837C6D3-B96F-428C-BBB2-86135D4B5B99', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1347 +INSERT INTO `tool_codegen_column` VALUES (437, 36, 'api_serial_no', 'varchar(255)', '短信 API å‘é€è¿”回的åºå·', b'1', b'0', '0', 20, 'String', 'apiSerialNo', '', '62923244790', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1348 +INSERT INTO `tool_codegen_column` VALUES (438, 36, 'receive_status', 'tinyint(4)', '接收状æ€', b'0', b'0', '0', 21, 'Integer', 'receiveStatus', 'sys_sms_receive_status', '0', b'0', b'0', b'1', '=', b'1', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1349 +INSERT INTO `tool_codegen_column` VALUES (439, 36, 'receive_time', 'datetime', '接收时间', b'1', b'0', '0', 22, 'Date', 'receiveTime', '', NULL, b'0', b'0', b'1', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1350 +INSERT INTO `tool_codegen_column` VALUES (440, 36, 'api_receive_code', 'varchar(63)', 'API 接收结果的编ç ', b'1', b'0', '0', 23, 'String', 'apiReceiveCode', '', 'DELIVRD', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1351 +INSERT INTO `tool_codegen_column` VALUES (441, 36, 'api_receive_msg', 'varchar(255)', 'API 接收结果的说明', b'1', b'0', '0', 24, 'String', 'apiReceiveMsg', '', 'DELIVRD', b'0', b'0', b'0', '=', b'1', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1352 +INSERT INTO `tool_codegen_column` VALUES (442, 36, 'creator', 'varchar(64)', '创建者', b'1', b'0', '0', 25, 'String', 'creator', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1353 +INSERT INTO `tool_codegen_column` VALUES (443, 36, 'create_time', 'datetime', '创建时间', b'0', b'0', '0', 26, 'Date', 'createTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'1', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1354 +INSERT INTO `tool_codegen_column` VALUES (444, 36, 'updater', 'varchar(64)', '更新者', b'1', b'0', '0', 27, 'String', 'updater', '', NULL, b'0', b'0', b'0', '=', b'0', 'input', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1355 +INSERT INTO `tool_codegen_column` VALUES (445, 36, 'update_time', 'datetime', 'æ›´æ–°æ—¶é—´', b'0', b'0', '0', 28, 'Date', 'updateTime', '', NULL, b'0', b'0', b'0', 'BETWEEN', b'0', 'datetime', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
  1356 +INSERT INTO `tool_codegen_column` VALUES (446, 36, 'deleted', 'bit(1)', '是å¦åˆ é™¤', b'0', b'0', '0', 29, 'Boolean', 'deleted', '', NULL, b'0', b'0', b'0', '=', b'0', 'radio', '1', '2021-04-11 09:13:48', '1', '2021-04-11 20:33:54', b'0');
1103 1357 COMMIT;
1104 1358  
1105 1359 -- ----------------------------
... ... @@ -1125,7 +1379,7 @@ CREATE TABLE `tool_codegen_table` (
1125 1379 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'æ›´æ–°æ—¶é—´',
1126 1380 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是å¦åˆ é™¤',
1127 1381 PRIMARY KEY (`id`) USING BTREE
1128   -) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å®šä¹‰';
  1382 +) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COMMENT='代ç ç”Ÿæˆè¡¨å®šä¹‰';
1129 1383  
1130 1384 -- ----------------------------
1131 1385 -- Records of tool_codegen_table
... ... @@ -1142,6 +1396,10 @@ INSERT INTO `tool_codegen_table` VALUES (27, 1, &#39;inf_api_error_log&#39;, &#39;API 错误
1142 1396 INSERT INTO `tool_codegen_table` VALUES (28, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dictType', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:45:55', '', '2021-03-06 03:51:02', b'1');
1143 1397 INSERT INTO `tool_codegen_table` VALUES (29, 1, 'sys_dict_type', '字典类型表', NULL, 'system', 'dict', 'SysDictType', '字典类型', '芋艿', 1, NULL, '', '2021-03-06 03:52:57', '', '2021-03-06 04:03:52', b'0');
1144 1398 INSERT INTO `tool_codegen_table` VALUES (30, 1, 'sys_dict_data', '字典数æ®è¡¨', NULL, 'system', 'type', 'SysDictData', '字典数æ®', 'èŠ‹é“æºç ', 1, NULL, '', '2021-03-06 06:48:28', '', '2021-03-06 06:50:47', b'0');
  1399 +INSERT INTO `tool_codegen_table` VALUES (33, 1, 'inf_file', '文件表', NULL, 'infra', 'file', 'InfFile', '文件', '芋艿', 1, 2, '1', '2021-03-13 09:43:20', '1', '2021-03-13 11:27:12', b'0');
  1400 +INSERT INTO `tool_codegen_table` VALUES (34, 1, 'sys_sms_channel', '短信渠é“', NULL, 'system', 'sms', 'SysSmsChannel', '短信渠é“', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-03 13:39:06', '1', '2021-04-05 20:52:09', b'0');
  1401 +INSERT INTO `tool_codegen_table` VALUES (35, 1, 'sys_sms_template', '短信模æ¿', NULL, 'system', 'sms', 'SysSmsTemplate', '短信模æ¿', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-03 13:58:55', '1', '2021-04-05 22:23:38', b'0');
  1402 +INSERT INTO `tool_codegen_table` VALUES (36, 1, 'sys_sms_log', '短信日志', NULL, 'system', 'sms', 'SysSmsLog', '短信日志', 'èŠ‹é“æºç ', 1, 1093, '1', '2021-04-11 01:12:57', '1', '2021-04-11 20:33:54', b'0');
1145 1403 COMMIT;
1146 1404  
1147 1405 -- ----------------------------
... ...
src/main/java/cn/iocoder/dashboard/common/core/KeyValue.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.core;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Data;
  5 +import lombok.NoArgsConstructor;
  6 +
  7 +/**
  8 + * Key Value 的键值对
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +public class KeyValue<K, V> {
  16 +
  17 + private K key;
  18 + private V value;
  19 +
  20 +}
... ...
src/main/java/cn/iocoder/dashboard/common/enums/DefaultBitFieldEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.common.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 通用状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum DefaultBitFieldEnum {
  14 +
  15 + NO(0, "否"),
  16 + YES(1, "是");
  17 +
  18 + /**
  19 + * 状态值
  20 + */
  21 + private final Integer val;
  22 + /**
  23 + * 状态名
  24 + */
  25 + private final String name;
  26 +
  27 +}
... ...
src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java
1 1 package cn.iocoder.dashboard.common.exception;
2 2  
  3 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
3 4 import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange;
4 5 import lombok.Data;
5 6  
6 7 /**
7 8 * 错误码对象
8 9 *
9   - * 全局错误码,占用 [0, 999],参见 {@link GlobalException}
  10 + * 全局错误码,占用 [0, 999], 参见 {@link GlobalErrorCodeConstants}
10 11 * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange}
11 12 *
12 13 * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备
... ... @@ -21,11 +22,11 @@ public class ErrorCode {
21 22 /**
22 23 * 错误提示
23 24 */
24   - private final String message;
  25 + private final String msg;
25 26  
26 27 public ErrorCode(Integer code, String message) {
27 28 this.code = code;
28   - this.message = message;
  29 + this.msg = message;
29 30 }
30 31  
31 32 }
... ...
src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java deleted
1   -package cn.iocoder.dashboard.common.exception;
2   -
3   -import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -
7   -/**
8   - * 全局异常 Exception
9   - */
10   -@Data
11   -@EqualsAndHashCode(callSuper = true)
12   -public class GlobalException extends RuntimeException {
13   -
14   - /**
15   - * 全局错误码
16   - *
17   - * @see GlobalErrorCodeConstants
18   - */
19   - private Integer code;
20   - /**
21   - * 错误提示
22   - */
23   - private String message;
24   -
25   - /**
26   - * 空构造方法,避免反序列化问题
27   - */
28   - public GlobalException() {
29   - }
30   -
31   - public GlobalException(ErrorCode errorCode) {
32   - this.code = errorCode.getCode();
33   - this.message = errorCode.getMessage();
34   - }
35   -
36   - public GlobalException(Integer code, String message) {
37   - this.code = code;
38   - this.message = message;
39   - }
40   -
41   -}
src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java
... ... @@ -30,7 +30,7 @@ public final class ServiceException extends RuntimeException {
30 30  
31 31 public ServiceException(ErrorCode errorCode) {
32 32 this.code = errorCode.getCode();
33   - this.message = errorCode.getMessage();
  33 + this.message = errorCode.getMsg();
34 34 }
35 35  
36 36 public ServiceException(Integer code, String message) {
... ...
src/main/java/cn/iocoder/dashboard/common/exception/enums/GlobalErrorCodeConstants.java
... ... @@ -32,6 +32,7 @@ public interface GlobalErrorCodeConstants {
32 32  
33 33 // ========== 自定义错误段 ==========
34 34 ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
  35 + ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
35 36  
36 37 ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
37 38  
... ...
src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java
... ... @@ -47,12 +47,12 @@ public class ServiceExceptionUtil {
47 47 // ========== 和 ServiceException 的集成 ==========
48 48  
49 49 public static ServiceException exception(ErrorCode errorCode) {
50   - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage());
  50 + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg());
51 51 return exception0(errorCode.getCode(), messagePattern);
52 52 }
53 53  
54 54 public static ServiceException exception(ErrorCode errorCode, Object... params) {
55   - String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage());
  55 + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMsg());
56 56 return exception0(errorCode.getCode(), messagePattern, params);
57 57 }
58 58  
... ...
src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java
1 1 package cn.iocoder.dashboard.common.pojo;
2 2  
3 3 import cn.iocoder.dashboard.common.exception.ErrorCode;
4   -import cn.iocoder.dashboard.common.exception.GlobalException;
5 4 import cn.iocoder.dashboard.common.exception.ServiceException;
6 5 import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
7 6 import com.fasterxml.jackson.annotation.JsonIgnore;
... ... @@ -9,6 +8,7 @@ import lombok.Data;
9 8 import org.springframework.util.Assert;
10 9  
11 10 import java.io.Serializable;
  11 +import java.util.Objects;
12 12  
13 13 /**
14 14 * 通用返回
... ... @@ -16,7 +16,7 @@ import java.io.Serializable;
16 16 * @param <T> 数据泛型
17 17 */
18 18 @Data
19   -public final class CommonResult<T> implements Serializable {
  19 +public class CommonResult<T> implements Serializable {
20 20  
21 21 /**
22 22 * 错误码
... ... @@ -31,7 +31,7 @@ public final class CommonResult&lt;T&gt; implements Serializable {
31 31 /**
32 32 * 错误提示,用户可阅读
33 33 *
34   - * @see ErrorCode#getMessage() ()
  34 + * @see ErrorCode#getMsg() ()
35 35 */
36 36 private String msg;
37 37  
... ... @@ -57,7 +57,7 @@ public final class CommonResult&lt;T&gt; implements Serializable {
57 57 }
58 58  
59 59 public static <T> CommonResult<T> error(ErrorCode errorCode) {
60   - return error(errorCode.getCode(), errorCode.getMessage());
  60 + return error(errorCode.getCode(), errorCode.getMsg());
61 61 }
62 62  
63 63 public static <T> CommonResult<T> success(T data) {
... ... @@ -68,9 +68,13 @@ public final class CommonResult&lt;T&gt; implements Serializable {
68 68 return result;
69 69 }
70 70  
  71 + public static boolean isSuccess(Integer code) {
  72 + return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
  73 + }
  74 +
71 75 @JsonIgnore // 避免 jackson 序列化
72 76 public boolean isSuccess() {
73   - return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code);
  77 + return isSuccess(code);
74 78 }
75 79  
76 80 @JsonIgnore // 避免 jackson 序列化
... ... @@ -81,16 +85,12 @@ public final class CommonResult&lt;T&gt; implements Serializable {
81 85 // ========= 和 Exception 异常体系集成 =========
82 86  
83 87 /**
84   - * 判断是否有异常。如果有,则抛出 {@link GlobalException} 或 {@link ServiceException} 异常
  88 + * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
85 89 */
86   - public void checkError() throws GlobalException, ServiceException {
  90 + public void checkError() throws ServiceException {
87 91 if (isSuccess()) {
88 92 return;
89 93 }
90   - // 全局异常
91   - if (GlobalErrorCodeConstants.isMatch(code)) {
92   - throw new GlobalException(code, msg);
93   - }
94 94 // 业务异常
95 95 throw new ServiceException(code, msg);
96 96 }
... ... @@ -99,8 +99,4 @@ public final class CommonResult&lt;T&gt; implements Serializable {
99 99 return error(serviceException.getCode(), serviceException.getMessage());
100 100 }
101 101  
102   - public static <T> CommonResult<T> error(GlobalException globalException) {
103   - return error(globalException.getCode(), globalException.getMessage());
104   - }
105   -
106 102 }
... ...
src/main/java/cn/iocoder/dashboard/framework/datasource/config/DataSourceConfiguration.java
1 1 package cn.iocoder.dashboard.framework.datasource.config;
2 2  
  3 +import cn.iocoder.dashboard.framework.datasource.core.filter.DruidAdRemoveFilter;
  4 +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
  5 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  6 +import org.springframework.boot.web.servlet.FilterRegistrationBean;
  7 +import org.springframework.context.annotation.Bean;
3 8 import org.springframework.context.annotation.Configuration;
4 9 import org.springframework.transaction.annotation.EnableTransactionManagement;
5 10  
6 11 /**
7   - * 数据库匹配类
  12 + * 数据库配置类
  13 + *
  14 + * @author 芋道源码
8 15 */
9 16 @Configuration
10 17 @EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理
11 18 public class DataSourceConfiguration {
  19 +
  20 + /**
  21 + * 创建 DruidAdRemoveFilter 过滤器,过滤 common.js 的广告
  22 + */
  23 + @Bean
  24 + @ConditionalOnProperty(name = "spring.datasource.druid.web-stat-filter.enabled", havingValue = "true")
  25 + public FilterRegistrationBean<DruidAdRemoveFilter> druidAdRemoveFilterFilter(DruidStatProperties properties) {
  26 + // 获取 druid web 监控页面的参数
  27 + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
  28 + // 提取 common.js 的配置路径
  29 + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
  30 + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
  31 + // 创建 DruidAdRemoveFilter Bean
  32 + FilterRegistrationBean<DruidAdRemoveFilter> registrationBean = new FilterRegistrationBean<>();
  33 + registrationBean.setFilter(new DruidAdRemoveFilter());
  34 + registrationBean.addUrlPatterns(commonJsPattern);
  35 + return registrationBean;
  36 + }
  37 +
12 38 }
... ...
src/main/java/cn/iocoder/dashboard/framework/datasource/core/enums/DataSourceEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.datasource.core.enums;
  2 +
  3 +/**
  4 + * 对应于多数据源中不同数据源配置
  5 + *
  6 + * 通过在方法上,使用 {@link com.baomidou.dynamic.datasource.annotation.DS} 注解,设置使用的数据源。
  7 + * 注意,默认是 {@link #MASTER} 数据源
  8 + *
  9 + * 对应官方文档为 http://dynamic-datasource.com/guide/customize/Annotation.html
  10 + */
  11 +public interface DataSourceEnum {
  12 +
  13 + /**
  14 + * 主库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Master} 注解
  15 + */
  16 + String MASTER = "master";
  17 + /**
  18 + * 从库,推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Slave} 注解
  19 + */
  20 + String SLAVE = "slave";
  21 +
  22 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/datasource/core/filter/DruidAdRemoveFilter.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.datasource.core.filter;
  2 +
  3 +import com.alibaba.druid.util.Utils;
  4 +import org.springframework.web.filter.OncePerRequestFilter;
  5 +
  6 +import javax.servlet.FilterChain;
  7 +import javax.servlet.ServletException;
  8 +import javax.servlet.http.HttpServletRequest;
  9 +import javax.servlet.http.HttpServletResponse;
  10 +import java.io.IOException;
  11 +
  12 +/**
  13 + * Druid 底部广告过滤器
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class DruidAdRemoveFilter extends OncePerRequestFilter {
  18 +
  19 + /**
  20 + * common.js 的路径
  21 + */
  22 + private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js";
  23 +
  24 + @Override
  25 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  26 + throws ServletException, IOException {
  27 + chain.doFilter(request, response);
  28 + // 重置缓冲区,响应头不会被重置
  29 + response.resetBuffer();
  30 + // 获取 common.js
  31 + String text = Utils.readFromResource(COMMON_JS_ILE_PATH);
  32 + // 正则替换 banner, 除去底部的广告信息
  33 + text = text.replaceAll("<a.*?banner\"></a><br/>", "");
  34 + text = text.replaceAll("powered.*?shrek.wang</a>", "");
  35 + response.getWriter().write(text);
  36 + }
  37 +
  38 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/DictConvert.java
... ... @@ -13,6 +13,11 @@ import com.alibaba.excel.metadata.GlobalConfiguration;
13 13 import com.alibaba.excel.metadata.property.ExcelContentProperty;
14 14 import lombok.extern.slf4j.Slf4j;
15 15  
  16 +/**
  17 + * Excel {@link SysDictDataDO} 数据字典转换器
  18 + *
  19 + * @author 芋道源码
  20 + */
16 21 @Slf4j
17 22 public class DictConvert implements Converter<Object> {
18 23  
... ...
src/main/java/cn/iocoder/dashboard/framework/excel/core/convert/JsonConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.excel.core.convert;
  2 +
  3 +import cn.iocoder.dashboard.util.json.JsonUtils;
  4 +import com.alibaba.excel.converters.Converter;
  5 +import com.alibaba.excel.enums.CellDataTypeEnum;
  6 +import com.alibaba.excel.metadata.CellData;
  7 +import com.alibaba.excel.metadata.GlobalConfiguration;
  8 +import com.alibaba.excel.metadata.property.ExcelContentProperty;
  9 +
  10 +/**
  11 + * Excel Json 转换器
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public class JsonConvert implements Converter<Object> {
  16 +
  17 + @Override
  18 + public Class<?> supportJavaTypeKey() {
  19 + throw new UnsupportedOperationException("暂不支持,也不需要");
  20 + }
  21 +
  22 + @Override
  23 + public CellDataTypeEnum supportExcelTypeKey() {
  24 + throw new UnsupportedOperationException("暂不支持,也不需要");
  25 + }
  26 +
  27 + @Override
  28 + public Object convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
  29 + throw new UnsupportedOperationException("暂不支持,也不需要");
  30 + }
  31 +
  32 + @Override
  33 + public CellData<String> convertToExcelData(Object value, ExcelContentProperty contentProperty,
  34 + GlobalConfiguration globalConfiguration) {
  35 + // 生成 Excel 小表格
  36 + return new CellData<>(JsonUtils.toJsonString(value));
  37 + }
  38 +
  39 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/file/config/FileProperties.java
1 1 package cn.iocoder.dashboard.framework.file.config;
2 2  
3   -import cn.iocoder.dashboard.modules.system.controller.common.SysFileController;
  3 +import cn.iocoder.dashboard.modules.infra.controller.file.InfFileController;
4 4 import lombok.Data;
5 5 import org.springframework.boot.context.properties.ConfigurationProperties;
6 6 import org.springframework.validation.annotation.Validated;
... ... @@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull;
13 13 public class FileProperties {
14 14  
15 15 /**
16   - * 对应 {@link SysFileController#}
  16 + * 对应 {@link InfFileController#}
17 17 */
18 18 @NotNull(message = "基础文件路径不能为空")
19 19 private String basePath;
... ...
src/main/java/cn/iocoder/dashboard/framework/jackson/config/JacksonConfig.java
1 1 package cn.iocoder.dashboard.framework.jackson.config;
2 2  
  3 +import cn.iocoder.dashboard.framework.jackson.deser.LocalDateTimeDeserializer;
  4 +import cn.iocoder.dashboard.framework.jackson.ser.LocalDateTimeSerializer;
3 5 import cn.iocoder.dashboard.util.json.JsonUtils;
4 6 import com.fasterxml.jackson.databind.ObjectMapper;
  7 +import com.fasterxml.jackson.databind.module.SimpleModule;
5 8 import org.springframework.context.annotation.Bean;
6 9 import org.springframework.context.annotation.Configuration;
7 10  
  11 +import java.time.LocalDateTime;
  12 +
8 13 @Configuration
9 14 public class JacksonConfig {
10 15  
11 16 @Bean
12 17 @SuppressWarnings("InstantiationOfUtilityClass")
13 18 public JsonUtils jsonUtils(ObjectMapper objectMapper) {
  19 + SimpleModule simpleModule = new SimpleModule();
  20 + /*
  21 + * 1. 新增Long类型序列化规则,数值超过2^53-1,在JS会出现精度丢失问题,因此Long自动序列化为字符串类型
  22 + * 2. 新增LocalDateTime序列化、反序列化规则
  23 + */
  24 + simpleModule
  25 +// .addSerializer(Long.class, ToStringSerializer.instance)
  26 +// .addSerializer(Long.TYPE, ToStringSerializer.instance)
  27 + .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)
  28 + .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
  29 +
  30 + objectMapper.registerModules(simpleModule);
  31 +
14 32 JsonUtils.init(objectMapper);
15 33 return new JsonUtils();
16 34 }
17   -
18 35 }
... ...
src/main/java/cn/iocoder/dashboard/framework/jackson/deser/LocalDateTimeDeserializer.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.jackson.deser;
  2 +
  3 +import com.fasterxml.jackson.core.JsonParser;
  4 +import com.fasterxml.jackson.core.JsonProcessingException;
  5 +import com.fasterxml.jackson.databind.DeserializationContext;
  6 +import com.fasterxml.jackson.databind.JsonDeserializer;
  7 +
  8 +import java.io.IOException;
  9 +import java.time.Instant;
  10 +import java.time.LocalDateTime;
  11 +import java.time.ZoneId;
  12 +
  13 +/**
  14 + * LocalDateTime反序列化规则
  15 + * <p>
  16 + * 会将毫秒级时间戳反序列化为LocalDateTime
  17 + */
  18 +public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
  19 +
  20 + public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer();
  21 +
  22 + @Override
  23 + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
  24 + return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
  25 + }
  26 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/jackson/ser/LocalDateTimeSerializer.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.jackson.ser;
  2 +
  3 +import com.fasterxml.jackson.core.JsonGenerator;
  4 +import com.fasterxml.jackson.databind.JsonSerializer;
  5 +import com.fasterxml.jackson.databind.SerializerProvider;
  6 +
  7 +import java.io.IOException;
  8 +import java.time.LocalDateTime;
  9 +import java.time.ZoneId;
  10 +
  11 +/**
  12 + * LocalDateTime序列化规则
  13 + * <p>
  14 + * 会将LocalDateTime序列化为毫秒级时间戳
  15 + */
  16 +public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
  17 +
  18 + public static final LocalDateTimeSerializer INSTANCE = new LocalDateTimeSerializer();
  19 +
  20 + @Override
  21 + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
  22 + gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
  23 + }
  24 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/filter/ApiAccessLogFilter.java
... ... @@ -81,7 +81,7 @@ public class ApiAccessLogFilter extends OncePerRequestFilter {
81 81 Map<String, String> queryString, String requestBody, Exception ex) {
82 82 // 处理用户信息
83 83 accessLog.setUserId(WebFrameworkUtils.getLoginUserId(request));
84   - accessLog.setUserType(WebFrameworkUtils.getUesrType(request));
  84 + accessLog.setUserType(WebFrameworkUtils.getUserType(request));
85 85 // 设置访问结果
86 86 CommonResult<?> result = WebFrameworkUtils.getCommonResult(request);
87 87 if (result != null) {
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/service/ApiAccessLogFrameworkService.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.logger.apilog.core.service;
3 3 import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiAccessLogCreateDTO;
4 4  
5 5 import javax.validation.Valid;
  6 +import java.util.concurrent.Future;
6 7  
7 8 /**
8 9 * API 访问日志 Framework Service 接口
... ... @@ -15,7 +16,8 @@ public interface ApiAccessLogFrameworkService {
15 16 * 创建 API 访问日志
16 17 *
17 18 * @param createDTO 创建信息
  19 + * @return 是否创建成功
18 20 */
19   - void createApiAccessLogAsync(@Valid ApiAccessLogCreateDTO createDTO);
  21 + Future<Boolean> createApiAccessLogAsync(@Valid ApiAccessLogCreateDTO createDTO);
20 22  
21 23 }
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/apilog/core/service/ApiErrorLogFrameworkService.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.dashboard.framework.logger.apilog.core.service;
3 3 import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO;
4 4  
5 5 import javax.validation.Valid;
  6 +import java.util.concurrent.Future;
6 7  
7 8 /**
8 9 * API 错误日志 Framework Service 接口
... ... @@ -15,7 +16,8 @@ public interface ApiErrorLogFrameworkService {
15 16 * 创建 API 错误日志
16 17 *
17 18 * @param createDTO 创建信息
  19 + * @return 是否创建成功
18 20 */
19   - void createApiErrorLogAsync(@Valid ApiErrorLogCreateDTO createDTO);
  21 + Future<Boolean> createApiErrorLogAsync(@Valid ApiErrorLogCreateDTO createDTO);
20 22  
21 23 }
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/service/OperateLogFrameworkService.java
... ... @@ -2,13 +2,16 @@ package cn.iocoder.dashboard.framework.logger.operatelog.core.service;
2 2  
3 3 import cn.iocoder.dashboard.modules.system.controller.logger.vo.operatelog.SysOperateLogCreateReqVO;
4 4  
  5 +import java.util.concurrent.Future;
  6 +
5 7 public interface OperateLogFrameworkService {
6 8  
7 9 /**
8   - * 要不记录操作日志
  10 + * 异步记录操作日志
9 11 *
10 12 * @param reqVO 操作日志请求
  13 + * @return true: 记录成功,false: 记录失败
11 14 */
12   - void createOperateLogAsync(SysOperateLogCreateReqVO reqVO);
  15 + Future<Boolean> createOperateLogAsync(SysOperateLogCreateReqVO reqVO);
13 16  
14 17 }
... ...
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/handler/DefaultDBFieldHandler.java
... ... @@ -57,7 +57,7 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
57 57 }
58 58 // 当前登录用户不为空,更新人为空,则当前登录用户为更新人
59 59 if (Objects.nonNull(loginUser) && Objects.isNull(modifier)) {
60   - setFieldValByName("updater", loginUser.getId(), metaObject);
  60 + setFieldValByName("updater", loginUser.getId().toString(), metaObject);
61 61 }
62 62 }
63 63 }
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/config/RedisConfig.java
1 1 package cn.iocoder.dashboard.framework.redis.config;
2 2  
  3 +import cn.hutool.system.SystemUtil;
3 4 import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener;
  5 +import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
4 6 import lombok.extern.slf4j.Slf4j;
5 7 import org.springframework.context.annotation.Bean;
6 8 import org.springframework.context.annotation.Configuration;
7 9 import org.springframework.data.redis.connection.RedisConnectionFactory;
  10 +import org.springframework.data.redis.connection.stream.Consumer;
  11 +import org.springframework.data.redis.connection.stream.ObjectRecord;
  12 +import org.springframework.data.redis.connection.stream.ReadOffset;
  13 +import org.springframework.data.redis.connection.stream.StreamOffset;
8 14 import org.springframework.data.redis.core.RedisTemplate;
9 15 import org.springframework.data.redis.listener.ChannelTopic;
10 16 import org.springframework.data.redis.listener.RedisMessageListenerContainer;
11 17 import org.springframework.data.redis.serializer.RedisSerializer;
  18 +import org.springframework.data.redis.stream.StreamMessageListenerContainer;
12 19  
13 20 import java.util.List;
14 21  
... ... @@ -19,6 +26,9 @@ import java.util.List;
19 26 @Slf4j
20 27 public class RedisConfig {
21 28  
  29 + /**
  30 + * 创建 RedisTemplate Bean,使用 JSON 序列化方式
  31 + */
22 32 @Bean
23 33 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
24 34 // 创建 RedisTemplate 对象
... ... @@ -27,14 +37,19 @@ public class RedisConfig {
27 37 template.setConnectionFactory(factory);
28 38 // 使用 String 序列化方式,序列化 KEY 。
29 39 template.setKeySerializer(RedisSerializer.string());
  40 + template.setHashKeySerializer(RedisSerializer.string());
30 41 // 使用 JSON 序列化方式(库是 Jackson ),序列化 VALUE 。
31 42 template.setValueSerializer(RedisSerializer.json());
  43 + template.setHashValueSerializer(RedisSerializer.json());
32 44 return template;
33 45 }
34 46  
  47 + /**
  48 + * 创建 Redis Pub/Sub 广播消费的容器
  49 + */
35 50 @Bean
36   - public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory factory,
37   - List<AbstractChannelMessageListener<?>> listeners) {
  51 + public RedisMessageListenerContainer redisMessageListenerContainer(
  52 + RedisConnectionFactory factory, List<AbstractChannelMessageListener<?>> listeners) {
38 53 // 创建 RedisMessageListenerContainer 对象
39 54 RedisMessageListenerContainer container = new RedisMessageListenerContainer();
40 55 // 设置 RedisConnection 工厂。
... ... @@ -48,4 +63,57 @@ public class RedisConfig {
48 63 return container;
49 64 }
50 65  
  66 + /**
  67 + * 创建 Redis Stream 集群消费的容器
  68 + *
  69 + * Redis Stream 的 xreadgroup 命令:https://www.geek-book.com/src/docs/redis/redis/redis.io/commands/xreadgroup.html
  70 + */
  71 + @Bean(initMethod = "start", destroyMethod = "stop")
  72 + public StreamMessageListenerContainer<String, ObjectRecord<String, String>> redisStreamMessageListenerContainer(
  73 + RedisTemplate<String, Object> redisTemplate, List<AbstractStreamMessageListener<?>> listeners) {
  74 + // 第一步,创建 StreamMessageListenerContainer 容器
  75 + // 创建 options 配置
  76 + StreamMessageListenerContainer.StreamMessageListenerContainerOptions<String, ObjectRecord<String, String>> containerOptions =
  77 + StreamMessageListenerContainer.StreamMessageListenerContainerOptions.builder()
  78 + .batchSize(10) // 一次性最多拉取多少条消息
  79 + .targetType(String.class) // 目标类型。统一使用 String,通过自己封装的 AbstractStreamMessageListener 去反序列化
  80 + .build();
  81 + // 创建 container 对象
  82 + StreamMessageListenerContainer<String, ObjectRecord<String, String>> container = StreamMessageListenerContainer.create(
  83 + redisTemplate.getRequiredConnectionFactory(), containerOptions);
  84 +
  85 + // 第二步,注册监听器,消费对应的 Stream 主题
  86 + String consumerName = buildConsumerName();
  87 +// String consumerName = "110";
  88 + listeners.forEach(listener -> {
  89 + // 创建 listener 对应的消费者分组
  90 + try {
  91 + redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup());
  92 + } catch (Exception ignore) {}
  93 + // 设置 listener 对应的 redisTemplate
  94 + listener.setRedisTemplate(redisTemplate);
  95 + // 创建 Consumer 对象
  96 + Consumer consumer = Consumer.from(listener.getGroup(), consumerName);
  97 + // 设置 Consumer 消费进度,以最小消费进度为准
  98 + StreamOffset<String> streamOffset = StreamOffset.create(listener.getStreamKey(), ReadOffset.lastConsumed());
  99 + // 设置 Consumer 监听
  100 + StreamMessageListenerContainer.StreamReadRequestBuilder<String> builder = StreamMessageListenerContainer.StreamReadRequest
  101 + .builder(streamOffset).consumer(consumer)
  102 + .autoAcknowledge(false) // 不自动 ack
  103 + .cancelOnError(throwable -> false); // 默认配置,发生异常就取消消费,显然不符合预期;因此,我们设置为 false
  104 + container.register(builder.build(), listener);
  105 + });
  106 + return container;
  107 + }
  108 +
  109 + /**
  110 + * 构建消费者名字,使用本地 IP + 进程编号的方式。
  111 + * 参考自 RocketMQ clientId 的实现
  112 + *
  113 + * @return 消费者名字
  114 + */
  115 + private static String buildConsumerName() {
  116 + return String.format("%s@%d", SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID());
  117 + }
  118 +
51 119 }
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/core/pubsub/AbstractChannelMessageListener.java
1 1 package cn.iocoder.dashboard.framework.redis.core.pubsub;
2 2  
3   -import cn.hutool.core.util.ArrayUtil;
  3 +import cn.hutool.core.util.TypeUtil;
4 4 import cn.iocoder.dashboard.util.json.JsonUtils;
5 5 import lombok.SneakyThrows;
6 6 import org.springframework.data.redis.connection.Message;
7 7 import org.springframework.data.redis.connection.MessageListener;
8   -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
9 8  
10 9 import java.lang.reflect.Type;
11 10  
... ... @@ -62,21 +61,11 @@ public abstract class AbstractChannelMessageListener&lt;T extends ChannelMessage&gt; i
62 61 */
63 62 @SuppressWarnings("unchecked")
64 63 private Class<T> getMessageClass() {
65   - Class<?> targetClass = getClass();
66   - while (targetClass.getSuperclass() != null) {
67   - // 如果不是 AbstractMessageListener 父类,继续向上查找
68   - if (targetClass.getSuperclass() != AbstractChannelMessageListener.class) {
69   - targetClass = targetClass.getSuperclass();
70   - continue;
71   - }
72   - // 如果是 AbstractMessageListener 父类,则解析泛型
73   - Type[] types = ((ParameterizedTypeImpl) targetClass.getGenericSuperclass()).getActualTypeArguments();
74   - if (ArrayUtil.isEmpty(types)) {
75   - throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
76   - }
77   - return (Class<T>) types[0];
  64 + Type type = TypeUtil.getTypeArgument(getClass(), 0);
  65 + if (type == null) {
  66 + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
78 67 }
79   - throw new IllegalStateException(String.format("类型(%s) 找不到 AbstractMessageListener 父类", getClass().getName()));
  68 + return (Class<T>) type;
80 69 }
81 70  
82 71 }
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/core/pubsub/ChannelMessage.java
... ... @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
4 4  
5 5 /**
6 6 * Redis Channel Message 接口
  7 + *
  8 + * @author 芋道源码
7 9 */
8 10 public interface ChannelMessage {
9 11  
... ... @@ -12,7 +14,7 @@ public interface ChannelMessage {
12 14 *
13 15 * @return Channel
14 16 */
15   - @JsonIgnore // 必须序列化
  17 + @JsonIgnore // 避免序列化
16 18 String getChannel();
17 19  
18 20 }
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/core/stream/AbstractStreamMessageListener.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.redis.core.stream;
  2 +
  3 +import cn.hutool.core.util.TypeUtil;
  4 +import cn.iocoder.dashboard.util.json.JsonUtils;
  5 +import lombok.Getter;
  6 +import lombok.Setter;
  7 +import lombok.SneakyThrows;
  8 +import org.springframework.beans.factory.annotation.Value;
  9 +import org.springframework.data.redis.connection.stream.ObjectRecord;
  10 +import org.springframework.data.redis.core.RedisTemplate;
  11 +import org.springframework.data.redis.stream.StreamListener;
  12 +
  13 +import java.lang.reflect.Type;
  14 +
  15 +/**
  16 + * Redis Stream 监听器抽象类,用于实现集群消费
  17 + *
  18 + * @param <T> 消息类型。一定要填写噢,不然会报错
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +public abstract class AbstractStreamMessageListener<T extends StreamMessage>
  23 + implements StreamListener<String, ObjectRecord<String, String>> {
  24 +
  25 + /**
  26 + * 消息类型
  27 + */
  28 + private final Class<T> messageType;
  29 + /**
  30 + * Redis Channel
  31 + */
  32 + @Getter
  33 + private final String streamKey;
  34 +
  35 + /**
  36 + * Redis 消费者分组,默认使用 spring.application.name 名字
  37 + */
  38 + @Value("${spring.application.name}")
  39 + @Getter
  40 + private String group;
  41 + /**
  42 + *
  43 + */
  44 + @Setter
  45 + private RedisTemplate<String, ?> redisTemplate;
  46 +
  47 + @SneakyThrows
  48 + protected AbstractStreamMessageListener() {
  49 + this.messageType = getMessageClass();
  50 + this.streamKey = messageType.newInstance().getStreamKey();
  51 + }
  52 +
  53 + @Override
  54 + public void onMessage(ObjectRecord<String, String> message) {
  55 + // 消费消息
  56 + T messageObj = JsonUtils.parseObject(message.getValue(), messageType);
  57 + this.onMessage(messageObj);
  58 + // ack 消息消费完成
  59 + redisTemplate.opsForStream().acknowledge(group, message);
  60 + // TODO 芋艿:需要额外考虑以下几个点:
  61 + // 1. 处理异常的情况
  62 + // 2. 发送日志;以及事务的结合
  63 + // 3. 消费日志;以及通用的幂等性
  64 + // 4. 消费失败的重试,https://zhuanlan.zhihu.com/p/60501638
  65 + }
  66 +
  67 + /**
  68 + * 处理消息
  69 + *
  70 + * @param message 消息
  71 + */
  72 + public abstract void onMessage(T message);
  73 +
  74 + /**
  75 + * 通过解析类上的泛型,获得消息类型
  76 + *
  77 + * @return 消息类型
  78 + */
  79 + @SuppressWarnings("unchecked")
  80 + private Class<T> getMessageClass() {
  81 + Type type = TypeUtil.getTypeArgument(getClass(), 0);
  82 + if (type == null) {
  83 + throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
  84 + }
  85 + return (Class<T>) type;
  86 + }
  87 +
  88 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/core/stream/StreamMessage.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.redis.core.stream;
  2 +
  3 +import com.fasterxml.jackson.annotation.JsonIgnore;
  4 +
  5 +/**
  6 + * Redis Stream Message 接口
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface StreamMessage {
  11 +
  12 + /**
  13 + * 获得 Redis Stream Key
  14 + *
  15 + * @return Channel
  16 + */
  17 + @JsonIgnore // 避免序列化
  18 + String getStreamKey();
  19 +
  20 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/redis/core/util/RedisMessageUtils.java
1 1 package cn.iocoder.dashboard.framework.redis.core.util;
2 2  
3 3 import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage;
  4 +import cn.iocoder.dashboard.framework.redis.core.stream.StreamMessage;
4 5 import cn.iocoder.dashboard.util.json.JsonUtils;
  6 +import org.springframework.data.redis.connection.stream.RecordId;
  7 +import org.springframework.data.redis.connection.stream.StreamRecords;
5 8 import org.springframework.data.redis.core.RedisTemplate;
6 9  
7 10 /**
... ... @@ -17,8 +20,21 @@ public class RedisMessageUtils {
17 20 * @param redisTemplate Redis 操作模板
18 21 * @param message 消息
19 22 */
20   - public static <T extends ChannelMessage> void sendChannelMessage(RedisTemplate<?, ?> redisTemplate, T message) {
  23 + public static <T extends ChannelMessage> void sendChannelMessage(RedisTemplate<?, ?> redisTemplate, T message) {
21 24 redisTemplate.convertAndSend(message.getChannel(), JsonUtils.toJsonString(message));
22 25 }
23 26  
  27 + /**
  28 + * 发送 Redis 消息,基于 Redis Stream 实现
  29 + *
  30 + * @param redisTemplate Redis 操作模板
  31 + * @param message 消息
  32 + * @return 消息记录的编号对象
  33 + */
  34 + public static <T extends StreamMessage> RecordId sendStreamMessage(RedisTemplate<String, ?> redisTemplate, T message) {
  35 + return redisTemplate.opsForStream().add(StreamRecords.newRecord()
  36 + .ofObject(JsonUtils.toJsonString(message)) // 设置内容
  37 + .withStreamKey(message.getStreamKey())); // 设置 stream key
  38 + }
  39 +
24 40 }
... ...
src/main/java/cn/iocoder/dashboard/framework/security/config/SecurityConfiguration.java
... ... @@ -128,13 +128,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
128 128 // 设置每个请求的权限
129 129 .authorizeRequests()
130 130 // 登陆的接口,可匿名访问
131   - .antMatchers(webProperties.getApiPrefix() + "/login").anonymous()
  131 + .antMatchers(api("/login")).anonymous()
132 132 // 通用的接口,可匿名访问
133   - .antMatchers( webProperties.getApiPrefix() + "/system/captcha/**").anonymous()
  133 + .antMatchers(api("/system/captcha/**")).anonymous()
134 134 // 静态资源,可匿名访问
135 135 .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
136 136 // 文件的获取接口,可匿名访问
137   - .antMatchers(webProperties.getApiPrefix() + "/system/file/get/**").anonymous()
  137 + .antMatchers(api("/infra/file/get/**")).anonymous()
138 138 // Swagger 接口文档
139 139 .antMatchers("/swagger-ui.html").anonymous()
140 140 .antMatchers("/swagger-resources/**").anonymous()
... ... @@ -148,13 +148,19 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
148 148 .antMatchers("/actuator/**").anonymous()
149 149 // Druid 监控
150 150 .antMatchers("/druid/**").anonymous()
  151 + // 短信回调 API
  152 + .antMatchers(api("/system/sms/callback/**")).anonymous()
151 153 // 除上面外的所有请求全部需要鉴权认证
152 154 .anyRequest().authenticated()
153 155 .and()
154 156 .headers().frameOptions().disable();
155   - httpSecurity.logout().logoutUrl(webProperties.getApiPrefix() + "/logout").logoutSuccessHandler(logoutSuccessHandler);
  157 + httpSecurity.logout().logoutUrl(api("/logout")).logoutSuccessHandler(logoutSuccessHandler);
156 158 // 添加 JWT Filter
157 159 httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
158 160 }
159 161  
  162 + private String api(String url) {
  163 + return webProperties.getApiPrefix() + url;
  164 + }
  165 +
160 166 }
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/config/SmsConfiguration.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.config;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.impl.SmsClientFactoryImpl;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +/**
  9 + * 短信配置类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Configuration
  14 +public class SmsConfiguration {
  15 +
  16 + @Bean
  17 + public SmsClientFactory smsClientFactory() {
  18 + return new SmsClientFactoryImpl();
  19 + }
  20 +
  21 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 短信客户端接口
  12 + *
  13 + * @author zzf
  14 + * @date 2021/1/25 14:14
  15 + */
  16 +public interface SmsClient {
  17 +
  18 + /**
  19 + * 获得渠道编号
  20 + *
  21 + * @return 渠道编号
  22 + */
  23 + Long getId();
  24 +
  25 + /**
  26 + * 发送消息
  27 + *
  28 + * @param logId 日志编号
  29 + * @param mobile 手机号
  30 + * @param apiTemplateId 短信 API 的模板编号
  31 + * @param templateParams 短信模板参数。通过 List 数组,保证参数的顺序
  32 + * @return 短信发送结果
  33 + */
  34 + SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile, String apiTemplateId,
  35 + List<KeyValue<String, Object>> templateParams);
  36 +
  37 + /**
  38 + * 解析接收短信的接收结果
  39 + *
  40 + * @param text 结果
  41 + * @return 结果内容
  42 + * @throws Throwable 当解析 text 发生异常时,则会抛出异常
  43 + */
  44 + List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable;
  45 +
  46 + /**
  47 + * 查询指定的短信模板
  48 + *
  49 + * @param apiTemplateId 短信 API 的模板编号
  50 + * @return 短信模板
  51 + */
  52 + SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId);
  53 +
  54 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsClientFactory.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  4 +
  5 +/**
  6 + * 短信客户端工厂接口
  7 + *
  8 + * @author zzf
  9 + * @date 2021/1/28 14:01
  10 + */
  11 +public interface SmsClientFactory {
  12 +
  13 + /**
  14 + * 获得短信 Client
  15 + *
  16 + * @param channelId 渠道编号
  17 + * @return 短信 Client
  18 + */
  19 + SmsClient getSmsClient(Long channelId);
  20 +
  21 + /**
  22 + * 获得短信 Client
  23 + *
  24 + * @param channelCode 渠道编码
  25 + * @return 短信 Client
  26 + */
  27 + SmsClient getSmsClient(String channelCode);
  28 +
  29 + /**
  30 + * 创建短信 Client
  31 + *
  32 + * @param properties 配置对象
  33 + */
  34 + void createOrUpdateSmsClient(SmsChannelProperties properties);
  35 +
  36 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
  5 +
  6 +import java.util.function.Function;
  7 +
  8 +/**
  9 + * 将 API 的错误码,转换为通用的错误码
  10 + *
  11 + * @see SmsCommonResult
  12 + * @see SmsFrameworkErrorCodeConstants
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface SmsCodeMapping extends Function<String, ErrorCode> {
  17 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/SmsCommonResult.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client;
  2 +
  3 +import cn.hutool.core.exceptions.ExceptionUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  6 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  7 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
  8 +import lombok.Data;
  9 +import lombok.EqualsAndHashCode;
  10 +import lombok.ToString;
  11 +
  12 +/**
  13 + * 短信的 CommonResult 拓展类
  14 + *
  15 + * 考虑到不同的平台,返回的 code 和 msg 是不同的,所以统一额外返回 {@link #apiCode} 和 {@link #apiMsg} 字段
  16 + *
  17 + * 另外,一些短信平台(例如说阿里云、腾讯云)会返回一个请求编号,用于排查请求失败的问题,我们设置到 {@link #apiRequestId} 字段
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +@Data
  22 +@EqualsAndHashCode(callSuper = true)
  23 +@ToString(callSuper = true)
  24 +public class SmsCommonResult<T> extends CommonResult<T> {
  25 +
  26 + /**
  27 + * API 返回错误码
  28 + *
  29 + * 由于第三方的错误码可能是字符串,所以使用 String 类型
  30 + */
  31 + private String apiCode;
  32 + /**
  33 + * API 返回提示
  34 + */
  35 + private String apiMsg;
  36 +
  37 + /**
  38 + * API 请求编号
  39 + */
  40 + private String apiRequestId;
  41 +
  42 + private SmsCommonResult() {
  43 + }
  44 +
  45 + public static <T> SmsCommonResult<T> build(String apiCode, String apiMsg, String apiRequestId,
  46 + T data, SmsCodeMapping codeMapping) {
  47 + Assert.notNull(codeMapping, "参数 codeMapping 不能为空");
  48 + SmsCommonResult<T> result = new SmsCommonResult<T>().setApiCode(apiCode).setApiMsg(apiMsg).setApiRequestId(apiRequestId);
  49 + result.setData(data);
  50 + // 翻译错误码
  51 + if (codeMapping != null) {
  52 + ErrorCode errorCode = codeMapping.apply(apiCode);
  53 + if (errorCode == null) {
  54 + errorCode = SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
  55 + }
  56 + result.setCode(errorCode.getCode()).setMsg(errorCode.getMsg());
  57 + }
  58 + return result;
  59 + }
  60 +
  61 + public static <T> SmsCommonResult<T> error(Throwable ex) {
  62 + SmsCommonResult<T> result = new SmsCommonResult<>();
  63 + result.setCode(SmsFrameworkErrorCodeConstants.EXCEPTION.getCode());
  64 + result.setMsg(ExceptionUtil.getRootCauseMessage(ex));
  65 + return result;
  66 + }
  67 +
  68 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsReceiveRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.Date;
  6 +
  7 +/**
  8 + * 消息接收 Response DTO
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class SmsReceiveRespDTO {
  14 +
  15 + /**
  16 + * 是否接收成功
  17 + */
  18 + private Boolean success;
  19 + /**
  20 + * API 接收结果的编码
  21 + */
  22 + private String errorCode;
  23 + /**
  24 + * API 接收结果的说明
  25 + */
  26 + private String errorMsg;
  27 +
  28 + /**
  29 + * 手机号
  30 + */
  31 + private String mobile;
  32 + /**
  33 + * 用户接收时间
  34 + */
  35 + private Date receiveTime;
  36 +
  37 + /**
  38 + * 短信 API 发送返回的序号
  39 + */
  40 + private String serialNo;
  41 + /**
  42 + * 短信日志编号
  43 + *
  44 + * 对应 SysSmsLogDO 的编号
  45 + */
  46 + private Long logId;
  47 +
  48 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsSendRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 短信发送 Response DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class SmsSendRespDTO {
  12 +
  13 + /**
  14 + * 短信 API 发送返回的序号
  15 + */
  16 + private String serialNo;
  17 +
  18 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/dto/SmsTemplateRespDTO.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.dto;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * 短信模板 Response DTO
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public class SmsTemplateRespDTO {
  13 +
  14 + /**
  15 + * 模板编号
  16 + */
  17 + private String id;
  18 + /**
  19 + * 短信内容
  20 + */
  21 + private String content;
  22 + /**
  23 + * 审核状态
  24 + *
  25 + * 枚举 {@link SmsTemplateAuditStatusEnum}
  26 + */
  27 + private Integer auditStatus;
  28 + /**
  29 + * 审核未通过的理由
  30 + */
  31 + private String auditReason;
  32 +
  33 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/AbstractSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl;
  2 +
  3 +import cn.iocoder.dashboard.common.core.KeyValue;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +
  13 +import java.util.List;
  14 +
  15 +/**
  16 + * 短信客户端抽象类
  17 + *
  18 + * @author zzf
  19 + * @date 2021/2/1 9:28
  20 + */
  21 +@Slf4j
  22 +public abstract class AbstractSmsClient implements SmsClient {
  23 +
  24 + /**
  25 + * 短信渠道配置
  26 + */
  27 + protected volatile SmsChannelProperties properties;
  28 + /**
  29 + * 错误码枚举类
  30 + */
  31 + protected final SmsCodeMapping codeMapping;
  32 +
  33 + /**
  34 + * 短信客户端有参构造函数
  35 + *
  36 + * @param properties 短信配置
  37 + */
  38 + public AbstractSmsClient(SmsChannelProperties properties, SmsCodeMapping codeMapping) {
  39 + this.properties = properties;
  40 + this.codeMapping = codeMapping;
  41 + }
  42 +
  43 + /**
  44 + * 初始化
  45 + */
  46 + public final void init() {
  47 + doInit();
  48 + log.info("[init][配置({}) 初始化完成]", properties);
  49 + }
  50 +
  51 + public final void refresh(SmsChannelProperties properties) {
  52 + // 判断是否更新
  53 + if (properties.equals(this.properties)) {
  54 + return;
  55 + }
  56 + log.info("[refresh][配置({})发生变化,重新初始化]", properties);
  57 + this.properties = properties;
  58 + // 初始化
  59 + this.init();
  60 + }
  61 +
  62 + /**
  63 + * 自定义初始化
  64 + */
  65 + protected abstract void doInit();
  66 +
  67 + @Override
  68 + public Long getId() {
  69 + return properties.getId();
  70 + }
  71 +
  72 + @Override
  73 + public final SmsCommonResult<SmsSendRespDTO> sendSms(Long logId, String mobile,
  74 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
  75 + // 执行短信发送
  76 + SmsCommonResult<SmsSendRespDTO> result;
  77 + try {
  78 + result = doSendSms(logId, mobile, apiTemplateId, templateParams);
  79 + } catch (Throwable ex) {
  80 + // 打印异常日志
  81 + log.error("[sendSms][发送短信异常,sendLogId({}) mobile({}) apiTemplateId({}) templateParams({})]",
  82 + logId, mobile, apiTemplateId, templateParams, ex);
  83 + // 封装返回
  84 + return SmsCommonResult.error(ex);
  85 + }
  86 + return result;
  87 + }
  88 +
  89 + protected abstract SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  90 + String apiTemplateId, List<KeyValue<String, Object>> templateParams)
  91 + throws Throwable;
  92 +
  93 + @Override
  94 + public List<SmsReceiveRespDTO> parseSmsReceiveStatus(String text) throws Throwable {
  95 + try {
  96 + return doParseSmsReceiveStatus(text);
  97 + } catch (Throwable ex) {
  98 + log.error("[parseSmsReceiveStatus][text({}) 解析发生异常]", text, ex);
  99 + throw ex;
  100 + }
  101 + }
  102 +
  103 + protected abstract List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable;
  104 +
  105 + @Override
  106 + public SmsCommonResult<SmsTemplateRespDTO> getSmsTemplate(String apiTemplateId) {
  107 + // 执行短信发送
  108 + SmsCommonResult<SmsTemplateRespDTO> result;
  109 + try {
  110 + result = doGetSmsTemplate(apiTemplateId);
  111 + } catch (Throwable ex) {
  112 + // 打印异常日志
  113 + log.error("[getSmsTemplate][获得短信模板({}) 发生异常]", apiTemplateId, ex);
  114 + // 封装返回
  115 + return SmsCommonResult.error(ex);
  116 + }
  117 + return result;
  118 + }
  119 +
  120 + protected abstract SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable;
  121 +
  122 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/SmsClientFactoryImpl.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl;
  2 +
  3 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClient;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsClientFactory;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
  6 +import cn.iocoder.dashboard.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
  8 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsChannelEnum;
  9 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  10 +import lombok.extern.slf4j.Slf4j;
  11 +import org.springframework.util.Assert;
  12 +import org.springframework.validation.annotation.Validated;
  13 +
  14 +import java.util.Arrays;
  15 +import java.util.concurrent.ConcurrentHashMap;
  16 +import java.util.concurrent.ConcurrentMap;
  17 +
  18 +/**
  19 + * 短信客户端工厂接口
  20 + *
  21 + * @author zzf
  22 + */
  23 +@Validated
  24 +@Slf4j
  25 +public class SmsClientFactoryImpl implements SmsClientFactory {
  26 +
  27 + /**
  28 + * 短信客户端 Map
  29 + * key:渠道编号,使用 {@link SmsChannelProperties#getId()}
  30 + */
  31 + private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();
  32 +
  33 + /**
  34 + * 短信客户端 Map
  35 + * key:渠道编码,使用 {@link SmsChannelProperties#getCode()} ()}
  36 + *
  37 + * 注意,一些场景下,需要获得某个渠道类型的客户端,所以需要使用它。
  38 + * 例如说,解析短信接收结果,是相对通用的,不需要使用某个渠道编号的 {@link #channelIdClients}
  39 + */
  40 + private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();
  41 +
  42 + public SmsClientFactoryImpl() {
  43 + // 初始化 channelCodeClients 集合
  44 + Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
  45 + // 创建一个空的 SmsChannelProperties 对象
  46 + SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode())
  47 + .setApiKey("default").setApiSecret("default");
  48 + // 创建 Sms 客户端
  49 + AbstractSmsClient smsClient = createSmsClient(properties);
  50 + channelCodeClients.put(channel.getCode(), smsClient);
  51 + });
  52 + }
  53 +
  54 + @Override
  55 + public SmsClient getSmsClient(Long channelId) {
  56 + return channelIdClients.get(channelId);
  57 + }
  58 +
  59 + @Override
  60 + public SmsClient getSmsClient(String channelCode) {
  61 + return channelCodeClients.get(channelCode);
  62 + }
  63 +
  64 + @Override
  65 + public void createOrUpdateSmsClient(SmsChannelProperties properties) {
  66 + AbstractSmsClient client = channelIdClients.get(properties.getId());
  67 + if (client == null) {
  68 + client = this.createSmsClient(properties);
  69 + client.init();
  70 + channelIdClients.put(client.getId(), client);
  71 + } else {
  72 + client.refresh(properties);
  73 + }
  74 + }
  75 +
  76 + private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
  77 + SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
  78 + Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
  79 + // 创建客户端
  80 + switch (channelEnum) {
  81 + case ALIYUN: return new AliyunSmsClient(properties);
  82 + case YUN_PIAN: return new YunpianSmsClient(properties);
  83 + case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
  84 + }
  85 + // 创建失败,错误日志 + 抛出异常
  86 + log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
  87 + throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
  88 + }
  89 +
  90 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.hutool.core.util.ReflectUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.dashboard.common.core.KeyValue;
  7 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  12 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  13 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  14 +import cn.iocoder.dashboard.util.collection.MapUtils;
  15 +import cn.iocoder.dashboard.util.json.JsonUtils;
  16 +import com.aliyuncs.AcsRequest;
  17 +import com.aliyuncs.AcsResponse;
  18 +import com.aliyuncs.DefaultAcsClient;
  19 +import com.aliyuncs.IAcsClient;
  20 +import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
  21 +import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
  22 +import com.aliyuncs.exceptions.ClientException;
  23 +import com.aliyuncs.profile.DefaultProfile;
  24 +import com.aliyuncs.profile.IClientProfile;
  25 +import com.fasterxml.jackson.annotation.JsonFormat;
  26 +import com.fasterxml.jackson.annotation.JsonProperty;
  27 +import com.google.common.annotations.VisibleForTesting;
  28 +import lombok.Data;
  29 +import lombok.extern.slf4j.Slf4j;
  30 +
  31 +import java.util.Date;
  32 +import java.util.List;
  33 +import java.util.Objects;
  34 +import java.util.function.Function;
  35 +import java.util.stream.Collectors;
  36 +
  37 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  38 +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
  39 +
  40 +/**
  41 + * 阿里短信客户端的实现类
  42 + *
  43 + * @author zzf
  44 + * @date 2021/1/25 14:17
  45 + */
  46 +@Slf4j
  47 +public class AliyunSmsClient extends AbstractSmsClient {
  48 +
  49 + /**
  50 + * REGION, 使用杭州
  51 + */
  52 + private static final String ENDPOINT = "cn-hangzhou";
  53 +
  54 + /**
  55 + * 阿里云客户端
  56 + */
  57 + private volatile IAcsClient client;
  58 +
  59 + public AliyunSmsClient(SmsChannelProperties properties) {
  60 + super(properties, new AliyunSmsCodeMapping());
  61 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  62 + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
  63 + }
  64 +
  65 + @Override
  66 + protected void doInit() {
  67 + IClientProfile profile = DefaultProfile.getProfile(ENDPOINT, properties.getApiKey(), properties.getApiSecret());
  68 + client = new DefaultAcsClient(profile);
  69 + }
  70 +
  71 + @Override
  72 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  73 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) {
  74 + // 构建参数
  75 + SendSmsRequest request = new SendSmsRequest();
  76 + request.setPhoneNumbers(mobile);
  77 + request.setSignName(properties.getSignature());
  78 + request.setTemplateCode(apiTemplateId);
  79 + request.setTemplateParam(JsonUtils.toJsonString(MapUtils.convertMap(templateParams)));
  80 + request.setOutId(String.valueOf(sendLogId));
  81 + // 执行请求
  82 + return invoke(request, response -> new SmsSendRespDTO().setSerialNo(response.getBizId()));
  83 + }
  84 +
  85 + @Override
  86 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  87 + List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
  88 + return statuses.stream().map(status -> {
  89 + SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
  90 + resp.setSuccess(status.getSuccess());
  91 + resp.setErrorCode(status.getErrCode()).setErrorMsg(status.getErrMsg());
  92 + resp.setMobile(status.getPhoneNumber()).setReceiveTime(status.getReportTime());
  93 + resp.setSerialNo(status.getBizId()).setLogId(Long.valueOf(status.getOutId()));
  94 + return resp;
  95 + }).collect(Collectors.toList());
  96 + }
  97 +
  98 + @Override
  99 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
  100 + // 构建参数
  101 + QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
  102 + request.setTemplateCode(apiTemplateId);
  103 + // 执行请求
  104 + return invoke(request, response -> {
  105 + SmsTemplateRespDTO data = new SmsTemplateRespDTO();
  106 + data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
  107 + data.setAuditStatus(convertSmsTemplateAuditStatus(response.getTemplateStatus())).setAuditReason(response.getReason());
  108 + return data;
  109 + });
  110 + }
  111 +
  112 + @VisibleForTesting
  113 + Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
  114 + switch (templateStatus) {
  115 + case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
  116 + case 1: return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
  117 + case 2: return SmsTemplateAuditStatusEnum.FAIL.getStatus();
  118 + default: throw new IllegalArgumentException(String.format("未知审核状态(%d)", templateStatus));
  119 + }
  120 + }
  121 +
  122 + @VisibleForTesting
  123 + <T extends AcsResponse, R> SmsCommonResult<R> invoke(AcsRequest<T> request, Function<T, R> responseConsumer) {
  124 + try {
  125 + // 执行发送. 由于阿里云 sms 短信没有统一的 Response,但是有统一的 code、message、requestId 属性,所以只好反射
  126 + T sendResult = client.getAcsResponse(request);
  127 + String code = (String) ReflectUtil.getFieldValue(sendResult, "code");
  128 + String message = (String) ReflectUtil.getFieldValue(sendResult, "message");
  129 + String requestId = (String) ReflectUtil.getFieldValue(sendResult, "requestId");
  130 + // 解析结果
  131 + R data = null;
  132 + if (Objects.equals(code, "OK")) { // 请求成功的情况下
  133 + data = responseConsumer.apply(sendResult);
  134 + }
  135 + // 拼接结果
  136 + return SmsCommonResult.build(code, message, requestId, data, codeMapping);
  137 + } catch (ClientException ex) {
  138 + return SmsCommonResult.build(ex.getErrCode(), formatResultMsg(ex), ex.getRequestId(), null, codeMapping);
  139 + }
  140 + }
  141 +
  142 + private static String formatResultMsg(ClientException ex) {
  143 + if (StrUtil.isEmpty(ex.getErrorDescription())) {
  144 + return ex.getErrMsg();
  145 + }
  146 + return ex.getErrMsg() + " => " + ex.getErrorDescription();
  147 + }
  148 +
  149 + /**
  150 + * 短信接收状态
  151 + *
  152 + * 参见 https://help.aliyun.com/document_detail/101867.html 文档
  153 + *
  154 + * @author 芋道源码
  155 + */
  156 + @Data
  157 + public static class SmsReceiveStatus {
  158 +
  159 + /**
  160 + * 手机号
  161 + */
  162 + @JsonProperty("phone_number")
  163 + private String phoneNumber;
  164 + /**
  165 + * 发送时间
  166 + */
  167 + @JsonProperty("send_time")
  168 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  169 + private Date sendTime;
  170 + /**
  171 + * 状态报告时间
  172 + */
  173 + @JsonProperty("report_time")
  174 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  175 + private Date reportTime;
  176 + /**
  177 + * 是否接收成功
  178 + */
  179 + private Boolean success;
  180 + /**
  181 + * 状态报告说明
  182 + */
  183 + @JsonProperty("err_msg")
  184 + private String errMsg;
  185 + /**
  186 + * 状态报告编码
  187 + */
  188 + @JsonProperty("err_code")
  189 + private String errCode;
  190 + /**
  191 + * 发送序列号
  192 + */
  193 + @JsonProperty("biz_id")
  194 + private String bizId;
  195 + /**
  196 + * 用户序列号
  197 + *
  198 + * 这里我们传递的是 SysSmsLogDO 的日志编号
  199 + */
  200 + @JsonProperty("out_id")
  201 + private String outId;
  202 + /**
  203 + * 短信长度,例如说 1、2、3
  204 + *
  205 + * 140 字节算一条短信,短信长度超过 140 字节时会拆分成多条短信发送
  206 + */
  207 + @JsonProperty("sms_size")
  208 + private Integer smsSize;
  209 +
  210 + }
  211 +
  212 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/aliyun/AliyunSmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.aliyun;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +
  7 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
  8 +
  9 +/**
  10 + * 阿里云的 SmsCodeMapping 实现类
  11 + *
  12 + * 参见 https://help.aliyun.com/document_detail/101346.htm 文档
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class AliyunSmsCodeMapping implements SmsCodeMapping {
  17 +
  18 + @Override
  19 + public ErrorCode apply(String apiCode) {
  20 + switch (apiCode) {
  21 + case "OK": return GlobalErrorCodeConstants.SUCCESS;
  22 + case "isv.ACCOUNT_NOT_EXISTS":
  23 + case "isv.ACCOUNT_ABNORMAL":
  24 + case "MissingAccessKeyId": return SMS_ACCOUNT_INVALID;
  25 + case "isp.RAM_PERMISSION_DENY": return SMS_PERMISSION_DENY;
  26 + case "isv.INVALID_JSON_PARAM":
  27 + case "isv.INVALID_PARAMETERS": return SMS_API_PARAM_ERROR;
  28 + case "isv.BUSINESS_LIMIT_CONTROL": return SMS_SEND_BUSINESS_LIMIT_CONTROL;
  29 + case "isv.DAY_LIMIT_CONTROL": return SMS_SEND_DAY_LIMIT_CONTROL;
  30 + case "isv.SMS_CONTENT_ILLEGAL": return SMS_SEND_CONTENT_INVALID;
  31 + case "isv.SMS_TEMPLATE_ILLEGAL": return SMS_TEMPLATE_INVALID;
  32 + case "isv.SMS_SIGNATURE_ILLEGAL":
  33 + case "isv.SIGN_NAME_ILLEGAL":
  34 + case "isv.SMS_SIGN_ILLEGAL": return SMS_SIGN_INVALID;
  35 + case "isv.AMOUNT_NOT_ENOUGH":
  36 + case "isv.OUT_OF_SERVICE": return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
  37 + case "isv.MOBILE_NUMBER_ILLEGAL": return SMS_MOBILE_INVALID;
  38 + case "isv.TEMPLATE_MISSING_PARAMETERS": return SMS_TEMPLATE_PARAM_ERROR;
  39 + }
  40 + return SMS_UNKNOWN;
  41 + }
  42 +
  43 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  5 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  6 +
  7 +import java.util.Objects;
  8 +
  9 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
  10 +
  11 +/**
  12 + * 钉钉的 SmsCodeMapping 实现类
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public class DebugDingTalkCodeMapping implements SmsCodeMapping {
  17 +
  18 + @Override
  19 + public ErrorCode apply(String apiCode) {
  20 + return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SMS_UNKNOWN;
  21 + }
  22 +
  23 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/debug/DebugDingTalkSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.debug;
  2 +
  3 +import cn.hutool.core.codec.Base64;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.map.MapUtil;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.hutool.crypto.digest.DigestUtil;
  8 +import cn.hutool.crypto.digest.HmacAlgorithm;
  9 +import cn.hutool.http.HttpUtil;
  10 +import cn.iocoder.dashboard.common.core.KeyValue;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  12 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  13 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  14 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  15 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  16 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  17 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  18 +import cn.iocoder.dashboard.util.collection.MapUtils;
  19 +import cn.iocoder.dashboard.util.json.JsonUtils;
  20 +
  21 +import java.util.HashMap;
  22 +import java.util.List;
  23 +import java.util.Map;
  24 +
  25 +/**
  26 + * 基于钉钉 WebHook 实现的调试的短信客户端实现类
  27 + *
  28 + * 考虑到省钱,我们使用钉钉 WebHook 模拟发送短信,方便调试。
  29 + *
  30 + * @author 芋道源码
  31 + */
  32 +public class DebugDingTalkSmsClient extends AbstractSmsClient {
  33 +
  34 + public DebugDingTalkSmsClient(SmsChannelProperties properties) {
  35 + super(properties, new DebugDingTalkCodeMapping());
  36 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  37 + Assert.notEmpty(properties.getApiSecret(), "apiSecret 不能为空");
  38 + }
  39 +
  40 + @Override
  41 + protected void doInit() {
  42 + }
  43 +
  44 + @Override
  45 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  46 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
  47 + // 构建请求
  48 + String url = buildUrl("robot/send");
  49 + Map<String, Object> params = new HashMap<>();
  50 + params.put("msgtype", "text");
  51 + String content = String.format("【模拟短信】\n手机号:%s\n短信日志编号:%d\n模板参数:%s",
  52 + mobile, sendLogId, MapUtils.convertMap(templateParams));
  53 + params.put("text", MapUtil.builder().put("content", content).build());
  54 + // 执行请求
  55 + String responseText = HttpUtil.post(url, JsonUtils.toJsonString(params));
  56 + // 解析结果
  57 + Map<?, ?> responseObj = JsonUtils.parseObject(responseText, Map.class);
  58 + return SmsCommonResult.build(MapUtil.getStr(responseObj, "errcode"), MapUtil.getStr(responseObj, "errorMsg"),
  59 + null, new SmsSendRespDTO().setSerialNo(StrUtil.uuid()), codeMapping);
  60 + }
  61 +
  62 + /**
  63 + * 构建请求地址
  64 + *
  65 + * 参见 https://developers.dingtalk.com/document/app/custom-robot-access/title-nfv-794-g71 文档
  66 + *
  67 + * @param path 请求路径
  68 + * @return 请求地址
  69 + */
  70 + @SuppressWarnings("SameParameterValue")
  71 + private String buildUrl(String path) {
  72 + // 生成 timestamp
  73 + long timestamp = System.currentTimeMillis();
  74 + // 生成 sign
  75 + String secret = properties.getApiSecret();
  76 + String stringToSign = timestamp + "\n" + secret;
  77 + byte[] signData = DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.bytes(secret)).digest(stringToSign);
  78 + String sign = Base64.encode(signData);
  79 + // 构建最终 URL
  80 + return String.format("https://oapi.dingtalk.com/%s?access_token=%s&timestamp=%d&sign=%s",
  81 + path, properties.getApiKey(), timestamp, sign);
  82 + }
  83 +
  84 + @Override
  85 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  86 + throw new UnsupportedOperationException("模拟短信客户端,暂时无需解析回调");
  87 + }
  88 +
  89 + @Override
  90 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) {
  91 + SmsTemplateRespDTO data = new SmsTemplateRespDTO().setId(apiTemplateId).setContent("")
  92 + .setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason("");
  93 + return SmsCommonResult.build("0", "success", null, data, codeMapping);
  94 + }
  95 +
  96 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsClient.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import cn.hutool.core.util.URLUtil;
  7 +import cn.iocoder.dashboard.common.core.KeyValue;
  8 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCommonResult;
  9 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsReceiveRespDTO;
  10 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsSendRespDTO;
  11 +import cn.iocoder.dashboard.framework.sms.core.client.dto.SmsTemplateRespDTO;
  12 +import cn.iocoder.dashboard.framework.sms.core.client.impl.AbstractSmsClient;
  13 +import cn.iocoder.dashboard.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
  14 +import cn.iocoder.dashboard.framework.sms.core.property.SmsChannelProperties;
  15 +import cn.iocoder.dashboard.util.json.JsonUtils;
  16 +import com.fasterxml.jackson.annotation.JsonFormat;
  17 +import com.fasterxml.jackson.annotation.JsonProperty;
  18 +import com.google.common.annotations.VisibleForTesting;
  19 +import com.yunpian.sdk.YunpianClient;
  20 +import com.yunpian.sdk.constant.YunpianConstant;
  21 +import com.yunpian.sdk.model.Result;
  22 +import com.yunpian.sdk.model.Template;
  23 +import lombok.Data;
  24 +import lombok.extern.slf4j.Slf4j;
  25 +
  26 +import java.util.*;
  27 +import java.util.function.Function;
  28 +import java.util.function.Supplier;
  29 +import java.util.stream.Collectors;
  30 +
  31 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  32 +import static cn.iocoder.dashboard.util.date.DateUtils.TIME_ZONE_DEFAULT;
  33 +
  34 +/**
  35 + * 云片短信客户端的实现类
  36 + *
  37 + * @author zzf
  38 + * @date 9:48 2021/3/5
  39 + */
  40 +@Slf4j
  41 +public class YunpianSmsClient extends AbstractSmsClient {
  42 +
  43 + /**
  44 + * 云信短信客户端
  45 + */
  46 + private volatile YunpianClient client;
  47 +
  48 + public YunpianSmsClient(SmsChannelProperties properties) {
  49 + super(properties, new YunpianSmsCodeMapping());
  50 + Assert.notEmpty(properties.getApiKey(), "apiKey 不能为空");
  51 + }
  52 +
  53 + @Override
  54 + public void doInit() {
  55 + YunpianClient oldClient = client;
  56 + // 初始化新的客户端
  57 + YunpianClient newClient = new YunpianClient(properties.getApiKey());
  58 + newClient.init();
  59 + this.client = newClient;
  60 + // 销毁老的客户端
  61 + if (oldClient != null) {
  62 + oldClient.close();
  63 + }
  64 + }
  65 +
  66 + @Override
  67 + protected SmsCommonResult<SmsSendRespDTO> doSendSms(Long sendLogId, String mobile,
  68 + String apiTemplateId, List<KeyValue<String, Object>> templateParams) throws Throwable {
  69 + return invoke(() -> {
  70 + Map<String, String> request = new HashMap<>();
  71 + request.put(YunpianConstant.MOBILE, mobile);
  72 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  73 + request.put(YunpianConstant.TPL_VALUE, formatTplValue(templateParams));
  74 + request.put(YunpianConstant.UID, String.valueOf(sendLogId));
  75 + request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
  76 + return client.sms().tpl_single_send(request);
  77 + }, response -> new SmsSendRespDTO().setSerialNo(String.valueOf(response.getSid())));
  78 + }
  79 +
  80 + private static String formatTplValue(List<KeyValue<String, Object>> templateParams) {
  81 + if (CollUtil.isEmpty(templateParams)) {
  82 + return "";
  83 + }
  84 + // 参考 https://www.yunpian.com/official/document/sms/zh_cn/introduction_demos_encode_sample 格式化
  85 + StringJoiner joiner = new StringJoiner("&");
  86 + templateParams.forEach(param -> joiner.add(String.format("#%s#=%s", param.getKey(), URLUtil.encode(String.valueOf(param.getValue())))));
  87 + return joiner.toString();
  88 + }
  89 +
  90 + @Override
  91 + protected List<SmsReceiveRespDTO> doParseSmsReceiveStatus(String text) throws Throwable {
  92 + List<SmsReceiveStatus> statuses = JsonUtils.parseArray(text, SmsReceiveStatus.class);
  93 + return statuses.stream().map(status -> {
  94 + SmsReceiveRespDTO resp = new SmsReceiveRespDTO();
  95 + resp.setSuccess(Objects.equals(status.getReportStatus(), "SUCCESS"));
  96 + resp.setErrorCode(status.getErrorMsg()).setErrorMsg(status.getErrorDetail());
  97 + resp.setMobile(status.getMobile()).setReceiveTime(status.getUserReceiveTime());
  98 + resp.setSerialNo(String.valueOf(status.getSid())).setLogId(status.getUid());
  99 + return resp;
  100 + }).collect(Collectors.toList());
  101 + }
  102 +
  103 + @Override
  104 + protected SmsCommonResult<SmsTemplateRespDTO> doGetSmsTemplate(String apiTemplateId) throws Throwable {
  105 + return invoke(() -> {
  106 + Map<String, String> request = new HashMap<>();
  107 + request.put(YunpianConstant.APIKEY, properties.getApiKey());
  108 + request.put(YunpianConstant.TPL_ID, apiTemplateId);
  109 + return client.tpl().get(request);
  110 + }, response -> {
  111 + Template template = response.get(0);
  112 + return new SmsTemplateRespDTO().setId(String.valueOf(template.getTpl_id())).setContent(template.getTpl_content())
  113 + .setAuditStatus(convertSmsTemplateAuditStatus(template.getCheck_status())).setAuditReason(template.getReason());
  114 + });
  115 + }
  116 +
  117 + @VisibleForTesting
  118 + Integer convertSmsTemplateAuditStatus(String checkStatus) {
  119 + switch (checkStatus) {
  120 + case "CHECKING": return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
  121 + case "SUCCESS": return SmsTemplateAuditStatusEnum.SUCCESS.getStatus();
  122 + case "FAIL": return SmsTemplateAuditStatusEnum.FAIL.getStatus();
  123 + default: throw new IllegalArgumentException(String.format("未知审核状态(%s)", checkStatus));
  124 + }
  125 + }
  126 +
  127 + @VisibleForTesting
  128 + <T, R> SmsCommonResult<R> invoke(Supplier<Result<T>> requestConsumer, Function<T, R> responseConsumer) throws Throwable {
  129 + // 执行请求
  130 + Result<T> result = requestConsumer.get();
  131 + if (result.getThrowable() != null) {
  132 + throw result.getThrowable();
  133 + }
  134 + // 解析结果
  135 + R data = null;
  136 + if (result.getData() != null) {
  137 + data = responseConsumer.apply(result.getData());
  138 + }
  139 + // 拼接结果
  140 + return SmsCommonResult.build(String.valueOf(result.getCode()), formatResultMsg(result), null, data, codeMapping);
  141 + }
  142 +
  143 + private static String formatResultMsg(Result<?> sendResult) {
  144 + if (StrUtil.isEmpty(sendResult.getDetail())) {
  145 + return sendResult.getMsg();
  146 + }
  147 + return sendResult.getMsg() + " => " + sendResult.getDetail();
  148 + }
  149 +
  150 + /**
  151 + * 短信接收状态
  152 + *
  153 + * 参见 https://www.yunpian.com/official/document/sms/zh_cn/domestic_push_report 文档
  154 + *
  155 + * @author 芋道源码
  156 + */
  157 + @Data
  158 + public static class SmsReceiveStatus {
  159 +
  160 + /**
  161 + * 接收状态
  162 + *
  163 + * 目前仅有 SUCCESS / FAIL,所以使用 Boolean 接收
  164 + */
  165 + @JsonProperty("report_status")
  166 + private String reportStatus;
  167 + /**
  168 + * 接收手机号
  169 + */
  170 + private String mobile;
  171 + /**
  172 + * 运营商返回的代码,如:"DB:0103"
  173 + *
  174 + * 由于不同运营商信息不同,此字段仅供参考;
  175 + */
  176 + @JsonProperty("error_msg")
  177 + private String errorMsg;
  178 + /**
  179 + * 运营商反馈代码的中文解释
  180 + *
  181 + * 默认不推送此字段,如需推送,请联系客服
  182 + */
  183 + @JsonProperty("error_detail")
  184 + private String errorDetail;
  185 + /**
  186 + * 短信编号
  187 + */
  188 + private Long sid;
  189 + /**
  190 + * 用户自定义 id
  191 + *
  192 + * 这里我们传递的是 SysSmsLogDO 的日志编号
  193 + */
  194 + private Long uid;
  195 + /**
  196 + * 用户接收时间
  197 + */
  198 + @JsonProperty("user_receive_time")
  199 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  200 + private Date userReceiveTime;
  201 +
  202 + }
  203 +
  204 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.client.impl.yunpian;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +import cn.iocoder.dashboard.framework.sms.core.client.SmsCodeMapping;
  5 +
  6 +import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
  7 +import static cn.iocoder.dashboard.framework.sms.core.enums.SmsFrameworkErrorCodeConstants.*;
  8 +import static com.yunpian.sdk.constant.Code.*;
  9 +
  10 +/**
  11 + * 云片的 SmsCodeMapping 实现类
  12 + *
  13 + * 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class YunpianSmsCodeMapping implements SmsCodeMapping {
  18 +
  19 + @Override
  20 + public ErrorCode apply(String apiCode) {
  21 + int code = Integer.parseInt(apiCode);
  22 + switch (code) {
  23 + case OK: return SUCCESS;
  24 + case ARGUMENT_MISSING: return SMS_API_PARAM_ERROR;
  25 + case BAD_ARGUMENT_FORMAT: return SMS_TEMPLATE_PARAM_ERROR;
  26 + case TPL_NOT_FOUND:
  27 + case TPL_NOT_VALID: return SMS_TEMPLATE_INVALID;
  28 + case MONEY_NOT_ENOUGH: return SMS_ACCOUNT_MONEY_NOT_ENOUGH;
  29 + case BLACK_WORD: return SMS_SEND_CONTENT_INVALID;
  30 + case DUP_IN_SHORT_TIME:
  31 + case TOO_MANY_TIME_IN_5:
  32 + case DAY_LIMIT_PER_MOBILE:
  33 + case HOUR_LIMIT_PER_MOBILE: return SMS_SEND_BUSINESS_LIMIT_CONTROL;
  34 + case BLACK_PHONE_FILTER: return SMS_MOBILE_BLACK;
  35 + case SIGN_NOT_MATCH:
  36 + case BAD_SIGN_FORMAT:
  37 + case SIGN_NOT_VALID: return SMS_SIGN_INVALID;
  38 + case BAD_API_KEY: return SMS_ACCOUNT_INVALID;
  39 + case API_NOT_ALLOWED: return SMS_PERMISSION_DENY;
  40 + case IP_NOT_ALLOWED: return SMS_IP_DENY;
  41 + }
  42 + return SMS_UNKNOWN;
  43 + }
  44 +
  45 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsChannelEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +/**
  8 + * 短信渠道枚举
  9 + *
  10 + * @author zzf
  11 + * @date 2021/1/25 10:56
  12 + */
  13 +@Getter
  14 +@AllArgsConstructor
  15 +public enum SmsChannelEnum {
  16 +
  17 + DEBUG_DING_TALK("DEBUG_DING_TALK", "调试(钉钉)"),
  18 + YUN_PIAN("YUN_PIAN", "云片"),
  19 + ALIYUN("ALIYUN", "阿里云"),
  20 +// TENCENT("TENCENT", "腾讯云"),
  21 +// HUA_WEI("HUA_WEI", "华为云"),
  22 + ;
  23 +
  24 + /**
  25 + * 编码
  26 + */
  27 + private final String code;
  28 + /**
  29 + * 名字
  30 + */
  31 + private final String name;
  32 +
  33 + public static SmsChannelEnum getByCode(String code) {
  34 + return ArrayUtil.firstMatch(o -> o.getCode().equals(code), values());
  35 + }
  36 +
  37 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import cn.iocoder.dashboard.common.exception.ErrorCode;
  4 +
  5 +/**
  6 + * 短信框架的错误码枚举
  7 + *
  8 + * 短信框架,使用 2-001-000-000 段
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +public interface SmsFrameworkErrorCodeConstants {
  13 +
  14 + ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误,需要解析");
  15 +
  16 + // ========== 权限 / 限流等相关 2001000100 ==========
  17 +
  18 + ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限");
  19 + // 云片:可以配置 IP 白名单,只有在白名单中才可以发送短信
  20 + ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信");
  21 +
  22 + // 阿里云:将短信发送频率限制在正常的业务限流范围内。默认短信验证码:使用同一签名,对同一个手机号验证码,支持 1 条 / 分钟,5 条 / 小时,累计 10 条 / 天。
  23 + ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流");
  24 + // 阿里云:已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置,修改发送总量阈值。
  25 + ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流");
  26 +
  27 + ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词");
  28 +
  29 + // ========== 模板相关 2001000200 ==========
  30 + ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在
  31 + ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确");
  32 +
  33 + // ========== 签名相关 2001000300 ==========
  34 + ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用");
  35 +
  36 + // ========== 账户相关 2001000400 ==========
  37 + ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足");
  38 + ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在");
  39 +
  40 + // ========== 其它相关 2001000900 开头 ==========
  41 + ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失");
  42 + ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确");
  43 + ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中");
  44 +
  45 + ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常");
  46 +
  47 +}
... ...
src/main/java/cn/iocoder/dashboard/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.sms.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * 短信模板的审核状态枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@AllArgsConstructor
  12 +@Getter
  13 +public enum SmsTemplateAuditStatusEnum {
  14 +
  15 + CHECKING(1),
  16 + SUCCESS(2),
  17 + FAIL(3);
  18 +
  19 + private final Integer status;
  20 +
  21 +}
... ...