Commit ca00cdd3 authored by YannGarcia's avatar YannGarcia
Browse files

Bug fixed in script 40-ttf_t012.sh

parent 4b434a8b
......@@ -475,17 +475,29 @@ int json_codec::decode (const OCTETSTRING& p_data, LibItsHttp__JsonMessageBodyTy
msg.provChgPc5Notification() = prov_chg_pc5_notification;
} else if (it->second.find("\"AssocStaSubscription\"") != std::string::npos) {
WlanInformationAPI__TypesAndValues::AssocStaSubscription assoc_sta_subscription;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
assoc_sta_subscription.decode(WlanInformationAPI__TypesAndValues::AssocStaSubscription_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.assocStaSubscription() = assoc_sta_subscription;
if (it->second.find("\"subscription\"") != std::string::npos) { // SubscriptionLinkList
WlanInformationAPI__TypesAndValues::SubscriptionLinkList subscription_link_list;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
subscription_link_list.decode(WlanInformationAPI__TypesAndValues::SubscriptionLinkList_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.subscriptionLinkList__wlan() = subscription_link_list;
} else { // AssocStaSubscription
WlanInformationAPI__TypesAndValues::AssocStaSubscription assoc_sta_subscription;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
assoc_sta_subscription.decode(WlanInformationAPI__TypesAndValues::AssocStaSubscription_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.assocStaSubscription() = assoc_sta_subscription;
}
} else if (it->second.find("\"StaDataRateSubscription\"") != std::string::npos) {
WlanInformationAPI__TypesAndValues::StaDataRateSubscription sta_data_rate_subscription;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
sta_data_rate_subscription.decode(WlanInformationAPI__TypesAndValues::StaDataRateSubscription_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.staDataRateSubscription() = sta_data_rate_subscription;
} else if ((it->second.find("\"_links\"") != std::string::npos) && (it->second.find("subscriptions") != std::string::npos)) { // SubscriptionLinkList
// decode_str: {"_links":{"self":{"href":"https://try-mec.etsi.org/sbxpb4c4k2/wai/v2/subscriptions"}}}
WlanInformationAPI__TypesAndValues::SubscriptionLinkList subscription_link_list;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
subscription_link_list.decode(WlanInformationAPI__TypesAndValues::SubscriptionLinkList_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.subscriptionLinkList__wlan() = subscription_link_list;
} else if ((it->second.find("\"apInfo\"") != std::string::npos) || (it->second.find("\"apId\"") != std::string::npos)) {
WlanInformationAPI__TypesAndValues::ApInfoList ap_info_list;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
......@@ -497,6 +509,11 @@ int json_codec::decode (const OCTETSTRING& p_data, LibItsHttp__JsonMessageBodyTy
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
sta_info_list.decode(WlanInformationAPI__TypesAndValues::StaInfoList_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.staInfoList() = sta_info_list;
} else if (it->second.find("\"AssocStaNotification\"") != std::string::npos) {
WlanInformationAPI__TypesAndValues::AssocStaNotification assoc_sta_notification;
TTCN_Buffer decoding_buffer_(OCTETSTRING(str.length(), (const unsigned char*)str.c_str()));
assoc_sta_notification.decode(WlanInformationAPI__TypesAndValues::AssocStaNotification_descr_, decoding_buffer_, TTCN_EncDec::CT_JSON);
msg.assocStaNotification() = assoc_sta_notification;
......
......@@ -78,10 +78,10 @@ tcp_layer::tcp_layer(const std::string & p_type, const std::string & param) : la
if (server_mode) {
parameter_set("serverPort", _params[params::local_port].c_str());
if (ssl_mode) { // Add certificate bundle
parameter_set(ssl_verifycertificate_name(), "no");
parameter_set(ssl_verifycertificate_name(), "yes");
parameter_set(ssl_private_key_file_name(), "../certificates/out/privates/486c4cb43fcbcdb5f564824ad201cffb405f3d3659fc1facd5f5cb21d4ea64e0_server_rsa.key.pem");
parameter_set(ssl_certificate_file_name(), "../certificates/out/certs/486c4cb43fcbcdb5f564824ad201cffb405f3d3659fc1facd5f5cb21d4ea64e0_server_rsa.cert.pem");
parameter_set(ssl_trustedCAlist_file_name(), "../certificates/out/certs/486c4cb43fcbcdb5f564824ad201cffb405f3d3659fc1facd5f5cb21d4ea64e0_server_rsa.cert.pem"); // FIXME Use a parameter
parameter_set(ssl_trustedCAlist_file_name(), "../certificates/out/certs/CA_rsa.cert.pem"); // FIXME Use a parameter
}
}
set_ttcn_buffer_usercontrol(false);
......
......@@ -31,3 +31,9 @@ make
echo -e "*****************************\n* Init Eclipse Workspace\n*****************************\n"
echo -e "*****************************\n* Change sudo in command line\n*****************************\n"
cd /home/etsi/dev/ETSI_Ng112/scripts
sed --in-place 's/sudo/echo "etsi" \| sudo -S/' ./run_mtc.bash
sed --in-place 's/sudo/echo "etsi" \| sudo -S/' ./run_ptcs.bash
cd /home/etsi/dev/TTF_T012_Mec
......@@ -14,7 +14,7 @@ LibItsHttp_Pics.PICS_HEADER_CONTENT_TYPE := "application/json"
LibItsHttp_Pics.PICS_USE_TOKEN_HEADER := true
#LibItsHttp_Pics.PICS_TOKEN_HEADER := "Basic WrongToken"
LibMec_Pics.PICS_ROOT_API := "/sbxj2byamx" # Need to sign in on https://try-mec.etsi.org/, section 'Try-it from your MEC application'
LibMec_Pics.PICS_ROOT_API := "/sbxpl1eil4" # Need to sign in on https://try-mec.etsi.org/, section 'Try-it from your MEC application'
# LibMec_Pixits
LibMec_Pixits.PX_ME_APP_Q_ZONE_ID_URI := "/location/v2/queries/zones"
......@@ -86,8 +86,8 @@ WlanInformationAPI_Pixits.PX_ASSOC_STA_SUBSCRIPTION_CALLBACK := "https://yanngar
LogFile := "../logs/AtsMec/%e.%h-%r.%s"
FileMask := LOG_ALL | USER | DEBUG | MATCHING
ConsoleMask := LOG_ALL | USER | DEBUG | MATCHING
#FileMask := ERROR | WARNING | USER | MATCHING | EXECUTOR_RUNTIME | VERDICTOP | PORTEVENT
#ConsoleMask := ERROR | WARNING | USER | MATCHING | EXECUTOR_RUNTIME | VERDICTOP | PORTEVENT
#FileMask := ERROR | WARNING | USER | MATCHING | EXECUTOR_RUNTIME | VERDICTOP | PORTEVENT | TESTCASE
#ConsoleMask := ERROR | WARNING | USER | MATCHING | EXECUTOR_RUNTIME | VERDICTOP | PORTEVENT | TESTCASE
LogSourceInfo := Stack
LogEntityName:= Yes
LogEventTypes:= Yes
......@@ -294,7 +294,7 @@ system.httpPort_notif.params := "HTTP(codecs=json:json_codec)/TCP(debug=1,server
# ETSI GS MEC 028
# Check that the IUT responds with the list of WLAN Access Point
#AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_001_OK
AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_001_OK
# Check that the IUT responds with the list of WLAN Access Point filtered by the macId provided as query parameter
#AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_002_OK
# Check that the IUT responds with an error when a request with incorrect parameters is sent by a MEC Application
......@@ -306,7 +306,7 @@ system.httpPort_notif.params := "HTTP(codecs=json:json_codec)/TCP(debug=1,server
# Check that the IUT responds with an error when a request with incorrect parameters is sent by a MEC Application
#AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_004_BR
# Check that the IUT responds with the requested list of subscription
AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_005_OK
#AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_005_OK
# Check that the IUT responds with the requested list of subscription
#AtsMec_WlanInformationAPI_TestCases.TC_MEC_MEC028_SRV_WAI_006_OK
# Check that the IUT responds with an error when a request with incorrect parameters is sent by a MEC Application
......
......@@ -184,7 +184,7 @@ module AtsMec_WlanInformationAPI_TestCases {
httpPort.send(
m_http_request(
m_http_request_get(
PICS_ROOT_API & PX_ME_WLAN_QUERIES_URI & "/apId/ap_information?filter=(eq," & PX_WLAN_FILTER_FIELD & "," & PX_WLAN_FILTER_VALUE & ")", // Invalid requery
PICS_ROOT_API & PX_ME_WLAN_QUERIES_URI & "/apId/ap_information?filter=(ee," & PX_WLAN_FILTER_FIELD & "," & PX_WLAN_FILTER_VALUE & ")", // Invalid requery
v_headers
)
)
......@@ -356,7 +356,7 @@ module AtsMec_WlanInformationAPI_TestCases {
httpPort.send(
m_http_request(
m_http_request_get(
PICS_ROOT_API & PX_ME_WLAN_QUERIES_URI & "/staId/sta_information?filter=(eq," & PX_WLAN_FILTER_FIELD & "," & PX_WLAN_FILTER_VALUE & ")", // Invalid requery
PICS_ROOT_API & PX_ME_WLAN_QUERIES_URI & "/staId/sta_information?filter=(ee," & PX_WLAN_FILTER_FIELD & "," & PX_WLAN_FILTER_VALUE & ")", // Invalid requery
v_headers
)
)
......@@ -447,127 +447,68 @@ module AtsMec_WlanInformationAPI_TestCases {
f_cf_01_http_down();
} // End of testcase TC_MEC_MEC028_SRV_WAI_005_OK
/**
* @desc Check that the IUT responds with the requested list of subscription
* @see https://forge.etsi.org/rep/mec/gs028-wai-api/blob/master/WlanInformationApi.json
* @see https://forge.etsi.org/rep/mec/gs032p2-test-purposes/blob/v2.2.1-dev/Test%20Purposes/MEC028/SRV/WAI/Subscription.tplan2
*/
testcase TC_MEC_MEC028_SRV_WAI_005_BR() runs on HttpComponent system HttpTestAdapter {
// Local variables
var AssocStaSubscription v_assoc_sta_subscription;
var Headers v_headers;
var HttpMessage v_response;
// Test control
if (not(PICS_MEC_PLAT) or not(PICS_WLAN_INFORMATION_API_SUPPORTED)) {
log("*** " & testcasename() & ": PICS_MEC_PLAT and PICS_WLAN_INFORMATION_API_SUPPORTED required for executing the TC ***");
setverdict(inconc);
stop;
}
// Test component configuration
f_cf_01_http_up();
// Test adapter configuration
// Preamble
f_create_assoc_sta_subscription(v_assoc_sta_subscription);
f_init_default_headers_list(-, -, v_headers);
httpPort.send(
m_http_request(
m_http_request_get(
PICS_ROOT_API & PX_ME_WLAN_URI & "/subscriptions",
v_headers
)
)
);
f_selfOrClientSyncAndVerdict(c_prDone, e_success);
// Test Body
tc_ac.start;
alt {
[] httpPort.receive(
mw_http_response(
mw_http_response_400_bad_request
)) -> value v_response {
tc_ac.stop;
log("*** " & testcasename() & ": PASS: IUT successfully responds with a correct error code ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
}
[] tc_ac.timeout {
log("*** " & testcasename() & ": INCONC: Expected message not received ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
}
} // End of 'alt' statement
// Postamble
f_delete_assoc_sta_subscription(v_assoc_sta_subscription);
f_cf_01_http_down();
} // End of testcase TC_MEC_MEC028_SRV_WAI_005_BR
/**
* @desc Check that the IUT responds with the requested list of subscription
* @see https://forge.etsi.org/rep/mec/gs028-wai-api/blob/master/WlanInformationApi.json
* @see https://forge.etsi.org/rep/mec/gs032p2-test-purposes/blob/v2.2.1-dev/Test%20Purposes/MEC028/SRV/WAI/Subscription.tplan2
*/
testcase TC_MEC_MEC028_SRV_WAI_006_OK() runs on HttpComponent system HttpTestAdapter {
// Local variables
// Local variables
var AssocStaSubscription v_assoc_sta_subscription;
var Headers v_headers;
var HttpMessage v_response;
// Test control
if (not(PICS_MEC_PLAT) or not(PICS_WLAN_INFORMATION_API_SUPPORTED)) {
log("*** " & testcasename() & ": PICS_MEC_PLAT and PICS_WLAN_INFORMATION_API_SUPPORTED required for executing the TC ***");
setverdict(inconc);
stop;
}
// Test component configuration
f_cf_01_http_up();
// Test adapter configuration
// Preamble
f_create_assoc_sta_subscription(v_assoc_sta_subscription);
f_init_default_headers_list(-, -, v_headers);
httpPort.send(
m_http_request(
m_http_request_get(
PICS_ROOT_API & PX_ME_WLAN_URI & "/subscriptions/assoc_sta",
v_headers
)
)
);
f_selfOrClientSyncAndVerdict(c_prDone, e_success);
// Test Body
tc_ac.start;
alt {
[] httpPort.receive(
mw_http_response(
mw_http_response_ok(
mw_http_message_body_json(
mw_body_json_wlan_subscription_link_list(
mw_subscription_link_list(
-,
?
)))))) -> value v_response {
tc_ac.stop;
var Headers v_headers;
var HttpMessage v_response;
// Test control
if (not(PICS_MEC_PLAT) or not(PICS_WLAN_INFORMATION_API_SUPPORTED)) {
log("*** " & testcasename() & ": PICS_MEC_PLAT and PICS_WLAN_INFORMATION_API_SUPPORTED required for executing the TC ***");
setverdict(inconc);
stop;
}
// Test component configuration
f_cf_01_http_up();
// Test adapter configuration
// Preamble
f_create_assoc_sta_subscription(v_assoc_sta_subscription);
f_init_default_headers_list(-, -, v_headers);
httpPort.send(
m_http_request(
m_http_request_get(
PICS_ROOT_API & PX_ME_WLAN_URI & "/subscriptions?subscription_type=assoc_sta",
v_headers
)
)
);
f_selfOrClientSyncAndVerdict(c_prDone, e_success);
// Test Body
tc_ac.start;
alt {
[] httpPort.receive(
mw_http_response(
mw_http_response_ok(
mw_http_message_body_json(
mw_body_json_wlan_subscription_link_list(
mw_subscription_link_list(
-,
?
)))))) -> value v_response {
tc_ac.stop;
log("*** " & testcasename() & ": PASS: IUT successfully responds with a list of AssocStaSubscription ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
}
[] tc_ac.timeout {
log("*** " & testcasename() & ": INCONC: Expected message not received ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
}
} // End of 'alt' statement
// Postamble
f_delete_assoc_sta_subscription(v_assoc_sta_subscription);
f_cf_01_http_down();
log("*** " & testcasename() & ": PASS: IUT successfully responds with a list of AssocStaSubscription ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_success);
}
[] tc_ac.timeout {
log("*** " & testcasename() & ": INCONC: Expected message not received ***");
f_selfOrClientSyncAndVerdict(c_tbDone, e_timeout);
}
} // End of 'alt' statement
// Postamble
f_delete_assoc_sta_subscription(v_assoc_sta_subscription);
f_cf_01_http_down();
} // End of testcase TC_MEC_MEC028_SRV_WAI_006_OK
/**
......@@ -683,6 +624,15 @@ module AtsMec_WlanInformationAPI_TestCases {
f_cf_01_http_down();
} // End of testcase TC_MEC_MEC028_SRV_WAI_006_NF
/***
var charstring v_uri;
v_uri := regexp(
oct2char(unichar2oct(v_assoc_sta_subscription.links.self_.href)),
"?+(" & PX_ME_WLAN_URI & "?*)",
0
);
***/
/**
* @desc Check that the IUT responds with the list of Station Point filtered by the macId provided as query parameter
* @see https://forge.etsi.org/rep/mec/gs028-wai-api/blob/master/WlanInformationApi.json
......@@ -718,7 +668,13 @@ module AtsMec_WlanInformationAPI_TestCases {
PX_ASSOC_STA_SUBSCRIPTION_CALLBACK,
m_ap_identity(
PX_MAC_ID
)))))));
),
-, -, -,
10, // notificationPeriod - Table 6.3.2-1: Attributes of the AssocStaSubscription Note 2
-,
m_time_stamp(
f_get_current_timestamp_utc() / 1000 + 30 // Expiry time: T + 30 seconds
)))))));
f_selfOrClientSyncAndVerdict(c_prDone, e_success);
// Test Body
......@@ -726,14 +682,14 @@ module AtsMec_WlanInformationAPI_TestCases {
alt {
[] httpPort.receive(
mw_http_response(
mw_http_response_ok(
mw_http_message_body_json(
mw_body_json_assoc_sta_subscription(
mw_assoc_sta_subscription(
PX_ASSOC_STA_SUBSCRIPTION_CALLBACK,
-, -, -,
?
)))))) -> value v_response {
mw_http_response_201_created(
mw_http_message_body_json(
mw_body_json_assoc_sta_subscription(
mw_assoc_sta_subscription(
PX_ASSOC_STA_SUBSCRIPTION_CALLBACK,
-, -, -,
?
)))))) -> value v_response {
tc_ac.stop;
log("*** " & testcasename() & ": PASS: IUT successfully responds to the subscription ***");
......
......@@ -55,7 +55,13 @@ module WlanInformationAPI_Functions {
PX_ASSOC_STA_SUBSCRIPTION_CALLBACK,
m_ap_identity(
PX_MAC_ID
)))))));
),
-, -, -,
10, // notificationPeriod - Table 6.3.2-1: Attributes of the AssocStaSubscription Note 2
-,
m_time_stamp(
f_get_current_timestamp_utc() / 1000 + 30 // Expiry time: T + 30 seconds
)))))));
tc_ac.start;
alt {
......@@ -91,7 +97,6 @@ module WlanInformationAPI_Functions {
"?+(" & PX_ME_WLAN_URI & "?*)",
0
);
log("====> v_uri: ", v_uri);
f_init_default_headers_list(-, -, v_headers);
httpPort.send(
......
......@@ -10,6 +10,22 @@ module WlanInformationAPI_Templates {
import from WlanInformationAPI_TypesAndValues all;
import from WlanInformationAPI_Pixits all;
template (value) TimeStamp m_time_stamp(
in Seconds p_seconds,
in NanoSeconds p_nanoSeconds := 0
) := {
seconds := p_seconds,
nanoSeconds := p_nanoSeconds
} // End of template m_time_stamp
template (present) TimeStamp mw_time_stamp(
template (present) Seconds p_seconds := ?,
template (present) NanoSeconds p_nanoSeconds := ?
) := {
seconds := p_seconds,
nanoSeconds := p_nanoSeconds
} // End of template mw_time_stamp
template (omit) ApInfo m_ap_info(
in template (value) ApIdentity p_apId,
in template (omit) UInt32 p_channel := omit,
......@@ -269,21 +285,21 @@ module WlanInformationAPI_Templates {
} // End of template mw_subscription_link_list
template (omit) ApIdentity m_ap_identity(
in JSON.String p_macId,
in JSON.String p_bssid,
in template (omit) SsidList p_ssid := omit,
in template (omit) IpAddressList p_ipAddress := omit
) := {
macId := p_macId,
bssid := p_bssid,
ssid := p_ssid,
ipAddress := p_ipAddress
} // End of template m_ap_identity
template (present) ApIdentity mw_ap_identity(
template (present) JSON.String p_macId := ?,
template (present) JSON.String p_bssid := ?,
template SsidList p_ssid := *,
template IpAddressList p_ipAddress := *
) := {
macId := p_macId,
bssid := p_bssid,
ssid := p_ssid,
ipAddress := p_ipAddress
} // End of template mw_ap_identity
......
......@@ -37,18 +37,17 @@ module WlanInformationAPI_TypesAndValues {
NanoSeconds nanoSeconds
}
type record of JSON.String SsidList;
type record of JSON.String IpAddressList;
/**
* @desc Identifiers determining a specific Access Point
* @member macId Unique Identifier assigned to an Access Point
* @member bssid Basic Service Set Identifier (BSSID) is a unique Identifier assigned to an Access Point (as network interface controller) for communications at the data link layer of a network segment
* @member ssid Service Set Identifier to identify logical networks including Basic Service Set and Extended Service Set
* @member ipAddress IPv4 or IPv6 address allocated for the Access Point
* @see ETSI GS MEC 028 Clause 6.5.3 Type: ApIdentity
*/
type record ApIdentity {
JSON.String macId,
JSON.String bssid,
SsidList ssid optional,
IpAddressList ipAddress optional
}
......@@ -346,14 +345,14 @@ module WlanInformationAPI_TypesAndValues {
/**
* @desc Information for the Access Point that the client station is associated to
* @member macId Unique identifier assigned to the Access Point (as network interface controller) for communications at the data link layer of a network segment
* @member bssid Basic Service Set Identifier (BSSID) is a unique identifier assigned to the Access Point (as network interface controller) for communications at the data link layer of a network segment.
* @member ssid Service Set Identifier to identify logical networks
* @member assocId Unique number which identifies a particular association between the station and Access Point
* @member ipAddress IPv4 or IPv6 address allocated for the Access Point
* @see ETSI GS MEC 028 Clause 6.5.12 Type: ApAssociated
*/
type record ApAssociated {
JSON.String macId,
JSON.String bssid,
JSON.String ssid optional,
JSON.String assocId optional,
JSON.String ipAddress optional
......@@ -412,7 +411,7 @@ module WlanInformationAPI_TypesAndValues {
* @see ETSI GS MEC 028 Clause 6.5.39 Type: ChannelLoad
*/
type record ChannelLoadItem {
StaIdentity staId optional,
StaIdentity staId optional,
JSON.String measurementId,
UInt8 operatingClass,
UInt8 channel,
......@@ -793,7 +792,7 @@ module WlanInformationAPI_TypesAndValues {
*/
type record AssocStaSubscription {
JSON.String subscriptionType,
JSON.AnyURI callbackReference,
JSON.AnyURI callbackReference optional,
JSON.Bool requestTestNotification optional,
WebsockNotifConfig websockNotifConfig optional,
LinkTypes links optional,
......
......@@ -139,6 +139,7 @@ module LibItsHttp_JsonMessageBodyTypes {
StaInfoList staInfoList,
AssocStaSubscription assocStaSubscription,
StaDataRateSubscription staDataRateSubscription,
AssocStaNotification assocStaNotification,
WlanInformationAPI_TypesAndValues.SubscriptionLinkList subscriptionLinkList_wlan,
MeasurementConfigLinkList measurementConfigLinkList,
MeasurementConfig measurementConfig,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment