Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
OpenXG-RAN
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
lizhongxiao
OpenXG-RAN
Commits
633551db
Commit
633551db
authored
Jun 18, 2019
by
Raphael Defosseux
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CI: a few cosmetics fixes on python
Signed-off-by:
Raphael Defosseux
<
raphael.defosseux@eurecom.fr
>
parent
08e91003
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
43 additions
and
47 deletions
+43
-47
ci-scripts/main.py
ci-scripts/main.py
+43
-47
No files found.
ci-scripts/main.py
View file @
633551db
# dummy commit
#/*
# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
# * contributor license agreements. See the NOTICE file distributed with
...
...
@@ -599,6 +598,10 @@ class SSHConnection():
if
self
.
UEIPAddress
==
''
or
self
.
UEUserName
==
''
or
self
.
UEPassword
==
''
or
self
.
UESourceCodePath
==
''
:
Usage
()
sys
.
exit
(
'Insufficient Parameter'
)
if
self
.
air_interface
==
'lte'
:
UE_prefix
=
''
else
:
UE_prefix
=
'NR '
#initialize_OAI_UE_flag = True
#pStatus = self.CheckOAIUEProcessExist(initialize_OAI_UE_flag)
#if (pStatus < 0):
...
...
@@ -608,7 +611,7 @@ class SSHConnection():
self
.
open
(
self
.
UEIPAddress
,
self
.
UEUserName
,
self
.
UEPassword
)
# b2xx_fx3_utils reset procedure
self
.
command
(
'echo '
+
self
.
UEPassword
+
' | sudo -S uhd_find_devices'
,
'\$'
,
30
)
result
=
re
.
search
(
'type:
n3xx
'
,
str
(
self
.
ssh
.
before
))
result
=
re
.
search
(
'type:
b200
'
,
str
(
self
.
ssh
.
before
))
if
result
is
not
None
:
pass
logging
.
debug
(
'Found a B2xx device --> resetting it'
)
...
...
@@ -624,10 +627,6 @@ class SSHConnection():
self
.
command
(
'echo "ulimit -c unlimited && ./'
+
self
.
air_interface
+
'-uesoftmodem '
+
self
.
Initialize_OAI_UE_args
+
'" > ./my-lte-uesoftmodem-run'
+
str
(
self
.
UE_instance
)
+
'.sh'
,
'\$'
,
5
)
self
.
command
(
'chmod 775 ./my-lte-uesoftmodem-run'
+
str
(
self
.
UE_instance
)
+
'.sh'
,
'\$'
,
5
)
self
.
command
(
'echo '
+
self
.
UEPassword
+
' | sudo -S rm -Rf '
+
self
.
UESourceCodePath
+
'/cmake_targets/ue_'
+
self
.
testCase_id
+
'.log'
,
'\$'
,
5
)
#to use daemon on CentOS we need to source the function
#linux_distro = platform.linux_distribution()[0]
#if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE):
#self.command('source /etc/init.d/functions', '\$', 5)
#use nohup instead of daemon
self
.
command
(
'echo $USER; nohup sudo ./my-lte-uesoftmodem-run'
+
str
(
self
.
UE_instance
)
+
'.sh'
+
' > '
+
self
.
UESourceCodePath
+
'/cmake_targets/ue_'
+
self
.
testCase_id
+
'.log '
+
' 2>&1 &'
,
self
.
UEUserName
,
5
)
#self.command('echo ' + self.UEPassword + ' | sudo -S -E daemon --inherit --unsafe --name=ue' + str(self.UE_instance) + '_daemon --chdir=' + self.UESourceCodePath + '/cmake_targets/ran_build/build -o ' + self.UESourceCodePath + '/cmake_targets/ue_' + self.testCase_id + '.log ./my-lte-uesoftmodem-run' + str(self.UE_instance) + '.sh', '\$', 5)
...
...
@@ -641,7 +640,7 @@ class SSHConnection():
if
(
loopCounter
==
0
):
self
.
close
()
doLoop
=
False
logging
.
error
(
'
\u001B
[1;37;41m UE logging system did not show got sync!
\u001B
[0m'
)
logging
.
error
(
'
\u001B
[1;37;41m
'
+
UE_prefix
+
'
UE logging system did not show got sync!
\u001B
[0m'
)
self
.
CreateHtmlTestRow
(
self
.
Initialize_OAI_UE_args
,
'KO'
,
ALL_PROCESSES_OK
,
'OAI UE'
)
self
.
CreateHtmlTabFooter
(
False
)
sys
.
exit
(
1
)
...
...
@@ -656,7 +655,7 @@ class SSHConnection():
else
:
doLoop
=
False
self
.
CreateHtmlTestRow
(
self
.
Initialize_OAI_UE_args
,
'OK'
,
ALL_PROCESSES_OK
,
'OAI UE'
)
logging
.
debug
(
'
\u001B
[1m Initialize OAI UE Completed
\u001B
[0m'
)
logging
.
debug
(
'
\u001B
[1m Initialize OAI
'
+
UE_prefix
+
'
UE Completed
\u001B
[0m'
)
self
.
close
()
def
InitializeOAIeNB
(
self
):
...
...
@@ -671,6 +670,10 @@ class SSHConnection():
# sys.exit(1)
self
.
open
(
self
.
eNBIPAddress
,
self
.
eNBUserName
,
self
.
eNBPassword
)
self
.
command
(
'cd '
+
self
.
eNBSourceCodePath
,
'\$'
,
5
)
if
self
.
air_interface
==
'lte'
:
nodeB_prefix
=
'e'
else
:
nodeB_prefix
=
'g'
# Initialize_OAI_eNB_args usually start with -C and followed by the location in repository
#full_config_file = self.Initialize_OAI_eNB_args.replace('-O ','')
#extIdx = full_config_file.find('.conf')
...
...
@@ -702,10 +705,6 @@ class SSHConnection():
self
.
command
(
'echo "ulimit -c unlimited && ./'
+
self
.
air_interface
+
'-softmodem '
+
self
.
Initialize_OAI_eNB_args
+
'|& tee '
+
self
.
eNBSourceCodePath
+
'/cmake_targets/'
+
self
.
eNBLogFile
+
'" > ./my-lte-softmodem-run'
+
str
(
self
.
eNB_instance
)
+
'.sh'
,
'\$'
,
5
)
self
.
command
(
'chmod 775 ./my-lte-softmodem-run'
+
str
(
self
.
eNB_instance
)
+
'.sh'
,
'\$'
,
5
)
self
.
command
(
'echo '
+
self
.
eNBPassword
+
' | sudo -S rm -Rf '
+
self
.
eNBSourceCodePath
+
'/cmake_targets/enb_'
+
self
.
testCase_id
+
'.log'
,
'\$'
,
5
)
#to use daemon on CentOS we need to source the function
#linux_distro = platform.linux_distribution()[0]
#if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE):
#self.command('source /etc/init.d/functions', '\$', 5)
#use nohup instead of daemon
self
.
command
(
'echo $USER; nohup sudo ./my-lte-softmodem-run'
+
str
(
self
.
eNB_instance
)
+
'.sh'
+
' > '
+
self
.
eNBSourceCodePath
+
'/cmake_targets/enb_'
+
self
.
testCase_id
+
'.log'
+
' 2>&1 &'
,
self
.
eNBUserName
,
5
)
#self.command('echo ' + self.eNBPassword + ' | sudo -S -E daemon --inherit --unsafe --name=enb' + str(self.eNB_instance) + '_daemon --chdir=' + self.eNBSourceCodePath + '/cmake_targets/ran_build/build -o ' + self.eNBSourceCodePath + '/cmake_targets/enb_' + self.testCase_id + '.log ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5)
...
...
@@ -713,7 +712,6 @@ class SSHConnection():
self
.
command
(
'cd ../..'
,
'\$'
,
5
)
doLoop
=
True
loopCounter
=
10
print
(
'gNB log file: '
+
self
.
eNBLogFile
)
while
(
doLoop
):
loopCounter
=
loopCounter
-
1
if
(
loopCounter
==
0
):
...
...
@@ -723,7 +721,7 @@ class SSHConnection():
# self.command('killall --signal SIGKILL record', '\$', 5)
self
.
close
()
doLoop
=
False
logging
.
error
(
'
\u001B
[1;37;41m
e
NB logging system did not show got sync!
\u001B
[0m'
)
logging
.
error
(
'
\u001B
[1;37;41m
'
+
nodeB_prefix
+
'
NB logging system did not show got sync!
\u001B
[0m'
)
self
.
CreateHtmlTestRow
(
self
.
Initialize_OAI_eNB_args
,
'KO'
,
ALL_PROCESSES_OK
,
'OAI eNB'
)
self
.
CreateHtmlTabFooter
(
False
)
## In case of T tracer recording, we need to kill tshark on EPC side
...
...
@@ -740,18 +738,14 @@ class SSHConnection():
# self.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, pcap_log_file, self.eNBSourceCodePath + '/cmake_targets/.')
sys
.
exit
(
1
)
else
:
#print('current directory: ' + os.getcwd())
#self.command('pwd', '\$', 4)
#print('self.command pwd: ' + str(self.ssh.before))
self
.
command
(
'stdbuf -o0 cat '
+
self
.
eNBLogFile
+
' | egrep --text --color=never -i "wait|sync"'
,
'\$'
,
30
)
#print(self.ssh.before)
result
=
re
.
search
(
'got sync'
,
str
(
self
.
ssh
.
before
))
if
result
is
None
:
time
.
sleep
(
11
)
else
:
doLoop
=
False
self
.
CreateHtmlTestRow
(
self
.
Initialize_OAI_eNB_args
,
'OK'
,
ALL_PROCESSES_OK
,
'OAI eNB'
)
logging
.
debug
(
'
\u001B
[1m Initialize OAI
e
NB Completed
\u001B
[0m'
)
logging
.
debug
(
'
\u001B
[1m Initialize OAI
'
+
nodeB_prefix
+
'
NB Completed
\u001B
[0m'
)
self
.
close
()
def
checkDevTTYisUnlocked
(
self
):
...
...
@@ -2091,38 +2085,42 @@ class SSHConnection():
rachCanceledProcedure
+=
1
enb_log_file
.
close
()
self
.
htmleNBFailureMsg
=
''
if
self
.
air_interface
==
'lte'
:
nodeB_prefix
=
'e'
else
:
nodeB_prefix
=
'g'
if
uciStatMsgCount
>
0
:
statMsg
=
'e
NB showed '
+
str
(
uciStatMsgCount
)
+
' "uci->stat" message(s)'
statMsg
=
nodeB_prefix
+
'
NB showed '
+
str
(
uciStatMsgCount
)
+
' "uci->stat" message(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
statMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
statMsg
+
'
\n
'
if
pdcpFailure
>
0
:
statMsg
=
'e
NB showed '
+
str
(
pdcpFailure
)
+
' "PDCP Out of Resources" message(s)'
statMsg
=
nodeB_prefix
+
'
NB showed '
+
str
(
pdcpFailure
)
+
' "PDCP Out of Resources" message(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
statMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
statMsg
+
'
\n
'
if
ulschFailure
>
0
:
statMsg
=
'e
NB showed '
+
str
(
ulschFailure
)
+
' "ULSCH in error in round" message(s)'
statMsg
=
nodeB_prefix
+
'
NB showed '
+
str
(
ulschFailure
)
+
' "ULSCH in error in round" message(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
statMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
statMsg
+
'
\n
'
if
rrcSetupRequest
>
0
or
rrcSetupComplete
>
0
:
rrcMsg
=
'e
NB requested '
+
str
(
rrcSetupRequest
)
+
' RRC Connection Setup(s)'
rrcMsg
=
nodeB_prefix
+
'
NB requested '
+
str
(
rrcSetupRequest
)
+
' RRC Connection Setup(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
rrcMsg
=
' -- '
+
str
(
rrcSetupComplete
)
+
' were completed'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
if
rrcReleaseRequest
>
0
:
rrcMsg
=
'e
NB requested '
+
str
(
rrcReleaseRequest
)
+
' RRC Connection Release(s)'
rrcMsg
=
nodeB_prefix
+
'
NB requested '
+
str
(
rrcReleaseRequest
)
+
' RRC Connection Release(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
if
rrcReconfigRequest
>
0
or
rrcReconfigComplete
>
0
:
rrcMsg
=
'e
NB requested '
+
str
(
rrcReconfigRequest
)
+
' RRC Connection Reconfiguration(s)'
rrcMsg
=
nodeB_prefix
+
'
NB requested '
+
str
(
rrcReconfigRequest
)
+
' RRC Connection Reconfiguration(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
rrcMsg
=
' -- '
+
str
(
rrcReconfigComplete
)
+
' were completed'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
if
rrcReestablishRequest
>
0
or
rrcReestablishComplete
>
0
or
rrcReestablishReject
>
0
:
rrcMsg
=
'e
NB requested '
+
str
(
rrcReestablishRequest
)
+
' RRC Connection Reestablishment(s)'
rrcMsg
=
nodeB_prefix
+
'
NB requested '
+
str
(
rrcReestablishRequest
)
+
' RRC Connection Reestablishment(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
rrcMsg
=
' -- '
+
str
(
rrcReestablishComplete
)
+
' were completed'
...
...
@@ -2132,22 +2130,22 @@ class SSHConnection():
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rrcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rrcMsg
+
'
\n
'
if
rachCanceledProcedure
>
0
:
rachMsg
=
'e
NB cancelled '
+
str
(
rachCanceledProcedure
)
+
' RA procedure(s)'
rachMsg
=
nodeB_prefix
+
'
NB cancelled '
+
str
(
rachCanceledProcedure
)
+
' RA procedure(s)'
logging
.
debug
(
'
\u001B
[1;30;43m '
+
rachMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rachMsg
+
'
\n
'
if
foundSegFault
:
logging
.
debug
(
'
\u001B
[1;37;41m
e
NB ended with a Segmentation Fault!
\u001B
[0m'
)
logging
.
debug
(
'
\u001B
[1;37;41m
'
+
nodeB_prefix
+
'
NB ended with a Segmentation Fault!
\u001B
[0m'
)
return
ENB_PROCESS_SEG_FAULT
if
foundAssertion
:
logging
.
debug
(
'
\u001B
[1;37;41m
e
NB ended with an assertion!
\u001B
[0m'
)
logging
.
debug
(
'
\u001B
[1;37;41m
'
+
nodeB_prefix
+
'
NB ended with an assertion!
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
msgAssertion
return
ENB_PROCESS_ASSERTION
if
foundRealTimeIssue
:
logging
.
debug
(
'
\u001B
[1;37;41m
e
NB faced real time issues!
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
'e
NB faced real time issues!
\n
'
logging
.
debug
(
'
\u001B
[1;37;41m
'
+
nodeB_prefix
+
'
NB faced real time issues!
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
nodeB_prefix
+
'
NB faced real time issues!
\n
'
#return ENB_PROCESS_REALTIME_ISSUE
if
rlcDiscardBuffer
>
0
:
rlcMsg
=
'e
NB RLC discarded '
+
str
(
rlcDiscardBuffer
)
+
' buffer(s)'
rlcMsg
=
nodeB_prefix
+
'
NB RLC discarded '
+
str
(
rlcDiscardBuffer
)
+
' buffer(s)'
logging
.
debug
(
'
\u001B
[1;37;41m '
+
rlcMsg
+
'
\u001B
[0m'
)
self
.
htmleNBFailureMsg
+=
rlcMsg
+
'
\n
'
return
ENB_PROCESS_REALTIME_ISSUE
...
...
@@ -2306,10 +2304,10 @@ class SSHConnection():
def
TerminateeNB
(
self
):
self
.
open
(
self
.
eNBIPAddress
,
self
.
eNBUserName
,
self
.
eNBPassword
)
self
.
command
(
'cd '
+
self
.
eNBSourceCodePath
+
'/cmake_targets'
,
'\$'
,
5
)
#to use daemon on CentOS we need to source the function
#linux_distro = platform.linux_distribution()[0]
#if re.match('(.*)CentOS(.*)', linux_distro, re.IGNORECASE)
:
#self.command('source /etc/init.d/functions', '\$', 5)
if
self
.
air_interface
==
'lte'
:
nodeB_prefix
=
'e'
else
:
nodeB_prefix
=
'g'
#use nohup instead of daemon
self
.
command
(
'echo '
+
self
.
eNBPassword
+
' | sudo -S daemon --name=enb'
+
str
(
self
.
eNB_instance
)
+
'_daemon --stop'
,
'\$'
,
5
)
self
.
command
(
'rm -f my-lte-softmodem-run'
+
str
(
self
.
eNB_instance
)
+
'.sh'
,
'\$'
,
5
)
...
...
@@ -2354,12 +2352,12 @@ class SSHConnection():
if
result
is
not
None
:
copyin_res
=
self
.
copyin
(
self
.
eNBIPAddress
,
self
.
eNBUserName
,
self
.
eNBPassword
,
self
.
eNBSourceCodePath
+
'/cmake_targets/'
+
self
.
eNBLogFile
,
'.'
)
if
(
copyin_res
==
-
1
):
logging
.
debug
(
'
\u001B
[1;37;41m Could not copy
e
NB logfile to analyze it!
\u001B
[0m'
)
self
.
htmleNBFailureMsg
=
'Could not copy
e
NB logfile to analyze it!'
logging
.
debug
(
'
\u001B
[1;37;41m Could not copy
'
+
nodeB_prefix
+
'
NB logfile to analyze it!
\u001B
[0m'
)
self
.
htmleNBFailureMsg
=
'Could not copy
'
+
nodeB_prefix
+
'
NB logfile to analyze it!'
self
.
CreateHtmlTestRow
(
'N/A'
,
'KO'
,
ENB_PROCESS_NOLOGFILE_TO_ANALYZE
)
self
.
eNBLogFile
=
''
return
logging
.
debug
(
'
\u001B
[1m Analyzing
e
NB logfile
\u001B
[0m'
)
logging
.
debug
(
'
\u001B
[1m Analyzing
'
+
nodeB_prefix
+
'
NB logfile
\u001B
[0m'
)
logStatus
=
self
.
AnalyzeLogFile_eNB
(
self
.
eNBLogFile
)
if
(
logStatus
<
0
):
self
.
CreateHtmlTestRow
(
'N/A'
,
'KO'
,
logStatus
)
...
...
@@ -2485,16 +2483,16 @@ class SSHConnection():
optionsMsg
+=
self
.
htmlUEFailureMsg
optionsMsg
+=
'</pre>'
self
.
CreateHtmlTestRow
(
optionsMsg
,
'KO'
,
logStatus
,
'UE'
)
self
.
CreateHtmlTabFooter
(
False
)
sys
.
exit
(
1
)
# for NR-UE at the moment keep running
if
self
.
air_interface
==
'lte'
:
self
.
CreateHtmlTabFooter
(
False
)
sys
.
exit
(
1
)
else
:
optionsMsg
=
'<pre style="background-color:white"><b>Sniffing Successful</b>
\n
'
optionsMsg
+=
self
.
htmlUEFailureMsg
optionsMsg
+=
'</pre>'
self
.
CreateHtmlTestRow
(
optionsMsg
,
'OK'
,
ALL_PROCESSES_OK
)
self
.
UELogFile
=
''
else
:
self
.
CreateHtmlTestRow
(
'<pre style="background-color:white">No Log File to analyze</pre>'
,
'OK'
,
ALL_PROCESSES_OK
)
def
AutoTerminateUEandeNB
(
self
):
self
.
testCase_id
=
'AUTO-KILL-UE'
...
...
@@ -2818,9 +2816,7 @@ class SSHConnection():
self
.
GetAllUEDevices
(
terminate_ue_flag
)
self
.
GetAllCatMDevices
(
terminate_ue_flag
)
else
:
self
.
UEDevices
.
append
(
'doughq9rehg'
)
self
.
UEDevices
.
append
(
'dnsgiuahgia'
)
self
.
UEDevices
.
append
(
'uehgieng9'
)
self
.
UEDevices
.
append
(
'OAI-UE'
)
self
.
htmlUEConnected
=
len
(
self
.
UEDevices
)
i
=
0
...
...
@@ -3340,7 +3336,7 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
elif
SSH
.
EPCIPAddress
==
''
or
SSH
.
EPCUserName
==
''
or
SSH
.
EPCPassword
==
''
or
SSH
.
EPCType
==
''
or
SSH
.
EPCSourceCodePath
==
''
or
SSH
.
ADBIPAddress
==
''
or
SSH
.
ADBUserName
==
''
or
SSH
.
ADBPassword
==
''
:
Usage
()
sys
.
exit
(
'Insufficient Parameter'
)
if
(
SSH
.
EPCIPAddress
!=
''
):
if
(
SSH
.
EPCIPAddress
!=
''
)
and
(
SSH
.
EPCIPAddress
!=
'none'
)
:
SSH
.
copyout
(
SSH
.
EPCIPAddress
,
SSH
.
EPCUserName
,
SSH
.
EPCPassword
,
cwd
+
"/tcp_iperf_stats.awk"
,
"/tmp"
)
SSH
.
copyout
(
SSH
.
EPCIPAddress
,
SSH
.
EPCUserName
,
SSH
.
EPCPassword
,
cwd
+
"/active_net_interfaces.awk"
,
"/tmp"
)
else
:
...
...
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