支持国标控制命令解析
parent
8892975d77
commit
367acdaf97
|
@ -1,9 +1,79 @@
|
||||||
package com.genersoft.iot.vmp.gb28181.bean;
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.command.*;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 国标28181控制指令
|
* 国标28181控制指令
|
||||||
*/
|
*/
|
||||||
public class ControlCommand {
|
public class ControlCommand {
|
||||||
|
|
||||||
|
public static ICommandInfo analysisCommand(String command){
|
||||||
|
if (ObjectUtils.isEmpty(command)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String byte4Str = command.substring(6, 8);
|
||||||
|
int byte4Int = Integer.parseInt(byte4Str, 16);
|
||||||
|
switch (byte4Int) {
|
||||||
|
case 0x81:
|
||||||
|
// 预置位指令: 设置
|
||||||
|
return PresetCommand.getInstance(PresetCommand.Type.SET, command);
|
||||||
|
case 0x82:
|
||||||
|
// 预置位指令: 调用
|
||||||
|
return PresetCommand.getInstance(PresetCommand.Type.CALL, command);
|
||||||
|
case 0x83:
|
||||||
|
// 预置位指令: 删除
|
||||||
|
return PresetCommand.getInstance(PresetCommand.Type.DELETE, command);
|
||||||
|
case 0x84:
|
||||||
|
// 巡航指令: 加入巡航点
|
||||||
|
return CruiseCommand.getInstance(CruiseCommand.Type.ADD_POINT, command);
|
||||||
|
case 0x85:
|
||||||
|
// 巡航指令: 删除一个巡航点
|
||||||
|
return CruiseCommand.getInstance(CruiseCommand.Type.DELETE_POINT, command);
|
||||||
|
case 0x86:
|
||||||
|
// 巡航指令: 设置巡航速度
|
||||||
|
return CruiseCommand.getInstance(CruiseCommand.Type.SET_SPEED, command);
|
||||||
|
case 0x87:
|
||||||
|
// 巡航指令: 设置巡航停留时间
|
||||||
|
return CruiseCommand.getInstance(CruiseCommand.Type.SET_TIME, command);
|
||||||
|
case 0x88:
|
||||||
|
// 巡航指令: 开始巡航
|
||||||
|
return CruiseCommand.getInstance(CruiseCommand.Type.START, command);
|
||||||
|
case 0x89:
|
||||||
|
// 扫描指令
|
||||||
|
String byte6Str = command.substring(10, 12);
|
||||||
|
int byte6Int = Integer.parseInt(byte6Str, 16);
|
||||||
|
switch (byte6Int){
|
||||||
|
case 0x00:
|
||||||
|
// 开始自动扫描
|
||||||
|
return ScanCommand.getInstance(ScanCommand.Type.START, command);
|
||||||
|
case 0x01:
|
||||||
|
// 设置自动扫描左边界
|
||||||
|
return ScanCommand.getInstance(ScanCommand.Type.SET_LEFT, command);
|
||||||
|
case 0x02:
|
||||||
|
// 设置自动扫描右边界
|
||||||
|
return ScanCommand.getInstance(ScanCommand.Type.SET_RIGHT, command);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case 0x8A:
|
||||||
|
// 扫描指令-设置自动扫描速度
|
||||||
|
return ScanCommand.getInstance(ScanCommand.Type.SET_SPEED, command);
|
||||||
|
case 0x8C:
|
||||||
|
// 辅助开关-开
|
||||||
|
return AuxiliaryCommand.getInstance(AuxiliaryCommand.Type.ON, command);
|
||||||
|
case 0x8D:
|
||||||
|
// 助开关-关
|
||||||
|
return AuxiliaryCommand.getInstance(AuxiliaryCommand.Type.OFF, command);
|
||||||
|
default:
|
||||||
|
int byte4ForBit6 = byte4Int >> 6 & 1;
|
||||||
|
if (byte4ForBit6 == 0) {
|
||||||
|
// PTZ指令
|
||||||
|
return PTZCommand.getInstance(command);
|
||||||
|
}else {
|
||||||
|
// FI指令
|
||||||
|
return FICommand.getInstance(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 辅助开关
|
||||||
|
*/
|
||||||
|
public class AuxiliaryCommand implements ICommandInfo{
|
||||||
|
|
||||||
|
public static enum Type{
|
||||||
|
ON, OFF
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令类型: 开, 关
|
||||||
|
*/
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 辅助开关编号,取值为“1”表示雨刷控制
|
||||||
|
*/
|
||||||
|
private int no;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.AUXILIARY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuxiliaryCommand getInstance(Type type, String command) {
|
||||||
|
AuxiliaryCommand auxiliaryCommand = new AuxiliaryCommand();
|
||||||
|
auxiliaryCommand.setType(type);
|
||||||
|
auxiliaryCommand.setNo(Integer.parseInt(command.substring(8, 10), 16));
|
||||||
|
return auxiliaryCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNo() {
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNo(int no) {
|
||||||
|
this.no = no;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
public enum CommandType {
|
||||||
|
PTZ, FI, PRESET, CRUISE, SCAN, AUXILIARY
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡航指令
|
||||||
|
*/
|
||||||
|
public class CruiseCommand implements ICommandInfo{
|
||||||
|
|
||||||
|
public static enum Type{
|
||||||
|
ADD_POINT, DELETE_POINT, SET_SPEED, SET_TIME, START
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令类型: 加入巡航点,删除一个巡航点, 设置巡航速度, 设置巡航停留时间, 开始巡航
|
||||||
|
*/
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡航组号
|
||||||
|
*/
|
||||||
|
private int cruiseGroupNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡航速度
|
||||||
|
*/
|
||||||
|
private int cruiseSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡航停留时间 是秒(s)
|
||||||
|
*/
|
||||||
|
private int cruiseTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预置位号
|
||||||
|
*/
|
||||||
|
private int presetNo;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.CRUISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CruiseCommand getInstance(Type type, String command) {
|
||||||
|
CruiseCommand presetCommand = new CruiseCommand();
|
||||||
|
presetCommand.setType(type);
|
||||||
|
presetCommand.setCruiseGroupNo(Integer.parseInt(command.substring(8, 10), 16));
|
||||||
|
presetCommand.setPresetNo(Integer.parseInt(command.substring(10, 12), 16));
|
||||||
|
int value = Integer.parseInt(command.substring(10, 12), 16) & 0xf0 >> 4;
|
||||||
|
if (type == Type.SET_SPEED) {
|
||||||
|
presetCommand.setCruiseSpeed(value);
|
||||||
|
}
|
||||||
|
if (type == Type.SET_TIME) {
|
||||||
|
presetCommand.setCruiseTime(value);
|
||||||
|
}
|
||||||
|
return presetCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCruiseGroupNo() {
|
||||||
|
return cruiseGroupNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCruiseGroupNo(int cruiseGroupNo) {
|
||||||
|
this.cruiseGroupNo = cruiseGroupNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCruiseSpeed() {
|
||||||
|
return cruiseSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCruiseSpeed(int cruiseSpeed) {
|
||||||
|
this.cruiseSpeed = cruiseSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCruiseTime() {
|
||||||
|
return cruiseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCruiseTime(int cruiseTime) {
|
||||||
|
this.cruiseTime = cruiseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPresetNo() {
|
||||||
|
return presetNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPresetNo(int presetNo) {
|
||||||
|
this.presetNo = presetNo;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FI指令
|
||||||
|
*/
|
||||||
|
public class FICommand implements ICommandInfo{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 光圈: 缩小
|
||||||
|
*/
|
||||||
|
private boolean IirisOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 光圈: 放大
|
||||||
|
*/
|
||||||
|
private boolean IirisIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聚焦: 近
|
||||||
|
*/
|
||||||
|
private boolean focusNear;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聚焦: 远
|
||||||
|
*/
|
||||||
|
private boolean focusFar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 光圈速度
|
||||||
|
*/
|
||||||
|
private int IirisSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聚焦速度
|
||||||
|
*/
|
||||||
|
private int focusSpeed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.FI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FICommand getInstance(String command) {
|
||||||
|
FICommand fiCommand = new FICommand();
|
||||||
|
int byte4 = Integer.parseInt(command.substring(6, 8), 16);
|
||||||
|
int byte5 = Integer.parseInt(command.substring(8, 10), 16);
|
||||||
|
int byte6 = Integer.parseInt(command.substring(10, 12), 16);
|
||||||
|
fiCommand.setIirisOut((byte4 >> 3 & 1) == 1);
|
||||||
|
fiCommand.setIirisIn((byte4 >> 2 & 1) == 1);
|
||||||
|
fiCommand.setFocusNear((byte4 >> 1 & 1) == 1);
|
||||||
|
fiCommand.setFocusFar((byte4 & 1) == 1);
|
||||||
|
fiCommand.setFocusSpeed(byte5);
|
||||||
|
fiCommand.setIirisSpeed(byte6);
|
||||||
|
return fiCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIirisOut() {
|
||||||
|
return IirisOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIirisOut(boolean iirisOut) {
|
||||||
|
IirisOut = iirisOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIirisIn() {
|
||||||
|
return IirisIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIirisIn(boolean iirisIn) {
|
||||||
|
IirisIn = iirisIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFocusNear() {
|
||||||
|
return focusNear;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFocusNear(boolean focusNear) {
|
||||||
|
this.focusNear = focusNear;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFocusFar() {
|
||||||
|
return focusFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFocusFar(boolean focusFar) {
|
||||||
|
this.focusFar = focusFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIirisSpeed() {
|
||||||
|
return IirisSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIirisSpeed(int iirisSpeed) {
|
||||||
|
IirisSpeed = iirisSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFocusSpeed() {
|
||||||
|
return focusSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFocusSpeed(int focusSpeed) {
|
||||||
|
this.focusSpeed = focusSpeed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
public interface ICommandInfo {
|
||||||
|
|
||||||
|
CommandType getType();
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PTZ指令
|
||||||
|
*/
|
||||||
|
public class PTZCommand implements ICommandInfo{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 镜头变倍: 缩小
|
||||||
|
*/
|
||||||
|
private boolean out;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 镜头变倍: 放大
|
||||||
|
*/
|
||||||
|
private boolean in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云台垂直方向控制: 上
|
||||||
|
*/
|
||||||
|
private boolean up;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云台垂直方向控制: 下
|
||||||
|
*/
|
||||||
|
private boolean down;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云台垂直方向控制: 左
|
||||||
|
*/
|
||||||
|
private boolean left;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云台垂直方向控制: 右
|
||||||
|
*/
|
||||||
|
private boolean right;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 水平控制速度相对值
|
||||||
|
*/
|
||||||
|
private int xSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 垂直控制速度相对值
|
||||||
|
*/
|
||||||
|
private int ySpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变倍控制速度相对值(地址高4位)
|
||||||
|
*/
|
||||||
|
private int zSpeed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.PTZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PTZCommand getInstance(String command) {
|
||||||
|
PTZCommand ptzCommand = new PTZCommand();
|
||||||
|
int byte4 = Integer.parseInt(command.substring(6, 8), 16);
|
||||||
|
int byte5 = Integer.parseInt(command.substring(8, 10), 16);
|
||||||
|
int byte6 = Integer.parseInt(command.substring(10, 12), 16);
|
||||||
|
int byte7 = Integer.parseInt(command.substring(12, 14), 16);
|
||||||
|
ptzCommand.setOut((byte4 >> 5 & 1) == 1);
|
||||||
|
ptzCommand.setIn((byte4 >> 4 & 1) == 1);
|
||||||
|
ptzCommand.setUp((byte4 >> 3 & 1) == 1);
|
||||||
|
ptzCommand.setDown((byte4 >> 2 & 1) == 1);
|
||||||
|
ptzCommand.setLeft((byte4 >> 1 & 1) == 1);
|
||||||
|
ptzCommand.setRight((byte4 & 1) == 1);
|
||||||
|
ptzCommand.setxSpeed(byte5);
|
||||||
|
ptzCommand.setySpeed(byte6);
|
||||||
|
// 取高四位
|
||||||
|
ptzCommand.setzSpeed(byte7 & 0xf0 >> 4);
|
||||||
|
return ptzCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOut() {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOut(boolean out) {
|
||||||
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIn() {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIn(boolean in) {
|
||||||
|
this.in = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUp() {
|
||||||
|
return up;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUp(boolean up) {
|
||||||
|
this.up = up;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDown() {
|
||||||
|
return down;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDown(boolean down) {
|
||||||
|
this.down = down;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeft() {
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLeft(boolean left) {
|
||||||
|
this.left = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRight() {
|
||||||
|
return right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRight(boolean right) {
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getxSpeed() {
|
||||||
|
return xSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setxSpeed(int xSpeed) {
|
||||||
|
this.xSpeed = xSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getySpeed() {
|
||||||
|
return ySpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setySpeed(int ySpeed) {
|
||||||
|
this.ySpeed = ySpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getzSpeed() {
|
||||||
|
return zSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setzSpeed(int zSpeed) {
|
||||||
|
this.zSpeed = zSpeed;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预置位
|
||||||
|
*/
|
||||||
|
public class PresetCommand implements ICommandInfo{
|
||||||
|
|
||||||
|
public static enum Type{
|
||||||
|
SET, CALL, DELETE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令类型: 设置,调用, 删除
|
||||||
|
*/
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预置位号
|
||||||
|
*/
|
||||||
|
private int no;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.PRESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PresetCommand getInstance(Type type, String command) {
|
||||||
|
PresetCommand presetCommand = new PresetCommand();
|
||||||
|
presetCommand.setType(type);
|
||||||
|
presetCommand.setNo(Integer.parseInt(command.substring(10, 13), 16));
|
||||||
|
return presetCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNo() {
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNo(int no) {
|
||||||
|
this.no = no;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.genersoft.iot.vmp.gb28181.bean.command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预置位
|
||||||
|
*/
|
||||||
|
public class ScanCommand implements ICommandInfo{
|
||||||
|
|
||||||
|
public static enum Type{
|
||||||
|
START, SET_LEFT, SET_RIGHT, SET_SPEED
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令类型: 开始自动扫描, 设置自动扫描左边界, 设置自动扫描右边界, 设置自动扫描速度
|
||||||
|
*/
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描组号
|
||||||
|
*/
|
||||||
|
private int no;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动扫描速度
|
||||||
|
*/
|
||||||
|
private int speed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandType getType() {
|
||||||
|
return CommandType.SCAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScanCommand getInstance(Type type, String command) {
|
||||||
|
ScanCommand scanCommand = new ScanCommand();
|
||||||
|
scanCommand.setType(type);
|
||||||
|
scanCommand.setNo(Integer.parseInt(command.substring(8, 10), 16));
|
||||||
|
if (type == Type.SET_SPEED) {
|
||||||
|
scanCommand.setSpeed(Integer.parseInt(command.substring(12, 14), 16) & 0xf0 >> 4);
|
||||||
|
}
|
||||||
|
return scanCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNo() {
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNo(int no) {
|
||||||
|
this.no = no;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpeed(int speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue