Commit 5a3e139e by 梁家彪

完善

parent b167f269
...@@ -43,8 +43,8 @@ public class DataCollectApiController { ...@@ -43,8 +43,8 @@ public class DataCollectApiController {
@ApiOperation("执行接口汇聚") @ApiOperation("执行接口汇聚")
@PostMapping(value = "/execute") @PostMapping(value = "/execute")
public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId, @RequestBody DataCollectApiExecuteReq dataCollectApiExecuteReq) { public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId, @RequestParam("collectType") Integer collectType, @RequestBody DataCollectApiExecuteReq dataCollectApiExecuteReq) {
dataCollectApiService.execute(dataCollectSettingId, dataCollectApiExecuteReq); dataCollectApiService.execute(dataCollectSettingId, collectType, dataCollectApiExecuteReq);
return ResultVo.success("汇聚执行成功"); return ResultVo.success("汇聚执行成功");
} }
} }
\ No newline at end of file
...@@ -41,8 +41,8 @@ public class DataCollectDbController { ...@@ -41,8 +41,8 @@ public class DataCollectDbController {
@ApiOperation("执行数据库汇聚") @ApiOperation("执行数据库汇聚")
@PostMapping(value = "/execute") @PostMapping(value = "/execute")
public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId) { public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId, @RequestParam("collectType") Integer collectType) {
dataCollectDbService.execute(dataCollectSettingId); dataCollectDbService.execute(dataCollectSettingId, collectType);
return ResultVo.success("汇聚执行成功"); return ResultVo.success("汇聚执行成功");
} }
} }
...@@ -48,8 +48,8 @@ public class DataCollectFileController { ...@@ -48,8 +48,8 @@ public class DataCollectFileController {
@ApiOperation("执行文件汇聚") @ApiOperation("执行文件汇聚")
@PostMapping(value = "/execute") @PostMapping(value = "/execute")
public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId, MultipartFile file) { public ResultVo executeDb(@RequestParam("dataCollectSettingId") Integer dataCollectSettingId, @RequestParam("collectType") Integer collectType, MultipartFile file) {
dataCollectFileService.execute(dataCollectSettingId, file); dataCollectFileService.execute(dataCollectSettingId, collectType, file);
return ResultVo.success("汇聚执行成功"); return ResultVo.success("汇聚执行成功");
} }
} }
\ No newline at end of file
...@@ -33,6 +33,12 @@ public class DataCollectLogController { ...@@ -33,6 +33,12 @@ public class DataCollectLogController {
return ResultVo.success(dataCollectLogService.getList(req)); return ResultVo.success(dataCollectLogService.getList(req));
} }
@ApiOperation("分页获取指定汇聚的日志")
@PostMapping(value = "/list/{id}")
public ResultVo getListById(@RequestBody DataCollectLogReq req, @PathVariable Integer id) {
return ResultVo.success(dataCollectLogService.getList(req, id));
}
@ApiOperation("删除数据汇聚日志") @ApiOperation("删除数据汇聚日志")
@DeleteMapping(value = "/delete/{id}") @DeleteMapping(value = "/delete/{id}")
public ResultVo delete(@PathVariable Integer id) { public ResultVo delete(@PathVariable Integer id) {
......
...@@ -91,14 +91,14 @@ public class DataCollectSetting { ...@@ -91,14 +91,14 @@ public class DataCollectSetting {
private Long deptId; private Long deptId;
/** /**
* createTime * createTime
*/ */
@TableField(fill = FieldFill.INSERT) @TableField(fill = FieldFill.INSERT)
private Date createTime; private Date createTime;
/** /**
* updateTime * updateTime
*/ */
@TableField(fill = FieldFill.INSERT_UPDATE) @TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime; private Date updateTime;
} }
\ No newline at end of file
...@@ -53,5 +53,5 @@ public class DataCollectSettingFile { ...@@ -53,5 +53,5 @@ public class DataCollectSettingFile {
* updateTime * updateTime
*/ */
@TableField(fill = FieldFill.INSERT_UPDATE) @TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;; private Date updateTime;
} }
\ No newline at end of file
...@@ -38,7 +38,7 @@ public class DatabaseRunner implements ApplicationRunner { ...@@ -38,7 +38,7 @@ public class DatabaseRunner implements ApplicationRunner {
switch (ds.getDbType()) { switch (ds.getDbType()) {
case 1: case 1:
className = "com.mysql.cj.jdbc.Driver"; className = "com.mysql.cj.jdbc.Driver";
url = "jdbc:mysql://" + ds.getDbIp() + ":" + ds.getDbPort() + "/" + ds.getDbName() + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true"; url = "jdbc:mysql://" + ds.getDbIp() + ":" + ds.getDbPort() + "/" + ds.getDbName() + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&autoReconnect=true";
break; break;
case 2: case 2:
className = "oracle.jdbc.driver.OracleDriver"; className = "oracle.jdbc.driver.OracleDriver";
......
...@@ -12,5 +12,5 @@ public interface DataCollectApiService { ...@@ -12,5 +12,5 @@ public interface DataCollectApiService {
void update(DataCollectApiAddReq dataCollectApiAddReq); void update(DataCollectApiAddReq dataCollectApiAddReq);
void execute(Integer dataCollectSettingId, DataCollectApiExecuteReq dataCollectApiExecuteReq); void execute(Integer dataCollectSettingId, Integer collectType, DataCollectApiExecuteReq dataCollectApiExecuteReq);
} }
\ No newline at end of file
...@@ -11,5 +11,5 @@ public interface DataCollectDbService { ...@@ -11,5 +11,5 @@ public interface DataCollectDbService {
void update(DataCollectDbAddReq dataCollectDbAddReq); void update(DataCollectDbAddReq dataCollectDbAddReq);
void execute(Integer dataCollectSettingId); void execute(Integer dataCollectSettingId, Integer collectType);
} }
...@@ -17,5 +17,5 @@ public interface DataCollectFileService { ...@@ -17,5 +17,5 @@ public interface DataCollectFileService {
Map<String, Object> analysisExcel(MultipartFile multipartFile); Map<String, Object> analysisExcel(MultipartFile multipartFile);
void execute(Integer dataCollectSettingId, MultipartFile file); void execute(Integer dataCollectSettingId, Integer collectType, MultipartFile file);
} }
\ No newline at end of file
...@@ -12,6 +12,8 @@ public interface DataCollectLogService { ...@@ -12,6 +12,8 @@ public interface DataCollectLogService {
PageVo getList(DataCollectLogReq req); PageVo getList(DataCollectLogReq req);
PageVo getList(DataCollectLogReq req, Integer id);
List<DataCollectFileLog> file(Integer id); List<DataCollectFileLog> file(Integer id);
boolean removeById(Integer id); boolean removeById(Integer id);
......
...@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; ...@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
...@@ -86,7 +87,7 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi ...@@ -86,7 +87,7 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi
@Override @Override
@Transactional @Transactional
public void execute(Integer dataCollectSettingId, DataCollectApiExecuteReq dataCollectApiExecuteReq) { public void execute(Integer dataCollectSettingId, Integer collectType, DataCollectApiExecuteReq dataCollectApiExecuteReq) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
DataCollectSettingApi settingApi = lambdaQuery().eq(DataCollectSettingApi::getDataCollectSettingId, dataCollectSettingId).one(); DataCollectSettingApi settingApi = lambdaQuery().eq(DataCollectSettingApi::getDataCollectSettingId, dataCollectSettingId).one();
List<DataCollectSettingApiPara> apiParas; List<DataCollectSettingApiPara> apiParas;
...@@ -106,12 +107,12 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi ...@@ -106,12 +107,12 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi
throw new BusinessException("不支持的请求类型"); throw new BusinessException("不支持的请求类型");
} }
if(StrUtil.isNotBlank(dataCollectApiExecuteReq.getHeaders())){ if(StrUtil.isNotBlank(dataCollectApiExecuteReq.getHeaders()) && JSONUtil.isJsonObj(dataCollectApiExecuteReq.getHeaders())){
for (Map.Entry<String, Object> entry : JSONObject.parseObject(dataCollectApiExecuteReq.getHeaders()).entrySet()) { for (Map.Entry<String, Object> entry : JSONObject.parseObject(dataCollectApiExecuteReq.getHeaders()).entrySet()) {
request.header(entry.getKey(), entry.getValue().toString()); request.header(entry.getKey(), entry.getValue().toString());
} }
} }
else if(StrUtil.isNotBlank(settingApi.getHeaders())){ else if(StrUtil.isNotBlank(settingApi.getHeaders()) && JSONUtil.isJsonObj(settingApi.getHeaders())){
for (Map.Entry<String, Object> entry : JSONObject.parseObject(settingApi.getHeaders()).entrySet()) { for (Map.Entry<String, Object> entry : JSONObject.parseObject(settingApi.getHeaders()).entrySet()) {
request.header(entry.getKey(), entry.getValue().toString()); request.header(entry.getKey(), entry.getValue().toString());
} }
...@@ -130,6 +131,9 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi ...@@ -130,6 +131,9 @@ public class DataCollectApiServiceImpl extends ServiceImpl<DataCollectSettingApi
JdbcTemplate toDbJdbcTemplate = DatabaseHolder.getJdbcTemplate(dataCollectSetting.getToDbId()); JdbcTemplate toDbJdbcTemplate = DatabaseHolder.getJdbcTemplate(dataCollectSetting.getToDbId());
Set<String> set = list.get(0).keySet(); Set<String> set = list.get(0).keySet();
set.remove("id"); set.remove("id");
if(collectType == 0){
toDbJdbcTemplate.execute("TRUNCATE TABLE " + dataCollectSetting.getToTable() + ";");
}
if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){ if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){
toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set)); toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set));
} }
......
...@@ -60,7 +60,7 @@ public class DataCollectDbServiceImpl extends ServiceImpl<DataCollectSettingDbMa ...@@ -60,7 +60,7 @@ public class DataCollectDbServiceImpl extends ServiceImpl<DataCollectSettingDbMa
@Override @Override
@Transactional @Transactional
public void execute(Integer dataCollectSettingId) { public void execute(Integer dataCollectSettingId, Integer collectType) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
DataCollectSetting dataCollectSetting = dataCollectMapper.selectById(dataCollectSettingId); DataCollectSetting dataCollectSetting = dataCollectMapper.selectById(dataCollectSettingId);
DataCollectSettingDb settingDb = getOne(new LambdaQueryWrapper<DataCollectSettingDb>().eq(DataCollectSettingDb::getDataCollectSettingId, dataCollectSettingId)); DataCollectSettingDb settingDb = getOne(new LambdaQueryWrapper<DataCollectSettingDb>().eq(DataCollectSettingDb::getDataCollectSettingId, dataCollectSettingId));
...@@ -69,6 +69,9 @@ public class DataCollectDbServiceImpl extends ServiceImpl<DataCollectSettingDbMa ...@@ -69,6 +69,9 @@ public class DataCollectDbServiceImpl extends ServiceImpl<DataCollectSettingDbMa
List<Map<String, Object>> list = fromDbJdbcTemplate.queryForList("SELECT * FROM " + settingDb.getFromTable()); List<Map<String, Object>> list = fromDbJdbcTemplate.queryForList("SELECT * FROM " + settingDb.getFromTable());
Set<String> set = list.get(0).keySet(); Set<String> set = list.get(0).keySet();
set.remove("id"); set.remove("id");
if(collectType == 0){
toDbJdbcTemplate.execute("TRUNCATE TABLE " + dataCollectSetting.getToTable() + ";");
}
if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){ if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){
toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set)); toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set));
} }
......
...@@ -67,7 +67,8 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi ...@@ -67,7 +67,8 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi
String suffix = FileUtil.extName(file.getOriginalFilename()); String suffix = FileUtil.extName(file.getOriginalFilename());
AssertUtils.isTrue(suffix.equals("xls") || suffix.equals("xlsx") || suffix.equals("et"), "不支持的文件类型"); AssertUtils.isTrue(suffix.equals("xls") || suffix.equals("xlsx") || suffix.equals("et"), "不支持的文件类型");
try { try {
return EasyExcelUtil.preview100(file.getInputStream()); Map<String, Object> map = EasyExcelUtil.preview100(file.getInputStream());
return map;
} catch (Exception e) { } catch (Exception e) {
throw new BusinessException("文件读取失败,请检查后重试"); throw new BusinessException("文件读取失败,请检查后重试");
} }
...@@ -75,7 +76,7 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi ...@@ -75,7 +76,7 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi
@Override @Override
@Transactional @Transactional
public void execute(Integer dataCollectSettingId, MultipartFile file) { public void execute(Integer dataCollectSettingId, Integer collectType, MultipartFile file) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
String suffix = FileUtil.extName(file.getOriginalFilename()); String suffix = FileUtil.extName(file.getOriginalFilename());
AssertUtils.isTrue(suffix.equals("xls") || suffix.equals("xlsx") || suffix.equals("et"), "不支持的文件类型"); AssertUtils.isTrue(suffix.equals("xls") || suffix.equals("xlsx") || suffix.equals("et"), "不支持的文件类型");
...@@ -85,6 +86,9 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi ...@@ -85,6 +86,9 @@ public class DataCollectFileServiceImpl extends ServiceImpl<DataCollectSettingFi
JdbcTemplate toDbJdbcTemplate = DatabaseHolder.getJdbcTemplate(dataCollectSetting.getToDbId()); JdbcTemplate toDbJdbcTemplate = DatabaseHolder.getJdbcTemplate(dataCollectSetting.getToDbId());
Set<String> set = list.get(0).keySet(); Set<String> set = list.get(0).keySet();
set.remove("id"); set.remove("id");
if(collectType == 0){
toDbJdbcTemplate.execute("TRUNCATE TABLE " + dataCollectSetting.getToTable() + ";");
}
if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){ if(dataCollectSetting.getCreateTable()==1 && toDbJdbcTemplate.queryForList("SHOW TABLES LIKE '"+ dataCollectSetting.getToTable() + "'").size()==0){
toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set)); toDbJdbcTemplate.execute(SqlUtil.joinCreateTableSql(dataCollectSetting.getToTable(), set));
} }
......
...@@ -52,6 +52,27 @@ public class DataCollectLogServiceImpl extends ServiceImpl<DataCollectTaskLogMap ...@@ -52,6 +52,27 @@ public class DataCollectLogServiceImpl extends ServiceImpl<DataCollectTaskLogMap
} }
@Override @Override
public PageVo getList(DataCollectLogReq req, Integer id) {
LambdaQueryWrapper<DataCollectTaskLog> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DataCollectTaskLog::getDataCollectSettingId, id);
PageVo pageVo = PagingUtils.paging(req, dataCollectTaskLogMapper, wrapper,DataCollectTaskLog.class);
List<DataCollectTaskLogResp> taskLogRespList = new ArrayList<>(pageVo.getRows().size());
for (Object row : pageVo.getRows()) {
DataCollectTaskLog dataCollectTaskLog = (DataCollectTaskLog) row;
DataCollectSetting dataCollectSetting = dataCollectServiceImpl.getById(dataCollectTaskLog.getDataCollectSettingId());
if(null == dataCollectSetting){
continue;
}
DataCollectTaskLogResp resp = new DataCollectTaskLogResp();
resp.setTaskName(dataCollectSetting.getTaskName());
BeanUtil.copyProperties(dataCollectTaskLog, resp);
taskLogRespList.add(resp);
}
pageVo.setRows(taskLogRespList);
return pageVo;
}
@Override
public List<DataCollectFileLog> file(Integer id){ public List<DataCollectFileLog> file(Integer id){
return dataCollectFileLogMapper.selectList(new LambdaQueryWrapper<DataCollectFileLog>().eq(DataCollectFileLog::getDataCollectSettingFileId, id)); return dataCollectFileLogMapper.selectList(new LambdaQueryWrapper<DataCollectFileLog>().eq(DataCollectFileLog::getDataCollectSettingFileId, id));
} }
......
...@@ -43,6 +43,9 @@ public class DataCollectServiceImpl extends ServiceImpl<DataCollectMapper, DataC ...@@ -43,6 +43,9 @@ public class DataCollectServiceImpl extends ServiceImpl<DataCollectMapper, DataC
@Resource @Resource
private DataCollectSettingApiParaMapper dataCollectSettingApiParaMapper; private DataCollectSettingApiParaMapper dataCollectSettingApiParaMapper;
@Resource
private DataCollectTaskLogMapper dataCollectTaskLogMapper;
@Override @Override
public PageVo<DataCollectSetting> list(DataCollectReq req) { public PageVo<DataCollectSetting> list(DataCollectReq req) {
return PagingUtils.paging(req, dataCollectMapper, new LambdaQueryWrapper<DataCollectSetting>().orderByDesc(DataCollectSetting::getId), DataCollectSetting.class); return PagingUtils.paging(req, dataCollectMapper, new LambdaQueryWrapper<DataCollectSetting>().orderByDesc(DataCollectSetting::getId), DataCollectSetting.class);
...@@ -64,26 +67,29 @@ public class DataCollectServiceImpl extends ServiceImpl<DataCollectMapper, DataC ...@@ -64,26 +67,29 @@ public class DataCollectServiceImpl extends ServiceImpl<DataCollectMapper, DataC
@Override @Override
@Transactional @Transactional
public void delete(Integer id){ public void delete(Integer id) {
DataCollectSetting dataCollectSetting = getById(id); DataCollectSetting dataCollectSetting = getById(id);
UpdateWrapper wrapper = new UpdateWrapper(); UpdateWrapper wrapper = new UpdateWrapper();
wrapper.eq("data_collect_setting_id", dataCollectSetting.getId()); wrapper.eq("data_collect_setting_id", dataCollectSetting.getId());
getDao(dataCollectSetting.getDataType()).delete(wrapper); getDao(dataCollectSetting.getDataType()).delete(wrapper);
if(dataCollectSetting.getDataType()==3){ if (dataCollectSetting.getDataType() == 2) {
dataCollectSettingFileMapper.delete(wrapper);
} else if (dataCollectSetting.getDataType() == 3) {
dataCollectSettingApiParaMapper.delete(wrapper); dataCollectSettingApiParaMapper.delete(wrapper);
} }
dataCollectTaskLogMapper.delete(wrapper);
AssertUtils.isTrue(removeById(id), "删除失败"); AssertUtils.isTrue(removeById(id), "删除失败");
} }
@Override @Override
@Transactional @Transactional
public void batchDelete(List<Integer> ids){ public void batchDelete(List<Integer> ids) {
for (Integer id : ids) { for (Integer id : ids) {
delete(id); delete(id);
} }
} }
public BaseMapper getDao(int dataType){ public BaseMapper getDao(int dataType) {
switch (dataType) { switch (dataType) {
case 1: case 1:
return dataCollectSettingDbMapper; return dataCollectSettingDbMapper;
......
...@@ -7,7 +7,7 @@ public class SqlUtil { ...@@ -7,7 +7,7 @@ public class SqlUtil {
public static String jointInsertSql(String tableName, Set<String> cloums){ public static String jointInsertSql(String tableName, Set<String> cloums){
StringBuilder fileds = new StringBuilder(); StringBuilder fileds = new StringBuilder();
for (String cloum : cloums) { for (String cloum : cloums) {
fileds.append(cloum.replaceAll("\\p{Punct}", "")).append(","); fileds.append(cloum.replaceAll("\\p{Punct}", "").replaceAll("(", "").replaceAll(")", "").replaceAll("\r", "").replaceAll("\n", "")).append(",");
} }
fileds.deleteCharAt(fileds.length()-1); fileds.deleteCharAt(fileds.length()-1);
StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(fileds).append(") VALUES ("); StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(fileds).append(") VALUES (");
...@@ -25,7 +25,7 @@ public class SqlUtil { ...@@ -25,7 +25,7 @@ public class SqlUtil {
public static String joinCreateTableSql(String tableName, Set<String> cloums){ public static String joinCreateTableSql(String tableName, Set<String> cloums){
StringBuilder sql = new StringBuilder("CREATE TABLE ").append(tableName).append("("); StringBuilder sql = new StringBuilder("CREATE TABLE ").append(tableName).append("(");
for (String cloum : cloums) { for (String cloum : cloums) {
sql.append(cloum.replaceAll("\\p{Punct}", "")).append(" VARCHAR(255),"); sql.append(cloum.replaceAll("\\p{Punct}", "").replaceAll("(", "").replaceAll(")", "").replaceAll("\r", "").replaceAll("\n", "")).append(" TEXT,");
} }
sql.deleteCharAt(sql.length()-1).append(")"); sql.deleteCharAt(sql.length()-1).append(")");
return sql.toString(); return sql.toString();
......
...@@ -22,7 +22,7 @@ public class DatabaseHolder { ...@@ -22,7 +22,7 @@ public class DatabaseHolder {
switch (dbType) { switch (dbType) {
case 1: case 1:
className = "com.mysql.cj.jdbc.Driver"; className = "com.mysql.cj.jdbc.Driver";
url = "jdbc:mysql://" + dbIp + ":" + dbPort + "/" + dbName + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true"; url = "jdbc:mysql://" + dbIp + ":" + dbPort + "/" + dbName + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&autoReconnect=true";
break; break;
case 2: case 2:
className = "oracle.jdbc.driver.OracleDriver"; className = "oracle.jdbc.driver.OracleDriver";
......
...@@ -6,6 +6,7 @@ import cn.hutool.json.JSONUtil; ...@@ -6,6 +6,7 @@ import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zq.common.context.ThreadContext; import com.zq.common.context.ThreadContext;
import com.zq.common.exception.BusinessException;
import com.zq.common.utils.AssertUtils;; import com.zq.common.utils.AssertUtils;;
import com.zq.common.vo.PageVo; import com.zq.common.vo.PageVo;
import com.zq.common.vo.ResultVo; import com.zq.common.vo.ResultVo;
...@@ -49,6 +50,7 @@ public class CommonQueryService extends ServiceImpl<CommonQuerySettingDao, Commo ...@@ -49,6 +50,7 @@ public class CommonQueryService extends ServiceImpl<CommonQuerySettingDao, Commo
} }
public ResultVo addDatasource(QueryDb queryDb) { public ResultVo addDatasource(QueryDb queryDb) {
queryDb.setCreateTime(DateUtil.date());
AssertUtils.isTrue(queryDbDao.insert(queryDb) == 1, "添加失败,请检查后重试"); AssertUtils.isTrue(queryDbDao.insert(queryDb) == 1, "添加失败,请检查后重试");
DatabaseHolder.add(queryDb.getDbType(), queryDb.getDbIp(), queryDb.getDbPort(), queryDb.getDbName(), queryDb.getUsername(), queryDb.getPassword(), queryDb.getId()); DatabaseHolder.add(queryDb.getDbType(), queryDb.getDbIp(), queryDb.getDbPort(), queryDb.getDbName(), queryDb.getUsername(), queryDb.getPassword(), queryDb.getId());
return ResultVo.success(); return ResultVo.success();
...@@ -93,14 +95,22 @@ public class CommonQueryService extends ServiceImpl<CommonQuerySettingDao, Commo ...@@ -93,14 +95,22 @@ public class CommonQueryService extends ServiceImpl<CommonQuerySettingDao, Commo
} }
public Object checkConnect(QueryDb queryDb) { public Object checkConnect(QueryDb queryDb) {
QueryDb queryDb1 = queryDbDao.selectById(queryDb.getId()); String url = null;
String jdbcUrl = queryDb1.getDbIp(); switch (queryDb.getDbType()) {
try { case 1:
return SqlUtils.testConnection(jdbcUrl, queryDb1.getUsername(), queryDb1.getPassword()); url = "jdbc:mysql://" + queryDb.getDbIp() + ":" + queryDb.getDbPort() + "/" + queryDb.getDbName() + "?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true";
} catch (Exception e) { break;
log.error(e.getMessage()); case 2:
return false; url = "jdbc:oracle:thin:@//" + queryDb.getDbIp() + ":" + queryDb.getDbPort() + "/" + queryDb.getDbName();
break;
case 3:
url = "jdbc:sqlserver://" + queryDb.getDbIp() + ":" + queryDb.getDbPort() + "/" + queryDb.getDbName();
break;
default:
throw new BusinessException("不支持的数据库");
} }
AssertUtils.isTrue(SqlUtils.testConnection(url, queryDb.getUsername(), queryDb.getPassword()), "连接失败");
return true;
} }
public List<Map<String, Object>> runSelect(Map<String, Object> body) throws Exception { public List<Map<String, Object>> runSelect(Map<String, Object> body) throws Exception {
......
package com.zq.spiderflow.datacollision.executor; package com.zq.spiderflow.datacollision.executor;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zq.common.exception.BusinessException; import com.zq.common.exception.BusinessException;
import com.zq.spiderflow.context.SpiderContext; import com.zq.spiderflow.context.SpiderContext;
import com.zq.spiderflow.executor.ShapeExecutor; import com.zq.spiderflow.executor.ShapeExecutor;
...@@ -10,17 +14,13 @@ import com.zq.spiderflow.model.SpiderNode; ...@@ -10,17 +14,13 @@ import com.zq.spiderflow.model.SpiderNode;
import com.zq.spiderflow.model.SpiderOutput; import com.zq.spiderflow.model.SpiderOutput;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
@Component @Component
public class DataCollisionExecutor implements ShapeExecutor { public class DataCollisionExecutor implements ShapeExecutor {
public static final String TABLE1 = "table1";
public static final String FIELD1 = "field1"; public static final String COLLISION = "collision";
public static final String TABLE2 = "table2";
public static final String FIELD2 = "field2";
public static final String RESERVE = "reserve"; public static final String RESERVE = "reserve";
@Override @Override
...@@ -40,53 +40,60 @@ public class DataCollisionExecutor implements ShapeExecutor { ...@@ -40,53 +40,60 @@ public class DataCollisionExecutor implements ShapeExecutor {
@Override @Override
public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception { public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception {
String table1 = null; JSONArray collisionArray = JSONUtil.parseArray(node.getStringJsonValue(COLLISION));
String table2 = null; LinkedHashSet<Map<String, Object>> results = new LinkedHashSet<>();
String field1 = null;
String field2 = null;
try {
table1 = node.getStringJsonValue(TABLE1);
table2 = node.getStringJsonValue(TABLE2);
field1 = node.getStringJsonValue(FIELD1);
field2 = node.getStringJsonValue(FIELD2);
}catch (Exception e){
throw new BusinessException("不是字符串");
}
if(StrUtil.isBlank(table1)){ for (Object o : collisionArray) {
throw new BusinessException("没有表1"); JSONObject jsonObject = JSONUtil.parseObj(o);
} String table1 = jsonObject.getStr("table1");
if(StrUtil.isBlank(table2)){ String field1 = jsonObject.getStr("field1");
throw new BusinessException("没有表2"); String condition = jsonObject.getStr("condition");
} String table2 = jsonObject.getStr("table2");
if(StrUtil.isBlank(field1)){ String field2 = jsonObject.getStr("field2");
throw new BusinessException("没有字段1"); String logic = jsonObject.getStr("logic", "2");
}
if(StrUtil.isBlank(field2)){
throw new BusinessException("没有字段2");
}
List<Map<String, Object>> list1 = (List<Map<String, Object>>) variables.get(table1); List<Map<String, Object>> list1 = (List<Map<String, Object>>) variables.get(table1);
List<Map<String, Object>> list2 = (List<Map<String, Object>>) variables.get(table2); List<Map<String, Object>> list2 = (List<Map<String, Object>>) variables.get(table2);
Set<Map<String, Object>> temp = new HashSet<>();
if(list1==null){ for (Map<String, Object> map1 : list1) {
throw new BusinessException("表1没有数据"); String field1Str = map1.get(field1).toString();
} for (Map<String, Object> map2 : list2) {
if(list2==null){ String field2Str = map2.get(field2).toString();
throw new BusinessException("表2没有数据"); switch (condition) {
} case "1":
if(field1Str.equals(field2Str)){
List<Map<String, Object>> results = new ArrayList<>(); map1.putAll(map2);
for (Map<String, Object> map1 : list1) { temp.add(map1);
String field1Str = map1.get(field1).toString(); }
for (Map<String, Object> map2 : list2) { break;
String field2Str = map2.get(field2).toString(); case "2":
if(field1Str.equals(field2Str)){ if(!field1Str.equals(field2Str)){
map1.putAll(map2); map1.putAll(map2);
results.add(map1); temp.add(map1);
break; }
break;
case "3":
if(field1Str.contains(field2Str)){
map1.putAll(map2);
temp.add(map1);
}
break;
case "4":
if(!field1Str.contains(field2Str)){
map1.putAll(map2);
temp.add(map1);
}
break;
}
} }
} }
if(logic.equals("1")){
results.retainAll(temp);
}else {
results.addAll(temp);
}
} }
variables.put(node.getNodeId() + "_" + node.getNodeName(), results); variables.put(node.getNodeId() + "_" + node.getNodeName(), results);
......
package com.zq.spiderflow.excelremoveduplicate.executor; //package com.zq.spiderflow.excelremoveduplicate.executor;
//
import com.zq.spiderflow.context.SpiderContext; //import com.zq.spiderflow.context.SpiderContext;
import com.zq.spiderflow.executor.ShapeExecutor; //import com.zq.spiderflow.executor.ShapeExecutor;
import com.zq.spiderflow.model.Shape; //import com.zq.spiderflow.model.Shape;
import com.zq.spiderflow.model.SpiderNode; //import com.zq.spiderflow.model.SpiderNode;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
//
import java.util.Map; //import java.util.Map;
//
@Component //@Component
public class ExcelRemoveDuplicateExecutor implements ShapeExecutor { //public class ExcelRemoveDuplicateExecutor implements ShapeExecutor {
//
public static final String TABLE1 = "table1"; // public static final String TABLE1 = "table1";
public static final String FIELD1 = "field1"; // public static final String FIELD1 = "field1";
public static final String TABLE2 = "table2"; // public static final String TABLE2 = "table2";
public static final String FIELD2 = "field2"; // public static final String FIELD2 = "field2";
public static final String RESERVE = "reserve"; // public static final String RESERVE = "reserve";
//
@Override // @Override
public Shape shape() { // public Shape shape() {
Shape shape = new Shape(); // Shape shape = new Shape();
shape.setImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjsAAAIACAYAAABka601AAAAAXNSR0IArs4c6QAAIABJREFUeF7tnQu0HFWV/r/dNwkg4SGSdN0bUBRQfKCg4hMUdAQRREDHJwqCgAyS7g4CijIG8QWBdHcCjChPH6joyENGBxkF8Y2o+Po7CuiMQG51YBQUFUhu7/+qvjeYhNzc6j67qk+d+notlmjO+c7ev71xf3RVVwky+lTb+vKK4mUQzFfFfABVoPefyV+bZ3QsZUmABEiABEiABPwm8DCATu8vRUcEcfL3qrg+bsiNWYQulqLVlh5UUbxaBQcCiCy1qUUCJEACJEACJBA8gXsAfFEFX+/OwjfuOV4esMjY2exs29TRWcCxEBwGYEeLoKhBAiRAAiRAAiRQegL3qOLKSgWfGK/Jj11oDGx2HjE5FRwNxZhLENxLAiRAAiRAAiRAAtMRUMUnXExP/2bnAp0d/Q3vA00Ou5IESIAESIAESCBHAonpgeLcziL5RT/H9mV2et/mCC4E8Kp+DuFaEiABEiABEiABEjAicKd2cXxnkXwlrV5qs1Nt6zNEkQjvkFac60iABEiABEiABEggEwKCI+OaXJJGO5XZiZq6NwQ3pBHkGhIgARIgARIgARLIg4AoGuMNac101oxmJ2rqYgg+MJMQ/5wESIAESIAESIAEciegOD1uyOKNnbtRsxM19QgIUn1FlHtyPJAESIAESIAESIAEACjwmk5drpkOxrRmh5eu2D8kQAIkQAIkQAKFIaDYZ7onMG/Q7ERN3UEF3xFgQWGSZKAkQAIkQAIkQALlJtDF8+NFcvP6EDZsdlr6nwD2KzcxZk8CJEACJEACJFAoAorfQnFovEh+tXbcjzI71ZYuFKBdqOQYLAmQAAmQAAmQAAkk9+8oPtFpyLHTmp2xs3Xb7iz8gO+4Yr+QAAmQAAmQAAkUlYAInrv2+7TW+WYnauoHITitqMkxbhIgARIgARIgARJY/9udR8zO2HLdpTvR+1ZnK2IiARIgARIgARIggSITWPvbnUfMTtTW86E4rsiJMXYSIAESIAESIAESSAis/e1Oz+zMO0/njqzC75K/JSISIAESIAESIAESCIDAHx+u4Il/XCh/7pmdaltfI4qrnBPTmRVUEAO4d+aVXEECJEACJEACJBAcAcVmAuw4Y14zvtBqRgWI4rDxhny2JxW19DwA/zLzthlWJGbHIDjnOChAAiRAAiRAAiRQegIq+GynJoetMTsrTS5h0eyUvrEIgARIgARIgAQ8IvDHuC6PE9N3YNHseFRfhkICJEACJEACJFAB9pXRln5YgVNNcNDsmGCkCAmQAAmQAAmQgA0BAT6SmJ0LFTjKRJJmxwQjRUiABEiABEiABGwICHBRchnrWggOMJGk2THBSBESIAESIAESIAEjAor/kKilPwLwXBNJmh0TjBQhARIgARIgARIwI3BLYnb+AGB7E0maHROMFCEBEiABEiCBMhNQoCNA1YjBnYnZeQjAHAtBVdwhkuJBQRaHUYMESIAESIAESCBMAopvQvAyo+QeTsxOiucepztOgV8K8Ix0q7mKBEiABEiABEiABB5NQBXXiOAgKzY0O1YkqUMCJEACJEACJGBCgGbHBCNFSIAESIAESIAEfCVAs+NrZRgXCZAACZAACZCACQGaHROMFCEBEiABEiABEvCVAM2Or5VhXCRAAiRAAiRAAiYEaHZMMFKEBEiABEiABEjAVwI0O75WhnGRAAmQAAmQAAmYEKDZMcFIERIgARIgARIgAV8J0Oz4WhnGRQIkQAIkQAIkYEKAZscEI0VIgARIgARIgAR8JUCz42tlGBcJkAAJkAAJkIAJAZodE4wUIQESIAESIAES8JUAzY6vlWFcJEACJEACJEACJgRodkwwUoQESIAESIAESMBXAjQ7vlaGcZEACZAACZAACZgQoNkxwUgREiABEiABEiABXwnQ7PhaGcZFAiRAAiRAAiRgQoBmxwQjRUiABEiABEiABHwlQLPja2UYFwmQAAmQAAmQgAkBmh0TjBQhARIgARIgARLwlQDNjq+VYVwkQAIkQAIkQAImBGh2TDBShARIgARIgARIwFcCNDu+VoZxkQAJkAAJkAAJmBCg2THBSBESIAESIAESIAFfCdDs+FoZxkUCJEACJEACJGBCgGbHBCNFSIAESIAESIAEfCVAs+NrZRgXCZAACZAACZCACQGaHROMFCEBEiABEiABEvCVAM2Or5VhXCRAAiRAAiRAAiYEaHZMMFKEBEiABEiABEjAVwI0O75WhnGRAAmQAAmQAAmYEKDZMcFIERIgARIgARIgAV8J0Oz4WhnGRQIkQAIkQAIkYEKAZscEI0VIgARIgARIgAR8JUCz42tlGBcJkAAJkAAJkIAJAZodE4wUIQESIAESIAES8JUAzY6vlWFcJEACJEACJEACJgRodkwwUoQESIAESIAESMBXAjQ7vlaGcZEACZAACZAACZgQoNkxwUgREiABEiABEiABXwnQ7PhaGcZFAiRAAiRAAiRgQoBmxwQjRUiABEiABEiABHwlQLPja2UYFwmQAAmQAAmQgAkBmh0TjBQhARIgARIgARLwlQDNjq+VYVwkQAIkQAIkQAImBGh2TDBShARIgARIgARIwFcCNDu+VoZxkQAJkAAJkAAJmBCg2THBSBESIAESIAESIAFfCdDs+FoZxkUCJEACJEACJGBCgGbHBCNFSIAESIAESIAEfCVAs+NrZRgXCZAACZAACZCACQGaHROMFCEBEiABEiABEvCVAM2Or5VhXCRAAiRAAiRAAiYEaHZMMFKEBEiABEiABEjAVwI0O75WhnGRAAmQAAmQAAmYEKDZMcFIERIgARIgARIgAV8J0Oz4WhnGRQIkQAIkQAIkYEKAZscEI0VIgARIgARIgAR8JUCz42tlGBcJkAAJkAAJkIAJAZodE4wUIQESIAESIAES8JUAzY6vlWFcJEACJEACJEACJgRodkwwUoQESIAESIAESMBXAjQ7vlaGcZEACZAACZAACZgQoNkxwUgREiABEiABEiABXwnQ7PhaGcZFAiRAAiRAAiRgQoBmxwQjRUiABEiABEiABHwlQLPja2UYFwmQAAmQAAmQgAkBmh0TjBQhARIgARIgARLwlYDvZuf3UNwBgfYAKuQRkMn/tv5/39CarPYlumljWDtOy30b0tpQp60fp8u+9fUH0BbgsZj8y+yjwO+mFRsgxp7WhvYZ5D+ttuV5w+7NNP/MzvDPQu59YtaNFMqTgABPMj7vTwr8yViTckMmIMD2EDzFKgyJWjppTAw+CtwqwG4GUpQgARIgARIgARIoKwHFtyB4qVX6NDtWJKlDAiRAAiRAAiRgQ4Bmx4YjVUiABEiABEiABDwlQLPjaWEYFgmQAAmQAAmQgA0Bmh0bjlQhARIgARIgARLwlADNjqeFYVgkQAIkQAIkQAI2BGh2bDhShQRIgARIgARIwFMCNDueFoZhkQAJkAAJkAAJ2BCg2bHhSBUSIAESIAESIAFPCdDseFoYhkUCJEACJEACJGBDgGbHhiNVSIAESIAESIAEPCVAs+NpYRgWCZAACZAACZCADQGaHRuOVCEBEiABEiABEvCUAM2Op4VhWCRAAiRAAiRAAjYEaHZsOFKFBEiABEiABEjAUwI0O54WhmGRAAmQAAmQAAnYEKDZseFIFRIgARIgARIgAU8J0Ox4WhiGRQIkQAIkQAIkYEOAZseGI1VIgARIgARIgAQ8JeC92VE0PEXHsAYkoMBuImgOuP3R2xSXAbjUTI9CXhBgn3hRBv+DEBwO4AirQFXREOBWKz3qeEPgCEz2islHopaqidKkyI1xXfYx1KOUBwSipu4NwQ1moShOjxuy2EyPQl4QYJ94UQbvg4iauhiCD5gFqtgnbsiNZnoU8oKAdZ/Q7HhRVr+D4BDzuz6+RMc+8aUSfscRtfUDUNj9yw7Njt8FHzA6mp0BwXHb4AQ4xAZnV6ad7JMyVXvwXGl2BmdXpp00O2Wqtie5coh5UgjPw2CfeF4gT8KzHmLgNzueVNY2DOs+4WUs2/oEqcYhFmRZzZNin5gjDVLQeojR7ATZJrDuE5qdMPvENCsOMVOcwYqxT4ItrWlivIxlijNYMZqdYEvrb2IcYv7WxqfI2Cc+VcPfWKyHGL/Z8bfWLpFZ9wm/2XGpRkn2coiVpNCOabJPHAGWZLv1EKPZCbNxrPuEZifMPjHNikPMFGewYuyTYEtrmhgvY5niDFaMZifY0vqbGIeYv7XxKTL2iU/V8DcW6yHGb3b8rbVLZNZ9wm92XKpRkr0cYiUptGOa7BNHgCXZbj3EaHbCbBzrPqHZCbNPTLPiEDPFGawY+yTY0pomxstYpjiDFaPZCba0/ibGIeZvbXyKjH3iUzX8jcV6iPGbHX9r7RKZdZ/wmx2XapRkL4dYSQrtmCb7xBFgSbZbDzGanTAbx7pPaHbC7BPTrDjETHEGK8Y+Cba0ponxMpYpzmDFaHaCLa2/iXGI+VsbnyJjn/hUDX9jodnxtzY+RUaz41M1ShILh1hJCu2YJvvEEWBJtlsPMV7GCrNxrPuEl7HC7BPTrDjETHEGK8Y+Cba0ponxmx1TnMGK0ewEW1p/E+MQ87c2PkXGPvGpGv7GQrPjb218ioxmx6dqlCQWDrGSFNoxTfaJI8CSbKfZKUmhHdOk2XEEyO39E+AQ659ZGXewT8pY9f5zth5ivGen/xoUYYd1n/CenSJUfcgxcogNuQAFOZ59UpBCDTlMfrMz5AIU5HianYIUKqQwOcRCqmZ2ubBPsmMbkjLNTkjVzC4Xmp3s2FJ5GgIcYmyNNATYJ2kocY31EONlrDB7yrpPeBkrzD4xzYpDzBRnsGLsk2BLa5qY9RCj2TEtjzdi1n1Cs+NNaf0NhEPM39r4FBn7xKdq+BsLL2P5WxufIqPZ8akaJYmFQ6wkhXZMk33iCLAk262HGL/ZCbNxrPuE3+yE2SemWXGImeIMVox9EmxpTROzHmI0O6bl8UbMuk9odrwprb+BcIj5WxufImOf+FQNf2PhZSx/a+NTZDQ7PlWjJLFwiJWk0I5psk8cAZZku/UQ4zc7YTaOdZ/wm50w+8Q0Kw4xU5zBirFPgi2taWLWQ4xmx7Q83ohZ9wnNjjel9TcQDjF/a+NTZOwTn6rhbyy8jOVvbXyKjGbHp2qUJBYOsZIU2jFN9okjwJJstx5i/GYnzMax7hN+sxNmn5hmxSFmijNYMfZJsKU1Tcx6iNHsmJbHGzHrPqHZ8aa0/gbCIeZvbXyKjH3iUzX8jYWXsfytjU+R0ez4VI2SxMIhVpJCO6bJPnEEWJLt1kOM3+yE2TjWfcJvdsLsE9OsOMRMcQYrxj4JtrSmiVkPMZod0/J4I2bdJzQ73pTW30A4xPytjU+RsU98qoa/sfAylr+18Skymh2fqlGSWDjESlJoxzTZJ44AS7KdZqckhXZMk2bHESC390+AQ6x/ZmXcwT4pY9X7z9l6iPEyVv81KMIO6z7hZawiVH3IMXKIDbkABTmefVKQQg05TH6zM+QCFOR4mp2CFCqkMDnEQqpmdrmwT7JjG5IyzU5I1cwuF5qd7NhSeRoCHGJsjTQE2CdpKHGN9RDjZawwe8q6T3gZK8w+Mc2KQ8wUZ7Bi7JNgS2uaGL/ZMcUZrBjNTrCl9TcxDjF/a+NTZOwTn6rhbyw0O/7WxqfIaHZ8qkZJYuEQK0mhHdNknzgCLMl26yHGy1hhNo51n/AyVph9YpoVh5gpzmDF2CfBltY0MeshRrNjWh5vxKz7hGbHm9L6GwiHmL+18Sky9olP1fA3Fl7G8rc2PkVGs+NTNUoSC4dYSQrtmCb7xBFgSbZbDzF+sxNm41j3Cb/ZCbNPTLPiEDPFGawY+yTY0pomZj3EaHZMy+ONmHWf0Ox4U1p/A+EQ87c2PkXGPvGpGv7GwstY/tbGp8hodnyqRkli4RArSaEd02SfOAIsyXaanZIU2jFNmh1HgNzePwEOsf6ZlXEH+6SMVe8/Z+shxstY/degCDus+4SXsYpQ9SHHyCE25AIU5Hj2SUEKNeQw+c3OkAtQkONpdgpSqJDC5BALqZrZ5cI+yY5tSMo0OyFVM7tcaHayY0vlaQhwiLE10hBgn6ShxDXWQ4yXscLsKes+4WWsMPvENCsOMVOcwYqxT4ItrWli/GbHFGewYjQ7wZbW38Q4xPytjU+RsU98qoa/sdDs+FsbnyKj2fGpGiWJhUOsJIV2TJN94giwJNuthxgvY4XZONZ9wstYYfaJaVYcYqY4gxVjnwRbWtPErIcYzY5pebwRs+4Tmh1vSutvIBxi/tbGp8jYJz5Vw99YrIcYzY6/tXaJzLpPaHZcqlGSvRxiJSm0Y5rsE0eAJdluPcRodsJsHOs+odkJs09Ms+IQM8UZrBj7JNjSmiZmPcRodkzL442YdZ/Q7HhTWn8D4RDztzY+RcY+8aka/sZiPcRodvyttUtk1n1Cs+NSjZLs5RArSaEd02SfOAIsyXbrIUazE2bjWPcJzU6YfWKaFYeYKc5gxdgnwZbWNDHrIUazY1oeb8Ss+4Rmx5vS+hsIh5i/tfEpMvaJT9XwNxbrIUaz42+tXSKz7hOaHZdqlGQvh1hJCu2YJvvEEWBJtlsPMZqdMBvHuk9odsLsE9OsOMRMcQYrxj4JtrSmiVkPMZod0/J4I2bdJzQ73pTW30A4xPytjU+RsU98qoa/sVgPMZodf2vtEpl1n9DsuFSjJHs5xEpSaMc02SeOAEuy3XqI0eyE2TjWfUKzE2afmGbFIWaKM1gx9kmwpTVNzHqI0eyYlscbMes+odnxprT+BsIh5m9tfIqMfeJTNfyNxXqI0ez4W2uXyKz7hGbHpRol2cshVpJCO6bJPnEEWJLt1kOMZifMxrHuE5qdMPvENCsOMVOcwYqxT4ItrWli1kOMZse0PN6IWfcJzY43pfU3EA4xf2vjU2TsE5+q4W8s1kOMZsffWrtEZt0nNDsu1SjJXg6xkhTaMU32iSPAkmy3HmI0O2E2jnWf0OyE2SemWXGImeIMVox9EmxpTROzHmI0O6bl8UbMuk9MzY4Ctwqwmze0GAgJkAAJkAAJkEDxCCi+BcFLrQKn2bEiSR0SIAESIAESIAEbAjQ7NhypQgIkQAIkQAIk4CkBmh1PC8OwSIAESIAESIAEbAjQ7NhwpAoJkAAJkAAJkICnBGh2PC0MwyIBEiABEiABErAhQLNjw5EqJEACJEACJEACnhKg2fG0MAyLBEiABEiABEjAhgDNjg1HqpAACZAACZAACXhKgGbH08IwLBIgARIgARIgARsCNDs2HKlCAiRAAiRAAiTgKQGaHU8Lw7BIgARIgARIgARsCNDs2HCkCgmQAAmQAAmQgKcEaHY8LQzDIgESIAESIAESsCFAs2PDkSokQAIkQAIkQAKeEqDZ8bQwDIsESIAESIAESMCGAM2ODUeqkAAJkAAJkAAJeEqAZsfTwjAsEiABEiABEiABGwI0OzYcqUICJEACJEACJOApAe/NjuJqT9ExrMEJ7ADB4YNvX29n0sTAjWZ6FPKFgG2fJD0y2SuP/lSg6EIG+rNk06B7B903jDOnizWJxYXfxnQ31on/OHNvCF5q2LSXQvG/fffCTAEMl9HMPb+x+NbfPWgu/ej0szZd7KZ9IlFLdaaa9/HnN8Z12aeP9VxaAAJRU5Omu8EsVMXpcUMWm+lRyAsC7BMvyuB9EFFTF0PwAbNAFfvEDeG/PJkB9UPIuk9odvyoq9dRcIh5XR5vgmOfeFMKrwOxHmKg2fG63oMGZ90nNDuDVqJE+zjESlRsh1TZJw7wSrTVeojR7ITZPNZ9QrMTZp+YZsUhZoozWDH2SbClNU3MeojR7JiWxxsx6z6h2fGmtP4GwiHmb218iox94lM1/I3FeojR7Phba5fIrPuEZselGiXZyyFWkkI7psk+cQRYku3WQ4xmJ8zGse4Tmp0w+8Q0Kw4xU5zBirFPgi2taWLWQ4xmx7Q83ohZ9wnNjjel9TcQDjF/a+NTZOwTn6rhbyzWQ4xmx99au0Rm3Sc0Oy7VKMleDrGSFNoxTfaJI8CSbLceYjQ7YTaOdZ/Q7ITZJ6ZZcYiZ4gxWjH0SbGlNE7MeYjQ7puXxRsy6T2h2vCmtv4FwiPlbG58iY5/4VA1/Y7EeYjQ7/tbaJTLrPqHZcalGSfZyiJWk0I5psk8cAZZku/UQo9kJs3Gs+4RmJ8w+Mc2KQ8wUZ7Bi7JNgS2uamPUQo9kxLY83YtZ9QrPjTWn9DYRDzN/a+BQZ+8Snavgbi/UQo9nxt9YukVn3Cc2OSzVKspdDrCSFdkyTfeIIsCTbrYcYzU6YjWPdJzQ7YfaJaVYcYqY4gxVjnwRbWtPErIcYzY5pebwRs+4Tmh1vSutvIBxi/tbGp8jYJz5Vw99YrIcYzY6/tXaJzLpPaHZcqlGSvRxiJSm0Y5rsE0eAJdluPcRodsJsHOs+odkJs09Ms+IQM8UZrBj7JNjSmiZmPcRodkzL442YdZ/Q7HhTWn8D4RDztzY+RcY+8aka/sZiPcRodvyttUtk1n1Cs+NSjZLs5RArSaEd02SfOAIsyXbrIUazE2bjWPcJzU6YfWKaFYeYKc5gxdgnwZbWNDHrIUazY1oeb8Ss+4Rmx5vS+hsIh5i/tfEpMvaJT9XwNxbrIUaz42+tXSKz7hOaHZdqlGQvh1hJCu2YJvvEEWBJtlsPMZqdMBvHuk9odsLsE9OsOMRMcQYrxj4JtrSmiVkPMZod0/J4I2bdJzQ73pTW30A4xPytjU+RsU98qoa/sVgPMZodf2vtEpl1n9DsuFSjJHs5xEpSaMc02SeOAEuy3XqI0eyE2TjWfUKzE2afmGbFIWaKM1gx9kmwpTVNzHqI0eyYlscbMes+odnxprT+BsIh5m9tfIqMfeJTNfyNxXqI0ez4W2uXyKz7hGbHpRol2cshVpJCO6bJPnEEWJLt1kOMZifMxrHuE5qdMPvENCsOMVOcwYqxT4ItrWli1kOMZse0PN6IWfcJzY43pfU3EA4xf2vjU2TsE5+q4W8s1kOMZsffWrtEZt0nNDsu1SjJXg6xkhTaMU32iSPAkmy3HmI0O2E2jnWf0OyE2SemWXGImeIMVox9EmxpTROzHmI0O6bl8UbMuk9odrwprb+BcIj5WxufImOf+FQNf2OxHmI0O/7W2iUy6z6h2XGpRkn2coiVpNCOabJPHAGWZLv1EKPZCbNxrPuEZifMPjHNikPMFGewYuyTYEtrmpj1EKPZMS2PN2LWfUKz401p/Q2EQ8zf2vgUGfvEp2r4G4v1EKPZ8bfWLpFZ9wnNjks1SrKXQ6wkhXZMk33iCLAk262HGM1OmI1j3Sc0O2H2iWlWHGKmOIMVY58EW1omRgK5E6DZyR05D+QQYw+kIcA+SUOJa0iABNIQoNlJQ4lrTAlwiJniDFaMfRJsaZkYCeROgGYnd+Q8kEOMPZCGAPskDSWuIQESSEOAZicNJa4xJcAhZoozWDH2SbClZWIkkDsBmp3ckfNADjH2QBoC7JM0lLiGBEggDQGanTSUuMaUAIeYKc5gxdgnwZaWiZFA7gRodnJHzgM5xNgDaQiwT9JQ4hoSIIE0BGh20lDiGlMCHGKmOIMVY58EW1omRgK5E6DZyR05D+QQYw+kIcA+SUOJa0iABNIQoNlJQ4lrTAlwiJniDFaMfRJsaZkYCeROgGYnd+Q8kEOMPZCGAPskDSWuIQESSEOAZicNJa4xJcAhZoozWDH2SbClZWIkkDsBmp3ckfNADjH2QBoC7JM0lLiGBEggDQGanTSUuMaUAIeYKc5gxdgnwZaWiZFA7gRodnJHzgM5xNgDaQiwT9JQ4hoSIIE0BGh20lDiGlMCHGKmOIMVY58EW1omRgK5E6DZyR05D+QQYw+kIcA+SUOJa0iABNIQoNlJQ4lrTAlwiJniDFaMfRJsaZkYCeROgGYnd+Q8kEOMPZCGAPskDSWuIQESSEOAZicNJa4xJcAhZoozWDH2SbClZWIkkDuBakvfIMDnLQ4W4DaJWqoWYlMaN8Z12cdQj1IeEOAQ86AIBQiBfVKAIjFEEigIgbHlukt3Ar82CVdxBc2OCcmwRTjEwq6vVXbsEyuS1CEBEkgIRC2NAVQNaLyHZseAYugSHGKhV9gmP/aJDUeqkAAJTBKImnoNBK925VHpYj+aHVeKJdjPIVaCIhukyD4xgEgJEiCBRwiMLdV9uxVc54hkSVyXk2l2HCmWYTuHWBmq7J4j+8SdIRVIgATWJRC19VNQvHVQLnMr2PT2hfIQzc6gBEu0j0OsRMV2SJV94gCPW0mABKYlMOgPqVTx5k5DPpcI0+ywwWYkwCE2IyIumLy+vjcEN5jBUJweN2SxmR6FSIAECktgtK3HqOKClAn8pis4cmVNvrdmPc1OSnJlXsYhVubqp8+dfZKeFVeSAAn0T6Da1mdAcYYALwYwb30FUfwMgi+N1+VDj/qzQb8emiZMPmen//p5v4NDzPsSeREg+8SLMjAIEigFgcT4VBS7QTEfgltGuvjlXYvkj9Mlz292StEWbklyiLnxK8tu9klZKs08SaB4BGh2ilez3CPmEMsdeSEPZJ8UsmwMmgRKQYBmpxRldkuSQ8yNX1l2s0/KUmnmSQLFI0CzU7ya5R4xh1juyAt5IPukkGVj0CRQCgI0O6Uos1uSHGJu/Mqym31SlkozTxIoHgGaneLVLPeIOcRyR17IA9knhSwbgyaBUhCg2SlFmd2S5BBz41eW3eyTslSaeZJA8QjQ7BSvZrlHzCGWO/JCHsg+KWTZGDQJlIIAzU4pyuyWJIeYG7+y7GaflKXSzJMEikfA1OwocKsIrnoEQxeCCnSD/z35s+Sz5s/L/t8TFr4yEDwBwBGG7X0jBDemyne6/lnDK/nzNdwMA6TUQAR2gODwgXZuaJPiWwBuNNMzFuJ7u4yB+iB3hY489k+Yu/lfMbdbwVwJPZ7EAAAgAElEQVTtYgsVzE3+QvIXMLfSnfx7BVZB8QAqeECS/8Tkf64ewQO6Gn/FajyAzfHAPcdL8mf8DJmAvdkBdhtyTjyeBEiABLImwFfjZE04I/3tlupmD1ew84hiJ61gJ+liZxXspMDOAizI5FjF7RDcBsXtWsFt0sXtE3Nw2z3Hy+2ZnEfRRxGg2WFTkAAJkED/BGh2+meW+47Rpj4bwEsAPD1zQzNodmsZIQA/0dX4Vuck+f2gcty3YQI0O+wMEiABEuifAM1O/8wy3VFdopvLLOyBCp7XMziKlyaXnTI9NDvx/0ku4ari2zIbP4zfJb/K7qhyKNPslKPOzJIESMCWAM2OLc++1R63VBeMCPYQwR4VxfM0MTiCOX0LFWPD/yjwHShulhH8MF4oNxcjbH+ipNnxpxaMhARIoDgEaHaGUKttL9ItZv0Fh6jgYFEcMoQQfDnyv0VwpU7gqngRjU+aotDspKHENSRAAiSwLgGanRw7otrWl0t3yuRkdRNxjvkYH/UNCK6cNYGr7lokdxtrByNHsxNMKZkICZBAjgRodjKGPbZcd5lYjUOkgoOhvftw+NkYAcVfEtMjXVw1vkiuJKx1CdDssCNIgARIoH8CNDv9M5t5xxU6Eq3AW3iZamZUM6zoXebCBL48vkhucVYLQIBmJ4AiMgUSIIHcCdDsGCLfZpluOVvxdlEcCeCZhtKUUlwmgovH63JTmWHQ7JS5+sydBEhgUAI0O4OSW2vfvPM0qqzCkYKeydnRQJIS0xEQfAldXBw35GtlhESzU8aqM2cSIAFXAjQ7DgTnL9MdR7o4UidNTuQgxa39E/gatGd6vtT/1uLuoNkpbu0YOQmQwPAI0OwMwH5+S585ojhSBW8HsOUAEtxiR+AmCC6Oa3KZnaS/SjQ7/taGkZEACfhLgGanj9qMnq1P0Fl4N4DjAIz0sZVLsydwiyqWdhryueyPGt4JNDvDY8+TSYAEikuAZidl7aotXSjASQC2S7mFy4ZBQHGFKJaE+ustmp1hNBXPJAESKDoBmp0ZKhg1dX9Iz+TsU/Rilyj+hxRY8vCDOPtP75H7Q8qbZiekajIXEiCBvAjQ7ExDet5S3akiOEkEx+RVDJ5jTuCXAJbEdfmUufKQBGl2hgSex5IACRSaAM3OBsoXNfXdkN69OdVCV5fB9wgocKUqlqxsyPeLjoRmp+gVZPwkQALDIECzsxb1aksPmrovZ89hFINnZkpAoVgyMQdn3HO8PJDpSRmK0+xkCJfSJEACwRKg2ZkqbdTWD0JxWrCVZmJrCPxAgFOK+iRmU7MDgP8HEOA/GFFT94bgBrPUFKfHDVlspkchLwiwT7woQ25BRMv0aZjAWRAckNuh2R70OwC3QfBbVawQ4M+iuL8ruL8C/HmigvtF8OfZq3D/XX/Gn6ubY5OJWdhyzixsNTGBrUaALbuKrXQEW1a62EoVW4lgZwV2BvBkAFtlG34u6g+p4JROTdq5nGZ4CM2OIcxQpTjEQq2sbV7sE1uePquNtvQwBc4EMOZznNPEdqMCt0liaiZwW0Xw2/H7cRsWy+osc6n+m84feQhP7gp2FsWTeyZI8FwonpDluZloCy7rKk5ZWZdOJvoZiNLsZAA1NEkOsdAqmk0+7JNsuHqlulhnRY/FmVAs8iqujQeTXH75Zlfwzc6muAnHyiqfYu/9em0Ee1cUL1PBPtCCvD5D8QsApxTlXVs0Oz51vaexcIh5WhjPwmKfeFYQ43Cilu4B4CwAextLW8v9HIJvq+LbE4qb7m3IuPUBWepVl+kLpIu9INgLXbwE4vflLwXe16nLR7JkYqFNs2NBMXANDrHAC2yUHvvECKSHMqMtPVYVZ3o8eH8IxX+q4GuduvzQQ4QDhbTdUt1mQrB/t4L9RbE/gG0GEsp6k+BL2sUpnYYk9z15+aHZ8bIsfgXFIeZXPXyNhn3ia2Xc4oqaumTq2TluQva7gzQ402EqgPH5jQDH+PprLZod+38Ag1PkEAuupJkkxD7JBOtQRaOmfgqCtw41iHUP/zEU14b2DU6/fNczPm8CUOlXI4v1AtynwDFxXb6Yhb6LJs2OC72S7OUQK0mhHdNknzgC9Gx7tanXiWBfH8IS4HtdxUWdhlzsQzw+xbCgqbtNCI4C8A4Am3oRm+BdcU3O8yKWqSBodnyqhqexcIh5WhjPwmKfeFaQAcN52hU6509342YVPGtACbttghuki4vGG/JZO9EwlUab+lRNDM+k8Rn+M30UZ8QN+VdfaNPs+FIJj+PgEPO4OB6Fxj7xqBgDhjK/pdUKcCsw9J8/X4cKLowXypcGTKW02+Yv0x1HFEep9kzP/CGDODeuywlDjqF3PM2OD1XwPAYOMc8L5El47BNPCjFgGGPLdZfuBP5fMhcGlHDeJsD1XeDcTl2ucRYrucCCZbrdxETvm56TADxmWDhU8dlOQw4b1vlrzqXZGXYFCnA+h1gBiuRBiOwTD4owYAjzm/rCiuB7A25336a4E4Kz4rqc6y5GhbUJjC3T3btdnAzgjUMk89W4LkN9rQjNzhCrX5SjOcSKUqnhxsk+GS7/QU/vveOqi18Nut9g37mV2ThrxfFyp4EWJaYhUG3rG0V7pmf3oUASfCWuyUFDOZuXsYaFvVjncogVq17DipZ9Mizyg5877zyNRlZhKE8YTi5ZTQBLVtbl+sEz4M5+CIxdoI/pPoiTMGl6cr+0JYL2eE3q/cRstZbf7FiRDFiHQyzg4hqmxj4xhJmD1DbLdMs5XcQANsvhuH8cwUtWueLe0GHDvLSlQK1Tl2V5Q6DZyZt4Ac/jECtg0YYQMvtkCNAHPfIKHYlW4GcAnj6oxCD7FLhSKzhp5UK5Y5D93GNLYLSt71TFEgBzbZU3rqaCt3RqcnmeZ9Ls5Em7oGdxiBW0cDmHzT7JGbjDcVFbr4Hi1Q4S/W9VnB43ZHH/G7kjSwLz2/qiEcUSBV6U5Tnra2sXB3cWydV5nUmzkxfpAp/DIVbg4uUYOvskR9gOR4029ZMqvaft5vW5QwQnjdfkyrwO5Dn9EZh3ns4dWdX7hued/e10W62KV3Qa8l9uKul20+yk41TqVRxipS5/6uTZJ6lRDW3haFNbKqjlFQAvW+VF2uacIVzW+ntX8fKVDfm+TQbTq9DsZE04AH0OsQCKmEMK7JMcIDscMdrSDytwqoNEf1t52ao/Xp6sHsJlrTu6wKEr6/LzLBHQ7GRJNxBtDrFACplxGuyTjAE7yI+29FgFPu4g0c/Wv0FxeNzgqx76gebT2qnLWp/M60GECnx35D7su2Kx/C0rDjQ7WZENSJdDLKBiZpgK+yRDuA7SUUv3gOJ6SC4vh+xUKnjbioXydYeQudUTAlFTL4Xg8JzCyfQ9WjQ7OVWxyMdwiBW5evnFzj7Jj3XqkxbrrGhrJA/t2zv1ngEXCnCbVnBwvFCS92vxEwiBalsvEMUxuaQjODKuySVZnEWzkwXVwDQ5xAIraEbpsE8yAusgG7X1HCgWOUik3fqTuC7PSbuY64pFIGrrMijyeHv5PSOKfe9uyK3WhGh2rIkGqMchFmBRM0iJfZIBVAfJ0ZYepsCnHSTSbr0xrss+aRdzXTEJRC1N3p5+VtbRq+DrnZrsZ30OzY410QD1OMQCLGoGKbFPMoA6oOTUyz2Ty1djA0qk3XZ+XJfj0y7mumITiJr6Ogi+mEMWZ8Z1eY/lOTQ7ljQD1eIQC7SwxmmxT4yBOshFTb0WggMcJNJsXRLXJXmhJD8lIlBt68tFkf2DAAVviGtyhRVamh0rkgHrcIgFXFzD1NgnhjAdpKK2fhCK0xwk0my9JK7LkWkWck14BKrL9NXSxTUZZ/Y/E4J976nJbRbn0OxYUAxcg0Ms8AIbpcc+MQLpIFNt6UECZPu+IcFX4poc5BAmtwZAoNrWN4vis1mmkjyBu1OXQy3OoNmxoBi4BodY4AU2So99YgTSQSZq6bcB7OkgMdPWH8R1eeFMi/jn5SBQbelCAdqZZmv0c3SanUyrFIY4h1gYdcw6C/ZJ1oQ3rh819d2Q3sscs/rcPlLBPncvlLuyOoC6xSNQbekZArw/w8h/PWcOXvyHf5E/uZxBs+NCryR7OcRKUmjHNNknjgAdts9bqjuNVPAdAFUHmem3Ku5XwX6duvwwE32KFppA1NJ/y/KN6SL46HhNnN7rRrNT6BbLJ3gOsXw4F/0U9snwKlht6gUi2T3lVoDXjdfl34eXIU/2nUC1pV8W4JCM4lyNCl4cL5SbB9Wn2RmUXIn2cYiVqNgOqbJPHOA5bI2auj8EX3WQ2PhWvr08M7QhCc9fpjtWurgOwI6Z5CX4UlyTfx5Um2ZnUHIl2schVqJiO6TKPnGA57A1auk3AWTyBGPLX8M4pMitBSEw2tZDVPHlrMIV4K3jdfnMIPo0O4NQK9keDrGSFXzAdNknA4Jz2Jbxr2Hu6Faw38qFcodDiNxaMgJRUxdD8IGM0v75xGy8+J7j5YF+9Wl2+iVWwvUcYiUs+gAps08GgOawZfRsfYLO6t2UvJ2DzLRbRXDoeE2uzEKbmmETyPj+nQ/GdenbTNHshN1zJtlxiJlgDF6EfZJviaOWLgfwrkxO5X06mWAti2jG9+/8vVLBi1cslJ/2w5Nmpx9aJV3LIVbSwveZNvukT2AOy+e39JkV4CcARhxkNriV9+lYEy2nXsb37/T9AlqanXL2YV9Zc4j1hau0i9kn+ZV+tKktFdTMT1Tc2R3BPrxPx5xsKQUzvH/nQVE8e7whv04LlmYnLakSr+MQK3Hx+0idfdIHLIelU5cIkm91tnSQmW7rCXFdzs1Al5IlJPDYj+lWm2yK7wN4agbpL4nrcnJaXZqdtKRKvI5DrMTF7yN19kkfsByWjrb0wwo4PU12Q8cLcP14XfZ1CI1bSeBRBEZberQCn8gAzf9VgGevqMsf0mjT7KShVPI1HGIlb4CU6bNPUoJyWDbvPI1GViG5MTNykNng1i6w78q6XG+tSz0SGG3r9ar4J3MSfdxIT7NjTj88QQ6x8GqaRUbskyyorqtZbempAnw4g5POjetyQga6lCQBRE09AIJrM0Dxh5FZePbd75L/m0mbZmcmQvzzpFH3huAGMxR9uHGzMymUOQH2SbaIt1mmW87p9n6BZfs4fsWdlTl48Yrj5c5sM6B6mQlELb0MwNsyYHByXJclM+nS7MxEiH9Os8MeSEWAZicVpoEXVdtaE0VrYIHpN/Km5AygUnJdAguautuE9G5W3tSYza833QrP/p+3y4Mb06XZMaYeohyHWIhVtc+JfWLP9BHFK3QkWtH7VueZlqfwpmRLmtSaicBoWz+iivfOtG6APz8+rsv5NDsDkOOWfxDgEGM3pCHAPklDabA1oy09TIFPD7Z7+l3SxaHji/hKCGuu1NswgW2X69isiZ5pr5oyEtwc1+T5NDumVMsnxiFWvpoPkjH7ZBBq6fZELf08gDekW5161XfiuuyVejUXkoABgWpbPySK9xlIrSOhgn/q1OQb0+nyMpY18QD1OMQCLGoGKbFPMoCavOVzqS5YXcFvAGxueYICx3Tq8klLzTy1qm19RkWxGxTzIbhlpItf3rVI/phnDHmdFVKu1eX6ROnix1A81pSf4ry4IdO+K45mx5R2mGIcYmHW1Tor9ok10Um90ZYeq8DHjdX/e24Fu92+UB4y1s1ULhn6UJwhwIsBzFv/MFH8rAtc2mlIFjdyZ5rb+uLzmrpbRfCBjeUKwZfG6/KhXAMzOCxq6xIo3m0g9YiEAndPbIGn3nuU/GVDujQ7lrQD1eIQC7SwxmmxT4yBTslFLf0KgAMt1VVxaqchH7XUzFprtK3HqOKCNOcocFVXcfo9Dbk1zXrf1lSbWsek0dk6RWy/6QqOXFmT76VY68WSsbN1l+4s/BjAY4wDOjyuy6dodoyplkWOQ6wslXbLk33ixm9Duxeco0+eGOldwrL83Duri93uWiR3W4pmqRW1VPvVV+A+AY6J6/LFfvcOb71K1MIXAPxzvzGo4s2dhnyu333DWh81dRkEpg+yVMGVnZocSrMzrKoW/FwOsYIXMKfw2Sf2oEebukgF55gqC5bGNTnRVDNDsaitn4LirQMfIXhDXJMrBt6f10btGZ0rIHjdoEfOrWDTolyanN/SZ1bQ+2XWyKD5bmhfZQRPXXGC/Pf6f8bLWJaUA9XiEAu0sMZpsU+MgSYvwGrpNwHsY6ncrWC3lQvlZ5aaWWmNLdV9uxVc56qvwBs7dUm+MfHzs1gr0WPxBejgRmcqsb7eBD5sGNWWflyAYy3jmO4SLc2OJeVAtTjEAi2scVrsE1ugY8t09+7k6yEsP9fEdXmNpWCWWlFTr4Hg1RZneGt4Jh8YmRix11rkWelivxWL5OsWWllrzG/pKyqAbazTPHOHZifragagzyEWQBFzSIF9Ygs5auppEHzQUlUVR3UacrGlZpZaUUtjywfQqeBNnZokzyzy4zNpdJJLbBu8z2TAIN8T1+XMAffmvi1qaWLod7c8eEPP3KHZsSQcqBaHWKCFNU6LfWILNGpp8h6hFxiq3ltZjaeueLfca6iZmdTYct2lO4FfWx/gzY28i3VWdWtcIcAhpjkqrogbYv0AStMQ1xaLmro4+eWZ5QEKNDt1WbS2Js2OJeFAtTjEAi2scVrsEzug887TnUZW4TY7RQCCi+OaHGWqmaFYtaVvECCTb2FU8JZOTS7PMPyNS1+gs6t/xxfMjU6vzLhtvC5PHlpufR6c0eXa78d1eRHNTp/FKPtyDrGyd0C6/Nkn6TilWVVt6pEiuCjN2rRrFHhNpy7XpF0/7HWZ/BJtraQqgresGILhedpinfN/W/eMzsEZMX4grssWGWlnIjva0q8r8ApL8YnZGL3neEkug/Y+/GbHkm6gWhxigRbWOC32iR3QqKmXQnC4nSJ+E9dlF0O9zKVGW/oSBb6V5UGiOGy8IZ/N8oy1tZ92hc750924QgVZ3iR+U1yXl+aVk8U5UUuT1zwst9BaS+P1az9jiWbHmG6IchxiIVbVPif2iR3TqKV3AHiSmaLgrLgmp5jp5SC03VLdZnUF/5f1UQK8dbwun8n6nJ2W6SZ/VXxBNVOjA1G0xxtSzzofS/2x83T77iokz8Yxe6Ly+vft0OxYVixQLQ6xQAtrnBb7xAbo2Dm6e3fE9ifnFcWeKxryXZsI81MZbeqtKnhW1ieK4m3jDfl0VufssFg3fXDr3s/LD8rqjEd0uzgiXiSXZX6O8QFRS5OnP7/RUHad+3ZodgzJhirFIRZqZW3zYp/Y8Ixamjzd+GwbtZ7KL+O67Gqol5tU8o4oETTzOFAEbxuv2RueHS7RTR+8r/dkZJPnBW2MhQK3PqTY576G3JcHM8szqsv0SOna3qc2MRtb3HO8PJDESbNjWa1AtTjEAi2scVrsExugUUu/CmB/GzVABZ/o1MT0KbVWsaXRqbb0ygxv5l0/hGlfJJkm1vXXbLdUN1td6T1Hx/RFrtPF0lUcsrIhVw0S67D3ZPKoAcWr4oZ8jWZn2NUtyPkcYgUp1JDDZJ/YFCBqafJvopvbqPV+i3xEXCveZY01+c9r6m4VwQ0p3wDujs3oMtDYBfqY7t97l65yMToKtDp1abgDGJ7CaFtvVbW7bCmKj4435FSaneHVtFAnc4gVqlxDC5Z94o5+dKnupRXc5K70D4XKBB6/4kS501Izb62opf8M6b07SnI529EgVpfo5jKnF+8BucQLfDGuy+tzOiuzY6K2ng/FcWYHCL4d1+QlNDtmRMMW4hALu75W2bFP3Elm8DTZn8R1eY57ZMNXiJr6OkjvklA+hkfx9rghl/abec/ozO7F+ap+9w60vmBPTN5Yjlk8SDJO7vriPTsDtVbpNnGIla7kAyXMPhkI2zqbqm39jCje4q40qSDAsvG61Kz0hq0z2tLXKnpGopJLLIIj45pckvaseefp3JFVvUtX+Rgd4AtxXSx/wZQ21UzWPf58fezDD+OPluITs7HzPcfL7bxB2ZJqoFocYoEW1jgt9ok70KilPwDwfHelKYUKDowXyn+Y6XkgNGV4EkMxkkc4aV+euu2ZusWsTXpGx+zm8o3mJ/h8XJM35cEgzzOilt4MYA+zM6duUqbZMSMarhCHWLi1tcyMfeJOM2pp8hC9bdyVJhW2uQ+b/L/F8rCVni86o009VCcvaeVjeCo4qrNw+rfFb3uRbjHrL714XpkTo8/H9fCMTsJutKUfVqB3U7HFRwULOzVZTrNjQTNwDQ6xwAtslB77xA1kBk8MvjGuyz5uUfm7e7Sth6j2DMasPKJU4B2dujzqfWXbLNMt53R7ceyXRxwCfG68Lm/O46xhnJHB/48sjxuykGZnGNUs2JkZNN/pcUMWFwwDw52BAPvErUWqLX2+AMllLJOPAp/s1OUYEzFPRcaaenB38hue2XmEqIqjOw25cM1Zj/2YbrXJpr1LV3kZncvH62J2T1cezPo9Y9vlOjZrAnf3u28j678W1+VVNDuGREOV4hALtbK2ebFP3HiONvUtKrB7R5PgpLgmlk9idkswo93zm3pwJflZOjAnoyPWkVXB0Z2aXLh1U7fepIIviGLfXM4FLu8EbnTWcDR91pTi9rghO9Ps5NGlBT+DQ6zgBcwpfPaJG2jrn51rFwd3FsnVblEVY3e1ra+R5FKS5GN4pIt6t4IDBHhFHoRU8NlOTQ7L4ywfzoha+hMAu1vFkvz8nGbHimbAOhxiARfXMDX2iRtM85+dK5423pBfu0VVnN3Vlh4kkz9L3yTzqDW3p/1Agc906vLWzHPy6ICoqV+AwOwhicnPz2l2PCqwr6FwiPlaGb/iYp+41cP6Z+fxfZiNxbLaLapi7a4u01dLctOyYtNiRT5NtIJPxzV5WxC59JFEtaVnCPD+PrZsfKmC9+yYwQxYiEMs4OIapsY+cYNp/LPz38V12dEtomLuri7VV8vkyzeLbXgUn44b5TM6SddFLU0M3mVWHZj8/Nz0m53k9fKiKPSLyKzghqSjwG4iaJrlpL0m7vsx7GbnUygTAr73SdyQGzNJ3ED0aYt1zh+3xkMGUmskrovrktczXwzDtpGqtvTAqUtam9ko5q7yqbguh+d+qicHVpfpC6SL71uFI8BH7M0OsJtVgNQhARIgASsCa96RY6VnqWP+jB3B8rgmCy1jLJpWtEwPwOTzbx5TqNgFl8U1OaJQMRsHu+BcfdzEatxrJZu8NoVmx4omdUiABLwm4LPZGWvp47vA/1oBFOC08bp8yEqvqDpRUw/ovS0d2LwQOSguixvlNjpr6hS19EGzm80FF9PsFOKfAAZJAiTgSsBnsxOdrU/DLPzKNce19p8c12WJoV5hpaK2vgqTT1r23fBcGtfl7YUFbRx41NIOgPkmsooraHZMSFKEBEjAdwJem52WJi8+TF6AaPJZ8z4gE7EARKKm7o/JJy3P9TSdS+K6HOlpbEMJK2rqbRDsZHT4V2l2jEhShgRIwG8CXpudtu4DxTetCIrg2PGafMJKLwSd0ba+cupdWlvMmI8AyQNucvkILo5rclQuZxXokKiltwB4jlHIN9HsGJGkDAmQgN8EfDY7vefDdHGNGcEujogXidlPd83iGrLQ6FJ9pVZ69/BsOeRQJo9XXBw3aHQ2VIuopd8A8DKjOv2EZseIJGVIgAT8JuC12Wnqm0RwuRVBBd7YqUsy1PlZj8BoS/fTySctP9rw5PhkZAEuGq/LO1igDROotvRKAQ424vMbmh0jkpQhARLwm4DXZqelRwtgdtmpojhkRUOu8rsiw4tubJnu2538WfpWw4hCBBeO1+ToYZxdlDOjtl4KhcmzhhS4m2anKJVnnCRAAk4EfDY7oy1tKLDUKcG1NyteFTfka2Z6AQqNLdV9k0taqtgayT06OX1EceF4g0ZnJtxRU5dBcMJM61L++f00OylJcRkJkECxCfhsdqKmngbBB60Iq+LlnYaY3fBsFZdvOtu29Y0jik8LMCuP2BT4fqcuL8rjrKKfYfx+rAmanaJ3BOMnARJIRcBrs9PWk6E4M1UiKRZVgH1X1OX6FEtLu2S7pbpgooIrFMjVfCSvVBpvSKu04FMmHrX0LAAnpVw+07K/0+zMhIh/TgIkEAQBr81OS/8FwHlWoBV4dacu11rphaazYJlu1+3iC3kbnTUcBVg0Xhe79w2GViAA1aZeIIJjjFK7h2bHiCRlSIAE/CbgudkxfcszFP8cN+RLfldkONElRmdi8ubkFw4ngslTaXg2Tj9q6ecBvMGoRr+n2TEiSRkSIAG/CfhsdkabeqgK/t2KoCgOG2/IZ630QtEZO0e37470jM4LfMhJFCeON8TuxnQfkjKKIWrpVwHsbyT3c5odI5KUIQES8JuAz2Yn+WVQt4LrrAhqBUd1FsrFVnoh6Ey9bDUxOs/3LJ93x3U5x7OYhh7OaEu/a3WZUYDv0ewMvaQMgARIIA8CPpud+W19UUXxXUMOx8d1Od9Qr9BSo2frE3RW78nJvhmdSa6Kk+KGnF1oyMbBRy39BYBnWMiq4Os0OxYkqUECJOA9Aa/NTkufWQF+ZgWR94P8g+ToufoEncAVUDzPim8mOoKT4hoNzxq2UUv/AGB7I9ZfptkxIkkZEiABvwn4bHaqy/WJMoHfWRFU4L2dunzMSq+oOlFTd5h623nyVvkifE6O67KkCIFmHWPU0vsMn3D9KZqdrCtGfRIgAS8I+Gx2omU6D12sNAOlOD1uyGIzvQIKVZfoE2V279JVUYzOJGXFKXFDkmfMlPoTtdTyvfPn25sdxdWlrlCYySf/dmTyjpKpf5i/BeDGvlFVMHPzd/N88PtGMthYrFnFuObMQfXdY86/TzYU8zT5+zz8t1uqm62u4G99/zMxzQYBLh+vy1us9IqmM/VNWXIz8nOLFnsvXsEpca28hme7tu68WvFbs9opzjI1O8kAi+uyj1mAFBMy5mAAABx+SURBVPKCQNTUvSG4wSwY/lunGUqfhNgnbtWIWpqYnc3cVB7Z/aO4Ln7fo2KU6Poy1aY+SaT38/LnZHREXrLvieti9lTtvIK2OCdq6gEQ2D0UU3AKzY5FZQLX4BALvMBG6bFP3EBGLU1uUH6mm8oju++P67K1kVZhZOYv0x0rkw8MfHZhgt5IoGW992p0mda1C7MnTIvitTQ7IfwTkXEOHGIZAw5Enn3iVsiopclDBQ91U/nHbt0E1c5xYncfkFVgGenMW6o7jVR69+jkY3SSN6XPfGHdOVtVnNppyEedhQokELX1fCiOswq5CzyLZseKZsA6HGIBF9cwNfaJG8yoqWdCcLKbyj92V4C9VtTlO1Z6PutMGZ3kG53d84hTFF+E4EUKLMjjvLIZntG2Xq+Kf7JiO6uLx9DsWNEMWIdDLODiGqbGPnGDWW3rO0TxSTeVtXYLjoxrcomZnqdC89q6c0VxhQC75RGiAq1OXRrJgyBl8tx8DA/wvk5dPpJHjsM+I2rp/wJ4vEUcCtzdqct2NDsWNAPX4BALvMBG6bFP3EBa8xPgY+N1ea9bVH7vXnCOPrk70nt7eV5Gp9mpy6I1VOY39YWVyZuht8uDlCjeP96QD+dx1rDO2GmZbvJAFw8ant/74RTNjiHRUKWs/08Y/DVWkK3CPnEr63ZLdcHqCu5yU1ln97/HdXmdoZ5XUgvO1Sd3J3CFKp6VR2AKrGN01jM8yb1CVk/73Wg6Inj/eC1cw1NdqrtKBT+3qqkoLhxvyNE0O1ZEA9bhEAu4uIapsU/cYZr+/Fzwv3FNdnCPyj+FsZY+pYveNypWv17beJKCpXFNTpxuUXWZvkCSV1JIToYHOG28Lh/yrzLuEUVtfTsUdi+xnXpmEc2Oe22CV+AQC77EJgmyT9wxGv/8HBNd7HzPIrndPTJ/FMaW6y7d1T1jsWtOUZ0T1+XdM51VbenzZdKAmdxrMtN5UPxr3JAzZlxXsAVRWz8FxVutwk5+dj7eENt3Y/Ghglbl8UuHQ8yvevgaDfvEvTLmPz8XHN2pyYXukfmhMNrUp2ry83LNyegIzo5rclLa7HuGR3rxPSHtHsd1H4jr8kFHDa+2V1t6l+VN38nPzlfW5ef8ZserMvsZDIeYn3XxLSr2iXtFrH9+LsDnxuvyZvfIhq/QMzqTNwM/I5doFGfHjfRGZ01M0VJ9Hiaf95PXJcRgDM/8lj6zAiQP1zT7JD87v2uR/J1mxwxpuEIcYuHW1jIz9ok7zWpLDxTgK+5KUwqCOK7JqJnekISiZfo0TD4Z+ek5hbAkrsvAzzyKWpq8fDSJNx/DI1gc1+T0nNhkdkzU1OMhONfwgEdem0KzY0g1VCkOsVAra5sX+8Sd57zzdO7IKvzFXekfClrBCzsL5QeWmnlqVZfo5jIb387rgYFQnBU35BTXHEeX63M1uWkZeKKrVpr9Aiwar4vZKxbSnGm9Jmprcgnw9Va6KvhwpybvT/RodqyoBqzDIRZwcQ1TY5/YwIzaehMUe9mo9VROjuuyxFAvV6lqS88QoDewMv8YGZ01cY4u1ef27jECnpR57MBfFXh5py4/zOEs+yMu0NnR37ECwLZm4hXsHS+Ub9HsmBENW4hDLOz6WmXHPrEhGbX0XwHYXZIQfCWuyUE20eWr0vtJd7f3rc6sHE4+M67Le6zPGW3rc1R73/BkbngUuL5Tl32tc8hDr9rUl4ngG4ZnPRjfhy2wWFbT7BhSDVmKQyzk6trlxj6xYZkBx/srE9hpxbvlXpsI81MZbetVqnhN1idm/bTp0aY+e+rm6h2zzqWoD22N2voBKBYb8rkmrssjvcPLWIZkQ5XK4P98T48bYtnUoaIvVF7sE5tyTT0u//8AbG6j2Hs59zGduti9d8sqsI3obLNMt5zTRQxgsyyPE8FHx2tyapZnJNpThie5pLVTxmetM+QzPstMPmrpzQCSG7tNPiqod2rSXiNGs2OCNWwRDrGw62uVHfvEimRvMF6lYvqNxlfjuhxgF2H2SqMt3U+B/8zyJFF8dLyRvdFZk8PYMt1du713ee2cYV53xnXJ58GGRkmMLdcXdyfwHSO5noyMYI/xE+QWmh1LqoFrcYgFXmCj9NgnRiABRC1NHmR3lp0i0K1gt5ULxfQZJpbxra9l/cyh9fUF+Mh4Xd6XZQ4b0l7Q1N1WS+9t6ZkZnpEKtr97oVi+Zy1TTKNt/YgqLF9a+/u4LuvcI8VvdjItYRjiHGJh1DHrLNgndoTHmvrirtj+my4K9iwW66dJr12dtX+SbFe19Erzl+mzKpPv0npy+l3pV0oXe4wv+se3Gul3Dmel9WtSoLgsbsgRa2dDszOc2hbqVA6xQpVraMGyTwzRq0rUxh8AbGelKoqfjTdkNyu9rHWqbX2HKMzvM1LgQ526nJZ1/DPpzz9Hn1UZ6f0s/Skzre3zz1fH92GzNb9C6nNv7ssz+BXWBu9Ro9nJvbTFO5BDrHg1G0bE7BNb6tWWflqAw0xVBQfENfmqqWZGYlNPTf6VpbwvRmdNTr3XI0y+S2sXwzwfeWqwoWZmUlFbz4FikeEBE90KnrJyodzBb3YMqZZBikOsDFV2z5F94s5wbYVqS98gwOctVQX45HhdjrHUzFIraukvzV4RoTgjbkjyDCOvPtXluqtMPmnZxPAocEGnLu/0KsmNBBO19L8tv90SwdXjNTl4/SP5zU5ROmKIcXKIDRF+gY5mn9gWK3lNAmbjN5ZvgAZwbxd4xsq6dGyjzUYtamny2oaPGah/MK7LBwx0MpGoLtVdZfJJy091PWD9XyG56mW53/xdcABUcHSnJhfS7GRZuUC1OcQCLaxxWuwTY6AAqi39uADHWiqL4MTxmiy11MxSy+D5K14bnTXsqm19hmjP8DxtUJ5SwWvHF8qXB92f974MbkL/88RsPOWe4yV5PtM6H36zk3d1C3geh1gBizaEkNkn9tCz+DdfAD+N6/Js+2izUdxuqW6zuoLkIYv9fxSFeoBptFSfjkrvklbfhkcVn+g0xNQY9w88/Y5omb4UXdyYfsfMKwW4fLwub9nQSpqdmfmVfgWHWOlbIBUA9kkqTH0vitr6G6jtT5RV8KZOTUzvB+o7sT42bNvU0VmC6/u4f+cBEZw0XpOP93GMF0vnL9MdpYslAhySOiDBv8U1+ZfU6z1YGDX1UggOtwxFBW/p1ORymh1LqiXS4hArUbEdUmWfOMDbyNYMfq0CCP4jrsmB2UScnepoS9+vwBkbO0GA700ITlpZk+9lF0n2ylFTF0Mw031GvxbgtPG6/Hv2EdmdMPXqjB/bKfaU4ocreMofF8qfaXaMyZZFjkOsLJV2y5N94sZvut1RW/eB4pvW6gK8dLwuN1nrZq03tlT37VawOxTPFsHuClRFcTMEt0Dxy9VzcPU9x8sDWceRh/5Muc5+EF/9w3vlT3nEYnlG1NLlAN5lqSmKC8cbcvR0mryMZUk7UC0OsUALa5wW+8QY6FpyUUt/AmB3yxMU+GSnQD9Dt8ydWsMjMK+tO48ofmr5otskG+3i4M4iuZpmZ3i1LfzJHGKFL2EuCbBPssMctfWDUFg/9fdvE108655Fcnt2kVOZBNYlkMF7sJID7ojH8BS8XiZodthxAxPgEBsYXak2sk+yK/foUn2uVvAj8xMK9msl8/wpmCuBsfN0++4q3Jy869by4DRPxuZlLEvigWpxiAVaWOO02CfGQNeTy+LXKwD+VqlgzxULJbmswA8JZEogi3t1ADww0cXuM31DSbOTaWnDEOcQC6OOWWfBPsmW8GhLX6LAtzI45fNxXd6UgS4lSeARAvNb+ooK8PUMkJwb1+WEmXRpdmYixD8HhxibIA0B9kkaSm5rorZ+EYrXuak8enfRnrtjnT/1sicw2tKvK/AK65Okiz3GF8ktM+nS7MxEiH9Os8MeSEWAZicVJqdFUVP3hyCLt5b/tLIZ9lxxrPzNKUBuJoENEIhamvzMPPm5uelHgc906vLWNKI0O2kolXwNh1jJGyBl+uyTlKAcl0UtTczO/o4yj94uWBzX5HRzXQqWmkDvpuSH8V0ItrcGoYpXdBryX2l0aXbSUCr5Gg6xkjdAyvTZJylBOS6Lmvo6CL7oKLOh7bxZOQOoZZfM6KbkBOu1cV1enZYvzU5aUiVexyFW4uL3kTr7pA9YjkujliY3Kr/EUWZD23mzcgZQyyqZ4U3JgOKf44Z8KS1bmp20pEq8jkOsxMXvI3X2SR+wHJdGbT0ciksdZTa4XQTHFfEFmlmwoObgBOadp3NnrcJ1CrxocJVpd34nrste/ejS7PRDq6RrOcRKWvg+02af9AnMcXnU0uQhg891lNnQ9ge6gv2K/iLNDLhQsg8CUUv/DcA7+9iSeqkqju405MLUGwDQ7PRDq6RrOcRKWvg+02af9AnMcXm1pW8Q4POOMhv+dgf43urZ2C+UF2pmwYia0xMYbes7VZGYnSw+18V1eWW/wjQ7/RIr4XoOsRIWfYCU2ScDQHPcUm3ppwU4zFFmuu0fj+tyXEbalA2UwPy2vqiiuA7A3ExSFLwsrskN/WrT7PRLrITrOcRKWPQBUmafDADNcUt0rj5dV+M7AmztKLXhb3h4/04WWIPVzPg+HUCwNK7JiYMApNkZhFrJ9nCIlazgA6bLPhkQnOO2qKWnAPiYo8x023n/TkZgQ5TN8j4dCH6rD2OvzkmychB2NDuDUCvZHg6xkhV8wHTZJwOCM9gWtfTbAPY0kHqUhPD+nSywBqeZ8X06UMVRnYZcPCg4mp1ByZVoH4dYiYrtkCr7xAGe49ZqSw8U4CuOMhvbzufvZAi36NKjbT1EFckzbypZ5KLAlZ26HOqiTbPjQq8keznESlJoxzTZJ44AHbdXW/pxAY51lJl+u+KyuCFHZKZP4UISiNr6Kkwanc2ySECBVVLBnvFCudlFn2bHhV5J9nKIlaTQjmmyTxwBOm6vLtEnYja+LcACR6lpt6vgE52aZGeosgqcupkQmN/SZ44A39KMbpDvBS04I67Jv7omQLPjSrAE+znESlBkgxTZJwYQHSWqTT1BBMscZTa+XbA8rsnCTM+guPcEtlmmW86ZwG0QzM8w2J/qqt5NyX91PYNmx5VgCfZziJWgyAYpsk8MIBpIRC1NHjT4BgOpjUmcHNdlScZnUN5jAlFT/5DFm8zXTlmAV47XJXlmj/OHZscZYfgCHGLh19giQ/aJBUV3jWpTnySC6wE8yV1tIwp9vogx01goniuBqKW3Adgpy0NVcWqnIR+1OoNmx4pkwDocYgEX1zA19okhTEepLF8lsXZoKvinTk2+4RgutxeIQNTWG6F4acYhfzGuy+stz6DZsaQZqBaHWKCFNU6LfWIM1FEuaus5UCxylJlxu1ZwUGehZPmz9xlj4IJ8CEQtTX4RtUfGp92uI9i3c4L83vIcmh1LmoFqcYgFWljjtNgnxkAd5XZapps80MV/ZfWwwfW+4XlLpyaXO4bM7Z4SSF4DMbIKPwDw9KxDFMVrxxvyZetzaHasiQaoxyEWYFEzSIl9kgFUR8mxlu7ZRc/wbOIoNeN2BWqdumT7S7AZo+ACawJRU3dABd+E4onW2uvrqeLDnYa8P4tzaHayoBqYJodYYAXNKB32SUZgHWVHm7pIBec4yqTarsCHOnU5LdViLvKeQNTS5JJVcomymkOwX43rckBW59DsZEU2IF0OsYCKmWEq7JMM4TpK5/Rz9DVRfjyuy3GOIXP7kAlETd0fgi8A2CKHUMZVsG+nJr/M6iyanazIBqTLIRZQMTNMhX2SIVxH6d7P0Sv4Dyh2cZRKtV0FV45UcOqKE+S/U23gIq8IRG09HkAbipE8AlPFmzsN+VyWZ9HsZEk3EG0OsUAKmXEa7JOMATvKz2/qCyuCK3O6JAEF7hbg1Lgun3IMndtzIrDdUl2wuoKPAHhbTkdCBfVOTdpZn0ezkzXhAPQ5xAIoYg4psE9ygOx4xNRLGxPDM8dRKv12xXmrt8R77z1K/pJ+E1fmTWB0qR6ik0Ynl2//kvwE+Mh4Xd6XR640O3lQLvgZHGIFL2BO4bNPcgLteEy1rW8URaaXDB4VouBmBU7lAwgdi5fR9tG2fkQV781IfoOyIrhwvCZH53UmzU5epAt8DodYgYuXY+jskxxhOx4VNfUICC5xlOl7u/UrAPoOgBvWIRAt1edh8tucl+eM5pq4Lq/J80yanTxpF/QsDrGCFi7nsNknOQN3PC5q6nEQnO8oM8j2ayqKs1Y05LuDbOYeGwJRU08G8H5ILr+2WjvoH8Z1eYFNFulVaHbSsyrtSg6x0pa+r8TZJ33h8mLxaEsbCiwdSjCCsyqrsGTFu+XeoZxf0kOrLT0IwMkCvHgICH4f1yXbF9ROkxTNzhCqXbQjOcSKVrHhxMs+GQ5311OrTX2vSO9SxjA+v1HFWZ2GXDyMw8t05lhLn9IVnAzFkUPK+69xXeYO6WzQ7AyLfIHO5RArULGGGCr7ZIjwHY8esuFJouelLccabmx775KV4CQA22Z4zMak/xjX5XFDOrt3LM3OMOkX5GwOsYIUashhsk+GXADH46O2Hg7FpY4ybtsFZ62uoH3vCbLCTYi7EwJDvmS1pgg/iuvyvGFXhGZn2BUowPkcYgUokgchsk88KIJjCKNtfaUqvuYo47q9o4ILUcFFnRPk965iZdw/2tLXKnAUgP2HnP/n47q8acgxPPLNzkOGD5j6cVyX5/qQGGOwI8AhZscyZCX2SRjVrbb15aK9N6UP9yP4E4CLKqtw0Yp387UTaYpRbeqbRPAOAC9Lsz7LNVm+wXyQuJNvdv4AYPtBNm9oz6wuHnPXIvm7lR51hk+AQ2z4NShCBOyTIlQpXYyjS3UvreCmdKszX/U3KC7qCi5cWZefZ35aAQ+Yem5S8k3Onl6ErzglbshZXsQyFURidn4EwOzbGAFeOl4XX/4h8Yl1YWPhECts6XINnH2SK+7MD6u29PkCXANgfuaHpTtgQoELFfj3lXW5Pt2WcFeNnafbd1cheTBf8h6rPTzK9Pi4LsN4ftNGEUjU1GshOMAKlAhOHK/JcJ7bYJUEddYhwCHGhkhDgH2ShlKx1ow29dkquBzAUzyL/KdQXFMZwdUrFspPPYsts3DGLtDHTDyIg0R7Jid5Xs5jMjtsEGHBEXFNLhtka9Z7ZLSliVNOvv6y+nRmdfGcuxbJ3VaC1BkuAQ6x4fIvyunsk6JUqr84q219BhQfH9JD6GYMVoDrNfnp+mxcveJ4uXPGDQVcML+lr6gk5iYxOWJ324kZCsHvBb0vOpKXzHr5SczOh5MXtFlGp4Kvd2qyn6UmtYZHgENseOyLdDL7pEjV6i/WscX6mO7WOBPAu/rbmevqvyXP6xHgm1LBLUX+xmfBufq4iVV4ASp4bs/gALvnSrK/w64dmcCJd58ov+1vW76rk8tYe0Nwg/Wx0sWh44v8dXnW+YasZ94jitPjhiwOmVkZc2OfhF/1qK1vh/ZMzzzvs1XcCcGPFPiRCm5aWZPv+Rrzdkt1wSrBS0TwIkjP4CT34Iz4Gu9acZ0Z1+U9BYgTkgQZtXRlFs2rik9MAIvvbch4EWAwxg0T4BBjZ6QhwD5JQ6n4axY0dbfVFZwpin0Llk3yzc8PoPi2jODnI4pf3FWT2/LO4bEf06022xS7dhW7QnqmZi8AO+Udh+N5K3uXreryGUed3LavMTvnAfiXzE5VnC4V/GxVFz+g8cmMcmbCHGKZoQ1KmH0SVDlnTCZq6ccAnDLjQp8XCB6E4hcQ/EIEv+gmfz8Hv+gcJ8kXAM6f6lLdFSPYtaLYVQW7IjE4wOOdhYcrcEOlghOLdpmwZ3aqbX2NKK7Kid8dAIK8iSwnfrkfo8DW1ocKcJ+1JvWGS6A0faK4WQU/geBXnZr8crjUh3t61NbXT13W2mG4kZifvhpA8sDdhzBpiHp/L4qHNPnvyd8DsxTYBMlfik0hU38/+b9t2vvfQ/sIli/YFCf++FhZVbTUemZn3nk6d2QVfpfFpayiAWG8JEACJNAHgRu7QK3MD7ub19adK4ozBTikD25cWiwC9wrw/vG6XFCssP8Rbc/sJJ+oredDcVxRE2HcJEACJDAsAqJ423hDPj2s8304d+rm5eTN2k/1IR7GYENABBeK4uwVdfmNjeJwVB4xO2PLdZfuBH4AYKvhhMJTSYAESKDABARHxjW5pMAZOIf++PP1satW4SRVJKZnlrMgBYZJ4CYFlnTqcu0wg7A6+xGz0/t2p6kfhOA0K3HqkAAJkECZCIxUsP3dC+WuMuW8oVyjZfo8JIZH8bqysyhg/uMCLBmvS7OAsU8b8jpmZ+xs3bY7q/ftzo4hJclcSIAESCAnAl+M6/L6nM7y/pjRlh6m6H3L80zvg2WAgODftIIlnRPk96HhWMfsJMlVW7pQgHZoiTIfEiABEsiFAB+auQ7mqR/AJIYn+WuzXGrAQ/oiIIL/EsGSFQvl631tLNDiR5mdJPaopf8JgK97KFAhGSoJkIA3BK6J65I84p+ftQiMLdPdu128A8CRUz/NJp/hE/i+Ci7u1OTC4YeSbQQbNjtN3UEF3xFgQbbHU50ESIAEgiNwZ1yXoj84LrOijDb1qSp4+5TpeVxmB1F4WgLJNzld4JJOTZI32pfis0Gz0/t2J6N3ZpWCKpMkARIoNQHeqDxz+cda+viu4khMGh+aw5mROa8QwdXdCVzSWSRXO4sVTGBaszNleI6AoNQ/pSxYPRkuCZCABwSkiz3GF8ktHoTifQi9N3yv7l3aSkwPn9GTQcUEuLyruKTTkP/KQL4Qkhs1O1OGZzEEHyhENgySBEiABIZPYHV8HzbDYkleOcBPSgI7XKKbPng/joTicAiel3Ibl01DQIH7KoovTQAXr2zI98sOakazM2V49obghrLDYv4kQAIkkILAj+K6cFinADXdkrGW7tkFDoTiQAie7iBVqq0KJO+suhaKa7Ea13ZOsnmhaQgQU5mdJNFqW58hiq8ACO2FbyHUkTmQAAl4QkCBCzp1eacn4RQ+jNGW7qeCAzBpfp5Y+ISySeA6VfzHlMEJ7hk5FshSm53ksG2bOjpLkPxE7VUWh1ODBEiABEIjICPYY/wE3q9jXdfnXKCzVzyIA3XNNz7AfOszCqb3nd63OLNwbfwu+VXBYs893L7MTi+6C3R29De8DxUcDcVY7hHzQBIgARLwlIBU8NrxhfJlT8MLJqwdmrr1gxXsC8VeCuwpwG7BJDd9In8GcBMU38YIbowXys0lyNksxf7NztTRvW95gGNpesxqQSESIIECE1DFJzoNObbAKRQ29Hlt3XkWsE9XsZcAewZ0u8WPEoOjwI2zu/jGXYvk74Ut0pADH9jsrIn7EdMjOIzv1BpyNXk8CZDAcAgIPh3X5G3DOZynrk8gWqpPRwX7ANhHgZcJsHVBKP1eFN/oVvANEXwjXij3FCRu78N0NjtrZ1ht6UEVxatVcGDyXELvs2eAJEACJOBAIPl5LxSndxrScpDh1owJbLdUF6wW7KwV7CRd7AzBTkDvr52H8L6uPwK4TQW3Sxe3C3BbV3D77C5uu2uRJH/GTwYETM3OOsanrS+vKF4GwXzV3o1kVUzeUJb8tXkGuVCSBEiABPIg8EMobpYKfrm6i5vvaciteRzKM7IhsLYRguIJAOZWFHNVMDf5+7X+2kKBuaKYi8k/exjAAxA8AMVfk78XxQPd5L8nf7/mz7r4Kw1NNrXrR/X/A9QibO0I8ddtAAAAAElFTkSuQmCC"); // shape.setImage("data:image/png;base64,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");
shape.setLabel("表格去重"); // shape.setLabel("表格去重");
shape.setName("ExcelRemoveDuplicate"); // shape.setName("ExcelRemoveDuplicate");
shape.setTitle("表格去重"); // shape.setTitle("表格去重");
return shape; // return shape;
} // }
//
@Override // @Override
public String supportShape() { // public String supportShape() {
return "ExcelRemoveDuplicate"; // return "ExcelRemoveDuplicate";
} // }
//
@Override // @Override
public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception { // public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception {
variables.put("test", "test"); // variables.put("test", "test");
} // }
} //}
\ No newline at end of file \ No newline at end of file
package com.zq.spiderflow.flowcall.executor; //package com.zq.spiderflow.flowcall.executor;
//
import com.zq.spiderflow.context.SpiderContext; //import com.zq.spiderflow.context.SpiderContext;
import com.zq.spiderflow.executor.ShapeExecutor; //import com.zq.spiderflow.executor.ShapeExecutor;
import com.zq.spiderflow.model.Shape; //import com.zq.spiderflow.model.Shape;
import com.zq.spiderflow.model.SpiderNode; //import com.zq.spiderflow.model.SpiderNode;
import org.springframework.stereotype.Component; //import org.springframework.stereotype.Component;
//
import java.util.Map; //import java.util.Map;
//
@Component //@Component
public class FlowCallExecutor implements ShapeExecutor { //public class FlowCallExecutor implements ShapeExecutor {
//
public static final String FLOW_ID = "flowId"; // public static final String FLOW_ID = "flowId";
//
@Override // @Override
public Shape shape() { // public Shape shape() {
Shape shape = new Shape(); // Shape shape = new Shape();
shape.setImage("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAAAXNSR0IArs4c6QAAIABJREFUeF7t3QuQnld93/HfWUnGTJyxbCLtu7ZD7QDjFiiYqYkTmIKhpOC4BtyAgaTQpECw48u+ay4N02QsSqdxnMC+a4uYi2cKYy6TGGpTPKjgEAundSiXQHGgMOXiElv7rgS2mLqDja33dN6VZGzJ0p7n2ec553/O+WpG4yE5z/n/z+d/dvenZ3Vx4gcCCCCAAAIIVCfgqjsxB0YAAQQQQAABEQC4BAgggAACCFQoQACocOgcGQEEEEAAAQIAdwABBBBAAIEKBQgAFQ6dIyOAAAIIIEAA4A4ggAACCCBQoQABoMKhc2QEEEAAAQQIANwBBBBAAAEEKhQgAFQ4dI6MAAIIIIAAAYA7gAACCCCAQIUCBIAKh86REUAAAQQQIABwBxBAAAEEEKhQgABQ4dA5MgIIIIAAAgQA7gACCCCAAAIVChAAKhw6R0YAAQQQQIAAwB1AAAEEEECgQgECQIVD58gIIIAAAggQALgDCCCAAAIIVChAAKhw6BwZAQQQQAABAgB3AAEEEEAAgQoFCAAVDp0jI4AAAgggQADgDiCAAAIIIFChAAGgwqFzZAQQQAABBAgA3AEEEEAAAQQqFCAAVDh0jowAAggggAABgDuAAAIIIIBAhQIEgAqHzpERQAABBBAgAHAHEEAAAQQQqFCAAFDh0DkyAggggAACBADuAAIIIIAAAhUKEAAqHDpHRgABBBBAgADAHUAAAQQQQKBCAQJAhUPnyAgggAACCBAAuAMIIIAAAghUKEAAqHDoHLkfgS2L/owZ6WzndLqkUx/x89h+Kma9652S9v/0+j8T6TO7F9zfZH0imkcgMwECQGYDo11bAoNFf46cLpB09oEv+LYazKubeyR9zjt9dmXeXZdX63SLQH4CBID8ZkbHBgS2LvnnbPC6xEuvMdBOiS3cJmn7eOhuKPFwnAkBCwIEAAtToIesBGZH/p1O+oOsms60WS/d+Lif6PU/eLu7N9Mj0DYCZgUIAGZHQ2MWBQaL/mo5XWqxt4J7+u6MdO6uoft2wWfkaAhEFyAARCenYK4Cg0X/v+X05Fz7z71vN9Hzli93f537OegfASsCBAArk6AP0wKDkR9LmjXdZAXNPXC/Nt/7++7HFRyVIyLQuwABoHdiCuQuMLvkP+O8/nnu5yiif6dPjefdS4s4C4dAILEAASDxAChvW2Cw5P9EXm+x3WVd3TnpyuWhe3tdp+a0CHQvQADo3pQdCxGY/lG/Ga//XshxijrGxOm5u+fd7UUdisMgEFmAABAZnHL5CMyN/Ef5c/425+Wkjy0P3W/a7I6uEMhDgACQx5zoMrLAgb/h79ORy1KuiYDXr48X3I4mj7AWAQR+JkAA4DYg8BgCcyN/nZdeD45dAd4C2J0NneUhQADIY050GVmAP/MfGbxdufv2bdLcnovdfe0e5ykE6hYgANQ9f07/GAKDq/1TNdE3wLEv4KTXLg/dh+13SocI2BMgANibCR0lFphd8pc6r6sTt0H5EAGnj4/n3StDlrIGAQQeLUAA4EYgcIjAYOSvlXQhMFkIfGs8dP8oi05pEgFjAgQAYwOhnfQCg5Gf/s7yl6TvhA4CBO4fD93jA9axBAEEDhEgAHAlEDj8DcD/kvQPgclDYN9PNbfnbW76bzXwAwEEGggQABpgsbQOgcHI/0TSsXWcNv9T+n361ZU3uy/kfxJOgEBcAQJAXG+qZSAwGHmfQZu0eFDA6wXjBbcTEAQQaCZAAGjmxeoKBAgAmQ2ZAJDZwGjXigABwMok6MOMAAHAzCjCGiEAhDmxCoFDBAgAXAkEDhEgAGR2JQgAmQ2Mdq0IEACsTII+zAgQAMyMIqwRAkCYE6sQ4A0AdwCBowsQADK7IQSAzAZGu1YEeANgZRL0YUaAAGBmFGGNEADCnFiFAG8AuAMI8AagqDtAAChqnBwmngBvAOJZUykTAd4AZDKog20SADIbGO1aESAAWJkEfZgRIACYGUVYIwSAMCdWIcC3ALgDCPAtgKLuAAGgqHFymHgCvAGIZ02lTAR4A5DJoPgWQGaDol1rAgQAaxOhn+QCBIDkI2jWAG8AmnmxGoEDAgQArgIChwgQADK7EgSAzAZGu1YECABWJkEfZgQIAGZGEdYIASDMiVUIHCJAAOBKIMAbgLzvAAEg7/nRfTIBAkAyegpbFeANgNXJHKEvAkBmA6NdKwIEACuToA8zAgQAM6MIa4QAEObEKgT4FgB3AIGjCxAAMrshBIDMBka7VgR4A2BlEvRhRoAAYGYUYY0QAMKcWIUAbwC4AwjwBqCoO0AAKGqcHCaeAG8A4llTKRMB3gBkMqiDbRIAMhsY7VoRIABYmQR9mBEgAJgZRVgjBIAwJ1YhwLcAuAMI8C2Aou4AAaCocXKYeAK8AYhnTaVMBHgDkMmg+BZAZoOiXWsCBABrE6Gf5AIEgOQjaNYAbwCaebEagQMCBACuAgKHCBAAMrsSBIDMBka7VgQIAFYmQR9mBAgAZkYR1ggBIMyJVQgcIkAA4EogwBuAvO8AASDv+dF9MgECQDJ6ClsV4A2A1ckcoS8CQGYDo10rAgQAK5OgDzMCBAAzowhrhAAQ5sQqBPgWAHcAgaMLEAAyuyEEgMwGRrtWBHgDYGUS9GFGgABgZhRhjRAAwpxYhQBvALgDCPAGoKg7QAAoapwcJp4AbwDiWVMpEwHeAGQyqINtEgAyGxjtWhEgAFiZBH2YESAAmBlFWCMEgDAnViHAtwC4AwjwLYCi7gABoKhxcph4ArwBiGdNpUwEeAOQyaD4FkBmg6JdawIEAGsToZ/kAgSA5CNo1gBvAJp5sRqBAwIEAK4CAocIEAAyuxIEgMwGRrtWBAgAViZBH2YECABmRhHWCAEgzIlVCBwiQADgSiDAG4C87wABIO/50X0yAQJAMnoKWxXgDYDVyRyhLwJAZgOjXSsCBAArk6APMwIEADOjCGuEABDmxCoE+BYAdwCBowsQADK7IQSAzAZGu1YEeANgZRL0YUaAAGBmFGGNEADCnFiFAG8AuAMI8AagqDtAAChqnBwmngBvAOJZUykTAd4AZDKog20SADIbGO1aESAAWJkEfZgRIACYGUVYIwSAMCdWIcC3ALgDCPAtgKLuAAGgqHFymHgCvAGIZ02lTAR4A5DJoPgWQGaDol1rAgQAaxOhn+QCBIDkI2jWAG8AmnmxGoEDAgQArgIChwgQADK7EgSAzAZGu1YECABWJkEfZgQIAGZGEdYIASDMiVUIHCJAAOBKIMAbgLzvAAEg7/nRfTIBAkAyegpbFeANgNXJHKEvAkBmA6NdKwIEACuToA8zAgQAM6MIa4QAEObEKgT4FgB3AIGjCxAAMrshBIDMBka7VgR4A2BlEvRhRoAAYGYUYY0QAMKcWIUAbwC4Awis+Qbg+5JOxSkTAa/Txgvuzky6pU0EzAjwBsDMKGjEisBg5G+VdLaVfujj6ALjoePzGJcEgRYCfOC0QOORsgUGI/+fJP122acs5nR3jofutGJOw0EQiChAAIiITak8BAaLfpucrsij2+q73DkeuhdUrwAAAi0ECAAt0HikbIGti/5XZ5xuL/uUZZzOey2sLLhRGafhFAjEFSAAxPWmWiYCg5H/kaQTM2m33jb5DYD1zp6Tr1uAALBuQjYoUWAw8n8h6ZUlnq2UM3mnz67MuxeXch7OgUBsAQJAbHHqZSEwu+Tf4Lw+kEWzlTbpnd64Mu+uq/T4HBuBdQsQANZNyAalCgxG/vOSnlfq+TI/123joXt+5megfQSSChAAkvJT3LLAYOSn3wKYfiuAH/YELhgP3Q322qIjBPIRIADkMys6TSAwO/L/2UnnJyhNySMLfGI8dK8ACAEE1idAAFifH08XLvDEP/In/PTx+pKkJxV+1DyO57TLH6NnrVzkdufRMF0iYFeAAGB3NnRmROCkkT99In3LSDtVt+E26NnLl7ovV43A4RHoSIAA0BEk25QtMPdu/0/9jG4r+5TGT+f1jvGC22a8S9pDIBsBAkA2o6LR1AInXOmPf9zjdb28zkvdS031vbR3xunfLM+7G2s6N2dFoG8BAkDfwuxfnMDcyP+Rl36/uIMZPJCXbvIzesvuy9x3DbZHSwhkLUAAyHp8NJ9KYOuSf84Gr0u89JpUPRRed/rtlu38Ub/Cp8zxkgoQAJLyUzx3gcGiP8c5vdZr9dsCx+V+HgP93+ydPsnf8GdgErRQvAABoPgRc8AYAlve44/b+KBe7p1eJq+nSzpV0rExamde405Jd3qnj2x0+q93X+buyvw8tI9ANgIEgGxGRaO5CWy5yg9mNuhUN9NhEHC6QtLZkS12yusdHde8c7zgpl/8+YEAAokECACJ4CmLQBuBwcjfmiIAjIfuBW365RkEELArQACwOxs6Q+AwAQIAlwIBBLoSIAB0Jck+CEQQIABEQKYEApUIEAAqGTTHLEOAAFDGHDkFAhYECAAWpkAPCAQKEAACoViGAAJrChAA1iRiAQJ2BAgAdmZBJwjkLkAAyH2C9F+VAAGgqnFzWAR6FSAA9MrL5gh0K0AA6NaT3RCoWYAAUPP0OXt2AgSA7EZGwwiYFSAAmB0NjSFwuAABgFuBAAJdCRAAupJkHwQiCBAAIiBTAoFKBAgAlQyaY5YhQAAoY46cAgELAgQAC1OgBwQCBQgAgVAsQwCBNQUIAGsSsQABOwIEADuzoBMEchcgAOQ+QfqvSoAAUNW4OSwCvQoQAHrlZXMEuhUgAHTryW4I1CxAAKh5+pw9OwECQHYjo2EEzAoQAMyOhsYQOFyAAMCtQACBrgQIAF1Jsg8CEQQIABGQKYFAJQIEgEoGzTHLECAAlDFHToGABQECgIUp0AMCgQIEgEAoliGAwJoCBIA1iViAgB0BAoCdWdAJArkLEABynyD9VyVAAKhq3BwWgV4FCAC98rI5At0KEAC69WQ3BGoWIADUPH3Onp0AASC7kdEwAmYFCABmR0NjCBwuQADgViCAQFcCBICuJNkHgQgCBIAIyJRAoBIBAkAlg+aYZQgQAMqYI6dAwIIAAcDCFOgBgUABAkAgFMsQQGBNAQLAmkQsQMCOAAHAzizoBIHcBQgAuU+Q/qsSIABUNW4Oi0CvAgSAXnnZHIFuBQgA3XqyGwI1CxAAap4+Z89OgACQ3choGAGzAgQAs6OhMQQOFyAAcCsQQKArAQJAV5Lsg0AEAQJABGRKIFCJAAGgkkFzzDIECABlzJFTIGBBgABgYQr0gECgAAEgEIplCCCwpgABYE0iFiBgR4AAYGcWdIJA7gIEgNwnSP9VCRAAqho3h0WgVwECQK+8bI5AtwIEgG492Q2BmgUIADVPn7NnJ0AAyG5kNIyAWQECgNnR0BgChwsQALgVCCDQlQABoCtJ9kEgggABIAIyJRCoRIAAUMmgOWYZAgSAMubIKRCwIEAAsDAFekAgUIAAEAjFMgQQWFOAALAmEQsQsCNAALAzCzpBIHcBAkDuE6T/qgQIAFWNm8Mi0KsAAaBXXjZHoFsBAkC3nuyGQM0CBICap8/ZsxMgAGQ3MhpGwKwAAcDsaGgMgcMFCADcCgQQ6EqAANCVJPsgEEGAABABmRIIVCJAAKhk0ByzDAECQBlz5BQIWBAgAFiYAj0gEChAAAiEYhkCCKwpQABYk4gFCNgRIADYmQWdIJC7AAEg9wnSf1UCBICqxs1hEehVgADQKy+bI9CtAAGgW092Q6BmAQJAzdPn7NkJEACyGxkNI2BWgABgdjQ0hsDhAgQAbgUCCHQlQADoSpJ9EIggQACIgEwJBCoRIABUMmiOWYYAAaCMOXIKBCwIEAAsTIEeEAgUIAAEQrEMAQTWFCAArEnEAgTsCBAA7MyCThDIXYAAkPsE6b8qAQJAVePmsAj0KkAA6JWXzRHoVoAA0K0nuyFQswABoObpc/bsBAgA2Y2MhhEwK0AAMDsaGkPgcAECALcCAQS6EiAAdCXJPghEECAARECmBAKVCBAAKhk0xyxDgABQxhw5BQIWBAgAFqZADwgEChAAAqFYhgACawoQANYkYgECdgQIAHZmQScI5C5AAMh9gvRflQABoKpxc1gEehUgAPTKy+YIdCtAAOjWk90QqFmAAFDz9Dl7dgIEgOxGRsMImBUgAJgdDY0hcLgAAYBbgQACXQkQALqSZB8EIggQACIgUwKBSgQIAJUMmmOWIUAAKGOOnAIBCwIEAAtToAcEAgUIAIFQLEMAgTUFCABrErEAATsCBAA7s6ATBHIXIADkPkH6r0qAAFDVuDksAr0KEAB65WVzBLoVIAB068luCNQsQACoefqcPTsBAkB2I6NhBMwKEADMjobGEDhcgADArUAAga4ECABdSbIPAhEECAARkCmBQCUCBIBKBs0xyxAgAJQxR06BgAUBAoCFKdADAoECBIBAKJYhgMCaAgSANYlYgIAdAQKAnVnQCQK5CxAAcp8g/VclQACoatwcFoFeBQgAvfKyOQLdChAAuvVkNwRqFiAA1Dx9zp6dAAEgu5HRMAJmBQgAZkdDYwgcLkAA4FYggEBXAgSAriTZB4EIAgSACMiUQKASAQJAJYPmmGUIEADKmCOnQMCCAAHAwhToAYFAAQJAIBTLEEBgTQECwJpELEDAjgABwM4s6ASB3AUIALlPkP6rEiAAVDVuDotArwIEgF552RyBbgUIAN16shsCNQsQAGqePmfPToAAkN3IaBgBswIEALOjoTEEDhcgAHArEECgKwECQFeS7INABAECQARkSiBQiQABoJJBc8wyBAgAZcyRUyBgQYAAYGEK9IBAoAABIBCKZQggsKYAAWBNIhYgYEeAAGBnFnSCQO4CBIDcJ0j/VQkQAKoaN4dFoFcBAkCvvGyOQLcCBIBuPdkNgZoFCAA1T5+zZydAAMhuZDSMgFkBAoDZ0dAYAocLEAC4FQgg0JUAAaArSfZBIIIAASACMiUQqESAAHCEQQ+u9lv8RGfJazDjNPDSrJwG0/8tPfzzuEruCcdEAAEErArcJ2m8+tNpLK+xk1Ymfv//3jTR7Xdd7u6x2nzKvggAj9CfftHXRK+UVn+enXIw1EYAAQQQ6Exgh/P6yAavHYSBn5lWHwBWf6Xv9TI30UvldF5n142NEEAAAQTMCXinj8xMtIMwIFUbALa+yz/TbdBFzuvVcjre3C2lIQQQQACBPgXu8dINfp+u3f1m9z/7LGR17+oCwEkjf7p3ush7XSTpGKuDoS8EEEAAgSgCP3VO1zqva3cN3bejVDRSpJoAMFj0p0q6SG71C//PG/GnDQQQQAABGwL/V17XSrp2vODutNFSv10UHwCeus0fc89m/bvVL/7Sln452R0BBBBAIHOBPdMQsHGiK++63P0k87Mctf2iA8BJ7/K/ONmgD0h6cclD5GwIIIAAAp0L3OadLl6Zd3/X+c5GNiw2AMy925/pZ/Tnkn7JiDVtIIAAAgjkJbB7xutNuxbcTXm1HdZtkQFgcLU/VxPdHEbAKgQQQAABBI4i4PXW8YL709KMigsAs4v+7c7pP5Y2KM6DAAIIIJBU4L3joZv+XrJifhQVAAZLfoe8XlLMdDgIAggggIAZAef1l8sL7tfMNLTORooJAINF/0E5/et1evA4AggggAACRxbwumq84P5tCURFBIDBov9DOf37EgbCGRBAAAEEbAs4p3+5PO9utN3l2t1lHwBmF/1rnNNH1z4qKxBAAAEEEOhGYOL03N3z7vZudkuzS9YBYDDyz5b0V5L4Z3nT3B+qIoAAArUK/Ggyo7N2X+a+mytAtgHglHf7Ex+a0WcknZkrPn0jgAACCGQt8Ff7Nulley529+V4imwDwNyS/4D3ekOO6PSMAAIIIFCGgHO6bnnevTHH02QZAGaX/D+b/nGMHMHpGQEEEECgLAHv9KKVefe53E6VZQAYjPwnJb00N2z6RQABBBAoUuC/jIfuZbmdLLsAwO/6z+2K0S8CCCBQvoD3+s2VBfexnE6aXQAYjPwXJJ2VEzK9IoAAAggUL/A/xkP3KzmdMqsAMLvk553XKCdgekUAAQQQqEPAOw1X5t1SLqfNJgDMXuu3ugc0/dX/abng0icCCCCAQFUC3/eP06+sXOR253DqbALA3JK/0HtdmwMqPSKAAAIIVCrgdcl4wb0nh9NnEwAGi/7P5XRBDqj0iAACCCBQp4CXbloZuvNzOH0WAWD2T/zPuU1alvTzOaDSIwIIIIBAtQL/b98mDXL42wGzCACDq/25mujmaq8TB0cAAQQQyEfA6VXjefcX1hvOIgDMjfySly6zjkl/CCCAAAIIyOtD4wX329YlsggAgyV/p7z+gXXMR/R3r6TvPfzT6/6Merfd6oy8Jmp+b9s+Z03D6fmSzo7c1k55fT5yTcrVLuB0rKRfesTPE3Ih8dLdK0N3ivV+m38ijXyikxf9Gfucvhq5bNNyd0n6G+/015ON2rHnYvedphuwHoEQgcHI35oiAIyH7gUh/bEGgb4EBov+1NW7/7MQPP3fln/88njovmS5QfMBYLDot8npCqOIX3FO71+ed+832h9tFSZAAChsoByntcDckv9d7/W7kv5J6036fNDrHeMFt63PEuvd23wAmB359zrpTes9aKfPe93hZrSdL/ydqrJZgAABIACJJVUJHAgC098j9jRLB/fS+1aG7kJLPR3ai/kAYPBf/ts5s0+v2/Vm9/eWB0tvZQoQAMqcK6dan8Dgav9UTTT9XfeWQoD5fyEwhwDwRUnPXt/16OzpnXwvtDNLNmohQABogcYj1QgMRv7vDIWAL42H7pct4+cQAH4g6ReTI3p9Z7zgnpK8DxqoWoAAUPX4OXyAgKF/Mfbvx0P3xICWky3JIQA8KGljMqH9hXePh242cQ+UR0AEAC4BAmsLDEZ++sewU//DcQ+Nh27T2t2mW2E6AAyu9ls0Uep/VekBeZ0/XnA70o2JygjsFyAAcBMQWFtg68g/Y0a6XdLPrb26xxUz2jq+zO3pscK6tjYdAGav8f/Y7dPX13XCdT7snd64Mu+uW+c2PI5AJwIEgE4Y2aQCgdkl/wbn9YGUR/Ub9IyVS90dKXs4Wm3TAWCw6Kd/6cP0Lz5J9eO28dBN/+Y1fiBgQoAAYGIMNJGJwGDkp3+D5fOStev1gvGC25ms/hqFCQBHB7pgPHQ3WB0efdUnQACob+acuL3AYORfKa3+8cA0PwgA7d0TvwHYMR66X2/fPU8i0L0AAaB7U3YsW2Aw8tPfv/WSJKckALRnTxkAnNNFy/Puve2750kEuhcgAHRvyo5lC8wt+su907uSnJIA0J49ZQDYONEpd13u7m7fPU8i0L0AAaB7U3YsW2D1HxFy+n6SUxIA2rOnCgDO6S+X592vte+cJxHoR4AA0I8ru5YtMDvy/81Jz41+SgJAe/JkAUD6w+Wh+w/tO+dJBPoRIAD048quZQvMjfwfeOmd0U9JAGhPnioASLp0PHTb23fOkwj0I0AA6MeVXcsWGIz8JZKuiX5KAkB78lQBwEmvXR66D7fvnCcR6EeAANCPK7uWLTA38v/KS9dHPyUBoD15qgDgpfNWhu7m9p3zJAL9CBAA+nFl17IFZkf+XzjpU9FPSQBoT54qAMj40NqL8mTuAgSA3CdI/ykE+Fry2Or8TYCP5UIASPExSs0AAQJAABJLEDhEgABAAAj/oCAAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPxQUy41AAAXRklEQVQqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAAIAOFXmQAQbsXKqAIEgKjcFCtEgABAAAi/ygSAcCtWRhUgAETlplghAgQAAkD4VSYAhFuxMqoAASAqN8UKESAAEADCrzIBINyKlVEFCABRuSlWiAABgAAQfpUJAOFWrIwqQACIyk2xQgQIAASA8KtMAAi3YmVUAQJAVG6KFSJAACAAhF9lAkC4FSujChAAonJTrBABAgABIPwqEwDCrVgZVYAAEJWbYoUIEAB6CABbrvKDjRt1xkTaPCNtnv7XOR3b6Z1xuqLT/UI2c9qmiVzI0sA193lpr5P2Tv+7crJu1QVuX+CzLMtIYHbJP11ep04/Hvz042H6X6+NnR3B6fmSzu5sv7CNdsrr82FLw1Yd/HiYSHtnpL3jBbcz7ElWFSmwzW+cPV5nr368HPi4kXRcp2dN9bUk5BCBX2+81/3Tj5eDHzd+o74yvsztCSnxWGsaf5E7aeRPn3idJ6fzJD2vbeHKn3tQ0kfktOOYTbrlB7/n7q3cI+vjb13yz9ngdZ7X6sfE07I+TKLmvXS3kz46kW7ZPXS3JGqDshEFTt7un7Bvn17qvc5z+z92ugvKEc9hoNQOJ31y4nXLyoL7XpN+ggPA6hd+6RLt/8mPjgSmn/gkbZ9s0vY9F7v7OtqWbSIIzC76F8rpEiedH6FcPSW8vuik7csL7vp6Dl3PSbe8xx838+D+ryVOOrmek0c56fYZafuuoft2SLW1A8D01cxmXeG8LpXT8SGbsqaVwDec0/bleffeVk/zUDSB6Wt+53W5pN+JVrTCQt7ps3LavnKZ+1SFxy/yyHNL/kLvV7/486asrwl7/dg7XfOEvXrnN7e5nx6tzFEDwCnv9ic+tEEf1PSVPz/iCDhdP553r4tTjCpNBaav+2cm+pCcntz0Wda3FPB6x3jBbWv5NI8ZERiM/FWS3mqkneLbcNLtMzN61d2XubuOdNgjBoDZa/xpbp++LOnE4qXsHfDr46F7pr226u5osOjPkdOn61ZIdvpPjIfuFcmqU3hdAoORn37cnLOuTXi4jcB9zuv5ywvubx/r4ccMALMjf5aTvtCmGs90JzAeurW/RdNdOXY6isBg0W9Tit9FzFQeKfDp8dCdC0leAoOR93l1XF63+yZ6yp7L3XcOPdlhX2BOGvknTqTv8jsyTVyCr4yH7kwTnVTcBF/8TQ3/0vHQbTfVEc0cUWAw8tPflX4aRMkFHph5SKfseov74SM7eVQAeOo2f8w9m3WbpLOSt0sDBwVuGA/dBXCkEZgd+dc76bo01al6hNeWr10eug+jY1tgMPKfk/RC211W1d3N4706X9vcQwdP/agAwK90jF4GfhNUksH8wqKf2zijL8vrpCQNUPSxBZx2PTTRmT9ccMsQ2RTga4nNueiQryUPBwA+2Rkd2LQtPuElGQ6fxJKwhxUlFIc5JVjF15IE6KElD/la8nAA4JNdqGCidXzCiwrPJ7Go3M2LEYqbm0V6gq8lkaDblnnE15LVAHDgz/vfwavOtqIRnnPadcwmPZ2/NjiCtSQ+icVxXlcVQvG6+Pp4+IQr/fGPe7y+ydeSPnQ72tNpl5zOmP4bAqsBYG7R/5Z34jfVdOTb4zYXjIfuhh73Z+sDAnNL/hbv9SJADAt43TFecM8w3GF1rQ0W/blyurm6g2d2YCdduDx071sNAIOR/7ik38jsDNW1673ev7Lg3lTdwSMfePZav9U9oJXIZSnXRoB/uruNWm/PDJb8H8vrbb0VYONOBKZ/zfbKvHuxW339P6MfdbIrm/Qt8L3x0D2p7yK17z+75F/tvD5Wu0Mm5/+z8dBdnEmvxbc5GPlvSTq9+IOWcMAZbXVbF/3LZ5xuLOE8NZzhfq8T9i64vTWcNdUZZ0d+0UnDVPWpGy7gpa+tDN2zwp9gZV8Cmxf95mOd+KfN+wLueN+J1/ludtFP/8LZxY73ZrueBPZ5PWvPgvtaT9uzraTZkb/RSS8Hw76Al/auDN0J9jstv8Mti/6MDU5fLf+kZZzQey04frWT1zCnqW33grspr67z6nZ25L/qpDPy6rrebnkrZmP2vE22MYfQLrw0mgYAfrUTKmZg3TS1rSy4kYFWim1hduTvddLmYg9Y2MF4K2ZjoLxNtjGH0C68dJMbjPytks4OfYh1iQX4s8+9D4B/vax34m4L8CcBuvVsuRt/d0ZLuHSP7SQApMNvV5kA0M6twVMEgAZYFpYSACxMgb88y8QUGjVBAGjEZWExAaD3KRAAeifutgABoFvPlrvxBqAlXLrHCADp7FtWJgC0hAt/jAAQbmViJQHAxBgIACbG0KQJAkATLRNrCQC9j4EA0DtxtwUIAN16ttyNANASLt1jBIB09i0rEwBawoU/RgAItzKxkgBgYgwEABNjaNIEAaCJlom1BIDex0AA6J242wIEgG49W+5GAGgJl+4xAkA6+5aVCQAt4cIfIwCEW5lYSQAwMQYCgIkxNGmCANBEy8RaAkDvYyAA9E7cbQECQLeeLXcjALSES/cYASCdfcvKBICWcOGPEQDCrUysJACYGAMBwMQYmjRBAGiiZWItAaD3MRAAeifutgABoFvPlrsRAFrCpXuMAJDOvmVlAkBLuPDHCADhViZWEgBMjIEAYGIMTZogADTRMrGWAND7GAgAvRN3W4AA0K1ny90IAC3h0j1GAEhn37IyAaAlXPhjBIBwKxMrCQAmxkAAMDGGJk0QAJpomVhLAOh9DASA3om7LUAA6Naz5W4EgJZw6R4jAKSzb1mZANASLvwxAkC4lYmVBAATYyAAmBhDkyYIAE20TKwlAPQ+BgJA78TdFiAAdOvZcjcCQEu4dI8RANLZt6xMAGgJF/4YASDcysRKAoCJMRAATIyhSRMEgCZaJtYSAHofAwGgd+JuCxAAuvVsuRsBoCVcuscIAOnsW1YmALSEC3+MABBuZWIlAcDEGAgAJsbQpAkCQBMtE2sJAL2PgQDQO3G3BQgA3Xq23I0A0BIu3WMEgHT2LSsTAFrChT9GAAi3MrGSAGBiDAQAE2No0gQBoImWibUEgN7HQADonbjbAgSAbj1b7kYAaAmX7jECQDr7lpUJAC3hwh8jAIRbmVhJADAxBgKAiTE0aYIA0ETLxFoCQO9jIAD0TtxtAQJAt54tdyMAtIRL9xgBIJ19y8oEgJZw4Y8RAMKtTKwkAJgYAwHAxBiaNEEAaKJlYi0BoPcxEAB6J+62AAGgW8+WuxEAWsKle4wAkM6+ZWUCQEu48McIAOFWJlYSAEyMgQBgYgxNmiAANNEysZYA0PsYCAC9E3dbgADQrWfL3QgALeHSPUYASGffsjIBoCVc+GMEgHArEysJACbGQAAwMYYmTRAAmmiZWEsA6H0MBIDeibstQADo1rPlbgSAlnDpHiMApLNvWZkA0BIu/DECQLiViZUEABNjIACYGEOTJggATbRMrCUA9D4GAkDvxN0WIAB069lyNwJAS7h0jxEA0tm3rEwAaAkX/hgBINzKxEoCgIkxEABMjKFJEwSAJlom1hIAeh8DAaB34m4LEAC69Wy5GwGgJVy6xwgA6exbViYAtIQLf4wAEG5lYiUBwMQYCAAmxtCkCQJAEy0TawkAvY+BANA7cbcFCADderbcjQDQEi7dYwSAdPYtKxMAWsKFP0YACLcysZIAYGIMBAATY2jSBAGgiZaJtQSA3sdAAOiduNsCBIBuPVvuRgBoCZfuMQJAOvuWlQkALeHCHyMAhFuZWEkAMDEGAoCJMTRpggDQRMvEWgJA72MgAPRO3G0BAkC3ni13IwC0hEv3GAEgnX3LygSAlnDhjxEAwq1MrCQAmBgDAcDEGJo0QQBoomViLQGg9zEQAHon7rYAAaBbz5a7EQBawqV7jACQzr5lZQJAS7jwxwgA4VYmVhIATIyBAGBiDE2aIAA00TKxlgDQ+xgIAL0Td1uAANCtZ8vdCAAt4dI9RgBIZ9+yMgGgJVz4YwSAcCsTKwkAJsZAADAxhiZNEACaaJlYSwDofQwEgN6Juy1AAOjWs+VuBICWcOkeIwCks29ZmQDQEi78MQJAuJWJlQQAE2MgAJgYQ5MmCABNtEysJQD0PgYCQO/E3RYgAHTr2XI3AkBLuHSPEQDS2besTABoCRf+GAEg3MrESgKAiTEQAEyMoUkTBIAmWibWEgB6HwMBoHfibgsQALr1bLkbAaAlXLrHCADp7FtWJgC0hAt/jAAQbmViJQHAxBgIACbG0KQJAkATLRNrCQC9j4EA0DtxtwUIAN16ttyNANASLt1jBIB09i0rEwBawoU/RgAItzKxkgBgYgwEABNjaNIEAaCJlom1BIDex0AA6J242wIEgG49W+5GAGgJl+4xAkA6+5aVCQAt4cIfIwCEW5lYSQAwMQYCgIkxNGmCANBEy8RaAkDvYyAA9E7cbQECQLeeLXcjALSES/cYASCdfcvKBICWcOGPEQDCrUysJACYGAMBwMQYmjRBAGiiZWItAaD3MRAAeifutgABoFvPlrsRAFrCpXtsp5sd+Rud9PJ0PVC5iYD3WlhZcKMmz7C2mcDsyN/rpM3NnmJ1KoF9Xs/as+C+lqo+dfcLzC76oXNaxCMPAS/dNA0Ai04a5tEyXU68zt+94G5Coj+B2ZH/qpPO6K8CO3cpcL/XCXsX3N4u92Sv5gJbF/3LZ5xubP4kT6QQ8NLIkdpS0Levya922tuFPslbsVCp9Ou8tHdl6E5I3wkdbFn0Z2xw+ioSeQhM3yY7UlsewzrYJb/a6X9evBXr37irCl762srQPaur/dinvcDmRb/5WKd72+/AkzEFpm+T3Snv9ic+NKMfxSxMrdYC3xsP3ZNaP82DQQKzS/7VzutjQYtZlFrgz8ZDd3HqJqi/X2Aw8t+SdDoeGQjMaKs7MLSPS/qNDFquukXv9f6VBfemqhEiHH72Wr/VPaCVCKUosV4B/gTAegU7fX6w5P9YXm/rdFM261zAO312Zd69eDUAzC363/JOH+68Cht2LXDBeOhu6HpT9jtcYG7J3+K9XoSNYQGvO8YL7hmGO6yutcGiP1dON1d38MwO7KQLl4fufasBYPXbABt0h7xOyuwc9bTrtOuYTXr6D37P8T22CFPnzzRHQF5vCf5OjPUKdv78CVf64x/3eH2TryWd03a3odMuOZ0xvsztWQ0A0x98wuvOt5ed+GTXC+uRNv2FRT+3cUZf5hNZVPbwYk67HprozB8uuOXwh1gZQ4CvJTGU11HjEV9LHg4AfMJbB2jfj/LJrm/hx9yfT2RJ2MOKEojDnBKs4mtJAvTQkod8LXk4APAWIFQwwTo+2SVAl/hEloR97aIE4rWNEq8gPCcewJHKH/K15FEB4Knb/DH3bNZtks4y2n6Nbd0wHroLajy4hTPPjvzrnXSdhV7oYb+Ak167PHT8pmXjF2Iw8p+T9ELjbdbU3s3jvTpf29xDBw/9qAAw/T+eNPJPnEjflbSxJhmjZ/3KeOjONNpbNW3xqxlTo750PHTbTXVEM0cUGIz89ySdBlFygQdmHtIpu97ifvjITg4LANP/5+zIn+WkLyRvufIGxtN/WoMfJgQIASbG8Onx0J1rohOaCBbgX9cMpupt4b6JnrLncvedQwsc8QvM7DX+NLdPX5Z0Ym9dsfGRBL4+HrpnwmNLYLDoz5HTp211VU03nxgP3SuqOW1hBx2M/PTj5pzCjpXDce5zXs9fXnB/+1jNHvVXmAf+foAPyuu8HE5aRI9O14/n3euKOEuBh9i65J8zM9GH5PTkAo9n80j8Jlibc2nY1WDkr5L01oaPsbylgJNun5nRq+6+zN11pC3WfsW8zW+c3awrnNelcjq+ZS88trbAN5zT9uV59961l7IipcDskn+687pc0u+k7KP02tO/rlRO21cuc58q/ay1nG9uyV/ovS6R9LRazhz9nF4/9k7XPGGv3vnNbe6nR6u/dgA48PRJI3/6RKuDm/7kR0cCXrpb0vbJJm3fc7G7r6Nt2SaCwOyif6GcLnHS+RHK1VPC64tO2r684K6v59D1nHTLe/xxMw/u/1ripJPrOXmUk26fkbbvGrpvh1QLDgAHN1sNAtNvCbjVbws8L6QIaw4TeFDSR+S045hNuoW/3jfvGzL9tsAGr/O8Vj8m+JVNi3FOg7CTPjqRbtk9dLe02IJHMhM4ebt/wr59eqn3Os/t/9jhT561m+EOJ31y4nXLyoKb/qmL4B+NA8Ajd95ylR9s3KgzJtLmGWnz9L/O6djg6vUsvM9Le520d/rflZN1qy5w++o5fj0nnX57QF6nTj8e/PTjYfpfzye2Q2/AwY+HibR3Rto7XnA767klnPQwgem3mo/X2asfLwc+biQdh9SjBbzX/dOPl4MfN36jvjL9O/3bOq0rALQtynMIIIAAAgggkFaAAJDWn+oIIIAAAggkESAAJGGnKAIIIIAAAmkFCABp/amOAAIIIIBAEgECQBJ2iiKAAAIIIJBWgACQ1p/qCCCAAAIIJBEgACRhpygCCCCAAAJpBQgAaf2pjgACCCCAQBIBAkASdooigAACCCCQVoAAkNaf6ggggAACCCQRIAAkYacoAggggAACaQUIAGn9qY4AAggggEASAQJAEnaKIoAAAgggkFaAAJDWn+oIIIAAAggkESAAJGGnKAIIIIAAAmkFCABp/amOAAIIIIBAEgECQBJ2iiKAAAIIIJBWgACQ1p/qCCCAAAIIJBEgACRhpygCCCCAAAJpBQgAaf2pjgACCCCAQBIBAkASdooigAACCCCQVoAAkNaf6ggggAACCCQRIAAkYacoAggggAACaQUIAGn9qY4AAggggEASAQJAEnaKIoAAAgggkFaAAJDWn+oIIIAAAggkESAAJGGnKAIIIIAAAmkFCABp/amOAAIIIIBAEgECQBJ2iiKAAAIIIJBWgACQ1p/qCCCAAAIIJBEgACRhpygCCCCAAAJpBQgAaf2pjgACCCCAQBIBAkASdooigAACCCCQVoAAkNaf6ggggAACCCQRIAAkYacoAggggAACaQX+P2z2kkJaQra2AAAAAElFTkSuQmCC"); // shape.setImage("data:image/png;base64,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");
shape.setLabel("流程调用"); // shape.setLabel("流程调用");
shape.setName("FlowCall"); // shape.setName("FlowCall");
shape.setTitle("流程调用"); // shape.setTitle("流程调用");
return shape; // return shape;
} // }
//
@Override // @Override
public String supportShape() { // public String supportShape() {
return "FlowCall"; // return "FlowCall";
} // }
//
@Override // @Override
public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception { // public void execute(SpiderNode node, SpiderContext context, Map<String, Object> variables) throws Exception {
String flowId = node.getStringJsonValue(FLOW_ID); // String flowId = node.getStringJsonValue(FLOW_ID);
} // }
} //}
\ No newline at end of file \ No newline at end of file
...@@ -86,6 +86,10 @@ public class SpiderNode { ...@@ -86,6 +86,10 @@ public class SpiderNode {
return value; return value;
} }
public Object getObjectJsonValue(String key){
return this.jsonProperty.get(key);
}
public String getStringJsonValue(String key,String defaultValue){ public String getStringJsonValue(String key,String defaultValue){
String value = getStringJsonValue(key); String value = getStringJsonValue(key);
return StringUtils.isNotBlank(value) ? value : defaultValue; return StringUtils.isNotBlank(value) ? value : defaultValue;
......
...@@ -5,6 +5,9 @@ import com.alibaba.fastjson.JSONObject; ...@@ -5,6 +5,9 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.ttl.TtlRunnable; import com.alibaba.ttl.TtlRunnable;
import com.zq.spiderflow.concurrent.*; import com.zq.spiderflow.concurrent.*;
import com.zq.spiderflow.core.exception.RpaException; import com.zq.spiderflow.core.exception.RpaException;
import com.zq.spiderflow.core.model.Task;
import com.zq.spiderflow.core.service.SpiderFlowService;
import com.zq.spiderflow.core.service.TaskService;
import com.zq.spiderflow.core.utils.ExecutorsUtils; import com.zq.spiderflow.core.utils.ExecutorsUtils;
import com.zq.spiderflow.core.utils.ExpressionUtils; import com.zq.spiderflow.core.utils.ExpressionUtils;
import com.zq.spiderflow.core.utils.SpiderFlowUtils; import com.zq.spiderflow.core.utils.SpiderFlowUtils;
...@@ -16,7 +19,6 @@ import org.dom4j.DocumentHelper; ...@@ -16,7 +19,6 @@ import org.dom4j.DocumentHelper;
import org.dom4j.Element; import org.dom4j.Element;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.zq.spiderflow.concurrent.*;
import com.zq.spiderflow.concurrent.SpiderFlowThreadPoolExecutor.SubThreadPoolExecutor; import com.zq.spiderflow.concurrent.SpiderFlowThreadPoolExecutor.SubThreadPoolExecutor;
import com.zq.spiderflow.context.SpiderContext; import com.zq.spiderflow.context.SpiderContext;
import com.zq.spiderflow.context.SpiderContextHolder; import com.zq.spiderflow.context.SpiderContextHolder;
...@@ -49,399 +51,412 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -49,399 +51,412 @@ import java.util.concurrent.atomic.AtomicInteger;
@Component @Component
public class Spider { public class Spider {
@Autowired(required = false) @Autowired(required = false)
private List<SpiderListener> listeners; private List<SpiderListener> listeners;
@Value("${spider.thread.max}") @Value("${spider.thread.max}")
private Integer totalThreads; private Integer totalThreads;
@Value("${spider.thread.default}") @Value("${spider.thread.default}")
private Integer defaultThreads; private Integer defaultThreads;
@Value("${spider.detect.dead-cycle:5000}") @Value("${spider.detect.dead-cycle:5000}")
private Integer deadCycle; private Integer deadCycle;
@Autowired @Autowired
private FlowNoticeService flowNoticeService; private FlowNoticeService flowNoticeService;
public static SpiderFlowThreadPoolExecutor executorInstance; @Autowired
private SpiderFlowService spiderFlowService;
private static final String ATOMIC_DEAD_CYCLE = "__atomic_dead_cycle";
@Autowired
private static Logger logger = LoggerFactory.getLogger(Spider.class); private TaskService taskService;
@PostConstruct public static SpiderFlowThreadPoolExecutor executorInstance;
private void init() {
executorInstance = new SpiderFlowThreadPoolExecutor(totalThreads); private static final String ATOMIC_DEAD_CYCLE = "__atomic_dead_cycle";
}
private static Logger logger = LoggerFactory.getLogger(Spider.class);
public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, Map<String, Object> variables) {
if (variables == null) { @PostConstruct
variables = new HashMap<>(); private void init() {
} executorInstance = new SpiderFlowThreadPoolExecutor(totalThreads);
SpiderNode root = SpiderFlowUtils.loadXMLFromString(spiderFlow.getXml()); }
// 流程开始通知
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.startNotice); public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, Map<String, Object> variables) {
executeRoot(root, context, variables); if (variables == null) {
// 流程结束通知 variables = new HashMap<>();
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.endNotice); }
return context.getOutputs(); SpiderNode root = SpiderFlowUtils.loadXMLFromString(spiderFlow.getXml());
} // 流程开始通知
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.startNotice);
public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, Map<String, Object> variables, String body) { executeRoot(root, context, variables);
if (variables == null) { // 流程结束通知
variables = new HashMap<>(); flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.endNotice);
} return context.getOutputs();
SpiderNode root = SpiderFlowUtils.loadXMLFromString(spiderFlow.getXml()); }
replaceParam(root.getNextNodes(), JSONObject.parseObject(body));
// 流程开始通知 public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, Map<String, Object> variables, String body) {
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.startNotice); if (variables == null) {
executeRoot(root, context, variables); variables = new HashMap<>();
// 流程结束通知 }
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.endNotice); SpiderNode root = SpiderFlowUtils.loadXMLFromString(spiderFlow.getXml());
return context.getOutputs(); replaceParam(root.getNextNodes(), JSONObject.parseObject(body));
} // 流程开始通知
flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.startNotice);
public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context) { executeRoot(root, context, variables);
return run(spiderFlow, context, new HashMap<>()); // 流程结束通知
} flowNoticeService.sendFlowNotice(spiderFlow, FlowNoticeType.endNotice);
return context.getOutputs();
public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, String body) { }
return run(spiderFlow, context, new HashMap<>(), body);
} public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context) {
return run(spiderFlow, context, new HashMap<>());
public void runWithTest(SpiderNode root, SpiderContext context) { }
//将上下文存到ThreadLocal里,以便后续使用
SpiderContextHolder.set(context); public List<SpiderOutput> run(SpiderFlow spiderFlow, SpiderContext context, String body) {
//死循环检测的计数器(死循环检测只在测试时有效) return run(spiderFlow, context, new HashMap<>(), body);
AtomicInteger executeCount = new AtomicInteger(0); }
//存入到上下文中,以供后续检测
context.put(ATOMIC_DEAD_CYCLE, executeCount); public void runWithTest(SpiderNode root, SpiderContext context) {
//执行根节点 //将上下文存到ThreadLocal里,以便后续使用
executeRoot(root, context, new HashMap<>()); SpiderContextHolder.set(context);
//当爬虫任务执行完毕时,判断是否超过预期 //死循环检测的计数器(死循环检测只在测试时有效)
if (executeCount.get() > deadCycle) { AtomicInteger executeCount = new AtomicInteger(0);
logger.error("检测到可能出现死循环,测试终止"); //存入到上下文中,以供后续检测
} else { context.put(ATOMIC_DEAD_CYCLE, executeCount);
logger.info("测试完毕!"); Task task = new Task();
} task.setFlowId(context.getFlowId());
//将上下文从ThreadLocal移除,防止内存泄漏 task.setBeginTime(new Date());
SpiderContextHolder.remove(); //执行根节点
} executeRoot(root, context, new HashMap<>());
//当爬虫任务执行完毕时,判断是否超过预期
/** if (executeCount.get() > deadCycle) {
* 执行根节点 logger.error("检测到可能出现死循环,测试终止");
*/ } else {
private void executeRoot(SpiderNode root, SpiderContext context, Map<String, Object> variables) { logger.info("测试完毕!");
//获取当前流程执行线程数 }
int nThreads = NumberUtils.toInt(root.getStringJsonValue(ShapeExecutor.THREAD_COUNT), defaultThreads); Date date = new Date();
String strategy = root.getStringJsonValue("submit-strategy"); task.setEndTime(date);
ThreadSubmitStrategy submitStrategy; taskService.save(task);
//选择提交策略,这里一定要使用new,不能与其他实例共享 spiderFlowService.executeCountIncrement(context.getFlowId(), date, null);
if("linked".equalsIgnoreCase(strategy)){ //将上下文从ThreadLocal移除,防止内存泄漏
submitStrategy = new LinkedThreadSubmitStrategy(); SpiderContextHolder.remove();
}else if("child".equalsIgnoreCase(strategy)){ }
submitStrategy = new ChildPriorThreadSubmitStrategy();
}else if("parent".equalsIgnoreCase(strategy)){ /**
submitStrategy = new ParentPriorThreadSubmitStrategy(); * 执行根节点
}else{ */
submitStrategy = new RandomThreadSubmitStrategy(); private void executeRoot(SpiderNode root, SpiderContext context, Map<String, Object> variables) {
} //获取当前流程执行线程数
//创建子线程池,采用一父多子的线程池,子线程数不能超过总线程数(超过时进入队列等待),+1是因为会占用一个线程用来调度执行下一级 int nThreads = NumberUtils.toInt(root.getStringJsonValue(ShapeExecutor.THREAD_COUNT), defaultThreads);
SubThreadPoolExecutor pool = executorInstance.createSubThreadPoolExecutor(Math.max(nThreads,1) + 1,submitStrategy); String strategy = root.getStringJsonValue("submit-strategy");
context.setRootNode(root); ThreadSubmitStrategy submitStrategy;
context.setThreadPool(pool); //选择提交策略,这里一定要使用new,不能与其他实例共享
//触发监听器 if ("linked".equalsIgnoreCase(strategy)) {
if (listeners != null) { submitStrategy = new LinkedThreadSubmitStrategy();
listeners.forEach(listener -> listener.beforeStart(context)); } else if ("child".equalsIgnoreCase(strategy)) {
} submitStrategy = new ChildPriorThreadSubmitStrategy();
Comparator<SpiderNode> comparator = submitStrategy.comparator(); } else if ("parent".equalsIgnoreCase(strategy)) {
//启动一个线程开始执行任务,并监听其结束并执行下一级 submitStrategy = new ParentPriorThreadSubmitStrategy();
Future<?> f = pool.submitAsync(TtlRunnable.get(() -> { } else {
try { submitStrategy = new RandomThreadSubmitStrategy();
//执行具体节点 }
Spider.this.executeNode(null, root, context, variables); //创建子线程池,采用一父多子的线程池,子线程数不能超过总线程数(超过时进入队列等待),+1是因为会占用一个线程用来调度执行下一级
Queue<Future<?>> queue = context.getFutureQueue(); SubThreadPoolExecutor pool = executorInstance.createSubThreadPoolExecutor(Math.max(nThreads, 1) + 1, submitStrategy);
//循环从队列中获取Future,直到队列为空结束,当任务完成时,则执行下一级 context.setRootNode(root);
while (!queue.isEmpty()) { context.setThreadPool(pool);
try { //触发监听器
//TODO 这里应该是取出最先执行完毕的任务 if (listeners != null) {
Optional<Future<?>> max = queue.stream().filter(Future::isDone).max((o1, o2) -> { listeners.forEach(listener -> listener.beforeStart(context));
try { }
return comparator.compare(((SpiderTask) o1.get()).node, ((SpiderTask) o2.get()).node); Comparator<SpiderNode> comparator = submitStrategy.comparator();
} catch (InterruptedException | ExecutionException e) { //启动一个线程开始执行任务,并监听其结束并执行下一级
} Future<?> f = pool.submitAsync(TtlRunnable.get(() -> {
return 0; try {
//执行具体节点
}); Spider.this.executeNode(null, root, context, variables);
if (max.isPresent()) { //判断任务是否完成 Queue<Future<?>> queue = context.getFutureQueue();
queue.remove(max.get()); //循环从队列中获取Future,直到队列为空结束,当任务完成时,则执行下一级
if (context.isRunning()) { //检测是否运行中(当在页面中点击"停止"时,此值为false,其余为true) while (!queue.isEmpty()) {
SpiderTask task = (SpiderTask) max.get().get(); try {
task.node.decrement(); //任务执行完毕,计数器减一(该计数器是给Join节点使用) //TODO 这里应该是取出最先执行完毕的任务
if (task.executor.allowExecuteNext(task.node, context, task.variables)) { //判断是否允许执行下一级 Optional<Future<?>> max = queue.stream().filter(Future::isDone).max((o1, o2) -> {
logger.debug("执行节点[{}:{}]完毕", task.node.getNodeName(), task.node.getNodeId()); try {
//执行下一级 return comparator.compare(((SpiderTask) o1.get()).node, ((SpiderTask) o2.get()).node);
Spider.this.executeNextNodes(task.node, context, task.variables); } catch (InterruptedException | ExecutionException e) {
} else { }
logger.debug("执行节点[{}:{}]完毕,忽略执行下一节点", task.node.getNodeName(), task.node.getNodeId()); return 0;
}
} });
} if (max.isPresent()) { //判断任务是否完成
//睡眠1ms,让出cpu queue.remove(max.get());
Thread.sleep(1); if (context.isRunning()) { //检测是否运行中(当在页面中点击"停止"时,此值为false,其余为true)
} catch (InterruptedException ignored) { SpiderTask task = (SpiderTask) max.get().get();
} catch (Throwable t){ task.node.decrement(); //任务执行完毕,计数器减一(该计数器是给Join节点使用)
if (t.getCause() instanceof RpaException) { if (task.executor.allowExecuteNext(task.node, context, task.variables)) { //判断是否允许执行下一级
throw (RpaException)t.getCause(); logger.debug("执行节点[{}:{}]完毕", task.node.getNodeName(), task.node.getNodeId());
}else { //执行下一级
logger.error("程序发生异常",t); Spider.this.executeNextNodes(task.node, context, task.variables);
throw new RuntimeException(t); } else {
} logger.debug("执行节点[{}:{}]完毕,忽略执行下一节点", task.node.getNodeName(), task.node.getNodeId());
} }
} }
//等待线程池结束 }
pool.awaitTermination(); //睡眠1ms,让出cpu
} finally { Thread.sleep(1);
//触发监听器 } catch (InterruptedException ignored) {
if (listeners != null) { } catch (Throwable t) {
listeners.forEach(listener -> listener.afterEnd(context)); if (t.getCause() instanceof RpaException) {
} throw (RpaException) t.getCause();
} } else {
}), null, root); logger.error("程序发生异常", t);
try { throw new RuntimeException(t);
f.get(); //阻塞等待所有任务执行完毕 }
} catch (Exception e) { }
throw new RuntimeException(); }
} //等待线程池结束
} pool.awaitTermination();
} finally {
/** //触发监听器
* 执行下一级节点 if (listeners != null) {
*/ listeners.forEach(listener -> listener.afterEnd(context));
private void executeNextNodes(SpiderNode node, SpiderContext context, Map<String, Object> variables) { }
List<SpiderNode> nextNodes = node.getNextNodes(); }
if (nextNodes != null) { }), null, root);
for (SpiderNode nextNode : nextNodes) { try {
executeNode(node, nextNode, context, variables); f.get(); //阻塞等待所有任务执行完毕
} } catch (Exception e) {
} throw new RuntimeException();
} }
}
/**
* 执行节点 /**
*/ * 执行下一级节点
public void executeNode(SpiderNode fromNode, SpiderNode node, SpiderContext context, Map<String, Object> variables) { */
String shape = node.getStringJsonValue("shape"); private void executeNextNodes(SpiderNode node, SpiderContext context, Map<String, Object> variables) {
if (StringUtils.isBlank(shape)) { List<SpiderNode> nextNodes = node.getNextNodes();
executeNextNodes(node, context, variables); if (nextNodes != null) {
return; for (SpiderNode nextNode : nextNodes) {
} executeNode(node, nextNode, context, variables);
//判断箭头上的条件,如果不成立则不执行 }
if (!executeCondition(fromNode, node, variables, context)) { }
return; }
}
logger.debug("执行节点[{}:{}]", node.getNodeName(), node.getNodeId()); /**
//找到对应的执行器 * 执行节点
ShapeExecutor executor = ExecutorsUtils.get(shape); */
if (executor == null) { public void executeNode(SpiderNode fromNode, SpiderNode node, SpiderContext context, Map<String, Object> variables) {
logger.error("执行失败,找不到对应的执行器:{}", shape); String shape = node.getStringJsonValue("shape");
context.setRunning(false); if (StringUtils.isBlank(shape)) {
} executeNextNodes(node, context, variables);
int loopCount = 1; //循环次数默认为1,如果节点有循环属性且填了循环次数/集合,则取出循环次数 return;
int loopStart = 0; //循环起始位置 }
int loopEnd = 1; //循环结束位置 //判断箭头上的条件,如果不成立则不执行
String loopCountStr = node.getStringJsonValue(ShapeExecutor.LOOP_COUNT); if (!executeCondition(fromNode, node, variables, context)) {
Object loopArray = null; return;
boolean isLoop = false; }
if (isLoop = StringUtils.isNotBlank(loopCountStr)) { logger.debug("执行节点[{}:{}]", node.getNodeName(), node.getNodeId());
try { //找到对应的执行器
loopArray = ExpressionUtils.execute(loopCountStr, variables); ShapeExecutor executor = ExecutorsUtils.get(shape);
if(loopArray == null){ if (executor == null) {
loopCount = 0; logger.error("执行失败,找不到对应的执行器:{}", shape);
}else if(loopArray instanceof Collection){ context.setRunning(false);
loopCount = ((Collection)loopArray).size(); }
loopArray = ((Collection)loopArray).toArray(); int loopCount = 1; //循环次数默认为1,如果节点有循环属性且填了循环次数/集合,则取出循环次数
}else if(loopArray.getClass().isArray()){ int loopStart = 0; //循环起始位置
loopCount = Array.getLength(loopArray); int loopEnd = 1; //循环结束位置
}else{ String loopCountStr = node.getStringJsonValue(ShapeExecutor.LOOP_COUNT);
loopCount = NumberUtils.toInt(loopArray.toString(),0); Object loopArray = null;
loopArray = null; boolean isLoop = false;
} if (isLoop = StringUtils.isNotBlank(loopCountStr)) {
loopEnd = loopCount; try {
if(loopCount > 0){ loopArray = ExpressionUtils.execute(loopCountStr, variables);
loopStart = Math.max(NumberUtils.toInt(node.getStringJsonValue(LoopExecutor.LOOP_START), 0),0); if (loopArray == null) {
int end = NumberUtils.toInt(node.getStringJsonValue(LoopExecutor.LOOP_END), -1); loopCount = 0;
if(end >=0){ } else if (loopArray instanceof Collection) {
loopEnd = Math.min(end,loopEnd); loopCount = ((Collection) loopArray).size();
}else{ loopArray = ((Collection) loopArray).toArray();
loopEnd = Math.max(loopEnd + end + 1,0); } else if (loopArray.getClass().isArray()) {
} loopCount = Array.getLength(loopArray);
} } else {
logger.info("获取循环次数{}={}", loopCountStr, loopCount); loopCount = NumberUtils.toInt(loopArray.toString(), 0);
} catch (Throwable t) { loopArray = null;
loopCount = 0; }
logger.error("获取循环次数失败,异常信息:{}", t); loopEnd = loopCount;
} if (loopCount > 0) {
} loopStart = Math.max(NumberUtils.toInt(node.getStringJsonValue(LoopExecutor.LOOP_START), 0), 0);
if (loopCount > 0) { int end = NumberUtils.toInt(node.getStringJsonValue(LoopExecutor.LOOP_END), -1);
//获取循环下标的变量名称 if (end >= 0) {
String loopVariableName = node.getStringJsonValue(ShapeExecutor.LOOP_VARIABLE_NAME); loopEnd = Math.min(end, loopEnd);
String loopItem = node.getStringJsonValue(LoopExecutor.LOOP_ITEM,"item"); } else {
List<SpiderTask> tasks = new ArrayList<>(); loopEnd = Math.max(loopEnd + end + 1, 0);
for (int i = loopStart; i < loopEnd; i++) { }
node.increment(); //节点执行次数+1(后续Join节点使用) }
if (context.isRunning()) { logger.info("获取循环次数{}={}", loopCountStr, loopCount);
Map<String, Object> nVariables = new HashMap<>(); } catch (Throwable t) {
// 判断是否需要传递变量 loopCount = 0;
if(fromNode == null || node.isTransmitVariable(fromNode.getNodeId())){ logger.error("获取循环次数失败,异常信息:{}", t);
nVariables.putAll(variables); }
} }
if(isLoop){ if (loopCount > 0) {
// 存入下标变量 //获取循环下标的变量名称
if (!StringUtils.isBlank(loopVariableName)) { String loopVariableName = node.getStringJsonValue(ShapeExecutor.LOOP_VARIABLE_NAME);
nVariables.put(loopVariableName, i); String loopItem = node.getStringJsonValue(LoopExecutor.LOOP_ITEM, "item");
} List<SpiderTask> tasks = new ArrayList<>();
// 存入item for (int i = loopStart; i < loopEnd; i++) {
nVariables.put(loopItem,loopArray == null ? i : Array.get(loopArray, i)); node.increment(); //节点执行次数+1(后续Join节点使用)
} if (context.isRunning()) {
tasks.add(new SpiderTask(TtlRunnable.get(() -> { Map<String, Object> nVariables = new HashMap<>();
if (context.isRunning()) { // 判断是否需要传递变量
try { if (fromNode == null || node.isTransmitVariable(fromNode.getNodeId())) {
//死循环检测,当执行节点次数大于阈值时,结束本次测试 nVariables.putAll(variables);
AtomicInteger executeCount = context.get(ATOMIC_DEAD_CYCLE); }
if (executeCount != null && executeCount.incrementAndGet() > deadCycle) { if (isLoop) {
context.setRunning(false); // 存入下标变量
return; if (!StringUtils.isBlank(loopVariableName)) {
} nVariables.put(loopVariableName, i);
//执行节点具体逻辑 }
executor.execute(node, context, nVariables); // 存入item
//当未发生异常时,移除ex变量 nVariables.put(loopItem, loopArray == null ? i : Array.get(loopArray, i));
nVariables.remove("ex"); }
} catch (RpaException e){ tasks.add(new SpiderTask(TtlRunnable.get(() -> {
nVariables.put("ex", e); if (context.isRunning()) {
throw e; try {
}catch (Throwable t) { //死循环检测,当执行节点次数大于阈值时,结束本次测试
nVariables.put("ex", t); AtomicInteger executeCount = context.get(ATOMIC_DEAD_CYCLE);
logger.error("执行节点[{}:{}]出错,异常信息:{}", node.getNodeName(), node.getNodeId(), t); if (executeCount != null && executeCount.incrementAndGet() > deadCycle) {
throw new RuntimeException(t.getMessage()); context.setRunning(false);
} return;
} }
}), node, nVariables, executor)); //执行节点具体逻辑
} executor.execute(node, context, nVariables);
} //当未发生异常时,移除ex变量
LinkedBlockingQueue<Future<?>> futureQueue = context.getFutureQueue(); nVariables.remove("ex");
for (SpiderTask task : tasks) { } catch (RpaException e) {
if(executor.isThread()){ //判断节点是否是异步运行 nVariables.put("ex", e);
//提交任务至线程池中,并将Future添加到队列末尾 throw e;
futureQueue.add(context.getThreadPool().submitAsync(task.runnable, task, node)); } catch (Throwable t) {
}else{ nVariables.put("ex", t);
FutureTask<SpiderTask> futureTask = new FutureTask<>(task.runnable, task); logger.error("执行节点[{}:{}]出错,异常信息:{}", node.getNodeName(), node.getNodeId(), t);
futureTask.run(); throw new RuntimeException(t.getMessage());
futureQueue.add(futureTask); }
} }
} }), node, nVariables, executor));
} }
} }
LinkedBlockingQueue<Future<?>> futureQueue = context.getFutureQueue();
/** for (SpiderTask task : tasks) {
* 判断箭头上的表达式是否成立 if (executor.isThread()) { //判断节点是否是异步运行
*/ //提交任务至线程池中,并将Future添加到队列末尾
private boolean executeCondition(SpiderNode fromNode, SpiderNode node, Map<String, Object> variables, SpiderContext context) { futureQueue.add(context.getThreadPool().submitAsync(task.runnable, task, node));
if (fromNode != null) { } else {
boolean hasException = variables.get("ex") != null; FutureTask<SpiderTask> futureTask = new FutureTask<>(task.runnable, task);
String exceptionFlow = node.getExceptionFlow(fromNode.getNodeId()); futureTask.run();
//当出现异常流转 : 1 futureQueue.add(futureTask);
//未出现异常流转 : 2 }
if(("1".equalsIgnoreCase(exceptionFlow) && !hasException) || ("2".equalsIgnoreCase(exceptionFlow) && hasException)){ }
return false; }
} }
String condition = node.getCondition(fromNode.getNodeId());
if (StringUtils.isNotBlank(condition)) { // 判断是否有条件 /**
Object result = null; * 判断箭头上的表达式是否成立
try { */
result = ExpressionUtils.execute(condition, variables); private boolean executeCondition(SpiderNode fromNode, SpiderNode node, Map<String, Object> variables, SpiderContext context) {
} catch (Exception e) { if (fromNode != null) {
logger.error("判断{}出错,异常信息:{}", condition, e); boolean hasException = variables.get("ex") != null;
} String exceptionFlow = node.getExceptionFlow(fromNode.getNodeId());
if (result != null) { //当出现异常流转 : 1
boolean isContinue = "true".equals(result) || Objects.equals(result, true); //未出现异常流转 : 2
logger.debug("判断{}={}", condition, isContinue); if (("1".equalsIgnoreCase(exceptionFlow) && !hasException) || ("2".equalsIgnoreCase(exceptionFlow) && hasException)) {
return isContinue; return false;
} }
return false; String condition = node.getCondition(fromNode.getNodeId());
} if (StringUtils.isNotBlank(condition)) { // 判断是否有条件
} Object result = null;
return true; try {
} result = ExpressionUtils.execute(condition, variables);
} catch (Exception e) {
public void replaceParam(List<SpiderNode> nodes, JSONObject paramJson){ logger.error("判断{}出错,异常信息:{}", condition, e);
for (SpiderNode node : nodes) { }
JSONObject jsonObject = new JSONObject(node.getJsonProperty()); if (result != null) {
if (jsonObject.containsKey("variable-name")) { boolean isContinue = "true".equals(result) || Objects.equals(result, true);
JSONArray jsonArray = jsonObject.getJSONArray("variable-name"); logger.debug("判断{}={}", condition, isContinue);
JSONArray valueArray = jsonObject.getJSONArray("variable-value"); return isContinue;
for (int i = 0; i < jsonArray.size(); i++) { }
String name = (String) jsonArray.get(i); return false;
if (paramJson.containsKey(name)) { }
valueArray.set(i, paramJson.get(name)); }
} return true;
} }
System.out.println(jsonObject);
} public void replaceParam(List<SpiderNode> nodes, JSONObject paramJson) {
replaceParam(node.getNextNodes(), paramJson); for (SpiderNode node : nodes) {
} JSONObject jsonObject = new JSONObject(node.getJsonProperty());
} if (jsonObject.containsKey("variable-name")) {
JSONArray jsonArray = jsonObject.getJSONArray("variable-name");
public String updateXml(String xml, String json){ JSONArray valueArray = jsonObject.getJSONArray("variable-value");
JSONObject jsonObject = JSONObject.parseObject(json); for (int i = 0; i < jsonArray.size(); i++) {
String name = (String) jsonArray.get(i);
Document document; if (paramJson.containsKey(name)) {
try { valueArray.set(i, paramJson.get(name));
document = DocumentHelper.parseText(xml); }
} catch (DocumentException e) { }
throw new RpaException("流程错误,请检查流程"); System.out.println(jsonObject);
} }
Element rootElement = document.getRootElement(); replaceParam(node.getNextNodes(), paramJson);
List<Element> elements = rootElement.elements().get(0).elements(); }
for (Element element : elements) { }
List<Element> elems = element.elements();
for (Element elem : elems) { public String updateXml(String xml, String json) {
if("JsonProperty".equals(elem.getName().trim())){ JSONObject jsonObject = JSONObject.parseObject(json);
JSONObject object = JSONObject.parseObject(elem.getText().trim());
if (object.containsKey("variable-name")) { Document document;
JSONArray jsonArray = object.getJSONArray("variable-name"); try {
JSONArray valueArray = object.getJSONArray("variable-value"); document = DocumentHelper.parseText(xml);
for (int i = 0; i < jsonArray.size(); i++) { } catch (DocumentException e) {
String name = (String) jsonArray.get(i); throw new RpaException("流程错误,请检查流程");
if (jsonObject.containsKey(name)) { }
valueArray.set(i, jsonObject.get(name)); Element rootElement = document.getRootElement();
} List<Element> elements = rootElement.elements().get(0).elements();
} for (Element element : elements) {
elem.setText(JSONObject.toJSONString(object)); List<Element> elems = element.elements();
} for (Element elem : elems) {
} if ("JsonProperty".equals(elem.getName().trim())) {
} JSONObject object = JSONObject.parseObject(elem.getText().trim());
} if (object.containsKey("variable-name")) {
JSONArray jsonArray = object.getJSONArray("variable-name");
return document.asXML(); JSONArray valueArray = object.getJSONArray("variable-value");
} for (int i = 0; i < jsonArray.size(); i++) {
String name = (String) jsonArray.get(i);
class SpiderTask{ if (jsonObject.containsKey(name)) {
valueArray.set(i, jsonObject.get(name));
Runnable runnable; }
}
SpiderNode node; elem.setText(JSONObject.toJSONString(object));
}
Map<String,Object> variables; }
}
ShapeExecutor executor; }
public SpiderTask(Runnable runnable, SpiderNode node, Map<String, Object> variables,ShapeExecutor executor) { return document.asXML();
this.runnable = runnable; }
this.node = node;
this.variables = variables; class SpiderTask {
this.executor = executor;
} Runnable runnable;
}
SpiderNode node;
Map<String, Object> variables;
ShapeExecutor executor;
public SpiderTask(Runnable runnable, SpiderNode node, Map<String, Object> variables, ShapeExecutor executor) {
this.runnable = runnable;
this.node = node;
this.variables = variables;
this.executor = executor;
}
}
} }
...@@ -38,24 +38,24 @@ public class WebSocketEditorServer { ...@@ -38,24 +38,24 @@ public class WebSocketEditorServer {
context.setDebug(isDebug); context.setDebug(isDebug);
context.setRunning(true); context.setRunning(true);
String flowId = event.getString("flowId"); String flowId = event.getString("flowId");
if(StrUtil.isBlank(flowId)){ if (StrUtil.isBlank(flowId)) {
context.write(new WebSocketEvent<>("error", "flowId不能为空!")); context.write(new WebSocketEvent<>("error", "flowId不能为空!"));
} }
context.setFlowId(flowId); context.setFlowId(flowId);
// new Thread(() -> { // new Thread(() -> {
String xml = event.getString("message"); String xml = event.getString("message");
if (xml != null) { if (xml != null) {
spider. runWithTest(SpiderFlowUtils.loadXMLFromString(xml), context); spider.runWithTest(SpiderFlowUtils.loadXMLFromString(xml), context);
context.write(new WebSocketEvent<>("finish", null)); context.write(new WebSocketEvent<>("finish", null));
} else { } else {
context.write(new WebSocketEvent<>("error", "xml不正确!")); context.write(new WebSocketEvent<>("error", "xml不正确!"));
} }
context.setRunning(false); context.setRunning(false);
// }).start(); // }).start();
} else if ("stop".equals(eventType) && context != null) { } else if ("stop".equals(eventType) && context != null) {
context.setRunning(false); context.setRunning(false);
context.stop(); context.stop();
} else if("resume".equalsIgnoreCase(eventType) && context != null){ } else if ("resume".equalsIgnoreCase(eventType) && context != null) {
context.resume(); context.resume();
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment