loraport
This commit is contained in:
parent
a5fed18d8b
commit
0545149e45
|
@ -2,7 +2,7 @@
|
||||||
"gateway_info": {
|
"gateway_info": {
|
||||||
"id": "F23FACD2-7D85-4FCC-88E3-C5B78931A26D",
|
"id": "F23FACD2-7D85-4FCC-88E3-C5B78931A26D",
|
||||||
"version": "yunhorn_gw_c_v1",
|
"version": "yunhorn_gw_c_v1",
|
||||||
"localtion": [113.960347, 22.54143],
|
"location": [113.960347, 22.54143],
|
||||||
"单位": "深圳市云兴科技",
|
"单位": "深圳市云兴科技",
|
||||||
"config": [{
|
"config": [{
|
||||||
"id": "EC13C2D9-6A93-4894-BB5B-89BDAA786D8A",
|
"id": "EC13C2D9-6A93-4894-BB5B-89BDAA786D8A",
|
||||||
|
@ -65,45 +65,28 @@
|
||||||
["男便池", 2],
|
["男便池", 2],
|
||||||
["男便池", 3]
|
["男便池", 3]
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4E5D52DD-EB81-43C0-A2B6-04E432412EBA",
|
||||||
|
"version": "yunhorn_kgl_l_v1",
|
||||||
|
"data": [
|
||||||
|
["纸巾卷", 1]
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devices_list": [
|
"devices_list": [
|
||||||
["EC13C2D9-6A93-4894-BB5B-89BDAA786D8A", "port3", "yunhorn_kgl_c8_v1", "1"],
|
["4E5D52DD-EB81-43C0-A2B6-04E432412EBA", "loraport", "yunhorn_kgl_l_v1", "1"]
|
||||||
["15394892-E8B0-4FF2-BC35-1BF380BD1B68", "port2", "yunhorn_xsy_c_v1", "1"],
|
|
||||||
["52A79B3D-D9D9-48AF-AEB4-7D456BA22B31", "port1", "yunhorn_db_c_v1", "1"],
|
|
||||||
["607E11C4-8986-4F8E-807E-FFA655A6F677", "port1", "yunhorn_sb_c_v1", "1"],
|
|
||||||
["066BB944-AFA2-4E5D-86FA-61D9080A97BB", "port2", "yunhorn_kq_c_v1", "1"],
|
|
||||||
["22E175B2-8DD5-4740-B428-0297F409AA47", "port2", "yunhorn_lhq_c_v1", "1"],
|
|
||||||
["20F44B9C-E4A1-478E-B28F-0B7B14A2AF64", "port2", "yunhorn_aq_c_v1", "1"]
|
|
||||||
],
|
],
|
||||||
"serialports_list": {
|
"serialports_list": {
|
||||||
"port1": {
|
"loraport": {
|
||||||
"com": "/dev/ttyUSB2",
|
"com": "/dev/cu.wchusbserial141420",
|
||||||
"bauds": 2400,
|
"bauds": 115200,
|
||||||
"size": 8,
|
"size": 8,
|
||||||
"parity": "E",
|
"parity": "E",
|
||||||
"stopbits": 1,
|
"stopbits": 1,
|
||||||
"readtimeout": 1,
|
"readtimeout": 100,
|
||||||
"note": "水表电表"
|
"note": "lorawan"
|
||||||
},
|
|
||||||
"port2": {
|
|
||||||
"com": "/dev/ttyUSB1",
|
|
||||||
"bauds": 9600,
|
|
||||||
"size": 8,
|
|
||||||
"parity": "N",
|
|
||||||
"stopbits": 1,
|
|
||||||
"readtimeout": 1,
|
|
||||||
"note": "空气质量"
|
|
||||||
},
|
|
||||||
"port3": {
|
|
||||||
"com": "/dev/ttyUSB0",
|
|
||||||
"bauds": 9600,
|
|
||||||
"size": 8,
|
|
||||||
"parity": "N",
|
|
||||||
"stopbits": 1,
|
|
||||||
"readtimeout": 1,
|
|
||||||
"note": "开关量监测"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rs485devices": {
|
"rs485devices": {
|
||||||
|
@ -171,8 +154,17 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"loradevices_list": {
|
||||||
|
"4E5D52DD-EB81-43C0-A2B6-04E432412EBA": {
|
||||||
|
"version": "yunhorn_zjj_l_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[85, 2, 242, 170]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"iconurl": "http://192.168.3.188/icons/",
|
"iconurl": "http://192.168.3.188/icons/",
|
||||||
"websocketurl": ["192.168.3.216:8080", "/echo"],
|
"websocketurl": ["192.168.3.216:8080", "/echo"],
|
||||||
"post_to_server": "https://smartoilets.cn/socketServer/statis/push",
|
"post_to_server": "https://smartoilets.cn/socketServer/statis/push",
|
||||||
"debug": false
|
"debug": true
|
||||||
}
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
{
|
||||||
|
"gateway_info": {
|
||||||
|
"id": "F23FACD2-7D85-4FCC-88E3-C5B78931A26D",
|
||||||
|
"version": "yunhorn_gw_c_v1",
|
||||||
|
"location": [113.960347, 22.54143],
|
||||||
|
"单位": "深圳市云兴科技",
|
||||||
|
"config": [{
|
||||||
|
"id": "EC13C2D9-6A93-4894-BB5B-89BDAA786D8A",
|
||||||
|
"version": "yunhorn_kgl_c8_v1",
|
||||||
|
"data": [
|
||||||
|
["男厕位", 1],
|
||||||
|
["男厕位", 2],
|
||||||
|
["男厕位", 3],
|
||||||
|
["男厕位", 4],
|
||||||
|
["男厕位", 5],
|
||||||
|
["男厕位", 6],
|
||||||
|
["男厕位", 7],
|
||||||
|
["男厕位", 8]
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"id": "82BF7B5E-EC0D-4DB6-807F-B097C3C84073",
|
||||||
|
"version": "yunhorn_kgl_c8_v1",
|
||||||
|
"data": [
|
||||||
|
["母婴", 1],
|
||||||
|
["残卫", 1],
|
||||||
|
["残卫", 2],
|
||||||
|
["男便池", 4],
|
||||||
|
["男便池", 5],
|
||||||
|
["男便池", 6],
|
||||||
|
["男便池", 7],
|
||||||
|
["男便池", 8]
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"id": "F5B7FDCC-79A8-499E-A925-F2FF357BE30D",
|
||||||
|
"version": "yunhorn_kgl_c8_v1",
|
||||||
|
"data": [
|
||||||
|
["男厕位", 9],
|
||||||
|
["男厕位", 10],
|
||||||
|
["女厕位", 14],
|
||||||
|
["女厕位", 15],
|
||||||
|
["女厕位", 16],
|
||||||
|
["女厕位", 17],
|
||||||
|
["女厕位", 18],
|
||||||
|
[null, null]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "00DD66A6-378E-450D-98AA-44AC02741980",
|
||||||
|
"version": "yunhorn_kgl_c16_v1",
|
||||||
|
"data": [
|
||||||
|
["女厕位", 1],
|
||||||
|
["女厕位", 2],
|
||||||
|
["女厕位", 3],
|
||||||
|
["女厕位", 4],
|
||||||
|
["女厕位", 5],
|
||||||
|
["女厕位", 6],
|
||||||
|
["女厕位", 7],
|
||||||
|
["女厕位", 8],
|
||||||
|
["女厕位", 9],
|
||||||
|
["女厕位", 10],
|
||||||
|
["女厕位", 11],
|
||||||
|
["女厕位", 12],
|
||||||
|
["女厕位", 13],
|
||||||
|
["男便池", 1],
|
||||||
|
["男便池", 2],
|
||||||
|
["男便池", 3]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devices_list": [
|
||||||
|
["EC13C2D9-6A93-4894-BB5B-89BDAA786D8A", "port3", "yunhorn_kgl_c8_v1", "1"],
|
||||||
|
["15394892-E8B0-4FF2-BC35-1BF380BD1B68", "port2", "yunhorn_xsy_c_v1", "1"],
|
||||||
|
["52A79B3D-D9D9-48AF-AEB4-7D456BA22B31", "port1", "yunhorn_db_c_v1", "1"],
|
||||||
|
["607E11C4-8986-4F8E-807E-FFA655A6F677", "port1", "yunhorn_sb_c_v1", "1"],
|
||||||
|
["066BB944-AFA2-4E5D-86FA-61D9080A97BB", "port2", "yunhorn_kq_c_v1", "1"],
|
||||||
|
["22E175B2-8DD5-4740-B428-0297F409AA47", "port2", "yunhorn_lhq_c_v1", "1"],
|
||||||
|
["20F44B9C-E4A1-478E-B28F-0B7B14A2AF64", "port2", "yunhorn_aq_c_v1", "1"]
|
||||||
|
],
|
||||||
|
"serialports_list": {
|
||||||
|
"port1": {
|
||||||
|
"com": "/dev/ttyUSB2",
|
||||||
|
"bauds": 2400,
|
||||||
|
"size": 8,
|
||||||
|
"parity": "E",
|
||||||
|
"stopbits": 1,
|
||||||
|
"readtimeout": 1,
|
||||||
|
"note": "水表电表"
|
||||||
|
},
|
||||||
|
"port2": {
|
||||||
|
"com": "/dev/ttyUSB1",
|
||||||
|
"bauds": 9600,
|
||||||
|
"size": 8,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 1,
|
||||||
|
"readtimeout": 1,
|
||||||
|
"note": "空气质量"
|
||||||
|
},
|
||||||
|
"port3": {
|
||||||
|
"com": "/dev/ttyUSB0",
|
||||||
|
"bauds": 9600,
|
||||||
|
"size": 8,
|
||||||
|
"parity": "N",
|
||||||
|
"stopbits": 1,
|
||||||
|
"readtimeout": 1,
|
||||||
|
"note": "开关量监测"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rs485devices": {
|
||||||
|
"15394892-E8B0-4FF2-BC35-1BF380BD1B68": {
|
||||||
|
"version": "yunhorn_xsy_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[8, 3, 0, 1, 0, 2, 149, 82]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"EC13C2D9-6A93-4894-BB5B-89BDAA786D8A": {
|
||||||
|
"version": "yunhorn_kgl_c8_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[1, 2, 0, 0, 0, 1, 185, 202],
|
||||||
|
[1, 2, 0, 1, 0, 1, 232, 10],
|
||||||
|
[1, 2, 0, 2, 0, 1, 24, 10],
|
||||||
|
[1, 2, 0, 3, 0, 1, 73, 202],
|
||||||
|
[1, 2, 0, 4, 0, 1, 248, 11],
|
||||||
|
[1, 2, 0, 5, 0, 1, 169, 203],
|
||||||
|
[1, 2, 0, 6, 0, 1, 89, 203],
|
||||||
|
[1, 2, 0, 7, 0, 1, 8, 11]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"00DD66A6-378E-450D-98AA-44AC02741980": {
|
||||||
|
"version": "yunhorn_kgl_c16_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[3, 2, 0, 0, 0, 16, 120, 36]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"52A79B3D-D9D9-48AF-AEB4-7D456BA22B31": {
|
||||||
|
"version": "yunhorn_db_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[104, 65, 4, 0, 120, 16, 68, 104, 17, 4, 51, 51, 52, 51, 195, 22]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"607E11C4-8986-4F8E-807E-FFA655A6F677": {
|
||||||
|
"version": "yunhorn_sb_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[104, 16, 103, 19, 146, 128, 1, 0, 0, 1, 3, 31, 144, 2, 186, 22]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"066BB944-AFA2-4E5D-86FA-61D9080A97BB": {
|
||||||
|
"version": "yunhorn_kq_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[2, 3, 0, 0, 0, 7, 4, 59]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"22E175B2-8DD5-4740-B428-0297F409AA47": {
|
||||||
|
"version": "yunhorn_lhq_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[4, 3, 0, 6, 0, 1, 100, 94]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"20F44B9C-E4A1-478E-B28F-0B7B14A2AF64": {
|
||||||
|
"version": "yunhorn_aq_c_v1",
|
||||||
|
"num": "1",
|
||||||
|
"command": [
|
||||||
|
[3, 3, 0, 0, 0, 1, 133, 232]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iconurl": "http://192.168.3.188/icons/",
|
||||||
|
"websocketurl": ["192.168.3.216:8080", "/echo"],
|
||||||
|
"post_to_server": "https://smartoilets.cn/socketServer/statis/push",
|
||||||
|
"debug": false
|
||||||
|
}
|
BIN
db/gateway.db
BIN
db/gateway.db
Binary file not shown.
|
@ -82,7 +82,7 @@ func init() {
|
||||||
dbdata_init()
|
dbdata_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
var good, bad float32
|
var good, bad float64
|
||||||
var traffic_data Traffic
|
var traffic_data Traffic
|
||||||
var satisfaction_data Satisfaction
|
var satisfaction_data Satisfaction
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -65,6 +66,9 @@ var rl_data EventNotificationAlert
|
||||||
|
|
||||||
func get_renliu_api(c *gin.Context) {
|
func get_renliu_api(c *gin.Context) {
|
||||||
err := c.Bind(&rl_data)
|
err := c.Bind(&rl_data)
|
||||||
|
if conf.DEBUG {
|
||||||
|
log.Println(rl_data)
|
||||||
|
}
|
||||||
check(err)
|
check(err)
|
||||||
send_data(1004)
|
send_data(1004)
|
||||||
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": rl_data})
|
c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": rl_data})
|
||||||
|
|
|
@ -31,7 +31,9 @@ func serial_run() {
|
||||||
Name: conf.SERIALPORTS_LIST[i].COM,
|
Name: conf.SERIALPORTS_LIST[i].COM,
|
||||||
Baud: conf.SERIALPORTS_LIST[i].BAUDS,
|
Baud: conf.SERIALPORTS_LIST[i].BAUDS,
|
||||||
Parity: PARITY,
|
Parity: PARITY,
|
||||||
ReadTimeout: time.Second * time.Duration(conf.SERIALPORTS_LIST[i].READTIMEOUT)})
|
ReadTimeout: time.Millisecond * time.Duration(conf.SERIALPORTS_LIST[i].READTIMEOUT),
|
||||||
|
// ReadTimeout: time.Second * time.Duration(conf.SERIALPORTS_LIST[i].READTIMEOUT),
|
||||||
|
})
|
||||||
check(err)
|
check(err)
|
||||||
defer SERIAL_PORT[i].Close()
|
defer SERIAL_PORT[i].Close()
|
||||||
}
|
}
|
||||||
|
@ -47,6 +49,11 @@ func serial_run() {
|
||||||
}
|
}
|
||||||
go run_port_device(k, the_same_port_devices)
|
go run_port_device(k, the_same_port_devices)
|
||||||
}
|
}
|
||||||
|
for i, k := range SERIAL_PORT {
|
||||||
|
if conf.SERIALPORTS_LIST[i].NOTE == "lorawan" {
|
||||||
|
yunhorn_lorawan_l_v1(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +75,10 @@ func run_port_device(port *serial.Port, the_same_port_devices [][]string) {
|
||||||
yunhorn_kgl_c8_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
yunhorn_kgl_c8_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||||
case "yunhorn_kgl_c16_v1":
|
case "yunhorn_kgl_c16_v1":
|
||||||
yunhorn_kgl_c16_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
yunhorn_kgl_c16_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||||
case "yunhorn_xsy_c_v1":
|
case "yunhorn_xsy_l_v1":
|
||||||
yunhorn_xsy_c_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
yunhorn_xsy_l_v1(port, i[0], conf.RS485DEVICES[i[0]].COMMAND, conf.RS485DEVICES[i[0]].NUM)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
time.Sleep(time.Duration(1) * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
worker.go
49
worker.go
|
@ -21,6 +21,47 @@ type Device struct {
|
||||||
DATA map[string]interface{} `json:"data"`
|
DATA map[string]interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func yunhorn_lorawan_l_v1(s *serial.Port) {
|
||||||
|
for {
|
||||||
|
buf := make([]byte, 128)
|
||||||
|
b_buf := make([]byte, 0)
|
||||||
|
nn := 0
|
||||||
|
for {
|
||||||
|
n, err := s.Read(buf)
|
||||||
|
nn = n + nn
|
||||||
|
b_buf = append(b_buf, buf[:n]...)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch nn {
|
||||||
|
case 4:
|
||||||
|
go yunhorn_kgl_l_v1(b_buf[:nn])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func yunhorn_kgl_l_v1(data_buf []byte) {
|
||||||
|
log.Println(data_buf)
|
||||||
|
var device Device
|
||||||
|
device.Lock()
|
||||||
|
device.ID = "4E5D52DD-EB81-43C0-A2B6-04E432412EBA"
|
||||||
|
device.VERSION = "yunhorn_kgl_l_v1"
|
||||||
|
device.ONLINE = true
|
||||||
|
device.DATA = make(map[string]interface{})
|
||||||
|
device.DATA["data1"] = 0
|
||||||
|
device.Unlock()
|
||||||
|
DEVICEDATAS.Lock()
|
||||||
|
DEVICEDATAS.DATA["yunhorn_kgl_l_v1_1"] = device
|
||||||
|
DEVICEDATAS.Unlock()
|
||||||
|
|
||||||
|
if conf.DEBUG {
|
||||||
|
log.Println(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
send_data(1005, device)
|
||||||
|
}
|
||||||
|
|
||||||
func yunhorn_sb_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
func yunhorn_sb_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||||
_, err = s.Write([]byte(command[0]))
|
_, err = s.Write([]byte(command[0]))
|
||||||
check(err)
|
check(err)
|
||||||
|
@ -60,7 +101,7 @@ func yunhorn_sb_c_v1(s *serial.Port, device_id string, command [][]byte, num str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func yunhorn_xsy_c_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
func yunhorn_xsy_l_v1(s *serial.Port, device_id string, command [][]byte, num string) {
|
||||||
_, err = s.Write([]byte(command[0]))
|
_, err = s.Write([]byte(command[0]))
|
||||||
check(err)
|
check(err)
|
||||||
if conf.DEBUG {
|
if conf.DEBUG {
|
||||||
|
@ -83,19 +124,19 @@ func yunhorn_xsy_c_v1(s *serial.Port, device_id string, command [][]byte, num st
|
||||||
data_buf := b_buf[3 : nn-4]
|
data_buf := b_buf[3 : nn-4]
|
||||||
|
|
||||||
DEVICEDATAS.RLock()
|
DEVICEDATAS.RLock()
|
||||||
var olddata = DEVICEDATAS.DATA["yunhorn_xsy_c_v1_"+num]
|
var olddata = DEVICEDATAS.DATA["yunhorn_xsy_l_v1_"+num]
|
||||||
DEVICEDATAS.RUnlock()
|
DEVICEDATAS.RUnlock()
|
||||||
|
|
||||||
var device Device
|
var device Device
|
||||||
device.Lock()
|
device.Lock()
|
||||||
device.ID = device_id
|
device.ID = device_id
|
||||||
device.VERSION = "yunhorn_xsy_c_v1"
|
device.VERSION = "yunhorn_xsy_l_v1"
|
||||||
device.ONLINE = true
|
device.ONLINE = true
|
||||||
device.DATA = make(map[string]interface{})
|
device.DATA = make(map[string]interface{})
|
||||||
device.DATA["data"] = binary.BigEndian.Uint16(data_buf)
|
device.DATA["data"] = binary.BigEndian.Uint16(data_buf)
|
||||||
device.Unlock()
|
device.Unlock()
|
||||||
DEVICEDATAS.Lock()
|
DEVICEDATAS.Lock()
|
||||||
DEVICEDATAS.DATA["yunhorn_xsy_c_v1_"+num] = device
|
DEVICEDATAS.DATA["yunhorn_xsy_l_v1_"+num] = device
|
||||||
DEVICEDATAS.Unlock()
|
DEVICEDATAS.Unlock()
|
||||||
|
|
||||||
if device.DATA["data"] != olddata.DATA["data"] {
|
if device.DATA["data"] != olddata.DATA["data"] {
|
||||||
|
|
Loading…
Reference in New Issue