Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
k-sdk
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈伟灿
k-sdk
Commits
cf79452b
Commit
cf79452b
authored
Aug 31, 2021
by
chen.weican
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【修改内容】增加kk_oldccu_msg.c
【提交人】陈伟灿
parent
a9cba6cf
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
559 additions
and
0 deletions
+559
-0
application/klansdk/kk_oldccu_msg.c
application/klansdk/kk_oldccu_msg.c
+559
-0
No files found.
application/klansdk/kk_oldccu_msg.c
0 → 100644
View file @
cf79452b
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kk_data_mng.h"
#include "kk_login_handle.h"
#include "kk_lan_node_db.h"
#include "kk_log.h"
#include "klist.h"
#include "kk_product.h"
#include "com_api.h"
#include "kk_opcode.h"
#include "kk_lan_ctrl.h"
#include "kk_data_mng.h"
#include "kk_oldccu_msg.h"
cJSON
*
old_ccu_msg_build_json
(
const
char
*
nodeid
,
const
char
*
opcode
,
const
char
*
status
,
cJSON
*
arg
)
{
cJSON
*
root
;
if
(
nodeid
==
NULL
||
opcode
==
NULL
||
arg
==
NULL
)
{
return
NULL
;
}
root
=
cJSON_CreateObject
();
if
(
root
){
cJSON_AddStringToObject
(
root
,
"nodeid"
,
nodeid
);
cJSON_AddStringToObject
(
root
,
"opcode"
,
opcode
);
cJSON_AddStringToObject
(
root
,
"status"
,
"success"
);
cJSON_AddItemToObject
(
root
,
"arg"
,
arg
);
}
return
root
;
}
cJSON
*
old_ccu_msg_build
(
const
char
*
nodeid
,
const
char
*
opcode
,
const
char
*
status
,
const
char
*
arg
)
{
cJSON
*
root
;
if
(
nodeid
==
NULL
||
opcode
==
NULL
||
arg
==
NULL
)
{
return
NULL
;
}
root
=
cJSON_CreateObject
();
if
(
root
){
cJSON_AddStringToObject
(
root
,
"nodeid"
,
nodeid
);
cJSON_AddStringToObject
(
root
,
"opcode"
,
opcode
);
if
(
status
==
NULL
){
cJSON_AddStringToObject
(
root
,
"status"
,
"success"
);
}
else
{
cJSON_AddStringToObject
(
root
,
"status"
,
status
);
}
cJSON_AddStringToObject
(
root
,
"arg"
,
arg
);
}
return
root
;
}
int
send_msg_to_module
(
cJSON
*
root
)
{
char
*
msg
;
if
(
root
==
NULL
){
return
-
1
;
}
if
((
msg
=
cJSON_Print
(
root
))
!=
NULL
){
debug_log
(
LOG_INFO_LEVEL
,
"[lan->module]
\n
%s
\n
"
,
msg
);
cJSON_Minify
(
msg
);
kk_send_data_to_sdk
(
msg
);
free
(
msg
);
}
return
0
;
}
cJSON
*
val_conver_new2old
(
cJSON
*
newccuItem
,
cJSON
*
oldccuItem
,
int
syn_type
)
{
cJSON
*
n_value
=
NULL
,
*
n_dataType
=
NULL
,
*
o_dataType
=
NULL
;
cJSON
*
o_valueRange
=
NULL
,
*
n_valueRange
=
NULL
;
if
(
newccuItem
==
NULL
||
newccuItem
->
type
!=
cJSON_Object
||
oldccuItem
==
NULL
||
oldccuItem
->
type
!=
cJSON_Object
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] para.
\n
"
);
return
NULL
;
}
o_valueRange
=
cJSON_GetObjectItem
(
oldccuItem
,
"valueRange"
);
n_valueRange
=
cJSON_GetObjectItem
(
newccuItem
,
"valueRange"
);
n_dataType
=
cJSON_GetObjectItem
(
newccuItem
,
DATATYPE_STRING
);
n_value
=
cJSON_GetObjectItem
(
newccuItem
,
"value"
);
if
(
syn_type
==
1
){
o_dataType
=
cJSON_GetObjectItem
(
oldccuItem
,
"synType"
);
}
else
{
o_dataType
=
cJSON_GetObjectItem
(
oldccuItem
,
DATATYPE_STRING
);
}
return
ccu_value_convert
(
n_dataType
,
n_valueRange
,
o_dataType
,
o_valueRange
,
n_value
);
}
//更新设备状态
static
int
_kk_lan_update_device_status
(
int
nodeId
,
cJSON
*
opcode
,
cJSON
*
arg
)
{
cJSON
*
msg
=
NULL
;
char
nodeBuff
[
33
]
=
{
0
};
char
valBuff
[
33
]
=
{
0
};
if
(
opcode
==
NULL
||
opcode
->
type
!=
cJSON_String
||
arg
==
NULL
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] para.
\n
"
);
return
-
1
;
}
memset
(
nodeBuff
,
0
,
sizeof
(
nodeBuff
));
snprintf
(
nodeBuff
,
32
,
"%d"
,
nodeId
);
memset
(
nodeBuff
,
0
,
sizeof
(
nodeBuff
));
memset
(
valBuff
,
0
,
sizeof
(
valBuff
));
if
(
arg
->
type
==
cJSON_String
){
debug_log
(
LOG_FOCUS_LEVEL
,
"nodeId=%d,opcode=%s,arg=%s
\n
"
,
nodeId
,
opcode
->
valuestring
,
arg
->
valuestring
);
snprintf
(
valBuff
,
sizeof
(
valBuff
),
"%s"
,
arg
->
valuestring
);
}
else
if
(
arg
->
type
==
cJSON_Number
){
if
(((
int
)(
arg
->
valuedouble
*
10
))
%
10
==
0
){
debug_log
(
LOG_FOCUS_LEVEL
,
"nodeId=%d,opcode=%s,arg=%d
\n
"
,
nodeId
,
opcode
->
valuestring
,
arg
->
valueint
);
snprintf
(
valBuff
,
sizeof
(
valBuff
),
"%d"
,
arg
->
valueint
);
}
else
{
debug_log
(
LOG_FOCUS_LEVEL
,
"nodeId=%d,opcode=%s,arg=%f
\n
"
,
nodeId
,
opcode
->
valuestring
,
arg
->
valuedouble
);
snprintf
(
valBuff
,
sizeof
(
valBuff
),
"%f"
,
arg
->
valuedouble
);
}
}
else
if
(
arg
->
type
==
cJSON_True
){
snprintf
(
valBuff
,
sizeof
(
valBuff
),
"%s"
,
"true"
);
}
else
if
(
arg
->
type
==
cJSON_True
){
snprintf
(
valBuff
,
sizeof
(
valBuff
),
"%s"
,
"false"
);
}
msg
=
old_ccu_msg_build
(
nodeBuff
,
opcode
->
valuestring
,
"success"
,
arg
->
valuestring
);
send_msg_to_module
(
msg
);
cJSON_Delete
(
msg
);
return
0
;
}
static
int
_kk_lan_check_channel
(
cJSON
*
channelObj
,
cJSON
*
epNumObj
)
{
int
channel
=
-
1
;
if
(
channelObj
!=
NULL
&&
epNumObj
!=
NULL
){
if
(
epNumObj
->
type
!=
cJSON_String
){
debug_log
(
LOG_INFO_LEVEL
,
"[err] epNumObj.
\n
"
);
return
-
1
;
}
if
(
strlen
(
channelObj
->
valuestring
)
!=
strlen
(
epNumObj
->
valuestring
)
||
strcmp
(
channelObj
->
valuestring
,
epNumObj
->
valuestring
)
!=
0
){
//debug_log(LOG_INFO,"[err] not match.\n");
return
-
1
;
}
channel
=
atoi
(
channelObj
->
valuestring
);
}
else
{
if
(
channelObj
==
NULL
){
if
(
epNumObj
->
type
!=
cJSON_String
){
debug_log
(
LOG_INFO_LEVEL
,
"[err] epNumObj.
\n
"
);
return
-
1
;
}
channel
=
atoi
(
epNumObj
->
valuestring
);
}
else
if
(
epNumObj
==
NULL
){
if
(
channelObj
->
type
!=
cJSON_String
){
debug_log
(
LOG_INFO_LEVEL
,
"[err] channelObj.
\n
"
);
return
-
1
;
}
channel
=
atoi
(
channelObj
->
valuestring
);
}
else
{
channel
=
1
;
}
}
return
channel
;
}
static
int
_kk_lan_sync_device_status
(
const
char
*
deviceCode
,
kk_map_dev_node_t
*
devNode
)
{
cJSON
*
msg
=
NULL
;
cJSON
*
arg
=
NULL
;
int
nodeId
=
-
1
;
char
nodeBuff
[
33
]
=
{
0
};
if
(
devNode
==
NULL
||
devNode
->
syn_type
!=
1
||
devNode
->
syn_opcode
==
NULL
){
return
-
1
;
}
if
((
arg
=
_kk_sync_devicestatus_arg_build
(
devNode
))
==
NULL
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] arg.
\n
"
);
return
-
1
;
}
if
((
nodeId
=
kk_lan_db_node_get
(
deviceCode
,
1
))
==-
1
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] nodeId.
\n
"
);
return
-
1
;
}
debug_log
(
LOG_FOCUS_LEVEL
,
"[sync] device status.
\n
"
);
memset
(
nodeBuff
,
0
,
sizeof
(
nodeBuff
));
snprintf
(
nodeBuff
,
sizeof
(
nodeBuff
),
"%d"
,
nodeId
);
msg
=
old_ccu_msg_build_json
(
nodeBuff
,
devNode
->
syn_opcode
,
NULL
,
arg
);
send_msg_to_module
(
msg
);
cJSON_Delete
(
msg
);
return
0
;
}
//属性转换
static
int
kk_lan_property_convert
(
const
char
*
deviceCode
,
kk_map_dev_node_t
*
devNode
,
cJSON
*
params
)
{
int
i
=
0
,
channel
=
-
1
,
nodeId
=
-
1
;
cJSON
*
args
=
NULL
,
*
valObj
=
NULL
;
cJSON
*
newccu
=
NULL
,
*
oldccu
=
NULL
;
cJSON
*
n_item
=
NULL
,
*
o_item
=
NULL
;
cJSON
*
o_valueRange
=
NULL
,
*
n_valueRange
=
NULL
;
cJSON
*
o_dataType
=
NULL
,
*
n_dataType
=
NULL
;
cJSON
*
opcode
=
NULL
,
*
channelObj
=
NULL
,
*
epNumObj
=
NULL
;
cJSON
*
n_id
=
NULL
;
int
o_item_size
=
0
,
n_item_size
=
0
;
int
item_size
=
0
;
cJSON
*
epsAry
=
NULL
,
*
epAryItem
=
NULL
,
*
epAryEpNumObj
=
NULL
;
int
j
,
mFlag
=
0
,
epsArySize
=
0
;
if
(
deviceCode
==
NULL
||
devNode
==
NULL
||
params
==
NULL
||
params
->
type
!=
cJSON_Object
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] para.
\n
"
);
return
-
1
;
}
oldccu
=
devNode
->
oldccu
;
newccu
=
devNode
->
newccu
;
o_item_size
=
cJSON_GetArraySize
(
oldccu
);
n_item_size
=
cJSON_GetArraySize
(
newccu
);
item_size
=
(
n_item_size
>
o_item_size
)
?
n_item_size
:
o_item_size
;
for
(
i
=
0
;
i
<
item_size
;
i
++
){
n_item
=
cJSON_GetArrayItem
(
newccu
,
i
);
if
((
o_item
=
cJSON_GetArrayItem
(
oldccu
,
i
))
==
NULL
||
o_item
->
type
!=
cJSON_Object
){
debug_log
(
LOG_INFO_LEVEL
,
"[err] para.i=%d
\n
"
,
i
);
continue
;
}
if
((
n_id
=
cJSON_GetObjectItem
(
n_item
,
"identifier"
))
==
NULL
||
n_id
->
type
!=
cJSON_String
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] cfg file.
\n
"
);
continue
;
}
n_dataType
=
cJSON_GetObjectItem
(
n_item
,
"dataType"
);
n_valueRange
=
cJSON_GetObjectItem
(
n_item
,
"valueRange"
);
o_dataType
=
cJSON_GetObjectItem
(
o_item
,
"dataType"
);
o_valueRange
=
cJSON_GetObjectItem
(
o_item
,
"valueRange"
);
if
(
n_dataType
==
NULL
||
n_dataType
->
type
!=
cJSON_String
||
o_dataType
==
NULL
||
o_dataType
->
type
!=
cJSON_String
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] dataType.
\n
"
);
continue
;
}
channelObj
=
cJSON_GetObjectItem
(
o_item
,
"channel"
);
epNumObj
=
cJSON_GetObjectItem
(
params
,
"epNum"
);
if
((
channel
=
_kk_lan_check_channel
(
channelObj
,
epNumObj
))
==-
1
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[channel] %d.
\n
"
,
channel
);
continue
;
}
if
((
epsAry
=
cJSON_GetObjectItem
(
params
,
"eps"
))
!=
NULL
&&
epsAry
->
type
==
cJSON_Array
){
epsArySize
=
cJSON_GetArraySize
(
epsAry
);
for
(
j
=
0
;
j
<
epsArySize
;
j
++
){
epAryItem
=
cJSON_GetArrayItem
(
epsAry
,
j
);
epAryEpNumObj
=
cJSON_GetObjectItem
(
epAryItem
,
"epNum"
);
if
(
epAryEpNumObj
==
NULL
||
epAryEpNumObj
->
type
!=
cJSON_String
||
channel
!=
atoi
(
epAryEpNumObj
->
valuestring
)){
debug_log
(
LOG_NORMAL_LEVEL
,
"[epsAry match] next.
\n
"
);
continue
;
}
if
((
valObj
=
cJSON_GetObjectItem
(
epAryItem
,
n_id
->
valuestring
))
==
NULL
){
debug_log
(
LOG_NORMAL_LEVEL
,
"[epsAry match] next.
\n
"
);
continue
;
}
else
{
mFlag
=
1
;
break
;
}
}
if
(
mFlag
!=
1
){
continue
;
}
}
else
{
if
((
valObj
=
cJSON_GetObjectItem
(
params
,
n_id
->
valuestring
))
==
NULL
){
debug_log
(
LOG_NORMAL_LEVEL
,
"[match] next.
\n
"
);
continue
;
}
}
if
((
nodeId
=
kk_lan_db_node_get
(
deviceCode
,
channel
))
==-
1
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] not find node.
\n
"
);
continue
;
}
if
((
opcode
=
cJSON_GetObjectItem
(
n_item
,
"opcodemap"
))
==
NULL
||
opcode
->
type
!=
cJSON_String
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] cfg file.
\n
"
);
continue
;
}
kk_lan_replace_val_to_obj
(
n_item
,
valObj
,
"value"
);
if
((
args
=
ccu_value_convert
(
n_dataType
,
n_valueRange
,
o_dataType
,
o_valueRange
,
valObj
))
!=
NULL
){
_kk_lan_update_device_status
(
nodeId
,
opcode
,
args
);
//todo :
//cJSON_Delete(args);
}
}
_kk_lan_sync_device_status
(
deviceCode
,
devNode
);
return
0
;
}
static
int
attr_indoorAir_report
(
cJSON
*
params
)
{
int
k
=
0
;
if
(
params
==
NULL
){
return
-
1
;
}
cJSON
*
epsAry
=
cJSON_GetObjectItem
(
params
,
"eps"
);
if
(
epsAry
==
NULL
){
return
-
1
;
}
int
epsize
=
cJSON_GetArraySize
(
epsAry
);
for
(
k
=
0
;
k
<
epsize
;
k
++
){
char
tmpIdx
[
4
]
=
{
0
};
cJSON
*
infoItem
=
cJSON_GetArrayItem
(
epsAry
,
k
);
if
(
infoItem
==
NULL
)
continue
;
kk_send_indoorAir_status
(
infoItem
);
}
return
0
;
}
//属性状态上报处理
int
kk_lan_property_post_deal
(
const
char
*
deviceCode
,
cJSON
*
payload
)
{
cJSON
*
params
=
NULL
;
kk_map_dev_node_t
*
dev
=
NULL
;
debug_log
(
LOG_FOCUS_LEVEL
,
"[property post] deviceCode(%s).
\n
"
,
deviceCode
);
if
(
kk_map_dev_search_by_deviceCode
(
deviceCode
,
&
dev
)
==
0
){
params
=
cJSON_GetObjectItem
(
payload
,
"params"
);
if
(
strcmp
(
dev
->
productCode
,
"3062"
)
==
0
){
attr_indoorAir_report
(
params
);
}
else
{
return
kk_lan_property_convert
(
deviceCode
,
dev
,
params
);
}
}
else
{
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] not find deviceCode(%s).
\n
"
,
deviceCode
);
return
-
1
;
}
return
0
;
}
//属性状态同步处理
int
kk_lan_property_syn_deal
(
const
char
*
deviceCode
,
cJSON
*
properties
)
{
cJSON
*
params
=
NULL
;
kk_map_dev_node_t
*
dev
=
NULL
;
debug_log
(
LOG_FOCUS_LEVEL
,
"[property syn] deviceCode(%s).
\n
"
,
deviceCode
);
if
(
kk_map_dev_search_by_deviceCode
(
deviceCode
,
&
dev
)
==
0
){
return
kk_lan_property_convert
(
deviceCode
,
dev
,
properties
);
}
else
{
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] not find deviceCode(%s).
\n
"
,
deviceCode
);
return
-
1
;
}
return
0
;
}
//添加场景通知
void
kk_lan_add_scene_notify
(
const
char
*
scene_id
)
{
debug_log
(
LOG_FOCUS_LEVEL
,
"[notify] add scene(%s).
\n
"
,
scene_id
);
kk_handle_sync_info
();
}
//删除场景通知
void
kk_lan_delete_scene_notify
(
const
char
*
scene_id
)
{
debug_log
(
LOG_FOCUS_LEVEL
,
"[notify] delete scene(%s).
\n
"
,
scene_id
);
cJSON
*
msg
=
old_ccu_msg_build
(
scene_id
,
"DELETE_SCENE"
,
SUCCESS_STR
,
WILDCARD_CHARACTER_STR
);
send_msg_to_module
(
msg
);
cJSON_Delete
(
msg
);
kk_handle_sync_info
();
}
//布防撤防状态通知(0-离家布防、1-撤防、2-在家布防、3-区域布防)
int
kk_lan_arming_status_notify
(
int
type
)
{
cJSON
*
msg
=
NULL
;
debug_log
(
LOG_FOCUS_LEVEL
,
"[notify] arming status(%d).
\n
"
,
type
);
if
(
type
==
0
){
msg
=
old_ccu_msg_build
(
WILDCARD_CHARACTER_STR
,
GUARD_STATUS_ARMING_LEAVE_HOME
,
SUCCESS_STR
,
WILDCARD_CHARACTER_STR
);
}
else
if
(
type
==
1
){
msg
=
old_ccu_msg_build
(
WILDCARD_CHARACTER_STR
,
GUARD_STATUS_DISARMING
,
SUCCESS_STR
,
WILDCARD_CHARACTER_STR
);
}
else
if
(
type
==
2
){
msg
=
old_ccu_msg_build
(
WILDCARD_CHARACTER_STR
,
GUARD_STATUS_ARMING_IN_HOME
,
SUCCESS_STR
,
WILDCARD_CHARACTER_STR
);
}
else
if
(
type
==
3
){
msg
=
old_ccu_msg_build
(
WILDCARD_CHARACTER_STR
,
ARMING_STATUS_GUARD_ZONE
,
SUCCESS_STR
,
WILDCARD_CHARACTER_STR
);
}
else
{
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] unknow type(%d).
\n
"
,
type
);
return
-
1
;
}
send_msg_to_module
(
msg
);
cJSON_Delete
(
msg
);
return
0
;
}
static
int
_kk_lan_delete_node
(
const
char
*
deviceCode
,
const
char
*
nodeid
)
{
cJSON
*
msg
;
cJSON
*
arg
;
char
mac
[
32
]
=
{
0
};
kk_map_dev_node_t
*
dev
;
if
(
deviceCode
==
NULL
||
nodeid
==
NULL
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] params.
\n
"
);
return
-
1
;
}
debug_log
(
LOG_FOCUS_LEVEL
,
"[del dev node] id(%s).
\n
"
,
nodeid
);
arg
=
cJSON_CreateObject
();
_deviceCode_switchto_mac
(
deviceCode
,
mac
);
cJSON_AddStringToObject
(
arg
,
"mac"
,
mac
);
msg
=
old_ccu_msg_build_json
(
nodeid
,
"DEL_DEVICE"
,
NULL
,
arg
);
send_msg_to_module
(
msg
);
cJSON_Delete
(
msg
);
return
0
;
}
static
int
_kk_lan_delete_device
(
const
char
*
deviceCode
)
{
#define MAX_CHANNEL_NUM 32
int
list
[
MAX_CHANNEL_NUM
]
=
{
0
};
int
i
,
num
=
0
;
char
nodeId
[
33
]
=
{
0
};
num
=
kk_lan_db_node_get_all
(
deviceCode
,
list
);
debug_log
(
LOG_FOCUS_LEVEL
,
"[del dev] deviceCode(%s)/node num(%d).
\n
"
,
deviceCode
,
num
);
for
(
i
=
0
;
i
<
num
;
i
++
){
memset
(
nodeId
,
0
,
sizeof
(
nodeId
));
snprintf
(
nodeId
,
sizeof
(
nodeId
),
"%d"
,
list
[
i
]);
_kk_lan_delete_node
(
deviceCode
,
nodeId
);
}
//删除数据库
kk_lan_db_node_delete
(
deviceCode
);
if
(
num
){
kk_handle_sync_info
();
}
return
0
;
}
int
kk_lan_device_delete_notify
(
cJSON
*
payload
)
{
cJSON
*
params
=
NULL
;
cJSON
*
deviceCode
=
NULL
;
if
((
params
=
cJSON_GetObjectItem
(
payload
,
"params"
))
==
NULL
||
params
->
type
!=
cJSON_Object
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] params.
\n
"
);
return
-
1
;
}
if
((
deviceCode
=
cJSON_GetObjectItem
(
params
,
"deviceCode"
))
==
NULL
||
deviceCode
->
type
!=
cJSON_String
){
debug_log
(
LOG_DEBUG_LEVEL
,
"[err] deviceCode.
\n
"
);
return
-
1
;
}
_kk_lan_delete_device
(
deviceCode
->
valuestring
);
return
0
;
}
void
device_add_sync
(
cJSON
*
payload
)
{
//NEW_DEVICES
printf
(
"[%s][%d]
\n
"
,
__FUNCTION__
,
__LINE__
);
kk_handle_sync_info
();
}
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