Commit 5a7a7a12bde268c104610d3e81a08df06ccab5eb

Authored by 648540858
2 parents 66eda32a fec69c71

Merge branch 'wvp-28181-2.0' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
#	src/main/resources/all-application.yml
#	web_src/config/index.js
#	web_src/src/components/dialog/devicePlayer.vue
Showing 162 changed files with 7373 additions and 2905 deletions
README.md
... ... @@ -27,7 +27,7 @@ wvp使用文档 [https://doc.wvp-pro.cn](https://doc.wvp-pro.cn)
27 27 ZLM使用文档 [https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
28 28 > wvp文档由gitee提供服务,如果遇到打不开请多刷新几次。
29 29  
30   -# 社群地址
  30 +# 付费社群
31 31 [![社群](doc/_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
32 32 > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
33 33  
... ... @@ -104,6 +104,8 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
104 104 - [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载
105 105 - [X] 支持打包可执行jar和war
106 106 - [X] 支持跨域请求,支持前后端分离部署
  107 +- [X] 支持Mysql,Postgresql,金仓等数据库
  108 +- [X] 支持Onvif(目前在onvif分支,需要安装onvif服务,服务请在知识星球获取)
107 109  
108 110 # 授权协议
109 111 本项目自有代码使用宽松的MIT协议,在保留版权信息的情况下可以自由应用于各自商用、非商业的项目。 但是本项目也零碎的使用了一些其他的开源代码,在商用的情况下请自行替代或剔除; 由于使用本项目而产生的商业纠纷或侵权行为一概与本项目及开发者无关,请自行承担法律风险。 在使用本项目代码时,也应该在授权协议中同时表明本项目依赖的第三方库的协议
... ...
doc/README.md
... ... @@ -14,7 +14,7 @@
14 14 - 完全开源,且使用MIT许可协议。保留版权的情况下可以用于商业项目。
15 15 - 支持多流媒体节点负载均衡。
16 16  
17   -# 社群
  17 +# 付费社群
18 18 [![社群](_media/shequ.png "shequ")](https://t.zsxq.com/0d8VAD3Dm)
19 19 > 收费是为了提供更好的服务,也是对作者更大的激励。加入星球的用户三天后可以私信我留下微信号,我会拉大家入群。加入三天内不满意可以直接退款,大家不需要有顾虑,来白嫖三天也不是不可以。
20 20  
... ... @@ -62,16 +62,16 @@
62 62 - [X] 注册
63 63 - [X] 注销
64 64 - [X] 实时视音频点播
65   -- [ ] 设备控制
66   - - [ ] 云台控制
  65 +- [X] 设备控制
  66 + - [X] 云台控制
67 67 - [ ] 远程启动
68   - - [ ] 录像控制
69   - - [ ] 报警布防/撤防
70   - - [ ] 报警复位
71   - - [ ] 强制关键帧
72   - - [ ] 拉框放大
73   - - [ ] 拉框缩小
74   - - [ ] 看守位控制
  68 + - [X] 录像控制
  69 + - [X] 报警布防/撤防
  70 + - [X] 报警复位
  71 + - [X] 强制关键帧
  72 + - [X] 拉框放大
  73 + - [X] 拉框缩小
  74 + - [X] 看守位控制
75 75 - [ ] 设备配置
76 76 - [ ] 报警事件通知和分发
77 77 - [X] 设备目录订阅
... ... @@ -79,7 +79,7 @@
79 79 - [X] 设备目录查询
80 80 - [X] 设备状态查询
81 81 - [ ] 设备配置查询
82   - - [ ] 设备预置位查询
  82 + - [X] 设备预置位查询
83 83 - [X] 状态信息报送
84 84 - [X] 设备视音频文件检索
85 85 - [X] 历史视音频的回放
... ... @@ -87,7 +87,7 @@
87 87 - [x] 暂停
88 88 - [x] 进/退
89 89 - [x] 停止
90   -- [ ] 视音频文件下载
  90 +- [X] 视音频文件下载
91 91 - [ ] ~~校时~~
92 92 - [X] 订阅和通知
93 93 - [X] 事件订阅
... ...
doc/_content/introduction/config.md
... ... @@ -29,10 +29,53 @@ java -jar wvp-pro-*.jar
29 29 ```
30 30 这也是我自己最常用的方式。
31 31 ## 2 配置WVP-PRO
32   -### 2.1 Mysql数据库配置
33   -首先你需要创建一个名为wvp(也可使用其他名字)的数据库,并使用sql/mysql.sql导入数据库,初始化数据库结构。
34   -(这里注意,取决于版本,新版的sql文件夹下有update.sql,补丁包,一定要注意运行导入)
35   -在application-dev.yml中配置(使用1.2方式的是在jar包的同级目录的application.yml)配置数据库连接,包括数据库连接信息,密码。
  32 +wvp支持多种数据库,包括Mysql,Postgresql,金仓等,配置任选一种即可。
  33 +### 2.1 数据库配置
  34 +#### 2.1.1 初始化数据库
  35 +首先使用创建数据库,然后使用sql/初始化.sql初始化数据库,如果是从旧版升级上来的,使用升级sql更新。
  36 +#### 2.1.2 Mysql数据库配置
  37 +数据库名称以wvp为例
  38 +```yaml
  39 +spring:
  40 + datasource:
  41 + type: com.zaxxer.hikari.HikariDataSource
  42 + driver-class-name: com.mysql.cj.jdbc.Driver
  43 + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
  44 + username: root
  45 + password: 12345678
  46 +
  47 +mybatis:
  48 + configuration:
  49 + map-underscore-to-camel-case: true
  50 +```
  51 +#### 2.1.3 Postgresql数据库配置
  52 +数据库名称以wvp为例
  53 +```yaml
  54 +spring:
  55 + datasource:
  56 + type: com.zaxxer.hikari.HikariDataSource
  57 + driver-class-name: org.postgresql.Driver
  58 + url: jdbc:postgresql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
  59 + username: root
  60 + password: 12345678
  61 +
  62 +pagehelper:
  63 + helper-dialect: postgresql
  64 +```
  65 +#### 2.1.4 金仓数据库配置
  66 +数据库名称以wvp为例
  67 +```yaml
  68 +spring:
  69 + datasource:
  70 + type: com.zaxxer.hikari.HikariDataSource
  71 + driver-class-name: com.kingbase8.Driver
  72 + url: jdbc:kingbase8://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=utf8
  73 + username: root
  74 + password: 12345678
  75 +
  76 +pagehelper:
  77 + helper-dialect: postgresql
  78 +```
36 79 ### 2.2 Redis数据库配置
37 80 配置wvp中的redis连接信息,建议wvp自己单独使用一个db。
38 81 ### 2.3 配置服务启动端口(可直接使用默认配置)
... ...
doc/_media/1372762149.jpg 0 → 100644

126 KB

doc/_media/903207146.jpg 0 → 100644

131 KB

doc/_media/logo.jpg 0 → 100644

102 KB

doc/index.html
... ... @@ -7,7 +7,7 @@
7 7 <meta name="description" content="Description">
8 8 <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
9 9 <link rel="icon" href="_media/favicon.ico" type="image/x-icon" />
10   - <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
  10 + <link rel="stylesheet" href="./lib/css/vue.css">
11 11 <!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify/lib/themes/dark.css">-->
12 12 <style>
13 13 .cover{
... ... @@ -47,11 +47,11 @@
47 47 }
48 48 </script>
49 49 <!-- Docsify v4 -->
50   - <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
51   - <script src="//unpkg.com/docsify-plantuml/dist/docsify-plantuml.min.js"></script>
52   - <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
53   - <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
54   - <script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
  50 + <script src="./lib/js/docsify@4.js"></script>
  51 + <script src="./lib/js/docsify-plantuml.min.js"></script>
  52 + <script src="./lib/js/search.min.js"></script>
  53 + <script src="./lib/js/zoom-image.min.js"></script>
  54 + <script src="./lib/js/docsify-copy-code.min.js"></script>
55 55  
56 56 </script>
57 57 <!-- <script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/disqus.min.js"></script>-->
... ...
doc/lib/css/vue.css 0 → 100644
  1 +@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready)>nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}img.emoji{height:1.2em}img.emoji,span.emoji{vertical-align:middle}span.emoji{font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1.2em}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;min-height:100vh;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave .56s ease-in-out}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{position:relative;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;min-height:100vh;width:100%;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;bottom:0;width:100%}section.cover .cover-main{flex:1;margin:0 16px;text-align:center;position:relative}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid #42b983;border-color:var(--theme-color,#42b983);box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code,.markdown-section output:after,.markdown-section pre{font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section code,.markdown-section pre{background-color:#f8f8f8}.markdown-section output,.markdown-section pre{margin:1.2em 0;position:relative}.markdown-section output,.markdown-section pre>code{border-radius:2px;display:block}.markdown-section output:after,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section code{border-radius:2px;color:#e96900;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{padding:0 1.4rem;line-height:1.5rem;overflow:auto;word-wrap:normal}.markdown-section pre>code{color:#525252;font-size:.8rem;padding:2.2em 5px;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;white-space:inherit}.markdown-section output{padding:1.7rem 1.4rem;border:1px dotted #ccc}.markdown-section output>:first-child{margin-top:0}.markdown-section output>:last-child{margin-bottom:0}.markdown-section code:after,.markdown-section code:before,.markdown-section output:after,.markdown-section output:before{letter-spacing:.05rem}.markdown-section output:after,.markdown-section pre:after{color:#ccc;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0;content:attr(data-lang)}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto}
0 2 \ No newline at end of file
... ...
doc/lib/js/docsify-copy-code.min.js 0 → 100644
  1 +/*!
  2 + * docsify-copy-code
  3 + * v2.1.1
  4 + * https://github.com/jperasmus/docsify-copy-code
  5 + * (c) 2017-2020 JP Erasmus <jperasmus11@gmail.com>
  6 + * MIT license
  7 + */
  8 +!function(){"use strict";function s(o){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o})(o)}!function(o,e){void 0===e&&(e={});var t=e.insertAt;if(o&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=o:c.appendChild(document.createTextNode(o))}}(".docsify-copy-code-button,.docsify-copy-code-button span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{position:absolute;z-index:1;top:0;right:0;overflow:visible;padding:.65em .8em;border:0;border-radius:0;outline:0;font-size:1em;background:grey;background:var(--theme-color,grey);color:#fff;opacity:0}.docsify-copy-code-button span{border-radius:3px;background:inherit;pointer-events:none}.docsify-copy-code-button .error,.docsify-copy-code-button .success{position:absolute;z-index:-100;top:50%;right:0;padding:.5em .65em;font-size:.825em;opacity:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.docsify-copy-code-button.error .error,.docsify-copy-code-button.success .success{right:100%;opacity:1;-webkit-transform:translate(-115%,-50%);transform:translate(-115%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(o,e){o.ready(function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")})}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,r){o.doneEach(function(){var o=Array.apply(null,document.querySelectorAll("pre[data-lang]")),c={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};r.config.copyCode&&Object.keys(c).forEach(function(t){var n=r.config.copyCode[t];"string"==typeof n?c[t]=n:"object"===s(n)&&Object.keys(n).some(function(o){var e=-1<location.href.indexOf(o);return c[t]=e?n[o]:c[t],e})});var e=['<button class="docsify-copy-code-button">','<span class="label">'.concat(c.buttonText,"</span>"),'<span class="error">'.concat(c.errorText,"</span>"),'<span class="success">'.concat(c.successText,"</span>"),"</button>"].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}();
  9 +//# sourceMappingURL=docsify-copy-code.min.js.map
... ...
doc/lib/js/docsify-plantuml.min.js 0 → 100644
  1 +!function(t){function e(a){if(n[a])return n[a].exports;var r=n[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var n={};e.m=t,e.c=n,e.d=function(t,n,a){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:a})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var a=n(1);window.$docsify||(window.$docsify={}),window.$docsify.plugins=(window.$docsify.plugins||[]).concat(a.a)},function(t,e,n){"use strict";function a(t,e){var t=Object(o.a)(e.skin)+t,n=e.serverPath||"//www.plantuml.com/plantuml/svg/";if(e.renderSvgAsObject){var a=n+Object(l.encode)(r(t));return'<object type="image/svg+xml" data="'+a+'" />'}var a=n+Object(l.encode)(t);return'<img src="'+a+'" />'}function r(t){function e(t,e){for(var n=(a+e).split("/"),r=[],i=0,s=n.length;i<s;i++){var o=n[i];".."===o?r.pop():"."!==o&&r.push(o)}return"[["+r.join("/")}var n=window.location.toString(),a=n.substring(0,n.lastIndexOf("/")+1);return t.replace(/\[\[\$((?:\.?\.\/)*)/g,e)}function i(t,e,n){var r=window.Docsify.dom,i=r.create("span",t);return i.querySelectorAll?((r.findAll(i,e)||[]).forEach(function(t){var e=t.parentNode,i=r.create("p",a(t.innerText,n));e&&(i.dataset.lang=h,t.parentNode.replaceChild(i,t))}),i.innerHTML):t}function s(t,e){const n=Object.assign({},{skin:"default",renderSvgAsObject:!1},e.config.plantuml);t.afterEach(function(t){return i(t,d,n)})}e.a=s;var o=n(2),l=n(5),h=(n.n(l),"plantuml"),d='pre[data-lang="'+h+'"]'},function(t,e,n){"use strict";function a(t){return t in l?l[t]:(console.warn("[Docsify-PlantUML] Invalid skin name: "+t),l[h])}e.a=a;var r=n(3),i=n.n(r),s=n(4),o=n.n(s);const l={default:i.a,classic:o.a},h="default"},function(t,e){t.exports="' fork from https://github.com/matthewjosephtaylor/plantuml-style/blob/master/style.pu\n' Not-ugly plantuml style defaults\n\nskinparam defaultFontName Helvetica\nskinparam defaultFontSize 12\nskinparam sequenceMessageAlign center\nskinparam monochrome true\nskinparam shadowing false\n\nskinparam activity {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\nskinparam actor {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam usecase {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\nskinparam class {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n\tBorderThickness 1\n}\n\n\nskinparam object {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam package {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\n'TODO stereotype\n\nskinparam component {\n\tBackgroundColor White\n\tInterfaceBackgroundColor White\n\tBorderColor Black\n\tInterfaceBorderColor Black\n}\n\nskinparam note {\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam state {\n\tArrowColor Black\n\tBackgroundColor White\n\tBorderColor Black\n}\n\nskinparam sequence {\n\tArrowColor Black\n\tBackgroundColor White\n\tParticipantBackgroundColor White\n\tBorderColor Black\n\tLifeLineBorderColor Black\n\tParticipantBorderColor Black\n\tBoxLineColor Black\n}\n\nskinparam interface {\n\tBackgroundColor White\n\tBorderColor Black\n}\n"},function(t,e){t.exports=""},function(t,e,n){t.exports={encode:n(6).encode,decode:n(7).decode}},function(t,e,n){var a,a;!function(e){t.exports=e()}(function(){return function(){function t(e,n,r){function i(o,l){if(!n[o]){if(!e[o]){var h="function"==typeof a&&a;if(!l&&h)return a(o,!0);if(s)return s(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var f=n[o]={exports:{}};e[o][0].call(f.exports,function(t){return i(e[o][1][t]||t)},f,f.exports,t,e,n,r)}return n[o].exports}for(var s="function"==typeof a&&a,o=0;o<r.length;o++)i(r[o]);return i}return t}()({1:[function(t,e,n){"use strict";var a=t("pako/lib/deflate.js");e.exports=function(t){return a.deflateRaw(t,{level:9,to:"string"})}},{"pako/lib/deflate.js":4}],2:[function(t,e,n){"use strict";function a(t){return t<10?String.fromCharCode(48+t):(t-=10)<26?String.fromCharCode(65+t):(t-=26)<26?String.fromCharCode(97+t):(t-=26,0===t?"-":1===t?"_":"?")}function r(t,e,n){var r=t>>2,i=(3&t)<<4|e>>4,s=(15&e)<<2|n>>6,o=63&n,l="";return l+=a(63&r),l+=a(63&i),l+=a(63&s),l+=a(63&o)}e.exports=function(t){for(var e="",n=0;n<t.length;n+=3)n+2===t.length?e+=r(t.charCodeAt(n),t.charCodeAt(n+1),0):n+1===t.length?e+=r(t.charCodeAt(n),0,0):e+=r(t.charCodeAt(n),t.charCodeAt(n+1),t.charCodeAt(n+2));return e}},{}],3:[function(t,e,n){"use strict";var a=t("./deflate"),r=t("./encode64");e.exports.encode=function(t){var e=a(t);return r(e)}},{"./deflate":1,"./encode64":2}],4:[function(t,e,n){"use strict";function a(t){if(!(this instanceof a))return new a(t);this.options=l.assign({level:_,method:p,chunkSize:16384,windowBits:15,memLevel:8,strategy:g,to:""},t||{});var e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var n=o.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(n!==c)throw new Error(d[n]);if(e.header&&o.deflateSetHeader(this.strm,e.header),e.dictionary){var r;if(r="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===u.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,(n=o.deflateSetDictionary(this.strm,r))!==c)throw new Error(d[n]);this._dict_set=!0}}function r(t,e){var n=new a(e);if(n.push(t,!0),n.err)throw n.msg||d[n.err];return n.result}function i(t,e){return e=e||{},e.raw=!0,r(t,e)}function s(t,e){return e=e||{},e.gzip=!0,r(t,e)}var o=t("./zlib/deflate"),l=t("./utils/common"),h=t("./utils/strings"),d=t("./zlib/messages"),f=t("./zlib/zstream"),u=Object.prototype.toString,c=0,_=-1,g=0,p=8;a.prototype.push=function(t,e){var n,a,r=this.strm,i=this.options.chunkSize;if(this.ended)return!1;a=e===~~e?e:!0===e?4:0,"string"==typeof t?r.input=h.string2buf(t):"[object ArrayBuffer]"===u.call(t)?r.input=new Uint8Array(t):r.input=t,r.next_in=0,r.avail_in=r.input.length;do{if(0===r.avail_out&&(r.output=new l.Buf8(i),r.next_out=0,r.avail_out=i),1!==(n=o.deflate(r,a))&&n!==c)return this.onEnd(n),this.ended=!0,!1;0!==r.avail_out&&(0!==r.avail_in||4!==a&&2!==a)||("string"===this.options.to?this.onData(h.buf2binstring(l.shrinkBuf(r.output,r.next_out))):this.onData(l.shrinkBuf(r.output,r.next_out)))}while((r.avail_in>0||0===r.avail_out)&&1!==n);return 4===a?(n=o.deflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===c):2!==a||(this.onEnd(c),r.avail_out=0,!0)},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===c&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=l.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},n.Deflate=a,n.deflate=r,n.deflateRaw=i,n.gzip=s},{"./utils/common":5,"./utils/strings":6,"./zlib/deflate":9,"./zlib/messages":10,"./zlib/zstream":12}],5:[function(t,e,n){"use strict";function a(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var r="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;n.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var n=e.shift();if(n){if("object"!=typeof n)throw new TypeError(n+"must be non-object");for(var r in n)a(n,r)&&(t[r]=n[r])}}return t},n.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var i={arraySet:function(t,e,n,a,r){if(e.subarray&&t.subarray)return void t.set(e.subarray(n,n+a),r);for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){var e,n,a,r,i,s;for(a=0,e=0,n=t.length;e<n;e++)a+=t[e].length;for(s=new Uint8Array(a),r=0,e=0,n=t.length;e<n;e++)i=t[e],s.set(i,r),r+=i.length;return s}},s={arraySet:function(t,e,n,a,r){for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){return[].concat.apply([],t)}};n.setTyped=function(t){t?(n.Buf8=Uint8Array,n.Buf16=Uint16Array,n.Buf32=Int32Array,n.assign(n,i)):(n.Buf8=Array,n.Buf16=Array,n.Buf32=Array,n.assign(n,s))},n.setTyped(r)},{}],6:[function(t,e,n){"use strict";function a(t,e){if(e<65534&&(t.subarray&&s||!t.subarray&&i))return String.fromCharCode.apply(null,r.shrinkBuf(t,e));for(var n="",a=0;a<e;a++)n+=String.fromCharCode(t[a]);return n}var r=t("./common"),i=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){i=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var o=new r.Buf8(256),l=0;l<256;l++)o[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,n.string2buf=function(t){var e,n,a,i,s,o=t.length,l=0;for(i=0;i<o;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),l+=n<128?1:n<2048?2:n<65536?3:4;for(e=new r.Buf8(l),s=0,i=0;s<l;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),n<128?e[s++]=n:n<2048?(e[s++]=192|n>>>6,e[s++]=128|63&n):n<65536?(e[s++]=224|n>>>12,e[s++]=128|n>>>6&63,e[s++]=128|63&n):(e[s++]=240|n>>>18,e[s++]=128|n>>>12&63,e[s++]=128|n>>>6&63,e[s++]=128|63&n);return e},n.buf2binstring=function(t){return a(t,t.length)},n.binstring2buf=function(t){for(var e=new r.Buf8(t.length),n=0,a=e.length;n<a;n++)e[n]=t.charCodeAt(n);return e},n.buf2string=function(t,e){var n,r,i,s,l=e||t.length,h=new Array(2*l);for(r=0,n=0;n<l;)if((i=t[n++])<128)h[r++]=i;else if((s=o[i])>4)h[r++]=65533,n+=s-1;else{for(i&=2===s?31:3===s?15:7;s>1&&n<l;)i=i<<6|63&t[n++],s--;s>1?h[r++]=65533:i<65536?h[r++]=i:(i-=65536,h[r++]=55296|i>>10&1023,h[r++]=56320|1023&i)}return a(h,r)},n.utf8border=function(t,e){var n;for(e=e||t.length,e>t.length&&(e=t.length),n=e-1;n>=0&&128==(192&t[n]);)n--;return n<0?e:0===n?e:n+o[t[n]]>e?n:e}},{"./common":5}],7:[function(t,e,n){"use strict";function a(t,e,n,a){for(var r=65535&t|0,i=t>>>16&65535|0,s=0;0!==n;){s=n>2e3?2e3:n,n-=s;do{r=r+e[a++]|0,i=i+r|0}while(--s);r%=65521,i%=65521}return r|i<<16|0}e.exports=a},{}],8:[function(t,e,n){"use strict";function a(t,e,n,a){var i=r,s=a+n;t^=-1;for(var o=a;o<s;o++)t=t>>>8^i[255&(t^e[o])];return-1^t}var r=function(){for(var t,e=[],n=0;n<256;n++){t=n;for(var a=0;a<8;a++)t=1&t?3988292384^t>>>1:t>>>1;e[n]=t}return e}();e.exports=a},{}],9:[function(t,e,n){"use strict";function a(t,e){return t.msg=D[e],e}function r(t){return(t<<1)-(t>4?9:0)}function i(t){for(var e=t.length;--e>=0;)t[e]=0}function s(t){var e=t.state,n=e.pending;n>t.avail_out&&(n=t.avail_out),0!==n&&(O.arraySet(t.output,e.pending_buf,e.pending_out,n,t.next_out),t.next_out+=n,e.pending_out+=n,t.total_out+=n,t.avail_out-=n,e.pending-=n,0===e.pending&&(e.pending_out=0))}function o(t,e){Z._tr_flush_block(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,s(t.strm)}function l(t,e){t.pending_buf[t.pending++]=e}function h(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function d(t,e,n,a){var r=t.avail_in;return r>a&&(r=a),0===r?0:(t.avail_in-=r,O.arraySet(e,t.input,t.next_in,r,n),1===t.state.wrap?t.adler=N(t.adler,e,r,n):2===t.state.wrap&&(t.adler=R(t.adler,e,r,n)),t.next_in+=r,t.total_in+=r,r)}function f(t,e){var n,a,r=t.max_chain_length,i=t.strstart,s=t.prev_length,o=t.nice_match,l=t.strstart>t.w_size-ht?t.strstart-(t.w_size-ht):0,h=t.window,d=t.w_mask,f=t.prev,u=t.strstart+lt,c=h[i+s-1],_=h[i+s];t.prev_length>=t.good_match&&(r>>=2),o>t.lookahead&&(o=t.lookahead);do{if(n=e,h[n+s]===_&&h[n+s-1]===c&&h[n]===h[i]&&h[++n]===h[i+1]){i+=2,n++;do{}while(h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&h[++i]===h[++n]&&i<u);if(a=lt-(u-i),i=u-lt,a>s){if(t.match_start=e,s=a,a>=o)break;c=h[i+s-1],_=h[i+s]}}}while((e=f[e&d])>l&&0!=--r);return s<=t.lookahead?s:t.lookahead}function u(t){var e,n,a,r,i,s=t.w_size;do{if(r=t.window_size-t.lookahead-t.strstart,t.strstart>=s+(s-ht)){O.arraySet(t.window,t.window,s,s,0),t.match_start-=s,t.strstart-=s,t.block_start-=s,n=t.hash_size,e=n;do{a=t.head[--e],t.head[e]=a>=s?a-s:0}while(--n);n=s,e=n;do{a=t.prev[--e],t.prev[e]=a>=s?a-s:0}while(--n);r+=s}if(0===t.strm.avail_in)break;if(n=d(t.strm,t.window,t.strstart+t.lookahead,r),t.lookahead+=n,t.lookahead+t.insert>=ot)for(i=t.strstart-t.insert,t.ins_h=t.window[i],t.ins_h=(t.ins_h<<t.hash_shift^t.window[i+1])&t.hash_mask;t.insert&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[i+ot-1])&t.hash_mask,t.prev[i&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=i,i++,t.insert--,!(t.lookahead+t.insert<ot)););}while(t.lookahead<ht&&0!==t.strm.avail_in)}function c(t,e){var n=65535;for(n>t.pending_buf_size-5&&(n=t.pending_buf_size-5);;){if(t.lookahead<=1){if(u(t),0===t.lookahead&&e===I)return bt;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var a=t.block_start+n;if((0===t.strstart||t.strstart>=a)&&(t.lookahead=t.strstart-a,t.strstart=a,o(t,!1),0===t.strm.avail_out))return bt;if(t.strstart-t.block_start>=t.w_size-ht&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):(t.strstart>t.block_start&&(o(t,!1),t.strm.avail_out),bt)}function _(t,e){for(var n,a;;){if(t.lookahead<ht){if(u(t),t.lookahead<ht&&e===I)return bt;if(0===t.lookahead)break}if(n=0,t.lookahead>=ot&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==n&&t.strstart-n<=t.w_size-ht&&(t.match_length=f(t,n)),t.match_length>=ot)if(a=Z._tr_tally(t,t.strstart-t.match_start,t.match_length-ot),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=ot){t.match_length--;do{t.strstart++,t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!=--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+1])&t.hash_mask;else a=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(a&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=t.strstart<ot-1?t.strstart:ot-1,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function g(t,e){for(var n,a,r;;){if(t.lookahead<ht){if(u(t),t.lookahead<ht&&e===I)return bt;if(0===t.lookahead)break}if(n=0,t.lookahead>=ot&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=ot-1,0!==n&&t.prev_length<t.max_lazy_match&&t.strstart-n<=t.w_size-ht&&(t.match_length=f(t,n),t.match_length<=5&&(t.strategy===Y||t.match_length===ot&&t.strstart-t.match_start>4096)&&(t.match_length=ot-1)),t.prev_length>=ot&&t.match_length<=t.prev_length){r=t.strstart+t.lookahead-ot,a=Z._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-ot),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=r&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+ot-1])&t.hash_mask,n=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!=--t.prev_length);if(t.match_available=0,t.match_length=ot-1,t.strstart++,a&&(o(t,!1),0===t.strm.avail_out))return bt}else if(t.match_available){if(a=Z._tr_tally(t,0,t.window[t.strstart-1]),a&&o(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return bt}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(a=Z._tr_tally(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<ot-1?t.strstart:ot-1,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function p(t,e){for(var n,a,r,i,s=t.window;;){if(t.lookahead<=lt){if(u(t),t.lookahead<=lt&&e===I)return bt;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=ot&&t.strstart>0&&(r=t.strstart-1,(a=s[r])===s[++r]&&a===s[++r]&&a===s[++r])){i=t.strstart+lt;do{}while(a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&a===s[++r]&&r<i);t.match_length=lt-(i-r),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=ot?(n=Z._tr_tally(t,1,t.match_length-ot),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(n=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),n&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function m(t,e){for(var n;;){if(0===t.lookahead&&(u(t),0===t.lookahead)){if(e===I)return bt;break}if(t.match_length=0,n=Z._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,n&&(o(t,!1),0===t.strm.avail_out))return bt}return t.insert=0,e===j?(o(t,!0),0===t.strm.avail_out?vt:kt):t.last_lit&&(o(t,!1),0===t.strm.avail_out)?bt:wt}function b(t,e,n,a,r){this.good_length=t,this.max_lazy=e,this.nice_length=n,this.max_chain=a,this.func=r}function w(t){t.window_size=2*t.w_size,i(t.head),t.max_lazy_match=E[t.level].max_lazy,t.good_match=E[t.level].good_length,t.nice_match=E[t.level].nice_length,t.max_chain_length=E[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=ot-1,t.match_available=0,t.ins_h=0}function v(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=Q,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new O.Buf16(2*it),this.dyn_dtree=new O.Buf16(2*(2*at+1)),this.bl_tree=new O.Buf16(2*(2*rt+1)),i(this.dyn_ltree),i(this.dyn_dtree),i(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new O.Buf16(st+1),this.heap=new O.Buf16(2*nt+1),i(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new O.Buf16(2*nt+1),i(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function k(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=J,e=t.state,e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?ft:pt,t.adler=2===e.wrap?0:1,e.last_flush=I,Z._tr_init(e),L):a(t,M)}function y(t){var e=k(t);return e===L&&w(t.state),e}function x(t,e){return t&&t.state?2!==t.state.wrap?M:(t.state.gzhead=e,L):M}function z(t,e,n,r,i,s){if(!t)return M;var o=1;if(e===K&&(e=6),r<0?(o=0,r=-r):r>15&&(o=2,r-=16),i<1||i>V||n!==Q||r<8||r>15||e<0||e>9||s<0||s>G)return a(t,M);8===r&&(r=9);var l=new v;return t.state=l,l.strm=t,l.wrap=o,l.gzhead=null,l.w_bits=r,l.w_size=1<<l.w_bits,l.w_mask=l.w_size-1,l.hash_bits=i+7,l.hash_size=1<<l.hash_bits,l.hash_mask=l.hash_size-1,l.hash_shift=~~((l.hash_bits+ot-1)/ot),l.window=new O.Buf8(2*l.w_size),l.head=new O.Buf16(l.hash_size),l.prev=new O.Buf16(l.w_size),l.lit_bufsize=1<<i+6,l.pending_buf_size=4*l.lit_bufsize,l.pending_buf=new O.Buf8(l.pending_buf_size),l.d_buf=1*l.lit_bufsize,l.l_buf=3*l.lit_bufsize,l.level=e,l.strategy=s,l.method=n,y(t)}function B(t,e){return z(t,e,Q,tt,et,X)}function C(t,e){var n,o,d,f;if(!t||!t.state||e>F||e<0)return t?a(t,M):M;if(o=t.state,!t.output||!t.input&&0!==t.avail_in||o.status===mt&&e!==j)return a(t,0===t.avail_out?W:M);if(o.strm=t,n=o.last_flush,o.last_flush=e,o.status===ft)if(2===o.wrap)t.adler=0,l(o,31),l(o,139),l(o,8),o.gzhead?(l(o,(o.gzhead.text?1:0)+(o.gzhead.hcrc?2:0)+(o.gzhead.extra?4:0)+(o.gzhead.name?8:0)+(o.gzhead.comment?16:0)),l(o,255&o.gzhead.time),l(o,o.gzhead.time>>8&255),l(o,o.gzhead.time>>16&255),l(o,o.gzhead.time>>24&255),l(o,9===o.level?2:o.strategy>=$||o.level<2?4:0),l(o,255&o.gzhead.os),o.gzhead.extra&&o.gzhead.extra.length&&(l(o,255&o.gzhead.extra.length),l(o,o.gzhead.extra.length>>8&255)),o.gzhead.hcrc&&(t.adler=R(t.adler,o.pending_buf,o.pending,0)),o.gzindex=0,o.status=ut):(l(o,0),l(o,0),l(o,0),l(o,0),l(o,0),l(o,9===o.level?2:o.strategy>=$||o.level<2?4:0),l(o,yt),o.status=pt);else{var u=Q+(o.w_bits-8<<4)<<8,c=-1;c=o.strategy>=$||o.level<2?0:o.level<6?1:6===o.level?2:3,u|=c<<6,0!==o.strstart&&(u|=dt),u+=31-u%31,o.status=pt,h(o,u),0!==o.strstart&&(h(o,t.adler>>>16),h(o,65535&t.adler)),t.adler=1}if(o.status===ut)if(o.gzhead.extra){for(d=o.pending;o.gzindex<(65535&o.gzhead.extra.length)&&(o.pending!==o.pending_buf_size||(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending!==o.pending_buf_size));)l(o,255&o.gzhead.extra[o.gzindex]),o.gzindex++;o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),o.gzindex===o.gzhead.extra.length&&(o.gzindex=0,o.status=ct)}else o.status=ct;if(o.status===ct)if(o.gzhead.name){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.name.length?255&o.gzhead.name.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.gzindex=0,o.status=_t)}else o.status=_t;if(o.status===_t)if(o.gzhead.comment){d=o.pending;do{if(o.pending===o.pending_buf_size&&(o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),s(t),d=o.pending,o.pending===o.pending_buf_size)){f=1;break}f=o.gzindex<o.gzhead.comment.length?255&o.gzhead.comment.charCodeAt(o.gzindex++):0,l(o,f)}while(0!==f);o.gzhead.hcrc&&o.pending>d&&(t.adler=R(t.adler,o.pending_buf,o.pending-d,d)),0===f&&(o.status=gt)}else o.status=gt;if(o.status===gt&&(o.gzhead.hcrc?(o.pending+2>o.pending_buf_size&&s(t),o.pending+2<=o.pending_buf_size&&(l(o,255&t.adler),l(o,t.adler>>8&255),t.adler=0,o.status=pt)):o.status=pt),0!==o.pending){if(s(t),0===t.avail_out)return o.last_flush=-1,L}else if(0===t.avail_in&&r(e)<=r(n)&&e!==j)return a(t,W);if(o.status===mt&&0!==t.avail_in)return a(t,W);if(0!==t.avail_in||0!==o.lookahead||e!==I&&o.status!==mt){var _=o.strategy===$?m(o,e):o.strategy===q?p(o,e):E[o.level].func(o,e);if(_!==vt&&_!==kt||(o.status=mt),_===bt||_===vt)return 0===t.avail_out&&(o.last_flush=-1),L;if(_===wt&&(e===U?Z._tr_align(o):e!==F&&(Z._tr_stored_block(o,0,0,!1),e===T&&(i(o.head),0===o.lookahead&&(o.strstart=0,o.block_start=0,o.insert=0))),s(t),0===t.avail_out))return o.last_flush=-1,L}return e!==j?L:o.wrap<=0?H:(2===o.wrap?(l(o,255&t.adler),l(o,t.adler>>8&255),l(o,t.adler>>16&255),l(o,t.adler>>24&255),l(o,255&t.total_in),l(o,t.total_in>>8&255),l(o,t.total_in>>16&255),l(o,t.total_in>>24&255)):(h(o,t.adler>>>16),h(o,65535&t.adler)),s(t),o.wrap>0&&(o.wrap=-o.wrap),0!==o.pending?L:H)}function A(t){var e;return t&&t.state?(e=t.state.status)!==ft&&e!==ut&&e!==ct&&e!==_t&&e!==gt&&e!==pt&&e!==mt?a(t,M):(t.state=null,e===pt?a(t,P):L):M}function S(t,e){var n,a,r,s,o,l,h,d,f=e.length;if(!t||!t.state)return M;if(n=t.state,2===(s=n.wrap)||1===s&&n.status!==ft||n.lookahead)return M;for(1===s&&(t.adler=N(t.adler,e,f,0)),n.wrap=0,f>=n.w_size&&(0===s&&(i(n.head),n.strstart=0,n.block_start=0,n.insert=0),d=new O.Buf8(n.w_size),O.arraySet(d,e,f-n.w_size,n.w_size,0),e=d,f=n.w_size),o=t.avail_in,l=t.next_in,h=t.input,t.avail_in=f,t.next_in=0,t.input=e,u(n);n.lookahead>=ot;){a=n.strstart,r=n.lookahead-(ot-1);do{n.ins_h=(n.ins_h<<n.hash_shift^n.window[a+ot-1])&n.hash_mask,n.prev[a&n.w_mask]=n.head[n.ins_h],n.head[n.ins_h]=a,a++}while(--r);n.strstart=a,n.lookahead=ot-1,u(n)}return n.strstart+=n.lookahead,n.block_start=n.strstart,n.insert=n.lookahead,n.lookahead=0,n.match_length=n.prev_length=ot-1,n.match_available=0,t.next_in=l,t.input=h,t.avail_in=o,n.wrap=s,L}var E,O=t("../utils/common"),Z=t("./trees"),N=t("./adler32"),R=t("./crc32"),D=t("./messages"),I=0,U=1,T=3,j=4,F=5,L=0,H=1,M=-2,P=-3,W=-5,K=-1,Y=1,$=2,q=3,G=4,X=0,J=2,Q=8,V=9,tt=15,et=8,nt=286,at=30,rt=19,it=2*nt+1,st=15,ot=3,lt=258,ht=lt+ot+1,dt=32,ft=42,ut=69,ct=73,_t=91,gt=103,pt=113,mt=666,bt=1,wt=2,vt=3,kt=4,yt=3;E=[new b(0,0,0,0,c),new b(4,4,8,4,_),new b(4,5,16,8,_),new b(4,6,32,32,_),new b(4,4,16,16,g),new b(8,16,32,32,g),new b(8,16,128,128,g),new b(8,32,128,256,g),new b(32,128,258,1024,g),new b(32,258,258,4096,g)],n.deflateInit=B,n.deflateInit2=z,n.deflateReset=y,n.deflateResetKeep=k,n.deflateSetHeader=x,n.deflate=C,n.deflateEnd=A,n.deflateSetDictionary=S,n.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":5,"./adler32":7,"./crc32":8,"./messages":10,"./trees":11}],10:[function(t,e,n){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],11:[function(t,e,n){"use strict";function a(t){for(var e=t.length;--e>=0;)t[e]=0}function r(t,e,n,a,r){this.static_tree=t,this.extra_bits=e,this.extra_base=n,this.elems=a,this.max_length=r,this.has_stree=t&&t.length}function i(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function s(t){return t<256?it[t]:it[256+(t>>>7)]}function o(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function l(t,e,n){t.bi_valid>$-n?(t.bi_buf|=e<<t.bi_valid&65535,o(t,t.bi_buf),t.bi_buf=e>>$-t.bi_valid,t.bi_valid+=n-$):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=n)}function h(t,e,n){l(t,n[2*e],n[2*e+1])}function d(t,e){var n=0;do{n|=1&t,t>>>=1,n<<=1}while(--e>0);return n>>>1}function f(t){16===t.bi_valid?(o(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}function u(t,e){var n,a,r,i,s,o,l=e.dyn_tree,h=e.max_code,d=e.stat_desc.static_tree,f=e.stat_desc.has_stree,u=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,_=e.stat_desc.max_length,g=0;for(i=0;i<=Y;i++)t.bl_count[i]=0;for(l[2*t.heap[t.heap_max]+1]=0,n=t.heap_max+1;n<K;n++)a=t.heap[n],i=l[2*l[2*a+1]+1]+1,i>_&&(i=_,g++),l[2*a+1]=i,a>h||(t.bl_count[i]++,s=0,a>=c&&(s=u[a-c]),o=l[2*a],t.opt_len+=o*(i+s),f&&(t.static_len+=o*(d[2*a+1]+s)));if(0!==g){do{for(i=_-1;0===t.bl_count[i];)i--;t.bl_count[i]--,t.bl_count[i+1]+=2,t.bl_count[_]--,g-=2}while(g>0);for(i=_;0!==i;i--)for(a=t.bl_count[i];0!==a;)(r=t.heap[--n])>h||(l[2*r+1]!==i&&(t.opt_len+=(i-l[2*r+1])*l[2*r],l[2*r+1]=i),a--)}}function c(t,e,n){var a,r,i=new Array(Y+1),s=0;for(a=1;a<=Y;a++)i[a]=s=s+n[a-1]<<1;for(r=0;r<=e;r++){var o=t[2*r+1];0!==o&&(t[2*r]=d(i[o]++,o))}}function _(){var t,e,n,a,i,s=new Array(Y+1);for(n=0,a=0;a<L-1;a++)for(ot[a]=n,t=0;t<1<<V[a];t++)st[n++]=a;for(st[n-1]=a,i=0,a=0;a<16;a++)for(lt[a]=i,t=0;t<1<<tt[a];t++)it[i++]=a;for(i>>=7;a<P;a++)for(lt[a]=i<<7,t=0;t<1<<tt[a]-7;t++)it[256+i++]=a;for(e=0;e<=Y;e++)s[e]=0;for(t=0;t<=143;)at[2*t+1]=8,t++,s[8]++;for(;t<=255;)at[2*t+1]=9,t++,s[9]++;for(;t<=279;)at[2*t+1]=7,t++,s[7]++;for(;t<=287;)at[2*t+1]=8,t++,s[8]++;for(c(at,M+1,s),t=0;t<P;t++)rt[2*t+1]=5,rt[2*t]=d(t,5);ht=new r(at,V,H+1,M,Y),dt=new r(rt,tt,0,P,Y),ft=new r(new Array(0),et,0,W,q)}function g(t){var e;for(e=0;e<M;e++)t.dyn_ltree[2*e]=0;for(e=0;e<P;e++)t.dyn_dtree[2*e]=0;for(e=0;e<W;e++)t.bl_tree[2*e]=0;t.dyn_ltree[2*G]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function p(t){t.bi_valid>8?o(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function m(t,e,n,a){p(t),a&&(o(t,n),o(t,~n)),N.arraySet(t.pending_buf,t.window,e,n,t.pending),t.pending+=n}function b(t,e,n,a){var r=2*e,i=2*n;return t[r]<t[i]||t[r]===t[i]&&a[e]<=a[n]}function w(t,e,n){for(var a=t.heap[n],r=n<<1;r<=t.heap_len&&(r<t.heap_len&&b(e,t.heap[r+1],t.heap[r],t.depth)&&r++,!b(e,a,t.heap[r],t.depth));)t.heap[n]=t.heap[r],n=r,r<<=1;t.heap[n]=a}function v(t,e,n){var a,r,i,o,d=0;if(0!==t.last_lit)do{a=t.pending_buf[t.d_buf+2*d]<<8|t.pending_buf[t.d_buf+2*d+1],r=t.pending_buf[t.l_buf+d],d++,0===a?h(t,r,e):(i=st[r],h(t,i+H+1,e),o=V[i],0!==o&&(r-=ot[i],l(t,r,o)),a--,i=s(a),h(t,i,n),0!==(o=tt[i])&&(a-=lt[i],l(t,a,o)))}while(d<t.last_lit);h(t,G,e)}function k(t,e){var n,a,r,i=e.dyn_tree,s=e.stat_desc.static_tree,o=e.stat_desc.has_stree,l=e.stat_desc.elems,h=-1;for(t.heap_len=0,t.heap_max=K,n=0;n<l;n++)0!==i[2*n]?(t.heap[++t.heap_len]=h=n,t.depth[n]=0):i[2*n+1]=0;for(;t.heap_len<2;)r=t.heap[++t.heap_len]=h<2?++h:0,i[2*r]=1,t.depth[r]=0,t.opt_len--,o&&(t.static_len-=s[2*r+1]);for(e.max_code=h,n=t.heap_len>>1;n>=1;n--)w(t,i,n);r=l;do{n=t.heap[1],t.heap[1]=t.heap[t.heap_len--],w(t,i,1),a=t.heap[1],t.heap[--t.heap_max]=n,t.heap[--t.heap_max]=a,i[2*r]=i[2*n]+i[2*a],t.depth[r]=(t.depth[n]>=t.depth[a]?t.depth[n]:t.depth[a])+1,i[2*n+1]=i[2*a+1]=r,t.heap[1]=r++,w(t,i,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],u(t,e),c(i,h,t.bl_count)}function y(t,e,n){var a,r,i=-1,s=e[1],o=0,l=7,h=4;for(0===s&&(l=138,h=3),e[2*(n+1)+1]=65535,a=0;a<=n;a++)r=s,s=e[2*(a+1)+1],++o<l&&r===s||(o<h?t.bl_tree[2*r]+=o:0!==r?(r!==i&&t.bl_tree[2*r]++,t.bl_tree[2*X]++):o<=10?t.bl_tree[2*J]++:t.bl_tree[2*Q]++,o=0,i=r,0===s?(l=138,h=3):r===s?(l=6,h=3):(l=7,h=4))}function x(t,e,n){var a,r,i=-1,s=e[1],o=0,d=7,f=4;for(0===s&&(d=138,f=3),a=0;a<=n;a++)if(r=s,s=e[2*(a+1)+1],!(++o<d&&r===s)){if(o<f)do{h(t,r,t.bl_tree)}while(0!=--o);else 0!==r?(r!==i&&(h(t,r,t.bl_tree),o--),h(t,X,t.bl_tree),l(t,o-3,2)):o<=10?(h(t,J,t.bl_tree),l(t,o-3,3)):(h(t,Q,t.bl_tree),l(t,o-11,7));o=0,i=r,0===s?(d=138,f=3):r===s?(d=6,f=3):(d=7,f=4)}}function z(t){var e;for(y(t,t.dyn_ltree,t.l_desc.max_code),y(t,t.dyn_dtree,t.d_desc.max_code),k(t,t.bl_desc),e=W-1;e>=3&&0===t.bl_tree[2*nt[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}function B(t,e,n,a){var r;for(l(t,e-257,5),l(t,n-1,5),l(t,a-4,4),r=0;r<a;r++)l(t,t.bl_tree[2*nt[r]+1],3);x(t,t.dyn_ltree,e-1),x(t,t.dyn_dtree,n-1)}function C(t){var e,n=4093624447;for(e=0;e<=31;e++,n>>>=1)if(1&n&&0!==t.dyn_ltree[2*e])return D;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return I;for(e=32;e<H;e++)if(0!==t.dyn_ltree[2*e])return I;return D}function A(t){ut||(_(),ut=!0),t.l_desc=new i(t.dyn_ltree,ht),t.d_desc=new i(t.dyn_dtree,dt),t.bl_desc=new i(t.bl_tree,ft),t.bi_buf=0,t.bi_valid=0,g(t)}function S(t,e,n,a){l(t,(T<<1)+(a?1:0),3),m(t,e,n,!0)}function E(t){l(t,j<<1,3),h(t,G,at),f(t)}function O(t,e,n,a){var r,i,s=0;t.level>0?(t.strm.data_type===U&&(t.strm.data_type=C(t)),k(t,t.l_desc),k(t,t.d_desc),s=z(t),r=t.opt_len+3+7>>>3,(i=t.static_len+3+7>>>3)<=r&&(r=i)):r=i=n+5,n+4<=r&&-1!==e?S(t,e,n,a):t.strategy===R||i===r?(l(t,(j<<1)+(a?1:0),3),v(t,at,rt)):(l(t,(F<<1)+(a?1:0),3),B(t,t.l_desc.max_code+1,t.d_desc.max_code+1,s+1),v(t,t.dyn_ltree,t.dyn_dtree)),g(t),a&&p(t)}function Z(t,e,n){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&n,t.last_lit++,0===e?t.dyn_ltree[2*n]++:(t.matches++,e--,t.dyn_ltree[2*(st[n]+H+1)]++,t.dyn_dtree[2*s(e)]++),t.last_lit===t.lit_bufsize-1}var N=t("../utils/common"),R=4,D=0,I=1,U=2,T=0,j=1,F=2,L=29,H=256,M=H+1+L,P=30,W=19,K=2*M+1,Y=15,$=16,q=7,G=256,X=16,J=17,Q=18,V=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],tt=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],et=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],nt=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],at=new Array(2*(M+2));a(at);var rt=new Array(2*P);a(rt);var it=new Array(512);a(it);var st=new Array(256);a(st);var ot=new Array(L);a(ot);var lt=new Array(P);a(lt);var ht,dt,ft,ut=!1;n._tr_init=A,n._tr_stored_block=S,n._tr_flush_block=O,n._tr_tally=Z,n._tr_align=E},{"../utils/common":5}],12:[function(t,e,n){"use strict";function a(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=a},{}]},{},[3])(3)})},function(t,e,n){var a,a;!function(e){t.exports=e()}(function(){return function(){function t(e,n,r){function i(o,l){if(!n[o]){if(!e[o]){var h="function"==typeof a&&a;if(!l&&h)return a(o,!0);if(s)return s(o,!0);var d=new Error("Cannot find module '"+o+"'");throw d.code="MODULE_NOT_FOUND",d}var f=n[o]={exports:{}};e[o][0].call(f.exports,function(t){return i(e[o][1][t]||t)},f,f.exports,t,e,n,r)}return n[o].exports}for(var s="function"==typeof a&&a,o=0;o<r.length;o++)i(r[o]);return i}return t}()({1:[function(t,e,n){"use strict";var a=t("pako/lib/inflate.js");e.exports=function(t){return a.inflateRaw(t,{to:"string"})}},{"pako/lib/inflate.js":4}],2:[function(t,e,n){"use strict";function a(t){var e=t.charCodeAt(0);return"_"===t?63:"-"===t?62:e>=97?e-61:e>=65?e-55:e>=48?e-48:"?"}function r(t){var e=a(t[0]),n=a(t[1]),r=a(t[2]);return[e<<2|n>>4&63,n<<4&240|r>>2&15,r<<6&192|63&a(t[3])]}e.exports=function(t){var e="",n=0;for(n=0;n<t.length;n+=4){var a=r(t.substring(n,n+4));e+=String.fromCharCode(a[0]),e+=String.fromCharCode(a[1]),e+=String.fromCharCode(a[2])}return e}},{}],3:[function(t,e,n){"use strict";var a=t("./inflate"),r=t("./decode64");e.exports.decode=function(t){var e=r(t);return a(e)}},{"./decode64":2,"./inflate":1}],4:[function(t,e,n){"use strict";function a(t){if(!(this instanceof a))return new a(t);this.options=o.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new f,this.strm.avail_out=0;var n=s.inflateInit2(this.strm,e.windowBits);if(n!==h.Z_OK)throw new Error(d[n]);if(this.header=new u,s.inflateGetHeader(this.strm,this.header),e.dictionary&&("string"==typeof e.dictionary?e.dictionary=l.string2buf(e.dictionary):"[object ArrayBuffer]"===c.call(e.dictionary)&&(e.dictionary=new Uint8Array(e.dictionary)),e.raw&&(n=s.inflateSetDictionary(this.strm,e.dictionary))!==h.Z_OK))throw new Error(d[n])}function r(t,e){var n=new a(e);if(n.push(t,!0),n.err)throw n.msg||d[n.err];return n.result}function i(t,e){return e=e||{},e.raw=!0,r(t,e)}var s=t("./zlib/inflate"),o=t("./utils/common"),l=t("./utils/strings"),h=t("./zlib/constants"),d=t("./zlib/messages"),f=t("./zlib/zstream"),u=t("./zlib/gzheader"),c=Object.prototype.toString;a.prototype.push=function(t,e){var n,a,r,i,d,f=this.strm,u=this.options.chunkSize,_=this.options.dictionary,g=!1;if(this.ended)return!1;a=e===~~e?e:!0===e?h.Z_FINISH:h.Z_NO_FLUSH,"string"==typeof t?f.input=l.binstring2buf(t):"[object ArrayBuffer]"===c.call(t)?f.input=new Uint8Array(t):f.input=t,f.next_in=0,f.avail_in=f.input.length;do{if(0===f.avail_out&&(f.output=new o.Buf8(u),f.next_out=0,f.avail_out=u),n=s.inflate(f,h.Z_NO_FLUSH),n===h.Z_NEED_DICT&&_&&(n=s.inflateSetDictionary(this.strm,_)),n===h.Z_BUF_ERROR&&!0===g&&(n=h.Z_OK,g=!1),n!==h.Z_STREAM_END&&n!==h.Z_OK)return this.onEnd(n),this.ended=!0,!1;f.next_out&&(0!==f.avail_out&&n!==h.Z_STREAM_END&&(0!==f.avail_in||a!==h.Z_FINISH&&a!==h.Z_SYNC_FLUSH)||("string"===this.options.to?(r=l.utf8border(f.output,f.next_out),i=f.next_out-r,d=l.buf2string(f.output,r),f.next_out=i,f.avail_out=u-i,i&&o.arraySet(f.output,f.output,r,i,0),this.onData(d)):this.onData(o.shrinkBuf(f.output,f.next_out)))),0===f.avail_in&&0===f.avail_out&&(g=!0)}while((f.avail_in>0||0===f.avail_out)&&n!==h.Z_STREAM_END);return n===h.Z_STREAM_END&&(a=h.Z_FINISH),a===h.Z_FINISH?(n=s.inflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===h.Z_OK):a!==h.Z_SYNC_FLUSH||(this.onEnd(h.Z_OK),f.avail_out=0,!0)},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===h.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},n.Inflate=a,n.inflate=r,n.inflateRaw=i,n.ungzip=r},{"./utils/common":5,"./utils/strings":6,"./zlib/constants":8,"./zlib/gzheader":10,"./zlib/inflate":12,"./zlib/messages":14,"./zlib/zstream":15}],5:[function(t,e,n){"use strict";function a(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var r="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;n.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var n=e.shift();if(n){if("object"!=typeof n)throw new TypeError(n+"must be non-object");for(var r in n)a(n,r)&&(t[r]=n[r])}}return t},n.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var i={arraySet:function(t,e,n,a,r){if(e.subarray&&t.subarray)return void t.set(e.subarray(n,n+a),r);for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){var e,n,a,r,i,s;for(a=0,e=0,n=t.length;e<n;e++)a+=t[e].length;for(s=new Uint8Array(a),r=0,e=0,n=t.length;e<n;e++)i=t[e],s.set(i,r),r+=i.length;return s}},s={arraySet:function(t,e,n,a,r){for(var i=0;i<a;i++)t[r+i]=e[n+i]},flattenChunks:function(t){return[].concat.apply([],t)}};n.setTyped=function(t){t?(n.Buf8=Uint8Array,n.Buf16=Uint16Array,n.Buf32=Int32Array,n.assign(n,i)):(n.Buf8=Array,n.Buf16=Array,n.Buf32=Array,n.assign(n,s))},n.setTyped(r)},{}],6:[function(t,e,n){"use strict";function a(t,e){if(e<65534&&(t.subarray&&s||!t.subarray&&i))return String.fromCharCode.apply(null,r.shrinkBuf(t,e));for(var n="",a=0;a<e;a++)n+=String.fromCharCode(t[a]);return n}var r=t("./common"),i=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){i=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var o=new r.Buf8(256),l=0;l<256;l++)o[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;o[254]=o[254]=1,n.string2buf=function(t){var e,n,a,i,s,o=t.length,l=0;for(i=0;i<o;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),l+=n<128?1:n<2048?2:n<65536?3:4;for(e=new r.Buf8(l),s=0,i=0;s<l;i++)n=t.charCodeAt(i),55296==(64512&n)&&i+1<o&&56320==(64512&(a=t.charCodeAt(i+1)))&&(n=65536+(n-55296<<10)+(a-56320),i++),n<128?e[s++]=n:n<2048?(e[s++]=192|n>>>6,e[s++]=128|63&n):n<65536?(e[s++]=224|n>>>12,e[s++]=128|n>>>6&63,e[s++]=128|63&n):(e[s++]=240|n>>>18,e[s++]=128|n>>>12&63,e[s++]=128|n>>>6&63,e[s++]=128|63&n);return e},n.buf2binstring=function(t){return a(t,t.length)},n.binstring2buf=function(t){for(var e=new r.Buf8(t.length),n=0,a=e.length;n<a;n++)e[n]=t.charCodeAt(n);return e},n.buf2string=function(t,e){var n,r,i,s,l=e||t.length,h=new Array(2*l);for(r=0,n=0;n<l;)if((i=t[n++])<128)h[r++]=i;else if((s=o[i])>4)h[r++]=65533,n+=s-1;else{for(i&=2===s?31:3===s?15:7;s>1&&n<l;)i=i<<6|63&t[n++],s--;s>1?h[r++]=65533:i<65536?h[r++]=i:(i-=65536,h[r++]=55296|i>>10&1023,h[r++]=56320|1023&i)}return a(h,r)},n.utf8border=function(t,e){var n;for(e=e||t.length,e>t.length&&(e=t.length),n=e-1;n>=0&&128==(192&t[n]);)n--;return n<0?e:0===n?e:n+o[t[n]]>e?n:e}},{"./common":5}],7:[function(t,e,n){"use strict";function a(t,e,n,a){for(var r=65535&t|0,i=t>>>16&65535|0,s=0;0!==n;){s=n>2e3?2e3:n,n-=s;do{r=r+e[a++]|0,i=i+r|0}while(--s);r%=65521,i%=65521}return r|i<<16|0}e.exports=a},{}],8:[function(t,e,n){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],9:[function(t,e,n){"use strict";function a(t,e,n,a){var i=r,s=a+n;t^=-1;for(var o=a;o<s;o++)t=t>>>8^i[255&(t^e[o])];return-1^t}var r=function(){for(var t,e=[],n=0;n<256;n++){t=n;for(var a=0;a<8;a++)t=1&t?3988292384^t>>>1:t>>>1;e[n]=t}return e}();e.exports=a},{}],10:[function(t,e,n){"use strict";function a(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}e.exports=a},{}],11:[function(t,e,n){"use strict";e.exports=function(t,e){var n,a,r,i,s,o,l,h,d,f,u,c,_,g,p,m,b,w,v,k,y,x,z,B,C;n=t.state,a=t.next_in,B=t.input,r=a+(t.avail_in-5),i=t.next_out,C=t.output,s=i-(e-t.avail_out),o=i+(t.avail_out-257),l=n.dmax,h=n.wsize,d=n.whave,f=n.wnext,u=n.window,c=n.hold,_=n.bits,g=n.lencode,p=n.distcode,m=(1<<n.lenbits)-1,b=(1<<n.distbits)-1;t:do{_<15&&(c+=B[a++]<<_,_+=8,c+=B[a++]<<_,_+=8),w=g[c&m];e:for(;;){if(v=w>>>24,c>>>=v,_-=v,0===(v=w>>>16&255))C[i++]=65535&w;else{if(!(16&v)){if(0==(64&v)){w=g[(65535&w)+(c&(1<<v)-1)];continue e}if(32&v){n.mode=12;break t}t.msg="invalid literal/length code",n.mode=30;break t}k=65535&w,v&=15,v&&(_<v&&(c+=B[a++]<<_,_+=8),k+=c&(1<<v)-1,c>>>=v,_-=v),_<15&&(c+=B[a++]<<_,_+=8,c+=B[a++]<<_,_+=8),w=p[c&b];n:for(;;){if(v=w>>>24,c>>>=v,_-=v,!(16&(v=w>>>16&255))){if(0==(64&v)){w=p[(65535&w)+(c&(1<<v)-1)];continue n}t.msg="invalid distance code",n.mode=30;break t}if(y=65535&w,v&=15,_<v&&(c+=B[a++]<<_,(_+=8)<v&&(c+=B[a++]<<_,_+=8)),(y+=c&(1<<v)-1)>l){t.msg="invalid distance too far back",n.mode=30;break t}if(c>>>=v,_-=v,v=i-s,y>v){if((v=y-v)>d&&n.sane){t.msg="invalid distance too far back",n.mode=30;break t}if(x=0,z=u,0===f){if(x+=h-v,v<k){k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}}else if(f<v){if(x+=h+f-v,(v-=f)<k){k-=v;do{C[i++]=u[x++]}while(--v);if(x=0,f<k){v=f,k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}}}else if(x+=f-v,v<k){k-=v;do{C[i++]=u[x++]}while(--v);x=i-y,z=C}for(;k>2;)C[i++]=z[x++],C[i++]=z[x++],C[i++]=z[x++],k-=3;k&&(C[i++]=z[x++],k>1&&(C[i++]=z[x++]))}else{x=i-y;do{C[i++]=C[x++],C[i++]=C[x++],C[i++]=C[x++],k-=3}while(k>2);k&&(C[i++]=C[x++],k>1&&(C[i++]=C[x++]))}break}}break}}while(a<r&&i<o);k=_>>3,a-=k,_-=k<<3,c&=(1<<_)-1,t.next_in=a,t.next_out=i,t.avail_in=a<r?r-a+5:5-(a-r),t.avail_out=i<o?o-i+257:257-(i-o),n.hold=c,n.bits=_}},{}],12:[function(t,e,n){"use strict";function a(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function r(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new b.Buf16(320),this.work=new b.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function i(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=T,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new b.Buf32(gt),e.distcode=e.distdyn=new b.Buf32(pt),e.sane=1,e.back=-1,E):N}function s(t){var e;return t&&t.state?(e=t.state,e.wsize=0,e.whave=0,e.wnext=0,i(t)):N}function o(t,e){var n,a;return t&&t.state?(a=t.state,e<0?(n=0,e=-e):(n=1+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?N:(null!==a.window&&a.wbits!==e&&(a.window=null),a.wrap=n,a.wbits=e,s(t))):N}function l(t,e){var n,a;return t?(a=new r,t.state=a,a.window=null,n=o(t,e),n!==E&&(t.state=null),n):N}function h(t){return l(t,mt)}function d(t){if(bt){var e;for(p=new b.Buf32(512),m=new b.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(y(z,t.lens,0,288,p,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;y(B,t.lens,0,32,m,0,t.work,{bits:5}),bt=!1}t.lencode=p,t.lenbits=9,t.distcode=m,t.distbits=5}function f(t,e,n,a){var r,i=t.state;return null===i.window&&(i.wsize=1<<i.wbits,i.wnext=0,i.whave=0,i.window=new b.Buf8(i.wsize)),a>=i.wsize?(b.arraySet(i.window,e,n-i.wsize,i.wsize,0),i.wnext=0,i.whave=i.wsize):(r=i.wsize-i.wnext,r>a&&(r=a),b.arraySet(i.window,e,n-a,r,i.wnext),a-=r,a?(b.arraySet(i.window,e,n-a,a,0),i.wnext=a,i.whave=i.wsize):(i.wnext+=r,i.wnext===i.wsize&&(i.wnext=0),i.whave<i.wsize&&(i.whave+=r))),0}function u(t,e){var n,r,i,s,o,l,h,u,c,_,g,p,m,gt,pt,mt,bt,wt,vt,kt,yt,xt,zt,Bt,Ct=0,At=new b.Buf8(4),St=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return N;n=t.state,n.mode===q&&(n.mode=G),o=t.next_out,i=t.output,h=t.avail_out,s=t.next_in,r=t.input,l=t.avail_in,u=n.hold,c=n.bits,_=l,g=h,xt=E;t:for(;;)switch(n.mode){case T:if(0===n.wrap){n.mode=G;break}for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(2&n.wrap&&35615===u){n.check=0,At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0),u=0,c=0,n.mode=j;break}if(n.flags=0,n.head&&(n.head.done=!1),!(1&n.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",n.mode=ut;break}if((15&u)!==U){t.msg="unknown compression method",n.mode=ut;break}if(u>>>=4,c-=4,yt=8+(15&u),0===n.wbits)n.wbits=yt;else if(yt>n.wbits){t.msg="invalid window size",n.mode=ut;break}n.dmax=1<<yt,t.adler=n.check=1,n.mode=512&u?Y:q,u=0,c=0;break;case j:for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(n.flags=u,(255&n.flags)!==U){t.msg="unknown compression method",n.mode=ut;break}if(57344&n.flags){t.msg="unknown header flags set",n.mode=ut;break}n.head&&(n.head.text=u>>8&1),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0,n.mode=F;case F:for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.head&&(n.head.time=u),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,At[2]=u>>>16&255,At[3]=u>>>24&255,n.check=v(n.check,At,4,0)),u=0,c=0,n.mode=L;case L:for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.head&&(n.head.xflags=255&u,n.head.os=u>>8),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0,n.mode=H;case H:if(1024&n.flags){for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.length=u,n.head&&(n.head.extra_len=u),512&n.flags&&(At[0]=255&u,At[1]=u>>>8&255,n.check=v(n.check,At,2,0)),u=0,c=0}else n.head&&(n.head.extra=null);n.mode=M;case M:if(1024&n.flags&&(p=n.length,p>l&&(p=l),p&&(n.head&&(yt=n.head.extra_len-n.length,n.head.extra||(n.head.extra=new Array(n.head.extra_len)),b.arraySet(n.head.extra,r,s,p,yt)),512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,n.length-=p),n.length))break t;n.length=0,n.mode=P;case P:if(2048&n.flags){if(0===l)break t;p=0;do{yt=r[s+p++],n.head&&yt&&n.length<65536&&(n.head.name+=String.fromCharCode(yt))}while(yt&&p<l);if(512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,yt)break t}else n.head&&(n.head.name=null);n.length=0,n.mode=W;case W:if(4096&n.flags){if(0===l)break t;p=0;do{yt=r[s+p++],n.head&&yt&&n.length<65536&&(n.head.comment+=String.fromCharCode(yt))}while(yt&&p<l);if(512&n.flags&&(n.check=v(n.check,r,p,s)),l-=p,s+=p,yt)break t}else n.head&&(n.head.comment=null);n.mode=K;case K:if(512&n.flags){for(;c<16;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u!==(65535&n.check)){t.msg="header crc mismatch",n.mode=ut;break}u=0,c=0}n.head&&(n.head.hcrc=n.flags>>9&1,n.head.done=!0),t.adler=n.check=0,n.mode=q;break;case Y:for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}t.adler=n.check=a(u),u=0,c=0,n.mode=$;case $:if(0===n.havedict)return t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,Z;t.adler=n.check=1,n.mode=q;case q:if(e===A||e===S)break t;case G:if(n.last){u>>>=7&c,c-=7&c,n.mode=ht;break}for(;c<3;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}switch(n.last=1&u,u>>>=1,c-=1,3&u){case 0:n.mode=X;break;case 1:if(d(n),n.mode=nt,e===S){u>>>=2,c-=2;break t}break;case 2:n.mode=V;break;case 3:t.msg="invalid block type",n.mode=ut}u>>>=2,c-=2;break;case X:for(u>>>=7&c,c-=7&c;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if((65535&u)!=(u>>>16^65535)){t.msg="invalid stored block lengths",n.mode=ut;break}if(n.length=65535&u,u=0,c=0,n.mode=J,e===S)break t;case J:n.mode=Q;case Q:if(p=n.length){if(p>l&&(p=l),p>h&&(p=h),0===p)break t;b.arraySet(i,r,s,p,o),l-=p,s+=p,h-=p,o+=p,n.length-=p;break}n.mode=q;break;case V:for(;c<14;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(n.nlen=257+(31&u),u>>>=5,c-=5,n.ndist=1+(31&u),u>>>=5,c-=5,n.ncode=4+(15&u),u>>>=4,c-=4,n.nlen>286||n.ndist>30){t.msg="too many length or distance symbols",n.mode=ut;break}n.have=0,n.mode=tt;case tt:for(;n.have<n.ncode;){for(;c<3;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.lens[St[n.have++]]=7&u,u>>>=3,c-=3}for(;n.have<19;)n.lens[St[n.have++]]=0;if(n.lencode=n.lendyn,n.lenbits=7,zt={bits:n.lenbits},xt=y(x,n.lens,0,19,n.lencode,0,n.work,zt),n.lenbits=zt.bits,xt){t.msg="invalid code lengths set",n.mode=ut;break}n.have=0,n.mode=et;case et:for(;n.have<n.nlen+n.ndist;){for(;Ct=n.lencode[u&(1<<n.lenbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(bt<16)u>>>=pt,c-=pt,n.lens[n.have++]=bt;else{if(16===bt){for(Bt=pt+2;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u>>>=pt,c-=pt,0===n.have){t.msg="invalid bit length repeat",n.mode=ut;break}yt=n.lens[n.have-1],p=3+(3&u),u>>>=2,c-=2}else if(17===bt){for(Bt=pt+3;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=pt,c-=pt,yt=0,p=3+(7&u),u>>>=3,c-=3}else{for(Bt=pt+7;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=pt,c-=pt,yt=0,p=11+(127&u),u>>>=7,c-=7}if(n.have+p>n.nlen+n.ndist){t.msg="invalid bit length repeat",n.mode=ut;break}for(;p--;)n.lens[n.have++]=yt}}if(n.mode===ut)break;if(0===n.lens[256]){t.msg="invalid code -- missing end-of-block",n.mode=ut;break}if(n.lenbits=9,zt={bits:n.lenbits},xt=y(z,n.lens,0,n.nlen,n.lencode,0,n.work,zt),n.lenbits=zt.bits,xt){t.msg="invalid literal/lengths set",n.mode=ut;break}if(n.distbits=6,n.distcode=n.distdyn,zt={bits:n.distbits},xt=y(B,n.lens,n.nlen,n.ndist,n.distcode,0,n.work,zt),n.distbits=zt.bits,xt){t.msg="invalid distances set",n.mode=ut;break}if(n.mode=nt,e===S)break t;case nt:n.mode=at;case at:if(l>=6&&h>=258){t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,k(t,g),o=t.next_out,i=t.output,h=t.avail_out,s=t.next_in,r=t.input,l=t.avail_in,u=n.hold,c=n.bits,n.mode===q&&(n.back=-1);break}for(n.back=0;Ct=n.lencode[u&(1<<n.lenbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(mt&&0==(240&mt)){for(wt=pt,vt=mt,kt=bt;Ct=n.lencode[kt+((u&(1<<wt+vt)-1)>>wt)],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(wt+pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=wt,c-=wt,n.back+=wt}if(u>>>=pt,c-=pt,n.back+=pt,n.length=bt,0===mt){n.mode=lt;break}if(32&mt){n.back=-1,n.mode=q;break}if(64&mt){t.msg="invalid literal/length code",n.mode=ut;break}n.extra=15&mt,n.mode=rt;case rt:if(n.extra){for(Bt=n.extra;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.length+=u&(1<<n.extra)-1,u>>>=n.extra,c-=n.extra,n.back+=n.extra}n.was=n.length,n.mode=it;case it:for(;Ct=n.distcode[u&(1<<n.distbits)-1],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(0==(240&mt)){for(wt=pt,vt=mt,kt=bt;Ct=n.distcode[kt+((u&(1<<wt+vt)-1)>>wt)],pt=Ct>>>24,mt=Ct>>>16&255,bt=65535&Ct,!(wt+pt<=c);){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}u>>>=wt,c-=wt,n.back+=wt}if(u>>>=pt,c-=pt,n.back+=pt,64&mt){t.msg="invalid distance code",n.mode=ut;break}n.offset=bt,n.extra=15&mt,n.mode=st;case st:if(n.extra){for(Bt=n.extra;c<Bt;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}n.offset+=u&(1<<n.extra)-1,u>>>=n.extra,c-=n.extra,n.back+=n.extra}if(n.offset>n.dmax){t.msg="invalid distance too far back",n.mode=ut;break}n.mode=ot;case ot:if(0===h)break t;if(p=g-h,n.offset>p){if((p=n.offset-p)>n.whave&&n.sane){t.msg="invalid distance too far back",n.mode=ut;break}p>n.wnext?(p-=n.wnext,m=n.wsize-p):m=n.wnext-p,p>n.length&&(p=n.length),gt=n.window}else gt=i,m=o-n.offset,p=n.length;p>h&&(p=h),h-=p,n.length-=p;do{i[o++]=gt[m++]}while(--p);0===n.length&&(n.mode=at);break;case lt:if(0===h)break t;i[o++]=n.length,h--,n.mode=at;break;case ht:if(n.wrap){for(;c<32;){if(0===l)break t;l--,u|=r[s++]<<c,c+=8}if(g-=h,t.total_out+=g,n.total+=g,g&&(t.adler=n.check=n.flags?v(n.check,i,g,o-g):w(n.check,i,g,o-g)),g=h,(n.flags?u:a(u))!==n.check){t.msg="incorrect data check",n.mode=ut;break}u=0,c=0}n.mode=dt;case dt:if(n.wrap&&n.flags){for(;c<32;){if(0===l)break t;l--,u+=r[s++]<<c,c+=8}if(u!==(4294967295&n.total)){t.msg="incorrect length check",n.mode=ut;break}u=0,c=0}n.mode=ft;case ft:xt=O;break t;case ut:xt=R;break t;case ct:return D;case _t:default:return N}return t.next_out=o,t.avail_out=h,t.next_in=s,t.avail_in=l,n.hold=u,n.bits=c,(n.wsize||g!==t.avail_out&&n.mode<ut&&(n.mode<ht||e!==C))&&f(t,t.output,t.next_out,g-t.avail_out)?(n.mode=ct,D):(_-=t.avail_in,g-=t.avail_out,t.total_in+=_,t.total_out+=g,n.total+=g,n.wrap&&g&&(t.adler=n.check=n.flags?v(n.check,i,g,t.next_out-g):w(n.check,i,g,t.next_out-g)),t.data_type=n.bits+(n.last?64:0)+(n.mode===q?128:0)+(n.mode===nt||n.mode===J?256:0),(0===_&&0===g||e===C)&&xt===E&&(xt=I),xt)}function c(t){if(!t||!t.state)return N;var e=t.state;return e.window&&(e.window=null),t.state=null,E}function _(t,e){var n;return t&&t.state?(n=t.state,0==(2&n.wrap)?N:(n.head=e,e.done=!1,E)):N}function g(t,e){var n,a,r=e.length;return t&&t.state?(n=t.state,0!==n.wrap&&n.mode!==$?N:n.mode===$&&(a=1,(a=w(a,e,r,0))!==n.check)?R:f(t,e,r,r)?(n.mode=ct,D):(n.havedict=1,E)):N}var p,m,b=t("../utils/common"),w=t("./adler32"),v=t("./crc32"),k=t("./inffast"),y=t("./inftrees"),x=0,z=1,B=2,C=4,A=5,S=6,E=0,O=1,Z=2,N=-2,R=-3,D=-4,I=-5,U=8,T=1,j=2,F=3,L=4,H=5,M=6,P=7,W=8,K=9,Y=10,$=11,q=12,G=13,X=14,J=15,Q=16,V=17,tt=18,et=19,nt=20,at=21,rt=22,it=23,st=24,ot=25,lt=26,ht=27,dt=28,ft=29,ut=30,ct=31,_t=32,gt=852,pt=592,mt=15,bt=!0;n.inflateReset=s,n.inflateReset2=o,n.inflateResetKeep=i,n.inflateInit=h,n.inflateInit2=l,n.inflate=u,n.inflateEnd=c,n.inflateGetHeader=_,n.inflateSetDictionary=g,n.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":5,"./adler32":7,"./crc32":9,"./inffast":11,"./inftrees":13}],13:[function(t,e,n){"use strict";var a=t("../utils/common"),r=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],i=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],s=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],o=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];e.exports=function(t,e,n,l,h,d,f,u){var c,_,g,p,m,b,w,v,k,y=u.bits,x=0,z=0,B=0,C=0,A=0,S=0,E=0,O=0,Z=0,N=0,R=null,D=0,I=new a.Buf16(16),U=new a.Buf16(16),T=null,j=0;for(x=0;x<=15;x++)I[x]=0;for(z=0;z<l;z++)I[e[n+z]]++;for(A=y,C=15;C>=1&&0===I[C];C--);if(A>C&&(A=C),0===C)return h[d++]=20971520,h[d++]=20971520,u.bits=1,0;for(B=1;B<C&&0===I[B];B++);for(A<B&&(A=B),O=1,x=1;x<=15;x++)if(O<<=1,(O-=I[x])<0)return-1;if(O>0&&(0===t||1!==C))return-1;for(U[1]=0,x=1;x<15;x++)U[x+1]=U[x]+I[x];for(z=0;z<l;z++)0!==e[n+z]&&(f[U[e[n+z]]++]=z);if(0===t?(R=T=f,b=19):1===t?(R=r,D-=257,T=i,j-=257,b=256):(R=s,T=o,b=-1),N=0,z=0,x=B,m=d,S=A,E=0,g=-1,Z=1<<A,p=Z-1,1===t&&Z>852||2===t&&Z>592)return 1;for(;;){w=x-E,f[z]<b?(v=0,k=f[z]):f[z]>b?(v=T[j+f[z]],k=R[D+f[z]]):(v=96,k=0),c=1<<x-E,_=1<<S,B=_;do{_-=c,h[m+(N>>E)+_]=w<<24|v<<16|k|0}while(0!==_);for(c=1<<x-1;N&c;)c>>=1;if(0!==c?(N&=c-1,N+=c):N=0,z++,0==--I[x]){if(x===C)break;x=e[n+f[z]]}if(x>A&&(N&p)!==g){for(0===E&&(E=A),m+=B,S=x-E,O=1<<S;S+E<C&&!((O-=I[S+E])<=0);)S++,O<<=1;if(Z+=1<<S,1===t&&Z>852||2===t&&Z>592)return 1;g=N&p,h[g]=A<<24|S<<16|m-d|0}}return 0!==N&&(h[m+N]=x-E<<24|64<<16|0),u.bits=A,0}},{"../utils/common":5}],14:[function(t,e,n){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],15:[function(t,e,n){"use strict";function a(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}e.exports=a},{}]},{},[3])(3)})}]);
0 2 \ No newline at end of file
... ...
doc/lib/js/docsify@4.js 0 → 100644
  1 +!function(){function c(i){var o=Object.create(null);return function(e){var n=f(e)?e:JSON.stringify(e);return o[n]||(o[n]=i(e))}}var a=c(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),u=Object.prototype.hasOwnProperty,m=Object.assign||function(e){for(var n=arguments,i=1;i<arguments.length;i++){var o,t=Object(n[i]);for(o in t)u.call(t,o)&&(e[o]=t[o])}return e};function f(e){return"string"==typeof e||"number"==typeof e}function d(){}function o(e){return"function"==typeof e}function g(e){e=e.match(/^([^:/?#]+:)?(?:\/{2,}([^/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/);return"string"==typeof e[1]&&0<e[1].length&&e[1].toLowerCase()!==location.protocol||"string"==typeof e[2]&&0<e[2].length&&e[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"),"")!==location.host}var s=document.body.clientWidth<=600,t=window.history&&window.history.pushState&&window.history.replaceState&&!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/),i={};function l(e,n){if(void 0===n&&(n=!1),"string"==typeof e){if(void 0!==window.Vue)return b(e);e=n?b(e):i[e]||(i[e]=b(e))}return e}var v=document,h=v.body,_=v.head;function b(e,n){return n?e.querySelector(n):v.querySelector(e)}function k(e,n){return[].slice.call(n?e.querySelectorAll(n):v.querySelectorAll(e))}function w(e,n){return e=v.createElement(e),n&&(e.innerHTML=n),e}function r(e,n){return e.appendChild(n)}function y(e,n){return e.insertBefore(n,e.children[0])}function p(e,n,i){o(n)?window.addEventListener(e,n):e.addEventListener(n,i)}function x(e,n,i){o(n)?window.removeEventListener(e,n):e.removeEventListener(n,i)}function S(e,n,i){e&&e.classList[i?n:"toggle"](i||n)}function e(e,n){var i=(n=void 0===n?document:n).readyState;if("complete"===i||"interactive"===i)return setTimeout(e,0);n.addEventListener("DOMContentLoaded",e)}var n=Object.freeze({__proto__:null,getNode:l,$:v,body:h,head:_,find:b,findAll:k,create:w,appendTo:r,before:y,on:p,off:x,toggleClass:S,style:function(e){r(_,w("style",e))},documentReady:e});function A(e,n){return-1!==e.indexOf(n,e.length-n.length)}var $=decodeURIComponent,z=encodeURIComponent;function F(e){var n={};return(e=e.trim().replace(/^(\?|#|&)/,""))&&e.split("&").forEach(function(e){e=e.replace(/\+/g," ").split("=");n[e[0]]=e[1]&&$(e[1])}),n}function E(e,n){void 0===n&&(n=[]);var i,o=[];for(i in e)-1<n.indexOf(i)||o.push(e[i]?(z(i)+"="+z(e[i])).toLowerCase():z(i));return o.length?"?"+o.join("&"):""}var T=c(function(e){return/(:|(\/{2}))/g.test(e)}),C=c(function(e){return e.split(/[?#]/)[0]}),R=c(function(e){if(/\/$/g.test(e))return e;e=e.match(/(\S*\/)[^/]+$/);return e?e[1]:""}),j=c(function(e){return e.replace(/^\/+/,"/").replace(/([^:])\/{2,}/g,"$1/")}),O=c(function(e){for(var n=e.replace(/^\//,"").split("/"),i=[],o=0,t=n.length;o<t;o++){var a=n[o];".."===a?i.pop():"."!==a&&i.push(a)}return"/"+i.join("/")});function L(e){return e.split("/").filter(function(e){return-1===e.indexOf("#")}).join("/")}function q(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];return j(e.map(L).join("/"))}var P=c(function(e){return e.replace("#","?id=")}),M={};function I(e){this.config=e}function N(e){var n=location.href.indexOf("#");location.replace(location.href.slice(0,0<=n?n:0)+"#"+e)}I.prototype.getBasePath=function(){return this.config.basePath},I.prototype.getFile=function(e,n){void 0===e&&(e=this.getCurrentPath());var i,o,t=this.config,a=this.getBasePath(),r="string"==typeof t.ext?t.ext:".md";return e=t.alias?function e(n,i,o){var t=Object.keys(i).filter(function(e){return(M[e]||(M[e]=new RegExp("^"+e+"$"))).test(n)&&n!==o})[0];return t?e(n.replace(M[t],i[t]),i,n):n}(e,t.alias):e,i=e,o=r,e=(e=new RegExp("\\.("+o.replace(/^\./,"")+"|html)$","g").test(i)?i:/\/$/g.test(i)?i+"README"+o:""+i+o)==="/README"+r&&t.homepage||e,e=T(e)?e:q(a,e),e=n?e.replace(new RegExp("^"+a),""):e},I.prototype.onchange=function(e){(e=void 0===e?d:e)()},I.prototype.getCurrentPath=function(){},I.prototype.normalize=function(){},I.prototype.parse=function(){},I.prototype.toURL=function(e,n,i){var o=i&&"#"===e[0],t=this.parse(P(e));if(t.query=m({},t.query,n),e=(e=t.path+E(t.query)).replace(/\.md(\?)|\.md$/,"$1"),o&&(e=(0<(o=i.indexOf("?"))?i.substring(0,o):i)+e),this.config.relativePath&&0!==e.indexOf("/")){i=i.substring(0,i.lastIndexOf("/")+1);return j(O(i+e))}return j("/"+e)};var H=function(o){function e(e){o.call(this,e),this.mode="hash"}return o&&(e.__proto__=o),((e.prototype=Object.create(o&&o.prototype)).constructor=e).prototype.getBasePath=function(){var e=window.location.pathname||"",n=this.config.basePath,e=A(e,".html")?e+"#/"+n:e+"/"+n;return/^(\/|https?:)/g.test(n)?n:j(e)},e.prototype.getCurrentPath=function(){var e=location.href,n=e.indexOf("#");return-1===n?"":e.slice(n+1)},e.prototype.onchange=function(i){void 0===i&&(i=d);var o=!1;p("click",function(e){e="A"===e.target.tagName?e.target:e.target.parentNode;e&&"A"===e.tagName&&!/_blank/.test(e.target)&&(o=!0)}),p("hashchange",function(e){var n=o?"navigate":"history";o=!1,i({event:e,source:n})})},e.prototype.normalize=function(){var e=this.getCurrentPath();if("/"===(e=P(e)).charAt(0))return N(e);N("/"+e)},e.prototype.parse=function(e){var n="",i=(e=void 0===e?location.href:e).indexOf("#"),i=(e=0<=i?e.slice(i+1):e).indexOf("?");return 0<=i&&(n=e.slice(i+1),e=e.slice(0,i)),{path:e,file:this.getFile(e,!0),query:F(n)}},e.prototype.toURL=function(e,n,i){return"#"+o.prototype.toURL.call(this,e,n,i)},e}(I),D=function(n){function e(e){n.call(this,e),this.mode="history"}return n&&(e.__proto__=n),((e.prototype=Object.create(n&&n.prototype)).constructor=e).prototype.getCurrentPath=function(){var e=this.getBasePath(),n=window.location.pathname;return((n=e&&0===n.indexOf(e)?n.slice(e.length):n)||"/")+window.location.search+window.location.hash},e.prototype.onchange=function(i){var o=this;void 0===i&&(i=d),p("click",function(e){var n="A"===e.target.tagName?e.target:e.target.parentNode;n&&"A"===n.tagName&&!/_blank/.test(n.target)&&(e.preventDefault(),n=n.href,-1!==o.config.crossOriginLinks.indexOf(n)?window.open(n,"_self"):window.history.pushState({key:n},"",n),i({event:e,source:"navigate"}))}),p("popstate",function(e){i({event:e,source:"history"})})},e.prototype.parse=function(e){var n="",i=(e=void 0===e?location.href:e).indexOf("?");0<=i&&(n=e.slice(i+1),e=e.slice(0,i));var o=q(location.origin),i=e.indexOf(o);return{path:e=-1<i?e.slice(i+o.length):e,file:this.getFile(e),query:F(n)}},e}(I),U={};var Z,B,V=/([^{]*?)\w(?=\})/g,Y={YYYY:"getFullYear",YY:"getYear",MM:function(e){return e.getMonth()+1},DD:"getDate",HH:"getHours",mm:"getMinutes",ss:"getSeconds",fff:"getMilliseconds"};function G(e){var n,i=e.loaded,o=e.total,t=e.step;Z||((e=w("div")).classList.add("progress"),r(h,e),Z=e),n=t?80<(n=parseInt(Z.style.width||0,10)+t)?80:n:Math.floor(i/o*100),Z.style.opacity=1,Z.style.width=95<=n?"100%":n+"%",95<=n&&(clearTimeout(B),B=setTimeout(function(e){Z.style.opacity=0,Z.style.width="0%"},200))}var W={};function X(t,e,n){void 0===e&&(e=!1),void 0===n&&(n={});function a(){r.addEventListener.apply(r,arguments)}var i,r=new XMLHttpRequest,o=W[t];if(o)return{then:function(e){return e(o.content,o.opt)},abort:d};for(i in r.open("GET",t),n)u.call(n,i)&&r.setRequestHeader(i,n[i]);return r.send(),{then:function(n,i){var o;void 0===i&&(i=d),e&&(o=setInterval(function(e){return G({step:Math.floor(5*Math.random()+1)})},500),a("progress",G),a("loadend",function(e){G(e),clearInterval(o)})),a("error",i),a("load",function(e){var e=e.target;400<=e.status?i(e):(e=W[t]={content:e.response,opt:{updatedAt:r.getResponseHeader("last-modified")}},n(e.content,e.opt))})},abort:function(e){return 4!==r.readyState&&r.abort()}}}function Q(e,n){e.innerHTML=e.innerHTML.replace(/var\(\s*--theme-color.*?\)/g,n)}var J=v.title;function K(){var e,n=l("section.cover");n&&(e=n.getBoundingClientRect().height,window.pageYOffset>=e||n.classList.contains("hidden")?S(h,"add","sticky"):S(h,"remove","sticky"))}function ee(e,n,o,i){var t=[];null!=(n=l(n))&&(t=k(n,"a"));var a,r=decodeURI(e.toURL(e.getCurrentPath()));return t.sort(function(e,n){return n.href.length-e.href.length}).forEach(function(e){var n=decodeURI(e.getAttribute("href")),i=o?e.parentNode:e;e.title=e.title||e.innerText,0!==r.indexOf(n)||a?S(i,"remove","active"):(a=e,S(i,"add","active"))}),i&&(v.title=a?a.title||a.innerText+" - "+J:J),a}function ne(e,n){for(var i=0;i<n.length;i++){var o=n[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var ie=(function(e,n,i){return n&&ne(e.prototype,n),i&&ne(e,i),e}(oe,[{key:"getIntermediateValue",value:function(e){return this.decimal?e:Math.round(e)}},{key:"getFinalValue",value:function(){return this.end}}]),oe);function oe(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,oe),this.start=e.start,this.end=e.end,this.decimal=e.decimal}function te(e,n){for(var i=0;i<n.length;i++){var o=n[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}var ae=(function(e,n,i){return n&&te(e.prototype,n),i&&te(e,i),e}(re,[{key:"begin",value:function(){return this.isRunning||this.next===this.end||(this.frame=window.requestAnimationFrame(this._tick.bind(this))),this}},{key:"stop",value:function(){return window.cancelAnimationFrame(this.frame),this.isRunning=!1,this.frame=null,this.timeStart=null,this.next=null,this}},{key:"on",value:function(e,n){return this.events[e]=this.events[e]||[],this.events[e].push(n),this}},{key:"_emit",value:function(e,n){var i=this,e=this.events[e];e&&e.forEach(function(e){return e.call(i,n)})}},{key:"_tick",value:function(e){this.isRunning=!0;var n=this.next||this.start;this.timeStart||(this.timeStart=e),this.timeElapsed=e-this.timeStart,this.next=this.ease(this.timeElapsed,this.start,this.end-this.start,this.duration),this._shouldTick(n)?(this._emit("tick",this.tweener.getIntermediateValue(this.next)),this.frame=window.requestAnimationFrame(this._tick.bind(this))):(this._emit("tick",this.tweener.getFinalValue()),this._emit("done",null))}},{key:"_shouldTick",value:function(e){return{up:this.next<this.end&&e<=this.next,down:this.next>this.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,n,i,o){return(e/=o/2)<1?i/2*e*e+n:-i/2*(--e*(e-2)-1)+n}}]),re);function re(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,re),this.duration=e.duration||1e3,this.ease=e.easing||this._defaultEase,this.tweener=e.tweener||new ie(e),this.start=this.tweener.start,this.end=this.tweener.end,this.frame=null,this.next=null,this.isRunning=!1,this.events={},this.direction=this.start<this.end?"up":"down"}var ce=document.currentScript;function ue(e){var n,i=m({auto2top:!1,autoHeader:!1,basePath:"",catchPluginErrors:!0,cornerExternalLinkTarget:"_blank",coverpage:"",crossOriginLinks:[],el:"#app",executeScript:null,ext:".md",externalLinkRel:"noopener",externalLinkTarget:"_blank",formatUpdated:"",ga:"",homepage:"README.md",loadNavbar:null,loadSidebar:null,maxLevel:6,mergeNavbar:!1,name:"",nameLink:window.location.pathname,nativeEmoji:!1,noCompileLinks:[],noEmoji:!1,notFoundPage:!0,relativePath:!1,repo:"",routes:{},routerMode:"hash",subMaxLevel:0,themeColor:"",topMargin:0},"function"==typeof window.$docsify?window.$docsify(e):window.$docsify),o=ce||[].slice.call(document.getElementsByTagName("script")).filter(function(e){return/docsify\./.test(e.src)})[0];if(o)for(var t in i)!u.call(i,t)||f(n=o.getAttribute("data-"+a(t)))&&(i[t]=""===n||n);return!0===i.loadSidebar&&(i.loadSidebar="_sidebar"+i.ext),!0===i.loadNavbar&&(i.loadNavbar="_navbar"+i.ext),!0===i.coverpage&&(i.coverpage="_coverpage"+i.ext),!0===i.repo&&(i.repo=""),!0===i.name&&(i.name=""),window.$docsify=i}var fe={},pe=!1,de=null,ge=!0,se=0;function le(e){if(ge){for(var n,i=l(".sidebar"),o=k(".anchor"),t=b(i,".sidebar-nav"),a=b(i,"li.active"),r=document.documentElement,c=(r&&r.scrollTop||document.body.scrollTop)-se,u=0,f=o.length;u<f;u+=1){var p=o[u];if(p.offsetTop>c){n=n||p;break}n=p}!n||(r=fe[ve(e,n.getAttribute("data-id"))])&&r!==a&&(a&&a.classList.remove("active"),r.classList.add("active"),a=r,!pe&&h.classList.contains("sticky")&&(e=i.clientHeight,r=a.offsetTop+a.clientHeight+40,a=a.offsetTop>=t.scrollTop&&r<=t.scrollTop+e,i.scrollTop=a?t.scrollTop:+r<e?0:r-e))}}function ve(e,n){return decodeURIComponent(e)+"?id="+decodeURIComponent(n)}function he(e,n){var i,o;n&&(o=ue().topMargin,(i=b("#"+n))&&(i=i,void 0===(o=o)&&(o=0),de&&de.stop(),ge=!1,de=new ae({start:window.pageYOffset,end:Math.round(i.getBoundingClientRect().top)+window.pageYOffset-o,duration:500}).on("tick",function(e){return window.scrollTo(0,e)}).on("done",function(){ge=!0,de=null}).begin()),e=fe[ve(e,n)],(n=b(l(".sidebar"),"li.active"))&&n.classList.remove("active"),e&&e.classList.add("active"))}var _e=v.scrollingElement||v.documentElement;var me="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function be(e,n){return e(n={exports:{}},n.exports),n.exports}function ke(e){return $e[e]}var we=be(function(n){function e(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:null,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tokenizer:null,walkTokens:null,xhtml:!1}}n.exports={defaults:e(),getDefaults:e,changeDefaults:function(e){n.exports.defaults=e}}}),ye=(we.defaults,we.getDefaults,we.changeDefaults,/[&<>"']/),xe=/[&<>"']/g,Se=/[<>"']|&(?!#?\w+;)/,Ae=/[<>"']|&(?!#?\w+;)/g,$e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};var ze=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function Fe(e){return e.replace(ze,function(e,n){return"colon"===(n=n.toLowerCase())?":":"#"===n.charAt(0)?"x"===n.charAt(1)?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1)):""})}var Ee=/(^|[^\[])\^/g;var Te=/[^\w:]/g,Ce=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var Re={},je=/^[^:]+:\/*[^/]*$/,Oe=/^([^:]+:)[\s\S]*$/,Le=/^([^:]+:\/*[^/]*)[\s\S]*$/;function qe(e,n){Re[" "+e]||(je.test(e)?Re[" "+e]=e+"/":Re[" "+e]=Pe(e,"/",!0));var i=-1===(e=Re[" "+e]).indexOf(":");return"//"===n.substring(0,2)?i?n:e.replace(Oe,"$1")+n:"/"===n.charAt(0)?i?n:e.replace(Le,"$1")+n:e+n}function Pe(e,n,i){var o=e.length;if(0===o)return"";for(var t=0;t<o;){var a=e.charAt(o-t-1);if(a!==n||i){if(a===n||!i)break;t++}else t++}return e.substr(0,o-t)}var Me=function(e,n){if(n){if(ye.test(e))return e.replace(xe,ke)}else if(Se.test(e))return e.replace(Ae,ke);return e},Ie=Fe,Ne=function(i,e){i=i.source||i,e=e||"";var o={replace:function(e,n){return n=(n=n.source||n).replace(Ee,"$1"),i=i.replace(e,n),o},getRegex:function(){return new RegExp(i,e)}};return o},He=function(e,n,i){if(e){var o;try{o=decodeURIComponent(Fe(i)).replace(Te,"").toLowerCase()}catch(e){return null}if(0===o.indexOf("javascript:")||0===o.indexOf("vbscript:")||0===o.indexOf("data:"))return null}n&&!Ce.test(i)&&(i=qe(n,i));try{i=encodeURI(i).replace(/%25/g,"%")}catch(e){return null}return i},De={exec:function(){}},Ue=function(e){for(var n,i,o=arguments,t=1;t<arguments.length;t++)for(i in n=o[t])Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i]);return e},Ze=function(e,n){var i=e.replace(/\|/g,function(e,n,i){for(var o=!1,t=n;0<=--t&&"\\"===i[t];)o=!o;return o?"|":" |"}).split(/ \|/),o=0;if(i.length>n)i.splice(n);else for(;i.length<n;)i.push("");for(;o<i.length;o++)i[o]=i[o].trim().replace(/\\\|/g,"|");return i},Be=Pe,Ve=function(e,n){if(-1===e.indexOf(n[1]))return-1;for(var i=e.length,o=0,t=0;t<i;t++)if("\\"===e[t])t++;else if(e[t]===n[0])o++;else if(e[t]===n[1]&&--o<0)return t;return-1},Ye=function(e){e&&e.sanitize&&!e.silent&&console.warn("marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options")},Ge=function(e,n){if(n<1)return"";for(var i="";1<n;)1&n&&(i+=e),n>>=1,e+=e;return i+e},We=we.defaults,Xe=Be,Qe=Ze,Je=Me,Ke=Ve;function en(e,n,i){var o=n.href,t=n.title?Je(n.title):null,n=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:i,href:o,title:t,text:n}:{type:"image",raw:i,href:o,title:t,text:Je(n)}}var nn=function(){function e(e){this.options=e||We}return e.prototype.space=function(e){e=this.rules.block.newline.exec(e);if(e)return 1<e[0].length?{type:"space",raw:e[0]}:{raw:"\n"}},e.prototype.code=function(e,n){e=this.rules.block.code.exec(e);if(e){n=n[n.length-1];if(n&&"paragraph"===n.type)return{raw:e[0],text:e[0].trimRight()};n=e[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:e[0],codeBlockStyle:"indented",text:this.options.pedantic?n:Xe(n,"\n")}}},e.prototype.fences=function(e){var n=this.rules.block.fences.exec(e);if(n){var i=n[0],e=function(e,n){if(null===(e=e.match(/^(\s+)(?:```)/)))return n;var i=e[1];return n.split("\n").map(function(e){var n=e.match(/^\s+/);return null!==n&&n[0].length>=i.length?e.slice(i.length):e}).join("\n")}(i,n[3]||"");return{type:"code",raw:i,lang:n[2]&&n[2].trim(),text:e}}},e.prototype.heading=function(e){var n=this.rules.block.heading.exec(e);if(n){var i=n[2].trim();return/#$/.test(i)&&(e=Xe(i,"#"),!this.options.pedantic&&e&&!/ $/.test(e)||(i=e.trim())),{type:"heading",raw:n[0],depth:n[1].length,text:i}}},e.prototype.nptable=function(e){e=this.rules.block.nptable.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[],raw:e[0]};if(n.header.length===n.align.length){for(var i=n.align.length,o=0;o<i;o++)/^ *-+: *$/.test(n.align[o])?n.align[o]="right":/^ *:-+: *$/.test(n.align[o])?n.align[o]="center":/^ *:-+ *$/.test(n.align[o])?n.align[o]="left":n.align[o]=null;for(i=n.cells.length,o=0;o<i;o++)n.cells[o]=Qe(n.cells[o],n.header.length);return n}}},e.prototype.hr=function(e){e=this.rules.block.hr.exec(e);if(e)return{type:"hr",raw:e[0]}},e.prototype.blockquote=function(e){var n=this.rules.block.blockquote.exec(e);if(n){e=n[0].replace(/^ *> ?/gm,"");return{type:"blockquote",raw:n[0],text:e}}},e.prototype.list=function(e){e=this.rules.block.list.exec(e);if(e){for(var n,i,o,t,a,r=e[0],c=e[2],u=1<c.length,f={type:"list",raw:r,ordered:u,start:u?+c.slice(0,-1):"",loose:!1,items:[]},p=e[0].match(this.rules.block.item),d=!1,g=p.length,s=this.rules.block.listItemStart.exec(p[0]),l=0;l<g;l++){if(r=n=p[l],l!==g-1){if(o=this.rules.block.listItemStart.exec(p[l+1]),this.options.pedantic?o[1].length>s[1].length:o[1].length>s[0].length||3<o[1].length){p.splice(l,2,p[l]+"\n"+p[l+1]),l--,g--;continue}(!this.options.pedantic||this.options.smartLists?o[2][o[2].length-1]!==c[c.length-1]:u==(1===o[2].length))&&(i=p.slice(l+1).join("\n"),f.raw=f.raw.substring(0,f.raw.length-i.length),l=g-1),s=o}o=n.length,~(n=n.replace(/^ *([*+-]|\d+[.)]) ?/,"")).indexOf("\n ")&&(o-=n.length,n=this.options.pedantic?n.replace(/^ {1,4}/gm,""):n.replace(new RegExp("^ {1,"+o+"}","gm"),"")),o=d||/\n\n(?!\s*$)/.test(n),l!==g-1&&(d="\n"===n.charAt(n.length-1),o=o||d),o&&(f.loose=!0),this.options.gfm&&(a=void 0,(t=/^\[[ xX]\] /.test(n))&&(a=" "!==n[1],n=n.replace(/^\[[ xX]\] +/,""))),f.items.push({type:"list_item",raw:r,task:t,checked:a,loose:o,text:n})}return f}},e.prototype.html=function(e){e=this.rules.block.html.exec(e);if(e)return{type:this.options.sanitize?"paragraph":"html",raw:e[0],pre:!this.options.sanitizer&&("pre"===e[1]||"script"===e[1]||"style"===e[1]),text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.def=function(e){e=this.rules.block.def.exec(e);if(e)return e[3]&&(e[3]=e[3].substring(1,e[3].length-1)),{tag:e[1].toLowerCase().replace(/\s+/g," "),raw:e[0],href:e[2],title:e[3]}},e.prototype.table=function(e){e=this.rules.block.table.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[]};if(n.header.length===n.align.length){n.raw=e[0];for(var i=n.align.length,o=0;o<i;o++)/^ *-+: *$/.test(n.align[o])?n.align[o]="right":/^ *:-+: *$/.test(n.align[o])?n.align[o]="center":/^ *:-+ *$/.test(n.align[o])?n.align[o]="left":n.align[o]=null;for(i=n.cells.length,o=0;o<i;o++)n.cells[o]=Qe(n.cells[o].replace(/^ *\| *| *\| *$/g,""),n.header.length);return n}}},e.prototype.lheading=function(e){e=this.rules.block.lheading.exec(e);if(e)return{type:"heading",raw:e[0],depth:"="===e[2].charAt(0)?1:2,text:e[1]}},e.prototype.paragraph=function(e){e=this.rules.block.paragraph.exec(e);if(e)return{type:"paragraph",raw:e[0],text:"\n"===e[1].charAt(e[1].length-1)?e[1].slice(0,-1):e[1]}},e.prototype.text=function(e,n){e=this.rules.block.text.exec(e);if(e){n=n[n.length-1];return n&&"text"===n.type?{raw:e[0],text:e[0]}:{type:"text",raw:e[0],text:e[0]}}},e.prototype.escape=function(e){e=this.rules.inline.escape.exec(e);if(e)return{type:"escape",raw:e[0],text:Je(e[1])}},e.prototype.tag=function(e,n,i){e=this.rules.inline.tag.exec(e);if(e)return!n&&/^<a /i.test(e[0])?n=!0:n&&/^<\/a>/i.test(e[0])&&(n=!1),!i&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?i=!0:i&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(i=!1),{type:this.options.sanitize?"text":"html",raw:e[0],inLink:n,inRawBlock:i,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.link=function(e){var n=this.rules.inline.link.exec(e);if(n){e=n[2].trim();if(!this.options.pedantic&&/^</.test(e)){if(!/>$/.test(e))return;var i=Xe(e.slice(0,-1),"\\");if((e.length-i.length)%2==0)return}else{var o=Ke(n[2],"()");-1<o&&(t=(0===n[0].indexOf("!")?5:4)+n[1].length+o,n[2]=n[2].substring(0,o),n[0]=n[0].substring(0,t).trim(),n[3]="")}var t,i=n[2],o="";return this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i))&&(i=t[1],o=t[3]):o=n[3]?n[3].slice(1,-1):"",i=i.trim(),en(n,{href:(i=/^</.test(i)?this.options.pedantic&&!/>$/.test(e)?i.slice(1):i.slice(1,-1):i)&&i.replace(this.rules.inline._escapes,"$1"),title:o&&o.replace(this.rules.inline._escapes,"$1")},n[0])}},e.prototype.reflink=function(e,n){if((i=this.rules.inline.reflink.exec(e))||(i=this.rules.inline.nolink.exec(e))){var e=(i[2]||i[1]).replace(/\s+/g," ");if((e=n[e.toLowerCase()])&&e.href)return en(i,e,i[0]);var i=i[0].charAt(0);return{type:"text",raw:i,text:i}}},e.prototype.strong=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.strong.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="**"===o[0]?this.rules.inline.strong.endAst:this.rules.inline.strong.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.strong.middle.exec(n.slice(0,o.index+3)))return{type:"strong",raw:e.slice(0,t[0].length),text:e.slice(2,t[0].length-2)}}},e.prototype.em=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.em.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="*"===o[0]?this.rules.inline.em.endAst:this.rules.inline.em.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.em.middle.exec(n.slice(0,o.index+2)))return{type:"em",raw:e.slice(0,t[0].length),text:e.slice(1,t[0].length-1)}}},e.prototype.codespan=function(e){var n=this.rules.inline.code.exec(e);if(n){var i=n[2].replace(/\n/g," "),o=/[^ ]/.test(i),e=/^ /.test(i)&&/ $/.test(i);return o&&e&&(i=i.substring(1,i.length-1)),i=Je(i,!0),{type:"codespan",raw:n[0],text:i}}},e.prototype.br=function(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}},e.prototype.del=function(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2]}},e.prototype.autolink=function(e,n){e=this.rules.inline.autolink.exec(e);if(e){var i,n="@"===e[2]?"mailto:"+(i=Je(this.options.mangle?n(e[1]):e[1])):i=Je(e[1]);return{type:"link",raw:e[0],text:i,href:n,tokens:[{type:"text",raw:i,text:i}]}}},e.prototype.url=function(e,n){var i,o,t,a;if(i=this.rules.inline.url.exec(e)){if("@"===i[2])t="mailto:"+(o=Je(this.options.mangle?n(i[0]):i[0]));else{for(;a=i[0],i[0]=this.rules.inline._backpedal.exec(i[0])[0],a!==i[0];);o=Je(i[0]),t="www."===i[1]?"http://"+o:o}return{type:"link",raw:i[0],text:o,href:t,tokens:[{type:"text",raw:o,text:o}]}}},e.prototype.inlineText=function(e,n,i){e=this.rules.inline.text.exec(e);if(e){i=n?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]:Je(this.options.smartypants?i(e[0]):e[0]);return{type:"text",raw:e[0],text:i}}},e}(),Ze=De,Ve=Ne,De=Ue,Ne={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Ze,table:Ze,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Ne.def=Ve(Ne.def).replace("label",Ne._label).replace("title",Ne._title).getRegex(),Ne.bullet=/(?:[*+-]|\d{1,9}[.)])/,Ne.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,Ne.item=Ve(Ne.item,"gm").replace(/bull/g,Ne.bullet).getRegex(),Ne.listItemStart=Ve(/^( *)(bull)/).replace("bull",Ne.bullet).getRegex(),Ne.list=Ve(Ne.list).replace(/bull/g,Ne.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Ne.def.source+")").getRegex(),Ne._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ne._comment=/<!--(?!-?>)[\s\S]*?(?:-->|$)/,Ne.html=Ve(Ne.html,"i").replace("comment",Ne._comment).replace("tag",Ne._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Ne.paragraph=Ve(Ne._paragraph).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.blockquote=Ve(Ne.blockquote).replace("paragraph",Ne.paragraph).getRegex(),Ne.normal=De({},Ne),Ne.gfm=De({},Ne.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Ne.gfm.nptable=Ve(Ne.gfm.nptable).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.gfm.table=Ve(Ne.gfm.table).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.pedantic=De({},Ne.normal,{html:Ve("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Ne._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Ze,paragraph:Ve(Ne.normal._paragraph).replace("hr",Ne.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Ne.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});Ze={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Ze,tag:"^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",strong:{start:/^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,middle:/^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,endAst:/[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/},em:{start:/^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,middle:/^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,endAst:/[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Ze,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n)))/,punctuation:/^([\s*punctuation])/,_punctuation:"!\"#$%&'()+\\-.,/:;<=>?@\\[\\]`^{|}~"};Ze.punctuation=Ve(Ze.punctuation).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze._blockSkip="\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>",Ze._overlapSkip="__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*",Ze._comment=Ve(Ne._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),Ze.em.start=Ve(Ze.em.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.middle=Ve(Ze.em.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.em.endAst=Ve(Ze.em.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.endUnd=Ve(Ze.em.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.start=Ve(Ze.strong.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.middle=Ve(Ze.strong.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.strong.endAst=Ve(Ze.strong.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.endUnd=Ve(Ze.strong.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.blockSkip=Ve(Ze._blockSkip,"g").getRegex(),Ze.overlapSkip=Ve(Ze._overlapSkip,"g").getRegex(),Ze._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,Ze._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,Ze._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,Ze.autolink=Ve(Ze.autolink).replace("scheme",Ze._scheme).replace("email",Ze._email).getRegex(),Ze._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,Ze.tag=Ve(Ze.tag).replace("comment",Ze._comment).replace("attribute",Ze._attribute).getRegex(),Ze._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ze._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,Ze._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,Ze.link=Ve(Ze.link).replace("label",Ze._label).replace("href",Ze._href).replace("title",Ze._title).getRegex(),Ze.reflink=Ve(Ze.reflink).replace("label",Ze._label).getRegex(),Ze.reflinkSearch=Ve(Ze.reflinkSearch,"g").replace("reflink",Ze.reflink).replace("nolink",Ze.nolink).getRegex(),Ze.normal=De({},Ze),Ze.pedantic=De({},Ze.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:Ve(/^!?\[(label)\]\((.*?)\)/).replace("label",Ze._label).getRegex(),reflink:Ve(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Ze._label).getRegex()}),Ze.gfm=De({},Ze.normal,{escape:Ve(Ze.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/}),Ze.gfm.url=Ve(Ze.gfm.url,"i").replace("email",Ze.gfm._extended_email).getRegex(),Ze.breaks=De({},Ze.gfm,{br:Ve(Ze.br).replace("{2,}","*").getRegex(),text:Ve(Ze.gfm.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()});var Ze={block:Ne,inline:Ze},on=we.defaults,tn=Ze.block,an=Ze.inline,rn=Ge;function cn(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")}function un(e){for(var n,i="",o=e.length,t=0;t<o;t++)n=e.charCodeAt(t),i+="&#"+(n=.5<Math.random()?"x"+n.toString(16):n)+";";return i}var fn=function(){function i(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||on,this.options.tokenizer=this.options.tokenizer||new nn,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options;e={block:tn.normal,inline:an.normal};this.options.pedantic?(e.block=tn.pedantic,e.inline=an.pedantic):this.options.gfm&&(e.block=tn.gfm,this.options.breaks?e.inline=an.breaks:e.inline=an.gfm),this.tokenizer.rules=e}var e={rules:{configurable:!0}};return e.rules.get=function(){return{block:tn,inline:an}},i.lex=function(e,n){return new i(n).lex(e)},i.lexInline=function(e,n){return new i(n).inlineTokens(e)},i.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," "),this.blockTokens(e,this.tokens,!0),this.inline(this.tokens),this.tokens},i.prototype.blockTokens=function(e,n,i){var o,t,a,r;for(void 0===n&&(n=[]),void 0===i&&(i=!0),this.options.pedantic&&(e=e.replace(/^ +$/gm,""));e;)if(o=this.tokenizer.space(e))e=e.substring(o.raw.length),o.type&&n.push(o);else if(o=this.tokenizer.code(e,n))e=e.substring(o.raw.length),o.type?n.push(o):((r=n[n.length-1]).raw+="\n"+o.raw,r.text+="\n"+o.text);else if(o=this.tokenizer.fences(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.heading(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.nptable(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.hr(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.blockquote(e))e=e.substring(o.raw.length),o.tokens=this.blockTokens(o.text,[],i),n.push(o);else if(o=this.tokenizer.list(e)){for(e=e.substring(o.raw.length),a=o.items.length,t=0;t<a;t++)o.items[t].tokens=this.blockTokens(o.items[t].text,[],!1);n.push(o)}else if(o=this.tokenizer.html(e))e=e.substring(o.raw.length),n.push(o);else if(i&&(o=this.tokenizer.def(e)))e=e.substring(o.raw.length),this.tokens.links[o.tag]||(this.tokens.links[o.tag]={href:o.href,title:o.title});else if(o=this.tokenizer.table(e))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.lheading(e))e=e.substring(o.raw.length),n.push(o);else if(i&&(o=this.tokenizer.paragraph(e)))e=e.substring(o.raw.length),n.push(o);else if(o=this.tokenizer.text(e,n))e=e.substring(o.raw.length),o.type?n.push(o):((r=n[n.length-1]).raw+="\n"+o.raw,r.text+="\n"+o.text);else if(e){var c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}throw new Error(c)}return n},i.prototype.inline=function(e){for(var n,i,o,t,a,r=e.length,c=0;c<r;c++)switch((a=e[c]).type){case"paragraph":case"text":case"heading":a.tokens=[],this.inlineTokens(a.text,a.tokens);break;case"table":for(a.tokens={header:[],cells:[]},o=a.header.length,n=0;n<o;n++)a.tokens.header[n]=[],this.inlineTokens(a.header[n],a.tokens.header[n]);for(o=a.cells.length,n=0;n<o;n++)for(t=a.cells[n],a.tokens.cells[n]=[],i=0;i<t.length;i++)a.tokens.cells[n][i]=[],this.inlineTokens(t[i],a.tokens.cells[n][i]);break;case"blockquote":this.inline(a.tokens);break;case"list":for(o=a.items.length,n=0;n<o;n++)this.inline(a.items[n].tokens)}return e},i.prototype.inlineTokens=function(e,n,i,o){var t;void 0===n&&(n=[]),void 0===i&&(i=!1),void 0===o&&(o=!1);var a,r,c,u=e;if(this.tokens.links){var f=Object.keys(this.tokens.links);if(0<f.length)for(;null!=(a=this.tokenizer.rules.inline.reflinkSearch.exec(u));)f.includes(a[0].slice(a[0].lastIndexOf("[")+1,-1))&&(u=u.slice(0,a.index)+"["+rn("a",a[0].length-2)+"]"+u.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(a=this.tokenizer.rules.inline.blockSkip.exec(u));)u=u.slice(0,a.index)+"["+rn("a",a[0].length-2)+"]"+u.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;e;)if(r||(c=""),r=!1,t=this.tokenizer.escape(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.tag(e,i,o))e=e.substring(t.raw.length),i=t.inLink,o=t.inRawBlock,n.push(t);else if(t=this.tokenizer.link(e))e=e.substring(t.raw.length),"link"===t.type&&(t.tokens=this.inlineTokens(t.text,[],!0,o)),n.push(t);else if(t=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(t.raw.length),"link"===t.type&&(t.tokens=this.inlineTokens(t.text,[],!0,o)),n.push(t);else if(t=this.tokenizer.strong(e,u,c))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.em(e,u,c))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.codespan(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.br(e))e=e.substring(t.raw.length),n.push(t);else if(t=this.tokenizer.del(e))e=e.substring(t.raw.length),t.tokens=this.inlineTokens(t.text,[],i,o),n.push(t);else if(t=this.tokenizer.autolink(e,un))e=e.substring(t.raw.length),n.push(t);else if(i||!(t=this.tokenizer.url(e,un))){if(t=this.tokenizer.inlineText(e,o,cn))e=e.substring(t.raw.length),c=t.raw.slice(-1),r=!0,n.push(t);else if(e){var p="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(p);break}throw new Error(p)}}else e=e.substring(t.raw.length),n.push(t);return n},Object.defineProperties(i,e),i}(),pn=we.defaults,dn=He,gn=Me,sn=function(){function e(e){this.options=e||pn}return e.prototype.code=function(e,n,i){var o=(n||"").match(/\S*/)[0];return!this.options.highlight||null!=(n=this.options.highlight(e,o))&&n!==e&&(i=!0,e=n),e=e.replace(/\n$/,"")+"\n",o?'<pre><code class="'+this.options.langPrefix+gn(o,!0)+'">'+(i?e:gn(e,!0))+"</code></pre>\n":"<pre><code>"+(i?e:gn(e,!0))+"</code></pre>\n"},e.prototype.blockquote=function(e){return"<blockquote>\n"+e+"</blockquote>\n"},e.prototype.html=function(e){return e},e.prototype.heading=function(e,n,i,o){return this.options.headerIds?"<h"+n+' id="'+this.options.headerPrefix+o.slug(i)+'">'+e+"</h"+n+">\n":"<h"+n+">"+e+"</h"+n+">\n"},e.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"},e.prototype.list=function(e,n,i){var o=n?"ol":"ul";return"<"+o+(n&&1!==i?' start="'+i+'"':"")+">\n"+e+"</"+o+">\n"},e.prototype.listitem=function(e){return"<li>"+e+"</li>\n"},e.prototype.checkbox=function(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox"'+(this.options.xhtml?" /":"")+"> "},e.prototype.paragraph=function(e){return"<p>"+e+"</p>\n"},e.prototype.table=function(e,n){return"<table>\n<thead>\n"+e+"</thead>\n"+(n=n&&"<tbody>"+n+"</tbody>")+"</table>\n"},e.prototype.tablerow=function(e){return"<tr>\n"+e+"</tr>\n"},e.prototype.tablecell=function(e,n){var i=n.header?"th":"td";return(n.align?"<"+i+' align="'+n.align+'">':"<"+i+">")+e+"</"+i+">\n"},e.prototype.strong=function(e){return"<strong>"+e+"</strong>"},e.prototype.em=function(e){return"<em>"+e+"</em>"},e.prototype.codespan=function(e){return"<code>"+e+"</code>"},e.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"},e.prototype.del=function(e){return"<del>"+e+"</del>"},e.prototype.link=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;e='<a href="'+gn(e)+'"';return n&&(e+=' title="'+n+'"'),e+=">"+i+"</a>"},e.prototype.image=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;i='<img src="'+e+'" alt="'+i+'"';return n&&(i+=' title="'+n+'"'),i+=this.options.xhtml?"/>":">"},e.prototype.text=function(e){return e},e}(),ln=function(){function e(){}return e.prototype.strong=function(e){return e},e.prototype.em=function(e){return e},e.prototype.codespan=function(e){return e},e.prototype.del=function(e){return e},e.prototype.html=function(e){return e},e.prototype.text=function(e){return e},e.prototype.link=function(e,n,i){return""+i},e.prototype.image=function(e,n,i){return""+i},e.prototype.br=function(){return""},e}(),vn=function(){function e(){this.seen={}}return e.prototype.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},e.prototype.getNextSafeSlug=function(e,n){var i=e,o=0;if(this.seen.hasOwnProperty(i))for(o=this.seen[e];i=e+"-"+ ++o,this.seen.hasOwnProperty(i););return n||(this.seen[e]=o,this.seen[i]=0),i},e.prototype.slug=function(e,n){void 0===n&&(n={});e=this.serialize(e);return this.getNextSafeSlug(e,n.dryrun)},e}(),hn=we.defaults,_n=Ie,mn=function(){function i(e){this.options=e||hn,this.options.renderer=this.options.renderer||new sn,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ln,this.slugger=new vn}return i.parse=function(e,n){return new i(n).parse(e)},i.parseInline=function(e,n){return new i(n).parseInline(e)},i.prototype.parse=function(e,n){void 0===n&&(n=!0);for(var i,o,t,a,r,c,u,f,p,d,g,s,l,v,h,_="",m=e.length,b=0;b<m;b++)switch((f=e[b]).type){case"space":continue;case"hr":_+=this.renderer.hr();continue;case"heading":_+=this.renderer.heading(this.parseInline(f.tokens),f.depth,_n(this.parseInline(f.tokens,this.textRenderer)),this.slugger);continue;case"code":_+=this.renderer.code(f.text,f.lang,f.escaped);continue;case"table":for(c=p="",t=f.header.length,i=0;i<t;i++)c+=this.renderer.tablecell(this.parseInline(f.tokens.header[i]),{header:!0,align:f.align[i]});for(p+=this.renderer.tablerow(c),u="",t=f.cells.length,i=0;i<t;i++){for(c="",a=(r=f.tokens.cells[i]).length,o=0;o<a;o++)c+=this.renderer.tablecell(this.parseInline(r[o]),{header:!1,align:f.align[o]});u+=this.renderer.tablerow(c)}_+=this.renderer.table(p,u);continue;case"blockquote":u=this.parse(f.tokens),_+=this.renderer.blockquote(u);continue;case"list":for(p=f.ordered,k=f.start,d=f.loose,t=f.items.length,u="",i=0;i<t;i++)l=(s=f.items[i]).checked,v=s.task,g="",s.task&&(h=this.renderer.checkbox(l),d?0<s.tokens.length&&"text"===s.tokens[0].type?(s.tokens[0].text=h+" "+s.tokens[0].text,s.tokens[0].tokens&&0<s.tokens[0].tokens.length&&"text"===s.tokens[0].tokens[0].type&&(s.tokens[0].tokens[0].text=h+" "+s.tokens[0].tokens[0].text)):s.tokens.unshift({type:"text",text:h}):g+=h),g+=this.parse(s.tokens,d),u+=this.renderer.listitem(g,v,l);_+=this.renderer.list(u,p,k);continue;case"html":_+=this.renderer.html(f.text);continue;case"paragraph":_+=this.renderer.paragraph(this.parseInline(f.tokens));continue;case"text":for(u=f.tokens?this.parseInline(f.tokens):f.text;b+1<m&&"text"===e[b+1].type;)u+="\n"+((f=e[++b]).tokens?this.parseInline(f.tokens):f.text);_+=n?this.renderer.paragraph(u):u;continue;default:var k='Token with "'+f.type+'" type was not found.';if(this.options.silent)return void console.error(k);throw new Error(k)}return _},i.prototype.parseInline=function(e,n){n=n||this.renderer;for(var i,o="",t=e.length,a=0;a<t;a++)switch((i=e[a]).type){case"escape":o+=n.text(i.text);break;case"html":o+=n.html(i.text);break;case"link":o+=n.link(i.href,i.title,this.parseInline(i.tokens,n));break;case"image":o+=n.image(i.href,i.title,i.text);break;case"strong":o+=n.strong(this.parseInline(i.tokens,n));break;case"em":o+=n.em(this.parseInline(i.tokens,n));break;case"codespan":o+=n.codespan(i.text);break;case"br":o+=n.br();break;case"del":o+=n.del(this.parseInline(i.tokens,n));break;case"text":o+=n.text(i.text);break;default:var r='Token with "'+i.type+'" type was not found.';if(this.options.silent)return void console.error(r);throw new Error(r)}return o},i}(),bn=Ue,kn=Ye,wn=Me,Me=we.getDefaults,yn=we.changeDefaults,we=we.defaults;function xn(e,i,o){if(null==e)throw new Error("marked(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");if("function"==typeof i&&(o=i,i=null),i=bn({},xn.defaults,i||{}),kn(i),o){var t,a=i.highlight;try{t=fn.lex(e,i)}catch(e){return o(e)}function r(n){var e;if(!n)try{e=mn.parse(t,i)}catch(e){n=e}return i.highlight=a,n?o(n):o(null,e)}if(!a||a.length<3)return r();if(delete i.highlight,!t.length)return r();var c=0;return xn.walkTokens(t,function(i){"code"===i.type&&(c++,setTimeout(function(){a(i.text,i.lang,function(e,n){return e?r(e):(null!=n&&n!==i.text&&(i.text=n,i.escaped=!0),void(0===--c&&r()))})},0))}),void(0===c&&r())}try{var n=fn.lex(e,i);return i.walkTokens&&xn.walkTokens(n,i.walkTokens),mn.parse(n,i)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",i.silent)return"<p>An error occurred:</p><pre>"+wn(e.message+"",!0)+"</pre>";throw e}}xn.options=xn.setOptions=function(e){return bn(xn.defaults,e),yn(xn.defaults),xn},xn.getDefaults=Me,xn.defaults=we,xn.use=function(a){var n,e=bn({},a);if(a.renderer){var i,r=xn.defaults.renderer||new sn;for(i in a.renderer)!function(o){var t=r[o];r[o]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.renderer[o].apply(r,e);return i=!1===i?t.apply(r,e):i}}(i);e.renderer=r}if(a.tokenizer){var t,c=xn.defaults.tokenizer||new nn;for(t in a.tokenizer)!function(){var o=c[t];c[t]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.tokenizer[t].apply(c,e);return i=!1===i?o.apply(c,e):i}}();e.tokenizer=c}a.walkTokens&&(n=xn.defaults.walkTokens,e.walkTokens=function(e){a.walkTokens(e),n&&n(e)}),xn.setOptions(e)},xn.walkTokens=function(e,n){for(var i=0,o=e;i<o.length;i+=1){var t=o[i];switch(n(t),t.type){case"table":for(var a=0,r=t.tokens.header;a<r.length;a+=1){var c=r[a];xn.walkTokens(c,n)}for(var u=0,f=t.tokens.cells;u<f.length;u+=1)for(var p=0,d=f[u];p<d.length;p+=1){var g=d[p];xn.walkTokens(g,n)}break;case"list":xn.walkTokens(t.items,n);break;default:t.tokens&&xn.walkTokens(t.tokens,n)}}},xn.parseInline=function(e,n){if(null==e)throw new Error("marked.parseInline(): input parameter is undefined or null");if("string"!=typeof e)throw new Error("marked.parseInline(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");n=bn({},xn.defaults,n||{}),kn(n);try{var i=fn.lexInline(e,n);return n.walkTokens&&xn.walkTokens(i,n.walkTokens),mn.parseInline(i,n)}catch(e){if(e.message+="\nPlease report this to https://github.com/markedjs/marked.",n.silent)return"<p>An error occurred:</p><pre>"+wn(e.message+"",!0)+"</pre>";throw e}},xn.Parser=mn,xn.parser=mn.parse,xn.Renderer=sn,xn.TextRenderer=ln,xn.Lexer=fn,xn.lexer=fn.lex,xn.Tokenizer=nn,xn.Slugger=vn;var Sn=xn.parse=xn;function An(e,i){if(void 0===i&&(i='<ul class="app-sub-sidebar">{inner}</ul>'),!e||!e.length)return"";var o="";return e.forEach(function(e){var n=e.title.replace(/(<([^>]+)>)/g,"");o+='<li><a class="section-link" href="'+e.slug+'" title="'+n+'">'+e.title+"</a></li>",e.children&&(o+=An(e.children,i))}),i.replace("{inner}",o)}function $n(e,n){return'<p class="'+e+'">'+n.slice(5).trim()+"</p>"}function zn(e,o){var t=[],a={};return e.forEach(function(e){var n=e.level||1,i=n-1;o<n||(a[i]?a[i].children=(a[i].children||[]).concat(e):t.push(e),a[n]=e)}),t}var Fn={},En=/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g;function Tn(e){return e.toLowerCase()}function Cn(e){if("string"!=typeof e)return"";var n=e.trim().replace(/[A-Z]+/g,Tn).replace(/<[^>]+>/g,"").replace(En,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),e=Fn[n],e=u.call(Fn,n)?e+1:0;return n=(Fn[n]=e)?n+"-"+e:n}Cn.clear=function(){Fn={}};var Rn={baseURL:"https://github.githubassets.com/images/icons/emoji/",data:{100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"}};function jn(e,t){return e.replace(/<(code|pre|script|template)[^>]*?>[\s\S]+?<\/(code|pre|script|template)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/<!--[\s\S]+?-->/g,function(e){return e.replace(/:/g,"__colon__")}).replace(/([a-z]{2,}:)?\/\/[^\s'">)]+/gi,function(e){return e.replace(/:/g,"__colon__")}).replace(/:([a-z0-9_\-+]+?):/g,function(e,n){return i=e,o=n,e=t,n=Rn.data[o],i,i=n?e&&/unicode/.test(n)?'<span class="emoji">'+n.replace("unicode/","").replace(/\.png.*/,"").split("-").map(function(e){return"&#x"+e+";"}).join("&zwj;").concat("&#xFE0E;")+"</span>":'<img src="'+Rn.baseURL+n+'.png" alt="'+o+'" class="emoji" loading="lazy">':i;var i,o}).replace(/__colon__/g,":")}function On(e){var o={};return{str:e=(e=void 0===e?"":e)&&e.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,i){return-1===n.indexOf(":")?(o[n]=i&&i.replace(/&quot;/g,"")||!0,""):e}).trim(),config:o}}function Ln(e){return(e=void 0===e?"":e).replace(/(<\/?a.*?>)/gi,"")}var qn,Pn=be(function(e){var u,f,p,d,n,g=function(u){var i=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,e={},T={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof C?new C(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,"__id",{value:++n}),e.__id},clone:function i(e,o){var t,n;switch(o=o||{},T.util.type(e)){case"Object":if(n=T.util.objId(e),o[n])return o[n];for(var a in t={},o[n]=t,e)e.hasOwnProperty(a)&&(t[a]=i(e[a],o));return t;case"Array":return(n=T.util.objId(e),o[n])?o[n]:(t=[],o[n]=t,e.forEach(function(e,n){t[n]=i(e,o)}),t);default:return e}},getLanguage:function(e){for(;e;){var n=i.exec(e.className);if(n)return n[1].toLowerCase();e=e.parentElement}return"none"},setLanguage:function(e,n){e.className=e.className.replace(RegExp(i,"gi"),""),e.classList.add("language-"+n)},currentScript:function(){if("undefined"==typeof document)return null;if("currentScript"in document)return document.currentScript;try{throw new Error}catch(e){var n=(/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(e.stack)||[])[1];if(n){var i,o=document.getElementsByTagName("script");for(i in o)if(o[i].src==n)return o[i]}return null}},isActive:function(e,n,i){for(var o="no-"+n;e;){var t=e.classList;if(t.contains(n))return!0;if(t.contains(o))return!1;e=e.parentElement}return!!i}},languages:{plain:e,plaintext:e,text:e,txt:e,extend:function(e,n){var i,o=T.util.clone(T.languages[e]);for(i in n)o[i]=n[i];return o},insertBefore:function(i,e,n,o){var t,a=(o=o||T.languages)[i],r={};for(t in a)if(a.hasOwnProperty(t)){if(t==e)for(var c in n)n.hasOwnProperty(c)&&(r[c]=n[c]);n.hasOwnProperty(t)||(r[t]=a[t])}var u=o[i];return o[i]=r,T.languages.DFS(T.languages,function(e,n){n===u&&e!=i&&(this[e]=r)}),r},DFS:function e(n,i,o,t){t=t||{};var a,r,c,u=T.util.objId;for(a in n)n.hasOwnProperty(a)&&(i.call(n,a,n[a],o||a),r=n[a],"Object"!==(c=T.util.type(r))||t[u(r)]?"Array"!==c||t[u(r)]||(t[u(r)]=!0,e(r,i,a,t)):(t[u(r)]=!0,e(r,i,null,t)))}},plugins:{},highlightAll:function(e,n){T.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,i){var o={callback:i,container:e,selector:'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'};T.hooks.run("before-highlightall",o),o.elements=Array.prototype.slice.apply(o.container.querySelectorAll(o.selector)),T.hooks.run("before-all-elements-highlight",o);for(var t,a=0;t=o.elements[a++];)T.highlightElement(t,!0===n,o.callback)},highlightElement:function(e,n,i){var o=T.util.getLanguage(e),t=T.languages[o];T.util.setLanguage(e,o);var a=e.parentElement;a&&"pre"===a.nodeName.toLowerCase()&&T.util.setLanguage(a,o);var r={element:e,language:o,grammar:t,code:e.textContent};function c(e){r.highlightedCode=e,T.hooks.run("before-insert",r),r.element.innerHTML=r.highlightedCode,T.hooks.run("after-highlight",r),T.hooks.run("complete",r),i&&i.call(r.element)}if(T.hooks.run("before-sanity-check",r),(a=r.element.parentElement)&&"pre"===a.nodeName.toLowerCase()&&!a.hasAttribute("tabindex")&&a.setAttribute("tabindex","0"),!r.code)return T.hooks.run("complete",r),void(i&&i.call(r.element));T.hooks.run("before-highlight",r),r.grammar?n&&u.Worker?((n=new Worker(T.filename)).onmessage=function(e){c(e.data)},n.postMessage(JSON.stringify({language:r.language,code:r.code,immediateClose:!0}))):c(T.highlight(r.code,r.grammar,r.language)):c(T.util.encode(r.code))},highlight:function(e,n,i){i={code:e,grammar:n,language:i};if(T.hooks.run("before-tokenize",i),!i.grammar)throw new Error('The language "'+i.language+'" has no grammar.');return i.tokens=T.tokenize(i.code,i.grammar),T.hooks.run("after-tokenize",i),C.stringify(T.util.encode(i.tokens),i.language)},tokenize:function(e,n){var i=n.rest;if(i){for(var o in i)n[o]=i[o];delete n.rest}var t=new a;return j(t,t.head,e),function e(n,i,o,t,a,r){for(var c in o)if(o.hasOwnProperty(c)&&o[c]){var u=o[c];u=Array.isArray(u)?u:[u];for(var f=0;f<u.length;++f){if(r&&r.cause==c+","+f)return;var p,d=u[f],g=d.inside,s=!!d.lookbehind,l=!!d.greedy,v=d.alias;l&&!d.pattern.global&&(p=d.pattern.toString().match(/[imsuy]*$/)[0],d.pattern=RegExp(d.pattern.source,p+"g"));for(var h=d.pattern||d,_=t.next,m=a;_!==i.tail&&!(r&&m>=r.reach);m+=_.value.length,_=_.next){var b=_.value;if(i.length>n.length)return;if(!(b instanceof C)){var k,w=1;if(l){if(!(k=R(h,m,n,s))||k.index>=n.length)break;var y=k.index,x=k.index+k[0].length,S=m;for(S+=_.value.length;S<=y;)_=_.next,S+=_.value.length;if(S-=_.value.length,m=S,_.value instanceof C)continue;for(var A=_;A!==i.tail&&(S<x||"string"==typeof A.value);A=A.next)w++,S+=A.value.length;w--,b=n.slice(m,S),k.index-=m}else if(!(k=R(h,0,b,s)))continue;var y=k.index,$=k[0],z=b.slice(0,y),F=b.slice(y+$.length),E=m+b.length;r&&E>r.reach&&(r.reach=E);b=_.prev;z&&(b=j(i,b,z),m+=z.length),O(i,b,w);$=new C(c,g?T.tokenize($,g):$,v,$);_=j(i,b,$),F&&j(i,_,F),1<w&&(E={cause:c+","+f,reach:E},e(n,i,o,_.prev,m,E),r&&E.reach>r.reach&&(r.reach=E.reach))}}}}}(e,t,n,t.head,0),function(e){var n=[],i=e.head.next;for(;i!==e.tail;)n.push(i.value),i=i.next;return n}(t)},hooks:{all:{},add:function(e,n){var i=T.hooks.all;i[e]=i[e]||[],i[e].push(n)},run:function(e,n){var i=T.hooks.all[e];if(i&&i.length)for(var o,t=0;o=i[t++];)o(n)}},Token:C};function C(e,n,i,o){this.type=e,this.content=n,this.alias=i,this.length=0|(o||"").length}function R(e,n,i,o){e.lastIndex=n;i=e.exec(i);return i&&o&&i[1]&&(o=i[1].length,i.index+=o,i[0]=i[0].slice(o)),i}function a(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function j(e,n,i){var o=n.next,i={value:i,prev:n,next:o};return n.next=i,o.prev=i,e.length++,i}function O(e,n,i){for(var o=n.next,t=0;t<i&&o!==e.tail;t++)o=o.next;(n.next=o).prev=n,e.length-=t}if(u.Prism=T,C.stringify=function n(e,i){if("string"==typeof e)return e;if(Array.isArray(e)){var o="";return e.forEach(function(e){o+=n(e,i)}),o}var t={type:e.type,content:n(e.content,i),tag:"span",classes:["token",e.type],attributes:{},language:i},e=e.alias;e&&(Array.isArray(e)?Array.prototype.push.apply(t.classes,e):t.classes.push(e)),T.hooks.run("wrap",t);var a,r="";for(a in t.attributes)r+=" "+a+'="'+(t.attributes[a]||"").replace(/"/g,"&quot;")+'"';return"<"+t.tag+' class="'+t.classes.join(" ")+'"'+r+">"+t.content+"</"+t.tag+">"},!u.document)return u.addEventListener&&(T.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,e=n.code,n=n.immediateClose;u.postMessage(T.highlight(e,T.languages[i],i)),n&&u.close()},!1)),T;var o=T.util.currentScript();function t(){T.manual||T.highlightAll()}return o&&(T.filename=o.src,o.hasAttribute("data-manual")&&(T.manual=!0)),T.manual||("loading"===(e=document.readyState)||"interactive"===e&&o&&o.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)),T}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=g),void 0!==me&&(me.Prism=g),g.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\s\S])*?-->/,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},g.languages.markup.tag.inside["attr-value"].inside.entity=g.languages.markup.entity,g.languages.markup.doctype.inside["internal-subset"].inside=g.languages.markup,g.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&amp;/,"&"))}),Object.defineProperty(g.languages.markup.tag,"addInlined",{value:function(e,n){var i={};i["language-"+n]={pattern:/(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,lookbehind:!0,inside:g.languages[n]},i.cdata=/^<!\[CDATA\[|\]\]>$/i;i={"included-cdata":{pattern:/<!\[CDATA\[[\s\S]*?\]\]>/i,inside:i}};i["language-"+n]={pattern:/[\s\S]+/,inside:g.languages[n]};n={};n[e]={pattern:RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:i},g.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(g.languages.markup.tag,"addAttribute",{value:function(e,n){g.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:g.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),g.languages.html=g.languages.markup,g.languages.mathml=g.languages.markup,g.languages.svg=g.languages.markup,g.languages.xml=g.languages.extend("markup",{}),g.languages.ssml=g.languages.xml,g.languages.atom=g.languages.xml,g.languages.rss=g.languages.xml,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;e=e.languages.markup;e&&(e.tag.addInlined("style","css"),e.tag.addAttribute("style","css"))}(g),g.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},g.languages.javascript=g.languages.extend("clike",{"class-name":[g.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),g.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,g.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:g.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:g.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:g.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:g.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:g.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),g.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:g.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),g.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),g.languages.markup&&(g.languages.markup.tag.addInlined("script","javascript"),g.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),g.languages.js=g.languages.javascript,void 0!==g&&"undefined"!=typeof document&&(Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),u={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},d="pre[data-src]:not(["+(f="data-src-status")+'="loaded"]):not(['+f+'="'+(p="loading")+'"])',g.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),g.hooks.add("before-sanity-check",function(e){var t,n,i,o,a,r,c=e.element;c.matches(d)&&(e.code="",c.setAttribute(f,p),(t=c.appendChild(document.createElement("CODE"))).textContent="Loading…",i=c.getAttribute("data-src"),"none"===(e=e.language)&&(n=(/\.(\w+)$/.exec(i)||[,"none"])[1],e=u[n]||n),g.util.setLanguage(t,e),g.util.setLanguage(c,e),(n=g.plugins.autoloader)&&n.loadLanguages(e),i=i,o=function(e){c.setAttribute(f,"loaded");var n,i,o=function(e){if(i=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(e||"")){var n=Number(i[1]),e=i[2],i=i[3];return e?i?[n,Number(i)]:[n,void 0]:[n,n]}}(c.getAttribute("data-range"));o&&(n=e.split(/\r\n?|\n/g),i=o[0],o=null==o[1]?n.length:o[1],i<0&&(i+=n.length),i=Math.max(0,Math.min(i-1,n.length)),o<0&&(o+=n.length),o=Math.max(0,Math.min(o,n.length)),e=n.slice(i,o).join("\n"),c.hasAttribute("data-start")||c.setAttribute("data-start",String(i+1))),t.textContent=e,g.highlightElement(t)},a=function(e){c.setAttribute(f,"failed"),t.textContent=e},(r=new XMLHttpRequest).open("GET",i,!0),r.onreadystatechange=function(){4==r.readyState&&(r.status<400&&r.responseText?o(r.responseText):400<=r.status?a("✖ Error "+r.status+" while fetching file: "+r.statusText):a("✖ Error: File does not exist or is empty"))},r.send(null))}),n=!(g.plugins.fileHighlight={highlight:function(e){for(var n,i=(e||document).querySelectorAll(d),o=0;n=i[o++];)g.highlightElement(n)}}),g.fileHighlight=function(){n||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),n=!0),g.plugins.fileHighlight.highlight.apply(this,arguments)})});function Mn(e,n){return"___"+e.toUpperCase()+n+"___"}qn=Prism,Object.defineProperties(qn.languages["markup-templating"]={},{buildPlaceholders:{value:function(o,t,e,a){var r;o.language===t&&(r=o.tokenStack=[],o.code=o.code.replace(e,function(e){if("function"==typeof a&&!a(e))return e;for(var n,i=r.length;-1!==o.code.indexOf(n=Mn(t,i));)++i;return r[i]=e,n}),o.grammar=qn.languages.markup)}},tokenizePlaceholders:{value:function(f,p){var d,g;f.language===p&&f.tokenStack&&(f.grammar=qn.languages[p],d=0,g=Object.keys(f.tokenStack),function e(n){for(var i=0;i<n.length&&!(d>=g.length);i++){var o,t,a,r,c,u=n[i];"string"==typeof u||u.content&&"string"==typeof u.content?(t=g[d],a=f.tokenStack[t],o="string"==typeof u?u:u.content,c=Mn(p,t),-1<(r=o.indexOf(c))&&(++d,t=o.substring(0,r),a=new qn.Token(p,qn.tokenize(a,f.grammar),"language-"+p,a),r=o.substring(r+c.length),c=[],t&&c.push.apply(c,e([t])),c.push(a),r&&c.push.apply(c,e([r])),"string"==typeof u?n.splice.apply(n,[i,1].concat(c)):u.content=c)):u.content&&e(u.content)}return n}(f.tokens))}}});function In(t,e){var a=this;this.config=t,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=t.externalLinkTarget||"_blank",this.linkRel="_blank"===this.linkTarget?t.externalLinkRel||"noopener":"",this.contentBase=e.getBasePath();var n=this._initRenderer();this.heading=n.heading;var r=o(e=t.markdown||{})?e(Sn,n):(Sn.setOptions(m(e,{renderer:m(n,e.renderer)})),Sn);this._marked=r,this.compile=function(i){var o=!0,e=c(function(e){o=!1;var n="";return i&&(n=f(i)?r(i):r.parser(i),n=t.noEmoji?n:jn(n,t.nativeEmoji),Cn.clear(),n)})(i),n=a.router.parse().file;return o?a.toc=a.cacheTOC[n]:a.cacheTOC[n]=[].concat(a.toc),e}}var Nn={},Hn={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,n){return{html:'<iframe src="'+e+'" '+(n||"width=100% height=400")+"></iframe>"}},video:function(e,n){return{html:'<video src="'+e+'" '+(n||"controls")+">Not Support</video>"}},audio:function(e,n){return{html:'<audio src="'+e+'" '+(n||"controls")+">Not Support</audio>"}},code:function(e,n){var i=e.match(/\.(\w+)$/);return{url:e,lang:i="md"===(i=n||i&&i[1])?"markdown":i}}};In.prototype.compileEmbed=function(e,n){var i,o,t=On(n),a=t.str,t=t.config;if(n=a,t.include)return T(e)||(e=q(this.contentBase,R(this.router.getCurrentPath()),e)),t.type&&(o=Hn[t.type])?(i=o.call(this,e,n)).type=t.type:(o="code",/\.(md|markdown)/.test(e)?o="markdown":/\.mmd/.test(e)?o="mermaid":/\.html?/.test(e)?o="iframe":/\.(mp4|ogg)/.test(e)?o="video":/\.mp3/.test(e)&&(o="audio"),(i=Hn[o].call(this,e,n)).type=o),i.fragment=t.fragment,i},In.prototype._matchNotCompileLink=function(e){for(var n=this.config.noCompileLinks||[],i=0;i<n.length;i++){var o=n[i];if((Nn[o]||(Nn[o]=new RegExp("^"+o+"$"))).test(e))return e}},In.prototype._initRenderer=function(){var r,c,u,f,p,d,e=new Sn.Renderer,n=this.linkTarget,i=this.linkRel,a=this.router,o=this.contentBase,g=this,t={};return t.heading=e.heading=function(e,n){var i=On(e),o=i.str,t=i.config,e={level:n,title:Ln(o)};/<!-- {docsify-ignore} -->/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore} --\x3e",""),e.title=Ln(o),e.ignoreSubHeading=!0),/{docsify-ignore}/g.test(o)&&(o=o.replace("{docsify-ignore}",""),e.title=Ln(o),e.ignoreSubHeading=!0),/<!-- {docsify-ignore-all} -->/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore-all} --\x3e",""),e.title=Ln(o),e.ignoreAllSubs=!0),/{docsify-ignore-all}/g.test(o)&&(o=o.replace("{docsify-ignore-all}",""),e.title=Ln(o),e.ignoreAllSubs=!0);i=Cn(t.id||o),t=a.toURL(a.getCurrentPath(),{id:i});return e.slug=t,g.toc.push(e),"<h"+n+' id="'+i+'"><a href="'+t+'" data-id="'+i+'" class="anchor"><span>'+o+"</span></a></h"+n+">"},t.code={renderer:e}.renderer.code=function(e,n){var i=Pn.languages[n=void 0===n?"markup":n]||Pn.languages.markup;return'<pre v-pre data-lang="'+n+'"><code class="lang-'+n+'">'+Pn.highlight(e.replace(/@DOCSIFY_QM@/g,"`"),i,n)+"</code></pre>"},t.link=(i=(n={renderer:e,router:a,linkTarget:n,linkRel:i,compilerClass:g}).renderer,c=n.router,u=n.linkTarget,n.linkRel,f=n.compilerClass,i.link=function(e,n,i){var o=[],t=On(n=void 0===n?"":n),a=t.str,t=t.config;return u=t.target||u,r="_blank"===u?f.config.externalLinkRel||"noopener":"",n=a,T(e)||f._matchNotCompileLink(e)||t.ignore?(T(e)||"./"!==e.slice(0,2)||(e=document.URL.replace(/\/(?!.*\/).*/,"/").replace("#/./","")+e),o.push(0===e.indexOf("mailto:")?"":'target="'+u+'"'),o.push(0!==e.indexOf("mailto:")&&""!==r?' rel="'+r+'"':"")):(e===f.config.homepage&&(e="README"),e=c.toURL(e,null,c.getCurrentPath())),t.crossorgin&&"_self"===u&&"history"===f.config.routerMode&&-1===f.config.crossOriginLinks.indexOf(e)&&f.config.crossOriginLinks.push(e),t.disabled&&(o.push("disabled"),e="javascript:void(0)"),t.class&&o.push('class="'+t.class+'"'),t.id&&o.push('id="'+t.id+'"'),n&&o.push('title="'+n+'"'),'<a href="'+e+'" '+o.join(" ")+">"+i+"</a>"}),t.paragraph={renderer:e}.renderer.paragraph=function(e){e=/^!&gt;/.test(e)?$n("tip",e):/^\?&gt;/.test(e)?$n("warn",e):"<p>"+e+"</p>";return e},t.image=(o=(i={renderer:e,contentBase:o,router:a}).renderer,p=i.contentBase,d=i.router,o.image=function(e,n,i){var o=e,t=[],a=On(n),r=a.str,a=a.config;return n=r,a["no-zoom"]&&t.push("data-no-zoom"),n&&t.push('title="'+n+'"'),a.size&&(n=(r=a.size.split("x"))[0],(r=r[1])?t.push('width="'+n+'" height="'+r+'"'):t.push('width="'+n+'"')),a.class&&t.push('class="'+a.class+'"'),a.id&&t.push('id="'+a.id+'"'),T(e)||(o=q(p,R(d.getCurrentPath()),e)),0<t.length?'<img src="'+o+'" data-origin="'+e+'" alt="'+i+'" '+t.join(" ")+" />":'<img src="'+o+'" data-origin="'+e+'" alt="'+i+'"'+t+">"}),t.list={renderer:e}.renderer.list=function(e,n,i){n=n?"ol":"ul";return"<"+n+" "+[/<li class="task-list-item">/.test(e.split('class="task-list"')[0])?'class="task-list"':"",i&&1<i?'start="'+i+'"':""].join(" ").trim()+">"+e+"</"+n+">"},t.listitem={renderer:e}.renderer.listitem=function(e){return/^(<input.*type="checkbox"[^>]*>)/.test(e)?'<li class="task-list-item"><label>'+e+"</label></li>":"<li>"+e+"</li>"},e.origin=t,e},In.prototype.sidebar=function(e,n){var i=this.toc,o=this.router.getCurrentPath(),t="";if(e)t=this.compile(e);else{for(var a=0;a<i.length;a++)if(i[a].ignoreSubHeading){var r=i[a].level;i.splice(a,1);for(var c=a;c<i.length&&r<i[c].level;c++)i.splice(c,1)&&c--&&a++;a--}n=this.cacheTree[o]||zn(i,n),t=An(n,"<ul>{inner}</ul>");this.cacheTree[o]=n}return t},In.prototype.subSidebar=function(e){if(e){var n=this.router.getCurrentPath(),i=this.cacheTree,o=this.toc;o[0]&&o[0].ignoreAllSubs&&o.splice(0),o[0]&&1===o[0].level&&o.shift();for(var t=0;t<o.length;t++)o[t].ignoreSubHeading&&o.splice(t,1)&&t--;e=i[n]||zn(o,e);return i[n]=e,this.toc=[],An(e)}this.toc=[]},In.prototype.header=function(e,n){return this.heading(e,n)},In.prototype.article=function(e){return this.compile(e)},In.prototype.cover=function(e){var n=this.toc.slice(),e=this.compile(e);return this.toc=n.slice(),e};function Dn(e){var n=Zn(e);return 0===n?e:(n=new RegExp("^[ \\t]{"+n+"}","gm"),e.replace(n,""))}var Un,Zn=function(e){e=e.match(/^[ \t]*(?=\S)/gm);return e?e.reduce(function(e,n){return Math.min(e,n.length)},1/0):0},Bn={};function Vn(e,o){var a=e.compiler,t=e.raw;void 0===t&&(t="");var n=e.fetch,e=Bn[t];if(e){var i=e.slice();return i.links=e.links,o(i)}var i=a._marked,r=i.lexer(t),c=[],u=i.Lexer.rules.inline.link,f=r.links;r.forEach(function(e,t){"paragraph"===e.type&&(e.text=e.text.replace(new RegExp(u.source,"g"),function(e,n,i,o){o=a.compileEmbed(i,o);return o&&c.push({index:t,embed:o}),e}))});var p=[];!function(e,a){var n,i=e.embedTokens,r=e.compile,c=(e.fetch,0),u=1;if(!i.length)return a({});for(;n=i[c++];){var o=function(t){return function(e){var n,i,o;e&&("markdown"===t.embed.type?((i=t.embed.url.split("/")).pop(),i=i.join("/"),e=e.replace(/\[([^[\]]+)\]\(([^)]+)\)/g,function(e){var n=e.indexOf("(");return"(."===e.slice(n,n+2)?e.substring(0,n)+"("+window.location.protocol+"//"+window.location.host+i+"/"+e.substring(n+1,e.length-1)+")":e}),!0===(($docsify.frontMatter||{}).installed||!1)&&(e=$docsify.frontMatter.parseMarkdown(e)),n=r.lexer(e)):"code"===t.embed.type?(t.embed.fragment&&(o=t.embed.fragment,o=new RegExp("(?:###|\\/\\/\\/)\\s*\\["+o+"\\]([\\s\\S]*)(?:###|\\/\\/\\/)\\s*\\["+o+"\\]"),e=Dn((e.match(o)||[])[1]||"").trim()),n=r.lexer("```"+t.embed.lang+"\n"+e.replace(/`/g,"@DOCSIFY_QM@")+"\n```\n")):"mermaid"===t.embed.type?(n=[{type:"html",text:'<div class="mermaid">\n'+e+"\n</div>"}]).links={}:(n=[{type:"html",text:e}]).links={}),a({token:t,embedToken:n}),++u>=c&&a({})}}(n);n.embed.url?X(n.embed.url).then(o):o(n.embed.html)}}({compile:i,embedTokens:c,fetch:n},function(e){var n,i=e.embedToken,e=e.token;e?(n=e.index,p.forEach(function(e){n>e.start&&(n+=e.length)}),m(f,i.links),r=r.slice(0,n).concat(i,r.slice(n+1)),p.push({start:n,length:i.length-1})):(Bn[t]=r.concat(),r.links=Bn[t].links=f,o(r))})}function Yn(e,n,i){var o,t,a,r;return n="function"==typeof i?i(n):"string"==typeof i?(a=[],r=0,(o=i).replace(V,function(n,e,i){a.push(o.substring(r,i-1)),r=i+=n.length+1,a.push(t&&t[n]||function(e){return("00"+("string"==typeof Y[n]?e[Y[n]]():Y[n](e))).slice(-n.length)})}),r!==o.length&&a.push(o.substring(r)),function(e){for(var n="",i=0,o=e||new Date;i<a.length;i++)n+="string"==typeof a[i]?a[i]:a[i](o);return n}(new Date(n))):n,e.replace(/{docsify-updated}/g,n)}function Gn(e){function n(e){var n=Boolean(e.__vue__&&e.__vue__._isVue),e=Boolean(e._vnode&&e._vnode.__v_skip);return n||e}var i=this.config,o=b(".markdown-section"),t="Vue"in window&&window.Vue.version&&Number(window.Vue.version.charAt(0));if(e=e||"<h1>404 - Not found</h1>","Vue"in window)for(var a=0,r=k(".markdown-section > *").filter(n);a<r.length;a+=1){var c=r[a];2===t?c.__vue__.$destroy():3===t&&c.__vue_app__.unmount()}if(this._renderTo(o,e),i.loadSidebar||this._renderSidebar(),(i.executeScript||"Vue"in window&&!1!==i.executeScript)&&(!(e=k(".markdown-section>script").filter(function(e){return!/template/.test(e.type)})[0])||(e=e.innerText.trim())&&new Function(e)()),"Vue"in window){var u,f,p=[],d=Object.keys(i.vueComponents||{});2===t&&d.length&&d.forEach(function(e){window.Vue.options.components[e]||window.Vue.component(e,i.vueComponents[e])}),!Un&&i.vueGlobalOptions&&"function"==typeof i.vueGlobalOptions.data&&(Un=i.vueGlobalOptions.data()),p.push.apply(p,Object.keys(i.vueMounts||{}).map(function(e){return[b(o,e),i.vueMounts[e]]}).filter(function(e){var n=e[0];e[1];return n})),(i.vueGlobalOptions||d.length)&&(u=/{{2}[^{}]*}{2}/,f=/<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/,p.push.apply(p,k(".markdown-section > *").filter(function(i){return!p.some(function(e){var n=e[0];e[1];return n===i})}).filter(function(e){return e.tagName.toLowerCase()in(i.vueComponents||{})||e.querySelector(d.join(",")||null)||u.test(e.outerHTML)||f.test(e.outerHTML)}).map(function(e){var n=m({},i.vueGlobalOptions||{});return Un&&(n.data=function(){return Un}),[e,n]})));for(var g=0,s=p;g<s.length;g+=1){var l,v=s[g],h=v[0],_=v[1],v="data-isvue";h.matches("pre, script")||n(h)||h.querySelector("["+v+"]")||(h.setAttribute(v,""),2===t?(_.el=void 0,new window.Vue(_).$mount(h)):3===t&&(l=window.Vue.createApp(_),d.forEach(function(e){var n=i.vueComponents[e];l.component(e,n)}),l.mount(h)))}}}function Wn(n,i,o,t,a,e){n=e?n:n.replace(/\/$/,""),(n=R(n))&&X(a.router.getFile(n+o)+i,!1,a.config.requestHeaders).then(t,function(e){return Wn(n,i,o,t,a)})}function Xn(){var n=function(){return null};return[function(e){n(e)},function(e){n=e}]}Me=Object.freeze({__proto__:null,cached:c,hyphenate:a,hasOwn:u,merge:m,isPrimitive:f,noop:d,isFn:o,isExternal:g,inBrowser:!0,isMobile:s,supportsPushState:t,parseQuery:F,stringifyQuery:E,isAbsolutePath:T,removeParams:C,getParentPath:R,cleanPath:j,resolvePath:O,getPath:q,replaceSlug:P});var Qn,Jn=function(e){function n(){e.call(this),this.config=ue(this),this.initLifecycle(),this.initPlugin(),this.callHook("init"),this.initRouter(),this.initRender(),this.initEvent(),this.initFetch(),this.callHook("mounted")}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initPlugin=function(){var n=this;[].concat(this.config.plugins).forEach(function(e){try{o(e)&&e(n._lifecycle,n)}catch(e){if(!n.config.catchPluginErrors)throw e;console.error("Docsify plugin error",e)}})},n}((we=Object,function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype._loadSideAndNav=function(e,n,i,o){var t=this;return function(){if(!i)return o();Wn(e,n,i,function(e){t._renderSidebar(e),o()},t,!0)}},n.prototype._fetch=function(i){var o=this;void 0===i&&(i=d);var t,e,n,a,r,c,u,f=this.route.query,p=this.route.path;g(p)?(history.replaceState(null,"","#"),this.router.normalize()):(t=E(f,["id"]),f=(e=this.config).loadNavbar,n=e.requestHeaders,a=e.loadSidebar,r=this.router.getFile(p),this.isRemoteUrl=g(r),this.isHTML=/\.html$/g.test(r),c=function(e,n){o._renderMain(e,n,o._loadSideAndNav(p,t,a,i))},u=function(e){o._fetchFallbackPage(p,t,i)||o._fetch404(r,t,i)},this.isRemoteUrl?Kn(r+t,0,n).then(c,u):this.matchVirtualRoute(p).then(function(e){"string"==typeof e?c(e):Kn(r+t,0,n).then(c,u)}),f&&Wn(p,t,f,function(e){return o._renderNav(e)},this,!0))},n.prototype._fetchCover=function(){var n=this,e=this.config,i=e.coverpage,o=e.requestHeaders,t=this.route.query,a=R(this.route.path);if(i){var r=null,e=this.route.path;"string"==typeof i?"/"===e&&(r=i):r=Array.isArray(i)?-1<i.indexOf(e)&&"_coverpage":!0===(e=i[e])?"_coverpage":e;var c=Boolean(r)&&this.config.onlyCover;return r?(r=this.router.getFile(a+r),this.coverIsHTML=/\.html$/g.test(r),X(r+E(t,["id"]),!1,o).then(function(e){return n._renderCover(e,c)})):this._renderCover(null,c),c}},n.prototype.$fetch=function(e,n){var i=this;void 0===e&&(e=d),void 0===n&&(n=this.$resetEvents.bind(this));function o(){i.callHook("doneEach"),e()}this._fetchCover()?o():this._fetch(function(){n(),o()})},n.prototype._fetchFallbackPage=function(i,o,t){var a=this;void 0===t&&(t=d);var e=this.config,n=e.requestHeaders,r=e.fallbackLanguages,c=e.loadSidebar;if(!r)return!1;e=i.split("/")[1];if(-1===r.indexOf(e))return!1;e=this.router.getFile(i.replace(new RegExp("^/"+e),""));return Kn(e+o,0,n).then(function(e,n){return a._renderMain(e,n,a._loadSideAndNav(i,o,c,t))},function(){return a._fetch404(i,o,t)}),!0},n.prototype._fetch404=function(e,n,i){var o=this,t=this.config,a=t.loadSidebar,r=t.requestHeaders,t=t.notFoundPage,c=this._loadSideAndNav(e,n,a,i=void 0===i?d:i);if(t){e=function(n,e){var i,o,t=e.notFoundPage,a="_404"+(e.ext||".md");switch(typeof t){case"boolean":o=a;break;case"string":o=t;break;case"object":o=(i=Object.keys(t).sort(function(e,n){return n.length-e.length}).filter(function(e){return n.match(new RegExp("^"+e))})[0])&&t[i]||a}return o}(e,this.config);return Kn(this.router.getFile(e),0,r).then(function(e,n){return o._renderMain(e,n,c)},function(){return o._renderMain(null,{},c)}),!0}return this._renderMain(null,{},c),!1},n.prototype.initFetch=function(){var e,n=this,i=this.config.loadSidebar;this.rendered?(e=ee(this.router,".sidebar-nav",!0,!0),i&&e&&(e.parentNode.innerHTML+=window.__SUB_SIDEBAR__),this._bindEventOnRendered(e),this.$resetEvents(),this.callHook("doneEach"),this.callHook("ready")):this.$fetch(function(e){return n.callHook("ready")})},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.$resetEvents=function(e){var n=this,i=this.config.auto2top;"history"!==e&&(n.route.query.id&&he(n.route.path,n.route.query.id),"navigate"===e&&i&&(i=i,_e.scrollTop=!0===(i=void 0===i?0:i)?0:Number(i))),this.config.loadNavbar&&ee(this.router,"nav")},n.prototype.initEvent=function(){function n(e){return h.classList.toggle("close")}var e;e="button.sidebar-toggle",this.router,null!=(e=l(e))&&(p(e,"click",function(e){e.stopPropagation(),n()}),s&&p(h,"click",function(e){return h.classList.contains("close")&&n()})),e=".sidebar",this.router,null!=(e=l(e))&&p(e,"click",function(e){e=e.target;"A"===e.nodeName&&e.nextSibling&&e.nextSibling.classList&&e.nextSibling.classList.contains("app-sub-sidebar")&&S(e.parentNode,"collapse")}),this.config.coverpage?s||p("scroll",K):h.classList.add("sticky")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype._renderTo=function(e,n,i){e=l(e);e&&(e[i?"outerHTML":"innerHTML"]=n)},n.prototype._renderSidebar=function(e){var n=this.config,i=n.maxLevel,o=n.subMaxLevel,t=n.loadSidebar;if(n.hideSidebar)return[document.querySelector("aside.sidebar"),document.querySelector("button.sidebar-toggle")].filter(function(e){return!!e}).forEach(function(e){return e.parentNode.removeChild(e)}),document.querySelector("section.content").style.right="unset",document.querySelector("section.content").style.left="unset",document.querySelector("section.content").style.position="relative",document.querySelector("section.content").style.width="100%",null;this._renderTo(".sidebar-nav",this.compiler.sidebar(e,i));i=ee(this.router,".sidebar-nav",!0,!0);t&&i?i.parentNode.innerHTML+=this.compiler.subSidebar(o)||"":this.compiler.subSidebar(),this._bindEventOnRendered(i)},n.prototype._bindEventOnRendered=function(e){var n,i=this.config.autoHeader;!function(e){var n=b(".cover.show");se=n?n.offsetHeight:0;for(var i,n=l(".sidebar"),o=[],t=0,a=(o=null!=n?k(n,"li"):o).length;t<a;t+=1){var r,c,u=o[t],f=u.querySelector("a");f&&("/"!==(r=f.getAttribute("href"))&&(f=(c=e.parse(r)).query.id,c=c.path,f&&(r=ve(c,f))),r&&(fe[decodeURIComponent(r)]=u))}s||(i=C(e.getCurrentPath()),x("scroll",function(){return le(i)}),p("scroll",function(){return le(i)}),p(n,"mouseover",function(){pe=!0}),p(n,"mouseleave",function(){pe=!1}))}(this.router),i&&e&&((i=(n=l("#main")).children[0])&&"H1"!==i.tagName&&y(n,w("div",this.compiler.header(e.innerText,1)).children[0]))},n.prototype._renderNav=function(e){e&&this._renderTo("nav",this.compiler.compile(e)),this.config.loadNavbar&&ee(this.router,"nav")},n.prototype._renderMain=function(o,t,a){var r=this;if(void 0===t&&(t={}),!o)return Gn.call(this,o);this.callHook("beforeEach",o,function(e){function n(){t.updatedAt&&(i=Yn(i,t.updatedAt,r.config.formatUpdated)),r.callHook("afterEach",i,function(e){Gn.call(r,e),a()})}var i;r.isHTML?(i=r.result=o,n()):Vn({compiler:r.compiler,raw:e},function(e){i=r.compiler.compile(e),n()})})},n.prototype._renderCover=function(e,n){var i,o=l(".cover");S(l("main"),n?"add":"remove","hidden"),e?(S(o,"add","show"),(n=(i=this.coverIsHTML?e:this.compiler.cover(e)).trim().match('<p><img.*?data-origin="(.*?)"[^a]+alt="(.*?)">([^<]*?)</p>$'))&&("color"===n[2]?o.style.background=n[1]+(n[3]||""):(e=n[1],S(o,"add","has-mask"),T(n[1])||(e=q(this.router.getBasePath(),n[1])),o.style.backgroundImage="url("+e+")",o.style.backgroundSize="cover",o.style.backgroundPosition="center center"),i=i.replace(n[0],"")),this._renderTo(".cover-main",i),K()):S(o,"remove","show")},n.prototype._updateRender=function(){var e,n,i,o;e=this,n=l(".app-name-link"),i=e.config.nameLink,o=e.route.path,n&&(f(e.config.nameLink)?n.setAttribute("href",i):"object"==typeof i&&(e=Object.keys(i).filter(function(e){return-1<o.indexOf(e)})[0],n.setAttribute("href",i[e])))},n.prototype.initRender=function(){var e=this.config;this.compiler=new In(e,this.router),window.__current_docsify_compiler__=this.compiler;var n,i,o,t,a,r=e.el||"#app",c=b("nav")||w("nav"),u=b(r),f="",p=h;u?(e.repo&&(f+=(t=e.repo,r=e.cornerExternalLinkTarget,t?'<a href="'+(t=(t=!/\/\//.test(t)?"https://github.com/"+t:t).replace(/^git\+/,""))+'" target="'+(r=r||"_blank")+'" class="github-corner" aria-label="View source on Github"><svg viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>':"")),e.coverpage&&(f+=(o=", 100%, 85%",'<section class="cover show" style="background: '+("linear-gradient(to left bottom, hsl("+Math.floor(255*Math.random())+o+") 0%,hsl("+Math.floor(255*Math.random())+o+") 100%)")+'"><div class="mask"></div><div class="cover-main">\x3c!--cover--\x3e</div></section>')),e.logo&&(o=/^data:image/.test(e.logo),n=/(?:http[s]?:)?\/\//.test(e.logo),i=/^\./.test(e.logo),o||n||i||(e.logo=q(this.router.getBasePath(),e.logo))),f+=(i=(n=e).name||"","<main>"+('<button class="sidebar-toggle" aria-label="Menu"><div class="sidebar-toggle-button"><span></span><span></span><span></span></div></button><aside class="sidebar">'+(n.name?'<h1 class="app-name"><a class="app-name-link" data-nosearch>'+(n.logo?'<img alt="'+i+'" src='+n.logo+">":i)+"</a></h1>":"")+'<div class="sidebar-nav">\x3c!--sidebar--\x3e</div></aside>')+'<section class="content"><article class="markdown-section" id="main">\x3c!--main--\x3e</article></section></main>'),this._renderTo(u,f,!0)):this.rendered=!0,e.mergeNavbar&&s?p=b(".sidebar"):(c.classList.add("app-nav"),e.repo||c.classList.add("no-badge")),e.loadNavbar&&y(p,c),e.themeColor&&(v.head.appendChild(w("div","<style>:root{--theme-color: "+e.themeColor+";}</style>").firstElementChild),a=e.themeColor,window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)")||(e=k("style:not(.inserted),link"),[].forEach.call(e,function(e){"STYLE"===e.nodeName?Q(e,a):"LINK"===e.nodeName&&(e=e.getAttribute("href"),/\.css$/.test(e)&&X(e).then(function(e){e=w("style",e);_.appendChild(e),Q(e,a)}))}))),this._updateRender(),S(h,"ready")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.routes=function(){return this.config.routes||{}},n.prototype.matchVirtualRoute=function(t){var a=this.routes(),r=Object.keys(a),c=function(){return null};function u(){var e=r.shift();if(!e)return c(null);var n=A(o=(i="^",0===(o=e).indexOf(i)?o:"^"+o),"$")?o:o+"$",i=t.match(n);if(!i)return u();var o=a[e];if("string"==typeof o)return c(o);if("function"!=typeof o)return u();n=o,e=Xn(),o=e[0];return(0,e[1])(function(e){return"string"==typeof e?c(e):!1===e?c(null):u()}),n.length<=2?o(n(t,i)):n(t,i,o)}return{then:function(e){c=e,u()}}},n}(function(i){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];i.apply(this,e),this.route={}}return i&&(e.__proto__=i),((e.prototype=Object.create(i&&i.prototype)).constructor=e).prototype.updateRender=function(){this.router.normalize(),this.route=this.router.parse(),h.setAttribute("data-page",this.route.file)},e.prototype.initRouter=function(){var n=this,e=this.config,e=new("history"===(e.routerMode||"hash")&&t?D:H)(e);this.router=e,this.updateRender(),U=this.route,e.onchange(function(e){n.updateRender(),n._updateRender(),U.path!==n.route.path?(n.$fetch(d,n.$resetEvents.bind(n,e.source)),U=n.route):n.$resetEvents(e.source)})},e}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initLifecycle=function(){var i=this;this._hooks={},this._lifecycle={},["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach(function(e){var n=i._hooks[e]=[];i._lifecycle[e]=function(e){return n.push(e)}})},n.prototype.callHook=function(e,t,a){void 0===a&&(a=d);var r=this._hooks[e],c=this.config.catchPluginErrors,u=function(n){var e=r[n];if(n>=r.length)a(t);else if("function"==typeof e){var i="Docsify plugin error";if(2===e.length)try{e(t,function(e){t=e,u(n+1)})}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}else try{var o=e(t);t=void 0===o?t:o,u(n+1)}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}}else u(n+1)};u(0)},n}(we))))))));function Kn(e,n,i){return Qn&&Qn.abort&&Qn.abort(),Qn=X(e,!0,i)}window.Docsify={util:Me,dom:n,get:X,slugify:Cn,version:"4.13.0"},window.DocsifyCompiler=In,window.marked=Sn,window.Prism=Pn,e(function(e){return new Jn})}();
... ...
doc/lib/js/search.min.js 0 → 100644
  1 +!function(){function u(e){return e.replace(/<!-- {docsify-ignore} -->/,"").replace(/{docsify-ignore}/,"").replace(/<!-- {docsify-ignore-all} -->/,"").replace(/{docsify-ignore-all}/,"").trim()}var f={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function g(e){var n={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function y(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function v(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function b(o,e,s,c){void 0===e&&(e="");var d,e=window.marked.lexer(e),l=window.Docsify.slugify,p={},h="";return e.forEach(function(e,n){var t,a,i,r;"heading"===e.type&&e.depth<=c?(t=(a=(i=e.text,r={},{str:i=(i=void 0===i?"":i)&&i.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(r[n]=t&&t.replace(/&quot;/g,"")||!0,""):e}).trim(),config:r})).str,i=a.config,a=u(e.text),d=i.id?s.toURL(o,{id:l(i.id)}):s.toURL(o,{id:l(g(a))}),t&&(h=u(t)),p[d]={slug:d,title:h,body:""}):(0===n&&(d=s.toURL(o),p[d]={slug:d,title:"/"!==o?o.slice(1):"Home Page",body:e.text||""}),d&&(p[d]?p[d].body?(e.text=y(e),e.text=v(e),p[d].body+="\n"+(e.text||"")):(e.text=y(e),e.text=v(e),p[d].body=p[d].body?p[d].body+e.text:e.text):p[d]={slug:d,title:"",body:""}))}),l.clear(),p}function p(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function o(e){var n=[],t=[];Object.keys(f).forEach(function(n){t=t.concat(Object.keys(f[n]).map(function(e){return f[n][e]}))});var a=(e=e.trim()).split(/[\s\-,\\/]+/);1!==a.length&&(a=[].concat(e,a));for(var i=0;i<t.length;i++)!function(e){var e=t[e],r=0,o="",s="",c="",d=e.title&&e.title.trim(),l=e.body&&e.body.trim(),e=e.slug||"";d&&(a.forEach(function(e){var n,t,a=new RegExp(g(p(e)).replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),i=-1;s=d&&g(p(d)),c=l&&g(p(l)),t=d?s.search(a):-1,i=l?c.search(a):-1,(0<=t||0<=i)&&(r+=0<=t?3:0<=i?2:0,t=(t=n=0)==(n=(i=i<0?0:i)<11?0:i-10)?70:i+e.length+60,l&&t>l.length&&(t=l.length),a=c&&"..."+c.substring(n,t).replace(a,function(e){return'<em class="search-keyword">'+e+"</em>"})+"...",o+=a)}),0<r&&(e={title:s,content:l?o:"",url:e,score:r},n.push(e)))}(i);return n.sort(function(e,n){return n.score-e.score})}function r(a,i){var t,r,n,e,o="auto"===a.paths,s=o?(t=i.router,r=[],Docsify.dom.findAll(".sidebar-nav a:not(.section-link):not([data-nosearch])").forEach(function(e){var n=e.href,e=e.getAttribute("href"),n=t.parse(n).path;n&&-1===r.indexOf(n)&&!Docsify.util.isAbsolutePath(e)&&r.push(n)}),r):a.paths,c="";s.length&&o&&a.pathNamespaces?(n=s[0],Array.isArray(a.pathNamespaces)?c=a.pathNamespaces.filter(function(e){return n.slice(0,e.length)===e})[0]||c:a.pathNamespaces instanceof RegExp&&((d=n.match(a.pathNamespaces))&&(c=d[0])),e=-1===s.indexOf(c+"/"),d=-1===s.indexOf(c+"/README"),e&&d&&s.unshift(c+"/")):-1===s.indexOf("/")&&-1===s.indexOf("/README")&&s.unshift("/");var d,l=((d=a.namespace)?m.EXPIRE_KEY+"/"+d:m.EXPIRE_KEY)+c,p=((d=a.namespace)?m.INDEX_KEY+"/"+d:m.INDEX_KEY)+c,c=localStorage.getItem(l)<Date.now();if(f=JSON.parse(localStorage.getItem(p)),c)f={};else if(!o)return;var h=s.length,u=0;s.forEach(function(t){return f[t]?u++:void Docsify.get(i.router.getFile(t),!1,i.config.requestHeaders).then(function(e){var n;f[t]=b(t,e,i.router,a.depth),h===++u&&(n=a.maxAge,e=p,localStorage.setItem(l,Date.now()+n),localStorage.setItem(e,JSON.stringify(f)))})})}var s,c="";function d(e){var n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,".results-panel"),a=Docsify.dom.find(n,".clear-button"),i=Docsify.dom.find(".sidebar-nav"),n=Docsify.dom.find(".app-name");if(!e)return t.classList.remove("show"),a.classList.remove("show"),t.innerHTML="",void(s.hideOtherSidebarContent&&(i&&i.classList.remove("hide"),n&&n.classList.remove("hide")));var e=o(e),r="";e.forEach(function(e){r+='<div class="matching-post">\n<a href="'+e.url+'">\n<h2>'+e.title+"</h2>\n<p>"+e.content+"</p>\n</a>\n</div>"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'<p class="empty">'+c+"</p>",s.hideOtherSidebarContent&&(i&&i.classList.add("hide"),n&&n.classList.add("hide"))}function l(e){s=e}function h(e,n){var t,a,i=n.router.parse().query.s;l(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n=Docsify.dom.create("div",'<div class="input-wrap">\n <input type="search" value="'+e+'" aria-label="Search text" />\n <div class="clear-button">\n <svg width="26" height="24">\n <circle cx="12" cy="12" r="11" fill="#ccc" />\n <path stroke="white" stroke-width="2" d="M8.25,8.25,15.75,15.75" />\n <path stroke="white" stroke-width="2"d="M8.25,15.75,15.75,8.25" />\n </svg>\n </div>\n </div>\n <div class="results-panel"></div>\n </div>'),e=Docsify.dom.find("aside");Docsify.dom.toggleClass(n,"search"),Docsify.dom.before(e,n)}(i),n=Docsify.dom.find("div.search"),a=Docsify.dom.find(n,"input"),e=Docsify.dom.find(n,".input-wrap"),Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(a,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return d(n.target.value.trim())},100)}),Docsify.dom.on(e,"click",function(e){"INPUT"!==e.target.tagName&&(a.value="",d())}),i&&setTimeout(function(e){return d(i)},500)}function x(e,n){var t,a,i,r,o;l(e),t=e.placeholder,a=n.route.path,(r=Docsify.dom.getNode('.search input[type="search"]'))&&("string"==typeof t?r.placeholder=t:(i=Object.keys(t).filter(function(e){return-1<a.indexOf(e)})[0],r.placeholder=t[i])),e=e.noData,o=n.route.path,c="string"==typeof e?e:e[Object.keys(e).filter(function(e){return-1<o.indexOf(e)})[0]]}var w={placeholder:"Type to search",noData:"No Results!",paths:"auto",depth:2,maxAge:864e5,hideOtherSidebarContent:!1,namespace:void 0,pathNamespaces:void 0};$docsify.plugins=[].concat(function(e,n){var t=Docsify.util,a=n.config.search||w;Array.isArray(a)?w.paths=a:"object"==typeof a&&(w.paths=Array.isArray(a.paths)?a.paths:"auto",w.maxAge=(t.isPrimitive(a.maxAge)?a:w).maxAge,w.placeholder=a.placeholder||w.placeholder,w.noData=a.noData||w.noData,w.depth=a.depth||w.depth,w.hideOtherSidebarContent=a.hideOtherSidebarContent||w.hideOtherSidebarContent,w.namespace=a.namespace||w.namespace,w.pathNamespaces=a.pathNamespaces||w.pathNamespaces);var i="auto"===w.paths;e.mounted(function(e){h(w,n),i||r(w,n)}),e.doneEach(function(e){x(w,n),i&&r(w,n)})},$docsify.plugins)}();
... ...
doc/lib/js/zoom-image.min.js 0 → 100644
  1 +!function(){function t(e){return"IMG"===e.tagName}function d(e){function t(){for(var e=arguments,t=arguments.length,o=Array(t),n=0;n<t;n++)o[n]=e[n];var i=o.reduce(function(e,t){return[].concat(e,z(t))},[]);return i.filter(function(e){return-1===m.indexOf(e)}).forEach(function(e){m.push(e),e.classList.add("medium-zoom-image")}),r.forEach(function(e){var t=e.type,o=e.listener,n=e.options;i.forEach(function(e){e.addEventListener(t,o,n)})}),f}function o(){var e=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}).target;return s.original?a():i({target:e})}var n=window.Promise||function(e){function t(){}e(t,t)},i=function(){function r(){var e={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},t=void 0,o=void 0;u.container&&(u.container instanceof Object?(t=(e=g({},e,u.container)).width-e.left-e.right-2*u.margin,o=e.height-e.top-e.bottom-2*u.margin):(r=(i=(h(u.container)?u.container:document.querySelector(u.container)).getBoundingClientRect()).width,m=i.height,d=i.left,a=i.top,e=g({},e,{width:r,height:m,left:d,top:a})));var t=t||e.width-2*u.margin,o=o||e.height-2*u.margin,n=s.zoomedHd||s.original,i=!v(n)&&n.naturalWidth||t,r=!v(n)&&n.naturalHeight||o,d=(m=n.getBoundingClientRect()).top,a=m.left,n=m.width,m=m.height,i=Math.min(i,t)/n,r=Math.min(r,o)/m,r="scale("+(r=Math.min(i,r))+") translate3d("+((t-n)/2-a+u.margin+e.left)/r+"px, "+((o-m)/2-d+u.margin+e.top)/r+"px, 0)";s.zoomed.style.transform=r,s.zoomedHd&&(s.zoomedHd.style.transform=r)}var d=(0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}).target;return new n(function(e){if(d&&-1===m.indexOf(d))e(f);else{function t(){c=!1,s.zoomed.removeEventListener("transitionend",t),s.original.dispatchEvent(E("medium-zoom:opened",{detail:{zoom:f}})),e(f)}var o,n;if(s.zoomed)e(f);else{if(d)s.original=d;else{if(!(0<m.length))return void e(f);var i=m;s.original=i[0]}s.original.dispatchEvent(E("medium-zoom:open",{detail:{zoom:f}})),l=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,c=!0,s.zoomed=b(s.original),document.body.appendChild(p),u.template&&(i=h(u.template)?u.template:document.querySelector(u.template),s.template=document.createElement("div"),s.template.appendChild(i.content.cloneNode(!0)),document.body.appendChild(s.template)),document.body.appendChild(s.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),s.original.classList.add("medium-zoom-image--hidden"),s.zoomed.classList.add("medium-zoom-image--opened"),s.zoomed.addEventListener("click",a),s.zoomed.addEventListener("transitionend",t),s.original.getAttribute("data-zoom-src")?(s.zoomedHd=s.zoomed.cloneNode(),s.zoomedHd.removeAttribute("srcset"),s.zoomedHd.removeAttribute("sizes"),s.zoomedHd.src=s.zoomed.getAttribute("data-zoom-src"),s.zoomedHd.onerror=function(){clearInterval(o),console.warn("Unable to reach the zoom image target "+s.zoomedHd.src),s.zoomedHd=null,r()},o=setInterval(function(){s.zoomedHd.complete&&(clearInterval(o),s.zoomedHd.classList.add("medium-zoom-image--opened"),s.zoomedHd.addEventListener("click",a),document.body.appendChild(s.zoomedHd),r())},10)):s.original.hasAttribute("srcset")?(s.zoomedHd=s.zoomed.cloneNode(),s.zoomedHd.removeAttribute("sizes"),s.zoomedHd.removeAttribute("loading"),n=s.zoomedHd.addEventListener("load",function(){s.zoomedHd.removeEventListener("load",n),s.zoomedHd.classList.add("medium-zoom-image--opened"),s.zoomedHd.addEventListener("click",a),document.body.appendChild(s.zoomedHd),r()})):r()}}})},a=function(){return new n(function(t){var e;!c&&s.original?(e=function e(){s.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(s.zoomed),s.zoomedHd&&document.body.removeChild(s.zoomedHd),document.body.removeChild(p),s.zoomed.classList.remove("medium-zoom-image--opened"),s.template&&document.body.removeChild(s.template),c=!1,s.zoomed.removeEventListener("transitionend",e),s.original.dispatchEvent(E("medium-zoom:closed",{detail:{zoom:f}})),s.original=null,s.zoomed=null,s.zoomedHd=null,s.template=null,t(f)},c=!0,document.body.classList.remove("medium-zoom--opened"),s.zoomed.style.transform="",s.zoomedHd&&(s.zoomedHd.style.transform=""),s.template&&(s.template.style.transition="opacity 150ms",s.template.style.opacity=0),s.original.dispatchEvent(E("medium-zoom:close",{detail:{zoom:f}})),s.zoomed.addEventListener("transitionend",e)):t(f)})},m=[],r=[],c=!1,l=0,u=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},s={original:null,zoomed:null,zoomedHd:null,template:null};"[object Object]"===Object.prototype.toString.call(e)?u=e:!e&&"string"!=typeof e||t(e);var u=g({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},u),p=y(u.background);document.addEventListener("click",function(e){e=e.target;e!==p?-1!==m.indexOf(e)&&o({target:e}):a()}),document.addEventListener("keyup",function(e){e=e.key||e.keyCode;"Escape"!==e&&"Esc"!==e&&27!==e||a()}),document.addEventListener("scroll",function(){var e;!c&&s.original&&(e=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,Math.abs(l-e)>u.scrollOffset&&setTimeout(a,150))}),window.addEventListener("resize",a);var f={open:i,close:a,toggle:o,update:function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},t=e;return e.background&&(p.style.background=e.background),e.container&&e.container instanceof Object&&(t.container=g({},u.container,e.container)),e.template&&(e=h(e.template)?e.template:document.querySelector(e.template),t.template=e),u=g({},u,t),m.forEach(function(e){e.dispatchEvent(E("medium-zoom:update",{detail:{zoom:f}}))}),f},clone:function(){return d(g({},u,0<arguments.length&&void 0!==arguments[0]?arguments[0]:{}))},attach:t,detach:function(){for(var e=arguments,t=arguments.length,o=Array(t),n=0;n<t;n++)o[n]=e[n];s.zoomed&&a();var i=0<o.length?o.reduce(function(e,t){return[].concat(e,z(t))},[]):m;return i.forEach(function(e){e.classList.remove("medium-zoom-image"),e.dispatchEvent(E("medium-zoom:detach",{detail:{zoom:f}}))}),m=m.filter(function(e){return-1===i.indexOf(e)}),f},on:function(t,o){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return m.forEach(function(e){e.addEventListener("medium-zoom:"+t,o,n)}),r.push({type:"medium-zoom:"+t,listener:o,options:n}),f},off:function(t,o){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return m.forEach(function(e){e.removeEventListener("medium-zoom:"+t,o,n)}),r=r.filter(function(e){return!(e.type==="medium-zoom:"+t&&e.listener.toString()===o.toString())}),f},getOptions:function(){return u},getImages:function(){return m},getZoomedImage:function(){return s.original}};return f}var g=Object.assign||function(e){for(var t=arguments,o=1;o<arguments.length;o++){var n,i=t[o];for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n])}return e},h=function(e){return e&&1===e.nodeType},v=function(e){return".svg"===(e.currentSrc||e.src).substr(-4).toLowerCase()},z=function(e){try{return Array.isArray(e)?e.filter(t):NodeList.prototype.isPrototypeOf(e)?[].slice.call(e).filter(t):h(e)?[e].filter(t):"string"==typeof e?[].slice.call(document.querySelectorAll(e)).filter(t):[]}catch(e){throw new TypeError("The provided selector is invalid.\nExpects a CSS selector, a Node element, a NodeList or an array.\nSee: https://github.com/francoischalifour/medium-zoom")}},y=function(e){var t=document.createElement("div");return t.classList.add("medium-zoom-overlay"),t.style.background=e,t},b=function(e){var t=e.getBoundingClientRect(),o=t.top,n=t.left,i=t.width,r=t.height,d=e.cloneNode(),t=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,e=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return d.removeAttribute("id"),d.style.position="absolute",d.style.top=o+t+"px",d.style.left=n+e+"px",d.style.width=i+"px",d.style.height=r+"px",d.style.transform="",d},E=function(e,t){var o=g({bubbles:!1,cancelable:!1,detail:void 0},t);if("function"==typeof window.CustomEvent)return new CustomEvent(e,o);t=document.createEvent("CustomEvent");return t.initCustomEvent(e,o.bubbles,o.cancelable,o.detail),t};var e,o,n,i;e=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}",i=(o=void 0===o?{}:o).insertAt,e&&"undefined"!=typeof document&&(n=document.head||document.getElementsByTagName("head")[0],(o=document.createElement("style")).type="text/css","top"===i&&n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e)));var r=Element.prototype.matches||Element.prototype.webkitMatchesSelector||Element.prototype.msMatchesSelector;$docsify.plugins=[].concat(function(e){var o;e.doneEach(function(e){var t=(t=Array.apply(null,document.querySelectorAll(".markdown-section img:not(.emoji):not([data-no-zoom])"))).filter(function(e){return!1===r.call(e,"a img")});o&&o.detach(),o=d(t)})},$docsify.plugins)}();
... ...
libs/jdbc-aarch/kingbase8-8.6.0.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/kingbase8-8.6.0.jre7.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jar 0 → 100644
No preview for this file type
libs/jdbc-aarch/postgresql-42.2.9.jre7.jar 0 → 100644
No preview for this file type
... ... @@ -11,7 +11,7 @@
11 11  
12 12 <groupId>com.genersoft</groupId>
13 13 <artifactId>wvp-pro</artifactId>
14   - <version>2.6.8</version>
  14 + <version>2.6.9</version>
15 15 <name>web video platform</name>
16 16 <description>国标28181视频平台</description>
17 17 <packaging>${project.packaging}</packaging>
... ... @@ -135,11 +135,30 @@
135 135 <version>8.0.30</version>
136 136 </dependency>
137 137  
  138 + <!--postgresql-->
  139 + <dependency>
  140 + <groupId>org.postgresql</groupId>
  141 + <artifactId>postgresql</artifactId>
  142 + <version>42.5.1</version>
  143 + </dependency>
  144 +
  145 + <!-- kingbase人大金仓 -->
  146 + <!-- 手动下载驱动后安装 -->
  147 + <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar
  148 + -->
  149 + <dependency>
  150 + <groupId>com.kingbase</groupId>
  151 + <artifactId>kingbase8</artifactId>
  152 + <version>8.6.0</version>
  153 + <scope>system</scope>
  154 + <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath>
  155 + </dependency>
  156 +
138 157 <!--Mybatis分页插件 -->
139 158 <dependency>
140 159 <groupId>com.github.pagehelper</groupId>
141 160 <artifactId>pagehelper-spring-boot-starter</artifactId>
142   - <version>1.4.3</version>
  161 + <version>1.4.6</version>
143 162 </dependency>
144 163  
145 164 <!--在线文档 -->
... ...
sql/2.6.6-2.6.7更新.sql
... ... @@ -7,6 +7,7 @@ alter table parent_platform
7 7 alter table device
8 8 add mediaServerId varchar(50) default null;
9 9  
10   -
  10 +ALTER TABLE device
  11 + ADD COLUMN `switchPrimarySubStream` bit(1) NOT NULL DEFAULT b'0' COMMENT '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备' AFTER `keepalive_interval_time`
11 12  
12 13  
... ...
sql/2.6.8升级2.6.9.sql 0 → 100644
  1 +alter table device
  2 + change deviceId device_id varchar(50) not null;
  3 +
  4 +alter table device
  5 + change streamMode stream_mode varchar(50) null;
  6 +
  7 +alter table device
  8 + change registerTime register_time varchar(50) null;
  9 +
  10 +alter table device
  11 + change keepaliveTime keepalive_time varchar(50) null;
  12 +
  13 +alter table device
  14 + change createTime create_time varchar(50) not null;
  15 +
  16 +alter table device
  17 + change updateTime update_time varchar(50) not null;
  18 +
  19 +alter table device
  20 + change subscribeCycleForCatalog subscribe_cycle_for_catalog bool default false;
  21 +
  22 +alter table device
  23 + change subscribeCycleForMobilePosition subscribe_cycle_for_mobile_position bool default false;
  24 +
  25 +alter table device
  26 + change mobilePositionSubmissionInterval mobile_position_submission_interval int default 5 not null;
  27 +
  28 +alter table device
  29 + change subscribeCycleForAlarm subscribe_cycle_for_alarm bool default false;
  30 +
  31 +alter table device
  32 + change hostAddress host_address varchar(50) null;
  33 +
  34 +alter table device
  35 + change ssrcCheck ssrc_check bool default false;
  36 +
  37 +alter table device
  38 + change geoCoordSys geo_coord_sys varchar(50) not null;
  39 +
  40 +alter table device
  41 + drop column treeType;
  42 +
  43 +alter table device
  44 + change mediaServerId media_server_id varchar(50) default 'auto' null;
  45 +
  46 +alter table device
  47 + change sdpIp sdp_ip varchar(50) null;
  48 +
  49 +alter table device
  50 + change localIp local_ip varchar(50) null;
  51 +
  52 +alter table device
  53 + change asMessageChannel as_message_channel bool default false;
  54 +
  55 +alter table device
  56 + change keepaliveIntervalTime keepalive_interval_time int null;
  57 +
  58 +alter table device
  59 + change online on_line varchar(50) null;
  60 +
  61 +alter table device
  62 + add COLUMN switch_primary_sub_stream bool default false comment '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备'
  63 +
  64 +
  65 +alter table device_alarm
  66 + change deviceId device_id varchar(50) not null;
  67 +
  68 +alter table device_alarm
  69 + change channelId channel_id varchar(50) not null;
  70 +
  71 +alter table device_alarm
  72 + change alarmPriority alarm_priority varchar(50) not null;
  73 +
  74 +alter table device_alarm
  75 + change alarmMethod alarm_method varchar(50) null;
  76 +
  77 +alter table device_alarm
  78 + change alarmTime alarm_time varchar(50) not null;
  79 +
  80 +alter table device_alarm
  81 + change alarmDescription alarm_description varchar(255) null;
  82 +
  83 +alter table device_alarm
  84 + change alarmType alarm_type varchar(50) null;
  85 +
  86 +alter table device_alarm
  87 + change createTime create_time varchar(50) null;
  88 +
  89 +alter table device_channel
  90 + change channelId channel_id varchar(50) not null;
  91 +
  92 +alter table device_channel
  93 + change civilCode civil_code varchar(50) null;
  94 +
  95 +alter table device_channel
  96 + change parentId parent_id varchar(50) null;
  97 +
  98 +alter table device_channel
  99 + change safetyWay safety_way int null;
  100 +
  101 +alter table device_channel
  102 + change registerWay register_way int null;
  103 +
  104 +alter table device_channel
  105 + change certNum cert_num varchar(50) null;
  106 +
  107 +alter table device_channel
  108 + change errCode err_code int null;
  109 +
  110 +alter table device_channel
  111 + change endTime end_time varchar(50) null;
  112 +
  113 +alter table device_channel
  114 + change ipAddress ip_address varchar(50) null;
  115 +
  116 +alter table device_channel
  117 + change PTZType ptz_type int null;
  118 +
  119 +alter table device_channel
  120 + change status status bool default false;
  121 +
  122 +alter table device_channel
  123 + change streamId stream_id varchar(50) null;
  124 +
  125 +alter table device_channel
  126 + change deviceId device_id varchar(50) not null;
  127 +
  128 +
  129 +alter table device_channel
  130 + change hasAudio has_audio bool default false;
  131 +
  132 +alter table device_channel
  133 + change createTime create_time varchar(50) not null;
  134 +
  135 +alter table device_channel
  136 + change updateTime update_time varchar(50) not null;
  137 +
  138 +alter table device_channel
  139 + change subCount sub_count int default 0 null;
  140 +
  141 +alter table device_channel
  142 + change longitudeGcj02 longitude_gcj02 double null;
  143 +
  144 +alter table device_channel
  145 + change latitudeGcj02 latitude_gcj02 double null;
  146 +
  147 +alter table device_channel
  148 + change longitudeWgs84 longitude_wgs84 double null;
  149 +
  150 +alter table device_channel
  151 + change latitudeWgs84 latitude_wgs84 double null;
  152 +
  153 +alter table device_channel
  154 + change businessGroupId business_group_id varchar(50) null;
  155 +
  156 +alter table device_channel
  157 + change gpsTime gps_time varchar(50) null;
  158 +
  159 +alter table device_mobile_position
  160 + change deviceId device_id varchar(50) not null;
  161 +
  162 +alter table device_mobile_position
  163 + change channelId channel_id varchar(50) not null;
  164 +
  165 +alter table device_mobile_position
  166 + change deviceName device_name varchar(255) null;
  167 +
  168 +alter table device_mobile_position
  169 + change reportSource report_source varchar(50) null;
  170 +
  171 +alter table device_mobile_position
  172 + change longitudeGcj02 longitude_gcj02 double null;
  173 +
  174 +alter table device_mobile_position
  175 + change latitudeGcj02 latitude_gcj02 double null;
  176 +
  177 +alter table device_mobile_position
  178 + change longitudeWgs84 longitude_wgs84 double null;
  179 +
  180 +alter table device_mobile_position
  181 + change latitudeWgs84 latitude_wgs84 double null;
  182 +
  183 +alter table device_mobile_position
  184 + change createTime create_time varchar(50) null;
  185 +
  186 +alter table gb_stream
  187 + change gbStreamId gb_stream_id int auto_increment;
  188 +
  189 +alter table gb_stream
  190 + change gbId gb_id varchar(50) not null;
  191 +
  192 +alter table gb_stream
  193 + change streamType stream_type varchar(50) null;
  194 +
  195 +alter table gb_stream
  196 + change mediaServerId media_server_id varchar(50) null;
  197 +
  198 +alter table gb_stream
  199 + change createTime create_time varchar(50) null;
  200 +
  201 +alter table log
  202 + change createTime create_time varchar(50) not null;
  203 +
  204 +alter table media_server
  205 + change hookIp hook_ip varchar(50) not null;
  206 +
  207 +alter table media_server
  208 + change sdpIp sdp_ip varchar(50) not null;
  209 +
  210 +alter table media_server
  211 + change streamIp stream_ip varchar(50) not null;
  212 +
  213 +alter table media_server
  214 + change httpPort http_port int not null;
  215 +
  216 +alter table media_server
  217 + change httpSSlPort http_ssl_port int not null;
  218 +
  219 +alter table media_server
  220 + change rtmpPort rtmp_port int not null;
  221 +
  222 +alter table media_server
  223 + change rtmpSSlPort rtmp_ssl_port int not null;
  224 +
  225 +alter table media_server
  226 + change rtpProxyPort rtp_proxy_port int not null;
  227 +
  228 +alter table media_server
  229 + change rtspPort rtsp_port int not null;
  230 +
  231 +alter table media_server
  232 + change rtspSSLPort rtsp_ssl_port int not null;
  233 +
  234 +alter table media_server
  235 + change autoConfig auto_config bool default true;
  236 +
  237 +alter table media_server
  238 + change rtpEnable rtp_enable bool default false;
  239 +
  240 +alter table media_server
  241 + change rtpPortRange rtp_port_range varchar(50) not null;
  242 +
  243 +alter table media_server
  244 + change recordAssistPort record_assist_port int not null;
  245 +
  246 +alter table media_server
  247 + change defaultServer default_server bool default false;
  248 +
  249 +alter table media_server
  250 + change createTime create_time varchar(50) not null;
  251 +
  252 +alter table media_server
  253 + change updateTime update_time varchar(50) not null;
  254 +
  255 +alter table media_server
  256 + change hookAliveInterval hook_alive_interval int not null;
  257 +
  258 +alter table parent_platform
  259 + change serverGBId server_gb_id varchar(50) not null;
  260 +
  261 +alter table parent_platform
  262 + change serverGBDomain server_gb_domain varchar(50) null;
  263 +
  264 +alter table parent_platform
  265 + change serverIP server_ip varchar(50) null;
  266 +
  267 +alter table parent_platform
  268 + change serverPort server_port int null;
  269 +
  270 +alter table parent_platform
  271 + change deviceGBId device_gb_id varchar(50) not null;
  272 +
  273 +alter table parent_platform
  274 + change deviceIp device_ip varchar(50) null;
  275 +
  276 +alter table parent_platform
  277 + change devicePort device_port varchar(50) null;
  278 +
  279 +alter table parent_platform
  280 + change keepTimeout keep_timeout varchar(50) null;
  281 +
  282 +alter table parent_platform
  283 + change characterSet character_set varchar(50) null;
  284 +
  285 +alter table parent_platform
  286 + change catalogId catalog_id varchar(50) not null;
  287 +
  288 +alter table parent_platform
  289 + change startOfflinePush start_offline_push bool default false;
  290 +
  291 +alter table parent_platform
  292 + change administrativeDivision administrative_division varchar(50) not null;
  293 +
  294 +alter table parent_platform
  295 + change catalogGroup catalog_group int default 1 null;
  296 +
  297 +alter table parent_platform
  298 + change createTime create_time varchar(50) null;
  299 +
  300 +alter table parent_platform
  301 + change updateTime update_time varchar(50) null;
  302 +
  303 +alter table parent_platform
  304 + drop column treeType;
  305 +
  306 +alter table parent_platform
  307 + change asMessageChannel as_message_channel bool default false;
  308 +
  309 +alter table parent_platform
  310 + change enable enable bool default false;
  311 +
  312 +alter table parent_platform
  313 + change ptz ptz bool default false;
  314 +
  315 +alter table parent_platform
  316 + change rtcp rtcp bool default false;
  317 +
  318 +alter table parent_platform
  319 + change status status bool default false;
  320 +
  321 +alter table parent_platform
  322 + change status status bool default false;
  323 +
  324 +alter table platform_catalog
  325 + change platformId platform_id varchar(50) not null;
  326 +
  327 +alter table platform_catalog
  328 + change parentId parent_id varchar(50) null;
  329 +
  330 +alter table platform_catalog
  331 + change civilCode civil_code varchar(50) null;
  332 +
  333 +alter table platform_catalog
  334 + change businessGroupId business_group_id varchar(50) null;
  335 +
  336 +alter table platform_gb_channel
  337 + change platformId platform_id varchar(50) not null;
  338 +
  339 +alter table platform_gb_channel
  340 + change catalogId catalog_id varchar(50) not null;
  341 +
  342 +alter table platform_gb_channel
  343 + change deviceChannelId device_channel_id int not null;
  344 +
  345 +alter table platform_gb_stream
  346 + change platformId platform_id varchar(50) not null;
  347 +
  348 +alter table platform_gb_stream
  349 + change catalogId catalog_id varchar(50) not null;
  350 +
  351 +alter table platform_gb_stream
  352 + change gbStreamId gb_stream_id int not null;
  353 +
  354 +alter table stream_proxy
  355 + change mediaServerId media_server_id varchar(50) null;
  356 +
  357 +alter table stream_proxy
  358 + change createTime create_time varchar(50) not null;
  359 +
  360 +alter table stream_proxy
  361 + change updateTime update_time varchar(50) null;
  362 +
  363 +alter table stream_proxy
  364 + change enable_remove_none_reader enable_remove_none_reader bool default false;
  365 +
  366 +alter table stream_proxy
  367 + change enable_disable_none_reader enable_disable_none_reader bool default false;
  368 +
  369 +alter table stream_proxy
  370 + change enable_audio enable_audio bool default false;
  371 +
  372 +alter table stream_proxy
  373 + change enable_mp4 enable_mp4 bool default false;
  374 +
  375 +alter table stream_proxy
  376 + change enable enable bool default false;
  377 +
  378 +alter table stream_push
  379 + change totalReaderCount total_reader_count varchar(50) null;
  380 +
  381 +alter table stream_push
  382 + change originType origin_type int null;
  383 +
  384 +alter table stream_push
  385 + change originTypeStr origin_type_str varchar(50) null;
  386 +
  387 +alter table stream_push
  388 + change createTime create_time varchar(50) null;
  389 +
  390 +alter table stream_push
  391 + change aliveSecond alive_second int null;
  392 +
  393 +alter table stream_push
  394 + change mediaServerId media_server_id varchar(50) null;
  395 +
  396 +alter table stream_push
  397 + change status status bool default false;
  398 +
  399 +alter table stream_push
  400 + change pushTime push_time varchar(50) null;
  401 +
  402 +alter table stream_push
  403 + change updateTime update_time varchar(50) null;
  404 +
  405 +alter table stream_push
  406 + change pushIng push_ing bool default false;
  407 +
  408 +alter table stream_push
  409 + change status status bool default false;
  410 +
  411 +alter table stream_push
  412 + change self self bool default false;
  413 +
  414 +alter table stream_push
  415 + drop column serverId;
  416 +
  417 +
  418 +alter table user
  419 + change roleId role_id int not null;
  420 +
  421 +alter table user
  422 + change createTime create_time varchar(50) not null;
  423 +
  424 +alter table user
  425 + change updateTime update_time varchar(50) not null;
  426 +
  427 +alter table user
  428 + change pushKey push_key varchar(50) null;
  429 +
  430 +alter table user_role
  431 + change createTime create_time varchar(50) not null;
  432 +
  433 +alter table user_role
  434 + change updateTime update_time varchar(50) not null;
  435 +
  436 +rename table device to wvp_device;
  437 +rename table device_alarm to wvp_device_alarm;
  438 +rename table device_channel to wvp_device_channel;
  439 +rename table device_mobile_position to wvp_device_mobile_position;
  440 +rename table gb_stream to wvp_gb_stream;
  441 +rename table log to wvp_log;
  442 +rename table media_server to wvp_media_server;
  443 +rename table parent_platform to wvp_platform;
  444 +rename table platform_catalog to wvp_platform_catalog;
  445 +rename table platform_gb_channel to wvp_platform_gb_channel;
  446 +rename table platform_gb_stream to wvp_platform_gb_stream;
  447 +rename table stream_proxy to wvp_stream_proxy;
  448 +rename table stream_push to wvp_stream_push;
  449 +rename table user to wvp_user;
  450 +rename table user_role to wvp_user_role;
  451 +
  452 +
  453 +
  454 +
  455 +
  456 +
  457 +
  458 +
  459 +
  460 +
  461 +
  462 +
  463 +
  464 +
  465 +
  466 +
  467 +
  468 +
  469 +
  470 +
  471 +
  472 +
  473 +
  474 +
  475 +
  476 +
  477 +
  478 +
  479 +
... ...
sql/clean.sql
1   -delete from device;
2   -delete from device_alarm;
3   -delete from device_channel;
4   -delete from device_mobile_position;
5   -delete from gb_stream;
6   -delete from log;
7   -delete from media_server;
8   -delete from parent_platform;
9   -delete from platform_catalog;
10   -delete from platform_gb_channel;
11   -delete from platform_gb_stream;
12   -delete from stream_proxy;
13   -delete from stream_push;
14 1 \ No newline at end of file
  2 +delete from wvp-device;
  3 +delete from wvp-device_alarm;
  4 +delete from wvp-device_channel;
  5 +delete from wvp-device_mobile_position;
  6 +delete from wvp-gb_stream;
  7 +delete from wvp-log;
  8 +delete from wvp-media_server;
  9 +delete from wvp-parent_platform;
  10 +delete from wvp-platform_catalog;
  11 +delete from wvp-platform_gb_channel;
  12 +delete from wvp-platform_gb_stream;
  13 +delete from wvp-stream_proxy;
  14 +delete from wvp-stream_push;
15 15 \ No newline at end of file
... ...
sql/初始化.sql
1   --- MySQL dump 10.13 Distrib 8.0.31, for Linux (x86_64)
2   ---
3   --- Host: 127.0.0.1 Database: wvp
4   --- ------------------------------------------------------
5   --- Server version 8.0.30
  1 +/*建表*/
  2 +create table wvp_device (
  3 + id serial primary key ,
  4 + device_id character varying(50) not null ,
  5 + name character varying(255),
  6 + manufacturer character varying(255),
  7 + model character varying(255),
  8 + firmware character varying(255),
  9 + transport character varying(50),
  10 + stream_mode character varying(50),
  11 + on_line bool default false,
  12 + register_time character varying(50),
  13 + keepalive_time character varying(50),
  14 + ip character varying(50),
  15 + create_time character varying(50),
  16 + update_time character varying(50),
  17 + port integer,
  18 + expires integer,
  19 + subscribe_cycle_for_catalog integer DEFAULT 0,
  20 + subscribe_cycle_for_mobile_position integer DEFAULT 0,
  21 + mobile_position_submission_interval integer DEFAULT 5,
  22 + subscribe_cycle_for_alarm integer DEFAULT 0,
  23 + host_address character varying(50),
  24 + charset character varying(50),
  25 + ssrc_check bool default false,
  26 + geo_coord_sys character varying(50),
  27 + media_server_id character varying(50),
  28 + custom_name character varying(255),
  29 + sdp_ip character varying(50),
  30 + local_ip character varying(50),
  31 + password character varying(255),
  32 + as_message_channel bool default false,
  33 + keepalive_interval_time integer,
  34 + switch_primary_sub_stream bool default false,
  35 + constraint uk_device_device unique (device_id)
  36 +);
  37 +
  38 +create table wvp_device_alarm (
  39 + id serial primary key ,
  40 + device_id character varying(50) not null,
  41 + channel_id character varying(50) not null,
  42 + alarm_priority character varying(50),
  43 + alarm_method character varying(50),
  44 + alarm_time character varying(50),
  45 + alarm_description character varying(255),
  46 + longitude double precision,
  47 + latitude double precision,
  48 + alarm_type character varying(50),
  49 + create_time character varying(50) not null
  50 +);
  51 +
  52 +create table wvp_device_channel (
  53 + id serial primary key ,
  54 + channel_id character varying(50) not null,
  55 + name character varying(255),
  56 + manufacture character varying(50),
  57 + model character varying(50),
  58 + owner character varying(50),
  59 + civil_code character varying(50),
  60 + block character varying(50),
  61 + address character varying(50),
  62 + parent_id character varying(50),
  63 + safety_way integer,
  64 + register_way integer,
  65 + cert_num character varying(50),
  66 + certifiable integer,
  67 + err_code integer,
  68 + end_time character varying(50),
  69 + secrecy character varying(50),
  70 + ip_address character varying(50),
  71 + port integer,
  72 + password character varying(255),
  73 + ptz_type integer,
  74 + status bool default false,
  75 + longitude double precision,
  76 + latitude double precision,
  77 + stream_id character varying(50),
  78 + device_id character varying(50) not null,
  79 + parental character varying(50),
  80 + has_audio bool default false,
  81 + create_time character varying(50) not null,
  82 + update_time character varying(50) not null,
  83 + sub_count integer,
  84 + longitude_gcj02 double precision,
  85 + latitude_gcj02 double precision,
  86 + longitude_wgs84 double precision,
  87 + latitude_wgs84 double precision,
  88 + business_group_id character varying(50),
  89 + gps_time character varying(50),
  90 + constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
  91 +);
  92 +
  93 +create table wvp_device_mobile_position (
  94 + id serial primary key,
  95 + device_id character varying(50) not null,
  96 + channel_id character varying(50) not null,
  97 + device_name character varying(255),
  98 + time character varying(50),
  99 + longitude double precision,
  100 + latitude double precision,
  101 + altitude double precision,
  102 + speed double precision,
  103 + direction double precision,
  104 + report_source character varying(50),
  105 + longitude_gcj02 double precision,
  106 + latitude_gcj02 double precision,
  107 + longitude_wgs84 double precision,
  108 + latitude_wgs84 double precision,
  109 + create_time character varying(50)
  110 +);
  111 +
  112 +create table wvp_gb_stream (
  113 + gb_stream_id serial primary key,
  114 + app character varying(255) not null,
  115 + stream character varying(255) not null,
  116 + gb_id character varying(50) not null,
  117 + name character varying(255),
  118 + longitude double precision,
  119 + latitude double precision,
  120 + stream_type character varying(50),
  121 + media_server_id character varying(50),
  122 + create_time character varying(50),
  123 + constraint uk_gb_stream_unique_gb_id unique (gb_id),
  124 + constraint uk_gb_stream_unique_app_stream unique (app, stream)
  125 +);
  126 +
  127 +create table wvp_log (
  128 + id serial primary key ,
  129 + name character varying(50),
  130 + type character varying(50),
  131 + uri character varying(200),
  132 + address character varying(50),
  133 + result character varying(50),
  134 + timing bigint,
  135 + username character varying(50),
  136 + create_time character varying(50)
  137 +);
  138 +
  139 +create table wvp_media_server (
  140 + id character varying(255) primary key ,
  141 + ip character varying(50),
  142 + hook_ip character varying(50),
  143 + sdp_ip character varying(50),
  144 + stream_ip character varying(50),
  145 + http_port integer,
  146 + http_ssl_port integer,
  147 + rtmp_port integer,
  148 + rtmp_ssl_port integer,
  149 + rtp_proxy_port integer,
  150 + rtsp_port integer,
  151 + rtsp_ssl_port integer,
  152 + auto_config bool default false,
  153 + secret character varying(50),
  154 + rtp_enable bool default false,
  155 + rtp_port_range character varying(50),
  156 + record_assist_port integer,
  157 + default_server bool default false,
  158 + create_time character varying(50),
  159 + update_time character varying(50),
  160 + hook_alive_interval integer,
  161 + constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
  162 +);
  163 +
  164 +create table wvp_platform (
  165 + id serial primary key ,
  166 + enable bool default false,
  167 + name character varying(255),
  168 + server_gb_id character varying(50),
  169 + server_gb_domain character varying(50),
  170 + server_ip character varying(50),
  171 + server_port integer,
  172 + device_gb_id character varying(50),
  173 + device_ip character varying(50),
  174 + device_port character varying(50),
  175 + username character varying(255),
  176 + password character varying(50),
  177 + expires character varying(50),
  178 + keep_timeout character varying(50),
  179 + transport character varying(50),
  180 + character_set character varying(50),
  181 + catalog_id character varying(50),
  182 + ptz bool default false,
  183 + rtcp bool default false,
  184 + status bool default false,
  185 + start_offline_push bool default false,
  186 + administrative_division character varying(50),
  187 + catalog_group integer,
  188 + create_time character varying(50),
  189 + update_time character varying(50),
  190 + as_message_channel bool default false,
  191 + constraint uk_platform_unique_server_gb_id unique (server_gb_id)
  192 +);
  193 +
  194 +create table wvp_platform_catalog (
  195 + id character varying(50),
  196 + platform_id character varying(50),
  197 + name character varying(255),
  198 + parent_id character varying(50),
  199 + civil_code character varying(50),
  200 + business_group_id character varying(50),
  201 + constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
  202 +);
  203 +
  204 +create table wvp_platform_gb_channel (
  205 + id serial primary key ,
  206 + platform_id character varying(50),
  207 + catalog_id character varying(50),
  208 + device_channel_id integer,
  209 + constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
  210 +);
  211 +
  212 +create table wvp_platform_gb_stream (
  213 + id serial primary key,
  214 + platform_id character varying(50),
  215 + catalog_id character varying(50),
  216 + gb_stream_id integer,
  217 + constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
  218 +);
  219 +
  220 +create table wvp_stream_proxy (
  221 + id serial primary key,
  222 + type character varying(50),
  223 + app character varying(255),
  224 + stream character varying(255),
  225 + url character varying(255),
  226 + src_url character varying(255),
  227 + dst_url character varying(255),
  228 + timeout_ms integer,
  229 + ffmpeg_cmd_key character varying(255),
  230 + rtp_type character varying(50),
  231 + media_server_id character varying(50),
  232 + enable_audio bool default false,
  233 + enable_mp4 bool default false,
  234 + enable bool default false,
  235 + status boolean,
  236 + enable_remove_none_reader bool default false,
  237 + create_time character varying(50),
  238 + name character varying(255),
  239 + update_time character varying(50),
  240 + enable_disable_none_reader bool default false,
  241 + constraint uk_stream_proxy_app_stream unique (app, stream)
  242 +);
  243 +
  244 +create table wvp_stream_push (
  245 + id serial primary key,
  246 + app character varying(255),
  247 + stream character varying(255),
  248 + total_reader_count character varying(50),
  249 + origin_type integer,
  250 + origin_type_str character varying(50),
  251 + create_time character varying(50),
  252 + alive_second integer,
  253 + media_server_id character varying(50),
  254 + push_time character varying(50),
  255 + status bool default false,
  256 + update_time character varying(50),
  257 + push_ing bool default false,
  258 + self bool default false,
  259 + constraint uk_stream_push_app_stream unique (app, stream)
  260 +);
  261 +
  262 +create table wvp_user (
  263 + id serial primary key,
  264 + username character varying(255),
  265 + password character varying(255),
  266 + role_id integer,
  267 + create_time character varying(50),
  268 + update_time character varying(50),
  269 + push_key character varying(50),
  270 + constraint uk_user_username unique (username)
  271 +);
  272 +
  273 +create table wvp_user_role (
  274 + id serial primary key,
  275 + name character varying(50),
  276 + authority character varying(50),
  277 + create_time character varying(50),
  278 + update_time character varying(50)
  279 +);
  280 +
  281 +/*初始数据*/
  282 +INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
  283 +INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
6 284  
7   -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8   -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9   -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10   -/*!50503 SET NAMES utf8mb4 */;
11   -/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12   -/*!40103 SET TIME_ZONE='+00:00' */;
13   -/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14   -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15   -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16   -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17 285  
18   ---
19   --- Table structure for table `device`
20   ---
21 286  
22   -DROP TABLE IF EXISTS `device`;
23   -/*!40101 SET @saved_cs_client = @@character_set_client */;
24   -/*!50503 SET character_set_client = utf8mb4 */;
25   -CREATE TABLE `device` (
26   - `id` int NOT NULL AUTO_INCREMENT,
27   - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
28   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
29   - `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
30   - `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
31   - `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
32   - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
33   - `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
34   - `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
35   - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
36   - `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
37   - `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
38   - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
39   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
40   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
41   - `port` int DEFAULT NULL,
42   - `expires` int DEFAULT NULL,
43   - `keepaliveIntervalTime` int DEFAULT NULL,
44   - `subscribeCycleForCatalog` int DEFAULT NULL,
45   - `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
46   - `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
47   - `subscribeCycleForMobilePosition` int DEFAULT NULL,
48   - `mobilePositionSubmissionInterval` int DEFAULT '5',
49   - `subscribeCycleForAlarm` int DEFAULT NULL,
50   - `ssrcCheck` int DEFAULT '0',
51   - `asMessageChannel` int DEFAULT '0',
52   - `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
53   - `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
54   - `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
55   - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
56   - `sdpIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
57   - `localIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
58   - PRIMARY KEY (`id`),
59   - UNIQUE KEY `device_deviceId_uindex` (`deviceId`)
60   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
61   -/*!40101 SET character_set_client = @saved_cs_client */;
62   -
63   ---
64   --- Dumping data for table `device`
65   ---
66   -
67   -LOCK TABLES `device` WRITE;
68   -/*!40000 ALTER TABLE `device` DISABLE KEYS */;
69   -/*!40000 ALTER TABLE `device` ENABLE KEYS */;
70   -UNLOCK TABLES;
71   -
72   ---
73   --- Table structure for table `device_alarm`
74   ---
75   -
76   -DROP TABLE IF EXISTS `device_alarm`;
77   -/*!40101 SET @saved_cs_client = @@character_set_client */;
78   -/*!50503 SET character_set_client = utf8mb4 */;
79   -CREATE TABLE `device_alarm` (
80   - `id` int NOT NULL AUTO_INCREMENT,
81   - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
82   - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
83   - `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
84   - `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
85   - `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
86   - `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
87   - `longitude` double DEFAULT NULL,
88   - `latitude` double DEFAULT NULL,
89   - `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
90   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
91   - PRIMARY KEY (`id`) USING BTREE
92   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
93   -/*!40101 SET character_set_client = @saved_cs_client */;
94   -
95   ---
96   --- Dumping data for table `device_alarm`
97   ---
98   -
99   -LOCK TABLES `device_alarm` WRITE;
100   -/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */;
101   -/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */;
102   -UNLOCK TABLES;
103   -
104   ---
105   --- Table structure for table `device_channel`
106   ---
107   -
108   -DROP TABLE IF EXISTS `device_channel`;
109   -/*!40101 SET @saved_cs_client = @@character_set_client */;
110   -/*!50503 SET character_set_client = utf8mb4 */;
111   -CREATE TABLE `device_channel` (
112   - `id` int NOT NULL AUTO_INCREMENT,
113   - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
114   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
115   - `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
116   - `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
117   - `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
118   - `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
119   - `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
120   - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
121   - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
122   - `safetyWay` int DEFAULT NULL,
123   - `registerWay` int DEFAULT NULL,
124   - `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
125   - `certifiable` int DEFAULT NULL,
126   - `errCode` int DEFAULT NULL,
127   - `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
128   - `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
129   - `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
130   - `port` int DEFAULT NULL,
131   - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
132   - `PTZType` int DEFAULT NULL,
133   - `status` int DEFAULT NULL,
134   - `longitude` double DEFAULT NULL,
135   - `latitude` double DEFAULT NULL,
136   - `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
137   - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
138   - `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
139   - `hasAudio` bit(1) DEFAULT NULL,
140   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
141   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
142   - `subCount` int DEFAULT '0',
143   - `longitudeGcj02` double DEFAULT NULL,
144   - `latitudeGcj02` double DEFAULT NULL,
145   - `longitudeWgs84` double DEFAULT NULL,
146   - `latitudeWgs84` double DEFAULT NULL,
147   - `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
148   - `gpsTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
149   - PRIMARY KEY (`id`),
150   - UNIQUE KEY `device_channel_id_uindex` (`id`),
151   - UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`)
152   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
153   -/*!40101 SET character_set_client = @saved_cs_client */;
154   -
155   ---
156   --- Dumping data for table `device_channel`
157   ---
158   -
159   -LOCK TABLES `device_channel` WRITE;
160   -/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */;
161   -/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */;
162   -UNLOCK TABLES;
163   -
164   ---
165   --- Table structure for table `device_mobile_position`
166   ---
167   -
168   -DROP TABLE IF EXISTS `device_mobile_position`;
169   -/*!40101 SET @saved_cs_client = @@character_set_client */;
170   -/*!50503 SET character_set_client = utf8mb4 */;
171   -CREATE TABLE `device_mobile_position` (
172   - `id` int NOT NULL AUTO_INCREMENT,
173   - `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
174   - `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
175   - `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
176   - `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
177   - `longitude` double NOT NULL,
178   - `latitude` double NOT NULL,
179   - `altitude` double DEFAULT NULL,
180   - `speed` double DEFAULT NULL,
181   - `direction` double DEFAULT NULL,
182   - `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
183   - `longitudeGcj02` double DEFAULT NULL,
184   - `latitudeGcj02` double DEFAULT NULL,
185   - `longitudeWgs84` double DEFAULT NULL,
186   - `latitudeWgs84` double DEFAULT NULL,
187   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
188   - PRIMARY KEY (`id`)
189   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
190   -/*!40101 SET character_set_client = @saved_cs_client */;
191   -
192   ---
193   --- Dumping data for table `device_mobile_position`
194   ---
195   -
196   -LOCK TABLES `device_mobile_position` WRITE;
197   -/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */;
198   -/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */;
199   -UNLOCK TABLES;
200   -
201   ---
202   --- Table structure for table `gb_stream`
203   ---
204   -
205   -DROP TABLE IF EXISTS `gb_stream`;
206   -/*!40101 SET @saved_cs_client = @@character_set_client */;
207   -/*!50503 SET character_set_client = utf8mb4 */;
208   -CREATE TABLE `gb_stream` (
209   - `gbStreamId` int NOT NULL AUTO_INCREMENT,
210   - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
211   - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
212   - `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
213   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
214   - `longitude` double DEFAULT NULL,
215   - `latitude` double DEFAULT NULL,
216   - `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
217   - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
218   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
219   - PRIMARY KEY (`gbStreamId`) USING BTREE,
220   - UNIQUE KEY `app` (`app`,`stream`) USING BTREE,
221   - UNIQUE KEY `gbId` (`gbId`) USING BTREE
222   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
223   -/*!40101 SET character_set_client = @saved_cs_client */;
224   -
225   ---
226   --- Dumping data for table `gb_stream`
227   ---
228   -
229   -LOCK TABLES `gb_stream` WRITE;
230   -/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */;
231   -/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */;
232   -UNLOCK TABLES;
233   -
234   ---
235   --- Table structure for table `log`
236   ---
237   -
238   -DROP TABLE IF EXISTS `log`;
239   -/*!40101 SET @saved_cs_client = @@character_set_client */;
240   -/*!50503 SET character_set_client = utf8mb4 */;
241   -CREATE TABLE `log` (
242   - `id` int NOT NULL AUTO_INCREMENT,
243   - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
244   - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
245   - `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
246   - `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
247   - `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
248   - `timing` bigint NOT NULL,
249   - `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
250   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
251   - PRIMARY KEY (`id`) USING BTREE
252   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
253   -/*!40101 SET character_set_client = @saved_cs_client */;
254   -
255   ---
256   --- Dumping data for table `log`
257   ---
258   -
259   -LOCK TABLES `log` WRITE;
260   -/*!40000 ALTER TABLE `log` DISABLE KEYS */;
261   -/*!40000 ALTER TABLE `log` ENABLE KEYS */;
262   -UNLOCK TABLES;
263   -
264   ---
265   --- Table structure for table `media_server`
266   ---
267   -
268   -DROP TABLE IF EXISTS `media_server`;
269   -/*!40101 SET @saved_cs_client = @@character_set_client */;
270   -/*!50503 SET character_set_client = utf8mb4 */;
271   -CREATE TABLE `media_server` (
272   - `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
273   - `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
274   - `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
275   - `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
276   - `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
277   - `httpPort` int NOT NULL,
278   - `httpSSlPort` int NOT NULL,
279   - `rtmpPort` int NOT NULL,
280   - `rtmpSSlPort` int NOT NULL,
281   - `rtpProxyPort` int NOT NULL,
282   - `rtspPort` int NOT NULL,
283   - `rtspSSLPort` int NOT NULL,
284   - `autoConfig` int NOT NULL,
285   - `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
286   - `rtpEnable` int NOT NULL,
287   - `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
288   - `recordAssistPort` int NOT NULL,
289   - `defaultServer` int NOT NULL,
290   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
291   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
292   - `hookAliveInterval` int NOT NULL,
293   - PRIMARY KEY (`id`) USING BTREE,
294   - UNIQUE KEY `media_server_i` (`ip`,`httpPort`) USING BTREE
295   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
296   -/*!40101 SET character_set_client = @saved_cs_client */;
297   -
298   ---
299   --- Dumping data for table `media_server`
300   ---
301   -
302   -LOCK TABLES `media_server` WRITE;
303   -/*!40000 ALTER TABLE `media_server` DISABLE KEYS */;
304   -/*!40000 ALTER TABLE `media_server` ENABLE KEYS */;
305   -UNLOCK TABLES;
306   -
307   ---
308   --- Table structure for table `parent_platform`
309   ---
310   -
311   -DROP TABLE IF EXISTS `parent_platform`;
312   -/*!40101 SET @saved_cs_client = @@character_set_client */;
313   -/*!50503 SET character_set_client = utf8mb4 */;
314   -CREATE TABLE `parent_platform` (
315   - `id` int NOT NULL AUTO_INCREMENT,
316   - `enable` int DEFAULT NULL,
317   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
318   - `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
319   - `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
320   - `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
321   - `serverPort` int DEFAULT NULL,
322   - `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
323   - `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
324   - `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
325   - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
326   - `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
327   - `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
328   - `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
329   - `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
330   - `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
331   - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
332   - `ptz` int DEFAULT NULL,
333   - `rtcp` int DEFAULT NULL,
334   - `asMessageChannel` int DEFAULT '0',
335   - `status` bit(1) DEFAULT NULL,
336   - `startOfflinePush` int DEFAULT '0',
337   - `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
338   - `catalogGroup` int DEFAULT '1',
339   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
340   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
341   - `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
342   - PRIMARY KEY (`id`),
343   - UNIQUE KEY `parent_platform_id_uindex` (`id`),
344   - UNIQUE KEY `parent_platform_pk` (`serverGBId`)
345   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
346   -/*!40101 SET character_set_client = @saved_cs_client */;
347   -
348   ---
349   --- Dumping data for table `parent_platform`
350   ---
351   -
352   -LOCK TABLES `parent_platform` WRITE;
353   -/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */;
354   -/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */;
355   -UNLOCK TABLES;
356   -
357   ---
358   --- Table structure for table `platform_catalog`
359   ---
360   -
361   -DROP TABLE IF EXISTS `platform_catalog`;
362   -/*!40101 SET @saved_cs_client = @@character_set_client */;
363   -/*!50503 SET character_set_client = utf8mb4 */;
364   -CREATE TABLE `platform_catalog` (
365   - `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
366   - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
367   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
368   - `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
369   - `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
370   - `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
371   - PRIMARY KEY (`id`) USING BTREE
372   -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
373   -/*!40101 SET character_set_client = @saved_cs_client */;
374   -
375   ---
376   --- Dumping data for table `platform_catalog`
377   ---
378   -
379   -LOCK TABLES `platform_catalog` WRITE;
380   -/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */;
381   -/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */;
382   -UNLOCK TABLES;
383   -
384   ---
385   --- Table structure for table `platform_gb_channel`
386   ---
387   -
388   -DROP TABLE IF EXISTS `platform_gb_channel`;
389   -/*!40101 SET @saved_cs_client = @@character_set_client */;
390   -/*!50503 SET character_set_client = utf8mb4 */;
391   -CREATE TABLE `platform_gb_channel` (
392   - `id` int NOT NULL AUTO_INCREMENT,
393   - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
394   - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
395   - `deviceChannelId` int NOT NULL,
396   - PRIMARY KEY (`id`)
397   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
398   -/*!40101 SET character_set_client = @saved_cs_client */;
399   -
400   ---
401   --- Dumping data for table `platform_gb_channel`
402   ---
403   -
404   -LOCK TABLES `platform_gb_channel` WRITE;
405   -/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */;
406   -/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */;
407   -UNLOCK TABLES;
408   -
409   ---
410   --- Table structure for table `platform_gb_stream`
411   ---
412   -
413   -DROP TABLE IF EXISTS `platform_gb_stream`;
414   -/*!40101 SET @saved_cs_client = @@character_set_client */;
415   -/*!50503 SET character_set_client = utf8mb4 */;
416   -CREATE TABLE `platform_gb_stream` (
417   - `id` int NOT NULL AUTO_INCREMENT,
418   - `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
419   - `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
420   - `gbStreamId` int NOT NULL,
421   - PRIMARY KEY (`id`),
422   - UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`)
423   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
424   -/*!40101 SET character_set_client = @saved_cs_client */;
425   -
426   ---
427   --- Dumping data for table `platform_gb_stream`
428   ---
429   -
430   -LOCK TABLES `platform_gb_stream` WRITE;
431   -/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */;
432   -/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */;
433   -UNLOCK TABLES;
434   -
435   ---
436   --- Table structure for table `stream_proxy`
437   ---
438   -
439   -DROP TABLE IF EXISTS `stream_proxy`;
440   -/*!40101 SET @saved_cs_client = @@character_set_client */;
441   -/*!50503 SET character_set_client = utf8mb4 */;
442   -CREATE TABLE `stream_proxy` (
443   - `id` int NOT NULL AUTO_INCREMENT,
444   - `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
445   - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
446   - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
447   - `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
448   - `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
449   - `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
450   - `timeout_ms` int DEFAULT NULL,
451   - `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
452   - `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
453   - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
454   - `enable_audio` bit(1) DEFAULT NULL,
455   - `enable_mp4` bit(1) DEFAULT NULL,
456   - `enable` bit(1) NOT NULL,
457   - `status` bit(1) NOT NULL,
458   - `enable_remove_none_reader` bit(1) NOT NULL,
459   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
460   - `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
461   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
462   - `enable_disable_none_reader` bit(1) DEFAULT NULL,
463   - PRIMARY KEY (`id`),
464   - UNIQUE KEY `stream_proxy_pk` (`app`,`stream`)
465   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
466   -/*!40101 SET character_set_client = @saved_cs_client */;
467   -
468   ---
469   --- Dumping data for table `stream_proxy`
470   ---
471   -
472   -LOCK TABLES `stream_proxy` WRITE;
473   -/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */;
474   -/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */;
475   -UNLOCK TABLES;
476   -
477   ---
478   --- Table structure for table `stream_push`
479   ---
480   -
481   -DROP TABLE IF EXISTS `stream_push`;
482   -/*!40101 SET @saved_cs_client = @@character_set_client */;
483   -/*!50503 SET character_set_client = utf8mb4 */;
484   -CREATE TABLE `stream_push` (
485   - `id` int NOT NULL AUTO_INCREMENT,
486   - `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
487   - `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
488   - `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
489   - `originType` int DEFAULT NULL,
490   - `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
491   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
492   - `aliveSecond` int DEFAULT NULL,
493   - `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
494   - `serverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
495   - `pushTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
496   - `status` int DEFAULT NULL,
497   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
498   - `pushIng` int DEFAULT NULL,
499   - `self` int DEFAULT NULL,
500   - PRIMARY KEY (`id`),
501   - UNIQUE KEY `stream_push_pk` (`app`,`stream`)
502   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
503   -/*!40101 SET character_set_client = @saved_cs_client */;
504   -
505   ---
506   --- Dumping data for table `stream_push`
507   ---
508   -
509   -LOCK TABLES `stream_push` WRITE;
510   -/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */;
511   -/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */;
512   -UNLOCK TABLES;
513   -
514   ---
515   --- Table structure for table `user`
516   ---
517   -
518   -DROP TABLE IF EXISTS `user`;
519   -/*!40101 SET @saved_cs_client = @@character_set_client */;
520   -/*!50503 SET character_set_client = utf8mb4 */;
521   -CREATE TABLE `user` (
522   - `id` int NOT NULL AUTO_INCREMENT,
523   - `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
524   - `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
525   - `roleId` int NOT NULL,
526   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
527   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
528   - `pushKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
529   - PRIMARY KEY (`id`) USING BTREE,
530   - UNIQUE KEY `user_username_uindex` (`username`) USING BTREE
531   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
532   -/*!40101 SET character_set_client = @saved_cs_client */;
533   -
534   ---
535   --- Dumping data for table `user`
536   ---
537   -
538   -LOCK TABLES `user` WRITE;
539   -/*!40000 ALTER TABLE `user` DISABLE KEYS */;
540   -INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
541   -/*!40000 ALTER TABLE `user` ENABLE KEYS */;
542   -UNLOCK TABLES;
543   -
544   ---
545   --- Table structure for table `user_role`
546   ---
547   -
548   -DROP TABLE IF EXISTS `user_role`;
549   -/*!40101 SET @saved_cs_client = @@character_set_client */;
550   -/*!50503 SET character_set_client = utf8mb4 */;
551   -CREATE TABLE `user_role` (
552   - `id` int NOT NULL AUTO_INCREMENT,
553   - `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
554   - `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
555   - `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
556   - `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
557   - PRIMARY KEY (`id`) USING BTREE
558   -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
559   -/*!40101 SET character_set_client = @saved_cs_client */;
560   -
561   ---
562   --- Dumping data for table `user_role`
563   ---
564   -
565   -LOCK TABLES `user_role` WRITE;
566   -/*!40000 ALTER TABLE `user_role` DISABLE KEYS */;
567   -INSERT INTO `user_role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
568   -/*!40000 ALTER TABLE `user_role` ENABLE KEYS */;
569   -UNLOCK TABLES;
570   -/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
571   -
572   -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
573   -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
574   -/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
575   -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
576   -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
577   -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
578   -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
579   -
580   --- Dump completed on 2022-11-29 11:47:46
581 287 \ No newline at end of file
... ...
src/main/java/com/genersoft/iot/vmp/common/CivilCodePo.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public class CivilCodePo {
  4 +
  5 + private String code;
  6 +
  7 + private String name;
  8 +
  9 + private String parentCode;
  10 +
  11 + public static CivilCodePo getInstance(String[] infoArray) {
  12 + CivilCodePo civilCodePo = new CivilCodePo();
  13 + civilCodePo.setCode(infoArray[0]);
  14 + civilCodePo.setName(infoArray[1]);
  15 + civilCodePo.setParentCode(infoArray[2]);
  16 + return civilCodePo;
  17 + }
  18 +
  19 + public String getCode() {
  20 + return code;
  21 + }
  22 +
  23 + public void setCode(String code) {
  24 + this.code = code;
  25 + }
  26 +
  27 + public String getName() {
  28 + return name;
  29 + }
  30 +
  31 + public void setName(String name) {
  32 + this.name = name;
  33 + }
  34 +
  35 + public String getParentCode() {
  36 + return parentCode;
  37 + }
  38 +
  39 + public void setParentCode(String parentCode) {
  40 + this.parentCode = parentCode;
  41 + }
  42 +}
... ...
src/main/java/com/genersoft/iot/vmp/common/GeneralCallback.java 0 → 100644
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +public interface GeneralCallback<T>{
  4 + void run(int code, String msg, T data);
  5 +}
... ...
src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java
1 1 package com.genersoft.iot.vmp.common;
2 2  
3 3 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
4 5  
5 6 /**
6 7 * 记录每次发送invite消息的状态
... ... @@ -28,7 +29,7 @@ public class InviteInfo {
28 29 private StreamInfo streamInfo;
29 30  
30 31  
31   - public static InviteInfo getinviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
  32 + public static InviteInfo getInviteInfo(String deviceId, String channelId, String stream, SSRCInfo ssrcInfo,
32 33 String receiveIp, Integer receivePort, String streamMode,
33 34 InviteSessionType type, InviteSessionStatus status) {
34 35 InviteInfo inviteInfo = new InviteInfo();
... ... @@ -123,4 +124,21 @@ public class InviteInfo {
123 124 public void setStreamMode(String streamMode) {
124 125 this.streamMode = streamMode;
125 126 }
  127 +
  128 +
  129 + /*=========================设备主子码流逻辑START====================*/
  130 + @Schema(description = "是否为子码流(true-是,false-主码流)")
  131 + private boolean subStream;
  132 +
  133 + public boolean isSubStream() {
  134 + return subStream;
  135 + }
  136 +
  137 + public void setSubStream(boolean subStream) {
  138 + this.subStream = subStream;
  139 + }
  140 +
  141 +
  142 +
  143 +
126 144 }
... ...
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
... ... @@ -528,4 +528,19 @@ public class StreamInfo implements Serializable, Cloneable{
528 528 }
529 529 return instance;
530 530 }
  531 +
  532 +
  533 + /*=========================设备主子码流逻辑START====================*/
  534 + @Schema(description = "是否为子码流(true-是,false-主码流)")
  535 + private boolean subStream;
  536 +
  537 + public boolean isSubStream() {
  538 + return subStream;
  539 + }
  540 +
  541 + public void setSubStream(boolean subStream) {
  542 + this.subStream = subStream;
  543 + }
  544 +
  545 +
531 546 }
... ...
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
... ... @@ -108,6 +108,11 @@ public class VideoManagerConstants {
108 108 public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
109 109  
110 110 /**
  111 + * redis 通知平台关闭推流
  112 + */
  113 + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
  114 +
  115 + /**
111 116 * redis 消息请求所有的在线通道
112 117 */
113 118 public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
... ...
src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import com.genersoft.iot.vmp.common.CivilCodePo;
  4 +import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.boot.CommandLineRunner;
  9 +import org.springframework.context.annotation.Configuration;
  10 +import org.springframework.context.annotation.Lazy;
  11 +import org.springframework.core.annotation.Order;
  12 +import org.springframework.core.io.ClassPathResource;
  13 +import org.springframework.util.ObjectUtils;
  14 +
  15 +import java.io.*;
  16 +import java.nio.file.Files;
  17 +import java.util.Map;
  18 +
  19 +/**
  20 + * 启动时读取行政区划表
  21 + */
  22 +@Configuration
  23 +@Order(value=14)
  24 +public class CivilCodeFileConf implements CommandLineRunner {
  25 +
  26 + private final static Logger logger = LoggerFactory.getLogger(CivilCodeFileConf.class);
  27 +
  28 + private final Map<String, CivilCodePo> civilCodeMap= new ConcurrentHashMap<>();
  29 +
  30 + @Autowired
  31 + @Lazy
  32 + private UserSetting userSetting;
  33 +
  34 + @Override
  35 + public void run(String... args) throws Exception {
  36 + if (ObjectUtils.isEmpty(userSetting.getCivilCodeFile())) {
  37 + logger.warn("[行政区划] 文件未设置,可能造成目录刷新结果不完整");
  38 + return;
  39 + }
  40 + InputStream inputStream;
  41 + if (userSetting.getCivilCodeFile().startsWith("classpath:")){
  42 + String filePath = userSetting.getCivilCodeFile().substring("classpath:".length());
  43 + ClassPathResource civilCodeFile = new ClassPathResource(filePath);
  44 + if (!civilCodeFile.exists()) {
  45 + logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
  46 + return;
  47 + }
  48 + inputStream = civilCodeFile.getInputStream();
  49 +
  50 + }else {
  51 + File civilCodeFile = new File(userSetting.getCivilCodeFile());
  52 + if (!civilCodeFile.exists()) {
  53 + logger.warn("[行政区划] 文件<{}>不存在,可能造成目录刷新结果不完整", userSetting.getCivilCodeFile());
  54 + return;
  55 + }
  56 + inputStream = Files.newInputStream(civilCodeFile.toPath());
  57 + }
  58 +
  59 + BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(inputStream));
  60 + int index = -1;
  61 + String line;
  62 + while ((line = inputStreamReader.readLine()) != null) {
  63 + index ++;
  64 + if (index == 0) {
  65 + continue;
  66 + }
  67 + String[] infoArray = line.split(",");
  68 + CivilCodePo civilCodePo = CivilCodePo.getInstance(infoArray);
  69 + civilCodeMap.put(civilCodePo.getCode(), civilCodePo);
  70 + }
  71 + inputStreamReader.close();
  72 + inputStream.close();
  73 + if (civilCodeMap.size() == 0) {
  74 + logger.warn("[行政区划] 文件内容为空,可能造成目录刷新结果不完整");
  75 + }else {
  76 + logger.info("[行政区划] 加载成功,共加载数据{}条", civilCodeMap.size());
  77 + }
  78 + }
  79 +
  80 + public CivilCodePo getParentCode(String code) {
  81 + if (code.length() > 8) {
  82 + return null;
  83 + }
  84 + if (code.length() == 8) {
  85 + String parentCode = code.substring(0, 6);
  86 + return civilCodeMap.get(parentCode);
  87 + }else {
  88 + CivilCodePo civilCodePo = civilCodeMap.get(code);
  89 + if (civilCodePo == null){
  90 + return null;
  91 + }
  92 + String parentCode = civilCodePo.getParentCode();
  93 + if (parentCode == null) {
  94 + return null;
  95 + }
  96 + return civilCodeMap.get(parentCode);
  97 + }
  98 +
  99 + }
  100 +
  101 +}
... ...
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
... ... @@ -2,11 +2,11 @@ package com.genersoft.iot.vmp.conf;
2 2  
3 3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 4 import com.genersoft.iot.vmp.utils.DateUtil;
5   -import org.junit.jupiter.api.Order;
6 5 import org.slf4j.Logger;
7 6 import org.slf4j.LoggerFactory;
8 7 import org.springframework.beans.factory.annotation.Value;
9 8 import org.springframework.context.annotation.Configuration;
  9 +import org.springframework.core.annotation.Order;
10 10 import org.springframework.util.ObjectUtils;
11 11  
12 12 import java.net.InetAddress;
... ...
src/main/java/com/genersoft/iot/vmp/conf/MybatisConfig.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.apache.ibatis.logging.stdout.StdOutImpl;
  4 +import org.apache.ibatis.session.SqlSessionFactory;
  5 +import org.mybatis.spring.SqlSessionFactoryBean;
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.context.annotation.Bean;
  8 +import org.springframework.context.annotation.Configuration;
  9 +import org.springframework.core.annotation.Order;
  10 +
  11 +import javax.sql.DataSource;
  12 +
  13 +/**
  14 + * 配置mybatis
  15 + */
  16 +@Configuration
  17 +@Order(value=1)
  18 +public class MybatisConfig {
  19 +
  20 + @Autowired
  21 + private UserSetting userSetting;
  22 +
  23 + @Bean
  24 + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  25 + final SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
  26 + sqlSessionFactory.setDataSource(dataSource);
  27 + org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
  28 + if (userSetting.getSqlLog()){
  29 + config.setLogImpl(StdOutImpl.class);
  30 + }
  31 + config.setMapUnderscoreToCamelCase(true);
  32 + sqlSessionFactory.setConfiguration(config);
  33 + return sqlSessionFactory.getObject();
  34 + }
  35 +
  36 +}
... ...
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
... ... @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.service.IMediaServerService;
5 5 import org.apache.http.HttpHost;
6 6 import org.apache.http.HttpRequest;
7 7 import org.apache.http.HttpResponse;
8   -import org.junit.jupiter.api.Order;
  8 +import org.springframework.core.annotation.Order;
9 9 import org.mitre.dsmiley.httpproxy.ProxyServlet;
10 10 import org.slf4j.Logger;
11 11 import org.slf4j.LoggerFactory;
... ...
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
3 3  
4   -import org.junit.jupiter.api.Order;
  4 +import org.springframework.core.annotation.Order;
5 5 import org.springframework.boot.context.properties.ConfigurationProperties;
6 6 import org.springframework.stereotype.Component;
7 7  
... ...
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
... ... @@ -56,7 +56,7 @@ public class SipPlatformRunner implements CommandLineRunner {
56 56 }
57 57  
58 58 // 设置所有平台离线
59   - platformService.offline(parentPlatform, true);
  59 + platformService.offline(parentPlatform, false);
60 60 }
61 61 }
62 62 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
... ... @@ -4,7 +4,7 @@ import io.swagger.v3.oas.models.OpenAPI;
4 4 import io.swagger.v3.oas.models.info.Contact;
5 5 import io.swagger.v3.oas.models.info.Info;
6 6 import io.swagger.v3.oas.models.info.License;
7   -import org.junit.jupiter.api.Order;
  7 +import org.springframework.core.annotation.Order;
8 8 import org.springdoc.core.GroupedOpenApi;
9 9 import org.springframework.beans.factory.annotation.Value;
10 10 import org.springframework.context.annotation.Bean;
... ...
src/main/java/com/genersoft/iot/vmp/conf/ThreadPoolTaskConfig.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
3   -import org.junit.jupiter.api.Order;
4 3 import org.springframework.context.annotation.Bean;
5 4 import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.core.annotation.Order;
6 6 import org.springframework.scheduling.annotation.EnableAsync;
7 7 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
8 8  
... ...
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
3   -import org.junit.jupiter.api.Order;
4 3 import org.springframework.boot.context.properties.ConfigurationProperties;
  4 +import org.springframework.core.annotation.Order;
5 5 import org.springframework.stereotype.Component;
6 6  
7 7 import java.util.ArrayList;
... ... @@ -50,6 +50,7 @@ public class UserSetting {
50 50 private Boolean pushStreamAfterAck = Boolean.FALSE;
51 51  
52 52 private Boolean sipLog = Boolean.FALSE;
  53 + private Boolean sqlLog = Boolean.FALSE;
53 54 private Boolean sendToPlatformsWhenIdLost = Boolean.FALSE;
54 55  
55 56 private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE;
... ... @@ -65,12 +66,18 @@ public class UserSetting {
65 66  
66 67 private String broadcastForPlatform = "UDP";
67 68  
  69 + private String civilCodeFile = "classpath:civilCode.csv";
  70 +
68 71 private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
69 72  
70 73 private List<String> allowedOrigins = new ArrayList<>();
71 74  
72 75 private int maxNotifyCountQueue = 10000;
73 76  
  77 + private int registerAgainAfterTime = 60;
  78 +
  79 + private boolean registerKeepIntDialog = false;
  80 +
74 81 public Boolean getSavePositionHistory() {
75 82 return savePositionHistory;
76 83 }
... ... @@ -306,4 +313,36 @@ public class UserSetting {
306 313 public void setUseCustomSsrcForParentInvite(Boolean useCustomSsrcForParentInvite) {
307 314 this.useCustomSsrcForParentInvite = useCustomSsrcForParentInvite;
308 315 }
  316 +
  317 + public Boolean getSqlLog() {
  318 + return sqlLog;
  319 + }
  320 +
  321 + public void setSqlLog(Boolean sqlLog) {
  322 + this.sqlLog = sqlLog;
  323 + }
  324 +
  325 + public String getCivilCodeFile() {
  326 + return civilCodeFile;
  327 + }
  328 +
  329 + public void setCivilCodeFile(String civilCodeFile) {
  330 + this.civilCodeFile = civilCodeFile;
  331 + }
  332 +
  333 + public int getRegisterAgainAfterTime() {
  334 + return registerAgainAfterTime;
  335 + }
  336 +
  337 + public void setRegisterAgainAfterTime(int registerAgainAfterTime) {
  338 + this.registerAgainAfterTime = registerAgainAfterTime;
  339 + }
  340 +
  341 + public boolean isRegisterKeepIntDialog() {
  342 + return registerKeepIntDialog;
  343 + }
  344 +
  345 + public void setRegisterKeepIntDialog(boolean registerKeepIntDialog) {
  346 + this.registerKeepIntDialog = registerKeepIntDialog;
  347 + }
309 348 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/VersionConfig.java
1 1 package com.genersoft.iot.vmp.conf;
2 2  
3   -import org.junit.jupiter.api.Order;
  3 +import org.springframework.core.annotation.Order;
4 4 import org.springframework.boot.context.properties.ConfigurationProperties;
5 5 import org.springframework.stereotype.Component;
6 6  
... ...
src/main/java/com/genersoft/iot/vmp/conf/redis/RedisMsgListenConfig.java
... ... @@ -43,6 +43,9 @@ public class RedisMsgListenConfig {
43 43 @Autowired
44 44 private RedisPushStreamResponseListener redisPushStreamResponseListener;
45 45  
  46 + @Autowired
  47 + private RedisCloseStreamMsgListener redisCloseStreamMsgListener;
  48 +
46 49  
47 50 /**
48 51 * redis消息监听器容器 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
... ... @@ -63,6 +66,7 @@ public class RedisMsgListenConfig {
63 66 container.addMessageListener(redisPushStreamStatusMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_STATUS_CHANGE));
64 67 container.addMessageListener(redisPushStreamListMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_PUSH_STREAM_LIST_CHANGE));
65 68 container.addMessageListener(redisPushStreamResponseListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_RESPONSE));
  69 + container.addMessageListener(redisCloseStreamMsgListener, new PatternTopic(VideoManagerConstants.VM_MSG_STREAM_PUSH_CLOSE));
66 70 return container;
67 71 }
68 72 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
... ... @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.conf.security;
3 3 import com.alibaba.fastjson2.JSONObject;
4 4 import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
5 5 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  6 +import org.springframework.http.MediaType;
6 7 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7 8 import org.springframework.security.core.AuthenticationException;
8 9 import org.springframework.security.core.context.SecurityContextHolder;
... ... @@ -12,6 +13,7 @@ import org.springframework.stereotype.Component;
12 13 import javax.servlet.http.HttpServletRequest;
13 14 import javax.servlet.http.HttpServletResponse;
14 15 import java.io.IOException;
  16 +import java.nio.charset.StandardCharsets;
15 17  
16 18 /**
17 19 * 处理匿名用户访问逻辑
... ... @@ -35,6 +37,8 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntry
35 37 jsonObject.put("msg", e.getMessage());
36 38 }
37 39 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  40 + response.setContentType(MediaType.APPLICATION_JSON_VALUE);
  41 + response.setCharacterEncoding(StandardCharsets.UTF_8.name());
38 42 try {
39 43 response.getWriter().print(jsonObject.toJSONString());
40 44 } catch (IOException ioException) {
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
1 1 package com.genersoft.iot.vmp.conf.security;
2 2  
3 3 import com.genersoft.iot.vmp.conf.UserSetting;
4   -import org.junit.jupiter.api.Order;
  4 +import org.springframework.core.annotation.Order;
5 5 import org.slf4j.Logger;
6 6 import org.slf4j.LoggerFactory;
7 7 import org.springframework.beans.factory.annotation.Autowired;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
... ... @@ -77,8 +77,8 @@ public class Device {
77 77 /**
78 78 * 在线
79 79 */
80   - @Schema(description = "是否在线,1为在线,0为离线")
81   - private int online;
  80 + @Schema(description = "是否在线,true为在线,false为离线")
  81 + private boolean onLine;
82 82  
83 83  
84 84 /**
... ... @@ -140,7 +140,7 @@ public class Device {
140 140 /**
141 141 * 目录订阅周期,0为不订阅
142 142 */
143   - @Schema(description = "目录订阅周期,0为不订阅")
  143 + @Schema(description = "目录订阅周期,o为不订阅")
144 144 private int subscribeCycleForCatalog;
145 145  
146 146 /**
... ... @@ -173,12 +173,6 @@ public class Device {
173 173 @Schema(description = "地理坐标系, 目前支持 WGS84,GCJ02")
174 174 private String geoCoordSys;
175 175  
176   - /**
177   - * 树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup
178   - */
179   - @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划:CivilCode 和业务分组:BusinessGroup")
180   - private String treeType;
181   -
182 176 @Schema(description = "密码")
183 177 private String password;
184 178  
... ... @@ -195,6 +189,8 @@ public class Device {
195 189 private SipTransactionInfo sipTransactionInfo;
196 190  
197 191  
  192 +
  193 +
198 194 public String getDeviceId() {
199 195 return deviceId;
200 196 }
... ... @@ -286,12 +282,12 @@ public class Device {
286 282 this.hostAddress = hostAddress;
287 283 }
288 284  
289   - public int getOnline() {
290   - return online;
  285 + public boolean isOnLine() {
  286 + return onLine;
291 287 }
292 288  
293   - public void setOnline(int online) {
294   - this.online = online;
  289 + public void setOnLine(boolean onLine) {
  290 + this.onLine = onLine;
295 291 }
296 292  
297 293 public int getChannelCount() {
... ... @@ -406,15 +402,6 @@ public class Device {
406 402 this.geoCoordSys = geoCoordSys;
407 403 }
408 404  
409   -
410   - public String getTreeType() {
411   - return treeType;
412   - }
413   -
414   - public void setTreeType(String treeType) {
415   - this.treeType = treeType;
416   - }
417   -
418 405 public String getPassword() {
419 406 return password;
420 407 }
... ... @@ -462,4 +449,20 @@ public class Device {
462 449 public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
463 450 this.sipTransactionInfo = sipTransactionInfo;
464 451 }
  452 +
  453 + /*======================设备主子码流逻辑START=========================*/
  454 + @Schema(description = "开启主子码流切换的开关(false-不开启,true-开启)")
  455 + private boolean switchPrimarySubStream;
  456 +
  457 + public boolean isSwitchPrimarySubStream() {
  458 + return switchPrimarySubStream;
  459 + }
  460 +
  461 + public void setSwitchPrimarySubStream(boolean switchPrimarySubStream) {
  462 + this.switchPrimarySubStream = switchPrimarySubStream;
  463 + }
  464 +
  465 + /*======================设备主子码流逻辑END=========================*/
  466 +
  467 +
465 468 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
... ... @@ -172,7 +172,7 @@ public class DeviceChannel {
172 172 * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
173 173 */
174 174 @Schema(description = "在线/离线, 1在线,0离线")
175   - private int status;
  175 + private boolean status;
176 176  
177 177 /**
178 178 * 经度
... ... @@ -455,11 +455,11 @@ public class DeviceChannel {
455 455 this.PTZTypeText = PTZTypeText;
456 456 }
457 457  
458   - public int getStatus() {
  458 + public boolean isStatus() {
459 459 return status;
460 460 }
461 461  
462   - public void setStatus(int status) {
  462 + public void setStatus(boolean status) {
463 463 this.status = status;
464 464 }
465 465  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Gb28181Sdp.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import javax.sdp.SessionDescription;
  4 +
  5 +/**
  6 + * 28181 的SDP解析器
  7 + */
  8 +public class Gb28181Sdp {
  9 + private SessionDescription baseSdb;
  10 + private String ssrc;
  11 +
  12 + private String mediaDescription;
  13 +
  14 + public static Gb28181Sdp getInstance(SessionDescription baseSdb, String ssrc, String mediaDescription) {
  15 + Gb28181Sdp gb28181Sdp = new Gb28181Sdp();
  16 + gb28181Sdp.setBaseSdb(baseSdb);
  17 + gb28181Sdp.setSsrc(ssrc);
  18 + gb28181Sdp.setMediaDescription(mediaDescription);
  19 + return gb28181Sdp;
  20 + }
  21 +
  22 +
  23 + public SessionDescription getBaseSdb() {
  24 + return baseSdb;
  25 + }
  26 +
  27 + public void setBaseSdb(SessionDescription baseSdb) {
  28 + this.baseSdb = baseSdb;
  29 + }
  30 +
  31 + public String getSsrc() {
  32 + return ssrc;
  33 + }
  34 +
  35 + public void setSsrc(String ssrc) {
  36 + this.ssrc = ssrc;
  37 + }
  38 +
  39 + public String getMediaDescription() {
  40 + return mediaDescription;
  41 + }
  42 +
  43 + public void setMediaDescription(String mediaDescription) {
  44 + this.mediaDescription = mediaDescription;
  45 + }
  46 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
... ... @@ -10,7 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
10 10 public class GbStream extends PlatformGbStream{
11 11  
12 12 @Schema(description = "ID")
13   - private Integer gbStreamId;
  13 + private int gbStreamId;
14 14 @Schema(description = "应用名")
15 15 private String app;
16 16 @Schema(description = "流ID")
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
... ... @@ -183,12 +183,6 @@ public class ParentPlatform {
183 183 @Schema(description = "创建时间")
184 184 private String createTime;
185 185  
186   - /**
187   - * 树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGroup
188   - */
189   - @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou")
190   - private String treeType;
191   -
192 186 @Schema(description = "是否作为消息通道")
193 187 private boolean asMessageChannel;
194 188  
... ... @@ -424,14 +418,6 @@ public class ParentPlatform {
424 418 this.createTime = createTime;
425 419 }
426 420  
427   - public String getTreeType() {
428   - return treeType;
429   - }
430   -
431   - public void setTreeType(String treeType) {
432   - this.treeType = treeType;
433   - }
434   -
435 421 public boolean isAsMessageChannel() {
436 422 return asMessageChannel;
437 423 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java
... ... @@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
5 5 public class PlatformGbStream {
6 6  
7 7 @Schema(description = "ID")
8   - private Integer gbStreamId;
  8 + private int gbStreamId;
9 9  
10 10 @Schema(description = "平台ID")
11 11 private String platformId;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/TreeType.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.gb28181.bean;
2   -
3   -/**
4   - * 目录结构类型
5   - * @author lin
6   - */
7   -public class TreeType {
8   - public static final String BUSINESS_GROUP = "BusinessGroup";
9   - public static final String CIVIL_CODE = "CivilCode";
10   -}
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java
1 1 package com.genersoft.iot.vmp.gb28181.session;
2 2  
3 3 import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
4 5 import org.springframework.beans.factory.annotation.Autowired;
5 6 import org.springframework.data.redis.core.StringRedisTemplate;
6 7 import org.springframework.stereotype.Component;
... ... @@ -31,10 +32,13 @@ public class SSRCFactory {
31 32 @Autowired
32 33 private SipConfig sipConfig;
33 34  
  35 + @Autowired
  36 + private UserSetting userSetting;
  37 +
34 38  
35 39 public void initMediaServerSSRC(String mediaServerId, Set<String> usedSet) {
36 40 String ssrcPrefix = sipConfig.getDomain().substring(3, 8);
37   - String redisKey = SSRC_INFO_KEY + mediaServerId;
  41 + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
38 42 List<String> ssrcList = new ArrayList<>();
39 43 for (int i = 1; i < MAX_STREAM_COUNT; i++) {
40 44 String ssrc = String.format("%s%04d", ssrcPrefix, i);
... ... @@ -77,7 +81,7 @@ public class SSRCFactory {
77 81 return;
78 82 }
79 83 String sn = ssrc.substring(1);
80   - String redisKey = SSRC_INFO_KEY + mediaServerId;
  84 + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
81 85 redisTemplate.opsForSet().add(redisKey, sn);
82 86 }
83 87  
... ... @@ -86,7 +90,7 @@ public class SSRCFactory {
86 90 */
87 91 private String getSN(String mediaServerId) {
88 92 String sn = null;
89   - String redisKey = SSRC_INFO_KEY + mediaServerId;
  93 + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
90 94 Long size = redisTemplate.opsForSet().size(redisKey);
91 95 if (size == null || size == 0) {
92 96 throw new RuntimeException("ssrc已经用完");
... ... @@ -113,20 +117,8 @@ public class SSRCFactory {
113 117 * @param mediaServerId 流媒体服务ID
114 118 */
115 119 public boolean hasMediaServerSSRC(String mediaServerId) {
116   - String redisKey = SSRC_INFO_KEY + mediaServerId;
  120 + String redisKey = SSRC_INFO_KEY + userSetting.getServerId() + "_" + mediaServerId;
117 121 return redisTemplate.opsForSet().members(redisKey) != null;
118 122 }
119 123  
120   - /**
121   - * 查询ssrc是否可用
122   - *
123   - * @param mediaServerId
124   - * @param ssrc
125   - * @return
126   - */
127   - public boolean checkSsrc(String mediaServerId, String ssrc) {
128   - String sn = ssrc.substring(1);
129   - String redisKey = SSRC_INFO_KEY + mediaServerId;
130   - return redisTemplate.opsForSet().isMember(redisKey, sn) != null;
131   - }
132 124 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
... ... @@ -39,16 +39,22 @@ public class DeferredResultHolder {
39 39  
40 40 public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
41 41  
  42 + public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
  43 +
42 44 public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
43 45  
44 46 public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
45 47  
46   - public static final String CALLBACK_CMD_MOBILEPOSITION = "CALLBACK_MOBILEPOSITION";
  48 + public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
47 49  
48 50 public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
49 51  
50 52 public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
51 53  
  54 + public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
  55 +
  56 + public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP";
  57 +
52 58 private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();
53 59  
54 60  
... ... @@ -149,4 +155,6 @@ public class DeferredResultHolder {
149 155 map.remove(msg.getKey());
150 156 }
151 157 }
  158 +
  159 +
152 160 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
... ... @@ -80,7 +80,7 @@ public interface ISIPCommanderForPlatform {
80 80 * @param fromTag
81 81 * @return
82 82 */
83   - void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException ;
  83 + void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException;
84 84  
85 85 /**
86 86 * 向上级回复移动位置订阅消息
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
... ... @@ -55,8 +55,8 @@ public class SIPRequestHeaderPlarformProvider {
55 55 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
56 56 //via
57 57 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
58   - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(),
59   - parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
  58 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(parentPlatform.getDeviceIp(),
  59 + Integer.parseInt(parentPlatform.getDevicePort()), parentPlatform.getTransport(), SipUtils.getNewViaTag());
60 60 viaHeader.setRPort();
61 61 viaHeaders.add(viaHeader);
62 62 //from
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2  
3   -import com.alibaba.fastjson2.JSONObject;
4 3 import com.genersoft.iot.vmp.common.InviteSessionType;
5 4 import com.genersoft.iot.vmp.common.StreamInfo;
6 5 import com.genersoft.iot.vmp.conf.SipConfig;
7 6 import com.genersoft.iot.vmp.conf.UserSetting;
8 7 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
9 8 import com.genersoft.iot.vmp.gb28181.SipLayer;
10   -import com.genersoft.iot.vmp.gb28181.bean.*;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
11 12 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
12 13 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
13 14 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
... ... @@ -21,6 +22,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
21 22 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
22 23 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamPush;
23 24 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  25 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
24 26 import com.genersoft.iot.vmp.service.IMediaServerService;
25 27 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
26 28 import com.genersoft.iot.vmp.utils.DateUtil;
... ... @@ -155,6 +157,11 @@ public class SIPCommander implements ISIPCommander {
155 157 builder.append(strTmp, 0, 2);
156 158 strTmp = String.format("%02X", parameter2);
157 159 builder.append(strTmp, 0, 2);
  160 + //优化zoom变倍速率
  161 + if ((combineCode2 > 0) && (combineCode2 <16))
  162 + {
  163 + combineCode2 = 16;
  164 + }
158 165 strTmp = String.format("%X", combineCode2);
159 166 builder.append(strTmp, 0, 1).append("0");
160 167 //计算校验码
... ... @@ -280,9 +287,9 @@ public class SIPCommander implements ISIPCommander {
280 287  
281 288 logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
282 289 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
283   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  290 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
284 291 if (event != null) {
285   - event.response(mediaServerItemInUse, json);
  292 + event.response(mediaServerItemInUse, hookParam);
286 293 subscribe.removeSubscribe(hookSubscribe);
287 294 }
288 295 });
... ... @@ -345,6 +352,22 @@ public class SIPCommander implements ISIPCommander {
345 352 }
346 353 }
347 354  
  355 + if( device.isSwitchPrimarySubStream() ){
  356 + if("TP-LINK".equals(device.getManufacturer())){
  357 + if (device.isSwitchPrimarySubStream()){
  358 + content.append("a=streamMode:sub\r\n");
  359 + }else {
  360 + content.append("a=streamMode:main\r\n");
  361 + }
  362 + }else {
  363 + if (device.isSwitchPrimarySubStream()){
  364 + content.append("a=streamprofile:1\r\n");
  365 + }else {
  366 + content.append("a=streamprofile:0\r\n");
  367 + }
  368 + }
  369 + }
  370 +
348 371 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
349 372 // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
350 373 // content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
... ... @@ -360,7 +383,8 @@ public class SIPCommander implements ISIPCommander {
360 383 // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
361 384 ResponseEvent responseEvent = (ResponseEvent) e.event;
362 385 SIPResponse response = (SIPResponse) responseEvent.getResponse();
363   - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY);
  386 + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
  387 + InviteSessionType.PLAY);
364 388 okEvent.response(e);
365 389 });
366 390 }
... ... @@ -450,13 +474,13 @@ public class SIPCommander implements ISIPCommander {
450 474  
451 475 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
452 476 // 添加订阅
453   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  477 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
454 478 if (hookEvent != null) {
455   - hookEvent.response(mediaServerItemInUse, json);
  479 + hookEvent.response(mediaServerItemInUse, hookParam);
456 480 }
457 481 subscribe.removeSubscribe(hookSubscribe);
458 482 });
459   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
  483 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
460 484  
461 485 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
462 486 ResponseEvent responseEvent = (ResponseEvent) event.event;
... ... @@ -553,15 +577,15 @@ public class SIPCommander implements ISIPCommander {
553 577 // 添加订阅
554 578 CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
555 579 String callId= newCallIdHeader.getCallId();
556   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
  580 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
557 581 logger.debug("sipc 添加订阅===callId {}",callId);
558   - hookEvent.response(mediaServerItemInUse, json);
  582 + hookEvent.response(mediaServerItemInUse, hookParam);
559 583 subscribe.removeSubscribe(hookSubscribe);
560 584 hookSubscribe.getContent().put("regist", false);
561 585 hookSubscribe.getContent().put("schema", "rtsp");
562 586 // 添加流注销的订阅,注销了后向设备发送bye
563 587 subscribe.addSubscribe(hookSubscribe,
564   - (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
  588 + (mediaServerItemForEnd, hookParam1) -> {
565 589 logger.info("[录像]下载结束, 发送BYE");
566 590 try {
567 591 streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
... ... @@ -572,17 +596,13 @@ public class SIPCommander implements ISIPCommander {
572 596 });
573 597 });
574 598  
575   - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
  599 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
576 600  
577 601 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
578 602 ResponseEvent responseEvent = (ResponseEvent) event.event;
579 603 SIPResponse response = (SIPResponse) responseEvent.getResponse();
580 604 String contentString =new String(response.getRawContent());
581   - int ssrcIndex = contentString.indexOf("y=");
582   - String ssrc=ssrcInfo.getSsrc();
583   - if (ssrcIndex >= 0) {
584   - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
585   - }
  605 + String ssrc = SipUtils.getSsrcFromSdp(contentString);
586 606 streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
587 607 okEvent.response(event);
588 608 });
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
... ... @@ -230,59 +230,150 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
230 230 // 行政区划分组只需要这两项就可以
231 231 catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n");
232 232 catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n");
233   - if (channel.getParentId() != null) {
234   - // 业务分组加上这一项即可,提高兼容性,
235   - catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
236   -// catalogXml.append("<ParentID>" + parentPlatform.getDeviceGBId() + "/" + channel.getParentId() + "</ParentID>\r\n");
237   - }
238   - if (channel.getChannelId().length() == 20 && Integer.parseInt(channel.getChannelId().substring(10, 13)) == 216) {
239   - // 虚拟组织增加BusinessGroupID字段
240   - catalogXml.append("<BusinessGroupID>" + channel.getParentId() + "</BusinessGroupID>\r\n");
241   - }
242   - if (!channel.getChannelId().equals(parentPlatform.getDeviceGBId())) {
243   - catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n");
244   - if (channel.getParental() == 0) {
245   - catalogXml.append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
  233 + if (channel.getChannelId().length() <= 8) {
  234 + catalogXml.append("</Item>\r\n");
  235 + continue;
  236 + }else {
  237 + if (channel.getChannelId().length() != 20) {
  238 + catalogXml.append("</Item>\r\n");
  239 + continue;
246 240 }
247   - }
248   - if (channel.getParental() == 0) {
249   - // 通道项
250   - catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
251   - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
252   - catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
253   - String civilCode = channel.getCivilCode() == null?parentPlatform.getAdministrativeDivision() : channel.getCivilCode();
254   - if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性
255   - catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
256   - catalogXml.append("<Owner>" + parentPlatform.getDeviceGBId()+ "</Owner>\r\n");
257   - catalogXml.append("<CivilCode>" + civilCode + "</CivilCode>\r\n");
258   - if (channel.getAddress() == null) {
259   - catalogXml.append("<Address></Address>\r\n");
260   - }else {
261   - catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
262   - }
263   - catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
264   - catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
265   - catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
266   - catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
267   - catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
268   - catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
269   - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
270   - catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
271   - catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
272   - catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n");
273   - catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
274   - catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n");
275   - catalogXml.append("<Longitude>" +
276   - (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
277   - + "</Longitude>\r\n");
278   - catalogXml.append("<Latitude>" +
279   - (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
280   - + "</Latitude>\r\n");
281   -
  241 + switch (Integer.parseInt(channel.getChannelId().substring(10, 13))){
  242 + case 200:
  243 +// catalogXml.append("<Manufacturer>三永华通</Manufacturer>\r\n");
  244 +// GitUtil gitUtil = SpringBeanFactory.getBean("gitUtil");
  245 +// String model = (gitUtil == null || gitUtil.getBuildVersion() == null)?"1.0": gitUtil.getBuildVersion();
  246 +// catalogXml.append("<Model>" + model + "</Manufacturer>\r\n");
  247 +// catalogXml.append("<Owner>三永华通</Owner>\r\n");
  248 + if (channel.getCivilCode() != null) {
  249 + catalogXml.append("<CivilCode>"+channel.getCivilCode()+"</CivilCode>\r\n");
  250 + }else {
  251 + catalogXml.append("<CivilCode></CivilCode>\r\n");
  252 + }
  253 +
  254 + catalogXml.append("<RegisterWay>1</RegisterWay>\r\n");
  255 + catalogXml.append("<Secrecy>0</Secrecy>\r\n");
  256 + break;
  257 + case 215:
  258 + if (!ObjectUtils.isEmpty(channel.getParentId())) {
  259 + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
  260 + }
  261 +
  262 + break;
  263 + case 216:
  264 + if (!ObjectUtils.isEmpty(channel.getParentId())) {
  265 + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
  266 + }else {
  267 + catalogXml.append("<ParentID></ParentID>\r\n");
  268 + }
  269 + if (!ObjectUtils.isEmpty(channel.getBusinessGroupId())) {
  270 + catalogXml.append("<BusinessGroupID>" + channel.getBusinessGroupId() + "</BusinessGroupID>\r\n");
  271 + }else {
  272 + catalogXml.append("<BusinessGroupID></BusinessGroupID>\r\n");
  273 + }
  274 + break;
  275 + default:
  276 + // 通道项
  277 + if (channel.getManufacture() != null) {
  278 + catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n");
  279 + }else {
  280 + catalogXml.append("<Manufacturer></Manufacturer>\r\n");
  281 + }
  282 + if (channel.getSecrecy() != null) {
  283 + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
  284 + }else {
  285 + catalogXml.append("<Secrecy></Secrecy>\r\n");
  286 + }
  287 + catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n");
  288 + if (channel.getModel() != null) {
  289 + catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n");
  290 + }else {
  291 + catalogXml.append("<Model></Model>\r\n");
  292 + }
  293 + if (channel.getOwner() != null) {
  294 + catalogXml.append("<Owner>" + channel.getOwner()+ "</Owner>\r\n");
  295 + }else {
  296 + catalogXml.append("<Owner></Owner>\r\n");
  297 + }
  298 + if (channel.getCivilCode() != null) {
  299 + catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n");
  300 + }else {
  301 + catalogXml.append("<CivilCode></CivilCode>\r\n");
  302 + }
  303 + if (channel.getAddress() == null) {
  304 + catalogXml.append("<Address></Address>\r\n");
  305 + }else {
  306 + catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n");
  307 + }
  308 + if (!ObjectUtils.isEmpty(channel.getParentId())) {
  309 + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n");
  310 + }else {
  311 + catalogXml.append("<ParentID></ParentID>\r\n");
  312 + }
  313 + if (!ObjectUtils.isEmpty(channel.getBlock())) {
  314 + catalogXml.append("<Block>" + channel.getBlock() + "</Block>\r\n");
  315 + }else {
  316 + catalogXml.append("<Block></Block>\r\n");
  317 + }
  318 + if (!ObjectUtils.isEmpty(channel.getSafetyWay())) {
  319 + catalogXml.append("<SafetyWay>" + channel.getSafetyWay() + "</SafetyWay>\r\n");
  320 + }else {
  321 + catalogXml.append("<SafetyWay></SafetyWay>\r\n");
  322 + }
  323 + if (!ObjectUtils.isEmpty(channel.getCertNum())) {
  324 + catalogXml.append("<CertNum>" + channel.getCertNum() + "</CertNum>\r\n");
  325 + }else {
  326 + catalogXml.append("<CertNum></CertNum>\r\n");
  327 + }
  328 + if (!ObjectUtils.isEmpty(channel.getCertifiable())) {
  329 + catalogXml.append("<Certifiable>" + channel.getCertifiable() + "</Certifiable>\r\n");
  330 + }else {
  331 + catalogXml.append("<Certifiable></Certifiable>\r\n");
  332 + }
  333 + if (!ObjectUtils.isEmpty(channel.getErrCode())) {
  334 + catalogXml.append("<ErrCode>" + channel.getErrCode() + "</ErrCode>\r\n");
  335 + }else {
  336 + catalogXml.append("<ErrCode></ErrCode>\r\n");
  337 + }
  338 + if (!ObjectUtils.isEmpty(channel.getEndTime())) {
  339 + catalogXml.append("<EndTime>" + channel.getEndTime() + "</EndTime>\r\n");
  340 + }else {
  341 + catalogXml.append("<EndTime></EndTime>\r\n");
  342 + }
  343 + if (!ObjectUtils.isEmpty(channel.getSecrecy())) {
  344 + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n");
  345 + }else {
  346 + catalogXml.append("<Secrecy></Secrecy>\r\n");
  347 + }
  348 + if (!ObjectUtils.isEmpty(channel.getIpAddress())) {
  349 + catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
  350 + }else {
  351 + catalogXml.append("<IPAddress></IPAddress>\r\n");
  352 + }
  353 + catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
  354 + if (!ObjectUtils.isEmpty(channel.getPassword())) {
  355 + catalogXml.append("<Password>" + channel.getPassword() + "</Password>\r\n");
  356 + }else {
  357 + catalogXml.append("<Password></Password>\r\n");
  358 + }
  359 + if (!ObjectUtils.isEmpty(channel.getPTZType())) {
  360 + catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
  361 + }else {
  362 + catalogXml.append("<PTZType></PTZType>\r\n");
  363 + }
  364 + catalogXml.append("<Status>" + (channel.isStatus() ?"ON":"OFF") + "</Status>\r\n");
  365 +
  366 + catalogXml.append("<Longitude>" +
  367 + (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
  368 + + "</Longitude>\r\n");
  369 + catalogXml.append("<Latitude>" +
  370 + (channel.getLatitudeWgs84() != 0? channel.getLatitudeWgs84():channel.getLatitude())
  371 + + "</Latitude>\r\n");
  372 + break;
282 373  
283 374 }
  375 + catalogXml.append("</Item>\r\n");
284 376 }
285   - catalogXml.append("</Item>\r\n");
286 377 }
287 378 }
288 379  
... ... @@ -399,11 +490,11 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
399 490 * @return
400 491 */
401 492 @Override
402   - public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,int status) throws SipException, InvalidArgumentException, ParseException {
  493 + public void deviceStatusResponse(ParentPlatform parentPlatform,String channelId, String sn, String fromTag,boolean status) throws SipException, InvalidArgumentException, ParseException {
403 494 if (parentPlatform == null) {
404 495 return ;
405 496 }
406   - String statusStr = (status==1)?"ONLINE":"OFFLINE";
  497 + String statusStr = (status)?"ONLINE":"OFFLINE";
407 498 String characterSet = parentPlatform.getCharacterSet();
408 499 StringBuffer deviceStatusXml = new StringBuffer(600);
409 500 deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
... ... @@ -564,7 +655,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
564 655 catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n")
565 656 .append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n")
566 657 .append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n")
567   - .append("<Status>" + (channel.getStatus() == 0 ? "OFF" : "ON") + "</Status>\r\n");
  658 + .append("<Status>" + (channel.isStatus() ? "ON" : "OFF") + "</Status>\r\n");
568 659  
569 660 if (channel.getChannelType() != 2) { // 业务分组/虚拟组织/行政区划 不设置以下属性
570 661 catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n")
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
... ... @@ -166,9 +166,8 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
166 166 streamSession.remove(device.getDeviceId(), channelId, ssrcTransactionForPlay.getStream());
167 167 }
168 168 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
169   -
  169 + inviteStreamService.removeInviteInfo(inviteInfo);
170 170 if (inviteInfo != null) {
171   - inviteStreamService.removeInviteInfo(inviteInfo);
172 171 if (inviteInfo.getStreamInfo() != null) {
173 172 mediaServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServerId(), inviteInfo.getStream());
174 173 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
... ... @@ -22,11 +22,12 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
22 22 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
23 23 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
24 24 import com.genersoft.iot.vmp.media.zlm.dto.*;
  25 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
25 26 import com.genersoft.iot.vmp.service.IMediaServerService;
26 27 import com.genersoft.iot.vmp.service.IPlayService;
27 28 import com.genersoft.iot.vmp.service.IStreamProxyService;
28 29 import com.genersoft.iot.vmp.service.IStreamPushService;
29   -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  30 +import com.genersoft.iot.vmp.service.bean.ErrorCallback;
30 31 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
31 32 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
32 33 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ... @@ -217,6 +218,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
217 218 logger.error("[命令发送失败] invite GONE: {}", e.getMessage());
218 219 }
219 220 return;
  221 + }else {
  222 + // TODO 可能漏回复消息
220 223 }
221 224 }
222 225 } else {
... ... @@ -270,18 +273,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
270 273 // 解析sdp消息, 使用jainsip 自带的sdp解析方式
271 274 String contentString = new String(request.getRawContent());
272 275  
273   - // jainSip不支持y=字段, 移除以解析。
274   - // 检查是否有y字段
275   - int ssrcIndex = contentString.indexOf("y=");
276   -
277   - SessionDescription sdp;
278   - if (ssrcIndex >= 0) {
279   - //ssrc规定长度为10个字节,不取余下长度以避免后续还有“f=”字段
280   - String substring = contentString.substring(0, ssrcIndex);
281   - sdp = SdpFactory.getInstance().createSessionDescription(substring);
282   - } else {
283   - sdp = SdpFactory.getInstance().createSessionDescription(contentString);
284   - }
  276 + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
  277 + SessionDescription sdp = gb28181Sdp.getBaseSdb();
285 278 String sessionName = sdp.getSessionName().getValue();
286 279  
287 280 Long startTime = null;
... ... @@ -369,11 +362,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
369 362 }
370 363  
371 364 String ssrc;
372   - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
  365 + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) {
373 366 // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
374 367 ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
375   - } else {
376   - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  368 + }else {
  369 + ssrc = gb28181Sdp.getSsrc();
377 370 }
378 371 String streamTypeStr = null;
379 372 if (mediaTransmissionTCP) {
... ... @@ -406,8 +399,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
406 399  
407 400 Long finalStartTime = startTime;
408 401 Long finalStopTime = stopTime;
409   - InviteErrorCallback<Object> hookEvent = (code, msg, data) -> {
410   - StreamInfo streamInfo = (StreamInfo) data;
  402 + ErrorCallback<Object> hookEvent = (code, msg, data) -> {
  403 + StreamInfo streamInfo = (StreamInfo)data;
411 404 MediaServerItem mediaServerItemInUSe = mediaServerService.getOne(streamInfo.getMediaServerId());
412 405 logger.info("[上级Invite]下级已经开始推流。 回复200OK(SDP), {}/{}", streamInfo.getApp(), streamInfo.getStream());
413 406 // * 0 等待设备推流上来
... ... @@ -460,7 +453,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
460 453 logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
461 454 }
462 455 };
463   - InviteErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
  456 + ErrorCallback<Object> errorEvent = ((statusCode, msg, data) -> {
464 457 // 未知错误。直接转发设备点播的错误
465 458 try {
466 459 if (statusCode > 0) {
... ... @@ -547,11 +540,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
547 540 } else if (gbStream != null) {
548 541  
549 542 String ssrc;
550   - if (userSetting.getUseCustomSsrcForParentInvite() || ssrcIndex < 0) {
  543 + if (userSetting.getUseCustomSsrcForParentInvite() || gb28181Sdp.getSsrc() == null) {
551 544 // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
552 545 ssrc = "Play".equalsIgnoreCase(sessionName) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId());
553   - } else {
554   - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  546 + }else {
  547 + ssrc = gb28181Sdp.getSsrc();
555 548 }
556 549  
557 550 if ("push".equals(gbStream.getStreamType())) {
... ... @@ -690,10 +683,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
690 683 logger.info("[ app={}, stream={} ]通道未推流,启用流后开始推流", gbStream.getApp(), gbStream.getStream());
691 684 // 监听流上线
692 685 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(gbStream.getApp(), gbStream.getStream(), true, "rtsp", mediaServerItem.getId());
693   - zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, responseJSON) -> {
694   - String app = responseJSON.getString("app");
695   - String stream = responseJSON.getString("stream");
696   - logger.info("[上级点播]拉流代理已经就绪, {}/{}", app, stream);
  686 + zlmHttpHookSubscribe.addSubscribe(hookSubscribe, (mediaServerItemInUSe, hookParam) -> {
  687 + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
  688 + logger.info("[上级点播]拉流代理已经就绪, {}/{}", streamChangedHookParam.getApp(), streamChangedHookParam.getStream());
697 689 dynamicTask.stop(callIdHeader.getCallId());
698 690 pushProxyStream(evt, request, gbStream, platform, callIdHeader, mediaServerItem, port, tcpActive,
699 691 mediaTransmissionTCP, channelId, addressStr, ssrc, requesterId);
... ... @@ -971,20 +963,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
971 963 }
972 964 String contentString = new String(request.getRawContent());
973 965 // jainSip不支持y=字段, 移除移除以解析。
974   - String substring = contentString;
975 966 String ssrc = "0000000404";
976   - int ssrcIndex = contentString.indexOf("y=");
977   - if (ssrcIndex > 0) {
978   - substring = contentString.substring(0, ssrcIndex);
979   - ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12).trim();
980   - }
981   - ssrcIndex = substring.indexOf("f=");
982   - if (ssrcIndex > 0) {
983   - substring = contentString.substring(0, ssrcIndex);
984   - }
985   - try {
986   - SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
987 967  
  968 + try {
  969 + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
  970 + SessionDescription sdp = gb28181Sdp.getBaseSdb();
988 971 // 获取支持的格式
989 972 Vector mediaDescriptions = sdp.getMediaDescriptions(true);
990 973  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2  
  3 +import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
3 4 import com.genersoft.iot.vmp.conf.DynamicTask;
4 5 import com.genersoft.iot.vmp.conf.UserSetting;
5 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
... ... @@ -20,7 +21,10 @@ import org.springframework.stereotype.Component;
20 21  
21 22 import javax.sip.RequestEvent;
22 23 import javax.sip.header.FromHeader;
23   -import java.util.*;
  24 +import java.util.ArrayList;
  25 +import java.util.Iterator;
  26 +import java.util.List;
  27 +import java.util.Map;
24 28 import java.util.concurrent.ConcurrentHashMap;
25 29 import java.util.concurrent.CopyOnWriteArrayList;
26 30  
... ... @@ -56,6 +60,9 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
56 60 @Autowired
57 61 private DynamicTask dynamicTask;
58 62  
  63 + @Autowired
  64 + private CivilCodeFileConf civilCodeFileConf;
  65 +
59 66 private final static String talkKey = "notify-request-for-catalog-task";
60 67  
61 68 public void process(RequestEvent evt) {
... ... @@ -65,7 +72,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
65 72 String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
66 73  
67 74 Device device = redisCatchStorage.getDevice(deviceId);
68   - if (device == null || device.getOnline() == 0) {
  75 + if (device == null || !device.isOnLine()) {
69 76 logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" ));
70 77 return;
71 78 }
... ... @@ -96,7 +103,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
96 103 }else {
97 104 event = eventElement.getText().toUpperCase();
98 105 }
99   - DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
  106 + DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
100 107  
101 108 channel.setDeviceId(device.getDeviceId());
102 109 logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
... ... @@ -175,6 +182,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
175 182 }
176 183 }else {
177 184 addChannelMap.put(channel.getChannelId(), channel);
  185 + if (userSetting.getDeviceStatusNotify()) {
  186 + // 发送redis消息
  187 + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
  188 + }
  189 +
178 190 if (addChannelMap.keySet().size() > 300) {
179 191 executeSaveForAdd();
180 192 }
... ... @@ -185,6 +197,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
185 197 // 删除
186 198 logger.info("[收到删除通道通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
187 199 deleteChannelList.add(channel);
  200 + if (userSetting.getDeviceStatusNotify()) {
  201 + // 发送redis消息
  202 + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), false);
  203 + }
188 204 if (deleteChannelList.size() > 300) {
189 205 executeSaveForDelete();
190 206 }
... ... @@ -205,6 +221,10 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
205 221 if (addChannelMap.keySet().size() > 300) {
206 222 executeSaveForAdd();
207 223 }
  224 + if (userSetting.getDeviceStatusNotify()) {
  225 + // 发送redis消息
  226 + redisCatchStorage.sendChannelAddOrDelete(device.getDeviceId(), channel.getChannelId(), true);
  227 + }
208 228 }
209 229 break;
210 230 default:
... ... @@ -232,7 +252,6 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
232 252 }
233 253  
234 254 private void executeSave(){
235   - System.out.println("定时存储数据");
236 255 executeSaveForUpdate();
237 256 executeSaveForDelete();
238 257 executeSaveForOnline();
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
4 5 import com.genersoft.iot.vmp.conf.SipConfig;
5 6 import com.genersoft.iot.vmp.conf.UserSetting;
6 7 import com.genersoft.iot.vmp.gb28181.bean.*;
... ... @@ -79,6 +80,9 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
79 80 @Autowired
80 81 private NotifyRequestForCatalogProcessor notifyRequestForCatalogProcessor;
81 82  
  83 + @Autowired
  84 + private CivilCodeFileConf civilCodeFileConf;
  85 +
82 86 private ConcurrentLinkedQueue<HandlerCatchData> taskQueue = new ConcurrentLinkedQueue<>();
83 87  
84 88 @Qualifier("taskExecutor")
... ... @@ -192,7 +196,12 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
192 196 mobilePosition.setDeviceId(device.getDeviceId());
193 197 mobilePosition.setChannelId(channelId);
194 198 String time = XmlUtil.getText(rootElement, "Time");
195   - mobilePosition.setTime(time);
  199 + if (ObjectUtils.isEmpty(time)){
  200 + mobilePosition.setTime(DateUtil.getNow());
  201 + }else {
  202 + mobilePosition.setTime(SipUtils.parseTime(time));
  203 + }
  204 +
196 205 mobilePosition.setLongitude(Double.parseDouble(XmlUtil.getText(rootElement, "Longitude")));
197 206 mobilePosition.setLatitude(Double.parseDouble(XmlUtil.getText(rootElement, "Latitude")));
198 207 if (NumericUtil.isDouble(XmlUtil.getText(rootElement, "Speed"))) {
... ... @@ -237,7 +246,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
237 246  
238 247 // 发送redis消息。 通知位置信息的变化
239 248 JSONObject jsonObject = new JSONObject();
240   - jsonObject.put("time", time);
  249 + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
241 250 jsonObject.put("serial", deviceId);
242 251 jsonObject.put("code", channelId);
243 252 jsonObject.put("longitude", mobilePosition.getLongitude());
... ... @@ -339,7 +348,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
339 348 storager.updateChannelPosition(deviceChannel);
340 349 // 发送redis消息。 通知位置信息的变化
341 350 JSONObject jsonObject = new JSONObject();
342   - jsonObject.put("time", mobilePosition.getTime());
  351 + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
343 352 jsonObject.put("serial", deviceChannel.getDeviceId());
344 353 jsonObject.put("code", deviceChannel.getChannelId());
345 354 jsonObject.put("longitude", mobilePosition.getLongitude());
... ... @@ -372,7 +381,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
372 381 String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
373 382  
374 383 Device device = redisCatchStorage.getDevice(deviceId);
375   - if (device == null || device.getOnline() == 0) {
  384 + if (device == null || !device.isOnLine()) {
376 385 logger.warn("[收到目录订阅]:{}, 但是设备已经离线", (device != null ? device.getDeviceId():"" ));
377 386 return;
378 387 }
... ... @@ -403,7 +412,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
403 412 }else {
404 413 event = eventElement.getText().toUpperCase();
405 414 }
406   - DeviceChannel channel = XmlUtil.channelContentHander(itemDevice, device, event);
  415 + DeviceChannel channel = XmlUtil.channelContentHandler(itemDevice, device, event, civilCodeFileConf);
407 416 channel.setDeviceId(device.getDeviceId());
408 417 logger.info("[收到目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
409 418 switch (event) {
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
... ... @@ -167,9 +167,8 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
167 167 device.setStreamMode("UDP");
168 168 device.setCharset("GB2312");
169 169 device.setGeoCoordSys("WGS84");
170   - device.setTreeType("CivilCode");
171 170 device.setDeviceId(deviceId);
172   - device.setOnline(0);
  171 + device.setOnLine(false);
173 172 }
174 173 device.setIp(remoteAddressInfo.getIp());
175 174 device.setPort(remoteAddressInfo.getPort());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
... ... @@ -164,7 +164,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
164 164  
165 165 // 发送redis消息。 通知位置信息的变化
166 166 JSONObject jsonObject = new JSONObject();
167   - jsonObject.put("time", mobilePosition.getTime());
  167 + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
168 168 jsonObject.put("serial", deviceChannel.getDeviceId());
169 169 jsonObject.put("code", deviceChannel.getChannelId());
170 170 jsonObject.put("longitude", mobilePosition.getLongitude());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
... ... @@ -83,12 +83,12 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
83 83  
84 84 device.setKeepaliveTime(DateUtil.getNow());
85 85  
86   - if (device.getOnline() == 1) {
  86 + if (device.isOnLine()) {
87 87 deviceService.updateDevice(device);
88 88 }else {
89 89 // 对于已经离线的设备判断他的注册是否已经过期
90 90 if (!deviceService.expire(device)){
91   - device.setOnline(0);
  91 + device.setOnLine(false);
92 92 deviceService.online(device, null);
93 93 }
94 94 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
... ... @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP
7 7 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
8 8 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
9 9 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
  10 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
10 11 import com.genersoft.iot.vmp.service.IDeviceChannelService;
11 12 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
12 13 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
... ... @@ -95,7 +96,12 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
95 96 }
96 97 mobilePosition.setDeviceId(sipMsgInfo.getDevice().getDeviceId());
97 98 mobilePosition.setChannelId(getText(rootElementAfterCharset, "DeviceID"));
98   - mobilePosition.setTime(getText(rootElementAfterCharset, "Time"));
  99 + String time = getText(rootElementAfterCharset, "Time");
  100 + if (ObjectUtils.isEmpty(time)){
  101 + mobilePosition.setTime(DateUtil.getNow());
  102 + }else {
  103 + mobilePosition.setTime(SipUtils.parseTime(time));
  104 + }
99 105 mobilePosition.setLongitude(Double.parseDouble(getText(rootElementAfterCharset, "Longitude")));
100 106 mobilePosition.setLatitude(Double.parseDouble(getText(rootElementAfterCharset, "Latitude")));
101 107 if (NumericUtil.isDouble(getText(rootElementAfterCharset, "Speed"))) {
... ... @@ -138,7 +144,7 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
138 144  
139 145 // 发送redis消息。 通知位置信息的变化
140 146 JSONObject jsonObject = new JSONObject();
141   - jsonObject.put("time", mobilePosition.getTime());
  147 + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
142 148 jsonObject.put("serial", deviceChannel.getDeviceId());
143 149 jsonObject.put("code", deviceChannel.getChannelId());
144 150 jsonObject.put("longitude", mobilePosition.getLongitude());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
... ... @@ -77,7 +77,7 @@ public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent i
77 77 return;
78 78 }
79 79 try {
80   - cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.getStatus());
  80 + cmderFroPlatform.deviceStatusResponse(parentPlatform,channelId, sn, fromHeader.getTag(),deviceChannel.isStatus());
81 81 } catch (SipException | InvalidArgumentException | ParseException e) {
82 82 logger.error("[命令发送失败] 国标级联 DeviceStatus查询回复: {}", e.getMessage());
83 83 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2  
  3 +import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
3 4 import com.genersoft.iot.vmp.gb28181.bean.*;
4 5 import com.genersoft.iot.vmp.gb28181.session.CatalogDataCatch;
5 6 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
... ... @@ -54,6 +55,9 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
54 55 @Autowired
55 56 private ThreadPoolTaskExecutor taskExecutor;
56 57  
  58 + @Autowired
  59 + private CivilCodeFileConf civilCodeFileConf;
  60 +
57 61 @Override
58 62 public void afterPropertiesSet() throws Exception {
59 63 responseMessageHandler.addHandler(cmdType, this);
... ... @@ -101,6 +105,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
101 105 Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
102 106 if (deviceListIterator != null) {
103 107 List<DeviceChannel> channelList = new ArrayList<>();
  108 + List<String> parentChannelIds = new ArrayList<>();
104 109 // 遍历DeviceList
105 110 while (deviceListIterator.hasNext()) {
106 111 Element itemDevice = deviceListIterator.next();
... ... @@ -108,7 +113,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
108 113 if (channelDeviceElement == null) {
109 114 continue;
110 115 }
111   - DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice, device, null);
  116 + DeviceChannel deviceChannel = XmlUtil.channelContentHandler(itemDevice, device, null, civilCodeFileConf);
112 117 deviceChannel = SipUtils.updateGps(deviceChannel, device.getGeoCoordSys());
113 118 deviceChannel.setDeviceId(take.getDevice().getDeviceId());
114 119  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2  
3   -import com.genersoft.iot.vmp.common.VideoManagerConstants;
4   -import com.genersoft.iot.vmp.conf.SipConfig;
5 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7   -import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
8 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 7 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
11 8 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
12 9 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
13 10 import com.genersoft.iot.vmp.service.IDeviceService;
14   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
15   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
16 11 import gov.nist.javax.sip.message.SIPRequest;
17 12 import org.dom4j.DocumentException;
18 13 import org.dom4j.Element;
... ... @@ -59,7 +54,7 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent
59 54 public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
60 55 logger.debug("接收到DeviceInfo应答消息");
61 56 // 检查设备是否存在, 不存在则不回复
62   - if (device == null || device.getOnline() == 0) {
  57 + if (device == null || !device.isOnLine()) {
63 58 logger.warn("[接收到DeviceInfo应答消息,但是设备已经离线]:" + (device != null ? device.getDeviceId():"" ));
64 59 return;
65 60 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
... ... @@ -2,17 +2,21 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
4 4 import com.genersoft.iot.vmp.conf.UserSetting;
5   -import com.genersoft.iot.vmp.gb28181.bean.*;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
  8 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  10 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
6 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
7 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
8 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
9   -import com.genersoft.iot.vmp.gb28181.utils.Coordtransform;
10 14 import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
  15 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
11 16 import com.genersoft.iot.vmp.service.IDeviceChannelService;
12 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 18 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
14 19 import com.genersoft.iot.vmp.utils.DateUtil;
15   -import com.genersoft.iot.vmp.utils.GpsUtil;
16 20 import gov.nist.javax.sip.message.SIPRequest;
17 21 import org.dom4j.DocumentException;
18 22 import org.dom4j.Element;
... ... @@ -56,6 +60,9 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
56 60 @Autowired
57 61 private IDeviceChannelService deviceChannelService;
58 62  
  63 + @Autowired
  64 + private DeferredResultHolder resultHolder;
  65 +
59 66 @Override
60 67 public void afterPropertiesSet() throws Exception {
61 68 responseMessageHandler.addHandler(cmdType, this);
... ... @@ -83,7 +90,13 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
83 90 }
84 91 mobilePosition.setDeviceId(device.getDeviceId());
85 92 mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
86   - mobilePosition.setTime(getText(rootElement, "Time"));
  93 + //兼容ISO 8601格式时间
  94 + String time = getText(rootElement, "Time");
  95 + if (ObjectUtils.isEmpty(time)){
  96 + mobilePosition.setTime(DateUtil.getNow());
  97 + }else {
  98 + mobilePosition.setTime(SipUtils.parseTime(time));
  99 + }
87 100 mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
88 101 mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
89 102 if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
... ... @@ -121,11 +134,18 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
121 134 if (userSetting.getSavePositionHistory()) {
122 135 storager.insertMobilePosition(mobilePosition);
123 136 }
  137 +
124 138 storager.updateChannelPosition(deviceChannel);
125 139  
  140 + String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + device.getDeviceId();
  141 + RequestMessage msg = new RequestMessage();
  142 + msg.setKey(key);
  143 + msg.setData(mobilePosition);
  144 + resultHolder.invokeAllResult(msg);
  145 +
126 146 // 发送redis消息。 通知位置信息的变化
127 147 JSONObject jsonObject = new JSONObject();
128   - jsonObject.put("time", mobilePosition.getTime());
  148 + jsonObject.put("time", DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(mobilePosition.getTime()));
129 149 jsonObject.put("serial", deviceChannel.getDeviceId());
130 150 jsonObject.put("code", deviceChannel.getChannelId());
131 151 jsonObject.put("longitude", mobilePosition.getLongitude());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.SipLayer;
  4 +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp;
4 5 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
5 6 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
6 7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
7 8 import com.genersoft.iot.vmp.gb28181.transmit.event.response.SIPResponseProcessorAbstract;
  9 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
8 10 import gov.nist.javax.sip.ResponseEventExt;
9 11 import gov.nist.javax.sip.message.SIPResponse;
10 12 import org.slf4j.Logger;
... ... @@ -12,7 +14,6 @@ import org.slf4j.LoggerFactory;
12 14 import org.springframework.beans.factory.annotation.Autowired;
13 15 import org.springframework.stereotype.Component;
14 16  
15   -import javax.sdp.SdpFactory;
16 17 import javax.sdp.SdpParseException;
17 18 import javax.sdp.SessionDescription;
18 19 import javax.sip.InvalidArgumentException;
... ... @@ -82,19 +83,8 @@ public class InviteResponseProcessor extends SIPResponseProcessorAbstract {
82 83 ResponseEventExt event = (ResponseEventExt)evt;
83 84  
84 85 String contentString = new String(response.getRawContent());
85   - // jainSip不支持y=字段, 移除以解析。
86   - int ssrcIndex = contentString.indexOf("y=");
87   - // 检查是否有y字段
88   - SessionDescription sdp;
89   - if (ssrcIndex >= 0) {
90   - //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
91   - String substring = contentString.substring(0, contentString.indexOf("y="));
92   - sdp = SdpFactory.getInstance().createSessionDescription(substring);
93   - } else {
94   - sdp = SdpFactory.getInstance().createSessionDescription(contentString);
95   - }
96   - // 查看是否是来自设备的,此是回复
97   -
  86 + Gb28181Sdp gb28181Sdp = SipUtils.parseSDP(contentString);
  87 + SessionDescription sdp = gb28181Sdp.getBaseSdb();
98 88 SipURI requestUri = SipFactory.getInstance().createAddressFactory().createSipURI(sdp.getOrigin().getUsername(), event.getRemoteIpAddress() + ":" + event.getRemotePort());
99 89 Request reqAck = headerProvider.createAckRequest(response.getLocalAddress().getHostAddress(), requestUri, response);
100 90  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
... ... @@ -102,7 +102,7 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
102 102 SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
103 103 platformService.online(parentPlatform, sipTransactionInfo);
104 104 }else {
105   - platformService.offline(parentPlatform, false);
  105 + platformService.offline(parentPlatform, true);
106 106 }
107 107  
108 108 // 注册/注销成功移除缓存的信息
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/SipUtils.java
1 1 package com.genersoft.iot.vmp.gb28181.utils;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  4 +import com.genersoft.iot.vmp.gb28181.bean.Gb28181Sdp;
4 5 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
  6 +import com.genersoft.iot.vmp.utils.DateUtil;
5 7 import com.genersoft.iot.vmp.utils.GitUtil;
6 8 import gov.nist.javax.sip.address.AddressImpl;
7 9 import gov.nist.javax.sip.address.SipUri;
8 10 import gov.nist.javax.sip.header.Subject;
9 11 import gov.nist.javax.sip.message.SIPRequest;
  12 +import org.apache.commons.lang3.RandomStringUtils;
  13 +import org.slf4j.Logger;
  14 +import org.slf4j.LoggerFactory;
10 15 import org.springframework.util.ObjectUtils;
11 16  
  17 +import javax.sdp.SdpFactory;
  18 +import javax.sdp.SdpParseException;
  19 +import javax.sdp.SessionDescription;
12 20 import javax.sip.PeerUnavailableException;
13 21 import javax.sip.SipFactory;
14 22 import javax.sip.header.FromHeader;
... ... @@ -16,6 +24,8 @@ import javax.sip.header.Header;
16 24 import javax.sip.header.UserAgentHeader;
17 25 import javax.sip.message.Request;
18 26 import java.text.ParseException;
  27 +import java.time.LocalDateTime;
  28 +import java.time.format.DateTimeParseException;
19 29 import java.util.ArrayList;
20 30 import java.util.List;
21 31 import java.util.UUID;
... ... @@ -28,6 +38,8 @@ import java.util.UUID;
28 38 */
29 39 public class SipUtils {
30 40  
  41 + private final static Logger logger = LoggerFactory.getLogger(SipUtils.class);
  42 +
31 43 public static String getUserIdFromFromHeader(Request request) {
32 44 FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
33 45 return getUserIdFromFromHeader(fromHeader);
... ... @@ -51,7 +63,7 @@ public class SipUtils {
51 63 }
52 64  
53 65 public static String getNewViaTag() {
54   - return "z9hG4bK" + System.currentTimeMillis();
  66 + return "z9hG4bK" + RandomStringUtils.randomNumeric(10);
55 67 }
56 68  
57 69 public static UserAgentHeader createUserAgentHeader(GitUtil gitUtil) throws PeerUnavailableException, ParseException {
... ... @@ -113,6 +125,12 @@ public class SipUtils {
113 125 strTmp = String.format("%02X", moveSpeed);
114 126 builder.append(strTmp, 0, 2);
115 127 builder.append(strTmp, 0, 2);
  128 +
  129 + //优化zoom低倍速下的变倍速率
  130 + if ((zoomSpeed > 0) && (zoomSpeed <16))
  131 + {
  132 + zoomSpeed = 16;
  133 + }
116 134 strTmp = String.format("%X", zoomSpeed);
117 135 builder.append(strTmp, 0, 1).append("0");
118 136 //计算校验码
... ... @@ -203,4 +221,66 @@ public class SipUtils {
203 221 }
204 222 return deviceChannel;
205 223 }
  224 +
  225 + public static Gb28181Sdp parseSDP(String sdpStr) throws SdpParseException {
  226 +
  227 + // jainSip不支持y= f=字段, 移除以解析。
  228 + int ssrcIndex = sdpStr.indexOf("y=");
  229 + int mediaDescriptionIndex = sdpStr.indexOf("f=");
  230 + // 检查是否有y字段
  231 + SessionDescription sdp;
  232 + String ssrc = null;
  233 + String mediaDescription = null;
  234 + if (mediaDescriptionIndex == 0 && ssrcIndex == 0) {
  235 + sdp = SdpFactory.getInstance().createSessionDescription(sdpStr);
  236 + }else {
  237 + String lines[] = sdpStr.split("\\r?\\n");
  238 + StringBuilder sdpBuffer = new StringBuilder();
  239 + for (String line : lines) {
  240 + if (line.trim().startsWith("y=")) {
  241 + ssrc = line.substring(2);
  242 + }else if (line.trim().startsWith("f=")) {
  243 + mediaDescription = line.substring(2);
  244 + }else {
  245 + sdpBuffer.append(line.trim()).append("\r\n");
  246 + }
  247 + }
  248 + sdp = SdpFactory.getInstance().createSessionDescription(sdpBuffer.toString());
  249 + }
  250 + return Gb28181Sdp.getInstance(sdp, ssrc, mediaDescription);
  251 + }
  252 +
  253 + public static String getSsrcFromSdp(String sdpStr) {
  254 +
  255 + // jainSip不支持y= f=字段, 移除以解析。
  256 + int ssrcIndex = sdpStr.indexOf("y=");
  257 + if (ssrcIndex == 0) {
  258 + return null;
  259 + }
  260 + String lines[] = sdpStr.split("\\r?\\n");
  261 + for (String line : lines) {
  262 + if (line.trim().startsWith("y=")) {
  263 + return line.substring(2);
  264 + }
  265 + }
  266 + return null;
  267 + }
  268 +
  269 + public static String parseTime(String timeStr) {
  270 + if (ObjectUtils.isEmpty(timeStr)){
  271 + return null;
  272 + }
  273 + LocalDateTime localDateTime;
  274 + try {
  275 + localDateTime = LocalDateTime.parse(timeStr);
  276 + }catch (DateTimeParseException e) {
  277 + try {
  278 + localDateTime = LocalDateTime.parse(timeStr, DateUtil.formatterISO8601);
  279 + }catch (DateTimeParseException e2) {
  280 + logger.error("[格式化时间] 无法格式化时间: {}", timeStr);
  281 + return null;
  282 + }
  283 + }
  284 + return localDateTime.format(DateUtil.formatterISO8601);
  285 + }
206 286 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
... ... @@ -2,6 +2,8 @@ package com.genersoft.iot.vmp.gb28181.utils;
2 2  
3 3 import com.alibaba.fastjson2.JSONArray;
4 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.CivilCodePo;
  6 +import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
5 7 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 8 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
7 9 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
... ... @@ -192,7 +194,7 @@ public class XmlUtil {
192 194 CivilCode, BusinessGroup,VirtualOrganization,Other
193 195 }
194 196  
195   - public static DeviceChannel channelContentHander(Element itemDevice, Device device, String event){
  197 + public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){
196 198 DeviceChannel deviceChannel = new DeviceChannel();
197 199 deviceChannel.setDeviceId(device.getDeviceId());
198 200 Element channdelIdElement = itemDevice.element("DeviceID");
... ... @@ -210,208 +212,353 @@ public class XmlUtil {
210 212 // 除了ADD和update情况下需要识别全部内容,
211 213 return deviceChannel;
212 214 }
213   -
214   - ChannelType channelType = ChannelType.Other;
215   - if (channelId.length() <= 8) {
216   - channelType = ChannelType.CivilCode;
  215 + Element nameElement = itemDevice.element("Name");
  216 + if (nameElement != null) {
  217 + deviceChannel.setName(nameElement.getText());
  218 + }
  219 + if(channelId.length() <= 8) {
217 220 deviceChannel.setHasAudio(false);
  221 + CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId);
  222 + if (parentCode != null) {
  223 + deviceChannel.setParentId(parentCode.getCode());
  224 + deviceChannel.setCivilCode(parentCode.getCode());
  225 + }else {
  226 + logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId);
  227 + }
  228 + deviceChannel.setStatus(true);
  229 + return deviceChannel;
218 230 }else {
219   - if (channelId.length() == 20) {
220   - int code = Integer.parseInt(channelId.substring(10, 13));
221   - switch (code){
222   - case 215:
223   - channelType = ChannelType.BusinessGroup;
224   - deviceChannel.setHasAudio(false);
225   - break;
226   - case 216:
227   - channelType = ChannelType.VirtualOrganization;
228   - deviceChannel.setHasAudio(false);
229   - break;
230   - case 136:
231   - case 137:
232   - case 138:
233   - deviceChannel.setHasAudio(true);
234   - break;
235   - default:
236   - deviceChannel.setHasAudio(false);
237   - break;
238   -
239   - }
  231 + if(channelId.length() != 20) {
  232 + logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId);
  233 + return null;
240 234 }
241   - }
242 235  
243   - Element channdelNameElement = itemDevice.element("Name");
244   - String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim() : "";
245   - deviceChannel.setName(channelName);
246   -
247   - String civilCode = XmlUtil.getText(itemDevice, "CivilCode");
248   - deviceChannel.setCivilCode(civilCode);
249   - if (channelType == ChannelType.CivilCode && civilCode == null) {
250   - deviceChannel.setParental(1);
251   - // 行政区划如果没有传递具体值,则推测一个
252   - if (channelId.length() > 2) {
253   - deviceChannel.setCivilCode(channelId.substring(0, channelId.length() - 2));
254   - }
255   - }
256   - if (channelType.equals(ChannelType.CivilCode)) {
257   - // 行政区划其他字段没必要识别了,默认在线即可
258   - deviceChannel.setStatus(1);
259   - deviceChannel.setParental(1);
260   - deviceChannel.setCreateTime(DateUtil.getNow());
261   - deviceChannel.setUpdateTime(DateUtil.getNow());
262   - return deviceChannel;
263   - }
264   - /**
265   - * 行政区划展示设备树与业务分组展示设备树是两种不同的模式
266   - * 行政区划展示设备树 各个目录之间主要靠deviceId做关联,摄像头通过CivilCode指定其属于那个行政区划;都是不超过十位的编号; 结构如下:
267   - * 河北省
268   - * --> 石家庄市
269   - * --> 摄像头
270   - *String parentId = XmlUtil.getText(itemDevice, "ParentID");
271   - if (parentId != null) {
272   - if (parentId.contains("/")) {
273   - String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
274   - String businessGroup = parentId.substring(0, parentId.indexOf("/"));
275   - deviceChannel.setParentId(lastParentId);
276   - }else {
277   - deviceChannel.setParentId(parentId);
278   - }
279   - }
280   - deviceCh --> 正定县
281   - * --> 摄像头
282   - * --> 摄像头
283   - *
284   - * 业务分组展示设备树是顶级是业务分组,其下的虚拟组织靠BusinessGroupID指定其所属的业务分组;摄像头通过ParentId来指定其所属于的虚拟组织:
285   - * 业务分组
286   - * --> 虚拟组织
287   - * --> 摄像头
288   - * --> 虚拟组织
289   - * --> 摄像头
290   - * --> 摄像头
291   - */
292   - String parentId = XmlUtil.getText(itemDevice, "ParentID");
293   - String businessGroupID = XmlUtil.getText(itemDevice, "BusinessGroupID");
294   - if (parentId != null) {
295   - if (parentId.contains("/")) {
296   - String lastParentId = parentId.substring(parentId.lastIndexOf("/") + 1);
297   - if (businessGroupID == null) {
298   - businessGroupID = parentId.substring(0, parentId.indexOf("/"));
299   - }
300   - deviceChannel.setParentId(lastParentId);
  236 + int code = Integer.parseInt(channelId.substring(10, 13));
  237 + if (code == 136 || code == 137 || code == 138) {
  238 + deviceChannel.setHasAudio(true);
301 239 }else {
302   - deviceChannel.setParentId(parentId);
  240 + deviceChannel.setHasAudio(false);
303 241 }
304   - // 兼容设备通道信息中自己为自己父节点的情况
305   - if (deviceChannel.getParentId().equals(deviceChannel.getChannelId())) {
306   - deviceChannel.setParentId(null);
  242 + // 设备厂商
  243 + String manufacturer = getText(itemDevice, "Manufacturer");
  244 + // 设备型号
  245 + String model = getText(itemDevice, "Model");
  246 + // 设备归属
  247 + String owner = getText(itemDevice, "Owner");
  248 + // 行政区域
  249 + String civilCode = getText(itemDevice, "CivilCode");
  250 + // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织
  251 + String businessGroupID = getText(itemDevice, "BusinessGroupID");
  252 + // 父设备/区域/系统ID
  253 + String parentID = getText(itemDevice, "ParentID");
  254 + if (parentID != null && parentID.equalsIgnoreCase("null")) {
  255 + parentID = null;
307 256 }
308   - }
309   - deviceChannel.setBusinessGroupId(businessGroupID);
310   - if (channelType.equals(ChannelType.BusinessGroup) || channelType.equals(ChannelType.VirtualOrganization)) {
311   - // 业务分组和虚拟组织 其他字段没必要识别了,默认在线即可
312   - deviceChannel.setStatus(1);
313   - deviceChannel.setParental(1);
314   - deviceChannel.setCreateTime(DateUtil.getNow());
315   - deviceChannel.setUpdateTime(DateUtil.getNow());
316   - return deviceChannel;
317   - }
  257 + // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
  258 + String registerWay = getText(itemDevice, "RegisterWay");
  259 + // 保密属性(必选)缺省为0;0:不涉密,1:涉密
  260 + String secrecy = getText(itemDevice, "Secrecy");
  261 + // 安装地址
  262 + String address = getText(itemDevice, "Address");
  263 +
  264 + switch (code){
  265 + case 200:
  266 + // 系统目录
  267 + if (!ObjectUtils.isEmpty(manufacturer)) {
  268 + deviceChannel.setManufacture(manufacturer);
  269 + }
  270 + if (!ObjectUtils.isEmpty(model)) {
  271 + deviceChannel.setModel(model);
  272 + }
  273 + if (!ObjectUtils.isEmpty(owner)) {
  274 + deviceChannel.setOwner(owner);
  275 + }
  276 + if (!ObjectUtils.isEmpty(civilCode)) {
  277 + deviceChannel.setCivilCode(civilCode);
  278 + deviceChannel.setParentId(civilCode);
  279 + }else {
  280 + if (!ObjectUtils.isEmpty(parentID)) {
  281 + deviceChannel.setParentId(parentID);
  282 + }
  283 + }
  284 + if (!ObjectUtils.isEmpty(address)) {
  285 + deviceChannel.setAddress(address);
  286 + }
  287 + deviceChannel.setStatus(true);
  288 + if (!ObjectUtils.isEmpty(registerWay)) {
  289 + try {
  290 + deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
  291 + }catch (NumberFormatException exception) {
  292 + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
  293 + }
  294 + }
  295 + if (!ObjectUtils.isEmpty(secrecy)) {
  296 + deviceChannel.setSecrecy(secrecy);
  297 + }
  298 + return deviceChannel;
  299 + case 215:
  300 + // 业务分组
  301 + deviceChannel.setStatus(true);
  302 + if (!ObjectUtils.isEmpty(parentID)) {
  303 + if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) {
  304 + deviceChannel.setParentId(parentID);
  305 + }
  306 + }else {
  307 + logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId");
  308 + if (!ObjectUtils.isEmpty(civilCode)) {
  309 + deviceChannel.setCivilCode(civilCode);
  310 + }
  311 + }
  312 + break;
  313 + case 216:
  314 + // 虚拟组织
  315 + deviceChannel.setStatus(true);
  316 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  317 + deviceChannel.setBusinessGroupId(businessGroupID);
  318 + }
318 319  
319   - Element statusElement = itemDevice.element("Status");
320 320  
321   - if (statusElement != null) {
322   - String status = statusElement.getTextTrim().trim();
323   - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
324   - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
325   - deviceChannel.setStatus(1);
326   - }
327   - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
328   - deviceChannel.setStatus(0);
329   - }
330   - }else {
331   - deviceChannel.setStatus(1);
332   - }
333   - // 识别自带的目录标识
334   - String parental = XmlUtil.getText(itemDevice, "Parental");
335   - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
336   - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
337   - deviceChannel.setParental(0);
338   - }else {
339   - deviceChannel.setParental(1);
340   - }
  321 + if (!ObjectUtils.isEmpty(parentID)) {
  322 + if (parentID.contains("/")) {
  323 + String[] parentIdArray = parentID.split("/");
  324 + parentID = parentIdArray[parentIdArray.length - 1];
  325 + }
  326 + deviceChannel.setParentId(parentID);
  327 + }else {
  328 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  329 + deviceChannel.setParentId(businessGroupID);
  330 + }
  331 + }
  332 + break;
  333 + default:
  334 + // 设备目录
  335 + if (!ObjectUtils.isEmpty(manufacturer)) {
  336 + deviceChannel.setManufacture(manufacturer);
  337 + }
  338 + if (!ObjectUtils.isEmpty(model)) {
  339 + deviceChannel.setModel(model);
  340 + }
  341 + if (!ObjectUtils.isEmpty(owner)) {
  342 + deviceChannel.setOwner(owner);
  343 + }
  344 + if (!ObjectUtils.isEmpty(civilCode)) {
  345 + deviceChannel.setCivilCode(civilCode);
  346 + }
  347 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  348 + deviceChannel.setBusinessGroupId(businessGroupID);
  349 + }
341 350  
  351 + // 警区
  352 + String block = getText(itemDevice, "Block");
  353 + if (!ObjectUtils.isEmpty(block)) {
  354 + deviceChannel.setBlock(block);
  355 + }
  356 + if (!ObjectUtils.isEmpty(address)) {
  357 + deviceChannel.setAddress(address);
  358 + }
342 359  
343   - deviceChannel.setManufacture(XmlUtil.getText(itemDevice, "Manufacturer"));
344   - deviceChannel.setModel(XmlUtil.getText(itemDevice, "Model"));
345   - deviceChannel.setOwner(XmlUtil.getText(itemDevice, "Owner"));
346   - deviceChannel.setCertNum(XmlUtil.getText(itemDevice, "CertNum"));
347   - deviceChannel.setBlock(XmlUtil.getText(itemDevice, "Block"));
348   - deviceChannel.setAddress(XmlUtil.getText(itemDevice, "Address"));
349   - deviceChannel.setPassword(XmlUtil.getText(itemDevice, "Password"));
  360 + if (!ObjectUtils.isEmpty(secrecy)) {
  361 + deviceChannel.setSecrecy(secrecy);
  362 + }
350 363  
351   - String safetyWay = XmlUtil.getText(itemDevice, "SafetyWay");
352   - if (ObjectUtils.isEmpty(safetyWay)) {
353   - deviceChannel.setSafetyWay(0);
354   - } else {
355   - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
356   - }
  364 + // 当为设备时,是否有子设备(必选)1有,0没有
  365 + String parental = getText(itemDevice, "Parental");
  366 + if (!ObjectUtils.isEmpty(parental)) {
  367 + try {
  368 + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
  369 + if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
  370 + deviceChannel.setParental(0);
  371 + }else {
  372 + deviceChannel.setParental(1);
  373 + }
  374 + }catch (NumberFormatException e) {
  375 + logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental);
  376 + }
  377 + }
  378 + // 父设备/区域/系统ID
  379 + String realParentId = parentID;
  380 + if (!ObjectUtils.isEmpty(parentID)) {
  381 + if (parentID.contains("/")) {
  382 + String[] parentIdArray = parentID.split("/");
  383 + realParentId = parentIdArray[parentIdArray.length - 1];
  384 + }
  385 + deviceChannel.setParentId(realParentId);
  386 + }else {
  387 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  388 + deviceChannel.setParentId(businessGroupID);
  389 + }else {
  390 + if (!ObjectUtils.isEmpty(civilCode)) {
  391 + deviceChannel.setParentId(civilCode);
  392 + }
  393 + }
  394 + }
  395 + // 注册方式
  396 + if (!ObjectUtils.isEmpty(registerWay)) {
  397 + try {
  398 + int registerWayInt = Integer.parseInt(registerWay);
  399 + deviceChannel.setRegisterWay(registerWayInt);
  400 + }catch (NumberFormatException exception) {
  401 + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
  402 + deviceChannel.setRegisterWay(1);
  403 + }
  404 + }else {
  405 + deviceChannel.setRegisterWay(1);
  406 + }
357 407  
358   - String registerWay = XmlUtil.getText(itemDevice, "RegisterWay");
359   - if (ObjectUtils.isEmpty(registerWay)) {
360   - deviceChannel.setRegisterWay(1);
361   - } else {
362   - deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
363   - }
  408 + // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式
  409 + String safetyWay = getText(itemDevice, "SafetyWay");
  410 + if (!ObjectUtils.isEmpty(safetyWay)) {
  411 + try {
  412 + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
  413 + }catch (NumberFormatException e) {
  414 + logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay);
  415 + }
  416 + }
364 417  
365   - if (XmlUtil.getText(itemDevice, "Certifiable") == null
366   - || XmlUtil.getText(itemDevice, "Certifiable") == "") {
367   - deviceChannel.setCertifiable(0);
368   - } else {
369   - deviceChannel.setCertifiable(Integer.parseInt(XmlUtil.getText(itemDevice, "Certifiable")));
370   - }
  418 + // 证书序列号(有证书的设备必选)
  419 + String certNum = getText(itemDevice, "CertNum");
  420 + if (!ObjectUtils.isEmpty(certNum)) {
  421 + deviceChannel.setCertNum(certNum);
  422 + }
371 423  
372   - if (XmlUtil.getText(itemDevice, "ErrCode") == null
373   - || XmlUtil.getText(itemDevice, "ErrCode") == "") {
374   - deviceChannel.setErrCode(0);
375   - } else {
376   - deviceChannel.setErrCode(Integer.parseInt(XmlUtil.getText(itemDevice, "ErrCode")));
377   - }
  424 + // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效
  425 + String certifiable = getText(itemDevice, "Certifiable");
  426 + if (!ObjectUtils.isEmpty(certifiable)) {
  427 + try {
  428 + deviceChannel.setCertifiable(Integer.parseInt(certifiable));
  429 + }catch (NumberFormatException e) {
  430 + logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable);
  431 + }
  432 + }
378 433  
379   - deviceChannel.setEndTime(XmlUtil.getText(itemDevice, "EndTime"));
380   - deviceChannel.setSecrecy(XmlUtil.getText(itemDevice, "Secrecy"));
381   - deviceChannel.setIpAddress(XmlUtil.getText(itemDevice, "IPAddress"));
382   - if (XmlUtil.getText(itemDevice, "Port") == null || XmlUtil.getText(itemDevice, "Port") == "") {
383   - deviceChannel.setPort(0);
384   - } else {
385   - deviceChannel.setPort(Integer.parseInt(XmlUtil.getText(itemDevice, "Port")));
386   - }
  434 + // 无效原因码(有证书且证书无效的设备必选)
  435 + String errCode = getText(itemDevice, "ErrCode");
  436 + if (!ObjectUtils.isEmpty(errCode)) {
  437 + try {
  438 + deviceChannel.setErrCode(Integer.parseInt(errCode));
  439 + }catch (NumberFormatException e) {
  440 + logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode);
  441 + }
  442 + }
387 443  
  444 + // 证书终止有效期(有证书的设备必选)
  445 + String endTime = getText(itemDevice, "EndTime");
  446 + if (!ObjectUtils.isEmpty(endTime)) {
  447 + deviceChannel.setEndTime(endTime);
  448 + }
388 449  
389   - String longitude = XmlUtil.getText(itemDevice, "Longitude");
390   - if (NumericUtil.isDouble(longitude)) {
391   - deviceChannel.setLongitude(Double.parseDouble(longitude));
392   - } else {
393   - deviceChannel.setLongitude(0.00);
394   - }
395   - String latitude = XmlUtil.getText(itemDevice, "Latitude");
396   - if (NumericUtil.isDouble(latitude)) {
397   - deviceChannel.setLatitude(Double.parseDouble(latitude));
398   - } else {
399   - deviceChannel.setLatitude(0.00);
400   - }
401 450  
402   - deviceChannel.setGpsTime(DateUtil.getNow());
  451 + // 设备/区域/系统IP地址
  452 + String ipAddress = getText(itemDevice, "IPAddress");
  453 + if (!ObjectUtils.isEmpty(ipAddress)) {
  454 + deviceChannel.setIpAddress(ipAddress);
  455 + }
  456 +
  457 + // 设备/区域/系统端口
  458 + String port = getText(itemDevice, "Port");
  459 + if (!ObjectUtils.isEmpty(port)) {
  460 + try {
  461 + deviceChannel.setPort(Integer.parseInt(port));
  462 + }catch (NumberFormatException e) {
  463 + logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port);
  464 + }
  465 + }
  466 +
  467 + // 设备口令
  468 + String password = getText(itemDevice, "Password");
  469 + if (!ObjectUtils.isEmpty(password)) {
  470 + deviceChannel.setPassword(password);
  471 + }
403 472  
404 473  
405   - if (XmlUtil.getText(itemDevice, "PTZType") == null || "".equals(XmlUtil.getText(itemDevice, "PTZType"))) {
406   - //兼容INFO中的信息
407   - Element info = itemDevice.element("Info");
408   - if(XmlUtil.getText(info, "PTZType") == null || "".equals(XmlUtil.getText(info, "PTZType"))){
409   - deviceChannel.setPTZType(0);
410   - }else{
411   - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(info, "PTZType")));
  474 + // 设备状态
  475 + String status = getText(itemDevice, "Status");
  476 + if (status != null) {
  477 + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
  478 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
  479 + deviceChannel.setStatus(true);
  480 + }
  481 + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
  482 + deviceChannel.setStatus(false);
  483 + }
  484 + }else {
  485 + deviceChannel.setStatus(true);
  486 + }
  487 +
  488 + // 经度
  489 + String longitude = getText(itemDevice, "Longitude");
  490 + if (NumericUtil.isDouble(longitude)) {
  491 + deviceChannel.setLongitude(Double.parseDouble(longitude));
  492 + } else {
  493 + deviceChannel.setLongitude(0.00);
  494 + }
  495 +
  496 + // 纬度
  497 + String latitude = getText(itemDevice, "Latitude");
  498 + if (NumericUtil.isDouble(latitude)) {
  499 + deviceChannel.setLatitude(Double.parseDouble(latitude));
  500 + } else {
  501 + deviceChannel.setLatitude(0.00);
  502 + }
  503 +
  504 + deviceChannel.setGpsTime(DateUtil.getNow());
  505 +
  506 + // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选
  507 + String ptzType = getText(itemDevice, "PTZType");
  508 + if (ObjectUtils.isEmpty(ptzType)) {
  509 + //兼容INFO中的信息
  510 + Element info = itemDevice.element("Info");
  511 + String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
  512 + if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
  513 + try {
  514 + deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo));
  515 + }catch (NumberFormatException e){
  516 + logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo);
  517 + }
  518 + }
  519 + } else {
  520 + try {
  521 + deviceChannel.setPTZType(Integer.parseInt(ptzType));
  522 + }catch (NumberFormatException e){
  523 + logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType);
  524 + }
  525 + }
  526 +
  527 + // TODO 摄像机位置类型扩展。
  528 + // 1-省际检查站、
  529 + // 2-党政机关、
  530 + // 3-车站码头、
  531 + // 4-中心广场、
  532 + // 5-体育场馆、
  533 + // 6-商业中心、
  534 + // 7-宗教场所、
  535 + // 8-校园周边、
  536 + // 9-治安复杂区域、
  537 + // 10-交通干线。
  538 + // String positionType = getText(itemDevice, "PositionType");
  539 +
  540 + // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。
  541 + // String roomType = getText(itemDevice, "RoomType");
  542 + // TODO 摄像机用途属性
  543 + // String useType = getText(itemDevice, "UseType");
  544 + // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光
  545 + // String supplyLightType = getText(itemDevice, "SupplyLightType");
  546 + // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。
  547 + // String directionType = getText(itemDevice, "DirectionType");
  548 + // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定
  549 + // String resolution = getText(itemDevice, "Resolution");
  550 +
  551 + // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4
  552 + // String downloadSpeed = getText(itemDevice, "DownloadSpeed");
  553 + // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层)
  554 + // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode");
  555 + // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强
  556 + // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode");
  557 +
  558 +
  559 + deviceChannel.setSecrecy(secrecy);
  560 + break;
412 561 }
413   - } else {
414   - deviceChannel.setPTZType(Integer.parseInt(XmlUtil.getText(itemDevice, "PTZType")));
415 562 }
416 563  
417 564 return deviceChannel;
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -131,14 +131,12 @@ public class ZLMHttpHookListener {
131 131 @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
132 132 public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
133 133  
134   -// logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId());
135 134  
136 135 taskExecutor.execute(() -> {
137 136 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
138   - JSONObject json = (JSONObject) JSON.toJSON(param);
139 137 if (subscribes != null && subscribes.size() > 0) {
140 138 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
141   - subscribe.response(null, json);
  139 + subscribe.response(null, param);
142 140 }
143 141 }
144 142 });
... ... @@ -165,7 +163,7 @@ public class ZLMHttpHookListener {
165 163 if (subscribe != null) {
166 164 MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
167 165 if (mediaInfo != null) {
168   - subscribe.response(mediaInfo, json);
  166 + subscribe.response(mediaInfo, param);
169 167 }
170 168 }
171 169 });
... ... @@ -198,13 +196,13 @@ public class ZLMHttpHookListener {
198 196 if (userSetting.getPushAuthority()) {
199 197 // 推流鉴权
200 198 if (param.getParams() == null) {
201   - logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
  199 + logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
202 200 return new HookResultForOnPublish(401, "Unauthorized");
203 201 }
204 202 Map<String, String> paramMap = urlParamToMap(param.getParams());
205 203 String sign = paramMap.get("sign");
206 204 if (sign == null) {
207   - logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
  205 + logger.info("推流鉴权失败: 缺少要参数:sign=md5(user表的pushKey)");
208 206 return new HookResultForOnPublish(401, "Unauthorized");
209 207 }
210 208 // 推流自定义播放鉴权码
... ... @@ -241,7 +239,7 @@ public class ZLMHttpHookListener {
241 239 ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
242 240 if (subscribe != null) {
243 241 if (mediaInfo != null) {
244   - subscribe.response(mediaInfo, json);
  242 + subscribe.response(mediaInfo, param);
245 243 } else {
246 244 new HookResultForOnPublish(1, "zlm not register");
247 245 }
... ... @@ -321,7 +319,7 @@ public class ZLMHttpHookListener {
321 319 return;
322 320 }
323 321 if (subscribe != null) {
324   - subscribe.response(mediaInfo, json);
  322 + subscribe.response(mediaInfo, param);
325 323 }
326 324  
327 325 List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
... ... @@ -551,7 +549,9 @@ public class ZLMHttpHookListener {
551 549 Device device = deviceService.getDevice(inviteInfo.getDeviceId());
552 550 if (device != null) {
553 551 try {
554   - if (inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream()) != null) {
  552 + InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
  553 + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  554 + if (info != null) {
555 555 cmder.streamByeCmd(device, inviteInfo.getChannelId(),
556 556 inviteInfo.getStream(), null);
557 557 }
... ... @@ -578,13 +578,13 @@ public class ZLMHttpHookListener {
578 578 // 拉流代理
579 579 StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
580 580 if (streamProxyItem != null) {
581   - if (streamProxyItem.isEnable_remove_none_reader()) {
  581 + if (streamProxyItem.isEnableDisableNoneReader()) {
582 582 // 无人观看自动移除
583 583 ret.put("close", true);
584 584 streamProxyService.del(param.getApp(), param.getStream());
585   - String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrc_url();
  585 + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
586 586 logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url);
587   - } else if (streamProxyItem.isEnable_disable_none_reader()) {
  587 + } else if (streamProxyItem.isEnableDisableNoneReader()) {
588 588 // 无人观看停用
589 589 ret.put("close", true);
590 590 // 修改数据
... ... @@ -669,7 +669,7 @@ public class ZLMHttpHookListener {
669 669 } else {
670 670 // 拉流代理
671 671 StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
672   - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnable_disable_none_reader()) {
  672 + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
673 673 streamProxyService.start(param.getApp(), param.getStream());
674 674 }
675 675 DeferredResult<HookResult> result = new DeferredResult<>();
... ... @@ -693,7 +693,7 @@ public class ZLMHttpHookListener {
693 693 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
694 694 if (subscribes != null && subscribes.size() > 0) {
695 695 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
696   - subscribe.response(null, jsonObject);
  696 + subscribe.response(null, zlmServerConfig);
697 697 }
698 698 }
699 699 mediaServerService.zlmServerOnline(zlmServerConfig);
... ... @@ -749,7 +749,7 @@ public class ZLMHttpHookListener {
749 749 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
750 750 if (subscribes != null && subscribes.size() > 0) {
751 751 for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
752   - subscribe.response(null, json);
  752 + subscribe.response(null, param);
753 753 }
754 754 }
755 755 });
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
... ... @@ -157,7 +157,6 @@ public class ZLMRESTfulUtils {
157 157  
158 158 public void sendGetForImg(MediaServerItem mediaServerItem, String api, Map<String, Object> params, String targetPath, String fileName) {
159 159 String url = String.format("http://%s:%s/index/api/%s", mediaServerItem.getIp(), mediaServerItem.getHttpPort(), api);
160   - logger.debug(url);
161 160 HttpUrl parseUrl = HttpUrl.parse(url);
162 161 if (parseUrl == null) {
163 162 return;
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
... ... @@ -9,6 +9,11 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
9 9 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
10 10 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
11 11 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  15 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
  16 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 17 import org.slf4j.Logger;
13 18 import org.slf4j.LoggerFactory;
14 19 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -228,7 +233,7 @@ public class ZLMRTPServerFactory {
228 233 int localPort = 0;
229 234 if (userSetting.getGbSendStreamStrict()) {
230 235 if (userSetting.getGbSendStreamStrict()) {
231   - localPort = keepPort(serverItem, ssrc, null);
  236 + localPort = keepPort(serverItem, ssrc, localPort);
232 237 if (localPort == 0) {
233 238 return null;
234 239 }
... ... @@ -264,7 +269,7 @@ public class ZLMRTPServerFactory {
264 269 // 默认为随机端口
265 270 int localPort = 0;
266 271 if (userSetting.getGbSendStreamStrict()) {
267   - localPort = keepPort(serverItem, ssrc, null);
  272 + localPort = keepPort(serverItem, ssrc, localPort);
268 273 if (localPort == 0) {
269 274 return null;
270 275 }
... ... @@ -290,9 +295,6 @@ public class ZLMRTPServerFactory {
290 295 */
291 296 public int keepPort(MediaServerItem serverItem, String ssrc, Integer localPort) {
292 297 Map<String, Object> param = new HashMap<>(3);
293   - if (localPort == null) {
294   - localPort = 0;
295   - }
296 298 param.put("port", localPort);
297 299 param.put("enable_tcp", 1);
298 300 param.put("stream_id", ssrc);
... ... @@ -302,22 +304,24 @@ public class ZLMRTPServerFactory {
302 304 HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(ssrc, null, serverItem.getId());
303 305 Integer finalLocalPort = localPort;
304 306 hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
305   - (MediaServerItem mediaServerItem, JSONObject response)->{
306   - if (ssrc.equals(response.getString("ssrc"))) {
307   - logger.info("[上级点播] {}->监听端口到期继续保持监听", ssrc);
308   - int port = keepPort(serverItem, ssrc, finalLocalPort);
309   - if (port == 0) {
310   - logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
311   - hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
312   - }
  307 + (MediaServerItem mediaServerItem, HookParam hookParam)->{
  308 + logger.info("[上级点播] {}->监听端口到期继续保持监听: {}", ssrc, finalLocalPort);
  309 + OnRtpServerTimeoutHookParam rtpServerTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam;
  310 + if (!ssrc.equals(rtpServerTimeoutHookParam.getSsrc())) {
  311 + return;
  312 + }
  313 + int port = keepPort(serverItem, ssrc, finalLocalPort);
  314 + if (port == 0) {
  315 + logger.info("[上级点播] {}->监听端口失败,移除监听", ssrc);
  316 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
313 317 }
314 318 });
315   - logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
316   - logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
  319 + logger.info("[上级点播] {}->监听端口: {}", ssrc, localPort);
  320 + return localPort;
317 321 }else {
318   - logger.info("[保持端口] 监听端口失败: {}", ssrc);
  322 + logger.info("[上级点播] 监听端口失败: {}->{}", ssrc, localPort);
  323 + return 0;
319 324 }
320   - return localPort;
321 325 }
322 326  
323 327 /**
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
... ... @@ -65,8 +65,8 @@ public class ZLMRunner implements CommandLineRunner {
65 65 HookSubscribeForServerStarted hookSubscribeForServerStarted = HookSubscribeFactory.on_server_started();
66 66 // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
67 67 hookSubscribe.addSubscribe(hookSubscribeForServerStarted,
68   - (MediaServerItem mediaServerItem, JSONObject response)->{
69   - ZLMServerConfig zlmServerConfig = response.to(ZLMServerConfig.class);
  68 + (mediaServerItem, hookParam)->{
  69 + ZLMServerConfig zlmServerConfig = (ZLMServerConfig)hookParam;
70 70 if (zlmServerConfig !=null ) {
71 71 if (startGetMedia != null) {
72 72 startGetMedia.remove(zlmServerConfig.getGeneralMediaServerId());
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
1 1 package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson2.annotation.JSONField;
  4 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
4 5  
5   -public class ZLMServerConfig {
  6 +public class ZLMServerConfig extends HookParam {
6 7  
7 8 @JSONField(name = "api.apiDebug")
8 9 private String apiDebug;
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java
... ... @@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
4 4 import com.genersoft.iot.vmp.media.zlm.dto.HookType;
5 5 import com.genersoft.iot.vmp.media.zlm.dto.IHookSubscribe;
6 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  7 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
7 8 import org.slf4j.Logger;
8 9 import org.slf4j.LoggerFactory;
9 10 import org.springframework.scheduling.annotation.Scheduled;
... ... @@ -26,7 +27,7 @@ public class ZlmHttpHookSubscribe {
26 27  
27 28 @FunctionalInterface
28 29 public interface Event{
29   - void response(MediaServerItem mediaServerItem, JSONObject response);
  30 + void response(MediaServerItem mediaServerItem, HookParam hookParam);
30 31 }
31 32  
32 33 private Map<HookType, Map<IHookSubscribe, ZlmHttpHookSubscribe.Event>> allSubscribes = new ConcurrentHashMap<>();
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
... ... @@ -20,28 +20,26 @@ public class StreamProxyItem extends GbStream {
20 20 @Schema(description = "拉流地址")
21 21 private String url;
22 22 @Schema(description = "拉流地址")
23   - private String src_url;
  23 + private String srcUrl;
24 24 @Schema(description = "目标地址")
25   - private String dst_url;
  25 + private String dstUrl;
26 26 @Schema(description = "超时时间")
27   - private int timeout_ms;
  27 + private int timeoutMs;
28 28 @Schema(description = "ffmpeg模板KEY")
29   - private String ffmpeg_cmd_key;
  29 + private String ffmpegCmdKey;
30 30 @Schema(description = "rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播")
31   - private String rtp_type;
  31 + private String rtpType;
32 32 @Schema(description = "是否启用")
33 33 private boolean enable;
34 34 @Schema(description = "是否启用音频")
35   - private boolean enable_audio;
  35 + private boolean enableAudio;
36 36 @Schema(description = "是否启用MP4")
37   - private boolean enable_mp4;
  37 + private boolean enableMp4;
38 38 @Schema(description = "是否 无人观看时删除")
39   - private boolean enable_remove_none_reader;
  39 + private boolean enableRemoveNoneReader;
40 40  
41 41 @Schema(description = "是否 无人观看时自动停用")
42   - private boolean enable_disable_none_reader;
43   - @Schema(description = "创建时间")
44   - private String createTime;
  42 + private boolean enableDisableNoneReader;
45 43  
46 44 public String getType() {
47 45 return type;
... ... @@ -89,44 +87,44 @@ public class StreamProxyItem extends GbStream {
89 87 this.url = url;
90 88 }
91 89  
92   - public String getSrc_url() {
93   - return src_url;
  90 + public String getSrcUrl() {
  91 + return srcUrl;
94 92 }
95 93  
96   - public void setSrc_url(String src_url) {
97   - this.src_url = src_url;
  94 + public void setSrcUrl(String src_url) {
  95 + this.srcUrl = src_url;
98 96 }
99 97  
100   - public String getDst_url() {
101   - return dst_url;
  98 + public String getDstUrl() {
  99 + return dstUrl;
102 100 }
103 101  
104   - public void setDst_url(String dst_url) {
105   - this.dst_url = dst_url;
  102 + public void setDstUrl(String dst_url) {
  103 + this.dstUrl = dst_url;
106 104 }
107 105  
108   - public int getTimeout_ms() {
109   - return timeout_ms;
  106 + public int getTimeoutMs() {
  107 + return timeoutMs;
110 108 }
111 109  
112   - public void setTimeout_ms(int timeout_ms) {
113   - this.timeout_ms = timeout_ms;
  110 + public void setTimeoutMs(int timeout_ms) {
  111 + this.timeoutMs = timeout_ms;
114 112 }
115 113  
116   - public String getFfmpeg_cmd_key() {
117   - return ffmpeg_cmd_key;
  114 + public String getFfmpegCmdKey() {
  115 + return ffmpegCmdKey;
118 116 }
119 117  
120   - public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) {
121   - this.ffmpeg_cmd_key = ffmpeg_cmd_key;
  118 + public void setFfmpegCmdKey(String ffmpeg_cmd_key) {
  119 + this.ffmpegCmdKey = ffmpeg_cmd_key;
122 120 }
123 121  
124   - public String getRtp_type() {
125   - return rtp_type;
  122 + public String getRtpType() {
  123 + return rtpType;
126 124 }
127 125  
128   - public void setRtp_type(String rtp_type) {
129   - this.rtp_type = rtp_type;
  126 + public void setRtpType(String rtp_type) {
  127 + this.rtpType = rtp_type;
130 128 }
131 129  
132 130 public boolean isEnable() {
... ... @@ -137,45 +135,37 @@ public class StreamProxyItem extends GbStream {
137 135 this.enable = enable;
138 136 }
139 137  
140   - public boolean isEnable_mp4() {
141   - return enable_mp4;
  138 + public boolean isEnableMp4() {
  139 + return enableMp4;
142 140 }
143 141  
144   - public void setEnable_mp4(boolean enable_mp4) {
145   - this.enable_mp4 = enable_mp4;
  142 + public void setEnableMp4(boolean enable_mp4) {
  143 + this.enableMp4 = enable_mp4;
146 144 }
147 145  
148   - @Override
149   - public String getCreateTime() {
150   - return createTime;
  146 + public boolean isEnableRemoveNoneReader() {
  147 + return enableRemoveNoneReader;
151 148 }
152 149  
153   - @Override
154   - public void setCreateTime(String createTime) {
155   - this.createTime = createTime;
  150 + public void setEnableRemoveNoneReader(boolean enable_remove_none_reader) {
  151 + this.enableRemoveNoneReader = enable_remove_none_reader;
156 152 }
157 153  
158   - public boolean isEnable_remove_none_reader() {
159   - return enable_remove_none_reader;
  154 + public boolean isEnableDisableNoneReader() {
  155 + return enableDisableNoneReader;
160 156 }
161 157  
162   - public void setEnable_remove_none_reader(boolean enable_remove_none_reader) {
163   - this.enable_remove_none_reader = enable_remove_none_reader;
  158 + public void setEnableDisableNoneReader(boolean enable_disable_none_reader) {
  159 + this.enableDisableNoneReader = enable_disable_none_reader;
164 160 }
165 161  
166   - public boolean isEnable_disable_none_reader() {
167   - return enable_disable_none_reader;
  162 + public boolean isEnableAudio() {
  163 + return enableAudio;
168 164 }
169 165  
170   - public void setEnable_disable_none_reader(boolean enable_disable_none_reader) {
171   - this.enable_disable_none_reader = enable_disable_none_reader;
  166 + public void setEnableAudio(boolean enable_audio) {
  167 + this.enableAudio = enable_audio;
172 168 }
173 169  
174   - public boolean isEnable_audio() {
175   - return enable_audio;
176   - }
177 170  
178   - public void setEnable_audio(boolean enable_audio) {
179   - this.enable_audio = enable_audio;
180   - }
181 171 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java
... ... @@ -325,5 +325,65 @@ public class StreamPushItem extends GbStream implements Comparable&lt;StreamPushIte
325 325 public void setSelf(boolean self) {
326 326 this.self = self;
327 327 }
  328 +
  329 +// @Override
  330 +// public Integer getGbStreamId() {
  331 +// return super.getGbStreamId();
  332 +// }
  333 +//
  334 +// @Override
  335 +// public void setGbStreamId(Integer gbStreamId) {
  336 +// super.setGbStreamId(gbStreamId);
  337 +// }
  338 +//
  339 +//
  340 +// public String getGbId() {
  341 +// return super.getGbId();
  342 +// }
  343 +//
  344 +// public void setGbId(String gbId) {
  345 +// super.setGbId(gbId);
  346 +// }
  347 +//
  348 +// public String getName() {
  349 +// return super.getName();
  350 +// }
  351 +//
  352 +// public void setName(String name) {
  353 +// super.setName(name);
  354 +// }
  355 +//
  356 +// public double getLongitude() {
  357 +// return super.getLongitude();
  358 +// }
  359 +//
  360 +// public void setLongitude(double longitude) {
  361 +// super.setLongitude(longitude);
  362 +// }
  363 +//
  364 +// public double getLatitude() {
  365 +// return super.getLatitude();
  366 +// }
  367 +//
  368 +// public void setLatitude(double latitude) {
  369 +// super.setLatitude(latitude);
  370 +// }
  371 +//
  372 +// public String getStreamType() {
  373 +// return super.getStreamType();
  374 +// }
  375 +//
  376 +// public void setStreamType(String streamType) {
  377 +// super.setStreamType(streamType);
  378 +// }
  379 +//
  380 +// public boolean isStatus() {
  381 +// return super.isStatus();
  382 +// }
  383 +//
  384 +// public void setStatus(boolean status) {
  385 +// super.setStatus(status);
  386 +// }
  387 +
328 388 }
329 389  
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
... ... @@ -50,4 +50,6 @@ public class HookResultForOnPublish extends HookResult{
50 50 public void setMp4_save_path(String mp4_save_path) {
51 51 this.mp4_save_path = mp4_save_path;
52 52 }
  53 +
  54 +
53 55 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java
... ... @@ -81,6 +81,15 @@ public class OnPlayHookParam extends HookParam{
81 81  
82 82 @Override
83 83 public String toString() {
84   - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
  84 + return "OnPlayHookParam{" +
  85 + "id='" + id + '\'' +
  86 + ", app='" + app + '\'' +
  87 + ", stream='" + stream + '\'' +
  88 + ", ip='" + ip + '\'' +
  89 + ", params='" + params + '\'' +
  90 + ", port=" + port +
  91 + ", schema='" + schema + '\'' +
  92 + ", vhost='" + vhost + '\'' +
  93 + '}';
85 94 }
86 95 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java
... ... @@ -81,6 +81,15 @@ public class OnPublishHookParam extends HookParam{
81 81  
82 82 @Override
83 83 public String toString() {
84   - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
  84 + return "OnPublishHookParam{" +
  85 + "id='" + id + '\'' +
  86 + ", app='" + app + '\'' +
  87 + ", stream='" + stream + '\'' +
  88 + ", ip='" + ip + '\'' +
  89 + ", params='" + params + '\'' +
  90 + ", port=" + port +
  91 + ", schema='" + schema + '\'' +
  92 + ", vhost='" + vhost + '\'' +
  93 + '}';
85 94 }
86 95 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java
... ... @@ -50,4 +50,15 @@ public class OnRtpServerTimeoutHookParam extends HookParam{
50 50 public void setSsrc(String ssrc) {
51 51 this.ssrc = ssrc;
52 52 }
  53 +
  54 + @Override
  55 + public String toString() {
  56 + return "OnRtpServerTimeoutHookParam{" +
  57 + "local_port=" + local_port +
  58 + ", stream_id='" + stream_id + '\'' +
  59 + ", tcpMode=" + tcpMode +
  60 + ", re_use_port=" + re_use_port +
  61 + ", ssrc='" + ssrc + '\'' +
  62 + '}';
  63 + }
53 64 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java
... ... @@ -24,4 +24,12 @@ public class OnSendRtpStoppedHookParam extends HookParam{
24 24 public void setStream(String stream) {
25 25 this.stream = stream;
26 26 }
  27 +
  28 + @Override
  29 + public String toString() {
  30 + return "OnSendRtpStoppedHookParam{" +
  31 + "app='" + app + '\'' +
  32 + ", stream='" + stream + '\'' +
  33 + '}';
  34 + }
27 35 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java
... ... @@ -17,4 +17,11 @@ public class OnServerKeepaliveHookParam extends HookParam{
17 17 public void setData(ServerKeepaliveData data) {
18 18 this.data = data;
19 19 }
  20 +
  21 + @Override
  22 + public String toString() {
  23 + return "OnServerKeepaliveHookParam{" +
  24 + "data=" + data +
  25 + '}';
  26 + }
20 27 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
... ... @@ -430,4 +430,14 @@ public class OnStreamChangedHookParam extends HookParam{
430 430 public void setCallId(String callId) {
431 431 this.callId = callId;
432 432 }
  433 +
  434 + @Override
  435 + public String toString() {
  436 + return "OnStreamChangedHookParam{" +
  437 + "regist=" + regist +
  438 + ", app='" + app + '\'' +
  439 + ", stream='" + stream + '\'' +
  440 + ", severId='" + severId + '\'' +
  441 + '}';
  442 + }
433 443 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java
... ... @@ -38,4 +38,14 @@ public class OnStreamNoneReaderHookParam extends HookParam{
38 38 public void setVhost(String vhost) {
39 39 this.vhost = vhost;
40 40 }
  41 +
  42 + @Override
  43 + public String toString() {
  44 + return "OnStreamNoneReaderHookParam{" +
  45 + "schema='" + schema + '\'' +
  46 + ", app='" + app + '\'' +
  47 + ", stream='" + stream + '\'' +
  48 + ", vhost='" + vhost + '\'' +
  49 + '}';
  50 + }
41 51 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java
... ... @@ -81,6 +81,15 @@ public class OnStreamNotFoundHookParam extends HookParam{
81 81  
82 82 @Override
83 83 public String toString() {
84   - return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
  84 + return "OnStreamNotFoundHookParam{" +
  85 + "id='" + id + '\'' +
  86 + ", app='" + app + '\'' +
  87 + ", stream='" + stream + '\'' +
  88 + ", ip='" + ip + '\'' +
  89 + ", params='" + params + '\'' +
  90 + ", port=" + port +
  91 + ", schema='" + schema + '\'' +
  92 + ", vhost='" + vhost + '\'' +
  93 + '}';
85 94 }
86 95 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java
... ... @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 4 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
5   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  5 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
6 6 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
7 7  
8 8 import java.util.List;
... ... @@ -38,7 +38,7 @@ public interface IDeviceChannelService {
38 38 * 获取统计信息
39 39 * @return
40 40 */
41   - ResourceBaceInfo getOverview();
  41 + ResourceBaseInfo getOverview();
42 42  
43 43 /**
44 44 * 查询所有未分配的通道
... ...
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
... ... @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
5 5 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
6 6 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
7 7 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
8   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  8 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
9 9  
10 10 import java.util.List;
11 11  
... ... @@ -162,7 +162,7 @@ public interface IDeviceService {
162 162 * 获取统计信息
163 163 * @return
164 164 */
165   - ResourceBaceInfo getOverview();
  165 + ResourceBaseInfo getOverview();
166 166  
167 167 /**
168 168 * 获取所有设备
... ...
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java
... ... @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.genersoft.iot.vmp.common.InviteInfo;
4 4 import com.genersoft.iot.vmp.common.InviteSessionType;
5   -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  5 +import com.genersoft.iot.vmp.service.bean.ErrorCallback;
6 6  
7 7 /**
8 8 * 记录国标点播的状态,包括实时预览,下载,录像回放
... ... @@ -14,6 +14,8 @@ public interface IInviteStreamService {
14 14 */
15 15 void updateInviteInfo(InviteInfo inviteInfo);
16 16  
  17 + InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream);
  18 +
17 19 /**
18 20 * 获取点播的状态信息
19 21 */
... ... @@ -54,7 +56,7 @@ public interface IInviteStreamService {
54 56 /**
55 57 * 添加一个invite回调
56 58 */
57   - void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback);
  59 + void once(InviteSessionType type, String deviceId, String channelId, String stream, ErrorCallback<Object> callback);
58 60  
59 61 /**
60 62 * 调用一个invite回调
... ... @@ -65,4 +67,12 @@ public interface IInviteStreamService {
65 67 * 清空一个设备的所有invite信息
66 68 */
67 69 void clearInviteInfo(String deviceId);
  70 +
  71 + /**
  72 + * 统计同一个zlm下的国标收流个数
  73 + */
  74 + int getStreamInfoCount(String mediaServerId);
  75 +
  76 +
  77 +
68 78 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
... ... @@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
7 7 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
8 8 import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
9 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
10   -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  10 +import com.genersoft.iot.vmp.service.bean.ErrorCallback;
11 11 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
12 12 import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult;
13 13 import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.AudioBroadcastEvent;
... ... @@ -25,8 +25,8 @@ import java.util.Map;
25 25 public interface IPlayService {
26 26  
27 27 void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
28   - InviteErrorCallback<Object> callback);
29   - SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback);
  28 + ErrorCallback<Object> callback);
  29 + SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, ErrorCallback<Object> callback);
30 30  
31 31 StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId);
32 32  
... ... @@ -37,13 +37,13 @@ public interface IPlayService {
37 37 */
38 38 MediaServerItem getNewMediaServerItemHasAssist(Device device);
39 39  
40   - void playBack(String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
41   - void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, InviteErrorCallback<Object> callback);
  40 + void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
  41 + void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
42 42  
43 43 void zlmServerOffline(String mediaServerId);
44 44  
45   - void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
46   - void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback);
  45 + void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
  46 + void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback);
47 47  
48 48 StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
49 49  
... ... @@ -69,4 +69,6 @@ public interface IPlayService {
69 69 void talkCmd(Device device, String channelId, MediaServerItem mediaServerItem, String stream, AudioBroadcastEvent event);
70 70  
71 71 void stopTalk(Device device, String channelId, Boolean streamIsReady);
  72 +
  73 + void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback);
72 74 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IRecordInfoServer.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.service;
2   -
3   -import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
4   -import com.github.pagehelper.PageInfo;
5   -
6   -public interface IRecordInfoServer {
7   - PageInfo<RecordInfo> getRecordList(int page, int count);
8   -}
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java
1 1 package com.genersoft.iot.vmp.service;
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.GeneralCallback;
4 5 import com.genersoft.iot.vmp.common.StreamInfo;
5 6 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 7 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
7   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  8 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
8 9 import com.github.pagehelper.PageInfo;
9 10  
10 11 public interface IStreamProxyService {
... ... @@ -13,7 +14,7 @@ public interface IStreamProxyService {
13 14 * 保存视频代理
14 15 * @param param
15 16 */
16   - StreamInfo save(StreamProxyItem param);
  17 + void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback);
17 18  
18 19 /**
19 20 * 添加视频代理到zlm
... ... @@ -108,6 +109,6 @@ public interface IStreamProxyService {
108 109 * 获取统计信息
109 110 * @return
110 111 */
111   - ResourceBaceInfo getOverview();
  112 + ResourceBaseInfo getOverview();
112 113  
113 114 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
... ... @@ -5,7 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
5 5 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 6 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
7 7 import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
8   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  8 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
9 9 import com.github.pagehelper.PageInfo;
10 10  
11 11 import java.util.List;
... ... @@ -113,5 +113,5 @@ public interface IStreamPushService {
113 113 * 获取统计信息
114 114 * @return
115 115 */
116   - ResourceBaceInfo getOverview();
  116 + ResourceBaseInfo getOverview();
117 117 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCallback.java renamed to src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java
1 1 package com.genersoft.iot.vmp.service.bean;
2 2  
3   -public interface InviteErrorCallback<T> {
  3 +public interface ErrorCallback<T> {
4 4  
5 5 void run(int code, String msg, T data);
6 6 }
... ...
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java
... ... @@ -5,6 +5,7 @@ package com.genersoft.iot.vmp.service.bean;
5 5 */
6 6 public enum InviteErrorCode {
7 7 SUCCESS(0, "成功"),
  8 + FAIL(-100, "失败"),
8 9 ERROR_FOR_SIGNALLING_TIMEOUT(-1, "信令超时"),
9 10 ERROR_FOR_STREAM_TIMEOUT(-2, "收流超时"),
10 11 ERROR_FOR_RESOURCE_EXHAUSTION(-3, "资源耗尽"),
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java
... ... @@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 11 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
12 12 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
13 13 import com.genersoft.iot.vmp.utils.DateUtil;
14   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  14 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
15 15 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
16 16 import org.slf4j.Logger;
17 17 import org.slf4j.LoggerFactory;
... ... @@ -50,8 +50,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
50 50 device = deviceMapper.getDeviceByDeviceId(deviceChannel.getDeviceId());
51 51 }
52 52  
53   -
54   -
55 53 if ("WGS84".equals(device.getGeoCoordSys())) {
56 54 deviceChannel.setLongitudeWgs84(deviceChannel.getLongitude());
57 55 deviceChannel.setLatitudeWgs84(deviceChannel.getLatitude());
... ... @@ -175,8 +173,12 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
175 173 }
176 174  
177 175 @Override
178   - public ResourceBaceInfo getOverview() {
179   - return channelMapper.getOverview();
  176 + public ResourceBaseInfo getOverview() {
  177 +
  178 + int online = channelMapper.getOnlineCount();
  179 + int total = channelMapper.getAllChannelCount();
  180 +
  181 + return new ResourceBaseInfo(total, online);
180 182 }
181 183  
182 184  
... ... @@ -258,4 +260,6 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
258 260 }
259 261 }
260 262 }
  263 +
  264 +
261 265 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
1 1 package com.genersoft.iot.vmp.service.impl;
2 2  
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
3 4 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 5 import com.genersoft.iot.vmp.conf.DynamicTask;
5 6 import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
6 8 import com.genersoft.iot.vmp.gb28181.bean.*;
7 9 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
8 10 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
... ... @@ -10,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
10 12 import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
11 13 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
12 14 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  15 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
13 16 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
14 17 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
15 18 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
... ... @@ -23,7 +26,7 @@ import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
23 26 import com.genersoft.iot.vmp.storager.dao.PlatformChannelMapper;
24 27 import com.genersoft.iot.vmp.utils.DateUtil;
25 28 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
26   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  29 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
27 30 import org.slf4j.Logger;
28 31 import org.slf4j.LoggerFactory;
29 32 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -49,6 +52,8 @@ public class DeviceServiceImpl implements IDeviceService {
49 52 private final static Logger logger = LoggerFactory.getLogger(DeviceServiceImpl.class);
50 53  
51 54 @Autowired
  55 + private SIPCommander cmder;
  56 + @Autowired
52 57 private DynamicTask dynamicTask;
53 58  
54 59 @Autowired
... ... @@ -124,9 +129,10 @@ public class DeviceServiceImpl implements IDeviceService {
124 129 }
125 130  
126 131 // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
127   - if (device.getCreateTime() == null) {
128   - device.setOnline(1);
  132 + if (deviceInDb == null) {
  133 + device.setOnLine(true);
129 134 device.setCreateTime(now);
  135 + device.setUpdateTime(now);
130 136 logger.info("[设备上线,首次注册]: {},查询设备信息以及通道信息", device.getDeviceId());
131 137 deviceMapper.add(device);
132 138 redisCatchStorage.updateDevice(device);
... ... @@ -137,8 +143,12 @@ public class DeviceServiceImpl implements IDeviceService {
137 143 }
138 144 sync(device);
139 145 }else {
140   - if(device.getOnline() == 0){
141   - device.setOnline(1);
  146 +
  147 + if (deviceInDb != null) {
  148 + device.setSwitchPrimarySubStream(deviceInDb.isSwitchPrimarySubStream());
  149 + }
  150 + if(!device.isOnLine()){
  151 + device.setOnLine(true);
142 152 device.setCreateTime(now);
143 153 deviceMapper.update(device);
144 154 redisCatchStorage.updateDevice(device);
... ... @@ -185,14 +195,14 @@ public class DeviceServiceImpl implements IDeviceService {
185 195  
186 196 @Override
187 197 public void offline(String deviceId, String reason) {
188   - logger.error("[设备离线],{}, device:{}", reason, deviceId);
  198 + logger.warn("[设备离线],{}, device:{}", reason, deviceId);
189 199 Device device = deviceMapper.getDeviceByDeviceId(deviceId);
190 200 if (device == null) {
191 201 return;
192 202 }
193 203 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId;
194 204 dynamicTask.stop(registerExpireTaskKey);
195   - device.setOnline(0);
  205 + device.setOnLine(false);
196 206 redisCatchStorage.updateDevice(device);
197 207 deviceMapper.update(device);
198 208 //进行通道离线
... ... @@ -256,7 +266,7 @@ public class DeviceServiceImpl implements IDeviceService {
256 266 }
257 267 logger.info("[移除目录订阅]: {}", device.getDeviceId());
258 268 String taskKey = device.getDeviceId() + "catalog";
259   - if (device.getOnline() == 1) {
  269 + if (device.isOnLine()) {
260 270 Runnable runnable = dynamicTask.get(taskKey);
261 271 if (runnable instanceof ISubscribeTask) {
262 272 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
... ... @@ -289,7 +299,7 @@ public class DeviceServiceImpl implements IDeviceService {
289 299 }
290 300 logger.info("[移除移动位置订阅]: {}", device.getDeviceId());
291 301 String taskKey = device.getDeviceId() + "mobile_position";
292   - if (device.getOnline() == 1) {
  302 + if (device.isOnLine()) {
293 303 Runnable runnable = dynamicTask.get(taskKey);
294 304 if (runnable instanceof ISubscribeTask) {
295 305 ISubscribeTask subscribeTask = (ISubscribeTask) runnable;
... ... @@ -356,7 +366,7 @@ public class DeviceServiceImpl implements IDeviceService {
356 366  
357 367 @Override
358 368 public void checkDeviceStatus(Device device) {
359   - if (device == null || device.getOnline() == 0) {
  369 + if (device == null || !device.isOnLine()) {
360 370 return;
361 371 }
362 372 try {
... ... @@ -405,63 +415,11 @@ public class DeviceServiceImpl implements IDeviceService {
405 415 if (device == null) {
406 416 return null;
407 417 }
408   - if (parentId == null || parentId.equals(deviceId)) {
409   - // 字根节点开始查询
410   - List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), true, !onlyCatalog);
411   - return transportChannelsToTree(rootNodes, "");
412   - }
413   -
414   - if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
415   - if (parentId.length()%2 != 0) {
416   - return null;
417   - }
418   - // 使用行政区划展示树
419   -// if (parentId.length() > 10) {
420   -// // TODO 可能是行政区划与业务分组混杂的情形
421   -// return null;
422   -// }
423   -
424   - if (parentId.length() == 10 ) {
425   - if (onlyCatalog) {
426   - return null;
427   - }
428   - // parentId为行业编码, 其下不会再有行政区划
429   - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
430   - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channels, parentId);
431   - return trees;
432   - }
433   - // 查询其下的行政区划和摄像机
434   - List<DeviceChannel> channelsForCivilCode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, parentId, parentId.length() + 2);
435   - if (!onlyCatalog) {
436   - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
437   -
438   - for(DeviceChannel channel : channels) {
439   - boolean flag = false;
440   - for(DeviceChannel deviceChannel : channelsForCivilCode) {
441   - if(channel.getChannelId().equals(deviceChannel.getChannelId())) {
442   - flag = true;
443   - }
444   - }
445   - if(!flag) {
446   - channelsForCivilCode.add(channel);
447   - }
448   - }
449   - }
450   - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(channelsForCivilCode, parentId);
451   - return trees;
452   -
453   - }
454   - // 使用业务分组展示树
455   - if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
456   - if (parentId.length() < 14 ) {
457   - return null;
458   - }
459   - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
460   - List<BaseTree<DeviceChannel>> trees = transportChannelsToTree(deviceChannels, parentId);
461   - return trees;
  418 + if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
  419 + parentId = null;
462 420 }
463   -
464   - return null;
  421 + List<DeviceChannel> rootNodes = deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, onlyCatalog);
  422 + return transportChannelsToTree(rootNodes, "");
465 423 }
466 424  
467 425 @Override
... ... @@ -470,42 +428,11 @@ public class DeviceServiceImpl implements IDeviceService {
470 428 if (device == null) {
471 429 return null;
472 430 }
473   - if (parentId == null || parentId.equals(deviceId)) {
474   - // 字根节点开始查询
475   - List<DeviceChannel> rootNodes = getRootNodes(deviceId, TreeType.CIVIL_CODE.equals(device.getTreeType()), false, true);
476   - return rootNodes;
477   - }
478   -
479   - if (TreeType.CIVIL_CODE.equals(device.getTreeType())) {
480   - if (parentId.length()%2 != 0) {
481   - return null;
482   - }
483   - // 使用行政区划展示树
484   - if (parentId.length() > 10) {
485   - // TODO 可能是行政区划与业务分组混杂的情形
486   - return null;
487   - }
488   -
489   - if (parentId.length() == 10 ) {
490   - // parentId为行业编码, 其下不会再有行政区划
491   - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
492   - return channels;
493   - }
494   - // 查询其下的行政区划和摄像机
495   - List<DeviceChannel> channels = deviceChannelMapper.getChannelsByCivilCode(deviceId, parentId);
496   - return channels;
497   -
498   - }
499   - // 使用业务分组展示树
500   - if (TreeType.BUSINESS_GROUP.equals(device.getTreeType())) {
501   - if (parentId.length() < 14 ) {
502   - return null;
503   - }
504   - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, parentId, null, null, null,null);
505   - return deviceChannels;
  431 + if (ObjectUtils.isEmpty(parentId) || parentId.equals(deviceId)) {
  432 + return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, null, false);
  433 + }else {
  434 + return deviceChannelMapper.getSubChannelsByDeviceId(deviceId, parentId, false);
506 435 }
507   -
508   - return null;
509 436 }
510 437  
511 438 private List<BaseTree<DeviceChannel>> transportChannelsToTree(List<DeviceChannel> channels, String parentId) {
... ... @@ -525,65 +452,26 @@ public class DeviceServiceImpl implements IDeviceService {
525 452 node.setPid(parentId);
526 453 node.setBasicData(channel);
527 454 node.setParent(false);
528   - if (channel.getChannelId().length() > 8) {
529   - if (channel.getChannelId().length() > 13) {
530   - String gbCodeType = channel.getChannelId().substring(10, 13);
531   - node.setParent(gbCodeType.equals(ChannelIdType.BUSINESS_GROUP) || gbCodeType.equals(ChannelIdType.VIRTUAL_ORGANIZATION) );
532   - }
533   - }else {
  455 + if (channel.getChannelId().length() <= 8) {
534 456 node.setParent(true);
535   - }
536   - treeNotes.add(node);
537   - }
538   - Collections.sort(treeNotes);
539   - return treeNotes;
540   - }
541   -
542   - private List<DeviceChannel> getRootNodes(String deviceId, boolean isCivilCode, boolean haveCatalog, boolean haveChannel) {
543   - if (!haveCatalog && !haveChannel) {
544   - return null;
545   - }
546   - List<DeviceChannel> result = new ArrayList<>();
547   - if (isCivilCode) {
548   - // 使用行政区划
549   - Integer length= deviceChannelMapper.getChannelMinLength(deviceId);
550   - if (length == null) {
551   - return null;
552   - }
553   - if (length <= 10) {
554   - if (haveCatalog) {
555   - List<DeviceChannel> provinceNode = deviceChannelMapper.getChannelsWithCivilCodeAndLength(deviceId, null, length);
556   - if (provinceNode != null && provinceNode.size() > 0) {
557   - result.addAll(provinceNode);
558   - }
559   - }
560   -
561   - if (haveChannel) {
562   - // 查询那些civilCode不在通道中的不规范通道,放置在根目录
563   - List<DeviceChannel> nonstandardNode = deviceChannelMapper.getChannelWithoutCiviCode(deviceId);
564   - if (nonstandardNode != null && nonstandardNode.size() > 0) {
565   - result.addAll(nonstandardNode);
566   - }
567   - }
568 457 }else {
569   - if (haveChannel) {
570   - List<DeviceChannel> deviceChannels = deviceChannelMapper.queryChannels(deviceId, null, null, null, null,null);
571   - if (deviceChannels != null && deviceChannels.size() > 0) {
572   - result.addAll(deviceChannels);
  458 + if (channel.getChannelId().length() != 20) {
  459 + node.setParent(channel.getParental() == 1);
  460 + }else {
  461 + try {
  462 + int type = Integer.parseInt(channel.getChannelId().substring(10, 13));
  463 + if (type == 215 || type == 216 || type == 200) {
  464 + node.setParent(true);
  465 + }
  466 + }catch (NumberFormatException e) {
  467 + node.setParent(false);
573 468 }
574 469 }
575 470 }
576   -
577   - }else {
578   - // 使用业务分组+虚拟组织
579   -
580   - // 只获取业务分组
581   - List<DeviceChannel> deviceChannels = deviceChannelMapper.getBusinessGroups(deviceId, ChannelIdType.BUSINESS_GROUP);
582   - if (deviceChannels != null && deviceChannels.size() > 0) {
583   - result.addAll(deviceChannels);
584   - }
  471 + treeNotes.add(node);
585 472 }
586   - return result;
  473 + Collections.sort(treeNotes);
  474 + return treeNotes;
587 475 }
588 476  
589 477 @Override
... ... @@ -593,7 +481,7 @@ public class DeviceServiceImpl implements IDeviceService {
593 481  
594 482 @Override
595 483 public void addDevice(Device device) {
596   - device.setOnline(0);
  484 + device.setOnLine(false);
597 485 device.setCreateTime(DateUtil.getNow());
598 486 device.setUpdateTime(DateUtil.getNow());
599 487 deviceMapper.addCustomDevice(device);
... ... @@ -606,6 +494,22 @@ public class DeviceServiceImpl implements IDeviceService {
606 494 logger.warn("更新设备时未找到设备信息");
607 495 return;
608 496 }
  497 + if(deviceInStore.isSwitchPrimarySubStream() != device.isSwitchPrimarySubStream()){
  498 + //当修改设备的主子码流开关时,需要校验是否存在流,如果存在流则直接关闭
  499 + List<SsrcTransaction> ssrcTransactionForAll = streamSession.getSsrcTransactionForAll(device.getDeviceId(), null, null, null);
  500 + if(ssrcTransactionForAll != null){
  501 + for (SsrcTransaction ssrcTransaction: ssrcTransactionForAll) {
  502 + try {
  503 + cmder.streamByeCmd(device, ssrcTransaction.getChannelId(), ssrcTransaction.getStream(), null, null);
  504 + } catch (InvalidArgumentException | SsrcTransactionNotFoundException | ParseException | SipException e) {
  505 + throw new RuntimeException(e);
  506 + }
  507 + }
  508 + }
  509 + deviceChannelMapper.clearPlay(device.getDeviceId());
  510 + inviteStreamService.clearInviteInfo(device.getDeviceId());
  511 + }
  512 +
609 513 if (!ObjectUtils.isEmpty(device.getName())) {
610 514 deviceInStore.setName(device.getName());
611 515 }
... ... @@ -617,7 +521,6 @@ public class DeviceServiceImpl implements IDeviceService {
617 521 }
618 522 deviceInStore.setSdpIp(device.getSdpIp());
619 523 deviceInStore.setCharset(device.getCharset());
620   - deviceInStore.setTreeType(device.getTreeType());
621 524  
622 525 // 目录订阅相关的信息
623 526 if (device.getSubscribeCycleForCatalog() > 0) {
... ... @@ -673,12 +576,17 @@ public class DeviceServiceImpl implements IDeviceService {
673 576 }catch (Exception e) {
674 577 dataSourceTransactionManager.rollback(transactionStatus);
675 578 }
  579 + if (result) {
  580 + redisCatchStorage.removeDevice(deviceId);
  581 + }
676 582 return result;
677 583 }
678 584  
679 585 @Override
680   - public ResourceBaceInfo getOverview() {
681   - return deviceMapper.getOverview();
  586 + public ResourceBaseInfo getOverview() {
  587 + List<Device> onlineDevices = deviceMapper.getOnlineDevices();
  588 + List<Device> all = deviceMapper.getAll();
  589 + return new ResourceBaseInfo(all.size(), onlineDevices.size());
682 590 }
683 591  
684 592 @Override
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
... ... @@ -110,23 +110,18 @@ public class GbStreamServiceImpl implements IGbStreamService {
110 110 deviceChannel.setLatitude(gbStream.getLatitude());
111 111 deviceChannel.setDeviceId(platform.getDeviceGBId());
112 112 deviceChannel.setManufacture("wvp-pro");
113   - deviceChannel.setStatus(gbStream.isStatus()?1:0);
  113 + deviceChannel.setStatus(gbStream.isStatus());
114 114  
115 115 deviceChannel.setRegisterWay(1);
116   - deviceChannel.setCivilCode(platform.getAdministrativeDivision());
117   -
118   - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
119   - deviceChannel.setCivilCode(catalogId);
120   - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
121   - PlatformCatalog catalog = catalogMapper.select(catalogId);
122   - if (catalog == null) {
123   - deviceChannel.setParentId(platform.getDeviceGBId());
124   - deviceChannel.setBusinessGroupId(null);
125   - }else {
126   - deviceChannel.setParentId(catalog.getId());
127   - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
128   - }
129 116  
  117 + PlatformCatalog catalog = catalogMapper.select(catalogId);
  118 + if (catalog != null) {
  119 + deviceChannel.setCivilCode(catalog.getCivilCode());
  120 + deviceChannel.setParentId(catalog.getParentId());
  121 + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
  122 + }else {
  123 + deviceChannel.setCivilCode(platform.getAdministrativeDivision());
  124 + deviceChannel.setParentId(platform.getDeviceGBId());
130 125 }
131 126  
132 127 deviceChannel.setModel("live");
... ... @@ -218,23 +213,17 @@ public class GbStreamServiceImpl implements IGbStreamService {
218 213 }else {
219 214 status = gbStreamMapper.selectStatusForPush(gbStream.getApp(), gbStream.getStream());
220 215 }
221   - deviceChannel.setStatus((status != null && status )?1:0);
  216 + deviceChannel.setStatus(status != null && status);
222 217  
223 218 deviceChannel.setRegisterWay(1);
224   - deviceChannel.setCivilCode(platform.getAdministrativeDivision());
225   -
226   - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
227   - deviceChannel.setCivilCode(catalogId);
228   - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
229   - PlatformCatalog catalog = catalogMapper.select(catalogId);
230   - if (catalog == null) {
231   - deviceChannel.setParentId(platform.getDeviceGBId());
232   - deviceChannel.setBusinessGroupId(null);
233   - }else {
234   - deviceChannel.setParentId(catalog.getId());
235   - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
236   - }
237   -
  219 + PlatformCatalog catalog = catalogMapper.select(catalogId);
  220 + if (catalog != null) {
  221 + deviceChannel.setCivilCode(catalog.getCivilCode());
  222 + deviceChannel.setParentId(catalog.getParentId());
  223 + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
  224 + }else {
  225 + deviceChannel.setCivilCode(platform.getAdministrativeDivision());
  226 + deviceChannel.setParentId(platform.getDeviceGBId());
238 227 }
239 228  
240 229 deviceChannel.setModel("live");
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
... ... @@ -6,7 +6,7 @@ import com.genersoft.iot.vmp.common.InviteSessionStatus;
6 6 import com.genersoft.iot.vmp.common.InviteSessionType;
7 7 import com.genersoft.iot.vmp.common.VideoManagerConstants;
8 8 import com.genersoft.iot.vmp.service.IInviteStreamService;
9   -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  9 +import com.genersoft.iot.vmp.service.bean.ErrorCallback;
10 10 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
11 11 import org.slf4j.Logger;
12 12 import org.slf4j.LoggerFactory;
... ... @@ -24,7 +24,7 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
24 24  
25 25 private final Logger logger = LoggerFactory.getLogger(InviteStreamServiceImpl.class);
26 26  
27   - private final Map<String, List<InviteErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
  27 + private final Map<String, List<ErrorCallback<Object>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();
28 28  
29 29 @Autowired
30 30 private RedisTemplate<Object, Object> redisTemplate;
... ... @@ -85,6 +85,24 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
85 85 }
86 86  
87 87 @Override
  88 + public InviteInfo updateInviteInfoForStream(InviteInfo inviteInfo, String stream) {
  89 +
  90 + InviteInfo inviteInfoInDb = getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  91 + if (inviteInfoInDb == null) {
  92 + return null;
  93 + }
  94 + removeInviteInfo(inviteInfoInDb);
  95 + String key = VideoManagerConstants.INVITE_PREFIX +
  96 + "_" + inviteInfo.getType() +
  97 + "_" + inviteInfo.getDeviceId() +
  98 + "_" + inviteInfo.getChannelId() +
  99 + "_" + stream;
  100 + inviteInfoInDb.setStream(stream);
  101 + redisTemplate.opsForValue().set(key, inviteInfoInDb);
  102 + return inviteInfoInDb;
  103 + }
  104 +
  105 + @Override
88 106 public InviteInfo getInviteInfo(InviteSessionType type, String deviceId, String channelId, String stream) {
89 107 String key = VideoManagerConstants.INVITE_PREFIX +
90 108 "_" + (type != null ? type : "*") +
... ... @@ -141,9 +159,9 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
141 159 }
142 160  
143 161 @Override
144   - public void once(InviteSessionType type, String deviceId, String channelId, String stream, InviteErrorCallback<Object> callback) {
  162 + public void once(InviteSessionType type, String deviceId, String channelId, String stream, ErrorCallback<Object> callback) {
145 163 String key = buildKey(type, deviceId, channelId, stream);
146   - List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  164 + List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
147 165 if (callbacks == null) {
148 166 callbacks = new CopyOnWriteArrayList<>();
149 167 inviteErrorCallbackMap.put(key, callbacks);
... ... @@ -152,31 +170,60 @@ public class InviteStreamServiceImpl implements IInviteStreamService {
152 170  
153 171 }
154 172  
  173 + private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
  174 + String key = type + "_" + deviceId + "_" + channelId;
  175 + // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
  176 + if (stream != null) {
  177 + key += ("_" + stream);
  178 + }
  179 + return key;
  180 + }
  181 +
  182 +
  183 + @Override
  184 + public void clearInviteInfo(String deviceId) {
  185 + removeInviteInfo(null, deviceId, null, null);
  186 + }
  187 +
  188 + @Override
  189 + public int getStreamInfoCount(String mediaServerId) {
  190 + int count = 0;
  191 + String key = VideoManagerConstants.INVITE_PREFIX + "_*_*_*_*";
  192 + List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
  193 + if (scanResult.size() == 0) {
  194 + return 0;
  195 + }else {
  196 + for (Object keyObj : scanResult) {
  197 + String keyStr = (String) keyObj;
  198 + InviteInfo inviteInfo = (InviteInfo) redisTemplate.opsForValue().get(keyStr);
  199 + if (inviteInfo != null && inviteInfo.getStreamInfo() != null && inviteInfo.getStreamInfo().getMediaServerId().equals(mediaServerId)) {
  200 + count++;
  201 + }
  202 + }
  203 + }
  204 + return count;
  205 + }
  206 +
155 207 @Override
156 208 public void call(InviteSessionType type, String deviceId, String channelId, String stream, int code, String msg, Object data) {
157   - String key = buildKey(type, deviceId, channelId, stream);
158   - List<InviteErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
  209 + String key = buildSubStreamKey(type, deviceId, channelId, stream);
  210 + List<ErrorCallback<Object>> callbacks = inviteErrorCallbackMap.get(key);
159 211 if (callbacks == null) {
160 212 return;
161 213 }
162   - for (InviteErrorCallback<Object> callback : callbacks) {
  214 + for (ErrorCallback<Object> callback : callbacks) {
163 215 callback.run(code, msg, data);
164 216 }
165 217 inviteErrorCallbackMap.remove(key);
166 218 }
167 219  
168   - private String buildKey(InviteSessionType type, String deviceId, String channelId, String stream) {
169   - String key = type + "_" + deviceId + "_" + channelId;
170   - // 如果ssrc未null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
  220 +
  221 + private String buildSubStreamKey(InviteSessionType type, String deviceId, String channelId, String stream) {
  222 + String key = type + "_" + "_" + deviceId + "_" + channelId;
  223 + // 如果ssrc为null那么可以实现一个通道只能一次操作,ssrc不为null则可以支持一个通道多次invite
171 224 if (stream != null) {
172 225 key += ("_" + stream);
173 226 }
174 227 return key;
175 228 }
176   -
177   -
178   - @Override
179   - public void clearInviteInfo(String deviceId) {
180   - removeInviteInfo(null, deviceId, null, null);
181   - }
182 229 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
... ... @@ -17,6 +17,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
17 17 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
18 18 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
19 19 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
  20 +import com.genersoft.iot.vmp.service.IInviteStreamService;
20 21 import com.genersoft.iot.vmp.service.IMediaServerService;
21 22 import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
22 23 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ... @@ -98,6 +99,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
98 99 private IRedisCatchStorage redisCatchStorage;
99 100  
100 101 @Autowired
  102 + private IInviteStreamService inviteStreamService;
  103 +
  104 + @Autowired
101 105 private RedisTemplate<Object, Object> redisTemplate;
102 106  
103 107  
... ... @@ -423,7 +427,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
423 427 }
424 428 final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
425 429 dynamicTask.stop(zlmKeepaliveKey);
426   - dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000);
  430 + dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (serverItem.getHookAliveInterval().intValue() + 5) * 1000);
427 431 publisher.zlmOnlineEventPublish(serverItem.getId());
428 432  
429 433 logger.info("[ZLM] 连接成功 {} - {}:{} ",
... ... @@ -694,7 +698,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
694 698 // 缓存不存在,从数据库查询,如果数据库不存在则是错误的
695 699 mediaServerItem = getOneFromDatabase(mediaServerId);
696 700 if (mediaServerItem == null) {
697   - logger.warn("[更新ZLM 保活信息]失败,未找到流媒体信息");
  701 + logger.warn("[更新ZLM 保活信息] 流媒体{}尚未加入使用,请检查节点中是否含有此流媒体 ", mediaServerId);
698 702 return;
699 703 }
700 704 // zlm连接重试
... ... @@ -744,7 +748,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
744 748 result.setId(mediaServerItem.getId());
745 749 result.setPush(redisCatchStorage.getPushStreamCount(mediaServerItem.getId()));
746 750 result.setProxy(redisCatchStorage.getProxyStreamCount(mediaServerItem.getId()));
747   - result.setGbReceive(redisCatchStorage.getGbReceiveCount(mediaServerItem.getId()));
  751 +
  752 + result.setGbReceive(inviteStreamService.getStreamInfoCount(mediaServerItem.getId()));
748 753 result.setGbSend(redisCatchStorage.getGbSendCount(mediaServerItem.getId()));
749 754 return result;
750 755 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
... ... @@ -126,22 +126,17 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
126 126 List<DeviceChannel> deviceChannelList = new ArrayList<>();
127 127 if (channelReduces.size() > 0){
128 128 PlatformCatalog catalog = catalogManager.select(catalogId);
129   - if (catalog == null && !catalogId.equals(platform.getDeviceGBId())) {
  129 + if (catalog == null || !catalogId.equals(platform.getDeviceGBId())) {
130 130 logger.warn("未查询到目录{}的信息", catalogId);
131 131 return null;
132 132 }
133 133 for (ChannelReduce channelReduce : channelReduces) {
134 134 DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
135 135 deviceChannel.setParental(0);
  136 + deviceChannel.setCivilCode(catalog.getCivilCode());
  137 + deviceChannel.setParentId(catalog.getParentId());
  138 + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
136 139 deviceChannelList.add(deviceChannel);
137   - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)){
138   - deviceChannel.setCivilCode(catalogId);
139   - }else if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)){
140   - deviceChannel.setParentId(catalogId);
141   - if (catalog != null) {
142   - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
143   - }
144   - }
145 140 }
146 141 }
147 142 return deviceChannelList;
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
... ... @@ -49,6 +49,8 @@ import java.util.UUID;
49 49 public class PlatformServiceImpl implements IPlatformService {
50 50  
51 51 private final static String REGISTER_KEY_PREFIX = "platform_register_";
  52 +
  53 + private final static String REGISTER_FAIL_AGAIN_KEY_PREFIX = "platform_register_fail_again_";
52 54 private final static String KEEPALIVE_KEY_PREFIX = "platform_keepalive_";
53 55  
54 56 private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
... ... @@ -158,14 +160,6 @@ public class PlatformServiceImpl implements IPlatformService {
158 160 ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId());
159 161 ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId());
160 162 parentPlatform.setUpdateTime(DateUtil.getNow());
161   - if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
162   - // 目录结构发生变化,清空之前的关联关系
163   - logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());
164   - catalogMapper.delByPlatformId(parentPlatformOld.getServerGBId());
165   - platformChannelMapper.delByPlatformId(parentPlatformOld.getServerGBId());
166   - platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId());
167   - }
168   -
169 163  
170 164 // 停止心跳定时
171 165 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId();
... ... @@ -176,12 +170,11 @@ public class PlatformServiceImpl implements IPlatformService {
176 170 // 注销旧的
177 171 try {
178 172 if (parentPlatformOld.isStatus()) {
179   - logger.info("保存平台{}时发现平台在线,发送注销命令", parentPlatformOld.getServerGBId());
  173 + logger.info("保存平台{}时发现平台在线,发送注销命令", parentPlatformOld.getServerGBId());
180 174 commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> {
181 175 logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId());
182 176 });
183 177 }
184   -
185 178 } catch (InvalidArgumentException | ParseException | SipException e) {
186 179 logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
187 180 }
... ... @@ -214,9 +207,6 @@ public class PlatformServiceImpl implements IPlatformService {
214 207 logger.error("[命令发送失败] 国标级联: {}", e.getMessage());
215 208 }
216 209 }
217   - // 重新开启定时注册, 使用续订消息
218   - // 重新开始心跳保活
219   -
220 210  
221 211 return false;
222 212 }
... ... @@ -225,6 +215,9 @@ public class PlatformServiceImpl implements IPlatformService {
225 215 @Override
226 216 public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) {
227 217 logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId());
  218 + final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId();
  219 + dynamicTask.stop(registerFailAgainTaskKey);
  220 +
228 221 platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true);
229 222 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
230 223 if (parentPlatformCatch == null) {
... ... @@ -265,15 +258,9 @@ public class PlatformServiceImpl implements IPlatformService {
265 258 // 此时是第三次心跳超时, 平台离线
266 259 if (platformCatch.getKeepAliveReply() == 2) {
267 260 // 设置平台离线,并重新注册
268   - logger.info("[国标级联] {},三次心跳超时后再次发起注册", parentPlatform.getServerGBId());
269   - try {
270   - commanderForPlatform.register(parentPlatform, eventResult1 -> {
271   - logger.info("[国标级联] {},三次心跳超时后再次发起注册仍然失败,开始定时发起注册,间隔为1分钟", parentPlatform.getServerGBId());
272   - offline(parentPlatform, false);
273   - }, null);
274   - } catch (InvalidArgumentException | ParseException | SipException e) {
275   - logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage());
276   - }
  261 + logger.info("[国标级联] 三次心跳超时, 平台{}({})离线", parentPlatform.getName(), parentPlatform.getServerGBId());
  262 + offline(parentPlatform, false);
  263 +
277 264 }
278 265  
279 266 }else {
... ... @@ -299,21 +286,22 @@ public class PlatformServiceImpl implements IPlatformService {
299 286  
300 287 private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){
301 288 try {
302   - // 设置超时重发, 后续从底层支持消息重发
303   - String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout";
304   - if (dynamicTask.isAlive(key)) {
305   - return;
  289 + // 不在同一个会话中续订则每次全新注册
  290 + if (!userSetting.isRegisterKeepIntDialog()) {
  291 + sipTransactionInfo = null;
  292 + }
  293 +
  294 + if (sipTransactionInfo == null) {
  295 + logger.info("[国标级联] 平台:{}注册即将到期,开始重新注册", parentPlatform.getServerGBId());
  296 + }else {
  297 + logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
306 298 }
307   - dynamicTask.startDelay(key, ()->{
308   - registerTask(parentPlatform, sipTransactionInfo);
309   - }, 1000);
310   - logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
  299 +
311 300 commanderForPlatform.register(parentPlatform, sipTransactionInfo, eventResult -> {
312   - dynamicTask.stop(key);
  301 + logger.info("[国标级联] 平台:{}注册失败,{}:{}", parentPlatform.getServerGBId(),
  302 + eventResult.statusCode, eventResult.msg);
313 303 offline(parentPlatform, false);
314   - },eventResult -> {
315   - dynamicTask.stop(key);
316   - });
  304 + }, null);
317 305 } catch (InvalidArgumentException | ParseException | SipException e) {
318 306 logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage());
319 307 }
... ... @@ -334,24 +322,35 @@ public class PlatformServiceImpl implements IPlatformService {
334 322 // 停止所有推流
335 323 logger.info("[平台离线] {}, 停止所有推流", parentPlatform.getServerGBId());
336 324 stopAllPush(parentPlatform.getServerGBId());
337   - if (stopRegister) {
338   - // 清除注册定时
339   - logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId());
340   - final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
341   - if (dynamicTask.contains(registerTaskKey)) {
342   - dynamicTask.stop(registerTaskKey);
343   - }
  325 +
  326 + // 清除注册定时
  327 + logger.info("[平台离线] {}, 停止定时注册任务", parentPlatform.getServerGBId());
  328 + final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
  329 + if (dynamicTask.contains(registerTaskKey)) {
  330 + dynamicTask.stop(registerTaskKey);
344 331 }
345 332 // 清除心跳定时
346 333 logger.info("[平台离线] {}, 停止定时发送心跳任务", parentPlatform.getServerGBId());
347 334 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
348 335 if (dynamicTask.contains(keepaliveTaskKey)) {
349   - // 添加心跳任务
  336 + // 清除心跳任务
350 337 dynamicTask.stop(keepaliveTaskKey);
351 338 }
352 339 // 停止目录订阅回复
353 340 logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId());
354 341 subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());
  342 + // 发起定时自动重新注册
  343 + if (!stopRegister) {
  344 + // 设置为60秒自动尝试重新注册
  345 + final String registerFailAgainTaskKey = REGISTER_FAIL_AGAIN_KEY_PREFIX + parentPlatform.getServerGBId();
  346 + ParentPlatform platform = platformMapper.getParentPlatById(parentPlatform.getId());
  347 + if (platform.isEnable()) {
  348 + dynamicTask.startCron(registerFailAgainTaskKey,
  349 + ()-> registerTask(platform, null),
  350 + userSetting.getRegisterAgainAfterTime() * 1000);
  351 + }
  352 +
  353 + }
355 354 }
356 355  
357 356 private void stopAllPush(String platformId) {
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
1 1 package com.genersoft.iot.vmp.service.impl;
2 2  
3   -import com.alibaba.fastjson2.JSONArray;
4 3 import com.alibaba.fastjson2.JSONObject;
5 4 import com.genersoft.iot.vmp.common.InviteInfo;
6 5 import com.genersoft.iot.vmp.common.InviteSessionStatus;
... ... @@ -29,8 +28,10 @@ import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
29 28 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
30 29 import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
31 30 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  31 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
  32 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
32 33 import com.genersoft.iot.vmp.service.*;
33   -import com.genersoft.iot.vmp.service.bean.InviteErrorCallback;
  34 +import com.genersoft.iot.vmp.service.bean.ErrorCallback;
34 35 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
35 36 import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg;
36 37 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
... ... @@ -57,6 +58,7 @@ import javax.sip.InvalidArgumentException;
57 58 import javax.sip.ResponseEvent;
58 59 import javax.sip.SipException;
59 60 import javax.sip.header.CallIdHeader;
  61 +import java.io.File;
60 62 import java.math.BigDecimal;
61 63 import java.math.RoundingMode;
62 64 import java.text.ParseException;
... ... @@ -144,14 +146,13 @@ public class PlayServiceImpl implements IPlayService {
144 146  
145 147  
146 148 @Override
147   - public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, InviteErrorCallback<Object> callback) {
  149 + public SSRCInfo play(MediaServerItem mediaServerItem, String deviceId, String channelId, ErrorCallback<Object> callback) {
148 150 if (mediaServerItem == null) {
149 151 throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm");
150 152 }
151 153  
152 154 Device device = redisCatchStorage.getDevice(deviceId);
153 155 InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
154   -
155 156 if (inviteInfo != null ) {
156 157 if (inviteInfo.getStreamInfo() == null) {
157 158 // 点播发起了但是尚未成功, 仅注册回调等待结果即可
... ... @@ -353,7 +354,7 @@ public class PlayServiceImpl implements IPlayService {
353 354  
354 355 @Override
355 356 public void play(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
356   - InviteErrorCallback<Object> callback) {
  357 + ErrorCallback<Object> callback) {
357 358  
358 359 if (mediaServerItem == null || ssrcInfo == null) {
359 360 callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
... ... @@ -361,8 +362,9 @@ public class PlayServiceImpl implements IPlayService {
361 362 null);
362 363 return;
363 364 }
364   - logger.info("[点播开始] deviceId: {}, channelId: {},收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
365   -
  365 + logger.info("[点播开始] deviceId: {}, channelId: {},码流类型:{},收流端口: {}, 收流模式:{}, SSRC: {}, SSRC校验:{}",
  366 + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", ssrcInfo.getPort(),
  367 + device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
366 368 //端口获取失败的ssrcInfo 没有必要发送点播指令
367 369 if (ssrcInfo.getPort() <= 0) {
368 370 logger.info("[点播端口分配异常],deviceId={},channelId={},ssrcInfo={}", device.getDeviceId(), channelId, ssrcInfo);
... ... @@ -377,9 +379,10 @@ public class PlayServiceImpl implements IPlayService {
377 379 }
378 380  
379 381 // 初始化redis中的invite消息状态
380   - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  382 + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
381 383 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY,
382 384 InviteSessionStatus.ready);
  385 + inviteInfo.setSubStream(device.isSwitchPrimarySubStream());
383 386 inviteStreamService.updateInviteInfo(inviteInfo);
384 387 // 超时处理
385 388 String timeOutTaskKey = UUID.randomUUID().toString();
... ... @@ -387,7 +390,10 @@ public class PlayServiceImpl implements IPlayService {
387 390 // 执行超时任务时查询是否已经成功,成功了则不执行超时任务,防止超时任务取消失败的情况
388 391 InviteInfo inviteInfoForTimeOut = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
389 392 if (inviteInfoForTimeOut == null || inviteInfoForTimeOut.getStreamInfo() == null) {
390   - logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", device.getDeviceId(), channelId, ssrcInfo.getPort(), ssrcInfo.getSsrc());
  393 + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}",
  394 + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流",
  395 + ssrcInfo.getPort(), ssrcInfo.getSsrc());
  396 +
391 397 // 点播超时回复BYE 同时释放ssrc以及此次点播的资源
392 398 // InviteInfo inviteInfoForTimeout = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.play, device.getDeviceId(), channelId);
393 399 // if (inviteInfoForTimeout == null) {
... ... @@ -401,8 +407,8 @@ public class PlayServiceImpl implements IPlayService {
401 407 callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
402 408 inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
403 409 InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), null);
404   -
405 410 inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, device.getDeviceId(), channelId);
  411 +
406 412 try {
407 413 cmder.streamByeCmd(device, channelId, ssrcInfo.getStream(), null);
408 414 } catch (InvalidArgumentException | ParseException | SipException |
... ... @@ -421,11 +427,11 @@ public class PlayServiceImpl implements IPlayService {
421 427 }, userSetting.getPlayTimeout());
422 428  
423 429 try {
424   - cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (MediaServerItem mediaServerItemInuse, JSONObject response) -> {
425   - logger.info("收到订阅消息: " + response.toJSONString());
  430 + cmder.playStreamCmd(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInuse, hookParam ) -> {
  431 + logger.info("收到订阅消息: " + hookParam);
426 432 dynamicTask.stop(timeOutTaskKey);
427 433 // hook响应
428   - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
  434 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInuse, hookParam, device.getDeviceId(), channelId);
429 435 if (streamInfo == null){
430 436 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
431 437 InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
... ... @@ -439,7 +445,8 @@ public class PlayServiceImpl implements IPlayService {
439 445 InviteErrorCode.SUCCESS.getCode(),
440 446 InviteErrorCode.SUCCESS.getMsg(),
441 447 streamInfo);
442   - logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
  448 + logger.info("[点播成功] deviceId: {}, channelId: {},码流类型:{}", device.getDeviceId(),
  449 + device.isSwitchPrimarySubStream() ? "辅码流" : "主码流");
443 450 String streamUrl;
444 451 if (mediaServerItemInuse.getRtspPort() != 0) {
445 452 streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", ssrcInfo.getStream());
... ... @@ -505,21 +512,8 @@ public class PlayServiceImpl implements IPlayService {
505 512 logger.info("[点播消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
506 513 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
507 514 logger.info("[点播消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
508   - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
509   - // ssrc 不可用
510   - logger.info("[点播消息] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
511   - // 释放ssrc
512   - ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
513   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
514   -
515   - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
516   - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
517   - inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
518   - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
519   - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
520   -
521   - return;
522   - }
  515 + // 释放ssrc
  516 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
523 517 // 单端口模式streamId也有变化,重新设置监听即可
524 518 if (!mediaServerItem.isRtpEnable()) {
525 519 // 添加订阅
... ... @@ -527,12 +521,12 @@ public class PlayServiceImpl implements IPlayService {
527 521 subscribe.removeSubscribe(hookSubscribe);
528 522 String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
529 523 hookSubscribe.getContent().put("stream", stream);
530   - inviteInfo.setStream(stream);
531   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
532   - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  524 + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
  525 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  526 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
533 527 dynamicTask.stop(timeOutTaskKey);
534 528 // hook响应
535   - StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId);
  529 + StreamInfo streamInfo = onPublishHandlerForPlay(mediaServerItemInUse, hookParam, device.getDeviceId(), channelId);
536 530 if (streamInfo == null){
537 531 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
538 532 InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getMsg(), null);
... ... @@ -542,7 +536,7 @@ public class PlayServiceImpl implements IPlayService {
542 536 return;
543 537 }
544 538 callback.run(InviteErrorCode.SUCCESS.getCode(),
545   - InviteErrorCode.SUCCESS.getMsg(), null);
  539 + InviteErrorCode.SUCCESS.getMsg(), streamInfo);
546 540 inviteStreamService.call(InviteSessionType.PLAY, device.getDeviceId(), channelId, null,
547 541 InviteErrorCode.SUCCESS.getCode(),
548 542 InviteErrorCode.SUCCESS.getMsg(),
... ... @@ -574,6 +568,9 @@ public class PlayServiceImpl implements IPlayService {
574 568 "下级自定义了ssrc,重新设置收流信息失败", null);
575 569  
576 570 }else {
  571 + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
  572 + inviteStreamService.removeInviteInfo(inviteInfo);
  573 + }
577 574 ssrcInfo.setSsrc(ssrcInResponse);
578 575 inviteInfo.setSsrcInfo(ssrcInfo);
579 576 inviteInfo.setStream(ssrcInfo.getStream());
... ... @@ -622,6 +619,8 @@ public class PlayServiceImpl implements IPlayService {
622 619 @Override
623 620 public StreamInfo onPublishHandlerForPlay(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId) {
624 621 StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
  622 + Device device = redisCatchStorage.getDevice(deviceId);
  623 + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
625 624 if (streamInfo != null) {
626 625 DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
627 626 if (deviceChannel != null) {
... ... @@ -639,9 +638,9 @@ public class PlayServiceImpl implements IPlayService {
639 638  
640 639 }
641 640  
642   - private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
643   -
644   - StreamInfo streamInfo = onPublishHandler(mediaServerItem, response, deviceId, channelId);
  641 + private StreamInfo onPublishHandlerForPlayback(MediaServerItem mediaServerItem, HookParam param, String deviceId, String channelId, String startTime, String endTime) {
  642 + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) param;
  643 + StreamInfo streamInfo = onPublishHandler(mediaServerItem, streamChangedHookParam, deviceId, channelId);
645 644 if (streamInfo != null) {
646 645 streamInfo.setStartTime(startTime);
647 646 streamInfo.setEndTime(endTime);
... ... @@ -698,7 +697,7 @@ public class PlayServiceImpl implements IPlayService {
698 697  
699 698 @Override
700 699 public void playBack(String deviceId, String channelId, String startTime,
701   - String endTime, InviteErrorCallback<Object> callback) {
  700 + String endTime, ErrorCallback<Object> callback) {
702 701 Device device = storager.queryVideoDevice(deviceId);
703 702 if (device == null) {
704 703 return;
... ... @@ -711,7 +710,7 @@ public class PlayServiceImpl implements IPlayService {
711 710 @Override
712 711 public void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,
713 712 String deviceId, String channelId, String startTime,
714   - String endTime, InviteErrorCallback<Object> callback) {
  713 + String endTime, ErrorCallback<Object> callback) {
715 714 if (mediaServerItem == null || ssrcInfo == null) {
716 715 callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
717 716 InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
... ... @@ -727,7 +726,7 @@ public class PlayServiceImpl implements IPlayService {
727 726 device.getDeviceId(), channelId, startTime, endTime, ssrcInfo.getPort(), device.getStreamMode(),
728 727 ssrcInfo.getSsrc(), device.isSsrcCheck());
729 728 // 初始化redis中的invite消息状态
730   - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  729 + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
731 730 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK,
732 731 InviteSessionStatus.ready);
733 732 inviteStreamService.updateInviteInfo(inviteInfo);
... ... @@ -760,10 +759,10 @@ public class PlayServiceImpl implements IPlayService {
760 759 inviteStreamService.removeInviteInfo(inviteInfo);
761 760 };
762 761  
763   - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
764   - logger.info("收到回放订阅消息: " + jsonObject);
  762 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> {
  763 + logger.info("收到回放订阅消息: " + hookParam);
765 764 dynamicTask.stop(playBackTimeOutTaskKey);
766   - StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
  765 + StreamInfo streamInfo = onPublishHandlerForPlayback(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime);
767 766 if (streamInfo == null) {
768 767 logger.warn("设备回放API调用失败!");
769 768 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
... ... @@ -829,17 +828,8 @@ public class PlayServiceImpl implements IPlayService {
829 828 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
830 829 logger.info("[录像回放] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
831 830  
832   - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
833   - // ssrc 不可用
834   - logger.info("[录像回放] SSRC修正时发现ssrc不可使用 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
835   - // 释放ssrc
836   - dynamicTask.stop(playBackTimeOutTaskKey);
837   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
838   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
839   - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
840   - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
841   - return;
842   - }
  831 + // 释放ssrc
  832 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
843 833  
844 834 // 单端口模式streamId也有变化,需要重新设置监听
845 835 if (!mediaServerItem.isRtpEnable()) {
... ... @@ -848,12 +838,12 @@ public class PlayServiceImpl implements IPlayService {
848 838 subscribe.removeSubscribe(hookSubscribe);
849 839 String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
850 840 hookSubscribe.getContent().put("stream", stream);
851   - inviteInfo.setStream(stream);
852   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
853   - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  841 + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
  842 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  843 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
854 844 dynamicTask.stop(playBackTimeOutTaskKey);
855 845 // hook响应
856   - hookEvent.response(mediaServerItemInUse, response);
  846 + hookEvent.response(mediaServerItemInUse, hookParam);
857 847 });
858 848 }
859 849 // 更新ssrc
... ... @@ -877,6 +867,10 @@ public class PlayServiceImpl implements IPlayService {
877 867 "下级自定义了ssrc,重新设置收流信息失败", null);
878 868  
879 869 }else {
  870 + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
  871 + inviteStreamService.removeInviteInfo(inviteInfo);
  872 + }
  873 +
880 874 ssrcInfo.setSsrc(ssrcInResponse);
881 875 inviteInfo.setSsrcInfo(ssrcInfo);
882 876 inviteInfo.setStream(ssrcInfo.getStream());
... ... @@ -900,7 +894,7 @@ public class PlayServiceImpl implements IPlayService {
900 894  
901 895  
902 896 @Override
903   - public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
  897 + public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
904 898 Device device = storager.queryVideoDevice(deviceId);
905 899 if (device == null) {
906 900 return;
... ... @@ -918,7 +912,7 @@ public class PlayServiceImpl implements IPlayService {
918 912  
919 913  
920 914 @Override
921   - public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteErrorCallback<Object> callback) {
  915 + public void download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) {
922 916 if (mediaServerItem == null || ssrcInfo == null) {
923 917 callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(),
924 918 InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(),
... ... @@ -934,7 +928,7 @@ public class PlayServiceImpl implements IPlayService {
934 928 }
935 929 logger.info("[录像下载] deviceId: {}, channelId: {}, 下载速度:{}, 收流端口:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", device.getDeviceId(), channelId, downloadSpeed, ssrcInfo.getPort(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck());
936 930 // 初始化redis中的invite消息状态
937   - InviteInfo inviteInfo = InviteInfo.getinviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
  931 + InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channelId, ssrcInfo.getStream(), ssrcInfo,
938 932 mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD,
939 933 InviteSessionStatus.ready);
940 934 inviteStreamService.updateInviteInfo(inviteInfo);
... ... @@ -964,10 +958,10 @@ public class PlayServiceImpl implements IPlayService {
964 958 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
965 959 inviteStreamService.removeInviteInfo(inviteInfo);
966 960 };
967   - ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, jsonObject) -> {
968   - logger.info("[录像下载]收到订阅消息: " + jsonObject);
  961 + ZlmHttpHookSubscribe.Event hookEvent = (mediaServerItemInuse, hookParam) -> {
  962 + logger.info("[录像下载]收到订阅消息: " + hookParam);
969 963 dynamicTask.stop(downLoadTimeOutTaskKey);
970   - StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, jsonObject, deviceId, channelId, startTime, endTime);
  964 + StreamInfo streamInfo = onPublishHandlerForDownload(mediaServerItemInuse, hookParam, deviceId, channelId, startTime, endTime);
971 965 if (streamInfo == null) {
972 966 logger.warn("[录像下载] 获取流地址信息失败");
973 967 callback.run(InviteErrorCode.ERROR_FOR_STREAM_PARSING_EXCEPTIONS.getCode(),
... ... @@ -1032,26 +1026,21 @@ public class PlayServiceImpl implements IPlayService {
1032 1026 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
1033 1027 logger.info("[录像下载] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
1034 1028  
1035   - if (!ssrcFactory.checkSsrc(mediaServerItem.getId(),ssrcInResponse)) {
1036   - // ssrc 不可用
1037   - // 释放ssrc
1038   - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
1039   - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
1040   - callback.run(InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getCode(),
1041   - InviteErrorCode.ERROR_FOR_SSRC_UNAVAILABLE.getMsg(), null);
1042   - return;
1043   - }
  1029 + // 释放ssrc
  1030 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
1044 1031  
1045 1032 // 单端口模式streamId也有变化,需要重新设置监听
1046 1033 if (!mediaServerItem.isRtpEnable()) {
1047 1034 // 添加订阅
1048 1035 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
1049 1036 subscribe.removeSubscribe(hookSubscribe);
1050   - hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
1051   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
1052   - logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  1037 + String stream = String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase();
  1038 + hookSubscribe.getContent().put("stream", stream);
  1039 + inviteStreamService.updateInviteInfoForStream(inviteInfo, stream);
  1040 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  1041 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + hookParam);
1053 1042 dynamicTask.stop(downLoadTimeOutTaskKey);
1054   - hookEvent.response(mediaServerItemInUse, response);
  1043 + hookEvent.response(mediaServerItemInUse, hookParam);
1055 1044 });
1056 1045 }
1057 1046  
... ... @@ -1075,6 +1064,9 @@ public class PlayServiceImpl implements IPlayService {
1075 1064 "下级自定义了ssrc,重新设置收流信息失败", null);
1076 1065  
1077 1066 }else {
  1067 + if (ssrcInfo.getStream()!= null && !ssrcInfo.getStream().equals(inviteInfo.getStream())) {
  1068 + inviteStreamService.removeInviteInfo(inviteInfo);
  1069 + }
1078 1070 ssrcInfo.setSsrc(ssrcInResponse);
1079 1071 inviteInfo.setSsrcInfo(ssrcInfo);
1080 1072 inviteInfo.setStream(ssrcInfo.getStream());
... ... @@ -1083,6 +1075,7 @@ public class PlayServiceImpl implements IPlayService {
1083 1075 logger.info("[录像下载] 收到invite 200, 下级自定义了ssrc, 但是当前模式无需修正");
1084 1076 }
1085 1077 }
  1078 + inviteStreamService.updateInviteInfo(inviteInfo);
1086 1079 });
1087 1080 } catch (InvalidArgumentException | SipException | ParseException e) {
1088 1081 logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
... ... @@ -1141,8 +1134,9 @@ public class PlayServiceImpl implements IPlayService {
1141 1134 return null;
1142 1135 }
1143 1136  
1144   - private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, JSONObject response, String deviceId, String channelId, String startTime, String endTime) {
1145   - StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, response, deviceId, channelId);
  1137 + private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) {
  1138 + OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam) hookParam;
  1139 + StreamInfo streamInfo = onPublishHandler(mediaServerItemInuse, streamChangedHookParam, deviceId, channelId);
1146 1140 if (streamInfo != null) {
1147 1141 streamInfo.setProgress(0);
1148 1142 streamInfo.setStartTime(startTime);
... ... @@ -1159,15 +1153,14 @@ public class PlayServiceImpl implements IPlayService {
1159 1153 }
1160 1154  
1161 1155  
1162   - public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, JSONObject resonse, String deviceId, String channelId) {
1163   - String streamId = resonse.getString("stream");
1164   - JSONArray tracks = resonse.getJSONArray("tracks");
1165   - StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", streamId, tracks, null);
  1156 + public StreamInfo onPublishHandler(MediaServerItem mediaServerItem, OnStreamChangedHookParam hookParam, String deviceId, String channelId) {
  1157 + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(mediaServerItem, "rtp", hookParam.getStream(), hookParam.getTracks(), null);
1166 1158 streamInfo.setDeviceID(deviceId);
1167 1159 streamInfo.setChannelId(channelId);
1168 1160 return streamInfo;
1169 1161 }
1170 1162  
  1163 +
1171 1164 @Override
1172 1165 public void zlmServerOffline(String mediaServerId) {
1173 1166 // 处理正在向上推流的上级平台
... ... @@ -1635,4 +1628,52 @@ public class PlayServiceImpl implements IPlayService {
1635 1628 }
1636 1629 redisCatchStorage.deleteSendRTPServer(device.getDeviceId(), channelId,null, null);
1637 1630 }
  1631 +
  1632 + @Override
  1633 + public void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback) {
  1634 + Device device = deviceService.getDevice(deviceId);
  1635 + if (device == null) {
  1636 + errorCallback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getMsg(), null);
  1637 + return;
  1638 + }
  1639 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  1640 + if (inviteInfo != null) {
  1641 + if (inviteInfo.getStreamInfo() != null) {
  1642 + // 已存在线直接截图
  1643 + MediaServerItem mediaServerItemInuse = mediaServerService.getOne(inviteInfo.getStreamInfo().getMediaServerId());
  1644 + String streamUrl;
  1645 + if (mediaServerItemInuse.getRtspPort() != 0) {
  1646 + streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", inviteInfo.getStreamInfo().getStream());
  1647 + }else {
  1648 + streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.mp4", mediaServerItemInuse.getHttpPort(), "rtp", inviteInfo.getStreamInfo().getStream());
  1649 + }
  1650 + String path = "snap";
  1651 + // 请求截图
  1652 + logger.info("[请求截图]: " + fileName);
  1653 + zlmresTfulUtils.getSnap(mediaServerItemInuse, streamUrl, 15, 1, path, fileName);
  1654 + File snapFile = new File(path + File.separator + fileName);
  1655 + if (snapFile.exists()) {
  1656 + errorCallback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), snapFile.getAbsoluteFile());
  1657 + }else {
  1658 + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
  1659 + }
  1660 + return;
  1661 + }
  1662 + }
  1663 +
  1664 + MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
  1665 + play(newMediaServerItem, deviceId, channelId, (code, msg, data)->{
  1666 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  1667 + InviteInfo inviteInfoForPlay = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  1668 + if (inviteInfoForPlay != null && inviteInfoForPlay.getStreamInfo() != null) {
  1669 + getSnap(deviceId, channelId, fileName, errorCallback);
  1670 + }else {
  1671 + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
  1672 + }
  1673 + }else {
  1674 + errorCallback.run(InviteErrorCode.FAIL.getCode(), InviteErrorCode.FAIL.getMsg(), null);
  1675 + }
  1676 + });
  1677 + }
  1678 +
1638 1679 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/RecordInfoServerImpl.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.service.impl;
2   -
3   -import com.genersoft.iot.vmp.service.IRecordInfoServer;
4   -import com.genersoft.iot.vmp.storager.dao.RecordInfoDao;
5   -import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
6   -import com.github.pagehelper.PageHelper;
7   -import com.github.pagehelper.PageInfo;
8   -import org.springframework.beans.factory.annotation.Autowired;
9   -import org.springframework.stereotype.Service;
10   -
11   -import java.util.List;
12   -
13   -@Service
14   -public class RecordInfoServerImpl implements IRecordInfoServer {
15   -
16   - @Autowired
17   - private RecordInfoDao recordInfoDao;
18   -
19   - @Override
20   - public PageInfo<RecordInfo> getRecordList(int page, int count) {
21   - PageHelper.startPage(page, count);
22   - List<RecordInfo> all = recordInfoDao.selectAll();
23   - return new PageInfo<>(all);
24   - }
25   -}
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
... ... @@ -2,12 +2,16 @@ package com.genersoft.iot.vmp.service.impl;
2 2  
3 3 import com.alibaba.fastjson2.JSONArray;
4 4 import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.GeneralCallback;
5 6 import com.genersoft.iot.vmp.common.StreamInfo;
6 7 import com.genersoft.iot.vmp.conf.UserSetting;
7 8 import com.genersoft.iot.vmp.conf.exception.ControllerException;
8 9 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
9 10 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
10 11 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  12 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
11 15 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 16 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
13 17 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
... ... @@ -23,7 +27,7 @@ import com.genersoft.iot.vmp.storager.dao.PlatformGbStreamMapper;
23 27 import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper;
24 28 import com.genersoft.iot.vmp.utils.DateUtil;
25 29 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
26   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  30 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
27 31 import com.github.pagehelper.PageInfo;
28 32 import org.slf4j.Logger;
29 33 import org.slf4j.LoggerFactory;
... ... @@ -80,6 +84,9 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
80 84 private IMediaServerService mediaServerService;
81 85  
82 86 @Autowired
  87 + private ZlmHttpHookSubscribe hookSubscribe;
  88 +
  89 + @Autowired
83 90 DataSourceTransactionManager dataSourceTransactionManager;
84 91  
85 92 @Autowired
... ... @@ -87,7 +94,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
87 94  
88 95  
89 96 @Override
90   - public StreamInfo save(StreamProxyItem param) {
  97 + public void save(StreamProxyItem param, GeneralCallback<StreamInfo> callback) {
91 98 MediaServerItem mediaInfo;
92 99 if (ObjectUtils.isEmpty(param.getMediaServerId()) || "auto".equals(param.getMediaServerId())){
93 100 mediaInfo = mediaServerService.getMediaServerForMinimumLoad(null);
... ... @@ -98,10 +105,43 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
98 105 logger.warn("保存代理未找到在线的ZLM...");
99 106 throw new ControllerException(ErrorCode.ERROR100.getCode(), "保存代理未找到在线的ZLM");
100 107 }
101   - String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
102   - param.getStream() );
103   - param.setDst_url(dstUrl);
104   - StringBuffer resultMsg = new StringBuffer();
  108 + String dstUrl;
  109 + if ("ffmpeg".equalsIgnoreCase(param.getType())) {
  110 + JSONObject jsonObject = zlmresTfulUtils.getMediaServerConfig(mediaInfo);
  111 + if (jsonObject.getInteger("code") != 0) {
  112 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取流媒体配置失败");
  113 + }
  114 + JSONArray dataArray = jsonObject.getJSONArray("data");
  115 + JSONObject mediaServerConfig = dataArray.getJSONObject(0);
  116 + String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey());
  117 + String schema = getSchemaFromFFmpegCmd(ffmpegCmd);
  118 + if (schema == null) {
  119 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式");
  120 + }
  121 + int port;
  122 + String schemaForUri;
  123 + if (schema.equalsIgnoreCase("rtsp")) {
  124 + port = mediaInfo.getRtspPort();
  125 + schemaForUri = schema;
  126 + }else if (schema.equalsIgnoreCase("flv")) {
  127 + port = mediaInfo.getHttpPort();
  128 + schemaForUri = "http";
  129 + }else if (schema.equalsIgnoreCase("rtmp")) {
  130 + port = mediaInfo.getRtmpPort();
  131 + schemaForUri = schema;
  132 + }else {
  133 + port = mediaInfo.getRtmpPort();
  134 + schemaForUri = schema;
  135 + }
  136 +
  137 + dstUrl = String.format("%s://%s:%s/%s/%s", schemaForUri, "127.0.0.1", port, param.getApp(),
  138 + param.getStream());
  139 + }else {
  140 + dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(),
  141 + param.getStream());
  142 + }
  143 + param.setDstUrl(dstUrl);
  144 + logger.info("[拉流代理] 输出地址为:{}", dstUrl);
105 145 param.setMediaServerId(mediaInfo.getId());
106 146 boolean saveResult;
107 147 // 更新
... ... @@ -111,29 +151,60 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
111 151 saveResult = addStreamProxy(param);
112 152 }
113 153 if (!saveResult) {
114   - throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败");
  154 + callback.run(ErrorCode.ERROR100.getCode(), "保存失败", null);
  155 + return;
115 156 }
116   - StreamInfo resultForStreamInfo = null;
117   - resultMsg.append("保存成功");
  157 +
  158 + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(param.getApp(), param.getStream(), true, "rtsp", mediaInfo.getId());
  159 + hookSubscribe.addSubscribe(hookSubscribeForStreamChange, (mediaServerItem, response) -> {
  160 + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
  161 + mediaInfo, param.getApp(), param.getStream(), null, null);
  162 + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
  163 + });
  164 +
118 165 if (param.isEnable()) {
119 166 JSONObject jsonObject = addStreamProxyToZlm(param);
120   - if (jsonObject == null || jsonObject.getInteger("code") != 0) {
121   - resultMsg.append(", 但是启用失败,请检查流地址是否可用");
  167 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  168 + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
  169 + StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream(
  170 + mediaInfo, param.getApp(), param.getStream(), null, null);
  171 + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
  172 + }else {
122 173 param.setEnable(false);
123 174 // 直接移除
124   - if (param.isEnable_remove_none_reader()) {
  175 + if (param.isEnableRemoveNoneReader()) {
125 176 del(param.getApp(), param.getStream());
126 177 }else {
127 178 updateStreamProxy(param);
128 179 }
  180 + if (jsonObject == null){
  181 + callback.run(ErrorCode.ERROR100.getCode(), "记录已保存,启用失败", null);
  182 + return;
  183 + }else {
  184 + callback.run(ErrorCode.ERROR100.getCode(), jsonObject.getString("msg"), null);
  185 + return;
  186 + }
  187 + }
  188 + }
  189 + }
129 190  
130   - }else {
131   - resultForStreamInfo = mediaService.getStreamInfoByAppAndStream(
132   - mediaInfo, param.getApp(), param.getStream(), null, null);
  191 + private String getSchemaFromFFmpegCmd(String ffmpegCmd) {
  192 + ffmpegCmd = ffmpegCmd.replaceAll(" + ", " ");
  193 + String[] paramArray = ffmpegCmd.split(" ");
  194 + if (paramArray.length == 0) {
  195 + return null;
  196 + }
  197 + for (int i = 0; i < paramArray.length; i++) {
  198 + if (paramArray[i].equalsIgnoreCase("-f")) {
  199 + if (i + 1 < paramArray.length - 1) {
  200 + return paramArray[i+1];
  201 + }else {
  202 + return null;
  203 + }
133 204  
134 205 }
135 206 }
136   - return resultForStreamInfo;
  207 + return null;
137 208 }
138 209  
139 210 /**
... ... @@ -222,11 +293,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
222 293 }
223 294 if ("default".equals(param.getType())){
224 295 result = zlmresTfulUtils.addStreamProxy(mediaServerItem, param.getApp(), param.getStream(), param.getUrl(),
225   - param.isEnable_audio(), param.isEnable_mp4(), param.getRtp_type());
  296 + param.isEnableAudio(), param.isEnableMp4(), param.getRtpType());
226 297 }else if ("ffmpeg".equals(param.getType())) {
227   - result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrc_url(), param.getDst_url(),
228   - param.getTimeout_ms() + "", param.isEnable_audio(), param.isEnable_mp4(),
229   - param.getFfmpeg_cmd_key());
  298 + result = zlmresTfulUtils.addFFmpegSource(mediaServerItem, param.getSrcUrl(), param.getDstUrl(),
  299 + param.getTimeoutMs() + "", param.isEnableAudio(), param.isEnableMp4(),
  300 + param.getFfmpegCmdKey());
230 301 }
231 302 return result;
232 303 }
... ... @@ -280,7 +351,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
280 351 updateStreamProxy(streamProxy);
281 352 }else {
282 353 logger.info("启用代理失败: {}/{}->{}({})", app, stream, jsonObject.getString("msg"),
283   - streamProxy.getSrc_url() == null? streamProxy.getUrl():streamProxy.getSrc_url());
  354 + streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl());
284 355 }
285 356 }
286 357 return result;
... ... @@ -326,7 +397,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
326 397 @Override
327 398 public void zlmServerOnline(String mediaServerId) {
328 399 // 移除开启了无人观看自动移除的流
329   - List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selecAutoRemoveItemByMediaServerId(mediaServerId);
  400 + List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selectAutoRemoveItemByMediaServerId(mediaServerId);
330 401 if (streamProxyItemList.size() > 0) {
331 402 gbStreamMapper.batchDel(streamProxyItemList);
332 403 }
... ... @@ -354,7 +425,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
354 425 @Override
355 426 public void zlmServerOffline(String mediaServerId) {
356 427 // 移除开启了无人观看自动移除的流
357   - List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selecAutoRemoveItemByMediaServerId(mediaServerId);
  428 + List<StreamProxyItem> streamProxyItemList = streamProxyMapper.selectAutoRemoveItemByMediaServerId(mediaServerId);
358 429 if (streamProxyItemList.size() > 0) {
359 430 gbStreamMapper.batchDel(streamProxyItemList);
360 431 }
... ... @@ -432,7 +503,11 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
432 503 }
433 504  
434 505 @Override
435   - public ResourceBaceInfo getOverview() {
436   - return streamProxyMapper.getOverview();
  506 + public ResourceBaseInfo getOverview() {
  507 +
  508 + int total = streamProxyMapper.getAllCount();
  509 + int online = streamProxyMapper.getOnline();
  510 +
  511 + return new ResourceBaseInfo(total, online);
437 512 }
438 513 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
... ... @@ -20,7 +20,7 @@ import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
20 20 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
21 21 import com.genersoft.iot.vmp.storager.dao.*;
22 22 import com.genersoft.iot.vmp.utils.DateUtil;
23   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  23 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
24 24 import com.github.pagehelper.PageHelper;
25 25 import com.github.pagehelper.PageInfo;
26 26 import org.slf4j.Logger;
... ... @@ -183,6 +183,7 @@ public class StreamPushServiceImpl implements IStreamPushService {
183 183  
184 184 @Override
185 185 public boolean stop(String app, String streamId) {
  186 + logger.info("[推流 ] 停止流: {}/{}", app, streamId);
186 187 StreamPushItem streamPushItem = streamPushMapper.selectOne(app, streamId);
187 188 if (streamPushItem != null) {
188 189 gbStreamService.sendCatalogMsg(streamPushItem, CatalogEvent.DEL);
... ... @@ -531,7 +532,10 @@ public class StreamPushServiceImpl implements IStreamPushService {
531 532 }
532 533  
533 534 @Override
534   - public ResourceBaceInfo getOverview() {
535   - return streamPushMapper.getOverview(userSetting.isUsePushingAsStatus());
  535 + public ResourceBaseInfo getOverview() {
  536 + int total = streamPushMapper.getAllCount();
  537 + int online = streamPushMapper.getAllOnline(userSetting.isUsePushingAsStatus());
  538 +
  539 + return new ResourceBaseInfo(total, online);
536 540 }
537 541 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java
... ... @@ -9,7 +9,6 @@ import com.genersoft.iot.vmp.vmanager.bean.StreamPushExcelDto;
9 9 import com.google.common.collect.BiMap;
10 10 import com.google.common.collect.HashBiMap;
11 11 import org.springframework.util.ObjectUtils;
12   -import org.springframework.util.StringUtils;
13 12  
14 13 import java.util.*;
15 14  
... ... @@ -33,38 +32,43 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener&lt;StreamPus
33 32 /**
34 33 * 用于存储不加过滤的所有数据
35 34 */
36   - private List<StreamPushItem> streamPushItems = new ArrayList<>();
  35 + private final List<StreamPushItem> streamPushItems = new ArrayList<>();
37 36  
38 37 /**
39 38 * 用于存储更具APP+Stream过滤后的数据,可以直接存入stream_push表与gb_stream表
40 39 */
41   - private Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>();
  40 + private final Map<String,StreamPushItem> streamPushItemForSave = new HashMap<>();
42 41  
43 42 /**
44 43 * 用于存储按照APP+Stream为KEY, 平台ID+目录Id 为value的数据,用于存储到gb_stream表后获取app+Stream对应的平台与目录信息,然后存入关联表
45 44 */
46   - private Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>();
  45 + private final Map<String, List<String[]>> streamPushItemsForPlatform = new HashMap<>();
47 46  
48 47 /**
49 48 * 用于判断文件是否存在重复的app+Stream+平台ID
50 49 */
51   - private Set<String> streamPushStreamSet = new HashSet<>();
  50 + private final Set<String> streamPushStreamSet = new HashSet<>();
52 51  
53 52 /**
54 53 * 用于存储APP+Stream->国标ID 的数据结构, 数据一一对应,全局判断APP+Stream->国标ID是否存在不对应
55 54 */
56   - private BiMap<String,String> gBMap = HashBiMap.create();
  55 + private final BiMap<String,String> gBMap = HashBiMap.create();
  56 +
  57 + /**
  58 + * 用于存储APP+Stream-> 在数据库中的数据
  59 + */
  60 + private final BiMap<String,String> pushMapInDb = HashBiMap.create();
57 61  
58 62 /**
59 63 * 记录错误的APP+Stream
60 64 */
61   - private List<String> errorStreamList = new ArrayList<>();
  65 + private final List<String> errorStreamList = new ArrayList<>();
62 66  
63 67  
64 68 /**
65 69 * 记录错误的国标ID
66 70 */
67   - private List<String> errorGBList = new ArrayList<>();
  71 + private final List<String> errorInfoList = new ArrayList<>();
68 72  
69 73 /**
70 74 * 读取数量计数器
... ... @@ -75,6 +79,13 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener&lt;StreamPus
75 79 this.pushService = pushService;
76 80 this.defaultMediaServerId = defaultMediaServerId;
77 81 this.errorDataHandler = errorDataHandler;
  82 + // 获取数据库已有的数据,已经存在的则忽略
  83 + List<String> allAppAndStreams = pushService.getAllAppAndStream();
  84 + if (allAppAndStreams.size() > 0) {
  85 + for (String allAppAndStream : allAppAndStreams) {
  86 + pushMapInDb.put(allAppAndStream, allAppAndStream);
  87 + }
  88 + }
78 89 }
79 90  
80 91 public interface ErrorDataHandler{
... ... @@ -88,26 +99,30 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener&lt;StreamPus
88 99 || ObjectUtils.isEmpty(streamPushExcelDto.getGbId())) {
89 100 return;
90 101 }
  102 + Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
91 103  
92 104 if (gBMap.get(streamPushExcelDto.getApp() + streamPushExcelDto.getStream()) == null) {
93 105 try {
94 106 gBMap.put(streamPushExcelDto.getApp() + streamPushExcelDto.getStream(), streamPushExcelDto.getGbId());
95 107 }catch (IllegalArgumentException e) {
96   - errorGBList.add(streamPushExcelDto.getGbId() + "(不同的app+stream使用了相同的国标ID)");
  108 + errorInfoList.add("行:" + rowIndex + ", " + streamPushExcelDto.getGbId() + " 国标ID重复使用");
97 109 return;
98 110 }
99 111 }else {
100 112 if (!gBMap.get(streamPushExcelDto.getApp() + streamPushExcelDto.getStream()).equals(streamPushExcelDto.getGbId())) {
101   - errorGBList.add(streamPushExcelDto.getGbId() + "(同一组app+stream使用了不同的国标ID)");
  113 + errorInfoList.add("行:" + rowIndex + ", " + streamPushExcelDto.getGbId() + " 同样的应用名和流ID使用了不同的国标ID");
102 114 return;
103 115 }
104 116 }
105 117  
106 118 if (streamPushStreamSet.contains(streamPushExcelDto.getApp() + streamPushExcelDto.getStream() + streamPushExcelDto.getPlatformId())) {
107   - errorStreamList.add(streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ "/" +
108   - streamPushExcelDto.getPlatformId() + "(同一组app+stream添加在了同一个平台下)");
  119 + errorStreamList.add("行:" + rowIndex + ", " + streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ " 平台信息重复");
109 120 return;
110 121 }else {
  122 + if (pushMapInDb.get(streamPushExcelDto.getApp()+streamPushExcelDto.getStream()) != null) {
  123 + errorStreamList.add("行:" + rowIndex + ", " + streamPushExcelDto.getApp() + "/" + streamPushExcelDto.getStream()+ " 数据已存在");
  124 + return;
  125 + }
111 126 streamPushStreamSet.add(streamPushExcelDto.getApp()+streamPushExcelDto.getStream() + streamPushExcelDto.getPlatformId());
112 127 }
113 128  
... ... @@ -165,7 +180,7 @@ public class StreamPushUploadFileHandler extends AnalysisEventListener&lt;StreamPus
165 180 gBMap.clear();
166 181 streamPushStreamSet.clear();
167 182 streamPushItemsForPlatform.clear();
168   - errorDataHandler.handle(errorStreamList, errorGBList);
  183 + errorDataHandler.handle(errorStreamList, errorInfoList);
169 184 }
170 185  
171 186 private void saveData(){
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
... ... @@ -7,8 +7,7 @@ import com.github.pagehelper.PageHelper;
7 7 import com.github.pagehelper.PageInfo;
8 8 import org.springframework.beans.factory.annotation.Autowired;
9 9 import org.springframework.stereotype.Service;
10   -import org.springframework.util.ObjectUtils;
11   -import org.springframework.util.StringUtils;
  10 +import org.springframework.util.DigestUtils;
12 11  
13 12 import java.util.List;
14 13  
... ... @@ -61,11 +60,22 @@ public class UserServiceImpl implements IUserService {
61 60  
62 61 @Override
63 62 public boolean checkPushAuthority(String callId, String sign) {
64   - if (ObjectUtils.isEmpty(callId)) {
65   - return userMapper.checkPushAuthorityByCallId(sign).size() > 0;
66   - }else {
67   - return userMapper.checkPushAuthorityByCallIdAndSign(callId, sign).size() > 0;
  63 +
  64 + List<User> users = userMapper.getUsers();
  65 + if (users.size() == 0) {
  66 + return false;
  67 + }
  68 + for (User user : users) {
  69 + if (user.getPushKey() == null) {
  70 + continue;
  71 + }
  72 + String checkStr = callId == null? user.getPushKey():(callId + "_" + user.getPushKey()) ;
  73 + String checkSign = DigestUtils.md5DigestAsHex(checkStr.getBytes());
  74 + if (checkSign.equals(sign)) {
  75 + return true;
  76 + }
68 77 }
  78 + return false;
69 79 }
70 80  
71 81 @Override
... ...
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java 0 → 100644
  1 +package com.genersoft.iot.vmp.service.redisMsg;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.service.IStreamPushService;
  6 +import org.jetbrains.annotations.NotNull;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.beans.factory.annotation.Qualifier;
  11 +import org.springframework.data.redis.connection.Message;
  12 +import org.springframework.data.redis.connection.MessageListener;
  13 +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import java.util.concurrent.ConcurrentLinkedQueue;
  17 +
  18 +/**
  19 + * 接收来自redis的关闭流更新通知
  20 + * @author lin
  21 + */
  22 +@Component
  23 +public class RedisCloseStreamMsgListener implements MessageListener {
  24 +
  25 + private final static Logger logger = LoggerFactory.getLogger(RedisCloseStreamMsgListener.class);
  26 +
  27 +
  28 + @Autowired
  29 + private IStreamPushService pushService;
  30 +
  31 + private ConcurrentLinkedQueue<Message> taskQueue = new ConcurrentLinkedQueue<>();
  32 +
  33 + @Qualifier("taskExecutor")
  34 + @Autowired
  35 + private ThreadPoolTaskExecutor taskExecutor;
  36 +
  37 + @Override
  38 + public void onMessage(@NotNull Message message, byte[] bytes) {
  39 + boolean isEmpty = taskQueue.isEmpty();
  40 + taskQueue.offer(message);
  41 + if (isEmpty) {
  42 + taskExecutor.execute(() -> {
  43 + while (!taskQueue.isEmpty()) {
  44 + Message msg = taskQueue.poll();
  45 + try {
  46 + JSONObject jsonObject = JSON.parseObject(msg.getBody());
  47 + String app = jsonObject.getString("app");
  48 + String stream = jsonObject.getString("stream");
  49 + pushService.stop(app, stream);
  50 +
  51 + }catch (Exception e) {
  52 + logger.warn("[REDIS的关闭推流通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  53 + logger.error("[REDIS的关闭推流通知] 异常内容: ", e);
  54 + }
  55 + }
  56 + });
  57 + }
  58 + }
  59 +}
... ...
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
... ... @@ -289,7 +289,7 @@ public class RedisGbPlayMsgListener implements MessageListener {
289 289 // 添加订阅
290 290 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(content.getApp(), content.getStream(), true, "rtsp", mediaServerItem.getId());
291 291  
292   - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json)->{
  292 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam)->{
293 293 dynamicTask.stop(taskKey);
294 294 responseSendItem(mediaServerItem, content, toId, serial);
295 295 });
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
... ... @@ -191,8 +191,6 @@ public interface IRedisCatchStorage {
191 191  
192 192 int getProxyStreamCount(String id);
193 193  
194   - int getGbReceiveCount(String id);
195   -
196 194 int getGbSendCount(String id);
197 195  
198 196 void addDiskInfo(List<Map<String, Object>> diskInfo);
... ... @@ -204,4 +202,5 @@ public interface IRedisCatchStorage {
204 202 void removeAllDevice();
205 203  
206 204 void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online);
  205 + void sendChannelAddOrDelete(String deviceId, String channelId, boolean add);
207 206 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java
... ... @@ -16,32 +16,32 @@ import java.util.List;
16 16 @Repository
17 17 public interface DeviceAlarmMapper {
18 18  
19   - @Insert("INSERT INTO device_alarm (deviceId, channelId, alarmPriority, alarmMethod, alarmTime, alarmDescription, longitude, latitude, alarmType , createTime ) " +
  19 + @Insert("INSERT INTO wvp_device_alarm (device_id, channel_id, alarm_priority, alarm_method, alarm_time, alarm_description, longitude, latitude, alarm_type , create_time ) " +
20 20 "VALUES (#{deviceId}, #{channelId}, #{alarmPriority}, #{alarmMethod}, #{alarmTime}, #{alarmDescription}, #{longitude}, #{latitude}, #{alarmType}, #{createTime})")
21 21 int add(DeviceAlarm alarm);
22 22  
23 23  
24 24 @Select( value = {" <script>" +
25   - " SELECT * FROM device_alarm " +
  25 + " SELECT * FROM wvp_device_alarm " +
26 26 " WHERE 1=1 " +
27   - " <if test=\"deviceId != null\" > AND deviceId = #{deviceId}</if>" +
28   - " <if test=\"alarmPriority != null\" > AND alarmPriority = #{alarmPriority} </if>" +
29   - " <if test=\"alarmMethod != null\" > AND alarmMethod = #{alarmMethod} </if>" +
30   - " <if test=\"alarmType != null\" > AND alarmType = #{alarmType} </if>" +
31   - " <if test=\"startTime != null\" > AND alarmTime &gt;= #{startTime} </if>" +
32   - " <if test=\"endTime != null\" > AND alarmTime &lt;= #{endTime} </if>" +
33   - " ORDER BY alarmTime ASC " +
  27 + " <if test=\"deviceId != null\" > AND device_id = #{deviceId}</if>" +
  28 + " <if test=\"alarmPriority != null\" > AND alarm_priority = #{alarmPriority} </if>" +
  29 + " <if test=\"alarmMethod != null\" > AND alarm_method = #{alarmMethod} </if>" +
  30 + " <if test=\"alarmType != null\" > AND alarm_type = #{alarmType} </if>" +
  31 + " <if test=\"startTime != null\" > AND alarm_time &gt;= #{startTime} </if>" +
  32 + " <if test=\"endTime != null\" > AND alarm_time &lt;= #{endTime} </if>" +
  33 + " ORDER BY alarm_time ASC " +
34 34 " </script>"})
35 35 List<DeviceAlarm> query(String deviceId, String alarmPriority, String alarmMethod,
36 36 String alarmType, String startTime, String endTime);
37 37  
38 38  
39 39 @Delete(" <script>" +
40   - "DELETE FROM device_alarm WHERE 1=1 " +
41   - " <if test=\"deviceIdList != null and id == null \" > AND deviceId in " +
  40 + "DELETE FROM wvp_device_alarm WHERE 1=1 " +
  41 + " <if test=\"deviceIdList != null and id == null \" > AND device_id in " +
42 42 "<foreach collection='deviceIdList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
43 43 "</if>" +
44   - " <if test=\"time != null and id == null \" > AND alarmTime &lt;= #{time}</if>" +
  44 + " <if test=\"time != null and id == null \" > AND alarm_time &lt;= #{time}</if>" +
45 45 " <if test=\"id != null\" > AND id = #{id}</if>" +
46 46 " </script>"
47 47 )
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
... ... @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.storager.dao;
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 4 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
5 5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform;
6   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
7 6 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
8 7 import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
9 8 import org.apache.ibatis.annotations.*;
... ... @@ -18,10 +17,10 @@ import java.util.List;
18 17 @Repository
19 18 public interface DeviceChannelMapper {
20 19  
21   - @Insert("INSERT INTO device_channel (channelId, deviceId, name, manufacture, model, owner, civilCode, block, " +
22   - "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
23   - "ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
24   - "longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
  20 + @Insert("INSERT INTO wvp_device_channel (channel_id, device_id, name, manufacture, model, owner, civil_code, block, " +
  21 + "address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " +
  22 + "ip_address, port, password, ptz_type, status, stream_id, longitude, latitude, longitude_gcj02, latitude_gcj02, " +
  23 + "longitude_wgs84, latitude_wgs84, has_audio, create_time, update_time, business_group_id, gps_time) " +
25 24 "VALUES (#{channelId}, #{deviceId}, #{name}, #{manufacture}, #{model}, #{owner}, #{civilCode}, #{block}," +
26 25 "#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{secrecy}, " +
27 26 "#{ipAddress}, #{port}, #{password}, #{PTZType}, #{status}, #{streamId}, #{longitude}, #{latitude}, #{longitudeGcj02}, " +
... ... @@ -29,39 +28,39 @@ public interface DeviceChannelMapper {
29 28 int add(DeviceChannel channel);
30 29  
31 30 @Update(value = {" <script>" +
32   - "UPDATE device_channel " +
33   - "SET updateTime=#{updateTime}" +
  31 + "UPDATE wvp_device_channel " +
  32 + "SET update_time=#{updateTime}" +
34 33 "<if test='name != null'>, name=#{name}</if>" +
35 34 "<if test='manufacture != null'>, manufacture=#{manufacture}</if>" +
36 35 "<if test='model != null'>, model=#{model}</if>" +
37 36 "<if test='owner != null'>, owner=#{owner}</if>" +
38   - "<if test='civilCode != null'>, civilCode=#{civilCode}</if>" +
  37 + "<if test='civilCode != null'>, civil_code=#{civilCode}</if>" +
39 38 "<if test='block != null'>, block=#{block}</if>" +
40 39 "<if test='address != null'>, address=#{address}</if>" +
41 40 "<if test='parental != null'>, parental=#{parental}</if>" +
42   - "<if test='parentId != null'>, parentId=#{parentId}</if>" +
43   - "<if test='safetyWay != null'>, safetyWay=#{safetyWay}</if>" +
44   - "<if test='registerWay != null'>, registerWay=#{registerWay}</if>" +
45   - "<if test='certNum != null'>, certNum=#{certNum}</if>" +
  41 + "<if test='parentId != null'>, parent_id=#{parentId}</if>" +
  42 + "<if test='safetyWay != null'>, safety_way=#{safetyWay}</if>" +
  43 + "<if test='registerWay != null'>, register_way=#{registerWay}</if>" +
  44 + "<if test='certNum != null'>, cert_num=#{certNum}</if>" +
46 45 "<if test='certifiable != null'>, certifiable=#{certifiable}</if>" +
47   - "<if test='errCode != null'>, errCode=#{errCode}</if>" +
  46 + "<if test='errCode != null'>, err_code=#{errCode}</if>" +
48 47 "<if test='secrecy != null'>, secrecy=#{secrecy}</if>" +
49   - "<if test='ipAddress != null'>, ipAddress=#{ipAddress}</if>" +
  48 + "<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" +
50 49 "<if test='port != null'>, port=#{port}</if>" +
51 50 "<if test='password != null'>, password=#{password}</if>" +
52   - "<if test='PTZType != null'>, PTZType=#{PTZType}</if>" +
  51 + "<if test='PTZType != null'>, ptz_type=#{PTZType}</if>" +
53 52 "<if test='status != null'>, status=#{status}</if>" +
54   - "<if test='streamId != null'>, streamId=#{streamId}</if>" +
55   - "<if test='hasAudio != null'>, hasAudio=#{hasAudio}</if>" +
  53 + "<if test='streamId != null'>, stream_id=#{streamId}</if>" +
  54 + "<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" +
56 55 "<if test='longitude != null'>, longitude=#{longitude}</if>" +
57 56 "<if test='latitude != null'>, latitude=#{latitude}</if>" +
58   - "<if test='longitudeGcj02 != null'>, longitudeGcj02=#{longitudeGcj02}</if>" +
59   - "<if test='latitudeGcj02 != null'>, latitudeGcj02=#{latitudeGcj02}</if>" +
60   - "<if test='longitudeWgs84 != null'>, longitudeWgs84=#{longitudeWgs84}</if>" +
61   - "<if test='latitudeWgs84 != null'>, latitudeWgs84=#{latitudeWgs84}</if>" +
62   - "<if test='businessGroupId != null'>, businessGroupId=#{businessGroupId}</if>" +
63   - "<if test='gpsTime != null'>, gpsTime=#{gpsTime}</if>" +
64   - "WHERE deviceId=#{deviceId} AND channelId=#{channelId}"+
  57 + "<if test='longitudeGcj02 != null'>, longitude_gcj02=#{longitudeGcj02}</if>" +
  58 + "<if test='latitudeGcj02 != null'>, latitude_gcj02=#{latitudeGcj02}</if>" +
  59 + "<if test='longitudeWgs84 != null'>, longitude_wgs84=#{longitudeWgs84}</if>" +
  60 + "<if test='latitudeWgs84 != null'>, latitude_wgs84=#{latitudeWgs84}</if>" +
  61 + "<if test='businessGroupId != null'>, business_group_id=#{businessGroupId}</if>" +
  62 + "<if test='gpsTime != null'>, gps_time=#{gpsTime}</if>" +
  63 + "WHERE device_id=#{deviceId} AND channel_id=#{channelId}"+
65 64 " </script>"})
66 65 int update(DeviceChannel channel);
67 66  
... ... @@ -69,42 +68,42 @@ public interface DeviceChannelMapper {
69 68 "SELECT " +
70 69 "dc.* " +
71 70 "from " +
72   - "device_channel dc " +
  71 + "wvp_device_channel dc " +
73 72 "WHERE " +
74   - "dc.deviceId = #{deviceId} " +
75   -" <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
76   - " <if test='parentChannelId != null'> AND (dc.parentId=#{parentChannelId} OR dc.civilCode = #{parentChannelId}) </if> " +
77   - " <if test='online == true' > AND dc.status=1</if>" +
78   - " <if test='online == false' > AND dc.status=0</if>" +
79   - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" +
80   - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" +
81   - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
  73 + "dc.device_id = #{deviceId} " +
  74 +" <if test='query != null'> AND (dc.channel_id LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
  75 + " <if test='parentChannelId != null'> AND (dc.parent_id=#{parentChannelId} OR dc.civil_code = #{parentChannelId}) </if> " +
  76 + " <if test='online == true' > AND dc.status= true</if>" +
  77 + " <if test='online == false' > AND dc.status= false</if>" +
  78 + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" +
  79 + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" +
  80 + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
82 81 "#{item} " +
83 82 "</foreach> </if>" +
84   - "ORDER BY dc.channelId " +
  83 + "ORDER BY dc.channel_id " +
85 84 " </script>"})
86 85 List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds);
87 86  
88 87 @Select(value = {" <script>" +
89 88 "SELECT " +
90 89 "dc.*, " +
91   - "de.name as deviceName, " +
92   - "de.online as deviceOnline " +
  90 + "de.name as device_name, " +
  91 + "de.on_line as device_online " +
93 92 "from " +
94   - "device_channel dc " +
95   - "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
  93 + "wvp_device_channel dc " +
  94 + "LEFT JOIN wvp_device de ON dc.device_id = de.device_id " +
96 95 "WHERE 1=1" +
97   - " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " +
98   - " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
99   - " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " +
100   - " <if test='online == true' > AND dc.status=1</if>" +
101   - " <if test='online == false' > AND dc.status=0</if>" +
102   - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" +
103   - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" +
104   - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
  96 + " <if test='deviceId != null'> AND dc.device_id = #{deviceId} </if> " +
  97 + " <if test='query != null'> AND (dc.channel_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
  98 + " <if test='parentChannelId != null'> AND dc.parent_id=#{parentChannelId} </if> " +
  99 + " <if test='online == true' > AND dc.status=true</if>" +
  100 + " <if test='online == false' > AND dc.status=false</if>" +
  101 + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" +
  102 + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" +
  103 + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
105 104 "#{item} " +
106 105 "</foreach> </if>" +
107   - "ORDER BY dc.channelId ASC" +
  106 + "ORDER BY dc.channel_id ASC" +
108 107 " </script>"})
109 108 List<DeviceChannelExtend> queryChannelsWithDeviceInfo(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds);
110 109  
... ... @@ -112,151 +111,97 @@ public interface DeviceChannelMapper {
112 111 @Select(value = {" <script>" +
113 112 "SELECT " +
114 113 "dc.*, " +
115   - "de.name as deviceName, " +
116   - "de.online as deviceOnline " +
  114 + "de.name as device_name, " +
  115 + "de.on_line as device_online " +
117 116 "from " +
118   - "device_channel dc " +
119   - "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
  117 + "wvp_device_channel dc " +
  118 + "LEFT JOIN wvp_device de ON dc.device_id = de.device_id " +
120 119 "WHERE 1=1" +
121   - " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " +
122   - " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
123   - " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " +
124   - " <if test='online == true' > AND dc.status=1</if>" +
125   - " <if test='online == false' > AND dc.status=0</if>" +
126   - " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" +
127   - " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" +
128   - "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
  120 + " <if test='deviceId != null'> AND dc.device_id = #{deviceId} </if> " +
  121 + " <if test='query != null'> AND (dc.channel_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
  122 + " <if test='parentChannelId != null'> AND dc.parent_id=#{parentChannelId} </if> " +
  123 + " <if test='online == true' > AND dc.status=true</if>" +
  124 + " <if test='online == false' > AND dc.status=false</if>" +
  125 + " <if test='hasSubChannel == true' > AND dc.sub_count > 0 </if>" +
  126 + " <if test='hasSubChannel == false' > AND dc.sub_count = 0 </if>" +
  127 + "<if test='channelIds != null'> AND dc.channel_id in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
129 128 "#{item} " +
130 129 "</foreach> </if>" +
131   - "ORDER BY dc.channelId ASC " +
  130 + "ORDER BY dc.channel_id ASC " +
132 131 "Limit #{limit} OFFSET #{start}" +
133 132 " </script>"})
134 133 List<DeviceChannelExtend> queryChannelsByDeviceIdWithStartAndLimit(String deviceId,List<String> channelIds, String parentChannelId, String query,
135 134 Boolean hasSubChannel, Boolean online, int start, int limit);
136 135  
137   - @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
  136 + @Select("SELECT * FROM wvp_device_channel WHERE device_id=#{deviceId} AND channel_id=#{channelId}")
138 137 DeviceChannel queryChannel(String deviceId, String channelId);
139 138  
140   - @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}")
  139 + @Delete("DELETE FROM wvp_device_channel WHERE device_id=#{deviceId}")
141 140 int cleanChannelsByDeviceId(String deviceId);
142 141  
143   - @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
  142 + @Delete("DELETE FROM wvp_device_channel WHERE device_id=#{deviceId} AND channel_id=#{channelId}")
144 143 int del(String deviceId, String channelId);
145 144  
146   - @Update(value = {"UPDATE device_channel SET streamId=null WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
  145 + @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_id=#{deviceId} AND channel_id=#{channelId}"})
147 146 void stopPlay(String deviceId, String channelId);
148 147  
149   - @Update(value = {"UPDATE device_channel SET streamId=#{streamId} WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
  148 + @Update(value = {"UPDATE wvp_device_channel SET stream_id=#{streamId} WHERE device_id=#{deviceId} AND channel_id=#{channelId}"})
150 149 void startPlay(String deviceId, String channelId, String streamId);
151 150  
152 151 @Select(value = {" <script>" +
153 152 "SELECT " +
154 153 " dc.id,\n" +
155   - " dc.channelId,\n" +
156   - " dc.deviceId,\n" +
  154 + " dc.channel_id,\n" +
  155 + " dc.device_id,\n" +
157 156 " dc.name,\n" +
158 157 " de.manufacturer,\n" +
159   - " de.hostAddress,\n" +
160   - " dc.subCount,\n" +
161   - " pgc.platformId as platformId,\n" +
162   - " pgc.catalogId as catalogId " +
163   - " FROM device_channel dc " +
164   - " LEFT JOIN device de ON dc.deviceId = de.deviceId " +
165   - " LEFT JOIN platform_gb_channel pgc on pgc.deviceChannelId = dc.id " +
  158 + " de.host_address,\n" +
  159 + " dc.sub_count,\n" +
  160 + " pgc.platform_id as platform_id,\n" +
  161 + " pgc.catalog_id as catalog_id " +
  162 + " FROM wvp_device_channel dc " +
  163 + " LEFT JOIN wvp_device de ON dc.device_id = de.device_id " +
  164 + " LEFT JOIN wvp_platform_gb_channel pgc on pgc.device_channel_id = dc.id " +
166 165 " WHERE 1=1 " +
167   - " <if test='query != null'> AND (dc.channelId LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
168   - " <if test='online == true' > AND dc.status=1</if> " +
169   - " <if test='online == false' > AND dc.status=0</if> " +
170   - " <if test='hasSubChannel!= null and hasSubChannel == true' > AND dc.subCount > 0</if> " +
171   - " <if test='hasSubChannel!= null and hasSubChannel == false' > AND dc.subCount = 0</if> " +
172   - " <if test='catalogId == null ' > AND dc.id not in (select deviceChannelId from platform_gb_channel where platformId=#{platformId} ) </if> " +
173   - " <if test='catalogId != null ' > AND pgc.platformId = #{platformId} and pgc.catalogId=#{catalogId} </if> " +
174   - " ORDER BY dc.deviceId, dc.channelId ASC" +
  166 + " <if test='query != null'> AND (dc.channel_id LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%') OR dc.name LIKE concat('%',#{query},'%'))</if> " +
  167 + " <if test='online == true' > AND dc.status=true</if> " +
  168 + " <if test='online == false' > AND dc.status=false</if> " +
  169 + " <if test='hasSubChannel!= null and has_sub_channel == true' > AND dc.sub_count > 0</if> " +
  170 + " <if test='hasSubChannel!= null and has_sub_channel == false' > AND dc.sub_count = 0</if> " +
  171 + " <if test='catalogId == null ' > AND dc.id not in (select device_channel_id from wvp_platform_gb_channel where platform_id=#{platformId} ) </if> " +
  172 + " <if test='catalogId != null ' > AND pgc.platform_id = #{platformId} and pgc.catalog_id=#{catalogId} </if> " +
  173 + " ORDER BY dc.device_id, dc.channel_id ASC" +
175 174 " </script>"})
176 175 List<ChannelReduce> queryChannelListInAll(String query, Boolean online, Boolean hasSubChannel, String platformId, String catalogId);
177 176  
178 177 @Select(value = {" <script>" +
179 178 "SELECT " +
180 179 " dc.*,\n" +
181   - " pgc.platformId as platformId,\n" +
182   - " pgc.catalogId as catalogId " +
183   - " FROM device_channel dc " +
184   - " LEFT JOIN platform_gb_channel pgc on pgc.deviceChannelId = dc.id " +
185   - " WHERE pgc.platformId = #{platformId} " +
186   - " ORDER BY dc.deviceId, dc.channelId ASC" +
  180 + " pgc.platform_id as platform_id,\n" +
  181 + " pgc.catalog_id as catalog_id " +
  182 + " FROM wvp_device_channel dc " +
  183 + " LEFT JOIN wvp_platform_gb_channel pgc on pgc.device_channel_id = dc.id " +
  184 + " WHERE pgc.platform_id = #{platformId} " +
  185 + " ORDER BY dc.device_id, dc.channel_id ASC" +
187 186 " </script>"})
188 187 List<DeviceChannelInPlatform> queryChannelByPlatformId(String platformId);
189 188  
190 189  
191   - @Select("SELECT * FROM device_channel WHERE channelId=#{channelId}")
  190 + @Select("SELECT * FROM wvp_device_channel WHERE channel_id=#{channelId}")
192 191 List<DeviceChannel> queryChannelByChannelId( String channelId);
193 192  
194   - @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
  193 + @Update(value = {"UPDATE wvp_device_channel SET status=false WHERE device_id=#{deviceId} AND channel_id=#{channelId}"})
195 194 void offline(String deviceId, String channelId);
196 195  
197   - @Update(value = {"UPDATE device_channel SET status=0 WHERE deviceId=#{deviceId}"})
  196 + @Update(value = {"UPDATE wvp_device_channel SET status=fasle WHERE device_id=#{deviceId}"})
198 197 void offlineByDeviceId(String deviceId);
199 198  
200   -// @Insert("<script> " +
201   -// "insert into device_channel " +
202   -// "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
203   -// " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
204   -// " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
205   -// " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
206   -// "values " +
207   -// "<foreach collection='addChannels' index='index' item='item' separator=','> " +
208   -// "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
209   -// "#{item.owner}, #{item.civilCode}, #{item.block},#{item.subCount}," +
210   -// "#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, " +
211   -// "#{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.secrecy}, " +
212   -// "#{item.ipAddress}, #{item.port}, #{item.password}, #{item.PTZType}, #{item.status}, " +
213   -// "#{item.streamId}, #{item.longitude}, #{item.latitude},#{item.longitudeGcj02}, " +
214   -// "#{item.latitudeGcj02},#{item.longitudeWgs84}, #{item.latitudeWgs84}, #{item.hasAudio}, now(), now(), " +
215   -// "#{item.businessGroupId}, #{item.gpsTime}) " +
216   -// "</foreach> " +
217   -// "ON DUPLICATE KEY UPDATE " +
218   -// "updateTime=VALUES(updateTime), " +
219   -// "name=VALUES(name), " +
220   -// "manufacture=VALUES(manufacture), " +
221   -// "model=VALUES(model), " +
222   -// "owner=VALUES(owner), " +
223   -// "civilCode=VALUES(civilCode), " +
224   -// "block=VALUES(block), " +
225   -// "subCount=VALUES(subCount), " +
226   -// "address=VALUES(address), " +
227   -// "parental=VALUES(parental), " +
228   -// "parentId=VALUES(parentId), " +
229   -// "safetyWay=VALUES(safetyWay), " +
230   -// "registerWay=VALUES(registerWay), " +
231   -// "certNum=VALUES(certNum), " +
232   -// "certifiable=VALUES(certifiable), " +
233   -// "errCode=VALUES(errCode), " +
234   -// "secrecy=VALUES(secrecy), " +
235   -// "ipAddress=VALUES(ipAddress), " +
236   -// "port=VALUES(port), " +
237   -// "password=VALUES(password), " +
238   -// "PTZType=VALUES(PTZType), " +
239   -// "status=VALUES(status), " +
240   -// "streamId=VALUES(streamId), " +
241   -// "longitude=VALUES(longitude), " +
242   -// "latitude=VALUES(latitude), " +
243   -// "longitudeGcj02=VALUES(longitudeGcj02), " +
244   -// "latitudeGcj02=VALUES(latitudeGcj02), " +
245   -// "longitudeWgs84=VALUES(longitudeWgs84), " +
246   -// "latitudeWgs84=VALUES(latitudeWgs84), " +
247   -// "hasAudio=VALUES(hasAudio), " +
248   -// "businessGroupId=VALUES(businessGroupId), " +
249   -// "gpsTime=VALUES(gpsTime)" +
250   -// "</script>")
251   -// int batchAdd(List<DeviceChannel> addChannels);
252   -
253   -
254 199 @Insert("<script> " +
255   - "insert into device_channel " +
256   - "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
257   - " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
258   - " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
259   - " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
  200 + "insert into wvp_device_channel " +
  201 + "(channel_id, device_id, name, manufacture, model, owner, civil_code, block, sub_count, " +
  202 + " address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, secrecy, " +
  203 + " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+
  204 + " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+
260 205 "values " +
261 206 "<foreach collection='addChannels' index='index' item='item' separator=','> " +
262 207 "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
... ... @@ -273,11 +218,11 @@ public interface DeviceChannelMapper {
273 218  
274 219  
275 220 @Insert("<script> " +
276   - "insert into device_channel " +
277   - "(channelId, deviceId, name, manufacture, model, owner, civilCode, block, subCount, " +
278   - " address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
279   - " ipAddress, port, password, PTZType, status, streamId, longitude, latitude, longitudeGcj02, latitudeGcj02, " +
280   - " longitudeWgs84, latitudeWgs84, hasAudio, createTime, updateTime, businessGroupId, gpsTime) " +
  221 + "insert into wvp_device_channel " +
  222 + "(channel_id,device_id,name,manufacture,model,owner,civil_code,block,sub_count,"+
  223 + " address,parental,parent_id,safety_way,register_way,cert_num,certifiable,err_code,secrecy,"+
  224 + " ip_address,port,password,ptz_type,status,stream_id,longitude,latitude,longitude_gcj02,latitude_gcj02,"+
  225 + " longitude_wgs84,latitude_wgs84,has_audio,create_time,update_time,business_group_id,gps_time)"+
281 226 "values " +
282 227 "<foreach collection='addChannels' index='index' item='item' separator=','> " +
283 228 "(#{item.channelId}, #{item.deviceId}, #{item.name}, #{item.manufacture}, #{item.model}, " +
... ... @@ -290,215 +235,234 @@ public interface DeviceChannelMapper {
290 235 "#{item.businessGroupId}, #{item.gpsTime}) " +
291 236 "</foreach> " +
292 237 "ON DUPLICATE KEY UPDATE " +
293   - "updateTime=VALUES(updateTime), " +
  238 + "update_time=VALUES(update_time), " +
294 239 "name=VALUES(name), " +
295 240 "manufacture=VALUES(manufacture), " +
296 241 "model=VALUES(model), " +
297 242 "owner=VALUES(owner), " +
298   - "civilCode=VALUES(civilCode), " +
  243 + "civil_code=VALUES(civil_code), " +
299 244 "block=VALUES(block), " +
300   - "subCount=VALUES(subCount), " +
  245 + "sub_count=VALUES(sub_count), " +
301 246 "address=VALUES(address), " +
302 247 "parental=VALUES(parental), " +
303   - "parentId=VALUES(parentId), " +
304   - "safetyWay=VALUES(safetyWay), " +
305   - "registerWay=VALUES(registerWay), " +
306   - "certNum=VALUES(certNum), " +
  248 + "parent_id=VALUES(parent_id), " +
  249 + "safety_way=VALUES(safety_way), " +
  250 + "register_way=VALUES(register_way), " +
  251 + "cert_num=VALUES(cert_num), " +
307 252 "certifiable=VALUES(certifiable), " +
308   - "errCode=VALUES(errCode), " +
  253 + "err_code=VALUES(err_code), " +
309 254 "secrecy=VALUES(secrecy), " +
310   - "ipAddress=VALUES(ipAddress), " +
  255 + "ip_address=VALUES(ip_address), " +
311 256 "port=VALUES(port), " +
312 257 "password=VALUES(password), " +
313   - "PTZType=VALUES(PTZType), " +
  258 + "ptz_type=VALUES(ptz_type), " +
314 259 "status=VALUES(status), " +
315   - "streamId=VALUES(streamId), " +
  260 + "stream_id=VALUES(stream_id), " +
316 261 "longitude=VALUES(longitude), " +
317 262 "latitude=VALUES(latitude), " +
318   - "longitudeGcj02=VALUES(longitudeGcj02), " +
319   - "latitudeGcj02=VALUES(latitudeGcj02), " +
320   - "longitudeWgs84=VALUES(longitudeWgs84), " +
321   - "latitudeWgs84=VALUES(latitudeWgs84), " +
322   - "hasAudio=VALUES(hasAudio), " +
323   - "businessGroupId=VALUES(businessGroupId), " +
324   - "gpsTime=VALUES(gpsTime)" +
  263 + "longitude_gcj02=VALUES(longitude_gcj02), " +
  264 + "latitude_gcj02=VALUES(latitude_gcj02), " +
  265 + "longitude_wgs84=VALUES(longitude_wgs84), " +
  266 + "latitude_wgs84=VALUES(latitude_wgs84), " +
  267 + "has_audio=VALUES(has_audio), " +
  268 + "business_group_id=VALUES(business_group_id), " +
  269 + "gps_time=VALUES(gps_time)" +
325 270 "</script>")
326 271 int batchAddOrUpdate(List<DeviceChannel> addChannels);
327 272  
328   - @Update(value = {"UPDATE device_channel SET status=1 WHERE deviceId=#{deviceId} AND channelId=#{channelId}"})
  273 + @Update(value = {"UPDATE wvp_device_channel SET status=true WHERE device_id=#{deviceId} AND channel_id=#{channelId}"})
329 274 void online(String deviceId, String channelId);
330 275  
331 276 @Update({"<script>" +
332 277 "<foreach collection='updateChannels' item='item' separator=';'>" +
333 278 " UPDATE" +
334   - " device_channel" +
335   - " SET updateTime=#{item.updateTime}" +
  279 + " wvp_device_channel" +
  280 + " SET update_time=#{item.updateTime}" +
336 281 "<if test='item.name != null'>, name=#{item.name}</if>" +
337 282 "<if test='item.manufacture != null'>, manufacture=#{item.manufacture}</if>" +
338 283 "<if test='item.model != null'>, model=#{item.model}</if>" +
339 284 "<if test='item.owner != null'>, owner=#{item.owner}</if>" +
340   - "<if test='item.civilCode != null'>, civilCode=#{item.civilCode}</if>" +
  285 + "<if test='item.civilCode != null'>, civil_code=#{item.civilCode}</if>" +
341 286 "<if test='item.block != null'>, block=#{item.block}</if>" +
342   - "<if test='item.subCount != null'>, subCount=#{item.subCount}</if>" +
  287 + "<if test='item.subCount != null'>, sub_count=#{item.subCount}</if>" +
343 288 "<if test='item.address != null'>, address=#{item.address}</if>" +
344 289 "<if test='item.parental != null'>, parental=#{item.parental}</if>" +
345   - "<if test='item.parentId != null'>, parentId=#{item.parentId}</if>" +
346   - "<if test='item.safetyWay != null'>, safetyWay=#{item.safetyWay}</if>" +
347   - "<if test='item.registerWay != null'>, registerWay=#{item.registerWay}</if>" +
348   - "<if test='item.certNum != null'>, certNum=#{item.certNum}</if>" +
  290 + "<if test='item.parentId != null'>, parent_id=#{item.parentId}</if>" +
  291 + "<if test='item.safetyWay != null'>, safety_way=#{item.safetyWay}</if>" +
  292 + "<if test='item.registerWay != null'>, register_way=#{item.registerWay}</if>" +
  293 + "<if test='item.certNum != null'>, cert_num=#{item.certNum}</if>" +
349 294 "<if test='item.certifiable != null'>, certifiable=#{item.certifiable}</if>" +
350   - "<if test='item.errCode != null'>, errCode=#{item.errCode}</if>" +
  295 + "<if test='item.errCode != null'>, err_code=#{item.errCode}</if>" +
351 296 "<if test='item.secrecy != null'>, secrecy=#{item.secrecy}</if>" +
352   - "<if test='item.ipAddress != null'>, ipAddress=#{item.ipAddress}</if>" +
  297 + "<if test='item.ipAddress != null'>, ip_address=#{item.ipAddress}</if>" +
353 298 "<if test='item.port != null'>, port=#{item.port}</if>" +
354 299 "<if test='item.password != null'>, password=#{item.password}</if>" +
355   - "<if test='item.PTZType != null'>, PTZType=#{item.PTZType}</if>" +
  300 + "<if test='item.PTZType != null'>, ptz_type=#{item.PTZType}</if>" +
356 301 "<if test='item.status != null'>, status=#{item.status}</if>" +
357   - "<if test='item.streamId != null'>, streamId=#{item.streamId}</if>" +
358   - "<if test='item.hasAudio != null'>, hasAudio=#{item.hasAudio}</if>" +
  302 + "<if test='item.streamId != null'>, stream_id=#{item.streamId}</if>" +
  303 + "<if test='item.hasAudio != null'>, has_audio=#{item.hasAudio}</if>" +
359 304 "<if test='item.longitude != null'>, longitude=#{item.longitude}</if>" +
360 305 "<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
361   - "<if test='item.longitudeGcj02 != null'>, longitudeGcj02=#{item.longitudeGcj02}</if>" +
362   - "<if test='item.latitudeGcj02 != null'>, latitudeGcj02=#{item.latitudeGcj02}</if>" +
363   - "<if test='item.longitudeWgs84 != null'>, longitudeWgs84=#{item.longitudeWgs84}</if>" +
364   - "<if test='item.latitudeWgs84 != null'>, latitudeWgs84=#{item.latitudeWgs84}</if>" +
365   - "<if test='item.businessGroupId != null'>, businessGroupId=#{item.businessGroupId}</if>" +
366   - "<if test='item.gpsTime != null'>, gpsTime=#{item.gpsTime}</if>" +
  306 + "<if test='item.longitudeGcj02 != null'>, longitude_gcj02=#{item.longitudeGcj02}</if>" +
  307 + "<if test='item.latitudeGcj02 != null'>, latitude_gcj02=#{item.latitudeGcj02}</if>" +
  308 + "<if test='item.longitudeWgs84 != null'>, longitude_wgs84=#{item.longitudeWgs84}</if>" +
  309 + "<if test='item.latitudeWgs84 != null'>, latitude_wgs84=#{item.latitudeWgs84}</if>" +
  310 + "<if test='item.businessGroupId != null'>, business_group_id=#{item.businessGroupId}</if>" +
  311 + "<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" +
367 312 "<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
368   - "<if test='item.id == 0'>WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}</if>" +
  313 + "<if test='item.id == 0'>WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}</if>" +
369 314 "</foreach>" +
370 315 "</script>"})
371 316 int batchUpdate(List<DeviceChannel> updateChannels);
372 317  
373 318  
374   - @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
  319 + @Select("SELECT * FROM wvp_device_channel WHERE device_id=#{deviceId} AND status=true")
375 320 List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
376 321  
377 322 @Delete(value = {" <script>" +
378 323 "DELETE " +
379 324 "from " +
380   - "device_channel " +
  325 + "wvp_device_channel " +
381 326 "WHERE " +
382   - "deviceId = #{deviceId} " +
383   - " AND channelId NOT IN " +
  327 + "device_id = #{deviceId} " +
  328 + " AND channel_id NOT IN " +
384 329 "<foreach collection='channels' item='item' open='(' separator=',' close=')' > #{item.channelId}</foreach>" +
385 330 " </script>"})
386 331 int cleanChannelsNotInList(String deviceId, List<DeviceChannel> channels);
387 332  
388   - @Update(" update device_channel" +
389   - " set subCount = (select *" +
  333 + @Update(" update wvp_device_channel" +
  334 + " set sub_count = (select *" +
390 335 " from (select count(0)" +
391   - " from device_channel" +
392   - " where deviceId = #{deviceId} and parentId = #{channelId}) as temp)" +
393   - " where deviceId = #{deviceId} " +
394   - " and channelId = #{channelId}")
  336 + " from wvp_device_channel" +
  337 + " where device_id = #{deviceId} and parent_id = #{channelId}) as temp)" +
  338 + " where device_id = #{deviceId} " +
  339 + " and channel_id = #{channelId}")
395 340 int updateChannelSubCount(String deviceId, String channelId);
396 341  
397 342 @Update(value = {" <script>" +
398   - "UPDATE device_channel " +
  343 + "UPDATE wvp_device_channel " +
399 344 "SET " +
400 345 "latitude=#{latitude}, " +
401 346 "longitude=#{longitude}, " +
402   - "longitudeGcj02=#{longitudeGcj02}, " +
403   - "latitudeGcj02=#{latitudeGcj02}, " +
404   - "longitudeWgs84=#{longitudeWgs84}, " +
405   - "latitudeWgs84=#{latitudeWgs84}, " +
406   - "gpsTime=#{gpsTime} " +
407   - "WHERE deviceId=#{deviceId} " +
408   - " <if test='channelId != null' > AND channelId=#{channelId}</if>" +
  347 + "longitude_gcj02=#{longitudeGcj02}, " +
  348 + "latitude_gcj02=#{latitudeGcj02}, " +
  349 + "longitude_wgs84=#{longitudeWgs84}, " +
  350 + "latitude_wgs84=#{latitudeWgs84}, " +
  351 + "gps_time=#{gpsTime} " +
  352 + "WHERE device_id=#{deviceId} " +
  353 + " <if test='channelId != null' > AND channel_id=#{channelId}</if>" +
409 354 " </script>"})
410 355 void updatePosition(DeviceChannel deviceChannel);
411 356  
412   - @Select("SELECT * FROM device_channel WHERE length(trim(streamId)) > 0")
  357 + @Select("SELECT * FROM wvp_device_channel WHERE length(trim(stream_id)) > 0")
413 358 List<DeviceChannel> getAllChannelInPlay();
414 359  
415   - @Select("select * from device_channel where longitude*latitude > 0 and deviceId = #{deviceId}")
  360 + @Select("select * from wvp_device_channel where longitude*latitude > 0 and device_id = #{deviceId}")
416 361 List<DeviceChannel> getAllChannelWithCoordinate(String deviceId);
417 362  
418 363  
419 364 @Select(value = {" <script>" +
420 365 "select * " +
421   - "from device_channel " +
422   - "where deviceId=#{deviceId}" +
423   - " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} and length(channelId)=#{length} </if>" +
424   - " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=#{length} </if>" +
425   - " <if test='parentId == null and length == null' > and parentId = #{parentId} </if>" +
426   - " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} </if>" +
  366 + "from wvp_device_channel " +
  367 + "where device_id=#{deviceId}" +
  368 + " <if test='parentId != null and length != null' > and parent_id= #{parentId} or left(channel_id, LENGTH(#{parentId})) = #{parentId} and length(channel_id)=#{length} </if>" +
  369 + " <if test='parentId == null and length != null' > and parent_id= #{parentId} or length(channel_id)=#{length} </if>" +
  370 + " <if test='parentId == null and length == null' > and parent_id= #{parentId} </if>" +
  371 + " <if test='parentId != null and length == null' > and parent_id= #{parentId} or left(channel_id, LENGTH(#{parentId})) = #{parentId} </if>" +
427 372 " </script>"})
428 373 List<DeviceChannel> getChannelsWithCivilCodeAndLength(String deviceId, String parentId, Integer length);
429 374  
430 375 @Select(value = {" <script>" +
431 376 "select * " +
432   - "from device_channel " +
433   - "where deviceId=#{deviceId} and length(channelId)>14 and civilCode=#{parentId}" +
  377 + "from wvp_device_channel " +
  378 + "where device_id=#{deviceId} and length(channel_id)>14 and civil_code=#{parentId}" +
434 379 " </script>"})
435 380 List<DeviceChannel> getChannelsByCivilCode(String deviceId, String parentId);
436 381  
437   - @Select("select min(length(channelId)) as minLength " +
438   - "from device_channel " +
439   - "where deviceId=#{deviceId}")
  382 + @Select("select min(length(channel_id)) as minLength " +
  383 + "from wvp_device_channel " +
  384 + "where device_id=#{deviceId}")
440 385 Integer getChannelMinLength(String deviceId);
441 386  
442   - @Select("select * from device_channel where deviceId=#{deviceId} and civilCode not in " +
443   - "(select civilCode from device_channel where deviceId=#{deviceId} group by civilCode)")
444   - List<DeviceChannel> getChannelWithoutCiviCode(String deviceId);
  387 + @Select("select * from wvp_device_channel where device_id=#{deviceId} and civil_code not in " +
  388 + "(select civil_code from wvp_device_channel where device_id=#{deviceId} group by civil_code)")
  389 + List<DeviceChannel> getChannelWithoutCivilCode(String deviceId);
445 390  
446   - @Select("select * from device_channel where deviceId=#{deviceId} and SUBSTRING(channelId, 11, 3)=#{typeCode}")
  391 + @Select("select * from wvp_device_channel where device_id=#{deviceId} and SUBSTRING(channel_id, 11, 3)=#{typeCode}")
447 392 List<DeviceChannel> getBusinessGroups(String deviceId, String typeCode);
448 393  
449   - @Select("select dc.id, dc.channelId, dc.deviceId, dc.name, dc.manufacture,dc.model,dc.owner, pc.civilCode,dc.block, " +
450   - " dc.address, '0' as parental,'0' as channelType, pc.id as parentId, dc.safetyWay, dc.registerWay,dc.certNum, dc.certifiable, " +
451   - " dc.errCode,dc.endTime, dc.secrecy, dc.ipAddress, dc.port, dc.PTZType, dc.password, dc.status, " +
452   - " dc.longitudeWgs84 as longitude, dc.latitudeWgs84 as latitude, pc.businessGroupId " +
453   - " from device_channel dc" +
454   - " left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId" +
455   - " left join platform_catalog pc on pgc.catalogId = pc.id and pgc.platformId = pc.platformId" +
456   - " where pgc.platformId=#{serverGBId}")
  394 + @Select("select dc.id, dc.channel_id, dc.device_id, dc.name, dc.manufacture,dc.model,dc.owner, pc.civil_code,dc.block, " +
  395 + " dc.address, '0' as parental,'0' as channel_type, pc.id as parent_id, dc.safety_way, dc.register_way,dc.cert_num, dc.certifiable, " +
  396 + " dc.err_code,dc.end_time, dc.secrecy, dc.ip_address, dc.port, dc.ptz_type, dc.password, dc.status, " +
  397 + " dc.longitude_wgs84 as longitude, dc.latitude_wgs84 as latitude, pc.business_group_id " +
  398 + " from wvp_device_channel dc" +
  399 + " LEFT JOIN wvp_platform_gb_channel pgc on dc.id = pgc.device_channel_id" +
  400 + " LEFT JOIN wvp_platform_catalog pc on pgc.catalog_id = pc.id and pgc.platform_id = pc.platform_id" +
  401 + " where pgc.platform_id=#{serverGBId}")
457 402 List<DeviceChannel> queryChannelWithCatalog(String serverGBId);
458 403  
459   - @Select("select * from device_channel where deviceId = #{deviceId}")
  404 + @Select("select * from wvp_device_channel where device_id = #{deviceId}")
460 405 List<DeviceChannel> queryAllChannels(String deviceId);
461 406  
462 407  
463   - @Select("select count(1) as total, sum(status) as online from device_channel")
464   - ResourceBaceInfo getOverview();
465   -
466 408 @Select("select channelId" +
467   - ", deviceId" +
  409 + ", device_id" +
468 410 ", latitude" +
469   - ", longitude" +
470   - ", latitudeWgs84" +
471   - ", longitudeWgs84" +
472   - ", latitudeGcj02" +
473   - ", longitudeGcj02 " +
474   - "from device_channel where deviceId = #{deviceId} " +
  411 + ", longitude"+
  412 + ",latitude_wgs84"+
  413 + ",longitude_wgs84"+
  414 + ",latitude_gcj02"+
  415 + ",longitude_gcj02"+
  416 + "from wvp_device_channel where device_id = #{deviceId} " +
475 417 "and latitude != 0 " +
476 418 "and longitude != 0 " +
477   - "and (latitudeGcj02 = 0 or latitudeWgs84 = 0 or longitudeWgs84 = 0 or longitudeGcj02 = 0)")
  419 + "and(latitude_gcj02=0 or latitude_wgs84=0 or longitude_wgs84= 0 or longitude_gcj02 = 0)")
478 420 List<DeviceChannel> getChannelsWithoutTransform(String deviceId);
479 421  
480   - @Select("select de.* from device de left join device_channel dc on de.deviceId = dc.deviceId where dc.channelId=#{channelId}")
  422 + @Select("select de.* from wvp_device de left join wvp_device_channel dc on de.device_id = dc.deviceId where dc.channel_id=#{channelId}")
481 423 List<Device> getDeviceByChannelId(String channelId);
482 424  
483 425  
484 426 @Delete({"<script>" +
485 427 "<foreach collection='deleteChannelList' item='item' separator=';'>" +
486   - "DELETE FROM device_channel WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  428 + "DELETE FROM wvp_device_channel WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" +
487 429 "</foreach>" +
488 430 "</script>"})
489 431 int batchDel(List<DeviceChannel> deleteChannelList);
490 432  
491 433 @Update({"<script>" +
492 434 "<foreach collection='channels' item='item' separator=';'>" +
493   - "UPDATE device_channel SET status=1 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  435 + "UPDATE wvp_device_channel SET status=true WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" +
494 436 "</foreach>" +
495 437 "</script>"})
496 438 int batchOnline(List<DeviceChannel> channels);
497 439  
498 440 @Update({"<script>" +
499 441 "<foreach collection='channels' item='item' separator=';'>" +
500   - "UPDATE device_channel SET status=0 WHERE deviceId=#{item.deviceId} AND channelId=#{item.channelId}" +
  442 + "UPDATE wvp_device_channel SET status= false WHERE device_id=#{item.deviceId} AND channel_id=#{item.channelId}" +
501 443 "</foreach>" +
502 444 "</script>"})
503 445 int batchOffline(List<DeviceChannel> channels);
  446 +
  447 +
  448 + @Select("select count(1) from wvp_device_channel where status = true")
  449 + int getOnlineCount();
  450 +
  451 + @Select("select count(1) from wvp_device_channel")
  452 + int getAllChannelCount();
  453 +
  454 + // 设备主子码流逻辑START
  455 + @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE device_id=#{deviceId}"})
  456 + void clearPlay(String deviceId);
  457 + // 设备主子码流逻辑END
  458 + @Select(value = {" <script>" +
  459 + "select * " +
  460 + "from wvp_device_channel " +
  461 + "where device_id=#{deviceId}" +
  462 + " <if test='parentId != null '> and parent_id = #{parentId} </if>" +
  463 + " <if test='parentId == null '> and parent_id is null </if>" +
  464 + " <if test='onlyCatalog == true '> and parental = 1 </if>" +
  465 + " </script>"})
  466 + List<DeviceChannel> getSubChannelsByDeviceId(String deviceId, String parentId, boolean onlyCatalog);
  467 +
504 468 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
1 1 package com.genersoft.iot.vmp.storager.dao;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
5 4 import org.apache.ibatis.annotations.*;
6 5 import org.springframework.stereotype.Repository;
7 6  
... ... @@ -15,68 +14,67 @@ import java.util.List;
15 14 public interface DeviceMapper {
16 15  
17 16 @Select("SELECT " +
18   - "deviceId, " +
  17 + "device_id, " +
19 18 "coalesce(custom_name, name) as name, " +
20 19 "password, " +
21 20 "manufacturer, " +
22 21 "model, " +
23 22 "firmware, " +
24 23 "transport," +
25   - "streamMode," +
  24 + "stream_mode," +
26 25 "ip," +
27   - "sdpIp," +
28   - "localIp," +
  26 + "sdp_ip," +
  27 + "local_ip," +
29 28 "port," +
30   - "hostAddress," +
  29 + "host_address," +
31 30 "expires," +
32   - "registerTime," +
33   - "keepaliveTime," +
34   - "createTime," +
35   - "updateTime," +
  31 + "register_time," +
  32 + "keepalive_time," +
  33 + "create_time," +
  34 + "update_time," +
36 35 "charset," +
37   - "subscribeCycleForCatalog," +
38   - "subscribeCycleForMobilePosition," +
39   - "mobilePositionSubmissionInterval," +
40   - "subscribeCycleForAlarm," +
41   - "ssrcCheck," +
42   - "asMessageChannel," +
43   - "geoCoordSys," +
44   - "treeType," +
45   - "online," +
46   - "mediaServerId," +
47   - "(SELECT count(0) FROM device_channel WHERE deviceId=device.deviceId) as channelCount "+
48   - " FROM device WHERE deviceId = #{deviceId}")
  36 + "subscribe_cycle_for_catalog," +
  37 + "subscribe_cycle_for_mobile_position," +
  38 + "mobile_position_submission_interval," +
  39 + "subscribe_cycle_for_alarm," +
  40 + "ssrc_check," +
  41 + "as_message_channel," +
  42 + "geo_coord_sys," +
  43 + "on_line," +
  44 + "media_server_id," +
  45 + "switch_primary_sub_stream," +
  46 + "(SELECT count(0) FROM wvp_device_channel WHERE device_id=wvp_device.device_id) as channel_count "+
  47 + " FROM wvp_device WHERE device_id = #{deviceId}")
49 48 Device getDeviceByDeviceId(String deviceId);
50 49  
51   - @Insert("INSERT INTO device (" +
52   - "deviceId, " +
  50 + @Insert("INSERT INTO wvp_device (" +
  51 + "device_id, " +
53 52 "name, " +
54 53 "manufacturer, " +
55 54 "model, " +
56 55 "firmware, " +
57 56 "transport," +
58   - "streamMode," +
  57 + "stream_mode," +
59 58 "ip," +
60   - "sdpIp," +
61   - "localIp," +
  59 + "sdp_ip," +
  60 + "local_ip," +
62 61 "port," +
63   - "hostAddress," +
  62 + "host_address," +
64 63 "expires," +
65   - "registerTime," +
66   - "keepaliveTime," +
67   - "keepaliveIntervalTime," +
68   - "createTime," +
69   - "updateTime," +
  64 + "register_time," +
  65 + "keepalive_time," +
  66 + "keepalive_interval_time," +
  67 + "create_time," +
  68 + "update_time," +
70 69 "charset," +
71   - "subscribeCycleForCatalog," +
72   - "subscribeCycleForMobilePosition," +
73   - "mobilePositionSubmissionInterval," +
74   - "subscribeCycleForAlarm," +
75   - "ssrcCheck," +
76   - "asMessageChannel," +
77   - "geoCoordSys," +
78   - "treeType," +
79   - "online" +
  70 + "subscribe_cycle_for_catalog," +
  71 + "subscribe_cycle_for_mobile_position,"+
  72 + "mobile_position_submission_interval,"+
  73 + "subscribe_cycle_for_alarm,"+
  74 + "ssrc_check,"+
  75 + "as_message_channel,"+
  76 + "geo_coord_sys,"+
  77 + "on_line"+
80 78 ") VALUES (" +
81 79 "#{deviceId}," +
82 80 "#{name}," +
... ... @@ -104,173 +102,172 @@ public interface DeviceMapper {
104 102 "#{ssrcCheck}," +
105 103 "#{asMessageChannel}," +
106 104 "#{geoCoordSys}," +
107   - "#{treeType}," +
108   - "#{online}" +
  105 + "#{onLine}" +
109 106 ")")
110 107 int add(Device device);
111 108  
112 109 @Update(value = {" <script>" +
113   - "UPDATE device " +
114   - "SET updateTime=#{updateTime}" +
  110 + "UPDATE wvp_device " +
  111 + "SET update_time=#{updateTime}" +
115 112 "<if test=\"name != null\">, name=#{name}</if>" +
116 113 "<if test=\"manufacturer != null\">, manufacturer=#{manufacturer}</if>" +
117 114 "<if test=\"model != null\">, model=#{model}</if>" +
118 115 "<if test=\"firmware != null\">, firmware=#{firmware}</if>" +
119 116 "<if test=\"transport != null\">, transport=#{transport}</if>" +
120 117 "<if test=\"ip != null\">, ip=#{ip}</if>" +
121   - "<if test=\"localIp != null\">, localIp=#{localIp}</if>" +
  118 + "<if test=\"localIp != null\">, local_ip=#{localIp}</if>" +
122 119 "<if test=\"port != null\">, port=#{port}</if>" +
123   - "<if test=\"hostAddress != null\">, hostAddress=#{hostAddress}</if>" +
124   - "<if test=\"online != null\">, online=#{online}</if>" +
125   - "<if test=\"registerTime != null\">, registerTime=#{registerTime}</if>" +
126   - "<if test=\"keepaliveTime != null\">, keepaliveTime=#{keepaliveTime}</if>" +
127   - "<if test=\"keepaliveIntervalTime != null\">, keepaliveIntervalTime=#{keepaliveIntervalTime}</if>" +
  120 + "<if test=\"hostAddress != null\">, host_address=#{hostAddress}</if>" +
  121 + "<if test=\"onLine != null\">, on_line=#{onLine}</if>" +
  122 + "<if test=\"registerTime != null\">, register_time=#{registerTime}</if>" +
  123 + "<if test=\"keepaliveTime != null\">, keepalive_time=#{keepaliveTime}</if>" +
  124 + "<if test=\"keepaliveIntervalTime != null\">, keepalive_interval_time=#{keepaliveIntervalTime}</if>" +
128 125 "<if test=\"expires != null\">, expires=#{expires}</if>" +
129   - "WHERE deviceId=#{deviceId}"+
  126 + "WHERE device_id=#{deviceId}"+
130 127 " </script>"})
131 128 int update(Device device);
132 129  
133 130 @Select(
134 131 " <script>" +
135 132 "SELECT " +
136   - "deviceId, " +
  133 + "device_id, " +
137 134 "coalesce(custom_name, name) as name, " +
138 135 "password, " +
139 136 "manufacturer, " +
140 137 "model, " +
141 138 "firmware, " +
142 139 "transport," +
143   - "streamMode," +
144   - "ip," +
145   - "sdpIp," +
146   - "localIp," +
147   - "port," +
148   - "hostAddress," +
149   - "expires," +
150   - "registerTime," +
151   - "keepaliveTime," +
152   - "createTime," +
153   - "updateTime," +
154   - "charset," +
155   - "subscribeCycleForCatalog," +
156   - "subscribeCycleForMobilePosition," +
157   - "mobilePositionSubmissionInterval," +
158   - "subscribeCycleForAlarm," +
159   - "ssrcCheck," +
160   - "asMessageChannel," +
161   - "geoCoordSys," +
162   - "treeType," +
163   - "online," +
164   - "mediaServerId," +
165   - "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de" +
166   - "<if test=\"online != null\"> where online=${online}</if>"+
  140 + "stream_mode," +
  141 + "ip,"+
  142 + "sdp_ip,"+
  143 + "local_ip,"+
  144 + "port,"+
  145 + "host_address,"+
  146 + "expires,"+
  147 + "register_time,"+
  148 + "keepalive_time,"+
  149 + "create_time,"+
  150 + "update_time,"+
  151 + "charset,"+
  152 + "subscribe_cycle_for_catalog,"+
  153 + "subscribe_cycle_for_mobile_position,"+
  154 + "mobile_position_submission_interval,"+
  155 + "subscribe_cycle_for_alarm,"+
  156 + "ssrc_check,"+
  157 + "as_message_channel,"+
  158 + "geo_coord_sys,"+
  159 + "on_line,"+
  160 + "media_server_id,"+
  161 + "switch_primary_sub_stream switchPrimarySubStream,"+
  162 + "(SELECT count(0) FROM wvp_device_channel WHERE device_id=de.device_id) as channel_count " +
  163 + "FROM wvp_device de" +
  164 + "<if test=\"onLine != null\"> where on_line=${onLine}</if>"+
  165 + " order by create_time desc "+
167 166 " </script>"
168 167 )
169   - List<Device> getDevices(Boolean online);
  168 + List<Device> getDevices(Boolean onLine);
170 169  
171   - @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
  170 + @Delete("DELETE FROM wvp_device WHERE device_id=#{deviceId}")
172 171 int del(String deviceId);
173 172  
174 173 @Select("SELECT " +
175   - "deviceId, " +
  174 + "device_id, " +
176 175 "coalesce(custom_name, name) as name, " +
177 176 "password, " +
178 177 "manufacturer, " +
179 178 "model, " +
180 179 "firmware, " +
181 180 "transport," +
182   - "streamMode," +
  181 + "stream_mode," +
183 182 "ip," +
184   - "sdpIp," +
185   - "localIp," +
186   - "port," +
187   - "hostAddress," +
188   - "expires," +
189   - "registerTime," +
190   - "keepaliveTime," +
191   - "createTime," +
192   - "updateTime," +
193   - "charset," +
194   - "subscribeCycleForCatalog," +
195   - "subscribeCycleForMobilePosition," +
196   - "mobilePositionSubmissionInterval," +
197   - "subscribeCycleForAlarm," +
198   - "ssrcCheck," +
199   - "asMessageChannel," +
200   - "geoCoordSys," +
201   - "treeType," +
202   - "online " +
203   - " FROM device WHERE online = 1")
  183 + "sdp_ip,"+
  184 + "local_ip,"+
  185 + "port,"+
  186 + "host_address,"+
  187 + "expires,"+
  188 + "register_time,"+
  189 + "keepalive_time,"+
  190 + "create_time,"+
  191 + "update_time,"+
  192 + "charset,"+
  193 + "subscribe_cycle_for_catalog,"+
  194 + "subscribe_cycle_for_mobile_position,"+
  195 + "mobile_position_submission_interval,"+
  196 + "subscribe_cycle_for_alarm,"+
  197 + "ssrc_check,"+
  198 + "as_message_channel,"+
  199 + "geo_coord_sys,"+
  200 + "on_line"+
  201 + " FROM wvp_device WHERE on_line = true")
204 202 List<Device> getOnlineDevices();
205 203 @Select("SELECT " +
206   - "deviceId, " +
207   - "coalesce(custom_name, name) as name, " +
208   - "password, " +
209   - "manufacturer, " +
210   - "model, " +
211   - "firmware, " +
212   - "transport," +
213   - "streamMode," +
214   - "ip," +
215   - "sdpIp," +
216   - "localIp," +
217   - "port," +
218   - "hostAddress," +
219   - "expires," +
220   - "registerTime," +
221   - "keepaliveTime," +
222   - "createTime," +
223   - "updateTime," +
224   - "charset," +
225   - "subscribeCycleForCatalog," +
226   - "subscribeCycleForMobilePosition," +
227   - "mobilePositionSubmissionInterval," +
228   - "subscribeCycleForAlarm," +
229   - "ssrcCheck," +
230   - "asMessageChannel," +
231   - "geoCoordSys," +
232   - "treeType," +
233   - "online" +
234   - " FROM device WHERE ip = #{host} AND port=#{port}")
  204 + "device_id,"+
  205 + "coalesce(custom_name,name)as name,"+
  206 + "password,"+
  207 + "manufacturer,"+
  208 + "model,"+
  209 + "firmware,"+
  210 + "transport,"+
  211 + "stream_mode,"+
  212 + "ip,"+
  213 + "sdp_ip,"+
  214 + "local_ip,"+
  215 + "port,"+
  216 + "host_address,"+
  217 + "expires,"+
  218 + "register_time,"+
  219 + "keepalive_time,"+
  220 + "create_time,"+
  221 + "update_time,"+
  222 + "charset,"+
  223 + "subscribe_cycle_for_catalog,"+
  224 + "subscribe_cycle_for_mobile_position,"+
  225 + "mobile_position_submission_interval,"+
  226 + "subscribe_cycle_for_alarm,"+
  227 + "ssrc_check,"+
  228 + "as_message_channel,"+
  229 + "geo_coord_sys,"+
  230 + "on_line"+
  231 + " FROM wvp_device WHERE ip = #{host} AND port=#{port}")
235 232 Device getDeviceByHostAndPort(String host, int port);
236 233  
237 234 @Update(value = {" <script>" +
238   - "UPDATE device " +
239   - "SET updateTime=#{updateTime}" +
  235 + "UPDATE wvp_device " +
  236 + "SET update_time=#{updateTime}" +
240 237 "<if test=\"name != null\">, custom_name=#{name}</if>" +
241 238 "<if test=\"password != null\">, password=#{password}</if>" +
242   - "<if test=\"streamMode != null\">, streamMode=#{streamMode}</if>" +
  239 + "<if test=\"streamMode != null\">, stream_mode=#{streamMode}</if>" +
243 240 "<if test=\"ip != null\">, ip=#{ip}</if>" +
244   - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
  241 + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" +
245 242 "<if test=\"port != null\">, port=#{port}</if>" +
246 243 "<if test=\"charset != null\">, charset=#{charset}</if>" +
247   - "<if test=\"subscribeCycleForCatalog != null\">, subscribeCycleForCatalog=#{subscribeCycleForCatalog}</if>" +
248   - "<if test=\"subscribeCycleForMobilePosition != null\">, subscribeCycleForMobilePosition=#{subscribeCycleForMobilePosition}</if>" +
249   - "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=#{mobilePositionSubmissionInterval}</if>" +
250   - "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=#{subscribeCycleForAlarm}</if>" +
251   - "<if test=\"ssrcCheck != null\">, ssrcCheck=#{ssrcCheck}</if>" +
252   - "<if test=\"asMessageChannel != null\">, asMessageChannel=#{asMessageChannel}</if>" +
253   - "<if test=\"geoCoordSys != null\">, geoCoordSys=#{geoCoordSys}</if>" +
254   - "<if test=\"treeType != null\">, treeType=#{treeType}</if>" +
255   - "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" +
256   - "WHERE deviceId=#{deviceId}"+
  244 + "<if test=\"subscribeCycleForCatalog != null\">, subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}</if>" +
  245 + "<if test=\"subscribeCycleForMobilePosition != null\">, subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}</if>" +
  246 + "<if test=\"mobilePositionSubmissionInterval != null\">, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}</if>" +
  247 + "<if test=\"subscribeCycleForAlarm != null\">, subscribe_cycle_for_alarm=#{subscribeCycleForAlarm}</if>" +
  248 + "<if test=\"ssrcCheck != null\">, ssrc_check=#{ssrcCheck}</if>" +
  249 + "<if test=\"asMessageChannel != null\">, as_message_channel=#{asMessageChannel}</if>" +
  250 + "<if test=\"geoCoordSys != null\">, geo_coord_sys=#{geoCoordSys}</if>" +
  251 + "<if test=\"switchPrimarySubStream != null\">, switch_primary_sub_stream=#{switchPrimarySubStream}</if>" +
  252 + "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" +
  253 + "WHERE device_id=#{deviceId}"+
257 254 " </script>"})
258 255 void updateCustom(Device device);
259 256  
260   - @Insert("INSERT INTO device (" +
261   - "deviceId, " +
262   - "custom_name, " +
263   - "password, " +
264   - "sdpIp, " +
265   - "createTime," +
266   - "updateTime," +
267   - "charset," +
268   - "ssrcCheck," +
269   - "asMessageChannel," +
270   - "geoCoordSys," +
271   - "treeType," +
272   - "online," +
273   - "mediaServerId" +
  257 + @Insert("INSERT INTO wvp_device (" +
  258 + "device_id,"+
  259 + "custom_name,"+
  260 + "password,"+
  261 + "sdp_ip,"+
  262 + "create_time,"+
  263 + "update_time,"+
  264 + "charset,"+
  265 + "ssrc_check,"+
  266 + "as_message_channel,"+
  267 + "geo_coord_sys,"+
  268 + "on_line,"+
  269 + "media_server_id,"+
  270 + "switch_primary_sub_stream"+
274 271 ") VALUES (" +
275 272 "#{deviceId}," +
276 273 "#{name}," +
... ... @@ -282,18 +279,15 @@ public interface DeviceMapper {
282 279 "#{ssrcCheck}," +
283 280 "#{asMessageChannel}," +
284 281 "#{geoCoordSys}," +
285   - "#{treeType}," +
286   - "#{online}," +
287   - "#{mediaServerId}" +
  282 + "#{onLine}," +
  283 + "#{mediaServerId}," +
  284 + "#{switchPrimarySubStream}" +
288 285 ")")
289 286 void addCustomDevice(Device device);
290 287  
291   - @Select("select count(1) as total, sum(online) as online from device")
292   - ResourceBaceInfo getOverview();
293   -
294   - @Select("select * from device")
  288 + @Select("select * FROM wvp_device")
295 289 List<Device> getAll();
296 290  
297   - @Select("select * from device where asMessageChannel = 1")
  291 + @Select("select * FROM wvp_device where as_message_channel = true")
298 292 List<Device> queryDeviceWithAsMessageChannel();
299 293 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java
... ... @@ -11,25 +11,25 @@ import java.util.List;
11 11 @Mapper
12 12 public interface DeviceMobilePositionMapper {
13 13  
14   - @Insert("INSERT INTO device_mobile_position (deviceId,channelId, deviceName, time, longitude, latitude, altitude, speed, direction, reportSource, longitudeGcj02, latitudeGcj02, longitudeWgs84, latitudeWgs84, createTime) " +
  14 + @Insert("INSERT INTO wvp_device_mobile_position (device_id,channel_id, device_name,time,longitude,latitude,altitude,speed,direction,report_source,longitude_gcj02,latitude_gcj02,longitude_wgs84,latitude_wgs84,create_time)"+
15 15 "VALUES (#{deviceId}, #{channelId}, #{deviceName}, #{time}, #{longitude}, #{latitude}, #{altitude}, #{speed}, #{direction}, #{reportSource}, #{longitudeGcj02}, #{latitudeGcj02}, #{longitudeWgs84}, #{latitudeWgs84}, #{createTime})")
16 16 int insertNewPosition(MobilePosition mobilePosition);
17 17  
18 18 @Select(value = {" <script>" +
19   - "SELECT * FROM device_mobile_position" +
20   - " WHERE deviceId = #{deviceId}" +
21   - "<if test=\"channelId != null\"> and channelId = #{channelId}</if>" +
  19 + "SELECT * FROM wvp_device_mobile_position" +
  20 + " WHERE device_id = #{deviceId}" +
  21 + "<if test=\"channelId != null\"> and channel_id = #{channelId}</if>" +
22 22 "<if test=\"startTime != null\"> AND time&gt;=#{startTime}</if>" +
23 23 "<if test=\"endTime != null\"> AND time&lt;=#{endTime}</if>" +
24 24 " ORDER BY time ASC" +
25 25 " </script>"})
26 26 List<MobilePosition> queryPositionByDeviceIdAndTime(String deviceId, String channelId, String startTime, String endTime);
27 27  
28   - @Select("SELECT * FROM device_mobile_position WHERE deviceId = #{deviceId}" +
  28 + @Select("SELECT * FROM wvp_device_mobile_position WHERE device_id = #{deviceId}" +
29 29 " ORDER BY time DESC LIMIT 1")
30 30 MobilePosition queryLatestPositionByDevice(String deviceId);
31 31  
32   - @Delete("DELETE FROM device_mobile_position WHERE deviceId = #{deviceId}")
  32 + @Delete("DELETE FROM wvp_device_mobile_position WHERE device_id = #{deviceId}")
33 33 int clearMobilePositionsByDeviceId(String deviceId);
34 34  
35 35 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
... ... @@ -14,94 +14,94 @@ import java.util.List;
14 14 @Repository
15 15 public interface GbStreamMapper {
16 16  
17   - @Insert("REPLACE INTO gb_stream (app, stream, gbId, name, " +
18   - "longitude, latitude, streamType, mediaServerId, createTime) VALUES" +
  17 + @Insert("REPLACE INTO wvp_gb_stream (app, stream, gb_id, name, " +
  18 + "longitude, latitude, stream_type,media_server_id,create_time) VALUES" +
19 19 "(#{app}, #{stream}, #{gbId}, #{name}, " +
20 20 "#{longitude}, #{latitude}, #{streamType}, " +
21 21 "#{mediaServerId}, #{createTime})")
22 22 @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
23 23 int add(GbStream gbStream);
24 24  
25   - @Update("UPDATE gb_stream " +
  25 + @Update("UPDATE wvp_gb_stream " +
26 26 "SET app=#{app}," +
27 27 "stream=#{stream}," +
28   - "gbId=#{gbId}," +
  28 + "gb_id=#{gbId}," +
29 29 "name=#{name}," +
30   - "streamType=#{streamType}," +
  30 + "stream_type=#{streamType}," +
31 31 "longitude=#{longitude}, " +
32 32 "latitude=#{latitude}," +
33   - "mediaServerId=#{mediaServerId}" +
  33 + "media_server_id=#{mediaServerId}" +
34 34 "WHERE app=#{app} AND stream=#{stream}")
35 35 int updateByAppAndStream(GbStream gbStream);
36 36  
37   - @Update("UPDATE gb_stream " +
  37 + @Update("UPDATE wvp_gb_stream " +
38 38 "SET app=#{app}," +
39 39 "stream=#{stream}," +
40   - "gbId=#{gbId}," +
  40 + "gb_id=#{gbId}," +
41 41 "name=#{name}," +
42   - "streamType=#{streamType}," +
  42 + "stream_type=#{streamType}," +
43 43 "longitude=#{longitude}, " +
44 44 "latitude=#{latitude}," +
45   - "mediaServerId=#{mediaServerId}" +
46   - "WHERE gbStreamId=#{gbStreamId}")
  45 + "media_server_id=#{mediaServerId}" +
  46 + "WHERE gb_stream_id=#{gbStreamId}")
47 47 int update(GbStream gbStream);
48 48  
49   - @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
  49 + @Delete("DELETE FROM wvp_gb_stream WHERE app=#{app} AND stream=#{stream}")
50 50 int del(String app, String stream);
51 51  
52 52 @Select("<script> "+
53   - "SELECT gs.* FROM gb_stream gs " +
  53 + "SELECT gs.* FROM wvp_gb_stream gs " +
54 54 "WHERE " +
55 55 "1=1 " +
56   - " <if test='catalogId != null'> AND gs.gbStreamId in" +
57   - "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId} and pgs.catalogId=#{catalogId})</if> " +
58   - " <if test='catalogId == null'> AND gs.gbStreamId not in" +
59   - "(select pgs.gbStreamId from platform_gb_stream pgs where pgs.platformId = #{platformId}) </if> " +
60   - " <if test='query != null'> AND (gs.app LIKE concat('%',#{query},'%') OR gs.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
61   - " <if test='mediaServerId != null' > AND gs.mediaServerId=#{mediaServerId} </if>" +
62   - " order by gs.gbStreamId asc " +
  56 + " <if test='catalogId != null'> AND gs.gb_stream_id in" +
  57 + "(select pgs.gb_stream_id from wvp_platform_gb_stream pgs where pgs.platform_id = #{platformId} and pgs.catalog_id=#{catalogId})</if> " +
  58 + " <if test='catalogId == null'> AND gs.gb_stream_id not in" +
  59 + "(select pgs.gb_stream_id from wvp_platform_gb_stream pgs where pgs.platform_id = #{platformId}) </if> " +
  60 + " <if test='query != null'> AND (gs.app LIKE concat('%',#{query},'%') OR gs.stream LIKE concat('%',#{query},'%') OR gs.gb_id LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
  61 + " <if test='mediaServerId != null' > AND gs.media_server_id=#{mediaServerId} </if>" +
  62 + " order by gs.gb_stream_id asc " +
63 63 "</script>")
64 64 List<GbStream> selectAll(String platformId, String catalogId, String query, String mediaServerId);
65 65  
66   - @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}")
  66 + @Select("SELECT * FROM wvp_gb_stream WHERE app=#{app} AND stream=#{stream}")
67 67 GbStream selectOne(String app, String stream);
68 68  
69   - @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}")
  69 + @Select("SELECT * FROM wvp_gb_stream WHERE gb_id=#{gbId}")
70 70 List<GbStream> selectByGBId(String gbId);
71 71  
72   - @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " +
73   - "LEFT JOIN platform_gb_stream pgs ON gs.gbStreamId = pgs.gbStreamId " +
74   - "WHERE gs.gbId = #{gbId} AND pgs.platformId = #{platformId}")
  72 + @Select("SELECT gs.*, pgs.platform_id as platform_id, pgs.catalog_id as catalog_id FROM wvp_gb_stream gs " +
  73 + "LEFT JOIN wvp_platform_gb_stream pgs ON gs.gb_stream_id = pgs.gb_stream_id " +
  74 + "WHERE gs.gb_id = #{gbId} AND pgs.platform_id = #{platformId}")
75 75 GbStream queryStreamInPlatform(String platformId, String gbId);
76 76  
77 77 @Select("<script> "+
78   - "select gt.gbId as channelId, gt.name, 'wvp-pro' as manufacture, st.status, gt.longitude, gt.latitude, pc.id as parentId," +
79   - " '1' as registerWay, pc.civilCode, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" +
80   - " from gb_stream gt " +
  78 + "select gt.gb_id as channel_id, gt.name, 'wvp-pro' as manufacture, st.status, gt.longitude, gt.latitude, pc.id as parent_id," +
  79 + " '1' as register_way, pc.civil_code, 'live' as model, 'wvp-pro' as owner, '0' as parental,'0' as secrecy" +
  80 + " from wvp_gb_stream gt " +
81 81 " left join (" +
82 82 " select " +
83 83 " <if test='usPushingAsStatus != true'> sp.status as status, </if>" +
84   - " <if test='usPushingAsStatus == true'> sp.pushIng as status, </if>" +
85   - "sp.app, sp.stream from stream_push sp" +
  84 + " <if test='usPushingAsStatus == true'> sp.push_ing as status, </if>" +
  85 + "sp.app, sp.stream from wvp_stream_push sp" +
86 86 " union all" +
87   - " select spxy.status, spxy.app, spxy.stream from stream_proxy spxy" +
  87 + " select spxy.status, spxy.app, spxy.stream from wvp_stream_proxy spxy" +
88 88 " ) st on st.app = gt.app and st.stream = gt.stream" +
89   - " left join platform_gb_stream pgs on gt.gbStreamId = pgs.gbStreamId" +
90   - " left join platform_catalog pc on pgs.catalogId = pc.id and pgs.platformId = pc.platformId" +
91   - " where pgs.platformId=#{platformId}" +
  89 + " left join wvp_platform_gb_stream pgs on gt.gb_stream_id = pgs.gb_stream_id" +
  90 + " left join wvp_platform_catalog pc on pgs.catalog_id = pc.id and pgs.platform_id = pc.platform_id" +
  91 + " where pgs.platform_id=#{platformId}" +
92 92 "</script>")
93 93 List<DeviceChannel> queryGbStreamListInPlatform(String platformId, boolean usPushingAsStatus);
94 94  
95 95  
96   - @Select("SELECT gs.* FROM gb_stream gs LEFT JOIN platform_gb_stream pgs " +
97   - "ON gs.gbStreamId = pgs.gbStreamId WHERE pgs.gbStreamId is NULL")
  96 + @Select("SELECT gs.* FROM wvp_gb_stream gs left join wvp_platform_gb_stream pgs " +
  97 + "ON gs.gb_stream_id = pgs.gb_stream_id WHERE pgs.gb_stream_id is NULL")
98 98 List<GbStream> queryStreamNotInPlatform();
99 99  
100   - @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}")
  100 + @Delete("DELETE FROM wvp_gb_stream WHERE stream_type=#{type} AND gb_id=NULL AND media_server_id=#{mediaServerId}")
101 101 void deleteWithoutGBId(String type, String mediaServerId);
102 102  
103 103 @Delete("<script> "+
104   - "DELETE FROM gb_stream where " +
  104 + "DELETE FROM wvp_gb_stream where " +
105 105 "<foreach collection='streamProxyItemList' item='item' separator='or'>" +
106 106 "(app=#{item.app} and stream=#{item.stream}) " +
107 107 "</foreach>" +
... ... @@ -109,7 +109,7 @@ public interface GbStreamMapper {
109 109 void batchDel(List<StreamProxyItem> streamProxyItemList);
110 110  
111 111 @Delete("<script> "+
112   - "DELETE FROM gb_stream where " +
  112 + "DELETE FROM wvp_gb_stream where " +
113 113 "<foreach collection='gbStreams' item='item' separator='or'>" +
114 114 "(app=#{item.app} and stream=#{item.stream}) " +
115 115 "</foreach>" +
... ... @@ -117,9 +117,9 @@ public interface GbStreamMapper {
117 117 void batchDelForGbStream(List<GbStream> gbStreams);
118 118  
119 119 @Insert("<script> " +
120   - "INSERT IGNORE into gb_stream " +
121   - "(app, stream, gbId, name, " +
122   - "longitude, latitude, streamType, mediaServerId, createTime)" +
  120 + "INSERT into wvp_gb_stream " +
  121 + "(app, stream, gb_id, name, " +
  122 + "longitude, latitude, stream_type,media_server_id,create_time)" +
123 123 "values " +
124 124 "<foreach collection='subList' index='index' item='item' separator=','> " +
125 125 "(#{item.app}, #{item.stream}, #{item.gbId}, #{item.name}, " +
... ... @@ -127,46 +127,46 @@ public interface GbStreamMapper {
127 127 "#{item.mediaServerId}, #{item.createTime}) "+
128 128 "</foreach> " +
129 129 "</script>")
130   - @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gbStreamId")
  130 + @Options(useGeneratedKeys = true, keyProperty = "gbStreamId", keyColumn = "gb_stream_id")
131 131 void batchAdd(List<StreamPushItem> subList);
132 132  
133 133 @Update({"<script>" +
134 134 "<foreach collection='gpsMsgInfos' item='item' separator=';'>" +
135 135 " UPDATE" +
136   - " gb_stream" +
  136 + " wvp_gb_stream" +
137 137 " SET longitude=#{item.lng}, latitude=#{item.lat} " +
138   - "WHERE gbId=#{item.id}"+
  138 + "WHERE gb_id=#{item.id}"+
139 139 "</foreach>" +
140 140 "</script>"})
141 141 int updateStreamGPS(List<GPSMsgInfo> gpsMsgInfos);
142 142  
143 143 @Select("<script> "+
144   - "SELECT * FROM gb_stream where " +
  144 + "SELECT * FROM wvp_gb_stream where " +
145 145 "<foreach collection='streamPushItems' item='item' separator='or'>" +
146 146 "(app=#{item.app} and stream=#{item.stream}) " +
147 147 "</foreach>" +
148 148 "</script>")
149 149 List<GbStream> selectAllForAppAndStream(List<StreamPushItem> streamPushItems);
150 150  
151   - @Update("UPDATE gb_stream " +
152   - "SET mediaServerId=#{mediaServerId}" +
  151 + @Update("UPDATE wvp_gb_stream " +
  152 + "SET media_server_id=#{mediaServerId}" +
153 153 "WHERE app=#{app} AND stream=#{stream}")
154 154 void updateMediaServer(String app, String stream, String mediaServerId);
155 155  
156 156 @Update("<script> "+
157 157 " <foreach collection='list' item='item' index='index' separator=';'>"+
158   - "UPDATE gb_stream " +
  158 + "UPDATE wvp_gb_stream " +
159 159 " SET name=#{item.name},"+
160   - " gbId=#{item.gbId}"+
  160 + " gb_id=#{item.gb_id}"+
161 161 " WHERE app=#{item.app} and stream=#{item.stream}"+
162 162 "</foreach>"+
163 163 "</script>")
164 164 int updateGbIdOrName(List<StreamPushItem> streamPushItemForUpdate);
165 165  
166   - @Select("SELECT status FROM stream_proxy WHERE app=#{app} AND stream=#{stream}")
  166 + @Select("SELECT status FROM wvp_stream_proxy WHERE app=#{app} AND stream=#{stream}")
167 167 Boolean selectStatusForProxy(String app, String stream);
168 168  
169   - @Select("SELECT status FROM stream_push WHERE app=#{app} AND stream=#{stream}")
  169 + @Select("SELECT status FROM wvp_stream_push WHERE app=#{app} AND stream=#{stream}")
170 170 Boolean selectStatusForPush(String app, String stream);
171 171  
172 172 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java
1 1 package com.genersoft.iot.vmp.storager.dao;
2 2  
3   -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
4 3 import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
5 4 import org.apache.ibatis.annotations.Delete;
6 5 import org.apache.ibatis.annotations.Insert;
... ... @@ -17,21 +16,21 @@ import java.util.List;
17 16 @Repository
18 17 public interface LogMapper {
19 18  
20   - @Insert("insert into log ( name, type, uri, address, result, timing, username, createTime) " +
  19 + @Insert("insert into wvp_log ( name,type,uri,address,result,timing,username,create_time) " +
21 20 "values (#{name}, #{type}, #{uri}, #{address}, #{result}, #{timing}, #{username}, #{createTime})")
22 21 int add(LogDto logDto);
23 22  
24 23 @Select(value = {"<script>" +
25   - " SELECT * FROM log " +
  24 + " SELECT * FROM wvp_log " +
26 25 " WHERE 1=1 " +
27 26 " <if test=\"query != null\"> AND (name LIKE concat('%',#{query},'%'))</if> " +
28 27 " <if test=\"type != null\" > AND type = #{type}</if>" +
29   - " <if test=\"startTime != null\" > AND createTime &gt;= #{startTime} </if>" +
30   - " <if test=\"endTime != null\" > AND createTime &lt;= #{endTime} </if>" +
31   - " ORDER BY createTime DESC " +
  28 + " <if test=\"startTime != null\" > AND create_time &gt;= #{startTime} </if>" +
  29 + " <if test=\"endTime != null\" > AND create_time &lt;= #{endTime} </if>" +
  30 + " ORDER BY create_time DESC " +
32 31 " </script>"})
33 32 List<LogDto> query(String query, String type, String startTime, String endTime);
34 33  
35   - @Delete("DELETE FROM log")
  34 + @Delete("DELETE FROM wvp_log")
36 35 int clear();
37 36 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
... ... @@ -11,28 +11,28 @@ import java.util.List;
11 11 @Repository
12 12 public interface MediaServerMapper {
13 13  
14   - @Insert("INSERT INTO media_server (" +
15   - "id, " +
16   - "ip, " +
17   - "hookIp, " +
18   - "sdpIp, " +
19   - "streamIp, " +
20   - "httpPort, " +
21   - "httpSSlPort, " +
22   - "rtmpPort, " +
23   - "rtmpSSlPort, " +
24   - "rtpProxyPort, " +
25   - "rtspPort, " +
26   - "rtspSSLPort, " +
27   - "autoConfig, " +
28   - "secret, " +
29   - "rtpEnable, " +
30   - "rtpPortRange, " +
31   - "recordAssistPort, " +
32   - "defaultServer, " +
33   - "createTime, " +
34   - "updateTime, " +
35   - "hookAliveInterval" +
  14 + @Insert("INSERT INTO wvp_media_server (" +
  15 + "id,"+
  16 + "ip,"+
  17 + "hook_ip,"+
  18 + "sdp_ip,"+
  19 + "stream_ip,"+
  20 + "http_port,"+
  21 + "http_ssl_port,"+
  22 + "rtmp_port,"+
  23 + "rtmp_ssl_port,"+
  24 + "rtp_proxy_port,"+
  25 + "rtsp_port,"+
  26 + "rtsp_ssl_port,"+
  27 + "auto_config,"+
  28 + "secret,"+
  29 + "rtp_enable,"+
  30 + "rtp_port_range,"+
  31 + "record_assist_port,"+
  32 + "default_server,"+
  33 + "create_time,"+
  34 + "update_time,"+
  35 + "hook_alive_interval"+
36 36 ") VALUES " +
37 37 "(" +
38 38 "#{id}, " +
... ... @@ -59,70 +59,70 @@ public interface MediaServerMapper {
59 59 int add(MediaServerItem mediaServerItem);
60 60  
61 61 @Update(value = {" <script>" +
62   - "UPDATE media_server " +
63   - "SET updateTime=#{updateTime}" +
  62 + "UPDATE wvp_media_server " +
  63 + "SET update_time=#{updateTime}" +
64 64 "<if test=\"ip != null\">, ip=#{ip}</if>" +
65   - "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" +
66   - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
67   - "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" +
68   - "<if test=\"httpPort != null\">, httpPort=#{httpPort}</if>" +
69   - "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" +
70   - "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" +
71   - "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" +
72   - "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" +
73   - "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" +
74   - "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" +
75   - "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" +
76   - "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" +
77   - "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" +
  65 + "<if test=\"hookIp != null\">, hook_ip=#{hookIp}</if>" +
  66 + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" +
  67 + "<if test=\"streamIp != null\">, stream_ip=#{streamIp}</if>" +
  68 + "<if test=\"httpPort != null\">, http_port=#{httpPort}</if>" +
  69 + "<if test=\"httpSSlPort != null\">, http_ssl_port=#{httpSSlPort}</if>" +
  70 + "<if test=\"rtmpPort != null\">, rtmp_port=#{rtmpPort}</if>" +
  71 + "<if test=\"rtmpSSlPort != null\">, rtmp_ssl_port=#{rtmpSSlPort}</if>" +
  72 + "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" +
  73 + "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" +
  74 + "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" +
  75 + "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" +
  76 + "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" +
  77 + "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" +
78 78 "<if test=\"secret != null\">, secret=#{secret}</if>" +
79   - "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" +
80   - "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" +
  79 + "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" +
  80 + "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
81 81 "WHERE id=#{id}"+
82 82 " </script>"})
83 83 int update(MediaServerItem mediaServerItem);
84 84  
85 85 @Update(value = {" <script>" +
86   - "UPDATE media_server " +
87   - "SET updateTime=#{updateTime}" +
  86 + "UPDATE wvp_media_server " +
  87 + "SET update_time=#{updateTime}" +
88 88 "<if test=\"id != null\">, id=#{id}</if>" +
89   - "<if test=\"hookIp != null\">, hookIp=#{hookIp}</if>" +
90   - "<if test=\"sdpIp != null\">, sdpIp=#{sdpIp}</if>" +
91   - "<if test=\"streamIp != null\">, streamIp=#{streamIp}</if>" +
92   - "<if test=\"httpSSlPort != null\">, httpSSlPort=#{httpSSlPort}</if>" +
93   - "<if test=\"rtmpPort != null\">, rtmpPort=#{rtmpPort}</if>" +
94   - "<if test=\"rtmpSSlPort != null\">, rtmpSSlPort=#{rtmpSSlPort}</if>" +
95   - "<if test=\"rtpProxyPort != null\">, rtpProxyPort=#{rtpProxyPort}</if>" +
96   - "<if test=\"rtspPort != null\">, rtspPort=#{rtspPort}</if>" +
97   - "<if test=\"rtspSSLPort != null\">, rtspSSLPort=#{rtspSSLPort}</if>" +
98   - "<if test=\"autoConfig != null\">, autoConfig=#{autoConfig}</if>" +
99   - "<if test=\"rtpEnable != null\">, rtpEnable=#{rtpEnable}</if>" +
100   - "<if test=\"rtpPortRange != null\">, rtpPortRange=#{rtpPortRange}</if>" +
  89 + "<if test=\"hookIp != null\">, hook_ip=#{hookIp}</if>" +
  90 + "<if test=\"sdpIp != null\">, sdp_ip=#{sdpIp}</if>" +
  91 + "<if test=\"streamIp != null\">, stream_ip=#{streamIp}</if>" +
  92 + "<if test=\"httpSSlPort != null\">, http_ssl_port=#{httpSSlPort}</if>" +
  93 + "<if test=\"rtmpPort != null\">, rtmp_port=#{rtmpPort}</if>" +
  94 + "<if test=\"rtmpSSlPort != null\">, rtmp_ssl_port=#{rtmpSSlPort}</if>" +
  95 + "<if test=\"rtpProxyPort != null\">, rtp_proxy_port=#{rtpProxyPort}</if>" +
  96 + "<if test=\"rtspPort != null\">, rtsp_port=#{rtspPort}</if>" +
  97 + "<if test=\"rtspSSLPort != null\">, rtsp_ssl_port=#{rtspSSLPort}</if>" +
  98 + "<if test=\"autoConfig != null\">, auto_config=#{autoConfig}</if>" +
  99 + "<if test=\"rtpEnable != null\">, rtp_enable=#{rtpEnable}</if>" +
  100 + "<if test=\"rtpPortRange != null\">, rtp_port_range=#{rtpPortRange}</if>" +
101 101 "<if test=\"secret != null\">, secret=#{secret}</if>" +
102   - "<if test=\"recordAssistPort != null\">, recordAssistPort=#{recordAssistPort}</if>" +
103   - "<if test=\"hookAliveInterval != null\">, hookAliveInterval=#{hookAliveInterval}</if>" +
104   - "WHERE ip=#{ip} and httpPort=#{httpPort}"+
  102 + "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" +
  103 + "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
  104 + "WHERE ip=#{ip} and http_port=#{httpPort}"+
105 105 " </script>"})
106 106 int updateByHostAndPort(MediaServerItem mediaServerItem);
107 107  
108   - @Select("SELECT * FROM media_server WHERE id=#{id}")
  108 + @Select("SELECT * FROM wvp_media_server WHERE id=#{id}")
109 109 MediaServerItem queryOne(String id);
110 110  
111   - @Select("SELECT * FROM media_server")
  111 + @Select("SELECT * FROM wvp_media_server")
112 112 List<MediaServerItem> queryAll();
113 113  
114   - @Delete("DELETE FROM media_server WHERE id=#{id}")
  114 + @Delete("DELETE FROM wvp_media_server WHERE id=#{id}")
115 115 void delOne(String id);
116 116  
117   - @Select("DELETE FROM media_server WHERE ip=#{host} and httpPort=#{port}")
  117 + @Select("DELETE FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}")
118 118 void delOneByIPAndPort(String host, int port);
119 119  
120   - @Delete("DELETE FROM media_server WHERE defaultServer=1")
  120 + @Delete("DELETE FROM wvp_media_server WHERE default_server=true")
121 121 int delDefault();
122 122  
123   - @Select("SELECT * FROM media_server WHERE ip=#{host} and httpPort=#{port}")
  123 + @Select("SELECT * FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}")
124 124 MediaServerItem queryOneByHostAndPort(String host, int port);
125 125  
126   - @Select("SELECT * FROM media_server WHERE defaultServer=1")
  126 + @Select("SELECT * FROM wvp_media_server WHERE default_server=true")
127 127 MediaServerItem queryDefault();
128 128 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
... ... @@ -14,88 +14,87 @@ import java.util.List;
14 14 @Repository
15 15 public interface ParentPlatformMapper {
16 16  
17   - @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " +
18   - " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, asMessageChannel, " +
19   - " status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " +
  17 + @Insert("INSERT INTO wvp_platform (enable, name, server_gb_id, server_gb_domain, server_ip, server_port,device_gb_id,device_ip,"+
  18 + "device_port,username,password,expires,keep_timeout,transport,character_set,ptz,rtcp,as_message_channel,"+
  19 + "status,start_offline_push,catalog_id,administrative_division,catalog_group,create_time,update_time) " +
20 20 " VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " +
21 21 " #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{asMessageChannel}, " +
22   - " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
  22 + " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime})")
23 23 int addParentPlatform(ParentPlatform parentPlatform);
24 24  
25   - @Update("UPDATE parent_platform " +
  25 + @Update("UPDATE wvp_platform " +
26 26 "SET enable=#{enable}, " +
27 27 "name=#{name}," +
28   - "deviceGBId=#{deviceGBId}," +
29   - "serverGBId=#{serverGBId}, " +
30   - "serverGBDomain=#{serverGBDomain}, " +
31   - "serverIP=#{serverIP}," +
32   - "serverPort=#{serverPort}, " +
33   - "deviceIp=#{deviceIp}, " +
34   - "devicePort=#{devicePort}, " +
  28 + "device_gb_id=#{deviceGBId}," +
  29 + "server_gb_id=#{serverGBId}, " +
  30 + "server_gb_domain=#{serverGBDomain}, " +
  31 + "server_ip=#{serverIP}," +
  32 + "server_port=#{serverPort}, " +
  33 + "device_ip=#{deviceIp}, " +
  34 + "device_port=#{devicePort}, " +
35 35 "username=#{username}, " +
36 36 "password=#{password}, " +
37 37 "expires=#{expires}, " +
38   - "keepTimeout=#{keepTimeout}, " +
  38 + "keep_timeout=#{keepTimeout}, " +
39 39 "transport=#{transport}, " +
40   - "characterSet=#{characterSet}, " +
  40 + "character_set=#{characterSet}, " +
41 41 "ptz=#{ptz}, " +
42 42 "rtcp=#{rtcp}, " +
43   - "asMessageChannel=#{asMessageChannel}, " +
  43 + "as_message_channel=#{asMessageChannel}, " +
44 44 "status=#{status}, " +
45   - "startOfflinePush=#{startOfflinePush}, " +
46   - "catalogGroup=#{catalogGroup}, " +
47   - "administrativeDivision=#{administrativeDivision}, " +
48   - "createTime=#{createTime}, " +
49   - "updateTime=#{updateTime}, " +
50   - "treeType=#{treeType}, " +
51   - "catalogId=#{catalogId} " +
  45 + "start_offline_push=#{startOfflinePush}, " +
  46 + "catalog_group=#{catalogGroup}, " +
  47 + "administrative_division=#{administrativeDivision}, " +
  48 + "create_time=#{createTime}, " +
  49 + "update_time=#{updateTime}, " +
  50 + "catalog_id=#{catalogId} " +
52 51 "WHERE id=#{id}")
53 52 int updateParentPlatform(ParentPlatform parentPlatform);
54 53  
55   - @Delete("DELETE FROM parent_platform WHERE serverGBId=#{serverGBId}")
  54 + @Delete("DELETE FROM wvp_platform WHERE server_gb_id=#{serverGBId}")
56 55 int delParentPlatform(ParentPlatform parentPlatform);
57 56  
58 57 @Select("SELECT *, ((SELECT count(0)\n" +
59   - " FROM platform_gb_channel pc\n" +
60   - " WHERE pc.platformId = pp.serverGBId)\n" +
  58 + " FROM wvp_platform_gb_channel pc\n" +
  59 + " WHERE pc.platform_id = pp.server_gb_id)\n" +
61 60 " +\n" +
62 61 " (SELECT count(0)\n" +
63   - " FROM platform_gb_stream pgs\n" +
64   - " WHERE pgs.platformId = pp.serverGBId)\n" +
  62 + " FROM wvp_platform_gb_stream pgs\n" +
  63 + " WHERE pgs.platform_id = pp.server_gb_id)\n" +
65 64 " +\n" +
66 65 " (SELECT count(0)\n" +
67   - " FROM platform_catalog pgc\n" +
68   - " WHERE pgc.platformId = pp.serverGBId)) as channelCount\n" +
69   - "FROM parent_platform pp ")
  66 + " FROM wvp_platform_catalog pgc\n" +
  67 + " WHERE pgc.platform_id = pp.server_gb_id)) as channel_count\n" +
  68 + "FROM wvp_platform pp ")
70 69 List<ParentPlatform> getParentPlatformList();
71 70  
72   - @Select("SELECT * FROM parent_platform WHERE enable=#{enable} ")
  71 + @Select("SELECT * FROM wvp_platform WHERE enable=#{enable} ")
73 72 List<ParentPlatform> getEnableParentPlatformList(boolean enable);
74 73  
75   - @Select("SELECT * FROM parent_platform WHERE enable=1 and asMessageChannel = 1")
  74 + @Select("SELECT * FROM wvp_platform WHERE enable=true and as_message_channel=true")
76 75 List<ParentPlatform> queryEnablePlatformListWithAsMessageChannel();
77 76  
78   - @Select("SELECT * FROM parent_platform WHERE serverGBId=#{platformGbId}")
  77 + @Select("SELECT * FROM wvp_platform WHERE server_gb_id=#{platformGbId}")
79 78 ParentPlatform getParentPlatByServerGBId(String platformGbId);
80 79  
81   - @Select("SELECT * FROM parent_platform WHERE id=#{id}")
  80 + @Select("SELECT * FROM wvp_platform WHERE id=#{id}")
82 81 ParentPlatform getParentPlatById(int id);
83 82  
84   - @Update("UPDATE parent_platform SET status=false" )
  83 + @Update("UPDATE wvp_platform SET status=false" )
85 84 int outlineForAllParentPlatform();
86 85  
87   - @Update("UPDATE parent_platform SET status=#{online} WHERE serverGBId=#{platformGbID}" )
  86 + @Update("UPDATE wvp_platform SET status=#{online} WHERE server_gb_id=#{platformGbID}" )
88 87 int updateParentPlatformStatus(String platformGbID, boolean online);
89 88  
90 89 @Update(value = {" <script>" +
91   - "UPDATE parent_platform " +
92   - "SET catalogId=#{catalogId}, updateTime=#{updateTime}" +
93   - "WHERE serverGBId=#{platformId}"+
  90 + "UPDATE wvp_platform " +
  91 + "SET catalog_id=#{catalogId}, update_time=#{updateTime}" +
  92 + "WHERE server_gb_id=#{platformId}"+
94 93 "</script>"})
95 94 int setDefaultCatalog(String platformId, String catalogId, String updateTime);
96 95  
97   - @Select("select 'channel' as name, count(pgc.platformId) count from platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId where pgc.platformId=#{platformId} and dc.channelId =#{gbId} " +
  96 + @Select("select 'channel' as name, count(pgc.platform_id) count from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id where pgc.platform_id=#{platform_id} and dc.channel_id =#{gbId} " +
98 97 "union " +
99   - "select 'stream' as name, count(pgs.platformId) count from platform_gb_stream pgs left join gb_stream gs on pgs.gbStreamId = gs.gbStreamId where pgs.platformId=#{platformId} and gs.gbId = #{gbId}")
100   - List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
  98 + "select 'stream' as name, count(pgs.platform_id) count from wvp_platform_gb_stream pgs left join wvp_gb_stream gs on pgs.gb_stream_id = gs.gb_stream_id where pgs.platform_id=#{platform_id} and gs.gb_id =#{gbId}")
  99 + List<ChannelSourceInfo> getChannelSource(String platform_id, String gbId);
101 100 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java
1 1 package com.genersoft.iot.vmp.storager.dao;
2 2  
3 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
4   -import com.genersoft.iot.vmp.gb28181.bean.GbStream;
5 4 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
6   -import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream;
7   -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
8 5 import org.apache.ibatis.annotations.*;
9 6 import org.springframework.stereotype.Repository;
10 7  
... ... @@ -15,42 +12,43 @@ import java.util.List;
15 12 @Repository
16 13 public interface PlatformCatalogMapper {
17 14  
18   - @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId, civilCode, businessGroupId) VALUES" +
  15 + @Insert("INSERT INTO wvp_platform_catalog (id, name, platform_id, parent_id, civil_code, business_group_id) VALUES" +
19 16 "(#{id}, #{name}, #{platformId}, #{parentId}, #{civilCode}, #{businessGroupId})")
20 17 int add(PlatformCatalog platformCatalog);
21 18  
22   - @Delete("DELETE FROM platform_catalog WHERE id=#{id}")
  19 + @Delete("DELETE from wvp_platform_catalog WHERE id=#{id}")
23 20 int del(String id);
24 21  
25   - @Delete("DELETE FROM platform_catalog WHERE platformId=#{platformId}")
  22 + @Delete("DELETE from wvp_platform_catalog WHERE platform_id=#{platformId}")
26 23 int delByPlatformId(String platformId);
27 24  
28   - @Select("SELECT pc.*, count(pc2.id) as childrenCount FROM platform_catalog pc " +
29   - "left join platform_catalog pc2 on pc.id = pc2.parentId " +
30   - "WHERE pc.parentId=#{parentId} AND pc.platformId=#{platformId} group by pc.id")
  25 + @Select("SELECT pc.*, count(pc2.id) as children_count from wvp_platform_catalog pc " +
  26 + "left join wvp_platform_catalog pc2 on pc.id = pc2.parent_id " +
  27 + "WHERE pc.parent_id=#{parentId} AND pc.platform_id=#{platformId} " +
  28 + "group by pc.id, pc.name, pc.platform_id, pc.business_group_id, pc.civil_code, pc.parent_id")
31 29 List<PlatformCatalog> selectByParentId(String platformId, String parentId);
32 30  
33   - @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.id=#{id}")
  31 + @Select("SELECT *, (SELECT COUNT(1) from wvp_platform_catalog where parent_id = pc.id) as children_count from wvp_platform_catalog pc WHERE pc.id=#{id}")
34 32 PlatformCatalog select(String id);
35 33  
36 34 @Update(value = {" <script>" +
37   - "UPDATE platform_catalog " +
  35 + "UPDATE wvp_platform_catalog " +
38 36 "SET name=#{name}" +
39 37 "WHERE id=#{id}"+
40 38 "</script>"})
41 39 int update(PlatformCatalog platformCatalog);
42 40  
43   - @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.platformId=#{platformId}")
  41 + @Select("SELECT *, (SELECT COUNT(1) from wvp_platform_catalog where parent_id = pc.id) as children_count from wvp_platform_catalog pc WHERE pc.platform_id=#{platformId}")
44 42 List<PlatformCatalog> selectByPlatForm(String platformId);
45 43  
46   - @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = (SELECT pp.catalogId from parent_platform pp WHERE pp.serverGBId=#{platformId})")
  44 + @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = (SELECT pp.catalog_id from wvp_platform pp WHERE pp.server_gb_id=#{platformId})")
47 45 PlatformCatalog selectDefaultByPlatFormId(String platformId);
48 46  
49 47  
50   - @Select("SELECT pc.* FROM platform_catalog pc WHERE pc.id = #{id}")
  48 + @Select("SELECT pc.* FROM wvp_platform_catalog pc WHERE pc.id = #{id}")
51 49 PlatformCatalog selectParentCatalog(String id);
52 50  
53   - @Select("SELECT pc.id as channelId, pc.name, pc.civilCode, pc.businessGroupId,'1' as parental, pc.parentId " +
54   - " FROM platform_catalog pc WHERE pc.platformId=#{platformId}")
  51 + @Select("SELECT pc.id as channel_id, pc.name, pc.civil_code, pc.business_group_id,'1' as parental, pc.parent_id " +
  52 + " from wvp_platform_catalog pc WHERE pc.platform_id=#{platformId}")
55 53 List<DeviceChannel> queryCatalogInPlatform(String platformId);
56 54 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
... ... @@ -21,13 +21,13 @@ public interface PlatformChannelMapper {
21 21 * 查询列表里已经关联的
22 22 */
23 23 @Select("<script> "+
24   - "SELECT deviceChannelId FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" +
  24 + "SELECT device_channel_id from wvp_platform_gb_channel WHERE platform_id=#{platformId} AND device_channel_id in" +
25 25 "<foreach collection='channelReduces' open='(' item='item' separator=',' close=')'> #{item.id}</foreach>" +
26 26 "</script>")
27 27 List<Integer> findChannelRelatedPlatform(String platformId, List<ChannelReduce> channelReduces);
28 28  
29 29 @Insert("<script> "+
30   - "INSERT INTO platform_gb_channel (platformId, deviceChannelId, catalogId) VALUES" +
  30 + "INSERT INTO wvp_platform_gb_channel (platform_id, device_channel_id, catalog_id) VALUES" +
31 31 "<foreach collection='channelReducesToAdd' item='item' separator=','>" +
32 32 " (#{platformId}, #{item.id} , #{item.catalogId} )" +
33 33 "</foreach>" +
... ... @@ -35,50 +35,50 @@ public interface PlatformChannelMapper {
35 35 int addChannels(String platformId, List<ChannelReduce> channelReducesToAdd);
36 36  
37 37 @Delete("<script> "+
38   - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId} AND deviceChannelId in" +
  38 + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId} AND device_channel_id in" +
39 39 "<foreach collection='channelReducesToDel' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
40 40 "</script>")
41 41 int delChannelForGB(String platformId, List<ChannelReduce> channelReducesToDel);
42 42  
43 43 @Delete("<script> "+
44   - "DELETE FROM platform_gb_channel WHERE deviceChannelId in " +
45   - "( select temp.deviceChannelId from " +
46   - "(select pgc.deviceChannelId from platform_gb_channel pgc " +
47   - "left join device_channel dc on dc.id = pgc.deviceChannelId where dc.deviceId =#{deviceId} " +
  44 + "DELETE from wvp_platform_gb_channel WHERE device_channel_id in " +
  45 + "( select temp.device_channel_id from " +
  46 + "(select pgc.device_channel_id from wvp_platform_gb_channel pgc " +
  47 + "left join wvp_device_channel dc on dc.id = pgc.device_channel_id where dc.device_id =#{deviceId} " +
48 48 ") temp)" +
49 49 "</script>")
50 50 int delChannelForDeviceId(String deviceId);
51 51  
52 52 @Delete("<script> "+
53   - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId}" +
  53 + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId}" +
54 54 "</script>")
55 55 int cleanChannelForGB(String platformId);
56 56  
57   - @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId=#{channelId} and pgc.platformId=#{platformId}")
  57 + @Select("SELECT dc.* from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id=#{channelId} and pgc.platform_id=#{platformId}")
58 58 List<DeviceChannel> queryChannelInParentPlatform(String platformId, String channelId);
59 59  
60   - @Select("SELECT dc.* FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}")
  60 + @Select("SELECT dc.* from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE pgc.platform_id=#{platformId} and pgc.catalog_id=#{catalogId}")
61 61 List<DeviceChannel> queryAllChannelInCatalog(String platformId, String catalogId);
62 62  
63   - @Select(" select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " +
64   - " from device_channel dc left join platform_gb_channel pgc on dc.id = pgc.deviceChannelId " +
65   - " where pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}")
  63 + @Select(" select dc.channel_id as id, dc.name as name, pgc.platform_id as platform_id, pgc.catalog_id as parent_id, 0 as children_count, 1 as type " +
  64 + " from wvp_device_channel dc left join wvp_platform_gb_channel pgc on dc.id = pgc.device_channel_id " +
  65 + " where pgc.platform_id=#{platformId} and pgc.catalog_id=#{catalogId}")
66 66 List<PlatformCatalog> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
67 67  
68 68 @Select("select d.*\n" +
69   - "from platform_gb_channel pgc\n" +
70   - " left join device_channel dc on dc.id = pgc.deviceChannelId\n" +
71   - " left join device d on dc.deviceId = d.deviceId\n" +
72   - "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}")
  69 + "from wvp_platform_gb_channel pgc\n" +
  70 + " left join wvp_device_channel dc on dc.id = pgc.device_channel_id\n" +
  71 + " left join wvp_device d on dc.device_id = d.device_id\n" +
  72 + "where dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}")
73 73 List<Device> queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId);
74 74  
75 75 @Delete("<script> "+
76   - "DELETE FROM platform_gb_channel WHERE catalogId=#{id}" +
  76 + "DELETE from wvp_platform_gb_channel WHERE catalog_id=#{id}" +
77 77 "</script>")
78 78 int delByCatalogId(String id);
79 79  
80 80 @Delete("<script> "+
81   - "DELETE FROM platform_gb_channel WHERE catalogId=#{parentId} AND platformId=#{platformId} AND channelId=#{id}" +
  81 + "DELETE from wvp_platform_gb_channel WHERE catalog_id=#{parentId} AND platform_id=#{platformId} AND channel_id=#{id}" +
82 82 "</script>")
83 83 int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog);
84 84  
... ... @@ -86,35 +86,35 @@ public interface PlatformChannelMapper {
86 86 "SELECT " +
87 87 "pp.* " +
88 88 "FROM " +
89   - "parent_platform pp " +
90   - "left join platform_gb_channel pgc on " +
91   - "pp.serverGBId = pgc.platformId " +
92   - "left join device_channel dc on " +
93   - "dc.id = pgc.deviceChannelId " +
  89 + "wvp_platform pp " +
  90 + "left join wvp_platform_gb_channel pgc on " +
  91 + "pp.server_gb_id = pgc.platform_id " +
  92 + "left join wvp_device_channel dc on " +
  93 + "dc.id = pgc.device_channel_id " +
94 94 "WHERE " +
95   - "dc.channelId = #{channelId} and pp.status = true " +
96   - "AND pp.serverGBId IN" +
97   - "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
  95 + "dc.channel_id = #{channelId} and pp.status = true " +
  96 + "AND pp.server_gb_id IN" +
  97 + "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
98 98 "</script> ")
99 99 List<ParentPlatform> queryPlatFormListForGBWithGBId(String channelId, List<String> platforms);
100 100  
101 101 @Delete("<script> " +
102   - "DELETE FROM platform_gb_channel WHERE platformId=#{serverGBId}" +
  102 + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{serverGBId}" +
103 103 "</script>")
104 104 void delByPlatformId(String serverGBId);
105 105  
106 106 @Delete("<script> " +
107   - "DELETE FROM platform_gb_channel WHERE platformId=#{platformId} and catalogId=#{catalogId}" +
  107 + "DELETE from wvp_platform_gb_channel WHERE platform_id=#{platformId} and catalog_id=#{catalogId}" +
108 108 "</script>")
109 109 int delChannelForGBByCatalogId(String platformId, String catalogId);
110 110  
111   - @Select("select dc.channelId deviceId,dc.name,d.manufacturer,d.model,d.firmware\n" +
112   - "from platform_gb_channel pgc\n" +
113   - " left join device_channel dc on dc.id = pgc.deviceChannelId\n" +
114   - " left join device d on dc.deviceId = d.deviceId\n" +
115   - "where dc.channelId = #{channelId} and pgc.platformId=#{platformId}")
  111 + @Select("select dc.channel_id dc.device_id,dc.name,d.manufacturer,d.model,d.firmware\n" +
  112 + "from wvp_platform_gb_channel pgc\n" +
  113 + " left join wvp_device_channel dc on dc.id = pgc.device_channel_id\n" +
  114 + " left join wvp_device d on dc.device_id = d.device_id\n" +
  115 + "where dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}")
116 116 List<Device> queryDeviceInfoByPlatformIdAndChannelId(String platformId, String channelId);
117 117  
118   - @Select("SELECT pgc.platformId FROM platform_gb_channel pgc left join device_channel dc on dc.id = pgc.deviceChannelId WHERE dc.channelId='${channelId}'")
  118 + @Select("SELECT pgc.platform_id from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id='${channelId}'")
119 119 List<String> queryParentPlatformByChannelId(String channelId);
120 120 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
... ... @@ -16,82 +16,82 @@ import java.util.List;
16 16 @Repository
17 17 public interface PlatformGbStreamMapper {
18 18  
19   - @Insert("REPLACE INTO platform_gb_stream (gbStreamId, platformId, catalogId) VALUES" +
  19 + @Insert("REPLACE INTO wvp_platform_gb_stream (gb_stream_id, platform_id, catalog_id) VALUES" +
20 20 "( #{gbStreamId}, #{platformId}, #{catalogId})")
21 21 int add(PlatformGbStream platformGbStream);
22 22  
23 23  
24 24 @Insert("<script> " +
25   - "INSERT into platform_gb_stream " +
26   - "(gbStreamId, platformId, catalogId) " +
  25 + "INSERT into wvp_platform_gb_stream " +
  26 + "(gb_stream_id, platform_id, catalog_id) " +
27 27 "values " +
28 28 "<foreach collection='streamPushItems' index='index' item='item' separator=','> " +
29   - "(#{item.gbStreamId}, #{item.platformId}, #{item.catalogId})" +
  29 + "(#{item.gbStreamId}, #{item.platform_id}, #{item.catalogId})" +
30 30 "</foreach> " +
31 31 "</script>")
32 32 int batchAdd(List<StreamPushItem> streamPushItems);
33 33  
34   - @Delete("DELETE FROM platform_gb_stream WHERE gbStreamId = (select gbStreamId from gb_stream where app=#{app} AND stream=#{stream})")
  34 + @Delete("DELETE from wvp_platform_gb_stream WHERE gb_stream_id = (select gb_stream_id from wvp_gb_stream where app=#{app} AND stream=#{stream})")
35 35 int delByAppAndStream(String app, String stream);
36 36  
37   - @Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId}")
  37 + @Delete("DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId}")
38 38 int delByPlatformId(String platformId);
39 39  
40 40 @Select("SELECT " +
41 41 "pp.* " +
42 42 "FROM " +
43   - "platform_gb_stream pgs " +
44   - "LEFT JOIN parent_platform pp ON pp.serverGBId = pgs.platformId " +
45   - "LEFT JOIN gb_stream gs ON gs.gbStreamId = pgs.gbStreamId " +
  43 + "wvp_platform_gb_stream pgs " +
  44 + "LEFT JOIN wvp_platform pp ON pp.server_gb_id = pgs.platform_id " +
  45 + "LEFT join wvp_gb_stream gs ON gs.gb_stream_id = pgs.gb_stream_id " +
46 46 "WHERE " +
47 47 "gs.app =#{app} " +
48 48 "AND gs.stream =#{stream} ")
49 49 List<ParentPlatform> selectByAppAndStream(String app, String stream);
50 50  
51   - @Select("SELECT pgs.*, gs.gbId FROM platform_gb_stream pgs " +
52   - "LEFT JOIN gb_stream gs ON pgs.gbStreamId = gs.gbStreamId " +
53   - "WHERE gs.app=#{app} AND gs.stream=#{stream} AND pgs.platformId=#{serverGBId}")
  51 + @Select("SELECT pgs.*, gs.gb_id from wvp_platform_gb_stream pgs " +
  52 + "LEFT join wvp_gb_stream gs ON pgs.gb_stream_id = gs.gb_stream_id " +
  53 + "WHERE gs.app=#{app} AND gs.stream=#{stream} AND pgs.platform_id=#{serverGBId}")
54 54 StreamProxyItem selectOne(String app, String stream, String serverGBId);
55 55  
56 56 @Select("select gs.* \n" +
57   - "from gb_stream gs\n" +
58   - " left join platform_gb_stream pgs\n" +
59   - " on gs.gbStreamId = pgs.gbStreamId\n" +
60   - "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
  57 + "from wvp_gb_stream gs\n" +
  58 + " left join wvp_platform_gb_stream pgs\n" +
  59 + " on gs.gb_stream_id = pgs.gb_stream_id\n" +
  60 + "where pgs.platform_id=#{platformId} and pgs.catalog_id=#{catalogId}")
61 61 List<GbStream> queryChannelInParentPlatformAndCatalog(String platformId, String catalogId);
62 62  
63   - @Select("select gs.gbId as id, gs.name as name, pgs.platformId as platformId, pgs.catalogId as catalogId , 0 as childrenCount, 2 as type\n" +
64   - "from gb_stream gs\n" +
65   - " left join platform_gb_stream pgs\n" +
66   - " on gs.gbStreamId = pgs.gbStreamId\n" +
67   - "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}")
  63 + @Select("select gs.gb_id as id, gs.name as name, pgs.platform_id as platform_id, pgs.catalog_id as catalog_id , 0 as children_count, 2 as type\n" +
  64 + "from wvp_gb_stream gs\n" +
  65 + " left join wvp_platform_gb_stream pgs\n" +
  66 + " on gs.gb_stream_id = pgs.gb_stream_id\n" +
  67 + "where pgs.platform_id=#{platformId} and pgs.catalog_id=#{catalogId}")
68 68 List<PlatformCatalog> queryChannelInParentPlatformAndCatalogForCatalog(String platformId, String catalogId);
69 69  
70   - @Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}")
  70 + @Delete("DELETE from wvp_platform_gb_stream WHERE catalog_id=#{id}")
71 71 int delByCatalogId(String id);
72 72  
73 73 @Select("<script> " +
74 74 "SELECT " +
75 75 "pp.* " +
76 76 "FROM " +
77   - "parent_platform pp " +
78   - "left join platform_gb_stream pgs on " +
79   - "pp.serverGBId = pgs.platformId " +
80   - "left join gb_stream gs " +
81   - "on gs.gbStreamId = pgs.gbStreamId " +
  77 + "wvp_platform pp " +
  78 + "left join wvp_platform_gb_stream pgs on " +
  79 + "pp.server_gb_id = pgs.platform_id " +
  80 + "left join wvp_gb_stream gs " +
  81 + "on gs.gb_stream_id = pgs.gb_stream_id " +
82 82 "WHERE " +
83 83 "gs.app = #{app} " +
84 84 "AND gs.stream = #{stream}" +
85   - "AND pp.serverGBId IN" +
  85 + "AND pp.server_gb_id IN" +
86 86 "<foreach collection='platforms' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
87 87 "</script> ")
88 88 List<ParentPlatform> queryPlatFormListForGBWithGBId(String app, String stream, List<String> platforms);
89 89  
90   - @Delete("DELETE FROM platform_gb_stream WHERE gbStreamId = (select id from gb_stream where app=#{app} AND stream=#{stream}) AND platformId=#{platformId}")
  90 + @Delete("DELETE from wvp_platform_gb_stream WHERE gb_stream_id = (select id from wvp_gb_stream where app=#{app} AND stream=#{stream}) AND platform_id=#{platformId}")
91 91 int delByAppAndStreamAndPlatform(String app, String stream, String platformId);
92 92  
93 93 @Delete("<script> "+
94   - "DELETE FROM platform_gb_stream where gbStreamId in " +
  94 + "DELETE from wvp_platform_gb_stream where gb_stream_id in " +
95 95 "<foreach collection='gbStreams' item='item' open='(' separator=',' close=')' >" +
96 96 "#{item.gbStreamId}" +
97 97 "</foreach>" +
... ... @@ -99,13 +99,13 @@ public interface PlatformGbStreamMapper {
99 99 void delByGbStreams(List<GbStream> gbStreams);
100 100  
101 101 @Delete("<script> "+
102   - "DELETE FROM platform_gb_stream where platformId=#{platformId} and gbStreamId in " +
  102 + "DELETE from wvp_platform_gb_stream where platform_id=#{platformId} and gb_stream_id in " +
103 103 "<foreach collection='gbStreams' item='item' open='(' separator=',' close=')'>" +
104 104 "#{item.gbStreamId} " +
105 105 "</foreach>" +
106 106 "</script>")
107 107 void delByAppAndStreamsByPlatformId(List<GbStream> gbStreams, String platformId);
108 108  
109   - @Delete("DELETE FROM platform_gb_stream WHERE platformId=#{platformId} and catalogId=#{catalogId}")
  109 + @Delete("DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId} and catalog_id=#{catalogId}")
110 110 int delByPlatformAndCatalogId(String platformId, String catalogId);
111 111 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/RecordInfoDao.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.storager.dao;
2   -
3   -import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
4   -import org.apache.ibatis.annotations.Delete;
5   -import org.apache.ibatis.annotations.Insert;
6   -import org.apache.ibatis.annotations.Mapper;
7   -import org.apache.ibatis.annotations.Select;
8   -import org.springframework.stereotype.Repository;
9   -
10   -import java.util.List;
11   -
12   -@Mapper
13   -@Repository
14   -public interface RecordInfoDao {
15   -
16   - @Insert("INSERT INTO recordInfo (app, stream, mediaServerId, createTime, type, deviceId, channelId, name) VALUES" +
17   - "(#{app}, #{stream}, #{mediaServerId}, datetime('now','localtime')), #{type}, #{deviceId}, #{channelId}, #{name}")
18   - int add(RecordInfo recordInfo);
19   -
20   - @Delete("DELETE FROM user WHERE createTime < #{beforeTime}")
21   - int deleteBefore(String beforeTime);
22   -
23   - @Select("select * FROM recordInfo")
24   - List<RecordInfo> selectAll();
25   -}
src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java
1 1 package com.genersoft.iot.vmp.storager.dao;
2 2  
3 3 import com.genersoft.iot.vmp.storager.dao.dto.Role;
4   -import com.genersoft.iot.vmp.storager.dao.dto.User;
5 4 import org.apache.ibatis.annotations.*;
6 5 import org.springframework.stereotype.Repository;
7 6  
... ... @@ -11,25 +10,25 @@ import java.util.List;
11 10 @Repository
12 11 public interface RoleMapper {
13 12  
14   - @Insert("INSERT INTO user_role (name, authority, createTime, updateTime) VALUES" +
  13 + @Insert("INSERT INTO wvp_user_role (name, authority, create_time, update_time) VALUES" +
15 14 "(#{name}, #{authority}, #{createTime}, #{updateTime})")
16 15 int add(Role role);
17 16  
18 17 @Update(value = {" <script>" +
19   - "UPDATE user_role " +
20   - "SET updateTime=#{updateTime} " +
  18 + "UPDATE wvp_user_role " +
  19 + "SET update_time=#{updateTime} " +
21 20 "<if test=\"name != null\">, name=#{name}</if>" +
22 21 "<if test=\"authority != null\">, authority=#{authority}</if>" +
23 22 "WHERE id != 1 and id=#{id}" +
24 23 " </script>"})
25 24 int update(Role role);
26 25  
27   - @Delete("DELETE FROM user_role WHERE id != 1 and id=#{id}")
  26 + @Delete("DELETE from wvp_user_role WHERE id != 1 and id=#{id}")
28 27 int delete(int id);
29 28  
30   - @Select("select * FROM user_role WHERE id=#{id}")
  29 + @Select("select * from wvp_user_role WHERE id=#{id}")
31 30 Role selectById(int id);
32 31  
33   - @Select("select * FROM user_role")
  32 + @Select("select * from wvp_user_role")
34 33 List<Role> selectAll();
35 34 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java
1 1 package com.genersoft.iot.vmp.storager.dao;
2 2  
3 3 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
4   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  4 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
5 5 import org.apache.ibatis.annotations.*;
6 6 import org.springframework.stereotype.Repository;
7 7  
... ... @@ -11,72 +11,79 @@ import java.util.List;
11 11 @Repository
12 12 public interface StreamProxyMapper {
13 13  
14   - @Insert("INSERT INTO stream_proxy (type, name, app, stream,mediaServerId, url, src_url, dst_url, " +
15   - "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, createTime) VALUES" +
16   - "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{src_url}, #{dst_url}, " +
17   - "#{timeout_ms}, #{ffmpeg_cmd_key}, #{rtp_type}, #{enable_audio}, #{enable_mp4}, #{enable}, #{status}, " +
18   - "#{enable_remove_none_reader}, #{enable_disable_none_reader}, #{createTime} )")
  14 + @Insert("INSERT INTO wvp_stream_proxy (type, name, app, stream,media_server_id, url, src_url, dst_url, " +
  15 + "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_audio, enable_mp4, enable, status, enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" +
  16 + "(#{type}, #{name}, #{app}, #{stream}, #{mediaServerId}, #{url}, #{srcUrl}, #{dstUrl}, " +
  17 + "#{timeoutMs}, #{ffmpegCmdKey}, #{rtpType}, #{enableAudio}, #{enableMp4}, #{enable}, #{status}, " +
  18 + "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )")
19 19 int add(StreamProxyItem streamProxyDto);
20 20  
21   - @Update("UPDATE stream_proxy " +
  21 + @Update("UPDATE wvp_stream_proxy " +
22 22 "SET type=#{type}, " +
23 23 "name=#{name}," +
24 24 "app=#{app}," +
25 25 "stream=#{stream}," +
26 26 "url=#{url}, " +
27   - "mediaServerId=#{mediaServerId}, " +
28   - "src_url=#{src_url}," +
29   - "dst_url=#{dst_url}, " +
30   - "timeout_ms=#{timeout_ms}, " +
31   - "ffmpeg_cmd_key=#{ffmpeg_cmd_key}, " +
32   - "rtp_type=#{rtp_type}, " +
33   - "enable_audio=#{enable_audio}, " +
  27 + "media_server_id=#{mediaServerId}, " +
  28 + "src_url=#{srcUrl}," +
  29 + "dst_url=#{dstUrl}, " +
  30 + "timeout_ms=#{timeoutMs}, " +
  31 + "ffmpeg_cmd_key=#{ffmpegCmdKey}, " +
  32 + "rtp_type=#{rtpType}, " +
  33 + "enable_audio=#{enableAudio}, " +
34 34 "enable=#{enable}, " +
35 35 "status=#{status}, " +
36   - "enable_remove_none_reader=#{enable_remove_none_reader}, " +
37   - "enable_disable_none_reader=#{enable_disable_none_reader}, " +
38   - "enable_mp4=#{enable_mp4} " +
  36 + "enable_remove_none_reader=#{enableRemoveNoneReader}, " +
  37 + "enable_disable_none_reader=#{enableDisableNoneReader}, " +
  38 + "enable_mp4=#{enableMp4} " +
39 39 "WHERE app=#{app} AND stream=#{stream}")
40 40 int update(StreamProxyItem streamProxyDto);
41 41  
42   - @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}")
  42 + @Delete("DELETE FROM wvp_stream_proxy WHERE app=#{app} AND stream=#{stream}")
43 43 int del(String app, String stream);
44 44  
45   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.createTime desc")
  45 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream order by st.create_time desc")
46 46 List<StreamProxyItem> selectAll();
47 47  
48   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.createTime desc")
  48 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable=#{enable} order by st.create_time desc")
49 49 List<StreamProxyItem> selectForEnable(boolean enable);
50 50  
51   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.createTime desc")
  51 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.app=#{app} AND st.stream=#{stream} order by st.create_time desc")
52 52 StreamProxyItem selectOne(String app, String stream);
53 53  
54   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
55   - "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
56   - "WHERE st.enable=#{enable} and st.mediaServerId = #{id} order by st.createTime desc")
  54 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st " +
  55 + "LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
  56 + "WHERE st.enable=#{enable} and st.media_server_id= #{id} order by st.create_time desc")
57 57 List<StreamProxyItem> selectForEnableInMediaServer(String id, boolean enable);
58 58  
59   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st " +
60   - "LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
61   - "WHERE st.mediaServerId = #{id} order by st.createTime desc")
  59 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st " +
  60 + "LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream " +
  61 + "WHERE st.media_server_id= #{id} order by st.create_time desc")
62 62 List<StreamProxyItem> selectInMediaServer(String id);
63 63  
64   - @Update("UPDATE stream_proxy " +
  64 + @Update("UPDATE wvp_stream_proxy " +
65 65 "SET status=#{status} " +
66   - "WHERE mediaServerId=#{mediaServerId}")
  66 + "WHERE media_server_id=#{mediaServerId}")
67 67 void updateStatusByMediaServerId(String mediaServerId, boolean status);
68 68  
69   - @Update("UPDATE stream_proxy " +
  69 + @Update("UPDATE wvp_stream_proxy " +
70 70 "SET status=#{status} " +
71 71 "WHERE app=#{app} AND stream=#{stream}")
72 72 int updateStatus(String app, String stream, boolean status);
73 73  
74   - @Delete("DELETE FROM stream_proxy WHERE enable_remove_none_reader=true AND mediaServerId=#{mediaServerId}")
  74 + @Delete("DELETE FROM wvp_stream_proxy WHERE enable_remove_none_reader=true AND media_server_id=#{mediaServerId}")
75 75 void deleteAutoRemoveItemByMediaServerId(String mediaServerId);
76 76  
77   - @Select("SELECT st.*, pgs.gbId, pgs.name, pgs.longitude, pgs.latitude FROM stream_proxy st LEFT JOIN gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable_remove_none_reader=true AND st.mediaServerId=#{mediaServerId} order by st.createTime desc")
78   - List<StreamProxyItem> selecAutoRemoveItemByMediaServerId(String mediaServerId);
  77 + @Select("SELECT st.*, pgs.gb_id, pgs.name, pgs.longitude, pgs.latitude FROM wvp_stream_proxy st LEFT join wvp_gb_stream pgs on st.app = pgs.app AND st.stream = pgs.stream WHERE st.enable_remove_none_reader=true AND st.media_server_id=#{mediaServerId} order by st.create_time desc")
  78 + List<StreamProxyItem> selectAutoRemoveItemByMediaServerId(String mediaServerId);
79 79  
80   - @Select("select count(1) as total, sum(status) as online from stream_proxy")
81   - ResourceBaceInfo getOverview();
  80 + @Select("select count(1) as total, sum(status) as online from wvp_stream_proxy")
  81 + ResourceBaseInfo getOverview();
  82 +
  83 + @Select("select count(1) from wvp_stream_proxy")
  84 +
  85 + int getAllCount();
  86 +
  87 + @Select("select count(1) from wvp_stream_proxy where status = true")
  88 + int getOnline();
82 89 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
... ... @@ -3,54 +3,51 @@ package com.genersoft.iot.vmp.storager.dao;
3 3 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
4 4 import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
5 5 import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis;
6   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
7 6 import org.apache.ibatis.annotations.*;
8   -// import org.omg.PortableInterceptor.INACTIVE;
9 7 import org.springframework.stereotype.Repository;
10 8  
11   -import java.util.Collection;
12 9 import java.util.List;
13 10  
14 11 @Mapper
15 12 @Repository
16 13 public interface StreamPushMapper {
17 14  
18   - @Insert("INSERT INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
19   - "pushTime, aliveSecond, mediaServerId, serverId, updateTime, createTime, pushIng, self) VALUES" +
  15 + @Insert("INSERT INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " +
  16 + "push_time, alive_second, media_server_id, update_time, create_time, push_ing, self) VALUES" +
20 17 "(#{app}, #{stream}, #{totalReaderCount}, #{originType}, #{originTypeStr}, " +
21   - "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{serverId} , #{updateTime} , #{createTime}, " +
  18 + "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{updateTime} , #{createTime}, " +
22 19 "#{pushIng}, #{self} )")
23 20 int add(StreamPushItem streamPushItem);
24 21  
25 22  
26 23 @Update(value = {" <script>" +
27   - "UPDATE stream_push " +
28   - "SET updateTime=#{updateTime}" +
29   - "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" +
30   - "<if test=\"totalReaderCount != null\">, totalReaderCount=#{totalReaderCount}</if>" +
31   - "<if test=\"originType != null\">, originType=#{originType}</if>" +
32   - "<if test=\"originTypeStr != null\">, originTypeStr=#{originTypeStr}</if>" +
33   - "<if test=\"pushTime != null\">, pushTime=#{pushTime}</if>" +
34   - "<if test=\"aliveSecond != null\">, aliveSecond=#{aliveSecond}</if>" +
35   - "<if test=\"pushIng != null\">, pushIng=#{pushIng}</if>" +
  24 + "UPDATE wvp_stream_push " +
  25 + "SET update_time=#{updateTime}" +
  26 + "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" +
  27 + "<if test=\"totalReaderCount != null\">, total_reader_count=#{totalReaderCount}</if>" +
  28 + "<if test=\"originType != null\">, origin_type=#{originType}</if>" +
  29 + "<if test=\"originTypeStr != null\">, origin_type_str=#{originTypeStr}</if>" +
  30 + "<if test=\"pushTime != null\">, push_time=#{pushTime}</if>" +
  31 + "<if test=\"aliveSecond != null\">, alive_second=#{aliveSecond}</if>" +
  32 + "<if test=\"pushIng != null\">, push_ing=#{pushIng}</if>" +
36 33 "<if test=\"self != null\">, self=#{self}</if>" +
37 34 "WHERE app=#{app} AND stream=#{stream}"+
38 35 " </script>"})
39 36 int update(StreamPushItem streamPushItem);
40 37  
41   - @Delete("DELETE FROM stream_push WHERE app=#{app} AND stream=#{stream}")
  38 + @Delete("DELETE FROM wvp_stream_push WHERE app=#{app} AND stream=#{stream}")
42 39 int del(String app, String stream);
43 40  
44 41 @Delete("<script> "+
45   - "DELETE sp FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where " +
  42 + "DELETE sp FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where " +
46 43 "<foreach collection='streamPushItems' item='item' separator='or'>" +
47   - "(sp.app=#{item.app} and sp.stream=#{item.stream} and gs.gbId is null) " +
  44 + "(sp.app=#{item.app} and sp.stream=#{item.stream} and gs.gb_id is null) " +
48 45 "</foreach>" +
49 46 "</script>")
50 47 int delAllWithoutGBId(List<StreamPushItem> streamPushItems);
51 48  
52 49 @Delete("<script> "+
53   - "DELETE FROM stream_push where " +
  50 + "DELETE FROM wvp_stream_push where " +
54 51 "<foreach collection='streamPushItems' item='item' separator='or'>" +
55 52 "(app=#{item.app} and stream=#{item.stream}) " +
56 53 "</foreach>" +
... ... @@ -58,7 +55,7 @@ public interface StreamPushMapper {
58 55 int delAll(List<StreamPushItem> streamPushItems);
59 56  
60 57 @Delete("<script> "+
61   - "DELETE FROM stream_push where " +
  58 + "DELETE FROM wvp_stream_push where " +
62 59 "<foreach collection='gbStreams' item='item' separator='or'>" +
63 60 "(app=#{item.app} and stream=#{item.stream}) " +
64 61 "</foreach>" +
... ... @@ -69,30 +66,30 @@ public interface StreamPushMapper {
69 66 @Select(value = {" <script>" +
70 67 "SELECT " +
71 68 "st.*, " +
72   - "gs.gbId, gs.name, gs.longitude, gs.latitude, gs.gbStreamId " +
  69 + "gs.gb_id, gs.name, gs.longitude, gs.latitude, gs.gb_stream_id " +
73 70 "from " +
74   - "stream_push st " +
75   - "LEFT JOIN gb_stream gs " +
  71 + "wvp_stream_push st " +
  72 + "LEFT join wvp_gb_stream gs " +
76 73 "on st.app = gs.app AND st.stream = gs.stream " +
77 74 "WHERE " +
78 75 "1=1 " +
79   - " <if test='query != null'> AND (st.app LIKE concat('%',#{query},'%') OR st.stream LIKE concat('%',#{query},'%') OR gs.gbId LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
80   - " <if test='pushing == true' > AND (gs.gbId is null OR st.pushIng=1)</if>" +
81   - " <if test='pushing == false' > AND (st.pushIng is null OR st.pushIng=0) </if>" +
82   - " <if test='mediaServerId != null' > AND st.mediaServerId=#{mediaServerId} </if>" +
83   - "order by st.createTime desc" +
  76 + " <if test='query != null'> AND (st.app LIKE concat('%',#{query},'%') OR st.stream LIKE concat('%',#{query},'%') OR gs.gb_id LIKE concat('%',#{query},'%') OR gs.name LIKE concat('%',#{query},'%'))</if> " +
  77 + " <if test='pushing == true' > AND (gs.gb_id is null OR st.push_ing=1)</if>" +
  78 + " <if test='pushing == false' > AND (st.push_ing is null OR st.push_ing=0) </if>" +
  79 + " <if test='mediaServerId != null' > AND st.media_server_id=#{mediaServerId} </if>" +
  80 + "order by st.create_time desc" +
84 81 " </script>"})
85 82 List<StreamPushItem> selectAllForList(String query, Boolean pushing, String mediaServerId);
86 83  
87   - @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.createTime desc")
  84 + @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream order by st.create_time desc")
88 85 List<StreamPushItem> selectAll();
89 86  
90   - @Select("SELECT st.*, gs.gbId, gs.name, gs.longitude, gs.latitude FROM stream_push st LEFT JOIN gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
  87 + @Select("SELECT st.*, gs.gb_id, gs.name, gs.longitude, gs.latitude FROM wvp_stream_push st LEFT join wvp_gb_stream gs on st.app = gs.app AND st.stream = gs.stream WHERE st.app=#{app} AND st.stream=#{stream}")
91 88 StreamPushItem selectOne(String app, String stream);
92 89  
93 90 @Insert("<script>" +
94   - "Insert IGNORE INTO stream_push (app, stream, totalReaderCount, originType, originTypeStr, " +
95   - "createTime, aliveSecond, mediaServerId, status, pushIng) " +
  91 + "Insert INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " +
  92 + "create_time, alive_second, media_server_id, status, push_ing) " +
96 93 "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" +
97 94 "( #{item.app}, #{item.stream}, #{item.totalReaderCount}, #{item.originType}, " +
98 95 "#{item.originTypeStr},#{item.createTime}, #{item.aliveSecond}, #{item.mediaServerId}, #{item.status} ," +
... ... @@ -102,37 +99,45 @@ public interface StreamPushMapper {
102 99 @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
103 100 int addAll(List<StreamPushItem> streamPushItems);
104 101  
105   - @Delete("DELETE FROM stream_push")
  102 + @Delete("DELETE FROM wvp_stream_push")
106 103 void clear();
107 104  
108   - @Delete("DELETE sp FROM stream_push sp left join gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.mediaServerId=#{mediaServerId} and gs.gbId is null ")
  105 + @Delete("delete" +
  106 + " from wvp_stream_push " +
  107 + " where id in " +
  108 + " (select temp.id from " +
  109 + " (select wgs.gb_stream_id as id " +
  110 + " from wvp_gb_stream wgs" +
  111 + " left join wvp_stream_push sp on sp.id = wgs.gb_stream_id" +
  112 + " where wgs.gb_id is null and wgs.media_server_id = #{mediaServerId}) temp)"
  113 + )
109 114 void deleteWithoutGBId(String mediaServerId);
110 115  
111   - @Select("SELECT * FROM stream_push WHERE mediaServerId=#{mediaServerId}")
  116 + @Select("SELECT * FROM wvp_stream_push WHERE media_server_id=#{mediaServerId}")
112 117 List<StreamPushItem> selectAllByMediaServerId(String mediaServerId);
113 118  
114   - @Select("SELECT sp.* FROM stream_push sp left join gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.mediaServerId=#{mediaServerId} and gs.gbId is null")
  119 + @Select("SELECT sp.* FROM wvp_stream_push sp left join wvp_gb_stream gs on gs.app = sp.app and gs.stream= sp.stream WHERE sp.media_server_id=#{mediaServerId} and gs.gb_id is null")
115 120 List<StreamPushItem> selectAllByMediaServerIdWithOutGbID(String mediaServerId);
116 121  
117   - @Update("UPDATE stream_push " +
  122 + @Update("UPDATE wvp_stream_push " +
118 123 "SET status=#{status} " +
119 124 "WHERE app=#{app} AND stream=#{stream}")
120 125 int updateStatus(String app, String stream, boolean status);
121 126  
122   - @Update("UPDATE stream_push " +
123   - "SET pushIng=#{pushIng} " +
  127 + @Update("UPDATE wvp_stream_push " +
  128 + "SET push_ing=#{pushIng} " +
124 129 "WHERE app=#{app} AND stream=#{stream}")
125 130 int updatePushStatus(String app, String stream, boolean pushIng);
126 131  
127   - @Update("UPDATE stream_push " +
  132 + @Update("UPDATE wvp_stream_push " +
128 133 "SET status=#{status} " +
129   - "WHERE mediaServerId=#{mediaServerId}")
  134 + "WHERE media_server_id=#{mediaServerId}")
130 135 void updateStatusByMediaServerId(String mediaServerId, boolean status);
131 136  
132 137  
133 138 @Select("<script> "+
134   - "SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
135   - "where sp.status = 1 and (gs.app, gs.stream) in (" +
  139 + "SELECT gs.* FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
  140 + "where sp.status = true and (gs.app, gs.stream) in (" +
136 141 "<foreach collection='offlineStreams' item='item' separator=','>" +
137 142 "(#{item.app}, #{item.stream}) " +
138 143 "</foreach>" +
... ... @@ -140,7 +145,7 @@ public interface StreamPushMapper {
140 145 List<GbStream> getOnlinePusherForGbInList(List<StreamPushItemFromRedis> offlineStreams);
141 146  
142 147 @Update("<script> "+
143   - "UPDATE stream_push SET status=0 where (app, stream) in (" +
  148 + "UPDATE wvp_stream_push SET status=0 where (app, stream) in (" +
144 149 "<foreach collection='offlineStreams' item='item' separator=','>" +
145 150 "(#{item.app}, #{item.stream}) " +
146 151 "</foreach>" +
... ... @@ -148,7 +153,7 @@ public interface StreamPushMapper {
148 153 void offline(List<StreamPushItemFromRedis> offlineStreams);
149 154  
150 155 @Select("<script> "+
151   - "SELECT * FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
  156 + "SELECT * FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream " +
152 157 "where sp.status = 0 and (gs.app, gs.stream) in (" +
153 158 "<foreach collection='onlineStreams' item='item' separator=','>" +
154 159 "(#{item.app}, #{item.stream}) " +
... ... @@ -157,25 +162,36 @@ public interface StreamPushMapper {
157 162 List<GbStream> getOfflinePusherForGbInList(List<StreamPushItemFromRedis> onlineStreams);
158 163  
159 164 @Update("<script> "+
160   - "UPDATE stream_push SET status=1 where (app, stream) in (" +
  165 + "UPDATE wvp_stream_push SET status=1 where (app, stream) in (" +
161 166 "<foreach collection='onlineStreams' item='item' separator=','>" +
162 167 "(#{item.app}, #{item.stream}) " +
163 168 "</foreach>" +
164 169 ")</script>")
165 170 void online(List<StreamPushItemFromRedis> onlineStreams);
166 171  
167   - @Select("SELECT gs.* FROM stream_push sp left join gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = 1")
  172 + @Select("SELECT gs.* FROM wvp_stream_push sp left join wvp_gb_stream gs on sp.app = gs.app AND sp.stream = gs.stream where sp.status = true")
168 173 List<GbStream> getOnlinePusherForGb();
169 174  
170   - @Update("UPDATE stream_push SET status=0")
  175 + @Update("UPDATE wvp_stream_push SET status=0")
171 176 void setAllStreamOffline();
172 177  
173   - @Select("SELECT CONCAT(app,stream) FROM gb_stream")
  178 + @Select("SELECT CONCAT(app,stream) from wvp_gb_stream")
174 179 List<String> getAllAppAndStream();
175 180  
  181 + @Select("select count(1) from wvp_stream_push ")
  182 + int getAllCount();
  183 +
176 184 @Select(value = {" <script>" +
177   - " <if test='pushIngAsOnline == true'> select count(1) as total, sum(pushIng) as online from stream_push </if>" +
178   - " <if test='pushIngAsOnline == false'> select count(1) as total, sum(status) as online from stream_push </if>" +
  185 + " <if test='pushIngAsOnline == true'> select count(1) from wvp_stream_push where push_ing = true </if>" +
  186 + " <if test='pushIngAsOnline == false'> select count(1)from wvp_stream_push where status = true </if>" +
179 187 " </script>"})
180   - ResourceBaceInfo getOverview(boolean pushIngAsOnline);
  188 + int getAllOnline(Boolean usePushingAsStatus);
  189 +
  190 + @Select("<script> " +
  191 + "select app, stream from wvp_stream_push where (app, stream) in " +
  192 + "<foreach collection='streamPushItems' item='item' separator=','>" +
  193 + "(#{item.app}, #{item.stream}) " +
  194 + "</foreach>" +
  195 + "</script>")
  196 + List<StreamPushItem> getListIn(List<StreamPushItem> streamPushItems);
181 197 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
... ... @@ -10,56 +10,50 @@ import java.util.List;
10 10 @Repository
11 11 public interface UserMapper {
12 12  
13   - @Insert("INSERT INTO user (username, password, roleId, pushKey, createTime, updateTime) VALUES" +
  13 + @Insert("INSERT INTO wvp_user (username, password, role_id, push_key, create_time, update_time) VALUES" +
14 14 "(#{username}, #{password}, #{role.id}, #{pushKey}, #{createTime}, #{updateTime})")
15 15 int add(User user);
16 16  
17 17 @Update(value = {" <script>" +
18   - "UPDATE user " +
19   - "SET updateTime=#{updateTime} " +
20   - "<if test=\"pushKey != null\">, pushKey=#{pushKey}</if>" +
21   - "<if test=\"role != null\">, roleId=#{role.id}</if>" +
  18 + "UPDATE wvp_user " +
  19 + "SET update_time=#{updateTime} " +
  20 + "<if test=\"pushKey != null\">, push_key=#{pushKey}</if>" +
  21 + "<if test=\"role != null\">, role_id=#{role.id}</if>" +
22 22 "<if test=\"password != null\">, password=#{password}</if>" +
23 23 "<if test=\"username != null\">, username=#{username}</if>" +
24 24 "WHERE id=#{id}" +
25 25 " </script>"})
26 26 int update(User user);
27 27  
28   - @Delete("DELETE FROM user WHERE id != 1 and id=#{id}")
  28 + @Delete("DELETE from wvp_user WHERE id != 1 and id=#{id}")
29 29 int delete(int id);
30 30  
31   - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.username=#{username} AND u.password=#{password}")
  31 + @Select("select u.*, r.id as role_id, r.name as roleName, r.authority as roleAuthority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.username=#{username} AND u.password=#{password}")
32 32 @Results(id = "roleMap", value = {
33   - @Result(column = "roleID", property = "role.id"),
34   - @Result(column = "roleName", property = "role.name"),
35   - @Result(column = "roleAuthority", property = "role.authority"),
36   - @Result(column = "roleCreateTime", property = "role.createTime"),
37   - @Result(column = "roleUpdateTime", property = "role.updateTime")
  33 + @Result(column = "role_id", property = "role.id"),
  34 + @Result(column = "role_name", property = "role.name"),
  35 + @Result(column = "role_authority", property = "role.authority"),
  36 + @Result(column = "role_create_time", property = "role.createTime"),
  37 + @Result(column = "role_update_time", property = "role.updateTime")
38 38 })
39 39 User select(String username, String password);
40 40  
41   - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.id=#{id}")
  41 + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.id=#{id}")
42 42 @ResultMap(value="roleMap")
43 43 User selectById(int id);
44 44  
45   - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id and u.username=#{username}")
  45 + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id and u.username=#{username}")
46 46 @ResultMap(value="roleMap")
47 47 User getUserByUsername(String username);
48 48  
49   - @Select("select u.*, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u, user_role r WHERE u.roleId=r.id")
  49 + @Select("select u.*, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u, wvp_user_role r WHERE u.role_id=r.id")
50 50 @ResultMap(value="roleMap")
51 51 List<User> selectAll();
52 52  
53   - @Select("select * from (select user.*, concat(concat(#{callId}, '_'), pushKey) as str1 from user) as u where md5(u.str1) = #{sign}")
54   - List<User> checkPushAuthorityByCallIdAndSign(String callId, String sign);
55   -
56   - @Select("select * from user where md5(pushKey) = #{sign}")
57   - List<User> checkPushAuthorityByCallId(String sign);
58   -
59   - @Select("select u.id, u.username,u.pushKey,u.roleId, r.id as roleID, r.name as roleName, r.authority as roleAuthority , r.createTime as roleCreateTime , r.updateTime as roleUpdateTime FROM user u join user_role r on u.roleId=r.id")
  53 + @Select("select u.id, u.username,u.push_key,u.role_id, r.id as role_id, r.name as role_name, r.authority as role_authority , r.create_time as role_create_time , r.update_time as role_update_time from wvp_user u join wvp_user_role r on u.role_id=r.id")
60 54 @ResultMap(value="roleMap")
61 55 List<User> getUsers();
62 56  
63   - @Update("update user set pushKey=#{pushKey} where id=#{id}")
  57 + @Update("UPDATE wvp_user set push_key=#{pushKey} where id=#{id}")
64 58 int changePushKey(int id, String pushKey);
65 59 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
... ... @@ -561,7 +561,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
561 561  
562 562 @Override
563 563 public boolean deviceIsOnline(String deviceId) {
564   - return getDevice(deviceId).getOnline() == 1;
  564 + return getDevice(deviceId).isOnLine();
565 565 }
566 566  
567 567  
... ... @@ -587,15 +587,6 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
587 587 }
588 588  
589 589 @Override
590   - public int getGbReceiveCount(String id) {
591   - String playKey = VideoManagerConstants.PLAYER_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*";
592   - String playBackKey = VideoManagerConstants.PLAY_BLACK_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*";
593   - String downloadKey = VideoManagerConstants.DOWNLOAD_PREFIX + "_" + userSetting.getServerId() + "_" + id + "_*";
594   -
595   - return RedisUtil.scan(redisTemplate, playKey).size() + RedisUtil.scan(redisTemplate, playBackKey).size() + RedisUtil.scan(redisTemplate, downloadKey).size();
596   - }
597   -
598   - @Override
599 590 public int getGbSendCount(String id) {
600 591 String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX
601 592 + userSetting.getServerId() + "_*_" + id + "_*";
... ... @@ -605,18 +596,29 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
605 596 @Override
606 597 public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) {
607 598 String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS;
608   - if (channelId == null) {
609   - logger.info("[redis通知] 推送设备状态, {}-{}", deviceId, online);
610   - }else {
611   - logger.info("[redis通知] 推送通道状态, {}/{}-{}", deviceId, channelId, online);
  599 + StringBuilder msg = new StringBuilder();
  600 + msg.append(deviceId);
  601 + if (channelId != null) {
  602 + msg.append(":").append(channelId);
612 603 }
  604 + msg.append(" ").append(online? "ON":"OFF");
  605 + logger.info("[redis通知] 推送状态-> {} ", msg);
  606 + // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号
  607 + stringRedisTemplate.convertAndSend(key, msg.toString());
  608 + }
  609 +
  610 + @Override
  611 + public void sendChannelAddOrDelete(String deviceId, String channelId, boolean add) {
  612 + String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS;
  613 +
613 614  
614 615 StringBuilder msg = new StringBuilder();
615 616 msg.append(deviceId);
616 617 if (channelId != null) {
617 618 msg.append(":").append(channelId);
618 619 }
619   - msg.append(" ").append(online? "ON":"OFF");
  620 + msg.append(" ").append(add? "ADD":"DELETE");
  621 + logger.info("[redis通知] 推送通道-> {}", msg);
620 622 // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号
621 623 stringRedisTemplate.convertAndSend(key, msg.toString());
622 624 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
... ... @@ -116,49 +116,61 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
116 116 TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
117 117 // 数据去重
118 118 List<DeviceChannel> channels = new ArrayList<>();
  119 +
  120 + List<DeviceChannel> updateChannels = new ArrayList<>();
  121 + List<DeviceChannel> addChannels = new ArrayList<>();
119 122 StringBuilder stringBuilder = new StringBuilder();
120 123 Map<String, Integer> subContMap = new HashMap<>();
121   - if (deviceChannelList.size() > 0) {
122   - // 数据去重
123   - Set<String> gbIdSet = new HashSet<>();
124   - for (DeviceChannel deviceChannel : deviceChannelList) {
125   - if (!gbIdSet.contains(deviceChannel.getChannelId())) {
126   - gbIdSet.add(deviceChannel.getChannelId());
127   - if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
128   - deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
129   - deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
130   - if (allChannelMap.get(deviceChannel.getChannelId()).getStatus() !=deviceChannel.getStatus()){
131   - List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
132   - if (!CollectionUtils.isEmpty(strings)){
133   - strings.forEach(platformId->{
134   - eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus()==1?CatalogEvent.ON:CatalogEvent.OFF);
135   - });
136   - }
137 124  
138   - }
139   - }
140   - channels.add(deviceChannel);
141   - if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
142   - if (subContMap.get(deviceChannel.getParentId()) == null) {
143   - subContMap.put(deviceChannel.getParentId(), 1);
144   - }else {
145   - Integer count = subContMap.get(deviceChannel.getParentId());
146   - subContMap.put(deviceChannel.getParentId(), count++);
147   - }
  125 + // 数据去重
  126 + Set<String> gbIdSet = new HashSet<>();
  127 + for (DeviceChannel deviceChannel : deviceChannelList) {
  128 + if (gbIdSet.contains(deviceChannel.getChannelId())) {
  129 + stringBuilder.append(deviceChannel.getChannelId()).append(",");
  130 + continue;
  131 + }
  132 + gbIdSet.add(deviceChannel.getChannelId());
  133 + if (allChannelMap.containsKey(deviceChannel.getChannelId())) {
  134 + deviceChannel.setStreamId(allChannelMap.get(deviceChannel.getChannelId()).getStreamId());
  135 + deviceChannel.setHasAudio(allChannelMap.get(deviceChannel.getChannelId()).isHasAudio());
  136 + if (allChannelMap.get(deviceChannel.getChannelId()).isStatus() !=deviceChannel.isStatus()){
  137 + List<String> strings = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getChannelId());
  138 + if (!CollectionUtils.isEmpty(strings)){
  139 + strings.forEach(platformId->{
  140 + eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.isStatus()?CatalogEvent.ON:CatalogEvent.OFF);
  141 + });
148 142 }
  143 +
  144 + }
  145 + deviceChannel.setUpdateTime(DateUtil.getNow());
  146 + updateChannels.add(deviceChannel);
  147 + }else {
  148 + deviceChannel.setCreateTime(DateUtil.getNow());
  149 + deviceChannel.setUpdateTime(DateUtil.getNow());
  150 + addChannels.add(deviceChannel);
  151 + }
  152 + channels.add(deviceChannel);
  153 + if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) {
  154 + if (subContMap.get(deviceChannel.getParentId()) == null) {
  155 + subContMap.put(deviceChannel.getParentId(), 1);
149 156 }else {
150   - stringBuilder.append(deviceChannel.getChannelId()).append(",");
  157 + Integer count = subContMap.get(deviceChannel.getParentId());
  158 + subContMap.put(deviceChannel.getParentId(), count++);
151 159 }
152 160 }
153   - if (channels.size() > 0) {
154   - for (DeviceChannel channel : channels) {
155   - if (subContMap.get(channel.getChannelId()) != null){
156   - channel.setSubCount(subContMap.get(channel.getChannelId()));
  161 + }
  162 + if (channels.size() > 0) {
  163 + for (DeviceChannel channel : channels) {
  164 + if (subContMap.get(channel.getChannelId()) != null){
  165 + Integer count = subContMap.get(channel.getChannelId());
  166 + if (count > 0) {
  167 + channel.setSubCount(count);
  168 + channel.setParental(1);
157 169 }
158 170 }
159 171 }
160   -
161 172 }
  173 +
162 174 if (stringBuilder.length() > 0) {
163 175 logger.info("[目录查询]收到的数据存在重复: {}" , stringBuilder);
164 176 }
... ... @@ -168,21 +180,36 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
168 180 }
169 181 try {
170 182 int cleanChannelsResult = deviceChannelMapper.cleanChannelsNotInList(deviceId, channels);
  183 +
171 184 int limitCount = 300;
172 185 boolean result = cleanChannelsResult < 0;
173   - if (!result && channels.size() > 0) {
174   - if (channels.size() > limitCount) {
175   - for (int i = 0; i < channels.size(); i += limitCount) {
  186 + if (!result && addChannels.size() > 0) {
  187 + if (addChannels.size() > limitCount) {
  188 + for (int i = 0; i < addChannels.size(); i += limitCount) {
  189 + int toIndex = i + limitCount;
  190 + if (i + limitCount > addChannels.size()) {
  191 + toIndex = addChannels.size();
  192 + }
  193 + result = result || deviceChannelMapper.batchAdd(addChannels.subList(i, toIndex)) < 0;
  194 + }
  195 + }else {
  196 + result = result || deviceChannelMapper.batchAdd(addChannels) < 0;
  197 + }
  198 + }
  199 + if (!result && updateChannels.size() > 0) {
  200 + if (updateChannels.size() > limitCount) {
  201 + for (int i = 0; i < updateChannels.size(); i += limitCount) {
176 202 int toIndex = i + limitCount;
177   - if (i + limitCount > channels.size()) {
178   - toIndex = channels.size();
  203 + if (i + limitCount > updateChannels.size()) {
  204 + toIndex = updateChannels.size();
179 205 }
180   - result = result || deviceChannelMapper.batchAddOrUpdate(channels.subList(i, toIndex)) < 0;
  206 + result = result || deviceChannelMapper.batchUpdate(updateChannels.subList(i, toIndex)) < 0;
181 207 }
182 208 }else {
183   - result = result || deviceChannelMapper.batchAddOrUpdate(channels) < 0;
  209 + result = result || deviceChannelMapper.batchUpdate(updateChannels) < 0;
184 210 }
185 211 }
  212 +
186 213 if (result) {
187 214 //事务回滚
188 215 dataSourceTransactionManager.rollback(transactionStatus);
... ... @@ -766,25 +793,49 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
766 793 if (platform == null) {
767 794 return 0;
768 795 }
769   - if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
770   - if (platform.getDeviceGBId().equals(platformCatalog.getParentId())) {
771   - // 第一层节点
772   - platformCatalog.setBusinessGroupId(platformCatalog.getId());
773   - platformCatalog.setParentId(platform.getDeviceGBId());
774   - }else {
775   - // 获取顶层的
776   - PlatformCatalog topCatalog = getTopCatalog(platformCatalog.getParentId(), platform.getDeviceGBId());
777   - platformCatalog.setBusinessGroupId(topCatalog.getId());
  796 + if (platformCatalog.getId().length() <= 8) {
  797 + platformCatalog.setCivilCode(platformCatalog.getParentId());
  798 + }else {
  799 + if (platformCatalog.getId().length() != 20) {
  800 + return 0;
778 801 }
779   - }
780   - if (platform.getTreeType().equals(TreeType.CIVIL_CODE)) {
781   - platformCatalog.setCivilCode(platformCatalog.getId());
782   - if (platformCatalog.getPlatformId().equals(platformCatalog.getParentId())) {
783   - // 第一层节点
784   - platformCatalog.setParentId(platform.getDeviceGBId());
  802 + if (platformCatalog.getParentId() != null) {
  803 + switch (Integer.parseInt(platformCatalog.getId().substring(10, 13))){
  804 + case 200:
  805 + case 215:
  806 + if (platformCatalog.getParentId().length() <= 8) {
  807 + platformCatalog.setCivilCode(platformCatalog.getParentId());
  808 + }else {
  809 + PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId());
  810 + if (catalog != null) {
  811 + platformCatalog.setCivilCode(catalog.getCivilCode());
  812 + }
  813 + }
  814 + break;
  815 + case 216:
  816 + if (platformCatalog.getParentId().length() <= 8) {
  817 + platformCatalog.setCivilCode(platformCatalog.getParentId());
  818 + }else {
  819 + PlatformCatalog catalog = catalogMapper.select(platformCatalog.getParentId());
  820 + if (catalog == null) {
  821 + logger.warn("[添加目录] 无法获取目录{}的CivilCode和BusinessGroupId", platformCatalog.getPlatformId());
  822 + break;
  823 + }
  824 + platformCatalog.setCivilCode(catalog.getCivilCode());
  825 + if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 215) {
  826 + platformCatalog.setBusinessGroupId(platformCatalog.getParentId());
  827 + }else {
  828 + if (Integer.parseInt(platformCatalog.getParentId().substring(10, 13)) == 216) {
  829 + platformCatalog.setBusinessGroupId(catalog.getBusinessGroupId());
  830 + }
  831 + }
  832 + }
  833 + break;
  834 + default:
  835 + break;
  836 + }
785 837 }
786 838 }
787   -
788 839 int result = catalogMapper.add(platformCatalog);
789 840 if (result > 0) {
790 841 DeviceChannel deviceChannel = getDeviceChannelByCatalog(platformCatalog);
... ... @@ -908,19 +959,14 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
908 959 DeviceChannel deviceChannel = new DeviceChannel();
909 960 deviceChannel.setChannelId(catalog.getId());
910 961 deviceChannel.setName(catalog.getName());
911   - deviceChannel.setLongitude(0.0);
912   - deviceChannel.setLatitude(0.0);
913 962 deviceChannel.setDeviceId(platform.getDeviceGBId());
914 963 deviceChannel.setManufacture("wvp-pro");
915   - deviceChannel.setStatus(1);
  964 + deviceChannel.setStatus(true);
916 965 deviceChannel.setParental(1);
917 966  
918 967 deviceChannel.setRegisterWay(1);
919   - // 行政区划应该是Domain的前八位
920   - if (platform.getTreeType().equals(TreeType.BUSINESS_GROUP)) {
921   - deviceChannel.setParentId(catalog.getParentId());
922   - deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
923   - }
  968 + deviceChannel.setParentId(catalog.getParentId());
  969 + deviceChannel.setBusinessGroupId(catalog.getBusinessGroupId());
924 970  
925 971 deviceChannel.setModel("live");
926 972 deviceChannel.setOwner("wvp-pro");
... ...
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
... ... @@ -32,11 +32,17 @@ public class DateUtil {
32 32 */
33 33 public static final String PATTERN = "yyyy-MM-dd HH:mm:ss";
34 34  
  35 + /**
  36 + * wvp内部统一时间格式
  37 + */
  38 + public static final String URL_PATTERN = "yyyyMMddHHmmss";
  39 +
35 40 public static final String zoneStr = "Asia/Shanghai";
36 41  
37 42 public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
38 43 public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
39 44 public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
  45 + public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
40 46  
41 47 public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) {
42 48  
... ... @@ -68,6 +74,15 @@ public class DateUtil {
68 74 }
69 75  
70 76 /**
  77 + * 获取当前时间
  78 + * @return
  79 + */
  80 + public static String getNowForUrl() {
  81 + LocalDateTime nowDateTime = LocalDateTime.now();
  82 + return urlFormatter.format(nowDateTime);
  83 + }
  84 +
  85 + /**
71 86 * 格式校验
72 87 * @param timeStr 时间字符串
73 88 * @param dateTimeFormatter 待校验的格式
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java
... ... @@ -6,7 +6,7 @@ package com.genersoft.iot.vmp.vmanager.bean;
6 6 public enum ErrorCode {
7 7 SUCCESS(0, "成功"),
8 8 ERROR100(100, "失败"),
9   - ERROR400(400, "参数不全或者错误"),
  9 + ERROR400(400, "参数或方法错误"),
10 10 ERROR404(404, "资源未找到"),
11 11 ERROR403(403, "无权限操作"),
12 12 ERROR401(401, "请登录后重新请求"),
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaceInfo.java renamed to src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java
1 1 package com.genersoft.iot.vmp.vmanager.bean;
2 2  
3   -public class ResourceBaceInfo {
  3 +public class ResourceBaseInfo {
4 4 private int total;
5 5 private int online;
6 6  
  7 + public ResourceBaseInfo() {
  8 + }
  9 +
  10 + public ResourceBaseInfo(int total, int online) {
  11 + this.total = total;
  12 + this.online = online;
  13 + }
  14 +
7 15 public int getTotal() {
8 16 return total;
9 17 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java
... ... @@ -2,40 +2,40 @@ package com.genersoft.iot.vmp.vmanager.bean;
2 2  
3 3 public class ResourceInfo {
4 4  
5   - private ResourceBaceInfo device;
6   - private ResourceBaceInfo channel;
7   - private ResourceBaceInfo push;
8   - private ResourceBaceInfo proxy;
  5 + private ResourceBaseInfo device;
  6 + private ResourceBaseInfo channel;
  7 + private ResourceBaseInfo push;
  8 + private ResourceBaseInfo proxy;
9 9  
10   - public ResourceBaceInfo getDevice() {
  10 + public ResourceBaseInfo getDevice() {
11 11 return device;
12 12 }
13 13  
14   - public void setDevice(ResourceBaceInfo device) {
  14 + public void setDevice(ResourceBaseInfo device) {
15 15 this.device = device;
16 16 }
17 17  
18   - public ResourceBaceInfo getChannel() {
  18 + public ResourceBaseInfo getChannel() {
19 19 return channel;
20 20 }
21 21  
22   - public void setChannel(ResourceBaceInfo channel) {
  22 + public void setChannel(ResourceBaseInfo channel) {
23 23 this.channel = channel;
24 24 }
25 25  
26   - public ResourceBaceInfo getPush() {
  26 + public ResourceBaseInfo getPush() {
27 27 return push;
28 28 }
29 29  
30   - public void setPush(ResourceBaceInfo push) {
  30 + public void setPush(ResourceBaseInfo push) {
31 31 this.push = push;
32 32 }
33 33  
34   - public ResourceBaceInfo getProxy() {
  34 + public ResourceBaseInfo getProxy() {
35 35 return proxy;
36 36 }
37 37  
38   - public void setProxy(ResourceBaceInfo proxy) {
  38 + public void setProxy(ResourceBaseInfo proxy) {
39 39 this.proxy = proxy;
40 40 }
41 41 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java 0 → 100644
  1 +package com.genersoft.iot.vmp.vmanager.bean;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +
  5 +@Schema(description = "截图地址信息")
  6 +public class SnapPath {
  7 +
  8 + @Schema(description = "相对地址")
  9 + private String path;
  10 +
  11 + @Schema(description = "绝对地址")
  12 + private String absoluteFilePath;
  13 +
  14 + @Schema(description = "请求地址")
  15 + private String url;
  16 +
  17 +
  18 + public static SnapPath getInstance(String path, String absoluteFilePath, String url) {
  19 + SnapPath snapPath = new SnapPath();
  20 + snapPath.setPath(path);
  21 + snapPath.setAbsoluteFilePath(absoluteFilePath);
  22 + snapPath.setUrl(url);
  23 + return snapPath;
  24 + }
  25 +
  26 +
  27 + public String getPath() {
  28 + return path;
  29 + }
  30 +
  31 + public void setPath(String path) {
  32 + this.path = path;
  33 + }
  34 +
  35 + public String getAbsoluteFilePath() {
  36 + return absoluteFilePath;
  37 + }
  38 +
  39 + public void setAbsoluteFilePath(String absoluteFilePath) {
  40 + this.absoluteFilePath = absoluteFilePath;
  41 + }
  42 +
  43 + public String getUrl() {
  44 + return url;
  45 + }
  46 +
  47 + public void setUrl(String url) {
  48 + this.url = url;
  49 + }
  50 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
... ... @@ -102,7 +102,7 @@ public class MobilePositionController {
102 102 public DeferredResult<MobilePosition> realTimePosition(@PathVariable String deviceId) {
103 103 Device device = storager.queryVideoDevice(deviceId);
104 104 String uuid = UUID.randomUUID().toString();
105   - String key = DeferredResultHolder.CALLBACK_CMD_MOBILEPOSITION + deviceId;
  105 + String key = DeferredResultHolder.CALLBACK_CMD_MOBILE_POSITION + deviceId;
106 106 try {
107 107 cmder.mobilePostitionQuery(device, event -> {
108 108 RequestMessage msg = new RequestMessage();
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
... ... @@ -466,10 +466,12 @@ public class DeviceQuery {
466 466 @Operation(summary = "请求截图")
467 467 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
468 468 @Parameter(name = "channelId", description = "通道国标编号", required = true)
469   - public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) {
  469 + @Parameter(name = "mark", description = "标识", required = false)
  470 + public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId, @RequestParam(required = false) String mark) {
470 471  
471 472 try {
472   - final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath());
  473 +
  474 + final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + (mark == null? ".jpg": ("_" + mark + ".jpg"))).toPath());
473 475 resp.setContentType(MediaType.IMAGE_PNG_VALUE);
474 476 IOUtils.copy(in, resp.getOutputStream());
475 477 } catch (IOException e) {
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
... ... @@ -403,8 +403,12 @@ public class PlatformController {
403 403 if (platform == null) {
404 404 throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台未找到");
405 405 }
406   - if (platformId.equals(parentId)) {
407   - parentId = platform.getDeviceGBId();
  406 +// if (platformId.equals(parentId)) {
  407 +// parentId = platform.getDeviceGBId();
  408 +// }
  409 +
  410 + if (platformId.equals(platform.getDeviceGBId())) {
  411 + parentId = null;
408 412 }
409 413  
410 414 return storager.getChildrenCatalogByPlatform(platformId, parentId);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
... ... @@ -24,6 +24,7 @@ import com.genersoft.iot.vmp.service.IPlayService;
24 24 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
25 25 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
26 26 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  27 +import com.genersoft.iot.vmp.utils.DateUtil;
27 28 import com.genersoft.iot.vmp.vmanager.bean.*;
28 29 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
29 30 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
... ... @@ -129,7 +130,7 @@ public class PlayController {
129 130 if (data != null) {
130 131 StreamInfo streamInfo = (StreamInfo)data;
131 132 if (userSetting.getUseSourceIpAsStreamIp()) {
132   - streamInfo.channgeStreamIp(request.getLocalName());
  133 + streamInfo.channgeStreamIp(request.getLocalAddr());
133 134 }
134 135 wvpResult.setData(new StreamContent(streamInfo));
135 136 }
... ... @@ -146,8 +147,9 @@ public class PlayController {
146 147 @Operation(summary = "停止点播")
147 148 @Parameter(name = "deviceId", description = "设备国标编号", required = true)
148 149 @Parameter(name = "channelId", description = "通道国标编号", required = true)
  150 + @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true)
149 151 @GetMapping("/stop/{deviceId}/{channelId}")
150   - public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId) {
  152 + public JSONObject playStop(@PathVariable String deviceId, @PathVariable String channelId,boolean isSubStream) {
151 153  
152 154 logger.debug(String.format("设备预览/回放停止API调用,streamId:%s_%s", deviceId, channelId ));
153 155  
... ... @@ -174,11 +176,12 @@ public class PlayController {
174 176 }
175 177 }
176 178 inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
177   -
178 179 storager.stopPlay(deviceId, channelId);
  180 +
179 181 JSONObject json = new JSONObject();
180 182 json.put("deviceId", deviceId);
181 183 json.put("channelId", channelId);
  184 + json.put("isSubStream", isSubStream);
182 185 return json;
183 186 }
184 187  
... ... @@ -316,5 +319,36 @@ public class PlayController {
316 319 return jsonObject;
317 320 }
318 321  
  322 + @Operation(summary = "获取截图")
  323 + @Parameter(name = "deviceId", description = "设备国标编号", required = true)
  324 + @Parameter(name = "channelId", description = "通道国标编号", required = true)
  325 + @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true)
  326 + @GetMapping("/snap")
  327 + public DeferredResult<String> getSnap(String deviceId, String channelId,boolean isSubStream) {
  328 + if (logger.isDebugEnabled()) {
  329 + logger.debug("获取截图: {}/{}", deviceId, channelId);
  330 + }
  331 +
  332 + DeferredResult<String> result = new DeferredResult<>(3 * 1000L);
  333 + String key = DeferredResultHolder.CALLBACK_CMD_SNAP + deviceId;
  334 + String uuid = UUID.randomUUID().toString();
  335 + resultHolder.put(key, uuid, result);
  336 +
  337 + RequestMessage message = new RequestMessage();
  338 + message.setKey(key);
  339 + message.setId(uuid);
  340 +
  341 + String fileName = deviceId + "_" + channelId + "_" + DateUtil.getNowForUrl() + "jpg";
  342 + playService.getSnap(deviceId, channelId, fileName, (code, msg, data) -> {
  343 + if (code == InviteErrorCode.SUCCESS.getCode()) {
  344 + message.setData(data);
  345 + }else {
  346 + message.setData(WVPResult.fail(code, msg));
  347 + }
  348 + resultHolder.invokeResult(message);
  349 + });
  350 + return result;
  351 + }
  352 +
319 353 }
320 354  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
... ... @@ -107,7 +107,7 @@ public class PlaybackController {
107 107 if (data != null) {
108 108 StreamInfo streamInfo = (StreamInfo)data;
109 109 if (userSetting.getUseSourceIpAsStreamIp()) {
110   - streamInfo.channgeStreamIp(request.getLocalName());
  110 + streamInfo.channgeStreamIp(request.getLocalAddr());
111 111 }
112 112 wvpResult.setData(new StreamContent(streamInfo));
113 113 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
... ... @@ -149,7 +149,7 @@ public class GBRecordController {
149 149 if (data != null) {
150 150 StreamInfo streamInfo = (StreamInfo)data;
151 151 if (userSetting.getUseSourceIpAsStreamIp()) {
152   - streamInfo.channgeStreamIp(request.getLocalName());
  152 + streamInfo.channgeStreamIp(request.getLocalAddr());
153 153 }
154 154 wvpResult.setData(new StreamContent(streamInfo));
155 155 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
... ... @@ -15,7 +15,7 @@ import com.genersoft.iot.vmp.service.*;
15 15 import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
16 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
17 17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
18   -import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
  18 +import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo;
19 19 import com.genersoft.iot.vmp.vmanager.bean.ResourceInfo;
20 20 import com.genersoft.iot.vmp.vmanager.bean.SystemConfigInfo;
21 21 import io.swagger.v3.oas.annotations.Operation;
... ... @@ -251,13 +251,13 @@ public class ServerController {
251 251 @Operation(summary = "获取负载信息")
252 252 public ResourceInfo getResourceInfo() {
253 253 ResourceInfo result = new ResourceInfo();
254   - ResourceBaceInfo deviceInfo = deviceService.getOverview();
  254 + ResourceBaseInfo deviceInfo = deviceService.getOverview();
255 255 result.setDevice(deviceInfo);
256   - ResourceBaceInfo channelInfo = channelService.getOverview();
  256 + ResourceBaseInfo channelInfo = channelService.getOverview();
257 257 result.setChannel(channelInfo);
258   - ResourceBaceInfo pushInfo = pushService.getOverview();
  258 + ResourceBaseInfo pushInfo = pushService.getOverview();
259 259 result.setPush(pushInfo);
260   - ResourceBaceInfo proxyInfo = proxyService.getOverview();
  260 + ResourceBaseInfo proxyInfo = proxyService.getOverview();
261 261 result.setProxy(proxyInfo);
262 262  
263 263 return result;
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java
1 1 package com.genersoft.iot.vmp.vmanager.streamProxy;
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.conf.UserSetting;
4 6 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  8 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
5 9 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 10 import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
7 11 import com.genersoft.iot.vmp.service.IMediaServerService;
8 12 import com.genersoft.iot.vmp.service.IStreamProxyService;
9 13 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
10 14 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
  15 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
11 16 import com.github.pagehelper.PageInfo;
12 17 import io.swagger.v3.oas.annotations.Operation;
13 18 import io.swagger.v3.oas.annotations.Parameter;
... ... @@ -18,6 +23,9 @@ import org.springframework.beans.factory.annotation.Autowired;
18 23 import org.springframework.stereotype.Controller;
19 24 import org.springframework.util.ObjectUtils;
20 25 import org.springframework.web.bind.annotation.*;
  26 +import org.springframework.web.context.request.async.DeferredResult;
  27 +
  28 +import java.util.UUID;
21 29  
22 30 @SuppressWarnings("rawtypes")
23 31 /**
... ... @@ -37,6 +45,12 @@ public class StreamProxyController {
37 45 @Autowired
38 46 private IStreamProxyService streamProxyService;
39 47  
  48 + @Autowired
  49 + private DeferredResultHolder resultHolder;
  50 +
  51 + @Autowired
  52 + private UserSetting userSetting;
  53 +
40 54  
41 55 @Operation(summary = "分页查询流代理")
42 56 @Parameter(name = "page", description = "当前页")
... ... @@ -58,7 +72,7 @@ public class StreamProxyController {
58 72 })
59 73 @PostMapping(value = "/save")
60 74 @ResponseBody
61   - public StreamContent save(@RequestBody StreamProxyItem param){
  75 + public DeferredResult<Object> save(@RequestBody StreamProxyItem param){
62 76 logger.info("添加代理: " + JSONObject.toJSONString(param));
63 77 if (ObjectUtils.isEmpty(param.getMediaServerId())) {
64 78 param.setMediaServerId("auto");
... ... @@ -69,7 +83,33 @@ public class StreamProxyController {
69 83 if (ObjectUtils.isEmpty(param.getGbId())) {
70 84 param.setGbId(null);
71 85 }
72   - return new StreamContent(streamProxyService.save(param));
  86 +
  87 + RequestMessage requestMessage = new RequestMessage();
  88 + String key = DeferredResultHolder.CALLBACK_CMD_PROXY + param.getApp() + param.getStream();
  89 + requestMessage.setKey(key);
  90 + String uuid = UUID.randomUUID().toString();
  91 + requestMessage.setId(uuid);
  92 + DeferredResult<Object> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  93 + // 录像查询以channelId作为deviceId查询
  94 + resultHolder.put(key, uuid, result);
  95 + result.onTimeout(()->{
  96 + WVPResult<StreamInfo> wvpResult = new WVPResult<>();
  97 + wvpResult.setCode(ErrorCode.ERROR100.getCode());
  98 + wvpResult.setMsg("超时");
  99 + requestMessage.setData(wvpResult);
  100 + resultHolder.invokeAllResult(requestMessage);
  101 + });
  102 +
  103 + streamProxyService.save(param, (code, msg, streamInfo) -> {
  104 + logger.info("[拉流代理] {}", code == ErrorCode.SUCCESS.getCode()? "成功":"失败: " + msg);
  105 + if (code == ErrorCode.SUCCESS.getCode()) {
  106 + requestMessage.setData(new StreamContent(streamInfo));
  107 + }else {
  108 + requestMessage.setData(WVPResult.fail(code, msg));
  109 + }
  110 + resultHolder.invokeAllResult(requestMessage);
  111 + });
  112 + return result;
73 113 }
74 114  
75 115 @GetMapping(value = "/ffmpeg_cmd/list")
... ...
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiDeviceController.java
... ... @@ -89,7 +89,7 @@ public class ApiDeviceController {
89 89 deviceJsonObject.put("RecvStreamIP", "");
90 90 deviceJsonObject.put("CatalogInterval", 3600); // 通道目录抓取周期
91 91 deviceJsonObject.put("SubscribeInterval", device.getSubscribeCycleForCatalog()); // 订阅周期(秒), 0 表示后台不周期订阅
92   - deviceJsonObject.put("Online", device.getOnline() == 1);
  92 + deviceJsonObject.put("Online", device.isOnLine());
93 93 deviceJsonObject.put("Password", "");
94 94 deviceJsonObject.put("MediaTransport", device.getTransport());
95 95 deviceJsonObject.put("RemoteIP", device.getIp());
... ... @@ -147,7 +147,7 @@ public class ApiDeviceController {
147 147 deviceJOSNChannel.put("ID", deviceChannelExtend.getChannelId());
148 148 deviceJOSNChannel.put("DeviceID", deviceChannelExtend.getDeviceId());
149 149 deviceJOSNChannel.put("DeviceName", deviceChannelExtend.getDeviceName());
150   - deviceJOSNChannel.put("DeviceOnline", deviceChannelExtend.getDeviceOnline() == 1);
  150 + deviceJOSNChannel.put("DeviceOnline", deviceChannelExtend.isDeviceOnline());
151 151 deviceJOSNChannel.put("Channel", 0); // TODO 自定义序号
152 152 deviceJOSNChannel.put("Name", deviceChannelExtend.getName());
153 153 deviceJOSNChannel.put("Custom", false);
... ... @@ -166,7 +166,7 @@ public class ApiDeviceController {
166 166 // 1-IETF RFC3261,
167 167 // 2-基于口令的双向认证,
168 168 // 3-基于数字证书的双向认证
169   - deviceJOSNChannel.put("Status", deviceChannelExtend.getStatus() == 1 ? "ON":"OFF");
  169 + deviceJOSNChannel.put("Status", deviceChannelExtend.isStatus() ? "ON":"OFF");
170 170 deviceJOSNChannel.put("Longitude", deviceChannelExtend.getLongitude());
171 171 deviceJOSNChannel.put("Latitude", deviceChannelExtend.getLatitude());
172 172 deviceJOSNChannel.put("PTZType ", deviceChannelExtend.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
... ...
src/main/java/com/genersoft/iot/vmp/web/gb28181/ApiStreamController.java
... ... @@ -92,7 +92,7 @@ public class ApiStreamController {
92 92 result.put("error","device[ " + serial + " ]未找到");
93 93 resultDeferredResult.setResult(result);
94 94 return resultDeferredResult;
95   - }else if (device.getOnline() == 0) {
  95 + }else if (!device.isOnLine()) {
96 96 JSONObject result = new JSONObject();
97 97 result.put("error","device[ " + code + " ]offline");
98 98 resultDeferredResult.setResult(result);
... ... @@ -113,7 +113,7 @@ public class ApiStreamController {
113 113 result.put("error","channel[ " + code + " ]未找到");
114 114 resultDeferredResult.setResult(result);
115 115 return resultDeferredResult;
116   - }else if (deviceChannel.getStatus() == 0) {
  116 + }else if (!deviceChannel.isStatus()) {
117 117 JSONObject result = new JSONObject();
118 118 result.put("error","channel[ " + code + " ]offline");
119 119 resultDeferredResult.setResult(result);
... ...
src/main/java/com/genersoft/iot/vmp/web/gb28181/dto/DeviceChannelExtend.java
... ... @@ -25,7 +25,7 @@ public class DeviceChannelExtend {
25 25  
26 26 private String deviceName;
27 27  
28   - private int deviceOnline;
  28 + private boolean deviceOnline;
29 29  
30 30 /**
31 31 * 生产厂商
... ... @@ -146,7 +146,7 @@ public class DeviceChannelExtend {
146 146 * <Status>OFF</Status>
147 147 * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
148 148 */
149   - private int status;
  149 + private boolean status;
150 150  
151 151 /**
152 152 * 经度
... ... @@ -417,11 +417,11 @@ public class DeviceChannelExtend {
417 417 this.PTZTypeText = PTZTypeText;
418 418 }
419 419  
420   - public int getStatus() {
  420 + public boolean isStatus() {
421 421 return status;
422 422 }
423 423  
424   - public void setStatus(int status) {
  424 + public void setStatus(boolean status) {
425 425 this.status = status;
426 426 }
427 427  
... ... @@ -545,11 +545,11 @@ public class DeviceChannelExtend {
545 545 this.deviceName = deviceName;
546 546 }
547 547  
548   - public int getDeviceOnline() {
  548 + public boolean isDeviceOnline() {
549 549 return deviceOnline;
550 550 }
551 551  
552   - public void setDeviceOnline(int deviceOnline) {
  552 + public void setDeviceOnline(boolean deviceOnline) {
553 553 this.deviceOnline = deviceOnline;
554 554 }
555 555 }
... ...
src/main/resources/all-application.yml
... ... @@ -44,6 +44,10 @@ spring:
44 44 max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位)
45 45  
46 46  
  47 +# 修改分页插件为 postgresql, 数据库类型为mysql不需要
  48 +#pagehelper:
  49 +# helper-dialect: postgresql
  50 +
47 51 # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
48 52 server:
49 53 port: 18080
... ... @@ -188,6 +192,8 @@ user-settings:
188 192 sip-use-source-ip-as-remote-address: false
189 193 # 是否开启sip日志
190 194 sip-log: true
  195 + # 是否开启sql日志
  196 + sql-log: true
191 197 # 收到ack消息后开始发流,默认false, 回复200ok后直接开始发流
192 198 push-stream-after-ack: false
193 199 # 消息通道功能-缺少国标ID是否给所有上级发送消息
... ... @@ -200,6 +206,10 @@ user-settings:
200 206 device-status-notify: false
201 207 # 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式
202 208 use-custom-ssrc-for-parent-invite: true
  209 + # 国标级联离线后多久重试一次注册
  210 + register-again-after-time: 60
  211 + # 国标续订方式,true为续订,每次注册在同一个会话里,false为重新注册,每次使用新的会话
  212 + register-keep-int-dialog: false
203 213 # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
204 214 allowed-origins:
205 215 - http://localhost:8008
... ...
src/main/resources/application-dev.yml
1 1 spring:
  2 + thymeleaf:
  3 + cache: false
2 4 # [可选]上传文件大小限制
3 5 servlet:
4 6 multipart:
... ... @@ -11,18 +13,18 @@ spring:
11 13 # [必须修改] 端口号
12 14 port: 6379
13 15 # [可选] 数据库 DB
14   - database: 6
  16 + database: 7
15 17 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
16   - password: face2020
  18 + password:
17 19 # [可选] 超时时间
18 20 timeout: 10000
19 21 # mysql数据源
20 22 datasource:
21 23 type: com.zaxxer.hikari.HikariDataSource
22 24 driver-class-name: com.mysql.cj.jdbc.Driver
23   - url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
  25 + url: jdbc:mysql://127.0.0.1:3306/test_gb-89wulian?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
24 26 username: root
25   - password: 123456
  27 + password: root
26 28 hikari:
27 29 connection-timeout: 20000 # 是客户端等待连接池连接的最大毫秒数
28 30 initialSize: 10 # 连接池初始化连接数
... ... @@ -30,11 +32,19 @@ spring:
30 32 minimum-idle: 5 # 连接池最小空闲连接数
31 33 idle-timeout: 300000 # 允许连接在连接池中空闲的最长时间(以毫秒为单位)
32 34 max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位)
33   -
34   -
35 35 #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
36 36 server:
37   - port: 18080
  37 + port: 18978
  38 + # [可选] HTTPS配置, 默认不开启
  39 + ssl:
  40 + # [可选] 是否开启HTTPS访问
  41 + enabled: false
  42 + # [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名
  43 + key-store: classpath:test.monitor.89iot.cn.jks
  44 + # [可选] 证书密码
  45 + key-store-password: gpf64qmw
  46 + # [可选] 证书类型, 默认为jks,根据实际修改
  47 + key-store-type: JKS
38 48  
39 49 # 作为28181服务器的配置
40 50 sip:
... ... @@ -42,26 +52,36 @@ sip:
42 52 # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
43 53 # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
44 54 # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
45   - ip: 192.168.41.16
  55 + ip: 192.168.1.18
46 56 # [可选] 28181服务监听的端口
47   - port: 5060
  57 + port: 8116
48 58 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
49 59 # 后两位为行业编码,定义参照附录D.3
50 60 # 3701020049标识山东济南历下区 信息行业接入
51 61 # [可选]
52   - domain: 4401020049
  62 + domain: 4101050000
53 63 # [可选]
54   - id: 44010200492000000001
  64 + id: 41010500002000000001
55 65 # [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
56   - password: admin123
  66 + password: bajiuwulian1006
  67 + # 是否存储alarm信息
  68 + alarm: true
57 69  
58 70 #zlm 默认服务器配置
59 71 media:
60   - id: FQ3TF8yT83wh5Wvz
  72 + id: 89wulian-one
61 73 # [必须修改] zlm服务器的内网IP
62   - ip: 192.168.41.16
  74 + ip: 192.168.1.18
63 75 # [必须修改] zlm服务器的http.port
64   - http-port: 8091
  76 + http-port: 80
  77 + # [可选] 返回流地址时的ip,置空使用 media.ip
  78 + stream-ip: 192.168.1.18
  79 + # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip
  80 + sdp-ip: 192.168.1.18
  81 + # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
  82 + hook-ip: 192.168.1.18
  83 + # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置
  84 + http-ssl-port: 443
65 85 # [可选] zlm服务器的hook.admin_params=secret
66 86 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
67 87 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
... ... @@ -69,11 +89,24 @@ media:
69 89 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
70 90 enable: true
71 91 # [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性,不然自动配置此属性可能不成功
72   - port-range: 30000,30500 # 端口范围
  92 + port-range: 50000,50300 # 端口范围
73 93 # [可选] 国标级联在此范围内选择端口发送媒体流,
74   - send-port-range: 30000,30500 # 端口范围
  94 + send-port-range: 50000,50300 # 端口范围
75 95 # 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用
76 96 record-assist-port: 18081
  97 +# [根据业务需求配置]
  98 +user-settings:
  99 + # 点播/录像回放 等待超时时间,单位:毫秒
  100 + play-timeout: 180000
  101 + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
  102 + auto-apply-play: true
  103 + # 设备/通道状态变化时发送消息
  104 + device-status-notify: true
  105 + # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
  106 + allowed-origins:
  107 + - http://localhost:8080
  108 + - http://127.0.0.1:8080
77 109 # [可选] 日志配置, 一般不需要改
78 110 logging:
79 111 config: classpath:logback-spring-local.xml
  112 +
... ...
src/main/resources/civilCode.csv 0 → 100644
  1 +编号,名称,上级
  2 +11,北京市,
  3 +110101,东城区,11
  4 +110102,西城区,11
  5 +110105,朝阳区,11
  6 +110106,丰台区,11
  7 +110107,石景山区,11
  8 +110108,海淀区,11
  9 +110109,门头沟区,11
  10 +110111,房山区,11
  11 +110112,通州区,11
  12 +110113,顺义区,11
  13 +110114,昌平区,11
  14 +110115,大兴区,11
  15 +110116,怀柔区,11
  16 +110117,平谷区,11
  17 +110118,密云区,11
  18 +110119,延庆区,11
  19 +12,天津市,
  20 +120101,和平区,12
  21 +120102,河东区,12
  22 +120103,河西区,12
  23 +120104,南开区,12
  24 +120105,河北区,12
  25 +120106,红桥区,12
  26 +120110,东丽区,12
  27 +120111,西青区,12
  28 +120112,津南区,12
  29 +120113,北辰区,12
  30 +120114,武清区,12
  31 +120115,宝坻区,12
  32 +120116,滨海新区,12
  33 +120117,宁河区,12
  34 +120118,静海区,12
  35 +120119,蓟州区,12
  36 +13,河北省,
  37 +1301,石家庄市,13
  38 +130102,长安区,1301
  39 +130104,桥西区,1301
  40 +130105,新华区,1301
  41 +130107,井陉矿区,1301
  42 +130108,裕华区,1301
  43 +130109,藁城区,1301
  44 +130110,鹿泉区,1301
  45 +130111,栾城区,1301
  46 +130121,井陉县,1301
  47 +130123,正定县,1301
  48 +130125,行唐县,1301
  49 +130126,灵寿县,1301
  50 +130127,高邑县,1301
  51 +130128,深泽县,1301
  52 +130129,赞皇县,1301
  53 +130130,无极县,1301
  54 +130131,平山县,1301
  55 +130132,元氏县,1301
  56 +130133,赵县,1301
  57 +130181,辛集市,1301
  58 +130183,晋州市,1301
  59 +130184,新乐市,1301
  60 +1302,唐山市,13
  61 +130202,路南区,1302
  62 +130203,路北区,1302
  63 +130204,古冶区,1302
  64 +130205,开平区,1302
  65 +130207,丰南区,1302
  66 +130208,丰润区,1302
  67 +130209,曹妃甸区,1302
  68 +130224,滦南县,1302
  69 +130225,乐亭县,1302
  70 +130227,迁西县,1302
  71 +130229,玉田县,1302
  72 +130281,遵化市,1302
  73 +130283,迁安市,1302
  74 +130284,滦州市,1302
  75 +1303,秦皇岛市,13
  76 +130302,海港区,1303
  77 +130303,山海关区,1303
  78 +130304,北戴河区,1303
  79 +130306,抚宁区,1303
  80 +130321,青龙满族自治县,1303
  81 +130322,昌黎县,1303
  82 +130324,卢龙县,1303
  83 +1304,邯郸市,13
  84 +130402,邯山区,1304
  85 +130403,丛台区,1304
  86 +130404,复兴区,1304
  87 +130406,峰峰矿区,1304
  88 +130407,肥乡区,1304
  89 +130408,永年区,1304
  90 +130423,临漳县,1304
  91 +130424,成安县,1304
  92 +130425,大名县,1304
  93 +130426,涉县,1304
  94 +130427,磁县,1304
  95 +130430,邱县,1304
  96 +130431,鸡泽县,1304
  97 +130432,广平县,1304
  98 +130433,馆陶县,1304
  99 +130434,魏县,1304
  100 +130435,曲周县,1304
  101 +130481,武安市,1304
  102 +1305,邢台市,13
  103 +130502,桥东区,1305
  104 +130503,桥西区,1305
  105 +130521,邢台县,1305
  106 +130522,临城县,1305
  107 +130523,内丘县,1305
  108 +130524,柏乡县,1305
  109 +130525,隆尧县,1305
  110 +130526,任县,1305
  111 +130527,南和县,1305
  112 +130528,宁晋县,1305
  113 +130529,巨鹿县,1305
  114 +130530,新河县,1305
  115 +130531,广宗县,1305
  116 +130532,平乡县,1305
  117 +130533,威县,1305
  118 +130534,清河县,1305
  119 +130535,临西县,1305
  120 +130581,南宫市,1305
  121 +130582,沙河市,1305
  122 +1306,保定市,13
  123 +130602,竞秀区,1306
  124 +130606,莲池区,1306
  125 +130607,满城区,1306
  126 +130608,清苑区,1306
  127 +130609,徐水区,1306
  128 +130623,涞水县,1306
  129 +130624,阜平县,1306
  130 +130626,定兴县,1306
  131 +130627,唐县,1306
  132 +130628,高阳县,1306
  133 +130629,容城县,1306
  134 +130630,涞源县,1306
  135 +130631,望都县,1306
  136 +130632,安新县,1306
  137 +130633,易县,1306
  138 +130634,曲阳县,1306
  139 +130635,蠡县,1306
  140 +130636,顺平县,1306
  141 +130637,博野县,1306
  142 +130638,雄县,1306
  143 +130681,涿州市,1306
  144 +130682,定州市,1306
  145 +130683,安国市,1306
  146 +130684,高碑店市,1306
  147 +1307,张家口市,13
  148 +130702,桥东区,1307
  149 +130703,桥西区,1307
  150 +130705,宣化区,1307
  151 +130706,下花园区,1307
  152 +130708,万全区,1307
  153 +130709,崇礼区,1307
  154 +130722,张北县,1307
  155 +130723,康保县,1307
  156 +130724,沽源县,1307
  157 +130725,尚义县,1307
  158 +130726,蔚县,1307
  159 +130727,阳原县,1307
  160 +130728,怀安县,1307
  161 +130730,怀来县,1307
  162 +130731,涿鹿县,1307
  163 +130732,赤城县,1307
  164 +1308,承德市,13
  165 +130802,双桥区,1308
  166 +130803,双滦区,1308
  167 +130804,鹰手营子矿区,1308
  168 +130821,承德县,1308
  169 +130822,兴隆县,1308
  170 +130824,滦平县,1308
  171 +130825,隆化县,1308
  172 +130826,丰宁满族自治县,1308
  173 +130827,宽城满族自治县,1308
  174 +130828,围场满族蒙古族自治县,1308
  175 +130881,平泉市,1308
  176 +1309,沧州市,13
  177 +130902,新华区,1309
  178 +130903,运河区,1309
  179 +130921,沧县,1309
  180 +130922,青县,1309
  181 +130923,东光县,1309
  182 +130924,海兴县,1309
  183 +130925,盐山县,1309
  184 +130926,肃宁县,1309
  185 +130927,南皮县,1309
  186 +130928,吴桥县,1309
  187 +130929,献县,1309
  188 +130930,孟村回族自治县,1309
  189 +130981,泊头市,1309
  190 +130982,任丘市,1309
  191 +130983,黄骅市,1309
  192 +130984,河间市,1309
  193 +1310,廊坊市,13
  194 +131002,安次区,1310
  195 +131003,广阳区,1310
  196 +131022,固安县,1310
  197 +131023,永清县,1310
  198 +131024,香河县,1310
  199 +131025,大城县,1310
  200 +131026,文安县,1310
  201 +131028,大厂回族自治县,1310
  202 +131081,霸州市,1310
  203 +131082,三河市,1310
  204 +1311,衡水市,13
  205 +131102,桃城区,1311
  206 +131103,冀州区,1311
  207 +131121,枣强县,1311
  208 +131122,武邑县,1311
  209 +131123,武强县,1311
  210 +131124,饶阳县,1311
  211 +131125,安平县,1311
  212 +131126,故城县,1311
  213 +131127,景县,1311
  214 +131128,阜城县,1311
  215 +131182,深州市,1311
  216 +14,山西省,
  217 +1401,太原市,14
  218 +140105,小店区,1401
  219 +140106,迎泽区,1401
  220 +140107,杏花岭区,1401
  221 +140108,尖草坪区,1401
  222 +140109,万柏林区,1401
  223 +140110,晋源区,1401
  224 +140121,清徐县,1401
  225 +140122,阳曲县,1401
  226 +140123,娄烦县,1401
  227 +140181,古交市,1401
  228 +1402,大同市,14
  229 +140212,新荣区,1402
  230 +140213,平城区,1402
  231 +140214,云冈区,1402
  232 +140215,云州区,1402
  233 +140221,阳高县,1402
  234 +140222,天镇县,1402
  235 +140223,广灵县,1402
  236 +140224,灵丘县,1402
  237 +140225,浑源县,1402
  238 +140226,左云县,1402
  239 +1403,阳泉市,14
  240 +140302,城区,1403
  241 +140303,矿区,1403
  242 +140311,郊区,1403
  243 +140321,平定县,1403
  244 +140322,盂县,1403
  245 +1404,长治市,14
  246 +140403,潞州区,1404
  247 +140404,上党区,1404
  248 +140405,屯留区,1404
  249 +140406,潞城区,1404
  250 +140423,襄垣县,1404
  251 +140425,平顺县,1404
  252 +140426,黎城县,1404
  253 +140427,壶关县,1404
  254 +140428,长子县,1404
  255 +140429,武乡县,1404
  256 +140430,沁县,1404
  257 +140431,沁源县,1404
  258 +1405,晋城市,14
  259 +140502,城区,1405
  260 +140521,沁水县,1405
  261 +140522,阳城县,1405
  262 +140524,陵川县,1405
  263 +140525,泽州县,1405
  264 +140581,高平市,1405
  265 +1406,朔州市,14
  266 +140602,朔城区,1406
  267 +140603,平鲁区,1406
  268 +140621,山阴县,1406
  269 +140622,应县,1406
  270 +140623,右玉县,1406
  271 +140681,怀仁市,1406
  272 +1407,晋中市,14
  273 +140702,榆次区,1407
  274 +140721,榆社县,1407
  275 +140722,左权县,1407
  276 +140723,和顺县,1407
  277 +140724,昔阳县,1407
  278 +140725,寿阳县,1407
  279 +140726,太谷县,1407
  280 +140727,祁县,1407
  281 +140728,平遥县,1407
  282 +140729,灵石县,1407
  283 +140781,介休市,1407
  284 +1408,运城市,14
  285 +140802,盐湖区,1408
  286 +140821,临猗县,1408
  287 +140822,万荣县,1408
  288 +140823,闻喜县,1408
  289 +140824,稷山县,1408
  290 +140825,新绛县,1408
  291 +140826,绛县,1408
  292 +140827,垣曲县,1408
  293 +140828,夏县,1408
  294 +140829,平陆县,1408
  295 +140830,芮城县,1408
  296 +140881,永济市,1408
  297 +140882,河津市,1408
  298 +1409,忻州市,14
  299 +140902,忻府区,1409
  300 +140921,定襄县,1409
  301 +140922,五台县,1409
  302 +140923,代县,1409
  303 +140924,繁峙县,1409
  304 +140925,宁武县,1409
  305 +140926,静乐县,1409
  306 +140927,神池县,1409
  307 +140928,五寨县,1409
  308 +140929,岢岚县,1409
  309 +140930,河曲县,1409
  310 +140931,保德县,1409
  311 +140932,偏关县,1409
  312 +140981,原平市,1409
  313 +1410,临汾市,14
  314 +141002,尧都区,1410
  315 +141021,曲沃县,1410
  316 +141022,翼城县,1410
  317 +141023,襄汾县,1410
  318 +141024,洪洞县,1410
  319 +141025,古县,1410
  320 +141026,安泽县,1410
  321 +141027,浮山县,1410
  322 +141028,吉县,1410
  323 +141029,乡宁县,1410
  324 +141030,大宁县,1410
  325 +141031,隰县,1410
  326 +141032,永和县,1410
  327 +141033,蒲县,1410
  328 +141034,汾西县,1410
  329 +141081,侯马市,1410
  330 +141082,霍州市,1410
  331 +1411,吕梁市,14
  332 +141102,离石区,1411
  333 +141121,文水县,1411
  334 +141122,交城县,1411
  335 +141123,兴县,1411
  336 +141124,临县,1411
  337 +141125,柳林县,1411
  338 +141126,石楼县,1411
  339 +141127,岚县,1411
  340 +141128,方山县,1411
  341 +141129,中阳县,1411
  342 +141130,交口县,1411
  343 +141181,孝义市,1411
  344 +141182,汾阳市,1411
  345 +15,内蒙古自治区,
  346 +1501,呼和浩特市,15
  347 +150102,新城区,1501
  348 +150103,回民区,1501
  349 +150104,玉泉区,1501
  350 +150105,赛罕区,1501
  351 +150121,土默特左旗,1501
  352 +150122,托克托县,1501
  353 +150123,和林格尔县,1501
  354 +150124,清水河县,1501
  355 +150125,武川县,1501
  356 +1502,包头市,15
  357 +150202,东河区,1502
  358 +150203,昆都仑区,1502
  359 +150204,青山区,1502
  360 +150205,石拐区,1502
  361 +150206,白云鄂博矿区,1502
  362 +150207,九原区,1502
  363 +150221,土默特右旗,1502
  364 +150222,固阳县,1502
  365 +150223,达尔罕茂明安联合旗,1502
  366 +1503,乌海市,15
  367 +150302,海勃湾区,1503
  368 +150303,海南区,1503
  369 +150304,乌达区,1503
  370 +1504,赤峰市,15
  371 +150402,红山区,1504
  372 +150403,元宝山区,1504
  373 +150404,松山区,1504
  374 +150421,阿鲁科尔沁旗,1504
  375 +150422,巴林左旗,1504
  376 +150423,巴林右旗,1504
  377 +150424,林西县,1504
  378 +150425,克什克腾旗,1504
  379 +150426,翁牛特旗,1504
  380 +150428,喀喇沁旗,1504
  381 +150429,宁城县,1504
  382 +150430,敖汉旗,1504
  383 +1505,通辽市,15
  384 +150502,科尔沁区,1505
  385 +150521,科尔沁左翼中旗,1505
  386 +150522,科尔沁左翼后旗,1505
  387 +150523,开鲁县,1505
  388 +150524,库伦旗,1505
  389 +150525,奈曼旗,1505
  390 +150526,扎鲁特旗,1505
  391 +150581,霍林郭勒市,1505
  392 +1506,鄂尔多斯市,15
  393 +150602,东胜区,1506
  394 +150603,康巴什区,1506
  395 +150621,达拉特旗,1506
  396 +150622,准格尔旗,1506
  397 +150623,鄂托克前旗,1506
  398 +150624,鄂托克旗,1506
  399 +150625,杭锦旗,1506
  400 +150626,乌审旗,1506
  401 +150627,伊金霍洛旗,1506
  402 +1507,呼伦贝尔市,15
  403 +150702,海拉尔区,1507
  404 +150703,扎赉诺尔区,1507
  405 +150721,阿荣旗,1507
  406 +150722,莫力达瓦达斡尔族自治旗,1507
  407 +150723,鄂伦春自治旗,1507
  408 +150724,鄂温克族自治旗,1507
  409 +150725,陈巴尔虎旗,1507
  410 +150726,新巴尔虎左旗,1507
  411 +150727,新巴尔虎右旗,1507
  412 +150781,满洲里市,1507
  413 +150782,牙克石市,1507
  414 +150783,扎兰屯市,1507
  415 +150784,额尔古纳市,1507
  416 +150785,根河市,1507
  417 +1508,巴彦淖尔市,15
  418 +150802,临河区,1508
  419 +150821,五原县,1508
  420 +150822,磴口县,1508
  421 +150823,乌拉特前旗,1508
  422 +150824,乌拉特中旗,1508
  423 +150825,乌拉特后旗,1508
  424 +150826,杭锦后旗,1508
  425 +1509,乌兰察布市,15
  426 +150902,集宁区,1509
  427 +150921,卓资县,1509
  428 +150922,化德县,1509
  429 +150923,商都县,1509
  430 +150924,兴和县,1509
  431 +150925,凉城县,1509
  432 +150926,察哈尔右翼前旗,1509
  433 +150927,察哈尔右翼中旗,1509
  434 +150928,察哈尔右翼后旗,1509
  435 +150929,四子王旗,1509
  436 +150981,丰镇市,1509
  437 +1522,兴安盟,15
  438 +152201,乌兰浩特市,1522
  439 +152202,阿尔山市,1522
  440 +152221,科尔沁右翼前旗,1522
  441 +152222,科尔沁右翼中旗,1522
  442 +152223,扎赉特旗,1522
  443 +152224,突泉县,1522
  444 +1525,锡林郭勒盟,15
  445 +152501,二连浩特市,1525
  446 +152502,锡林浩特市,1525
  447 +152522,阿巴嘎旗,1525
  448 +152523,苏尼特左旗,1525
  449 +152524,苏尼特右旗,1525
  450 +152525,东乌珠穆沁旗,1525
  451 +152526,西乌珠穆沁旗,1525
  452 +152527,太仆寺旗,1525
  453 +152528,镶黄旗,1525
  454 +152529,正镶白旗,1525
  455 +152530,正蓝旗,1525
  456 +152531,多伦县,1525
  457 +1529,阿拉善盟,15
  458 +152921,阿拉善左旗,1529
  459 +152922,阿拉善右旗,1529
  460 +152923,额济纳旗,1529
  461 +21,辽宁省,
  462 +2101,沈阳市,21
  463 +210102,和平区,2101
  464 +210103,沈河区,2101
  465 +210104,大东区,2101
  466 +210105,皇姑区,2101
  467 +210106,铁西区,2101
  468 +210111,苏家屯区,2101
  469 +210112,浑南区,2101
  470 +210113,沈北新区,2101
  471 +210114,于洪区,2101
  472 +210115,辽中区,2101
  473 +210123,康平县,2101
  474 +210124,法库县,2101
  475 +210181,新民市,2101
  476 +2102,大连市,21
  477 +210202,中山区,2102
  478 +210203,西岗区,2102
  479 +210204,沙河口区,2102
  480 +210211,甘井子区,2102
  481 +210212,旅顺口区,2102
  482 +210213,金州区,2102
  483 +210214,普兰店区,2102
  484 +210224,长海县,2102
  485 +210281,瓦房店市,2102
  486 +210283,庄河市,2102
  487 +2103,鞍山市,21
  488 +210302,铁东区,2103
  489 +210303,铁西区,2103
  490 +210304,立山区,2103
  491 +210311,千山区,2103
  492 +210321,台安县,2103
  493 +210323,岫岩满族自治县,2103
  494 +210381,海城市,2103
  495 +2104,抚顺市,21
  496 +210402,新抚区,2104
  497 +210403,东洲区,2104
  498 +210404,望花区,2104
  499 +210411,顺城区,2104
  500 +210421,抚顺县,2104
  501 +210422,新宾满族自治县,2104
  502 +210423,清原满族自治县,2104
  503 +2105,本溪市,21
  504 +210502,平山区,2105
  505 +210503,溪湖区,2105
  506 +210504,明山区,2105
  507 +210505,南芬区,2105
  508 +210521,本溪满族自治县,2105
  509 +210522,桓仁满族自治县,2105
  510 +2106,丹东市,21
  511 +210602,元宝区,2106
  512 +210603,振兴区,2106
  513 +210604,振安区,2106
  514 +210624,宽甸满族自治县,2106
  515 +210681,东港市,2106
  516 +210682,凤城市,2106
  517 +2107,锦州市,21
  518 +210702,古塔区,2107
  519 +210703,凌河区,2107
  520 +210711,太和区,2107
  521 +210726,黑山县,2107
  522 +210727,义县,2107
  523 +210781,凌海市,2107
  524 +210782,北镇市,2107
  525 +2108,营口市,21
  526 +210802,站前区,2108
  527 +210803,西市区,2108
  528 +210804,鲅鱼圈区,2108
  529 +210811,老边区,2108
  530 +210881,盖州市,2108
  531 +210882,大石桥市,2108
  532 +2109,阜新市,21
  533 +210902,海州区,2109
  534 +210903,新邱区,2109
  535 +210904,太平区,2109
  536 +210905,清河门区,2109
  537 +210911,细河区,2109
  538 +210921,阜新蒙古族自治县,2109
  539 +210922,彰武县,2109
  540 +2110,辽阳市,21
  541 +211002,白塔区,2110
  542 +211003,文圣区,2110
  543 +211004,宏伟区,2110
  544 +211005,弓长岭区,2110
  545 +211011,太子河区,2110
  546 +211021,辽阳县,2110
  547 +211081,灯塔市,2110
  548 +2111,盘锦市,21
  549 +211102,双台子区,2111
  550 +211103,兴隆台区,2111
  551 +211104,大洼区,2111
  552 +211122,盘山县,2111
  553 +2112,铁岭市,21
  554 +211202,银州区,2112
  555 +211204,清河区,2112
  556 +211221,铁岭县,2112
  557 +211223,西丰县,2112
  558 +211224,昌图县,2112
  559 +211281,调兵山市,2112
  560 +211282,开原市,2112
  561 +2113,朝阳市,21
  562 +211302,双塔区,2113
  563 +211303,龙城区,2113
  564 +211321,朝阳县,2113
  565 +211322,建平县,2113
  566 +211324,喀喇沁左翼蒙古族自治县,2113
  567 +211381,北票市,2113
  568 +211382,凌源市,2113
  569 +2114,葫芦岛市,21
  570 +211402,连山区,2114
  571 +211403,龙港区,2114
  572 +211404,南票区,2114
  573 +211421,绥中县,2114
  574 +211422,建昌县,2114
  575 +211481,兴城市,2114
  576 +22,吉林省,
  577 +2201,长春市,22
  578 +220102,南关区,2201
  579 +220103,宽城区,2201
  580 +220104,朝阳区,2201
  581 +220105,二道区,2201
  582 +220106,绿园区,2201
  583 +220112,双阳区,2201
  584 +220113,九台区,2201
  585 +220122,农安县,2201
  586 +220182,榆树市,2201
  587 +220183,德惠市,2201
  588 +2202,吉林市,22
  589 +220202,昌邑区,2202
  590 +220203,龙潭区,2202
  591 +220204,船营区,2202
  592 +220211,丰满区,2202
  593 +220221,永吉县,2202
  594 +220281,蛟河市,2202
  595 +220282,桦甸市,2202
  596 +220283,舒兰市,2202
  597 +220284,磐石市,2202
  598 +2203,四平市,22
  599 +220302,铁西区,2203
  600 +220303,铁东区,2203
  601 +220322,梨树县,2203
  602 +220323,伊通满族自治县,2203
  603 +220381,公主岭市,2203
  604 +220382,双辽市,2203
  605 +2204,辽源市,22
  606 +220402,龙山区,2204
  607 +220403,西安区,2204
  608 +220421,东丰县,2204
  609 +220422,东辽县,2204
  610 +2205,通化市,22
  611 +220502,东昌区,2205
  612 +220503,二道江区,2205
  613 +220521,通化县,2205
  614 +220523,辉南县,2205
  615 +220524,柳河县,2205
  616 +220581,梅河口市,2205
  617 +220582,集安市,2205
  618 +2206,白山市,22
  619 +220602,浑江区,2206
  620 +220605,江源区,2206
  621 +220621,抚松县,2206
  622 +220622,靖宇县,2206
  623 +220623,长白朝鲜族自治县,2206
  624 +220681,临江市,2206
  625 +2207,松原市,22
  626 +220702,宁江区,2207
  627 +220721,前郭尔罗斯蒙古族自治县,2207
  628 +220722,长岭县,2207
  629 +220723,乾安县,2207
  630 +220781,扶余市,2207
  631 +2208,白城市,22
  632 +220802,洮北区,2208
  633 +220821,镇赉县,2208
  634 +220822,通榆县,2208
  635 +220881,洮南市,2208
  636 +220882,大安市,2208
  637 +2224,延边朝鲜族自治州,22
  638 +222401,延吉市,2224
  639 +222402,图们市,2224
  640 +222403,敦化市,2224
  641 +222404,珲春市,2224
  642 +222405,龙井市,2224
  643 +222406,和龙市,2224
  644 +222424,汪清县,2224
  645 +222426,安图县,2224
  646 +23,黑龙江省,
  647 +2301,哈尔滨市,23
  648 +230102,道里区,2301
  649 +230103,南岗区,2301
  650 +230104,道外区,2301
  651 +230108,平房区,2301
  652 +230109,松北区,2301
  653 +230110,香坊区,2301
  654 +230111,呼兰区,2301
  655 +230112,阿城区,2301
  656 +230113,双城区,2301
  657 +230123,依兰县,2301
  658 +230124,方正县,2301
  659 +230125,宾县,2301
  660 +230126,巴彦县,2301
  661 +230127,木兰县,2301
  662 +230128,通河县,2301
  663 +230129,延寿县,2301
  664 +230183,尚志市,2301
  665 +230184,五常市,2301
  666 +2302,齐齐哈尔市,23
  667 +230202,龙沙区,2302
  668 +230203,建华区,2302
  669 +230204,铁锋区,2302
  670 +230205,昂昂溪区,2302
  671 +230206,富拉尔基区,2302
  672 +230207,碾子山区,2302
  673 +230208,梅里斯达斡尔族区,2302
  674 +230221,龙江县,2302
  675 +230223,依安县,2302
  676 +230224,泰来县,2302
  677 +230225,甘南县,2302
  678 +230227,富裕县,2302
  679 +230229,克山县,2302
  680 +230230,克东县,2302
  681 +230231,拜泉县,2302
  682 +230281,讷河市,2302
  683 +2303,鸡西市,23
  684 +230302,鸡冠区,2303
  685 +230303,恒山区,2303
  686 +230304,滴道区,2303
  687 +230305,梨树区,2303
  688 +230306,城子河区,2303
  689 +230307,麻山区,2303
  690 +230321,鸡东县,2303
  691 +230381,虎林市,2303
  692 +230382,密山市,2303
  693 +2304,鹤岗市,23
  694 +230402,向阳区,2304
  695 +230403,工农区,2304
  696 +230404,南山区,2304
  697 +230405,兴安区,2304
  698 +230406,东山区,2304
  699 +230407,兴山区,2304
  700 +230421,萝北县,2304
  701 +230422,绥滨县,2304
  702 +2305,双鸭山市,23
  703 +230502,尖山区,2305
  704 +230503,岭东区,2305
  705 +230505,四方台区,2305
  706 +230506,宝山区,2305
  707 +230521,集贤县,2305
  708 +230522,友谊县,2305
  709 +230523,宝清县,2305
  710 +230524,饶河县,2305
  711 +2306,大庆市,23
  712 +230602,萨尔图区,2306
  713 +230603,龙凤区,2306
  714 +230604,让胡路区,2306
  715 +230605,红岗区,2306
  716 +230606,大同区,2306
  717 +230621,肇州县,2306
  718 +230622,肇源县,2306
  719 +230623,林甸县,2306
  720 +230624,杜尔伯特蒙古族自治县,2306
  721 +2307,伊春市,23
  722 +230702,伊春区,2307
  723 +230703,南岔区,2307
  724 +230704,友好区,2307
  725 +230705,西林区,2307
  726 +230706,翠峦区,2307
  727 +230707,新青区,2307
  728 +230708,美溪区,2307
  729 +230709,金山屯区,2307
  730 +230710,五营区,2307
  731 +230711,乌马河区,2307
  732 +230712,汤旺河区,2307
  733 +230713,带岭区,2307
  734 +230714,乌伊岭区,2307
  735 +230715,红星区,2307
  736 +230716,上甘岭区,2307
  737 +230722,嘉荫县,2307
  738 +230781,铁力市,2307
  739 +2308,佳木斯市,23
  740 +230803,向阳区,2308
  741 +230804,前进区,2308
  742 +230805,东风区,2308
  743 +230811,郊区,2308
  744 +230822,桦南县,2308
  745 +230826,桦川县,2308
  746 +230828,汤原县,2308
  747 +230881,同江市,2308
  748 +230882,富锦市,2308
  749 +230883,抚远市,2308
  750 +2309,七台河市,23
  751 +230902,新兴区,2309
  752 +230903,桃山区,2309
  753 +230904,茄子河区,2309
  754 +230921,勃利县,2309
  755 +2310,牡丹江市,23
  756 +231002,东安区,2310
  757 +231003,阳明区,2310
  758 +231004,爱民区,2310
  759 +231005,西安区,2310
  760 +231025,林口县,2310
  761 +231081,绥芬河市,2310
  762 +231083,海林市,2310
  763 +231084,宁安市,2310
  764 +231085,穆棱市,2310
  765 +231086,东宁市,2310
  766 +2311,黑河市,23
  767 +231102,爱辉区,2311
  768 +231121,嫩江县,2311
  769 +231123,逊克县,2311
  770 +231124,孙吴县,2311
  771 +231181,北安市,2311
  772 +231182,五大连池市,2311
  773 +2312,绥化市,23
  774 +231202,北林区,2312
  775 +231221,望奎县,2312
  776 +231222,兰西县,2312
  777 +231223,青冈县,2312
  778 +231224,庆安县,2312
  779 +231225,明水县,2312
  780 +231226,绥棱县,2312
  781 +231281,安达市,2312
  782 +231282,肇东市,2312
  783 +231283,海伦市,2312
  784 +2327,大兴安岭地区,23
  785 +232701,漠河市,2327
  786 +232721,呼玛县,2327
  787 +232722,塔河县,2327
  788 +31,上海市,
  789 +310101,黄浦区,31
  790 +310104,徐汇区,31
  791 +310105,长宁区,31
  792 +310106,静安区,31
  793 +310107,普陀区,31
  794 +310109,虹口区,31
  795 +310110,杨浦区,31
  796 +310112,闵行区,31
  797 +310113,宝山区,31
  798 +310114,嘉定区,31
  799 +310115,浦东新区,31
  800 +310116,金山区,31
  801 +310117,松江区,31
  802 +310118,青浦区,31
  803 +310120,奉贤区,31
  804 +310151,崇明区,31
  805 +32,江苏省,
  806 +3201,南京市,32
  807 +320102,玄武区,3201
  808 +320104,秦淮区,3201
  809 +320105,建邺区,3201
  810 +320106,鼓楼区,3201
  811 +320111,浦口区,3201
  812 +320113,栖霞区,3201
  813 +320114,雨花台区,3201
  814 +320115,江宁区,3201
  815 +320116,六合区,3201
  816 +320117,溧水区,3201
  817 +320118,高淳区,3201
  818 +3202,无锡市,32
  819 +320205,锡山区,3202
  820 +320206,惠山区,3202
  821 +320211,滨湖区,3202
  822 +320213,梁溪区,3202
  823 +320214,新吴区,3202
  824 +320281,江阴市,3202
  825 +320282,宜兴市,3202
  826 +3203,徐州市,32
  827 +320302,鼓楼区,3203
  828 +320303,云龙区,3203
  829 +320305,贾汪区,3203
  830 +320311,泉山区,3203
  831 +320312,铜山区,3203
  832 +320321,丰县,3203
  833 +320322,沛县,3203
  834 +320324,睢宁县,3203
  835 +320381,新沂市,3203
  836 +320382,邳州市,3203
  837 +3204,常州市,32
  838 +320402,天宁区,3204
  839 +320404,钟楼区,3204
  840 +320411,新北区,3204
  841 +320412,武进区,3204
  842 +320413,金坛区,3204
  843 +320481,溧阳市,3204
  844 +3205,苏州市,32
  845 +320505,虎丘区,3205
  846 +320506,吴中区,3205
  847 +320507,相城区,3205
  848 +320508,姑苏区,3205
  849 +320509,吴江区,3205
  850 +320581,常熟市,3205
  851 +320582,张家港市,3205
  852 +320583,昆山市,3205
  853 +320585,太仓市,3205
  854 +3206,南通市,32
  855 +320602,崇川区,3206
  856 +320611,港闸区,3206
  857 +320612,通州区,3206
  858 +320623,如东县,3206
  859 +320681,启东市,3206
  860 +320682,如皋市,3206
  861 +320684,海门市,3206
  862 +320685,海安市,3206
  863 +3207,连云港市,32
  864 +320703,连云区,3207
  865 +320706,海州区,3207
  866 +320707,赣榆区,3207
  867 +320722,东海县,3207
  868 +320723,灌云县,3207
  869 +320724,灌南县,3207
  870 +3208,淮安市,32
  871 +320803,淮安区,3208
  872 +320804,淮阴区,3208
  873 +320812,清江浦区,3208
  874 +320813,洪泽区,3208
  875 +320826,涟水县,3208
  876 +320830,盱眙县,3208
  877 +320831,金湖县,3208
  878 +3209,盐城市,32
  879 +320902,亭湖区,3209
  880 +320903,盐都区,3209
  881 +320904,大丰区,3209
  882 +320921,响水县,3209
  883 +320922,滨海县,3209
  884 +320923,阜宁县,3209
  885 +320924,射阳县,3209
  886 +320925,建湖县,3209
  887 +320981,东台市,3209
  888 +3210,扬州市,32
  889 +321002,广陵区,3210
  890 +321003,邗江区,3210
  891 +321012,江都区,3210
  892 +321023,宝应县,3210
  893 +321081,仪征市,3210
  894 +321084,高邮市,3210
  895 +3211,镇江市,32
  896 +321102,京口区,3211
  897 +321111,润州区,3211
  898 +321112,丹徒区,3211
  899 +321181,丹阳市,3211
  900 +321182,扬中市,3211
  901 +321183,句容市,3211
  902 +3212,泰州市,32
  903 +321202,海陵区,3212
  904 +321203,高港区,3212
  905 +321204,姜堰区,3212
  906 +321281,兴化市,3212
  907 +321282,靖江市,3212
  908 +321283,泰兴市,3212
  909 +3213,宿迁市,32
  910 +321302,宿城区,3213
  911 +321311,宿豫区,3213
  912 +321322,沭阳县,3213
  913 +321323,泗阳县,3213
  914 +321324,泗洪县,3213
  915 +33,浙江省,
  916 +3301,杭州市,33
  917 +330102,上城区,3301
  918 +330103,下城区,3301
  919 +330104,江干区,3301
  920 +330105,拱墅区,3301
  921 +330106,西湖区,3301
  922 +330108,滨江区,3301
  923 +330109,萧山区,3301
  924 +330110,余杭区,3301
  925 +330111,富阳区,3301
  926 +330112,临安区,3301
  927 +330122,桐庐县,3301
  928 +330127,淳安县,3301
  929 +330182,建德市,3301
  930 +3302,宁波市,33
  931 +330203,海曙区,3302
  932 +330205,江北区,3302
  933 +330206,北仑区,3302
  934 +330211,镇海区,3302
  935 +330212,鄞州区,3302
  936 +330213,奉化区,3302
  937 +330225,象山县,3302
  938 +330226,宁海县,3302
  939 +330281,余姚市,3302
  940 +330282,慈溪市,3302
  941 +3303,温州市,33
  942 +330302,鹿城区,3303
  943 +330303,龙湾区,3303
  944 +330304,瓯海区,3303
  945 +330305,洞头区,3303
  946 +330324,永嘉县,3303
  947 +330326,平阳县,3303
  948 +330327,苍南县,3303
  949 +330328,文成县,3303
  950 +330329,泰顺县,3303
  951 +330381,瑞安市,3303
  952 +330382,乐清市,3303
  953 +3304,嘉兴市,33
  954 +330402,南湖区,3304
  955 +330411,秀洲区,3304
  956 +330421,嘉善县,3304
  957 +330424,海盐县,3304
  958 +330481,海宁市,3304
  959 +330482,平湖市,3304
  960 +330483,桐乡市,3304
  961 +3305,湖州市,33
  962 +330502,吴兴区,3305
  963 +330503,南浔区,3305
  964 +330521,德清县,3305
  965 +330522,长兴县,3305
  966 +330523,安吉县,3305
  967 +3306,绍兴市,33
  968 +330602,越城区,3306
  969 +330603,柯桥区,3306
  970 +330604,上虞区,3306
  971 +330624,新昌县,3306
  972 +330681,诸暨市,3306
  973 +330683,嵊州市,3306
  974 +3307,金华市,33
  975 +330702,婺城区,3307
  976 +330703,金东区,3307
  977 +330723,武义县,3307
  978 +330726,浦江县,3307
  979 +330727,磐安县,3307
  980 +330781,兰溪市,3307
  981 +330782,义乌市,3307
  982 +330783,东阳市,3307
  983 +330784,永康市,3307
  984 +3308,衢州市,33
  985 +330802,柯城区,3308
  986 +330803,衢江区,3308
  987 +330822,常山县,3308
  988 +330824,开化县,3308
  989 +330825,龙游县,3308
  990 +330881,江山市,3308
  991 +3309,舟山市,33
  992 +330902,定海区,3309
  993 +330903,普陀区,3309
  994 +330921,岱山县,3309
  995 +330922,嵊泗县,3309
  996 +3310,台州市,33
  997 +331002,椒江区,3310
  998 +331003,黄岩区,3310
  999 +331004,路桥区,3310
  1000 +331022,三门县,3310
  1001 +331023,天台县,3310
  1002 +331024,仙居县,3310
  1003 +331081,温岭市,3310
  1004 +331082,临海市,3310
  1005 +331083,玉环市,3310
  1006 +3311,丽水市,33
  1007 +331102,莲都区,3311
  1008 +331121,青田县,3311
  1009 +331122,缙云县,3311
  1010 +331123,遂昌县,3311
  1011 +331124,松阳县,3311
  1012 +331125,云和县,3311
  1013 +331126,庆元县,3311
  1014 +331127,景宁畲族自治县,3311
  1015 +331181,龙泉市,3311
  1016 +34,安徽省,
  1017 +3401,合肥市,34
  1018 +340102,瑶海区,3401
  1019 +340103,庐阳区,3401
  1020 +340104,蜀山区,3401
  1021 +340111,包河区,3401
  1022 +340121,长丰县,3401
  1023 +340122,肥东县,3401
  1024 +340123,肥西县,3401
  1025 +340124,庐江县,3401
  1026 +340181,巢湖市,3401
  1027 +3402,芜湖市,34
  1028 +340202,镜湖区,3402
  1029 +340203,弋江区,3402
  1030 +340207,鸠江区,3402
  1031 +340208,三山区,3402
  1032 +340221,芜湖县,3402
  1033 +340222,繁昌县,3402
  1034 +340223,南陵县,3402
  1035 +340225,无为县,3402
  1036 +3403,蚌埠市,34
  1037 +340302,龙子湖区,3403
  1038 +340303,蚌山区,3403
  1039 +340304,禹会区,3403
  1040 +340311,淮上区,3403
  1041 +340321,怀远县,3403
  1042 +340322,五河县,3403
  1043 +340323,固镇县,3403
  1044 +3404,淮南市,34
  1045 +340402,大通区,3404
  1046 +340403,田家庵区,3404
  1047 +340404,谢家集区,3404
  1048 +340405,八公山区,3404
  1049 +340406,潘集区,3404
  1050 +340421,凤台县,3404
  1051 +340422,寿县,3404
  1052 +3405,马鞍山市,34
  1053 +340503,花山区,3405
  1054 +340504,雨山区,3405
  1055 +340506,博望区,3405
  1056 +340521,当涂县,3405
  1057 +340522,含山县,3405
  1058 +340523,和县,3405
  1059 +3406,淮北市,34
  1060 +340602,杜集区,3406
  1061 +340603,相山区,3406
  1062 +340604,烈山区,3406
  1063 +340621,濉溪县,3406
  1064 +3407,铜陵市,34
  1065 +340705,铜官区,3407
  1066 +340706,义安区,3407
  1067 +340711,郊区,3407
  1068 +340722,枞阳县,3407
  1069 +3408,安庆市,34
  1070 +340802,迎江区,3408
  1071 +340803,大观区,3408
  1072 +340811,宜秀区,3408
  1073 +340822,怀宁县,3408
  1074 +340825,太湖县,3408
  1075 +340826,宿松县,3408
  1076 +340827,望江县,3408
  1077 +340828,岳西县,3408
  1078 +340881,桐城市,3408
  1079 +340882,潜山市,3408
  1080 +3410,黄山市,34
  1081 +341002,屯溪区,3410
  1082 +341003,黄山区,3410
  1083 +341004,徽州区,3410
  1084 +341021,歙县,3410
  1085 +341022,休宁县,3410
  1086 +341023,黟县,3410
  1087 +341024,祁门县,3410
  1088 +3411,滁州市,34
  1089 +341102,琅琊区,3411
  1090 +341103,南谯区,3411
  1091 +341122,来安县,3411
  1092 +341124,全椒县,3411
  1093 +341125,定远县,3411
  1094 +341126,凤阳县,3411
  1095 +341181,天长市,3411
  1096 +341182,明光市,3411
  1097 +3412,阜阳市,34
  1098 +341202,颍州区,3412
  1099 +341203,颍东区,3412
  1100 +341204,颍泉区,3412
  1101 +341221,临泉县,3412
  1102 +341222,太和县,3412
  1103 +341225,阜南县,3412
  1104 +341226,颍上县,3412
  1105 +341282,界首市,3412
  1106 +3413,宿州市,34
  1107 +341302,埇桥区,3413
  1108 +341321,砀山县,3413
  1109 +341322,萧县,3413
  1110 +341323,灵璧县,3413
  1111 +341324,泗县,3413
  1112 +3415,六安市,34
  1113 +341502,金安区,3415
  1114 +341503,裕安区,3415
  1115 +341504,叶集区,3415
  1116 +341522,霍邱县,3415
  1117 +341523,舒城县,3415
  1118 +341524,金寨县,3415
  1119 +341525,霍山县,3415
  1120 +3416,亳州市,34
  1121 +341602,谯城区,3416
  1122 +341621,涡阳县,3416
  1123 +341622,蒙城县,3416
  1124 +341623,利辛县,3416
  1125 +3417,池州市,34
  1126 +341702,贵池区,3417
  1127 +341721,东至县,3417
  1128 +341722,石台县,3417
  1129 +341723,青阳县,3417
  1130 +3418,宣城市,34
  1131 +341802,宣州区,3418
  1132 +341821,郎溪县,3418
  1133 +341822,广德县,3418
  1134 +341823,泾县,3418
  1135 +341824,绩溪县,3418
  1136 +341825,旌德县,3418
  1137 +341881,宁国市,3418
  1138 +35,福建省,
  1139 +3501,福州市,35
  1140 +350102,鼓楼区,3501
  1141 +350103,台江区,3501
  1142 +350104,仓山区,3501
  1143 +350105,马尾区,3501
  1144 +350111,晋安区,3501
  1145 +350112,长乐区,3501
  1146 +350121,闽侯县,3501
  1147 +350122,连江县,3501
  1148 +350123,罗源县,3501
  1149 +350124,闽清县,3501
  1150 +350125,永泰县,3501
  1151 +350128,平潭县,3501
  1152 +350181,福清市,3501
  1153 +3502,厦门市,35
  1154 +350203,思明区,3502
  1155 +350205,海沧区,3502
  1156 +350206,湖里区,3502
  1157 +350211,集美区,3502
  1158 +350212,同安区,3502
  1159 +350213,翔安区,3502
  1160 +3503,莆田市,35
  1161 +350302,城厢区,3503
  1162 +350303,涵江区,3503
  1163 +350304,荔城区,3503
  1164 +350305,秀屿区,3503
  1165 +350322,仙游县,3503
  1166 +3504,三明市,35
  1167 +350402,梅列区,3504
  1168 +350403,三元区,3504
  1169 +350421,明溪县,3504
  1170 +350423,清流县,3504
  1171 +350424,宁化县,3504
  1172 +350425,大田县,3504
  1173 +350426,尤溪县,3504
  1174 +350427,沙县,3504
  1175 +350428,将乐县,3504
  1176 +350429,泰宁县,3504
  1177 +350430,建宁县,3504
  1178 +350481,永安市,3504
  1179 +3505,泉州市,35
  1180 +350502,鲤城区,3505
  1181 +350503,丰泽区,3505
  1182 +350504,洛江区,3505
  1183 +350505,泉港区,3505
  1184 +350521,惠安县,3505
  1185 +350524,安溪县,3505
  1186 +350525,永春县,3505
  1187 +350526,德化县,3505
  1188 +350527,金门县,3505
  1189 +350581,石狮市,3505
  1190 +350582,晋江市,3505
  1191 +350583,南安市,3505
  1192 +3506,漳州市,35
  1193 +350602,芗城区,3506
  1194 +350603,龙文区,3506
  1195 +350622,云霄县,3506
  1196 +350623,漳浦县,3506
  1197 +350624,诏安县,3506
  1198 +350625,长泰县,3506
  1199 +350626,东山县,3506
  1200 +350627,南靖县,3506
  1201 +350628,平和县,3506
  1202 +350629,华安县,3506
  1203 +350681,龙海市,3506
  1204 +3507,南平市,35
  1205 +350702,延平区,3507
  1206 +350703,建阳区,3507
  1207 +350721,顺昌县,3507
  1208 +350722,浦城县,3507
  1209 +350723,光泽县,3507
  1210 +350724,松溪县,3507
  1211 +350725,政和县,3507
  1212 +350781,邵武市,3507
  1213 +350782,武夷山市,3507
  1214 +350783,建瓯市,3507
  1215 +3508,龙岩市,35
  1216 +350802,新罗区,3508
  1217 +350803,永定区,3508
  1218 +350821,长汀县,3508
  1219 +350823,上杭县,3508
  1220 +350824,武平县,3508
  1221 +350825,连城县,3508
  1222 +350881,漳平市,3508
  1223 +3509,宁德市,35
  1224 +350902,蕉城区,3509
  1225 +350921,霞浦县,3509
  1226 +350922,古田县,3509
  1227 +350923,屏南县,3509
  1228 +350924,寿宁县,3509
  1229 +350925,周宁县,3509
  1230 +350926,柘荣县,3509
  1231 +350981,福安市,3509
  1232 +350982,福鼎市,3509
  1233 +36,江西省,
  1234 +3601,南昌市,36
  1235 +360102,东湖区,3601
  1236 +360103,西湖区,3601
  1237 +360104,青云谱区,3601
  1238 +360105,湾里区,3601
  1239 +360111,青山湖区,3601
  1240 +360112,新建区,3601
  1241 +360121,南昌县,3601
  1242 +360123,安义县,3601
  1243 +360124,进贤县,3601
  1244 +3602,景德镇市,36
  1245 +360202,昌江区,3602
  1246 +360203,珠山区,3602
  1247 +360222,浮梁县,3602
  1248 +360281,乐平市,3602
  1249 +3603,萍乡市,36
  1250 +360302,安源区,3603
  1251 +360313,湘东区,3603
  1252 +360321,莲花县,3603
  1253 +360322,上栗县,3603
  1254 +360323,芦溪县,3603
  1255 +3604,九江市,36
  1256 +360402,濂溪区,3604
  1257 +360403,浔阳区,3604
  1258 +360404,柴桑区,3604
  1259 +360423,武宁县,3604
  1260 +360424,修水县,3604
  1261 +360425,永修县,3604
  1262 +360426,德安县,3604
  1263 +360428,都昌县,3604
  1264 +360429,湖口县,3604
  1265 +360430,彭泽县,3604
  1266 +360481,瑞昌市,3604
  1267 +360482,共青城市,3604
  1268 +360483,庐山市,3604
  1269 +3605,新余市,36
  1270 +360502,渝水区,3605
  1271 +360521,分宜县,3605
  1272 +3606,鹰潭市,36
  1273 +360602,月湖区,3606
  1274 +360603,余江区,3606
  1275 +360681,贵溪市,3606
  1276 +3607,赣州市,36
  1277 +360702,章贡区,3607
  1278 +360703,南康区,3607
  1279 +360704,赣县区,3607
  1280 +360722,信丰县,3607
  1281 +360723,大余县,3607
  1282 +360724,上犹县,3607
  1283 +360725,崇义县,3607
  1284 +360726,安远县,3607
  1285 +360727,龙南县,3607
  1286 +360728,定南县,3607
  1287 +360729,全南县,3607
  1288 +360730,宁都县,3607
  1289 +360731,于都县,3607
  1290 +360732,兴国县,3607
  1291 +360733,会昌县,3607
  1292 +360734,寻乌县,3607
  1293 +360735,石城县,3607
  1294 +360781,瑞金市,3607
  1295 +3608,吉安市,36
  1296 +360802,吉州区,3608
  1297 +360803,青原区,3608
  1298 +360821,吉安县,3608
  1299 +360822,吉水县,3608
  1300 +360823,峡江县,3608
  1301 +360824,新干县,3608
  1302 +360825,永丰县,3608
  1303 +360826,泰和县,3608
  1304 +360827,遂川县,3608
  1305 +360828,万安县,3608
  1306 +360829,安福县,3608
  1307 +360830,永新县,3608
  1308 +360881,井冈山市,3608
  1309 +3609,宜春市,36
  1310 +360902,袁州区,3609
  1311 +360921,奉新县,3609
  1312 +360922,万载县,3609
  1313 +360923,上高县,3609
  1314 +360924,宜丰县,3609
  1315 +360925,靖安县,3609
  1316 +360926,铜鼓县,3609
  1317 +360981,丰城市,3609
  1318 +360982,樟树市,3609
  1319 +360983,高安市,3609
  1320 +3610,抚州市,36
  1321 +361002,临川区,3610
  1322 +361003,东乡区,3610
  1323 +361021,南城县,3610
  1324 +361022,黎川县,3610
  1325 +361023,南丰县,3610
  1326 +361024,崇仁县,3610
  1327 +361025,乐安县,3610
  1328 +361026,宜黄县,3610
  1329 +361027,金溪县,3610
  1330 +361028,资溪县,3610
  1331 +361030,广昌县,3610
  1332 +3611,上饶市,36
  1333 +361102,信州区,3611
  1334 +361103,广丰区,3611
  1335 +361121,上饶县,3611
  1336 +361123,玉山县,3611
  1337 +361124,铅山县,3611
  1338 +361125,横峰县,3611
  1339 +361126,弋阳县,3611
  1340 +361127,余干县,3611
  1341 +361128,鄱阳县,3611
  1342 +361129,万年县,3611
  1343 +361130,婺源县,3611
  1344 +361181,德兴市,3611
  1345 +37,山东省,
  1346 +3701,济南市,37
  1347 +370102,历下区,3701
  1348 +370103,市中区,3701
  1349 +370104,槐荫区,3701
  1350 +370105,天桥区,3701
  1351 +370112,历城区,3701
  1352 +370113,长清区,3701
  1353 +370114,章丘区,3701
  1354 +370115,济阳区,3701
  1355 +370124,平阴县,3701
  1356 +370126,商河县,3701
  1357 +3702,青岛市,37
  1358 +370202,市南区,3702
  1359 +370203,市北区,3702
  1360 +370211,黄岛区,3702
  1361 +370212,崂山区,3702
  1362 +370213,李沧区,3702
  1363 +370214,城阳区,3702
  1364 +370215,即墨区,3702
  1365 +370281,胶州市,3702
  1366 +370283,平度市,3702
  1367 +370285,莱西市,3702
  1368 +3703,淄博市,37
  1369 +370302,淄川区,3703
  1370 +370303,张店区,3703
  1371 +370304,博山区,3703
  1372 +370305,临淄区,3703
  1373 +370306,周村区,3703
  1374 +370321,桓台县,3703
  1375 +370322,高青县,3703
  1376 +370323,沂源县,3703
  1377 +3704,枣庄市,37
  1378 +370402,市中区,3704
  1379 +370403,薛城区,3704
  1380 +370404,峄城区,3704
  1381 +370405,台儿庄区,3704
  1382 +370406,山亭区,3704
  1383 +370481,滕州市,3704
  1384 +3705,东营市,37
  1385 +370502,东营区,3705
  1386 +370503,河口区,3705
  1387 +370505,垦利区,3705
  1388 +370522,利津县,3705
  1389 +370523,广饶县,3705
  1390 +3706,烟台市,37
  1391 +370602,芝罘区,3706
  1392 +370611,福山区,3706
  1393 +370612,牟平区,3706
  1394 +370613,莱山区,3706
  1395 +370634,长岛县,3706
  1396 +370681,龙口市,3706
  1397 +370682,莱阳市,3706
  1398 +370683,莱州市,3706
  1399 +370684,蓬莱市,3706
  1400 +370685,招远市,3706
  1401 +370686,栖霞市,3706
  1402 +370687,海阳市,3706
  1403 +3707,潍坊市,37
  1404 +370702,潍城区,3707
  1405 +370703,寒亭区,3707
  1406 +370704,坊子区,3707
  1407 +370705,奎文区,3707
  1408 +370724,临朐县,3707
  1409 +370725,昌乐县,3707
  1410 +370781,青州市,3707
  1411 +370782,诸城市,3707
  1412 +370783,寿光市,3707
  1413 +370784,安丘市,3707
  1414 +370785,高密市,3707
  1415 +370786,昌邑市,3707
  1416 +3708,济宁市,37
  1417 +370811,任城区,3708
  1418 +370812,兖州区,3708
  1419 +370826,微山县,3708
  1420 +370827,鱼台县,3708
  1421 +370828,金乡县,3708
  1422 +370829,嘉祥县,3708
  1423 +370830,汶上县,3708
  1424 +370831,泗水县,3708
  1425 +370832,梁山县,3708
  1426 +370881,曲阜市,3708
  1427 +370883,邹城市,3708
  1428 +3709,泰安市,37
  1429 +370902,泰山区,3709
  1430 +370911,岱岳区,3709
  1431 +370921,宁阳县,3709
  1432 +370923,东平县,3709
  1433 +370982,新泰市,3709
  1434 +370983,肥城市,3709
  1435 +3710,威海市,37
  1436 +371002,环翠区,3710
  1437 +371003,文登区,3710
  1438 +371082,荣成市,3710
  1439 +371083,乳山市,3710
  1440 +3711,日照市,37
  1441 +371102,东港区,3711
  1442 +371103,岚山区,3711
  1443 +371121,五莲县,3711
  1444 +371122,莒县,3711
  1445 +3712,莱芜市,37
  1446 +371202,莱城区,3712
  1447 +371203,钢城区,3712
  1448 +3713,临沂市,37
  1449 +371302,兰山区,3713
  1450 +371311,罗庄区,3713
  1451 +371312,河东区,3713
  1452 +371321,沂南县,3713
  1453 +371322,郯城县,3713
  1454 +371323,沂水县,3713
  1455 +371324,兰陵县,3713
  1456 +371325,费县,3713
  1457 +371326,平邑县,3713
  1458 +371327,莒南县,3713
  1459 +371328,蒙阴县,3713
  1460 +371329,临沭县,3713
  1461 +3714,德州市,37
  1462 +371402,德城区,3714
  1463 +371403,陵城区,3714
  1464 +371422,宁津县,3714
  1465 +371423,庆云县,3714
  1466 +371424,临邑县,3714
  1467 +371425,齐河县,3714
  1468 +371426,平原县,3714
  1469 +371427,夏津县,3714
  1470 +371428,武城县,3714
  1471 +371481,乐陵市,3714
  1472 +371482,禹城市,3714
  1473 +3715,聊城市,37
  1474 +371502,东昌府区,3715
  1475 +371521,阳谷县,3715
  1476 +371522,莘县,3715
  1477 +371523,茌平县,3715
  1478 +371524,东阿县,3715
  1479 +371525,冠县,3715
  1480 +371526,高唐县,3715
  1481 +371581,临清市,3715
  1482 +3716,滨州市,37
  1483 +371602,滨城区,3716
  1484 +371603,沾化区,3716
  1485 +371621,惠民县,3716
  1486 +371622,阳信县,3716
  1487 +371623,无棣县,3716
  1488 +371625,博兴县,3716
  1489 +371681,邹平市,3716
  1490 +3717,菏泽市,37
  1491 +371702,牡丹区,3717
  1492 +371703,定陶区,3717
  1493 +371721,曹县,3717
  1494 +371722,单县,3717
  1495 +371723,成武县,3717
  1496 +371724,巨野县,3717
  1497 +371725,郓城县,3717
  1498 +371726,鄄城县,3717
  1499 +371728,东明县,3717
  1500 +41,河南省,
  1501 +4101,郑州市,41
  1502 +410102,中原区,4101
  1503 +410103,二七区,4101
  1504 +410104,管城回族区,4101
  1505 +410105,金水区,4101
  1506 +410106,上街区,4101
  1507 +410108,惠济区,4101
  1508 +410122,中牟县,4101
  1509 +410181,巩义市,4101
  1510 +410182,荥阳市,4101
  1511 +410183,新密市,4101
  1512 +410184,新郑市,4101
  1513 +410185,登封市,4101
  1514 +4102,开封市,41
  1515 +410202,龙亭区,4102
  1516 +410203,顺河回族区,4102
  1517 +410204,鼓楼区,4102
  1518 +410205,禹王台区,4102
  1519 +410212,祥符区,4102
  1520 +410221,杞县,4102
  1521 +410222,通许县,4102
  1522 +410223,尉氏县,4102
  1523 +410225,兰考县,4102
  1524 +4103,洛阳市,41
  1525 +410302,老城区,4103
  1526 +410303,西工区,4103
  1527 +410304,瀍河回族区,4103
  1528 +410305,涧西区,4103
  1529 +410306,吉利区,4103
  1530 +410311,洛龙区,4103
  1531 +410322,孟津县,4103
  1532 +410323,新安县,4103
  1533 +410324,栾川县,4103
  1534 +410325,嵩县,4103
  1535 +410326,汝阳县,4103
  1536 +410327,宜阳县,4103
  1537 +410328,洛宁县,4103
  1538 +410329,伊川县,4103
  1539 +410381,偃师市,4103
  1540 +4104,平顶山市,41
  1541 +410402,新华区,4104
  1542 +410403,卫东区,4104
  1543 +410404,石龙区,4104
  1544 +410411,湛河区,4104
  1545 +410421,宝丰县,4104
  1546 +410422,叶县,4104
  1547 +410423,鲁山县,4104
  1548 +410425,郏县,4104
  1549 +410481,舞钢市,4104
  1550 +410482,汝州市,4104
  1551 +4105,安阳市,41
  1552 +410502,文峰区,4105
  1553 +410503,北关区,4105
  1554 +410505,殷都区,4105
  1555 +410506,龙安区,4105
  1556 +410522,安阳县,4105
  1557 +410523,汤阴县,4105
  1558 +410526,滑县,4105
  1559 +410527,内黄县,4105
  1560 +410581,林州市,4105
  1561 +4106,鹤壁市,41
  1562 +410602,鹤山区,4106
  1563 +410603,山城区,4106
  1564 +410611,淇滨区,4106
  1565 +410621,浚县,4106
  1566 +410622,淇县,4106
  1567 +4107,新乡市,41
  1568 +410702,红旗区,4107
  1569 +410703,卫滨区,4107
  1570 +410704,凤泉区,4107
  1571 +410711,牧野区,4107
  1572 +410721,新乡县,4107
  1573 +410724,获嘉县,4107
  1574 +410725,原阳县,4107
  1575 +410726,延津县,4107
  1576 +410727,封丘县,4107
  1577 +410728,长垣县,4107
  1578 +410781,卫辉市,4107
  1579 +410782,辉县市,4107
  1580 +4108,焦作市,41
  1581 +410802,解放区,4108
  1582 +410803,中站区,4108
  1583 +410804,马村区,4108
  1584 +410811,山阳区,4108
  1585 +410821,修武县,4108
  1586 +410822,博爱县,4108
  1587 +410823,武陟县,4108
  1588 +410825,温县,4108
  1589 +410882,沁阳市,4108
  1590 +410883,孟州市,4108
  1591 +4109,濮阳市,41
  1592 +410902,华龙区,4109
  1593 +410922,清丰县,4109
  1594 +410923,南乐县,4109
  1595 +410926,范县,4109
  1596 +410927,台前县,4109
  1597 +410928,濮阳县,4109
  1598 +4110,许昌市,41
  1599 +411002,魏都区,4110
  1600 +411003,建安区,4110
  1601 +411024,鄢陵县,4110
  1602 +411025,襄城县,4110
  1603 +411081,禹州市,4110
  1604 +411082,长葛市,4110
  1605 +4111,漯河市,41
  1606 +411102,源汇区,4111
  1607 +411103,郾城区,4111
  1608 +411104,召陵区,4111
  1609 +411121,舞阳县,4111
  1610 +411122,临颍县,4111
  1611 +4112,三门峡市,41
  1612 +411202,湖滨区,4112
  1613 +411203,陕州区,4112
  1614 +411221,渑池县,4112
  1615 +411224,卢氏县,4112
  1616 +411281,义马市,4112
  1617 +411282,灵宝市,4112
  1618 +4113,南阳市,41
  1619 +411302,宛城区,4113
  1620 +411303,卧龙区,4113
  1621 +411321,南召县,4113
  1622 +411322,方城县,4113
  1623 +411323,西峡县,4113
  1624 +411324,镇平县,4113
  1625 +411325,内乡县,4113
  1626 +411326,淅川县,4113
  1627 +411327,社旗县,4113
  1628 +411328,唐河县,4113
  1629 +411329,新野县,4113
  1630 +411330,桐柏县,4113
  1631 +411381,邓州市,4113
  1632 +4114,商丘市,41
  1633 +411402,梁园区,4114
  1634 +411403,睢阳区,4114
  1635 +411421,民权县,4114
  1636 +411422,睢县,4114
  1637 +411423,宁陵县,4114
  1638 +411424,柘城县,4114
  1639 +411425,虞城县,4114
  1640 +411426,夏邑县,4114
  1641 +411481,永城市,4114
  1642 +4115,信阳市,41
  1643 +411502,浉河区,4115
  1644 +411503,平桥区,4115
  1645 +411521,罗山县,4115
  1646 +411522,光山县,4115
  1647 +411523,新县,4115
  1648 +411524,商城县,4115
  1649 +411525,固始县,4115
  1650 +411526,潢川县,4115
  1651 +411527,淮滨县,4115
  1652 +411528,息县,4115
  1653 +4116,周口市,41
  1654 +411602,川汇区,4116
  1655 +411621,扶沟县,4116
  1656 +411622,西华县,4116
  1657 +411623,商水县,4116
  1658 +411624,沈丘县,4116
  1659 +411625,郸城县,4116
  1660 +411626,淮阳县,4116
  1661 +411627,太康县,4116
  1662 +411628,鹿邑县,4116
  1663 +411681,项城市,4116
  1664 +4117,驻马店市,41
  1665 +411702,驿城区,4117
  1666 +411721,西平县,4117
  1667 +411722,上蔡县,4117
  1668 +411723,平舆县,4117
  1669 +411724,正阳县,4117
  1670 +411725,确山县,4117
  1671 +411726,泌阳县,4117
  1672 +411727,汝南县,4117
  1673 +411728,遂平县,4117
  1674 +411729,新蔡县,4117
  1675 +419001,济源市,41
  1676 +42,湖北省,
  1677 +4201,武汉市,42
  1678 +420102,江岸区,4201
  1679 +420103,江汉区,4201
  1680 +420104,硚口区,4201
  1681 +420105,汉阳区,4201
  1682 +420106,武昌区,4201
  1683 +420107,青山区,4201
  1684 +420111,洪山区,4201
  1685 +420112,东西湖区,4201
  1686 +420113,汉南区,4201
  1687 +420114,蔡甸区,4201
  1688 +420115,江夏区,4201
  1689 +420116,黄陂区,4201
  1690 +420117,新洲区,4201
  1691 +4202,黄石市,42
  1692 +420202,黄石港区,4202
  1693 +420203,西塞山区,4202
  1694 +420204,下陆区,4202
  1695 +420205,铁山区,4202
  1696 +420222,阳新县,4202
  1697 +420281,大冶市,4202
  1698 +4203,十堰市,42
  1699 +420302,茅箭区,4203
  1700 +420303,张湾区,4203
  1701 +420304,郧阳区,4203
  1702 +420322,郧西县,4203
  1703 +420323,竹山县,4203
  1704 +420324,竹溪县,4203
  1705 +420325,房县,4203
  1706 +420381,丹江口市,4203
  1707 +4205,宜昌市,42
  1708 +420502,西陵区,4205
  1709 +420503,伍家岗区,4205
  1710 +420504,点军区,4205
  1711 +420505,猇亭区,4205
  1712 +420506,夷陵区,4205
  1713 +420525,远安县,4205
  1714 +420526,兴山县,4205
  1715 +420527,秭归县,4205
  1716 +420528,长阳土家族自治县,4205
  1717 +420529,五峰土家族自治县,4205
  1718 +420581,宜都市,4205
  1719 +420582,当阳市,4205
  1720 +420583,枝江市,4205
  1721 +4206,襄阳市,42
  1722 +420602,襄城区,4206
  1723 +420606,樊城区,4206
  1724 +420607,襄州区,4206
  1725 +420624,南漳县,4206
  1726 +420625,谷城县,4206
  1727 +420626,保康县,4206
  1728 +420682,老河口市,4206
  1729 +420683,枣阳市,4206
  1730 +420684,宜城市,4206
  1731 +4207,鄂州市,42
  1732 +420702,梁子湖区,4207
  1733 +420703,华容区,4207
  1734 +420704,鄂城区,4207
  1735 +4208,荆门市,42
  1736 +420802,东宝区,4208
  1737 +420804,掇刀区,4208
  1738 +420822,沙洋县,4208
  1739 +420881,钟祥市,4208
  1740 +420882,京山市,4208
  1741 +4209,孝感市,42
  1742 +420902,孝南区,4209
  1743 +420921,孝昌县,4209
  1744 +420922,大悟县,4209
  1745 +420923,云梦县,4209
  1746 +420981,应城市,4209
  1747 +420982,安陆市,4209
  1748 +420984,汉川市,4209
  1749 +4210,荆州市,42
  1750 +421002,沙市区,4210
  1751 +421003,荆州区,4210
  1752 +421022,公安县,4210
  1753 +421023,监利县,4210
  1754 +421024,江陵县,4210
  1755 +421081,石首市,4210
  1756 +421083,洪湖市,4210
  1757 +421087,松滋市,4210
  1758 +4211,黄冈市,42
  1759 +421102,黄州区,4211
  1760 +421121,团风县,4211
  1761 +421122,红安县,4211
  1762 +421123,罗田县,4211
  1763 +421124,英山县,4211
  1764 +421125,浠水县,4211
  1765 +421126,蕲春县,4211
  1766 +421127,黄梅县,4211
  1767 +421181,麻城市,4211
  1768 +421182,武穴市,4211
  1769 +4212,咸宁市,42
  1770 +421202,咸安区,4212
  1771 +421221,嘉鱼县,4212
  1772 +421222,通城县,4212
  1773 +421223,崇阳县,4212
  1774 +421224,通山县,4212
  1775 +421281,赤壁市,4212
  1776 +4213,随州市,42
  1777 +421303,曾都区,4213
  1778 +421321,随县,4213
  1779 +421381,广水市,4213
  1780 +4228,恩施土家族苗族自治州,42
  1781 +422801,恩施市,4228
  1782 +422802,利川市,4228
  1783 +422822,建始县,4228
  1784 +422823,巴东县,4228
  1785 +422825,宣恩县,4228
  1786 +422826,咸丰县,4228
  1787 +422827,来凤县,4228
  1788 +422828,鹤峰县,4228
  1789 +429004,仙桃市,42
  1790 +429005,潜江市,42
  1791 +429006,天门市,42
  1792 +429021,神农架林区,42
  1793 +43,湖南省,
  1794 +4301,长沙市,43
  1795 +430102,芙蓉区,4301
  1796 +430103,天心区,4301
  1797 +430104,岳麓区,4301
  1798 +430105,开福区,4301
  1799 +430111,雨花区,4301
  1800 +430112,望城区,4301
  1801 +430121,长沙县,4301
  1802 +430181,浏阳市,4301
  1803 +430182,宁乡市,4301
  1804 +4302,株洲市,43
  1805 +430202,荷塘区,4302
  1806 +430203,芦淞区,4302
  1807 +430204,石峰区,4302
  1808 +430211,天元区,4302
  1809 +430212,渌口区,4302
  1810 +430223,攸县,4302
  1811 +430224,茶陵县,4302
  1812 +430225,炎陵县,4302
  1813 +430281,醴陵市,4302
  1814 +4303,湘潭市,43
  1815 +430302,雨湖区,4303
  1816 +430304,岳塘区,4303
  1817 +430321,湘潭县,4303
  1818 +430381,湘乡市,4303
  1819 +430382,韶山市,4303
  1820 +4304,衡阳市,43
  1821 +430405,珠晖区,4304
  1822 +430406,雁峰区,4304
  1823 +430407,石鼓区,4304
  1824 +430408,蒸湘区,4304
  1825 +430412,南岳区,4304
  1826 +430421,衡阳县,4304
  1827 +430422,衡南县,4304
  1828 +430423,衡山县,4304
  1829 +430424,衡东县,4304
  1830 +430426,祁东县,4304
  1831 +430481,耒阳市,4304
  1832 +430482,常宁市,4304
  1833 +4305,邵阳市,43
  1834 +430502,双清区,4305
  1835 +430503,大祥区,4305
  1836 +430511,北塔区,4305
  1837 +430521,邵东县,4305
  1838 +430522,新邵县,4305
  1839 +430523,邵阳县,4305
  1840 +430524,隆回县,4305
  1841 +430525,洞口县,4305
  1842 +430527,绥宁县,4305
  1843 +430528,新宁县,4305
  1844 +430529,城步苗族自治县,4305
  1845 +430581,武冈市,4305
  1846 +4306,岳阳市,43
  1847 +430602,岳阳楼区,4306
  1848 +430603,云溪区,4306
  1849 +430611,君山区,4306
  1850 +430621,岳阳县,4306
  1851 +430623,华容县,4306
  1852 +430624,湘阴县,4306
  1853 +430626,平江县,4306
  1854 +430681,汨罗市,4306
  1855 +430682,临湘市,4306
  1856 +4307,常德市,43
  1857 +430702,武陵区,4307
  1858 +430703,鼎城区,4307
  1859 +430721,安乡县,4307
  1860 +430722,汉寿县,4307
  1861 +430723,澧县,4307
  1862 +430724,临澧县,4307
  1863 +430725,桃源县,4307
  1864 +430726,石门县,4307
  1865 +430781,津市市,4307
  1866 +4308,张家界市,43
  1867 +430802,永定区,4308
  1868 +430811,武陵源区,4308
  1869 +430821,慈利县,4308
  1870 +430822,桑植县,4308
  1871 +4309,益阳市,43
  1872 +430902,资阳区,4309
  1873 +430903,赫山区,4309
  1874 +430921,南县,4309
  1875 +430922,桃江县,4309
  1876 +430923,安化县,4309
  1877 +430981,沅江市,4309
  1878 +4310,郴州市,43
  1879 +431002,北湖区,4310
  1880 +431003,苏仙区,4310
  1881 +431021,桂阳县,4310
  1882 +431022,宜章县,4310
  1883 +431023,永兴县,4310
  1884 +431024,嘉禾县,4310
  1885 +431025,临武县,4310
  1886 +431026,汝城县,4310
  1887 +431027,桂东县,4310
  1888 +431028,安仁县,4310
  1889 +431081,资兴市,4310
  1890 +4311,永州市,43
  1891 +431102,零陵区,4311
  1892 +431103,冷水滩区,4311
  1893 +431121,祁阳县,4311
  1894 +431122,东安县,4311
  1895 +431123,双牌县,4311
  1896 +431124,道县,4311
  1897 +431125,江永县,4311
  1898 +431126,宁远县,4311
  1899 +431127,蓝山县,4311
  1900 +431128,新田县,4311
  1901 +431129,江华瑶族自治县,4311
  1902 +4312,怀化市,43
  1903 +431202,鹤城区,4312
  1904 +431221,中方县,4312
  1905 +431222,沅陵县,4312
  1906 +431223,辰溪县,4312
  1907 +431224,溆浦县,4312
  1908 +431225,会同县,4312
  1909 +431226,麻阳苗族自治县,4312
  1910 +431227,新晃侗族自治县,4312
  1911 +431228,芷江侗族自治县,4312
  1912 +431229,靖州苗族侗族自治县,4312
  1913 +431230,通道侗族自治县,4312
  1914 +431281,洪江市,4312
  1915 +4313,娄底市,43
  1916 +431302,娄星区,4313
  1917 +431321,双峰县,4313
  1918 +431322,新化县,4313
  1919 +431381,冷水江市,4313
  1920 +431382,涟源市,4313
  1921 +4331,湘西土家族苗族自治州,43
  1922 +433101,吉首市,4331
  1923 +433122,泸溪县,4331
  1924 +433123,凤凰县,4331
  1925 +433124,花垣县,4331
  1926 +433125,保靖县,4331
  1927 +433126,古丈县,4331
  1928 +433127,永顺县,4331
  1929 +433130,龙山县,4331
  1930 +44,广东省,
  1931 +4401,广州市,44
  1932 +440103,荔湾区,4401
  1933 +440104,越秀区,4401
  1934 +440105,海珠区,4401
  1935 +440106,天河区,4401
  1936 +440111,白云区,4401
  1937 +440112,黄埔区,4401
  1938 +440113,番禺区,4401
  1939 +440114,花都区,4401
  1940 +440115,南沙区,4401
  1941 +440117,从化区,4401
  1942 +440118,增城区,4401
  1943 +4402,韶关市,44
  1944 +440203,武江区,4402
  1945 +440204,浈江区,4402
  1946 +440205,曲江区,4402
  1947 +440222,始兴县,4402
  1948 +440224,仁化县,4402
  1949 +440229,翁源县,4402
  1950 +440232,乳源瑶族自治县,4402
  1951 +440233,新丰县,4402
  1952 +440281,乐昌市,4402
  1953 +440282,南雄市,4402
  1954 +4403,深圳市,44
  1955 +440303,罗湖区,4403
  1956 +440304,福田区,4403
  1957 +440305,南山区,4403
  1958 +440306,宝安区,4403
  1959 +440307,龙岗区,4403
  1960 +440308,盐田区,4403
  1961 +440309,龙华区,4403
  1962 +440310,坪山区,4403
  1963 +440311,光明区,4403
  1964 +4404,珠海市,44
  1965 +440402,香洲区,4404
  1966 +440403,斗门区,4404
  1967 +440404,金湾区,4404
  1968 +4405,汕头市,44
  1969 +440507,龙湖区,4405
  1970 +440511,金平区,4405
  1971 +440512,濠江区,4405
  1972 +440513,潮阳区,4405
  1973 +440514,潮南区,4405
  1974 +440515,澄海区,4405
  1975 +440523,南澳县,4405
  1976 +4406,佛山市,44
  1977 +440604,禅城区,4406
  1978 +440605,南海区,4406
  1979 +440606,顺德区,4406
  1980 +440607,三水区,4406
  1981 +440608,高明区,4406
  1982 +4407,江门市,44
  1983 +440703,蓬江区,4407
  1984 +440704,江海区,4407
  1985 +440705,新会区,4407
  1986 +440781,台山市,4407
  1987 +440783,开平市,4407
  1988 +440784,鹤山市,4407
  1989 +440785,恩平市,4407
  1990 +4408,湛江市,44
  1991 +440802,赤坎区,4408
  1992 +440803,霞山区,4408
  1993 +440804,坡头区,4408
  1994 +440811,麻章区,4408
  1995 +440823,遂溪县,4408
  1996 +440825,徐闻县,4408
  1997 +440881,廉江市,4408
  1998 +440882,雷州市,4408
  1999 +440883,吴川市,4408
  2000 +4409,茂名市,44
  2001 +440902,茂南区,4409
  2002 +440904,电白区,4409
  2003 +440981,高州市,4409
  2004 +440982,化州市,4409
  2005 +440983,信宜市,4409
  2006 +4412,肇庆市,44
  2007 +441202,端州区,4412
  2008 +441203,鼎湖区,4412
  2009 +441204,高要区,4412
  2010 +441223,广宁县,4412
  2011 +441224,怀集县,4412
  2012 +441225,封开县,4412
  2013 +441226,德庆县,4412
  2014 +441284,四会市,4412
  2015 +4413,惠州市,44
  2016 +441302,惠城区,4413
  2017 +441303,惠阳区,4413
  2018 +441322,博罗县,4413
  2019 +441323,惠东县,4413
  2020 +441324,龙门县,4413
  2021 +4414,梅州市,44
  2022 +441402,梅江区,4414
  2023 +441403,梅县区,4414
  2024 +441422,大埔县,4414
  2025 +441423,丰顺县,4414
  2026 +441424,五华县,4414
  2027 +441426,平远县,4414
  2028 +441427,蕉岭县,4414
  2029 +441481,兴宁市,4414
  2030 +4415,汕尾市,44
  2031 +441502,城区,4415
  2032 +441521,海丰县,4415
  2033 +441523,陆河县,4415
  2034 +441581,陆丰市,4415
  2035 +4416,河源市,44
  2036 +441602,源城区,4416
  2037 +441621,紫金县,4416
  2038 +441622,龙川县,4416
  2039 +441623,连平县,4416
  2040 +441624,和平县,4416
  2041 +441625,东源县,4416
  2042 +4417,阳江市,44
  2043 +441702,江城区,4417
  2044 +441704,阳东区,4417
  2045 +441721,阳西县,4417
  2046 +441781,阳春市,4417
  2047 +4418,清远市,44
  2048 +441802,清城区,4418
  2049 +441803,清新区,4418
  2050 +441821,佛冈县,4418
  2051 +441823,阳山县,4418
  2052 +441825,连山壮族瑶族自治县,4418
  2053 +441826,连南瑶族自治县,4418
  2054 +441881,英德市,4418
  2055 +441882,连州市,4418
  2056 +4419,东莞市,44
  2057 +4420,中山市,44
  2058 +4451,潮州市,44
  2059 +445102,湘桥区,4451
  2060 +445103,潮安区,4451
  2061 +445122,饶平县,4451
  2062 +4452,揭阳市,44
  2063 +445202,榕城区,4452
  2064 +445203,揭东区,4452
  2065 +445222,揭西县,4452
  2066 +445224,惠来县,4452
  2067 +445281,普宁市,4452
  2068 +4453,云浮市,44
  2069 +445302,云城区,4453
  2070 +445303,云安区,4453
  2071 +445321,新兴县,4453
  2072 +445322,郁南县,4453
  2073 +445381,罗定市,4453
  2074 +45,广西壮族自治区,
  2075 +4501,南宁市,45
  2076 +450102,兴宁区,4501
  2077 +450103,青秀区,4501
  2078 +450105,江南区,4501
  2079 +450107,西乡塘区,4501
  2080 +450108,良庆区,4501
  2081 +450109,邕宁区,4501
  2082 +450110,武鸣区,4501
  2083 +450123,隆安县,4501
  2084 +450124,马山县,4501
  2085 +450125,上林县,4501
  2086 +450126,宾阳县,4501
  2087 +450127,横县,4501
  2088 +4502,柳州市,45
  2089 +450202,城中区,4502
  2090 +450203,鱼峰区,4502
  2091 +450204,柳南区,4502
  2092 +450205,柳北区,4502
  2093 +450206,柳江区,4502
  2094 +450222,柳城县,4502
  2095 +450223,鹿寨县,4502
  2096 +450224,融安县,4502
  2097 +450225,融水苗族自治县,4502
  2098 +450226,三江侗族自治县,4502
  2099 +4503,桂林市,45
  2100 +450302,秀峰区,4503
  2101 +450303,叠彩区,4503
  2102 +450304,象山区,4503
  2103 +450305,七星区,4503
  2104 +450311,雁山区,4503
  2105 +450312,临桂区,4503
  2106 +450321,阳朔县,4503
  2107 +450323,灵川县,4503
  2108 +450324,全州县,4503
  2109 +450325,兴安县,4503
  2110 +450326,永福县,4503
  2111 +450327,灌阳县,4503
  2112 +450328,龙胜各族自治县,4503
  2113 +450329,资源县,4503
  2114 +450330,平乐县,4503
  2115 +450332,恭城瑶族自治县,4503
  2116 +450381,荔浦市,4503
  2117 +4504,梧州市,45
  2118 +450403,万秀区,4504
  2119 +450405,长洲区,4504
  2120 +450406,龙圩区,4504
  2121 +450421,苍梧县,4504
  2122 +450422,藤县,4504
  2123 +450423,蒙山县,4504
  2124 +450481,岑溪市,4504
  2125 +4505,北海市,45
  2126 +450502,海城区,4505
  2127 +450503,银海区,4505
  2128 +450512,铁山港区,4505
  2129 +450521,合浦县,4505
  2130 +4506,防城港市,45
  2131 +450602,港口区,4506
  2132 +450603,防城区,4506
  2133 +450621,上思县,4506
  2134 +450681,东兴市,4506
  2135 +4507,钦州市,45
  2136 +450702,钦南区,4507
  2137 +450703,钦北区,4507
  2138 +450721,灵山县,4507
  2139 +450722,浦北县,4507
  2140 +4508,贵港市,45
  2141 +450802,港北区,4508
  2142 +450803,港南区,4508
  2143 +450804,覃塘区,4508
  2144 +450821,平南县,4508
  2145 +450881,桂平市,4508
  2146 +4509,玉林市,45
  2147 +450902,玉州区,4509
  2148 +450903,福绵区,4509
  2149 +450921,容县,4509
  2150 +450922,陆川县,4509
  2151 +450923,博白县,4509
  2152 +450924,兴业县,4509
  2153 +450981,北流市,4509
  2154 +4510,百色市,45
  2155 +451002,右江区,4510
  2156 +451021,田阳县,4510
  2157 +451022,田东县,4510
  2158 +451023,平果县,4510
  2159 +451024,德保县,4510
  2160 +451026,那坡县,4510
  2161 +451027,凌云县,4510
  2162 +451028,乐业县,4510
  2163 +451029,田林县,4510
  2164 +451030,西林县,4510
  2165 +451031,隆林各族自治县,4510
  2166 +451081,靖西市,4510
  2167 +4511,贺州市,45
  2168 +451102,八步区,4511
  2169 +451103,平桂区,4511
  2170 +451121,昭平县,4511
  2171 +451122,钟山县,4511
  2172 +451123,富川瑶族自治县,4511
  2173 +4512,河池市,45
  2174 +451202,金城江区,4512
  2175 +451203,宜州区,4512
  2176 +451221,南丹县,4512
  2177 +451222,天峨县,4512
  2178 +451223,凤山县,4512
  2179 +451224,东兰县,4512
  2180 +451225,罗城仫佬族自治县,4512
  2181 +451226,环江毛南族自治县,4512
  2182 +451227,巴马瑶族自治县,4512
  2183 +451228,都安瑶族自治县,4512
  2184 +451229,大化瑶族自治县,4512
  2185 +4513,来宾市,45
  2186 +451302,兴宾区,4513
  2187 +451321,忻城县,4513
  2188 +451322,象州县,4513
  2189 +451323,武宣县,4513
  2190 +451324,金秀瑶族自治县,4513
  2191 +451381,合山市,4513
  2192 +4514,崇左市,45
  2193 +451402,江州区,4514
  2194 +451421,扶绥县,4514
  2195 +451422,宁明县,4514
  2196 +451423,龙州县,4514
  2197 +451424,大新县,4514
  2198 +451425,天等县,4514
  2199 +451481,凭祥市,4514
  2200 +46,海南省,
  2201 +4601,海口市,46
  2202 +460105,秀英区,4601
  2203 +460106,龙华区,4601
  2204 +460107,琼山区,4601
  2205 +460108,美兰区,4601
  2206 +4602,三亚市,46
  2207 +460202,海棠区,4602
  2208 +460203,吉阳区,4602
  2209 +460204,天涯区,4602
  2210 +460205,崖州区,4602
  2211 +4603,三沙市,46
  2212 +4604,儋州市,46
  2213 +469001,五指山市,46
  2214 +469002,琼海市,46
  2215 +469005,文昌市,46
  2216 +469006,万宁市,46
  2217 +469007,东方市,46
  2218 +469021,定安县,46
  2219 +469022,屯昌县,46
  2220 +469023,澄迈县,46
  2221 +469024,临高县,46
  2222 +469025,白沙黎族自治县,46
  2223 +469026,昌江黎族自治县,46
  2224 +469027,乐东黎族自治县,46
  2225 +469028,陵水黎族自治县,46
  2226 +469029,保亭黎族苗族自治县,46
  2227 +469030,琼中黎族苗族自治县,46
  2228 +50,重庆市,
  2229 +500101,万州区,50
  2230 +500102,涪陵区,50
  2231 +500103,渝中区,50
  2232 +500104,大渡口区,50
  2233 +500105,江北区,50
  2234 +500106,沙坪坝区,50
  2235 +500107,九龙坡区,50
  2236 +500108,南岸区,50
  2237 +500109,北碚区,50
  2238 +500110,綦江区,50
  2239 +500111,大足区,50
  2240 +500112,渝北区,50
  2241 +500113,巴南区,50
  2242 +500114,黔江区,50
  2243 +500115,长寿区,50
  2244 +500116,江津区,50
  2245 +500117,合川区,50
  2246 +500118,永川区,50
  2247 +500119,南川区,50
  2248 +500120,璧山区,50
  2249 +500151,铜梁区,50
  2250 +500152,潼南区,50
  2251 +500153,荣昌区,50
  2252 +500154,开州区,50
  2253 +500155,梁平区,50
  2254 +500156,武隆区,50
  2255 +500229,城口县,50
  2256 +500230,丰都县,50
  2257 +500231,垫江县,50
  2258 +500233,忠县,50
  2259 +500235,云阳县,50
  2260 +500236,奉节县,50
  2261 +500237,巫山县,50
  2262 +500238,巫溪县,50
  2263 +500240,石柱土家族自治县,50
  2264 +500241,秀山土家族苗族自治县,50
  2265 +500242,酉阳土家族苗族自治县,50
  2266 +500243,彭水苗族土家族自治县,50
  2267 +51,四川省,
  2268 +5101,成都市,51
  2269 +510104,锦江区,5101
  2270 +510105,青羊区,5101
  2271 +510106,金牛区,5101
  2272 +510107,武侯区,5101
  2273 +510108,成华区,5101
  2274 +510112,龙泉驿区,5101
  2275 +510113,青白江区,5101
  2276 +510114,新都区,5101
  2277 +510115,温江区,5101
  2278 +510116,双流区,5101
  2279 +510117,郫都区,5101
  2280 +510121,金堂县,5101
  2281 +510129,大邑县,5101
  2282 +510131,蒲江县,5101
  2283 +510132,新津县,5101
  2284 +510181,都江堰市,5101
  2285 +510182,彭州市,5101
  2286 +510183,邛崃市,5101
  2287 +510184,崇州市,5101
  2288 +510185,简阳市,5101
  2289 +5103,自贡市,51
  2290 +510302,自流井区,5103
  2291 +510303,贡井区,5103
  2292 +510304,大安区,5103
  2293 +510311,沿滩区,5103
  2294 +510321,荣县,5103
  2295 +510322,富顺县,5103
  2296 +5104,攀枝花市,51
  2297 +510402,东区,5104
  2298 +510403,西区,5104
  2299 +510411,仁和区,5104
  2300 +510421,米易县,5104
  2301 +510422,盐边县,5104
  2302 +5105,泸州市,51
  2303 +510502,江阳区,5105
  2304 +510503,纳溪区,5105
  2305 +510504,龙马潭区,5105
  2306 +510521,泸县,5105
  2307 +510522,合江县,5105
  2308 +510524,叙永县,5105
  2309 +510525,古蔺县,5105
  2310 +5106,德阳市,51
  2311 +510603,旌阳区,5106
  2312 +510604,罗江区,5106
  2313 +510623,中江县,5106
  2314 +510681,广汉市,5106
  2315 +510682,什邡市,5106
  2316 +510683,绵竹市,5106
  2317 +5107,绵阳市,51
  2318 +510703,涪城区,5107
  2319 +510704,游仙区,5107
  2320 +510705,安州区,5107
  2321 +510722,三台县,5107
  2322 +510723,盐亭县,5107
  2323 +510725,梓潼县,5107
  2324 +510726,北川羌族自治县,5107
  2325 +510727,平武县,5107
  2326 +510781,江油市,5107
  2327 +5108,广元市,51
  2328 +510802,利州区,5108
  2329 +510811,昭化区,5108
  2330 +510812,朝天区,5108
  2331 +510821,旺苍县,5108
  2332 +510822,青川县,5108
  2333 +510823,剑阁县,5108
  2334 +510824,苍溪县,5108
  2335 +5109,遂宁市,51
  2336 +510903,船山区,5109
  2337 +510904,安居区,5109
  2338 +510921,蓬溪县,5109
  2339 +510922,射洪县,5109
  2340 +510923,大英县,5109
  2341 +5110,内江市,51
  2342 +511002,市中区,5110
  2343 +511011,东兴区,5110
  2344 +511024,威远县,5110
  2345 +511025,资中县,5110
  2346 +511083,隆昌市,5110
  2347 +5111,乐山市,51
  2348 +511102,市中区,5111
  2349 +511111,沙湾区,5111
  2350 +511112,五通桥区,5111
  2351 +511113,金口河区,5111
  2352 +511123,犍为县,5111
  2353 +511124,井研县,5111
  2354 +511126,夹江县,5111
  2355 +511129,沐川县,5111
  2356 +511132,峨边彝族自治县,5111
  2357 +511133,马边彝族自治县,5111
  2358 +511181,峨眉山市,5111
  2359 +5113,南充市,51
  2360 +511302,顺庆区,5113
  2361 +511303,高坪区,5113
  2362 +511304,嘉陵区,5113
  2363 +511321,南部县,5113
  2364 +511322,营山县,5113
  2365 +511323,蓬安县,5113
  2366 +511324,仪陇县,5113
  2367 +511325,西充县,5113
  2368 +511381,阆中市,5113
  2369 +5114,眉山市,51
  2370 +511402,东坡区,5114
  2371 +511403,彭山区,5114
  2372 +511421,仁寿县,5114
  2373 +511423,洪雅县,5114
  2374 +511424,丹棱县,5114
  2375 +511425,青神县,5114
  2376 +5115,宜宾市,51
  2377 +511502,翠屏区,5115
  2378 +511503,南溪区,5115
  2379 +511504,叙州区,5115
  2380 +511523,江安县,5115
  2381 +511524,长宁县,5115
  2382 +511525,高县,5115
  2383 +511526,珙县,5115
  2384 +511527,筠连县,5115
  2385 +511528,兴文县,5115
  2386 +511529,屏山县,5115
  2387 +5116,广安市,51
  2388 +511602,广安区,5116
  2389 +511603,前锋区,5116
  2390 +511621,岳池县,5116
  2391 +511622,武胜县,5116
  2392 +511623,邻水县,5116
  2393 +511681,华蓥市,5116
  2394 +5117,达州市,51
  2395 +511702,通川区,5117
  2396 +511703,达川区,5117
  2397 +511722,宣汉县,5117
  2398 +511723,开江县,5117
  2399 +511724,大竹县,5117
  2400 +511725,渠县,5117
  2401 +511781,万源市,5117
  2402 +5118,雅安市,51
  2403 +511802,雨城区,5118
  2404 +511803,名山区,5118
  2405 +511822,荥经县,5118
  2406 +511823,汉源县,5118
  2407 +511824,石棉县,5118
  2408 +511825,天全县,5118
  2409 +511826,芦山县,5118
  2410 +511827,宝兴县,5118
  2411 +5119,巴中市,51
  2412 +511902,巴州区,5119
  2413 +511903,恩阳区,5119
  2414 +511921,通江县,5119
  2415 +511922,南江县,5119
  2416 +511923,平昌县,5119
  2417 +5120,资阳市,51
  2418 +512002,雁江区,5120
  2419 +512021,安岳县,5120
  2420 +512022,乐至县,5120
  2421 +5132,阿坝藏族羌族自治州,51
  2422 +513201,马尔康市,5132
  2423 +513221,汶川县,5132
  2424 +513222,理县,5132
  2425 +513223,茂县,5132
  2426 +513224,松潘县,5132
  2427 +513225,九寨沟县,5132
  2428 +513226,金川县,5132
  2429 +513227,小金县,5132
  2430 +513228,黑水县,5132
  2431 +513230,壤塘县,5132
  2432 +513231,阿坝县,5132
  2433 +513232,若尔盖县,5132
  2434 +513233,红原县,5132
  2435 +5133,甘孜藏族自治州,51
  2436 +513301,康定市,5133
  2437 +513322,泸定县,5133
  2438 +513323,丹巴县,5133
  2439 +513324,九龙县,5133
  2440 +513325,雅江县,5133
  2441 +513326,道孚县,5133
  2442 +513327,炉霍县,5133
  2443 +513328,甘孜县,5133
  2444 +513329,新龙县,5133
  2445 +513330,德格县,5133
  2446 +513331,白玉县,5133
  2447 +513332,石渠县,5133
  2448 +513333,色达县,5133
  2449 +513334,理塘县,5133
  2450 +513335,巴塘县,5133
  2451 +513336,乡城县,5133
  2452 +513337,稻城县,5133
  2453 +513338,得荣县,5133
  2454 +5134,凉山彝族自治州,51
  2455 +513401,西昌市,5134
  2456 +513422,木里藏族自治县,5134
  2457 +513423,盐源县,5134
  2458 +513424,德昌县,5134
  2459 +513425,会理县,5134
  2460 +513426,会东县,5134
  2461 +513427,宁南县,5134
  2462 +513428,普格县,5134
  2463 +513429,布拖县,5134
  2464 +513430,金阳县,5134
  2465 +513431,昭觉县,5134
  2466 +513432,喜德县,5134
  2467 +513433,冕宁县,5134
  2468 +513434,越西县,5134
  2469 +513435,甘洛县,5134
  2470 +513436,美姑县,5134
  2471 +513437,雷波县,5134
  2472 +52,贵州省,
  2473 +5201,贵阳市,52
  2474 +520102,南明区,5201
  2475 +520103,云岩区,5201
  2476 +520111,花溪区,5201
  2477 +520112,乌当区,5201
  2478 +520113,白云区,5201
  2479 +520115,观山湖区,5201
  2480 +520121,开阳县,5201
  2481 +520122,息烽县,5201
  2482 +520123,修文县,5201
  2483 +520181,清镇市,5201
  2484 +5202,六盘水市,52
  2485 +520201,钟山区,5202
  2486 +520203,六枝特区,5202
  2487 +520221,水城县,5202
  2488 +520281,盘州市,5202
  2489 +5203,遵义市,52
  2490 +520302,红花岗区,5203
  2491 +520303,汇川区,5203
  2492 +520304,播州区,5203
  2493 +520322,桐梓县,5203
  2494 +520323,绥阳县,5203
  2495 +520324,正安县,5203
  2496 +520325,道真仡佬族苗族自治县,5203
  2497 +520326,务川仡佬族苗族自治县,5203
  2498 +520327,凤冈县,5203
  2499 +520328,湄潭县,5203
  2500 +520329,余庆县,5203
  2501 +520330,习水县,5203
  2502 +520381,赤水市,5203
  2503 +520382,仁怀市,5203
  2504 +5204,安顺市,52
  2505 +520402,西秀区,5204
  2506 +520403,平坝区,5204
  2507 +520422,普定县,5204
  2508 +520423,镇宁布依族苗族自治县,5204
  2509 +520424,关岭布依族苗族自治县,5204
  2510 +520425,紫云苗族布依族自治县,5204
  2511 +5205,毕节市,52
  2512 +520502,七星关区,5205
  2513 +520521,大方县,5205
  2514 +520522,黔西县,5205
  2515 +520523,金沙县,5205
  2516 +520524,织金县,5205
  2517 +520525,纳雍县,5205
  2518 +520526,威宁彝族回族苗族自治县,5205
  2519 +520527,赫章县,5205
  2520 +5206,铜仁市,52
  2521 +520602,碧江区,5206
  2522 +520603,万山区,5206
  2523 +520621,江口县,5206
  2524 +520622,玉屏侗族自治县,5206
  2525 +520623,石阡县,5206
  2526 +520624,思南县,5206
  2527 +520625,印江土家族苗族自治县,5206
  2528 +520626,德江县,5206
  2529 +520627,沿河土家族自治县,5206
  2530 +520628,松桃苗族自治县,5206
  2531 +5223,黔西南布依族苗族自治州,52
  2532 +522301,兴义市,5223
  2533 +522302,兴仁市,5223
  2534 +522323,普安县,5223
  2535 +522324,晴隆县,5223
  2536 +522325,贞丰县,5223
  2537 +522326,望谟县,5223
  2538 +522327,册亨县,5223
  2539 +522328,安龙县,5223
  2540 +5226,黔东南苗族侗族自治州,52
  2541 +522601,凯里市,5226
  2542 +522622,黄平县,5226
  2543 +522623,施秉县,5226
  2544 +522624,三穗县,5226
  2545 +522625,镇远县,5226
  2546 +522626,岑巩县,5226
  2547 +522627,天柱县,5226
  2548 +522628,锦屏县,5226
  2549 +522629,剑河县,5226
  2550 +522630,台江县,5226
  2551 +522631,黎平县,5226
  2552 +522632,榕江县,5226
  2553 +522633,从江县,5226
  2554 +522634,雷山县,5226
  2555 +522635,麻江县,5226
  2556 +522636,丹寨县,5226
  2557 +5227,黔南布依族苗族自治州,52
  2558 +522701,都匀市,5227
  2559 +522702,福泉市,5227
  2560 +522722,荔波县,5227
  2561 +522723,贵定县,5227
  2562 +522725,瓮安县,5227
  2563 +522726,独山县,5227
  2564 +522727,平塘县,5227
  2565 +522728,罗甸县,5227
  2566 +522729,长顺县,5227
  2567 +522730,龙里县,5227
  2568 +522731,惠水县,5227
  2569 +522732,三都水族自治县,5227
  2570 +53,云南省,
  2571 +5301,昆明市,53
  2572 +530102,五华区,5301
  2573 +530103,盘龙区,5301
  2574 +530111,官渡区,5301
  2575 +530112,西山区,5301
  2576 +530113,东川区,5301
  2577 +530114,呈贡区,5301
  2578 +530115,晋宁区,5301
  2579 +530124,富民县,5301
  2580 +530125,宜良县,5301
  2581 +530126,石林彝族自治县,5301
  2582 +530127,嵩明县,5301
  2583 +530128,禄劝彝族苗族自治县,5301
  2584 +530129,寻甸回族彝族自治县,5301
  2585 +530181,安宁市,5301
  2586 +5303,曲靖市,53
  2587 +530302,麒麟区,5303
  2588 +530303,沾益区,5303
  2589 +530304,马龙区,5303
  2590 +530322,陆良县,5303
  2591 +530323,师宗县,5303
  2592 +530324,罗平县,5303
  2593 +530325,富源县,5303
  2594 +530326,会泽县,5303
  2595 +530381,宣威市,5303
  2596 +5304,玉溪市,53
  2597 +530402,红塔区,5304
  2598 +530403,江川区,5304
  2599 +530422,澄江县,5304
  2600 +530423,通海县,5304
  2601 +530424,华宁县,5304
  2602 +530425,易门县,5304
  2603 +530426,峨山彝族自治县,5304
  2604 +530427,新平彝族傣族自治县,5304
  2605 +530428,元江哈尼族彝族傣族自治县,5304
  2606 +5305,保山市,53
  2607 +530502,隆阳区,5305
  2608 +530521,施甸县,5305
  2609 +530523,龙陵县,5305
  2610 +530524,昌宁县,5305
  2611 +530581,腾冲市,5305
  2612 +5306,昭通市,53
  2613 +530602,昭阳区,5306
  2614 +530621,鲁甸县,5306
  2615 +530622,巧家县,5306
  2616 +530623,盐津县,5306
  2617 +530624,大关县,5306
  2618 +530625,永善县,5306
  2619 +530626,绥江县,5306
  2620 +530627,镇雄县,5306
  2621 +530628,彝良县,5306
  2622 +530629,威信县,5306
  2623 +530681,水富市,5306
  2624 +5307,丽江市,53
  2625 +530702,古城区,5307
  2626 +530721,玉龙纳西族自治县,5307
  2627 +530722,永胜县,5307
  2628 +530723,华坪县,5307
  2629 +530724,宁蒗彝族自治县,5307
  2630 +5308,普洱市,53
  2631 +530802,思茅区,5308
  2632 +530821,宁洱哈尼族彝族自治县,5308
  2633 +530822,墨江哈尼族自治县,5308
  2634 +530823,景东彝族自治县,5308
  2635 +530824,景谷傣族彝族自治县,5308
  2636 +530825,镇沅彝族哈尼族拉祜族自治县,5308
  2637 +530826,江城哈尼族彝族自治县,5308
  2638 +530827,孟连傣族拉祜族佤族自治县,5308
  2639 +530828,澜沧拉祜族自治县,5308
  2640 +530829,西盟佤族自治县,5308
  2641 +5309,临沧市,53
  2642 +530902,临翔区,5309
  2643 +530921,凤庆县,5309
  2644 +530922,云县,5309
  2645 +530923,永德县,5309
  2646 +530924,镇康县,5309
  2647 +530925,双江拉祜族佤族布朗族傣族自治县,5309
  2648 +530926,耿马傣族佤族自治县,5309
  2649 +530927,沧源佤族自治县,5309
  2650 +5323,楚雄彝族自治州,53
  2651 +532301,楚雄市,5323
  2652 +532322,双柏县,5323
  2653 +532323,牟定县,5323
  2654 +532324,南华县,5323
  2655 +532325,姚安县,5323
  2656 +532326,大姚县,5323
  2657 +532327,永仁县,5323
  2658 +532328,元谋县,5323
  2659 +532329,武定县,5323
  2660 +532331,禄丰县,5323
  2661 +5325,红河哈尼族彝族自治州,53
  2662 +532501,个旧市,5325
  2663 +532502,开远市,5325
  2664 +532503,蒙自市,5325
  2665 +532504,弥勒市,5325
  2666 +532523,屏边苗族自治县,5325
  2667 +532524,建水县,5325
  2668 +532525,石屏县,5325
  2669 +532527,泸西县,5325
  2670 +532528,元阳县,5325
  2671 +532529,红河县,5325
  2672 +532530,金平苗族瑶族傣族自治县,5325
  2673 +532531,绿春县,5325
  2674 +532532,河口瑶族自治县,5325
  2675 +5326,文山壮族苗族自治州,53
  2676 +532601,文山市,5326
  2677 +532622,砚山县,5326
  2678 +532623,西畴县,5326
  2679 +532624,麻栗坡县,5326
  2680 +532625,马关县,5326
  2681 +532626,丘北县,5326
  2682 +532627,广南县,5326
  2683 +532628,富宁县,5326
  2684 +5328,西双版纳傣族自治州,53
  2685 +532801,景洪市,5328
  2686 +532822,勐海县,5328
  2687 +532823,勐腊县,5328
  2688 +5329,大理白族自治州,53
  2689 +532901,大理市,5329
  2690 +532922,漾濞彝族自治县,5329
  2691 +532923,祥云县,5329
  2692 +532924,宾川县,5329
  2693 +532925,弥渡县,5329
  2694 +532926,南涧彝族自治县,5329
  2695 +532927,巍山彝族回族自治县,5329
  2696 +532928,永平县,5329
  2697 +532929,云龙县,5329
  2698 +532930,洱源县,5329
  2699 +532931,剑川县,5329
  2700 +532932,鹤庆县,5329
  2701 +5331,德宏傣族景颇族自治州,53
  2702 +533102,瑞丽市,5331
  2703 +533103,芒市,5331
  2704 +533122,梁河县,5331
  2705 +533123,盈江县,5331
  2706 +533124,陇川县,5331
  2707 +5333,怒江傈僳族自治州,53
  2708 +533301,泸水市,5333
  2709 +533323,福贡县,5333
  2710 +533324,贡山独龙族怒族自治县,5333
  2711 +533325,兰坪白族普米族自治县,5333
  2712 +5334,迪庆藏族自治州,53
  2713 +533401,香格里拉市,5334
  2714 +533422,德钦县,5334
  2715 +533423,维西傈僳族自治县,5334
  2716 +54,西藏自治区,
  2717 +5401,拉萨市,54
  2718 +540102,城关区,5401
  2719 +540103,堆龙德庆区,5401
  2720 +540104,达孜区,5401
  2721 +540121,林周县,5401
  2722 +540122,当雄县,5401
  2723 +540123,尼木县,5401
  2724 +540124,曲水县,5401
  2725 +540127,墨竹工卡县,5401
  2726 +5402,日喀则市,54
  2727 +540202,桑珠孜区,5402
  2728 +540221,南木林县,5402
  2729 +540222,江孜县,5402
  2730 +540223,定日县,5402
  2731 +540224,萨迦县,5402
  2732 +540225,拉孜县,5402
  2733 +540226,昂仁县,5402
  2734 +540227,谢通门县,5402
  2735 +540228,白朗县,5402
  2736 +540229,仁布县,5402
  2737 +540230,康马县,5402
  2738 +540231,定结县,5402
  2739 +540232,仲巴县,5402
  2740 +540233,亚东县,5402
  2741 +540234,吉隆县,5402
  2742 +540235,聂拉木县,5402
  2743 +540236,萨嘎县,5402
  2744 +540237,岗巴县,5402
  2745 +5403,昌都市,54
  2746 +540302,卡若区,5403
  2747 +540321,江达县,5403
  2748 +540322,贡觉县,5403
  2749 +540323,类乌齐县,5403
  2750 +540324,丁青县,5403
  2751 +540325,察雅县,5403
  2752 +540326,八宿县,5403
  2753 +540327,左贡县,5403
  2754 +540328,芒康县,5403
  2755 +540329,洛隆县,5403
  2756 +540330,边坝县,5403
  2757 +5404,林芝市,54
  2758 +540402,巴宜区,5404
  2759 +540421,工布江达县,5404
  2760 +540422,米林县,5404
  2761 +540423,墨脱县,5404
  2762 +540424,波密县,5404
  2763 +540425,察隅县,5404
  2764 +540426,朗县,5404
  2765 +5405,山南市,54
  2766 +540502,乃东区,5405
  2767 +540521,扎囊县,5405
  2768 +540522,贡嘎县,5405
  2769 +540523,桑日县,5405
  2770 +540524,琼结县,5405
  2771 +540525,曲松县,5405
  2772 +540526,措美县,5405
  2773 +540527,洛扎县,5405
  2774 +540528,加查县,5405
  2775 +540529,隆子县,5405
  2776 +540530,错那县,5405
  2777 +540531,浪卡子县,5405
  2778 +5406,那曲市,54
  2779 +540602,色尼区,5406
  2780 +540621,嘉黎县,5406
  2781 +540622,比如县,5406
  2782 +540623,聂荣县,5406
  2783 +540624,安多县,5406
  2784 +540625,申扎县,5406
  2785 +540626,索县,5406
  2786 +540627,班戈县,5406
  2787 +540628,巴青县,5406
  2788 +540629,尼玛县,5406
  2789 +540630,双湖县,5406
  2790 +5425,阿里地区,54
  2791 +542521,普兰县,5425
  2792 +542522,札达县,5425
  2793 +542523,噶尔县,5425
  2794 +542524,日土县,5425
  2795 +542525,革吉县,5425
  2796 +542526,改则县,5425
  2797 +542527,措勤县,5425
  2798 +61,陕西省,
  2799 +6101,西安市,61
  2800 +610102,新城区,6101
  2801 +610103,碑林区,6101
  2802 +610104,莲湖区,6101
  2803 +610111,灞桥区,6101
  2804 +610112,未央区,6101
  2805 +610113,雁塔区,6101
  2806 +610114,阎良区,6101
  2807 +610115,临潼区,6101
  2808 +610116,长安区,6101
  2809 +610117,高陵区,6101
  2810 +610118,鄠邑区,6101
  2811 +610122,蓝田县,6101
  2812 +610124,周至县,6101
  2813 +6102,铜川市,61
  2814 +610202,王益区,6102
  2815 +610203,印台区,6102
  2816 +610204,耀州区,6102
  2817 +610222,宜君县,6102
  2818 +6103,宝鸡市,61
  2819 +610302,渭滨区,6103
  2820 +610303,金台区,6103
  2821 +610304,陈仓区,6103
  2822 +610322,凤翔县,6103
  2823 +610323,岐山县,6103
  2824 +610324,扶风县,6103
  2825 +610326,眉县,6103
  2826 +610327,陇县,6103
  2827 +610328,千阳县,6103
  2828 +610329,麟游县,6103
  2829 +610330,凤县,6103
  2830 +610331,太白县,6103
  2831 +6104,咸阳市,61
  2832 +610402,秦都区,6104
  2833 +610403,杨陵区,6104
  2834 +610404,渭城区,6104
  2835 +610422,三原县,6104
  2836 +610423,泾阳县,6104
  2837 +610424,乾县,6104
  2838 +610425,礼泉县,6104
  2839 +610426,永寿县,6104
  2840 +610428,长武县,6104
  2841 +610429,旬邑县,6104
  2842 +610430,淳化县,6104
  2843 +610431,武功县,6104
  2844 +610481,兴平市,6104
  2845 +610482,彬州市,6104
  2846 +6105,渭南市,61
  2847 +610502,临渭区,6105
  2848 +610503,华州区,6105
  2849 +610522,潼关县,6105
  2850 +610523,大荔县,6105
  2851 +610524,合阳县,6105
  2852 +610525,澄城县,6105
  2853 +610526,蒲城县,6105
  2854 +610527,白水县,6105
  2855 +610528,富平县,6105
  2856 +610581,韩城市,6105
  2857 +610582,华阴市,6105
  2858 +6106,延安市,61
  2859 +610602,宝塔区,6106
  2860 +610603,安塞区,6106
  2861 +610621,延长县,6106
  2862 +610622,延川县,6106
  2863 +610623,子长县,6106
  2864 +610625,志丹县,6106
  2865 +610626,吴起县,6106
  2866 +610627,甘泉县,6106
  2867 +610628,富县,6106
  2868 +610629,洛川县,6106
  2869 +610630,宜川县,6106
  2870 +610631,黄龙县,6106
  2871 +610632,黄陵县,6106
  2872 +6107,汉中市,61
  2873 +610702,汉台区,6107
  2874 +610703,南郑区,6107
  2875 +610722,城固县,6107
  2876 +610723,洋县,6107
  2877 +610724,西乡县,6107
  2878 +610725,勉县,6107
  2879 +610726,宁强县,6107
  2880 +610727,略阳县,6107
  2881 +610728,镇巴县,6107
  2882 +610729,留坝县,6107
  2883 +610730,佛坪县,6107
  2884 +6108,榆林市,61
  2885 +610802,榆阳区,6108
  2886 +610803,横山区,6108
  2887 +610822,府谷县,6108
  2888 +610824,靖边县,6108
  2889 +610825,定边县,6108
  2890 +610826,绥德县,6108
  2891 +610827,米脂县,6108
  2892 +610828,佳县,6108
  2893 +610829,吴堡县,6108
  2894 +610830,清涧县,6108
  2895 +610831,子洲县,6108
  2896 +610881,神木市,6108
  2897 +6109,安康市,61
  2898 +610902,汉滨区,6109
  2899 +610921,汉阴县,6109
  2900 +610922,石泉县,6109
  2901 +610923,宁陕县,6109
  2902 +610924,紫阳县,6109
  2903 +610925,岚皋县,6109
  2904 +610926,平利县,6109
  2905 +610927,镇坪县,6109
  2906 +610928,旬阳县,6109
  2907 +610929,白河县,6109
  2908 +6110,商洛市,61
  2909 +611002,商州区,6110
  2910 +611021,洛南县,6110
  2911 +611022,丹凤县,6110
  2912 +611023,商南县,6110
  2913 +611024,山阳县,6110
  2914 +611025,镇安县,6110
  2915 +611026,柞水县,6110
  2916 +62,甘肃省,
  2917 +6201,兰州市,62
  2918 +620102,城关区,6201
  2919 +620103,七里河区,6201
  2920 +620104,西固区,6201
  2921 +620105,安宁区,6201
  2922 +620111,红古区,6201
  2923 +620121,永登县,6201
  2924 +620122,皋兰县,6201
  2925 +620123,榆中县,6201
  2926 +6202,嘉峪关市,62
  2927 +6203,金昌市,62
  2928 +620302,金川区,6203
  2929 +620321,永昌县,6203
  2930 +6204,白银市,62
  2931 +620402,白银区,6204
  2932 +620403,平川区,6204
  2933 +620421,靖远县,6204
  2934 +620422,会宁县,6204
  2935 +620423,景泰县,6204
  2936 +6205,天水市,62
  2937 +620502,秦州区,6205
  2938 +620503,麦积区,6205
  2939 +620521,清水县,6205
  2940 +620522,秦安县,6205
  2941 +620523,甘谷县,6205
  2942 +620524,武山县,6205
  2943 +620525,张家川回族自治县,6205
  2944 +6206,武威市,62
  2945 +620602,凉州区,6206
  2946 +620621,民勤县,6206
  2947 +620622,古浪县,6206
  2948 +620623,天祝藏族自治县,6206
  2949 +6207,张掖市,62
  2950 +620702,甘州区,6207
  2951 +620721,肃南裕固族自治县,6207
  2952 +620722,民乐县,6207
  2953 +620723,临泽县,6207
  2954 +620724,高台县,6207
  2955 +620725,山丹县,6207
  2956 +6208,平凉市,62
  2957 +620802,崆峒区,6208
  2958 +620821,泾川县,6208
  2959 +620822,灵台县,6208
  2960 +620823,崇信县,6208
  2961 +620825,庄浪县,6208
  2962 +620826,静宁县,6208
  2963 +620881,华亭市,6208
  2964 +6209,酒泉市,62
  2965 +620902,肃州区,6209
  2966 +620921,金塔县,6209
  2967 +620922,瓜州县,6209
  2968 +620923,肃北蒙古族自治县,6209
  2969 +620924,阿克塞哈萨克族自治县,6209
  2970 +620981,玉门市,6209
  2971 +620982,敦煌市,6209
  2972 +6210,庆阳市,62
  2973 +621002,西峰区,6210
  2974 +621021,庆城县,6210
  2975 +621022,环县,6210
  2976 +621023,华池县,6210
  2977 +621024,合水县,6210
  2978 +621025,正宁县,6210
  2979 +621026,宁县,6210
  2980 +621027,镇原县,6210
  2981 +6211,定西市,62
  2982 +621102,安定区,6211
  2983 +621121,通渭县,6211
  2984 +621122,陇西县,6211
  2985 +621123,渭源县,6211
  2986 +621124,临洮县,6211
  2987 +621125,漳县,6211
  2988 +621126,岷县,6211
  2989 +6212,陇南市,62
  2990 +621202,武都区,6212
  2991 +621221,成县,6212
  2992 +621222,文县,6212
  2993 +621223,宕昌县,6212
  2994 +621224,康县,6212
  2995 +621225,西和县,6212
  2996 +621226,礼县,6212
  2997 +621227,徽县,6212
  2998 +621228,两当县,6212
  2999 +6229,临夏回族自治州,62
  3000 +622901,临夏市,6229
  3001 +622921,临夏县,6229
  3002 +622922,康乐县,6229
  3003 +622923,永靖县,6229
  3004 +622924,广河县,6229
  3005 +622925,和政县,6229
  3006 +622926,东乡族自治县,6229
  3007 +622927,积石山保安族东乡族撒拉族自治县,6229
  3008 +6230,甘南藏族自治州,62
  3009 +623001,合作市,6230
  3010 +623021,临潭县,6230
  3011 +623022,卓尼县,6230
  3012 +623023,舟曲县,6230
  3013 +623024,迭部县,6230
  3014 +623025,玛曲县,6230
  3015 +623026,碌曲县,6230
  3016 +623027,夏河县,6230
  3017 +63,青海省,
  3018 +6301,西宁市,63
  3019 +630102,城东区,6301
  3020 +630103,城中区,6301
  3021 +630104,城西区,6301
  3022 +630105,城北区,6301
  3023 +630121,大通回族土族自治县,6301
  3024 +630122,湟中县,6301
  3025 +630123,湟源县,6301
  3026 +6302,海东市,63
  3027 +630202,乐都区,6302
  3028 +630203,平安区,6302
  3029 +630222,民和回族土族自治县,6302
  3030 +630223,互助土族自治县,6302
  3031 +630224,化隆回族自治县,6302
  3032 +630225,循化撒拉族自治县,6302
  3033 +6322,海北藏族自治州,63
  3034 +632221,门源回族自治县,6322
  3035 +632222,祁连县,6322
  3036 +632223,海晏县,6322
  3037 +632224,刚察县,6322
  3038 +6323,黄南藏族自治州,63
  3039 +632321,同仁县,6323
  3040 +632322,尖扎县,6323
  3041 +632323,泽库县,6323
  3042 +632324,河南蒙古族自治县,6323
  3043 +6325,海南藏族自治州,63
  3044 +632521,共和县,6325
  3045 +632522,同德县,6325
  3046 +632523,贵德县,6325
  3047 +632524,兴海县,6325
  3048 +632525,贵南县,6325
  3049 +6326,果洛藏族自治州,63
  3050 +632621,玛沁县,6326
  3051 +632622,班玛县,6326
  3052 +632623,甘德县,6326
  3053 +632624,达日县,6326
  3054 +632625,久治县,6326
  3055 +632626,玛多县,6326
  3056 +6327,玉树藏族自治州,63
  3057 +632701,玉树市,6327
  3058 +632722,杂多县,6327
  3059 +632723,称多县,6327
  3060 +632724,治多县,6327
  3061 +632725,囊谦县,6327
  3062 +632726,曲麻莱县,6327
  3063 +6328,海西蒙古族藏族自治州,63
  3064 +632801,格尔木市,6328
  3065 +632802,德令哈市,6328
  3066 +632803,茫崖市,6328
  3067 +632821,乌兰县,6328
  3068 +632822,都兰县,6328
  3069 +632823,天峻县,6328
  3070 +64,宁夏回族自治区,
  3071 +6401,银川市,64
  3072 +640104,兴庆区,6401
  3073 +640105,西夏区,6401
  3074 +640106,金凤区,6401
  3075 +640121,永宁县,6401
  3076 +640122,贺兰县,6401
  3077 +640181,灵武市,6401
  3078 +6402,石嘴山市,64
  3079 +640202,大武口区,6402
  3080 +640205,惠农区,6402
  3081 +640221,平罗县,6402
  3082 +6403,吴忠市,64
  3083 +640302,利通区,6403
  3084 +640303,红寺堡区,6403
  3085 +640323,盐池县,6403
  3086 +640324,同心县,6403
  3087 +640381,青铜峡市,6403
  3088 +6404,固原市,64
  3089 +640402,原州区,6404
  3090 +640422,西吉县,6404
  3091 +640423,隆德县,6404
  3092 +640424,泾源县,6404
  3093 +640425,彭阳县,6404
  3094 +6405,中卫市,64
  3095 +640502,沙坡头区,6405
  3096 +640521,中宁县,6405
  3097 +640522,海原县,6405
  3098 +65,新疆维吾尔自治区,
  3099 +6501,乌鲁木齐市,65
  3100 +650102,天山区,6501
  3101 +650103,沙依巴克区,6501
  3102 +650104,新市区,6501
  3103 +650105,水磨沟区,6501
  3104 +650106,头屯河区,6501
  3105 +650107,达坂城区,6501
  3106 +650109,米东区,6501
  3107 +650121,乌鲁木齐县,6501
  3108 +6502,克拉玛依市,65
  3109 +650202,独山子区,6502
  3110 +650203,克拉玛依区,6502
  3111 +650204,白碱滩区,6502
  3112 +650205,乌尔禾区,6502
  3113 +6504,吐鲁番市,65
  3114 +650402,高昌区,6504
  3115 +650421,鄯善县,6504
  3116 +650422,托克逊县,6504
  3117 +6505,哈密市,65
  3118 +650502,伊州区,6505
  3119 +650521,巴里坤哈萨克自治县,6505
  3120 +650522,伊吾县,6505
  3121 +6523,昌吉回族自治州,65
  3122 +652301,昌吉市,6523
  3123 +652302,阜康市,6523
  3124 +652323,呼图壁县,6523
  3125 +652324,玛纳斯县,6523
  3126 +652325,奇台县,6523
  3127 +652327,吉木萨尔县,6523
  3128 +652328,木垒哈萨克自治县,6523
  3129 +6527,博尔塔拉蒙古自治州,65
  3130 +652701,博乐市,6527
  3131 +652702,阿拉山口市,6527
  3132 +652722,精河县,6527
  3133 +652723,温泉县,6527
  3134 +6528,巴音郭楞蒙古自治州,65
  3135 +652801,库尔勒市,6528
  3136 +652822,轮台县,6528
  3137 +652823,尉犁县,6528
  3138 +652824,若羌县,6528
  3139 +652825,且末县,6528
  3140 +652826,焉耆回族自治县,6528
  3141 +652827,和静县,6528
  3142 +652828,和硕县,6528
  3143 +652829,博湖县,6528
  3144 +6529,阿克苏地区,65
  3145 +652901,阿克苏市,6529
  3146 +652922,温宿县,6529
  3147 +652923,库车县,6529
  3148 +652924,沙雅县,6529
  3149 +652925,新和县,6529
  3150 +652926,拜城县,6529
  3151 +652927,乌什县,6529
  3152 +652928,阿瓦提县,6529
  3153 +652929,柯坪县,6529
  3154 +6530,克孜勒苏柯尔克孜自治州,65
  3155 +653001,阿图什市,6530
  3156 +653022,阿克陶县,6530
  3157 +653023,阿合奇县,6530
  3158 +653024,乌恰县,6530
  3159 +6531,喀什地区,65
  3160 +653101,喀什市,6531
  3161 +653121,疏附县,6531
  3162 +653122,疏勒县,6531
  3163 +653123,英吉沙县,6531
  3164 +653124,泽普县,6531
  3165 +653125,莎车县,6531
  3166 +653126,叶城县,6531
  3167 +653127,麦盖提县,6531
  3168 +653128,岳普湖县,6531
  3169 +653129,伽师县,6531
  3170 +653130,巴楚县,6531
  3171 +653131,塔什库尔干塔吉克自治县,6531
  3172 +6532,和田地区,65
  3173 +653201,和田市,6532
  3174 +653221,和田县,6532
  3175 +653222,墨玉县,6532
  3176 +653223,皮山县,6532
  3177 +653224,洛浦县,6532
  3178 +653225,策勒县,6532
  3179 +653226,于田县,6532
  3180 +653227,民丰县,6532
  3181 +6540,伊犁哈萨克自治州,65
  3182 +654002,伊宁市,6540
  3183 +654003,奎屯市,6540
  3184 +654004,霍尔果斯市,6540
  3185 +654021,伊宁县,6540
  3186 +654022,察布查尔锡伯自治县,6540
  3187 +654023,霍城县,6540
  3188 +654024,巩留县,6540
  3189 +654025,新源县,6540
  3190 +654026,昭苏县,6540
  3191 +654027,特克斯县,6540
  3192 +654028,尼勒克县,6540
  3193 +6542,塔城地区,65
  3194 +654201,塔城市,6542
  3195 +654202,乌苏市,6542
  3196 +654221,额敏县,6542
  3197 +654223,沙湾县,6542
  3198 +654224,托里县,6542
  3199 +654225,裕民县,6542
  3200 +654226,和布克赛尔蒙古自治县,6542
  3201 +6543,阿勒泰地区,65
  3202 +654301,阿勒泰市,6543
  3203 +654321,布尔津县,6543
  3204 +654322,富蕴县,6543
  3205 +654323,福海县,6543
  3206 +654324,哈巴河县,6543
  3207 +654325,青河县,6543
  3208 +654326,吉木乃县,6543
  3209 +659001,石河子市,65
  3210 +659002,阿拉尔市,65
  3211 +659003,图木舒克市,65
  3212 +659004,五家渠市,65
  3213 +659005,北屯市,65
  3214 +659006,铁门关市,65
  3215 +659007,双河市,65
  3216 +659008,可克达拉市,65
  3217 +659009,昆玉市,65
  3218 +71,台湾省,
  3219 +81,香港特别行政区,
  3220 +82,澳门特别行政区,
0 3221 \ No newline at end of file
... ...
web_src/package-lock.json
... ... @@ -8,7 +8,7 @@
8 8 "name": "gb_web",
9 9 "version": "1.0.0",
10 10 "dependencies": {
11   - "@liveqing/liveplayer": "^2.7.0",
  11 + "@liveqing/liveplayer": "^2.7.10",
12 12 "axios": "^0.24.0",
13 13 "core-js": "^2.6.5",
14 14 "echarts": "^4.9.0",
... ... @@ -71,9 +71,9 @@
71 71 }
72 72 },
73 73 "node_modules/@liveqing/liveplayer": {
74   - "version": "2.7.0",
75   - "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.0.tgz",
76   - "integrity": "sha512-SWveQRqhhfJzkcpmHZxL6eLn+xLQuub888/JiBtUDHgt1eVwYYsorDiGcAKciNcyD70PuMfQ3+QrLoLbWE2vWA=="
  74 + "version": "2.7.10",
  75 + "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.10.tgz",
  76 + "integrity": "sha512-OrRzy2t0WZvO/h+hxMYL2+Ips7ON75l+PH8rjZDT7sps1zKW6dct6qPJm3EsVQuttUQ0dVGu3UXaSUm5gEM4dQ=="
77 77 },
78 78 "node_modules/@mapbox/jsonlint-lines-primitives": {
79 79 "version": "2.0.2",
... ... @@ -184,15 +184,19 @@
184 184 }
185 185 },
186 186 "node_modules/ajv": {
187   - "version": "5.5.2",
188   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-5.5.2.tgz",
189   - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
  187 + "version": "6.12.6",
  188 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
  189 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
190 190 "dev": true,
191 191 "dependencies": {
192   - "co": "^4.6.0",
193   - "fast-deep-equal": "^1.0.0",
  192 + "fast-deep-equal": "^3.1.1",
194 193 "fast-json-stable-stringify": "^2.0.0",
195   - "json-schema-traverse": "^0.3.0"
  194 + "json-schema-traverse": "^0.4.1",
  195 + "uri-js": "^4.2.2"
  196 + },
  197 + "funding": {
  198 + "type": "github",
  199 + "url": "https://github.com/sponsors/epoberezkin"
196 200 }
197 201 },
198 202 "node_modules/ajv-keywords": {
... ... @@ -2111,8 +2115,8 @@
2111 2115 },
2112 2116 "node_modules/co": {
2113 2117 "version": "4.6.0",
2114   - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz",
2115   - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
  2118 + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
  2119 + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
2116 2120 "dev": true,
2117 2121 "engines": {
2118 2122 "iojs": ">= 1.0.0",
... ... @@ -4620,9 +4624,9 @@
4620 4624 }
4621 4625 },
4622 4626 "node_modules/fast-deep-equal": {
4623   - "version": "1.1.0",
4624   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz",
4625   - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
  4627 + "version": "3.1.3",
  4628 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
  4629 + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
4626 4630 "dev": true
4627 4631 },
4628 4632 "node_modules/fast-json-stable-stringify": {
... ... @@ -4665,30 +4669,6 @@
4665 4669 "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0"
4666 4670 }
4667 4671 },
4668   - "node_modules/file-loader/node_modules/ajv": {
4669   - "version": "6.12.5",
4670   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
4671   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
4672   - "dev": true,
4673   - "dependencies": {
4674   - "fast-deep-equal": "^3.1.1",
4675   - "fast-json-stable-stringify": "^2.0.0",
4676   - "json-schema-traverse": "^0.4.1",
4677   - "uri-js": "^4.2.2"
4678   - }
4679   - },
4680   - "node_modules/file-loader/node_modules/fast-deep-equal": {
4681   - "version": "3.1.3",
4682   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
4683   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
4684   - "dev": true
4685   - },
4686   - "node_modules/file-loader/node_modules/json-schema-traverse": {
4687   - "version": "0.4.1",
4688   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
4689   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
4690   - "dev": true
4691   - },
4692 4672 "node_modules/file-loader/node_modules/schema-utils": {
4693 4673 "version": "0.4.7",
4694 4674 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -6126,9 +6106,9 @@
6126 6106 "dev": true
6127 6107 },
6128 6108 "node_modules/json-schema-traverse": {
6129   - "version": "0.3.1",
6130   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.3.1.tgz",
6131   - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
  6109 + "version": "0.4.1",
  6110 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
  6111 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
6132 6112 "dev": true
6133 6113 },
6134 6114 "node_modules/json-stringify-pretty-compact": {
... ... @@ -8770,30 +8750,6 @@
8770 8750 "node": ">= 4"
8771 8751 }
8772 8752 },
8773   - "node_modules/postcss-loader/node_modules/ajv": {
8774   - "version": "6.12.5",
8775   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
8776   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
8777   - "dev": true,
8778   - "dependencies": {
8779   - "fast-deep-equal": "^3.1.1",
8780   - "fast-json-stable-stringify": "^2.0.0",
8781   - "json-schema-traverse": "^0.4.1",
8782   - "uri-js": "^4.2.2"
8783   - }
8784   - },
8785   - "node_modules/postcss-loader/node_modules/fast-deep-equal": {
8786   - "version": "3.1.3",
8787   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
8788   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
8789   - "dev": true
8790   - },
8791   - "node_modules/postcss-loader/node_modules/json-schema-traverse": {
8792   - "version": "0.4.1",
8793   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
8794   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
8795   - "dev": true
8796   - },
8797 8753 "node_modules/postcss-loader/node_modules/schema-utils": {
8798 8754 "version": "0.4.7",
8799 8755 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -11500,6 +11456,30 @@
11500 11456 "node": ">= 4.3 < 5.0.0 || >= 5.10"
11501 11457 }
11502 11458 },
  11459 + "node_modules/schema-utils/node_modules/ajv": {
  11460 + "version": "5.5.2",
  11461 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
  11462 + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==",
  11463 + "dev": true,
  11464 + "dependencies": {
  11465 + "co": "^4.6.0",
  11466 + "fast-deep-equal": "^1.0.0",
  11467 + "fast-json-stable-stringify": "^2.0.0",
  11468 + "json-schema-traverse": "^0.3.0"
  11469 + }
  11470 + },
  11471 + "node_modules/schema-utils/node_modules/fast-deep-equal": {
  11472 + "version": "1.1.0",
  11473 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
  11474 + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==",
  11475 + "dev": true
  11476 + },
  11477 + "node_modules/schema-utils/node_modules/json-schema-traverse": {
  11478 + "version": "0.3.1",
  11479 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
  11480 + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==",
  11481 + "dev": true
  11482 + },
11503 11483 "node_modules/select": {
11504 11484 "version": "1.1.2",
11505 11485 "resolved": "https://registry.npm.taobao.org/select/download/select-1.1.2.tgz",
... ... @@ -12721,36 +12701,12 @@
12721 12701 "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0"
12722 12702 }
12723 12703 },
12724   - "node_modules/uglifyjs-webpack-plugin/node_modules/ajv": {
12725   - "version": "6.12.5",
12726   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
12727   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
12728   - "dev": true,
12729   - "dependencies": {
12730   - "fast-deep-equal": "^3.1.1",
12731   - "fast-json-stable-stringify": "^2.0.0",
12732   - "json-schema-traverse": "^0.4.1",
12733   - "uri-js": "^4.2.2"
12734   - }
12735   - },
12736 12704 "node_modules/uglifyjs-webpack-plugin/node_modules/commander": {
12737 12705 "version": "2.13.0",
12738 12706 "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz?cache=0&sync_timestamp=1598576136669&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.13.0.tgz",
12739 12707 "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=",
12740 12708 "dev": true
12741 12709 },
12742   - "node_modules/uglifyjs-webpack-plugin/node_modules/fast-deep-equal": {
12743   - "version": "3.1.3",
12744   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
12745   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
12746   - "dev": true
12747   - },
12748   - "node_modules/uglifyjs-webpack-plugin/node_modules/json-schema-traverse": {
12749   - "version": "0.4.1",
12750   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
12751   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
12752   - "dev": true
12753   - },
12754 12710 "node_modules/uglifyjs-webpack-plugin/node_modules/schema-utils": {
12755 12711 "version": "0.4.7",
12756 12712 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -14082,24 +14038,6 @@
14082 14038 "source-map": "~0.6.1"
14083 14039 }
14084 14040 },
14085   - "node_modules/webpack/node_modules/ajv": {
14086   - "version": "6.12.5",
14087   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
14088   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
14089   - "dev": true,
14090   - "dependencies": {
14091   - "fast-deep-equal": "^3.1.1",
14092   - "fast-json-stable-stringify": "^2.0.0",
14093   - "json-schema-traverse": "^0.4.1",
14094   - "uri-js": "^4.2.2"
14095   - }
14096   - },
14097   - "node_modules/webpack/node_modules/fast-deep-equal": {
14098   - "version": "3.1.3",
14099   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
14100   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
14101   - "dev": true
14102   - },
14103 14041 "node_modules/webpack/node_modules/has-flag": {
14104 14042 "version": "2.0.0",
14105 14043 "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz",
... ... @@ -14109,12 +14047,6 @@
14109 14047 "node": ">=0.10.0"
14110 14048 }
14111 14049 },
14112   - "node_modules/webpack/node_modules/json-schema-traverse": {
14113   - "version": "0.4.1",
14114   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
14115   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
14116   - "dev": true
14117   - },
14118 14050 "node_modules/webpack/node_modules/source-map": {
14119 14051 "version": "0.5.7",
14120 14052 "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz",
... ... @@ -14464,9 +14396,9 @@
14464 14396 },
14465 14397 "dependencies": {
14466 14398 "@liveqing/liveplayer": {
14467   - "version": "2.7.0",
14468   - "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.0.tgz",
14469   - "integrity": "sha512-SWveQRqhhfJzkcpmHZxL6eLn+xLQuub888/JiBtUDHgt1eVwYYsorDiGcAKciNcyD70PuMfQ3+QrLoLbWE2vWA=="
  14399 + "version": "2.7.10",
  14400 + "resolved": "https://registry.npmmirror.com/@liveqing/liveplayer/-/liveplayer-2.7.10.tgz",
  14401 + "integrity": "sha512-OrRzy2t0WZvO/h+hxMYL2+Ips7ON75l+PH8rjZDT7sps1zKW6dct6qPJm3EsVQuttUQ0dVGu3UXaSUm5gEM4dQ=="
14470 14402 },
14471 14403 "@mapbox/jsonlint-lines-primitives": {
14472 14404 "version": "2.0.2",
... ... @@ -14551,15 +14483,15 @@
14551 14483 }
14552 14484 },
14553 14485 "ajv": {
14554   - "version": "5.5.2",
14555   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-5.5.2.tgz",
14556   - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
  14486 + "version": "6.12.6",
  14487 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
  14488 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
14557 14489 "dev": true,
14558 14490 "requires": {
14559   - "co": "^4.6.0",
14560   - "fast-deep-equal": "^1.0.0",
  14491 + "fast-deep-equal": "^3.1.1",
14561 14492 "fast-json-stable-stringify": "^2.0.0",
14562   - "json-schema-traverse": "^0.3.0"
  14493 + "json-schema-traverse": "^0.4.1",
  14494 + "uri-js": "^4.2.2"
14563 14495 }
14564 14496 },
14565 14497 "ajv-keywords": {
... ... @@ -16303,8 +16235,8 @@
16303 16235 },
16304 16236 "co": {
16305 16237 "version": "4.6.0",
16306   - "resolved": "https://registry.npm.taobao.org/co/download/co-4.6.0.tgz",
16307   - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
  16238 + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
  16239 + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
16308 16240 "dev": true
16309 16241 },
16310 16242 "coa": {
... ... @@ -18423,9 +18355,9 @@
18423 18355 }
18424 18356 },
18425 18357 "fast-deep-equal": {
18426   - "version": "1.1.0",
18427   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz",
18428   - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=",
  18358 + "version": "3.1.3",
  18359 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
  18360 + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
18429 18361 "dev": true
18430 18362 },
18431 18363 "fast-json-stable-stringify": {
... ... @@ -18459,30 +18391,6 @@
18459 18391 "schema-utils": "^0.4.5"
18460 18392 },
18461 18393 "dependencies": {
18462   - "ajv": {
18463   - "version": "6.12.5",
18464   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
18465   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
18466   - "dev": true,
18467   - "requires": {
18468   - "fast-deep-equal": "^3.1.1",
18469   - "fast-json-stable-stringify": "^2.0.0",
18470   - "json-schema-traverse": "^0.4.1",
18471   - "uri-js": "^4.2.2"
18472   - }
18473   - },
18474   - "fast-deep-equal": {
18475   - "version": "3.1.3",
18476   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
18477   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
18478   - "dev": true
18479   - },
18480   - "json-schema-traverse": {
18481   - "version": "0.4.1",
18482   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
18483   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
18484   - "dev": true
18485   - },
18486 18394 "schema-utils": {
18487 18395 "version": "0.4.7",
18488 18396 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -19648,9 +19556,9 @@
19648 19556 "dev": true
19649 19557 },
19650 19558 "json-schema-traverse": {
19651   - "version": "0.3.1",
19652   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.3.1.tgz",
19653   - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
  19559 + "version": "0.4.1",
  19560 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
  19561 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
19654 19562 "dev": true
19655 19563 },
19656 19564 "json-stringify-pretty-compact": {
... ... @@ -21822,30 +21730,6 @@
21822 21730 "schema-utils": "^0.4.0"
21823 21731 },
21824 21732 "dependencies": {
21825   - "ajv": {
21826   - "version": "6.12.5",
21827   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
21828   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
21829   - "dev": true,
21830   - "requires": {
21831   - "fast-deep-equal": "^3.1.1",
21832   - "fast-json-stable-stringify": "^2.0.0",
21833   - "json-schema-traverse": "^0.4.1",
21834   - "uri-js": "^4.2.2"
21835   - }
21836   - },
21837   - "fast-deep-equal": {
21838   - "version": "3.1.3",
21839   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
21840   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
21841   - "dev": true
21842   - },
21843   - "json-schema-traverse": {
21844   - "version": "0.4.1",
21845   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
21846   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
21847   - "dev": true
21848   - },
21849 21733 "schema-utils": {
21850 21734 "version": "0.4.7",
21851 21735 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -24097,6 +23981,32 @@
24097 23981 "dev": true,
24098 23982 "requires": {
24099 23983 "ajv": "^5.0.0"
  23984 + },
  23985 + "dependencies": {
  23986 + "ajv": {
  23987 + "version": "5.5.2",
  23988 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
  23989 + "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==",
  23990 + "dev": true,
  23991 + "requires": {
  23992 + "co": "^4.6.0",
  23993 + "fast-deep-equal": "^1.0.0",
  23994 + "fast-json-stable-stringify": "^2.0.0",
  23995 + "json-schema-traverse": "^0.3.0"
  23996 + }
  23997 + },
  23998 + "fast-deep-equal": {
  23999 + "version": "1.1.0",
  24000 + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
  24001 + "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==",
  24002 + "dev": true
  24003 + },
  24004 + "json-schema-traverse": {
  24005 + "version": "0.3.1",
  24006 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
  24007 + "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==",
  24008 + "dev": true
  24009 + }
24100 24010 }
24101 24011 },
24102 24012 "select": {
... ... @@ -25116,36 +25026,12 @@
25116 25026 "worker-farm": "^1.5.2"
25117 25027 },
25118 25028 "dependencies": {
25119   - "ajv": {
25120   - "version": "6.12.5",
25121   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
25122   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
25123   - "dev": true,
25124   - "requires": {
25125   - "fast-deep-equal": "^3.1.1",
25126   - "fast-json-stable-stringify": "^2.0.0",
25127   - "json-schema-traverse": "^0.4.1",
25128   - "uri-js": "^4.2.2"
25129   - }
25130   - },
25131 25029 "commander": {
25132 25030 "version": "2.13.0",
25133 25031 "resolved": "https://registry.npm.taobao.org/commander/download/commander-2.13.0.tgz?cache=0&sync_timestamp=1598576136669&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcommander%2Fdownload%2Fcommander-2.13.0.tgz",
25134 25032 "integrity": "sha1-aWS8pnaF33wfFDDFhPB9dZeIW5w=",
25135 25033 "dev": true
25136 25034 },
25137   - "fast-deep-equal": {
25138   - "version": "3.1.3",
25139   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
25140   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
25141   - "dev": true
25142   - },
25143   - "json-schema-traverse": {
25144   - "version": "0.4.1",
25145   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
25146   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
25147   - "dev": true
25148   - },
25149 25035 "schema-utils": {
25150 25036 "version": "0.4.7",
25151 25037 "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz?cache=0&sync_timestamp=1601922251376&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fschema-utils%2Fdownload%2Fschema-utils-0.4.7.tgz",
... ... @@ -25846,36 +25732,12 @@
25846 25732 "yargs": "^8.0.2"
25847 25733 },
25848 25734 "dependencies": {
25849   - "ajv": {
25850   - "version": "6.12.5",
25851   - "resolved": "https://registry.npm.taobao.org/ajv/download/ajv-6.12.5.tgz?cache=0&sync_timestamp=1600886864349&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv%2Fdownload%2Fajv-6.12.5.tgz",
25852   - "integrity": "sha1-GbDouuj0duW6ZmMAOHd1+xoApNo=",
25853   - "dev": true,
25854   - "requires": {
25855   - "fast-deep-equal": "^3.1.1",
25856   - "fast-json-stable-stringify": "^2.0.0",
25857   - "json-schema-traverse": "^0.4.1",
25858   - "uri-js": "^4.2.2"
25859   - }
25860   - },
25861   - "fast-deep-equal": {
25862   - "version": "3.1.3",
25863   - "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz",
25864   - "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU=",
25865   - "dev": true
25866   - },
25867 25735 "has-flag": {
25868 25736 "version": "2.0.0",
25869 25737 "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-2.0.0.tgz",
25870 25738 "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
25871 25739 "dev": true
25872 25740 },
25873   - "json-schema-traverse": {
25874   - "version": "0.4.1",
25875   - "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1599334207614&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
25876   - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=",
25877   - "dev": true
25878   - },
25879 25741 "source-map": {
25880 25742 "version": "0.5.7",
25881 25743 "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz",
... ...
web_src/package.json
... ... @@ -10,7 +10,7 @@
10 10 "build": "node build/build.js"
11 11 },
12 12 "dependencies": {
13   - "@liveqing/liveplayer": "^2.7.0",
  13 + "@liveqing/liveplayer": "^2.7.10",
14 14 "axios": "^0.24.0",
15 15 "core-js": "^2.6.5",
16 16 "echarts": "^4.9.0",
... ...
web_src/src/components/DeviceList.vue
... ... @@ -41,8 +41,8 @@
41 41 <el-table-column label="状态" min-width="120">
42 42 <template slot-scope="scope">
43 43 <div slot="reference" class="name-wrapper">
44   - <el-tag size="medium" v-if="scope.row.online == 1">在线</el-tag>
45   - <el-tag size="medium" type="info" v-if="scope.row.online == 0">离线</el-tag>
  44 + <el-tag size="medium" v-if="scope.row.onLine">在线</el-tag>
  45 + <el-tag size="medium" type="info" v-if="!scope.row.onLine">离线</el-tag>
46 46 </div>
47 47 </template>
48 48 </el-table-column>
... ...
web_src/src/components/ParentPlatformList.vue
... ... @@ -144,7 +144,7 @@ export default {
144 144 },
145 145 chooseChannel: function(platform) {
146 146 console.log("platform.name: " + platform.name)
147   - this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, platform.treeType, this.initData)
  147 + this.$refs.chooseChannelDialog.openDialog(platform.serverGBId,platform.deviceGBId, platform.name, platform.catalogId, this.initData)
148 148 },
149 149 initData: function() {
150 150 this.getPlatformList();
... ...
web_src/src/components/StreamProxyList.vue
... ... @@ -22,8 +22,8 @@
22 22 {{scope.row.url}}
23 23 </el-tag>
24 24 <el-tag size="medium" v-if="scope.row.type != 'default'">
25   - <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.src_url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
26   - {{scope.row.src_url}}
  25 + <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.srcUrl" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i>
  26 + {{scope.row.srcUrl}}
27 27 </el-tag>
28 28 </div>
29 29 </template>
... ... @@ -58,25 +58,25 @@
58 58 <el-table-column label="音频" min-width="120" >
59 59 <template slot-scope="scope">
60 60 <div slot="reference" class="name-wrapper">
61   - <el-tag size="medium" v-if="scope.row.enable_audio">已启用</el-tag>
62   - <el-tag size="medium" type="info" v-if="!scope.row.enable_audio">未启用</el-tag>
  61 + <el-tag size="medium" v-if="scope.row.enableAudio">已启用</el-tag>
  62 + <el-tag size="medium" type="info" v-if="!scope.row.enableAudio">未启用</el-tag>
63 63 </div>
64 64 </template>
65 65 </el-table-column>
66 66 <el-table-column label="录制" min-width="120" >
67 67 <template slot-scope="scope">
68 68 <div slot="reference" class="name-wrapper">
69   - <el-tag size="medium" v-if="scope.row.enable_mp4">已启用</el-tag>
70   - <el-tag size="medium" type="info" v-if="!scope.row.enable_mp4">未启用</el-tag>
  69 + <el-tag size="medium" v-if="scope.row.enableMp4">已启用</el-tag>
  70 + <el-tag size="medium" type="info" v-if="!scope.row.enableMp4">未启用</el-tag>
71 71 </div>
72 72 </template>
73 73 </el-table-column>
74 74 <el-table-column label="无人观看" min-width="160" >
75 75 <template slot-scope="scope">
76 76 <div slot="reference" class="name-wrapper">
77   - <el-tag size="medium" v-if="scope.row.enable_remove_none_reader">移除</el-tag>
78   - <el-tag size="medium" v-if="scope.row.enable_disable_none_reader">停用</el-tag>
79   - <el-tag size="medium" type="info" v-if="!scope.row.enable_remove_none_reader && !scope.row.enable_disable_none_reader">不做处理</el-tag>
  77 + <el-tag size="medium" v-if="scope.row.enableRemoveNoneReader">移除</el-tag>
  78 + <el-tag size="medium" v-if="scope.row.enableDisableNoneReader">停用</el-tag>
  79 + <el-tag size="medium" type="info" v-if="!scope.row.enableRemoveNoneReader && !scope.row.enableDisableNoneReader">不做处理</el-tag>
80 80 </div>
81 81 </template>
82 82 </el-table-column>
... ... @@ -197,7 +197,7 @@
197 197 this.$refs.onvifEdit.openDialog(res.data.data, (url)=>{
198 198 if (url != null) {
199 199 this.$refs.onvifEdit.close();
200   - this.$refs.streamProxyEdit.openDialog({type: "default", url: url, src_url: url}, this.initData())
  200 + this.$refs.streamProxyEdit.openDialog({type: "default", url: url, srcUrl: url}, this.initData())
201 201 }
202 202 })
203 203 }else {
... ... @@ -245,18 +245,25 @@
245 245 },
246 246 deleteStreamProxy: function(row){
247 247 let that = this;
248   - that.$axios({
249   - method:"delete",
250   - url:"/api/proxy/del",
251   - params:{
252   - app: row.app,
253   - stream: row.stream
254   - }
255   - }).then((res)=>{
256   - that.initData()
257   - }).catch(function (error) {
258   - console.log(error);
259   - });
  248 + this.$confirm('确定删除此代理吗?', '提示', {
  249 + confirmButtonText: '确定',
  250 + cancelButtonText: '取消',
  251 + type: 'warning'
  252 + }).then(() => {
  253 + that.$axios({
  254 + method:"delete",
  255 + url:"/api/proxy/del",
  256 + params:{
  257 + app: row.app,
  258 + stream: row.stream
  259 + }
  260 + }).then((res)=>{
  261 + that.initData()
  262 + }).catch(function (error) {
  263 + console.log(error);
  264 + });
  265 + }).catch(() => {
  266 + });
260 267 },
261 268 start: function(row){
262 269 this.stopUpdateList()
... ...
web_src/src/components/channelList.vue
... ... @@ -26,6 +26,12 @@
26 26 <el-option label="在线" value="true"></el-option>
27 27 <el-option label="离线" value="false"></el-option>
28 28 </el-select>
  29 + 清晰度:
  30 + <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="isSubStream" placeholder="请选择"
  31 + default-first-option>
  32 + <el-option label="原画" :value="false"></el-option>
  33 + <el-option label="流畅" :value="true"></el-option>
  34 + </el-select>
29 35 </div>
30 36 <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
31 37 <el-button v-if="showTree" icon="iconfont icon-list" circle size="mini" @click="switchList()"></el-button>
... ... @@ -79,8 +85,8 @@
79 85 <el-table-column label="状态" min-width="120">
80 86 <template slot-scope="scope">
81 87 <div slot="reference" class="name-wrapper">
82   - <el-tag size="medium" v-if="scope.row.status === 1">在线</el-tag>
83   - <el-tag size="medium" type="info" v-if="scope.row.status === 0">离线</el-tag>
  88 + <el-tag size="medium" v-if="scope.row.status === true">在线</el-tag>
  89 + <el-tag size="medium" type="info" v-if="scope.row.status === false">离线</el-tag>
84 90 </div>
85 91 </template>
86 92 </el-table-column>
... ... @@ -146,6 +152,7 @@ export default {
146 152 searchSrt: "",
147 153 channelType: "",
148 154 online: "",
  155 + isSubStream: false,
149 156 winHeight: window.innerHeight - 200,
150 157 currentPage: 1,
151 158 count: 15,
... ... @@ -237,7 +244,10 @@ export default {
237 244 let that = this;
238 245 this.$axios({
239 246 method: 'get',
240   - url: '/api/play/start/' + deviceId + '/' + channelId
  247 + url: '/api/play/start/' + deviceId + '/' + channelId,
  248 + params:{
  249 + isSubStream: this.isSubStream
  250 + }
241 251 }).then(function (res) {
242 252 console.log(res)
243 253 that.isLoging = false;
... ... @@ -277,7 +287,10 @@ export default {
277 287 var that = this;
278 288 this.$axios({
279 289 method: 'get',
280   - url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId
  290 + url: '/api/play/stop/' + this.deviceId + "/" + itemData.channelId,
  291 + params:{
  292 + isSubStream: this.isSubStream
  293 + }
281 294 }).then(function (res) {
282 295 that.initData();
283 296 }).catch(function (error) {
... ...
web_src/src/components/dialog/StreamProxyEdit.vue
... ... @@ -33,13 +33,13 @@
33 33 <el-form-item label="拉流地址" prop="url" v-if="proxyParam.type=='default'">
34 34 <el-input v-model="proxyParam.url" clearable></el-input>
35 35 </el-form-item>
36   - <el-form-item label="拉流地址" prop="src_url" v-if="proxyParam.type=='ffmpeg'">
37   - <el-input v-model="proxyParam.src_url" clearable></el-input>
  36 + <el-form-item label="拉流地址" prop="srcUrl" v-if="proxyParam.type=='ffmpeg'">
  37 + <el-input v-model="proxyParam.srcUrl" clearable></el-input>
38 38 </el-form-item>
39   - <el-form-item label="超时时间:毫秒" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'">
40   - <el-input v-model="proxyParam.timeout_ms" clearable></el-input>
  39 + <el-form-item label="超时时间:毫秒" prop="timeoutMs" v-if="proxyParam.type=='ffmpeg'">
  40 + <el-input v-model="proxyParam.timeoutMs" clearable></el-input>
41 41 </el-form-item>
42   - <el-form-item label="节点选择" prop="rtp_type">
  42 + <el-form-item label="节点选择" prop="rtpType">
43 43 <el-select
44 44 v-model="proxyParam.mediaServerId"
45 45 @change="mediaServerIdChange"
... ... @@ -54,10 +54,9 @@
54 54 </el-option>
55 55 </el-select>
56 56 </el-form-item>
57   - <el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'">
58   -<!-- <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input>-->
  57 + <el-form-item label="FFmpeg命令模板" prop="ffmpegCmdKey" v-if="proxyParam.type=='ffmpeg'">
59 58 <el-select
60   - v-model="proxyParam.ffmpeg_cmd_key"
  59 + v-model="proxyParam.ffmpegCmdKey"
61 60 style="width: 100%"
62 61 placeholder="请选择FFmpeg命令模板"
63 62 >
... ... @@ -72,9 +71,9 @@
72 71 <el-form-item label="国标编码" prop="gbId">
73 72 <el-input v-model="proxyParam.gbId" placeholder="设置国标编码可推送到国标" clearable></el-input>
74 73 </el-form-item>
75   - <el-form-item label="拉流方式" prop="rtp_type" v-if="proxyParam.type=='default'">
  74 + <el-form-item label="拉流方式" prop="rtpType" v-if="proxyParam.type=='default'">
76 75 <el-select
77   - v-model="proxyParam.rtp_type"
  76 + v-model="proxyParam.rtpType"
78 77 style="width: 100%"
79 78 placeholder="请选择拉流方式"
80 79 >
... ... @@ -83,10 +82,10 @@
83 82 <el-option label="组播" value="2"></el-option>
84 83 </el-select>
85 84 </el-form-item>
86   - <el-form-item label="无人观看" prop="rtp_type" >
  85 + <el-form-item label="无人观看" prop="rtpType" >
87 86 <el-select
88 87 @change="noneReaderHandler"
89   - v-model="proxyParam.none_reader"
  88 + v-model="proxyParam.noneReader"
90 89 style="width: 100%"
91 90 placeholder="请选择无人观看的处理方式"
92 91 >
... ... @@ -98,8 +97,8 @@
98 97 <el-form-item label="其他选项">
99 98 <div style="float: left;">
100 99 <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox>
101   - <el-checkbox label="开启音频" v-model="proxyParam.enable_audio" ></el-checkbox>
102   - <el-checkbox label="录制" v-model="proxyParam.enable_mp4" ></el-checkbox>
  100 + <el-checkbox label="开启音频" v-model="proxyParam.enableAudio" ></el-checkbox>
  101 + <el-checkbox label="录制" v-model="proxyParam.enableMp4" ></el-checkbox>
103 102 </div>
104 103  
105 104 </el-form-item>
... ... @@ -155,17 +154,17 @@ export default {
155 154 app: null,
156 155 stream: null,
157 156 url: "",
158   - src_url: null,
159   - timeout_ms: null,
160   - ffmpeg_cmd_key: null,
  157 + srcUrl: null,
  158 + timeoutMs: null,
  159 + ffmpegCmdKey: null,
161 160 gbId: null,
162   - rtp_type: null,
  161 + rtpType: null,
163 162 enable: true,
164   - enable_audio: true,
165   - enable_mp4: false,
166   - none_reader: null,
167   - enable_remove_none_reader: false,
168   - enable_disable_none_reader: false,
  163 + enableAudio: true,
  164 + enableMp4: false,
  165 + noneReader: null,
  166 + enableRemoveNoneReader: false,
  167 + enableDisableNoneReader: false,
169 168 platformGbId: null,
170 169 mediaServerId: null,
171 170 },
... ... @@ -177,9 +176,9 @@ export default {
177 176 app: [{ required: true, message: "请输入应用名", trigger: "blur" }],
178 177 stream: [{ required: true, message: "请输入流ID", trigger: "blur" }],
179 178 url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
180   - src_url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
181   - timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
182   - ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
  179 + srcUrl: [{ required: true, message: "请输入要代理的流", trigger: "blur" }],
  180 + timeoutMs: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }],
  181 + ffmpegCmdKey: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }],
183 182 },
184 183 };
185 184 },
... ... @@ -189,7 +188,7 @@ export default {
189 188 this.listChangeCallback = callback;
190 189 if (proxyParam != null) {
191 190 this.proxyParam = proxyParam;
192   - this.proxyParam.none_reader = null;
  191 + this.proxyParam.noneReader = null;
193 192 }
194 193  
195 194 let that = this;
... ... @@ -218,7 +217,7 @@ export default {
218 217 }
219 218 }).then(function (res) {
220 219 that.ffmpegCmdList = res.data.data;
221   - that.proxyParam.ffmpeg_cmd_key = Object.keys(res.data.data)[0];
  220 + that.proxyParam.ffmpegCmdKey = Object.keys(res.data.data)[0];
222 221 }).catch(function (error) {
223 222 console.log(error);
224 223 });
... ... @@ -275,15 +274,15 @@ export default {
275 274 }
276 275 },
277 276 noneReaderHandler: function() {
278   - if (this.proxyParam.none_reader === null || this.proxyParam.none_reader === "0") {
279   - this.proxyParam.enable_disable_none_reader = false;
280   - this.proxyParam.enable_remove_none_reader = false;
281   - }else if (this.proxyParam.none_reader === "1"){
282   - this.proxyParam.enable_disable_none_reader = true;
283   - this.proxyParam.enable_remove_none_reader = false;
284   - }else if (this.proxyParam.none_reader ==="2"){
285   - this.proxyParam.enable_disable_none_reader = false;
286   - this.proxyParam.enable_remove_none_reader = true;
  277 + if (this.proxyParam.noneReader === null || this.proxyParam.noneReader === "0") {
  278 + this.proxyParam.enableDisableNoneReader = false;
  279 + this.proxyParam.enableRemoveNoneReader = false;
  280 + }else if (this.proxyParam.noneReader === "1"){
  281 + this.proxyParam.enableDisableNoneReader = true;
  282 + this.proxyParam.enableRemoveNoneReader = false;
  283 + }else if (this.proxyParam.noneReader ==="2"){
  284 + this.proxyParam.enableDisableNoneReader = false;
  285 + this.proxyParam.enableRemoveNoneReader = true;
287 286 }
288 287 },
289 288 },
... ...
web_src/src/components/dialog/catalogEdit.vue
... ... @@ -46,12 +46,11 @@
46 46 export default {
47 47 name: "catalogEdit",
48 48 computed: {},
49   - props: ['platformId'],
  49 + props: ['platformId', 'platformDeviceId'],
50 50 created() {},
51 51 data() {
52 52 let checkId = (rule, value, callback) => {
53 53 console.log("checkId")
54   - console.log(this.treeType)
55 54 console.log(rule)
56 55 console.log(value)
57 56 console.log(value.length)
... ... @@ -59,21 +58,34 @@ export default {
59 58 if (!value) {
60 59 return callback(new Error('编号不能为空'));
61 60 }
62   - if (this.treeType === "BusinessGroup" && value.length !== 20) {
63   - return callback(new Error('编号必须由20位数字组成'));
64   - }
65   - if (this.treeType === "CivilCode" && value.length <= 8 && value.length%2 !== 0) {
66   - return callback(new Error('行政区划必须是八位以下的偶数个数字组成'));
67   - }
68   - if (this.treeType === "BusinessGroup") {
  61 + if (value.trim().length <= 8) {
  62 + if (value.trim().length%2 !== 0) {
  63 + return callback(new Error('行政区划编号必须为2/4/6/8位'));
  64 + }
  65 + if (this.form.parentId !== this.platformDeviceId && this.form.parentId.length >= value.trim().length) {
  66 + return callback(new Error('行政区划编号长度应该每次两位递增'));
  67 + }
  68 + }else {
  69 + if (value.trim().length !== 20) {
  70 + return callback(new Error('编号必须为2/4/6/8位的行政区划或20位的虚拟组织/业务分组'));
  71 + }
69 72 let catalogType = value.substring(10, 13);
70 73 console.log(catalogType)
71   - // 216 为虚拟组织 215 为业务分组;目录第一级必须为业务分组, 业务分组下为虚拟组织,虚拟组织下可以有其他虚拟组织
72   - if (this.level === 1 && catalogType !== "215") {
73   - return callback(new Error('业务分组模式下第一层目录的编号11到13位必须为215'));
  74 + if (catalogType !== "215" && catalogType !== "216") {
  75 + return callback(new Error('编号错误,业务分组11-13位为215,虚拟组织11-13位为216'));
74 76 }
75   - if (this.level > 1 && catalogType !== "216") {
76   - return callback(new Error('业务分组模式下第一层以下目录的编号11到13位必须为216'));
  77 + if (catalogType === "216") {
  78 +
  79 + if (this.form.parentId !== this.platformDeviceId){
  80 + if (this.form.parentId.length <= 8) {
  81 + return callback(new Error('编号错误,建立虚拟组织前必须先建立业务分组(11-13位为215)'));
  82 + }
  83 + }
  84 + }
  85 + if (catalogType === "215") {
  86 + if (this.form.parentId.length === "215") {
  87 + return callback(new Error('编号错误,业务分组下只能建立虚拟组织(11-13位为216)'));
  88 + }
77 89 }
78 90 }
79 91 callback();
... ... @@ -83,7 +95,6 @@ export default {
83 95 showDialog: false,
84 96 isLoging: false,
85 97 isEdit: false,
86   - treeType: null,
87 98 level: 0,
88 99 form: {
89 100 id: null,
... ... @@ -98,7 +109,7 @@ export default {
98 109 };
99 110 },
100 111 methods: {
101   - openDialog: function (isEdit, id, name, parentId, treeType, level, callback) {
  112 + openDialog: function (isEdit, id, name, parentId, level, callback) {
102 113 console.log("parentId: " + parentId)
103 114 console.log(this.form)
104 115 this.isEdit = isEdit;
... ... @@ -108,7 +119,6 @@ export default {
108 119 this.form.parentId = parentId;
109 120 this.showDialog = true;
110 121 this.submitCallback = callback;
111   - this.treeType = treeType;
112 122 this.level = level;
113 123 },
114 124 onSubmit: function () {
... ...
web_src/src/components/dialog/chooseChannel.vue
... ... @@ -8,7 +8,7 @@
8 8 <el-tab-pane label="目录结构" name="catalog">
9 9 <el-container>
10 10 <el-main v-bind:style="{backgroundColor: '#FFF', maxHeight: winHeight + 'px'}">
11   - <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" :treeType=treeType ></chooseChannelForCatalog>
  11 + <chooseChannelForCatalog ref="chooseChannelForCatalog" :platformId=platformId :platformDeviceId=platformDeviceId :platformName=platformName :defaultCatalogId=defaultCatalogId :catalogIdChange="catalogIdChange" ></chooseChannelForCatalog>
12 12 </el-main>
13 13 </el-container>
14 14 </el-tab-pane>
... ... @@ -67,14 +67,13 @@ export default {
67 67 platformName: "",
68 68 defaultCatalogId: "",
69 69 showDialog: false,
70   - treeType: null,
71 70 chooseData: {},
72 71 winHeight: window.innerHeight - 250,
73 72  
74 73 };
75 74 },
76 75 methods: {
77   - openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, treeType, closeCallback) {
  76 + openDialog(platformId, platformDeviceId, platformName, defaultCatalogId, closeCallback) {
78 77 console.log("defaultCatalogId: " + defaultCatalogId)
79 78 this.platformId = platformId
80 79 this.platformDeviceId = platformDeviceId
... ... @@ -82,7 +81,6 @@ export default {
82 81 this.defaultCatalogId = defaultCatalogId
83 82 this.showDialog = true
84 83 this.closeCallback = closeCallback
85   - this.treeType = treeType
86 84 },
87 85 tabClick (tab, event){
88 86  
... ...
web_src/src/components/dialog/chooseChannelForCatalog.vue
... ... @@ -28,7 +28,7 @@
28 28 </span>
29 29 </el-tree>
30 30 </div>
31   - <catalogEdit ref="catalogEdit" :platformId="platformId"></catalogEdit>
  31 + <catalogEdit ref="catalogEdit" :platformId="platformId" :platformDeviceId="platformDeviceId"></catalogEdit>
32 32 </div>
33 33 </template>
34 34  
... ... @@ -38,7 +38,7 @@
38 38 import catalogEdit from './catalogEdit.vue'
39 39 export default {
40 40 name: 'chooseChannelForCatalog',
41   - props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange', 'treeType'],
  41 + props: ['platformId', 'platformDeviceId', 'platformName', 'defaultCatalogId', 'catalogIdChange'],
42 42 created() {
43 43 this.chooseId = this.defaultCatalogId;
44 44 this.defaultCatalogIdSign = this.defaultCatalogId;
... ... @@ -101,9 +101,10 @@ export default {
101 101 },
102 102 addCatalog: function (parentId, node){
103 103 let that = this;
104   - console.log(this.treeType)
  104 + console.log(this.platformId)
  105 + console.log(parentId)
105 106 // 打开添加弹窗
106   - that.$refs.catalogEdit.openDialog(false, null, null, parentId, this.treeType, node.level, ()=>{
  107 + that.$refs.catalogEdit.openDialog(false, null, null, parentId, node.level, ()=>{
107 108 node.loaded = false
108 109 node.expand();
109 110 });
... ...
web_src/src/components/dialog/deviceEdit.vue
... ... @@ -52,12 +52,6 @@
52 52 <el-option key="GCJ02" label="GCJ02" value="GCJ02"></el-option>
53 53 </el-select>
54 54 </el-form-item>
55   - <el-form-item label="目录结构" prop="treeType" >
56   - <el-select v-model="form.treeType" style="float: left; width: 100%" >
57   - <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option>
58   - <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option>
59   - </el-select>
60   - </el-form-item>
61 55 <el-form-item v-if="this.isEdit" label="目录订阅" title="0为取消订阅" prop="subscribeCycleForCatalog" >
62 56 <el-input v-model="form.subscribeCycleForCatalog" clearable ></el-input>
63 57 </el-form-item>
... ... @@ -67,6 +61,12 @@
67 61 <el-form-item v-if="form.subscribeCycleForMobilePosition > 0" label="移动位置报送间隔" prop="subscribeCycleForCatalog" >
68 62 <el-input v-model="form.mobilePositionSubmissionInterval" clearable ></el-input>
69 63 </el-form-item>
  64 + <el-form-item label="主子码流开关" prop="switchPrimarySubStream" >
  65 + <el-select v-model="form.switchPrimarySubStream" style="float: left; width: 100%" >
  66 + <el-option key="true" label="开启" :value="true"></el-option>
  67 + <el-option key="false" label="关闭" :value="false"></el-option>
  68 + </el-select>
  69 + </el-form-item>
70 70 <el-form-item label="其他选项">
71 71 <el-checkbox label="SSRC校验" v-model="form.ssrcCheck" style="float: left"></el-checkbox>
72 72 <el-checkbox label="作为消息通道" v-model="form.asMessageChannel" style="float: left"></el-checkbox>
... ...
web_src/src/components/dialog/devicePlayer.vue
... ... @@ -16,7 +16,6 @@
16 16 :hasAudio="hasAudio" fluent autoplay live></rtc-player>
17 17 </el-tab-pane>
18 18 <el-tab-pane label="h265web">h265web敬请期待</el-tab-pane>
19   - <el-tab-pane label="wsPlayer">wsPlayer 敬请期待</el-tab-pane>
20 19 </el-tabs>
21 20 <jessibucaPlayer v-if="Object.keys(this.player).length == 1 && this.player.jessibuca" ref="jessibuca"
22 21 :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError"
... ... @@ -540,25 +539,31 @@ export default {
540 539 // if (callback )callback();
541 540 },
542 541  
543   - playFromStreamInfo: function (realHasAudio, streamInfo) {
544   - this.showVideoDialog = true;
545   - this.hasaudio = realHasAudio && this.hasaudio;
546   - this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
547   - },
548   - close: function () {
549   - console.log('关闭视频');
550   - if (!!this.$refs[this.activePlayer]) {
551   - this.$refs[this.activePlayer].pause();
552   - }
553   - this.videoUrl = '';
554   - this.coverPlaying = false;
555   - this.showVideoDialog = false;
556   - if (this.convertKey != '') {
557   - this.convertStop();
558   - }
559   - this.convertKey = ''
560   - this.stopBroadcast()
561   - },
  542 + playFromStreamInfo: function (realHasAudio, streamInfo) {
  543 + this.showVideoDialog = true;
  544 + this.hasaudio = realHasAudio && this.hasaudio;
  545 + if (this.$refs[this.activePlayer]) {
  546 + this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
  547 + }else {
  548 + this.$nextTick(() => {
  549 + this.$refs[this.activePlayer].play(this.getUrlByStreamInfo(streamInfo))
  550 + });
  551 + }
  552 + },
  553 + close: function () {
  554 + console.log('关闭视频');
  555 + if (!!this.$refs[this.activePlayer]){
  556 + this.$refs[this.activePlayer].pause();
  557 + }
  558 + this.videoUrl = '';
  559 + this.coverPlaying = false;
  560 + this.showVideoDialog = false;
  561 + if (this.convertKey != '') {
  562 + this.convertStop();
  563 + }
  564 + this.convertKey = ''
  565 + this.stopBroadcast()
  566 + },
562 567  
563 568 copySharedInfo: function (data) {
564 569 console.log('复制内容:' + data);
... ...
web_src/src/components/dialog/platformEdit.vue
... ... @@ -78,12 +78,6 @@
78 78 <el-option label="8" value="8"></el-option>
79 79 </el-select>
80 80 </el-form-item>
81   - <el-form-item label="目录结构" prop="treeType" >
82   - <el-select v-model="platform.treeType" style="width: 100%" @change="treeTypeChange">
83   - <el-option key="WGS84" label="行政区划" value="CivilCode"></el-option>
84   - <el-option key="GCJ02" label="业务分组" value="BusinessGroup"></el-option>
85   - </el-select>
86   - </el-form-item>
87 81 <el-form-item label="字符集" prop="characterSet">
88 82 <el-select
89 83 v-model="platform.characterSet"
... ... @@ -164,7 +158,6 @@ export default {
164 158 startOfflinePush: false,
165 159 catalogGroup: 1,
166 160 administrativeDivision: null,
167   - treeType: "BusinessGroup",
168 161 },
169 162 rules: {
170 163 name: [{ required: true, message: "请输入平台名称", trigger: "blur" }],
... ... @@ -203,7 +196,6 @@ export default {
203 196 that.platform.devicePort = res.data.data.devicePort;
204 197 that.platform.username = res.data.data.username;
205 198 that.platform.password = res.data.data.password;
206   - that.platform.treeType = "BusinessGroup";
207 199 that.platform.administrativeDivision = res.data.data.username.substr(0, 6);
208 200 }
209 201  
... ... @@ -234,7 +226,6 @@ export default {
234 226 this.platform.startOfflinePush = platform.startOfflinePush;
235 227 this.platform.catalogGroup = platform.catalogGroup;
236 228 this.platform.administrativeDivision = platform.administrativeDivision;
237   - this.platform.treeType = platform.treeType;
238 229 this.onSubmit_text = "保存";
239 230 this.saveUrl = "/api/platform/save";
240 231 }
... ... @@ -252,7 +243,6 @@ export default {
252 243 if (this.platform.administrativeDivision == null) {
253 244 this.platform.administrativeDivision = this.platform.deviceGBId.substr(0, 6);
254 245 }
255   -
256 246 },
257 247 onSubmit: function () {
258 248 this.saveForm()
... ... @@ -309,7 +299,6 @@ export default {
309 299 keepTimeout: 60,
310 300 transport: "UDP",
311 301 characterSet: "GB2312",
312   - treeType: "BusinessGroup",
313 302 startOfflinePush: false,
314 303 catalogGroup: 1,
315 304 }
... ... @@ -344,13 +333,6 @@ export default {
344 333 });
345 334 }
346 335 },
347   - treeTypeChange: function (){
348   - this.$message({
349   - showClose: true,
350   - message: "修改目录结构会导致关联目录与通道数据被清空,保存后生效",
351   - type: "warning",
352   - });
353   - }
354 336 },
355 337 };
356 338 </script>
... ...
web_src/src/components/map.vue
... ... @@ -22,10 +22,10 @@
22 22 <el-descriptions-item label="行政区域" >{{channel.civilCode}}</el-descriptions-item>
23 23 <el-descriptions-item label="设备归属" >{{channel.owner}}</el-descriptions-item>
24 24 <el-descriptions-item label="安装地址" >{{channel.address == null?'未知': channel.address}}</el-descriptions-item>
25   - <el-descriptions-item label="云台类型" >{{channel.ptztypeText}}</el-descriptions-item>
26   - <el-descriptions-item label="状态">
27   - <el-tag size="small" v-if="channel.status === 1">在线</el-tag>
28   - <el-tag size="small" type="info" v-if="channel.status === 0">离线</el-tag>
  25 + <el-descriptions-item label="云台类型" >{{channel.PTZTypeText}}</el-descriptions-item>
  26 + <el-descriptions-item label="通道状态">
  27 + <el-tag size="small" v-if="channel.status === true">在线</el-tag>
  28 + <el-tag size="small" type="info" v-if="channel.status === false">离线</el-tag>
29 29 </el-descriptions-item>
30 30 </el-descriptions>
31 31 <div style="padding-top: 10px">
... ...