diff --git a/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/RemoteDataToEsService.java b/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/RemoteDataToEsService.java index 92fa899f..a96344a3 100644 --- a/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/RemoteDataToEsService.java +++ b/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/RemoteDataToEsService.java @@ -4,8 +4,15 @@ import org.dromara.common.core.domain.R; import org.dromara.data2es.api.domain.RemoteGpsInfo; import java.util.List; +import java.util.concurrent.ExecutionException; public interface RemoteDataToEsService { R saveDataBatch(List gpsInfoList); + + R saveData(RemoteGpsInfo gpsInfo) throws Exception; + + R updateOnlineStatusBatch(List gpsInfoList); + + R updateOnlineStatus(RemoteGpsInfo gpsInfo); } diff --git a/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/domain/RemoteGpsInfo.java b/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/domain/RemoteGpsInfo.java index a1ed9279..598c0a2f 100644 --- a/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/domain/RemoteGpsInfo.java +++ b/stwzhj-api/stwzhj-api-data2es/src/main/java/org/dromara/data2es/api/domain/RemoteGpsInfo.java @@ -22,8 +22,8 @@ public class RemoteGpsInfo implements Serializable { * 类型 */ private String deviceType; - private String latitude; - private String longitude; + private String lat; + private String lng; //方向 private String orientation; //高程 diff --git a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java index 095fd7c8..97050b22 100644 --- a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java +++ b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/RemoteDeptService.java @@ -1,5 +1,10 @@ package org.dromara.system.api; +import org.dromara.system.api.domain.bo.RemoteDeptBo; +import org.dromara.system.api.domain.vo.RemoteDeptVo; + +import java.util.List; + /** * 部门服务 * @@ -15,4 +20,6 @@ public interface RemoteDeptService { */ String selectDeptNameByIds(String deptIds); + List selectDept(RemoteDeptBo bo); + } diff --git a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeptBo.java b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeptBo.java new file mode 100644 index 00000000..2ee6c9dc --- /dev/null +++ b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeptBo.java @@ -0,0 +1,70 @@ +package org.dromara.system.api.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 部门业务对象 sys_dept + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +public class RemoteDeptBo implements Serializable { + + /** + * 部门id + */ + private String deptId; + + /** + * 父部门ID + */ + private String parentId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + + private String fullName; + +} diff --git a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeviceBo.java b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeviceBo.java index 2a49aa1e..0a113cb3 100644 --- a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeviceBo.java +++ b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/bo/RemoteDeviceBo.java @@ -87,6 +87,8 @@ public class RemoteDeviceBo implements Serializable { private String updateTime; + private String[] zzjgdms; + /** * 备注字段2 */ diff --git a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java new file mode 100644 index 00000000..ca96413b --- /dev/null +++ b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/domain/vo/RemoteDeptVo.java @@ -0,0 +1,96 @@ +package org.dromara.system.api.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 部门视图对象 sys_dept + * + * @author Michelle.Chung + */ +@Data +public class RemoteDeptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + private String deptId; + + /** + * 父部门id + */ + private String parentId; + + /** + * 父部门名称 + */ + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人ID + */ + private Long leader; + + /** + * 负责人 + */ + private String leaderName; + + /** + * 联系电话 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + + /** + * 创建时间 + */ + private Date createTime; + + private Integer allCount; + + private Integer onlineCount; + + private String fullName; + +} diff --git a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/model/LoginUser.java b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/model/LoginUser.java index b6c1fce0..2af448d4 100644 --- a/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/model/LoginUser.java +++ b/stwzhj-api/stwzhj-api-system/src/main/java/org/dromara/system/api/model/LoginUser.java @@ -130,6 +130,8 @@ public class LoginUser implements Serializable { */ private String deviceType; + private String manageDeptId; + /** * 获取登录id */ diff --git a/stwzhj-auth/src/main/resources/application.yml b/stwzhj-auth/src/main/resources/application.yml index bb4d0cf1..35e4a1bd 100644 --- a/stwzhj-auth/src/main/resources/application.yml +++ b/stwzhj-auth/src/main/resources/application.yml @@ -6,7 +6,7 @@ server: spring: application: # 应用名称 - name: stwzhj-auth + name: wzhj-auth profiles: # 环境配置 active: @profiles.active@ diff --git a/stwzhj-common/stwzhj-common-core/src/main/java/org/dromara/common/core/utils/RedisConstants.java b/stwzhj-common/stwzhj-common-core/src/main/java/org/dromara/common/core/utils/RedisConstants.java index 828ca4c5..6647cd24 100644 --- a/stwzhj-common/stwzhj-common-core/src/main/java/org/dromara/common/core/utils/RedisConstants.java +++ b/stwzhj-common/stwzhj-common-core/src/main/java/org/dromara/common/core/utils/RedisConstants.java @@ -21,8 +21,12 @@ public class RedisConstants { public static final long REDIS_ONLINE_USER_NEVER_EXPIRE = -1; + public static final long REDIS_NEVER_EXPIRE = 0L; + public static final long FIVE_MINUTES_REDIS_ONLINE_USER_EXPIRE_TIME = 60 * 5; + public static final String ONLINE_USERS_TEN = "ten:online_users:"; + public static String getUserTokenKey(String token) { return CCL_CODING_SSO_TOKEN + token; diff --git a/stwzhj-common/stwzhj-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/stwzhj-common/stwzhj-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java index 5a30d687..c5bb49b4 100644 --- a/stwzhj-common/stwzhj-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java +++ b/stwzhj-common/stwzhj-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -38,12 +38,12 @@ public enum DataScopeType { /** * 部门数据权限 */ - DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "), + DEPT("3", " #{#deptName} = #{#user.manageDeptId} ", " 1 = 0 "), /** * 部门及以下数据权限 */ - DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "), + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.manageDeptId )} )", " 1 = 0 "), /** * 仅本人数据权限 diff --git a/stwzhj-common/stwzhj-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java b/stwzhj-common/stwzhj-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java index 30d6b5c5..a7f0e8af 100644 --- a/stwzhj-common/stwzhj-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java +++ b/stwzhj-common/stwzhj-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java @@ -1,9 +1,11 @@ package org.dromara.common.redis.utils; +import cn.hutool.core.date.DateUnit; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.RedisConstants; import org.dromara.common.core.utils.SpringUtils; import org.redisson.api.*; import org.springframework.dao.DataAccessException; @@ -345,6 +347,29 @@ public class RedisUtils { return rSet.add(data); } + public static void set(final String key, String data,long time) { + if (time > 0){ + CLIENT.getBucket(key).set(data, time, TimeUnit.SECONDS); + }else { + CLIENT.getBucket(key).set(data); + } + + /*RSet rSet = CLIENT.getSet(key); + if (time > 0){ + rSet.expireAsync(time,TimeUnit.SECONDS); + } + return rSet.add(data);*/ + } + + public static void del(final String key) { + CLIENT.getBucket(key).delete(); + /*RSet rSet = CLIENT.getSet(key); + if (time > 0){ + rSet.expireAsync(time,TimeUnit.SECONDS); + } + return rSet.add(data);*/ + } + /** * 注册Set监听器 *

@@ -669,24 +694,25 @@ public class RedisUtils { * @param pattern 模糊匹配的模式,例如 "user:*" * @return 匹配到的 key 和 value 对 */ - public Map getMatchingKeysAndValues(String pattern) { + public static List getMatchingKeysAndValues(String pattern) { RKeys rKeys = CLIENT.getKeys(); Iterable keysIterable = rKeys.getKeysByPattern(pattern); // 获取匹配的 key // 获取匹配的键值对 RMap map = CLIENT.getMap("myMap"); - Map result = new java.util.HashMap<>(); List list = new ArrayList<>(); // RBatch batch = CLIENT.createBatch(); // 批量获取这些key的值 for (String key : keysIterable) { String value = map.get(key); // 获取每个 key 对应的 value - JSONObject jsonObject = JSONUtil.parseObj(value); - list.add(jsonObject); + if (null != value){ + JSONObject jsonObject = JSONUtil.parseObj(value); + list.add(jsonObject); + } } - return result; + return list; } /* @@ -719,12 +745,10 @@ public class RedisUtils { /* * 批量插入GEO数据 * */ - /*public static void batchGeoAdd(Map entryMap){ - RGeo> geo = CLIENT.getGeo("myGeo"); - Map entries = new HashMap<>(); - entries.put("place1", new GeoEntry(13.361389, 38.115556, "Palermo")); - entries.put("place2", new GeoEntry(15.087269, 37.502669, "Catania")); - geo.p(entries); - }*/ + public static long geoAdd(Double lng,Double lat,String member){ + RGeo geo = CLIENT.getGeo(RedisConstants.ONLINE_USERS_GEO); + long count1 = geo.add(lng, lat, member); + return count1; + } } diff --git a/stwzhj-common/stwzhj-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/stwzhj-common/stwzhj-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java index 896d3726..685480e7 100644 --- a/stwzhj-common/stwzhj-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java +++ b/stwzhj-common/stwzhj-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java @@ -36,6 +36,8 @@ public class LoginHelper { public static final String USER_NAME_KEY = "userName"; public static final String DEPT_KEY = "deptId"; public static final String DEPT_NAME_KEY = "deptName"; + + public static final String MANAGE_DEPT__KEY = "manageDeptId"; public static final String DEPT_CATEGORY_KEY = "deptCategory"; public static final String CLIENT_KEY = "clientid"; @@ -53,6 +55,7 @@ public class LoginHelper { .setExtra(USER_KEY, loginUser.getUserId()) .setExtra(USER_NAME_KEY, loginUser.getUsername()) .setExtra(DEPT_KEY, loginUser.getDeptId()) + .setExtra(MANAGE_DEPT__KEY,loginUser.getManageDeptId()) .setExtra(DEPT_NAME_KEY, loginUser.getDeptName()) .setExtra(DEPT_CATEGORY_KEY, loginUser.getDeptCategory()) ); diff --git a/stwzhj-gateway/src/main/java/org/dromara/gateway/filter/GlobalCacheRequestFilter.java b/stwzhj-gateway/src/main/java/org/dromara/gateway/filter/GlobalCacheRequestFilter.java index 09e50ff2..92885c2a 100644 --- a/stwzhj-gateway/src/main/java/org/dromara/gateway/filter/GlobalCacheRequestFilter.java +++ b/stwzhj-gateway/src/main/java/org/dromara/gateway/filter/GlobalCacheRequestFilter.java @@ -23,6 +23,7 @@ public class GlobalCacheRequestFilter implements GlobalFilter, Ordered { if (!WebFluxUtils.isJsonRequest(exchange)) { return chain.filter(exchange); } + return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> { if (serverHttpRequest == exchange.getRequest()) { return chain.filter(exchange); diff --git a/stwzhj-gateway/src/main/resources/application.yml b/stwzhj-gateway/src/main/resources/application.yml index 229dc16a..49897aaf 100644 --- a/stwzhj-gateway/src/main/resources/application.yml +++ b/stwzhj-gateway/src/main/resources/application.yml @@ -8,7 +8,7 @@ server: spring: application: # 应用名称 - name: stwzhj-gateway + name: wzhj-gateway profiles: # 环境配置 active: @profiles.active@ diff --git a/stwzhj-modules/pom.xml b/stwzhj-modules/pom.xml index f057905b..132b6144 100644 --- a/stwzhj-modules/pom.xml +++ b/stwzhj-modules/pom.xml @@ -19,6 +19,9 @@ stwzhj-consumer stwzhj-location stwzhj-dataToGas + wzhj-webscoket + wzhj-extract + wzhj-udp stwzhj-modules diff --git a/stwzhj-modules/stwzhj-consumer/src/main/java/org/dromara/kafka/consumer/handler/ConsumerWorker.java b/stwzhj-modules/stwzhj-consumer/src/main/java/org/dromara/kafka/consumer/handler/ConsumerWorker.java index 0aa0bc3a..b906fcd5 100644 --- a/stwzhj-modules/stwzhj-consumer/src/main/java/org/dromara/kafka/consumer/handler/ConsumerWorker.java +++ b/stwzhj-modules/stwzhj-consumer/src/main/java/org/dromara/kafka/consumer/handler/ConsumerWorker.java @@ -92,12 +92,12 @@ public class ConsumerWorker { logger.info("deviceCode:{} is null or is too long ",deviceCode); return; } - String latitude = esGpsInfo.getLatitude(); + String latitude = esGpsInfo.getLat(); if(StringUtils.isEmpty(latitude) || "0.0".equals(latitude)){ logger.info("latitude:{} is null or is zero ",latitude); return; } - String longitude = esGpsInfo.getLongitude(); + String longitude = esGpsInfo.getLng(); if(StringUtils.isEmpty(longitude) || "0.0".equals(longitude)){ logger.info("longitude:{} is null or is zero ",longitude); return; diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/ElasticsearchConfig.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/ElasticsearchConfig.java index 44217c19..a41e0289 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/ElasticsearchConfig.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/ElasticsearchConfig.java @@ -68,7 +68,7 @@ public class ElasticsearchConfig { RestClientBuilder builder = RestClient.builder(httpHost); // 设置用户名、密码 CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password)); +// credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password)); // 连接延时配置 builder.setRequestConfigCallback(requestConfigBuilder -> { requestConfigBuilder.setConnectTimeout(connectTimeOut); diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/KafkaConfig.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/KafkaConfig.java index 9ccb8af0..fedb34ec 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/KafkaConfig.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/config/KafkaConfig.java @@ -27,8 +27,8 @@ public class KafkaConfig { // private String kafkaServers = "140.168.2.31:21007,140.168.2.32:21007,140.168.2.33:21007"; // private String kafkaServers = "53.208.61.105:6667,53.208.61.106:6667,53.208.61.107:6667";//六安GA网 // private String kafkaServers = "34.72.62.93:9092";//六安视频网 -// private String kafkaServers = "127.0.0.1:9092";//本地 - private String kafkaServers = "53.207.8.71:9092,53.193.3.15:9092,53.160.0.237:9092,53.104.56.58:9092,53.128.22.61:9092";//省厅 马伟提供 + private String kafkaServers = "127.0.0.1:9092";//本地 +// private String kafkaServers = "53.238.79.4:9092,53.238.79.5:9092,53.238.79.6:9092";//省厅 马伟提供 private String groupId = "ruansiProducer"; @@ -128,9 +128,9 @@ public class KafkaConfig { // props.put(kerberosDomainName, "hadoop.hadoop.com"); //设置自定义的分区策略类,默认不传key,是粘性分区,尽量往一个分区中发消息。如果key不为null,则默认是按照key的hashcode与 partition的取余来决定哪个partition //props.put("partitioner.class","com.kafka.myparitioner.CidPartitioner"); - props.put(securityProtocol, "SASL_PLAINTEXT"); + /*props.put(securityProtocol, "SASL_PLAINTEXT"); props.put("sasl.jaas.config", "org.apache.kafka.common.security.scram.ScramLoginModule required username=\"zkxc\" password=\"zkxcKafka07252023\";"); - props.put("sasl.mechanism", "SCRAM-SHA-256"); + props.put("sasl.mechanism", "SCRAM-SHA-256");*/ KafkaProducer producer = new KafkaProducer<>(props); // KafkaProducer producer = new KafkaProducer<>(props); diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/controller/DataToEsController.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/controller/DataToEsController.java index 66a88528..9a03e581 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/controller/DataToEsController.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/controller/DataToEsController.java @@ -32,11 +32,6 @@ public class DataToEsController extends BaseController { public R saveGpsInfo(@RequestBody EsGpsInfoVO2 esGpsInfo ){ R apiResponse = new R<>(); try { - if(StringUtils.isBlank(esGpsInfo.getInfoSource())){ - apiResponse.setCode(500); - apiResponse.setMsg("infoSource为空"); - return apiResponse; - } boolean offer = linkedBlockingDeque.offer(esGpsInfo); apiResponse = R.ok(offer); } catch (Exception e) { @@ -87,16 +82,15 @@ public class DataToEsController extends BaseController { EsGpsInfoVO2 esGpsInfo = new EsGpsInfoVO2(); HashMap map = new HashMap<>(); - esGpsInfo.setDeviceCode("34153800001320000101"); - esGpsInfo.setDeviceType("05"); - esGpsInfo.setInfoSource("3401"); + esGpsInfo.setDeviceCode("34180201001310000071"); + esGpsInfo.setDeviceType("5"); esGpsInfo.setGpsTime(new Date()); - esGpsInfo.setLatitude("31.1" + (a + i)); - esGpsInfo.setLongitude("117.2" + (b + i)); - esGpsInfo.setZzjgdm("340100000000"); - esGpsInfo.setZzjgmc("合肥市公安局"); - esGpsInfo.setCarNum("霍邱看守所01"); + esGpsInfo.setLat("30.68" + (a + i)); + esGpsInfo.setLng("118.40" + (b + i)); + esGpsInfo.setZzjgdm("341802400000"); + esGpsInfo.setZzjgmc("宣州分局济川派出所"); + esGpsInfo.setPoliceName("057486_郭超"); saveGpsInfo(esGpsInfo); //gpsService.saveData(map); diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/DSQinwuEntity.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/DSQinwuEntity.java new file mode 100644 index 00000000..0ac9624a --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/DSQinwuEntity.java @@ -0,0 +1,32 @@ +package org.dromara.data2es.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** + *

description:

+ * + * @author chenle + * @date 2023-03-22 9:51 + */ +@Data +@TableName("td_ds_qinwu") +public class DSQinwuEntity { + private int id; + private String category; + private String linkId;//外部系统id + private String imei; + private boolean majorPersonTerminal; + private boolean majorVehicleTerminal; + private String name; + private String orgId; + private String orgName; + private String type; + //时间戳 + private Date updateTime; + private String policeNumber; + + private String policeName; +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/EsGpsInfo.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/EsGpsInfo.java index 342d0623..d585b0ba 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/EsGpsInfo.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/EsGpsInfo.java @@ -15,8 +15,8 @@ public class EsGpsInfo implements Serializable { */ private String deviceCode; private String deviceType; - private String latitude; - private String longitude; + private String lat; + private String lng; //方向 private String orientation; //高程 @@ -28,7 +28,6 @@ public class EsGpsInfo implements Serializable { @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") private Date gpsTime; //3401 ,3402 地市代码 - private String infoSource; private Integer online; diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/DSResponse.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/DSResponse.java new file mode 100644 index 00000000..17dfacb4 --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/DSResponse.java @@ -0,0 +1,176 @@ +package org.dromara.data2es.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + *

description:

+ * + * @author chenle + * @date 2023-03-20 11:53 + */ +@Data +public class DSResponse { + + /** + * msg : Success + * ret : ok + * dataStore : [{"category":"SCZD","id":"SCZD","imei":"SCZD","majorPersonTerminal":false,"majorVehicleTerminal":false,"name":"SCZD","orgId":"SCZD","orgName":"SCZD","type":"SCZD"}] + */ + + private String msg; + private String ret; + private List dataStore; + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public String getRet() { + return ret; + } + + public void setRet(String ret) { + this.ret = ret; + } + + public List getDataStore() { + return dataStore; + } + + public void setDataStore(List dataStore) { + this.dataStore = dataStore; + } + + public static class DataStoreBean { + /** + * category : SCZD + * id : SCZD + * imei : SCZD + * majorPersonTerminal : false + * majorVehicleTerminal : false + * name : SCZD + * orgId : SCZD + * orgName : SCZD + * type : SCZD + */ + + private String category; + private String id; + private String imei; + private boolean majorPersonTerminal; + private boolean majorVehicleTerminal; + private String name; + + private String personName; + + private String orgId; + private String orgName; + private String type; + private String policeNumber; + //时间戳 + private String updateTime; + + public String getPoliceNumber() { + return policeNumber; + } + + public void setPoliceNumber(String policeNumber) { + this.policeNumber = policeNumber; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getImei() { + return imei; + } + + public void setImei(String imei) { + this.imei = imei; + } + + public boolean isMajorPersonTerminal() { + return majorPersonTerminal; + } + + public void setMajorPersonTerminal(boolean majorPersonTerminal) { + this.majorPersonTerminal = majorPersonTerminal; + } + + public boolean isMajorVehicleTerminal() { + return majorVehicleTerminal; + } + + public void setMajorVehicleTerminal(boolean majorVehicleTerminal) { + this.majorVehicleTerminal = majorVehicleTerminal; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPersonName() { + return personName; + } + + public void setPersonName(String personName) { + this.personName = personName; + } + + public String getOrgId() { + return orgId; + } + + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + public String getOrgName() { + return orgName; + } + + public void setOrgName(String orgName) { + this.orgName = orgName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + } +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/EsGpsInfoVO3.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/EsGpsInfoVO3.java new file mode 100644 index 00000000..fa98b324 --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/domain/vo/EsGpsInfoVO3.java @@ -0,0 +1,28 @@ +package org.dromara.data2es.domain.vo; + +import lombok.Data; +import org.dromara.data2es.domain.EsGpsInfo; + +/** + *

description:

+ * + * @author chenle + * @date 2021-10-11 15:14 + */ +@Data +public class EsGpsInfoVO3 extends EsGpsInfo { + + private static final long serialVersionUID = -4252583194984423318L; + + private String zzjgdm; + private String zzjgmc; + private String policeNo; + private String policeName; + private String phoneNum; + private String carNum; + //勤务Id,DS公司自己系统内有deviceCode 和 勤务ID 的关联,可以直接使用这个id + //其他公司没有这个关联关系,所以还需要上面的policeNo和policeName等信息用于展示 + private String linkId; + private String typeOfDevice; + +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/dubbo/RemoteDataToEsServiceImpl.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/dubbo/RemoteDataToEsServiceImpl.java index 449f62b4..6123b28f 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/dubbo/RemoteDataToEsServiceImpl.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/dubbo/RemoteDataToEsServiceImpl.java @@ -24,4 +24,19 @@ public class RemoteDataToEsServiceImpl implements RemoteDataToEsService { public R saveDataBatch(List gpsInfoList) { return gpsService.saveDataBatch(BeanUtil.copyToList(gpsInfoList, EsGpsInfoVO2.class)); } + + @Override + public R saveData(RemoteGpsInfo gpsInfo) throws Exception { + return gpsService.saveData(BeanUtil.toBean(gpsInfo, EsGpsInfoVO2.class)); + } + + @Override + public R updateOnlineStatusBatch(List gpsInfoList) { + return gpsService.updateOnlineStatusBatch(BeanUtil.copyToList(gpsInfoList, EsGpsInfoVO2.class)); + } + + @Override + public R updateOnlineStatus(RemoteGpsInfo gpsInfo) { + return null; + } } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/DataInsertBatchHandler.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/DataInsertBatchHandler.java index 87a2d5de..1e328c0e 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/DataInsertBatchHandler.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/DataInsertBatchHandler.java @@ -7,6 +7,7 @@ import org.dromara.data2es.controller.DataToEsController; import org.dromara.data2es.domain.EsGpsInfo; import org.dromara.data2es.domain.EsGpsInfoVO2; import org.dromara.data2es.service.IGpsService; +import org.dromara.data2es.service.StoreDataService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Configuration; @@ -31,6 +32,9 @@ public class DataInsertBatchHandler implements CommandLineRunner { @Autowired IGpsService gpsService; + @Autowired + StoreDataService storeDataService; + @Override public void run(String... args) throws Exception { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); @@ -45,6 +49,7 @@ public class DataInsertBatchHandler implements CommandLineRunner { log.info("batch size={}", list.size()); if(CollectionUtil.isNotEmpty(list)) { gpsService.saveDataBatch(list); + storeDataService.saveDataByPersonTypeBatch(list); } } catch (Exception e) { log.error("缓存队列批量消费异常:{}", e.getMessage()); diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RedisExpireListener.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RedisExpireListener.java index ea228278..73ba4e6d 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RedisExpireListener.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RedisExpireListener.java @@ -2,11 +2,14 @@ package org.dromara.data2es.handler; import cn.hutool.core.bean.BeanUtil; import cn.hutool.json.JSONObject; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.dromara.common.core.utils.RedisConstants; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.data2es.controller.DataToEsController; import org.dromara.data2es.domain.EsGpsInfoVO2; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +22,7 @@ import org.springframework.stereotype.Component; import java.util.Date; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** *

description:

@@ -27,6 +31,7 @@ import java.util.Objects; * @date 2021-11-08 16:40 */ @Component +@Slf4j public class RedisExpireListener extends KeyExpirationEventMessageListener { @Autowired @@ -49,22 +54,39 @@ public class RedisExpireListener extends KeyExpirationEventMessageListener { String expireKey = message.toString(); if(StringUtils.isNotEmpty(expireKey) && expireKey.startsWith(RedisConstants.ORG_CODE_PRE)){ - String[] split = expireKey.split(":"); - EsGpsInfoVO2 esGpsInfoVO2 = new EsGpsInfoVO2(); - esGpsInfoVO2.setDeviceType(split[2]); - esGpsInfoVO2.setDeviceCode(split[3]); - String zzjgdm = split[1]; - String deviceType = split[2]; - String deviceCode = split[3]; - if(StringUtils.isNotEmpty(zzjgdm)) { - JSONObject object = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + zzjgdm + ":" - + deviceType+":"+deviceCode); + handleExpiredEvent(expireKey); + } + } + + private void handleExpiredEvent(String expiredKey) { + RedissonClient redisson = RedisUtils.getClient(); + RLock lock = redisson.getLock("LOCK:" + expiredKey); + try { + if (lock.tryLock(0, 30, TimeUnit.SECONDS)) { + // 实际业务逻辑 + String[] split = expiredKey.split(":"); + + String deviceType = split[2]; + String deviceCode = split[3]; + if ("5".equals(deviceType) || "9".equals(deviceType) || "8".equals(deviceType) || "7".equals(deviceType)){ + return; + } + log.error("redis key expired:key={}",expiredKey); + JSONObject object = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType+":"+deviceCode); + if (Objects.isNull(object)) { + log.info("redis key={},Object=null,deviceType={},deviceCode={}", expiredKey,deviceType,deviceCode); + return; + } EsGpsInfoVO2 gpsInfo = BeanUtil.toBean(object, EsGpsInfoVO2.class); - gpsInfo.setGpsTime(new Date()); gpsInfo.setOnline(0); dataToEsController.saveGpsInfo(gpsInfo); + log.info("redis key expired:key={}", expiredKey); } + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); } - logger.info("redis key expired:key={}", expireKey); } + } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RequestHandler.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RequestHandler.java index 0396544c..54bcbd85 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RequestHandler.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/handler/RequestHandler.java @@ -5,14 +5,19 @@ package org.dromara.data2es.handler; * es redis kafka * */ +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONPObject; import com.alibaba.fastjson2.util.JSONObject1O; import jodd.util.StringUtil; import org.apache.commons.lang.StringUtils; +import org.dromara.common.core.utils.RedisConstants; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.data2es.domain.EsGpsInfo; import org.dromara.data2es.domain.EsGpsInfoVO2; +import org.dromara.data2es.domain.vo.EsGpsInfoVO3; import org.dromara.data2es.service.IGpsService; import org.dromara.data2es.util.ConfigConstants; import org.elasticsearch.action.bulk.BulkRequest; @@ -57,12 +62,9 @@ public class RequestHandler { String deviceType = esGpsInfoVO2.getDeviceType(); if(StringUtil.isEmpty(deviceType)){ - deviceType = "99"; - } - String infoSource = esGpsInfoVO2.getInfoSource(); - if(StringUtils.isEmpty(infoSource)){ - infoSource = "other"; + deviceType = "6"; } + /** * 获取该条记录的基本信息推送给第三方使用 */ @@ -76,7 +78,6 @@ public class RequestHandler { //kafkaProducer.send(esGpsInfoVO2, ConfigConstants.KAFKA_TOPIC_SEND_PRE+"."+deviceType); //地市的kafka数据,如接收地市某个设备的数据可以对接此kafka topic //todo 暂时隐藏 - kafkaTemplate.send(ConfigConstants.KAFKA_TOPIC_SEND_PRE+"."+infoSource+"."+deviceType,JSON.toJSONString(esGpsInfoVO2)); } } @@ -130,4 +131,100 @@ public class RequestHandler { + /** + * 在线用户存入 + * @param esGpsInfoVo2 + */ + @Async + public void redisOnlineUser(EsGpsInfoVO2 esGpsInfoVo2){ + //todo 存储的value应该改为 esGpsInfoVo2为后面大屏展示提供数据 + if(null == esGpsInfoVo2){ + logger.error("redis存入对象为空"); + return; + } + + Date gpsTime = esGpsInfoVo2.getGpsTime(); + String jsonValue = JSONUtil.toJsonStr(esGpsInfoVo2); + if(!Objects.isNull(gpsTime)){ + + //设置永不过期,便于前端查询设备的最后位置 ----2022年9月15日 + + long betweenS = DateUtil.between(gpsTime, new Date(), DateUnit.SECOND); + //过期时间应该是20分钟减去设备定位时间与当前时间的差值,比如设备已经比当前时间晚15分钟了,那么设备的过期时间应该只剩5分钟了 + long onlineTime = 60*10 - betweenS; + + String deviceCode = esGpsInfoVo2.getDeviceCode(); + String deviceType = esGpsInfoVo2.getDeviceType(); + //设置永不过期,便于前端查询设备的最后位置 ----2022年9月15日 + RedisUtils.set(RedisConstants.ONLINE_USERS + + deviceType + + ":" + deviceCode, jsonValue, RedisConstants.REDIS_NEVER_EXPIRE); + logger.error("redis存入,deviceCode={}",deviceCode); + + //地理位置空间查询 + long b = RedisUtils.geoAdd(Double.valueOf(esGpsInfoVo2.getLng()), + Double.valueOf(esGpsInfoVo2.getLat()), deviceCode +"#"+ deviceType); + + if(onlineTime > 0) { + //设置一个过期时间,方便key自动过期监听,设置离线 [RedisExpireListener] + RedisUtils.set(RedisConstants.ONLINE_USERS_TEN + + deviceType + + ":" + deviceCode, jsonValue, onlineTime); + + + + } + //方便根据组织机构计算数量 + + String zzjgdm = esGpsInfoVo2.getZzjgdm(); + if(esGpsInfoVo2.getOnline() == 1) { + if(StringUtils.isNotBlank(zzjgdm)) { + RedisUtils.set(RedisConstants.ORG_CODE_ONLINE_DEVICES + esGpsInfoVo2.getDeviceType() + ":" + + zzjgdm + ":" + esGpsInfoVo2.getDeviceCode(), jsonValue, RedisConstants.REDIS_NEVER_EXPIRE); + + } + + }else{ + if(StringUtils.isNotBlank(zzjgdm)) { + //如果是离线的情况,那么就清除这个在线的 + RedisUtils.del(RedisConstants.ORG_CODE_ONLINE_DEVICES + esGpsInfoVo2.getDeviceType() + ":" + + zzjgdm + ":" + esGpsInfoVo2.getDeviceCode()); + } + } + + } + + } + + + /** + * 单独存入 + * @param esGpsInfo + */ + @Async + public void redisOnlineUserByPerson(EsGpsInfo esGpsInfo){ + EsGpsInfoVO3 esGpsInfoVO3 = (EsGpsInfoVO3) esGpsInfo; + String jsonValue = JSONUtil.toJsonStr(esGpsInfoVO3); + Date gpsTime = esGpsInfoVO3.getGpsTime(); + if(!Objects.isNull(gpsTime)){ + + //设置永不过期,便于前端查询设备的最后位置 ----2022年9月15日 + RedisUtils.set(RedisConstants.ONLINE_USERS + + esGpsInfoVO3.getDeviceType() + + ":" + esGpsInfoVO3.getDeviceCode(), jsonValue, RedisConstants.REDIS_NEVER_EXPIRE); + + //设置一个10分钟过期的。然后用redis监听、监听过期的数据然后重新发送到kafka + RedisUtils.set(RedisConstants.ONLINE_USERS_TEN + + esGpsInfoVO3.getDeviceType() + + ":" + esGpsInfoVO3.getDeviceCode(), jsonValue, 60*10); + long b = RedisUtils.geoAdd( Double.valueOf(esGpsInfoVO3.getLng()), Double.valueOf(esGpsInfoVO3.getLat()), esGpsInfoVO3.getDeviceCode()+"#"+esGpsInfoVO3.getDeviceType()); + + + + } + + } + + + } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/DSQinwuMapper.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/DSQinwuMapper.java new file mode 100644 index 00000000..8579658f --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/DSQinwuMapper.java @@ -0,0 +1,14 @@ +package org.dromara.data2es.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.dromara.data2es.domain.DSQinwuEntity; +import org.springframework.stereotype.Repository; + +/** + *

description:

+ * + */ +@Repository +public interface DSQinwuMapper extends BaseMapper { + +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/TDeviceMapper.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/TDeviceMapper.java deleted file mode 100644 index e8d379cf..00000000 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/mapper/TDeviceMapper.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.dromara.data2es.mapper; - -public class TDeviceMapper { -} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/BaseDataSchedule.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/BaseDataSchedule.java new file mode 100644 index 00000000..b98c0a9c --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/BaseDataSchedule.java @@ -0,0 +1,160 @@ +package org.dromara.data2es.schedule; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.dromara.data2es.domain.DSQinwuEntity; +import org.dromara.data2es.domain.vo.DSResponse; +import org.dromara.data2es.service.DSQinwuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +/** + *

description:

+ * DS勤务人员和设备关系数据抽取 + * @author chenle + * @date 2023-03-21 17:37 + */ +@Configuration +@Slf4j +public class BaseDataSchedule { + + + private String lastUpdateTime; + + private String preUrl = "http://53.238.84.10:28080/ds-portal-web"; + + @Autowired + DSQinwuService dsQinwuService; + + @Value("${ruansi.ruansi-kafka.send-to-third-enabled}") + private boolean sendToThirdEnabled; + + @Value("${ruansi.ruansi-kafka.start-update-time}") + private String startUpdateTime; + + @Value("${ruansi.ruansi-kafka.ds-preurl}") + private String dsPreurl; + /** + * 娱特单位抽取 + */ +// @Scheduled(cron = "0/30 * * * * ?") + public void updateDsQw(){ + if(StringUtils.isBlank(lastUpdateTime)){ + DSQinwuEntity qinwu = dsQinwuService.lastOne(); + lastUpdateTime = DateUtil.formatDateTime(qinwu.getUpdateTime()); + } + String suffixUrl = "/v1/terminal/updateTime-terminal"; + DSResponse dsResponse = requestList(lastUpdateTime, suffixUrl); + List dataStores = dsResponse.getDataStore(); + if(CollectionUtils.isEmpty(dataStores)){ + log.info("没有可更新的设备"); + return; + } + log.info("updateTime={},deviceSize={}",lastUpdateTime,dataStores.size()); + + List newDeviceList = generateEntityList(dataStores); +// List newDeviceList = generateEntityList2(dataStores); + if(CollectionUtils.isEmpty(newDeviceList)){ + log.info("未查询到设备newDeviceList = null"); + return; + } + int count = dsQinwuService.saveOrUpdate(newDeviceList); + log.info("更新或插入的count={}",count); + if(count == newDeviceList.size()){ //如果有一个失败的情况出现,那么更新时间就不变 + DSQinwuEntity qinwu = dsQinwuService.lastOne(); + Date updateTime = qinwu.getUpdateTime(); + lastUpdateTime = DateUtil.formatDateTime(updateTime); + log.info("timestamp={},lastUpdateTime={}",updateTime,lastUpdateTime); + } + } + + /** + * 构造数据库实体list + * @param dataStores ds系统列表 + * @return 自己系统数据库列表 + */ + private List generateEntityList(List dataStores) { + List newDeviceList = new ArrayList<>(); + for (DSResponse.DataStoreBean dataStoreBean : dataStores) { + String deviceCode = dataStoreBean.getImei(); + String policeName = dataStoreBean.getName(); + String type = dataStoreBean.getType();//类型 PDT、ZFJLY等 + if(StringUtils.isBlank(deviceCode) || StringUtils.isBlank(policeName) || StringUtils.isBlank(type)){ + log.info("deviceCode、policeName、type有一个为空,deviceCode={}",deviceCode); + continue; + } + + DSQinwuEntity entity = new DSQinwuEntity(); +// BeanUtil.copyProperties(dataStoreBean,com.ruansee.common_kafka.entity,"id","updateTime"); + entity.setCategory(dataStoreBean.getCategory()); + entity.setLinkId(dataStoreBean.getId()); + entity.setImei(dataStoreBean.getImei()); + entity.setMajorPersonTerminal(dataStoreBean.isMajorPersonTerminal()); + entity.setMajorVehicleTerminal(dataStoreBean.isMajorVehicleTerminal()); + entity.setOrgId(dataStoreBean.getOrgId()); + entity.setOrgName(dataStoreBean.getOrgName()); + entity.setName(dataStoreBean.getName()); + entity.setType(dataStoreBean.getType()); + entity.setPoliceNumber(dataStoreBean.getPoliceNumber()); + entity.setPoliceName(dataStoreBean.getPersonName()); + + try { + entity.setUpdateTime(DateUtil.date(Long.valueOf(dataStoreBean.getUpdateTime()))); + }catch (Exception e){ + log.info("时间转换错误,msg={}",e.getMessage()); + continue; + } + newDeviceList.add(entity); + } + return newDeviceList; + } + + + /** + * 构造数据库实体list + * @param dataStores ds系统列表 + * @return 自己系统数据库列表 + */ + private List generateEntityList2(List dataStores) { + List newDeviceList = new ArrayList<>(); + for (int i =1;i<100;i++) { + + DSQinwuEntity entity = new DSQinwuEntity(); + + entity.setCategory("123"); + entity.setLinkId("asdasdsasd"); + entity.setImei("12343435345" + new Random(100).nextInt()); + entity.setMajorPersonTerminal(false); + entity.setMajorVehicleTerminal(false); + entity.setOrgId("341100000000"); + entity.setOrgName("滁州市公安局"); + entity.setName("张三"); + entity.setType("PDT"); + + try { + entity.setUpdateTime(DateUtil.date(System.currentTimeMillis())); + }catch (Exception e){ + log.info("时间转换错误,msg={}",e.getMessage()); + continue; + } + newDeviceList.add(entity); + } + return newDeviceList; + } + + private DSResponse requestList(String updateTime, String suffixUrl) { + Map map = new HashMap<>(); + map.put("updateTime",updateTime); + String content = HttpUtil.get(dsPreurl + suffixUrl, map); + DSResponse dsResponse = JSONUtil.toBean(content, DSResponse.class); + return dsResponse; + } + +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/GpsTaskTest.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/GpsTaskTest.java index fbdb6a13..9f5f14d8 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/GpsTaskTest.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/GpsTaskTest.java @@ -24,7 +24,7 @@ public class GpsTaskTest { IGpsService gpsService; - @Scheduled(cron = "0/10 * * * * ?") +// @Scheduled(cron = "0/10 * * * * ?") public void produceGps() throws InvocationTargetException, IllegalAccessException, ExecutionException, InterruptedException { int a = 10000; int b = 20000; @@ -45,9 +45,9 @@ public class GpsTaskTest { map.put("gpsTime",new Date()); map.put("locationDesc","合肥市公安局"); - esGpsInfo.setLatitude("31.3" + (a + i)); + esGpsInfo.setLat("31.3" + (a + i)); map.put("lat","31." + (a + i)); - esGpsInfo.setLongitude("117.2" + (b + i)); + esGpsInfo.setLng("117.2" + (b + i)); map.put("lng","117." + (b + i)); //gpsService.saveData(map); diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/RedisOnlineUserSchedule.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/RedisOnlineUserSchedule.java deleted file mode 100644 index 48740302..00000000 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/schedule/RedisOnlineUserSchedule.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.dromara.data2es.schedule; - -/** - *

description:

- * - * @author chenle - * @date 2021-05-18 18:23 - */ - -public class RedisOnlineUserSchedule { - - -} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/DSQinwuService.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/DSQinwuService.java new file mode 100644 index 00000000..82cb28b4 --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/DSQinwuService.java @@ -0,0 +1,20 @@ +package org.dromara.data2es.service; + +import org.dromara.data2es.domain.DSQinwuEntity; + +import java.util.List; + +/** + *

description:

+ * + * @author chenle + * @date 2023-03-22 12:16 + */ +public interface DSQinwuService { + + DSQinwuEntity checkExist(DSQinwuEntity dsQinwuEntity); + + DSQinwuEntity lastOne(); + + int saveOrUpdate(List deviceList); +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/IGpsService.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/IGpsService.java index 2b2f326d..847f3979 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/IGpsService.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/IGpsService.java @@ -14,4 +14,10 @@ public interface IGpsService { R saveDataBatch(List esGpsInfoVO2s); + R saveData(EsGpsInfoVO2 esGpsInfoVO2) throws ExecutionException, InterruptedException; + + R updateOnlineStatusBatch(List esGpsInfoVO2s); + + R updateOnlineStatus(EsGpsInfoVO2 gpsInfoVO2); + } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/StoreDataService.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/StoreDataService.java new file mode 100644 index 00000000..47551cd9 --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/StoreDataService.java @@ -0,0 +1,23 @@ +package org.dromara.data2es.service; + + + +import org.dromara.common.core.domain.R; +import org.dromara.data2es.domain.EsGpsInfo; +import org.dromara.data2es.domain.EsGpsInfoVO2; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.concurrent.ExecutionException; + +/** + *

description:

+ * 2023年3月13日 新增加一类数据,发送给DS使用 + * @author chenle + * @date 2021-05-14 16:44 + */ +public interface StoreDataService { + R saveDataByPersonType(EsGpsInfo esGpsInfo); + + R saveDataByPersonTypeBatch(List esGpsInfo) throws InvocationTargetException, IllegalAccessException, ExecutionException, InterruptedException; +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/DSQinwuServiceImpl.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/DSQinwuServiceImpl.java new file mode 100644 index 00000000..a5b1aa10 --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/DSQinwuServiceImpl.java @@ -0,0 +1,78 @@ +package org.dromara.data2es.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.data2es.domain.DSQinwuEntity; +import org.dromara.data2es.mapper.DSQinwuMapper; +import org.dromara.data2es.service.DSQinwuService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; + +/** + *

description:

+ * + * @author chenle + * @date 2023-03-22 12:18 + */ +@Service +@Slf4j +public class DSQinwuServiceImpl implements DSQinwuService { + + @Autowired + DSQinwuMapper dsQinwuMapper; + + @Override + public DSQinwuEntity checkExist(DSQinwuEntity dsQinwuEntity) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(DSQinwuEntity::getImei, dsQinwuEntity.getImei()); + lqw.eq(DSQinwuEntity::getType, dsQinwuEntity.getType()); + DSQinwuEntity entity = dsQinwuMapper.selectOne(lqw); + return entity; + } + + @Override + public DSQinwuEntity lastOne() { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.orderByDesc(DSQinwuEntity::getUpdateTime); + lqw.last("limit 1"); + DSQinwuEntity entity = dsQinwuMapper.selectOne(lqw); + return entity; + } + + @Override + public int saveOrUpdate(List deviceList) { + + int insertCount = 0; + int updatedCount = 0; + + for (DSQinwuEntity newEntity : deviceList) { + + DSQinwuEntity oldEntity = checkExist(newEntity); + if (Objects.isNull(oldEntity)) { + int insert = dsQinwuMapper.insert(newEntity); + if (insert > 0) { + insertCount++; + } + } else { + int compare = DateUtil.compare(oldEntity.getUpdateTime(), newEntity.getUpdateTime()); + //数据库的已存在设备的更新日期大于新来设备的更新日期,以最新日期为准,不更新此条设备。 + if(compare >= 0){ + updatedCount++; + continue; + } + newEntity.setId(oldEntity.getId()); + int update = dsQinwuMapper.updateById(newEntity); + if (update > 0) { + updatedCount++; + } + } + } + + return (insertCount+updatedCount); + } +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/GpsServiceImpl.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/GpsServiceImpl.java index a8ba7fca..85400564 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/GpsServiceImpl.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/GpsServiceImpl.java @@ -4,8 +4,9 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; -import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.RequiredArgsConstructor; import org.apache.commons.lang.StringUtils; import org.apache.dubbo.config.annotation.DubboReference; @@ -18,6 +19,7 @@ import org.dromara.data2es.domain.entity.GpsInfoEntity; import org.dromara.data2es.exception.MyBusinessException; import org.dromara.data2es.handler.RequestHandler; import org.dromara.data2es.service.IGpsService; +import org.dromara.data2es.service.StoreDataService; import org.dromara.system.api.RemoteDeviceService; import org.dromara.system.api.domain.vo.RemoteDeviceVo; import org.elasticsearch.action.bulk.BulkRequest; @@ -35,12 +37,15 @@ import org.elasticsearch.rest.RestStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.IOException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; @RequiredArgsConstructor @@ -50,8 +55,8 @@ public class GpsServiceImpl implements IGpsService { @Autowired private RestHighLevelClient restHighLevelClient; - @DubboReference - private RemoteDeviceService deviceService; + @Autowired + StoreDataService storeDataService; private final RequestHandler requestHandler; @@ -65,10 +70,10 @@ public class GpsServiceImpl implements IGpsService { double lng ; double lat ; try { - lng = Double.parseDouble(esGpsInfo.getLongitude()); - lat = Double.parseDouble(esGpsInfo.getLatitude()); + lng = Double.parseDouble(esGpsInfo.getLng()); + lat = Double.parseDouble(esGpsInfo.getLat()); }catch (NumberFormatException e){ - throw new MyBusinessException("经纬度转double异常,经度为:"+esGpsInfo.getLongitude() +"纬度为"+esGpsInfo.getLatitude()); + throw new MyBusinessException("经纬度转double异常,经度为:"+esGpsInfo.getLng() +"纬度为"+esGpsInfo.getLat()); } gpsInfoEntity.setLocation(new Double[]{lng,lat}); @@ -105,68 +110,149 @@ public class GpsServiceImpl implements IGpsService { List deleteKeys = new ArrayList<>(); BulkRequest bulkRequest = new BulkRequest(); for (EsGpsInfoVO2 info : list) { - if(StringUtils.isBlank(info.getInfoSource())){ - logger.info("infoSource 为空"); + + //设置地市zzjgdm + info = getInfo(info); + if (Objects.isNull(info)) { + logger.error("redis中的Object=null,deviceType={},deviceCode={}",info.getDeviceType(),info.getDeviceCode()); continue; } - //设置地市zzjgdm - info = getInfoByInfoSource(info); //redis - buildRedisMap(info,onlineUserDataMap,orgCodeDataMap,deleteKeys); +// buildRedisMap(info,onlineUserDataMap,orgCodeDataMap,deleteKeys); // logger.error("接收数据={},deviceCode={},gpsTime={}",info,info.getDeviceCode(),info.getGpsTime()); IndexRequest indexRequest = buildEsIndexRequest(info); bulkRequest.add(indexRequest); // 发送到 kafka requestHandler.sendToKafka(info); + //地市版本没用批量插入 + requestHandler.redisOnlineUser(info); } - requestHandler.redisOnlineUserBatch(onlineUserDataMap, RedisConstants.REDIS_ONLINE_USER_NEVER_EXPIRE); - requestHandler.redisOnlineUserBatch(orgCodeDataMap, 600); +// requestHandler.redisOnlineUserBatch(onlineUserDataMap, RedisConstants.REDIS_ONLINE_USER_NEVER_EXPIRE); +// requestHandler.redisOnlineUserBatch(orgCodeDataMap, 600); // requestHandler.batchPut(onlineUserDataMap); // requestHandler.batchPutWithExpire(orgCodeDataMap,600); - requestHandler.redisDeleteBatch(deleteKeys); +// requestHandler.redisDeleteBatch(deleteKeys); requestHandler.esRealBulkSave(bulkRequest); return R.ok(); } + @Override + public R saveData(EsGpsInfoVO2 info) throws ExecutionException, InterruptedException{ + //设置地市zzjgdm + info = getInfo(info); + IndexRequest indexRequest = buildEsIndexRequest(info); + //存es + CompletableFuture esFuture = doRequest(info); - /** - * 获取基本信息(主要是组织机构) 不查库 否者对库压力过大 - * @param esGpsInfo - * @return - */ - private EsGpsInfoVO2 getInfoByInfoSource(EsGpsInfo esGpsInfo) { - EsGpsInfoVO2 esGpsInfoVO2 = new EsGpsInfoVO2(); - BeanUtil.copyProperties(esGpsInfo,esGpsInfoVO2); - JSONObject object = RedisUtils.getBucket("deviceInfo:"+esGpsInfo.getInfoSource()+":"+esGpsInfo.getDeviceCode()); -// RemoteDeviceVo vo = deviceService.getDeviceInfo(esGpsInfoVO2.getDeviceCode(),esGpsInfoVO2.getInfoSource()); - if (null != object){ - RemoteDeviceVo vo = BeanUtil.toBean(object,RemoteDeviceVo.class); - esGpsInfoVO2.setZzjgdm(vo.getZzjgdm()); - esGpsInfoVO2.setZzjgmc(vo.getZzjgmc()); - esGpsInfoVO2.setPoliceName(vo.getPoliceName()); - esGpsInfoVO2.setPoliceNo(vo.getPoliceNo()); - esGpsInfoVO2.setCarNum(vo.getCarNum()); - String deviceType = vo.getDeviceType(); - if(StringUtils.isNotBlank(deviceType)){ - deviceType = deviceType.replaceAll("\"", ""); - if(deviceType.charAt(0) == '0' && deviceType.length() > 1){ - deviceType = deviceType.substring(1); - if(deviceType.equals("1")){ - deviceType = "2"; - } - } + // 发送到 kafka + requestHandler.sendToKafka(info); + //地市版本没用批量插入 + requestHandler.redisOnlineUser(info); + //发送到勤务 + storeDataService.saveDataByPersonType(info); + + CompletableFuture.allOf(esFuture); + EsGpsInfo esGpsInfo1 = esFuture.get(); + if(Objects.isNull(esGpsInfo1)){ + return R.fail(-1,"保存失败"); + }else{ + return R.ok("保存成功"); + } + } + + @Override + public R updateOnlineStatusBatch(List list) { + logger.error("下线设备数量={}",list.size()); + int num = 0; + for (EsGpsInfo originEsGpsInfo : list) { + String deviceCode = originEsGpsInfo.getDeviceCode(); + String deviceType = originEsGpsInfo.getDeviceType(); +// DeviceEntityV2 de = deviceService.checkDeviceExists(info); + Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType+":" + deviceCode); + if (Objects.isNull(o)) { + logger.error("redis中的Object=null,deviceType={},deviceCode={}",deviceType,deviceCode); + continue; } - esGpsInfoVO2.setDeviceType(deviceType); - }else { - esGpsInfoVO2.setDeviceType("99"); - esGpsInfoVO2.setZzjgdm(esGpsInfo.getInfoSource()+"00000000"); + JSONObject o1 = (JSONObject) o; + String json = o1.toJSONString(); + EsGpsInfoVO2 esGpsInfoVO2 = JSON.parseObject(json, EsGpsInfoVO2.class); + //更新在线状态和时间,经纬度不变 + esGpsInfoVO2.setOnline(originEsGpsInfo.getOnline()); + + if(!Objects.isNull(originEsGpsInfo.getGpsTime())) { + esGpsInfoVO2.setGpsTime(originEsGpsInfo.getGpsTime()); + } + + EsGpsInfoVO2 esGpsInfo = new EsGpsInfoVO2(); + esGpsInfo.setOnline(esGpsInfoVO2.getOnline()); + esGpsInfo.setGpsTime(esGpsInfoVO2.getGpsTime()); + esGpsInfo.setLat(esGpsInfoVO2.getLat()); + esGpsInfo.setLng(esGpsInfoVO2.getLng()); + esGpsInfo.setHeight(esGpsInfoVO2.getHeight()); + esGpsInfo.setDeltaH(esGpsInfoVO2.getDeltaH()); + esGpsInfo.setOrientation(esGpsInfoVO2.getOrientation()); + esGpsInfo.setSpeed(esGpsInfoVO2.getSpeed()); + esGpsInfo.setDeviceType(esGpsInfoVO2.getDeviceType()); + esGpsInfo.setDeviceCode(esGpsInfoVO2.getDeviceCode()); + try { + saveData(esGpsInfo); + num++; +// storeDataService.saveDataByPersonType(esGpsInfo); + } catch (Exception e) { + num--; + logger.error(e.getMessage()); +// return response.error(500,e.getMessage()); + } + + } + logger.error("update status,设备数量={}",num); + return R.ok(); + } + + @Override + public R updateOnlineStatus(EsGpsInfoVO2 gpsInfoVO2) { + String deviceCode = gpsInfoVO2.getDeviceCode(); + String deviceType = gpsInfoVO2.getDeviceType(); +// DeviceEntityV2 de = deviceService.checkDeviceExists(info); + Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode); + if (Objects.isNull(o)) { + logger.error("redis中的Object=null,deviceType={},deviceCode={}", deviceType, deviceCode); + return null; + } + JSONObject o1 = (JSONObject) o; + String json = o1.toJSONString(); + EsGpsInfoVO2 esGpsInfoVO2 = JSON.parseObject(json, EsGpsInfoVO2.class); + //更新在线状态和时间,经纬度不变 + esGpsInfoVO2.setOnline(gpsInfoVO2.getOnline()); + + if (!Objects.isNull(gpsInfoVO2.getGpsTime())) { + esGpsInfoVO2.setGpsTime(gpsInfoVO2.getGpsTime()); + } + + EsGpsInfoVO2 esGpsInfo = new EsGpsInfoVO2(); + esGpsInfo.setOnline(esGpsInfoVO2.getOnline()); + esGpsInfo.setGpsTime(esGpsInfoVO2.getGpsTime()); + esGpsInfo.setLat(esGpsInfoVO2.getLat()); + esGpsInfo.setLng(esGpsInfoVO2.getLng()); + esGpsInfo.setHeight(esGpsInfoVO2.getHeight()); + esGpsInfo.setDeltaH(esGpsInfoVO2.getDeltaH()); + esGpsInfo.setOrientation(esGpsInfoVO2.getOrientation()); + esGpsInfo.setSpeed(esGpsInfoVO2.getSpeed()); + esGpsInfo.setDeviceType(esGpsInfoVO2.getDeviceType()); + esGpsInfo.setDeviceCode(esGpsInfoVO2.getDeviceCode()); + try { + return saveData(esGpsInfo); + + } catch (Exception e) { + logger.error(e.getMessage()); + return R.fail(e.getMessage()); +// return response.error(500,e.getMessage()); } - return esGpsInfoVO2; } private IndexRequest buildEsIndexRequest(EsGpsInfo esGpsInfo) { @@ -179,7 +265,7 @@ public class GpsServiceImpl implements IGpsService { * @param */ private String checkIndexExist() { - String todayIndexName = "rs_gpsinfo"+ LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + String todayIndexName = "gpsinfo"+ LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); CreateIndexRequest createIndexRequest ; if(!existsIndex(todayIndexName)){ logger.error("进入了exist"); @@ -247,10 +333,10 @@ public class GpsServiceImpl implements IGpsService { double lng ; double lat ; try { - lng = Double.parseDouble(esGpsInfo.getLongitude()); - lat = Double.parseDouble(esGpsInfo.getLatitude()); + lng = Double.parseDouble(esGpsInfo.getLng()); + lat = Double.parseDouble(esGpsInfo.getLat()); }catch (NumberFormatException e){ - throw new MyBusinessException("经纬度转double异常,经度为:"+esGpsInfo.getLongitude() +"纬度为"+esGpsInfo.getLatitude()); + throw new MyBusinessException("经纬度转double异常,经度为:"+esGpsInfo.getLng() +"纬度为"+esGpsInfo.getLat()); } gpsInfoEntity.setLocation(new Double[]{lng,lat}); @@ -283,9 +369,7 @@ public class GpsServiceImpl implements IGpsService { } String jsonValue = JSONUtil.toJsonStr(esGpsInfoVo2); - String onlineUsersKey = RedisConstants.ONLINE_USERS + - zzjgdm + ":" + deviceType + - ":" + deviceCode; + String onlineUsersKey = RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode; onlineUserDataMap.put(onlineUsersKey, jsonValue); //todo 省厅左侧只需要展示到市级以及区县级数量,所以需要查询出该单位的上级单位进行存储。 //如:key = "org_code:340800260000:deviceType:deviceCode 安庆交通警察支队 @@ -304,6 +388,67 @@ public class GpsServiceImpl implements IGpsService { } } + + @Async + public CompletableFuture doRequest(EsGpsInfoVO2 esGpsInfo){ + EsGpsInfo entity = createEntity(esGpsInfo); + + return CompletableFuture.completedFuture(entity); + } + + /** + * 获取基本信息(主要是组织机构) + * @param esGpsInfo + * @return + */ + private EsGpsInfoVO2 getInfo(EsGpsInfo esGpsInfo) { + RemoteDeviceVo deviceEntityV2 = new RemoteDeviceVo(); + String deviceCode = esGpsInfo.getDeviceCode(); + String deviceType = esGpsInfo.getDeviceType(); + /*if(StringUtils.isEmpty(deviceCode) || StringUtils.isEmpty(deviceType)){ + logger.error("deviceCode or deviceType = null{},{}",deviceCode,deviceType); + return null; + }*/ + deviceEntityV2.setDeviceCode(deviceCode); + deviceEntityV2.setDeviceType(deviceType); + RemoteDeviceVo deviceEntityV21 = BeanUtil.toBean(RedisUtils.getBucket("deviceInfo:" + deviceType+":"+deviceCode), RemoteDeviceVo.class) ; + if(Objects.isNull(deviceEntityV21)){ + logger.error("库里没有这个数据,deviceCode={}",deviceCode); + return null; + } + EsGpsInfoVO2 esGpsInfoVO2 = new EsGpsInfoVO2(); + BeanUtil.copyProperties(esGpsInfo,esGpsInfoVO2); + if(!Objects.isNull(deviceEntityV21)){ + deviceType = deviceEntityV21.getDeviceType()+""; + esGpsInfoVO2.setDeviceType(deviceEntityV21.getDeviceType()+""); + esGpsInfoVO2.setZzjgdm(deviceEntityV21.getZzjgdm()); + esGpsInfoVO2.setZzjgmc(deviceEntityV21.getZzjgmc()); + esGpsInfoVO2.setPoliceNo(deviceEntityV21.getPoliceNo()); + esGpsInfoVO2.setPoliceName(deviceEntityV21.getPoliceName()); + esGpsInfoVO2.setCarNum(deviceEntityV21.getCarNum()); + esGpsInfoVO2.setPhoneNum(deviceEntityV21.getPhoneNum()); + } + String lat = esGpsInfo.getLat(); + String lng = esGpsInfo.getLng(); + + //如果定位是0的话 ,则上传最后一次有定位的坐标,如果最后一次是0的话,那就上传0 + boolean nonLatLng = isNonLatLng(lat, lng); + if(nonLatLng){ + Object o = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + deviceType + ":" + deviceCode); + if(!Objects.isNull(o)) { + com.alibaba.fastjson.JSONObject o1 = (JSONObject) o; + String json = o1.toJSONString(); + EsGpsInfoVO2 esGpsInfoVO3 = JSON.parseObject(json, EsGpsInfoVO2.class); + String lat1 = esGpsInfoVO3.getLat(); + String lng1 = esGpsInfoVO3.getLng(); + esGpsInfoVO2.setLat(lat1); + esGpsInfoVO2.setLng(lng1); + } + + } + return esGpsInfoVO2; + } + private void generateMappingRequest(CreateIndexRequest createIndexRequest) { XContentBuilder builder = null; try { @@ -352,5 +497,16 @@ public class GpsServiceImpl implements IGpsService { } } + /** + * 判断一个定位是否是0的方法 + * @param lat + * @param lng + * @return + */ + private boolean isNonLatLng(String lat, String lng) { + return StringUtils.isBlank(lat) || StringUtils.isBlank(lng) + || "0".equals(lat) || "0".equals(lng) + || "0.0".equals(lat) || "0.0".equals(lng); + } } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/StoreDataServiceImpl.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/StoreDataServiceImpl.java new file mode 100644 index 00000000..5aa5e7cd --- /dev/null +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/service/impl/StoreDataServiceImpl.java @@ -0,0 +1,238 @@ +package org.dromara.data2es.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.RedisConstants; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.data2es.domain.DSQinwuEntity; +import org.dromara.data2es.domain.EsGpsInfo; +import org.dromara.data2es.domain.EsGpsInfoVO2; +import org.dromara.data2es.domain.vo.EsGpsInfoVO3; +import org.dromara.data2es.handler.RequestHandler; +import org.dromara.data2es.mapper.DSQinwuMapper; +import org.dromara.data2es.service.StoreDataService; +import org.dromara.data2es.util.ConfigConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +import java.lang.reflect.InvocationTargetException; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.ExecutionException; + +/** + *

description:

+ * + * @author chenle + * @date 2021-05-14 16:45 + */ +@Slf4j +@Service +public class StoreDataServiceImpl implements StoreDataService { + + @Autowired + RequestHandler requestHandler; + + + @Autowired + private KafkaTemplate kafkaTemplate; + + @Autowired + DSQinwuMapper dsQinwuDao; + + /** + * 从定位数据中单独列出一类数据,发送给持有该设备的人。这个关系从DS公司获取“勤务排班”关系 + * @param esGpsInfo + * @return + */ + @Override + public R saveDataByPersonType(EsGpsInfo esGpsInfo) { + if(Objects.isNull(esGpsInfo)){ + log.error("esGpsInfo 实体为null"); + return R.fail(500,"esGpsInfo 实体为null"); + } + String deviceType = esGpsInfo.getDeviceType(); + //即不是PDT手台也不是执法记录仪 + if(!"3".equals(deviceType) && !"5".equals(deviceType) && !"1".equals(deviceType) && !"4".equals(deviceType)){ + //log.error("不是记录仪或者手台,不需要处理,deviceType={}",deviceType); + return R.fail(200,"type not 1 3 4 5,deviceType="+deviceType); + } + //获取勤务排班信息 + EsGpsInfoVO3 info = getInfo(esGpsInfo); + if(Objects.isNull(info)){ + log.error("未找到勤务排班信息,deviceCode={},deviceType={}",esGpsInfo.getDeviceCode(),esGpsInfo.getDeviceType()); + return R.fail(500,"未找到勤务排班信息,deviceCode={}"+esGpsInfo.getDeviceCode()); + } + + //发送到kafka + kafkaTemplate.send( ConfigConstants.KAFKA_TOPIC_SEND_PRE+"."+info.getDeviceType(), JSON.toJSONString(info)); + //存入到redis + requestHandler.redisOnlineUserByPerson(info); + + + return R.ok(); + } + + @Override + public R saveDataByPersonTypeBatch(List list) throws InvocationTargetException, IllegalAccessException, ExecutionException, InterruptedException { + for (EsGpsInfo esGpsInfo : list) { + saveDataByPersonType(esGpsInfo); + } + + return R.ok(); + } + + /** + * 获取勤务排班信息 + * @param esGpsInfo + * @return + */ + private EsGpsInfoVO3 getInfo(EsGpsInfo esGpsInfo) { + EsGpsInfoVO3 esGpsInfoVO3 = new EsGpsInfoVO3(); + BeanUtil.copyProperties(esGpsInfo, esGpsInfoVO3); + /** + * 1、如果记录仪有数据,就以记录仪的为准,pdt的数据过来了,就忽略 + * 2、如果记录仪没数据,就以pdt的为准 + */ + String deviceType = esGpsInfo.getDeviceType(); + if("5".equals(deviceType)){ + EsGpsInfoVO3 zfjly = setVO3(esGpsInfo.getDeviceCode(), "ZFJLY", esGpsInfoVO3); + if(!Objects.isNull(zfjly)) { +// zfjly.setTypeOfDevice("5"); + if ("XLC".equals(zfjly.getTypeOfDevice())){ + zfjly.setTypeOfDevice("8"); + }else if ("BKQ".equals(zfjly.getTypeOfDevice())){ + zfjly.setTypeOfDevice("7"); + }else { + zfjly.setTypeOfDevice("5"); + } + } + return zfjly; + } + if("3".equals(deviceType)){ + //pdt设备 + EsGpsInfoVO3 pdt = setVO3(esGpsInfo.getDeviceCode(), "PDT", esGpsInfoVO3); + if(!Objects.isNull(pdt)) { + pdt.setTypeOfDevice("3"); + } + return pdt; + } + if("1".equals(deviceType)){ + //pdt设备 + EsGpsInfoVO3 djj = setVO3(esGpsInfo.getDeviceCode(), "DJJ", esGpsInfoVO3); + if(!Objects.isNull(djj)) { + djj.setTypeOfDevice("1"); + } + return djj; + } + if("4".equals(deviceType)){ + //警务通设备 + EsGpsInfoVO3 pdt = setVO3(esGpsInfo.getDeviceCode(), "JWT", esGpsInfoVO3); + if(!Objects.isNull(pdt)) { + pdt.setTypeOfDevice("4"); + } + return pdt; + } + /*if("2".equals(deviceType)){ + //北斗设备 + EsGpsInfoVO3 pdt = setVO3(esGpsInfo.getDeviceCode(), "XLC", esGpsInfoVO3); + if(!Objects.isNull(pdt)) { + pdt.setTypeOfDevice("2"); + } + return pdt; + } + */ + + return null; + } + + private EsGpsInfoVO3 setVO3(String deviceCode,String deviceType, EsGpsInfoVO3 esGpsInfoVO3) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(DSQinwuEntity::getImei,deviceCode); + if (!"ZFJLY".equals(deviceType)){ + lqw.eq(DSQinwuEntity::getType,deviceType); + } + DSQinwuEntity dsQinwuEntity = dsQinwuDao.selectOne(lqw); + if(Objects.isNull(dsQinwuEntity)){ + return null; + } + if ("PDT".equals(deviceType) && jlyLatLng(dsQinwuEntity) && jwtLatLng(dsQinwuEntity)){ + log.error("该警员记录仪或警务通设备最近有坐标回传,警号={}",dsQinwuEntity.getPoliceNumber()); + return null; + } + if ("JWT".equals(deviceType) && jlyLatLng(dsQinwuEntity)){ + log.error("该警员记录仪设备最近有坐标回传,警号={}",dsQinwuEntity.getPoliceNumber()); + return null; + } + esGpsInfoVO3.setPoliceName(dsQinwuEntity.getPoliceName()); + if ("XLC".equals(dsQinwuEntity.getType())){ + esGpsInfoVO3.setCarNum(dsQinwuEntity.getName()); + } + esGpsInfoVO3.setZzjgdm(dsQinwuEntity.getOrgId()); + esGpsInfoVO3.setZzjgmc(dsQinwuEntity.getOrgName()); + //ds勤务绑定系统的id,对于其他系统来说可不用 + esGpsInfoVO3.setLinkId(dsQinwuEntity.getLinkId()); + //最后设置为101,即勤务需要的deviceType + esGpsInfoVO3.setDeviceType("9"); + esGpsInfoVO3.setTypeOfDevice(dsQinwuEntity.getType()); + + esGpsInfoVO3.setPoliceNo(dsQinwuEntity.getPoliceNumber()); + return esGpsInfoVO3; + } + + private boolean jlyLatLng(DSQinwuEntity dsQinwuEntity){ + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(DSQinwuEntity::getPoliceNumber,dsQinwuEntity.getPoliceNumber()); + lqw.eq(DSQinwuEntity::getType,"ZFJLY"); + lqw.orderByDesc(DSQinwuEntity::getUpdateTime).last("limit 1"); + + DSQinwuEntity qinwu = dsQinwuDao.selectOne(lqw); + if (null == qinwu){ + return false; + } + Object obj = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + "9:" + qinwu.getImei()); + if (null == obj){ + return false; + }else { + // 如需按照gps最新时间来判断 可在这添加逻辑 + + EsGpsInfoVO3 esGpsInfoVO3 = BeanUtil.toBean(obj.toString(),EsGpsInfoVO3.class); + if (DateUtil.between(new Date(),esGpsInfoVO3.getGpsTime(), DateUnit.SECOND)>120){ + return false; + }else { + return true; + } + } + } + + private boolean jwtLatLng(DSQinwuEntity dsQinwuEntity){ + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(DSQinwuEntity::getPoliceNumber,dsQinwuEntity.getPoliceNumber()); + lqw.eq(DSQinwuEntity::getType,"JWT"); + lqw.orderByDesc(DSQinwuEntity::getUpdateTime).last("limit 1"); + + DSQinwuEntity qinwu = dsQinwuDao.selectOne(lqw); + if (null == qinwu){ + return false; + } + Object obj = RedisUtils.getBucket(RedisConstants.ONLINE_USERS + "9:" + qinwu.getImei()); + if (null == obj){ + return false; + }else { + EsGpsInfoVO3 esGpsInfoVO3 = BeanUtil.toBean(obj.toString(),EsGpsInfoVO3.class); + if (DateUtil.between(new Date(),esGpsInfoVO3.getGpsTime(), DateUnit.SECOND)>120){ + return false; + }else { + return true; + } + } + } + +} diff --git a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/util/ConfigConstants.java b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/util/ConfigConstants.java index 52f2b634..867ad32a 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/util/ConfigConstants.java +++ b/stwzhj-modules/stwzhj-data2es/src/main/java/org/dromara/data2es/util/ConfigConstants.java @@ -3,5 +3,5 @@ package org.dromara.data2es.util; public class ConfigConstants { public static final String HTTP_HEADER_AUTH_TOKEN = "Auth-Token"; - public static final String KAFKA_TOPIC_SEND_PRE = "rs_topic.send"; + public static final String KAFKA_TOPIC_SEND_PRE = "topic.send"; } diff --git a/stwzhj-modules/stwzhj-data2es/src/main/resources/application.yml b/stwzhj-modules/stwzhj-data2es/src/main/resources/application.yml index ea12e957..5d89ca5f 100644 --- a/stwzhj-modules/stwzhj-data2es/src/main/resources/application.yml +++ b/stwzhj-modules/stwzhj-data2es/src/main/resources/application.yml @@ -6,7 +6,7 @@ server: spring: application: # 应用名称 - name: stwzhj-data2es + name: wzhj-data2es profiles: # 环境配置 active: @profiles.active@ diff --git a/stwzhj-modules/stwzhj-dataToGas/src/main/java/org/dromara/data2gs/service/package-info.java b/stwzhj-modules/stwzhj-dataToGas/src/main/java/org/dromara/data2gs/service/package-info.java new file mode 100644 index 00000000..5f8d0a37 --- /dev/null +++ b/stwzhj-modules/stwzhj-dataToGas/src/main/java/org/dromara/data2gs/service/package-info.java @@ -0,0 +1 @@ +package org.dromara.data2gs.service; diff --git a/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java b/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java index ff53efa7..1cf210af 100644 --- a/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java +++ b/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java @@ -1,8 +1,10 @@ package org.dromara.location.controller; import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUnit; import cn.hutool.core.date.DateUtil; import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import org.apache.dubbo.config.annotation.DubboReference; @@ -14,6 +16,7 @@ import org.dromara.system.api.domain.vo.RemoteDeviceVo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.PostMapping; @@ -32,6 +35,11 @@ public class LocationController { @DubboReference private RemoteDeviceService deviceService; + + //判断回传离当前多少秒 + @Value("${location.pointtime}") + private Integer pointTime; + Logger logger = LoggerFactory.getLogger(LocationController.class); @@ -47,6 +55,10 @@ public class LocationController { key = keys +"*"; } List list = new ArrayList<>(); + String times = ""; //用来判断是否需要最新数据 + if (null != params.get("times")){ + times = params.get("times").toString(); + } if (null != params.get("type")){ String type = params.get("type").toString(); key = keys + "*:[" +type+"]:*"; @@ -54,9 +66,23 @@ public class LocationController { key = keys + params.get("deptId").toString() + "*:["+type+"]:*"; // key值为 online_users:2022-04-20:3401*:[01,02]:* } + }else { + key = keys +"*"; } list = RedisUtils.searchAndGetKeysValues(key); list.removeAll(Collections.singleton(null)); + if ("1".equals(times)){ + List nearList = new ArrayList<>(); + for (Object o : list) { + JSONObject object = JSONUtil.parseObj(o); + Integer online = object.getInt("online"); + Long gpstime = object.getLong("gpsTime"); + if (1 == online && DateUtil.between(new Date(gpstime),new Date(), DateUnit.SECOND) dlist = new ArrayList<>(); if (null != params.get("type")){ //类型不为空时 查询Redis数据 @@ -92,6 +122,18 @@ public class LocationController { } } JSONArray.toJSONString(dlist); + if ("1".equals(times)){ + List nearList = new ArrayList<>(); + for (Object o : dlist) { + JSONObject object = JSONUtil.parseObj(o); + Integer online = object.getInt("online"); + Long gpstime = object.getLong("gpsTime"); + if (1 == online && DateUtil.between(new Date(gpstime),new Date(), DateUnit.SECOND) params){ + if(CollectionUtils.isEmpty(params)){ + return R.fail(-1,"参数不能为空"); + } + RemoteDeviceBo device = new RemoteDeviceBo(); + device.setValid(1); + if (null != params.get("deviceType")){ + device.setDeviceType(params.get("deviceType").toString()); + } + if (null != params.get("zzjgdm") && !"341800000000".equals(params.get("zzjgdm").toString())){ + String[] zzjgdms = params.get("zzjgdm").toString().split(","); + device.setZzjgdms(zzjgdms); + } + + List list = deviceService.deviceList(device); + + return R.ok(list); + } + public String deptIdSub(String zzjgdm){ if (zzjgdm.endsWith("0000000000")){ // 省厅 即全部 diff --git a/stwzhj-modules/stwzhj-location/src/main/resources/application.yml b/stwzhj-modules/stwzhj-location/src/main/resources/application.yml index 7ab487c2..497aac98 100644 --- a/stwzhj-modules/stwzhj-location/src/main/resources/application.yml +++ b/stwzhj-modules/stwzhj-location/src/main/resources/application.yml @@ -6,7 +6,7 @@ server: spring: application: # 应用名称 - name: stwzhj-location + name: wzhj-location profiles: # 环境配置 active: @profiles.active@ diff --git a/stwzhj-modules/stwzhj-system/pom.xml b/stwzhj-modules/stwzhj-system/pom.xml index bd976e2a..2f608feb 100644 --- a/stwzhj-modules/stwzhj-system/pom.xml +++ b/stwzhj-modules/stwzhj-system/pom.xml @@ -127,6 +127,18 @@ + + org.apache.maven.plugins + maven-resources-plugin + 3.1.0 + + + + xlsx + xls + + + diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java index ce954fa9..ea35ac0c 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -8,7 +8,10 @@ import org.dromara.common.core.domain.R; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.web.core.BaseController; +import org.dromara.system.api.model.LoginUser; +import org.dromara.system.domain.SysUser; import org.dromara.system.domain.bo.SysDeptBo; import org.dromara.system.domain.vo.SysDeptVo; import org.dromara.system.service.ISysDeptService; @@ -44,7 +47,8 @@ public class SysDeptController extends BaseController { @GetMapping("/deviceDept/{deviceType}") public R> deviceDpet(@PathVariable(value = "deviceType", required = false) String deviceType) { - List depts = deptService.deviceStatics(deviceType); + LoginUser user = LoginHelper.getLoginUser(); + List depts = deptService.deviceStatics(deviceType,user.getManageDeptId()); return R.ok(depts); } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysUserController.java index fae9451d..df512f05 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysUserController.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/SysUserController.java @@ -72,7 +72,7 @@ public class SysUserController extends BaseController { @PostMapping("/export") public void export(SysUserBo user, HttpServletResponse response) { List list = userService.selectUserExportList(user); - ExcelUtil.exportExcel(list, "用户数据", SysUserExportVo.class, response); + ExcelUtil.exportExcel(list, "user", SysUserExportVo.class, response); } /** diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/TDeviceController.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/TDeviceController.java index 8e7f87da..edd4248c 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/TDeviceController.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/controller/system/TDeviceController.java @@ -1,11 +1,19 @@ package org.dromara.system.controller; +import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.system.domain.vo.SysUserImportVo; +import org.dromara.system.domain.vo.TDeviceExportVo; +import org.dromara.system.domain.vo.TDeviceImportVo; +import org.dromara.system.listener.SysUserImportListener; +import org.dromara.system.listener.TDeviceImportListener; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import org.dromara.common.idempotent.annotation.RepeatSubmit; @@ -21,6 +29,7 @@ import org.dromara.system.domain.vo.TDeviceVo; import org.dromara.system.domain.bo.TDeviceBo; import org.dromara.system.service.ITDeviceService; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; /** * device @@ -53,8 +62,32 @@ public class TDeviceController extends BaseController { @Log(title = "device", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(TDeviceBo bo, HttpServletResponse response) { - List list = tDeviceService.queryList(bo); - ExcelUtil.exportExcel(list, "device", TDeviceVo.class, response); + List list = tDeviceService.selectDeviceExportList(bo); + ExcelUtil.exportExcel(list, "device", TDeviceExportVo.class, response); + } + + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "设备数据", TDeviceImportVo.class, response); + } + + + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "设备管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:device:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), TDeviceImportVo.class, new TDeviceImportListener(updateSupport)); + return R.ok(result.getAnalysis()); } /** diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysDept.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysDept.java index ca416d48..2113f91d 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysDept.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysDept.java @@ -77,4 +77,6 @@ public class SysDept extends TenantEntity { */ private String ancestors; + private String fullName; + } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysUser.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysUser.java index b291a36b..4028aa2f 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysUser.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/SysUser.java @@ -103,6 +103,8 @@ public class SysUser extends TenantEntity { */ private String remark; + private String manageDeptId; + public SysUser(Long userId) { this.userId = userId; diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/TDevice.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/TDevice.java index 0b81b76f..572858ea 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/TDevice.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/TDevice.java @@ -30,7 +30,6 @@ public class TDevice { /** * 外部系统设备编号建议21位 */ - @MppMultiId private String deviceCode; /** @@ -38,12 +37,6 @@ public class TDevice { */ private String deviceType; - private String sbpp; - - private String sbxh; - - @MppMultiId - private String infoSource; /** * 组织机构代码 @@ -92,25 +85,11 @@ public class TDevice { */ private String remark2; + @TableField(fill = FieldFill.INSERT) private String createTime; + @TableField(fill = FieldFill.INSERT_UPDATE) private String updateTime; - private String lrdwdm; - - private String lrdwmc; - - private String lrrxm; - - private String lrrsfzh; - - private String xgdwdm; - - private String xgdwmc; - - private String xgrxm; - - private String xgrsfzh; - } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java index 6fdb0584..e0812819 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java @@ -73,4 +73,6 @@ public class SysDeptBo extends BaseEntity { */ private String status; + private String fullName; + } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java index 834ebbb7..ea591729 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java @@ -108,6 +108,8 @@ public class SysUserBo extends BaseEntity { */ private String excludeUserIds; + private String manageDeptId; + public SysUserBo(Long userId) { this.userId = userId; } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/TDeviceBo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/TDeviceBo.java index 4f697e88..2334e292 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/TDeviceBo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/bo/TDeviceBo.java @@ -31,7 +31,6 @@ public class TDeviceBo extends BaseEntity { @NotBlank(message = "设备编号不能为空", groups = { AddGroup.class, EditGroup.class }) private String deviceCode; - @NotBlank(message = "地市编码不能为空", groups = { AddGroup.class, EditGroup.class }) private String infoSource; /** @@ -93,21 +92,8 @@ public class TDeviceBo extends BaseEntity { */ private String remark2; - private String lrdwdm; + private String[] zzjgdms; - private String lrdwmc; - - private String lrrxm; - - private String lrrsfzh; - - private String xgdwdm; - - private String xgdwmc; - - private String xgrxm; - - private String xgrsfzh; } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java index 565c0c72..75d16f5b 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java @@ -99,8 +99,10 @@ public class SysDeptVo implements Serializable { @ExcelProperty(value = "创建时间") private Date createTime; - private Integer co; + private Integer allCount; - private String online; + private Integer onlineCount; + + private String fullName; } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java index 0140acea..4f6eb2e5 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -113,6 +113,7 @@ public class SysUserVo implements Serializable { */ private Date createTime; + private String manageDeptId; /** * 部门名 */ diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceExportVo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceExportVo.java new file mode 100644 index 00000000..a611044c --- /dev/null +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceExportVo.java @@ -0,0 +1,87 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@NoArgsConstructor +public class TDeviceExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "设备编号") + private String deviceCode; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型") + @ExcelDictFormat(dictType = "zd_device_type") + private String deviceType; + + /** + * 组织机构代码 + */ + @ExcelProperty(value = "组织机构代码") + private String zzjgdm; + + /** + * 组织机构名称 + */ + @ExcelProperty(value = "组织机构名称") + private String zzjgmc; + + /** + * 警号(若有) + */ + @ExcelProperty(value = "警号", converter = ExcelDictConvert.class) + private String policeNo; + + /** + * 姓名(若有) + */ + @ExcelProperty(value = "警员姓名", converter = ExcelDictConvert.class) + private String policeName; + + /** + * 联系电话(若有) + */ + @ExcelProperty(value = "电话号码", converter = ExcelDictConvert.class) + private String phoneNum; + + /** + * 车牌号(若有) + */ + @ExcelProperty(value = "车牌号", converter = ExcelDictConvert.class) + private String carNum; + + @ExcelProperty(value = "证件号码", converter = ExcelDictConvert.class) + private String cardNum; + + /** + * 0无效,1有效 + */ + @ExcelProperty(value = "有效性") + @ExcelDictFormat(readConverterExp = "1=有效,0=无效") + private Integer valid; + + /** + * 备注字段1 + */ + @ExcelProperty(value = "备注字段1") + private String remark1; + + /** + * 备注字段2 + */ + @ExcelProperty(value = "备注字段2") + private String remark2; + +} diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceImportVo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceImportVo.java new file mode 100644 index 00000000..69b1ecc8 --- /dev/null +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceImportVo.java @@ -0,0 +1,87 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@NoArgsConstructor +public class TDeviceImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "设备编号") + private String deviceCode; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "zd_device_type") + private String deviceType; + + /** + * 组织机构代码 + */ + @ExcelProperty(value = "组织机构代码") + private String zzjgdm; + + /** + * 组织机构名称 + */ + @ExcelProperty(value = "组织机构名称") + private String zzjgmc; + + /** + * 警号(若有) + */ + @ExcelProperty(value = "警号") + private String policeNo; + + /** + * 姓名(若有) + */ + @ExcelProperty(value = "警员姓名") + private String policeName; + + /** + * 联系电话(若有) + */ + @ExcelProperty(value = "电话号码") + private String phoneNum; + + /** + * 车牌号(若有) + */ + @ExcelProperty(value = "车牌号") + private String carNum; + + @ExcelProperty(value = "证件号码") + private String cardNum; + + /** + * 0无效,1有效 + */ + @ExcelProperty(value = "有效性", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "zd_device_status") + private String valid; + + /** + * 备注字段1 + */ + @ExcelProperty(value = "备注字段1") + private String remark1; + + /** + * 备注字段2 + */ + @ExcelProperty(value = "备注字段2") + private String remark2; + +} diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceVo.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceVo.java index 38215862..c812ca5e 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceVo.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/domain/vo/TDeviceVo.java @@ -37,7 +37,7 @@ public class TDeviceVo implements Serializable { /** * 外部系统设备编号建议21位 */ - @ExcelProperty(value = "外部系统设备编号建议21位") + @ExcelProperty(value = "设备编码") private String deviceCode; // 警号、姓名、车牌号组合字段 @@ -49,13 +49,6 @@ public class TDeviceVo implements Serializable { @ExcelProperty(value = "设备类型") private String deviceType; - - private String sbpp; - - private String sbxh; - - private String infoSource; - /** * 组织机构代码 */ @@ -121,21 +114,4 @@ public class TDeviceVo implements Serializable { private String updateTime; - private String lrdwdm; - - private String lrdwmc; - - private String lrrxm; - - private String lrrsfzh; - - private String xgdwdm; - - private String xgdwmc; - - private String xgrxm; - - private String xgrsfzh; - - } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java index dbd417b9..11e95310 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java @@ -1,11 +1,19 @@ package org.dromara.system.dubbo; +import cn.hutool.core.bean.BeanUtil; import org.dromara.system.api.RemoteDeptService; +import org.dromara.system.api.domain.bo.RemoteDeptBo; +import org.dromara.system.api.domain.vo.RemoteDeptVo; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; import org.dromara.system.service.ISysDeptService; import lombok.RequiredArgsConstructor; import org.apache.dubbo.config.annotation.DubboService; +import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; +import java.util.List; + /** * 部门服务 * @@ -28,4 +36,10 @@ public class RemoteDeptServiceImpl implements RemoteDeptService { public String selectDeptNameByIds(String deptIds) { return sysDeptService.selectDeptNameByIds(deptIds); } + + @Override + public List selectDept(RemoteDeptBo bo) { + List vos = sysDeptService.selectDeptList(BeanUtil.toBean(bo, SysDeptBo.class)); + return BeanUtil.copyToList(vos, RemoteDeptVo.class); + } } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java index fe2cbe69..00524fe4 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java @@ -253,6 +253,7 @@ public class RemoteUserServiceImpl implements RemoteUserService { loginUser.setTenantId(userVo.getTenantId()); loginUser.setUserId(userVo.getUserId()); loginUser.setDeptId(userVo.getDeptId()); + loginUser.setManageDeptId(userVo.getManageDeptId()); loginUser.setUsername(userVo.getUserName()); loginUser.setNickname(userVo.getNickName()); loginUser.setPassword(userVo.getPassword()); diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/listener/TDeviceImportListener.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/listener/TDeviceImportListener.java new file mode 100644 index 00000000..046e5b8a --- /dev/null +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/listener/TDeviceImportListener.java @@ -0,0 +1,111 @@ +package org.dromara.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HtmlUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.excel.core.ExcelListener; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.TDeviceBo; +import org.dromara.system.domain.vo.TDeviceImportVo; +import org.dromara.system.domain.vo.TDeviceVo; +import org.dromara.system.service.ITDeviceService; + +import java.util.List; + +@Slf4j +public class TDeviceImportListener extends AnalysisEventListener implements ExcelListener { + + private final ITDeviceService deviceService; + + private final Boolean isUpdateSupport; + + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public TDeviceImportListener(Boolean isUpdateSupport) { + this.deviceService = SpringUtils.getBean(ITDeviceService.class); + this.isUpdateSupport = isUpdateSupport; + } + + @Override + public void invoke(TDeviceImportVo deviceImportVo, AnalysisContext context) { + TDeviceVo deviceVo = this.deviceService.queryByDeviceCode(deviceImportVo.getDeviceCode()); + try { + // 验证是否存在这个设备 + if (ObjectUtil.isNull(deviceVo)) { + TDeviceBo deviceBo = BeanUtil.toBean(deviceImportVo, TDeviceBo.class); + ValidatorUtils.validate(deviceBo); + deviceService.insertByBo(deviceBo); + successNum++; + successMsg.append("
").append(successNum).append("、设备 ").append(deviceBo.getDeviceCode()).append(" 导入成功"); + } else if (isUpdateSupport) { + Long id = deviceVo.getId(); + TDeviceBo deviceBo = BeanUtil.toBean(deviceVo, TDeviceBo.class); + deviceBo.setId(id); + ValidatorUtils.validate(deviceBo); + deviceService.updateByBo(deviceBo); + successNum++; + successMsg.append("
").append(successNum).append("、设备 ").append(deviceImportVo.getDeviceCode()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append("
").append(failureNum).append("、设备 ").append(deviceImportVo.getDeviceCode()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、设备 " + HtmlUtil.cleanHtmlTag(deviceImportVo.getDeviceCode()) + " 导入失败:"; + String message = e.getMessage(); + if (e instanceof ConstraintViolationException cvException) { + message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + } + failureMsg.append(msg).append(message); + log.error(msg, e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult() { + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public List getList() { + return null; + } + + @Override + public List getErrorList() { + return null; + } + }; + } + + +} diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java index a2221dbb..addd6878 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java @@ -45,4 +45,6 @@ public interface SysDeptMapper extends BaseMapperPlus { List deviceStatics(@Param("deviceType") String deviceType); + List deviceStaticsByDeptId(@Param("deviceType")String deviceType, @Param("deptId")String deptId); + } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/TDeviceMapper.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/TDeviceMapper.java index 591e203c..b834effd 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/TDeviceMapper.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/mapper/TDeviceMapper.java @@ -1,7 +1,15 @@ package org.dromara.system.mapper; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; import org.dromara.system.domain.TDevice; +import org.dromara.system.domain.bo.TDeviceBo; import org.dromara.system.domain.vo.DeviceStaticsVo; +import org.dromara.system.domain.vo.TDeviceExportVo; import org.dromara.system.domain.vo.TDeviceVo; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; @@ -17,4 +25,14 @@ public interface TDeviceMapper extends BaseMapperPlus { List countByDs(); + @DataPermission({ + @DataColumn(key = "deptName", value = "zzjgdm") + }) + List selectDeviceExportList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + @DataPermission({ + @DataColumn(key = "deptName", value = "zzjgdm") + }) + Page selectPageDevicetList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/schedule/DeviceRedisSchedule.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/schedule/DeviceRedisSchedule.java index e19dbc9e..bda57b27 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/schedule/DeviceRedisSchedule.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/schedule/DeviceRedisSchedule.java @@ -45,7 +45,8 @@ public class DeviceRedisSchedule { redisService.insertBatch(BeanUtil.copyToList(jlist, DeviceRedis.class)); } -// @Scheduled(cron = "0 0 0/1 * * ?") + @PostConstruct + @Scheduled(cron = "0 0 0/1 * * ?") public void handleDeviceInfoToRedis(){ if (null == lastUpdateTime || "".equals(lastUpdateTime)){ log.error("lastUpdateTime=null"); @@ -61,7 +62,7 @@ public class DeviceRedisSchedule { for (TDeviceVo vo : list) { String jsonValue = JSONUtil.toJsonStr(vo); - String infoKey = "deviceInfo:" + vo.getInfoSource()+":"+vo.getDeviceCode(); + String infoKey = "deviceInfo:" + vo.getDeviceType()+":"+vo.getDeviceCode(); deviceInfoDataMap.put(infoKey, jsonValue); } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ISysDeptService.java index f47230aa..254f73d6 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ISysDeptService.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -137,5 +137,5 @@ public interface ISysDeptService { * */ List getDsList(); - List deviceStatics(String deviceType); + List deviceStatics(String deviceType,String manageDeptId); } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ITDeviceService.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ITDeviceService.java index 8cc93964..eac8b717 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ITDeviceService.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/ITDeviceService.java @@ -3,6 +3,7 @@ package org.dromara.system.service; import org.dromara.common.core.domain.R; import org.dromara.system.domain.TDevice; import org.dromara.system.domain.vo.DeviceStaticsVo; +import org.dromara.system.domain.vo.TDeviceExportVo; import org.dromara.system.domain.vo.TDeviceVo; import org.dromara.system.domain.bo.TDeviceBo; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -78,4 +79,8 @@ public interface ITDeviceService { Long countByCondition(TDeviceBo bo); R saveDeviceToSt(String infoSource,List list); + + TDeviceVo queryByDeviceCode(String deviceCode); + + List selectDeviceExportList(TDeviceBo bo); } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index 07cc150e..96eecc22 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -82,6 +82,7 @@ public class SysDeptServiceImpl implements ISysDeptService { lqw.eq(StringUtils.isNotBlank(bo.getParentId()), SysDept::getParentId, bo.getParentId()); lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName()); lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getFullName()), SysDept::getFullName, bo.getFullName()); lqw.orderByAsc(SysDept::getAncestors); lqw.orderByAsc(SysDept::getParentId); lqw.orderByAsc(SysDept::getOrderNum); @@ -349,7 +350,22 @@ public class SysDeptServiceImpl implements ISysDeptService { } @Override - public List deviceStatics(String deviceType) { + public List deviceStatics(String deviceType,String manageDeptId) { + if(!manageDeptId.equals("341800000000")){ + String subManageId = manageDeptId.substring(0,findLastNonZeroIndex(manageDeptId) + 1); + return baseMapper.deviceStaticsByDeptId(deviceType,subManageId); + + } return baseMapper.deviceStatics(deviceType); } + + public int findLastNonZeroIndex(String str) { + // 从字符串末尾开始向前查找 + for (int i = str.length() - 1; i >= 0; i--) { + if (str.charAt(i) != '0') { + return i; // 返回最后一个不为0的字符的下标 + } + } + return -1; // 如果没有找到不为0的字符,返回-1 + } } diff --git a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/TDeviceServiceImpl.java b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/TDeviceServiceImpl.java index 8ee6e27d..89be59d7 100644 --- a/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/TDeviceServiceImpl.java +++ b/stwzhj-modules/stwzhj-system/src/main/java/org/dromara/system/service/impl/TDeviceServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.system.service.impl; import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.dubbo.config.annotation.DubboReference; import org.dromara.common.core.domain.R; import org.dromara.common.core.utils.MapstructUtils; @@ -14,6 +15,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import org.dromara.system.api.RemoteDataScopeService; import org.dromara.system.domain.vo.DeviceStaticsVo; +import org.dromara.system.domain.vo.TDeviceExportVo; import org.springframework.stereotype.Service; import org.dromara.system.domain.bo.TDeviceBo; import org.dromara.system.domain.vo.TDeviceVo; @@ -62,8 +64,9 @@ public class TDeviceServiceImpl implements ITDeviceService { */ @Override public TableDataInfo queryPageList(TDeviceBo bo, PageQuery pageQuery) { + bo.setValid(1); LambdaQueryWrapper lqw = buildQueryWrapper(bo); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + Page result = baseMapper.selectPageDevicetList(pageQuery.build(), lqw); List list = result.getRecords(); for (TDeviceVo vo : list) { if ("".equals(vo.getPoliceName()) || null == vo.getPoliceName()){ @@ -91,7 +94,28 @@ public class TDeviceServiceImpl implements ITDeviceService { @Override public List queryList(TDeviceBo bo) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); + List list = baseMapper.selectVoList(lqw); + for (TDeviceVo vo : list) { + if ("".equals(vo.getPoliceName()) || null == vo.getPoliceName()){ + vo.setDeviceName(vo.getCarNum()); + } + if("".equals(vo.getCarNum()) || null == vo.getCarNum()){ + if (!"".equals(vo.getPoliceNo()) && null != vo.getPoliceNo()){ + vo.setDeviceName(vo.getPoliceNo()+"-"+vo.getPoliceName()); + }else { + vo.setDeviceName(vo.getPoliceName()); + } + + } + + } + return list; + } + + @Override + public List selectDeviceExportList(TDeviceBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectDeviceExportList(lqw); } @Override @@ -119,8 +143,8 @@ public class TDeviceServiceImpl implements ITDeviceService { lqw.inSql(TDevice::getZzjgdm,depts); } } + lqw.in(null != bo.getZzjgdms() && bo.getZzjgdms().length>0,TDevice::getZzjgdm,bo.getZzjgdms()); lqw.eq(StringUtils.isNotBlank(bo.getZzjgmc()), TDevice::getZzjgmc, bo.getZzjgmc()); - lqw.eq(StringUtils.isNotBlank(bo.getInfoSource()), TDevice::getInfoSource, bo.getInfoSource()); lqw.and(StringUtils.isNotBlank(bo.getPoliceName()),wrapper -> wrapper.like(TDevice::getPoliceNo, bo.getPoliceName()) .or().like(TDevice::getPoliceName, bo.getPoliceName()).or().like(TDevice::getCarNum, bo.getPoliceName())); lqw.eq(StringUtils.isNotBlank(bo.getPhoneNum()), TDevice::getPhoneNum, bo.getPhoneNum()); @@ -143,6 +167,8 @@ public class TDeviceServiceImpl implements ITDeviceService { public Boolean insertByBo(TDeviceBo bo) { TDevice add = MapstructUtils.convert(bo, TDevice.class); validEntityBeforeSave(add); + add.setCreateTime(DateUtil.now()); + add.setUpdateTime(DateUtil.now()); boolean flag = baseMapper.insert(add) > 0; if (flag) { bo.setId(add.getId()); @@ -159,6 +185,7 @@ public class TDeviceServiceImpl implements ITDeviceService { @Override public Boolean updateByBo(TDeviceBo bo) { TDevice update = MapstructUtils.convert(bo, TDevice.class); + update.setUpdateTime(DateUtil.now()); validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } @@ -182,7 +209,11 @@ public class TDeviceServiceImpl implements ITDeviceService { if(isValid){ //TODO 做一些业务上的校验,判断是否需要校验 } - return baseMapper.deleteByIds(ids) > 0; + LambdaUpdateWrapper luw = new LambdaUpdateWrapper<>(); + luw.set(TDevice::getValid,0); + luw.set(TDevice::getUpdateTime,DateUtil.now()); + luw.in(TDevice::getId,ids); + return baseMapper.update(luw) > 0; } @Override @@ -191,7 +222,7 @@ public class TDeviceServiceImpl implements ITDeviceService { // 先根据 field1 和 field2 查询出已存在的记录 List existingEntities = baseMapper.selectList(new QueryWrapper() .in("device_code", list.stream().map(TDevice::getDeviceCode).collect(Collectors.toList())) - .in("info_source", list.stream().map(TDevice::getInfoSource).collect(Collectors.toList()))); + .in("device_type", list.stream().map(TDevice::getDeviceType).collect(Collectors.toList()))); // 找到需要更新的记录 List toUpdate = new ArrayList<>(); @@ -201,7 +232,7 @@ public class TDeviceServiceImpl implements ITDeviceService { for (TDevice entity : list) { boolean exists = false; for (TDevice existingEntity : existingEntities) { - if (entity.getDeviceCode().equals(existingEntity.getDeviceCode()) && entity.getInfoSource().equals(existingEntity.getInfoSource())) { + if (entity.getDeviceCode().equals(existingEntity.getDeviceCode()) && entity.getDeviceType().equals(existingEntity.getDeviceType())) { entity.setId(existingEntity.getId()); // 设置 ID 以便更新 toUpdate.add(entity); exists = true; @@ -259,7 +290,6 @@ public class TDeviceServiceImpl implements ITDeviceService { errorList.add(deviceEntityV2); continue; } - deviceEntityV2.setInfoSource(infoSource); try { TDevice oldEntity = checkDeviceExists(deviceEntityV2); if (Objects.isNull(oldEntity)) { @@ -299,7 +329,7 @@ public class TDeviceServiceImpl implements ITDeviceService { public TDevice checkDeviceExists(TDevice deviceEntityV2) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("device_code", deviceEntityV2.getDeviceCode()); - queryWrapper.eq("info_source", deviceEntityV2.getInfoSource()); + queryWrapper.eq("info_source", deviceEntityV2.getDeviceType()); TDevice deviceEntity1 = baseMapper.selectOne(queryWrapper); return deviceEntity1; } @@ -314,4 +344,11 @@ public class TDeviceServiceImpl implements ITDeviceService { return matcher.matches(); } + @Override + public TDeviceVo queryByDeviceCode(String deviceCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("device_code", deviceCode); + TDeviceVo vo = baseMapper.selectVoOne(queryWrapper); + return vo; + } } diff --git a/stwzhj-modules/stwzhj-system/src/main/resources/application.yml b/stwzhj-modules/stwzhj-system/src/main/resources/application.yml index dc30ec3e..59269b86 100644 --- a/stwzhj-modules/stwzhj-system/src/main/resources/application.yml +++ b/stwzhj-modules/stwzhj-system/src/main/resources/application.yml @@ -6,7 +6,7 @@ server: spring: application: # 应用名称 - name: stwzhj-system + name: wzhj-system profiles: # 环境配置 active: @profiles.active@ diff --git a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/DeviceRedisMapper.xml b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/DeviceRedisMapper.xml index 79d7d2ed..8065277e 100644 --- a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/DeviceRedisMapper.xml +++ b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/DeviceRedisMapper.xml @@ -16,8 +16,10 @@ #{entity.deviceCode},#{entity.deviceType},#{entity.online},#{entity.zzjgdm} ) - ON conflict(device_code,device_type) do update set - (online,zzjgdm) =(EXCLUDED.online,EXCLUDED.zzjgdm) + ON DUPLICATE KEY UPDATE + device_type = VALUES(device_type), + online = VALUES(online), + zzjgdm = VALUES(zzjgdm) diff --git a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/SysDeptMapper.xml b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/SysDeptMapper.xml index 24f60ace..98fa431b 100644 --- a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/SysDeptMapper.xml +++ b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -36,108 +36,197 @@ + + diff --git a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/TDeviceMapper.xml b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/TDeviceMapper.xml index 3e8426d0..1cf491f0 100644 --- a/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/TDeviceMapper.xml +++ b/stwzhj-modules/stwzhj-system/src/main/resources/mapper/system/TDeviceMapper.xml @@ -7,9 +7,31 @@ + + + + + + + + + + + + diff --git a/stwzhj-modules/wzhj-extract/pom.xml b/stwzhj-modules/wzhj-extract/pom.xml new file mode 100644 index 00000000..f37265c8 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/pom.xml @@ -0,0 +1,138 @@ + + + + org.dromara + stwzhj-modules + ${revision} + + 4.0.0 + + wzhj-extract + + + wzhj-extract 数据抽取服务 + + + + + + org.dromara + stwzhj-common-nacos + + + + org.dromara + stwzhj-common-sentinel + + + + + org.dromara + stwzhj-common-log + + + + org.dromara + stwzhj-common-dict + + + + org.dromara + stwzhj-common-doc + + + + org.dromara + stwzhj-common-web + + + + org.dromara + stwzhj-common-mybatis + + + + org.dromara + stwzhj-common-dubbo + + + + org.dromara + stwzhj-common-seata + + + + org.dromara + stwzhj-common-idempotent + + + + org.dromara + stwzhj-common-tenant + + + + org.dromara + stwzhj-common-security + + + + org.dromara + stwzhj-common-translation + + + + org.dromara + stwzhj-common-sensitive + + + + org.dromara + stwzhj-common-encrypt + + + + org.dromara + stwzhj-common-redis + + + + + org.dromara + stwzhj-api-system + + + + org.dromara + stwzhj-api-resource + + + + org.dromara + stwzhj-api-data2es + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/WzhjExtractApplication.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/WzhjExtractApplication.java new file mode 100644 index 00000000..2be09980 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/WzhjExtractApplication.java @@ -0,0 +1,24 @@ +package org.dromara.extract; + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 系统模块 + * + * @author ruoyi + */ +@EnableDubbo +@EnableScheduling +@SpringBootApplication +public class WzhjExtractApplication { + public static void main(String[] args) { + SpringApplication application = new SpringApplication(WzhjExtractApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ 数据抽取模块启动成功 ლ(´ڡ`ლ)゙ "); + } +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/conf/ruansi.properties b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/conf/ruansi.properties new file mode 100644 index 00000000..d270ad1a --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/conf/ruansi.properties @@ -0,0 +1 @@ +lastUpdateTime=2020-06-05 11:40:00 \ No newline at end of file diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/controller/DeviceGPSController.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/controller/DeviceGPSController.java new file mode 100644 index 00000000..650b419e --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/controller/DeviceGPSController.java @@ -0,0 +1,139 @@ +package org.dromara.extract.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.extract.domain.EsGpsInfo; +import org.dromara.extract.exception.MyBusinessException; +import org.dromara.extract.service.ITDeviceGpsService; +import org.dromara.extract.util.PathUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Duration; +import java.time.Instant; +import java.util.*; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.stream.Collectors; + +@RestController +public class DeviceGPSController { + + private Logger logger = LoggerFactory.getLogger(DeviceGPSController.class); + + @Autowired + ITDeviceGpsService deviceGpsService; + + @DubboReference + RemoteDataToEsService dataToEsService; + + + + private String lastUpdateTime = "2024-06-05 11:40:00"; + + @RequestMapping("/maxId") + public String getMaxId(){ + return lastUpdateTime; + } + + + + @RequestMapping("/getMaxGcTime") + public String getMaxGcTime(){ + EsGpsInfo info = deviceGpsService.selectBDGCMaxTime(); + return DateUtil.formatDateTime(info.getGpsTime()); + } + + @Scheduled(cron = "0/30 * * * * ?") + @Async + public void bdgcGps(){ + if(StringUtils.isBlank(lastUpdateTime)){ + try { + lastUpdateTime = getLastUpdateTimeFromProperties(); + }catch (Exception e){ + logger.info("lastUpdateTime={},lastUpdateTimeError={}",lastUpdateTime,e.getMessage()); + } + } +// Date date = DateUtil.parseDateTime(lastUpdateTime); + EsGpsInfo gpsInfo = new EsGpsInfo(); + gpsInfo.setGpsTime(DateUtil.parseDateTime(lastUpdateTime)); + Instant start = Instant.now(); +// some code + List list = deviceGpsService.selectBDGCGPS(gpsInfo); + Instant finish = Instant.now(); + long timeElapsed = Duration.between(start, finish).toMillis(); + logger.info("查询耗时:"+timeElapsed); + logger.info("数据大小size"+list.size()); + Date nowDate = new Date(); + + for (int i = 0; i < list.size(); i++) { + EsGpsInfo info = list.get(i); + if(i == 0){ + lastUpdateTime = DateUtil.formatDateTime(info.getGpsTime()); +// resetUpdateTime(info.getId()+""); + } + if (DateUtil.between(nowDate,info.getGpsTime(),DateUnit.MINUTE) > 30){ + info.setOnline("0"); + }else { + info.setOnline("1"); + } +// dataToEsService.saveGps(info); +// kafkaProducer.sendByObj(info,"car_gps_xuancheng"); + } + ArrayList collect = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> + new TreeSet<>(Comparator.comparing(EsGpsInfo::getDeviceCode))), ArrayList::new)); + logger.info("去重前size={},去重后size={}",list.size(),collect.size()); +// List remoteGpsInfos = new ArrayList<>(); +// remoteGpsInfos.add() + dataToEsService.saveDataBatch(BeanUtil.copyToList(collect,RemoteGpsInfo.class)); + Instant end = Instant.now(); + long timeEnd = Duration.between(finish, end).toMillis(); + logger.info("方法执行逻辑耗时:"+timeEnd); + + } + + + private void resetUpdateTime(String lastUpdateTime) { + try { +// lastUpdateTime = DateUtil.format(gpsTime,"yyyy-MM-dd HH:mm:ss"); + PathUtil.updateProperties(PathUtil.getProperties("ruansi.properties"),"lastUpdateTime",lastUpdateTime,"ruansi.properties"); + }catch (Exception e){ + logger.info("lastTime reset error"+e.getMessage()); + e.printStackTrace(); + } + } + + + private String getLastUpdateTimeFromProperties() { + Properties properties = PathUtil.getProperties("ruansi.properties"); + if(Objects.isNull(properties)){ + throw new MyBusinessException("jar包所在文件夹下conf子目录下缺少[ruansi.properties] 文件,请新建"); + } + String lastUpdateTime = properties.getProperty("lastUpdateTime"); + if(StringUtils.isEmpty(lastUpdateTime)){ + throw new MyBusinessException("[ruansi.properties]文件内缺少[lastUpdateTime]属性"); + } +// checkTimeFormatter(lastUpdateTime); + return lastUpdateTime; + } + + private void checkTimeFormatter(String lastUpdateTime) { + try { + DateTime parse = DateUtil.parse(lastUpdateTime, "yyyy-MM-dd HH:mm:ss"); + }catch (Exception e){ + throw new MyBusinessException(e.getMessage()); + } + } + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/domain/EsGpsInfo.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/domain/EsGpsInfo.java new file mode 100644 index 00000000..d83ed7d3 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/domain/EsGpsInfo.java @@ -0,0 +1,46 @@ +package org.dromara.extract.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + *

description:

+ * gps定位信息(es表) + * @author chenle + * @date 2021-05-14 9:39 + */ +@Data +public class EsGpsInfo implements Serializable { + + private static final long serialVersionUID = 7455495841680488351L; + + private Long id; + /** + * 唯一码(外部系统)合肥版本不需要 21位id, + * 到时候上传省厅的时候 需要在kafka发送端处理,生成一个省厅需要的21位id + */ + private String deviceCode; + /** + * 类型 + */ + private String deviceType; + private String lat; + private String lng; + //方向 + private String orientation; + //高程 + private String height; + //精度 + private String deltaH; + private String speed; + + + @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private Date gpsTime; + + private String online; + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/exception/MyBusinessException.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/exception/MyBusinessException.java new file mode 100644 index 00000000..4ebf17dd --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/exception/MyBusinessException.java @@ -0,0 +1,54 @@ +package org.dromara.extract.exception; + +/** + *

description:

+ * + * @author chenle + * @date 2021-06-07 10:56 + */ +public class MyBusinessException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public MyBusinessException(String msg) { + super(msg); + this.msg = msg; + } + + public MyBusinessException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public MyBusinessException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public MyBusinessException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/mapper/DeviceGpsMapper.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/mapper/DeviceGpsMapper.java new file mode 100644 index 00000000..1bb591ed --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/mapper/DeviceGpsMapper.java @@ -0,0 +1,19 @@ +package org.dromara.extract.mapper; + + + +import org.dromara.extract.domain.EsGpsInfo; + +import java.util.List; + +public interface DeviceGpsMapper { + + List selectPDTGPS(EsGpsInfo esGpsInfo); + + List selectYDJWGPS(EsGpsInfo esGpsInfo); + + List selectBDGCGPS(EsGpsInfo esGpsInfo); + + EsGpsInfo selectBDGCMaxTime(); + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/ITDeviceGpsService.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/ITDeviceGpsService.java new file mode 100644 index 00000000..f9cb7850 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/ITDeviceGpsService.java @@ -0,0 +1,15 @@ +package org.dromara.extract.service; + + + +import org.dromara.extract.domain.EsGpsInfo; + +import java.util.List; + +public interface ITDeviceGpsService { + + List selectBDGCGPS(EsGpsInfo esGpsInfo); + + EsGpsInfo selectBDGCMaxTime(); + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/impl/TDeviceGpsServiceImpl.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/impl/TDeviceGpsServiceImpl.java new file mode 100644 index 00000000..ddaf97b5 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/service/impl/TDeviceGpsServiceImpl.java @@ -0,0 +1,29 @@ +package org.dromara.extract.service.impl; + + + +import org.dromara.extract.domain.EsGpsInfo; +import org.dromara.extract.mapper.DeviceGpsMapper; +import org.dromara.extract.service.ITDeviceGpsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class TDeviceGpsServiceImpl implements ITDeviceGpsService { + + @Autowired + DeviceGpsMapper deviceMapper; + + + @Override + public List selectBDGCGPS(EsGpsInfo esGpsInfo) { + return deviceMapper.selectBDGCGPS(esGpsInfo); + } + + @Override + public EsGpsInfo selectBDGCMaxTime() { + return deviceMapper.selectBDGCMaxTime(); + } +} diff --git a/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/util/PathUtil.java b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/util/PathUtil.java new file mode 100644 index 00000000..35dc6320 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/java/org/dromara/extract/util/PathUtil.java @@ -0,0 +1,60 @@ +package org.dromara.extract.util; + +/** + *

description:

+ * + * @author chenle + * @date 2022-08-05 12:00 + */ + +import java.io.*; +import java.util.Properties; + +public class PathUtil { + + static String outpath = System.getProperty("user.dir")+File.separator+"conf"+File.separator;//先读取config目录的,没有再加载classpath的 + + + public static Properties getProperties(String fileName) { + System.out.println("文件路径:"+outpath); + try { + Properties properties = new Properties(); + InputStream in = new FileInputStream(new File(outpath + fileName)); + properties.load(in); + return properties; + } catch (IOException e) { + try { + Properties properties = new Properties(); + InputStream in = PathUtil.class.getClassLoader().getResourceAsStream(fileName);//默认加载classpath的 + properties.load(in); + return properties; + } catch (IOException es) { + return null; + } + } + } + + + + /** + * 更新properties文件的键值对 + * 如果该主键已经存在,更新该主键的值; + * 如果该主键不存在,则插件一对键值。 + * @param keyname 键名 + * @param keyvalue 键值 + */ + public static void updateProperties(Properties props,String keyname,String keyvalue,String fileName) throws IOException { + + // 调用 Hashtable 的方法 put,使用 getProperty 方法提供并行性。 + // 强制要求为属性的键和值使用字符串。返回值是 Hashtable 调用 put 的结果。 + OutputStream fos = new FileOutputStream(outpath + fileName); + props.setProperty(keyname, keyvalue); + // 以适合使用 load 方法加载到 Properties 表中的格式, + // 将此 Properties 表中的属性列表(键和元素对)写入输出流 + props.store(fos, "Update '" + keyname + "' value"); + + } + + + +} diff --git a/stwzhj-modules/wzhj-extract/src/main/resources/application.yml b/stwzhj-modules/wzhj-extract/src/main/resources/application.yml new file mode 100644 index 00000000..ce52ecf9 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/resources/application.yml @@ -0,0 +1,34 @@ +# Tomcat +server: + port: 9216 + +# Spring +spring: + application: + # 应用名称 + name: wzhj-extract + profiles: + # 环境配置 + active: @profiles.active@ + +--- # nacos 配置 +spring: + cloud: + nacos: + # nacos 服务地址 + server-addr: @nacos.server@ + username: @nacos.username@ + password: @nacos.password@ + discovery: + # 注册组 + group: @nacos.discovery.group@ + namespace: ${spring.profiles.active} + config: + # 配置组 + group: @nacos.config.group@ + namespace: ${spring.profiles.active} + config: + import: + - optional:nacos:application-common.yml + - optional:nacos:datasource.yml + - optional:nacos:${spring.application.name}.yml diff --git a/stwzhj-modules/wzhj-extract/src/main/resources/banner.txt b/stwzhj-modules/wzhj-extract/src/main/resources/banner.txt new file mode 100644 index 00000000..fbd45f53 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ + (_) | | + _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___ +| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ +| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | | +|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_| + __/ | __/ | + |___/ |___/ \ No newline at end of file diff --git a/stwzhj-modules/wzhj-extract/src/main/resources/logback-plus.xml b/stwzhj-modules/wzhj-extract/src/main/resources/logback-plus.xml new file mode 100644 index 00000000..caaa3455 --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/resources/logback-plus.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + + + + + + + + + + diff --git a/stwzhj-modules/wzhj-extract/src/main/resources/mapper/DeviceGpsMapper.xml b/stwzhj-modules/wzhj-extract/src/main/resources/mapper/DeviceGpsMapper.xml new file mode 100644 index 00000000..ac1a372c --- /dev/null +++ b/stwzhj-modules/wzhj-extract/src/main/resources/mapper/DeviceGpsMapper.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stwzhj-modules/wzhj-udp/pom.xml b/stwzhj-modules/wzhj-udp/pom.xml new file mode 100644 index 00000000..25d8699f --- /dev/null +++ b/stwzhj-modules/wzhj-udp/pom.xml @@ -0,0 +1,138 @@ + + + + org.dromara + stwzhj-modules + ${revision} + + 4.0.0 + + wzhj-udp + + + wzhj-udp UDP数据接收服务 + + + + + + org.dromara + stwzhj-common-nacos + + + + org.dromara + stwzhj-common-sentinel + + + + + org.dromara + stwzhj-common-log + + + + org.dromara + stwzhj-common-dict + + + + org.dromara + stwzhj-common-doc + + + + org.dromara + stwzhj-common-web + + + + org.dromara + stwzhj-common-mybatis + + + + org.dromara + stwzhj-common-dubbo + + + + org.dromara + stwzhj-common-seata + + + + org.dromara + stwzhj-common-idempotent + + + + org.dromara + stwzhj-common-tenant + + + + org.dromara + stwzhj-common-security + + + + org.dromara + stwzhj-common-translation + + + + org.dromara + stwzhj-common-sensitive + + + + org.dromara + stwzhj-common-encrypt + + + + org.dromara + stwzhj-common-redis + + + + + org.dromara + stwzhj-api-system + + + + org.dromara + stwzhj-api-resource + + + + org.dromara + stwzhj-api-data2es + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/WzhjUdpReceiverTlApplication.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/WzhjUdpReceiverTlApplication.java new file mode 100644 index 00000000..02752e1d --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/WzhjUdpReceiverTlApplication.java @@ -0,0 +1,24 @@ +package org.dromara.udp; + + +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableScheduling +public class WzhjUdpReceiverTlApplication { + + public static void main(String[] args) { + SpringApplication.run(WzhjUdpReceiverTlApplication.class, args); + } + +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncConfiguration.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncConfiguration.java new file mode 100644 index 00000000..d359333d --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncConfiguration.java @@ -0,0 +1,42 @@ +package org.dromara.udp.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +@Configuration +@EnableAsync +public class AsyncConfiguration { + + /*@Bean("taskExecutor") + public Executor taskExecutor(){ + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(8); + taskExecutor.setMaxPoolSize(20); + taskExecutor.setQueueCapacity(Integer.MAX_VALUE); + taskExecutor.setKeepAliveSeconds(60); + taskExecutor.setThreadNamePrefix("zfjly--"); + taskExecutor.setWaitForTasksToCompleteOnShutdown(true); + taskExecutor.setAwaitTerminationSeconds(60); + taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); + return taskExecutor; + }*/ + + @Bean("taskExecutor") + public ThreadPoolTaskExecutor taskExecutor(){ + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(4); + taskExecutor.setMaxPoolSize(10); + taskExecutor.setQueueCapacity(20); + taskExecutor.setKeepAliveSeconds(60); + taskExecutor.setThreadNamePrefix("zfjly--"); + taskExecutor.setWaitForTasksToCompleteOnShutdown(true); + taskExecutor.setAwaitTerminationSeconds(60); + taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); + return taskExecutor; + } + +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncUtils.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncUtils.java new file mode 100644 index 00000000..d0fd2368 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/AsyncUtils.java @@ -0,0 +1,252 @@ +package org.dromara.udp.config; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.time.DateUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.common.core.domain.R; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.udp.exception.MyBusinessException; +import org.dromara.udp.utils.BitConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.stereotype.Component; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Date; + +/** + *

description:

+ * + * @author chenle + * @date 2021-07-13 8:45 + */ +@EnableAsync +@Component +public class AsyncUtils { + + private Logger logger = LoggerFactory.getLogger(AsyncUtils.class); + + @DubboReference + RemoteDataToEsService dataEsService; + + + /** + * 保存data + * @param bytes + * @throws ParseException + */ + @Async(value = "taskExecutor") + public void saveData(byte[] bytes) throws Exception { + //logger.info("当前线程名={}",Thread.currentThread().getName()); + RemoteGpsInfo esGpsInfo = parseBytes(bytes); + esGpsInfo.setDeviceType("3"); + //和redis过期监听时间一定要一致 + if (DateUtil.between(new Date(),esGpsInfo.getGpsTime(),DateUnit.MINUTE)> 10){ + esGpsInfo.setOnline(0); + }else { + esGpsInfo.setOnline(1); + } + logger.error(esGpsInfo.toString()); + R response = dataEsService.saveData(esGpsInfo); + //logger.error("位置信息接口={},失败信息={},失败设备={}",response.getCode(),response.getMessage(),esGpsInfo.getDeviceId()); + + } + + /** + * AA--10101010 10101010 2^15+2^13+2^11+2^9 + 170= + * @param bytes 待解析的字节数组 + */ + private RemoteGpsInfo parseBytes(byte[] bytes) throws ParseException { + + checkHeaderByte(bytes); + + byte[] copyByte = Arrays.copyOfRange(bytes, 10, 4+256); + byte[] gpsIdBytes = Arrays.copyOf(copyByte, 20); + //String gpsId = singleByteToString(gpsIdBytes); + String gpsId = String.copyValueOf(getChars(gpsIdBytes)).trim(); + int le =gpsId.length(); + if(StringUtils.isEmpty(gpsId)){ + throw new MyBusinessException("gpsId 不符合规范,gpsId为:"+gpsId); + } + logger.error("gpsid:"+gpsId); + byte[] lonBytes = Arrays.copyOfRange(copyByte, 20, 28); + long lon = BitConverter.byteArrayToLong(lonBytes,true); + double lonD = Double.longBitsToDouble(lon); + logger.error("lon:"+lonD); + //lat + byte[] latBytes = Arrays.copyOfRange(copyByte, 28, 36); + long lat = BitConverter.byteArrayToLong(latBytes,true); + double latD = Double.longBitsToDouble(lat); + logger.error("lat:"+latD); + + long speed = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 36,38),true); + logger.error("speed:"+speed); + + long angle = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 38, 40), true); + long height = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 40, 42), true); + long jingdu = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 42, 44), true); + logger.error("angle:"+angle); + logger.error("height:"+height); + logger.error("jingdu:"+jingdu); + + long year = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 44, 46), false); + //月日时分秒 + byte[] sfm = Arrays.copyOfRange(copyByte, 46, 51); + String time = singleByteToString2(sfm); + logger.error("time:"+year+time); + + return BuilderEsGpsInfo(gpsId, lonD, latD, speed, angle, height, jingdu, (year + time)); + + + } + + /** + * 构建EsgpsInfo对象 + * @param gpsId 000340100000000001000001 + * @param lonD 经度 + * @param latD 纬度 + * @param speed 速度 + * @param angle 方向 + * @param height 高度 + * @param jingdu 经度 + * @param time 20210616123208 + */ + private RemoteGpsInfo BuilderEsGpsInfo(String gpsId, double lonD, double latD, long speed, + long angle, long height, long jingdu, String time) throws ParseException { + RemoteGpsInfo gpsInfo = new RemoteGpsInfo(); + gpsInfo.setDeviceCode(parseGpsId(gpsId)); + gpsInfo.setDeviceType(parseDeviceType(gpsId)); + gpsInfo.setLat(String.valueOf(latD)); + gpsInfo.setLng(String.valueOf(lonD)); + gpsInfo.setOrientation(String.valueOf(angle)); + gpsInfo.setHeight(String.valueOf(height)); + gpsInfo.setDeltaH(String.valueOf(jingdu)); + gpsInfo.setSpeed(String.valueOf(speed)); + gpsInfo.setGpsTime(parseGpsTime(time)); + + return gpsInfo; + } + + private Date parseGpsTime(String time) throws ParseException { + if(StringUtils.isEmpty(time)){ + throw new MyBusinessException("时间为空"); + } + Date date = DateUtils.parseDate(time, new String[]{"yyyy-MM-dd HH:mm:ss", "yyyyMMddHHmmss"}); + return date; + + } + + /** + * 解析出城市前缀3401 + * @param gpsId 000340100000000001000001 + * @return cityCode + */ + private String parseCityCode(String gpsId) { + checkGpsId(gpsId); + return gpsId.substring(3,7); + } + + /** + * 解析出设备类型 + * @param gpsId + * @return + */ + private String parseDeviceType(String gpsId) { + checkGpsId(gpsId); + return gpsId; + } + + /** + * 返回deviceSn,和parseGpsId一样的值 + * @param gpsId 000340100000000001000001 + * @return deviceSn + */ + private String parseDeviceSn(String gpsId) { + return parseGpsId(gpsId); + } + + /** + * 解析gpsId 去除前面的 000 + * @param gpsId 000340100000000001000001 + * @return gpsId + */ + private String parseGpsId(String gpsId) { + checkGpsId(gpsId); + return gpsId; + } + + private void checkGpsId(String gpsId) { + if(gpsId.length() != 8){ + throw new MyBusinessException("gpsId为空"); + } + } + + private void checkHeaderByte(byte[] bytes) { + byte first = bytes[0]; + byte second = bytes[2]; + //校验标准头 + int aa = 0xAA; + int cc = 0xCC; + int ff = 0xff; + if((first & ff) != aa){ + throw new MyBusinessException("头文件校验错误,你的字节数组第一位为:"+Integer.toHexString(first & ff)+",应该为:AA"); + } + if((second & ff) != cc){ + throw new MyBusinessException("头文件校验错误,你的字节数组第三位为:"+Integer.toHexString(cc & ff)+",应该为:CC"); + } + } + + /** + * + * @param ss 要转换前的byte数组 + * @return 拼接后的字符串 小于0的在前面补0 + */ + private String singleByteToString(byte[] ss) { + + StringBuilder ret = new StringBuilder(); + + for (byte b : ss) { + String v = (int) b +""; + if (v.length() < 2) { + v = v + "0"; + } + ret.append(v); + } + return ret.toString(); + } + + private String singleByteToString2(byte[] ss) { + + StringBuilder ret = new StringBuilder(); + + for (byte b : ss) { + String v = (int) b +""; + if (v.length() < 2) { + v = "0" + v ; + } + ret.append(v); + } + return ret.toString(); + } + + private char[] getChars (byte[] bytes) { + Charset cs = Charset.forName ("UTF-8"); + ByteBuffer bb = ByteBuffer.allocate (bytes.length); + bb.put (bytes); + bb.flip (); + CharBuffer cb = cs.decode (bb); + + return cb.array(); + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/UrlInterceptor.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/UrlInterceptor.java new file mode 100644 index 00000000..fb74b71a --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/UrlInterceptor.java @@ -0,0 +1,64 @@ +package org.dromara.udp.config; + +import com.alibaba.fastjson.JSON; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.domain.R; +import org.dromara.udp.utils.IPUtils; +import org.springframework.http.MediaType; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.HandlerInterceptor; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.Objects; + +/** + *

description:

+ * + * @author chenle + * @date 2021-12-30 9:53 + */ +public class UrlInterceptor implements HandlerInterceptor { + + private List whiteUrls; + + public UrlInterceptor(String whiteUrl) { + String[] urlArray = whiteUrl.split(","); + whiteUrls = CollectionUtils.arrayToList(urlArray); + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + //过滤ip,若用户在白名单内,则放行 + String ipAddress= IPUtils.getRealIP(request); + + if(StringUtils.isEmpty(ipAddress)){ + return false; + } + + if(!whiteUrls.contains(ipAddress)){ + R error = R.fail("ip not allowed"); + handleResponse(error,response); + return false; + } + return true; + } + + private void handleResponse(R r, HttpServletResponse response) { + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + PrintWriter printWriter = null; + try { + printWriter = response.getWriter(); + printWriter.write(JSON.toJSONString(r)); + } catch (IOException e) { + e.printStackTrace(); + }finally{ + if(!Objects.isNull(printWriter)){ + printWriter.close(); + } + } + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/WebConfiguration.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/WebConfiguration.java new file mode 100644 index 00000000..5954331d --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/config/WebConfiguration.java @@ -0,0 +1,23 @@ +package org.dromara.udp.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + *

description:

+ * + * @author chenle + * @date 2021-12-30 10:03 + */ +//@Configuration +public class WebConfiguration implements WebMvcConfigurer { + + @Value("${ruansi.whiteUrl}") + private String whiteUrl; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new UrlInterceptor(whiteUrl)); + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/controller/OriginalUdpReceiver.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/controller/OriginalUdpReceiver.java new file mode 100644 index 00000000..f702b648 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/controller/OriginalUdpReceiver.java @@ -0,0 +1,330 @@ +package org.dromara.udp.controller; + +/** + *

description:

+ * + * @author chenle + * @date 2021-12-17 10:54 + */ + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import org.apache.commons.lang.time.DateUtils; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.udp.config.AsyncUtils; +import org.dromara.udp.exception.MyBusinessException; +import org.dromara.udp.utils.BitConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketException; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Date; +import java.util.concurrent.Executors; + +/** + *

description:

+ * + * @author chenle + * @date 2021-07-12 9:30 + */ +@Component +public class OriginalUdpReceiver implements ApplicationListener { + + private Logger logger = LoggerFactory.getLogger(OriginalUdpReceiver.class); + + private static final char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + @Resource + private ThreadPoolTaskExecutor taskExecutor; + + @Autowired + private AsyncUtils asyncUtils; + + + /*private static OriginalUdpReceiver originalUdpReceiver; + + + @PostConstruct + public void init() { + originalUdpReceiver = this; + }*/ + + private static final int MAX_UDP_DATA_SIZE = 64*1024; + + /*@Override + public void run(String... args) throws Exception { + //System.out.println( Arrays.toString(args)); + //new Thread(new UDPProcess("192.168.10.14",9909)).start(); + //原生方式启动 + System.out.println("原生方式启动"); + Executors.newSingleThreadExecutor().execute(new UDPProcess("10.20.80.8",Integer.parseInt("10013"))); +// Executors.newSingleThreadExecutor().execute(new UDPProcess("53.1.237.83",8082)); + + }*/ + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + logger.info("原生方式启动"); + try { +// Executors.newSingleThreadExecutor().execute(new UDPProcess("53.238.79.4",Integer.parseInt("10013"))); + Executors.newSingleThreadExecutor().execute(new UDPProcess("localhost",Integer.parseInt("10013"))); + } catch (SocketException e) { + e.printStackTrace(); + } + } + + + class UDPProcess implements Runnable { + DatagramSocket socket = null; + + UDPProcess(String ip, final int port) throws SocketException { + + socket = new DatagramSocket(new InetSocketAddress(ip,port)); + } + + @Override + public void run() { + + while (true) { + byte[] buffer = new byte[MAX_UDP_DATA_SIZE]; + DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + try { + socket.receive(packet); + byte[] data = packet.getData(); + + String unSendData = new String(buffer,0,data.length); + //String sendData = bytes2hexStr(data); + logger.error("接收到了数据:"+data); + asyncUtils.saveData(data); + /*taskExecutor.execute(() -> { + try { + saveData(data); + } catch (ParseException e) { + e.printStackTrace(); + } + });*/ + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void saveData(byte[] bytes) throws ParseException { + //logger.info("当前线程名={}",Thread.currentThread().getName()); + RemoteGpsInfo esGpsInfo = parseBytes(bytes); + if (DateUtil.between(new Date(),esGpsInfo.getGpsTime(),DateUnit.MINUTE)> 10){ + esGpsInfo.setOnline(0); + }else { + esGpsInfo.setOnline(1); + } + //ApiResponse response = dataEsService.saveGps(esGpsInfo); + } + + } + + + public static String bytes2hex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + String tmp; + sb.append("["); + for (byte b : bytes) { + // 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制 + tmp = Integer.toHexString(0xFF & b); + if (tmp.length() == 1) { + tmp = "0" + tmp;//只有一位的前面补个0 + } + sb.append(tmp).append(" ");//每个字节用空格断开 + } + sb.delete(sb.length() - 1, sb.length());//删除最后一个字节后面对于的空格 + sb.append("]"); + return sb.toString(); + } + + /** + * AA--10101010 10101010 2^15+2^13+2^11+2^9 + 170= + * @param bytes 待解析的字节数组 + */ + private RemoteGpsInfo parseBytes(byte[] bytes) throws ParseException { + + checkHeaderByte(bytes); + + byte[] copyByte = Arrays.copyOfRange(bytes, 10, 4+256); + byte[] gpsIdBytes = Arrays.copyOf(copyByte, 10); + String gpsId = singleByteToString(gpsIdBytes); + if(org.apache.commons.lang.StringUtils.isEmpty(gpsId) || gpsId.length() != 20){ + throw new MyBusinessException("gpsId 不符合规范,gpsId为:"+gpsId); + } + logger.error(gpsId); + byte[] lonBytes = Arrays.copyOfRange(copyByte, 10, 18); + long lon = BitConverter.byteArrayToLong(lonBytes,true); + double lonD = Double.longBitsToDouble(lon); + logger.error("lon:"+lonD); + //lat + byte[] latBytes = Arrays.copyOfRange(copyByte, 18, 26); + long lat = BitConverter.byteArrayToLong(latBytes,true); + double latD = Double.longBitsToDouble(lat); + logger.error("lat:"+latD); + + long speed = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 26,28),true); + logger.error("speed:"+speed); + + long angle = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 28, 30), true); + long height = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 30, 32), true); + long jingdu = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 32, 34), true); + logger.error("angle:"+angle); + logger.error("height:"+height); + logger.error("jingdu:"+jingdu); + + long year = BitConverter.byteArrayToShort(Arrays.copyOfRange(copyByte, 34, 36), true); + //月日时分秒 + byte[] sfm = Arrays.copyOfRange(copyByte, 36, 41); + String time = singleByteToString(sfm); + logger.error("time:"+year+time); + + return BuilderEsGpsInfo(gpsId, lonD, latD, speed, angle, height, jingdu, (year + time)); + + + } + + /** + * 构建EsgpsInfo对象 + * @param gpsId 000340100000000001000001 + * @param lonD 经度 + * @param latD 纬度 + * @param speed 速度 + * @param angle 方向 + * @param height 高度 + * @param jingdu 经度 + * @param time 20210616123208 + */ + private RemoteGpsInfo BuilderEsGpsInfo(String gpsId, double lonD, double latD, long speed, + long angle, long height, long jingdu, String time) throws ParseException { + RemoteGpsInfo gpsInfo = new RemoteGpsInfo(); + gpsInfo.setDeviceCode(parseGpsId(gpsId)); + gpsInfo.setDeviceType(parseDeviceType(gpsId)); + gpsInfo.setLat(String.valueOf(latD)); + gpsInfo.setLng(String.valueOf(lonD)); + gpsInfo.setOrientation(String.valueOf(angle)); + gpsInfo.setHeight(String.valueOf(height)); + gpsInfo.setDeltaH(String.valueOf(jingdu)); + gpsInfo.setSpeed(String.valueOf(speed)); + gpsInfo.setGpsTime(parseGpsTime(time)); + + return gpsInfo; + } + + private Date parseGpsTime(String time) throws ParseException { + if(org.apache.commons.lang.StringUtils.isEmpty(time)){ + throw new MyBusinessException("时间为空"); + } + Date date = DateUtils.parseDate(time, new String[]{"yyyy-MM-dd HH:mm:ss", "yyyyMMddHHmmss"}); + return date; + + } + + /** + * 解析出城市前缀3401 + * @param gpsId 000340100000000001000001 + * @return cityCode + */ + private String parseCityCode(String gpsId) { + checkGpsId(gpsId); + return gpsId.substring(3,7); + } + + /** + * 解析出设备类型 + * @param gpsId + * @return + */ + private String parseDeviceType(String gpsId) { + checkGpsId(gpsId); + return gpsId.substring(17,18); + } + + /** + * 返回deviceSn,和parseGpsId一样的值 + * @param gpsId 000340100000000001000001 + * @return deviceSn + */ + private String parseDeviceSn(String gpsId) { + return parseGpsId(gpsId); + } + + /** + * 解析gpsId 去除前面的 000 + * @param gpsId 000340100000000001000001 + * @return gpsId + */ + private String parseGpsId(String gpsId) { + checkGpsId(gpsId); + return gpsId.substring(3); + } + + private void checkGpsId(String gpsId) { + if(gpsId.length() != 20){ + throw new MyBusinessException("gpsId为空"); + } + } + + private void checkHeaderByte(byte[] bytes) { + byte first = bytes[0]; + byte second = bytes[2]; + //校验标准头 + int aa = 0xAA; + int cc = 0xCC; + int ff = 0xff; + if((first & ff) != aa){ + throw new MyBusinessException("头文件校验错误,你的字节数组第一位为:"+Integer.toHexString(first & ff)+",应该为:AA"); + } + if((second & ff) != cc){ + throw new MyBusinessException("头文件校验错误,你的字节数组第三位为:"+Integer.toHexString(cc & ff)+",应该为:CC"); + } + } + + /** + * + * @param ss 要转换前的byte数组 + * @return 拼接后的字符串 小于0的在前面补0 + */ + private String singleByteToString(byte[] ss) { + + StringBuilder ret = new StringBuilder(); + + for (byte b : ss) { + String v = (int) b +""; + if (v.length() < 2) { + v = v + "0"; + } + ret.append(v); + } + return ret.toString(); + } + + + public static String bytes2hexStr(byte[] bytes) { + int len = bytes.length; + if (len==0) { + return null; + } + char[] cbuf = new char[len*2]; + for (int i=0; i>> 4) & 0xf]; + cbuf[x+1] = HEX_CHARS[bytes[i] & 0xf]; + } + return new String(cbuf); + } + +} + diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/domain/Gps.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/domain/Gps.java new file mode 100644 index 00000000..88dd6ba4 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/domain/Gps.java @@ -0,0 +1,33 @@ +package org.dromara.udp.domain; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-11 11:58 + */ +public class Gps { + + private double wgLat; + private double wgLon; + public Gps(double wgLat, double wgLon) { + setWgLat(wgLat); + setWgLon(wgLon); + } + public double getWgLat() { + return wgLat; + } + public void setWgLat(double wgLat) { + this.wgLat = wgLat; + } + public double getWgLon() { + return wgLon; + } + public void setWgLon(double wgLon) { + this.wgLon = wgLon; + } + @Override + public String toString() { + return wgLat + "," + wgLon; + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/exception/MyBusinessException.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/exception/MyBusinessException.java new file mode 100644 index 00000000..2d40c6f5 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/exception/MyBusinessException.java @@ -0,0 +1,54 @@ +package org.dromara.udp.exception; + +/** + *

description:

+ * + * @author chenle + * @date 2021-06-07 10:56 + */ +public class MyBusinessException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public MyBusinessException(String msg) { + super(msg); + this.msg = msg; + } + + public MyBusinessException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public MyBusinessException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public MyBusinessException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/BitConverter.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/BitConverter.java new file mode 100644 index 00000000..9d8dcff8 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/BitConverter.java @@ -0,0 +1,247 @@ +package org.dromara.udp.utils; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + *

description:

+ * + * @author chenle + * @date 2021-01-13 18:44 + */ +public class BitConverter { + + public static short ToInt16(byte[] bytes, int offset) { + short result = (short) ((int)bytes[offset]&0xff); + result |= ((int)bytes[offset+1]&0xff) << 8; + return (short) (result & 0xffff); + } + public static int ToUInt16(byte[] bytes, int offset) { + int result = (int)bytes[offset+1]&0xff; + result |= ((int)bytes[offset]&0xff) << 8; + return result & 0xffff; + } + + /** + * 大端模式 + * @param bytes + * @param offset + * @return + */ + public static int ToInt32(byte[] bytes, int offset) { + int result = (int)bytes[offset]&0xff; + result |= ((int)bytes[offset+1]&0xff) << 8; + result |= ((int)bytes[offset+2]&0xff) << 16; + result |= ((int)bytes[offset+3]&0xff) << 24; + return result; + } + + /** + * 小端模式 + * @param bytes + * @param offset + * @return + */ + public static int ToInt32Reverse(byte[] bytes, int offset) { + int result = ((int)bytes[offset]&0xff) << 24; + result |= ((int)bytes[offset+1]&0xff) << 16; + result |= ((int)bytes[offset+2]&0xff) << 8; + result |= ((int)bytes[offset+3]&0xff) ; + return result; + } + + public static long ToUInt32(byte[] bytes, int offset) { + long result = (int)bytes[offset]&0xff; + result |= ((int)bytes[offset+1]&0xff) << 8; + result |= ((int)bytes[offset+2]&0xff) << 16; + result |= ((int)bytes[offset+3]&0xff) << 24; + return result & 0xFFFFFFFFL; + } + public static long ToInt64(byte[] buffer,int offset) { + long values = 0; + for (int i = 0; i < 8; i++) { + values <<= 8; values |= (buffer[offset+i] & 0xFF); + } + return values; + } + + public static long ToInt64Reverse(byte[] bytes, int offset) { + long result = 0; + for (int i = 0; i <= 56; i += 8) { + result |= ((int)bytes[offset++]&0xff) << 56 - i; + } + return result; + } + + + + public static long ToUInt64(byte[] bytes, int offset) { + long result = 0; + for (int i = 0; i <= 56; i += 8) { + result |= ((int)bytes[offset++]&0xff) << i; + } + return result; + } + + + + public static float ToFloat(byte[] bs, int index) { + return Float.intBitsToFloat(ToInt32(bs, index)); + } + public static double ToDouble(byte[] arr,int offset) { + return Double.longBitsToDouble(ToUInt64(arr, offset)); + } + public static boolean ToBoolean(byte[] bytes,int offset) { + return (bytes[offset]==0x00)? false:true; + } + + public static byte[] GetBytes(short value) { + byte[] bytes = new byte[2]; + bytes[0] = (byte) (value & 0xff); + bytes[1] = (byte) ((value & 0xff00) >> 8); + return bytes; + } + public static byte[] GetBytes(int value) { + byte[] bytes = new byte[4]; + bytes[0] = (byte) ((value)&0xFF); //最低位 + bytes[1] = (byte) ((value >> 8)&0xFF); + bytes[2] = (byte) ((value >> 16)&0xFF); + bytes[3] = (byte) ((value >>> 24)); //最高位,无符号右移 + return bytes; + } + public static byte[] GetBytes(long values) { + byte[] buffer = new byte[8]; + for (int i = 0; i < 8; i++) { + int offset = 64 - (i + 1) * 8; + buffer[i] = (byte)((values >> offset) & 0xff); + } + return buffer; + } + public static byte[] GetBytes(float value) { + return GetBytes(Float.floatToIntBits(value)); + } + public static byte[] GetBytes(double val) { + long value = Double.doubleToLongBits(val); + return GetBytes(value); + } + public static byte[] GetBytes(boolean value) { + return new byte[]{(byte)(value? 1:0)}; + } + + public static byte IntToByte(int x) { + return (byte) x; + } + public static int ByteToInt(byte b) { + return b & 0xFF; + } + public static char ToChar(byte[] bs,int offset) { + return (char) (((bs[offset] & 0xFF) << 8) | (bs[offset+1] & 0xFF)); + } + public static byte[] GetBytes(char value) { + byte[] b = new byte[2]; + b[0] = (byte) ((value & 0xFF00) >> 8); + b[1] = (byte) (value & 0xFF); + return b; + } + + public static byte[] Concat(byte[]... bs) { + int len = 0,idx=0; + for(byte[] b:bs)len+=b.length; + byte[] buffer = new byte[len]; + for(byte[] b:bs) { + System.arraycopy(b,0, buffer, idx, b.length); + idx+=b.length; + } + return buffer; + } + public static void main(String[] args) { + long a = 123456; + byte[] b1=GetBytes(a); + long b= ToInt64(b1, 0); + System.out.println(b); + } + + public static byte[] flipEndian(byte[] data) { + if (data == null) { + return new byte[0]; + } + byte[] newData = new byte[data.length]; + for (int i = 0; i < data.length; i++) { + newData[data.length - i - 1] = data[i]; + } + + return newData; + } + + public static long byteArrayToLong(byte[] bytes,boolean isLittle) { + ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.put(bytes, 0, bytes.length); + buffer.flip(); + if(isLittle){ + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + return buffer.getLong(); + } + + public static long byteArrayToShort(byte[] bytes,boolean isLittle) { + ByteBuffer buffer = ByteBuffer.allocate(2); + buffer.put(bytes, 0, bytes.length); + buffer.flip(); + if(isLittle){ + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + return buffer.getShort(); + } + + public static long byteArrayToInt(byte[] bytes,boolean isLittle) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.put(bytes, 0, bytes.length); + buffer.flip(); + if(isLittle){ + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + return buffer.getInt(); + } + + + /** + * 将字节数组转为long
+ * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 + * @param input + * @param offset 起始偏移量 + * @param littleEndian 输入数组是否小端模式 + * @return + */ + public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian) { + long value = 0; + // 循环读取每个字节通过移位运算完成long的8个字节拼装 + for (int count = 0; count < 8; ++count) { + int shift = (littleEndian ? count : (7 - count)) << 3; + value |= ((long) 0xff << shift) & ((long) input[offset + count] << shift); + } + return value; + } + + /** +    * 字节数组到double的转换. +    */ + public static double getDouble(byte[] b) { + long m; + m = b[0]; + m &= 0xff; + m |= ((long) b[1] << 8); + m &= 0xffff; + m |= ((long) b[2] << 16); + m &= 0xffffff; + m |= ((long) b[3] << 24); + m &= 0xffffffffl; + m |= ((long) b[4] << 32); + m &= 0xffffffffffl; + m |= ((long) b[5] << 40); + m &= 0xffffffffffffl; + m |= ((long) b[6] << 48); + m &= 0xffffffffffffffl; + m |= ((long) b[7] << 56); + return Double.longBitsToDouble(m); +} +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/ConvertTool.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/ConvertTool.java new file mode 100644 index 00000000..be8780b3 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/ConvertTool.java @@ -0,0 +1,62 @@ +package org.dromara.udp.utils; + + +import org.dromara.udp.domain.Gps; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-14 14:43 + */ +public class ConvertTool { + public static final String BAIDU_LBS_TYPE = "bd09ll"; + public static double pi = 3.1415926535897932384626; + public static double a = 6378245.0; + public static double ee = 0.00669342162296594323; + /** + * * 火星坐标系 (GCJ-02) to 84 + * * @param lon * @param lat * @return + */ + public static Gps gcj_To_Gps84(double lat, double lon) { + Gps gps = transform(lat, lon); + double lontitude = lon * 2 - gps.getWgLon(); + double latitude = lat * 2 - gps.getWgLat(); + return new Gps(latitude, lontitude); + } + public static Gps transform(double lat, double lon) { + + double dLat = transformLat(lon - 105.0, lat - 35.0); + double dLon = transformLon(lon - 105.0, lat - 35.0); + double radLat = lat / 180.0 * pi; + double magic = Math.sin(radLat); + magic = 1 - ee * magic * magic; + double sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); + dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLat, mgLon); + } + + public static double transformLat(double x, double y) { + double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + + 0.2 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; + return ret; + } + + + public static double transformLon(double x, double y) { + double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 + * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 + * pi)) * 2.0 / 3.0; + return ret; + } + +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/IPUtils.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/IPUtils.java new file mode 100644 index 00000000..96849995 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/IPUtils.java @@ -0,0 +1,54 @@ +package org.dromara.udp.utils; + +import jakarta.servlet.http.HttpServletRequest; + +/** + *

description:

+ * + * @author chenle + * @date 2021-12-30 9:54 + */ + + +public class IPUtils { + /** + * 获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址, + * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值 + * + * @return ip + */ + public static String getRealIP(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { + // 多次反向代理后会有多个ip值,第一个ip才是真实ip + if( ip.indexOf(",")!=-1 ){ + ip = ip.split(",")[0]; + } + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + System.out.println("Proxy-Client-IP ip: " + ip); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + System.out.println("WL-Proxy-Client-IP ip: " + ip); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + System.out.println("HTTP_CLIENT_IP ip: " + ip); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + System.out.println("X-Real-IP ip: " + ip); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + System.out.println("getRemoteAddr ip: " + ip); + } + return ip; + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/LocationConvert.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/LocationConvert.java new file mode 100644 index 00000000..c0017606 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/LocationConvert.java @@ -0,0 +1,126 @@ +package org.dromara.udp.utils; + + +import org.dromara.udp.domain.Gps; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-11 11:58 + */ +public class LocationConvert { + + public static double pi = 3.1415926535897932384626 * 3000.0 / 180.0; //此处注意 pi = 派 * 3000 / 180 ; + public static double a = 6378245.0; + public static double ee = 0.00669342162296594323; + /** + * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return + * 谷歌转地球 + * */ + public static Gps gcj_To_Gps84(double lat, double lon) { + Gps gps = transform(lat, lon); + double lontitude = lon * 2 - gps.getWgLon(); + double latitude = lat * 2 - gps.getWgLat(); + return new Gps(latitude, lontitude); + } + + public static Gps GPS84ToGCJ02(double lon, double lat) { + double dLat = transformLat(lon - 105.0, lat - 35.0); + double dLon = transformLon(lon - 105.0, lat - 35.0); + double radLat = lat / 180.0 * pi; + double magic = Math.sin(radLat); + magic = 1 - ee * magic * magic; + double sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); + dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLon, mgLat); + } + + public static Gps transform(double lat, double lon) { + + double dLat = transformLat(lon - 105.0, lat - 35.0); + double dLon = transformLon(lon - 105.0, lat - 35.0); + double radLat = lat / 180.0 * pi; + double magic = Math.sin(radLat); + magic = 1 - ee * magic * magic; + double sqrtMagic = Math.sqrt(magic); + dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi); + dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); + double mgLat = lat + dLat; + double mgLon = lon + dLon; + return new Gps(mgLat, mgLon); + } + + /** + * (BD-09)-->84 + * 百度转地球 + * @param bd_lat + * @param bd_lon + * @return + */ + public static Gps bd09_To_Gps84(double bd_lat, double bd_lon) { + + Gps gcj02 = bd09_To_Gcj02(bd_lat, bd_lon); + Gps map84 = gcj_To_Gps84(gcj02.getWgLat(), + gcj02.getWgLon()); + return map84; + + } + + /** + * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param + * 百度转谷歌 + */ + public static Gps bd09_To_Gcj02(double bd_lat, double bd_lon) { + double x = bd_lon - 0.0065, y = bd_lat - 0.006; + double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi); + double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi); + double gg_lon = z * Math.cos(theta); + double gg_lat = z * Math.sin(theta); + return new Gps(gg_lat, gg_lon); + } + + public static double transformLat(double x, double y) { + double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + + 0.2 * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; + ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; + return ret; + } + + public static double transformLon(double x, double y) { + double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 + * Math.sqrt(Math.abs(x)); + ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; + ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; + ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 + * pi)) * 2.0 / 3.0; + return ret; + } + + public static void main(String[] args) { + HashMap dto = new HashMap<>(2); + String latitude = dto.put("Latitude", "31.739913"); + String longtide = dto.put("Longtide", "116.475212"); + //Gps gps = gcj_To_Gps84(Double.valueOf("31.739913"), Double.valueOf("116.475212")); +// Gps gps = gcj_To_Gps84(Double.valueOf("31.736539"), Double.valueOf("116.476364")); + //Longtide,value=116.47661293112877;Latitude,value=31.736592029405035 + Gps gps = ConvertTool.gcj_To_Gps84(Double.valueOf("31.736539"), Double.valueOf("116.476364")); + latitude = String.valueOf(gps.getWgLat()); + longtide = String.valueOf(gps.getWgLon()); + dto.put("Latitude",latitude); + dto.put("Longtide",longtide); + Set> entries = dto.entrySet(); + for (Map.Entry entry : entries) { + System.out.println("key="+entry.getKey()+",value="+entry.getValue());; + } + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/Util.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/Util.java new file mode 100644 index 00000000..43f2b810 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/Util.java @@ -0,0 +1,57 @@ +package org.dromara.udp.utils; + +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + *

description:

+ * + * @author chenle + * @date 2021-01-13 18:00 + */ +public class Util { + // double转换为byte[8]数组 + public static byte[] getByteArray(double d) { + long longbits = Double.doubleToLongBits(d); + return getByteArray(longbits); + } + + /** + * 时间转double + * @param date 时间基准 1899年12月30日 --- 1970年1月1日 + * @return 返回值类似:43322.3770190278 + */ + public static double date2Double(Date date){ + + long localOffset = date.getTimezoneOffset()*60000; + double dd = (double)(date.getTime()-localOffset)/ 24 / 3600 / 1000 + 25569.0000000; + DecimalFormat df = new DecimalFormat("#.0000000000");//先默认保留10位小数 + + return Double.valueOf(df.format(dd)); + } + + /** + * double 转 Date 时间 + * @param dVal + */ + public static Date doubleToDate(Double dVal){ + Date oDate = new Date(); + @SuppressWarnings("deprecation") + long localOffset = oDate.getTimezoneOffset() * 60000; //系统时区偏移 1900/1/1 到 1970/1/1 的 25569 天 + oDate.setTime((long) ((dVal - 25569) * 24 * 3600 * 1000 + localOffset)); + + return oDate; + } + + public static Date str2Date(String str) { + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//小写的mm表示的是分钟 + try { + return sdf.parse(str); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/test.java b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/test.java new file mode 100644 index 00000000..c5b8cbfc --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/java/org/dromara/udp/utils/test.java @@ -0,0 +1,61 @@ +package org.dromara.udp.utils; + +import io.micrometer.core.instrument.util.StringUtils; + +public class test { + + + + private static final char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /* + * byte[]数组转十六进制 + */ + public static String bytes2hexStr(byte[] bytes) { + int len = bytes.length; + if (len==0) { + return null; + } + char[] cbuf = new char[len*2]; + for (int i=0; i>> 4) & 0xf]; + cbuf[x+1] = HEX_CHARS[bytes[i] & 0xf]; + } + return new String(cbuf); + } + + + /* + * 十六进制转byte[]数组 + */ + public static byte[] hexStr2bytes(String hexStr) { + //String hexStr = "aaaacccc22000000003335363233303334300000000000000000000000007527c5b45c835d40c1a8a44e40fb3e4000000000ffff000007e609140f1d2e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + //String hexStr = "aaaacccc22000000003335363232303632310000000000000000000000002cf9c5925f745d40a4703d0ad7eb3e4000000000ffff000007e60914100032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + //String hexStr = "aaaacccc22000000003335363232303630390000000000000000000000009d36d06903755d4079c7293a92f33e4000000000ffff000007e609141000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + if(StringUtils.isBlank(hexStr)) { + return null; + } + if(hexStr.length()%2 != 0) {//长度为单数 + hexStr = "0" + hexStr;//前面补0 + } + char[] chars = hexStr.toCharArray(); + int len = chars.length/2; + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) { + int x = i*2; + bytes[i] = (byte)Integer.parseInt(String.valueOf(new char[]{chars[x], chars[x+1]}), 16); + } + return bytes; + } + + /*public static void main(String[] args) throws ParseException { + byte[] bytes = hexStr2bytes(); + AsyncUtils asyncUtils = new AsyncUtils(); + asyncUtils.saveData(bytes); + System.out.println(bytes); + } +*/ + + + } diff --git a/stwzhj-modules/wzhj-udp/src/main/resources/application.yml b/stwzhj-modules/wzhj-udp/src/main/resources/application.yml new file mode 100644 index 00000000..bf0a217f --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/resources/application.yml @@ -0,0 +1,34 @@ +# Tomcat +server: + port: 9217 + +# Spring +spring: + application: + # 应用名称 + name: wzhj-udp + profiles: + # 环境配置 + active: @profiles.active@ + +--- # nacos 配置 +spring: + cloud: + nacos: + # nacos 服务地址 + server-addr: @nacos.server@ + username: @nacos.username@ + password: @nacos.password@ + discovery: + # 注册组 + group: @nacos.discovery.group@ + namespace: ${spring.profiles.active} + config: + # 配置组 + group: @nacos.config.group@ + namespace: ${spring.profiles.active} + config: + import: + - optional:nacos:application-common.yml + - optional:nacos:datasource.yml + - optional:nacos:${spring.application.name}.yml diff --git a/stwzhj-modules/wzhj-udp/src/main/resources/banner.txt b/stwzhj-modules/wzhj-udp/src/main/resources/banner.txt new file mode 100644 index 00000000..fbd45f53 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/resources/banner.txt @@ -0,0 +1,10 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ + (_) | | + _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___ +| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ +| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | | +|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_| + __/ | __/ | + |___/ |___/ \ No newline at end of file diff --git a/stwzhj-modules/wzhj-udp/src/main/resources/logback-plus.xml b/stwzhj-modules/wzhj-udp/src/main/resources/logback-plus.xml new file mode 100644 index 00000000..caaa3455 --- /dev/null +++ b/stwzhj-modules/wzhj-udp/src/main/resources/logback-plus.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + + + + + + + + + + diff --git a/stwzhj-modules/wzhj-webscoket/pom.xml b/stwzhj-modules/wzhj-webscoket/pom.xml new file mode 100644 index 00000000..02d179d2 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/pom.xml @@ -0,0 +1,182 @@ + + + + org.dromara + stwzhj-modules + ${revision} + + 4.0.0 + + wzhj-webscoket + + + wzhj-webscoket记录仪数据接收 + + + + + + org.dromara + stwzhj-common-nacos + + + + org.dromara + stwzhj-common-sentinel + + + + + org.dromara + stwzhj-common-log + + + + org.dromara + stwzhj-common-dict + + + + org.dromara + stwzhj-common-doc + + + + org.dromara + stwzhj-common-web + + + + org.dromara + stwzhj-common-mybatis + + + + org.dromara + stwzhj-common-dubbo + + + + org.dromara + stwzhj-common-seata + + + + org.dromara + stwzhj-common-idempotent + + + + org.dromara + stwzhj-common-tenant + + + + org.dromara + stwzhj-common-security + + + + org.dromara + stwzhj-common-translation + + + + org.dromara + stwzhj-common-sensitive + + + + org.dromara + stwzhj-common-encrypt + + + + org.dromara + stwzhj-common-redis + + + + + org.dromara + stwzhj-api-system + + + + org.dromara + stwzhj-api-resource + + + + org.dromara + stwzhj-api-data2es + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + org.elasticsearch + elasticsearch + 7.14.0 + + + log4j-api + org.apache.logging.log4j + + + + + org.elasticsearch.client + elasticsearch-rest-client + 7.14.0 + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 7.14.0 + + + org.elasticsearch + elasticsearch + + + elasticsearch-rest-client + org.elasticsearch.client + + + + + + + + org.springframework.kafka + spring-kafka + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/ZfjlyWebscoketApplication.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/ZfjlyWebscoketApplication.java new file mode 100644 index 00000000..7e29ffc3 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/ZfjlyWebscoketApplication.java @@ -0,0 +1,22 @@ +package org.dromara.webscoket; + + +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; +import org.springframework.scheduling.annotation.EnableScheduling; + +@EnableDubbo +@EnableScheduling +@SpringBootApplication +public class ZfjlyWebscoketApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(ZfjlyWebscoketApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ 执法记录仪模块启动成功 ლ(´ڡ`ლ)゙ "); + } + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/AsyncConfiguration.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/AsyncConfiguration.java new file mode 100644 index 00000000..bdd86700 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/AsyncConfiguration.java @@ -0,0 +1,29 @@ +package org.dromara.webscoket.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ThreadPoolExecutor; + +@Configuration +@EnableAsync +public class AsyncConfiguration { + + @Bean("myTaskExecutor") + public ThreadPoolTaskExecutor taskExecutor(){ + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(4); + taskExecutor.setMaxPoolSize(10); + taskExecutor.setQueueCapacity(500); + taskExecutor.setKeepAliveSeconds(60); + taskExecutor.setThreadNamePrefix("zfjly--"); + taskExecutor.setWaitForTasksToCompleteOnShutdown(true); + taskExecutor.setAwaitTerminationSeconds(60); + taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); + return taskExecutor; + } + + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/TestController.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/TestController.java new file mode 100644 index 00000000..26277ffb --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/TestController.java @@ -0,0 +1,52 @@ +package org.dromara.webscoket.config; + +import cn.hutool.core.date.DateUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-21 14:31 + */ +//@RestController +@Slf4j +public class TestController { + + @Autowired + private ThreadPoolTaskExecutor myTaskExecutor; + + @DubboReference + private RemoteDataToEsService dataToEsService; + + @RequestMapping("testSend") + public void request(){ + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + esGpsInfo.setDeviceCode("123"); + esGpsInfo.setDeviceType("5");//执法记录仪 + esGpsInfo.setLat(String.valueOf(30.54879)); + esGpsInfo.setLng(String.valueOf(117.1234)); + esGpsInfo.setSpeed(String.valueOf(0.0)); + esGpsInfo.setDeltaH(String.valueOf(21.32)); + esGpsInfo.setOrientation(String.valueOf(0.0)); + String mobileTime = "2022-03-21T14:33:50+08:00"; + if(StringUtils.isBlank(mobileTime)){ + log.error("时间为空:{}",mobileTime); + } + String[] split = mobileTime.split("\\+"); + String s = split[0]; + String formatTime = s.replaceAll("T", " "); + esGpsInfo.setGpsTime(DateUtil.parse(formatTime,"yyyy-MM-dd HH:mm:ss")); + myTaskExecutor.execute(() -> { +// R response = dataToEsService.saveDataBatch(esGpsInfo); + log.info("responsecode={}",300); + }); + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/ThreadConfig.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/ThreadConfig.java new file mode 100644 index 00000000..0c481820 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/config/ThreadConfig.java @@ -0,0 +1,23 @@ +package org.dromara.webscoket.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +import java.util.concurrent.ScheduledThreadPoolExecutor; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-15 10:11 + */ +@Configuration +@EnableScheduling +public class ThreadConfig { + @Bean + public ScheduledThreadPoolExecutor scheduledExecutorService() { + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(8); + return executor; + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/constants/WebSocketMessageConstant.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/constants/WebSocketMessageConstant.java new file mode 100644 index 00000000..11d3866e --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/constants/WebSocketMessageConstant.java @@ -0,0 +1,14 @@ +package org.dromara.webscoket.constants; + +/** + *

description:

+ * + */ +public class WebSocketMessageConstant { + public static final String POSITION_MSG_TYPE = "msg_vedio_mobileposition"; + public static final String POSITION_MSG_TYPE_ORIGINAL = "msg_sipbody_parseerror"; + public static final int POSITION_DATA_TYPE = 130; + public static final int POSITION_DATA_TYPE_ORIGINAL = 131; + public static final int ONLINE = 1; + public static final int OFFLINE = 2; +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntity.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntity.java new file mode 100644 index 00000000..9f5afd0c --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntity.java @@ -0,0 +1,208 @@ +package org.dromara.webscoket.domain; + +import java.util.List; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 11:46 + */ +public class LocationZfjlyEntity { + + /** + * data : [{"sysId":"11010000002000000001","resourceInfoList":[{"globalRid":"11010000001320002060","MobileTime":"2020-08-28 13:53:14","Longitude":14.123456,"Latitude":13.12345,"Speed ":13.12345,"Direction":13.12345,"Altitude":1,"AlarmDescription":"移动位置通知"}],"datatype":130}] + * sn : 2020-08-28 13:53:14 + * msgtype : msg_vedio_mobileposition + */ + + private String sn; + private String msgtype; + private List data; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getMsgtype() { + return msgtype; + } + + public void setMsgtype(String msgtype) { + this.msgtype = msgtype; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public static class DataBean { + /** + * sysId : 11010000002000000001 + * resourceInfoList : [{"globalRid":"11010000001320002060","MobileTime":"2020-08-28 13:53:14","Longitude":14.123456,"Latitude":13.12345,"Speed ":13.12345,"Direction":13.12345,"Altitude":1,"AlarmDescription":"移动位置通知"}] + * datatype : 130 + */ + + private String sysId; + private int datatype; + private List resourceInfoList; + + public String getSysId() { + return sysId; + } + + public void setSysId(String sysId) { + this.sysId = sysId; + } + + public int getDatatype() { + return datatype; + } + + public void setDatatype(int datatype) { + this.datatype = datatype; + } + + public List getResourceInfoList() { + return resourceInfoList; + } + + public void setResourceInfoList(List resourceInfoList) { + this.resourceInfoList = resourceInfoList; + } + + public static class ResourceInfoListBean { + /** + * globalRid : 11010000001320002060 + * MobileTime : 2020-08-28 13:53:14 + * Longitude : 14.123456 + * Latitude : 13.12345 + * Speed : 13.12345 + * Direction : 13.12345 + * Altitude : 1 + * AlarmDescription : 移动位置通知 + */ + + private String globalRid; + private String MobileTime; + private double Longitude; + private double Latitude; + private double Speed; + private double Direction; + private int Altitude; + private String AlarmDescription; + + //上线先的属性 + private int status; + private String rid; + private int resourceTypeId; + private String floorNo; + //上线先的属性 + + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public String getRid() { + return rid; + } + + public void setRid(String rid) { + this.rid = rid; + } + + public int getResourceTypeId() { + return resourceTypeId; + } + + public void setResourceTypeId(int resourceTypeId) { + this.resourceTypeId = resourceTypeId; + } + + public String getFloorNo() { + return floorNo; + } + + public void setFloorNo(String floorNo) { + this.floorNo = floorNo; + } + + public String getGlobalRid() { + return globalRid; + } + + public void setGlobalRid(String globalRid) { + this.globalRid = globalRid; + } + + public String getMobileTime() { + return MobileTime; + } + + public void setMobileTime(String MobileTime) { + this.MobileTime = MobileTime; + } + + public double getLongitude() { + return Longitude; + } + + public void setLongitude(double Longitude) { + this.Longitude = Longitude; + } + + public double getLatitude() { + return Latitude; + } + + public void setLatitude(double Latitude) { + this.Latitude = Latitude; + } + + public double getSpeed() { + return Speed; + } + + public void setSpeed(double Speed) { + this.Speed = Speed; + } + + public double getDirection() { + return Direction; + } + + public void setDirection(double Direction) { + this.Direction = Direction; + } + + public int getAltitude() { + return Altitude; + } + + public void setAltitude(int Altitude) { + this.Altitude = Altitude; + } + + public String getAlarmDescription() { + return AlarmDescription; + } + + public void setAlarmDescription(String AlarmDescription) { + this.AlarmDescription = AlarmDescription; + } + } + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntityXml.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntityXml.java new file mode 100644 index 00000000..599b8b82 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/LocationZfjlyEntityXml.java @@ -0,0 +1,98 @@ +package org.dromara.webscoket.domain; + +import java.util.List; + +/** + *

description:

+ * + * @author chenle + * @date 2022-07-01 6:28 + */ +public class LocationZfjlyEntityXml { + + /** + * data : [{"sysId":"34150000002000987654","resourceInfoList":[{"sipbody":"PD94bWwgdmVyc2lvbj0iMS4wIiA/Pg0KPE5vdGlmeT4NCjxDbWRUeXBlPk1vYmlsZVBvc2l0aW9uPC9DbWRUeXBlPg0KPFNOPjE5MjwvU04+DQo8RGV2aWNlSUQ+MzQxNTAxMDAwMDIwMDAwMDAwMDk8L0RldmljZUlEPg0KPEdwc0l0ZW1MaXN0IE51bT0iMSI+DQo8SXRlbT4NCjxEZXZpY2VJRD4zNDE1MDEwMDAwMTMyMDAwMDAwNDwvRGV2aWNlSUQ+DQo8VGltZT4yMDIyLTA3LTAxVDE0OjA2OjE1KzA4OjAwPC9UaW1lPg0KPExvbmdpdHVkZT4xMTYuMzI0NDIyOTk5OTk5OTk2PC9Mb25naXR1ZGU+DQo8TGF0aXR1ZGU+MzEuNDA3NzMwMDAwMDAwMDAwODwvTGF0aXR1ZGU+DQo8U3BlZWQ+MDwvU3BlZWQ+DQo8RGlyZWN0aW9uPjA8L0RpcmVjdGlvbj4NCjxBbHRpdHVkZT41MjwvQWx0aXR1ZGU+DQo8L0l0ZW0+DQo8L0dwc0l0ZW1MaXN0Pg0KPC9Ob3RpZnk+DQo="}],"datatype":131}] + * sn : 2022-07-01 14:04:47 + * msgtype : msg_sipbody_parseerror + */ + + private String sn; + private String msgtype; + private List data; + + public String getSn() { + return sn; + } + + public void setSn(String sn) { + this.sn = sn; + } + + public String getMsgtype() { + return msgtype; + } + + public void setMsgtype(String msgtype) { + this.msgtype = msgtype; + } + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public static class DataBean { + /** + * sysId : 34150000002000987654 + * resourceInfoList : [{"sipbody":"PD94bWwgdmVyc2lvbj0iMS4wIiA/Pg0KPE5vdGlmeT4NCjxDbWRUeXBlPk1vYmlsZVBvc2l0aW9uPC9DbWRUeXBlPg0KPFNOPjE5MjwvU04+DQo8RGV2aWNlSUQ+MzQxNTAxMDAwMDIwMDAwMDAwMDk8L0RldmljZUlEPg0KPEdwc0l0ZW1MaXN0IE51bT0iMSI+DQo8SXRlbT4NCjxEZXZpY2VJRD4zNDE1MDEwMDAwMTMyMDAwMDAwNDwvRGV2aWNlSUQ+DQo8VGltZT4yMDIyLTA3LTAxVDE0OjA2OjE1KzA4OjAwPC9UaW1lPg0KPExvbmdpdHVkZT4xMTYuMzI0NDIyOTk5OTk5OTk2PC9Mb25naXR1ZGU+DQo8TGF0aXR1ZGU+MzEuNDA3NzMwMDAwMDAwMDAwODwvTGF0aXR1ZGU+DQo8U3BlZWQ+MDwvU3BlZWQ+DQo8RGlyZWN0aW9uPjA8L0RpcmVjdGlvbj4NCjxBbHRpdHVkZT41MjwvQWx0aXR1ZGU+DQo8L0l0ZW0+DQo8L0dwc0l0ZW1MaXN0Pg0KPC9Ob3RpZnk+DQo="}] + * datatype : 131 + */ + + private String sysId; + private int datatype; + private List resourceInfoList; + + public String getSysId() { + return sysId; + } + + public void setSysId(String sysId) { + this.sysId = sysId; + } + + public int getDatatype() { + return datatype; + } + + public void setDatatype(int datatype) { + this.datatype = datatype; + } + + public List getResourceInfoList() { + return resourceInfoList; + } + + public void setResourceInfoList(List resourceInfoList) { + this.resourceInfoList = resourceInfoList; + } + + public static class ResourceInfoListBean { + /** + * sipbody : PD94bWwgdmVyc2lvbj0iMS4wIiA/Pg0KPE5vdGlmeT4NCjxDbWRUeXBlPk1vYmlsZVBvc2l0aW9uPC9DbWRUeXBlPg0KPFNOPjE5MjwvU04+DQo8RGV2aWNlSUQ+MzQxNTAxMDAwMDIwMDAwMDAwMDk8L0RldmljZUlEPg0KPEdwc0l0ZW1MaXN0IE51bT0iMSI+DQo8SXRlbT4NCjxEZXZpY2VJRD4zNDE1MDEwMDAwMTMyMDAwMDAwNDwvRGV2aWNlSUQ+DQo8VGltZT4yMDIyLTA3LTAxVDE0OjA2OjE1KzA4OjAwPC9UaW1lPg0KPExvbmdpdHVkZT4xMTYuMzI0NDIyOTk5OTk5OTk2PC9Mb25naXR1ZGU+DQo8TGF0aXR1ZGU+MzEuNDA3NzMwMDAwMDAwMDAwODwvTGF0aXR1ZGU+DQo8U3BlZWQ+MDwvU3BlZWQ+DQo8RGlyZWN0aW9uPjA8L0RpcmVjdGlvbj4NCjxBbHRpdHVkZT41MjwvQWx0aXR1ZGU+DQo8L0l0ZW0+DQo8L0dwc0l0ZW1MaXN0Pg0KPC9Ob3RpZnk+DQo= + */ + + private String sipbody; + + public String getSipbody() { + return sipbody; + } + + public void setSipbody(String sipbody) { + this.sipbody = sipbody; + } + } + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/OriginDevice.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/OriginDevice.java new file mode 100644 index 00000000..d116943a --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/OriginDevice.java @@ -0,0 +1,73 @@ +package org.dromara.webscoket.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.sql.Timestamp; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 16:33 + */ +@Data +@TableName("zkxc_rs") +public class OriginDevice { + @TableId(value = "ID",type = IdType.AUTO) + private int ID; + @TableField("DevPubID") + private String DevPubID; + @TableField("ResType") + private int ResType; + @TableField("Nickname") + private String Nickname; + @TableField("ChanPubID") + private String ChanPubID; + @TableField("Alive") + private int Alive; + @TableField("CorpID") + private String CorpID; + @TableField("Model") + private String Model; + @TableField("Owner") + private String Owner; + @TableField("CivilCode") + private String CivilCode; + @TableField("Address") + private String Address; + @TableField("Parental") + private int Parental; + @TableField("ParentId") + private String ParentId; + @TableField("IP") + private String IP; + @TableField("Port") + private int Port; + @TableField("Longitude") + private Double Longitude; + @TableField("Latitude") + private Double Latitude; + @TableField("Altitude") + private Double Altitude; + @TableField("PTZType") + private int PTZType; + @TableField("RoomType") + private int RoomType; + @TableField("DirectionType") + private int DirectionType; + @TableField("StreamType") + private int StreamType; + @TableField("ChanRtspUrl") + private String ChanRtspUrl; + @TableField("RealRtspUrl") + private String RealRtspUrl; + @TableField("DMarker") + private int DMarker; + @TableField("UpdateTime") + private Timestamp UpdateTime; + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/XmlEntity.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/XmlEntity.java new file mode 100644 index 00000000..fec1f8f9 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/domain/XmlEntity.java @@ -0,0 +1,173 @@ +package org.dromara.webscoket.domain; + +import java.util.List; + +/** + *

description:

+ * + * @author chenle + * @date 2022-07-01 6:26 + */ +public class XmlEntity { + /** + * Notify : {"DeviceID":"34150100002000000009","GpsItemList":{"Num":1,"Item":[{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52},{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52}]},"SN":192,"CmdType":"MobilePosition"} + */ + + private NotifyBean Notify; + + public NotifyBean getNotify() { + return Notify; + } + + public void setNotify(NotifyBean Notify) { + this.Notify = Notify; + } + + public static class NotifyBean { + /** + * DeviceID : 34150100002000000009 + * GpsItemList : {"Num":1,"Item":[{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52},{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52}]} + * SN : 192 + * CmdType : MobilePosition + */ + + private String DeviceID; + private GpsItemListBean GpsItemList; + private int SN; + private String CmdType; + + public String getDeviceID() { + return DeviceID; + } + + public void setDeviceID(String DeviceID) { + this.DeviceID = DeviceID; + } + + public GpsItemListBean getGpsItemList() { + return GpsItemList; + } + + public void setGpsItemList(GpsItemListBean GpsItemList) { + this.GpsItemList = GpsItemList; + } + + public int getSN() { + return SN; + } + + public void setSN(int SN) { + this.SN = SN; + } + + public String getCmdType() { + return CmdType; + } + + public void setCmdType(String CmdType) { + this.CmdType = CmdType; + } + + public static class GpsItemListBean { + /** + * Num : 1 + * Item : [{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52},{"Speed":0,"DeviceID":"34150100001320000004","Time":"2022-07-01T14:06:15+08:00","Latitude":31.40773,"Longitude":116.324423,"Direction":0,"Altitude":52}] + */ + + private int Num; + private List Item; + + public int getNum() { + return Num; + } + + public void setNum(int Num) { + this.Num = Num; + } + + public List getItem() { + return Item; + } + + public void setItem(List Item) { + this.Item = Item; + } + + public static class ItemBean { + /** + * Speed : 0 + * DeviceID : 34150100001320000004 + * Time : 2022-07-01T14:06:15+08:00 + * Latitude : 31.40773 + * Longitude : 116.324423 + * Direction : 0 + * Altitude : 52 + */ + + private int Speed; + private String DeviceID; + private String Time; + private double Latitude; + private double Longitude; + private int Direction; + private int Altitude; + + public int getSpeed() { + return Speed; + } + + public void setSpeed(int Speed) { + this.Speed = Speed; + } + + public String getDeviceID() { + return DeviceID; + } + + public void setDeviceID(String DeviceID) { + this.DeviceID = DeviceID; + } + + public String getTime() { + return Time; + } + + public void setTime(String Time) { + this.Time = Time; + } + + public double getLatitude() { + return Latitude; + } + + public void setLatitude(double Latitude) { + this.Latitude = Latitude; + } + + public double getLongitude() { + return Longitude; + } + + public void setLongitude(double Longitude) { + this.Longitude = Longitude; + } + + public int getDirection() { + return Direction; + } + + public void setDirection(int Direction) { + this.Direction = Direction; + } + + public int getAltitude() { + return Altitude; + } + + public void setAltitude(int Altitude) { + this.Altitude = Altitude; + } + } + } + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/exception/MyBusinessException.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/exception/MyBusinessException.java new file mode 100644 index 00000000..010009bc --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/exception/MyBusinessException.java @@ -0,0 +1,54 @@ +package org.dromara.webscoket.exception; + +/** + *

description:

+ * + * @author chenle + * @date 2021-06-07 10:56 + */ +public class MyBusinessException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public MyBusinessException(String msg) { + super(msg); + this.msg = msg; + } + + public MyBusinessException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public MyBusinessException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public MyBusinessException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyApplicationContextRefreshedListener.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyApplicationContextRefreshedListener.java new file mode 100644 index 00000000..c436fe38 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyApplicationContextRefreshedListener.java @@ -0,0 +1,56 @@ +package org.dromara.webscoket.handler; + +import jakarta.servlet.annotation.WebListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.client.WebSocketConnectionManager; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; + +/** + * spring容器初始化监听,初始化完成后执行websocket连接 + * + * @author kesq + * + */ +@WebListener +@Component +public class MyApplicationContextRefreshedListener implements ApplicationListener { + private static Logger logger = LoggerFactory.getLogger(MyApplicationContextRefreshedListener.class); + + + @Autowired + MyWebSocketClientHandler myWebSocketClientHandler; + + //安庆 +// public static final String WEBSOCKET_URL = "ws://140.168.7.220:32090/vms/websocket/socketServer.do"; +// 六安 +// public static final String WEBSOCKET_URL = "ws://10.20.80.9:32090/vms/websocket/socketServer.do"; + //滁州 +// public static final String WEBSOCKET_URL = "ws://53.193.3.5:32090/vms/websocket/socketServer.do"; + //铜陵 + public static final String WEBSOCKET_URL = "ws://53.238.84.26:32090/vms/websocket/socketServer.do"; + + /** + * 定义websocket配置 + * + * @return + */ + @Bean(name = "wsCloudConnectionManager") + public WebSocketConnectionManager wsCloudConnectionManager() { + StandardWebSocketClient webSocketClient = new StandardWebSocketClient(); + WebSocketConnectionManager manager = new WebSocketConnectionManager(webSocketClient, myWebSocketClientHandler, + WEBSOCKET_URL); + manager.setAutoStartup(true); + return manager; + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + logger.info("准备进行中"); + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyWebSocketClientHandler.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyWebSocketClientHandler.java new file mode 100644 index 00000000..02b69ff0 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/handler/MyWebSocketClientHandler.java @@ -0,0 +1,128 @@ +package org.dromara.webscoket.handler; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.webscoket.strategy.WebMessageContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.*; +import org.springframework.web.socket.client.WebSocketConnectionManager; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-15 10:05 + */ +@Slf4j +@Component +public class MyWebSocketClientHandler implements WebSocketHandler { + + /** + * 当前服务建立与服务端建立的链接信息 + */ + private WebSocketSession clientSession = null; + + /** + * 初始化当前重连次数 + */ + private Integer currentConnectionTimes = 0; + + @Autowired + WebMessageContext webMessageContext; + + @Autowired + @Lazy + @Qualifier("wsCloudConnectionManager") + WebSocketConnectionManager wsConnectionManager; + + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + System.out.println("Websocket client connection established"); + this.clientSession = session; + System.out.println("获取链接之后的session={}"+clientSession); + log.info("获取链接之后的session={}",clientSession); + } + + @Override + public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception { + webMessageContext.handle(message); + + } + + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { + exception.printStackTrace(); + if (session.isOpen()) { + session.close(); + } + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { + log.info("Websocket client connection closed"); + this.clientSession = null; + } + + /** + * 发送消息,如果连接断开,缓存到数据库 + * + * @param content + * 发送内容 + */ + public void sendMessage(String content) { + System.out.println("send content >>> " + content); + if (isConnected()) { + try { + this.clientSession.sendMessage(new TextMessage(content)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + // cache + log.info("Connection closed "); + } + } + + + /** + * 每60秒发送一个心跳,检测断开后重连 + */ + @Scheduled(cron = "${websocket.pong.schedule.cron}") + public void heartBeat() { + System.out.println("执行定时任务开始"); + System.out.println(isConnected()); + try { + if (isConnected()) { + this.clientSession.sendMessage(new PongMessage(ByteBuffer.wrap("1".getBytes()))); + } else { + log.info("Send Ping Message fail, not connect try {} 次,reconnecting",currentConnectionTimes); + currentConnectionTimes++; + // 重连 + wsConnectionManager.startInternal(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 判断连接是否存在 + * + * @return + */ + public Boolean isConnected() { + return null != this.clientSession && this.clientSession.isOpen(); + } + + @Override + public boolean supportsPartialMessages() { + return false; + } +} + diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/mapper/OriginDeviceMapper.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/mapper/OriginDeviceMapper.java new file mode 100644 index 00000000..f7075749 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/mapper/OriginDeviceMapper.java @@ -0,0 +1,15 @@ +package org.dromara.webscoket.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.webscoket.domain.OriginDevice; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-18 10:23 + */ +@Mapper +public interface OriginDeviceMapper extends BaseMapper { +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceSchedule.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceSchedule.java new file mode 100644 index 00000000..a1561b63 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceSchedule.java @@ -0,0 +1,168 @@ +package org.dromara.webscoket.schedule; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.system.api.RemoteDeptService; +import org.dromara.system.api.RemoteDeviceService; +import org.dromara.system.api.domain.bo.RemoteDeptBo; +import org.dromara.system.api.domain.bo.RemoteDeviceBo; +import org.dromara.system.api.domain.vo.RemoteDeptVo; +import org.dromara.webscoket.domain.OriginDevice; +import org.dromara.webscoket.mapper.OriginDeviceMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.util.CollectionUtils; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 16:49 + */ +@Configuration +@Slf4j +public class DeviceSchedule { + + + @Value("${ruansi.start_update_time}") + private String startUpdateTime; + + private String lastUpdateTime = ""; + + @Autowired + OriginDeviceMapper originDeviceMapper; + + @DubboReference + RemoteDeptService deptService; + + @DubboReference + RemoteDeviceService deviceService; + + + @Scheduled( cron = "0 */3 * * * ?") + public void deviceTrans(){ + if(StringUtils.isBlank(lastUpdateTime)){ + lastUpdateTime = startUpdateTime; + } + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.gt(OriginDevice::getUpdateTime,lastUpdateTime); + lqw.orderByDesc(OriginDevice::getUpdateTime); + lqw.eq(OriginDevice::getResType,1); + + + lqw.ne(OriginDevice::getNickname,"BroadcastChannel"); + List originDevices = originDeviceMapper.selectList(lqw); + List newDeviceList = new ArrayList<>(); + log.info("updateTime={},deviceSize={}",lastUpdateTime,originDevices.size()); + if(CollectionUtils.isEmpty(originDevices)){ + log.info("没有可更新的设备"); + return; + } + for (OriginDevice originDevice : originDevices) { + RemoteDeviceBo newDevice = new RemoteDeviceBo(); + String deviceCode = originDevice.getChanPubID(); + if(StringUtils.isNotBlank(deviceCode)){ + newDevice.setDeviceCode(deviceCode); + if (originDevice.getNickname().contains("皖")){ + newDevice.setDeviceType("8"); + }else if(originDevice.getNickname().contains("布控球")) { + newDevice.setDeviceType("7"); + }else { + newDevice.setDeviceType("5"); + } + newDevice.setValid(1); + newDevice.setPoliceName(originDevice.getNickname()); + Timestamp updateTime = originDevice.getUpdateTime(); +// DateTime dateTime = DateUtil.offsetHour(updateTime, 13); + newDevice.setUpdateTime(DateUtil.formatDateTime(updateTime) ); + setZzjgdm(newDevice,originDevice); + + } + if(StringUtils.isBlank(newDevice.getZzjgdm())){ + log.info("没找到该组织机构代码"); + continue; + } + newDeviceList.add(newDevice); + } + if(CollectionUtils.isEmpty(newDeviceList)){ + log.info("未查询到设备newDeviceList = null"); + return; + } + + boolean count = deviceService.batchSaveDevice(newDeviceList); + log.info("更新的结果={}",count); + if(count){ + Timestamp updateTime = originDevices.get(0).getUpdateTime(); + + lastUpdateTime = DateUtil.formatDateTime(updateTime); + log.info("timestamp={},lastUpdateTime={}",updateTime,lastUpdateTime); + } + } + + + /** + * 赋值组织机构代码和名称 + * @param newDevice + * @param originDevice + */ + private void setZzjgdm(RemoteDeviceBo newDevice, OriginDevice originDevice) { + String parentId = originDevice.getParentId(); + String eqValue = ""; + RemoteDeptBo bo = new RemoteDeptBo(); + bo.setFullName(parentId); + RemoteDeptVo one = null; + try { + List list = deptService.selectDept(bo); + if (list.size()> 0){ + one = list.get(0); + } + }catch (Exception e){ + log.info("查询组织机构错误:{}",e.getMessage()); + return; + } + if(Objects.isNull(one)){ +// log.info("未找到该组织机构,civilCode={},civilCode + eqValue={}",civilCode,civilCode + eqValue); + newDevice.setZzjgdm("341800000000"); + newDevice.setZzjgmc("宣城市公安局"); + return; + } + + //将组织机构加在人员名称前面 +// resetPoliceName(newDevice,one.getFullName()); + //newDevice.setPoliceName(newDevice.getZzjgmc() + newDevice.getPoliceName()); +// reSetPoliceName(newDevice,civilCode); + } + + private void resetPoliceName(RemoteDeviceBo newDevice,String shortName) { + String zzjgmc = shortName; + String preName = zzjgmc; + if(StringUtils.isBlank(zzjgmc)){ + log.info("zzjgmc 为空:{}",newDevice.getPoliceName()); + } + + if((zzjgmc.contains("分局") || zzjgmc.contains("公安分局")) && + ((zzjgmc.contains("派出所") || zzjgmc.contains("大队")))) { + preName = preName.replaceAll("分局", "") + .replaceAll("派出",""); + } + + if(zzjgmc.contains("支队") && zzjgmc.contains("大队")){ + preName = preName.replaceAll("支队",""); + } + + newDevice.setPoliceName(preName + newDevice.getPoliceName()); + + } + + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceStatusSchedule.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceStatusSchedule.java new file mode 100644 index 00000000..883c6988 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/schedule/DeviceStatusSchedule.java @@ -0,0 +1,93 @@ +package org.dromara.webscoket.schedule; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.common.core.domain.R; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.system.api.RemoteDeviceService; +import org.dromara.system.api.domain.vo.RemoteDeviceVo; +import org.dromara.webscoket.domain.OriginDevice; +import org.dromara.webscoket.mapper.OriginDeviceMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.util.CollectionUtils; + +import java.sql.Timestamp; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Configuration +@Slf4j +public class DeviceStatusSchedule { + + @DubboReference + RemoteDataToEsService dataToEsService; + + @Value("${ruansi.start_update_time}") + private String startUpdateTime; + + private String lastUpdateTime = ""; + + @Autowired + OriginDeviceMapper originDeviceMapper; + + + @DubboReference + RemoteDeviceService newDeviceService; + + @Scheduled( cron = "0 */2 * * * ?") // + public void deviceStatus(){ + if(StringUtils.isBlank(lastUpdateTime)){ + lastUpdateTime = startUpdateTime; + } + Instant start = Instant.now(); + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.gt("UpdateTime",lastUpdateTime); + wrapper.orderByDesc("UpdateTime"); + wrapper.eq("ResType",1); + wrapper.ne("Nickname","BroadcastChannel"); + List originDevices = originDeviceMapper.selectList(wrapper); + List newDeviceList = new ArrayList<>(); + if(CollectionUtils.isEmpty(originDevices)){ + log.info("没有可更新的设备"); + return; + } + List list = new ArrayList<>(); + for (OriginDevice originDevice : originDevices) { + RemoteGpsInfo info = new RemoteGpsInfo(); + String deviceCode = originDevice.getChanPubID(); + if(StringUtils.isNotBlank(deviceCode)){ + info.setDeviceCode(deviceCode); + if (originDevice.getNickname().contains("皖")){ + info.setDeviceType("8"); + }else if(originDevice.getNickname().contains("布控球")) { + info.setDeviceType("7"); + }else { + info.setDeviceType("5"); + } + info.setOnline(originDevice.getAlive()); + Timestamp updateTime = originDevice.getUpdateTime(); + list.add(info); +// dataToEsService.updateOnlineStatus(info); + + } + + } + Timestamp updateTime = originDevices.get(0).getUpdateTime(); + lastUpdateTime = DateUtil.formatDateTime(updateTime); + R r = dataToEsService.updateOnlineStatusBatch(list); + log.info("response ={}",r.getMsg()); + Instant finish = Instant.now(); + long timeElapsed = Duration.between(start, finish).toMillis(); + log.info("请求总耗时={},timestamp={},lastUpdateTime={}",timeElapsed,updateTime,lastUpdateTime); + } + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/ChuZhouTextMessageHandler.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/ChuZhouTextMessageHandler.java new file mode 100644 index 00000000..c32e98b1 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/ChuZhouTextMessageHandler.java @@ -0,0 +1,183 @@ +package org.dromara.webscoket.strategy; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64Decoder; +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.hutool.json.XML; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.common.core.domain.R; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.webscoket.domain.LocationZfjlyEntityXml; +import org.dromara.webscoket.domain.XmlEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketMessage; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +import static org.dromara.webscoket.constants.WebSocketMessageConstant.POSITION_DATA_TYPE_ORIGINAL; +import static org.dromara.webscoket.constants.WebSocketMessageConstant.POSITION_MSG_TYPE_ORIGINAL; + + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 11:57 + */ +@Service("chuZhouMessageHandler") +@Slf4j +public class ChuZhouTextMessageHandler implements IMessageHandleStrategy { + + @Autowired + private ThreadPoolTaskExecutor myTaskExecutor; + + @DubboReference + RemoteDataToEsService dataToEsService; + + + + + @Override + public void handleMessage(WebSocketMessage message) { + TextMessage textMessage = (TextMessage) message; + String payload = textMessage.getPayload(); + //log.error("payload={}",payload); + //解析xml 六安 滁州 + parseXml(payload); + //正常解析json 安庆 + //parseNormalJson(payload); + + } + + private void parseXml(String payload) { + + LocationZfjlyEntityXml locationZfjlyEntityXml = JSONUtil.toBean(payload, LocationZfjlyEntityXml.class); + if(Objects.isNull(locationZfjlyEntityXml)){ + log.error("websocket message解析失败,实体类为null,message={}",locationZfjlyEntityXml); + return; + } + String msgtype = locationZfjlyEntityXml.getMsgtype(); + if(StringUtils.isBlank(msgtype) || !POSITION_MSG_TYPE_ORIGINAL.equals(msgtype)){ + log.error("messageType为空或msgtype不等于msg_vedio_mobileposition,message={}",msgtype); + return; + } + List data = locationZfjlyEntityXml.getData(); + if(CollectionUtils.isEmpty(data)){ + //log.error("data 为 null,message={}",message); + log.error("data 为 null"); + return; + } + for (LocationZfjlyEntityXml.DataBean dataBean : data) { + int datatype = dataBean.getDatatype(); + if(POSITION_DATA_TYPE_ORIGINAL != datatype){ + log.error("datatype 不等于131,dataType={}",datatype); + continue; + } + List resourceInfoList = dataBean.getResourceInfoList(); + if(CollectionUtils.isEmpty(resourceInfoList)){ + log.error("resourceInfoList为空"); + continue; + } +// log.error("payload={}",payload); + parseSipBody(resourceInfoList); + } + + } + + private void parseSipBody(List resourceInfoList) { + LocationZfjlyEntityXml.DataBean.ResourceInfoListBean resourceInfoListBean = resourceInfoList.get(0); + String sipbody = resourceInfoListBean.getSipbody(); + String xml = Base64Decoder.decodeStr(sipbody); + JSONObject jsonObject = XML.toJSONObject(xml); + if(Objects.isNull(jsonObject)){ + log.info("jsonobject=null,xml={}",xml); + return; + } + log.error("jsonObject={}",jsonObject.toString()); + XmlEntity xmlEntity = BeanUtil.toBean(jsonObject, XmlEntity.class); + if(Objects.isNull(xmlEntity)){ + log.info("xmlEntity=null,xml={}",xml); + return; + } + XmlEntity.NotifyBean notify = xmlEntity.getNotify(); + if(Objects.isNull(notify)){ + log.info("notify=null,xml={}",xml); + return; + } + XmlEntity.NotifyBean.GpsItemListBean gpsItemList = notify.getGpsItemList(); + if(Objects.isNull(gpsItemList)){ + log.info("gpsItemList=null,xml={}",xml); + return; + } + List item = gpsItemList.getItem(); + if(CollectionUtils.isEmpty(item)){ + log.info("GpsItemListBean=null,xml={}",xml); + return; + } + for (XmlEntity.NotifyBean.GpsItemListBean.ItemBean itemBean : item) { + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + String deviceID = itemBean.getDeviceID(); + double latitude = itemBean.getLatitude(); + double longitude = itemBean.getLongitude(); + int speed = itemBean.getSpeed(); + String mobileTime = itemBean.getTime(); + int direction = itemBean.getDirection(); + + esGpsInfo.setDeviceCode(deviceID); + esGpsInfo.setLat(String.valueOf(latitude)); + esGpsInfo.setLng(String.valueOf(longitude)); + esGpsInfo.setSpeed(String.valueOf(speed)); + esGpsInfo.setOrientation(String.valueOf(direction)); + esGpsInfo.setOnline(1); + esGpsInfo.setDeviceType("5"); + if(StringUtils.isBlank(mobileTime)){ + log.info("时间为空:{}",mobileTime); + continue; + } + String[] split = mobileTime.split("\\+"); + String s = split[0]; + String formatTime = s.replaceAll("T", " "); + esGpsInfo.setGpsTime(DateUtil.parse(formatTime,"yyyy-MM-dd HH:mm:ss")); + + //前端判断如果定位时间在当前时间前十分钟的话,那判定它离线。 + if(DateUtil.between(esGpsInfo.getGpsTime(),new Date(), DateUnit.SECOND) > 600L){ + esGpsInfo.setOnline(0); + } + +// sendToKafka(esGpsInfo); + myTaskExecutor.execute(() -> { + //安庆 + R response = null; + try { + response = dataToEsService.saveData(esGpsInfo); + } catch (Exception e) { + throw new RuntimeException(e); + } + if(Objects.isNull(response)){ + log.info("dataes response:null"); + } + if(response.getCode() != 200){ + log.info("dataes response:fail,{}",response.getMsg()); + } + if(response.getCode() == 200){ + log.info("dataes response:success"); + } + }); + + } + } + + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/IMessageHandleStrategy.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/IMessageHandleStrategy.java new file mode 100644 index 00000000..00f28125 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/IMessageHandleStrategy.java @@ -0,0 +1,14 @@ +package org.dromara.webscoket.strategy; + +import org.springframework.web.socket.WebSocketMessage; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 11:56 + */ +public interface IMessageHandleStrategy { + + public void handleMessage(WebSocketMessage message); +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TextMessageHandler.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TextMessageHandler.java new file mode 100644 index 00000000..7c947f81 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TextMessageHandler.java @@ -0,0 +1,233 @@ +package org.dromara.webscoket.strategy; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.codec.Base64Decoder; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import cn.hutool.json.XML; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.common.core.domain.R; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.webscoket.domain.LocationZfjlyEntity; +import org.dromara.webscoket.domain.LocationZfjlyEntityXml; +import org.dromara.webscoket.domain.XmlEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketMessage; + +import java.util.*; + +import static org.dromara.webscoket.constants.WebSocketMessageConstant.*; + + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 11:57 + */ +@Service("textMessageHandler") +@Slf4j +public class TextMessageHandler implements IMessageHandleStrategy { + + @Autowired + private ThreadPoolTaskExecutor myTaskExecutor; + + @DubboReference + RemoteDataToEsService dataToEsService; + + + + + @Override + public void handleMessage(WebSocketMessage message) { + TextMessage textMessage = (TextMessage) message; + String payload = textMessage.getPayload(); + log.error("payload={}",payload); + //解析xml 六安 滁州 + //parseXml(payload); + //正常解析json 安庆 + parseNormalJson(payload); + + } + + private void parseXml(String payload) { + + LocationZfjlyEntityXml locationZfjlyEntityXml = JSONUtil.toBean(payload, LocationZfjlyEntityXml.class); + if(Objects.isNull(locationZfjlyEntityXml)){ + //log.error("websocket message解析失败,实体类为null,message={}",message); + return; + } + String msgtype = locationZfjlyEntityXml.getMsgtype(); + if(StringUtils.isBlank(msgtype) || !POSITION_MSG_TYPE_ORIGINAL.equals(msgtype)){ + //log.error("messageType为空或msgtype不等于msg_vedio_mobileposition,message={}",message); + return; + } + List data = locationZfjlyEntityXml.getData(); + if(CollectionUtils.isEmpty(data)){ + //log.error("data 为 null,message={}",message); + return; + } + for (LocationZfjlyEntityXml.DataBean dataBean : data) { + int datatype = dataBean.getDatatype(); + if(POSITION_DATA_TYPE_ORIGINAL != datatype){ + continue; + } + List resourceInfoList = dataBean.getResourceInfoList(); + if(CollectionUtils.isEmpty(resourceInfoList)){ + continue; + } +// log.error("payload={}",payload); + parseSipBody(resourceInfoList); + } + + } + + private void parseSipBody(List resourceInfoList) { + LocationZfjlyEntityXml.DataBean.ResourceInfoListBean resourceInfoListBean = resourceInfoList.get(0); + String sipbody = resourceInfoListBean.getSipbody(); + String xml = Base64Decoder.decodeStr(sipbody); + JSONObject jsonObject = XML.toJSONObject(xml); + if(Objects.isNull(jsonObject)){ + log.info("jsonobject=null,xml={}",xml); + return; + } + XmlEntity xmlEntity = BeanUtil.toBean(jsonObject, XmlEntity.class); + if(Objects.isNull(xmlEntity)){ + log.info("xmlEntity=null,xml={}",xml); + return; + } + XmlEntity.NotifyBean notify = xmlEntity.getNotify(); + if(Objects.isNull(notify)){ + log.info("notify=null,xml={}",xml); + return; + } + XmlEntity.NotifyBean.GpsItemListBean gpsItemList = notify.getGpsItemList(); + if(Objects.isNull(gpsItemList)){ + log.info("gpsItemList=null,xml={}",xml); + return; + } + List item = gpsItemList.getItem(); + if(CollectionUtils.isEmpty(item)){ + log.info("GpsItemListBean=null,xml={}",xml); + return; + } + for (XmlEntity.NotifyBean.GpsItemListBean.ItemBean itemBean : item) { + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + String deviceID = itemBean.getDeviceID(); + double latitude = itemBean.getLatitude(); + double longitude = itemBean.getLongitude(); + int speed = itemBean.getSpeed(); + String mobileTime = itemBean.getTime(); + int direction = itemBean.getDirection(); + + esGpsInfo.setDeviceCode(deviceID); + esGpsInfo.setLat(String.valueOf(latitude)); + esGpsInfo.setLng(String.valueOf(longitude)); + esGpsInfo.setSpeed(String.valueOf(speed)); + esGpsInfo.setOrientation(String.valueOf(direction)); + + if(StringUtils.isBlank(mobileTime)){ + log.info("时间为空:{}",mobileTime); + continue; + } + String[] split = mobileTime.split("\\+"); + String s = split[0]; + String formatTime = s.replaceAll("T", " "); + esGpsInfo.setGpsTime(DateUtil.parse(formatTime,"yyyy-MM-dd HH:mm:ss")); + sendToKafka(esGpsInfo); + } + } + + private void parseNormalJson(String payload) { + LocationZfjlyEntity locationZfjlyEntity = JSONUtil.toBean(payload, LocationZfjlyEntity.class); + if(Objects.isNull(locationZfjlyEntity)){ + //log.error("websocket message解析失败,实体类为null,message={}",message); + return; + } + String msgtype = locationZfjlyEntity.getMsgtype(); + if(StringUtils.isBlank(msgtype) || !POSITION_MSG_TYPE.equals(msgtype)){ + //log.error("messageType为空或msgtype不等于msg_vedio_mobileposition,message={}",message); + return; + } + + List data = locationZfjlyEntity.getData(); + if(CollectionUtils.isEmpty(data)){ + //log.error("data 为 null,message={}",message); + return; + } + for (LocationZfjlyEntity.DataBean dataBean : data) { + int datatype = dataBean.getDatatype(); + if(POSITION_DATA_TYPE != datatype){ + continue; + } + List resourceInfoList = dataBean.getResourceInfoList(); + if(CollectionUtils.isEmpty(resourceInfoList)){ + continue; + } +// log.error("payload={}",payload); + sendRequest(resourceInfoList); + } + } + + private void sendRequest(List resourceInfoList) { + for (LocationZfjlyEntity.DataBean.ResourceInfoListBean resourceInfoListBean : resourceInfoList) { + double latitude = resourceInfoListBean.getLatitude(); + double longitude = resourceInfoListBean.getLongitude(); + if(latitude == 0.0 || longitude == 0.0){ + //log.error("经纬度坐标为0,globalRid={}",resourceInfoListBean.getGlobalRid()); + continue; + } + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + esGpsInfo.setDeviceCode(resourceInfoListBean.getGlobalRid()); + esGpsInfo.setDeviceType("5");//执法记录仪 + esGpsInfo.setLat(String.valueOf(resourceInfoListBean.getLatitude())); + esGpsInfo.setLng(String.valueOf(resourceInfoListBean.getLongitude())); + esGpsInfo.setSpeed(String.valueOf(resourceInfoListBean.getSpeed())); + esGpsInfo.setDeltaH(String.valueOf(resourceInfoListBean.getAltitude())); + esGpsInfo.setOrientation(String.valueOf(resourceInfoListBean.getDirection())); + String mobileTime = resourceInfoListBean.getMobileTime(); + if(StringUtils.isBlank(mobileTime)){ + //log.error("时间为空:{}",mobileTime); + continue; + } + String[] split = mobileTime.split("\\+"); + String s = split[0]; + String formatTime = s.replaceAll("T", " "); + esGpsInfo.setGpsTime(DateUtil.parse(formatTime,"yyyy-MM-dd HH:mm:ss")); + myTaskExecutor.execute(() -> { + //安庆 + try { + R response = dataToEsService.saveData(esGpsInfo); + } catch (Exception e) { + throw new RuntimeException(e); + } + //六安 + //sendToKafka(esGpsInfo); + //log.error("responsecode={}",response.getCode()); + }); + } + } + + //发送到kafka (六安) + private void sendToKafka(RemoteGpsInfo esGpsInfo) { + Map map = new HashMap<>(); + map.put("Latitude",esGpsInfo.getLat()); + map.put("Longtide",esGpsInfo.getLng()); + Date gpsTime = esGpsInfo.getGpsTime(); + String time = String.valueOf(gpsTime.getTime()); + map.put("Time",time.substring(0,time.length() - 3)); + map.put("Puid",esGpsInfo.getDeviceCode()); + map.put("Speed",esGpsInfo.getSpeed()); + map.put("Bearing",esGpsInfo.getOrientation()); + +// kafkaProducer.send(map,"topic_gps_zfjly"); + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TonglingTextMessageHandler.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TonglingTextMessageHandler.java new file mode 100644 index 00000000..138b46e0 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/TonglingTextMessageHandler.java @@ -0,0 +1,205 @@ +package org.dromara.webscoket.strategy; + +import cn.hutool.core.date.DateUnit; +import cn.hutool.core.date.DateUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.dubbo.config.annotation.DubboReference; +import org.dromara.common.core.domain.R; +import org.dromara.data2es.api.RemoteDataToEsService; +import org.dromara.data2es.api.domain.RemoteGpsInfo; +import org.dromara.webscoket.domain.LocationZfjlyEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketMessage; + +import java.util.Date; +import java.util.List; +import java.util.Objects; + +import static org.dromara.webscoket.constants.WebSocketMessageConstant.*; + + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 11:57 + */ +@Service("tonglingMessageHandler") +@Slf4j +public class TonglingTextMessageHandler implements IMessageHandleStrategy { + + @Autowired + private ThreadPoolTaskExecutor myTaskExecutor; + + @DubboReference + RemoteDataToEsService dataToEsService; + + /*@Autowired + private UpdateToEsService updateToEsService;*/ + + + + + @Override + public void handleMessage(WebSocketMessage message) { + TextMessage textMessage = (TextMessage) message; + String payload = textMessage.getPayload(); + log.error("payload={}",payload); + parseNormalJson(payload); + + } + + private void parseNormalJson(String payload) { + LocationZfjlyEntity locationZfjlyEntity = JSONUtil.toBean(payload, LocationZfjlyEntity.class); + if(Objects.isNull(locationZfjlyEntity)){ + log.error("websocket message解析失败,实体类为null"); + return; + } + /*String msgtype = locationZfjlyEntity.getMsgtype(); + if(StringUtils.isBlank(msgtype) || !POSITION_MSG_TYPE.equals(msgtype)){ + //log.error("messageType为空或msgtype不等于msg_vedio_mobileposition,message={}",message); + return; + }*/ + + List data = locationZfjlyEntity.getData(); + if(CollectionUtils.isEmpty(data)){ + log.error("data 为 null"); + return; + } + for (LocationZfjlyEntity.DataBean dataBean : data) { + int datatype = dataBean.getDatatype(); + log.error("设备状态更新判断前"+dataBean.getResourceInfoList().toString()); + if(ONLINE == datatype || OFFLINE == datatype){ + //todo 解析上下线状态 上线 datatype =1 ;下线datatype=2 + List resourceInfoList = dataBean.getResourceInfoList(); + sendRequestOnlineOffline(resourceInfoList,locationZfjlyEntity); + } + if(POSITION_DATA_TYPE == datatype){ + List resourceInfoList = dataBean.getResourceInfoList(); + if (CollectionUtils.isEmpty(resourceInfoList)) { + continue; + } + sendRequest(resourceInfoList); + } + } + } + + /** + * 发送上下线状态 + * @param resourceInfoList + * @param locationZfjlyEntity + */ + private void sendRequestOnlineOffline(List resourceInfoList, LocationZfjlyEntity locationZfjlyEntity) { + for (LocationZfjlyEntity.DataBean.ResourceInfoListBean resourceInfoListBean : resourceInfoList) { + log.error("更新设备状态开始:"+resourceInfoListBean.getGlobalRid()); + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + esGpsInfo.setDeviceCode(resourceInfoListBean.getGlobalRid()); + esGpsInfo.setDeviceType("5");//执法记录仪 + /*esGpsInfo.setLat("0"); + esGpsInfo.setLng("0"); + esGpsInfo.setSpeed("0"); + esGpsInfo.setDeltaH("0"); + esGpsInfo.setOrientation("0");*/ + int status = resourceInfoListBean.getStatus(); + //2 代表下线 + /*if(status == 2){ + status = 0; + }*/ + esGpsInfo.setOnline(status); + String mobileTime = locationZfjlyEntity.getSn(); + + esGpsInfo.setGpsTime(DateUtil.parse(mobileTime,"yyyy-MM-dd HH:mm:ss")); + //前端判断如果定位时间在当前时间前三十分钟的话,那判定它离线。 + if(DateUtil.between(esGpsInfo.getGpsTime(),new Date(), DateUnit.SECOND) > 60*10){ + esGpsInfo.setOnline(0); + } + realSendRequest(esGpsInfo); + log.error("更新设备状态结束:"+resourceInfoListBean.getGlobalRid()); + } + } + + private void realSendRequest(RemoteGpsInfo esGpsInfo) { + log.info("update dataes ,设备编码={}",esGpsInfo.getDeviceCode()); + R response = dataToEsService.updateOnlineStatus(esGpsInfo); + log.info("update response ,设备编码={},结果={}",esGpsInfo.getDeviceCode(),response.getMsg()); + if (Objects.isNull(response)) { + log.info("update dataes response:null,设备编码={}",esGpsInfo.getDeviceCode()); + } + if (response.getCode() != 200 || response.getCode() != 0) { + log.info("update dataes response:fail,{},设备编码={}", response.getMsg(),esGpsInfo.getDeviceCode()); + } + if (response.getCode() == 200 || response.getCode() == 0) { + log.info("update dataes response:success"); + } + /*myTaskExecutor.execute(() -> { + //安庆 + + });*/ + } + + private void saveAsync(RemoteGpsInfo esGpsInfo) { + myTaskExecutor.execute(() -> { + //安庆 + R response = null; + try { + response = dataToEsService.saveData(esGpsInfo); + } catch (Exception e) { + throw new RuntimeException(e); + } + if (Objects.isNull(response)) { + log.info("dataes response:null"); + } + if (response.getCode() != 200) { + log.info("dataes response:fail,{}", response.getMsg()); + } + if (response.getCode() == 200) { + log.info("dataes response:success"); + } + }); + } + + /** + * 发送定位信息 + * @param resourceInfoList + */ + private void sendRequest(List resourceInfoList) { + for (LocationZfjlyEntity.DataBean.ResourceInfoListBean resourceInfoListBean : resourceInfoList) { + double latitude = resourceInfoListBean.getLatitude(); + double longitude = resourceInfoListBean.getLongitude(); + + RemoteGpsInfo esGpsInfo = new RemoteGpsInfo(); + esGpsInfo.setDeviceCode(resourceInfoListBean.getGlobalRid()); + esGpsInfo.setDeviceType("5");//执法记录仪 + esGpsInfo.setLat(String.valueOf(resourceInfoListBean.getLatitude())); + esGpsInfo.setLng(String.valueOf(resourceInfoListBean.getLongitude())); + esGpsInfo.setSpeed(String.valueOf(resourceInfoListBean.getSpeed())); + esGpsInfo.setDeltaH(String.valueOf(resourceInfoListBean.getAltitude())); + esGpsInfo.setOrientation(String.valueOf(resourceInfoListBean.getDirection())); + esGpsInfo.setOnline(1); + String mobileTime = resourceInfoListBean.getMobileTime(); + if(StringUtils.isBlank(mobileTime)){ + //log.error("时间为空:{}",mobileTime); + continue; + } + String[] split = mobileTime.split("\\+"); + String s = split[0]; + String formatTime = s.replaceAll("T", " "); + esGpsInfo.setGpsTime(DateUtil.parse(formatTime,"yyyy-MM-dd HH:mm:ss")); + //前端判断如果定位时间在当前时间前十分钟的话,那判定它离线。 + if(DateUtil.between(esGpsInfo.getGpsTime(),new Date(), DateUnit.SECOND) > 60 * 30){ + esGpsInfo.setOnline(0); + } + saveAsync(esGpsInfo); + } + } + + + + +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/WebMessageContext.java b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/WebMessageContext.java new file mode 100644 index 00000000..1e23360a --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/java/org/dromara/webscoket/strategy/WebMessageContext.java @@ -0,0 +1,53 @@ +package org.dromara.webscoket.strategy; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.webscoket.exception.MyBusinessException; +import org.springframework.stereotype.Service; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.PongMessage; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketMessage; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + *

description:

+ * + * @author chenle + * @date 2022-03-17 14:13 + */ +@Service +@Slf4j +public class WebMessageContext { + + private final Map strategyMap = new ConcurrentHashMap<>(); + + /** + * spring4.3开始 构造函数注入bean 可以隐藏 @Autowired注解,称为构造函数隐式注入 + */ + public WebMessageContext(Map strategyMap) { + this.strategyMap.clear(); + strategyMap.forEach(this.strategyMap::put); + } + + public void handle(WebSocketMessage message) throws Exception { + String beanName = ""; + if(message instanceof PongMessage) { + beanName = ""; + }else if(message instanceof TextMessage){ + beanName = "tonglingMessageHandler"; + + }else if(message instanceof BinaryMessage){ + beanName = ""; + }else { + throw new MyBusinessException("未知的websocket消息类型:"+message); + } + IMessageHandleStrategy iMessageHandleStrategy = strategyMap.get(beanName); + if(Objects.isNull(iMessageHandleStrategy)){ + log.error("未找到处理该消息的处理器={}",message); + } + iMessageHandleStrategy.handleMessage(message); + } +} diff --git a/stwzhj-modules/wzhj-webscoket/src/main/resources/application.yml b/stwzhj-modules/wzhj-webscoket/src/main/resources/application.yml new file mode 100644 index 00000000..8261485c --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/resources/application.yml @@ -0,0 +1,34 @@ +# Tomcat +server: + port: 9214 + +# Spring +spring: + application: + # 应用名称 + name: wzhj-webscoket + profiles: + # 环境配置 + active: @profiles.active@ + +--- # nacos 配置 +spring: + cloud: + nacos: + # nacos 服务地址 + server-addr: @nacos.server@ + username: @nacos.username@ + password: @nacos.password@ + discovery: + # 注册组 + group: @nacos.discovery.group@ + namespace: ${spring.profiles.active} + config: + # 配置组 + group: @nacos.config.group@ + namespace: ${spring.profiles.active} + config: + import: + - optional:nacos:application-common.yml + - optional:nacos:datasource.yml + - optional:nacos:${spring.application.name}.yml diff --git a/stwzhj-modules/wzhj-webscoket/src/main/resources/mapper/OriginDeviceMapper.xml b/stwzhj-modules/wzhj-webscoket/src/main/resources/mapper/OriginDeviceMapper.xml new file mode 100644 index 00000000..ee66fad1 --- /dev/null +++ b/stwzhj-modules/wzhj-webscoket/src/main/resources/mapper/OriginDeviceMapper.xml @@ -0,0 +1,7 @@ + + + + +