Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
SigerCalculation
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
TCS-eConfigTool
SigerCalculation
Commits
073323de
Commit
073323de
authored
Dec 02, 2025
by
lvshi.gong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改tcp通信方式,修正特征值处理逻辑
parent
991e4584
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
215 additions
and
153 deletions
+215
-153
RamdomForestCalculate.cpp
SigerCalculation/RadomForestSAC/RamdomForestCalculate.cpp
+169
-50
RandomForestClassifier.cpp
SigerCalculation/RadomForestSAC/RandomForestClassifier.cpp
+7
-0
SigerCalculation
SigerCalculation/package/E3/SigerCalculation
+0
-0
TcpClient.cpp
SigerCalculation/tcp/TcpClient.cpp
+31
-82
TcpClient.h
SigerCalculation/tcp/TcpClient.h
+8
-21
No files found.
SigerCalculation/RadomForestSAC/RamdomForestCalculate.cpp
View file @
073323de
...
@@ -3,6 +3,20 @@
...
@@ -3,6 +3,20 @@
#include "spdlog/spdlog.h"
#include "spdlog/spdlog.h"
#include <QFileInfo>
#include <QFileInfo>
int
pickPriorityValue
(
double
xpred
,
double
ypred
,
double
zpred
)
{
// 四舍五入
int
x
=
qRound
(
xpred
);
int
y
=
qRound
(
ypred
);
int
z
=
qRound
(
zpred
);
// 优先检查 1 → 2 → 3
if
(
x
==
1
||
y
==
1
||
z
==
1
)
return
1
;
if
(
x
==
2
||
y
==
2
||
z
==
2
)
return
2
;
if
(
x
==
3
||
y
==
3
||
z
==
3
)
return
3
;
return
0
;
// 都没有
}
void
CreatTable
()
void
CreatTable
()
{
{
...
@@ -122,8 +136,8 @@ RamdomForestCalculate::RamdomForestCalculate(QObject *parent)
...
@@ -122,8 +136,8 @@ RamdomForestCalculate::RamdomForestCalculate(QObject *parent)
}
}
//GLS Test
//GLS Test
StreamInfo
info
(
1
,
"A$14$1$1$1$202$0"
,
"1764237011402
-0"
,
"0"
);
// StreamInfo info(1,"C$14$1$1$1$202$0","1764581206660
-0","0");
SendStreamAlarminfo
(
info
);
//
SendStreamAlarminfo(info);
//连接信号和槽函数
//连接信号和槽函数
...
@@ -179,49 +193,101 @@ QString RamdomForestCalculate::QueryPowerData(const StreamInfo &alarmInfo)
...
@@ -179,49 +193,101 @@ QString RamdomForestCalculate::QueryPowerData(const StreamInfo &alarmInfo)
void
RamdomForestCalculate
::
SendStreamAlarminfo
(
const
StreamInfo
&
alarmInfo
)
void
RamdomForestCalculate
::
SendStreamAlarminfo
(
const
StreamInfo
&
alarmInfo
)
{
{
TcpClient
*
client
=
new
TcpClient
();
QString
ip
(
"127.0.0.1"
);
TcpClient
tcp_client
(
ip
,
5999
);
// 统一的清理函数
QJsonObject
json
;
auto
cleanup
=
[
client
]()
{
json
[
"source"
]
=
STREAM_MESSAGE
;
static
bool
cleaned
=
false
;
// 静态变量确保只清理一次收到 TMS 信号
json
[
"typealarm"
]
=
QString
::
number
(
alarmInfo
.
alarmtype
);
if
(
!
cleaned
)
{
json
[
"target"
]
=
alarmInfo
.
target
;
cleaned
=
true
;
json
[
"startIds"
]
=
alarmInfo
.
startIds
;
//qDebug() << "清理客户端资源";
json
[
"endIds"
]
=
alarmInfo
.
endIds
;
client
->
disconnectFromServer
();
QTimer
::
singleShot
(
0
,
client
,
&
QObject
::
deleteLater
);
// 延迟删除确保安全
tcp_client
.
sendData
(
QString
(
QJsonDocument
(
json
).
toJson
(
QJsonDocument
::
Compact
)).
toStdString
().
c_str
());
}
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"发送流式报警信息成功"
);
};
// 创建短连接 TcpClient
// 连接所有信号到统一的清理函数
// TcpClient* client = new TcpClient();
QObject
::
connect
(
client
,
&
TcpClient
::
connected
,
[
client
,
alarmInfo
,
cleanup
]()
{
qDebug
()
<<
"=== 连接成功,开始发送报警消息 ==="
;
// // 构造消息
// QJsonObject message;
QJsonObject
message
;
// message["source"] = STREAM_MESSAGE;
message
[
"source"
]
=
STREAM_MESSAGE
;
// message["typealarm"] = QString::number(alarmInfo.alarmtype);
message
[
"typealarm"
]
=
alarmInfo
.
alarmtype
;
// message["target"] = alarmInfo.target;
message
[
"target"
]
=
alarmInfo
.
target
;
// message["startIds"] = alarmInfo.startIds;
message
[
"startIds"
]
=
alarmInfo
.
startIds
;
// message["endIds"] = alarmInfo.endIds;
message
[
"endIds"
]
=
alarmInfo
.
endIds
;
//message["power"] = alarmInfo.endIds;
// // 连接成功后发送消息
// QObject::connect(client, &TcpClient::connected, [client, message]() {
client
->
sendMessage
(
message
);
// qDebug() << "=== 连接成功,开始发送报警消息 ===";
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"发送给流式告警信息成功"
);
// client->sendMessage(message);
// 发送完成后立即开始清理
cleanup
();
// // 延迟关闭,确保消息发送完成
});
// QTimer::singleShot(200, client, [client]() {
// //client->disconnectFromServer();
QObject
::
connect
(
client
,
&
TcpClient
::
disconnected
,
cleanup
);
// client->deleteLater();
QObject
::
connect
(
client
,
&
TcpClient
::
messageReceived
,
cleanup
);
// });
QObject
::
connect
(
client
,
&
TcpClient
::
errorOccurred
,
cleanup
);
// SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),
// "发送流式报警信息成功");
// });
// // 连接错误也自动释放
// QObject::connect(client, &TcpClient::errorOccurred, [client](const QString &err) {
// qWarning() << "TcpClient错误:" << err;
// client->deleteLater();
// });
// // 发起连接
// client->connectToServer("127.0.0.1", STREAM_PORT);
}
// 设置连接超时(5秒)
QTimer
::
singleShot
(
5000
,
client
,
cleanup
);
// 连接到服务器
//void RamdomForestCalculate::SendStreamAlarminfo(const StreamInfo &alarmInfo)
qDebug
()
<<
"正在连接到服务器..."
;
//{
client
->
connectToServer
(
"127.0.0.1"
,
STREAM_PORT
);
// TcpClient* client = new TcpClient();
}
// // 统一的清理函数
// auto cleanup = [client]() {
// static bool cleaned = false; // 静态变量确保只清理一次收到 TMS 信号
// if (!cleaned) {
// cleaned = true;
// //qDebug() << "清理客户端资源";
// client->disconnectFromServer();
// QTimer::singleShot(0, client, &QObject::deleteLater); // 延迟删除确保安全
// }
// };
// // 连接所有信号到统一的清理函数
// QObject::connect(client, &TcpClient::connected, [client, alarmInfo, cleanup]() {
// qDebug() << "=== 连接成功,开始发送报警消息 ===";
// QJsonObject message;
// message["source"] = STREAM_MESSAGE;
// message["typealarm"] = QString::number(alarmInfo.alarmtype);
// message["target"] = alarmInfo.target;
// message["startIds"] = alarmInfo.startIds;
// message["endIds"] = alarmInfo.endIds;
// //message["power"] = alarmInfo.endIds;
// client->sendMessage(message);
// SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"发送给流式告警信息成功");
// // 发送完成后立即开始清理
// cleanup();
// });
// QObject::connect(client, &TcpClient::disconnected, cleanup);
// QObject::connect(client, &TcpClient::messageReceived, cleanup);
// QObject::connect(client, &TcpClient::errorOccurred, cleanup);
// // 设置连接超时(5秒)
// QTimer::singleShot(5000, client, cleanup);
// // 连接到服务器
// qDebug() << "正在连接到服务器...";
// client->connectToServer("127.0.0.1", STREAM_PORT);
//}
QList
<
SACRecord
>
RamdomForestCalculate
::
queryRecordsByLabel
(
const
QString
&
dbFileName
,
int
targetLabel
)
QList
<
SACRecord
>
RamdomForestCalculate
::
queryRecordsByLabel
(
const
QString
&
dbFileName
,
int
targetLabel
)
{
{
...
@@ -310,36 +376,89 @@ int RamdomForestCalculate::Save_SACDATA(const Dc_SacData &sacdata)
...
@@ -310,36 +376,89 @@ int RamdomForestCalculate::Save_SACDATA(const Dc_SacData &sacdata)
for
(
int
i
=
0
;
i
<
3
;
++
i
)
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
{
fea
[
i
].
print
();
fea
[
i
].
print
();
if
(
i
==
0
)
{
fea
[
i
].
fill
(
x
);
fea
[
i
].
fill
(
x
);
}
else
if
(
i
==
1
)
{
fea
[
i
].
fill
(
y
);
fea
[
i
].
fill
(
y
);
}
else
if
(
i
==
2
)
{
fea
[
i
].
fill
(
z
);
fea
[
i
].
fill
(
z
);
}
}
}
//step2: 预测报警
//step2: 预测报警
//std::string data;
//std::string data;
qDebug
()
<<
"x "
<<
x
;
qDebug
()
<<
"x "
<<
x
;
if
(
IfHaveModel
)
if
(
IfHaveModel
)
{
{
std
::
vector
<
float
>
test_sample
(
10
,
0
);
//X轴预测
std
::
vector
<
float
>
xtest_sample
;
//用逗号分割
QStringList
xlist
=
x
.
split
(
','
);
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"xlist: {}"
,
xlist
.
size
());
//转成 float 并存到 vector
for
(
const
QString
&
s
:
xlist
)
{
bool
ok
=
false
;
float
f
=
s
.
toFloat
(
&
ok
);
if
(
ok
)
{
xtest_sample
.
push_back
(
f
);
}
else
{
std
::
cerr
<<
"转换失败: "
<<
s
.
toStdString
()
<<
std
::
endl
;
}
}
double
xpred
=
Classifier
->
predict
(
xtest_sample
);
//cout << "测试样本预测类别: " << pred << endl;
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"x轴测试样本预测类别: {}"
,
xpred
);
//Y轴预测
std
::
vector
<
float
>
ytest_sample
;
//用逗号分割
//用逗号分割
QStringList
list
=
x
.
split
(
','
);
QStringList
ylist
=
y
.
split
(
','
);
//转成 float 并存到 vector
//转成 float 并存到 vector
for
(
const
QString
&
s
:
list
)
{
for
(
const
QString
&
s
:
y
list
)
{
bool
ok
=
false
;
bool
ok
=
false
;
float
f
=
s
.
toFloat
(
&
ok
);
float
f
=
s
.
toFloat
(
&
ok
);
if
(
ok
)
{
if
(
ok
)
{
test_sample
.
push_back
(
f
);
y
test_sample
.
push_back
(
f
);
}
else
{
}
else
{
std
::
cerr
<<
"转换失败: "
<<
s
.
toStdString
()
<<
std
::
endl
;
std
::
cerr
<<
"转换失败: "
<<
s
.
toStdString
()
<<
std
::
endl
;
}
}
}
}
double
pred
=
Classifier
->
predict
(
test_sample
);
double
ypred
=
Classifier
->
predict
(
y
test_sample
);
//cout << "测试样本预测类别: " << pred << endl;
//cout << "测试样本预测类别: " << pred << endl;
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"y轴测试样本预测类别: {}"
,
ypred
);
//Z轴预测
std
::
vector
<
float
>
ztest_sample
;
//用逗号分割
QStringList
zlist
=
z
.
split
(
','
);
//转成 float 并存到 vector
for
(
const
QString
&
s
:
zlist
)
{
bool
ok
=
false
;
float
f
=
s
.
toFloat
(
&
ok
);
if
(
ok
)
{
ztest_sample
.
push_back
(
f
);
}
else
{
std
::
cerr
<<
"转换失败: "
<<
s
.
toStdString
()
<<
std
::
endl
;
}
}
double
zpred
=
Classifier
->
predict
(
ztest_sample
);
//cout << "测试样本预测类别: " << pred << endl;
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"z轴测试样本预测类别: {}"
,
zpred
);
int
predRes
=
pickPriorityValue
(
xpred
,
ypred
,
zpred
);
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"测试样本预测类别: {}"
,
pred
);
StreamInfo
info
(
pred
,
sacdata
.
target
,
sacdata
.
startIds
,
sacdata
.
endIds
);
StreamInfo
info
(
pred
Res
,
sacdata
.
target
,
sacdata
.
startIds
,
sacdata
.
endIds
);
SendStreamAlarminfo
(
info
);
SendStreamAlarminfo
(
info
);
}
}
...
...
SigerCalculation/RadomForestSAC/RandomForestClassifier.cpp
View file @
073323de
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
#include <algorithm>
#include <algorithm>
#include <random>
#include <random>
#include "common.h"
#include "common.h"
#include "spdlog/spdlog.h"
std
::
vector
<
sample_type
>
RandomForestClassifier
::
convert_to_dlib_format
(
const
std
::
vector
<
std
::
vector
<
float
>>&
X
)
std
::
vector
<
sample_type
>
RandomForestClassifier
::
convert_to_dlib_format
(
const
std
::
vector
<
std
::
vector
<
float
>>&
X
)
{
{
...
@@ -294,6 +295,9 @@ double RandomForestClassifier::predict(const std::vector<float>& sample)
...
@@ -294,6 +295,9 @@ double RandomForestClassifier::predict(const std::vector<float>& sample)
if
(
sample
.
size
()
!=
static_cast
<
size_t
>
(
feature_dim
))
if
(
sample
.
size
()
!=
static_cast
<
size_t
>
(
feature_dim
))
{
{
printf
(
"invalid param: sample_size=%ld feature_dim=%d
\n
"
,
sample
.
size
(),
feature_dim
);
printf
(
"invalid param: sample_size=%ld feature_dim=%d
\n
"
,
sample
.
size
(),
feature_dim
);
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"invalid param: sample_size-------sample.size:{}--------feature_dim{}"
,
sample
.
size
(),
feature_dim
);
return
-
1
;
return
-
1
;
}
}
...
@@ -306,6 +310,9 @@ double RandomForestClassifier::predict(const std::vector<float>& sample)
...
@@ -306,6 +310,9 @@ double RandomForestClassifier::predict(const std::vector<float>& sample)
}
}
catch
(
const
std
::
exception
&
e
)
{
catch
(
const
std
::
exception
&
e
)
{
DEBUG_PRINT
(
"load model failure: %s
\n
"
,
e
.
what
());
DEBUG_PRINT
(
"load model failure: %s
\n
"
,
e
.
what
());
SPDLOG_LOGGER_DEBUG
(
spdlog
::
get
(
"logger"
),
"load model failure:--------------"
);
return
-
1
;
return
-
1
;
}
}
}
}
...
...
SigerCalculation/package/E3/SigerCalculation
View file @
073323de
No preview for this file type
SigerCalculation/tcp/TcpClient.cpp
View file @
073323de
#include "TcpClient.h"
#include "TcpClient.h"
#include <QHostAddress>
#include <QDebug>
TcpClient
::
TcpClient
(
QObject
*
parent
)
TcpClient
::
TcpClient
(
const
QString
&
ip
,
qint16
port
,
QObject
*
parent
)
:
QObject
(
parent
)
:
QObject
(
parent
)
,
m_socket
(
new
QTcpSocket
(
this
))
,
m_ip
(
ip
)
,
m_port
(
port
)
{
{
// 连接信号槽
m_socket
=
new
QTcpSocket
();
connect
(
m_socket
,
&
QTcpSocket
::
connected
,
this
,
&
TcpClient
::
onConnected
);
m_socket
->
connectToHost
(
ip
,
port
);
connect
(
m_socket
,
&
QTcpSocket
::
disconnected
,
this
,
&
TcpClient
::
onDisconnected
);
connect
(
m_socket
,
&
QTcpSocket
::
readyRead
,
this
,
&
TcpClient
::
onReadyRead
);
connect
(
m_socket
,
QOverload
<
QAbstractSocket
::
SocketError
>::
of
(
&
QTcpSocket
::
error
),
this
,
&
TcpClient
::
onErrorOccurred
);
}
}
TcpClient
::~
TcpClient
()
TcpClient
::~
TcpClient
()
{
{
disconnectFromServer
();
releaseSocket
();
}
}
void
TcpClient
::
connectToServer
(
const
QString
&
host
,
quint16
port
)
void
TcpClient
::
releaseSocket
(
)
{
{
qDebug
()
<<
"正在连接到服务器:"
<<
host
<<
":"
<<
port
;
if
(
m_socket
)
{
m_socket
->
connectToHost
(
host
,
port
);
m_socket
->
close
();
delete
m_socket
;
m_socket
=
nullptr
;
}
}
}
void
TcpClient
::
sendMessage
(
const
QJsonObject
&
message
)
bool
TcpClient
::
sendData
(
const
char
*
data
)
{
{
if
(
m_socket
->
state
()
!=
QAbstractSocket
::
ConnectedState
)
{
if
(
!
m_socket
->
isOpen
())
{
qWarning
()
<<
"未连接到服务器,无法发送消息"
;
m_socket
->
connectToHost
(
m_ip
,
m_port
);
return
;
if
(
!
m_socket
->
isOpen
())
{
return
false
;
}
}
// 将JSON对象转换为字符串
QJsonDocument
doc
(
message
);
QString
jsonString
=
doc
.
toJson
(
QJsonDocument
::
Compact
);
// 添加换行符作为消息结束标记(根据你的服务端实现)
jsonString
+=
"
\n
"
;
// 发送消息
qint64
bytesWritten
=
m_socket
->
write
(
jsonString
.
toUtf8
());
if
(
bytesWritten
==
-
1
)
{
qWarning
()
<<
"发送消息失败"
;
}
else
{
qDebug
()
<<
"消息发送成功,字节数:"
<<
bytesWritten
;
qDebug
()
<<
"发送的内容:"
<<
jsonString
.
trimmed
();
}
}
}
qint64
sendRe
=
m_socket
->
write
(
data
,
strlen
(
data
));
if
(
-
1
==
sendRe
)
{
void
TcpClient
::
disconnectFromServer
()
qDebug
()
<<
Q_FUNC_INFO
<<
" error : sendRe is -1, data :"
<<
data
;
{
return
false
;
if
(
m_socket
->
state
()
==
QAbstractSocket
::
ConnectedState
)
{
m_socket
->
disconnectFromHost
();
}
}
}
if
(
sendRe
!=
qint64
(
strlen
(
data
)))
{
qDebug
()
<<
Q_FUNC_INFO
<<
" error : sendRe != strlen(data), data :"
<<
data
;
void
TcpClient
::
onConnected
()
return
false
;
{
qDebug
()
<<
"成功连接到服务器"
;
emit
connected
();
}
void
TcpClient
::
onDisconnected
()
{
qDebug
()
<<
"与服务器断开连接"
;
emit
disconnected
();
}
void
TcpClient
::
onReadyRead
()
{
QByteArray
data
=
m_socket
->
readAll
();
m_buffer
.
append
(
data
);
qDebug
()
<<
"接收到服务器响应:"
<<
data
;
// 简单的消息分割(根据你的服务端实现调整)
while
(
m_buffer
.
contains
(
'\n'
))
{
int
endIndex
=
m_buffer
.
indexOf
(
'\n'
);
QByteArray
messageData
=
m_buffer
.
left
(
endIndex
).
trimmed
();
m_buffer
=
m_buffer
.
mid
(
endIndex
+
1
);
// 解析JSON响应
QJsonParseError
parseError
;
QJsonDocument
doc
=
QJsonDocument
::
fromJson
(
messageData
,
&
parseError
);
if
(
parseError
.
error
==
QJsonParseError
::
NoError
&&
doc
.
isObject
())
{
QJsonObject
jsonObj
=
doc
.
object
();
emit
messageReceived
(
jsonObj
);
qDebug
()
<<
"解析服务器响应成功:"
<<
jsonObj
;
}
else
{
// 如果不是JSON,直接作为字符串处理
QString
response
=
QString
::
fromUtf8
(
messageData
);
qDebug
()
<<
"服务器响应:"
<<
response
;
}
}
if
(
!
m_socket
->
waitForBytesWritten
())
{
qDebug
()
<<
Q_FUNC_INFO
<<
" error : sendRe waitForBytesWritten false , data :"
<<
data
<<
m_socket
->
errorString
();
return
false
;
}
}
qDebug
()
<<
Q_FUNC_INFO
<<
" is : "
<<
data
;
return
true
;
}
}
void
TcpClient
::
onErrorOccurred
(
QAbstractSocket
::
SocketError
error
)
bool
TcpClient
::
isConnect
(
)
{
{
QString
errorString
=
m_socket
->
errorString
();
return
m_socket
->
isWritable
();
qWarning
()
<<
"Socket错误:"
<<
errorString
;
emit
errorOccurred
(
errorString
);
}
}
SigerCalculation/tcp/TcpClient.h
View file @
073323de
...
@@ -9,33 +9,20 @@
...
@@ -9,33 +9,20 @@
#define STREAM_MESSAGE "random_alarm"
#define STREAM_MESSAGE "random_alarm"
#define STREAM_PORT 5999
#define STREAM_PORT 5999
class
TcpClient
:
public
QObject
class
TcpClient
:
public
QObject
{
{
Q_OBJECT
Q_OBJECT
public
:
public
:
explicit
TcpClient
(
QObject
*
parent
=
nullptr
);
explicit
TcpClient
(
const
QString
&
ip
,
qint16
port
,
QObject
*
parent
=
nullptr
);
~
TcpClient
();
~
TcpClient
();
void
releaseSocket
();
void
connectToServer
(
const
QString
&
host
=
"127.0.0.1"
,
quint16
port
=
8888
);
bool
sendData
(
const
char
*
data
);
void
sendMessage
(
const
QJsonObject
&
message
);
bool
isConnect
();
void
disconnectFromServer
();
signals
:
signals
:
void
connected
();
void
disconnected
();
void
messageReceived
(
const
QJsonObject
&
message
);
void
errorOccurred
(
const
QString
&
error
);
private
slots
:
void
onConnected
();
void
onDisconnected
();
void
onReadyRead
();
void
onErrorOccurred
(
QAbstractSocket
::
SocketError
error
);
private
:
private
:
QTcpSocket
*
m_socket
;
QTcpSocket
*
m_socket
=
nullptr
;
QByteArray
m_buffer
;
const
QString
m_ip
;
qint16
m_port
;
};
};
#endif // TCPCLIENT_H
#endif // TCPCLIENT_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment